From bdc0b794b54356eef3aa6205c046de8aa22a8e73 Mon Sep 17 00:00:00 2001 From: CANOE-main Date: Thu, 16 May 2024 14:54:27 -0600 Subject: [PATCH 001/587] Update run_actions.py Adds excel outputs for completed runs --- temoa/temoa_model/run_actions.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/temoa/temoa_model/run_actions.py b/temoa/temoa_model/run_actions.py index d1f6576d7..073a09046 100644 --- a/temoa/temoa_model/run_actions.py +++ b/temoa/temoa_model/run_actions.py @@ -47,6 +47,7 @@ ) from pyomo.opt import SolverResults +from temoa.data_processing.DB_to_Excel import make_excel from temoa.temoa_model.table_writer import TableWriter from temoa.temoa_model.temoa_config import TemoaConfig from temoa.temoa_model.temoa_model import TemoaModel @@ -327,33 +328,35 @@ def check_solve_status(result: SolverResults) -> tuple[bool, str]: return False, f'{soln.Status} was returned from solve' -def handle_results(instance: TemoaModel, results, options: TemoaConfig): +def handle_results(instance: TemoaModel, results, config: TemoaConfig): hack = time() - if not options.silent: + if not config.silent: msg = '[ ] Calculating reporting variables and formatting results.' # yield 'Calculating reporting variables and formatting results.' SE.write(msg) SE.flush() - # output_stream = pformat_results(instance, results, options) - table_writer = TableWriter(config=options) - if options.save_duals: + # output_stream = pformat_results(instance, results, config) + table_writer = TableWriter(config=config) + if config.save_duals: table_writer.write_results(M=instance, results=results) else: table_writer.write_results(M=instance) - if not options.silent: + if not config.silent: SE.write('\r[%8.2f] Results processed.\n' % (time() - hack)) SE.flush() - # if options.stream_output: + if config.save_excel: + temp_scenario = set() + temp_scenario.add(config.scenario) + # make_excel function imported near the top + excel_filename = config.output_path / config.scenario + make_excel(str(config.output_database), excel_filename, temp_scenario) + + # if config.stream_output: # print(output_stream.getvalue()) # normal (non-MGA) run will have a TotalCost as the OBJ: if hasattr(instance, 'TotalCost'): logger.info('TotalCost value: %0.2f', value(instance.TotalCost)) - # MGA runs should have either a FirstObj or SecondObj - if hasattr(instance, 'FirstObj'): - logger.info('MGA First Obj value: %0.2f', value(instance.FirstObj)) - elif hasattr(instance, 'SecondObj'): - logger.info('MGA Second Obj value: %0.2f', value(instance.SecondObj)) return From bf33646b39e79f3ceb728b44bdc50031f35c4268 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 17 May 2024 17:39:26 -0400 Subject: [PATCH 002/587] update run_actions --- temoa/temoa_model/run_actions.py | 44 ++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/temoa/temoa_model/run_actions.py b/temoa/temoa_model/run_actions.py index 073a09046..e6c3b198b 100644 --- a/temoa/temoa_model/run_actions.py +++ b/temoa/temoa_model/run_actions.py @@ -257,6 +257,13 @@ def solve_instance( optimizer.options['barrier convergetol'] = 1.0e-5 optimizer.options['feasopt tolerance'] = 1.0e-6 + elif solver_name == 'gurobi': + # Note: these parameter values are taken to be the same as those in PyPSA (see: https://pypsa-eur.readthedocs.io/en/latest/configuration.html) + optimizer.options["Method"] = 2 # barrier + optimizer.options["Crossover"] = 0 # non basic solution, ie no crossover + optimizer.options["BarConvTol"] = 1.e-5 + optimizer.options["FeasibilityTol"] = 1.e-6 + elif solver_name == 'appsi_highs': pass @@ -280,9 +287,9 @@ def solve_instance( solver_suffixes = [] try: if solver_name == 'appsi_highs' and not solver_suffixes: - result: SolverResults = optimizer.solve(instance) + result: SolverResults = optimizer.solve(instance, tee=True) else: # we can try it... - result: SolverResults = optimizer.solve(instance, suffixes=solver_suffixes) + result: SolverResults = optimizer.solve(instance, suffixes=solver_suffixes, tee=True) except RuntimeError as error: logger.error('Solver failed to solve and returned an error: %s', error) logger.error( @@ -328,35 +335,40 @@ def check_solve_status(result: SolverResults) -> tuple[bool, str]: return False, f'{soln.Status} was returned from solve' -def handle_results(instance: TemoaModel, results, config: TemoaConfig): +def handle_results(instance: TemoaModel, results, options: TemoaConfig): hack = time() - if not config.silent: + if not options.silent: msg = '[ ] Calculating reporting variables and formatting results.' # yield 'Calculating reporting variables and formatting results.' SE.write(msg) SE.flush() - # output_stream = pformat_results(instance, results, config) - table_writer = TableWriter(config=config) - if config.save_duals: + # output_stream = pformat_results(instance, results, options) + table_writer = TableWriter(config=options) + if options.save_duals: table_writer.write_results(M=instance, results=results) else: table_writer.write_results(M=instance) - if not config.silent: - SE.write('\r[%8.2f] Results processed.\n' % (time() - hack)) - SE.flush() - - if config.save_excel: + if options.save_excel: temp_scenario = set() - temp_scenario.add(config.scenario) + temp_scenario.add(options.scenario) # make_excel function imported near the top - excel_filename = config.output_path / config.scenario - make_excel(str(config.output_database), excel_filename, temp_scenario) + excel_filename = options.output_path / options.scenario + make_excel(str(options.output_database), excel_filename, temp_scenario) + + if not options.silent: + SE.write('\r[%8.2f] Results processed.\n' % (time() - hack)) + SE.flush() - # if config.stream_output: + # if options.stream_output: # print(output_stream.getvalue()) # normal (non-MGA) run will have a TotalCost as the OBJ: if hasattr(instance, 'TotalCost'): logger.info('TotalCost value: %0.2f', value(instance.TotalCost)) + # MGA runs should have either a FirstObj or SecondObj + if hasattr(instance, 'FirstObj'): + logger.info('MGA First Obj value: %0.2f', value(instance.FirstObj)) + elif hasattr(instance, 'SecondObj'): + logger.info('MGA Second Obj value: %0.2f', value(instance.SecondObj)) return From 2d44176156d98ff2c33d59355c7d7e0ec174dae3 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 23 May 2024 15:43:16 -0400 Subject: [PATCH 003/587] Added SeasonalActivity constraints --- temoa/temoa_model/hybrid_loader.py | 32 +++++- .../model_checking/commodity_graph.py | 2 + temoa/temoa_model/temoa_model.py | 18 +++ temoa/temoa_model/temoa_rules.py | 108 ++++++++++++++++++ 4 files changed, 159 insertions(+), 1 deletion(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 56dfde8a4..2abda3353 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -537,7 +537,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # DemandSpecificDistribution raw = cur.execute( - 'SELECT region, season, tod, demand_name, dds FROM main.DemandSpecificDistribution' + 'SELECT region, season, tod, demand_name, dsd FROM main.DemandSpecificDistribution' ).fetchall() load_element(M.DemandSpecificDistribution, raw) @@ -942,6 +942,34 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): ).fetchall() load_element(M.MinActivity, raw, self.viable_rt, (0, 2)) + # MaxSeasonalActivity + if self.table_exists('MaxSeasonalActivity'): + if mi: + raw = cur.execute( + 'SELECT region, period, season, tech, max_act FROM main.MaxSeasonalActivity ' + 'WHERE period >= ? AND period <= ?', + (mi.base_year, mi.last_demand_year), + ).fetchall() + else: + raw = cur.execute( + 'SELECT region, period, season, tech, max_act FROM main.MaxSeasonalActivity ' + ).fetchall() + load_element(M.MaxSeasonalActivity, raw, self.viable_rt, (0, 3)) + + # MinSeasonalActivity + if self.table_exists('MinSeasonalActivity'): + if mi: + raw = cur.execute( + 'SELECT region, period, season, tech, min_act FROM main.MinSeasonalActivity ' + 'WHERE period >= ? AND period <= ?', + (mi.base_year, mi.last_demand_year), + ).fetchall() + else: + raw = cur.execute( + 'SELECT region, period, season, tech, min_act FROM main.MinSeasonalActivity ' + ).fetchall() + load_element(M.MinSeasonalActivity, raw, self.viable_rt, (0, 3)) + # MinAnnualCapacityFactor if self.table_exists('MinAnnualCapacityFactor'): raw = cur.execute( @@ -1080,6 +1108,7 @@ def load_param_idx_sets(self, data: dict) -> dict: M.CostInvest.name: M.CostInvest_rtv.name, M.EmissionLimit.name: M.EmissionLimitConstraint_rpe.name, M.MaxActivity.name: M.MaxActivityConstraint_rpt.name, + M.MaxSeasonalActivity.name: M.MaxSeasonalActivityConstraint_rpst.name, M.MaxActivityGroup.name: M.MaxActivityGroup_rpg.name, M.MaxActivityShare.name: M.MaxActivityShareConstraint_rptg.name, M.MaxAnnualCapacityFactor.name: M.MaxAnnualCapacityFactorConstraint_rpto.name, @@ -1091,6 +1120,7 @@ def load_param_idx_sets(self, data: dict) -> dict: M.MaxNewCapacityShare.name: M.MaxNewCapacityShareConstraint_rptg.name, M.MaxResource.name: M.MaxResourceConstraint_rt.name, M.MinActivity.name: M.MinActivityConstraint_rpt.name, + M.MinSeasonalActivity.name: M.MinSeasonalActivityConstraint_rpst.name, M.MinActivityGroup.name: M.MinActivityGroup_rpg.name, M.MinActivityShare.name: M.MinActivityShareConstraint_rptg.name, M.MinAnnualCapacityFactor.name: M.MinAnnualCapacityFactorConstraint_rpto.name, diff --git a/temoa/temoa_model/model_checking/commodity_graph.py b/temoa/temoa_model/model_checking/commodity_graph.py index 642f17667..a548d3579 100644 --- a/temoa/temoa_model/model_checking/commodity_graph.py +++ b/temoa/temoa_model/model_checking/commodity_graph.py @@ -41,6 +41,7 @@ """ logger = logging.getLogger(__name__) +import traceback def generate_graph( @@ -173,6 +174,7 @@ def _graph_connections( 'tech?\n Error message: %s', e, ) + print(traceback.format_exc()) except Exception as e: logger.error('Failed to export the network graph into HTML. Error message: %s', e) diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index ed402bbbb..5b43b6f73 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -365,6 +365,16 @@ def __init__(M, *args, **kwargs): ) M.MinActivity = Param(M.MinActivityConstraint_rpt) + M.MaxSeasonalActivityConstraint_rpst = Set( + within=M.RegionalGlobalIndices * M.time_optimize * M.time_season * M.tech_all + ) + M.MaxSeasonalActivity = Param(M.MaxSeasonalActivityConstraint_rpst) + + M.MinSeasonalActivityConstraint_rpst = Set( + within=M.RegionalGlobalIndices * M.time_optimize * M.time_season * M.tech_all + ) + M.MinSeasonalActivity = Param(M.MinSeasonalActivityConstraint_rpst) + M.MinAnnualCapacityFactorConstraint_rpto = Set( within=M.RegionalGlobalIndices * M.time_optimize * M.tech_all * M.commodity_carrier ) @@ -674,6 +684,14 @@ def __init__(M, *args, **kwargs): M.MinActivityConstraint_rpt, rule=MinActivity_Constraint ) + M.MaxSeasonalActivityConstraint = Constraint( + M.MaxSeasonalActivityConstraint_rpst, rule=MaxSeasonalActivity_Constraint + ) + + M.MinSeasonalActivityConstraint = Constraint( + M.MinSeasonalActivityConstraint_rpst, rule=MinSeasonalActivity_Constraint + ) + M.MinActivityGroupConstraint = Constraint( M.MinActivityGroup_rpg, rule=MinActivityGroup_Constraint ) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index b444cf55d..570ae6090 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -2106,6 +2106,60 @@ def MaxActivity_Constraint(M: 'TemoaModel', r, p, t): return expr +def MaxSeasonalActivity_Constraint(M: 'TemoaModel', r, p, s, t): + + r""" + The MaxSeasonalActivity sets an upper bound on the activity from a specific technology. + Note that the indices for these constraints are region, period, season, and tech. + The first component of the constraint pertains to technologies with + variable output at the time slice level, and the second component pertains to + technologies with constant annual output belonging to the :code:`tech_annual` + set. + .. math:: + :label: MaxSeasonalActivity + \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le MAXSSNACT_{r, p, s, t} + \forall \{r, p, s, t\} \in \Theta_{\text{MaxSeasonalActivity}} + \sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \le MAXSSNACT_{r, p, s, t} + \forall \{r, p, s, t \in T^{a}\} \in \Theta_{\text{MaxSeasonalActivity}} + """ + + # Notice that this constraint follows the implementation of the + # MaxActivity_Constraint(). The difference is that this function is defined + # over each representative day, or "season", as opposed to the entire + # year, or "period". + + # The V_FlowOut variable is scaled by the weights of each representative day. + # In order to determine the daily, or "seasonal", flow, the V_FLowOut variable + # must be converted back to its un-scaled value. We do this by dividing the + # V_FlowOut value by M.SegFrac[s, d]*365*24. + + try: + activity_rpst = sum( + M.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] / (M.SegFrac[s, d]*365*24) + 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 d in M.time_of_day + ) + except: + msg = ( + "\nWarning: MaxSeasonalActivity constraint can not be defined for " + "technologies in \"tech_annual\". Continuing by ignoring the constraint " + "for '%s'.\n " + ) + SE.write(msg % (t)) + return Constraint.Skip + + max_act = value(M.MaxSeasonalActivity[r, p, s, t]) + expr = activity_rpst <= max_act + + # in the case that there is nothing to sum, skip + if isinstance(expr, bool): # an empty list was generated + return Constraint.Skip + + return expr + + def MinActivity_Constraint(M: 'TemoaModel', r, p, t): r""" @@ -2168,6 +2222,60 @@ def MinActivity_Constraint(M: 'TemoaModel', r, p, t): return expr +def MinSeasonalActivity_Constraint(M: 'TemoaModel', r, p, s, t): + + r""" + The MinSeasonalActivity sets a lower bound on the activity from a specific technology + over a specific season. Note that the indices for these constraints are region, + period, season and tech, not tech and vintage. The first version of the constraint + pertains to technologies with variable output at the time slice level, and the + second version pertains to technologies with constant annual output belonging to + the :code:`tech_annual` set. + .. math:: + :label: MinSeasonalActivity + \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \ge MINSSNACT_{r, p, t} + \forall \{r, p, s, t\} \in \Theta_{\text{MinSeasonalActivity}} + \sum_{I,V,O} \textbf{FOA}_{r, p, s, i, t, v, o} \ge MINSSNACT_{r, p, s, t} + \forall \{r, p, s, t \in T^{a}\} \in \Theta_{\text{MinSeasonalActivity}} + """ + + # Notice that this constraint follows the implementation of the + # MinActivity_Constraint(). The difference is that this function is defined + # over each representative day, or "season", as opposed to the entire + # year, or "period". + + # The V_FlowOut variable is scaled by the weights of each representative day. + # In order to determine the daily, or "seasonal", flow, the V_FLowOut variable + # must be converted back to its un-scaled value. We do this using the + # weighting_factor below: + + try: + activity_rpst = sum( + M.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] / (M.SegFrac[s, d]*365*24) + 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 d in M.time_of_day + ) + except: + msg = ( + "\nWarning: MinSeasonalActivity constraint can not be defined for " + "technologies in \"tech_annual\". Continuing by ignoring the constraint " + "for '%s'.\n " + ) + SE.write(msg % (t)) + return Constraint.Skip + + min_act = value(M.MinSeasonalActivity[r, p, s, t]) + expr = activity_rpst >= min_act + + # in the case that there is nothing to sum, skip + if isinstance(expr, bool): # an empty list was generated + return Constraint.Skip + + return expr + + def MinActivityGroup_Constraint(M: 'TemoaModel', r, p, g): r""" From ab0b9c66db6be108ce8368fa80313c0d712ce736 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 4 Jun 2024 17:14:13 -0400 Subject: [PATCH 004/587] Fixed bugs in objective function. Fixed bugs in emissions accounting --- temoa/temoa_model/table_writer.py | 31 ++++++++----------------------- temoa/temoa_model/temoa_rules.py | 14 ++++++++------ 2 files changed, 16 insertions(+), 29 deletions(-) diff --git a/temoa/temoa_model/table_writer.py b/temoa/temoa_model/table_writer.py index e28882a86..efa651e34 100644 --- a/temoa/temoa_model/table_writer.py +++ b/temoa/temoa_model/table_writer.py @@ -450,6 +450,7 @@ def loan_costs( invest_cost, loan_annualize=loan_ar, lifetime_loan_process=loan_life, + lifetime_process=process_life, P_0=p_0, P_e=p_e, GDR=global_discount_rate, @@ -462,6 +463,7 @@ def loan_costs( invest_cost, loan_annualize=loan_ar, lifetime_loan_process=loan_life, + lifetime_process=process_life, P_0=p_0, P_e=p_e, GDR=global_discount_rate, @@ -652,30 +654,13 @@ def _gather_emission_costs_and_flows(self, M: 'TemoaModel'): flows: dict[EI, float] = defaultdict(float) # iterate through the normal and annual and accumulate flow values for r, p, e, s, d, i, t, v, o in normal: - if t in M.tech_curtailment: - flows[EI(r, p, t, v, e)] += ( - value(M.V_Curtailment[r, p, s, d, i, t, v, o]) - * M.EmissionActivity[r, e, i, t, v, o] - ) - elif t in M.tech_flex: - flows[EI(r, p, t, v, e)] += ( - value(M.V_Flex[r, p, s, d, i, t, v, o]) * M.EmissionActivity[r, e, i, t, v, o] - ) - else: - flows[EI(r, p, t, v, e)] += ( - value(M.V_FlowOut[r, p, s, d, i, t, v, o]) - * M.EmissionActivity[r, e, i, t, v, o] - ) + flows[EI(r, p, t, v, e)] += ( + value(M.V_FlowOut[r, p, s, d, i, t, v, o]) * M.EmissionActivity[r, e, i, t, v, o] + ) for r, p, e, i, t, v, o in annual: - if t in M.tech_flex and o in M.flex_commodities: - flows[EI(r, p, t, v, e)] += ( - value(M.V_FlexAnnual[r, p, i, t, v, o]) * M.EmissionActivity[r, e, i, t, v, o] - ) - else: - flows[EI(r, p, t, v, e)] += ( - value(M.V_FlowOutAnnual[r, p, i, t, v, o]) - * M.EmissionActivity[r, e, i, t, v, o] - ) + flows[EI(r, p, t, v, e)] += ( + value(M.V_FlexAnnual[r, p, i, t, v, o]) * M.EmissionActivity[r, e, i, t, v, o] + ) # gather costs ud_costs = defaultdict(float) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 570ae6090..4fbf35f28 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -379,6 +379,7 @@ def loan_cost( invest_cost: float, loan_annualize: float, lifetime_loan_process: float | int, + lifetime_process: int, P_0: int, P_e: int, GDR: float, @@ -398,9 +399,9 @@ def loan_cost( :return: fixed number or pyomo expression based on input types """ if GDR == 0: # return the non-discounted result - regular_payment = capacity * invest_cost * loan_annualize - payments_made = min(lifetime_loan_process, P_e - vintage) - return regular_payment * payments_made + annuity = capacity * invest_cost * loan_annualize * lifetime_loan_process / lifetime_process + payments_made = min(lifetime_process, P_e - vintage) + return annuity * payments_made x = 1 + GDR # a convenience res = ( capacity @@ -414,8 +415,8 @@ def loan_cost( ) ) * ( - (1 - x ** (-min(lifetime_loan_process, P_e - vintage))) - / (1 - x ** (-lifetime_loan_process)) + (1 - x ** (-min(lifetime_process, P_e - vintage))) + / (1 - x ** (-lifetime_process)) ) ) return res @@ -467,6 +468,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): M.CostInvest[r, S_t, S_v], M.LoanAnnualize[r, S_t, S_v], value(M.LoanLifetimeProcess[r, S_t, S_v]), + value(M.LifetimeProcess[r, S_t, S_v]), P_0, P_e, GDR, @@ -623,7 +625,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): var_emissions # + flex_emissions # + curtail_emissions - # + var_annual_emissions + + var_annual_emissions # + flex_annual_emissions ) From 672034c2928f8252f13bec47403a7ef2ea73c496 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 5 Jun 2024 12:15:35 -0400 Subject: [PATCH 005/587] Fix mistake in results output for annual emissions --- temoa/temoa_model/table_writer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temoa/temoa_model/table_writer.py b/temoa/temoa_model/table_writer.py index efa651e34..5470b6da9 100644 --- a/temoa/temoa_model/table_writer.py +++ b/temoa/temoa_model/table_writer.py @@ -659,7 +659,7 @@ def _gather_emission_costs_and_flows(self, M: 'TemoaModel'): ) for r, p, e, i, t, v, o in annual: flows[EI(r, p, t, v, e)] += ( - value(M.V_FlexAnnual[r, p, i, t, v, o]) * M.EmissionActivity[r, e, i, t, v, o] + value(M.V_FlowOutAnnual[r, p, i, t, v, o]) * M.EmissionActivity[r, e, i, t, v, o] ) # gather costs From 6fafa7f9afe3562e4a9f1b04204b5545180b07ea Mon Sep 17 00:00:00 2001 From: idelder <35704891+idelder@users.noreply.github.com> Date: Mon, 18 Nov 2024 10:32:06 -0500 Subject: [PATCH 006/587] Fix TechInputSplit constraint summation --- temoa/temoa_model/temoa_rules.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 4fbf35f28..5bfa07b13 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -2946,7 +2946,7 @@ def TechInputSplit_Constraint(M: 'TemoaModel', r, p, s, d, i, t, v): total_inp = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] / value(M.Efficiency[r, S_i, t, v, S_o]) for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, i] + for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] ) expr = inp >= M.TechInputSplit[r, p, i, t] * total_inp @@ -2968,7 +2968,7 @@ def TechInputSplitAnnual_Constraint(M: 'TemoaModel', r, p, i, t, v): total_inp = sum( M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] / value(M.Efficiency[r, S_i, t, v, S_o]) for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, i] + for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] ) expr = inp >= M.TechInputSplit[r, p, i, t] * total_inp From 53a6c26183ce29a22eabb127c2f65b55c675f537 Mon Sep 17 00:00:00 2001 From: idelder <35704891+idelder@users.noreply.github.com> Date: Tue, 26 Nov 2024 16:02:42 -0500 Subject: [PATCH 007/587] Fix variable and emissions costs in temoa_rules --- temoa/temoa_model/temoa_rules.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 5bfa07b13..b5f6577db 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -495,7 +495,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): fixed_or_variable_cost( M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, S_o], M.CostVariable[r, p, S_t, S_v], - MPL[r, p, S_t, S_v], + M.PeriodLength[p], GDR, P_0, p, @@ -512,7 +512,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): fixed_or_variable_cost( M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, S_o], M.CostVariable[r, p, S_t, S_v], - MPL[r, p, S_t, S_v], + M.PeriodLength[p], GDR, P_0, p, @@ -558,7 +558,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): fixed_or_variable_cost( cap_or_flow=M.V_FlowOut[r, p, s, d, i, t, v, o] * M.EmissionActivity[r, e, i, t, v, o], cost_factor=M.CostEmission[r, p, e], - process_lifetime=MPL[r, p, t, v], + process_lifetime=M.PeriodLength[p], GDR=GDR, P_0=P_0, p=p, @@ -600,7 +600,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): fixed_or_variable_cost( cap_or_flow=M.V_FlowOutAnnual[r, p, i, t, v, o] * M.EmissionActivity[r, e, i, t, v, o], cost_factor=M.CostEmission[r, p, e], - process_lifetime=MPL[r, p, t, v], + process_lifetime=M.PeriodLength[p], GDR=GDR, P_0=P_0, p=p, From a76f8cddbd75215f8fffaf66372e2626a041a8cf Mon Sep 17 00:00:00 2001 From: idelder <35704891+idelder@users.noreply.github.com> Date: Tue, 26 Nov 2024 16:06:58 -0500 Subject: [PATCH 008/587] Fix variable and emissions costs in table_writer --- temoa/temoa_model/table_writer.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/temoa/temoa_model/table_writer.py b/temoa/temoa_model/table_writer.py index 5470b6da9..2e39a8d0f 100644 --- a/temoa/temoa_model/table_writer.py +++ b/temoa/temoa_model/table_writer.py @@ -591,10 +591,10 @@ def write_costs(self, M: TemoaModel, emission_entries=None): continue var_cost = value(M.CostVariable[r, p, t, v]) - undiscounted_var_cost = activity * var_cost * value(MPL[r, p, t, v]) + undiscounted_var_cost = activity * var_cost * value(M.PeriodLength[p]) model_var_cost = temoa_rules.fixed_or_variable_cost( - activity, var_cost, value(MPL[r, p, t, v]), GDR=GDR, P_0=p_0, p=p + activity, var_cost, value(M.PeriodLength[p]), GDR=GDR, P_0=p_0, p=p ) if '-' in r: exchange_costs.add_cost_record( @@ -675,12 +675,12 @@ def _gather_emission_costs_and_flows(self, M: 'TemoaModel'): flows[ei] = 0.0 continue undiscounted_emiss_cost = ( - flows[ei] * M.CostEmission[ei.r, ei.p, ei.e] * MPL[ei.r, ei.p, ei.t, ei.v] + flows[ei] * M.CostEmission[ei.r, ei.p, ei.e] * M.PeriodLength[ei.p] ) discounted_emiss_cost = temoa_rules.fixed_or_variable_cost( cap_or_flow=flows[ei], cost_factor=M.CostEmission[ei.r, ei.p, ei.e], - process_lifetime=MPL[ei.r, ei.p, ei.t, ei.v], + process_lifetime=M.PeriodLength[ei.p], GDR=GDR, P_0=p_0, p=ei.p, From 2020137a49f2806b63f384c3eba80bd355ac54b1 Mon Sep 17 00:00:00 2001 From: idelder <35704891+idelder@users.noreply.github.com> Date: Thu, 28 Nov 2024 16:18:12 -0500 Subject: [PATCH 009/587] Change to TechXputSplitAverage implementation removing tech_variable set (#3) * Change to TechXputSplitAverage implementation removing tech_variable set * Fix techsplitaverage update * Remove print statement... --------- Co-authored-by: Davey Elder --- temoa/temoa_model/hybrid_loader.py | 20 ++++++++-- temoa/temoa_model/table_writer.py | 4 +- temoa/temoa_model/temoa_initialize.py | 55 +++++++++++++++++++++++---- temoa/temoa_model/temoa_model.py | 16 +++++--- temoa/temoa_model/temoa_rules.py | 32 +++++++++++++++- 5 files changed, 105 insertions(+), 22 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 2abda3353..48443a033 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -451,10 +451,6 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): raw = cur.execute('SELECT tech FROM Technology WHERE annual > 0').fetchall() load_element(M.tech_annual, raw, self.viable_techs) - # tech_variable - raw = cur.execute('SELECT tech FROM Technology WHERE variable > 0').fetchall() - load_element(M.tech_variable, raw, self.viable_techs) - # tech_retirement raw = cur.execute('SELECT tech FROM Technology WHERE retire > 0').fetchall() load_element(M.tech_retirement, raw, self.viable_techs) @@ -630,6 +626,22 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): ).fetchall() load_element(M.TechOutputSplit, raw, self.viable_rt, (0, 2)) + # TechOutputSplitAverage + if self.table_exists('TechOutputSplitAverage'): + if mi: + raw = cur.execute( + 'SELECT region, period, tech, output_comm, min_proportion ' + 'FROM main.TechOutputSplitAverage ' + 'WHERE period >= ? AND period <= ?', + (mi.base_year, mi.last_demand_year), + ).fetchall() + else: + raw = cur.execute( + 'SELECT region, period, tech, output_comm, min_proportion ' + 'FROM main.TechOutputSplitAverage ' + ).fetchall() + load_element(M.TechOutputSplitAverage, raw, self.viable_rt, (0, 2)) + # RenewablePortfolioStandard if self.table_exists('RPSRequirement'): if mi: diff --git a/temoa/temoa_model/table_writer.py b/temoa/temoa_model/table_writer.py index 2e39a8d0f..c2b59d6dc 100644 --- a/temoa/temoa_model/table_writer.py +++ b/temoa/temoa_model/table_writer.py @@ -310,7 +310,6 @@ def check_flow_balance(self, M: TemoaModel) -> bool: flost = flows[fi][FlowType.LOST] # some identifiers tech = fi.t - var_tech = fi.t in M.tech_variable flex_tech = fi.t in M.tech_flex annual_tech = fi.t in M.tech_annual @@ -327,9 +326,8 @@ def check_flow_balance(self, M: TemoaModel) -> bool: 'Flow balance check failed for index: %s, delta: %0.2f', fi, deltas[fi] ) logger.info( - 'Tech: %s, Var: %s, Flex: %s, Annual: %s', + 'Tech: %s, Flex: %s, Annual: %s', tech, - var_tech, flex_tech, annual_tech, ) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 8568eb6e3..88d31e55c 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -699,6 +699,13 @@ def CreateSparseDicts(M: 'TemoaModel'): o, ) not in M.outputsplitVintages: M.outputsplitVintages[r, p, t, o] = set() + if (r, p, t, o) in M.TechOutputSplitAverage.sparse_iterkeys() and ( + r, + p, + t, + o, + ) not in M.outputsplitaverageVintages: + M.outputsplitaverageVintages[r, p, t, o] = set() if t in M.tech_resource and (r, p, o) not in M.ProcessByPeriodAndOutput: M.ProcessByPeriodAndOutput[r, p, o] = set() if t in M.tech_reserve and (r, p) not in M.processReservePeriods: @@ -738,6 +745,8 @@ def CreateSparseDicts(M: 'TemoaModel'): M.inputsplitaverageVintages[r, p, i, t].add(v) if (r, p, t, o) in M.TechOutputSplit.sparse_iterkeys(): M.outputsplitVintages[r, p, t, o].add(v) + if (r, p, t, o) in M.TechOutputSplitAverage.sparse_iterkeys(): + M.outputsplitaverageVintages[r, p, t, o].add(v) if t in M.tech_resource: M.ProcessByPeriodAndOutput[r, p, o].add((i, t, v)) if t in M.tech_reserve: @@ -1300,11 +1309,22 @@ def TechInputSplitConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, s, d, i, t, v) for r, p, i, t in M.inputsplitVintages.keys() - if t not in M.tech_annual and t not in M.tech_variable + if t not in M.tech_annual for v in M.inputsplitVintages[r, p, i, t] for s in M.time_season for d in M.time_of_day ) + ann_indices = set( + (r, p, i, t) + for r, p, i, t in M.inputsplitVintages.keys() + if t in M.tech_annual + ) + if len(ann_indices) > 0: + msg = ( + "Warning: Annual technologies included in TechInputSplit table. " + "Use TechInputSplitAverage table instead or these constraints will be ignored: {}" + ) + logger.warning(msg.format(ann_indices)) return indices @@ -1312,9 +1332,9 @@ def TechInputSplitConstraintIndices(M: 'TemoaModel'): def TechInputSplitAnnualConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, i, t, v) - for r, p, i, t in M.inputsplitVintages.keys() + for r, p, i, t in M.inputsplitaverageVintages.keys() if t in M.tech_annual - for v in M.inputsplitVintages[r, p, i, t] + for v in M.inputsplitaverageVintages[r, p, i, t] ) return indices @@ -1324,7 +1344,7 @@ def TechInputSplitAverageConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, i, t, v) for r, p, i, t in M.inputsplitaverageVintages.keys() - if t in M.tech_variable + if t not in M.tech_annual for v in M.inputsplitaverageVintages[r, p, i, t] ) return indices @@ -1339,6 +1359,17 @@ def TechOutputSplitConstraintIndices(M: 'TemoaModel'): for s in M.time_season for d in M.time_of_day ) + ann_indices = set( + (r, p, t, o) + for r, p, t, o in M.outputsplitVintages.keys() + if t in M.tech_annual + ) + if len(ann_indices) > 0: + msg = ( + "Warning: Annual technologies included in TechOutputSplit table. " + "Use TechOutputSplitAverage table instead or these constraints will be ignored: {}" + ) + logger.warning(msg.format(ann_indices)) return indices @@ -1346,14 +1377,24 @@ def TechOutputSplitConstraintIndices(M: 'TemoaModel'): def TechOutputSplitAnnualConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, t, v, o) - for r, p, t, o in M.outputsplitVintages.keys() - if t in M.tech_annual and t not in M.tech_variable - for v in M.outputsplitVintages[r, p, t, o] + for r, p, t, o in M.outputsplitaverageVintages.keys() + if t in M.tech_annual + for v in M.outputsplitaverageVintages[r, p, t, o] ) return indices +def TechOutputSplitAverageConstraintIndices(M: 'TemoaModel'): + indices = set( + (r, p, t, v, o) + for r, p, t, o in M.outputsplitaverageVintages.keys() + if t not in M.tech_annual + for v in M.outputsplitaverageVintages[r, p, t, o] + ) + return indices + + def get_loan_life(M, r, t, _): return M.LoanLifetimeTech[r, t] diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 5b43b6f73..c7b61d3ad 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -101,6 +101,7 @@ def __init__(M, *args, **kwargs): M.inputsplitVintages = dict() M.inputsplitaverageVintages = dict() M.outputsplitVintages = dict() + M.outputsplitaverageVintages = dict() M.ProcessByPeriodAndOutput = dict() M.exportRegions = dict() M.importRegions = dict() @@ -160,9 +161,6 @@ def __init__(M, *args, **kwargs): # the below is a convenience for domain checking in params below that should not accept uncap techs... M.tech_with_capacity = Set(initialize=M.tech_all - M.tech_uncap) """techs eligible for capacitization""" - # Define techs for use with TechInputSplitAverage constraint, - # where techs have variable annual output but the user wishes to constrain them annually - M.tech_variable = Set(within=M.tech_all) # Define techs for which economic retirement is an option # Note: Storage techs cannot (currently) be retired due to linkage to initialization # process, which is currently incapable of reducing initializations on retirements. @@ -287,10 +285,9 @@ def __init__(M, *args, **kwargs): M.LoanLifetimeProcess = Param(M.LoanLifetimeProcess_rtv, default=get_loan_life) M.TechInputSplit = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all) - M.TechInputSplitAverage = Param( - M.regions, M.time_optimize, M.commodity_physical, M.tech_variable - ) + M.TechInputSplitAverage = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all) M.TechOutputSplit = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier) + M.TechOutputSplitAverage = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier) M.RenewablePortfolioStandardConstraint_rpg = Set( within=M.regions * M.time_optimize * M.tech_group_names @@ -807,6 +804,13 @@ def __init__(M, *args, **kwargs): M.TechOutputSplitAnnualConstraint_rptvo, rule=TechOutputSplitAnnual_Constraint ) + M.TechOutputSplitAverageConstraint_rptvo = Set( + dimen=5, initialize=TechOutputSplitAverageConstraintIndices + ) + M.TechOutputSplitAverageConstraint = Constraint( + M.TechOutputSplitAverageConstraint_rptvo, rule=TechOutputSplitAverage_Constraint + ) + M.RenewablePortfolioStandardConstraint = Constraint( M.RenewablePortfolioStandardConstraint_rpg, rule=RenewablePortfolioStandard_Constraint ) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index b5f6577db..acefa204b 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -2971,7 +2971,7 @@ def TechInputSplitAnnual_Constraint(M: 'TemoaModel', r, p, i, t, v): for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] ) - expr = inp >= M.TechInputSplit[r, p, i, t] * total_inp + expr = inp >= M.TechInputSplitAverage[r, p, i, t] * total_inp return expr @@ -3078,7 +3078,35 @@ def TechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o): for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] ) - expr = out >= M.TechOutputSplit[r, p, t, o] * total_out + expr = out >= M.TechOutputSplitAverage[r, p, t, o] * total_out + return expr + + +def TechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o): + r""" + Allows users to specify fixed or minimum shares of commodity outputs from a process. + 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 TechOutputSplit 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 output shares over the course of a year.""" + + out = sum( + M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, o] + for S_i in M.ProcessInputsByOutput[r, p, t, v, o] + for S_s in M.time_season + for S_d in M.time_of_day + ) + + total_out = sum( + M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_s in M.time_season + for S_d in M.time_of_day + ) + + expr = out >= M.TechOutputSplitAverage[r, p, t, o] * total_out return expr From e4ee86954d1d58aaa969ec3bc34ce804f435334f Mon Sep 17 00:00:00 2001 From: CANOE-main Date: Mon, 9 Dec 2024 13:42:25 -0700 Subject: [PATCH 010/587] Uploaded canoe schema Added techoutputsplitaverage table, removed tech variable in technology table and added data_flags table to allow for easier filtering --- data_files/canoe_schema_template.sql | 1642 ++++++++++++++++++++++++++ 1 file changed, 1642 insertions(+) create mode 100644 data_files/canoe_schema_template.sql diff --git a/data_files/canoe_schema_template.sql b/data_files/canoe_schema_template.sql new file mode 100644 index 000000000..66d5081e9 --- /dev/null +++ b/data_files/canoe_schema_template.sql @@ -0,0 +1,1642 @@ +CREATE TABLE IF NOT EXISTS "Technology" ( + "tech" text, + "flag" text, + "sector" text, + "description" text, + "category" text, + "data_flags" text, + "reference" text, + "additional_notes" text, sub_category, unlim_cap INTEGER, annual INTEGER, reserve INTEGER, curtail INTEGER, retire INTEGER, flex INTEGER, exchange INTEGER, + + FOREIGN KEY("reference") REFERENCES "references"(reference), + PRIMARY KEY("tech"), + FOREIGN KEY("flag") REFERENCES "TechnologyType"("label"), + FOREIGN KEY("sector") REFERENCES "SectorLabel"("sector") +); +CREATE TABLE IF NOT EXISTS "Commodity" ( + "name" text, + "flag" text, + "description" text, + 'data_flags' text, + "reference" text, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"(reference), + PRIMARY KEY("name"), + FOREIGN KEY("flag") REFERENCES "CommodityType"("label") +); +CREATE TABLE IF NOT EXISTS "data_flags" ( + "data_flags" text, + "description" text + ); +CREATE TABLE IF NOT EXISTS "TechOutputSplit" ( + "region" TEXT, + "period" integer, + "tech" TEXT, + "output_comm" text, + "min_proportion" real, + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","period","tech","output_comm", 'data_flags'), + FOREIGN KEY("output_comm") REFERENCES "Commodity"("name"), + FOREIGN KEY("period") REFERENCES "TimePeriod"("period"), + FOREIGN KEY("tech") REFERENCES "Technology"("tech") +); +CREATE TABLE "TechOutputSplitAverage" ( + "region" TEXT, + "period" integer, + "tech" TEXT, + "output_comm" text, + "min_proportion" real, + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","period","tech","output_comm"), + FOREIGN KEY("output_comm") REFERENCES "Commodity"("name"), + FOREIGN KEY("period") REFERENCES "TimePeriod"("period"), + FOREIGN KEY("tech") REFERENCES "Technology"("tech") +); +CREATE TABLE IF NOT EXISTS "TechInputSplit" ( + "region" TEXT, + "period" integer, + "input_comm" text, + "tech" text, + "min_proportion" real, + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","period","input_comm","tech",'data_flags'), + FOREIGN KEY("tech") REFERENCES "Technology"("tech"), + FOREIGN KEY("input_comm") REFERENCES "Commodity"("name"), + FOREIGN KEY("period") REFERENCES "TimePeriod"("period") +); +CREATE TABLE IF NOT EXISTS "TechInputSplitAverage" ( + "region" TEXT, + "period" integer, + "input_comm" text, + "tech" text, + "min_proportion" real, + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","period","input_comm","tech",'data_flags'), + FOREIGN KEY("input_comm") REFERENCES "Commodity"("name"), + FOREIGN KEY("tech") REFERENCES "Technology"("tech"), + FOREIGN KEY("period") REFERENCES "TimePeriod"("period") +); +CREATE TABLE IF NOT EXISTS "TimeSegmentFraction" ( + "season" text, + "tod" text, + "segfrac" real CHECK("segfrac" >= 0 AND "segfrac" <= 1), + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("season","tod"), + FOREIGN KEY("season") REFERENCES "TimeSeason"("season"), + FOREIGN KEY("tod") REFERENCES "TimeOfDay"("tod") +); +CREATE TABLE IF NOT EXISTS "PlanningReserveMargin" ( + "region" text, + "margin" REAL, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY('region', 'data_flags'), + FOREIGN KEY("region") REFERENCES "Region" +); +CREATE TABLE IF NOT EXISTS "RampDown" ( + "region" text, + `tech` text, + "rate" real, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region", "tech", 'data_flags'), + FOREIGN KEY("tech") REFERENCES "Technology"("tech") +); +CREATE TABLE IF NOT EXISTS "RampUp" ( + "region" text, + `tech` text, + "rate" real, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region", "tech", 'data_flags'), + FOREIGN KEY("tech") REFERENCES "Technology"("tech") +); +CREATE TABLE IF NOT EXISTS "MinCapacity" ( + "region" text, + "period" integer, + "tech" text, + "min_cap" real, + "units" text, + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","period","tech", 'data_flags'), + FOREIGN KEY("tech") REFERENCES "Technology"("tech"), + FOREIGN KEY("period") REFERENCES "TimePeriod"("period") +); +CREATE TABLE IF NOT EXISTS "MinActivity" ( + "region" text, + "period" integer, + "tech" text, + "min_act" real, + "units" text, + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","period","tech", 'data_flags'), + FOREIGN KEY("tech") REFERENCES "Technology"("tech"), + FOREIGN KEY("period") REFERENCES "TimePeriod"("period") +); +CREATE TABLE IF NOT EXISTS "MaxCapacity" ( + "region" text, + "period" integer, + "tech" text, + "max_cap" real, + "units" text, + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","period","tech", 'data_flags'), + FOREIGN KEY("period") REFERENCES "TimePeriod"("period"), + FOREIGN KEY("tech") REFERENCES "Technology"("tech") +); +CREATE TABLE IF NOT EXISTS "MaxActivity" ( + "region" text, + "period" integer, + "tech" text, + "max_act" real, + "units" text, + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","period","tech", 'data_flags'), + FOREIGN KEY("period") REFERENCES "TimePeriod"("period"), + FOREIGN KEY("tech") REFERENCES "Technology"("tech") +); +CREATE TABLE IF NOT EXISTS "MinAnnualCapacityFactor" ( + "region" text, + "period" integer, + "tech" text, + "output_comm" text, + "factor" real CHECK("factor" >= 0 AND "factor" <= 1), + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, source, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + + PRIMARY KEY("region","period","tech","output_comm", 'data_flags'), + FOREIGN KEY("period") REFERENCES "TimePeriod"("period"), + FOREIGN KEY("tech") REFERENCES "Technology"("tech"), + FOREIGN KEY("output_comm") REFERENCES "Commodity"("name") +); +CREATE TABLE IF NOT EXISTS "MaxAnnualCapacityFactor" ( + "region" text, + "period" integer, + "tech" text, + "output_comm" text, + "factor" real CHECK("factor" >= 0 AND "factor" <= 1), + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, source, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + + PRIMARY KEY("region","period","tech","output_comm",'data_flags'), + FOREIGN KEY("period") REFERENCES "TimePeriod"("period"), + FOREIGN KEY("tech") REFERENCES "Technology"("tech"), + FOREIGN KEY("output_comm") REFERENCES "Commodity"("name") +); +CREATE TABLE IF NOT EXISTS "LifetimeTech" ( + "region" text, + "tech" text, + "lifetime" real, + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","tech", 'data_flags'), + FOREIGN KEY("tech") REFERENCES "Technology"("tech") +); +CREATE TABLE IF NOT EXISTS "LifetimeProcess" ( + "region" text, + "tech" text, + "vintage" integer, + "lifetime" real, + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","tech","vintage", 'data_flags'), + FOREIGN KEY("vintage") REFERENCES "TimePeriod"("period"), + FOREIGN KEY("tech") REFERENCES "Technology"("tech") +); +CREATE TABLE IF NOT EXISTS "LoanLifetimeTech" ( + "region" text, + "tech" text, + "lifetime" real, + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","tech", 'data_flags'), + FOREIGN KEY("tech") REFERENCES "Technology"("tech") +); +CREATE TABLE IF NOT EXISTS "GrowthRateSeed" ( + "region" text, + "tech" text, + "seed" real, + "units" text, + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","tech", 'data_flags'), + FOREIGN KEY("tech") REFERENCES "Technology"("tech") +); +CREATE TABLE IF NOT EXISTS "GrowthRateMax" ( + "region" text, + "tech" text, + "rate" real, + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","tech", 'data_flags'), + FOREIGN KEY("tech") REFERENCES "Technology"("tech") +); +CREATE TABLE IF NOT EXISTS "ExistingCapacity" ( + "region" text, + "tech" text, + "vintage" integer, + "capacity" real, + "units" text, + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","tech","vintage", 'data_flags'), + FOREIGN KEY("tech") REFERENCES "Technology"("tech"), + FOREIGN KEY("vintage") REFERENCES "TimePeriod"("period") +); +CREATE TABLE IF NOT EXISTS "EmissionLimit" ( + "region" text, + "period" integer, + "emis_comm" text, + "value" real, + "units" text, + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","period","emis_comm", 'data_flags'), + FOREIGN KEY("period") REFERENCES "TimePeriod"("period"), + FOREIGN KEY("emis_comm") REFERENCES "Commodity"("name") +); +CREATE TABLE IF NOT EXISTS "EmissionActivity" ( + "region" text, + "emis_comm" text, + "input_comm" text, + "tech" text, + "vintage" integer, + "output_comm" text, + "activity" real, + "units" text, + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","emis_comm","input_comm","tech","vintage","output_comm", 'data_flags'), + FOREIGN KEY("input_comm") REFERENCES "Commodity"("name"), + FOREIGN KEY("tech") REFERENCES "Technology"("tech"), + FOREIGN KEY("vintage") REFERENCES "TimePeriod"("period"), + FOREIGN KEY("output_comm") REFERENCES "Commodity"("name"), + FOREIGN KEY("emis_comm") REFERENCES "Commodity"("name") +); +CREATE TABLE IF NOT EXISTS "Efficiency" ( + "region" text, + "input_comm" text, + "tech" text, + "vintage" integer, + "output_comm" text, + "efficiency" real CHECK("efficiency" > 0), + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","input_comm","tech","vintage","output_comm", 'data_flags'), + FOREIGN KEY("output_comm") REFERENCES "Commodity"("name"), + FOREIGN KEY("tech") REFERENCES "Technology"("tech"), + FOREIGN KEY("vintage") REFERENCES "TimePeriod"("period"), + FOREIGN KEY("input_comm") REFERENCES "Commodity"("name") +); +CREATE TABLE IF NOT EXISTS "Demand" ( + "region" text, + "period" integer, + "commodity" text, + "demand" real, + "units" text, + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","period","commodity", 'data_flags'), + FOREIGN KEY("period") REFERENCES "TimePeriod"("period"), + FOREIGN KEY("commodity") REFERENCES "Commodity"("name") +); +CREATE TABLE IF NOT EXISTS "CostVariable" ( + "region" text NOT NULL, + "period" integer NOT NULL, + "tech" text NOT NULL, + "vintage" integer NOT NULL, + "cost" real, + "units" text, + "notes" text, + "data_cost_variable" REAL, + "data_cost_year" INTEGER, + "data_curr" TEXT, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("data_curr") REFERENCES "currencies"("curr_label"), + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","period","tech","vintage", 'data_flags'), + FOREIGN KEY("tech") REFERENCES "Technology"("tech"), + FOREIGN KEY("vintage") REFERENCES "TimePeriod"("period"), + FOREIGN KEY("period") REFERENCES "TimePeriod"("period") +); +CREATE TABLE IF NOT EXISTS "CostInvest" ( + "region" text, + "tech" text, + "vintage" integer, + "cost" real, + "units" text, + "notes" text, + "data_cost_invest" REAL, + "data_cost_year" INTEGER, + "data_curr" TEXT, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("data_curr") REFERENCES "currencies"("curr_label"), + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","tech","vintage", 'data_flags'), + FOREIGN KEY("tech") REFERENCES "Technology"("tech"), + FOREIGN KEY("vintage") REFERENCES "TimePeriod"("period") +); +CREATE TABLE IF NOT EXISTS "CostFixed" ( + "region" text NOT NULL, + "period" integer NOT NULL, + "tech" text NOT NULL, + "vintage" integer NOT NULL, + "cost" real, + "units" text, + "notes" text, + "data_cost_fixed" REAL, + "data_cost_year" INTEGER, + "data_curr" TEXT, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("data_curr") REFERENCES "currencies"("curr_label"), + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","period","tech","vintage", 'data_flags'), + FOREIGN KEY("tech") REFERENCES "Technology"("tech"), + FOREIGN KEY("vintage") REFERENCES "TimePeriod"("period"), + FOREIGN KEY("period") REFERENCES "TimePeriod"("period") +); +CREATE TABLE IF NOT EXISTS "CapacityToActivity" ( + "region" text, + "tech" text, + "c2a" real, + "notes" TEXT, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","tech",'data_flags'), + FOREIGN KEY("tech") REFERENCES "Technology"("tech") +); +CREATE TABLE IF NOT EXISTS "CapacityFactorTech" ( + "region" text, + "season" text, + "tod" text, + "tech" text, + "factor" real CHECK("factor" >= 0 AND "factor" <= 1), + "cf_tech_notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","season","tod","tech", 'data_flags'), + FOREIGN KEY("season") REFERENCES "TimeSeason"("season"), + FOREIGN KEY("tod") REFERENCES "TimeOfDay"("tod"), + FOREIGN KEY("tech") REFERENCES "Technology"("tech") +); +CREATE TABLE IF NOT EXISTS "CapacityFactorProcess" ( + "region" text, + "season" text, + "tod" text, + "tech" text, + "vintage" integer, + "factor" real CHECK("factor" >= 0 AND "factor" <= 1), + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","season","tod","tech","vintage", 'data_flags'), + FOREIGN KEY("tech") REFERENCES "Technology"("tech"), + FOREIGN KEY("season") REFERENCES "TimeSeason"("season"), + FOREIGN KEY("tod") REFERENCES "TimeOfDay"("tod") +); +CREATE TABLE IF NOT EXISTS "CapacityCredit" ( + "region" text, + "period" integer, + "tech" text, + "vintage" integer, + "credit" real CHECK("credit" >= 0 AND "credit" <= 1), + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + PRIMARY KEY("region","period","tech","vintage",'data_flags') +); +CREATE TABLE IF NOT EXISTS "MaxResource" ( + "region" text, + "tech" text, + "max_res" real, + "units" text, + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + FOREIGN KEY("tech") REFERENCES "Technology"("tech"), + PRIMARY KEY("region","tech", 'data_flags') +); +CREATE TABLE IF NOT EXISTS "LinkedTech" ( + "primary_region" text, + "primary_tech" text, + "emis_comm" text, + "driven_tech" text, + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + FOREIGN KEY("primary_tech") REFERENCES "Technology"("tech"), + FOREIGN KEY("driven_tech") REFERENCES "Technology"("tech"), + FOREIGN KEY("emis_comm") REFERENCES "Commodity"("name"), + PRIMARY KEY("primary_region","primary_tech", "emis_comm", 'data_flags') +); +CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" ( + + "region" text, + + "period" integer, + + "season" text, + + "tech" text, + + "max_act" real, + + "units" text, + + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + FOREIGN KEY("period") REFERENCES "TimePeriod"("period"), + + FOREIGN KEY("season") REFERENCES "TimeSeason"("season"), + + FOREIGN KEY("tech") REFERENCES "Technology"("tech"), + + PRIMARY KEY("region","period","season","tech", 'data_flags') + +); +CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" ( + + "region" text, + + "period" integer, + + "season" text, + + "tech" text, + + "min_act" real, + + "units" text, + + "notes" text, + + "reference" text, + "data_year" integer, + "data_flags" text, + "dq_est" integer, + "dq_rel" integer, + "dq_comp" integer, + "dq_time" integer, + "dq_geog" integer, + "dq_tech" integer, + "additional_notes" text, + + FOREIGN KEY("reference") REFERENCES "references"("reference"), + FOREIGN KEY("dq_est") REFERENCES "dq_estimate"("data_quality_estimated"), + FOREIGN KEY("dq_rel") REFERENCES "dq_estimate"("data_quality_reliability"), + FOREIGN KEY("dq_comp") REFERENCES "dq_estimate"("data_quality_completeness"), + FOREIGN KEY("dq_time") REFERENCES "dq_estimate"("data_quality_time_related"), + FOREIGN KEY("dq_geog") REFERENCES "dq_estimate"("data_quality_geography"), + FOREIGN KEY("dq_tech") REFERENCES "dq_estimate"("data_quality_technology") + FOREIGN KEY("period") REFERENCES "TimePeriod"("period"), + + FOREIGN KEY("tech") REFERENCES "Technology"("tech"), + + FOREIGN KEY("season") REFERENCES "TimeSeason"("season"), + + PRIMARY KEY("region","period","season","tech",'data_flags') + +); +CREATE TABLE IF NOT EXISTS "references" ( + + "reference" text, + + CONSTRAINT references_PK PRIMARY KEY ("reference") +); +CREATE TABLE IF NOT EXISTS "CommodityType" ( +"label" TEXT, + "description" TEXT, + "reference" REAL, + "additional_notes" REAL +); +CREATE TABLE IF NOT EXISTS "currencies" ( +"curr_label" TEXT, + "currency_description" TEXT, + "reference" REAL, + "additional_notes" REAL +); +CREATE TABLE IF NOT EXISTS "dq_estimate" ( +"data_quality_estimated" INTEGER, + "dq_est_description" REAL, + "reference" REAL, + "additional_notes" REAL +); +CREATE TABLE IF NOT EXISTS "dq_reliability" ( +"data_quality_reliability" INTEGER, + "dq_rel_description" REAL, + "reference" REAL, + "additional_notes" REAL +); +CREATE TABLE IF NOT EXISTS "dq_completeness" ( +"data_quality_completeness" INTEGER, + "dq_comp_description" REAL, + "reference" REAL, + "additional_notes" REAL +); +CREATE TABLE IF NOT EXISTS "dq_time" ( +"data_quality_time_related" INTEGER, + "dq_time_description" REAL, + "reference" REAL, + "additional_notes" REAL +); +CREATE TABLE IF NOT EXISTS "dq_geography" ( +"data_quality_geography" INTEGER, + "dq_geog_description" REAL, + "reference" REAL, + "additional_notes" REAL +); +CREATE TABLE IF NOT EXISTS "dq_technology" ( +"data_quality_technology" INTEGER, + "dq_tech_description" REAL, + "reference" REAL, + "additional_notes" REAL +); +CREATE TABLE IF NOT EXISTS "Region" ( +"region" TEXT, + "region_note" TEXT, + "reference" REAL, + "additional_notes" REAL +); +CREATE TABLE IF NOT EXISTS "SectorLabel" ( +"sector" TEXT, + "reference" REAL, + "additional_notes" REAL +); +CREATE TABLE IF NOT EXISTS "TechnologyType" ( +"label" TEXT, + "description" TEXT, + "reference" REAL, + "additional_notes" REAL +); +CREATE TABLE IF NOT EXISTS "TimePeriodType" ( +"label" TEXT, + "description" TEXT, + "reference" REAL, + "additional_notes" REAL +); +CREATE TABLE IF NOT EXISTS "TimePeriod" ( +"period" INTEGER, + "flag" TEXT, + "reference" REAL, + "additional_notes" REAL +, sequence); +CREATE TABLE IF NOT EXISTS "TimeSeason" ( +"season" TEXT, + "reference" REAL, + "additional_notes" REAL +, sequence); +CREATE TABLE IF NOT EXISTS "TimeOfDay" ( +"tod" TEXT, + "reference" REAL, + "additional_notes" REAL +, sequence); +CREATE TABLE IF NOT EXISTS "StorageDuration" ( +"region" TEXT, + "tech" TEXT, + "duration" INTEGER, + "notes" TEXT, + "reference" REAL, + "data_year" REAL, + "data_flags" REAL, + "dq_est" REAL, + "dq_rel" REAL, + "dq_comp" REAL, + "dq_time" REAL, + "dq_geog" REAL, + "dq_tech" REAL, + "additional_notes" REAL +); +CREATE TABLE IF NOT EXISTS "DemandSpecificDistribution" ( +"region" TEXT, + "season" TEXT, + "tod" TEXT, + "demand_name" TEXT, + "dsd" REAL, + "notes" TEXT, + "reference" TEXT, + "data_year" INTEGER, + "data_flags" TEXT, + "dq_est" TEXT, + "dq_rel" INTEGER, + "dq_comp" INTEGER, + "dq_time" INTEGER, + "dq_geog" INTEGER, + "dq_tech" INTEGER, + "additional_notes" TEXT +); +CREATE TABLE CostEmission +( + region TEXT + REFERENCES Region (region), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT NOT NULL + REFERENCES Commodity (name), + cost REAL NOT NULL, + units TEXT, + notes TEXT, reference, data_year, data_flags, dq_est, dq_rel, dq_comp, dq_time, dq_geog, dq_tech, additional_notes, + PRIMARY KEY (region, period, emis_comm, 'data_flags') +); +CREATE TABLE LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + "data_flags" TEXT + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage, 'data_flags') +); +CREATE TABLE MaxActivityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + max_act REAL, + units TEXT, + notes TEXT, reference, data_year, data_flags, dq_est, dq_rel, dq_comp, dq_time, dq_geog, dq_tech, additional_notes, + PRIMARY KEY (region, period, group_name, 'data_flags') +); +CREATE TABLE MaxActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, reference, data_year, data_flags, dq_est, dq_rel, dq_comp, dq_time, dq_geog, dq_tech, additional_notes, + PRIMARY KEY (region, period, tech, group_name, 'data_flags') +); +CREATE TABLE MaxCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + max_cap REAL, + units TEXT, + notes TEXT, reference, data_year, data_flags, dq_est, dq_rel, dq_comp, dq_time, dq_geog, dq_tech, additional_notes, + PRIMARY KEY (region, period, group_name, 'data_flags') +); +CREATE TABLE MaxCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, reference, data_year, data_flags, dq_est, dq_rel, dq_comp, dq_time, dq_geog, dq_tech, additional_notes, + PRIMARY KEY (region, period, tech, group_name, 'data_flags') +); +CREATE TABLE MaxNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + max_cap REAL, + units TEXT, + notes TEXT, reference, data_year, data_flags, dq_est, dq_rel, dq_comp, dq_time, dq_geog, dq_tech, additional_notes, + PRIMARY KEY (region, period, tech, 'data_flags') +); +CREATE TABLE MaxNewCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + max_new_cap REAL, + units TEXT, + notes TEXT, reference, data_year, data_flags, dq_est, dq_rel, dq_comp, dq_time, dq_geog, dq_tech, additional_notes, + PRIMARY KEY (region, period, group_name, 'data_flags') +); +CREATE TABLE MaxNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, reference, data_year, data_flags, dq_est, dq_rel, dq_comp, dq_time, dq_geog, dq_tech, additional_notes, + PRIMARY KEY (region, period, tech, group_name, 'data_flags') +); +CREATE TABLE MetaData +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +CREATE TABLE MetaDataReal +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +CREATE TABLE MinActivityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + min_act REAL, + units TEXT, + notes TEXT, reference, data_year, data_flags, dq_est, dq_rel, dq_comp, dq_time, dq_geog, dq_tech, additional_notes, + PRIMARY KEY (region, period, group_name,'data_flags') +); +CREATE TABLE MinActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, reference, data_year, data_flags, dq_est, dq_rel, dq_comp, dq_time, dq_geog, dq_tech, additional_notes, + PRIMARY KEY (region, period, tech, group_name, 'data_flags') +); +CREATE TABLE MinCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + min_cap REAL, + units TEXT, + notes TEXT, reference, data_year, data_flags, dq_est, dq_rel, dq_comp, dq_time, dq_geog, dq_tech, additional_notes, + PRIMARY KEY (region, period, group_name, 'data_flags') +); +CREATE TABLE MinCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, reference, data_year, data_flags, dq_est, dq_rel, dq_comp, dq_time, dq_geog, dq_tech, additional_notes, + PRIMARY KEY (region, period, tech, group_name, 'data_flags') +); +CREATE TABLE MinNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + min_cap REAL, + units TEXT, + notes TEXT, reference, data_year, data_flags, dq_est, dq_rel, dq_comp, dq_time, dq_geog, dq_tech, additional_notes, + PRIMARY KEY (region, period, tech, 'data_flags') +); +CREATE TABLE MinNewCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + min_new_cap REAL, + units TEXT, + notes TEXT, reference, data_year, data_flags, dq_est, dq_rel, dq_comp, dq_time, dq_geog, dq_tech, additional_notes, + PRIMARY KEY (region, period, group_name, 'data_flags') +); +CREATE TABLE MinNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, reference, data_year, data_flags, dq_est, dq_rel, dq_comp, dq_time, dq_geog, dq_tech, additional_notes, + PRIMARY KEY (region, period, tech, group_name, 'data_flags') +); +CREATE TABLE OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE OutputCost +( + scenario TEXT, + region TEXT, + period INTEGER, + tech TEXT, + vintage INTEGER, + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES TimePeriod (period), + FOREIGN KEY (tech) REFERENCES Technology (tech) +); +CREATE TABLE OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputDualVariable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE OutputEmission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputFlowOut +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputObjective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE RPSRequirement +( + region TEXT NOT NULL + REFERENCES Region (region), + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech_group TEXT NOT NULL + REFERENCES TechGroup (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE StorageInit +( + tech TEXT + PRIMARY KEY, + value REAL, + notes TEXT +, reference, data_year, data_flags, dq_est, dq_rel, dq_comp, dq_time, dq_geog, dq_tech, additional_notes); +CREATE TABLE TechGroup +( + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE TechGroupMember +( + group_name TEXT + REFERENCES TechGroup (group_name), + tech TEXT + REFERENCES Technology (tech), + PRIMARY KEY (group_name, tech) +); From a110a67cdbc6988c912f57cf5171003310d5a3c9 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 14 Jan 2025 12:15:23 -0500 Subject: [PATCH 011/587] Merge latest Temoa 3 into CANOE --- data_files/my_configs/config_sample.toml | 2 +- temoa/temoa_model/table_data_puller.py | 2 ++ tests/testing_configs/config_emissions.toml | 6 +++--- tests/testing_configs/config_link_test.toml | 6 +++--- tests/testing_configs/config_mediumville.toml | 6 +++--- tests/testing_configs/config_storageville.toml | 6 +++--- tests/testing_configs/config_test_system.toml | 6 +++--- tests/testing_configs/config_utopia.toml | 6 +++--- tests/testing_configs/config_utopia_myopic.toml | 6 +++--- tests/testing_data/emissions.sql | 6 +++--- tests/testing_data/mediumville.sql | 6 +++--- tests/testing_data/simple_linked_tech.sql | 6 +++--- tests/testing_data/storageville.sql | 6 +++--- tests/testing_data/test_system.sql | 6 +++--- tests/testing_data/utopia.sql | 6 +++--- 15 files changed, 42 insertions(+), 40 deletions(-) diff --git a/data_files/my_configs/config_sample.toml b/data_files/my_configs/config_sample.toml index 1763880ab..b18e18c24 100644 --- a/data_files/my_configs/config_sample.toml +++ b/data_files/my_configs/config_sample.toml @@ -58,7 +58,7 @@ neos = false # solver (Mandatory) # Depending on what client machine has installed. # [cbc, appsi_highs, gurobi, cplex, ...] -solver_name = "cbc" +solver_name = "gurobi" # ------------------------------------ # OUTPUTS diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index 4301662cb..3a2ad85a1 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -385,6 +385,7 @@ def loan_costs( invest_cost, loan_annualize=loan_ar, lifetime_loan_process=loan_life, + lifetime_process=process_life, P_0=p_0, P_e=p_e, GDR=global_discount_rate, @@ -397,6 +398,7 @@ def loan_costs( invest_cost, loan_annualize=loan_ar, lifetime_loan_process=loan_life, + lifetime_process=process_life, P_0=p_0, P_e=p_e, GDR=global_discount_rate, diff --git a/tests/testing_configs/config_emissions.toml b/tests/testing_configs/config_emissions.toml index b3c9db6d7..6bbff4e5e 100644 --- a/tests/testing_configs/config_emissions.toml +++ b/tests/testing_configs/config_emissions.toml @@ -2,12 +2,12 @@ scenario = "test run" scenario_mode = "perfect_foresight" -input_database = "testing_outputs/emissions.sqlite" -output_database = "testing_outputs/emissions.sqlite" +input_database = "tests/testing_outputs/emissions.sqlite" +output_database = "tests/testing_outputs/emissions.sqlite" neos = false # solver -solver_name = "cbc" +solver_name = "gurobi" # generate an excel file in the output_files folder save_excel = false diff --git a/tests/testing_configs/config_link_test.toml b/tests/testing_configs/config_link_test.toml index 2edfc0a78..f725245be 100644 --- a/tests/testing_configs/config_link_test.toml +++ b/tests/testing_configs/config_link_test.toml @@ -18,13 +18,13 @@ scenario = "test_linked_tech" scenario_mode = "perfect_foresight" # Input database (Mandatory) -input_database = "testing_outputs/simple_linked_tech.sqlite" +input_database = "tests/testing_outputs/simple_linked_tech.sqlite" # Output file (Mandatory) # The output file must be an existing .sqlite file # For Pefrect Foresight, the user may target the same input file or a separate / # copied sqlite file in a different location. Myopic requires that input_database = output_database -output_database = "testing_outputs/simple_linked_tech.sqlite" +output_database = "tests/testing_outputs/simple_linked_tech.sqlite" # ------------------------------------ # DATA / MODEL CHECKS @@ -55,7 +55,7 @@ neos = false # solver (Mandatory) # Depending on what client machine has installed. # [cbc, appsi_highs, gurobi, cplex, ...] -solver_name = "cbc" +solver_name = "gurobi" # ------------------------------------ # OUTPUTS diff --git a/tests/testing_configs/config_mediumville.toml b/tests/testing_configs/config_mediumville.toml index 2fa7b0aaf..d363a6b3c 100644 --- a/tests/testing_configs/config_mediumville.toml +++ b/tests/testing_configs/config_mediumville.toml @@ -19,13 +19,13 @@ scenario_mode = "build_only" # Input file (Mandatory) # Input can be a .sqlite or .dat file # Both relative path and absolute path are accepted -input_database = "testing_outputs/mediumville.sqlite" +input_database = "tests/testing_outputs/mediumville.sqlite" # Output file (Mandatory) # The output file must be an existing .sqlite file # the user may target the same input file or a separate / # copied sqlite file in a different location -output_database = "testing_outputs/mediumville.sqlite" +output_database = "tests/testing_outputs/mediumville.sqlite" # ------------------------------------ # SOLVER @@ -36,7 +36,7 @@ output_database = "testing_outputs/mediumville.sqlite" neos = false # solver -solver_name = "cbc" +solver_name = "gurobi" # ------------------------------------ # OUTPUTS diff --git a/tests/testing_configs/config_storageville.toml b/tests/testing_configs/config_storageville.toml index 35ee7b05b..877be5fc0 100644 --- a/tests/testing_configs/config_storageville.toml +++ b/tests/testing_configs/config_storageville.toml @@ -19,13 +19,13 @@ scenario_mode = "perfect_foresight" # Input file (Mandatory) # Input can be a .sqlite or .dat file # Both relative path and absolute path are accepted -input_database = "testing_outputs/storageville.sqlite" +input_database = "tests/testing_outputs/storageville.sqlite" # Output file (Mandatory) # The output file must be an existing .sqlite file # the user may target the same input file or a separate / # copied sqlite file in a different location -output_database = "testing_outputs/storageville.sqlite" +output_database = "tests/testing_outputs/storageville.sqlite" # ------------------------------------ # SOLVER @@ -36,7 +36,7 @@ output_database = "testing_outputs/storageville.sqlite" neos = false # solver -solver_name = "cbc" +solver_name = "gurobi" # ------------------------------------ # OUTPUTS diff --git a/tests/testing_configs/config_test_system.toml b/tests/testing_configs/config_test_system.toml index 7ea66fc5e..6514086e6 100644 --- a/tests/testing_configs/config_test_system.toml +++ b/tests/testing_configs/config_test_system.toml @@ -2,12 +2,12 @@ scenario = "test run" scenario_mode = "perfect_foresight" -input_database = "testing_outputs/test_system.sqlite" -output_database = "testing_outputs/test_system.sqlite" +input_database = "tests/testing_outputs/test_system.sqlite" +output_database = "tests/testing_outputs/test_system.sqlite" neos = false # solver -solver_name = "cbc" +solver_name = "gurobi" # generate an excel file in the output_files folder save_excel = false diff --git a/tests/testing_configs/config_utopia.toml b/tests/testing_configs/config_utopia.toml index 8732362b3..8708215d8 100644 --- a/tests/testing_configs/config_utopia.toml +++ b/tests/testing_configs/config_utopia.toml @@ -2,12 +2,12 @@ scenario = "test run" scenario_mode = "perfect_foresight" -input_database = "testing_outputs/utopia.sqlite" -output_database = "testing_outputs/utopia.sqlite" +input_database = "tests/testing_outputs/utopia.sqlite" +output_database = "tests/testing_outputs/utopia.sqlite" neos = false # solver -solver_name = "cbc" +solver_name = "gurobi" # generate an excel file in the output_files folder save_excel = false diff --git a/tests/testing_configs/config_utopia_myopic.toml b/tests/testing_configs/config_utopia_myopic.toml index e9a14600d..a172edce1 100644 --- a/tests/testing_configs/config_utopia_myopic.toml +++ b/tests/testing_configs/config_utopia_myopic.toml @@ -4,12 +4,12 @@ scenario_mode = "myopic" # note that myopic currently only supports input = output. Test code will be responsible # for making a fresh copy (if desired) and moving it to the output folder -input_database = "testing_outputs/myo_utopia.sqlite" -output_database = "testing_outputs/myo_utopia.sqlite" +input_database = "tests/testing_outputs/myo_utopia.sqlite" +output_database = "tests/testing_outputs/myo_utopia.sqlite" neos = false # solver -solver_name = "cbc" +solver_name = "gurobi" # generate an excel file in the output_files folder save_excel = true diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 23203e965..06344fa12 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -203,10 +203,10 @@ CREATE TABLE DemandSpecificDistribution REFERENCES TimeOfDay (tod), demand_name TEXT REFERENCES Commodity (name), - dds REAL, - dds_notes TEXT, + dsd REAL, + dsd_notes TEXT, PRIMARY KEY (region, season, tod, demand_name), - CHECK (dds >= 0 AND dds <= 1) + CHECK (dsd >= 0 AND dsd <= 1) ); CREATE TABLE LoanRate ( diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 6d3315fb2..b2c7a2879 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -243,10 +243,10 @@ CREATE TABLE DemandSpecificDistribution REFERENCES TimeOfDay (tod), demand_name TEXT REFERENCES Commodity (name), - dds REAL, - dds_notes TEXT, + dsd REAL, + dsd_notes TEXT, PRIMARY KEY (region, season, tod, demand_name), - CHECK (dds >= 0 AND dds <= 1) + CHECK (dsd >= 0 AND dsd <= 1) ); INSERT INTO DemandSpecificDistribution VALUES('A','s1','d1','RL',0.25,NULL); INSERT INTO DemandSpecificDistribution VALUES('A','s1','d2','RL',0.25,NULL); diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index ce9a7fc71..12221d3dc 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -198,10 +198,10 @@ CREATE TABLE DemandSpecificDistribution REFERENCES TimeOfDay (tod), demand_name TEXT REFERENCES Commodity (name), - dds REAL, - dds_notes TEXT, + dsd REAL, + dsd_notes TEXT, PRIMARY KEY (region, season, tod, demand_name), - CHECK (dds >= 0 AND dds <= 1) + CHECK (dsd >= 0 AND dsd <= 1) ); INSERT INTO DemandSpecificDistribution VALUES('linkville','summer','day','ELC',0.5,''); INSERT INTO DemandSpecificDistribution VALUES('linkville','winter','day','ELC',0.5,''); diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index 0cf789f65..db9215315 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -198,10 +198,10 @@ CREATE TABLE DemandSpecificDistribution REFERENCES TimeOfDay (tod), demand_name TEXT REFERENCES Commodity (name), - dds REAL, - dds_notes TEXT, + dsd REAL, + dsd_notes TEXT, PRIMARY KEY (region, season, tod, demand_name), - CHECK (dds >= 0 AND dds <= 1) + CHECK (dsd >= 0 AND dsd <= 1) ); INSERT INTO DemandSpecificDistribution VALUES('electricville','s1','d1','RL',0.07499999999999999723,''); INSERT INTO DemandSpecificDistribution VALUES('electricville','s1','d2','RL',0.07499999999999999723,''); diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index d2a9b2939..5410a7122 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -414,10 +414,10 @@ CREATE TABLE DemandSpecificDistribution REFERENCES TimeOfDay (tod), demand_name TEXT REFERENCES Commodity (name), - dds REAL, - dds_notes TEXT, + dsd REAL, + dsd_notes TEXT, PRIMARY KEY (region, season, tod, demand_name), - CHECK (dds >= 0 AND dds <= 1) + CHECK (dsd >= 0 AND dsd <= 1) ); INSERT INTO DemandSpecificDistribution VALUES('R1','spring','day','RH',0.05000000000000000277,''); INSERT INTO DemandSpecificDistribution VALUES('R1','spring','night','RH',0.1000000000000000055,''); diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 2d49c629f..3586e3096 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -428,10 +428,10 @@ CREATE TABLE DemandSpecificDistribution REFERENCES TimeOfDay (tod), demand_name TEXT REFERENCES Commodity (name), - dds REAL, - dds_notes TEXT, + dsd REAL, + dsd_notes TEXT, PRIMARY KEY (region, season, tod, demand_name), - CHECK (dds >= 0 AND dds <= 1) + CHECK (dsd >= 0 AND dsd <= 1) ); INSERT INTO DemandSpecificDistribution VALUES('utopia','inter','day','RH',0.1199999999999999956,''); INSERT INTO DemandSpecificDistribution VALUES('utopia','inter','night','RH',0.05999999999999999778,''); From 4afe7178e414842c787910180fbdf1fd3516c58b Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 14 Jan 2025 12:57:55 -0500 Subject: [PATCH 012/587] Updating tests to CANOE changes so all pass --- .vscode/settings.json | 7 +++++++ tests/test_table_writer.py | 8 ++++---- tests/testing_data/mediumville_sets.json | 6 +++--- tests/testing_data/test_system_sets.json | 4 +++- tests/testing_data/utopia_sets.json | 4 +++- 5 files changed, 20 insertions(+), 9 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..9b388533a --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "python.testing.pytestArgs": [ + "tests" + ], + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true +} \ No newline at end of file diff --git a/tests/test_table_writer.py b/tests/test_table_writer.py index ac43c5f37..e966ae7b3 100644 --- a/tests/test_table_writer.py +++ b/tests/test_table_writer.py @@ -42,8 +42,8 @@ 'p_0': 2020, # the "myopic base year" to which all prices are discounted 'vintage': 2020, # the vintage of the new 'tech' 'p_e': 2100, # last year in the myopic view - 'model_cost': 409037.69, - 'undiscounted_cost': 409037.69, + 'model_cost': 409037.66, + 'undiscounted_cost': 409037.66, }, { 'ID': 'shortened term', @@ -56,8 +56,8 @@ 'p_0': 2020, 'vintage': 2030, 'p_e': 2035, - 'model_cost': 23403.85, - 'undiscounted_cost': 41930.08, + 'model_cost': 21997.72, + 'undiscounted_cost': 33544.06, }, ] params_with_zero_GDR = [ diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 74d7ac75f..6132ad718 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -114,9 +114,6 @@ "GeoThermal", "GeoHeater" ], - "tech_variable": [ - "GeoHeater" - ], "tech_retirement": [ "EH" ], @@ -4134,6 +4131,9 @@ ] ], "TechOutputSplitAnnualConstraint_rptvo": [], + "TechOutputSplitAverageConstraint_rptvo": [], + "MaxSeasonalActivityConstraint_rpst": [], + "MinSeasonalActivityConstraint_rpst": [], "LinkedEmissionsTechConstraint_rpsdtve": [ [ "A", diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index d49b39b14..4bc8413d4 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -128,7 +128,6 @@ "R_NGH", "E_TRANS" ], - "tech_variable": [], "tech_retirement": [], "commodity_demand": [ "VMT", @@ -45031,5 +45030,8 @@ ] ], "TechOutputSplitAnnualConstraint_rptvo": [], + "TechOutputSplitAverageConstraint_rptvo": [], + "MaxSeasonalActivityConstraint_rpst": [], + "MinSeasonalActivityConstraint_rpst": [], "LinkedEmissionsTechConstraint_rpsdtve": [] } \ No newline at end of file diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index fa218f837..e33d68126 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -132,7 +132,6 @@ "TXE", "TXG" ], - "tech_variable": [], "tech_retirement": [], "commodity_demand": [ "RH", @@ -25326,5 +25325,8 @@ ] ], "TechOutputSplitAnnualConstraint_rptvo": [], + "TechOutputSplitAverageConstraint_rptvo": [], + "MaxSeasonalActivityConstraint_rpst": [], + "MinSeasonalActivityConstraint_rpst": [], "LinkedEmissionsTechConstraint_rpsdtve": [] } \ No newline at end of file From b162692abb74df8c203e8450f06b0caf554edff4 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 6 Aug 2025 14:41:48 -0400 Subject: [PATCH 013/587] Renaming SplitAverage tables to SplitAnnual and squash dds --- data_files/example_dbs/morris_utopia.sql | 8 ++-- data_files/example_dbs/stepped_demand.sql | 8 ++-- data_files/example_dbs/test_system.sql | 4 +- data_files/example_dbs/utopia.sql | 8 ++-- temoa/temoa_model/hybrid_loader.py | 41 ++++++++++++----- temoa/temoa_model/temoa_initialize.py | 40 ++++++++--------- temoa/temoa_model/temoa_model.py | 8 ++-- temoa/temoa_model/temoa_rules.py | 8 ++-- tests/testing_data/emissions.sql | 2 +- tests/testing_data/mediumville.sql | 4 +- tests/testing_data/simple_linked_tech.sql | 2 +- tests/testing_data/storageville.sql | 2 +- tests/testing_data/test_system.sql | 2 +- tests/testing_data/utopia.sql | 54 ++++++++++++++--------- 14 files changed, 110 insertions(+), 81 deletions(-) diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index 9eb1b62b8..be83fff42 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -320,10 +320,10 @@ CREATE TABLE DemandSpecificDistribution REFERENCES TimeOfDay (tod), demand_name TEXT REFERENCES Commodity (name), - dds REAL, - dds_notes TEXT, + dsd REAL, + dsd_notes TEXT, PRIMARY KEY (region, season, tod, demand_name), - CHECK (dds >= 0 AND dds <= 1) + CHECK (dsd >= 0 AND dsd <= 1) ); INSERT INTO DemandSpecificDistribution VALUES('utopia','inter','night','RH',0.06,''); INSERT INTO DemandSpecificDistribution VALUES('utopia','winter','day','RH',0.54669999999999996376,''); @@ -796,7 +796,7 @@ CREATE TABLE TechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechInputSplitAverage +CREATE TABLE TechInputSplitAnnual ( region TEXT, period INTEGER diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index 6b6fce42d..a6acd8b4f 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -273,10 +273,10 @@ CREATE TABLE DemandSpecificDistribution REFERENCES TimeOfDay (tod), demand_name TEXT REFERENCES Commodity (name), - dds REAL, - dds_notes TEXT, + dsd REAL, + dsd_notes TEXT, PRIMARY KEY (region, season, tod, demand_name), - CHECK (dds >= 0 AND dds <= 1) + CHECK (dsd >= 0 AND dsd <= 1) ); INSERT INTO DemandSpecificDistribution VALUES('electricville','inter','day','RL',0.3332999999999999852,''); INSERT INTO DemandSpecificDistribution VALUES('electricville','summer','day','RL',0.3332999999999999852,''); @@ -1007,7 +1007,7 @@ CREATE TABLE TechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechInputSplitAverage +CREATE TABLE TechInputSplitAnnual ( region TEXT, period INTEGER diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index 35767f2af..2370d6d85 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -727,8 +727,8 @@ CREATE TABLE "DemandSpecificDistribution" ( "season_name" text, "time_of_day_name" text, "demand_name" text, - "dds" real CHECK("dds" >= 0 AND "dds" <= 1), - "dds_notes" text, + "dsd" real CHECK("dsd" >= 0 AND "dsd" <= 1), + "dsd_notes" text, PRIMARY KEY("regions","season_name","time_of_day_name","demand_name"), FOREIGN KEY("time_of_day_name") REFERENCES "time_of_day"("t_day"), FOREIGN KEY("season_name") REFERENCES "time_season"("t_season"), diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 704867bb6..d25e031ad 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -428,10 +428,10 @@ CREATE TABLE DemandSpecificDistribution REFERENCES TimeOfDay (tod), demand_name TEXT REFERENCES Commodity (name), - dds REAL, - dds_notes TEXT, + dsd REAL, + dsd_notes TEXT, PRIMARY KEY (region, season, tod, demand_name), - CHECK (dds >= 0 AND dds <= 1) + CHECK (dsd >= 0 AND dsd <= 1) ); INSERT INTO DemandSpecificDistribution VALUES('utopia','inter','day','RH',0.1199999999999999956,''); INSERT INTO DemandSpecificDistribution VALUES('utopia','inter','night','RH',0.05999999999999999778,''); @@ -984,7 +984,7 @@ CREATE TABLE TechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechInputSplitAverage +CREATE TABLE TechInputSplitAnnual ( region TEXT, period INTEGER diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index fceae5d6d..e95909c1a 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -644,21 +644,21 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): ic, ) - # TechInputSplitAverage - if self.table_exists('TechInputSplitAverage'): + # TechInputSplitAnnual + if self.table_exists('TechInputSplitAnnual'): if mi: raw = cur.execute( 'SELECT region, period, input_comm, tech, min_proportion ' - 'FROM main.TechInputSplitAverage ' + 'FROM main.TechInputSplitAnnual ' 'WHERE period >= ? AND period <= ?', (mi.base_year, mi.last_demand_year), ).fetchall() else: raw = cur.execute( 'SELECT region, period, input_comm, tech, min_proportion ' - 'FROM main.TechInputSplitAverage ' + 'FROM main.TechInputSplitAnnual ' ).fetchall() - loaded = load_element(M.TechInputSplitAverage, raw, self.viable_rpit, (0, 1, 2, 3)) + loaded = load_element(M.TechInputSplitAnnual, raw, self.viable_rpit, (0, 1, 2, 3)) # we need to see if anything was filtered out here and raise warning if so as it may have invalidated # a blending process and any missing items should be reviewed if len(loaded) < len(raw): @@ -666,7 +666,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): for item in sorted(missing, key=lambda x: (x[0], x[1], x[3], x[2])): region, period, ic, tech, _ = item logger.warning( - 'Technology Input Split requirement in region %s, period %d for tech %s with input' + 'Technology Input Split Annual requirement in region %s, period %d for tech %s with input' 'commodity %s has ' 'been removed because the tech path with that input is ' 'invalid/not available/orphan. See the other warnings for this TECH in ' @@ -697,7 +697,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): logger.warning( 'Technology Output Split requirement in region %s, period %d for tech %s with output' 'commodity %s has ' - 'been removed because the tech path with that input is ' + 'been removed because the tech path with that output is ' 'invalid/not available/orphan. See the other warnings for this TECH in ' 'this region-period, and check for availability of all components in data.', region, @@ -706,21 +706,38 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): oc, ) - # TechOutputSplitAverage - if self.table_exists('TechOutputSplitAverage'): + # TechOutputSplitAnnual + if self.table_exists('TechOutputSplitAnnual'): if mi: raw = cur.execute( 'SELECT region, period, tech, output_comm, min_proportion ' - 'FROM main.TechOutputSplitAverage ' + 'FROM main.TechOutputSplitAnnual ' 'WHERE period >= ? AND period <= ?', (mi.base_year, mi.last_demand_year), ).fetchall() else: raw = cur.execute( 'SELECT region, period, tech, output_comm, min_proportion ' - 'FROM main.TechOutputSplitAverage ' + 'FROM main.TechOutputSplitAnnual ' ).fetchall() - load_element(M.TechOutputSplitAverage, raw, self.viable_rt, (0, 2)) + loaded = load_element(M.TechOutputSplitAnnual, raw, self.viable_rpto, (0, 1, 2, 3)) + # we need to see if anything was filtered out here and raise warning if so as it may have invalidated + # a blending process and any missing items should be reviewed + if len(loaded) < len(raw): + missing = set(raw) - set(loaded) + for item in sorted(missing): + region, period, tech, oc, _ = item + logger.warning( + 'Technology Output Split Annual requirement in region %s, period %d for tech %s with output' + 'commodity %s has ' + 'been removed because the tech path with that output is ' + 'invalid/not available/orphan. See the other warnings for this TECH in ' + 'this region-period, and check for availability of all components in data.', + region, + period, + tech, + oc, + ) # RenewablePortfolioStandard if self.table_exists('RPSRequirement'): diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index aab2f7727..76b959209 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -685,13 +685,13 @@ def CreateSparseDicts(M: 'TemoaModel'): t, ) not in M.inputsplitVintages: M.inputsplitVintages[r, p, i, t] = set() - if (r, p, i, t) in M.TechInputSplitAverage.sparse_iterkeys() and ( + if (r, p, i, t) in M.TechInputSplitAnnual.sparse_iterkeys() and ( r, p, i, t, - ) not in M.inputsplitaverageVintages: - M.inputsplitaverageVintages[r, p, i, t] = set() + ) not in M.inputsplitannualVintages: + M.inputsplitannualVintages[r, p, i, t] = set() if (r, p, t, o) in M.TechOutputSplit.sparse_iterkeys() and ( r, p, @@ -699,13 +699,13 @@ def CreateSparseDicts(M: 'TemoaModel'): o, ) not in M.outputsplitVintages: M.outputsplitVintages[r, p, t, o] = set() - if (r, p, t, o) in M.TechOutputSplitAverage.sparse_iterkeys() and ( + if (r, p, t, o) in M.TechOutputSplitAnnual.sparse_iterkeys() and ( r, p, t, o, - ) not in M.outputsplitaverageVintages: - M.outputsplitaverageVintages[r, p, t, o] = set() + ) not in M.outputsplitannualVintages: + M.outputsplitannualVintages[r, p, t, o] = set() if t in M.tech_resource and (r, p, o) not in M.ProcessByPeriodAndOutput: M.ProcessByPeriodAndOutput[r, p, o] = set() if t in M.tech_reserve and (r, p) not in M.processReservePeriods: @@ -739,12 +739,12 @@ def CreateSparseDicts(M: 'TemoaModel'): M.rampVintages[r, p, t].add(v) if (r, p, i, t) in M.TechInputSplit.sparse_iterkeys(): M.inputsplitVintages[r, p, i, t].add(v) - if (r, p, i, t) in M.TechInputSplitAverage.sparse_iterkeys(): - M.inputsplitaverageVintages[r, p, i, t].add(v) + if (r, p, i, t) in M.TechInputSplitAnnual.sparse_iterkeys(): + M.inputsplitannualVintages[r, p, i, t].add(v) if (r, p, t, o) in M.TechOutputSplit.sparse_iterkeys(): M.outputsplitVintages[r, p, t, o].add(v) - if (r, p, t, o) in M.TechOutputSplitAverage.sparse_iterkeys(): - M.outputsplitaverageVintages[r, p, t, o].add(v) + if (r, p, t, o) in M.TechOutputSplitAnnual.sparse_iterkeys(): + M.outputsplitannualVintages[r, p, t, o].add(v) if t in M.tech_resource: M.ProcessByPeriodAndOutput[r, p, o].add((i, t, v)) if t in M.tech_reserve: @@ -1317,7 +1317,7 @@ def TechInputSplitConstraintIndices(M: 'TemoaModel'): if len(ann_indices) > 0: msg = ( "Warning: Annual technologies included in TechInputSplit table. " - "Use TechInputSplitAverage table instead or these constraints will be ignored: {}" + "Use TechInputSplitAnnual table instead or these constraints will be ignored: {}" ) logger.warning(msg.format(ann_indices)) @@ -1327,9 +1327,9 @@ def TechInputSplitConstraintIndices(M: 'TemoaModel'): def TechInputSplitAnnualConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, i, t, v) - for r, p, i, t in M.inputsplitaverageVintages.keys() + for r, p, i, t in M.inputsplitannualVintages.keys() if t in M.tech_annual - for v in M.inputsplitaverageVintages[r, p, i, t] + for v in M.inputsplitannualVintages[r, p, i, t] ) return indices @@ -1338,9 +1338,9 @@ def TechInputSplitAnnualConstraintIndices(M: 'TemoaModel'): def TechInputSplitAverageConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, i, t, v) - for r, p, i, t in M.inputsplitaverageVintages.keys() + for r, p, i, t in M.inputsplitannualVintages.keys() if t not in M.tech_annual - for v in M.inputsplitaverageVintages[r, p, i, t] + for v in M.inputsplitannualVintages[r, p, i, t] ) return indices @@ -1362,7 +1362,7 @@ def TechOutputSplitConstraintIndices(M: 'TemoaModel'): if len(ann_indices) > 0: msg = ( "Warning: Annual technologies included in TechOutputSplit table. " - "Use TechOutputSplitAverage table instead or these constraints will be ignored: {}" + "Use TechOutputSplitAnnual table instead or these constraints will be ignored: {}" ) logger.warning(msg.format(ann_indices)) @@ -1372,9 +1372,9 @@ def TechOutputSplitConstraintIndices(M: 'TemoaModel'): def TechOutputSplitAnnualConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, t, v, o) - for r, p, t, o in M.outputsplitaverageVintages.keys() + for r, p, t, o in M.outputsplitannualVintages.keys() if t in M.tech_annual - for v in M.outputsplitaverageVintages[r, p, t, o] + for v in M.outputsplitannualVintages[r, p, t, o] ) return indices @@ -1383,9 +1383,9 @@ def TechOutputSplitAnnualConstraintIndices(M: 'TemoaModel'): def TechOutputSplitAverageConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, t, v, o) - for r, p, t, o in M.outputsplitaverageVintages.keys() + for r, p, t, o in M.outputsplitannualVintages.keys() if t not in M.tech_annual - for v in M.outputsplitaverageVintages[r, p, t, o] + for v in M.outputsplitannualVintages[r, p, t, o] ) return indices diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index acea7a5d3..c54bd3320 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -105,9 +105,9 @@ def __init__(M, *args, **kwargs): M.storageVintages = dict() M.rampVintages = dict() M.inputsplitVintages = dict() - M.inputsplitaverageVintages = dict() + M.inputsplitannualVintages = dict() M.outputsplitVintages = dict() - M.outputsplitaverageVintages = dict() + M.outputsplitannualVintages = dict() M.ProcessByPeriodAndOutput = dict() M.exportRegions = dict() M.importRegions = dict() @@ -295,9 +295,9 @@ def __init__(M, *args, **kwargs): M.LoanLifetimeProcess = Param(M.LoanLifetimeProcess_rtv, default=get_loan_life) M.TechInputSplit = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all) - M.TechInputSplitAverage = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all) + M.TechInputSplitAnnual = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all) M.TechOutputSplit = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier) - M.TechOutputSplitAverage = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier) + M.TechOutputSplitAnnual = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier) M.RenewablePortfolioStandardConstraint_rpg = Set( within=M.regions * M.time_optimize * M.tech_group_names diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index ae5fab8dd..42acf8795 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -2856,7 +2856,7 @@ def TechInputSplitAnnual_Constraint(M: 'TemoaModel', r, p, i, t, v): for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] ) - expr = inp >= M.TechInputSplitAverage[r, p, i, t] * total_inp + expr = inp >= M.TechInputSplitAnnual[r, p, i, t] * total_inp return expr @@ -2884,7 +2884,7 @@ def TechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v): for S_o in M.ProcessOutputsByInput[r, p, t, v, i] ) - expr = inp >= M.TechInputSplitAverage[r, p, i, t] * total_inp + expr = inp >= M.TechInputSplitAnnual[r, p, i, t] * total_inp return expr @@ -2963,7 +2963,7 @@ def TechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o): for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] ) - expr = out >= M.TechOutputSplitAverage[r, p, t, o] * total_out + expr = out >= M.TechOutputSplitAnnual[r, p, t, o] * total_out return expr @@ -2991,7 +2991,7 @@ def TechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o): for S_d in M.time_of_day ) - expr = out >= M.TechOutputSplitAverage[r, p, t, o] * total_out + expr = out >= M.TechOutputSplitAnnual[r, p, t, o] * total_out return expr diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 06344fa12..8b6c97397 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -625,7 +625,7 @@ CREATE TABLE TechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechInputSplitAverage +CREATE TABLE TechInputSplitAnnual ( region TEXT, period INTEGER diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index b2c7a2879..72e6d51bb 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -713,7 +713,7 @@ CREATE TABLE TechInputSplit PRIMARY KEY (region, period, input_comm, tech) ); INSERT INTO TechInputSplit VALUES('A',2025,'HYD','EH',0.949999999999999956,'95% HYD reqt. (other not specified...)'); -CREATE TABLE TechInputSplitAverage +CREATE TABLE TechInputSplitAnnual ( region TEXT, period INTEGER @@ -726,7 +726,7 @@ CREATE TABLE TechInputSplitAverage notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -INSERT INTO TechInputSplitAverage VALUES('A',2025,'GeoHyd','GeoHeater',0.8000000000000000444,'80% geothermal'); +INSERT INTO TechInputSplitAnnual VALUES('A',2025,'GeoHyd','GeoHeater',0.8000000000000000444,'80% geothermal'); CREATE TABLE TechOutputSplit ( region TEXT, diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index 12221d3dc..9ce704833 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -610,7 +610,7 @@ CREATE TABLE TechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechInputSplitAverage +CREATE TABLE TechInputSplitAnnual ( region TEXT, period INTEGER diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index db9215315..ca9c9e166 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -630,7 +630,7 @@ CREATE TABLE TechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechInputSplitAverage +CREATE TABLE TechInputSplitAnnual ( region TEXT, period INTEGER diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 5410a7122..16b1e01d0 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -1005,7 +1005,7 @@ INSERT INTO TechInputSplit VALUES('R2',2025,'GSL','T_BLND',0.7199999999999999734 INSERT INTO TechInputSplit VALUES('R2',2025,'ETH','T_BLND',0.08000000000000000166,''); INSERT INTO TechInputSplit VALUES('R2',2030,'GSL','T_BLND',0.7199999999999999734,''); INSERT INTO TechInputSplit VALUES('R2',2030,'ETH','T_BLND',0.08000000000000000166,''); -CREATE TABLE TechInputSplitAverage +CREATE TABLE TechInputSplitAnnual ( region TEXT, period INTEGER diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 3586e3096..ff69a0e14 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -984,7 +984,7 @@ CREATE TABLE TechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechInputSplitAverage +CREATE TABLE TechInputSplitAnnual ( region TEXT, period INTEGER @@ -1016,6 +1016,19 @@ INSERT INTO TechOutputSplit VALUES('utopia',2010,'SRE','DSL',0.69999999999999995 INSERT INTO TechOutputSplit VALUES('utopia',1990,'SRE','GSL',0.2999999999999999889,''); INSERT INTO TechOutputSplit VALUES('utopia',2000,'SRE','GSL',0.2999999999999999889,''); INSERT INTO TechOutputSplit VALUES('utopia',2010,'SRE','GSL',0.2999999999999999889,''); +CREATE TABLE TechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -1297,30 +1310,29 @@ CREATE TABLE Technology curtail INTEGER NOT NULL DEFAULT 0, retire INTEGER NOT NULL DEFAULT 0, flex INTEGER NOT NULL DEFAULT 0, - variable INTEGER NOT NULL DEFAULT 0, exchange INTEGER NOT NULL DEFAULT 0, description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('IMPDSL1','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported diesel'); -INSERT INTO Technology VALUES('IMPGSL1','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported gasoline'); -INSERT INTO Technology VALUES('IMPHCO1','r','supply','coal','',1,0,0,0,0,0,0,0,' imported coal'); -INSERT INTO Technology VALUES('IMPOIL1','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO Technology VALUES('IMPURN1','r','supply','nuclear','',1,0,0,0,0,0,0,0,' imported uranium'); -INSERT INTO Technology VALUES('IMPFEQ','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported fossil equivalent'); -INSERT INTO Technology VALUES('IMPHYD','r','supply','hydro','',1,0,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); -INSERT INTO Technology VALUES('E01','pb','electric','coal','',0,0,0,0,0,0,0,0,' coal power plant'); -INSERT INTO Technology VALUES('E21','pb','electric','nuclear','',0,0,0,0,0,0,0,0,' nuclear power plant'); -INSERT INTO Technology VALUES('E31','pb','electric','hydro','',0,0,0,0,0,0,0,0,' hydro power'); -INSERT INTO Technology VALUES('E51','ps','electric','electric','',0,0,0,0,0,0,0,0,' electric storage'); -INSERT INTO Technology VALUES('E70','p','electric','petroleum','',0,0,0,0,0,0,0,0,' diesel power plant'); -INSERT INTO Technology VALUES('RHE','p','residential','electric','',0,0,0,0,0,0,0,0,' electric residential heating'); -INSERT INTO Technology VALUES('RHO','p','residential','petroleum','',0,0,0,0,0,0,0,0,' diesel residential heating'); -INSERT INTO Technology VALUES('RL1','p','residential','electric','',0,0,0,0,0,0,0,0,' residential lighting'); -INSERT INTO Technology VALUES('SRE','p','supply','petroleum','',0,0,0,0,0,0,0,0,' crude oil processor'); -INSERT INTO Technology VALUES('TXD','p','transport','petroleum','',0,0,0,0,0,0,0,0,' diesel powered vehicles'); -INSERT INTO Technology VALUES('TXE','p','transport','electric','',0,0,0,0,0,0,0,0,' electric powered vehicles'); -INSERT INTO Technology VALUES('TXG','p','transport','petroleum','',0,0,0,0,0,0,0,0,' gasoline powered vehicles'); +INSERT INTO Technology VALUES('IMPDSL1','r','supply','petroleum','',1,0,0,0,0,0,0,' imported diesel'); +INSERT INTO Technology VALUES('IMPGSL1','r','supply','petroleum','',1,0,0,0,0,0,0,' imported gasoline'); +INSERT INTO Technology VALUES('IMPHCO1','r','supply','coal','',1,0,0,0,0,0,0,' imported coal'); +INSERT INTO Technology VALUES('IMPOIL1','r','supply','petroleum','',1,0,0,0,0,0,0,' imported crude oil'); +INSERT INTO Technology VALUES('IMPURN1','r','supply','nuclear','',1,0,0,0,0,0,0,' imported uranium'); +INSERT INTO Technology VALUES('IMPFEQ','r','supply','petroleum','',1,0,0,0,0,0,0,' imported fossil equivalent'); +INSERT INTO Technology VALUES('IMPHYD','r','supply','hydro','',1,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); +INSERT INTO Technology VALUES('E01','pb','electric','coal','',0,0,0,0,0,0,0,' coal power plant'); +INSERT INTO Technology VALUES('E21','pb','electric','nuclear','',0,0,0,0,0,0,0,' nuclear power plant'); +INSERT INTO Technology VALUES('E31','pb','electric','hydro','',0,0,0,0,0,0,0,' hydro power'); +INSERT INTO Technology VALUES('E51','ps','electric','electric','',0,0,0,0,0,0,0,' electric storage'); +INSERT INTO Technology VALUES('E70','p','electric','petroleum','',0,0,0,0,0,0,0,' diesel power plant'); +INSERT INTO Technology VALUES('RHE','p','residential','electric','',0,0,0,0,0,0,0,' electric residential heating'); +INSERT INTO Technology VALUES('RHO','p','residential','petroleum','',0,0,0,0,0,0,0,' diesel residential heating'); +INSERT INTO Technology VALUES('RL1','p','residential','electric','',0,0,0,0,0,0,0,' residential lighting'); +INSERT INTO Technology VALUES('SRE','p','supply','petroleum','',0,0,0,0,0,0,0,' crude oil processor'); +INSERT INTO Technology VALUES('TXD','p','transport','petroleum','',0,0,0,0,0,0,0,' diesel powered vehicles'); +INSERT INTO Technology VALUES('TXE','p','transport','electric','',0,0,0,0,0,0,0,' electric powered vehicles'); +INSERT INTO Technology VALUES('TXG','p','transport','petroleum','',0,0,0,0,0,0,0,' gasoline powered vehicles'); CREATE TABLE OutputCost ( scenario TEXT, From e8db51a240f8fef9058760aa9e557188c91cb0d7 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 6 Aug 2025 14:46:15 -0400 Subject: [PATCH 014/587] Add annual commodities --- temoa/temoa_model/hybrid_loader.py | 6 +- temoa/temoa_model/temoa_initialize.py | 71 ++++--- temoa/temoa_model/temoa_model.py | 18 +- temoa/temoa_model/temoa_rules.py | 242 ++++++++++++----------- tests/testing_data/mediumville_sets.json | 61 ++++-- tests/testing_data/test_system_sets.json | 10 +- tests/testing_data/utopia_sets.json | 10 +- 7 files changed, 224 insertions(+), 194 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index e95909c1a..88b9d5006 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -506,7 +506,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # commodity_physical raw = cur.execute( - "SELECT name FROM main.Commodity WHERE flag = 'p' OR flag = 's'" + "SELECT name FROM main.Commodity WHERE flag = 'p' OR flag = 's' OR flag = 'a'" ).fetchall() # The model enforces 0 symmetric difference between the physical commodities # and the input commodities, so we need to include only the viable INPUTS @@ -516,6 +516,10 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): raw = cur.execute("SELECT name FROM main.Commodity WHERE flag = 's'").fetchall() load_element(M.commodity_source, raw, self.viable_input_comms) + # commodity_annual + raw = cur.execute("SELECT name FROM main.Commodity WHERE flag = 'a'").fetchall() + load_element(M.commodity_annual, raw, self.viable_input_comms) + # === PARAMS === # Efficiency diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 76b959209..411d0de59 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -66,45 +66,46 @@ def get_str_padding(obj): return len(str(obj)) -def CommodityBalanceConstraintErrorCheck(vflow_out, vflow_in, r, p, s, d, c): - # an "int" here indicates that the summation ended up without any variables (empty) - if isinstance(vflow_out, int): - flow_in_expr = StringIO() - vflow_in.pprint(ostream=flow_in_expr) +def CommodityBalanceConstraintErrorCheck(supplied, demanded, r, p, s, d, c): + # note: if a pyomo equation simplifies to an int, there are no variables in it, which + # is an indicator of a problem. How this might come up I do not know + if isinstance(supplied, int) or isinstance(demanded, int): + expr = str(supplied == demanded) msg = ( - "Unable to meet an interprocess '{}' transfer in ({}, {}, {}).\n" - 'No flow out. Constraint flow in:\n {}\n' + "Unable to balance commodity {} in ({}, {}, {}, {}).\n" + 'No flows on one side of constraint expression:\n' + ' {}\n' 'Possible reasons:\n' " - Is there a missing period in set 'time_future'?\n" " - Is there a missing tech in set 'tech_resource'?\n" " - Is there a missing tech in set 'tech_production'?\n" " - Is there a missing commodity in set 'commodity_physical'?\n" - ' - Are there missing entries in the Efficiency parameter?\n' - ' - Does a process need a longer LifetimeProcess parameter setting?' + ' - Are there missing entries in the Efficiency table?\n' + ' - Does a process need a longer Lifetime?' ) - logger.error(msg.format(r, c, s, d, p, flow_in_expr.getvalue())) - raise Exception(msg.format(r, c, s, d, p, flow_in_expr.getvalue())) + logger.error(msg.format(c, r, p, s, d, expr)) + raise Exception(msg.format(c, r, p, s, d, expr)) -def CommodityBalanceConstraintErrorCheckAnnual(vflow_out, vflow_in, r, p, c): +def AnnualCommodityBalanceConstraintErrorCheck(supplied, demanded, r, p, c): # note: if a pyomo equation simplifies to an int, there are no variables in it, which - # is an indicator of a problem - if isinstance(vflow_out, int): - flow_in_expr = StringIO() - vflow_in.pprint(ostream=flow_in_expr) + # is an indicator of a problem. How this might come up I do not know + if isinstance(supplied, int) or isinstance(demanded, int): + expr = str(supplied == demanded) msg = ( - "Unable to meet an interprocess '{}' transfer in ({}, {}, {}).\n" - 'No flow out. Constraint flow in:\n {}\n' + "Unable to balance annual commodity {} in ({}, {}).\n" + 'No flows on one side of constraint expression:\n' + ' {}\n' 'Possible reasons:\n' " - Is there a missing period in set 'time_future'?\n" " - Is there a missing tech in set 'tech_resource'?\n" " - Is there a missing tech in set 'tech_production'?\n" " - Is there a missing commodity in set 'commodity_physical'?\n" - ' - Are there missing entries in the Efficiency parameter?\n' - ' - Does a process need a longer LifetimeProcess parameter setting?' + ' - Are there missing entries in the Efficiency table?\n' + ' - Does a process need a longer Lifetime?' ) - logger.error(msg) - raise Exception(msg.format(r, c, p, flow_in_expr.getvalue())) + logger.error(msg.format(c, r, p, expr)) + raise Exception(msg.format(c, r, p, expr)) def DemandConstraintErrorCheck(supply, r, p, s, d, dem): @@ -112,14 +113,14 @@ def DemandConstraintErrorCheck(supply, r, p, s, d, dem): # is an indicator of a problem if isinstance(supply, int): msg = ( - "Error: Demand '{}' for ({}, {}, {}) unable to be met by any " + "Error: Demand '{}' for ({}, {}, {}, {}) unable to be met by any " 'technology.\n\tPossible reasons:\n' ' - Is the Efficiency parameter missing an entry for this demand?\n' ' - Does a tech that satisfies this demand need a longer ' - 'LifetimeProcess?\n' + 'Lifetime?\n' ) logger.error(msg) - raise Exception(msg.format(r, dem, p, s, d)) + raise Exception(msg.format(dem, r, p, s, d)) def validate_time(M: 'TemoaModel'): @@ -1199,14 +1200,13 @@ def CommodityBalanceConstraintIndices(M: 'TemoaModel'): # technologies with varying output at the time slice level. period_commodity_with_up = set(M.commodityUStreamProcess.keys()) period_commodity_with_dn = set(M.commodityDStreamProcess.keys()) - period_commodity = period_commodity_with_up.intersection(period_commodity_with_dn) + balanceable_rpc = period_commodity_with_up.intersection(period_commodity_with_dn) indices = set( - (r, p, s, d, o) - for r, p, o in period_commodity + (r, p, s, d, c) + for r, p, c in balanceable_rpc # r in this line includes interregional transfer combinations (not needed). if r in M.regions # this line ensures only the regions are included. - for t, v in M.commodityUStreamProcess[r, p, o] - if (r, t) not in M.tech_storage and t not in M.tech_annual + and c not in M.commodity_annual for s in M.time_season for d in M.time_of_day ) @@ -1214,19 +1214,18 @@ def CommodityBalanceConstraintIndices(M: 'TemoaModel'): return indices -def CommodityBalanceAnnualConstraintIndices(M: 'TemoaModel'): +def AnnualCommodityBalanceConstraintIndices(M: 'TemoaModel'): # Generate indices only for those commodities that are produced by # technologies with constant annual output. period_commodity_with_up = set(M.commodityUStreamProcess.keys()) period_commodity_with_dn = set(M.commodityDStreamProcess.keys()) - period_commodity = period_commodity_with_up.intersection(period_commodity_with_dn) + balanceable_rpc = period_commodity_with_up.intersection(period_commodity_with_dn) indices = set( - (r, p, o) - for r, p, o in period_commodity + (r, p, c) + for r, p, c in balanceable_rpc # r in this line includes interregional transfer combinations (not needed). if r in M.regions # this line ensures only the regions are included. - for t, v in M.commodityUStreamProcess[r, p, o] - if (r, t) not in M.tech_storage and t in M.tech_annual + and c in M.commodity_annual ) return indices diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index c54bd3320..adc5f2765 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -178,20 +178,12 @@ def __init__(M, *args, **kwargs): M.commodity_emissions = Set() M.commodity_physical = Set() M.commodity_source = Set(within=M.commodity_physical) + M.commodity_annual = Set(within=M.commodity_physical) M.commodity_carrier = Set(initialize=M.commodity_physical | M.commodity_demand) M.commodity_all = Set( initialize=M.commodity_carrier | M.commodity_emissions, validate=no_slash_or_pipe ) - # Define sets for MGA weighting - M.tech_mga = Set(within=M.tech_all) - M.tech_electric = Set(within=M.tech_all) - M.tech_transport = Set(within=M.tech_all) - M.tech_industrial = Set(within=M.tech_all) - M.tech_commercial = Set(within=M.tech_all) - M.tech_residential = Set(within=M.tech_all) - M.tech_PowerPlants = Set(within=M.tech_all) - ################################################ # Model Parameters # # (data gathered/derived from source) # @@ -583,11 +575,11 @@ def __init__(M, *args, **kwargs): M.CommodityBalanceConstraint_rpsdc, rule=CommodityBalance_Constraint ) - M.CommodityBalanceAnnualConstraint_rpc = Set( - dimen=3, initialize=CommodityBalanceAnnualConstraintIndices + M.AnnualCommodityBalanceConstraint_rpc = Set( + dimen=3, initialize=AnnualCommodityBalanceConstraintIndices ) - M.CommodityBalanceAnnualConstraint = Constraint( - M.CommodityBalanceAnnualConstraint_rpc, rule=CommodityBalanceAnnual_Constraint + M.AnnualCommodityBalanceConstraint = Constraint( + M.AnnualCommodityBalanceConstraint_rpc, rule=AnnualCommodityBalance_Constraint ) M.ResourceExtractionConstraint = Constraint( diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 42acf8795..eb9968ede 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -29,7 +29,7 @@ from temoa.temoa_model.temoa_initialize import ( DemandConstraintErrorCheck, CommodityBalanceConstraintErrorCheck, - CommodityBalanceConstraintErrorCheckAnnual, + AnnualCommodityBalanceConstraintErrorCheck, ) if TYPE_CHECKING: @@ -744,11 +744,10 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): 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 - :code:`CommodityBalanceAnnual_Constraint` is used, which is simplified and - reduces computational burden. + Finally, for annual commodities, AnnualCommodityBalance is used which balances + the sum of flows over each year. - *production + imports = consumption + exports + excess* + *production + imports = consumption + exports + flex waste* .. math:: :label: CommodityBalance @@ -771,80 +770,86 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): &\forall \{r, p, s, d, c\} \in \Theta_{\text{CommodityBalance}} """ - if c in M.commodity_demand: + if c in M.commodity_demand: # Is this necessary? Demand comms have no downstream process no shouldnt be in indices return Constraint.Skip - vflow_in_ToStorage = sum( + # Only storage techs have a flow in variable + # For other techs, it would be redundant as in = out / eff + stored = sum( M.V_FlowIn[r, p, s, d, c, S_t, S_v, S_o] for S_t, S_v in M.commodityDStreamProcess[r, p, c] if S_t in M.tech_storage for S_o in M.ProcessOutputsByInput[r, p, S_t, S_v, c] ) - vflow_in_ToNonStorage = sum( + consumed = sum( M.V_FlowOut[r, p, s, d, c, S_t, S_v, S_o] / value(M.Efficiency[r, c, S_t, S_v, S_o]) for S_t, S_v in M.commodityDStreamProcess[r, p, c] if S_t not in M.tech_storage and S_t not in M.tech_annual for S_o in M.ProcessOutputsByInput[r, p, S_t, S_v, c] ) - vflow_in_ToNonStorageAnnual = value(M.SegFrac[s, d]) * sum( + consumed_annual = value(M.SegFrac[s, d]) * sum( M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] / value(M.Efficiency[r, c, S_t, S_v, S_o]) for S_t, S_v in M.commodityDStreamProcess[r, p, c] if S_t not in M.tech_storage and S_t in M.tech_annual for S_o in M.ProcessOutputsByInput[r, p, S_t, S_v, c] ) - try: - vflow_out = sum( - M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, c] - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, c] - ) + # Includes output from storage + produced = sum( + M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, c] + for S_t, S_v in M.commodityUStreamProcess[r, p, c] + if S_t not in M.tech_annual + for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, c] + ) - # export of commodity c from region r to other regions - interregional_exports = 0 - if (r, p, c) in M.exportRegions: - interregional_exports = sum( - M.V_FlowOut[r + '-' + reg, p, s, d, c, S_t, S_v, S_o] - / value(M.Efficiency[r + '-' + reg, c, S_t, S_v, S_o]) - for reg, S_t, S_v, S_o in M.exportRegions[r, p, c] - ) + produced_annual = value(M.SegFrac[s, d]) * sum( + M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, c] + for S_t, S_v in M.commodityUStreamProcess[r, p, c] + if S_t in M.tech_annual + for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, c] + ) - # import of commodity c from other regions into region r - interregional_imports = 0 - if (r, p, c) in M.importRegions: - interregional_imports = sum( - M.V_FlowOut[reg + '-' + r, p, s, d, S_i, S_t, S_v, c] - for reg, S_t, S_v, S_i in M.importRegions[r, p, c] - ) + # export of commodity c from region r to other regions + exported = 0 + if (r, p, c) in M.exportRegions: + exported = sum( + M.V_FlowOut[r + '-' + reg, p, s, d, c, S_t, S_v, S_o] + / value(M.Efficiency[r + '-' + reg, c, S_t, S_v, S_o]) + for reg, S_t, S_v, S_o in M.exportRegions[r, p, c] + ) - v_out_excess = 0 - if c in M.flex_commodities: - v_out_excess = sum( - M.V_Flex[r, p, s, d, S_i, S_t, S_v, c] - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t not in M.tech_storage and S_t not in M.tech_annual and S_t in M.tech_flex - for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, c] - ) + # import of commodity c from other regions into region r + imported = 0 + if (r, p, c) in M.importRegions: + imported = sum( + M.V_FlowOut[reg + '-' + r, p, s, d, S_i, S_t, S_v, c] + for reg, S_t, S_v, S_i in M.importRegions[r, p, c] + ) - except KeyError: - raise KeyError( - 'The commodity "' - + str(c) - + '" can be produced \ - by at least one technology in the tech_annual set and one technology \ - not in the tech_annual set. All the producers of the commodity must \ - either be in tech_annual or not in tech_annual' + flex_waste = 0 + flex_waste_annual = 0 + if c in M.flex_commodities: + flex_waste = sum( + M.V_Flex[r, p, s, d, S_i, S_t, S_v, c] + for S_t, S_v in M.commodityUStreamProcess[r, p, c] + if S_t not in M.tech_annual and S_t in M.tech_flex + for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, c] + ) + flex_waste_annual = value(M.SegFrac[s, d]) * sum( + M.V_FlexAnnual[r, p, S_i, S_t, S_v, c] + for S_t, S_v in M.commodityUStreamProcess[r, p, c] + if S_t in M.tech_annual and S_t in M.tech_flex + for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, c] ) + supplied = produced + produced_annual + imported + demanded = stored + consumed + consumed_annual + exported + flex_waste + flex_waste_annual + CommodityBalanceConstraintErrorCheck( - vflow_out + interregional_imports, - vflow_in_ToStorage - + vflow_in_ToNonStorage - + vflow_in_ToNonStorageAnnual - + interregional_exports - + v_out_excess, + supplied, + demanded, r, p, s, @@ -852,113 +857,116 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): c, ) - expr = ( - vflow_out + interregional_imports - == vflow_in_ToStorage - + vflow_in_ToNonStorage - + vflow_in_ToNonStorageAnnual - + interregional_exports - + v_out_excess - ) + expr = supplied == demanded return expr -def CommodityBalanceAnnual_Constraint(M: 'TemoaModel', r, p, c): +def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): r""" - Similar to the CommodityBalance_Constraint, but this version applies only - to commodities produced at a constant annual rate. This version of the - constraint improves computational performance for commodities that do not - need to be balanced at the timeslice level. - - While the commodity :math:`c` can only be produced by technologies in the - :code:`tech_annual` set, it can be consumed by any technology in the - :math:`T-T^{s}` set. - - *production + imports = consumption + exports + excess* - - .. math:: - :label: CommodityBalanceAnnual - - \sum_{I,T, V} \textbf{FOA}_{r, p, i, t \in T^{a}, v, c} - + - &\sum_{reg} \textbf{FIM}_{reg-r, p, i, t, v, c} \; \forall reg \neq r - \\ = - &\sum_{S, D, T-T^{s}, V, O} \textbf{FO}_{r, p, s, d, c, t, v, o} /EFF_{r, c,t,v,o} - \\ + &\quad - \sum_{I, T^{a}, V, O} \textbf{FOA}_{r, p, c, t \in T^{a}, v, o} /EFF_{r, c,t,v,o} - \\ &+ - \sum_{reg} \textbf{FEX}_{r-reg, p, c, t, v, o} \; \forall reg \neq r - \\ &+ - \textbf{FX}_{r, p, i, t, v, c} - - \\ - &\forall \{r, p, c\} \in \Theta_{\text{CommodityBalanceAnnual}} - + Similar to CommodityBalance_Constraint but only balances the supply and demand of the commodity + at the annual level, summing all flows over the year. Applies only to commodities tagged as annual + 'a' in the Commodity table. """ - if c in M.commodity_demand: + + if c in M.commodity_demand: # Is this necessary? Demand comms have no downstream process no shouldnt be in indices return Constraint.Skip + + # Only storage techs have a flow in variable + # For other techs, it would be redundant as in = out / eff + stored = sum( + M.V_FlowIn[r, p, S_s, S_d, c, S_t, S_v, S_o] + for S_s in M.time_season + for S_d in M.time_of_day + for S_t, S_v in M.commodityDStreamProcess[r, p, c] + if S_t in M.tech_storage + for S_o in M.ProcessOutputsByInput[r, p, S_t, S_v, c] + ) - vflow_in = sum( - M.V_FlowOut[r, p, s, d, c, S_t, S_v, S_o] / value(M.Efficiency[r, c, S_t, S_v, S_o]) + consumed = sum( + M.V_FlowOut[r, p, S_s, S_d, c, S_t, S_v, S_o] / value(M.Efficiency[r, c, S_t, S_v, S_o]) + for S_s in M.time_season + for S_d in M.time_of_day for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t not in M.tech_annual + if S_t not in M.tech_storage and S_t not in M.tech_annual for S_o in M.ProcessOutputsByInput[r, p, S_t, S_v, c] - for d in M.time_of_day - for s in M.time_season ) - vflow_in_annual = sum( + consumed_annual = sum( M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] / value(M.Efficiency[r, c, S_t, S_v, S_o]) for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t in M.tech_annual + if S_t not in M.tech_storage and S_t in M.tech_annual for S_o in M.ProcessOutputsByInput[r, p, S_t, S_v, c] ) - vflow_out = sum( + # Includes output from storage + produced = sum( + M.V_FlowOut[r, p, S_s, S_d, S_i, S_t, S_v, c] + for S_s in M.time_season + for S_d in M.time_of_day + for S_t, S_v in M.commodityUStreamProcess[r, p, c] + if S_t not in M.tech_annual + for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, c] + ) + + produced_annual = sum( M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, c] for S_t, S_v in M.commodityUStreamProcess[r, p, c] + if S_t in M.tech_annual for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, c] ) # export of commodity c from region r to other regions - interregional_exports = 0 + exported = 0 if (r, p, c) in M.exportRegions: - interregional_exports = sum( - M.V_FlowOutAnnual[str(r) + '-' + str(reg), p, c, S_t, S_v, S_o] - / value(M.Efficiency[str(r) + '-' + str(reg), c, S_t, S_v, S_o]) - for reg, S_t, S_v, S_o in M.exportRegions[r, p, c] + exported = sum( + M.V_FlowOut[r + '-' + S_r, p, S_s, S_d, c, S_t, S_v, S_o] + / value(M.Efficiency[r + '-' + S_r, c, S_t, S_v, S_o]) + for S_s in M.time_season + for S_d in M.time_of_day + for S_r, S_t, S_v, S_o in M.exportRegions[r, p, c] ) # import of commodity c from other regions into region r - interregional_imports = 0 + imported = 0 if (r, p, c) in M.importRegions: - interregional_imports = sum( - M.V_FlowOutAnnual[str(reg) + '-' + str(r), p, S_i, S_t, S_v, c] - for reg, S_t, S_v, S_i in M.importRegions[r, p, c] + imported = sum( + M.V_FlowOut[S_r + '-' + r, p, S_s, S_d, S_i, S_t, S_v, c] + for S_s in M.time_season + for S_d in M.time_of_day + for S_r, S_t, S_v, S_i in M.importRegions[r, p, c] ) - v_out_excess = 0 + flex_waste = 0 + flex_waste_annual = 0 if c in M.flex_commodities: - v_out_excess = sum( + flex_waste = sum( + M.V_Flex[r, p, S_s, S_d, S_i, S_t, S_v, c] + for S_s in M.time_season + for S_d in M.time_of_day + for S_t, S_v in M.commodityUStreamProcess[r, p, c] + if S_t not in M.tech_annual and S_t in M.tech_flex + for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, c] + ) + flex_waste_annual = sum( M.V_FlexAnnual[r, p, S_i, S_t, S_v, c] for S_t, S_v in M.commodityUStreamProcess[r, p, c] if S_t in M.tech_flex and S_t in M.tech_annual for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, c] ) - CommodityBalanceConstraintErrorCheckAnnual( - vflow_out + interregional_imports, - vflow_in_annual + vflow_in + interregional_exports + v_out_excess, + supplied = produced + produced_annual + imported + demanded = stored + consumed + consumed_annual + exported + flex_waste + flex_waste_annual + + AnnualCommodityBalanceConstraintErrorCheck( + supplied, + demanded, r, p, c, ) - expr = ( - vflow_out + interregional_imports - == vflow_in_annual + vflow_in + interregional_exports + v_out_excess - ) + expr = supplied == demanded return expr diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 6132ad718..1930109b6 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -133,6 +133,7 @@ "GeoHyd" ], "commodity_source": [], + "commodity_annual": [], "commodity_carrier": [ "ELC", "HYD", @@ -153,13 +154,6 @@ "co2", "FusionGas" ], - "tech_mga": [], - "tech_electric": [], - "tech_transport": [], - "tech_industrial": [], - "tech_commercial": [], - "tech_residential": [], - "tech_PowerPlants": [], "ResourceConstraint_rpr": [], "CapacityFactor_rsdt": [ [ @@ -3776,20 +3770,65 @@ "s1", "d1", "ELC" - ] - ], - "CommodityBalanceAnnualConstraint_rpc": [ + ], [ - "B", + "A", + 2025, + "s1", + "d1", + "GeoHyd" + ], + [ + "A", + 2025, + "s1", + "d2", + "GeoHyd" + ], + [ + "A", 2025, + "s2", + "d1", "GeoHyd" ], [ "A", 2025, + "s2", + "d2", + "GeoHyd" + ], + [ + "B", + 2025, + "s1", + "d1", + "GeoHyd" + ], + [ + "B", + 2025, + "s1", + "d2", + "GeoHyd" + ], + [ + "B", + 2025, + "s2", + "d1", + "GeoHyd" + ], + [ + "B", + 2025, + "s2", + "d2", "GeoHyd" ] ], + "AnnualCommodityBalanceConstraint_rpc": [], "BaseloadDiurnalConstraint_rpsdtv": [ [ "A", diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 4bc8413d4..225a08872 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -151,6 +151,7 @@ "commodity_source": [ "ethos" ], + "commodity_annual": [], "commodity_carrier": [ "ethos", "OIL", @@ -180,13 +181,6 @@ "RH", "CO2" ], - "tech_mga": [], - "tech_electric": [], - "tech_transport": [], - "tech_industrial": [], - "tech_commercial": [], - "tech_residential": [], - "tech_PowerPlants": [], "ResourceConstraint_rpr": [], "CapacityFactor_rsdt": [ [ @@ -41032,7 +41026,7 @@ "DSL" ] ], - "CommodityBalanceAnnualConstraint_rpc": [], + "AnnualCommodityBalanceConstraint_rpc": [], "BaseloadDiurnalConstraint_rpsdtv": [ [ "R1", diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index e33d68126..3a04814f1 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -156,6 +156,7 @@ "commodity_source": [ "ethos" ], + "commodity_annual": [], "commodity_carrier": [ "ethos", "DSL", @@ -186,13 +187,6 @@ "co2", "nox" ], - "tech_mga": [], - "tech_electric": [], - "tech_transport": [], - "tech_industrial": [], - "tech_commercial": [], - "tech_residential": [], - "tech_PowerPlants": [], "ResourceConstraint_rpr": [], "CapacityFactor_rsdt": [ [ @@ -22823,7 +22817,7 @@ "GSL" ] ], - "CommodityBalanceAnnualConstraint_rpc": [], + "AnnualCommodityBalanceConstraint_rpc": [], "BaseloadDiurnalConstraint_rpsdtv": [ [ "utopia", From ce7cce0326cb970ae603f548de3c9ed5affdb7a6 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 6 Aug 2025 15:11:52 -0400 Subject: [PATCH 015/587] Rework storage and ramp rates - Rework storage to make diurnal the default behaviour with an option to change back - Update ramp rates - Rework and revive StorageInit constraint --- temoa/temoa_model/hybrid_loader.py | 25 +- temoa/temoa_model/temoa_initialize.py | 45 +- temoa/temoa_model/temoa_model.py | 45 +- temoa/temoa_model/temoa_rules.py | 399 +++++------ tests/legacy_test_values.py | 8 +- tests/test_full_runs.py | 3 +- tests/test_storage.py | 124 +++- tests/testing_data/emissions.sql | 1 + tests/testing_data/mediumville.sql | 1 + tests/testing_data/mediumville_sets.json | 45 +- tests/testing_data/simple_linked_tech.sql | 1 + tests/testing_data/storageville.sql | 15 +- tests/testing_data/test_system.sql | 16 +- tests/testing_data/test_system_sets.json | 832 ++++++++++------------ tests/testing_data/utopia.sql | 1 + tests/testing_data/utopia_sets.json | 454 ++++++------ 16 files changed, 950 insertions(+), 1065 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 88b9d5006..d496b753d 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -382,6 +382,12 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): raw = cur.execute('SELECT season FROM main.TimeSeason ORDER BY sequence').fetchall() load_element(M.time_season, raw) + # link_seasons + raw = cur.execute("SELECT value from MetaData WHERE element == 'link_seasons'").fetchall() + if not raw: + raise ValueError('link_seasons boolean parameter missing from MetaData table. Seasons will loop by default.') + data[M.link_seasons.name] = {None: bool(raw[0][0])} + # myopic_base_year if mi: raw = cur.execute( @@ -1199,16 +1205,17 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): raw = cur.execute('SELECT region, tech, duration FROM main.StorageDuration').fetchall() load_element(M.StorageDuration, raw, self.viable_rt, (0, 1)) - # StorageInit + # StorageInitFrac # Not currently supported -- odd behavior and not region-indexed - if self.table_exists('StorageInit'): - raw = cur.execute('SELECT * FROM main.StorageInit').fetchall() - if len(raw) > 0: - logger.warning( - 'Initialization of storage values currently NOT supported.' - ' Values in StorageInit table will be ignored, and storage init value' - ' will be optimized.' - ) + if self.table_exists('StorageInitFrac'): + raw = cur.execute('SELECT region, period, season, tech, vintage, frac FROM main.StorageInitFrac').fetchall() + load_element(M.StorageInitFrac, raw, self.viable_rtv, (0,3,4)) + # if len(raw) > 0: + # logger.warning( + # 'Initialization of storage values currently NOT supported.' + # ' Values in StorageInit table will be ignored, and storage init value' + # ' will be optimized.' + # ) # For T/S: dump the size of all data elements into the log if self.debugging: diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 411d0de59..9e585aa7c 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1231,58 +1231,53 @@ def AnnualCommodityBalanceConstraintIndices(M: 'TemoaModel'): return indices -def StorageVariableIndices(M: 'TemoaModel'): +# StorageInit needs an overhaul +def StorageInitIndices(M: 'TemoaModel'): indices = set( - (r, p, s, d, t, v) + (r, p, s, t, v) for r, p, t in M.storageVintages.keys() - for s in M.time_season - for d in M.time_of_day for v in M.storageVintages[r, p, t] + for s in M.time_season ) return indices -def StorageInitIndices(M: 'TemoaModel'): +def StorageConstraintIndices(M: 'TemoaModel'): indices = set( - (r, t, v) for r, p, t in M.storageVintages.keys() for v in M.storageVintages[r, p, t] + (r, p, s, d, t, v) + for (r, p, s, t, v) in M.StorageInit_rpstv + for d in M.time_of_day ) return indices -def StorageInitConstraintIndices(M: 'TemoaModel'): - indices = set((r, t, v) for r, t, v in M.StorageInitFrac.sparse_iterkeys()) - - return indices - - -def RampConstraintDayIndices(M: 'TemoaModel'): +def StorageStateIndices(M: 'TemoaModel'): indices = set( (r, p, s, d, t, v) - for r, p, t in M.rampVintages.keys() - for s in M.time_season + for (r, p, s, t, v) in M.StorageInit_rpstv for d in M.time_of_day - for v in M.rampVintages[r, p, t] + if d != M.time_of_day.last() # replaced by storageinit ) return indices -def RampConstraintSeasonIndices(M: 'TemoaModel'): - indices = set( - (r, p, s, t, v) - for r, p, t in M.rampVintages.keys() - for s in M.time_season - for v in M.rampVintages[r, p, t] - ) +# StorageInit needs an overhaul +def StorageInitFracIndices(M: 'TemoaModel'): + indices = set((r, p, s, t, v) for r, p, s, t, v in M.StorageInitFrac.sparse_iterkeys()) return indices -def RampConstraintPeriodIndices(M: 'TemoaModel'): +def RampConstraintIndices(M: 'TemoaModel'): indices = set( - (r, p, t, v) for r, p, t in M.rampVintages.keys() for v in M.rampVintages[r, p, t] + (r, p, s, d, t, v) + for r, p, t in M.rampVintages.keys() + for s in M.time_season + for d in M.time_of_day + for v in M.rampVintages[r, p, t] ) return indices diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index adc5f2765..218c3103d 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -68,6 +68,8 @@ def __init__(M, *args, **kwargs): # (not formal model elements) # ################################################ + + # Dev Note: The triple-quotes UNDER the items below pop up as dox in most IDEs M.processInputs = dict() M.processOutputs = dict() @@ -453,10 +455,11 @@ def __init__(M, *args, **kwargs): M.StorageDuration = Param(M.regions, M.tech_storage, default=4) # Initial storage charge level, expressed as fraction of full energy capacity. # If the parameter is not defined, the model optimizes the initial storage charge level. - M.StorageInit_rtv = Set(dimen=3, initialize=StorageInitIndices) - M.StorageInitFrac = Param(M.StorageInit_rtv) + # Dev note: needs overhaul + M.StorageInitFrac = Param(M.regions, M.time_optimize, M.time_season, M.tech_storage, M.vintage_all) M.MyopicBaseyear = Param(default=0) + M.link_seasons = Param(default=0) # do states carry from one season to the next? otherwise loop each season ################################################ # Model Variables # @@ -493,9 +496,10 @@ def __init__(M, *args, **kwargs): M.FlowInStorage_rpsditvo = Set(dimen=8, initialize=FlowInStorageVariableIndices) M.V_FlowIn = Var(M.FlowInStorage_rpsditvo, domain=NonNegativeReals) - M.StorageLevel_rpsdtv = Set(dimen=6, initialize=StorageVariableIndices) + M.StorageInit_rpstv = Set(dimen=5, initialize=StorageInitIndices) + M.V_StorageInit = Var(M.StorageInit_rpstv, domain=NonNegativeReals) + M.StorageLevel_rpsdtv = Set(dimen=6, initialize=StorageStateIndices) M.V_StorageLevel = Var(M.StorageLevel_rpsdtv, domain=NonNegativeReals) - M.V_StorageInit = Var(M.StorageInit_rtv, domain=NonNegativeReals) # Derived decision variables @@ -602,7 +606,8 @@ def __init__(M, *args, **kwargs): M.progress_marker_6 = BuildAction(['Starting Storage Constraints'], rule=progress_check) # This set works for all the storage-related constraints - M.StorageConstraints_rpsdtv = Set(dimen=6, initialize=StorageVariableIndices) + M.StorageConstraints_rpsdtv = Set(dimen=6, initialize=StorageConstraintIndices) + M.StorageEnergyConstraint = Constraint( M.StorageConstraints_rpsdtv, rule=StorageEnergy_Constraint ) @@ -627,32 +632,14 @@ def __init__(M, *args, **kwargs): M.StorageConstraints_rpsdtv, rule=StorageThroughput_Constraint ) - M.StorageInitConstraint_rtv = Set(dimen=2, initialize=StorageInitConstraintIndices) - M.StorageInitConstraint = Constraint( - M.StorageInitConstraint_rtv, rule=StorageInit_Constraint + M.StorageInitFracConstraint_rpstv = Set(dimen=5, initialize=StorageInitFracIndices) + M.StorageInitFracConstraint = Constraint( + M.StorageInitFracConstraint_rpstv, rule=StorageInitFrac_Constraint ) - M.RampConstraintDay_rpsdtv = Set(dimen=6, initialize=RampConstraintDayIndices) - M.RampUpConstraintDay = Constraint(M.RampConstraintDay_rpsdtv, rule=RampUpDay_Constraint) - M.RampDownConstraintDay = Constraint( - M.RampConstraintDay_rpsdtv, rule=RampDownDay_Constraint - ) - - # M.RampConstraintSeason_rpstv = Set(dimen=5, initialize=RampConstraintSeasonIndices) - # M.RampUpConstraintSeason = Constraint( - # M.RampConstraintSeason_rpstv, rule=RampUpSeason_Constraint - # ) - # M.RampDownConstraintSeason = Constraint( - # M.RampConstraintSeason_rpstv, rule=RampDownSeason_Constraint - # ) - - M.RampConstraintPeriod_rptv = Set(dimen=4, initialize=RampConstraintPeriodIndices) - M.RampUpConstraintPeriod = Constraint( - M.RampConstraintPeriod_rptv, rule=RampUpPeriod_Constraint - ) - M.RampDownConstraintPeriod = Constraint( - M.RampConstraintPeriod_rptv, rule=RampDownPeriod_Constraint - ) + M.RampConstraint_rpsdtv = Set(dimen=6, initialize=RampConstraintIndices) + M.RampUpConstraint = Constraint(M.RampConstraint_rpsdtv, rule=RampUpDay_Constraint) + M.RampDownConstraint = Constraint(M.RampConstraint_rpsdtv, rule=RampDownDay_Constraint) M.ReserveMargin_rpsd = Set(dimen=4, initialize=ReserveMarginIndices) M.ReserveMarginConstraint = Constraint(M.ReserveMargin_rpsd, rule=ReserveMargin_Constraint) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index eb9968ede..c633c3608 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1106,6 +1106,30 @@ def RegionalExchangeCapacity_Constraint(M: 'TemoaModel', r_e, r_i, p, t, v): def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): + + # This is the sum of all input=i sent TO storage tech t of vintage v with + # output=o in p,s,d + charge = sum( + M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] * M.Efficiency[r, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + ) + + # This is the sum of all output=o withdrawn FROM storage tech t of vintage v + # with input=i in p,s,d + discharge = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_o in M.processOutputs[r, p, t, v] + for S_i in M.ProcessInputsByOutput[r, p, t, v, S_o] + ) + + stored_energy = charge - discharge + + if M.link_seasons: return link_season_storage_energy(M, r, p, s, d, t, v, stored_energy) + else: return loop_season_storage_energy(M, r, p, s, d, t, v, stored_energy) + + +def link_season_storage_energy(M: 'TemoaModel', r, p, s, d, t, v, stored_energy) -> Expression: r""" This constraint tracks the storage charge level (:math:`\textbf{SL}_{r, p, s, d, t, v}`) @@ -1159,7 +1183,51 @@ def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): .. math:: \forall \{r, p, s, d, t, v\} \in \Theta_{\text{StorageEnergy}} + + This constraint is used if link_seasons is set to 1 in the MetaData table """ + + # First time slice of any season + # Begin storage state at StorageInit which MAY be constrained by StorageInitFrac + if d == M.time_of_day.first(): + expr = M.V_StorageLevel[r, p, s, d, t, v] == M.V_StorageInit[r, p, s, t, v] + stored_energy + + # Final time slice of final season (end of period) + # Loop storage state to initial state of first season + # Loop storage state from end to start of same period + elif s == M.time_season.last() and d == M.time_of_day.last(): + d_prev = M.time_of_day.prev(d) + s_first = M.time_season.first() + expr = M.V_StorageInit[r, p, s_first, t, v] == M.V_StorageLevel[r, p, s, d_prev, t, v] + stored_energy + + # Last time slice of any season that is NOT the last season + # Carry storage state to initial state of next season + # Carry storage state between seasons + elif d == M.time_of_day.last(): + d_prev = M.time_of_day.prev(d) + s_next = M.time_season.next(s) + expr = M.V_StorageInit[r, p, s_next, t, v] == M.V_StorageLevel[r, p, s, d_prev, t, v] + stored_energy + + # Not the start or end of any season. Somewhere in the middle of a season + # Carry storage state between time slices within the same season + else: + d_prev = M.time_of_day.prev(d) + expr = M.V_StorageLevel[r, p, s, d, t, v] == M.V_StorageLevel[r, p, s, d_prev, t, v] + stored_energy + + return expr + + +def loop_season_storage_energy(M: 'TemoaModel', r, p, s, d, t, v) -> Expression: + r""" + This variant of the storage energy constraint, used by default, loops the state + of storage within each season rather than carrying it between seasons. Necessary + when the order of seasons in the database is not representative of their actual + chronological sequence. + + Can set link_seasons to value 1 in MetaData table to allow storage state + to carry between seasons, if seasons are real-world chronological. + """ + # This is the sum of all input=i sent TO storage tech t of vintage v with # output=o in p,s,d charge = sum( @@ -1178,34 +1246,23 @@ def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): stored_energy = charge - discharge - # This storage formulation allows stored energy to carry over through - # time of day and seasons, but must be zeroed out at the end of each period, i.e., - # the last time slice of the last season must zero out - if d == M.time_of_day.last() and s == M.time_season.last(): + # First time slice of any season + # Begin storage state at StorageInit which MAY be constrained by StorageInitFrac + if d == M.time_of_day.first(): + expr = M.V_StorageLevel[r, p, s, d, t, v] == M.V_StorageInit[r, p, s, t, v] + stored_energy + + # Last time slice of any season + # Loop storage state back to initial state of same season + # Loop storage state within each season + elif d == M.time_of_day.last(): d_prev = M.time_of_day.prev(d) - expr = M.V_StorageLevel[r, p, s, d_prev, t, v] + stored_energy == M.V_StorageInit[r, t, v] - - # First time slice of the first season (i.e., start of period), starts at StorageInit level - elif d == M.time_of_day.first() and s == M.time_season.first(): - expr = M.V_StorageLevel[r, p, s, d, t, v] == M.V_StorageInit[r, t, v] + stored_energy - - # First time slice of any season that is NOT the first season - elif d == M.time_of_day.first(): - d_last = M.time_of_day.last() - s_prev = M.time_season.prev(s) - expr = ( - M.V_StorageLevel[r, p, s, d, t, v] - == M.V_StorageLevel[r, p, s_prev, d_last, t, v] + stored_energy - ) + expr = M.V_StorageInit[r, p, s, t, v] == M.V_StorageLevel[r, p, s, d_prev, t, v] + stored_energy - # Any time slice that is NOT covered above (i.e., not the time slice ending - # the period, or the first time slice of any season) + # Not the start or end of any season. Somewhere in the middle of a season + # Carry storage state between time slices within the same season else: d_prev = M.time_of_day.prev(d) - expr = ( - M.V_StorageLevel[r, p, s, d, t, v] - == M.V_StorageLevel[r, p, s, d_prev, t, v] + stored_energy - ) + expr = M.V_StorageLevel[r, p, s, d, t, v] == M.V_StorageLevel[r, p, s, d_prev, t, v] + stored_energy return expr @@ -1247,7 +1304,11 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): * 365 * value(M.ProcessLifeFrac[r, p, t, v]) ) - expr = M.V_StorageLevel[r, p, s, d, t, v] <= energy_capacity + + if d == M.time_of_day.last(): storage_level = M.V_StorageInit[r, p, s, t, v] + else: storage_level = M.V_StorageLevel[r, p, s, d, t, v] + + expr = storage_level <= energy_capacity return expr @@ -1369,7 +1430,7 @@ def StorageThroughput_Constraint(M: 'TemoaModel', r, p, s, d, t, v): return expr -def StorageInit_Constraint(M: 'TemoaModel', r, t, v): +def StorageInitFrac_Constraint(M: 'TemoaModel', r, p, s, t, v): r""" This constraint is used if the users wishes to force a specific initial storage charge level @@ -1397,22 +1458,18 @@ def StorageInit_Constraint(M: 'TemoaModel', r, t, v): # dev note: This constraint is not currently accessible and needs close review. # the hybrid loader currently screens out inputs for this to keep # it idle. - raise NotImplementedError('This constraint needs overhaul...') - s = M.time_season.first() - # the only capacity of concern here is for the vintage year for initialization - vintage_period = s + #raise NotImplementedError('This constraint needs overhaul...') - # devnote: storage techs are currently excluded from the tech_retirements, so no change in - # capacity should ever occur energy_capacity = ( - M.V_Capacity[r, vintage_period, t, v] + M.V_Capacity[r, p, t, v] * M.CapacityToActivity[r, t] * (M.StorageDuration[r, t] / 8760) * sum(M.SegFrac[s, S_d] for S_d in M.time_of_day) * 365 - * value(M.ProcessLifeFrac[r, v, t, v]) + * value(M.ProcessLifeFrac[r, p, t, v]) ) - expr = M.V_StorageInit[r, t, v] == energy_capacity * M.StorageInitFrac[r, t, v] + + expr = M.V_StorageInit[r, p, s, t, v] == energy_capacity * M.StorageInitFrac[r, p, s, t, v] return expr @@ -1464,27 +1521,47 @@ def RampUpDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): \\ \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampUpDay}} """ - if d != M.time_of_day.first(): - d_prev = M.time_of_day.prev(d) - activity_sd_prev = sum( - M.V_FlowOut[r, p, s, d_prev, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] - ) - activity_sd = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] - ) - - expr_left = ( - activity_sd / value(M.SegFrac[s, d]) - activity_sd_prev / value(M.SegFrac[s, d_prev]) - ) / value(M.CapacityToActivity[r, t]) - expr_right = M.V_Capacity[r, p, t, v] * value(M.RampUp[r, t]) - expr = expr_left <= expr_right + if M.link_seasons: + # Linking seasons together chronologically + if s == M.time_season.first() and d == M.time_of_day.first(): + # beginning of period, loop to end of same period + s_prev = M.time_season.last() + d_prev = M.time_of_day.last() + elif d == M.time_of_day.first(): + # beginning of season (but not period), link to end of last season + s_prev = M.time_season.prev(s) + d_prev = M.time_of_day.last() + else: + # middle of season, link to previous time slice in same season + s_prev = s + d_prev = M.time_of_day.prev(d) else: - return Constraint.Skip + # Looping each season within itself (default behaviour) + if d == M.time_of_day.first(): + # beginning of season, loop to end of same season + s_prev = s + d_prev = M.time_of_day.last() + else: + # middle of season, link to previous time slice in same season + s_prev = s + d_prev = M.time_of_day.prev(d) + + activity_sd_prev = sum( + M.V_FlowOut[r, p, s_prev, d_prev, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + ) / value(M.SegFrac[s_prev, d_prev]) + + activity_sd = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + ) / value(M.SegFrac[s, d]) + + activity_increase = activity_sd - activity_sd_prev # opposite sign from rampdown + rampable_activity = M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.RampUp[r, t]) + expr = activity_increase <= rampable_activity return expr @@ -1514,193 +1591,51 @@ def RampDownDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): \\ \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampDownDay}} """ - if d != M.time_of_day.first(): - d_prev = M.time_of_day.prev(d) - activity_sd_prev = sum( - M.V_FlowOut[r, p, s, d_prev, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] - ) - - activity_sd = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] - ) - - expr_left = ( - activity_sd / value(M.SegFrac[s, d]) - activity_sd_prev / value(M.SegFrac[s, d_prev]) - ) / value(M.CapacityToActivity[r, t]) - expr_right = -(M.V_Capacity[r, p, t, v] * value(M.RampDown[r, t])) - expr = expr_left >= expr_right - else: - return Constraint.Skip - - return expr - - -def RampUpSeason_Constraint(M: 'TemoaModel', r, p, s, t, v): - r""" - - Note that :math:`d_1` and :math:`d_{nd}` represent the first and last time-of-day, - respectively. - - .. math:: - :label: - - \frac{ - \sum_{I, O} \textbf{FO}_{r, p, s_{i + 1}, d_1, i, t, v, o} - }{ - SEG_{s_{i + 1}, d_1} \cdot C2A_{r,t} - } - - - \frac{ - \sum_{I, O} \textbf{FO}_{r, p, s_i, d_{nd}, i, t, v, o} - }{ - SEG_{s_i, d_{nd}} \cdot C2A_{r,t} - } - \leq - r_t \cdot \textbf{CAPAVL}_{r,p,t} - \\ - \forall \{r, p, s, t, v\} \in \Theta_{\text{RampUpSeason}} - """ - if s != M.time_season.first(): - s_prev = M.time_season.prev(s) - d_first = M.time_of_day.first() - d_last = M.time_of_day.last() - - activity_sd_first = sum( - M.V_FlowOut[r, p, s, d_first, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] - ) - activity_s_prev_d_last = sum( - M.V_FlowOut[r, p, s_prev, d_last, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] - ) - - expr_left = ( - activity_sd_first / M.SegFrac[s, d_first] - - activity_s_prev_d_last / M.SegFrac[s_prev, d_last] - ) / value(M.CapacityToActivity[r, t]) - expr_right = M.V_Capacity[r, p, t, v] * value(M.RampUp[r, t]) - expr = expr_left <= expr_right + if M.link_seasons: + # Linking seasons together chronologically + if s == M.time_season.first() and d == M.time_of_day.first(): + # beginning of period, loop to end of same period + s_prev = M.time_season.last() + d_prev = M.time_of_day.last() + elif d == M.time_of_day.first(): + # beginning of season (but not period), link to end of last season + s_prev = M.time_season.prev(s) + d_prev = M.time_of_day.last() + else: + # middle of season, link to previous time slice in same season + s_prev = s + d_prev = M.time_of_day.prev(d) else: - return Constraint.Skip - - return expr - - -def RampDownSeason_Constraint(M: 'TemoaModel', r, p, s, t, v): - r""" - - Similar to the :code:`RampUpSeason` constraint, we use the - :code:`RampDownSeason` constraint to limit ramp down rates - between any two adjacent seasons. - - .. math:: - :label: RampDownSeason - - \frac{ - \sum_{I, O} \textbf{FO}_{r, p, s_{i + 1}, d_1, i, t, v, o} - }{ - SEG_{s_{i + 1}, d_1} \cdot C2A_{r,t} - } - - - \frac{ - \sum_{I, O} \textbf{FO}_{r, p, s_i, d_{nd}, i, t, v, o} - }{ - SEG_{s_i, d_{nd}} \cdot C2A_{r,t} - } - \geq - -r_t \cdot \textbf{CAPAVL}_{r,p,t} - \\ - \forall \{r, p, s, t, v\} \in \Theta_{\text{RampDownSeason}} - """ - if s != M.time_season.first(): - s_prev = M.time_season.prev(s) - d_first = M.time_of_day.first() - d_last = M.time_of_day.last() + # Looping each season within itself (default behaviour) + if d == M.time_of_day.first(): + # beginning of season, loop to end of same season + s_prev = s + d_prev = M.time_of_day.last() + else: + # middle of season, link to previous time slice in same season + s_prev = s + d_prev = M.time_of_day.prev(d) - activity_sd_first = sum( - M.V_FlowOut[r, p, s, d_first, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] - ) + activity_sd_prev = sum( + M.V_FlowOut[r, p, s_prev, d_prev, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + ) / value(M.SegFrac[s_prev, d_prev]) - activity_s_prev_d_last = sum( - M.V_FlowOut[r, p, s_prev, d_last, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] - ) + activity_sd = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + ) / value(M.SegFrac[s, d]) - expr_left = ( - activity_sd_first / value(M.SegFrac[s, d_first]) - - activity_s_prev_d_last / value(M.SegFrac[s_prev, d_last]) - ) / value(M.CapacityToActivity[r, t]) - expr_right = -(M.V_Capacity[r, p, t, v] * value(M.RampDown[r, t])) - expr = expr_left >= expr_right - else: - return Constraint.Skip + activity_decrease = activity_sd_prev - activity_sd # opposite sign from rampup + rampable_activity = M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.RampDown[r, t]) + expr = activity_decrease <= rampable_activity return expr -def RampUpPeriod_Constraint(M: 'TemoaModel', r, p, t, v): - # if p != M.time_future.first(): - # p_prev = M.time_future.prev(p) - # s_first = M.time_season.first() - # s_last = M.time_season.last() - # d_first = M.time_of_day.first() - # d_last = M.time_of_day.last() - # expr_left = ( - # M.V_Activity[ p, s_first, d_first, t, v ] - - # M.V_Activity[ p_prev, s_last, d_last, t, v ] - # ) - # expr_right = ( - # M.V_Capacity[t, v]* - # value( M.RampUp[t] )* - # value( M.CapacityToActivity[ t ] )* - # value( M.SegFrac[s, d]) - # ) - # expr = (expr_left <= expr_right) - # else: - # return Constraint.Skip - - # return expr - - return Constraint.Skip # We don't need inter-period ramp up/down constraint. - - -def RampDownPeriod_Constraint(M: 'TemoaModel', r, p, t, v): - # if p != M.time_future.first(): - # p_prev = M.time_future.prev(p) - # s_first = M.time_season.first() - # s_last = M.time_season.last() - # d_first = M.time_of_day.first() - # d_last = M.time_of_day.last() - # expr_left = ( - # M.V_Activity[ p, s_first, d_first, t, v ] - - # M.V_Activity[ p_prev, s_last, d_last, t, v ] - # ) - # expr_right = ( - # -1* - # M.V_Capacity[t, v]* - # value( M.RampDown[t] )* - # value( M.CapacityToActivity[ t ] )* - # value( M.SegFrac[s, d]) - # ) - # expr = (expr_left >= expr_right) - # else: - # return Constraint.Skip - - # return expr - - return Constraint.Skip # We don't need inter-period ramp up/down constraint. - - def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): r""" diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index 9e55e24a0..c72bad8c0 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -44,14 +44,14 @@ class ExpectedVals(Enum): ExpectedVals.OBJ_VALUE: 491977.7000753, ExpectedVals.EFF_DOMAIN_SIZE: 30720, ExpectedVals.EFF_INDEX_SIZE: 74, - ExpectedVals.CONSTR_COUNT: 2826, - ExpectedVals.VAR_COUNT: 1904, + ExpectedVals.CONSTR_COUNT: 2828, # increased by 2 when reworking storageinit + ExpectedVals.VAR_COUNT: 1898, # reduced by 6 when reworking storageinit }, 'utopia': { - ExpectedVals.OBJ_VALUE: 36535.631200, + ExpectedVals.OBJ_VALUE: 36468.56, # reduced after reworking storageinit ExpectedVals.EFF_DOMAIN_SIZE: 12312, ExpectedVals.EFF_INDEX_SIZE: 64, ExpectedVals.CONSTR_COUNT: 1452, # reduced 3/27: unlim_cap techs now employed - ExpectedVals.VAR_COUNT: 1055, # reduced 3/27: unlim_cap techs now employed + ExpectedVals.VAR_COUNT: 1051, # reduced 3/27: unlim_cap techs now employed. Reduced by 4 storageinit }, } diff --git a/tests/test_full_runs.py b/tests/test_full_runs.py index 61538e50d..09e75809a 100644 --- a/tests/test_full_runs.py +++ b/tests/test_full_runs.py @@ -108,5 +108,6 @@ def test_myopic_utopia(system_test_run): cur = con.cursor() res = cur.execute('SELECT SUM(d_invest) FROM main.OutputCost').fetchone() invest_sum = res[0] - assert invest_sum == pytest.approx(11564.3985), 'sum of investment costs did not match expected' + # reduced this target after storageinit rework + assert invest_sum == pytest.approx(11525.19), 'sum of investment costs did not match expected' con.close() diff --git a/tests/test_storage.py b/tests/test_storage.py index 8a66b78bd..b38273454 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -25,34 +25,98 @@ ] -@pytest.mark.skip(reason='known not working...fix deferred') @pytest.mark.parametrize( 'system_test_run', argvalues=storage_config_files, indirect=True, ids=[d['name'] for d in storage_config_files], ) -def test_initialization_in_last_period(system_test_run): +def test_storage_init_frac(system_test_run): """ - The last period should end up back at the initialization value + The level at the end of the first time slice in each season should be + initialization ± flows """ + + model: TemoaModel # helps with typing for some reason... + data_name, results, model, _ = system_test_run + assert len(model.StorageInitFracConstraint_rpstv) > 0, ( + 'This model does not appear to have any StorageInitFrac constraints to test' + ) + # test the first periods + # get references to first timeslot for each rptv combo in things with storage + frac_slices = { + (r, p, s, t, v) + for r, p, s, t, v in model.StorageInitFracConstraint_rpstv + } + # test that the last day/season combo starts up at the initialization value + # devnote: the Level variable is assessed at the end of the timeperiod, so the init ± flows + # should total the end value + for r, p, s, t, v in frac_slices: + + init_energy = ( + model.StorageInitFrac[r, p, s, t, v] + * model.V_Capacity[r, p, t, v].value + * model.CapacityToActivity[r, t] + * (model.StorageDuration[r, t] / 8760) + * sum(model.SegFrac[s, S_d] for S_d in model.time_of_day) + * 365 + * model.ProcessLifeFrac[r, p, t, v] + ) + + assert model.V_StorageInit[r, p, s, t, v].value == pytest.approx( + init_energy, rel=1e-3 + ), f'model fails to initialise storage state at start of season {r, p, s, t, v}' + + +@pytest.mark.parametrize( + 'system_test_run', + argvalues=storage_config_files, + indirect=True, + ids=[d['name'] for d in storage_config_files], +) +def test_season_start(system_test_run): + """ + The level at the end of the first time slice in each season should be + initialization ± flows + """ + model: TemoaModel # helps with typing for some reason... data_name, results, model, _ = system_test_run assert len(model.V_StorageInit.index_set()) > 0, ( 'This model does not appear to have' 'any available storage components' ) - # get references to last timeslot for each prtv combo in things with storage - last_slots = { + # test the first periods + # get references to first timeslot for each rptv combo in things with storage + start_slices = { (r, p, s, d, t, v) for r, p, s, d, t, v in model.StorageLevel_rpsdtv - if s == model.time_season.last() and d == model.time_of_day.last() + if d == model.time_of_day.first() } - # test that the last day/season combo ends up at the initialization value - # devnote: the Level variable is assessed at the end of the timeperiod - for r, p, s, d, t, v in last_slots: - assert model.V_StorageLevel[r, p, s, d, t, v].value == pytest.approx( - model.V_StorageInit[r, t, v].value, rel=1e-3 - ), f'model fails to align last season/day slot with initialization value for {r, t, v}' + # test that the last day/season combo starts up at the initialization value + # devnote: the Level variable is assessed at the end of the timeperiod, so the init ± flows + # should total the end value + for r, p, s, d, t, v in start_slices: + inflow_indices = { + (rr, pp, ss, dd, ii, tt, vv, oo) + for rr, pp, ss, dd, ii, tt, vv, oo in model.FlowInStorage_rpsditvo + if all((rr == r, pp == p, ss == s, dd == d, tt == t, vv == v)) + } + outflow_indices = { + (rr, pp, ss, dd, ii, tt, vv, oo) + for (rr, pp, ss, dd, ii, tt, vv, oo) in model.FlowVar_rpsditvo + if all((rr == r, pp == p, ss == s, dd == d, tt == t, vv == v)) + } + + # calculate the inflow and outflow. Inflow is taxed by efficiency in the model, + # so we need to do that here as well + inflow = sum( + model.V_FlowIn[r, p, s, d, i, t, v, o].value * model.Efficiency[r, i, t, v, o] + for (r, p, s, d, i, t, v, o) in inflow_indices + ) + outflow = sum(model.V_FlowOut[idx].value for idx in outflow_indices) + assert model.V_StorageInit[r, p, s, t, v].value + inflow - outflow == pytest.approx( + model.V_StorageLevel[r, p, s, d, t, v].value, rel=1e-3 + ), f'model fails to initialise storage state at start of season {r, p, s, t, v}' @pytest.mark.parametrize( @@ -61,9 +125,10 @@ def test_initialization_in_last_period(system_test_run): indirect=True, ids=[d['name'] for d in storage_config_files], ) -def test_initialization_in_first_period(system_test_run): +def test_season_end(system_test_run): """ - The level at the end of the first period should be the initialization ± flows + The season should end on the appropriate initialisation state + (state should loop correctly) """ model: TemoaModel # helps with typing for some reason... @@ -72,16 +137,16 @@ def test_initialization_in_first_period(system_test_run): 'This model does not appear to have' 'any available storage components' ) # test the first periods - # get references to first timeslot for each prtv combo in things with storage - first_slots = { + # get references to first timeslot for each rptv combo in things with storage + end_slices = { (r, p, s, d, t, v) for r, p, s, d, t, v in model.StorageLevel_rpsdtv - if s == model.time_season.first() and d == model.time_of_day.first() + if d == model.time_of_day.last() } # test that the last day/season combo starts up at the initialization value # devnote: the Level variable is assessed at the end of the timeperiod, so the init ± flows # should total the end value - for r, p, s, d, t, v in first_slots: + for r, p, s, d, t, v in end_slices: inflow_indices = { (rr, pp, ss, dd, ii, tt, vv, oo) for rr, pp, ss, dd, ii, tt, vv, oo in model.FlowInStorage_rpsditvo @@ -100,10 +165,23 @@ def test_initialization_in_first_period(system_test_run): for (r, p, s, d, i, t, v, o) in inflow_indices ) outflow = sum(model.V_FlowOut[idx].value for idx in outflow_indices) - start = model.V_StorageInit[r, t, v].value - assert model.V_StorageInit[r, t, v].value + inflow - outflow == pytest.approx( - model.V_StorageLevel[r, p, s, d, t, v].value, rel=1e-3 - ), f'model fails to align last season/day slot with initialization value for {r, t, v}' + + if model.interseason_storage: + # periods loop + if s == model.time_season.last(): + # end of last season should loop to start of first season + following_init = model.V_StorageInit[r, p, model.time_season.first(), t, v].value + else: + # end of other seasons should continue to start of next season + following_init = model.V_StorageInit[r, p, model.time_season.next(s), t, v].value + else: + # seasons loop + # end of season should loop to start of same season + following_init = model.V_StorageInit[r, p, s, t, v].value + + assert model.V_StorageLevel[r, p, s, d, t, v].value + inflow - outflow == pytest.approx( + following_init, rel=1e-3 + ), f'model fails to correctly loop storage state at end of season {r, p, s, t, v}' @pytest.mark.parametrize( @@ -143,7 +221,7 @@ def test_storage_flow_balance(system_test_run): outflow = sum(model.V_FlowOut[idx].value for idx in outflow_indices) assert inflow == pytest.approx( outflow, rel=1e-3 - ), f'the inflow and outflow of storage tech {s_tech} do not match' + ), f'total inflow and outflow of storage tech {s_tech} do not match - not looping state correctly' @pytest.mark.skip('not ready for primetime') diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 8b6c97397..cbc10643e 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -10,6 +10,7 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); +INSERT INTO MetaData VALUES('link_seasons',1,'Carry storage states between seasons'); CREATE TABLE MetaDataReal ( element TEXT, diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 72e6d51bb..0233ac4b7 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -10,6 +10,7 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); INSERT INTO MetaData VALUES('myopic_base_year',2000,''); +INSERT INTO MetaData VALUES('link_seasons',1,'Carry storage states between seasons'); CREATE TABLE MetaDataReal ( element TEXT, diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 1930109b6..e6a962455 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -1691,9 +1691,18 @@ "MaxActivityShareConstraint_rptg": [], "MinNewCapacityShareConstraint_rptg": [], "MaxNewCapacityShareConstraint_rptg": [], - "StorageInit_rtv": [ + "StorageInit_rpstv": [ [ "B", + 2025, + "s1", + "batt", + 2025 + ], + [ + "B", + 2025, + "s2", "batt", 2025 ] @@ -2526,14 +2535,6 @@ ] ], "StorageLevel_rpsdtv": [ - [ - "B", - 2025, - "s2", - "d2", - "batt", - 2025 - ], [ "B", 2025, @@ -2549,14 +2550,6 @@ "d1", "batt", 2025 - ], - [ - "B", - 2025, - "s1", - "d2", - "batt", - 2025 ] ], "CapacityVar_rptv": [ @@ -3945,8 +3938,8 @@ 2025 ] ], - "StorageInitConstraint_rtv": [], - "RampConstraintDay_rpsdtv": [ + "StorageInitFracConstraint_rpstv": [], + "RampConstraint_rpsdtv": [ [ "A", 2025, @@ -4012,20 +4005,6 @@ 2025 ] ], - "RampConstraintPeriod_rptv": [ - [ - "B", - 2025, - "EH", - 2025 - ], - [ - "A", - 2025, - "EH", - 2025 - ] - ], "ReserveMargin_rpsd": [ [ "A", diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index 9ce704833..0ede3b641 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -10,6 +10,7 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); INSERT INTO MetaData VALUES('myopic_base_year',1990,''); +INSERT INTO MetaData VALUES('link_seasons',1,'Carry storage states between seasons'); CREATE TABLE MetaDataReal ( element TEXT, diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index ca9c9e166..6704be263 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -10,6 +10,7 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); INSERT INTO MetaData VALUES('myopic_base_year',2000,''); +INSERT INTO MetaData VALUES('link_seasons',1,'Carry storage states between seasons'); CREATE TABLE MetaDataReal ( element TEXT, @@ -600,13 +601,17 @@ CREATE TABLE StorageDuration PRIMARY KEY (region, tech) ); INSERT INTO StorageDuration VALUES('electricville','batt',10.0,NULL); -CREATE TABLE StorageInit -( - tech TEXT - PRIMARY KEY, - value REAL, +CREATE TABLE StorageInitFrac +( + region TEXT, + period INTEGER REFERENCES TimePeriod (period), + season TEXT REFERENCES TimeSeason (season), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), + frac REAL, notes TEXT ); +INSERT INTO StorageInitFrac VALUES('electricville',2025,'s1','batt',2025,0.5,''); CREATE TABLE TechnologyType ( label TEXT diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 16b1e01d0..e99b27694 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -10,6 +10,7 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); +INSERT INTO MetaData VALUES('link_seasons',1,'Carry storage states between seasons'); CREATE TABLE MetaDataReal ( element TEXT, @@ -963,13 +964,18 @@ CREATE TABLE StorageDuration ); INSERT INTO StorageDuration VALUES('R1','E_BATT',8.0,'8-hour duration specified as fraction of a day'); INSERT INTO StorageDuration VALUES('R2','E_BATT',8.0,'8-hour duration specified as fraction of a day'); -CREATE TABLE StorageInit -( - tech TEXT - PRIMARY KEY, - value REAL, +CREATE TABLE StorageInitFrac +( + region TEXT, + period INTEGER REFERENCES TimePeriod (period), + season TEXT REFERENCES TimeSeason (season), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), + frac REAL, notes TEXT ); +INSERT INTO StorageInitFrac VALUES('R1',2025,'winter','E_BATT',2025,0.5,''); +INSERT INTO StorageInitFrac VALUES('R2',2020,'summer','E_BATT',2020,0.5,''); CREATE TABLE TechnologyType ( label TEXT diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 225a08872..86d419f08 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -6949,36 +6949,342 @@ "MaxActivityShareConstraint_rptg": [], "MinNewCapacityShareConstraint_rptg": [], "MaxNewCapacityShareConstraint_rptg": [], - "StorageInit_rtv": [ + "StorageInit_rpstv": [ + [ + "R1", + 2020, + "summer", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "spring", + "E_BATT", + 2030 + ], [ "R2", + 2025, + "fall", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "winter", "E_BATT", 2030 ], + [ + "R1", + 2030, + "fall", + "E_BATT", + 2020 + ], [ "R2", + 2025, + "winter", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "summer", + "E_BATT", + 2025 + ], + [ + "R2", + 2025, + "spring", + "E_BATT", + 2025 + ], + [ + "R2", + 2025, + "summer", + "E_BATT", + 2025 + ], + [ + "R1", + 2020, + "winter", "E_BATT", 2020 ], [ "R1", + 2025, + "spring", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "winter", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "spring", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "summer", "E_BATT", 2030 ], [ "R1", + 2025, + "fall", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "spring", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "winter", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "winter", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "summer", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "fall", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "fall", + "E_BATT", + 2025 + ], + [ + "R1", + 2020, + "spring", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "fall", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "summer", + "E_BATT", + 2030 + ], + [ + "R2", + 2020, + "fall", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "summer", "E_BATT", 2020 ], [ "R2", + 2030, + "winter", + "E_BATT", + 2030 + ], + [ + "R2", + 2025, + "summer", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "spring", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "winter", "E_BATT", 2025 ], [ "R1", + 2025, + "summer", "E_BATT", 2025 + ], + [ + "R1", + 2030, + "spring", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "winter", + "E_BATT", + 2025 + ], + [ + "R1", + 2025, + "winter", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "fall", + "E_BATT", + 2030 + ], + [ + "R2", + 2030, + "fall", + "E_BATT", + 2030 + ], + [ + "R1", + 2030, + "summer", + "E_BATT", + 2020 + ], + [ + "R2", + 2020, + "spring", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "spring", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "winter", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "spring", + "E_BATT", + 2020 + ], + [ + "R2", + 2020, + "winter", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "summer", + "E_BATT", + 2025 + ], + [ + "R1", + 2025, + "fall", + "E_BATT", + 2020 + ], + [ + "R1", + 2020, + "fall", + "E_BATT", + 2020 + ], + [ + "R2", + 2020, + "summer", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "spring", + "E_BATT", + 2030 + ], + [ + "R2", + 2030, + "fall", + "E_BATT", + 2020 ] ], "FlowVar_rpsditvo": [ @@ -22354,22 +22660,6 @@ [ "R1", 2030, - "fall", - "night", - "E_BATT", - 2030 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, "winter", "day", "E_BATT", @@ -22389,48 +22679,8 @@ "summer", "day", "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_BATT", 2020 ], - [ - "R1", - 2025, - "spring", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_BATT", - 2030 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_BATT", - 2025 - ], [ "R2", 2025, @@ -22439,40 +22689,8 @@ "E_BATT", 2025 ], - [ - "R2", - 2025, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "winter", - "day", - "E_BATT", - 2020 - ], [ "R1", - 2020, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R2", 2030, "fall", "day", @@ -22481,98 +22699,26 @@ ], [ "R1", - 2030, + 2025, "fall", "day", "E_BATT", - 2025 - ], - [ - "R1", - 2020, - "spring", - "night", - "E_BATT", 2020 ], - [ - "R2", - 2030, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_BATT", - 2025 - ], [ "R1", - 2030, - "fall", - "night", - "E_BATT", - 2025 - ], - [ - "R2", 2025, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, "summer", "day", "E_BATT", 2025 ], - [ - "R1", - 2030, - "summer", - "day", - "E_BATT", - 2020 - ], [ "R2", 2030, - "summer", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, "fall", "day", "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_BATT", 2020 ], [ @@ -22581,31 +22727,23 @@ "spring", "day", "E_BATT", - 2025 + 2020 ], [ "R1", - 2025, - "fall", - "night", - "E_BATT", - 2025 - ], - [ - "R2", 2030, - "fall", + "spring", "day", "E_BATT", 2025 ], [ - "R1", + "R2", 2030, - "fall", + "spring", "day", "E_BATT", - 2020 + 2025 ], [ "R2", @@ -22617,47 +22755,7 @@ ], [ "R1", - 2025, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R2", 2020, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, "summer", "day", "E_BATT", @@ -22665,31 +22763,7 @@ ], [ "R1", - 2030, - "spring", - "day", - "E_BATT", - 2030 - ], - [ - "R2", 2020, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_BATT", - 2030 - ], - [ - "R1", - 2025, "fall", "day", "E_BATT", @@ -22697,35 +22771,19 @@ ], [ "R2", - 2025, + 2030, "summer", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "spring", "day", "E_BATT", 2020 ], - [ - "R1", - 2025, - "fall", - "night", - "E_BATT", - 2020 - ], [ "R2", 2030, - "fall", + "winter", "day", "E_BATT", - 2020 + 2030 ], [ "R1", @@ -22737,96 +22795,48 @@ ], [ "R1", - 2025, + 2030, "summer", "day", "E_BATT", 2025 ], - [ - "R1", - 2030, - "winter", - "night", - "E_BATT", - 2030 - ], [ "R2", - 2025, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R1", 2020, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, "summer", - "night", + "day", "E_BATT", 2020 ], [ "R1", 2030, - "spring", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, "fall", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "summer", - "night", + "day", "E_BATT", 2020 ], [ "R2", 2025, - "spring", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, "winter", "day", "E_BATT", - 2030 + 2020 ], [ "R1", - 2020, + 2025, "fall", "day", "E_BATT", - 2020 + 2025 ], [ - "R1", + "R2", 2030, - "winter", + "fall", "day", "E_BATT", 2025 @@ -22834,42 +22844,26 @@ [ "R1", 2025, - "summer", + "winter", "day", "E_BATT", 2020 ], [ - "R1", - 2030, - "winter", - "night", - "E_BATT", - 2025 - ], - [ - "R1", + "R2", 2025, - "winter", + "spring", "day", "E_BATT", 2025 ], - [ - "R2", - 2030, - "summer", - "night", - "E_BATT", - 2020 - ], [ "R1", - 2030, + 2025, "spring", - "night", + "day", "E_BATT", - 2030 + 2020 ], [ "R1", @@ -22877,12 +22871,12 @@ "spring", "day", "E_BATT", - 2020 + 2030 ], [ "R2", - 2020, - "spring", + 2025, + "fall", "day", "E_BATT", 2020 @@ -22890,8 +22884,8 @@ [ "R2", 2030, - "fall", - "night", + "winter", + "day", "E_BATT", 2020 ], @@ -22905,55 +22899,39 @@ ], [ "R1", - 2025, - "summer", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R2", 2030, - "spring", - "night", + "winter", + "day", "E_BATT", - 2030 + 2020 ], [ "R2", 2030, - "winter", + "summer", "day", "E_BATT", 2025 ], [ - "R1", - 2030, - "winter", + "R2", + 2025, + "summer", "day", "E_BATT", 2020 ], [ "R1", - 2025, + 2020, "spring", "day", "E_BATT", - 2025 + 2020 ], [ "R1", - 2020, + 2025, "summer", "day", "E_BATT", @@ -22961,161 +22939,105 @@ ], [ "R1", - 2025, - "winter", + 2030, + "summer", "day", "E_BATT", - 2020 + 2030 ], [ "R1", 2030, - "spring", - "night", + "fall", + "day", "E_BATT", 2025 ], [ - "R2", + "R1", 2030, - "winter", - "night", + "spring", + "day", "E_BATT", - 2030 + 2020 ], [ "R2", - 2030, - "spring", + 2025, + "winter", "day", "E_BATT", 2025 ], [ - "R1", + "R2", 2020, "winter", "day", "E_BATT", 2020 ], - [ - "R1", - 2025, - "summer", - "night", - "E_BATT", - 2020 - ], [ "R2", 2020, - "summer", + "spring", "day", "E_BATT", 2020 ], [ - "R1", + "R2", 2030, - "summer", + "fall", "day", "E_BATT", 2030 ], [ "R2", - 2025, - "fall", + 2030, + "spring", "day", "E_BATT", - 2025 + 2020 ], [ "R1", 2025, "winter", - "night", + "day", "E_BATT", 2025 ], [ "R1", 2020, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, "winter", "day", "E_BATT", 2020 ], - [ - "R2", - 2020, - "summer", - "night", - "E_BATT", - 2020 - ], [ "R1", 2025, "spring", "day", "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_BATT", - 2030 + 2025 ], [ "R2", 2025, "fall", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "fall", "day", "E_BATT", - 2030 - ], - [ - "R2", - 2020, - "spring", - "night", - "E_BATT", - 2020 + 2025 ], [ "R2", 2030, "winter", - "night", + "day", "E_BATT", 2025 ] @@ -42995,9 +42917,23 @@ 2025 ] ], - "StorageInitConstraint_rtv": [], - "RampConstraintDay_rpsdtv": [], - "RampConstraintPeriod_rptv": [], + "StorageInitFracConstraint_rpstv": [ + [ + "R1", + 2025, + "winter", + "E_BATT", + 2025 + ], + [ + "R2", + 2020, + "summer", + "E_BATT", + 2020 + ] + ], + "RampConstraint_rpsdtv": [], "ReserveMargin_rpsd": [ [ "R2", diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index ff69a0e14..f43ae13fd 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -10,6 +10,7 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('myopic_base_year',1990,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); +INSERT INTO MetaData VALUES('link_seasons',1,'Carry storage states between seasons'); CREATE TABLE MetaDataReal ( element TEXT, diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 3a04814f1..8b34cc397 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -5300,26 +5300,195 @@ "MaxActivityShareConstraint_rptg": [], "MinNewCapacityShareConstraint_rptg": [], "MaxNewCapacityShareConstraint_rptg": [], - "StorageInit_rtv": [ + "StorageInit_rpstv": [ [ "utopia", + 2000, + "summer", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "E51", + 2000 + ], + [ + "utopia", + 2000, + "winter", + "E51", + 1980 + ], + [ + "utopia", + 1990, + "summer", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "E51", + 2010 + ], + [ + "utopia", + 2010, + "summer", + "E51", + 2000 + ], + [ + "utopia", + 1990, + "inter", + "E51", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "E51", + 2010 + ], + [ + "utopia", + 1990, + "winter", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "inter", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "E51", + 1980 + ], + [ + "utopia", + 1990, + "inter", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "E51", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "E51", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "E51", + 1990 + ], + [ + "utopia", + 1990, + "winter", "E51", 1990 ], [ "utopia", + 1990, + "summer", "E51", 1980 ], [ "utopia", + 2000, + "inter", + "E51", + 2000 + ], + [ + "utopia", + 2010, + "summer", "E51", 2010 ], [ "utopia", + 2010, + "winter", "E51", 2000 + ], + [ + "utopia", + 2000, + "inter", + "E51", + 1980 + ], + [ + "utopia", + 2010, + "winter", + "E51", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "E51", + 1980 ] ], "FlowVar_rpsditvo": [ @@ -13491,58 +13660,10 @@ ] ], "StorageLevel_rpsdtv": [ - [ - "utopia", - 2010, - "summer", - "day", - "E51", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E51", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E51", - 2010 - ], [ "utopia", 2000, - "winter", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2010, "summer", - "night", - "E51", - 2000 - ], - [ - "utopia", - 2000, - "inter", "day", "E51", 2000 @@ -13551,34 +13672,10 @@ "utopia", 2010, "winter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "inter", "day", "E51", 2000 ], - [ - "utopia", - 2000, - "summer", - "day", - "E51", - 1990 - ], [ "utopia", 2010, @@ -13587,29 +13684,13 @@ "E51", 1980 ], - [ - "utopia", - 2000, - "summer", - "night", - "E51", - 1990 - ], [ "utopia", 2000, "winter", - "night", - "E51", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "night", + "day", "E51", - 2000 + 1990 ], [ "utopia", @@ -13617,27 +13698,11 @@ "summer", "day", "E51", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E51", - 1980 + 2000 ], [ "utopia", 1990, - "inter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2000, "winter", "day", "E51", @@ -13645,19 +13710,11 @@ ], [ "utopia", - 2010, + 2000, "summer", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "winter", "day", "E51", - 2010 + 1980 ], [ "utopia", @@ -13665,24 +13722,8 @@ "inter", "day", "E51", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E51", 1980 ], - [ - "utopia", - 2010, - "inter", - "night", - "E51", - 2000 - ], [ "utopia", 1990, @@ -13697,15 +13738,15 @@ "inter", "day", "E51", - 1990 + 2000 ], [ "utopia", 2000, - "summer", + "inter", "day", "E51", - 1980 + 1990 ], [ "utopia", @@ -13713,75 +13754,35 @@ "summer", "day", "E51", - 2010 + 1980 ], [ "utopia", 2010, - "winter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2000, "inter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", + "day", "E51", 1980 ], - [ - "utopia", - 2010, - "winter", - "night", - "E51", - 2010 - ], [ "utopia", 1990, - "inter", - "night", + "summer", + "day", "E51", - 1980 + 1990 ], [ "utopia", - 2000, + 2010, "winter", "day", "E51", - 1980 + 2010 ], [ "utopia", 2010, - "summer", - "night", - "E51", - 1980 - ], - [ - "utopia", - 1990, "winter", "day", "E51", @@ -13790,14 +13791,14 @@ [ "utopia", 2000, - "inter", + "summer", "day", "E51", - 1980 + 1990 ], [ "utopia", - 2010, + 2000, "winter", "day", "E51", @@ -13806,26 +13807,18 @@ [ "utopia", 2010, - "inter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 1990, "summer", "day", "E51", - 1990 + 2010 ], [ "utopia", - 2010, - "summer", + 2000, + "winter", "day", "E51", - 2000 + 1980 ], [ "utopia", @@ -13833,79 +13826,47 @@ "inter", "day", "E51", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E51", 2010 ], [ "utopia", 1990, "winter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", + "day", "E51", 1980 ], [ "utopia", - 2010, - "winter", - "night", + 1990, + "inter", + "day", "E51", - 2000 + 1990 ], [ "utopia", 2000, "inter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 1990, - "winter", "day", "E51", - 1980 + 2000 ], [ "utopia", 2010, - "inter", + "summer", "day", "E51", - 2010 + 1990 ], [ "utopia", 2010, "inter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "summer", "day", "E51", - 2000 + 1990 ], [ "utopia", @@ -13914,14 +13875,6 @@ "day", "E51", 1980 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E51", - 2000 ] ], "CapacityVar_rptv": [ @@ -24551,9 +24504,8 @@ 2000 ] ], - "StorageInitConstraint_rtv": [], - "RampConstraintDay_rpsdtv": [], - "RampConstraintPeriod_rptv": [], + "StorageInitFracConstraint_rpstv": [], + "RampConstraint_rpsdtv": [], "ReserveMargin_rpsd": [ [ "utopia", From 71a9c3dec667fdf50979e6a82e3914185b05fd24 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 7 Aug 2025 09:11:40 -0400 Subject: [PATCH 016/587] Update GrowthRateMax constraint and replant seed every period --- temoa/temoa_model/temoa_initialize.py | 16 +++++++++------- temoa/temoa_model/temoa_model.py | 9 +++------ temoa/temoa_model/temoa_rules.py | 24 +++++++++++++----------- tests/testing_data/mediumville_sets.json | 2 +- 4 files changed, 26 insertions(+), 25 deletions(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 9e585aa7c..f506b4ebd 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1231,7 +1231,6 @@ def AnnualCommodityBalanceConstraintIndices(M: 'TemoaModel'): return indices -# StorageInit needs an overhaul def StorageInitIndices(M: 'TemoaModel'): indices = set( (r, p, s, t, v) @@ -1264,7 +1263,6 @@ def StorageStateIndices(M: 'TemoaModel'): return indices -# StorageInit needs an overhaul def StorageInitFracIndices(M: 'TemoaModel'): indices = set((r, p, s, t, v) for r, p, s, t, v in M.StorageInitFrac.sparse_iterkeys()) @@ -1384,13 +1382,17 @@ def TechOutputSplitAverageConstraintIndices(M: 'TemoaModel'): return indices -def get_loan_life(M, r, t, _): - return M.LoanLifetimeTech[r, t] +def GrowthRateMaxIndices(M: 'TemoaModel'): + indices = set( + (r, p, t) + for r, t in M.GrowthRateMax.sparse_iterkeys() + for p in M.time_optimize + ) + return indices -def GrowthRateMax_rtv_initializer(M: 'TemoaModel'): - # need to do this outside of the model because the elements are not initialized yet for 'product' - return set(product(M.time_optimize, M.GrowthRateMax.sparse_iterkeys())) +def get_loan_life(M, r, t, _): + return M.LoanLifetimeTech[r, t] def copy_from(other_set): diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 218c3103d..062cd4d53 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -651,12 +651,9 @@ def __init__(M, *args, **kwargs): ['Starting Growth and Activity Constraints'], rule=progress_check ) - M.GrowthRateMaxConstraint_rtv = Set( - dimen=3, - initialize=GrowthRateMax_rtv_initializer, - ) - M.GrowthRateConstraint = Constraint( - M.GrowthRateMaxConstraint_rtv, rule=GrowthRateConstraint_rule + M.GrowthRateMaxConstraint_rtv = Set(dimen=3, initialize=GrowthRateMaxIndices) + M.GrowthRateMaxConstraint = Constraint( + M.GrowthRateMaxConstraint_rtv, rule=GrowthRateMaxConstraint_rule ) M.MaxActivityConstraint = Constraint( diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index c633c3608..35a3deea1 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1839,7 +1839,7 @@ def EmissionLimit_Constraint(M: 'TemoaModel', r, p, e): return expr -def GrowthRateConstraint_rule(M: 'TemoaModel', p, r, t): +def GrowthRateMaxConstraint_rule(M: 'TemoaModel', r, p, t): r""" This constraint sets an upper bound growth rate on technology-specific capacity. @@ -1862,22 +1862,24 @@ def GrowthRateConstraint_rule(M: 'TemoaModel', p, r, t): GRM = value(M.GrowthRateMax[r, t]) CapPT = M.V_CapacityAvailableByPeriodAndTech - periods = sorted(set(p_ for r_, p_, t_ in CapPT if t_ == t)) + # periods the technology can have capacity in this region (sorted) + periods = sorted(set(S_p for S_r, S_p, S_t in CapPT if S_t == t and S_r == r)) if p not in periods: + # cant have capacity in this period return Constraint.Skip - + if p == periods[0]: + # first period it can have capacity + # plant a seed and grow it expr = CapPT[r, p, t] <= GRS * GRM - else: - p_prev = periods.index(p) - p_prev = periods[p_prev - 1] - if (r, p_prev, t) in CapPT.keys(): - expr = CapPT[r, p, t] <= GRM * CapPT[r, p_prev, t] - else: - expr = CapPT[r, p, t] <= GRS * GRM - + # can have capacity in previous period + # plant a seed and grow last period's capacity + # note: we plant a seed every period to survive zero-outs + p_prev = periods[periods.index(p) - 1] # previous period + expr = CapPT[r, p, t] <= GRS + GRM * CapPT[r, p_prev, t] + return expr diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index e6a962455..d7e280b5f 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -4057,8 +4057,8 @@ ], "GrowthRateMaxConstraint_rtv": [ [ - 2025, "A", + 2025, "GeoHeater" ] ], From bc1070b5e14a44406e3aaed2ea1024a169b67fa1 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 7 Aug 2025 09:19:41 -0400 Subject: [PATCH 017/587] Merge embodied emissions - Merge embodied emissions from work by Sutubra - Add embodied emissions to emissions test - Add embodied emissions to OutputEmissions table - Reapply variable and emissions costs fix post merge --- data_files/example_dbs/utopia.sql | 14 +++++ data_files/temoa_schema_v3.sql | 18 +++++- temoa/temoa_model/hybrid_loader.py | 15 +++++ temoa/temoa_model/table_data_puller.py | 67 +++++++++++++++----- temoa/temoa_model/table_writer.py | 8 ++- temoa/temoa_model/temoa_initialize.py | 13 ++-- temoa/temoa_model/temoa_model.py | 2 +- temoa/temoa_model/temoa_rules.py | 57 ++++++++++++----- tests/test_emission_results.py | 85 ++++++++++++++++++++++++-- tests/testing_data/emissions.sql | 38 +++++++++--- 10 files changed, 263 insertions(+), 54 deletions(-) diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index d25e031ad..7e5ed1042 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -566,6 +566,20 @@ INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',1980,'TX',1.0,'', INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',1990,'TX',1.0,'',''); INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',2000,'TX',1.0,'',''); INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',2010,'TX',1.0,'',''); +CREATE TABLE EmissionEmbodied +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); CREATE TABLE ExistingCapacity ( region TEXT, diff --git a/data_files/temoa_schema_v3.sql b/data_files/temoa_schema_v3.sql index 3c03e7b80..20014d4db 100644 --- a/data_files/temoa_schema_v3.sql +++ b/data_files/temoa_schema_v3.sql @@ -193,8 +193,8 @@ CREATE TABLE IF NOT EXISTS DemandSpecificDistribution REFERENCES TimeOfDay (tod), demand_name TEXT REFERENCES Commodity (name), - dds REAL, - dds_notes TEXT, + dsd REAL, + dsd_notes TEXT, PRIMARY KEY (region, season, tod, demand_name), CHECK (dds >= 0 AND dds <= 1) ); @@ -243,6 +243,20 @@ CREATE TABLE IF NOT EXISTS EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); +CREATE TABLE IF NOT EXISTS EmissionEmbodied +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); CREATE TABLE IF NOT EXISTS ExistingCapacity ( region TEXT, diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index d496b753d..2c2f37197 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -1144,6 +1144,21 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): ).fetchall() load_element(M.EmissionActivity, raw, self.viable_ritvo, (0, 2, 3, 4, 5)) + # EmissionEmbodied + if self.table_exists('EmissionEmbodied'): + if mi: + raw = cur.execute( + 'SELECT region, emis_comm, tech, vintage, value ' + 'FROM main.EmissionEmbodied' + ).fetchall() + else: + raw = cur.execute( + 'SELECT region, emis_comm, tech, vintage, value ' + 'FROM main.EmissionEmbodied' + ).fetchall() + load_element(M.EmissionEmbodied, raw, self.viable_rtv, (0, 2, 3)) + + # LinkedTechs # Note: Both of the linked techs must be viable. As this is non period/vintage # specific, it should be true that if one is built, the other is also diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index 3a2ad85a1..f6b3cce0a 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -331,10 +331,10 @@ def poll_cost_results( continue var_cost = value(M.CostVariable[r, p, t, v]) - undiscounted_var_cost = activity * var_cost * value(MPL[r, p, t, v]) + undiscounted_var_cost = activity * var_cost * value(M.PeriodLength[p]) model_var_cost = temoa_rules.fixed_or_variable_cost( - activity, var_cost, value(MPL[r, p, t, v]), GDR=GDR, P_0=p_0, p=p + activity, var_cost, value(M.PeriodLength[p]), GDR=GDR, P_0=p_0, p=p ) if '-' in r: exchange_costs.add_cost_record( @@ -424,7 +424,10 @@ def poll_emissions( p_0 = min(M.time_optimize) GDR = value(M.GlobalDiscountRate) - MPL = M.ModelProcessLife + + ########################### + # Process Emissions + ########################### base = [ (r, p, e, i, t, v, o) @@ -459,32 +462,68 @@ def poll_emissions( ud_costs = defaultdict(float) d_costs = defaultdict(float) for ei in flows: + # zero out tiny flows + if abs(flows[ei]) < epsilon: + flows[ei] = 0.0 + continue # screen to see if there is an associated cost cost_index = (ei.r, ei.p, ei.e) if cost_index not in M.CostEmission: continue - # check for epsilon - if abs(flows[ei]) < epsilon: - flows[ei] = 0.0 - continue undiscounted_emiss_cost = ( - flows[ei] * M.CostEmission[ei.r, ei.p, ei.e] * MPL[ei.r, ei.p, ei.t, ei.v] + flows[ei] * M.CostEmission[ei.r, ei.p, ei.e] * M.PeriodLength[ei.p] ) discounted_emiss_cost = temoa_rules.fixed_or_variable_cost( cap_or_flow=flows[ei], cost_factor=M.CostEmission[ei.r, ei.p, ei.e], - process_lifetime=MPL[ei.r, ei.p, ei.t, ei.v], + cost_years=M.PeriodLength[ei.p], GDR=GDR, P_0=p_0, p=ei.p, ) ud_costs[ei.r, ei.p, ei.t, ei.v] += undiscounted_emiss_cost d_costs[ei.r, ei.p, ei.t, ei.v] += discounted_emiss_cost + + ########################### + # Embodied Emissions + ########################### + + # iterate through embodied flows + embodied_flows: dict[EI, float] = defaultdict(float) + for r, e, t, v in M.EmissionEmbodied.sparse_iterkeys(): + embodied_flows[EI(r, v, t, v, e)] += value(M.V_NewCapacity[r, t, v] * M.EmissionEmbodied[r, e, t, v]) # for embodied costs + flows[EI(r, v, t, v, e)] += value(M.V_NewCapacity[r, t, v] * M.EmissionEmbodied[r, e, t, v]) # add embodied to process emissions + + # add embodied costs to process costs + for ei in embodied_flows: + # zero out again if still tiny after embodied flows + if abs(flows[ei]) < epsilon: + flows[ei] = 0.0 + continue + # screen to see if there is an associated cost + cost_index = (ei.r, ei.v, ei.e) + if cost_index not in M.CostEmission: + continue + undiscounted_emiss_cost = ( + embodied_flows[ei] * M.CostEmission[ei.r, ei.v, ei.e] * 1 # treat as fixed cost incurred in a single year (year of construction) + ) + discounted_emiss_cost = temoa_rules.fixed_or_variable_cost( + cap_or_flow=embodied_flows[ei], + cost_factor=M.CostEmission[ei.r, ei.v, ei.e], + cost_years=1, # treat as fixed cost incurred in a single year (year of construction) + GDR=GDR, + P_0=p_0, + p=ei.v, + ) + ud_costs[ei.r, ei.v, ei.t, ei.v] += undiscounted_emiss_cost + d_costs[ei.r, ei.v, ei.t, ei.v] += discounted_emiss_cost + + # finally, now that all costs are added up for each rptv, put in cost dict costs = defaultdict(dict) - for k in ud_costs: - costs[k][CostType.EMISS] = ud_costs[k] - for k in d_costs: - costs[k][CostType.D_EMISS] = d_costs[k] + for rptv in ud_costs: + costs[rptv][CostType.EMISS] = ud_costs[rptv] + for rptv in d_costs: + costs[rptv][CostType.D_EMISS] = d_costs[rptv] # wow, that was like pulling teeth - return costs, flows + return costs, flows \ No newline at end of file diff --git a/temoa/temoa_model/table_writer.py b/temoa/temoa_model/table_writer.py index 1992f3c9d..416692417 100644 --- a/temoa/temoa_model/table_writer.py +++ b/temoa/temoa_model/table_writer.py @@ -128,6 +128,7 @@ def write_results( else: p_0 = None # min year will be used in poll e_costs, e_flows = poll_emissions(M=M, p_0=p_0) + self.emission_register = e_flows self.write_emissions(iteration=iteration) self.write_costs(M, emission_entries=e_costs, iteration=iteration) @@ -251,7 +252,10 @@ def write_emissions(self, iteration=None) -> None: val = self.emission_register[ei] if abs(val) < self.epsilon: continue - entry = (scenario, ei.r, sector, ei.p, ei.e, ei.t, ei.v, val) + if hasattr(ei, 'p'): # emissions from flows + entry = (scenario, ei.r, sector, ei.p, ei.e, ei.t, ei.v, val) + else: # embodied emissions + entry = (scenario, ei.r, sector, ei.v, ei.e, ei.t, ei.v, val) data.append(entry) qry = f'INSERT INTO OutputEmission VALUES {_marks(8)}' self.con.executemany(qry, data) @@ -322,7 +326,7 @@ def write_flow_tables(self, iteration=None) -> None: FlowType.OUT: 'OutputFlowOut', FlowType.IN: 'OutputFlowIn', FlowType.CURTAIL: 'OutputCurtailment', - FlowType.FLEX: 'OutputCurtailment', + FlowType.FLEX: 'OutputCurtailment', # devnote: should flex have its own table? } for flow_type, table_name in table_associations.items(): diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index f506b4ebd..b385aad66 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -958,13 +958,14 @@ def EmissionActivityIndices(M: 'TemoaModel'): return indices +# devnote: this does not appear to be used anywhere +# given that it doesnt check if periods are valid, cant think what it would be for +# def EmissionActivityByPeriodAndTechVariableIndices(M: 'TemoaModel'): +# indices = set( +# (e, p, t) for e, i, t, v, o in M.EmissionActivity.sparse_iterkeys() for p in M.time_optimize +# ) -def EmissionActivityByPeriodAndTechVariableIndices(M: 'TemoaModel'): - indices = set( - (e, p, t) for e, i, t, v, o in M.EmissionActivity.sparse_iterkeys() for p in M.time_optimize - ) - - return indices +# return indices def ModelProcessLifeIndices(M: 'TemoaModel'): diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 062cd4d53..277f98513 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -455,8 +455,8 @@ def __init__(M, *args, **kwargs): M.StorageDuration = Param(M.regions, M.tech_storage, default=4) # Initial storage charge level, expressed as fraction of full energy capacity. # If the parameter is not defined, the model optimizes the initial storage charge level. - # Dev note: needs overhaul M.StorageInitFrac = Param(M.regions, M.time_optimize, M.time_season, M.tech_storage, M.vintage_all) + M.EmissionEmbodied = Param(M.regions, M.commodity_emissions, M.tech_with_capacity, M.vintage_optimize) M.MyopicBaseyear = Param(default=0) M.link_seasons = Param(default=0) # do states carry from one season to the next? otherwise loop each season diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 35a3deea1..81c20f670 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -110,7 +110,7 @@ def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): capacity = value(M.CapacityFactorProcess[r, s, d, t, v]) else: # use the capacity factor for the tech capacity = value(M.CapacityFactorTech[r, s, d, t]) - + if t in M.tech_curtailment: # If technologies are present in the curtailment set, then enough # capacity must be available to cover both activity and curtailment. @@ -424,7 +424,7 @@ def loan_cost( def fixed_or_variable_cost( cap_or_flow: float | Var, cost_factor: float, - process_lifetime: float, + cost_years: float, GDR: float | None, P_0: float, p: int, @@ -434,7 +434,7 @@ def fixed_or_variable_cost( flow as the driving variable.) :param cap_or_flow: Capacity if fixed cost / flow out if variable :param cost_factor: the cost (either fixed or variable) of the cap/flow variable - :param process_lifetime: see the computation of this variable separately + :param cost_years: for how many years is this cost incurred :param GDR: discount rate or None :param P_0: the period to discount this back to :param p: the period under evaluation @@ -444,9 +444,9 @@ def fixed_or_variable_cost( res = cap_or_flow * ( cost_factor * ( - process_lifetime + cost_years if not GDR - else (x ** (P_0 - p + 1) * (1 - x ** (-process_lifetime)) / GDR) + else (x ** (P_0 - p + 1) * (1 - x ** (-cost_years)) / GDR) ) ) return res @@ -557,7 +557,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): fixed_or_variable_cost( cap_or_flow=M.V_FlowOut[r, p, s, d, i, t, v, o] * M.EmissionActivity[r, e, i, t, v, o], cost_factor=M.CostEmission[r, p, e], - process_lifetime=M.PeriodLength[p], + cost_years=M.PeriodLength[p], GDR=GDR, P_0=P_0, p=p, @@ -565,16 +565,16 @@ def PeriodCost_rule(M: 'TemoaModel', p): for (r, p, e, s, d, i, t, v, o) in normal ) - # 2. flex emissions -- removed (double counting) + # 2. flex emissions -- removed (double counting, flex wastes are SUBTRACTIVE from flowout) - # 3. curtailment emissions -- removed (curtailment consumes no input, so no emittances) + # 3. curtailment emissions -- removed (curtailment is no-flow, for accounting only, so no emissions) # 4. annual emissions var_annual_emissions = sum( fixed_or_variable_cost( cap_or_flow=M.V_FlowOutAnnual[r, p, i, t, v, o] * M.EmissionActivity[r, e, i, t, v, o], cost_factor=M.CostEmission[r, p, e], - process_lifetime=M.PeriodLength[p], + cost_years=M.PeriodLength[p], GDR=GDR, P_0=P_0, p=p, @@ -582,9 +582,24 @@ def PeriodCost_rule(M: 'TemoaModel', p): for (r, p, e, i, t, v, o) in annual if t not in M.tech_flex ) - # 5. flex annual emissions -- removed (double counting) - period_emission_cost = var_emissions + var_annual_emissions + # 5. flex annual emissions -- removed (double counting, flex wastes are SUBTRACTIVE from flowout) + + # 6. embodied - treated as a fixed cost in a single year (year of construction) + embodied_emissions = sum( + fixed_or_variable_cost( + cap_or_flow=M.V_NewCapacity[r, t, v] * M.EmissionEmbodied[r, e, t, v], + cost_factor=M.CostEmission[r, p, e], + cost_years=1, # We assume the embodied emissions are emitted in the same year as the capacity is installed. + GDR=GDR, + P_0=P_0, + p=p, + ) + for (r, e, t, v) in M.EmissionEmbodied.sparse_iterkeys() + if v == p + ) + + period_emission_cost = var_emissions + var_annual_emissions + embodied_emissions period_costs = ( loan_costs + fixed_costs + variable_costs + variable_costs_annual + period_emission_cost @@ -1804,7 +1819,7 @@ def EmissionLimit_Constraint(M: 'TemoaModel', r, p, e): # Flex flows are deducted from V_FlowOut, so it is NOT NEEDED to tax them again. (See commodity balance constr) # Curtailment does not draw any inputs, so it seems logical that curtailed flows not be taxed either - actual_emissions = sum( + process_emissions = sum( M.V_FlowOut[reg, p, S_s, S_d, S_i, S_t, S_v, S_o] * M.EmissionActivity[reg, e, S_i, S_t, S_v, S_o] for reg in regions @@ -1816,7 +1831,7 @@ def EmissionLimit_Constraint(M: 'TemoaModel', r, p, e): for S_d in M.time_of_day ) - actual_emissions_annual = sum( + process_emissions_annual = sum( M.V_FlowOutAnnual[reg, p, S_i, S_t, S_v, S_o] * M.EmissionActivity[reg, e, S_i, S_t, S_v, S_o] for reg in regions @@ -1826,7 +1841,20 @@ def EmissionLimit_Constraint(M: 'TemoaModel', r, p, e): if (reg, p, S_t, S_v) in M.processInputs.keys() ) - expr = actual_emissions + actual_emissions_annual <= emission_limit + embodied_emissions = sum( + M.V_NewCapacity[r, t, v] + * M.EmissionEmbodied[r, e, t, v] + for (S_r, S_e, t, v) in M.EmissionEmbodied.sparse_iterkeys() + if v == p and S_r == r and S_e == e + ) + + expr = ( + process_emissions + process_emissions_annual + embodied_emissions + # + emissions_flex # NO! flex is subtracted from flowout, already accounted by flowout + # + emissions_curtail # NO! curtailed flows are not actual flows, just an accounting tool + # + emissions_flex_annual # NO! flexannual is subtracted from flowoutannual, already accounted + <= emission_limit + ) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated @@ -1836,6 +1864,7 @@ def EmissionLimit_Constraint(M: 'TemoaModel', r, p, e): logger.warning(msg, (e, emission_limit)) SE.write(msg % (e, emission_limit)) return Constraint.Skip + return expr diff --git a/tests/test_emission_results.py b/tests/test_emission_results.py index 129494bc1..e212174dc 100644 --- a/tests/test_emission_results.py +++ b/tests/test_emission_results.py @@ -71,6 +71,10 @@ def solved_connection(request, tmp_path_factory): {'name': 'total', 'tech': '%', 'target': 3.6}, ] +embodied_tests = [ + {'name': 'embodied archetype', 'tech': 'TechEmbodied', 'target': 0.3}, +] + # Emissions @pytest.mark.parametrize( @@ -86,7 +90,7 @@ def test_emissions(solved_connection): con, name, tech, emis_target = solved_connection emis = ( con.cursor() - .execute(f"SELECT SUM(emission) FROM main.OutputEmission WHERE tech LIKE '{tech}'") + .execute(f"SELECT SUM(emission) FROM main.OutputEmission WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied'") .fetchone()[0] ) assert emis == pytest.approx( @@ -103,12 +107,12 @@ def test_emissions(solved_connection): ) def test_emissions_costs_undiscounted(solved_connection): """ - Test that the emission costs from each technology archetype are correct, and check total emissions + Test that the undiscounted emission costs from each technology archetype are correct """ con, name, tech, emis_target = solved_connection ec = ( con.cursor() - .execute(f"SELECT SUM(emiss) FROM main.OutputCost WHERE tech LIKE '{tech}'") + .execute(f"SELECT SUM(emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied'") .fetchone()[0] ) cost_target = 0.7 * emis_target * 5 # emission cost x emissions x 5y @@ -126,12 +130,12 @@ def test_emissions_costs_undiscounted(solved_connection): ) def test_emissions_costs_discounted(solved_connection): """ - Test that the emission costs from each technology archetype are correct, and check total emissions + Test that the discounted emission costs from each technology archetype are correct """ con, name, tech, emis_target = solved_connection ec = ( con.cursor() - .execute(f"SELECT SUM(d_emiss) FROM main.OutputCost WHERE tech LIKE '{tech}'") + .execute(f"SELECT SUM(d_emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied'") .fetchone()[0] ) cost_target = ( @@ -142,6 +146,76 @@ def test_emissions_costs_discounted(solved_connection): ), f'{name} discounted emission costs were incorrect. Should be {cost_target}, got {ec}' +# Embodied emissions +@pytest.mark.parametrize( + 'solved_connection', + argvalues=embodied_tests, + indirect=True, + ids=[t['name'] for t in embodied_tests], +) +def test_embodied_emissions(solved_connection): + """ + Test that the embodied emissions from each technology archetype are correct, and check total emissions + """ + con, name, tech, emis_target = solved_connection + emis = ( + con.cursor() + .execute(f"SELECT SUM(emission) FROM main.OutputEmission WHERE tech LIKE '{tech}'") + .fetchone()[0] + ) + assert emis == pytest.approx( + emis_target + ), f'{name} embodied emissions were incorrect. Should be {emis_target}, got {emis}' + + +# Embodied emission costs undiscounted +@pytest.mark.parametrize( + 'solved_connection', + argvalues=embodied_tests, + indirect=True, + ids=[t['name'] for t in embodied_tests], +) +def test_embodied_emissions_costs_undiscounted(solved_connection): + """ + Test that the undiscounted embodied emission costs from each technology archetype are correct + """ + con, name, tech, emis_target = solved_connection + ec = ( + con.cursor() + .execute(f"SELECT SUM(emiss) FROM main.OutputCost WHERE tech LIKE '{tech}'") + .fetchone()[0] + ) + cost_target = 0.7 * emis_target # emission cost x embodied emissions + assert ec == pytest.approx( + cost_target + ), f'{name} undiscounted embodied emission costs were incorrect. Should be {cost_target}, got {ec}' + + +# Embodied emission costs discounted +@pytest.mark.parametrize( + 'solved_connection', + argvalues=embodied_tests, + indirect=True, + ids=[t['name'] for t in embodied_tests], +) +def test_embodied_emissions_costs_discounted(solved_connection): + """ + Test that discounted embodied emission costs from each technology archetype are correct + """ + con, name, tech, emis_target = solved_connection + ec = ( + con.cursor() + .execute(f"SELECT SUM(d_emiss) FROM main.OutputCost WHERE tech LIKE '{tech}'") + .fetchone()[0] + ) + cost_target = ( + 0.7 * emis_target / 1.05 * 1.05 + ) # emission cost x embodied emissions x P/A(5%, 1y, 1) [x F/P(5%, 1y) legacy bug?] + assert ec == pytest.approx( + cost_target + ), f'{name} discounted emission costs were incorrect. Should be {cost_target}, got {ec}' + + # Curtailment # List of tech archetypes to test and their correct curtailment value curtailment_tests = [ @@ -160,6 +234,7 @@ def test_emissions_costs_discounted(solved_connection): ) def test_curtailment(solved_connection): con, name, tech, curt_target = solved_connection + print(name, tech, curt_target) curt = ( con.cursor() .execute(f"SELECT SUM(curtailment) FROM main.OutputCurtailment WHERE tech LIKE '{tech}'") diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index cbc10643e..53296ebbd 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -19,8 +19,8 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,'Discount Rate for future costs'); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -34,7 +34,6 @@ CREATE TABLE OutputObjective objective_name TEXT, total_system_cost REAL ); -INSERT INTO OutputObjective VALUES('test run','TotalCost',3.600000000000003641); CREATE TABLE SectorLabel ( sector TEXT, @@ -114,6 +113,8 @@ INSERT INTO Commodity VALUES('flex_null','d',NULL); INSERT INTO Commodity VALUES('annual_flex_out','p',NULL); INSERT INTO Commodity VALUES('annual_flex_in','s',NULL); INSERT INTO Commodity VALUES('annual_flex_null','d',NULL); +INSERT INTO Commodity VALUES('embodied_in','s',NULL); +INSERT INTO Commodity VALUES('embodied_out','d',NULL); CREATE TABLE CommodityType ( label TEXT @@ -195,6 +196,7 @@ INSERT INTO Demand VALUES('TestRegion',2000,'ordinary_out',0.3,NULL,NULL); INSERT INTO Demand VALUES('TestRegion',2000,'curtailment_out',0.3,NULL,NULL); INSERT INTO Demand VALUES('TestRegion',2000,'flex_null',0.3,NULL,NULL); INSERT INTO Demand VALUES('TestRegion',2000,'annual_flex_null',0.3,NULL,NULL); +INSERT INTO Demand VALUES('TestRegion',2000,'embodied_out',0.6,NULL,NULL); CREATE TABLE DemandSpecificDistribution ( region TEXT, @@ -243,6 +245,7 @@ INSERT INTO Efficiency VALUES('TestRegion','curtailment_in','TechCurtailment',20 INSERT INTO Efficiency VALUES('TestRegion','flex_out','TechFlexNull',2000,'flex_null',1.0,NULL); INSERT INTO Efficiency VALUES('TestRegion','annual_flex_out','TechFlexNull',2000,'annual_flex_null',1.0,NULL); INSERT INTO Efficiency VALUES('TestRegion','annual_flex_in','TechAnnualFlex',2000,'annual_flex_out',1.0,NULL); +INSERT INTO Efficiency VALUES('TestRegion','embodied_in','TechEmbodied',2000,'embodied_out',1.0,NULL); CREATE TABLE EmissionActivity ( region TEXT, @@ -266,6 +269,21 @@ INSERT INTO EmissionActivity VALUES('TestRegion','emission','flex_in','TechFlex' INSERT INTO EmissionActivity VALUES('TestRegion','emission','ordinary_in','TechOrdinary',2000,'ordinary_out',1.0,NULL,NULL); INSERT INTO EmissionActivity VALUES('TestRegion','emission','curtailment_in','TechCurtailment',2000,'curtailment_out',1.0,NULL,NULL); INSERT INTO EmissionActivity VALUES('TestRegion','emission','annual_flex_in','TechAnnualFlex',2000,'annual_flex_out',1.0,NULL,NULL); +CREATE TABLE IF NOT EXISTS EmissionEmbodied +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +INSERT INTO EmissionEmbodied VALUES('TestRegion','emission','TechEmbodied',2000,0.5,NULL,NULL); CREATE TABLE ExistingCapacity ( region TEXT, @@ -925,17 +943,17 @@ CREATE TABLE Technology curtail INTEGER NOT NULL DEFAULT 0, retire INTEGER NOT NULL DEFAULT 0, flex INTEGER NOT NULL DEFAULT 0, - variable INTEGER NOT NULL DEFAULT 0, exchange INTEGER NOT NULL DEFAULT 0, description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('TechAnnual','p','energy',NULL,NULL,0,1,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('TechFlex','p','energy',NULL,NULL,0,0,0,0,0,1,0,0,NULL); -INSERT INTO Technology VALUES('TechOrdinary','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('TechCurtailment','p','energy',NULL,NULL,0,0,0,1,0,0,0,0,NULL); -INSERT INTO Technology VALUES('TechFlexNull','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('TechAnnualFlex','p','energy',NULL,NULL,0,1,0,0,0,1,0,0,NULL); +INSERT INTO Technology VALUES('TechAnnual','p','energy',NULL,NULL,0,1,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('TechFlex','p','energy',NULL,NULL,0,0,0,0,0,1,0,NULL); +INSERT INTO Technology VALUES('TechOrdinary','p','energy',NULL,NULL,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('TechCurtailment','p','energy',NULL,NULL,0,0,0,1,0,0,0,NULL); +INSERT INTO Technology VALUES('TechFlexNull','p','energy',NULL,NULL,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('TechAnnualFlex','p','energy',NULL,NULL,0,1,0,0,0,1,0,NULL); +INSERT INTO Technology VALUES('TechEmbodied','p','energy',NULL,NULL,0,0,0,0,0,0,0,NULL); CREATE TABLE OutputCost ( scenario TEXT, From a77cd5271271ca0466c7068d3be2854bed64e47d Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 7 Aug 2025 09:23:49 -0400 Subject: [PATCH 018/587] Split RampUp from RampDown indices and some tidy up --- temoa/temoa_model/hybrid_loader.py | 17 ++-- temoa/temoa_model/temoa_initialize.py | 99 +++++++++++++----------- temoa/temoa_model/temoa_model.py | 51 +++++++----- temoa/temoa_model/temoa_rules.py | 6 +- tests/testing_data/mediumville_sets.json | 79 +++++++++++++++++-- tests/testing_data/test_system_sets.json | 6 +- tests/testing_data/utopia_sets.json | 6 +- 7 files changed, 178 insertions(+), 86 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 2c2f37197..4c1f6a26b 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -457,11 +457,12 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): if self.table_exists('RampUp'): ramp_up_techs = cur.execute('SELECT tech FROM main.RampUp').fetchall() techs.update({t[0] for t in ramp_up_techs}) + load_element(M.tech_upramping, sorted((t,) for t in techs), self.viable_techs) # sort for deterministic behavior + techs = set() if self.table_exists('RampDown'): ramp_dn_techs = cur.execute('SELECT tech FROM main.RampDown').fetchall() techs.update({t[0] for t in ramp_dn_techs}) - load_element(M.tech_ramping, sorted((t,) for t in techs), self.viable_techs) # sort for - # deterministic behavior + load_element(M.tech_downramping, sorted((t,) for t in techs), self.viable_techs) # sort for deterministic behavior # tech_curtailment raw = cur.execute('SELECT tech FROM Technology WHERE curtail > 0').fetchall() @@ -977,14 +978,14 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): raw = cur.execute( 'SELECT region, period, tech, group_name, max_proportion FROM main.MinNewCapacityShare' ).fetchall() - load_element(M.MinCapacityShare, raw, self.viable_rt, (0, 2)) + load_element(M.MinNewCapacityShare, raw, self.viable_rt, (0, 2)) # MaxNewCapacityShare if self.table_exists('MaxNewCapacityShare'): raw = cur.execute( 'SELECT region, period, tech, group_name, max_proportion FROM main.MaxNewCapacityShare' ).fetchall() - load_element(M.MaxCapacityShare, raw, self.viable_rt, (0, 2)) + load_element(M.MaxNewCapacityShare, raw, self.viable_rt, (0, 2)) # MinActivityGroup if self.table_exists('MinActivityGroup'): @@ -1221,16 +1222,9 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): load_element(M.StorageDuration, raw, self.viable_rt, (0, 1)) # StorageInitFrac - # Not currently supported -- odd behavior and not region-indexed if self.table_exists('StorageInitFrac'): raw = cur.execute('SELECT region, period, season, tech, vintage, frac FROM main.StorageInitFrac').fetchall() load_element(M.StorageInitFrac, raw, self.viable_rtv, (0,3,4)) - # if len(raw) > 0: - # logger.warning( - # 'Initialization of storage values currently NOT supported.' - # ' Values in StorageInit table will be ignored, and storage init value' - # ' will be optimized.' - # ) # For T/S: dump the size of all data elements into the log if self.debugging: @@ -1289,6 +1283,7 @@ def load_param_idx_sets(self, data: dict) -> dict: M.MinNewCapacityShare.name: M.MinNewCapacityShareConstraint_rptg.name, M.RenewablePortfolioStandard.name: M.RenewablePortfolioStandardConstraint_rpg.name, M.ResourceBound.name: M.ResourceConstraint_rpr.name, + M.StorageInitFrac.name: M.StorageInitFracConstraint_rpstv.name } res = {} diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index b385aad66..7f52c2b51 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -677,8 +677,10 @@ def CreateSparseDicts(M: 'TemoaModel'): M.baseloadVintages[r, p, t] = set() if t in M.tech_storage and (r, p, t) not in M.storageVintages: M.storageVintages[r, p, t] = set() - if t in M.tech_ramping and (r, p, t) not in M.rampVintages: - M.rampVintages[r, p, t] = set() + if t in M.tech_upramping and (r, p, t) not in M.rampUpVintages: + M.rampUpVintages[r, p, t] = set() + if t in M.tech_downramping and (r, p, t) not in M.rampDownVintages: + M.rampDownVintages[r, p, t] = set() if (r, p, i, t) in M.TechInputSplit.sparse_iterkeys() and ( r, p, @@ -736,8 +738,10 @@ def CreateSparseDicts(M: 'TemoaModel'): M.baseloadVintages[r, p, t].add(v) if t in M.tech_storage: M.storageVintages[r, p, t].add(v) - if t in M.tech_ramping: - M.rampVintages[r, p, t].add(v) + if t in M.tech_upramping: + M.rampUpVintages[r, p, t].add(v) + if t in M.tech_upramping: + M.rampDownVintages[r, p, t].add(v) if (r, p, i, t) in M.TechInputSplit.sparse_iterkeys(): M.inputsplitVintages[r, p, i, t].add(v) if (r, p, i, t) in M.TechInputSplitAnnual.sparse_iterkeys(): @@ -787,6 +791,11 @@ def CreateSparseDicts(M: 'TemoaModel'): for i in sorted(l_unused_techs): SE.write(msg.format(i)) + # valid region-period-commodity sets for commodity balance constraints + commodityUpstream_rpi = set(M.commodityUStreamProcess.keys()) + commodityDownstream_rpo = set(M.commodityDStreamProcess.keys()) + M.commodityBalance_rpc = commodityUpstream_rpi.intersection(commodityDownstream_rpo) + M.activeFlow_rpsditvo = set( (r, p, s, d, i, t, v, o) for r, p, t in M.processVintages.keys() @@ -876,6 +885,20 @@ def CreateSparseDicts(M: 'TemoaModel'): for v in M.processVintages[r, p, t] if t not in M.tech_uncap ) + + M.storageInitIndices_rpstv = set( + (r, p, s, t, v) + for r, p, t in M.storageVintages.keys() + for v in M.storageVintages[r, p, t] + for s in M.time_season + ) + + M.storageLevelIndices_rpsdtv = set( + (r, p, s, d, t, v) + for (r, p, s, t, v) in M.storageInitIndices_rpstv + for d in M.time_of_day + ) + logger.debug('Completed creation of SparseDicts') @@ -1053,6 +1076,24 @@ def CurtailmentVariableIndices(M: 'TemoaModel'): return M.activeCurtailment_rpsditvo +def StorageInitVariableIndices(M: 'TemoaModel'): + return M.storageInitIndices_rpstv + + +def StorageLevelVariableIndices(M: 'TemoaModel'): + indices = set( + (r, p, s, d, t, v) + for r, p, s, d, t, v in M.storageLevelIndices_rpsdtv + if d != M.time_of_day.last() + ) + + return indices + + +def StorageConstraintIndices(M: 'TemoaModel'): + return M.storageLevelIndices_rpsdtv + + def CapacityConstraintIndices(M: 'TemoaModel'): capacity_indices = set( (r, p, s, d, t, v) @@ -1199,12 +1240,9 @@ def RegionalExchangeCapacityConstraintIndices(M: 'TemoaModel'): def CommodityBalanceConstraintIndices(M: 'TemoaModel'): # Generate indices only for those commodities that are produced by # technologies with varying output at the time slice level. - period_commodity_with_up = set(M.commodityUStreamProcess.keys()) - period_commodity_with_dn = set(M.commodityDStreamProcess.keys()) - balanceable_rpc = period_commodity_with_up.intersection(period_commodity_with_dn) indices = set( (r, p, s, d, c) - for r, p, c in balanceable_rpc + for r, p, c in M.commodityBalance_rpc # r in this line includes interregional transfer combinations (not needed). if r in M.regions # this line ensures only the regions are included. and c not in M.commodity_annual @@ -1218,12 +1256,9 @@ def CommodityBalanceConstraintIndices(M: 'TemoaModel'): def AnnualCommodityBalanceConstraintIndices(M: 'TemoaModel'): # Generate indices only for those commodities that are produced by # technologies with constant annual output. - period_commodity_with_up = set(M.commodityUStreamProcess.keys()) - period_commodity_with_dn = set(M.commodityDStreamProcess.keys()) - balanceable_rpc = period_commodity_with_up.intersection(period_commodity_with_dn) indices = set( (r, p, c) - for r, p, c in balanceable_rpc + for r, p, c in M.commodityBalance_rpc # r in this line includes interregional transfer combinations (not needed). if r in M.regions # this line ensures only the regions are included. and c in M.commodity_annual @@ -1232,51 +1267,25 @@ def AnnualCommodityBalanceConstraintIndices(M: 'TemoaModel'): return indices -def StorageInitIndices(M: 'TemoaModel'): - indices = set( - (r, p, s, t, v) - for r, p, t in M.storageVintages.keys() - for v in M.storageVintages[r, p, t] - for s in M.time_season - ) - - return indices - - -def StorageConstraintIndices(M: 'TemoaModel'): +def RampUpConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, s, d, t, v) - for (r, p, s, t, v) in M.StorageInit_rpstv - for d in M.time_of_day - ) - - return indices - - -def StorageStateIndices(M: 'TemoaModel'): - indices = set( - (r, p, s, d, t, v) - for (r, p, s, t, v) in M.StorageInit_rpstv + for r, p, t in M.rampUpVintages.keys() + for s in M.time_season for d in M.time_of_day - if d != M.time_of_day.last() # replaced by storageinit + for v in M.rampUpVintages[r, p, t] ) return indices -def StorageInitFracIndices(M: 'TemoaModel'): - indices = set((r, p, s, t, v) for r, p, s, t, v in M.StorageInitFrac.sparse_iterkeys()) - - return indices - - -def RampConstraintIndices(M: 'TemoaModel'): +def RampDownConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, s, d, t, v) - for r, p, t in M.rampVintages.keys() + for r, p, t in M.rampDownVintages.keys() for s in M.time_season for d in M.time_of_day - for v in M.rampVintages[r, p, t] + for v in M.rampDownVintages[r, p, t] ) return indices diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 277f98513..6d40e9070 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -85,6 +85,8 @@ def __init__(M, *args, **kwargs): M.activeFlowInStorage_rpsditvo = None M.activeCurtailment_rpsditvo = None M.activeActivity_rptv = None + M.storageInitIndices_rpstv = None + M.storageLevelIndices_rpsdtv = None """currently available (within lifespan) (r, p, t, v) tuples (from M.processVintages)""" M.activeRegionsForTech = None @@ -93,6 +95,7 @@ def __init__(M, *args, **kwargs): M.activeCapacity_rtv = None M.activeCapacityAvailable_rpt = None M.activeCapacityAvailable_rptv = None + M.commodityBalance_rpc = None # Set of valid region-period-commodity indices to balance M.commodityDStreamProcess = dict() # The downstream process of a commodity during a period M.commodityUStreamProcess = dict() # The upstream process of a commodity during a period M.ProcessInputsByOutput = dict() @@ -105,7 +108,8 @@ def __init__(M, *args, **kwargs): M.baseloadVintages = dict() M.curtailmentVintages = dict() M.storageVintages = dict() - M.rampVintages = dict() + M.rampUpVintages = dict() + M.rampDownVintages = dict() M.inputsplitVintages = dict() M.inputsplitannualVintages = dict() M.outputsplitVintages = dict() @@ -153,7 +157,8 @@ def __init__(M, *args, **kwargs): # annual storage not supported in Storage constraint or TableWriter, so exclude from domain M.tech_storage = Set(within=M.tech_all - M.tech_annual) M.tech_reserve = Set(within=M.tech_all) - M.tech_ramping = Set(within=M.tech_all) + M.tech_upramping = Set(within=M.tech_all) + M.tech_downramping = Set(within=M.tech_all) M.tech_curtailment = Set(within=M.tech_all) M.tech_flex = Set(within=M.tech_all) # ensure there is no overlap flex <=> curtailable technologies @@ -383,6 +388,7 @@ def __init__(M, *args, **kwargs): within=M.RegionalGlobalIndices * M.time_optimize * M.tech_all * M.commodity_carrier ) M.MaxAnnualCapacityFactor = Param(M.MaxAnnualCapacityFactorConstraint_rpto) + M.GrowthRateMax = Param(M.RegionalIndices, M.tech_all) M.GrowthRateSeed = Param(M.RegionalIndices, M.tech_all) @@ -401,7 +407,6 @@ def __init__(M, *args, **kwargs): M.MaxActivityGroup_rpg = Set( within=M.RegionalGlobalIndices * M.time_optimize * M.tech_group_names ) - M.MaxActivityGroup = Param(M.MaxActivityGroup_rpg) M.MinCapacityGroupConstraint_rpg = Set( @@ -442,20 +447,27 @@ def __init__(M, *args, **kwargs): M.MaxNewCapacityShareConstraint_rptg = Set(within=M.GroupShareIndices) M.MaxNewCapacityShare = Param(M.GroupShareIndices) + + # Initial storage charge level, expressed as fraction of full energy capacity. + # If the parameter is not defined, the model optimizes the initial storage charge level. + M.StorageInit_rpstv = Set(dimen=5, initialize=StorageInitVariableIndices) + M.StorageInitFracConstraint_rpstv = Set(within=M.StorageInit_rpstv) + M.StorageInitFrac = Param(M.StorageInit_rpstv) + + # Storage duration is expressed in hours + M.StorageDuration = Param(M.regions, M.tech_storage, default=4) + M.LinkedTechs = Param(M.RegionalIndices, M.tech_all, M.commodity_emissions, within=Any) # Define parameters associated with electric sector operation - M.RampUp = Param(M.regions, M.tech_ramping) - M.RampDown = Param(M.regions, M.tech_ramping) + M.RampUp = Param(M.regions, M.tech_upramping) + M.RampDown = Param(M.regions, M.tech_downramping) + M.CapacityCredit = Param( M.RegionalIndices, M.time_optimize, M.tech_all, M.vintage_all, default=0 ) M.PlanningReserveMargin = Param(M.regions, default=0.2) - # Storage duration is expressed in hours - M.StorageDuration = Param(M.regions, M.tech_storage, default=4) - # Initial storage charge level, expressed as fraction of full energy capacity. - # If the parameter is not defined, the model optimizes the initial storage charge level. - M.StorageInitFrac = Param(M.regions, M.time_optimize, M.time_season, M.tech_storage, M.vintage_all) + M.EmissionEmbodied = Param(M.regions, M.commodity_emissions, M.tech_with_capacity, M.vintage_optimize) M.MyopicBaseyear = Param(default=0) @@ -496,9 +508,9 @@ def __init__(M, *args, **kwargs): M.FlowInStorage_rpsditvo = Set(dimen=8, initialize=FlowInStorageVariableIndices) M.V_FlowIn = Var(M.FlowInStorage_rpsditvo, domain=NonNegativeReals) - M.StorageInit_rpstv = Set(dimen=5, initialize=StorageInitIndices) M.V_StorageInit = Var(M.StorageInit_rpstv, domain=NonNegativeReals) - M.StorageLevel_rpsdtv = Set(dimen=6, initialize=StorageStateIndices) + + M.StorageLevel_rpsdtv = Set(dimen=6, initialize=StorageLevelVariableIndices) M.V_StorageLevel = Var(M.StorageLevel_rpsdtv, domain=NonNegativeReals) # Derived decision variables @@ -605,8 +617,11 @@ def __init__(M, *args, **kwargs): ) M.progress_marker_6 = BuildAction(['Starting Storage Constraints'], rule=progress_check) - # This set works for all the storage-related constraints - M.StorageConstraints_rpsdtv = Set(dimen=6, initialize=StorageConstraintIndices) + + # This set works for most storage-related constraints + M.StorageConstraints_rpsdtv = Set( + dimen=6, initialize=StorageConstraintIndices + ) M.StorageEnergyConstraint = Constraint( M.StorageConstraints_rpsdtv, rule=StorageEnergy_Constraint @@ -632,14 +647,14 @@ def __init__(M, *args, **kwargs): M.StorageConstraints_rpsdtv, rule=StorageThroughput_Constraint ) - M.StorageInitFracConstraint_rpstv = Set(dimen=5, initialize=StorageInitFracIndices) M.StorageInitFracConstraint = Constraint( M.StorageInitFracConstraint_rpstv, rule=StorageInitFrac_Constraint ) - M.RampConstraint_rpsdtv = Set(dimen=6, initialize=RampConstraintIndices) - M.RampUpConstraint = Constraint(M.RampConstraint_rpsdtv, rule=RampUpDay_Constraint) - M.RampDownConstraint = Constraint(M.RampConstraint_rpsdtv, rule=RampDownDay_Constraint) + M.RampUpConstraint_rpsdtv = Set(dimen=6, initialize=RampUpConstraintIndices) + M.RampUpConstraint = Constraint(M.RampUpConstraint_rpsdtv, rule=RampUp_Constraint) + M.RampDownConstraint_rpsdtv = Set(dimen=6, initialize=RampDownConstraintIndices) + M.RampDownConstraint = Constraint(M.RampDownConstraint_rpsdtv, rule=RampDown_Constraint) M.ReserveMargin_rpsd = Set(dimen=4, initialize=ReserveMarginIndices) M.ReserveMarginConstraint = Constraint(M.ReserveMargin_rpsd, rule=ReserveMargin_Constraint) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 81c20f670..2711bfe99 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1232,7 +1232,7 @@ def link_season_storage_energy(M: 'TemoaModel', r, p, s, d, t, v, stored_energy) return expr -def loop_season_storage_energy(M: 'TemoaModel', r, p, s, d, t, v) -> Expression: +def loop_season_storage_energy(M: 'TemoaModel', r, p, s, d, t, v, stored_energy) -> Expression: r""" This variant of the storage energy constraint, used by default, loops the state of storage within each season rather than carrying it between seasons. Necessary @@ -1489,7 +1489,7 @@ def StorageInitFrac_Constraint(M: 'TemoaModel', r, p, s, t, v): return expr -def RampUpDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): +def RampUp_Constraint(M: 'TemoaModel', r, p, s, d, t, v): # M.time_of_day is a sorted set, and M.time_of_day.first() returns the first # element in the set, similarly, M.time_of_day.last() returns the last element. # M.time_of_day.prev(d) function will return the previous element before s, and @@ -1581,7 +1581,7 @@ def RampUpDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): return expr -def RampDownDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): +def RampDown_Constraint(M: 'TemoaModel', r, p, s, d, t, v): r""" Similar to the :code`RampUpDay` constraint, we use the :code:`RampDownDay` diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index d7e280b5f..7cc7e8057 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -79,7 +79,10 @@ "tech_reserve": [ "EH" ], - "tech_ramping": [ + "tech_upramping": [ + "EH" + ], + "tech_downramping": [ "EH" ], "tech_curtailment": [ @@ -3939,11 +3942,27 @@ ] ], "StorageInitFracConstraint_rpstv": [], - "RampConstraint_rpsdtv": [ + "RampUpConstraint_rpsdtv": [ [ - "A", + "B", 2025, "s2", + "d1", + "EH", + 2025 + ], + [ + "B", + 2025, + "s1", + "d1", + "EH", + 2025 + ], + [ + "A", + 2025, + "s1", "d2", "EH", 2025 @@ -3956,10 +3975,26 @@ "EH", 2025 ], + [ + "A", + 2025, + "s2", + "d2", + "EH", + 2025 + ], [ "A", 2025, "s1", + "d1", + "EH", + 2025 + ], + [ + "B", + 2025, + "s1", "d2", "EH", 2025 @@ -3971,9 +4006,19 @@ "d1", "EH", 2025 + ] + ], + "RampDownConstraint_rpsdtv": [ + [ + "B", + 2025, + "s2", + "d1", + "EH", + 2025 ], [ - "A", + "B", 2025, "s1", "d1", @@ -3981,7 +4026,7 @@ 2025 ], [ - "B", + "A", 2025, "s1", "d2", @@ -3992,6 +4037,22 @@ "B", 2025, "s2", + "d2", + "EH", + 2025 + ], + [ + "A", + 2025, + "s2", + "d2", + "EH", + 2025 + ], + [ + "A", + 2025, + "s1", "d1", "EH", 2025 @@ -4000,6 +4061,14 @@ "B", 2025, "s1", + "d2", + "EH", + 2025 + ], + [ + "A", + 2025, + "s2", "d1", "EH", 2025 diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 86d419f08..2bdc0bd7d 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -98,7 +98,8 @@ "E_BATT" ], "tech_reserve": [], - "tech_ramping": [], + "tech_upramping": [], + "tech_downramping": [], "tech_curtailment": [ "S_OILREF" ], @@ -42933,7 +42934,8 @@ 2020 ] ], - "RampConstraint_rpsdtv": [], + "RampUpConstraint_rpsdtv": [], + "RampDownConstraint_rpsdtv": [], "ReserveMargin_rpsd": [ [ "R2", diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 8b34cc397..675e1809b 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -103,7 +103,8 @@ "E51" ], "tech_reserve": [], - "tech_ramping": [], + "tech_upramping": [], + "tech_downramping": [], "tech_curtailment": [], "tech_flex": [], "tech_exchange": [], @@ -24505,7 +24506,8 @@ ] ], "StorageInitFracConstraint_rpstv": [], - "RampConstraint_rpsdtv": [], + "RampUpConstraint_rpsdtv": [], + "RampDownConstraint_rpsdtv": [], "ReserveMargin_rpsd": [ [ "utopia", From 8937a1c6cf066d72c7199dd5f78be485362f8a58 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 7 Aug 2025 09:26:08 -0400 Subject: [PATCH 019/587] Rework StorageInitFrac and ramp rates - Update StorageInitFrac to StorageFraction in any time slice - Rework ramp rates to use same new time sequencing framework as storage --- temoa/temoa_model/hybrid_loader.py | 10 +- temoa/temoa_model/table_data_puller.py | 21 + temoa/temoa_model/temoa_initialize.py | 21 +- temoa/temoa_model/temoa_model.py | 28 +- temoa/temoa_model/temoa_rules.py | 274 +++------ tests/test_storage.py | 164 ++--- tests/testing_data/mediumville.sql | 14 +- tests/testing_data/mediumville_sets.json | 54 +- tests/testing_data/storageville.sql | 5 +- tests/testing_data/test_system.sql | 7 +- tests/testing_data/test_system_sets.json | 726 ++++++++++++----------- tests/testing_data/utopia_sets.json | 409 +++++++------ 12 files changed, 796 insertions(+), 937 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 4c1f6a26b..d8b00d34a 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -1221,10 +1221,10 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): raw = cur.execute('SELECT region, tech, duration FROM main.StorageDuration').fetchall() load_element(M.StorageDuration, raw, self.viable_rt, (0, 1)) - # StorageInitFrac - if self.table_exists('StorageInitFrac'): - raw = cur.execute('SELECT region, period, season, tech, vintage, frac FROM main.StorageInitFrac').fetchall() - load_element(M.StorageInitFrac, raw, self.viable_rtv, (0,3,4)) + # StorageFraction + if self.table_exists('StorageFraction'): + raw = cur.execute('SELECT region, period, season, time_of_day, tech, vintage, frac FROM main.StorageFraction').fetchall() + load_element(M.StorageFraction, raw, self.viable_rtv, (0,4,5)) # For T/S: dump the size of all data elements into the log if self.debugging: @@ -1283,7 +1283,7 @@ def load_param_idx_sets(self, data: dict) -> dict: M.MinNewCapacityShare.name: M.MinNewCapacityShareConstraint_rptg.name, M.RenewablePortfolioStandard.name: M.RenewablePortfolioStandardConstraint_rpg.name, M.ResourceBound.name: M.ResourceConstraint_rpr.name, - M.StorageInitFrac.name: M.StorageInitFracConstraint_rpstv.name + M.StorageFraction.name: M.StorageFractionConstraint_rpsdtv.name } res = {} diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index f6b3cce0a..c58d26069 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -70,6 +70,9 @@ class FlowType(Enum): FI = namedtuple('FI', ['r', 'p', 's', 'd', 'i', 't', 'v', 'o']) """Flow Index""" +SSI = namedtuple('SSI', ['r', 'p', 's', 'd', 't', 'v']) +"""Storage State Index""" + CapData = namedtuple('CapData', ['built', 'net', 'retired']) """Small container to hold named dictionaries of capacity data for processing""" @@ -201,6 +204,24 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl return res +def poll_storage_state_results(M: TemoaModel, epsilon=1e-5) -> dict[SSI, float]: + """ + Poll a solved model for flow results. + :param M: A solved Model + :param epsilon: epsilon (default 1e-5) + :return: nested dictionary of FlowIndex, FlowType : value + """ + res: dict[SSI, float] = defaultdict(float) + + # Storage level, the state variable for all but last time slice of each season + for ssi in M.StorageLevel_rpsdtv: + state = value(M.V_StorageLevel[ssi]) + ssi = SSI(*ssi) + if abs(state) < epsilon: + continue + res[ssi] = state + + def poll_objective(M: TemoaModel) -> list[tuple[str, float]]: """gather objective name, value tuples for all active objectives""" objs: list[Objective] = list(M.component_data_objects(Objective)) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 7f52c2b51..899830898 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -886,16 +886,11 @@ def CreateSparseDicts(M: 'TemoaModel'): if t not in M.tech_uncap ) - M.storageInitIndices_rpstv = set( - (r, p, s, t, v) + M.storageLevelIndices_rpsdtv = set( + (r, p, s, d, t, v) for r, p, t in M.storageVintages.keys() for v in M.storageVintages[r, p, t] for s in M.time_season - ) - - M.storageLevelIndices_rpsdtv = set( - (r, p, s, d, t, v) - for (r, p, s, t, v) in M.storageInitIndices_rpstv for d in M.time_of_day ) @@ -1076,18 +1071,8 @@ def CurtailmentVariableIndices(M: 'TemoaModel'): return M.activeCurtailment_rpsditvo -def StorageInitVariableIndices(M: 'TemoaModel'): - return M.storageInitIndices_rpstv - - def StorageLevelVariableIndices(M: 'TemoaModel'): - indices = set( - (r, p, s, d, t, v) - for r, p, s, d, t, v in M.storageLevelIndices_rpsdtv - if d != M.time_of_day.last() - ) - - return indices + return M.storageLevelIndices_rpsdtv def StorageConstraintIndices(M: 'TemoaModel'): diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 6d40e9070..d44eca5da 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -85,7 +85,6 @@ def __init__(M, *args, **kwargs): M.activeFlowInStorage_rpsditvo = None M.activeCurtailment_rpsditvo = None M.activeActivity_rptv = None - M.storageInitIndices_rpstv = None M.storageLevelIndices_rpsdtv = None """currently available (within lifespan) (r, p, t, v) tuples (from M.processVintages)""" @@ -448,11 +447,10 @@ def __init__(M, *args, **kwargs): M.MaxNewCapacityShareConstraint_rptg = Set(within=M.GroupShareIndices) M.MaxNewCapacityShare = Param(M.GroupShareIndices) - # Initial storage charge level, expressed as fraction of full energy capacity. - # If the parameter is not defined, the model optimizes the initial storage charge level. - M.StorageInit_rpstv = Set(dimen=5, initialize=StorageInitVariableIndices) - M.StorageInitFracConstraint_rpstv = Set(within=M.StorageInit_rpstv) - M.StorageInitFrac = Param(M.StorageInit_rpstv) + # This set works for all storage-related constraints + M.StorageConstraints_rpsdtv = Set(dimen=6, initialize=StorageConstraintIndices) + M.StorageFractionConstraint_rpsdtv = Set(within=M.StorageConstraints_rpsdtv) + M.StorageFraction = Param(M.StorageConstraints_rpsdtv) # Storage duration is expressed in hours M.StorageDuration = Param(M.regions, M.tech_storage, default=4) @@ -508,8 +506,7 @@ def __init__(M, *args, **kwargs): M.FlowInStorage_rpsditvo = Set(dimen=8, initialize=FlowInStorageVariableIndices) M.V_FlowIn = Var(M.FlowInStorage_rpsditvo, domain=NonNegativeReals) - M.V_StorageInit = Var(M.StorageInit_rpstv, domain=NonNegativeReals) - + # Storage state at the BEGINNING of each time slice M.StorageLevel_rpsdtv = Set(dimen=6, initialize=StorageLevelVariableIndices) M.V_StorageLevel = Var(M.StorageLevel_rpsdtv, domain=NonNegativeReals) @@ -618,19 +615,14 @@ def __init__(M, *args, **kwargs): M.progress_marker_6 = BuildAction(['Starting Storage Constraints'], rule=progress_check) - # This set works for most storage-related constraints - M.StorageConstraints_rpsdtv = Set( - dimen=6, initialize=StorageConstraintIndices - ) + # We make use of this following set in some of the storage constraints. + # Pre-computing it is considerably faster. + M.SegFracPerSeason = Param(M.time_season, initialize=SegFracPerSeason_rule) M.StorageEnergyConstraint = Constraint( M.StorageConstraints_rpsdtv, rule=StorageEnergy_Constraint ) - # We make use of this following set in some of the storage constraints. - # Pre-computing it is considerably faster. - M.SegFracPerSeason = Param(M.time_season, initialize=SegFracPerSeason_rule) - M.StorageEnergyUpperBoundConstraint = Constraint( M.StorageConstraints_rpsdtv, rule=StorageEnergyUpperBound_Constraint ) @@ -647,8 +639,8 @@ def __init__(M, *args, **kwargs): M.StorageConstraints_rpsdtv, rule=StorageThroughput_Constraint ) - M.StorageInitFracConstraint = Constraint( - M.StorageInitFracConstraint_rpstv, rule=StorageInitFrac_Constraint + M.StorageFractionConstraint = Constraint( + M.StorageFractionConstraint_rpsdtv, rule=StorageFraction_Constraint ) M.RampUpConstraint_rpsdtv = Set(dimen=6, initialize=RampUpConstraintIndices) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 2711bfe99..30dc5584c 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1140,146 +1140,58 @@ def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): stored_energy = charge - discharge - if M.link_seasons: return link_season_storage_energy(M, r, p, s, d, t, v, stored_energy) - else: return loop_season_storage_energy(M, r, p, s, d, t, v, stored_energy) + # What time slice follows this one + if M.link_seasons: s_next, d_next = link_season_next_timeslice(M, s, d) + else: s_next, d_next = loop_season_next_timeslice(M, s, d) + expr = M.V_StorageLevel[r, p, s, d, t, v] + stored_energy == M.V_StorageLevel[r, p, s_next, d_next, t, v] -def link_season_storage_energy(M: 'TemoaModel', r, p, s, d, t, v, stored_energy) -> Expression: - r""" - - This constraint tracks the storage charge level (:math:`\textbf{SL}_{r, p, s, d, t, v}`) - assuming ordered time slices. The initial storage charge level is optimized - for the first time slice in each period, and then the charge level is updated each time - slice based on the amount of energy stored or discharged. At the end of the last time - slice associated with each period, the charge level must equal the starting charge level. - In the formulation below, note that :math:`\textbf{stored\_energy}` is an internal model - decision variable. - - First, the amount of stored energy in a given time slice is calculated as the - difference between the amount of energy stored (first term) and the amount of energy - dispatched (second term). Note that the storage device's roundtrip efficiency is applied - on the input side: - - .. math:: - :label: StorageEnergy - - \textbf{stored\_energy} = - \sum_{I, O} \textbf{FIS}_{r, p, s, d, i, t, v, o} \cdot - EFF_{r,i,t,v,o} - - - \sum_{I, O} \textbf{FO}_{r, p, s, d, i, t, v, o} - - With :math:`\textbf{stored\_energy}` calculated, the storage - charge level (:math:`\textbf{SL}_{r,p,s,d,t,v}`) is updated, but the update procedure varies - based on the time slice within each time period. For the first season and time-of-day within - a given period: - - .. math:: - \textbf{SL}_{r, p, s, d, t, v} = \textbf{SI}_{r,t,v} + \textbf{stored\_energy} - - For the first time-of-day slice in any other season except the first: - - .. math:: - \textbf{SL}_{r, p, s, d, t, v} = - \textbf{SL}_{r, p, s_{prev}, d_{last}, t, v} + \textbf{stored\_energy} - - For the last season and time-of-day in the year, the ending storage charge level - should be equal to the starting charge level: - - .. math:: - \textbf{SL}_{r, p, s, d, t, v} + \textbf{stored\_energy} = \textbf{SI}_{r,t,v} - - For all other time slices not explicitly outlined above: - - .. math:: - \textbf{SL}_{r, p, s, d, t, v} = \textbf{SL}_{r, p, s, d_{prev}, t, v} + \textbf{stored\_energy} - - All equations below are sparsely indexed such that: - - .. math:: - \forall \{r, p, s, d, t, v\} \in \Theta_{\text{StorageEnergy}} - - This constraint is used if link_seasons is set to 1 in the MetaData table - """ + return expr - # First time slice of any season - # Begin storage state at StorageInit which MAY be constrained by StorageInitFrac - if d == M.time_of_day.first(): - expr = M.V_StorageLevel[r, p, s, d, t, v] == M.V_StorageInit[r, p, s, t, v] + stored_energy +def link_season_next_timeslice(M: 'TemoaModel', s, d) -> tuple[str, str]: + # Final time slice of final season (end of period) - # Loop storage state to initial state of first season - # Loop storage state from end to start of same period - elif s == M.time_season.last() and d == M.time_of_day.last(): - d_prev = M.time_of_day.prev(d) - s_first = M.time_season.first() - expr = M.V_StorageInit[r, p, s_first, t, v] == M.V_StorageLevel[r, p, s, d_prev, t, v] + stored_energy + # Loop storage state back to initial state of first season + # Loop the period + if s == M.time_season.last() and d == M.time_of_day.last(): + s_next = M.time_season.first() + d_next = M.time_of_day.first() # Last time slice of any season that is NOT the last season # Carry storage state to initial state of next season # Carry storage state between seasons elif d == M.time_of_day.last(): - d_prev = M.time_of_day.prev(d) s_next = M.time_season.next(s) - expr = M.V_StorageInit[r, p, s_next, t, v] == M.V_StorageLevel[r, p, s, d_prev, t, v] + stored_energy + d_next = M.time_of_day.first() - # Not the start or end of any season. Somewhere in the middle of a season - # Carry storage state between time slices within the same season + # Any other time slice + # Carry storage state to next time slice in the same season + # Continuing through this season else: - d_prev = M.time_of_day.prev(d) - expr = M.V_StorageLevel[r, p, s, d, t, v] == M.V_StorageLevel[r, p, s, d_prev, t, v] + stored_energy + s_next = s + d_next = M.time_of_day.next(d) - return expr - - -def loop_season_storage_energy(M: 'TemoaModel', r, p, s, d, t, v, stored_energy) -> Expression: - r""" - This variant of the storage energy constraint, used by default, loops the state - of storage within each season rather than carrying it between seasons. Necessary - when the order of seasons in the database is not representative of their actual - chronological sequence. - - Can set link_seasons to value 1 in MetaData table to allow storage state - to carry between seasons, if seasons are real-world chronological. - """ - - # This is the sum of all input=i sent TO storage tech t of vintage v with - # output=o in p,s,d - charge = sum( - M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] * M.Efficiency[r, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] - ) + return s_next, d_next - # This is the sum of all output=o withdrawn FROM storage tech t of vintage v - # with input=i in p,s,d - discharge = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_o in M.processOutputs[r, p, t, v] - for S_i in M.ProcessInputsByOutput[r, p, t, v, S_o] - ) - stored_energy = charge - discharge +def loop_season_next_timeslice(M: 'TemoaModel', s, d) -> Expression: - # First time slice of any season - # Begin storage state at StorageInit which MAY be constrained by StorageInitFrac - if d == M.time_of_day.first(): - expr = M.V_StorageLevel[r, p, s, d, t, v] == M.V_StorageInit[r, p, s, t, v] + stored_energy + s_next = s - # Last time slice of any season + # Final time slice of any season # Loop storage state back to initial state of same season - # Loop storage state within each season - elif d == M.time_of_day.last(): - d_prev = M.time_of_day.prev(d) - expr = M.V_StorageInit[r, p, s, t, v] == M.V_StorageLevel[r, p, s, d_prev, t, v] + stored_energy + # Loop each season + if d == M.time_of_day.last(): + d_next = M.time_of_day.first() - # Not the start or end of any season. Somewhere in the middle of a season - # Carry storage state between time slices within the same season + # Any other time slice + # Carry storage state to next time slice in the same season + # Continuing through this season else: - d_prev = M.time_of_day.prev(d) - expr = M.V_StorageLevel[r, p, s, d, t, v] == M.V_StorageLevel[r, p, s, d_prev, t, v] + stored_energy + d_next = M.time_of_day.next(d) - return expr + return s_next, d_next def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): @@ -1319,11 +1231,8 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): * 365 * value(M.ProcessLifeFrac[r, p, t, v]) ) - - if d == M.time_of_day.last(): storage_level = M.V_StorageInit[r, p, s, t, v] - else: storage_level = M.V_StorageLevel[r, p, s, d, t, v] - expr = storage_level <= energy_capacity + expr = M.V_StorageLevel[r, p, s, d, t, v] <= energy_capacity return expr @@ -1445,46 +1354,43 @@ def StorageThroughput_Constraint(M: 'TemoaModel', r, p, s, d, t, v): return expr -def StorageInitFrac_Constraint(M: 'TemoaModel', r, p, s, t, v): +def StorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v): r""" - This constraint is used if the users wishes to force a specific initial storage charge level - for certain storage technologies and vintages. In this case, the value of the decision variable - :math:`\textbf{SI}_{r,t,v}` is set by this constraint rather than being optimized. - User-specified initial storage charge levels that are sufficiently different from the optimal - :math:`\textbf{SI}_{r,t,v}` could impact the cost-effectiveness of storage. For example, if the - optimal initial charge level happens to be 50% of the full energy capacity, forced initial - charge levels (specified by parameter :math:`SIF_{r,t,v}`) equal to 10% or 90% of the full energy - capacity could lead to more expensive solutions. + This constraint is used if the users wishes to force a specific storage charge level + for certain storage technologies and vintages at a certain time slice. + In this case, the value of the decision variable :math:`\textbf{SI}_{r,t,v}` is set by + this constraint rather than being optimized. User-specified storage charge levels that are + sufficiently different from the optimal :math:`\textbf{SI}_{r,t,v}` could impact the + cost-effectiveness of storage. For example, if the optimal charge level happens to be + 50% of the full energy capacity, forced charge levels (specified by parameter + :math:`SIF_{r,t,v}`) equal to 10% or 90% of the full energycapacity could lead to + more expensive solutions. .. math:: - :label: StorageInit + :label: StorageFraction - \textbf{SI}_{r,t, v} \le - \ SIF_{r,t,v} + \textbf{SF}_{r,p,s,d,t,v} \le + \ SF_{r,p,s,d,t,v} \cdot - \textbf{CAP}_{r,t,v} \cdot C2A_{r,t} \cdot \frac {SD_{r,t}}{8760 hrs/yr} - \cdot \sum_{d} SEG_{s_{first},d} \cdot 365 days/yr + \textbf{CAP}_{r,p,t,v} \cdot C2A_{r,t} \cdot \frac {SD_{r,t}}{8760 hrs/yr} + \cdot \sum_{d} SEG_{s,d} \cdot 365 days/yr \cdot MPL_{r,p,t,v} \\ - \forall \{r, t, v\} \in \Theta_{\text{StorageInit}} + \forall \{r, p, s, d, t, v\} \in \Theta_{\text{StorageFraction}} """ - # dev note: This constraint is not currently accessible and needs close review. - # the hybrid loader currently screens out inputs for this to keep - # it idle. - #raise NotImplementedError('This constraint needs overhaul...') energy_capacity = ( M.V_Capacity[r, p, t, v] * M.CapacityToActivity[r, t] * (M.StorageDuration[r, t] / 8760) - * sum(M.SegFrac[s, S_d] for S_d in M.time_of_day) + * M.SegFracPerSeason[s] * 365 * value(M.ProcessLifeFrac[r, p, t, v]) ) - expr = M.V_StorageInit[r, p, s, t, v] == energy_capacity * M.StorageInitFrac[r, p, s, t, v] + expr = M.V_StorageLevel[r, p, s, d, t, v] == energy_capacity * M.StorageFraction[r, p, s, d, t, v] return expr @@ -1537,36 +1443,9 @@ def RampUp_Constraint(M: 'TemoaModel', r, p, s, d, t, v): \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampUpDay}} """ - if M.link_seasons: - # Linking seasons together chronologically - if s == M.time_season.first() and d == M.time_of_day.first(): - # beginning of period, loop to end of same period - s_prev = M.time_season.last() - d_prev = M.time_of_day.last() - elif d == M.time_of_day.first(): - # beginning of season (but not period), link to end of last season - s_prev = M.time_season.prev(s) - d_prev = M.time_of_day.last() - else: - # middle of season, link to previous time slice in same season - s_prev = s - d_prev = M.time_of_day.prev(d) - else: - # Looping each season within itself (default behaviour) - if d == M.time_of_day.first(): - # beginning of season, loop to end of same season - s_prev = s - d_prev = M.time_of_day.last() - else: - # middle of season, link to previous time slice in same season - s_prev = s - d_prev = M.time_of_day.prev(d) - - activity_sd_prev = sum( - M.V_FlowOut[r, p, s_prev, d_prev, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] - ) / value(M.SegFrac[s_prev, d_prev]) + # What time slice follows this one + if M.link_seasons: s_next, d_next = link_season_next_timeslice(M, s, d) + else: s_next, d_next = loop_season_next_timeslice(M, s, d) activity_sd = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] @@ -1574,7 +1453,13 @@ def RampUp_Constraint(M: 'TemoaModel', r, p, s, d, t, v): for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] ) / value(M.SegFrac[s, d]) - activity_increase = activity_sd - activity_sd_prev # opposite sign from rampdown + activity_sd_next = sum( + M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + ) / value(M.SegFrac[s_next, d_next]) + + activity_increase = activity_sd_next - activity_sd # opposite sign from rampdown rampable_activity = M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.RampUp[r, t]) expr = activity_increase <= rampable_activity @@ -1607,36 +1492,9 @@ def RampDown_Constraint(M: 'TemoaModel', r, p, s, d, t, v): \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampDownDay}} """ - if M.link_seasons: - # Linking seasons together chronologically - if s == M.time_season.first() and d == M.time_of_day.first(): - # beginning of period, loop to end of same period - s_prev = M.time_season.last() - d_prev = M.time_of_day.last() - elif d == M.time_of_day.first(): - # beginning of season (but not period), link to end of last season - s_prev = M.time_season.prev(s) - d_prev = M.time_of_day.last() - else: - # middle of season, link to previous time slice in same season - s_prev = s - d_prev = M.time_of_day.prev(d) - else: - # Looping each season within itself (default behaviour) - if d == M.time_of_day.first(): - # beginning of season, loop to end of same season - s_prev = s - d_prev = M.time_of_day.last() - else: - # middle of season, link to previous time slice in same season - s_prev = s - d_prev = M.time_of_day.prev(d) - - activity_sd_prev = sum( - M.V_FlowOut[r, p, s_prev, d_prev, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] - ) / value(M.SegFrac[s_prev, d_prev]) + # What time slice follows this one + if M.link_seasons: s_next, d_next = link_season_next_timeslice(M, s, d) + else: s_next, d_next = loop_season_next_timeslice(M, s, d) activity_sd = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] @@ -1644,7 +1502,13 @@ def RampDown_Constraint(M: 'TemoaModel', r, p, s, d, t, v): for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] ) / value(M.SegFrac[s, d]) - activity_decrease = activity_sd_prev - activity_sd # opposite sign from rampup + activity_sd_next = sum( + M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + ) / value(M.SegFrac[s_next, d_next]) + + activity_decrease = activity_sd - activity_sd_next # opposite sign from rampup rampable_activity = M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.RampDown[r, t]) expr = activity_decrease <= rampable_activity diff --git a/tests/test_storage.py b/tests/test_storage.py index b38273454..906795463 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -16,6 +16,10 @@ from temoa.temoa_model.temoa_mode import TemoaMode from temoa.temoa_model.temoa_model import TemoaModel from temoa.temoa_model.temoa_sequencer import TemoaSequencer +from temoa.temoa_model.temoa_rules import ( + link_season_next_timeslice, + loop_season_next_timeslice +) logger = logging.getLogger(__name__) # suitable scenarios for storage testing....singleton for now. @@ -31,41 +35,32 @@ indirect=True, ids=[d['name'] for d in storage_config_files], ) -def test_storage_init_frac(system_test_run): +def test_storage_fraction(system_test_run): """ - The level at the end of the first time slice in each season should be - initialization ± flows + Level at the start of the time slice should equal the forced fraction """ model: TemoaModel # helps with typing for some reason... data_name, results, model, _ = system_test_run - assert len(model.StorageInitFracConstraint_rpstv) > 0, ( - 'This model does not appear to have any StorageInitFrac constraints to test' + assert len(model.StorageFractionConstraint_rpsdtv) > 0, ( + 'This model does not appear to have any StorageFraction constraints to test' ) - # test the first periods - # get references to first timeslot for each rptv combo in things with storage - frac_slices = { - (r, p, s, t, v) - for r, p, s, t, v in model.StorageInitFracConstraint_rpstv - } - # test that the last day/season combo starts up at the initialization value - # devnote: the Level variable is assessed at the end of the timeperiod, so the init ± flows - # should total the end value - for r, p, s, t, v in frac_slices: - - init_energy = ( - model.StorageInitFrac[r, p, s, t, v] + + for r, p, s, d, t, v in model.StorageFractionConstraint_rpsdtv: + + energy = ( + model.StorageFraction[r, p, s, d, t, v] * model.V_Capacity[r, p, t, v].value * model.CapacityToActivity[r, t] * (model.StorageDuration[r, t] / 8760) - * sum(model.SegFrac[s, S_d] for S_d in model.time_of_day) + * model.SegFracPerSeason[s] * 365 * model.ProcessLifeFrac[r, p, t, v] ) - assert model.V_StorageInit[r, p, s, t, v].value == pytest.approx( - init_energy, rel=1e-3 - ), f'model fails to initialise storage state at start of season {r, p, s, t, v}' + assert model.V_StorageLevel[r, p, s, d, t, v].value == pytest.approx( + energy, rel=1e-3 + ), f'model fails to initialise storage state at start of season {r, p, s, d, t, v}' @pytest.mark.parametrize( @@ -74,114 +69,39 @@ def test_storage_init_frac(system_test_run): indirect=True, ids=[d['name'] for d in storage_config_files], ) -def test_season_start(system_test_run): +def test_state_sequencing(system_test_run): """ - The level at the end of the first time slice in each season should be - initialization ± flows + Make sure that everything is looping properly """ model: TemoaModel # helps with typing for some reason... data_name, results, model, _ = system_test_run - assert len(model.V_StorageInit.index_set()) > 0, ( - 'This model does not appear to have' 'any available storage components' + assert len(model.StorageLevel_rpsdtv) > 0, ( + 'This model does not appear to have any available storage components' ) - # test the first periods - # get references to first timeslot for each rptv combo in things with storage - start_slices = { - (r, p, s, d, t, v) - for r, p, s, d, t, v in model.StorageLevel_rpsdtv - if d == model.time_of_day.first() - } - # test that the last day/season combo starts up at the initialization value - # devnote: the Level variable is assessed at the end of the timeperiod, so the init ± flows - # should total the end value - for r, p, s, d, t, v in start_slices: - inflow_indices = { - (rr, pp, ss, dd, ii, tt, vv, oo) - for rr, pp, ss, dd, ii, tt, vv, oo in model.FlowInStorage_rpsditvo - if all((rr == r, pp == p, ss == s, dd == d, tt == t, vv == v)) - } - outflow_indices = { - (rr, pp, ss, dd, ii, tt, vv, oo) - for (rr, pp, ss, dd, ii, tt, vv, oo) in model.FlowVar_rpsditvo - if all((rr == r, pp == p, ss == s, dd == d, tt == t, vv == v)) - } + + for r, p, s, d, t, v in model.StorageLevel_rpsdtv: - # calculate the inflow and outflow. Inflow is taxed by efficiency in the model, - # so we need to do that here as well - inflow = sum( - model.V_FlowIn[r, p, s, d, i, t, v, o].value * model.Efficiency[r, i, t, v, o] - for (r, p, s, d, i, t, v, o) in inflow_indices + charge = sum( + model.V_FlowIn[r, p, s, d, S_i, t, v, S_o].value * model.Efficiency[r, S_i, t, v, S_o] + for S_i in model.processInputs[r, p, t, v] + for S_o in model.ProcessOutputsByInput[r, p, t, v, S_i] ) - outflow = sum(model.V_FlowOut[idx].value for idx in outflow_indices) - assert model.V_StorageInit[r, p, s, t, v].value + inflow - outflow == pytest.approx( - model.V_StorageLevel[r, p, s, d, t, v].value, rel=1e-3 - ), f'model fails to initialise storage state at start of season {r, p, s, t, v}' - - -@pytest.mark.parametrize( - 'system_test_run', - argvalues=storage_config_files, - indirect=True, - ids=[d['name'] for d in storage_config_files], -) -def test_season_end(system_test_run): - """ - The season should end on the appropriate initialisation state - (state should loop correctly) - """ - - model: TemoaModel # helps with typing for some reason... - data_name, results, model, _ = system_test_run - assert len(model.V_StorageInit.index_set()) > 0, ( - 'This model does not appear to have' 'any available storage components' - ) - # test the first periods - # get references to first timeslot for each rptv combo in things with storage - end_slices = { - (r, p, s, d, t, v) - for r, p, s, d, t, v in model.StorageLevel_rpsdtv - if d == model.time_of_day.last() - } - # test that the last day/season combo starts up at the initialization value - # devnote: the Level variable is assessed at the end of the timeperiod, so the init ± flows - # should total the end value - for r, p, s, d, t, v in end_slices: - inflow_indices = { - (rr, pp, ss, dd, ii, tt, vv, oo) - for rr, pp, ss, dd, ii, tt, vv, oo in model.FlowInStorage_rpsditvo - if all((rr == r, pp == p, ss == s, dd == d, tt == t, vv == v)) - } - outflow_indices = { - (rr, pp, ss, dd, ii, tt, vv, oo) - for (rr, pp, ss, dd, ii, tt, vv, oo) in model.FlowVar_rpsditvo - if all((rr == r, pp == p, ss == s, dd == d, tt == t, vv == v)) - } - - # calculate the inflow and outflow. Inflow is taxed by efficiency in the model, - # so we need to do that here as well - inflow = sum( - model.V_FlowIn[r, p, s, d, i, t, v, o].value * model.Efficiency[r, i, t, v, o] - for (r, p, s, d, i, t, v, o) in inflow_indices + discharge = sum( + model.V_FlowOut[r, p, s, d, S_i, t, v, S_o].value + for S_o in model.processOutputs[r, p, t, v] + for S_i in model.ProcessInputsByOutput[r, p, t, v, S_o] ) - outflow = sum(model.V_FlowOut[idx].value for idx in outflow_indices) - if model.interseason_storage: - # periods loop - if s == model.time_season.last(): - # end of last season should loop to start of first season - following_init = model.V_StorageInit[r, p, model.time_season.first(), t, v].value - else: - # end of other seasons should continue to start of next season - following_init = model.V_StorageInit[r, p, model.time_season.next(s), t, v].value - else: - # seasons loop - # end of season should loop to start of same season - following_init = model.V_StorageInit[r, p, s, t, v].value + if model.link_seasons: s_next, d_next = link_season_next_timeslice(model, s, d) + else: s_next, d_next = loop_season_next_timeslice(model, s, d) - assert model.V_StorageLevel[r, p, s, d, t, v].value + inflow - outflow == pytest.approx( - following_init, rel=1e-3 - ), f'model fails to correctly loop storage state at end of season {r, p, s, t, v}' + state = model.V_StorageLevel[r, p, s, d, t, v].value + next_state = model.V_StorageLevel[r, p, s_next, d_next, t, v].value + + assert state + charge - discharge == pytest.approx( + next_state, rel=1e-3 + ), f'model fails to correctly sequence storage states {r, p, s, t, v}' @pytest.mark.parametrize( @@ -197,7 +117,7 @@ def test_storage_flow_balance(system_test_run): """ model: TemoaModel # helps with typing for some reason... data_name, results, model, _ = system_test_run - assert len(model.V_StorageInit.index_set()) > 0, ( + assert len(model.StorageLevel_rpsdtv) > 0, ( 'This model does not appear to have' 'any available storage components' ) for s_tech in model.tech_storage: @@ -219,9 +139,11 @@ def test_storage_flow_balance(system_test_run): for (r, p, s, d, i, t, v, o) in inflow_indices ) outflow = sum(model.V_FlowOut[idx].value for idx in outflow_indices) + assert inflow == pytest.approx( outflow, rel=1e-3 - ), f'total inflow and outflow of storage tech {s_tech} do not match - not looping state correctly' + ), (f'total inflow and outflow of storage tech {s_tech} do not match', + ' - there is a discontinuity of storage states') @pytest.mark.skip('not ready for primetime') diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 0233ac4b7..7e071a34b 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -351,7 +351,7 @@ CREATE TABLE TechGroup ); INSERT INTO TechGroup VALUES('RPS_global',''); INSERT INTO TechGroup VALUES('RPS_common',''); -INSERT INTO TechGroup VALUES('(A)_tech_grp_1','converted from old db'); +INSERT INTO TechGroup VALUES('A_tech_grp_1','converted from old db'); CREATE TABLE GrowthRateMax ( region TEXT, @@ -484,7 +484,7 @@ CREATE TABLE MaxCapacityGroup notes TEXT, PRIMARY KEY (region, period, group_name) ); -INSERT INTO MaxCapacityGroup VALUES('A',2025,'(A)_tech_grp_1',6000.0,'',NULL); +INSERT INTO MaxCapacityGroup VALUES('A',2025,'A_tech_grp_1',6000.0,'',NULL); CREATE TABLE MinCapacity ( region TEXT, @@ -511,7 +511,7 @@ CREATE TABLE MinCapacityGroup notes TEXT, PRIMARY KEY (region, period, group_name) ); -INSERT INTO MinCapacityGroup VALUES('A',2025,'(A)_tech_grp_1',0.2000000000000000111,'',NULL); +INSERT INTO MinCapacityGroup VALUES('A',2025,'A_tech_grp_1',0.2000000000000000111,'',NULL); CREATE TABLE OutputCurtailment ( scenario TEXT, @@ -962,7 +962,7 @@ CREATE TABLE MinActivityGroup notes TEXT, PRIMARY KEY (region, period, group_name) ); -INSERT INTO MinActivityGroup VALUES('A',2025,'(A)_tech_grp_1',0.05000000000000000277,'',NULL); +INSERT INTO MinActivityGroup VALUES('A',2025,'A_tech_grp_1',0.05000000000000000277,'',NULL); CREATE TABLE EmissionLimit ( region TEXT, @@ -988,7 +988,7 @@ CREATE TABLE MaxActivityGroup notes TEXT, PRIMARY KEY (region, period, group_name) ); -INSERT INTO MaxActivityGroup VALUES('A',2025,'(A)_tech_grp_1',10000.0,'',NULL); +INSERT INTO MaxActivityGroup VALUES('A',2025,'A_tech_grp_1',10000.0,'',NULL); CREATE TABLE RPSRequirement ( region TEXT NOT NULL @@ -1010,8 +1010,8 @@ CREATE TABLE TechGroupMember PRIMARY KEY (group_name, tech) ); INSERT INTO TechGroupMember VALUES('RPS_common','EF'); -INSERT INTO TechGroupMember VALUES('(A)_tech_grp_1','EH'); -INSERT INTO TechGroupMember VALUES('(A)_tech_grp_1','EF'); +INSERT INTO TechGroupMember VALUES('A_tech_grp_1','EH'); +INSERT INTO TechGroupMember VALUES('A_tech_grp_1','EF'); CREATE TABLE Technology ( tech TEXT NOT NULL PRIMARY KEY, diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 7cc7e8057..d5ab25e31 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -95,12 +95,12 @@ "FGF_pipe" ], "tech_group_names": [ - "(A)_tech_grp_1", + "A_tech_grp_1", "RPS_common", "RPS_global" ], "tech_group_members": [ - "(A)_tech_grp_1", + "A_tech_grp_1", "RPS_common", "RPS_global" ], @@ -1624,28 +1624,28 @@ [ "A", 2025, - "(A)_tech_grp_1" + "A_tech_grp_1" ] ], "MaxActivityGroup_rpg": [ [ "A", 2025, - "(A)_tech_grp_1" + "A_tech_grp_1" ] ], "MinCapacityGroupConstraint_rpg": [ [ "A", 2025, - "(A)_tech_grp_1" + "A_tech_grp_1" ] ], "MaxCapacityGroupConstraint_rpg": [ [ "A", 2025, - "(A)_tech_grp_1" + "A_tech_grp_1" ] ], "MinNewCapacityGroupConstraint_rpg": [], @@ -1655,7 +1655,7 @@ "B", 2025, "EH", - "(A)_tech_grp_1" + "A_tech_grp_1" ], [ "B", @@ -1667,19 +1667,19 @@ "A", 2025, "EF", - "(A)_tech_grp_1" + "A_tech_grp_1" ], [ "B", 2025, "EF", - "(A)_tech_grp_1" + "A_tech_grp_1" ], [ "A", 2025, "EH", - "(A)_tech_grp_1" + "A_tech_grp_1" ], [ "A", @@ -1694,22 +1694,6 @@ "MaxActivityShareConstraint_rptg": [], "MinNewCapacityShareConstraint_rptg": [], "MaxNewCapacityShareConstraint_rptg": [], - "StorageInit_rpstv": [ - [ - "B", - 2025, - "s1", - "batt", - 2025 - ], - [ - "B", - 2025, - "s2", - "batt", - 2025 - ] - ], "FlowVar_rpsditvo": [ [ "A-B", @@ -2538,6 +2522,22 @@ ] ], "StorageLevel_rpsdtv": [ + [ + "B", + 2025, + "s2", + "d2", + "batt", + 2025 + ], + [ + "B", + 2025, + "s1", + "d2", + "batt", + 2025 + ], [ "B", 2025, @@ -3941,7 +3941,7 @@ 2025 ] ], - "StorageInitFracConstraint_rpstv": [], + "StorageFractionConstraint_rpsdtv": [], "RampUpConstraint_rpsdtv": [ [ "B", diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index 6704be263..0b57ba082 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -601,17 +601,18 @@ CREATE TABLE StorageDuration PRIMARY KEY (region, tech) ); INSERT INTO StorageDuration VALUES('electricville','batt',10.0,NULL); -CREATE TABLE StorageInitFrac +CREATE TABLE StorageFraction ( region TEXT, period INTEGER REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), + time_of_day TEXT REFERENCES TimeOfDay (time_of_day), tech TEXT REFERENCES Technology (tech), vintage INTEGER REFERENCES TimePeriod (period), frac REAL, notes TEXT ); -INSERT INTO StorageInitFrac VALUES('electricville',2025,'s1','batt',2025,0.5,''); +INSERT INTO StorageFraction VALUES('electricville',2025,'s1','d1','batt',2025,0.5,''); CREATE TABLE TechnologyType ( label TEXT diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index e99b27694..471e33006 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -964,18 +964,19 @@ CREATE TABLE StorageDuration ); INSERT INTO StorageDuration VALUES('R1','E_BATT',8.0,'8-hour duration specified as fraction of a day'); INSERT INTO StorageDuration VALUES('R2','E_BATT',8.0,'8-hour duration specified as fraction of a day'); -CREATE TABLE StorageInitFrac +CREATE TABLE StorageFraction ( region TEXT, period INTEGER REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), + time_of_day TEXT REFERENCES TimeOfDay (time_of_day), tech TEXT REFERENCES Technology (tech), vintage INTEGER REFERENCES TimePeriod (period), frac REAL, notes TEXT ); -INSERT INTO StorageInitFrac VALUES('R1',2025,'winter','E_BATT',2025,0.5,''); -INSERT INTO StorageInitFrac VALUES('R2',2020,'summer','E_BATT',2020,0.5,''); +INSERT INTO StorageFraction VALUES('R1',2025,'winter','day','E_BATT',2025,0.5,''); +INSERT INTO StorageFraction VALUES('R2',2020,'summer','day','E_BATT',2020,0.5,''); CREATE TABLE TechnologyType ( label TEXT diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 2bdc0bd7d..e52313457 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -6950,344 +6950,6 @@ "MaxActivityShareConstraint_rptg": [], "MinNewCapacityShareConstraint_rptg": [], "MaxNewCapacityShareConstraint_rptg": [], - "StorageInit_rpstv": [ - [ - "R1", - 2020, - "summer", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "spring", - "E_BATT", - 2030 - ], - [ - "R2", - 2025, - "fall", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "winter", - "E_BATT", - 2030 - ], - [ - "R1", - 2030, - "fall", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "winter", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "summer", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "spring", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "summer", - "E_BATT", - 2025 - ], - [ - "R1", - 2020, - "winter", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "spring", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "winter", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "spring", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "summer", - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "fall", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "spring", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "winter", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "winter", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "summer", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "fall", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "fall", - "E_BATT", - 2025 - ], - [ - "R1", - 2020, - "spring", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "fall", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "summer", - "E_BATT", - 2030 - ], - [ - "R2", - 2020, - "fall", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "summer", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "winter", - "E_BATT", - 2030 - ], - [ - "R2", - 2025, - "summer", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "spring", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "winter", - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "summer", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "spring", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "winter", - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "winter", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "fall", - "E_BATT", - 2030 - ], - [ - "R2", - 2030, - "fall", - "E_BATT", - 2030 - ], - [ - "R1", - 2030, - "summer", - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "spring", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "spring", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "winter", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "spring", - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "winter", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "summer", - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "fall", - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "fall", - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "summer", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "spring", - "E_BATT", - 2030 - ], - [ - "R2", - 2030, - "fall", - "E_BATT", - 2020 - ] - ], "FlowVar_rpsditvo": [ [ "R1", @@ -22658,6 +22320,390 @@ ] ], "StorageLevel_rpsdtv": [ + [ + "R2", + 2030, + "fall", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_BATT", + 2030 + ], + [ + "R1", + 2025, + "winter", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "summer", + "night", + "E_BATT", + 2030 + ], + [ + "R2", + 2025, + "winter", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "winter", + "night", + "E_BATT", + 2030 + ], + [ + "R1", + 2025, + "summer", + "night", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "spring", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "winter", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2020, + "spring", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "spring", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "fall", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "summer", + "night", + "E_BATT", + 2025 + ], + [ + "R2", + 2020, + "fall", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "spring", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "fall", + "night", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "summer", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "fall", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "winter", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "winter", + "night", + "E_BATT", + 2025 + ], + [ + "R2", + 2020, + "summer", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "spring", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2025, + "spring", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2020, + "spring", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_BATT", + 2030 + ], + [ + "R2", + 2030, + "winter", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2025, + "fall", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_BATT", + 2025 + ], + [ + "R2", + 2020, + "winter", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2020, + "summer", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "spring", + "night", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "fall", + "night", + "E_BATT", + 2030 + ], + [ + "R2", + 2030, + "summer", + "night", + "E_BATT", + 2025 + ], + [ + "R2", + 2025, + "fall", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_BATT", + 2030 + ], + [ + "R2", + 2025, + "winter", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "winter", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2020, + "winter", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "summer", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "spring", + "night", + "E_BATT", + 2030 + ], + [ + "R2", + 2025, + "summer", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "winter", + "night", + "E_BATT", + 2030 + ], + [ + "R1", + 2020, + "fall", + "night", + "E_BATT", + 2020 + ], [ "R1", 2030, @@ -42918,11 +42964,12 @@ 2025 ] ], - "StorageInitFracConstraint_rpstv": [ + "StorageFractionConstraint_rpsdtv": [ [ "R1", 2025, "winter", + "day", "E_BATT", 2025 ], @@ -42930,6 +42977,7 @@ "R2", 2020, "summer", + "day", "E_BATT", 2020 ] diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 675e1809b..9620aa675 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -5301,197 +5301,6 @@ "MaxActivityShareConstraint_rptg": [], "MinNewCapacityShareConstraint_rptg": [], "MaxNewCapacityShareConstraint_rptg": [], - "StorageInit_rpstv": [ - [ - "utopia", - 2000, - "summer", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "E51", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "E51", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "E51", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "E51", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "E51", - 2010 - ], - [ - "utopia", - 1990, - "winter", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "E51", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "E51", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "E51", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "E51", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "E51", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "E51", - 1980 - ] - ], "FlowVar_rpsditvo": [ [ "utopia", @@ -13661,6 +13470,222 @@ ] ], "StorageLevel_rpsdtv": [ + [ + "utopia", + 2010, + "summer", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E51", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E51", + 2000 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E51", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E51", + 2000 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E51", + 2010 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E51", + 2010 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E51", + 1990 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E51", + 1990 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E51", + 2000 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E51", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E51", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E51", + 1980 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E51", + 1980 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E51", + 1980 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E51", + 2010 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E51", + 1990 + ], [ "utopia", 2000, @@ -24505,7 +24530,7 @@ 2000 ] ], - "StorageInitFracConstraint_rpstv": [], + "StorageFractionConstraint_rpsdtv": [], "RampUpConstraint_rpsdtv": [], "RampDownConstraint_rpsdtv": [], "ReserveMargin_rpsd": [ From 6bcd8d1f90223ca86b5fb92702af2de5873ab427 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 7 Aug 2025 09:26:52 -0400 Subject: [PATCH 020/587] Add option to output storage levels by time slice --- data_files/my_configs/config_sample.toml | 3 +++ temoa/temoa_model/run_actions.py | 6 ++---- temoa/temoa_model/table_data_puller.py | 20 ++++++++++--------- temoa/temoa_model/table_writer.py | 25 ++++++++++++++++++++++++ temoa/temoa_model/temoa_config.py | 3 +++ 5 files changed, 44 insertions(+), 13 deletions(-) diff --git a/data_files/my_configs/config_sample.toml b/data_files/my_configs/config_sample.toml index 1763880ab..1ab39cfa1 100644 --- a/data_files/my_configs/config_sample.toml +++ b/data_files/my_configs/config_sample.toml @@ -71,6 +71,9 @@ save_excel = true # save the duals in the output Database (may slow execution slightly?) save_duals = true +# save storage levels by time slice (may be a large amount of data) +save_storage_levels = true + # save a copy of the pyomo-generated lp file(s) to the outputs folder (maybe a large file(s)!) save_lp_file = false diff --git a/temoa/temoa_model/run_actions.py b/temoa/temoa_model/run_actions.py index 8d737d81d..587653567 100644 --- a/temoa/temoa_model/run_actions.py +++ b/temoa/temoa_model/run_actions.py @@ -337,11 +337,9 @@ def handle_results( table_writer = TableWriter(config=config) if config.save_duals: - table_writer.write_results( - M=instance, results_with_duals=results, append=append, iteration=iteration - ) + table_writer.write_results(M=instance, results_with_duals=results, save_storage_levels=config.save_storage_levels, append=append, iteration=iteration) else: - table_writer.write_results(M=instance, append=append, iteration=iteration) + table_writer.write_results(M=instance, append=append, save_storage_levels=config.save_storage_levels, iteration=iteration) if not config.silent: SE.write( diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index c58d26069..08625bbfd 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -70,8 +70,8 @@ class FlowType(Enum): FI = namedtuple('FI', ['r', 'p', 's', 'd', 'i', 't', 'v', 'o']) """Flow Index""" -SSI = namedtuple('SSI', ['r', 'p', 's', 'd', 't', 'v']) -"""Storage State Index""" +SLI = namedtuple('SLI', ['r', 'p', 's', 'd', 't', 'v']) +"""Storage Level Index""" CapData = namedtuple('CapData', ['built', 'net', 'retired']) """Small container to hold named dictionaries of capacity data for processing""" @@ -204,22 +204,24 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl return res -def poll_storage_state_results(M: TemoaModel, epsilon=1e-5) -> dict[SSI, float]: +def poll_storage_level_results(M: TemoaModel, epsilon=1e-5) -> dict[SLI, float]: """ Poll a solved model for flow results. :param M: A solved Model :param epsilon: epsilon (default 1e-5) - :return: nested dictionary of FlowIndex, FlowType : value + :return: dictionary of storage level index, storage level """ - res: dict[SSI, float] = defaultdict(float) + res: dict[SLI, float] = defaultdict(float) # Storage level, the state variable for all but last time slice of each season - for ssi in M.StorageLevel_rpsdtv: - state = value(M.V_StorageLevel[ssi]) - ssi = SSI(*ssi) + for sli in M.StorageLevel_rpsdtv: + state = value(M.V_StorageLevel[sli]) + sli = SLI(*sli) if abs(state) < epsilon: continue - res[ssi] = state + res[sli] = state + + return res def poll_objective(M: TemoaModel) -> list[tuple[str, float]]: diff --git a/temoa/temoa_model/table_writer.py b/temoa/temoa_model/table_writer.py index 416692417..103f3ebef 100644 --- a/temoa/temoa_model/table_writer.py +++ b/temoa/temoa_model/table_writer.py @@ -24,6 +24,7 @@ _marks, CapData, poll_objective, + poll_storage_level_results, poll_cost_results, poll_emissions, ) @@ -105,6 +106,7 @@ def write_results( self, M: TemoaModel, results_with_duals: SolverResults | None = None, + save_storage_levels: bool = True, append=False, iteration: int | None = None, ) -> None: @@ -122,6 +124,8 @@ def write_results( self._set_tech_sectors() self.write_objective(M, iteration=iteration) self.write_capacity_tables(M, iteration=iteration) + if save_storage_levels: + self.write_storage_level(M, iteration=iteration) # analyze the emissions to get the costs and flows if self.config.scenario_mode == TemoaMode.MYOPIC: p_0 = M.MyopicBaseyear @@ -219,6 +223,27 @@ def clear_iterative_runs(self): pass self.con.commit() + def write_storage_level(self, M: TemoaModel, iteration=None) -> None: + """Write the storage level table to the DB""" + + # For backwards compatibility + qry = self.con.execute(f"SELECT name FROM sqlite_master WHERE type='table' AND name='OutputStorageLevel';").fetchone() + if qry is None: return + + storage_levels = poll_storage_level_results(M=M) + + scenario_name = ( + self.config.scenario + f'-{iteration}' + if iteration is not None + else self.config.scenario + ) + + for sli, storage_level in storage_levels.items(): + qry = 'INSERT INTO OutputStorageLevel VALUES (?, ?, ?, ?, ?, ?, ?, ?)' + data = (scenario_name, *sli, storage_level) + self.con.execute(qry, data) + self.con.commit() + def write_objective(self, M: TemoaModel, iteration=None) -> None: """Write the value of all ACTIVE objectives to the DB""" obj_vals = poll_objective(M=M) diff --git a/temoa/temoa_model/temoa_config.py b/temoa/temoa_model/temoa_config.py index 9a3583c08..eb0539bf3 100644 --- a/temoa/temoa_model/temoa_config.py +++ b/temoa/temoa_model/temoa_config.py @@ -45,6 +45,7 @@ def __init__( neos: bool = False, save_excel: bool = False, save_duals: bool = False, + save_storage_levels: bool = False, save_lp_file: bool = False, MGA: dict | None = None, SVMGA: dict | None = None, @@ -117,6 +118,7 @@ def __init__( self.solver_name = solver_name self.save_excel = save_excel self.save_duals = save_duals + self.save_storage_levels = save_storage_levels self.save_lp_file = save_lp_file self.mga_inputs = MGA @@ -190,6 +192,7 @@ def __repr__(self): msg += '{:>{}s}: {}\n'.format('Spreadsheet output', width, self.save_excel) msg += '{:>{}s}: {}\n'.format('Pyomo LP write status', width, self.save_lp_file) msg += '{:>{}s}: {}\n'.format('Save duals to output db', width, self.save_duals) + msg += '{:>{}s}: {}\n'.format('Save storage to output db', width, self.save_storage_levels) if self.scenario_mode == TemoaMode.MYOPIC: msg += spacer From 455aae0e45a78dc49e8f34d16e72df07919481aa Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 7 Aug 2025 09:28:08 -0400 Subject: [PATCH 021/587] Create time_next dictionary Initialize time slice sequence only once at beginning of instantation (time_next dictionary) and call from this going forward --- temoa/temoa_model/hybrid_loader.py | 4 +- temoa/temoa_model/table_writer.py | 4 +- temoa/temoa_model/temoa_initialize.py | 52 ++++++++++++++++++++++++++ temoa/temoa_model/temoa_model.py | 3 +- temoa/temoa_model/temoa_rules.py | 54 ++------------------------- 5 files changed, 61 insertions(+), 56 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index d8b00d34a..49b389591 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -382,11 +382,11 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): raw = cur.execute('SELECT season FROM main.TimeSeason ORDER BY sequence').fetchall() load_element(M.time_season, raw) - # link_seasons + # LinkSeasons raw = cur.execute("SELECT value from MetaData WHERE element == 'link_seasons'").fetchall() if not raw: raise ValueError('link_seasons boolean parameter missing from MetaData table. Seasons will loop by default.') - data[M.link_seasons.name] = {None: bool(raw[0][0])} + data[M.LinkSeasons.name] = {None: bool(raw[0][0])} # myopic_base_year if mi: diff --git a/temoa/temoa_model/table_writer.py b/temoa/temoa_model/table_writer.py index 103f3ebef..85ba41201 100644 --- a/temoa/temoa_model/table_writer.py +++ b/temoa/temoa_model/table_writer.py @@ -226,9 +226,9 @@ def clear_iterative_runs(self): def write_storage_level(self, M: TemoaModel, iteration=None) -> None: """Write the storage level table to the DB""" - # For backwards compatibility + # For backwards compatibility, check if the output table actually exists qry = self.con.execute(f"SELECT name FROM sqlite_master WHERE type='table' AND name='OutputStorageLevel';").fetchone() - if qry is None: return + if qry is None: return # if not, skip storage_levels = poll_storage_level_results(M=M) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 899830898..f4403ce08 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -791,6 +791,12 @@ def CreateSparseDicts(M: 'TemoaModel'): for i in sorted(l_unused_techs): SE.write(msg.format(i)) + # Establishing chronology of states + for s, d in M.time_season * M.time_of_day: + if M.LinkSeasons: s_next, d_next = link_season_next_timeslice(M, s, d) + else: s_next, d_next = loop_season_next_timeslice(M, s, d) + M.time_next[s, d] = (s_next, d_next) + # valid region-period-commodity sets for commodity balance constraints commodityUpstream_rpi = set(M.commodityUStreamProcess.keys()) commodityDownstream_rpo = set(M.commodityDStreamProcess.keys()) @@ -1386,6 +1392,52 @@ def GrowthRateMaxIndices(M: 'TemoaModel'): return indices +def link_season_next_timeslice(M: 'TemoaModel', s, d) -> tuple[str, str]: + + # Final time slice of final season (end of period) + # Loop state back to initial state of first season + # Loop the period + if s == M.time_season.last() and d == M.time_of_day.last(): + s_next = M.time_season.first() + d_next = M.time_of_day.first() + + # Last time slice of any season that is NOT the last season + # Carry state to initial state of next season + # Carry state between seasons + elif d == M.time_of_day.last(): + s_next = M.time_season.next(s) + d_next = M.time_of_day.first() + + # Any other time slice + # Carry state to next time slice in the same season + # Continuing through this season + else: + s_next = s + d_next = M.time_of_day.next(d) + + return s_next, d_next + + +def loop_season_next_timeslice(M: 'TemoaModel', s, d) -> tuple[str, str]: + + # We loop each season so never carrying state between seasons + s_next = s + + # Final time slice of any season + # Loop state back to initial state of same season + # Loop each season + if d == M.time_of_day.last(): + d_next = M.time_of_day.first() + + # Any other time slice + # Carry state to next time slice in the same season + # Continuing through this season + else: + d_next = M.time_of_day.next(d) + + return s_next, d_next + + def get_loan_life(M, r, t, _): return M.LoanLifetimeTech[r, t] diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index d44eca5da..3e074a0fb 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -116,6 +116,7 @@ def __init__(M, *args, **kwargs): M.ProcessByPeriodAndOutput = dict() M.exportRegions = dict() M.importRegions = dict() + M.time_next = dict() M.flex_commodities = set() ################################################ @@ -219,6 +220,7 @@ def __init__(M, *args, **kwargs): M.PeriodLength = Param(M.time_optimize, initialize=ParamPeriodLength) M.SegFrac = Param(M.time_season, M.time_of_day) M.validate_SegFrac = BuildAction(rule=validate_SegFrac) + M.LinkSeasons = Param(default=0) # do states carry from one season to the next? otherwise loop each season # Define demand- and resource-related parameters # Dev Note: There does not appear to be a DB table supporting DemandDefaultDistro. This does not @@ -469,7 +471,6 @@ def __init__(M, *args, **kwargs): M.EmissionEmbodied = Param(M.regions, M.commodity_emissions, M.tech_with_capacity, M.vintage_optimize) M.MyopicBaseyear = Param(default=0) - M.link_seasons = Param(default=0) # do states carry from one season to the next? otherwise loop each season ################################################ # Model Variables # diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 30dc5584c..f0e4230c4 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1140,58 +1140,14 @@ def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): stored_energy = charge - discharge - # What time slice follows this one - if M.link_seasons: s_next, d_next = link_season_next_timeslice(M, s, d) - else: s_next, d_next = loop_season_next_timeslice(M, s, d) + s_next, d_next = M.time_next[s, d] expr = M.V_StorageLevel[r, p, s, d, t, v] + stored_energy == M.V_StorageLevel[r, p, s_next, d_next, t, v] return expr -def link_season_next_timeslice(M: 'TemoaModel', s, d) -> tuple[str, str]: - - # Final time slice of final season (end of period) - # Loop storage state back to initial state of first season - # Loop the period - if s == M.time_season.last() and d == M.time_of_day.last(): - s_next = M.time_season.first() - d_next = M.time_of_day.first() - - # Last time slice of any season that is NOT the last season - # Carry storage state to initial state of next season - # Carry storage state between seasons - elif d == M.time_of_day.last(): - s_next = M.time_season.next(s) - d_next = M.time_of_day.first() - - # Any other time slice - # Carry storage state to next time slice in the same season - # Continuing through this season - else: - s_next = s - d_next = M.time_of_day.next(d) - - return s_next, d_next - - -def loop_season_next_timeslice(M: 'TemoaModel', s, d) -> Expression: - - s_next = s - - # Final time slice of any season - # Loop storage state back to initial state of same season - # Loop each season - if d == M.time_of_day.last(): - d_next = M.time_of_day.first() - - # Any other time slice - # Carry storage state to next time slice in the same season - # Continuing through this season - else: - d_next = M.time_of_day.next(d) - return s_next, d_next def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): @@ -1443,9 +1399,7 @@ def RampUp_Constraint(M: 'TemoaModel', r, p, s, d, t, v): \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampUpDay}} """ - # What time slice follows this one - if M.link_seasons: s_next, d_next = link_season_next_timeslice(M, s, d) - else: s_next, d_next = loop_season_next_timeslice(M, s, d) + s_next, d_next = M.time_next[s, d] activity_sd = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] @@ -1492,9 +1446,7 @@ def RampDown_Constraint(M: 'TemoaModel', r, p, s, d, t, v): \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampDownDay}} """ - # What time slice follows this one - if M.link_seasons: s_next, d_next = link_season_next_timeslice(M, s, d) - else: s_next, d_next = loop_season_next_timeslice(M, s, d) + s_next, d_next = M.time_next[s, d] activity_sd = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] From e46b5ccd7efeadebdbac41e8d6e630e80cc65c83 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 7 Aug 2025 09:29:51 -0400 Subject: [PATCH 022/587] Clean up storage changes - Make column names consistent with other tables - Create storage level output table if needed for backwards compatibility --- temoa/temoa_model/hybrid_loader.py | 2 +- temoa/temoa_model/table_data_puller.py | 3 +-- temoa/temoa_model/table_writer.py | 34 ++++++++++++++++++++------ tests/testing_data/storageville.sql | 3 ++- tests/testing_data/test_system.sql | 2 +- tests/testing_data/utopia.sql | 19 ++++++++++++++ 6 files changed, 51 insertions(+), 12 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 49b389591..0b3de4255 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -1223,7 +1223,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # StorageFraction if self.table_exists('StorageFraction'): - raw = cur.execute('SELECT region, period, season, time_of_day, tech, vintage, frac FROM main.StorageFraction').fetchall() + raw = cur.execute('SELECT region, period, season, tod, tech, vintage, frac FROM main.StorageFraction').fetchall() load_element(M.StorageFraction, raw, self.viable_rtv, (0,4,5)) # For T/S: dump the size of all data elements into the log diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index 08625bbfd..832922d6c 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -217,8 +217,7 @@ def poll_storage_level_results(M: TemoaModel, epsilon=1e-5) -> dict[SLI, float]: for sli in M.StorageLevel_rpsdtv: state = value(M.V_StorageLevel[sli]) sli = SLI(*sli) - if abs(state) < epsilon: - continue + if abs(state) < epsilon: state = 0 # still want to know but decimals are ugly res[sli] = state return res diff --git a/temoa/temoa_model/table_writer.py b/temoa/temoa_model/table_writer.py index 85ba41201..c5521ff12 100644 --- a/temoa/temoa_model/table_writer.py +++ b/temoa/temoa_model/table_writer.py @@ -21,6 +21,7 @@ FI, FlowType, EI, + SLI, _marks, CapData, poll_objective, @@ -80,7 +81,7 @@ 'OutputObjective', 'OutputRetiredCapacity', ] -optional_output_tables = ['OutputFlowOutSummary', 'OutputMCDelta'] +optional_output_tables = ['OutputFlowOutSummary', 'OutputMCDelta', 'OutputStorageLevel'] flow_summary_file_loc = Path( PROJECT_ROOT, 'temoa/extensions/modeling_to_generate_alternatives/make_flow_summary_table.sql' @@ -201,7 +202,12 @@ def _set_tech_sectors(self): def clear_scenario(self): cur = self.con.cursor() for table in basic_output_tables: - cur.execute(f'DELETE FROM {table} WHERE scenario = ?', (self.config.scenario,)) + cur.execute(f'DELETE FROM {table} WHERE scenario == ?', (self.config.scenario,)) + for table in optional_output_tables: + try: + cur.execute(f'DELETE FROM {table} WHERE scenario == ?', (self.config.scenario,)) + except sqlite3.OperationalError: + pass self.con.commit() self.clear_iterative_runs() @@ -226,9 +232,22 @@ def clear_iterative_runs(self): def write_storage_level(self, M: TemoaModel, iteration=None) -> None: """Write the storage level table to the DB""" - # For backwards compatibility, check if the output table actually exists - qry = self.con.execute(f"SELECT name FROM sqlite_master WHERE type='table' AND name='OutputStorageLevel';").fetchone() - if qry is None: return # if not, skip + # For backwards compatibility, make the output table if it doesn't exist + qry = self.con.execute( + f"""CREATE TABLE IF NOT EXISTS + OutputStorageLevel( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + season TEXT REFERENCES TimePeriod (period), + tod TEXT REFERENCES TimeOfDay (tod), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (region, scenario, period, season, tod, tech, vintage) + );""" + ) storage_levels = poll_storage_level_results(M=M) @@ -239,8 +258,9 @@ def write_storage_level(self, M: TemoaModel, iteration=None) -> None: ) for sli, storage_level in storage_levels.items(): - qry = 'INSERT INTO OutputStorageLevel VALUES (?, ?, ?, ?, ?, ?, ?, ?)' - data = (scenario_name, *sli, storage_level) + sector = self.tech_sectors[sli.t] + qry = 'INSERT INTO OutputStorageLevel VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)' + data = (scenario_name, sli.r, sector, sli.p, sli.s, sli.d, sli.t, sli.v, storage_level) self.con.execute(qry, data) self.con.commit() diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index 0b57ba082..1af83d686 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -606,11 +606,12 @@ CREATE TABLE StorageFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), - time_of_day TEXT REFERENCES TimeOfDay (time_of_day), + tod TEXT REFERENCES TimeOfDay (tod), tech TEXT REFERENCES Technology (tech), vintage INTEGER REFERENCES TimePeriod (period), frac REAL, notes TEXT + PRIMARY KEY (region, period, season, tod, tech, vintage) ); INSERT INTO StorageFraction VALUES('electricville',2025,'s1','d1','batt',2025,0.5,''); CREATE TABLE TechnologyType diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 471e33006..bbed5cdf3 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -969,7 +969,7 @@ CREATE TABLE StorageFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), - time_of_day TEXT REFERENCES TimeOfDay (time_of_day), + tod TEXT REFERENCES TimeOfDay (tod), tech TEXT REFERENCES Technology (tech), vintage INTEGER REFERENCES TimePeriod (period), frac REAL, diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index f43ae13fd..ccf336bf1 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -900,6 +900,25 @@ CREATE TABLE OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); +CREATE TABLE OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (region, scenario, period, season, tod, tech, vintage) +); CREATE TABLE PlanningReserveMargin ( region TEXT From 97938538cc942971627b3323a8676d4b98782ccf Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 7 Aug 2025 09:30:26 -0400 Subject: [PATCH 023/587] Fix ramp rates to be per hour as intended --- temoa/temoa_model/temoa_initialize.py | 8 +++---- temoa/temoa_model/temoa_rules.py | 30 ++++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index f4403ce08..733fdd691 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -355,7 +355,7 @@ def CreateDemands(M: 'TemoaModel'): # demand in the tuple (r, s, d, dem) DSD_region_getter = iget(0) - # Step 1 + # Step 1: Check if any demand commodities are going unused used_dems = set(dem for r, p, dem in M.Demand.sparse_iterkeys()) unused_dems = sorted(M.commodity_demand.difference(used_dems)) if unused_dems: @@ -364,7 +364,7 @@ def CreateDemands(M: 'TemoaModel'): logger.warning(msg.format(dem)) SE.write(msg.format(dem)) - # Step 2 + # Step 2: Build the demand default distribution (= segfrac) DDD = M.DemandDefaultDistribution # Shorter, for us lazy programmer types unset_defaults = set(M.SegFrac.sparse_iterkeys()) unset_defaults.difference_update(DDD.sparse_iterkeys()) @@ -377,7 +377,7 @@ def CreateDemands(M: 'TemoaModel'): for tslice in unset_defaults: DDD[tslice] = M.SegFrac[tslice] # DDD._constructed = True - # Step 3 + # Step 3: Check that DDD sums to 1 total = sum(i for i in DDD.values()) if abs(value(total) - 1.0) > 0.001: # We can't explicitly test for "!= 1.0" because of incremental rounding @@ -402,7 +402,7 @@ def CreateDemands(M: 'TemoaModel'): logger.error(msg.format(items, total)) raise ValueError(msg.format(items, total)) - # Step 4 + # Step 4: Fill out demand specific distribution table and check sums to 1 by region and demand DSD = M.DemandSpecificDistribution demands_specified = set(map(DSD_dem_getter, (i for i in DSD.sparse_iterkeys()))) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index f0e4230c4..cd66376d8 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1413,8 +1413,19 @@ def RampUp_Constraint(M: 'TemoaModel', r, p, s, d, t, v): for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] ) / value(M.SegFrac[s_next, d_next]) + hours_elapsed = 8760 * (value(M.SegFrac[s, d]) + value(M.SegFrac[s_next, d_next])) / 2 + hours_elapsed /= M.SegFracPerSeason[s] * 365 # adjust for how many days this season represents + ramp_fraction = hours_elapsed * value(M.RampUp[r, t]) + + if ramp_fraction >= 1: + msg = ( + "Warning: Hourly ramp up rate ({}, {}) is too large to be constraining from ({}, {}) to ({}, {}). Constraint skipped." + ) + logger.warning(msg.format(r, t, s, d, s_next, d_next)) + return Constraint.Skip + activity_increase = activity_sd_next - activity_sd # opposite sign from rampdown - rampable_activity = M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.RampUp[r, t]) + rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * M.ProcessLifeFrac[r, p, t, v] expr = activity_increase <= rampable_activity return expr @@ -1460,8 +1471,21 @@ def RampDown_Constraint(M: 'TemoaModel', r, p, s, d, t, v): for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] ) / value(M.SegFrac[s_next, d_next]) - activity_decrease = activity_sd - activity_sd_next # opposite sign from rampup - rampable_activity = M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.RampDown[r, t]) + # We should adjust the hours elapsed to the number of days this season represents + # but then we'd adjust the activity by that same factor, so they cancel out. Serendipitous. + hours_elapsed = 8760 * (value(M.SegFrac[s, d]) + value(M.SegFrac[s_next, d_next])) / 2 + hours_elapsed /= M.SegFracPerSeason[s] * 365 # adjust for how many days this season represents + ramp_fraction = hours_elapsed * value(M.RampDown[r, t]) + + if ramp_fraction >= 1: + msg = ( + "Warning: Hourly ramp down rate ({}, {}) is too large to be constraining from ({}, {}) to ({}, {}). Constraint skipped." + ) + logger.warning(msg.format(r, t, s, d, s_next, d_next)) + return Constraint.Skip + + activity_decrease = activity_sd - activity_sd_next # opposite sign from rampdown + rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * M.ProcessLifeFrac[r, p, t, v] expr = activity_decrease <= rampable_activity return expr From 4f92942020cd0fb80e23afcb7f737e0c9367279a Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 7 Aug 2025 09:30:53 -0400 Subject: [PATCH 024/587] Remove erroneous comment --- temoa/temoa_model/temoa_rules.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index cd66376d8..fffbd64d9 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1471,8 +1471,6 @@ def RampDown_Constraint(M: 'TemoaModel', r, p, s, d, t, v): for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] ) / value(M.SegFrac[s_next, d_next]) - # We should adjust the hours elapsed to the number of days this season represents - # but then we'd adjust the activity by that same factor, so they cancel out. Serendipitous. hours_elapsed = 8760 * (value(M.SegFrac[s, d]) + value(M.SegFrac[s_next, d_next])) / 2 hours_elapsed /= M.SegFracPerSeason[s] * 365 # adjust for how many days this season represents ramp_fraction = hours_elapsed * value(M.RampDown[r, t]) From eabb87c6461cd218eb3c8b3e6146a112673a3b72 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 7 Aug 2025 09:46:22 -0400 Subject: [PATCH 025/587] Clean up and audit myopic loading in hybrid_loader - Collapse time sequencing into time_next dictionary - Factorise myopic loading in hybrid_loader, moving the myopic check to a function - Make some fixes to new storage for myopic modelling --- temoa/extensions/myopic/myopic_sequencer.py | 2 + temoa/temoa_model/hybrid_loader.py | 406 ++++---------------- temoa/temoa_model/table_writer.py | 9 +- temoa/temoa_model/temoa_rules.py | 2 +- tests/test_storage.py | 7 +- tests/testing_data/storageville.sql | 2 +- 6 files changed, 84 insertions(+), 344 deletions(-) diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index ebb026bda..a335502cc 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -69,6 +69,7 @@ class MyopicSequencer: 'OutputNetCapacity', 'OutputObjective', 'OutputRetiredCapacity', + 'OutputStorageLevel', ] tables_without_scenario_reference = [ 'MyopicEfficiency', @@ -85,6 +86,7 @@ class MyopicSequencer: 'OutputFlowOut', 'OutputNetCapacity', 'OutputRetiredCapacity', + 'OutputStorageLevel', ] def __init__(self, config: TemoaConfig | None): diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 0b3de4255..a9171b99d 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -34,7 +34,7 @@ import time from collections import defaultdict from logging import getLogger -from sqlite3 import Connection, OperationalError +from sqlite3 import Connection, OperationalError, Cursor from typing import Sequence from pyomo.core import Param, Set @@ -580,16 +580,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): load_element(M.DemandSpecificDistribution, raw) # Demand - if mi: - raw = cur.execute( - 'SELECT region, period, commodity, demand FROM main.Demand ' - 'WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, commodity, demand FROM main.Demand ' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, commodity, demand FROM main.Demand', mi=mi) load_element(M.Demand, raw) # RescourceBound @@ -626,49 +617,30 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): load_element(M.LoanLifetimeTech, raw, self.viable_rt, (0, 1)) # TechInputSplit - if mi: - raw = cur.execute( - 'SELECT region, period, input_comm, tech, min_proportion FROM main.TechInputSplit ' - 'WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, input_comm, tech, min_proportion FROM main.TechInputSplit ' - ).fetchall() - loaded = load_element(M.TechInputSplit, raw, self.viable_rpit, (0, 1, 2, 3)) - # we need to see if anything was filtered out here and raise warning if so as it may have invalidated - # a blending process and any missing items should be reviewed - if len(loaded) < len(raw): - missing = set(raw) - set(loaded) - for item in sorted(missing, key=lambda x: (x[0], x[1], x[3], x[2])): - region, period, ic, tech, _ = item - logger.warning( - 'Technology Input Split requirement in region %s, period %d for tech %s with input' - 'commodity %s has ' - 'been removed because the tech path with that input is ' - 'invalid/not available/orphan. See the other warnings for this TECH in ' - 'this region-period, and check for availability of all components in data.', - region, - period, - tech, - ic, + if self.table_exists('TechInputSplit'): + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, input_comm, tech, min_proportion FROM main.TechInputSplit', mi=mi) + loaded = load_element(M.TechInputSplit, raw, self.viable_rpit, (0, 1, 2, 3)) + # we need to see if anything was filtered out here and raise warning if so as it may have invalidated + # a blending process and any missing items should be reviewed + if len(loaded) < len(raw): + missing = set(raw) - set(loaded) + for item in sorted(missing, key=lambda x: (x[0], x[1], x[3], x[2])): + region, period, ic, tech, _ = item + logger.warning( + 'Technology Input Split requirement in region %s, period %d for tech %s with input' + 'commodity %s has ' + 'been removed because the tech path with that input is ' + 'invalid/not available/orphan. See the other warnings for this TECH in ' + 'this region-period, and check for availability of all components in data.', + region, + period, + tech, + ic, ) # TechInputSplitAnnual if self.table_exists('TechInputSplitAnnual'): - if mi: - raw = cur.execute( - 'SELECT region, period, input_comm, tech, min_proportion ' - 'FROM main.TechInputSplitAnnual ' - 'WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, input_comm, tech, min_proportion ' - 'FROM main.TechInputSplitAnnual ' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, input_comm, tech, min_proportion FROM main.TechInputSplitAnnual', mi=mi) loaded = load_element(M.TechInputSplitAnnual, raw, self.viable_rpit, (0, 1, 2, 3)) # we need to see if anything was filtered out here and raise warning if so as it may have invalidated # a blending process and any missing items should be reviewed @@ -687,18 +659,10 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): tech, ic, ) + # TechOutputSplit if self.table_exists('TechOutputSplit'): - if mi: - raw = cur.execute( - 'SELECT region, period, tech, output_comm, min_proportion FROM main.TechOutputSplit ' - 'WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, tech, output_comm, min_proportion FROM main.TechOutputSplit ' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, output_comm, min_proportion FROM main.TechOutputSplit', mi=mi) loaded = load_element(M.TechOutputSplit, raw, self.viable_rpto, (0, 1, 2, 3)) # raise warning regarding any deletions here... similar to input split above if len(loaded) < len(raw): @@ -719,18 +683,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # TechOutputSplitAnnual if self.table_exists('TechOutputSplitAnnual'): - if mi: - raw = cur.execute( - 'SELECT region, period, tech, output_comm, min_proportion ' - 'FROM main.TechOutputSplitAnnual ' - 'WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, tech, output_comm, min_proportion ' - 'FROM main.TechOutputSplitAnnual ' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, output_comm, min_proportion FROM main.TechOutputSplitAnnual', mi=mi) loaded = load_element(M.TechOutputSplitAnnual, raw, self.viable_rpto, (0, 1, 2, 3)) # we need to see if anything was filtered out here and raise warning if so as it may have invalidated # a blending process and any missing items should be reviewed @@ -752,29 +705,11 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # RenewablePortfolioStandard if self.table_exists('RPSRequirement'): - if mi: - raw = cur.execute( - 'SELECT region, period, tech_group, requirement FROM main.RPSRequirement ' - ' WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, tech_group, requirement FROM main.RPSRequirement ' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech_group, requirement FROM main.RPSRequirement', mi=mi) load_element(M.RenewablePortfolioStandard, raw) # CostFixed - if mi: - raw = cur.execute( - 'SELECT region, period, tech, vintage, cost FROM main.CostFixed ' - 'WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, tech, vintage, cost FROM main.CostFixed ' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, vintage, cost FROM main.CostFixed', mi=mi) load_element(M.CostFixed, raw, self.viable_rtv, val_loc=(0, 2, 3)) # CostInvest @@ -790,44 +725,15 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): load_element(M.CostInvest, raw, self.viable_rtv, (0, 1, 2)) # CostVariable - if mi: - raw = cur.execute( - 'SELECT region, period, tech, vintage, cost FROM main.CostVariable ' - 'WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, tech, vintage, cost FROM main.CostVariable ' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, vintage, cost FROM main.CostVariable', mi=mi) load_element(M.CostVariable, raw, self.viable_rtv, (0, 2, 3)) # CostEmissions (and supporting index set) if self.table_exists('CostEmission'): - if mi: - raw = cur.execute( - 'SELECT region, period, emis_comm from main.CostEmission ' - 'WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - load_element(M.CostEmission_rpe, raw) - - raw = cur.execute( - 'SELECT region, period, emis_comm, cost from main.CostEmission ' - 'WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - load_element(M.CostEmission, raw) - else: - raw = cur.execute( - 'SELECT region, period, emis_comm from main.CostEmission ' - ).fetchall() - load_element(M.CostEmission_rpe, raw) - - raw = cur.execute( - 'SELECT region, period, emis_comm, cost from main.CostEmission ' - ).fetchall() - load_element(M.CostEmission, raw) + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, emis_comm from main.CostEmission', mi=mi) + load_element(M.CostEmission_rpe, raw) + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, emis_comm, cost from main.CostEmission', mi=mi) + load_element(M.CostEmission, raw) # DefaultLoanRate raw = cur.execute( @@ -849,184 +755,82 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # MinCapacity if self.table_exists('MinCapacity'): - if mi: - raw = cur.execute( - 'SELECT region, period, tech, min_cap FROM main.MinCapacity ' - 'WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, tech, min_cap FROM main.MinCapacity ' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, min_cap FROM main.MinCapacity', mi=mi) load_element(M.MinCapacity, raw, self.viable_rt, (0, 2)) # MaxCapacity if self.table_exists('MaxCapacity'): - if mi: - raw = cur.execute( - 'SELECT region, period, tech, max_cap FROM main.MaxCapacity ' - 'WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, tech, max_cap FROM main.MaxCapacity ' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, max_cap FROM main.MaxCapacity', mi=mi) load_element(M.MaxCapacity, raw, self.viable_rt, (0, 2)) # MinNewCap if self.table_exists('MinNewCapacity'): - if mi: - raw = cur.execute( - 'SELECT region, period, tech, min_cap FROM main.MinNewCapacity ' - 'WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, tech, min_cap FROM main.MinNewCapacity ' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, min_cap FROM main.MinNewCapacity', mi=mi) load_element(M.MinNewCapacity, raw, self.viable_rt, (0, 2)) # MaxNewCap if self.table_exists('MaxNewCapacity'): - if mi: - raw = cur.execute( - 'SELECT region, period, tech, max_cap FROM main.MaxNewCapacity ' - 'WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, tech, max_cap FROM main.MaxNewCapacity ' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, max_cap FROM main.MaxNewCapacity', mi=mi) load_element(M.MaxNewCapacity, raw, self.viable_rt, (0, 2)) # MaxCapacityGroup if self.table_exists('MaxCapacityGroup'): - if mi: - raw = cur.execute( - 'SELECT region, period, group_name, max_cap FROM main.MaxCapacityGroup ' - ' WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, group_name, max_cap FROM main.MaxCapacityGroup ' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, group_name, max_cap FROM main.MaxCapacityGroup', mi=mi) load_element(M.MaxCapacityGroup, raw) # MinCapacityGroup if self.table_exists('MinCapacityGroup'): - if mi: - raw = cur.execute( - 'SELECT region, period, group_name, min_cap FROM main.MinCapacityGroup ' - ' WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, group_name, min_cap FROM main.MinCapacityGroup ' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, group_name, min_cap FROM main.MinCapacityGroup', mi=mi) load_element(M.MinCapacityGroup, raw) # MinNewCapacityGroup if self.table_exists('MinNewCapacityGroup'): - if mi: - raw = cur.execute( - 'SELECT region, period, group_name, min_new_cap FROM main.MinNewCapacityGroup ' - ' WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, group_name, min_new_cap FROM main.MinNewCapacityGroup ' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, group_name, min_new_cap FROM main.MinNewCapacityGroup', mi=mi) load_element(M.MinNewCapacityGroup, raw) # MaxNewCapacityGroup if self.table_exists('MaxNewCapacityGroup'): - if mi: - raw = cur.execute( - 'SELECT region, period, group_name, max_new_cap FROM main.MaxNewCapacityGroup ' - ' WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, group_name, max_new_cap FROM main.MaxNewCapacityGroup ' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, group_name, max_new_cap FROM main.MaxNewCapacityGroup', mi=mi) load_element(M.MaxNewCapacityGroup, raw) # MinCapacityShare if self.table_exists('MinCapacityShare'): - raw = cur.execute( - 'SELECT region, period, tech, group_name, min_proportion FROM main.MinCapacityShare' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, group_name, min_proportion FROM main.MinCapacityShare', mi=mi) load_element(M.MinCapacityShare, raw, self.viable_rt, (0, 2)) # MaxCapacityShare if self.table_exists('MaxCapacityShare'): - raw = cur.execute( - 'SELECT region, period, tech, group_name, max_proportion FROM main.MaxCapacityShare' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, group_name, max_proportion FROM main.MaxCapacityShare', mi=mi) load_element(M.MaxCapacityShare, raw, self.viable_rt, (0, 2)) # MinNewCapacityShare if self.table_exists('MinNewCapacityShare'): - raw = cur.execute( - 'SELECT region, period, tech, group_name, max_proportion FROM main.MinNewCapacityShare' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, group_name, max_proportion FROM main.MinNewCapacityShare', mi=mi) load_element(M.MinNewCapacityShare, raw, self.viable_rt, (0, 2)) # MaxNewCapacityShare if self.table_exists('MaxNewCapacityShare'): - raw = cur.execute( - 'SELECT region, period, tech, group_name, max_proportion FROM main.MaxNewCapacityShare' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, group_name, max_proportion FROM main.MaxNewCapacityShare', mi=mi) load_element(M.MaxNewCapacityShare, raw, self.viable_rt, (0, 2)) # MinActivityGroup if self.table_exists('MinActivityGroup'): - if mi: - raw = cur.execute( - 'SELECT region, period, group_name, min_act FROM main.MinActivityGroup ' - ' WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, group_name, min_act FROM main.MinActivityGroup ' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, group_name, min_act FROM main.MinActivityGroup', mi=mi) load_element(M.MinActivityGroup, raw) # MaxActivityGroup if self.table_exists('MaxActivityGroup'): - if mi: - raw = cur.execute( - 'SELECT region, period, group_name, max_act FROM main.MaxActivityGroup ' - ' WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, group_name, max_act FROM main.MaxActivityGroup ' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, group_name, max_act FROM main.MaxActivityGroup', mi=mi) load_element(M.MaxActivityGroup, raw) # MinActivityShare if self.table_exists('MinActivityShare'): - raw = cur.execute( - 'SELECT region, period, tech, group_name, min_proportion FROM main.MinActivityShare' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, group_name, min_proportion FROM main.MinActivityShare', mi=mi) load_element(M.MinActivityShare, raw, self.viable_rt, (0, 2)) # MaxActivityShare if self.table_exists('MaxActivityShare'): - raw = cur.execute( - 'SELECT region, period, tech, group_name, max_proportion FROM main.MaxActivityShare' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, group_name, max_proportion FROM main.MaxActivityShare', mi=mi) load_element(M.MaxActivityShare, raw, self.viable_rt, (0, 2)) # MaxResource @@ -1036,72 +840,32 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # MaxActivity if self.table_exists('MaxActivity'): - if mi: - raw = cur.execute( - 'SELECT region, period, tech, max_act FROM main.MaxActivity ' - 'WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, tech, max_act FROM main.MaxActivity ' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, max_act FROM main.MaxActivity', mi=mi) load_element(M.MaxActivity, raw, self.viable_rt, (0, 2)) # MinActivity if self.table_exists('MinActivity'): - if mi: - raw = cur.execute( - 'SELECT region, period, tech, min_act FROM main.MinActivity ' - 'WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, tech, min_act FROM main.MinActivity ' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, min_act FROM main.MinActivity', mi=mi) load_element(M.MinActivity, raw, self.viable_rt, (0, 2)) # MaxSeasonalActivity if self.table_exists('MaxSeasonalActivity'): - if mi: - raw = cur.execute( - 'SELECT region, period, season, tech, max_act FROM main.MaxSeasonalActivity ' - 'WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, season, tech, max_act FROM main.MaxSeasonalActivity ' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, season, tech, max_act FROM main.MaxSeasonalActivity', mi=mi) load_element(M.MaxSeasonalActivity, raw, self.viable_rt, (0, 3)) # MinSeasonalActivity if self.table_exists('MinSeasonalActivity'): - if mi: - raw = cur.execute( - 'SELECT region, period, season, tech, min_act FROM main.MinSeasonalActivity ' - 'WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, season, tech, min_act FROM main.MinSeasonalActivity ' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, season, tech, min_act FROM main.MinSeasonalActivity', mi=mi) load_element(M.MinSeasonalActivity, raw, self.viable_rt, (0, 3)) # MinAnnualCapacityFactor if self.table_exists('MinAnnualCapacityFactor'): - raw = cur.execute( - 'SELECT region, period, tech, output_comm, factor FROM main.MinAnnualCapacityFactor' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, output_comm, factor FROM main.MinAnnualCapacityFactor', mi=mi) load_element(M.MinAnnualCapacityFactor, raw, self.viable_rt, (0, 2)) # MaxAnnualCapacityFactor if self.table_exists('MaxAnnualCapacityFactor'): - raw = cur.execute( - 'SELECT region, period, tech, output_comm, factor FROM main.MaxAnnualCapacityFactor' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, output_comm, factor FROM main.MaxAnnualCapacityFactor', mi=mi) load_element(M.MaxAnnualCapacityFactor, raw, self.viable_rt, (0, 2)) # GrowthRateMax @@ -1116,47 +880,25 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # EmissionLimit if self.table_exists('EmissionLimit'): - if mi: - raw = cur.execute( - 'SELECT region, period, emis_comm, value FROM main.EmissionLimit ' - 'WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, emis_comm, value FROM main.EmissionLimit ' - ).fetchall() - + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, emis_comm, value FROM main.EmissionLimit', mi=mi) load_element(M.EmissionLimit, raw) # EmissionActivity # The current emission constraint screens by valid inputs, so if it is NOT # built in a particular region, this should still be OK if self.table_exists('EmissionActivity'): - if mi: - raw = cur.execute( - 'SELECT region, emis_comm, input_comm, tech, vintage, output_comm, activity ' - 'FROM main.EmissionActivity ' - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, emis_comm, input_comm, tech, vintage, output_comm, activity ' - 'FROM main.EmissionActivity ' - ).fetchall() + raw = cur.execute( + 'SELECT region, emis_comm, input_comm, tech, vintage, output_comm, activity ' + 'FROM main.EmissionActivity ' + ).fetchall() load_element(M.EmissionActivity, raw, self.viable_ritvo, (0, 2, 3, 4, 5)) # EmissionEmbodied if self.table_exists('EmissionEmbodied'): - if mi: - raw = cur.execute( - 'SELECT region, emis_comm, tech, vintage, value ' - 'FROM main.EmissionEmbodied' - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, emis_comm, tech, vintage, value ' - 'FROM main.EmissionEmbodied' - ).fetchall() + raw = cur.execute( + 'SELECT region, emis_comm, tech, vintage, value ' + 'FROM main.EmissionEmbodied' + ).fetchall() load_element(M.EmissionEmbodied, raw, self.viable_rtv, (0, 2, 3)) @@ -1199,16 +941,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # CapacityCredit if self.table_exists('CapacityCredit'): - if mi: - raw = cur.execute( - 'SELECT region, period, tech, vintage, credit FROM main.CapacityCredit ' - 'WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, period, tech, vintage, credit FROM main.CapacityCredit ' - ).fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, vintage, credit FROM main.CapacityCredit', mi=mi) load_element(M.CapacityCredit, raw, self.viable_rtv, (0, 2, 3)) # PlanningReserveMargin @@ -1223,7 +956,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # StorageFraction if self.table_exists('StorageFraction'): - raw = cur.execute('SELECT region, period, season, tod, tech, vintage, frac FROM main.StorageFraction').fetchall() + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, season, tod, tech, vintage, frac FROM main.StorageFraction', mi=mi) load_element(M.StorageFraction, raw, self.viable_rtv, (0,4,5)) # For T/S: dump the size of all data elements into the log @@ -1237,6 +970,15 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): self.data = data return data + + def raw_check_mi_period(self, cur: Cursor, qry: str, mi: MyopicIndex | None = None) -> list: + if mi: + return cur.execute( + qry + ' WHERE period >= ? AND period <= ?', + (mi.base_year, mi.last_demand_year), + ).fetchall() + else: + return cur.execute(qry).fetchall() def load_param_idx_sets(self, data: dict) -> dict: """ diff --git a/temoa/temoa_model/table_writer.py b/temoa/temoa_model/table_writer.py index c5521ff12..19cc021d3 100644 --- a/temoa/temoa_model/table_writer.py +++ b/temoa/temoa_model/table_writer.py @@ -107,7 +107,7 @@ def write_results( self, M: TemoaModel, results_with_duals: SolverResults | None = None, - save_storage_levels: bool = True, + save_storage_levels: bool = False, append=False, iteration: int | None = None, ) -> None: @@ -125,8 +125,6 @@ def write_results( self._set_tech_sectors() self.write_objective(M, iteration=iteration) self.write_capacity_tables(M, iteration=iteration) - if save_storage_levels: - self.write_storage_level(M, iteration=iteration) # analyze the emissions to get the costs and flows if self.config.scenario_mode == TemoaMode.MYOPIC: p_0 = M.MyopicBaseyear @@ -142,6 +140,8 @@ def write_results( self.write_flow_tables(iteration=iteration) if results_with_duals: # write the duals self.write_dual_variables(results_with_duals, iteration=iteration) + if save_storage_levels: + self.write_storage_level(M, iteration=iteration) # catch-all self.con.commit() self.con.execute('VACUUM') @@ -245,7 +245,7 @@ def write_storage_level(self, M: TemoaModel, iteration=None) -> None: tech TEXT REFERENCES Technology (tech), vintage INTEGER REFERENCES TimePeriod (period), level REAL, - PRIMARY KEY (region, scenario, period, season, tod, tech, vintage) + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) );""" ) @@ -358,6 +358,7 @@ def write_flow_tables(self, iteration=None) -> None: if iteration is not None else self.config.scenario ) + for fi in self.flow_register: sector = self.tech_sectors.get(fi.t) for flow_type in self.flow_register[fi]: diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index fffbd64d9..d70d70878 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1482,7 +1482,7 @@ def RampDown_Constraint(M: 'TemoaModel', r, p, s, d, t, v): logger.warning(msg.format(r, t, s, d, s_next, d_next)) return Constraint.Skip - activity_decrease = activity_sd - activity_sd_next # opposite sign from rampdown + activity_decrease = activity_sd - activity_sd_next # opposite sign from rampup rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * M.ProcessLifeFrac[r, p, t, v] expr = activity_decrease <= rampable_activity diff --git a/tests/test_storage.py b/tests/test_storage.py index 906795463..c7376ae28 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -16,10 +16,6 @@ from temoa.temoa_model.temoa_mode import TemoaMode from temoa.temoa_model.temoa_model import TemoaModel from temoa.temoa_model.temoa_sequencer import TemoaSequencer -from temoa.temoa_model.temoa_rules import ( - link_season_next_timeslice, - loop_season_next_timeslice -) logger = logging.getLogger(__name__) # suitable scenarios for storage testing....singleton for now. @@ -93,8 +89,7 @@ def test_state_sequencing(system_test_run): for S_i in model.ProcessInputsByOutput[r, p, t, v, S_o] ) - if model.link_seasons: s_next, d_next = link_season_next_timeslice(model, s, d) - else: s_next, d_next = loop_season_next_timeslice(model, s, d) + s_next, d_next = model.time_next[s, d] state = model.V_StorageLevel[r, p, s, d, t, v].value next_state = model.V_StorageLevel[r, p, s_next, d_next, t, v].value diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index 1af83d686..9b951fa4a 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -610,7 +610,7 @@ CREATE TABLE StorageFraction tech TEXT REFERENCES Technology (tech), vintage INTEGER REFERENCES TimePeriod (period), frac REAL, - notes TEXT + notes TEXT, PRIMARY KEY (region, period, season, tod, tech, vintage) ); INSERT INTO StorageFraction VALUES('electricville',2025,'s1','d1','batt',2025,0.5,''); From b14a4630d442c43abfb7035cd8bdb48e42f51b09 Mon Sep 17 00:00:00 2001 From: idelder <35704891+idelder@users.noreply.github.com> Date: Fri, 5 Sep 2025 12:15:11 -0400 Subject: [PATCH 026/587] Merge interim CANOE changes prior to latest major Temoa/main branch changes (#106) Summary by jdecarolis: Keep observed changes: - Correct 'dds' to 'dsd' - Add max / min constraints on seasonal activity - Fix amortized capex costs in obj function, which were not properly indexed over lifetime - Fix accounting of variable and emissions costs as noted in GH Issue #90 - TechInput/OutputSplit constraints: fix summation over commodity inputs - Add TechInput/OutputSplit constraints for variable techs with annual share constraints - Add CANOE sql template ---- original commit messages: * Update run_actions.py Adds excel outputs for completed runs * update run_actions * Added SeasonalActivity constraints * Fixed bugs in objective function. Fixed bugs in emissions accounting * Fix mistake in results output for annual emissions * Fix TechInputSplit constraint summation * Fix variable and emissions costs in temoa_rules * Fix variable and emissions costs in table_writer * Change to TechXputSplitAverage implementation removing tech_variable set (#3) * Change to TechXputSplitAverage implementation removing tech_variable set * Fix techsplitaverage update * Remove print statement... --------- Co-authored-by: Davey Elder * Uploaded canoe schema Added techoutputsplitaverage table, removed tech variable in technology table and added data_flags table to allow for easier filtering * Merge latest Temoa 3 into CANOE * Updating tests to CANOE changes so all pass * Renaming SplitAverage tables to SplitAnnual and squash dds --------- Co-authored-by: CANOE-main Co-authored-by: Davey Elder --- data_files/example_dbs/morris_utopia.sql | 8 +- data_files/example_dbs/stepped_demand.sql | 8 +- data_files/example_dbs/test_system.sql | 4 +- data_files/example_dbs/utopia.sql | 8 +- temoa/temoa_model/hybrid_loader.py | 83 +++++++-- temoa/temoa_model/run_actions.py | 6 +- temoa/temoa_model/table_data_puller.py | 2 + temoa/temoa_model/table_writer.py | 4 +- temoa/temoa_model/temoa_initialize.py | 69 ++++++-- temoa/temoa_model/temoa_model.py | 37 +++- temoa/temoa_model/temoa_rules.py | 166 ++++++++++++++++-- tests/test_table_writer.py | 8 +- tests/testing_configs/config_emissions.toml | 4 +- tests/testing_configs/config_link_test.toml | 4 +- tests/testing_configs/config_mediumville.toml | 4 +- .../testing_configs/config_storageville.toml | 4 +- tests/testing_configs/config_test_system.toml | 4 +- tests/testing_configs/config_utopia.toml | 4 +- .../testing_configs/config_utopia_myopic.toml | 4 +- tests/testing_data/emissions.sql | 8 +- tests/testing_data/mediumville.sql | 10 +- tests/testing_data/mediumville_sets.json | 6 +- tests/testing_data/simple_linked_tech.sql | 8 +- tests/testing_data/storageville.sql | 8 +- tests/testing_data/test_system.sql | 8 +- tests/testing_data/test_system_sets.json | 4 +- tests/testing_data/utopia.sql | 60 ++++--- tests/testing_data/utopia_sets.json | 4 +- 28 files changed, 413 insertions(+), 134 deletions(-) diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index 9eb1b62b8..be83fff42 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -320,10 +320,10 @@ CREATE TABLE DemandSpecificDistribution REFERENCES TimeOfDay (tod), demand_name TEXT REFERENCES Commodity (name), - dds REAL, - dds_notes TEXT, + dsd REAL, + dsd_notes TEXT, PRIMARY KEY (region, season, tod, demand_name), - CHECK (dds >= 0 AND dds <= 1) + CHECK (dsd >= 0 AND dsd <= 1) ); INSERT INTO DemandSpecificDistribution VALUES('utopia','inter','night','RH',0.06,''); INSERT INTO DemandSpecificDistribution VALUES('utopia','winter','day','RH',0.54669999999999996376,''); @@ -796,7 +796,7 @@ CREATE TABLE TechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechInputSplitAverage +CREATE TABLE TechInputSplitAnnual ( region TEXT, period INTEGER diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index 6b6fce42d..a6acd8b4f 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -273,10 +273,10 @@ CREATE TABLE DemandSpecificDistribution REFERENCES TimeOfDay (tod), demand_name TEXT REFERENCES Commodity (name), - dds REAL, - dds_notes TEXT, + dsd REAL, + dsd_notes TEXT, PRIMARY KEY (region, season, tod, demand_name), - CHECK (dds >= 0 AND dds <= 1) + CHECK (dsd >= 0 AND dsd <= 1) ); INSERT INTO DemandSpecificDistribution VALUES('electricville','inter','day','RL',0.3332999999999999852,''); INSERT INTO DemandSpecificDistribution VALUES('electricville','summer','day','RL',0.3332999999999999852,''); @@ -1007,7 +1007,7 @@ CREATE TABLE TechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechInputSplitAverage +CREATE TABLE TechInputSplitAnnual ( region TEXT, period INTEGER diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index 35767f2af..2370d6d85 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -727,8 +727,8 @@ CREATE TABLE "DemandSpecificDistribution" ( "season_name" text, "time_of_day_name" text, "demand_name" text, - "dds" real CHECK("dds" >= 0 AND "dds" <= 1), - "dds_notes" text, + "dsd" real CHECK("dsd" >= 0 AND "dsd" <= 1), + "dsd_notes" text, PRIMARY KEY("regions","season_name","time_of_day_name","demand_name"), FOREIGN KEY("time_of_day_name") REFERENCES "time_of_day"("t_day"), FOREIGN KEY("season_name") REFERENCES "time_season"("t_season"), diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 704867bb6..d25e031ad 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -428,10 +428,10 @@ CREATE TABLE DemandSpecificDistribution REFERENCES TimeOfDay (tod), demand_name TEXT REFERENCES Commodity (name), - dds REAL, - dds_notes TEXT, + dsd REAL, + dsd_notes TEXT, PRIMARY KEY (region, season, tod, demand_name), - CHECK (dds >= 0 AND dds <= 1) + CHECK (dsd >= 0 AND dsd <= 1) ); INSERT INTO DemandSpecificDistribution VALUES('utopia','inter','day','RH',0.1199999999999999956,''); INSERT INTO DemandSpecificDistribution VALUES('utopia','inter','night','RH',0.05999999999999999778,''); @@ -984,7 +984,7 @@ CREATE TABLE TechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechInputSplitAverage +CREATE TABLE TechInputSplitAnnual ( region TEXT, period INTEGER diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 5963433ab..e95909c1a 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -489,10 +489,6 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): raw = cur.execute('SELECT tech FROM Technology WHERE annual > 0').fetchall() load_element(M.tech_annual, raw, self.viable_techs) - # tech_variable - raw = cur.execute('SELECT tech FROM Technology WHERE variable > 0').fetchall() - load_element(M.tech_variable, raw, self.viable_techs) - # tech_retirement raw = cur.execute('SELECT tech FROM Technology WHERE retire > 0').fetchall() load_element(M.tech_retirement, raw, self.viable_techs) @@ -568,7 +564,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # DemandSpecificDistribution raw = cur.execute( - 'SELECT region, season, tod, demand_name, dds FROM main.DemandSpecificDistribution' + 'SELECT region, season, tod, demand_name, dsd FROM main.DemandSpecificDistribution' ).fetchall() load_element(M.DemandSpecificDistribution, raw) @@ -648,21 +644,21 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): ic, ) - # TechInputSplitAverage - if self.table_exists('TechInputSplitAverage'): + # TechInputSplitAnnual + if self.table_exists('TechInputSplitAnnual'): if mi: raw = cur.execute( 'SELECT region, period, input_comm, tech, min_proportion ' - 'FROM main.TechInputSplitAverage ' + 'FROM main.TechInputSplitAnnual ' 'WHERE period >= ? AND period <= ?', (mi.base_year, mi.last_demand_year), ).fetchall() else: raw = cur.execute( 'SELECT region, period, input_comm, tech, min_proportion ' - 'FROM main.TechInputSplitAverage ' + 'FROM main.TechInputSplitAnnual ' ).fetchall() - loaded = load_element(M.TechInputSplitAverage, raw, self.viable_rpit, (0, 1, 2, 3)) + loaded = load_element(M.TechInputSplitAnnual, raw, self.viable_rpit, (0, 1, 2, 3)) # we need to see if anything was filtered out here and raise warning if so as it may have invalidated # a blending process and any missing items should be reviewed if len(loaded) < len(raw): @@ -670,7 +666,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): for item in sorted(missing, key=lambda x: (x[0], x[1], x[3], x[2])): region, period, ic, tech, _ = item logger.warning( - 'Technology Input Split requirement in region %s, period %d for tech %s with input' + 'Technology Input Split Annual requirement in region %s, period %d for tech %s with input' 'commodity %s has ' 'been removed because the tech path with that input is ' 'invalid/not available/orphan. See the other warnings for this TECH in ' @@ -701,7 +697,40 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): logger.warning( 'Technology Output Split requirement in region %s, period %d for tech %s with output' 'commodity %s has ' - 'been removed because the tech path with that input is ' + 'been removed because the tech path with that output is ' + 'invalid/not available/orphan. See the other warnings for this TECH in ' + 'this region-period, and check for availability of all components in data.', + region, + period, + tech, + oc, + ) + + # TechOutputSplitAnnual + if self.table_exists('TechOutputSplitAnnual'): + if mi: + raw = cur.execute( + 'SELECT region, period, tech, output_comm, min_proportion ' + 'FROM main.TechOutputSplitAnnual ' + 'WHERE period >= ? AND period <= ?', + (mi.base_year, mi.last_demand_year), + ).fetchall() + else: + raw = cur.execute( + 'SELECT region, period, tech, output_comm, min_proportion ' + 'FROM main.TechOutputSplitAnnual ' + ).fetchall() + loaded = load_element(M.TechOutputSplitAnnual, raw, self.viable_rpto, (0, 1, 2, 3)) + # we need to see if anything was filtered out here and raise warning if so as it may have invalidated + # a blending process and any missing items should be reviewed + if len(loaded) < len(raw): + missing = set(raw) - set(loaded) + for item in sorted(missing): + region, period, tech, oc, _ = item + logger.warning( + 'Technology Output Split Annual requirement in region %s, period %d for tech %s with output' + 'commodity %s has ' + 'been removed because the tech path with that output is ' 'invalid/not available/orphan. See the other warnings for this TECH in ' 'this region-period, and check for availability of all components in data.', region, @@ -1022,6 +1051,34 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): ).fetchall() load_element(M.MinActivity, raw, self.viable_rt, (0, 2)) + # MaxSeasonalActivity + if self.table_exists('MaxSeasonalActivity'): + if mi: + raw = cur.execute( + 'SELECT region, period, season, tech, max_act FROM main.MaxSeasonalActivity ' + 'WHERE period >= ? AND period <= ?', + (mi.base_year, mi.last_demand_year), + ).fetchall() + else: + raw = cur.execute( + 'SELECT region, period, season, tech, max_act FROM main.MaxSeasonalActivity ' + ).fetchall() + load_element(M.MaxSeasonalActivity, raw, self.viable_rt, (0, 3)) + + # MinSeasonalActivity + if self.table_exists('MinSeasonalActivity'): + if mi: + raw = cur.execute( + 'SELECT region, period, season, tech, min_act FROM main.MinSeasonalActivity ' + 'WHERE period >= ? AND period <= ?', + (mi.base_year, mi.last_demand_year), + ).fetchall() + else: + raw = cur.execute( + 'SELECT region, period, season, tech, min_act FROM main.MinSeasonalActivity ' + ).fetchall() + load_element(M.MinSeasonalActivity, raw, self.viable_rt, (0, 3)) + # MinAnnualCapacityFactor if self.table_exists('MinAnnualCapacityFactor'): raw = cur.execute( @@ -1182,6 +1239,7 @@ def load_param_idx_sets(self, data: dict) -> dict: M.CostInvest.name: M.CostInvest_rtv.name, M.EmissionLimit.name: M.EmissionLimitConstraint_rpe.name, M.MaxActivity.name: M.MaxActivityConstraint_rpt.name, + M.MaxSeasonalActivity.name: M.MaxSeasonalActivityConstraint_rpst.name, M.MaxActivityGroup.name: M.MaxActivityGroup_rpg.name, M.MaxActivityShare.name: M.MaxActivityShareConstraint_rptg.name, M.MaxAnnualCapacityFactor.name: M.MaxAnnualCapacityFactorConstraint_rpto.name, @@ -1193,6 +1251,7 @@ def load_param_idx_sets(self, data: dict) -> dict: M.MaxNewCapacityShare.name: M.MaxNewCapacityShareConstraint_rptg.name, M.MaxResource.name: M.MaxResourceConstraint_rt.name, M.MinActivity.name: M.MinActivityConstraint_rpt.name, + M.MinSeasonalActivity.name: M.MinSeasonalActivityConstraint_rpst.name, M.MinActivityGroup.name: M.MinActivityGroup_rpg.name, M.MinActivityShare.name: M.MinActivityShareConstraint_rptg.name, M.MinAnnualCapacityFactor.name: M.MinAnnualCapacityFactorConstraint_rpto.name, diff --git a/temoa/temoa_model/run_actions.py b/temoa/temoa_model/run_actions.py index 17f083d5d..8d737d81d 100644 --- a/temoa/temoa_model/run_actions.py +++ b/temoa/temoa_model/run_actions.py @@ -245,7 +245,11 @@ def solve_instance( optimizer.options['feasopt tolerance'] = 1.0e-6 elif solver_name == 'gurobi': - pass + # Note: these parameter values are taken to be the same as those in PyPSA (see: https://pypsa-eur.readthedocs.io/en/latest/configuration.html) + optimizer.options["Method"] = 2 # barrier + optimizer.options["Crossover"] = 0 # non basic solution, ie no crossover + optimizer.options["BarConvTol"] = 1.e-5 + optimizer.options["FeasibilityTol"] = 1.e-6 elif solver_name == 'appsi_highs': pass diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index 4301662cb..3a2ad85a1 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -385,6 +385,7 @@ def loan_costs( invest_cost, loan_annualize=loan_ar, lifetime_loan_process=loan_life, + lifetime_process=process_life, P_0=p_0, P_e=p_e, GDR=global_discount_rate, @@ -397,6 +398,7 @@ def loan_costs( invest_cost, loan_annualize=loan_ar, lifetime_loan_process=loan_life, + lifetime_process=process_life, P_0=p_0, P_e=p_e, GDR=global_discount_rate, diff --git a/temoa/temoa_model/table_writer.py b/temoa/temoa_model/table_writer.py index 7e97b6bf0..1992f3c9d 100644 --- a/temoa/temoa_model/table_writer.py +++ b/temoa/temoa_model/table_writer.py @@ -401,7 +401,6 @@ def check_flow_balance(self, M: TemoaModel) -> bool: flost = flows[fi][FlowType.LOST] # some identifiers tech = fi.t - var_tech = fi.t in M.tech_variable flex_tech = fi.t in M.tech_flex annual_tech = fi.t in M.tech_annual @@ -418,9 +417,8 @@ def check_flow_balance(self, M: TemoaModel) -> bool: 'Flow balance check failed for index: %s, delta: %0.2f', fi, deltas[fi] ) logger.info( - 'Tech: %s, Var: %s, Flex: %s, Annual: %s', + 'Tech: %s, Flex: %s, Annual: %s', tech, - var_tech, flex_tech, annual_tech, ) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 252bc7aea..76b959209 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -685,13 +685,13 @@ def CreateSparseDicts(M: 'TemoaModel'): t, ) not in M.inputsplitVintages: M.inputsplitVintages[r, p, i, t] = set() - if (r, p, i, t) in M.TechInputSplitAverage.sparse_iterkeys() and ( + if (r, p, i, t) in M.TechInputSplitAnnual.sparse_iterkeys() and ( r, p, i, t, - ) not in M.inputsplitaverageVintages: - M.inputsplitaverageVintages[r, p, i, t] = set() + ) not in M.inputsplitannualVintages: + M.inputsplitannualVintages[r, p, i, t] = set() if (r, p, t, o) in M.TechOutputSplit.sparse_iterkeys() and ( r, p, @@ -699,6 +699,13 @@ def CreateSparseDicts(M: 'TemoaModel'): o, ) not in M.outputsplitVintages: M.outputsplitVintages[r, p, t, o] = set() + if (r, p, t, o) in M.TechOutputSplitAnnual.sparse_iterkeys() and ( + r, + p, + t, + o, + ) not in M.outputsplitannualVintages: + M.outputsplitannualVintages[r, p, t, o] = set() if t in M.tech_resource and (r, p, o) not in M.ProcessByPeriodAndOutput: M.ProcessByPeriodAndOutput[r, p, o] = set() if t in M.tech_reserve and (r, p) not in M.processReservePeriods: @@ -732,10 +739,12 @@ def CreateSparseDicts(M: 'TemoaModel'): M.rampVintages[r, p, t].add(v) if (r, p, i, t) in M.TechInputSplit.sparse_iterkeys(): M.inputsplitVintages[r, p, i, t].add(v) - if (r, p, i, t) in M.TechInputSplitAverage.sparse_iterkeys(): - M.inputsplitaverageVintages[r, p, i, t].add(v) + if (r, p, i, t) in M.TechInputSplitAnnual.sparse_iterkeys(): + M.inputsplitannualVintages[r, p, i, t].add(v) if (r, p, t, o) in M.TechOutputSplit.sparse_iterkeys(): M.outputsplitVintages[r, p, t, o].add(v) + if (r, p, t, o) in M.TechOutputSplitAnnual.sparse_iterkeys(): + M.outputsplitannualVintages[r, p, t, o].add(v) if t in M.tech_resource: M.ProcessByPeriodAndOutput[r, p, o].add((i, t, v)) if t in M.tech_reserve: @@ -1295,11 +1304,22 @@ def TechInputSplitConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, s, d, i, t, v) for r, p, i, t in M.inputsplitVintages.keys() - if t not in M.tech_annual and t not in M.tech_variable + if t not in M.tech_annual for v in M.inputsplitVintages[r, p, i, t] for s in M.time_season for d in M.time_of_day ) + ann_indices = set( + (r, p, i, t) + for r, p, i, t in M.inputsplitVintages.keys() + if t in M.tech_annual + ) + if len(ann_indices) > 0: + msg = ( + "Warning: Annual technologies included in TechInputSplit table. " + "Use TechInputSplitAnnual table instead or these constraints will be ignored: {}" + ) + logger.warning(msg.format(ann_indices)) return indices @@ -1307,9 +1327,9 @@ def TechInputSplitConstraintIndices(M: 'TemoaModel'): def TechInputSplitAnnualConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, i, t, v) - for r, p, i, t in M.inputsplitVintages.keys() + for r, p, i, t in M.inputsplitannualVintages.keys() if t in M.tech_annual - for v in M.inputsplitVintages[r, p, i, t] + for v in M.inputsplitannualVintages[r, p, i, t] ) return indices @@ -1318,9 +1338,9 @@ def TechInputSplitAnnualConstraintIndices(M: 'TemoaModel'): def TechInputSplitAverageConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, i, t, v) - for r, p, i, t in M.inputsplitaverageVintages.keys() - if t in M.tech_variable - for v in M.inputsplitaverageVintages[r, p, i, t] + for r, p, i, t in M.inputsplitannualVintages.keys() + if t not in M.tech_annual + for v in M.inputsplitannualVintages[r, p, i, t] ) return indices @@ -1334,6 +1354,17 @@ def TechOutputSplitConstraintIndices(M: 'TemoaModel'): for s in M.time_season for d in M.time_of_day ) + ann_indices = set( + (r, p, t, o) + for r, p, t, o in M.outputsplitVintages.keys() + if t in M.tech_annual + ) + if len(ann_indices) > 0: + msg = ( + "Warning: Annual technologies included in TechOutputSplit table. " + "Use TechOutputSplitAnnual table instead or these constraints will be ignored: {}" + ) + logger.warning(msg.format(ann_indices)) return indices @@ -1341,14 +1372,24 @@ def TechOutputSplitConstraintIndices(M: 'TemoaModel'): def TechOutputSplitAnnualConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, t, v, o) - for r, p, t, o in M.outputsplitVintages.keys() - if t in M.tech_annual and t not in M.tech_variable - for v in M.outputsplitVintages[r, p, t, o] + for r, p, t, o in M.outputsplitannualVintages.keys() + if t in M.tech_annual + for v in M.outputsplitannualVintages[r, p, t, o] ) return indices +def TechOutputSplitAverageConstraintIndices(M: 'TemoaModel'): + indices = set( + (r, p, t, v, o) + for r, p, t, o in M.outputsplitannualVintages.keys() + if t not in M.tech_annual + for v in M.outputsplitannualVintages[r, p, t, o] + ) + return indices + + def get_loan_life(M, r, t, _): return M.LoanLifetimeTech[r, t] diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index a602e3ab8..c54bd3320 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -105,8 +105,9 @@ def __init__(M, *args, **kwargs): M.storageVintages = dict() M.rampVintages = dict() M.inputsplitVintages = dict() - M.inputsplitaverageVintages = dict() + M.inputsplitannualVintages = dict() M.outputsplitVintages = dict() + M.outputsplitannualVintages = dict() M.ProcessByPeriodAndOutput = dict() M.exportRegions = dict() M.importRegions = dict() @@ -167,10 +168,6 @@ def __init__(M, *args, **kwargs): # the below is a convenience for domain checking in params below that should not accept uncap techs... M.tech_with_capacity = Set(initialize=M.tech_all - M.tech_uncap) """techs eligible for capacitization""" - - # Define techs for use with TechInputSplitAverage constraint, - # where techs have variable annual output but the user wishes to constrain them annually - M.tech_variable = Set(within=M.tech_all) # Define techs for which economic retirement is an option # Note: Storage techs cannot (currently) be retired due to linkage to initialization # process, which is currently incapable of reducing initializations on retirements. @@ -298,10 +295,9 @@ def __init__(M, *args, **kwargs): M.LoanLifetimeProcess = Param(M.LoanLifetimeProcess_rtv, default=get_loan_life) M.TechInputSplit = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all) - M.TechInputSplitAverage = Param( - M.regions, M.time_optimize, M.commodity_physical, M.tech_variable - ) + M.TechInputSplitAnnual = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all) M.TechOutputSplit = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier) + M.TechOutputSplitAnnual = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier) M.RenewablePortfolioStandardConstraint_rpg = Set( within=M.regions * M.time_optimize * M.tech_group_names @@ -374,6 +370,16 @@ def __init__(M, *args, **kwargs): ) M.MinActivity = Param(M.MinActivityConstraint_rpt) + M.MaxSeasonalActivityConstraint_rpst = Set( + within=M.RegionalGlobalIndices * M.time_optimize * M.time_season * M.tech_all + ) + M.MaxSeasonalActivity = Param(M.MaxSeasonalActivityConstraint_rpst) + + M.MinSeasonalActivityConstraint_rpst = Set( + within=M.RegionalGlobalIndices * M.time_optimize * M.time_season * M.tech_all + ) + M.MinSeasonalActivity = Param(M.MinSeasonalActivityConstraint_rpst) + M.MinAnnualCapacityFactorConstraint_rpto = Set( within=M.RegionalGlobalIndices * M.time_optimize * M.tech_all * M.commodity_carrier ) @@ -682,6 +688,14 @@ def __init__(M, *args, **kwargs): M.MinActivityConstraint_rpt, rule=MinActivity_Constraint ) + M.MaxSeasonalActivityConstraint = Constraint( + M.MaxSeasonalActivityConstraint_rpst, rule=MaxSeasonalActivity_Constraint + ) + + M.MinSeasonalActivityConstraint = Constraint( + M.MinSeasonalActivityConstraint_rpst, rule=MinSeasonalActivity_Constraint + ) + M.MinActivityGroupConstraint = Constraint( M.MinActivityGroup_rpg, rule=MinActivityGroup_Constraint ) @@ -797,6 +811,13 @@ def __init__(M, *args, **kwargs): M.TechOutputSplitAnnualConstraint_rptvo, rule=TechOutputSplitAnnual_Constraint ) + M.TechOutputSplitAverageConstraint_rptvo = Set( + dimen=5, initialize=TechOutputSplitAverageConstraintIndices + ) + M.TechOutputSplitAverageConstraint = Constraint( + M.TechOutputSplitAverageConstraint_rptvo, rule=TechOutputSplitAverage_Constraint + ) + M.RenewablePortfolioStandardConstraint = Constraint( M.RenewablePortfolioStandardConstraint_rpg, rule=RenewablePortfolioStandard_Constraint ) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index ae8561292..42acf8795 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -378,6 +378,7 @@ def loan_cost( invest_cost: float, loan_annualize: float, lifetime_loan_process: float | int, + lifetime_process: int, P_0: int, P_e: int, GDR: float, @@ -397,9 +398,9 @@ def loan_cost( :return: fixed number or pyomo expression based on input types """ if GDR == 0: # return the non-discounted result - regular_payment = capacity * invest_cost * loan_annualize - payments_made = min(lifetime_loan_process, P_e - vintage) - return regular_payment * payments_made + annuity = capacity * invest_cost * loan_annualize * lifetime_loan_process / lifetime_process + payments_made = min(lifetime_process, P_e - vintage) + return annuity * payments_made x = 1 + GDR # a convenience res = ( capacity @@ -413,8 +414,8 @@ def loan_cost( ) ) * ( - (1 - x ** (-min(lifetime_loan_process, P_e - vintage))) - / (1 - x ** (-lifetime_loan_process)) + (1 - x ** (-min(lifetime_process, P_e - vintage))) + / (1 - x ** (-lifetime_process)) ) ) return res @@ -466,6 +467,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): M.CostInvest[r, S_t, S_v], M.LoanAnnualize[r, S_t, S_v], value(M.LoanLifetimeProcess[r, S_t, S_v]), + value(M.LifetimeProcess[r, S_t, S_v]), P_0, P_e, GDR, @@ -492,7 +494,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): fixed_or_variable_cost( M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, S_o], M.CostVariable[r, p, S_t, S_v], - MPL[r, p, S_t, S_v], + M.PeriodLength[p], GDR, P_0, p, @@ -509,7 +511,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): fixed_or_variable_cost( M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, S_o], M.CostVariable[r, p, S_t, S_v], - MPL[r, p, S_t, S_v], + M.PeriodLength[p], GDR, P_0, p, @@ -555,7 +557,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): fixed_or_variable_cost( cap_or_flow=M.V_FlowOut[r, p, s, d, i, t, v, o] * M.EmissionActivity[r, e, i, t, v, o], cost_factor=M.CostEmission[r, p, e], - process_lifetime=MPL[r, p, t, v], + process_lifetime=M.PeriodLength[p], GDR=GDR, P_0=P_0, p=p, @@ -572,7 +574,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): fixed_or_variable_cost( cap_or_flow=M.V_FlowOutAnnual[r, p, i, t, v, o] * M.EmissionActivity[r, e, i, t, v, o], cost_factor=M.CostEmission[r, p, e], - process_lifetime=MPL[r, p, t, v], + process_lifetime=M.PeriodLength[p], GDR=GDR, P_0=P_0, p=p, @@ -1991,6 +1993,60 @@ def MaxActivity_Constraint(M: 'TemoaModel', r, p, t): return expr +def MaxSeasonalActivity_Constraint(M: 'TemoaModel', r, p, s, t): + + r""" + The MaxSeasonalActivity sets an upper bound on the activity from a specific technology. + Note that the indices for these constraints are region, period, season, and tech. + The first component of the constraint pertains to technologies with + variable output at the time slice level, and the second component pertains to + technologies with constant annual output belonging to the :code:`tech_annual` + set. + .. math:: + :label: MaxSeasonalActivity + \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le MAXSSNACT_{r, p, s, t} + \forall \{r, p, s, t\} \in \Theta_{\text{MaxSeasonalActivity}} + \sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \le MAXSSNACT_{r, p, s, t} + \forall \{r, p, s, t \in T^{a}\} \in \Theta_{\text{MaxSeasonalActivity}} + """ + + # Notice that this constraint follows the implementation of the + # MaxActivity_Constraint(). The difference is that this function is defined + # over each representative day, or "season", as opposed to the entire + # year, or "period". + + # The V_FlowOut variable is scaled by the weights of each representative day. + # In order to determine the daily, or "seasonal", flow, the V_FLowOut variable + # must be converted back to its un-scaled value. We do this by dividing the + # V_FlowOut value by M.SegFrac[s, d]*365*24. + + try: + activity_rpst = sum( + M.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] / (M.SegFrac[s, d]*365*24) + 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 d in M.time_of_day + ) + except: + msg = ( + "\nWarning: MaxSeasonalActivity constraint can not be defined for " + "technologies in \"tech_annual\". Continuing by ignoring the constraint " + "for '%s'.\n " + ) + SE.write(msg % (t)) + return Constraint.Skip + + max_act = value(M.MaxSeasonalActivity[r, p, s, t]) + expr = activity_rpst <= max_act + + # in the case that there is nothing to sum, skip + if isinstance(expr, bool): # an empty list was generated + return Constraint.Skip + + return expr + + def MinActivity_Constraint(M: 'TemoaModel', r, p, t): r""" @@ -2053,6 +2109,60 @@ def MinActivity_Constraint(M: 'TemoaModel', r, p, t): return expr +def MinSeasonalActivity_Constraint(M: 'TemoaModel', r, p, s, t): + + r""" + The MinSeasonalActivity sets a lower bound on the activity from a specific technology + over a specific season. Note that the indices for these constraints are region, + period, season and tech, not tech and vintage. The first version of the constraint + pertains to technologies with variable output at the time slice level, and the + second version pertains to technologies with constant annual output belonging to + the :code:`tech_annual` set. + .. math:: + :label: MinSeasonalActivity + \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \ge MINSSNACT_{r, p, t} + \forall \{r, p, s, t\} \in \Theta_{\text{MinSeasonalActivity}} + \sum_{I,V,O} \textbf{FOA}_{r, p, s, i, t, v, o} \ge MINSSNACT_{r, p, s, t} + \forall \{r, p, s, t \in T^{a}\} \in \Theta_{\text{MinSeasonalActivity}} + """ + + # Notice that this constraint follows the implementation of the + # MinActivity_Constraint(). The difference is that this function is defined + # over each representative day, or "season", as opposed to the entire + # year, or "period". + + # The V_FlowOut variable is scaled by the weights of each representative day. + # In order to determine the daily, or "seasonal", flow, the V_FLowOut variable + # must be converted back to its un-scaled value. We do this using the + # weighting_factor below: + + try: + activity_rpst = sum( + M.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] / (M.SegFrac[s, d]*365*24) + 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 d in M.time_of_day + ) + except: + msg = ( + "\nWarning: MinSeasonalActivity constraint can not be defined for " + "technologies in \"tech_annual\". Continuing by ignoring the constraint " + "for '%s'.\n " + ) + SE.write(msg % (t)) + return Constraint.Skip + + min_act = value(M.MinSeasonalActivity[r, p, s, t]) + expr = activity_rpst >= min_act + + # in the case that there is nothing to sum, skip + if isinstance(expr, bool): # an empty list was generated + return Constraint.Skip + + return expr + + def MinActivityGroup_Constraint(M: 'TemoaModel', r, p, g): r""" @@ -2721,7 +2831,7 @@ def TechInputSplit_Constraint(M: 'TemoaModel', r, p, s, d, i, t, v): total_inp = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] / value(M.Efficiency[r, S_i, t, v, S_o]) for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, i] + for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] ) expr = inp >= M.TechInputSplit[r, p, i, t] * total_inp @@ -2743,10 +2853,10 @@ def TechInputSplitAnnual_Constraint(M: 'TemoaModel', r, p, i, t, v): total_inp = sum( M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] / value(M.Efficiency[r, S_i, t, v, S_o]) for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, i] + for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] ) - expr = inp >= M.TechInputSplit[r, p, i, t] * total_inp + expr = inp >= M.TechInputSplitAnnual[r, p, i, t] * total_inp return expr @@ -2774,7 +2884,7 @@ def TechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v): for S_o in M.ProcessOutputsByInput[r, p, t, v, i] ) - expr = inp >= M.TechInputSplitAverage[r, p, i, t] * total_inp + expr = inp >= M.TechInputSplitAnnual[r, p, i, t] * total_inp return expr @@ -2853,7 +2963,35 @@ def TechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o): for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] ) - expr = out >= M.TechOutputSplit[r, p, t, o] * total_out + expr = out >= M.TechOutputSplitAnnual[r, p, t, o] * total_out + return expr + + +def TechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o): + r""" + Allows users to specify fixed or minimum shares of commodity outputs from a process. + 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 TechOutputSplit 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 output shares over the course of a year.""" + + out = sum( + M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, o] + for S_i in M.ProcessInputsByOutput[r, p, t, v, o] + for S_s in M.time_season + for S_d in M.time_of_day + ) + + total_out = sum( + M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_s in M.time_season + for S_d in M.time_of_day + ) + + expr = out >= M.TechOutputSplitAnnual[r, p, t, o] * total_out return expr diff --git a/tests/test_table_writer.py b/tests/test_table_writer.py index ac43c5f37..e966ae7b3 100644 --- a/tests/test_table_writer.py +++ b/tests/test_table_writer.py @@ -42,8 +42,8 @@ 'p_0': 2020, # the "myopic base year" to which all prices are discounted 'vintage': 2020, # the vintage of the new 'tech' 'p_e': 2100, # last year in the myopic view - 'model_cost': 409037.69, - 'undiscounted_cost': 409037.69, + 'model_cost': 409037.66, + 'undiscounted_cost': 409037.66, }, { 'ID': 'shortened term', @@ -56,8 +56,8 @@ 'p_0': 2020, 'vintage': 2030, 'p_e': 2035, - 'model_cost': 23403.85, - 'undiscounted_cost': 41930.08, + 'model_cost': 21997.72, + 'undiscounted_cost': 33544.06, }, ] params_with_zero_GDR = [ diff --git a/tests/testing_configs/config_emissions.toml b/tests/testing_configs/config_emissions.toml index b3c9db6d7..ae37576d3 100644 --- a/tests/testing_configs/config_emissions.toml +++ b/tests/testing_configs/config_emissions.toml @@ -2,8 +2,8 @@ scenario = "test run" scenario_mode = "perfect_foresight" -input_database = "testing_outputs/emissions.sqlite" -output_database = "testing_outputs/emissions.sqlite" +input_database = "tests/testing_outputs/emissions.sqlite" +output_database = "tests/testing_outputs/emissions.sqlite" neos = false # solver diff --git a/tests/testing_configs/config_link_test.toml b/tests/testing_configs/config_link_test.toml index 2edfc0a78..2c5e1ec37 100644 --- a/tests/testing_configs/config_link_test.toml +++ b/tests/testing_configs/config_link_test.toml @@ -18,13 +18,13 @@ scenario = "test_linked_tech" scenario_mode = "perfect_foresight" # Input database (Mandatory) -input_database = "testing_outputs/simple_linked_tech.sqlite" +input_database = "tests/testing_outputs/simple_linked_tech.sqlite" # Output file (Mandatory) # The output file must be an existing .sqlite file # For Pefrect Foresight, the user may target the same input file or a separate / # copied sqlite file in a different location. Myopic requires that input_database = output_database -output_database = "testing_outputs/simple_linked_tech.sqlite" +output_database = "tests/testing_outputs/simple_linked_tech.sqlite" # ------------------------------------ # DATA / MODEL CHECKS diff --git a/tests/testing_configs/config_mediumville.toml b/tests/testing_configs/config_mediumville.toml index 2fa7b0aaf..4f2c5652e 100644 --- a/tests/testing_configs/config_mediumville.toml +++ b/tests/testing_configs/config_mediumville.toml @@ -19,13 +19,13 @@ scenario_mode = "build_only" # Input file (Mandatory) # Input can be a .sqlite or .dat file # Both relative path and absolute path are accepted -input_database = "testing_outputs/mediumville.sqlite" +input_database = "tests/testing_outputs/mediumville.sqlite" # Output file (Mandatory) # The output file must be an existing .sqlite file # the user may target the same input file or a separate / # copied sqlite file in a different location -output_database = "testing_outputs/mediumville.sqlite" +output_database = "tests/testing_outputs/mediumville.sqlite" # ------------------------------------ # SOLVER diff --git a/tests/testing_configs/config_storageville.toml b/tests/testing_configs/config_storageville.toml index 35ee7b05b..6bfb3986e 100644 --- a/tests/testing_configs/config_storageville.toml +++ b/tests/testing_configs/config_storageville.toml @@ -19,13 +19,13 @@ scenario_mode = "perfect_foresight" # Input file (Mandatory) # Input can be a .sqlite or .dat file # Both relative path and absolute path are accepted -input_database = "testing_outputs/storageville.sqlite" +input_database = "tests/testing_outputs/storageville.sqlite" # Output file (Mandatory) # The output file must be an existing .sqlite file # the user may target the same input file or a separate / # copied sqlite file in a different location -output_database = "testing_outputs/storageville.sqlite" +output_database = "tests/testing_outputs/storageville.sqlite" # ------------------------------------ # SOLVER diff --git a/tests/testing_configs/config_test_system.toml b/tests/testing_configs/config_test_system.toml index 7ea66fc5e..10c504964 100644 --- a/tests/testing_configs/config_test_system.toml +++ b/tests/testing_configs/config_test_system.toml @@ -2,8 +2,8 @@ scenario = "test run" scenario_mode = "perfect_foresight" -input_database = "testing_outputs/test_system.sqlite" -output_database = "testing_outputs/test_system.sqlite" +input_database = "tests/testing_outputs/test_system.sqlite" +output_database = "tests/testing_outputs/test_system.sqlite" neos = false # solver diff --git a/tests/testing_configs/config_utopia.toml b/tests/testing_configs/config_utopia.toml index 8732362b3..58ef1d25f 100644 --- a/tests/testing_configs/config_utopia.toml +++ b/tests/testing_configs/config_utopia.toml @@ -2,8 +2,8 @@ scenario = "test run" scenario_mode = "perfect_foresight" -input_database = "testing_outputs/utopia.sqlite" -output_database = "testing_outputs/utopia.sqlite" +input_database = "tests/testing_outputs/utopia.sqlite" +output_database = "tests/testing_outputs/utopia.sqlite" neos = false # solver diff --git a/tests/testing_configs/config_utopia_myopic.toml b/tests/testing_configs/config_utopia_myopic.toml index e9a14600d..89f198fe0 100644 --- a/tests/testing_configs/config_utopia_myopic.toml +++ b/tests/testing_configs/config_utopia_myopic.toml @@ -4,8 +4,8 @@ scenario_mode = "myopic" # note that myopic currently only supports input = output. Test code will be responsible # for making a fresh copy (if desired) and moving it to the output folder -input_database = "testing_outputs/myo_utopia.sqlite" -output_database = "testing_outputs/myo_utopia.sqlite" +input_database = "tests/testing_outputs/myo_utopia.sqlite" +output_database = "tests/testing_outputs/myo_utopia.sqlite" neos = false # solver diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 23203e965..8b6c97397 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -203,10 +203,10 @@ CREATE TABLE DemandSpecificDistribution REFERENCES TimeOfDay (tod), demand_name TEXT REFERENCES Commodity (name), - dds REAL, - dds_notes TEXT, + dsd REAL, + dsd_notes TEXT, PRIMARY KEY (region, season, tod, demand_name), - CHECK (dds >= 0 AND dds <= 1) + CHECK (dsd >= 0 AND dsd <= 1) ); CREATE TABLE LoanRate ( @@ -625,7 +625,7 @@ CREATE TABLE TechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechInputSplitAverage +CREATE TABLE TechInputSplitAnnual ( region TEXT, period INTEGER diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 6d3315fb2..72e6d51bb 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -243,10 +243,10 @@ CREATE TABLE DemandSpecificDistribution REFERENCES TimeOfDay (tod), demand_name TEXT REFERENCES Commodity (name), - dds REAL, - dds_notes TEXT, + dsd REAL, + dsd_notes TEXT, PRIMARY KEY (region, season, tod, demand_name), - CHECK (dds >= 0 AND dds <= 1) + CHECK (dsd >= 0 AND dsd <= 1) ); INSERT INTO DemandSpecificDistribution VALUES('A','s1','d1','RL',0.25,NULL); INSERT INTO DemandSpecificDistribution VALUES('A','s1','d2','RL',0.25,NULL); @@ -713,7 +713,7 @@ CREATE TABLE TechInputSplit PRIMARY KEY (region, period, input_comm, tech) ); INSERT INTO TechInputSplit VALUES('A',2025,'HYD','EH',0.949999999999999956,'95% HYD reqt. (other not specified...)'); -CREATE TABLE TechInputSplitAverage +CREATE TABLE TechInputSplitAnnual ( region TEXT, period INTEGER @@ -726,7 +726,7 @@ CREATE TABLE TechInputSplitAverage notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -INSERT INTO TechInputSplitAverage VALUES('A',2025,'GeoHyd','GeoHeater',0.8000000000000000444,'80% geothermal'); +INSERT INTO TechInputSplitAnnual VALUES('A',2025,'GeoHyd','GeoHeater',0.8000000000000000444,'80% geothermal'); CREATE TABLE TechOutputSplit ( region TEXT, diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 74d7ac75f..6132ad718 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -114,9 +114,6 @@ "GeoThermal", "GeoHeater" ], - "tech_variable": [ - "GeoHeater" - ], "tech_retirement": [ "EH" ], @@ -4134,6 +4131,9 @@ ] ], "TechOutputSplitAnnualConstraint_rptvo": [], + "TechOutputSplitAverageConstraint_rptvo": [], + "MaxSeasonalActivityConstraint_rpst": [], + "MinSeasonalActivityConstraint_rpst": [], "LinkedEmissionsTechConstraint_rpsdtve": [ [ "A", diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index ce9a7fc71..9ce704833 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -198,10 +198,10 @@ CREATE TABLE DemandSpecificDistribution REFERENCES TimeOfDay (tod), demand_name TEXT REFERENCES Commodity (name), - dds REAL, - dds_notes TEXT, + dsd REAL, + dsd_notes TEXT, PRIMARY KEY (region, season, tod, demand_name), - CHECK (dds >= 0 AND dds <= 1) + CHECK (dsd >= 0 AND dsd <= 1) ); INSERT INTO DemandSpecificDistribution VALUES('linkville','summer','day','ELC',0.5,''); INSERT INTO DemandSpecificDistribution VALUES('linkville','winter','day','ELC',0.5,''); @@ -610,7 +610,7 @@ CREATE TABLE TechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechInputSplitAverage +CREATE TABLE TechInputSplitAnnual ( region TEXT, period INTEGER diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index 0cf789f65..ca9c9e166 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -198,10 +198,10 @@ CREATE TABLE DemandSpecificDistribution REFERENCES TimeOfDay (tod), demand_name TEXT REFERENCES Commodity (name), - dds REAL, - dds_notes TEXT, + dsd REAL, + dsd_notes TEXT, PRIMARY KEY (region, season, tod, demand_name), - CHECK (dds >= 0 AND dds <= 1) + CHECK (dsd >= 0 AND dsd <= 1) ); INSERT INTO DemandSpecificDistribution VALUES('electricville','s1','d1','RL',0.07499999999999999723,''); INSERT INTO DemandSpecificDistribution VALUES('electricville','s1','d2','RL',0.07499999999999999723,''); @@ -630,7 +630,7 @@ CREATE TABLE TechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechInputSplitAverage +CREATE TABLE TechInputSplitAnnual ( region TEXT, period INTEGER diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index d2a9b2939..16b1e01d0 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -414,10 +414,10 @@ CREATE TABLE DemandSpecificDistribution REFERENCES TimeOfDay (tod), demand_name TEXT REFERENCES Commodity (name), - dds REAL, - dds_notes TEXT, + dsd REAL, + dsd_notes TEXT, PRIMARY KEY (region, season, tod, demand_name), - CHECK (dds >= 0 AND dds <= 1) + CHECK (dsd >= 0 AND dsd <= 1) ); INSERT INTO DemandSpecificDistribution VALUES('R1','spring','day','RH',0.05000000000000000277,''); INSERT INTO DemandSpecificDistribution VALUES('R1','spring','night','RH',0.1000000000000000055,''); @@ -1005,7 +1005,7 @@ INSERT INTO TechInputSplit VALUES('R2',2025,'GSL','T_BLND',0.7199999999999999734 INSERT INTO TechInputSplit VALUES('R2',2025,'ETH','T_BLND',0.08000000000000000166,''); INSERT INTO TechInputSplit VALUES('R2',2030,'GSL','T_BLND',0.7199999999999999734,''); INSERT INTO TechInputSplit VALUES('R2',2030,'ETH','T_BLND',0.08000000000000000166,''); -CREATE TABLE TechInputSplitAverage +CREATE TABLE TechInputSplitAnnual ( region TEXT, period INTEGER diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index d49b39b14..4bc8413d4 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -128,7 +128,6 @@ "R_NGH", "E_TRANS" ], - "tech_variable": [], "tech_retirement": [], "commodity_demand": [ "VMT", @@ -45031,5 +45030,8 @@ ] ], "TechOutputSplitAnnualConstraint_rptvo": [], + "TechOutputSplitAverageConstraint_rptvo": [], + "MaxSeasonalActivityConstraint_rpst": [], + "MinSeasonalActivityConstraint_rpst": [], "LinkedEmissionsTechConstraint_rpsdtve": [] } \ No newline at end of file diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 2d49c629f..ff69a0e14 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -428,10 +428,10 @@ CREATE TABLE DemandSpecificDistribution REFERENCES TimeOfDay (tod), demand_name TEXT REFERENCES Commodity (name), - dds REAL, - dds_notes TEXT, + dsd REAL, + dsd_notes TEXT, PRIMARY KEY (region, season, tod, demand_name), - CHECK (dds >= 0 AND dds <= 1) + CHECK (dsd >= 0 AND dsd <= 1) ); INSERT INTO DemandSpecificDistribution VALUES('utopia','inter','day','RH',0.1199999999999999956,''); INSERT INTO DemandSpecificDistribution VALUES('utopia','inter','night','RH',0.05999999999999999778,''); @@ -984,7 +984,7 @@ CREATE TABLE TechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechInputSplitAverage +CREATE TABLE TechInputSplitAnnual ( region TEXT, period INTEGER @@ -1016,6 +1016,19 @@ INSERT INTO TechOutputSplit VALUES('utopia',2010,'SRE','DSL',0.69999999999999995 INSERT INTO TechOutputSplit VALUES('utopia',1990,'SRE','GSL',0.2999999999999999889,''); INSERT INTO TechOutputSplit VALUES('utopia',2000,'SRE','GSL',0.2999999999999999889,''); INSERT INTO TechOutputSplit VALUES('utopia',2010,'SRE','GSL',0.2999999999999999889,''); +CREATE TABLE TechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -1297,30 +1310,29 @@ CREATE TABLE Technology curtail INTEGER NOT NULL DEFAULT 0, retire INTEGER NOT NULL DEFAULT 0, flex INTEGER NOT NULL DEFAULT 0, - variable INTEGER NOT NULL DEFAULT 0, exchange INTEGER NOT NULL DEFAULT 0, description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('IMPDSL1','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported diesel'); -INSERT INTO Technology VALUES('IMPGSL1','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported gasoline'); -INSERT INTO Technology VALUES('IMPHCO1','r','supply','coal','',1,0,0,0,0,0,0,0,' imported coal'); -INSERT INTO Technology VALUES('IMPOIL1','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO Technology VALUES('IMPURN1','r','supply','nuclear','',1,0,0,0,0,0,0,0,' imported uranium'); -INSERT INTO Technology VALUES('IMPFEQ','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported fossil equivalent'); -INSERT INTO Technology VALUES('IMPHYD','r','supply','hydro','',1,0,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); -INSERT INTO Technology VALUES('E01','pb','electric','coal','',0,0,0,0,0,0,0,0,' coal power plant'); -INSERT INTO Technology VALUES('E21','pb','electric','nuclear','',0,0,0,0,0,0,0,0,' nuclear power plant'); -INSERT INTO Technology VALUES('E31','pb','electric','hydro','',0,0,0,0,0,0,0,0,' hydro power'); -INSERT INTO Technology VALUES('E51','ps','electric','electric','',0,0,0,0,0,0,0,0,' electric storage'); -INSERT INTO Technology VALUES('E70','p','electric','petroleum','',0,0,0,0,0,0,0,0,' diesel power plant'); -INSERT INTO Technology VALUES('RHE','p','residential','electric','',0,0,0,0,0,0,0,0,' electric residential heating'); -INSERT INTO Technology VALUES('RHO','p','residential','petroleum','',0,0,0,0,0,0,0,0,' diesel residential heating'); -INSERT INTO Technology VALUES('RL1','p','residential','electric','',0,0,0,0,0,0,0,0,' residential lighting'); -INSERT INTO Technology VALUES('SRE','p','supply','petroleum','',0,0,0,0,0,0,0,0,' crude oil processor'); -INSERT INTO Technology VALUES('TXD','p','transport','petroleum','',0,0,0,0,0,0,0,0,' diesel powered vehicles'); -INSERT INTO Technology VALUES('TXE','p','transport','electric','',0,0,0,0,0,0,0,0,' electric powered vehicles'); -INSERT INTO Technology VALUES('TXG','p','transport','petroleum','',0,0,0,0,0,0,0,0,' gasoline powered vehicles'); +INSERT INTO Technology VALUES('IMPDSL1','r','supply','petroleum','',1,0,0,0,0,0,0,' imported diesel'); +INSERT INTO Technology VALUES('IMPGSL1','r','supply','petroleum','',1,0,0,0,0,0,0,' imported gasoline'); +INSERT INTO Technology VALUES('IMPHCO1','r','supply','coal','',1,0,0,0,0,0,0,' imported coal'); +INSERT INTO Technology VALUES('IMPOIL1','r','supply','petroleum','',1,0,0,0,0,0,0,' imported crude oil'); +INSERT INTO Technology VALUES('IMPURN1','r','supply','nuclear','',1,0,0,0,0,0,0,' imported uranium'); +INSERT INTO Technology VALUES('IMPFEQ','r','supply','petroleum','',1,0,0,0,0,0,0,' imported fossil equivalent'); +INSERT INTO Technology VALUES('IMPHYD','r','supply','hydro','',1,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); +INSERT INTO Technology VALUES('E01','pb','electric','coal','',0,0,0,0,0,0,0,' coal power plant'); +INSERT INTO Technology VALUES('E21','pb','electric','nuclear','',0,0,0,0,0,0,0,' nuclear power plant'); +INSERT INTO Technology VALUES('E31','pb','electric','hydro','',0,0,0,0,0,0,0,' hydro power'); +INSERT INTO Technology VALUES('E51','ps','electric','electric','',0,0,0,0,0,0,0,' electric storage'); +INSERT INTO Technology VALUES('E70','p','electric','petroleum','',0,0,0,0,0,0,0,' diesel power plant'); +INSERT INTO Technology VALUES('RHE','p','residential','electric','',0,0,0,0,0,0,0,' electric residential heating'); +INSERT INTO Technology VALUES('RHO','p','residential','petroleum','',0,0,0,0,0,0,0,' diesel residential heating'); +INSERT INTO Technology VALUES('RL1','p','residential','electric','',0,0,0,0,0,0,0,' residential lighting'); +INSERT INTO Technology VALUES('SRE','p','supply','petroleum','',0,0,0,0,0,0,0,' crude oil processor'); +INSERT INTO Technology VALUES('TXD','p','transport','petroleum','',0,0,0,0,0,0,0,' diesel powered vehicles'); +INSERT INTO Technology VALUES('TXE','p','transport','electric','',0,0,0,0,0,0,0,' electric powered vehicles'); +INSERT INTO Technology VALUES('TXG','p','transport','petroleum','',0,0,0,0,0,0,0,' gasoline powered vehicles'); CREATE TABLE OutputCost ( scenario TEXT, diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index fa218f837..e33d68126 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -132,7 +132,6 @@ "TXE", "TXG" ], - "tech_variable": [], "tech_retirement": [], "commodity_demand": [ "RH", @@ -25326,5 +25325,8 @@ ] ], "TechOutputSplitAnnualConstraint_rptvo": [], + "TechOutputSplitAverageConstraint_rptvo": [], + "MaxSeasonalActivityConstraint_rpst": [], + "MinSeasonalActivityConstraint_rpst": [], "LinkedEmissionsTechConstraint_rpsdtve": [] } \ No newline at end of file From 5cfdd59a29a7da8483e283c30f590dac9eadd748 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 22 Sep 2025 12:53:40 -0400 Subject: [PATCH 027/587] Add optional period-indexed demand distribution --- temoa/temoa_model/hybrid_loader.py | 5 +++ temoa/temoa_model/temoa_initialize.py | 55 +++++++++++++++++++++++++-- temoa/temoa_model/temoa_model.py | 6 +-- temoa/temoa_model/temoa_rules.py | 15 ++++++-- tests/testing_data/test_system.sql | 18 +++++++++ 5 files changed, 89 insertions(+), 10 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index a9171b99d..9bc0f46f1 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -579,6 +579,11 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): ).fetchall() load_element(M.DemandSpecificDistribution, raw) + # DemandPeriodDistribution + if self.table_exists('DemandPeriodDistribution'): + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, season, tod, demand_name, dpd FROM main.DemandPeriodDistribution') + load_element(M.DemandPeriodDistribution, raw) + # Demand raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, commodity, demand FROM main.Demand', mi=mi) load_element(M.Demand, raw) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 733fdd691..c95106028 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -435,10 +435,15 @@ def CreateDemands(M: 'TemoaModel'): if DSD_dem_getter(k) == dem and DSD_region_getter(k) == r ] if len(keys) != expected_key_length: - logger.debug( - 'Missing some keys in this set for creation of Demand Distribution %s: %s', - dem, - keys, + missing = set( + (s, d) + for s in M.time_season + for d in M.time_of_day + if (r, s, d, dem) not in keys + ) + logger.warning( + 'Missing some time slices for Demand Specific Distribution %s: %s', + (r, dem), missing, ) total = sum(DSD[i] for i in keys) if abs(value(total) - 1.0) > 0.001: @@ -469,6 +474,48 @@ def CreateDemands(M: 'TemoaModel'): ) logger.error(msg.format(dem, items, total)) raise ValueError(msg.format(dem, items, total)) + + # No DPD by default + for p in M.time_optimize: + M.demandPeriodDistributions[(r, p, dem)] = False + + # Step 6: Validate DPD + DPD = M.DemandPeriodDistribution + + # Get the rp_dem combos that have period indexing, so we know later on which demands use it + rp_dem = set( + (r, p, dem) + for r, p, s, d, dem in DPD.sparse_iterkeys() + ) + for r, p, dem in rp_dem: + + # Check that each DPD demand actually has all the timeslices defined + missing = set( + (s, d) + for s in M.time_season + for d in M.time_of_day + if (r, p, s, d, dem) not in DPD.sparse_iterkeys() + ) + if len(missing) > 0: + msg = ('Missing some time slices for Demand Period Distribution {}: {}') + logger.warning(msg.format((r, p, dem), missing)) + + total = sum( + M.DemandPeriodDistribution[r, p, s, d, dem] + for s in M.time_season + for d in M.time_of_day + ) + if abs(value(total) - 1.0) > 0.001: + msg = ( + 'The values of the DemandPeriodDistribution parameter do not ' + 'sum to 1 for {}. Current sum = {}. Defaulting to DSD/DDD.' + ) + logger.warning(msg.format((r, p, dem), total)) + continue + + # This is a good DPD, override DSD/DDD + M.demandPeriodDistributions[(r, p, dem)] = True + logger.debug('Finished creating demand distributions') diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 3e074a0fb..a947b11f2 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -117,6 +117,7 @@ def __init__(M, *args, **kwargs): M.exportRegions = dict() M.importRegions = dict() M.time_next = dict() + M.demandPeriodDistributions: dict[tuple, bool] = dict() # which demands have period indexing M.flex_commodities = set() ################################################ @@ -226,9 +227,8 @@ def __init__(M, *args, **kwargs): # Dev Note: There does not appear to be a DB table supporting DemandDefaultDistro. This does not # cause any problems, so let it be for now. M.DemandDefaultDistribution = Param(M.time_season, M.time_of_day, mutable=True) - M.DemandSpecificDistribution = Param( - M.regions, M.time_season, M.time_of_day, M.commodity_demand, mutable=True, default=0 - ) + M.DemandSpecificDistribution = Param(M.regions, M.time_season, M.time_of_day, M.commodity_demand, mutable=True, default=0) + M.DemandPeriodDistribution = Param(M.regions, M.time_optimize, M.time_season, M.time_of_day, M.commodity_demand, default=0) M.Demand = Param(M.regions, M.time_optimize, M.commodity_demand) M.initialize_Demands = BuildAction(rule=CreateDemands) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index d70d70878..bdbfc91fd 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -655,7 +655,7 @@ def Demand_Constraint(M: 'TemoaModel', r, p, s, d, dem): DemandConstraintErrorCheck(supply + supply_annual, r, p, s, d, dem) expr = ( - supply + supply_annual == M.Demand[r, p, dem] * M.DemandSpecificDistribution[r, s, d, dem] + supply + supply_annual == M.Demand[r, p, dem] * get_demand_distribution(M, r, p, s, d, dem) ) return expr @@ -700,8 +700,8 @@ def DemandActivity_Constraint(M: 'TemoaModel', r, p, s, d, t, v, dem, s_0, d_0): ) expr = ( - act_a * M.DemandSpecificDistribution[r, s, d, dem] - == act_b * M.DemandSpecificDistribution[r, s_0, d_0, dem] + act_a * get_demand_distribution(M, r, p, s, d, dem) + == act_b * get_demand_distribution(M, r, p, s_0, d_0, dem) ) return expr @@ -2947,3 +2947,12 @@ def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): ) return -primary_flow == linked_flow + + +# Doing it this way allows us to avoid building a big period-indexed parameter for every demand +# when only a few demands will likely utilise that option +def get_demand_distribution(M: 'TemoaModel', r, p, s, d, dem): + if M.demandPeriodDistributions[(r, p, dem)]: + return M.DemandPeriodDistribution[r, p, s, d, dem] + else: + return M.DemandSpecificDistribution[r, s, d, dem] \ No newline at end of file diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index bbed5cdf3..e0234665e 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -436,6 +436,24 @@ INSERT INTO DemandSpecificDistribution VALUES('R2','fall','day','RH',0.050000000 INSERT INTO DemandSpecificDistribution VALUES('R2','fall','night','RH',0.1000000000000000055,''); INSERT INTO DemandSpecificDistribution VALUES('R2','winter','day','RH',0.2999999999999999889,''); INSERT INTO DemandSpecificDistribution VALUES('R2','winter','night','RH',0.4000000000000000222,''); +CREATE TABLE DemandPeriodDistribution +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + demand_name TEXT + REFERENCES Commodity (name), + dpd REAL, + dpd_notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), + CHECK (dpd >= 0 AND dpd <= 1) +); +INSERT INTO DemandPeriodDistribution VALUES('R1',2020,'fall','day','VMT',0.125,'Same as default distribution (segfrac)'); +INSERT INTO DemandPeriodDistribution VALUES('R2',2025,'winter','night','VMT',0.125,'Same as default distribution (segfrac)'); CREATE TABLE LoanRate ( region TEXT, From 7afd25d5f1322b35bdf325256f63ca58bce9c7da Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 23 Jan 2025 18:51:24 -0500 Subject: [PATCH 028/587] Fix storage level output speed --- temoa/temoa_model/table_writer.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/temoa/temoa_model/table_writer.py b/temoa/temoa_model/table_writer.py index 19cc021d3..4ca015168 100644 --- a/temoa/temoa_model/table_writer.py +++ b/temoa/temoa_model/table_writer.py @@ -257,12 +257,14 @@ def write_storage_level(self, M: TemoaModel, iteration=None) -> None: else self.config.scenario ) + data = [] for sli, storage_level in storage_levels.items(): sector = self.tech_sectors[sli.t] - qry = 'INSERT INTO OutputStorageLevel VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)' - data = (scenario_name, sli.r, sector, sli.p, sli.s, sli.d, sli.t, sli.v, storage_level) - self.con.execute(qry, data) - self.con.commit() + data.append((scenario_name, sli.r, sector, sli.p, sli.s, sli.d, sli.t, sli.v, storage_level)) + + qry = f'INSERT INTO OutputStorageLevel VALUES {_marks(9)}' + self.con.executemany(qry, data) + self.con.commit() def write_objective(self, M: TemoaModel, iteration=None) -> None: """Write the value of all ACTIVE objectives to the DB""" From 18aa78d03dc53b8751e1f601c754e8ba09561beb Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 24 Jan 2025 11:50:02 -0500 Subject: [PATCH 029/587] Add NewCapacityGroupShare constraints --- temoa/temoa_model/hybrid_loader.py | 12 +++ temoa/temoa_model/temoa_initialize.py | 12 +++ temoa/temoa_model/temoa_model.py | 15 ++++ temoa/temoa_model/temoa_rules.py | 78 ++++++++++++++-- tests/testing_configs/config_mediumville.toml | 2 +- tests/testing_data/mediumville.sql | 36 +++++++- tests/testing_data/mediumville_sets.json | 90 +++++++++++++++++++ tests/testing_data/test_system_sets.json | 3 + tests/testing_data/utopia_sets.json | 3 + 9 files changed, 237 insertions(+), 14 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 9bc0f46f1..85aa79087 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -818,6 +818,16 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, group_name, max_proportion FROM main.MaxNewCapacityShare', mi=mi) load_element(M.MaxNewCapacityShare, raw, self.viable_rt, (0, 2)) + # MinNewCapacityGroupShare + if self.table_exists('MinNewCapacityGroupShare'): + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, sub_group, super_group, min_proportion FROM main.MinNewCapacityGroupShare', mi=mi) + load_element(M.MinNewCapacityGroupShare, raw) + + # MaxNewCapacityGroupShare + if self.table_exists('MaxNewCapacityGroupShare'): + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, sub_group, super_group, max_proportion FROM main.MaxNewCapacityGroupShare', mi=mi) + load_element(M.MaxNewCapacityGroupShare, raw) + # MinActivityGroup if self.table_exists('MinActivityGroup'): raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, group_name, min_act FROM main.MinActivityGroup', mi=mi) @@ -1016,6 +1026,7 @@ def load_param_idx_sets(self, data: dict) -> dict: M.MaxNewCapacity.name: M.MaxNewCapacityConstraint_rpt.name, M.MaxNewCapacityGroup.name: M.MaxNewCapacityGroupConstraint_rpg.name, M.MaxNewCapacityShare.name: M.MaxNewCapacityShareConstraint_rptg.name, + M.MaxNewCapacityGroupShare.name: M.MaxNewCapacityGroupShareConstraint_rpgg.name, M.MaxResource.name: M.MaxResourceConstraint_rt.name, M.MinActivity.name: M.MinActivityConstraint_rpt.name, M.MinSeasonalActivity.name: M.MinSeasonalActivityConstraint_rpst.name, @@ -1028,6 +1039,7 @@ def load_param_idx_sets(self, data: dict) -> dict: M.MinNewCapacity.name: M.MinNewCapacityConstraint_rpt.name, M.MinNewCapacityGroup.name: M.MinNewCapacityGroupConstraint_rpg.name, M.MinNewCapacityShare.name: M.MinNewCapacityShareConstraint_rptg.name, + M.MinNewCapacityGroupShare.name: M.MinNewCapacityGroupShareConstraint_rpgg.name, M.RenewablePortfolioStandard.name: M.RenewablePortfolioStandardConstraint_rpg.name, M.ResourceBound.name: M.ResourceConstraint_rpr.name, M.StorageFraction.name: M.StorageFractionConstraint_rpsdtv.name diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index c95106028..d778a2f60 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1019,6 +1019,17 @@ def GroupShareIndices(M: 'TemoaModel'): return indices +def TwoGroupShareIndices(M: 'TemoaModel'): + indices = set( + (r, p, g1, g2) + for g1 in M.tech_group_names + for g2 in M.tech_group_names + for r, p, _t in M.processVintages.keys() + if _t in M.tech_group_members[g2] + ) + return indices + + def EmissionActivityIndices(M: 'TemoaModel'): indices = set( (r, e, i, t, v, o) @@ -1029,6 +1040,7 @@ def EmissionActivityIndices(M: 'TemoaModel'): return indices + # devnote: this does not appear to be used anywhere # given that it doesnt check if periods are valid, cant think what it would be for # def EmissionActivityByPeriodAndTechVariableIndices(M: 'TemoaModel'): diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index a947b11f2..4b4d41d7a 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -449,6 +449,14 @@ def __init__(M, *args, **kwargs): M.MaxNewCapacityShareConstraint_rptg = Set(within=M.GroupShareIndices) M.MaxNewCapacityShare = Param(M.GroupShareIndices) + M.TwoGroupShareIndices = Set(dimen=4, initialize=TwoGroupShareIndices) + + M.MinNewCapacityGroupShareConstraint_rpgg = Set(within=M.TwoGroupShareIndices) + M.MinNewCapacityGroupShare = Param(M.TwoGroupShareIndices) + + M.MaxNewCapacityGroupShareConstraint_rpgg = Set(within=M.TwoGroupShareIndices) + M.MaxNewCapacityGroupShare = Param(M.TwoGroupShareIndices) + # This set works for all storage-related constraints M.StorageConstraints_rpsdtv = Set(dimen=6, initialize=StorageConstraintIndices) M.StorageFractionConstraint_rpsdtv = Set(within=M.StorageConstraints_rpsdtv) @@ -736,6 +744,13 @@ def __init__(M, *args, **kwargs): M.MaxNewCapacityShareConstraint_rptg, rule=MaxNewCapacityShare_Constraint ) + M.MinNewCapacityGroupShareConstraint = Constraint( + M.MinNewCapacityGroupShareConstraint_rpgg, rule=MinNewCapacityGroupShare_Constraint + ) + M.MaxNewCapacityGroupShareConstraint = Constraint( + M.MaxNewCapacityGroupShareConstraint_rpgg, rule=MaxNewCapacityGroupShare_Constraint + ) + M.progress_marker_8 = BuildAction( ['Starting Max/Min Capacity and Tech Split ' 'Constraints'], rule=progress_check ) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index bdbfc91fd..64032ebbb 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -2174,7 +2174,12 @@ def MaxCapacityGroup_Constraint(M: 'TemoaModel', r, p, g): expr = cap <= max_capgroup # in the case that there is nothing to sum, skip - if isinstance(expr, bool): # an empty list was generated + if isinstance(expr, bool): # an empty list was generated + logger.error( + 'No elements available to support max-capacity group: %s.' + ' Check data/log for available/suppressed techs. Constraint ignored.', + (r, p, g) + ) return Constraint.Skip return expr @@ -2239,11 +2244,9 @@ def MinCapacityGroup_Constraint(M: 'TemoaModel', r, p, g): # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated logger.error( - 'No elements available to support min-capacity group: (%s, %d, %s).' - ' Check data/log for available/suppressed techs. Requirement IGNORED.', - r, - p, - g, + 'No elements available to support min-capacity group: %s.' + ' Check data/log for available/suppressed techs. Constraint ignored.', + (r, p, g) ) return Constraint.Skip return expr @@ -2261,7 +2264,7 @@ def MinNewCapacityGroup_Constraint(M: 'TemoaModel', r, p, g): expr = agg_new_cap >= min_new_cap if isinstance(expr, bool): logger.error( - 'No elements available to support min-activity group: (%s, %d, %s).' + 'No elements available to support min-capacity group: (%s, %d, %s).' ' Check data/log for available/suppressed techs. Requirement IGNORED.', r, p, @@ -2519,6 +2522,64 @@ def MaxNewCapacityShare_Constraint(M: 'TemoaModel', r, p, t, g): return expr +def MinNewCapacityGroupShare_Constraint(M: 'TemoaModel', r, p, g1, g2): + r""" + Sets the minimum aggregate capacity of one group of technologies as a share of + another group of technologies. + """ + min_share = value(M.MinNewCapacityGroupShare[r, p, g1, g2]) + agg_new_cap_g1 = sum( + M.V_NewCapacity[r, t, p] + for t in M.tech_group_members[g1] + if (r, p, t) in M.V_CapacityAvailableByPeriodAndTech + ) + agg_new_cap_g2 = sum( + M.V_NewCapacity[r, t, p] + for t in M.tech_group_members[g2] + if (r, p, t) in M.V_CapacityAvailableByPeriodAndTech + ) + expr = agg_new_cap_g1 >= agg_new_cap_g2 * min_share + + if isinstance(expr, bool): # one side of expression was empty + logger.error( + 'Missing group techs to support min new capacity group share constraint: {}.' + ' Check data/log for available/suppressed techs. Constraint ignored.', + (r, p, g1, g2) + ) + return Constraint.Skip + + return expr + + +def MaxNewCapacityGroupShare_Constraint(M: 'TemoaModel', r, p, g1, g2): + r""" + Sets the maximum aggregate capacity of one group of technologies as a share of + another group of technologies. + """ + max_share = value(M.MaxNewCapacityGroupShare[r, p, g1, g2]) + agg_new_cap_g1 = sum( + M.V_NewCapacity[r, t, p] + for t in M.tech_group_members[g1] + if (r, p, t) in M.V_CapacityAvailableByPeriodAndTech + ) + agg_new_cap_g2 = sum( + M.V_NewCapacity[r, t, p] + for t in M.tech_group_members[g2] + if (r, p, t) in M.V_CapacityAvailableByPeriodAndTech + ) + expr = agg_new_cap_g1 <= agg_new_cap_g2 * max_share + + if isinstance(expr, bool): # one side of expression was empty + logger.error( + 'Missing group techs to support max new capacity group share constraint: {}.' + ' Check data/log for available/suppressed techs. Constraint ignored.', + (r, p, g1, g2) + ) + return Constraint.Skip + + return expr + + def MinAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o): r""" The MinAnnualCapacityFactor sets a lower bound on the annual capacity factor @@ -2949,8 +3010,7 @@ def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): return -primary_flow == linked_flow -# Doing it this way allows us to avoid building a big period-indexed parameter for every demand -# when only a few demands will likely utilise that option +# To avoid building big many-indexed parameters when they aren't needed def get_demand_distribution(M: 'TemoaModel', r, p, s, d, dem): if M.demandPeriodDistributions[(r, p, dem)]: return M.DemandPeriodDistribution[r, p, s, d, dem] diff --git a/tests/testing_configs/config_mediumville.toml b/tests/testing_configs/config_mediumville.toml index 4f2c5652e..3b677ece3 100644 --- a/tests/testing_configs/config_mediumville.toml +++ b/tests/testing_configs/config_mediumville.toml @@ -14,7 +14,7 @@ scenario = "testing" # See documentation for explanations. A standard single run is "perfect foresight" # mode must be one of (case-insensitive): # [perfect_foresight, MGA, myopic, method_of_morris, build_only] -scenario_mode = "build_only" +scenario_mode = "perfect_foresight" # Input file (Mandatory) # Input can be a .sqlite or .dat file diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 7e071a34b..06afbc417 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -639,8 +639,8 @@ CREATE TABLE RampDown rate REAL, PRIMARY KEY (region, tech) ); -INSERT INTO RampDown VALUES('A','EH',0.2000000000000000111); -INSERT INTO RampDown VALUES('B','EH',0.2000000000000000111); +INSERT INTO RampDown VALUES('A','EH',0.05); +INSERT INTO RampDown VALUES('B','EH',0.05); CREATE TABLE RampUp ( region TEXT, @@ -649,8 +649,8 @@ CREATE TABLE RampUp rate REAL, PRIMARY KEY (region, tech) ); -INSERT INTO RampUp VALUES('B','EH',100.0); -INSERT INTO RampUp VALUES('A','EH',100.0); +INSERT INTO RampUp VALUES('B','EH',0.05); +INSERT INTO RampUp VALUES('A','EH',0.05); CREATE TABLE Region ( region TEXT @@ -855,6 +855,20 @@ CREATE TABLE MaxNewCapacityShare notes TEXT, PRIMARY KEY (region, period, tech, group_name) ); +CREATE TABLE MaxNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); +INSERT INTO MaxNewCapacityGroupShare VALUES('A', 2025, 'RPS_common', 'A_tech_grp_1', 1, ''); CREATE TABLE MinActivityShare ( region TEXT, @@ -933,6 +947,20 @@ CREATE TABLE MinNewCapacityShare notes TEXT, PRIMARY KEY (region, period, tech, group_name) ); +CREATE TABLE MinNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); +INSERT INTO MinNewCapacityGroupShare VALUES('A', 2025, 'RPS_common', 'A_tech_grp_1', 0, ''); CREATE TABLE OutputEmission ( scenario TEXT, diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index d5ab25e31..02fc33ccc 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -1690,6 +1690,96 @@ ], "MinCapacityShareConstraint_rptg": [], "MaxCapacityShareConstraint_rptg": [], + "TwoGroupShareIndices": [ + [ + "B", + 2025, + "RPS_global", + "RPS_common" + ], + [ + "A", + 2025, + "A_tech_grp_1", + "RPS_common" + ], + [ + "B", + 2025, + "A_tech_grp_1", + "A_tech_grp_1" + ], + [ + "A", + 2025, + "A_tech_grp_1", + "A_tech_grp_1" + ], + [ + "A", + 2025, + "RPS_global", + "A_tech_grp_1" + ], + [ + "A", + 2025, + "RPS_common", + "RPS_common" + ], + [ + "B", + 2025, + "RPS_global", + "A_tech_grp_1" + ], + [ + "A", + 2025, + "RPS_common", + "A_tech_grp_1" + ], + [ + "B", + 2025, + "A_tech_grp_1", + "RPS_common" + ], + [ + "B", + 2025, + "RPS_common", + "RPS_common" + ], + [ + "B", + 2025, + "RPS_common", + "A_tech_grp_1" + ], + [ + "A", + 2025, + "RPS_global", + "RPS_common" + ] + ], + "MaxNewCapacityGroupShareConstraint_rpgg": [ + [ + "A", + 2025, + "RPS_common", + "A_tech_grp_1" + ] + ], + "MinNewCapacityGroupShareConstraint_rpgg": [ + [ + "A", + 2025, + "RPS_common", + "A_tech_grp_1" + ] + ], "MinActivityShareConstraint_rptg": [], "MaxActivityShareConstraint_rptg": [], "MinNewCapacityShareConstraint_rptg": [], diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index e52313457..f405cdf7b 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -6946,6 +6946,9 @@ "GroupShareIndices": [], "MinCapacityShareConstraint_rptg": [], "MaxCapacityShareConstraint_rptg": [], + "TwoGroupShareIndices": [], + "MaxNewCapacityGroupShareConstraint_rpgg": [], + "MinNewCapacityGroupShareConstraint_rpgg": [], "MinActivityShareConstraint_rptg": [], "MaxActivityShareConstraint_rptg": [], "MinNewCapacityShareConstraint_rptg": [], diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 9620aa675..908db1967 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -5297,6 +5297,9 @@ "GroupShareIndices": [], "MinCapacityShareConstraint_rptg": [], "MaxCapacityShareConstraint_rptg": [], + "TwoGroupShareIndices": [], + "MaxNewCapacityGroupShareConstraint_rpgg": [], + "MinNewCapacityGroupShareConstraint_rpgg": [], "MinActivityShareConstraint_rptg": [], "MaxActivityShareConstraint_rptg": [], "MinNewCapacityShareConstraint_rptg": [], From 29f90ad3195b614bc5035308d266ceecb8ed4507 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 24 Jan 2025 12:25:42 -0500 Subject: [PATCH 030/587] Split techsplit constraints into min and max split constraints --- temoa/temoa_model/hybrid_loader.py | 119 ++++++++++-- temoa/temoa_model/temoa_initialize.py | 216 +++++++++++++++++---- temoa/temoa_model/temoa_model.py | 122 ++++++++---- temoa/temoa_model/temoa_rules.py | 221 ++++++++++++++++++++-- tests/testing_data/emissions.sql | 6 +- tests/testing_data/mediumville.sql | 12 +- tests/testing_data/mediumville_sets.json | 18 +- tests/testing_data/simple_linked_tech.sql | 6 +- tests/testing_data/storageville.sql | 6 +- tests/testing_data/test_system.sql | 54 +++--- tests/testing_data/test_system_sets.json | 18 +- tests/testing_data/utopia.sql | 20 +- tests/testing_data/utopia_sets.json | 18 +- 13 files changed, 657 insertions(+), 179 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 85aa79087..e35e6143b 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -621,10 +621,10 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): raw = cur.execute('SELECT region, tech, lifetime FROM main.LoanLifetimeTech').fetchall() load_element(M.LoanLifetimeTech, raw, self.viable_rt, (0, 1)) - # TechInputSplit - if self.table_exists('TechInputSplit'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, input_comm, tech, min_proportion FROM main.TechInputSplit', mi=mi) - loaded = load_element(M.TechInputSplit, raw, self.viable_rpit, (0, 1, 2, 3)) + # MinTechInputSplit + if self.table_exists('MinTechInputSplit'): + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, input_comm, tech, min_proportion FROM main.MinTechInputSplit', mi=mi) + loaded = load_element(M.MinTechInputSplit, raw, self.viable_rpit, (0, 1, 2, 3)) # we need to see if anything was filtered out here and raise warning if so as it may have invalidated # a blending process and any missing items should be reviewed if len(loaded) < len(raw): @@ -643,10 +643,10 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): ic, ) - # TechInputSplitAnnual - if self.table_exists('TechInputSplitAnnual'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, input_comm, tech, min_proportion FROM main.TechInputSplitAnnual', mi=mi) - loaded = load_element(M.TechInputSplitAnnual, raw, self.viable_rpit, (0, 1, 2, 3)) + # MinTechInputSplitAnnual + if self.table_exists('MinTechInputSplitAnnual'): + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, input_comm, tech, min_proportion FROM main.MinTechInputSplitAnnual', mi=mi) + loaded = load_element(M.MinTechInputSplitAnnual, raw, self.viable_rpit, (0, 1, 2, 3)) # we need to see if anything was filtered out here and raise warning if so as it may have invalidated # a blending process and any missing items should be reviewed if len(loaded) < len(raw): @@ -665,10 +665,10 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): ic, ) - # TechOutputSplit - if self.table_exists('TechOutputSplit'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, output_comm, min_proportion FROM main.TechOutputSplit', mi=mi) - loaded = load_element(M.TechOutputSplit, raw, self.viable_rpto, (0, 1, 2, 3)) + # MinTechOutputSplit + if self.table_exists('MinTechOutputSplit'): + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, output_comm, min_proportion FROM main.MinTechOutputSplit', mi=mi) + loaded = load_element(M.MinTechOutputSplit, raw, self.viable_rpto, (0, 1, 2, 3)) # raise warning regarding any deletions here... similar to input split above if len(loaded) < len(raw): missing = set(raw) - set(loaded) @@ -686,10 +686,97 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): oc, ) - # TechOutputSplitAnnual - if self.table_exists('TechOutputSplitAnnual'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, output_comm, min_proportion FROM main.TechOutputSplitAnnual', mi=mi) - loaded = load_element(M.TechOutputSplitAnnual, raw, self.viable_rpto, (0, 1, 2, 3)) + # MinTechOutputSplitAnnual + if self.table_exists('MinTechOutputSplitAnnual'): + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, output_comm, min_proportion FROM main.MinTechOutputSplitAnnual', mi=mi) + loaded = load_element(M.MinTechOutputSplitAnnual, raw, self.viable_rpto, (0, 1, 2, 3)) + # we need to see if anything was filtered out here and raise warning if so as it may have invalidated + # a blending process and any missing items should be reviewed + if len(loaded) < len(raw): + missing = set(raw) - set(loaded) + for item in sorted(missing): + region, period, tech, oc, _ = item + logger.warning( + 'Technology Output Split Annual requirement in region %s, period %d for tech %s with output' + 'commodity %s has ' + 'been removed because the tech path with that output is ' + 'invalid/not available/orphan. See the other warnings for this TECH in ' + 'this region-period, and check for availability of all components in data.', + region, + period, + tech, + oc, + ) + + # MaxTechInputSplit + if self.table_exists('MaxTechInputSplit'): + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, input_comm, tech, max_proportion FROM main.MaxTechInputSplit', mi=mi) + loaded = load_element(M.MaxTechInputSplit, raw, self.viable_rpit, (0, 1, 2, 3)) + # we need to see if anything was filtered out here and raise warning if so as it may have invalidated + # a blending process and any missing items should be reviewed + if len(loaded) < len(raw): + missing = set(raw) - set(loaded) + for item in sorted(missing, key=lambda x: (x[0], x[1], x[3], x[2])): + region, period, ic, tech, _ = item + logger.warning( + 'Technology Input Split requirement in region %s, period %d for tech %s with input' + 'commodity %s has ' + 'been removed because the tech path with that input is ' + 'invalid/not available/orphan. See the other warnings for this TECH in ' + 'this region-period, and check for availability of all components in data.', + region, + period, + tech, + ic, + ) + + # MaxTechInputSplitAnnual + if self.table_exists('MaxTechInputSplitAnnual'): + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, input_comm, tech, max_proportion FROM main.MaxTechInputSplitAnnual', mi=mi) + loaded = load_element(M.MaxTechInputSplitAnnual, raw, self.viable_rpit, (0, 1, 2, 3)) + # we need to see if anything was filtered out here and raise warning if so as it may have invalidated + # a blending process and any missing items should be reviewed + if len(loaded) < len(raw): + missing = set(raw) - set(loaded) + for item in sorted(missing, key=lambda x: (x[0], x[1], x[3], x[2])): + region, period, ic, tech, _ = item + logger.warning( + 'Technology Input Split Annual requirement in region %s, period %d for tech %s with input' + 'commodity %s has ' + 'been removed because the tech path with that input is ' + 'invalid/not available/orphan. See the other warnings for this TECH in ' + 'this region-period, and check for availability of all components in data.', + region, + period, + tech, + ic, + ) + + # MaxTechOutputSplit + if self.table_exists('MaxTechOutputSplit'): + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, output_comm, max_proportion FROM main.MaxTechOutputSplit', mi=mi) + loaded = load_element(M.MaxTechOutputSplit, raw, self.viable_rpto, (0, 1, 2, 3)) + # raise warning regarding any deletions here... similar to input split above + if len(loaded) < len(raw): + missing = set(raw) - set(loaded) + for item in sorted(missing): + region, period, tech, oc, _ = item + logger.warning( + 'Technology Output Split requirement in region %s, period %d for tech %s with output' + 'commodity %s has ' + 'been removed because the tech path with that output is ' + 'invalid/not available/orphan. See the other warnings for this TECH in ' + 'this region-period, and check for availability of all components in data.', + region, + period, + tech, + oc, + ) + + # MaxTechOutputSplitAnnual + if self.table_exists('MaxTechOutputSplitAnnual'): + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, output_comm, max_proportion FROM main.MaxTechOutputSplitAnnual', mi=mi) + loaded = load_element(M.MaxTechOutputSplitAnnual, raw, self.viable_rpto, (0, 1, 2, 3)) # we need to see if anything was filtered out here and raise warning if so as it may have invalidated # a blending process and any missing items should be reviewed if len(loaded) < len(raw): diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index d778a2f60..a5a8ec405 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -728,34 +728,67 @@ def CreateSparseDicts(M: 'TemoaModel'): M.rampUpVintages[r, p, t] = set() if t in M.tech_downramping and (r, p, t) not in M.rampDownVintages: M.rampDownVintages[r, p, t] = set() - if (r, p, i, t) in M.TechInputSplit.sparse_iterkeys() and ( + + # min tech split + if (r, p, i, t) in M.MinTechInputSplit.sparse_iterkeys() and ( r, p, i, t, - ) not in M.inputsplitVintages: - M.inputsplitVintages[r, p, i, t] = set() - if (r, p, i, t) in M.TechInputSplitAnnual.sparse_iterkeys() and ( + ) not in M.minInputSplitVintages: + M.minInputSplitVintages[r, p, i, t] = set() + if (r, p, i, t) in M.MinTechInputSplitAnnual.sparse_iterkeys() and ( r, p, i, t, - ) not in M.inputsplitannualVintages: - M.inputsplitannualVintages[r, p, i, t] = set() - if (r, p, t, o) in M.TechOutputSplit.sparse_iterkeys() and ( + ) not in M.minInputSplitAnnualVintages: + M.minInputSplitAnnualVintages[r, p, i, t] = set() + if (r, p, t, o) in M.MinTechOutputSplit.sparse_iterkeys() and ( r, p, t, o, - ) not in M.outputsplitVintages: - M.outputsplitVintages[r, p, t, o] = set() - if (r, p, t, o) in M.TechOutputSplitAnnual.sparse_iterkeys() and ( + ) not in M.minOutputSplitVintages: + M.minOutputSplitVintages[r, p, t, o] = set() + if (r, p, t, o) in M.MinTechOutputSplitAnnual.sparse_iterkeys() and ( r, p, t, o, - ) not in M.outputsplitannualVintages: - M.outputsplitannualVintages[r, p, t, o] = set() + ) not in M.minOutputSplitAnnualVintages: + M.minOutputSplitAnnualVintages[r, p, t, o] = set() + + # max tech split + if (r, p, i, t) in M.MaxTechInputSplit.sparse_iterkeys() and ( + r, + p, + i, + t, + ) not in M.maxInputSplitVintages: + M.maxInputSplitVintages[r, p, i, t] = set() + if (r, p, i, t) in M.MaxTechInputSplitAnnual.sparse_iterkeys() and ( + r, + p, + i, + t, + ) not in M.maxInputSplitAnnualVintages: + M.maxInputSplitAnnualVintages[r, p, i, t] = set() + if (r, p, t, o) in M.MaxTechOutputSplit.sparse_iterkeys() and ( + r, + p, + t, + o, + ) not in M.maxOutputSplitVintages: + M.maxOutputSplitVintages[r, p, t, o] = set() + if (r, p, t, o) in M.MaxTechOutputSplitAnnual.sparse_iterkeys() and ( + r, + p, + t, + o, + ) not in M.maxOutputSplitAnnualVintages: + M.maxOutputSplitAnnualVintages[r, p, t, o] = set() + if t in M.tech_resource and (r, p, o) not in M.ProcessByPeriodAndOutput: M.ProcessByPeriodAndOutput[r, p, o] = set() if t in M.tech_reserve and (r, p) not in M.processReservePeriods: @@ -789,14 +822,27 @@ def CreateSparseDicts(M: 'TemoaModel'): M.rampUpVintages[r, p, t].add(v) if t in M.tech_upramping: M.rampDownVintages[r, p, t].add(v) - if (r, p, i, t) in M.TechInputSplit.sparse_iterkeys(): - M.inputsplitVintages[r, p, i, t].add(v) - if (r, p, i, t) in M.TechInputSplitAnnual.sparse_iterkeys(): - M.inputsplitannualVintages[r, p, i, t].add(v) - if (r, p, t, o) in M.TechOutputSplit.sparse_iterkeys(): - M.outputsplitVintages[r, p, t, o].add(v) - if (r, p, t, o) in M.TechOutputSplitAnnual.sparse_iterkeys(): - M.outputsplitannualVintages[r, p, t, o].add(v) + + # min tech split + if (r, p, i, t) in M.MinTechInputSplit.sparse_iterkeys(): + M.minInputSplitVintages[r, p, i, t].add(v) + if (r, p, i, t) in M.MinTechInputSplitAnnual.sparse_iterkeys(): + M.minInputSplitAnnualVintages[r, p, i, t].add(v) + if (r, p, t, o) in M.MinTechOutputSplit.sparse_iterkeys(): + M.minOutputSplitVintages[r, p, t, o].add(v) + if (r, p, t, o) in M.MinTechOutputSplitAnnual.sparse_iterkeys(): + M.minInputSplitAnnualVintages[r, p, t, o].add(v) + + # max tech split + if (r, p, i, t) in M.MaxTechInputSplit.sparse_iterkeys(): + M.maxInputSplitVintages[r, p, i, t].add(v) + if (r, p, i, t) in M.MaxTechInputSplitAnnual.sparse_iterkeys(): + M.maxInputSplitAnnualVintages[r, p, i, t].add(v) + if (r, p, t, o) in M.MaxTechOutputSplit.sparse_iterkeys(): + M.maxOutputSplitVintages[r, p, t, o].add(v) + if (r, p, t, o) in M.MaxTechOutputSplitAnnual.sparse_iterkeys(): + M.maxInputSplitAnnualVintages[r, p, t, o].add(v) + if t in M.tech_resource: M.ProcessByPeriodAndOutput[r, p, o].add((i, t, v)) if t in M.tech_reserve: @@ -1352,18 +1398,108 @@ def ReserveMarginIndices(M: 'TemoaModel'): return indices -def TechInputSplitConstraintIndices(M: 'TemoaModel'): +def MinTechInputSplitConstraintIndices(M: 'TemoaModel'): + indices = set( + (r, p, s, d, i, t, v) + for r, p, i, t in M.minInputSplitVintages.keys() + if t not in M.tech_annual + for v in M.minInputSplitVintages[r, p, i, t] + for s in M.time_season + for d in M.time_of_day + ) + ann_indices = set( + (r, p, i, t) + for r, p, i, t in M.minInputSplitVintages.keys() + if t in M.tech_annual + ) + if len(ann_indices) > 0: + msg = ( + "Warning: Annual technologies included in TechInputSplit table. " + "Use TechInputSplitAnnual table instead or these constraints will be ignored: {}" + ) + logger.warning(msg.format(ann_indices)) + + return indices + + +def MinTechInputSplitAnnualConstraintIndices(M: 'TemoaModel'): + indices = set( + (r, p, i, t, v) + for r, p, i, t in M.minInputSplitAnnualVintages.keys() + if t in M.tech_annual + for v in M.minInputSplitAnnualVintages[r, p, i, t] + ) + + return indices + + +def MinTechInputSplitAverageConstraintIndices(M: 'TemoaModel'): + indices = set( + (r, p, i, t, v) + for r, p, i, t in M.minInputSplitAnnualVintages.keys() + if t not in M.tech_annual + for v in M.minInputSplitAnnualVintages[r, p, i, t] + ) + return indices + + +def MinTechOutputSplitConstraintIndices(M: 'TemoaModel'): + indices = set( + (r, p, s, d, t, v, o) + for r, p, t, o in M.minOutputSplitVintages.keys() + if t not in M.tech_annual + for v in M.minOutputSplitVintages[r, p, t, o] + for s in M.time_season + for d in M.time_of_day + ) + ann_indices = set( + (r, p, t, o) + for r, p, t, o in M.minOutputSplitVintages.keys() + if t in M.tech_annual + ) + if len(ann_indices) > 0: + msg = ( + "Warning: Annual technologies included in TechOutputSplit table. " + "Use TechOutputSplitAnnual table instead or these constraints will be ignored: {}" + ) + logger.warning(msg.format(ann_indices)) + + return indices + + +def MinTechOutputSplitAnnualConstraintIndices(M: 'TemoaModel'): + indices = set( + (r, p, t, v, o) + for r, p, t, o in M.minOutputSplitAnnualVintages.keys() + if t in M.tech_annual + for v in M.minOutputSplitAnnualVintages[r, p, t, o] + ) + + return indices + + +def MinTechOutputSplitAverageConstraintIndices(M: 'TemoaModel'): + indices = set( + (r, p, t, v, o) + for r, p, t, o in M.minOutputSplitAnnualVintages.keys() + if t not in M.tech_annual + for v in M.minOutputSplitAnnualVintages[r, p, t, o] + ) + return indices + + +def MaxTechInputSplitConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, s, d, i, t, v) - for r, p, i, t in M.inputsplitVintages.keys() + for r, p, i, t in M.maxInputSplitVintages.keys() if t not in M.tech_annual - for v in M.inputsplitVintages[r, p, i, t] + for v in M.maxInputSplitVintages[r, p, i, t] for s in M.time_season for d in M.time_of_day ) ann_indices = set( (r, p, i, t) - for r, p, i, t in M.inputsplitVintages.keys() + for r, p, i, t in M.maxInputSplitVintages.keys() if t in M.tech_annual ) if len(ann_indices) > 0: @@ -1376,39 +1512,39 @@ def TechInputSplitConstraintIndices(M: 'TemoaModel'): return indices -def TechInputSplitAnnualConstraintIndices(M: 'TemoaModel'): +def MaxTechInputSplitAnnualConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, i, t, v) - for r, p, i, t in M.inputsplitannualVintages.keys() + for r, p, i, t in M.maxInputSplitAnnualVintages.keys() if t in M.tech_annual - for v in M.inputsplitannualVintages[r, p, i, t] + for v in M.maxInputSplitAnnualVintages[r, p, i, t] ) return indices -def TechInputSplitAverageConstraintIndices(M: 'TemoaModel'): +def MaxTechInputSplitAverageConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, i, t, v) - for r, p, i, t in M.inputsplitannualVintages.keys() + for r, p, i, t in M.maxInputSplitAnnualVintages.keys() if t not in M.tech_annual - for v in M.inputsplitannualVintages[r, p, i, t] + for v in M.maxInputSplitAnnualVintages[r, p, i, t] ) return indices -def TechOutputSplitConstraintIndices(M: 'TemoaModel'): +def MaxTechOutputSplitConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, s, d, t, v, o) - for r, p, t, o in M.outputsplitVintages.keys() + for r, p, t, o in M.maxOutputSplitVintages.keys() if t not in M.tech_annual - for v in M.outputsplitVintages[r, p, t, o] + for v in M.maxOutputSplitVintages[r, p, t, o] for s in M.time_season for d in M.time_of_day ) ann_indices = set( (r, p, t, o) - for r, p, t, o in M.outputsplitVintages.keys() + for r, p, t, o in M.maxOutputSplitVintages.keys() if t in M.tech_annual ) if len(ann_indices) > 0: @@ -1421,23 +1557,23 @@ def TechOutputSplitConstraintIndices(M: 'TemoaModel'): return indices -def TechOutputSplitAnnualConstraintIndices(M: 'TemoaModel'): +def MaxTechOutputSplitAnnualConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, t, v, o) - for r, p, t, o in M.outputsplitannualVintages.keys() + for r, p, t, o in M.maxOutputSplitAnnualVintages.keys() if t in M.tech_annual - for v in M.outputsplitannualVintages[r, p, t, o] + for v in M.maxOutputSplitAnnualVintages[r, p, t, o] ) return indices -def TechOutputSplitAverageConstraintIndices(M: 'TemoaModel'): +def MaxTechOutputSplitAverageConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, t, v, o) - for r, p, t, o in M.outputsplitannualVintages.keys() + for r, p, t, o in M.maxOutputSplitAnnualVintages.keys() if t not in M.tech_annual - for v in M.outputsplitannualVintages[r, p, t, o] + for v in M.maxOutputSplitAnnualVintages[r, p, t, o] ) return indices diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 4b4d41d7a..0280ed34d 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -109,10 +109,14 @@ def __init__(M, *args, **kwargs): M.storageVintages = dict() M.rampUpVintages = dict() M.rampDownVintages = dict() - M.inputsplitVintages = dict() - M.inputsplitannualVintages = dict() - M.outputsplitVintages = dict() - M.outputsplitannualVintages = dict() + M.minInputSplitVintages = dict() + M.minInputSplitAnnualVintages = dict() + M.maxInputSplitVintages = dict() + M.maxInputSplitAnnualVintages = dict() + M.minOutputSplitVintages = dict() + M.minOutputSplitAnnualVintages = dict() + M.maxOutputSplitVintages = dict() + M.maxOutputSplitAnnualVintages = dict() M.ProcessByPeriodAndOutput = dict() M.exportRegions = dict() M.importRegions = dict() @@ -294,10 +298,18 @@ def __init__(M, *args, **kwargs): M.LoanLifetimeProcess = Param(M.LoanLifetimeProcess_rtv, default=get_loan_life) - M.TechInputSplit = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all) - M.TechInputSplitAnnual = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all) - M.TechOutputSplit = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier) - M.TechOutputSplitAnnual = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier) + # Min tech input split + M.MinTechInputSplit = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all) + M.MinTechInputSplitAnnual = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all) + # Min tech output split + M.MinTechOutputSplit = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier) + M.MinTechOutputSplitAnnual = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier) + # Max tech input split + M.MaxTechInputSplit = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all) + M.MaxTechInputSplitAnnual = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all) + # Max tech output split + M.MaxTechOutputSplit = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier) + M.MaxTechOutputSplitAnnual = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier) M.RenewablePortfolioStandardConstraint_rpg = Set( within=M.regions * M.time_optimize * M.tech_group_names @@ -774,47 +786,93 @@ def __init__(M, *args, **kwargs): M.MaxAnnualCapacityFactorConstraint = Constraint( M.MaxAnnualCapacityFactorConstraint_rpto, rule=MaxAnnualCapacityFactor_Constraint ) + + ## Min tech input splits + M.MinTechInputSplitConstraint_rpsditv = Set( + dimen=7, initialize=MinTechInputSplitConstraintIndices + ) + M.MinTechInputSplitConstraint = Constraint( + M.MinTechInputSplitConstraint_rpsditv, rule=MinTechInputSplit_Constraint + ) + + M.MinTechInputSplitAnnualConstraint_rpitv = Set( + dimen=5, initialize=MinTechInputSplitAnnualConstraintIndices + ) + M.MinTechInputSplitAnnualConstraint = Constraint( + M.MinTechInputSplitAnnualConstraint_rpitv, rule=MinTechInputSplitAnnual_Constraint + ) + + M.MinTechInputSplitAverageConstraint_rpitv = Set( + dimen=5, initialize=MinTechInputSplitAverageConstraintIndices + ) + M.MinTechInputSplitAverageConstraint = Constraint( + M.MinTechInputSplitAverageConstraint_rpitv, rule=MinTechInputSplitAverage_Constraint + ) + + ## Min tech output splits + M.MinTechOutputSplitConstraint_rpsdtvo = Set( + dimen=7, initialize=MinTechOutputSplitConstraintIndices + ) + M.MinTechOutputSplitConstraint = Constraint( + M.MinTechOutputSplitConstraint_rpsdtvo, rule=MinTechOutputSplit_Constraint + ) + + M.MinTechOutputSplitAnnualConstraint_rptvo = Set( + dimen=5, initialize=MinTechOutputSplitAnnualConstraintIndices + ) + M.MinTechOutputSplitAnnualConstraint = Constraint( + M.MinTechOutputSplitAnnualConstraint_rptvo, rule=MinTechOutputSplitAnnual_Constraint + ) + + M.MinTechOutputSplitAverageConstraint_rptvo = Set( + dimen=5, initialize=MinTechOutputSplitAverageConstraintIndices + ) + M.MinTechOutputSplitAverageConstraint = Constraint( + M.MinTechOutputSplitAverageConstraint_rptvo, rule=MinTechOutputSplitAverage_Constraint + ) - M.TechInputSplitConstraint_rpsditv = Set( - dimen=7, initialize=TechInputSplitConstraintIndices + ## Max tech input splits + M.MaxTechInputSplitConstraint_rpsditv = Set( + dimen=7, initialize=MaxTechInputSplitConstraintIndices ) - M.TechInputSplitConstraint = Constraint( - M.TechInputSplitConstraint_rpsditv, rule=TechInputSplit_Constraint + M.MaxTechInputSplitConstraint = Constraint( + M.MaxTechInputSplitConstraint_rpsditv, rule=MaxTechInputSplit_Constraint ) - M.TechInputSplitAnnualConstraint_rpitv = Set( - dimen=5, initialize=TechInputSplitAnnualConstraintIndices + M.MaxTechInputSplitAnnualConstraint_rpitv = Set( + dimen=5, initialize=MaxTechInputSplitAnnualConstraintIndices ) - M.TechInputSplitAnnualConstraint = Constraint( - M.TechInputSplitAnnualConstraint_rpitv, rule=TechInputSplitAnnual_Constraint + M.MaxTechInputSplitAnnualConstraint = Constraint( + M.MaxTechInputSplitAnnualConstraint_rpitv, rule=MaxTechInputSplitAnnual_Constraint ) - M.TechInputSplitAverageConstraint_rpitv = Set( - dimen=5, initialize=TechInputSplitAverageConstraintIndices + M.MaxTechInputSplitAverageConstraint_rpitv = Set( + dimen=5, initialize=MaxTechInputSplitAverageConstraintIndices ) - M.TechInputSplitAverageConstraint = Constraint( - M.TechInputSplitAverageConstraint_rpitv, rule=TechInputSplitAverage_Constraint + M.MaxTechInputSplitAverageConstraint = Constraint( + M.MaxTechInputSplitAverageConstraint_rpitv, rule=MaxTechInputSplitAverage_Constraint ) - M.TechOutputSplitConstraint_rpsdtvo = Set( - dimen=7, initialize=TechOutputSplitConstraintIndices + ## Max tech output splits + M.MaxTechOutputSplitConstraint_rpsdtvo = Set( + dimen=7, initialize=MaxTechOutputSplitConstraintIndices ) - M.TechOutputSplitConstraint = Constraint( - M.TechOutputSplitConstraint_rpsdtvo, rule=TechOutputSplit_Constraint + M.MaxTechOutputSplitConstraint = Constraint( + M.MaxTechOutputSplitConstraint_rpsdtvo, rule=MaxTechOutputSplit_Constraint ) - M.TechOutputSplitAnnualConstraint_rptvo = Set( - dimen=5, initialize=TechOutputSplitAnnualConstraintIndices + M.MaxTechOutputSplitAnnualConstraint_rptvo = Set( + dimen=5, initialize=MaxTechOutputSplitAnnualConstraintIndices ) - M.TechOutputSplitAnnualConstraint = Constraint( - M.TechOutputSplitAnnualConstraint_rptvo, rule=TechOutputSplitAnnual_Constraint + M.MaxTechOutputSplitAnnualConstraint = Constraint( + M.MaxTechOutputSplitAnnualConstraint_rptvo, rule=MaxTechOutputSplitAnnual_Constraint ) - M.TechOutputSplitAverageConstraint_rptvo = Set( - dimen=5, initialize=TechOutputSplitAverageConstraintIndices + M.MaxTechOutputSplitAverageConstraint_rptvo = Set( + dimen=5, initialize=MaxTechOutputSplitAverageConstraintIndices ) - M.TechOutputSplitAverageConstraint = Constraint( - M.TechOutputSplitAverageConstraint_rptvo, rule=TechOutputSplitAverage_Constraint + M.MaxTechOutputSplitAverageConstraint = Constraint( + M.MaxTechOutputSplitAverageConstraint_rptvo, rule=MaxTechOutputSplitAverage_Constraint ) M.RenewablePortfolioStandardConstraint = Constraint( diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 64032ebbb..f0295ab39 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -2689,11 +2689,11 @@ def MaxAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o): return expr -def TechInputSplit_Constraint(M: 'TemoaModel', r, p, s, d, i, t, v): +def MinTechInputSplit_Constraint(M: 'TemoaModel', r, p, s, d, i, t, v): r""" Allows users to specify fixed or minimum shares of commodity inputs to a process producing a single output. These shares can vary by model time period. See - TechOutputSplit_Constraint for an analogous explanation. Under this constraint, + MinTechOutputSplit_Constraint for an analogous explanation. Under this constraint, only the technologies with variable output at the timeslice level (i.e., NOT in the :code:`tech_annual` set) are considered.""" inp = sum( @@ -2707,15 +2707,15 @@ def TechInputSplit_Constraint(M: 'TemoaModel', r, p, s, d, i, t, v): for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] ) - expr = inp >= M.TechInputSplit[r, p, i, t] * total_inp + expr = inp >= M.MinTechInputSplit[r, p, i, t] * total_inp return expr -def TechInputSplitAnnual_Constraint(M: 'TemoaModel', r, p, i, t, v): +def MinTechInputSplitAnnual_Constraint(M: 'TemoaModel', r, p, i, t, v): r""" Allows users to specify fixed or minimum shares of commodity inputs to a process producing a single output. These shares can vary by model time period. See - TechOutputSplitAnnual_Constraint for an analogous explanation. Under this + MinTechOutputSplitAnnual_Constraint for an analogous explanation. Under this function, only the technologies with constant annual output (i.e., members of the :math:`tech_annual` set) are considered.""" inp = sum( @@ -2729,16 +2729,16 @@ def TechInputSplitAnnual_Constraint(M: 'TemoaModel', r, p, i, t, v): for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] ) - expr = inp >= M.TechInputSplitAnnual[r, p, i, t] * total_inp + expr = inp >= M.MinTechInputSplitAnnual[r, p, i, t] * total_inp return expr -def TechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v): +def MinTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v): r""" Allows users to specify fixed or minimum shares of commodity inputs to a process 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, + This constraint differs from MinTechInputSplit 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.""" @@ -2757,11 +2757,11 @@ def TechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v): for S_o in M.ProcessOutputsByInput[r, p, t, v, i] ) - expr = inp >= M.TechInputSplitAnnual[r, p, i, t] * total_inp + expr = inp >= M.MinTechInputSplitAnnual[r, p, i, t] * total_inp return expr -def TechOutputSplit_Constraint(M: 'TemoaModel', r, p, s, d, t, v, o): +def MinTechOutputSplit_Constraint(M: 'TemoaModel', r, p, s, d, t, v, o): r""" Some processes take a single input and make multiple outputs, and the user would like to @@ -2789,13 +2789,13 @@ def TechOutputSplit_Constraint(M: 'TemoaModel', r, p, s, d, t, v, o): The constraint is formulated as follows: .. math:: - :label: TechOutputSplit + :label: MinTechOutputSplit \sum_{I, t \not \in T^{a}} \textbf{FO}_{r, p, s, d, i, t, v, o} \geq TOS_{r, p, t, o} \cdot \sum_{I, O, t \not \in T^{a}} \textbf{FO}_{r, p, s, d, i, t, v, o} - \forall \{r, p, s, d, t, v, o\} \in \Theta_{\text{TechOutputSplit}}""" + \forall \{r, p, s, d, t, v, o\} \in \Theta_{\text{MinTechOutputSplit}}""" out = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, o] for S_i in M.ProcessInputsByOutput[r, p, t, v, o] ) @@ -2806,18 +2806,18 @@ def TechOutputSplit_Constraint(M: 'TemoaModel', r, p, s, d, t, v, o): for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] ) - expr = out >= M.TechOutputSplit[r, p, t, o] * total_out + expr = out >= M.MinTechOutputSplit[r, p, t, o] * total_out return expr -def TechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o): +def MinTechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o): r""" - This constraint operates similarly to TechOutputSplit_Constraint. + This constraint operates similarly to MinTechOutputSplit_Constraint. However, under this function, only the technologies with constant annual output (i.e., members of the :math:`tech_annual` set) are considered. .. math:: - :label: TechOutputSplitAnnual + :label: MinTechOutputSplitAnnual \sum_{I, T^{a}} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} @@ -2825,7 +2825,7 @@ def TechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o): TOS_{r, p, t, o} \cdot \sum_{I, O, T^{a}} \textbf{FOA}_{r, p, s, d, i, t \in T^{a}, v, o} - \forall \{r, p, t \in T^{a}, v, o\} \in \Theta_{\text{TechOutputSplitAnnual}}""" + \forall \{r, p, t \in T^{a}, v, o\} \in \Theta_{\text{MinTechOutputSplitAnnual}}""" out = sum( M.V_FlowOutAnnual[r, p, S_i, t, v, o] for S_i in M.ProcessInputsByOutput[r, p, t, v, o] ) @@ -2836,16 +2836,16 @@ def TechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o): for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] ) - expr = out >= M.TechOutputSplitAnnual[r, p, t, o] * total_out + expr = out >= M.MinTechOutputSplitAnnual[r, p, t, o] * total_out return expr -def TechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o): +def MinTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o): r""" Allows users to specify fixed or minimum shares of commodity outputs from a process. 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 TechOutputSplit as it specifies shares on an annual basis, + This constraint differs from MinTechOutputSplit 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 output shares over the course of a year.""" @@ -2864,7 +2864,186 @@ def TechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o): for S_d in M.time_of_day ) - expr = out >= M.TechOutputSplitAnnual[r, p, t, o] * total_out + expr = out >= M.MinTechOutputSplitAnnual[r, p, t, o] * total_out + return expr + + +def MaxTechInputSplit_Constraint(M: 'TemoaModel', r, p, s, d, i, t, v): + r""" + Allows users to specify fixed or minimum shares of commodity inputs to a process + producing a single output. These shares can vary by model time period. See + MaxTechOutputSplit_Constraint for an analogous explanation. Under this constraint, + only the technologies with variable output at the timeslice level (i.e., + NOT in the :code:`tech_annual` set) are considered.""" + inp = sum( + M.V_FlowOut[r, p, s, d, i, t, v, S_o] / value(M.Efficiency[r, i, t, v, S_o]) + for S_o in M.ProcessOutputsByInput[r, p, t, v, i] + ) + + total_inp = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] / value(M.Efficiency[r, S_i, t, v, S_o]) + for S_i in M.processInputs[r, p, t, v] + for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + ) + + expr = inp <= M.MaxTechInputSplit[r, p, i, t] * total_inp + return expr + + +def MaxTechInputSplitAnnual_Constraint(M: 'TemoaModel', r, p, i, t, v): + r""" + Allows users to specify fixed or minimum shares of commodity inputs to a process + producing a single output. These shares can vary by model time period. See + MaxTechOutputSplitAnnual_Constraint for an analogous explanation. Under this + function, only the technologies with constant annual output (i.e., members + of the :math:`tech_annual` set) are considered.""" + inp = sum( + M.V_FlowOutAnnual[r, p, i, t, v, S_o] / value(M.Efficiency[r, i, t, v, S_o]) + for S_o in M.ProcessOutputsByInput[r, p, t, v, i] + ) + + total_inp = sum( + M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] / value(M.Efficiency[r, S_i, t, v, S_o]) + for S_i in M.processInputs[r, p, t, v] + for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + ) + + expr = inp <= M.MaxTechInputSplitAnnual[r, p, i, t] * total_inp + return expr + + +def MaxTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v): + r""" + Allows users to specify fixed or minimum shares of commodity inputs to a process + 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 MaxTechInputSplit 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.""" + + inp = sum( + M.V_FlowOut[r, p, s, d, i, t, v, S_o] / value(M.Efficiency[r, i, t, v, S_o]) + for s in M.time_season + for d in M.time_of_day + for S_o in M.ProcessOutputsByInput[r, p, t, v, i] + ) + + total_inp = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] / value(M.Efficiency[r, S_i, t, v, S_o]) + for s in M.time_season + for d in M.time_of_day + for S_i in M.processInputs[r, p, t, v] + for S_o in M.ProcessOutputsByInput[r, p, t, v, i] + ) + + expr = inp <= M.MaxTechInputSplitAnnual[r, p, i, t] * total_inp + return expr + + +def MaxTechOutputSplit_Constraint(M: 'TemoaModel', r, p, s, d, t, v, o): + r""" + + Some processes take a single input and make multiple outputs, and the user would like to + specify either a constant or time-varying ratio of outputs per unit input. The most + canonical example is an oil refinery. Crude oil is used to produce many different refined + products. In many cases, the modeler would like to specify a minimum share of each refined + product produced by the refinery. + + For example, a hypothetical (and highly simplified) refinery might have a crude oil input + that produces 4 parts diesel, 3 parts gasoline, and 2 parts kerosene. The relative + ratios to the output then are: + + .. math:: + + d = \tfrac{4}{9} \cdot \text{total output}, \qquad + g = \tfrac{3}{9} \cdot \text{total output}, \qquad + k = \tfrac{2}{9} \cdot \text{total output} + + Note that it is possible to specify output shares that sum to less than unity. In such + cases, the model optimizes the remaining share. In addition, it is possible to change the + specified shares by model time period. Under this constraint, only the + technologies with variable output at the timeslice level (i.e., NOT in the + :code:`tech_annual` set) are considered. + + The constraint is formulated as follows: + + .. math:: + :label: MaxTechOutputSplit + + \sum_{I, t \not \in T^{a}} \textbf{FO}_{r, p, s, d, i, t, v, o} + \geq + TOS_{r, p, t, o} \cdot \sum_{I, O, t \not \in T^{a}} \textbf{FO}_{r, p, s, d, i, t, v, o} + + \forall \{r, p, s, d, t, v, o\} \in \Theta_{\text{MaxTechOutputSplit}}""" + out = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, o] for S_i in M.ProcessInputsByOutput[r, p, t, v, o] + ) + + total_out = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + ) + + expr = out <= M.MaxTechOutputSplit[r, p, t, o] * total_out + return expr + + +def MaxTechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o): + r""" + This constraint operates similarly to MaxTechOutputSplit_Constraint. + However, under this function, only the technologies with constant annual + output (i.e., members of the :math:`tech_annual` set) are considered. + + .. math:: + :label: MaxTechOutputSplitAnnual + + \sum_{I, T^{a}} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} + + \geq + + TOS_{r, p, t, o} \cdot \sum_{I, O, T^{a}} \textbf{FOA}_{r, p, s, d, i, t \in T^{a}, v, o} + + \forall \{r, p, t \in T^{a}, v, o\} \in \Theta_{\text{MaxTechOutputSplitAnnual}}""" + out = sum( + M.V_FlowOutAnnual[r, p, S_i, t, v, o] for S_i in M.ProcessInputsByOutput[r, p, t, v, o] + ) + + total_out = sum( + M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + ) + + expr = out <= M.MaxTechOutputSplitAnnual[r, p, t, o] * total_out + return expr + + +def MaxTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o): + r""" + Allows users to specify fixed or minimum shares of commodity outputs from a process. + 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 MaxTechOutputSplit 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 output shares over the course of a year.""" + + out = sum( + M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, o] + for S_i in M.ProcessInputsByOutput[r, p, t, v, o] + for S_s in M.time_season + for S_d in M.time_of_day + ) + + total_out = sum( + M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_s in M.time_season + for S_d in M.time_of_day + ) + + expr = out <= M.MaxTechOutputSplitAnnual[r, p, t, o] * total_out return expr diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 53296ebbd..2a50cec3a 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -631,7 +631,7 @@ INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE TechInputSplit +CREATE TABLE MinTechInputSplit ( region TEXT, period INTEGER @@ -644,7 +644,7 @@ CREATE TABLE TechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechInputSplitAnnual +CREATE TABLE MinTechInputSplitAnnual ( region TEXT, period INTEGER @@ -657,7 +657,7 @@ CREATE TABLE TechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechOutputSplit +CREATE TABLE MinTechOutputSplit ( region TEXT, period INTEGER diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 06afbc417..fd4b0b35a 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -700,7 +700,7 @@ INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE TechInputSplit +CREATE TABLE MinTechInputSplit ( region TEXT, period INTEGER @@ -713,8 +713,8 @@ CREATE TABLE TechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -INSERT INTO TechInputSplit VALUES('A',2025,'HYD','EH',0.949999999999999956,'95% HYD reqt. (other not specified...)'); -CREATE TABLE TechInputSplitAnnual +INSERT INTO MinTechInputSplit VALUES('A',2025,'HYD','EH',0.949999999999999956,'95% HYD reqt. (other not specified...)'); +CREATE TABLE MinTechInputSplitAnnual ( region TEXT, period INTEGER @@ -727,8 +727,8 @@ CREATE TABLE TechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -INSERT INTO TechInputSplitAnnual VALUES('A',2025,'GeoHyd','GeoHeater',0.8000000000000000444,'80% geothermal'); -CREATE TABLE TechOutputSplit +INSERT INTO MinTechInputSplitAnnual VALUES('A',2025,'GeoHyd','GeoHeater',0.8000000000000000444,'80% geothermal'); +CREATE TABLE MinTechOutputSplit ( region TEXT, period INTEGER @@ -741,7 +741,7 @@ CREATE TABLE TechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm) ); -INSERT INTO TechOutputSplit VALUES('B',2025,'EH','ELC',0.949999999999999956,'95% ELC output (there are not others, this is a min)'); +INSERT INTO MinTechOutputSplit VALUES('B',2025,'EH','ELC',0.949999999999999956,'95% ELC output (there are not others, this is a min)'); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 02fc33ccc..1e5a10cf2 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -4221,7 +4221,7 @@ "GeoHeater" ] ], - "TechInputSplitConstraint_rpsditv": [ + "MinTechInputSplitConstraint_rpsditv": [ [ "A", 2025, @@ -4259,8 +4259,8 @@ 2025 ] ], - "TechInputSplitAnnualConstraint_rpitv": [], - "TechInputSplitAverageConstraint_rpitv": [ + "MinTechInputSplitAnnualConstraint_rpitv": [], + "MinTechInputSplitAverageConstraint_rpitv": [ [ "A", 2025, @@ -4269,7 +4269,7 @@ 2025 ] ], - "TechOutputSplitConstraint_rpsdtvo": [ + "MinTechOutputSplitConstraint_rpsdtvo": [ [ "B", 2025, @@ -4307,8 +4307,14 @@ "ELC" ] ], - "TechOutputSplitAnnualConstraint_rptvo": [], - "TechOutputSplitAverageConstraint_rptvo": [], + "MinTechOutputSplitAnnualConstraint_rptvo": [], + "MinTechOutputSplitAverageConstraint_rptvo": [], + "MaxTechInputSplitConstraint_rpsditv": [], + "MaxTechInputSplitAnnualConstraint_rpitv": [], + "MaxTechInputSplitAverageConstraint_rpitv": [], + "MaxTechOutputSplitConstraint_rpsdtvo": [], + "MaxTechOutputSplitAnnualConstraint_rptvo": [], + "MaxTechOutputSplitAverageConstraint_rptvo": [], "MaxSeasonalActivityConstraint_rpst": [], "MinSeasonalActivityConstraint_rpst": [], "LinkedEmissionsTechConstraint_rpsdtve": [ diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index 0ede3b641..36c6979fe 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -598,7 +598,7 @@ INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE TechInputSplit +CREATE TABLE MinTechInputSplit ( region TEXT, period INTEGER @@ -611,7 +611,7 @@ CREATE TABLE TechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechInputSplitAnnual +CREATE TABLE MinTechInputSplitAnnual ( region TEXT, period INTEGER @@ -624,7 +624,7 @@ CREATE TABLE TechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechOutputSplit +CREATE TABLE MinTechOutputSplit ( region TEXT, period INTEGER diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index 9b951fa4a..a5eadacd7 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -624,7 +624,7 @@ INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE TechInputSplit +CREATE TABLE MinTechInputSplit ( region TEXT, period INTEGER @@ -637,7 +637,7 @@ CREATE TABLE TechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechInputSplitAnnual +CREATE TABLE MinTechInputSplitAnnual ( region TEXT, period INTEGER @@ -650,7 +650,7 @@ CREATE TABLE TechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechOutputSplit +CREATE TABLE MinTechOutputSplit ( region TEXT, period INTEGER diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index e0234665e..2aa22f3de 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -1005,7 +1005,7 @@ INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE TechInputSplit +CREATE TABLE MinTechInputSplit ( region TEXT, period INTEGER @@ -1018,19 +1018,19 @@ CREATE TABLE TechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -INSERT INTO TechInputSplit VALUES('R1',2020,'GSL','T_BLND',0.9000000000000000222,''); -INSERT INTO TechInputSplit VALUES('R1',2020,'ETH','T_BLND',0.1000000000000000055,''); -INSERT INTO TechInputSplit VALUES('R1',2025,'GSL','T_BLND',0.9000000000000000222,''); -INSERT INTO TechInputSplit VALUES('R1',2025,'ETH','T_BLND',0.1000000000000000055,''); -INSERT INTO TechInputSplit VALUES('R1',2030,'GSL','T_BLND',0.9000000000000000222,''); -INSERT INTO TechInputSplit VALUES('R1',2030,'ETH','T_BLND',0.1000000000000000055,''); -INSERT INTO TechInputSplit VALUES('R2',2020,'GSL','T_BLND',0.7199999999999999734,''); -INSERT INTO TechInputSplit VALUES('R2',2020,'ETH','T_BLND',0.08000000000000000166,''); -INSERT INTO TechInputSplit VALUES('R2',2025,'GSL','T_BLND',0.7199999999999999734,''); -INSERT INTO TechInputSplit VALUES('R2',2025,'ETH','T_BLND',0.08000000000000000166,''); -INSERT INTO TechInputSplit VALUES('R2',2030,'GSL','T_BLND',0.7199999999999999734,''); -INSERT INTO TechInputSplit VALUES('R2',2030,'ETH','T_BLND',0.08000000000000000166,''); -CREATE TABLE TechInputSplitAnnual +INSERT INTO MinTechInputSplit VALUES('R1',2020,'GSL','T_BLND',0.9000000000000000222,''); +INSERT INTO MinTechInputSplit VALUES('R1',2020,'ETH','T_BLND',0.1000000000000000055,''); +INSERT INTO MinTechInputSplit VALUES('R1',2025,'GSL','T_BLND',0.9000000000000000222,''); +INSERT INTO MinTechInputSplit VALUES('R1',2025,'ETH','T_BLND',0.1000000000000000055,''); +INSERT INTO MinTechInputSplit VALUES('R1',2030,'GSL','T_BLND',0.9000000000000000222,''); +INSERT INTO MinTechInputSplit VALUES('R1',2030,'ETH','T_BLND',0.1000000000000000055,''); +INSERT INTO MinTechInputSplit VALUES('R2',2020,'GSL','T_BLND',0.7199999999999999734,''); +INSERT INTO MinTechInputSplit VALUES('R2',2020,'ETH','T_BLND',0.08000000000000000166,''); +INSERT INTO MinTechInputSplit VALUES('R2',2025,'GSL','T_BLND',0.7199999999999999734,''); +INSERT INTO MinTechInputSplit VALUES('R2',2025,'ETH','T_BLND',0.08000000000000000166,''); +INSERT INTO MinTechInputSplit VALUES('R2',2030,'GSL','T_BLND',0.7199999999999999734,''); +INSERT INTO MinTechInputSplit VALUES('R2',2030,'ETH','T_BLND',0.08000000000000000166,''); +CREATE TABLE MinTechInputSplitAnnual ( region TEXT, period INTEGER @@ -1043,7 +1043,7 @@ CREATE TABLE TechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechOutputSplit +CREATE TABLE MinTechOutputSplit ( region TEXT, period INTEGER @@ -1056,18 +1056,18 @@ CREATE TABLE TechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm) ); -INSERT INTO TechOutputSplit VALUES('R1',2020,'S_OILREF','GSL',0.9000000000000000222,''); -INSERT INTO TechOutputSplit VALUES('R1',2020,'S_OILREF','DSL',0.1000000000000000055,''); -INSERT INTO TechOutputSplit VALUES('R1',2025,'S_OILREF','GSL',0.9000000000000000222,''); -INSERT INTO TechOutputSplit VALUES('R1',2025,'S_OILREF','DSL',0.1000000000000000055,''); -INSERT INTO TechOutputSplit VALUES('R1',2030,'S_OILREF','GSL',0.9000000000000000222,''); -INSERT INTO TechOutputSplit VALUES('R1',2030,'S_OILREF','DSL',0.1000000000000000055,''); -INSERT INTO TechOutputSplit VALUES('R2',2020,'S_OILREF','GSL',0.7199999999999999734,''); -INSERT INTO TechOutputSplit VALUES('R2',2020,'S_OILREF','DSL',0.08000000000000000166,''); -INSERT INTO TechOutputSplit VALUES('R2',2025,'S_OILREF','GSL',0.7199999999999999734,''); -INSERT INTO TechOutputSplit VALUES('R2',2025,'S_OILREF','DSL',0.08000000000000000166,''); -INSERT INTO TechOutputSplit VALUES('R2',2030,'S_OILREF','GSL',0.7199999999999999734,''); -INSERT INTO TechOutputSplit VALUES('R2',2030,'S_OILREF','DSL',0.08000000000000000166,''); +INSERT INTO MinTechOutputSplit VALUES('R1',2020,'S_OILREF','GSL',0.9000000000000000222,''); +INSERT INTO MinTechOutputSplit VALUES('R1',2020,'S_OILREF','DSL',0.1000000000000000055,''); +INSERT INTO MinTechOutputSplit VALUES('R1',2025,'S_OILREF','GSL',0.9000000000000000222,''); +INSERT INTO MinTechOutputSplit VALUES('R1',2025,'S_OILREF','DSL',0.1000000000000000055,''); +INSERT INTO MinTechOutputSplit VALUES('R1',2030,'S_OILREF','GSL',0.9000000000000000222,''); +INSERT INTO MinTechOutputSplit VALUES('R1',2030,'S_OILREF','DSL',0.1000000000000000055,''); +INSERT INTO MinTechOutputSplit VALUES('R2',2020,'S_OILREF','GSL',0.7199999999999999734,''); +INSERT INTO MinTechOutputSplit VALUES('R2',2020,'S_OILREF','DSL',0.08000000000000000166,''); +INSERT INTO MinTechOutputSplit VALUES('R2',2025,'S_OILREF','GSL',0.7199999999999999734,''); +INSERT INTO MinTechOutputSplit VALUES('R2',2025,'S_OILREF','DSL',0.08000000000000000166,''); +INSERT INTO MinTechOutputSplit VALUES('R2',2030,'S_OILREF','GSL',0.7199999999999999734,''); +INSERT INTO MinTechOutputSplit VALUES('R2',2030,'S_OILREF','DSL',0.08000000000000000166,''); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index f405cdf7b..6e7e1e32f 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -43278,7 +43278,7 @@ ] ], "GrowthRateMaxConstraint_rtv": [], - "TechInputSplitConstraint_rpsditv": [ + "MinTechInputSplitConstraint_rpsditv": [ [ "R2", 2030, @@ -44144,9 +44144,9 @@ 2020 ] ], - "TechInputSplitAnnualConstraint_rpitv": [], - "TechInputSplitAverageConstraint_rpitv": [], - "TechOutputSplitConstraint_rpsdtvo": [ + "MinTechInputSplitAnnualConstraint_rpitv": [], + "MinTechInputSplitAverageConstraint_rpitv": [], + "MinTechOutputSplitConstraint_rpsdtvo": [ [ "R1", 2030, @@ -45012,8 +45012,14 @@ "GSL" ] ], - "TechOutputSplitAnnualConstraint_rptvo": [], - "TechOutputSplitAverageConstraint_rptvo": [], + "MinTechOutputSplitAnnualConstraint_rptvo": [], + "MinTechOutputSplitAverageConstraint_rptvo": [], + "MaxTechInputSplitConstraint_rpsditv": [], + "MaxTechInputSplitAnnualConstraint_rpitv": [], + "MaxTechInputSplitAverageConstraint_rpitv": [], + "MaxTechOutputSplitConstraint_rpsdtvo": [], + "MaxTechOutputSplitAnnualConstraint_rptvo": [], + "MaxTechOutputSplitAverageConstraint_rptvo": [], "MaxSeasonalActivityConstraint_rpst": [], "MinSeasonalActivityConstraint_rpst": [], "LinkedEmissionsTechConstraint_rpsdtve": [] diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index ccf336bf1..c7249401e 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -991,7 +991,7 @@ INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE TechInputSplit +CREATE TABLE MinTechInputSplit ( region TEXT, period INTEGER @@ -1004,7 +1004,7 @@ CREATE TABLE TechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechInputSplitAnnual +CREATE TABLE MinTechInputSplitAnnual ( region TEXT, period INTEGER @@ -1017,7 +1017,7 @@ CREATE TABLE TechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechOutputSplit +CREATE TABLE MinTechOutputSplit ( region TEXT, period INTEGER @@ -1030,13 +1030,13 @@ CREATE TABLE TechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm) ); -INSERT INTO TechOutputSplit VALUES('utopia',1990,'SRE','DSL',0.6999999999999999556,''); -INSERT INTO TechOutputSplit VALUES('utopia',2000,'SRE','DSL',0.6999999999999999556,''); -INSERT INTO TechOutputSplit VALUES('utopia',2010,'SRE','DSL',0.6999999999999999556,''); -INSERT INTO TechOutputSplit VALUES('utopia',1990,'SRE','GSL',0.2999999999999999889,''); -INSERT INTO TechOutputSplit VALUES('utopia',2000,'SRE','GSL',0.2999999999999999889,''); -INSERT INTO TechOutputSplit VALUES('utopia',2010,'SRE','GSL',0.2999999999999999889,''); -CREATE TABLE TechOutputSplitAnnual +INSERT INTO MinTechOutputSplit VALUES('utopia',1990,'SRE','DSL',0.6999999999999999556,''); +INSERT INTO MinTechOutputSplit VALUES('utopia',2000,'SRE','DSL',0.6999999999999999556,''); +INSERT INTO MinTechOutputSplit VALUES('utopia',2010,'SRE','DSL',0.6999999999999999556,''); +INSERT INTO MinTechOutputSplit VALUES('utopia',1990,'SRE','GSL',0.2999999999999999889,''); +INSERT INTO MinTechOutputSplit VALUES('utopia',2000,'SRE','GSL',0.2999999999999999889,''); +INSERT INTO MinTechOutputSplit VALUES('utopia',2010,'SRE','GSL',0.2999999999999999889,''); +CREATE TABLE MinTechOutputSplitAnnual ( region TEXT, period INTEGER diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 908db1967..0b77eba60 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -24647,10 +24647,10 @@ ] ], "GrowthRateMaxConstraint_rtv": [], - "TechInputSplitConstraint_rpsditv": [], - "TechInputSplitAnnualConstraint_rpitv": [], - "TechInputSplitAverageConstraint_rpitv": [], - "TechOutputSplitConstraint_rpsdtvo": [ + "MinTechInputSplitConstraint_rpsditv": [], + "MinTechInputSplitAnnualConstraint_rpitv": [], + "MinTechInputSplitAverageConstraint_rpitv": [], + "MinTechOutputSplitConstraint_rpsdtvo": [ [ "utopia", 2010, @@ -25300,8 +25300,14 @@ "GSL" ] ], - "TechOutputSplitAnnualConstraint_rptvo": [], - "TechOutputSplitAverageConstraint_rptvo": [], + "MinTechOutputSplitAnnualConstraint_rptvo": [], + "MinTechOutputSplitAverageConstraint_rptvo": [], + "MaxTechInputSplitConstraint_rpsditv": [], + "MaxTechInputSplitAnnualConstraint_rpitv": [], + "MaxTechInputSplitAverageConstraint_rpitv": [], + "MaxTechOutputSplitConstraint_rpsdtvo": [], + "MaxTechOutputSplitAnnualConstraint_rptvo": [], + "MaxTechOutputSplitAverageConstraint_rptvo": [], "MaxSeasonalActivityConstraint_rpst": [], "MinSeasonalActivityConstraint_rpst": [], "LinkedEmissionsTechConstraint_rpsdtve": [] From d4b63fec872a137b63dfcfd52fc99d6cc0b63f55 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 27 Jan 2025 12:13:48 -0500 Subject: [PATCH 031/587] Do some tidy up --- .../temoa_model/exchange_tech_cost_ledger.py | 8 +- temoa/temoa_model/table_data_puller.py | 4 +- temoa/temoa_model/temoa_initialize.py | 32 +- temoa/temoa_model/temoa_model.py | 6 +- temoa/temoa_model/temoa_rules.py | 322 +++++++++--------- tests/test_exchange_cost_ledger.py | 2 +- tests/test_storage.py | 4 +- 7 files changed, 193 insertions(+), 185 deletions(-) diff --git a/temoa/temoa_model/exchange_tech_cost_ledger.py b/temoa/temoa_model/exchange_tech_cost_ledger.py index 5faedb576..7159adfa3 100644 --- a/temoa/temoa_model/exchange_tech_cost_ledger.py +++ b/temoa/temoa_model/exchange_tech_cost_ledger.py @@ -97,7 +97,7 @@ def get_use_ratio(self, exporter, importer, period, tech, vintage) -> float: for s in M.time_season for d in M.time_of_day for S_i in M.processInputs[rr1, period, tech, vintage] - for S_o in M.ProcessOutputsByInput[rr1, period, tech, vintage, S_i] + for S_o in M.processOutputsByInput[rr1, period, tech, vintage, S_i] ) ) act_dir2 = value( @@ -106,7 +106,7 @@ def get_use_ratio(self, exporter, importer, period, tech, vintage) -> float: for s in M.time_season for d in M.time_of_day for S_i in M.processInputs[rr2, period, tech, vintage] - for S_o in M.ProcessOutputsByInput[rr2, period, tech, vintage, S_i] + for S_o in M.processOutputsByInput[rr2, period, tech, vintage, S_i] ) ) else: @@ -114,14 +114,14 @@ def get_use_ratio(self, exporter, importer, period, tech, vintage) -> float: sum( M.V_FlowOutAnnual[rr1, period, S_i, tech, vintage, S_o] for S_i in M.processInputs[rr1, period, tech, vintage] - for S_o in M.ProcessOutputsByInput[rr1, period, tech, vintage, S_i] + for S_o in M.processOutputsByInput[rr1, period, tech, vintage, S_i] ) ) act_dir2 = value( sum( M.V_FlowOutAnnual[rr2, period, S_i, tech, vintage, S_o] for S_i in M.processInputs[rr2, period, tech, vintage] - for S_o in M.ProcessOutputsByInput[rr2, period, tech, vintage, S_i] + for S_o in M.processOutputsByInput[rr2, period, tech, vintage, S_i] ) ) diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index 832922d6c..37382898b 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -339,7 +339,7 @@ def poll_cost_results( activity = sum( value(M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o]) for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] for S_s in M.time_season for S_d in M.time_of_day ) @@ -347,7 +347,7 @@ def poll_cost_results( activity = sum( value(M.V_FlowOutAnnual[r, p, S_i, t, v, S_o]) for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) if abs(activity) < epsilon: continue diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index a5a8ec405..e13a8c171 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -707,10 +707,10 @@ def CreateSparseDicts(M: 'TemoaModel'): M.commodityDStreamProcess[r, p, i] = set() if (r, p, o) not in M.commodityUStreamProcess: M.commodityUStreamProcess[r, p, o] = set() - if (r, p, t, v, i) not in M.ProcessOutputsByInput: - M.ProcessOutputsByInput[r, p, t, v, i] = set() - if (r, p, t, v, o) not in M.ProcessInputsByOutput: - M.ProcessInputsByOutput[r, p, t, v, o] = set() + if (r, p, t, v, i) not in M.processOutputsByInput: + M.processOutputsByInput[r, p, t, v, i] = set() + if (r, p, t, v, o) not in M.processInputsByOutput: + M.processInputsByOutput[r, p, t, v, o] = set() if (r, t) not in M.processTechs: M.processTechs[r, t] = set() # While the dictionary just above identifies the vintage (v) @@ -789,8 +789,8 @@ def CreateSparseDicts(M: 'TemoaModel'): ) not in M.maxOutputSplitAnnualVintages: M.maxOutputSplitAnnualVintages[r, p, t, o] = set() - if t in M.tech_resource and (r, p, o) not in M.ProcessByPeriodAndOutput: - M.ProcessByPeriodAndOutput[r, p, o] = set() + if t in M.tech_resource and (r, p, o) not in M.processByPeriodAndOutput: + M.processByPeriodAndOutput[r, p, o] = set() if t in M.tech_reserve and (r, p) not in M.processReservePeriods: M.processReservePeriods[r, p] = set() @@ -808,8 +808,8 @@ def CreateSparseDicts(M: 'TemoaModel'): M.processOutputs[pindex].add(o) M.commodityDStreamProcess[r, p, i].add((t, v)) M.commodityUStreamProcess[r, p, o].add((t, v)) - M.ProcessOutputsByInput[r, p, t, v, i].add(o) - M.ProcessInputsByOutput[r, p, t, v, o].add(i) + M.processOutputsByInput[r, p, t, v, i].add(o) + M.processInputsByOutput[r, p, t, v, o].add(i) M.processTechs[r, t].add((p, v)) M.processVintages[r, p, t].add(v) if t in M.tech_curtailment: @@ -844,7 +844,7 @@ def CreateSparseDicts(M: 'TemoaModel'): M.maxInputSplitAnnualVintages[r, p, t, o].add(v) if t in M.tech_resource: - M.ProcessByPeriodAndOutput[r, p, o].add((i, t, v)) + M.processByPeriodAndOutput[r, p, o].add((i, t, v)) if t in M.tech_reserve: M.processReservePeriods[r, p].add((t, v)) if t in M.tech_exchange: @@ -901,7 +901,7 @@ def CreateSparseDicts(M: 'TemoaModel'): if t not in M.tech_annual for v in M.processVintages[r, p, t] for i in M.processInputs[r, p, t, v] - for o in M.ProcessOutputsByInput[r, p, t, v, i] + for o in M.processOutputsByInput[r, p, t, v, i] for s in M.time_season for d in M.time_of_day ) @@ -912,7 +912,7 @@ def CreateSparseDicts(M: 'TemoaModel'): if t in M.tech_annual for v in M.processVintages[r, p, t] for i in M.processInputs[r, p, t, v] - for o in M.ProcessOutputsByInput[r, p, t, v, i] + for o in M.processOutputsByInput[r, p, t, v, i] ) M.activeFlex_rpsditvo = set( @@ -921,7 +921,7 @@ def CreateSparseDicts(M: 'TemoaModel'): if (t not in M.tech_annual) and (t in M.tech_flex) for v in M.processVintages[r, p, t] for i in M.processInputs[r, p, t, v] - for o in M.ProcessOutputsByInput[r, p, t, v, i] + for o in M.processOutputsByInput[r, p, t, v, i] for s in M.time_season for d in M.time_of_day ) @@ -932,7 +932,7 @@ def CreateSparseDicts(M: 'TemoaModel'): if (t in M.tech_annual) and (t in M.tech_flex) for v in M.processVintages[r, p, t] for i in M.processInputs[r, p, t, v] - for o in M.ProcessOutputsByInput[r, p, t, v, i] + for o in M.processOutputsByInput[r, p, t, v, i] ) M.activeFlowInStorage_rpsditvo = set( @@ -941,7 +941,7 @@ def CreateSparseDicts(M: 'TemoaModel'): if t in M.tech_storage for v in M.processVintages[r, p, t] for i in M.processInputs[r, p, t, v] - for o in M.ProcessOutputsByInput[r, p, t, v, i] + for o in M.processOutputsByInput[r, p, t, v, i] for s in M.time_season for d in M.time_of_day ) @@ -951,7 +951,7 @@ def CreateSparseDicts(M: 'TemoaModel'): for r, p, t in M.curtailmentVintages.keys() for v in M.curtailmentVintages[r, p, t] for i in M.processInputs[r, p, t, v] - for o in M.ProcessOutputsByInput[r, p, t, v, i] + for o in M.processOutputsByInput[r, p, t, v, i] for s in M.time_season for d in M.time_of_day ) @@ -1254,7 +1254,7 @@ def DemandActivityConstraintIndices(M: 'TemoaModel'): viable_tech_vintage = defaultdict(list) # start the loop over possible combos - for r, p, t, v, dem in M.ProcessInputsByOutput: + for r, p, t, v, dem in M.processInputsByOutput: # we aren't concerned with non-demand commodities or annual techs if dem not in M.commodity_demand or t in M.tech_annual: continue diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 0280ed34d..3ab271862 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -97,8 +97,8 @@ def __init__(M, *args, **kwargs): M.commodityBalance_rpc = None # Set of valid region-period-commodity indices to balance M.commodityDStreamProcess = dict() # The downstream process of a commodity during a period M.commodityUStreamProcess = dict() # The upstream process of a commodity during a period - M.ProcessInputsByOutput = dict() - M.ProcessOutputsByInput = dict() + M.processInputsByOutput = dict() + M.processOutputsByInput = dict() M.processTechs = dict() M.processReservePeriods = dict() M.processVintages = dict() @@ -117,7 +117,7 @@ def __init__(M, *args, **kwargs): M.minOutputSplitAnnualVintages = dict() M.maxOutputSplitVintages = dict() M.maxOutputSplitAnnualVintages = dict() - M.ProcessByPeriodAndOutput = dict() + M.processByPeriodAndOutput = dict() M.exportRegions = dict() M.importRegions = dict() M.time_next = dict() diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index f0295ab39..841bd2f35 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -50,7 +50,7 @@ def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): that occurred up until the period in question, :code:`p`.""" if t not in M.tech_retirement: if v in M.time_exist: - return M.V_Capacity[r, p, t, v] == M.ExistingCapacity[r, t, v] + return M.V_Capacity[r, p, t, v] == value(M.ExistingCapacity[r, t, v]) else: return M.V_Capacity[r, p, t, v] == M.V_NewCapacity[r, t, v] @@ -59,7 +59,7 @@ def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): M.V_RetiredCapacity[r, S_p, t, v] for S_p in M.time_optimize if p >= S_p > v ) if v in M.time_exist: - return M.V_Capacity[r, p, t, v] == M.ExistingCapacity[r, t, v] - retired_cap + return M.V_Capacity[r, p, t, v] == value(M.ExistingCapacity[r, t, v]) - retired_cap else: return M.V_Capacity[r, p, t, v] == M.V_NewCapacity[r, t, v] - retired_cap @@ -103,7 +103,7 @@ def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): useful_activity = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) if (r, s, d, t, v) in M.CapacityFactorProcess: # use the data provided @@ -114,12 +114,16 @@ def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): if t in M.tech_curtailment: # If technologies are present in the curtailment set, then enough # capacity must be available to cover both activity and curtailment. - return capacity * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[s, d]) * value( - M.ProcessLifeFrac[r, p, t, v] - ) * M.V_Capacity[r, p, t, v] == useful_activity + sum( - M.V_Curtailment[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + return ( + capacity + * value(M.CapacityToActivity[r, t]) + * value(M.SegFrac[s, d]) + * value(M.ProcessLifeFrac[r, p, t, v]) + * M.V_Capacity[r, p, t, v] == useful_activity + sum( + M.V_Curtailment[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) ) else: return ( @@ -163,7 +167,7 @@ def CapacityAnnual_Constraint(M: 'TemoaModel', r, p, t, v): activity_rptv = sum( M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) return ( @@ -263,7 +267,7 @@ def RetiredCapacity_Constraint(M: 'TemoaModel', r, p, t, v): \forall \{r, p, t, v\} \in \Theta_{\text{RetiredCapacity}} """ if p == M.time_optimize.first(): - cap_avail = M.ExistingCapacity[r, t, v] + cap_avail = value(M.ExistingCapacity[r, t, v]) else: cap_avail = M.V_Capacity[r, M.time_optimize.prev(p), t, v] expr = M.V_RetiredCapacity[r, p, t, v] <= cap_avail @@ -464,8 +468,8 @@ def PeriodCost_rule(M: 'TemoaModel', p): loan_costs = sum( loan_cost( M.V_NewCapacity[r, S_t, S_v], - M.CostInvest[r, S_t, S_v], - M.LoanAnnualize[r, S_t, S_v], + value(M.CostInvest[r, S_t, S_v]), + value(M.LoanAnnualize[r, S_t, S_v]), value(M.LoanLifetimeProcess[r, S_t, S_v]), value(M.LifetimeProcess[r, S_t, S_v]), P_0, @@ -480,8 +484,8 @@ def PeriodCost_rule(M: 'TemoaModel', p): fixed_costs = sum( fixed_or_variable_cost( M.V_Capacity[r, p, S_t, S_v], - M.CostFixed[r, p, S_t, S_v], - MPL[r, p, S_t, S_v], + value(M.CostFixed[r, p, S_t, S_v]), + value(MPL[r, p, S_t, S_v]), GDR, P_0, p=p, @@ -493,8 +497,8 @@ def PeriodCost_rule(M: 'TemoaModel', p): variable_costs = sum( fixed_or_variable_cost( M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, S_o], - M.CostVariable[r, p, S_t, S_v], - M.PeriodLength[p], + value(M.CostVariable[r, p, S_t, S_v]), + value(M.PeriodLength[p]), GDR, P_0, p, @@ -502,7 +506,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): for r, S_p, S_t, S_v in M.CostVariable.sparse_iterkeys() if S_p == p and S_t not in M.tech_annual for S_i in M.processInputs[r, S_p, S_t, S_v] - for S_o in M.ProcessOutputsByInput[r, S_p, S_t, S_v, S_i] + for S_o in M.processOutputsByInput[r, S_p, S_t, S_v, S_i] for s in M.time_season for d in M.time_of_day ) @@ -510,8 +514,8 @@ def PeriodCost_rule(M: 'TemoaModel', p): variable_costs_annual = sum( fixed_or_variable_cost( M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, S_o], - M.CostVariable[r, p, S_t, S_v], - M.PeriodLength[p], + value(M.CostVariable[r, p, S_t, S_v]), + value(M.PeriodLength[p]), GDR, P_0, p, @@ -519,7 +523,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): for r, S_p, S_t, S_v in M.CostVariable.sparse_iterkeys() if S_p == p and S_t in M.tech_annual for S_i in M.processInputs[r, S_p, S_t, S_v] - for S_o in M.ProcessOutputsByInput[r, S_p, S_t, S_v, S_i] + for S_o in M.processOutputsByInput[r, S_p, S_t, S_v, S_i] ) # The emissions costs occur over the five possible emission sources. @@ -555,9 +559,9 @@ def PeriodCost_rule(M: 'TemoaModel', p): # 1. variable emissions var_emissions = sum( fixed_or_variable_cost( - cap_or_flow=M.V_FlowOut[r, p, s, d, i, t, v, o] * M.EmissionActivity[r, e, i, t, v, o], - cost_factor=M.CostEmission[r, p, e], - cost_years=M.PeriodLength[p], + cap_or_flow=M.V_FlowOut[r, p, s, d, i, t, v, o] * value(M.EmissionActivity[r, e, i, t, v, o]), + cost_factor=value(M.CostEmission[r, p, e]), + cost_years=value(M.PeriodLength[p]), GDR=GDR, P_0=P_0, p=p, @@ -572,9 +576,9 @@ def PeriodCost_rule(M: 'TemoaModel', p): # 4. annual emissions var_annual_emissions = sum( fixed_or_variable_cost( - cap_or_flow=M.V_FlowOutAnnual[r, p, i, t, v, o] * M.EmissionActivity[r, e, i, t, v, o], - cost_factor=M.CostEmission[r, p, e], - cost_years=M.PeriodLength[p], + cap_or_flow=M.V_FlowOutAnnual[r, p, i, t, v, o] * value(M.EmissionActivity[r, e, i, t, v, o]), + cost_factor=value(M.CostEmission[r, p, e]), + cost_years=value(M.PeriodLength[p]), GDR=GDR, P_0=P_0, p=p, @@ -588,8 +592,8 @@ def PeriodCost_rule(M: 'TemoaModel', p): # 6. embodied - treated as a fixed cost in a single year (year of construction) embodied_emissions = sum( fixed_or_variable_cost( - cap_or_flow=M.V_NewCapacity[r, t, v] * M.EmissionEmbodied[r, e, t, v], - cost_factor=M.CostEmission[r, p, e], + cap_or_flow=M.V_NewCapacity[r, t, v] * value(M.EmissionEmbodied[r, e, t, v]), + cost_factor=value(M.CostEmission[r, p, e]), cost_years=1, # We assume the embodied emissions are emitted in the same year as the capacity is installed. GDR=GDR, P_0=P_0, @@ -642,20 +646,20 @@ def Demand_Constraint(M: 'TemoaModel', r, p, s, d, dem): M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, dem] for S_t, S_v in M.commodityUStreamProcess[r, p, dem] if S_t not in M.tech_annual - for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, dem] + for S_i in M.processInputsByOutput[r, p, S_t, S_v, dem] ) supply_annual = sum( M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, dem] for S_t, S_v in M.commodityUStreamProcess[r, p, dem] if S_t in M.tech_annual - for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, dem] + for S_i in M.processInputsByOutput[r, p, S_t, S_v, dem] ) * value(M.SegFrac[s, d]) DemandConstraintErrorCheck(supply + supply_annual, r, p, s, d, dem) expr = ( - supply + supply_annual == M.Demand[r, p, dem] * get_demand_distribution(M, r, p, s, d, dem) + supply + supply_annual == value(M.Demand[r, p, dem]) * get_demand_distribution(M, r, p, s, d, dem) ) return expr @@ -693,10 +697,10 @@ def DemandActivity_Constraint(M: 'TemoaModel', r, p, s, d, t, v, dem, s_0, d_0): act_a = sum( M.V_FlowOut[r, p, s_0, d_0, S_i, t, v, dem] - for S_i in M.ProcessInputsByOutput[r, p, t, v, dem] + for S_i in M.processInputsByOutput[r, p, t, v, dem] ) act_b = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, dem] for S_i in M.ProcessInputsByOutput[r, p, t, v, dem] + M.V_FlowOut[r, p, s, d, S_i, t, v, dem] for S_i in M.processInputsByOutput[r, p, t, v, dem] ) expr = ( @@ -794,21 +798,21 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): M.V_FlowIn[r, p, s, d, c, S_t, S_v, S_o] for S_t, S_v in M.commodityDStreamProcess[r, p, c] if S_t in M.tech_storage - for S_o in M.ProcessOutputsByInput[r, p, S_t, S_v, c] + for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] ) consumed = sum( M.V_FlowOut[r, p, s, d, c, S_t, S_v, S_o] / value(M.Efficiency[r, c, S_t, S_v, S_o]) for S_t, S_v in M.commodityDStreamProcess[r, p, c] if S_t not in M.tech_storage and S_t not in M.tech_annual - for S_o in M.ProcessOutputsByInput[r, p, S_t, S_v, c] + for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] ) consumed_annual = value(M.SegFrac[s, d]) * sum( M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] / value(M.Efficiency[r, c, S_t, S_v, S_o]) for S_t, S_v in M.commodityDStreamProcess[r, p, c] if S_t not in M.tech_storage and S_t in M.tech_annual - for S_o in M.ProcessOutputsByInput[r, p, S_t, S_v, c] + for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] ) # Includes output from storage @@ -816,14 +820,14 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, c] for S_t, S_v in M.commodityUStreamProcess[r, p, c] if S_t not in M.tech_annual - for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, c] + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] ) produced_annual = value(M.SegFrac[s, d]) * sum( M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, c] for S_t, S_v in M.commodityUStreamProcess[r, p, c] if S_t in M.tech_annual - for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, c] + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] ) # export of commodity c from region r to other regions @@ -850,13 +854,13 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): M.V_Flex[r, p, s, d, S_i, S_t, S_v, c] for S_t, S_v in M.commodityUStreamProcess[r, p, c] if S_t not in M.tech_annual and S_t in M.tech_flex - for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, c] + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] ) flex_waste_annual = value(M.SegFrac[s, d]) * sum( M.V_FlexAnnual[r, p, S_i, S_t, S_v, c] for S_t, S_v in M.commodityUStreamProcess[r, p, c] if S_t in M.tech_annual and S_t in M.tech_flex - for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, c] + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] ) supplied = produced + produced_annual + imported @@ -895,7 +899,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): for S_d in M.time_of_day for S_t, S_v in M.commodityDStreamProcess[r, p, c] if S_t in M.tech_storage - for S_o in M.ProcessOutputsByInput[r, p, S_t, S_v, c] + for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] ) consumed = sum( @@ -904,14 +908,14 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): for S_d in M.time_of_day for S_t, S_v in M.commodityDStreamProcess[r, p, c] if S_t not in M.tech_storage and S_t not in M.tech_annual - for S_o in M.ProcessOutputsByInput[r, p, S_t, S_v, c] + for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] ) consumed_annual = sum( M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] / value(M.Efficiency[r, c, S_t, S_v, S_o]) for S_t, S_v in M.commodityDStreamProcess[r, p, c] if S_t not in M.tech_storage and S_t in M.tech_annual - for S_o in M.ProcessOutputsByInput[r, p, S_t, S_v, c] + for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] ) # Includes output from storage @@ -921,14 +925,14 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): for S_d in M.time_of_day for S_t, S_v in M.commodityUStreamProcess[r, p, c] if S_t not in M.tech_annual - for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, c] + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] ) produced_annual = sum( M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, c] for S_t, S_v in M.commodityUStreamProcess[r, p, c] if S_t in M.tech_annual - for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, c] + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] ) # export of commodity c from region r to other regions @@ -961,13 +965,13 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): for S_d in M.time_of_day for S_t, S_v in M.commodityUStreamProcess[r, p, c] if S_t not in M.tech_annual and S_t in M.tech_flex - for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, c] + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] ) flex_waste_annual = sum( M.V_FlexAnnual[r, p, S_i, S_t, S_v, c] for S_t, S_v in M.commodityUStreamProcess[r, p, c] if S_t in M.tech_flex and S_t in M.tech_annual - for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, c] + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] ) supplied = produced + produced_annual + imported @@ -1014,18 +1018,18 @@ def ResourceExtraction_Constraint(M: 'TemoaModel', reg, p, r): # by BOTH a non-annual and annual tech. It should be re-written to add these try: collected = sum( - M.V_FlowOut[reg, p, S_s, S_d, S_i, S_t, S_v, r] - for S_i, S_t, S_v in M.ProcessByPeriodAndOutput.keys() + M.V_FlowOut[reg, p, S_s, S_d, S_i, S_t, S_v, r] # is r the input or the output!? + for S_i, S_t, S_v in M.processByPeriodAndOutput.keys() for S_s in M.time_season for S_d in M.time_of_day ) except KeyError: collected = sum( M.V_FlowOutAnnual[reg, p, S_i, S_t, S_v, r] - for S_i, S_t, S_v in M.ProcessByPeriodAndOutput.keys() + for S_i, S_t, S_v in M.processByPeriodAndOutput.keys() ) - expr = collected <= M.ResourceBound[reg, p, r] + expr = collected <= value(M.ResourceBound[reg, p, r]) return expr @@ -1084,16 +1088,16 @@ def BaseloadDiurnal_Constraint(M: 'TemoaModel', r, p, s, d, t, v): activity_sd = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) activity_sd_0 = sum( M.V_FlowOut[r, p, s, d_0, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - expr = activity_sd * M.SegFrac[s, d_0] == activity_sd_0 * M.SegFrac[s, d] + expr = activity_sd * value(M.SegFrac[s, d_0]) == activity_sd_0 * value(M.SegFrac[s, d]) return expr @@ -1125,9 +1129,9 @@ def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): # This is the sum of all input=i sent TO storage tech t of vintage v with # output=o in p,s,d charge = sum( - M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] * M.Efficiency[r, S_i, t, v, S_o] + M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] * value(M.Efficiency[r, S_i, t, v, S_o]) for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) # This is the sum of all output=o withdrawn FROM storage tech t of vintage v @@ -1135,7 +1139,7 @@ def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): discharge = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] for S_o in M.processOutputs[r, p, t, v] - for S_i in M.ProcessInputsByOutput[r, p, t, v, S_o] + for S_i in M.processInputsByOutput[r, p, t, v, S_o] ) stored_energy = charge - discharge @@ -1181,8 +1185,8 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): energy_capacity = ( M.V_Capacity[r, p, t, v] - * M.CapacityToActivity[r, t] - * (M.StorageDuration[r, t] / 8760) + * value(M.CapacityToActivity[r, t]) + * (value(M.StorageDuration[r, t]) / 8760) * M.SegFracPerSeason[s] * 365 * value(M.ProcessLifeFrac[r, p, t, v]) @@ -1212,16 +1216,16 @@ def StorageChargeRate_Constraint(M: 'TemoaModel', r, p, s, d, t, v): """ # Calculate energy charge in each time slice slice_charge = sum( - M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] * M.Efficiency[r, S_i, t, v, S_o] + M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] * value(M.Efficiency[r, S_i, t, v, S_o]) for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) # Maximum energy charge in each time slice max_charge = ( M.V_Capacity[r, p, t, v] - * M.CapacityToActivity[r, t] - * M.SegFrac[s, d] + * value(M.CapacityToActivity[r, t]) + * value(M.SegFrac[s, d]) * value(M.ProcessLifeFrac[r, p, t, v]) ) @@ -1251,14 +1255,14 @@ def StorageDischargeRate_Constraint(M: 'TemoaModel', r, p, s, d, t, v): slice_discharge = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] for S_o in M.processOutputs[r, p, t, v] - for S_i in M.ProcessInputsByOutput[r, p, t, v, S_o] + for S_i in M.processInputsByOutput[r, p, t, v, S_o] ) # Maximum energy discharge in each time slice max_discharge = ( M.V_Capacity[r, p, t, v] - * M.CapacityToActivity[r, t] - * M.SegFrac[s, d] + * value(M.CapacityToActivity[r, t]) + * value(M.SegFrac[s, d]) * value(M.ProcessLifeFrac[r, p, t, v]) ) @@ -1290,20 +1294,20 @@ def StorageThroughput_Constraint(M: 'TemoaModel', r, p, s, d, t, v): discharge = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] for S_o in M.processOutputs[r, p, t, v] - for S_i in M.ProcessInputsByOutput[r, p, t, v, S_o] + for S_i in M.processInputsByOutput[r, p, t, v, S_o] ) charge = sum( - M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] * M.Efficiency[r, S_i, t, v, S_o] + M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] * value(M.Efficiency[r, S_i, t, v, S_o]) for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) throughput = charge + discharge max_throughput = ( M.V_Capacity[r, p, t, v] - * M.CapacityToActivity[r, t] - * M.SegFrac[s, d] + * value(M.CapacityToActivity[r, t]) + * value(M.SegFrac[s, d]) * value(M.ProcessLifeFrac[r, p, t, v]) ) expr = throughput <= max_throughput @@ -1339,14 +1343,14 @@ def StorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v): energy_capacity = ( M.V_Capacity[r, p, t, v] - * M.CapacityToActivity[r, t] - * (M.StorageDuration[r, t] / 8760) + * value(M.CapacityToActivity[r, t]) + * (value(M.StorageDuration[r, t]) / 8760) * M.SegFracPerSeason[s] * 365 * value(M.ProcessLifeFrac[r, p, t, v]) ) - expr = M.V_StorageLevel[r, p, s, d, t, v] == energy_capacity * M.StorageFraction[r, p, s, d, t, v] + expr = M.V_StorageLevel[r, p, s, d, t, v] == energy_capacity * value(M.StorageFraction[r, p, s, d, t, v]) return expr @@ -1404,13 +1408,13 @@ def RampUp_Constraint(M: 'TemoaModel', r, p, s, d, t, v): activity_sd = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) / value(M.SegFrac[s, d]) activity_sd_next = sum( M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) / value(M.SegFrac[s_next, d_next]) hours_elapsed = 8760 * (value(M.SegFrac[s, d]) + value(M.SegFrac[s_next, d_next])) / 2 @@ -1425,7 +1429,7 @@ def RampUp_Constraint(M: 'TemoaModel', r, p, s, d, t, v): return Constraint.Skip activity_increase = activity_sd_next - activity_sd # opposite sign from rampdown - rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * M.ProcessLifeFrac[r, p, t, v] + rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.ProcessLifeFrac[r, p, t, v]) expr = activity_increase <= rampable_activity return expr @@ -1462,13 +1466,13 @@ def RampDown_Constraint(M: 'TemoaModel', r, p, s, d, t, v): activity_sd = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) / value(M.SegFrac[s, d]) activity_sd_next = sum( M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) / value(M.SegFrac[s_next, d_next]) hours_elapsed = 8760 * (value(M.SegFrac[s, d]) + value(M.SegFrac[s_next, d_next])) / 2 @@ -1483,7 +1487,7 @@ def RampDown_Constraint(M: 'TemoaModel', r, p, s, d, t, v): return Constraint.Skip activity_decrease = activity_sd - activity_sd_next # opposite sign from rampup - rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * M.ProcessLifeFrac[r, p, t, v] + rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.ProcessLifeFrac[r, p, t, v]) expr = activity_decrease <= rampable_activity return expr @@ -1519,7 +1523,7 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): cap_avail = sum( value(M.CapacityCredit[r, p, t, v]) - * M.ProcessLifeFrac[r, p, t, v] + * value(M.ProcessLifeFrac[r, p, t, v]) * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[s, d]) @@ -1551,7 +1555,7 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): # add the available capacity of the exchange tech. cap_avail += sum( value(M.CapacityCredit[r1r2, p, t, v]) - * M.ProcessLifeFrac[r1r2, p, t, v] + * value(M.ProcessLifeFrac[r1r2, p, t, v]) * M.V_Capacity[r1r2, p, t, v] * value(M.CapacityToActivity[r1r2, t]) * value(M.SegFrac[s, d]) @@ -1568,7 +1572,7 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): M.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] for (t, S_v) in M.processReservePeriods[r, p] 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_o in M.processOutputsByInput[r, p, t, S_v, S_i] ) # We must take into account flows into storage technologies. @@ -1579,7 +1583,7 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): for (t, S_v) in M.processReservePeriods[r, p] if t in M.tech_storage 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_o in M.processOutputsByInput[r, p, t, S_v, S_i] ) # Electricity imports and exports via exchange techs are accounted @@ -1598,7 +1602,7 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): / value(M.Efficiency[r1r2, S_i, t, S_v, S_o]) for (t, S_v) in M.processReservePeriods[r1r2, p] for S_i in M.processInputs[r1r2, p, t, S_v] - for S_o in M.ProcessOutputsByInput[r1r2, p, t, S_v, S_i] + for S_o in M.processOutputsByInput[r1r2, p, t, S_v, S_i] ) # Second, determine the imports, and add this value from the # total generation. @@ -1607,7 +1611,7 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): M.V_FlowOut[r1r2, p, s, d, S_i, t, S_v, S_o] for (t, S_v) in M.processReservePeriods[r1r2, p] for S_i in M.processInputs[r1r2, p, t, S_v] - for S_o in M.ProcessOutputsByInput[r1r2, p, t, S_v, S_i] + for S_o in M.processOutputsByInput[r1r2, p, t, S_v, S_i] if (t, S_v) in M.processReservePeriods[r1r2, p] ) @@ -1643,7 +1647,7 @@ def EmissionLimit_Constraint(M: 'TemoaModel', r, p, e): & \forall \{r, p, e\} \in \Theta_{\text{EmissionLimit}} """ - emission_limit = M.EmissionLimit[r, p, e] + emission_limit = value(M.EmissionLimit[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 @@ -1659,7 +1663,7 @@ def EmissionLimit_Constraint(M: 'TemoaModel', r, p, e): process_emissions = sum( M.V_FlowOut[reg, p, S_s, S_d, S_i, S_t, S_v, S_o] - * M.EmissionActivity[reg, e, S_i, S_t, S_v, S_o] + * value(M.EmissionActivity[reg, e, S_i, S_t, S_v, S_o]) for reg in regions for tmp_r, tmp_e, S_i, S_t, S_v, S_o in M.EmissionActivity.sparse_iterkeys() if tmp_e == e and tmp_r == reg and S_t not in M.tech_annual @@ -1671,7 +1675,7 @@ def EmissionLimit_Constraint(M: 'TemoaModel', r, p, e): process_emissions_annual = sum( M.V_FlowOutAnnual[reg, p, S_i, S_t, S_v, S_o] - * M.EmissionActivity[reg, e, S_i, S_t, S_v, S_o] + * value(M.EmissionActivity[reg, e, S_i, S_t, S_v, S_o]) for reg in regions for tmp_r, tmp_e, S_i, S_t, S_v, S_o in M.EmissionActivity.sparse_iterkeys() if tmp_e == e and tmp_r == reg and S_t in M.tech_annual @@ -1681,7 +1685,7 @@ def EmissionLimit_Constraint(M: 'TemoaModel', r, p, e): embodied_emissions = sum( M.V_NewCapacity[r, t, v] - * M.EmissionEmbodied[r, e, t, v] + * value(M.EmissionEmbodied[r, e, t, v]) for (S_r, S_e, t, v) in M.EmissionEmbodied.sparse_iterkeys() if v == p and S_r == r and S_e == e ) @@ -1782,7 +1786,7 @@ def MaxActivity_Constraint(M: 'TemoaModel', r, p, t): for r in reg for S_v in M.processVintages.get((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_o in M.processOutputsByInput[r, p, t, S_v, S_i] for s in M.time_season for d in M.time_of_day if (r, p, s, d, S_i, t, S_v, S_o) in M.V_FlowOut @@ -1793,7 +1797,7 @@ def MaxActivity_Constraint(M: 'TemoaModel', r, p, t): for r in reg for S_v in M.processVintages.get((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_o in M.processOutputsByInput[r, p, t, S_v, S_i] if (r, p, S_i, t, S_v, S_o) in M.V_FlowOutAnnual ) @@ -1834,10 +1838,10 @@ def MaxSeasonalActivity_Constraint(M: 'TemoaModel', r, p, s, t): try: activity_rpst = sum( - M.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] / (M.SegFrac[s, d]*365*24) + M.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] / (value(M.SegFrac[s, d])*365*24) 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_o in M.processOutputsByInput[r, p, t, S_v, S_i] for d in M.time_of_day ) except: @@ -1891,7 +1895,7 @@ def MinActivity_Constraint(M: 'TemoaModel', r, p, t): for _r in regions for S_v in M.processVintages.get((_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_o in M.processOutputsByInput[_r, p, t, S_v, S_i] for s in M.time_season for d in M.time_of_day if (_r, p, s, d, S_i, t, S_v, S_o) in M.V_FlowOut @@ -1902,7 +1906,7 @@ def MinActivity_Constraint(M: 'TemoaModel', r, p, t): for _r in regions for S_v in M.processVintages.get((_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_o in M.processOutputsByInput[_r, p, t, S_v, S_i] if (_r, p, S_i, t, S_v, S_o) in M.V_FlowOutAnnual ) @@ -1950,10 +1954,10 @@ def MinSeasonalActivity_Constraint(M: 'TemoaModel', r, p, s, t): try: activity_rpst = sum( - M.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] / (M.SegFrac[s, d]*365*24) + M.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] / (value(M.SegFrac[s, d])*365*24) 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_o in M.processOutputsByInput[r, p, t, S_v, S_i] for d in M.time_of_day ) except: @@ -2003,7 +2007,7 @@ def MinActivityGroup_Constraint(M: 'TemoaModel', r, p, g): if (r_i, p, S_t) in M.processVintages and S_t not in M.tech_annual for S_v in M.processVintages[r_i, p, S_t] for S_i in M.processInputs[r_i, p, S_t, S_v] - for S_o in M.ProcessOutputsByInput[r_i, p, S_t, S_v, S_i] + for S_o in M.processOutputsByInput[r_i, p, S_t, S_v, S_i] for s in M.time_season for d in M.time_of_day if (r_i, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut @@ -2015,7 +2019,7 @@ def MinActivityGroup_Constraint(M: 'TemoaModel', r, p, g): if (r_i, p, S_t) in M.processVintages and S_t in M.tech_annual for S_v in M.processVintages[r_i, p, S_t] for S_i in M.processInputs[r_i, p, S_t, S_v] - for S_o in M.ProcessOutputsByInput[r_i, p, S_t, S_v, S_i] + for S_o in M.processOutputsByInput[r_i, p, S_t, S_v, S_i] if (r_i, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual ) min_act = value(M.MinActivityGroup[r, p, g]) @@ -2057,7 +2061,7 @@ def MaxActivityGroup_Constraint(M: 'TemoaModel', r, p, g): if (r_i, p, S_t) in M.processVintages and S_t not in M.tech_annual for S_v in M.processVintages[r_i, p, S_t] for S_i in M.processInputs[r_i, p, S_t, S_v] - for S_o in M.ProcessOutputsByInput[r_i, p, S_t, S_v, S_i] + for S_o in M.processOutputsByInput[r_i, p, S_t, S_v, S_i] for s in M.time_season for d in M.time_of_day if (r_i, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut @@ -2068,7 +2072,7 @@ def MaxActivityGroup_Constraint(M: 'TemoaModel', r, p, g): if (r_i, p, S_t) in M.processVintages and S_t in M.tech_annual for S_v in M.processVintages[r_i, p, S_t] for S_i in M.processInputs[r_i, p, S_t, S_v] - for S_o in M.ProcessOutputsByInput[r_i, p, S_t, S_v, S_i] + for S_o in M.processOutputsByInput[r_i, p, S_t, S_v, S_i] if (r_i, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual ) @@ -2302,7 +2306,7 @@ def MinActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): M.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] for S_v in M.processVintages.get((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_o in M.processOutputsByInput[r, p, t, S_v, S_i] for s in M.time_season for d in M.time_of_day ) @@ -2311,7 +2315,7 @@ def MinActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): M.V_FlowOutAnnual[r, p, S_i, t, S_v, S_o] for S_v in M.processVintages.get((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_o in M.processOutputsByInput[r, p, t, S_v, S_i] ) activity_t = activity_rpt @@ -2321,7 +2325,7 @@ def MinActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): if (r, p, S_t) in M.processVintages and S_t not in M.tech_annual for S_v in M.processVintages[r, p, S_t] for S_i in M.processInputs[r, p, S_t, S_v] - for S_o in M.ProcessOutputsByInput[r, p, S_t, S_v, S_i] + for S_o in M.processOutputsByInput[r, p, S_t, S_v, S_i] for s in M.time_season for d in M.time_of_day ) @@ -2332,7 +2336,7 @@ def MinActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): if (r, p, S_t) in M.processVintages and S_t in M.tech_annual for S_v in M.processVintages[r, p, S_t] for S_i in M.processInputs[r, p, S_t, S_v] - for S_o in M.ProcessOutputsByInput[r, p, S_t, S_v, S_i] + for S_o in M.processOutputsByInput[r, p, S_t, S_v, S_i] ) activity_group = activity_p + activity_p_annual min_activity_share = value(M.MinActivityShare[r, p, t, g]) @@ -2367,7 +2371,7 @@ def MaxActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): for _r in regions for S_v in M.processVintages.get((_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_o in M.processOutputsByInput[_r, p, t, S_v, S_i] for s in M.time_season for d in M.time_of_day if (_r, p, s, d, S_i, t, S_v, S_o) in M.V_FlowOut @@ -2378,7 +2382,7 @@ def MaxActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): for _r in regions for S_v in M.processVintages.get((_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_o in M.processOutputsByInput[_r, p, t, S_v, S_i] if (_r, p, S_i, t, S_v, S_o) in M.V_FlowOutAnnual ) @@ -2390,7 +2394,7 @@ def MaxActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): if (_r, p, S_t) in M.processVintages and S_t not in M.tech_annual for S_v in M.processVintages[_r, p, S_t] for S_i in M.processInputs[_r, p, S_t, S_v] - for S_o in M.ProcessOutputsByInput[_r, p, S_t, S_v, S_i] + for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] for s in M.time_season for d in M.time_of_day if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut @@ -2403,7 +2407,7 @@ def MaxActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): if (_r, p, S_t) in M.processVintages and S_t in M.tech_annual for S_v in M.processVintages[_r, p, S_t] for S_i in M.processInputs[_r, p, S_t, S_v] - for S_o in M.ProcessOutputsByInput[_r, p, S_t, S_v, S_i] + for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual ) activity_group = activity_p + activity_p_annual @@ -2621,7 +2625,7 @@ def MinAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o): ) max_possible_activity_rpt = ( - M.V_CapacityAvailableByPeriodAndTech[r, p, t] * M.CapacityToActivity[r, t] + M.V_CapacityAvailableByPeriodAndTech[r, p, t] * value(M.CapacityToActivity[r, t]) ) min_annual_cf = value(M.MinAnnualCapacityFactor[r, p, t, o]) expr = activity_rpt >= min_annual_cf * max_possible_activity_rpt @@ -2679,7 +2683,7 @@ def MaxAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o): ) max_possible_activity_rpt = ( - M.V_CapacityAvailableByPeriodAndTech[r, p, t] * M.CapacityToActivity[r, t] + M.V_CapacityAvailableByPeriodAndTech[r, p, t] * value(M.CapacityToActivity[r, t]) ) max_annual_cf = value(M.MaxAnnualCapacityFactor[r, p, t, o]) expr = activity_rpt <= max_annual_cf * max_possible_activity_rpt @@ -2698,16 +2702,16 @@ def MinTechInputSplit_Constraint(M: 'TemoaModel', r, p, s, d, i, t, v): NOT in the :code:`tech_annual` set) are considered.""" inp = sum( M.V_FlowOut[r, p, s, d, i, t, v, S_o] / value(M.Efficiency[r, i, t, v, S_o]) - for S_o in M.ProcessOutputsByInput[r, p, t, v, i] + for S_o in M.processOutputsByInput[r, p, t, v, i] ) total_inp = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] / value(M.Efficiency[r, S_i, t, v, S_o]) for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - expr = inp >= M.MinTechInputSplit[r, p, i, t] * total_inp + expr = inp >= value(M.MinTechInputSplit[r, p, i, t]) * total_inp return expr @@ -2720,16 +2724,16 @@ def MinTechInputSplitAnnual_Constraint(M: 'TemoaModel', r, p, i, t, v): of the :math:`tech_annual` set) are considered.""" inp = sum( M.V_FlowOutAnnual[r, p, i, t, v, S_o] / value(M.Efficiency[r, i, t, v, S_o]) - for S_o in M.ProcessOutputsByInput[r, p, t, v, i] + for S_o in M.processOutputsByInput[r, p, t, v, i] ) total_inp = sum( M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] / value(M.Efficiency[r, S_i, t, v, S_o]) for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - expr = inp >= M.MinTechInputSplitAnnual[r, p, i, t] * total_inp + expr = inp >= value(M.MinTechInputSplitAnnual[r, p, i, t]) * total_inp return expr @@ -2746,7 +2750,7 @@ def MinTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v): M.V_FlowOut[r, p, s, d, i, t, v, S_o] / value(M.Efficiency[r, i, t, v, S_o]) for s in M.time_season for d in M.time_of_day - for S_o in M.ProcessOutputsByInput[r, p, t, v, i] + for S_o in M.processOutputsByInput[r, p, t, v, i] ) total_inp = sum( @@ -2754,10 +2758,10 @@ def MinTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v): for s in M.time_season for d in M.time_of_day for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, i] + for S_o in M.processOutputsByInput[r, p, t, v, i] ) - expr = inp >= M.MinTechInputSplitAnnual[r, p, i, t] * total_inp + expr = inp >= value(M.MinTechInputSplitAnnual[r, p, i, t]) * total_inp return expr @@ -2797,16 +2801,17 @@ def MinTechOutputSplit_Constraint(M: 'TemoaModel', r, p, s, d, t, v, o): \forall \{r, p, s, d, t, v, o\} \in \Theta_{\text{MinTechOutputSplit}}""" out = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, o] for S_i in M.ProcessInputsByOutput[r, p, t, v, o] + M.V_FlowOut[r, p, s, d, S_i, t, v, o] + for S_i in M.processInputsByOutput[r, p, t, v, o] ) total_out = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - expr = out >= M.MinTechOutputSplit[r, p, t, o] * total_out + expr = out >= value(M.MinTechOutputSplit[r, p, t, o]) * total_out return expr @@ -2827,16 +2832,17 @@ def MinTechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o): \forall \{r, p, t \in T^{a}, v, o\} \in \Theta_{\text{MinTechOutputSplitAnnual}}""" out = sum( - M.V_FlowOutAnnual[r, p, S_i, t, v, o] for S_i in M.ProcessInputsByOutput[r, p, t, v, o] + M.V_FlowOutAnnual[r, p, S_i, t, v, o] + for S_i in M.processInputsByOutput[r, p, t, v, o] ) total_out = sum( M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - expr = out >= M.MinTechOutputSplitAnnual[r, p, t, o] * total_out + expr = out >= value(M.MinTechOutputSplitAnnual[r, p, t, o]) * total_out return expr @@ -2851,7 +2857,7 @@ def MinTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o): out = sum( M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, o] - for S_i in M.ProcessInputsByOutput[r, p, t, v, o] + for S_i in M.processInputsByOutput[r, p, t, v, o] for S_s in M.time_season for S_d in M.time_of_day ) @@ -2859,12 +2865,12 @@ def MinTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o): total_out = sum( M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] for S_s in M.time_season for S_d in M.time_of_day ) - expr = out >= M.MinTechOutputSplitAnnual[r, p, t, o] * total_out + expr = out >= value(M.MinTechOutputSplitAnnual[r, p, t, o]) * total_out return expr @@ -2877,16 +2883,16 @@ def MaxTechInputSplit_Constraint(M: 'TemoaModel', r, p, s, d, i, t, v): NOT in the :code:`tech_annual` set) are considered.""" inp = sum( M.V_FlowOut[r, p, s, d, i, t, v, S_o] / value(M.Efficiency[r, i, t, v, S_o]) - for S_o in M.ProcessOutputsByInput[r, p, t, v, i] + for S_o in M.processOutputsByInput[r, p, t, v, i] ) total_inp = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] / value(M.Efficiency[r, S_i, t, v, S_o]) for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - expr = inp <= M.MaxTechInputSplit[r, p, i, t] * total_inp + expr = inp <= value(M.MaxTechInputSplit[r, p, i, t]) * total_inp return expr @@ -2899,16 +2905,16 @@ def MaxTechInputSplitAnnual_Constraint(M: 'TemoaModel', r, p, i, t, v): of the :math:`tech_annual` set) are considered.""" inp = sum( M.V_FlowOutAnnual[r, p, i, t, v, S_o] / value(M.Efficiency[r, i, t, v, S_o]) - for S_o in M.ProcessOutputsByInput[r, p, t, v, i] + for S_o in M.processOutputsByInput[r, p, t, v, i] ) total_inp = sum( M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] / value(M.Efficiency[r, S_i, t, v, S_o]) for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - expr = inp <= M.MaxTechInputSplitAnnual[r, p, i, t] * total_inp + expr = inp <= value(M.MaxTechInputSplitAnnual[r, p, i, t]) * total_inp return expr @@ -2925,7 +2931,7 @@ def MaxTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v): M.V_FlowOut[r, p, s, d, i, t, v, S_o] / value(M.Efficiency[r, i, t, v, S_o]) for s in M.time_season for d in M.time_of_day - for S_o in M.ProcessOutputsByInput[r, p, t, v, i] + for S_o in M.processOutputsByInput[r, p, t, v, i] ) total_inp = sum( @@ -2933,10 +2939,10 @@ def MaxTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v): for s in M.time_season for d in M.time_of_day for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, i] + for S_o in M.processOutputsByInput[r, p, t, v, i] ) - expr = inp <= M.MaxTechInputSplitAnnual[r, p, i, t] * total_inp + expr = inp <= value(M.MaxTechInputSplitAnnual[r, p, i, t]) * total_inp return expr @@ -2976,16 +2982,17 @@ def MaxTechOutputSplit_Constraint(M: 'TemoaModel', r, p, s, d, t, v, o): \forall \{r, p, s, d, t, v, o\} \in \Theta_{\text{MaxTechOutputSplit}}""" out = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, o] for S_i in M.ProcessInputsByOutput[r, p, t, v, o] + M.V_FlowOut[r, p, s, d, S_i, t, v, o] + for S_i in M.processInputsByOutput[r, p, t, v, o] ) total_out = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - expr = out <= M.MaxTechOutputSplit[r, p, t, o] * total_out + expr = out <= value(M.MaxTechOutputSplit[r, p, t, o]) * total_out return expr @@ -3006,16 +3013,17 @@ def MaxTechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o): \forall \{r, p, t \in T^{a}, v, o\} \in \Theta_{\text{MaxTechOutputSplitAnnual}}""" out = sum( - M.V_FlowOutAnnual[r, p, S_i, t, v, o] for S_i in M.ProcessInputsByOutput[r, p, t, v, o] + M.V_FlowOutAnnual[r, p, S_i, t, v, o] + for S_i in M.processInputsByOutput[r, p, t, v, o] ) total_out = sum( M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - expr = out <= M.MaxTechOutputSplitAnnual[r, p, t, o] * total_out + expr = out <= value(M.MaxTechOutputSplitAnnual[r, p, t, o]) * total_out return expr @@ -3030,7 +3038,7 @@ def MaxTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o): out = sum( M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, o] - for S_i in M.ProcessInputsByOutput[r, p, t, v, o] + for S_i in M.processInputsByOutput[r, p, t, v, o] for S_s in M.time_season for S_d in M.time_of_day ) @@ -3038,12 +3046,12 @@ def MaxTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o): total_out = sum( M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] for S_s in M.time_season for S_d in M.time_of_day ) - expr = out <= M.MaxTechOutputSplitAnnual[r, p, t, o] * total_out + expr = out <= value(M.MaxTechOutputSplitAnnual[r, p, t, o]) * total_out return expr @@ -3060,7 +3068,7 @@ def RenewablePortfolioStandard_Constraint(M: 'TemoaModel', r, p, g): for s in M.time_season for d in M.time_of_day for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) total_inp = sum( @@ -3069,7 +3077,7 @@ def RenewablePortfolioStandard_Constraint(M: 'TemoaModel', r, p, g): for s in M.time_season for d in M.time_of_day for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) expr = inp >= (value(M.RenewablePortfolioStandard[r, p, g]) * total_inp) @@ -3146,7 +3154,7 @@ def ParamLoanAnnualize_rule(M: 'TemoaModel', r, t, v): def SegFracPerSeason_rule(M: 'TemoaModel', s): - return sum(M.SegFrac[s, S_d] for S_d in M.time_of_day) + return sum(value(M.SegFrac[s, S_d]) for S_d in M.time_of_day) def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): @@ -3175,15 +3183,15 @@ def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): linked_t = M.LinkedTechs[r, t, e] primary_flow = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] * M.EmissionActivity[r, e, S_i, t, v, S_o] + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] * value(M.EmissionActivity[r, e, S_i, t, v, S_o]) for S_i in M.processInputs[r, p, t, v] - for S_o in M.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) linked_flow = sum( M.V_FlowOut[r, p, s, d, S_i, linked_t, v, S_o] for S_i in M.processInputs[r, p, linked_t, v] - for S_o in M.ProcessOutputsByInput[r, p, linked_t, v, S_i] + for S_o in M.processOutputsByInput[r, p, linked_t, v, S_i] ) return -primary_flow == linked_flow @@ -3192,6 +3200,6 @@ def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): # To avoid building big many-indexed parameters when they aren't needed def get_demand_distribution(M: 'TemoaModel', r, p, s, d, dem): if M.demandPeriodDistributions[(r, p, dem)]: - return M.DemandPeriodDistribution[r, p, s, d, dem] + return value(M.DemandPeriodDistribution[r, p, s, d, dem]) else: - return M.DemandSpecificDistribution[r, s, d, dem] \ No newline at end of file + return value(M.DemandSpecificDistribution[r, s, d, dem]) \ No newline at end of file diff --git a/tests/test_exchange_cost_ledger.py b/tests/test_exchange_cost_ledger.py index 055b03ae3..6b75358b5 100644 --- a/tests/test_exchange_cost_ledger.py +++ b/tests/test_exchange_cost_ledger.py @@ -38,7 +38,7 @@ 'tech_annual': set(), 'LifetimeProcess': {('A-B', 't1', 2000): 30, ('B-A', 't1', 2000): 30}, 'processInputs': {('A-B', 2000, 't1', 2000): ('c1',), ('B-A', 2000, 't1', 2000): ('c1',)}, - 'ProcessOutputsByInput': { + 'processOutputsByInput': { ('A-B', 2000, 't1', 2000, 'c1'): ('c1',), ('B-A', 2000, 't1', 2000, 'c1'): ('c1',), }, diff --git a/tests/test_storage.py b/tests/test_storage.py index c7376ae28..3ef6d2f46 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -81,12 +81,12 @@ def test_state_sequencing(system_test_run): charge = sum( model.V_FlowIn[r, p, s, d, S_i, t, v, S_o].value * model.Efficiency[r, S_i, t, v, S_o] for S_i in model.processInputs[r, p, t, v] - for S_o in model.ProcessOutputsByInput[r, p, t, v, S_i] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) discharge = sum( model.V_FlowOut[r, p, s, d, S_i, t, v, S_o].value for S_o in model.processOutputs[r, p, t, v] - for S_i in model.ProcessInputsByOutput[r, p, t, v, S_o] + for S_i in model.processInputsByOutput[r, p, t, v, S_o] ) s_next, d_next = model.time_next[s, d] From 35ee0d10c1e9c35dd54aaec2b4a23d775439e85c Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 27 Jan 2025 13:00:34 -0500 Subject: [PATCH 032/587] Reactivated MaxResource constraint with multiregion indexing --- temoa/temoa_model/hybrid_loader.py | 5 +- temoa/temoa_model/temoa_model.py | 12 ++-- temoa/temoa_model/temoa_rules.py | 109 +++++++++++++++++------------ 3 files changed, 73 insertions(+), 53 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index e35e6143b..ea8820ef2 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -60,8 +60,11 @@ 'EmissionLimit': 'region', 'MinActivityGroup': 'region', 'MaxActivityGroup': 'region', + 'MinActivityShare': 'region', + 'MaxActivityShare': 'region', 'MinCapacityGroup': 'region', 'MaxCapacityGroup': 'region', + 'MaxResource': 'region', } @@ -1128,7 +1131,7 @@ def load_param_idx_sets(self, data: dict) -> dict: M.MinNewCapacityShare.name: M.MinNewCapacityShareConstraint_rptg.name, M.MinNewCapacityGroupShare.name: M.MinNewCapacityGroupShareConstraint_rpgg.name, M.RenewablePortfolioStandard.name: M.RenewablePortfolioStandardConstraint_rpg.name, - M.ResourceBound.name: M.ResourceConstraint_rpr.name, + # M.ResourceBound.name: M.ResourceConstraint_rpr.name, M.StorageFraction.name: M.StorageFractionConstraint_rpsdtv.name } diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 3ab271862..bcd8625c3 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -237,10 +237,10 @@ def __init__(M, *args, **kwargs): M.Demand = Param(M.regions, M.time_optimize, M.commodity_demand) M.initialize_Demands = BuildAction(rule=CreateDemands) - M.ResourceConstraint_rpr = Set(within=M.regions * M.time_optimize * M.commodity_physical) + # M.ResourceConstraint_rpr = Set(within=M.regions * M.time_optimize * M.commodity_physical) # Dev Note: This parameter is currently NOT implemented. Preserved for later refactoring - M.ResourceBound = Param(M.ResourceConstraint_rpr) + # M.ResourceBound = Param(M.ResourceConstraint_rpr) # Define technology performance parameters M.CapacityToActivity = Param(M.RegionalIndices, M.tech_all, default=1) @@ -369,7 +369,7 @@ def __init__(M, *args, **kwargs): ) M.MaxNewCapacity = Param(M.MaxNewCapacityConstraint_rpt) - M.MaxResourceConstraint_rt = Set(within=M.RegionalIndices * M.tech_all) + M.MaxResourceConstraint_rt = Set(within=M.RegionalGlobalIndices * M.tech_all) M.MaxResource = Param(M.MaxResourceConstraint_rt) M.MaxActivityConstraint_rpt = Set( @@ -616,9 +616,9 @@ def __init__(M, *args, **kwargs): M.AnnualCommodityBalanceConstraint_rpc, rule=AnnualCommodityBalance_Constraint ) - M.ResourceExtractionConstraint = Constraint( - M.ResourceConstraint_rpr, rule=ResourceExtraction_Constraint - ) + # M.ResourceExtractionConstraint = Constraint( + # M.ResourceConstraint_rpr, rule=ResourceExtraction_Constraint + # ) M.BaseloadDiurnalConstraint_rpsdtv = Set( dimen=6, initialize=BaseloadDiurnalConstraintIndices diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 841bd2f35..ee8543572 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1016,6 +1016,7 @@ def ResourceExtraction_Constraint(M: 'TemoaModel', reg, p, r): # dev note: This constraint does not have a table in the current schema # Additionally, the below (incorrect) construct assumes that a resource cannot be used # by BOTH a non-annual and annual tech. It should be re-written to add these + # dev note: Cant think of a case where this would be needed but cant use MaxActivityGroup try: collected = sum( M.V_FlowOut[reg, p, S_s, S_d, S_i, S_t, S_v, r] # is r the input or the output!? @@ -2128,37 +2129,43 @@ def MaxResource_Constraint(M: 'TemoaModel', r, t): \sum_{P} \textbf{CAPAVL}_{r, p, t} \le MAR_{r, t} \forall \{r, t\} \in \Theta_{\text{MaxCapacity}}""" - logger.warning( - 'The MaxResource constraint is not currently supported in the model, pending review. Recommend ' - 'removing data from the MaxResource Table' - ) + # logger.warning( + # 'The MaxResource constraint is not currently supported in the model, pending review. Recommend ' + # 'removing data from the MaxResource Table' + # ) # dev note: this constraint is a misnomer. It is actually a "global activity constraint on a tech" # regardless of whatever "resources" are consumed. + # dev note: this would generally be applied to a "dummy import" technology to restrict something like + # oil/mineral extraction across all model periods. Looks fine to me. + + regions = gather_group_regions(M, r) + + if t in M.tech_annual: + activity_rt = sum( + M.V_FlowOutAnnual[_r, p, S_i, t, S_v, S_o] + for p in M.time_optimize + for _r in regions + if (_r, p, t) in M.processVintages.keys() + 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] + ) + else: + activity_rt = sum( + M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] + for p in M.time_optimize + for _r in regions + if (_r, p, t) in M.processVintages.keys() + 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 + ) + max_resource = value(M.MaxResource[r, t]) - return Constraint.Skip - # try: - # activity_rt = sum( - # M.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] - # for p in M.time_optimize - # if (r, p, t) in M.processVintages.keys() - # 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 KeyError: - # activity_rt = sum( - # M.V_FlowOutAnnual[r, p, S_i, t, S_v, S_o] - # for p in M.time_optimize - # if (r, p, t) in M.processVintages.keys() - # 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] - # ) - # - # expr = activity_rt <= max_resource - # return expr + expr = activity_rt <= max_resource + return expr def MaxCapacityGroup_Constraint(M: 'TemoaModel', r, p, g): @@ -2301,42 +2308,52 @@ def MinActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): members are different types for LDVs. This constraint could be used to enforce that no less than 10% of LDVs must be of a certain type.""" + regions = gather_group_regions(M, r) + if t not in M.tech_annual: activity_rpt = sum( - M.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] - for S_v in M.processVintages.get((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] + M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] + for _r in regions + for S_v in M.processVintages.get((_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 + if (_r, p, s, d, S_i, t, S_v, S_o) in M.V_FlowOut ) else: activity_rpt = sum( - M.V_FlowOutAnnual[r, p, S_i, t, S_v, S_o] - for S_v in M.processVintages.get((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] + M.V_FlowOutAnnual[_r, p, S_i, t, S_v, S_o] + for _r in regions + for S_v in M.processVintages.get((_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] + if (_r, p, S_i, t, S_v, S_o) in M.V_FlowOutAnnual ) activity_t = activity_rpt activity_p = sum( - M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, S_o] + M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] for S_t in M.tech_group_members[g] - if (r, p, S_t) in M.processVintages and S_t not in M.tech_annual - for S_v in M.processVintages[r, p, S_t] - for S_i in M.processInputs[r, p, S_t, S_v] - for S_o in M.processOutputsByInput[r, p, S_t, S_v, S_i] + for _r in regions + if (_r, p, S_t) in M.processVintages and S_t not in M.tech_annual + for S_v in M.processVintages[_r, p, S_t] + for S_i in M.processInputs[_r, p, S_t, S_v] + for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] for s in M.time_season for d in M.time_of_day + if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut ) activity_p_annual = sum( - M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, S_o] + M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] for S_t in M.tech_group_members[g] - if (r, p, S_t) in M.processVintages and S_t in M.tech_annual - for S_v in M.processVintages[r, p, S_t] - for S_i in M.processInputs[r, p, S_t, S_v] - for S_o in M.processOutputsByInput[r, p, S_t, S_v, S_i] + for _r in regions + if (_r, p, S_t) in M.processVintages and S_t in M.tech_annual + for S_v in M.processVintages[_r, p, S_t] + for S_i in M.processInputs[_r, p, S_t, S_v] + for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] + if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual ) activity_group = activity_p + activity_p_annual min_activity_share = value(M.MinActivityShare[r, p, t, g]) From 359cba6570b9f59c624f246ddaa09d0bdb69c727 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 27 Jan 2025 18:34:40 -0500 Subject: [PATCH 033/587] Audit and expand group region indexing --- temoa/temoa_model/hybrid_loader.py | 26 +- .../temoa_model/model_checking/validators.py | 4 +- temoa/temoa_model/temoa_initialize.py | 26 +- temoa/temoa_model/temoa_model.py | 61 ++-- temoa/temoa_model/temoa_rules.py | 331 +++++++++++------- temoa/utilities/unit_cost_explorer.py | 2 +- tests/test_storage.py | 4 +- tests/testing_data/mediumville.sql | 6 +- tests/testing_data/mediumville_sets.json | 66 +++- tests/testing_data/test_system_sets.json | 5 +- tests/testing_data/utopia_sets.json | 7 +- 11 files changed, 352 insertions(+), 186 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index ea8820ef2..90fe14993 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -53,18 +53,34 @@ # the tables below are ones in which we might find regional groups which should be captured # to make the members of the RegionalGlobalIndices Set in the model. They need to aggregated tables_with_regional_groups = { - 'MaxActivity': 'region', - 'MinActivity': 'region', 'MinAnnualCapacityFactor': 'region', 'MaxAnnualCapacityFactor': 'region', 'EmissionLimit': 'region', 'MinActivityGroup': 'region', 'MaxActivityGroup': 'region', - 'MinActivityShare': 'region', - 'MaxActivityShare': 'region', + 'MinSeasonalActivity': 'region', + 'MaxSeasonalActivity': 'region', + 'MinCapacity': 'region', + 'MaxCapacity': 'region', + 'MinActivity': 'region', + 'MaxActivity': 'region', + 'MinNewCapacity': 'region', + 'MaxNewCapacity': 'region', + 'MinNewCapacityGroup': 'region', + 'MaxNewCapacityGroup': 'region', 'MinCapacityGroup': 'region', 'MaxCapacityGroup': 'region', + 'MinActivityShare': 'region', + 'MaxActivityShare': 'region', + 'MinCapacityShare': 'region', + 'MaxCapacityShare': 'region', + 'MinNewCapacityShare': 'region', + 'MaxNewCapacityShare': 'region', + 'MinNewCapacityGroupShare': 'region', + 'MaxNewCapacityGroupShare': 'region', 'MaxResource': 'region', + 'GrowthRateMax': 'region', + 'GrowthRateSeed': 'region', } @@ -419,7 +435,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): raise ValueError('Table %s appears to have an empty entry for region.' % table) # sort (for deterministic pyomo behavior) list_of_groups = sorted((t,) for t in regions_and_groups) - load_element(M.RegionalGlobalIndices, list_of_groups) + load_element(M.regionalGlobalIndices, list_of_groups) # region-exchanges # auto-generated diff --git a/temoa/temoa_model/model_checking/validators.py b/temoa/temoa_model/model_checking/validators.py index 16799edde..b5c7e5e38 100644 --- a/temoa/temoa_model/model_checking/validators.py +++ b/temoa/temoa_model/model_checking/validators.py @@ -284,7 +284,7 @@ def validate_Efficiency(M: 'TemoaModel', val, r, si, t, v, so) -> bool: ( isinstance(val, float), val > 0, - r in M.RegionalIndices, + r in M.regionalIndices, si in M.commodity_physical, t in M.tech_all, so in M.commodity_carrier, @@ -293,7 +293,7 @@ def validate_Efficiency(M: 'TemoaModel', val, r, si, t, v, so) -> bool: ): return True print('Element Validations:') - print('region', r in M.RegionalIndices) + print('region', r in M.regionalIndices) print('input_commodity', si in M.commodity_physical) print('tech', t in M.tech_all) print('vintage', v in M.vintage_all) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index e13a8c171..299e285d3 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -22,7 +22,7 @@ from itertools import product as cross_product, product from operator import itemgetter as iget from sys import stderr as SE -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Iterable from deprecated import deprecated from pyomo.core import Set @@ -985,6 +985,13 @@ def CreateSparseDicts(M: 'TemoaModel'): if t not in M.tech_uncap ) + M.groupRegionActiveFlow_rpt = set( + (gr, p, t) + for _r, p, t in M.processVintages.keys() + for gr in M.regionalGlobalIndices + if _r in gather_group_regions(M, gr) + ) + M.storageLevelIndices_rpsdtv = set( (r, p, s, d, t, v) for r, p, t in M.storageVintages.keys() @@ -1049,7 +1056,7 @@ def RegionalGlobalInitializedIndices(M: 'TemoaModel'): for i in regional_perms: indices.add('+'.join(i)) indices.add('global') - indices = indices.union(M.RegionalIndices) + indices = indices.union(M.regionalIndices) return indices @@ -1058,7 +1065,7 @@ def GroupShareIndices(M: 'TemoaModel'): indices = set( (r, p, t, g) for g in M.tech_group_names - for r, p, t in M.processVintages.keys() + for r, p, t in M.groupRegionActiveFlow_rpt if t in M.tech_group_members[g] ) @@ -1070,9 +1077,10 @@ def TwoGroupShareIndices(M: 'TemoaModel'): (r, p, g1, g2) for g1 in M.tech_group_names for g2 in M.tech_group_names - for r, p, _t in M.processVintages.keys() + for r, p, _t in M.groupRegionActiveFlow_rpt if _t in M.tech_group_members[g2] ) + return indices @@ -1633,6 +1641,16 @@ def loop_season_next_timeslice(M: 'TemoaModel', s, d) -> tuple[str, str]: return s_next, d_next +def gather_group_regions(M: 'TemoaModel', region: str) -> Iterable[str]: + if region == 'global': + regions = M.regions + elif '+' in region: + regions = region.split('+') + else: + regions = (region,) + return regions + + def get_loan_life(M, r, t, _): return M.LoanLifetimeTech[r, t] diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index bcd8625c3..58c21fbe2 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -94,6 +94,7 @@ def __init__(M, *args, **kwargs): M.activeCapacity_rtv = None M.activeCapacityAvailable_rpt = None M.activeCapacityAvailable_rptv = None + M.groupRegionActiveFlow_rpt = None # Set of valid group-region, period, tech indices M.commodityBalance_rpc = None # Set of valid region-period-commodity indices to balance M.commodityDStreamProcess = dict() # The downstream process of a commodity during a period M.commodityUStreamProcess = dict() # The upstream process of a commodity during a period @@ -150,8 +151,8 @@ def __init__(M, *args, **kwargs): M.regions = Set(validate=region_check) # RegionalIndices is the set of all the possible combinations of interregional exchanges # plus original region indices. If tech_exchange is empty, RegionalIndices =regions. - M.RegionalIndices = Set(initialize=CreateRegionalIndices) - M.RegionalGlobalIndices = Set(validate=region_group_check) + M.regionalIndices = Set(initialize=CreateRegionalIndices) + M.regionalGlobalIndices = Set(validate=region_group_check) # Define technology-related sets M.tech_resource = Set() @@ -243,9 +244,9 @@ def __init__(M, *args, **kwargs): # M.ResourceBound = Param(M.ResourceConstraint_rpr) # Define technology performance parameters - M.CapacityToActivity = Param(M.RegionalIndices, M.tech_all, default=1) + M.CapacityToActivity = Param(M.regionalIndices, M.tech_all, default=1) - M.ExistingCapacity = Param(M.RegionalIndices, M.tech_with_capacity, M.vintage_exist) + M.ExistingCapacity = Param(M.regionalIndices, M.tech_with_capacity, M.vintage_exist) # Dev Note: The below is temporarily useful for passing down to validator to find set violations # Uncomment this assignment, and comment out the orig below it... @@ -254,7 +255,7 @@ def __init__(M, *args, **kwargs): # within=NonNegativeReals, validate=validate_Efficiency # ) M.Efficiency = Param( - M.RegionalIndices, + M.regionalIndices, M.commodity_physical, M.tech_all, M.vintage_all, @@ -283,13 +284,13 @@ def __init__(M, *args, **kwargs): # M.initialize_CapacityFactors = BuildAction(rule=CreateCapacityFactors) M.LifetimeTech = Param( - M.RegionalIndices, M.tech_all, default=TemoaModel.default_lifetime_tech + M.regionalIndices, M.tech_all, default=TemoaModel.default_lifetime_tech ) M.LifetimeProcess_rtv = Set(dimen=3, initialize=LifetimeProcessIndices) M.LifetimeProcess = Param(M.LifetimeProcess_rtv, default=get_default_process_lifetime) - M.LoanLifetimeTech = Param(M.RegionalIndices, M.tech_all, default=10) + M.LoanLifetimeTech = Param(M.regionalIndices, M.tech_all, default=10) M.LoanLifetimeProcess_rtv = Set(dimen=3, initialize=LifetimeLoanProcessIndices) # Dev Note: The LoanLifetimeProcess table *could* be removed. There is no longer a supporting @@ -327,7 +328,7 @@ def __init__(M, *args, **kwargs): M.CostFixed_rptv = Set(dimen=4, initialize=CostFixedIndices) M.CostFixed = Param(M.CostFixed_rptv) - M.CostInvest_rtv = Set(within=M.RegionalIndices * M.tech_all * M.time_optimize) + M.CostInvest_rtv = Set(within=M.regionalIndices * M.tech_all * M.time_optimize) M.CostInvest = Param(M.CostInvest_rtv) M.DefaultLoanRate = Param(domain=NonNegativeReals) @@ -349,96 +350,96 @@ def __init__(M, *args, **kwargs): M.ProcessLifeFrac = Param(M.ProcessLifeFrac_rptv, initialize=ParamProcessLifeFraction_rule) M.MinCapacityConstraint_rpt = Set( - within=M.RegionalIndices * M.time_optimize * M.tech_with_capacity + within=M.regionalGlobalIndices * M.time_optimize * M.tech_with_capacity ) M.MinCapacity = Param(M.MinCapacityConstraint_rpt) M.MaxCapacityConstraint_rpt = Set( - within=M.RegionalIndices * M.time_optimize * M.tech_with_capacity + within=M.regionalGlobalIndices * M.time_optimize * M.tech_with_capacity ) M.MaxCapacity = Param(M.MaxCapacityConstraint_rpt) M.MinNewCapacityConstraint_rpt = Set( - within=M.RegionalIndices * M.time_optimize * M.tech_with_capacity + within=M.regionalGlobalIndices * M.time_optimize * M.tech_with_capacity ) M.MinNewCapacity = Param(M.MinNewCapacityConstraint_rpt) M.MaxNewCapacityConstraint_rpt = Set( - within=M.RegionalIndices * M.time_optimize * M.tech_with_capacity + within=M.regionalGlobalIndices * M.time_optimize * M.tech_with_capacity ) M.MaxNewCapacity = Param(M.MaxNewCapacityConstraint_rpt) - M.MaxResourceConstraint_rt = Set(within=M.RegionalGlobalIndices * M.tech_all) + M.MaxResourceConstraint_rt = Set(within=M.regionalGlobalIndices * M.tech_all) M.MaxResource = Param(M.MaxResourceConstraint_rt) M.MaxActivityConstraint_rpt = Set( - within=M.RegionalGlobalIndices * M.time_optimize * M.tech_all + within=M.regionalGlobalIndices * M.time_optimize * M.tech_all ) M.MaxActivity = Param(M.MaxActivityConstraint_rpt) M.MinActivityConstraint_rpt = Set( - within=M.RegionalGlobalIndices * M.time_optimize * M.tech_all + within=M.regionalGlobalIndices * M.time_optimize * M.tech_all ) M.MinActivity = Param(M.MinActivityConstraint_rpt) M.MaxSeasonalActivityConstraint_rpst = Set( - within=M.RegionalGlobalIndices * M.time_optimize * M.time_season * M.tech_all + within=M.regionalGlobalIndices * M.time_optimize * M.time_season * M.tech_all ) M.MaxSeasonalActivity = Param(M.MaxSeasonalActivityConstraint_rpst) M.MinSeasonalActivityConstraint_rpst = Set( - within=M.RegionalGlobalIndices * M.time_optimize * M.time_season * M.tech_all + within=M.regionalGlobalIndices * M.time_optimize * M.time_season * M.tech_all ) M.MinSeasonalActivity = Param(M.MinSeasonalActivityConstraint_rpst) M.MinAnnualCapacityFactorConstraint_rpto = Set( - within=M.RegionalGlobalIndices * M.time_optimize * M.tech_all * M.commodity_carrier + within=M.regionalGlobalIndices * M.time_optimize * M.tech_all * M.commodity_carrier ) M.MinAnnualCapacityFactor = Param(M.MinAnnualCapacityFactorConstraint_rpto) M.MaxAnnualCapacityFactorConstraint_rpto = Set( - within=M.RegionalGlobalIndices * M.time_optimize * M.tech_all * M.commodity_carrier + within=M.regionalGlobalIndices * M.time_optimize * M.tech_all * M.commodity_carrier ) M.MaxAnnualCapacityFactor = Param(M.MaxAnnualCapacityFactorConstraint_rpto) - M.GrowthRateMax = Param(M.RegionalIndices, M.tech_all) - M.GrowthRateSeed = Param(M.RegionalIndices, M.tech_all) + M.GrowthRateMax = Param(M.regionalGlobalIndices, M.tech_all) + M.GrowthRateSeed = Param(M.regionalGlobalIndices, M.tech_all) M.EmissionLimitConstraint_rpe = Set( - within=M.RegionalGlobalIndices * M.time_optimize * M.commodity_emissions + within=M.regionalGlobalIndices * M.time_optimize * M.commodity_emissions ) M.EmissionLimit = Param(M.EmissionLimitConstraint_rpe) M.EmissionActivity_reitvo = Set(dimen=6, initialize=EmissionActivityIndices) M.EmissionActivity = Param(M.EmissionActivity_reitvo) M.MinActivityGroup_rpg = Set( - within=M.RegionalGlobalIndices * M.time_optimize * M.tech_group_names + within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names ) M.MinActivityGroup = Param(M.MinActivityGroup_rpg) M.MaxActivityGroup_rpg = Set( - within=M.RegionalGlobalIndices * M.time_optimize * M.tech_group_names + within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names ) M.MaxActivityGroup = Param(M.MaxActivityGroup_rpg) M.MinCapacityGroupConstraint_rpg = Set( - within=M.RegionalGlobalIndices * M.time_optimize * M.tech_group_names + within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names ) M.MinCapacityGroup = Param(M.MinCapacityGroupConstraint_rpg) M.MaxCapacityGroupConstraint_rpg = Set( - within=M.RegionalGlobalIndices * M.time_optimize * M.tech_group_names + within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names ) M.MaxCapacityGroup = Param(M.MaxCapacityGroupConstraint_rpg) M.MinNewCapacityGroupConstraint_rpg = Set( - within=M.RegionalIndices * M.time_optimize * M.tech_group_names + within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names ) M.MinNewCapacityGroup = Param(M.MinNewCapacityGroupConstraint_rpg) M.MaxNewCapacityGroupConstraint_rpg = Set( - within=M.RegionalIndices * M.time_optimize * M.tech_group_names + within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names ) M.MaxNewCapacityGroup = Param(M.MaxNewCapacityGroupConstraint_rpg) M.GroupShareIndices = Set(dimen=4, initialize=GroupShareIndices) @@ -477,14 +478,14 @@ def __init__(M, *args, **kwargs): # Storage duration is expressed in hours M.StorageDuration = Param(M.regions, M.tech_storage, default=4) - M.LinkedTechs = Param(M.RegionalIndices, M.tech_all, M.commodity_emissions, within=Any) + M.LinkedTechs = Param(M.regionalIndices, M.tech_all, M.commodity_emissions, within=Any) # Define parameters associated with electric sector operation M.RampUp = Param(M.regions, M.tech_upramping) M.RampDown = Param(M.regions, M.tech_downramping) M.CapacityCredit = Param( - M.RegionalIndices, M.time_optimize, M.tech_all, M.vintage_all, default=0 + M.regionalIndices, M.time_optimize, M.tech_all, M.vintage_all, default=0 ) M.PlanningReserveMargin = Param(M.regions, default=0.2) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index ee8543572..a50504e17 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -21,7 +21,7 @@ from logging import getLogger from sys import stderr as SE -from typing import TYPE_CHECKING, Iterable +from typing import TYPE_CHECKING from pyomo.core import Var, Expression from pyomo.environ import Constraint, value @@ -30,6 +30,7 @@ DemandConstraintErrorCheck, CommodityBalanceConstraintErrorCheck, AnnualCommodityBalanceConstraintErrorCheck, + gather_group_regions, ) if TYPE_CHECKING: @@ -1418,7 +1419,7 @@ def RampUp_Constraint(M: 'TemoaModel', r, p, s, d, t, v): for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) / value(M.SegFrac[s_next, d_next]) - hours_elapsed = 8760 * (value(M.SegFrac[s, d]) + value(M.SegFrac[s_next, d_next])) / 2 + hours_elapsed = 8760 * ( value(M.SegFrac[s, d]) + value(M.SegFrac[s_next, d_next]) ) / 2 hours_elapsed /= M.SegFracPerSeason[s] * 365 # adjust for how many days this season represents ramp_fraction = hours_elapsed * value(M.RampUp[r, t]) @@ -1476,7 +1477,7 @@ def RampDown_Constraint(M: 'TemoaModel', r, p, s, d, t, v): for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) / value(M.SegFrac[s_next, d_next]) - hours_elapsed = 8760 * (value(M.SegFrac[s, d]) + value(M.SegFrac[s_next, d_next])) / 2 + hours_elapsed = 8760 * ( value(M.SegFrac[s, d]) + value(M.SegFrac[s_next, d_next]) ) / 2 hours_elapsed /= M.SegFracPerSeason[s] * 365 # adjust for how many days this season represents ramp_fraction = hours_elapsed * value(M.RampDown[r, t]) @@ -1543,7 +1544,7 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): # First, determine the amount of firm capacity each exchange tech # contributes. - for r1r2 in M.RegionalIndices: + for r1r2 in M.regionalIndices: if '-' not in r1r2: continue r1, r2 = r1r2.split('-') @@ -1589,7 +1590,7 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): # Electricity imports and exports via exchange techs are accounted # for below: - for r1r2 in M.RegionalIndices: # ensure the region is of the form r1-r2 + for r1r2 in M.regionalIndices: # ensure the region is of the form r1-r2 if '-' not in r1r2: continue if (r1r2, p) not in M.processReservePeriods: # ensure the technology in question exists @@ -1656,7 +1657,7 @@ def EmissionLimit_Constraint(M: 'TemoaModel', r, p, e): # if r == 'global', the constraint is system-wide - regions = gather_group_regions(M=M, region=r) + regions = gather_group_regions(M, r) # ================= Emissions and Flex and Curtailment ================= # Flex flows are deducted from V_FlowOut, so it is NOT NEEDED to tax them again. (See commodity balance constr) @@ -1685,10 +1686,11 @@ def EmissionLimit_Constraint(M: 'TemoaModel', r, p, e): ) embodied_emissions = sum( - M.V_NewCapacity[r, t, v] - * value(M.EmissionEmbodied[r, e, t, v]) + M.V_NewCapacity[reg, t, v] + * value(M.EmissionEmbodied[reg, e, t, v]) + for reg in regions for (S_r, S_e, t, v) in M.EmissionEmbodied.sparse_iterkeys() - if v == p and S_r == r and S_e == e + if v == p and S_r == reg and S_e == e ) expr = ( @@ -1730,27 +1732,33 @@ def GrowthRateMaxConstraint_rule(M: 'TemoaModel', r, p, t): period would be restricted to zero capacity for the remainder of the time horizon. """ + + regions = gather_group_regions(M, r) + GRS = value(M.GrowthRateSeed[r, t]) GRM = value(M.GrowthRateMax[r, t]) CapPT = M.V_CapacityAvailableByPeriodAndTech # periods the technology can have capacity in this region (sorted) - periods = sorted(set(S_p for S_r, S_p, S_t in CapPT if S_t == t and S_r == r)) + periods = sorted(set(_p for _r, _p, _t in CapPT if _t == t and _r in regions)) if p not in periods: # cant have capacity in this period return Constraint.Skip + capacity = sum(CapPT[_r, p, t] for _r in regions) + if p == periods[0]: # first period it can have capacity # plant a seed and grow it - expr = CapPT[r, p, t] <= GRS * GRM + expr = capacity <= GRS * GRM else: # can have capacity in previous period # plant a seed and grow last period's capacity # note: we plant a seed every period to survive zero-outs p_prev = periods[periods.index(p) - 1] # previous period - expr = CapPT[r, p, t] <= GRS + GRM * CapPT[r, p_prev, t] + capacity_prev = sum(CapPT[_r, p_prev, t] for _r in regions) + expr = capacity <= GRS + GRM * capacity_prev return expr @@ -1779,27 +1787,27 @@ def MaxActivity_Constraint(M: 'TemoaModel', r, p, t): # r can be an individual region (r='US'), or a combination of regions separated by # a + (r='Mexico+US+Canada'), or 'global'. # if r == 'global', the constraint is system-wide - reg = gather_group_regions(M=M, region=r) + regions = gather_group_regions(M=M, region=r) if t not in M.tech_annual: activity_rpt = sum( - M.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] - for r in reg - for S_v in M.processVintages.get((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] + M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] + for _r in regions + for S_v in M.processVintages.get((_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 - if (r, p, s, d, S_i, t, S_v, S_o) in M.V_FlowOut + if (_r, p, s, d, S_i, t, S_v, S_o) in M.V_FlowOut ) else: activity_rpt = sum( - M.V_FlowOutAnnual[r, p, S_i, t, S_v, S_o] - for r in reg - for S_v in M.processVintages.get((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] - if (r, p, S_i, t, S_v, S_o) in M.V_FlowOutAnnual + M.V_FlowOutAnnual[_r, p, S_i, t, S_v, S_o] + for _r in regions + for S_v in M.processVintages.get((_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] + if (_r, p, S_i, t, S_v, S_o) in M.V_FlowOutAnnual ) max_act = value(M.MaxActivity[r, p, t]) @@ -1837,12 +1845,15 @@ def MaxSeasonalActivity_Constraint(M: 'TemoaModel', r, p, s, t): # must be converted back to its un-scaled value. We do this by dividing the # V_FlowOut value by M.SegFrac[s, d]*365*24. + regions = gather_group_regions(M, r) + try: activity_rpst = sum( - M.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] / (value(M.SegFrac[s, d])*365*24) - 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] + M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] / (value(M.SegFrac[s, d])*365*24) + for _r in regions + 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 d in M.time_of_day ) except: @@ -1953,12 +1964,15 @@ def MinSeasonalActivity_Constraint(M: 'TemoaModel', r, p, s, t): # must be converted back to its un-scaled value. We do this using the # weighting_factor below: + regions = gather_group_regions(M, r) + try: activity_rpst = sum( - M.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] / (value(M.SegFrac[s, d])*365*24) - 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] + M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] / (value(M.SegFrac[s, d])*365*24) + for _r in regions + 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 d in M.time_of_day ) except: @@ -2001,27 +2015,27 @@ def MinActivityGroup_Constraint(M: 'TemoaModel', r, p, g): activity_p = 0 activity_p_annual = 0 - for r_i in regions: + for _r in regions: activity_p += sum( - M.V_FlowOut[r_i, p, s, d, S_i, S_t, S_v, S_o] + M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] for S_t in M.tech_group_members[g] - if (r_i, p, S_t) in M.processVintages and S_t not in M.tech_annual - for S_v in M.processVintages[r_i, p, S_t] - for S_i in M.processInputs[r_i, p, S_t, S_v] - for S_o in M.processOutputsByInput[r_i, p, S_t, S_v, S_i] + if (_r, p, S_t) in M.processVintages and S_t not in M.tech_annual + for S_v in M.processVintages[_r, p, S_t] + for S_i in M.processInputs[_r, p, S_t, S_v] + for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] for s in M.time_season for d in M.time_of_day - if (r_i, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut + if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut ) activity_p_annual += sum( - M.V_FlowOutAnnual[r_i, p, S_i, S_t, S_v, S_o] + M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] for S_t in M.tech_group_members[g] - if (r_i, p, S_t) in M.processVintages and S_t in M.tech_annual - for S_v in M.processVintages[r_i, p, S_t] - for S_i in M.processInputs[r_i, p, S_t, S_v] - for S_o in M.processOutputsByInput[r_i, p, S_t, S_v, S_i] - if (r_i, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual + if (_r, p, S_t) in M.processVintages and S_t in M.tech_annual + for S_v in M.processVintages[_r, p, S_t] + for S_i in M.processInputs[_r, p, S_t, S_v] + for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] + if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual ) min_act = value(M.MinActivityGroup[r, p, g]) expr = activity_p + activity_p_annual >= min_act @@ -2055,26 +2069,26 @@ def MaxActivityGroup_Constraint(M: 'TemoaModel', r, p, g): activity_p = 0 activity_p_annual = 0 - for r_i in regions: + for _r in regions: activity_p += sum( - M.V_FlowOut[r_i, p, s, d, S_i, S_t, S_v, S_o] + M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] for S_t in M.tech_group_members[g] - if (r_i, p, S_t) in M.processVintages and S_t not in M.tech_annual - for S_v in M.processVintages[r_i, p, S_t] - for S_i in M.processInputs[r_i, p, S_t, S_v] - for S_o in M.processOutputsByInput[r_i, p, S_t, S_v, S_i] + if (_r, p, S_t) in M.processVintages and S_t not in M.tech_annual + for S_v in M.processVintages[_r, p, S_t] + for S_i in M.processInputs[_r, p, S_t, S_v] + for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] for s in M.time_season for d in M.time_of_day - if (r_i, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut + if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut ) activity_p_annual += sum( - M.V_FlowOutAnnual[r_i, p, S_i, S_t, S_v, S_o] + M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] for S_t in M.tech_group_members[g] - if (r_i, p, S_t) in M.processVintages and S_t in M.tech_annual - for S_v in M.processVintages[r_i, p, S_t] - for S_i in M.processInputs[r_i, p, S_t, S_v] - for S_o in M.processOutputsByInput[r_i, p, S_t, S_v, S_i] - if (r_i, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual + if (_r, p, S_t) in M.processVintages and S_t in M.tech_annual + for S_v in M.processVintages[_r, p, S_t] + for S_i in M.processInputs[_r, p, S_t, S_v] + for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] + if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual ) max_act = value(M.MaxActivityGroup[r, p, g]) @@ -2093,8 +2107,13 @@ def MaxNewCapacity_Constraint(M: 'TemoaModel', r, p, t): .. math:: :label: MaxNewCapacity \textbf{CAP}_{r, t, p} \le MAX_{r, p, t}""" + regions = gather_group_regions(M, r) max_cap = value(M.MaxNewCapacity[r, p, t]) - expr = M.V_NewCapacity[r, t, p] <= max_cap + new_cap = sum( + M.V_NewCapacity[_r, t, p] + for _r in regions + ) + expr = new_cap <= max_cap return expr @@ -2111,8 +2130,13 @@ def MaxCapacity_Constraint(M: 'TemoaModel', r, p, t): \textbf{CAPAVL}_{r, p, t} \le MAC_{r, p, t} \forall \{r, p, t\} \in \Theta_{\text{MaxCapacity}}""" + regions = gather_group_regions(M, r) max_cap = value(M.MaxCapacity[r, p, t]) - expr = M.V_CapacityAvailableByPeriodAndTech[r, p, t] <= max_cap + capacity = sum( + M.V_CapacityAvailableByPeriodAndTech[_r, p, t] + for _r in regions + ) + expr = capacity <= max_cap return expr @@ -2177,10 +2201,10 @@ def MaxCapacityGroup_Constraint(M: 'TemoaModel', r, p, g): max_capgroup = value(M.MaxCapacityGroup[r, p, g]) cap = sum( - M.V_CapacityAvailableByPeriodAndTech[r_i, p, t] + M.V_CapacityAvailableByPeriodAndTech[_r, p, t] for t in M.tech_group_members[g] - for r_i in regions - if (r_i, p, t) in M.V_CapacityAvailableByPeriodAndTech + for _r in regions + if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech ) expr = cap <= max_capgroup @@ -2203,8 +2227,13 @@ def MinNewCapacity_Constraint(M: 'TemoaModel', r, p, t): .. math:: :label: MaxMinCapacity \textbf{CAP}_{r, t, p} \ge MIN_{r, p, t}""" + regions = gather_group_regions(M, r) min_cap = value(M.MinNewCapacity[r, p, t]) - expr = M.V_NewCapacity[r, t, p] >= min_cap + new_cap = sum( + M.V_NewCapacity[_r, t, p] + for _r in regions + ) + expr = new_cap >= min_cap return expr @@ -2221,21 +2250,16 @@ def MinCapacity_Constraint(M: 'TemoaModel', r, p, t): \textbf{CAPAVL}_{r, p, t} \ge MIC_{r, p, t} \forall \{r, p, t\} \in \Theta_{\text{MinCapacity}}""" + regions = gather_group_regions(M, r) min_cap = value(M.MinCapacity[r, p, t]) - expr = M.V_CapacityAvailableByPeriodAndTech[r, p, t] >= min_cap + capacity = sum( + M.V_CapacityAvailableByPeriodAndTech[_r, p, t] + for _r in regions + ) + expr = capacity >= min_cap return expr -def gather_group_regions(M: 'TemoaModel', region: str) -> Iterable[str]: - if region == 'global': - regions = M.regions - elif '+' in region: - regions = region.split('+') - else: - regions = (region,) - return regions - - def MinCapacityGroup_Constraint(M: 'TemoaModel', r, p, g): r""" Similar to the :code:`MinCapacity` constraint, but works on a group of technologies. @@ -2266,16 +2290,20 @@ def MinCapacityGroup_Constraint(M: 'TemoaModel', r, p, g): def MinNewCapacityGroup_Constraint(M: 'TemoaModel', r, p, g): r""" Similar to the :code:`MinNewCapacity` constraint, but works on a group of technologies.""" + + regions = gather_group_regions(M, r) + min_new_cap = value(M.MinNewCapacityGroup[r, p, g]) agg_new_cap = sum( - M.V_NewCapacity[r, t, p] + M.V_NewCapacity[_r, t, p] for t in M.tech_group_members[g] - if (r, p, t) in M.V_CapacityAvailableByPeriodAndTech + for _r in regions + if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech ) expr = agg_new_cap >= min_new_cap if isinstance(expr, bool): logger.error( - 'No elements available to support min-capacity group: (%s, %d, %s).' + 'No elements available to support min new capacity group: (%s, %d, %s).' ' Check data/log for available/suppressed techs. Requirement IGNORED.', r, p, @@ -2288,14 +2316,25 @@ def MinNewCapacityGroup_Constraint(M: 'TemoaModel', r, p, g): def MaxNewCapacityGroup_Constraint(M: 'TemoaModel', r, p, g): r""" Similar to the :code:`MinNewCapacity` constraint, but works on a group of technologies.""" + + regions = gather_group_regions(M, r) + max_new_cap = value(M.MaxNewCapacityGroup[r, p, g]) agg_new_cap = sum( - M.V_NewCapacity[r, t, p] + M.V_NewCapacity[_r, t, p] for t in M.tech_group_members[g] - if (r, p, t) in M.V_CapacityAvailableByPeriodAndTech + for _r in regions + if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech ) expr = max_new_cap >= agg_new_cap if isinstance(expr, bool): + logger.error( + 'No elements available to support max new capacity group: (%s, %d, %s).' + ' Check data/log for available/suppressed techs. Requirement IGNORED.', + r, + p, + g, + ) return Constraint.Skip return expr @@ -2311,7 +2350,7 @@ def MinActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): regions = gather_group_regions(M, r) if t not in M.tech_annual: - activity_rpt = sum( + activity_tech = sum( M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] for _r in regions for S_v in M.processVintages.get((_r, p, t), []) @@ -2322,7 +2361,7 @@ def MinActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): if (_r, p, s, d, S_i, t, S_v, S_o) in M.V_FlowOut ) else: - activity_rpt = sum( + activity_tech = sum( M.V_FlowOutAnnual[_r, p, S_i, t, S_v, S_o] for _r in regions for S_v in M.processVintages.get((_r, p, t), []) @@ -2331,8 +2370,7 @@ def MinActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): if (_r, p, S_i, t, S_v, S_o) in M.V_FlowOutAnnual ) - activity_t = activity_rpt - activity_p = sum( + activity_group = sum( M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] for S_t in M.tech_group_members[g] for _r in regions @@ -2344,8 +2382,7 @@ def MinActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): for d in M.time_of_day if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut ) - - activity_p_annual = sum( + activity_group_annual = sum( M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] for S_t in M.tech_group_members[g] for _r in regions @@ -2355,10 +2392,10 @@ def MinActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual ) - activity_group = activity_p + activity_p_annual - min_activity_share = value(M.MinActivityShare[r, p, t, g]) + activity_group = activity_group + activity_group_annual - expr = activity_t >= min_activity_share * activity_group + min_activity_share = value(M.MinActivityShare[r, p, t, g]) + expr = activity_tech >= min_activity_share * activity_group # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated logger.error( @@ -2383,7 +2420,7 @@ def MaxActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): regions = gather_group_regions(M, r) if t not in M.tech_annual: - activity_rpt = sum( + activity_tech = sum( M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] for _r in regions for S_v in M.processVintages.get((_r, p, t), []) @@ -2394,7 +2431,7 @@ def MaxActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): if (_r, p, s, d, S_i, t, S_v, S_o) in M.V_FlowOut ) else: - activity_rpt = sum( + activity_tech = sum( M.V_FlowOutAnnual[_r, p, S_i, t, S_v, S_o] for _r in regions for S_v in M.processVintages.get((_r, p, t), []) @@ -2403,8 +2440,7 @@ def MaxActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): if (_r, p, S_i, t, S_v, S_o) in M.V_FlowOutAnnual ) - activity_t = activity_rpt - activity_p = sum( + activity_group = sum( M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] for S_t in M.tech_group_members[g] for _r in regions @@ -2416,8 +2452,7 @@ def MaxActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): for d in M.time_of_day if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut ) - - activity_p_annual = sum( + activity_group_annual = sum( M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] for S_t in M.tech_group_members[g] for _r in regions @@ -2427,10 +2462,10 @@ def MaxActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual ) - activity_group = activity_p + activity_p_annual - max_activity_share = value(M.MaxActivityShare[r, p, t, g]) + activity_group = activity_group + activity_group_annual - expr = activity_t <= max_activity_share * activity_group + max_activity_share = value(M.MaxActivityShare[r, p, t, g]) + expr = activity_tech <= max_activity_share * activity_group # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated return Constraint.Skip @@ -2449,11 +2484,17 @@ def MinCapacityShare_Constraint(M: 'TemoaModel', r, p, t, g): members are different types for LDVs. This constraint could be used to enforce that no less than 10% of LDVs must be of a certain type.""" - capacity_t = M.V_CapacityAvailableByPeriodAndTech[r, p, t] + regions = gather_group_regions(M, r) + + capacity_t = sum( + M.V_CapacityAvailableByPeriodAndTech[_r, p, t] + for _r in regions + ) capacity_group = sum( - M.V_CapacityAvailableByPeriodAndTech[r, p, S_t] + M.V_CapacityAvailableByPeriodAndTech[_r, p, S_t] for S_t in M.tech_group_members[g] - if (r, p, S_t) in M.processVintages.keys() + for _r in regions + if (_r, p, S_t) in M.processVintages.keys() ) min_cap_share = value(M.MinCapacityShare[r, p, t, g]) @@ -2478,11 +2519,17 @@ def MaxCapacityShare_Constraint(M: 'TemoaModel', r, p, t, g): members are different types for LDVs. This constraint could be used to enforce that no more than 10% of LDVs must be of a certain type.""" - capacity_t = M.V_CapacityAvailableByPeriodAndTech[r, p, t] + regions = gather_group_regions(M, r) + + capacity_t = sum( + M.V_CapacityAvailableByPeriodAndTech[_r, p, t] + for _r in regions + ) capacity_group = sum( - M.V_CapacityAvailableByPeriodAndTech[r, p, S_t] + M.V_CapacityAvailableByPeriodAndTech[_r, p, S_t] for S_t in M.tech_group_members[g] - if (r, p, S_t) in M.processVintages.keys() + for _r in regions + if (_r, p, S_t) in M.processVintages.keys() ) max_cap_share = value(M.MaxCapacityShare[r, p, t, g]) @@ -2500,11 +2547,17 @@ def MinNewCapacityShare_Constraint(M: 'TemoaModel', r, p, t, g): members are different types for LDVs. This constraint could be used to enforce that no less than 10% of new LDV purchases in a given year must be of a certain type.""" - capacity_t = M.V_NewCapacity[r, t, p] + regions = gather_group_regions(M, r) + + capacity_t = sum( + M.V_NewCapacity[_r, t, p] + for _r in regions + ) capacity_group = sum( - M.V_NewCapacity[r, S_t, p] + M.V_NewCapacity[_r, S_t, p] for S_t in M.tech_group_members[g] - if (r, S_t, p) in M.V_NewCapacity.keys() + for _r in regions + if (_r, S_t, p) in M.V_NewCapacity.keys() ) min_cap_share = value(M.MinNewCapacityShare[r, p, t, g]) @@ -2529,11 +2582,17 @@ def MaxNewCapacityShare_Constraint(M: 'TemoaModel', r, p, t, g): members are different types for LDVs. This constraint could be used to enforce that no more than 10% of LDV purchases in a given year must be of a certain type.""" - capacity_t = M.V_NewCapacity[r, t, p] + regions = gather_group_regions(M, r) + + capacity_t = sum( + M.V_NewCapacity[_r, t, p] + for _r in regions + ) capacity_group = sum( - M.V_NewCapacity[r, S_t, p] + M.V_NewCapacity[_r, S_t, p] for S_t in M.tech_group_members[g] - if (r, S_t, p) in M.V_NewCapacity.keys() + for _r in regions + if (_r, S_t, p) in M.V_NewCapacity.keys() ) max_cap_share = value(M.MaxNewCapacityShare[r, p, t, g]) @@ -2548,22 +2607,27 @@ def MinNewCapacityGroupShare_Constraint(M: 'TemoaModel', r, p, g1, g2): Sets the minimum aggregate capacity of one group of technologies as a share of another group of technologies. """ + + regions = gather_group_regions(M, r) + min_share = value(M.MinNewCapacityGroupShare[r, p, g1, g2]) agg_new_cap_g1 = sum( - M.V_NewCapacity[r, t, p] + M.V_NewCapacity[_r, t, p] for t in M.tech_group_members[g1] - if (r, p, t) in M.V_CapacityAvailableByPeriodAndTech + for _r in regions + if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech ) agg_new_cap_g2 = sum( - M.V_NewCapacity[r, t, p] + M.V_NewCapacity[_r, t, p] for t in M.tech_group_members[g2] - if (r, p, t) in M.V_CapacityAvailableByPeriodAndTech + for _r in regions + if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech ) expr = agg_new_cap_g1 >= agg_new_cap_g2 * min_share if isinstance(expr, bool): # one side of expression was empty logger.error( - 'Missing group techs to support min new capacity group share constraint: {}.' + 'Missing group techs to support min new capacity group share constraint: %s.' ' Check data/log for available/suppressed techs. Constraint ignored.', (r, p, g1, g2) ) @@ -2577,22 +2641,27 @@ def MaxNewCapacityGroupShare_Constraint(M: 'TemoaModel', r, p, g1, g2): Sets the maximum aggregate capacity of one group of technologies as a share of another group of technologies. """ + + regions = gather_group_regions(M, r) + max_share = value(M.MaxNewCapacityGroupShare[r, p, g1, g2]) agg_new_cap_g1 = sum( - M.V_NewCapacity[r, t, p] + M.V_NewCapacity[_r, t, p] for t in M.tech_group_members[g1] - if (r, p, t) in M.V_CapacityAvailableByPeriodAndTech + for _r in regions + if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech ) agg_new_cap_g2 = sum( - M.V_NewCapacity[r, t, p] + M.V_NewCapacity[_r, t, p] for t in M.tech_group_members[g2] - if (r, p, t) in M.V_CapacityAvailableByPeriodAndTech + for _r in regions + if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech ) expr = agg_new_cap_g1 <= agg_new_cap_g2 * max_share if isinstance(expr, bool): # one side of expression was empty logger.error( - 'Missing group techs to support max new capacity group share constraint: {}.' + 'Missing group techs to support max new capacity group share constraint: %s.' ' Check data/log for available/suppressed techs. Constraint ignored.', (r, p, g1, g2) ) @@ -2619,7 +2688,10 @@ def MinAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o): regions = gather_group_regions(M, r) # we need to screen here because it is possible that the restriction extends beyond the # lifetime of any vintage of the tech... - if (r, p, t) not in M.V_CapacityAvailableByPeriodAndTech: + if all( + (_r, p, t) not in M.V_CapacityAvailableByPeriodAndTech + for _r in regions + ): return Constraint.Skip if t not in M.tech_annual: @@ -2641,8 +2713,9 @@ def MinAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o): if (_r, p, S_i, t, S_v, o) in M.V_FlowOutAnnual ) - max_possible_activity_rpt = ( - M.V_CapacityAvailableByPeriodAndTech[r, p, t] * value(M.CapacityToActivity[r, t]) + max_possible_activity_rpt = sum( + M.V_CapacityAvailableByPeriodAndTech[_r, p, t] * value(M.CapacityToActivity[_r, t]) + for _r in regions ) min_annual_cf = value(M.MinAnnualCapacityFactor[r, p, t, o]) expr = activity_rpt >= min_annual_cf * max_possible_activity_rpt @@ -2677,7 +2750,10 @@ def MaxAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o): regions = gather_group_regions(M, r) # we need to screen here because it is possible that the restriction extends beyond the # lifetime of any vintage of the tech... - if (r, p, t) not in M.V_CapacityAvailableByPeriodAndTech: + if all( + (_r, p, t) not in M.V_CapacityAvailableByPeriodAndTech + for _r in regions + ): return Constraint.Skip if t not in M.tech_annual: @@ -2699,8 +2775,9 @@ def MaxAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o): if (_r, p, S_i, t, S_v, o) in M.V_FlowOutAnnual ) - max_possible_activity_rpt = ( - M.V_CapacityAvailableByPeriodAndTech[r, p, t] * value(M.CapacityToActivity[r, t]) + max_possible_activity_rpt = sum( + M.V_CapacityAvailableByPeriodAndTech[_r, p, t] * value(M.CapacityToActivity[_r, t]) + for _r in regions ) max_annual_cf = value(M.MaxAnnualCapacityFactor[r, p, t, o]) expr = activity_rpt <= max_annual_cf * max_possible_activity_rpt diff --git a/temoa/utilities/unit_cost_explorer.py b/temoa/utilities/unit_cost_explorer.py index fff83fa72..c33552cd7 100644 --- a/temoa/utilities/unit_cost_explorer.py +++ b/temoa/utilities/unit_cost_explorer.py @@ -37,7 +37,7 @@ M.Loan_rtv.construct(data=rtv) M.LoanRate_rtv.construct(data=rtv) M.LifetimeProcess_rtv.construct(data=rtv) -M.RegionalIndices.construct(data=['A']) +M.regionalIndices.construct(data=['A']) M.MyopicBaseyear.construct(data={None: 0}) M.ModelProcessLife_rptv.construct(data=rptv) diff --git a/tests/test_storage.py b/tests/test_storage.py index 3ef6d2f46..010b18133 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -95,8 +95,8 @@ def test_state_sequencing(system_test_run): next_state = model.V_StorageLevel[r, p, s_next, d_next, t, v].value assert state + charge - discharge == pytest.approx( - next_state, rel=1e-3 - ), f'model fails to correctly sequence storage states {r, p, s, t, v}' + next_state, rel=1e-2 + ), f'model fails to correctly sequence storage states {r, p, s, t, v} sequenced {s, d} to {s_next, d_next}' @pytest.mark.parametrize( diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index fd4b0b35a..81b17ad41 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -361,7 +361,7 @@ CREATE TABLE GrowthRateMax notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO GrowthRateMax VALUES('A','GeoHeater',0.2000000000000000111,NULL); +INSERT INTO GrowthRateMax VALUES('global','GeoHeater',0.2000000000000000111,NULL); CREATE TABLE GrowthRateSeed ( region TEXT, @@ -372,7 +372,7 @@ CREATE TABLE GrowthRateSeed notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO GrowthRateSeed VALUES('A','GeoHeater',1000.0,'jobs','unk'); +INSERT INTO GrowthRateSeed VALUES('global','GeoHeater',1000.0,'jobs','unk'); CREATE TABLE LoanLifetimeTech ( region TEXT, @@ -868,7 +868,7 @@ CREATE TABLE MaxNewCapacityGroupShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group) ); -INSERT INTO MaxNewCapacityGroupShare VALUES('A', 2025, 'RPS_common', 'A_tech_grp_1', 1, ''); +INSERT INTO MaxNewCapacityGroupShare VALUES('global', 2025, 'RPS_common', 'A_tech_grp_1', 1, ''); CREATE TABLE MinActivityShare ( region TEXT, diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 1e5a10cf2..50747f977 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -31,13 +31,14 @@ "A", "B" ], - "RegionalIndices": [ + "regionalIndices": [ "A", "A-B", "B", "B-A" ], - "RegionalGlobalIndices": [ + "regionalGlobalIndices": [ + "global", "A", "B" ], @@ -157,7 +158,6 @@ "co2", "FusionGas" ], - "ResourceConstraint_rpr": [], "CapacityFactor_rsdt": [ [ "A", @@ -1686,6 +1686,24 @@ 2025, "EF", "RPS_common" + ], + [ + "global", + 2025, + "EH", + "A_tech_grp_1" + ], + [ + "global", + 2025, + "EF", + "A_tech_grp_1" + ], + [ + "global", + 2025, + "EF", + "RPS_common" ] ], "MinCapacityShareConstraint_rptg": [], @@ -1762,17 +1780,53 @@ 2025, "RPS_global", "RPS_common" + ], + [ + "global", + 2025, + "RPS_global", + "A_tech_grp_1" + ], + [ + "global", + 2025, + "A_tech_grp_1", + "A_tech_grp_1" + ], + [ + "global", + 2025, + "RPS_common", + "A_tech_grp_1" + ], + [ + "global", + 2025, + "RPS_global", + "RPS_common" + ], + [ + "global", + 2025, + "A_tech_grp_1", + "RPS_common" + ], + [ + "global", + 2025, + "RPS_common", + "RPS_common" ] ], "MaxNewCapacityGroupShareConstraint_rpgg": [ [ - "A", + "global", 2025, "RPS_common", "A_tech_grp_1" ] ], - "MinNewCapacityGroupShareConstraint_rpgg": [ + "MinNewCapacityGroupShareConstraint_rpgg": [ [ "A", 2025, @@ -4216,7 +4270,7 @@ ], "GrowthRateMaxConstraint_rtv": [ [ - "A", + "global", 2025, "GeoHeater" ] diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 6e7e1e32f..6f6c171e1 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -41,13 +41,13 @@ "R1", "R2" ], - "RegionalIndices": [ + "regionalIndices": [ "R1", "R1-R2", "R2", "R2-R1" ], - "RegionalGlobalIndices": [ + "regionalGlobalIndices": [ "R1", "R2", "global" @@ -182,7 +182,6 @@ "RH", "CO2" ], - "ResourceConstraint_rpr": [], "CapacityFactor_rsdt": [ [ "R1", diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 0b77eba60..ad622e191 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -45,10 +45,12 @@ "regions": [ "utopia" ], - "RegionalIndices": [ + "regionalIndices": [ + "utopia" + ], + "regionalGlobalIndices": [ "utopia" ], - "RegionalGlobalIndices": [], "tech_resource": [ "IMPDSL1", "IMPGSL1", @@ -188,7 +190,6 @@ "co2", "nox" ], - "ResourceConstraint_rpr": [], "CapacityFactor_rsdt": [ [ "utopia", From 215d654e0650567d558644398a50f8ca5de99a94 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 13 Feb 2025 16:48:17 -0500 Subject: [PATCH 034/587] Add room for new forms of state sequencing --- temoa/temoa_model/hybrid_loader.py | 11 ++++++----- temoa/temoa_model/temoa_initialize.py | 9 +++++---- temoa/temoa_model/temoa_model.py | 2 +- tests/testing_data/utopia.sql | 2 +- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 90fe14993..a6c0554f0 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -401,11 +401,12 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): raw = cur.execute('SELECT season FROM main.TimeSeason ORDER BY sequence').fetchall() load_element(M.time_season, raw) - # LinkSeasons - raw = cur.execute("SELECT value from MetaData WHERE element == 'link_seasons'").fetchall() - if not raw: - raise ValueError('link_seasons boolean parameter missing from MetaData table. Seasons will loop by default.') - data[M.LinkSeasons.name] = {None: bool(raw[0][0])} + # StateSequencing + raw = cur.execute("SELECT value from MetaData WHERE element == 'state_sequencing'").fetchall() + if raw: + data[M.StateSequencing.name] = {None: bool(raw[0][0])} + else: + logger.warning("state_sequencing parameter missing from MetaData table. By default, states will loop each period.") # myopic_base_year if mi: diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 299e285d3..621007047 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -884,10 +884,11 @@ def CreateSparseDicts(M: 'TemoaModel'): for i in sorted(l_unused_techs): SE.write(msg.format(i)) - # Establishing chronology of states + # Establishing sequence of states for s, d in M.time_season * M.time_of_day: - if M.LinkSeasons: s_next, d_next = link_season_next_timeslice(M, s, d) - else: s_next, d_next = loop_season_next_timeslice(M, s, d) + match M.StateSequencing: + case 0: s_next, d_next = loop_period_next_timeslice(M, s, d) + case 1: s_next, d_next = loop_season_next_timeslice(M, s, d) M.time_next[s, d] = (s_next, d_next) # valid region-period-commodity sets for commodity balance constraints @@ -1595,7 +1596,7 @@ def GrowthRateMaxIndices(M: 'TemoaModel'): return indices -def link_season_next_timeslice(M: 'TemoaModel', s, d) -> tuple[str, str]: +def loop_period_next_timeslice(M: 'TemoaModel', s, d) -> tuple[str, str]: # Final time slice of final season (end of period) # Loop state back to initial state of first season diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 58c21fbe2..2d2e2c123 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -226,7 +226,7 @@ def __init__(M, *args, **kwargs): M.PeriodLength = Param(M.time_optimize, initialize=ParamPeriodLength) M.SegFrac = Param(M.time_season, M.time_of_day) M.validate_SegFrac = BuildAction(rule=validate_SegFrac) - M.LinkSeasons = Param(default=0) # do states carry from one season to the next? otherwise loop each season + M.StateSequencing = Param(default=0) # How do states carry between time segments? # Define demand- and resource-related parameters # Dev Note: There does not appear to be a DB table supporting DemandDefaultDistro. This does not diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index c7249401e..137b4fd4f 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -10,7 +10,7 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('myopic_base_year',1990,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); -INSERT INTO MetaData VALUES('link_seasons',1,'Carry storage states between seasons'); +INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); CREATE TABLE MetaDataReal ( element TEXT, From da0e62506a95e93a008e4955e58afe70f182f4de Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 13 Feb 2025 19:03:04 -0500 Subject: [PATCH 035/587] Add some super basic versions of the schema for learning purposes and modify code to support them --- data_files/temoa_basics_0.sql | 345 ++++++++++++ data_files/temoa_basics_1.sql | 495 +++++++++++++++++ data_files/temoa_basics_2.sql | 718 +++++++++++++++++++++++++ data_files/temoa_schema_minimal_v3.sql | 2 +- temoa/data_processing/DB_to_Excel.py | 9 +- temoa/temoa_model/hybrid_loader.py | 154 +++--- temoa/temoa_model/temoa_initialize.py | 23 +- temoa/temoa_model/temoa_model.py | 2 +- 8 files changed, 1662 insertions(+), 86 deletions(-) create mode 100644 data_files/temoa_basics_0.sql create mode 100644 data_files/temoa_basics_1.sql create mode 100644 data_files/temoa_basics_2.sql diff --git a/data_files/temoa_basics_0.sql b/data_files/temoa_basics_0.sql new file mode 100644 index 000000000..eff70ce4f --- /dev/null +++ b/data_files/temoa_basics_0.sql @@ -0,0 +1,345 @@ +PRAGMA foreign_keys= OFF; +BEGIN TRANSACTION; + +CREATE TABLE IF NOT EXISTS MetaData +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +REPLACE INTO MetaData +VALUES ('DB_MAJOR', 3, 'DB major version number'); +REPLACE INTO MetaData +VALUES ('DB_MINOR', 0, 'DB minor version number'); +CREATE TABLE IF NOT EXISTS OutputObjective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE IF NOT EXISTS Commodity +( + name TEXT + PRIMARY KEY, + flag TEXT + REFERENCES CommodityType (label), + description TEXT +); +REPLACE INTO Commodity +VALUES ('ethos', 's', NULL); +REPLACE INTO Commodity +VALUES ('fuel', 'p', NULL); +REPLACE INTO Commodity +VALUES ('carrier', 'p', NULL); +REPLACE INTO Commodity +VALUES ('demand', 'd', NULL); +CREATE TABLE IF NOT EXISTS CommodityType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO CommodityType +VALUES ('p', 'physical commodity'); +REPLACE INTO CommodityType +VALUES ('d', 'demand commodity'); +REPLACE INTO CommodityType +VALUES ('s', 'source commodity'); +CREATE TABLE IF NOT EXISTS CostFixed +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS CostInvest +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS CostVariable +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS Demand +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + commodity TEXT + REFERENCES Commodity (name), + demand REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, commodity) +); +REPLACE INTO Demand +VALUES ('region', 2000, 'demand', 1, NULL, NULL); +CREATE TABLE IF NOT EXISTS Efficiency +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +REPLACE INTO Efficiency +VALUES ('region', 'ethos', 'importer', 2000, 'fuel', 1, NULL); +REPLACE INTO Efficiency +VALUES ('region', 'fuel', 'producer', 2000, 'carrier', 1, NULL); +REPLACE INTO Efficiency +VALUES ('region', 'carrier', 'consumer', 2000, 'demand', 1, NULL); +CREATE TABLE IF NOT EXISTS OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputFlowOut +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputDualVariable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE IF NOT EXISTS Region +( + region TEXT + PRIMARY KEY, + notes TEXT +); +REPLACE INTO Region +VALUES ('region', NULL); +CREATE TABLE IF NOT EXISTS TechnologyType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO TechnologyType +VALUES ('r', 'resource technology'); +REPLACE INTO TechnologyType +VALUES ('p', 'production technology'); +REPLACE INTO TechnologyType +VALUES ('pb', 'baseload production technology'); +REPLACE INTO TechnologyType +VALUES ('ps', 'storage production technology'); +CREATE TABLE IF NOT EXISTS TimePeriod +( + sequence INTEGER UNIQUE, + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES TimePeriodType (label) +); +REPLACE INTO TimePeriod +VALUES (0, 2000, 'f'); +REPLACE INTO TimePeriod +VALUES (1, 2001, 'f'); +CREATE TABLE IF NOT EXISTS TimePeriodType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO TimePeriodType VALUES ('f', 'future'); +CREATE TABLE IF NOT EXISTS OutputEmission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS Technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + variable INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES TechnologyType (label) +); +REPLACE INTO Technology +VALUES ('importer', 'r', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); +REPLACE INTO Technology +VALUES ('producer', 'p', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); +REPLACE INTO Technology +VALUES ('consumer', 'p', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); +CREATE TABLE IF NOT EXISTS OutputCost +( + scenario TEXT, + region TEXT, + period INTEGER, + tech TEXT, + vintage INTEGER, + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES TimePeriod (period), + FOREIGN KEY (tech) REFERENCES Technology (tech) +); +COMMIT; +PRAGMA FOREIGN_KEYS = 1; diff --git a/data_files/temoa_basics_1.sql b/data_files/temoa_basics_1.sql new file mode 100644 index 000000000..fd92c9305 --- /dev/null +++ b/data_files/temoa_basics_1.sql @@ -0,0 +1,495 @@ +PRAGMA foreign_keys= OFF; +BEGIN TRANSACTION; + +CREATE TABLE IF NOT EXISTS MetaData +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +REPLACE INTO MetaData +VALUES ('DB_MAJOR', 3, 'DB major version number'); +REPLACE INTO MetaData +VALUES ('DB_MINOR', 0, 'DB minor version number'); +CREATE TABLE IF NOT EXISTS OutputObjective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE IF NOT EXISTS CapacityToActivity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + c2a REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE CapacityFactorTech +( + region TEXT, + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + factor REAL, + notes TEXT, + PRIMARY KEY (region, season, tod, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS Commodity +( + name TEXT + PRIMARY KEY, + flag TEXT + REFERENCES CommodityType (label), + description TEXT +); +REPLACE INTO Commodity +VALUES ('ethos', 's', NULL); +REPLACE INTO Commodity +VALUES ('fuel', 'p', NULL); +REPLACE INTO Commodity +VALUES ('carrier', 'p', NULL); +REPLACE INTO Commodity +VALUES ('demand', 'd', NULL); +CREATE TABLE IF NOT EXISTS CommodityType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO CommodityType +VALUES ('p', 'physical commodity'); +REPLACE INTO CommodityType +VALUES ('d', 'demand commodity'); +REPLACE INTO CommodityType +VALUES ('s', 'source commodity'); +CREATE TABLE IF NOT EXISTS CostEmission +( + region TEXT + REFERENCES Region (region), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT NOT NULL + REFERENCES Commodity (name), + cost REAL NOT NULL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE IF NOT EXISTS CostFixed +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS CostInvest +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS CostVariable +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS Demand +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + commodity TEXT + REFERENCES Commodity (name), + demand REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, commodity) +); +REPLACE INTO Demand +VALUES ('region', 2000, 'demand', 1, NULL, NULL); +CREATE TABLE IF NOT EXISTS DemandSpecificDistribution +( + region TEXT, + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + demand_name TEXT + REFERENCES Commodity (name), + dsd REAL, + dsd_notes TEXT, + PRIMARY KEY (region, season, tod, demand_name), + CHECK (dsd >= 0 AND dsd <= 1) +); +REPLACE INTO DemandSpecificDistribution +VALUES ('region','S1', 'D1', 'demand', 0.25, NULL); +REPLACE INTO DemandSpecificDistribution +VALUES ('region','S1', 'D2', 'demand', 0.25, NULL); +REPLACE INTO DemandSpecificDistribution +VALUES ('region','S2', 'D1', 'demand', 0.25, NULL); +REPLACE INTO DemandSpecificDistribution +VALUES ('region','S2', 'D2', 'demand', 0.25, NULL); +CREATE TABLE IF NOT EXISTS Efficiency +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +REPLACE INTO Efficiency +VALUES ('region', 'ethos', 'importer', 2000, 'fuel', 1, NULL); +REPLACE INTO Efficiency +VALUES ('region', 'fuel', 'producer', 2000, 'carrier', 1, NULL); +REPLACE INTO Efficiency +VALUES ('region', 'carrier', 'consumer', 2000, 'demand', 1, NULL); +CREATE TABLE IF NOT EXISTS EmissionActivity +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS ExistingCapacity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS LifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputFlowOut +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputDualVariable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE IF NOT EXISTS Region +( + region TEXT + PRIMARY KEY, + notes TEXT +); +REPLACE INTO Region +VALUES ('region', NULL); +CREATE TABLE SectorLabel +( + sector TEXT, + PRIMARY KEY (sector) +); +CREATE TABLE IF NOT EXISTS StorageDuration +( + region TEXT, + tech TEXT, + duration REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS TimeSegmentFraction +( + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + segfrac REAL, + notes TEXT, + PRIMARY KEY (season, tod), + CHECK (segfrac >= 0 AND segfrac <= 1) +); +REPLACE INTO TimeSegmentFraction +VALUES ('S1', 'D1', 0.25, NULL); +REPLACE INTO TimeSegmentFraction +VALUES ('S1', 'D2', 0.25, NULL); +REPLACE INTO TimeSegmentFraction +VALUES ('S2', 'D1', 0.25, NULL); +REPLACE INTO TimeSegmentFraction +VALUES ('S2', 'D2', 0.25, NULL); +CREATE TABLE IF NOT EXISTS TechnologyType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO TechnologyType +VALUES ('r', 'resource technology'); +REPLACE INTO TechnologyType +VALUES ('p', 'production technology'); +REPLACE INTO TechnologyType +VALUES ('pb', 'baseload production technology'); +REPLACE INTO TechnologyType +VALUES ('ps', 'storage production technology'); +CREATE TABLE IF NOT EXISTS TimePeriod +( + sequence INTEGER UNIQUE, + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES TimePeriodType (label) +); +REPLACE INTO TimePeriod +VALUES (0, 2000, 'f'); +REPLACE INTO TimePeriod +VALUES (1, 2001, 'f'); +CREATE TABLE IF NOT EXISTS TimeOfDay +( + sequence INTEGER UNIQUE, + tod TEXT + PRIMARY KEY +); +REPLACE INTO TimeOfDay +VALUES (0, 'D1'); +REPLACE INTO TimeOfDay +VALUES (1, 'D2'); +CREATE TABLE IF NOT EXISTS TimeSeason +( + sequence INTEGER UNIQUE, + season TEXT + PRIMARY KEY +); +REPLACE INTO TimeSeason +VALUES (0, 'S1'); +REPLACE INTO TimeSeason +VALUES (1, 'S2'); +CREATE TABLE IF NOT EXISTS TimePeriodType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO TimePeriodType VALUES ('e', 'existing'); +REPLACE INTO TimePeriodType VALUES ('f', 'future'); +CREATE TABLE IF NOT EXISTS OutputEmission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS Technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + variable INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES TechnologyType (label) +); +REPLACE INTO Technology +VALUES ('importer', 'r', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); +REPLACE INTO Technology +VALUES ('producer', 'p', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); +REPLACE INTO Technology +VALUES ('consumer', 'p', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); +CREATE TABLE IF NOT EXISTS OutputCost +( + scenario TEXT, + region TEXT, + period INTEGER, + tech TEXT, + vintage INTEGER, + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES TimePeriod (period), + FOREIGN KEY (tech) REFERENCES Technology (tech) +); +COMMIT; +PRAGMA FOREIGN_KEYS = 1; diff --git a/data_files/temoa_basics_2.sql b/data_files/temoa_basics_2.sql new file mode 100644 index 000000000..e73abb2da --- /dev/null +++ b/data_files/temoa_basics_2.sql @@ -0,0 +1,718 @@ +PRAGMA foreign_keys= OFF; +BEGIN TRANSACTION; + +CREATE TABLE IF NOT EXISTS MetaData +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +REPLACE INTO MetaData +VALUES ('DB_MAJOR', 3, 'DB major version number'); +REPLACE INTO MetaData +VALUES ('DB_MINOR', 0, 'DB minor version number'); +CREATE TABLE IF NOT EXISTS OutputObjective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE IF NOT EXISTS CapacityToActivity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + c2a REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE CapacityFactorTech +( + region TEXT, + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + factor REAL, + notes TEXT, + PRIMARY KEY (region, season, tod, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS Commodity +( + name TEXT + PRIMARY KEY, + flag TEXT + REFERENCES CommodityType (label), + description TEXT +); +REPLACE INTO Commodity +VALUES ('ethos', 's', NULL); +REPLACE INTO Commodity +VALUES ('fuel', 'p', NULL); +REPLACE INTO Commodity +VALUES ('carrier', 'p', NULL); +REPLACE INTO Commodity +VALUES ('demand', 'd', NULL); +CREATE TABLE IF NOT EXISTS CommodityType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO CommodityType +VALUES ('p', 'physical commodity'); +REPLACE INTO CommodityType +VALUES ('d', 'demand commodity'); +REPLACE INTO CommodityType +VALUES ('s', 'source commodity'); +CREATE TABLE IF NOT EXISTS CostEmission +( + region TEXT + REFERENCES Region (region), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT NOT NULL + REFERENCES Commodity (name), + cost REAL NOT NULL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE IF NOT EXISTS CostFixed +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS CostInvest +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS CostVariable +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS Demand +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + commodity TEXT + REFERENCES Commodity (name), + demand REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, commodity) +); +REPLACE INTO Demand +VALUES ('region', 2000, 'demand', 1, NULL, NULL); +CREATE TABLE IF NOT EXISTS DemandSpecificDistribution +( + region TEXT, + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + demand_name TEXT + REFERENCES Commodity (name), + dsd REAL, + dsd_notes TEXT, + PRIMARY KEY (region, season, tod, demand_name), + CHECK (dsd >= 0 AND dsd <= 1) +); +REPLACE INTO DemandSpecificDistribution +VALUES ('region','S1', 'D1', 'demand', 0.25, NULL); +REPLACE INTO DemandSpecificDistribution +VALUES ('region','S1', 'D2', 'demand', 0.25, NULL); +REPLACE INTO DemandSpecificDistribution +VALUES ('region','S2', 'D1', 'demand', 0.25, NULL); +REPLACE INTO DemandSpecificDistribution +VALUES ('region','S2', 'D2', 'demand', 0.25, NULL); +CREATE TABLE IF NOT EXISTS Efficiency +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +REPLACE INTO Efficiency +VALUES ('region', 'ethos', 'importer', 2000, 'fuel', 1, NULL); +REPLACE INTO Efficiency +VALUES ('region', 'fuel', 'producer', 2000, 'carrier', 1, NULL); +REPLACE INTO Efficiency +VALUES ('region', 'carrier', 'consumer', 2000, 'demand', 1, NULL); +CREATE TABLE IF NOT EXISTS EmissionActivity +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS EmissionLimit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE IF NOT EXISTS ExistingCapacity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE GrowthRateMax +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE GrowthRateSeed +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + seed REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS LifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE LoanLifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE MaxResource +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + max_res REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS MinActivity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + min_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE IF NOT EXISTS MaxActivity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + max_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE IF NOT EXISTS MinCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + min_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE IF NOT EXISTS MaxCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + max_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE MinCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + min_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE MaxCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + max_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE IF NOT EXISTS MinNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + min_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE IF NOT EXISTS MaxNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + max_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE MinTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MinTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MaxTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputFlowOut +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputDualVariable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE IF NOT EXISTS Region +( + region TEXT + PRIMARY KEY, + notes TEXT +); +REPLACE INTO Region +VALUES ('region', NULL); +CREATE TABLE SectorLabel +( + sector TEXT, + PRIMARY KEY (sector) +); +CREATE TABLE IF NOT EXISTS StorageDuration +( + region TEXT, + tech TEXT, + duration REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS TimeSegmentFraction +( + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + segfrac REAL, + notes TEXT, + PRIMARY KEY (season, tod), + CHECK (segfrac >= 0 AND segfrac <= 1) +); +REPLACE INTO TimeSegmentFraction +VALUES ('S1', 'D1', 0.25, NULL); +REPLACE INTO TimeSegmentFraction +VALUES ('S1', 'D2', 0.25, NULL); +REPLACE INTO TimeSegmentFraction +VALUES ('S2', 'D1', 0.25, NULL); +REPLACE INTO TimeSegmentFraction +VALUES ('S2', 'D2', 0.25, NULL); +CREATE TABLE TechGroup +( + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE TechGroupMember +( + group_name TEXT + REFERENCES TechGroup (group_name), + tech TEXT + REFERENCES Technology (tech), + PRIMARY KEY (group_name, tech) +); +CREATE TABLE IF NOT EXISTS TechnologyType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO TechnologyType +VALUES ('r', 'resource technology'); +REPLACE INTO TechnologyType +VALUES ('p', 'production technology'); +REPLACE INTO TechnologyType +VALUES ('pb', 'baseload production technology'); +REPLACE INTO TechnologyType +VALUES ('ps', 'storage production technology'); +CREATE TABLE IF NOT EXISTS TimePeriod +( + sequence INTEGER UNIQUE, + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES TimePeriodType (label) +); +REPLACE INTO TimePeriod +VALUES (0, 2000, 'f'); +REPLACE INTO TimePeriod +VALUES (1, 2001, 'f'); +CREATE TABLE IF NOT EXISTS TimeOfDay +( + sequence INTEGER UNIQUE, + tod TEXT + PRIMARY KEY +); +REPLACE INTO TimeOfDay +VALUES (0, 'D1'); +REPLACE INTO TimeOfDay +VALUES (1, 'D2'); +CREATE TABLE IF NOT EXISTS TimeSeason +( + sequence INTEGER UNIQUE, + season TEXT + PRIMARY KEY +); +REPLACE INTO TimeSeason +VALUES (0, 'S1'); +REPLACE INTO TimeSeason +VALUES (1, 'S2'); +CREATE TABLE IF NOT EXISTS TimePeriodType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO TimePeriodType VALUES ('e', 'existing'); +REPLACE INTO TimePeriodType VALUES ('f', 'future'); +CREATE TABLE IF NOT EXISTS OutputEmission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS Technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + variable INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES TechnologyType (label) +); +REPLACE INTO Technology +VALUES ('importer', 'r', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); +REPLACE INTO Technology +VALUES ('producer', 'p', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); +REPLACE INTO Technology +VALUES ('consumer', 'p', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); +CREATE TABLE IF NOT EXISTS OutputCost +( + scenario TEXT, + region TEXT, + period INTEGER, + tech TEXT, + vintage INTEGER, + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES TimePeriod (period), + FOREIGN KEY (tech) REFERENCES Technology (tech) +); +COMMIT; +PRAGMA FOREIGN_KEYS = 1; diff --git a/data_files/temoa_schema_minimal_v3.sql b/data_files/temoa_schema_minimal_v3.sql index 92438444c..27333fe26 100644 --- a/data_files/temoa_schema_minimal_v3.sql +++ b/data_files/temoa_schema_minimal_v3.sql @@ -186,7 +186,7 @@ CREATE TABLE IF NOT EXISTS DemandSpecificDistribution dds REAL, dds_notes TEXT, PRIMARY KEY (region, season, tod, demand_name), - CHECK (dds >= 0 AND dds <= 1) + CHECK (dsd >= 0 AND dsd <= 1) ); CREATE TABLE IF NOT EXISTS LoanRate ( diff --git a/temoa/data_processing/DB_to_Excel.py b/temoa/data_processing/DB_to_Excel.py index dc265fcef..8460d0545 100644 --- a/temoa/data_processing/DB_to_Excel.py +++ b/temoa/data_processing/DB_to_Excel.py @@ -101,13 +101,16 @@ def make_excel(ifile, ofile: Path, scenario): 'SELECT DISTINCT EmissionActivity.region, EmissionActivity.tech, EmissionActivity.emis_comm, Technology.sector FROM EmissionActivity \ INNER JOIN Technology ON EmissionActivity.tech=Technology.tech' ) - all_emis_techs = pd.read_sql_query(query, con) - + try: + all_emis_techs = pd.read_sql_query(query, con) + except: + all_emis_techs = {} + query = ( "SELECT region, tech, sector, period, emis_comm, sum(emission) as emissions FROM OutputEmission WHERE scenario='" + scenario + "' GROUP BY \ - region, tech, sector, period, emis_comm" + region, tech, sector, period, emis_comm" ) df_emissions_raw = pd.read_sql_query(query, con) if not df_emissions_raw.empty: diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index a6c0554f0..904c0357f 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -394,12 +394,18 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): load_element(M.time_future, raw) # time_of_day - raw = cur.execute('SELECT tod FROM main.TimeOfDay ORDER BY sequence').fetchall() - load_element(M.time_of_day, raw) + if self.table_exists("TimeOfDay"): + raw = cur.execute('SELECT tod FROM main.TimeOfDay ORDER BY sequence').fetchall() + load_element(M.time_of_day, raw) + else: + load_element(M.time_of_day, [('D',)]) # time_season - raw = cur.execute('SELECT season FROM main.TimeSeason ORDER BY sequence').fetchall() - load_element(M.time_season, raw) + if self.table_exists("TimeSeason"): + raw = cur.execute('SELECT season FROM main.TimeSeason ORDER BY sequence').fetchall() + load_element(M.time_season, raw) + else: + load_element(M.time_season, [('S',)]) # StateSequencing raw = cur.execute("SELECT value from MetaData WHERE element == 'state_sequencing'").fetchall() @@ -556,48 +562,54 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): load_element(M.Efficiency, raw) # ExistingCapacity - if mi: - # In order to get accurate capacity at start of this interval, we want to - # 1. Only look at the previous period in the net capacity table (things that had some capacity) - # 2. Omit any techs that are "unlimited capacity" to keep them out of capacity variables - # 3. add in everything from the original ExistingCapacity table + if self.table_exists("ExistingCapacity"): + if mi: + # In order to get accurate capacity at start of this interval, we want to + # 1. Only look at the previous period in the net capacity table (things that had some capacity) + # 2. Omit any techs that are "unlimited capacity" to keep them out of capacity variables + # 3. add in everything from the original ExistingCapacity table + + # get previous period + raw = cur.execute( + 'SELECT MAX(period) FROM main.TimePeriod WHERE period < ?', (mi.base_year,) + ).fetchone() + previous_period = raw[0] + # noinspection SqlUnused + raw = cur.execute( + 'SELECT region, tech, vintage, capacity FROM main.OutputNetCapacity ' + ' WHERE period = ? ' + ' AND scenario = ? ' + 'UNION ' + ' SELECT region, tech, vintage, capacity FROM main.ExistingCapacity ', + (previous_period, self.config.scenario), + ).fetchall() + else: + raw = cur.execute( + 'SELECT region, tech, vintage, capacity FROM main.ExistingCapacity' + ).fetchall() + load_element(M.ExistingCapacity, raw, self.viable_rtv, (0, 1, 2)) - # get previous period - raw = cur.execute( - 'SELECT MAX(period) FROM main.TimePeriod WHERE period < ?', (mi.base_year,) - ).fetchone() - previous_period = raw[0] - # noinspection SqlUnused - raw = cur.execute( - 'SELECT region, tech, vintage, capacity FROM main.OutputNetCapacity ' - ' WHERE period = ? ' - ' AND scenario = ? ' - 'UNION ' - ' SELECT region, tech, vintage, capacity FROM main.ExistingCapacity ', - (previous_period, self.config.scenario), - ).fetchall() - else: + # GlobalDiscountRate + if self.table_exists("MetaDataReal"): raw = cur.execute( - 'SELECT region, tech, vintage, capacity FROM main.ExistingCapacity' + "SELECT value FROM main.MetaDataReal WHERE element = 'global_discount_rate'" ).fetchall() - load_element(M.ExistingCapacity, raw, self.viable_rtv, (0, 1, 2)) - - # GlobalDiscountRate - raw = cur.execute( - "SELECT value FROM main.MetaDataReal WHERE element = 'global_discount_rate'" - ).fetchall() - # do this separately as it is non-indexed, so we need to make a mapping with None - data[M.GlobalDiscountRate.name] = {None: raw[0][0]} + # do this separately as it is non-indexed, so we need to make a mapping with None + data[M.GlobalDiscountRate.name] = {None: raw[0][0]} # SegFrac - raw = cur.execute('SELECT season, tod, segfrac FROM main.TimeSegmentFraction').fetchall() - load_element(M.SegFrac, raw) + if self.table_exists("TimeSegmentFraction"): + raw = cur.execute('SELECT season, tod, segfrac FROM main.TimeSegmentFraction').fetchall() + load_element(M.SegFrac, raw) + else: + load_element(M.SegFrac, [("S","D",1)]) # DemandSpecificDistribution - raw = cur.execute( - 'SELECT region, season, tod, demand_name, dsd FROM main.DemandSpecificDistribution' - ).fetchall() - load_element(M.DemandSpecificDistribution, raw) + if self.table_exists('DemandSpecificDistribution'): + raw = cur.execute( + 'SELECT region, season, tod, demand_name, dsd FROM main.DemandSpecificDistribution' + ).fetchall() + load_element(M.DemandSpecificDistribution, raw) # DemandPeriodDistribution if self.table_exists('DemandPeriodDistribution'): @@ -612,34 +624,34 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # Not currently implemented # CapacityToActivity - raw = cur.execute('SELECT region, tech, c2a FROM main.CapacityToActivity ').fetchall() - load_element(M.CapacityToActivity, raw, self.viable_rt, (0, 1)) + if self.table_exists("CapacityToActivity"): + raw = cur.execute('SELECT region, tech, c2a FROM main.CapacityToActivity ').fetchall() + load_element(M.CapacityToActivity, raw, self.viable_rt, (0, 1)) # CapacityFactorTech - raw = cur.execute( - 'SELECT region, season, tod, tech, factor ' 'FROM main.CapacityFactorTech' - ).fetchall() - load_element(M.CapacityFactorTech, raw, self.viable_rt, (0, 3)) + if self.table_exists("CapacityFactorTech"): + raw = cur.execute('SELECT region, season, tod, tech, factor ' 'FROM main.CapacityFactorTech').fetchall() + load_element(M.CapacityFactorTech, raw, self.viable_rt, (0, 3)) # CapacityFactorProcess - raw = cur.execute( - 'SELECT region, season, tod, tech, vintage, factor ' ' FROM main.CapacityFactorProcess' - ).fetchall() - load_element(M.CapacityFactorProcess, raw, self.viable_rtv, (0, 3, 4)) + if self.table_exists("CapacityFactorProcess"): + raw = cur.execute('SELECT region, season, tod, tech, vintage, factor ' ' FROM main.CapacityFactorProcess').fetchall() + load_element(M.CapacityFactorProcess, raw, self.viable_rtv, (0, 3, 4)) # LifetimeTech - raw = cur.execute('SELECT region, tech, lifetime FROM main.LifetimeTech').fetchall() - load_element(M.LifetimeTech, raw, self.viable_rt, val_loc=(0, 1)) + if self.table_exists("LifetimeTech"): + raw = cur.execute('SELECT region, tech, lifetime FROM main.LifetimeTech').fetchall() + load_element(M.LifetimeTech, raw, self.viable_rt, val_loc=(0, 1)) # LifetimeProcess - raw = cur.execute( - 'SELECT region, tech, vintage, lifetime FROM main.LifetimeProcess' - ).fetchall() - load_element(M.LifetimeProcess, raw, self.viable_rtv, val_loc=(0, 1, 2)) + if self.table_exists("LifetimeProcess"): + raw = cur.execute('SELECT region, tech, vintage, lifetime FROM main.LifetimeProcess').fetchall() + load_element(M.LifetimeProcess, raw, self.viable_rtv, val_loc=(0, 1, 2)) # LoanLifetimeTech - raw = cur.execute('SELECT region, tech, lifetime FROM main.LoanLifetimeTech').fetchall() - load_element(M.LoanLifetimeTech, raw, self.viable_rt, (0, 1)) + if self.table_exists("LoanLifetimeTech"): + raw = cur.execute('SELECT region, tech, lifetime FROM main.LoanLifetimeTech').fetchall() + load_element(M.LoanLifetimeTech, raw, self.viable_rt, (0, 1)) # MinTechInputSplit if self.table_exists('MinTechInputSplit'): @@ -848,22 +860,24 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): load_element(M.CostEmission, raw) # DefaultLoanRate - raw = cur.execute( - "SELECT value FROM main.MetaDataReal WHERE element = 'default_loan_rate'" - ).fetchall() - # do this separately as it is non-indexed, so we need to make a mapping with None - data[M.DefaultLoanRate.name] = {None: raw[0][0]} - - # LoanRate - if mi: + if self.table_exists("MetaDataReal"): raw = cur.execute( - 'SELECT region, tech, vintage, rate FROM main.LoanRate ' 'WHERE vintage >= ?', - (mi.base_year,), + "SELECT value FROM main.MetaDataReal WHERE element = 'default_loan_rate'" ).fetchall() - else: - raw = cur.execute('SELECT region, tech, vintage, rate FROM main.LoanRate ').fetchall() + # do this separately as it is non-indexed, so we need to make a mapping with None + data[M.DefaultLoanRate.name] = {None: raw[0][0]} + + # LoanRate + if self.table_exists("LoanRate"): + if mi: + raw = cur.execute( + 'SELECT region, tech, vintage, rate FROM main.LoanRate ' 'WHERE vintage >= ?', + (mi.base_year,), + ).fetchall() + else: + raw = cur.execute('SELECT region, tech, vintage, rate FROM main.LoanRate ').fetchall() - load_element(M.LoanRate, raw, self.viable_rtv, (0, 1, 2)) + load_element(M.LoanRate, raw, self.viable_rtv, (0, 1, 2)) # MinCapacity if self.table_exists('MinCapacity'): diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 621007047..bbec93f0a 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -161,18 +161,19 @@ def validate_time(M: 'TemoaModel'): raise RuntimeError(msg) # Ensure that the time_exist < time_future - max_exist = max(M.time_exist) - min_horizon = min(M.time_future) + if len(M.time_exist) > 0: + max_exist = max(M.time_exist) + min_horizon = min(M.time_future) - if not (max_exist < min_horizon): - msg = ( - 'All items in time_future must be larger than in time_exist.' - '\ntime_exist max: {}' - '\ntime_future min: {}' - ) - logger.error(msg.format(max_exist, min_horizon)) - raise Exception(msg.format(max_exist, min_horizon)) - logger.debug('Finished validating time') + if not (max_exist < min_horizon): + msg = ( + 'All items in time_future must be larger than in time_exist.' + '\ntime_exist max: {}' + '\ntime_future min: {}' + ) + logger.error(msg.format(max_exist, min_horizon)) + raise Exception(msg.format(max_exist, min_horizon)) + logger.debug('Finished validating time') def validate_SegFrac(M: 'TemoaModel'): diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 2d2e2c123..d686a42a9 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -220,7 +220,7 @@ def __init__(M, *args, **kwargs): # these "progress markers" report build progress in the log, if the level == debug M.progress_marker_2 = BuildAction(['Starting to build Params'], rule=progress_check) - M.GlobalDiscountRate = Param() + M.GlobalDiscountRate = Param(default=0.05) # Define time-related parameters M.PeriodLength = Param(M.time_optimize, initialize=ParamPeriodLength) From 63ae180a334ac41fb90a8aaef9a4d03d72aae7cc Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 14 Feb 2025 09:59:40 -0500 Subject: [PATCH 036/587] Add if not exists checks on basics sql schemas --- data_files/temoa_basics_1.sql | 4 ++-- data_files/temoa_basics_2.sql | 30 +++++++++++++++--------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/data_files/temoa_basics_1.sql b/data_files/temoa_basics_1.sql index fd92c9305..53fb8c04f 100644 --- a/data_files/temoa_basics_1.sql +++ b/data_files/temoa_basics_1.sql @@ -27,7 +27,7 @@ CREATE TABLE IF NOT EXISTS CapacityToActivity notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE CapacityFactorTech +CREATE TABLE IF NOT EXISTS CapacityFactorTech ( region TEXT, season TEXT @@ -345,7 +345,7 @@ CREATE TABLE IF NOT EXISTS Region ); REPLACE INTO Region VALUES ('region', NULL); -CREATE TABLE SectorLabel +CREATE TABLE IF NOT EXISTS SectorLabel ( sector TEXT, PRIMARY KEY (sector) diff --git a/data_files/temoa_basics_2.sql b/data_files/temoa_basics_2.sql index e73abb2da..cdacd9aa1 100644 --- a/data_files/temoa_basics_2.sql +++ b/data_files/temoa_basics_2.sql @@ -27,7 +27,7 @@ CREATE TABLE IF NOT EXISTS CapacityToActivity notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE CapacityFactorTech +CREATE TABLE IF NOT EXISTS CapacityFactorTech ( region TEXT, season TEXT @@ -222,7 +222,7 @@ CREATE TABLE IF NOT EXISTS ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE GrowthRateMax +CREATE TABLE IF NOT EXISTS GrowthRateMax ( region TEXT, tech TEXT @@ -231,7 +231,7 @@ CREATE TABLE GrowthRateMax notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE GrowthRateSeed +CREATE TABLE IF NOT EXISTS GrowthRateSeed ( region TEXT, tech TEXT @@ -250,7 +250,7 @@ CREATE TABLE IF NOT EXISTS LifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE LoanLifetimeTech +CREATE TABLE IF NOT EXISTS LoanLifetimeTech ( region TEXT, tech TEXT @@ -259,7 +259,7 @@ CREATE TABLE LoanLifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE LoanRate +CREATE TABLE IF NOT EXISTS LoanRate ( region TEXT, tech TEXT @@ -270,7 +270,7 @@ CREATE TABLE LoanRate notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE MaxResource +CREATE TABLE IF NOT EXISTS MaxResource ( region TEXT, tech TEXT @@ -328,7 +328,7 @@ CREATE TABLE IF NOT EXISTS MaxCapacity notes TEXT, PRIMARY KEY (region, period, tech) ); -CREATE TABLE MinCapacityGroup +CREATE TABLE IF NOT EXISTS MinCapacityGroup ( region TEXT, period INTEGER @@ -340,7 +340,7 @@ CREATE TABLE MinCapacityGroup notes TEXT, PRIMARY KEY (region, period, group_name) ); -CREATE TABLE MaxCapacityGroup +CREATE TABLE IF NOT EXISTS MaxCapacityGroup ( region TEXT, period INTEGER @@ -376,7 +376,7 @@ CREATE TABLE IF NOT EXISTS MaxNewCapacity notes TEXT, PRIMARY KEY (region, period, tech) ); -CREATE TABLE MinTechInputSplit +CREATE TABLE IF NOT EXISTS MinTechInputSplit ( region TEXT, period INTEGER @@ -389,7 +389,7 @@ CREATE TABLE MinTechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE MaxTechInputSplit +CREATE TABLE IF NOT EXISTS MaxTechInputSplit ( region TEXT, period INTEGER @@ -402,7 +402,7 @@ CREATE TABLE MaxTechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE MinTechOutputSplit +CREATE TABLE IF NOT EXISTS MinTechOutputSplit ( region TEXT, period INTEGER @@ -415,7 +415,7 @@ CREATE TABLE MinTechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm) ); -CREATE TABLE MaxTechOutputSplit +CREATE TABLE IF NOT EXISTS MaxTechOutputSplit ( region TEXT, period INTEGER @@ -554,7 +554,7 @@ CREATE TABLE IF NOT EXISTS Region ); REPLACE INTO Region VALUES ('region', NULL); -CREATE TABLE SectorLabel +CREATE TABLE IF NOT EXISTS SectorLabel ( sector TEXT, PRIMARY KEY (sector) @@ -586,13 +586,13 @@ REPLACE INTO TimeSegmentFraction VALUES ('S2', 'D1', 0.25, NULL); REPLACE INTO TimeSegmentFraction VALUES ('S2', 'D2', 0.25, NULL); -CREATE TABLE TechGroup +CREATE TABLE IF NOT EXISTS TechGroup ( group_name TEXT PRIMARY KEY, notes TEXT ); -CREATE TABLE TechGroupMember +CREATE TABLE IF NOT EXISTS TechGroupMember ( group_name TEXT REFERENCES TechGroup (group_name), From f8eaa8a23594cf9cae38ca9f6a7de4717e750b32 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 14 Feb 2025 13:16:19 -0500 Subject: [PATCH 037/587] Add EfficiencyVariable --- temoa/temoa_model/hybrid_loader.py | 6 ++- temoa/temoa_model/temoa_initialize.py | 51 ++++++++++++++++++++++ temoa/temoa_model/temoa_model.py | 15 ++++++- temoa/temoa_model/temoa_rules.py | 62 +++++++++++++++------------ 4 files changed, 105 insertions(+), 29 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 904c0357f..7cb3a2804 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -556,11 +556,15 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # === PARAMS === # Efficiency - # we have already computed/filtered this... no need for another data pull raw = self.efficiency_values load_element(M.Efficiency, raw) + # EfficiencyVariable + if self.table_exists("EfficiencyVariable"): + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, season, tod, input_comm, tech, vintage, output_comm, efficiency FROM main.EfficiencyVariable') + load_element(M.EfficiencyVariable, raw, self.viable_ritvo, (0, 4, 5, 6, 7)) + # ExistingCapacity if self.table_exists("ExistingCapacity"): if mi: diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index bbec93f0a..37b742171 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -520,6 +520,57 @@ def CreateDemands(M: 'TemoaModel'): logger.debug('Finished creating demand distributions') +def CreateVariableEfficiencies(M: 'TemoaModel'): + + indices = set( + (r, p, s, d, i, t, v, o) + + for r, i, t, v, o in M.Efficiency.sparse_iterkeys() + for p in M.time_optimize + for s in M.time_season + for d in M.time_of_day + ) + + for rpsditvo in indices: + M.variableEfficiencies[rpsditvo] = False # pull non-variable efficiency by default + + count_ritvo = dict() + for r, p, s, d, i, t, v, o in M.EfficiencyVariable.sparse_iterkeys(): + try: + M.Efficiency[r, i, t, v, o] + except ValueError: + msg = f"Set in EfficiencyVariable table missing from Efficiency table (EfficiencyVariable is a multiplier on Efficiency): {(r, i, t, v, o)}" + logger.error(msg) + raise ValueError(msg) + + l = value(M.LifetimeProcess[r, t, v]) + if p < v: + msg = f"Invalid period-vintage set (period cannot come before vintage) in EfficiencyVariable table: {(t, p, v)}" + logger.error(msg) + raise ValueError(msg) + elif v + l <= p: + msg = f"Invalid period-vintage-lifetime set (v + l must be greater than p) in EfficiencyVariable table: {(t, v, l, p)}" + logger.error(msg) + raise ValueError(msg) + else: + M.variableEfficiencies[(r, p, s, d, i, t, v, o)] = True # pull from efficiencyvariable if available + if (r, i, t, v, o) not in count_ritvo.keys(): + count_ritvo[(r, i, t, v, o)] = 1 + else: + count_ritvo[(r, i, t, v, o)] += 1 + + num_seg = len(M.time_season) * len(M.time_of_day) + for (r, i, t, v, o), count in count_ritvo.items(): + num_p = len(set( + p + for p in M.time_optimize + if v <= p and v + value(M.LifetimeProcess[r, t, v]) > p + )) + target_count = num_seg * num_p + if count > 0 and count < target_count: + logger.warning("Only some variable efficiencies were set (%i out of a possible %i) for: %s", count, target_count, (r, i, t, v, o)) + + @deprecated(reason='vintage defaults are no longer available, so this should not be needed') def CreateCosts(M: 'TemoaModel'): """ diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index d686a42a9..261c1e392 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -123,6 +123,7 @@ def __init__(M, *args, **kwargs): M.importRegions = dict() M.time_next = dict() M.demandPeriodDistributions: dict[tuple, bool] = dict() # which demands have period indexing + M.variableEfficiencies: dict[tuple, bool] = dict() # which efficiencies have variable indexing M.flex_commodities = set() ################################################ @@ -263,7 +264,6 @@ def __init__(M, *args, **kwargs): within=NonNegativeReals, validate=validate_Efficiency, ) - M.validate_UsedEfficiencyIndices = BuildAction(rule=CheckEfficiencyIndices) M.CapacityFactor_rsdt = Set(dimen=4, initialize=CapacityFactorTechIndices) @@ -290,6 +290,19 @@ def __init__(M, *args, **kwargs): M.LifetimeProcess_rtv = Set(dimen=3, initialize=LifetimeProcessIndices) M.LifetimeProcess = Param(M.LifetimeProcess_rtv, default=get_default_process_lifetime) + M.EfficiencyVariable = Param( + M.regionalIndices, + M.time_optimize, + M.time_season, + M.time_of_day, + M.commodity_physical, + M.tech_all, + M.vintage_all, + M.commodity_carrier, + within=NonNegativeReals, + ) + M.initialize_variableEfficiencies = BuildAction(rule=CreateVariableEfficiencies) + M.LoanLifetimeTech = Param(M.regionalIndices, M.tech_all, default=10) M.LoanLifetimeProcess_rtv = Set(dimen=3, initialize=LifetimeLoanProcessIndices) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index a50504e17..d6e2c5ecd 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -803,14 +803,14 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): ) consumed = sum( - M.V_FlowOut[r, p, s, d, c, S_t, S_v, S_o] / value(M.Efficiency[r, c, S_t, S_v, S_o]) + M.V_FlowOut[r, p, s, d, c, S_t, S_v, S_o] / get_variable_efficiency(M, r, p, s, d, c, S_t, S_v, S_o) for S_t, S_v in M.commodityDStreamProcess[r, p, c] if S_t not in M.tech_storage and S_t not in M.tech_annual for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] ) consumed_annual = value(M.SegFrac[s, d]) * sum( - M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] / value(M.Efficiency[r, c, S_t, S_v, S_o]) + M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] / get_variable_efficiency(M, r, p, s, d, c, S_t, S_v, S_o) for S_t, S_v in M.commodityDStreamProcess[r, p, c] if S_t not in M.tech_storage and S_t in M.tech_annual for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] @@ -836,7 +836,7 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): if (r, p, c) in M.exportRegions: exported = sum( M.V_FlowOut[r + '-' + reg, p, s, d, c, S_t, S_v, S_o] - / value(M.Efficiency[r + '-' + reg, c, S_t, S_v, S_o]) + / get_variable_efficiency(M, r + '-' + reg, p, s, d, c, S_t, S_v, S_o) for reg, S_t, S_v, S_o in M.exportRegions[r, p, c] ) @@ -904,7 +904,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): ) consumed = sum( - M.V_FlowOut[r, p, S_s, S_d, c, S_t, S_v, S_o] / value(M.Efficiency[r, c, S_t, S_v, S_o]) + M.V_FlowOut[r, p, S_s, S_d, c, S_t, S_v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, c, S_t, S_v, S_o) for S_s in M.time_season for S_d in M.time_of_day for S_t, S_v in M.commodityDStreamProcess[r, p, c] @@ -941,7 +941,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): if (r, p, c) in M.exportRegions: exported = sum( M.V_FlowOut[r + '-' + S_r, p, S_s, S_d, c, S_t, S_v, S_o] - / value(M.Efficiency[r + '-' + S_r, c, S_t, S_v, S_o]) + / get_variable_efficiency(M, r + '-' + S_r, p, S_s, S_d, c, S_t, S_v, S_o) for S_s in M.time_season for S_d in M.time_of_day for S_r, S_t, S_v, S_o in M.exportRegions[r, p, c] @@ -1131,7 +1131,7 @@ def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): # This is the sum of all input=i sent TO storage tech t of vintage v with # output=o in p,s,d charge = sum( - M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] * value(M.Efficiency[r, S_i, t, v, S_o]) + M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] * get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) @@ -1218,7 +1218,7 @@ def StorageChargeRate_Constraint(M: 'TemoaModel', r, p, s, d, t, v): """ # Calculate energy charge in each time slice slice_charge = sum( - M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] * value(M.Efficiency[r, S_i, t, v, S_o]) + M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] * get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) @@ -1300,7 +1300,7 @@ def StorageThroughput_Constraint(M: 'TemoaModel', r, p, s, d, t, v): ) charge = sum( - M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] * value(M.Efficiency[r, S_i, t, v, S_o]) + M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] * get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) @@ -1601,7 +1601,7 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): if r1 == r: total_generation -= sum( M.V_FlowOut[r1r2, p, s, d, S_i, t, S_v, S_o] - / value(M.Efficiency[r1r2, S_i, t, S_v, S_o]) + / get_variable_efficiency(M, r1r2, p, s, d, S_i, t, S_v, S_o) for (t, S_v) in M.processReservePeriods[r1r2, p] for S_i in M.processInputs[r1r2, p, t, S_v] for S_o in M.processOutputsByInput[r1r2, p, t, S_v, S_i] @@ -2795,12 +2795,12 @@ def MinTechInputSplit_Constraint(M: 'TemoaModel', r, p, s, d, i, t, v): only the technologies with variable output at the timeslice level (i.e., NOT in the :code:`tech_annual` set) are considered.""" inp = sum( - M.V_FlowOut[r, p, s, d, i, t, v, S_o] / value(M.Efficiency[r, i, t, v, S_o]) + M.V_FlowOut[r, p, s, d, i, t, v, S_o] / get_variable_efficiency(M, r, p, s, d, i, t, v, S_o) for S_o in M.processOutputsByInput[r, p, t, v, i] ) total_inp = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] / value(M.Efficiency[r, S_i, t, v, S_o]) + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] / get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) @@ -2841,16 +2841,16 @@ def MinTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v): the constraint only fixes the input shares over the course of a year.""" inp = sum( - M.V_FlowOut[r, p, s, d, i, t, v, S_o] / value(M.Efficiency[r, i, t, v, S_o]) - for s in M.time_season - for d in M.time_of_day + M.V_FlowOut[r, p, S_s, S_d, i, t, v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) + for S_s in M.time_season + for S_d in M.time_of_day for S_o in M.processOutputsByInput[r, p, t, v, i] ) total_inp = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] / value(M.Efficiency[r, S_i, t, v, S_o]) - for s in M.time_season - for d in M.time_of_day + M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) + for S_s in M.time_season + for S_d in M.time_of_day for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, i] ) @@ -2976,12 +2976,12 @@ def MaxTechInputSplit_Constraint(M: 'TemoaModel', r, p, s, d, i, t, v): only the technologies with variable output at the timeslice level (i.e., NOT in the :code:`tech_annual` set) are considered.""" inp = sum( - M.V_FlowOut[r, p, s, d, i, t, v, S_o] / value(M.Efficiency[r, i, t, v, S_o]) + M.V_FlowOut[r, p, s, d, i, t, v, S_o] / get_variable_efficiency(M, r, p, s, d, i, t, v, S_o) for S_o in M.processOutputsByInput[r, p, t, v, i] ) total_inp = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] / value(M.Efficiency[r, S_i, t, v, S_o]) + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] / get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) @@ -3022,16 +3022,16 @@ def MaxTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v): the constraint only fixes the input shares over the course of a year.""" inp = sum( - M.V_FlowOut[r, p, s, d, i, t, v, S_o] / value(M.Efficiency[r, i, t, v, S_o]) - for s in M.time_season - for d in M.time_of_day + M.V_FlowOut[r, p, S_s, S_d, i, t, v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) + for S_s in M.time_season + for S_d in M.time_of_day for S_o in M.processOutputsByInput[r, p, t, v, i] ) total_inp = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] / value(M.Efficiency[r, S_i, t, v, S_o]) - for s in M.time_season - for d in M.time_of_day + M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) + for S_s in M.time_season + for S_d in M.time_of_day for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, i] ) @@ -3291,9 +3291,17 @@ def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): return -primary_flow == linked_flow -# To avoid building big many-indexed parameters when they aren't needed +# To avoid building big many-indexed parameters when they aren't needed - saves memory +# Much faster to build a dictionary and check that than check the parameter +# indices directly every time - saves build time def get_demand_distribution(M: 'TemoaModel', r, p, s, d, dem): if M.demandPeriodDistributions[(r, p, dem)]: return value(M.DemandPeriodDistribution[r, p, s, d, dem]) else: - return value(M.DemandSpecificDistribution[r, s, d, dem]) \ No newline at end of file + return value(M.DemandSpecificDistribution[r, s, d, dem]) + +def get_variable_efficiency(M: 'TemoaModel', r, p, s, d, i, t, v, o): + if M.variableEfficiencies[(r, p, s, d, i, t, v, o)]: + return value(M.Efficiency[r, i, t, v, o]) * value(M.EfficiencyVariable[r, p, s, d, i, t, v, o]) + else: + return value(M.Efficiency[r, i, t, v, o]) \ No newline at end of file From c7f538c07baeb5006a41c91d6ab25e02ff2714f9 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 14 Feb 2025 13:27:56 -0500 Subject: [PATCH 038/587] Remember to change things on output side as well --- temoa/temoa_model/table_data_puller.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index 37382898b..4e68d332b 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -144,7 +144,7 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl if abs(flow) < epsilon: continue res[fi][FlowType.IN] = flow - res[fi][FlowType.LOST] = (1 - value(M.Efficiency[ritvo(fi)])) * flow + res[fi][FlowType.LOST] = (1 - temoa_rules.get_variable_efficiency(M, *key)) * flow # regular flows for key in M.V_FlowOut: @@ -155,9 +155,9 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl res[fi][FlowType.OUT] = flow if fi.t not in M.tech_storage: # we can get the flow in by out/eff... - flow = value(M.V_FlowOut[fi]) / value(M.Efficiency[ritvo(fi)]) + flow = value(M.V_FlowOut[fi]) / temoa_rules.get_variable_efficiency(M, *key) res[fi][FlowType.IN] = flow - res[fi][FlowType.LOST] = (1 - value(M.Efficiency[ritvo(fi)])) * flow + res[fi][FlowType.LOST] = (1 - temoa_rules.get_variable_efficiency(M, *key)) * flow # curtailment flows for key in M.V_Curtailment: From 6f534678385d0df45f9ac865ab0f60ea99bd44a7 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Sun, 16 Feb 2025 11:15:52 -0500 Subject: [PATCH 039/587] Add period index to CapacityFactorProcess and optimize --- temoa/temoa_model/hybrid_loader.py | 4 +- .../temoa_model/model_checking/validators.py | 11 +- temoa/temoa_model/temoa_initialize.py | 187 ++++++++++-------- temoa/temoa_model/temoa_model.py | 82 ++++---- temoa/temoa_model/temoa_rules.py | 18 +- tests/testing_data/emissions.sql | 4 +- tests/testing_data/mediumville.sql | 8 +- tests/testing_data/simple_linked_tech.sql | 4 +- tests/testing_data/storageville.sql | 4 +- tests/testing_data/test_system.sql | 4 +- tests/testing_data/utopia.sql | 34 ++-- 11 files changed, 209 insertions(+), 151 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 7cb3a2804..251259bd8 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -639,8 +639,8 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # CapacityFactorProcess if self.table_exists("CapacityFactorProcess"): - raw = cur.execute('SELECT region, season, tod, tech, vintage, factor ' ' FROM main.CapacityFactorProcess').fetchall() - load_element(M.CapacityFactorProcess, raw, self.viable_rtv, (0, 3, 4)) + raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, season, tod, tech, vintage, factor FROM main.CapacityFactorProcess') + load_element(M.CapacityFactorProcess, raw, self.viable_rtv, (0, 4, 5)) # LifetimeTech if self.table_exists("LifetimeTech"): diff --git a/temoa/temoa_model/model_checking/validators.py b/temoa/temoa_model/model_checking/validators.py index b5c7e5e38..28cf59ff3 100644 --- a/temoa/temoa_model/model_checking/validators.py +++ b/temoa/temoa_model/model_checking/validators.py @@ -265,12 +265,14 @@ def validate_CapacityFactorProcess(M: 'TemoaModel', val, r, s, d, t, v) -> bool: :param v: vintage :return: """ + # devnote: CapacityFactorProcess can be a BIG table and most of these seem redundant + # when they're already enforced by the domain of the parameter return all( ( r in M.regions, s in M.time_season, d in M.time_of_day, - t in M.tech_all, + t in M.tech_with_capacity, v in M.vintage_all, 0 <= val <= 1.0, ) @@ -311,8 +313,8 @@ def check_flex_curtail(M: 'TemoaModel'): return False return True - -def validate_tech_input_split(M: 'TemoaModel', val, r, p, c, t): +# Seems unused +def validate_tech_split(M: 'TemoaModel', val, r, p, c, t): if all( ( r in M.regions, @@ -327,3 +329,6 @@ def validate_tech_input_split(M: 'TemoaModel', val, r, p, c, t): print('c', c in M.commodity_physical) print('t', t in M.tech_all) return False + +def validate_0to1(M: 'TemoaModel', val, *args): + return 0.0 <= val <= 1.0 \ No newline at end of file diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 37b742171..36eefacf6 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -247,6 +247,75 @@ def CheckEfficiencyIndices(M: 'TemoaModel'): f_msg = msg.format(', '.join(diff)) logger.error(f_msg) raise ValueError(f_msg) + + +def CheckEfficiencyVariable(M: 'TemoaModel'): + + count_rpitvo = dict() + # Pull non-variable efficiency by default + for r, i, t, v, o in M.Efficiency.sparse_iterkeys(): + for p in M.processPeriods[r, t, v]: + M.efficiencyVariables[r, p, i, t, v, o] = False + count_rpitvo[r, p, i, t, v, o] = 0 + + # Check for bad values and count up the good ones + for r, p, s, d, i, t, v, o in M.EfficiencyVariable.sparse_iterkeys(): + + if p not in M.processPeriods[r, t, v]: + msg = f"Invalid period {p} for process {r, t, v} in EfficiencyVariable table" + logger.error(msg) + raise ValueError(msg) + + # Good value, pull from EfficiencyVariable table + count_rpitvo[r, p, i, t, v, o] += 1 + + # Check if all possible values have been set as variable + # log a warning if some are missing (allowed but maybe accidental) + num_seg = len(M.time_season) * len(M.time_of_day) + for (r, p, i, t, v, o), count in count_rpitvo.items(): + + if count > 0: + M.efficiencyVariables[r, p, i, t, v, o] = True + if count < num_seg: + logger.warning( + 'Some but not all EfficiencyVariable values were set (%i out of a possible %i) for: %s' + ' Missing values will default to value set in Efficiency table.' + , count, num_seg, (r, p, i, t, v, o) + ) + + +def CheckCapacityFactorProcess(M: 'TemoaModel'): + + count_rptv = dict() + # Pull CapacityFactorTech by default + for r, s, d, t in M.CapacityFactor_rsdt: + for p, v in M.processTechs[r, t]: + M.capacityFactorProcesses[r, p, t, v] = False + count_rptv[r, p, t, v] = 0 + + # Check for bad values and count up the good ones + for r, p, s, d, t, v in M.CapacityFactorProcess.sparse_iterkeys(): + + if (p, v) not in M.processTechs[r, t]: + msg = f"Invalid process {p, v} for {r, t} in CapacityFactorProcess table" + logger.error(msg) + raise ValueError(msg) + + # Good value, pull from CapacityFactorProcess table + count_rptv[r, p, t, v] += 1 + + # Check if all possible values have been set by process + # log a warning if some are missing (allowed but maybe accidental) + num_seg = len(M.time_season) * len(M.time_of_day) + for (r, p, t, v), count in count_rptv.items(): + if count > 0: + M.capacityFactorProcesses[r, p, t, v] = True + if count < num_seg: + logger.warning( + 'Some but not all processes were set in CapacityFactorProcess (%i out of a possible %i) for: %s' + ' Missing values will default to CapacityFactorTech value or 1 if that is not set either.' + , count, num_seg, (r, p, t, v) + ) @deprecated('should not be needed. We are pulling the default on-the-fly where used') @@ -306,7 +375,7 @@ def get_default_process_lifetime(M: 'TemoaModel', r, t, v): return M.LifetimeTech[r, t] -def get_default_capacity_factor(M: 'TemoaModel', r, s, d, t, v): +def get_default_capacity_factor(M: 'TemoaModel', r, p, s, d, t, v): """ This initializer is used to fill the CapacityFactorProcess from the CapacityFactorTech where needed. @@ -429,6 +498,7 @@ def CreateDemands(M: 'TemoaModel'): # and we need to ensure even the zeros are passed in expected_key_length = len(M.time_season) * len(M.time_of_day) used_reg_dems = set((r, dem) for r, p, dem in M.Demand.sparse_iterkeys()) + count_rp_dem = dict() for r, dem in used_reg_dems: keys = [ k @@ -440,7 +510,7 @@ def CreateDemands(M: 'TemoaModel'): (s, d) for s in M.time_season for d in M.time_of_day - if (r, s, d, dem) not in keys + if (r, s, d, dem) not in keys # this could be very slow but only calls when there's a problem ) logger.warning( 'Missing some time slices for Demand Specific Distribution %s: %s', @@ -478,99 +548,43 @@ def CreateDemands(M: 'TemoaModel'): # No DPD by default for p in M.time_optimize: - M.demandPeriodDistributions[(r, p, dem)] = False + M.demandPeriodDistributions[r, p, dem] = False + count_rp_dem[r, p, dem] = 0 # Step 6: Validate DPD DPD = M.DemandPeriodDistribution - # Get the rp_dem combos that have period indexing, so we know later on which demands use it - rp_dem = set( - (r, p, dem) - for r, p, s, d, dem in DPD.sparse_iterkeys() - ) - for r, p, dem in rp_dem: + # This is a fast way to check if we're missing indices + for r, p, s, d, dem in DPD.sparse_iterkeys(): + count_rp_dem[r, p, dem] += 1 - # Check that each DPD demand actually has all the timeslices defined - missing = set( - (s, d) - for s in M.time_season - for d in M.time_of_day - if (r, p, s, d, dem) not in DPD.sparse_iterkeys() - ) - if len(missing) > 0: - msg = ('Missing some time slices for Demand Period Distribution {}: {}') - logger.warning(msg.format((r, p, dem), missing)) + for (r, p, dem), count in count_rp_dem.items(): + + if count == 0: continue + elif count < expected_key_length: + logger.warning( + "Some but not all DemandPeriodDistribution values were set (%i out of a possible %i) for: %s" + , count, expected_key_length, (r, p, dem) + ) total = sum( M.DemandPeriodDistribution[r, p, s, d, dem] for s in M.time_season for d in M.time_of_day ) - if abs(value(total) - 1.0) > 0.001: + if abs(value(total) - 1.0) < 0.001: + # This is a good DPD, override DSD/DDD + M.demandPeriodDistributions[r, p, dem] = True + else: msg = ( 'The values of the DemandPeriodDistribution parameter do not ' 'sum to 1 for {}. Current sum = {}. Defaulting to DSD/DDD.' ) logger.warning(msg.format((r, p, dem), total)) - continue - - # This is a good DPD, override DSD/DDD - M.demandPeriodDistributions[(r, p, dem)] = True logger.debug('Finished creating demand distributions') -def CreateVariableEfficiencies(M: 'TemoaModel'): - - indices = set( - (r, p, s, d, i, t, v, o) - - for r, i, t, v, o in M.Efficiency.sparse_iterkeys() - for p in M.time_optimize - for s in M.time_season - for d in M.time_of_day - ) - - for rpsditvo in indices: - M.variableEfficiencies[rpsditvo] = False # pull non-variable efficiency by default - - count_ritvo = dict() - for r, p, s, d, i, t, v, o in M.EfficiencyVariable.sparse_iterkeys(): - try: - M.Efficiency[r, i, t, v, o] - except ValueError: - msg = f"Set in EfficiencyVariable table missing from Efficiency table (EfficiencyVariable is a multiplier on Efficiency): {(r, i, t, v, o)}" - logger.error(msg) - raise ValueError(msg) - - l = value(M.LifetimeProcess[r, t, v]) - if p < v: - msg = f"Invalid period-vintage set (period cannot come before vintage) in EfficiencyVariable table: {(t, p, v)}" - logger.error(msg) - raise ValueError(msg) - elif v + l <= p: - msg = f"Invalid period-vintage-lifetime set (v + l must be greater than p) in EfficiencyVariable table: {(t, v, l, p)}" - logger.error(msg) - raise ValueError(msg) - else: - M.variableEfficiencies[(r, p, s, d, i, t, v, o)] = True # pull from efficiencyvariable if available - if (r, i, t, v, o) not in count_ritvo.keys(): - count_ritvo[(r, i, t, v, o)] = 1 - else: - count_ritvo[(r, i, t, v, o)] += 1 - - num_seg = len(M.time_season) * len(M.time_of_day) - for (r, i, t, v, o), count in count_ritvo.items(): - num_p = len(set( - p - for p in M.time_optimize - if v <= p and v + value(M.LifetimeProcess[r, t, v]) > p - )) - target_count = num_seg * num_p - if count > 0 and count < target_count: - logger.warning("Only some variable efficiencies were set (%i out of a possible %i) for: %s", count, target_count, (r, i, t, v, o)) - - @deprecated(reason='vintage defaults are no longer available, so this should not be needed') def CreateCosts(M: 'TemoaModel'): """ @@ -770,6 +784,8 @@ def CreateSparseDicts(M: 'TemoaModel'): # technology subsets. if (r, p, t) not in M.processVintages: M.processVintages[r, p, t] = set() + if (r, t, v) not in M.processPeriods: + M.processPeriods[r, t, v] = set() if t in M.tech_curtailment and (r, p, t) not in M.curtailmentVintages: M.curtailmentVintages[r, p, t] = set() if t in M.tech_baseload and (r, p, t) not in M.baseloadVintages: @@ -864,6 +880,7 @@ def CreateSparseDicts(M: 'TemoaModel'): M.processInputsByOutput[r, p, t, v, o].add(i) M.processTechs[r, t].add((p, v)) M.processVintages[r, p, t].add(v) + M.processPeriods[r, t, v].add(p) if t in M.tech_curtailment: M.curtailmentVintages[r, p, t].add(v) if t in M.tech_baseload: @@ -936,13 +953,6 @@ def CreateSparseDicts(M: 'TemoaModel'): for i in sorted(l_unused_techs): SE.write(msg.format(i)) - # Establishing sequence of states - for s, d in M.time_season * M.time_of_day: - match M.StateSequencing: - case 0: s_next, d_next = loop_period_next_timeslice(M, s, d) - case 1: s_next, d_next = loop_season_next_timeslice(M, s, d) - M.time_next[s, d] = (s_next, d_next) - # valid region-period-commodity sets for commodity balance constraints commodityUpstream_rpi = set(M.commodityUStreamProcess.keys()) commodityDownstream_rpo = set(M.commodityDStreamProcess.keys()) @@ -1056,6 +1066,17 @@ def CreateSparseDicts(M: 'TemoaModel'): logger.debug('Completed creation of SparseDicts') +def CreateStateSequence(M: 'TemoaModel'): + # Establishing sequence of states + for s, d in M.time_season * M.time_of_day: + match M.StateSequencing: + case 0: s_next, d_next = loop_period_next_timeslice(M, s, d) + case 1: s_next, d_next = loop_season_next_timeslice(M, s, d) + M.time_next[s, d] = (s_next, d_next) + + logger.debug('Created sequence of states') + + # --------------------------------------------------------------- # Create sparse parameter indices. # These functions are called from temoa_model.py and use the sparse keys @@ -1335,7 +1356,7 @@ def DemandActivityConstraintIndices(M: 'TemoaModel'): s0, d0 = None, None for s0, d0 in ((ss, dd) for ss in M.time_season for dd in M.time_of_day): if (r, s0, d0, dem) in M.DemandSpecificDistribution.sparse_iterkeys(): - if value(M.DemandSpecificDistribution[(r, s0, d0, dem)]) >= appreciable_size: + if value(M.DemandSpecificDistribution[r, s0, d0, dem]) >= appreciable_size: found_flag = True break # we have one with some value associated found = 'found' if found_flag else 'not found' diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 261c1e392..e983d1b24 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -37,6 +37,7 @@ validate_linked_tech, region_check, validate_CapacityFactorProcess, + validate_0to1, region_group_check, validate_Efficiency, check_flex_curtail, @@ -102,6 +103,7 @@ def __init__(M, *args, **kwargs): M.processOutputsByInput = dict() M.processTechs = dict() M.processReservePeriods = dict() + M.processPeriods = dict() # {(r, t, v): set(p)} M.processVintages = dict() """current available (within lifespan) vintages {(r, p, t) : set(v)}""" @@ -122,10 +124,17 @@ def __init__(M, *args, **kwargs): M.exportRegions = dict() M.importRegions = dict() M.time_next = dict() - M.demandPeriodDistributions: dict[tuple, bool] = dict() # which demands have period indexing - M.variableEfficiencies: dict[tuple, bool] = dict() # which efficiencies have variable indexing M.flex_commodities = set() + ################################################ + # Switching Sets # + # (used to optimize big tables/params) # + ################################################ + + M.demandPeriodDistributions: dict[tuple, bool] = dict() # which demands have period indexing + M.efficiencyVariables: dict[tuple, bool] = dict() # which efficiencies have variable indexing + M.capacityFactorProcesses: dict[tuple, bool] = dict() # which capacity factors have have period-vintage indexing + ################################################ # Model Sets # # (used for indexing model elements) # @@ -266,23 +275,36 @@ def __init__(M, *args, **kwargs): ) M.validate_UsedEfficiencyIndices = BuildAction(rule=CheckEfficiencyIndices) + M.EfficiencyVariable = Param( + M.regionalIndices, + M.time_optimize, + M.time_season, + M.time_of_day, + M.commodity_physical, + M.tech_all, + M.vintage_all, + M.commodity_carrier, + within=NonNegativeReals, + default=1, + ) + M.CapacityFactor_rsdt = Set(dimen=4, initialize=CapacityFactorTechIndices) - M.CapacityFactorTech = Param(M.CapacityFactor_rsdt, default=1) + M.CapacityFactorTech = Param(M.CapacityFactor_rsdt, default=1, validate=validate_0to1) # Dev note: using a default function below alleviates need to make this set. # M.CapacityFactor_rsdtv = Set(dimen=5, initialize=CapacityFactorProcessIndices) M.CapacityFactorProcess = Param( - M.regions, + M.regionalIndices, + M.time_optimize, M.time_season, M.time_of_day, M.tech_with_capacity, M.vintage_all, - validate=validate_CapacityFactorProcess, - default=get_default_capacity_factor, + # validate=validate_CapacityFactorProcess, + validate=validate_0to1, + default=get_default_capacity_factor, # surprisingly slow but only called if value is missing ) - # M.initialize_CapacityFactors = BuildAction(rule=CreateCapacityFactors) - M.LifetimeTech = Param( M.regionalIndices, M.tech_all, default=TemoaModel.default_lifetime_tech ) @@ -290,19 +312,6 @@ def __init__(M, *args, **kwargs): M.LifetimeProcess_rtv = Set(dimen=3, initialize=LifetimeProcessIndices) M.LifetimeProcess = Param(M.LifetimeProcess_rtv, default=get_default_process_lifetime) - M.EfficiencyVariable = Param( - M.regionalIndices, - M.time_optimize, - M.time_season, - M.time_of_day, - M.commodity_physical, - M.tech_all, - M.vintage_all, - M.commodity_carrier, - within=NonNegativeReals, - ) - M.initialize_variableEfficiencies = BuildAction(rule=CreateVariableEfficiencies) - M.LoanLifetimeTech = Param(M.regionalIndices, M.tech_all, default=10) M.LoanLifetimeProcess_rtv = Set(dimen=3, initialize=LifetimeLoanProcessIndices) @@ -313,27 +322,31 @@ def __init__(M, *args, **kwargs): M.LoanLifetimeProcess = Param(M.LoanLifetimeProcess_rtv, default=get_loan_life) # Min tech input split - M.MinTechInputSplit = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all) - M.MinTechInputSplitAnnual = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all) + M.MinTechInputSplit = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all, validate=validate_0to1) + M.MinTechInputSplitAnnual = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all, validate=validate_0to1) # Min tech output split - M.MinTechOutputSplit = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier) - M.MinTechOutputSplitAnnual = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier) + M.MinTechOutputSplit = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier, validate=validate_0to1) + M.MinTechOutputSplitAnnual = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier, validate=validate_0to1) # Max tech input split - M.MaxTechInputSplit = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all) - M.MaxTechInputSplitAnnual = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all) + M.MaxTechInputSplit = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all, validate=validate_0to1) + M.MaxTechInputSplitAnnual = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all, validate=validate_0to1) # Max tech output split - M.MaxTechOutputSplit = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier) - M.MaxTechOutputSplitAnnual = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier) + M.MaxTechOutputSplit = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier, validate=validate_0to1) + M.MaxTechOutputSplitAnnual = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier, validate=validate_0to1) M.RenewablePortfolioStandardConstraint_rpg = Set( within=M.regions * M.time_optimize * M.tech_group_names ) - M.RenewablePortfolioStandard = Param(M.RenewablePortfolioStandardConstraint_rpg) + M.RenewablePortfolioStandard = Param(M.RenewablePortfolioStandardConstraint_rpg, validate=validate_0to1) # The method below creates a series of helper functions that are used to # perform the sparse matrix of indexing for the parameters, variables, and # equations below. M.Create_SparseDicts = BuildAction(rule=CreateSparseDicts) + M.Create_StateSequence = BuildAction(rule=CreateStateSequence) + M.CapacityConstraint_rpsdtv = Set(dimen=6, initialize=CapacityConstraintIndices) + M.initialize_CapacityFactors = BuildAction(rule=CheckCapacityFactorProcess) + M.initialize_EfficiencyVariable = BuildAction(rule=CheckEfficiencyVariable) # Define technology cost parameters # dev note: the CostFixed_rptv isn't truly needed, but it is included in a constraint, so @@ -486,7 +499,7 @@ def __init__(M, *args, **kwargs): # This set works for all storage-related constraints M.StorageConstraints_rpsdtv = Set(dimen=6, initialize=StorageConstraintIndices) M.StorageFractionConstraint_rpsdtv = Set(within=M.StorageConstraints_rpsdtv) - M.StorageFraction = Param(M.StorageConstraints_rpsdtv) + M.StorageFraction = Param(M.StorageConstraints_rpsdtv, validate=validate_0to1) # Storage duration is expressed in hours M.StorageDuration = Param(M.regions, M.tech_storage, default=4) @@ -494,11 +507,11 @@ def __init__(M, *args, **kwargs): M.LinkedTechs = Param(M.regionalIndices, M.tech_all, M.commodity_emissions, within=Any) # Define parameters associated with electric sector operation - M.RampUp = Param(M.regions, M.tech_upramping) - M.RampDown = Param(M.regions, M.tech_downramping) + M.RampUp = Param(M.regions, M.tech_upramping, validate=validate_0to1) + M.RampDown = Param(M.regions, M.tech_downramping, validate=validate_0to1) M.CapacityCredit = Param( - M.regionalIndices, M.time_optimize, M.tech_all, M.vintage_all, default=0 + M.regionalIndices, M.time_optimize, M.tech_all, M.vintage_all, default=0, validate=validate_0to1 ) M.PlanningReserveMargin = Param(M.regions, default=0.2) @@ -583,7 +596,6 @@ def __init__(M, *args, **kwargs): M.progress_marker_4 = BuildAction(['Starting to build Constraints'], rule=progress_check) # Declare constraints to calculate derived decision variables - M.CapacityConstraint_rpsdtv = Set(dimen=6, initialize=CapacityConstraintIndices) M.CapacityConstraint = Constraint(M.CapacityConstraint_rpsdtv, rule=Capacity_Constraint) M.CapacityAnnualConstraint_rptv = Set(dimen=4, initialize=CapacityAnnualConstraintIndices) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index d6e2c5ecd..537672109 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -106,11 +106,7 @@ def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - if (r, s, d, t, v) in M.CapacityFactorProcess: - # use the data provided - capacity = value(M.CapacityFactorProcess[r, s, d, t, v]) - else: # use the capacity factor for the tech - capacity = value(M.CapacityFactorTech[r, s, d, t]) + capacity = get_capacity_factor(M, r, p, s, d, t, v) if t in M.tech_curtailment: # If technologies are present in the curtailment set, then enough @@ -3295,13 +3291,19 @@ def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): # Much faster to build a dictionary and check that than check the parameter # indices directly every time - saves build time def get_demand_distribution(M: 'TemoaModel', r, p, s, d, dem): - if M.demandPeriodDistributions[(r, p, dem)]: + if M.demandPeriodDistributions[r, p, dem]: return value(M.DemandPeriodDistribution[r, p, s, d, dem]) else: return value(M.DemandSpecificDistribution[r, s, d, dem]) def get_variable_efficiency(M: 'TemoaModel', r, p, s, d, i, t, v, o): - if M.variableEfficiencies[(r, p, s, d, i, t, v, o)]: + if M.efficiencyVariables[r, p, i, t, v, o]: return value(M.Efficiency[r, i, t, v, o]) * value(M.EfficiencyVariable[r, p, s, d, i, t, v, o]) else: - return value(M.Efficiency[r, i, t, v, o]) \ No newline at end of file + return value(M.Efficiency[r, i, t, v, o]) + +def get_capacity_factor(M: 'TemoaModel', r, p, s, d, t, v): + if M.capacityFactorProcesses[r, p, t, v]: + return value(M.CapacityFactorProcess[r, p, s, d, t, v]) + else: + return value(M.CapacityFactorTech[r, s, d, t]) \ No newline at end of file diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 2a50cec3a..34368dec6 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -53,6 +53,8 @@ CREATE TABLE CapacityCredit CREATE TABLE CapacityFactorProcess ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -62,7 +64,7 @@ CREATE TABLE CapacityFactorProcess vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, season, tod, tech, vintage), + PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE CapacityFactorTech diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 81b17ad41..21ed61de5 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -60,6 +60,8 @@ INSERT INTO CapacityCredit VALUES('A',2025,'EF',2025,0.5999999999999999778,NULL) CREATE TABLE CapacityFactorProcess ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -69,11 +71,11 @@ CREATE TABLE CapacityFactorProcess vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, season, tod, tech, vintage), + PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorProcess VALUES('A','s2','d1','EFL',2025,0.8000000000000000444,NULL); -INSERT INTO CapacityFactorProcess VALUES('A','s1','d2','EFL',2025,0.9000000000000000222,NULL); +INSERT INTO CapacityFactorProcess VALUES('A',2025,'s2','d1','EFL',2025,0.8000000000000000444,NULL); +INSERT INTO CapacityFactorProcess VALUES('A',2025,'s1','d2','EFL',2025,0.9000000000000000222,NULL); CREATE TABLE CapacityFactorTech ( region TEXT, diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index 36c6979fe..f3b222015 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -59,6 +59,8 @@ CREATE TABLE CapacityCredit CREATE TABLE CapacityFactorProcess ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -68,7 +70,7 @@ CREATE TABLE CapacityFactorProcess vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, season, tod, tech, vintage), + PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE CapacityFactorTech diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index a5eadacd7..da236bbc3 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -59,6 +59,8 @@ CREATE TABLE CapacityCredit CREATE TABLE CapacityFactorProcess ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -68,7 +70,7 @@ CREATE TABLE CapacityFactorProcess vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, season, tod, tech, vintage), + PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE CapacityFactorTech diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 2aa22f3de..2279e1e48 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -59,6 +59,8 @@ CREATE TABLE CapacityCredit CREATE TABLE CapacityFactorProcess ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -68,7 +70,7 @@ CREATE TABLE CapacityFactorProcess vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, season, tod, tech, vintage), + PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE CapacityFactorTech diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 137b4fd4f..7a6aba710 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -59,6 +59,8 @@ CREATE TABLE CapacityCredit CREATE TABLE CapacityFactorProcess ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -68,21 +70,27 @@ CREATE TABLE CapacityFactorProcess vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, season, tod, tech, vintage), + PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorProcess VALUES('utopia','inter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','inter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','winter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','winter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','summer','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','summer','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','inter','day','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','inter','night','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','winter','day','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','winter','night','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','summer','day','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','summer','night','E31',2010,0.2756000000000000116,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2010,0.2756000000000000116,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2010,0.2756000000000000116,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2010,0.2756000000000000116,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2010,0.2756000000000000116,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2010,0.2756000000000000116,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2010,0.2756000000000000116,''); CREATE TABLE CapacityFactorTech ( region TEXT, From d1e1f809358149ab768f1ed6bd8b579b34ac1305 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Sun, 16 Feb 2025 11:30:38 -0500 Subject: [PATCH 040/587] Fix myopic bug and make it harder to make same mistake in future --- temoa/temoa_model/hybrid_loader.py | 90 +++++++++++++++--------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 251259bd8..aba230956 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -562,7 +562,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # EfficiencyVariable if self.table_exists("EfficiencyVariable"): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, season, tod, input_comm, tech, vintage, output_comm, efficiency FROM main.EfficiencyVariable') + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tod, input_comm, tech, vintage, output_comm, efficiency FROM main.EfficiencyVariable') load_element(M.EfficiencyVariable, raw, self.viable_ritvo, (0, 4, 5, 6, 7)) # ExistingCapacity @@ -617,11 +617,11 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # DemandPeriodDistribution if self.table_exists('DemandPeriodDistribution'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, season, tod, demand_name, dpd FROM main.DemandPeriodDistribution') + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tod, demand_name, dpd FROM main.DemandPeriodDistribution') load_element(M.DemandPeriodDistribution, raw) # Demand - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, commodity, demand FROM main.Demand', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, commodity, demand FROM main.Demand') load_element(M.Demand, raw) # RescourceBound @@ -639,7 +639,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # CapacityFactorProcess if self.table_exists("CapacityFactorProcess"): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, season, tod, tech, vintage, factor FROM main.CapacityFactorProcess') + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tod, tech, vintage, factor FROM main.CapacityFactorProcess') load_element(M.CapacityFactorProcess, raw, self.viable_rtv, (0, 4, 5)) # LifetimeTech @@ -659,7 +659,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # MinTechInputSplit if self.table_exists('MinTechInputSplit'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, input_comm, tech, min_proportion FROM main.MinTechInputSplit', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, input_comm, tech, min_proportion FROM main.MinTechInputSplit') loaded = load_element(M.MinTechInputSplit, raw, self.viable_rpit, (0, 1, 2, 3)) # we need to see if anything was filtered out here and raise warning if so as it may have invalidated # a blending process and any missing items should be reviewed @@ -681,7 +681,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # MinTechInputSplitAnnual if self.table_exists('MinTechInputSplitAnnual'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, input_comm, tech, min_proportion FROM main.MinTechInputSplitAnnual', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, input_comm, tech, min_proportion FROM main.MinTechInputSplitAnnual') loaded = load_element(M.MinTechInputSplitAnnual, raw, self.viable_rpit, (0, 1, 2, 3)) # we need to see if anything was filtered out here and raise warning if so as it may have invalidated # a blending process and any missing items should be reviewed @@ -703,7 +703,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # MinTechOutputSplit if self.table_exists('MinTechOutputSplit'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, output_comm, min_proportion FROM main.MinTechOutputSplit', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, output_comm, min_proportion FROM main.MinTechOutputSplit') loaded = load_element(M.MinTechOutputSplit, raw, self.viable_rpto, (0, 1, 2, 3)) # raise warning regarding any deletions here... similar to input split above if len(loaded) < len(raw): @@ -724,7 +724,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # MinTechOutputSplitAnnual if self.table_exists('MinTechOutputSplitAnnual'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, output_comm, min_proportion FROM main.MinTechOutputSplitAnnual', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, output_comm, min_proportion FROM main.MinTechOutputSplitAnnual') loaded = load_element(M.MinTechOutputSplitAnnual, raw, self.viable_rpto, (0, 1, 2, 3)) # we need to see if anything was filtered out here and raise warning if so as it may have invalidated # a blending process and any missing items should be reviewed @@ -746,7 +746,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # MaxTechInputSplit if self.table_exists('MaxTechInputSplit'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, input_comm, tech, max_proportion FROM main.MaxTechInputSplit', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, input_comm, tech, max_proportion FROM main.MaxTechInputSplit') loaded = load_element(M.MaxTechInputSplit, raw, self.viable_rpit, (0, 1, 2, 3)) # we need to see if anything was filtered out here and raise warning if so as it may have invalidated # a blending process and any missing items should be reviewed @@ -768,7 +768,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # MaxTechInputSplitAnnual if self.table_exists('MaxTechInputSplitAnnual'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, input_comm, tech, max_proportion FROM main.MaxTechInputSplitAnnual', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, input_comm, tech, max_proportion FROM main.MaxTechInputSplitAnnual') loaded = load_element(M.MaxTechInputSplitAnnual, raw, self.viable_rpit, (0, 1, 2, 3)) # we need to see if anything was filtered out here and raise warning if so as it may have invalidated # a blending process and any missing items should be reviewed @@ -790,7 +790,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # MaxTechOutputSplit if self.table_exists('MaxTechOutputSplit'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, output_comm, max_proportion FROM main.MaxTechOutputSplit', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, output_comm, max_proportion FROM main.MaxTechOutputSplit') loaded = load_element(M.MaxTechOutputSplit, raw, self.viable_rpto, (0, 1, 2, 3)) # raise warning regarding any deletions here... similar to input split above if len(loaded) < len(raw): @@ -811,7 +811,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # MaxTechOutputSplitAnnual if self.table_exists('MaxTechOutputSplitAnnual'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, output_comm, max_proportion FROM main.MaxTechOutputSplitAnnual', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, output_comm, max_proportion FROM main.MaxTechOutputSplitAnnual') loaded = load_element(M.MaxTechOutputSplitAnnual, raw, self.viable_rpto, (0, 1, 2, 3)) # we need to see if anything was filtered out here and raise warning if so as it may have invalidated # a blending process and any missing items should be reviewed @@ -833,11 +833,11 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # RenewablePortfolioStandard if self.table_exists('RPSRequirement'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech_group, requirement FROM main.RPSRequirement', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech_group, requirement FROM main.RPSRequirement') load_element(M.RenewablePortfolioStandard, raw) # CostFixed - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, vintage, cost FROM main.CostFixed', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, vintage, cost FROM main.CostFixed') load_element(M.CostFixed, raw, self.viable_rtv, val_loc=(0, 2, 3)) # CostInvest @@ -853,14 +853,14 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): load_element(M.CostInvest, raw, self.viable_rtv, (0, 1, 2)) # CostVariable - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, vintage, cost FROM main.CostVariable', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, vintage, cost FROM main.CostVariable') load_element(M.CostVariable, raw, self.viable_rtv, (0, 2, 3)) # CostEmissions (and supporting index set) if self.table_exists('CostEmission'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, emis_comm from main.CostEmission', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, emis_comm from main.CostEmission') load_element(M.CostEmission_rpe, raw) - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, emis_comm, cost from main.CostEmission', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, emis_comm, cost from main.CostEmission') load_element(M.CostEmission, raw) # DefaultLoanRate @@ -885,92 +885,92 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # MinCapacity if self.table_exists('MinCapacity'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, min_cap FROM main.MinCapacity', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, min_cap FROM main.MinCapacity') load_element(M.MinCapacity, raw, self.viable_rt, (0, 2)) # MaxCapacity if self.table_exists('MaxCapacity'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, max_cap FROM main.MaxCapacity', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, max_cap FROM main.MaxCapacity') load_element(M.MaxCapacity, raw, self.viable_rt, (0, 2)) # MinNewCap if self.table_exists('MinNewCapacity'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, min_cap FROM main.MinNewCapacity', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, min_cap FROM main.MinNewCapacity') load_element(M.MinNewCapacity, raw, self.viable_rt, (0, 2)) # MaxNewCap if self.table_exists('MaxNewCapacity'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, max_cap FROM main.MaxNewCapacity', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, max_cap FROM main.MaxNewCapacity') load_element(M.MaxNewCapacity, raw, self.viable_rt, (0, 2)) # MaxCapacityGroup if self.table_exists('MaxCapacityGroup'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, group_name, max_cap FROM main.MaxCapacityGroup', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, max_cap FROM main.MaxCapacityGroup') load_element(M.MaxCapacityGroup, raw) # MinCapacityGroup if self.table_exists('MinCapacityGroup'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, group_name, min_cap FROM main.MinCapacityGroup', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, min_cap FROM main.MinCapacityGroup') load_element(M.MinCapacityGroup, raw) # MinNewCapacityGroup if self.table_exists('MinNewCapacityGroup'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, group_name, min_new_cap FROM main.MinNewCapacityGroup', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, min_new_cap FROM main.MinNewCapacityGroup') load_element(M.MinNewCapacityGroup, raw) # MaxNewCapacityGroup if self.table_exists('MaxNewCapacityGroup'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, group_name, max_new_cap FROM main.MaxNewCapacityGroup', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, max_new_cap FROM main.MaxNewCapacityGroup') load_element(M.MaxNewCapacityGroup, raw) # MinCapacityShare if self.table_exists('MinCapacityShare'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, group_name, min_proportion FROM main.MinCapacityShare', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, group_name, min_proportion FROM main.MinCapacityShare') load_element(M.MinCapacityShare, raw, self.viable_rt, (0, 2)) # MaxCapacityShare if self.table_exists('MaxCapacityShare'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, group_name, max_proportion FROM main.MaxCapacityShare', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, group_name, max_proportion FROM main.MaxCapacityShare') load_element(M.MaxCapacityShare, raw, self.viable_rt, (0, 2)) # MinNewCapacityShare if self.table_exists('MinNewCapacityShare'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, group_name, max_proportion FROM main.MinNewCapacityShare', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, group_name, max_proportion FROM main.MinNewCapacityShare') load_element(M.MinNewCapacityShare, raw, self.viable_rt, (0, 2)) # MaxNewCapacityShare if self.table_exists('MaxNewCapacityShare'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, group_name, max_proportion FROM main.MaxNewCapacityShare', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, group_name, max_proportion FROM main.MaxNewCapacityShare') load_element(M.MaxNewCapacityShare, raw, self.viable_rt, (0, 2)) # MinNewCapacityGroupShare if self.table_exists('MinNewCapacityGroupShare'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, sub_group, super_group, min_proportion FROM main.MinNewCapacityGroupShare', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, sub_group, super_group, min_proportion FROM main.MinNewCapacityGroupShare') load_element(M.MinNewCapacityGroupShare, raw) # MaxNewCapacityGroupShare if self.table_exists('MaxNewCapacityGroupShare'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, sub_group, super_group, max_proportion FROM main.MaxNewCapacityGroupShare', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, sub_group, super_group, max_proportion FROM main.MaxNewCapacityGroupShare') load_element(M.MaxNewCapacityGroupShare, raw) # MinActivityGroup if self.table_exists('MinActivityGroup'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, group_name, min_act FROM main.MinActivityGroup', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, min_act FROM main.MinActivityGroup') load_element(M.MinActivityGroup, raw) # MaxActivityGroup if self.table_exists('MaxActivityGroup'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, group_name, max_act FROM main.MaxActivityGroup', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, max_act FROM main.MaxActivityGroup') load_element(M.MaxActivityGroup, raw) # MinActivityShare if self.table_exists('MinActivityShare'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, group_name, min_proportion FROM main.MinActivityShare', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, group_name, min_proportion FROM main.MinActivityShare') load_element(M.MinActivityShare, raw, self.viable_rt, (0, 2)) # MaxActivityShare if self.table_exists('MaxActivityShare'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, group_name, max_proportion FROM main.MaxActivityShare', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, group_name, max_proportion FROM main.MaxActivityShare') load_element(M.MaxActivityShare, raw, self.viable_rt, (0, 2)) # MaxResource @@ -980,32 +980,32 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # MaxActivity if self.table_exists('MaxActivity'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, max_act FROM main.MaxActivity', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, max_act FROM main.MaxActivity') load_element(M.MaxActivity, raw, self.viable_rt, (0, 2)) # MinActivity if self.table_exists('MinActivity'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, min_act FROM main.MinActivity', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, min_act FROM main.MinActivity') load_element(M.MinActivity, raw, self.viable_rt, (0, 2)) # MaxSeasonalActivity if self.table_exists('MaxSeasonalActivity'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, season, tech, max_act FROM main.MaxSeasonalActivity', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tech, max_act FROM main.MaxSeasonalActivity') load_element(M.MaxSeasonalActivity, raw, self.viable_rt, (0, 3)) # MinSeasonalActivity if self.table_exists('MinSeasonalActivity'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, season, tech, min_act FROM main.MinSeasonalActivity', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tech, min_act FROM main.MinSeasonalActivity') load_element(M.MinSeasonalActivity, raw, self.viable_rt, (0, 3)) # MinAnnualCapacityFactor if self.table_exists('MinAnnualCapacityFactor'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, output_comm, factor FROM main.MinAnnualCapacityFactor', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, output_comm, factor FROM main.MinAnnualCapacityFactor') load_element(M.MinAnnualCapacityFactor, raw, self.viable_rt, (0, 2)) # MaxAnnualCapacityFactor if self.table_exists('MaxAnnualCapacityFactor'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, output_comm, factor FROM main.MaxAnnualCapacityFactor', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, output_comm, factor FROM main.MaxAnnualCapacityFactor') load_element(M.MaxAnnualCapacityFactor, raw, self.viable_rt, (0, 2)) # GrowthRateMax @@ -1020,7 +1020,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # EmissionLimit if self.table_exists('EmissionLimit'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, emis_comm, value FROM main.EmissionLimit', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, emis_comm, value FROM main.EmissionLimit') load_element(M.EmissionLimit, raw) # EmissionActivity @@ -1081,7 +1081,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # CapacityCredit if self.table_exists('CapacityCredit'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, tech, vintage, credit FROM main.CapacityCredit', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, vintage, credit FROM main.CapacityCredit') load_element(M.CapacityCredit, raw, self.viable_rtv, (0, 2, 3)) # PlanningReserveMargin @@ -1096,7 +1096,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # StorageFraction if self.table_exists('StorageFraction'): - raw = self.raw_check_mi_period(cur=cur, qry='SELECT region, period, season, tod, tech, vintage, frac FROM main.StorageFraction', mi=mi) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tod, tech, vintage, frac FROM main.StorageFraction') load_element(M.StorageFraction, raw, self.viable_rtv, (0,4,5)) # For T/S: dump the size of all data elements into the log @@ -1111,7 +1111,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): return data - def raw_check_mi_period(self, cur: Cursor, qry: str, mi: MyopicIndex | None = None) -> list: + def raw_check_mi_period(self, mi: MyopicIndex | None, cur: Cursor, qry: str) -> list: if mi: return cur.execute( qry + ' WHERE period >= ? AND period <= ?', From a8dc91b2dd647182bb724751b5dad4e8fdfa4d5f Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 25 Feb 2025 12:05:39 -0500 Subject: [PATCH 041/587] Add some log messaging for new state sequencing behaviour --- temoa/temoa_model/temoa_initialize.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 36eefacf6..582cf74a0 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1068,15 +1068,22 @@ def CreateSparseDicts(M: 'TemoaModel'): def CreateStateSequence(M: 'TemoaModel'): # Establishing sequence of states - for s, d in M.time_season * M.time_of_day: - match M.StateSequencing: - case 0: s_next, d_next = loop_period_next_timeslice(M, s, d) - case 1: s_next, d_next = loop_season_next_timeslice(M, s, d) - M.time_next[s, d] = (s_next, d_next) - - logger.debug('Created sequence of states') - + match M.StateSequencing: + case 0: + msg = 'Looping state each period, chaining between seasons.' + for s, d in M.time_season * M.time_of_day: + M.time_next[s, d] = loop_period_next_timeslice(M, s, d) + case 1: + msg = 'Looping state each season.' + for s, d in M.time_season * M.time_of_day: + M.time_next[s, d] = loop_season_next_timeslice(M, s, d) + + msg += (' This behaviour can be changed using the' + ' state_sequencing parameter in the MetaData table') + logger.info(msg) + logger.debug('Created sequence of states.') + # --------------------------------------------------------------- # Create sparse parameter indices. # These functions are called from temoa_model.py and use the sparse keys From e2c40140bfa30c3ca44a431e0e29ae386043f414 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 25 Feb 2025 13:11:16 -0500 Subject: [PATCH 042/587] Fix a bug in RampDown initialisation --- temoa/temoa_model/temoa_initialize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 582cf74a0..4618553f2 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -889,7 +889,7 @@ def CreateSparseDicts(M: 'TemoaModel'): M.storageVintages[r, p, t].add(v) if t in M.tech_upramping: M.rampUpVintages[r, p, t].add(v) - if t in M.tech_upramping: + if t in M.tech_downramping: M.rampDownVintages[r, p, t].add(v) # min tech split From 3a471c5b6217a52926cca774f26e850d97bdda04 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 13 Mar 2025 13:50:13 -0400 Subject: [PATCH 043/587] Add more detail to state sequencing log info --- temoa/temoa_model/temoa_initialize.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 4618553f2..423425ccf 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1079,7 +1079,9 @@ def CreateStateSequence(M: 'TemoaModel'): M.time_next[s, d] = loop_season_next_timeslice(M, s, d) msg += (' This behaviour can be changed using the' - ' state_sequencing parameter in the MetaData table') + ' state_sequencing parameter in the MetaData table. ' + '0 = loop periods, ' + '1 = loop seasons.') logger.info(msg) logger.debug('Created sequence of states.') From a0d5018ec6afc466ea65e8b006385a78b4ae3312 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 13 Mar 2025 22:27:24 -0400 Subject: [PATCH 044/587] Add experimental support for different seasons and segfracs by period --- temoa/temoa_model/hybrid_loader.py | 65 ++++-- temoa/temoa_model/table_data_puller.py | 8 +- temoa/temoa_model/temoa_initialize.py | 304 +++++++++++-------------- temoa/temoa_model/temoa_model.py | 11 +- temoa/temoa_model/temoa_rules.py | 146 ++++++------ 5 files changed, 258 insertions(+), 276 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index aba230956..2179c941d 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -348,7 +348,7 @@ def load_element( data[c.name] = {t[:-1]: t[-1] for t in screened} return screened - def load_indexed_set(indexed_set: Set, index_value, element, element_validator): + def load_indexed_set(indexed_set: Set, index_value, element, element_validator=None): """ load an element into an indexed set in the data store :param indexed_set: the name of the pyomo Set @@ -392,19 +392,41 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): "SELECT period FROM main.TimePeriod WHERE flag = 'f' ORDER BY sequence" ).fetchall() load_element(M.time_future, raw) + time_optimize = [p[0] for p in raw[0:-1]] # time_of_day if self.table_exists("TimeOfDay"): raw = cur.execute('SELECT tod FROM main.TimeOfDay ORDER BY sequence').fetchall() load_element(M.time_of_day, raw) else: + logger.warning('No TimeOfDay table found. Loading a single filler time of day "D" (assume this is an annual model)') load_element(M.time_of_day, [('D',)]) - # time_season + # TimeSeason if self.table_exists("TimeSeason"): - raw = cur.execute('SELECT season FROM main.TimeSeason ORDER BY sequence').fetchall() - load_element(M.time_season, raw) + if mi: + raw = cur.execute( + 'SELECT period, season FROM main.TimeSeason WHERE' + ' period >= ? AND period <= ? ORDER BY period, sequence', + (mi.base_year, mi.last_demand_year) + ).fetchall() + else: + raw = cur.execute('SELECT period, season FROM main.TimeSeason ORDER BY period, sequence').fetchall() + for row in raw: + load_indexed_set( + M.TimeSeason, + index_value=row[0], + element=row[1] + ) + load_element(M.time_season, [(row[1],) for row in raw]) else: + for period in time_optimize: + load_indexed_set( + M.TimeSeason, + index_value=period, + element='S' + ) + logger.warning('No TimeSeason table found. Loading a single filler season "S" (assume this is an annual model)') load_element(M.time_season, [('S',)]) # StateSequencing @@ -479,16 +501,14 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): load_element(M.tech_reserve, raw, self.viable_techs) # tech_ramping - techs = set() if self.table_exists('RampUp'): ramp_up_techs = cur.execute('SELECT tech FROM main.RampUp').fetchall() - techs.update({t[0] for t in ramp_up_techs}) - load_element(M.tech_upramping, sorted((t,) for t in techs), self.viable_techs) # sort for deterministic behavior - techs = set() + techs = {t[0] for t in ramp_up_techs} + load_element(M.tech_upramping, sorted((t,) for t in techs), self.viable_techs) # sort for deterministic behavior if self.table_exists('RampDown'): ramp_dn_techs = cur.execute('SELECT tech FROM main.RampDown').fetchall() - techs.update({t[0] for t in ramp_dn_techs}) - load_element(M.tech_downramping, sorted((t,) for t in techs), self.viable_techs) # sort for deterministic behavior + techs = {t[0] for t in ramp_dn_techs} + load_element(M.tech_downramping, sorted((t,) for t in techs), self.viable_techs) # sort for deterministic behavior # tech_curtailment raw = cur.execute('SELECT tech FROM Technology WHERE curtail > 0').fetchall() @@ -603,38 +623,33 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator): # SegFrac if self.table_exists("TimeSegmentFraction"): - raw = cur.execute('SELECT season, tod, segfrac FROM main.TimeSegmentFraction').fetchall() + raw = self.raw_check_mi_period(mi=mi, cur=cur, qry='SELECT period, season, tod, segfrac FROM main.TimeSegmentFraction') load_element(M.SegFrac, raw) else: - load_element(M.SegFrac, [("S","D",1)]) + logger.warning( + 'No TimeSegmentFraction table found. Loading filler SegFrac ("S", "D") for one time segment per period' + ' (assume this is an annual model)' + ) + filler_segfrac = [(p, "S", "D", 1) for p in time_optimize] # if no segfrac table, assume this is an annual model + load_element(M.SegFrac, filler_segfrac) # DemandSpecificDistribution if self.table_exists('DemandSpecificDistribution'): - raw = cur.execute( - 'SELECT region, season, tod, demand_name, dsd FROM main.DemandSpecificDistribution' - ).fetchall() + raw = self.raw_check_mi_period(mi=mi, cur=cur, qry='SELECT region, period, season, tod, demand_name, dsd FROM main.DemandSpecificDistribution') load_element(M.DemandSpecificDistribution, raw) - # DemandPeriodDistribution - if self.table_exists('DemandPeriodDistribution'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tod, demand_name, dpd FROM main.DemandPeriodDistribution') - load_element(M.DemandPeriodDistribution, raw) - # Demand raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, commodity, demand FROM main.Demand') load_element(M.Demand, raw) - # RescourceBound - # Not currently implemented - # CapacityToActivity if self.table_exists("CapacityToActivity"): - raw = cur.execute('SELECT region, tech, c2a FROM main.CapacityToActivity ').fetchall() + raw = cur.execute('SELECT region, tech, c2a FROM main.CapacityToActivity').fetchall() load_element(M.CapacityToActivity, raw, self.viable_rt, (0, 1)) # CapacityFactorTech if self.table_exists("CapacityFactorTech"): - raw = cur.execute('SELECT region, season, tod, tech, factor ' 'FROM main.CapacityFactorTech').fetchall() + raw = self.raw_check_mi_period(mi=mi, cur=cur, qry='SELECT region, season, tod, tech, factor FROM main.CapacityFactorTech') load_element(M.CapacityFactorTech, raw, self.viable_rt, (0, 3)) # CapacityFactorProcess diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index 4e68d332b..2ebd765b1 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -180,7 +180,7 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl # basic annual flows for r, p, i, t, v, o in M.V_FlowOutAnnual: - for s in M.time_season: + for s in M.TimeSeason[p]: for d in M.time_of_day: fi = FI(r, p, s, d, i, t, v, o) flow = value(M.V_FlowOutAnnual[r, p, i, t, v, o]) * value(M.SegFrac[s, d]) @@ -192,7 +192,7 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl # flex annual for r, p, i, t, v, o in M.V_FlexAnnual: - for s in M.time_season: + for s in M.TimeSeason[p]: for d in M.time_of_day: fi = FI(r, p, s, d, i, t, v, o) flow = value(M.V_FlexAnnual[r, p, i, t, v, o]) * value(M.SegFrac[s, d]) @@ -340,7 +340,7 @@ def poll_cost_results( value(M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o]) for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] - for S_s in M.time_season + for S_s in M.TimeSeason[p] for S_d in M.time_of_day ) else: @@ -462,7 +462,7 @@ def poll_emissions( normal = [ (r, p, e, s, d, i, t, v, o) for (r, p, e, i, t, v, o) in base - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day if t not in M.tech_annual ] diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 423425ccf..7600dbcbf 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -178,28 +178,40 @@ def validate_time(M: 'TemoaModel'): def validate_SegFrac(M: 'TemoaModel'): """Ensure that the segment fractions adds up to 1""" - total = sum(i for i in M.SegFrac.values()) - if abs(float(total) - 1.0) > 0.001: - # We can't explicitly test for "!= 1.0" because of incremental rounding - # errors associated with the specification of SegFrac by time slice, - # but we check to make sure it is within the specified tolerance. + for p in M.time_optimize: - key_padding = max(map(get_str_padding, M.SegFrac.sparse_iterkeys())) + keys = [ + (_p, s, d) + for _p, s, d in M.SegFrac.sparse_iterkeys() + if _p == p + ] - fmt = '%%-%ds = %%s' % key_padding - # Works out to something like "%-25s = %s" + total = sum( + M.SegFrac[k] + for k in keys + ) - items = sorted(M.SegFrac.items()) - items = '\n '.join(fmt % (str(k), v) for k, v in items) + if abs(float(total) - 1.0) > 0.001: + # We can't explicitly test for "!= 1.0" because of incremental rounding + # errors associated with the specification of SegFrac by time slice, + # but we check to make sure it is within the specified tolerance. - msg = ( - 'The values of the SegFrac parameter do not sum to 1. Each item ' - 'in SegFrac represents a fraction of a year, so they must total to ' - '1. Current values:\n {}\n\tsum = {}' - ) - logger.error(msg.format(items, total)) - raise Exception(msg.format(items, total)) + key_padding = max(map(get_str_padding, keys)) + + fmt = '%%-%ds = %%s' % key_padding + # Works out to something like "%-25s = %s" + + items = sorted([(k, M.SegFrac[k]) for k in keys]) + items = '\n '.join(fmt % (str(k), v) for k, v in items) + + msg = ( + 'The values of the SegFrac parameter do not sum to 1 for period {}. ' + 'Each item in SegFrac represents a fraction of a year, so they must ' + 'total to 1. Current values:\n {}\n\tsum = {}' + ) + logger.error(msg.format(p, items, total)) + raise Exception(msg.format(p, items, total)) def CheckEfficiencyIndices(M: 'TemoaModel'): @@ -271,7 +283,7 @@ def CheckEfficiencyVariable(M: 'TemoaModel'): # Check if all possible values have been set as variable # log a warning if some are missing (allowed but maybe accidental) - num_seg = len(M.time_season) * len(M.time_of_day) + num_seg = len(M.TimeSeason[p]) * len(M.time_of_day) for (r, p, i, t, v, o), count in count_rpitvo.items(): if count > 0: @@ -306,7 +318,7 @@ def CheckCapacityFactorProcess(M: 'TemoaModel'): # Check if all possible values have been set by process # log a warning if some are missing (allowed but maybe accidental) - num_seg = len(M.time_season) * len(M.time_of_day) + num_seg = len(M.TimeSeason[p]) * len(M.time_of_day) for (r, p, t, v), count in count_rptv.items(): if count > 0: M.capacityFactorProcesses[r, p, t, v] = True @@ -334,7 +346,7 @@ def CreateCapacityFactors(M: 'TemoaModel'): all_cfs = set( (r, s, d, t, v) - for (r, t, v), s, d in cross_product(processes, M.time_season, M.time_of_day) + for (r, t, v), s, d in cross_product(processes, M.TimeSeason[p], M.time_of_day) ) # Step 2 @@ -416,15 +428,12 @@ def CreateDemands(M: 'TemoaModel'): logger.debug('Started creating demand distributions in CreateDemands()') # Step 0: some setup for a couple of reusable items - - # iget(3): 3 = magic number to specify the fourth column. Currently the - # demand in the tuple (r, s, d, dem) - DSD_dem_getter = iget(3) - - # iget(0): 0 = magic number to specify the first column. Currently the - # demand in the tuple (r, s, d, dem) - DSD_region_getter = iget(0) - + # Get the nth element from the tuple (r, p, s, d, dem) + # So we only have to update these indices in one place if they change + DSD_region = iget(0) + DSD_period = iget(1) + DSD_dem = iget(4) + # Step 1: Check if any demand commodities are going unused used_dems = set(dem for r, p, dem in M.Demand.sparse_iterkeys()) unused_dems = sorted(M.commodity_demand.difference(used_dems)) @@ -435,152 +444,107 @@ def CreateDemands(M: 'TemoaModel'): SE.write(msg.format(dem)) # Step 2: Build the demand default distribution (= segfrac) - DDD = M.DemandDefaultDistribution # Shorter, for us lazy programmer types - unset_defaults = set(M.SegFrac.sparse_iterkeys()) - unset_defaults.difference_update(DDD.sparse_iterkeys()) - if unset_defaults: + # DDD = M.DemandDefaultDistribution # Shorter, for us lazy programmer types + # unset_defaults = set(M.SegFrac.sparse_iterkeys()) + # unset_defaults.difference_update(DDD.sparse_iterkeys()) + # if unset_defaults: # Some hackery because Pyomo thinks that this Param is constructed. # However, in our view, it is not yet, because we're specifically # targeting values that have not yet been constructed, that we know are # valid, and that we will need. # DDD._constructed = False - for tslice in unset_defaults: - DDD[tslice] = M.SegFrac[tslice] # DDD._constructed = True + # for tslice in unset_defaults: + # DDD[tslice] = M.SegFrac[tslice] # DDD._constructed = True # Step 3: Check that DDD sums to 1 - total = sum(i for i in DDD.values()) - if abs(value(total) - 1.0) > 0.001: - # We can't explicitly test for "!= 1.0" because of incremental rounding - # errors associated with the specification of demand shares by time slice, - # but we check to make sure it is within the specified tolerance. - - key_padding = max(map(get_str_padding, DDD.sparse_iterkeys())) - - fmt = '%%-%ds = %%s' % key_padding - # Works out to something like "%-25s = %s" - - items = sorted(DDD.items()) - items = '\n '.join(fmt % (str(k), v) for k, v in items) - - msg = ( - 'The values of the DemandDefaultDistribution parameter do not ' - 'sum to 1. The DemandDefaultDistribution specifies how end-use ' - 'demands are distributed among the time slices (i.e., time_season, ' - 'time_of_day), so together, the data must total to 1. Current ' - 'values:\n {}\n\tsum = {}' - ) - logger.error(msg.format(items, total)) - raise ValueError(msg.format(items, total)) + # devnote: this seems redundant to the SegFrac sum to 1 check. + # total = sum(i for i in DDD.values()) + # if abs(value(total) - 1.0) > 0.001: + # # We can't explicitly test for "!= 1.0" because of incremental rounding + # # errors associated with the specification of demand shares by time slice, + # # but we check to make sure it is within the specified tolerance. + + # key_padding = max(map(get_str_padding, DDD.sparse_iterkeys())) + + # fmt = '%%-%ds = %%s' % key_padding + # # Works out to something like "%-25s = %s" + + # items = sorted(DDD.items()) + # items = '\n '.join(fmt % (str(k), v) for k, v in items) + + # msg = ( + # 'The values of the DemandDefaultDistribution parameter do not ' + # 'sum to 1. The DemandDefaultDistribution specifies how end-use ' + # 'demands are distributed among the time slices (i.e., time_season, ' + # 'time_of_day), so together, the data must total to 1. Current ' + # 'values:\n {}\n\tsum = {}' + # ) + # logger.error(msg.format(items, total)) + # raise ValueError(msg.format(items, total)) # Step 4: Fill out demand specific distribution table and check sums to 1 by region and demand DSD = M.DemandSpecificDistribution - demands_specified = set(map(DSD_dem_getter, (i for i in DSD.sparse_iterkeys()))) + demands_specified = set(map(DSD_dem, (i for i in DSD.sparse_iterkeys()))) unset_demand_distributions = used_dems.difference( demands_specified ) # the demands not mentioned in DSD *at all* - unset_distributions = set( - cross_product(M.regions, M.time_season, M.time_of_day, unset_demand_distributions) - ) - if unset_distributions: - # Some hackery because Pyomo thinks that this Param is constructed. - # However, in our view, it is not yet, because we're specifically - # targeting values that have not yet been constructed, that we know are - # valid, and that we will need. - # DSD._constructed = False - for r, s, d, dem in unset_distributions: - DSD[r, s, d, dem] = DDD[s, d] # DSD._constructed = True + if unset_demand_distributions: + for p in M.time_optimize: + unset_distributions = set( + cross_product(M.regions, (p,), M.TimeSeason[p], M.time_of_day, unset_demand_distributions) + ) + for r, p, s, d, dem in unset_distributions: + DSD[r, p, s, d, dem] = M.SegFrac[p, s, d] # DSD._constructed = True # Step 5: A final "sum to 1" check for all DSD members (which now should be everything) # Also check that all keys are made... The demand distro should be supported # by the full set of (r, p, dem) keys because it is an equality constraint # and we need to ensure even the zeros are passed in - expected_key_length = len(M.time_season) * len(M.time_of_day) - used_reg_dems = set((r, dem) for r, p, dem in M.Demand.sparse_iterkeys()) - count_rp_dem = dict() - for r, dem in used_reg_dems: + expected_key_length = len(M.TimeSeason[p]) * len(M.time_of_day) + used_rp_dems = set((r, p, dem) for r, p, dem in M.Demand.sparse_iterkeys()) + for r, p, dem in used_rp_dems: keys = [ k for k in DSD.sparse_iterkeys() - if DSD_dem_getter(k) == dem and DSD_region_getter(k) == r + if DSD_region(k) == r and DSD_period(k) == p and DSD_dem(k) == dem ] if len(keys) != expected_key_length: + # this could be very slow but only calls when there's a problem missing = set( (s, d) - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day - if (r, s, d, dem) not in keys # this could be very slow but only calls when there's a problem + if (r, p, s, d, dem) not in keys ) logger.warning( 'Missing some time slices for Demand Specific Distribution %s: %s', - (r, dem), missing, + (r, p, dem), missing, ) - total = sum(DSD[i] for i in keys) + total = sum(value(DSD[i]) for i in keys) if abs(value(total) - 1.0) > 0.001: # We can't explicitly test for "!= 1.0" because of incremental rounding # errors associated with the specification of demand shares by time slice, # but we check to make sure it is within the specified tolerance. - - keys = [ - k - for k in DSD.sparse_iterkeys() - if DSD_dem_getter(k) == dem and DSD_region_getter(k) == r - ] key_padding = max(map(get_str_padding, keys)) fmt = '%%-%ds = %%s' % key_padding # Works out to something like "%-25s = %s" - items = sorted((k, DSD[k]) for k in keys) + items = sorted((k, value(DSD[k])) for k in keys) items = '\n '.join(fmt % (str(k), v) for k, v in items) msg = ( 'The values of the DemandSpecificDistribution parameter do not ' - 'sum to 1. The DemandSpecificDistribution specifies how end-use ' + 'sum to 1 for {}. The DemandSpecificDistribution specifies how end-use ' 'demands are distributed per time-slice (i.e., time_season, ' - 'time_of_day). Within each end-use Demand, then, the distribution ' - 'must total to 1.\n\n Demand-specific distribution in error: ' - ' {}\n\n {}\n\tsum = {}' + 'time_of_day). Within each region, period, end-use demand, then, the distribution ' + 'must total to 1.\n\n Demand-specific distribution in error: ' + ' \n {}\n\tsum = {}' ) - logger.error(msg.format(dem, items, total)) - raise ValueError(msg.format(dem, items, total)) - - # No DPD by default - for p in M.time_optimize: - M.demandPeriodDistributions[r, p, dem] = False - count_rp_dem[r, p, dem] = 0 - - # Step 6: Validate DPD - DPD = M.DemandPeriodDistribution - - # This is a fast way to check if we're missing indices - for r, p, s, d, dem in DPD.sparse_iterkeys(): - count_rp_dem[r, p, dem] += 1 - - for (r, p, dem), count in count_rp_dem.items(): - - if count == 0: continue - elif count < expected_key_length: - logger.warning( - "Some but not all DemandPeriodDistribution values were set (%i out of a possible %i) for: %s" - , count, expected_key_length, (r, p, dem) - ) - - total = sum( - M.DemandPeriodDistribution[r, p, s, d, dem] - for s in M.time_season - for d in M.time_of_day - ) - if abs(value(total) - 1.0) < 0.001: - # This is a good DPD, override DSD/DDD - M.demandPeriodDistributions[r, p, dem] = True - else: - msg = ( - 'The values of the DemandPeriodDistribution parameter do not ' - 'sum to 1 for {}. Current sum = {}. Defaulting to DSD/DDD.' - ) - logger.warning(msg.format((r, p, dem), total)) + logger.error(msg.format((r, p, dem), items, total)) + raise ValueError(msg.format((r, p, dem), items, total)) logger.debug('Finished creating demand distributions') @@ -965,7 +929,7 @@ def CreateSparseDicts(M: 'TemoaModel'): for v in M.processVintages[r, p, t] for i in M.processInputs[r, p, t, v] for o in M.processOutputsByInput[r, p, t, v, i] - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -985,7 +949,7 @@ def CreateSparseDicts(M: 'TemoaModel'): for v in M.processVintages[r, p, t] for i in M.processInputs[r, p, t, v] for o in M.processOutputsByInput[r, p, t, v, i] - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -1005,7 +969,7 @@ def CreateSparseDicts(M: 'TemoaModel'): for v in M.processVintages[r, p, t] for i in M.processInputs[r, p, t, v] for o in M.processOutputsByInput[r, p, t, v, i] - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -1015,7 +979,7 @@ def CreateSparseDicts(M: 'TemoaModel'): for v in M.curtailmentVintages[r, p, t] for i in M.processInputs[r, p, t, v] for o in M.processOutputsByInput[r, p, t, v, i] - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -1059,7 +1023,7 @@ def CreateSparseDicts(M: 'TemoaModel'): (r, p, s, d, t, v) for r, p, t in M.storageVintages.keys() for v in M.storageVintages[r, p, t] - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -1067,16 +1031,19 @@ def CreateSparseDicts(M: 'TemoaModel'): def CreateStateSequence(M: 'TemoaModel'): + # Establishing sequence of states match M.StateSequencing: case 0: msg = 'Looping state each period, chaining between seasons.' - for s, d in M.time_season * M.time_of_day: - M.time_next[s, d] = loop_period_next_timeslice(M, s, d) + for p in M.time_optimize: + for s, d in M.TimeSeason[p] * M.time_of_day: + M.time_next[p, s, d] = loop_period_next_timeslice(M, p, s, d) case 1: msg = 'Looping state each season.' - for s, d in M.time_season * M.time_of_day: - M.time_next[s, d] = loop_season_next_timeslice(M, s, d) + for p in M.time_optimize: + for s, d in M.TimeSeason[p] * M.time_of_day: + M.time_next[p, s, d] = loop_season_next_timeslice(M, p, s, d) msg += (' This behaviour can be changed using the' ' state_sequencing parameter in the MetaData table. ' @@ -1098,7 +1065,8 @@ def CapacityFactorProcessIndices(M: 'TemoaModel'): indices = set( (r, s, d, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys() - for s in M.time_season + for p in M.time_optimize + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -1108,7 +1076,9 @@ def CapacityFactorProcessIndices(M: 'TemoaModel'): def CapacityFactorTechIndices(M: 'TemoaModel'): processes = set((r, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) all_cfs = set( - (r, s, d, t) for (r, t, v), s, d in cross_product(processes, M.time_season, M.time_of_day) + (r, s, d, t) + for p in M.time_optimize + for (r, t, v), s, d in cross_product(processes, M.TimeSeason[p], M.time_of_day) ) return all_cfs @@ -1287,7 +1257,7 @@ def CapacityConstraintIndices(M: 'TemoaModel'): for r, p, t, v in M.activeActivity_rptv if t not in M.tech_annual if t not in M.tech_uncap - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -1302,7 +1272,7 @@ def LinkedTechConstraintIndices(M: 'TemoaModel'): if (r, p, t) in M.processVintages.keys() for v in M.processVintages[r, p, t] if (r, p, t, v) in M.activeActivity_rptv - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -1350,27 +1320,27 @@ def DemandActivityConstraintIndices(M: 'TemoaModel'): if dem not in M.commodity_demand or t in M.tech_annual: continue # capture the (p, t, v) in case we need to act on it - viable_tech_vintage[r, dem].append((p, t, v)) + viable_tech_vintage[r, p, dem].append((t, v)) suppliers[dem].add(t) # one more recognized supplier if len(suppliers[dem]) > 1: # We need to act on (build) for this region-demand, put in a placeholder - anchor_season_tod[r, dem] = None + anchor_season_tod[r, p, dem] = None # Find the first timestep of the year where the demand is appreciably sized: # appreciable = not so small that we get into numerical instability when applying small multipliers appreciable_size = 0.0001 - for r, dem in anchor_season_tod: + for r, p, dem in anchor_season_tod: found_flag = False s0, d0 = None, None - for s0, d0 in ((ss, dd) for ss in M.time_season for dd in M.time_of_day): - if (r, s0, d0, dem) in M.DemandSpecificDistribution.sparse_iterkeys(): - if value(M.DemandSpecificDistribution[r, s0, d0, dem]) >= appreciable_size: + for s0, d0 in ((ss, dd) for ss in M.TimeSeason[p] for dd in M.time_of_day): + if (r, p, s0, d0, dem) in M.DemandSpecificDistribution.sparse_iterkeys(): + if value(M.DemandSpecificDistribution[r, p, s0, d0, dem]) >= appreciable_size: found_flag = True break # we have one with some value associated found = 'found' if found_flag else 'not found' # set it. If nothing was found the first indices should work just fine... - anchor_season_tod[r, dem] = (s0, d0) + anchor_season_tod[r, p, dem] = (s0, d0) logger.debug( 'Using season/tod: %s, %s for commodity %s in region %s which was %s in DSD ' 'to set DemandActivity baseline', @@ -1382,10 +1352,10 @@ def DemandActivityConstraintIndices(M: 'TemoaModel'): ) # Start yielding the constraint indices - for r, dem in anchor_season_tod: - s0, d0 = anchor_season_tod[r, dem] - for p, t, v in viable_tech_vintage[r, dem]: - for s in M.time_season: + for r, p, dem in anchor_season_tod: + s0, d0 = anchor_season_tod[r, p, dem] + for t, v in viable_tech_vintage[r, p, dem]: + for s in M.TimeSeason[p]: for d in M.time_of_day: if s != s0 or d != d0: yield r, p, s, d, t, v, dem, s0, d0 @@ -1395,7 +1365,7 @@ def DemandConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, s, d, dem) for r, p, dem in M.Demand.sparse_iterkeys() - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -1407,7 +1377,7 @@ def BaseloadDiurnalConstraintIndices(M: 'TemoaModel'): (r, p, s, d, t, v) for r, p, t in M.baseloadVintages.keys() for v in M.baseloadVintages[r, p, t] - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -1433,7 +1403,7 @@ def CommodityBalanceConstraintIndices(M: 'TemoaModel'): # r in this line includes interregional transfer combinations (not needed). if r in M.regions # this line ensures only the regions are included. and c not in M.commodity_annual - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -1458,7 +1428,7 @@ def RampUpConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, s, d, t, v) for r, p, t in M.rampUpVintages.keys() - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day for v in M.rampUpVintages[r, p, t] ) @@ -1470,7 +1440,7 @@ def RampDownConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, s, d, t, v) for r, p, t in M.rampDownVintages.keys() - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day for v in M.rampDownVintages[r, p, t] ) @@ -1483,7 +1453,7 @@ def ReserveMarginIndices(M: 'TemoaModel'): (r, p, s, d) for r in M.regions for p in M.time_optimize - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day ) return indices @@ -1495,7 +1465,7 @@ def MinTechInputSplitConstraintIndices(M: 'TemoaModel'): for r, p, i, t in M.minInputSplitVintages.keys() if t not in M.tech_annual for v in M.minInputSplitVintages[r, p, i, t] - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day ) ann_indices = set( @@ -1540,7 +1510,7 @@ def MinTechOutputSplitConstraintIndices(M: 'TemoaModel'): for r, p, t, o in M.minOutputSplitVintages.keys() if t not in M.tech_annual for v in M.minOutputSplitVintages[r, p, t, o] - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day ) ann_indices = set( @@ -1585,7 +1555,7 @@ def MaxTechInputSplitConstraintIndices(M: 'TemoaModel'): for r, p, i, t in M.maxInputSplitVintages.keys() if t not in M.tech_annual for v in M.maxInputSplitVintages[r, p, i, t] - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day ) ann_indices = set( @@ -1630,7 +1600,7 @@ def MaxTechOutputSplitConstraintIndices(M: 'TemoaModel'): for r, p, t, o in M.maxOutputSplitVintages.keys() if t not in M.tech_annual for v in M.maxOutputSplitVintages[r, p, t, o] - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day ) ann_indices = set( @@ -1678,20 +1648,20 @@ def GrowthRateMaxIndices(M: 'TemoaModel'): return indices -def loop_period_next_timeslice(M: 'TemoaModel', s, d) -> tuple[str, str]: +def loop_period_next_timeslice(M: 'TemoaModel', p, s, d) -> tuple[str, str]: # Final time slice of final season (end of period) # Loop state back to initial state of first season # Loop the period - if s == M.time_season.last() and d == M.time_of_day.last(): - s_next = M.time_season.first() + if s == M.TimeSeason[p][-1] and d == M.time_of_day.last(): + s_next = M.TimeSeason[p][0] d_next = M.time_of_day.first() # Last time slice of any season that is NOT the last season # Carry state to initial state of next season # Carry state between seasons elif d == M.time_of_day.last(): - s_next = M.time_season.next(s) + s_next = M.TimeSeason[p][M.TimeSeason[p].index(s)+1] d_next = M.time_of_day.first() # Any other time slice @@ -1704,7 +1674,7 @@ def loop_period_next_timeslice(M: 'TemoaModel', s, d) -> tuple[str, str]: return s_next, d_next -def loop_season_next_timeslice(M: 'TemoaModel', s, d) -> tuple[str, str]: +def loop_season_next_timeslice(M: 'TemoaModel', p, s, d) -> tuple[str, str]: # We loop each season so never carrying state between seasons s_next = s diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index e983d1b24..b12fe2abb 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -131,7 +131,6 @@ def __init__(M, *args, **kwargs): # (used to optimize big tables/params) # ################################################ - M.demandPeriodDistributions: dict[tuple, bool] = dict() # which demands have period indexing M.efficiencyVariables: dict[tuple, bool] = dict() # which efficiencies have variable indexing M.capacityFactorProcesses: dict[tuple, bool] = dict() # which capacity factors have have period-vintage indexing @@ -233,17 +232,17 @@ def __init__(M, *args, **kwargs): M.GlobalDiscountRate = Param(default=0.05) # Define time-related parameters + M.TimeSeason = Param(M.time_optimize) M.PeriodLength = Param(M.time_optimize, initialize=ParamPeriodLength) - M.SegFrac = Param(M.time_season, M.time_of_day) + M.SegFrac = Param(M.time_optimize, M.time_season, M.time_of_day) M.validate_SegFrac = BuildAction(rule=validate_SegFrac) M.StateSequencing = Param(default=0) # How do states carry between time segments? # Define demand- and resource-related parameters # Dev Note: There does not appear to be a DB table supporting DemandDefaultDistro. This does not # cause any problems, so let it be for now. - M.DemandDefaultDistribution = Param(M.time_season, M.time_of_day, mutable=True) - M.DemandSpecificDistribution = Param(M.regions, M.time_season, M.time_of_day, M.commodity_demand, mutable=True, default=0) - M.DemandPeriodDistribution = Param(M.regions, M.time_optimize, M.time_season, M.time_of_day, M.commodity_demand, default=0) + # M.DemandDefaultDistribution = Param(M.time_optimize, M.time_season, M.time_of_day, mutable=True) + M.DemandSpecificDistribution = Param(M.regions, M.time_optimize, M.time_season, M.time_of_day, M.commodity_demand, mutable=True, default=0) M.Demand = Param(M.regions, M.time_optimize, M.commodity_demand) M.initialize_Demands = BuildAction(rule=CreateDemands) @@ -664,7 +663,7 @@ def __init__(M, *args, **kwargs): # We make use of this following set in some of the storage constraints. # Pre-computing it is considerably faster. - M.SegFracPerSeason = Param(M.time_season, initialize=SegFracPerSeason_rule) + M.SegFracPerSeason = Param(M.time_optimize, M.time_season, initialize=SegFracPerSeason_rule) M.StorageEnergyConstraint = Constraint( M.StorageConstraints_rpsdtv, rule=StorageEnergy_Constraint diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 537672109..216cd0875 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -114,7 +114,7 @@ def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): return ( capacity * value(M.CapacityToActivity[r, t]) - * value(M.SegFrac[s, d]) + * value(M.SegFrac[p, s, d]) * value(M.ProcessLifeFrac[r, p, t, v]) * M.V_Capacity[r, p, t, v] == useful_activity + sum( M.V_Curtailment[r, p, s, d, S_i, t, v, S_o] @@ -126,7 +126,7 @@ def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): return ( capacity * value(M.CapacityToActivity[r, t]) - * value(M.SegFrac[s, d]) + * value(M.SegFrac[p, s, d]) * value(M.ProcessLifeFrac[r, p, t, v]) * M.V_Capacity[r, p, t, v] >= useful_activity @@ -504,7 +504,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): if S_p == p and S_t not in M.tech_annual for S_i in M.processInputs[r, S_p, S_t, S_v] for S_o in M.processOutputsByInput[r, S_p, S_t, S_v, S_i] - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -546,7 +546,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): normal = [ (r, p, e, s, d, i, t, v, o) for (r, p, e, i, t, v, o) in base - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day if t not in M.tech_annual ] @@ -651,12 +651,12 @@ def Demand_Constraint(M: 'TemoaModel', r, p, s, d, dem): for S_t, S_v in M.commodityUStreamProcess[r, p, dem] if S_t in M.tech_annual for S_i in M.processInputsByOutput[r, p, S_t, S_v, dem] - ) * value(M.SegFrac[s, d]) + ) * value(M.SegFrac[p, s, d]) DemandConstraintErrorCheck(supply + supply_annual, r, p, s, d, dem) expr = ( - supply + supply_annual == value(M.Demand[r, p, dem]) * get_demand_distribution(M, r, p, s, d, dem) + supply + supply_annual == value(M.Demand[r, p, dem]) * value(M.DemandSpecificDistribution[r, p, s, d, dem]) ) return expr @@ -701,8 +701,8 @@ def DemandActivity_Constraint(M: 'TemoaModel', r, p, s, d, t, v, dem, s_0, d_0): ) expr = ( - act_a * get_demand_distribution(M, r, p, s, d, dem) - == act_b * get_demand_distribution(M, r, p, s_0, d_0, dem) + act_a * value(M.DemandSpecificDistribution[r, p, s, d, dem]) + == act_b * value(M.DemandSpecificDistribution[r, p, s_0, d_0, dem]) ) return expr @@ -805,7 +805,7 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] ) - consumed_annual = value(M.SegFrac[s, d]) * sum( + consumed_annual = value(M.SegFrac[p, s, d]) * sum( M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] / get_variable_efficiency(M, r, p, s, d, c, S_t, S_v, S_o) for S_t, S_v in M.commodityDStreamProcess[r, p, c] if S_t not in M.tech_storage and S_t in M.tech_annual @@ -820,7 +820,7 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] ) - produced_annual = value(M.SegFrac[s, d]) * sum( + produced_annual = value(M.SegFrac[p, s, d]) * sum( M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, c] for S_t, S_v in M.commodityUStreamProcess[r, p, c] if S_t in M.tech_annual @@ -853,7 +853,7 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): if S_t not in M.tech_annual and S_t in M.tech_flex for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] ) - flex_waste_annual = value(M.SegFrac[s, d]) * sum( + flex_waste_annual = value(M.SegFrac[p, s, d]) * sum( M.V_FlexAnnual[r, p, S_i, S_t, S_v, c] for S_t, S_v in M.commodityUStreamProcess[r, p, c] if S_t in M.tech_annual and S_t in M.tech_flex @@ -892,7 +892,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): # For other techs, it would be redundant as in = out / eff stored = sum( M.V_FlowIn[r, p, S_s, S_d, c, S_t, S_v, S_o] - for S_s in M.time_season + for S_s in M.TimeSeason[p] for S_d in M.time_of_day for S_t, S_v in M.commodityDStreamProcess[r, p, c] if S_t in M.tech_storage @@ -901,7 +901,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): consumed = sum( M.V_FlowOut[r, p, S_s, S_d, c, S_t, S_v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, c, S_t, S_v, S_o) - for S_s in M.time_season + for S_s in M.TimeSeason[p] for S_d in M.time_of_day for S_t, S_v in M.commodityDStreamProcess[r, p, c] if S_t not in M.tech_storage and S_t not in M.tech_annual @@ -918,7 +918,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): # Includes output from storage produced = sum( M.V_FlowOut[r, p, S_s, S_d, S_i, S_t, S_v, c] - for S_s in M.time_season + for S_s in M.TimeSeason[p] for S_d in M.time_of_day for S_t, S_v in M.commodityUStreamProcess[r, p, c] if S_t not in M.tech_annual @@ -938,7 +938,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): exported = sum( M.V_FlowOut[r + '-' + S_r, p, S_s, S_d, c, S_t, S_v, S_o] / get_variable_efficiency(M, r + '-' + S_r, p, S_s, S_d, c, S_t, S_v, S_o) - for S_s in M.time_season + for S_s in M.TimeSeason[p] for S_d in M.time_of_day for S_r, S_t, S_v, S_o in M.exportRegions[r, p, c] ) @@ -948,7 +948,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): if (r, p, c) in M.importRegions: imported = sum( M.V_FlowOut[S_r + '-' + r, p, S_s, S_d, S_i, S_t, S_v, c] - for S_s in M.time_season + for S_s in M.TimeSeason[p] for S_d in M.time_of_day for S_r, S_t, S_v, S_i in M.importRegions[r, p, c] ) @@ -958,7 +958,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): if c in M.flex_commodities: flex_waste = sum( M.V_Flex[r, p, S_s, S_d, S_i, S_t, S_v, c] - for S_s in M.time_season + for S_s in M.TimeSeason[p] for S_d in M.time_of_day for S_t, S_v in M.commodityUStreamProcess[r, p, c] if S_t not in M.tech_annual and S_t in M.tech_flex @@ -1018,7 +1018,7 @@ def ResourceExtraction_Constraint(M: 'TemoaModel', reg, p, r): collected = sum( M.V_FlowOut[reg, p, S_s, S_d, S_i, S_t, S_v, r] # is r the input or the output!? for S_i, S_t, S_v in M.processByPeriodAndOutput.keys() - for S_s in M.time_season + for S_s in M.TimeSeason[p] for S_d in M.time_of_day ) except KeyError: @@ -1095,7 +1095,7 @@ def BaseloadDiurnal_Constraint(M: 'TemoaModel', r, p, s, d, t, v): for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - expr = activity_sd * value(M.SegFrac[s, d_0]) == activity_sd_0 * value(M.SegFrac[s, d]) + expr = activity_sd * value(M.SegFrac[p, s, d_0]) == activity_sd_0 * value(M.SegFrac[p, s, d]) return expr @@ -1142,7 +1142,7 @@ def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): stored_energy = charge - discharge - s_next, d_next = M.time_next[s, d] + s_next, d_next = M.time_next[p, s, d] expr = M.V_StorageLevel[r, p, s, d, t, v] + stored_energy == M.V_StorageLevel[r, p, s_next, d_next, t, v] @@ -1185,7 +1185,7 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * (value(M.StorageDuration[r, t]) / 8760) - * M.SegFracPerSeason[s] + * M.SegFracPerSeason[p, s] * 365 * value(M.ProcessLifeFrac[r, p, t, v]) ) @@ -1223,7 +1223,7 @@ def StorageChargeRate_Constraint(M: 'TemoaModel', r, p, s, d, t, v): max_charge = ( M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) - * value(M.SegFrac[s, d]) + * value(M.SegFrac[p, s, d]) * value(M.ProcessLifeFrac[r, p, t, v]) ) @@ -1260,7 +1260,7 @@ def StorageDischargeRate_Constraint(M: 'TemoaModel', r, p, s, d, t, v): max_discharge = ( M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) - * value(M.SegFrac[s, d]) + * value(M.SegFrac[p, s, d]) * value(M.ProcessLifeFrac[r, p, t, v]) ) @@ -1305,7 +1305,7 @@ def StorageThroughput_Constraint(M: 'TemoaModel', r, p, s, d, t, v): max_throughput = ( M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) - * value(M.SegFrac[s, d]) + * value(M.SegFrac[p, s, d]) * value(M.ProcessLifeFrac[r, p, t, v]) ) expr = throughput <= max_throughput @@ -1343,7 +1343,7 @@ def StorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v): M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * (value(M.StorageDuration[r, t]) / 8760) - * M.SegFracPerSeason[s] + * M.SegFracPerSeason[p, s] * 365 * value(M.ProcessLifeFrac[r, p, t, v]) ) @@ -1401,29 +1401,29 @@ def RampUp_Constraint(M: 'TemoaModel', r, p, s, d, t, v): \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampUpDay}} """ - s_next, d_next = M.time_next[s, d] + s_next, d_next = M.time_next[p, s, d] activity_sd = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) / value(M.SegFrac[s, d]) + ) / value(M.SegFrac[p, s, d]) activity_sd_next = sum( M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) / value(M.SegFrac[s_next, d_next]) + ) / value(M.SegFrac[p, s_next, d_next]) - hours_elapsed = 8760 * ( value(M.SegFrac[s, d]) + value(M.SegFrac[s_next, d_next]) ) / 2 - hours_elapsed /= M.SegFracPerSeason[s] * 365 # adjust for how many days this season represents + hours_elapsed = 8760 * ( value(M.SegFrac[p, s, d]) + value(M.SegFrac[p, s_next, d_next]) ) / 2 + hours_elapsed /= M.SegFracPerSeason[p, s] * 365 # adjust for how many days this season represents ramp_fraction = hours_elapsed * value(M.RampUp[r, t]) if ramp_fraction >= 1: msg = ( - "Warning: Hourly ramp up rate ({}, {}) is too large to be constraining from ({}, {}) to ({}, {}). Constraint skipped." + "Warning: Hourly ramp up rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). Constraint skipped." ) - logger.warning(msg.format(r, t, s, d, s_next, d_next)) + logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) return Constraint.Skip activity_increase = activity_sd_next - activity_sd # opposite sign from rampdown @@ -1459,29 +1459,29 @@ def RampDown_Constraint(M: 'TemoaModel', r, p, s, d, t, v): \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampDownDay}} """ - s_next, d_next = M.time_next[s, d] + s_next, d_next = M.time_next[p, s, d] activity_sd = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) / value(M.SegFrac[s, d]) + ) / value(M.SegFrac[p, s, d]) activity_sd_next = sum( M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) / value(M.SegFrac[s_next, d_next]) + ) / value(M.SegFrac[p, s_next, d_next]) - hours_elapsed = 8760 * ( value(M.SegFrac[s, d]) + value(M.SegFrac[s_next, d_next]) ) / 2 - hours_elapsed /= M.SegFracPerSeason[s] * 365 # adjust for how many days this season represents + hours_elapsed = 8760 * ( value(M.SegFrac[p, s, d]) + value(M.SegFrac[p, s_next, d_next]) ) / 2 + hours_elapsed /= M.SegFracPerSeason[p, s] * 365 # adjust for how many days this season represents ramp_fraction = hours_elapsed * value(M.RampDown[r, t]) if ramp_fraction >= 1: msg = ( - "Warning: Hourly ramp down rate ({}, {}) is too large to be constraining from ({}, {}) to ({}, {}). Constraint skipped." + "Warning: Hourly ramp down rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). Constraint skipped." ) - logger.warning(msg.format(r, t, s, d, s_next, d_next)) + logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) return Constraint.Skip activity_decrease = activity_sd - activity_sd_next # opposite sign from rampup @@ -1524,7 +1524,7 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): * value(M.ProcessLifeFrac[r, p, t, v]) * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) - * value(M.SegFrac[s, d]) + * value(M.SegFrac[p, s, d]) for t in M.tech_reserve if (r, p, t) in M.processVintages.keys() for v in M.processVintages[r, p, t] @@ -1556,7 +1556,7 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): * value(M.ProcessLifeFrac[r1r2, p, t, v]) * M.V_Capacity[r1r2, p, t, v] * value(M.CapacityToActivity[r1r2, t]) - * value(M.SegFrac[s, d]) + * value(M.SegFrac[p, s, d]) for t in M.tech_reserve if (r1r2, p, t) in M.processVintages.keys() for v in M.processVintages[r1r2, p, t] @@ -1667,7 +1667,7 @@ def EmissionLimit_Constraint(M: 'TemoaModel', r, p, e): if tmp_e == e and tmp_r == reg and S_t not in M.tech_annual # EmissionsActivity not indexed by p, so make sure (r,p,t,v) combos valid if (reg, p, S_t, S_v) in M.processInputs.keys() - for S_s in M.time_season + for S_s in M.TimeSeason[p] for S_d in M.time_of_day ) @@ -1792,7 +1792,7 @@ def MaxActivity_Constraint(M: 'TemoaModel', r, p, t): for S_v in M.processVintages.get((_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 s in M.TimeSeason[p] for d in M.time_of_day if (_r, p, s, d, S_i, t, S_v, S_o) in M.V_FlowOut ) @@ -1839,13 +1839,13 @@ def MaxSeasonalActivity_Constraint(M: 'TemoaModel', r, p, s, t): # The V_FlowOut variable is scaled by the weights of each representative day. # In order to determine the daily, or "seasonal", flow, the V_FLowOut variable # must be converted back to its un-scaled value. We do this by dividing the - # V_FlowOut value by M.SegFrac[s, d]*365*24. + # V_FlowOut value by M.SegFrac[p, s, d]*365*24. regions = gather_group_regions(M, r) try: activity_rpst = sum( - M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] / (value(M.SegFrac[s, d])*365*24) + M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] / (value(M.SegFrac[p, s, d])*365*24) for _r in regions for S_v in M.processVintages[_r, p, t] for S_i in M.processInputs[_r, p, t, S_v] @@ -1904,7 +1904,7 @@ def MinActivity_Constraint(M: 'TemoaModel', r, p, t): for S_v in M.processVintages.get((_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 s in M.TimeSeason[p] for d in M.time_of_day if (_r, p, s, d, S_i, t, S_v, S_o) in M.V_FlowOut ) @@ -1964,7 +1964,7 @@ def MinSeasonalActivity_Constraint(M: 'TemoaModel', r, p, s, t): try: activity_rpst = sum( - M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] / (value(M.SegFrac[s, d])*365*24) + M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] / (value(M.SegFrac[p, s, d])*365*24) for _r in regions for S_v in M.processVintages[_r, p, t] for S_i in M.processInputs[_r, p, t, S_v] @@ -2019,7 +2019,7 @@ def MinActivityGroup_Constraint(M: 'TemoaModel', r, p, g): for S_v in M.processVintages[_r, p, S_t] for S_i in M.processInputs[_r, p, S_t, S_v] for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut ) @@ -2073,7 +2073,7 @@ def MaxActivityGroup_Constraint(M: 'TemoaModel', r, p, g): for S_v in M.processVintages[_r, p, S_t] for S_i in M.processInputs[_r, p, S_t, S_v] for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut ) @@ -2179,7 +2179,7 @@ def MaxResource_Constraint(M: 'TemoaModel', r, t): 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 s in M.TimeSeason[p] for d in M.time_of_day ) @@ -2352,7 +2352,7 @@ def MinActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): for S_v in M.processVintages.get((_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 s in M.TimeSeason[p] for d in M.time_of_day if (_r, p, s, d, S_i, t, S_v, S_o) in M.V_FlowOut ) @@ -2374,7 +2374,7 @@ def MinActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): for S_v in M.processVintages[_r, p, S_t] for S_i in M.processInputs[_r, p, S_t, S_v] for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut ) @@ -2422,7 +2422,7 @@ def MaxActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): for S_v in M.processVintages.get((_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 s in M.TimeSeason[p] for d in M.time_of_day if (_r, p, s, d, S_i, t, S_v, S_o) in M.V_FlowOut ) @@ -2444,7 +2444,7 @@ def MaxActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): for S_v in M.processVintages[_r, p, S_t] for S_i in M.processInputs[_r, p, S_t, S_v] for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut ) @@ -2696,7 +2696,7 @@ def MinAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o): for _r in regions for S_v in M.processVintages.get((_r, p, t), []) for S_i in M.processInputs[_r, p, t, S_v] - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day if (_r, p, s, d, S_i, t, S_v, o) in M.V_FlowOut ) @@ -2758,7 +2758,7 @@ def MaxAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o): for _r in regions for S_v in M.processVintages.get((_r, p, t), []) for S_i in M.processInputs[_r, p, t, S_v] - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day if (_r, p, s, d, S_i, t, S_v, o) in M.V_FlowOut ) @@ -2838,14 +2838,14 @@ def MinTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v): inp = sum( M.V_FlowOut[r, p, S_s, S_d, i, t, v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) - for S_s in M.time_season + for S_s in M.TimeSeason[p] for S_d in M.time_of_day for S_o in M.processOutputsByInput[r, p, t, v, i] ) total_inp = sum( M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) - for S_s in M.time_season + for S_s in M.TimeSeason[p] for S_d in M.time_of_day for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, i] @@ -2948,7 +2948,7 @@ def MinTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o): out = sum( M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, o] for S_i in M.processInputsByOutput[r, p, t, v, o] - for S_s in M.time_season + for S_s in M.TimeSeason[p] for S_d in M.time_of_day ) @@ -2956,7 +2956,7 @@ def MinTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o): M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] - for S_s in M.time_season + for S_s in M.TimeSeason[p] for S_d in M.time_of_day ) @@ -3019,14 +3019,14 @@ def MaxTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v): inp = sum( M.V_FlowOut[r, p, S_s, S_d, i, t, v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) - for S_s in M.time_season + for S_s in M.TimeSeason[p] for S_d in M.time_of_day for S_o in M.processOutputsByInput[r, p, t, v, i] ) total_inp = sum( M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) - for S_s in M.time_season + for S_s in M.TimeSeason[p] for S_d in M.time_of_day for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, i] @@ -3129,7 +3129,7 @@ def MaxTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o): out = sum( M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, o] for S_i in M.processInputsByOutput[r, p, t, v, o] - for S_s in M.time_season + for S_s in M.TimeSeason[p] for S_d in M.time_of_day ) @@ -3137,7 +3137,7 @@ def MaxTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o): M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] - for S_s in M.time_season + for S_s in M.TimeSeason[p] for S_d in M.time_of_day ) @@ -3155,7 +3155,7 @@ def RenewablePortfolioStandard_Constraint(M: 'TemoaModel', r, p, g): for t in M.tech_group_members[g] for (_t, v) in M.processReservePeriods[r, p] if _t == t - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] @@ -3164,7 +3164,7 @@ def RenewablePortfolioStandard_Constraint(M: 'TemoaModel', r, p, g): total_inp = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] for (t, v) in M.processReservePeriods[r, p] - for s in M.time_season + for s in M.TimeSeason[p] for d in M.time_of_day for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] @@ -3243,8 +3243,12 @@ def ParamLoanAnnualize_rule(M: 'TemoaModel', r, t, v): return annualized_rate -def SegFracPerSeason_rule(M: 'TemoaModel', s): - return sum(value(M.SegFrac[s, S_d]) for S_d in M.time_of_day) +def SegFracPerSeason_rule(M: 'TemoaModel', p, s): + return sum( + value(M.SegFrac[p, s, S_d]) + for S_d in M.time_of_day + if (p, s, S_d) in M.SegFrac.sparse_iterkeys() + ) def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): @@ -3290,12 +3294,6 @@ def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): # To avoid building big many-indexed parameters when they aren't needed - saves memory # Much faster to build a dictionary and check that than check the parameter # indices directly every time - saves build time -def get_demand_distribution(M: 'TemoaModel', r, p, s, d, dem): - if M.demandPeriodDistributions[r, p, dem]: - return value(M.DemandPeriodDistribution[r, p, s, d, dem]) - else: - return value(M.DemandSpecificDistribution[r, s, d, dem]) - def get_variable_efficiency(M: 'TemoaModel', r, p, s, d, i, t, v, o): if M.efficiencyVariables[r, p, i, t, v, o]: return value(M.Efficiency[r, i, t, v, o]) * value(M.EfficiencyVariable[r, p, s, d, i, t, v, o]) From d8d75bb12c355bfcf6a94232f4b7c30bd42533fc Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 14 Mar 2025 08:31:06 -0400 Subject: [PATCH 045/587] Add some index validation to SegFrac --- temoa/temoa_model/temoa_initialize.py | 28 +++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 7600dbcbf..aae159ee5 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -181,11 +181,27 @@ def validate_SegFrac(M: 'TemoaModel'): for p in M.time_optimize: - keys = [ + expected_keys = set( + (p, s, d) + for s in M.TimeSeason[p] + for d in M.time_of_day + ) + keys = set( (_p, s, d) for _p, s, d in M.SegFrac.sparse_iterkeys() if _p == p - ] + ) + + if expected_keys != keys: + extra = keys.difference(expected_keys) + missing = expected_keys.difference(keys) + msg = ( + 'TimeSegmentFraction elements for period {} do not match TimeSeason and TimeOfDay.' + '\n\nIndices missing from TimeSegmentFraction:\n{}' + '\n\nIndices in TimeSegmentFraction missing from TimeSeason/TimeOfDay:\n{}' + ).format(p, missing, extra) + logger.error(msg) + raise Exception(msg) total = sum( M.SegFrac[k] @@ -206,12 +222,12 @@ def validate_SegFrac(M: 'TemoaModel'): items = '\n '.join(fmt % (str(k), v) for k, v in items) msg = ( - 'The values of the SegFrac parameter do not sum to 1 for period {}. ' + 'The values of TimeSegmentFraction do not sum to 1 for period {}. ' 'Each item in SegFrac represents a fraction of a year, so they must ' 'total to 1. Current values:\n {}\n\tsum = {}' - ) - logger.error(msg.format(p, items, total)) - raise Exception(msg.format(p, items, total)) + ).format(p, items, total) + logger.error(msg) + raise Exception(msg) def CheckEfficiencyIndices(M: 'TemoaModel'): From 9a8144bc455e3906638be3de9ac8cbd58842228f Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 14 Mar 2025 09:42:29 -0400 Subject: [PATCH 046/587] Fix new time_season implementation --- .../single_vector_mga/sv_mga_sequencer.py | 2 +- .../temoa_model/exchange_tech_cost_ledger.py | 4 +- temoa/temoa_model/hybrid_loader.py | 8 +-- .../temoa_model/model_checking/validators.py | 6 +- temoa/temoa_model/table_data_puller.py | 8 +-- temoa/temoa_model/temoa_initialize.py | 72 ++++++++++--------- temoa/temoa_model/temoa_model.py | 23 +++--- temoa/temoa_model/temoa_rules.py | 62 ++++++++-------- 8 files changed, 95 insertions(+), 90 deletions(-) diff --git a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py index a8aca3341..3c2aa3e4b 100644 --- a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py +++ b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py @@ -198,7 +198,7 @@ def flow_idxs_from_eac_idx(M: TemoaModel, reitvo: tuple) -> tuple[list[tuple], . for membership later """ r, _, i, t, v, o = reitvo - psd_set = [(p, s, d) for p in M.time_optimize for s in M.time_season for d in M.time_of_day] + psd_set = [(p, s, d) for p in M.time_optimize for s in M.time_season[p] for d in M.time_of_day] flow_idxs = [(r, *psd, i, t, v, o) for psd in psd_set] annual_flow_idxs = [(r, p, i, t, v, o) for p in M.time_optimize] diff --git a/temoa/temoa_model/exchange_tech_cost_ledger.py b/temoa/temoa_model/exchange_tech_cost_ledger.py index 7159adfa3..846f8cc95 100644 --- a/temoa/temoa_model/exchange_tech_cost_ledger.py +++ b/temoa/temoa_model/exchange_tech_cost_ledger.py @@ -94,7 +94,7 @@ def get_use_ratio(self, exporter, importer, period, tech, vintage) -> float: act_dir1 = value( sum( M.V_FlowOut[rr1, period, s, d, S_i, tech, vintage, S_o] - for s in M.time_season + for s in M.time_season[period] for d in M.time_of_day for S_i in M.processInputs[rr1, period, tech, vintage] for S_o in M.processOutputsByInput[rr1, period, tech, vintage, S_i] @@ -103,7 +103,7 @@ def get_use_ratio(self, exporter, importer, period, tech, vintage) -> float: act_dir2 = value( sum( M.V_FlowOut[rr2, period, s, d, S_i, tech, vintage, S_o] - for s in M.time_season + for s in M.time_season[period] for d in M.time_of_day for S_i in M.processInputs[rr2, period, tech, vintage] for S_o in M.processOutputsByInput[rr2, period, tech, vintage, S_i] diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 2179c941d..46c31928e 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -414,20 +414,20 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N raw = cur.execute('SELECT period, season FROM main.TimeSeason ORDER BY period, sequence').fetchall() for row in raw: load_indexed_set( - M.TimeSeason, + M.time_season, index_value=row[0], element=row[1] ) - load_element(M.time_season, [(row[1],) for row in raw]) + load_element(M.time_season_all, [(row[1],) for row in raw]) else: for period in time_optimize: load_indexed_set( - M.TimeSeason, + M.time_season, index_value=period, element='S' ) logger.warning('No TimeSeason table found. Loading a single filler season "S" (assume this is an annual model)') - load_element(M.time_season, [('S',)]) + load_element(M.time_season_all, [('S',)]) # StateSequencing raw = cur.execute("SELECT value from MetaData WHERE element == 'state_sequencing'").fetchall() diff --git a/temoa/temoa_model/model_checking/validators.py b/temoa/temoa_model/model_checking/validators.py index 28cf59ff3..78fcd5220 100644 --- a/temoa/temoa_model/model_checking/validators.py +++ b/temoa/temoa_model/model_checking/validators.py @@ -253,7 +253,7 @@ def emission_limit_param_check(M: 'TemoaModel', val, rg, p, e) -> bool: return all((region_group_check(M, rg), p in M.time_optimize, e in M.commodity_emissions)) -def validate_CapacityFactorProcess(M: 'TemoaModel', val, r, s, d, t, v) -> bool: +def validate_CapacityFactorProcess(M: 'TemoaModel', val, r, p, s, d, t, v) -> bool: """ validate the rsdtv index :param val: the parameter value @@ -267,10 +267,12 @@ def validate_CapacityFactorProcess(M: 'TemoaModel', val, r, s, d, t, v) -> bool: """ # devnote: CapacityFactorProcess can be a BIG table and most of these seem redundant # when they're already enforced by the domain of the parameter + # Doesn't seem worth the compute time return all( ( r in M.regions, - s in M.time_season, + p in M.time_optimize, + s in M.time_season[p], d in M.time_of_day, t in M.tech_with_capacity, v in M.vintage_all, diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index 2ebd765b1..21c365ab8 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -180,7 +180,7 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl # basic annual flows for r, p, i, t, v, o in M.V_FlowOutAnnual: - for s in M.TimeSeason[p]: + for s in M.time_season[p]: for d in M.time_of_day: fi = FI(r, p, s, d, i, t, v, o) flow = value(M.V_FlowOutAnnual[r, p, i, t, v, o]) * value(M.SegFrac[s, d]) @@ -192,7 +192,7 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl # flex annual for r, p, i, t, v, o in M.V_FlexAnnual: - for s in M.TimeSeason[p]: + for s in M.time_season[p]: for d in M.time_of_day: fi = FI(r, p, s, d, i, t, v, o) flow = value(M.V_FlexAnnual[r, p, i, t, v, o]) * value(M.SegFrac[s, d]) @@ -340,7 +340,7 @@ def poll_cost_results( value(M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o]) for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] - for S_s in M.TimeSeason[p] + for S_s in M.time_season[p] for S_d in M.time_of_day ) else: @@ -462,7 +462,7 @@ def poll_emissions( normal = [ (r, p, e, s, d, i, t, v, o) for (r, p, e, i, t, v, o) in base - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day if t not in M.tech_annual ] diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index aae159ee5..c4e3860bc 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -183,7 +183,7 @@ def validate_SegFrac(M: 'TemoaModel'): expected_keys = set( (p, s, d) - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day ) keys = set( @@ -196,9 +196,9 @@ def validate_SegFrac(M: 'TemoaModel'): extra = keys.difference(expected_keys) missing = expected_keys.difference(keys) msg = ( - 'TimeSegmentFraction elements for period {} do not match TimeSeason and TimeOfDay.' + 'TimeSegmentFraction elements for period {} do not match time_season and TimeOfDay.' '\n\nIndices missing from TimeSegmentFraction:\n{}' - '\n\nIndices in TimeSegmentFraction missing from TimeSeason/TimeOfDay:\n{}' + '\n\nIndices in TimeSegmentFraction missing from time_season/TimeOfDay:\n{}' ).format(p, missing, extra) logger.error(msg) raise Exception(msg) @@ -299,7 +299,7 @@ def CheckEfficiencyVariable(M: 'TemoaModel'): # Check if all possible values have been set as variable # log a warning if some are missing (allowed but maybe accidental) - num_seg = len(M.TimeSeason[p]) * len(M.time_of_day) + num_seg = len(M.time_season[p]) * len(M.time_of_day) for (r, p, i, t, v, o), count in count_rpitvo.items(): if count > 0: @@ -334,7 +334,7 @@ def CheckCapacityFactorProcess(M: 'TemoaModel'): # Check if all possible values have been set by process # log a warning if some are missing (allowed but maybe accidental) - num_seg = len(M.TimeSeason[p]) * len(M.time_of_day) + num_seg = len(M.time_season[p]) * len(M.time_of_day) for (r, p, t, v), count in count_rptv.items(): if count > 0: M.capacityFactorProcesses[r, p, t, v] = True @@ -362,7 +362,7 @@ def CreateCapacityFactors(M: 'TemoaModel'): all_cfs = set( (r, s, d, t, v) - for (r, t, v), s, d in cross_product(processes, M.TimeSeason[p], M.time_of_day) + for (r, t, v), s, d in cross_product(processes, M.time_season[p], M.time_of_day) ) # Step 2 @@ -459,6 +459,8 @@ def CreateDemands(M: 'TemoaModel'): logger.warning(msg.format(dem)) SE.write(msg.format(dem)) + # devnote: DDD just clones SegFrac. Unless we want to specify it in the database, + # makes sense to just use SegFrac directly # Step 2: Build the demand default distribution (= segfrac) # DDD = M.DemandDefaultDistribution # Shorter, for us lazy programmer types # unset_defaults = set(M.SegFrac.sparse_iterkeys()) @@ -509,7 +511,7 @@ def CreateDemands(M: 'TemoaModel'): if unset_demand_distributions: for p in M.time_optimize: unset_distributions = set( - cross_product(M.regions, (p,), M.TimeSeason[p], M.time_of_day, unset_demand_distributions) + cross_product(M.regions, (p,), M.time_season[p], M.time_of_day, unset_demand_distributions) ) for r, p, s, d, dem in unset_distributions: DSD[r, p, s, d, dem] = M.SegFrac[p, s, d] # DSD._constructed = True @@ -518,7 +520,7 @@ def CreateDemands(M: 'TemoaModel'): # Also check that all keys are made... The demand distro should be supported # by the full set of (r, p, dem) keys because it is an equality constraint # and we need to ensure even the zeros are passed in - expected_key_length = len(M.TimeSeason[p]) * len(M.time_of_day) + expected_key_length = len(M.time_season[p]) * len(M.time_of_day) used_rp_dems = set((r, p, dem) for r, p, dem in M.Demand.sparse_iterkeys()) for r, p, dem in used_rp_dems: keys = [ @@ -530,7 +532,7 @@ def CreateDemands(M: 'TemoaModel'): # this could be very slow but only calls when there's a problem missing = set( (s, d) - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day if (r, p, s, d, dem) not in keys ) @@ -945,7 +947,7 @@ def CreateSparseDicts(M: 'TemoaModel'): for v in M.processVintages[r, p, t] for i in M.processInputs[r, p, t, v] for o in M.processOutputsByInput[r, p, t, v, i] - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day ) @@ -965,7 +967,7 @@ def CreateSparseDicts(M: 'TemoaModel'): for v in M.processVintages[r, p, t] for i in M.processInputs[r, p, t, v] for o in M.processOutputsByInput[r, p, t, v, i] - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day ) @@ -985,7 +987,7 @@ def CreateSparseDicts(M: 'TemoaModel'): for v in M.processVintages[r, p, t] for i in M.processInputs[r, p, t, v] for o in M.processOutputsByInput[r, p, t, v, i] - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day ) @@ -995,7 +997,7 @@ def CreateSparseDicts(M: 'TemoaModel'): for v in M.curtailmentVintages[r, p, t] for i in M.processInputs[r, p, t, v] for o in M.processOutputsByInput[r, p, t, v, i] - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day ) @@ -1039,7 +1041,7 @@ def CreateSparseDicts(M: 'TemoaModel'): (r, p, s, d, t, v) for r, p, t in M.storageVintages.keys() for v in M.storageVintages[r, p, t] - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day ) @@ -1053,12 +1055,12 @@ def CreateStateSequence(M: 'TemoaModel'): case 0: msg = 'Looping state each period, chaining between seasons.' for p in M.time_optimize: - for s, d in M.TimeSeason[p] * M.time_of_day: + for s, d in M.time_season[p] * M.time_of_day: M.time_next[p, s, d] = loop_period_next_timeslice(M, p, s, d) case 1: msg = 'Looping state each season.' for p in M.time_optimize: - for s, d in M.TimeSeason[p] * M.time_of_day: + for s, d in M.time_season[p] * M.time_of_day: M.time_next[p, s, d] = loop_season_next_timeslice(M, p, s, d) msg += (' This behaviour can be changed using the' @@ -1082,7 +1084,7 @@ def CapacityFactorProcessIndices(M: 'TemoaModel'): (r, s, d, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys() for p in M.time_optimize - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day ) @@ -1094,7 +1096,7 @@ def CapacityFactorTechIndices(M: 'TemoaModel'): all_cfs = set( (r, s, d, t) for p in M.time_optimize - for (r, t, v), s, d in cross_product(processes, M.TimeSeason[p], M.time_of_day) + for (r, t, v), s, d in cross_product(processes, M.time_season[p], M.time_of_day) ) return all_cfs @@ -1273,7 +1275,7 @@ def CapacityConstraintIndices(M: 'TemoaModel'): for r, p, t, v in M.activeActivity_rptv if t not in M.tech_annual if t not in M.tech_uncap - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day ) @@ -1288,7 +1290,7 @@ def LinkedTechConstraintIndices(M: 'TemoaModel'): if (r, p, t) in M.processVintages.keys() for v in M.processVintages[r, p, t] if (r, p, t, v) in M.activeActivity_rptv - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day ) @@ -1349,7 +1351,7 @@ def DemandActivityConstraintIndices(M: 'TemoaModel'): for r, p, dem in anchor_season_tod: found_flag = False s0, d0 = None, None - for s0, d0 in ((ss, dd) for ss in M.TimeSeason[p] for dd in M.time_of_day): + for s0, d0 in ((ss, dd) for ss in M.time_season[p] for dd in M.time_of_day): if (r, p, s0, d0, dem) in M.DemandSpecificDistribution.sparse_iterkeys(): if value(M.DemandSpecificDistribution[r, p, s0, d0, dem]) >= appreciable_size: found_flag = True @@ -1371,7 +1373,7 @@ def DemandActivityConstraintIndices(M: 'TemoaModel'): for r, p, dem in anchor_season_tod: s0, d0 = anchor_season_tod[r, p, dem] for t, v in viable_tech_vintage[r, p, dem]: - for s in M.TimeSeason[p]: + for s in M.time_season[p]: for d in M.time_of_day: if s != s0 or d != d0: yield r, p, s, d, t, v, dem, s0, d0 @@ -1381,7 +1383,7 @@ def DemandConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, s, d, dem) for r, p, dem in M.Demand.sparse_iterkeys() - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day ) @@ -1393,7 +1395,7 @@ def BaseloadDiurnalConstraintIndices(M: 'TemoaModel'): (r, p, s, d, t, v) for r, p, t in M.baseloadVintages.keys() for v in M.baseloadVintages[r, p, t] - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day ) @@ -1419,7 +1421,7 @@ def CommodityBalanceConstraintIndices(M: 'TemoaModel'): # r in this line includes interregional transfer combinations (not needed). if r in M.regions # this line ensures only the regions are included. and c not in M.commodity_annual - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day ) @@ -1444,7 +1446,7 @@ def RampUpConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, s, d, t, v) for r, p, t in M.rampUpVintages.keys() - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day for v in M.rampUpVintages[r, p, t] ) @@ -1456,7 +1458,7 @@ def RampDownConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, s, d, t, v) for r, p, t in M.rampDownVintages.keys() - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day for v in M.rampDownVintages[r, p, t] ) @@ -1469,7 +1471,7 @@ def ReserveMarginIndices(M: 'TemoaModel'): (r, p, s, d) for r in M.regions for p in M.time_optimize - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day ) return indices @@ -1481,7 +1483,7 @@ def MinTechInputSplitConstraintIndices(M: 'TemoaModel'): for r, p, i, t in M.minInputSplitVintages.keys() if t not in M.tech_annual for v in M.minInputSplitVintages[r, p, i, t] - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day ) ann_indices = set( @@ -1526,7 +1528,7 @@ def MinTechOutputSplitConstraintIndices(M: 'TemoaModel'): for r, p, t, o in M.minOutputSplitVintages.keys() if t not in M.tech_annual for v in M.minOutputSplitVintages[r, p, t, o] - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day ) ann_indices = set( @@ -1571,7 +1573,7 @@ def MaxTechInputSplitConstraintIndices(M: 'TemoaModel'): for r, p, i, t in M.maxInputSplitVintages.keys() if t not in M.tech_annual for v in M.maxInputSplitVintages[r, p, i, t] - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day ) ann_indices = set( @@ -1616,7 +1618,7 @@ def MaxTechOutputSplitConstraintIndices(M: 'TemoaModel'): for r, p, t, o in M.maxOutputSplitVintages.keys() if t not in M.tech_annual for v in M.maxOutputSplitVintages[r, p, t, o] - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day ) ann_indices = set( @@ -1669,15 +1671,15 @@ def loop_period_next_timeslice(M: 'TemoaModel', p, s, d) -> tuple[str, str]: # Final time slice of final season (end of period) # Loop state back to initial state of first season # Loop the period - if s == M.TimeSeason[p][-1] and d == M.time_of_day.last(): - s_next = M.TimeSeason[p][0] + if s == M.time_season[p].last() and d == M.time_of_day.last(): + s_next = M.time_season[p].first() d_next = M.time_of_day.first() # Last time slice of any season that is NOT the last season # Carry state to initial state of next season # Carry state between seasons elif d == M.time_of_day.last(): - s_next = M.TimeSeason[p][M.TimeSeason[p].index(s)+1] + s_next = M.time_season[p].next(s) d_next = M.time_of_day.first() # Any other time slice diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index b12fe2abb..0ec2560de 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -153,7 +153,8 @@ def __init__(M, *args, **kwargs): M.validate_time = BuildAction(rule=validate_time) # Define the model time slices - M.time_season = Set(ordered=True, validate=no_slash_or_pipe) + M.time_season_all = Set(ordered=True, validate=no_slash_or_pipe) + M.time_season = Set(M.time_optimize, within=M.time_season_all, ordered=True) M.time_of_day = Set(ordered=True, validate=no_slash_or_pipe) # Define regions @@ -232,17 +233,17 @@ def __init__(M, *args, **kwargs): M.GlobalDiscountRate = Param(default=0.05) # Define time-related parameters - M.TimeSeason = Param(M.time_optimize) M.PeriodLength = Param(M.time_optimize, initialize=ParamPeriodLength) - M.SegFrac = Param(M.time_optimize, M.time_season, M.time_of_day) + M.SegFrac = Param(M.time_optimize, M.time_season_all, M.time_of_day) M.validate_SegFrac = BuildAction(rule=validate_SegFrac) M.StateSequencing = Param(default=0) # How do states carry between time segments? # Define demand- and resource-related parameters # Dev Note: There does not appear to be a DB table supporting DemandDefaultDistro. This does not # cause any problems, so let it be for now. + # Doesn't seem to be much point in the table. Just clones SegFrac # M.DemandDefaultDistribution = Param(M.time_optimize, M.time_season, M.time_of_day, mutable=True) - M.DemandSpecificDistribution = Param(M.regions, M.time_optimize, M.time_season, M.time_of_day, M.commodity_demand, mutable=True, default=0) + M.DemandSpecificDistribution = Param(M.regions, M.time_optimize, M.time_season_all, M.time_of_day, M.commodity_demand, mutable=True, default=0) M.Demand = Param(M.regions, M.time_optimize, M.commodity_demand) M.initialize_Demands = BuildAction(rule=CreateDemands) @@ -277,7 +278,7 @@ def __init__(M, *args, **kwargs): M.EfficiencyVariable = Param( M.regionalIndices, M.time_optimize, - M.time_season, + M.time_season_all, M.time_of_day, M.commodity_physical, M.tech_all, @@ -295,13 +296,13 @@ def __init__(M, *args, **kwargs): M.CapacityFactorProcess = Param( M.regionalIndices, M.time_optimize, - M.time_season, + M.time_season_all, M.time_of_day, M.tech_with_capacity, M.vintage_all, - # validate=validate_CapacityFactorProcess, + # validate=validate_CapacityFactorProcess, # opting for a quicker validation, just 0->1 validate=validate_0to1, - default=get_default_capacity_factor, # surprisingly slow but only called if value is missing + default=get_default_capacity_factor, # surprisingly slow but only called if a value is missing ) M.LifetimeTech = Param( @@ -409,12 +410,12 @@ def __init__(M, *args, **kwargs): M.MinActivity = Param(M.MinActivityConstraint_rpt) M.MaxSeasonalActivityConstraint_rpst = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.time_season * M.tech_all + within=M.regionalGlobalIndices * M.time_optimize * M.time_season_all * M.tech_all ) M.MaxSeasonalActivity = Param(M.MaxSeasonalActivityConstraint_rpst) M.MinSeasonalActivityConstraint_rpst = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.time_season * M.tech_all + within=M.regionalGlobalIndices * M.time_optimize * M.time_season_all * M.tech_all ) M.MinSeasonalActivity = Param(M.MinSeasonalActivityConstraint_rpst) @@ -663,7 +664,7 @@ def __init__(M, *args, **kwargs): # We make use of this following set in some of the storage constraints. # Pre-computing it is considerably faster. - M.SegFracPerSeason = Param(M.time_optimize, M.time_season, initialize=SegFracPerSeason_rule) + M.SegFracPerSeason = Param(M.time_optimize, M.time_season_all, initialize=SegFracPerSeason_rule) M.StorageEnergyConstraint = Constraint( M.StorageConstraints_rpsdtv, rule=StorageEnergy_Constraint diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 216cd0875..c1f10613c 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -504,7 +504,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): if S_p == p and S_t not in M.tech_annual for S_i in M.processInputs[r, S_p, S_t, S_v] for S_o in M.processOutputsByInput[r, S_p, S_t, S_v, S_i] - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day ) @@ -546,7 +546,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): normal = [ (r, p, e, s, d, i, t, v, o) for (r, p, e, i, t, v, o) in base - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day if t not in M.tech_annual ] @@ -892,7 +892,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): # For other techs, it would be redundant as in = out / eff stored = sum( M.V_FlowIn[r, p, S_s, S_d, c, S_t, S_v, S_o] - for S_s in M.TimeSeason[p] + for S_s in M.time_season[p] for S_d in M.time_of_day for S_t, S_v in M.commodityDStreamProcess[r, p, c] if S_t in M.tech_storage @@ -901,7 +901,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): consumed = sum( M.V_FlowOut[r, p, S_s, S_d, c, S_t, S_v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, c, S_t, S_v, S_o) - for S_s in M.TimeSeason[p] + for S_s in M.time_season[p] for S_d in M.time_of_day for S_t, S_v in M.commodityDStreamProcess[r, p, c] if S_t not in M.tech_storage and S_t not in M.tech_annual @@ -918,7 +918,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): # Includes output from storage produced = sum( M.V_FlowOut[r, p, S_s, S_d, S_i, S_t, S_v, c] - for S_s in M.TimeSeason[p] + for S_s in M.time_season[p] for S_d in M.time_of_day for S_t, S_v in M.commodityUStreamProcess[r, p, c] if S_t not in M.tech_annual @@ -938,7 +938,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): exported = sum( M.V_FlowOut[r + '-' + S_r, p, S_s, S_d, c, S_t, S_v, S_o] / get_variable_efficiency(M, r + '-' + S_r, p, S_s, S_d, c, S_t, S_v, S_o) - for S_s in M.TimeSeason[p] + for S_s in M.time_season[p] for S_d in M.time_of_day for S_r, S_t, S_v, S_o in M.exportRegions[r, p, c] ) @@ -948,7 +948,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): if (r, p, c) in M.importRegions: imported = sum( M.V_FlowOut[S_r + '-' + r, p, S_s, S_d, S_i, S_t, S_v, c] - for S_s in M.TimeSeason[p] + for S_s in M.time_season[p] for S_d in M.time_of_day for S_r, S_t, S_v, S_i in M.importRegions[r, p, c] ) @@ -958,7 +958,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): if c in M.flex_commodities: flex_waste = sum( M.V_Flex[r, p, S_s, S_d, S_i, S_t, S_v, c] - for S_s in M.TimeSeason[p] + for S_s in M.time_season[p] for S_d in M.time_of_day for S_t, S_v in M.commodityUStreamProcess[r, p, c] if S_t not in M.tech_annual and S_t in M.tech_flex @@ -1018,7 +1018,7 @@ def ResourceExtraction_Constraint(M: 'TemoaModel', reg, p, r): collected = sum( M.V_FlowOut[reg, p, S_s, S_d, S_i, S_t, S_v, r] # is r the input or the output!? for S_i, S_t, S_v in M.processByPeriodAndOutput.keys() - for S_s in M.TimeSeason[p] + for S_s in M.time_season[p] for S_d in M.time_of_day ) except KeyError: @@ -1667,7 +1667,7 @@ def EmissionLimit_Constraint(M: 'TemoaModel', r, p, e): if tmp_e == e and tmp_r == reg and S_t not in M.tech_annual # EmissionsActivity not indexed by p, so make sure (r,p,t,v) combos valid if (reg, p, S_t, S_v) in M.processInputs.keys() - for S_s in M.TimeSeason[p] + for S_s in M.time_season[p] for S_d in M.time_of_day ) @@ -1792,7 +1792,7 @@ def MaxActivity_Constraint(M: 'TemoaModel', r, p, t): for S_v in M.processVintages.get((_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.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day if (_r, p, s, d, S_i, t, S_v, S_o) in M.V_FlowOut ) @@ -1904,7 +1904,7 @@ def MinActivity_Constraint(M: 'TemoaModel', r, p, t): for S_v in M.processVintages.get((_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.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day if (_r, p, s, d, S_i, t, S_v, S_o) in M.V_FlowOut ) @@ -2019,7 +2019,7 @@ def MinActivityGroup_Constraint(M: 'TemoaModel', r, p, g): for S_v in M.processVintages[_r, p, S_t] for S_i in M.processInputs[_r, p, S_t, S_v] for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut ) @@ -2073,7 +2073,7 @@ def MaxActivityGroup_Constraint(M: 'TemoaModel', r, p, g): for S_v in M.processVintages[_r, p, S_t] for S_i in M.processInputs[_r, p, S_t, S_v] for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut ) @@ -2179,7 +2179,7 @@ def MaxResource_Constraint(M: 'TemoaModel', r, t): 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.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day ) @@ -2352,7 +2352,7 @@ def MinActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): for S_v in M.processVintages.get((_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.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day if (_r, p, s, d, S_i, t, S_v, S_o) in M.V_FlowOut ) @@ -2374,7 +2374,7 @@ def MinActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): for S_v in M.processVintages[_r, p, S_t] for S_i in M.processInputs[_r, p, S_t, S_v] for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut ) @@ -2422,7 +2422,7 @@ def MaxActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): for S_v in M.processVintages.get((_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.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day if (_r, p, s, d, S_i, t, S_v, S_o) in M.V_FlowOut ) @@ -2444,7 +2444,7 @@ def MaxActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): for S_v in M.processVintages[_r, p, S_t] for S_i in M.processInputs[_r, p, S_t, S_v] for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut ) @@ -2696,7 +2696,7 @@ def MinAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o): for _r in regions for S_v in M.processVintages.get((_r, p, t), []) for S_i in M.processInputs[_r, p, t, S_v] - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day if (_r, p, s, d, S_i, t, S_v, o) in M.V_FlowOut ) @@ -2758,7 +2758,7 @@ def MaxAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o): for _r in regions for S_v in M.processVintages.get((_r, p, t), []) for S_i in M.processInputs[_r, p, t, S_v] - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day if (_r, p, s, d, S_i, t, S_v, o) in M.V_FlowOut ) @@ -2838,14 +2838,14 @@ def MinTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v): inp = sum( M.V_FlowOut[r, p, S_s, S_d, i, t, v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) - for S_s in M.TimeSeason[p] + for S_s in M.time_season[p] for S_d in M.time_of_day for S_o in M.processOutputsByInput[r, p, t, v, i] ) total_inp = sum( M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) - for S_s in M.TimeSeason[p] + for S_s in M.time_season[p] for S_d in M.time_of_day for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, i] @@ -2948,7 +2948,7 @@ def MinTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o): out = sum( M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, o] for S_i in M.processInputsByOutput[r, p, t, v, o] - for S_s in M.TimeSeason[p] + for S_s in M.time_season[p] for S_d in M.time_of_day ) @@ -2956,7 +2956,7 @@ def MinTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o): M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] - for S_s in M.TimeSeason[p] + for S_s in M.time_season[p] for S_d in M.time_of_day ) @@ -3019,14 +3019,14 @@ def MaxTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v): inp = sum( M.V_FlowOut[r, p, S_s, S_d, i, t, v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) - for S_s in M.TimeSeason[p] + for S_s in M.time_season[p] for S_d in M.time_of_day for S_o in M.processOutputsByInput[r, p, t, v, i] ) total_inp = sum( M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) - for S_s in M.TimeSeason[p] + for S_s in M.time_season[p] for S_d in M.time_of_day for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, i] @@ -3129,7 +3129,7 @@ def MaxTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o): out = sum( M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, o] for S_i in M.processInputsByOutput[r, p, t, v, o] - for S_s in M.TimeSeason[p] + for S_s in M.time_season[p] for S_d in M.time_of_day ) @@ -3137,7 +3137,7 @@ def MaxTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o): M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] - for S_s in M.TimeSeason[p] + for S_s in M.time_season[p] for S_d in M.time_of_day ) @@ -3155,7 +3155,7 @@ def RenewablePortfolioStandard_Constraint(M: 'TemoaModel', r, p, g): for t in M.tech_group_members[g] for (_t, v) in M.processReservePeriods[r, p] if _t == t - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] @@ -3164,7 +3164,7 @@ def RenewablePortfolioStandard_Constraint(M: 'TemoaModel', r, p, g): total_inp = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] for (t, v) in M.processReservePeriods[r, p] - for s in M.TimeSeason[p] + for s in M.time_season[p] for d in M.time_of_day for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] From 9b57268cbaf21f36fb4625e95870df08f71d98df Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 14 Mar 2025 14:21:23 -0400 Subject: [PATCH 047/587] Add v3.1 schema and database migrator --- data_files/example_dbs/utopia.sql | 2 +- data_files/temoa_schema_v3_1.sql | 1083 ++++++++++++++++++++ temoa/temoa_model/hybrid_loader.py | 14 +- temoa/temoa_model/temoa_model.py | 10 +- temoa/utilities/db_migration_v3_to_v3_1.py | 288 ++++++ 5 files changed, 1388 insertions(+), 9 deletions(-) create mode 100644 data_files/temoa_schema_v3_1.sql create mode 100644 temoa/utilities/db_migration_v3_to_v3_1.py diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 7e5ed1042..3fef621b8 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -429,7 +429,7 @@ CREATE TABLE DemandSpecificDistribution demand_name TEXT REFERENCES Commodity (name), dsd REAL, - dsd_notes TEXT, + notes TEXT, PRIMARY KEY (region, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql new file mode 100644 index 000000000..59889abb3 --- /dev/null +++ b/data_files/temoa_schema_v3_1.sql @@ -0,0 +1,1083 @@ +PRAGMA foreign_keys= OFF; +BEGIN TRANSACTION; + +CREATE TABLE IF NOT EXISTS MetaData +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +REPLACE INTO MetaData +VALUES ('myopic_base_year', 2000, 'Base Year for Myopic Analysis'); +REPLACE INTO MetaData +VALUES ('DB_MAJOR', 3, 'DB major version number'); +REPLACE INTO MetaData +VALUES ('DB_MINOR', 0, 'DB minor version number'); + +CREATE TABLE IF NOT EXISTS MetaDataReal +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +REPLACE INTO MetaDataReal +VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); +REPLACE INTO MetaDataReal +VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in LoanRate table'); + +CREATE TABLE IF NOT EXISTS OutputDualVariable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE IF NOT EXISTS OutputObjective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE IF NOT EXISTS SectorLabel +( + sector TEXT, + PRIMARY KEY (sector) +); + +CREATE TABLE IF NOT EXISTS CapacityCredit +( + region TEXT, + period INTEGER, + tech TEXT, + vintage INTEGER, + credit REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage), + CHECK (credit >= 0 AND credit <= 1) +); +CREATE TABLE IF NOT EXISTS CapacityFactorProcess +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS CapacityFactorTech +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS CapacityToActivity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + c2a REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS Commodity +( + name TEXT + PRIMARY KEY, + flag TEXT + REFERENCES CommodityType (label), + description TEXT +); +CREATE TABLE IF NOT EXISTS CommodityType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO CommodityType +VALUES ('p', 'physical commodity'); +REPLACE INTO CommodityType +VALUES ('a', 'annual commodity'); +REPLACE INTO CommodityType +VALUES ('e', 'emissions commodity'); +REPLACE INTO CommodityType +VALUES ('d', 'demand commodity'); +REPLACE INTO CommodityType +VALUES ('s', 'source commodity'); + +CREATE TABLE IF NOT EXISTS CostEmission +( + region TEXT + REFERENCES Region (region), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT NOT NULL + REFERENCES Commodity (name), + cost REAL NOT NULL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE IF NOT EXISTS CostFixed +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS CostInvest +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS CostVariable +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS Demand +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + commodity TEXT + REFERENCES Commodity (name), + demand REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, commodity) +); +CREATE TABLE IF NOT EXISTS DemandSpecificDistribution +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + demand_name TEXT + REFERENCES Commodity (name), + dsd REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), + CHECK (dsd >= 0 AND dsd <= 1) +); +CREATE TABLE IF NOT EXISTS LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS Efficiency +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE IF NOT EXISTS EfficiencyVariable +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE IF NOT EXISTS EmissionActivity +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS EmissionEmbodied +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS ExistingCapacity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS TechGroup +( + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE IF NOT EXISTS GrowthRateMax +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS GrowthRateSeed +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + seed REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS LoanLifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS LifetimeProcess +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS LifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE IF NOT EXISTS MaxActivity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + max_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE IF NOT EXISTS MaxCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + max_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE IF NOT EXISTS MaxResource +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + max_res REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS MinActivity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + min_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE IF NOT EXISTS MaxCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + max_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE IF NOT EXISTS MinCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + min_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE IF NOT EXISTS MinCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + min_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE IF NOT EXISTS OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputFlowOut +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS PlanningReserveMargin +( + region TEXT + PRIMARY KEY + REFERENCES Region (region), + margin REAL +); +CREATE TABLE IF NOT EXISTS RampDown +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS RampUp +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS Region +( + region TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE IF NOT EXISTS TimeSegmentFraction +( + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + segfrac REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segfrac >= 0 AND segfrac <= 1) +); +CREATE TABLE IF NOT EXISTS StorageDuration +( + region TEXT, + tech TEXT, + duration REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS StorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage) +); +CREATE TABLE IF NOT EXISTS TechnologyType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO TechnologyType +VALUES ('r', 'resource technology'); +REPLACE INTO TechnologyType +VALUES ('p', 'production technology'); +REPLACE INTO TechnologyType +VALUES ('pb', 'baseload production technology'); +REPLACE INTO TechnologyType +VALUES ('ps', 'storage production technology'); + +CREATE TABLE IF NOT EXISTS MinTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE IF NOT EXISTS MinTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE IF NOT EXISTS MinTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE IF NOT EXISTS MinTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE IF NOT EXISTS MaxTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE IF NOT EXISTS MaxTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE IF NOT EXISTS MaxTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE IF NOT EXISTS MaxTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE IF NOT EXISTS TimeOfDay +( + sequence INTEGER UNIQUE, + tod TEXT + PRIMARY KEY +); +CREATE TABLE IF NOT EXISTS TimePeriod +( + sequence INTEGER UNIQUE, + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES TimePeriodType (label) +); +CREATE TABLE IF NOT EXISTS TimeSeason +( + season TEXT + PRIMARY KEY +); +CREATE TABLE IF NOT EXISTS PeriodSeasons +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT + REFERENCES TimeSeason (season), + PRIMARY KEY (period, sequence) +); +CREATE TABLE IF NOT EXISTS TimePeriodType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO TimePeriodType +VALUES('e', 'existing vintages'); +REPLACE INTO TimePeriodType +VALUES('f', 'future'); +CREATE TABLE IF NOT EXISTS MaxActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE IF NOT EXISTS MaxCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE IF NOT EXISTS MaxAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + factor REAL, + source TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS MaxNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + max_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE IF NOT EXISTS MaxNewCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + max_new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE IF NOT EXISTS MaxNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE IF NOT EXISTS MinActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE IF NOT EXISTS MinAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + factor REAL, + source TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS MinCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE IF NOT EXISTS MinNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + min_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE IF NOT EXISTS MinNewCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + min_new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE IF NOT EXISTS MinNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE IF NOT EXISTS OutputEmission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS MinActivityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + min_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE IF NOT EXISTS EmissionLimit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE IF NOT EXISTS MaxActivityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + max_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "min_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); +CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "max_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); +CREATE TABLE IF NOT EXISTS RPSRequirement +( + region TEXT NOT NULL + REFERENCES Region (region), + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech_group TEXT NOT NULL + REFERENCES TechGroup (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE IF NOT EXISTS TechGroupMember +( + group_name TEXT + REFERENCES TechGroup (group_name), + tech TEXT + REFERENCES Technology (tech), + PRIMARY KEY (group_name, tech) +); +CREATE TABLE IF NOT EXISTS Technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + variable INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES TechnologyType (label) +); +CREATE TABLE IF NOT EXISTS OutputCost +( + scenario TEXT, + region TEXT, + period INTEGER, + tech TEXT, + vintage INTEGER, + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES TimePeriod (period), + FOREIGN KEY (tech) REFERENCES Technology (tech) +); +COMMIT; +PRAGMA FOREIGN_KEYS = 1; + + diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 46c31928e..3154c56b1 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -402,16 +402,16 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N logger.warning('No TimeOfDay table found. Loading a single filler time of day "D" (assume this is an annual model)') load_element(M.time_of_day, [('D',)]) - # TimeSeason - if self.table_exists("TimeSeason"): + # PeriodSeasons + if self.table_exists("PeriodSeasons"): if mi: raw = cur.execute( - 'SELECT period, season FROM main.TimeSeason WHERE' + 'SELECT period, season FROM main.PeriodSeasons WHERE' ' period >= ? AND period <= ? ORDER BY period, sequence', (mi.base_year, mi.last_demand_year) ).fetchall() else: - raw = cur.execute('SELECT period, season FROM main.TimeSeason ORDER BY period, sequence').fetchall() + raw = cur.execute('SELECT period, season FROM main.PeriodSeasons ORDER BY period, sequence').fetchall() for row in raw: load_indexed_set( M.time_season, @@ -426,7 +426,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N index_value=period, element='S' ) - logger.warning('No TimeSeason table found. Loading a single filler season "S" (assume this is an annual model)') + logger.warning('No PeriodSeasons table found. Loading a single filler season "S" (assume this is an annual model)') load_element(M.time_season_all, [('S',)]) # StateSequencing @@ -1110,8 +1110,8 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N load_element(M.StorageDuration, raw, self.viable_rt, (0, 1)) # StorageFraction - if self.table_exists('StorageFraction'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tod, tech, vintage, frac FROM main.StorageFraction') + if self.table_exists('StorageLevelFraction'): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tod, tech, vintage, fraction FROM main.StorageLevelFraction') load_element(M.StorageFraction, raw, self.viable_rtv, (0,4,5)) # For T/S: dump the size of all data elements into the log diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 0ec2560de..19eaff930 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -243,7 +243,15 @@ def __init__(M, *args, **kwargs): # cause any problems, so let it be for now. # Doesn't seem to be much point in the table. Just clones SegFrac # M.DemandDefaultDistribution = Param(M.time_optimize, M.time_season, M.time_of_day, mutable=True) - M.DemandSpecificDistribution = Param(M.regions, M.time_optimize, M.time_season_all, M.time_of_day, M.commodity_demand, mutable=True, default=0) + M.DemandSpecificDistribution = Param( + M.regions, + M.time_optimize, + M.time_season_all, + M.time_of_day, + M.commodity_demand, + mutable=True, + default=0 + ) M.Demand = Param(M.regions, M.time_optimize, M.commodity_demand) M.initialize_Demands = BuildAction(rule=CreateDemands) diff --git a/temoa/utilities/db_migration_v3_to_v3_1.py b/temoa/utilities/db_migration_v3_to_v3_1.py new file mode 100644 index 000000000..04ecd9935 --- /dev/null +++ b/temoa/utilities/db_migration_v3_to_v3_1.py @@ -0,0 +1,288 @@ +""" +Tools for Energy Model Optimization and Analysis (Temoa): +An open source framework for energy systems optimization modeling + +Copyright (C) 2015, NC State University + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +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 +received this license file. If not, see . + +Written by: I. D. Elder +iandavidelder@gmail.com +Created on: 2025/03/14 + +Transition a v3.0 database to a v3.1 database. +""" + +import argparse +import sqlite3 +from pathlib import Path + +parser = argparse.ArgumentParser() +parser.add_argument( + '--source', + help='Path to original database', + required=True, + action='store', + dest='source_db', +) +parser.add_argument( + '--schema', + help='Path to schema file (default=../../data_files/temoa_schema_v3_1.sql)', + required=False, + dest='schema', + default='../../data_files/temoa_schema_v3_1.sql', +) +options = parser.parse_args() +legacy_db: Path = Path(options.source_db) +schema_file = Path(options.schema) + +new_db_name = legacy_db.stem + '_v3_1.sqlite' +new_db_path = Path(legacy_db.parent, new_db_name) + +con_old = sqlite3.connect(legacy_db) +con_new = sqlite3.connect(new_db_path) +cur = con_new.cursor() + +# bring in the new schema and execute +with open(schema_file, 'r') as src: + sql_script = src.read() +con_new.executescript(sql_script) + +# turn off FK verification while process executes +con_new.execute('PRAGMA foreign_keys = 0;') + +# table mapping for DIRECT transfers +# fmt: off +direct_transfer_tables = [ + ('', 'CapacityCredit'), + ('', 'CapacityToActivity'), + ('', 'Commodity'), + ('', 'CommodityType'), + ('', 'CostEmission'), + ('', 'CostFixed'), + ('', 'CostInvest'), + ('', 'CostVariable'), + ('', 'Demand'), + ('', 'Efficiency'), + ('', 'EmissionActivity'), + ('', 'EmissionLimit'), + ('', 'ExistingCapacity'), + ('', 'GrowthRateMax'), + ('', 'GrowthRateSeed'), + ('', 'LifetimeProcess'), + ('', 'LifetimeTech'), + ('', 'LinkedTech'), + ('', 'LoanLifetimeTech'), + ('', 'LoanRate'), + ('', 'MaxActivity'), + ('', 'MaxActivityGroup'), + ('', 'MaxActivityShare'), + ('', 'MaxAnnualCapacityFactor'), + ('', 'MaxCapacity'), + ('', 'MaxCapacityGroup'), + ('', 'MaxCapacityShare'), + ('', 'MaxNewCapacity'), + ('', 'MaxNewCapacityGroup'), + ('', 'MaxNewCapacityShare'), + ('', 'MaxResource'), + ('', 'MaxSeasonalActivity'), + ('', 'MetaData'), + ('', 'MetaDataReal'), + ('', 'MinActivity'), + ('', 'MinActivityGroup'), + ('', 'MinActivityShare'), + ('', 'MinAnnualCapacityFactor'), + ('', 'MinCapacity'), + ('', 'MinCapacityGroup'), + ('', 'MinCapacityShare'), + ('', 'MinNewCapacity'), + ('', 'MinNewCapacityGroup'), + ('', 'MinNewCapacityShare'), + ('', 'MinSeasonalActivity'), + ('', 'PlanningReserveMargin'), + ('', 'RampDown'), + ('', 'RampUp'), + ('', 'Region'), + ('', 'RPSRequirement'), + ('', 'SectorLabel'), + ('', 'StorageDuration'), + ('', 'TechGroup'), + ('', 'TechGroupMember'), + ('TechInputSplit', 'MinTechInputSplit'), + ('TechInputSplitAnnual', 'MinTechInputSplitAnnual'), + ('TechInputSplitAverage', 'MinTechInputSplitAnnual'), + ('', 'Technology'), + ('', 'TechnologyType'), + ('TechOutputSplit', 'MinTechOutputSplit'), + ('', 'TimeOfDay'), + ('', 'TimePeriod'), + ('', 'TimePeriodType'), +] + +period_added_tables =[ + ('', 'CapacityFactorProcess'), + ('', 'CapacityFactorTech'), + ('', 'DemandSpecificDistribution'), + ('TimeSeason', 'PeriodSeasons'), + ('', 'TimeSegmentFraction'), +] + +# It wasn't active anyway... can't be bothered +# StorageInit -> StorageFraction + +# TimeSeason +data = con_old.execute('SELECT season FROM TimeSeason ORDER BY sequence').fetchall() +query = 'INSERT OR REPLACE INTO TimeSeason(season) VALUES(?)' +con_new.executemany(query, data) + +# execute the direct transfers +print('\n --- Executing direct transfers ---') +for old_name, new_name in direct_transfer_tables: + if old_name == '': + old_name = new_name + + try: + con_old.execute(f'SELECT * FROM {old_name}').fetchone() + except sqlite3.OperationalError: + print('TABLE NOT FOUND: ' + old_name) + continue + + new_columns = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] + old_columns = [c[1] for c in con_old.execute(f'PRAGMA table_info({old_name});').fetchall()] + + missing = [c for c in new_columns if c not in old_columns] + if len(missing) > 0: + msg = ( + f'Columns of {new_name} in the new database missing from {old_name} in old database. Try adding or renaming the column in the old database:' + f'\n{missing}\n' + ) + raise ValueError(msg) + + print(f'SELECT {str(new_columns)[1:-1].replace("'","")} FROM {old_name}') + data = con_old.execute(f'SELECT {str(new_columns)[1:-1].replace("'","")} FROM {old_name}').fetchall() + + if not data: + print('No data for: ' + old_name) + continue + + # construct the query with correct number of placeholders + num_placeholders = len(data[0]) + placeholders = ','.join(['?' for _ in range(num_placeholders)]) + query = f'INSERT OR REPLACE INTO {new_name} VALUES ({placeholders})' + con_new.executemany(query, data) + print(f'inserted {len(data)} rows into {new_name}') + +# get lifetimes. Major headache but needs to be done +data = cur.execute('SELECT region, tech, lifetime FROM LifetimeTech').fetchall() +lifetime_tech = dict() +for rtl in data: lifetime_tech[rtl[0:2]] = rtl[2] +data = cur.execute('SELECT region, tech, vintage, lifetime FROM LifetimeProcess').fetchall() +lifetime_process = dict() +for rtvl in data: lifetime_tech[rtvl[0:3]] = rtvl[3] + +# add period indexing to seasonal tables +print('\n --- Adding period index to some tables ---') +time_future = cur.execute('SELECT period FROM TimePeriod WHERE flag == "f"').fetchall() +time_optimize = [p[0] for p in time_future[0:-1]] +for old_name, new_name in period_added_tables: + if old_name == '': + old_name = new_name + + try: + con_old.execute(f'SELECT * FROM {old_name}').fetchone() + except sqlite3.OperationalError: + print('TABLE NOT FOUND: ' + old_name) + continue + + new_columns = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] + old_columns = [c[1] for c in con_old.execute(f'PRAGMA table_info({old_name});').fetchall()] + + missing = [c for c in new_columns if c not in old_columns and c != 'period'] + if len(missing) > 0: + msg = ( + f'Columns of {new_name} in the new database missing from {old_name} in old database. Try adding or renaming the column in the old database:' + f'\n{missing}\n' + ) + raise ValueError(msg) + + columns = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall() if c[1] != 'period'] + + print(f'SELECT {str(columns)[1:-1].replace("'","")} FROM {old_name}') + data = con_old.execute(f'SELECT {str(columns)[1:-1].replace("'","")} FROM {old_name}').fetchall() + + if not data: + print('No data for: ' + old_name) + continue + + if 'vintage' in columns: + r = columns.index('region') + t = columns.index('tech') + v = columns.index('vintage') + + data_new = [] + for p in time_optimize: + for row in data: + # Remove infeasible rows + if 'vintage' in columns: + if row[v] > p: continue # v <= p + if (row[r], row[t], row[v]) in lifetime_process: life = lifetime_process[row[r], row[t], row[v]] + elif (row[r], row[t]) in lifetime_tech: life = lifetime_tech[row[r], row[t]] + else: life = 40 # TODO replace by calling default lifetime from TemoaModel + if row[v] + life <= p: continue # v+l > p + + if old_name[0:5] == 'TimeS': # horrible but covers TimeSeason and TimeSegmentFraction + data_new.append((p, *row)) + else: + data_new.append((row[0], p, *row[1::])) + + # construct the query with correct number of placeholders + num_placeholders = len(data_new[0]) + placeholders = ','.join(['?' for _ in range(num_placeholders)]) + query = f'INSERT OR REPLACE INTO {new_name} VALUES ({placeholders})' + con_new.executemany(query, data_new) + print(f'Added period index to {new_name} and inserted {len(data_new)} rows') + + +# state_sequencing parameter +print('\n --- Updating MetaData ---') +cur.execute( + """REPLACE INTO + MetaData(element, value, notes) + VALUES('state_sequencing', 0, '0 = loop periods, 1 = loop seasons')""" +) +print("Added state_sequencing parameter") +# new database version +cur.execute("UPDATE MetaData SET value = 1 WHERE element == 'DB_MINOR'") +print("Updated database version to 3.1") + +print('\n --- Validating foreign keys ---') +con_new.commit() +con_new.execute('VACUUM;') +con_new.execute('PRAGMA FOREIGN_KEYS=1;') +try: + data = con_new.execute('PRAGMA FOREIGN_KEY_CHECK;').fetchall() + if not data: + print('No Foreign Key Failures. (Good news!)') + else: + print('\nFK check fails (MUST BE FIXED):') + print('(Table, Row ID, Reference Table, (fkid) )') + for row in data: + print(row) +except sqlite3.OperationalError as e: + print('Foreign Key Check FAILED on new DB. Something may be wrong with schema.') + print(e) + +con_new.close() +con_old.close() \ No newline at end of file From b8678ecfc7dda1c55210f5b0a654d1e53a2c13c6 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 14 Mar 2025 20:45:32 -0400 Subject: [PATCH 048/587] Some tidy up before updating all databases --- data_files/example_dbs/utopia.sql | 2 +- data_files/temoa_schema_v3_1.sql | 28 +++++++++++++++++++++- temoa/temoa_model/hybrid_loader.py | 4 ++-- temoa/utilities/db_migration_v3_to_v3_1.py | 4 +++- 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 3fef621b8..44de4a156 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -1222,7 +1222,7 @@ CREATE TABLE MinNewCapacityShare REFERENCES Technology (tech), group_name TEXT REFERENCES TechGroup (group_name), - max_proportion REAL, + min_proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, group_name) ); diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index 59889abb3..dd94a8f9d 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -934,10 +934,36 @@ CREATE TABLE IF NOT EXISTS MinNewCapacityShare REFERENCES Technology (tech), group_name TEXT REFERENCES TechGroup (group_name), - max_proportion REAL, + min_proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, group_name) ); +CREATE TABLE IF NOT EXISTS MinNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); +CREATE TABLE IF NOT EXISTS MaxNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); CREATE TABLE IF NOT EXISTS OutputEmission ( scenario TEXT, diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 3154c56b1..9002e443e 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -418,7 +418,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N index_value=row[0], element=row[1] ) - load_element(M.time_season_all, [(row[1],) for row in raw]) + load_element(M.time_season_all, list(set((row[1],) for row in raw))) else: for period in time_optimize: load_indexed_set( @@ -950,7 +950,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # MinNewCapacityShare if self.table_exists('MinNewCapacityShare'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, group_name, max_proportion FROM main.MinNewCapacityShare') + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, group_name, min_proportion FROM main.MinNewCapacityShare') load_element(M.MinNewCapacityShare, raw, self.viable_rt, (0, 2)) # MaxNewCapacityShare diff --git a/temoa/utilities/db_migration_v3_to_v3_1.py b/temoa/utilities/db_migration_v3_to_v3_1.py index 04ecd9935..245c0438a 100644 --- a/temoa/utilities/db_migration_v3_to_v3_1.py +++ b/temoa/utilities/db_migration_v3_to_v3_1.py @@ -39,7 +39,7 @@ ) parser.add_argument( '--schema', - help='Path to schema file (default=../../data_files/temoa_schema_v3_1.sql)', + help='Path to schema file (default=../../data_files/temoa_schema_v3_1)', required=False, dest='schema', default='../../data_files/temoa_schema_v3_1.sql', @@ -110,6 +110,8 @@ ('', 'MinNewCapacity'), ('', 'MinNewCapacityGroup'), ('', 'MinNewCapacityShare'), + ('', 'MinNewCapacityGroupShare'), + ('', 'MaxNewCapacityGroupShare'), ('', 'MinSeasonalActivity'), ('', 'PlanningReserveMargin'), ('', 'RampDown'), From 5b17958c3115f5d6db31f55823b43f9a0eaaab4d Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Sat, 15 Mar 2025 09:50:18 -0400 Subject: [PATCH 049/587] Update most databases to v3.1 --- data_files/example_dbs/test_system.sql | 2733 ++++++++++++-------- data_files/example_dbs/utopia.sql | 732 ++++-- data_files/temoa_basics_0.sql | 1 - data_files/temoa_basics_1.sql | 43 +- data_files/temoa_basics_2.sql | 41 +- data_files/temoa_schema_minimal_v3.sql | 709 ----- data_files/temoa_schema_v3.sql | 935 ------- data_files/temoa_schema_v3_1.sql | 25 +- temoa/temoa_model/table_data_puller.py | 4 +- temoa/temoa_model/table_writer.py | 2 +- temoa/temoa_model/temoa_initialize.py | 2 +- temoa/utilities/db_migration_v3_to_v3_1.py | 17 +- tests/legacy_test_values.py | 4 +- tests/test_exchange_cost_ledger.py | 2 +- tests/test_storage.py | 4 +- tests/testing_data/emissions.sql | 240 +- tests/testing_data/mediumville.sql | 362 ++- tests/testing_data/simple_linked_tech.sql | 271 +- tests/testing_data/storageville.sql | 307 ++- tests/testing_data/test_system.sql | 781 ++++-- tests/testing_data/utopia.sql | 692 +++-- 21 files changed, 4256 insertions(+), 3651 deletions(-) delete mode 100644 data_files/temoa_schema_minimal_v3.sql delete mode 100644 data_files/temoa_schema_v3.sql diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index 2370d6d85..9296bdf85 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -1,1079 +1,1672 @@ +PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE "time_season" ( - "t_season" text, - PRIMARY KEY("t_season") -); -INSERT INTO `time_season` VALUES ('spring'); -INSERT INTO `time_season` VALUES ('summer'); -INSERT INTO `time_season` VALUES ('fall'); -INSERT INTO `time_season` VALUES ('winter'); -CREATE TABLE "time_periods" ( - "t_periods" integer, - "flag" text, - PRIMARY KEY("t_periods"), - FOREIGN KEY("flag") REFERENCES "time_period_labels"("t_period_labels") -); -INSERT INTO `time_periods` VALUES (2015,'e'); -INSERT INTO `time_periods` VALUES (2020,'f'); -INSERT INTO `time_periods` VALUES (2025,'f'); -INSERT INTO `time_periods` VALUES (2030,'f'); -INSERT INTO `time_periods` VALUES (2035,'f'); -CREATE TABLE "time_period_labels" ( - "t_period_labels" text, - "t_period_labels_desc" text, - PRIMARY KEY("t_period_labels") -); -INSERT INTO `time_period_labels` VALUES ('e','existing vintages'); -INSERT INTO `time_period_labels` VALUES ('f','future'); -CREATE TABLE "time_of_day" ( - "t_day" text, - PRIMARY KEY("t_day") -); -INSERT INTO `time_of_day` VALUES ('day'); -INSERT INTO `time_of_day` VALUES ('night'); -CREATE TABLE "technology_labels" ( - "tech_labels" text, - "tech_labels_desc" text, - PRIMARY KEY("tech_labels") -); -INSERT INTO `technology_labels` VALUES ('r','resource technology'); -INSERT INTO `technology_labels` VALUES ('p','production technology'); -INSERT INTO `technology_labels` VALUES ('pb','baseload production technology'); -INSERT INTO `technology_labels` VALUES ('ps','storage production technology'); -CREATE TABLE "technologies" ( - "tech" text, - "flag" text, - "sector" text, - "tech_desc" text, - "tech_category" text, - PRIMARY KEY("tech"), - FOREIGN KEY("sector") REFERENCES "sector_labels"("sector"), - FOREIGN KEY("flag") REFERENCES "technology_labels"("tech_labels") -); -INSERT INTO `technologies` VALUES ('S_IMPETH','r','supply',' imported ethanol',''); -INSERT INTO `technologies` VALUES ('S_IMPOIL','r','supply',' imported crude oil',''); -INSERT INTO `technologies` VALUES ('S_IMPNG','r','supply',' imported natural gas',''); -INSERT INTO `technologies` VALUES ('S_IMPURN','r','supply',' imported uranium',''); -INSERT INTO `technologies` VALUES ('S_OILREF','p','supply',' crude oil refinery',''); -INSERT INTO `technologies` VALUES ('E_NGCC','p','electric',' natural gas combined-cycle',''); -INSERT INTO `technologies` VALUES ('E_SOLPV','p','electric',' solar photovoltaic',''); -INSERT INTO `technologies` VALUES ('E_BATT','ps','electric',' lithium-ion battery',''); -INSERT INTO `technologies` VALUES ('E_NUCLEAR','pb','electric',' nuclear power plant',''); -INSERT INTO `technologies` VALUES ('T_BLND','p','transport','ethanol - gasoline blending process',''); -INSERT INTO `technologies` VALUES ('T_DSL','p','transport','diesel vehicle',''); -INSERT INTO `technologies` VALUES ('T_GSL','p','transport','gasoline vehicle',''); -INSERT INTO `technologies` VALUES ('T_EV','p','transport','electric vehicle',''); -INSERT INTO `technologies` VALUES ('R_EH','p','residential',' electric residential heating',''); -INSERT INTO `technologies` VALUES ('R_NGH','p','residential',' natural gas residential heating',''); -INSERT INTO `technologies` VALUES ('E_TRANS','p','electric','electric transmission',''); -CREATE TABLE "tech_reserve" ( - "tech" text, - "notes" text, - PRIMARY KEY("tech") -); -CREATE TABLE "tech_exchange" ( - "tech" text, - "notes" TEXT, - PRIMARY KEY("tech"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech") +CREATE TABLE MetaData +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) ); -INSERT INTO `tech_exchange` VALUES ('E_TRANS',''); -CREATE TABLE "tech_curtailment" ( - "tech" text, - "notes" TEXT, - PRIMARY KEY("tech"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech") +INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); +INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); +INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO MetaData VALUES('link_seasons',1,'Carry storage states between seasons'); +INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); +CREATE TABLE MetaDataReal +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) ); -CREATE TABLE "tech_flex" ( - "tech" text, - "notes" TEXT, - PRIMARY KEY("tech"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech") +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,''); +CREATE TABLE OutputDualVariable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE OutputObjective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE SectorLabel +( + sector TEXT, + PRIMARY KEY (sector) +); +INSERT INTO SectorLabel VALUES('supply'); +INSERT INTO SectorLabel VALUES('electric'); +INSERT INTO SectorLabel VALUES('transport'); +INSERT INTO SectorLabel VALUES('commercial'); +INSERT INTO SectorLabel VALUES('residential'); +INSERT INTO SectorLabel VALUES('industrial'); +CREATE TABLE CapacityCredit +( + region TEXT, + period INTEGER, + tech TEXT, + vintage INTEGER, + credit REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage), + CHECK (credit >= 0 AND credit <= 1) +); +CREATE TABLE CapacityFactorProcess +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE CapacityFactorTech +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech), + CHECK (factor >= 0 AND factor <= 1) +); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'spring','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'spring','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'summer','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'summer','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'fall','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'fall','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'winter','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'winter','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'spring','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'spring','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'summer','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'summer','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'fall','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'fall','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'winter','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'winter','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'spring','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'spring','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'summer','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'summer','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'fall','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'fall','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'winter','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'winter','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'spring','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'spring','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'summer','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'summer','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'fall','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'fall','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'winter','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'winter','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'spring','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'spring','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'summer','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'summer','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'fall','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'fall','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'winter','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'winter','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'spring','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'spring','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'summer','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'summer','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'fall','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'fall','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'winter','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'winter','night','E_SOLPV',0.0,''); +CREATE TABLE CapacityToActivity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + c2a REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +INSERT INTO CapacityToActivity VALUES('R1','S_IMPETH',1.0,''); +INSERT INTO CapacityToActivity VALUES('R1','S_IMPOIL',1.0,''); +INSERT INTO CapacityToActivity VALUES('R1','S_IMPNG',1.0,''); +INSERT INTO CapacityToActivity VALUES('R1','S_IMPURN',1.0,''); +INSERT INTO CapacityToActivity VALUES('R1','S_OILREF',1.0,''); +INSERT INTO CapacityToActivity VALUES('R1','E_NGCC',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('R1','E_SOLPV',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('R1','E_BATT',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('R1','E_NUCLEAR',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('R1','T_BLND',1.0,''); +INSERT INTO CapacityToActivity VALUES('R1','T_DSL',1.0,''); +INSERT INTO CapacityToActivity VALUES('R1','T_GSL',1.0,''); +INSERT INTO CapacityToActivity VALUES('R1','T_EV',1.0,''); +INSERT INTO CapacityToActivity VALUES('R1','R_EH',1.0,''); +INSERT INTO CapacityToActivity VALUES('R1','R_NGH',1.0,''); +INSERT INTO CapacityToActivity VALUES('R2','S_IMPETH',1.0,''); +INSERT INTO CapacityToActivity VALUES('R2','S_IMPOIL',1.0,''); +INSERT INTO CapacityToActivity VALUES('R2','S_IMPNG',1.0,''); +INSERT INTO CapacityToActivity VALUES('R2','S_IMPURN',1.0,''); +INSERT INTO CapacityToActivity VALUES('R2','S_OILREF',1.0,''); +INSERT INTO CapacityToActivity VALUES('R2','E_NGCC',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('R2','E_SOLPV',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('R2','E_BATT',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('R2','E_NUCLEAR',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('R2','T_BLND',1.0,''); +INSERT INTO CapacityToActivity VALUES('R2','T_DSL',1.0,''); +INSERT INTO CapacityToActivity VALUES('R2','T_GSL',1.0,''); +INSERT INTO CapacityToActivity VALUES('R2','T_EV',1.0,''); +INSERT INTO CapacityToActivity VALUES('R2','R_EH',1.0,''); +INSERT INTO CapacityToActivity VALUES('R2','R_NGH',1.0,''); +INSERT INTO CapacityToActivity VALUES('R1-R2','E_TRANS',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('R2-R1','E_TRANS',31.539999999999999147,''); +CREATE TABLE Commodity +( + name TEXT + PRIMARY KEY, + flag TEXT + REFERENCES CommodityType (label), + description TEXT +); +INSERT INTO Commodity VALUES('ethos','s','dummy commodity to supply inputs (makes graph easier to read)'); +INSERT INTO Commodity VALUES('OIL','p','crude oil'); +INSERT INTO Commodity VALUES('NG','p','natural gas'); +INSERT INTO Commodity VALUES('URN','p','uranium'); +INSERT INTO Commodity VALUES('ETH','p','ethanol'); +INSERT INTO Commodity VALUES('SOL','p','solar insolation'); +INSERT INTO Commodity VALUES('GSL','p','gasoline'); +INSERT INTO Commodity VALUES('DSL','p','diesel'); +INSERT INTO Commodity VALUES('ELC','p','electricity'); +INSERT INTO Commodity VALUES('E10','p','gasoline blend with 10% ethanol'); +INSERT INTO Commodity VALUES('VMT','d','travel demand for vehicle-miles traveled'); +INSERT INTO Commodity VALUES('RH','d','demand for residential heating'); +INSERT INTO Commodity VALUES('CO2','e','CO2 emissions commodity'); +CREATE TABLE CommodityType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO CommodityType VALUES('a','annual commodity'); +INSERT INTO CommodityType VALUES('s','source commodity'); +INSERT INTO CommodityType VALUES('p','physical commodity'); +INSERT INTO CommodityType VALUES('e','emissions commodity'); +INSERT INTO CommodityType VALUES('d','demand commodity'); +CREATE TABLE CostEmission +( + region TEXT + REFERENCES Region (region), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT NOT NULL + REFERENCES Commodity (name), + cost REAL NOT NULL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE CostFixed +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +INSERT INTO CostFixed VALUES('R1',2020,'E_NGCC',2020,30.600000000000000532,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_NGCC',2020,9.7799999999999993605,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_NGCC',2025,9.7799999999999993605,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2020,9.7799999999999993605,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2025,9.7799999999999993605,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2030,9.7799999999999993605,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2020,'E_SOLPV',2020,10.400000000000000355,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_SOLPV',2020,10.400000000000000355,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_SOLPV',2025,9.0999999999999996447,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2020,10.400000000000000355,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2025,9.0999999999999996447,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2030,9.0999999999999996447,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2020,'E_NUCLEAR',2020,98.09999999999998721,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_NUCLEAR',2020,98.09999999999998721,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_NUCLEAR',2025,98.09999999999998721,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2020,98.09999999999998721,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2025,98.09999999999998721,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2030,98.09999999999998721,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2020,'E_BATT',2020,7.0499999999999998223,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_BATT',2020,7.0499999999999998223,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_BATT',2025,7.0499999999999998223,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2020,7.0499999999999998223,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2025,7.0499999999999998223,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2030,7.0499999999999998223,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2020,'E_NGCC',2020,24.479999999999999538,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_NGCC',2020,7.8239999999999998436,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_NGCC',2025,7.8239999999999998436,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2020,7.8239999999999998436,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2025,7.8239999999999998436,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2030,7.8239999999999998436,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2020,'E_SOLPV',2020,8.3200000000000002842,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_SOLPV',2020,8.3200000000000002842,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_SOLPV',2025,7.2800000000000002486,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2020,8.3200000000000002842,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2025,7.2800000000000002486,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2030,7.2800000000000002486,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2020,'E_NUCLEAR',2020,78.480000000000007531,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_NUCLEAR',2020,78.480000000000007531,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_NUCLEAR',2025,78.480000000000007531,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2020,78.480000000000007531,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2025,78.480000000000007531,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2030,78.480000000000007531,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2020,'E_BATT',2020,5.6399999999999996802,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_BATT',2020,5.6399999999999996802,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_BATT',2025,5.6399999999999996802,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2020,5.6399999999999996802,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2025,5.6399999999999996802,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2030,5.6399999999999996802,'$M/GWyr',''); +CREATE TABLE CostInvest +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +INSERT INTO CostInvest VALUES('R1','E_NGCC',2020,1050.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R1','E_NGCC',2025,1025.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R1','E_NGCC',2030,1000.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R1','E_SOLPV',2020,900.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R1','E_SOLPV',2025,560.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R1','E_SOLPV',2030,800.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R1','E_NUCLEAR',2020,6145.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R1','E_NUCLEAR',2025,6045.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R1','E_NUCLEAR',2030,5890.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R1','E_BATT',2020,1150.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R1','E_BATT',2025,720.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R1','E_BATT',2030,480.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R1','T_GSL',2020,2570.0,'$/bvmt/yr',''); +INSERT INTO CostInvest VALUES('R1','T_GSL',2025,2700.0,'$/bvmt/yr',''); +INSERT INTO CostInvest VALUES('R1','T_GSL',2030,2700.0,'$/bvmt/yr',''); +INSERT INTO CostInvest VALUES('R1','T_DSL',2020,2715.0,'$/bvmt/yr',''); +INSERT INTO CostInvest VALUES('R1','T_DSL',2025,2810.0,'$/bvmt/yr',''); +INSERT INTO CostInvest VALUES('R1','T_DSL',2030,2810.0,'$/bvmt/yr',''); +INSERT INTO CostInvest VALUES('R1','T_EV',2020,3100.0,'$/bvmt/yr',''); +INSERT INTO CostInvest VALUES('R1','T_EV',2025,3030.0,'$/bvmt/yr',''); +INSERT INTO CostInvest VALUES('R1','T_EV',2030,2925.0,'$/bvmt/yr',''); +INSERT INTO CostInvest VALUES('R1','R_EH',2020,4.0999999999999996447,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R1','R_EH',2025,4.0999999999999996447,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R1','R_EH',2030,4.0999999999999996447,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R1','R_NGH',2020,7.5999999999999996447,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R1','R_NGH',2025,7.5999999999999996447,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R1','R_NGH',2030,7.5999999999999996447,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R2','E_NGCC',2020,840.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R2','E_NGCC',2025,820.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R2','E_NGCC',2030,800.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R2','E_SOLPV',2020,720.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R2','E_SOLPV',2025,448.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R2','E_SOLPV',2030,640.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R2','E_NUCLEAR',2020,4916.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R2','E_NUCLEAR',2025,4836.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R2','E_NUCLEAR',2030,4712.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R2','E_BATT',2020,920.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R2','E_BATT',2025,576.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R2','E_BATT',2030,384.0,'$M/GW',''); +INSERT INTO CostInvest VALUES('R2','T_GSL',2020,2056.0,'$/bvmt/yr',''); +INSERT INTO CostInvest VALUES('R2','T_GSL',2025,2160.0,'$/bvmt/yr',''); +INSERT INTO CostInvest VALUES('R2','T_GSL',2030,2160.0,'$/bvmt/yr',''); +INSERT INTO CostInvest VALUES('R2','T_DSL',2020,2172.0,'$/bvmt/yr',''); +INSERT INTO CostInvest VALUES('R2','T_DSL',2025,2248.0,'$/bvmt/yr',''); +INSERT INTO CostInvest VALUES('R2','T_DSL',2030,2248.0,'$/bvmt/yr',''); +INSERT INTO CostInvest VALUES('R2','T_EV',2020,2480.0,'$/bvmt/yr',''); +INSERT INTO CostInvest VALUES('R2','T_EV',2025,2424.0,'$/bvmt/yr',''); +INSERT INTO CostInvest VALUES('R2','T_EV',2030,2340.0,'$/bvmt/yr',''); +INSERT INTO CostInvest VALUES('R2','R_EH',2020,3.2799999999999998046,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R2','R_EH',2025,3.2799999999999998046,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R2','R_EH',2030,3.2799999999999998046,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R2','R_NGH',2020,6.080000000000000071,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R2','R_NGH',2025,6.080000000000000071,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R2','R_NGH',2030,6.080000000000000071,'$/PJ/yr',''); +CREATE TABLE CostVariable +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +INSERT INTO CostVariable VALUES('R1',2020,'S_IMPETH',2020,32.0,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2025,'S_IMPETH',2020,32.0,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'S_IMPETH',2020,32.0,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2020,'S_IMPOIL',2020,20.0,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2025,'S_IMPOIL',2020,20.0,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'S_IMPOIL',2020,20.0,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2020,'S_IMPNG',2020,4.0,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2025,'S_IMPNG',2020,4.0,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'S_IMPNG',2020,4.0,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2020,'S_OILREF',2020,1.0,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2025,'S_OILREF',2020,1.0,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'S_OILREF',2020,1.0,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2020,'E_NGCC',2020,1.6000000000000000888,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2025,'E_NGCC',2020,1.6000000000000000888,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2025,'E_NGCC',2025,1.7,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2020,1.6000000000000000888,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2025,1.7,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2030,1.8,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2020,'E_NUCLEAR',2020,0.23999999999999999111,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2025,'E_NUCLEAR',2020,0.23999999999999999111,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2025,'E_NUCLEAR',2025,0.25,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2020,0.23999999999999999111,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2025,0.25,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2030,0.26000000000000000888,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2020,'S_IMPETH',2020,25.600000000000000532,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'S_IMPETH',2020,25.600000000000000532,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'S_IMPETH',2020,25.600000000000000532,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2020,'S_IMPOIL',2020,16.0,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'S_IMPOIL',2020,16.0,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'S_IMPOIL',2020,16.0,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2020,'S_IMPNG',2020,3.2000000000000001776,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'S_IMPNG',2020,3.2000000000000001776,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'S_IMPNG',2020,3.2000000000000001776,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2020,'S_OILREF',2020,0.8,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'S_OILREF',2020,0.8,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'S_OILREF',2020,0.8,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2020,'E_NGCC',2020,1.2800000000000000355,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'E_NGCC',2020,1.2800000000000000355,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'E_NGCC',2025,1.3600000000000000976,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2020,1.2800000000000000355,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2025,1.3600000000000000976,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2030,1.4399999999999999467,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2020,'E_NUCLEAR',2020,0.19199999999999999289,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'E_NUCLEAR',2020,0.19199999999999999289,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'E_NUCLEAR',2025,0.2,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2020,0.19199999999999999289,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2025,0.2,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2030,0.2080000000000000071,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1-R2',2020,'E_TRANS',2015,0.1,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1-R2',2025,'E_TRANS',2015,0.1,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1-R2',2030,'E_TRANS',2015,0.1,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2-R1',2020,'E_TRANS',2015,0.1,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2-R1',2025,'E_TRANS',2015,0.1,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2-R1',2030,'E_TRANS',2015,0.1,'$M/PJ',''); +CREATE TABLE Demand +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + commodity TEXT + REFERENCES Commodity (name), + demand REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, commodity) +); +INSERT INTO Demand VALUES('R1',2020,'RH',30.0,'',''); +INSERT INTO Demand VALUES('R1',2025,'RH',33.0,'',''); +INSERT INTO Demand VALUES('R1',2030,'RH',36.0,'',''); +INSERT INTO Demand VALUES('R1',2020,'VMT',84.0,'',''); +INSERT INTO Demand VALUES('R1',2025,'VMT',91.0,'',''); +INSERT INTO Demand VALUES('R1',2030,'VMT',98.0,'',''); +INSERT INTO Demand VALUES('R2',2020,'RH',70.0,'',''); +INSERT INTO Demand VALUES('R2',2025,'RH',77.0,'',''); +INSERT INTO Demand VALUES('R2',2030,'RH',84.0,'',''); +INSERT INTO Demand VALUES('R2',2020,'VMT',36.0,'',''); +INSERT INTO Demand VALUES('R2',2025,'VMT',39.0,'',''); +INSERT INTO Demand VALUES('R2',2030,'VMT',42.0,'',''); +CREATE TABLE DemandSpecificDistribution +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + demand_name TEXT + REFERENCES Commodity (name), + dsd REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), + CHECK (dsd >= 0 AND dsd <= 1) +); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'spring','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'summer','day','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'summer','night','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'fall','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'fall','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'winter','day','RH',0.3,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'winter','night','RH',0.4,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'spring','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'summer','day','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'summer','night','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'fall','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'fall','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'winter','day','RH',0.3,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'winter','night','RH',0.4,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'spring','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'summer','day','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'summer','night','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'fall','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'fall','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'winter','day','RH',0.3,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'winter','night','RH',0.4,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'spring','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'summer','day','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'summer','night','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'fall','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'fall','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'winter','day','RH',0.3,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'winter','night','RH',0.4,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'spring','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'summer','day','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'summer','night','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'fall','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'fall','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'winter','day','RH',0.3,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'winter','night','RH',0.4,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'spring','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'summer','day','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'summer','night','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'fall','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'fall','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'winter','day','RH',0.3,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'winter','night','RH',0.4,''); +CREATE TABLE LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE Efficiency +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +INSERT INTO Efficiency VALUES('R1','ethos','S_IMPETH',2020,'ETH',1.0,''); +INSERT INTO Efficiency VALUES('R1','ethos','S_IMPOIL',2020,'OIL',1.0,''); +INSERT INTO Efficiency VALUES('R1','ethos','S_IMPNG',2020,'NG',1.0,''); +INSERT INTO Efficiency VALUES('R1','ethos','S_IMPURN',2020,'URN',1.0,''); +INSERT INTO Efficiency VALUES('R1','OIL','S_OILREF',2020,'GSL',1.0,''); +INSERT INTO Efficiency VALUES('R1','OIL','S_OILREF',2020,'DSL',1.0,''); +INSERT INTO Efficiency VALUES('R1','ETH','T_BLND',2020,'E10',1.0,''); +INSERT INTO Efficiency VALUES('R1','GSL','T_BLND',2020,'E10',1.0,''); +INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2020,'ELC',0.55,''); +INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2025,'ELC',0.55,''); +INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2030,'ELC',0.55,''); +INSERT INTO Efficiency VALUES('R1','SOL','E_SOLPV',2020,'ELC',1.0,''); +INSERT INTO Efficiency VALUES('R1','SOL','E_SOLPV',2025,'ELC',1.0,''); +INSERT INTO Efficiency VALUES('R1','SOL','E_SOLPV',2030,'ELC',1.0,''); +INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2015,'ELC',0.4,''); +INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2020,'ELC',0.4,''); +INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2025,'ELC',0.4,''); +INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2030,'ELC',0.4,''); +INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2020,'ELC',0.85,''); +INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2025,'ELC',0.85,''); +INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2030,'ELC',0.85,''); +INSERT INTO Efficiency VALUES('R1','E10','T_GSL',2020,'VMT',0.25,''); +INSERT INTO Efficiency VALUES('R1','E10','T_GSL',2025,'VMT',0.25,''); +INSERT INTO Efficiency VALUES('R1','E10','T_GSL',2030,'VMT',0.25,''); +INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2020,'VMT',0.3,''); +INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2025,'VMT',0.3,''); +INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2030,'VMT',0.3,''); +INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2020,'VMT',0.89000000000000003552,''); +INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2025,'VMT',0.89000000000000003552,''); +INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2030,'VMT',0.89000000000000003552,''); +INSERT INTO Efficiency VALUES('R1','ELC','R_EH',2020,'RH',1.0,''); +INSERT INTO Efficiency VALUES('R1','ELC','R_EH',2025,'RH',1.0,''); +INSERT INTO Efficiency VALUES('R1','ELC','R_EH',2030,'RH',1.0,''); +INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2020,'RH',0.85,''); +INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2025,'RH',0.85,''); +INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2030,'RH',0.85,''); +INSERT INTO Efficiency VALUES('R2','ethos','S_IMPETH',2020,'ETH',1.0,''); +INSERT INTO Efficiency VALUES('R2','ethos','S_IMPOIL',2020,'OIL',1.0,''); +INSERT INTO Efficiency VALUES('R2','ethos','S_IMPNG',2020,'NG',1.0,''); +INSERT INTO Efficiency VALUES('R2','ethos','S_IMPURN',2020,'URN',1.0,''); +INSERT INTO Efficiency VALUES('R2','OIL','S_OILREF',2020,'GSL',1.0,''); +INSERT INTO Efficiency VALUES('R2','OIL','S_OILREF',2020,'DSL',1.0,''); +INSERT INTO Efficiency VALUES('R2','ETH','T_BLND',2020,'E10',1.0,''); +INSERT INTO Efficiency VALUES('R2','GSL','T_BLND',2020,'E10',1.0,''); +INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2020,'ELC',0.55,''); +INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2025,'ELC',0.55,''); +INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2030,'ELC',0.55,''); +INSERT INTO Efficiency VALUES('R2','SOL','E_SOLPV',2020,'ELC',1.0,''); +INSERT INTO Efficiency VALUES('R2','SOL','E_SOLPV',2025,'ELC',1.0,''); +INSERT INTO Efficiency VALUES('R2','SOL','E_SOLPV',2030,'ELC',1.0,''); +INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2015,'ELC',0.4,''); +INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2020,'ELC',0.4,''); +INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2025,'ELC',0.4,''); +INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2030,'ELC',0.4,''); +INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2020,'ELC',0.85,''); +INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2025,'ELC',0.85,''); +INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2030,'ELC',0.85,''); +INSERT INTO Efficiency VALUES('R2','E10','T_GSL',2020,'VMT',0.25,''); +INSERT INTO Efficiency VALUES('R2','E10','T_GSL',2025,'VMT',0.25,''); +INSERT INTO Efficiency VALUES('R2','E10','T_GSL',2030,'VMT',0.25,''); +INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2020,'VMT',0.3,''); +INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2025,'VMT',0.3,''); +INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2030,'VMT',0.3,''); +INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2020,'VMT',0.89000000000000003552,''); +INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2025,'VMT',0.89000000000000003552,''); +INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2030,'VMT',0.89000000000000003552,''); +INSERT INTO Efficiency VALUES('R2','ELC','R_EH',2020,'RH',1.0,''); +INSERT INTO Efficiency VALUES('R2','ELC','R_EH',2025,'RH',1.0,''); +INSERT INTO Efficiency VALUES('R2','ELC','R_EH',2030,'RH',1.0,''); +INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2020,'RH',0.85,''); +INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2025,'RH',0.85,''); +INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2030,'RH',0.85,''); +INSERT INTO Efficiency VALUES('R1-R2','ELC','E_TRANS',2015,'ELC',0.9,''); +INSERT INTO Efficiency VALUES('R2-R1','ELC','E_TRANS',2015,'ELC',0.9,''); +CREATE TABLE EfficiencyVariable +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE EmissionActivity +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) +); +INSERT INTO EmissionActivity VALUES('R1','CO2','ethos','S_IMPNG',2020,'NG',50.299999999999993605,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO EmissionActivity VALUES('R1','CO2','OIL','S_OILREF',2020,'GSL',67.200000000000006394,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO EmissionActivity VALUES('R1','CO2','OIL','S_OILREF',2020,'DSL',69.400000000000003907,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO EmissionActivity VALUES('R2','CO2','ethos','S_IMPNG',2020,'NG',50.299999999999993605,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO EmissionActivity VALUES('R2','CO2','OIL','S_OILREF',2020,'GSL',67.200000000000006394,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO EmissionActivity VALUES('R2','CO2','OIL','S_OILREF',2020,'DSL',69.400000000000003907,'kT/PJ','taken from MIT Energy Fact Sheet'); +CREATE TABLE EmissionEmbodied +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE ExistingCapacity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +INSERT INTO ExistingCapacity VALUES('R1','E_NUCLEAR',2015,0.070000000000000008881,'GW',''); +INSERT INTO ExistingCapacity VALUES('R2','E_NUCLEAR',2015,0.03,'GW',''); +INSERT INTO ExistingCapacity VALUES('R1-R2','E_TRANS',2015,10.0,'GW',''); +INSERT INTO ExistingCapacity VALUES('R2-R1','E_TRANS',2015,10.0,'GW',''); +CREATE TABLE TechGroup +( + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE GrowthRateMax +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE GrowthRateSeed +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + seed REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE LoanLifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +INSERT INTO LoanLifetimeTech VALUES('R1','S_IMPETH',100.0,''); +INSERT INTO LoanLifetimeTech VALUES('R1','S_IMPOIL',100.0,''); +INSERT INTO LoanLifetimeTech VALUES('R1','S_IMPNG',100.0,''); +INSERT INTO LoanLifetimeTech VALUES('R1','S_IMPURN',100.0,''); +INSERT INTO LoanLifetimeTech VALUES('R1','S_OILREF',100.0,''); +INSERT INTO LoanLifetimeTech VALUES('R1','E_NGCC',30.0,''); +INSERT INTO LoanLifetimeTech VALUES('R1','E_SOLPV',30.0,''); +INSERT INTO LoanLifetimeTech VALUES('R1','E_BATT',20.0,''); +INSERT INTO LoanLifetimeTech VALUES('R1','E_NUCLEAR',50.0,''); +INSERT INTO LoanLifetimeTech VALUES('R1','T_BLND',100.0,''); +INSERT INTO LoanLifetimeTech VALUES('R1','T_DSL',12.0,''); +INSERT INTO LoanLifetimeTech VALUES('R1','T_GSL',12.0,''); +INSERT INTO LoanLifetimeTech VALUES('R1','T_EV',12.0,''); +INSERT INTO LoanLifetimeTech VALUES('R1','R_EH',20.0,''); +INSERT INTO LoanLifetimeTech VALUES('R1','R_NGH',20.0,''); +INSERT INTO LoanLifetimeTech VALUES('R2','S_IMPETH',100.0,''); +INSERT INTO LoanLifetimeTech VALUES('R2','S_IMPOIL',100.0,''); +INSERT INTO LoanLifetimeTech VALUES('R2','S_IMPNG',100.0,''); +INSERT INTO LoanLifetimeTech VALUES('R2','S_IMPURN',100.0,''); +INSERT INTO LoanLifetimeTech VALUES('R2','S_OILREF',100.0,''); +INSERT INTO LoanLifetimeTech VALUES('R2','E_NGCC',30.0,''); +INSERT INTO LoanLifetimeTech VALUES('R2','E_SOLPV',30.0,''); +INSERT INTO LoanLifetimeTech VALUES('R2','E_BATT',20.0,''); +INSERT INTO LoanLifetimeTech VALUES('R2','E_NUCLEAR',50.0,''); +INSERT INTO LoanLifetimeTech VALUES('R2','T_BLND',100.0,''); +INSERT INTO LoanLifetimeTech VALUES('R2','T_DSL',12.0,''); +INSERT INTO LoanLifetimeTech VALUES('R2','T_GSL',12.0,''); +INSERT INTO LoanLifetimeTech VALUES('R2','T_EV',12.0,''); +INSERT INTO LoanLifetimeTech VALUES('R2','R_EH',20.0,''); +INSERT INTO LoanLifetimeTech VALUES('R2','R_NGH',20.0,''); +CREATE TABLE LifetimeProcess +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE LifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +INSERT INTO LifetimeTech VALUES('R1','S_IMPETH',100.0,''); +INSERT INTO LifetimeTech VALUES('R1','S_IMPOIL',100.0,''); +INSERT INTO LifetimeTech VALUES('R1','S_IMPNG',100.0,''); +INSERT INTO LifetimeTech VALUES('R1','S_IMPURN',100.0,''); +INSERT INTO LifetimeTech VALUES('R1','S_OILREF',100.0,''); +INSERT INTO LifetimeTech VALUES('R1','E_NGCC',30.0,''); +INSERT INTO LifetimeTech VALUES('R1','E_SOLPV',30.0,''); +INSERT INTO LifetimeTech VALUES('R1','E_BATT',20.0,''); +INSERT INTO LifetimeTech VALUES('R1','E_NUCLEAR',50.0,''); +INSERT INTO LifetimeTech VALUES('R1','T_BLND',100.0,''); +INSERT INTO LifetimeTech VALUES('R1','T_DSL',12.0,''); +INSERT INTO LifetimeTech VALUES('R1','T_GSL',12.0,''); +INSERT INTO LifetimeTech VALUES('R1','T_EV',12.0,''); +INSERT INTO LifetimeTech VALUES('R1','R_EH',20.0,''); +INSERT INTO LifetimeTech VALUES('R1','R_NGH',20.0,''); +INSERT INTO LifetimeTech VALUES('R2','S_IMPETH',100.0,''); +INSERT INTO LifetimeTech VALUES('R2','S_IMPOIL',100.0,''); +INSERT INTO LifetimeTech VALUES('R2','S_IMPNG',100.0,''); +INSERT INTO LifetimeTech VALUES('R2','S_IMPURN',100.0,''); +INSERT INTO LifetimeTech VALUES('R2','S_OILREF',100.0,''); +INSERT INTO LifetimeTech VALUES('R2','E_NGCC',30.0,''); +INSERT INTO LifetimeTech VALUES('R2','E_SOLPV',30.0,''); +INSERT INTO LifetimeTech VALUES('R2','E_BATT',20.0,''); +INSERT INTO LifetimeTech VALUES('R2','E_NUCLEAR',50.0,''); +INSERT INTO LifetimeTech VALUES('R2','T_BLND',100.0,''); +INSERT INTO LifetimeTech VALUES('R2','T_DSL',12.0,''); +INSERT INTO LifetimeTech VALUES('R2','T_GSL',12.0,''); +INSERT INTO LifetimeTech VALUES('R2','T_EV',12.0,''); +INSERT INTO LifetimeTech VALUES('R2','R_EH',20.0,''); +INSERT INTO LifetimeTech VALUES('R2','R_NGH',20.0,''); +INSERT INTO LifetimeTech VALUES('R1-R2','E_TRANS',30.0,''); +INSERT INTO LifetimeTech VALUES('R2-R1','E_TRANS',30.0,''); +CREATE TABLE LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE MaxActivity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + max_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE MaxCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + max_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE MaxResource +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + max_res REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE MinActivity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + min_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +INSERT INTO MinActivity VALUES('R1',2020,'T_GSL',35.0,'',''); +INSERT INTO MinActivity VALUES('R1',2025,'T_GSL',35.0,'',''); +INSERT INTO MinActivity VALUES('R1',2030,'T_GSL',35.0,'',''); +INSERT INTO MinActivity VALUES('R2',2020,'T_GSL',15.0,'',''); +INSERT INTO MinActivity VALUES('R2',2025,'T_GSL',15.0,'',''); +INSERT INTO MinActivity VALUES('R2',2030,'T_GSL',15.0,'',''); +CREATE TABLE MaxCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + max_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE MinCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + min_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE MinCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + min_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputFlowOut +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); -INSERT INTO `tech_curtailment` VALUES ('S_OILREF',NULL); -CREATE TABLE "tech_annual" ( - "tech" text, +CREATE TABLE PlanningReserveMargin +( + region TEXT + PRIMARY KEY + REFERENCES Region (region), + margin REAL +); +CREATE TABLE RampDown +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE RampUp +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE Region +( + region TEXT + PRIMARY KEY, + notes TEXT +); +INSERT INTO Region VALUES('R1',NULL); +INSERT INTO Region VALUES('R2',NULL); +CREATE TABLE TimeSegmentFraction +( + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + segfrac REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segfrac >= 0 AND segfrac <= 1) +); +INSERT INTO TimeSegmentFraction VALUES(2020,'spring','day',0.125,'Spring - Day'); +INSERT INTO TimeSegmentFraction VALUES(2020,'spring','night',0.125,'Spring - Night'); +INSERT INTO TimeSegmentFraction VALUES(2020,'summer','day',0.125,'Summer - Day'); +INSERT INTO TimeSegmentFraction VALUES(2020,'summer','night',0.125,'Summer - Night'); +INSERT INTO TimeSegmentFraction VALUES(2020,'fall','day',0.125,'Fall - Day'); +INSERT INTO TimeSegmentFraction VALUES(2020,'fall','night',0.125,'Fall - Night'); +INSERT INTO TimeSegmentFraction VALUES(2020,'winter','day',0.125,'Winter - Day'); +INSERT INTO TimeSegmentFraction VALUES(2020,'winter','night',0.125,'Winter - Night'); +INSERT INTO TimeSegmentFraction VALUES(2025,'spring','day',0.125,'Spring - Day'); +INSERT INTO TimeSegmentFraction VALUES(2025,'spring','night',0.125,'Spring - Night'); +INSERT INTO TimeSegmentFraction VALUES(2025,'summer','day',0.125,'Summer - Day'); +INSERT INTO TimeSegmentFraction VALUES(2025,'summer','night',0.125,'Summer - Night'); +INSERT INTO TimeSegmentFraction VALUES(2025,'fall','day',0.125,'Fall - Day'); +INSERT INTO TimeSegmentFraction VALUES(2025,'fall','night',0.125,'Fall - Night'); +INSERT INTO TimeSegmentFraction VALUES(2025,'winter','day',0.125,'Winter - Day'); +INSERT INTO TimeSegmentFraction VALUES(2025,'winter','night',0.125,'Winter - Night'); +INSERT INTO TimeSegmentFraction VALUES(2030,'spring','day',0.125,'Spring - Day'); +INSERT INTO TimeSegmentFraction VALUES(2030,'spring','night',0.125,'Spring - Night'); +INSERT INTO TimeSegmentFraction VALUES(2030,'summer','day',0.125,'Summer - Day'); +INSERT INTO TimeSegmentFraction VALUES(2030,'summer','night',0.125,'Summer - Night'); +INSERT INTO TimeSegmentFraction VALUES(2030,'fall','day',0.125,'Fall - Day'); +INSERT INTO TimeSegmentFraction VALUES(2030,'fall','night',0.125,'Fall - Night'); +INSERT INTO TimeSegmentFraction VALUES(2030,'winter','day',0.125,'Winter - Day'); +INSERT INTO TimeSegmentFraction VALUES(2030,'winter','night',0.125,'Winter - Night'); +CREATE TABLE StorageDuration +( + region TEXT, + tech TEXT, + duration REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +INSERT INTO StorageDuration VALUES('R1','E_BATT',8.0,'8-hour duration specified as fraction of a day'); +INSERT INTO StorageDuration VALUES('R2','E_BATT',8.0,'8-hour duration specified as fraction of a day'); +CREATE TABLE StorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage) +); +INSERT INTO StorageLevelFraction VALUES('R1',2025,'winter','day','E_BATT',2025,0.5,''); +INSERT INTO StorageLevelFraction VALUES('R2',2020,'summer','day','E_BATT',2020,0.5,''); +CREATE TABLE TechnologyType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO TechnologyType VALUES('r','resource technology'); +INSERT INTO TechnologyType VALUES('p','production technology'); +INSERT INTO TechnologyType VALUES('pb','baseload production technology'); +INSERT INTO TechnologyType VALUES('ps','storage production technology'); +CREATE TABLE MinTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +INSERT INTO MinTechInputSplit VALUES('R1',2020,'GSL','T_BLND',0.9000000000000000222,''); +INSERT INTO MinTechInputSplit VALUES('R1',2020,'ETH','T_BLND',0.1000000000000000055,''); +INSERT INTO MinTechInputSplit VALUES('R1',2025,'GSL','T_BLND',0.9000000000000000222,''); +INSERT INTO MinTechInputSplit VALUES('R1',2025,'ETH','T_BLND',0.1000000000000000055,''); +INSERT INTO MinTechInputSplit VALUES('R1',2030,'GSL','T_BLND',0.9000000000000000222,''); +INSERT INTO MinTechInputSplit VALUES('R1',2030,'ETH','T_BLND',0.1000000000000000055,''); +INSERT INTO MinTechInputSplit VALUES('R2',2020,'GSL','T_BLND',0.7199999999999999734,''); +INSERT INTO MinTechInputSplit VALUES('R2',2020,'ETH','T_BLND',0.08000000000000000166,''); +INSERT INTO MinTechInputSplit VALUES('R2',2025,'GSL','T_BLND',0.7199999999999999734,''); +INSERT INTO MinTechInputSplit VALUES('R2',2025,'ETH','T_BLND',0.08000000000000000166,''); +INSERT INTO MinTechInputSplit VALUES('R2',2030,'GSL','T_BLND',0.7199999999999999734,''); +INSERT INTO MinTechInputSplit VALUES('R2',2030,'ETH','T_BLND',0.08000000000000000166,''); +CREATE TABLE MinTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MinTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +INSERT INTO MinTechOutputSplit VALUES('R1',2020,'S_OILREF','GSL',0.9000000000000000222,''); +INSERT INTO MinTechOutputSplit VALUES('R1',2020,'S_OILREF','DSL',0.1000000000000000055,''); +INSERT INTO MinTechOutputSplit VALUES('R1',2025,'S_OILREF','GSL',0.9000000000000000222,''); +INSERT INTO MinTechOutputSplit VALUES('R1',2025,'S_OILREF','DSL',0.1000000000000000055,''); +INSERT INTO MinTechOutputSplit VALUES('R1',2030,'S_OILREF','GSL',0.9000000000000000222,''); +INSERT INTO MinTechOutputSplit VALUES('R1',2030,'S_OILREF','DSL',0.1000000000000000055,''); +INSERT INTO MinTechOutputSplit VALUES('R2',2020,'S_OILREF','GSL',0.7199999999999999734,''); +INSERT INTO MinTechOutputSplit VALUES('R2',2020,'S_OILREF','DSL',0.08000000000000000166,''); +INSERT INTO MinTechOutputSplit VALUES('R2',2025,'S_OILREF','GSL',0.7199999999999999734,''); +INSERT INTO MinTechOutputSplit VALUES('R2',2025,'S_OILREF','DSL',0.08000000000000000166,''); +INSERT INTO MinTechOutputSplit VALUES('R2',2030,'S_OILREF','GSL',0.7199999999999999734,''); +INSERT INTO MinTechOutputSplit VALUES('R2',2030,'S_OILREF','DSL',0.08000000000000000166,''); +CREATE TABLE MinTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MaxTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MaxTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE TimeOfDay +( + sequence INTEGER UNIQUE, + tod TEXT + PRIMARY KEY +); +INSERT INTO TimeOfDay VALUES(1,'day'); +INSERT INTO TimeOfDay VALUES(2,'night'); +CREATE TABLE TimePeriod +( + sequence INTEGER UNIQUE, + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES TimePeriodType (label) +); +INSERT INTO TimePeriod VALUES(1,2015,'e'); +INSERT INTO TimePeriod VALUES(2,2020,'f'); +INSERT INTO TimePeriod VALUES(3,2025,'f'); +INSERT INTO TimePeriod VALUES(4,2030,'f'); +INSERT INTO TimePeriod VALUES(5,2035,'f'); +CREATE TABLE TimeSeason +( + season TEXT + PRIMARY KEY +); +INSERT INTO TimeSeason VALUES('spring'); +INSERT INTO TimeSeason VALUES('summer'); +INSERT INTO TimeSeason VALUES('fall'); +INSERT INTO TimeSeason VALUES('winter'); +CREATE TABLE PeriodSeasons +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT + REFERENCES TimeSeason (season), + notes TEXT, + PRIMARY KEY (period, sequence) +); +INSERT INTO PeriodSeasons VALUES(2020,1,'spring',NULL); +INSERT INTO PeriodSeasons VALUES(2020,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2020,3,'fall',NULL); +INSERT INTO PeriodSeasons VALUES(2020,4,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2025,1,'spring',NULL); +INSERT INTO PeriodSeasons VALUES(2025,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2025,3,'fall',NULL); +INSERT INTO PeriodSeasons VALUES(2025,4,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2030,1,'spring',NULL); +INSERT INTO PeriodSeasons VALUES(2030,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2030,3,'fall',NULL); +INSERT INTO PeriodSeasons VALUES(2030,4,'winter',NULL); +CREATE TABLE TimePeriodType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO TimePeriodType VALUES('e','existing vintages'); +INSERT INTO TimePeriodType VALUES('f','future'); +CREATE TABLE MaxActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE MaxCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE MaxAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + factor REAL, + source TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE MaxNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + max_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE MaxNewCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + max_new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE MaxNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE MinActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE MinAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + factor REAL, + source TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE MinCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE MinNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + min_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE MinNewCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + min_new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE MinNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE MinNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); +CREATE TABLE MaxNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); +CREATE TABLE OutputEmission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE MinActivityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + min_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE EmissionLimit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +INSERT INTO EmissionLimit VALUES('R1',2020,'CO2',25000.0,'kT CO2',''); +INSERT INTO EmissionLimit VALUES('R1',2025,'CO2',24000.0,'kT CO2',''); +INSERT INTO EmissionLimit VALUES('R1',2030,'CO2',23000.0,'kT CO2',''); +INSERT INTO EmissionLimit VALUES('global',2020,'CO2',37500.0,'kT CO2',''); +INSERT INTO EmissionLimit VALUES('global',2025,'CO2',36000.0,'kT CO2',''); +INSERT INTO EmissionLimit VALUES('global',2030,'CO2',34500.0,'kT CO2',''); +CREATE TABLE MaxActivityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + max_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "min_act" REAL, + "units" TEXT, "notes" TEXT, - PRIMARY KEY("tech"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech") + PRIMARY KEY("region","period","season","tech") ); -CREATE TABLE "tech_retirement" ( - "tech" text, +CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "max_act" REAL, + "units" TEXT, "notes" TEXT, - PRIMARY KEY("tech"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech") -); -CREATE TABLE "sector_labels" ( - "sector" text, - PRIMARY KEY("sector") -); -INSERT INTO `sector_labels` VALUES ('supply'); -INSERT INTO `sector_labels` VALUES ('electric'); -INSERT INTO `sector_labels` VALUES ('transport'); -INSERT INTO `sector_labels` VALUES ('commercial'); -INSERT INTO `sector_labels` VALUES ('residential'); -INSERT INTO `sector_labels` VALUES ('industrial'); -CREATE TABLE "regions" ( - "regions" TEXT, - "region_note" TEXT, - PRIMARY KEY("regions") -); -INSERT INTO `regions` VALUES ('R1',NULL); -INSERT INTO `regions` VALUES ('R2',NULL); -CREATE TABLE "groups" ( - "group_name" text, - "notes" text, - PRIMARY KEY("group_name") -); -CREATE TABLE "commodity_labels" ( - "comm_labels" text, - "comm_labels_desc" text, - PRIMARY KEY("comm_labels") -); -INSERT INTO `commodity_labels` VALUES ('p','physical commodity'); -INSERT INTO `commodity_labels` VALUES ('e','emissions commodity'); -INSERT INTO `commodity_labels` VALUES ('d','demand commodity'); -CREATE TABLE "commodities" ( - "comm_name" text, - "flag" text, - "comm_desc" text, - PRIMARY KEY("comm_name"), - FOREIGN KEY("flag") REFERENCES "commodity_labels"("comm_labels") -); -INSERT INTO `commodities` VALUES ('ethos','p','dummy commodity to supply inputs (makes graph easier to read)'); -INSERT INTO `commodities` VALUES ('OIL','p','crude oil'); -INSERT INTO `commodities` VALUES ('NG','p','natural gas'); -INSERT INTO `commodities` VALUES ('URN','p','uranium'); -INSERT INTO `commodities` VALUES ('ETH','p','ethanol'); -INSERT INTO `commodities` VALUES ('SOL','p','solar insolation'); -INSERT INTO `commodities` VALUES ('GSL','p','gasoline'); -INSERT INTO `commodities` VALUES ('DSL','p','diesel'); -INSERT INTO `commodities` VALUES ('ELC','p','electricity'); -INSERT INTO `commodities` VALUES ('E10','p','gasoline blend with 10% ethanol'); -INSERT INTO `commodities` VALUES ('VMT','d','travel demand for vehicle-miles traveled'); -INSERT INTO `commodities` VALUES ('RH','d','demand for residential heating'); -INSERT INTO `commodities` VALUES ('CO2','e','CO2 emissions commodity'); -CREATE TABLE "TechOutputSplit" ( - "regions" TEXT, - "periods" integer, - "tech" text, - "output_comm" text, - "to_split" real, - "to_split_notes" text, - PRIMARY KEY("regions","periods","tech","output_comm"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech"), - FOREIGN KEY("output_comm") REFERENCES "commodities"("comm_name"), - FOREIGN KEY("periods") REFERENCES "time_periods"("t_periods") -); -INSERT INTO `TechOutputSplit` VALUES ('R1',2020,'S_OILREF','GSL',0.9,''); -INSERT INTO `TechOutputSplit` VALUES ('R1',2020,'S_OILREF','DSL',0.1,''); -INSERT INTO `TechOutputSplit` VALUES ('R1',2025,'S_OILREF','GSL',0.9,''); -INSERT INTO `TechOutputSplit` VALUES ('R1',2025,'S_OILREF','DSL',0.1,''); -INSERT INTO `TechOutputSplit` VALUES ('R1',2030,'S_OILREF','GSL',0.9,''); -INSERT INTO `TechOutputSplit` VALUES ('R1',2030,'S_OILREF','DSL',0.1,''); -INSERT INTO `TechOutputSplit` VALUES ('R2',2020,'S_OILREF','GSL',0.72,''); -INSERT INTO `TechOutputSplit` VALUES ('R2',2020,'S_OILREF','DSL',0.08,''); -INSERT INTO `TechOutputSplit` VALUES ('R2',2025,'S_OILREF','GSL',0.72,''); -INSERT INTO `TechOutputSplit` VALUES ('R2',2025,'S_OILREF','DSL',0.08,''); -INSERT INTO `TechOutputSplit` VALUES ('R2',2030,'S_OILREF','GSL',0.72,''); -INSERT INTO `TechOutputSplit` VALUES ('R2',2030,'S_OILREF','DSL',0.08,''); -CREATE TABLE "TechInputSplit" ( - "regions" TEXT, - "periods" integer, - "input_comm" text, - "tech" text, - "ti_split" real, - "ti_split_notes" text, - PRIMARY KEY("regions","periods","input_comm","tech"), - FOREIGN KEY("input_comm") REFERENCES "commodities"("comm_name"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech"), - FOREIGN KEY("periods") REFERENCES "time_periods"("t_periods") -); -INSERT INTO `TechInputSplit` VALUES ('R1',2020,'GSL','T_BLND',0.9,''); -INSERT INTO `TechInputSplit` VALUES ('R1',2020,'ETH','T_BLND',0.1,''); -INSERT INTO `TechInputSplit` VALUES ('R1',2025,'GSL','T_BLND',0.9,''); -INSERT INTO `TechInputSplit` VALUES ('R1',2025,'ETH','T_BLND',0.1,''); -INSERT INTO `TechInputSplit` VALUES ('R1',2030,'GSL','T_BLND',0.9,''); -INSERT INTO `TechInputSplit` VALUES ('R1',2030,'ETH','T_BLND',0.1,''); -INSERT INTO `TechInputSplit` VALUES ('R2',2020,'GSL','T_BLND',0.72,''); -INSERT INTO `TechInputSplit` VALUES ('R2',2020,'ETH','T_BLND',0.08,''); -INSERT INTO `TechInputSplit` VALUES ('R2',2025,'GSL','T_BLND',0.72,''); -INSERT INTO `TechInputSplit` VALUES ('R2',2025,'ETH','T_BLND',0.08,''); -INSERT INTO `TechInputSplit` VALUES ('R2',2030,'GSL','T_BLND',0.72,''); -INSERT INTO `TechInputSplit` VALUES ('R2',2030,'ETH','T_BLND',0.08,''); -CREATE TABLE "StorageDuration" ( - "regions" text, - "tech" text, - "duration" real, - "duration_notes" text, - PRIMARY KEY("regions","tech") -); -INSERT INTO `StorageDuration` VALUES ('R1','E_BATT',8.0,'8-hour duration specified as fraction of a day'); -INSERT INTO `StorageDuration` VALUES ('R2','E_BATT',8.0,'8-hour duration specified as fraction of a day'); -CREATE TABLE "SegFrac" ( - "season_name" text, - "time_of_day_name" text, - "segfrac" real CHECK("segfrac" >= 0 AND "segfrac" <= 1), - "segfrac_notes" text, - PRIMARY KEY("season_name","time_of_day_name"), - FOREIGN KEY("season_name") REFERENCES "time_season"("t_season"), - FOREIGN KEY("time_of_day_name") REFERENCES "time_of_day"("t_day") -); -INSERT INTO `SegFrac` VALUES ('spring','day',0.125,'Spring - Day'); -INSERT INTO `SegFrac` VALUES ('spring','night',0.125,'Spring - Night'); -INSERT INTO `SegFrac` VALUES ('summer','day',0.125,'Summer - Day'); -INSERT INTO `SegFrac` VALUES ('summer','night',0.125,'Summer - Night'); -INSERT INTO `SegFrac` VALUES ('fall','day',0.125,'Fall - Day'); -INSERT INTO `SegFrac` VALUES ('fall','night',0.125,'Fall - Night'); -INSERT INTO `SegFrac` VALUES ('winter','day',0.125,'Winter - Day'); -INSERT INTO `SegFrac` VALUES ('winter','night',0.125,'Winter - Night'); -CREATE TABLE "PlanningReserveMargin" ( - `regions` text, - `reserve_margin` REAL, - PRIMARY KEY(regions), - FOREIGN KEY(`regions`) REFERENCES regions -); -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"), - 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, - "sector" text, - "t_periods" integer, - "t_season" text, - "t_day" text, - "input_comm" text, - "tech" text, - "vintage" integer, - "output_comm" text, - "vflow_out" real, - PRIMARY KEY("regions","scenario","t_periods","t_season","t_day","input_comm","tech","vintage","output_comm"), - FOREIGN KEY("input_comm") REFERENCES "commodities"("comm_name"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech"), - FOREIGN KEY("sector") REFERENCES "sector_labels"("sector"), - FOREIGN KEY("t_day") REFERENCES "time_of_day"("t_day"), - FOREIGN KEY("t_season") REFERENCES "time_periods"("t_periods"), - FOREIGN KEY("t_periods") REFERENCES "time_periods"("t_periods"), - FOREIGN KEY("vintage") REFERENCES "time_periods"("t_periods"), - FOREIGN KEY("output_comm") REFERENCES "commodities"("comm_name") -); -CREATE TABLE "Output_VFlow_In" ( - "regions" text, - "scenario" text, - "sector" text, - "t_periods" integer, - "t_season" text, - "t_day" text, - "input_comm" text, - "tech" text, - "vintage" integer, - "output_comm" text, - "vflow_in" real, - PRIMARY KEY("regions","scenario","t_periods","t_season","t_day","input_comm","tech","vintage","output_comm"), - FOREIGN KEY("output_comm") REFERENCES "commodities"("comm_name"), - FOREIGN KEY("t_day") REFERENCES "time_of_day"("t_day"), - FOREIGN KEY("t_season") REFERENCES "time_periods"("t_periods"), - FOREIGN KEY("t_periods") REFERENCES "time_periods"("t_periods"), - FOREIGN KEY("input_comm") REFERENCES "commodities"("comm_name"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech"), - FOREIGN KEY("vintage") REFERENCES "time_periods"("t_periods"), - FOREIGN KEY("sector") REFERENCES "sector_labels"("sector") -); -CREATE TABLE "Output_Objective" ( - "scenario" text, - "objective_name" text, - "total_system_cost" real -); -CREATE TABLE "Output_Emissions" ( - "regions" text, - "scenario" text, - "sector" text, - "t_periods" integer, - "emissions_comm" text, - "tech" text, - "vintage" integer, - "emissions" real, - PRIMARY KEY("regions","scenario","t_periods","emissions_comm","tech","vintage"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech"), - FOREIGN KEY("emissions_comm") REFERENCES "EmissionActivity"("emis_comm"), - FOREIGN KEY("sector") REFERENCES "sector_labels"("sector"), - FOREIGN KEY("t_periods") REFERENCES "time_periods"("t_periods"), - FOREIGN KEY("vintage") REFERENCES "time_periods"("t_periods") -); -CREATE TABLE "Output_Curtailment" ( - "regions" text, - "scenario" text, - "sector" text, - "t_periods" integer, - "t_season" text, - "t_day" text, - "input_comm" text, - "tech" text, - "vintage" integer, - "output_comm" text, - "curtailment" real, - PRIMARY KEY("regions","scenario","t_periods","t_season","t_day","input_comm","tech","vintage","output_comm"), - FOREIGN KEY("output_comm") REFERENCES "commodities"("comm_name"), - FOREIGN KEY("t_day") REFERENCES "time_of_day"("t_day"), - FOREIGN KEY("input_comm") REFERENCES "commodities"("comm_name"), - FOREIGN KEY("vintage") REFERENCES "time_periods"("t_periods"), - FOREIGN KEY("t_periods") REFERENCES "time_periods"("t_periods"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech"), - FOREIGN KEY("t_season") REFERENCES "time_periods"("t_periods") -); -CREATE TABLE "Output_Costs" ( - "regions" text, - "scenario" text, - "sector" text, - "output_name" text, - "tech" text, - "vintage" integer, - "output_cost" real, - PRIMARY KEY("regions","scenario","output_name","tech","vintage"), - FOREIGN KEY("sector") REFERENCES "sector_labels"("sector"), - FOREIGN KEY("vintage") REFERENCES "time_periods"("t_periods"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech") -); -CREATE TABLE "Output_Duals" ( - "constraint_name" text, - "scenario" text, - "dual" real, - PRIMARY KEY("constraint_name","scenario") -); -CREATE TABLE "Output_CapacityByPeriodAndTech" ( - "regions" text, - "scenario" text, - "sector" text, - "t_periods" integer, - "tech" text, - "capacity" real, - PRIMARY KEY("regions","scenario","t_periods","tech"), - FOREIGN KEY("sector") REFERENCES "sector_labels"("sector"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech"), - FOREIGN KEY("t_periods") REFERENCES "time_periods"("t_periods") -); -CREATE TABLE "MyopicBaseyear" ( - "year" real - "notes" text -); -CREATE TABLE "MinGenGroupWeight" ( - "regions" text, - "tech" text, - "group_name" text, - "act_fraction" REAL, - "tech_desc" text, - PRIMARY KEY("tech","group_name","regions") -); -CREATE TABLE "MinGenGroupTarget" ( - "regions" text, - "periods" integer, - "group_name" text, - "min_act_g" real, - "notes" text, - PRIMARY KEY("periods","group_name","regions") -); -CREATE TABLE "MinCapacity" ( - "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, - "tech" text, - "minact" real, - "minact_units" text, - "minact_notes" text, - PRIMARY KEY("regions","periods","tech"), - FOREIGN KEY("periods") REFERENCES "time_periods"("t_periods"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech") -); -INSERT INTO `MinActivity` VALUES ('R1',2020,'T_GSL',35.0,'',''); -INSERT INTO `MinActivity` VALUES ('R1',2025,'T_GSL',35.0,'',''); -INSERT INTO `MinActivity` VALUES ('R1',2030,'T_GSL',35.0,'',''); -INSERT INTO `MinActivity` VALUES ('R2',2020,'T_GSL',15.0,'',''); -INSERT INTO `MinActivity` VALUES ('R2',2025,'T_GSL',15.0,'',''); -INSERT INTO `MinActivity` VALUES ('R2',2030,'T_GSL',15.0,'',''); -CREATE TABLE "MaxCapacity" ( - "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, - "tech" text, - "maxact" real, - "maxact_units" text, - "maxact_notes" text, - PRIMARY KEY("regions","periods","tech"), - FOREIGN KEY("periods") REFERENCES "time_periods"("t_periods"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech") -); -CREATE TABLE "LifetimeTech" ( - "regions" text, - "tech" text, - "life" real, - "life_notes" text, - PRIMARY KEY("regions","tech"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech") -); -INSERT INTO `LifetimeTech` VALUES ('R1','S_IMPETH',100.0,''); -INSERT INTO `LifetimeTech` VALUES ('R1','S_IMPOIL',100.0,''); -INSERT INTO `LifetimeTech` VALUES ('R1','S_IMPNG',100.0,''); -INSERT INTO `LifetimeTech` VALUES ('R1','S_IMPURN',100.0,''); -INSERT INTO `LifetimeTech` VALUES ('R1','S_OILREF',100.0,''); -INSERT INTO `LifetimeTech` VALUES ('R1','E_NGCC',30.0,''); -INSERT INTO `LifetimeTech` VALUES ('R1','E_SOLPV',30.0,''); -INSERT INTO `LifetimeTech` VALUES ('R1','E_BATT',20.0,''); -INSERT INTO `LifetimeTech` VALUES ('R1','E_NUCLEAR',50.0,''); -INSERT INTO `LifetimeTech` VALUES ('R1','T_BLND',100.0,''); -INSERT INTO `LifetimeTech` VALUES ('R1','T_DSL',12.0,''); -INSERT INTO `LifetimeTech` VALUES ('R1','T_GSL',12.0,''); -INSERT INTO `LifetimeTech` VALUES ('R1','T_EV',12.0,''); -INSERT INTO `LifetimeTech` VALUES ('R1','R_EH',20.0,''); -INSERT INTO `LifetimeTech` VALUES ('R1','R_NGH',20.0,''); -INSERT INTO `LifetimeTech` VALUES ('R2','S_IMPETH',100.0,''); -INSERT INTO `LifetimeTech` VALUES ('R2','S_IMPOIL',100.0,''); -INSERT INTO `LifetimeTech` VALUES ('R2','S_IMPNG',100.0,''); -INSERT INTO `LifetimeTech` VALUES ('R2','S_IMPURN',100.0,''); -INSERT INTO `LifetimeTech` VALUES ('R2','S_OILREF',100.0,''); -INSERT INTO `LifetimeTech` VALUES ('R2','E_NGCC',30.0,''); -INSERT INTO `LifetimeTech` VALUES ('R2','E_SOLPV',30.0,''); -INSERT INTO `LifetimeTech` VALUES ('R2','E_BATT',20.0,''); -INSERT INTO `LifetimeTech` VALUES ('R2','E_NUCLEAR',50.0,''); -INSERT INTO `LifetimeTech` VALUES ('R2','T_BLND',100.0,''); -INSERT INTO `LifetimeTech` VALUES ('R2','T_DSL',12.0,''); -INSERT INTO `LifetimeTech` VALUES ('R2','T_GSL',12.0,''); -INSERT INTO `LifetimeTech` VALUES ('R2','T_EV',12.0,''); -INSERT INTO `LifetimeTech` VALUES ('R2','R_EH',20.0,''); -INSERT INTO `LifetimeTech` VALUES ('R2','R_NGH',20.0,''); -INSERT INTO `LifetimeTech` VALUES ('R1-R2','E_TRANS',30.0,''); -INSERT INTO `LifetimeTech` VALUES ('R2-R1','E_TRANS',30.0,''); -CREATE TABLE "LifetimeProcess" ( - "regions" text, - "tech" text, - "vintage" integer, - "life_process" real, - "life_process_notes" text, - PRIMARY KEY("regions","tech","vintage"), - FOREIGN KEY("vintage") REFERENCES "time_periods"("t_periods"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech") -); -CREATE TABLE "LifetimeLoanTech" ( - "regions" text, - "tech" text, - "loan" real, - "loan_notes" text, - PRIMARY KEY("regions","tech"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech") -); -INSERT INTO `LifetimeLoanTech` VALUES ('R1','S_IMPETH',100.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R1','S_IMPOIL',100.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R1','S_IMPNG',100.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R1','S_IMPURN',100.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R1','S_OILREF',100.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R1','E_NGCC',30.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R1','E_SOLPV',30.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R1','E_BATT',20.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R1','E_NUCLEAR',50.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R1','T_BLND',100.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R1','T_DSL',12.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R1','T_GSL',12.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R1','T_EV',12.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R1','R_EH',20.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R1','R_NGH',20.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R2','S_IMPETH',100.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R2','S_IMPOIL',100.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R2','S_IMPNG',100.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R2','S_IMPURN',100.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R2','S_OILREF',100.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R2','E_NGCC',30.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R2','E_SOLPV',30.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R2','E_BATT',20.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R2','E_NUCLEAR',50.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R2','T_BLND',100.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R2','T_DSL',12.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R2','T_GSL',12.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R2','T_EV',12.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R2','R_EH',20.0,''); -INSERT INTO `LifetimeLoanTech` VALUES ('R2','R_NGH',20.0,''); -CREATE TABLE "GrowthRateSeed" ( - "regions" text, - "tech" text, - "growthrate_seed" real, - "growthrate_seed_units" text, - "growthrate_seed_notes" text, - PRIMARY KEY("regions","tech"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech") -); -CREATE TABLE "GrowthRateMax" ( - "regions" text, - "tech" text, - "growthrate_max" real, - "growthrate_max_notes" text, - PRIMARY KEY("regions","tech"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech") -); -CREATE TABLE "GlobalDiscountRate" ( - "rate" real -); -INSERT INTO `GlobalDiscountRate` VALUES (0.05); -CREATE TABLE "ExistingCapacity" ( - "regions" text, - "tech" text, - "vintage" integer, - "exist_cap" real, - "exist_cap_units" text, - "exist_cap_notes" text, - PRIMARY KEY("regions","tech","vintage"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech"), - FOREIGN KEY("vintage") REFERENCES "time_periods"("t_periods") -); -INSERT INTO `ExistingCapacity` VALUES ('R1','E_NUCLEAR',2015,0.07,'GW',''); -INSERT INTO `ExistingCapacity` VALUES ('R2','E_NUCLEAR',2015,0.03,'GW',''); -INSERT INTO `ExistingCapacity` VALUES ('R1-R2','E_TRANS',2015,10.0,'GW',''); -INSERT INTO `ExistingCapacity` VALUES ('R2-R1','E_TRANS',2015,10.0,'GW',''); -CREATE TABLE "EmissionLimit" ( - "regions" text, - "periods" integer, - "emis_comm" text, - "emis_limit" real, - "emis_limit_units" text, - "emis_limit_notes" text, - PRIMARY KEY("regions","periods","emis_comm"), - FOREIGN KEY("periods") REFERENCES "time_periods"("t_periods"), - FOREIGN KEY("emis_comm") REFERENCES "commodities"("comm_name") -); -INSERT INTO `EmissionLimit` VALUES ('R1',2020,'CO2',25000.0,'kT CO2',''); -INSERT INTO `EmissionLimit` VALUES ('R1',2025,'CO2',24000.0,'kT CO2',''); -INSERT INTO `EmissionLimit` VALUES ('R1',2030,'CO2',23000.0,'kT CO2',''); -INSERT INTO `EmissionLimit` VALUES ('global',2020,'CO2',37500.0,'kT CO2',''); -INSERT INTO `EmissionLimit` VALUES ('global',2025,'CO2',36000.0,'kT CO2',''); -INSERT INTO `EmissionLimit` VALUES ('global',2030,'CO2',34500.0,'kT CO2',''); -CREATE TABLE "EmissionActivity" ( - "regions" text, - "emis_comm" text, - "input_comm" text, - "tech" text, - "vintage" integer, - "output_comm" text, - "emis_act" real, - "emis_act_units" text, - "emis_act_notes" text, - PRIMARY KEY("regions","emis_comm","input_comm","tech","vintage","output_comm"), - FOREIGN KEY("vintage") REFERENCES "time_periods"("t_periods"), - FOREIGN KEY("input_comm") REFERENCES "commodities"("comm_name"), - FOREIGN KEY("output_comm") REFERENCES "commodities"("comm_name"), - FOREIGN KEY("emis_comm") REFERENCES "commodities"("comm_name"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech") -); -INSERT INTO `EmissionActivity` VALUES ('R1','CO2','ethos','S_IMPNG',2020,'NG',50.3,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO `EmissionActivity` VALUES ('R1','CO2','OIL','S_OILREF',2020,'GSL',67.2,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO `EmissionActivity` VALUES ('R1','CO2','OIL','S_OILREF',2020,'DSL',69.4,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO `EmissionActivity` VALUES ('R2','CO2','ethos','S_IMPNG',2020,'NG',50.3,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO `EmissionActivity` VALUES ('R2','CO2','OIL','S_OILREF',2020,'GSL',67.2,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO `EmissionActivity` VALUES ('R2','CO2','OIL','S_OILREF',2020,'DSL',69.4,'kT/PJ','taken from MIT Energy Fact Sheet'); -CREATE TABLE "Efficiency" ( - "regions" text, - "input_comm" text, - "tech" text, - "vintage" integer, - "output_comm" text, - "efficiency" real CHECK("efficiency" > 0), - "eff_notes" text, - PRIMARY KEY("regions","input_comm","tech","vintage","output_comm"), - FOREIGN KEY("output_comm") REFERENCES "commodities"("comm_name"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech"), - FOREIGN KEY("vintage") REFERENCES "time_periods"("t_periods"), - FOREIGN KEY("input_comm") REFERENCES "commodities"("comm_name") -); -INSERT INTO `Efficiency` VALUES ('R1','ethos','S_IMPETH',2020,'ETH',1.0,''); -INSERT INTO `Efficiency` VALUES ('R1','ethos','S_IMPOIL',2020,'OIL',1.0,''); -INSERT INTO `Efficiency` VALUES ('R1','ethos','S_IMPNG',2020,'NG',1.0,''); -INSERT INTO `Efficiency` VALUES ('R1','ethos','S_IMPURN',2020,'URN',1.0,''); -INSERT INTO `Efficiency` VALUES ('R1','OIL','S_OILREF',2020,'GSL',1.0,''); -INSERT INTO `Efficiency` VALUES ('R1','OIL','S_OILREF',2020,'DSL',1.0,''); -INSERT INTO `Efficiency` VALUES ('R1','ETH','T_BLND',2020,'E10',1.0,''); -INSERT INTO `Efficiency` VALUES ('R1','GSL','T_BLND',2020,'E10',1.0,''); -INSERT INTO `Efficiency` VALUES ('R1','NG','E_NGCC',2020,'ELC',0.55,''); -INSERT INTO `Efficiency` VALUES ('R1','NG','E_NGCC',2025,'ELC',0.55,''); -INSERT INTO `Efficiency` VALUES ('R1','NG','E_NGCC',2030,'ELC',0.55,''); -INSERT INTO `Efficiency` VALUES ('R1','SOL','E_SOLPV',2020,'ELC',1.0,''); -INSERT INTO `Efficiency` VALUES ('R1','SOL','E_SOLPV',2025,'ELC',1.0,''); -INSERT INTO `Efficiency` VALUES ('R1','SOL','E_SOLPV',2030,'ELC',1.0,''); -INSERT INTO `Efficiency` VALUES ('R1','URN','E_NUCLEAR',2015,'ELC',0.4,''); -INSERT INTO `Efficiency` VALUES ('R1','URN','E_NUCLEAR',2020,'ELC',0.4,''); -INSERT INTO `Efficiency` VALUES ('R1','URN','E_NUCLEAR',2025,'ELC',0.4,''); -INSERT INTO `Efficiency` VALUES ('R1','URN','E_NUCLEAR',2030,'ELC',0.4,''); -INSERT INTO `Efficiency` VALUES ('R1','ELC','E_BATT',2020,'ELC',0.85,''); -INSERT INTO `Efficiency` VALUES ('R1','ELC','E_BATT',2025,'ELC',0.85,''); -INSERT INTO `Efficiency` VALUES ('R1','ELC','E_BATT',2030,'ELC',0.85,''); -INSERT INTO `Efficiency` VALUES ('R1','E10','T_GSL',2020,'VMT',0.25,''); -INSERT INTO `Efficiency` VALUES ('R1','E10','T_GSL',2025,'VMT',0.25,''); -INSERT INTO `Efficiency` VALUES ('R1','E10','T_GSL',2030,'VMT',0.25,''); -INSERT INTO `Efficiency` VALUES ('R1','DSL','T_DSL',2020,'VMT',0.3,''); -INSERT INTO `Efficiency` VALUES ('R1','DSL','T_DSL',2025,'VMT',0.3,''); -INSERT INTO `Efficiency` VALUES ('R1','DSL','T_DSL',2030,'VMT',0.3,''); -INSERT INTO `Efficiency` VALUES ('R1','ELC','T_EV',2020,'VMT',0.89,''); -INSERT INTO `Efficiency` VALUES ('R1','ELC','T_EV',2025,'VMT',0.89,''); -INSERT INTO `Efficiency` VALUES ('R1','ELC','T_EV',2030,'VMT',0.89,''); -INSERT INTO `Efficiency` VALUES ('R1','ELC','R_EH',2020,'RH',1.0,''); -INSERT INTO `Efficiency` VALUES ('R1','ELC','R_EH',2025,'RH',1.0,''); -INSERT INTO `Efficiency` VALUES ('R1','ELC','R_EH',2030,'RH',1.0,''); -INSERT INTO `Efficiency` VALUES ('R1','NG','R_NGH',2020,'RH',0.85,''); -INSERT INTO `Efficiency` VALUES ('R1','NG','R_NGH',2025,'RH',0.85,''); -INSERT INTO `Efficiency` VALUES ('R1','NG','R_NGH',2030,'RH',0.85,''); -INSERT INTO `Efficiency` VALUES ('R2','ethos','S_IMPETH',2020,'ETH',1.0,''); -INSERT INTO `Efficiency` VALUES ('R2','ethos','S_IMPOIL',2020,'OIL',1.0,''); -INSERT INTO `Efficiency` VALUES ('R2','ethos','S_IMPNG',2020,'NG',1.0,''); -INSERT INTO `Efficiency` VALUES ('R2','ethos','S_IMPURN',2020,'URN',1.0,''); -INSERT INTO `Efficiency` VALUES ('R2','OIL','S_OILREF',2020,'GSL',1.0,''); -INSERT INTO `Efficiency` VALUES ('R2','OIL','S_OILREF',2020,'DSL',1.0,''); -INSERT INTO `Efficiency` VALUES ('R2','ETH','T_BLND',2020,'E10',1.0,''); -INSERT INTO `Efficiency` VALUES ('R2','GSL','T_BLND',2020,'E10',1.0,''); -INSERT INTO `Efficiency` VALUES ('R2','NG','E_NGCC',2020,'ELC',0.55,''); -INSERT INTO `Efficiency` VALUES ('R2','NG','E_NGCC',2025,'ELC',0.55,''); -INSERT INTO `Efficiency` VALUES ('R2','NG','E_NGCC',2030,'ELC',0.55,''); -INSERT INTO `Efficiency` VALUES ('R2','SOL','E_SOLPV',2020,'ELC',1.0,''); -INSERT INTO `Efficiency` VALUES ('R2','SOL','E_SOLPV',2025,'ELC',1.0,''); -INSERT INTO `Efficiency` VALUES ('R2','SOL','E_SOLPV',2030,'ELC',1.0,''); -INSERT INTO `Efficiency` VALUES ('R2','URN','E_NUCLEAR',2015,'ELC',0.4,''); -INSERT INTO `Efficiency` VALUES ('R2','URN','E_NUCLEAR',2020,'ELC',0.4,''); -INSERT INTO `Efficiency` VALUES ('R2','URN','E_NUCLEAR',2025,'ELC',0.4,''); -INSERT INTO `Efficiency` VALUES ('R2','URN','E_NUCLEAR',2030,'ELC',0.4,''); -INSERT INTO `Efficiency` VALUES ('R2','ELC','E_BATT',2020,'ELC',0.85,''); -INSERT INTO `Efficiency` VALUES ('R2','ELC','E_BATT',2025,'ELC',0.85,''); -INSERT INTO `Efficiency` VALUES ('R2','ELC','E_BATT',2030,'ELC',0.85,''); -INSERT INTO `Efficiency` VALUES ('R2','E10','T_GSL',2020,'VMT',0.25,''); -INSERT INTO `Efficiency` VALUES ('R2','E10','T_GSL',2025,'VMT',0.25,''); -INSERT INTO `Efficiency` VALUES ('R2','E10','T_GSL',2030,'VMT',0.25,''); -INSERT INTO `Efficiency` VALUES ('R2','DSL','T_DSL',2020,'VMT',0.3,''); -INSERT INTO `Efficiency` VALUES ('R2','DSL','T_DSL',2025,'VMT',0.3,''); -INSERT INTO `Efficiency` VALUES ('R2','DSL','T_DSL',2030,'VMT',0.3,''); -INSERT INTO `Efficiency` VALUES ('R2','ELC','T_EV',2020,'VMT',0.89,''); -INSERT INTO `Efficiency` VALUES ('R2','ELC','T_EV',2025,'VMT',0.89,''); -INSERT INTO `Efficiency` VALUES ('R2','ELC','T_EV',2030,'VMT',0.89,''); -INSERT INTO `Efficiency` VALUES ('R2','ELC','R_EH',2020,'RH',1.0,''); -INSERT INTO `Efficiency` VALUES ('R2','ELC','R_EH',2025,'RH',1.0,''); -INSERT INTO `Efficiency` VALUES ('R2','ELC','R_EH',2030,'RH',1.0,''); -INSERT INTO `Efficiency` VALUES ('R2','NG','R_NGH',2020,'RH',0.85,''); -INSERT INTO `Efficiency` VALUES ('R2','NG','R_NGH',2025,'RH',0.85,''); -INSERT INTO `Efficiency` VALUES ('R2','NG','R_NGH',2030,'RH',0.85,''); -INSERT INTO `Efficiency` VALUES ('R1-R2','ELC','E_TRANS',2015,'ELC',0.9,''); -INSERT INTO `Efficiency` VALUES ('R2-R1','ELC','E_TRANS',2015,'ELC',0.9,''); -CREATE TABLE "DiscountRate" ( - "regions" text, - "tech" text, - "vintage" integer, - "tech_rate" real, - "tech_rate_notes" text, - PRIMARY KEY("regions","tech","vintage"), - FOREIGN KEY("vintage") REFERENCES "time_periods"("t_periods"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech") -); -CREATE TABLE "DemandSpecificDistribution" ( - "regions" text, - "season_name" text, - "time_of_day_name" text, - "demand_name" text, - "dsd" real CHECK("dsd" >= 0 AND "dsd" <= 1), - "dsd_notes" text, - PRIMARY KEY("regions","season_name","time_of_day_name","demand_name"), - FOREIGN KEY("time_of_day_name") REFERENCES "time_of_day"("t_day"), - FOREIGN KEY("season_name") REFERENCES "time_season"("t_season"), - FOREIGN KEY("demand_name") REFERENCES "commodities"("comm_name") -); -INSERT INTO `DemandSpecificDistribution` VALUES ('R1','spring','day','RH',0.05,''); -INSERT INTO `DemandSpecificDistribution` VALUES ('R1','spring','night','RH',0.1,''); -INSERT INTO `DemandSpecificDistribution` VALUES ('R1','summer','day','RH',0.0,''); -INSERT INTO `DemandSpecificDistribution` VALUES ('R1','summer','night','RH',0.0,''); -INSERT INTO `DemandSpecificDistribution` VALUES ('R1','fall','day','RH',0.05,''); -INSERT INTO `DemandSpecificDistribution` VALUES ('R1','fall','night','RH',0.1,''); -INSERT INTO `DemandSpecificDistribution` VALUES ('R1','winter','day','RH',0.3,''); -INSERT INTO `DemandSpecificDistribution` VALUES ('R1','winter','night','RH',0.4,''); -INSERT INTO `DemandSpecificDistribution` VALUES ('R2','spring','day','RH',0.05,''); -INSERT INTO `DemandSpecificDistribution` VALUES ('R2','spring','night','RH',0.1,''); -INSERT INTO `DemandSpecificDistribution` VALUES ('R2','summer','day','RH',0.0,''); -INSERT INTO `DemandSpecificDistribution` VALUES ('R2','summer','night','RH',0.0,''); -INSERT INTO `DemandSpecificDistribution` VALUES ('R2','fall','day','RH',0.05,''); -INSERT INTO `DemandSpecificDistribution` VALUES ('R2','fall','night','RH',0.1,''); -INSERT INTO `DemandSpecificDistribution` VALUES ('R2','winter','day','RH',0.3,''); -INSERT INTO `DemandSpecificDistribution` VALUES ('R2','winter','night','RH',0.4,''); -CREATE TABLE "Demand" ( - "regions" text, - "periods" integer, - "demand_comm" text, - "demand" real, - "demand_units" text, - "demand_notes" text, - PRIMARY KEY("regions","periods","demand_comm"), - FOREIGN KEY("demand_comm") REFERENCES "commodities"("comm_name"), - FOREIGN KEY("periods") REFERENCES "time_periods"("t_periods") -); -INSERT INTO `Demand` VALUES ('R1',2020,'RH',30.0,'',''); -INSERT INTO `Demand` VALUES ('R1',2025,'RH',33.0,'',''); -INSERT INTO `Demand` VALUES ('R1',2030,'RH',36.0,'',''); -INSERT INTO `Demand` VALUES ('R1',2020,'VMT',84.0,'',''); -INSERT INTO `Demand` VALUES ('R1',2025,'VMT',91.0,'',''); -INSERT INTO `Demand` VALUES ('R1',2030,'VMT',98.0,'',''); -INSERT INTO `Demand` VALUES ('R2',2020,'RH',70.0,'',''); -INSERT INTO `Demand` VALUES ('R2',2025,'RH',77.0,'',''); -INSERT INTO `Demand` VALUES ('R2',2030,'RH',84.0,'',''); -INSERT INTO `Demand` VALUES ('R2',2020,'VMT',36.0,'',''); -INSERT INTO `Demand` VALUES ('R2',2025,'VMT',39.0,'',''); -INSERT INTO `Demand` VALUES ('R2',2030,'VMT',42.0,'',''); -CREATE TABLE "CostVariable" ( - "regions" text NOT NULL, - "periods" integer NOT NULL, - "tech" text NOT NULL, - "vintage" integer NOT NULL, - "cost_variable" real, - "cost_variable_units" text, - "cost_variable_notes" text, - PRIMARY KEY("regions","periods","tech","vintage"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech"), - FOREIGN KEY("periods") REFERENCES "time_periods"("t_periods"), - FOREIGN KEY("vintage") REFERENCES "time_periods"("t_periods") -); -INSERT INTO `CostVariable` VALUES ('R1',2020,'S_IMPETH',2020,32.0,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1',2025,'S_IMPETH',2020,32.0,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1',2030,'S_IMPETH',2020,32.0,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1',2020,'S_IMPOIL',2020,20.0,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1',2025,'S_IMPOIL',2020,20.0,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1',2030,'S_IMPOIL',2020,20.0,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1',2020,'S_IMPNG',2020,4.0,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1',2025,'S_IMPNG',2020,4.0,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1',2030,'S_IMPNG',2020,4.0,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1',2020,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1',2025,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1',2030,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1',2020,'E_NGCC',2020,1.6,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1',2025,'E_NGCC',2020,1.6,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1',2025,'E_NGCC',2025,1.7,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1',2030,'E_NGCC',2020,1.6,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1',2030,'E_NGCC',2025,1.7,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1',2030,'E_NGCC',2030,1.8,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1',2020,'E_NUCLEAR',2020,0.24,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1',2025,'E_NUCLEAR',2020,0.24,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1',2025,'E_NUCLEAR',2025,0.25,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1',2030,'E_NUCLEAR',2020,0.24,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1',2030,'E_NUCLEAR',2025,0.25,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1',2030,'E_NUCLEAR',2030,0.26,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2020,'S_IMPETH',2020,25.6,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2025,'S_IMPETH',2020,25.6,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2030,'S_IMPETH',2020,25.6,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2020,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2025,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2030,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2020,'S_IMPNG',2020,3.2,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2025,'S_IMPNG',2020,3.2,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2030,'S_IMPNG',2020,3.2,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2020,'S_OILREF',2020,0.8,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2025,'S_OILREF',2020,0.8,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2030,'S_OILREF',2020,0.8,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2020,'E_NGCC',2020,1.28,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2025,'E_NGCC',2020,1.28,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2025,'E_NGCC',2025,1.36,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2030,'E_NGCC',2020,1.28,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2030,'E_NGCC',2025,1.36,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2030,'E_NGCC',2030,1.44,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2020,'E_NUCLEAR',2020,0.192,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2025,'E_NUCLEAR',2020,0.192,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2025,'E_NUCLEAR',2025,0.2,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2030,'E_NUCLEAR',2020,0.192,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2030,'E_NUCLEAR',2025,0.2,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2',2030,'E_NUCLEAR',2030,0.208,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1-R2',2020,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1-R2',2025,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R1-R2',2030,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2-R1',2020,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2-R1',2025,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO `CostVariable` VALUES ('R2-R1',2030,'E_TRANS',2015,0.1,'$M/PJ',''); -CREATE TABLE "CostInvest" ( - "regions" text, - "tech" text, - "vintage" integer, - "cost_invest" real, - "cost_invest_units" text, - "cost_invest_notes" text, - PRIMARY KEY("regions","tech","vintage"), - FOREIGN KEY("vintage") REFERENCES "time_periods"("t_periods"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech") -); -INSERT INTO `CostInvest` VALUES ('R1','E_NGCC',2020,1050.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R1','E_NGCC',2025,1025.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R1','E_NGCC',2030,1000.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R1','E_SOLPV',2020,900.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R1','E_SOLPV',2025,560.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R1','E_SOLPV',2030,800.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R1','E_NUCLEAR',2020,6145.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R1','E_NUCLEAR',2025,6045.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R1','E_NUCLEAR',2030,5890.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R1','E_BATT',2020,1150.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R1','E_BATT',2025,720.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R1','E_BATT',2030,480.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R1','T_GSL',2020,2570.0,'$/bvmt/yr',''); -INSERT INTO `CostInvest` VALUES ('R1','T_GSL',2025,2700.0,'$/bvmt/yr',''); -INSERT INTO `CostInvest` VALUES ('R1','T_GSL',2030,2700.0,'$/bvmt/yr',''); -INSERT INTO `CostInvest` VALUES ('R1','T_DSL',2020,2715.0,'$/bvmt/yr',''); -INSERT INTO `CostInvest` VALUES ('R1','T_DSL',2025,2810.0,'$/bvmt/yr',''); -INSERT INTO `CostInvest` VALUES ('R1','T_DSL',2030,2810.0,'$/bvmt/yr',''); -INSERT INTO `CostInvest` VALUES ('R1','T_EV',2020,3100.0,'$/bvmt/yr',''); -INSERT INTO `CostInvest` VALUES ('R1','T_EV',2025,3030.0,'$/bvmt/yr',''); -INSERT INTO `CostInvest` VALUES ('R1','T_EV',2030,2925.0,'$/bvmt/yr',''); -INSERT INTO `CostInvest` VALUES ('R1','R_EH',2020,4.1,'$/PJ/yr',''); -INSERT INTO `CostInvest` VALUES ('R1','R_EH',2025,4.1,'$/PJ/yr',''); -INSERT INTO `CostInvest` VALUES ('R1','R_EH',2030,4.1,'$/PJ/yr',''); -INSERT INTO `CostInvest` VALUES ('R1','R_NGH',2020,7.6,'$/PJ/yr',''); -INSERT INTO `CostInvest` VALUES ('R1','R_NGH',2025,7.6,'$/PJ/yr',''); -INSERT INTO `CostInvest` VALUES ('R1','R_NGH',2030,7.6,'$/PJ/yr',''); -INSERT INTO `CostInvest` VALUES ('R2','E_NGCC',2020,840.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R2','E_NGCC',2025,820.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R2','E_NGCC',2030,800.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R2','E_SOLPV',2020,720.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R2','E_SOLPV',2025,448.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R2','E_SOLPV',2030,640.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R2','E_NUCLEAR',2020,4916.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R2','E_NUCLEAR',2025,4836.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R2','E_NUCLEAR',2030,4712.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R2','E_BATT',2020,920.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R2','E_BATT',2025,576.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R2','E_BATT',2030,384.0,'$M/GW',''); -INSERT INTO `CostInvest` VALUES ('R2','T_GSL',2020,2056.0,'$/bvmt/yr',''); -INSERT INTO `CostInvest` VALUES ('R2','T_GSL',2025,2160.0,'$/bvmt/yr',''); -INSERT INTO `CostInvest` VALUES ('R2','T_GSL',2030,2160.0,'$/bvmt/yr',''); -INSERT INTO `CostInvest` VALUES ('R2','T_DSL',2020,2172.0,'$/bvmt/yr',''); -INSERT INTO `CostInvest` VALUES ('R2','T_DSL',2025,2248.0,'$/bvmt/yr',''); -INSERT INTO `CostInvest` VALUES ('R2','T_DSL',2030,2248.0,'$/bvmt/yr',''); -INSERT INTO `CostInvest` VALUES ('R2','T_EV',2020,2480.0,'$/bvmt/yr',''); -INSERT INTO `CostInvest` VALUES ('R2','T_EV',2025,2424.0,'$/bvmt/yr',''); -INSERT INTO `CostInvest` VALUES ('R2','T_EV',2030,2340.0,'$/bvmt/yr',''); -INSERT INTO `CostInvest` VALUES ('R2','R_EH',2020,3.28,'$/PJ/yr',''); -INSERT INTO `CostInvest` VALUES ('R2','R_EH',2025,3.28,'$/PJ/yr',''); -INSERT INTO `CostInvest` VALUES ('R2','R_EH',2030,3.28,'$/PJ/yr',''); -INSERT INTO `CostInvest` VALUES ('R2','R_NGH',2020,6.08,'$/PJ/yr',''); -INSERT INTO `CostInvest` VALUES ('R2','R_NGH',2025,6.08,'$/PJ/yr',''); -INSERT INTO `CostInvest` VALUES ('R2','R_NGH',2030,6.08,'$/PJ/yr',''); -CREATE TABLE "CostFixed" ( - "regions" text NOT NULL, - "periods" integer NOT NULL, - "tech" text NOT NULL, - "vintage" integer NOT NULL, - "cost_fixed" real, - "cost_fixed_units" text, - "cost_fixed_notes" text, - PRIMARY KEY("regions","periods","tech","vintage"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech"), - FOREIGN KEY("periods") REFERENCES "time_periods"("t_periods"), - FOREIGN KEY("vintage") REFERENCES "time_periods"("t_periods") -); -INSERT INTO `CostFixed` VALUES ('R1',2020,'E_NGCC',2020,30.6,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R1',2025,'E_NGCC',2020,9.78,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R1',2025,'E_NGCC',2025,9.78,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R1',2030,'E_NGCC',2020,9.78,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R1',2030,'E_NGCC',2025,9.78,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R1',2030,'E_NGCC',2030,9.78,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R1',2020,'E_SOLPV',2020,10.4,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R1',2025,'E_SOLPV',2020,10.4,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R1',2025,'E_SOLPV',2025,9.1,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R1',2030,'E_SOLPV',2020,10.4,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R1',2030,'E_SOLPV',2025,9.1,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R1',2030,'E_SOLPV',2030,9.1,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R1',2020,'E_NUCLEAR',2020,98.1,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R1',2025,'E_NUCLEAR',2020,98.1,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R1',2025,'E_NUCLEAR',2025,98.1,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R1',2030,'E_NUCLEAR',2020,98.1,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R1',2030,'E_NUCLEAR',2025,98.1,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R1',2030,'E_NUCLEAR',2030,98.1,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R1',2020,'E_BATT',2020,7.05,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R1',2025,'E_BATT',2020,7.05,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R1',2025,'E_BATT',2025,7.05,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R1',2030,'E_BATT',2020,7.05,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R1',2030,'E_BATT',2025,7.05,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R1',2030,'E_BATT',2030,7.05,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2020,'E_NGCC',2020,24.48,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2025,'E_NGCC',2020,7.824,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2025,'E_NGCC',2025,7.824,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2030,'E_NGCC',2020,7.824,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2030,'E_NGCC',2025,7.824,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2030,'E_NGCC',2030,7.824,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2020,'E_SOLPV',2020,8.32,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2025,'E_SOLPV',2020,8.32,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2025,'E_SOLPV',2025,7.28,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2030,'E_SOLPV',2020,8.32,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2030,'E_SOLPV',2025,7.28,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2030,'E_SOLPV',2030,7.28,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2020,'E_NUCLEAR',2020,78.48,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2025,'E_NUCLEAR',2020,78.48,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2025,'E_NUCLEAR',2025,78.48,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2030,'E_NUCLEAR',2020,78.48,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2030,'E_NUCLEAR',2025,78.48,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2030,'E_NUCLEAR',2030,78.48,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2020,'E_BATT',2020,5.64,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2025,'E_BATT',2020,5.64,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2025,'E_BATT',2025,5.64,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2030,'E_BATT',2020,5.64,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2030,'E_BATT',2025,5.64,'$M/GWyr',''); -INSERT INTO `CostFixed` VALUES ('R2',2030,'E_BATT',2030,5.64,'$M/GWyr',''); -CREATE TABLE "CapacityToActivity" ( - "regions" text, - "tech" text, - "c2a" real, - "c2a_notes" TEXT, - PRIMARY KEY("regions","tech"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech") -); -INSERT INTO `CapacityToActivity` VALUES ('R1','S_IMPETH',1.0,''); -INSERT INTO `CapacityToActivity` VALUES ('R1','S_IMPOIL',1.0,''); -INSERT INTO `CapacityToActivity` VALUES ('R1','S_IMPNG',1.0,''); -INSERT INTO `CapacityToActivity` VALUES ('R1','S_IMPURN',1.0,''); -INSERT INTO `CapacityToActivity` VALUES ('R1','S_OILREF',1.0,''); -INSERT INTO `CapacityToActivity` VALUES ('R1','E_NGCC',31.54,''); -INSERT INTO `CapacityToActivity` VALUES ('R1','E_SOLPV',31.54,''); -INSERT INTO `CapacityToActivity` VALUES ('R1','E_BATT',31.54,''); -INSERT INTO `CapacityToActivity` VALUES ('R1','E_NUCLEAR',31.54,''); -INSERT INTO `CapacityToActivity` VALUES ('R1','T_BLND',1.0,''); -INSERT INTO `CapacityToActivity` VALUES ('R1','T_DSL',1.0,''); -INSERT INTO `CapacityToActivity` VALUES ('R1','T_GSL',1.0,''); -INSERT INTO `CapacityToActivity` VALUES ('R1','T_EV',1.0,''); -INSERT INTO `CapacityToActivity` VALUES ('R1','R_EH',1.0,''); -INSERT INTO `CapacityToActivity` VALUES ('R1','R_NGH',1.0,''); -INSERT INTO `CapacityToActivity` VALUES ('R2','S_IMPETH',1.0,''); -INSERT INTO `CapacityToActivity` VALUES ('R2','S_IMPOIL',1.0,''); -INSERT INTO `CapacityToActivity` VALUES ('R2','S_IMPNG',1.0,''); -INSERT INTO `CapacityToActivity` VALUES ('R2','S_IMPURN',1.0,''); -INSERT INTO `CapacityToActivity` VALUES ('R2','S_OILREF',1.0,''); -INSERT INTO `CapacityToActivity` VALUES ('R2','E_NGCC',31.54,''); -INSERT INTO `CapacityToActivity` VALUES ('R2','E_SOLPV',31.54,''); -INSERT INTO `CapacityToActivity` VALUES ('R2','E_BATT',31.54,''); -INSERT INTO `CapacityToActivity` VALUES ('R2','E_NUCLEAR',31.54,''); -INSERT INTO `CapacityToActivity` VALUES ('R2','T_BLND',1.0,''); -INSERT INTO `CapacityToActivity` VALUES ('R2','T_DSL',1.0,''); -INSERT INTO `CapacityToActivity` VALUES ('R2','T_GSL',1.0,''); -INSERT INTO `CapacityToActivity` VALUES ('R2','T_EV',1.0,''); -INSERT INTO `CapacityToActivity` VALUES ('R2','R_EH',1.0,''); -INSERT INTO `CapacityToActivity` VALUES ('R2','R_NGH',1.0,''); -INSERT INTO `CapacityToActivity` VALUES ('R1-R2','E_TRANS',31.54,''); -INSERT INTO `CapacityToActivity` VALUES ('R2-R1','E_TRANS',31.54,''); -CREATE TABLE "CapacityFactorTech" ( - "regions" text, - "season_name" text, - "time_of_day_name" text, - "tech" text, - "cf_tech" real CHECK("cf_tech" >= 0 AND "cf_tech" <= 1), - "cf_tech_notes" text, - PRIMARY KEY("regions","season_name","time_of_day_name","tech"), - FOREIGN KEY("season_name") REFERENCES "time_season"("t_season"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech"), - FOREIGN KEY("time_of_day_name") REFERENCES "time_of_day"("t_day") -); -INSERT INTO `CapacityFactorTech` VALUES ('R1','spring','day','E_SOLPV',0.6,''); -INSERT INTO `CapacityFactorTech` VALUES ('R1','spring','night','E_SOLPV',0.0,''); -INSERT INTO `CapacityFactorTech` VALUES ('R1','summer','day','E_SOLPV',0.6,''); -INSERT INTO `CapacityFactorTech` VALUES ('R1','summer','night','E_SOLPV',0.0,''); -INSERT INTO `CapacityFactorTech` VALUES ('R1','fall','day','E_SOLPV',0.6,''); -INSERT INTO `CapacityFactorTech` VALUES ('R1','fall','night','E_SOLPV',0.0,''); -INSERT INTO `CapacityFactorTech` VALUES ('R1','winter','day','E_SOLPV',0.6,''); -INSERT INTO `CapacityFactorTech` VALUES ('R1','winter','night','E_SOLPV',0.0,''); -INSERT INTO `CapacityFactorTech` VALUES ('R2','spring','day','E_SOLPV',0.48,''); -INSERT INTO `CapacityFactorTech` VALUES ('R2','spring','night','E_SOLPV',0.0,''); -INSERT INTO `CapacityFactorTech` VALUES ('R2','summer','day','E_SOLPV',0.48,''); -INSERT INTO `CapacityFactorTech` VALUES ('R2','summer','night','E_SOLPV',0.0,''); -INSERT INTO `CapacityFactorTech` VALUES ('R2','fall','day','E_SOLPV',0.48,''); -INSERT INTO `CapacityFactorTech` VALUES ('R2','fall','night','E_SOLPV',0.0,''); -INSERT INTO `CapacityFactorTech` VALUES ('R2','winter','day','E_SOLPV',0.48,''); -INSERT INTO `CapacityFactorTech` VALUES ('R2','winter','night','E_SOLPV',0.0,''); -CREATE TABLE "CapacityFactorProcess" ( - "regions" text, - "season_name" text, - "time_of_day_name" text, - "tech" text, - "vintage" integer, - "cf_process" real CHECK("cf_process" >= 0 AND "cf_process" <= 1), - "cf_process_notes" text, - PRIMARY KEY("regions","season_name","time_of_day_name","tech","vintage"), - FOREIGN KEY("tech") REFERENCES "technologies"("tech"), - FOREIGN KEY("season_name") REFERENCES "time_season"("t_season"), - FOREIGN KEY("time_of_day_name") REFERENCES "time_of_day"("t_day") -); -CREATE TABLE "CapacityCredit" ( - "regions" text, - "periods" integer, - "tech" text, - "vintage" integer, - "cf_tech" real CHECK("cf_tech" >= 0 AND "cf_tech" <= 1), - "cf_tech_notes" text, - PRIMARY KEY("regions","periods","tech","vintage") -); -CREATE TABLE "MaxResource" ( - "regions" text, - "tech" text, - "maxres" real, - "maxres_units" text, - "maxres_notes" text, - FOREIGN KEY("tech") REFERENCES "technologies"("tech"), - PRIMARY KEY("regions","tech") -); -CREATE TABLE "LinkedTechs" ( - "primary_region" text, - "primary_tech" text, - "emis_comm" text, - "linked_tech" text, - "tech_linked_notes" text, - FOREIGN KEY("primary_tech") REFERENCES "technologies"("tech"), - FOREIGN KEY("linked_tech") REFERENCES "technologies"("tech"), - FOREIGN KEY("emis_comm") REFERENCES "commodities"("comm_name"), - PRIMARY KEY("primary_region","primary_tech", "emis_comm") + PRIMARY KEY("region","period","season","tech") +); +CREATE TABLE RPSRequirement +( + region TEXT NOT NULL + REFERENCES Region (region), + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech_group TEXT NOT NULL + REFERENCES TechGroup (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE TechGroupMember +( + group_name TEXT + REFERENCES TechGroup (group_name), + tech TEXT + REFERENCES Technology (tech), + PRIMARY KEY (group_name, tech) +); +CREATE TABLE Technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES TechnologyType (label) +); +INSERT INTO Technology VALUES('S_IMPETH','r','supply','','',1,0,0,0,0,0,0,' imported ethanol'); +INSERT INTO Technology VALUES('S_IMPOIL','r','supply','','',1,0,0,0,0,0,0,' imported crude oil'); +INSERT INTO Technology VALUES('S_IMPNG','r','supply','','',1,0,0,0,0,0,0,' imported natural gas'); +INSERT INTO Technology VALUES('S_IMPURN','r','supply','','',1,0,0,0,0,0,0,' imported uranium'); +INSERT INTO Technology VALUES('S_OILREF','p','supply','','',0,0,0,1,0,0,0,' crude oil refinery'); +INSERT INTO Technology VALUES('E_NGCC','p','electric','','',0,0,0,0,0,0,0,' natural gas combined-cycle'); +INSERT INTO Technology VALUES('E_SOLPV','p','electric','','',0,0,0,0,0,0,0,' solar photovoltaic'); +INSERT INTO Technology VALUES('E_BATT','ps','electric','','',0,0,0,0,0,0,0,' lithium-ion battery'); +INSERT INTO Technology VALUES('E_NUCLEAR','pb','electric','','',0,0,0,0,0,0,0,' nuclear power plant'); +INSERT INTO Technology VALUES('T_BLND','p','transport','','',0,0,0,0,0,0,0,'ethanol - gasoline blending process'); +INSERT INTO Technology VALUES('T_DSL','p','transport','','',0,0,0,0,0,0,0,'diesel vehicle'); +INSERT INTO Technology VALUES('T_GSL','p','transport','','',0,0,0,0,0,0,0,'gasoline vehicle'); +INSERT INTO Technology VALUES('T_EV','p','transport','','',0,0,0,0,0,0,0,'electric vehicle'); +INSERT INTO Technology VALUES('R_EH','p','residential','','',0,0,0,0,0,0,0,' electric residential heating'); +INSERT INTO Technology VALUES('R_NGH','p','residential','','',0,0,0,0,0,0,0,' natural gas residential heating'); +INSERT INTO Technology VALUES('E_TRANS','p','electric','','',0,0,0,0,0,0,1,'electric transmission'); +CREATE TABLE OutputCost +( + scenario TEXT, + region TEXT, + period INTEGER, + tech TEXT, + vintage INTEGER, + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES TimePeriod (period), + FOREIGN KEY (tech) REFERENCES Technology (tech) ); COMMIT; +PRAGMA FOREIGN_KEYS = 1; \ No newline at end of file diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 44de4a156..01ce296c2 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -9,7 +9,8 @@ CREATE TABLE MetaData ); INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); +INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); CREATE TABLE MetaDataReal ( element TEXT, @@ -58,6 +59,8 @@ CREATE TABLE CapacityCredit CREATE TABLE CapacityFactorProcess ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -67,24 +70,32 @@ CREATE TABLE CapacityFactorProcess vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, season, tod, tech, vintage), + PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorProcess VALUES('utopia','inter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','inter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','winter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','winter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','summer','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','summer','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','inter','day','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','inter','night','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','winter','day','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','winter','night','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','summer','day','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','summer','night','E31',2010,0.2756000000000000116,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','day','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','night','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','day','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','night','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','day','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','night','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2010,0.27560000000000002273,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2010,0.27560000000000002273,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2010,0.27560000000000002273,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2010,0.27560000000000002273,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2010,0.27560000000000002273,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2010,0.27560000000000002273,''); CREATE TABLE CapacityFactorTech ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -93,39 +104,99 @@ CREATE TABLE CapacityFactorTech REFERENCES Technology (tech), factor REAL, notes TEXT, - PRIMARY KEY (region, season, tod, tech), + PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E70',0.8,''); CREATE TABLE CapacityToActivity ( region TEXT, @@ -135,11 +206,11 @@ CREATE TABLE CapacityToActivity notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO CapacityToActivity VALUES('utopia','E01',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('utopia','E21',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('utopia','E31',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('utopia','E51',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('utopia','E70',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('utopia','E01',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('utopia','E21',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('utopia','E31',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('utopia','E51',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('utopia','E70',31.539999999999999147,''); INSERT INTO CapacityToActivity VALUES('utopia','RHE',1.0,''); INSERT INTO CapacityToActivity VALUES('utopia','RHO',1.0,''); INSERT INTO CapacityToActivity VALUES('utopia','RL1',1.0,''); @@ -175,6 +246,7 @@ CREATE TABLE CommodityType PRIMARY KEY, description TEXT ); +INSERT INTO CommodityType VALUES('a','annual commodity'); INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); @@ -263,10 +335,10 @@ INSERT INTO CostFixed VALUES('utopia',2000,'RHO',2000,1.0,'',''); INSERT INTO CostFixed VALUES('utopia',2010,'RHO',1990,1.0,'',''); INSERT INTO CostFixed VALUES('utopia',2010,'RHO',2000,1.0,'',''); INSERT INTO CostFixed VALUES('utopia',2010,'RHO',2010,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1980,9.46000000000000086,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1990,9.46000000000000086,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'RL1',2000,9.46000000000000086,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'RL1',2010,9.46000000000000086,'',''); +INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1980,9.4600000000000008526,'',''); +INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1990,9.4600000000000008526,'',''); +INSERT INTO CostFixed VALUES('utopia',2000,'RL1',2000,9.4600000000000008526,'',''); +INSERT INTO CostFixed VALUES('utopia',2010,'RL1',2010,9.4600000000000008526,'',''); INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1970,52.0,'',''); INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1980,52.0,'',''); INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1990,52.0,'',''); @@ -362,36 +434,36 @@ INSERT INTO CostVariable VALUES('utopia',2010,'IMPOIL1',1990,8.0,'',''); INSERT INTO CostVariable VALUES('utopia',1990,'IMPURN1',1990,2.0,'',''); INSERT INTO CostVariable VALUES('utopia',2000,'IMPURN1',1990,2.0,'',''); INSERT INTO CostVariable VALUES('utopia',2010,'IMPURN1',1990,2.0,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1960,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1970,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1980,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1990,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1970,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1980,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1990,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',2000,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',1980,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',1990,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',2000,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',2010,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1960,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1970,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1980,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1990,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',1970,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',1980,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',1990,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',2000,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',1980,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',1990,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',2000,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',2010,0.3,'',''); INSERT INTO CostVariable VALUES('utopia',1990,'E21',1990,1.5,'',''); INSERT INTO CostVariable VALUES('utopia',2000,'E21',1990,1.5,'',''); INSERT INTO CostVariable VALUES('utopia',2010,'E21',1990,1.5,'',''); INSERT INTO CostVariable VALUES('utopia',2000,'E21',2000,1.5,'',''); INSERT INTO CostVariable VALUES('utopia',2010,'E21',2000,1.5,'',''); INSERT INTO CostVariable VALUES('utopia',2010,'E21',2010,1.5,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1960,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1970,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1980,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1990,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1970,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1980,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1990,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',2000,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',1980,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',1990,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',2000,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',2010,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1960,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1970,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1980,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1990,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',1970,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',1980,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',1990,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',2000,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',1980,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',1990,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',2000,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',2010,0.4,'',''); INSERT INTO CostVariable VALUES('utopia',1990,'SRE',1990,10.0,'',''); INSERT INTO CostVariable VALUES('utopia',2000,'SRE',1990,10.0,'',''); INSERT INTO CostVariable VALUES('utopia',2000,'SRE',2000,10.0,'',''); @@ -410,18 +482,20 @@ CREATE TABLE Demand notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO Demand VALUES('utopia',1990,'RH',25.19999999999999929,'',''); -INSERT INTO Demand VALUES('utopia',2000,'RH',37.79999999999999715,'',''); -INSERT INTO Demand VALUES('utopia',2010,'RH',56.70000000000000284,'',''); -INSERT INTO Demand VALUES('utopia',1990,'RL',5.599999999999999645,'',''); -INSERT INTO Demand VALUES('utopia',2000,'RL',8.400000000000000355,'',''); -INSERT INTO Demand VALUES('utopia',2010,'RL',12.59999999999999965,'',''); -INSERT INTO Demand VALUES('utopia',1990,'TX',5.200000000000000177,'',''); -INSERT INTO Demand VALUES('utopia',2000,'TX',7.799999999999999823,'',''); -INSERT INTO Demand VALUES('utopia',2010,'TX',11.68999999999999951,'',''); +INSERT INTO Demand VALUES('utopia',1990,'RH',25.200000000000000177,'',''); +INSERT INTO Demand VALUES('utopia',2000,'RH',37.799999999999998046,'',''); +INSERT INTO Demand VALUES('utopia',2010,'RH',56.699999999999999289,'',''); +INSERT INTO Demand VALUES('utopia',1990,'RL',5.5999999999999996447,'',''); +INSERT INTO Demand VALUES('utopia',2000,'RL',8.4000000000000003552,'',''); +INSERT INTO Demand VALUES('utopia',2010,'RL',12.600000000000000088,'',''); +INSERT INTO Demand VALUES('utopia',1990,'TX',5.2000000000000001776,'',''); +INSERT INTO Demand VALUES('utopia',2000,'TX',7.7999999999999998223,'',''); +INSERT INTO Demand VALUES('utopia',2010,'TX',11.69000000000000039,'',''); CREATE TABLE DemandSpecificDistribution ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -429,20 +503,40 @@ CREATE TABLE DemandSpecificDistribution demand_name TEXT REFERENCES Commodity (name), dsd REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, demand_name), + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('utopia','inter','day','RH',0.1199999999999999956,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','inter','night','RH',0.05999999999999999778,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','winter','day','RH',0.5466999999999999638,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','winter','night','RH',0.2732999999999999874,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','inter','day','RL',0.1499999999999999945,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','inter','night','RL',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','summer','day','RL',0.1499999999999999945,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','summer','night','RL',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','winter','day','RL',0.5,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','winter','night','RL',0.1000000000000000055,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RH',0.11999999999999999644,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RH',0.06,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','day','RH',0.54669999999999996376,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RH',0.27329999999999996518,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RL',0.15,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','day','RL',0.15,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','day','RL',0.5,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RL',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RH',0.11999999999999999644,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RH',0.06,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','day','RH',0.54669999999999996376,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RH',0.27329999999999996518,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RL',0.15,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','day','RL',0.15,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','day','RL',0.5,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RL',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RH',0.11999999999999999644,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RH',0.06,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RH',0.54669999999999996376,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RH',0.27329999999999996518,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RL',0.15,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','day','RL',0.15,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RL',0.5,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RL',0.1,''); CREATE TABLE LoanRate ( region TEXT, @@ -477,40 +571,40 @@ INSERT INTO Efficiency VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,''); INSERT INTO Efficiency VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,''); INSERT INTO Efficiency VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,''); INSERT INTO Efficiency VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,''); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1960,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1970,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1980,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1990,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',2000,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',2010,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',1990,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2000,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2010,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','URN','E21',1990,'ELC',0.4000000000000000222,'# 1/2.5'); -INSERT INTO Efficiency VALUES('utopia','URN','E21',2000,'ELC',0.4000000000000000222,'# 1/2.5'); -INSERT INTO Efficiency VALUES('utopia','URN','E21',2010,'ELC',0.4000000000000000222,'# 1/2.5'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',1980,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',1990,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',2000,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',2010,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1960,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1970,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1980,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1990,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',2000,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',2010,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',1980,'ELC',0.7199999999999999734,'# 1/1.3889'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',1990,'ELC',0.7199999999999999734,'# 1/1.3889'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',2000,'ELC',0.7199999999999999734,'# 1/1.3889'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',2010,'ELC',0.7199999999999999734,'# 1/1.3889'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1960,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1970,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1980,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1990,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',2000,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',2010,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','FEQ','E21',1990,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2000,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2010,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','URN','E21',1990,'ELC',0.4,'# 1/2.5'); +INSERT INTO Efficiency VALUES('utopia','URN','E21',2000,'ELC',0.4,'# 1/2.5'); +INSERT INTO Efficiency VALUES('utopia','URN','E21',2010,'ELC',0.4,'# 1/2.5'); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',1980,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',1990,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',2000,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',2010,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1960,'ELC',0.29399999999999998578,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1970,'ELC',0.29399999999999998578,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1980,'ELC',0.29399999999999998578,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1990,'ELC',0.29399999999999998578,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',2000,'ELC',0.29399999999999998578,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',2010,'ELC',0.29399999999999998578,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',1980,'ELC',0.71999999999999992894,'# 1/1.3889'); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',1990,'ELC',0.71999999999999992894,'# 1/1.3889'); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',2000,'ELC',0.71999999999999992894,'# 1/1.3889'); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',2010,'ELC',0.71999999999999992894,'# 1/1.3889'); INSERT INTO Efficiency VALUES('utopia','ELC','RHE',1990,'RH',1.0,'# direct translation from DMD_EFF'); INSERT INTO Efficiency VALUES('utopia','ELC','RHE',2000,'RH',1.0,'# direct translation from DMD_EFF'); INSERT INTO Efficiency VALUES('utopia','ELC','RHE',2010,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1970,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1980,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1990,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2000,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2010,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1970,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1980,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1990,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2000,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2010,'RH',0.7,'# direct translation from DMD_EFF'); INSERT INTO Efficiency VALUES('utopia','ELC','RL1',1980,'RL',1.0,'# direct translation from DMD_EFF'); INSERT INTO Efficiency VALUES('utopia','ELC','RL1',1990,'RL',1.0,'# direct translation from DMD_EFF'); INSERT INTO Efficiency VALUES('utopia','ELC','RL1',2000,'RL',1.0,'# direct translation from DMD_EFF'); @@ -521,19 +615,41 @@ INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'# direct tran INSERT INTO Efficiency VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',1990,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2000,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2010,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1970,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1980,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1990,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2000,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2010,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','ELC','TXE',1990,'TX',0.82699999999999995736,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2000,'TX',0.82699999999999995736,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2010,'TX',0.82699999999999995736,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1970,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1980,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1990,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2000,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2010,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); +CREATE TABLE EfficiencyVariable +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); CREATE TABLE EmissionActivity ( region TEXT, @@ -552,10 +668,10 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.07499999999999999723,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.07499999999999999723,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',0.08899999999999999579,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.07499999999999999723,'',''); +INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.075,'',''); +INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.075,'',''); +INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',0.088999999999999985789,'',''); +INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.075,'',''); INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1970,'TX',1.0,'',''); INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1980,'TX',1.0,'',''); INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1990,'TX',1.0,'',''); @@ -578,7 +694,7 @@ CREATE TABLE EmissionEmbodied value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) ); CREATE TABLE ExistingCapacity ( @@ -592,20 +708,20 @@ CREATE TABLE ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1960,0.1749999999999999889,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1970,0.1749999999999999889,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1980,0.1499999999999999945,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E31',1980,0.1000000000000000055,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E01',1960,0.175,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E01',1970,0.175,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E01',1980,0.15,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E31',1980,0.1,'',''); INSERT INTO ExistingCapacity VALUES('utopia','E51',1980,0.5,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1960,0.05000000000000000277,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1970,0.05000000000000000277,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1980,0.2000000000000000111,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E70',1960,0.05,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E70',1970,0.05,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E70',1980,0.2,'',''); INSERT INTO ExistingCapacity VALUES('utopia','RHO',1970,12.5,'',''); INSERT INTO ExistingCapacity VALUES('utopia','RHO',1980,12.5,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','RL1',1980,5.599999999999999645,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXD',1970,0.4000000000000000222,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXD',1980,0.2000000000000000111,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXG',1970,3.100000000000000088,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','RL1',1980,5.5999999999999996447,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','TXD',1970,0.4,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','TXD',1980,0.2,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','TXG',1970,3.1000000000000000888,'',''); INSERT INTO ExistingCapacity VALUES('utopia','TXG',1980,1.5,'',''); CREATE TABLE TechGroup ( @@ -733,13 +849,13 @@ CREATE TABLE MaxCapacity notes TEXT, PRIMARY KEY (region, period, tech) ); -INSERT INTO MaxCapacity VALUES('utopia',1990,'E31',0.1300000000000000044,'',''); -INSERT INTO MaxCapacity VALUES('utopia',2000,'E31',0.1700000000000000122,'',''); -INSERT INTO MaxCapacity VALUES('utopia',2010,'E31',0.2099999999999999923,'',''); +INSERT INTO MaxCapacity VALUES('utopia',1990,'E31',0.13000000000000000444,'',''); +INSERT INTO MaxCapacity VALUES('utopia',2000,'E31',0.17000000000000001776,'',''); +INSERT INTO MaxCapacity VALUES('utopia',2010,'E31',0.21000000000000000888,'',''); INSERT INTO MaxCapacity VALUES('utopia',1990,'RHE',0.0,'',''); -INSERT INTO MaxCapacity VALUES('utopia',1990,'TXD',0.5999999999999999778,'',''); -INSERT INTO MaxCapacity VALUES('utopia',2000,'TXD',1.760000000000000008,'',''); -INSERT INTO MaxCapacity VALUES('utopia',2010,'TXD',4.759999999999999787,'',''); +INSERT INTO MaxCapacity VALUES('utopia',1990,'TXD',0.6,'',''); +INSERT INTO MaxCapacity VALUES('utopia',2000,'TXD',1.7599999999999999644,'',''); +INSERT INTO MaxCapacity VALUES('utopia',2010,'TXD',4.7599999999999997868,'',''); CREATE TABLE MaxResource ( region TEXT, @@ -786,10 +902,10 @@ CREATE TABLE MinCapacity notes TEXT, PRIMARY KEY (region, period, tech) ); -INSERT INTO MinCapacity VALUES('utopia',1990,'E31',0.1300000000000000044,'',''); -INSERT INTO MinCapacity VALUES('utopia',2000,'E31',0.1300000000000000044,'',''); -INSERT INTO MinCapacity VALUES('utopia',2010,'E31',0.1300000000000000044,'',''); -INSERT INTO MinCapacity VALUES('utopia',1990,'SRE',0.1000000000000000055,'',''); +INSERT INTO MinCapacity VALUES('utopia',1990,'E31',0.13000000000000000444,'',''); +INSERT INTO MinCapacity VALUES('utopia',2000,'E31',0.13000000000000000444,'',''); +INSERT INTO MinCapacity VALUES('utopia',2010,'E31',0.13000000000000000444,'',''); +INSERT INTO MinCapacity VALUES('utopia',1990,'SRE',0.1,'',''); CREATE TABLE MinCapacityGroup ( region TEXT, @@ -899,7 +1015,7 @@ CREATE TABLE OutputFlowOut period INTEGER REFERENCES TimePeriod (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -913,6 +1029,25 @@ CREATE TABLE OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); +CREATE TABLE OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); CREATE TABLE PlanningReserveMargin ( region TEXT @@ -944,22 +1079,36 @@ CREATE TABLE Region ); INSERT INTO Region VALUES('utopia',NULL); CREATE TABLE TimeSegmentFraction -( +( + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, notes TEXT, - PRIMARY KEY (season, tod), + PRIMARY KEY (period, season, tod), CHECK (segfrac >= 0 AND segfrac <= 1) ); -INSERT INTO TimeSegmentFraction VALUES('inter','day',0.166699999999999987,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES('inter','night',0.08329999999999999905,'# I-N'); -INSERT INTO TimeSegmentFraction VALUES('summer','day',0.166699999999999987,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES('summer','night',0.08329999999999999905,'# S-N'); -INSERT INTO TimeSegmentFraction VALUES('winter','day',0.3332999999999999852,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES('winter','night',0.166699999999999987,'# W-N'); +INSERT INTO TimeSegmentFraction VALUES(1990,'inter','day',0.16669999999999998152,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(1990,'inter','night',0.08330000000000000071,'# I-N'); +INSERT INTO TimeSegmentFraction VALUES(1990,'summer','day',0.16669999999999998152,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(1990,'summer','night',0.08330000000000000071,'# S-N'); +INSERT INTO TimeSegmentFraction VALUES(1990,'winter','day',0.33329999999999997406,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(1990,'winter','night',0.16669999999999998152,'# W-N'); +INSERT INTO TimeSegmentFraction VALUES(2000,'inter','day',0.16669999999999998152,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'inter','night',0.08330000000000000071,'# I-N'); +INSERT INTO TimeSegmentFraction VALUES(2000,'summer','day',0.16669999999999998152,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'summer','night',0.08330000000000000071,'# S-N'); +INSERT INTO TimeSegmentFraction VALUES(2000,'winter','day',0.33329999999999997406,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'winter','night',0.16669999999999998152,'# W-N'); +INSERT INTO TimeSegmentFraction VALUES(2010,'inter','day',0.16669999999999998152,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'inter','night',0.08330000000000000071,'# I-N'); +INSERT INTO TimeSegmentFraction VALUES(2010,'summer','day',0.16669999999999998152,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'summer','night',0.08330000000000000071,'# S-N'); +INSERT INTO TimeSegmentFraction VALUES(2010,'winter','day',0.33329999999999997406,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'winter','night',0.16669999999999998152,'# W-N'); CREATE TABLE StorageDuration ( region TEXT, @@ -968,12 +1117,22 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE StorageInit +CREATE TABLE StorageLevelFraction ( - tech TEXT - PRIMARY KEY, - value REAL, - notes TEXT + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage) ); CREATE TABLE TechnologyType ( @@ -985,7 +1144,7 @@ INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE TechInputSplit +CREATE TABLE MinTechInputSplit ( region TEXT, period INTEGER @@ -998,7 +1157,7 @@ CREATE TABLE TechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechInputSplitAnnual +CREATE TABLE MinTechInputSplitAnnual ( region TEXT, period INTEGER @@ -1011,7 +1170,26 @@ CREATE TABLE TechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechOutputSplit +CREATE TABLE MinTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +INSERT INTO MinTechOutputSplit VALUES('utopia',1990,'SRE','DSL',0.7,''); +INSERT INTO MinTechOutputSplit VALUES('utopia',2000,'SRE','DSL',0.7,''); +INSERT INTO MinTechOutputSplit VALUES('utopia',2010,'SRE','DSL',0.7,''); +INSERT INTO MinTechOutputSplit VALUES('utopia',1990,'SRE','GSL',0.3,''); +INSERT INTO MinTechOutputSplit VALUES('utopia',2000,'SRE','GSL',0.3,''); +INSERT INTO MinTechOutputSplit VALUES('utopia',2010,'SRE','GSL',0.3,''); +CREATE TABLE MinTechOutputSplitAnnual ( region TEXT, period INTEGER @@ -1024,12 +1202,58 @@ CREATE TABLE TechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm) ); -INSERT INTO TechOutputSplit VALUES('utopia',1990,'SRE','DSL',0.6999999999999999556,''); -INSERT INTO TechOutputSplit VALUES('utopia',2000,'SRE','DSL',0.6999999999999999556,''); -INSERT INTO TechOutputSplit VALUES('utopia',2010,'SRE','DSL',0.6999999999999999556,''); -INSERT INTO TechOutputSplit VALUES('utopia',1990,'SRE','GSL',0.2999999999999999889,''); -INSERT INTO TechOutputSplit VALUES('utopia',2000,'SRE','GSL',0.2999999999999999889,''); -INSERT INTO TechOutputSplit VALUES('utopia',2010,'SRE','GSL',0.2999999999999999889,''); +CREATE TABLE MaxTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MaxTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -1055,13 +1279,31 @@ INSERT INTO TimePeriod VALUES(6,2010,'f'); INSERT INTO TimePeriod VALUES(7,2020,'f'); CREATE TABLE TimeSeason ( - sequence INTEGER UNIQUE, - season TEXT + season TEXT PRIMARY KEY ); -INSERT INTO TimeSeason VALUES(1,'inter'); -INSERT INTO TimeSeason VALUES(2,'summer'); -INSERT INTO TimeSeason VALUES(3,'winter'); +INSERT INTO TimeSeason VALUES('inter'); +INSERT INTO TimeSeason VALUES('summer'); +INSERT INTO TimeSeason VALUES('winter'); +CREATE TABLE PeriodSeasons +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT + REFERENCES TimeSeason (season), + notes TEXT, + PRIMARY KEY (period, sequence) +); +INSERT INTO PeriodSeasons VALUES(1990,1,'inter',NULL); +INSERT INTO PeriodSeasons VALUES(1990,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(1990,3,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2000,1,'inter',NULL); +INSERT INTO PeriodSeasons VALUES(2000,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2000,3,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2010,1,'inter',NULL); +INSERT INTO PeriodSeasons VALUES(2010,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2010,3,'winter',NULL); CREATE TABLE TimePeriodType ( label TEXT @@ -1226,6 +1468,32 @@ CREATE TABLE MinNewCapacityShare notes TEXT, PRIMARY KEY (region, period, tech, group_name) ); +CREATE TABLE MinNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); +CREATE TABLE MaxNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1279,6 +1547,36 @@ CREATE TABLE MaxActivityGroup notes TEXT, PRIMARY KEY (region, period, group_name) ); +CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "min_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); +CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "max_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); CREATE TABLE RPSRequirement ( region TEXT NOT NULL @@ -1311,30 +1609,29 @@ CREATE TABLE Technology curtail INTEGER NOT NULL DEFAULT 0, retire INTEGER NOT NULL DEFAULT 0, flex INTEGER NOT NULL DEFAULT 0, - variable INTEGER NOT NULL DEFAULT 0, exchange INTEGER NOT NULL DEFAULT 0, description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('IMPDSL1','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported diesel'); -INSERT INTO Technology VALUES('IMPGSL1','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported gasoline'); -INSERT INTO Technology VALUES('IMPHCO1','r','supply','coal','',1,0,0,0,0,0,0,0,' imported coal'); -INSERT INTO Technology VALUES('IMPOIL1','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO Technology VALUES('IMPURN1','r','supply','nuclear','',1,0,0,0,0,0,0,0,' imported uranium'); -INSERT INTO Technology VALUES('IMPFEQ','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported fossil equivalent'); -INSERT INTO Technology VALUES('IMPHYD','r','supply','hydro','',1,0,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); -INSERT INTO Technology VALUES('E01','pb','electric','coal','',0,0,0,0,0,0,0,0,' coal power plant'); -INSERT INTO Technology VALUES('E21','pb','electric','nuclear','',0,0,0,0,0,0,0,0,' nuclear power plant'); -INSERT INTO Technology VALUES('E31','pb','electric','hydro','',0,0,0,0,0,0,0,0,' hydro power'); -INSERT INTO Technology VALUES('E51','ps','electric','electric','',0,0,0,0,0,0,0,0,' electric storage'); -INSERT INTO Technology VALUES('E70','p','electric','petroleum','',0,0,0,0,0,0,0,0,' diesel power plant'); -INSERT INTO Technology VALUES('RHE','p','residential','electric','',0,0,0,0,0,0,0,0,' electric residential heating'); -INSERT INTO Technology VALUES('RHO','p','residential','petroleum','',0,0,0,0,0,0,0,0,' diesel residential heating'); -INSERT INTO Technology VALUES('RL1','p','residential','electric','',0,0,0,0,0,0,0,0,' residential lighting'); -INSERT INTO Technology VALUES('SRE','p','supply','petroleum','',0,0,0,0,0,0,0,0,' crude oil processor'); -INSERT INTO Technology VALUES('TXD','p','transport','petroleum','',0,0,0,0,0,0,0,0,' diesel powered vehicles'); -INSERT INTO Technology VALUES('TXE','p','transport','electric','',0,0,0,0,0,0,0,0,' electric powered vehicles'); -INSERT INTO Technology VALUES('TXG','p','transport','petroleum','',0,0,0,0,0,0,0,0,' gasoline powered vehicles'); +INSERT INTO Technology VALUES('IMPDSL1','r','supply','petroleum','',1,0,0,0,0,0,0,' imported diesel'); +INSERT INTO Technology VALUES('IMPGSL1','r','supply','petroleum','',1,0,0,0,0,0,0,' imported gasoline'); +INSERT INTO Technology VALUES('IMPHCO1','r','supply','coal','',1,0,0,0,0,0,0,' imported coal'); +INSERT INTO Technology VALUES('IMPOIL1','r','supply','petroleum','',1,0,0,0,0,0,0,' imported crude oil'); +INSERT INTO Technology VALUES('IMPURN1','r','supply','nuclear','',1,0,0,0,0,0,0,' imported uranium'); +INSERT INTO Technology VALUES('IMPFEQ','r','supply','petroleum','',1,0,0,0,0,0,0,' imported fossil equivalent'); +INSERT INTO Technology VALUES('IMPHYD','r','supply','hydro','',1,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); +INSERT INTO Technology VALUES('E01','pb','electric','coal','',0,0,0,0,0,0,0,' coal power plant'); +INSERT INTO Technology VALUES('E21','pb','electric','nuclear','',0,0,0,0,0,0,0,' nuclear power plant'); +INSERT INTO Technology VALUES('E31','pb','electric','hydro','',0,0,0,0,0,0,0,' hydro power'); +INSERT INTO Technology VALUES('E51','ps','electric','electric','',0,0,0,0,0,0,0,' electric storage'); +INSERT INTO Technology VALUES('E70','p','electric','petroleum','',0,0,0,0,0,0,0,' diesel power plant'); +INSERT INTO Technology VALUES('RHE','p','residential','electric','',0,0,0,0,0,0,0,' electric residential heating'); +INSERT INTO Technology VALUES('RHO','p','residential','petroleum','',0,0,0,0,0,0,0,' diesel residential heating'); +INSERT INTO Technology VALUES('RL1','p','residential','electric','',0,0,0,0,0,0,0,' residential lighting'); +INSERT INTO Technology VALUES('SRE','p','supply','petroleum','',0,0,0,0,0,0,0,' crude oil processor'); +INSERT INTO Technology VALUES('TXD','p','transport','petroleum','',0,0,0,0,0,0,0,' diesel powered vehicles'); +INSERT INTO Technology VALUES('TXE','p','transport','electric','',0,0,0,0,0,0,0,' electric powered vehicles'); +INSERT INTO Technology VALUES('TXG','p','transport','petroleum','',0,0,0,0,0,0,0,' gasoline powered vehicles'); CREATE TABLE OutputCost ( scenario TEXT, @@ -1355,3 +1652,4 @@ CREATE TABLE OutputCost FOREIGN KEY (tech) REFERENCES Technology (tech) ); COMMIT; +PRAGMA FOREIGN_KEYS = 1; \ No newline at end of file diff --git a/data_files/temoa_basics_0.sql b/data_files/temoa_basics_0.sql index eff70ce4f..2e8df8c72 100644 --- a/data_files/temoa_basics_0.sql +++ b/data_files/temoa_basics_0.sql @@ -311,7 +311,6 @@ CREATE TABLE IF NOT EXISTS Technology curtail INTEGER NOT NULL DEFAULT 0, retire INTEGER NOT NULL DEFAULT 0, flex INTEGER NOT NULL DEFAULT 0, - variable INTEGER NOT NULL DEFAULT 0, exchange INTEGER NOT NULL DEFAULT 0, description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) diff --git a/data_files/temoa_basics_1.sql b/data_files/temoa_basics_1.sql index 53fb8c04f..dca7321fb 100644 --- a/data_files/temoa_basics_1.sql +++ b/data_files/temoa_basics_1.sql @@ -30,6 +30,8 @@ CREATE TABLE IF NOT EXISTS CapacityToActivity CREATE TABLE IF NOT EXISTS CapacityFactorTech ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -139,6 +141,8 @@ VALUES ('region', 2000, 'demand', 1, NULL, NULL); CREATE TABLE IF NOT EXISTS DemandSpecificDistribution ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -147,17 +151,17 @@ CREATE TABLE IF NOT EXISTS DemandSpecificDistribution REFERENCES Commodity (name), dsd REAL, dsd_notes TEXT, - PRIMARY KEY (region, season, tod, demand_name), + PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); REPLACE INTO DemandSpecificDistribution -VALUES ('region','S1', 'D1', 'demand', 0.25, NULL); +VALUES ('region', 2000, 'S1', 'D1', 'demand', 0.25, NULL); REPLACE INTO DemandSpecificDistribution -VALUES ('region','S1', 'D2', 'demand', 0.25, NULL); +VALUES ('region', 2000, 'S1', 'D2', 'demand', 0.25, NULL); REPLACE INTO DemandSpecificDistribution -VALUES ('region','S2', 'D1', 'demand', 0.25, NULL); +VALUES ('region', 2000, 'S2', 'D1', 'demand', 0.25, NULL); REPLACE INTO DemandSpecificDistribution -VALUES ('region','S2', 'D2', 'demand', 0.25, NULL); +VALUES ('region', 2000, 'S2', 'D2', 'demand', 0.25, NULL); CREATE TABLE IF NOT EXISTS Efficiency ( region TEXT, @@ -337,6 +341,20 @@ CREATE TABLE IF NOT EXISTS OutputDualVariable dual REAL, PRIMARY KEY (constraint_name, scenario) ); +CREATE TABLE IF NOT EXISTS PeriodSeasons +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT + REFERENCES TimeSeason (season), + notes TEXT, + PRIMARY KEY (period, sequence) +); +REPLACE INTO PeriodSeasons +VALUES (2000, 1, 'S1', NULL); +REPLACE INTO PeriodSeasons +VALUES (2000, 2, 'S2', NULL); CREATE TABLE IF NOT EXISTS Region ( region TEXT @@ -359,24 +377,26 @@ CREATE TABLE IF NOT EXISTS StorageDuration PRIMARY KEY (region, tech) ); CREATE TABLE IF NOT EXISTS TimeSegmentFraction -( +( + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, notes TEXT, - PRIMARY KEY (season, tod), + PRIMARY KEY (period, season, tod), CHECK (segfrac >= 0 AND segfrac <= 1) ); REPLACE INTO TimeSegmentFraction -VALUES ('S1', 'D1', 0.25, NULL); +VALUES (2000, 'S1', 'D1', 0.25, NULL); REPLACE INTO TimeSegmentFraction -VALUES ('S1', 'D2', 0.25, NULL); +VALUES (2000, 'S1', 'D2', 0.25, NULL); REPLACE INTO TimeSegmentFraction -VALUES ('S2', 'D1', 0.25, NULL); +VALUES (2000, 'S2', 'D1', 0.25, NULL); REPLACE INTO TimeSegmentFraction -VALUES ('S2', 'D2', 0.25, NULL); +VALUES (2000, 'S2', 'D2', 0.25, NULL); CREATE TABLE IF NOT EXISTS TechnologyType ( label TEXT @@ -461,7 +481,6 @@ CREATE TABLE IF NOT EXISTS Technology curtail INTEGER NOT NULL DEFAULT 0, retire INTEGER NOT NULL DEFAULT 0, flex INTEGER NOT NULL DEFAULT 0, - variable INTEGER NOT NULL DEFAULT 0, exchange INTEGER NOT NULL DEFAULT 0, description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) diff --git a/data_files/temoa_basics_2.sql b/data_files/temoa_basics_2.sql index cdacd9aa1..0a77f5024 100644 --- a/data_files/temoa_basics_2.sql +++ b/data_files/temoa_basics_2.sql @@ -139,6 +139,8 @@ VALUES ('region', 2000, 'demand', 1, NULL, NULL); CREATE TABLE IF NOT EXISTS DemandSpecificDistribution ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -147,17 +149,17 @@ CREATE TABLE IF NOT EXISTS DemandSpecificDistribution REFERENCES Commodity (name), dsd REAL, dsd_notes TEXT, - PRIMARY KEY (region, season, tod, demand_name), + PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); REPLACE INTO DemandSpecificDistribution -VALUES ('region','S1', 'D1', 'demand', 0.25, NULL); +VALUES ('region', 2000, 'S1', 'D1', 'demand', 0.25, NULL); REPLACE INTO DemandSpecificDistribution -VALUES ('region','S1', 'D2', 'demand', 0.25, NULL); +VALUES ('region', 2000, 'S1', 'D2', 'demand', 0.25, NULL); REPLACE INTO DemandSpecificDistribution -VALUES ('region','S2', 'D1', 'demand', 0.25, NULL); +VALUES ('region', 2000, 'S2', 'D1', 'demand', 0.25, NULL); REPLACE INTO DemandSpecificDistribution -VALUES ('region','S2', 'D2', 'demand', 0.25, NULL); +VALUES ('region', 2000, 'S2', 'D2', 'demand', 0.25, NULL); CREATE TABLE IF NOT EXISTS Efficiency ( region TEXT, @@ -546,6 +548,20 @@ CREATE TABLE IF NOT EXISTS OutputDualVariable dual REAL, PRIMARY KEY (constraint_name, scenario) ); +CREATE TABLE IF NOT EXISTS PeriodSeasons +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT + REFERENCES TimeSeason (season), + notes TEXT, + PRIMARY KEY (period, sequence) +); +REPLACE INTO PeriodSeasons +VALUES (2000, 1, 'S1', NULL); +REPLACE INTO PeriodSeasons +VALUES (2000, 2, 'S2', NULL); CREATE TABLE IF NOT EXISTS Region ( region TEXT @@ -568,24 +584,26 @@ CREATE TABLE IF NOT EXISTS StorageDuration PRIMARY KEY (region, tech) ); CREATE TABLE IF NOT EXISTS TimeSegmentFraction -( +( + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, notes TEXT, - PRIMARY KEY (season, tod), + PRIMARY KEY (period, season, tod), CHECK (segfrac >= 0 AND segfrac <= 1) ); REPLACE INTO TimeSegmentFraction -VALUES ('S1', 'D1', 0.25, NULL); +VALUES (2000, 'S1', 'D1', 0.25, NULL); REPLACE INTO TimeSegmentFraction -VALUES ('S1', 'D2', 0.25, NULL); +VALUES (2000, 'S1', 'D2', 0.25, NULL); REPLACE INTO TimeSegmentFraction -VALUES ('S2', 'D1', 0.25, NULL); +VALUES (2000, 'S2', 'D1', 0.25, NULL); REPLACE INTO TimeSegmentFraction -VALUES ('S2', 'D2', 0.25, NULL); +VALUES (2000, 'S2', 'D2', 0.25, NULL); CREATE TABLE IF NOT EXISTS TechGroup ( group_name TEXT @@ -684,7 +702,6 @@ CREATE TABLE IF NOT EXISTS Technology curtail INTEGER NOT NULL DEFAULT 0, retire INTEGER NOT NULL DEFAULT 0, flex INTEGER NOT NULL DEFAULT 0, - variable INTEGER NOT NULL DEFAULT 0, exchange INTEGER NOT NULL DEFAULT 0, description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) diff --git a/data_files/temoa_schema_minimal_v3.sql b/data_files/temoa_schema_minimal_v3.sql deleted file mode 100644 index 27333fe26..000000000 --- a/data_files/temoa_schema_minimal_v3.sql +++ /dev/null @@ -1,709 +0,0 @@ -PRAGMA foreign_keys= OFF; -BEGIN TRANSACTION; - -CREATE TABLE IF NOT EXISTS MetaData -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -REPLACE INTO MetaData -VALUES ('myopic_base_year', 2000, 'Base Year for Myopic Analysis'); -REPLACE INTO MetaData -VALUES ('DB_MAJOR', 3, 'DB major version number'); -REPLACE INTO MetaData -VALUES ('DB_MINOR', 0, 'DB minor version number'); - -CREATE TABLE IF NOT EXISTS MetaDataReal -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -REPLACE INTO MetaDataReal -VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); -REPLACE INTO MetaDataReal -VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in LoanRate table'); - -CREATE TABLE IF NOT EXISTS OutputDualVariable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE IF NOT EXISTS OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE IF NOT EXISTS SectorLabel -( - sector TEXT, - PRIMARY KEY (sector) -); - - -CREATE TABLE IF NOT EXISTS CapacityFactorProcess -( - region TEXT, - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS CapacityFactorTech -( - region TEXT, - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS CapacityToActivity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS Commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES CommodityType (label), - description TEXT -); -CREATE TABLE IF NOT EXISTS CommodityType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO CommodityType -VALUES ('p', 'physical commodity'); -REPLACE INTO CommodityType -VALUES ('e', 'emissions commodity'); -REPLACE INTO CommodityType -VALUES ('d', 'demand commodity'); -REPLACE INTO CommodityType -VALUES ('s', 'source commodity'); - -CREATE TABLE IF NOT EXISTS CostEmission -( - region TEXT - REFERENCES Region (region), - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT NOT NULL - REFERENCES Commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE IF NOT EXISTS CostFixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS CostInvest -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS CostVariable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS Demand -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - commodity TEXT - REFERENCES Commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -CREATE TABLE IF NOT EXISTS DemandSpecificDistribution -( - region TEXT, - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - demand_name TEXT - REFERENCES Commodity (name), - dds REAL, - dds_notes TEXT, - PRIMARY KEY (region, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -CREATE TABLE IF NOT EXISTS LoanRate -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS Efficiency -( - region TEXT, - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE IF NOT EXISTS EmissionActivity -( - region TEXT, - emis_comm TEXT - REFERENCES Commodity (name), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS ExistingCapacity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); - -CREATE TABLE IF NOT EXISTS LoanLifetimeTech -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS LifetimeProcess -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS LifetimeTech -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS LinkedTech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES Technology (tech), - emis_comm TEXT - REFERENCES Commodity (name), - driven_tech TEXT - REFERENCES Technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -CREATE TABLE IF NOT EXISTS MaxActivity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE IF NOT EXISTS MaxCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); - -CREATE TABLE IF NOT EXISTS MinActivity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); - -CREATE TABLE IF NOT EXISTS MinCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); - -CREATE TABLE IF NOT EXISTS OutputCurtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputNetCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputBuiltCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputRetiredCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputFlowIn -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputFlowOut -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS PlanningReserveMargin -( - region TEXT - PRIMARY KEY - REFERENCES Region (region), - margin REAL -); -CREATE TABLE IF NOT EXISTS RampDown -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS RampUp -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS Region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS TimeSegmentFraction -( - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) -); -CREATE TABLE IF NOT EXISTS StorageDuration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); - -CREATE TABLE IF NOT EXISTS TechnologyType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO TechnologyType -VALUES ('r', 'resource technology'); -REPLACE INTO TechnologyType -VALUES ('p', 'production technology'); -REPLACE INTO TechnologyType -VALUES ('pb', 'baseload production technology'); -REPLACE INTO TechnologyType -VALUES ('ps', 'storage production technology'); - -CREATE TABLE IF NOT EXISTS TechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE IF NOT EXISTS TechInputSplitAverage -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE IF NOT EXISTS TechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE IF NOT EXISTS TimeOfDay -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY -); -CREATE TABLE IF NOT EXISTS TimePeriod -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES TimePeriodType (label) -); -CREATE TABLE IF NOT EXISTS TimeSeason -( - sequence INTEGER UNIQUE, - season TEXT - PRIMARY KEY -); -CREATE TABLE IF NOT EXISTS TimePeriodType -( - label TEXT - PRIMARY KEY, - description TEXT -); - -CREATE TABLE IF NOT EXISTS MaxAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS MaxNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); - - -CREATE TABLE IF NOT EXISTS MinAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); - -CREATE TABLE IF NOT EXISTS MinNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); - -CREATE TABLE IF NOT EXISTS OutputEmission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); - -CREATE TABLE IF NOT EXISTS EmissionLimit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); - -CREATE TABLE IF NOT EXISTS Technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - variable INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) -); -CREATE TABLE IF NOT EXISTS OutputCost -( - scenario TEXT, - region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) -); -COMMIT; -PRAGMA FOREIGN_KEYS = 1; diff --git a/data_files/temoa_schema_v3.sql b/data_files/temoa_schema_v3.sql deleted file mode 100644 index 20014d4db..000000000 --- a/data_files/temoa_schema_v3.sql +++ /dev/null @@ -1,935 +0,0 @@ -PRAGMA foreign_keys= OFF; -BEGIN TRANSACTION; - -CREATE TABLE IF NOT EXISTS MetaData -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -REPLACE INTO MetaData -VALUES ('myopic_base_year', 2000, 'Base Year for Myopic Analysis'); -REPLACE INTO MetaData -VALUES ('DB_MAJOR', 3, 'DB major version number'); -REPLACE INTO MetaData -VALUES ('DB_MINOR', 0, 'DB minor version number'); - -CREATE TABLE IF NOT EXISTS MetaDataReal -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -REPLACE INTO MetaDataReal -VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); -REPLACE INTO MetaDataReal -VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in LoanRate table'); - -CREATE TABLE IF NOT EXISTS OutputDualVariable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE IF NOT EXISTS OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE IF NOT EXISTS SectorLabel -( - sector TEXT, - PRIMARY KEY (sector) -); - -CREATE TABLE IF NOT EXISTS CapacityCredit -( - region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -CREATE TABLE IF NOT EXISTS CapacityFactorProcess -( - region TEXT, - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS CapacityFactorTech -( - region TEXT, - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS CapacityToActivity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS Commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES CommodityType (label), - description TEXT -); -CREATE TABLE IF NOT EXISTS CommodityType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO CommodityType -VALUES ('p', 'physical commodity'); -REPLACE INTO CommodityType -VALUES ('e', 'emissions commodity'); -REPLACE INTO CommodityType -VALUES ('d', 'demand commodity'); -REPLACE INTO CommodityType -VALUES ('s', 'source commodity'); - -CREATE TABLE IF NOT EXISTS CostEmission -( - region TEXT - REFERENCES Region (region), - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT NOT NULL - REFERENCES Commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE IF NOT EXISTS CostFixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS CostInvest -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS CostVariable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS Demand -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - commodity TEXT - REFERENCES Commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -CREATE TABLE IF NOT EXISTS DemandSpecificDistribution -( - region TEXT, - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - demand_name TEXT - REFERENCES Commodity (name), - dsd REAL, - dsd_notes TEXT, - PRIMARY KEY (region, season, tod, demand_name), - CHECK (dds >= 0 AND dds <= 1) -); -CREATE TABLE IF NOT EXISTS LoanRate -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS Efficiency -( - region TEXT, - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE IF NOT EXISTS EmissionActivity -( - region TEXT, - emis_comm TEXT - REFERENCES Commodity (name), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS EmissionEmbodied -( - region TEXT, - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS ExistingCapacity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS GrowthRateMax -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS GrowthRateSeed -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - seed REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS LoanLifetimeTech -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS LifetimeProcess -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS LifetimeTech -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS LinkedTech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES Technology (tech), - emis_comm TEXT - REFERENCES Commodity (name), - driven_tech TEXT - REFERENCES Technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -CREATE TABLE IF NOT EXISTS MaxActivity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE IF NOT EXISTS MaxCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE IF NOT EXISTS MaxResource -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - max_res REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS MinActivity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE IF NOT EXISTS MaxCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS MinCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE IF NOT EXISTS MinCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS OutputCurtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputNetCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputBuiltCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputRetiredCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputFlowIn -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputFlowOut -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS PlanningReserveMargin -( - region TEXT - PRIMARY KEY - REFERENCES Region (region), - margin REAL -); -CREATE TABLE IF NOT EXISTS RampDown -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS RampUp -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS Region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS TimeSegmentFraction -( - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) -); -CREATE TABLE IF NOT EXISTS StorageDuration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS StorageInit -( - tech TEXT - PRIMARY KEY, - value REAL, - notes TEXT -); -CREATE TABLE IF NOT EXISTS TechnologyType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO TechnologyType -VALUES ('r', 'resource technology'); -REPLACE INTO TechnologyType -VALUES ('p', 'production technology'); -REPLACE INTO TechnologyType -VALUES ('pb', 'baseload production technology'); -REPLACE INTO TechnologyType -VALUES ('ps', 'storage production technology'); - -CREATE TABLE IF NOT EXISTS TechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE IF NOT EXISTS TechInputSplitAverage -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE IF NOT EXISTS TechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE IF NOT EXISTS TimeOfDay -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY -); -CREATE TABLE IF NOT EXISTS TimePeriod -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES TimePeriodType (label) -); -CREATE TABLE IF NOT EXISTS TimeSeason -( - sequence INTEGER UNIQUE, - season TEXT - PRIMARY KEY -); -CREATE TABLE IF NOT EXISTS TimePeriodType -( - label TEXT - PRIMARY KEY, - description TEXT -); -CREATE TABLE IF NOT EXISTS MaxActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE IF NOT EXISTS MaxCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE IF NOT EXISTS MaxAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS MaxNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE IF NOT EXISTS MaxNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS MaxNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE IF NOT EXISTS MinActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE IF NOT EXISTS MinAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS MinCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE IF NOT EXISTS MinNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE IF NOT EXISTS MinNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS MinNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE IF NOT EXISTS OutputEmission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS MinActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS EmissionLimit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE IF NOT EXISTS MaxActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); - -CREATE TABLE RPSRequirement -( - region TEXT NOT NULL - REFERENCES Region (region), - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech_group TEXT NOT NULL - REFERENCES TechGroup (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE TechGroupMember -( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES Technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE IF NOT EXISTS Technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - variable INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) -); -CREATE TABLE IF NOT EXISTS OutputCost -( - scenario TEXT, - region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) -); -COMMIT; -PRAGMA FOREIGN_KEYS = 1; - - diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index dd94a8f9d..059c304eb 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -558,6 +558,25 @@ CREATE TABLE IF NOT EXISTS OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); +CREATE TABLE IF NOT EXISTS OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); CREATE TABLE IF NOT EXISTS PlanningReserveMargin ( region TEXT @@ -770,6 +789,7 @@ CREATE TABLE IF NOT EXISTS PeriodSeasons sequence INTEGER, season TEXT REFERENCES TimeSeason (season), + notes TEXT, PRIMARY KEY (period, sequence) ); CREATE TABLE IF NOT EXISTS TimePeriodType @@ -1079,7 +1099,6 @@ CREATE TABLE IF NOT EXISTS Technology curtail INTEGER NOT NULL DEFAULT 0, retire INTEGER NOT NULL DEFAULT 0, flex INTEGER NOT NULL DEFAULT 0, - variable INTEGER NOT NULL DEFAULT 0, exchange INTEGER NOT NULL DEFAULT 0, description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) @@ -1104,6 +1123,4 @@ CREATE TABLE IF NOT EXISTS OutputCost FOREIGN KEY (tech) REFERENCES Technology (tech) ); COMMIT; -PRAGMA FOREIGN_KEYS = 1; - - +PRAGMA FOREIGN_KEYS = 1; \ No newline at end of file diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index 21c365ab8..8d2da26a7 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -183,7 +183,7 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl for s in M.time_season[p]: for d in M.time_of_day: fi = FI(r, p, s, d, i, t, v, o) - flow = value(M.V_FlowOutAnnual[r, p, i, t, v, o]) * value(M.SegFrac[s, d]) + flow = value(M.V_FlowOutAnnual[r, p, i, t, v, o]) * value(M.SegFrac[p, s, d]) if abs(flow) < epsilon: continue res[fi][FlowType.OUT] = flow @@ -195,7 +195,7 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl for s in M.time_season[p]: for d in M.time_of_day: fi = FI(r, p, s, d, i, t, v, o) - flow = value(M.V_FlexAnnual[r, p, i, t, v, o]) * value(M.SegFrac[s, d]) + flow = value(M.V_FlexAnnual[r, p, i, t, v, o]) * value(M.SegFrac[p, s, d]) if abs(flow) < epsilon: continue res[fi][FlowType.FLEX] = flow diff --git a/temoa/temoa_model/table_writer.py b/temoa/temoa_model/table_writer.py index 4ca015168..a092dd8f6 100644 --- a/temoa/temoa_model/table_writer.py +++ b/temoa/temoa_model/table_writer.py @@ -233,7 +233,7 @@ def write_storage_level(self, M: TemoaModel, iteration=None) -> None: """Write the storage level table to the DB""" # For backwards compatibility, make the output table if it doesn't exist - qry = self.con.execute( + self.con.execute( f"""CREATE TABLE IF NOT EXISTS OutputStorageLevel( scenario TEXT, diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index c4e3860bc..b4d1a5690 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -520,9 +520,9 @@ def CreateDemands(M: 'TemoaModel'): # Also check that all keys are made... The demand distro should be supported # by the full set of (r, p, dem) keys because it is an equality constraint # and we need to ensure even the zeros are passed in - expected_key_length = len(M.time_season[p]) * len(M.time_of_day) used_rp_dems = set((r, p, dem) for r, p, dem in M.Demand.sparse_iterkeys()) for r, p, dem in used_rp_dems: + expected_key_length = len(M.time_season[p]) * len(M.time_of_day) keys = [ k for k in DSD.sparse_iterkeys() diff --git a/temoa/utilities/db_migration_v3_to_v3_1.py b/temoa/utilities/db_migration_v3_to_v3_1.py index 245c0438a..2a3a8bbc1 100644 --- a/temoa/utilities/db_migration_v3_to_v3_1.py +++ b/temoa/utilities/db_migration_v3_to_v3_1.py @@ -42,7 +42,7 @@ help='Path to schema file (default=../../data_files/temoa_schema_v3_1)', required=False, dest='schema', - default='../../data_files/temoa_schema_v3_1.sql', + default='data_files/temoa_schema_v3_1.sql', ) options = parser.parse_args() legacy_db: Path = Path(options.source_db) @@ -145,9 +145,12 @@ # StorageInit -> StorageFraction # TimeSeason -data = con_old.execute('SELECT season FROM TimeSeason ORDER BY sequence').fetchall() -query = 'INSERT OR REPLACE INTO TimeSeason(season) VALUES(?)' -con_new.executemany(query, data) +try: + data = con_old.execute('SELECT DISTINCT season FROM TimeSeason ORDER BY sequence').fetchall() + query = 'INSERT OR REPLACE INTO TimeSeason(season) VALUES(?)' + con_new.executemany(query, data) +except sqlite3.OperationalError: + print('TABLE NOT FOUND: TimeSeason') # execute the direct transfers print('\n --- Executing direct transfers ---') @@ -172,7 +175,6 @@ ) raise ValueError(msg) - print(f'SELECT {str(new_columns)[1:-1].replace("'","")} FROM {old_name}') data = con_old.execute(f'SELECT {str(new_columns)[1:-1].replace("'","")} FROM {old_name}').fetchall() if not data: @@ -220,8 +222,6 @@ raise ValueError(msg) columns = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall() if c[1] != 'period'] - - print(f'SELECT {str(columns)[1:-1].replace("'","")} FROM {old_name}') data = con_old.execute(f'SELECT {str(columns)[1:-1].replace("'","")} FROM {old_name}').fetchall() if not data: @@ -286,5 +286,8 @@ print('Foreign Key Check FAILED on new DB. Something may be wrong with schema.') print(e) +print('\nFinished! Check your database for any missing data.' + ' If there was a mismatch of table names, something may have been lost.') + con_new.close() con_old.close() \ No newline at end of file diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index c72bad8c0..276c21923 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -48,10 +48,10 @@ class ExpectedVals(Enum): ExpectedVals.VAR_COUNT: 1898, # reduced by 6 when reworking storageinit }, 'utopia': { - ExpectedVals.OBJ_VALUE: 36468.56, # reduced after reworking storageinit + ExpectedVals.OBJ_VALUE: 36468.56, # reduced after reworking storageinit -> storage was less constrained ExpectedVals.EFF_DOMAIN_SIZE: 12312, ExpectedVals.EFF_INDEX_SIZE: 64, - ExpectedVals.CONSTR_COUNT: 1452, # reduced 3/27: unlim_cap techs now employed + ExpectedVals.CONSTR_COUNT: 1452, # reduced 3/27: unlim_cap techs now employed ExpectedVals.VAR_COUNT: 1051, # reduced 3/27: unlim_cap techs now employed. Reduced by 4 storageinit }, } diff --git a/tests/test_exchange_cost_ledger.py b/tests/test_exchange_cost_ledger.py index 6b75358b5..aab73ce90 100644 --- a/tests/test_exchange_cost_ledger.py +++ b/tests/test_exchange_cost_ledger.py @@ -33,7 +33,7 @@ # these are the necessary Temoa elements to make the ledger work data = { - 'time_season': {1}, + 'time_season': {2000: [1]}, 'time_of_day': {1}, 'tech_annual': set(), 'LifetimeProcess': {('A-B', 't1', 2000): 30, ('B-A', 't1', 2000): 30}, diff --git a/tests/test_storage.py b/tests/test_storage.py index 010b18133..9f2965cea 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -49,7 +49,7 @@ def test_storage_fraction(system_test_run): * model.V_Capacity[r, p, t, v].value * model.CapacityToActivity[r, t] * (model.StorageDuration[r, t] / 8760) - * model.SegFracPerSeason[s] + * model.SegFracPerSeason[p, s] * 365 * model.ProcessLifeFrac[r, p, t, v] ) @@ -89,7 +89,7 @@ def test_state_sequencing(system_test_run): for S_i in model.processInputsByOutput[r, p, t, v, S_o] ) - s_next, d_next = model.time_next[s, d] + s_next, d_next = model.time_next[p, s, d] state = model.V_StorageLevel[r, p, s, d, t, v].value next_state = model.V_StorageLevel[r, p, s_next, d_next, t, v].value diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 34368dec6..abdc6a1f7 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -9,8 +9,9 @@ CREATE TABLE MetaData ); INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); +INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES('link_seasons',1,'Carry storage states between seasons'); +INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); CREATE TABLE MetaDataReal ( element TEXT, @@ -70,6 +71,8 @@ CREATE TABLE CapacityFactorProcess CREATE TABLE CapacityFactorTech ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -78,13 +81,13 @@ CREATE TABLE CapacityFactorTech REFERENCES Technology (tech), factor REAL, notes TEXT, - PRIMARY KEY (region, season, tod, tech), + PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('TestRegion','S1','TOD1','TechCurtailment',1,NULL); -INSERT INTO CapacityFactorTech VALUES('TestRegion','S1','TOD2','TechCurtailment',0.5,NULL); -INSERT INTO CapacityFactorTech VALUES('TestRegion','S1','TOD1','TechOrdinary',1,NULL); -INSERT INTO CapacityFactorTech VALUES('TestRegion','S1','TOD2','TechOrdinary',0.5,NULL); +INSERT INTO CapacityFactorTech VALUES('TestRegion',2000,'S1','TOD1','TechCurtailment',1.0,NULL); +INSERT INTO CapacityFactorTech VALUES('TestRegion',2000,'S1','TOD2','TechCurtailment',0.5,NULL); +INSERT INTO CapacityFactorTech VALUES('TestRegion',2000,'S1','TOD1','TechOrdinary',1.0,NULL); +INSERT INTO CapacityFactorTech VALUES('TestRegion',2000,'S1','TOD2','TechOrdinary',0.5,NULL); CREATE TABLE CapacityToActivity ( region TEXT, @@ -123,6 +126,7 @@ CREATE TABLE CommodityType PRIMARY KEY, description TEXT ); +INSERT INTO CommodityType VALUES('a','annual commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); @@ -202,6 +206,8 @@ INSERT INTO Demand VALUES('TestRegion',2000,'embodied_out',0.6,NULL,NULL); CREATE TABLE DemandSpecificDistribution ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -209,8 +215,8 @@ CREATE TABLE DemandSpecificDistribution demand_name TEXT REFERENCES Commodity (name), dsd REAL, - dsd_notes TEXT, - PRIMARY KEY (region, season, tod, demand_name), + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); CREATE TABLE LoanRate @@ -248,6 +254,28 @@ INSERT INTO Efficiency VALUES('TestRegion','flex_out','TechFlexNull',2000,'flex_ INSERT INTO Efficiency VALUES('TestRegion','annual_flex_out','TechFlexNull',2000,'annual_flex_null',1.0,NULL); INSERT INTO Efficiency VALUES('TestRegion','annual_flex_in','TechAnnualFlex',2000,'annual_flex_out',1.0,NULL); INSERT INTO Efficiency VALUES('TestRegion','embodied_in','TechEmbodied',2000,'embodied_out',1.0,NULL); +CREATE TABLE EfficiencyVariable +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); CREATE TABLE EmissionActivity ( region TEXT, @@ -271,7 +299,7 @@ INSERT INTO EmissionActivity VALUES('TestRegion','emission','flex_in','TechFlex' INSERT INTO EmissionActivity VALUES('TestRegion','emission','ordinary_in','TechOrdinary',2000,'ordinary_out',1.0,NULL,NULL); INSERT INTO EmissionActivity VALUES('TestRegion','emission','curtailment_in','TechCurtailment',2000,'curtailment_out',1.0,NULL,NULL); INSERT INTO EmissionActivity VALUES('TestRegion','emission','annual_flex_in','TechAnnualFlex',2000,'annual_flex_out',1.0,NULL,NULL); -CREATE TABLE IF NOT EXISTS EmissionEmbodied +CREATE TABLE EmissionEmbodied ( region TEXT, emis_comm TEXT @@ -280,7 +308,7 @@ CREATE TABLE IF NOT EXISTS EmissionEmbodied REFERENCES Technology (tech), vintage INTEGER REFERENCES TimePeriod (period), - value REAL, + value REAL, units TEXT, notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) @@ -551,7 +579,7 @@ CREATE TABLE OutputFlowOut period INTEGER REFERENCES TimePeriod (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -565,6 +593,25 @@ CREATE TABLE OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); +CREATE TABLE OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); CREATE TABLE PlanningReserveMargin ( region TEXT @@ -596,18 +643,20 @@ CREATE TABLE Region ); INSERT INTO Region VALUES('TestRegion',NULL); CREATE TABLE TimeSegmentFraction -( +( + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, notes TEXT, - PRIMARY KEY (season, tod), + PRIMARY KEY (period, season, tod), CHECK (segfrac >= 0 AND segfrac <= 1) ); -INSERT INTO TimeSegmentFraction VALUES('S1','TOD1',0.5,NULL); -INSERT INTO TimeSegmentFraction VALUES('S1','TOD2',0.5,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'S1','TOD1',0.5,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'S1','TOD2',0.5,NULL); CREATE TABLE StorageDuration ( region TEXT, @@ -616,12 +665,22 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE StorageInit +CREATE TABLE StorageLevelFraction ( - tech TEXT - PRIMARY KEY, - value REAL, - notes TEXT + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage) ); CREATE TABLE TechnologyType ( @@ -672,6 +731,71 @@ CREATE TABLE MinTechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm) ); +CREATE TABLE MinTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MaxTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MaxTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -693,17 +817,29 @@ INSERT INTO TimePeriod VALUES(2,2000,'f'); INSERT INTO TimePeriod VALUES(3,2005,'f'); CREATE TABLE TimeSeason ( - sequence INTEGER UNIQUE, - season TEXT + season TEXT PRIMARY KEY ); -INSERT INTO TimeSeason VALUES(1,'S1'); +INSERT INTO TimeSeason VALUES('S1'); +CREATE TABLE PeriodSeasons +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT + REFERENCES TimeSeason (season), + notes TEXT, + PRIMARY KEY (period, sequence) +); +INSERT INTO PeriodSeasons VALUES(2000,1,'S1',NULL); CREATE TABLE TimePeriodType ( label TEXT PRIMARY KEY, description TEXT ); +INSERT INTO TimePeriodType VALUES('e','existing vintages'); +INSERT INTO TimePeriodType VALUES('f','future'); CREATE TABLE MaxActivityShare ( region TEXT, @@ -856,10 +992,36 @@ CREATE TABLE MinNewCapacityShare REFERENCES Technology (tech), group_name TEXT REFERENCES TechGroup (group_name), - max_proportion REAL, + min_proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, group_name) ); +CREATE TABLE MinNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); +CREATE TABLE MaxNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); CREATE TABLE OutputEmission ( scenario TEXT, @@ -913,6 +1075,36 @@ CREATE TABLE MaxActivityGroup notes TEXT, PRIMARY KEY (region, period, group_name) ); +CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "min_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); +CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "max_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); CREATE TABLE RPSRequirement ( region TEXT NOT NULL diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 21ed61de5..204f8fed2 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -8,9 +8,10 @@ CREATE TABLE MetaData PRIMARY KEY (element) ); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); +INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES('myopic_base_year',2000,''); INSERT INTO MetaData VALUES('link_seasons',1,'Carry storage states between seasons'); +INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); CREATE TABLE MetaDataReal ( element TEXT, @@ -19,8 +20,8 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.4199999999999999845,''); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.42000000000000001776,''); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -56,7 +57,7 @@ CREATE TABLE CapacityCredit PRIMARY KEY (region, period, tech, vintage), CHECK (credit >= 0 AND credit <= 1) ); -INSERT INTO CapacityCredit VALUES('A',2025,'EF',2025,0.5999999999999999778,NULL); +INSERT INTO CapacityCredit VALUES('A',2025,'EF',2025,0.6,NULL); CREATE TABLE CapacityFactorProcess ( region TEXT, @@ -74,11 +75,13 @@ CREATE TABLE CapacityFactorProcess PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorProcess VALUES('A',2025,'s2','d1','EFL',2025,0.8000000000000000444,NULL); -INSERT INTO CapacityFactorProcess VALUES('A',2025,'s1','d2','EFL',2025,0.9000000000000000222,NULL); +INSERT INTO CapacityFactorProcess VALUES('A',2025,'s2','d1','EFL',2025,0.8,NULL); +INSERT INTO CapacityFactorProcess VALUES('A',2025,'s1','d2','EFL',2025,0.9,NULL); CREATE TABLE CapacityFactorTech ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -87,11 +90,11 @@ CREATE TABLE CapacityFactorTech REFERENCES Technology (tech), factor REAL, notes TEXT, - PRIMARY KEY (region, season, tod, tech), + PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('A','s1','d1','EF',0.8000000000000000444,NULL); -INSERT INTO CapacityFactorTech VALUES('B','s2','d2','bulbs',0.75,NULL); +INSERT INTO CapacityFactorTech VALUES('A',2025,'s1','d1','EF',0.8,NULL); +INSERT INTO CapacityFactorTech VALUES('B',2025,'s2','d2','bulbs',0.75,NULL); CREATE TABLE CapacityToActivity ( region TEXT, @@ -126,6 +129,7 @@ CREATE TABLE CommodityType PRIMARY KEY, description TEXT ); +INSERT INTO CommodityType VALUES('a','annual commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); @@ -143,7 +147,7 @@ CREATE TABLE CostEmission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -INSERT INTO CostEmission VALUES ('A', 2025, 'co2', 1.99, 'dollars', 'none' ); +INSERT INTO CostEmission VALUES('A',2025,'co2',1.9900000000000000355,'dollars','none'); CREATE TABLE CostFixed ( region TEXT NOT NULL, @@ -158,7 +162,7 @@ CREATE TABLE CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostFixed VALUES('A',2025,'EH',2025,3.299999999999999823,'',''); +INSERT INTO CostFixed VALUES('A',2025,'EH',2025,3.2999999999999998223,'',''); INSERT INTO CostFixed VALUES('A',2025,'EF',2025,2.0,NULL,NULL); INSERT INTO CostFixed VALUES('A',2025,'EFL',2025,3.0,NULL,NULL); INSERT INTO CostFixed VALUES('B',2025,'batt',2025,1.0,NULL,NULL); @@ -169,7 +173,7 @@ INSERT INTO CostFixed VALUES('A',2025,'heater',2025,2.0,NULL,NULL); INSERT INTO CostFixed VALUES('B',2025,'heater',2025,2.0,NULL,NULL); INSERT INTO CostFixed VALUES('B',2025,'GeoThermal',2025,6.0,NULL,NULL); INSERT INTO CostFixed VALUES('B',2025,'GeoHeater',2025,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('B',2025,'EH',2025,3.299999999999999823,NULL,NULL); +INSERT INTO CostFixed VALUES('B',2025,'EH',2025,3.2999999999999998223,NULL,NULL); INSERT INTO CostFixed VALUES('A',2025,'GeoThermal',2025,4.0,NULL,NULL); INSERT INTO CostFixed VALUES('A',2025,'GeoHeater',2025,4.5,NULL,NULL); CREATE TABLE CostInvest @@ -195,9 +199,9 @@ INSERT INTO CostInvest VALUES('B','heater',2025,9.0,NULL,NULL); INSERT INTO CostInvest VALUES('A','EFL',2025,2.0,NULL,NULL); INSERT INTO CostInvest VALUES('B','GeoThermal',2025,3.0,NULL,NULL); INSERT INTO CostInvest VALUES('B','GeoHeater',2025,4.0,NULL,NULL); -INSERT INTO CostInvest VALUES('B','EH',2025,3.299999999999999823,NULL,NULL); -INSERT INTO CostInvest VALUES('A','GeoThermal',2025,5.599999999999999645,NULL,NULL); -INSERT INTO CostInvest VALUES('A','GeoHeater',2025,4.200000000000000177,NULL,NULL); +INSERT INTO CostInvest VALUES('B','EH',2025,3.2999999999999998223,NULL,NULL); +INSERT INTO CostInvest VALUES('A','GeoThermal',2025,5.5999999999999996447,NULL,NULL); +INSERT INTO CostInvest VALUES('A','GeoHeater',2025,4.2000000000000001776,NULL,NULL); CREATE TABLE CostVariable ( region TEXT NOT NULL, @@ -240,6 +244,8 @@ INSERT INTO Demand VALUES('B',2025,'RH',50.0,NULL,NULL); CREATE TABLE DemandSpecificDistribution ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -247,26 +253,26 @@ CREATE TABLE DemandSpecificDistribution demand_name TEXT REFERENCES Commodity (name), dsd REAL, - dsd_notes TEXT, - PRIMARY KEY (region, season, tod, demand_name), + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('A','s1','d1','RL',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('A','s1','d2','RL',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('A','s2','d1','RL',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('A','s2','d2','RL',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('B','s1','d1','RL',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('B','s1','d2','RL',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('B','s2','d1','RL',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('B','s2','d2','RL',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('A','s1','d1','RH',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('A','s2','d1','RH',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('B','s1','d1','RH',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('B','s2','d1','RH',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('A','s1','d2','RH',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('A','s2','d2','RH',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('B','s1','d2','RH',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('B','s2','d2','RH',0.25,NULL); +INSERT INTO DemandSpecificDistribution VALUES('A',2025,'s1','d1','RL',0.25,NULL); +INSERT INTO DemandSpecificDistribution VALUES('A',2025,'s1','d2','RL',0.25,NULL); +INSERT INTO DemandSpecificDistribution VALUES('A',2025,'s2','d1','RL',0.25,NULL); +INSERT INTO DemandSpecificDistribution VALUES('A',2025,'s2','d2','RL',0.25,NULL); +INSERT INTO DemandSpecificDistribution VALUES('B',2025,'s1','d1','RL',0.25,NULL); +INSERT INTO DemandSpecificDistribution VALUES('B',2025,'s1','d2','RL',0.25,NULL); +INSERT INTO DemandSpecificDistribution VALUES('B',2025,'s2','d1','RL',0.25,NULL); +INSERT INTO DemandSpecificDistribution VALUES('B',2025,'s2','d2','RL',0.25,NULL); +INSERT INTO DemandSpecificDistribution VALUES('A',2025,'s1','d1','RH',0.25,NULL); +INSERT INTO DemandSpecificDistribution VALUES('A',2025,'s2','d1','RH',0.25,NULL); +INSERT INTO DemandSpecificDistribution VALUES('B',2025,'s1','d1','RH',0.25,NULL); +INSERT INTO DemandSpecificDistribution VALUES('B',2025,'s2','d1','RH',0.25,NULL); +INSERT INTO DemandSpecificDistribution VALUES('A',2025,'s1','d2','RH',0.25,NULL); +INSERT INTO DemandSpecificDistribution VALUES('A',2025,'s2','d2','RH',0.25,NULL); +INSERT INTO DemandSpecificDistribution VALUES('B',2025,'s1','d2','RH',0.25,NULL); +INSERT INTO DemandSpecificDistribution VALUES('B',2025,'s2','d2','RH',0.25,NULL); CREATE TABLE LoanRate ( region TEXT, @@ -304,14 +310,36 @@ INSERT INTO Efficiency VALUES('B','HYD','EF',2025,'ELC',1.0,NULL); INSERT INTO Efficiency VALUES('A','earth','well',2025,'HYD',1.0,NULL); INSERT INTO Efficiency VALUES('B','earth','well',2025,'HYD',1.0,NULL); INSERT INTO Efficiency VALUES('A','earth','EFL',2025,'FusionGasFuel',1.0,NULL); -INSERT INTO Efficiency VALUES('A','FusionGasFuel','heater',2025,'RH',0.9000000000000000222,NULL); -INSERT INTO Efficiency VALUES('A-B','FusionGasFuel','FGF_pipe',2025,'FusionGasFuel',0.949999999999999956,NULL); -INSERT INTO Efficiency VALUES('B','FusionGasFuel','heater',2025,'RH',0.9000000000000000222,NULL); -INSERT INTO Efficiency VALUES('B','GeoHyd','GeoHeater',2025,'RH',0.979999999999999983,NULL); +INSERT INTO Efficiency VALUES('A','FusionGasFuel','heater',2025,'RH',0.9,NULL); +INSERT INTO Efficiency VALUES('A-B','FusionGasFuel','FGF_pipe',2025,'FusionGasFuel',0.95,NULL); +INSERT INTO Efficiency VALUES('B','FusionGasFuel','heater',2025,'RH',0.9,NULL); +INSERT INTO Efficiency VALUES('B','GeoHyd','GeoHeater',2025,'RH',0.98000000000000007105,NULL); INSERT INTO Efficiency VALUES('B','earth','GeoThermal',2025,'GeoHyd',1.0,NULL); -INSERT INTO Efficiency VALUES('B-A','FusionGasFuel','FGF_pipe',2025,'FusionGasFuel',0.949999999999999956,NULL); -INSERT INTO Efficiency VALUES('A','GeoHyd','GeoHeater',2025,'RH',0.9000000000000000222,NULL); +INSERT INTO Efficiency VALUES('B-A','FusionGasFuel','FGF_pipe',2025,'FusionGasFuel',0.95,NULL); +INSERT INTO Efficiency VALUES('A','GeoHyd','GeoHeater',2025,'RH',0.9,NULL); INSERT INTO Efficiency VALUES('A','earth','GeoThermal',2025,'GeoHyd',1.0,NULL); +CREATE TABLE EfficiencyVariable +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); CREATE TABLE EmissionActivity ( region TEXT, @@ -330,8 +358,22 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('A','co2','HYD','EH',2025,'ELC',0.02000000000000000041,NULL,NULL); -INSERT INTO EmissionActivity VALUES('A','FusionGas','HYD','EF',2025,'ELC',-0.2000000000000000111,NULL,'needs to be negative as a driver of linked tech...don''t ask'); +INSERT INTO EmissionActivity VALUES('A','co2','HYD','EH',2025,'ELC',0.02,NULL,NULL); +INSERT INTO EmissionActivity VALUES('A','FusionGas','HYD','EF',2025,'ELC',-0.2,NULL,'needs to be negative as a driver of linked tech...don''t ask'); +CREATE TABLE EmissionEmbodied +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); CREATE TABLE ExistingCapacity ( region TEXT, @@ -363,7 +405,7 @@ CREATE TABLE GrowthRateMax notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO GrowthRateMax VALUES('global','GeoHeater',0.2000000000000000111,NULL); +INSERT INTO GrowthRateMax VALUES('global','GeoHeater',0.2,NULL); CREATE TABLE GrowthRateSeed ( region TEXT, @@ -473,7 +515,7 @@ CREATE TABLE MinActivity notes TEXT, PRIMARY KEY (region, period, tech) ); -INSERT INTO MinActivity VALUES('A',2025,'EF',0.00100000000000000002,'PJ/CY','goofy units'); +INSERT INTO MinActivity VALUES('A',2025,'EF',0.001,'PJ/CY','goofy units'); CREATE TABLE MaxCapacityGroup ( region TEXT, @@ -499,8 +541,8 @@ CREATE TABLE MinCapacity notes TEXT, PRIMARY KEY (region, period, tech) ); -INSERT INTO MinCapacity VALUES('A',2025,'EH',0.1000000000000000055,'',''); -INSERT INTO MinCapacity VALUES('B',2025,'batt',0.1000000000000000055,'',''); +INSERT INTO MinCapacity VALUES('A',2025,'EH',0.1,'',''); +INSERT INTO MinCapacity VALUES('B',2025,'batt',0.1,'',''); CREATE TABLE MinCapacityGroup ( region TEXT, @@ -513,7 +555,7 @@ CREATE TABLE MinCapacityGroup notes TEXT, PRIMARY KEY (region, period, group_name) ); -INSERT INTO MinCapacityGroup VALUES('A',2025,'A_tech_grp_1',0.2000000000000000111,'',NULL); +INSERT INTO MinCapacityGroup VALUES('A',2025,'A_tech_grp_1',0.2,'',NULL); CREATE TABLE OutputCurtailment ( scenario TEXT, @@ -611,7 +653,7 @@ CREATE TABLE OutputFlowOut period INTEGER REFERENCES TimePeriod (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -625,6 +667,25 @@ CREATE TABLE OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); +CREATE TABLE OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); CREATE TABLE PlanningReserveMargin ( region TEXT @@ -632,7 +693,7 @@ CREATE TABLE PlanningReserveMargin REFERENCES Region (region), margin REAL ); -INSERT INTO PlanningReserveMargin VALUES('A',0.05000000000000000277); +INSERT INTO PlanningReserveMargin VALUES('A',0.05); CREATE TABLE RampDown ( region TEXT, @@ -662,20 +723,22 @@ CREATE TABLE Region INSERT INTO Region VALUES('A','main region'); INSERT INTO Region VALUES('B','just a 2nd region'); CREATE TABLE TimeSegmentFraction -( +( + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, notes TEXT, - PRIMARY KEY (season, tod), + PRIMARY KEY (period, season, tod), CHECK (segfrac >= 0 AND segfrac <= 1) ); -INSERT INTO TimeSegmentFraction VALUES('s2','d1',0.25,NULL); -INSERT INTO TimeSegmentFraction VALUES('s2','d2',0.25,NULL); -INSERT INTO TimeSegmentFraction VALUES('s1','d1',0.25,NULL); -INSERT INTO TimeSegmentFraction VALUES('s1','d2',0.25,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d1',0.25,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d2',0.25,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d1',0.25,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d2',0.25,NULL); CREATE TABLE StorageDuration ( region TEXT, @@ -685,12 +748,22 @@ CREATE TABLE StorageDuration PRIMARY KEY (region, tech) ); INSERT INTO StorageDuration VALUES('B','batt',15.0,NULL); -CREATE TABLE StorageInit +CREATE TABLE StorageLevelFraction ( - tech TEXT - PRIMARY KEY, - value REAL, - notes TEXT + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage) ); CREATE TABLE TechnologyType ( @@ -744,6 +817,71 @@ CREATE TABLE MinTechOutputSplit PRIMARY KEY (region, period, tech, output_comm) ); INSERT INTO MinTechOutputSplit VALUES('B',2025,'EH','ELC',0.949999999999999956,'95% ELC output (there are not others, this is a min)'); +CREATE TABLE MinTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MaxTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MaxTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -765,12 +903,23 @@ INSERT INTO TimePeriod VALUES(2,2025,'f'); INSERT INTO TimePeriod VALUES(3,2030,'f'); CREATE TABLE TimeSeason ( - sequence INTEGER UNIQUE, - season TEXT + season TEXT PRIMARY KEY ); -INSERT INTO TimeSeason VALUES(1,'s1'); -INSERT INTO TimeSeason VALUES(2,'s2'); +INSERT INTO TimeSeason VALUES('s1'); +INSERT INTO TimeSeason VALUES('s2'); +CREATE TABLE PeriodSeasons +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT + REFERENCES TimeSeason (season), + notes TEXT, + PRIMARY KEY (period, sequence) +); +INSERT INTO PeriodSeasons VALUES(2025,1,'s1',NULL); +INSERT INTO PeriodSeasons VALUES(2025,2,'s2',NULL); CREATE TABLE TimePeriodType ( label TEXT @@ -857,20 +1006,6 @@ CREATE TABLE MaxNewCapacityShare notes TEXT, PRIMARY KEY (region, period, tech, group_name) ); -CREATE TABLE MaxNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); -INSERT INTO MaxNewCapacityGroupShare VALUES('global', 2025, 'RPS_common', 'A_tech_grp_1', 1, ''); CREATE TABLE MinActivityShare ( region TEXT, @@ -945,7 +1080,7 @@ CREATE TABLE MinNewCapacityShare REFERENCES Technology (tech), group_name TEXT REFERENCES TechGroup (group_name), - max_proportion REAL, + min_proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, group_name) ); @@ -962,7 +1097,21 @@ CREATE TABLE MinNewCapacityGroupShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group) ); -INSERT INTO MinNewCapacityGroupShare VALUES('A', 2025, 'RPS_common', 'A_tech_grp_1', 0, ''); +INSERT INTO MinNewCapacityGroupShare VALUES('A',2025,'RPS_common','A_tech_grp_1',0.0,''); +CREATE TABLE MaxNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); +INSERT INTO MaxNewCapacityGroupShare VALUES('global',2025,'RPS_common','A_tech_grp_1',1.0,''); CREATE TABLE OutputEmission ( scenario TEXT, @@ -992,7 +1141,7 @@ CREATE TABLE MinActivityGroup notes TEXT, PRIMARY KEY (region, period, group_name) ); -INSERT INTO MinActivityGroup VALUES('A',2025,'A_tech_grp_1',0.05000000000000000277,'',NULL); +INSERT INTO MinActivityGroup VALUES('A',2025,'A_tech_grp_1',0.05,'',NULL); CREATE TABLE EmissionLimit ( region TEXT, @@ -1019,6 +1168,36 @@ CREATE TABLE MaxActivityGroup PRIMARY KEY (region, period, group_name) ); INSERT INTO MaxActivityGroup VALUES('A',2025,'A_tech_grp_1',10000.0,'',NULL); +CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "min_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); +CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "max_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); CREATE TABLE RPSRequirement ( region TEXT NOT NULL @@ -1030,7 +1209,7 @@ CREATE TABLE RPSRequirement requirement REAL NOT NULL, notes TEXT ); -INSERT INTO RPSRequirement VALUES('B',2025,'RPS_common',0.2999999999999999889,NULL); +INSERT INTO RPSRequirement VALUES('B',2025,'RPS_common',0.3,NULL); CREATE TABLE TechGroupMember ( group_name TEXT @@ -1055,21 +1234,20 @@ CREATE TABLE Technology curtail INTEGER NOT NULL DEFAULT 0, retire INTEGER NOT NULL DEFAULT 0, flex INTEGER NOT NULL DEFAULT 0, - variable INTEGER NOT NULL DEFAULT 0, exchange INTEGER NOT NULL DEFAULT 0, description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('well','r','supply','water','',0,0,0,0,0,0,0,0,'plain old water'); -INSERT INTO Technology VALUES('bulbs','p','residential','electric','',0,0,0,0,0,0,0,0,'residential lighting'); -INSERT INTO Technology VALUES('EH','pb','electric','hydro','',0,0,1,1,1,0,0,0,'hydro power electric plant'); -INSERT INTO Technology VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0,0,'big battery'); -INSERT INTO Technology VALUES('EF','p','electric','electric','',0,0,0,0,0,0,0,0,'fusion plant'); -INSERT INTO Technology VALUES('EFL','p','electric','electric','',0,0,0,0,0,1,0,0,'linked (to Fusion) producer'); -INSERT INTO Technology VALUES('heater','p','residential','electric','',0,0,0,0,0,0,0,0,'heater'); -INSERT INTO Technology VALUES('FGF_pipe','p','transport',NULL,'',0,0,0,0,0,0,0,1,'transportation line A->B'); -INSERT INTO Technology VALUES('GeoThermal','p','residential','hydro','',0,1,0,0,0,0,0,0,'geothermal hot water source'); -INSERT INTO Technology VALUES('GeoHeater','p','residential','hydro','',0,0,0,0,0,0,1,0,'geothermal heater from geo hyd'); +INSERT INTO Technology VALUES('well','r','supply','water','',0,0,0,0,0,0,0,'plain old water'); +INSERT INTO Technology VALUES('bulbs','p','residential','electric','',0,0,0,0,0,0,0,'residential lighting'); +INSERT INTO Technology VALUES('EH','pb','electric','hydro','',0,0,1,1,1,0,0,'hydro power electric plant'); +INSERT INTO Technology VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0,'big battery'); +INSERT INTO Technology VALUES('EF','p','electric','electric','',0,0,0,0,0,0,0,'fusion plant'); +INSERT INTO Technology VALUES('EFL','p','electric','electric','',0,0,0,0,0,1,0,'linked (to Fusion) producer'); +INSERT INTO Technology VALUES('heater','p','residential','electric','',0,0,0,0,0,0,0,'heater'); +INSERT INTO Technology VALUES('FGF_pipe','p','transport',NULL,'',0,0,0,0,0,0,1,'transportation line A->B'); +INSERT INTO Technology VALUES('GeoThermal','p','residential','hydro','',0,1,0,0,0,0,0,'geothermal hot water source'); +INSERT INTO Technology VALUES('GeoHeater','p','residential','hydro','',0,0,0,0,0,0,0,'geothermal heater from geo hyd'); CREATE TABLE OutputCost ( scenario TEXT, diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index f3b222015..52d8485c9 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -8,9 +8,10 @@ CREATE TABLE MetaData PRIMARY KEY (element) ); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); +INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES('myopic_base_year',1990,''); INSERT INTO MetaData VALUES('link_seasons',1,'Carry storage states between seasons'); +INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); CREATE TABLE MetaDataReal ( element TEXT, @@ -76,6 +77,8 @@ CREATE TABLE CapacityFactorProcess CREATE TABLE CapacityFactorTech ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -84,7 +87,7 @@ CREATE TABLE CapacityFactorTech REFERENCES Technology (tech), factor REAL, notes TEXT, - PRIMARY KEY (region, season, tod, tech), + PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE CapacityToActivity @@ -115,6 +118,7 @@ CREATE TABLE CommodityType PRIMARY KEY, description TEXT ); +INSERT INTO CommodityType VALUES('a','annual commodity'); INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); @@ -195,6 +199,8 @@ INSERT INTO Demand VALUES('linkville',2000,'ELC',10.0,NULL,NULL); CREATE TABLE DemandSpecificDistribution ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -202,12 +208,12 @@ CREATE TABLE DemandSpecificDistribution demand_name TEXT REFERENCES Commodity (name), dsd REAL, - dsd_notes TEXT, - PRIMARY KEY (region, season, tod, demand_name), + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('linkville','summer','day','ELC',0.5,''); -INSERT INTO DemandSpecificDistribution VALUES('linkville','winter','day','ELC',0.5,''); +INSERT INTO DemandSpecificDistribution VALUES('linkville',2000,'summer','day','ELC',0.5,''); +INSERT INTO DemandSpecificDistribution VALUES('linkville',2000,'winter','day','ELC',0.5,''); CREATE TABLE LoanRate ( region TEXT, @@ -239,6 +245,28 @@ INSERT INTO Efficiency VALUES('linkville','ETHOS','MINE',2000,'NGA',1.0,''); INSERT INTO Efficiency VALUES('linkville','ETHOS','CCS',2000,'CO2_CAP',1.0,'capture eff'); INSERT INTO Efficiency VALUES('linkville','ETHOS','FAKE_SOURCE',2000,'CO2_CAP',1.0,''); INSERT INTO Efficiency VALUES('linkville','NGA','PLANT',2000,'ELC',0.5,NULL); +CREATE TABLE EfficiencyVariable +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); CREATE TABLE EmissionActivity ( region TEXT, @@ -258,6 +286,20 @@ CREATE TABLE EmissionActivity PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); INSERT INTO EmissionActivity VALUES('linkville','CO2','NGA','PLANT',2000,'ELC',-3.0,'',''); +CREATE TABLE EmissionEmbodied +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); CREATE TABLE ExistingCapacity ( region TEXT, @@ -518,7 +560,7 @@ CREATE TABLE OutputFlowOut period INTEGER REFERENCES TimePeriod (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -532,6 +574,25 @@ CREATE TABLE OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); +CREATE TABLE OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); CREATE TABLE PlanningReserveMargin ( region TEXT @@ -563,18 +624,20 @@ CREATE TABLE Region ); INSERT INTO Region VALUES('linkville',NULL); CREATE TABLE TimeSegmentFraction -( +( + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, notes TEXT, - PRIMARY KEY (season, tod), + PRIMARY KEY (period, season, tod), CHECK (segfrac >= 0 AND segfrac <= 1) ); -INSERT INTO TimeSegmentFraction VALUES('summer','day',0.5,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES('winter','day',0.5,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'summer','day',0.5,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'winter','day',0.5,'# W-D'); CREATE TABLE StorageDuration ( region TEXT, @@ -583,12 +646,22 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE StorageInit +CREATE TABLE StorageLevelFraction ( - tech TEXT - PRIMARY KEY, - value REAL, - notes TEXT + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage) ); CREATE TABLE TechnologyType ( @@ -639,6 +712,71 @@ CREATE TABLE MinTechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm) ); +CREATE TABLE MinTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MaxTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MaxTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -659,12 +797,23 @@ INSERT INTO TimePeriod VALUES(1,2000,'f'); INSERT INTO TimePeriod VALUES(2,2005,'f'); CREATE TABLE TimeSeason ( - sequence INTEGER UNIQUE, - season TEXT + season TEXT PRIMARY KEY ); -INSERT INTO TimeSeason VALUES(1,'summer'); -INSERT INTO TimeSeason VALUES(2,'winter'); +INSERT INTO TimeSeason VALUES('summer'); +INSERT INTO TimeSeason VALUES('winter'); +CREATE TABLE PeriodSeasons +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT + REFERENCES TimeSeason (season), + notes TEXT, + PRIMARY KEY (period, sequence) +); +INSERT INTO PeriodSeasons VALUES(2000,1,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2000,2,'winter',NULL); CREATE TABLE TimePeriodType ( label TEXT @@ -825,10 +974,36 @@ CREATE TABLE MinNewCapacityShare REFERENCES Technology (tech), group_name TEXT REFERENCES TechGroup (group_name), - max_proportion REAL, + min_proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, group_name) ); +CREATE TABLE MinNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); +CREATE TABLE MaxNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); CREATE TABLE OutputEmission ( scenario TEXT, @@ -882,6 +1057,36 @@ CREATE TABLE MaxActivityGroup notes TEXT, PRIMARY KEY (region, period, group_name) ); +CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "min_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); +CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "max_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); CREATE TABLE RPSRequirement ( region TEXT NOT NULL @@ -914,15 +1119,14 @@ CREATE TABLE Technology curtail INTEGER NOT NULL DEFAULT 0, retire INTEGER NOT NULL DEFAULT 0, flex INTEGER NOT NULL DEFAULT 0, - variable INTEGER NOT NULL DEFAULT 0, exchange INTEGER NOT NULL DEFAULT 0, description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('PLANT','p','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('CCS','r','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('MINE','r','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('FAKE_SOURCE','r','supply',NULL,NULL,1,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('PLANT','p','supply',NULL,NULL,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('CCS','r','supply',NULL,NULL,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('MINE','r','supply',NULL,NULL,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('FAKE_SOURCE','r','supply',NULL,NULL,1,0,0,0,0,0,0,NULL); CREATE TABLE OutputCost ( scenario TEXT, @@ -942,19 +1146,4 @@ CREATE TABLE OutputCost FOREIGN KEY (vintage) REFERENCES TimePeriod (period), FOREIGN KEY (tech) REFERENCES Technology (tech) ); -CREATE TABLE MyopicEfficiency -( - base_year integer, - region text, - input_comm text, - tech text, - vintage integer, - output_comm text, - efficiency real, - lifetime integer, - - FOREIGN KEY (tech) REFERENCES Technology (tech), - PRIMARY KEY (region, input_comm, tech, vintage, output_comm) -); -CREATE INDEX region_tech_vintage ON MyopicEfficiency (region, tech, vintage); COMMIT; diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index da236bbc3..cc598dbcb 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -8,9 +8,10 @@ CREATE TABLE MetaData PRIMARY KEY (element) ); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); +INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES('myopic_base_year',2000,''); INSERT INTO MetaData VALUES('link_seasons',1,'Carry storage states between seasons'); +INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); CREATE TABLE MetaDataReal ( element TEXT, @@ -19,8 +20,8 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,''); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -76,6 +77,8 @@ CREATE TABLE CapacityFactorProcess CREATE TABLE CapacityFactorTech ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -84,7 +87,7 @@ CREATE TABLE CapacityFactorTech REFERENCES Technology (tech), factor REAL, notes TEXT, - PRIMARY KEY (region, season, tod, tech), + PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE CapacityToActivity @@ -116,6 +119,7 @@ CREATE TABLE CommodityType PRIMARY KEY, description TEXT ); +INSERT INTO CommodityType VALUES('a','annual commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); @@ -195,6 +199,8 @@ INSERT INTO Demand VALUES('electricville',2025,'RL',100.0,'',''); CREATE TABLE DemandSpecificDistribution ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -202,20 +208,20 @@ CREATE TABLE DemandSpecificDistribution demand_name TEXT REFERENCES Commodity (name), dsd REAL, - dsd_notes TEXT, - PRIMARY KEY (region, season, tod, demand_name), + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('electricville','s1','d1','RL',0.07499999999999999723,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville','s1','d2','RL',0.07499999999999999723,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville','s1','d3','RL',0.07499999999999999723,NULL); -INSERT INTO DemandSpecificDistribution VALUES('electricville','s2','d1','RL',0.07499999999999999723,NULL); -INSERT INTO DemandSpecificDistribution VALUES('electricville','s2','d2','RL',0.07499999999999999723,NULL); -INSERT INTO DemandSpecificDistribution VALUES('electricville','s2','d3','RL',0.07499999999999999723,NULL); -INSERT INTO DemandSpecificDistribution VALUES('electricville','s1','d4','RL',0.07499999999999999723,NULL); -INSERT INTO DemandSpecificDistribution VALUES('electricville','s1','d5','RL',0.2000000000000000111,NULL); -INSERT INTO DemandSpecificDistribution VALUES('electricville','s2','d4','RL',0.2000000000000000111,NULL); -INSERT INTO DemandSpecificDistribution VALUES('electricville','s2','d5','RL',0.07499999999999999723,NULL); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s1','d1','RL',0.075,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s1','d2','RL',0.075,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s1','d3','RL',0.075,NULL); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s2','d1','RL',0.075,NULL); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s2','d2','RL',0.075,NULL); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s2','d3','RL',0.075,NULL); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s1','d4','RL',0.075,NULL); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s1','d5','RL',0.2,NULL); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s2','d4','RL',0.2,NULL); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s2','d5','RL',0.075,NULL); CREATE TABLE LoanRate ( region TEXT, @@ -247,6 +253,28 @@ INSERT INTO Efficiency VALUES('electricville','HYD','EH',2025,'ELC',1.0,NULL); INSERT INTO Efficiency VALUES('electricville','ELC','bulbs',2025,'RL',1.0,NULL); INSERT INTO Efficiency VALUES('electricville','earth','well',2025,'HYD',1.0,'water source'); INSERT INTO Efficiency VALUES('electricville','ELC','batt',2025,'ELC',0.75,NULL); +CREATE TABLE EfficiencyVariable +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); CREATE TABLE EmissionActivity ( region TEXT, @@ -265,7 +293,21 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('electricville','co2','HYD','EH',2025,'ELC',0.02000000000000000041,NULL,NULL); +INSERT INTO EmissionActivity VALUES('electricville','co2','HYD','EH',2025,'ELC',0.02,NULL,NULL); +CREATE TABLE EmissionEmbodied +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); CREATE TABLE ExistingCapacity ( region TEXT, @@ -418,8 +460,8 @@ CREATE TABLE MinCapacity notes TEXT, PRIMARY KEY (region, period, tech) ); -INSERT INTO MinCapacity VALUES('electricville',2025,'EH',0.1000000000000000055,'',''); -INSERT INTO MinCapacity VALUES('electricville',2025,'batt',0.1000000000000000055,'',''); +INSERT INTO MinCapacity VALUES('electricville',2025,'EH',0.1,'',''); +INSERT INTO MinCapacity VALUES('electricville',2025,'batt',0.1,'',''); CREATE TABLE MinCapacityGroup ( region TEXT, @@ -529,7 +571,7 @@ CREATE TABLE OutputFlowOut period INTEGER REFERENCES TimePeriod (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -543,6 +585,25 @@ CREATE TABLE OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); +CREATE TABLE OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); CREATE TABLE PlanningReserveMargin ( region TEXT @@ -574,26 +635,28 @@ CREATE TABLE Region ); INSERT INTO Region VALUES('electricville',NULL); CREATE TABLE TimeSegmentFraction -( +( + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, notes TEXT, - PRIMARY KEY (season, tod), + PRIMARY KEY (period, season, tod), CHECK (segfrac >= 0 AND segfrac <= 1) ); -INSERT INTO TimeSegmentFraction VALUES('s1','d3',0.1000000000000000055,NULL); -INSERT INTO TimeSegmentFraction VALUES('s2','d1',0.1000000000000000055,NULL); -INSERT INTO TimeSegmentFraction VALUES('s2','d2',0.1000000000000000055,NULL); -INSERT INTO TimeSegmentFraction VALUES('s2','d3',0.1000000000000000055,NULL); -INSERT INTO TimeSegmentFraction VALUES('s1','d1',0.1000000000000000055,NULL); -INSERT INTO TimeSegmentFraction VALUES('s1','d2',0.1000000000000000055,NULL); -INSERT INTO TimeSegmentFraction VALUES('s1','d4',0.1000000000000000055,NULL); -INSERT INTO TimeSegmentFraction VALUES('s1','d5',0.1000000000000000055,NULL); -INSERT INTO TimeSegmentFraction VALUES('s2','d4',0.1000000000000000055,NULL); -INSERT INTO TimeSegmentFraction VALUES('s2','d5',0.1000000000000000055,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d3',0.1,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d1',0.1,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d2',0.1,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d3',0.1,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d1',0.1,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d2',0.1,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d4',0.1,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d5',0.1,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d4',0.1,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d5',0.1,NULL); CREATE TABLE StorageDuration ( region TEXT, @@ -603,19 +666,24 @@ CREATE TABLE StorageDuration PRIMARY KEY (region, tech) ); INSERT INTO StorageDuration VALUES('electricville','batt',10.0,NULL); -CREATE TABLE StorageFraction -( - region TEXT, - period INTEGER REFERENCES TimePeriod (period), - season TEXT REFERENCES TimeSeason (season), - tod TEXT REFERENCES TimeOfDay (tod), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), - frac REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage) +CREATE TABLE StorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage) ); -INSERT INTO StorageFraction VALUES('electricville',2025,'s1','d1','batt',2025,0.5,''); +INSERT INTO StorageLevelFraction VALUES('electricville',2025,'s1','d1','batt',2025,0.5,NULL); CREATE TABLE TechnologyType ( label TEXT @@ -665,6 +733,71 @@ CREATE TABLE MinTechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm) ); +CREATE TABLE MinTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MaxTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MaxTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -689,12 +822,23 @@ INSERT INTO TimePeriod VALUES(2,2025,'f'); INSERT INTO TimePeriod VALUES(3,2030,'f'); CREATE TABLE TimeSeason ( - sequence INTEGER UNIQUE, - season TEXT + season TEXT PRIMARY KEY ); -INSERT INTO TimeSeason VALUES(1,'s1'); -INSERT INTO TimeSeason VALUES(2,'s2'); +INSERT INTO TimeSeason VALUES('s1'); +INSERT INTO TimeSeason VALUES('s2'); +CREATE TABLE PeriodSeasons +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT + REFERENCES TimeSeason (season), + notes TEXT, + PRIMARY KEY (period, sequence) +); +INSERT INTO PeriodSeasons VALUES(2025,1,'s1',NULL); +INSERT INTO PeriodSeasons VALUES(2025,2,'s2',NULL); CREATE TABLE TimePeriodType ( label TEXT @@ -855,10 +999,36 @@ CREATE TABLE MinNewCapacityShare REFERENCES Technology (tech), group_name TEXT REFERENCES TechGroup (group_name), - max_proportion REAL, + min_proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, group_name) ); +CREATE TABLE MinNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); +CREATE TABLE MaxNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); CREATE TABLE OutputEmission ( scenario TEXT, @@ -912,6 +1082,36 @@ CREATE TABLE MaxActivityGroup notes TEXT, PRIMARY KEY (region, period, group_name) ); +CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "min_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); +CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "max_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); CREATE TABLE RPSRequirement ( region TEXT NOT NULL @@ -944,15 +1144,14 @@ CREATE TABLE Technology curtail INTEGER NOT NULL DEFAULT 0, retire INTEGER NOT NULL DEFAULT 0, flex INTEGER NOT NULL DEFAULT 0, - variable INTEGER NOT NULL DEFAULT 0, exchange INTEGER NOT NULL DEFAULT 0, description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('well','r','supply','water','',0,0,0,0,0,0,0,0,'plain old water'); -INSERT INTO Technology VALUES('bulbs','p','residential','electric','',0,0,0,0,0,0,0,0,' residential lighting'); -INSERT INTO Technology VALUES('EH','pb','electric','hydro','',0,0,0,0,0,0,0,0,'hydro power electric plant'); -INSERT INTO Technology VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0,0,'big battery'); +INSERT INTO Technology VALUES('well','r','supply','water','',0,0,0,0,0,0,0,'plain old water'); +INSERT INTO Technology VALUES('bulbs','p','residential','electric','',0,0,0,0,0,0,0,' residential lighting'); +INSERT INTO Technology VALUES('EH','pb','electric','hydro','',0,0,0,0,0,0,0,'hydro power electric plant'); +INSERT INTO Technology VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0,'big battery'); CREATE TABLE OutputCost ( scenario TEXT, diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 2279e1e48..9296bdf85 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -9,8 +9,9 @@ CREATE TABLE MetaData ); INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); +INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES('link_seasons',1,'Carry storage states between seasons'); +INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); CREATE TABLE MetaDataReal ( element TEXT, @@ -76,6 +77,8 @@ CREATE TABLE CapacityFactorProcess CREATE TABLE CapacityFactorTech ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -84,25 +87,57 @@ CREATE TABLE CapacityFactorTech REFERENCES Technology (tech), factor REAL, notes TEXT, - PRIMARY KEY (region, season, tod, tech), + PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('R1','spring','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1','spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1','summer','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1','summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1','fall','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1','fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1','winter','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1','winter','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2','spring','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2','spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2','summer','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2','summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2','fall','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2','fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2','winter','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2','winter','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'spring','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'spring','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'summer','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'summer','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'fall','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'fall','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'winter','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'winter','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'spring','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'spring','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'summer','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'summer','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'fall','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'fall','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'winter','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'winter','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'spring','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'spring','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'summer','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'summer','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'fall','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'fall','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'winter','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'winter','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'spring','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'spring','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'summer','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'summer','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'fall','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'fall','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'winter','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'winter','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'spring','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'spring','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'summer','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'summer','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'fall','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'fall','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'winter','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'winter','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'spring','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'spring','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'summer','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'summer','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'fall','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'fall','night','E_SOLPV',0.0,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'winter','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'winter','night','E_SOLPV',0.0,''); CREATE TABLE CapacityToActivity ( region TEXT, @@ -117,10 +152,10 @@ INSERT INTO CapacityToActivity VALUES('R1','S_IMPOIL',1.0,''); INSERT INTO CapacityToActivity VALUES('R1','S_IMPNG',1.0,''); INSERT INTO CapacityToActivity VALUES('R1','S_IMPURN',1.0,''); INSERT INTO CapacityToActivity VALUES('R1','S_OILREF',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1','E_NGCC',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R1','E_SOLPV',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R1','E_BATT',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R1','E_NUCLEAR',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('R1','E_NGCC',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('R1','E_SOLPV',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('R1','E_BATT',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('R1','E_NUCLEAR',31.539999999999999147,''); INSERT INTO CapacityToActivity VALUES('R1','T_BLND',1.0,''); INSERT INTO CapacityToActivity VALUES('R1','T_DSL',1.0,''); INSERT INTO CapacityToActivity VALUES('R1','T_GSL',1.0,''); @@ -132,18 +167,18 @@ INSERT INTO CapacityToActivity VALUES('R2','S_IMPOIL',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','S_IMPNG',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','S_IMPURN',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','S_OILREF',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','E_NGCC',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R2','E_SOLPV',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R2','E_BATT',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R2','E_NUCLEAR',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('R2','E_NGCC',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('R2','E_SOLPV',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('R2','E_BATT',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('R2','E_NUCLEAR',31.539999999999999147,''); INSERT INTO CapacityToActivity VALUES('R2','T_BLND',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','T_DSL',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','T_GSL',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','T_EV',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','R_EH',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','R_NGH',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1-R2','E_TRANS',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R2-R1','E_TRANS',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('R1-R2','E_TRANS',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('R2-R1','E_TRANS',31.539999999999999147,''); CREATE TABLE Commodity ( name TEXT @@ -171,6 +206,7 @@ CREATE TABLE CommodityType PRIMARY KEY, description TEXT ); +INSERT INTO CommodityType VALUES('a','annual commodity'); INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); @@ -202,54 +238,54 @@ CREATE TABLE CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostFixed VALUES('R1',2020,'E_NGCC',2020,30.60000000000000142,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_NGCC',2020,9.77999999999999937,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_NGCC',2025,9.77999999999999937,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2020,9.77999999999999937,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2025,9.77999999999999937,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2030,9.77999999999999937,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2020,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_SOLPV',2025,9.099999999999999645,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2025,9.099999999999999645,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2030,9.099999999999999645,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2020,'E_NUCLEAR',2020,98.0999999999999944,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_NUCLEAR',2020,98.0999999999999944,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_NUCLEAR',2025,98.0999999999999944,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2020,98.0999999999999944,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2025,98.0999999999999944,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2030,98.0999999999999944,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2020,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_BATT',2025,7.049999999999999823,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2025,7.049999999999999823,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2030,7.049999999999999823,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2020,'E_NGCC',2020,24.48000000000000042,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_NGCC',2020,7.823999999999999844,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_NGCC',2025,7.823999999999999844,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2020,7.823999999999999844,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2025,7.823999999999999844,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2030,7.823999999999999844,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2020,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_SOLPV',2025,7.280000000000000248,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2025,7.280000000000000248,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2030,7.280000000000000248,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2020,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_NUCLEAR',2025,78.48000000000000397,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2025,78.48000000000000397,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2030,78.48000000000000397,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2020,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_BATT',2025,5.639999999999999681,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2025,5.639999999999999681,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2030,5.639999999999999681,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2020,'E_NGCC',2020,30.600000000000000532,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_NGCC',2020,9.7799999999999993605,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_NGCC',2025,9.7799999999999993605,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2020,9.7799999999999993605,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2025,9.7799999999999993605,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2030,9.7799999999999993605,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2020,'E_SOLPV',2020,10.400000000000000355,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_SOLPV',2020,10.400000000000000355,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_SOLPV',2025,9.0999999999999996447,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2020,10.400000000000000355,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2025,9.0999999999999996447,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2030,9.0999999999999996447,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2020,'E_NUCLEAR',2020,98.09999999999998721,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_NUCLEAR',2020,98.09999999999998721,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_NUCLEAR',2025,98.09999999999998721,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2020,98.09999999999998721,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2025,98.09999999999998721,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2030,98.09999999999998721,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2020,'E_BATT',2020,7.0499999999999998223,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_BATT',2020,7.0499999999999998223,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_BATT',2025,7.0499999999999998223,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2020,7.0499999999999998223,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2025,7.0499999999999998223,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2030,7.0499999999999998223,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2020,'E_NGCC',2020,24.479999999999999538,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_NGCC',2020,7.8239999999999998436,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_NGCC',2025,7.8239999999999998436,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2020,7.8239999999999998436,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2025,7.8239999999999998436,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2030,7.8239999999999998436,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2020,'E_SOLPV',2020,8.3200000000000002842,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_SOLPV',2020,8.3200000000000002842,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_SOLPV',2025,7.2800000000000002486,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2020,8.3200000000000002842,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2025,7.2800000000000002486,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2030,7.2800000000000002486,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2020,'E_NUCLEAR',2020,78.480000000000007531,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_NUCLEAR',2020,78.480000000000007531,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_NUCLEAR',2025,78.480000000000007531,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2020,78.480000000000007531,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2025,78.480000000000007531,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2030,78.480000000000007531,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2020,'E_BATT',2020,5.6399999999999996802,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_BATT',2020,5.6399999999999996802,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_BATT',2025,5.6399999999999996802,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2020,5.6399999999999996802,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2025,5.6399999999999996802,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2030,5.6399999999999996802,'$M/GWyr',''); CREATE TABLE CostInvest ( region TEXT, @@ -283,12 +319,12 @@ INSERT INTO CostInvest VALUES('R1','T_DSL',2030,2810.0,'$/bvmt/yr',''); INSERT INTO CostInvest VALUES('R1','T_EV',2020,3100.0,'$/bvmt/yr',''); INSERT INTO CostInvest VALUES('R1','T_EV',2025,3030.0,'$/bvmt/yr',''); INSERT INTO CostInvest VALUES('R1','T_EV',2030,2925.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R1','R_EH',2020,4.099999999999999644,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_EH',2025,4.099999999999999644,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_EH',2030,4.099999999999999644,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_NGH',2020,7.599999999999999645,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_NGH',2025,7.599999999999999645,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_NGH',2030,7.599999999999999645,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R1','R_EH',2020,4.0999999999999996447,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R1','R_EH',2025,4.0999999999999996447,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R1','R_EH',2030,4.0999999999999996447,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R1','R_NGH',2020,7.5999999999999996447,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R1','R_NGH',2025,7.5999999999999996447,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R1','R_NGH',2030,7.5999999999999996447,'$/PJ/yr',''); INSERT INTO CostInvest VALUES('R2','E_NGCC',2020,840.0,'$M/GW',''); INSERT INTO CostInvest VALUES('R2','E_NGCC',2025,820.0,'$M/GW',''); INSERT INTO CostInvest VALUES('R2','E_NGCC',2030,800.0,'$M/GW',''); @@ -310,9 +346,9 @@ INSERT INTO CostInvest VALUES('R2','T_DSL',2030,2248.0,'$/bvmt/yr',''); INSERT INTO CostInvest VALUES('R2','T_EV',2020,2480.0,'$/bvmt/yr',''); INSERT INTO CostInvest VALUES('R2','T_EV',2025,2424.0,'$/bvmt/yr',''); INSERT INTO CostInvest VALUES('R2','T_EV',2030,2340.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R2','R_EH',2020,3.279999999999999805,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R2','R_EH',2025,3.279999999999999805,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R2','R_EH',2030,3.279999999999999805,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R2','R_EH',2020,3.2799999999999998046,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R2','R_EH',2025,3.2799999999999998046,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R2','R_EH',2030,3.2799999999999998046,'$/PJ/yr',''); INSERT INTO CostInvest VALUES('R2','R_NGH',2020,6.080000000000000071,'$/PJ/yr',''); INSERT INTO CostInvest VALUES('R2','R_NGH',2025,6.080000000000000071,'$/PJ/yr',''); INSERT INTO CostInvest VALUES('R2','R_NGH',2030,6.080000000000000071,'$/PJ/yr',''); @@ -342,48 +378,48 @@ INSERT INTO CostVariable VALUES('R1',2030,'S_IMPNG',2020,4.0,'$M/PJ',''); INSERT INTO CostVariable VALUES('R1',2020,'S_OILREF',2020,1.0,'$M/PJ',''); INSERT INTO CostVariable VALUES('R1',2025,'S_OILREF',2020,1.0,'$M/PJ',''); INSERT INTO CostVariable VALUES('R1',2030,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2020,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'E_NGCC',2025,1.699999999999999956,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2025,1.699999999999999956,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2030,1.800000000000000044,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2020,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2020,'E_NGCC',2020,1.6000000000000000888,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2025,'E_NGCC',2020,1.6000000000000000888,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2025,'E_NGCC',2025,1.7,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2020,1.6000000000000000888,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2025,1.7,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2030,1.8,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2020,'E_NUCLEAR',2020,0.23999999999999999111,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2025,'E_NUCLEAR',2020,0.23999999999999999111,'$M/PJ',''); INSERT INTO CostVariable VALUES('R1',2025,'E_NUCLEAR',2025,0.25,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2020,0.23999999999999999111,'$M/PJ',''); INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2025,0.25,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2030,0.2600000000000000088,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2030,0.26000000000000000888,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2020,'S_IMPETH',2020,25.600000000000000532,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'S_IMPETH',2020,25.600000000000000532,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'S_IMPETH',2020,25.600000000000000532,'$M/PJ',''); INSERT INTO CostVariable VALUES('R2',2020,'S_IMPOIL',2020,16.0,'$M/PJ',''); INSERT INTO CostVariable VALUES('R2',2025,'S_IMPOIL',2020,16.0,'$M/PJ',''); INSERT INTO CostVariable VALUES('R2',2030,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'E_NGCC',2025,1.360000000000000097,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2025,1.360000000000000097,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2030,1.439999999999999947,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'E_NUCLEAR',2025,0.2000000000000000111,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2025,0.2000000000000000111,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2030,0.2079999999999999905,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1-R2',2020,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1-R2',2025,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1-R2',2030,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2-R1',2020,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2-R1',2025,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2-R1',2030,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2020,'S_IMPNG',2020,3.2000000000000001776,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'S_IMPNG',2020,3.2000000000000001776,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'S_IMPNG',2020,3.2000000000000001776,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2020,'S_OILREF',2020,0.8,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'S_OILREF',2020,0.8,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'S_OILREF',2020,0.8,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2020,'E_NGCC',2020,1.2800000000000000355,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'E_NGCC',2020,1.2800000000000000355,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'E_NGCC',2025,1.3600000000000000976,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2020,1.2800000000000000355,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2025,1.3600000000000000976,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2030,1.4399999999999999467,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2020,'E_NUCLEAR',2020,0.19199999999999999289,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'E_NUCLEAR',2020,0.19199999999999999289,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'E_NUCLEAR',2025,0.2,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2020,0.19199999999999999289,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2025,0.2,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2030,0.2080000000000000071,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1-R2',2020,'E_TRANS',2015,0.1,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1-R2',2025,'E_TRANS',2015,0.1,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1-R2',2030,'E_TRANS',2015,0.1,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2-R1',2020,'E_TRANS',2015,0.1,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2-R1',2025,'E_TRANS',2015,0.1,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2-R1',2030,'E_TRANS',2015,0.1,'$M/PJ',''); CREATE TABLE Demand ( region TEXT, @@ -411,37 +447,7 @@ INSERT INTO Demand VALUES('R2',2030,'VMT',42.0,'',''); CREATE TABLE DemandSpecificDistribution ( region TEXT, - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - demand_name TEXT - REFERENCES Commodity (name), - dsd REAL, - dsd_notes TEXT, - PRIMARY KEY (region, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -INSERT INTO DemandSpecificDistribution VALUES('R1','spring','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R1','spring','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R1','summer','day','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R1','summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R1','fall','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R1','fall','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R1','winter','day','RH',0.2999999999999999889,''); -INSERT INTO DemandSpecificDistribution VALUES('R1','winter','night','RH',0.4000000000000000222,''); -INSERT INTO DemandSpecificDistribution VALUES('R2','spring','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R2','spring','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R2','summer','day','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R2','summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R2','fall','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R2','fall','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R2','winter','day','RH',0.2999999999999999889,''); -INSERT INTO DemandSpecificDistribution VALUES('R2','winter','night','RH',0.4000000000000000222,''); -CREATE TABLE DemandPeriodDistribution -( - region TEXT, - period INTEGER + period INTEGER REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), @@ -449,13 +455,59 @@ CREATE TABLE DemandPeriodDistribution REFERENCES TimeOfDay (tod), demand_name TEXT REFERENCES Commodity (name), - dpd REAL, - dpd_notes TEXT, + dsd REAL, + notes TEXT, PRIMARY KEY (region, period, season, tod, demand_name), - CHECK (dpd >= 0 AND dpd <= 1) + CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandPeriodDistribution VALUES('R1',2020,'fall','day','VMT',0.125,'Same as default distribution (segfrac)'); -INSERT INTO DemandPeriodDistribution VALUES('R2',2025,'winter','night','VMT',0.125,'Same as default distribution (segfrac)'); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'spring','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'summer','day','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'summer','night','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'fall','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'fall','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'winter','day','RH',0.3,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'winter','night','RH',0.4,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'spring','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'summer','day','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'summer','night','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'fall','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'fall','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'winter','day','RH',0.3,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'winter','night','RH',0.4,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'spring','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'summer','day','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'summer','night','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'fall','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'fall','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'winter','day','RH',0.3,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'winter','night','RH',0.4,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'spring','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'summer','day','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'summer','night','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'fall','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'fall','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'winter','day','RH',0.3,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'winter','night','RH',0.4,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'spring','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'summer','day','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'summer','night','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'fall','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'fall','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'winter','day','RH',0.3,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'winter','night','RH',0.4,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'spring','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'summer','day','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'summer','night','RH',0.0,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'fall','day','RH',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'fall','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'winter','day','RH',0.3,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'winter','night','RH',0.4,''); CREATE TABLE LoanRate ( region TEXT, @@ -491,34 +543,34 @@ INSERT INTO Efficiency VALUES('R1','OIL','S_OILREF',2020,'GSL',1.0,''); INSERT INTO Efficiency VALUES('R1','OIL','S_OILREF',2020,'DSL',1.0,''); INSERT INTO Efficiency VALUES('R1','ETH','T_BLND',2020,'E10',1.0,''); INSERT INTO Efficiency VALUES('R1','GSL','T_BLND',2020,'E10',1.0,''); -INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2020,'ELC',0.5500000000000000444,''); -INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2025,'ELC',0.5500000000000000444,''); -INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2030,'ELC',0.5500000000000000444,''); +INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2020,'ELC',0.55,''); +INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2025,'ELC',0.55,''); +INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2030,'ELC',0.55,''); INSERT INTO Efficiency VALUES('R1','SOL','E_SOLPV',2020,'ELC',1.0,''); INSERT INTO Efficiency VALUES('R1','SOL','E_SOLPV',2025,'ELC',1.0,''); INSERT INTO Efficiency VALUES('R1','SOL','E_SOLPV',2030,'ELC',1.0,''); -INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2015,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2020,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2025,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2030,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2020,'ELC',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2025,'ELC',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2030,'ELC',0.8499999999999999778,''); +INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2015,'ELC',0.4,''); +INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2020,'ELC',0.4,''); +INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2025,'ELC',0.4,''); +INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2030,'ELC',0.4,''); +INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2020,'ELC',0.85,''); +INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2025,'ELC',0.85,''); +INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2030,'ELC',0.85,''); INSERT INTO Efficiency VALUES('R1','E10','T_GSL',2020,'VMT',0.25,''); INSERT INTO Efficiency VALUES('R1','E10','T_GSL',2025,'VMT',0.25,''); INSERT INTO Efficiency VALUES('R1','E10','T_GSL',2030,'VMT',0.25,''); -INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2020,'VMT',0.2999999999999999889,''); -INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2025,'VMT',0.2999999999999999889,''); -INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2030,'VMT',0.2999999999999999889,''); -INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2020,'VMT',0.8900000000000000133,''); -INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2025,'VMT',0.8900000000000000133,''); -INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2030,'VMT',0.8900000000000000133,''); +INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2020,'VMT',0.3,''); +INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2025,'VMT',0.3,''); +INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2030,'VMT',0.3,''); +INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2020,'VMT',0.89000000000000003552,''); +INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2025,'VMT',0.89000000000000003552,''); +INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2030,'VMT',0.89000000000000003552,''); INSERT INTO Efficiency VALUES('R1','ELC','R_EH',2020,'RH',1.0,''); INSERT INTO Efficiency VALUES('R1','ELC','R_EH',2025,'RH',1.0,''); INSERT INTO Efficiency VALUES('R1','ELC','R_EH',2030,'RH',1.0,''); -INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2020,'RH',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2025,'RH',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2030,'RH',0.8499999999999999778,''); +INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2020,'RH',0.85,''); +INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2025,'RH',0.85,''); +INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2030,'RH',0.85,''); INSERT INTO Efficiency VALUES('R2','ethos','S_IMPETH',2020,'ETH',1.0,''); INSERT INTO Efficiency VALUES('R2','ethos','S_IMPOIL',2020,'OIL',1.0,''); INSERT INTO Efficiency VALUES('R2','ethos','S_IMPNG',2020,'NG',1.0,''); @@ -527,36 +579,58 @@ INSERT INTO Efficiency VALUES('R2','OIL','S_OILREF',2020,'GSL',1.0,''); INSERT INTO Efficiency VALUES('R2','OIL','S_OILREF',2020,'DSL',1.0,''); INSERT INTO Efficiency VALUES('R2','ETH','T_BLND',2020,'E10',1.0,''); INSERT INTO Efficiency VALUES('R2','GSL','T_BLND',2020,'E10',1.0,''); -INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2020,'ELC',0.5500000000000000444,''); -INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2025,'ELC',0.5500000000000000444,''); -INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2030,'ELC',0.5500000000000000444,''); +INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2020,'ELC',0.55,''); +INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2025,'ELC',0.55,''); +INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2030,'ELC',0.55,''); INSERT INTO Efficiency VALUES('R2','SOL','E_SOLPV',2020,'ELC',1.0,''); INSERT INTO Efficiency VALUES('R2','SOL','E_SOLPV',2025,'ELC',1.0,''); INSERT INTO Efficiency VALUES('R2','SOL','E_SOLPV',2030,'ELC',1.0,''); -INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2015,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2020,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2025,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2030,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2020,'ELC',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2025,'ELC',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2030,'ELC',0.8499999999999999778,''); +INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2015,'ELC',0.4,''); +INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2020,'ELC',0.4,''); +INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2025,'ELC',0.4,''); +INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2030,'ELC',0.4,''); +INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2020,'ELC',0.85,''); +INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2025,'ELC',0.85,''); +INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2030,'ELC',0.85,''); INSERT INTO Efficiency VALUES('R2','E10','T_GSL',2020,'VMT',0.25,''); INSERT INTO Efficiency VALUES('R2','E10','T_GSL',2025,'VMT',0.25,''); INSERT INTO Efficiency VALUES('R2','E10','T_GSL',2030,'VMT',0.25,''); -INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2020,'VMT',0.2999999999999999889,''); -INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2025,'VMT',0.2999999999999999889,''); -INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2030,'VMT',0.2999999999999999889,''); -INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2020,'VMT',0.8900000000000000133,''); -INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2025,'VMT',0.8900000000000000133,''); -INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2030,'VMT',0.8900000000000000133,''); +INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2020,'VMT',0.3,''); +INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2025,'VMT',0.3,''); +INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2030,'VMT',0.3,''); +INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2020,'VMT',0.89000000000000003552,''); +INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2025,'VMT',0.89000000000000003552,''); +INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2030,'VMT',0.89000000000000003552,''); INSERT INTO Efficiency VALUES('R2','ELC','R_EH',2020,'RH',1.0,''); INSERT INTO Efficiency VALUES('R2','ELC','R_EH',2025,'RH',1.0,''); INSERT INTO Efficiency VALUES('R2','ELC','R_EH',2030,'RH',1.0,''); -INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2020,'RH',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2025,'RH',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2030,'RH',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R1-R2','ELC','E_TRANS',2015,'ELC',0.9000000000000000222,''); -INSERT INTO Efficiency VALUES('R2-R1','ELC','E_TRANS',2015,'ELC',0.9000000000000000222,''); +INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2020,'RH',0.85,''); +INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2025,'RH',0.85,''); +INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2030,'RH',0.85,''); +INSERT INTO Efficiency VALUES('R1-R2','ELC','E_TRANS',2015,'ELC',0.9,''); +INSERT INTO Efficiency VALUES('R2-R1','ELC','E_TRANS',2015,'ELC',0.9,''); +CREATE TABLE EfficiencyVariable +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); CREATE TABLE EmissionActivity ( region TEXT, @@ -575,12 +649,26 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('R1','CO2','ethos','S_IMPNG',2020,'NG',50.29999999999999716,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R1','CO2','OIL','S_OILREF',2020,'GSL',67.20000000000000284,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R1','CO2','OIL','S_OILREF',2020,'DSL',69.40000000000000569,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R2','CO2','ethos','S_IMPNG',2020,'NG',50.29999999999999716,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R2','CO2','OIL','S_OILREF',2020,'GSL',67.20000000000000284,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R2','CO2','OIL','S_OILREF',2020,'DSL',69.40000000000000569,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO EmissionActivity VALUES('R1','CO2','ethos','S_IMPNG',2020,'NG',50.299999999999993605,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO EmissionActivity VALUES('R1','CO2','OIL','S_OILREF',2020,'GSL',67.200000000000006394,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO EmissionActivity VALUES('R1','CO2','OIL','S_OILREF',2020,'DSL',69.400000000000003907,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO EmissionActivity VALUES('R2','CO2','ethos','S_IMPNG',2020,'NG',50.299999999999993605,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO EmissionActivity VALUES('R2','CO2','OIL','S_OILREF',2020,'GSL',67.200000000000006394,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO EmissionActivity VALUES('R2','CO2','OIL','S_OILREF',2020,'DSL',69.400000000000003907,'kT/PJ','taken from MIT Energy Fact Sheet'); +CREATE TABLE EmissionEmbodied +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); CREATE TABLE ExistingCapacity ( region TEXT, @@ -593,8 +681,8 @@ CREATE TABLE ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO ExistingCapacity VALUES('R1','E_NUCLEAR',2015,0.07000000000000000667,'GW',''); -INSERT INTO ExistingCapacity VALUES('R2','E_NUCLEAR',2015,0.02999999999999999889,'GW',''); +INSERT INTO ExistingCapacity VALUES('R1','E_NUCLEAR',2015,0.070000000000000008881,'GW',''); +INSERT INTO ExistingCapacity VALUES('R2','E_NUCLEAR',2015,0.03,'GW',''); INSERT INTO ExistingCapacity VALUES('R1-R2','E_TRANS',2015,10.0,'GW',''); INSERT INTO ExistingCapacity VALUES('R2-R1','E_TRANS',2015,10.0,'GW',''); CREATE TABLE TechGroup @@ -910,7 +998,7 @@ CREATE TABLE OutputFlowOut period INTEGER REFERENCES TimePeriod (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -924,6 +1012,25 @@ CREATE TABLE OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); +CREATE TABLE OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); CREATE TABLE PlanningReserveMargin ( region TEXT @@ -956,24 +1063,42 @@ CREATE TABLE Region INSERT INTO Region VALUES('R1',NULL); INSERT INTO Region VALUES('R2',NULL); CREATE TABLE TimeSegmentFraction -( +( + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, notes TEXT, - PRIMARY KEY (season, tod), + PRIMARY KEY (period, season, tod), CHECK (segfrac >= 0 AND segfrac <= 1) ); -INSERT INTO TimeSegmentFraction VALUES('spring','day',0.125,'Spring - Day'); -INSERT INTO TimeSegmentFraction VALUES('spring','night',0.125,'Spring - Night'); -INSERT INTO TimeSegmentFraction VALUES('summer','day',0.125,'Summer - Day'); -INSERT INTO TimeSegmentFraction VALUES('summer','night',0.125,'Summer - Night'); -INSERT INTO TimeSegmentFraction VALUES('fall','day',0.125,'Fall - Day'); -INSERT INTO TimeSegmentFraction VALUES('fall','night',0.125,'Fall - Night'); -INSERT INTO TimeSegmentFraction VALUES('winter','day',0.125,'Winter - Day'); -INSERT INTO TimeSegmentFraction VALUES('winter','night',0.125,'Winter - Night'); +INSERT INTO TimeSegmentFraction VALUES(2020,'spring','day',0.125,'Spring - Day'); +INSERT INTO TimeSegmentFraction VALUES(2020,'spring','night',0.125,'Spring - Night'); +INSERT INTO TimeSegmentFraction VALUES(2020,'summer','day',0.125,'Summer - Day'); +INSERT INTO TimeSegmentFraction VALUES(2020,'summer','night',0.125,'Summer - Night'); +INSERT INTO TimeSegmentFraction VALUES(2020,'fall','day',0.125,'Fall - Day'); +INSERT INTO TimeSegmentFraction VALUES(2020,'fall','night',0.125,'Fall - Night'); +INSERT INTO TimeSegmentFraction VALUES(2020,'winter','day',0.125,'Winter - Day'); +INSERT INTO TimeSegmentFraction VALUES(2020,'winter','night',0.125,'Winter - Night'); +INSERT INTO TimeSegmentFraction VALUES(2025,'spring','day',0.125,'Spring - Day'); +INSERT INTO TimeSegmentFraction VALUES(2025,'spring','night',0.125,'Spring - Night'); +INSERT INTO TimeSegmentFraction VALUES(2025,'summer','day',0.125,'Summer - Day'); +INSERT INTO TimeSegmentFraction VALUES(2025,'summer','night',0.125,'Summer - Night'); +INSERT INTO TimeSegmentFraction VALUES(2025,'fall','day',0.125,'Fall - Day'); +INSERT INTO TimeSegmentFraction VALUES(2025,'fall','night',0.125,'Fall - Night'); +INSERT INTO TimeSegmentFraction VALUES(2025,'winter','day',0.125,'Winter - Day'); +INSERT INTO TimeSegmentFraction VALUES(2025,'winter','night',0.125,'Winter - Night'); +INSERT INTO TimeSegmentFraction VALUES(2030,'spring','day',0.125,'Spring - Day'); +INSERT INTO TimeSegmentFraction VALUES(2030,'spring','night',0.125,'Spring - Night'); +INSERT INTO TimeSegmentFraction VALUES(2030,'summer','day',0.125,'Summer - Day'); +INSERT INTO TimeSegmentFraction VALUES(2030,'summer','night',0.125,'Summer - Night'); +INSERT INTO TimeSegmentFraction VALUES(2030,'fall','day',0.125,'Fall - Day'); +INSERT INTO TimeSegmentFraction VALUES(2030,'fall','night',0.125,'Fall - Night'); +INSERT INTO TimeSegmentFraction VALUES(2030,'winter','day',0.125,'Winter - Day'); +INSERT INTO TimeSegmentFraction VALUES(2030,'winter','night',0.125,'Winter - Night'); CREATE TABLE StorageDuration ( region TEXT, @@ -984,19 +1109,25 @@ CREATE TABLE StorageDuration ); INSERT INTO StorageDuration VALUES('R1','E_BATT',8.0,'8-hour duration specified as fraction of a day'); INSERT INTO StorageDuration VALUES('R2','E_BATT',8.0,'8-hour duration specified as fraction of a day'); -CREATE TABLE StorageFraction -( - region TEXT, - period INTEGER REFERENCES TimePeriod (period), - season TEXT REFERENCES TimeSeason (season), - tod TEXT REFERENCES TimeOfDay (tod), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), - frac REAL, - notes TEXT -); -INSERT INTO StorageFraction VALUES('R1',2025,'winter','day','E_BATT',2025,0.5,''); -INSERT INTO StorageFraction VALUES('R2',2020,'summer','day','E_BATT',2020,0.5,''); +CREATE TABLE StorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage) +); +INSERT INTO StorageLevelFraction VALUES('R1',2025,'winter','day','E_BATT',2025,0.5,''); +INSERT INTO StorageLevelFraction VALUES('R2',2020,'summer','day','E_BATT',2020,0.5,''); CREATE TABLE TechnologyType ( label TEXT @@ -1070,6 +1201,71 @@ INSERT INTO MinTechOutputSplit VALUES('R2',2025,'S_OILREF','GSL',0.7199999999999 INSERT INTO MinTechOutputSplit VALUES('R2',2025,'S_OILREF','DSL',0.08000000000000000166,''); INSERT INTO MinTechOutputSplit VALUES('R2',2030,'S_OILREF','GSL',0.7199999999999999734,''); INSERT INTO MinTechOutputSplit VALUES('R2',2030,'S_OILREF','DSL',0.08000000000000000166,''); +CREATE TABLE MinTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MaxTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MaxTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -1093,14 +1289,35 @@ INSERT INTO TimePeriod VALUES(4,2030,'f'); INSERT INTO TimePeriod VALUES(5,2035,'f'); CREATE TABLE TimeSeason ( - sequence INTEGER UNIQUE, - season TEXT + season TEXT PRIMARY KEY ); -INSERT INTO TimeSeason VALUES(1,'spring'); -INSERT INTO TimeSeason VALUES(2,'summer'); -INSERT INTO TimeSeason VALUES(3,'fall'); -INSERT INTO TimeSeason VALUES(4,'winter'); +INSERT INTO TimeSeason VALUES('spring'); +INSERT INTO TimeSeason VALUES('summer'); +INSERT INTO TimeSeason VALUES('fall'); +INSERT INTO TimeSeason VALUES('winter'); +CREATE TABLE PeriodSeasons +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT + REFERENCES TimeSeason (season), + notes TEXT, + PRIMARY KEY (period, sequence) +); +INSERT INTO PeriodSeasons VALUES(2020,1,'spring',NULL); +INSERT INTO PeriodSeasons VALUES(2020,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2020,3,'fall',NULL); +INSERT INTO PeriodSeasons VALUES(2020,4,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2025,1,'spring',NULL); +INSERT INTO PeriodSeasons VALUES(2025,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2025,3,'fall',NULL); +INSERT INTO PeriodSeasons VALUES(2025,4,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2030,1,'spring',NULL); +INSERT INTO PeriodSeasons VALUES(2030,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2030,3,'fall',NULL); +INSERT INTO PeriodSeasons VALUES(2030,4,'winter',NULL); CREATE TABLE TimePeriodType ( label TEXT @@ -1261,10 +1478,36 @@ CREATE TABLE MinNewCapacityShare REFERENCES Technology (tech), group_name TEXT REFERENCES TechGroup (group_name), - max_proportion REAL, + min_proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, group_name) ); +CREATE TABLE MinNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); +CREATE TABLE MaxNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1324,6 +1567,36 @@ CREATE TABLE MaxActivityGroup notes TEXT, PRIMARY KEY (region, period, group_name) ); +CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "min_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); +CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "max_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); CREATE TABLE RPSRequirement ( region TEXT NOT NULL @@ -1356,27 +1629,26 @@ CREATE TABLE Technology curtail INTEGER NOT NULL DEFAULT 0, retire INTEGER NOT NULL DEFAULT 0, flex INTEGER NOT NULL DEFAULT 0, - variable INTEGER NOT NULL DEFAULT 0, exchange INTEGER NOT NULL DEFAULT 0, description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('S_IMPETH','r','supply','','',1,0,0,0,0,0,0,0,' imported ethanol'); -INSERT INTO Technology VALUES('S_IMPOIL','r','supply','','',1,0,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO Technology VALUES('S_IMPNG','r','supply','','',1,0,0,0,0,0,0,0,' imported natural gas'); -INSERT INTO Technology VALUES('S_IMPURN','r','supply','','',1,0,0,0,0,0,0,0,' imported uranium'); -INSERT INTO Technology VALUES('S_OILREF','p','supply','','',0,0,0,1,0,0,0,0,' crude oil refinery'); -INSERT INTO Technology VALUES('E_NGCC','p','electric','','',0,0,0,0,0,0,0,0,' natural gas combined-cycle'); -INSERT INTO Technology VALUES('E_SOLPV','p','electric','','',0,0,0,0,0,0,0,0,' solar photovoltaic'); -INSERT INTO Technology VALUES('E_BATT','ps','electric','','',0,0,0,0,0,0,0,0,' lithium-ion battery'); -INSERT INTO Technology VALUES('E_NUCLEAR','pb','electric','','',0,0,0,0,0,0,0,0,' nuclear power plant'); -INSERT INTO Technology VALUES('T_BLND','p','transport','','',0,0,0,0,0,0,0,0,'ethanol - gasoline blending process'); -INSERT INTO Technology VALUES('T_DSL','p','transport','','',0,0,0,0,0,0,0,0,'diesel vehicle'); -INSERT INTO Technology VALUES('T_GSL','p','transport','','',0,0,0,0,0,0,0,0,'gasoline vehicle'); -INSERT INTO Technology VALUES('T_EV','p','transport','','',0,0,0,0,0,0,0,0,'electric vehicle'); -INSERT INTO Technology VALUES('R_EH','p','residential','','',0,0,0,0,0,0,0,0,' electric residential heating'); -INSERT INTO Technology VALUES('R_NGH','p','residential','','',0,0,0,0,0,0,0,0,' natural gas residential heating'); -INSERT INTO Technology VALUES('E_TRANS','p','electric','','',0,0,0,0,0,0,0,1,'electric transmission'); +INSERT INTO Technology VALUES('S_IMPETH','r','supply','','',1,0,0,0,0,0,0,' imported ethanol'); +INSERT INTO Technology VALUES('S_IMPOIL','r','supply','','',1,0,0,0,0,0,0,' imported crude oil'); +INSERT INTO Technology VALUES('S_IMPNG','r','supply','','',1,0,0,0,0,0,0,' imported natural gas'); +INSERT INTO Technology VALUES('S_IMPURN','r','supply','','',1,0,0,0,0,0,0,' imported uranium'); +INSERT INTO Technology VALUES('S_OILREF','p','supply','','',0,0,0,1,0,0,0,' crude oil refinery'); +INSERT INTO Technology VALUES('E_NGCC','p','electric','','',0,0,0,0,0,0,0,' natural gas combined-cycle'); +INSERT INTO Technology VALUES('E_SOLPV','p','electric','','',0,0,0,0,0,0,0,' solar photovoltaic'); +INSERT INTO Technology VALUES('E_BATT','ps','electric','','',0,0,0,0,0,0,0,' lithium-ion battery'); +INSERT INTO Technology VALUES('E_NUCLEAR','pb','electric','','',0,0,0,0,0,0,0,' nuclear power plant'); +INSERT INTO Technology VALUES('T_BLND','p','transport','','',0,0,0,0,0,0,0,'ethanol - gasoline blending process'); +INSERT INTO Technology VALUES('T_DSL','p','transport','','',0,0,0,0,0,0,0,'diesel vehicle'); +INSERT INTO Technology VALUES('T_GSL','p','transport','','',0,0,0,0,0,0,0,'gasoline vehicle'); +INSERT INTO Technology VALUES('T_EV','p','transport','','',0,0,0,0,0,0,0,'electric vehicle'); +INSERT INTO Technology VALUES('R_EH','p','residential','','',0,0,0,0,0,0,0,' electric residential heating'); +INSERT INTO Technology VALUES('R_NGH','p','residential','','',0,0,0,0,0,0,0,' natural gas residential heating'); +INSERT INTO Technology VALUES('E_TRANS','p','electric','','',0,0,0,0,0,0,1,'electric transmission'); CREATE TABLE OutputCost ( scenario TEXT, @@ -1397,3 +1669,4 @@ CREATE TABLE OutputCost FOREIGN KEY (tech) REFERENCES Technology (tech) ); COMMIT; +PRAGMA FOREIGN_KEYS = 1; \ No newline at end of file diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 7a6aba710..01ce296c2 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -7,9 +7,9 @@ CREATE TABLE MetaData notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('myopic_base_year',1990,'Base Year for Myopic Analysis'); +INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); +INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); CREATE TABLE MetaDataReal ( @@ -73,27 +73,29 @@ CREATE TABLE CapacityFactorProcess PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2010,0.2756000000000000116,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','day','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','night','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','day','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','night','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','day','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','night','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2010,0.27560000000000002273,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2010,0.27560000000000002273,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2010,0.27560000000000002273,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2010,0.27560000000000002273,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2010,0.27560000000000002273,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2010,0.27560000000000002273,''); CREATE TABLE CapacityFactorTech ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -102,39 +104,99 @@ CREATE TABLE CapacityFactorTech REFERENCES Technology (tech), factor REAL, notes TEXT, - PRIMARY KEY (region, season, tod, tech), + PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E70',0.8,''); CREATE TABLE CapacityToActivity ( region TEXT, @@ -144,11 +206,11 @@ CREATE TABLE CapacityToActivity notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO CapacityToActivity VALUES('utopia','E01',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('utopia','E21',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('utopia','E31',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('utopia','E51',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('utopia','E70',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('utopia','E01',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('utopia','E21',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('utopia','E31',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('utopia','E51',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('utopia','E70',31.539999999999999147,''); INSERT INTO CapacityToActivity VALUES('utopia','RHE',1.0,''); INSERT INTO CapacityToActivity VALUES('utopia','RHO',1.0,''); INSERT INTO CapacityToActivity VALUES('utopia','RL1',1.0,''); @@ -184,6 +246,7 @@ CREATE TABLE CommodityType PRIMARY KEY, description TEXT ); +INSERT INTO CommodityType VALUES('a','annual commodity'); INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); @@ -272,10 +335,10 @@ INSERT INTO CostFixed VALUES('utopia',2000,'RHO',2000,1.0,'',''); INSERT INTO CostFixed VALUES('utopia',2010,'RHO',1990,1.0,'',''); INSERT INTO CostFixed VALUES('utopia',2010,'RHO',2000,1.0,'',''); INSERT INTO CostFixed VALUES('utopia',2010,'RHO',2010,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1980,9.46000000000000086,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1990,9.46000000000000086,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'RL1',2000,9.46000000000000086,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'RL1',2010,9.46000000000000086,'',''); +INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1980,9.4600000000000008526,'',''); +INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1990,9.4600000000000008526,'',''); +INSERT INTO CostFixed VALUES('utopia',2000,'RL1',2000,9.4600000000000008526,'',''); +INSERT INTO CostFixed VALUES('utopia',2010,'RL1',2010,9.4600000000000008526,'',''); INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1970,52.0,'',''); INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1980,52.0,'',''); INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1990,52.0,'',''); @@ -371,36 +434,36 @@ INSERT INTO CostVariable VALUES('utopia',2010,'IMPOIL1',1990,8.0,'',''); INSERT INTO CostVariable VALUES('utopia',1990,'IMPURN1',1990,2.0,'',''); INSERT INTO CostVariable VALUES('utopia',2000,'IMPURN1',1990,2.0,'',''); INSERT INTO CostVariable VALUES('utopia',2010,'IMPURN1',1990,2.0,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1960,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1970,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1980,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1990,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1970,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1980,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1990,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',2000,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',1980,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',1990,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',2000,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',2010,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1960,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1970,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1980,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1990,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',1970,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',1980,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',1990,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',2000,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',1980,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',1990,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',2000,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',2010,0.3,'',''); INSERT INTO CostVariable VALUES('utopia',1990,'E21',1990,1.5,'',''); INSERT INTO CostVariable VALUES('utopia',2000,'E21',1990,1.5,'',''); INSERT INTO CostVariable VALUES('utopia',2010,'E21',1990,1.5,'',''); INSERT INTO CostVariable VALUES('utopia',2000,'E21',2000,1.5,'',''); INSERT INTO CostVariable VALUES('utopia',2010,'E21',2000,1.5,'',''); INSERT INTO CostVariable VALUES('utopia',2010,'E21',2010,1.5,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1960,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1970,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1980,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1990,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1970,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1980,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1990,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',2000,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',1980,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',1990,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',2000,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',2010,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1960,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1970,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1980,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1990,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',1970,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',1980,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',1990,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',2000,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',1980,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',1990,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',2000,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',2010,0.4,'',''); INSERT INTO CostVariable VALUES('utopia',1990,'SRE',1990,10.0,'',''); INSERT INTO CostVariable VALUES('utopia',2000,'SRE',1990,10.0,'',''); INSERT INTO CostVariable VALUES('utopia',2000,'SRE',2000,10.0,'',''); @@ -419,18 +482,20 @@ CREATE TABLE Demand notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO Demand VALUES('utopia',1990,'RH',25.19999999999999929,'',''); -INSERT INTO Demand VALUES('utopia',2000,'RH',37.79999999999999715,'',''); -INSERT INTO Demand VALUES('utopia',2010,'RH',56.70000000000000284,'',''); -INSERT INTO Demand VALUES('utopia',1990,'RL',5.599999999999999645,'',''); -INSERT INTO Demand VALUES('utopia',2000,'RL',8.400000000000000355,'',''); -INSERT INTO Demand VALUES('utopia',2010,'RL',12.59999999999999965,'',''); -INSERT INTO Demand VALUES('utopia',1990,'TX',5.200000000000000177,'',''); -INSERT INTO Demand VALUES('utopia',2000,'TX',7.799999999999999823,'',''); -INSERT INTO Demand VALUES('utopia',2010,'TX',11.68999999999999951,'',''); +INSERT INTO Demand VALUES('utopia',1990,'RH',25.200000000000000177,'',''); +INSERT INTO Demand VALUES('utopia',2000,'RH',37.799999999999998046,'',''); +INSERT INTO Demand VALUES('utopia',2010,'RH',56.699999999999999289,'',''); +INSERT INTO Demand VALUES('utopia',1990,'RL',5.5999999999999996447,'',''); +INSERT INTO Demand VALUES('utopia',2000,'RL',8.4000000000000003552,'',''); +INSERT INTO Demand VALUES('utopia',2010,'RL',12.600000000000000088,'',''); +INSERT INTO Demand VALUES('utopia',1990,'TX',5.2000000000000001776,'',''); +INSERT INTO Demand VALUES('utopia',2000,'TX',7.7999999999999998223,'',''); +INSERT INTO Demand VALUES('utopia',2010,'TX',11.69000000000000039,'',''); CREATE TABLE DemandSpecificDistribution ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -438,20 +503,40 @@ CREATE TABLE DemandSpecificDistribution demand_name TEXT REFERENCES Commodity (name), dsd REAL, - dsd_notes TEXT, - PRIMARY KEY (region, season, tod, demand_name), + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('utopia','inter','day','RH',0.1199999999999999956,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','inter','night','RH',0.05999999999999999778,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','winter','day','RH',0.5466999999999999638,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','winter','night','RH',0.2732999999999999874,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','inter','day','RL',0.1499999999999999945,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','inter','night','RL',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','summer','day','RL',0.1499999999999999945,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','summer','night','RL',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','winter','day','RL',0.5,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','winter','night','RL',0.1000000000000000055,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RH',0.11999999999999999644,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RH',0.06,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','day','RH',0.54669999999999996376,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RH',0.27329999999999996518,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RL',0.15,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','day','RL',0.15,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','day','RL',0.5,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RL',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RH',0.11999999999999999644,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RH',0.06,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','day','RH',0.54669999999999996376,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RH',0.27329999999999996518,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RL',0.15,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','day','RL',0.15,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','day','RL',0.5,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RL',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RH',0.11999999999999999644,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RH',0.06,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RH',0.54669999999999996376,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RH',0.27329999999999996518,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RL',0.15,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','day','RL',0.15,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RL',0.5,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RL',0.1,''); CREATE TABLE LoanRate ( region TEXT, @@ -486,40 +571,40 @@ INSERT INTO Efficiency VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,''); INSERT INTO Efficiency VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,''); INSERT INTO Efficiency VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,''); INSERT INTO Efficiency VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,''); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1960,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1970,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1980,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1990,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',2000,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',2010,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',1990,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2000,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2010,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','URN','E21',1990,'ELC',0.4000000000000000222,'# 1/2.5'); -INSERT INTO Efficiency VALUES('utopia','URN','E21',2000,'ELC',0.4000000000000000222,'# 1/2.5'); -INSERT INTO Efficiency VALUES('utopia','URN','E21',2010,'ELC',0.4000000000000000222,'# 1/2.5'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',1980,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',1990,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',2000,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',2010,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1960,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1970,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1980,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1990,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',2000,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',2010,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',1980,'ELC',0.7199999999999999734,'# 1/1.3889'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',1990,'ELC',0.7199999999999999734,'# 1/1.3889'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',2000,'ELC',0.7199999999999999734,'# 1/1.3889'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',2010,'ELC',0.7199999999999999734,'# 1/1.3889'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1960,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1970,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1980,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1990,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',2000,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',2010,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','FEQ','E21',1990,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2000,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2010,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','URN','E21',1990,'ELC',0.4,'# 1/2.5'); +INSERT INTO Efficiency VALUES('utopia','URN','E21',2000,'ELC',0.4,'# 1/2.5'); +INSERT INTO Efficiency VALUES('utopia','URN','E21',2010,'ELC',0.4,'# 1/2.5'); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',1980,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',1990,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',2000,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',2010,'ELC',0.32000000000000001776,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1960,'ELC',0.29399999999999998578,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1970,'ELC',0.29399999999999998578,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1980,'ELC',0.29399999999999998578,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1990,'ELC',0.29399999999999998578,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',2000,'ELC',0.29399999999999998578,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',2010,'ELC',0.29399999999999998578,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',1980,'ELC',0.71999999999999992894,'# 1/1.3889'); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',1990,'ELC',0.71999999999999992894,'# 1/1.3889'); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',2000,'ELC',0.71999999999999992894,'# 1/1.3889'); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',2010,'ELC',0.71999999999999992894,'# 1/1.3889'); INSERT INTO Efficiency VALUES('utopia','ELC','RHE',1990,'RH',1.0,'# direct translation from DMD_EFF'); INSERT INTO Efficiency VALUES('utopia','ELC','RHE',2000,'RH',1.0,'# direct translation from DMD_EFF'); INSERT INTO Efficiency VALUES('utopia','ELC','RHE',2010,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1970,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1980,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1990,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2000,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2010,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1970,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1980,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1990,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2000,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2010,'RH',0.7,'# direct translation from DMD_EFF'); INSERT INTO Efficiency VALUES('utopia','ELC','RL1',1980,'RL',1.0,'# direct translation from DMD_EFF'); INSERT INTO Efficiency VALUES('utopia','ELC','RL1',1990,'RL',1.0,'# direct translation from DMD_EFF'); INSERT INTO Efficiency VALUES('utopia','ELC','RL1',2000,'RL',1.0,'# direct translation from DMD_EFF'); @@ -530,19 +615,41 @@ INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'# direct tran INSERT INTO Efficiency VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',1990,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2000,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2010,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1970,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1980,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1990,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2000,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2010,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','ELC','TXE',1990,'TX',0.82699999999999995736,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2000,'TX',0.82699999999999995736,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2010,'TX',0.82699999999999995736,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1970,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1980,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1990,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2000,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2010,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); +CREATE TABLE EfficiencyVariable +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); CREATE TABLE EmissionActivity ( region TEXT, @@ -561,10 +668,10 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.07499999999999999723,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.07499999999999999723,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',0.08899999999999999579,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.07499999999999999723,'',''); +INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.075,'',''); +INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.075,'',''); +INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',0.088999999999999985789,'',''); +INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.075,'',''); INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1970,'TX',1.0,'',''); INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1980,'TX',1.0,'',''); INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1990,'TX',1.0,'',''); @@ -575,6 +682,20 @@ INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',1980,'TX',1.0,'', INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',1990,'TX',1.0,'',''); INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',2000,'TX',1.0,'',''); INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',2010,'TX',1.0,'',''); +CREATE TABLE EmissionEmbodied +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); CREATE TABLE ExistingCapacity ( region TEXT, @@ -587,20 +708,20 @@ CREATE TABLE ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1960,0.1749999999999999889,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1970,0.1749999999999999889,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1980,0.1499999999999999945,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E31',1980,0.1000000000000000055,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E01',1960,0.175,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E01',1970,0.175,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E01',1980,0.15,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E31',1980,0.1,'',''); INSERT INTO ExistingCapacity VALUES('utopia','E51',1980,0.5,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1960,0.05000000000000000277,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1970,0.05000000000000000277,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1980,0.2000000000000000111,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E70',1960,0.05,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E70',1970,0.05,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E70',1980,0.2,'',''); INSERT INTO ExistingCapacity VALUES('utopia','RHO',1970,12.5,'',''); INSERT INTO ExistingCapacity VALUES('utopia','RHO',1980,12.5,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','RL1',1980,5.599999999999999645,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXD',1970,0.4000000000000000222,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXD',1980,0.2000000000000000111,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXG',1970,3.100000000000000088,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','RL1',1980,5.5999999999999996447,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','TXD',1970,0.4,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','TXD',1980,0.2,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','TXG',1970,3.1000000000000000888,'',''); INSERT INTO ExistingCapacity VALUES('utopia','TXG',1980,1.5,'',''); CREATE TABLE TechGroup ( @@ -728,13 +849,13 @@ CREATE TABLE MaxCapacity notes TEXT, PRIMARY KEY (region, period, tech) ); -INSERT INTO MaxCapacity VALUES('utopia',1990,'E31',0.1300000000000000044,'',''); -INSERT INTO MaxCapacity VALUES('utopia',2000,'E31',0.1700000000000000122,'',''); -INSERT INTO MaxCapacity VALUES('utopia',2010,'E31',0.2099999999999999923,'',''); +INSERT INTO MaxCapacity VALUES('utopia',1990,'E31',0.13000000000000000444,'',''); +INSERT INTO MaxCapacity VALUES('utopia',2000,'E31',0.17000000000000001776,'',''); +INSERT INTO MaxCapacity VALUES('utopia',2010,'E31',0.21000000000000000888,'',''); INSERT INTO MaxCapacity VALUES('utopia',1990,'RHE',0.0,'',''); -INSERT INTO MaxCapacity VALUES('utopia',1990,'TXD',0.5999999999999999778,'',''); -INSERT INTO MaxCapacity VALUES('utopia',2000,'TXD',1.760000000000000008,'',''); -INSERT INTO MaxCapacity VALUES('utopia',2010,'TXD',4.759999999999999787,'',''); +INSERT INTO MaxCapacity VALUES('utopia',1990,'TXD',0.6,'',''); +INSERT INTO MaxCapacity VALUES('utopia',2000,'TXD',1.7599999999999999644,'',''); +INSERT INTO MaxCapacity VALUES('utopia',2010,'TXD',4.7599999999999997868,'',''); CREATE TABLE MaxResource ( region TEXT, @@ -781,10 +902,10 @@ CREATE TABLE MinCapacity notes TEXT, PRIMARY KEY (region, period, tech) ); -INSERT INTO MinCapacity VALUES('utopia',1990,'E31',0.1300000000000000044,'',''); -INSERT INTO MinCapacity VALUES('utopia',2000,'E31',0.1300000000000000044,'',''); -INSERT INTO MinCapacity VALUES('utopia',2010,'E31',0.1300000000000000044,'',''); -INSERT INTO MinCapacity VALUES('utopia',1990,'SRE',0.1000000000000000055,'',''); +INSERT INTO MinCapacity VALUES('utopia',1990,'E31',0.13000000000000000444,'',''); +INSERT INTO MinCapacity VALUES('utopia',2000,'E31',0.13000000000000000444,'',''); +INSERT INTO MinCapacity VALUES('utopia',2010,'E31',0.13000000000000000444,'',''); +INSERT INTO MinCapacity VALUES('utopia',1990,'SRE',0.1,'',''); CREATE TABLE MinCapacityGroup ( region TEXT, @@ -894,7 +1015,7 @@ CREATE TABLE OutputFlowOut period INTEGER REFERENCES TimePeriod (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -910,22 +1031,22 @@ CREATE TABLE OutputFlowOut ); CREATE TABLE OutputStorageLevel ( - scenario TEXT, - region TEXT, - sector TEXT + scenario TEXT, + region TEXT, + sector TEXT REFERENCES SectorLabel (sector), - period INTEGER + period INTEGER REFERENCES TimePeriod (period), - season TEXT + season TEXT REFERENCES TimePeriod (period), - tod TEXT + tod TEXT REFERENCES TimeOfDay (tod), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES TimePeriod (period), - level REAL, - PRIMARY KEY (region, scenario, period, season, tod, tech, vintage) + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); CREATE TABLE PlanningReserveMargin ( @@ -958,22 +1079,36 @@ CREATE TABLE Region ); INSERT INTO Region VALUES('utopia',NULL); CREATE TABLE TimeSegmentFraction -( +( + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, notes TEXT, - PRIMARY KEY (season, tod), + PRIMARY KEY (period, season, tod), CHECK (segfrac >= 0 AND segfrac <= 1) ); -INSERT INTO TimeSegmentFraction VALUES('inter','day',0.166699999999999987,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES('inter','night',0.08329999999999999905,'# I-N'); -INSERT INTO TimeSegmentFraction VALUES('summer','day',0.166699999999999987,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES('summer','night',0.08329999999999999905,'# S-N'); -INSERT INTO TimeSegmentFraction VALUES('winter','day',0.3332999999999999852,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES('winter','night',0.166699999999999987,'# W-N'); +INSERT INTO TimeSegmentFraction VALUES(1990,'inter','day',0.16669999999999998152,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(1990,'inter','night',0.08330000000000000071,'# I-N'); +INSERT INTO TimeSegmentFraction VALUES(1990,'summer','day',0.16669999999999998152,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(1990,'summer','night',0.08330000000000000071,'# S-N'); +INSERT INTO TimeSegmentFraction VALUES(1990,'winter','day',0.33329999999999997406,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(1990,'winter','night',0.16669999999999998152,'# W-N'); +INSERT INTO TimeSegmentFraction VALUES(2000,'inter','day',0.16669999999999998152,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'inter','night',0.08330000000000000071,'# I-N'); +INSERT INTO TimeSegmentFraction VALUES(2000,'summer','day',0.16669999999999998152,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'summer','night',0.08330000000000000071,'# S-N'); +INSERT INTO TimeSegmentFraction VALUES(2000,'winter','day',0.33329999999999997406,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'winter','night',0.16669999999999998152,'# W-N'); +INSERT INTO TimeSegmentFraction VALUES(2010,'inter','day',0.16669999999999998152,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'inter','night',0.08330000000000000071,'# I-N'); +INSERT INTO TimeSegmentFraction VALUES(2010,'summer','day',0.16669999999999998152,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'summer','night',0.08330000000000000071,'# S-N'); +INSERT INTO TimeSegmentFraction VALUES(2010,'winter','day',0.33329999999999997406,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'winter','night',0.16669999999999998152,'# W-N'); CREATE TABLE StorageDuration ( region TEXT, @@ -982,12 +1117,22 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE StorageInit +CREATE TABLE StorageLevelFraction ( - tech TEXT - PRIMARY KEY, - value REAL, - notes TEXT + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage) ); CREATE TABLE TechnologyType ( @@ -1038,12 +1183,12 @@ CREATE TABLE MinTechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm) ); -INSERT INTO MinTechOutputSplit VALUES('utopia',1990,'SRE','DSL',0.6999999999999999556,''); -INSERT INTO MinTechOutputSplit VALUES('utopia',2000,'SRE','DSL',0.6999999999999999556,''); -INSERT INTO MinTechOutputSplit VALUES('utopia',2010,'SRE','DSL',0.6999999999999999556,''); -INSERT INTO MinTechOutputSplit VALUES('utopia',1990,'SRE','GSL',0.2999999999999999889,''); -INSERT INTO MinTechOutputSplit VALUES('utopia',2000,'SRE','GSL',0.2999999999999999889,''); -INSERT INTO MinTechOutputSplit VALUES('utopia',2010,'SRE','GSL',0.2999999999999999889,''); +INSERT INTO MinTechOutputSplit VALUES('utopia',1990,'SRE','DSL',0.7,''); +INSERT INTO MinTechOutputSplit VALUES('utopia',2000,'SRE','DSL',0.7,''); +INSERT INTO MinTechOutputSplit VALUES('utopia',2010,'SRE','DSL',0.7,''); +INSERT INTO MinTechOutputSplit VALUES('utopia',1990,'SRE','GSL',0.3,''); +INSERT INTO MinTechOutputSplit VALUES('utopia',2000,'SRE','GSL',0.3,''); +INSERT INTO MinTechOutputSplit VALUES('utopia',2010,'SRE','GSL',0.3,''); CREATE TABLE MinTechOutputSplitAnnual ( region TEXT, @@ -1057,6 +1202,58 @@ CREATE TABLE MinTechOutputSplitAnnual notes TEXT, PRIMARY KEY (region, period, tech, output_comm) ); +CREATE TABLE MaxTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MaxTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -1082,13 +1279,31 @@ INSERT INTO TimePeriod VALUES(6,2010,'f'); INSERT INTO TimePeriod VALUES(7,2020,'f'); CREATE TABLE TimeSeason ( - sequence INTEGER UNIQUE, - season TEXT + season TEXT PRIMARY KEY ); -INSERT INTO TimeSeason VALUES(1,'inter'); -INSERT INTO TimeSeason VALUES(2,'summer'); -INSERT INTO TimeSeason VALUES(3,'winter'); +INSERT INTO TimeSeason VALUES('inter'); +INSERT INTO TimeSeason VALUES('summer'); +INSERT INTO TimeSeason VALUES('winter'); +CREATE TABLE PeriodSeasons +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT + REFERENCES TimeSeason (season), + notes TEXT, + PRIMARY KEY (period, sequence) +); +INSERT INTO PeriodSeasons VALUES(1990,1,'inter',NULL); +INSERT INTO PeriodSeasons VALUES(1990,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(1990,3,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2000,1,'inter',NULL); +INSERT INTO PeriodSeasons VALUES(2000,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2000,3,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2010,1,'inter',NULL); +INSERT INTO PeriodSeasons VALUES(2010,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2010,3,'winter',NULL); CREATE TABLE TimePeriodType ( label TEXT @@ -1249,10 +1464,36 @@ CREATE TABLE MinNewCapacityShare REFERENCES Technology (tech), group_name TEXT REFERENCES TechGroup (group_name), - max_proportion REAL, + min_proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, group_name) ); +CREATE TABLE MinNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); +CREATE TABLE MaxNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1306,6 +1547,36 @@ CREATE TABLE MaxActivityGroup notes TEXT, PRIMARY KEY (region, period, group_name) ); +CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "min_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); +CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "max_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); CREATE TABLE RPSRequirement ( region TEXT NOT NULL @@ -1381,3 +1652,4 @@ CREATE TABLE OutputCost FOREIGN KEY (tech) REFERENCES Technology (tech) ); COMMIT; +PRAGMA FOREIGN_KEYS = 1; \ No newline at end of file From 469ee9dcd22b1cdd52ac954fe5a1f5126bb4df37 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Sat, 15 Mar 2025 12:42:03 -0400 Subject: [PATCH 050/587] Fix CapacityFactorTech and finish updating databases chasing myopic discrepancy --- data_files/example_dbs/morris_utopia.sql | 929 ++++++++++++------ data_files/example_dbs/stepped_demand.sql | 798 +++++++-------- data_files/my_configs/monte_carlo_utopia.toml | 2 +- temoa/extensions/myopic/myopic_sequencer.py | 9 + temoa/temoa_model/hybrid_loader.py | 9 +- temoa/temoa_model/temoa_initialize.py | 8 +- temoa/temoa_model/temoa_model.py | 14 +- temoa/temoa_model/temoa_rules.py | 2 +- 8 files changed, 1051 insertions(+), 720 deletions(-) diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index be83fff42..e016e9038 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -9,7 +9,8 @@ CREATE TABLE MetaData ); INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); +INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); CREATE TABLE MetaDataReal ( element TEXT, @@ -58,6 +59,8 @@ CREATE TABLE CapacityCredit CREATE TABLE CapacityFactorProcess ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -67,24 +70,32 @@ CREATE TABLE CapacityFactorProcess vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, season, tod, tech, vintage), + PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorProcess VALUES('utopia','inter','day','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','inter','night','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','winter','day','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','winter','night','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','summer','day','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','summer','night','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','inter','day','E31',2010,0.27560000000000002273,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','inter','night','E31',2010,0.27560000000000002273,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','winter','day','E31',2010,0.27560000000000002273,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','winter','night','E31',2010,0.27560000000000002273,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','summer','day','E31',2010,0.27560000000000002273,''); -INSERT INTO CapacityFactorProcess VALUES('utopia','summer','night','E31',2010,0.27560000000000002273,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','day','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','night','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','day','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','night','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','day','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','night','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2000,0.27530000000000001136,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2010,0.27560000000000002273,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2010,0.27560000000000002273,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2010,0.27560000000000002273,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2010,0.27560000000000002273,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2010,0.27560000000000002273,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2010,0.27560000000000002273,''); CREATE TABLE CapacityFactorTech ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -93,39 +104,99 @@ CREATE TABLE CapacityFactorTech REFERENCES Technology (tech), factor REAL, notes TEXT, - PRIMARY KEY (region, season, tod, tech), + PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia','inter','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia','winter','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia','summer','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E01',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E21',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E31',0.275,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E51',0.17000000000000001776,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E70',0.8,''); CREATE TABLE CapacityToActivity ( region TEXT, @@ -175,6 +246,7 @@ CREATE TABLE CommodityType PRIMARY KEY, description TEXT ); +INSERT INTO CommodityType VALUES('a','annual commodity'); INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); @@ -290,6 +362,118 @@ INSERT INTO CostFixed VALUES('utopia',2000,'TXG',1990,48.0,'',''); INSERT INTO CostFixed VALUES('utopia',2000,'TXG',2000,48.0,'',''); INSERT INTO CostFixed VALUES('utopia',2010,'TXG',2000,48.0,'',''); INSERT INTO CostFixed VALUES('utopia',2010,'TXG',2010,48.0,'',''); +CREATE TABLE IF NOT EXISTS "CostInvest" +( + region TEXT, + tech TEXT + references Technology, + vintage INTEGER + references TimePeriod, + cost REAL, + units TEXT, + notes TEXT, + MMAnalysis TEXT, + primary key (region, tech, vintage) +); +INSERT INTO CostInvest VALUES('utopia','E01',1990,2000.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','E01',2000,1300.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','E01',2010,1200.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','E21',1990,5000.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','E21',2000,5000.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','E21',2010,5000.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','E31',1990,3000.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','E31',2000,3000.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','E31',2010,3000.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','E51',1990,900.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','E51',2000,900.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','E51',2010,900.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','E70',1990,1000.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','E70',2000,1000.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','E70',2010,1000.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','RHE',1990,90.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','RHE',2000,90.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','RHE',2010,90.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','RHO',1990,100.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','RHO',2000,100.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','RHO',2010,100.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','SRE',1990,100.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','SRE',2000,100.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','SRE',2010,100.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','TXD',1990,1044.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','TXD',2000,1044.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','TXD',2010,1044.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','TXE',1990,2000.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','TXE',2000,1750.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','TXE',2010,1500.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','TXG',1990,1044.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','TXG',2000,1044.0,'','',NULL); +INSERT INTO CostInvest VALUES('utopia','TXG',2010,1044.0,'','',NULL); +CREATE TABLE IF NOT EXISTS "CostVariable" +( + region TEXT not null, + period INTEGER not null + references TimePeriod, + tech TEXT not null + references Technology, + vintage INTEGER not null + references TimePeriod, + cost REAL, + units TEXT, + notes TEXT, + MMAnalysis TEXT, + primary key (region, period, tech, vintage) +); +INSERT INTO CostVariable VALUES('utopia',1990,'IMPDSL1',1990,10.0,'','','OIL_COST'); +INSERT INTO CostVariable VALUES('utopia',2000,'IMPDSL1',1990,10.0,'','','OIL_COST'); +INSERT INTO CostVariable VALUES('utopia',2010,'IMPDSL1',1990,10.0,'','','OIL_COST'); +INSERT INTO CostVariable VALUES('utopia',1990,'IMPGSL1',1990,15.0,'','','OIL_COST'); +INSERT INTO CostVariable VALUES('utopia',2000,'IMPGSL1',1990,15.0,'','','OIL_COST'); +INSERT INTO CostVariable VALUES('utopia',2010,'IMPGSL1',1990,15.0,'','','OIL_COST'); +INSERT INTO CostVariable VALUES('utopia',1990,'IMPHCO1',1990,2.0,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2000,'IMPHCO1',1990,2.0,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'IMPHCO1',1990,2.0,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',1990,'IMPOIL1',1990,8.0,'','','OIL_COST'); +INSERT INTO CostVariable VALUES('utopia',2000,'IMPOIL1',1990,8.0,'','','OIL_COST'); +INSERT INTO CostVariable VALUES('utopia',2010,'IMPOIL1',1990,8.0,'','','OIL_COST'); +INSERT INTO CostVariable VALUES('utopia',1990,'IMPURN1',1990,2.0,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2000,'IMPURN1',1990,2.0,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'IMPURN1',1990,2.0,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1960,0.3,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1970,0.3,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1980,0.3,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1990,0.3,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',1970,0.3,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',1980,0.3,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',1990,0.3,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',2000,0.3,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',1980,0.3,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',1990,0.3,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',2000,0.3,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',2010,0.3,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',1990,'E21',1990,1.5,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2000,'E21',1990,1.5,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'E21',1990,1.5,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2000,'E21',2000,1.5,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'E21',2000,1.5,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'E21',2010,1.5,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1960,0.4,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1970,0.4,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1980,0.4,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1990,0.4,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',1970,0.4,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',1980,0.4,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',1990,0.4,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',2000,0.4,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',1980,0.4,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',1990,0.4,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',2000,0.4,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',2010,0.4,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',1990,'SRE',1990,10.0,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2000,'SRE',1990,10.0,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2000,'SRE',2000,10.0,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'SRE',1990,10.0,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'SRE',2000,10.0,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'SRE',2010,10.0,'','',NULL); CREATE TABLE Demand ( region TEXT, @@ -314,6 +498,8 @@ INSERT INTO Demand VALUES('utopia',2010,'TX',11.69000000000000039,'',''); CREATE TABLE DemandSpecificDistribution ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -321,20 +507,40 @@ CREATE TABLE DemandSpecificDistribution demand_name TEXT REFERENCES Commodity (name), dsd REAL, - dsd_notes TEXT, - PRIMARY KEY (region, season, tod, demand_name), + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('utopia','inter','night','RH',0.06,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','winter','day','RH',0.54669999999999996376,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','winter','night','RH',0.27329999999999996518,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','inter','day','RL',0.15,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','inter','night','RL',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','summer','day','RL',0.15,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','summer','night','RL',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','winter','day','RL',0.5,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','winter','night','RL',0.1,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia','inter','day','RH',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RH',0.06,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','day','RH',0.54669999999999996376,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RH',0.27329999999999992077,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RL',0.15,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','day','RL',0.15,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','day','RL',0.5,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RL',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RH',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RH',0.06,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','day','RH',0.54669999999999996376,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RH',0.27329999999999992077,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RL',0.15,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','day','RL',0.15,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','day','RL',0.5,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RL',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RH',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RH',0.06,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RH',0.54669999999999996376,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RH',0.27329999999999992077,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RL',0.15,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','day','RL',0.15,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RL',0.5,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RL',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RH',0.11999999999999999644,NULL); CREATE TABLE LoanRate ( region TEXT, @@ -346,6 +552,109 @@ CREATE TABLE LoanRate notes TEXT, PRIMARY KEY (region, tech, vintage) ); +CREATE TABLE IF NOT EXISTS "Efficiency" +( + region TEXT, + input_comm TEXT + references Commodity, + tech TEXT + references Technology, + vintage INTEGER + references TimePeriod, + output_comm TEXT + references Commodity, + efficiency REAL, + notes TEXT, + MMAnalysis TEXT, + primary key (region, input_comm, tech, vintage, output_comm), + check (efficiency > 0) +); +INSERT INTO Efficiency VALUES('utopia','ethos','IMPDSL1',1990,'DSL',1.0,'',NULL); +INSERT INTO Efficiency VALUES('utopia','ethos','IMPGSL1',1990,'GSL',1.0,'',NULL); +INSERT INTO Efficiency VALUES('utopia','ethos','IMPHCO1',1990,'HCO',1.0,'',NULL); +INSERT INTO Efficiency VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,'',NULL); +INSERT INTO Efficiency VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,'',NULL); +INSERT INTO Efficiency VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,'',NULL); +INSERT INTO Efficiency VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,'',NULL); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1960,'ELC',0.32000000000000001776,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1970,'ELC',0.32000000000000001776,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1980,'ELC',0.32000000000000001776,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1990,'ELC',0.32000000000000001776,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',2000,'ELC',0.32000000000000001776,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',2010,'ELC',0.32000000000000001776,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','FEQ','E21',1990,'ELC',0.32000000000000001776,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2000,'ELC',0.32000000000000001776,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2010,'ELC',0.32000000000000001776,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','URN','E21',1990,'ELC',0.4,'# 1/2.5',NULL); +INSERT INTO Efficiency VALUES('utopia','URN','E21',2000,'ELC',0.4,'# 1/2.5',NULL); +INSERT INTO Efficiency VALUES('utopia','URN','E21',2010,'ELC',0.4,'# 1/2.5',NULL); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',1980,'ELC',0.32000000000000001776,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',1990,'ELC',0.32000000000000001776,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',2000,'ELC',0.32000000000000001776,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',2010,'ELC',0.32000000000000001776,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1960,'ELC',0.29399999999999998578,'# 1/3.4',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1970,'ELC',0.29399999999999998578,'# 1/3.4',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1980,'ELC',0.29399999999999998578,'# 1/3.4',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1990,'ELC',0.29399999999999998578,'# 1/3.4',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',2000,'ELC',0.29399999999999998578,'# 1/3.4',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',2010,'ELC',0.29399999999999998578,'# 1/3.4',NULL); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',1980,'ELC',0.71999999999999992894,'# 1/1.3889',NULL); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',1990,'ELC',0.71999999999999992894,'# 1/1.3889',NULL); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',2000,'ELC',0.71999999999999992894,'# 1/1.3889',NULL); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',2010,'ELC',0.71999999999999992894,'# 1/1.3889',NULL); +INSERT INTO Efficiency VALUES('utopia','ELC','RHE',1990,'RH',1.0,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','ELC','RHE',2000,'RH',1.0,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','ELC','RHE',2010,'RH',1.0,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1970,'RH',0.7,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1980,'RH',0.7,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1990,'RH',0.7,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2000,'RH',0.7,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2010,'RH',0.7,'# direct translation from DMD_EFF','Res_heating_2010_eff'); +INSERT INTO Efficiency VALUES('utopia','ELC','RL1',1980,'RL',1.0,'# direct translation from DMD_EFF','Res_lighting_eff'); +INSERT INTO Efficiency VALUES('utopia','ELC','RL1',1990,'RL',1.0,'# direct translation from DMD_EFF','Res_lighting_eff'); +INSERT INTO Efficiency VALUES('utopia','ELC','RL1',2000,'RL',1.0,'# direct translation from DMD_EFF','Res_lighting_eff'); +INSERT INTO Efficiency VALUES('utopia','ELC','RL1',2010,'RL',1.0,'# direct translation from DMD_EFF','Res_lighting_eff'); +INSERT INTO Efficiency VALUES('utopia','OIL','SRE',1990,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); +INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2000,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); +INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); +INSERT INTO Efficiency VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); +INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); +INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1970,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1980,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1990,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2000,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2010,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','ELC','TXE',1990,'TX',0.82699999999999995736,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2000,'TX',0.82699999999999995736,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2010,'TX',0.82699999999999995736,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1970,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1980,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1990,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2000,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2010,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); +CREATE TABLE EfficiencyVariable +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); CREATE TABLE EmissionActivity ( region TEXT, @@ -378,6 +687,20 @@ INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',1980,'TX',1.0,'', INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',1990,'TX',1.0,'',''); INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',2000,'TX',1.0,'',''); INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',2010,'TX',1.0,'',''); +CREATE TABLE EmissionEmbodied +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); CREATE TABLE ExistingCapacity ( region TEXT, @@ -697,7 +1020,7 @@ CREATE TABLE OutputFlowOut period INTEGER REFERENCES TimePeriod (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -711,6 +1034,25 @@ CREATE TABLE OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); +CREATE TABLE OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); CREATE TABLE PlanningReserveMargin ( region TEXT @@ -742,22 +1084,36 @@ CREATE TABLE Region ); INSERT INTO Region VALUES('utopia',NULL); CREATE TABLE TimeSegmentFraction -( +( + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, notes TEXT, - PRIMARY KEY (season, tod), + PRIMARY KEY (period, season, tod), CHECK (segfrac >= 0 AND segfrac <= 1) ); -INSERT INTO TimeSegmentFraction VALUES('inter','day',0.16669999999999998152,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES('inter','night',0.08330000000000000071,'# I-N'); -INSERT INTO TimeSegmentFraction VALUES('summer','day',0.16669999999999998152,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES('summer','night',0.08330000000000000071,'# S-N'); -INSERT INTO TimeSegmentFraction VALUES('winter','day',0.33329999999999997406,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES('winter','night',0.16669999999999998152,'# W-N'); +INSERT INTO TimeSegmentFraction VALUES(1990,'inter','day',0.16669999999999998152,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(1990,'inter','night',0.08330000000000000071,'# I-N'); +INSERT INTO TimeSegmentFraction VALUES(1990,'summer','day',0.16669999999999998152,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(1990,'summer','night',0.08330000000000000071,'# S-N'); +INSERT INTO TimeSegmentFraction VALUES(1990,'winter','day',0.33329999999999997406,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(1990,'winter','night',0.16669999999999998152,'# W-N'); +INSERT INTO TimeSegmentFraction VALUES(2000,'inter','day',0.16669999999999998152,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'inter','night',0.08330000000000000071,'# I-N'); +INSERT INTO TimeSegmentFraction VALUES(2000,'summer','day',0.16669999999999998152,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'summer','night',0.08330000000000000071,'# S-N'); +INSERT INTO TimeSegmentFraction VALUES(2000,'winter','day',0.33329999999999997406,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'winter','night',0.16669999999999998152,'# W-N'); +INSERT INTO TimeSegmentFraction VALUES(2010,'inter','day',0.16669999999999998152,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'inter','night',0.08330000000000000071,'# I-N'); +INSERT INTO TimeSegmentFraction VALUES(2010,'summer','day',0.16669999999999998152,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'summer','night',0.08330000000000000071,'# S-N'); +INSERT INTO TimeSegmentFraction VALUES(2010,'winter','day',0.33329999999999997406,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'winter','night',0.16669999999999998152,'# W-N'); CREATE TABLE StorageDuration ( region TEXT, @@ -766,24 +1122,34 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE StorageInit -( - tech TEXT - PRIMARY KEY, - value REAL, - notes TEXT -); -CREATE TABLE TechnologyType +CREATE TABLE StorageLevelFraction ( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO TechnologyType VALUES('r','resource technology'); -INSERT INTO TechnologyType VALUES('p','production technology'); -INSERT INTO TechnologyType VALUES('pb','baseload production technology'); + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage) +); +CREATE TABLE TechnologyType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO TechnologyType VALUES('r','resource technology'); +INSERT INTO TechnologyType VALUES('p','production technology'); +INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE TechInputSplit +CREATE TABLE MinTechInputSplit ( region TEXT, period INTEGER @@ -796,7 +1162,7 @@ CREATE TABLE TechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechInputSplitAnnual +CREATE TABLE MinTechInputSplitAnnual ( region TEXT, period INTEGER @@ -809,7 +1175,26 @@ CREATE TABLE TechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechOutputSplit +CREATE TABLE MinTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +INSERT INTO MinTechOutputSplit VALUES('utopia',1990,'SRE','DSL',0.7,''); +INSERT INTO MinTechOutputSplit VALUES('utopia',2000,'SRE','DSL',0.7,''); +INSERT INTO MinTechOutputSplit VALUES('utopia',2010,'SRE','DSL',0.7,''); +INSERT INTO MinTechOutputSplit VALUES('utopia',1990,'SRE','GSL',0.3,''); +INSERT INTO MinTechOutputSplit VALUES('utopia',2000,'SRE','GSL',0.3,''); +INSERT INTO MinTechOutputSplit VALUES('utopia',2010,'SRE','GSL',0.3,''); +CREATE TABLE MinTechOutputSplitAnnual ( region TEXT, period INTEGER @@ -822,12 +1207,58 @@ CREATE TABLE TechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm) ); -INSERT INTO TechOutputSplit VALUES('utopia',1990,'SRE','DSL',0.7,''); -INSERT INTO TechOutputSplit VALUES('utopia',2000,'SRE','DSL',0.7,''); -INSERT INTO TechOutputSplit VALUES('utopia',2010,'SRE','DSL',0.7,''); -INSERT INTO TechOutputSplit VALUES('utopia',1990,'SRE','GSL',0.3,''); -INSERT INTO TechOutputSplit VALUES('utopia',2000,'SRE','GSL',0.3,''); -INSERT INTO TechOutputSplit VALUES('utopia',2010,'SRE','GSL',0.3,''); +CREATE TABLE MaxTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MaxTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -853,13 +1284,31 @@ INSERT INTO TimePeriod VALUES(6,2010,'f'); INSERT INTO TimePeriod VALUES(7,2020,'f'); CREATE TABLE TimeSeason ( - sequence INTEGER UNIQUE, - season TEXT + season TEXT PRIMARY KEY ); -INSERT INTO TimeSeason VALUES(2,'summer'); -INSERT INTO TimeSeason VALUES(3,'winter'); -INSERT INTO TimeSeason VALUES(1,'inter'); +INSERT INTO TimeSeason VALUES('inter'); +INSERT INTO TimeSeason VALUES('summer'); +INSERT INTO TimeSeason VALUES('winter'); +CREATE TABLE PeriodSeasons +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT + REFERENCES TimeSeason (season), + notes TEXT, + PRIMARY KEY (period, sequence) +); +INSERT INTO PeriodSeasons VALUES(1990,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(1990,3,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(1990,1,'inter',NULL); +INSERT INTO PeriodSeasons VALUES(2000,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2000,3,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2000,1,'inter',NULL); +INSERT INTO PeriodSeasons VALUES(2010,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2010,3,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2010,1,'inter',NULL); CREATE TABLE TimePeriodType ( label TEXT @@ -1020,10 +1469,36 @@ CREATE TABLE MinNewCapacityShare REFERENCES Technology (tech), group_name TEXT REFERENCES TechGroup (group_name), - max_proportion REAL, + min_proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, group_name) ); +CREATE TABLE MinNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); +CREATE TABLE MaxNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1077,6 +1552,36 @@ CREATE TABLE MaxActivityGroup notes TEXT, PRIMARY KEY (region, period, group_name) ); +CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "min_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); +CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "max_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); CREATE TABLE RPSRequirement ( region TEXT NOT NULL @@ -1109,30 +1614,29 @@ CREATE TABLE Technology curtail INTEGER NOT NULL DEFAULT 0, retire INTEGER NOT NULL DEFAULT 0, flex INTEGER NOT NULL DEFAULT 0, - variable INTEGER NOT NULL DEFAULT 0, exchange INTEGER NOT NULL DEFAULT 0, description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('IMPDSL1','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported diesel'); -INSERT INTO Technology VALUES('IMPGSL1','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported gasoline'); -INSERT INTO Technology VALUES('IMPHCO1','r','supply','coal','',1,0,0,0,0,0,0,0,' imported coal'); -INSERT INTO Technology VALUES('IMPOIL1','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO Technology VALUES('IMPURN1','r','supply','nuclear','',1,0,0,0,0,0,0,0,' imported uranium'); -INSERT INTO Technology VALUES('IMPFEQ','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported fossil equivalent'); -INSERT INTO Technology VALUES('IMPHYD','r','supply','','',1,0,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); -INSERT INTO Technology VALUES('E01','pb','electric','coal','',0,0,0,1,1,0,0,0,' coal power plant'); -INSERT INTO Technology VALUES('E21','pb','electric','nuclear','',0,0,0,1,1,0,0,0,' nuclear power plant'); -INSERT INTO Technology VALUES('E31','pb','electric','hydro','',0,0,0,1,1,0,0,0,' hydro power'); -INSERT INTO Technology VALUES('E51','ps','electric','electric','',0,0,0,1,0,0,0,0,' electric storage'); -INSERT INTO Technology VALUES('E70','p','electric','petroleum','',0,0,0,1,1,0,0,0,' diesel power plant'); -INSERT INTO Technology VALUES('RHE','p','residential','electric','',0,0,0,1,1,0,0,0,' electric residential heating'); -INSERT INTO Technology VALUES('RHO','p','residential','petroleum','',0,0,0,1,1,0,0,0,' diesel residential heating'); -INSERT INTO Technology VALUES('RL1','p','residential','electric','',0,0,0,1,1,0,0,0,' residential lighting'); -INSERT INTO Technology VALUES('SRE','p','supply','petroleum','',0,0,0,1,1,0,0,0,' crude oil processor'); -INSERT INTO Technology VALUES('TXD','p','transport','petroleum','',0,0,0,1,1,0,0,0,' diesel powered vehicles'); -INSERT INTO Technology VALUES('TXE','p','transport','electric','',0,0,0,1,1,0,0,0,' electric powered vehicles'); -INSERT INTO Technology VALUES('TXG','p','transport','petroleum','',0,0,0,1,1,0,0,0,' gasoline powered vehicles'); +INSERT INTO Technology VALUES('IMPDSL1','r','supply','petroleum','',1,0,0,0,0,0,0,' imported diesel'); +INSERT INTO Technology VALUES('IMPGSL1','r','supply','petroleum','',1,0,0,0,0,0,0,' imported gasoline'); +INSERT INTO Technology VALUES('IMPHCO1','r','supply','coal','',1,0,0,0,0,0,0,' imported coal'); +INSERT INTO Technology VALUES('IMPOIL1','r','supply','petroleum','',1,0,0,0,0,0,0,' imported crude oil'); +INSERT INTO Technology VALUES('IMPURN1','r','supply','nuclear','',1,0,0,0,0,0,0,' imported uranium'); +INSERT INTO Technology VALUES('IMPFEQ','r','supply','petroleum','',1,0,0,0,0,0,0,' imported fossil equivalent'); +INSERT INTO Technology VALUES('IMPHYD','r','supply','','',1,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); +INSERT INTO Technology VALUES('E01','pb','electric','coal','',0,0,0,1,1,0,0,' coal power plant'); +INSERT INTO Technology VALUES('E21','pb','electric','nuclear','',0,0,0,1,1,0,0,' nuclear power plant'); +INSERT INTO Technology VALUES('E31','pb','electric','hydro','',0,0,0,1,1,0,0,' hydro power'); +INSERT INTO Technology VALUES('E51','ps','electric','electric','',0,0,0,1,0,0,0,' electric storage'); +INSERT INTO Technology VALUES('E70','p','electric','petroleum','',0,0,0,1,1,0,0,' diesel power plant'); +INSERT INTO Technology VALUES('RHE','p','residential','electric','',0,0,0,1,1,0,0,' electric residential heating'); +INSERT INTO Technology VALUES('RHO','p','residential','petroleum','',0,0,0,1,1,0,0,' diesel residential heating'); +INSERT INTO Technology VALUES('RL1','p','residential','electric','',0,0,0,1,1,0,0,' residential lighting'); +INSERT INTO Technology VALUES('SRE','p','supply','petroleum','',0,0,0,1,1,0,0,' crude oil processor'); +INSERT INTO Technology VALUES('TXD','p','transport','petroleum','',0,0,0,1,1,0,0,' diesel powered vehicles'); +INSERT INTO Technology VALUES('TXE','p','transport','electric','',0,0,0,1,1,0,0,' electric powered vehicles'); +INSERT INTO Technology VALUES('TXG','p','transport','petroleum','',0,0,0,1,1,0,0,' gasoline powered vehicles'); CREATE TABLE OutputCost ( scenario TEXT, @@ -1152,197 +1656,4 @@ CREATE TABLE OutputCost FOREIGN KEY (vintage) REFERENCES TimePeriod (period), FOREIGN KEY (tech) REFERENCES Technology (tech) ); -CREATE TABLE IF NOT EXISTS "CostInvest" -( - region TEXT, - tech TEXT - references Technology, - vintage INTEGER - references TimePeriod, - cost REAL, - units TEXT, - notes TEXT, - MMAnalysis TEXT, - primary key (region, tech, vintage) -); -INSERT INTO CostInvest VALUES('utopia','E01',1990,2000.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E01',2000,1300.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E01',2010,1200.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E21',1990,5000.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E21',2000,5000.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E21',2010,5000.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E31',1990,3000.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E31',2000,3000.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E31',2010,3000.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E51',1990,900.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E51',2000,900.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E51',2010,900.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E70',1990,1000.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E70',2000,1000.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E70',2010,1000.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','RHE',1990,90.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','RHE',2000,90.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','RHE',2010,90.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','RHO',1990,100.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','RHO',2000,100.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','RHO',2010,100.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','SRE',1990,100.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','SRE',2000,100.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','SRE',2010,100.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','TXD',1990,1044.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','TXD',2000,1044.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','TXD',2010,1044.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','TXE',1990,2000.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','TXE',2000,1750.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','TXE',2010,1500.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','TXG',1990,1044.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','TXG',2000,1044.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','TXG',2010,1044.0,'','',NULL); -CREATE TABLE IF NOT EXISTS "CostVariable" -( - region TEXT not null, - period INTEGER not null - references TimePeriod, - tech TEXT not null - references Technology, - vintage INTEGER not null - references TimePeriod, - cost REAL, - units TEXT, - notes TEXT, - MMAnalysis TEXT, - primary key (region, period, tech, vintage) -); -INSERT INTO CostVariable VALUES('utopia',1990,'IMPDSL1',1990,10.0,'','','OIL_COST'); -INSERT INTO CostVariable VALUES('utopia',2000,'IMPDSL1',1990,10.0,'','','OIL_COST'); -INSERT INTO CostVariable VALUES('utopia',2010,'IMPDSL1',1990,10.0,'','','OIL_COST'); -INSERT INTO CostVariable VALUES('utopia',1990,'IMPGSL1',1990,15.0,'','','OIL_COST'); -INSERT INTO CostVariable VALUES('utopia',2000,'IMPGSL1',1990,15.0,'','','OIL_COST'); -INSERT INTO CostVariable VALUES('utopia',2010,'IMPGSL1',1990,15.0,'','','OIL_COST'); -INSERT INTO CostVariable VALUES('utopia',1990,'IMPHCO1',1990,2.0,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'IMPHCO1',1990,2.0,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'IMPHCO1',1990,2.0,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'IMPOIL1',1990,8.0,'','','OIL_COST'); -INSERT INTO CostVariable VALUES('utopia',2000,'IMPOIL1',1990,8.0,'','','OIL_COST'); -INSERT INTO CostVariable VALUES('utopia',2010,'IMPOIL1',1990,8.0,'','','OIL_COST'); -INSERT INTO CostVariable VALUES('utopia',1990,'IMPURN1',1990,2.0,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'IMPURN1',1990,2.0,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'IMPURN1',1990,2.0,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1960,0.3,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1970,0.3,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1980,0.3,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1990,0.3,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1970,0.3,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1980,0.3,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1990,0.3,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',2000,0.3,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',1980,0.3,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',1990,0.3,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',2000,0.3,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',2010,0.3,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E21',1990,1.5,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E21',1990,1.5,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E21',1990,1.5,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E21',2000,1.5,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E21',2000,1.5,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E21',2010,1.5,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1960,0.4,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1970,0.4,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1980,0.4,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1990,0.4,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1970,0.4,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1980,0.4,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1990,0.4,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',2000,0.4,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',1980,0.4,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',1990,0.4,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',2000,0.4,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',2010,0.4,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'SRE',1990,10.0,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'SRE',1990,10.0,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'SRE',2000,10.0,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'SRE',1990,10.0,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'SRE',2000,10.0,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'SRE',2010,10.0,'','',NULL); -CREATE TABLE IF NOT EXISTS "Efficiency" -( - region TEXT, - input_comm TEXT - references Commodity, - tech TEXT - references Technology, - vintage INTEGER - references TimePeriod, - output_comm TEXT - references Commodity, - efficiency REAL, - notes TEXT, - MMAnalysis TEXT, - primary key (region, input_comm, tech, vintage, output_comm), - check (efficiency > 0) -); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPDSL1',1990,'DSL',1.0,'',NULL); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPGSL1',1990,'GSL',1.0,'',NULL); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPHCO1',1990,'HCO',1.0,'',NULL); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,'',NULL); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,'',NULL); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,'',NULL); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,'',NULL); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1960,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1970,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1980,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1990,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',2000,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',2010,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',1990,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2000,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2010,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','URN','E21',1990,'ELC',0.4,'# 1/2.5',NULL); -INSERT INTO Efficiency VALUES('utopia','URN','E21',2000,'ELC',0.4,'# 1/2.5',NULL); -INSERT INTO Efficiency VALUES('utopia','URN','E21',2010,'ELC',0.4,'# 1/2.5',NULL); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',1980,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',1990,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',2000,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',2010,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1960,'ELC',0.29399999999999998578,'# 1/3.4',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1970,'ELC',0.29399999999999998578,'# 1/3.4',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1980,'ELC',0.29399999999999998578,'# 1/3.4',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1990,'ELC',0.29399999999999998578,'# 1/3.4',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',2000,'ELC',0.29399999999999998578,'# 1/3.4',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',2010,'ELC',0.29399999999999998578,'# 1/3.4',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',1980,'ELC',0.71999999999999992894,'# 1/1.3889',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',1990,'ELC',0.71999999999999992894,'# 1/1.3889',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',2000,'ELC',0.71999999999999992894,'# 1/1.3889',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',2010,'ELC',0.71999999999999992894,'# 1/1.3889',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','RHE',1990,'RH',1.0,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','RHE',2000,'RH',1.0,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','RHE',2010,'RH',1.0,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1970,'RH',0.7,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1980,'RH',0.7,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1990,'RH',0.7,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2000,'RH',0.7,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2010,'RH',0.7,'# direct translation from DMD_EFF','Res_heating_2010_eff'); -INSERT INTO Efficiency VALUES('utopia','ELC','RL1',1980,'RL',1.0,'# direct translation from DMD_EFF','Res_lighting_eff'); -INSERT INTO Efficiency VALUES('utopia','ELC','RL1',1990,'RL',1.0,'# direct translation from DMD_EFF','Res_lighting_eff'); -INSERT INTO Efficiency VALUES('utopia','ELC','RL1',2000,'RL',1.0,'# direct translation from DMD_EFF','Res_lighting_eff'); -INSERT INTO Efficiency VALUES('utopia','ELC','RL1',2010,'RL',1.0,'# direct translation from DMD_EFF','Res_lighting_eff'); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',1990,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2000,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1970,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1980,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1990,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2000,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2010,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',1990,'TX',0.82699999999999995736,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2000,'TX',0.82699999999999995736,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2010,'TX',0.82699999999999995736,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1970,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1980,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1990,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2000,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2010,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); COMMIT; diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index a6acd8b4f..526ca5d4f 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -8,8 +8,9 @@ CREATE TABLE MetaData PRIMARY KEY (element) ); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); +INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES('myopic_base_year',2000,''); +INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); CREATE TABLE MetaDataReal ( element TEXT, @@ -18,8 +19,8 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,''); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -58,6 +59,8 @@ CREATE TABLE CapacityCredit CREATE TABLE CapacityFactorProcess ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -67,12 +70,14 @@ CREATE TABLE CapacityFactorProcess vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, season, tod, tech, vintage), + PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE CapacityFactorTech ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -81,15 +86,75 @@ CREATE TABLE CapacityFactorTech REFERENCES Technology (tech), factor REAL, notes TEXT, - PRIMARY KEY (region, season, tod, tech), + PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('electricville','inter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville','winter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville','summer','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville','inter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville','winter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville','summer','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2000,'inter','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2000,'winter','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2000,'summer','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2000,'inter','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2000,'winter','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2000,'summer','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2005,'inter','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2005,'winter','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2005,'summer','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2005,'inter','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2005,'winter','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2005,'summer','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2010,'inter','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2010,'winter','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2010,'summer','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2010,'inter','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2010,'winter','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2010,'summer','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2015,'inter','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2015,'winter','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2015,'summer','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2015,'inter','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2015,'winter','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2015,'summer','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2020,'inter','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2020,'winter','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2020,'summer','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2020,'inter','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2020,'winter','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2020,'summer','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2025,'inter','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2025,'winter','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2025,'summer','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2025,'inter','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2025,'winter','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2025,'summer','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2030,'inter','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2030,'winter','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2030,'summer','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2030,'inter','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2030,'winter','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2030,'summer','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2035,'inter','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2035,'winter','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2035,'summer','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2035,'inter','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2035,'winter','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2035,'summer','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2040,'inter','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2040,'winter','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2040,'summer','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2040,'inter','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2040,'winter','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2040,'summer','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2045,'inter','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2045,'winter','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2045,'summer','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2045,'inter','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2045,'winter','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2045,'summer','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2050,'inter','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2050,'winter','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2050,'summer','day','EF',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2050,'inter','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2050,'winter','day','EH',1.0,''); +INSERT INTO CapacityFactorTech VALUES('electricville',2050,'summer','day','EH',1.0,''); CREATE TABLE CapacityToActivity ( region TEXT, @@ -119,6 +184,7 @@ CREATE TABLE CommodityType PRIMARY KEY, description TEXT ); +INSERT INTO CommodityType VALUES('a','annual commodity'); INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); @@ -267,6 +333,8 @@ INSERT INTO Demand VALUES('electricville',2050,'RL',2.0,NULL,NULL); CREATE TABLE DemandSpecificDistribution ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT @@ -274,13 +342,43 @@ CREATE TABLE DemandSpecificDistribution demand_name TEXT REFERENCES Commodity (name), dsd REAL, - dsd_notes TEXT, - PRIMARY KEY (region, season, tod, demand_name), + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('electricville','inter','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville','summer','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville','winter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2000,'inter','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2000,'summer','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2000,'winter','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2005,'inter','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2005,'summer','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2005,'winter','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2010,'inter','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2010,'summer','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2010,'winter','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2015,'inter','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2015,'summer','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2015,'winter','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2020,'inter','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2020,'summer','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2020,'winter','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'inter','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'summer','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'winter','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2030,'inter','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2030,'summer','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2030,'winter','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2035,'inter','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2035,'summer','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2035,'winter','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2040,'inter','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2040,'summer','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2040,'winter','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2045,'inter','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2045,'summer','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2045,'winter','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2050,'inter','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2050,'summer','day','RL',0.33329999999999997406,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2050,'winter','day','RL',0.33329999999999997406,''); CREATE TABLE LoanRate ( region TEXT, @@ -314,6 +412,28 @@ INSERT INTO Efficiency VALUES('electricville','HYD','EF',2010,'ELC',10.0,'est'); INSERT INTO Efficiency VALUES('electricville','ELC','bulbs',2000,'RL',1.0,NULL); INSERT INTO Efficiency VALUES('electricville','earth','well',2000,'HYD',1.0,'water source'); INSERT INTO Efficiency VALUES('electricville','HYD','EH',2020,'ELC',1.0,NULL); +CREATE TABLE EfficiencyVariable +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); CREATE TABLE EmissionActivity ( region TEXT, @@ -332,9 +452,23 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('electricville','co2','HYD','EH',1995,'ELC',0.05000000000000000277,'',''); -INSERT INTO EmissionActivity VALUES('electricville','co2','HYD','EF',2010,'ELC',0.0100000000000000002,'',''); -INSERT INTO EmissionActivity VALUES('electricville','co2','HYD','EH',2000,'ELC',0.02000000000000000041,NULL,NULL); +INSERT INTO EmissionActivity VALUES('electricville','co2','HYD','EH',1995,'ELC',0.05,'',''); +INSERT INTO EmissionActivity VALUES('electricville','co2','HYD','EF',2010,'ELC',0.01,'',''); +INSERT INTO EmissionActivity VALUES('electricville','co2','HYD','EH',2000,'ELC',0.02,NULL,NULL); +CREATE TABLE EmissionEmbodied +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); CREATE TABLE ExistingCapacity ( region TEXT, @@ -499,10 +633,10 @@ CREATE TABLE MinCapacity notes TEXT, PRIMARY KEY (region, period, tech) ); -INSERT INTO MinCapacity VALUES('electricville',2000,'EH',0.2000000000000000111,'',''); -INSERT INTO MinCapacity VALUES('electricville',2005,'EH',0.2000000000000000111,'',''); -INSERT INTO MinCapacity VALUES('electricville',2010,'EH',0.2000000000000000111,'',''); -INSERT INTO MinCapacity VALUES('electricville',2015,'EH',0.2000000000000000111,'',''); +INSERT INTO MinCapacity VALUES('electricville',2000,'EH',0.2,'',''); +INSERT INTO MinCapacity VALUES('electricville',2005,'EH',0.2,'',''); +INSERT INTO MinCapacity VALUES('electricville',2010,'EH',0.2,'',''); +INSERT INTO MinCapacity VALUES('electricville',2015,'EH',0.2,'',''); CREATE TABLE MinCapacityGroup ( region TEXT, @@ -552,44 +686,6 @@ CREATE TABLE OutputNetCapacity capacity REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2000,'EH',2000,1.5); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2000,'EH',1995,0.5); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2005,'EH',1995,0.5); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2005,'EH',2000,1.5); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2025,'EH',2000,1.5); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2015,'EH',2000,1.5); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2010,'EH',1995,0.5); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2020,'EH',2020,3.0); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2030,'EH',1995,0.5); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2020,'EF',2010,45.0); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2020,'EH',1995,0.5); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2010,'EH',2000,1.5); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2030,'EH',2000,1.5); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2025,'EH',2020,3.0); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2025,'EF',2010,45.0); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2015,'EF',2010,45.0); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2020,'EH',2000,1.5); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2025,'EH',1995,0.5); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2015,'EH',1995,0.5); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2010,'EF',2010,45.0); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2030,'EH',2020,3.0); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2030,'EF',2010,45.0); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2035,'EH',2000,1.5); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2035,'EH',1995,0.5); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2035,'EF',2010,45.0); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2035,'EH',2020,3.0); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2040,'EH',2000,1.5); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2040,'EF',2010,45.0); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2040,'EH',1995,0.5); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2040,'EH',2020,3.0); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2045,'EF',2010,45.0); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2045,'EH',1995,0.5); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2045,'EH',2020,3.0); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2045,'EH',2000,1.5); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2050,'EH',2020,3.0); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2050,'EF',2010,45.0); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2050,'EH',2000,1.5); -INSERT INTO OutputNetCapacity VALUES('myo_1','electricville','electric',2050,'EH',1995,0.5); CREATE TABLE OutputBuiltCapacity ( scenario TEXT, @@ -603,9 +699,6 @@ CREATE TABLE OutputBuiltCapacity capacity REAL, PRIMARY KEY (region, scenario, tech, vintage) ); -INSERT INTO OutputBuiltCapacity VALUES('myo_1','electricville','electric','EH',2000,1.5); -INSERT INTO OutputBuiltCapacity VALUES('myo_1','electricville','electric','EF',2010,45.0); -INSERT INTO OutputBuiltCapacity VALUES('myo_1','electricville','electric','EH',2020,3.0); CREATE TABLE OutputRetiredCapacity ( scenario TEXT, @@ -644,135 +737,6 @@ CREATE TABLE OutputFlowIn flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2000,'summer','day','HYD','EH',2000,'ELC',0.4999500000000000055); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2000,'inter','day','HYD','EH',1995,'ELC',0.1666499999999999926); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2000,'winter','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2000,'summer','day','HYD','EH',1995,'ELC',0.1666499999999999926); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2000,'winter','day','earth','well',2000,'HYD',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2000,'winter','day','HYD','EH',1995,'ELC',0.1666499999999999926); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2000,'summer','day','earth','well',2000,'HYD',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2000,'inter','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2000,'summer','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2000,'inter','day','earth','well',2000,'HYD',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2000,'inter','day','HYD','EH',2000,'ELC',0.4999500000000000055); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2000,'winter','day','HYD','EH',2000,'ELC',0.4999500000000000055); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2005,'inter','day','HYD','EH',1995,'ELC',0.1666499999999999926); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2005,'inter','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2005,'inter','day','earth','well',2000,'HYD',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2005,'winter','day','HYD','EH',1995,'ELC',0.1666499999999999926); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2005,'summer','day','earth','well',2000,'HYD',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2005,'summer','day','HYD','EH',2000,'ELC',0.4999500000000000055); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2005,'winter','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2005,'inter','day','HYD','EH',2000,'ELC',0.4999500000000000055); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2005,'winter','day','earth','well',2000,'HYD',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2005,'summer','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2005,'winter','day','HYD','EH',2000,'ELC',0.4999500000000000055); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2005,'summer','day','HYD','EH',1995,'ELC',0.1666499999999999926); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2020,'winter','day','HYD','EF',2010,'ELC',0.2333099999999999897); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2030,'summer','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2020,'summer','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2025,'inter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2020,'winter','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2020,'summer','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2015,'summer','day','earth','well',2000,'HYD',0.06665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2010,'winter','day','earth','well',2000,'HYD',0.06665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2025,'inter','day','HYD','EF',2010,'ELC',0.2333099999999999897); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2020,'winter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2020,'winter','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2025,'inter','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2010,'inter','day','HYD','EF',2010,'ELC',0.06665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2030,'winter','day','HYD','EF',2010,'ELC',0.2333099999999999897); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2025,'winter','day','HYD','EF',2010,'ELC',0.2333099999999999897); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2025,'summer','day','HYD','EF',2010,'ELC',0.2333099999999999897); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2010,'winter','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2015,'winter','day','earth','well',2000,'HYD',0.06665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2020,'inter','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2025,'summer','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2010,'summer','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2020,'summer','day','HYD','EF',2010,'ELC',0.2333099999999999897); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2020,'summer','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2015,'summer','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2025,'winter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2020,'inter','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2015,'winter','day','HYD','EF',2010,'ELC',0.06665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2030,'winter','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2030,'inter','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2010,'summer','day','HYD','EF',2010,'ELC',0.06665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2025,'inter','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2010,'inter','day','earth','well',2000,'HYD',0.06665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2025,'summer','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2015,'winter','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2015,'inter','day','HYD','EF',2010,'ELC',0.06665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2015,'inter','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2030,'inter','day','HYD','EF',2010,'ELC',0.2333099999999999897); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2015,'inter','day','earth','well',2000,'HYD',0.06665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2025,'winter','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2015,'summer','day','HYD','EF',2010,'ELC',0.06665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2030,'summer','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2030,'summer','day','HYD','EF',2010,'ELC',0.2333099999999999897); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2030,'inter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2020,'inter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2020,'inter','day','HYD','EF',2010,'ELC',0.2333099999999999897); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2030,'winter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2010,'inter','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2030,'inter','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2010,'summer','day','earth','well',2000,'HYD',0.06665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2030,'summer','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2010,'winter','day','HYD','EF',2010,'ELC',0.06665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2025,'summer','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2030,'winter','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2025,'winter','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2035,'winter','day','HYD','EF',2010,'ELC',1.499849999999999906); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2035,'inter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2035,'winter','day','HYD','EH',1995,'ELC',0.1666499999999999926); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2035,'summer','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2035,'inter','day','HYD','EH',2000,'ELC',0.4999500000000000055); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2035,'summer','day','HYD','EH',2000,'ELC',0.4999500000000000055); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2035,'winter','day','earth','well',2000,'HYD',3.166349999999999998); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2035,'inter','day','HYD','EH',1995,'ELC',0.1666499999999999926); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2035,'inter','day','ELC','bulbs',2000,'RL',16.66499999999999915); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2035,'summer','day','ELC','bulbs',2000,'RL',16.66499999999999915); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2035,'inter','day','earth','well',2000,'HYD',3.166349999999999998); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2035,'summer','day','HYD','EF',2010,'ELC',1.499849999999999906); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2035,'summer','day','HYD','EH',1995,'ELC',0.1666499999999999926); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2035,'winter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2035,'winter','day','ELC','bulbs',2000,'RL',16.66499999999999915); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2035,'inter','day','HYD','EF',2010,'ELC',1.499849999999999906); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2035,'winter','day','HYD','EH',2000,'ELC',0.4999500000000000055); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2035,'summer','day','earth','well',2000,'HYD',3.166349999999999998); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2040,'summer','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2040,'winter','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2040,'winter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2040,'inter','day','HYD','EF',2010,'ELC',0.2333099999999999897); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2040,'summer','day','HYD','EF',2010,'ELC',0.2333099999999999897); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2040,'inter','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2040,'summer','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2040,'winter','day','HYD','EF',2010,'ELC',0.2333099999999999897); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2040,'inter','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2040,'summer','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2040,'inter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2040,'winter','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2045,'summer','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2045,'summer','day','HYD','EF',2010,'ELC',0.2333099999999999897); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2045,'inter','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2045,'inter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2045,'inter','day','HYD','EF',2010,'ELC',0.2333099999999999897); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2045,'winter','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2045,'summer','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2045,'winter','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2045,'summer','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2045,'winter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2045,'inter','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2045,'winter','day','HYD','EF',2010,'ELC',0.2333099999999999897); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2050,'inter','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2050,'winter','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2050,'summer','day','HYD','EH',2020,'ELC',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','residential',2050,'summer','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2050,'winter','day','HYD','EH',2020,'ELC',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2050,'inter','day','earth','well',2000,'HYD',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2050,'summer','day','earth','well',2000,'HYD',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','supply',2050,'winter','day','earth','well',2000,'HYD',0.6665999999999999704); -INSERT INTO OutputFlowIn VALUES('myo_1','electricville','electric',2050,'inter','day','HYD','EH',2020,'ELC',0.6665999999999999704); CREATE TABLE OutputFlowOut ( scenario TEXT, @@ -782,7 +746,7 @@ CREATE TABLE OutputFlowOut period INTEGER REFERENCES TimePeriod (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -796,135 +760,25 @@ CREATE TABLE OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2000,'summer','day','HYD','EH',2000,'ELC',0.4999500000000000055); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2000,'inter','day','HYD','EH',1995,'ELC',0.1666499999999999926); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2000,'winter','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2000,'summer','day','HYD','EH',1995,'ELC',0.1666499999999999926); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2000,'winter','day','earth','well',2000,'HYD',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2000,'winter','day','HYD','EH',1995,'ELC',0.1666499999999999926); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2000,'summer','day','earth','well',2000,'HYD',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2000,'inter','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2000,'summer','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2000,'inter','day','earth','well',2000,'HYD',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2000,'inter','day','HYD','EH',2000,'ELC',0.4999500000000000055); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2000,'winter','day','HYD','EH',2000,'ELC',0.4999500000000000055); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2005,'inter','day','HYD','EH',1995,'ELC',0.1666499999999999926); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2005,'inter','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2005,'inter','day','earth','well',2000,'HYD',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2005,'winter','day','HYD','EH',1995,'ELC',0.1666499999999999926); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2005,'summer','day','earth','well',2000,'HYD',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2005,'summer','day','HYD','EH',2000,'ELC',0.4999500000000000055); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2005,'winter','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2005,'inter','day','HYD','EH',2000,'ELC',0.4999500000000000055); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2005,'winter','day','earth','well',2000,'HYD',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2005,'summer','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2005,'winter','day','HYD','EH',2000,'ELC',0.4999500000000000055); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2005,'summer','day','HYD','EH',1995,'ELC',0.1666499999999999926); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2020,'winter','day','HYD','EF',2010,'ELC',2.333099999999999952); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2030,'summer','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2020,'summer','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2025,'inter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2020,'winter','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2020,'summer','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2015,'summer','day','earth','well',2000,'HYD',0.06665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2010,'winter','day','earth','well',2000,'HYD',0.06665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2025,'inter','day','HYD','EF',2010,'ELC',2.333099999999999952); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2020,'winter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2020,'winter','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2025,'inter','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2010,'inter','day','HYD','EF',2010,'ELC',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2030,'winter','day','HYD','EF',2010,'ELC',2.333099999999999952); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2025,'winter','day','HYD','EF',2010,'ELC',2.333099999999999952); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2025,'summer','day','HYD','EF',2010,'ELC',2.333099999999999952); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2010,'winter','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2015,'winter','day','earth','well',2000,'HYD',0.06665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2020,'inter','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2025,'summer','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2010,'summer','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2020,'summer','day','HYD','EF',2010,'ELC',2.333099999999999952); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2020,'summer','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2015,'summer','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2025,'winter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2020,'inter','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2015,'winter','day','HYD','EF',2010,'ELC',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2030,'winter','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2030,'inter','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2010,'summer','day','HYD','EF',2010,'ELC',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2025,'inter','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2010,'inter','day','earth','well',2000,'HYD',0.06665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2025,'summer','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2015,'winter','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2015,'inter','day','HYD','EF',2010,'ELC',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2015,'inter','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2030,'inter','day','HYD','EF',2010,'ELC',2.333099999999999952); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2015,'inter','day','earth','well',2000,'HYD',0.06665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2025,'winter','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2015,'summer','day','HYD','EF',2010,'ELC',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2030,'summer','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2030,'summer','day','HYD','EF',2010,'ELC',2.333099999999999952); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2030,'inter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2020,'inter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2020,'inter','day','HYD','EF',2010,'ELC',2.333099999999999952); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2030,'winter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2010,'inter','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2030,'inter','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2010,'summer','day','earth','well',2000,'HYD',0.06665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2030,'summer','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2010,'winter','day','HYD','EF',2010,'ELC',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2025,'summer','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2030,'winter','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2025,'winter','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2035,'winter','day','HYD','EF',2010,'ELC',14.99849999999999995); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2035,'inter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2035,'winter','day','HYD','EH',1995,'ELC',0.1666499999999999926); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2035,'summer','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2035,'inter','day','HYD','EH',2000,'ELC',0.4999500000000000055); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2035,'summer','day','HYD','EH',2000,'ELC',0.4999500000000000055); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2035,'winter','day','earth','well',2000,'HYD',3.166349999999999998); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2035,'inter','day','HYD','EH',1995,'ELC',0.1666499999999999926); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2035,'inter','day','ELC','bulbs',2000,'RL',16.66499999999999915); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2035,'summer','day','ELC','bulbs',2000,'RL',16.66499999999999915); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2035,'inter','day','earth','well',2000,'HYD',3.166349999999999998); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2035,'summer','day','HYD','EF',2010,'ELC',14.99849999999999995); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2035,'summer','day','HYD','EH',1995,'ELC',0.1666499999999999926); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2035,'winter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2035,'winter','day','ELC','bulbs',2000,'RL',16.66499999999999915); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2035,'inter','day','HYD','EF',2010,'ELC',14.99849999999999995); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2035,'winter','day','HYD','EH',2000,'ELC',0.4999500000000000055); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2035,'summer','day','earth','well',2000,'HYD',3.166349999999999998); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2040,'summer','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2040,'winter','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2040,'winter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2040,'inter','day','HYD','EF',2010,'ELC',2.333099999999999952); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2040,'summer','day','HYD','EF',2010,'ELC',2.333099999999999952); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2040,'inter','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2040,'summer','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2040,'winter','day','HYD','EF',2010,'ELC',2.333099999999999952); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2040,'inter','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2040,'summer','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2040,'inter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2040,'winter','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2045,'summer','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2045,'summer','day','HYD','EF',2010,'ELC',2.333099999999999952); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2045,'inter','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2045,'inter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2045,'inter','day','HYD','EF',2010,'ELC',2.333099999999999952); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2045,'winter','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2045,'summer','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2045,'winter','day','earth','well',2000,'HYD',1.233209999999999918); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2045,'summer','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2045,'winter','day','HYD','EH',2020,'ELC',0.999900000000000011); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2045,'inter','day','ELC','bulbs',2000,'RL',3.333000000000000184); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2045,'winter','day','HYD','EF',2010,'ELC',2.333099999999999952); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2050,'inter','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2050,'winter','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2050,'summer','day','HYD','EH',2020,'ELC',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','residential',2050,'summer','day','ELC','bulbs',2000,'RL',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2050,'winter','day','HYD','EH',2020,'ELC',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2050,'inter','day','earth','well',2000,'HYD',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2050,'summer','day','earth','well',2000,'HYD',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','supply',2050,'winter','day','earth','well',2000,'HYD',0.6665999999999999704); -INSERT INTO OutputFlowOut VALUES('myo_1','electricville','electric',2050,'inter','day','HYD','EH',2020,'ELC',0.6665999999999999704); +CREATE TABLE OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); CREATE TABLE PlanningReserveMargin ( region TEXT @@ -956,19 +810,51 @@ CREATE TABLE Region ); INSERT INTO Region VALUES('electricville',NULL); CREATE TABLE TimeSegmentFraction -( +( + period INTEGER + REFERENCES TimePeriod (period), season TEXT REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, notes TEXT, - PRIMARY KEY (season, tod), + PRIMARY KEY (period, season, tod), CHECK (segfrac >= 0 AND segfrac <= 1) ); -INSERT INTO TimeSegmentFraction VALUES('inter','day',0.3332999999999999852,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES('summer','day',0.3332999999999999852,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES('winter','day',0.3332999999999999852,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'inter','day',0.33329999999999997406,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'summer','day',0.33329999999999997406,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'winter','day',0.33329999999999997406,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2005,'inter','day',0.33329999999999997406,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2005,'summer','day',0.33329999999999997406,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2005,'winter','day',0.33329999999999997406,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'inter','day',0.33329999999999997406,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'summer','day',0.33329999999999997406,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'winter','day',0.33329999999999997406,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2015,'inter','day',0.33329999999999997406,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2015,'summer','day',0.33329999999999997406,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2015,'winter','day',0.33329999999999997406,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2020,'inter','day',0.33329999999999997406,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2020,'summer','day',0.33329999999999997406,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2020,'winter','day',0.33329999999999997406,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2025,'inter','day',0.33329999999999997406,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2025,'summer','day',0.33329999999999997406,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2025,'winter','day',0.33329999999999997406,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2030,'inter','day',0.33329999999999997406,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2030,'summer','day',0.33329999999999997406,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2030,'winter','day',0.33329999999999997406,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2035,'inter','day',0.33329999999999997406,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2035,'summer','day',0.33329999999999997406,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2035,'winter','day',0.33329999999999997406,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2040,'inter','day',0.33329999999999997406,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2040,'summer','day',0.33329999999999997406,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2040,'winter','day',0.33329999999999997406,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2045,'inter','day',0.33329999999999997406,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2045,'summer','day',0.33329999999999997406,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2045,'winter','day',0.33329999999999997406,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2050,'inter','day',0.33329999999999997406,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2050,'summer','day',0.33329999999999997406,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2050,'winter','day',0.33329999999999997406,'# W-D'); CREATE TABLE StorageDuration ( region TEXT, @@ -977,12 +863,22 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE StorageInit +CREATE TABLE StorageLevelFraction ( - tech TEXT - PRIMARY KEY, - value REAL, - notes TEXT + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage) ); CREATE TABLE TechnologyType ( @@ -994,7 +890,7 @@ INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE TechInputSplit +CREATE TABLE MinTechInputSplit ( region TEXT, period INTEGER @@ -1007,7 +903,7 @@ CREATE TABLE TechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechInputSplitAnnual +CREATE TABLE MinTechInputSplitAnnual ( region TEXT, period INTEGER @@ -1020,7 +916,20 @@ CREATE TABLE TechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech) ); -CREATE TABLE TechOutputSplit +CREATE TABLE MinTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MinTechOutputSplitAnnual ( region TEXT, period INTEGER @@ -1033,6 +942,58 @@ CREATE TABLE TechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm) ); +CREATE TABLE MaxTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MaxTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -1063,13 +1024,55 @@ INSERT INTO TimePeriod VALUES(12,2050,'f'); INSERT INTO TimePeriod VALUES(13,2055,'f'); CREATE TABLE TimeSeason ( - sequence INTEGER UNIQUE, - season TEXT + season TEXT PRIMARY KEY ); -INSERT INTO TimeSeason VALUES(1,'inter'); -INSERT INTO TimeSeason VALUES(2,'summer'); -INSERT INTO TimeSeason VALUES(3,'winter'); +INSERT INTO TimeSeason VALUES('inter'); +INSERT INTO TimeSeason VALUES('summer'); +INSERT INTO TimeSeason VALUES('winter'); +CREATE TABLE PeriodSeasons +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT + REFERENCES TimeSeason (season), + notes TEXT, + PRIMARY KEY (period, sequence) +); +INSERT INTO PeriodSeasons VALUES(2000,1,'inter',NULL); +INSERT INTO PeriodSeasons VALUES(2000,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2000,3,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2005,1,'inter',NULL); +INSERT INTO PeriodSeasons VALUES(2005,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2005,3,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2010,1,'inter',NULL); +INSERT INTO PeriodSeasons VALUES(2010,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2010,3,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2015,1,'inter',NULL); +INSERT INTO PeriodSeasons VALUES(2015,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2015,3,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2020,1,'inter',NULL); +INSERT INTO PeriodSeasons VALUES(2020,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2020,3,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2025,1,'inter',NULL); +INSERT INTO PeriodSeasons VALUES(2025,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2025,3,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2030,1,'inter',NULL); +INSERT INTO PeriodSeasons VALUES(2030,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2030,3,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2035,1,'inter',NULL); +INSERT INTO PeriodSeasons VALUES(2035,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2035,3,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2040,1,'inter',NULL); +INSERT INTO PeriodSeasons VALUES(2040,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2040,3,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2045,1,'inter',NULL); +INSERT INTO PeriodSeasons VALUES(2045,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2045,3,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2050,1,'inter',NULL); +INSERT INTO PeriodSeasons VALUES(2050,2,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2050,3,'winter',NULL); CREATE TABLE TimePeriodType ( label TEXT @@ -1230,10 +1233,36 @@ CREATE TABLE MinNewCapacityShare REFERENCES Technology (tech), group_name TEXT REFERENCES TechGroup (group_name), - max_proportion REAL, + min_proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, group_name) ); +CREATE TABLE MinNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); +CREATE TABLE MaxNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1251,20 +1280,6 @@ CREATE TABLE OutputEmission emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -INSERT INTO OutputEmission VALUES('myo_1','electricville','electric',2000,'co2','EH',2000,0.02999700000000000283); -INSERT INTO OutputEmission VALUES('myo_1','electricville','electric',2000,'co2','EH',1995,0.02499749999999999889); -INSERT INTO OutputEmission VALUES('myo_1','electricville','electric',2005,'co2','EH',1995,0.02499749999999999889); -INSERT INTO OutputEmission VALUES('myo_1','electricville','electric',2005,'co2','EH',2000,0.02999700000000000283); -INSERT INTO OutputEmission VALUES('myo_1','electricville','electric',2010,'co2','EF',2010,0.01999800000000000189); -INSERT INTO OutputEmission VALUES('myo_1','electricville','electric',2015,'co2','EF',2010,0.01999800000000000189); -INSERT INTO OutputEmission VALUES('myo_1','electricville','electric',2020,'co2','EF',2010,0.06999299999999999967); -INSERT INTO OutputEmission VALUES('myo_1','electricville','electric',2025,'co2','EF',2010,0.06999299999999999967); -INSERT INTO OutputEmission VALUES('myo_1','electricville','electric',2030,'co2','EF',2010,0.06999299999999999967); -INSERT INTO OutputEmission VALUES('myo_1','electricville','electric',2035,'co2','EF',2010,0.4499549999999999939); -INSERT INTO OutputEmission VALUES('myo_1','electricville','electric',2035,'co2','EH',1995,0.02499749999999999889); -INSERT INTO OutputEmission VALUES('myo_1','electricville','electric',2035,'co2','EH',2000,0.02999700000000000283); -INSERT INTO OutputEmission VALUES('myo_1','electricville','electric',2040,'co2','EF',2010,0.06999299999999999967); -INSERT INTO OutputEmission VALUES('myo_1','electricville','electric',2045,'co2','EF',2010,0.06999299999999999967); CREATE TABLE MinActivityGroup ( region TEXT, @@ -1301,6 +1316,36 @@ CREATE TABLE MaxActivityGroup notes TEXT, PRIMARY KEY (region, period, group_name) ); +CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "min_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); +CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "max_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); CREATE TABLE RPSRequirement ( region TEXT NOT NULL @@ -1333,15 +1378,14 @@ CREATE TABLE Technology curtail INTEGER NOT NULL DEFAULT 0, retire INTEGER NOT NULL DEFAULT 0, flex INTEGER NOT NULL DEFAULT 0, - variable INTEGER NOT NULL DEFAULT 0, exchange INTEGER NOT NULL DEFAULT 0, description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('well','r','supply','water','',1,0,0,0,0,0,0,0,'plain old water'); -INSERT INTO Technology VALUES('bulbs','p','residential','electric','',1,0,0,0,0,0,0,0,' residential lighting'); -INSERT INTO Technology VALUES('EH','p','electric','hydro','',0,0,0,0,0,0,0,0,'hydro power electric plant'); -INSERT INTO Technology VALUES('EF','p','electric','electric','',0,0,0,0,0,0,0,0,'fusion plant'); +INSERT INTO Technology VALUES('well','r','supply','water','',1,0,0,0,0,0,0,'plain old water'); +INSERT INTO Technology VALUES('bulbs','p','residential','electric','',1,0,0,0,0,0,0,' residential lighting'); +INSERT INTO Technology VALUES('EH','p','electric','hydro','',0,0,0,0,0,0,0,'hydro power electric plant'); +INSERT INTO Technology VALUES('EF','p','electric','electric','',0,0,0,0,0,0,0,'fusion plant'); CREATE TABLE OutputCost ( scenario TEXT, @@ -1361,38 +1405,6 @@ CREATE TABLE OutputCost FOREIGN KEY (vintage) REFERENCES TimePeriod (period), FOREIGN KEY (tech) REFERENCES Technology (tech) ); -INSERT INTO OutputCost VALUES('myo_1','electricville',2000,'EH',1995,0.0,4.545950504162363793,4.545495909111947341,0.0,0.0,5.0,4.999500000000000277,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2000,'EH',2000,61.27462483904239577,13.63785151248709226,13.63648772733584202,0.0,194.2568624481849327,15.0,14.99849999999999995,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2000,'well',2000,0.0,0.0,9.090991818223894682,0.0,0.0,0.0,9.99900000000000055,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2005,'EH',1995,0.0,3.561871171481695076,3.561514984364547054,0.0,0.0,5.0,4.999500000000000277,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2005,'EH',2000,0.0,10.68561351444508566,10.68454495309364027,0.0,0.0,15.0,14.99849999999999995,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2010,'EH',1995,0.0,2.790819264445571157,0.0,0.0,0.0,5.0,0.0,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2015,'EH',1995,0.0,2.186679919577362518,0.0,0.0,0.0,5.0,0.0,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2020,'EH',1995,0.0,1.713320934680008679,0.0,0.0,0.0,5.0,0.0,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2025,'EH',1995,0.0,1.342431783879983964,0.0,0.0,0.0,5.0,0.0,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2010,'EH',2000,0.0,8.37245779333671436,0.0,0.0,0.0,15.0,0.0,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2015,'EH',2000,0.0,6.560039758732087555,0.0,0.0,0.0,15.0,0.0,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2020,'EH',2000,0.0,5.139962804040026256,0.0,0.0,0.0,15.0,0.0,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2025,'EH',2000,0.0,4.027295351639951448,0.0,0.0,0.0,15.0,0.0,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2030,'EH',2000,0.0,3.155491288106695436,0.0,0.0,0.0,15.0,0.0,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2010,'well',2000,0.0,0.0,0.5581080365038253443,0.0,0.0,0.0,0.999900000000000011,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2010,'EF',2010,4493.317939551132441,251.1737338001014166,11.16216073007650599,0.0,14789.71858114884889,450.0,19.9980000000000011,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2015,'EF',2010,0.0,196.8011927619626248,8.745845006341619765,0.0,0.0,450.0,19.9980000000000011,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2020,'EF',2010,0.0,154.1988841212007913,23.98409443621157066,0.0,0.0,450.0,69.992999999999995,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2025,'EF',2010,0.0,120.8188605491985613,18.79216556982234465,0.0,0.0,450.0,69.992999999999995,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2030,'EF',2010,0.0,94.664738643200863,14.72415344856346131,0.0,0.0,450.0,69.992999999999995,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2035,'EH',1995,0.0,0.8241366640982862312,0.8240542504318764116,0.0,0.0,5.0,4.999500000000000277,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2035,'EH',2000,0.0,2.472409992294858583,2.472162751295629235,0.0,0.0,15.0,14.99849999999999995,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2035,'EF',2010,0.0,74.17229976884576104,74.1648825388688806,0.0,0.0,450.0,449.9549999999999841,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2040,'EH',1995,0.0,0.6457326410670342077,0.0,0.0,0.0,5.0,0.0,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2040,'EH',2000,0.0,1.937197923201102512,0.0,0.0,0.0,15.0,0.0,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2040,'EF',2010,0.0,58.1159376960330789,9.039352949240985425,0.0,0.0,450.0,69.992999999999995,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2045,'EH',1995,0.0,0.5059484208188066435,0.0,0.0,0.0,5.0,0.0,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2045,'EH',2000,0.0,1.517845262456420042,0.0,0.0,0.0,15.0,0.0,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2045,'EF',2010,0.0,45.53535787369259679,7.082569563674146807,0.0,0.0,450.0,69.992999999999995,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2050,'EH',1995,0.0,0.3964238265949301953,0.0,0.0,0.0,5.0,0.0,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2050,'EH',2000,0.0,1.18927147978479053,0.0,0.0,0.0,15.0,0.0,0.0); -INSERT INTO OutputCost VALUES('myo_1','electricville',2050,'EF',2010,0.0,35.67814439354371813,0.0,0.0,0.0,450.0,0.0,0.0); CREATE TABLE MyopicEfficiency ( base_year integer, diff --git a/data_files/my_configs/monte_carlo_utopia.toml b/data_files/my_configs/monte_carlo_utopia.toml index 875946bfe..263afb912 100644 --- a/data_files/my_configs/monte_carlo_utopia.toml +++ b/data_files/my_configs/monte_carlo_utopia.toml @@ -110,5 +110,5 @@ activity_labels = [] [monte_carlo] # a path from the PROJECT ROOT to the settings file that contains the run data. -run_settings = 'data_files/monte_carlo/run_settings_4.csv' +run_settings = 'data_files/monte_carlo/run_settings_1.csv' diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index a335502cc..add584f38 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -287,6 +287,15 @@ def start(self): # 11. Compact the db... lots of writes/deletes leads to bloat self.output_con.execute('VACUUM;') + # Total system cost is, theoretically, sum of discounted costs from OutputCost table + total_cost = self.output_con.execute('SELECT SUM(d_invest)+SUM(d_fixed)+SUM(d_var)+SUM(d_emiss) FROM OutputCost').fetchone()[0] + self.output_con.execute( + f"""INSERT INTO + OutputObjective(scenario, objective_name, total_system_cost) + VALUES('{self.config.scenario}', 'TotalCost', {total_cost})""" + ) + self.output_con.commit() + if self.config.save_excel: temp_scenario = set() temp_scenario.add(self.config.scenario) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 9002e443e..b1a7a1fd4 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -418,7 +418,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N index_value=row[0], element=row[1] ) - load_element(M.time_season_all, list(set((row[1],) for row in raw))) + load_element(M.time_season_all, list(set((row[1],) for row in raw))) # unique seasons into TimeSeason table else: for period in time_optimize: load_indexed_set( @@ -649,8 +649,8 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # CapacityFactorTech if self.table_exists("CapacityFactorTech"): - raw = self.raw_check_mi_period(mi=mi, cur=cur, qry='SELECT region, season, tod, tech, factor FROM main.CapacityFactorTech') - load_element(M.CapacityFactorTech, raw, self.viable_rt, (0, 3)) + raw = self.raw_check_mi_period(mi=mi, cur=cur, qry='SELECT region, period, season, tod, tech, factor FROM main.CapacityFactorTech') + load_element(M.CapacityFactorTech, raw, self.viable_rt, (0, 4)) # CapacityFactorProcess if self.table_exists("CapacityFactorProcess"): @@ -873,8 +873,6 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # CostEmissions (and supporting index set) if self.table_exists('CostEmission'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, emis_comm from main.CostEmission') - load_element(M.CostEmission_rpe, raw) raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, emis_comm, cost from main.CostEmission') load_element(M.CostEmission, raw) @@ -1154,6 +1152,7 @@ def load_param_idx_sets(self, data: dict) -> dict: M: TemoaModel = TemoaModel() # for typing param_idx_sets = { M.CostInvest.name: M.CostInvest_rtv.name, + M.CostEmission.name: M.CostEmission_rpe.name, M.EmissionLimit.name: M.EmissionLimitConstraint_rpe.name, M.MaxActivity.name: M.MaxActivityConstraint_rpt.name, M.MaxSeasonalActivity.name: M.MaxSeasonalActivityConstraint_rpst.name, diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index b4d1a5690..8e9646470 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -316,15 +316,15 @@ def CheckCapacityFactorProcess(M: 'TemoaModel'): count_rptv = dict() # Pull CapacityFactorTech by default - for r, s, d, t in M.CapacityFactor_rsdt: - for p, v in M.processTechs[r, t]: + for r, p, s, d, t in M.CapacityFactor_rpsdt: + for v in M.processVintages[r, p, t]: M.capacityFactorProcesses[r, p, t, v] = False count_rptv[r, p, t, v] = 0 # Check for bad values and count up the good ones for r, p, s, d, t, v in M.CapacityFactorProcess.sparse_iterkeys(): - if (p, v) not in M.processTechs[r, t]: + if v not in M.processVintages[r, p, t]: msg = f"Invalid process {p, v} for {r, t} in CapacityFactorProcess table" logger.error(msg) raise ValueError(msg) @@ -1094,7 +1094,7 @@ def CapacityFactorProcessIndices(M: 'TemoaModel'): def CapacityFactorTechIndices(M: 'TemoaModel'): processes = set((r, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) all_cfs = set( - (r, s, d, t) + (r, p, s, d, t) for p in M.time_optimize for (r, t, v), s, d in cross_product(processes, M.time_season[p], M.time_of_day) ) diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 19eaff930..2ee41034c 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -256,9 +256,9 @@ def __init__(M, *args, **kwargs): M.Demand = Param(M.regions, M.time_optimize, M.commodity_demand) M.initialize_Demands = BuildAction(rule=CreateDemands) - # M.ResourceConstraint_rpr = Set(within=M.regions * M.time_optimize * M.commodity_physical) - # Dev Note: This parameter is currently NOT implemented. Preserved for later refactoring + # MaxResource IS implemented but sums cumulatively for a technology rather than resource commodity + # M.ResourceConstraint_rpr = Set(within=M.regions * M.time_optimize * M.commodity_physical) # M.ResourceBound = Param(M.ResourceConstraint_rpr) # Define technology performance parameters @@ -296,8 +296,8 @@ def __init__(M, *args, **kwargs): default=1, ) - M.CapacityFactor_rsdt = Set(dimen=4, initialize=CapacityFactorTechIndices) - M.CapacityFactorTech = Param(M.CapacityFactor_rsdt, default=1, validate=validate_0to1) + M.CapacityFactor_rpsdt = Set(dimen=5, initialize=CapacityFactorTechIndices) + M.CapacityFactorTech = Param(M.CapacityFactor_rpsdt, default=1, validate=validate_0to1) # Dev note: using a default function below alleviates need to make this set. # M.CapacityFactor_rsdtv = Set(dimen=5, initialize=CapacityFactorProcessIndices) @@ -373,9 +373,9 @@ def __init__(M, *args, **kwargs): M.CostVariable = Param(M.CostVariable_rptv) M.CostEmission_rpe = Set( - dimen=3, domain=M.regions * M.time_optimize * M.commodity_emissions - ) # read from data - M.CostEmission = Param(M.CostEmission_rpe, domain=NonNegativeReals) + within=M.regions * M.time_optimize * M.commodity_emissions + ) + M.CostEmission = Param(M.CostEmission_rpe) M.ModelProcessLife_rptv = Set(dimen=4, initialize=ModelProcessLifeIndices) M.ModelProcessLife = Param(M.ModelProcessLife_rptv, initialize=ParamModelProcessLife_rule) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index c1f10613c..8fc0f257a 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -3304,4 +3304,4 @@ def get_capacity_factor(M: 'TemoaModel', r, p, s, d, t, v): if M.capacityFactorProcesses[r, p, t, v]: return value(M.CapacityFactorProcess[r, p, s, d, t, v]) else: - return value(M.CapacityFactorTech[r, s, d, t]) \ No newline at end of file + return value(M.CapacityFactorTech[r, p, s, d, t]) \ No newline at end of file From 4b257d859a2bc5a54282fdbbf174fa03557ba27e Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Sat, 15 Mar 2025 13:16:12 -0400 Subject: [PATCH 051/587] Fix utopia myopic base year and remove vscode settings --- data_files/example_dbs/utopia.sql | 2 +- tests/testing_data/utopia.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 01ce296c2..12fe5eb07 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -7,7 +7,7 @@ CREATE TABLE MetaData notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); +INSERT INTO MetaData VALUES('myopic_base_year',1990,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 01ce296c2..12fe5eb07 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -7,7 +7,7 @@ CREATE TABLE MetaData notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); +INSERT INTO MetaData VALUES('myopic_base_year',1990,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); From fd1916ff412f7d9cd5747300645339c8150cf67b Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Sat, 15 Mar 2025 13:20:31 -0400 Subject: [PATCH 052/587] Add vscode settings to gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 1d51d8a49..8d142742a 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,6 @@ data_files/untracked_data/* # ignore (for now) associated jupyter notebooks other_notebooks/ /temoa/temoa_model/config_sample_9R + +# ignore cached vscode settings +.vscode \ No newline at end of file From 1a3e78a5f02807f7aca6a182f6ff6616287c2d55 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Sat, 15 Mar 2025 13:41:41 -0400 Subject: [PATCH 053/587] Fix small bug getting default capacity factor --- temoa/temoa_model/temoa_initialize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 8e9646470..b0507cc7b 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -419,7 +419,7 @@ def get_default_capacity_factor(M: 'TemoaModel', r, p, s, d, t, v): :param v: vintage :return: the capacity factor """ - return M.CapacityFactorTech[r, s, d, t] + return M.CapacityFactorTech[r, p, s, d, t] def get_default_loan_rate(M, *_): From 217cdc3ad1adb194fea9dc4857235e8aa82f26ea Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Sat, 15 Mar 2025 13:58:54 -0400 Subject: [PATCH 054/587] Update test sets all passing again --- temoa/temoa_model/hybrid_loader.py | 2 +- tests/testing_data/mediumville_sets.json | 391 +- tests/testing_data/test_system_sets.json | 5039 +++++++++++++++++++--- tests/testing_data/utopia_sets.json | 2151 ++++++++- 4 files changed, 6609 insertions(+), 974 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index b1a7a1fd4..835dd1bf7 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -418,7 +418,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N index_value=row[0], element=row[1] ) - load_element(M.time_season_all, list(set((row[1],) for row in raw))) # unique seasons into TimeSeason table + load_element(M.time_season_all, list(set((row[1],) for row in raw))) # unique seasons into time_season_all set else: for period in time_optimize: load_indexed_set( diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 50747f977..e5f9a19c8 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -19,10 +19,13 @@ 2020, 2025 ], - "time_season": [ + "time_season_all": [ "s1", "s2" ], + "time_season": [ + 2025 + ], "time_of_day": [ "d1", "d2" @@ -158,438 +161,510 @@ "co2", "FusionGas" ], - "CapacityFactor_rsdt": [ + "CapacityFactor_rpsdt": [ [ - "A", - "s2", + "B", + 2025, + "s1", "d1", - "bulbs" + "well" ], [ - "A", + "B", + 2025, "s1", - "d1", + "d2", "EF" ], [ - "B-A", + "B", + 2025, "s2", - "d1", - "FGF_pipe" + "d2", + "batt" ], [ "B", - "s1", + 2025, + "s2", "d2", "EH" ], [ "B", + 2025, + "s1", + "d2", + "bulbs" + ], + [ + "A-B", + 2025, "s2", + "d1", + "FGF_pipe" + ], + [ + "A", + 2025, + "s1", + "d1", + "EFL" + ], + [ + "A", + 2025, + "s1", "d2", - "batt" + "EFL" ], [ "B-A", + 2025, "s1", "d1", "FGF_pipe" ], [ "B", - "s2", - "d2", - "well" + 2025, + "s1", + "d1", + "heater" ], [ "A", + 2025, "s2", "d2", "EH" ], [ - "B", + "A", + 2025, "s2", - "d2", + "d1", "GeoThermal" ], [ - "B", + "A", + 2025, "s2", - "d2", - "heater" + "d1", + "GeoHeater" ], [ - "A", + "A-B", + 2025, "s1", - "d2", - "well" + "d1", + "FGF_pipe" ], [ - "A-B", + "B", + 2025, "s1", "d2", - "FGF_pipe" + "well" ], [ - "B", + "A", + 2025, "s1", "d1", - "batt" + "GeoHeater" ], [ "B", + 2025, "s1", "d1", - "well" + "batt" ], [ "A", + 2025, "s1", - "d2", + "d1", "GeoThermal" ], [ - "A", - "s1", - "d2", - "heater" - ], - [ - "A", + "A-B", + 2025, "s1", "d2", - "EFL" + "FGF_pipe" ], [ "B", + 2025, "s2", "d1", - "bulbs" + "GeoThermal" ], [ "A", - "s2", - "d1", - "well" + 2025, + "s1", + "d2", + "GeoThermal" ], [ "B", - "s1", + 2025, + "s2", "d1", - "GeoThermal" + "GeoHeater" ], [ "B", + 2025, "s1", "d1", - "heater" + "EH" ], [ "A", + 2025, "s1", - "d1", - "bulbs" + "d2", + "GeoHeater" ], [ "A", + 2025, "s2", "d1", - "GeoThermal" + "EF" ], [ "B", + 2025, "s1", "d2", - "GeoHeater" + "heater" ], [ "A", + 2025, "s2", "d1", - "heater" + "bulbs" ], [ "A", - "s1", - "d2", - "EH" - ], - [ - "B", + 2025, "s2", "d2", - "EH" + "EFL" ], [ "A", - "s2", + 2025, + "s1", "d1", - "EFL" + "EF" ], [ - "B", + "B-A", + 2025, "s1", "d2", - "EF" + "FGF_pipe" ], [ - "B-A", + "B", + 2025, "s2", + "d1", + "EF" + ], + [ + "A", + 2025, + "s1", "d2", - "FGF_pipe" + "EF" ], [ - "B", + "A", + 2025, "s1", "d1", - "EH" + "bulbs" ], [ - "A-B", - "s2", - "d1", - "FGF_pipe" + "B", + 2025, + "s1", + "d2", + "EH" ], [ "B", + 2025, "s2", "d1", - "batt" + "bulbs" ], [ "A", - "s2", + 2025, + "s1", "d2", - "GeoHeater" + "bulbs" ], [ - "B", + "A-B", + 2025, "s2", - "d1", - "well" + "d2", + "FGF_pipe" ], [ "A", + 2025, "s2", "d1", - "EH" + "well" ], [ - "B", + "A", + 2025, "s2", - "d1", + "d2", "GeoThermal" ], [ "B", + 2025, "s2", - "d1", - "heater" + "d2", + "GeoHeater" ], [ "A", + 2025, "s2", "d2", - "EF" - ], - [ - "A-B", - "s1", - "d1", - "FGF_pipe" + "GeoHeater" ], [ - "A", + "B", + 2025, "s1", - "d1", - "well" + "d2", + "batt" ], [ - "A", - "s1", - "d1", + "B", + 2025, + "s2", + "d2", "GeoThermal" ], [ "A", - "s1", + 2025, + "s2", "d1", "heater" ], [ "A", + 2025, "s1", "d1", - "EFL" + "well" ], [ "B", + 2025, "s2", - "d2", - "GeoHeater" + "d1", + "well" ], [ "B", + 2025, "s2", "d2", "EF" ], [ - "B", + "A", + 2025, "s1", "d2", - "bulbs" - ], - [ - "B", - "s1", - "d1", - "GeoHeater" + "well" ], [ "A", - "s1", + 2025, + "s2", "d2", - "GeoHeater" + "EF" ], [ "B", - "s2", + 2025, + "s1", "d1", - "EH" + "GeoThermal" ], [ - "A", + "B", + 2025, "s2", "d2", "bulbs" ], [ - "A", + "B", + 2025, "s1", - "d2", - "EF" + "d1", + "GeoHeater" ], [ "A", - "s1", - "d1", - "EH" + 2025, + "s2", + "d2", + "bulbs" ], [ "B-A", - "s1", - "d2", + 2025, + "s2", + "d1", "FGF_pipe" ], [ - "B", + "A", + 2025, "s1", "d1", - "EF" + "heater" ], [ - "A", + "B", + 2025, "s2", "d1", - "GeoHeater" + "heater" ], [ - "A-B", - "s2", + "A", + 2025, + "s1", "d2", - "FGF_pipe" + "heater" ], [ "A", + 2025, "s2", "d1", - "EF" + "EH" ], [ "B", + 2025, "s1", - "d2", - "batt" + "d1", + "EF" ], [ "B", + 2025, "s2", "d2", - "bulbs" + "well" ], [ - "B", + "A", + 2025, "s1", + "d1", + "EH" + ], + [ + "A", + 2025, + "s2", "d2", "well" ], [ "B", - "s1", - "d2", - "GeoThermal" + 2025, + "s2", + "d1", + "EH" ], [ "B", + 2025, "s1", - "d2", - "heater" + "d1", + "bulbs" ], [ "B", + 2025, "s2", "d1", - "GeoHeater" + "batt" ], [ - "A", + "B", + 2025, "s1", "d2", - "bulbs" + "GeoThermal" ], [ - "A", - "s2", + "B", + 2025, + "s1", "d2", - "well" + "GeoHeater" ], [ - "A", + "B-A", + 2025, "s2", "d2", - "EFL" - ], - [ - "B", - "s2", - "d1", - "EF" - ], - [ - "B", - "s1", - "d1", - "bulbs" + "FGF_pipe" ], [ "A", + 2025, "s1", - "d1", - "GeoHeater" + "d2", + "EH" ], [ - "A", + "B", + 2025, "s2", "d2", - "GeoThermal" + "heater" ], [ "A", + 2025, "s2", "d2", "heater" + ], + [ + "A", + 2025, + "s2", + "d1", + "EFL" ] ], "LifetimeProcess_rtv": [ diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 6f6c171e1..a8b200b7d 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -27,12 +27,17 @@ 2025, 2030 ], - "time_season": [ + "time_season_all": [ "spring", "summer", "fall", "winter" ], + "time_season": [ + 2020, + 2025, + 2030 + ], "time_of_day": [ "day", "night" @@ -182,1542 +187,5382 @@ "RH", "CO2" ], - "CapacityFactor_rsdt": [ - [ - "R1", - "fall", - "night", - "E_NUCLEAR" - ], + "CapacityFactor_rpsdt": [ [ - "R1-R2", + "R2", + 2025, "winter", "night", - "E_TRANS" - ], - [ - "R1", - "summer", - "night", - "E_BATT" + "R_EH" ], [ - "R1", + "R2", + 2020, "winter", - "night", - "E_SOLPV" - ], - [ - "R1", - "summer", "day", - "R_NGH" - ], - [ - "R1", - "fall", - "day", - "E_SOLPV" + "S_IMPNG" ], [ - "R1", - "fall", + "R2", + 2030, + "summer", "night", - "S_IMPETH" + "T_DSL" ], [ "R2", + 2030, "winter", - "day", + "night", "S_IMPNG" ], [ "R1", - "winter", + 2020, + "spring", "night", - "T_DSL" + "E_SOLPV" ], [ - "R1-R2", + "R1", + 2025, "fall", "day", - "E_TRANS" + "E_BATT" ], [ - "R2", + "R1-R2", + 2025, "winter", "night", - "E_NUCLEAR" + "E_TRANS" ], [ "R1", - "fall", + 2025, + "winter", "day", - "T_DSL" + "R_NGH" ], [ "R2", - "winter", - "day", - "E_BATT" + 2020, + "summer", + "night", + "S_IMPETH" ], [ "R2", + 2025, "summer", "day", - "S_IMPURN" + "E_SOLPV" ], [ "R2", - "spring", + 2025, + "summer", "night", - "T_BLND" + "E_NGCC" ], [ "R1", - "spring", - "day", - "E_NGCC" + 2030, + "summer", + "night", + "S_OILREF" ], [ "R1", - "spring", + 2030, + "summer", "night", - "S_OILREF" + "S_IMPNG" ], [ "R2", + 2030, "winter", - "day", - "E_SOLPV" - ], - [ - "R2-R1", - "fall", "night", - "E_TRANS" + "E_BATT" ], [ "R2", + 2020, "summer", "day", - "S_IMPOIL" + "S_OILREF" ], [ "R2", - "winter", - "night", - "E_NGCC" - ], - [ - "R2-R1", - "spring", + 2020, + "summer", "day", - "E_TRANS" + "S_IMPNG" ], [ - "R1-R2", + "R1", + 2025, "winter", - "day", - "E_TRANS" - ], - [ - "R2", - "fall", "night", - "S_OILREF" - ], - [ - "R2", - "fall", - "day", - "E_NGCC" + "R_EH" ], [ "R1", - "winter", - "day", - "T_GSL" + 2030, + "fall", + "night", + "T_DSL" ], [ "R2", + 2020, "spring", - "day", - "S_IMPNG" - ], - [ - "R2", - "summer", "night", - "R_NGH" + "E_SOLPV" ], [ "R1", + 2020, "spring", - "night", - "T_DSL" + "day", + "T_EV" ], [ - "R2", + "R1", + 2020, "summer", "day", "T_EV" ], [ - "R2", + "R1", + 2025, "spring", - "night", - "E_NUCLEAR" + "day", + "R_EH" ], [ - "R2", + "R1", + 2025, "fall", "night", - "E_SOLPV" + "S_IMPOIL" ], [ - "R2", + "R1", + 2025, "summer", "day", - "R_EH" + "E_SOLPV" ], [ "R1", - "winter", - "day", - "S_IMPNG" + 2030, + "spring", + "night", + "E_NUCLEAR" ], [ - "R2", - "spring", + "R1", + 2025, + "fall", "day", - "E_BATT" + "E_NGCC" ], [ "R2", - "summer", + 2025, + "winter", "day", - "S_IMPETH" + "R_NGH" ], [ "R1", - "winter", - "day", + 2030, + "summer", + "night", "E_BATT" ], [ "R2", + 2030, "fall", "night", - "T_DSL" + "T_EV" ], [ - "R2", - "spring", - "day", - "E_SOLPV" + "R1", + 2020, + "winter", + "night", + "R_NGH" ], [ - "R1", + "R2", + 2030, "summer", "day", - "S_IMPURN" + "R_NGH" ], [ "R2", + 2030, "spring", "night", - "E_NGCC" + "T_EV" ], [ "R1-R2", - "spring", - "day", + 2030, + "fall", + "night", "E_TRANS" ], [ "R1", - "summer", - "day", - "S_IMPOIL" + 2025, + "spring", + "night", + "T_DSL" ], [ "R1", - "winter", + 2025, + "fall", "night", - "E_NGCC" + "T_GSL" ], [ - "R1", - "fall", + "R2", + 2030, + "winter", "day", - "E_NGCC" + "S_IMPURN" ], [ "R1", + 2030, "spring", + "night", + "E_BATT" + ], + [ + "R2", + 2025, + "fall", "day", - "T_GSL" + "S_IMPOIL" ], [ "R1", - "spring", - "day", - "S_IMPNG" - ], - [ - "R1", - "summer", + 2025, + "fall", "night", - "R_NGH" + "T_BLND" ], [ "R1", - "summer", - "day", - "R_EH" + 2020, + "spring", + "night", + "S_IMPOIL" ], [ - "R1", - "summer", + "R2", + 2020, + "spring", "day", "T_EV" ], [ - "R1", + "R2", + 2025, "spring", "night", - "E_NUCLEAR" - ], - [ - "R1", - "fall", - "night", - "E_SOLPV" + "S_IMPURN" ], [ "R2", + 2025, "fall", "day", "T_GSL" ], [ "R2", - "winter", - "night", - "S_IMPNG" - ], - [ - "R1-R2", - "fall", - "night", - "E_TRANS" + 2025, + "spring", + "day", + "E_SOLPV" ], [ "R1", - "spring", + 2030, + "fall", "day", - "E_BATT" + "R_NGH" ], [ "R1", - "summer", + 2025, + "winter", "day", - "S_IMPETH" + "T_EV" ], [ "R2", - "fall", + 2030, + "spring", "day", - "S_IMPNG" + "T_DSL" ], [ "R1", + 2020, "fall", "night", - "T_DSL" + "E_NGCC" ], [ - "R2", - "winter", - "night", - "E_BATT" + "R1", + 2030, + "summer", + "day", + "S_IMPURN" ], [ "R2", + 2030, "summer", "night", - "S_IMPURN" + "E_SOLPV" + ], + [ + "R1", + 2020, + "spring", + "night", + "T_GSL" ], [ "R2", - "winter", + 2025, + "summer", "day", - "R_NGH" + "S_IMPOIL" ], [ "R2", + 2025, "fall", "day", - "E_BATT" + "T_BLND" ], [ "R1", - "spring", - "night", - "E_NGCC" - ], - [ - "R2", + 2030, "winter", "night", - "E_SOLPV" + "E_NGCC" ], [ - "R2", - "summer", + "R1-R2", + 2030, + "spring", "night", - "S_IMPOIL" + "E_TRANS" ], [ "R2-R1", - "spring", - "night", + 2025, + "winter", + "day", "E_TRANS" ], [ "R2", - "fall", + 2025, + "summer", "night", - "E_NGCC" + "S_IMPURN" ], [ - "R2", + "R1", + 2020, "summer", "day", - "S_OILREF" - ], - [ - "R2", - "spring", - "night", - "S_OILREF" + "E_NUCLEAR" ], [ "R1", - "winter", + 2020, + "spring", "night", - "S_IMPNG" + "T_BLND" ], [ - "R1", - "fall", + "R2", + 2025, + "summer", "day", "T_GSL" ], [ "R2", - "summer", + 2020, + "spring", "night", - "T_EV" + "S_IMPOIL" ], [ "R2", + 2020, + "fall", + "day", + "E_NGCC" + ], + [ + "R1", + 2020, "summer", "night", - "R_EH" + "T_GSL" ], [ - "R1", - "fall", + "R1-R2", + 2025, + "spring", "day", - "S_IMPNG" + "E_TRANS" ], [ - "R2", + "R1", + 2030, "spring", - "night", - "E_BATT" + "day", + "E_NGCC" ], [ "R1", - "winter", + 2030, + "spring", "night", - "E_BATT" + "E_NGCC" ], [ "R2", + 2030, "spring", "night", - "E_SOLPV" + "E_NUCLEAR" ], [ "R1", + 2020, "summer", - "night", - "S_IMPURN" + "day", + "E_BATT" ], [ - "R1", - "winter", + "R2", + 2025, + "summer", "day", - "R_NGH" + "T_BLND" ], [ "R1", - "fall", + 2025, + "summer", "day", - "E_BATT" + "S_IMPOIL" ], [ "R2", + 2025, "winter", "day", - "T_GSL" + "T_EV" ], [ "R2", - "spring", + 2020, + "fall", "night", - "T_DSL" + "T_GSL" ], [ - "R1-R2", - "spring", - "night", - "E_TRANS" + "R2", + 2030, + "winter", + "day", + "S_IMPETH" ], [ - "R1", - "summer", + "R2", + 2020, + "spring", "night", - "S_IMPOIL" + "T_GSL" ], [ "R1", + 2025, "fall", "night", - "E_NGCC" - ], - [ - "R1", - "summer", - "day", "S_OILREF" ], [ "R2", + 2030, "summer", "day", - "T_BLND" + "T_EV" ], [ "R1", - "spring", + 2025, + "summer", "night", - "S_IMPNG" + "E_SOLPV" ], [ "R1-R2", + 2030, "summer", "day", "E_TRANS" ], [ - "R1", - "summer", + "R2", + 2025, + "winter", "night", - "R_EH" + "R_NGH" ], [ - "R1", - "summer", + "R2", + 2020, + "spring", + "day", + "E_NUCLEAR" + ], + [ + "R2-R1", + 2020, + "winter", "night", - "T_EV" + "E_TRANS" ], [ "R1", - "spring", + 2025, + "fall", "night", - "E_BATT" + "E_NUCLEAR" + ], + [ + "R2", + 2020, + "spring", + "night", + "T_BLND" ], [ "R1", + 2025, "summer", - "night", - "S_IMPETH" + "day", + "T_GSL" ], [ "R2", + 2025, "fall", "night", - "S_IMPNG" - ], - [ - "R1", - "spring", - "night", - "E_SOLPV" + "S_IMPETH" ], [ "R1", - "spring", + 2020, + "winter", "day", - "R_NGH" + "R_EH" ], [ "R2", + 2025, "spring", - "day", - "T_GSL" + "night", + "S_IMPETH" ], [ "R2", + 2025, + "fall", + "night", + "E_SOLPV" + ], + [ + "R1", + 2020, + "fall", + "night", + "T_DSL" + ], + [ + "R1", + 2025, "summer", "day", - "E_NUCLEAR" + "T_BLND" ], [ "R2", + 2030, "fall", - "night", - "E_BATT" + "day", + "T_DSL" ], [ "R2", + 2030, "winter", - "day", - "T_EV" + "night", + "S_IMPURN" ], [ "R2", + 2025, "fall", "day", - "R_NGH" + "S_OILREF" ], [ "R1", + 2030, "summer", "day", - "T_BLND" + "S_IMPETH" + ], + [ + "R1", + 2025, + "fall", + "night", + "E_BATT" ], [ "R1", + 2030, "winter", - "day", - "S_IMPURN" + "night", + "T_DSL" ], [ - "R2", - "summer", + "R1", + 2020, + "spring", "night", "S_OILREF" ], [ - "R1", - "winter", + "R2", + 2025, + "spring", "day", "S_IMPOIL" ], [ "R1", + 2030, "fall", - "night", - "T_GSL" + "day", + "T_EV" ], [ - "R1", + "R2", + 2025, "fall", + "day", + "E_NUCLEAR" + ], + [ + "R2", + 2025, + "summer", "night", - "S_IMPNG" + "S_IMPETH" + ], + [ + "R1", + 2020, + "spring", + "day", + "E_NGCC" ], [ "R1", + 2020, "summer", "day", - "E_NUCLEAR" + "E_NGCC" ], [ "R1", + 2025, "winter", "night", "R_NGH" ], [ - "R1", - "fall", + "R2-R1", + 2030, + "summer", "night", - "E_BATT" + "E_TRANS" ], [ "R1", - "winter", - "day", - "T_EV" + 2020, + "spring", + "night", + "E_NUCLEAR" ], [ "R2", - "spring", - "day", - "T_EV" + 2025, + "summer", + "night", + "E_SOLPV" ], [ - "R1", - "winter", + "R2", + 2020, + "fall", "day", - "R_EH" + "T_DSL" ], [ "R1", - "fall", + 2030, + "spring", "day", - "R_NGH" + "T_DSL" ], [ "R2", - "winter", - "night", - "T_GSL" - ], - [ - "R1", + 2025, "spring", "day", - "S_IMPURN" + "T_GSL" ], [ - "R1", + "R2", + 2025, "summer", - "night", + "day", "S_OILREF" ], [ - "R2", + "R1", + 2030, "summer", "night", - "T_BLND" + "S_IMPURN" ], [ "R1", - "summer", + 2020, + "fall", "day", + "T_GSL" + ], + [ + "R2", + 2030, + "fall", + "night", "E_NGCC" ], [ - "R1", - "spring", + "R2", + 2025, + "fall", "day", - "S_IMPOIL" + "E_BATT" ], [ - "R1-R2", + "R1", + 2020, "summer", "night", - "E_TRANS" + "S_OILREF" ], [ "R2", - "fall", + 2020, + "winter", "day", - "S_IMPURN" + "R_EH" ], [ - "R2-R1", + "R2", + 2020, "summer", - "day", - "E_TRANS" + "night", + "S_IMPNG" ], [ "R2", - "fall", + 2020, + "summer", "day", - "S_IMPOIL" + "S_IMPURN" ], [ - "R1", + "R1-R2", + 2025, "spring", "night", - "R_NGH" - ], - [ - "R1", - "spring", - "day", - "R_EH" + "E_TRANS" ], [ "R1", + 2025, "spring", "day", - "T_EV" + "R_NGH" ], [ "R2", - "spring", + 2030, + "summer", "night", "T_GSL" ], [ - "R1", - "winter", + "R2", + 2030, + "spring", "night", - "T_GSL" + "E_NGCC" ], [ - "R2", + "R1", + 2020, "spring", "night", - "S_IMPNG" + "E_BATT" ], [ "R2", + 2025, "summer", - "night", + "day", "E_NUCLEAR" ], [ "R2", - "winter", + 2025, + "spring", + "day", + "T_BLND" + ], + [ + "R1", + 2020, + "summer", "night", - "T_EV" + "E_NUCLEAR" ], [ "R2", + 2020, "fall", "night", - "R_NGH" + "S_OILREF" ], [ "R2", + 2030, + "summer", + "night", + "T_BLND" + ], + [ + "R2", + 2020, + "spring", + "night", + "S_OILREF" + ], + [ + "R2-R1", + 2020, + "summer", + "day", + "E_TRANS" + ], + [ + "R1", + 2025, + "fall", + "day", + "E_SOLPV" + ], + [ + "R2", + 2020, + "fall", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_EV" + ], + [ + "R2", + 2020, + "spring", + "day", + "E_NGCC" + ], + [ + "R2", + 2025, + "summer", + "day", + "E_BATT" + ], + [ + "R2", + 2020, + "spring", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2020, + "summer", + "night", + "E_BATT" + ], + [ + "R1", + 2025, + "summer", + "day", + "S_OILREF" + ], + [ + "R2", + 2020, + "summer", + "day", + "R_EH" + ], + [ + "R1", + 2025, + "summer", + "night", + "S_IMPOIL" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_GSL" + ], + [ + "R2", + 2025, + "winter", + "night", + "T_EV" + ], + [ + "R2", + 2030, + "winter", + "night", + "S_IMPETH" + ], + [ + "R1", + 2025, + "summer", + "day", + "E_NUCLEAR" + ], + [ + "R2", + 2020, + "fall", + "night", + "E_BATT" + ], + [ + "R2", + 2020, + "spring", + "night", + "E_BATT" + ], + [ + "R2", + 2025, + "fall", + "night", + "S_IMPOIL" + ], + [ + "R1", + 2020, + "spring", + "day", + "T_DSL" + ], + [ + "R1", + 2025, + "summer", + "day", + "E_BATT" + ], + [ + "R1", + 2025, + "summer", + "night", + "T_BLND" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_DSL" + ], + [ + "R1", + 2020, + "fall", + "night", + "E_SOLPV" + ], + [ + "R1", + 2025, + "winter", + "night", + "T_EV" + ], + [ + "R2", + 2025, + "spring", + "day", + "S_OILREF" + ], + [ + "R1", + 2025, + "spring", + "night", + "T_GSL" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_DSL" + ], + [ + "R2", + 2020, + "summer", + "day", + "S_IMPETH" + ], + [ + "R1", + 2020, + "fall", + "day", + "S_OILREF" + ], + [ + "R1", + 2030, + "summer", + "night", + "S_IMPETH" + ], + [ + "R2", + 2025, + "summer", + "night", + "S_IMPOIL" + ], + [ + "R2", + 2030, + "summer", + "night", + "S_OILREF" + ], + [ + "R1", + 2030, + "winter", + "night", + "E_SOLPV" + ], + [ + "R2", + 2025, + "fall", + "night", + "T_BLND" + ], + [ + "R2", + 2025, + "spring", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2020, + "summer", + "night", + "E_NGCC" + ], + [ + "R1", + 2020, + "fall", + "day", + "E_NUCLEAR" + ], + [ + "R2", + 2030, + "summer", + "day", + "E_NGCC" + ], + [ + "R1", + 2025, + "spring", + "day", + "T_EV" + ], + [ + "R2", + 2030, + "summer", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "winter", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "spring", + "day", + "E_SOLPV" + ], + [ + "R2", + 2020, + "fall", + "day", + "E_SOLPV" + ], + [ + "R1", + 2030, + "spring", + "night", + "E_SOLPV" + ], + [ + "R2", + 2020, + "fall", + "night", + "E_NGCC" + ], + [ + "R2", + 2020, + "winter", + "night", + "R_EH" + ], + [ + "R2", + 2025, + "spring", + "day", + "E_BATT" + ], + [ + "R2", + 2030, + "spring", + "day", + "T_GSL" + ], + [ + "R1", + 2020, + "fall", + "day", + "E_BATT" + ], + [ + "R1", + 2025, + "winter", + "day", + "T_DSL" + ], + [ + "R2", + 2030, + "summer", + "night", + "E_BATT" + ], + [ + "R2", + 2025, + "summer", + "night", + "T_BLND" + ], + [ + "R1", + 2025, + "fall", + "day", + "S_IMPOIL" + ], + [ + "R1", + 2030, + "fall", + "night", + "S_OILREF" + ], + [ + "R1-R2", + 2020, + "winter", + "night", + "E_TRANS" + ], + [ + "R1", + 2025, + "fall", + "night", + "S_IMPURN" + ], + [ + "R1", + 2020, + "winter", + "day", + "R_NGH" + ], + [ + "R2-R1", + 2020, + "summer", + "night", + "E_TRANS" + ], + [ + "R1", + 2030, + "fall", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2025, + "fall", + "day", + "T_GSL" + ], + [ + "R1", + 2025, + "summer", + "night", + "S_OILREF" + ], + [ + "R1", + 2025, + "summer", + "night", + "S_IMPNG" + ], + [ + "R2", + 2030, + "winter", + "day", + "S_IMPNG" + ], + [ + "R1", + 2020, + "winter", + "night", + "R_EH" + ], + [ + "R1", + 2025, + "fall", + "day", + "T_BLND" + ], + [ + "R1", + 2030, + "fall", + "night", + "E_BATT" + ], + [ + "R2", + 2025, + "fall", + "day", + "S_IMPURN" + ], + [ + "R2", + 2025, + "fall", + "night", + "S_IMPNG" + ], + [ + "R1", + 2025, + "spring", + "night", + "S_OILREF" + ], + [ + "R2", + 2025, + "spring", + "night", + "S_IMPNG" + ], + [ + "R2", + 2025, + "winter", + "day", + "T_DSL" + ], + [ + "R1", + 2020, + "spring", + "night", + "S_IMPURN" + ], + [ + "R1", + 2020, + "fall", + "night", + "S_IMPOIL" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_DSL" + ], + [ + "R1", + 2020, + "spring", + "day", + "E_SOLPV" + ], + [ + "R1", + 2020, + "summer", + "day", + "E_SOLPV" + ], + [ + "R1", + 2020, + "fall", + "day", + "E_NGCC" + ], + [ + "R2", + 2020, + "winter", + "day", + "R_NGH" + ], + [ + "R1", + 2025, + "spring", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "summer", + "day", + "S_IMPNG" + ], + [ + "R2", + 2030, + "winter", + "night", + "R_NGH" + ], + [ + "R1", + 2030, + "winter", + "day", + "E_NGCC" + ], + [ + "R1-R2", + 2025, + "winter", + "day", + "E_TRANS" + ], + [ + "R2", + 2025, + "summer", + "day", + "S_IMPURN" + ], + [ + "R2", + 2025, + "summer", + "night", + "S_IMPNG" + ], + [ + "R1", + 2020, + "fall", + "night", + "T_GSL" + ], + [ + "R2", + 2030, + "fall", + "night", + "E_SOLPV" + ], + [ + "R2", + 2030, + "fall", + "day", + "T_GSL" + ], + [ + "R1", + 2020, + "summer", + "night", + "S_IMPURN" + ], + [ + "R2", + 2030, + "spring", + "night", + "E_SOLPV" + ], + [ + "R1", + 2025, + "spring", + "night", + "E_BATT" + ], + [ + "R2", + 2030, + "spring", + "day", + "S_OILREF" + ], + [ + "R2", + 2025, + "winter", + "night", + "E_NGCC" + ], + [ + "R2", + 2020, + "fall", + "day", + "S_IMPOIL" + ], + [ + "R1", + 2030, + "winter", + "night", + "T_GSL" + ], + [ + "R1", + 2030, + "spring", + "night", + "S_IMPOIL" + ], + [ + "R1", + 2020, + "fall", + "night", + "T_BLND" + ], + [ + "R2", + 2020, + "fall", + "night", + "S_IMPURN" + ], + [ + "R1", + 2025, + "fall", + "night", + "S_IMPETH" + ], + [ + "R1", + 2030, + "summer", + "night", + "R_NGH" + ], + [ + "R2", + 2030, + "spring", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "fall", + "day", + "T_DSL" + ], + [ + "R2", + 2020, + "summer", + "day", + "R_NGH" + ], + [ + "R2", + 2020, + "spring", + "night", + "S_IMPURN" + ], + [ + "R1", + 2030, + "winter", + "night", + "T_BLND" + ], + [ + "R1", + 2030, + "fall", + "night", + "E_NGCC" + ], + [ + "R1", + 2030, + "spring", + "day", + "T_GSL" + ], + [ + "R2", + 2020, + "fall", + "day", + "T_GSL" + ], + [ + "R2", + 2020, + "spring", + "day", + "E_SOLPV" + ], + [ + "R1", + 2020, + "winter", + "day", + "T_EV" + ], + [ + "R1", + 2025, + "fall", + "day", + "S_OILREF" + ], + [ + "R1", + 2025, + "fall", + "day", + "S_IMPNG" + ], + [ + "R1", + 2025, + "summer", + "day", + "S_IMPURN" + ], + [ + "R2", + 2020, + "summer", + "night", + "R_EH" + ], + [ + "R2", + 2030, + "spring", + "day", + "E_BATT" + ], + [ + "R1", + 2030, + "spring", + "day", + "T_BLND" + ], + [ + "R2", + 2020, + "fall", + "day", + "T_BLND" + ], + [ + "R1", + 2025, + "winter", + "night", + "E_NGCC" + ], + [ + "R1", + 2030, + "spring", + "night", + "T_BLND" + ], + [ + "R2-R1", + 2020, + "winter", + "day", + "E_TRANS" + ], + [ + "R2", + 2025, + "fall", + "day", + "S_IMPETH" + ], + [ + "R1", + 2020, + "spring", + "night", + "S_IMPETH" + ], + [ + "R1", + 2025, + "spring", + "day", + "E_NGCC" + ], + [ + "R1", + 2025, + "spring", + "night", + "E_NGCC" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_DSL" + ], + [ + "R1", + 2020, + "spring", + "day", + "S_IMPOIL" + ], + [ + "R1", + 2020, + "summer", + "day", + "S_IMPOIL" + ], + [ + "R2", + 2020, + "winter", + "day", + "T_EV" + ], + [ + "R2", + 2025, + "summer", + "day", + "S_IMPETH" + ], + [ + "R2", + 2025, + "spring", + "day", + "S_IMPURN" + ], + [ + "R1", + 2020, + "summer", + "night", + "S_IMPETH" + ], + [ + "R1", + 2020, + "fall", + "day", + "S_IMPURN" + ], + [ + "R1", + 2020, + "fall", + "night", + "S_OILREF" + ], + [ + "R2", + 2025, + "winter", + "night", + "T_DSL" + ], + [ + "R1-R2", + 2030, + "winter", + "night", + "E_TRANS" + ], + [ + "R2", + 2030, + "summer", + "night", + "S_IMPURN" + ], + [ + "R1", + 2020, + "summer", + "night", + "E_SOLPV" + ], + [ + "R1", + 2030, + "winter", + "night", + "S_OILREF" + ], + [ + "R2", + 2030, + "summer", + "day", + "E_SOLPV" + ], + [ + "R2", + 2020, + "winter", + "night", + "R_NGH" + ], + [ + "R1", + 2020, + "fall", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2020, + "spring", + "day", + "T_GSL" + ], + [ + "R1", + 2020, + "summer", + "day", + "T_GSL" + ], + [ + "R2", + 2020, + "fall", + "night", + "S_IMPETH" + ], + [ + "R2", + 2030, + "fall", + "day", + "E_NUCLEAR" + ], + [ + "R2", + 2030, + "spring", + "night", + "S_IMPOIL" + ], + [ + "R2", + 2030, + "spring", + "day", + "E_NGCC" + ], + [ + "R2", + 2020, + "spring", + "night", + "S_IMPETH" + ], + [ + "R1-R2", + 2030, + "spring", + "day", + "E_TRANS" + ], + [ + "R1", + 2030, + "winter", + "night", + "E_NUCLEAR" + ], + [ + "R2", + 2020, + "fall", + "night", + "E_SOLPV" + ], + [ + "R1", + 2020, + "spring", + "day", + "T_BLND" + ], + [ + "R1", + 2020, + "summer", + "day", + "T_BLND" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_GSL" + ], + [ + "R2", + 2020, + "fall", + "day", + "S_OILREF" + ], + [ + "R1", + 2030, + "spring", + "day", + "S_OILREF" + ], + [ + "R1", + 2025, + "summer", + "day", + "S_IMPETH" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_GSL" + ], + [ + "R1", + 2030, + "spring", + "night", + "S_IMPNG" + ], + [ + "R1", + 2020, + "fall", + "night", + "E_BATT" + ], + [ + "R1", + 2030, + "spring", + "night", + "S_OILREF" + ], + [ + "R2", + 2030, + "fall", + "day", + "E_BATT" + ], + [ + "R1", + 2025, + "winter", + "night", + "T_DSL" + ], + [ + "R2", + 2020, + "spring", + "day", + "S_IMPOIL" + ], + [ + "R1", + 2030, + "spring", + "day", + "E_NUCLEAR" + ], + [ + "R2", + 2020, + "fall", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "winter", + "night", + "E_BATT" + ], + [ + "R1", + 2030, + "fall", + "night", + "S_IMPURN" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_BLND" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_BLND" + ], + [ + "R2-R1", + 2025, + "summer", + "night", + "E_TRANS" + ], + [ + "R1", + 2030, + "fall", + "day", + "E_SOLPV" + ], + [ + "R1", + 2025, + "spring", + "day", + "T_DSL" + ], + [ + "R2", + 2020, + "spring", + "day", + "T_GSL" + ], + [ + "R1", + 2025, + "summer", + "night", + "S_IMPURN" + ], + [ + "R1", + 2030, + "spring", + "day", + "E_BATT" + ], + [ + "R2", + 2020, + "fall", + "day", + "E_BATT" + ], + [ + "R1", + 2025, + "winter", + "day", + "T_GSL" + ], + [ + "R2", + 2020, + "spring", + "day", + "T_BLND" + ], + [ + "R2", + 2025, + "fall", + "night", + "S_IMPURN" + ], + [ + "R2", + 2025, + "spring", + "day", + "S_IMPETH" + ], + [ + "R1", + 2020, + "fall", + "day", + "S_IMPETH" + ], + [ + "R1", + 2025, + "spring", + "night", + "S_IMPURN" + ], + [ + "R2", + 2030, + "summer", + "night", + "S_IMPETH" + ], + [ + "R1", + 2020, + "fall", + "day", + "E_SOLPV" + ], + [ + "R2-R1", + 2030, + "fall", + "night", + "E_TRANS" + ], + [ + "R2", + 2030, + "fall", + "day", + "E_NGCC" + ], + [ + "R1", + 2020, + "spring", + "day", + "S_OILREF" + ], + [ + "R1", + 2020, + "summer", + "day", + "S_IMPNG" + ], + [ + "R1", + 2020, + "summer", + "day", + "S_OILREF" + ], + [ + "R1", + 2025, + "summer", + "night", + "R_EH" + ], + [ + "R2", + 2030, + "winter", + "day", + "R_EH" + ], + [ + "R1", + 2030, + "winter", + "day", + "E_SOLPV" + ], + [ + "R1", + 2020, + "summer", + "night", + "S_IMPOIL" + ], + [ + "R2", + 2030, + "summer", + "day", + "S_IMPOIL" + ], + [ + "R2", + 2020, + "winter", + "night", + "T_EV" + ], + [ + "R1", + 2020, + "spring", + "day", + "E_NUCLEAR" + ], + [ + "R2", + 2030, + "fall", + "night", + "S_OILREF" + ], + [ + "R2", + 2025, + "fall", + "night", + "R_EH" + ], + [ + "R2", + 2025, + "winter", + "night", + "E_SOLPV" + ], + [ + "R2", + 2030, + "spring", + "night", + "S_OILREF" + ], + [ + "R2", + 2025, + "spring", + "night", + "R_EH" + ], + [ + "R2", + 2025, + "winter", + "day", + "T_GSL" + ], + [ + "R2", + 2020, + "fall", + "night", + "S_IMPOIL" + ], + [ + "R2", + 2030, + "spring", + "night", + "S_IMPNG" + ], + [ + "R2", + 2030, + "spring", + "day", + "S_IMPURN" + ], + [ + "R1", + 2030, + "fall", + "night", + "S_IMPETH" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_GSL" + ], + [ + "R2", + 2030, + "fall", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "summer", + "day", + "R_EH" + ], + [ + "R2", + 2020, + "summer", + "night", + "R_NGH" + ], + [ + "R1", + 2020, + "spring", + "day", + "E_BATT" + ], + [ + "R1", + 2030, + "fall", + "night", + "E_SOLPV" + ], + [ + "R1", + 2020, + "summer", + "night", + "T_BLND" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_BLND" + ], + [ + "R1", + 2020, + "winter", + "night", + "T_EV" + ], + [ + "R1", + 2025, + "summer", + "night", + "S_IMPETH" + ], + [ + "R2", + 2020, + "spring", + "day", + "S_OILREF" + ], + [ + "R2", + 2020, + "spring", + "day", + "S_IMPNG" + ], + [ + "R1", + 2025, + "fall", + "night", + "S_IMPNG" + ], + [ + "R2", + 2025, + "summer", + "night", + "R_EH" + ], + [ + "R1", + 2025, + "fall", + "day", + "S_IMPURN" + ], + [ + "R2", + 2030, + "fall", + "night", + "E_BATT" + ], + [ + "R2", + 2030, + "spring", + "night", + "E_BATT" + ], + [ + "R1", + 2025, + "winter", + "night", + "E_SOLPV" + ], + [ + "R2", + 2020, + "winter", + "day", + "E_NGCC" + ], + [ + "R2", + 2020, + "fall", + "night", + "T_BLND" + ], + [ + "R1", + 2025, + "spring", + "night", + "S_IMPETH" + ], + [ + "R1", + 2030, + "fall", + "day", + "T_GSL" + ], + [ + "R1", + 2025, + "winter", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2025, + "spring", + "day", + "E_SOLPV" + ], + [ + "R1", + 2025, + "spring", + "night", + "E_SOLPV" + ], + [ + "R2", + 2025, + "fall", + "day", + "S_IMPNG" + ], + [ + "R2", + 2020, + "spring", + "day", + "E_BATT" + ], + [ + "R1", + 2030, + "fall", + "day", + "T_BLND" + ], + [ + "R1", + 2025, + "fall", + "day", + "R_EH" + ], + [ + "R1", + 2020, + "spring", + "night", + "S_IMPNG" + ], + [ + "R2", + 2020, + "winter", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2020, + "winter", + "day", + "T_DSL" + ], + [ + "R1", + 2020, + "fall", + "day", + "S_IMPOIL" + ], + [ + "R2", + 2030, + "summer", + "night", + "S_IMPOIL" + ], + [ + "R1", + 2025, + "winter", + "day", + "E_BATT" + ], + [ + "R2-R1", + 2030, + "summer", + "day", + "E_TRANS" + ], + [ + "R1", + 2020, + "fall", + "night", + "S_IMPURN" + ], + [ + "R1", + 2030, + "winter", + "day", + "S_IMPOIL" + ], + [ + "R2", + 2030, + "spring", + "day", + "S_IMPETH" + ], + [ + "R2", + 2025, + "winter", + "day", + "S_OILREF" + ], + [ + "R1", + 2030, + "winter", + "night", + "S_IMPURN" + ], + [ + "R2", + 2025, + "summer", + "day", + "S_IMPNG" + ], + [ + "R2", + 2030, + "winter", + "night", + "R_EH" + ], + [ + "R1", + 2020, + "summer", + "night", + "S_IMPNG" + ], + [ + "R2", + 2025, + "winter", + "night", + "S_IMPOIL" + ], + [ + "R2", + 2030, + "spring", + "day", + "E_SOLPV" + ], + [ + "R2", + 2030, + "summer", + "day", + "S_OILREF" + ], + [ + "R2-R1", + 2020, + "spring", + "night", + "E_TRANS" + ], + [ + "R2", + 2025, + "winter", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_GSL" + ], + [ + "R1", + 2020, + "winter", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2020, + "fall", + "day", + "T_BLND" + ], + [ + "R2", + 2030, + "summer", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "spring", + "day", + "S_IMPURN" + ], + [ + "R2", + 2020, + "fall", + "day", + "S_IMPURN" + ], + [ + "R2", + 2020, + "summer", + "night", + "T_EV" + ], + [ + "R2", + 2020, + "fall", + "night", + "S_IMPNG" + ], + [ + "R1", + 2025, + "fall", + "day", + "S_IMPETH" + ], + [ + "R1", + 2030, + "spring", + "night", + "S_IMPURN" + ], + [ + "R1", + 2030, + "fall", + "night", + "S_IMPOIL" + ], + [ + "R2", + 2020, + "spring", + "night", + "S_IMPNG" + ], + [ + "R2", + 2020, + "winter", + "day", + "T_DSL" + ], + [ + "R2", + 2025, + "winter", + "night", + "T_GSL" + ], + [ + "R2", + 2030, + "winter", + "night", + "T_DSL" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_BLND" + ], + [ + "R2", + 2025, + "winter", + "day", + "E_BATT" + ], + [ + "R2-R1", + 2025, + "fall", + "day", + "E_TRANS" + ], + [ + "R1", + 2025, + "summer", + "day", + "S_IMPNG" + ], + [ + "R1", + 2030, + "summer", + "night", + "R_EH" + ], + [ + "R2", + 2030, + "summer", + "day", + "E_BATT" + ], + [ + "R2", + 2025, + "winter", + "night", + "T_BLND" + ], + [ + "R1", + 2025, + "winter", + "night", + "S_IMPOIL" + ], + [ + "R1", + 2030, + "fall", + "day", + "S_OILREF" + ], + [ + "R1", + 2025, + "winter", + "day", + "E_NGCC" + ], + [ + "R1-R2", + 2020, + "winter", + "day", + "E_TRANS" + ], + [ + "R1", + 2030, + "spring", + "night", + "R_EH" + ], + [ + "R1", + 2030, + "fall", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_BLND" + ], + [ + "R2", + 2020, + "winter", + "night", + "E_NGCC" + ], + [ + "R1", + 2025, + "spring", + "day", + "S_IMPOIL" + ], + [ + "R2", + 2020, + "summer", + "day", + "T_DSL" + ], + [ + "R1", + 2025, + "winter", + "night", + "T_GSL" + ], + [ + "R1", + 2025, + "spring", + "night", + "S_IMPOIL" + ], + [ + "R1", + 2025, + "summer", + "night", + "R_NGH" + ], + [ + "R1", + 2020, + "fall", + "night", + "S_IMPETH" + ], + [ + "R2", + 2030, + "winter", + "day", + "R_NGH" + ], + [ + "R2", + 2030, + "fall", + "day", + "S_IMPETH" + ], + [ + "R1", + 2025, + "winter", + "night", + "T_BLND" + ], + [ + "R1", + 2030, + "fall", + "day", + "E_BATT" + ], + [ + "R1", + 2030, + "winter", + "night", + "S_IMPETH" + ], + [ + "R1", + 2025, + "spring", + "day", + "T_GSL" + ], + [ + "R2", + 2030, + "fall", + "day", + "E_SOLPV" + ], + [ + "R2", + 2025, + "spring", + "day", + "S_IMPNG" + ], + [ + "R2", + 2025, + "fall", + "night", + "R_NGH" + ], + [ + "R1", + 2020, + "fall", + "day", + "S_IMPNG" + ], + [ + "R1", + 2020, + "spring", + "day", + "S_IMPURN" + ], + [ + "R1", + 2020, + "summer", + "day", + "S_IMPURN" + ], + [ + "R1-R2", + 2030, + "winter", + "day", + "E_TRANS" + ], + [ + "R2", + 2025, + "spring", + "night", + "R_NGH" + ], + [ + "R2", + 2030, + "summer", + "night", + "S_IMPNG" + ], + [ + "R2", + 2025, + "winter", + "day", + "E_NGCC" + ], + [ + "R1", + 2025, + "spring", + "day", + "T_BLND" + ], + [ + "R1", + 2020, + "winter", + "night", + "E_NGCC" + ], + [ + "R1", + 2025, + "spring", + "night", + "T_BLND" + ], + [ + "R1", + 2030, + "winter", + "day", + "S_IMPNG" + ], + [ + "R2", + 2030, + "spring", + "day", + "S_IMPOIL" + ], + [ + "R1", + 2030, + "spring", + "day", + "S_IMPETH" + ], + [ + "R2", + 2020, + "fall", + "day", + "S_IMPETH" + ], + [ + "R1", + 2030, + "spring", + "night", + "S_IMPETH" + ], + [ + "R1", + 2030, + "winter", + "day", + "S_OILREF" + ], + [ + "R1", + 2030, + "summer", + "day", + "R_NGH" + ], + [ + "R2", + 2030, + "fall", + "night", + "S_IMPURN" + ], + [ + "R2", + 2030, + "spring", + "night", + "S_IMPURN" + ], + [ + "R2", + 2025, + "winter", + "night", + "S_OILREF" + ], + [ + "R2", + 2025, + "summer", + "night", + "R_NGH" + ], + [ + "R2", + 2025, + "winter", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2020, + "summer", + "day", + "R_EH" + ], + [ + "R1", + 2030, + "fall", + "night", + "S_IMPNG" + ], + [ + "R1", + 2030, + "winter", + "day", + "E_BATT" + ], + [ + "R2", + 2020, + "spring", + "day", + "S_IMPURN" + ], + [ + "R2", + 2030, + "spring", + "day", + "T_BLND" + ], + [ + "R2", + 2020, + "winter", + "night", + "T_DSL" + ], + [ + "R1", + 2030, + "fall", + "day", + "E_NGCC" + ], + [ + "R2", + 2020, + "winter", + "day", + "E_SOLPV" + ], + [ + "R2", + 2025, + "winter", + "night", + "E_BATT" + ], + [ + "R1", + 2025, + "winter", + "night", + "S_OILREF" + ], + [ + "R1", + 2025, + "fall", + "day", + "R_NGH" + ], + [ + "R1", + 2025, + "winter", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2025, + "summer", + "night", + "T_EV" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_EV" + ], + [ + "R1", + 2025, + "spring", + "day", + "S_OILREF" + ], + [ + "R1", + 2020, + "spring", + "day", + "S_IMPETH" + ], + [ + "R1", + 2020, + "summer", + "day", + "S_IMPETH" + ], + [ + "R1", + 2025, + "fall", + "night", + "R_EH" + ], + [ + "R1", + 2025, + "spring", + "night", + "S_IMPNG" + ], + [ + "R1", + 2020, + "winter", + "night", + "T_DSL" + ], + [ + "R2", + 2030, + "fall", + "day", + "S_IMPOIL" + ], + [ + "R1", + 2025, + "spring", + "day", + "E_NUCLEAR" + ], + [ + "R2", + 2020, + "summer", + "night", + "E_NGCC" + ], + [ + "R2", + 2025, + "fall", + "night", + "T_EV" + ], + [ + "R1", + 2025, + "winter", + "night", + "E_BATT" + ], + [ + "R2-R1", + 2030, + "fall", + "day", + "E_TRANS" + ], + [ + "R2", + 2030, + "fall", + "night", + "S_IMPETH" + ], + [ + "R2", + 2025, + "spring", + "night", + "T_EV" + ], + [ + "R1", + 2030, + "winter", + "night", + "S_IMPOIL" + ], + [ + "R2", + 2030, + "spring", + "night", + "S_IMPETH" + ], + [ + "R2", + 2025, + "winter", + "day", + "S_IMPURN" + ], + [ + "R1", + 2030, + "summer", + "day", + "T_EV" + ], + [ + "R2", + 2025, + "fall", + "day", + "R_EH" + ], + [ + "R1", + 2025, + "spring", + "day", + "E_BATT" + ], + [ + "R2", + 2030, + "summer", + "day", + "S_IMPURN" + ], + [ + "R2", + 2030, + "spring", + "day", + "S_IMPNG" + ], + [ + "R1", + 2030, + "spring", + "day", + "S_IMPOIL" + ], + [ + "R1", + 2020, + "spring", + "night", + "R_EH" + ], + [ + "R1", + 2020, + "winter", + "day", + "T_GSL" + ], + [ + "R2", + 2025, + "summer", + "night", + "T_EV" + ], + [ + "R2", + 2030, + "fall", + "day", + "T_BLND" + ], + [ + "R2", + 2020, + "spring", + "day", + "S_IMPETH" + ], + [ + "R1-R2", + 2025, + "summer", + "night", + "E_TRANS" + ], + [ + "R2", + 2025, + "summer", + "day", + "R_EH" + ], + [ + "R2-R1", + 2025, + "fall", + "night", + "E_TRANS" + ], + [ + "R1", + 2030, + "spring", + "night", + "R_NGH" + ], + [ + "R1", + 2020, + "summer", + "night", + "R_EH" + ], + [ + "R1", + 2025, + "winter", + "day", + "E_SOLPV" + ], + [ + "R1", + 2030, + "fall", + "day", + "S_IMPURN" + ], + [ + "R2", + 2020, + "fall", + "night", + "R_EH" + ], + [ + "R2", + 2020, + "winter", + "night", + "E_SOLPV" + ], + [ + "R2", + 2020, + "spring", + "night", + "R_EH" + ], + [ + "R2", + 2020, + "winter", + "day", + "T_GSL" + ], + [ + "R2", + 2020, + "summer", + "night", + "T_DSL" + ], + [ + "R1", + 2025, + "summer", + "day", + "R_EH" + ], + [ + "R1-R2", + 2020, + "fall", + "night", + "E_TRANS" + ], + [ + "R2", + 2020, + "winter", + "day", + "T_BLND" + ], + [ + "R2", + 2025, + "winter", + "day", + "S_IMPETH" + ], + [ + "R2", + 2030, + "winter", + "night", + "T_EV" + ], + [ + "R2", + 2030, + "summer", + "day", + "S_IMPETH" + ], + [ + "R1", + 2020, + "fall", + "night", + "S_IMPNG" + ], + [ + "R2-R1", + 2025, + "spring", + "night", + "E_TRANS" + ], + [ + "R2", + 2030, + "fall", + "day", + "S_OILREF" + ], + [ + "R2", + 2030, + "fall", + "day", + "S_IMPNG" + ], + [ + "R2", + 2025, + "winter", + "day", + "E_SOLPV" + ], + [ + "R2", + 2030, + "fall", + "night", + "S_IMPOIL" + ], + [ + "R1", + 2020, + "winter", + "night", + "E_SOLPV" + ], + [ + "R1", + 2030, + "winter", + "day", + "S_IMPURN" + ], + [ + "R1", + 2030, + "winter", + "night", + "S_IMPNG" + ], + [ + "R1", + 2020, + "winter", + "day", + "S_OILREF" + ], + [ + "R1", + 2020, + "summer", + "day", + "R_NGH" + ], + [ + "R2", + 2025, + "winter", + "night", + "S_IMPURN" + ], + [ + "R1", + 2020, + "winter", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "summer", + "night", + "T_EV" + ], + [ + "R1", + 2030, + "spring", + "day", + "S_IMPNG" + ], + [ + "R2", + 2020, + "summer", + "day", + "T_EV" + ], + [ + "R2", + 2020, + "fall", + "day", + "S_IMPNG" + ], + [ + "R2", + 2025, + "spring", + "day", + "R_EH" + ], + [ + "R1", + 2020, + "fall", + "day", + "R_EH" + ], + [ + "R2", + 2030, + "spring", + "night", + "R_NGH" + ], + [ + "R2", + 2030, + "summer", + "night", + "R_EH" + ], + [ + "R1", + 2030, + "fall", + "day", + "S_IMPETH" + ], + [ + "R2-R1", + 2030, + "winter", + "night", + "E_TRANS" + ], + [ + "R2", + 2030, + "winter", + "day", + "E_NGCC" + ], + [ + "R1", + 2020, + "winter", + "day", + "E_BATT" + ], + [ + "R1", + 2030, + "spring", + "night", + "T_EV" + ], + [ + "R2-R1", + 2025, + "summer", + "day", + "E_TRANS" + ], + [ + "R1", + 2025, + "winter", + "day", + "S_IMPOIL" + ], + [ + "R2", + 2020, + "winter", + "day", + "S_OILREF" + ], + [ + "R1", + 2025, + "winter", + "night", + "S_IMPURN" + ], + [ + "R2-R1", + 2030, + "spring", + "day", + "E_TRANS" + ], + [ + "R2", + 2025, + "spring", + "night", + "E_NGCC" + ], + [ + "R2", + 2020, + "winter", + "night", + "S_IMPOIL" + ], + [ + "R2", + 2020, + "spring", + "day", + "R_NGH" + ], + [ + "R1", + 2025, + "fall", + "night", + "R_NGH" + ], + [ + "R2", + 2030, + "winter", + "night", + "E_NUCLEAR" + ], + [ + "R2", + 2020, + "winter", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "summer", + "day", + "E_NGCC" + ], + [ + "R1", + 2030, + "fall", + "night", + "R_EH" + ], + [ + "R1", + 2025, + "spring", + "day", + "S_IMPURN" + ], + [ + "R1-R2", + 2020, + "summer", + "day", + "E_TRANS" + ], + [ + "R2", + 2020, + "winter", + "night", + "T_GSL" + ], + [ + "R1", + 2025, + "winter", + "day", + "T_BLND" + ], + [ + "R2", + 2020, + "summer", + "night", + "E_SOLPV" + ], + [ + "R1", + 2030, + "winter", + "day", + "S_IMPETH" + ], + [ + "R2", + 2020, + "winter", + "day", + "E_BATT" + ], + [ + "R2", + 2025, + "fall", + "day", + "R_NGH" + ], + [ + "R2-R1", + 2020, + "fall", + "day", + "E_TRANS" + ], + [ + "R1", + 2020, + "spring", + "day", + "S_IMPNG" + ], + [ + "R2", + 2025, + "winter", + "day", + "S_IMPOIL" + ], + [ + "R2", + 2020, + "winter", + "night", + "T_BLND" + ], + [ + "R2-R1", + 2020, + "spring", + "day", + "E_TRANS" + ], + [ + "R1", + 2020, + "winter", + "night", + "S_IMPOIL" + ], + [ + "R1", + 2020, + "spring", + "night", + "R_NGH" + ], + [ + "R2", + 2025, + "winter", + "night", + "S_IMPETH" + ], + [ + "R1", + 2030, + "summer", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2020, + "winter", + "day", + "E_NGCC" + ], + [ + "R2", + 2020, + "summer", + "day", + "E_NUCLEAR" + ], + [ + "R2", + 2030, + "fall", + "night", + "S_IMPNG" + ], + [ + "R1", + 2025, + "spring", + "night", + "R_EH" + ], + [ + "R1", + 2025, + "summer", + "night", + "T_DSL" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_DSL" + ], + [ + "R1", + 2020, + "winter", + "night", + "T_GSL" + ], + [ + "R2", + 2025, + "summer", + "day", + "R_NGH" + ], + [ + "R2", + 2020, + "summer", + "day", + "E_BATT" + ], + [ + "R1", + 2020, + "summer", + "night", + "R_NGH" + ], + [ + "R1-R2", + 2025, + "fall", + "night", + "E_TRANS" + ], + [ + "R2", + 2025, + "winter", + "day", + "T_BLND" + ], + [ + "R2", + 2025, + "fall", + "night", + "T_DSL" + ], + [ + "R1", + 2020, + "winter", + "night", + "T_BLND" + ], + [ + "R2", + 2025, + "spring", + "night", + "T_DSL" + ], + [ + "R1", + 2025, + "winter", + "night", + "S_IMPETH" + ], + [ + "R1", + 2030, + "fall", + "day", + "S_IMPOIL" + ], + [ + "R2-R1", + 2030, + "spring", + "night", + "E_TRANS" + ], + [ + "R2", + 2020, + "fall", + "night", + "R_NGH" + ], + [ + "R2", + 2020, + "spring", + "night", + "R_NGH" + ], + [ + "R1", + 2030, + "summer", + "day", + "T_DSL" + ], + [ + "R2", + 2030, + "winter", + "night", + "E_NGCC" + ], + [ + "R2", + 2030, + "spring", + "day", + "R_EH" + ], + [ + "R1", + 2025, + "winter", + "day", + "S_OILREF" + ], + [ + "R1", + 2025, + "winter", + "day", + "S_IMPNG" + ], + [ + "R1", + 2025, + "fall", + "night", + "T_EV" + ], + [ + "R1", + 2025, + "spring", + "day", + "S_IMPETH" + ], + [ + "R1", + 2025, + "summer", + "day", + "R_NGH" + ], + [ + "R2", + 2025, + "summer", + "night", + "T_DSL" + ], + [ + "R2", + 2020, + "winter", + "night", + "S_OILREF" + ], + [ + "R2", + 2020, + "winter", + "night", + "S_IMPNG" + ], + [ + "R2", + 2020, + "summer", + "night", + "S_IMPOIL" + ], + [ + "R1", + 2030, + "summer", + "night", + "E_NGCC" + ], + [ + "R2", + 2020, + "summer", + "day", + "E_NGCC" + ], + [ + "R2", + 2025, + "fall", + "day", + "T_EV" + ], + [ + "R2", + 2030, + "fall", + "day", + "S_IMPURN" + ], + [ + "R1", + 2020, + "spring", + "night", + "T_EV" + ], + [ + "R1", + 2025, + "fall", + "day", + "T_DSL" + ], + [ + "R2", + 2020, + "winter", + "night", + "E_BATT" + ], + [ + "R2", + 2020, + "summer", + "night", + "T_GSL" + ], + [ + "R2", + 2025, + "winter", + "day", + "S_IMPNG" + ], + [ + "R1", + 2020, + "winter", + "day", + "S_IMPURN" + ], + [ + "R1", + 2020, + "winter", + "night", + "S_IMPNG" + ], + [ + "R1", + 2020, + "winter", + "night", + "S_OILREF" + ], + [ + "R2", + 2025, + "spring", + "day", + "R_NGH" + ], + [ + "R2", + 2030, + "summer", + "day", + "S_IMPNG" + ], + [ + "R1", + 2020, + "fall", + "day", + "R_NGH" + ], + [ + "R2", + 2030, + "summer", + "night", + "R_NGH" + ], + [ + "R2", + 2020, + "summer", + "night", + "T_BLND" + ], + [ + "R2", + 2025, + "summer", + "day", + "T_EV" + ], + [ + "R1", + 2030, + "winter", + "day", + "R_NGH" + ], + [ + "R1", + 2020, + "summer", + "night", + "T_EV" + ], + [ + "R1-R2", + 2025, + "summer", + "day", + "E_TRANS" + ], + [ + "R1", + 2020, + "fall", + "night", + "R_EH" + ], + [ + "R2", + 2030, "fall", "day", "R_EH" ], [ "R2", + 2030, + "winter", + "day", + "E_SOLPV" + ], + [ + "R1-R2", + 2030, + "summer", + "night", + "E_TRANS" + ], + [ + "R2", + 2020, + "fall", + "night", + "T_EV" + ], + [ + "R1", + 2020, + "winter", + "night", + "E_BATT" + ], + [ + "R1", + 2030, + "winter", + "night", + "R_EH" + ], + [ + "R2", + 2020, + "spring", + "night", + "T_EV" + ], + [ + "R1", + 2030, "fall", "day", - "T_EV" + "S_IMPNG" ], [ "R2", - "summer", + 2020, + "winter", "day", - "E_SOLPV" + "S_IMPURN" ], [ "R2", - "summer", + 2025, + "spring", "night", - "S_IMPETH" + "E_SOLPV" ], [ "R1", - "summer", + 2030, + "fall", "night", - "T_BLND" + "R_NGH" ], [ - "R2", - "spring", + "R1", + 2025, + "summer", "day", - "R_NGH" + "T_EV" ], [ "R1", - "winter", - "night", - "S_IMPURN" + 2030, + "spring", + "day", + "R_EH" ], [ "R2", - "summer", + 2020, + "fall", "day", + "R_EH" + ], + [ + "R1", + 2030, + "summer", + "night", "T_DSL" ], [ "R1", - "fall", + 2030, + "summer", "day", - "S_IMPURN" + "E_SOLPV" ], [ - "R1", - "winter", + "R1-R2", + 2020, + "summer", "night", - "S_IMPOIL" + "E_TRANS" ], [ "R1", - "fall", - "day", - "S_IMPOIL" + 2030, + "spring", + "night", + "T_DSL" ], [ "R1", + 2020, "winter", "day", - "S_OILREF" + "S_IMPETH" ], [ "R2", - "winter", - "day", - "T_BLND" + 2020, + "summer", + "night", + "S_OILREF" + ], + [ + "R2-R1", + 2020, + "fall", + "night", + "E_TRANS" ], [ "R1", + 2025, "spring", "night", - "T_GSL" + "R_NGH" ], [ - "R2", + "R1", + 2020, "winter", "day", - "S_IMPURN" + "E_SOLPV" ], [ - "R1", + "R2", + 2020, "summer", "night", "E_NUCLEAR" ], + [ + "R2", + 2025, + "spring", + "day", + "T_EV" + ], [ "R1", - "winter", + 2020, + "fall", + "day", + "T_EV" + ], + [ + "R2", + 2030, + "summer", "night", "T_EV" ], + [ + "R2", + 2025, + "winter", + "night", + "S_IMPNG" + ], [ "R1", + 2025, "fall", "night", - "R_NGH" + "E_NGCC" + ], + [ + "R2", + 2020, + "summer", + "night", + "E_BATT" ], [ "R1", - "fall", + 2020, + "spring", "day", "R_EH" ], [ - "R1", - "fall", + "R2", + 2030, + "winter", "day", - "T_EV" + "S_IMPOIL" ], [ - "R1", - "summer", + "R2", + 2030, + "spring", "day", - "E_SOLPV" + "R_NGH" + ], + [ + "R2-R1", + 2030, + "winter", + "day", + "E_TRANS" + ], + [ + "R2", + 2020, + "winter", + "day", + "S_IMPETH" ], [ "R2", + 2030, "fall", "night", - "T_GSL" + "R_EH" ], [ "R2", + 2030, "winter", - "day", + "night", + "E_SOLPV" + ], + [ + "R2", + 2030, + "spring", + "night", + "R_EH" + ], + [ + "R2", + 2025, + "spring", + "night", "S_IMPOIL" ], [ "R1", + 2020, + "summer", + "day", + "T_DSL" + ], + [ + "R2", + 2025, "fall", "day", - "S_IMPETH" + "E_NGCC" ], [ "R1", + 2025, "summer", + "night", + "T_GSL" + ], + [ + "R1", + 2025, + "winter", "day", - "T_DSL" + "S_IMPURN" ], [ - "R2", + "R1", + 2025, "winter", "night", - "R_NGH" + "S_IMPNG" ], [ "R2", + 2030, "winter", "day", - "R_EH" + "T_GSL" ], [ - "R2", + "R1", + 2030, "fall", "night", - "S_IMPURN" + "T_EV" ], [ - "R2-R1", - "summer", + "R1", + 2020, + "spring", "night", - "E_TRANS" + "E_NGCC" ], [ - "R2", - "spring", + "R1", + 2030, + "summer", "day", - "T_BLND" + "S_IMPOIL" ], [ "R2", + 2030, "winter", "day", - "S_IMPETH" + "T_BLND" ], [ "R2", - "spring", - "day", + 2025, + "fall", + "night", + "T_GSL" + ], + [ + "R2", + 2020, + "winter", + "night", "S_IMPURN" ], [ "R2", - "fall", + 2025, + "spring", "night", - "S_IMPOIL" + "T_GSL" ], [ "R1", - "winter", + 2025, + "spring", + "day", + "S_IMPNG" + ], + [ + "R2", + 2020, + "spring", "day", - "T_BLND" + "R_EH" ], [ "R1", - "spring", + 2030, + "summer", "night", - "T_EV" + "E_SOLPV" ], [ "R2", + 2025, "summer", "day", "E_NGCC" ], [ - "R2", - "fall", + "R1", + 2030, + "summer", "day", - "S_OILREF" + "T_GSL" ], [ "R2", - "spring", + 2020, + "summer", "day", - "S_IMPOIL" - ], - [ - "R2", - "fall", - "night", - "T_EV" + "E_SOLPV" ], [ - "R2", - "summer", + "R2-R1", + 2025, + "winter", "night", - "E_SOLPV" + "E_TRANS" ], [ "R2", + 2025, "spring", "night", - "R_NGH" + "T_BLND" ], [ "R1", + 2025, "winter", "day", - "E_NUCLEAR" - ], - [ - "R2", - "spring", - "day", "R_EH" ], [ - "R2", - "summer", - "night", - "T_DSL" + "R1-R2", + 2020, + "fall", + "day", + "E_TRANS" ], [ "R1", - "fall", + 2025, + "spring", "night", - "S_IMPURN" + "T_EV" ], [ - "R2", + "R1-R2", + 2020, "spring", "day", - "S_IMPETH" + "E_TRANS" ], [ "R1", + 2020, "winter", "day", - "S_IMPETH" + "S_IMPOIL" ], [ - "R1", + "R2", + 2025, + "summer", + "night", + "T_GSL" + ], + [ + "R2", + 2020, "spring", "day", - "T_BLND" + "T_DSL" ], [ "R1", + 2025, "fall", "night", - "S_IMPOIL" + "T_DSL" ], [ - "R2", - "winter", - "night", + "R1", + 2030, + "summer", + "day", "T_BLND" ], [ - "R2", + "R1", + 2020, "winter", "night", "S_IMPURN" ], [ - "R1", - "fall", - "day", - "S_OILREF" - ], - [ - "R2", - "fall", + "R2-R1", + 2025, + "spring", "day", - "T_BLND" + "E_TRANS" ], [ "R2", - "winter", + 2020, + "spring", "night", - "S_IMPOIL" + "E_NGCC" ], [ "R1", + 2020, "fall", "night", - "R_EH" + "R_NGH" ], [ - "R1", + "R2", + 2030, "fall", - "night", - "T_EV" + "day", + "R_NGH" ], [ "R1", + 2025, "summer", + "day", + "E_NGCC" + ], + [ + "R1", + 2030, + "winter", "night", - "E_SOLPV" + "R_NGH" ], [ "R2", - "summer", + 2030, + "spring", "day", - "T_GSL" + "T_EV" + ], + [ + "R2", + 2025, + "fall", + "day", + "T_DSL" + ], + [ + "R1-R2", + 2030, + "fall", + "day", + "E_TRANS" ], [ "R1", - "spring", + 2020, + "winter", "day", - "E_NUCLEAR" + "T_BLND" ], [ - "R2", + "R1", + 2025, "winter", "day", - "S_OILREF" + "S_IMPETH" ], [ "R2", - "summer", + 2030, + "winter", "day", - "S_IMPNG" + "S_OILREF" ], [ "R1", - "summer", + 2020, + "spring", "night", "T_DSL" ], [ "R2", + 2025, "winter", - "night", + "day", "R_EH" ], [ "R1", + 2030, "spring", "day", - "S_IMPETH" + "R_NGH" ], [ "R2", + 2020, "fall", "day", - "E_NUCLEAR" + "R_NGH" ], [ "R2", - "summer", - "day", - "E_BATT" + 2030, + "winter", + "night", + "S_IMPOIL" ], [ - "R2-R1", + "R2", + 2020, "winter", "day", - "E_TRANS" + "S_IMPOIL" + ], + [ + "R2", + 2030, + "summer", + "day", + "R_EH" ], [ "R2", + 2020, "winter", "night", "S_IMPETH" ], [ - "R2", - "spring", + "R1", + 2025, + "summer", "night", - "S_IMPURN" + "E_NUCLEAR" ], [ - "R1", + "R2", + 2030, "winter", - "night", - "T_BLND" + "day", + "E_NUCLEAR" ], [ "R2", + 2025, + "fall", + "night", + "S_OILREF" + ], + [ + "R1", + 2025, "fall", "day", - "S_IMPETH" + "T_EV" ], [ "R2", - "winter", + 2025, + "spring", + "night", + "S_OILREF" + ], + [ + "R2", + 2025, + "summer", "day", "T_DSL" ], [ "R2", - "summer", + 2030, + "winter", "night", - "E_NGCC" + "T_GSL" ], [ "R1", + 2020, + "summer", + "night", + "T_DSL" + ], + [ + "R2", + 2025, "fall", + "night", + "E_NUCLEAR" + ], + [ + "R2", + 2025, + "spring", "day", - "T_BLND" + "E_NGCC" ], [ "R2", + 2025, "spring", "night", - "S_IMPOIL" + "E_NUCLEAR" ], [ "R1", + 2025, "summer", - "day", - "T_GSL" + "night", + "E_BATT" ], [ "R2", - "spring", + 2030, + "winter", "day", - "S_OILREF" + "E_BATT" ], [ "R1", + 2030, "summer", "day", - "S_IMPNG" + "S_OILREF" + ], + [ + "R2", + 2030, + "summer", + "night", + "E_NGCC" ], [ "R1", - "winter", + 2030, + "summer", "night", - "E_NUCLEAR" + "S_IMPOIL" ], [ "R2", - "spring", + 2030, + "winter", "night", - "T_EV" + "T_BLND" ], [ "R2", - "spring", + 2020, + "fall", "night", - "R_EH" + "T_DSL" ], [ - "R1", - "winter", - "night", - "R_EH" + "R2", + 2020, + "summer", + "day", + "S_IMPOIL" ], [ "R1", - "fall", + 2030, + "summer", "day", "E_NUCLEAR" ], [ - "R1", + "R2", + 2025, "summer", - "day", - "E_BATT" + "night", + "S_OILREF" ], [ "R2", + 2020, "spring", "night", - "S_IMPETH" + "T_DSL" ], [ "R1", - "winter", + 2030, + "fall", "day", - "E_SOLPV" + "R_EH" ], [ "R1", + 2020, "winter", "night", "S_IMPETH" ], [ - "R1", - "spring", + "R2", + 2025, + "fall", "night", - "T_BLND" + "E_BATT" ], [ - "R1", - "spring", + "R2", + 2020, + "summer", "night", "S_IMPURN" ], [ "R2", + 2025, "spring", - "day", - "T_DSL" + "night", + "E_BATT" + ], + [ + "R2", + 2025, + "summer", + "night", + "E_NUCLEAR" ], [ "R1", - "winter", + 2025, + "summer", "day", "T_DSL" ], [ "R1", + 2030, "summer", "night", - "E_NGCC" + "T_GSL" ], [ "R2", + 2020, + "summer", + "day", + "T_GSL" + ], + [ + "R1", + 2020, "winter", "day", - "E_NUCLEAR" + "S_IMPNG" + ], + [ + "R1", + 2030, + "summer", + "day", + "E_BATT" ], [ "R1", + 2020, "fall", "night", - "S_OILREF" + "T_EV" ], [ "R2", + 2030, "fall", - "night", - "T_BLND" + "day", + "T_EV" ], [ - "R1", + "R1-R2", + 2020, "spring", "night", - "S_IMPOIL" + "E_TRANS" ], [ "R1", + 2020, "spring", "day", - "S_OILREF" - ], - [ - "R2-R1", - "fall", - "day", - "E_TRANS" + "R_NGH" ], [ - "R2", + "R1", + 2030, "summer", "night", - "T_GSL" + "T_BLND" ], [ "R2", - "winter", - "night", - "S_OILREF" + 2020, + "summer", + "day", + "T_BLND" ], [ "R1", - "spring", + 2025, + "fall", "night", - "R_EH" + "E_SOLPV" ], [ - "R2", + "R1", + 2030, "winter", - "day", - "E_NGCC" + "night", + "T_EV" ], [ "R2", + 2025, "summer", "night", - "S_IMPNG" - ], - [ - "R1", - "spring", - "day", - "E_SOLPV" + "E_BATT" ], [ "R1", + 2030, "spring", "night", - "S_IMPETH" + "T_GSL" ], [ "R2", + 2030, "fall", "night", - "E_NUCLEAR" + "R_NGH" ], [ - "R2", + "R1", + 2025, "summer", "night", - "E_BATT" + "E_NGCC" ], [ - "R2", + "R1", + 2025, "fall", - "night", - "R_EH" - ], - [ - "R2-R1", - "winter", - "night", - "E_TRANS" - ], - [ - "R2", - "summer", "day", - "R_NGH" + "E_NUCLEAR" ], [ "R1", + 2030, "spring", "day", - "T_DSL" + "T_EV" ], [ "R2", - "spring", + 2020, + "fall", "day", - "E_NUCLEAR" + "T_EV" ], [ - "R2", + "R1-R2", + 2025, "fall", "day", - "E_SOLPV" + "E_TRANS" ], [ - "R2", - "fall", - "night", - "S_IMPETH" + "R1", + 2030, + "winter", + "day", + "R_EH" ], [ "R2", - "winter", - "night", + 2025, + "spring", + "day", "T_DSL" ], - [ - "R1", - "fall", - "night", - "T_BLND" - ], [ "R2", + 2025, "fall", "day", - "T_DSL" + "E_SOLPV" ], [ "R1", - "summer", - "night", - "T_GSL" + 2020, + "fall", + "day", + "T_DSL" ], [ "R2", - "spring", - "day", + 2025, + "fall", + "night", "E_NGCC" ], [ - "R1", + "R2", + 2030, "winter", "night", "S_OILREF" - ], - [ - "R1", - "summer", - "night", - "S_IMPNG" - ], - [ - "R1", - "winter", - "day", - "E_NGCC" ] ], "LifetimeProcess_rtv": [ diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index ad622e191..781dfcc4c 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -33,11 +33,16 @@ 2000, 2010 ], - "time_season": [ + "time_season_all": [ "inter", "summer", "winter" ], + "time_season": [ + 1990, + 2000, + 2010 + ], "time_of_day": [ "day", "night" @@ -190,688 +195,2398 @@ "co2", "nox" ], - "CapacityFactor_rsdt": [ + "CapacityFactor_rpsdt": [ [ "utopia", - "inter", - "night", - "E21" + 2000, + "winter", + "day", + "SRE" ], [ "utopia", - "inter", + 1990, + "winter", "day", - "IMPFEQ" + "IMPURN1" ], [ "utopia", + 2000, "inter", - "night", - "IMPGSL1" + "day", + "IMPOIL1" ], [ "utopia", + 2000, "summer", - "day", - "E51" + "night", + "TXD" ], [ "utopia", - "inter", + 2000, + "winter", "night", - "RL1" + "IMPURN1" ], [ "utopia", - "winter", + 2000, + "summer", "night", - "E31" + "E70" ], [ "utopia", + 2010, "summer", "day", - "E31" + "TXG" ], [ "utopia", - "winter", - "night", - "TXD" + 2000, + "inter", + "day", + "E51" ], [ "utopia", - "summer", + 2000, + "inter", "day", - "TXD" + "RL1" ], [ "utopia", + 2000, "summer", - "night", - "IMPHCO1" + "day", + "IMPFEQ" ], [ "utopia", + 1990, "inter", "day", - "E01" + "RHE" ], [ "utopia", + 1990, "summer", - "night", + "day", "SRE" ], [ "utopia", - "inter", - "night", - "E31" + 2010, + "winter", + "day", + "TXG" ], [ "utopia", + 1990, "inter", + "day", + "IMPDSL1" + ], + [ + "utopia", + 2010, + "summer", "night", - "TXD" + "IMPHYD" ], [ "utopia", + 2010, "summer", "night", "E21" ], [ "utopia", + 1990, "winter", "night", - "IMPFEQ" + "IMPGSL1" ], [ "utopia", - "summer", - "day", - "IMPFEQ" + 2010, + "inter", + "night", + "RHE" ], [ "utopia", + 2000, "winter", "day", - "E51" + "E01" ], [ "utopia", - "winter", + 2000, + "summer", "day", + "SRE" + ], + [ + "utopia", + 1990, + "summer", + "night", + "TXG" + ], + [ + "utopia", + 2010, + "inter", + "night", "IMPDSL1" ], [ "utopia", + 2000, "winter", "day", - "IMPURN1" + "IMPHYD" ], [ "utopia", - "winter", + 2010, + "inter", "day", "RHO" ], [ "utopia", - "inter", - "night", - "IMPFEQ" + 2010, + "winter", + "day", + "IMPURN1" ], [ "utopia", - "inter", + 2000, + "winter", "day", - "E51" + "E21" ], [ "utopia", + 2000, "inter", "day", - "IMPURN1" + "IMPGSL1" ], [ "utopia", - "winter", + 2010, + "summer", "night", - "E01" + "IMPOIL1" ], [ "utopia", - "winter", + 1990, + "summer", "day", - "E70" + "E01" ], [ "utopia", - "winter", - "day", - "TXE" + 2000, + "summer", + "night", + "TXG" ], [ "utopia", + 1990, "summer", - "night", - "E31" + "day", + "IMPHYD" ], [ "utopia", + 1990, "summer", "night", - "TXD" + "IMPURN1" ], [ "utopia", - "inter", + 2010, + "winter", "night", - "E01" + "RHE" ], [ "utopia", + 1990, "inter", + "day", + "E31" + ], + [ + "utopia", + 2010, + "summer", "night", - "SRE" + "E51" ], [ "utopia", - "inter", + 1990, + "summer", "day", - "E70" + "E21" ], [ "utopia", + 2000, "winter", "day", "IMPOIL1" ], [ "utopia", - "summer", + 2010, + "winter", "night", - "IMPFEQ" + "IMPDSL1" ], [ "utopia", - "winter", + 1990, + "inter", "night", - "E51" + "RHO" ], [ "utopia", - "summer", + 2010, + "inter", "day", - "IMPDSL1" + "IMPFEQ" + ], + [ + "utopia", + 1990, + "winter", + "day", + "IMPHCO1" ], [ "utopia", + 2000, "summer", "day", - "IMPURN1" + "E01" ], [ "utopia", + 2000, "winter", "night", - "IMPURN1" + "IMPHCO1" ], [ "utopia", - "summer", + 2000, + "winter", "day", - "RHO" - ], - [ - "utopia", - "inter", - "night", "E51" ], [ "utopia", + 2000, "summer", - "night", - "E01" + "day", + "IMPHYD" ], [ "utopia", + 2000, "winter", "day", - "IMPHYD" + "RL1" ], [ "utopia", - "winter", + 2000, + "summer", "night", - "E70" + "IMPURN1" ], [ "utopia", - "summer", - "day", - "E70" + 2010, + "inter", + "night", + "E31" ], [ "utopia", + 2000, "summer", "day", - "TXE" + "E21" ], [ "utopia", + 2000, "inter", "day", - "IMPHYD" + "RHE" ], [ "utopia", - "winter", + 2000, + "inter", "night", - "IMPOIL1" + "RHO" ], [ "utopia", + 1990, "summer", "day", "IMPOIL1" ], [ "utopia", - "summer", - "night", - "E51" - ], - [ - "utopia", + 2000, "inter", "day", "IMPDSL1" ], [ "utopia", - "summer", - "night", - "IMPDSL1" - ], - [ - "utopia", - "summer", - "night", - "IMPURN1" - ], - [ - "utopia", + 2010, "inter", "day", - "RHO" + "SRE" ], [ "utopia", + 1990, "inter", "day", - "TXE" - ], - [ - "utopia", - "winter", - "night", - "IMPHYD" + "TXD" ], [ "utopia", + 1990, "summer", "day", - "IMPHYD" + "E51" ], [ "utopia", + 1990, "summer", - "night", - "E70" + "day", + "RL1" ], [ "utopia", - "winter", + 1990, + "inter", "day", - "TXG" + "E70" ], [ "utopia", + 1990, "inter", "night", - "IMPHYD" + "IMPFEQ" ], [ "utopia", - "inter", + 2000, + "summer", "day", - "TXG" + "IMPOIL1" ], [ "utopia", + 1990, "winter", "day", - "IMPGSL1" + "TXE" ], [ "utopia", - "inter", + 2010, + "summer", "day", - "IMPOIL1" + "IMPHCO1" ], [ "utopia", + 2010, "winter", "night", - "IMPDSL1" - ], - [ - "utopia", - "summer", - "night", - "IMPOIL1" + "E31" ], [ "utopia", + 2000, "winter", "night", - "RHO" - ], - [ - "utopia", - "winter", - "day", - "RL1" - ], - [ - "utopia", - "inter", - "day", - "IMPGSL1" + "TXE" ], [ "utopia", + 2010, "inter", "night", - "IMPDSL1" + "TXD" ], [ "utopia", + 2010, "inter", "night", - "IMPURN1" + "E70" ], [ "utopia", - "inter", - "night", - "RHO" + 2000, + "summer", + "day", + "E51" ], [ "utopia", + 2000, "winter", "night", - "TXE" + "RHO" ], [ "utopia", - "inter", - "night", - "E70" + 2000, + "summer", + "day", + "RL1" ], [ "utopia", + 2000, "inter", "night", - "TXE" + "IMPFEQ" ], [ "utopia", + 2010, "winter", "day", - "RHE" + "IMPHCO1" ], [ "utopia", - "summer", - "night", - "IMPHYD" + 2000, + "winter", + "day", + "IMPGSL1" ], [ "utopia", - "winter", + 1990, + "inter", "night", - "TXG" + "SRE" ], [ "utopia", - "summer", + 2000, + "inter", "day", - "TXG" + "E31" ], [ "utopia", + 2010, "inter", "day", - "RHE" + "E01" ], [ "utopia", - "winter", + 1990, + "summer", "night", - "IMPGSL1" + "IMPHCO1" ], [ "utopia", + 2010, "summer", - "day", - "IMPGSL1" + "night", + "RHE" ], [ "utopia", + 2010, "inter", - "night", - "IMPOIL1" + "day", + "IMPHYD" ], [ "utopia", + 1990, "summer", - "night", - "RHO" + "day", + "IMPGSL1" ], [ "utopia", + 2010, "winter", "night", - "RL1" + "TXD" ], [ "utopia", - "summer", - "day", - "RL1" + 2000, + "inter", + "night", + "SRE" ], [ "utopia", - "winter", + 2010, + "inter", "day", - "IMPHCO1" + "E21" ], [ "utopia", + 2010, "summer", "night", - "TXE" + "IMPDSL1" ], [ "utopia", - "winter", + 2010, + "summer", "day", - "E01" + "RHO" ], [ "utopia", - "winter", - "day", - "SRE" + 2000, + "summer", + "night", + "IMPHCO1" ], [ "utopia", - "inter", + 2000, + "summer", "day", - "IMPHCO1" + "IMPGSL1" ], [ "utopia", + 2000, "winter", - "night", - "RHE" + "day", + "IMPDSL1" ], [ "utopia", - "summer", + 2010, + "winter", "day", - "RHE" + "RHO" ], [ "utopia", - "winter", - "day", - "E21" + 1990, + "inter", + "night", + "E01" ], [ "utopia", + 2000, "inter", "day", - "SRE" + "TXD" ], [ "utopia", - "summer", + 1990, + "inter", "night", - "TXG" + "IMPHYD" ], [ "utopia", + 2010, "inter", "night", - "RHE" + "TXG" ], [ "utopia", + 2010, "inter", "day", - "E21" + "IMPOIL1" ], [ "utopia", - "summer", + 1990, + "inter", "night", - "IMPGSL1" + "E21" ], [ "utopia", + 1990, "inter", "day", - "RL1" + "IMPURN1" ], [ "utopia", + 1990, "summer", "night", - "RL1" + "RHO" ], [ "utopia", + 1990, "winter", "night", - "IMPHCO1" - ], - [ - "utopia", - "winter", - "day", - "E31" + "IMPHYD" ], [ "utopia", - "summer", + 2010, + "inter", "day", - "IMPHCO1" + "E51" ], [ "utopia", - "winter", + 2010, + "inter", "day", - "TXD" + "RL1" ], [ "utopia", + 2010, "summer", "day", - "E01" + "IMPFEQ" ], [ "utopia", - "winter", + 2000, + "inter", "night", - "SRE" + "E01" ], [ "utopia", + 1990, "summer", "day", - "SRE" + "IMPDSL1" ], [ "utopia", - "inter", + 2010, + "summer", "night", - "IMPHCO1" + "E31" + ], + [ + "utopia", + 2000, + "inter", + "night", + "IMPHYD" + ], + [ + "utopia", + 2010, + "winter", + "day", + "IMPFEQ" + ], + [ + "utopia", + 2010, + "inter", + "night", + "IMPURN1" + ], + [ + "utopia", + 2000, + "inter", + "night", + "E21" + ], + [ + "utopia", + 2000, + "summer", + "night", + "RHO" + ], + [ + "utopia", + 1990, + "inter", + "night", + "IMPOIL1" + ], + [ + "utopia", + 1990, + "winter", + "day", + "TXG" + ], + [ + "utopia", + 2000, + "summer", + "day", + "IMPDSL1" + ], + [ + "utopia", + 2000, + "winter", + "day", + "E31" + ], + [ + "utopia", + 2010, + "summer", + "day", + "SRE" + ], + [ + "utopia", + 1990, + "winter", + "day", + "E01" + ], + [ + "utopia", + 1990, + "inter", + "night", + "E51" + ], + [ + "utopia", + 1990, + "inter", + "night", + "RL1" + ], + [ + "utopia", + 1990, + "summer", + "night", + "IMPFEQ" + ], + [ + "utopia", + 2000, + "winter", + "night", + "E01" + ], + [ + "utopia", + 2000, + "inter", + "night", + "IMPOIL1" + ], + [ + "utopia", + 2010, + "summer", + "night", + "TXD" + ], + [ + "utopia", + 2010, + "inter", + "day", + "IMPGSL1" + ], + [ + "utopia", + 1990, + "summer", + "day", + "E31" + ], + [ + "utopia", + 2010, + "winter", + "night", + "IMPURN1" + ], + [ + "utopia", + 2000, + "winter", + "night", + "E21" + ], + [ + "utopia", + 2010, + "summer", + "night", + "E70" + ], + [ + "utopia", + 2000, + "inter", + "night", + "E51" + ], + [ + "utopia", + 2000, + "inter", + "night", + "RL1" + ], + [ + "utopia", + 2000, + "summer", + "night", + "IMPFEQ" + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXD" + ], + [ + "utopia", + 2000, + "summer", + "day", + "E31" + ], + [ + "utopia", + 2010, + "summer", + "day", + "E01" + ], + [ + "utopia", + 2000, + "inter", + "day", + "IMPURN1" + ], + [ + "utopia", + 1990, + "inter", + "night", + "IMPGSL1" + ], + [ + "utopia", + 1990, + "inter", + "day", + "IMPHCO1" + ], + [ + "utopia", + 1990, + "winter", + "day", + "RL1" + ], + [ + "utopia", + 2010, + "summer", + "day", + "E21" + ], + [ + "utopia", + 2010, + "winter", + "day", + "E01" + ], + [ + "utopia", + 2000, + "winter", + "night", + "E51" + ], + [ + "utopia", + 2000, + "winter", + "night", + "RL1" + ], + [ + "utopia", + 2010, + "inter", + "day", + "IMPDSL1" + ], + [ + "utopia", + 2010, + "winter", + "day", + "E21" + ], + [ + "utopia", + 2010, + "inter", + "night", + "IMPHCO1" + ], + [ + "utopia", + 2000, + "inter", + "night", + "IMPGSL1" + ], + [ + "utopia", + 1990, + "summer", + "night", + "E01" + ], + [ + "utopia", + 2010, + "summer", + "day", + "IMPOIL1" + ], + [ + "utopia", + 1990, + "summer", + "night", + "E21" + ], + [ + "utopia", + 1990, + "inter", + "day", + "TXE" + ], + [ + "utopia", + 2010, + "summer", + "day", + "E51" + ], + [ + "utopia", + 2010, + "summer", + "day", + "RL1" + ], + [ + "utopia", + 2010, + "winter", + "day", + "IMPOIL1" + ], + [ + "utopia", + 2000, + "summer", + "night", + "E01" + ], + [ + "utopia", + 1990, + "inter", + "night", + "IMPDSL1" + ], + [ + "utopia", + 1990, + "winter", + "night", + "RHE" + ], + [ + "utopia", + 1990, + "winter", + "day", + "IMPGSL1" + ], + [ + "utopia", + 2010, + "winter", + "night", + "IMPHCO1" + ], + [ + "utopia", + 2000, + "winter", + "night", + "IMPGSL1" + ], + [ + "utopia", + 1990, + "winter", + "night", + "IMPDSL1" + ], + [ + "utopia", + 2010, + "winter", + "day", + "E51" + ], + [ + "utopia", + 2010, + "winter", + "day", + "RL1" + ], + [ + "utopia", + 2010, + "summer", + "night", + "IMPURN1" + ], + [ + "utopia", + 2000, + "summer", + "night", + "E21" + ], + [ + "utopia", + 2010, + "inter", + "day", + "E31" + ], + [ + "utopia", + 2010, + "inter", + "night", + "TXE" + ], + [ + "utopia", + 1990, + "summer", + "night", + "IMPOIL1" + ], + [ + "utopia", + 2000, + "inter", + "night", + "IMPDSL1" + ], + [ + "utopia", + 1990, + "summer", + "night", + "E51" + ], + [ + "utopia", + 2000, + "winter", + "day", + "IMPURN1" + ], + [ + "utopia", + 1990, + "summer", + "night", + "RL1" + ], + [ + "utopia", + 2000, + "inter", + "day", + "IMPHCO1" + ], + [ + "utopia", + 2000, + "summer", + "night", + "IMPOIL1" + ], + [ + "utopia", + 2010, + "summer", + "day", + "IMPGSL1" + ], + [ + "utopia", + 1990, + "inter", + "night", + "E31" + ], + [ + "utopia", + 2010, + "winter", + "night", + "TXE" + ], + [ + "utopia", + 2000, + "summer", + "night", + "E51" + ], + [ + "utopia", + 2000, + "summer", + "night", + "RL1" + ], + [ + "utopia", + 1990, + "summer", + "day", + "IMPURN1" + ], + [ + "utopia", + 2010, + "inter", + "day", + "TXD" + ], + [ + "utopia", + 1990, + "winter", + "night", + "TXE" + ], + [ + "utopia", + 1990, + "winter", + "night", + "E31" + ], + [ + "utopia", + 1990, + "winter", + "day", + "RHO" + ], + [ + "utopia", + 2010, + "winter", + "day", + "IMPGSL1" + ], + [ + "utopia", + 2000, + "inter", + "night", + "E31" + ], + [ + "utopia", + 2000, + "summer", + "day", + "IMPURN1" + ], + [ + "utopia", + 2000, + "inter", + "day", + "TXE" + ], + [ + "utopia", + 1990, + "summer", + "night", + "IMPGSL1" + ], + [ + "utopia", + 1990, + "winter", + "day", + "IMPFEQ" + ], + [ + "utopia", + 2010, + "winter", + "night", + "E70" + ], + [ + "utopia", + 1990, + "winter", + "night", + "TXD" + ], + [ + "utopia", + 2000, + "winter", + "night", + "IMPFEQ" + ], + [ + "utopia", + 2000, + "summer", + "night", + "IMPGSL1" + ], + [ + "utopia", + 1990, + "winter", + "night", + "E70" + ], + [ + "utopia", + 2010, + "summer", + "night", + "IMPHCO1" + ], + [ + "utopia", + 1990, + "inter", + "day", + "TXG" + ], + [ + "utopia", + 2000, + "winter", + "day", + "RHE" + ], + [ + "utopia", + 1990, + "inter", + "day", + "E01" + ], + [ + "utopia", + 2000, + "winter", + "day", + "IMPHCO1" + ], + [ + "utopia", + 1990, + "winter", + "day", + "SRE" + ], + [ + "utopia", + 2000, + "inter", + "day", + "E70" + ], + [ + "utopia", + 2000, + "winter", + "night", + "SRE" + ], + [ + "utopia", + 1990, + "summer", + "day", + "RHE" + ], + [ + "utopia", + 2010, + "inter", + "night", + "E01" + ], + [ + "utopia", + 2010, + "summer", + "day", + "E31" + ], + [ + "utopia", + 2010, + "summer", + "night", + "TXE" + ], + [ + "utopia", + 2010, + "inter", + "night", + "E21" + ], + [ + "utopia", + 2010, + "inter", + "day", + "IMPURN1" + ], + [ + "utopia", + 2000, + "summer", + "day", + "RHE" + ], + [ + "utopia", + 2010, + "winter", + "night", + "TXG" + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXE" + ], + [ + "utopia", + 1990, + "winter", + "night", + "TXG" + ], + [ + "utopia", + 1990, + "inter", + "day", + "RL1" + ], + [ + "utopia", + 2010, + "winter", + "night", + "E01" + ], + [ + "utopia", + 1990, + "winter", + "day", + "IMPHYD" + ], + [ + "utopia", + 2010, + "winter", + "day", + "SRE" + ], + [ + "utopia", + 1990, + "inter", + "night", + "IMPURN1" + ], + [ + "utopia", + 2000, + "winter", + "night", + "IMPHYD" + ], + [ + "utopia", + 1990, + "winter", + "day", + "E21" + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXE" + ], + [ + "utopia", + 2010, + "inter", + "night", + "E51" + ], + [ + "utopia", + 2010, + "inter", + "night", + "RL1" + ], + [ + "utopia", + 2000, + "inter", + "day", + "TXG" + ], + [ + "utopia", + 1990, + "winter", + "night", + "IMPURN1" + ], + [ + "utopia", + 1990, + "summer", + "night", + "SRE" + ], + [ + "utopia", + 2000, + "inter", + "night", + "IMPURN1" + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXE" + ], + [ + "utopia", + 2000, + "winter", + "day", + "E70" + ], + [ + "utopia", + 1990, + "winter", + "day", + "IMPOIL1" + ], + [ + "utopia", + 2000, + "winter", + "night", + "IMPOIL1" + ], + [ + "utopia", + 1990, + "inter", + "day", + "IMPGSL1" + ], + [ + "utopia", + 2010, + "summer", + "day", + "IMPHYD" + ], + [ + "utopia", + 2010, + "winter", + "night", + "RL1" + ], + [ + "utopia", + 2000, + "summer", + "night", + "SRE" + ], + [ + "utopia", + 1990, + "winter", + "day", + "E51" + ], + [ + "utopia", + 2010, + "inter", + "day", + "RHE" + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXD" + ], + [ + "utopia", + 1990, + "summer", + "day", + "E70" + ], + [ + "utopia", + 2010, + "winter", + "day", + "IMPHYD" + ], + [ + "utopia", + 2010, + "inter", + "night", + "IMPGSL1" + ], + [ + "utopia", + 2010, + "inter", + "day", + "IMPHCO1" + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXD" + ], + [ + "utopia", + 1990, + "summer", + "night", + "IMPHYD" + ], + [ + "utopia", + 2010, + "summer", + "night", + "TXG" + ], + [ + "utopia", + 2000, + "summer", + "day", + "E70" + ], + [ + "utopia", + 2010, + "summer", + "night", + "E01" + ], + [ + "utopia", + 1990, + "inter", + "night", + "RHE" + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXG" + ], + [ + "utopia", + 2010, + "winter", + "night", + "IMPGSL1" + ], + [ + "utopia", + 1990, + "inter", + "night", + "IMPHCO1" + ], + [ + "utopia", + 1990, + "inter", + "day", + "RHO" + ], + [ + "utopia", + 2000, + "summer", + "night", + "IMPHYD" + ], + [ + "utopia", + 2010, + "summer", + "day", + "IMPURN1" + ], + [ + "utopia", + 2010, + "inter", + "day", + "TXE" + ], + [ + "utopia", + 1990, + "winter", + "night", + "IMPHCO1" + ], + [ + "utopia", + 2000, + "inter", + "night", + "RHE" + ], + [ + "utopia", + 2010, + "inter", + "night", + "RHO" + ], + [ + "utopia", + 2000, + "inter", + "night", + "IMPHCO1" + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXG" + ], + [ + "utopia", + 1990, + "inter", + "day", + "IMPFEQ" + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXE" + ], + [ + "utopia", + 1990, + "winter", + "day", + "RHE" + ], + [ + "utopia", + 2010, + "summer", + "night", + "RL1" + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXG" + ], + [ + "utopia", + 2000, + "winter", + "night", + "RHE" + ], + [ + "utopia", + 1990, + "winter", + "day", + "IMPDSL1" + ], + [ + "utopia", + 2000, + "winter", + "night", + "IMPDSL1" + ], + [ + "utopia", + 2010, + "winter", + "night", + "RHO" + ], + [ + "utopia", + 2010, + "inter", + "day", + "E70" + ], + [ + "utopia", + 2010, + "inter", + "night", + "IMPFEQ" + ], + [ + "utopia", + 1990, + "winter", + "night", + "RHO" + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXE" + ], + [ + "utopia", + 1990, + "inter", + "day", + "SRE" + ], + [ + "utopia", + 2000, + "inter", + "day", + "RHO" + ], + [ + "utopia", + 2010, + "summer", + "day", + "RHE" + ], + [ + "utopia", + 2010, + "inter", + "night", + "SRE" + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXD" + ], + [ + "utopia", + 1990, + "inter", + "night", + "E70" + ], + [ + "utopia", + 2010, + "winter", + "night", + "IMPFEQ" + ], + [ + "utopia", + 2010, + "summer", + "night", + "IMPGSL1" + ], + [ + "utopia", + 2010, + "summer", + "day", + "IMPDSL1" + ], + [ + "utopia", + 1990, + "winter", + "night", + "IMPFEQ" + ], + [ + "utopia", + 1990, + "winter", + "day", + "E31" + ], + [ + "utopia", + 2010, + "winter", + "day", + "RHE" + ], + [ + "utopia", + 2000, + "winter", + "night", + "E31" + ], + [ + "utopia", + 2010, + "winter", + "day", + "IMPDSL1" + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXD" + ], + [ + "utopia", + 2000, + "inter", + "night", + "E70" + ], + [ + "utopia", + 1990, + "summer", + "night", + "RHE" + ], + [ + "utopia", + 1990, + "inter", + "day", + "IMPHYD" + ], + [ + "utopia", + 2010, + "inter", + "day", + "TXG" + ], + [ + "utopia", + 2000, + "inter", + "day", + "IMPFEQ" + ], + [ + "utopia", + 2010, + "winter", + "night", + "SRE" + ], + [ + "utopia", + 1990, + "winter", + "night", + "SRE" + ], + [ + "utopia", + 1990, + "inter", + "day", + "E21" + ], + [ + "utopia", + 1990, + "summer", + "night", + "IMPDSL1" + ], + [ + "utopia", + 2010, + "summer", + "day", + "TXE" + ], + [ + "utopia", + 2010, + "inter", + "night", + "IMPHYD" + ], + [ + "utopia", + 1990, + "winter", + "day", + "TXD" + ], + [ + "utopia", + 2000, + "summer", + "night", + "RHE" + ], + [ + "utopia", + 1990, + "summer", + "day", + "IMPHCO1" + ], + [ + "utopia", + 1990, + "winter", + "day", + "E70" + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXD" ], [ "utopia", + 2000, + "winter", + "night", + "E70" + ], + [ + "utopia", + 2000, + "summer", + "night", + "IMPDSL1" + ], + [ + "utopia", + 2010, + "summer", + "night", + "RHO" + ], + [ + "utopia", + 2000, + "inter", + "day", + "SRE" + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXG" + ], + [ + "utopia", + 1990, "inter", "day", + "IMPOIL1" + ], + [ + "utopia", + 2010, + "winter", + "day", + "TXE" + ], + [ + "utopia", + 2010, + "winter", + "day", "E31" ], [ "utopia", + 2000, + "summer", + "day", + "IMPHCO1" + ], + [ + "utopia", + 1990, "inter", "day", - "TXD" + "E51" + ], + [ + "utopia", + 2000, + "winter", + "day", + "RHO" + ], + [ + "utopia", + 1990, + "winter", + "night", + "E01" ], [ "utopia", + 1990, "summer", "night", - "RHE" + "TXE" + ], + [ + "utopia", + 2010, + "inter", + "night", + "IMPOIL1" + ], + [ + "utopia", + 2010, + "winter", + "night", + "IMPHYD" + ], + [ + "utopia", + 1990, + "summer", + "night", + "E31" ], [ "utopia", + 2000, "inter", "night", "TXG" ], [ "utopia", + 2010, + "winter", + "night", + "E21" + ], + [ + "utopia", + 2010, + "summer", + "day", + "TXD" + ], + [ + "utopia", + 1990, "winter", "night", "E21" ], [ "utopia", + 2010, + "summer", + "day", + "E70" + ], + [ + "utopia", + 2010, + "summer", + "night", + "IMPFEQ" + ], + [ + "utopia", + 1990, + "summer", + "day", + "RHO" + ], + [ + "utopia", + 2000, + "summer", + "night", + "TXE" + ], + [ + "utopia", + 2000, + "inter", + "day", + "E01" + ], + [ + "utopia", + 2010, + "winter", + "day", + "TXD" + ], + [ + "utopia", + 2000, "summer", + "night", + "E31" + ], + [ + "utopia", + 2010, + "winter", + "day", + "E70" + ], + [ + "utopia", + 2000, + "inter", + "day", + "IMPHYD" + ], + [ + "utopia", + 2000, + "winter", + "day", + "IMPFEQ" + ], + [ + "utopia", + 2010, + "winter", + "night", + "IMPOIL1" + ], + [ + "utopia", + 2000, + "inter", "day", "E21" ], [ "utopia", + 2000, + "winter", + "night", + "TXG" + ], + [ + "utopia", + 1990, + "winter", + "night", + "IMPOIL1" + ], + [ + "utopia", + 2000, + "summer", + "day", + "RHO" + ], + [ + "utopia", + 2010, + "summer", + "night", + "SRE" + ], + [ + "utopia", + 1990, + "summer", + "night", + "TXD" + ], + [ + "utopia", + 1990, + "summer", + "night", + "E70" + ], + [ + "utopia", + 2010, + "winter", + "night", + "E51" + ], + [ + "utopia", + 1990, + "winter", + "night", + "E51" + ], + [ + "utopia", + 1990, "winter", + "night", + "RL1" + ], + [ + "utopia", + 1990, + "summer", "day", "IMPFEQ" ] From be61efeac9761da37be604c0fef7b7eb909c8db9 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Sat, 15 Mar 2025 14:23:05 -0400 Subject: [PATCH 055/587] Update a segfrac error message --- temoa/temoa_model/temoa_initialize.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index b0507cc7b..4abc20f13 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -196,12 +196,12 @@ def validate_SegFrac(M: 'TemoaModel'): extra = keys.difference(expected_keys) missing = expected_keys.difference(keys) msg = ( - 'TimeSegmentFraction elements for period {} do not match time_season and TimeOfDay.' + 'TimeSegmentFraction elements for period {} do not match PeriodSeasons and TimeOfDay.' '\n\nIndices missing from TimeSegmentFraction:\n{}' - '\n\nIndices in TimeSegmentFraction missing from time_season/TimeOfDay:\n{}' + '\n\nIndices in TimeSegmentFraction missing from PeriodSeasons/TimeOfDay:\n{}' ).format(p, missing, extra) logger.error(msg) - raise Exception(msg) + raise ValueError(msg) total = sum( M.SegFrac[k] From 78fc64a7ca454acea3e185141038b75f9ed76f48 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 17 Mar 2025 16:19:27 -0400 Subject: [PATCH 056/587] Fix a bug in the new database migrator --- temoa/utilities/db_migration_v3_to_v3_1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temoa/utilities/db_migration_v3_to_v3_1.py b/temoa/utilities/db_migration_v3_to_v3_1.py index 2a3a8bbc1..ee36a53b0 100644 --- a/temoa/utilities/db_migration_v3_to_v3_1.py +++ b/temoa/utilities/db_migration_v3_to_v3_1.py @@ -194,7 +194,7 @@ for rtl in data: lifetime_tech[rtl[0:2]] = rtl[2] data = cur.execute('SELECT region, tech, vintage, lifetime FROM LifetimeProcess').fetchall() lifetime_process = dict() -for rtvl in data: lifetime_tech[rtvl[0:3]] = rtvl[3] +for rtvl in data: lifetime_process[rtvl[0:3]] = rtvl[3] # add period indexing to seasonal tables print('\n --- Adding period index to some tables ---') From 603c36e8850a7ad9c6ce782f59a5871efee59574 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 20 Mar 2025 16:56:50 -0400 Subject: [PATCH 057/587] Tidy up --- data_files/temoa_schema_v3_1.sql | 36 ++++++++++++++++---------------- temoa/temoa_model/temoa_model.py | 2 -- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index 059c304eb..d6fbfab03 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -1037,35 +1037,35 @@ CREATE TABLE IF NOT EXISTS MaxActivityGroup notes TEXT, PRIMARY KEY (region, period, group_name) ); -CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" +CREATE TABLE IF NOT EXISTS MinSeasonalActivity ( - "region" TEXT + region TEXT REFERENCES Region (region), - "period" INTEGER + period INTEGER REFERENCES TimePeriod (period), - "season" TEXT + season TEXT REFERENCES TimeSeason (season), - "tech" TEXT + tech TEXT REFERENCES Technology (tech), - "min_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") + min_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY(region,period,season,tech) ); -CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" +CREATE TABLE IF NOT EXISTS MaxSeasonalActivity ( - "region" TEXT + region TEXT REFERENCES Region (region), - "period" INTEGER + period INTEGER REFERENCES TimePeriod (period), - "season" TEXT + season TEXT REFERENCES TimeSeason (season), - "tech" TEXT + tech TEXT REFERENCES Technology (tech), - "max_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") + max_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY(region,period,season,tech) ); CREATE TABLE IF NOT EXISTS RPSRequirement ( diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 2ee41034c..4af2008f3 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -562,12 +562,10 @@ def __init__(M, *args, **kwargs): M.FlowInStorage_rpsditvo = Set(dimen=8, initialize=FlowInStorageVariableIndices) M.V_FlowIn = Var(M.FlowInStorage_rpsditvo, domain=NonNegativeReals) - # Storage state at the BEGINNING of each time slice M.StorageLevel_rpsdtv = Set(dimen=6, initialize=StorageLevelVariableIndices) M.V_StorageLevel = Var(M.StorageLevel_rpsdtv, domain=NonNegativeReals) # Derived decision variables - M.CapacityVar_rptv = Set(dimen=4, initialize=CostFixedIndices) M.V_Capacity = Var(M.CapacityVar_rptv, domain=NonNegativeReals) From 66aa815c6148af4d050990760361ea2d505ce99b Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 20 Mar 2025 18:08:18 -0400 Subject: [PATCH 058/587] Fix CapacityFactorTechIndices --- temoa/temoa_model/temoa_initialize.py | 6 ++--- temoa/temoa_model/temoa_model.py | 35 ++++++++++++++------------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 4abc20f13..81d25193e 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1092,11 +1092,11 @@ def CapacityFactorProcessIndices(M: 'TemoaModel'): def CapacityFactorTechIndices(M: 'TemoaModel'): - processes = set((r, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) all_cfs = set( (r, p, s, d, t) - for p in M.time_optimize - for (r, t, v), s, d in cross_product(processes, M.time_season[p], M.time_of_day) + for r, p, t in M.activeCapacityAvailable_rpt + for s in M.time_season[p] + for d in M.time_of_day ) return all_cfs diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 4af2008f3..f5bb407a9 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -296,23 +296,6 @@ def __init__(M, *args, **kwargs): default=1, ) - M.CapacityFactor_rpsdt = Set(dimen=5, initialize=CapacityFactorTechIndices) - M.CapacityFactorTech = Param(M.CapacityFactor_rpsdt, default=1, validate=validate_0to1) - - # Dev note: using a default function below alleviates need to make this set. - # M.CapacityFactor_rsdtv = Set(dimen=5, initialize=CapacityFactorProcessIndices) - M.CapacityFactorProcess = Param( - M.regionalIndices, - M.time_optimize, - M.time_season_all, - M.time_of_day, - M.tech_with_capacity, - M.vintage_all, - # validate=validate_CapacityFactorProcess, # opting for a quicker validation, just 0->1 - validate=validate_0to1, - default=get_default_capacity_factor, # surprisingly slow but only called if a value is missing - ) - M.LifetimeTech = Param( M.regionalIndices, M.tech_all, default=TemoaModel.default_lifetime_tech ) @@ -352,6 +335,24 @@ def __init__(M, *args, **kwargs): # equations below. M.Create_SparseDicts = BuildAction(rule=CreateSparseDicts) M.Create_StateSequence = BuildAction(rule=CreateStateSequence) + + M.CapacityFactor_rpsdt = Set(dimen=5, initialize=CapacityFactorTechIndices) + M.CapacityFactorTech = Param(M.CapacityFactor_rpsdt, default=1, validate=validate_0to1) + + # Dev note: using a default function below alleviates need to make this set. + # M.CapacityFactor_rsdtv = Set(dimen=5, initialize=CapacityFactorProcessIndices) + M.CapacityFactorProcess = Param( + M.regionalIndices, + M.time_optimize, + M.time_season_all, + M.time_of_day, + M.tech_with_capacity, + M.vintage_all, + # validate=validate_CapacityFactorProcess, # opting for a quicker validation, just 0->1 + validate=validate_0to1, + default=get_default_capacity_factor, # surprisingly slow but only called if a value is missing + ) + M.CapacityConstraint_rpsdtv = Set(dimen=6, initialize=CapacityConstraintIndices) M.initialize_CapacityFactors = BuildAction(rule=CheckCapacityFactorProcess) M.initialize_EfficiencyVariable = BuildAction(rule=CheckEfficiencyVariable) From 4e48ca8a731aa63dd55b5ce02c9c014459353264 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 22 Apr 2025 11:55:05 -0400 Subject: [PATCH 059/587] Fix bug initializing TechOutputSplitAnnual dict --- temoa/temoa_model/temoa_initialize.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 81d25193e..d8e936ed3 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -882,7 +882,7 @@ def CreateSparseDicts(M: 'TemoaModel'): if (r, p, t, o) in M.MinTechOutputSplit.sparse_iterkeys(): M.minOutputSplitVintages[r, p, t, o].add(v) if (r, p, t, o) in M.MinTechOutputSplitAnnual.sparse_iterkeys(): - M.minInputSplitAnnualVintages[r, p, t, o].add(v) + M.minOutputSplitAnnualVintages[r, p, t, o].add(v) # max tech split if (r, p, i, t) in M.MaxTechInputSplit.sparse_iterkeys(): @@ -892,7 +892,7 @@ def CreateSparseDicts(M: 'TemoaModel'): if (r, p, t, o) in M.MaxTechOutputSplit.sparse_iterkeys(): M.maxOutputSplitVintages[r, p, t, o].add(v) if (r, p, t, o) in M.MaxTechOutputSplitAnnual.sparse_iterkeys(): - M.maxInputSplitAnnualVintages[r, p, t, o].add(v) + M.maxOutputSplitAnnualVintages[r, p, t, o].add(v) if t in M.tech_resource: M.processByPeriodAndOutput[r, p, o].add((i, t, v)) From 82ebec37f0b3ca5a23e0437974324a289c8033d4 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 22 Apr 2025 16:49:10 -0400 Subject: [PATCH 060/587] Add error check for baseload annual technologies --- temoa/temoa_model/temoa_initialize.py | 17 +++++++++++++++++ temoa/temoa_model/temoa_model.py | 1 + 2 files changed, 18 insertions(+) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index d8e936ed3..a5adfcc3b 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -121,6 +121,23 @@ def DemandConstraintErrorCheck(supply, r, p, s, d, dem): ) logger.error(msg) raise Exception(msg.format(dem, r, p, s, d)) + + +def validate_tech_sets(M: 'TemoaModel'): + """ + Check sets for any errors + """ + + # Baseload technologies cannot also be annual technologies + baseload_annual = M.tech_annual & M.tech_baseload + if baseload_annual: + msg = ( + 'The following technologies were added to both baseload and annual sets. ' + 'Annual technologies have no output variability by time slice so ' + f'there is no need to tag them as baseload:\n{list(baseload_annual)}' + ) + logger.error(msg) + raise ValueError(msg) def validate_time(M: 'TemoaModel'): diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index f5bb407a9..41c7f226d 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -180,6 +180,7 @@ def __init__(M, *args, **kwargs): # ensure there is no overlap flex <=> curtailable technologies M.check_flex_and_curtailment = BuildAction(rule=check_flex_curtail) M.tech_exchange = Set(within=M.tech_all) + M.validate_techs = BuildAction(rule=validate_tech_sets) # Define groups for technologies M.tech_group_names = Set() From 5c5f405ac1e3506d6d52ffcafd7e75e720755433 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 22 Apr 2025 16:51:10 -0400 Subject: [PATCH 061/587] Add back v3 migration support and make robust to excess columns --- data_files/temoa_schema_v3.sql | 921 ++++++++++++++++++++++++++ temoa/utilities/db_migration_to_v3.py | 27 +- 2 files changed, 942 insertions(+), 6 deletions(-) create mode 100644 data_files/temoa_schema_v3.sql diff --git a/data_files/temoa_schema_v3.sql b/data_files/temoa_schema_v3.sql new file mode 100644 index 000000000..a85c1e086 --- /dev/null +++ b/data_files/temoa_schema_v3.sql @@ -0,0 +1,921 @@ +PRAGMA foreign_keys= OFF; +BEGIN TRANSACTION; + +CREATE TABLE IF NOT EXISTS MetaData +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +REPLACE INTO MetaData +VALUES ('myopic_base_year', 2000, 'Base Year for Myopic Analysis'); +REPLACE INTO MetaData +VALUES ('DB_MAJOR', 3, 'DB major version number'); +REPLACE INTO MetaData +VALUES ('DB_MINOR', 0, 'DB minor version number'); + +CREATE TABLE IF NOT EXISTS MetaDataReal +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +REPLACE INTO MetaDataReal +VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); +REPLACE INTO MetaDataReal +VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in LoanRate table'); + +CREATE TABLE IF NOT EXISTS OutputDualVariable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE IF NOT EXISTS OutputObjective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE IF NOT EXISTS SectorLabel +( + sector TEXT, + PRIMARY KEY (sector) +); + +CREATE TABLE IF NOT EXISTS CapacityCredit +( + region TEXT, + period INTEGER, + tech TEXT, + vintage INTEGER, + credit REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage), + CHECK (credit >= 0 AND credit <= 1) +); +CREATE TABLE IF NOT EXISTS CapacityFactorProcess +( + region TEXT, + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, season, tod, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS CapacityFactorTech +( + region TEXT, + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + factor REAL, + notes TEXT, + PRIMARY KEY (region, season, tod, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS CapacityToActivity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + c2a REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS Commodity +( + name TEXT + PRIMARY KEY, + flag TEXT + REFERENCES CommodityType (label), + description TEXT +); +CREATE TABLE IF NOT EXISTS CommodityType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO CommodityType +VALUES ('p', 'physical commodity'); +REPLACE INTO CommodityType +VALUES ('e', 'emissions commodity'); +REPLACE INTO CommodityType +VALUES ('d', 'demand commodity'); +REPLACE INTO CommodityType +VALUES ('s', 'source commodity'); + +CREATE TABLE IF NOT EXISTS CostEmission +( + region TEXT + REFERENCES Region (region), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT NOT NULL + REFERENCES Commodity (name), + cost REAL NOT NULL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE IF NOT EXISTS CostFixed +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS CostInvest +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS CostVariable +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS Demand +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + commodity TEXT + REFERENCES Commodity (name), + demand REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, commodity) +); +CREATE TABLE IF NOT EXISTS DemandSpecificDistribution +( + region TEXT, + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + demand_name TEXT + REFERENCES Commodity (name), + dds REAL, + dds_notes TEXT, + PRIMARY KEY (region, season, tod, demand_name), + CHECK (dds >= 0 AND dds <= 1) +); +CREATE TABLE IF NOT EXISTS LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS Efficiency +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE IF NOT EXISTS EmissionActivity +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS ExistingCapacity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS TechGroup +( + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE IF NOT EXISTS GrowthRateMax +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS GrowthRateSeed +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + seed REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS LoanLifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS LifetimeProcess +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS LifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE IF NOT EXISTS MaxActivity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + max_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE IF NOT EXISTS MaxCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + max_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE IF NOT EXISTS MaxResource +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + max_res REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS MinActivity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + min_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE IF NOT EXISTS MaxCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + max_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE IF NOT EXISTS MinCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + min_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE IF NOT EXISTS MinCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + min_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE IF NOT EXISTS OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputFlowOut +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS PlanningReserveMargin +( + region TEXT + PRIMARY KEY + REFERENCES Region (region), + margin REAL +); +CREATE TABLE IF NOT EXISTS RampDown +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS RampUp +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS Region +( + region TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE IF NOT EXISTS TimeSegmentFraction +( + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + segfrac REAL, + notes TEXT, + PRIMARY KEY (season, tod), + CHECK (segfrac >= 0 AND segfrac <= 1) +); +CREATE TABLE IF NOT EXISTS StorageDuration +( + region TEXT, + tech TEXT, + duration REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS StorageInit +( + tech TEXT + PRIMARY KEY, + value REAL, + notes TEXT +); +CREATE TABLE IF NOT EXISTS TechnologyType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO TechnologyType +VALUES ('r', 'resource technology'); +REPLACE INTO TechnologyType +VALUES ('p', 'production technology'); +REPLACE INTO TechnologyType +VALUES ('pb', 'baseload production technology'); +REPLACE INTO TechnologyType +VALUES ('ps', 'storage production technology'); + +CREATE TABLE IF NOT EXISTS TechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE IF NOT EXISTS TechInputSplitAverage +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE IF NOT EXISTS TechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE IF NOT EXISTS TimeOfDay +( + sequence INTEGER UNIQUE, + tod TEXT + PRIMARY KEY +); +CREATE TABLE IF NOT EXISTS TimePeriod +( + sequence INTEGER UNIQUE, + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES TimePeriodType (label) +); +CREATE TABLE IF NOT EXISTS TimeSeason +( + sequence INTEGER UNIQUE, + season TEXT + PRIMARY KEY +); +CREATE TABLE IF NOT EXISTS TimePeriodType +( + label TEXT + PRIMARY KEY, + description TEXT +); +CREATE TABLE IF NOT EXISTS MaxActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE IF NOT EXISTS MaxCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE IF NOT EXISTS MaxAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + factor REAL, + source TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS MaxNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + max_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE IF NOT EXISTS MaxNewCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + max_new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE IF NOT EXISTS MaxNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE IF NOT EXISTS MinActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE IF NOT EXISTS MinAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + factor REAL, + source TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS MinCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE IF NOT EXISTS MinNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + min_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE IF NOT EXISTS MinNewCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + min_new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE IF NOT EXISTS MinNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE IF NOT EXISTS OutputEmission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS MinActivityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + min_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE IF NOT EXISTS EmissionLimit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE IF NOT EXISTS MaxActivityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + max_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); + +CREATE TABLE RPSRequirement +( + region TEXT NOT NULL + REFERENCES Region (region), + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech_group TEXT NOT NULL + REFERENCES TechGroup (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE TechGroupMember +( + group_name TEXT + REFERENCES TechGroup (group_name), + tech TEXT + REFERENCES Technology (tech), + PRIMARY KEY (group_name, tech) +); +CREATE TABLE IF NOT EXISTS Technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + variable INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES TechnologyType (label) +); +CREATE TABLE IF NOT EXISTS OutputCost +( + scenario TEXT, + region TEXT, + period INTEGER, + tech TEXT, + vintage INTEGER, + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES TimePeriod (period), + FOREIGN KEY (tech) REFERENCES Technology (tech) +); +COMMIT; +PRAGMA FOREIGN_KEYS = 1; + + diff --git a/temoa/utilities/db_migration_to_v3.py b/temoa/utilities/db_migration_to_v3.py index 9cbcb0920..a441049d2 100644 --- a/temoa/utilities/db_migration_to_v3.py +++ b/temoa/utilities/db_migration_to_v3.py @@ -48,10 +48,10 @@ ) parser.add_argument( '--schema', - help='Path to schema file (default=../../data_files/temoa_schema_v3.sql)', + help='Path to schema file (default=data_files/temoa_schema_v3.sql)', required=False, dest='schema', - default='../../data_files/temoa_schema_v3.sql', + default='data_files/temoa_schema_v3.sql', ) options = parser.parse_args() legacy_db: Path = Path(options.source_db) @@ -150,8 +150,13 @@ old_name, new_name = name_pair if old_name == '': old_name = new_name + + new_columns = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] + old_columns = [c[1] for c in con_old.execute(f'PRAGMA table_info({old_name});').fetchall()] + cols = str(old_columns[0:len(new_columns)])[1:-1].replace("'","") + try: - data = con_old.execute(f'SELECT * FROM {old_name}').fetchall() + data = con_old.execute(f'SELECT {cols} FROM {old_name}').fetchall() except sqlite3.OperationalError: print('TABLE NOT FOUND: ' + old_name) data = [] @@ -174,8 +179,13 @@ old_name, new_name = name_pair if old_name == '': old_name = new_name + + new_columns = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] + old_columns = [c[1] for c in con_old.execute(f'PRAGMA table_info({old_name});').fetchall()] + cols = str(old_columns[0:len(new_columns)])[1:-1].replace("'","") + try: - data = con_old.execute(f'SELECT * FROM {old_name}').fetchall() + data = con_old.execute(f'SELECT {cols} FROM {old_name}').fetchall() except sqlite3.OperationalError: print('table not found: ' + old_name) data = [] @@ -204,13 +214,18 @@ old_name, new_name = name_pair if old_name == '': old_name = new_name + + new_columns = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] + old_columns = [c[1] for c in con_old.execute(f'PRAGMA table_info({old_name});').fetchall()] + cols = str(old_columns[0:len(new_columns)-1])[1:-1].replace("'","") + try: - data = con_old.execute(f'SELECT * FROM {old_name}').fetchall() + data = con_old.execute(f'SELECT {cols} FROM {old_name}').fetchall() except sqlite3.OperationalError: print(f'mandatory table: {old_name} not found. Operation Failed') sys.exit(-1) count = 1 - num_placeholders = len(data[0]) + num_placeholders = len(new_columns)-1 for row in data: placeholders = ','.join(['?' for _ in range(num_placeholders)]) query = f'INSERT INTO {new_name} VALUES ({count}, {placeholders})' From 911dd86590e60b32193d12d8dc7a4b14699fdc5c Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 22 Apr 2025 16:51:59 -0400 Subject: [PATCH 062/587] Check for all column mismatches at once in v3 to v3_1 migration --- temoa/utilities/db_migration_v3_to_v3_1.py | 55 +++++++++++++--------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/temoa/utilities/db_migration_v3_to_v3_1.py b/temoa/utilities/db_migration_v3_to_v3_1.py index ee36a53b0..28425a210 100644 --- a/temoa/utilities/db_migration_v3_to_v3_1.py +++ b/temoa/utilities/db_migration_v3_to_v3_1.py @@ -27,6 +27,7 @@ import argparse import sqlite3 +import sys from pathlib import Path parser = argparse.ArgumentParser() @@ -39,7 +40,7 @@ ) parser.add_argument( '--schema', - help='Path to schema file (default=../../data_files/temoa_schema_v3_1)', + help='Path to schema file (default=data_files/temoa_schema_v3_1)', required=False, dest='schema', default='data_files/temoa_schema_v3_1.sql', @@ -63,6 +64,28 @@ # turn off FK verification while process executes con_new.execute('PRAGMA foreign_keys = 0;') +def column_check(old_name: str, new_name: str) -> bool: + if old_name == '': + old_name = new_name + + try: + con_old.execute(f'SELECT * FROM {old_name}').fetchone() + except sqlite3.OperationalError: + return True + + new_columns = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] + old_columns = [c[1] for c in con_old.execute(f'PRAGMA table_info({old_name});').fetchall()] + + missing = [c for c in new_columns if c not in old_columns and c != 'period'] + if len(missing) > 0: + msg = ( + f'Columns of {new_name} in the new database missing from {old_name} in old database. Try adding or renaming the column in the old database:' + f'\n{missing}\n' + ) + print(msg) + return False + return True + # table mapping for DIRECT transfers # fmt: off direct_transfer_tables = [ @@ -141,6 +164,15 @@ ('', 'TimeSegmentFraction'), ] +all_good = True +for old_name, new_name in direct_transfer_tables: + good = column_check(old_name, new_name) + all_good = all_good and good +for old_name, new_name in period_added_tables: + good = column_check(old_name, new_name) + all_good = all_good and good +if not all_good: sys.exit(-1) + # It wasn't active anyway... can't be bothered # StorageInit -> StorageFraction @@ -165,16 +197,6 @@ continue new_columns = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] - old_columns = [c[1] for c in con_old.execute(f'PRAGMA table_info({old_name});').fetchall()] - - missing = [c for c in new_columns if c not in old_columns] - if len(missing) > 0: - msg = ( - f'Columns of {new_name} in the new database missing from {old_name} in old database. Try adding or renaming the column in the old database:' - f'\n{missing}\n' - ) - raise ValueError(msg) - data = con_old.execute(f'SELECT {str(new_columns)[1:-1].replace("'","")} FROM {old_name}').fetchall() if not data: @@ -209,17 +231,6 @@ except sqlite3.OperationalError: print('TABLE NOT FOUND: ' + old_name) continue - - new_columns = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] - old_columns = [c[1] for c in con_old.execute(f'PRAGMA table_info({old_name});').fetchall()] - - missing = [c for c in new_columns if c not in old_columns and c != 'period'] - if len(missing) > 0: - msg = ( - f'Columns of {new_name} in the new database missing from {old_name} in old database. Try adding or renaming the column in the old database:' - f'\n{missing}\n' - ) - raise ValueError(msg) columns = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall() if c[1] != 'period'] data = con_old.execute(f'SELECT {str(columns)[1:-1].replace("'","")} FROM {old_name}').fetchall() From 515169ecf1820e27ac515328595550ae34d8d097 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 28 Apr 2025 18:04:09 -0400 Subject: [PATCH 063/587] Generalise check on tech set intersections --- .../temoa_model/model_checking/validators.py | 25 ++++++++++++++----- temoa/temoa_model/temoa_initialize.py | 17 ------------- temoa/temoa_model/temoa_model.py | 5 ++-- 3 files changed, 21 insertions(+), 26 deletions(-) diff --git a/temoa/temoa_model/model_checking/validators.py b/temoa/temoa_model/model_checking/validators.py index 78fcd5220..c6afb3155 100644 --- a/temoa/temoa_model/model_checking/validators.py +++ b/temoa/temoa_model/model_checking/validators.py @@ -304,14 +304,27 @@ def validate_Efficiency(M: 'TemoaModel', val, r, si, t, v, so) -> bool: print('output_commodity', so in M.commodity_carrier) return False +def validate_tech_sets(M: 'TemoaModel'): + """ + Check tech sets for any forbidden intersections + """ + if not all( + ( + check_no_intersection(M.tech_annual, M.tech_baseload), + check_no_intersection(M.tech_annual, M.tech_storage), + check_no_intersection(M.tech_annual, M.tech_upramping), + check_no_intersection(M.tech_annual, M.tech_downramping), + check_no_intersection(M.tech_annual, M.tech_curtailment), + check_no_intersection(M.tech_curtailment, M.tech_flex), + ) + ): + raise ValueError("Technology sets failed to validate. Check log file for details.") -def check_flex_curtail(M: 'TemoaModel'): - violations = M.tech_flex & M.tech_curtailment +def check_no_intersection(set_one, set_two): + violations = set_one & set_two if violations: - logger.error( - 'The following technologies are in both flex and curtail, which is not permitted:', - violations, - ) + msg = f'The following are in both {set_one} and {set_two}, which is not permitted:\n{list(violations)}' + logger.error(msg) return False return True diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index a5adfcc3b..d8e936ed3 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -121,23 +121,6 @@ def DemandConstraintErrorCheck(supply, r, p, s, d, dem): ) logger.error(msg) raise Exception(msg.format(dem, r, p, s, d)) - - -def validate_tech_sets(M: 'TemoaModel'): - """ - Check sets for any errors - """ - - # Baseload technologies cannot also be annual technologies - baseload_annual = M.tech_annual & M.tech_baseload - if baseload_annual: - msg = ( - 'The following technologies were added to both baseload and annual sets. ' - 'Annual technologies have no output variability by time slice so ' - f'there is no need to tag them as baseload:\n{list(baseload_annual)}' - ) - logger.error(msg) - raise ValueError(msg) def validate_time(M: 'TemoaModel'): diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 41c7f226d..679d264d8 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -40,7 +40,7 @@ validate_0to1, region_group_check, validate_Efficiency, - check_flex_curtail, + validate_tech_sets, no_slash_or_pipe, ) from temoa.temoa_model.temoa_initialize import * @@ -171,14 +171,13 @@ def __init__(M, *args, **kwargs): M.tech_baseload = Set(within=M.tech_all) M.tech_annual = Set(within=M.tech_all) # annual storage not supported in Storage constraint or TableWriter, so exclude from domain - M.tech_storage = Set(within=M.tech_all - M.tech_annual) + M.tech_storage = Set(within=M.tech_all) M.tech_reserve = Set(within=M.tech_all) M.tech_upramping = Set(within=M.tech_all) M.tech_downramping = Set(within=M.tech_all) M.tech_curtailment = Set(within=M.tech_all) M.tech_flex = Set(within=M.tech_all) # ensure there is no overlap flex <=> curtailable technologies - M.check_flex_and_curtailment = BuildAction(rule=check_flex_curtail) M.tech_exchange = Set(within=M.tech_all) M.validate_techs = BuildAction(rule=validate_tech_sets) From dd1a2d454e70f64a235c9e4b4c6901dec26a1815 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 7 May 2025 11:32:53 -0400 Subject: [PATCH 064/587] Add sector to outputcost table with support for backwards compatibility --- temoa/temoa_model/table_writer.py | 33 ++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/temoa/temoa_model/table_writer.py b/temoa/temoa_model/table_writer.py index a092dd8f6..05227a139 100644 --- a/temoa/temoa_model/table_writer.py +++ b/temoa/temoa_model/table_writer.py @@ -232,7 +232,9 @@ def clear_iterative_runs(self): def write_storage_level(self, M: TemoaModel, iteration=None) -> None: """Write the storage level table to the DB""" - # For backwards compatibility, make the output table if it doesn't exist + # ----- + # TODO for backwards compatibility, make the output table if it doesn't exist + # remove this one day when it is no longer needed self.con.execute( f"""CREATE TABLE IF NOT EXISTS OutputStorageLevel( @@ -248,6 +250,7 @@ def write_storage_level(self, M: TemoaModel, iteration=None) -> None: PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) );""" ) + # ----- storage_levels = poll_storage_level_results(M=M) @@ -526,6 +529,12 @@ def _insert_cost_results(self, regular_entries, exchange_entries, emission_entri def _write_cost_rows(self, entries, iteration=None): """Write the entries to the OutputCost table""" + cur = self.con.cursor() + # ----- + # TODO remove one day (see below) + cols = [c[1] for c in cur.execute('PRAGMA table_info(OutputCost);').fetchall()] + include_sector = cols[2] == 'sector' + # ----- scenario_name = ( self.config.scenario + f'-{iteration}' if iteration is not None @@ -549,10 +558,24 @@ def _write_cost_rows(self, entries, iteration=None): ) for (r, p, t, v) in entries ] - # let's be kind and sort by something reasonable (r, v, t, p) - rows.sort(key=lambda r: (r[1], r[4], r[3], r[2])) - cur = self.con.cursor() - qry = 'INSERT INTO OutputCost VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' + # ----- + # TODO This was done for backwards-compatibility. Make this the only behaviour one day when + # this is no longer needed + if include_sector: + rows = [ + ( + *r[0:2], + self.tech_sectors[r[3]], + *r[2::], + ) + for r in rows + ] + rows.sort(key=lambda r: (r[0], r[1], r[2], r[3], r[4], r[5])) + qry = 'INSERT INTO OutputCost VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' + # ----- + else: + rows.sort(key=lambda r: (r[0], r[1], r[2], r[3], r[4])) + qry = 'INSERT INTO OutputCost VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' cur.executemany(qry, rows) self.con.commit() From 57583bdde6f20abf61105ae8047e91bd911aee23 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 7 May 2025 11:42:45 -0400 Subject: [PATCH 065/587] Update databases and schemas for addition of sector in OutputCost --- data_files/example_dbs/morris_utopia.sql | 9 +++++---- data_files/example_dbs/stepped_demand.sql | 9 +++++---- data_files/example_dbs/test_system.sql | 9 +++++---- data_files/example_dbs/utopia.sql | 9 +++++---- data_files/temoa_basics_0.sql | 11 ++++++----- data_files/temoa_basics_1.sql | 11 ++++++----- data_files/temoa_basics_2.sql | 11 ++++++----- data_files/temoa_schema_v3_1.sql | 11 ++++++----- tests/testing_data/emissions.sql | 9 +++++---- tests/testing_data/mediumville.sql | 9 +++++---- tests/testing_data/simple_linked_tech.sql | 9 +++++---- tests/testing_data/storageville.sql | 9 +++++---- tests/testing_data/test_system.sql | 9 +++++---- tests/testing_data/utopia.sql | 9 +++++---- 14 files changed, 74 insertions(+), 60 deletions(-) diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index e016e9038..8a993d4a5 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -1640,10 +1640,11 @@ INSERT INTO Technology VALUES('TXG','p','transport','petroleum','',0,0,0,1,1,0,0 CREATE TABLE OutputCost ( scenario TEXT, - region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, + region TEXT REFERENCES Region (region), + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), d_invest REAL, d_fixed REAL, d_var REAL, diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index 526ca5d4f..2172b7234 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -1389,10 +1389,11 @@ INSERT INTO Technology VALUES('EF','p','electric','electric','',0,0,0,0,0,0,0,'f CREATE TABLE OutputCost ( scenario TEXT, - region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, + region TEXT REFERENCES Region (region), + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), d_invest REAL, d_fixed REAL, d_var REAL, diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index 9296bdf85..d24811d5d 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -1652,10 +1652,11 @@ INSERT INTO Technology VALUES('E_TRANS','p','electric','','',0,0,0,0,0,0,1,'elec CREATE TABLE OutputCost ( scenario TEXT, - region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, + region TEXT REFERENCES Region (region), + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), d_invest REAL, d_fixed REAL, d_var REAL, diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 12fe5eb07..c06426a32 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -1635,10 +1635,11 @@ INSERT INTO Technology VALUES('TXG','p','transport','petroleum','',0,0,0,0,0,0,0 CREATE TABLE OutputCost ( scenario TEXT, - region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, + region TEXT REFERENCES Region (region), + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), d_invest REAL, d_fixed REAL, d_var REAL, diff --git a/data_files/temoa_basics_0.sql b/data_files/temoa_basics_0.sql index 2e8df8c72..52d82fd33 100644 --- a/data_files/temoa_basics_0.sql +++ b/data_files/temoa_basics_0.sql @@ -321,13 +321,14 @@ REPLACE INTO Technology VALUES ('producer', 'p', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); REPLACE INTO Technology VALUES ('consumer', 'p', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); -CREATE TABLE IF NOT EXISTS OutputCost +CREATE TABLE OutputCost ( scenario TEXT, - region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, + region TEXT REFERENCES Region (region), + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), d_invest REAL, d_fixed REAL, d_var REAL, diff --git a/data_files/temoa_basics_1.sql b/data_files/temoa_basics_1.sql index dca7321fb..361a58ae6 100644 --- a/data_files/temoa_basics_1.sql +++ b/data_files/temoa_basics_1.sql @@ -491,13 +491,14 @@ REPLACE INTO Technology VALUES ('producer', 'p', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); REPLACE INTO Technology VALUES ('consumer', 'p', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); -CREATE TABLE IF NOT EXISTS OutputCost +CREATE TABLE OutputCost ( scenario TEXT, - region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, + region TEXT REFERENCES Region (region), + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), d_invest REAL, d_fixed REAL, d_var REAL, diff --git a/data_files/temoa_basics_2.sql b/data_files/temoa_basics_2.sql index 0a77f5024..5b1a809e5 100644 --- a/data_files/temoa_basics_2.sql +++ b/data_files/temoa_basics_2.sql @@ -712,13 +712,14 @@ REPLACE INTO Technology VALUES ('producer', 'p', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); REPLACE INTO Technology VALUES ('consumer', 'p', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); -CREATE TABLE IF NOT EXISTS OutputCost +CREATE TABLE OutputCost ( scenario TEXT, - region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, + region TEXT REFERENCES Region (region), + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), d_invest REAL, d_fixed REAL, d_var REAL, diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index d6fbfab03..a4d286de2 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -1103,13 +1103,14 @@ CREATE TABLE IF NOT EXISTS Technology description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -CREATE TABLE IF NOT EXISTS OutputCost +CREATE TABLE OutputCost ( scenario TEXT, - region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, + region TEXT REFERENCES Region (region), + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), d_invest REAL, d_fixed REAL, d_var REAL, diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index abdc6a1f7..d564ed23d 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -1151,10 +1151,11 @@ INSERT INTO Technology VALUES('TechEmbodied','p','energy',NULL,NULL,0,0,0,0,0,0, CREATE TABLE OutputCost ( scenario TEXT, - region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, + region TEXT REFERENCES Region (region), + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), d_invest REAL, d_fixed REAL, d_var REAL, diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 204f8fed2..606c1cbd8 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -1251,10 +1251,11 @@ INSERT INTO Technology VALUES('GeoHeater','p','residential','hydro','',0,0,0,0,0 CREATE TABLE OutputCost ( scenario TEXT, - region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, + region TEXT REFERENCES Region (region), + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), d_invest REAL, d_fixed REAL, d_var REAL, diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index 52d8485c9..f3ae5dc2b 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -1130,10 +1130,11 @@ INSERT INTO Technology VALUES('FAKE_SOURCE','r','supply',NULL,NULL,1,0,0,0,0,0,0 CREATE TABLE OutputCost ( scenario TEXT, - region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, + region TEXT REFERENCES Region (region), + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), d_invest REAL, d_fixed REAL, d_var REAL, diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index cc598dbcb..ec94f0286 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -1155,10 +1155,11 @@ INSERT INTO Technology VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0 CREATE TABLE OutputCost ( scenario TEXT, - region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, + region TEXT REFERENCES Region (region), + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), d_invest REAL, d_fixed REAL, d_var REAL, diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 9296bdf85..d24811d5d 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -1652,10 +1652,11 @@ INSERT INTO Technology VALUES('E_TRANS','p','electric','','',0,0,0,0,0,0,1,'elec CREATE TABLE OutputCost ( scenario TEXT, - region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, + region TEXT REFERENCES Region (region), + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), d_invest REAL, d_fixed REAL, d_var REAL, diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 12fe5eb07..c06426a32 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -1635,10 +1635,11 @@ INSERT INTO Technology VALUES('TXG','p','transport','petroleum','',0,0,0,0,0,0,0 CREATE TABLE OutputCost ( scenario TEXT, - region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, + region TEXT REFERENCES Region (region), + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), d_invest REAL, d_fixed REAL, d_var REAL, From b2d856dfa580ec77d8646ec9a81a950060d71dab Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 8 May 2025 12:44:28 -0400 Subject: [PATCH 066/587] Add hidden TimeNext feature manually defining sequence of states --- temoa/temoa_model/hybrid_loader.py | 22 ++++++++++++++++- temoa/temoa_model/temoa_initialize.py | 35 +++++++++++++++++++++++++-- temoa/temoa_model/temoa_model.py | 4 ++- temoa/temoa_model/temoa_rules.py | 4 +-- 4 files changed, 59 insertions(+), 6 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 835dd1bf7..d49dc7bc2 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -432,7 +432,27 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # StateSequencing raw = cur.execute("SELECT value from MetaData WHERE element == 'state_sequencing'").fetchall() if raw: - data[M.StateSequencing.name] = {None: bool(raw[0][0])} + seq = int(raw[0][0]) + data[M.StateSequencing.name] = {None: seq} + if seq == 2: + # TimeNext + # This is a hidden feature allowing the user to manually specify the sequence of states. + if self.table_exists("TimeNext"): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT period, season, tod, season_next, tod_next FROM main.TimeNext') + load_element(M.TimeNext, raw) + else: + # Hidden feature unlocked! Give a nice long explanation + msg = ( + 'Tried to manually sequence states (time slices) using TimeNext but the table did not exist. ' + 'With state_sequencing set to 2 in the MetaData table, the sequence of states will be pulled ' + 'directly from the TimeNext table, where each row defines the next state in the order. ' + 'This is an advanced feature and not recommended for most users. If you do NOT want to ' + 'manually define the sequence of states, change the state_sequencing parameter. Otherwise ' + 'add the TimeNext table to the database with the following columns then fill it out: ' + '(period, season, tod, season_next, tod_next).' + ) + logger.error(msg) + raise ValueError(msg) else: logger.warning("state_sequencing parameter missing from MetaData table. By default, states will loop each period.") diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index d8e936ed3..95e64e6be 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -228,6 +228,31 @@ def validate_SegFrac(M: 'TemoaModel'): ).format(p, items, total) logger.error(msg) raise Exception(msg) + + +def validate_TimeNext(M: 'TemoaModel'): + """ + If using this table, check that defined states are actually valid. + TimeSegmentFraction is already compared to other tables so just compare to SegFrac. + """ + # Only check TimeNext if it is actually being used + if M.StateSequencing != 2: + return + + segfrac_psd = set(M.SegFrac.sparse_iterkeys()) + time_next_psd = set((p, s, d) for p, s, d, s_next, d_next in M.TimeNext) + time_next_psd_next = set((p, s_next, d_next) for p, s, d, s_next, d_next in M.TimeNext) + + missing_psd = segfrac_psd.difference(time_next_psd) + missing_psd_next = segfrac_psd.difference(time_next_psd_next) + if missing_psd or missing_psd_next: + msg = ( + 'Failed to build state sequence. ' + '\nThese states from TimeSegmentFraction were not given a next state:\n{}\n' + '\nThese states from TimeSegmentFraction do not follow any state:\n{}' + ).format(missing_psd, missing_psd_next) + logger.error(msg) + raise ValueError(msg) def CheckEfficiencyIndices(M: 'TemoaModel'): @@ -723,7 +748,7 @@ def CreateSparseDicts(M: 'TemoaModel'): l_used_techs.add(t) if t in M.tech_flex: - M.flex_commodities.add(o) + M.commodity_flex.add(o) # Add in the period (p) index, since it's not included in the efficiency # table. @@ -1062,11 +1087,17 @@ def CreateStateSequence(M: 'TemoaModel'): for p in M.time_optimize: for s, d in M.time_season[p] * M.time_of_day: M.time_next[p, s, d] = loop_season_next_timeslice(M, p, s, d) + case 2: + # Hidden feature. Define the sequence directly in the TimeNext table + msg = 'Pulling state sequence from TimeNext table.' + for p, s, d, s_next, d_next in M.TimeNext: + M.time_next[p, s, d] = s_next, d_next msg += (' This behaviour can be changed using the' ' state_sequencing parameter in the MetaData table. ' '0 = loop periods, ' - '1 = loop seasons.') + '1 = loop seasons, ' + '2 = define manually in TimeNext.') logger.info(msg) logger.debug('Created sequence of states.') diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 679d264d8..342d177cb 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -124,7 +124,6 @@ def __init__(M, *args, **kwargs): M.exportRegions = dict() M.importRegions = dict() M.time_next = dict() - M.flex_commodities = set() ################################################ # Switching Sets # @@ -200,6 +199,7 @@ def __init__(M, *args, **kwargs): M.commodity_demand = Set() M.commodity_emissions = Set() M.commodity_physical = Set() + M.commodity_flex = Set(within=M.commodity_physical) M.commodity_source = Set(within=M.commodity_physical) M.commodity_annual = Set(within=M.commodity_physical) M.commodity_carrier = Set(initialize=M.commodity_physical | M.commodity_demand) @@ -237,6 +237,8 @@ def __init__(M, *args, **kwargs): M.SegFrac = Param(M.time_optimize, M.time_season_all, M.time_of_day) M.validate_SegFrac = BuildAction(rule=validate_SegFrac) M.StateSequencing = Param(default=0) # How do states carry between time segments? + M.TimeNext = Set() # This is just to get data from the table. Hidden feature and usually not used + M.validate_TimeNext = BuildAction(rule=validate_TimeNext) # Define demand- and resource-related parameters # Dev Note: There does not appear to be a DB table supporting DemandDefaultDistro. This does not diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 8fc0f257a..9bf9a45b0 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -846,7 +846,7 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): flex_waste = 0 flex_waste_annual = 0 - if c in M.flex_commodities: + if c in M.commodity_flex: flex_waste = sum( M.V_Flex[r, p, s, d, S_i, S_t, S_v, c] for S_t, S_v in M.commodityUStreamProcess[r, p, c] @@ -955,7 +955,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): flex_waste = 0 flex_waste_annual = 0 - if c in M.flex_commodities: + if c in M.commodity_flex: flex_waste = sum( M.V_Flex[r, p, S_s, S_d, S_i, S_t, S_v, c] for S_s in M.time_season[p] From a895dc505c58a9dc75fc9255cdaecdd89e43ddb3 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 8 May 2025 12:51:43 -0400 Subject: [PATCH 067/587] Add TimeNext to schema but commented out --- data_files/temoa_schema_v3_1.sql | 14 ++++++++++++++ temoa/temoa_model/hybrid_loader.py | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index a4d286de2..da1fe1d66 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -763,6 +763,20 @@ CREATE TABLE IF NOT EXISTS MaxTechOutputSplitAnnual notes TEXT, PRIMARY KEY (region, period, tech, output_comm) ); +-- CREATE TABLE IF NOT EXISTS TimeNext +-- ( +-- period INTEGER +-- REFERENCES TimePeriod (period), +-- season TEXT +-- REFERENCES TimeSeason (season), +-- tod TEXT +-- REFERENCES TimeOfDay (tod), +-- season_next TEXT +-- REFERENCES TimeSeason (season), +-- tod_next TEXT +-- REFERENCES TimeOfDay (tod), +-- PRIMARY KEY (period, season, tod) +-- ); CREATE TABLE IF NOT EXISTS TimeOfDay ( sequence INTEGER UNIQUE, diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index d49dc7bc2..97fb23ff4 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -449,7 +449,8 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N 'This is an advanced feature and not recommended for most users. If you do NOT want to ' 'manually define the sequence of states, change the state_sequencing parameter. Otherwise ' 'add the TimeNext table to the database with the following columns then fill it out: ' - '(period, season, tod, season_next, tod_next).' + '(period, season, tod, season_next, tod_next). This structure can also be found commented ' + 'out in the schema.' ) logger.error(msg) raise ValueError(msg) From d55efe8e94f2acb2d287c790606156a75da379af Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 8 May 2025 12:57:11 -0400 Subject: [PATCH 068/587] Add a notes column to TimeNext why not --- data_files/temoa_schema_v3_1.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index da1fe1d66..e65858f6d 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -775,6 +775,7 @@ CREATE TABLE IF NOT EXISTS MaxTechOutputSplitAnnual -- REFERENCES TimeSeason (season), -- tod_next TEXT -- REFERENCES TimeOfDay (tod), +-- notes TEXT, -- PRIMARY KEY (period, season, tod) -- ); CREATE TABLE IF NOT EXISTS TimeOfDay From 11290ca43bf9eb03739786f37c0ce08d81724a2d Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 8 May 2025 16:04:18 -0400 Subject: [PATCH 069/587] Change some documentation --- temoa/temoa_model/hybrid_loader.py | 4 ++-- temoa/temoa_model/temoa_rules.py | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 97fb23ff4..e011dbb46 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -449,8 +449,8 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N 'This is an advanced feature and not recommended for most users. If you do NOT want to ' 'manually define the sequence of states, change the state_sequencing parameter. Otherwise ' 'add the TimeNext table to the database with the following columns then fill it out: ' - '(period, season, tod, season_next, tod_next). This structure can also be found commented ' - 'out in the schema.' + '(period, season, tod, season_next, tod_next). The sql code can also be found commented ' + 'out in the v3.1 schema.' ) logger.error(msg) raise ValueError(msg) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 9bf9a45b0..285fad532 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1123,6 +1123,10 @@ def RegionalExchangeCapacity_Constraint(M: 'TemoaModel', r_e, r_i, p, t, v): def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): + """ + This constraint enforces the continuity of state of charge (StorageLevel) between time slices. + StorageLevel in the next time slice is equal to current StorageLevel plus net charge in the current time slice. + """ # This is the sum of all input=i sent TO storage tech t of vintage v with # output=o in p,s,d @@ -1149,9 +1153,6 @@ def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): return expr - - - def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): r""" From 38539605caef8874b0b2c1a3fc9f986d6d628954 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 8 May 2025 18:40:33 -0400 Subject: [PATCH 070/587] Add a warning for rows being filtered out at load time --- temoa/temoa_model/hybrid_loader.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index e011dbb46..29da406b1 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -336,6 +336,9 @@ def load_element( 'Failed to validate members of %s. Coding error likely.' '\n%s' % (c.name, e) ) + if len(screened) < len(values): + msg = ('Some rows in {} failed to validate and were ignored:\n{}') + logger.warning(msg.format(c.name, [val for val in values if val not in screened])) match c: case Set(): if not screened: # no available values From a9da650959c97b594efdf33c5df2a081ac55414c Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 8 May 2025 18:44:49 -0400 Subject: [PATCH 071/587] Small fix to wording --- temoa/temoa_model/hybrid_loader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 29da406b1..658c55266 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -337,7 +337,7 @@ def load_element( '\n%s' % (c.name, e) ) if len(screened) < len(values): - msg = ('Some rows in {} failed to validate and were ignored:\n{}') + msg = ('Some values for {} failed to validate and were ignored:\n{}') logger.warning(msg.format(c.name, [val for val in values if val not in screened])) match c: case Set(): From fce9a61e89cbc11dcce99466ada89b64869685a6 Mon Sep 17 00:00:00 2001 From: CANOE-main Date: Tue, 13 May 2025 14:24:49 -0600 Subject: [PATCH 072/587] Merging materials into main dev branch (#6) * Add construction and end of life flows and end of life emissions but still needs work * Add test for end of life emissions * Add test for materials recycling * Support materials in source tracing * Add flow data output for materials * Update network manager to allow and map material flows and annual exchange techs * Update 3_1 schema for materials * Fix retirement period checks in network manager * Fix to allow existing techs that retire in p0 for end of life flows * Fix to get_annual_retirement and add natural retirement to OutputRetirement table * Add if not exists check for new tables in v3.1 schema * Fix some bugs in materials * Make AnnualRetirement a derived variable --------- Co-authored-by: Davey Elder --- data_files/temoa_schema_v3_1.sql | 57 +- temoa/temoa_model/hybrid_loader.py | 21 + .../model_checking/commodity_graph.py | 26 +- .../model_checking/commodity_network.py | 2 +- .../model_checking/network_model_data.py | 78 +- .../temoa_model/model_checking/validators.py | 4 + temoa/temoa_model/table_data_puller.py | 80 +- temoa/temoa_model/table_writer.py | 9 +- temoa/temoa_model/temoa_initialize.py | 116 +- temoa/temoa_model/temoa_model.py | 15 + temoa/temoa_model/temoa_rules.py | 383 +- tests/conftest.py | 1 + tests/legacy_test_values.py | 8 +- tests/test_emission_results.py | 94 +- tests/test_material_results.py | 88 + tests/test_network_model_data.py | 15 + tests/testing_configs/config_materials.toml | 36 + tests/testing_data/emissions.sql | 55 + tests/testing_data/materials.sql | 1190 ++++ tests/testing_data/mediumville.sql | 28 + tests/testing_data/mediumville_sets.json | 29 + tests/testing_data/simple_linked_tech.sql | 28 + tests/testing_data/storageville.sql | 28 + tests/testing_data/test_system.sql | 30 +- tests/testing_data/test_system_sets.json | 4777 ++++++----------- tests/testing_data/utopia.sql | 28 + tests/testing_data/utopia_sets.json | 2006 +++---- 27 files changed, 4599 insertions(+), 4633 deletions(-) create mode 100644 tests/test_material_results.py create mode 100644 tests/testing_configs/config_materials.toml create mode 100644 tests/testing_data/materials.sql diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index e65858f6d..125904929 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -124,7 +124,20 @@ REPLACE INTO CommodityType VALUES ('d', 'demand commodity'); REPLACE INTO CommodityType VALUES ('s', 'source commodity'); - +CREATE TABLE IF NOT EXISTS ConstructionInput +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); CREATE TABLE IF NOT EXISTS CostEmission ( region TEXT @@ -206,16 +219,19 @@ CREATE TABLE IF NOT EXISTS DemandSpecificDistribution PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -CREATE TABLE IF NOT EXISTS LoanRate +CREATE TABLE IF NOT EXISTS EndOfLifeOutput ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES TimePeriod (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); CREATE TABLE IF NOT EXISTS Efficiency ( @@ -287,6 +303,20 @@ CREATE TABLE IF NOT EXISTS EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); +CREATE TABLE IF NOT EXISTS EmissionEndOfLife +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); CREATE TABLE IF NOT EXISTS ExistingCapacity ( region TEXT, @@ -333,6 +363,17 @@ CREATE TABLE IF NOT EXISTS LoanLifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); +CREATE TABLE IF NOT EXISTS LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); CREATE TABLE IF NOT EXISTS LifetimeProcess ( region TEXT, diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 658c55266..da500019b 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -1078,6 +1078,27 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N ).fetchall() load_element(M.EmissionEmbodied, raw, self.viable_rtv, (0, 2, 3)) + # EmissionEndOfLife + if self.table_exists('EmissionEndOfLife'): + raw = cur.execute( + 'SELECT region, emis_comm, tech, vintage, value ' + 'FROM main.EmissionEndOfLife' + ).fetchall() + load_element(M.EmissionEndOfLife, raw, self.viable_rtv, (0, 2, 3)) + + # ConstructionInput + if self.table_exists('ConstructionInput'): + raw = cur.execute( + 'SELECT region, input_comm, tech, vintage, value FROM main.ConstructionInput' + ).fetchall() + load_element(M.ConstructionInput, raw, self.viable_rtv, (0, 2, 3)) + + # EndOfLifeOutput + if self.table_exists('EndOfLifeOutput'): + raw = cur.execute( + 'SELECT region, tech, vintage, output_comm, value FROM main.EndOfLifeOutput' + ).fetchall() + load_element(M.EndOfLifeOutput, raw, self.viable_rtv, (0, 1, 2)) # LinkedTechs # Note: Both of the linked techs must be viable. As this is non period/vintage diff --git a/temoa/temoa_model/model_checking/commodity_graph.py b/temoa/temoa_model/model_checking/commodity_graph.py index 50d3a9474..145a6febb 100644 --- a/temoa/temoa_model/model_checking/commodity_graph.py +++ b/temoa/temoa_model/model_checking/commodity_graph.py @@ -66,10 +66,14 @@ def generate_graph( layers = {} for c in network_data.all_commodities: layers[c] = 2 # physical - for c in network_data.source_commodities: + for c in network_data.source_commodities[region, period]: layers[c] = 1 for c in network_data.demand_commodities[region, period]: layers[c] = 3 + for c in network_data.cap_commodities: + layers[c] = 4 + for c in network_data.exc_commodities: + layers[c] = 5 edge_colors = {} edge_weights = {} @@ -80,6 +84,14 @@ def generate_graph( all_edges = { (tech.ic, tech.name, tech.oc) for tech in network_data.available_techs[region, period] } + cap_edges = { + (tech.ic, tech.name, tech.oc) for tech in network_data.available_techs[region, period] + if tech.name in ('Construction','EndOfLife') + } + exc_edges = { + (tech.ic, tech.name, tech.oc) for tech in network_data.available_techs[region, period] + if tech.ic in network_data.exc_commodities or tech.oc in network_data.exc_commodities + } # troll through the tech_data and label things of low importance for edge in all_edges: tech = edge[1] @@ -101,6 +113,14 @@ def generate_graph( edge_colors[edge] = 'red' edge_weights[edge] = 5 all_edges.add(edge) + for edge in cap_edges: + edge_colors[edge] = 'darkgreen' + edge_weights[edge] = 2 + all_edges.add(edge) + for edge in exc_edges: + edge_colors[edge] = 'darkblue' + edge_weights[edge] = 2 + all_edges.add(edge) dg = make_nx_graph(all_edges, edge_colors, edge_weights, layers) @@ -186,8 +206,8 @@ def make_nx_graph(connections, edge_colors, edge_weights, layer_map) -> nx.Multi :return: a nx MultiDiGraph """ dg = nx.MultiDiGraph() # networkx multi(edge) directed graph - layer_colors = {1: 'limegreen', 2: 'violet', 3: 'darkorange'} - node_size = {1: 50, 2: 15, 3: 30} + layer_colors = {1: 'limegreen', 2: 'violet', 3: 'darkorange', 4: 'darkgreen', 5: 'darkblue'} + node_size = {1: 50, 2: 15, 3: 30, 4:20, 5:20} for ic, tech, oc in connections: dg.add_node( ic, diff --git a/temoa/temoa_model/model_checking/commodity_network.py b/temoa/temoa_model/model_checking/commodity_network.py index 530b276a4..a7f156596 100644 --- a/temoa/temoa_model/model_checking/commodity_network.py +++ b/temoa/temoa_model/model_checking/commodity_network.py @@ -215,7 +215,7 @@ def analyze_network(self): # it is consumed by the function. (easier than managing it in the recursion) discovered_sources, demand_side_connections = _visited_dfs( self.model_data.demand_commodities[self.region, self.period], - self.model_data.source_commodities, + self.model_data.source_commodities[self.region, self.period], self.connections.copy(), ) self.good_connections = _mark_good_connections( diff --git a/temoa/temoa_model/model_checking/network_model_data.py b/temoa/temoa_model/model_checking/network_model_data.py index d15c6e631..45b53f553 100644 --- a/temoa/temoa_model/model_checking/network_model_data.py +++ b/temoa/temoa_model/model_checking/network_model_data.py @@ -55,7 +55,9 @@ def __init__(self, **kwargs): self.demand_commodities: dict[tuple[str, int | str], set[str]] = kwargs.get( 'demand_commodities' ) - self.source_commodities: set[str] = kwargs.get('source_commodities') + self.cap_commodities: set[str] = kwargs.get('cap_commodities') + self.exc_commodities: set[str] = kwargs.get('exc_commodities') + self.source_commodities: dict[tuple[str, int | str], set[str]] = kwargs.get('source_commodities') self.all_commodities: set[str] = kwargs.get('all_commodities') # dict of (region, period): {Tech} self._available_techs: dict[tuple[str, int | str], set[Tech]] = kwargs.get( @@ -73,6 +75,8 @@ def clone(self) -> Self: return NetworkModelData( demand_commodities=self.demand_commodities.copy(), source_commodities=self.source_commodities.copy(), + cap_commodities=self.cap_commodities.copy(), + exc_commodities=self.exc_commodities.copy(), all_commodities=self.all_commodities.copy(), available_techs=self.available_techs.copy(), available_linked_techs=self.available_linked_techs.copy(), @@ -144,7 +148,7 @@ def _build_from_model(M: TemoaModel, myopic_index=None) -> NetworkModelData: raise NotImplementedError('cannot build network data from model using a MyopicIndex') res = NetworkModelData() res.all_commodities = set(M.commodity_all) - res.source_commodities = set(M.commodity_source) + source_com = defaultdict(set) dem_com = defaultdict(set) for r, p, d in M.Demand: dem_com[r, p].add(d) @@ -173,16 +177,23 @@ def _build_from_db( # re-use some of the hybrid loader code in a clear way. Not too much overlap, though res = NetworkModelData() cur = con.cursor() + raw = cur.execute('SELECT tech FROM Technology WHERE retire==1').fetchall() + tech_retire = {t[0] for t in raw} + raw = cur.execute('SELECT period FROM TimePeriod').fetchall() + periods = [p[0] for p in raw] + period_length = {periods[i]: periods[i+1] - periods[i] for i in range(len(periods)-1)} raw = cur.execute('SELECT Commodity.name FROM Commodity').fetchall() + res.cap_commodities = set() + res.exc_commodities = set() res.all_commodities = {t[0] for t in raw} raw = cur.execute("SELECT Commodity.name FROM Commodity WHERE flag = 's'").fetchall() - res.source_commodities = {t[0] for t in raw} + source_comms = {t[0] for t in raw} + source_dict = defaultdict(set) # use Demand to get the region, period specific demand comms raw = cur.execute('SELECT region, period, commodity FROM main.Demand').fetchall() demand_dict = defaultdict(set) for r, p, d in raw: demand_dict[r, p].add(d) - res.demand_commodities = demand_dict # need lifetime to screen techs... :/ default_lifetime = TemoaModel.default_lifetime_tech if not myopic_index: @@ -230,12 +241,65 @@ def _build_from_db( living_techs = set() # for screening the linked techs below # filter out the dead ones... for element in raw: + (r, ic, tech, v, oc, lifetime) = element for p in periods: - (r, ic, tech, v, oc, lifetime) = element if v <= p < v + lifetime: - techs[r, p].add(Tech(r, ic, tech, v, oc)) - living_techs.add(tech) + if '-' in r: + r1, r2 = r.split('-') + source = f"{ic} ({r1})" + destination = f"{oc} ({r2})" + techs[r2, p].add(Tech(r2, source, tech, v, oc)) + techs[r1, p].add(Tech(r1, ic, tech, v, destination)) + techs[r, p].add(Tech(r, ic, tech, v, oc)) + source_dict[r2, p].add(source) + demand_dict[r1, p].add(destination) + res.all_commodities.add(source) + res.exc_commodities.add(source) + res.all_commodities.add(destination) + res.exc_commodities.add(destination) + else: + techs[r, p].add(Tech(r, ic, tech, v, oc)) + living_techs.add(tech) + if ic in source_comms: + source_dict[r, p].add(ic) + + # End of life output + if any(( + p==v and lifetime bool: print('output_commodity', so in M.commodity_carrier) return False + def validate_tech_sets(M: 'TemoaModel'): """ Check tech sets for any forbidden intersections @@ -320,6 +321,7 @@ def validate_tech_sets(M: 'TemoaModel'): ): raise ValueError("Technology sets failed to validate. Check log file for details.") + def check_no_intersection(set_one, set_two): violations = set_one & set_two if violations: @@ -328,6 +330,7 @@ def check_no_intersection(set_one, set_two): return False return True + # Seems unused def validate_tech_split(M: 'TemoaModel', val, r, p, c, t): if all( @@ -345,5 +348,6 @@ def validate_tech_split(M: 'TemoaModel', val, r, p, c, t): print('t', t in M.tech_all) return False + def validate_0to1(M: 'TemoaModel', val, *args): return 0.0 <= val <= 1.0 \ No newline at end of file diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index 8d2da26a7..f9c73ca8a 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -115,12 +115,14 @@ def poll_capacity_results(M: TemoaModel, epsilon=1e-5) -> CapData: # Retired Capacity ret = [] - for r, p, t, v in M.V_RetiredCapacity: - val = value(M.V_RetiredCapacity[r, p, t, v]) - if abs(val) < epsilon: - continue - new_retired_cap = (r, p, t, v, val) - ret.append(new_retired_cap) + for r, t, v in M.retirementPeriods: + for p in M.retirementPeriods[r, t, v]: + # We want to output period retirement, not annual retirement, so multiply by PeriodLength + val = value(M.PeriodLength[p]) * value(M.V_AnnualRetirement[r, p, t, v]) + if abs(val) < epsilon: + continue + new_retired_cap = (r, p, t, v, val) + ret.append(new_retired_cap) return CapData(built=built, net=net, retired=ret) @@ -201,6 +203,29 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl res[fi][FlowType.FLEX] = flow res[fi][FlowType.OUT] -= flow + # construction flows + for (r, i, t, v) in M.ConstructionInput.sparse_iterkeys(): + annual = value(M.ConstructionInput[r, i, t, v]) * value(M.V_NewCapacity[r, t, v]) / value(M.PeriodLength[v]) + for s in M.time_season[v]: + for d in M.time_of_day: + fi = FI(r, v, s, d, i, t, v, 'ConstructionInput') + flow = annual * value(M.SegFrac[v, s, d]) + if abs(flow) < epsilon: + continue + res[fi][FlowType.IN] = flow + + # end of life flows + for (r, t, v, o) in M.EndOfLifeOutput.sparse_iterkeys(): + for p in M.retirementPeriods[r, t, v]: + annual = value(M.EndOfLifeOutput[r, t, v, o]) * value(M.V_AnnualRetirement[r, p, t, v]) + for s in M.time_season[p]: + for d in M.time_of_day: + fi = FI(r, p, s, d, 'EndOfLifeOutput', t, v, o) + flow = annual * value(M.SegFrac[p, s, d]) + if abs(flow) < epsilon: + continue + res[fi][FlowType.OUT] = flow + return res @@ -513,8 +538,8 @@ def poll_emissions( # iterate through embodied flows embodied_flows: dict[EI, float] = defaultdict(float) for r, e, t, v in M.EmissionEmbodied.sparse_iterkeys(): - embodied_flows[EI(r, v, t, v, e)] += value(M.V_NewCapacity[r, t, v] * M.EmissionEmbodied[r, e, t, v]) # for embodied costs - flows[EI(r, v, t, v, e)] += value(M.V_NewCapacity[r, t, v] * M.EmissionEmbodied[r, e, t, v]) # add embodied to process emissions + embodied_flows[EI(r, v, t, v, e)] += value(M.V_NewCapacity[r, t, v] * M.EmissionEmbodied[r, e, t, v] / M.PeriodLength[v]) # for embodied costs + flows[EI(r, v, t, v, e)] += value(M.V_NewCapacity[r, t, v] * M.EmissionEmbodied[r, e, t, v] / M.PeriodLength[v]) # add embodied to process emissions # add embodied costs to process costs for ei in embodied_flows: @@ -527,18 +552,53 @@ def poll_emissions( if cost_index not in M.CostEmission: continue undiscounted_emiss_cost = ( - embodied_flows[ei] * M.CostEmission[ei.r, ei.v, ei.e] * 1 # treat as fixed cost incurred in a single year (year of construction) + embodied_flows[ei] * M.CostEmission[ei.r, ei.v, ei.e] * M.PeriodLength[ei.v] # treat as fixed cost distributed over construction period ) discounted_emiss_cost = temoa_rules.fixed_or_variable_cost( cap_or_flow=embodied_flows[ei], cost_factor=M.CostEmission[ei.r, ei.v, ei.e], - cost_years=1, # treat as fixed cost incurred in a single year (year of construction) + cost_years=M.PeriodLength[ei.v], # treat as fixed cost distributed over construction period GDR=GDR, P_0=p_0, p=ei.v, ) ud_costs[ei.r, ei.v, ei.t, ei.v] += undiscounted_emiss_cost d_costs[ei.r, ei.v, ei.t, ei.v] += discounted_emiss_cost + + ########################### + # End of life Emissions + ########################### + + # iterate through end of life flows + eol_flows: dict[EI, float] = defaultdict(float) + for r, e, t, v in M.EmissionEndOfLife.sparse_iterkeys(): + for p in M.retirementPeriods[r, t, v]: + eol_flows[EI(r, p, t, v, e)] += value(M.V_AnnualRetirement[r, p, t, v] * M.EmissionEndOfLife[r, e, t, v]) # for eol costs + flows[EI(r, p, t, v, e)] += value(M.V_AnnualRetirement[r, p, t, v] * M.EmissionEndOfLife[r, e, t, v]) # add eol to process emissions + + # add embodied costs to process costs + for ei in eol_flows: + # zero out again if still tiny + if abs(flows[ei]) < epsilon: + flows[ei] = 0.0 + continue + # screen to see if there is an associated cost + cost_index = (ei.r, ei.p, ei.e) + if cost_index not in M.CostEmission: + continue + undiscounted_emiss_cost = ( + eol_flows[ei] * M.CostEmission[ei.r, ei.p, ei.e] * M.PeriodLength[ei.p] # treat as fixed cost distributed over retirement period + ) + discounted_emiss_cost = temoa_rules.fixed_or_variable_cost( + cap_or_flow=eol_flows[ei], + cost_factor=M.CostEmission[ei.r, ei.p, ei.e], + cost_years=M.PeriodLength[ei.p], # treat as fixed cost distributed over retirement period + GDR=GDR, + P_0=p_0, + p=ei.p, + ) + ud_costs[ei.r, ei.p, ei.t, ei.v] += undiscounted_emiss_cost + d_costs[ei.r, ei.p, ei.t, ei.v] += discounted_emiss_cost # finally, now that all costs are added up for each rptv, put in cost dict costs = defaultdict(dict) diff --git a/temoa/temoa_model/table_writer.py b/temoa/temoa_model/table_writer.py index 05227a139..81d7ba632 100644 --- a/temoa/temoa_model/table_writer.py +++ b/temoa/temoa_model/table_writer.py @@ -440,13 +440,20 @@ def _insert_summary_flow_results(self, flow_data: dict, iteration: int | None) - # flow_data = self.calculate_flows(M) def check_flow_balance(self, M: TemoaModel) -> bool: - """An easy sanity check to ensure that the flow tables are balanced, except for storage""" + """ + An easy sanity check to ensure that the flow tables are balanced, except for storage + and construction/end of life flows + """ flows = self.flow_register all_good = True deltas = defaultdict(float) for fi in flows: if fi.t in M.tech_storage: continue + if fi.i == 'EndOfLifeOutput': + continue + if fi.o == 'ConstructionInput': + continue # some conveniences for the players... fin = flows[fi][FlowType.IN] diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 95e64e6be..6dfb486ca 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -119,7 +119,7 @@ def DemandConstraintErrorCheck(supply, r, p, s, d, dem): ' - Does a tech that satisfies this demand need a longer ' 'Lifetime?\n' ) - logger.error(msg) + logger.error(msg.format(dem, r, p, s, d)) raise Exception(msg.format(dem, r, p, s, d)) @@ -262,8 +262,10 @@ def CheckEfficiencyIndices(M: 'TemoaModel'): # TODO: This could be upgraded to scan for finer resolution # by checking by REGION and PERIOD... Each region/period is unique. c_physical = set(i for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) + c_physical = c_physical | set(i for r, i, t, v in M.ConstructionInput) techs = set(t for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) c_outputs = set(o for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) + c_outputs = c_outputs | set(o for r, t, v, o in M.EndOfLifeOutput) symdiff = c_physical.symmetric_difference(M.commodity_physical) if symdiff: @@ -307,10 +309,15 @@ def CheckEfficiencyVariable(M: 'TemoaModel'): count_rpitvo = dict() # Pull non-variable efficiency by default for r, i, t, v, o in M.Efficiency.sparse_iterkeys(): + if (r, t, v) not in M.processPeriods: + # Probably an existing vintage that retires in p0 + # Still want it for end of life flows + continue for p in M.processPeriods[r, t, v]: M.efficiencyVariables[r, p, i, t, v, o] = False count_rpitvo[r, p, i, t, v, o] = 0 + annual = set() # Check for bad values and count up the good ones for r, p, s, d, i, t, v, o in M.EfficiencyVariable.sparse_iterkeys(): @@ -319,9 +326,20 @@ def CheckEfficiencyVariable(M: 'TemoaModel'): logger.error(msg) raise ValueError(msg) + if t in M.tech_annual: + annual.add(t) + # Good value, pull from EfficiencyVariable table count_rpitvo[r, p, i, t, v, o] += 1 + for t in annual: + msg = ( + f"Variable efficiencies were provided for the annual technology {t}, which has " + "no variable output. This will only be applied to flows on non-annual commodities. " + "This is ambiguous behaviour and not recommended." + ) + logger.warning(msg) + # Check if all possible values have been set as variable # log a warning if some are missing (allowed but maybe accidental) num_seg = len(M.time_season[p]) * len(M.time_of_day) @@ -726,13 +744,14 @@ def CreateSparseDicts(M: 'TemoaModel'): msg = ( '\nWarning: %s specified as ExistingCapacity, but its ' 'LifetimeProcess parameter does not extend past the beginning ' - 'of time_future. (i.e. useless parameter)' + 'of time_future.' '\n\tLifetime: %s' '\n\tFirst period: %s\n' ) logger.warning(msg, l_process, l_lifetime, l_first_period) - SE.write(msg % (l_process, l_lifetime, l_first_period)) - continue + # Devnote: these are now useful due to end of life outputs + #SE.write(msg % (l_process, l_lifetime, l_first_period)) + #continue eindex = (r, i, t, v, o) if M.Efficiency[eindex] == 0: @@ -766,6 +785,16 @@ def CreateSparseDicts(M: 'TemoaModel'): # if v + l_loan_life >= p: # M.processLoans[pindex] = True + if t not in M.tech_uncap and any(( + p==v and l_lifetime= v and (r1, p, o1) not in M.commodityDStreamProcess: - msg = ( - 'The {} process in region {} has no downstream process other ' - 'than a transport ({}) process. This will cause the commodity ' - 'balance constraint to fail. Add a dummy technology downstream ' - 'of the {} process to the Efficiency table to avoid this ' - 'issue. The dummy technology should have the same region and ' - 'vintage as the {} process, an efficiency of 100%, with the {} ' - 'commodity as the input and output.' - 'The dummy technology may also need a corresponding row in the ' - 'ExistingCapacity table with capacity values that equal the {} ' - 'technology.' - ) - f_msg = msg.format(t1, r1, t, t1, t1, o1, t1) - logger.error(f_msg) - raise ValueError(f_msg) + # devnote: I think this was only necessary because the commodity balance constraint rpc indices + # weren't accounting for imports/exports. I added them to the set below so this should be fixed + # for r, i, t, v, o in M.Efficiency.sparse_iterkeys(): + # if t in M.tech_exchange: + # reg = r.split('-')[0] + # for r1, i1, t1, v1, o1 in M.Efficiency.sparse_iterkeys(): + # if (r1 == reg) & (o1 == i): + # for p in M.time_optimize: + # if p >= v and (r1, p, o1) not in M.commodityDStreamProcess: + # msg = ( + # 'The {} process in region {} has no downstream process other ' + # 'than a transport ({}) process. This will cause the commodity ' + # 'balance constraint to fail. Add a dummy technology downstream ' + # 'of the {} process to the Efficiency table to avoid this ' + # 'issue. The dummy technology should have the same region and ' + # 'vintage as the {} process, an efficiency of 100%, with the {} ' + # 'commodity as the input and output.' + # 'The dummy technology may also need a corresponding row in the ' + # 'ExistingCapacity table with capacity values that equal the {} ' + # 'technology.' + # ) + # f_msg = msg.format(t1, r1, t, t1, t1, o1, t1) + # logger.error(f_msg) + # raise ValueError(f_msg) + + # Need this here for the commodity balance rpc set + for r, i, t, v in M.ConstructionInput: + if (r, v, i) not in M.capacityConsumptionTechs: + M.capacityConsumptionTechs[r, v, i] = set() + M.capacityConsumptionTechs[r, v, i].add(t) + for r, t, v, o in M.EndOfLifeOutput: + if (r, t, v) not in M.retirementPeriods: + msg = ( + f'Process {(r, t, v)} in EndOfLifeOutput does not retire within the planning horizon. ' + 'All processes in EndOfLifeOutput must naturally reach end of life at the start of ' + 'or during the planning horizon (p0 <= v+lifetime < pE) or be a retirement tech ' + '(allowing early retirement).' + ) + logger.error(msg) + raise ValueError(msg) + for p in M.retirementPeriods[r, t, v]: + # What periods can this process retire in, either naturally or economically? + if (r, p, o) not in M.retirementProductionProcesses: + M.retirementProductionProcesses[r, p, o] = set() + M.retirementProductionProcesses[r, p, o].add((t, v)) l_unused_techs = M.tech_all - l_used_techs if l_unused_techs: @@ -961,8 +1013,8 @@ def CreateSparseDicts(M: 'TemoaModel'): SE.write(msg.format(i)) # valid region-period-commodity sets for commodity balance constraints - commodityUpstream_rpi = set(M.commodityUStreamProcess.keys()) - commodityDownstream_rpo = set(M.commodityDStreamProcess.keys()) + commodityUpstream_rpi = set(M.commodityUStreamProcess.keys() | M.retirementProductionProcesses.keys() | M.importRegions.keys()) + commodityDownstream_rpo = set(M.commodityDStreamProcess.keys() | M.capacityConsumptionTechs.keys() | M.exportRegions.keys()) M.commodityBalance_rpc = commodityUpstream_rpi.intersection(commodityDownstream_rpo) M.activeFlow_rpsditvo = set( @@ -1260,6 +1312,14 @@ def RetiredCapacityVariableIndices(M: 'TemoaModel'): ) +def AnnualRetirementVariableIndices(M: 'TemoaModel'): + return set( + (r, p, t, v) + for r, t, v in M.retirementPeriods.keys() + for p in M.retirementPeriods[r, t, v] + ) + + def CapacityAvailableVariableIndices(M: 'TemoaModel'): return M.activeCapacityAvailable_rpt diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 342d177cb..05bb1bc95 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -99,11 +99,14 @@ def __init__(M, *args, **kwargs): M.commodityBalance_rpc = None # Set of valid region-period-commodity indices to balance M.commodityDStreamProcess = dict() # The downstream process of a commodity during a period M.commodityUStreamProcess = dict() # The upstream process of a commodity during a period + M.capacityConsumptionTechs = dict() # New capacity consuming a commodity during a period [r,p,c] -> t + M.retirementProductionProcesses = dict() # Retired capacity producing a commodity during a period [r,p,c] -> t,v M.processInputsByOutput = dict() M.processOutputsByInput = dict() M.processTechs = dict() M.processReservePeriods = dict() M.processPeriods = dict() # {(r, t, v): set(p)} + M.retirementPeriods = dict() # {(r, t, v): set(p)} periods in which a process can economically or naturally retire M.processVintages = dict() """current available (within lifespan) vintages {(r, p, t) : set(v)}""" @@ -274,6 +277,11 @@ def __init__(M, *args, **kwargs): # Any, Any, Any, Any, Any, # within=NonNegativeReals, validate=validate_Efficiency # ) + + # devnote: need these here or CheckEfficiencyIndices may flag these commodities as unused + M.ConstructionInput = Param(M.regions, M.commodity_physical, M.tech_with_capacity, M.vintage_optimize) + M.EndOfLifeOutput = Param(M.regions, M.tech_with_capacity, M.vintage_all, M.commodity_physical) + M.Efficiency = Param( M.regionalIndices, M.commodity_physical, @@ -527,6 +535,7 @@ def __init__(M, *args, **kwargs): M.PlanningReserveMargin = Param(M.regions, default=0.2) M.EmissionEmbodied = Param(M.regions, M.commodity_emissions, M.tech_with_capacity, M.vintage_optimize) + M.EmissionEndOfLife = Param(M.regions, M.commodity_emissions, M.tech_with_capacity, M.vintage_all) M.MyopicBaseyear = Param(default=0) @@ -578,6 +587,9 @@ def __init__(M, *args, **kwargs): M.RetiredCapacityVar_rptv = Set(dimen=4, initialize=RetiredCapacityVariableIndices) M.V_RetiredCapacity = Var(M.RetiredCapacityVar_rptv, domain=NonNegativeReals, initialize=0) + M.AnnualRetirementVar_rptv = Set(dimen=4, initialize=AnnualRetirementVariableIndices) + M.V_AnnualRetirement = Var(M.AnnualRetirementVar_rptv, domain=NonNegativeReals, initialize=0) + M.CapacityAvailableVar_rpt = Set(dimen=3, initialize=CapacityAvailableVariableIndices) M.V_CapacityAvailableByPeriodAndTech = Var( M.CapacityAvailableVar_rpt, domain=NonNegativeReals, initialize=0 @@ -619,6 +631,9 @@ def __init__(M, *args, **kwargs): M.RetiredCapacityConstraint = Constraint( M.RetiredCapacityVar_rptv, rule=RetiredCapacity_Constraint ) + M.AnnualRetirementConstraint = Constraint( + M.AnnualRetirementVar_rptv, rule=AnnualRetirement_Constraint + ) M.AdjustedCapacityConstraint = Constraint( M.CostFixed_rptv, rule=AdjustedCapacity_Constraint ) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 285fad532..558bfa16a 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -63,7 +63,7 @@ def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): return M.V_Capacity[r, p, t, v] == value(M.ExistingCapacity[r, t, v]) - retired_cap else: return M.V_Capacity[r, p, t, v] == M.V_NewCapacity[r, t, v] - retired_cap - + def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): r""" @@ -271,6 +271,41 @@ def RetiredCapacity_Constraint(M: 'TemoaModel', r, p, t, v): return expr +def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): + r""" + Get the annualised retirement rate for a process in a given period. + Used to model end of life flows and emissions. Assumes that retirement + is evenly distributed over the model period, in the same way we assume + capacity is deployed evenly over the model period. + """ + + # Need to know what already (before period p) retired economically so we don't double count + already_retired = 0 + if t in M.tech_retirement: + already_retired = sum( + M.V_RetiredCapacity[r, S_p, t, v] for S_p in M.time_optimize if v < S_p < p + ) + + # If it naturally retires at the beginning of or during this period, all capacity minus already retired + l = value(M.LifetimeProcess[r, t, v]) + if v+l == p or value(M.ModelProcessLife[r, p, t, v]) < value(M.PeriodLength[p]): + if v in M.time_optimize: + retired = M.V_NewCapacity[r, t, v] - already_retired + elif v in M.time_exist: + retired = M.ExistingCapacity[r, t, v] - already_retired + # Otherwise if not the vintage period then just early (economic) retirement in this period + elif t in M.tech_retirement and v < p: + retired = M.V_RetiredCapacity[r, p, t, v] + # Neither natural retirement nor early economic retirement possible + else: + retired = 0.0 + + # Distribute retirement evenly over planning period + retired /= value(M.PeriodLength[p]) + + return M.V_AnnualRetirement[r, p, t, v] == retired + + # --------------------------------------------------------------- # Define the Objective Function # --------------------------------------------------------------- @@ -586,21 +621,37 @@ def PeriodCost_rule(M: 'TemoaModel', p): # 5. flex annual emissions -- removed (double counting, flex wastes are SUBTRACTIVE from flowout) - # 6. embodied - treated as a fixed cost in a single year (year of construction) + # 6. embodied - treated as a fixed cost distributed over the deployment period (vintage) embodied_emissions = sum( fixed_or_variable_cost( - cap_or_flow=M.V_NewCapacity[r, t, v] * value(M.EmissionEmbodied[r, e, t, v]), + cap_or_flow=M.V_NewCapacity[r, t, v] * value(M.EmissionEmbodied[r, e, t, v]) / value(M.PeriodLength[p]), cost_factor=value(M.CostEmission[r, p, e]), - cost_years=1, # We assume the embodied emissions are emitted in the same year as the capacity is installed. + cost_years=M.PeriodLength[v], # We assume the embodied emissions are emitted in the same year as the capacity is installed. GDR=GDR, P_0=P_0, p=p, ) for (r, e, t, v) in M.EmissionEmbodied.sparse_iterkeys() + if (r, p, e) in M.CostEmission if v == p ) - period_emission_cost = var_emissions + var_annual_emissions + embodied_emissions + # 6. endoflife - treated as a fixed cost distributed over the retirement period + endoflife_emissions = sum( + fixed_or_variable_cost( + cap_or_flow=M.V_AnnualRetirement[r, p, t, v] * value(M.EmissionEndOfLife[r, e, t, v]), + cost_factor=value(M.CostEmission[r, p, e]), + cost_years=M.PeriodLength[p], # We assume the embodied emissions are emitted in the same year as the capacity is installed. + GDR=GDR, + P_0=P_0, + p=p, + ) + for (r, e, t, v) in M.EmissionEndOfLife.sparse_iterkeys() + if (r, p, e) in M.CostEmission + if p in M.retirementPeriods[r, t, v] + ) + + period_emission_cost = var_emissions + var_annual_emissions + embodied_emissions + endoflife_emissions period_costs = ( loan_costs + fixed_costs + variable_costs + variable_costs_annual + period_emission_cost @@ -789,83 +840,115 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): if c in M.commodity_demand: # Is this necessary? Demand comms have no downstream process no shouldnt be in indices return Constraint.Skip - # Only storage techs have a flow in variable - # For other techs, it would be redundant as in = out / eff - stored = sum( - M.V_FlowIn[r, p, s, d, c, S_t, S_v, S_o] - for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t in M.tech_storage - for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] - ) + produced = 0 + consumed = 0 + + if (r, p, c) in M.commodityDStreamProcess: + # Only storage techs have a flow in variable + # For other techs, it would be redundant as in = out / eff + consumed += sum( + M.V_FlowIn[r, p, s, d, c, S_t, S_v, S_o] + for S_t, S_v in M.commodityDStreamProcess[r, p, c] + if S_t in M.tech_storage + for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] + ) - consumed = sum( - M.V_FlowOut[r, p, s, d, c, S_t, S_v, S_o] / get_variable_efficiency(M, r, p, s, d, c, S_t, S_v, S_o) - for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t not in M.tech_storage and S_t not in M.tech_annual - for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] - ) + # Into flows + consumed += sum( + M.V_FlowOut[r, p, s, d, c, S_t, S_v, S_o] / get_variable_efficiency(M, r, p, s, d, c, S_t, S_v, S_o) + for S_t, S_v in M.commodityDStreamProcess[r, p, c] + if S_t not in M.tech_storage and S_t not in M.tech_annual + for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] + ) - consumed_annual = value(M.SegFrac[p, s, d]) * sum( - M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] / get_variable_efficiency(M, r, p, s, d, c, S_t, S_v, S_o) - for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t not in M.tech_storage and S_t in M.tech_annual - for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] - ) + # Into annual flows + consumed += value(M.SegFrac[p, s, d]) * sum( + M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] / get_variable_efficiency(M, r, p, s, d, c, S_t, S_v, S_o) + for S_t, S_v in M.commodityDStreamProcess[r, p, c] + if S_t not in M.tech_storage and S_t in M.tech_annual + for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] + ) - # Includes output from storage - produced = sum( - M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, c] - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t not in M.tech_annual - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] - ) + if (r, p, c) in M.capacityConsumptionTechs: + # Consumed by building capacity + # Assume evenly distributed over a year + consumed += value(M.SegFrac[p, s, d]) * sum( + value(M.ConstructionInput[r, c, S_t, p]) * M.V_NewCapacity[r, S_t, p] + for S_t in M.capacityConsumptionTechs[r, p, c] + ) / M.PeriodLength[p] + + if (r, p, c) in M.commodityUStreamProcess: + # From flows including output from storage + produced += sum( + M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, c] + for S_t, S_v in M.commodityUStreamProcess[r, p, c] + if S_t not in M.tech_annual + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + ) - produced_annual = value(M.SegFrac[p, s, d]) * sum( - M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, c] - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t in M.tech_annual - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] - ) + # From annual flows + produced += value(M.SegFrac[p, s, d]) * sum( + M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, c] + for S_t, S_v in M.commodityUStreamProcess[r, p, c] + if S_t in M.tech_annual + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + ) + + if c in M.flex_commodities: + # Wasted by flex flows + consumed += sum( + M.V_Flex[r, p, s, d, S_i, S_t, S_v, c] + for S_t, S_v in M.commodityUStreamProcess[r, p, c] + if S_t not in M.tech_annual and S_t in M.tech_flex + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + ) + # Wasted by annual flex flows + consumed += value(M.SegFrac[p, s, d]) * sum( + M.V_FlexAnnual[r, p, S_i, S_t, S_v, c] + for S_t, S_v in M.commodityUStreamProcess[r, p, c] + if S_t in M.tech_annual and S_t in M.tech_flex + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + ) + + if (r, p, c) in M.retirementProductionProcesses: + # Produced by retiring capacity + # Assume evenly distributed over a year + produced += value(M.SegFrac[p, s, d]) * sum( + value(M.EndOfLifeOutput[r, S_t, S_v, c]) * M.V_AnnualRetirement[r, p, S_t, S_v] + for S_t, S_v in M.retirementProductionProcesses[r, p, c] + ) # export of commodity c from region r to other regions - exported = 0 if (r, p, c) in M.exportRegions: - exported = sum( + consumed += sum( M.V_FlowOut[r + '-' + reg, p, s, d, c, S_t, S_v, S_o] / get_variable_efficiency(M, r + '-' + reg, p, s, d, c, S_t, S_v, S_o) for reg, S_t, S_v, S_o in M.exportRegions[r, p, c] + if S_t not in M.tech_annual + ) + consumed += sum( + value(M.SegFrac[p, s, d]) * M.V_FlowOutAnnual[reg + '-' + r, p, c, S_t, S_v, S_o] + / get_variable_efficiency(M, r + '-' + reg, p, s, d, c, S_t, S_v, S_o) + for reg, S_t, S_v, S_o in M.exportRegions[r, p, c] + if S_t in M.tech_annual ) # import of commodity c from other regions into region r - imported = 0 if (r, p, c) in M.importRegions: - imported = sum( + produced += sum( M.V_FlowOut[reg + '-' + r, p, s, d, S_i, S_t, S_v, c] for reg, S_t, S_v, S_i in M.importRegions[r, p, c] + if S_t not in M.tech_annual ) - - flex_waste = 0 - flex_waste_annual = 0 - if c in M.commodity_flex: - flex_waste = sum( - M.V_Flex[r, p, s, d, S_i, S_t, S_v, c] - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t not in M.tech_annual and S_t in M.tech_flex - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] - ) - flex_waste_annual = value(M.SegFrac[p, s, d]) * sum( - M.V_FlexAnnual[r, p, S_i, S_t, S_v, c] - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t in M.tech_annual and S_t in M.tech_flex - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + produced += sum( + value(M.SegFrac[p, s, d]) * M.V_FlowOutAnnual[reg + '-' + r, p, S_i, S_t, S_v, c] + for reg, S_t, S_v, S_i in M.importRegions[r, p, c] + if S_t in M.tech_annual ) - supplied = produced + produced_annual + imported - demanded = stored + consumed + consumed_annual + exported + flex_waste + flex_waste_annual - CommodityBalanceConstraintErrorCheck( - supplied, - demanded, + produced, + consumed, r, p, s, @@ -873,7 +956,7 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): c, ) - expr = supplied == demanded + expr = produced == consumed return expr @@ -888,101 +971,128 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): if c in M.commodity_demand: # Is this necessary? Demand comms have no downstream process no shouldnt be in indices return Constraint.Skip - # Only storage techs have a flow in variable - # For other techs, it would be redundant as in = out / eff - stored = sum( - M.V_FlowIn[r, p, S_s, S_d, c, S_t, S_v, S_o] - for S_s in M.time_season[p] - for S_d in M.time_of_day - for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t in M.tech_storage - for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] - ) + produced = 0 + consumed = 0 + + if (r, p, c) in M.commodityDStreamProcess: + # Only storage techs have a flow in variable + # For other techs, it would be redundant as in = out / eff + consumed += sum( + M.V_FlowIn[r, p, S_s, S_d, c, S_t, S_v, S_o] + for S_s in M.time_season[p] + for S_d in M.time_of_day + for S_t, S_v in M.commodityDStreamProcess[r, p, c] + if S_t in M.tech_storage + for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] + ) - consumed = sum( - M.V_FlowOut[r, p, S_s, S_d, c, S_t, S_v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, c, S_t, S_v, S_o) - for S_s in M.time_season[p] - for S_d in M.time_of_day - for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t not in M.tech_storage and S_t not in M.tech_annual - for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] - ) + consumed += sum( + M.V_FlowOut[r, p, S_s, S_d, c, S_t, S_v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, c, S_t, S_v, S_o) + for S_s in M.time_season[p] + for S_d in M.time_of_day + for S_t, S_v in M.commodityDStreamProcess[r, p, c] + if S_t not in M.tech_storage and S_t not in M.tech_annual + for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] + ) - consumed_annual = sum( - M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] / value(M.Efficiency[r, c, S_t, S_v, S_o]) - for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t not in M.tech_storage and S_t in M.tech_annual - for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] - ) + consumed += sum( + M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] / value(M.Efficiency[r, c, S_t, S_v, S_o]) + for S_t, S_v in M.commodityDStreamProcess[r, p, c] + if S_t not in M.tech_storage and S_t in M.tech_annual + for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] + ) - # Includes output from storage - produced = sum( - M.V_FlowOut[r, p, S_s, S_d, S_i, S_t, S_v, c] - for S_s in M.time_season[p] - for S_d in M.time_of_day - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t not in M.tech_annual - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] - ) + if (r, p, c) in M.capacityConsumptionTechs: + # Consumed by building capacity + # Assume evenly distributed over a year + consumed += sum( + value(M.ConstructionInput[r, c, S_t, p]) * M.V_NewCapacity[r, S_t, p] + for S_t in M.capacityConsumptionTechs[r, p, c] + ) / M.PeriodLength[p] + + if (r, p, c) in M.commodityUStreamProcess: + # Includes output from storage + produced += sum( + M.V_FlowOut[r, p, S_s, S_d, S_i, S_t, S_v, c] + for S_s in M.time_season[p] + for S_d in M.time_of_day + for S_t, S_v in M.commodityUStreamProcess[r, p, c] + if S_t not in M.tech_annual + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + ) - produced_annual = sum( - M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, c] - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t in M.tech_annual - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] - ) + produced += sum( + M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, c] + for S_t, S_v in M.commodityUStreamProcess[r, p, c] + if S_t in M.tech_annual + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + ) + + if c in M.flex_commodities: + consumed += sum( + M.V_Flex[r, p, S_s, S_d, S_i, S_t, S_v, c] + for S_s in M.time_season[p] + for S_d in M.time_of_day + for S_t, S_v in M.commodityUStreamProcess[r, p, c] + if S_t not in M.tech_annual and S_t in M.tech_flex + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + ) + consumed += sum( + M.V_FlexAnnual[r, p, S_i, S_t, S_v, c] + for S_t, S_v in M.commodityUStreamProcess[r, p, c] + if S_t in M.tech_flex and S_t in M.tech_annual + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + ) + + if (r, p, c) in M.retirementProductionProcesses: + # Produced by retiring capacity + # Assume evenly distributed over a year + produced += sum( + value(M.EndOfLifeOutput[r, S_t, S_v, c]) * M.V_AnnualRetirement[r, p, S_t, S_v] + for S_t, S_v in M.retirementProductionProcesses[r, p, c] + ) # export of commodity c from region r to other regions - exported = 0 if (r, p, c) in M.exportRegions: - exported = sum( + consumed += sum( M.V_FlowOut[r + '-' + S_r, p, S_s, S_d, c, S_t, S_v, S_o] / get_variable_efficiency(M, r + '-' + S_r, p, S_s, S_d, c, S_t, S_v, S_o) for S_s in M.time_season[p] for S_d in M.time_of_day for S_r, S_t, S_v, S_o in M.exportRegions[r, p, c] + if S_t not in M.tech_annual + ) + consumed += sum( + M.V_FlowOutAnnual[r + '-' + S_r, p, c, S_t, S_v, S_o] + / M.Efficiency[r + '-' + S_r, c, S_t, S_v, S_o] + for S_r, S_t, S_v, S_o in M.exportRegions[r, p, c] + if S_t in M.tech_annual ) # import of commodity c from other regions into region r - imported = 0 if (r, p, c) in M.importRegions: - imported = sum( + produced += sum( M.V_FlowOut[S_r + '-' + r, p, S_s, S_d, S_i, S_t, S_v, c] for S_s in M.time_season[p] for S_d in M.time_of_day for S_r, S_t, S_v, S_i in M.importRegions[r, p, c] + if S_t not in M.tech_annual ) - - flex_waste = 0 - flex_waste_annual = 0 - if c in M.commodity_flex: - flex_waste = sum( - M.V_Flex[r, p, S_s, S_d, S_i, S_t, S_v, c] - for S_s in M.time_season[p] - for S_d in M.time_of_day - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t not in M.tech_annual and S_t in M.tech_flex - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] - ) - flex_waste_annual = sum( - M.V_FlexAnnual[r, p, S_i, S_t, S_v, c] - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t in M.tech_flex and S_t in M.tech_annual - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + produced += sum( + M.V_FlowOutAnnual[r + '-' + S_r, p, S_i, S_t, S_v, c] + for S_r, S_t, S_v, S_i in M.importRegions[r, p, c] + if S_t in M.tech_annual ) - supplied = produced + produced_annual + imported - demanded = stored + consumed + consumed_annual + exported + flex_waste + flex_waste_annual - AnnualCommodityBalanceConstraintErrorCheck( - supplied, - demanded, + produced, + consumed, r, p, c, ) - expr = supplied == demanded + expr = produced == consumed return expr @@ -1685,13 +1795,22 @@ def EmissionLimit_Constraint(M: 'TemoaModel', r, p, e): embodied_emissions = sum( M.V_NewCapacity[reg, t, v] * value(M.EmissionEmbodied[reg, e, t, v]) + / value(M.PeriodLength[v]) for reg in regions for (S_r, S_e, t, v) in M.EmissionEmbodied.sparse_iterkeys() if v == p and S_r == reg and S_e == e ) + retirement_emissions = sum( + M.V_AnnualRetirement[reg, p, t, v] + * value(M.EmissionEndOfLife[reg, e, t, v]) + for reg in regions + for (S_r, S_e, t, v) in M.EmissionEndOfLife.sparse_iterkeys() + if p in M.retirementPeriods[r, t, v] and S_r == reg and S_e == e + ) + expr = ( - process_emissions + process_emissions_annual + embodied_emissions + process_emissions + process_emissions_annual + embodied_emissions + retirement_emissions # + emissions_flex # NO! flex is subtracted from flowout, already accounted by flowout # + emissions_curtail # NO! curtailed flows are not actual flows, just an accounting tool # + emissions_flex_annual # NO! flexannual is subtracted from flowoutannual, already accounted @@ -3180,9 +3299,9 @@ def RenewablePortfolioStandard_Constraint(M: 'TemoaModel', r, p, g): # --------------------------------------------------------------- def ParamModelProcessLife_rule(M: 'TemoaModel', r, p, t, v): life_length = value(M.LifetimeProcess[r, t, v]) - tpl = min(v + life_length - p, value(M.PeriodLength[p])) + mpl = min(v + life_length - p, value(M.PeriodLength[p])) - return tpl + return mpl def ParamPeriodLength(M: 'TemoaModel', p): diff --git a/tests/conftest.py b/tests/conftest.py index 12f7ecf44..8f1929e07 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -74,6 +74,7 @@ def refresh_databases() -> None: ('storageville.sql', 'storageville.sqlite'), ('mediumville.sql', 'mediumville.sqlite'), ('emissions.sql', 'emissions.sqlite'), + ('materials.sql', 'materials.sqlite'), ('simple_linked_tech.sql', 'simple_linked_tech.sqlite'), ) for src, db in databases: diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index 276c21923..c0b23b6b9 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -44,14 +44,14 @@ class ExpectedVals(Enum): ExpectedVals.OBJ_VALUE: 491977.7000753, ExpectedVals.EFF_DOMAIN_SIZE: 30720, ExpectedVals.EFF_INDEX_SIZE: 74, - ExpectedVals.CONSTR_COUNT: 2828, # increased by 2 when reworking storageinit - ExpectedVals.VAR_COUNT: 1898, # reduced by 6 when reworking storageinit + ExpectedVals.CONSTR_COUNT: 2834, # increased by 2 when reworking storageinit. Increased after making annualretirement derived var + ExpectedVals.VAR_COUNT: 1904, # reduced by 6 when reworking storageinit. Increased after making annualretirement derived var }, 'utopia': { ExpectedVals.OBJ_VALUE: 36468.56, # reduced after reworking storageinit -> storage was less constrained ExpectedVals.EFF_DOMAIN_SIZE: 12312, ExpectedVals.EFF_INDEX_SIZE: 64, - ExpectedVals.CONSTR_COUNT: 1452, # reduced 3/27: unlim_cap techs now employed - ExpectedVals.VAR_COUNT: 1051, # reduced 3/27: unlim_cap techs now employed. Reduced by 4 storageinit + ExpectedVals.CONSTR_COUNT: 1471, # reduced 3/27: unlim_cap techs now employed. Increased after making annualretirement derived var + ExpectedVals.VAR_COUNT: 1070, # reduced 3/27: unlim_cap techs now employed. Reduced by 4 storageinit. Increased after making annualretirement derived var }, } diff --git a/tests/test_emission_results.py b/tests/test_emission_results.py index e212174dc..cd72c6eca 100644 --- a/tests/test_emission_results.py +++ b/tests/test_emission_results.py @@ -70,10 +70,12 @@ def solved_connection(request, tmp_path_factory): {'name': 'annual flex archetype', 'tech': 'TechAnnualFlex', 'target': 1.0}, {'name': 'total', 'tech': '%', 'target': 3.6}, ] - embodied_tests = [ {'name': 'embodied archetype', 'tech': 'TechEmbodied', 'target': 0.3}, ] +eol_tests = [ + {'name': 'end of life archetype', 'tech': 'TechEndOfLife', 'target': 0.3}, +] # Emissions @@ -90,7 +92,7 @@ def test_emissions(solved_connection): con, name, tech, emis_target = solved_connection emis = ( con.cursor() - .execute(f"SELECT SUM(emission) FROM main.OutputEmission WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied'") + .execute(f"SELECT SUM(emission) FROM main.OutputEmission WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied' AND period == 2000") .fetchone()[0] ) assert emis == pytest.approx( @@ -112,7 +114,7 @@ def test_emissions_costs_undiscounted(solved_connection): con, name, tech, emis_target = solved_connection ec = ( con.cursor() - .execute(f"SELECT SUM(emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied'") + .execute(f"SELECT SUM(emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied' AND period == 2000") .fetchone()[0] ) cost_target = 0.7 * emis_target * 5 # emission cost x emissions x 5y @@ -135,7 +137,7 @@ def test_emissions_costs_discounted(solved_connection): con, name, tech, emis_target = solved_connection ec = ( con.cursor() - .execute(f"SELECT SUM(d_emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied'") + .execute(f"SELECT SUM(d_emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied' AND period == 2000") .fetchone()[0] ) cost_target = ( @@ -160,11 +162,11 @@ def test_embodied_emissions(solved_connection): con, name, tech, emis_target = solved_connection emis = ( con.cursor() - .execute(f"SELECT SUM(emission) FROM main.OutputEmission WHERE tech LIKE '{tech}'") + .execute(f"SELECT SUM(emission) FROM main.OutputEmission WHERE tech LIKE '{tech}' AND period == 2000") .fetchone()[0] ) assert emis == pytest.approx( - emis_target + emis_target/5 # embodied emissions are distributed over vintage period ), f'{name} embodied emissions were incorrect. Should be {emis_target}, got {emis}' @@ -182,7 +184,7 @@ def test_embodied_emissions_costs_undiscounted(solved_connection): con, name, tech, emis_target = solved_connection ec = ( con.cursor() - .execute(f"SELECT SUM(emiss) FROM main.OutputCost WHERE tech LIKE '{tech}'") + .execute(f"SELECT SUM(emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND period == 2000") .fetchone()[0] ) cost_target = 0.7 * emis_target # emission cost x embodied emissions @@ -205,12 +207,82 @@ def test_embodied_emissions_costs_discounted(solved_connection): con, name, tech, emis_target = solved_connection ec = ( con.cursor() - .execute(f"SELECT SUM(d_emiss) FROM main.OutputCost WHERE tech LIKE '{tech}'") + .execute(f"SELECT SUM(d_emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND period == 2000") + .fetchone()[0] + ) + cost_target = ( + 0.7 * emis_target * 1/5 * (1.05**5-1)/(0.05*1.05**5) * 1.05 + ) # emission cost x embodied emissions x annual distribution x P/A(5%, 5y, 1) [x F/P(5%, 1y) legacy bug?] + assert ec == pytest.approx( + cost_target + ), f'{name} discounted emission costs were incorrect. Should be {cost_target}, got {ec}' + + +# End of life emissions +@pytest.mark.parametrize( + 'solved_connection', + argvalues=eol_tests, + indirect=True, + ids=[t['name'] for t in eol_tests], +) +def test_endoflife_emissions(solved_connection): + """ + Test that the end of life emissions from each technology archetype are correct, and check total emissions + """ + con, name, tech, emis_target = solved_connection + emis = ( + con.cursor() + .execute(f"SELECT SUM(emission) FROM main.OutputEmission WHERE tech LIKE '{tech}' AND period == 2005") + .fetchone()[0] + ) + assert emis == pytest.approx( + emis_target/5 # end of life emissions are distributed over vintage period + ), f'{name} end of life emissions were incorrect. Should be {emis_target}, got {emis}' + + +# End of life emission costs undiscounted +@pytest.mark.parametrize( + 'solved_connection', + argvalues=eol_tests, + indirect=True, + ids=[t['name'] for t in eol_tests], +) +def test_endoflife_emissions_costs_undiscounted(solved_connection): + """ + Test that the undiscounted end of life emission costs from each technology archetype are correct + """ + con, name, tech, emis_target = solved_connection + ec = ( + con.cursor() + .execute(f"SELECT SUM(emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND period == 2005") + .fetchone()[0] + ) + cost_target = 0.7 * emis_target # emission cost x end of life emissions + assert ec == pytest.approx( + cost_target + ), f'{name} undiscounted end of life emission costs were incorrect. Should be {cost_target}, got {ec}' + + +# End of life emission costs discounted +@pytest.mark.parametrize( + 'solved_connection', + argvalues=eol_tests, + indirect=True, + ids=[t['name'] for t in eol_tests], +) +def test_endoflife_emissions_costs_discounted(solved_connection): + """ + Test that discounted end of life emission costs from each technology archetype are correct + """ + con, name, tech, emis_target = solved_connection + ec = ( + con.cursor() + .execute(f"SELECT SUM(d_emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND period == 2005") .fetchone()[0] ) cost_target = ( - 0.7 * emis_target / 1.05 * 1.05 - ) # emission cost x embodied emissions x P/A(5%, 1y, 1) [x F/P(5%, 1y) legacy bug?] + 0.7 * emis_target * 1/5 * (1.05**5-1)/(0.05*1.05**5) / 1.05**5 * 1.05 + ) # emission cost x end of life emissions x annual distribution x P/A(5%, 5y, 1) x P/F(5%, 1y) [x F/P(5%, 1y) legacy bug?] assert ec == pytest.approx( cost_target ), f'{name} discounted emission costs were incorrect. Should be {cost_target}, got {ec}' @@ -237,7 +309,7 @@ def test_curtailment(solved_connection): print(name, tech, curt_target) curt = ( con.cursor() - .execute(f"SELECT SUM(curtailment) FROM main.OutputCurtailment WHERE tech LIKE '{tech}'") + .execute(f"SELECT SUM(curtailment) FROM main.OutputCurtailment WHERE tech LIKE '{tech}' AND period == 2000") .fetchone()[0] ) assert curt == pytest.approx( diff --git a/tests/test_material_results.py b/tests/test_material_results.py new file mode 100644 index 000000000..70676f61b --- /dev/null +++ b/tests/test_material_results.py @@ -0,0 +1,88 @@ +""" +Test some emissions and curtailment results for some basic technology archetypes + +Written by: Ian David Elder +iandavidelder@gmail.com +Created on: 2025/05/01 + +Tools for Energy Model Optimization and Analysis (Temoa): +An open source framework for energy systems optimization modeling + +Copyright (C) 2015, NC State University + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +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 +received this license file. If not, see . +""" + +import logging +import sqlite3 +from pathlib import Path + +import pytest + +from definitions import PROJECT_ROOT +from temoa.temoa_model.temoa_sequencer import TemoaSequencer + +logger = logging.getLogger(__name__) + + +@pytest.fixture(scope='module') +def solved_connection(request, tmp_path_factory): + """ + spin up the model, solve it, and hand over a connection to the results db + """ + data_name = 'materials' + logger.info('Setting up and solving: %s', data_name) + filename = 'config_materials.toml' + options = {'silent': True, 'debug': True} + config_file = Path(PROJECT_ROOT, 'tests', 'testing_configs', filename) + tmp_path = tmp_path_factory.mktemp('data') + sequencer = TemoaSequencer( + config_file=config_file, + output_path=tmp_path, + **options, + ) + + sequencer.start() + # make connection here as in your code... + con = sqlite3.connect(sequencer.config.output_database) + yield con, request.param['name'], request.param['tech'], request.param['period'], request.param['target'] + con.close() + + +# List of tech archetypes to test and their correct flowout value +flow_tests = [ + {'name': 'lithium import', 'tech': 'LI_IMPORT', 'period': 2005, 'target': 0.199}, +] + +# Flows +@pytest.mark.parametrize( + 'solved_connection', + argvalues=flow_tests, + indirect=True, + ids=[t['name'] for t in flow_tests], +) +def test_flows(solved_connection): + """ + Test that the emissions from each technology archetype are correct, and check total emissions + """ + con, name, tech, period, flow_target = solved_connection + flow = ( + con.cursor() + .execute(f"SELECT SUM(flow) FROM main.OutputFlowOut WHERE tech == '{tech}' AND period == {period}") + .fetchone()[0] + ) + assert flow == pytest.approx( + flow_target + ), f'{name} flows were incorrect. Should be {flow_target}, got {flow}' \ No newline at end of file diff --git a/tests/test_network_model_data.py b/tests/test_network_model_data.py index 854388adf..1bb101b84 100644 --- a/tests/test_network_model_data.py +++ b/tests/test_network_model_data.py @@ -51,6 +51,11 @@ { 'name': 'basic', 'data': [ + [], # retirement techs + [ + (2020,), + (2025,), + ], # periods [(t,) for t in ['s1', 'p1', 'p2', 'p3', 'd1', 'd2']], # all commodities [ (t,) @@ -93,6 +98,11 @@ { 'name': 'bad linked tech', 'data': [ + [], # retirement techs + [ + (2020,), + (2025,), + ], # periods [(t,) for t in ['s1', 'p3', 'd1', 'd2']], # all commodities [ (t,) @@ -134,6 +144,11 @@ # 'name': 'good linked tech', 'data': [ + [], # retirement techs + [ + (2020,), + (2025,), + ], # periods [(t,) for t in ['s1', 'd1', 'd2', 's2']], # all commodities [(t,) for t in ['s1', 's2']], # sources [('R1', 2020, 'd1'), ('R1', 2020, 'd2')], # demands diff --git a/tests/testing_configs/config_materials.toml b/tests/testing_configs/config_materials.toml new file mode 100644 index 000000000..b21821b82 --- /dev/null +++ b/tests/testing_configs/config_materials.toml @@ -0,0 +1,36 @@ +# this config is used for testing in test_full_runs.py +scenario = "test run" +scenario_mode = "perfect_foresight" + +input_database = "tests/testing_outputs/materials.sqlite" +output_database = "tests/testing_outputs/materials.sqlite" +neos = false + +# solver +solver_name = "gurobi" + +# generate an excel file in the output_files folder +save_excel = false + +# save the duals in the output .sqlite database +save_duals = false + +# save a copy of the pyomo-generated lp file to the outputs folder (may be large file!) +save_lp_file = false + +# --------------------------------------------------- +# MODE OPTIONS +# options below are mode-specific and will be ignored +# if the run is not executed in that mode. +# --------------------------------------------------- +[MGA] +slack = 0.1 +iterations = 4 +weight = "integer" # currently supported: [integer, normalized] + +[myopic] +myopic_view = 2 # number of periods seen at one iteration + + + + diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index d564ed23d..3946802ae 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -120,6 +120,8 @@ INSERT INTO Commodity VALUES('annual_flex_in','s',NULL); INSERT INTO Commodity VALUES('annual_flex_null','d',NULL); INSERT INTO Commodity VALUES('embodied_in','s',NULL); INSERT INTO Commodity VALUES('embodied_out','d',NULL); +INSERT INTO Commodity VALUES('eol_in','s',NULL); +INSERT INTO Commodity VALUES('eol_out','d',NULL); CREATE TABLE CommodityType ( label TEXT @@ -131,6 +133,34 @@ INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); INSERT INTO CommodityType VALUES('s','source commodity'); +CREATE TABLE ConstructionInput +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); +CREATE TABLE EndOfLifeOutput +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) +); CREATE TABLE CostEmission ( region TEXT @@ -145,6 +175,7 @@ CREATE TABLE CostEmission PRIMARY KEY (region, period, emis_comm) ); INSERT INTO CostEmission VALUES('TestRegion',2000,'emission',0.7,NULL,NULL); +INSERT INTO CostEmission VALUES('TestRegion',2005,'emission',0.7,NULL,NULL); CREATE TABLE CostFixed ( region TEXT NOT NULL, @@ -203,6 +234,8 @@ INSERT INTO Demand VALUES('TestRegion',2000,'curtailment_out',0.3,NULL,NULL); INSERT INTO Demand VALUES('TestRegion',2000,'flex_null',0.3,NULL,NULL); INSERT INTO Demand VALUES('TestRegion',2000,'annual_flex_null',0.3,NULL,NULL); INSERT INTO Demand VALUES('TestRegion',2000,'embodied_out',0.6,NULL,NULL); +INSERT INTO Demand VALUES('TestRegion',2000,'eol_out',0.6,NULL,NULL); +INSERT INTO Demand VALUES('TestRegion',2005,'ordinary_out',0.3,NULL,NULL); CREATE TABLE DemandSpecificDistribution ( region TEXT, @@ -254,6 +287,7 @@ INSERT INTO Efficiency VALUES('TestRegion','flex_out','TechFlexNull',2000,'flex_ INSERT INTO Efficiency VALUES('TestRegion','annual_flex_out','TechFlexNull',2000,'annual_flex_null',1.0,NULL); INSERT INTO Efficiency VALUES('TestRegion','annual_flex_in','TechAnnualFlex',2000,'annual_flex_out',1.0,NULL); INSERT INTO Efficiency VALUES('TestRegion','embodied_in','TechEmbodied',2000,'embodied_out',1.0,NULL); +INSERT INTO Efficiency VALUES('TestRegion','eol_in','TechEndOfLife',2000,'eol_out',1.0,NULL); CREATE TABLE EfficiencyVariable ( region TEXT, @@ -314,6 +348,21 @@ CREATE TABLE EmissionEmbodied PRIMARY KEY (region, emis_comm, tech, vintage) ); INSERT INTO EmissionEmbodied VALUES('TestRegion','emission','TechEmbodied',2000,0.5,NULL,NULL); +CREATE TABLE EmissionEndOfLife +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +INSERT INTO EmissionEndOfLife VALUES('TestRegion','emission','TechEndOfLife',2000,0.5,NULL,NULL); CREATE TABLE ExistingCapacity ( region TEXT, @@ -380,6 +429,7 @@ CREATE TABLE LifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); +INSERT INTO LifetimeTech VALUES('TestRegion','TechEndOfLife',5,NULL); CREATE TABLE LinkedTech ( primary_region TEXT, @@ -657,6 +707,8 @@ CREATE TABLE TimeSegmentFraction ); INSERT INTO TimeSegmentFraction VALUES(2000,'S1','TOD1',0.5,NULL); INSERT INTO TimeSegmentFraction VALUES(2000,'S1','TOD2',0.5,NULL); +INSERT INTO TimeSegmentFraction VALUES(2005,'S1','TOD1',0.5,NULL); +INSERT INTO TimeSegmentFraction VALUES(2005,'S1','TOD2',0.5,NULL); CREATE TABLE StorageDuration ( region TEXT, @@ -815,6 +867,7 @@ CREATE TABLE TimePeriod INSERT INTO TimePeriod VALUES(1,1999,'e'); INSERT INTO TimePeriod VALUES(2,2000,'f'); INSERT INTO TimePeriod VALUES(3,2005,'f'); +INSERT INTO TimePeriod VALUES(4,2010,'f'); CREATE TABLE TimeSeason ( season TEXT @@ -832,6 +885,7 @@ CREATE TABLE PeriodSeasons PRIMARY KEY (period, sequence) ); INSERT INTO PeriodSeasons VALUES(2000,1,'S1',NULL); +INSERT INTO PeriodSeasons VALUES(2005,1,'S1',NULL); CREATE TABLE TimePeriodType ( label TEXT @@ -1148,6 +1202,7 @@ INSERT INTO Technology VALUES('TechCurtailment','p','energy',NULL,NULL,0,0,0,1,0 INSERT INTO Technology VALUES('TechFlexNull','p','energy',NULL,NULL,0,0,0,0,0,0,0,NULL); INSERT INTO Technology VALUES('TechAnnualFlex','p','energy',NULL,NULL,0,1,0,0,0,1,0,NULL); INSERT INTO Technology VALUES('TechEmbodied','p','energy',NULL,NULL,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('TechEndOfLife','p','energy',NULL,NULL,0,0,0,0,0,0,0,NULL); CREATE TABLE OutputCost ( scenario TEXT, diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql new file mode 100644 index 000000000..f3f7f93e0 --- /dev/null +++ b/tests/testing_data/materials.sql @@ -0,0 +1,1190 @@ +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE MetaData +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); +INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); +INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO MetaData VALUES('link_seasons',1,'Carry storage states between seasons'); +INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); +CREATE TABLE MetaDataReal +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); +CREATE TABLE OutputDualVariable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE OutputObjective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE SectorLabel +( + sector TEXT, + PRIMARY KEY (sector) +); +CREATE TABLE CapacityCredit +( + region TEXT, + period INTEGER, + tech TEXT, + vintage INTEGER, + credit REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage), + CHECK (credit >= 0 AND credit <= 1) +); +CREATE TABLE CapacityFactorProcess +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE CapacityFactorTech +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE CapacityToActivity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + c2a REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE Commodity +( + name TEXT + PRIMARY KEY, + flag TEXT + REFERENCES CommodityType (label), + description TEXT +); +INSERT INTO Commodity VALUES('ethos','s',NULL); +INSERT INTO Commodity VALUES('electricity','p',NULL); +INSERT INTO Commodity VALUES('li','a',NULL); +INSERT INTO Commodity VALUES('li_waste','a',NULL); +INSERT INTO Commodity VALUES('passenger_km','d',NULL); +CREATE TABLE CommodityType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO CommodityType VALUES('a','annual commodity'); +INSERT INTO CommodityType VALUES('p','physical commodity'); +INSERT INTO CommodityType VALUES('e','emissions commodity'); +INSERT INTO CommodityType VALUES('d','demand commodity'); +INSERT INTO CommodityType VALUES('s','source commodity'); +CREATE TABLE ConstructionInput +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); +INSERT INTO ConstructionInput VALUES('TestRegion','li','ELECTRIC_CAR',2000,1.0,NULL,NULL); +INSERT INTO ConstructionInput VALUES('TestRegion','li','ELECTRIC_CAR',2005,1.0,NULL,NULL); +CREATE TABLE EndOfLifeOutput +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) +); +INSERT INTO EndOfLifeOutput VALUES('TestRegion','ELECTRIC_CAR',2000,'li_waste',1.0,NULL,NULL); +CREATE TABLE CostEmission +( + region TEXT + REFERENCES Region (region), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT NOT NULL + REFERENCES Commodity (name), + cost REAL NOT NULL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE CostFixed +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE CostInvest +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE CostVariable +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +INSERT INTO CostVariable VALUES('TestRegion',2000,'ELEC_IMPORT',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('TestRegion',2005,'ELEC_IMPORT',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('TestRegion',2000,'LI_IMPORT',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('TestRegion',2005,'LI_IMPORT',2000,1.0,NULL,NULL); +CREATE TABLE Demand +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + commodity TEXT + REFERENCES Commodity (name), + demand REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, commodity) +); +INSERT INTO Demand VALUES('TestRegion',2000,'passenger_km',1.0,NULL,NULL); +INSERT INTO Demand VALUES('TestRegion',2005,'passenger_km',1.0,NULL,NULL); +CREATE TABLE DemandSpecificDistribution +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + demand_name TEXT + REFERENCES Commodity (name), + dsd REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), + CHECK (dsd >= 0 AND dsd <= 1) +); +CREATE TABLE LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE Efficiency +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +INSERT INTO Efficiency VALUES('TestRegion','electricity','ELECTRIC_CAR',2000,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('TestRegion','ethos','LI_IMPORT',2000,'li',1.0,NULL); +INSERT INTO Efficiency VALUES('TestRegion','ethos','ELEC_IMPORT',2000,'electricity',1.0,NULL); +INSERT INTO Efficiency VALUES('TestRegion','electricity','ELECTRIC_CAR',2005,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('TestRegion','li_waste','LI_RECYCLE',2005,'li',0.8,NULL); +INSERT INTO Efficiency VALUES('TestRegion','electricity','LI_RECYCLE',2005,'li',0.001,NULL); +CREATE TABLE EfficiencyVariable +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE EmissionActivity +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) +); +CREATE TABLE EmissionEmbodied +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE EmissionEndOfLife +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE ExistingCapacity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE TechGroup +( + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE GrowthRateMax +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE GrowthRateSeed +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + seed REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE LoanLifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE LifetimeProcess +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE LifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +INSERT INTO LifetimeTech VALUES('TestRegion','ELECTRIC_CAR',5.0,NULL); +CREATE TABLE LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE MaxActivity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + max_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE MaxCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + max_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE MaxResource +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + max_res REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE MinActivity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + min_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE MaxCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + max_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE MinCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + min_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE MinCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + min_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputFlowOut +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); +CREATE TABLE PlanningReserveMargin +( + region TEXT + PRIMARY KEY + REFERENCES Region (region), + margin REAL +); +CREATE TABLE RampDown +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE RampUp +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE Region +( + region TEXT + PRIMARY KEY, + notes TEXT +); +INSERT INTO Region VALUES('TestRegion',NULL); +CREATE TABLE TimeSegmentFraction +( + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + segfrac REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segfrac >= 0 AND segfrac <= 1) +); +INSERT INTO TimeSegmentFraction VALUES(2000,'S1','TOD1',0.5,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'S1','TOD2',0.5,NULL); +INSERT INTO TimeSegmentFraction VALUES(2005,'S1','TOD1',0.5,NULL); +INSERT INTO TimeSegmentFraction VALUES(2005,'S1','TOD2',0.5,NULL); +CREATE TABLE StorageDuration +( + region TEXT, + tech TEXT, + duration REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE StorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage) +); +CREATE TABLE TechnologyType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO TechnologyType VALUES('r','resource technology'); +INSERT INTO TechnologyType VALUES('p','production technology'); +INSERT INTO TechnologyType VALUES('pb','baseload production technology'); +INSERT INTO TechnologyType VALUES('ps','storage production technology'); +CREATE TABLE MinTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MinTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +INSERT INTO MinTechInputSplitAnnual VALUES('TestRegion',2005,'li_waste','LI_RECYCLE',0.5,''); +INSERT INTO MinTechInputSplitAnnual VALUES('TestRegion',2005,'electricity','LI_RECYCLE',0.5,NULL); +CREATE TABLE MinTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MinTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MaxTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MaxTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE TimeOfDay +( + sequence INTEGER UNIQUE, + tod TEXT + PRIMARY KEY +); +INSERT INTO TimeOfDay VALUES(1,'TOD1'); +INSERT INTO TimeOfDay VALUES(2,'TOD2'); +CREATE TABLE TimePeriod +( + sequence INTEGER UNIQUE, + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES TimePeriodType (label) +); +INSERT INTO TimePeriod VALUES(1,1999,'e'); +INSERT INTO TimePeriod VALUES(2,2000,'f'); +INSERT INTO TimePeriod VALUES(3,2005,'f'); +INSERT INTO TimePeriod VALUES(4,2010,'f'); +CREATE TABLE TimeSeason +( + season TEXT + PRIMARY KEY +); +INSERT INTO TimeSeason VALUES('S1'); +CREATE TABLE PeriodSeasons +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT + REFERENCES TimeSeason (season), + notes TEXT, + PRIMARY KEY (period, sequence) +); +INSERT INTO PeriodSeasons VALUES(2000,1,'S1',NULL); +INSERT INTO PeriodSeasons VALUES(2005,1,'S1',NULL); +CREATE TABLE TimePeriodType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO TimePeriodType VALUES('e','existing vintages'); +INSERT INTO TimePeriodType VALUES('f','future'); +CREATE TABLE MaxActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE MaxCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE MaxAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + factor REAL, + source TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech), + CHECK (factor >= 0 AND factor <= 1) +); +INSERT INTO MaxAnnualCapacityFactor VALUES('TestRegion',2000,'ELECTRIC_CAR','passenger_km',0.2,NULL,NULL); +INSERT INTO MaxAnnualCapacityFactor VALUES('TestRegion',2005,'ELECTRIC_CAR','passenger_km',0.2,NULL,NULL); +CREATE TABLE MaxNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + max_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE MaxNewCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + max_new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE MaxNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE MinActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE MinAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + factor REAL, + source TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE MinCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE MinNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + min_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE MinNewCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + min_new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE MinNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE MinNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); +CREATE TABLE MaxNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); +CREATE TABLE OutputEmission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE MinActivityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + min_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE EmissionLimit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE MaxActivityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + max_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "min_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); +CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "max_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); +CREATE TABLE RPSRequirement +( + region TEXT NOT NULL + REFERENCES Region (region), + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech_group TEXT NOT NULL + REFERENCES TechGroup (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE TechGroupMember +( + group_name TEXT + REFERENCES TechGroup (group_name), + tech TEXT + REFERENCES Technology (tech), + PRIMARY KEY (group_name, tech) +); +CREATE TABLE Technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES TechnologyType (label) +); +INSERT INTO Technology VALUES('LI_IMPORT','p','energy',NULL,NULL,1,1,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('LI_RECYCLE','p','energy',NULL,NULL,1,1,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('ELEC_IMPORT','p','energy',NULL,NULL,1,1,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('ELECTRIC_CAR','p','energy',NULL,NULL,0,0,0,0,0,0,0,NULL); +CREATE TABLE OutputCost +( + scenario TEXT, + region TEXT, + period INTEGER, + tech TEXT, + vintage INTEGER, + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES TimePeriod (period), + FOREIGN KEY (tech) REFERENCES Technology (tech) +); +COMMIT; diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 606c1cbd8..69e2faad5 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -134,6 +134,34 @@ INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); INSERT INTO CommodityType VALUES('s','source commodity'); +CREATE TABLE ConstructionInput +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); +CREATE TABLE EndOfLifeOutput +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) +); CREATE TABLE CostEmission ( region TEXT diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index e5f9a19c8..8390365a9 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -2977,6 +2977,7 @@ ] ], "RetiredCapacityVar_rptv": [], + "AnnualRetirementVar_rptv": [], "CapacityAvailableVar_rpt": [ [ "B", @@ -3846,6 +3847,34 @@ ] ], "CommodityBalanceConstraint_rpsdc": [ + [ + "B", + 2025, + "s1", + "d2", + "FusionGasFuel" + ], + [ + "B", + 2025, + "s1", + "d1", + "FusionGasFuel" + ], + [ + "B", + 2025, + "s2", + "d2", + "FusionGasFuel" + ], + [ + "B", + 2025, + "s2", + "d1", + "FusionGasFuel" + ], [ "A", 2025, diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index f3ae5dc2b..c40ce6ee9 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -123,6 +123,34 @@ INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); +CREATE TABLE ConstructionInput +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); +CREATE TABLE EndOfLifeOutput +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) +); CREATE TABLE CostEmission ( region TEXT diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index ec94f0286..2a9bbd3e1 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -124,6 +124,34 @@ INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); INSERT INTO CommodityType VALUES('s','source commodity'); +CREATE TABLE ConstructionInput +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); +CREATE TABLE EndOfLifeOutput +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) +); CREATE TABLE CostEmission ( region TEXT diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index d24811d5d..6ba6abc41 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -192,7 +192,7 @@ INSERT INTO Commodity VALUES('OIL','p','crude oil'); INSERT INTO Commodity VALUES('NG','p','natural gas'); INSERT INTO Commodity VALUES('URN','p','uranium'); INSERT INTO Commodity VALUES('ETH','p','ethanol'); -INSERT INTO Commodity VALUES('SOL','p','solar insolation'); +INSERT INTO Commodity VALUES('SOL','s','solar insolation'); INSERT INTO Commodity VALUES('GSL','p','gasoline'); INSERT INTO Commodity VALUES('DSL','p','diesel'); INSERT INTO Commodity VALUES('ELC','p','electricity'); @@ -211,6 +211,34 @@ INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); +CREATE TABLE ConstructionInput +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); +CREATE TABLE EndOfLifeOutput +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) +); CREATE TABLE CostEmission ( region TEXT diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index a8b200b7d..77d8d1353 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -155,7 +155,8 @@ "E10" ], "commodity_source": [ - "ethos" + "ethos", + "SOL" ], "commodity_annual": [], "commodity_carrier": [ @@ -189,196 +190,189 @@ ], "CapacityFactor_rpsdt": [ [ - "R2", - 2025, - "winter", + "R1", + 2030, + "spring", "night", - "R_EH" + "E_NUCLEAR" ], [ - "R2", - 2020, - "winter", + "R1", + 2030, + "spring", "day", - "S_IMPNG" + "E_SOLPV" ], [ - "R2", - 2030, - "summer", + "R1", + 2020, + "spring", "night", - "T_DSL" + "T_EV" ], [ "R2", - 2030, - "winter", + 2025, + "spring", "night", - "S_IMPNG" + "T_DSL" ], [ - "R1", + "R2", 2020, - "spring", + "fall", "night", - "E_SOLPV" + "R_NGH" ], [ - "R1", - 2025, - "fall", - "day", + "R2", + 2020, + "summer", + "night", "E_BATT" ], [ - "R1-R2", - 2025, + "R1", + 2030, "winter", - "night", - "E_TRANS" + "day", + "T_DSL" ], [ "R1", 2025, - "winter", - "day", + "summer", + "night", "R_NGH" ], [ - "R2", + "R1", 2020, - "summer", + "winter", "night", - "S_IMPETH" + "T_DSL" ], [ - "R2", - 2025, - "summer", + "R1", + 2020, + "spring", "day", - "E_SOLPV" + "T_GSL" ], [ "R2", - 2025, + 2020, "summer", - "night", + "day", "E_NGCC" ], [ "R1", - 2030, - "summer", - "night", - "S_OILREF" - ], - [ - "R1", - 2030, - "summer", + 2025, + "spring", "night", - "S_IMPNG" + "T_DSL" ], [ "R2", - 2030, - "winter", + 2020, + "summer", "night", - "E_BATT" + "T_GSL" ], [ "R2", 2020, - "summer", + "fall", "day", "S_OILREF" ], [ - "R2", + "R1", 2020, "summer", "day", - "S_IMPNG" - ], - [ - "R1", - 2025, - "winter", - "night", - "R_EH" + "S_OILREF" ], [ - "R1", - 2030, - "fall", + "R2", + 2020, + "spring", "night", - "T_DSL" + "T_BLND" ], [ "R2", 2020, - "spring", + "fall", "night", - "E_SOLPV" + "E_NUCLEAR" ], [ - "R1", + "R2", 2020, - "spring", + "fall", "day", - "T_EV" + "E_SOLPV" ], [ "R1", 2020, "summer", "day", - "T_EV" + "E_SOLPV" ], [ "R1", 2025, - "spring", - "day", + "summer", + "night", "R_EH" ], [ - "R1", - 2025, + "R2", + 2030, "fall", "night", - "S_IMPOIL" + "T_BLND" ], [ "R1", 2025, "summer", - "day", - "E_SOLPV" + "night", + "E_NUCLEAR" ], [ "R1", 2030, - "spring", + "winter", "night", - "E_NUCLEAR" + "E_NGCC" ], [ "R1", 2025, "fall", - "day", + "night", "E_NGCC" ], [ "R2", - 2025, + 2020, "winter", - "day", - "R_NGH" + "night", + "T_GSL" ], [ - "R1", + "R2-R1", + 2030, + "winter", + "night", + "E_TRANS" + ], + [ + "R2", 2030, "summer", "night", @@ -387,716 +381,786 @@ [ "R2", 2030, - "fall", + "spring", "night", - "T_EV" + "E_BATT" ], [ "R1", - 2020, + 2030, "winter", - "night", - "R_NGH" + "day", + "E_BATT" ], [ "R2", - 2030, - "summer", + 2020, + "winter", "day", - "R_NGH" + "T_EV" ], [ "R2", 2030, - "spring", - "night", - "T_EV" + "summer", + "day", + "E_NGCC" ], [ - "R1-R2", - 2030, + "R1", + 2025, "fall", "night", - "E_TRANS" + "T_EV" ], [ - "R1", + "R2", 2025, "spring", - "night", - "T_DSL" + "day", + "E_NGCC" ], [ "R1", - 2025, - "fall", - "night", - "T_GSL" + 2020, + "summer", + "day", + "R_NGH" ], [ "R2", 2030, - "winter", - "day", - "S_IMPURN" + "summer", + "night", + "T_GSL" ], [ - "R1", + "R2", 2030, "spring", "night", - "E_BATT" + "T_GSL" ], [ - "R2", - 2025, - "fall", + "R1", + 2020, + "winter", "day", - "S_IMPOIL" + "E_NGCC" ], [ "R1", 2025, - "fall", - "night", - "T_BLND" + "spring", + "day", + "E_NGCC" ], [ - "R1", + "R1-R2", 2020, "spring", "night", - "S_IMPOIL" + "E_TRANS" ], [ - "R2", + "R1", 2020, - "spring", + "summer", "day", - "T_EV" + "R_EH" ], [ - "R2", - 2025, - "spring", - "night", - "S_IMPURN" + "R1", + 2030, + "summer", + "day", + "S_OILREF" ], [ - "R2", - 2025, + "R1", + 2020, "fall", - "day", - "T_GSL" + "night", + "E_SOLPV" ], [ - "R2", - 2025, - "spring", + "R1", + 2030, + "summer", "day", "E_SOLPV" ], [ "R1", - 2030, + 2020, "fall", "day", "R_NGH" ], [ - "R1", - 2025, + "R2", + 2030, "winter", "day", - "T_EV" + "T_DSL" ], [ "R2", - 2030, - "spring", - "day", + 2025, + "summer", + "night", "T_DSL" ], [ - "R1", - 2020, - "fall", + "R2", + 2025, + "spring", "night", - "E_NGCC" + "T_EV" ], [ "R1", - 2030, - "summer", - "day", - "S_IMPURN" + 2020, + "winter", + "night", + "T_EV" ], [ "R2", - 2030, - "summer", + 2025, + "winter", "night", - "E_SOLPV" + "T_DSL" ], [ "R1", + 2025, + "spring", + "night", + "T_EV" + ], + [ + "R2-R1", 2020, "spring", "night", - "T_GSL" + "E_TRANS" ], [ - "R2", - 2025, - "summer", + "R1", + 2020, + "fall", "day", - "S_IMPOIL" + "R_EH" ], [ - "R2", - 2025, + "R1", + 2020, "fall", "day", - "T_BLND" + "E_NUCLEAR" ], [ - "R1", + "R2", 2030, "winter", "night", "E_NGCC" ], [ - "R1-R2", - 2030, - "spring", + "R2", + 2020, + "summer", "night", - "E_TRANS" + "T_BLND" ], [ - "R2-R1", + "R1-R2", 2025, - "winter", + "fall", "day", "E_TRANS" ], [ - "R2", + "R1", 2025, - "summer", + "winter", "night", - "S_IMPURN" + "T_DSL" ], [ - "R1", + "R2", 2020, + "spring", + "night", + "R_NGH" + ], + [ + "R1-R2", + 2030, "summer", "day", - "E_NUCLEAR" + "E_TRANS" ], [ "R1", - 2020, - "spring", + 2030, + "fall", + "day", + "T_DSL" + ], + [ + "R2", + 2030, + "fall", "night", - "T_BLND" + "R_NGH" ], [ "R2", 2025, "summer", "day", - "T_GSL" + "E_NGCC" ], [ "R2", - 2020, - "spring", + 2025, + "winter", "night", - "S_IMPOIL" + "E_BATT" ], [ "R2", - 2020, + 2025, "fall", "day", - "E_NGCC" + "S_OILREF" ], [ - "R1", - 2020, + "R2", + 2030, "summer", "night", - "T_GSL" + "T_BLND" ], [ - "R1-R2", - 2025, + "R2", + 2020, "spring", - "day", - "E_TRANS" + "night", + "R_EH" ], [ - "R1", - 2030, + "R2", + 2020, "spring", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2025, + "summer", "day", "E_NGCC" ], [ - "R1", + "R2", 2030, - "spring", + "fall", "night", + "R_EH" + ], + [ + "R2", + 2025, + "winter", + "day", "E_NGCC" ], [ "R2", 2030, - "spring", + "fall", "night", "E_NUCLEAR" ], [ "R1", - 2020, + 2030, "summer", - "day", - "E_BATT" + "night", + "E_NUCLEAR" ], [ - "R2", - 2025, - "summer", + "R1", + 2030, + "winter", "day", "T_BLND" ], [ "R1", 2025, - "summer", - "day", - "S_IMPOIL" + "winter", + "night", + "E_BATT" ], [ - "R2", + "R1", + 2030, + "fall", + "night", + "E_NGCC" + ], + [ + "R1", 2025, - "winter", + "fall", "day", - "T_EV" + "S_OILREF" ], [ - "R2", + "R1", 2020, - "fall", + "winter", "night", - "T_GSL" + "T_BLND" ], [ "R2", 2030, "winter", - "day", - "S_IMPETH" + "night", + "T_GSL" ], [ - "R2", - 2020, + "R1", + 2025, "spring", "night", - "T_GSL" + "T_BLND" ], [ "R1", 2025, "fall", + "day", + "E_SOLPV" + ], + [ + "R1", + 2025, + "winter", + "day", + "E_NGCC" + ], + [ + "R1-R2", + 2020, + "winter", "night", - "S_OILREF" + "E_TRANS" ], [ - "R2", + "R1", 2030, - "summer", + "fall", "day", - "T_EV" + "E_BATT" ], [ "R1", 2025, "summer", "night", - "E_SOLPV" + "T_DSL" ], [ - "R1-R2", + "R2", 2030, - "summer", + "winter", "day", - "E_TRANS" + "T_EV" ], [ "R2", 2025, - "winter", - "night", + "fall", + "day", "R_NGH" ], [ "R2", - 2020, - "spring", - "day", - "E_NUCLEAR" - ], - [ - "R2-R1", - 2020, - "winter", - "night", - "E_TRANS" - ], - [ - "R1", 2025, - "fall", + "summer", "night", - "E_NUCLEAR" + "T_EV" ], [ - "R2", + "R1", 2020, "spring", - "night", - "T_BLND" + "day", + "S_OILREF" ], [ "R1", 2025, - "summer", + "fall", "day", - "T_GSL" + "R_NGH" ], [ "R2", 2025, "fall", - "night", - "S_IMPETH" + "day", + "R_EH" ], [ - "R1", + "R2", 2020, "winter", - "day", - "R_EH" + "night", + "S_OILREF" ], [ "R2", - 2025, - "spring", + 2020, + "winter", "night", - "S_IMPETH" + "E_SOLPV" ], [ - "R2", + "R1", 2025, "fall", - "night", - "E_SOLPV" + "day", + "R_EH" ], [ "R1", - 2020, - "fall", + 2030, + "spring", "night", - "T_DSL" + "E_NGCC" ], [ "R1", - 2025, - "summer", + 2020, + "spring", "day", - "T_BLND" + "R_NGH" ], [ - "R2", - 2030, - "fall", + "R1", + 2020, + "summer", "day", "T_DSL" ], [ "R2", - 2030, - "winter", + 2020, + "summer", "night", - "S_IMPURN" + "R_NGH" ], [ - "R2", - 2025, + "R1", + 2030, "fall", "day", - "S_OILREF" + "T_EV" ], [ "R1", 2030, - "summer", + "spring", "day", - "S_IMPETH" + "E_BATT" ], [ - "R1", - 2025, - "fall", - "night", - "E_BATT" + "R2", + 2020, + "winter", + "day", + "E_NUCLEAR" ], [ - "R1", - 2030, + "R2", + 2020, "winter", "night", - "T_DSL" + "R_NGH" ], [ "R1", 2020, "spring", - "night", - "S_OILREF" + "day", + "R_EH" ], [ "R2", - 2025, - "spring", + 2030, + "winter", "day", - "S_IMPOIL" + "T_BLND" ], [ - "R1", - 2030, - "fall", - "day", - "T_EV" + "R2", + 2020, + "summer", + "night", + "R_EH" ], [ "R2", + 2020, + "summer", + "night", + "E_NUCLEAR" + ], + [ + "R1-R2", 2025, - "fall", + "spring", "day", - "E_NUCLEAR" + "E_TRANS" ], [ "R2", - 2025, - "summer", + 2020, + "fall", "night", - "S_IMPETH" + "E_NGCC" ], [ "R1", - 2020, + 2030, "spring", "day", - "E_NGCC" + "T_GSL" ], [ "R1", 2020, "summer", - "day", + "night", "E_NGCC" ], [ "R1", - 2025, + 2030, "winter", "night", - "R_NGH" + "S_OILREF" ], [ - "R2-R1", - 2030, - "summer", + "R2", + 2025, + "winter", "night", - "E_TRANS" + "T_BLND" ], [ "R1", 2020, - "spring", + "fall", + "day", + "T_DSL" + ], + [ + "R2", + 2020, + "winter", "night", - "E_NUCLEAR" + "R_EH" ], [ "R2", - 2025, + 2030, "summer", "night", - "E_SOLPV" + "R_NGH" ], [ - "R2", + "R1", 2020, - "fall", + "summer", "day", - "T_DSL" + "E_BATT" ], [ "R1", 2030, - "spring", - "day", - "T_DSL" + "winter", + "night", + "E_SOLPV" ], [ "R2", - 2025, - "spring", + 2020, + "fall", "day", - "T_GSL" + "E_BATT" ], [ "R2", - 2025, - "summer", - "day", - "S_OILREF" + 2020, + "fall", + "night", + "T_EV" ], [ - "R1", + "R2", 2030, - "summer", + "spring", "night", - "S_IMPURN" + "R_NGH" ], [ "R1", - 2020, - "fall", + 2030, + "winter", "day", - "T_GSL" + "R_NGH" ], [ - "R2", - 2030, - "fall", + "R1", + 2025, + "summer", "night", - "E_NGCC" + "T_EV" + ], + [ + "R1", + 2025, + "winter", + "night", + "T_BLND" ], [ "R2", 2025, - "fall", + "spring", "day", - "E_BATT" + "S_OILREF" ], [ - "R1", - 2020, + "R2", + 2030, "summer", "night", - "S_OILREF" + "R_EH" ], [ "R2", 2020, - "winter", + "fall", "day", - "R_EH" + "T_GSL" ], [ "R2", - 2020, + 2030, "summer", "night", - "S_IMPNG" + "E_NUCLEAR" ], [ - "R2", - 2020, - "summer", + "R2-R1", + 2030, + "fall", "day", - "S_IMPURN" + "E_TRANS" ], [ - "R1-R2", + "R2", 2025, "spring", "night", - "E_TRANS" + "E_NUCLEAR" ], [ - "R1", + "R2", 2025, "spring", "day", - "R_NGH" + "E_SOLPV" ], [ "R2", 2030, - "summer", + "spring", "night", - "T_GSL" + "R_EH" ], [ - "R2", + "R1", 2030, - "spring", - "night", - "E_NGCC" + "fall", + "day", + "T_BLND" ], [ "R1", - 2020, - "spring", - "night", - "E_BATT" + 2030, + "winter", + "day", + "E_NUCLEAR" ], [ - "R2", - 2025, - "summer", + "R1", + 2020, + "winter", "day", - "E_NUCLEAR" + "S_OILREF" ], [ - "R2", + "R1", 2025, "spring", "day", - "T_BLND" + "S_OILREF" ], [ "R1", 2020, - "summer", + "winter", "night", "E_NUCLEAR" ], [ - "R2", + "R1", 2020, - "fall", - "night", - "S_OILREF" - ], + "winter", + "day", + "E_SOLPV" + ], [ - "R2", - 2030, - "summer", + "R1", + 2025, + "spring", "night", - "T_BLND" + "E_NUCLEAR" + ], + [ + "R1", + 2025, + "spring", + "day", + "E_SOLPV" ], [ "R2", 2020, "spring", "night", - "S_OILREF" + "T_DSL" ], [ "R2-R1", @@ -1105,228 +1169,172 @@ "day", "E_TRANS" ], - [ - "R1", - 2025, - "fall", - "day", - "E_SOLPV" - ], [ "R2", - 2020, + 2030, "fall", "night", - "E_NUCLEAR" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_EV" + "T_DSL" ], [ - "R2", + "R1-R2", 2020, - "spring", + "summer", "day", - "E_NGCC" + "E_TRANS" ], [ - "R2", - 2025, + "R1", + 2020, "summer", "day", - "E_BATT" + "T_EV" ], [ - "R2", - 2020, + "R2-R1", + 2030, "spring", - "night", - "E_NUCLEAR" + "day", + "E_TRANS" ], [ "R1", 2020, - "summer", + "fall", "night", "E_BATT" ], [ "R1", - 2025, - "summer", - "day", - "S_OILREF" - ], - [ - "R2", - 2020, + 2030, "summer", "day", - "R_EH" - ], - [ - "R1", - 2025, - "summer", - "night", - "S_IMPOIL" + "E_BATT" ], [ "R1", - 2030, + 2020, "fall", "night", "T_GSL" ], - [ - "R2", - 2025, - "winter", - "night", - "T_EV" - ], [ "R2", 2030, "winter", "night", - "S_IMPETH" + "S_OILREF" ], [ "R1", - 2025, + 2030, "summer", "day", - "E_NUCLEAR" + "T_GSL" ], [ - "R2", - 2020, - "fall", + "R2-R1", + 2025, + "winter", "night", - "E_BATT" + "E_TRANS" ], [ - "R2", + "R2-R1", 2020, - "spring", - "night", - "E_BATT" - ], - [ - "R2", - 2025, "fall", "night", - "S_IMPOIL" + "E_TRANS" ], [ "R1", - 2020, + 2030, "spring", "day", - "T_DSL" - ], - [ - "R1", - 2025, - "summer", - "day", - "E_BATT" - ], - [ - "R1", - 2025, - "summer", - "night", "T_BLND" ], [ "R2", 2030, - "fall", + "winter", "night", - "T_DSL" + "E_SOLPV" ], [ "R1", 2020, "fall", - "night", - "E_SOLPV" + "day", + "T_EV" ], [ - "R1", + "R2", 2025, - "winter", - "night", - "T_EV" + "fall", + "day", + "T_DSL" ], [ "R2", - 2025, + 2020, "spring", "day", - "S_OILREF" + "E_NGCC" ], [ "R1", 2025, - "spring", - "night", - "T_GSL" + "fall", + "day", + "T_DSL" ], [ "R2", - 2030, - "spring", + 2025, + "winter", "night", - "T_DSL" + "R_NGH" ], [ "R2", - 2020, + 2025, "summer", "day", - "S_IMPETH" - ], - [ - "R1", - 2020, - "fall", - "day", "S_OILREF" ], [ - "R1", + "R2", 2030, - "summer", - "night", - "S_IMPETH" + "winter", + "day", + "E_NUCLEAR" ], [ "R2", 2025, "summer", "night", - "S_IMPOIL" + "E_NUCLEAR" ], [ - "R2", + "R1-R2", 2030, - "summer", - "night", - "S_OILREF" + "spring", + "day", + "E_TRANS" ], [ "R1", - 2030, - "winter", - "night", + 2020, + "summer", + "day", + "T_BLND" + ], + [ + "R2", + 2025, + "summer", + "day", "E_SOLPV" ], [ @@ -1334,88 +1342,81 @@ 2025, "fall", "night", - "T_BLND" + "E_NGCC" ], [ - "R2", + "R1", 2025, - "spring", - "day", - "E_NUCLEAR" + "winter", + "night", + "R_NGH" ], [ "R1", - 2020, + 2030, "summer", "night", "E_NGCC" ], [ "R1", - 2020, - "fall", + 2025, + "summer", "day", - "E_NUCLEAR" + "S_OILREF" ], [ "R2", - 2030, - "summer", + 2025, + "winter", "day", - "E_NGCC" + "S_OILREF" ], [ "R1", - 2025, - "spring", - "day", - "T_EV" + 2030, + "fall", + "night", + "S_OILREF" ], [ "R2", - 2030, - "summer", + 2025, + "winter", "night", "E_NUCLEAR" ], [ "R1", - 2030, - "winter", + 2020, + "spring", "day", - "E_NUCLEAR" + "T_DSL" ], [ "R1", - 2030, - "spring", + 2025, + "summer", "day", "E_SOLPV" ], [ "R2", - 2020, - "fall", + 2025, + "winter", "day", "E_SOLPV" ], [ - "R1", + "R2", 2030, "spring", - "night", - "E_SOLPV" - ], - [ - "R2", - 2020, - "fall", - "night", + "day", "E_NGCC" ], [ "R2", - 2020, + 2030, "winter", "night", "R_EH" @@ -1423,2249 +1424,2186 @@ [ "R2", 2025, - "spring", + "fall", "day", "E_BATT" ], [ "R2", - 2030, - "spring", - "day", - "T_GSL" + 2020, + "summer", + "night", + "T_DSL" ], [ "R1", - 2020, + 2030, "fall", - "day", - "E_BATT" + "night", + "E_SOLPV" ], [ - "R1", - 2025, - "winter", - "day", - "T_DSL" + "R2", + 2020, + "spring", + "night", + "T_EV" ], [ "R2", 2030, - "summer", + "fall", "night", - "E_BATT" + "T_EV" ], [ - "R2", + "R1", 2025, - "summer", + "winter", "night", - "T_BLND" + "E_NUCLEAR" + ], + [ + "R2-R1", + 2030, + "summer", + "day", + "E_TRANS" ], [ "R1", 2025, - "fall", + "winter", "day", - "S_IMPOIL" + "E_SOLPV" ], [ "R1", - 2030, + 2025, "fall", - "night", - "S_OILREF" + "day", + "E_BATT" ], [ - "R1-R2", + "R2", 2020, "winter", "night", - "E_TRANS" + "T_DSL" ], [ - "R1", - 2025, - "fall", - "night", - "S_IMPURN" + "R2", + 2020, + "spring", + "day", + "T_GSL" ], [ - "R1", - 2020, - "winter", + "R2", + 2030, + "fall", "day", - "R_NGH" + "T_GSL" ], [ - "R2-R1", + "R1", 2020, - "summer", + "spring", "night", - "E_TRANS" + "E_NGCC" ], [ "R1", 2030, "fall", - "night", + "day", "E_NUCLEAR" ], [ - "R1", - 2025, + "R1-R2", + 2020, "fall", "day", - "T_GSL" + "E_TRANS" ], [ - "R1", + "R2", 2025, "summer", - "night", - "S_OILREF" + "day", + "R_EH" ], [ "R1", - 2025, - "summer", - "night", - "S_IMPNG" + 2020, + "spring", + "day", + "E_BATT" ], [ "R2", 2030, - "winter", - "day", - "S_IMPNG" + "summer", + "night", + "T_DSL" ], [ "R1", - 2020, - "winter", - "night", - "R_EH" + 2030, + "summer", + "day", + "T_BLND" ], [ "R1", 2025, - "fall", + "summer", "day", - "T_BLND" + "R_EH" ], [ - "R1", + "R2", 2030, - "fall", + "spring", "night", - "E_BATT" + "T_DSL" ], [ - "R2", + "R1-R2", 2025, - "fall", + "summer", "day", - "S_IMPURN" + "E_TRANS" ], [ "R2", 2025, "fall", - "night", - "S_IMPNG" - ], - [ - "R1", - 2025, - "spring", - "night", - "S_OILREF" + "day", + "T_EV" ], [ "R2", - 2025, + 2030, "spring", - "night", - "S_IMPNG" + "day", + "T_GSL" ], [ "R2", - 2025, + 2020, "winter", - "day", - "T_DSL" + "night", + "E_BATT" ], [ "R1", - 2020, + 2030, "spring", - "night", - "S_IMPURN" + "day", + "R_NGH" ], [ "R1", - 2020, + 2025, "fall", - "night", - "S_IMPOIL" + "day", + "T_EV" ], [ "R2", - 2030, - "summer", + 2020, + "winter", "day", - "T_DSL" + "E_NGCC" + ], + [ + "R1-R2", + 2030, + "winter", + "night", + "E_TRANS" ], [ "R1", - 2020, + 2030, "spring", "day", - "E_SOLPV" + "R_EH" ], [ "R1", 2020, "summer", - "day", - "E_SOLPV" + "night", + "S_OILREF" ], [ "R1", 2020, - "fall", + "spring", "day", - "E_NGCC" + "T_EV" + ], + [ + "R1", + 2020, + "summer", + "night", + "E_SOLPV" ], [ "R2", 2020, - "winter", + "fall", "day", "R_NGH" ], [ - "R1", - 2025, - "spring", + "R2", + 2020, + "summer", "night", - "E_NUCLEAR" + "T_EV" ], [ - "R1", - 2030, + "R2", + 2020, "summer", "day", - "S_IMPNG" + "T_GSL" ], [ - "R2", + "R1", 2030, "winter", "night", - "R_NGH" + "E_BATT" ], [ - "R1", - 2030, + "R2", + 2020, "winter", - "day", - "E_NGCC" + "night", + "T_EV" ], [ - "R1-R2", + "R2", 2025, - "winter", + "fall", "day", - "E_TRANS" + "T_BLND" ], [ "R2", - 2025, + 2020, + "fall", + "day", + "R_EH" + ], + [ + "R1", + 2020, "summer", "day", - "S_IMPURN" + "E_NUCLEAR" ], [ "R2", 2025, - "summer", + "spring", "night", - "S_IMPNG" + "E_NGCC" ], [ "R1", 2020, "fall", "night", - "T_GSL" + "S_OILREF" ], [ - "R2", + "R1", 2030, - "fall", + "winter", "night", - "E_SOLPV" + "T_GSL" ], [ - "R2", - 2030, + "R1", + 2025, "fall", "day", - "T_GSL" + "T_BLND" ], [ "R1", 2020, - "summer", + "winter", "night", - "S_IMPURN" + "E_NGCC" ], [ - "R2", - 2030, - "spring", + "R1", + 2025, + "fall", "night", - "E_SOLPV" + "T_GSL" ], [ "R1", 2025, "spring", "night", - "E_BATT" + "E_NGCC" ], [ "R2", 2030, - "spring", - "day", - "S_OILREF" + "summer", + "night", + "T_EV" ], [ "R2", 2025, + "spring", + "day", + "E_BATT" + ], + [ + "R1", + 2030, "winter", - "night", - "E_NGCC" + "day", + "T_EV" ], [ "R2", + 2030, + "spring", + "night", + "T_EV" + ], + [ + "R1", 2020, - "fall", + "winter", "day", - "S_IMPOIL" + "E_BATT" ], [ - "R1", + "R2", 2030, - "winter", - "night", + "summer", + "day", "T_GSL" ], [ "R1", - 2030, + 2025, "spring", - "night", - "S_IMPOIL" + "day", + "E_BATT" + ], + [ + "R2", + 2025, + "spring", + "day", + "T_GSL" ], [ "R1", 2020, - "fall", - "night", + "spring", + "day", "T_BLND" ], [ - "R2", + "R1", 2020, "fall", "night", - "S_IMPURN" + "R_NGH" ], [ - "R1", - 2025, - "fall", + "R2", + 2030, + "winter", "night", - "S_IMPETH" + "T_DSL" ], [ "R1", 2030, "summer", - "night", + "day", "R_NGH" ], [ - "R2", - 2030, - "spring", + "R2-R1", + 2025, + "summer", "day", - "E_NUCLEAR" + "E_TRANS" ], [ "R1", - 2030, - "fall", + 2020, + "winter", "day", - "T_DSL" + "T_GSL" ], [ - "R2", + "R1-R2", 2020, - "summer", + "spring", "day", - "R_NGH" + "E_TRANS" ], [ - "R2", - 2020, + "R1", + 2025, "spring", - "night", - "S_IMPURN" + "day", + "T_GSL" ], [ - "R1", - 2030, + "R2", + 2020, "winter", "night", "T_BLND" ], [ "R1", - 2030, + 2020, "fall", "night", - "E_NGCC" + "R_EH" ], [ "R1", 2030, - "spring", + "summer", "day", - "T_GSL" + "R_EH" ], [ - "R2", - 2020, + "R1", + 2030, + "summer", + "day", + "E_NUCLEAR" + ], + [ + "R1-R2", + 2025, "fall", + "night", + "E_TRANS" + ], + [ + "R2", + 2025, + "summer", "day", - "T_GSL" + "T_DSL" ], [ "R2", 2020, "spring", "day", - "E_SOLPV" + "S_OILREF" ], [ - "R1", - 2020, + "R2", + 2030, "winter", - "day", - "T_EV" + "night", + "E_BATT" ], [ - "R1", - 2025, + "R2", + 2030, "fall", "day", "S_OILREF" ], [ - "R1", + "R2-R1", 2025, "fall", "day", - "S_IMPNG" + "E_TRANS" ], [ - "R1", - 2025, - "summer", + "R2", + 2020, + "spring", "day", - "S_IMPURN" + "E_SOLPV" ], [ "R2", - 2020, + 2030, + "spring", + "night", + "T_BLND" + ], + [ + "R1-R2", + 2030, "summer", "night", - "R_EH" + "E_TRANS" ], [ "R2", 2030, - "spring", + "fall", "day", - "E_BATT" + "E_SOLPV" ], [ - "R1", + "R2", 2030, - "spring", + "winter", "day", - "T_BLND" + "E_NGCC" ], [ "R2", - 2020, - "fall", - "day", - "T_BLND" + 2025, + "summer", + "night", + "E_NGCC" ], [ - "R1", + "R2", 2025, - "winter", + "fall", "night", - "E_NGCC" + "S_OILREF" ], [ "R1", 2030, - "spring", + "summer", "night", - "T_BLND" + "S_OILREF" ], [ - "R2-R1", - 2020, - "winter", - "day", - "E_TRANS" + "R2", + 2025, + "fall", + "night", + "E_SOLPV" ], [ "R2", 2025, - "fall", + "summer", "day", - "S_IMPETH" + "E_BATT" ], [ "R1", - 2020, - "spring", + 2030, + "winter", "night", - "S_IMPETH" + "T_BLND" ], [ "R1", - 2025, + 2030, + "summer", + "night", + "E_SOLPV" + ], + [ + "R2", + 2030, "spring", "day", - "E_NGCC" + "S_OILREF" ], [ - "R1", + "R2", + 2030, + "fall", + "day", + "R_NGH" + ], + [ + "R2-R1", 2025, "spring", - "night", - "E_NGCC" + "day", + "E_TRANS" ], [ "R1", 2030, - "winter", + "spring", "day", "T_DSL" ], [ - "R1", - 2020, + "R2", + 2030, "spring", "day", - "S_IMPOIL" + "E_SOLPV" ], [ "R1", - 2020, + 2025, "summer", "day", - "S_IMPOIL" + "E_BATT" ], [ "R2", - 2020, + 2025, "winter", "day", - "T_EV" + "E_BATT" ], [ "R2", 2025, "summer", "day", - "S_IMPETH" + "T_GSL" ], [ "R2", 2025, - "spring", - "day", - "S_IMPURN" + "winter", + "night", + "T_EV" ], [ "R1", - 2020, - "summer", + 2030, + "fall", "night", - "S_IMPETH" + "E_BATT" ], [ - "R1", - 2020, - "fall", + "R2", + 2025, + "spring", "day", - "S_IMPURN" - ], - [ - "R1", - 2020, - "fall", - "night", - "S_OILREF" + "T_BLND" ], [ "R2", 2025, - "winter", - "night", - "T_DSL" + "fall", + "day", + "E_NUCLEAR" ], [ - "R1-R2", - 2030, - "winter", - "night", - "E_TRANS" + "R2", + 2020, + "spring", + "day", + "R_EH" ], [ "R2", 2030, - "summer", - "night", - "S_IMPURN" + "fall", + "day", + "R_EH" ], [ "R1", 2020, - "summer", + "spring", "night", - "E_SOLPV" + "S_OILREF" ], [ "R1", - 2030, + 2025, "winter", - "night", - "S_OILREF" + "day", + "E_BATT" ], [ - "R2", + "R1", 2030, + "fall", + "day", + "E_NGCC" + ], + [ + "R1", + 2025, "summer", "day", - "E_SOLPV" + "T_GSL" ], [ - "R2", - 2020, + "R1", + 2025, "winter", "night", - "R_NGH" + "T_EV" ], [ - "R1", + "R2-R1", 2020, - "fall", + "winter", "night", - "E_NUCLEAR" + "E_TRANS" ], [ - "R1", - 2020, - "spring", + "R2", + 2025, + "winter", "day", "T_GSL" ], [ "R1", 2020, - "summer", + "winter", "day", + "T_BLND" + ], + [ + "R1", + 2030, + "fall", + "night", "T_GSL" ], [ - "R2", + "R1", 2020, - "fall", + "spring", "night", - "S_IMPETH" + "E_SOLPV" ], [ - "R2", - 2030, + "R1", + 2025, "fall", "day", "E_NUCLEAR" ], [ - "R2", - 2030, - "spring", - "night", - "S_IMPOIL" - ], - [ - "R2", - 2030, + "R1", + 2025, "spring", "day", - "E_NGCC" + "T_BLND" ], [ "R2", 2020, - "spring", - "night", - "S_IMPETH" + "fall", + "day", + "T_DSL" ], [ - "R1-R2", - 2030, - "spring", + "R1", + 2025, + "winter", "day", - "E_TRANS" + "T_GSL" ], [ - "R1", + "R2", 2030, - "winter", - "night", - "E_NUCLEAR" + "spring", + "day", + "R_EH" ], [ "R2", 2020, - "fall", - "night", - "E_SOLPV" + "summer", + "day", + "S_OILREF" ], [ "R1", 2020, "spring", "day", - "T_BLND" + "E_NUCLEAR" ], [ - "R1", + "R2", 2020, "summer", "day", - "T_BLND" + "E_SOLPV" ], [ - "R2", - 2030, - "fall", + "R1", + 2025, + "summer", "night", - "T_GSL" + "E_NGCC" ], [ "R2", 2020, - "fall", + "winter", "day", "S_OILREF" ], [ "R1", - 2030, - "spring", - "day", + 2025, + "fall", + "night", "S_OILREF" ], [ - "R1", - 2025, - "summer", + "R2", + 2020, + "winter", + "night", + "E_NUCLEAR" + ], + [ + "R2", + 2020, + "winter", "day", - "S_IMPETH" + "E_SOLPV" ], [ "R2", 2030, - "spring", + "winter", "night", - "T_GSL" + "T_BLND" ], [ "R1", - 2030, - "spring", + 2025, + "fall", "night", - "S_IMPNG" + "E_SOLPV" ], [ - "R1", - 2020, + "R1-R2", + 2030, "fall", "night", - "E_BATT" + "E_TRANS" ], [ "R1", 2030, "spring", "night", - "S_OILREF" + "T_GSL" ], [ "R2", 2030, - "fall", + "summer", "day", - "E_BATT" + "S_OILREF" ], [ "R1", - 2025, - "winter", + 2020, + "fall", "night", "T_DSL" ], [ - "R2", - 2020, - "spring", + "R1", + 2030, + "summer", "day", - "S_IMPOIL" + "T_DSL" ], [ "R1", 2030, "spring", "day", - "E_NUCLEAR" + "T_EV" ], [ "R2", - 2020, - "fall", + 2030, + "summer", "day", - "E_NUCLEAR" + "E_SOLPV" ], [ "R1", - 2030, - "winter", + 2020, + "summer", "night", "E_BATT" ], [ - "R1", + "R2", 2030, - "fall", + "spring", "night", - "S_IMPURN" + "E_NUCLEAR" ], [ - "R2", + "R1", 2030, - "fall", + "winter", "night", - "T_BLND" + "R_NGH" ], [ "R2", - 2030, - "spring", - "night", + 2025, + "summer", + "day", "T_BLND" ], [ - "R2-R1", - 2025, + "R2", + 2020, "summer", - "night", - "E_TRANS" + "day", + "R_EH" ], [ "R1", - 2030, - "fall", + 2020, + "summer", "day", - "E_SOLPV" + "E_NGCC" ], [ - "R1", + "R2", 2025, "spring", - "day", - "T_DSL" + "night", + "S_OILREF" ], [ "R2", 2020, - "spring", - "day", + "fall", + "night", "T_GSL" ], [ "R1", - 2025, + 2020, "summer", "night", - "S_IMPURN" - ], - [ - "R1", - 2030, - "spring", - "day", - "E_BATT" - ], - [ - "R2", - 2020, - "fall", - "day", - "E_BATT" + "T_GSL" ], [ "R1", 2025, - "winter", + "summer", "day", - "T_GSL" + "T_BLND" ], [ "R2", - 2020, + 2025, "spring", - "day", - "T_BLND" + "night", + "E_SOLPV" ], [ - "R2", - 2025, - "fall", + "R1", + 2030, + "winter", "night", - "S_IMPURN" + "R_EH" ], [ "R2", 2025, "spring", "day", - "S_IMPETH" + "R_NGH" ], [ "R1", - 2020, - "fall", - "day", - "S_IMPETH" + 2030, + "winter", + "night", + "E_NUCLEAR" ], [ "R1", 2025, - "spring", - "night", - "S_IMPURN" - ], - [ - "R2", - 2030, - "summer", + "fall", "night", - "S_IMPETH" + "R_EH" ], [ "R1", 2020, - "fall", - "day", - "E_SOLPV" + "winter", + "night", + "S_OILREF" ], [ - "R2-R1", + "R1", 2030, "fall", "night", - "E_TRANS" + "T_BLND" ], [ "R2", - 2030, + 2020, "fall", "day", - "E_NGCC" + "T_EV" ], [ "R1", - 2020, + 2025, "spring", - "day", + "night", "S_OILREF" ], [ "R1", 2020, - "summer", - "day", - "S_IMPNG" + "winter", + "night", + "E_SOLPV" ], [ "R1", 2020, - "summer", + "winter", "day", - "S_OILREF" + "R_NGH" ], [ "R1", 2025, - "summer", + "spring", "night", - "R_EH" + "E_SOLPV" ], [ - "R2", - 2030, - "winter", + "R1", + 2025, + "spring", "day", - "R_EH" + "R_NGH" ], [ - "R1", + "R2", 2030, - "winter", + "summer", "day", - "E_SOLPV" + "R_EH" ], [ - "R1", + "R2-R1", 2020, "summer", "night", - "S_IMPOIL" + "E_TRANS" ], [ "R2", - 2030, - "summer", + 2025, + "spring", "day", - "S_IMPOIL" + "R_EH" ], [ "R2", - 2020, - "winter", - "night", - "T_EV" + 2025, + "spring", + "day", + "E_NUCLEAR" ], [ "R1", 2020, - "spring", + "fall", "day", - "E_NUCLEAR" + "E_NGCC" ], [ - "R2", + "R2-R1", 2030, - "fall", + "spring", "night", - "S_OILREF" + "E_TRANS" ], [ - "R2", - 2025, - "fall", - "night", + "R1", + 2020, + "winter", + "day", "R_EH" ], [ - "R2", - 2025, + "R1", + 2020, "winter", - "night", - "E_SOLPV" + "day", + "E_NUCLEAR" ], [ - "R2", - 2030, + "R1", + 2025, "spring", - "night", - "S_OILREF" + "day", + "R_EH" ], [ - "R2", + "R1", 2025, "spring", - "night", - "R_EH" + "day", + "E_NUCLEAR" ], [ - "R2", + "R1-R2", 2025, "winter", "day", - "T_GSL" + "E_TRANS" ], [ "R2", 2020, - "fall", - "night", - "S_IMPOIL" - ], - [ - "R2", - 2030, - "spring", - "night", - "S_IMPNG" - ], - [ - "R2", - 2030, "spring", "day", - "S_IMPURN" + "T_DSL" ], [ - "R1", + "R2", 2030, "fall", - "night", - "S_IMPETH" + "day", + "T_DSL" ], [ "R2", 2030, - "summer", - "day", - "T_GSL" + "winter", + "night", + "R_NGH" ], [ - "R2", - 2030, + "R1", + 2020, "fall", "night", - "E_NUCLEAR" + "T_EV" ], [ "R1", 2030, "summer", "day", - "R_EH" + "T_EV" ], [ "R2", 2020, - "summer", - "night", - "R_NGH" + "fall", + "day", + "T_BLND" ], [ - "R1", + "R2", 2020, "spring", - "day", - "E_BATT" + "night", + "E_NGCC" ], [ - "R1", + "R2-R1", 2030, "fall", "night", - "E_SOLPV" + "E_TRANS" ], [ - "R1", - 2020, - "summer", + "R2", + 2030, + "fall", "night", - "T_BLND" + "E_NGCC" ], [ "R2", 2030, - "summer", + "spring", "day", - "T_BLND" - ], - [ - "R1", - 2020, - "winter", - "night", - "T_EV" + "T_DSL" ], [ - "R1", + "R2", 2025, "summer", "night", - "S_IMPETH" + "S_OILREF" ], [ "R2", - 2020, - "spring", - "day", - "S_OILREF" + 2030, + "winter", + "night", + "E_NUCLEAR" ], [ "R2", 2020, "spring", "day", - "S_IMPNG" - ], - [ - "R1", - 2025, - "fall", - "night", - "S_IMPNG" + "E_BATT" ], [ "R2", - 2025, - "summer", - "night", - "R_EH" - ], - [ - "R1", - 2025, - "fall", + 2030, + "winter", "day", - "S_IMPURN" + "E_SOLPV" ], [ "R2", 2030, "fall", - "night", - "E_BATT" - ], - [ - "R2", - 2030, - "spring", - "night", + "day", "E_BATT" ], [ "R1", 2025, "winter", - "night", - "E_SOLPV" - ], - [ - "R2", - 2020, - "winter", "day", - "E_NGCC" + "S_OILREF" ], [ - "R2", + "R1", 2020, - "fall", + "summer", "night", "T_BLND" ], [ - "R1", - 2025, + "R1-R2", + 2030, "spring", "night", - "S_IMPETH" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_GSL" + "E_TRANS" ], [ - "R1", + "R2", 2025, - "winter", - "day", - "E_NUCLEAR" + "summer", + "night", + "E_SOLPV" ], [ - "R1", + "R2", 2025, - "spring", + "summer", "day", - "E_SOLPV" + "R_NGH" ], [ "R1", 2025, - "spring", - "night", - "E_SOLPV" + "summer", + "day", + "R_NGH" ], [ "R2", 2025, - "fall", + "winter", "day", - "S_IMPNG" + "R_NGH" ], [ "R2", - 2020, - "spring", - "day", + 2025, + "fall", + "night", "E_BATT" ], [ "R1", 2030, - "fall", - "day", - "T_BLND" + "summer", + "night", + "E_BATT" ], [ "R1", - 2025, + 2030, "fall", - "day", - "R_EH" - ], - [ - "R1", - 2020, - "spring", "night", - "S_IMPNG" + "R_NGH" ], [ "R2", - 2020, - "winter", - "night", + 2025, + "summer", + "day", "E_NUCLEAR" ], [ - "R1", - 2020, - "winter", + "R2", + 2025, + "fall", "day", - "T_DSL" + "E_NGCC" ], [ "R1", - 2020, - "fall", + 2025, + "winter", "day", - "S_IMPOIL" + "R_NGH" ], [ "R2", 2030, - "summer", - "night", - "S_IMPOIL" - ], - [ - "R1", - 2025, - "winter", + "spring", "day", "E_BATT" ], [ - "R2-R1", - 2030, - "summer", - "day", - "E_TRANS" + "R2", + 2025, + "fall", + "night", + "T_GSL" ], [ "R1", 2020, "fall", "night", - "S_IMPURN" + "T_BLND" ], [ "R1", 2030, - "winter", - "day", - "S_IMPOIL" - ], - [ - "R2", - 2030, - "spring", - "day", - "S_IMPETH" + "summer", + "night", + "T_GSL" ], [ "R2", 2025, "winter", "day", - "S_OILREF" + "R_EH" ], [ "R1", - 2030, - "winter", - "night", - "S_IMPURN" + 2025, + "summer", + "day", + "E_NUCLEAR" ], [ - "R2", + "R1", 2025, - "summer", + "fall", "day", - "S_IMPNG" + "E_NGCC" ], [ - "R2", + "R1", 2030, - "winter", + "fall", "night", "R_EH" ], [ "R1", - 2020, - "summer", + 2030, + "fall", "night", - "S_IMPNG" + "E_NUCLEAR" ], [ - "R2", - 2025, - "winter", + "R1-R2", + 2020, + "fall", "night", - "S_IMPOIL" + "E_TRANS" ], [ "R2", + 2020, + "summer", + "day", + "T_DSL" + ], + [ + "R1", 2030, "spring", + "night", + "S_OILREF" + ], + [ + "R1", + 2030, + "fall", "day", "E_SOLPV" ], [ "R2", 2030, - "summer", + "fall", "day", - "S_OILREF" - ], - [ - "R2-R1", - 2020, - "spring", - "night", - "E_TRANS" + "T_EV" ], [ - "R2", + "R1", 2025, "winter", "day", - "E_NUCLEAR" + "R_EH" ], [ "R1", 2030, - "winter", - "day", - "T_GSL" + "spring", + "night", + "E_SOLPV" ], [ "R1", 2020, - "winter", + "spring", "night", - "E_NUCLEAR" + "E_BATT" ], [ "R1", - 2020, - "fall", - "day", - "T_BLND" + 2030, + "winter", + "night", + "T_DSL" ], [ - "R2", - 2030, - "summer", - "day", - "E_NUCLEAR" + "R1", + 2025, + "fall", + "night", + "T_DSL" ], [ "R1", - 2030, + 2020, "spring", "day", - "S_IMPURN" + "E_NGCC" ], [ - "R2", + "R1", 2020, - "fall", - "day", - "S_IMPURN" + "spring", + "night", + "T_GSL" ], [ "R2", 2020, "summer", "night", - "T_EV" + "E_NGCC" ], [ "R2", 2020, "fall", "night", - "S_IMPNG" + "S_OILREF" ], [ "R1", - 2025, - "fall", + 2030, + "spring", "day", - "S_IMPETH" + "E_NUCLEAR" ], [ "R1", 2030, "spring", "night", - "S_IMPURN" + "R_NGH" ], [ "R1", - 2030, - "fall", + 2025, + "summer", "night", - "S_IMPOIL" + "S_OILREF" ], [ "R2", - 2020, - "spring", - "night", - "S_IMPNG" + 2030, + "summer", + "day", + "T_DSL" ], [ "R2", - 2020, - "winter", + 2025, + "spring", "day", "T_DSL" ], [ "R2", - 2025, - "winter", + 2020, + "fall", "night", - "T_GSL" + "E_SOLPV" ], [ "R2", - 2030, + 2020, "winter", "night", - "T_DSL" + "E_NGCC" ], [ - "R1", - 2030, - "winter", + "R2", + 2020, + "summer", "day", - "T_BLND" + "E_BATT" ], [ - "R2", + "R1", 2025, - "winter", - "day", - "E_BATT" + "summer", + "night", + "E_SOLPV" ], [ "R2-R1", - 2025, - "fall", + 2020, + "spring", "day", "E_TRANS" ], + [ + "R1", + 2020, + "winter", + "day", + "T_DSL" + ], [ "R1", 2025, - "summer", + "spring", "day", - "S_IMPNG" + "T_DSL" ], [ "R1", 2030, - "summer", + "spring", "night", "R_EH" ], [ "R2", - 2030, - "summer", + 2020, + "winter", "day", "E_BATT" ], [ - "R2", - 2025, - "winter", + "R2-R1", + 2030, + "summer", "night", - "T_BLND" + "E_TRANS" ], [ "R1", 2025, - "winter", + "fall", "night", - "S_IMPOIL" + "E_BATT" ], [ - "R1", + "R2", 2030, - "fall", - "day", - "S_OILREF" + "summer", + "night", + "E_NGCC" ], [ - "R1", - 2025, - "winter", + "R2", + 2020, + "spring", "day", - "E_NGCC" + "T_BLND" ], [ - "R1-R2", + "R2", 2020, - "winter", + "fall", "day", - "E_TRANS" + "E_NUCLEAR" ], [ "R1", - 2030, - "spring", + 2020, + "summer", "night", - "R_EH" + "R_NGH" ], [ - "R1", + "R2", 2030, "fall", "day", - "E_NUCLEAR" + "T_BLND" ], [ - "R1", + "R2", 2030, - "fall", + "spring", "night", - "T_BLND" + "E_NGCC" + ], + [ + "R1", + 2030, + "winter", + "day", + "E_NGCC" ], [ "R2", 2020, "winter", - "night", - "E_NGCC" + "day", + "T_GSL" ], [ - "R1", - 2025, - "spring", + "R2-R1", + 2030, + "winter", "day", - "S_IMPOIL" + "E_TRANS" ], [ "R2", - 2020, + 2030, "summer", "day", - "T_DSL" + "E_BATT" ], [ - "R1", - 2025, + "R1-R2", + 2030, "winter", - "night", - "T_GSL" + "day", + "E_TRANS" ], [ - "R1", + "R2", 2025, - "spring", + "fall", "night", - "S_IMPOIL" + "T_BLND" + ], + [ + "R2", + 2020, + "fall", + "night", + "R_EH" ], [ "R1", - 2025, + 2020, "summer", "night", - "R_NGH" + "R_EH" ], [ "R1", 2020, - "fall", + "summer", "night", - "S_IMPETH" + "E_NUCLEAR" ], [ - "R2", + "R1", 2030, - "winter", + "summer", + "night", + "T_BLND" + ], + [ + "R2", + 2020, + "summer", "day", - "R_NGH" + "T_EV" ], [ "R2", 2030, - "fall", + "spring", "day", - "S_IMPETH" + "T_BLND" ], [ - "R1", + "R2", 2025, - "winter", + "spring", "night", - "T_BLND" + "E_BATT" ], [ "R1", 2030, - "fall", - "day", - "E_BATT" + "winter", + "night", + "T_EV" ], [ "R1", - 2030, + 2020, "winter", "night", - "S_IMPETH" + "E_BATT" ], [ "R1", - 2025, - "spring", + 2020, + "fall", "day", - "T_GSL" + "S_OILREF" ], [ - "R2", - 2030, - "fall", - "day", - "E_SOLPV" + "R1-R2", + 2025, + "summer", + "night", + "E_TRANS" ], [ - "R2", + "R1", 2025, "spring", - "day", - "S_IMPNG" + "night", + "E_BATT" ], [ "R2", 2025, - "fall", + "spring", "night", - "R_NGH" + "T_GSL" ], [ "R1", 2020, - "fall", - "day", - "S_IMPNG" + "spring", + "night", + "T_BLND" ], [ "R1", 2020, - "spring", + "fall", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "winter", "day", - "S_IMPURN" + "T_GSL" ], [ "R1", 2020, - "summer", + "fall", "day", - "S_IMPURN" + "E_SOLPV" ], [ - "R1-R2", + "R2", 2030, - "winter", + "summer", "day", - "E_TRANS" + "T_EV" ], [ - "R2", + "R2-R1", 2025, - "spring", + "summer", "night", - "R_NGH" + "E_TRANS" ], [ - "R2", - 2030, - "summer", + "R1", + 2020, + "winter", "night", - "S_IMPNG" + "T_GSL" ], [ "R2", 2025, - "winter", + "spring", "day", - "E_NGCC" + "T_EV" ], [ "R1", 2025, "spring", - "day", - "T_BLND" + "night", + "T_GSL" ], [ "R1", 2020, "winter", - "night", - "E_NGCC" + "day", + "T_EV" ], [ "R1", 2025, - "spring", - "night", - "T_BLND" + "summer", + "day", + "T_DSL" ], [ - "R1", - 2030, + "R2", + 2025, "winter", "day", - "S_IMPNG" + "T_DSL" ], [ - "R2", - 2030, + "R1", + 2025, "spring", "day", - "S_IMPOIL" + "T_EV" ], [ "R1", 2030, - "spring", - "day", - "S_IMPETH" + "fall", + "night", + "T_DSL" ], [ "R2", 2020, - "fall", + "summer", "day", - "S_IMPETH" - ], - [ - "R1", - 2030, - "spring", - "night", - "S_IMPETH" + "T_BLND" ], [ "R1", - 2030, + 2025, "winter", "day", - "S_OILREF" - ], - [ - "R1", - 2030, - "summer", - "day", - "R_NGH" - ], - [ - "R2", - 2030, - "fall", - "night", - "S_IMPURN" + "T_DSL" ], [ "R2", - 2030, + 2020, "spring", "night", - "S_IMPURN" + "S_OILREF" ], [ "R2", - 2025, - "winter", + 2030, + "fall", "night", "S_OILREF" ], [ "R2", - 2025, - "summer", - "night", - "R_NGH" + 2020, + "winter", + "day", + "T_BLND" ], [ "R2", 2025, "winter", "night", - "E_NUCLEAR" + "E_NGCC" ], [ - "R1", + "R2", 2020, - "summer", - "day", - "R_EH" - ], - [ - "R1", - 2030, - "fall", + "spring", "night", - "S_IMPNG" - ], - [ - "R1", - 2030, - "winter", - "day", - "E_BATT" + "E_SOLPV" ], [ "R2", 2020, "spring", "day", - "S_IMPURN" + "R_NGH" ], [ "R2", 2030, - "spring", - "day", - "T_BLND" + "fall", + "night", + "E_SOLPV" ], [ - "R2", - 2020, - "winter", + "R1", + 2025, + "fall", "night", - "T_DSL" + "T_BLND" ], [ "R1", - 2030, - "fall", - "day", + 2025, + "winter", + "night", "E_NGCC" ], [ "R2", - 2020, - "winter", + 2030, + "summer", "day", - "E_SOLPV" + "T_BLND" ], [ "R2", - 2025, + 2030, "winter", - "night", + "day", "E_BATT" ], [ - "R1", - 2025, + "R2", + 2030, "winter", "night", - "S_OILREF" + "T_EV" ], [ - "R1", + "R2", 2025, "fall", - "day", - "R_NGH" - ], - [ - "R1", - 2025, - "winter", "night", - "E_NUCLEAR" + "R_NGH" ], [ - "R1", + "R2", 2025, "summer", "night", - "T_EV" + "E_BATT" ], [ "R2", - 2030, - "winter", - "day", - "T_EV" - ], - [ - "R1", - 2025, - "spring", - "day", - "S_OILREF" - ], - [ - "R1", 2020, "spring", "day", - "S_IMPETH" + "E_NUCLEAR" ], [ - "R1", - 2020, - "summer", + "R2", + 2030, + "fall", "day", - "S_IMPETH" + "E_NUCLEAR" ], [ "R1", - 2025, - "fall", + 2030, + "summer", "night", - "R_EH" + "R_NGH" ], [ - "R1", + "R2-R1", 2025, "spring", "night", - "S_IMPNG" + "E_TRANS" ], [ "R1", - 2020, - "winter", + 2030, + "spring", "night", "T_DSL" ], [ "R2", 2030, - "fall", + "winter", "day", - "S_IMPOIL" + "T_GSL" ], [ - "R1", - 2025, + "R2", + 2030, "spring", "day", - "E_NUCLEAR" - ], - [ - "R2", - 2020, - "summer", - "night", - "E_NGCC" + "R_NGH" ], [ "R2", 2025, - "fall", + "summer", "night", - "T_EV" + "T_GSL" ], [ - "R1", - 2025, + "R1-R2", + 2020, "winter", - "night", - "E_BATT" - ], - [ - "R2-R1", - 2030, - "fall", "day", "E_TRANS" ], [ "R2", - 2030, + 2025, "fall", "night", - "S_IMPETH" + "R_EH" ], [ "R2", 2025, "spring", "night", - "T_EV" - ], - [ - "R1", - 2030, - "winter", - "night", - "S_IMPOIL" + "T_BLND" ], [ "R2", - 2030, - "spring", + 2025, + "fall", "night", - "S_IMPETH" + "E_NUCLEAR" ], [ "R2", 2025, - "winter", + "fall", "day", - "S_IMPURN" + "E_SOLPV" ], [ "R1", 2030, "summer", - "day", - "T_EV" - ], - [ - "R2", - 2025, - "fall", - "day", + "night", "R_EH" ], - [ - "R1", - 2025, - "spring", - "day", - "E_BATT" - ], [ "R2", - 2030, + 2025, "summer", "day", - "S_IMPURN" + "T_EV" ], [ "R2", - 2030, - "spring", - "day", - "S_IMPNG" + 2025, + "winter", + "night", + "T_GSL" ], [ - "R1", + "R2", 2030, "spring", "day", - "S_IMPOIL" + "E_NUCLEAR" ], [ "R1", 2020, "spring", "night", - "R_EH" + "R_NGH" ], [ "R1", - 2020, - "winter", - "day", - "T_GSL" - ], - [ - "R2", 2025, "summer", - "night", + "day", "T_EV" ], [ "R2", - 2030, - "fall", + 2025, + "winter", "day", - "T_BLND" + "T_EV" ], [ "R2", 2020, - "spring", - "day", - "S_IMPETH" + "fall", + "night", + "T_DSL" ], [ - "R1-R2", - 2025, + "R1", + 2020, "summer", "night", - "E_TRANS" + "T_DSL" ], [ - "R2", + "R1", 2025, - "summer", - "day", - "R_EH" + "winter", + "night", + "T_GSL" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_EV" ], [ "R2-R1", @@ -3679,179 +3617,179 @@ 2030, "spring", "night", - "R_NGH" - ], - [ - "R1", - 2020, - "summer", - "night", - "R_EH" + "E_BATT" ], [ "R1", 2025, "winter", "day", - "E_SOLPV" + "T_EV" ], [ - "R1", - 2030, - "fall", + "R2-R1", + 2020, + "winter", "day", - "S_IMPURN" + "E_TRANS" ], [ - "R2", + "R1", 2020, - "fall", + "spring", "night", "R_EH" ], [ "R2", 2020, - "winter", + "summer", "night", - "E_SOLPV" + "S_OILREF" ], [ - "R2", + "R1", 2020, "spring", "night", - "R_EH" + "E_NUCLEAR" ], [ - "R2", - 2020, - "winter", + "R1", + 2030, + "fall", "day", "T_GSL" ], [ - "R2", + "R1", 2020, - "summer", - "night", - "T_DSL" + "spring", + "day", + "E_SOLPV" ], [ "R1", - 2025, - "summer", + 2030, + "spring", "day", - "R_EH" + "E_NGCC" ], [ "R1-R2", - 2020, - "fall", + 2025, + "spring", "night", "E_TRANS" ], [ "R2", 2020, - "winter", - "day", - "T_BLND" + "summer", + "night", + "E_SOLPV" ], [ "R2", - 2025, - "winter", + 2020, + "summer", "day", - "S_IMPETH" + "R_NGH" ], [ "R2", - 2030, - "winter", + 2020, + "fall", "night", - "T_EV" + "E_BATT" ], [ "R2", - 2030, - "summer", + 2020, + "winter", "day", - "S_IMPETH" + "R_NGH" ], [ "R1", - 2020, + 2025, "fall", "night", - "S_IMPNG" + "R_NGH" ], [ - "R2-R1", + "R1", 2025, - "spring", + "summer", "night", - "E_TRANS" + "E_BATT" ], [ "R2", - 2030, - "fall", + 2020, + "summer", "day", - "S_OILREF" + "E_NUCLEAR" ], [ "R2", - 2030, + 2020, "fall", "day", - "S_IMPNG" + "E_NGCC" ], [ "R2", - 2025, - "winter", - "day", - "E_SOLPV" + 2030, + "summer", + "night", + "S_OILREF" ], [ "R2", 2030, - "fall", + "spring", "night", - "S_IMPOIL" + "S_OILREF" ], [ "R1", - 2020, - "winter", + 2030, + "spring", "night", - "E_SOLPV" + "T_EV" ], [ - "R1", + "R2", 2030, - "winter", - "day", - "S_IMPURN" + "summer", + "night", + "E_SOLPV" ], [ "R1", 2030, "winter", - "night", - "S_IMPNG" + "day", + "S_OILREF" ], [ - "R1", + "R2", 2020, "winter", "day", - "S_OILREF" + "R_EH" ], [ "R1", - 2020, + 2025, + "summer", + "night", + "T_GSL" + ], + [ + "R2", + 2030, "summer", "day", "R_NGH" @@ -3860,1709 +3798,428 @@ "R2", 2025, "winter", + "day", + "T_BLND" + ], + [ + "R2", + 2030, + "spring", "night", - "S_IMPURN" + "E_SOLPV" ], [ "R1", - 2020, - "winter", - "day", + 2025, + "fall", + "night", "E_NUCLEAR" ], [ "R1", 2030, + "winter", + "day", + "E_SOLPV" + ], + [ + "R2", + 2025, "summer", "night", - "T_EV" + "T_BLND" ], [ - "R1", + "R1-R2", 2030, - "spring", + "fall", "day", - "S_IMPNG" + "E_TRANS" ], [ - "R2", - 2020, - "summer", + "R1", + 2025, + "winter", "day", - "T_EV" + "T_BLND" ], [ "R2", - 2020, - "fall", + 2030, + "summer", "day", - "S_IMPNG" + "E_NUCLEAR" ], [ "R2", 2025, "spring", - "day", - "R_EH" + "night", + "R_NGH" ], [ "R1", 2020, - "fall", - "day", - "R_EH" + "summer", + "night", + "T_EV" ], [ - "R2", - 2030, + "R1", + 2020, + "winter", + "night", + "R_NGH" + ], + [ + "R1", + 2025, "spring", "night", "R_NGH" ], [ - "R2", - 2030, + "R1", + 2020, "summer", + "day", + "T_GSL" + ], + [ + "R2", + 2025, + "spring", "night", "R_EH" ], [ "R1", - 2030, + 2020, "fall", - "day", - "S_IMPETH" + "night", + "E_NGCC" ], [ - "R2-R1", + "R1", 2030, - "winter", - "night", - "E_TRANS" + "summer", + "day", + "E_NGCC" ], [ - "R2", + "R1", 2030, "winter", "day", - "E_NGCC" + "R_EH" ], [ "R1", 2020, "winter", - "day", - "E_BATT" + "night", + "R_EH" ], [ "R1", 2030, "spring", "night", - "T_EV" + "T_BLND" ], [ - "R2-R1", + "R1", 2025, - "summer", - "day", - "E_TRANS" - ], - [ - "R1", - 2025, - "winter", - "day", - "S_IMPOIL" - ], - [ - "R2", - 2020, - "winter", - "day", - "S_OILREF" - ], - [ - "R1", - 2025, - "winter", - "night", - "S_IMPURN" - ], - [ - "R2-R1", - 2030, - "spring", - "day", - "E_TRANS" - ], - [ - "R2", - 2025, - "spring", - "night", - "E_NGCC" - ], - [ - "R2", - 2020, - "winter", - "night", - "S_IMPOIL" - ], - [ - "R2", - 2020, - "spring", - "day", - "R_NGH" - ], - [ - "R1", - 2025, - "fall", - "night", - "R_NGH" - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NUCLEAR" - ], - [ - "R2", - 2020, - "winter", - "day", - "E_NUCLEAR" - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NGCC" - ], - [ - "R1", - 2030, - "fall", - "night", - "R_EH" - ], - [ - "R1", - 2025, - "spring", - "day", - "S_IMPURN" - ], - [ - "R1-R2", - 2020, - "summer", - "day", - "E_TRANS" - ], - [ - "R2", - 2020, - "winter", - "night", - "T_GSL" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_BLND" - ], - [ - "R2", - 2020, - "summer", - "night", - "E_SOLPV" - ], - [ - "R1", - 2030, - "winter", - "day", - "S_IMPETH" - ], - [ - "R2", - 2020, - "winter", - "day", - "E_BATT" - ], - [ - "R2", - 2025, - "fall", - "day", - "R_NGH" - ], - [ - "R2-R1", - 2020, - "fall", - "day", - "E_TRANS" - ], - [ - "R1", - 2020, - "spring", - "day", - "S_IMPNG" - ], - [ - "R2", - 2025, - "winter", - "day", - "S_IMPOIL" - ], - [ - "R2", - 2020, - "winter", - "night", - "T_BLND" - ], - [ - "R2-R1", - 2020, - "spring", - "day", - "E_TRANS" - ], - [ - "R1", - 2020, - "winter", - "night", - "S_IMPOIL" - ], - [ - "R1", - 2020, - "spring", - "night", - "R_NGH" - ], - [ - "R2", - 2025, - "winter", - "night", - "S_IMPETH" - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NUCLEAR" - ], - [ - "R1", - 2020, - "winter", - "day", - "E_NGCC" - ], - [ - "R2", - 2020, - "summer", - "day", - "E_NUCLEAR" - ], - [ - "R2", - 2030, - "fall", - "night", - "S_IMPNG" - ], - [ - "R1", - 2025, - "spring", - "night", - "R_EH" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_DSL" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_DSL" - ], - [ - "R1", - 2020, - "winter", - "night", - "T_GSL" - ], - [ - "R2", - 2025, - "summer", - "day", - "R_NGH" - ], - [ - "R2", - 2020, - "summer", - "day", - "E_BATT" - ], - [ - "R1", - 2020, - "summer", - "night", - "R_NGH" - ], - [ - "R1-R2", - 2025, - "fall", - "night", - "E_TRANS" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_BLND" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_DSL" - ], - [ - "R1", - 2020, - "winter", - "night", - "T_BLND" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_DSL" - ], - [ - "R1", - 2025, - "winter", - "night", - "S_IMPETH" - ], - [ - "R1", - 2030, - "fall", - "day", - "S_IMPOIL" - ], - [ - "R2-R1", - 2030, - "spring", - "night", - "E_TRANS" - ], - [ - "R2", - 2020, - "fall", - "night", - "R_NGH" - ], - [ - "R2", - 2020, - "spring", - "night", - "R_NGH" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_DSL" - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NGCC" - ], - [ - "R2", - 2030, - "spring", - "day", - "R_EH" - ], - [ - "R1", - 2025, - "winter", - "day", - "S_OILREF" - ], - [ - "R1", - 2025, - "winter", - "day", - "S_IMPNG" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_EV" - ], - [ - "R1", - 2025, - "spring", - "day", - "S_IMPETH" - ], - [ - "R1", - 2025, - "summer", - "day", - "R_NGH" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_DSL" - ], - [ - "R2", - 2020, - "winter", - "night", - "S_OILREF" - ], - [ - "R2", - 2020, - "winter", - "night", - "S_IMPNG" - ], - [ - "R2", - 2020, - "summer", - "night", - "S_IMPOIL" - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NGCC" - ], - [ - "R2", - 2020, - "summer", - "day", - "E_NGCC" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_EV" - ], - [ - "R2", - 2030, - "fall", - "day", - "S_IMPURN" - ], - [ - "R1", - 2020, - "spring", - "night", - "T_EV" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_DSL" - ], - [ - "R2", - 2020, - "winter", - "night", - "E_BATT" - ], - [ - "R2", - 2020, - "summer", - "night", - "T_GSL" - ], - [ - "R2", - 2025, - "winter", - "day", - "S_IMPNG" - ], - [ - "R1", - 2020, - "winter", - "day", - "S_IMPURN" - ], - [ - "R1", - 2020, - "winter", - "night", - "S_IMPNG" - ], - [ - "R1", - 2020, - "winter", - "night", - "S_OILREF" - ], - [ - "R2", - 2025, - "spring", - "day", - "R_NGH" - ], - [ - "R2", - 2030, - "summer", - "day", - "S_IMPNG" - ], - [ - "R1", - 2020, - "fall", - "day", - "R_NGH" - ], - [ - "R2", - 2030, - "summer", - "night", - "R_NGH" - ], - [ - "R2", - 2020, - "summer", - "night", - "T_BLND" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_EV" - ], - [ - "R1", - 2030, - "winter", - "day", - "R_NGH" - ], - [ - "R1", - 2020, - "summer", - "night", - "T_EV" - ], - [ - "R1-R2", - 2025, - "summer", - "day", - "E_TRANS" - ], - [ - "R1", - 2020, - "fall", - "night", - "R_EH" - ], - [ - "R2", - 2030, - "fall", - "day", - "R_EH" - ], - [ - "R2", - 2030, - "winter", - "day", - "E_SOLPV" - ], - [ - "R1-R2", - 2030, - "summer", - "night", - "E_TRANS" - ], - [ - "R2", - 2020, - "fall", - "night", - "T_EV" - ], - [ - "R1", - 2020, - "winter", - "night", - "E_BATT" - ], - [ - "R1", - 2030, - "winter", - "night", - "R_EH" - ], - [ - "R2", - 2020, - "spring", - "night", - "T_EV" - ], - [ - "R1", - 2030, - "fall", - "day", - "S_IMPNG" - ], - [ - "R2", - 2020, - "winter", - "day", - "S_IMPURN" - ], - [ - "R2", - 2025, - "spring", - "night", - "E_SOLPV" - ], - [ - "R1", - 2030, - "fall", - "night", - "R_NGH" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_EV" - ], - [ - "R1", - 2030, - "spring", - "day", - "R_EH" - ], - [ - "R2", - 2020, - "fall", - "day", - "R_EH" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_DSL" - ], - [ - "R1", - 2030, - "summer", - "day", - "E_SOLPV" - ], - [ - "R1-R2", - 2020, - "summer", - "night", - "E_TRANS" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_DSL" - ], - [ - "R1", - 2020, - "winter", - "day", - "S_IMPETH" - ], - [ - "R2", - 2020, - "summer", - "night", - "S_OILREF" - ], - [ - "R2-R1", - 2020, - "fall", - "night", - "E_TRANS" - ], - [ - "R1", - 2025, - "spring", - "night", - "R_NGH" - ], - [ - "R1", - 2020, - "winter", - "day", - "E_SOLPV" - ], - [ - "R2", - 2020, - "summer", - "night", - "E_NUCLEAR" - ], - [ - "R2", - 2025, - "spring", - "day", - "T_EV" - ], - [ - "R1", - 2020, - "fall", - "day", - "T_EV" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_EV" - ], - [ - "R2", - 2025, - "winter", - "night", - "S_IMPNG" - ], - [ - "R1", - 2025, - "fall", - "night", - "E_NGCC" - ], - [ - "R2", - 2020, - "summer", - "night", - "E_BATT" - ], - [ - "R1", - 2020, - "spring", - "day", - "R_EH" - ], - [ - "R2", - 2030, - "winter", - "day", - "S_IMPOIL" - ], - [ - "R2", - 2030, - "spring", - "day", - "R_NGH" - ], - [ - "R2-R1", - 2030, - "winter", - "day", - "E_TRANS" - ], - [ - "R2", - 2020, - "winter", - "day", - "S_IMPETH" - ], - [ - "R2", - 2030, - "fall", - "night", - "R_EH" - ], - [ - "R2", - 2030, - "winter", - "night", - "E_SOLPV" - ], - [ - "R2", - 2030, - "spring", - "night", - "R_EH" - ], - [ - "R2", - 2025, - "spring", - "night", - "S_IMPOIL" - ], - [ - "R1", - 2020, - "summer", - "day", - "T_DSL" - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NGCC" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_GSL" - ], - [ - "R1", - 2025, - "winter", - "day", - "S_IMPURN" - ], - [ - "R1", - 2025, - "winter", - "night", - "S_IMPNG" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_GSL" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_EV" - ], - [ - "R1", - 2020, - "spring", - "night", - "E_NGCC" - ], - [ - "R1", - 2030, - "summer", - "day", - "S_IMPOIL" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_BLND" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_GSL" - ], - [ - "R2", - 2020, - "winter", - "night", - "S_IMPURN" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_GSL" - ], - [ - "R1", - 2025, - "spring", - "day", - "S_IMPNG" - ], - [ - "R2", - 2020, - "spring", - "day", - "R_EH" - ], - [ - "R1", - 2030, - "summer", - "night", - "E_SOLPV" - ], - [ - "R2", - 2025, - "summer", - "day", - "E_NGCC" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_GSL" - ], - [ - "R2", - 2020, - "summer", - "day", - "E_SOLPV" - ], - [ - "R2-R1", - 2025, - "winter", - "night", - "E_TRANS" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_BLND" - ], - [ - "R1", - 2025, - "winter", - "day", - "R_EH" - ], - [ - "R1-R2", - 2020, - "fall", - "day", - "E_TRANS" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_EV" - ], - [ - "R1-R2", - 2020, - "spring", - "day", - "E_TRANS" - ], - [ - "R1", - 2020, - "winter", - "day", - "S_IMPOIL" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_GSL" - ], - [ - "R2", - 2020, - "spring", - "day", - "T_DSL" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_DSL" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_BLND" - ], - [ - "R1", - 2020, - "winter", - "night", - "S_IMPURN" - ], - [ - "R2-R1", - 2025, - "spring", - "day", - "E_TRANS" - ], - [ - "R2", - 2020, "spring", "night", - "E_NGCC" + "R_EH" ], [ "R1", 2020, "fall", - "night", - "R_NGH" - ], - [ - "R2", - 2030, - "fall", "day", - "R_NGH" + "E_BATT" ], [ - "R1", + "R1-R2", 2025, - "summer", - "day", - "E_NGCC" - ], - [ - "R1", - 2030, "winter", "night", - "R_NGH" - ], - [ - "R2", - 2030, - "spring", - "day", - "T_EV" + "E_TRANS" ], [ "R2", 2025, "fall", - "day", - "T_DSL" - ], - [ - "R1-R2", - 2030, - "fall", - "day", - "E_TRANS" - ], - [ - "R1", - 2020, - "winter", - "day", - "T_BLND" - ], - [ - "R1", - 2025, - "winter", - "day", - "S_IMPETH" - ], - [ - "R2", - 2030, - "winter", - "day", - "S_OILREF" - ], - [ - "R1", - 2020, - "spring", "night", "T_DSL" ], - [ - "R2", - 2025, - "winter", - "day", - "R_EH" - ], [ "R1", 2030, - "spring", - "day", - "R_NGH" - ], - [ - "R2", - 2020, - "fall", - "day", - "R_NGH" - ], - [ - "R2", - 2030, - "winter", - "night", - "S_IMPOIL" - ], - [ - "R2", - 2020, - "winter", - "day", - "S_IMPOIL" - ], - [ - "R2", - 2030, "summer", - "day", - "R_EH" - ], - [ - "R2", - 2020, - "winter", - "night", - "S_IMPETH" - ], - [ - "R1", - 2025, - "summer", - "night", - "E_NUCLEAR" - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NUCLEAR" - ], - [ - "R2", - 2025, - "fall", - "night", - "S_OILREF" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_EV" - ], - [ - "R2", - 2025, - "spring", "night", - "S_OILREF" - ], - [ - "R2", - 2025, - "summer", - "day", "T_DSL" ], - [ - "R2", - 2030, - "winter", - "night", - "T_GSL" - ], [ "R1", 2020, - "summer", - "night", - "T_DSL" - ], - [ - "R2", - 2025, "fall", - "night", - "E_NUCLEAR" - ], - [ - "R2", - 2025, - "spring", - "day", - "E_NGCC" - ], - [ - "R2", - 2025, - "spring", - "night", - "E_NUCLEAR" - ], - [ - "R1", - 2025, - "summer", - "night", - "E_BATT" - ], - [ - "R2", - 2030, - "winter", - "day", - "E_BATT" - ], - [ - "R1", - 2030, - "summer", "day", - "S_OILREF" - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NGCC" - ], - [ - "R1", - 2030, - "summer", - "night", - "S_IMPOIL" + "T_GSL" ], [ "R2", 2030, "winter", - "night", - "T_BLND" + "day", + "S_OILREF" ], [ - "R2", + "R2-R1", + 2025, + "winter", + "day", + "E_TRANS" + ], + [ + "R2-R1", 2020, "fall", - "night", - "T_DSL" + "day", + "E_TRANS" ], [ "R2", 2020, - "summer", - "day", - "S_IMPOIL" + "fall", + "night", + "T_BLND" ], [ "R1", - 2030, + 2025, "summer", - "day", - "E_NUCLEAR" + "night", + "T_BLND" ], [ "R2", 2025, - "summer", + "winter", "night", "S_OILREF" ], [ - "R2", + "R1", 2020, "spring", "night", "T_DSL" ], [ - "R1", - 2030, - "fall", - "day", - "R_EH" + "R2", + 2025, + "winter", + "night", + "E_SOLPV" ], [ - "R1", + "R2", 2020, - "winter", + "spring", "night", - "S_IMPETH" + "E_BATT" ], [ "R2", - 2025, + 2030, "fall", "night", "E_BATT" ], [ - "R2", - 2020, - "summer", + "R1", + 2025, + "winter", "night", - "S_IMPURN" + "S_OILREF" ], [ "R2", - 2025, - "spring", - "night", - "E_BATT" + 2030, + "winter", + "day", + "R_NGH" ], [ "R2", 2025, "summer", "night", - "E_NUCLEAR" + "R_NGH" ], [ "R1", 2025, - "summer", - "day", - "T_DSL" + "winter", + "night", + "E_SOLPV" ], [ - "R1", + "R2", 2030, + "fall", + "day", + "E_NGCC" + ], + [ + "R1-R2", + 2020, "summer", "night", - "T_GSL" + "E_TRANS" ], [ "R2", 2020, - "summer", - "day", + "spring", + "night", "T_GSL" ], [ - "R1", - 2020, - "winter", - "day", - "S_IMPNG" + "R2", + 2030, + "fall", + "night", + "T_GSL" ], [ "R1", 2030, - "summer", + "fall", "day", - "E_BATT" + "S_OILREF" ], [ - "R1", - 2020, - "fall", - "night", - "T_EV" + "R2", + 2025, + "winter", + "day", + "E_NUCLEAR" ], [ "R2", 2030, - "fall", + "winter", "day", - "T_EV" + "R_EH" ], [ - "R1-R2", - 2020, - "spring", + "R2", + 2025, + "summer", "night", - "E_TRANS" + "R_EH" ], [ - "R1", + "R2", 2020, "spring", "day", - "R_NGH" + "T_EV" ], [ "R1", - 2030, - "summer", - "night", - "T_BLND" + 2025, + "winter", + "day", + "E_NUCLEAR" ], [ "R2", 2020, - "summer", + "winter", "day", - "T_BLND" + "T_DSL" ], [ - "R1", + "R2", 2025, - "fall", - "night", - "E_SOLPV" - ], - [ - "R1", - 2030, "winter", "night", - "T_EV" + "R_EH" ], [ "R2", 2025, - "summer", + "fall", "night", - "E_BATT" + "T_EV" ], [ "R1", 2030, - "spring", - "night", - "T_GSL" + "fall", + "day", + "R_NGH" ], [ - "R2", + "R1", 2030, - "fall", + "summer", "night", - "R_NGH" + "T_EV" ], [ "R1", 2025, - "summer", + "winter", "night", - "E_NGCC" + "R_EH" ], [ - "R1", + "R2", 2025, "fall", "day", - "E_NUCLEAR" + "T_GSL" ], [ - "R1", + "R2", 2030, "spring", "day", "T_EV" ], [ - "R2", + "R1", 2020, "fall", "day", - "T_EV" - ], - [ - "R1-R2", - 2025, - "fall", - "day", - "E_TRANS" + "T_BLND" ], [ "R1", 2030, - "winter", + "fall", "day", "R_EH" ], [ - "R2", - 2025, + "R1", + 2030, "spring", "day", - "T_DSL" - ], - [ - "R2", - 2025, - "fall", - "day", - "E_SOLPV" + "S_OILREF" ], [ "R1", - 2020, - "fall", - "day", - "T_DSL" - ], - [ - "R2", 2025, "fall", - "night", - "E_NGCC" - ], - [ - "R2", - 2030, - "winter", - "night", - "S_OILREF" + "day", + "T_GSL" ] ], "LifetimeProcess_rtv": [ @@ -28043,6 +26700,44 @@ ] ], "RetiredCapacityVar_rptv": [], + "AnnualRetirementVar_rptv": [ + [ + "R2", + 2030, + "T_EV", + 2020 + ], + [ + "R1", + 2030, + "T_DSL", + 2020 + ], + [ + "R2", + 2030, + "T_DSL", + 2020 + ], + [ + "R2", + 2030, + "T_GSL", + 2020 + ], + [ + "R1", + 2030, + "T_EV", + 2020 + ], + [ + "R1", + 2030, + "T_GSL", + 2020 + ] + ], "CapacityAvailableVar_rpt": [ [ "R1-R2", diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index c06426a32..aa664b5f4 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -251,6 +251,34 @@ INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); +CREATE TABLE ConstructionInput +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); +CREATE TABLE EndOfLifeOutput +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) +); CREATE TABLE CostEmission ( region TEXT diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 781dfcc4c..01da59456 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -199,113 +199,113 @@ [ "utopia", 2000, - "winter", + "summer", "day", - "SRE" + "E31" ], [ "utopia", - 1990, - "winter", - "day", - "IMPURN1" + 2010, + "inter", + "night", + "E51" ], [ "utopia", - 2000, + 2010, "inter", - "day", - "IMPOIL1" + "night", + "E70" ], [ "utopia", 2000, "summer", - "night", - "TXD" + "day", + "E01" ], [ "utopia", - 2000, + 2010, "winter", "night", - "IMPURN1" + "RHO" ], [ "utopia", - 2000, - "summer", + 1990, + "inter", "night", - "E70" + "RHO" ], [ "utopia", 2010, - "summer", + "inter", "day", - "TXG" + "TXE" ], [ "utopia", - 2000, - "inter", - "day", - "E51" + 1990, + "summer", + "night", + "SRE" ], [ "utopia", - 2000, - "inter", - "day", - "RL1" + 1990, + "winter", + "night", + "E21" ], [ "utopia", 2000, "summer", "day", - "IMPFEQ" + "RL1" ], [ "utopia", - 1990, + 2000, "inter", - "day", + "night", "RHE" ], [ "utopia", - 1990, - "summer", + 2000, + "inter", "day", - "SRE" + "RHE" ], [ "utopia", - 2010, - "winter", + 2000, + "inter", "day", - "TXG" + "E21" ], [ "utopia", - 1990, - "inter", + 2010, + "summer", "day", - "IMPDSL1" + "TXD" ], [ "utopia", - 2010, + 1990, "summer", "night", - "IMPHYD" + "RHE" ], [ "utopia", - 2010, + 1990, "summer", - "night", + "day", "E21" ], [ @@ -313,322 +313,301 @@ 1990, "winter", "night", - "IMPGSL1" + "E51" ], [ "utopia", - 2010, - "inter", + 2000, + "summer", "night", "RHE" ], [ "utopia", - 2000, + 1990, "winter", - "day", - "E01" + "night", + "TXE" ], [ "utopia", 2000, "summer", - "day", - "SRE" - ], - [ - "utopia", - 1990, - "summer", "night", - "TXG" + "E21" ], [ "utopia", - 2010, - "inter", - "night", - "IMPDSL1" + 2000, + "summer", + "day", + "E21" ], [ "utopia", 2000, "winter", "day", - "IMPHYD" + "TXG" ], [ "utopia", - 2010, + 2000, "inter", "day", - "RHO" + "E51" ], [ "utopia", - 2010, - "winter", + 2000, + "inter", "day", - "IMPURN1" + "E70" ], [ "utopia", 2000, - "winter", - "day", - "E21" + "inter", + "night", + "E70" ], [ "utopia", - 2000, - "inter", - "day", - "IMPGSL1" + 1990, + "summer", + "night", + "E70" ], [ "utopia", 2010, "summer", - "night", - "IMPOIL1" + "day", + "E31" ], [ "utopia", 1990, "summer", "day", - "E01" + "E51" ], [ "utopia", - 2000, + 2010, "summer", - "night", - "TXG" + "day", + "E01" ], [ "utopia", 1990, "summer", "day", - "IMPHYD" + "TXE" ], [ "utopia", - 1990, + 2000, "summer", "night", - "IMPURN1" + "E51" ], [ "utopia", - 2010, + 2000, "winter", "night", - "RHE" + "TXD" ], [ "utopia", - 1990, - "inter", - "day", - "E31" + 2000, + "summer", + "night", + "E70" ], [ "utopia", 2010, "summer", - "night", - "E51" + "day", + "RL1" ], [ "utopia", - 1990, + 2000, "summer", "day", - "E21" + "TXE" + ], + [ + "utopia", + 1990, + "winter", + "day", + "TXD" ], [ "utopia", 2000, "winter", "day", - "IMPOIL1" + "RHO" ], [ "utopia", 2010, - "winter", + "summer", "night", - "IMPDSL1" + "RHE" ], [ "utopia", - 1990, - "inter", + 2010, + "summer", "night", - "RHO" + "E21" ], [ "utopia", 2010, - "inter", + "winter", "day", - "IMPFEQ" + "TXG" ], [ "utopia", - 1990, - "winter", + 2010, + "summer", "day", - "IMPHCO1" + "E21" ], [ "utopia", - 2000, - "summer", + 1990, + "inter", "day", - "E01" + "TXG" ], [ "utopia", 2000, "winter", "night", - "IMPHCO1" + "E31" ], [ "utopia", 2000, "winter", - "day", - "E51" + "night", + "E01" ], [ "utopia", - 2000, - "summer", - "day", - "IMPHYD" + 2010, + "inter", + "night", + "SRE" ], [ "utopia", 2000, "winter", - "day", + "night", "RL1" ], [ "utopia", - 2000, + 1990, + "winter", + "day", + "E31" + ], + [ + "utopia", + 2010, "summer", "night", - "IMPURN1" + "E51" ], [ "utopia", 2010, - "inter", + "summer", "night", - "E31" + "E70" ], [ "utopia", - 2000, - "summer", - "day", - "E21" + 2010, + "winter", + "night", + "TXD" ], [ "utopia", - 2000, + 2010, "inter", "day", "RHE" ], [ "utopia", - 2000, + 1990, "inter", "night", - "RHO" + "TXD" ], [ "utopia", - 1990, + 2010, "summer", "day", - "IMPOIL1" + "TXE" ], [ "utopia", - 2000, - "inter", - "day", - "IMPDSL1" + 1990, + "winter", + "night", + "SRE" ], [ "utopia", 2010, "inter", - "day", - "SRE" + "night", + "TXG" ], [ "utopia", - 1990, + 2000, "inter", "day", - "TXD" + "SRE" ], [ "utopia", - 1990, - "summer", + 2010, + "inter", "day", "E51" ], [ "utopia", - 1990, - "summer", - "day", - "RL1" - ], - [ - "utopia", - 1990, + 2010, "inter", "day", "E70" ], - [ - "utopia", - 1990, - "inter", - "night", - "IMPFEQ" - ], - [ - "utopia", - 2000, - "summer", - "day", - "IMPOIL1" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXE" - ], [ "utopia", 2010, - "summer", + "winter", "day", - "IMPHCO1" + "RHO" ], [ "utopia", @@ -639,227 +618,227 @@ ], [ "utopia", - 2000, + 1990, + "inter", + "day", + "RHO" + ], + [ + "utopia", + 1990, "winter", "night", - "TXE" + "RHE" ], [ "utopia", 2010, - "inter", + "winter", "night", - "TXD" + "E01" ], [ "utopia", - 2010, + 1990, "inter", "night", - "E70" + "E31" ], [ "utopia", - 2000, - "summer", + 1990, + "winter", "day", - "E51" + "E21" ], [ "utopia", - 2000, - "winter", + 1990, + "inter", "night", - "RHO" + "E01" ], [ "utopia", - 2000, + 1990, "summer", "day", - "RL1" + "SRE" ], [ "utopia", 2000, - "inter", + "summer", "night", - "IMPFEQ" + "SRE" ], [ "utopia", 2010, "winter", - "day", - "IMPHCO1" + "night", + "RL1" ], [ "utopia", 2000, "winter", - "day", - "IMPGSL1" + "night", + "TXE" ], [ "utopia", 1990, "inter", "night", - "SRE" + "RL1" ], [ "utopia", 2000, "inter", - "day", - "E31" + "night", + "TXG" ], [ "utopia", - 2010, - "inter", + 1990, + "summer", "day", - "E01" + "RHE" ], [ "utopia", 1990, - "summer", + "winter", "night", - "IMPHCO1" + "E70" ], [ "utopia", - 2010, - "summer", - "night", - "RHE" + 2000, + "inter", + "day", + "TXG" ], [ "utopia", - 2010, - "inter", + 1990, + "winter", "day", - "IMPHYD" + "E51" ], [ "utopia", - 1990, + 2000, "summer", "day", - "IMPGSL1" + "RHE" ], [ "utopia", - 2010, + 1990, "winter", - "night", - "TXD" + "day", + "TXE" ], [ "utopia", - 2000, - "inter", + 1990, + "summer", "night", - "SRE" + "TXG" ], [ "utopia", - 2010, - "inter", - "day", - "E21" + 2000, + "summer", + "night", + "TXG" ], [ "utopia", - 2010, - "summer", + 1990, + "inter", "night", - "IMPDSL1" + "E21" ], [ "utopia", - 2010, + 1990, "summer", "day", - "RHO" + "E70" ], [ "utopia", 2000, "summer", - "night", - "IMPHCO1" + "day", + "E51" ], [ "utopia", 2000, "summer", "day", - "IMPGSL1" + "E70" ], [ "utopia", 2000, "winter", "day", - "IMPDSL1" + "TXD" ], [ "utopia", 2010, - "winter", - "day", - "RHO" + "summer", + "night", + "SRE" ], [ "utopia", 1990, "inter", "night", - "E01" + "E51" ], [ "utopia", - 2000, - "inter", - "day", - "TXD" + 2010, + "winter", + "night", + "TXE" ], [ "utopia", 1990, "inter", "night", - "IMPHYD" + "TXE" ], [ "utopia", - 2010, + 2000, "inter", "night", - "TXG" + "RHO" ], [ "utopia", 2010, - "inter", + "summer", "day", - "IMPOIL1" - ], - [ - "utopia", - 1990, - "inter", - "night", - "E21" + "RHE" ], [ "utopia", - 1990, - "inter", + 2000, + "winter", "day", - "IMPURN1" + "E31" ], [ "utopia", @@ -870,126 +849,112 @@ ], [ "utopia", - 1990, + 2000, "winter", - "night", - "IMPHYD" - ], - [ - "utopia", - 2010, - "inter", "day", - "E51" + "E01" ], [ "utopia", 2010, "inter", "day", - "RL1" + "SRE" ], [ "utopia", 2010, "summer", - "day", - "IMPFEQ" + "night", + "TXG" ], [ "utopia", 2000, - "inter", - "night", - "E01" + "winter", + "day", + "RL1" ], [ "utopia", - 1990, + 2010, "summer", "day", - "IMPDSL1" + "E70" ], [ "utopia", 2010, "summer", - "night", - "E31" - ], - [ - "utopia", - 2000, - "inter", - "night", - "IMPHYD" + "day", + "E51" ], [ "utopia", 2010, "winter", "day", - "IMPFEQ" + "TXD" ], [ "utopia", - 2010, + 1990, "inter", - "night", - "IMPURN1" + "day", + "TXD" ], [ "utopia", - 2000, - "inter", - "night", - "E21" + 1990, + "winter", + "day", + "SRE" ], [ "utopia", 2000, - "summer", + "winter", "night", - "RHO" + "RHE" ], [ "utopia", - 1990, + 2010, "inter", - "night", - "IMPOIL1" + "day", + "TXG" ], [ "utopia", - 1990, + 2000, "winter", - "day", - "TXG" + "night", + "E21" ], [ "utopia", 2000, - "summer", + "winter", "day", - "IMPDSL1" + "E21" ], [ "utopia", - 2000, + 2010, "winter", "day", "E31" ], [ "utopia", - 2010, - "summer", + 1990, + "winter", "day", - "SRE" + "RHE" ], [ "utopia", - 1990, + 2010, "winter", "day", "E01" @@ -998,728 +963,28 @@ "utopia", 1990, "inter", - "night", - "E51" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RL1" - ], - [ - "utopia", - 1990, - "summer", - "night", - "IMPFEQ" - ], - [ - "utopia", - 2000, - "winter", - "night", - "E01" - ], - [ - "utopia", - 2000, - "inter", - "night", - "IMPOIL1" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXD" - ], - [ - "utopia", - 2010, - "inter", - "day", - "IMPGSL1" - ], - [ - "utopia", - 1990, - "summer", - "day", - "E31" - ], - [ - "utopia", - 2010, - "winter", - "night", - "IMPURN1" - ], - [ - "utopia", - 2000, - "winter", - "night", - "E21" - ], - [ - "utopia", - 2010, - "summer", - "night", - "E70" - ], - [ - "utopia", - 2000, - "inter", - "night", - "E51" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RL1" - ], - [ - "utopia", - 2000, - "summer", - "night", - "IMPFEQ" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXD" - ], - [ - "utopia", - 2000, - "summer", - "day", - "E31" - ], - [ - "utopia", - 2010, - "summer", - "day", - "E01" - ], - [ - "utopia", - 2000, - "inter", - "day", - "IMPURN1" - ], - [ - "utopia", - 1990, - "inter", - "night", - "IMPGSL1" - ], - [ - "utopia", - 1990, - "inter", - "day", - "IMPHCO1" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RL1" - ], - [ - "utopia", - 2010, - "summer", - "day", - "E21" - ], - [ - "utopia", - 2010, - "winter", - "day", - "E01" - ], - [ - "utopia", - 2000, - "winter", - "night", - "E51" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RL1" - ], - [ - "utopia", - 2010, - "inter", - "day", - "IMPDSL1" - ], - [ - "utopia", - 2010, - "winter", - "day", - "E21" - ], - [ - "utopia", - 2010, - "inter", - "night", - "IMPHCO1" - ], - [ - "utopia", - 2000, - "inter", - "night", - "IMPGSL1" - ], - [ - "utopia", - 1990, - "summer", - "night", - "E01" - ], - [ - "utopia", - 2010, - "summer", - "day", - "IMPOIL1" - ], - [ - "utopia", - 1990, - "summer", - "night", - "E21" - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXE" - ], - [ - "utopia", - 2010, - "summer", - "day", - "E51" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RL1" - ], - [ - "utopia", - 2010, - "winter", - "day", - "IMPOIL1" - ], - [ - "utopia", - 2000, - "summer", - "night", - "E01" - ], - [ - "utopia", - 1990, - "inter", - "night", - "IMPDSL1" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHE" - ], - [ - "utopia", - 1990, - "winter", - "day", - "IMPGSL1" - ], - [ - "utopia", - 2010, - "winter", - "night", - "IMPHCO1" - ], - [ - "utopia", - 2000, - "winter", - "night", - "IMPGSL1" - ], - [ - "utopia", - 1990, - "winter", - "night", - "IMPDSL1" - ], - [ - "utopia", - 2010, - "winter", - "day", - "E51" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RL1" - ], - [ - "utopia", - 2010, - "summer", - "night", - "IMPURN1" - ], - [ - "utopia", - 2000, - "summer", - "night", - "E21" - ], - [ - "utopia", - 2010, - "inter", - "day", - "E31" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXE" - ], - [ - "utopia", - 1990, - "summer", - "night", - "IMPOIL1" - ], - [ - "utopia", - 2000, - "inter", - "night", - "IMPDSL1" - ], - [ - "utopia", - 1990, - "summer", - "night", - "E51" - ], - [ - "utopia", - 2000, - "winter", - "day", - "IMPURN1" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RL1" - ], - [ - "utopia", - 2000, - "inter", - "day", - "IMPHCO1" - ], - [ - "utopia", - 2000, - "summer", - "night", - "IMPOIL1" - ], - [ - "utopia", - 2010, - "summer", - "day", - "IMPGSL1" - ], - [ - "utopia", - 1990, - "inter", - "night", - "E31" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXE" - ], - [ - "utopia", - 2000, - "summer", - "night", - "E51" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RL1" - ], - [ - "utopia", - 1990, - "summer", - "day", - "IMPURN1" - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXD" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXE" - ], - [ - "utopia", - 1990, - "winter", - "night", - "E31" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHO" - ], - [ - "utopia", - 2010, - "winter", - "day", - "IMPGSL1" - ], - [ - "utopia", - 2000, - "inter", - "night", - "E31" - ], - [ - "utopia", - 2000, - "summer", - "day", - "IMPURN1" - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXE" - ], - [ - "utopia", - 1990, - "summer", - "night", - "IMPGSL1" - ], - [ - "utopia", - 1990, - "winter", - "day", - "IMPFEQ" - ], - [ - "utopia", - 2010, - "winter", - "night", - "E70" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXD" - ], - [ - "utopia", - 2000, - "winter", - "night", - "IMPFEQ" - ], - [ - "utopia", - 2000, - "summer", - "night", - "IMPGSL1" - ], - [ - "utopia", - 1990, - "winter", - "night", - "E70" - ], - [ - "utopia", - 2010, - "summer", - "night", - "IMPHCO1" - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXG" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHE" - ], - [ - "utopia", - 1990, - "inter", - "day", - "E01" - ], - [ - "utopia", - 2000, - "winter", - "day", - "IMPHCO1" - ], - [ - "utopia", - 1990, - "winter", - "day", - "SRE" - ], - [ - "utopia", - 2000, - "inter", - "day", - "E70" - ], - [ - "utopia", - 2000, - "winter", - "night", - "SRE" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHE" - ], - [ - "utopia", - 2010, - "inter", - "night", - "E01" - ], - [ - "utopia", - 2010, - "summer", - "day", - "E31" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXE" - ], - [ - "utopia", - 2010, - "inter", - "night", - "E21" - ], - [ - "utopia", - 2010, - "inter", - "day", - "IMPURN1" - ], - [ - "utopia", - 2000, - "summer", "day", - "RHE" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXG" + "E31" ], [ "utopia", 2000, "winter", - "day", - "TXE" - ], - [ - "utopia", - 1990, - "winter", "night", - "TXG" + "E51" ], [ "utopia", 1990, "inter", "day", - "RL1" - ], - [ - "utopia", - 2010, - "winter", - "night", "E01" ], - [ - "utopia", - 1990, - "winter", - "day", - "IMPHYD" - ], - [ - "utopia", - 2010, - "winter", - "day", - "SRE" - ], - [ - "utopia", - 1990, - "inter", - "night", - "IMPURN1" - ], [ "utopia", 2000, "winter", - "night", - "IMPHYD" - ], - [ - "utopia", - 1990, - "winter", - "day", - "E21" - ], - [ - "utopia", - 1990, - "summer", "day", - "TXE" - ], - [ - "utopia", - 2010, - "inter", - "night", "E51" ], [ @@ -1727,294 +992,119 @@ 2010, "inter", "night", - "RL1" + "TXD" ], [ "utopia", 2000, - "inter", - "day", - "TXG" - ], - [ - "utopia", - 1990, - "winter", - "night", - "IMPURN1" - ], - [ - "utopia", - 1990, "summer", - "night", + "day", "SRE" ], [ "utopia", 2000, - "inter", + "winter", "night", - "IMPURN1" + "E70" ], [ "utopia", - 2000, - "summer", + 2010, + "winter", "day", - "TXE" + "RL1" ], [ "utopia", 2000, "winter", "day", - "E70" + "TXE" ], [ "utopia", 1990, "winter", - "day", - "IMPOIL1" - ], - [ - "utopia", - 2000, - "winter", "night", - "IMPOIL1" + "TXG" ], [ "utopia", 1990, "inter", "day", - "IMPGSL1" - ], - [ - "utopia", - 2010, - "summer", - "day", - "IMPHYD" - ], - [ - "utopia", - 2010, - "winter", - "night", "RL1" ], - [ - "utopia", - 2000, - "summer", - "night", - "SRE" - ], [ "utopia", 1990, "winter", "day", - "E51" - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHE" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXD" - ], - [ - "utopia", - 1990, - "summer", - "day", "E70" ], - [ - "utopia", - 2010, - "winter", - "day", - "IMPHYD" - ], [ "utopia", 2010, "inter", "night", - "IMPGSL1" - ], - [ - "utopia", - 2010, - "inter", - "day", - "IMPHCO1" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXD" + "RHO" ], [ "utopia", 1990, "summer", - "night", - "IMPHYD" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXG" - ], - [ - "utopia", - 2000, - "summer", - "day", - "E70" - ], - [ - "utopia", - 2010, - "summer", - "night", - "E01" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RHE" - ], - [ - "utopia", - 2000, - "winter", "day", "TXG" ], [ "utopia", 2010, - "winter", - "night", - "IMPGSL1" - ], - [ - "utopia", - 1990, - "inter", - "night", - "IMPHCO1" - ], - [ - "utopia", - 1990, "inter", "day", "RHO" ], - [ - "utopia", - 2000, - "summer", - "night", - "IMPHYD" - ], - [ - "utopia", - 2010, - "summer", - "day", - "IMPURN1" - ], [ "utopia", 2010, - "inter", - "day", - "TXE" - ], - [ - "utopia", - 1990, "winter", "night", - "IMPHCO1" - ], - [ - "utopia", - 2000, - "inter", - "night", "RHE" ], [ "utopia", 2010, - "inter", - "night", - "RHO" - ], - [ - "utopia", - 2000, - "inter", + "winter", "night", - "IMPHCO1" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXG" - ], - [ - "utopia", - 1990, - "inter", - "day", - "IMPFEQ" + "E21" ], [ "utopia", - 1990, + 2010, "inter", "night", - "TXE" + "E31" ], [ "utopia", - 1990, + 2010, "winter", "day", + "E21" + ], + [ + "utopia", + 1990, + "inter", + "night", "RHE" ], [ "utopia", 2010, - "summer", + "inter", "night", - "RL1" + "E01" ], [ "utopia", @@ -2023,212 +1113,219 @@ "day", "TXG" ], - [ - "utopia", - 2000, - "winter", - "night", - "RHE" - ], [ "utopia", 1990, - "winter", + "inter", "day", - "IMPDSL1" + "E21" ], [ "utopia", 2000, - "winter", + "inter", + "night", + "TXD" + ], + [ + "utopia", + 2010, + "inter", "night", - "IMPDSL1" + "RL1" ], [ "utopia", 2010, "winter", "night", - "RHO" + "E51" ], [ "utopia", 2010, - "inter", - "day", + "winter", + "night", "E70" ], [ "utopia", 2010, - "inter", - "night", - "IMPFEQ" + "winter", + "day", + "E51" ], [ "utopia", 1990, - "winter", + "summer", "night", - "RHO" + "TXD" ], [ "utopia", - 2000, + 1990, "inter", "night", - "TXE" + "E70" ], [ "utopia", - 1990, - "inter", + 2010, + "summer", "day", "SRE" ], [ "utopia", - 2000, + 1990, "inter", "day", - "RHO" + "E51" ], [ "utopia", - 2010, + 2000, "summer", - "day", - "RHE" + "night", + "TXD" ], [ "utopia", 2010, - "inter", - "night", - "SRE" + "winter", + "day", + "TXE" ], [ "utopia", 1990, - "inter", + "winter", "night", - "TXD" + "RHO" ], [ "utopia", 1990, "inter", - "night", - "E70" + "day", + "TXE" ], [ "utopia", - 2010, - "winter", - "night", - "IMPFEQ" + 2000, + "inter", + "day", + "RHO" ], [ "utopia", - 2010, - "summer", + 2000, + "inter", "night", - "IMPGSL1" + "E31" ], [ "utopia", - 2010, - "summer", + 2000, + "inter", "day", - "IMPDSL1" + "E31" ], [ "utopia", - 1990, - "winter", + 2000, + "inter", "night", - "IMPFEQ" + "E01" ], [ "utopia", - 1990, - "winter", + 2000, + "inter", "day", - "E31" + "E01" ], [ "utopia", - 2010, - "winter", + 1990, + "summer", "day", - "RHE" + "RHO" ], [ "utopia", 2000, - "winter", + "inter", "night", - "E31" + "RL1" ], [ "utopia", - 2010, - "winter", - "day", - "IMPDSL1" + 1990, + "summer", + "night", + "E31" ], [ "utopia", 2000, "inter", - "night", - "TXD" + "day", + "RL1" ], [ "utopia", 2000, - "inter", + "summer", "night", - "E70" + "RHO" ], [ "utopia", 1990, "summer", "night", - "RHE" + "E01" + ], + [ + "utopia", + 2000, + "summer", + "day", + "RHO" ], [ "utopia", 1990, - "inter", + "summer", "day", - "IMPHYD" + "E01" ], [ "utopia", 2010, - "inter", + "summer", "day", "TXG" ], [ "utopia", 2000, - "inter", - "day", - "IMPFEQ" + "summer", + "night", + "E31" ], [ "utopia", - 2010, - "winter", + 2000, + "summer", "night", - "SRE" + "E01" ], [ "utopia", - 1990, + 2000, "winter", "night", "SRE" @@ -2236,149 +1333,156 @@ [ "utopia", 1990, - "inter", - "day", - "E21" + "summer", + "night", + "RL1" ], [ "utopia", - 1990, - "summer", - "night", - "IMPDSL1" + 2000, + "winter", + "day", + "SRE" ], [ "utopia", - 2010, + 1990, "summer", "day", - "TXE" + "RL1" ], [ "utopia", 2010, "inter", "night", - "IMPHYD" + "TXE" ], [ "utopia", - 1990, - "winter", - "day", - "TXD" + 2000, + "summer", + "night", + "RL1" ], [ "utopia", 2000, - "summer", + "inter", "night", - "RHE" + "E21" ], [ "utopia", - 1990, + 2010, "summer", - "day", - "IMPHCO1" + "night", + "TXD" ], [ "utopia", - 1990, + 2000, "winter", "day", - "E70" + "RHE" ], [ "utopia", - 2000, - "winter", + 1990, + "summer", "night", - "TXD" + "E21" ], [ "utopia", 2000, "winter", "night", - "E70" + "TXG" ], [ "utopia", 2000, - "summer", + "inter", "night", - "IMPDSL1" + "E51" ], [ "utopia", - 2010, - "summer", + 2000, + "inter", "night", - "RHO" + "TXE" ], [ "utopia", 2000, - "inter", + "winter", "day", - "SRE" + "E70" ], [ "utopia", - 1990, - "inter", + 2010, + "summer", "night", - "TXG" + "RHO" ], [ "utopia", - 1990, + 2000, "inter", "day", - "IMPOIL1" + "TXE" ], [ "utopia", 2010, - "winter", + "inter", "day", - "TXE" + "TXD" ], [ "utopia", 2010, - "winter", + "summer", "day", - "E31" + "RHO" ], [ "utopia", - 2000, + 2010, "summer", - "day", - "IMPHCO1" + "night", + "E31" ], [ "utopia", 1990, - "inter", - "day", + "summer", + "night", "E51" ], [ "utopia", - 2000, + 1990, "winter", "day", - "RHO" + "TXG" + ], + [ + "utopia", + 2010, + "summer", + "night", + "E01" ], [ "utopia", - 1990, + 2010, "winter", "night", - "E01" + "SRE" ], [ "utopia", @@ -2390,100 +1494,107 @@ [ "utopia", 2010, - "inter", - "night", - "IMPOIL1" + "winter", + "day", + "SRE" ], [ "utopia", - 2010, - "winter", + 1990, + "inter", "night", - "IMPHYD" + "SRE" ], [ "utopia", 1990, - "summer", - "night", - "E31" + "inter", + "day", + "SRE" ], [ "utopia", - 2000, - "inter", + 2010, + "summer", "night", - "TXG" + "RL1" ], [ "utopia", - 2010, - "winter", + 2000, + "summer", "night", - "E21" + "TXE" ], [ "utopia", 2010, - "summer", + "winter", "day", - "TXD" + "RHE" ], [ "utopia", 1990, "winter", "night", - "E21" + "TXD" ], [ "utopia", 2010, - "summer", + "inter", "day", - "E70" + "E31" ], [ "utopia", - 2010, - "summer", - "night", - "IMPFEQ" + 1990, + "inter", + "day", + "RHE" ], [ "utopia", - 1990, - "summer", + 2010, + "inter", "day", - "RHO" + "E01" ], [ "utopia", 2000, - "summer", + "winter", "night", - "TXE" + "RHO" ], [ "utopia", 2000, "inter", "day", - "E01" + "TXD" ], [ "utopia", 2010, "winter", + "night", + "TXG" + ], + [ + "utopia", + 2010, + "inter", "day", - "TXD" + "RL1" ], [ "utopia", - 2000, - "summer", + 1990, + "inter", "night", - "E31" + "TXG" ], [ "utopia", @@ -2494,93 +1605,93 @@ ], [ "utopia", - 2000, - "inter", + 1990, + "summer", "day", - "IMPHYD" + "TXD" ], [ "utopia", - 2000, - "winter", + 1990, + "inter", "day", - "IMPFEQ" + "E70" ], [ "utopia", - 2010, + 1990, "winter", - "night", - "IMPOIL1" + "day", + "RHO" ], [ "utopia", 2000, - "inter", + "summer", "day", - "E21" + "TXD" ], [ "utopia", - 2000, + 1990, "winter", "night", - "TXG" + "E31" ], [ "utopia", 1990, "winter", "night", - "IMPOIL1" + "E01" ], [ "utopia", - 2000, - "summer", + 1990, + "winter", "day", - "RHO" + "E01" ], [ "utopia", 2010, - "summer", + "inter", "night", - "SRE" + "RHE" ], [ "utopia", - 1990, - "summer", + 2010, + "inter", "night", - "TXD" + "E21" ], [ "utopia", - 1990, + 2010, "summer", "night", - "E70" + "TXE" ], [ "utopia", 2010, - "winter", - "night", - "E51" + "inter", + "day", + "E21" ], [ "utopia", 1990, "winter", "night", - "E51" + "RL1" ], [ "utopia", 1990, "winter", - "night", + "day", "RL1" ], [ @@ -2588,7 +1699,14 @@ 1990, "summer", "day", - "IMPFEQ" + "E31" + ], + [ + "utopia", + 2000, + "inter", + "night", + "SRE" ] ], "LifetimeProcess_rtv": [ @@ -16446,6 +15564,122 @@ ] ], "RetiredCapacityVar_rptv": [], + "AnnualRetirementVar_rptv": [ + [ + "utopia", + 2000, + "RHO", + 1970 + ], + [ + "utopia", + 2010, + "TXG", + 1980 + ], + [ + "utopia", + 2010, + "TXD", + 1980 + ], + [ + "utopia", + 2000, + "E70", + 1960 + ], + [ + "utopia", + 2000, + "RL1", + 1990 + ], + [ + "utopia", + 2000, + "TXE", + 1990 + ], + [ + "utopia", + 2010, + "E70", + 1970 + ], + [ + "utopia", + 2010, + "RL1", + 2000 + ], + [ + "utopia", + 2000, + "E01", + 1960 + ], + [ + "utopia", + 2010, + "RHO", + 1980 + ], + [ + "utopia", + 2000, + "TXG", + 1990 + ], + [ + "utopia", + 2010, + "TXE", + 2000 + ], + [ + "utopia", + 2000, + "TXG", + 1970 + ], + [ + "utopia", + 2000, + "RL1", + 1980 + ], + [ + "utopia", + 2000, + "TXD", + 1990 + ], + [ + "utopia", + 2010, + "E01", + 1970 + ], + [ + "utopia", + 2010, + "TXD", + 2000 + ], + [ + "utopia", + 2000, + "TXD", + 1970 + ], + [ + "utopia", + 2010, + "TXG", + 2000 + ] + ], "CapacityAvailableVar_rpt": [ [ "utopia", From f218a518c0d3509026354992c94972e18da1b3e4 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 13 May 2025 16:35:20 -0400 Subject: [PATCH 073/587] Minor fixes after merging materials --- temoa/temoa_model/temoa_rules.py | 4 ++-- tests/testing_data/mediumville_sets.json | 4 ++++ tests/testing_data/test_system_sets.json | 2 ++ tests/testing_data/utopia_sets.json | 2 ++ 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 558bfa16a..7ded25cf3 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -894,7 +894,7 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] ) - if c in M.flex_commodities: + if c in M.commodity_flex: # Wasted by flex flows consumed += sum( M.V_Flex[r, p, s, d, S_i, S_t, S_v, c] @@ -1028,7 +1028,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] ) - if c in M.flex_commodities: + if c in M.commodity_flex: consumed += sum( M.V_Flex[r, p, S_s, S_d, S_i, S_t, S_v, c] for S_s in M.time_season[p] diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 8390365a9..819c6bb4d 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -26,6 +26,7 @@ "time_season": [ 2025 ], + "TimeNext": [], "time_of_day": [ "d1", "d2" @@ -132,6 +133,9 @@ "co2", "FusionGas" ], + "commodity_flex" : [ + "FusionGasFuel" + ], "commodity_physical": [ "ELC", "HYD", diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 77d8d1353..3817d6e0a 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -38,6 +38,7 @@ 2025, 2030 ], + "TimeNext": [], "time_of_day": [ "day", "night" @@ -142,6 +143,7 @@ "commodity_emissions": [ "CO2" ], + "commodity_flex": [], "commodity_physical": [ "ethos", "OIL", diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 01da59456..388ad6995 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -43,6 +43,7 @@ 2000, 2010 ], + "TimeNext": [], "time_of_day": [ "day", "night" @@ -150,6 +151,7 @@ "co2", "nox" ], + "commodity_flex": [], "commodity_physical": [ "ethos", "DSL", From 7dd1b6678e194929e5f1ef68718e23779d8f7d18 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 13 May 2025 17:26:03 -0400 Subject: [PATCH 074/587] Clean up index checking in dictionaries --- temoa/temoa_model/temoa_initialize.py | 40 ++++++++++++++------------- temoa/temoa_model/temoa_rules.py | 26 ++++++++--------- 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 6dfb486ca..0b2c1a3d2 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -834,28 +834,28 @@ def CreateSparseDicts(M: 'TemoaModel'): M.rampDownVintages[r, p, t] = set() # min tech split - if (r, p, i, t) in M.MinTechInputSplit.sparse_iterkeys() and ( + if (r, p, i, t) in M.MinTechInputSplit and ( r, p, i, t, ) not in M.minInputSplitVintages: M.minInputSplitVintages[r, p, i, t] = set() - if (r, p, i, t) in M.MinTechInputSplitAnnual.sparse_iterkeys() and ( + if (r, p, i, t) in M.MinTechInputSplitAnnual and ( r, p, i, t, ) not in M.minInputSplitAnnualVintages: M.minInputSplitAnnualVintages[r, p, i, t] = set() - if (r, p, t, o) in M.MinTechOutputSplit.sparse_iterkeys() and ( + if (r, p, t, o) in M.MinTechOutputSplit and ( r, p, t, o, ) not in M.minOutputSplitVintages: M.minOutputSplitVintages[r, p, t, o] = set() - if (r, p, t, o) in M.MinTechOutputSplitAnnual.sparse_iterkeys() and ( + if (r, p, t, o) in M.MinTechOutputSplitAnnual and ( r, p, t, @@ -864,28 +864,28 @@ def CreateSparseDicts(M: 'TemoaModel'): M.minOutputSplitAnnualVintages[r, p, t, o] = set() # max tech split - if (r, p, i, t) in M.MaxTechInputSplit.sparse_iterkeys() and ( + if (r, p, i, t) in M.MaxTechInputSplit and ( r, p, i, t, ) not in M.maxInputSplitVintages: M.maxInputSplitVintages[r, p, i, t] = set() - if (r, p, i, t) in M.MaxTechInputSplitAnnual.sparse_iterkeys() and ( + if (r, p, i, t) in M.MaxTechInputSplitAnnual and ( r, p, i, t, ) not in M.maxInputSplitAnnualVintages: M.maxInputSplitAnnualVintages[r, p, i, t] = set() - if (r, p, t, o) in M.MaxTechOutputSplit.sparse_iterkeys() and ( + if (r, p, t, o) in M.MaxTechOutputSplit and ( r, p, t, o, ) not in M.maxOutputSplitVintages: M.maxOutputSplitVintages[r, p, t, o] = set() - if (r, p, t, o) in M.MaxTechOutputSplitAnnual.sparse_iterkeys() and ( + if (r, p, t, o) in M.MaxTechOutputSplitAnnual and ( r, p, t, @@ -929,23 +929,23 @@ def CreateSparseDicts(M: 'TemoaModel'): M.rampDownVintages[r, p, t].add(v) # min tech split - if (r, p, i, t) in M.MinTechInputSplit.sparse_iterkeys(): + if (r, p, i, t) in M.MinTechInputSplit: M.minInputSplitVintages[r, p, i, t].add(v) - if (r, p, i, t) in M.MinTechInputSplitAnnual.sparse_iterkeys(): + if (r, p, i, t) in M.MinTechInputSplitAnnual: M.minInputSplitAnnualVintages[r, p, i, t].add(v) - if (r, p, t, o) in M.MinTechOutputSplit.sparse_iterkeys(): + if (r, p, t, o) in M.MinTechOutputSplit: M.minOutputSplitVintages[r, p, t, o].add(v) - if (r, p, t, o) in M.MinTechOutputSplitAnnual.sparse_iterkeys(): + if (r, p, t, o) in M.MinTechOutputSplitAnnual: M.minOutputSplitAnnualVintages[r, p, t, o].add(v) # max tech split - if (r, p, i, t) in M.MaxTechInputSplit.sparse_iterkeys(): + if (r, p, i, t) in M.MaxTechInputSplit: M.maxInputSplitVintages[r, p, i, t].add(v) - if (r, p, i, t) in M.MaxTechInputSplitAnnual.sparse_iterkeys(): + if (r, p, i, t) in M.MaxTechInputSplitAnnual: M.maxInputSplitAnnualVintages[r, p, i, t].add(v) - if (r, p, t, o) in M.MaxTechOutputSplit.sparse_iterkeys(): + if (r, p, t, o) in M.MaxTechOutputSplit: M.maxOutputSplitVintages[r, p, t, o].add(v) - if (r, p, t, o) in M.MaxTechOutputSplitAnnual.sparse_iterkeys(): + if (r, p, t, o) in M.MaxTechOutputSplitAnnual: M.maxOutputSplitAnnualVintages[r, p, t, o].add(v) if t in M.tech_resource: @@ -1079,7 +1079,9 @@ def CreateSparseDicts(M: 'TemoaModel'): ) M.activeActivity_rptv = set( - (r, p, t, v) for r, p, t in M.processVintages.keys() for v in M.processVintages[r, p, t] + (r, p, t, v) + for r, p, t in M.processVintages.keys() + for v in M.processVintages[r, p, t] ) M.activeRegionsForTech = defaultdict(set) @@ -1378,7 +1380,7 @@ def LinkedTechConstraintIndices(M: 'TemoaModel'): (r, p, s, d, t, v, e) for r, t, e in M.LinkedTechs.sparse_iterkeys() for p in M.time_optimize - if (r, p, t) in M.processVintages.keys() + if (r, p, t) in M.processVintages for v in M.processVintages[r, p, t] if (r, p, t, v) in M.activeActivity_rptv for s in M.time_season[p] @@ -1443,7 +1445,7 @@ def DemandActivityConstraintIndices(M: 'TemoaModel'): found_flag = False s0, d0 = None, None for s0, d0 in ((ss, dd) for ss in M.time_season[p] for dd in M.time_of_day): - if (r, p, s0, d0, dem) in M.DemandSpecificDistribution.sparse_iterkeys(): + if (r, p, s0, d0, dem) in M.DemandSpecificDistribution: if value(M.DemandSpecificDistribution[r, p, s0, d0, dem]) >= appreciable_size: found_flag = True break # we have one with some value associated diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 7ded25cf3..e59a9d294 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1626,8 +1626,8 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): &\qquad \qquad \forall \{r, p, s, d\} \in \Theta_{\text{ReserveMargin}} \text{and} \forall r_i \in R """ if (not M.tech_reserve) or ( - (r, p) not in M.processReservePeriods.keys() - ): # If reserve set empty or if r,p not in M.processReservePeriod.keys(), skip the constraint + (r, p) not in M.processReservePeriods + ): # If reserve set empty or if r,p not in M.processReservePeriod, skip the constraint return Constraint.Skip cap_avail = sum( @@ -1637,7 +1637,7 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[p, s, d]) for t in M.tech_reserve - if (r, p, t) in M.processVintages.keys() + if (r, p, t) in M.processVintages for v in M.processVintages[r, p, t] # Make sure (r,p,t,v) combinations are defined if (r, p, t, v) in M.activeCapacityAvailable_rptv @@ -1669,7 +1669,7 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): * value(M.CapacityToActivity[r1r2, t]) * value(M.SegFrac[p, s, d]) for t in M.tech_reserve - if (r1r2, p, t) in M.processVintages.keys() + if (r1r2, p, t) in M.processVintages for v in M.processVintages[r1r2, p, t] # Make sure (r,p,t,v) combinations are defined if (r1r2, p, t, v) in M.activeCapacityAvailable_rptv @@ -1777,7 +1777,7 @@ def EmissionLimit_Constraint(M: 'TemoaModel', r, p, e): for tmp_r, tmp_e, S_i, S_t, S_v, S_o in M.EmissionActivity.sparse_iterkeys() if tmp_e == e and tmp_r == reg and S_t not in M.tech_annual # EmissionsActivity not indexed by p, so make sure (r,p,t,v) combos valid - if (reg, p, S_t, S_v) in M.processInputs.keys() + if (reg, p, S_t, S_v) in M.processInputs for S_s in M.time_season[p] for S_d in M.time_of_day ) @@ -1789,7 +1789,7 @@ def EmissionLimit_Constraint(M: 'TemoaModel', r, p, e): for tmp_r, tmp_e, S_i, S_t, S_v, S_o in M.EmissionActivity.sparse_iterkeys() if tmp_e == e and tmp_r == reg and S_t in M.tech_annual # EmissionsActivity not indexed by p, so make sure (r,p,t,v) combos valid - if (reg, p, S_t, S_v) in M.processInputs.keys() + if (reg, p, S_t, S_v) in M.processInputs ) embodied_emissions = sum( @@ -2285,7 +2285,7 @@ def MaxResource_Constraint(M: 'TemoaModel', r, t): M.V_FlowOutAnnual[_r, p, S_i, t, S_v, S_o] for p in M.time_optimize for _r in regions - if (_r, p, t) in M.processVintages.keys() + if (_r, p, t) in M.processVintages 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] @@ -2295,7 +2295,7 @@ def MaxResource_Constraint(M: 'TemoaModel', r, t): M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] for p in M.time_optimize for _r in regions - if (_r, p, t) in M.processVintages.keys() + if (_r, p, t) in M.processVintages 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] @@ -2610,7 +2610,7 @@ def MinCapacityShare_Constraint(M: 'TemoaModel', r, p, t, g): M.V_CapacityAvailableByPeriodAndTech[_r, p, S_t] for S_t in M.tech_group_members[g] for _r in regions - if (_r, p, S_t) in M.processVintages.keys() + if (_r, p, S_t) in M.processVintages ) min_cap_share = value(M.MinCapacityShare[r, p, t, g]) @@ -2645,7 +2645,7 @@ def MaxCapacityShare_Constraint(M: 'TemoaModel', r, p, t, g): M.V_CapacityAvailableByPeriodAndTech[_r, p, S_t] for S_t in M.tech_group_members[g] for _r in regions - if (_r, p, S_t) in M.processVintages.keys() + if (_r, p, S_t) in M.processVintages ) max_cap_share = value(M.MaxCapacityShare[r, p, t, g]) @@ -2673,7 +2673,7 @@ def MinNewCapacityShare_Constraint(M: 'TemoaModel', r, p, t, g): M.V_NewCapacity[_r, S_t, p] for S_t in M.tech_group_members[g] for _r in regions - if (_r, S_t, p) in M.V_NewCapacity.keys() + if (_r, S_t, p) in M.V_NewCapacity ) min_cap_share = value(M.MinNewCapacityShare[r, p, t, g]) @@ -2708,7 +2708,7 @@ def MaxNewCapacityShare_Constraint(M: 'TemoaModel', r, p, t, g): M.V_NewCapacity[_r, S_t, p] for S_t in M.tech_group_members[g] for _r in regions - if (_r, S_t, p) in M.V_NewCapacity.keys() + if (_r, S_t, p) in M.V_NewCapacity ) max_cap_share = value(M.MaxNewCapacityShare[r, p, t, g]) @@ -3367,7 +3367,7 @@ def SegFracPerSeason_rule(M: 'TemoaModel', p, s): return sum( value(M.SegFrac[p, s, S_d]) for S_d in M.time_of_day - if (p, s, S_d) in M.SegFrac.sparse_iterkeys() + if (p, s, S_d) in M.SegFrac ) From ac8c9806e5bba2480ead5c232be0b9923a2e572c Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 13 May 2025 18:09:52 -0400 Subject: [PATCH 075/587] Fix GrowthRateMax constraint and allow growth from existing capacity --- temoa/temoa_model/temoa_model.py | 2 +- temoa/temoa_model/temoa_rules.py | 69 ++++++++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 05bb1bc95..e75cdb654 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -449,7 +449,7 @@ def __init__(M, *args, **kwargs): M.MaxAnnualCapacityFactor = Param(M.MaxAnnualCapacityFactorConstraint_rpto) M.GrowthRateMax = Param(M.regionalGlobalIndices, M.tech_all) - M.GrowthRateSeed = Param(M.regionalGlobalIndices, M.tech_all) + M.GrowthRateSeed = Param(M.regionalGlobalIndices, M.tech_all, default=0) M.EmissionLimitConstraint_rpe = Set( within=M.regionalGlobalIndices * M.time_optimize * M.commodity_emissions diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index e59a9d294..732a59bfe 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1852,17 +1852,78 @@ def GrowthRateMaxConstraint_rule(M: 'TemoaModel', r, p, t): regions = gather_group_regions(M, r) GRS = value(M.GrowthRateSeed[r, t]) - GRM = value(M.GrowthRateMax[r, t]) - CapPT = M.V_CapacityAvailableByPeriodAndTech + GRM = 1 + value(M.GrowthRateMax[r, t]) + CapRPT = M.V_CapacityAvailableByPeriodAndTech + # relevant r, p, t indices + cap_rpt = set((_r, _p, _t) for _r, _p, _t in CapRPT if _t == t and _r in regions) # periods the technology can have capacity in this region (sorted) - periods = sorted(set(_p for _r, _p, _t in CapPT if _t == t and _r in regions)) + periods = sorted(set(_p for _r, _p, _t in cap_rpt)) if p not in periods: # cant have capacity in this period return Constraint.Skip - capacity = sum(CapPT[_r, p, t] for _r in regions) + # sum available capacity in this period + capacity = sum(CapRPT[_r, _p, _t] for _r, _p, _t in cap_rpt if _p == p) + + if p == periods[0]: + # first period it can have capacity + # plant a seed and grow it + # grow from existing capacity in last existing period, adjusting in-line for PLF + p_last = M.time_exist.last() + exist_cap = sum( + value(M.ExistingCapacity[_r, _t, _v]) \ + * min( 1.0, (_v + value(M.LifetimeProcess[_r, _t, _v]) - p_last)/(p - p_last) ) + for _r, _t, _v in M.ExistingCapacity + if _r in regions and _t == t and _v + value(M.LifetimeProcess[_r, _t, _v]) > p_last + ) + if exist_cap == 0 and GRS == 0: + msg = ( + 'No constant term (GrowthRateSeed) provided for GrowthRateMax constraint {} ' + 'and no existing capacity was found so there is nothing to grow from. No capacity ' + 'will be built for this technology in this region.' + ).format((r, t)) + logger.warning(msg) + expr = capacity <= GRS + GRM * exist_cap + else: + # can have capacity in previous period + # plant a seed and grow last period's capacity + # note: we plant a seed every period to survive zero-outs + if GRS == 0: + msg = ( + 'No constant term (GrowthRateSeed) provided for GrowthRateMax constraint {}. ' + 'No capacity can be built in any period following one with zero capacity.' + ).format((r, t)) + logger.warning(msg) + p_prev = periods[periods.index(p) - 1] # previous period + capacity_prev = sum(CapRPT[_r, p_prev, t] for _r in regions) + expr = capacity <= GRS + GRM * capacity_prev + + return expr + + +def GrowthRateChangeMaxConstraint_rule(M: 'TemoaModel', r, p, t): + r""" + Constrain the change of new capacity deployed between periods. + Forces the model to ramp up and down the deployment of new technologies + more smoothly. + """ + + regions = gather_group_regions(M, r) + + GRS = value(M.GrowthRateChangeSeed[r, t]) + GRM = value(M.GrowthRateChangeMax[r, t]) + NewCapRTV = M.V_NewCapacity + + # periods the technology can have capacity in this region (sorted) + periods = sorted(set(_v for _r, _t, _v in NewCapRTV if _t == t and _r in regions)) + + if p not in periods: + # cant have capacity in this period + return Constraint.Skip + + capacity = sum(NewCapRTV[_r, t, p] for _r in regions) if p == periods[0]: # first period it can have capacity From f6b599c58ec671d88c34d1e13d28a614b0fba711 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 14 May 2025 09:14:47 -0400 Subject: [PATCH 076/587] Clean up some logging --- temoa/temoa_model/hybrid_loader.py | 2 +- .../model_checking/commodity_graph.py | 14 ++-- .../model_checking/pricing_check.py | 2 +- temoa/temoa_model/run_actions.py | 11 +++- temoa/temoa_model/temoa_initialize.py | 22 ++++--- temoa/temoa_model/temoa_rules.py | 64 ++++++++++++++----- temoa/temoa_model/temoa_sequencer.py | 8 +-- 7 files changed, 83 insertions(+), 40 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index da500019b..aa24761cb 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -337,7 +337,7 @@ def load_element( '\n%s' % (c.name, e) ) if len(screened) < len(values): - msg = ('Some values for {} failed to validate and were ignored:\n{}') + msg = ('Some values for {} failed to validate and were ignored: {}') logger.warning(msg.format(c.name, [val for val in values if val not in screened])) match c: case Set(): diff --git a/temoa/temoa_model/model_checking/commodity_graph.py b/temoa/temoa_model/model_checking/commodity_graph.py index 145a6febb..e8a8dc902 100644 --- a/temoa/temoa_model/model_checking/commodity_graph.py +++ b/temoa/temoa_model/model_checking/commodity_graph.py @@ -131,17 +131,17 @@ def generate_graph( cycle = list(cycle) if len(cycle) < 2: # a storage item--not reportable continue - logger.warning( - 'Found cycle in region %s, period %d. No action needed if this is correct:', - region, - period, - ) - res = ' ' + res = '' first = cycle[0] for node in cycle: res += f'{node} --> ' res += first - logger.info(res) + logger.info( + 'Found cycle in region %s, period %d. No action needed if this is correct: %s', + region, + period, + res, + ) except nx.NetworkXError as e: logger.warning('NetworkX exception encountered: %s. Loop evaluation NOT performed.', e) if config.plot_commodity_network: diff --git a/temoa/temoa_model/model_checking/pricing_check.py b/temoa/temoa_model/model_checking/pricing_check.py index 872b71c3e..1564bc499 100644 --- a/temoa/temoa_model/model_checking/pricing_check.py +++ b/temoa/temoa_model/model_checking/pricing_check.py @@ -117,7 +117,7 @@ def price_checker(M: 'TemoaModel') -> bool: if not any((has_fc, has_ic)): logger.warning( - f'Check 1a (detail): tech {tech} of vintage {vintage} in region {region} does not ' + f'Check 1a (detail): tech with capacity {tech} of vintage {vintage} in region {region} does not ' f'have a Fixed Cost or Investment Cost component' ) techs_without_fc_or_ic.add(tech) diff --git a/temoa/temoa_model/run_actions.py b/temoa/temoa_model/run_actions.py index 587653567..449b5b010 100644 --- a/temoa/temoa_model/run_actions.py +++ b/temoa/temoa_model/run_actions.py @@ -26,6 +26,8 @@ received this license file. If not, see . """ +import os +import definitions import sqlite3 import sys from logging import getLogger @@ -154,7 +156,14 @@ def build_instance( logger.info('Started creating model instance from data') instance = model.create_instance(loaded_portal, name=model_name) if not silent: - SE.write('\r[%8.2f] Instance created.\n' % (time() - hack)) + # Check for warnings in log file to notify user. Ugly but it works + log_file = os.path.join(definitions.get_OUTPUT_PATH(), 'log.log') + with open(log_file, 'r') as f: + warnings_found = any("| WARNING |" in line or "| ERROR |" in line or "| CRITICAL |" in line for line in f) + if warnings_found: + SE.write('\r[%8.2f] Instance created with warnings. Check log file.\n' % (time() - hack)) + else: + SE.write('\r[%8.2f] Instance created. \n' % (time() - hack)) # needs spaces to clear previous line SE.flush() logger.info('Finished creating model instance from data') diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 0b2c1a3d2..570e25e9d 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -742,14 +742,15 @@ def CreateSparseDicts(M: 'TemoaModel'): continue if v + l_lifetime <= l_first_period: msg = ( - '\nWarning: %s specified as ExistingCapacity, but its ' - 'LifetimeProcess parameter does not extend past the beginning ' - 'of time_future.' - '\n\tLifetime: %s' - '\n\tFirst period: %s\n' - ) - logger.warning(msg, l_process, l_lifetime, l_first_period) - # Devnote: these are now useful due to end of life outputs + '{} specified as ExistingCapacity, but its ' + 'lifetime ({} years) does not extend past the ' + 'beginning of time_future ({}) so it is never active. This ' + 'may be intentional for use in GrowthRate constraints ' + 'or end of life flows.' + ).format(l_process, l_lifetime, l_first_period) + logger.info(msg) + # Devnote: these are now useful due to end of life flows and + # GrowthRate constraints growing from existing cap so do not skip #SE.write(msg % (l_process, l_lifetime, l_first_period)) #continue @@ -766,7 +767,7 @@ def CreateSparseDicts(M: 'TemoaModel'): l_used_techs.add(t) - if t in M.tech_flex: + if t in M.tech_flex and o not in M.commodity_flex: M.commodity_flex.add(o) # Add in the period (p) index, since it's not included in the efficiency @@ -784,7 +785,8 @@ def CreateSparseDicts(M: 'TemoaModel'): # l_loan_life = value(M.LoanLifetimeProcess[l_process]) # if v + l_loan_life >= p: # M.processLoans[pindex] = True - + + # Get all periods where the process can retire if t not in M.tech_uncap and any(( p==v and l_lifetime TemoaModel | None: if self.config.price_check is False: logger.warning('Price check of model is automatic with CHECK') good_prices = price_checker(instance) - if not good_prices and not self.config.silent: - print('\nWarning: Cost anomalies discovered. Check log file for details.') + # if not good_prices and not self.config.silent: + # print('\nWarning: Cost anomalies discovered. Check log file for details.') con.close() case TemoaMode.PERFECT_FORESIGHT: @@ -210,8 +210,8 @@ def start(self) -> TemoaModel | None: ) if self.config.price_check: good_prices = price_checker(instance) - if not good_prices and not self.config.silent: - print('\nWarning: Cost anomalies discovered. Check log file for details.') + # if not good_prices and not self.config.silent: + # print('\nWarning: Cost anomalies discovered. Check log file for details.') suffixes = ( [ 'dual', From caa1c8e98a44b65317fb3218d4e15ed8866907df Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 14 May 2025 13:29:24 -0400 Subject: [PATCH 077/587] Add GrowthRateChange constraints --- data_files/temoa_schema_v3_1.sql | 32 ++++++++++++++----- temoa/temoa_model/hybrid_loader.py | 12 ++++++++ temoa/temoa_model/temoa_initialize.py | 18 ++++++++--- temoa/temoa_model/temoa_model.py | 12 +++++++- temoa/temoa_model/temoa_rules.py | 44 ++++++++++++++++++--------- temoa/temoa_model/temoa_sequencer.py | 8 ++--- 6 files changed, 95 insertions(+), 31 deletions(-) diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index 125904929..e6fa6689f 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -14,6 +14,8 @@ REPLACE INTO MetaData VALUES ('DB_MAJOR', 3, 'DB major version number'); REPLACE INTO MetaData VALUES ('DB_MINOR', 0, 'DB minor version number'); +REPLACE INTO MetaData +VALUES ('state_sequencing', 0, '0 = loop periods, 1 = loop seasons'); CREATE TABLE IF NOT EXISTS MetaDataReal ( @@ -140,8 +142,7 @@ CREATE TABLE IF NOT EXISTS ConstructionInput ); CREATE TABLE IF NOT EXISTS CostEmission ( - region TEXT - REFERENCES Region (region), + region TEXT, period INTEGER REFERENCES TimePeriod (period), emis_comm TEXT NOT NULL @@ -354,6 +355,25 @@ CREATE TABLE IF NOT EXISTS GrowthRateSeed notes TEXT, PRIMARY KEY (region, tech) ); +CREATE TABLE GrowthRateChangeMax +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE GrowthRateChangeSeed +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + seed REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech) +); CREATE TABLE IF NOT EXISTS LoanLifetimeTech ( region TEXT, @@ -1095,8 +1115,7 @@ CREATE TABLE IF NOT EXISTS MaxActivityGroup ); CREATE TABLE IF NOT EXISTS MinSeasonalActivity ( - region TEXT - REFERENCES Region (region), + region TEXT, period INTEGER REFERENCES TimePeriod (period), season TEXT @@ -1110,8 +1129,7 @@ CREATE TABLE IF NOT EXISTS MinSeasonalActivity ); CREATE TABLE IF NOT EXISTS MaxSeasonalActivity ( - region TEXT - REFERENCES Region (region), + region TEXT, period INTEGER REFERENCES TimePeriod (period), season TEXT @@ -1162,7 +1180,7 @@ CREATE TABLE IF NOT EXISTS Technology CREATE TABLE OutputCost ( scenario TEXT, - region TEXT REFERENCES Region (region), + region TEXT, sector TEXT REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index aa24761cb..8f01d580a 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -81,6 +81,8 @@ 'MaxResource': 'region', 'GrowthRateMax': 'region', 'GrowthRateSeed': 'region', + 'GrowthRateChangeMax': 'region', + 'GrowthRateChangeSeed': 'region', } @@ -1055,6 +1057,16 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N raw = cur.execute('SELECT region, tech, seed FROM main.GrowthRateSeed').fetchall() load_element(M.GrowthRateSeed, raw, self.viable_rt, (0, 1)) + # GrowthRateChangeMax + if self.table_exists('GrowthRateChangeMax'): + raw = cur.execute('SELECT region, tech, rate FROM main.GrowthRateChangeMax').fetchall() + load_element(M.GrowthRateChangeMax, raw, self.viable_rt, (0, 1)) + + # GrowthRateChangeSeed + if self.table_exists('GrowthRateChangeSeed'): + raw = cur.execute('SELECT region, tech, seed FROM main.GrowthRateChangeSeed').fetchall() + load_element(M.GrowthRateChangeSeed, raw, self.viable_rt, (0, 1)) + # EmissionLimit if self.table_exists('EmissionLimit'): raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, emis_comm, value FROM main.EmissionLimit') diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 570e25e9d..b273d0d74 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -729,7 +729,8 @@ def CreateSparseDicts(M: 'TemoaModel'): 'Warning: %s has a specified Efficiency, but does not ' 'have any existing install base (ExistingCapacity).\n' ) - SE.write(msg % str(l_process)) + logger.warning(msg, str(l_process)) + # SE.write(msg % str(l_process)) continue if t not in M.tech_uncap and M.ExistingCapacity[l_process] == 0: msg = ( @@ -737,8 +738,8 @@ def CreateSparseDicts(M: 'TemoaModel'): '%s. If specifying a capacity of zero, you may simply ' 'omit the declaration.\n' ) - logger.info(msg, str(l_process)) - SE.write(msg % str(l_process)) + logger.warning(msg, str(l_process)) + # SE.write(msg % str(l_process)) continue if v + l_lifetime <= l_first_period: msg = ( @@ -1755,7 +1756,16 @@ def MaxTechOutputSplitAverageConstraintIndices(M: 'TemoaModel'): def GrowthRateMaxIndices(M: 'TemoaModel'): indices = set( (r, p, t) - for r, t in M.GrowthRateMax.sparse_iterkeys() + for r, t in M.GrowthRateMax.sparse_iterkeys() | M.GrowthRateSeed.sparse_iterkeys() + for p in M.time_optimize + ) + return indices + + +def GrowthRateChangeIndices(M: 'TemoaModel'): + indices = set( + (r, p, t) + for r, t in M.GrowthRateChangeMax.sparse_iterkeys() | M.GrowthRateChangeSeed.sparse_iterkeys() for p in M.time_optimize ) return indices diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index e75cdb654..53fa3e625 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -448,8 +448,10 @@ def __init__(M, *args, **kwargs): ) M.MaxAnnualCapacityFactor = Param(M.MaxAnnualCapacityFactorConstraint_rpto) - M.GrowthRateMax = Param(M.regionalGlobalIndices, M.tech_all) + M.GrowthRateMax = Param(M.regionalGlobalIndices, M.tech_all, default=0) M.GrowthRateSeed = Param(M.regionalGlobalIndices, M.tech_all, default=0) + M.GrowthRateChangeMax = Param(M.regionalGlobalIndices, M.tech_all, default=0) + M.GrowthRateChangeSeed = Param(M.regionalGlobalIndices, M.tech_all, default=0) M.EmissionLimitConstraint_rpe = Set( within=M.regionalGlobalIndices * M.time_optimize * M.commodity_emissions @@ -734,6 +736,14 @@ def __init__(M, *args, **kwargs): M.GrowthRateMaxConstraint_rtv, rule=GrowthRateMaxConstraint_rule ) + M.GrowthRateChangeConstraint_rtv = Set(dimen=3, initialize=GrowthRateChangeIndices) + M.GrowthRateChangeMinConstraint = Constraint( + M.GrowthRateChangeConstraint_rtv, rule=GrowthRateChangeMinConstraint_rule + ) + M.GrowthRateChangeMaxConstraint = Constraint( + M.GrowthRateChangeConstraint_rtv, rule=GrowthRateChangeMaxConstraint_rule + ) + M.MaxActivityConstraint = Constraint( M.MaxActivityConstraint_rpt, rule=MaxActivity_Constraint ) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 1d0d7da5b..6b021d0d9 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1872,13 +1872,13 @@ def GrowthRateMaxConstraint_rule(M: 'TemoaModel', r, p, t): # grow from existing capacity in last existing period, adjusting in-line for PLF # or, otherwise, capped at the constant (seed) parameter p_last = M.time_exist.last() - exist_cap = sum( + capacity_prev = sum( value(M.ExistingCapacity[_r, _t, _v]) \ * min( 1.0, (_v + value(M.LifetimeProcess[_r, _t, _v]) - p_last)/(p - p_last) ) for _r, _t, _v in M.ExistingCapacity if _r in regions and _t == t and _v + value(M.LifetimeProcess[_r, _t, _v]) > p_last ) - if exist_cap == 0 and GRS == 0: + if capacity_prev == 0 and GRS == 0: msg = ( 'No constant term (GrowthRateSeed) provided for GrowthRateMax constraint {} ' 'and no existing capacity was found in the last existing period so there is ' @@ -1887,7 +1887,6 @@ def GrowthRateMaxConstraint_rule(M: 'TemoaModel', r, p, t): ).format((r, t)) logger.error(msg) raise ValueError(msg) - expr = capacity <= GRS + GRM * exist_cap else: # can have capacity in previous period # plant a seed and grow last period's capacity @@ -1905,12 +1904,21 @@ def GrowthRateMaxConstraint_rule(M: 'TemoaModel', r, p, t): for _r, _p, _t in cap_rpt if _p == p_prev ) - expr = capacity <= GRS + GRM * capacity_prev - - return expr + return capacity <= GRS + GRM * capacity_prev + +def GrowthRateChangeMinConstraint_rule(M: 'TemoaModel', r, p, t): + r"""Constrain ramp down rate of new capacity deployment""" + new_cap, new_cap_prev, GRS, GRM = GrowthRateChange_rule(M, r, p, t) + return new_cap_prev <= GRS + GRM * new_cap def GrowthRateChangeMaxConstraint_rule(M: 'TemoaModel', r, p, t): + r"""Constrain ramp up rate of new capacity deployment""" + new_cap, new_cap_prev, GRS, GRM = GrowthRateChange_rule(M, r, p, t) + return new_cap <= GRS + GRM * new_cap_prev + + +def GrowthRateChange_rule(M: 'TemoaModel', r, p, t): r""" Constrain the change of new capacity deployed between periods. Forces the model to ramp up and down the deployment of new technologies @@ -1927,9 +1935,10 @@ def GrowthRateChangeMaxConstraint_rule(M: 'TemoaModel', r, p, t): NewCapRTV = M.V_NewCapacity # relevant r, p, t indices - cap_rtv = set((_r, _t, _v) for _r, _t, _v in NewCapRTV if _t == t and _r in regions) + cap_rtv = set((_r, _t, _v) for _r, _t, _v in NewCapRTV if _t == t and _r in regions + ) # periods the technology can have capacity in this region (sorted) - periods = sorted(set(_v for _r, _t, _v in cap_rtv)) + periods = sorted(set(_v for _r, _t, _v in cap_rtv if _v in M.time_optimize)) if p not in periods: # cant build capacity in this period @@ -1942,15 +1951,21 @@ def GrowthRateChangeMaxConstraint_rule(M: 'TemoaModel', r, p, t): # first period it can build new capacity # Capped at the constant (seed) parameter p_last = M.time_exist.last() - if GRS == 0: + new_cap_prev = sum( + value(M.ExistingCapacity[_r, _t, _v]) \ + * min( 1.0, (_v + value(M.LifetimeProcess[_r, _t, _v]) - p_last)/(p - p_last) ) + for _r, _t, _v in M.ExistingCapacity + if _r in regions and _t == t and _v == p_last + ) + if new_cap_prev == 0 and GRS == 0: msg = ( 'No constant term (GrowthRateChangeSeed) provided for GrowthRateChangeMax constraint {} ' - 'so there is nothing to grow from. No capacity would be built for this technology in ' - 'this region.' + 'and no existing capacity was deployed in the last existing period so there is ' + 'nothing to grow from. No capacity would be built for this technology in this ' + 'region.' ).format((r, t)) logger.error(msg) raise ValueError(msg) - expr = new_cap <= GRS else: # can have capacity in previous period # plant a seed and grow last period's capacity @@ -1967,9 +1982,8 @@ def GrowthRateChangeMaxConstraint_rule(M: 'TemoaModel', r, p, t): for _r, _t, _v in cap_rtv if _v == p_prev ) - expr = new_cap <= GRS + GRM * new_cap_prev - - return expr + + return new_cap, new_cap_prev, GRS, GRM def MaxActivity_Constraint(M: 'TemoaModel', r, p, t): diff --git a/temoa/temoa_model/temoa_sequencer.py b/temoa/temoa_model/temoa_sequencer.py index 6804dcbc8..5057564c6 100644 --- a/temoa/temoa_model/temoa_sequencer.py +++ b/temoa/temoa_model/temoa_sequencer.py @@ -194,8 +194,8 @@ def start(self) -> TemoaModel | None: if self.config.price_check is False: logger.warning('Price check of model is automatic with CHECK') good_prices = price_checker(instance) - # if not good_prices and not self.config.silent: - # print('\nWarning: Cost anomalies discovered. Check log file for details.') + if not good_prices and not self.config.silent: + print('Warning: Cost anomalies discovered. Check log file for details.') con.close() case TemoaMode.PERFECT_FORESIGHT: @@ -210,8 +210,8 @@ def start(self) -> TemoaModel | None: ) if self.config.price_check: good_prices = price_checker(instance) - # if not good_prices and not self.config.silent: - # print('\nWarning: Cost anomalies discovered. Check log file for details.') + if not good_prices and not self.config.silent: + print('Warning: Cost anomalies discovered. Check log file for details.') suffixes = ( [ 'dual', From da6abea0580e40d4627d3da246161e22dfbe0d76 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 21 May 2025 12:41:00 -0400 Subject: [PATCH 078/587] Rework and expand growth constraints --- temoa/extensions/myopic/myopic_sequencer.py | 62 ++-- temoa/temoa_model/hybrid_loader.py | 80 +++-- temoa/temoa_model/temoa_initialize.py | 50 ++- temoa/temoa_model/temoa_model.py | 44 ++- temoa/temoa_model/temoa_rules.py | 338 ++++++++++++++------ 5 files changed, 404 insertions(+), 170 deletions(-) diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index add584f38..83cde4072 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -385,38 +385,40 @@ def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: i ) self.output_con.commit() + # devnote: There is a bug here somewhere where we lose existing capacities when + # rolling back. Better just to leave it out. # 1. Clean up stuff not implemented or retired by the last time period in previous step, # exempting unlim_cap techs (of course...who would forget that?) - last_interval_end, flag = self.cursor.execute( - 'SELECT MAX(period), flag FROM main.TimePeriod WHERE period < ?', - (myopic_index.base_year,), - ).fetchone() - if flag == 'f': # the prior period should have an OutputNetCapacity entry - # Delete anything that doesn't have capacity remaining at the end of last interval - delete_qry = ( - 'DELETE FROM MyopicEfficiency ' - 'WHERE (SELECT region, tech, vintage) ' - ' NOT IN (SELECT region, tech, vintage FROM OutputNetCapacity ' - ' WHERE period = ? AND scenario = ?) ' - 'AND tech not in (SELECT tech FROM Technology where unlim_cap > 0)' - ) - - if self.debugging: - debug_query = ( - 'SELECT * FROM MyopicEfficiency ' - 'WHERE (SELECT region, tech, vintage) ' - ' NOT IN (SELECT region, tech, vintage FROM OutputNetCapacity ' - ' WHERE period = ? AND scenario = ?) ' - 'AND tech not in (SELECT tech FROM Technology where unlim_cap > 0)' - ) - print('\n\n **** Removing these unused region-tech-vintage combos ****') - removals = self.cursor.execute( - debug_query, (last_interval_end, self.config.scenario) - ).fetchall() - for i, removal in enumerate(removals): - print(f'{i}. Removing: {removal}') - self.cursor.execute(delete_qry, (last_interval_end, self.config.scenario)) - self.output_con.commit() + # last_interval_end, flag = self.cursor.execute( + # 'SELECT MAX(period), flag FROM main.TimePeriod WHERE period < ?', + # (myopic_index.base_year,), + # ).fetchone() + # if flag == 'f': # the prior period should have an OutputNetCapacity entry + # # Delete anything that doesn't have capacity remaining at the end of last interval + # delete_qry = ( + # 'DELETE FROM MyopicEfficiency ' + # 'WHERE (SELECT region, tech, vintage) ' + # ' NOT IN (SELECT region, tech, vintage FROM OutputNetCapacity ' + # ' WHERE period = ? AND scenario = ?) ' + # 'AND tech not in (SELECT tech FROM Technology where unlim_cap > 0)' + # ) + + # if self.debugging: + # debug_query = ( + # 'SELECT * FROM MyopicEfficiency ' + # 'WHERE (SELECT region, tech, vintage) ' + # ' NOT IN (SELECT region, tech, vintage FROM OutputNetCapacity ' + # ' WHERE period = ? AND scenario = ?) ' + # 'AND tech not in (SELECT tech FROM Technology where unlim_cap > 0)' + # ) + # print('\n\n **** Removing these unused region-tech-vintage combos ****') + # removals = self.cursor.execute( + # debug_query, (last_interval_end, self.config.scenario) + # ).fetchall() + # for i, removal in enumerate(removals): + # print(f'{i}. Removing: {removal}') + # self.cursor.execute(delete_qry, (last_interval_end, self.config.scenario)) + # self.output_con.commit() # 2. Add the new stuff now visible # dev note: the `coalesce()` command is a nested if-else. The first hit wins, so it is priority: diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 8f01d580a..fdb355fe6 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -79,10 +79,12 @@ 'MinNewCapacityGroupShare': 'region', 'MaxNewCapacityGroupShare': 'region', 'MaxResource': 'region', - 'GrowthRateMax': 'region', - 'GrowthRateSeed': 'region', - 'GrowthRateChangeMax': 'region', - 'GrowthRateChangeSeed': 'region', + 'GrowthCapacity': 'region', + 'DegrowthCapacity': 'region', + 'GrowthNewCapacity': 'region', + 'DegrowthNewCapacity': 'region', + 'GrowthNewCapacityDelta': 'region', + 'DegrowthNewCapacityDelta': 'region', } @@ -599,6 +601,12 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N raw = cur.execute("SELECT name FROM main.Commodity WHERE flag = 'a'").fetchall() load_element(M.commodity_annual, raw, self.viable_input_comms) + # === OPERATORS === + + # operator + raw = cur.execute("SELECT operator FROM main.Operator").fetchall() + load_element(M.operator, raw) + # === PARAMS === # Efficiency @@ -626,8 +634,8 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N previous_period = raw[0] # noinspection SqlUnused raw = cur.execute( - 'SELECT region, tech, vintage, capacity FROM main.OutputNetCapacity ' - ' WHERE period = ? ' + 'SELECT region, tech, vintage, capacity FROM main.OutputBuiltCapacity ' + ' WHERE vintage <= ? ' ' AND scenario = ? ' 'UNION ' ' SELECT region, tech, vintage, capacity FROM main.ExistingCapacity ', @@ -1047,25 +1055,41 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, output_comm, factor FROM main.MaxAnnualCapacityFactor') load_element(M.MaxAnnualCapacityFactor, raw, self.viable_rt, (0, 2)) - # GrowthRateMax - if self.table_exists('GrowthRateMax'): - raw = cur.execute('SELECT region, tech, rate FROM main.GrowthRateMax').fetchall() - load_element(M.GrowthRateMax, raw, self.viable_rt, (0, 1)) - - # GrowthRateSeed - if self.table_exists('GrowthRateSeed'): - raw = cur.execute('SELECT region, tech, seed FROM main.GrowthRateSeed').fetchall() - load_element(M.GrowthRateSeed, raw, self.viable_rt, (0, 1)) - - # GrowthRateChangeMax - if self.table_exists('GrowthRateChangeMax'): - raw = cur.execute('SELECT region, tech, rate FROM main.GrowthRateChangeMax').fetchall() - load_element(M.GrowthRateChangeMax, raw, self.viable_rt, (0, 1)) - - # GrowthRateChangeSeed - if self.table_exists('GrowthRateChangeSeed'): - raw = cur.execute('SELECT region, tech, seed FROM main.GrowthRateChangeSeed').fetchall() - load_element(M.GrowthRateChangeSeed, raw, self.viable_rt, (0, 1)) + # GrowthCapacity + if self.table_exists('GrowthCapacity'): + raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.GrowthCapacity').fetchall() + raw = self.tuple_values(raw, 3) + load_element(M.GrowthCapacity, raw, self.viable_rt, (0, 1)) + + # DegrowthCapacity + if self.table_exists('DegrowthCapacity'): + raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.DegrowthCapacity').fetchall() + raw = self.tuple_values(raw, 3) + load_element(M.DegrowthCapacity, raw, self.viable_rt, (0, 1)) + + # GrowthNewCapacity + if self.table_exists('GrowthNewCapacity'): + raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.GrowthNewCapacity').fetchall() + raw = self.tuple_values(raw, 3) + load_element(M.GrowthNewCapacity, raw, self.viable_rt, (0, 1)) + + # DegrowthNewCapacity + if self.table_exists('DegrowthNewCapacity'): + raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.DegrowthNewCapacity').fetchall() + raw = self.tuple_values(raw, 3) + load_element(M.DegrowthNewCapacity, raw, self.viable_rt, (0, 1)) + + # GrowthNewCapacityDelta + if self.table_exists('GrowthNewCapacityDelta'): + raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.GrowthNewCapacityDelta').fetchall() + raw = self.tuple_values(raw, 3) + load_element(M.GrowthNewCapacityDelta, raw, self.viable_rt, (0, 1)) + + # DegrowthNewCapacityDelta + if self.table_exists('DegrowthNewCapacityDelta'): + raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.DegrowthNewCapacityDelta').fetchall() + raw = self.tuple_values(raw, 3) + load_element(M.DegrowthNewCapacityDelta, raw, self.viable_rt, (0, 1)) # EmissionLimit if self.table_exists('EmissionLimit'): @@ -1181,6 +1205,12 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N return data + def tuple_values(self, raw, index_length): + new_raw = [] + for row in raw: + new_raw.append((*row[0:index_length], row[index_length::])) + return new_raw + def raw_check_mi_period(self, mi: MyopicIndex | None, cur: Cursor, qry: str) -> list: if mi: return cur.execute( diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index b273d0d74..b160f78f7 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -746,12 +746,12 @@ def CreateSparseDicts(M: 'TemoaModel'): '{} specified as ExistingCapacity, but its ' 'lifetime ({} years) does not extend past the ' 'beginning of time_future ({}) so it is never active. This ' - 'may be intentional for use in GrowthRate constraints ' + 'may be intentional for use in Growth constraints ' 'or end of life flows.' ).format(l_process, l_lifetime, l_first_period) logger.info(msg) # Devnote: these are now useful due to end of life flows and - # GrowthRate constraints growing from existing cap so do not skip + # Growth constraints growing from existing cap so do not skip #SE.write(msg % (l_process, l_lifetime, l_first_period)) #continue @@ -1739,7 +1739,6 @@ def MaxTechOutputSplitAnnualConstraintIndices(M: 'TemoaModel'): if t in M.tech_annual for v in M.maxOutputSplitAnnualVintages[r, p, t, o] ) - return indices @@ -1753,19 +1752,52 @@ def MaxTechOutputSplitAverageConstraintIndices(M: 'TemoaModel'): return indices -def GrowthRateMaxIndices(M: 'TemoaModel'): +def GrowthCapacityIndices(M: 'TemoaModel'): indices = set( - (r, p, t) - for r, t in M.GrowthRateMax.sparse_iterkeys() | M.GrowthRateSeed.sparse_iterkeys() + (r, p, t, op) + for r, t, op in M.GrowthCapacity.sparse_iterkeys() + for p in M.time_optimize + ) + return indices + +def DegrowthCapacityIndices(M: 'TemoaModel'): + indices = set( + (r, p, t, op) + for r, t, op in M.DegrowthCapacity.sparse_iterkeys() for p in M.time_optimize ) return indices -def GrowthRateChangeIndices(M: 'TemoaModel'): +def GrowthNewCapacityIndices(M: 'TemoaModel'): indices = set( - (r, p, t) - for r, t in M.GrowthRateChangeMax.sparse_iterkeys() | M.GrowthRateChangeSeed.sparse_iterkeys() + (r, p, t, op) + for r, t, op in M.GrowthNewCapacity.sparse_iterkeys() + for p in M.time_optimize + ) + return indices + +def DegrowthNewCapacityIndices(M: 'TemoaModel'): + indices = set( + (r, p, t, op) + for r, t, op in M.DegrowthNewCapacity.sparse_iterkeys() + for p in M.time_optimize + ) + return indices + + +def GrowthNewCapacityDeltaIndices(M: 'TemoaModel'): + indices = set( + (r, p, t, op) + for r, t, op in M.GrowthNewCapacityDelta.sparse_iterkeys() + for p in M.time_optimize + ) + return indices + +def DegrowthNewCapacityDeltaIndices(M: 'TemoaModel'): + indices = set( + (r, p, t, op) + for r, t, op in M.DegrowthNewCapacityDelta.sparse_iterkeys() for p in M.time_optimize ) return indices diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 53fa3e625..e37102f58 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -126,7 +126,7 @@ def __init__(M, *args, **kwargs): M.processByPeriodAndOutput = dict() M.exportRegions = dict() M.importRegions = dict() - M.time_next = dict() + M.time_next = dict() # {(s, d): (s_next, d_next)} sequence of following time slices ################################################ # Switching Sets # @@ -143,6 +143,8 @@ def __init__(M, *args, **kwargs): M.progress_marker_1 = BuildAction(['Starting to build Sets'], rule=progress_check) + M.operator = Set() + # Define time periods M.time_exist = Set(ordered=True) M.time_future = Set(ordered=True) @@ -448,10 +450,12 @@ def __init__(M, *args, **kwargs): ) M.MaxAnnualCapacityFactor = Param(M.MaxAnnualCapacityFactorConstraint_rpto) - M.GrowthRateMax = Param(M.regionalGlobalIndices, M.tech_all, default=0) - M.GrowthRateSeed = Param(M.regionalGlobalIndices, M.tech_all, default=0) - M.GrowthRateChangeMax = Param(M.regionalGlobalIndices, M.tech_all, default=0) - M.GrowthRateChangeSeed = Param(M.regionalGlobalIndices, M.tech_all, default=0) + M.GrowthCapacity = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) + M.DegrowthCapacity = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) + M.GrowthNewCapacity = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) + M.DegrowthNewCapacity = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) + M.GrowthNewCapacityDelta = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) + M.DegrowthNewCapacityDelta = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) M.EmissionLimitConstraint_rpe = Set( within=M.regionalGlobalIndices * M.time_optimize * M.commodity_emissions @@ -731,17 +735,31 @@ def __init__(M, *args, **kwargs): ['Starting Growth and Activity Constraints'], rule=progress_check ) - M.GrowthRateMaxConstraint_rtv = Set(dimen=3, initialize=GrowthRateMaxIndices) - M.GrowthRateMaxConstraint = Constraint( - M.GrowthRateMaxConstraint_rtv, rule=GrowthRateMaxConstraint_rule + M.GrowthCapacityConstraint_rtpop = Set(dimen=4, initialize=GrowthCapacityIndices) + M.GrowthCapacityConstraint = Constraint( + M.GrowthCapacityConstraint_rtpop, rule=GrowthCapacityConstraint_rule + ) + M.DegrowthCapacityConstraint_rtpop = Set(dimen=4, initialize=DegrowthCapacityIndices) + M.DegrowthCapacityConstraint = Constraint( + M.DegrowthCapacityConstraint_rtpop, rule=DegrowthCapacityConstraint_rule + ) + + M.GrowthNewCapacityConstraint_rtpop = Set(dimen=4, initialize=GrowthNewCapacityIndices) + M.GrowthNewCapacityConstraint = Constraint( + M.GrowthNewCapacityConstraint_rtpop, rule=GrowthNewCapacityConstraint_rule + ) + M.DegrowthNewCapacityConstraint_rtpop = Set(dimen=4, initialize=DegrowthNewCapacityIndices) + M.DegrowthNewCapacityConstraint = Constraint( + M.DegrowthNewCapacityConstraint_rtpop, rule=DegrowthNewCapacityConstraint_rule ) - M.GrowthRateChangeConstraint_rtv = Set(dimen=3, initialize=GrowthRateChangeIndices) - M.GrowthRateChangeMinConstraint = Constraint( - M.GrowthRateChangeConstraint_rtv, rule=GrowthRateChangeMinConstraint_rule + M.GrowthNewCapacityDeltaConstraint_rtpop = Set(dimen=4, initialize=GrowthNewCapacityDeltaIndices) + M.GrowthNewCapacityDeltaConstraint = Constraint( + M.GrowthNewCapacityDeltaConstraint_rtpop, rule=GrowthNewCapacityDeltaConstraint_rule ) - M.GrowthRateChangeMaxConstraint = Constraint( - M.GrowthRateChangeConstraint_rtv, rule=GrowthRateChangeMaxConstraint_rule + M.DegrowthNewCapacityDeltaConstraint_rtpop = Set(dimen=4, initialize=DegrowthNewCapacityDeltaIndices) + M.DegrowthNewCapacityDeltaConstraint = Constraint( + M.DegrowthNewCapacityDeltaConstraint_rtpop, rule=DegrowthNewCapacityDeltaConstraint_rule ) M.MaxActivityConstraint = Constraint( diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 6b021d0d9..0e48d7a8b 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1829,30 +1829,27 @@ def EmissionLimit_Constraint(M: 'TemoaModel', r, p, e): return expr -def GrowthRateMaxConstraint_rule(M: 'TemoaModel', r, p, t): - r""" - - This constraint sets an upper bound growth rate on technology-specific capacity. - - .. math:: - :label: GrowthRate +def GrowthCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): + r"""Constrain ramp down rate of available capacity""" + return GrowthCapacity(M, r, p, t, op, False) - CAPAVL_{r, p_{i},t} \le GRM \cdot CAPAVL_{r,p_{i-1},t} + GRS +def DegrowthCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): + r"""Constrain ramp up rate of available capacity""" + return GrowthCapacity(M, r, p, t, op, True) - \\ - \forall \{r, p, t\} \in \Theta_{\text{GrowthRate}} - - where :math:`GRM` is the maximum growth rate, and should be specified as - :math:`(1+r)` and :math:`GRS` is the growth rate seed, which has units of - capacity. Without the seed, any technology with zero capacity in the first time - period would be restricted to zero capacity for the remainder of the time - horizon. +def GrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): + r""" + Constrain the change of capacity available between periods. + Forces the model to ramp up and down the availability of new technologies + more smoothly. Has constant (seed) and proportional (rate) terms. + + CapacityAvailable_(p) <= SEED + RATE * CapacityAvailable_(p-1) """ regions = gather_group_regions(M, r) - GRS = value(M.GrowthRateSeed[r, t]) - GRM = 1 + value(M.GrowthRateMax[r, t]) + RATE = 1 + value(M.GrowthCapacity[r, t, op][0]) + SEED = value(M.GrowthCapacity[r, t, op][1]) CapRPT = M.V_CapacityAvailableByPeriodAndTech # relevant r, p, t indices @@ -1860,130 +1857,256 @@ def GrowthRateMaxConstraint_rule(M: 'TemoaModel', r, p, t): # periods the technology can have capacity in this region (sorted) periods = sorted(set(_p for _r, _p, _t in cap_rpt)) - if p not in periods: - # cant have capacity in this period + if len(periods) == 0 and p == M.time_optimize.first(): + msg = ( + 'Tried to set {}rowthCapacity constraint {} but there are no periods where this ' + 'technology is available in this region. Constraint skipped.' + ).format("Deg" if degrowth else "G", (r, t)) + logger.warning(msg) return Constraint.Skip + # Only warn in p0 so we dont dump multiple warnings + if p == periods[0]: + if SEED == 0: + msg = ( + 'No constant term (seed) provided for {}rowthCapacity constraint {}. ' + 'No capacity will be built in any period following one with zero capacity.' + ).format("Deg" if degrowth else "G", (r, t)) + logger.info(msg) + gaps = [_p for _p in M.time_optimize if _p not in periods and min(periods) < _p < max(periods)] + if gaps: + msg = ( + 'Constructing {}rowthCapacity constraint {} and there are period gaps in which' + 'capacity cannot exist in this region ({}). Capacity in these periods ' + 'will be treated as zero which may cause infeasibility or other problems.' + ).format("Deg" if degrowth else "G", (r, t), gaps) + logger.warning(msg) + # sum available capacity in this period capacity = sum(CapRPT[_r, _p, _t] for _r, _p, _t in cap_rpt if _p == p) - if p == periods[0]: - # first period it can have new capacity - # grow from existing capacity in last existing period, adjusting in-line for PLF - # or, otherwise, capped at the constant (seed) parameter - p_last = M.time_exist.last() + if p == M.time_optimize.first(): + # First future period. Grab available capacity in last existing period + # Adjust in-line for past PLF because we are constraining available capacity + p_prev = M.time_exist.last() capacity_prev = sum( value(M.ExistingCapacity[_r, _t, _v]) \ - * min( 1.0, (_v + value(M.LifetimeProcess[_r, _t, _v]) - p_last)/(p - p_last) ) + * min( 1.0, (_v + value(M.LifetimeProcess[_r, _t, _v]) - p_prev)/(p - p_prev) ) for _r, _t, _v in M.ExistingCapacity - if _r in regions and _t == t and _v + value(M.LifetimeProcess[_r, _t, _v]) > p_last + if _r in regions and _t == t and _v + value(M.LifetimeProcess[_r, _t, _v]) > p_prev ) - if capacity_prev == 0 and GRS == 0: - msg = ( - 'No constant term (GrowthRateSeed) provided for GrowthRateMax constraint {} ' - 'and no existing capacity was found in the last existing period so there is ' - 'nothing to grow from. No capacity would be built for this technology in this ' - 'region.' - ).format((r, t)) - logger.error(msg) - raise ValueError(msg) else: - # can have capacity in previous period - # plant a seed and grow last period's capacity - # note: we plant a seed every period to survive zero-outs - if GRS == 0: - msg = ( - 'No constant term (GrowthRateSeed) provided for GrowthRateMax constraint {}. ' - 'No capacity will be built in any period following one with zero capacity.' - ).format((r, t)) - logger.warning(msg) - p_prev = periods[periods.index(p) - 1] # previous period - capacity_prev = sum(CapRPT[_r, p_prev, t] for _r in regions) + # Otherwise, grab previous future period + p_prev = M.time_optimize.prev(p) capacity_prev = sum( CapRPT[_r, _p, _t] for _r, _p, _t in cap_rpt if _p == p_prev ) - return capacity <= GRS + GRM * capacity_prev + if degrowth: + expr = operator_expression(capacity_prev, op, SEED + capacity * RATE) + else: + expr = operator_expression(capacity, op, SEED + capacity_prev * RATE) + + # Check if any variables are actually included before returning + if isinstance(expr, bool): + return Constraint.Skip + return expr + -def GrowthRateChangeMinConstraint_rule(M: 'TemoaModel', r, p, t): +def GrowthNewCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): r"""Constrain ramp down rate of new capacity deployment""" - new_cap, new_cap_prev, GRS, GRM = GrowthRateChange_rule(M, r, p, t) - return new_cap_prev <= GRS + GRM * new_cap + return GrowthNewCapacity(M, r, p, t, op, False) -def GrowthRateChangeMaxConstraint_rule(M: 'TemoaModel', r, p, t): +def DegrowthNewCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): r"""Constrain ramp up rate of new capacity deployment""" - new_cap, new_cap_prev, GRS, GRM = GrowthRateChange_rule(M, r, p, t) - return new_cap <= GRS + GRM * new_cap_prev - + return GrowthNewCapacity(M, r, p, t, op, True) -def GrowthRateChange_rule(M: 'TemoaModel', r, p, t): +def GrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): r""" Constrain the change of new capacity deployed between periods. Forces the model to ramp up and down the deployment of new technologies - more smoothly. Has constant (GrowthRateChangeSeed) and proportional - (GrowthRateChangeMax) terms. + more smoothly. Has constant (seed) and proportional (rate) terms. - NewCapacity_(p+1) <= GRCS + GRCM * NewCapacity_(p) + NewCapacity_(p) <= SEED + RATE * NewCapacity_(p-1) """ regions = gather_group_regions(M, r) - GRS = value(M.GrowthRateChangeSeed[r, t]) - GRM = 1 + value(M.GrowthRateChangeMax[r, t]) + RATE = 1 + value(M.GrowthNewCapacity[r, t, op][0]) + SEED = value(M.GrowthNewCapacity[r, t, op][1]) NewCapRTV = M.V_NewCapacity - # relevant r, p, t indices - cap_rtv = set((_r, _t, _v) for _r, _t, _v in NewCapRTV if _t == t and _r in regions - ) - # periods the technology can have capacity in this region (sorted) - periods = sorted(set(_v for _r, _t, _v in cap_rtv if _v in M.time_optimize)) + # relevant r, t, v indices + cap_rtv = set((_r, _t, _v) for _r, _t, _v in NewCapRTV if _t == t and _r in regions) + # periods the technology can be built in this region (sorted) + periods = sorted(set(_v for _r, _t, _v in NewCapRTV if _v in M.time_optimize)) - if p not in periods: - # cant build capacity in this period + if len(periods) == 0 and p == M.time_optimize.first(): + msg = ( + 'Tried to set {}rowthNewCapacity constraint {} but there are no periods where this ' + 'technology can be built in this region. Constraint skipped.' + ).format("Deg" if degrowth else "G", (r, t)) + logger.warning(msg) return Constraint.Skip + # Only warn in p0 so we dont dump multiple warnings + if p == periods[0]: + if SEED == 0: + msg = ( + 'No constant term (seed) provided for {}rowthNewCapacity constraint {}. ' + 'No capacity will be built in any period following one with zero new capacity.' + ).format("Deg" if degrowth else "G", (r, t)) + logger.info(msg) + gaps = [_p for _p in M.time_optimize if _p not in periods and min(periods) < _p < max(periods)] + if gaps: + msg = ( + 'Constructing {}rowthNewCapacity constraint {} and there are period gaps in which' + 'new capacity cannot be built in this region ({}). New capacity in these periods ' + 'will be treated as zero which may cause infeasibility or other problems.' + ).format("Deg" if degrowth else "G", (r, t), gaps) + logger.warning(msg) + # sum new capacity in this period new_cap = sum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p) - if p == periods[0]: - # first period it can build new capacity - # Capped at the constant (seed) parameter - p_last = M.time_exist.last() + if p == M.time_optimize.first(): + # First future period. Grab last existing vintage + p_prev = M.time_exist.last() new_cap_prev = sum( - value(M.ExistingCapacity[_r, _t, _v]) \ - * min( 1.0, (_v + value(M.LifetimeProcess[_r, _t, _v]) - p_last)/(p - p_last) ) + value(M.ExistingCapacity[_r, _t, _v]) for _r, _t, _v in M.ExistingCapacity - if _r in regions and _t == t and _v == p_last + if _r in regions and _t == t and _v == p_prev ) - if new_cap_prev == 0 and GRS == 0: - msg = ( - 'No constant term (GrowthRateChangeSeed) provided for GrowthRateChangeMax constraint {} ' - 'and no existing capacity was deployed in the last existing period so there is ' - 'nothing to grow from. No capacity would be built for this technology in this ' - 'region.' - ).format((r, t)) - logger.error(msg) - raise ValueError(msg) else: - # can have capacity in previous period - # plant a seed and grow last period's capacity - # note: we plant a seed every period to survive zero-outs - if GRS == 0: + # Otherwise, grab previous future vintage + p_prev = M.time_optimize.prev(p) + new_cap_prev = sum( + NewCapRTV[_r, _t, _v] + for _r, _t, _v in cap_rtv + if _v == p_prev + ) + + if degrowth: + expr = operator_expression(new_cap_prev, op, SEED + new_cap * RATE) + else: + expr = operator_expression(new_cap, op, SEED + new_cap_prev * RATE) + + # Check if any variables are actually included before returning + if isinstance(expr, bool): + return Constraint.Skip + return expr + + +def GrowthNewCapacityDeltaConstraint_rule(M: 'TemoaModel', r, p, t, op): + r"""Constrain ramp down rate of change in new capacity deployment""" + return GrowthNewCapacityDelta(M, r, p, t, op, False) + +def DegrowthNewCapacityDeltaConstraint_rule(M: 'TemoaModel', r, p, t, op): + r"""Constrain ramp up rate of change in new capacity deployment""" + return GrowthNewCapacityDelta(M, r, p, t, op, True) + +def GrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): + r""" + Constrain the acceleration of new capacity deployed between periods. + Forces the model to ramp up and down the change in deployment of new technologies + more smoothly. Has constant (seed) and proportional (rate) terms. + + (NewCapacity_(p) - NewCapacity_(p-1)) <= SEED + RATE * (NewCapacity_(p-1) - NewCapacity_(p-2)) + """ + + regions = gather_group_regions(M, r) + + RATE = 1 + value(M.GrowthNewCapacityDelta[r, t, op][0]) + SEED = value(M.GrowthNewCapacityDelta[r, t, op][1]) + NewCapRTV = M.V_NewCapacity + + # relevant r, t, v indices + cap_rtv = set((_r, _t, _v) for _r, _t, _v in NewCapRTV if _t == t and _r in regions) + # periods the technology can be built in this region (sorted) + periods = sorted(set(_v for _r, _t, _v in cap_rtv if _v in M.time_optimize)) + + if len(periods) == 0 and p == M.time_optimize.first(): + msg = ( + 'Tried to set {}rowthNewCapacityDelta constraint {} but there are no periods where this ' + 'technology can be built in this region. Constraint skipped.' + ).format("Deg" if degrowth else "G", (r, t)) + logger.warning(msg) + return Constraint.Skip + + # Only warn in p0 so we dont dump multiple warnings + if p == periods[0]: + if SEED == 0: msg = ( - 'No constant term (GrowthRateChangeSeed) provided for GrowthRateChangeMax constraint {}. ' - 'No new capacity will be built in any period following one with zero new capacity.' - ).format((r, t)) + 'No constant term (seed) provided for {}rowthNewCapacityDelta constraint {}. ' + 'This is not recommended as deployment rates cannot inflect (change from ' + 'accelerating to decelerating or vice-versa).' + ).format("Deg" if degrowth else "G", (r, t)) logger.warning(msg) - p_prev = periods[periods.index(p) - 1] # previous period + gaps = [_p for _p in M.time_optimize if _p not in periods and min(periods) < _p < max(periods)] + if gaps: + msg = ( + 'Constructing {}rowthNewCapacityDelta constraint {} and there are period gaps in which' + 'new capacity cannot be built in this region ({}). New capacity in these periods ' + 'will be treated as zero which may cause infeasibility or other problems.' + ).format("Deg" if degrowth else "G", (r, t), gaps) + logger.warning(msg) + + # sum new capacity in this period + new_cap = sum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p) + + if p == M.time_optimize.first(): + # First planning period, pull last two existing vintages + p_prev = M.time_exist.last() + new_cap_prev = sum( + value(M.ExistingCapacity[_r, _t, _v]) + for _r, _t, _v in M.ExistingCapacity + if _r in regions and _t == t and _v == p_prev + ) + p_prev2 = M.time_exist.prev(p_prev) + new_cap_prev2 = sum( + value(M.ExistingCapacity[_r, _t, _v]) + for _r, _t, _v in M.ExistingCapacity + if _r in regions and _t == t and _v == p_prev2 + ) + else: + # Not the first future period. Grab previous future period + p_prev = M.time_optimize.prev(p) new_cap_prev = sum( NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p_prev ) + if p == M.time_optimize.at(2): # apparently pyomo sets are indexed 1-based + # Second future period, grab last existing vintage + p_prev2 = M.time_exist.last() + new_cap_prev2 = sum( + value(M.ExistingCapacity[_r, _t, _v]) + for _r, _t, _v in M.ExistingCapacity + if _r in regions and _t == t and _v == p_prev2 + ) + else: + # At least the third future period. Grab last two future vintages + p_prev2 = M.time_optimize.prev(p_prev) + new_cap_prev2 = sum( + NewCapRTV[_r, _t, _v] + for _r, _t, _v in cap_rtv + if _v == p_prev2 + ) + + nc_delta_prev = new_cap_prev - new_cap_prev2 + nc_delta = new_cap - new_cap_prev + + if degrowth: + expr = operator_expression(nc_delta_prev, op, SEED + nc_delta * RATE) + else: + expr = operator_expression(nc_delta, op, SEED + nc_delta_prev * RATE) - return new_cap, new_cap_prev, GRS, GRM + # Check if any variables are actually included before returning + if isinstance(expr, bool): + return Constraint.Skip + return expr def MaxActivity_Constraint(M: 'TemoaModel', r, p, t): @@ -3517,6 +3640,35 @@ def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): return -primary_flow == linked_flow +def operator_expression(lhs: Expression | None, operator: str | None, rhs: Expression | None): + """Returns an expression, applying a configured operator""" + if any((lhs is None, operator is None, rhs is None)): + msg = ( + 'Tried to build a constraint using a bad expression or operator. Constraint skipped: ' + '{} {} {}' + ).format(lhs, operator, rhs) + logger.error(msg) + raise ValueError(msg) + match operator: + case "e": + expr = lhs == rhs + case "l": + expr = lhs < rhs + case "g": + expr = lhs > rhs + case "le": + expr = lhs <= rhs + case "ge": + expr = lhs >= rhs + case _: + msg = ( + 'Tried to build a constraint using a bad operator. Constraint skipped: {} {} {}' + ).format(lhs, operator, rhs) + logger.error(msg) + raise ValueError(msg) + + return expr + # To avoid building big many-indexed parameters when they aren't needed - saves memory # Much faster to build a dictionary and check that than check the parameter From 5a95027a58cb86e087b2c71e092ebb7c1378c40a Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 21 May 2025 14:26:37 -0400 Subject: [PATCH 079/587] Hotfix to asymmetric growth and degrowth --- temoa/temoa_model/temoa_rules.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 0e48d7a8b..44b888663 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1848,8 +1848,9 @@ def GrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): regions = gather_group_regions(M, r) - RATE = 1 + value(M.GrowthCapacity[r, t, op][0]) - SEED = value(M.GrowthCapacity[r, t, op][1]) + growth = M.DegrowthCapacity if degrowth else M.GrowthCapacity + RATE = 1 + value(growth[r, t, op][0]) + SEED = value(growth[r, t, op][1]) CapRPT = M.V_CapacityAvailableByPeriodAndTech # relevant r, p, t indices @@ -1934,8 +1935,9 @@ def GrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): regions = gather_group_regions(M, r) - RATE = 1 + value(M.GrowthNewCapacity[r, t, op][0]) - SEED = value(M.GrowthNewCapacity[r, t, op][1]) + growth = M.DegrowthNewCapacity if degrowth else M.GrowthNewCapacity + RATE = 1 + value(growth[r, t, op][0]) + SEED = value(growth[r, t, op][1]) NewCapRTV = M.V_NewCapacity # relevant r, t, v indices @@ -2018,8 +2020,9 @@ def GrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = False) regions = gather_group_regions(M, r) - RATE = 1 + value(M.GrowthNewCapacityDelta[r, t, op][0]) - SEED = value(M.GrowthNewCapacityDelta[r, t, op][1]) + growth = M.DegrowthNewCapacityDelta if degrowth else M.GrowthNewCapacityDelta + RATE = 1 + value(growth[r, t, op][0]) + SEED = value(growth[r, t, op][1]) NewCapRTV = M.V_NewCapacity # relevant r, t, v indices From 4ab3669a5204a0136502e278d018fd0e0afab1ed Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 21 May 2025 18:10:13 -0400 Subject: [PATCH 080/587] Fix some bugs for handling existing capacities --- temoa/extensions/myopic/myopic_sequencer.py | 62 +++++++++---------- temoa/temoa_model/hybrid_loader.py | 4 +- .../model_checking/network_model_data.py | 18 +++--- temoa/temoa_model/table_data_puller.py | 4 ++ temoa/temoa_model/temoa_initialize.py | 10 +-- temoa/temoa_model/temoa_rules.py | 5 +- 6 files changed, 50 insertions(+), 53 deletions(-) diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index 83cde4072..add584f38 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -385,40 +385,38 @@ def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: i ) self.output_con.commit() - # devnote: There is a bug here somewhere where we lose existing capacities when - # rolling back. Better just to leave it out. # 1. Clean up stuff not implemented or retired by the last time period in previous step, # exempting unlim_cap techs (of course...who would forget that?) - # last_interval_end, flag = self.cursor.execute( - # 'SELECT MAX(period), flag FROM main.TimePeriod WHERE period < ?', - # (myopic_index.base_year,), - # ).fetchone() - # if flag == 'f': # the prior period should have an OutputNetCapacity entry - # # Delete anything that doesn't have capacity remaining at the end of last interval - # delete_qry = ( - # 'DELETE FROM MyopicEfficiency ' - # 'WHERE (SELECT region, tech, vintage) ' - # ' NOT IN (SELECT region, tech, vintage FROM OutputNetCapacity ' - # ' WHERE period = ? AND scenario = ?) ' - # 'AND tech not in (SELECT tech FROM Technology where unlim_cap > 0)' - # ) - - # if self.debugging: - # debug_query = ( - # 'SELECT * FROM MyopicEfficiency ' - # 'WHERE (SELECT region, tech, vintage) ' - # ' NOT IN (SELECT region, tech, vintage FROM OutputNetCapacity ' - # ' WHERE period = ? AND scenario = ?) ' - # 'AND tech not in (SELECT tech FROM Technology where unlim_cap > 0)' - # ) - # print('\n\n **** Removing these unused region-tech-vintage combos ****') - # removals = self.cursor.execute( - # debug_query, (last_interval_end, self.config.scenario) - # ).fetchall() - # for i, removal in enumerate(removals): - # print(f'{i}. Removing: {removal}') - # self.cursor.execute(delete_qry, (last_interval_end, self.config.scenario)) - # self.output_con.commit() + last_interval_end, flag = self.cursor.execute( + 'SELECT MAX(period), flag FROM main.TimePeriod WHERE period < ?', + (myopic_index.base_year,), + ).fetchone() + if flag == 'f': # the prior period should have an OutputNetCapacity entry + # Delete anything that doesn't have capacity remaining at the end of last interval + delete_qry = ( + 'DELETE FROM MyopicEfficiency ' + 'WHERE (SELECT region, tech, vintage) ' + ' NOT IN (SELECT region, tech, vintage FROM OutputNetCapacity ' + ' WHERE period = ? AND scenario = ?) ' + 'AND tech not in (SELECT tech FROM Technology where unlim_cap > 0)' + ) + + if self.debugging: + debug_query = ( + 'SELECT * FROM MyopicEfficiency ' + 'WHERE (SELECT region, tech, vintage) ' + ' NOT IN (SELECT region, tech, vintage FROM OutputNetCapacity ' + ' WHERE period = ? AND scenario = ?) ' + 'AND tech not in (SELECT tech FROM Technology where unlim_cap > 0)' + ) + print('\n\n **** Removing these unused region-tech-vintage combos ****') + removals = self.cursor.execute( + debug_query, (last_interval_end, self.config.scenario) + ).fetchall() + for i, removal in enumerate(removals): + print(f'{i}. Removing: {removal}') + self.cursor.execute(delete_qry, (last_interval_end, self.config.scenario)) + self.output_con.commit() # 2. Add the new stuff now visible # dev note: the `coalesce()` command is a nested if-else. The first hit wins, so it is priority: diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index fdb355fe6..61b857f43 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -645,7 +645,9 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N raw = cur.execute( 'SELECT region, tech, vintage, capacity FROM main.ExistingCapacity' ).fetchall() - load_element(M.ExistingCapacity, raw, self.viable_rtv, (0, 1, 2)) + # devnote: We want full existing capacity history for end of life flows and growth constraints + # load_element(M.ExistingCapacity, raw, self.viable_rtv, (0, 1, 2)) + load_element(M.ExistingCapacity, raw) # GlobalDiscountRate if self.table_exists("MetaDataReal"): diff --git a/temoa/temoa_model/model_checking/network_model_data.py b/temoa/temoa_model/model_checking/network_model_data.py index 45b53f553..0fca77efc 100644 --- a/temoa/temoa_model/model_checking/network_model_data.py +++ b/temoa/temoa_model/model_checking/network_model_data.py @@ -271,23 +271,23 @@ def _build_from_db( tech in tech_retire and v < p < v+lifetime, # allowed early retirement )): try: - raw = cur.execute( + raw_eol = cur.execute( 'SELECT region, tech, vintage, output_comm FROM EndOfLifeOutput ' f' WHERE region == "{r}" AND tech == "{tech}" AND vintage == {v}' - ) - - for r, tech, v, oc in raw: - techs[r, p].add(Tech(r, tech, 'EndOfLife', v, oc)) - source_dict[r, p].add(tech) - res.cap_commodities.add(tech) - living_techs.add(tech) + ).fetchall() + + for _r, _tech, _v, _oc in raw_eol: + techs[_r, p].add(Tech(_r, _tech, 'EndOfLife', _v, _oc)) + source_dict[_r, p].add(_tech) + res.cap_commodities.add(_tech) + living_techs.add(_tech) except: # EndOfLifeOutput table did not exist TODO remove this eventually pass # Construction input try: - raw = cur.execute('SELECT region, input_comm, tech, vintage FROM ConstructionInput') + raw = cur.execute('SELECT region, input_comm, tech, vintage FROM ConstructionInput').fetchall() for r, ic, tech, v in raw: techs[r, v].add(Tech(r, ic, 'Construction', v, tech)) demand_dict[r, v].add(tech) diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index f9c73ca8a..393c713eb 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -216,6 +216,8 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl # end of life flows for (r, t, v, o) in M.EndOfLifeOutput.sparse_iterkeys(): + if (r, t, v) not in M.retirementPeriods: + continue for p in M.retirementPeriods[r, t, v]: annual = value(M.EndOfLifeOutput[r, t, v, o]) * value(M.V_AnnualRetirement[r, p, t, v]) for s in M.time_season[p]: @@ -572,6 +574,8 @@ def poll_emissions( # iterate through end of life flows eol_flows: dict[EI, float] = defaultdict(float) for r, e, t, v in M.EmissionEndOfLife.sparse_iterkeys(): + if (r, t, v) not in M.retirementPeriods: + continue for p in M.retirementPeriods[r, t, v]: eol_flows[EI(r, p, t, v, e)] += value(M.V_AnnualRetirement[r, p, t, v] * M.EmissionEndOfLife[r, e, t, v]) # for eol costs flows[EI(r, p, t, v, e)] += value(M.V_AnnualRetirement[r, p, t, v] * M.EmissionEndOfLife[r, e, t, v]) # add eol to process emissions diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index b160f78f7..9534d0e0b 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -992,14 +992,7 @@ def CreateSparseDicts(M: 'TemoaModel'): M.capacityConsumptionTechs[r, v, i].add(t) for r, t, v, o in M.EndOfLifeOutput: if (r, t, v) not in M.retirementPeriods: - msg = ( - f'Process {(r, t, v)} in EndOfLifeOutput does not retire within the planning horizon. ' - 'All processes in EndOfLifeOutput must naturally reach end of life at the start of ' - 'or during the planning horizon (p0 <= v+lifetime < pE) or be a retirement tech ' - '(allowing early retirement).' - ) - logger.error(msg) - raise ValueError(msg) + continue # might be running myopic for p in M.retirementPeriods[r, t, v]: # What periods can this process retire in, either naturally or economically? if (r, p, o) not in M.retirementProductionProcesses: @@ -1175,7 +1168,6 @@ def CapacityFactorProcessIndices(M: 'TemoaModel'): for s in M.time_season[p] for d in M.time_of_day ) - return indices diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 44b888663..17ecca4d6 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -648,7 +648,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): ) for (r, e, t, v) in M.EmissionEndOfLife.sparse_iterkeys() if (r, p, e) in M.CostEmission - if p in M.retirementPeriods[r, t, v] + if (r, t, v) in M.retirementPeriods and p in M.retirementPeriods[r, t, v] ) period_emission_cost = var_emissions + var_annual_emissions + embodied_emissions + endoflife_emissions @@ -1806,7 +1806,8 @@ def EmissionLimit_Constraint(M: 'TemoaModel', r, p, e): * value(M.EmissionEndOfLife[reg, e, t, v]) for reg in regions for (S_r, S_e, t, v) in M.EmissionEndOfLife.sparse_iterkeys() - if p in M.retirementPeriods[r, t, v] and S_r == reg and S_e == e + if (r, t, v) in M.retirementPeriods and p in M.retirementPeriods[r, t, v] + if S_r == reg and S_e == e ) expr = ( From f67c621f7ef95a2bb676f3fd32b99541d04621bd Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 21 May 2025 19:20:40 -0400 Subject: [PATCH 081/587] Fix to keep old existing capacities in myopic --- temoa/temoa_model/hybrid_loader.py | 8 ++++++++ temoa/temoa_model/temoa_model.py | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 61b857f43..de0a31c12 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -574,6 +574,14 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N raw = cur.execute('SELECT tech FROM Technology WHERE retire > 0').fetchall() load_element(M.tech_retirement, raw, self.viable_techs) + # tech_exist + # this is to allow features doing accounting on old existing capacities + raw = cur.execute( + 'SELECT DISTINCT tech FROM ExistingCapacity ' + 'WHERE tech NOT IN (SELECT tech FROM Technology WHERE unlim_cap > 0)' + ).fetchall() + load_element(M.tech_exist, raw) + # === COMMODITIES === # commodity_demand diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index e37102f58..acd705742 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -190,6 +190,7 @@ def __init__(M, *args, **kwargs): M.tech_group_members = Set(M.tech_group_names, within=M.tech_all) M.tech_uncap = Set(within=M.tech_all - M.tech_reserve) + M.tech_exist = Set() """techs with unlimited capacity, ALWAYS available within lifespan""" # the below is a convenience for domain checking in params below that should not accept uncap techs... @@ -271,7 +272,7 @@ def __init__(M, *args, **kwargs): # Define technology performance parameters M.CapacityToActivity = Param(M.regionalIndices, M.tech_all, default=1) - M.ExistingCapacity = Param(M.regionalIndices, M.tech_with_capacity, M.vintage_exist) + M.ExistingCapacity = Param(M.regionalIndices, M.tech_exist, M.vintage_exist) # Dev Note: The below is temporarily useful for passing down to validator to find set violations # Uncomment this assignment, and comment out the orig below it... From fd7a39f5204e90d0cea6cc437a0b13d1daed6e3d Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 22 May 2025 14:46:23 -0400 Subject: [PATCH 082/587] Fix tech exist initialisation for myopic --- temoa/temoa_model/hybrid_loader.py | 14 +++-------- temoa/temoa_model/temoa_model.py | 4 ++- temoa/temoa_model/temoa_rules.py | 39 ++++++++++++++++-------------- 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index de0a31c12..a5282d15a 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -574,14 +574,6 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N raw = cur.execute('SELECT tech FROM Technology WHERE retire > 0').fetchall() load_element(M.tech_retirement, raw, self.viable_techs) - # tech_exist - # this is to allow features doing accounting on old existing capacities - raw = cur.execute( - 'SELECT DISTINCT tech FROM ExistingCapacity ' - 'WHERE tech NOT IN (SELECT tech FROM Technology WHERE unlim_cap > 0)' - ).fetchall() - load_element(M.tech_exist, raw) - # === COMMODITIES === # commodity_demand @@ -612,8 +604,9 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # === OPERATORS === # operator - raw = cur.execute("SELECT operator FROM main.Operator").fetchall() - load_element(M.operator, raw) + if self.table_exists("Operator"): + raw = cur.execute("SELECT operator FROM main.Operator").fetchall() + load_element(M.operator, raw) # === PARAMS === @@ -656,6 +649,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # devnote: We want full existing capacity history for end of life flows and growth constraints # load_element(M.ExistingCapacity, raw, self.viable_rtv, (0, 1, 2)) load_element(M.ExistingCapacity, raw) + load_element(M.tech_exist, [(row[1],) for row in raw]) # need to keep these for accounting purposes # GlobalDiscountRate if self.table_exists("MetaDataReal"): diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index acd705742..12da6dfb2 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -190,9 +190,11 @@ def __init__(M, *args, **kwargs): M.tech_group_members = Set(M.tech_group_names, within=M.tech_all) M.tech_uncap = Set(within=M.tech_all - M.tech_reserve) - M.tech_exist = Set() """techs with unlimited capacity, ALWAYS available within lifespan""" + M.tech_exist = Set() + """techs with existing capacity, want to keep these for accounting reasons""" + # the below is a convenience for domain checking in params below that should not accept uncap techs... M.tech_with_capacity = Set(initialize=M.tech_all - M.tech_uncap) """techs eligible for capacitization""" diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 17ecca4d6..40567b9d2 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1859,12 +1859,13 @@ def GrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): # periods the technology can have capacity in this region (sorted) periods = sorted(set(_p for _r, _p, _t in cap_rpt)) - if len(periods) == 0 and p == M.time_optimize.first(): - msg = ( - 'Tried to set {}rowthCapacity constraint {} but there are no periods where this ' - 'technology is available in this region. Constraint skipped.' - ).format("Deg" if degrowth else "G", (r, t)) - logger.warning(msg) + if len(periods) == 0: + if p == M.time_optimize.first(): + msg = ( + 'Tried to set {}rowthCapacity constraint {} but there are no periods where this ' + 'technology is available in this region. Constraint skipped.' + ).format("Deg" if degrowth else "G", (r, t)) + logger.warning(msg) return Constraint.Skip # Only warn in p0 so we dont dump multiple warnings @@ -1946,12 +1947,13 @@ def GrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): # periods the technology can be built in this region (sorted) periods = sorted(set(_v for _r, _t, _v in NewCapRTV if _v in M.time_optimize)) - if len(periods) == 0 and p == M.time_optimize.first(): - msg = ( - 'Tried to set {}rowthNewCapacity constraint {} but there are no periods where this ' - 'technology can be built in this region. Constraint skipped.' - ).format("Deg" if degrowth else "G", (r, t)) - logger.warning(msg) + if len(periods) == 0: + if p == M.time_optimize.first(): + msg = ( + 'Tried to set {}rowthNewCapacity constraint {} but there are no periods where this ' + 'technology can be built in this region. Constraint skipped.' + ).format("Deg" if degrowth else "G", (r, t)) + logger.warning(msg) return Constraint.Skip # Only warn in p0 so we dont dump multiple warnings @@ -2031,12 +2033,13 @@ def GrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = False) # periods the technology can be built in this region (sorted) periods = sorted(set(_v for _r, _t, _v in cap_rtv if _v in M.time_optimize)) - if len(periods) == 0 and p == M.time_optimize.first(): - msg = ( - 'Tried to set {}rowthNewCapacityDelta constraint {} but there are no periods where this ' - 'technology can be built in this region. Constraint skipped.' - ).format("Deg" if degrowth else "G", (r, t)) - logger.warning(msg) + if len(periods) == 0: + if p == M.time_optimize.first(): + msg = ( + 'Tried to set {}rowthNewCapacityDelta constraint {} but there are no periods where this ' + 'technology can be built in this region. Constraint skipped.' + ).format("Deg" if degrowth else "G", (r, t)) + logger.warning(msg) return Constraint.Skip # Only warn in p0 so we dont dump multiple warnings From 299f48dcc397648cbd28d878b030491379894e3f Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 22 May 2025 16:50:09 -0400 Subject: [PATCH 083/587] Tiny fix to tech_exist loading --- temoa/temoa_model/hybrid_loader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index a5282d15a..4a6596f6e 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -649,7 +649,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # devnote: We want full existing capacity history for end of life flows and growth constraints # load_element(M.ExistingCapacity, raw, self.viable_rtv, (0, 1, 2)) load_element(M.ExistingCapacity, raw) - load_element(M.tech_exist, [(row[1],) for row in raw]) # need to keep these for accounting purposes + load_element(M.tech_exist, list({(row[1],) for row in raw})) # need to keep these for accounting purposes # GlobalDiscountRate if self.table_exists("MetaDataReal"): From 0d5632c1451a8f5513002eeaf7e23ef1c9f61858 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 22 May 2025 16:20:30 -0400 Subject: [PATCH 084/587] Add waste commodities --- temoa/temoa_model/hybrid_loader.py | 8 ++- .../model_checking/commodity_graph.py | 14 ++--- .../model_checking/commodity_network.py | 2 +- .../model_checking/network_model_data.py | 54 +++++++++++-------- temoa/temoa_model/temoa_model.py | 5 +- temoa/temoa_model/temoa_rules.py | 10 +++- tests/test_network_model_data.py | 3 ++ tests/testing_data/mediumville.sql | 21 -------- tests/testing_data/mediumville_sets.json | 18 ++++--- tests/testing_data/test_system_sets.json | 13 ++++- tests/testing_data/utopia_sets.json | 19 ++++++- 11 files changed, 102 insertions(+), 65 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 4a6596f6e..4a16aa9dd 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -587,7 +587,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # commodity_physical raw = cur.execute( - "SELECT name FROM main.Commodity WHERE flag = 'p' OR flag = 's' OR flag = 'a'" + "SELECT name FROM main.Commodity WHERE flag LIKE '%p%' OR flag = 's' OR flag LIKE '%a%'" ).fetchall() # The model enforces 0 symmetric difference between the physical commodities # and the input commodities, so we need to include only the viable INPUTS @@ -598,9 +598,13 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N load_element(M.commodity_source, raw, self.viable_input_comms) # commodity_annual - raw = cur.execute("SELECT name FROM main.Commodity WHERE flag = 'a'").fetchall() + raw = cur.execute("SELECT name FROM main.Commodity WHERE flag LIKE '%a%'").fetchall() load_element(M.commodity_annual, raw, self.viable_input_comms) + # commodity_waste + raw = cur.execute("SELECT name FROM main.Commodity WHERE flag LIKE '%w%'").fetchall() + load_element(M.commodity_waste, raw, self.viable_output_comms) + # === OPERATORS === # operator diff --git a/temoa/temoa_model/model_checking/commodity_graph.py b/temoa/temoa_model/model_checking/commodity_graph.py index e8a8dc902..95dcdbe81 100644 --- a/temoa/temoa_model/model_checking/commodity_graph.py +++ b/temoa/temoa_model/model_checking/commodity_graph.py @@ -64,15 +64,17 @@ def generate_graph( :return: """ layers = {} - for c in network_data.all_commodities: + for c in network_data.waste_commodities[region, period]: + layers[c] = 6 + for c in network_data.physical_commodities: layers[c] = 2 # physical for c in network_data.source_commodities[region, period]: layers[c] = 1 for c in network_data.demand_commodities[region, period]: layers[c] = 3 - for c in network_data.cap_commodities: + for c in network_data.capacity_commodities: layers[c] = 4 - for c in network_data.exc_commodities: + for c in network_data.exchange_commodities: layers[c] = 5 edge_colors = {} @@ -90,7 +92,7 @@ def generate_graph( } exc_edges = { (tech.ic, tech.name, tech.oc) for tech in network_data.available_techs[region, period] - if tech.ic in network_data.exc_commodities or tech.oc in network_data.exc_commodities + if tech.ic in network_data.exchange_commodities or tech.oc in network_data.exchange_commodities } # troll through the tech_data and label things of low importance for edge in all_edges: @@ -206,8 +208,8 @@ def make_nx_graph(connections, edge_colors, edge_weights, layer_map) -> nx.Multi :return: a nx MultiDiGraph """ dg = nx.MultiDiGraph() # networkx multi(edge) directed graph - layer_colors = {1: 'limegreen', 2: 'violet', 3: 'darkorange', 4: 'darkgreen', 5: 'darkblue'} - node_size = {1: 50, 2: 15, 3: 30, 4:20, 5:20} + layer_colors = {1: 'limegreen', 2: 'violet', 3: 'darkorange', 4: 'darkgreen', 5: 'darkblue', 6: 'darkred'} + node_size = {1: 50, 2: 15, 3: 30, 4:20, 5:20, 6:30} for ic, tech, oc in connections: dg.add_node( ic, diff --git a/temoa/temoa_model/model_checking/commodity_network.py b/temoa/temoa_model/model_checking/commodity_network.py index a7f156596..91d97c8cb 100644 --- a/temoa/temoa_model/model_checking/commodity_network.py +++ b/temoa/temoa_model/model_checking/commodity_network.py @@ -214,7 +214,7 @@ def analyze_network(self): # dev note: send a copy of connections... # it is consumed by the function. (easier than managing it in the recursion) discovered_sources, demand_side_connections = _visited_dfs( - self.model_data.demand_commodities[self.region, self.period], + self.model_data.demand_commodities[self.region, self.period] | self.model_data.waste_commodities[self.region, self.period], self.model_data.source_commodities[self.region, self.period], self.connections.copy(), ) diff --git a/temoa/temoa_model/model_checking/network_model_data.py b/temoa/temoa_model/model_checking/network_model_data.py index 0fca77efc..ba9f86ea4 100644 --- a/temoa/temoa_model/model_checking/network_model_data.py +++ b/temoa/temoa_model/model_checking/network_model_data.py @@ -55,10 +55,11 @@ def __init__(self, **kwargs): self.demand_commodities: dict[tuple[str, int | str], set[str]] = kwargs.get( 'demand_commodities' ) - self.cap_commodities: set[str] = kwargs.get('cap_commodities') - self.exc_commodities: set[str] = kwargs.get('exc_commodities') + self.waste_commodities: set[str] = kwargs.get('waste_commodities') + self.capacity_commodities: set[str] = kwargs.get('capacity_commodities') + self.exchange_commodities: set[str] = kwargs.get('exchange_commodities') self.source_commodities: dict[tuple[str, int | str], set[str]] = kwargs.get('source_commodities') - self.all_commodities: set[str] = kwargs.get('all_commodities') + self.physical_commodities: set[str] = kwargs.get('all_commodities') # dict of (region, period): {Tech} self._available_techs: dict[tuple[str, int | str], set[Tech]] = kwargs.get( 'available_techs' @@ -74,10 +75,11 @@ def clone(self) -> Self: """create a copy of the current""" return NetworkModelData( demand_commodities=self.demand_commodities.copy(), + waste_commodities=self.waste_commodities.copy(), source_commodities=self.source_commodities.copy(), - cap_commodities=self.cap_commodities.copy(), - exc_commodities=self.exc_commodities.copy(), - all_commodities=self.all_commodities.copy(), + capacity_commodities=self.capacity_commodities.copy(), + exchange_commodities=self.exchange_commodities.copy(), + all_commodities=self.physical_commodities.copy(), available_techs=self.available_techs.copy(), available_linked_techs=self.available_linked_techs.copy(), ) @@ -117,7 +119,7 @@ def get_driven_techs(self, region, period) -> set[Tech]: def __str__(self): return ( - f'all commodities: {len(self.all_commodities)}, demand commodities: {len(self.demand_commodities)}, ' + f'all commodities: {len(self.physical_commodities)}, demand commodities: {len(self.demand_commodities)}, ' f'source commodities: {len(self.source_commodities)},' f'available techs: {len(tuple(chain(*self.available_techs.values())))}, ' f'linked techs: {len(self.available_linked_techs)}' @@ -147,7 +149,7 @@ def _build_from_model(M: TemoaModel, myopic_index=None) -> NetworkModelData: if myopic_index is not None: raise NotImplementedError('cannot build network data from model using a MyopicIndex') res = NetworkModelData() - res.all_commodities = set(M.commodity_all) + res.physical_commodities = set(M.commodity_all) source_com = defaultdict(set) dem_com = defaultdict(set) for r, p, d in M.Demand: @@ -180,14 +182,18 @@ def _build_from_db( raw = cur.execute('SELECT tech FROM Technology WHERE retire==1').fetchall() tech_retire = {t[0] for t in raw} raw = cur.execute('SELECT period FROM TimePeriod').fetchall() - periods = [p[0] for p in raw] + periods = [p[0] for p in sorted(raw)] period_length = {periods[i]: periods[i+1] - periods[i] for i in range(len(periods)-1)} - raw = cur.execute('SELECT Commodity.name FROM Commodity').fetchall() - res.cap_commodities = set() - res.exc_commodities = set() - res.all_commodities = {t[0] for t in raw} + periods = periods[:-1] + raw = cur.execute("SELECT name FROM main.Commodity WHERE flag LIKE '%p%' OR flag = 's' OR flag LIKE '%a%'").fetchall() + res.physical_commodities = {c[0] for c in raw} + res.capacity_commodities = set() + res.exchange_commodities = set() + raw = cur.execute("SELECT Commodity.name FROM Commodity WHERE flag LIKE '%w%'").fetchall() + waste_comms = {c[0] for c in raw} + waste_dict = defaultdict(set) raw = cur.execute("SELECT Commodity.name FROM Commodity WHERE flag = 's'").fetchall() - source_comms = {t[0] for t in raw} + source_comms = {c[0] for c in raw} source_dict = defaultdict(set) # use Demand to get the region, period specific demand comms raw = cur.execute('SELECT region, period, commodity FROM main.Demand').fetchall() @@ -228,10 +234,9 @@ def _build_from_db( # f' WHERE main.MyopicEfficiency.vintage <= {myopic_index.last_demand_year}' ) raw = cur.execute(query).fetchall() - periods = cur.execute('SELECT period FROM TimePeriod').fetchall() # need to exclude the final year which is a non-demand year and should have no tech data # This ensures that the periods in this will match the periods in the hybrid loader. - periods = [t[0] for t in sorted(periods)[:-1]] + # filter further if myopic if myopic_index: periods = { @@ -253,15 +258,17 @@ def _build_from_db( techs[r, p].add(Tech(r, ic, tech, v, oc)) source_dict[r2, p].add(source) demand_dict[r1, p].add(destination) - res.all_commodities.add(source) - res.exc_commodities.add(source) - res.all_commodities.add(destination) - res.exc_commodities.add(destination) + res.physical_commodities.add(source) + res.exchange_commodities.add(source) + res.physical_commodities.add(destination) + res.exchange_commodities.add(destination) else: techs[r, p].add(Tech(r, ic, tech, v, oc)) living_techs.add(tech) if ic in source_comms: source_dict[r, p].add(ic) + if oc in waste_comms: + waste_dict[r, p].add(oc) # End of life output if any(( @@ -279,8 +286,10 @@ def _build_from_db( for _r, _tech, _v, _oc in raw_eol: techs[_r, p].add(Tech(_r, _tech, 'EndOfLife', _v, _oc)) source_dict[_r, p].add(_tech) - res.cap_commodities.add(_tech) + res.capacity_commodities.add(_tech) living_techs.add(_tech) + if _oc in waste_comms: + waste_dict[_r, p].add(_oc) except: # EndOfLifeOutput table did not exist TODO remove this eventually pass @@ -291,7 +300,7 @@ def _build_from_db( for r, ic, tech, v in raw: techs[r, v].add(Tech(r, ic, 'Construction', v, tech)) demand_dict[r, v].add(tech) - res.cap_commodities.add(tech) + res.capacity_commodities.add(tech) living_techs.add(tech) except: # ConstructionInput table did not exist TODO remove this eventually @@ -300,6 +309,7 @@ def _build_from_db( res.available_techs = techs res.demand_commodities = demand_dict res.source_commodities = source_dict + res.waste_commodities = waste_dict # pick up the linked techs... raw = cur.execute( diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 12da6dfb2..01da1e69a 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -207,10 +207,11 @@ def __init__(M, *args, **kwargs): M.commodity_demand = Set() M.commodity_emissions = Set() M.commodity_physical = Set() + M.commodity_waste = Set() M.commodity_flex = Set(within=M.commodity_physical) M.commodity_source = Set(within=M.commodity_physical) M.commodity_annual = Set(within=M.commodity_physical) - M.commodity_carrier = Set(initialize=M.commodity_physical | M.commodity_demand) + M.commodity_carrier = Set(initialize=M.commodity_physical | M.commodity_demand | M.commodity_waste) M.commodity_all = Set( initialize=M.commodity_carrier | M.commodity_emissions, validate=no_slash_or_pipe ) @@ -285,7 +286,7 @@ def __init__(M, *args, **kwargs): # devnote: need these here or CheckEfficiencyIndices may flag these commodities as unused M.ConstructionInput = Param(M.regions, M.commodity_physical, M.tech_with_capacity, M.vintage_optimize) - M.EndOfLifeOutput = Param(M.regions, M.tech_with_capacity, M.vintage_all, M.commodity_physical) + M.EndOfLifeOutput = Param(M.regions, M.tech_with_capacity, M.vintage_all, M.commodity_carrier) M.Efficiency = Param( M.regionalIndices, diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 40567b9d2..de9676dbc 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -956,7 +956,10 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): c, ) - expr = produced == consumed + if c in M.commodity_waste: + expr = produced >= consumed + else: + expr = produced == consumed return expr @@ -1092,7 +1095,10 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): c, ) - expr = produced == consumed + if c in M.commodity_waste: + expr = produced >= consumed + else: + expr = produced == consumed return expr diff --git a/tests/test_network_model_data.py b/tests/test_network_model_data.py index 1bb101b84..2bd6a3e01 100644 --- a/tests/test_network_model_data.py +++ b/tests/test_network_model_data.py @@ -57,6 +57,7 @@ (2025,), ], # periods [(t,) for t in ['s1', 'p1', 'p2', 'p3', 'd1', 'd2']], # all commodities + [], # waste commodities [ (t,) for t in [ @@ -104,6 +105,7 @@ (2025,), ], # periods [(t,) for t in ['s1', 'p3', 'd1', 'd2']], # all commodities + [], # waste commodities [ (t,) for t in [ @@ -150,6 +152,7 @@ (2025,), ], # periods [(t,) for t in ['s1', 'd1', 'd2', 's2']], # all commodities + [], # waste commodities [(t,) for t in ['s1', 's2']], # sources [('R1', 2020, 'd1'), ('R1', 2020, 'd2')], # demands [ diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 69e2faad5..d0dd0e0a6 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -424,27 +424,6 @@ CREATE TABLE TechGroup INSERT INTO TechGroup VALUES('RPS_global',''); INSERT INTO TechGroup VALUES('RPS_common',''); INSERT INTO TechGroup VALUES('A_tech_grp_1','converted from old db'); -CREATE TABLE GrowthRateMax -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO GrowthRateMax VALUES('global','GeoHeater',0.2,NULL); -CREATE TABLE GrowthRateSeed -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - seed REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO GrowthRateSeed VALUES('global','GeoHeater',1000.0,'jobs','unk'); CREATE TABLE LoanLifetimeTech ( region TEXT, diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 819c6bb4d..a48d8b253 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -3602,6 +3602,17 @@ 2025 ] ], + "commodity_waste": [], + "tech_exist": [ + "EH" + ], + "operator": [], + "DegrowthCapacityConstraint_rtpop": [], + "DegrowthNewCapacityConstraint_rtpop": [], + "DegrowthNewCapacityDeltaConstraint_rtpop": [], + "GrowthCapacityConstraint_rtpop": [], + "GrowthNewCapacityConstraint_rtpop": [], + "GrowthNewCapacityDeltaConstraint_rtpop": [], "DemandConstraint_rpsdc": [ [ "B", @@ -4376,13 +4387,6 @@ "d1" ] ], - "GrowthRateMaxConstraint_rtv": [ - [ - "global", - 2025, - "GeoHeater" - ] - ], "MinTechInputSplitConstraint_rpsditv": [ [ "A", diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 3817d6e0a..04b959bf7 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -35553,6 +35553,18 @@ ] ], "CapacityAnnualConstraint_rptv": [], + "commodity_waste": [], + "tech_exist": [ + "E_NUCLEAR", + "E_TRANS" + ], + "operator": [], + "DegrowthCapacityConstraint_rtpop": [], + "DegrowthNewCapacityConstraint_rtpop": [], + "DegrowthNewCapacityDeltaConstraint_rtpop": [], + "GrowthCapacityConstraint_rtpop": [], + "GrowthNewCapacityConstraint_rtpop": [], + "GrowthNewCapacityDeltaConstraint_rtpop": [], "DemandConstraint_rpsdc": [ [ "R2", @@ -45818,7 +45830,6 @@ "day" ] ], - "GrowthRateMaxConstraint_rtv": [], "MinTechInputSplitConstraint_rpsditv": [ [ "R2", diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 388ad6995..adfe54103 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -20379,6 +20379,24 @@ ] ], "CapacityAnnualConstraint_rptv": [], + "commodity_waste": [], + "tech_exist": [ + "RL1", + "E01", + "TXG", + "E31", + "RHO", + "TXD", + "E70", + "E51" + ], + "operator": [], + "DegrowthCapacityConstraint_rtpop": [], + "DegrowthNewCapacityConstraint_rtpop": [], + "DegrowthNewCapacityDeltaConstraint_rtpop": [], + "GrowthCapacityConstraint_rtpop": [], + "GrowthNewCapacityConstraint_rtpop": [], + "GrowthNewCapacityDeltaConstraint_rtpop": [], "DemandConstraint_rpsdc": [ [ "utopia", @@ -25598,7 +25616,6 @@ "day" ] ], - "GrowthRateMaxConstraint_rtv": [], "MinTechInputSplitConstraint_rpsditv": [], "MinTechInputSplitAnnualConstraint_rpitv": [], "MinTechInputSplitAverageConstraint_rpitv": [], From 5cb3e7e04923e0b62e8eeed31d2cab986055974b Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 22 May 2025 16:54:37 -0400 Subject: [PATCH 085/587] Add example database for materials --- data_files/example_dbs/materials.sql | 1726 ++++++++++++++++++++++++++ 1 file changed, 1726 insertions(+) create mode 100644 data_files/example_dbs/materials.sql diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql new file mode 100644 index 000000000..e1617d14b --- /dev/null +++ b/data_files/example_dbs/materials.sql @@ -0,0 +1,1726 @@ +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE MetaData +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); +INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); +INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO MetaData VALUES('link_seasons',1,'Carry storage states between seasons'); +INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); +CREATE TABLE MetaDataReal +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); +CREATE TABLE OutputDualVariable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE OutputObjective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE SectorLabel +( + sector TEXT, + PRIMARY KEY (sector) +); +CREATE TABLE CapacityCredit +( + region TEXT, + period INTEGER, + tech TEXT, + vintage INTEGER, + credit REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage), + CHECK (credit >= 0 AND credit <= 1) +); +CREATE TABLE CapacityFactorProcess +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE CapacityFactorTech +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech), + CHECK (factor >= 0 AND factor <= 1) +); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'summer','morning','SOL_PV',0.3,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'autumn','morning','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'winter','morning','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'spring','morning','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'summer','afternoon','SOL_PV',0.3,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'autumn','afternoon','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'winter','afternoon','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'spring','afternoon','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'summer','morning','SOL_PV',0.3,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'autumn','morning','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'winter','morning','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'spring','morning','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'summer','afternoon','SOL_PV',0.3,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'autumn','afternoon','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'winter','afternoon','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'spring','afternoon','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'summer','morning','SOL_PV',0.3,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'autumn','morning','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'winter','morning','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'spring','morning','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'summer','afternoon','SOL_PV',0.3,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'autumn','afternoon','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'winter','afternoon','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'spring','afternoon','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'summer','morning','SOL_PV',0.3,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'autumn','morning','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'winter','morning','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'spring','morning','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'summer','afternoon','SOL_PV',0.3,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'autumn','afternoon','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'winter','afternoon','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'spring','afternoon','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'summer','morning','SOL_PV',0.3,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'autumn','morning','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'winter','morning','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'spring','morning','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'summer','afternoon','SOL_PV',0.3,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'autumn','afternoon','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'winter','afternoon','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'spring','afternoon','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'summer','morning','SOL_PV',0.3,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'autumn','morning','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'winter','morning','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'spring','morning','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'summer','afternoon','SOL_PV',0.3,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'autumn','afternoon','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'winter','afternoon','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'spring','afternoon','SOL_PV',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'spring','overnight','SOL_PV',0.0,NULL); +CREATE TABLE CapacityToActivity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + c2a REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE Commodity +( + name TEXT + PRIMARY KEY, + flag TEXT + REFERENCES CommodityType (label), + description TEXT +); +INSERT INTO Commodity VALUES('ethos','s','import dummy source'); +INSERT INTO Commodity VALUES('electricity','p','grid electricity'); +INSERT INTO Commodity VALUES('passenger_km','d','demand for passenger km'); +INSERT INTO Commodity VALUES('battery_nmc','a','battery - lithium nickel manganese cobalt oxide'); +INSERT INTO Commodity VALUES('battery_lfp','a','battery - lithium iron phosphate'); +INSERT INTO Commodity VALUES('lithium','a','lithium'); +INSERT INTO Commodity VALUES('cobalt','a','cobalt'); +INSERT INTO Commodity VALUES('phosphorous','a','phosphorous'); +INSERT INTO Commodity VALUES('diesel','a','diesel'); +INSERT INTO Commodity VALUES('heating','d','demand for residential heating'); +INSERT INTO Commodity VALUES('nickel','a','nickel'); +INSERT INTO Commodity VALUES('used_batt_nmc','aw','used battery - lithium nickel manganese cobalt oxide'); +INSERT INTO Commodity VALUES('used_batt_lfp','aw','used battery - lithium iron phosphate'); +INSERT INTO Commodity VALUES('co2e','e','emitted co2-equivalent GHGs'); +INSERT INTO Commodity VALUES('waste_steel','w','waste steel from cars'); +CREATE TABLE CommodityType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO CommodityType VALUES('a','annual commodity'); +INSERT INTO CommodityType VALUES('p','physical commodity'); +INSERT INTO CommodityType VALUES('e','emissions commodity'); +INSERT INTO CommodityType VALUES('d','demand commodity'); +INSERT INTO CommodityType VALUES('s','source commodity'); +CREATE TABLE ConstructionInput +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); +INSERT INTO ConstructionInput VALUES('RegionA','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionA','battery_lfp','CAR_PHEV',2000,0.1,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionA','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionA','battery_lfp','CAR_PHEV',2010,0.1,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionA','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionA','battery_lfp','CAR_PHEV',2020,0.1,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionB','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionB','battery_lfp','CAR_PHEV',2000,0.1,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionB','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionB','battery_lfp','CAR_PHEV',2010,0.1,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionB','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionB','battery_lfp','CAR_PHEV',2020,0.1,NULL,NULL); +CREATE TABLE EndOfLifeOutput +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) +); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',1990,'used_batt_lfp',0.1,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2000,'used_batt_lfp',0.1,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2010,'used_batt_lfp',0.1,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',1990,'used_batt_lfp',0.1,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2000,'used_batt_lfp',0.1,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2010,'used_batt_lfp',0.1,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); +CREATE TABLE CostEmission +( + region TEXT + REFERENCES Region (region), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT NOT NULL + REFERENCES Commodity (name), + cost REAL NOT NULL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +INSERT INTO CostEmission VALUES('RegionA',2000,'co2e',1.0,NULL,NULL); +INSERT INTO CostEmission VALUES('RegionA',2010,'co2e',1.0,NULL,NULL); +INSERT INTO CostEmission VALUES('RegionA',2020,'co2e',1.0,NULL,NULL); +INSERT INTO CostEmission VALUES('RegionB',2000,'co2e',1.0,NULL,NULL); +INSERT INTO CostEmission VALUES('RegionB',2010,'co2e',1.0,NULL,NULL); +INSERT INTO CostEmission VALUES('RegionB',2020,'co2e',1.0,NULL,NULL); +CREATE TABLE CostFixed +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE CostInvest +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +INSERT INTO CostInvest VALUES('RegionA','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','CAR_PHEV',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','CAR_PHEV',2010,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','CAR_PHEV',2020,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','CAR_ICE',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','CAR_ICE',2010,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','CAR_ICE',2020,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','RECYCLE_NMC',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','RECYCLE_LFP',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','MANUFAC_NMC',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','MANUFAC_LFP',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','BATT_GRID',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','SOL_PV',2000,10.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','GEN_DSL',2000,2.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','CAR_PHEV',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','CAR_PHEV',2010,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','CAR_PHEV',2020,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','CAR_ICE',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','CAR_ICE',2010,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','CAR_ICE',2020,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','RECYCLE_NMC',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','RECYCLE_LFP',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','MANUFAC_NMC',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','MANUFAC_LFP',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','BATT_GRID',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','GEN_DSL',2000,2.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA-RegionB','ELEC_INTERTIE',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB-RegionA','ELEC_INTERTIE',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','SOL_PV',2000,1.0,NULL,NULL); +CREATE TABLE CostVariable +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +INSERT INTO CostVariable VALUES('RegionA',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2000,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2010,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2020,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2000,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2010,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2020,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2000,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2010,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2020,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2000,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2010,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2020,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2000,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2010,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2020,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2000,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2010,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2020,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2000,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2010,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2020,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2000,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2010,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2020,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); +CREATE TABLE Demand +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + commodity TEXT + REFERENCES Commodity (name), + demand REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, commodity) +); +INSERT INTO Demand VALUES('RegionA',2000,'passenger_km',1.0,NULL,NULL); +INSERT INTO Demand VALUES('RegionA',2010,'passenger_km',1.0,NULL,NULL); +INSERT INTO Demand VALUES('RegionA',2020,'passenger_km',1.0,NULL,NULL); +INSERT INTO Demand VALUES('RegionA',2000,'heating',1.0,NULL,NULL); +INSERT INTO Demand VALUES('RegionA',2010,'heating',1.0,NULL,NULL); +INSERT INTO Demand VALUES('RegionA',2020,'heating',1.0,NULL,NULL); +INSERT INTO Demand VALUES('RegionB',2000,'passenger_km',1.0,NULL,NULL); +INSERT INTO Demand VALUES('RegionB',2010,'passenger_km',1.0,NULL,NULL); +INSERT INTO Demand VALUES('RegionB',2020,'passenger_km',1.0,NULL,NULL); +INSERT INTO Demand VALUES('RegionB',2000,'heating',1.0,NULL,NULL); +INSERT INTO Demand VALUES('RegionB',2010,'heating',1.0,NULL,NULL); +INSERT INTO Demand VALUES('RegionB',2020,'heating',1.0,NULL,NULL); +CREATE TABLE DemandSpecificDistribution +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + demand_name TEXT + REFERENCES Commodity (name), + dsd REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), + CHECK (dsd >= 0 AND dsd <= 1) +); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'summer','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','morning','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','morning','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'spring','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'summer','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','afternoon','heating',0.08,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','afternoon','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'spring','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'summer','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','evening','heating',0.08,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','evening','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'spring','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'summer','overnight','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','overnight','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','overnight','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'spring','overnight','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'summer','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','morning','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','morning','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'spring','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'summer','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','afternoon','heating',0.08,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','afternoon','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'spring','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'summer','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','evening','heating',0.08,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','evening','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'spring','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'summer','overnight','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','overnight','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','overnight','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'spring','overnight','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'summer','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','morning','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','morning','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'spring','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'summer','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','afternoon','heating',0.08,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','afternoon','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'spring','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'summer','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','evening','heating',0.08,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','evening','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'spring','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'summer','overnight','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','overnight','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','overnight','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'spring','overnight','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'summer','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','morning','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','morning','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'spring','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'summer','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','afternoon','heating',0.08,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','afternoon','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'spring','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'summer','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','evening','heating',0.08,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','evening','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'spring','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'summer','overnight','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','overnight','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','overnight','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'spring','overnight','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'summer','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','morning','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','morning','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'spring','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'summer','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','afternoon','heating',0.08,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','afternoon','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'spring','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'summer','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','evening','heating',0.08,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','evening','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'spring','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'summer','overnight','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','overnight','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','overnight','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'spring','overnight','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'summer','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','morning','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','morning','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'spring','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'summer','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','afternoon','heating',0.08,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','afternoon','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'spring','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'summer','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','evening','heating',0.08,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','evening','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'spring','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'summer','overnight','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','overnight','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','overnight','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'spring','overnight','heating',0.0,NULL); +CREATE TABLE LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE Efficiency +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +INSERT INTO Efficiency VALUES('RegionA','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2,NULL); +INSERT INTO Efficiency VALUES('RegionA','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2,NULL); +INSERT INTO Efficiency VALUES('RegionA','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','electricity','RECYCLE_NMC',2000,'battery_nmc',0.001,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionA','electricity','RECYCLE_LFP',2000,'battery_lfp',0.001,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionA','electricity','MANUFAC_NMC',2000,'battery_nmc',0.001,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionA','electricity','MANUFAC_LFP',2000,'battery_lfp',0.001,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionA','diesel','GEN_DSL',2000,'electricity',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','ethos','SOL_PV',2000,'electricity',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','electricity','BATT_GRID',2000,'electricity',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','diesel','FURNACE',2000,'heating',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','electricity','HEATPUMP',2000,'heating',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2,NULL); +INSERT INTO Efficiency VALUES('RegionB','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2,NULL); +INSERT INTO Efficiency VALUES('RegionB','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','electricity','RECYCLE_NMC',2000,'battery_nmc',0.001,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionB','electricity','RECYCLE_LFP',2000,'battery_lfp',0.001,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionB','electricity','MANUFAC_NMC',2000,'battery_nmc',0.001,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionB','electricity','MANUFAC_LFP',2000,'battery_lfp',0.001,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionB','diesel','GEN_DSL',2000,'electricity',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','ethos','SOL_PV',2000,'electricity',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','electricity','BATT_GRID',2000,'electricity',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','diesel','FURNACE',2000,'heating',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','electricity','HEATPUMP',2000,'heating',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA-RegionB','electricity','ELEC_INTERTIE',2000,'electricity',0.9,NULL); +INSERT INTO Efficiency VALUES('RegionB-RegionA','electricity','ELEC_INTERTIE',2000,'electricity',0.9,NULL); +CREATE TABLE EfficiencyVariable +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE EmissionActivity +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) +); +INSERT INTO EmissionActivity VALUES('RegionA','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); +INSERT INTO EmissionActivity VALUES('RegionB','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); +CREATE TABLE EmissionEmbodied +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE EmissionEndOfLife +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE ExistingCapacity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +INSERT INTO ExistingCapacity VALUES('RegionA','CAR_BEV',1990,1.0,NULL,NULL); +INSERT INTO ExistingCapacity VALUES('RegionA','CAR_PHEV',1990,1.0,NULL,NULL); +INSERT INTO ExistingCapacity VALUES('RegionA','CAR_ICE',1990,1.0,NULL,NULL); +INSERT INTO ExistingCapacity VALUES('RegionB','CAR_BEV',1990,1.0,NULL,NULL); +INSERT INTO ExistingCapacity VALUES('RegionB','CAR_PHEV',1990,1.0,NULL,NULL); +INSERT INTO ExistingCapacity VALUES('RegionB','CAR_ICE',1990,1.0,NULL,NULL); +CREATE TABLE TechGroup +( + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE GrowthRateMax +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE GrowthRateSeed +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + seed REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE LoanLifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE LifetimeProcess +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE LifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +INSERT INTO LifetimeTech VALUES('RegionA','CAR_BEV',10.0,NULL); +INSERT INTO LifetimeTech VALUES('RegionA','CAR_PHEV',10.0,NULL); +INSERT INTO LifetimeTech VALUES('RegionA','CAR_ICE',10.0,NULL); +INSERT INTO LifetimeTech VALUES('RegionB','CAR_BEV',10.0,NULL); +INSERT INTO LifetimeTech VALUES('RegionB','CAR_PHEV',10.0,NULL); +INSERT INTO LifetimeTech VALUES('RegionB','CAR_ICE',10.0,NULL); +CREATE TABLE LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE MaxActivity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + max_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE MaxCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + max_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE MaxResource +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + max_res REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE MinActivity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + min_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE MaxCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + max_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE MinCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + min_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE MinCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + min_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputFlowOut +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); +CREATE TABLE PlanningReserveMargin +( + region TEXT + PRIMARY KEY + REFERENCES Region (region), + margin REAL +); +CREATE TABLE RampDown +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE RampUp +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE Region +( + region TEXT + PRIMARY KEY, + notes TEXT +); +INSERT INTO Region VALUES('RegionA',NULL); +INSERT INTO Region VALUES('RegionB',NULL); +CREATE TABLE TimeSegmentFraction +( + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + segfrac REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segfrac >= 0 AND segfrac <= 1) +); +INSERT INTO TimeSegmentFraction VALUES(2000,'summer','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'autumn','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'winter','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'spring','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'summer','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'autumn','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'winter','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'spring','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'summer','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'autumn','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'winter','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'spring','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'summer','overnight',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'autumn','overnight',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'winter','overnight',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'spring','overnight',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'summer','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'autumn','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'winter','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'spring','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'summer','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'autumn','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'winter','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'spring','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'summer','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'autumn','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'winter','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'spring','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'summer','overnight',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'autumn','overnight',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'winter','overnight',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'spring','overnight',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'summer','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'autumn','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'winter','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'spring','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'summer','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'autumn','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'winter','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'spring','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'summer','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'autumn','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'winter','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'spring','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'summer','overnight',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'autumn','overnight',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'winter','overnight',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'spring','overnight',0.0625,NULL); +CREATE TABLE StorageDuration +( + region TEXT, + tech TEXT, + duration REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +INSERT INTO StorageDuration VALUES('RegionA','BATT_GRID',2.0,'2 hours energy storage'); +INSERT INTO StorageDuration VALUES('RegionB','BATT_GRID',2.0,'2 hours energy storage'); +CREATE TABLE StorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage) +); +CREATE TABLE TechnologyType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO TechnologyType VALUES('r','resource technology'); +INSERT INTO TechnologyType VALUES('p','production technology'); +INSERT INTO TechnologyType VALUES('pb','baseload production technology'); +INSERT INTO TechnologyType VALUES('ps','storage production technology'); +CREATE TABLE MinTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MinTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2000,'lithium','MANUFAC_NMC',0.8,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2000,'nickel','MANUFAC_NMC',0.15,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2000,'cobalt','MANUFAC_NMC',0.04,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2000,'electricity','MANUFAC_NMC',0.01,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2000,'lithium','MANUFAC_LFP',0.8,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2000,'phosphorous','MANUFAC_LFP',0.19,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2000,'electricity','MANUFAC_LFP',0.01,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2010,'lithium','MANUFAC_NMC',0.8,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2010,'nickel','MANUFAC_NMC',0.15,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2010,'cobalt','MANUFAC_NMC',0.04,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2010,'electricity','MANUFAC_NMC',0.01,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2010,'lithium','MANUFAC_LFP',0.8,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2010,'phosphorous','MANUFAC_LFP',0.19,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2010,'electricity','MANUFAC_LFP',0.01,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2020,'lithium','MANUFAC_NMC',0.8,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2020,'nickel','MANUFAC_NMC',0.15,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2020,'cobalt','MANUFAC_NMC',0.04,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2020,'electricity','MANUFAC_NMC',0.01,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2020,'lithium','MANUFAC_LFP',0.8,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2020,'phosphorous','MANUFAC_LFP',0.19,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2020,'electricity','MANUFAC_LFP',0.01,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2000,'electricity','CAR_PHEV',0.2,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2000,'diesel','CAR_PHEV',0.8,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2010,'electricity','CAR_PHEV',0.2,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2010,'diesel','CAR_PHEV',0.8,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2020,'electricity','CAR_PHEV',0.2,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2020,'diesel','CAR_PHEV',0.8,NULL); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2000,'lithium','MANUFAC_NMC',0.8,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2000,'nickel','MANUFAC_NMC',0.15,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2000,'cobalt','MANUFAC_NMC',0.04,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2000,'electricity','MANUFAC_NMC',0.01,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2000,'lithium','MANUFAC_LFP',0.8,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2000,'phosphorous','MANUFAC_LFP',0.19,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2000,'electricity','MANUFAC_LFP',0.01,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2010,'lithium','MANUFAC_NMC',0.8,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2010,'nickel','MANUFAC_NMC',0.15,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2010,'cobalt','MANUFAC_NMC',0.04,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2010,'electricity','MANUFAC_NMC',0.01,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2010,'lithium','MANUFAC_LFP',0.8,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2010,'phosphorous','MANUFAC_LFP',0.19,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2010,'electricity','MANUFAC_LFP',0.01,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2020,'lithium','MANUFAC_NMC',0.8,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2020,'nickel','MANUFAC_NMC',0.15,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2020,'cobalt','MANUFAC_NMC',0.04,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2020,'electricity','MANUFAC_NMC',0.01,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2020,'lithium','MANUFAC_LFP',0.8,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2020,'phosphorous','MANUFAC_LFP',0.19,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2020,'electricity','MANUFAC_LFP',0.01,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2000,'electricity','CAR_PHEV',0.2,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2000,'diesel','CAR_PHEV',0.8,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2010,'electricity','CAR_PHEV',0.2,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2010,'diesel','CAR_PHEV',0.8,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2020,'electricity','CAR_PHEV',0.2,''); +INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2020,'diesel','CAR_PHEV',0.8,NULL); +CREATE TABLE MinTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MinTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MaxTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE MaxTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE MaxTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE TimeOfDay +( + sequence INTEGER UNIQUE, + tod TEXT + PRIMARY KEY +); +INSERT INTO TimeOfDay VALUES(1,'morning'); +INSERT INTO TimeOfDay VALUES(2,'afternoon'); +INSERT INTO TimeOfDay VALUES(3,'evening'); +INSERT INTO TimeOfDay VALUES(4,'overnight'); +CREATE TABLE TimePeriod +( + sequence INTEGER UNIQUE, + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES TimePeriodType (label) +); +INSERT INTO TimePeriod VALUES(1,1990,'e'); +INSERT INTO TimePeriod VALUES(2,2000,'f'); +INSERT INTO TimePeriod VALUES(3,2010,'f'); +INSERT INTO TimePeriod VALUES(4,2020,'f'); +INSERT INTO TimePeriod VALUES(5,2030,'f'); +CREATE TABLE TimeSeason +( + season TEXT + PRIMARY KEY +); +INSERT INTO TimeSeason VALUES('summer'); +INSERT INTO TimeSeason VALUES('autumn'); +INSERT INTO TimeSeason VALUES('winter'); +INSERT INTO TimeSeason VALUES('spring'); +CREATE TABLE PeriodSeasons +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT + REFERENCES TimeSeason (season), + notes TEXT, + PRIMARY KEY (period, sequence) +); +INSERT INTO PeriodSeasons VALUES(2000,1,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2000,2,'autumn',NULL); +INSERT INTO PeriodSeasons VALUES(2000,3,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2000,4,'spring',NULL); +INSERT INTO PeriodSeasons VALUES(2010,5,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2010,6,'autumn',NULL); +INSERT INTO PeriodSeasons VALUES(2010,7,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2010,8,'spring',NULL); +INSERT INTO PeriodSeasons VALUES(2020,9,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2020,10,'autumn',NULL); +INSERT INTO PeriodSeasons VALUES(2020,11,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2020,12,'spring',NULL); +CREATE TABLE TimePeriodType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO TimePeriodType VALUES('e','existing vintages'); +INSERT INTO TimePeriodType VALUES('f','future'); +CREATE TABLE MaxActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE MaxCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE MaxAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + factor REAL, + source TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE MaxNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + max_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE MaxNewCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + max_new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE MaxNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE MinActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE MinAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + factor REAL, + source TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE MinCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE MinNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + min_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE MinNewCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + min_new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE MinNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE MinNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); +CREATE TABLE MaxNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group) +); +CREATE TABLE OutputEmission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE MinActivityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + min_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE EmissionLimit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE MaxActivityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + max_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "min_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); +CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" +( + "region" TEXT + REFERENCES Region (region), + "period" INTEGER + REFERENCES TimePeriod (period), + "season" TEXT + REFERENCES TimeSeason (season), + "tech" TEXT + REFERENCES Technology (tech), + "max_act" REAL, + "units" TEXT, + "notes" TEXT, + PRIMARY KEY("region","period","season","tech") +); +CREATE TABLE RPSRequirement +( + region TEXT NOT NULL + REFERENCES Region (region), + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech_group TEXT NOT NULL + REFERENCES TechGroup (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE TechGroupMember +( + group_name TEXT + REFERENCES TechGroup (group_name), + tech TEXT + REFERENCES Technology (tech), + PRIMARY KEY (group_name, tech) +); +CREATE TABLE Technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES TechnologyType (label) +); +INSERT INTO Technology VALUES('IMPORT_LI','p','materials',NULL,NULL,1,1,0,0,0,0,0,'lithium importer'); +INSERT INTO Technology VALUES('IMPORT_CO','p','materials',NULL,NULL,1,1,0,0,0,0,0,'cobalt importer'); +INSERT INTO Technology VALUES('IMPORT_P','p','materials',NULL,NULL,1,1,0,0,0,0,0,'phosphorous importer'); +INSERT INTO Technology VALUES('CAR_BEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,'car - battery electric'); +INSERT INTO Technology VALUES('CAR_PHEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,'car - plug in hybrid'); +INSERT INTO Technology VALUES('CAR_ICE','p','transportation',NULL,NULL,0,0,0,0,0,0,0,'car - internal combustion'); +INSERT INTO Technology VALUES('RECYCLE_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,'nmc battery recycler'); +INSERT INTO Technology VALUES('RECYCLE_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,'lfp battery recycler'); +INSERT INTO Technology VALUES('MANUFAC_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,'nmc battery manufacturing'); +INSERT INTO Technology VALUES('MANUFAC_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,'lfp battery manufacturing'); +INSERT INTO Technology VALUES('IMPORT_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,'nickel importer'); +INSERT INTO Technology VALUES('DOMESTIC_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,'domestic nickel production'); +INSERT INTO Technology VALUES('GEN_DSL','p','electricity',NULL,NULL,0,0,0,0,0,0,0,'diesel generators'); +INSERT INTO Technology VALUES('SOL_PV','p','electricity',NULL,NULL,0,0,0,1,0,0,0,'solar panels'); +INSERT INTO Technology VALUES('BATT_GRID','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,'grid battery storage'); +INSERT INTO Technology VALUES('FURNACE','p','residential',NULL,NULL,1,0,0,0,0,0,0,'diesel furnace heater'); +INSERT INTO Technology VALUES('HEATPUMP','p','residential',NULL,NULL,1,0,0,0,0,0,0,'heat pump'); +INSERT INTO Technology VALUES('IMPORT_DSL','p','fuels',NULL,NULL,1,1,0,0,0,0,0,'diesel importer'); +INSERT INTO Technology VALUES('ELEC_INTERTIE','p','electricity',NULL,NULL,0,0,0,0,0,0,1,'dummy tech to make landfill feasible'); +CREATE TABLE OutputCost +( + scenario TEXT, + region TEXT, + period INTEGER, + tech TEXT, + vintage INTEGER, + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES TimePeriod (period), + FOREIGN KEY (tech) REFERENCES Technology (tech) +); +COMMIT; From b46c496bcbd026ef7aa8f6055973c7c904e0d7a4 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 23 May 2025 15:38:16 -0400 Subject: [PATCH 086/587] Nitpicky little tidy up to capacity constraint --- temoa/temoa_model/temoa_initialize.py | 1 + temoa/temoa_model/temoa_rules.py | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 9534d0e0b..68b7e3379 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1363,6 +1363,7 @@ def CapacityConstraintIndices(M: 'TemoaModel'): for r, p, t, v in M.activeActivity_rptv if t not in M.tech_annual if t not in M.tech_uncap + if t not in M.tech_storage for s in M.time_season[p] for d in M.time_of_day ) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index de9676dbc..7c81600e0 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -96,8 +96,6 @@ def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): \\ \forall \{r, p, s, d, t, v\} \in \Theta_{\text{FO}} """ - if t in M.tech_storage: - return Constraint.Skip # The expressions below are defined in-line to minimize the amount of # expression cloning taking place with Pyomo. From 55edcf57f7fe87feed5ec7631b6fe29fa0d3fd93 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 30 May 2025 18:06:37 -0400 Subject: [PATCH 087/587] Update test sets for nitpicky fix --- tests/testing_data/mediumville_sets.json | 32 - tests/testing_data/test_system_sets.json | 7464 ++++++++++------------ tests/testing_data/utopia_sets.json | 3526 +++++----- 3 files changed, 4895 insertions(+), 6127 deletions(-) diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index a48d8b253..e410c7100 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -3171,14 +3171,6 @@ "bulbs", 2025 ], - [ - "B", - 2025, - "s1", - "d1", - "batt", - 2025 - ], [ "A", 2025, @@ -3259,14 +3251,6 @@ "EF", 2025 ], - [ - "B", - 2025, - "s1", - "d2", - "batt", - 2025 - ], [ "A", 2025, @@ -3499,14 +3483,6 @@ "well", 2025 ], - [ - "B", - 2025, - "s2", - "d1", - "batt", - 2025 - ], [ "A", 2025, @@ -3555,14 +3531,6 @@ "FGF_pipe", 2025 ], - [ - "B", - 2025, - "s2", - "d2", - "batt", - 2025 - ], [ "A", 2025, diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 04b959bf7..0f51eda9e 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -27104,209 +27104,249 @@ ], "CapacityConstraint_rpsdtv": [ [ - "R1", + "R2", 2020, - "winter", + "fall", "night", - "E_NUCLEAR", + "E_SOLPV", 2020 ], + [ + "R1", + 2030, + "fall", + "night", + "E_NGCC", + 2025 + ], [ "R2", - 2025, - "winter", + 2030, + "summer", "day", - "T_EV", + "R_EH", 2020 ], [ - "R1", + "R2", 2025, "summer", "night", - "E_NUCLEAR", - 2025 + "T_EV", + 2020 ], [ "R2", 2030, - "spring", + "fall", "day", - "E_SOLPV", - 2020 + "T_DSL", + 2030 ], [ "R2", - 2020, + 2030, "winter", + "night", + "T_GSL", + 2025 + ], + [ + "R2", + 2020, + "summer", "day", - "T_DSL", + "R_EH", 2020 ], [ "R2", - 2030, + 2020, "spring", - "day", - "E_BATT", + "night", + "T_DSL", 2020 ], [ "R1", 2030, "fall", - "night", - "E_NUCLEAR", - 2030 + "day", + "T_BLND", + 2020 ], [ "R1", - 2020, + 2030, "spring", - "night", - "R_EH", + "day", + "R_NGH", 2020 ], [ "R1", 2030, - "summer", + "spring", "day", - "T_GSL", + "E_NUCLEAR", 2030 ], [ - "R1", - 2020, - "summer", + "R2", + 2030, + "fall", "day", - "E_NGCC", + "T_BLND", 2020 ], [ "R1", - 2020, + 2030, "summer", "day", - "T_BLND", - 2020 + "R_EH", + 2025 ], [ "R1", + 2025, + "winter", + "day", + "R_NGH", + 2020 + ], + [ + "R2", 2030, "spring", - "day", + "night", "R_NGH", 2025 ], [ "R2", - 2025, - "winter", + 2030, + "spring", "day", - "E_NUCLEAR", - 2025 + "E_NGCC", + 2030 ], [ "R2", - 2025, - "fall", - "day", - "E_SOLPV", + 2030, + "spring", + "night", + "S_OILREF", 2020 ], [ "R2", 2025, - "fall", + "summer", "day", - "E_BATT", - 2020 + "E_NGCC", + 2025 ], [ "R2", 2030, "summer", "day", - "R_EH", + "E_NUCLEAR", 2025 ], [ - "R2", + "R1", 2025, - "winter", + "spring", "night", - "T_EV", + "R_NGH", 2020 ], [ "R2", 2030, "summer", - "day", + "night", "R_NGH", - 2030 + 2020 + ], + [ + "R1", + 2025, + "spring", + "day", + "E_NGCC", + 2025 ], [ "R2", 2030, - "fall", + "summer", "day", "T_EV", 2025 ], + [ + "R2", + 2025, + "summer", + "night", + "T_DSL", + 2025 + ], [ "R1", 2030, "winter", "night", - "E_BATT", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2025, + "spring", + "night", + "R_NGH", 2020 ], [ "R1", 2030, - "summer", + "winter", "night", "T_GSL", - 2030 + 2020 ], [ "R1", - 2020, + 2030, "summer", - "night", - "E_NGCC", - 2020 + "day", + "E_NUCLEAR", + 2015 ], [ "R1", 2020, "summer", "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "winter", - "day", - "E_NUCLEAR", + "T_GSL", 2020 ], [ "R2", 2025, "spring", - "night", - "E_NUCLEAR", + "day", + "E_NGCC", 2025 ], [ "R2", - 2025, - "fall", + 2030, + "winter", "night", "E_SOLPV", 2020 @@ -27314,151 +27354,151 @@ [ "R2", 2025, - "fall", + "summer", "night", - "E_BATT", - 2020 + "E_SOLPV", + 2025 ], [ - "R1", + "R1-R2", 2025, - "summer", - "day", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, "spring", "day", - "R_EH", - 2025 + "E_TRANS", + 2015 ], [ - "R2", - 2030, + "R2-R1", + 2020, "summer", - "night", - "R_EH", - 2025 + "day", + "E_TRANS", + 2015 ], [ "R2", 2030, - "summer", - "night", - "R_NGH", + "winter", + "day", + "E_NGCC", 2030 ], [ - "R1", - 2030, - "fall", - "day", - "T_DSL", - 2025 + "R2", + 2020, + "winter", + "night", + "E_SOLPV", + 2020 ], [ "R2", 2030, - "winter", + "summer", "day", - "E_SOLPV", + "E_NGCC", 2020 ], [ "R2", - 2020, + 2025, "winter", "night", - "E_NGCC", - 2020 + "E_NUCLEAR", + 2015 ], [ - "R2", + "R1", 2030, "summer", "day", - "T_GSL", + "T_EV", 2030 ], [ - "R1", - 2025, + "R2", + 2020, "summer", "night", - "T_DSL", + "E_NUCLEAR", 2020 ], [ "R1", - 2030, + 2020, "winter", "day", - "R_EH", + "E_NUCLEAR", 2020 ], [ "R1", - 2030, - "spring", - "night", - "R_EH", + 2025, + "winter", + "day", + "E_NUCLEAR", 2025 ], [ "R1", - 2030, - "spring", - "night", - "R_NGH", - 2030 + 2020, + "winter", + "day", + "T_EV", + 2020 ], [ "R1", 2030, - "fall", - "night", + "summer", + "day", "T_DSL", - 2025 + 2030 ], [ - "R2", - 2025, + "R1", + 2030, "fall", - "day", - "S_OILREF", + "night", + "E_NGCC", 2020 ], [ - "R1", - 2025, + "R2", + 2030, "summer", "day", - "E_NUCLEAR", - 2020 + "T_DSL", + 2030 ], [ - "R2-R1", - 2020, + "R1-R2", + 2030, "summer", - "day", + "night", "E_TRANS", 2015 ], + [ + "R1", + 2020, + "spring", + "night", + "T_BLND", + 2020 + ], [ "R2", 2030, - "summer", + "fall", "day", - "T_EV", - 2030 + "T_DSL", + 2025 ], [ - "R1", - 2030, - "winter", + "R2", + 2025, + "summer", "day", "R_NGH", 2025 @@ -27466,137 +27506,129 @@ [ "R1", 2030, - "fall", + "spring", "day", - "E_NUCLEAR", + "R_EH", 2025 ], [ "R2", - 2025, - "winter", - "day", - "T_DSL", + 2020, + "summer", + "night", + "R_EH", 2020 ], [ - "R2-R1", - 2025, - "fall", + "R1", + 2030, + "spring", "day", - "E_TRANS", - 2015 + "E_NUCLEAR", + 2025 ], [ - "R2", - 2030, + "R1", + 2025, "winter", - "night", - "E_SOLPV", - 2020 + "day", + "R_EH", + 2025 ], [ "R1", 2030, "summer", - "night", - "R_NGH", - 2025 + "day", + "R_EH", + 2020 ], [ - "R2", - 2030, - "winter", + "R1", + 2020, + "spring", "night", - "E_BATT", + "E_NUCLEAR", 2020 ], [ "R1", - 2030, + 2020, "fall", "night", - "T_EV", + "E_NGCC", 2020 ], [ - "R1", - 2030, + "R2", + 2025, "winter", "night", - "R_EH", + "T_DSL", 2020 ], [ - "R1", + "R2", 2030, - "winter", + "spring", "night", "R_NGH", - 2025 + 2020 ], [ - "R1", - 2020, - "winter", + "R2", + 2025, + "fall", "night", - "E_NUCLEAR", - 2015 + "R_NGH", + 2025 ], [ "R1", 2025, - "summer", - "night", - "E_NUCLEAR", + "fall", + "day", + "T_GSL", 2020 ], [ - "R2-R1", - 2020, - "summer", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", + "R2", 2030, - "spring", + "winter", "day", - "T_EV", + "E_NUCLEAR", 2030 ], [ - "R1", + "R2", 2030, "summer", - "day", - "T_GSL", + "night", + "R_EH", 2025 ], [ - "R1", + "R2", 2030, - "fall", - "night", + "summer", + "day", "E_NUCLEAR", - 2025 + 2020 ], [ "R1", 2030, - "spring", + "winter", "day", - "R_NGH", + "S_OILREF", 2020 ], [ "R2", - 2025, - "spring", + 2020, + "winter", "day", - "E_NUCLEAR", + "E_NGCC", 2020 ], [ @@ -27604,7 +27636,15 @@ 2030, "winter", "day", - "S_OILREF", + "T_EV", + 2030 + ], + [ + "R2", + 2025, + "summer", + "night", + "T_DSL", 2020 ], [ @@ -27612,23 +27652,31 @@ 2030, "summer", "day", - "R_EH", + "T_EV", 2020 ], [ "R1", - 2020, + 2025, "spring", "day", - "T_GSL", + "E_NGCC", 2020 ], [ - "R2", + "R1", 2030, - "summer", + "fall", "day", - "R_NGH", + "E_SOLPV", + 2030 + ], + [ + "R2", + 2025, + "spring", + "night", + "E_NUCLEAR", 2025 ], [ @@ -27636,414 +27684,350 @@ 2030, "fall", "day", - "T_EV", - 2020 + "E_SOLPV", + 2030 ], [ "R1", 2030, "spring", - "night", + "day", "T_EV", 2030 ], [ "R1", - 2030, - "summer", + 2020, + "winter", "night", - "T_GSL", - 2025 + "T_BLND", + 2020 ], [ "R2", 2030, - "fall", - "night", - "T_EV", - 2030 + "winter", + "day", + "E_NGCC", + 2025 ], [ - "R2", + "R1", 2025, - "spring", - "night", - "E_NUCLEAR", - 2020 + "fall", + "day", + "E_SOLPV", + 2025 ], [ "R2", - 2020, - "spring", - "night", - "E_NGCC", - 2020 + 2030, + "winter", + "day", + "R_EH", + 2030 ], [ "R2", 2020, "spring", "night", - "T_BLND", + "E_SOLPV", 2020 ], [ "R1", 2030, - "spring", + "summer", "day", - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "S_OILREF", - 2020 + "T_EV", + 2025 ], [ "R2", - 2030, + 2020, "summer", "night", - "R_EH", - 2020 + "E_NUCLEAR", + 2015 ], [ "R1", - 2030, - "fall", + 2020, + "winter", "day", - "T_DSL", - 2020 + "E_NUCLEAR", + 2015 ], [ "R2", 2030, "summer", "night", - "R_NGH", - 2025 + "E_NUCLEAR", + 2030 ], [ "R1", 2020, "fall", "day", - "R_EH", + "T_BLND", 2020 ], - [ - "R2", - 2025, - "spring", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "summer", - "day", - "T_DSL", - 2030 - ], [ "R1", 2020, - "spring", + "winter", "night", - "T_EV", + "E_NUCLEAR", 2020 ], [ "R1", 2030, - "spring", - "night", - "R_EH", - 2020 + "summer", + "day", + "T_DSL", + 2025 ], [ "R1", - 2030, + 2025, "winter", "day", - "R_NGH", + "E_NUCLEAR", 2020 ], [ - "R1", + "R2", 2030, - "fall", + "summer", "night", - "T_DSL", - 2020 + "T_EV", + 2030 ], [ "R1", - 2025, - "summer", + 2030, + "spring", "day", - "E_NUCLEAR", - 2015 + "T_BLND", + 2020 ], [ "R2", 2030, "summer", "day", - "T_EV", + "T_DSL", 2025 ], [ "R2", - 2025, - "winter", - "night", - "E_NGCC", - 2025 + 2030, + "fall", + "day", + "T_GSL", + 2030 ], [ - "R1", + "R2", 2030, "fall", "day", - "E_NUCLEAR", + "T_DSL", 2020 ], [ - "R1", - 2030, - "spring", + "R2", + 2020, + "winter", "day", - "T_DSL", - 2030 + "R_EH", + 2020 ], [ - "R1", - 2030, + "R2", + 2025, "summer", - "night", + "day", "R_NGH", 2020 ], [ "R1", 2030, - "winter", - "night", - "T_EV", - 2030 + "spring", + "day", + "R_EH", + 2020 ], [ "R2", - 2030, - "fall", + 2020, + "winter", "day", - "T_DSL", - 2030 - ], - [ - "R1", - 2025, - "summer", - "night", "E_NUCLEAR", - 2015 + 2020 ], [ - "R1", - 2030, + "R2", + 2020, "spring", - "day", - "T_EV", - 2025 + "night", + "T_GSL", + 2020 ], [ "R1", - 2025, + 2020, "fall", - "night", - "R_NGH", - 2025 - ], - [ - "R2", - 2025, - "summer", "day", - "E_NGCC", - 2025 + "T_EV", + 2020 ], [ "R1", 2030, - "summer", + "spring", "day", - "T_GSL", + "E_NUCLEAR", 2020 ], [ "R1", 2030, - "fall", - "night", - "E_NUCLEAR", - 2020 + "winter", + "day", + "R_NGH", + 2030 ], [ - "R2", + "R1", 2025, - "spring", + "winter", "day", - "E_NUCLEAR", - 2015 + "R_EH", + 2020 ], [ "R1", 2020, "spring", - "day", - "T_DSL", - 2020 - ], - [ - "R2-R1", - 2025, - "summer", "night", - "E_TRANS", + "E_NUCLEAR", 2015 ], [ - "R1", + "R2", 2025, - "fall", - "day", + "winter", + "night", "T_GSL", 2025 ], [ "R2", - 2030, - "summer", - "day", - "R_NGH", + 2025, + "spring", + "night", + "T_BLND", 2020 ], [ "R1", 2030, - "spring", - "night", - "T_EV", + "fall", + "day", + "T_DSL", 2025 ], [ "R2", - 2025, + 2020, "summer", "night", - "E_SOLPV", - 2025 + "T_BLND", + 2020 ], [ "R1", - 2025, - "summer", + 2020, + "winter", "day", - "S_OILREF", + "T_DSL", 2020 ], [ "R2", - 2025, - "summer", - "night", - "E_BATT", + 2030, + "winter", + "day", + "E_NUCLEAR", 2025 ], [ - "R1", + "R2", 2030, "summer", "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "S_OILREF", + "R_EH", 2020 ], [ "R2", - 2025, - "spring", - "night", + 2030, + "summer", + "day", "E_NUCLEAR", 2015 ], [ - "R2", + "R1", 2030, "summer", - "night", - "T_EV", + "day", + "E_SOLPV", 2030 ], [ - "R1", + "R2", 2020, "spring", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "winter", "day", - "T_DSL", - 2030 + "E_NGCC", + 2020 ], [ "R2", 2030, - "fall", + "winter", "day", - "E_NGCC", - 2020 + "T_EV", + 2025 ], [ "R2", - 2030, + 2025, "summer", "night", - "R_NGH", - 2020 + "T_GSL", + 2025 ], [ "R1", - 2025, + 2030, "fall", - "night", - "T_GSL", + "day", + "E_SOLPV", 2025 ], [ - "R1", - 2020, + "R2", + 2025, "spring", - "day", + "night", "E_NUCLEAR", 2020 ], @@ -28051,504 +28035,512 @@ "R2", 2030, "fall", - "night", - "E_NGCC", - 2030 - ], - [ - "R2", - 2025, - "spring", "day", - "E_BATT", - 2020 + "E_SOLPV", + 2025 ], [ "R1", - 2025, + 2020, "summer", "day", - "E_SOLPV", - 2025 + "E_NGCC", + 2020 ], [ "R1", 2030, - "fall", + "spring", + "night", + "R_NGH", + 2020 + ], + [ + "R1-R2", + 2030, + "spring", "day", - "E_SOLPV", - 2030 + "E_TRANS", + 2015 ], [ "R1", - 2020, - "summer", + 2030, + "spring", "day", - "R_EH", - 2020 + "T_EV", + 2025 ], [ "R2", 2030, - "summer", + "winter", "day", - "T_DSL", - 2025 + "E_NGCC", + 2020 ], [ - "R2", + "R1", 2020, - "summer", - "day", + "spring", + "night", "T_EV", 2020 ], [ - "R2", - 2020, + "R1", + 2025, "fall", "day", - "T_GSL", + "E_SOLPV", 2020 ], [ - "R2", - 2030, - "summer", + "R1", + 2025, + "winter", "day", "T_EV", - 2020 + 2025 ], [ - "R1", + "R2", 2030, "winter", "day", - "E_NUCLEAR", - 2030 + "R_EH", + 2025 ], [ "R2", 2025, - "winter", + "fall", "night", "E_NGCC", - 2020 + 2025 ], [ "R1", 2030, - "fall", + "summer", "day", - "E_NUCLEAR", - 2015 + "T_EV", + 2020 ], [ "R1", 2020, - "summer", + "spring", "night", - "R_EH", + "T_DSL", 2020 ], [ "R1", - 2030, - "spring", + 2025, + "winter", "day", - "T_DSL", - 2025 + "E_NUCLEAR", + 2015 ], [ - "R1", + "R2", 2030, - "winter", + "summer", "night", - "T_EV", - 2025 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_SOLPV", + "E_NUCLEAR", 2025 ], [ "R1", 2030, "summer", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2020, - "fall", - "night", + "day", "T_GSL", - 2020 + 2030 ], [ "R1", 2030, - "spring", + "summer", "day", - "T_EV", + "T_DSL", 2020 ], [ "R1", - 2025, - "fall", + 2020, + "winter", "night", - "R_NGH", - 2020 + "E_NUCLEAR", + 2015 ], [ "R2", - 2025, + 2030, "summer", - "day", - "E_NGCC", - 2020 + "night", + "T_EV", + 2025 ], [ - "R2", - 2025, + "R1-R2", + 2020, "summer", - "day", - "T_BLND", - 2020 + "night", + "E_TRANS", + 2015 ], [ - "R1", - 2025, - "fall", + "R2", + 2030, + "summer", "day", "T_GSL", - 2020 + 2030 ], [ "R2", 2030, "summer", - "night", + "day", "T_DSL", - 2030 - ], - [ - "R1", - 2030, - "spring", - "night", - "T_EV", 2020 ], [ "R2", 2025, - "summer", - "night", - "E_SOLPV", - 2020 + "winter", + "day", + "R_NGH", + 2025 ], [ "R2", 2030, - "summer", + "fall", "day", - "E_NUCLEAR", - 2030 + "T_GSL", + 2025 ], [ "R2", 2025, - "summer", - "night", - "E_BATT", + "winter", + "day", + "S_OILREF", 2020 ], - [ - "R1-R2", - 2025, - "spring", - "night", - "E_TRANS", - 2015 - ], [ "R2", - 2030, + 2020, "summer", - "night", - "T_EV", - 2025 + "day", + "T_DSL", + 2020 ], [ - "R1", + "R2", 2025, - "fall", + "spring", "night", - "T_GSL", - 2020 + "T_DSL", + 2025 ], [ "R1", 2030, - "winter", + "spring", "day", "T_DSL", - 2025 + 2030 ], [ "R1", - 2020, + 2030, "spring", "day", "E_NUCLEAR", 2015 ], [ - "R2", + "R1", 2030, - "fall", - "night", - "E_NGCC", + "winter", + "day", + "R_NGH", 2025 ], [ - "R2", + "R1", 2020, "summer", "day", - "T_DSL", + "R_EH", 2020 ], [ "R2", 2030, "summer", - "night", - "E_NUCLEAR", - 2030 + "day", + "S_OILREF", + 2020 ], [ - "R1", - 2030, - "fall", + "R2", + 2020, + "summer", "day", "E_SOLPV", - 2025 + 2020 ], [ - "R1", + "R2", 2020, "summer", "day", - "R_NGH", + "T_GSL", + 2020 + ], + [ + "R2", + 2025, + "fall", + "night", + "R_EH", + 2025 + ], + [ + "R2", + 2025, + "winter", + "night", + "T_GSL", 2020 ], [ "R1", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2030 + 2020, + "winter", + "night", + "T_EV", + 2020 ], [ "R1", - 2025, - "summer", + 2030, + "fall", "day", - "E_SOLPV", + "T_DSL", 2020 ], + [ + "R2", + 2025, + "fall", + "night", + "E_NUCLEAR", + 2025 + ], [ "R2", 2030, - "summer", + "winter", "day", - "T_DSL", + "E_NUCLEAR", 2020 ], [ - "R1", + "R2", 2030, "summer", "night", "T_DSL", - 2025 + 2030 ], [ "R1", - 2030, + 2025, "winter", "day", - "T_EV", + "T_BLND", 2020 ], [ "R1", 2030, - "winter", + "summer", "day", - "E_NUCLEAR", + "E_SOLPV", 2025 ], [ - "R1", + "R2", 2025, - "winter", - "day", - "E_NGCC", - 2025 - ], - [ - "R1", - 2020, "summer", "night", - "R_NGH", + "T_GSL", 2020 ], [ "R1", 2030, - "spring", + "fall", + "day", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2025, + "summer", "night", "E_NGCC", - 2030 + 2025 ], [ - "R1", - 2030, - "spring", + "R2", + 2020, + "winter", "day", - "T_DSL", + "T_EV", 2020 ], [ - "R2", + "R1", 2025, - "summer", + "winter", "night", - "S_OILREF", - 2020 + "E_SOLPV", + 2025 ], [ "R2", - 2025, - "spring", + 2030, + "fall", "day", "E_SOLPV", 2020 ], + [ + "R2", + 2025, + "spring", + "night", + "E_NUCLEAR", + 2015 + ], [ "R1", - 2030, - "winter", + 2025, + "spring", "night", - "T_EV", + "T_BLND", 2020 ], [ "R2", - 2020, + 2030, "summer", - "day", - "E_NGCC", + "night", + "T_BLND", 2020 ], [ "R1", 2030, - "summer", - "night", - "E_NUCLEAR", - 2025 + "spring", + "day", + "T_EV", + 2020 ], [ - "R1-R2", + "R2", 2025, "winter", "night", - "E_TRANS", - 2015 + "E_SOLPV", + 2025 ], [ "R1", 2020, - "summer", + "fall", "day", - "T_GSL", + "T_DSL", 2020 ], [ - "R1", - 2020, - "spring", + "R2", + 2025, + "fall", "night", - "E_NUCLEAR", + "E_NGCC", 2020 ], [ "R1", - 2020, + 2025, "winter", "day", - "S_OILREF", + "T_EV", 2020 ], [ "R2", 2030, - "summer", + "spring", "night", - "T_DSL", + "T_EV", 2025 ], [ - "R2", - 2030, - "summer", + "R1", + 2020, + "fall", "day", - "E_NUCLEAR", - 2025 + "E_SOLPV", + 2020 ], [ "R2", 2030, "summer", "night", - "T_EV", + "E_NUCLEAR", 2020 ], [ "R1", - 2020, - "fall", + 2030, + "summer", "day", + "T_GSL", + 2025 + ], + [ + "R2", + 2030, + "summer", + "night", "T_EV", 2020 ], [ - "R1", + "R2", 2030, - "winter", + "summer", "day", - "T_DSL", - 2020 + "T_GSL", + 2025 ], [ "R2", 2025, "spring", - "day", - "S_OILREF", + "night", + "T_EV", 2020 ], [ @@ -28557,86 +28549,62 @@ "summer", "day", "R_EH", - 2025 + 2020 ], [ "R2", - 2030, - "fall", - "night", - "E_NGCC", + 2025, + "winter", + "day", + "R_NGH", 2020 ], [ - "R1", + "R2", 2030, - "spring", + "fall", "day", - "E_NUCLEAR", - 2025 + "T_GSL", + 2020 ], [ - "R1", + "R2", 2025, - "summer", + "spring", "night", - "T_GSL", + "T_DSL", 2020 ], [ - "R1", - 2025, + "R2-R1", + 2030, "spring", "day", - "E_NGCC", - 2025 + "E_TRANS", + 2015 ], [ - "R2", - 2025, - "fall", + "R1", + 2030, + "spring", "day", - "T_EV", + "T_DSL", 2025 ], [ "R2", - 2025, - "winter", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, + 2020, "summer", "night", "T_DSL", 2020 ], - [ - "R2", - 2020, - "spring", - "day", - "R_NGH", - 2020 - ], [ "R1", 2030, "winter", "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_NGCC", + "R_NGH", 2020 ], [ @@ -28644,53 +28612,69 @@ 2025, "winter", "day", - "T_BLND", - 2020 + "T_DSL", + 2025 ], [ - "R1", + "R1-R2", 2025, - "spring", + "fall", "night", - "E_SOLPV", - 2025 + "E_TRANS", + 2015 ], [ - "R1", + "R2", 2030, "spring", "night", - "E_NGCC", - 2025 + "T_DSL", + 2030 ], [ "R2", - 2020, - "spring", + 2030, + "fall", "night", "R_NGH", - 2020 + 2030 ], [ - "R1", + "R2", 2030, "summer", + "day", + "E_SOLPV", + 2030 + ], + [ + "R2", + 2025, + "fall", "night", - "E_NUCLEAR", + "R_EH", 2020 ], [ - "R1-R2", + "R1", 2030, - "summer", + "fall", "day", - "E_TRANS", - 2015 + "T_GSL", + 2025 ], [ "R2", + 2025, + "fall", + "day", + "T_BLND", + 2020 + ], + [ + "R1", 2020, - "spring", + "winter", "day", "T_GSL", 2020 @@ -28698,18 +28682,18 @@ [ "R1", 2025, - "fall", - "night", - "E_NUCLEAR", + "winter", + "day", + "E_SOLPV", 2025 ], [ "R1", - 2020, + 2030, "spring", "night", - "E_NUCLEAR", - 2015 + "T_BLND", + 2020 ], [ "R2", @@ -28717,206 +28701,222 @@ "summer", "night", "T_DSL", - 2020 + 2025 ], [ "R1", - 2020, - "fall", + 2030, + "summer", "day", - "T_DSL", + "E_SOLPV", 2020 ], [ - "R2", - 2030, + "R1", + 2020, "winter", "day", - "E_NGCC", - 2030 + "S_OILREF", + 2020 ], [ "R2", - 2020, + 2030, "spring", "night", - "R_EH", + "T_BLND", 2020 ], [ "R2", 2025, - "winter", - "night", - "R_NGH", + "summer", + "day", + "T_EV", 2025 ], [ - "R2", - 2030, + "R1", + 2025, "summer", - "day", - "E_NUCLEAR", + "night", + "E_NGCC", 2020 ], [ "R1", - 2020, + 2025, "winter", - "day", + "night", "E_SOLPV", 2020 ], + [ + "R1", + 2025, + "summer", + "day", + "E_NUCLEAR", + 2015 + ], [ "R1", 2030, - "fall", + "spring", "night", - "T_GSL", - 2030 + "E_NUCLEAR", + 2020 ], [ - "R1", - 2020, + "R2", + 2025, "winter", - "day", - "E_BATT", + "night", + "E_SOLPV", 2020 ], [ - "R1", - 2030, + "R2", + 2025, "summer", "day", - "E_SOLPV", - 2030 + "E_NUCLEAR", + 2015 ], [ "R2", - 2025, - "winter", - "day", - "T_GSL", - 2025 + 2030, + "spring", + "night", + "E_NUCLEAR", + 2020 ], [ - "R1", + "R2-R1", 2030, - "summer", + "fall", "day", - "E_BATT", - 2030 + "E_TRANS", + 2015 ], [ "R2", 2030, - "winter", + "spring", "night", - "E_NGCC", - 2030 + "T_EV", + 2020 ], [ - "R2", - 2025, - "summer", + "R1-R2", + 2030, + "winter", "day", - "R_EH", - 2020 + "E_TRANS", + 2015 ], [ "R2", + 2025, + "fall", + "night", + "T_EV", + 2025 + ], + [ + "R1", 2020, "winter", "night", - "R_NGH", + "T_DSL", 2020 ], [ - "R2", + "R1", 2020, - "summer", + "spring", "night", - "E_NGCC", + "T_GSL", 2020 ], [ "R2", - 2020, + 2030, "summer", "night", - "T_BLND", - 2020 + "E_NUCLEAR", + 2015 ], [ - "R1", - 2025, + "R2", + 2020, "spring", "day", - "E_NGCC", + "R_EH", 2020 ], [ - "R1", - 2025, - "spring", + "R2-R1", + 2020, + "fall", "day", - "T_BLND", - 2020 + "E_TRANS", + 2015 ], [ "R2", 2025, - "fall", + "winter", "day", - "T_EV", - 2020 + "R_EH", + 2025 ], [ "R2", 2020, - "fall", - "night", - "E_NUCLEAR", + "winter", + "day", + "T_DSL", 2020 ], [ "R2", - 2030, - "summer", - "night", - "E_NGCC", - 2020 + 2025, + "winter", + "day", + "E_NUCLEAR", + 2025 ], [ "R1", 2030, "spring", "day", - "E_NUCLEAR", - 2020 + "E_SOLPV", + 2030 ], [ "R2", 2025, - "summer", - "day", - "R_NGH", + "spring", + "night", + "T_GSL", 2025 ], [ - "R2", + "R1", 2030, - "fall", + "spring", "day", - "T_BLND", - 2020 + "T_GSL", + 2030 ], [ - "R2", - 2020, - "winter", + "R1", + 2030, + "spring", "day", - "T_GSL", + "T_DSL", 2020 ], [ @@ -28924,215 +28924,247 @@ 2030, "summer", "night", - "E_SOLPV", + "R_NGH", 2030 ], [ "R1", - 2030, + 2025, "summer", "day", - "E_NUCLEAR", - 2015 + "T_BLND", + 2020 ], [ "R1", 2030, - "summer", + "spring", "night", - "E_BATT", - 2030 + "T_DSL", + 2025 ], [ "R1", - 2020, - "summer", - "night", - "T_EV", + 2025, + "winter", + "day", + "T_DSL", 2020 ], [ "R2", - 2030, - "fall", + 2025, + "summer", "day", - "T_GSL", - 2030 + "T_BLND", + 2020 ], [ "R1", - 2025, + 2030, "fall", "night", - "T_DSL", + "S_OILREF", 2020 ], [ - "R1", + "R2", 2030, "winter", - "day", - "E_NUCLEAR", - 2015 + "night", + "T_BLND", + 2020 ], [ - "R1", - 2025, + "R2", + 2030, "spring", "night", - "E_SOLPV", - 2020 + "T_DSL", + 2025 ], [ - "R1", + "R2", 2030, - "spring", + "fall", "night", - "E_NGCC", + "R_NGH", + 2025 + ], + [ + "R2", + 2030, + "fall", + "night", + "S_OILREF", 2020 ], [ "R1", 2030, - "spring", - "night", - "T_BLND", + "fall", + "day", + "T_GSL", 2020 ], [ - "R1-R2", + "R1", 2025, - "summer", + "spring", "day", - "E_TRANS", - 2015 + "S_OILREF", + 2020 ], [ "R2", 2030, - "fall", + "summer", "night", - "T_BLND", - 2020 + "E_SOLPV", + 2030 ], [ - "R2", - 2020, + "R1", + 2025, "winter", - "night", - "T_GSL", + "day", + "E_SOLPV", 2020 ], [ - "R1", + "R2", 2030, "summer", "night", - "E_NUCLEAR", - 2015 + "T_GSL", + 2030 ], [ "R2", 2030, + "summer", + "night", + "T_DSL", + 2020 + ], + [ + "R1", + 2025, "spring", - "day", - "E_NGCC", - 2030 + "night", + "T_DSL", + 2020 ], [ "R2", + 2025, + "summer", + "day", + "T_EV", + 2020 + ], + [ + "R1", 2030, "fall", "night", - "T_GSL", + "R_NGH", 2030 ], [ "R1", - 2025, - "fall", + 2030, + "spring", "night", "E_NUCLEAR", - 2020 + 2015 ], [ - "R1-R2", - 2025, + "R1", + 2020, "fall", "day", - "E_TRANS", - 2015 + "T_GSL", + 2020 ], [ - "R2", + "R1", 2030, "winter", "day", - "E_NGCC", - 2025 + "T_EV", + 2030 + ], + [ + "R2", + 2020, + "summer", + "night", + "E_SOLPV", + 2020 ], [ "R2", 2030, "spring", "night", - "E_SOLPV", - 2030 + "E_NUCLEAR", + 2015 ], [ "R2", 2025, - "winter", - "night", + "spring", + "day", "R_NGH", + 2025 + ], + [ + "R2", + 2025, + "fall", + "night", + "T_EV", 2020 ], [ "R2", - 2030, - "summer", + 2025, + "winter", "day", - "E_NUCLEAR", - 2015 + "T_BLND", + 2020 ], [ "R1", - 2020, + 2025, "summer", "day", "T_DSL", - 2020 + 2025 ], [ "R2", - 2030, - "fall", - "night", - "R_EH", - 2030 - ], - [ - "R1", 2025, - "spring", - "night", - "S_OILREF", + "winter", + "day", + "R_EH", 2020 ], [ - "R1", + "R2", 2030, - "fall", - "night", - "T_GSL", - 2025 + "summer", + "day", + "R_NGH", + 2020 ], [ - "R1", - 2030, + "R2", + 2025, "summer", "day", - "E_SOLPV", + "T_DSL", 2025 ], [ @@ -29140,23 +29172,23 @@ 2025, "winter", "day", - "T_GSL", + "E_NUCLEAR", 2020 ], [ "R1", 2030, - "summer", + "spring", "day", - "E_BATT", + "E_SOLPV", 2025 ], [ "R2", 2025, - "summer", - "day", - "R_NGH", + "spring", + "night", + "T_GSL", 2020 ], [ @@ -29164,219 +29196,179 @@ 2030, "spring", "day", - "E_NUCLEAR", - 2015 + "T_GSL", + 2025 ], [ "R1", - 2020, - "summer", - "night", - "T_DSL", - 2020 - ], + 2030, + "winter", + "day", + "R_EH", + 2020 + ], [ "R2", 2020, - "fall", + "summer", "night", - "E_NUCLEAR", - 2015 + "T_GSL", + 2020 ], [ "R1", - 2025, + 2020, "spring", "night", - "E_BATT", - 2025 + "E_SOLPV", + 2020 ], [ - "R1", - 2020, + "R2", + 2025, "summer", "day", - "E_NUCLEAR", - 2020 + "E_SOLPV", + 2025 ], [ - "R2", - 2020, + "R1", + 2030, "spring", "night", "T_GSL", - 2020 + 2030 ], [ "R1", 2030, - "summer", + "spring", "night", - "E_SOLPV", - 2025 + "T_DSL", + 2020 ], [ "R1", - 2030, - "summer", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "fall", + 2025, + "winter", "day", "T_GSL", 2025 ], - [ - "R2", - 2020, - "spring", - "night", - "T_EV", - 2020 - ], [ "R1", - 2020, + 2030, "summer", "night", - "E_NUCLEAR", - 2020 + "R_NGH", + 2025 ], [ "R2", 2030, "spring", - "day", - "E_NGCC", - 2025 + "night", + "T_GSL", + 2030 ], [ - "R1", - 2025, + "R2", + 2030, "spring", - "day", - "R_EH", - 2025 + "night", + "T_DSL", + 2020 ], [ "R2", 2030, - "spring", + "fall", "night", - "S_OILREF", + "R_NGH", 2020 ], [ "R2", 2025, - "winter", + "summer", "night", - "T_GSL", - 2025 + "T_BLND", + 2020 ], [ - "R1", - 2025, + "R2", + 2030, "fall", "night", "E_NUCLEAR", - 2015 + 2030 ], [ "R2", 2025, "fall", - "day", - "E_NGCC", + "night", + "T_DSL", 2025 ], [ "R1", - 2020, + 2025, "spring", - "day", - "S_OILREF", - 2020 - ], - [ - "R1", - 2020, - "fall", - "night", - "E_NGCC", - 2020 - ], - [ - "R1", - 2020, - "fall", "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "T_BLND", - 2020 + "E_SOLPV", + 2025 ], [ "R2", 2030, - "winter", - "day", - "E_NGCC", - 2020 + "summer", + "night", + "E_SOLPV", + 2025 ], [ "R1", 2025, "spring", "night", - "R_EH", + "T_GSL", 2025 ], [ "R2", 2030, - "spring", + "summer", "night", - "E_SOLPV", + "T_GSL", 2025 ], [ - "R2", - 2030, - "spring", - "night", - "E_BATT", - 2025 + "R2-R1", + 2025, + "summer", + "day", + "E_TRANS", + 2015 ], [ "R2", - 2030, - "fall", + 2025, + "spring", "night", - "R_EH", + "E_SOLPV", 2025 ], [ "R2", - 2030, - "fall", - "night", - "R_NGH", - 2030 + 2025, + "winter", + "day", + "T_EV", + 2025 ], [ - "R2", + "R1", 2025, "fall", "night", @@ -29388,191 +29380,151 @@ 2030, "fall", "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "T_EV", + "R_NGH", 2025 ], [ "R1", 2030, - "summer", + "winter", "day", - "E_SOLPV", - 2020 + "E_NUCLEAR", + 2025 ], [ "R1", 2030, - "summer", + "winter", "day", - "E_BATT", - 2020 + "T_EV", + 2025 ], [ "R1-R2", - 2025, - "summer", - "night", + 2020, + "winter", + "day", "E_TRANS", 2015 ], [ "R1", - 2025, - "fall", - "day", - "E_SOLPV", - 2025 - ], - [ - "R2", 2020, - "spring", + "winter", "night", - "T_DSL", + "E_SOLPV", 2020 ], [ "R1", - 2025, + 2020, "winter", - "day", - "R_EH", - 2025 + "night", + "T_GSL", + 2020 ], [ - "R2-R1", - 2020, + "R1-R2", + 2030, "fall", - "day", + "night", "E_TRANS", 2015 ], [ - "R1", - 2020, - "summer", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", + "R2", 2025, - "fall", + "spring", "day", - "E_BATT", - 2025 + "R_NGH", + 2020 ], [ - "R2", + "R1-R2", 2025, "summer", "night", - "T_EV", - 2025 + "E_TRANS", + 2015 ], [ - "R2", + "R1", 2020, "spring", "day", - "E_NUCLEAR", + "E_NGCC", 2020 ], [ "R1", - 2025, - "spring", + 2020, + "fall", "night", - "E_BATT", + "S_OILREF", 2020 ], [ - "R2", - 2030, - "fall", + "R1", + 2025, + "summer", "day", - "T_GSL", + "T_DSL", 2020 ], [ - "R2-R1", + "R2", 2030, "winter", "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_BATT", + "R_NGH", 2025 ], [ "R2", - 2020, + 2030, "spring", - "night", - "E_NUCLEAR", - 2020 + "day", + "R_NGH", + 2030 ], [ "R2", 2030, - "spring", + "winter", "day", - "E_NGCC", + "S_OILREF", 2020 ], [ "R2", - 2030, - "spring", + 2025, + "summer", "day", - "T_BLND", + "T_DSL", 2020 ], [ "R2", - 2020, - "summer", - "night", - "R_EH", - 2020 + 2025, + "winter", + "day", + "E_NUCLEAR", + 2015 ], [ "R1", - 2025, + 2030, "spring", "day", - "R_NGH", - 2025 + "E_SOLPV", + 2020 ], [ "R1", 2030, - "summer", + "spring", "day", - "S_OILREF", + "T_GSL", 2020 ], [ @@ -29580,237 +29532,277 @@ 2025, "spring", "day", - "R_EH", - 2020 + "R_NGH", + 2025 ], [ - "R2", - 2025, + "R1", + 2030, "winter", + "day", + "T_DSL", + 2030 + ], + [ + "R1", + 2030, + "spring", "night", "T_GSL", - 2020 + 2025 ], [ "R2", - 2020, - "fall", + 2025, + "summer", "day", "E_SOLPV", 2020 ], [ "R1", - 2030, + 2025, "winter", "day", "T_GSL", - 2030 + 2020 ], [ "R2", - 2025, - "fall", - "day", - "E_NGCC", - 2020 + 2030, + "spring", + "night", + "T_GSL", + 2025 ], [ "R2", 2025, "fall", - "day", - "T_BLND", + "night", + "T_DSL", 2020 ], [ "R2", - 2020, + 2030, "fall", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2030, + "winter", "day", - "E_BATT", + "T_BLND", 2020 ], [ "R2", 2030, - "spring", + "summer", "night", "E_SOLPV", 2020 ], [ - "R2", - 2020, - "winter", + "R1", + 2025, + "spring", "night", - "T_DSL", + "E_SOLPV", 2020 ], [ "R2", 2030, + "summer", + "night", + "T_GSL", + 2020 + ], + [ + "R1", + 2025, "spring", "night", - "E_BATT", + "T_GSL", 2020 ], [ "R2", 2025, + "spring", + "night", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2025, "summer", "day", - "T_DSL", + "E_SOLPV", 2025 ], [ "R1", - 2030, - "winter", - "night", - "T_BLND", + 2020, + "spring", + "day", + "R_EH", 2020 ], [ - "R1", + "R2", 2025, "winter", - "night", - "E_BATT", + "day", + "T_EV", 2020 ], [ - "R2", - 2020, + "R1", + 2025, "fall", "night", - "E_SOLPV", + "E_NGCC", 2020 ], [ - "R2", + "R1", 2030, - "fall", + "spring", "night", - "R_EH", - 2020 + "E_SOLPV", + 2030 ], [ - "R2", + "R1", 2030, "fall", "night", "R_NGH", - 2025 + 2020 ], [ - "R2", - 2025, - "fall", - "night", - "E_NGCC", + "R1", + 2030, + "winter", + "day", + "E_NUCLEAR", 2020 ], [ "R2", - 2025, - "fall", + 2030, + "spring", "night", - "T_BLND", - 2020 + "E_SOLPV", + 2030 ], [ "R1", 2030, - "winter", + "fall", "night", - "T_GSL", + "E_NUCLEAR", 2030 ], [ - "R2", - 2020, - "fall", - "night", - "E_BATT", + "R1", + 2030, + "winter", + "day", + "T_EV", 2020 ], [ - "R2", + "R1", 2025, - "summer", + "spring", "day", + "R_EH", + 2025 + ], + [ + "R1", + 2030, + "fall", + "night", "T_EV", - 2020 + 2030 ], [ "R2", 2030, - "spring", - "day", - "R_EH", + "fall", + "night", + "T_EV", 2030 ], [ - "R2-R1", - 2030, + "R2", + 2025, "spring", "day", - "E_TRANS", - 2015 + "R_EH", + 2025 ], [ "R2", 2020, - "winter", - "night", - "E_NUCLEAR", + "summer", + "day", + "T_BLND", 2020 ], [ - "R2", + "R1", 2025, "summer", "day", - "E_NUCLEAR", + "T_GSL", 2025 ], [ "R1", - 2025, + 2030, "fall", - "day", - "E_SOLPV", - 2020 + "night", + "R_EH", + 2030 ], [ - "R1", - 2025, - "fall", + "R2", + 2030, + "winter", "day", - "E_BATT", + "R_NGH", 2020 ], [ - "R1", - 2025, - "winter", + "R2", + 2030, + "spring", "day", - "R_EH", - 2020 + "R_NGH", + 2025 ], [ - "R1", + "R2", 2025, "winter", "day", - "R_NGH", + "T_DSL", 2025 ], [ "R2", - 2020, - "fall", + 2030, + "spring", "day", "S_OILREF", 2020 @@ -29819,412 +29811,372 @@ "R2", 2025, "summer", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2020, - "spring", "day", - "E_NUCLEAR", - 2015 + "T_GSL", + 2025 ], [ "R2", 2030, - "spring", + "fall", "night", "R_EH", 2030 ], [ "R2", - 2030, + 2020, "winter", "day", - "T_GSL", - 2030 + "R_NGH", + 2020 ], [ "R2", 2020, - "summer", + "spring", "day", - "R_NGH", + "S_OILREF", 2020 ], [ "R1", 2025, - "fall", - "night", - "E_SOLPV", + "spring", + "day", + "R_NGH", 2020 ], [ - "R2", + "R1", 2030, "winter", - "night", - "T_BLND", - 2020 + "day", + "T_DSL", + 2025 ], [ - "R2", + "R1", 2030, - "summer", + "spring", "night", "T_GSL", - 2030 + 2020 ], [ - "R1", + "R2", 2030, "spring", - "day", + "night", "T_GSL", - 2030 + 2020 ], [ "R1", - 2025, - "fall", - "night", - "E_BATT", + 2020, + "summer", + "day", + "S_OILREF", 2020 ], [ "R2", - 2020, + 2025, "fall", "night", - "S_OILREF", - 2020 + "T_GSL", + 2025 ], [ - "R2", + "R1-R2", 2020, - "spring", + "fall", "night", - "E_NUCLEAR", + "E_TRANS", 2015 ], [ "R2", - 2020, - "summer", + 2030, + "fall", "night", - "R_NGH", + "E_NUCLEAR", 2020 ], [ "R1", 2025, - "spring", + "summer", "day", - "R_NGH", + "E_SOLPV", 2020 ], [ - "R2", + "R1", 2030, - "winter", - "day", - "R_EH", + "spring", + "night", + "E_SOLPV", + 2025 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_NUCLEAR", 2030 ], [ "R1", 2020, - "fall", + "winter", "day", - "T_GSL", + "T_BLND", 2020 ], [ - "R2", - 2025, + "R1", + 2030, "winter", "day", "E_NUCLEAR", - 2020 + 2015 ], [ "R1", 2030, - "winter", - "day", - "T_GSL", + "fall", + "night", + "E_NUCLEAR", 2025 ], [ - "R1", + "R2", 2030, "spring", "night", - "T_GSL", - 2030 + "E_SOLPV", + 2025 ], [ "R1", - 2025, + 2030, + "summer", + "night", + "T_EV", + 2030 + ], + [ + "R1-R2", + 2030, "summer", "day", - "E_BATT", - 2025 + "E_TRANS", + 2015 ], [ - "R2-R1", - 2025, + "R1", + 2030, "fall", "night", - "E_TRANS", - 2015 + "T_EV", + 2025 ], [ "R1", 2025, - "fall", + "spring", "day", - "S_OILREF", + "R_EH", 2020 ], [ "R2", - 2020, - "summer", + 2025, + "spring", "day", - "T_GSL", + "R_EH", 2020 ], [ - "R1", - 2025, - "winter", - "day", + "R2", + 2030, + "fall", + "night", "T_EV", 2025 ], [ "R2-R1", - 2020, + 2025, "fall", - "night", + "day", "E_TRANS", 2015 ], [ - "R2", - 2025, + "R1", + 2030, "summer", - "day", - "T_DSL", - 2020 + "night", + "E_NGCC", + 2025 ], [ - "R2", - 2020, - "winter", - "day", - "E_NUCLEAR", - 2015 + "R1", + 2030, + "summer", + "night", + "R_EH", + 2030 ], [ "R2", 2030, - "winter", - "night", + "spring", + "day", "R_EH", 2030 ], [ "R1", 2020, - "fall", - "night", - "T_GSL", + "spring", + "day", + "E_NUCLEAR", 2020 ], [ "R1", - 2020, - "winter", - "night", - "E_BATT", + 2025, + "summer", + "day", + "T_GSL", 2020 ], [ "R1", 2030, - "winter", + "fall", "night", - "T_GSL", + "R_EH", 2025 ], [ "R2", - 2030, - "fall", - "night", - "R_NGH", + 2025, + "winter", + "day", + "T_DSL", 2020 ], [ - "R2-R1", + "R2", 2030, - "winter", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", - 2020, - "spring", - "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "R_EH", - 2025 + "spring", + "day", + "R_NGH", + 2020 ], [ "R2", 2025, - "spring", + "summer", "day", - "E_NGCC", - 2025 + "T_GSL", + 2020 ], [ "R2", 2030, "spring", "day", - "R_NGH", - 2030 - ], - [ - "R2", - 2020, - "winter", - "night", "E_NUCLEAR", - 2015 + 2030 ], [ "R2", - 2025, + 2030, "fall", - "day", + "night", "R_EH", 2025 ], [ "R2", 2030, - "summer", - "day", + "winter", + "night", "T_GSL", - 2025 + 2020 ], [ "R1", - 2025, - "winter", + 2030, + "summer", "day", - "R_NGH", + "T_BLND", 2020 ], [ "R1", - 2025, + 2030, "winter", - "night", - "R_EH", - 2025 - ], - [ - "R1", - 2020, - "fall", - "night", - "R_EH", - 2020 + "day", + "T_GSL", + 2030 ], [ "R1", 2030, - "spring", - "night", - "R_NGH", - 2025 + "winter", + "day", + "T_DSL", + 2020 ], [ "R2", 2030, - "winter", + "summer", "day", - "T_GSL", - 2025 + "T_BLND", + 2020 ], [ - "R2", + "R1", 2025, "spring", - "night", - "E_BATT", + "day", + "E_NUCLEAR", 2025 ], [ "R2", - 2025, - "winter", - "night", - "T_DSL", - 2025 + 2020, + "fall", + "day", + "E_NGCC", + 2020 ], [ "R2", 2025, - "fall", - "night", - "R_EH", - 2025 - ], - [ - "R1", - 2030, "spring", "day", - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "T_GSL", + "E_NUCLEAR", 2025 ], [ "R1", - 2030, - "winter", - "night", + 2020, + "summer", + "day", "R_NGH", 2020 ], [ - "R1", + "R2", 2025, "spring", "day", @@ -30232,50 +30184,42 @@ 2025 ], [ - "R1", + "R2", 2030, - "spring", + "fall", "night", - "T_DSL", - 2030 + "E_NUCLEAR", + 2015 ], [ "R2", 2030, - "winter", + "spring", "day", - "R_EH", + "E_NGCC", 2025 ], [ "R2", - 2030, - "winter", - "day", - "R_NGH", - 2030 + 2025, + "fall", + "night", + "S_OILREF", + 2020 ], [ - "R2", + "R2-R1", 2025, - "winter", - "day", - "E_NUCLEAR", + "spring", + "night", + "E_TRANS", 2015 ], [ - "R2", + "R2-R1", 2030, - "fall", + "summer", "night", - "T_DSL", - 2030 - ], - [ - "R1-R2", - 2030, - "fall", - "day", "E_TRANS", 2015 ], @@ -30284,139 +30228,115 @@ 2030, "spring", "night", - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "T_GSL", + "E_SOLPV", 2020 ], [ - "R1", + "R2", 2025, - "summer", + "spring", "day", - "E_BATT", + "E_NGCC", 2020 ], [ - "R2", + "R1", 2030, - "fall", - "day", + "summer", + "night", "E_NUCLEAR", - 2030 + 2025 ], [ - "R1", - 2025, - "winter", - "day", - "T_EV", + "R2", + 2030, + "spring", + "night", + "E_SOLPV", 2020 ], [ "R1", - 2025, - "spring", + 2030, + "fall", "night", - "T_EV", - 2025 + "E_NUCLEAR", + 2020 ], [ "R2", 2025, "summer", "night", - "E_NGCC", - 2025 + "E_SOLPV", + 2020 ], [ - "R2", + "R1", 2030, - "fall", + "summer", "night", "T_EV", 2025 ], [ - "R2", + "R1", 2030, - "winter", + "fall", "night", - "R_EH", - 2025 + "T_EV", + 2020 ], [ - "R2", - 2030, - "winter", + "R1", + 2020, + "fall", "night", "R_NGH", - 2030 + 2020 ], [ - "R1-R2", + "R2", 2030, "fall", "night", - "E_TRANS", - 2015 + "T_EV", + 2020 ], [ "R1", 2030, - "winter", + "summer", "night", - "T_GSL", + "E_NGCC", 2020 ], - [ - "R2", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2030 - ], [ "R2", 2020, - "spring", + "winter", "day", - "E_SOLPV", + "T_BLND", 2020 ], [ "R1", - 2020, - "fall", - "day", - "R_NGH", - 2020 - ], - [ - "R2", 2030, - "spring", - "day", + "summer", + "night", "R_EH", - 2020 + 2025 ], [ - "R2", - 2025, - "spring", - "day", - "E_NGCC", + "R1", + 2020, + "summer", + "night", + "E_SOLPV", 2020 ], [ - "R2", + "R1", 2025, "spring", "day", @@ -30428,199 +30348,183 @@ 2030, "spring", "day", - "R_NGH", + "R_EH", 2025 ], [ - "R2", + "R1", 2020, - "spring", - "day", - "E_BATT", + "fall", + "night", + "E_NUCLEAR", 2020 ], [ - "R1", - 2030, - "fall", + "R2", + 2025, + "winter", "day", - "E_NGCC", - 2030 + "E_SOLPV", + 2025 ], [ - "R2", - 2025, + "R1", + 2030, "fall", - "day", + "night", "R_EH", 2020 ], [ "R2", 2025, - "fall", - "day", - "R_NGH", - 2025 - ], - [ - "R2-R1", - 2020, "winter", "day", - "E_TRANS", - 2015 + "T_GSL", + 2025 ], [ "R2", - 2030, - "summer", + 2025, + "spring", "day", - "T_GSL", + "T_BLND", 2020 ], [ "R2", 2030, - "winter", + "spring", "day", - "T_EV", - 2030 + "E_NUCLEAR", + 2025 ], [ - "R1", + "R2", 2030, - "spring", + "fall", "night", - "R_NGH", + "R_EH", 2020 ], [ "R1", - 2020, + 2030, "winter", - "night", - "E_SOLPV", + "day", + "T_GSL", + 2025 + ], + [ + "R1", + 2025, + "spring", + "day", + "E_NUCLEAR", 2020 ], [ "R1", - 2020, - "fall", + 2025, + "summer", "night", "R_NGH", - 2020 + 2025 ], [ "R1", 2025, "summer", "night", - "E_SOLPV", - 2025 + "S_OILREF", + 2020 ], [ "R2", 2025, "spring", - "night", - "E_BATT", + "day", + "E_NUCLEAR", 2020 ], [ "R1", - 2025, - "summer", + 2030, + "winter", "night", - "E_BATT", - 2025 + "E_NGCC", + 2030 ], [ "R1", - 2030, + 2020, "fall", "night", - "E_SOLPV", - 2030 + "R_EH", + 2020 ], [ - "R1", + "R2", 2025, "spring", "day", - "T_DSL", - 2025 - ], - [ - "R1", - 2020, - "winter", - "day", "T_EV", 2020 ], [ "R2", - 2025, + 2030, "winter", "night", - "T_DSL", - 2020 + "E_NGCC", + 2030 ], [ "R2", 2025, "fall", "night", - "R_EH", + "R_NGH", 2020 ], [ "R2", - 2025, - "winter", + 2030, + "spring", "day", - "E_SOLPV", - 2025 + "E_NGCC", + 2020 ], [ "R2", - 2030, + 2025, "fall", "day", - "T_DSL", + "E_NGCC", 2025 ], [ "R2", 2030, - "summer", - "night", - "T_GSL", - 2020 + "spring", + "day", + "T_EV", + 2030 ], [ "R1", 2030, - "spring", + "winter", "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "R_NGH", - 2025 + "E_SOLPV", + 2030 ], [ - "R2", - 2020, + "R1", + 2030, "summer", "night", - "T_EV", + "E_NUCLEAR", 2020 ], [ @@ -30629,22 +30533,6 @@ "spring", "day", "T_EV", - 2020 - ], - [ - "R2", - 2020, - "spring", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "T_GSL", 2025 ], [ @@ -30658,190 +30546,150 @@ [ "R1", 2030, - "spring", + "summer", "night", - "T_DSL", - 2025 + "T_EV", + 2020 ], [ "R2", - 2030, + 2020, "winter", - "day", - "R_EH", + "night", + "E_NGCC", 2020 ], [ - "R2", - 2030, + "R2-R1", + 2025, + "winter", + "night", + "E_TRANS", + 2015 + ], + [ + "R1-R2", + 2025, "winter", "day", - "R_NGH", - 2025 + "E_TRANS", + 2015 ], [ "R1", 2025, "spring", "day", - "E_NUCLEAR", + "T_DSL", 2025 ], [ - "R2", + "R1", 2025, - "spring", - "night", - "E_SOLPV", + "fall", + "day", + "R_NGH", 2025 ], [ "R2", - 2030, - "fall", - "night", + 2025, + "spring", + "day", "T_DSL", 2025 ], [ "R1", 2030, - "spring", + "winter", "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_SOLPV", + "R_EH", 2030 ], [ "R2", 2020, - "winter", + "spring", "day", - "E_SOLPV", + "R_NGH", 2020 ], [ - "R2", + "R1", 2030, - "fall", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "spring", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2025, "summer", "night", - "E_NGCC", + "R_EH", 2020 ], [ - "R1", + "R2", 2020, - "winter", + "fall", "night", - "S_OILREF", + "R_EH", 2020 ], [ "R2", 2030, - "fall", - "night", - "T_EV", + "spring", + "day", + "R_EH", 2020 ], [ - "R2-R1", - 2030, - "summer", - "day", - "E_TRANS", + "R1", + 2020, + "fall", + "night", + "E_NUCLEAR", 2015 ], [ "R2", 2025, - "summer", - "night", - "T_BLND", + "winter", + "day", + "E_SOLPV", 2020 ], [ "R2", - 2030, + 2025, "winter", - "night", - "R_EH", + "day", + "T_GSL", 2020 ], [ - "R2", + "R1", 2030, - "winter", + "fall", "night", - "R_NGH", - 2025 - ], - [ - "R2-R1", - 2020, - "spring", - "day", - "E_TRANS", - 2015 + "T_DSL", + 2030 ], [ "R2", 2030, "spring", "day", - "T_EV", - 2030 + "E_NUCLEAR", + 2020 ], [ "R2", 2030, "fall", "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "winter", - "day", "T_DSL", 2030 ], - [ - "R2", - 2030, - "spring", - "day", - "R_NGH", - 2020 - ], [ "R1", - 2025, + 2020, "summer", "day", "T_BLND", @@ -30849,303 +30697,303 @@ ], [ "R2", - 2025, + 2020, "winter", - "night", + "day", "E_NUCLEAR", - 2025 + 2015 ], [ "R1", - 2030, - "fall", - "day", - "E_NGCC", - 2025 - ], - [ - "R2", 2025, - "fall", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "T_EV", - 2025 - ], - [ - "R2", - 2020, - "winter", + "spring", "day", - "S_OILREF", - 2020 + "E_NUCLEAR", + 2015 ], [ - "R2", + "R1", 2030, - "spring", + "fall", "night", - "T_EV", + "T_GSL", 2030 ], [ "R1", - 2025, + 2030, "winter", "day", - "E_NUCLEAR", - 2025 + "T_GSL", + 2020 ], [ "R1", - 2025, - "summer", + 2030, + "fall", "night", - "E_SOLPV", + "T_BLND", 2020 ], [ - "R2", - 2020, + "R1", + 2025, "summer", "night", - "T_DSL", + "R_NGH", 2020 ], [ - "R1", + "R2", 2030, - "spring", + "fall", "night", - "E_NUCLEAR", + "E_SOLPV", 2030 ], [ - "R1", + "R2", 2025, "spring", "day", - "T_DSL", - 2020 + "E_NUCLEAR", + 2015 ], [ "R1", 2030, - "fall", + "winter", "night", - "E_SOLPV", + "E_NGCC", 2025 ], [ "R1", - 2025, + 2020, "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R2-R1", - 2025, - "winter", "day", - "E_TRANS", - 2015 + "E_NUCLEAR", + 2020 ], [ - "R1", - 2025, + "R2", + 2030, "winter", - "day", - "T_DSL", + "night", + "E_NGCC", 2025 ], - [ - "R2", - 2020, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], [ "R2", 2025, "fall", - "night", - "R_NGH", + "day", + "E_NGCC", 2020 ], [ "R2", - 2025, + 2030, "winter", "day", - "E_SOLPV", + "T_EV", 2020 ], [ "R2", 2030, - "fall", + "spring", "day", - "T_DSL", - 2020 + "T_EV", + 2025 ], [ "R1", - 2025, + 2030, "winter", - "night", - "E_NGCC", + "day", + "E_SOLPV", 2025 ], [ "R1", 2030, - "spring", + "summer", "night", - "T_DSL", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2025, + "spring", + "day", + "T_EV", 2020 ], [ "R2", 2020, - "summer", + "fall", "night", - "E_NUCLEAR", + "E_NGCC", 2020 ], [ "R2-R1", - 2025, - "winter", + 2020, + "summer", "night", "E_TRANS", 2015 ], [ - "R2", + "R1", 2025, "spring", - "night", - "E_SOLPV", + "day", + "T_DSL", 2020 ], [ "R2", 2030, - "fall", - "night", - "T_DSL", + "winter", + "day", + "R_EH", 2020 ], [ "R2", 2025, - "summer", + "spring", "day", - "T_GSL", - 2025 + "T_DSL", + 2020 ], [ - "R2", + "R1", 2030, "winter", - "day", - "R_NGH", - 2020 + "night", + "R_EH", + 2025 ], [ - "R2", + "R1", 2030, "fall", "day", - "E_SOLPV", - 2025 + "R_NGH", + 2030 ], [ "R2", 2030, "fall", "day", - "E_NUCLEAR", - 2020 + "R_NGH", + 2030 + ], + [ + "R1", + 2030, + "fall", + "night", + "T_DSL", + 2025 ], [ "R2", 2030, "spring", "day", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "fall", + "night", "T_DSL", - 2030 + 2025 ], [ "R2-R1", 2020, - "winter", + "spring", "night", "E_TRANS", 2015 ], [ - "R1", - 2020, - "summer", + "R2", + 2025, + "fall", "night", - "T_GSL", + "T_BLND", 2020 ], [ - "R2", + "R1", 2030, - "winter", + "fall", "night", - "T_EV", - 2030 + "T_GSL", + 2025 ], [ "R1", 2025, - "summer", + "winter", "night", "S_OILREF", 2020 ], [ - "R1", + "R2", 2030, "fall", - "day", - "E_BATT", - 2030 + "night", + "E_SOLPV", + 2025 ], [ - "R2", - 2025, - "summer", + "R1", + 2030, + "winter", "night", - "T_GSL", - 2025 + "E_NGCC", + 2020 ], [ - "R2", + "R1", + 2020, + "summer", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", 2030, - "spring", + "winter", + "night", + "E_NUCLEAR", + 2030 + ], + [ + "R1", + 2020, + "winter", "day", - "T_EV", - 2025 + "E_SOLPV", + 2020 ], [ "R2", - 2030, + 2020, "fall", "night", "E_NUCLEAR", @@ -31153,154 +31001,162 @@ ], [ "R2", - 2025, + 2030, "winter", - "day", - "S_OILREF", + "night", + "E_NGCC", 2020 ], [ - "R1-R2", + "R2", 2030, - "spring", + "winter", "day", - "E_TRANS", + "E_NUCLEAR", 2015 ], [ "R2", 2025, - "winter", + "fall", "night", - "E_SOLPV", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2025, + "summer", + "night", + "E_NGCC", 2025 ], [ "R2", 2030, - "winter", + "spring", "day", - "T_DSL", - 2025 + "T_EV", + 2020 ], [ "R1", 2030, "winter", - "night", - "T_DSL", - 2030 + "day", + "E_SOLPV", + 2020 ], [ - "R2", + "R1", 2030, - "summer", + "fall", "night", - "E_NUCLEAR", - 2025 + "E_SOLPV", + 2030 ], [ "R1", - 2030, - "fall", + 2020, + "spring", "day", - "E_SOLPV", + "S_OILREF", 2020 ], [ "R2", - 2030, + 2020, "spring", "day", - "E_NUCLEAR", - 2030 + "T_BLND", + 2020 ], [ - "R2", + "R1", 2025, - "winter", - "night", - "E_NUCLEAR", - 2020 + "fall", + "day", + "R_EH", + 2025 ], [ - "R2-R1", + "R1", 2025, "spring", "day", - "E_TRANS", - 2015 + "T_GSL", + 2025 ], [ - "R1", + "R2", 2030, - "fall", - "night", - "E_BATT", + "winter", + "day", + "T_DSL", 2030 ], [ "R1", - 2025, - "winter", - "night", + 2020, + "summer", + "day", "T_EV", + 2020 + ], + [ + "R2", + 2025, + "spring", + "day", + "T_GSL", 2025 ], [ "R1", 2020, - "fall", - "night", - "T_EV", + "summer", + "day", + "T_DSL", 2020 ], [ - "R2", + "R1", 2030, - "spring", - "night", - "T_EV", - 2025 + "summer", + "day", + "T_GSL", + 2020 ], [ "R2", 2030, "winter", "day", - "T_EV", - 2020 + "E_SOLPV", + 2030 ], [ "R2", - 2025, - "winter", + 2020, + "spring", "day", - "E_BATT", - 2025 + "E_NUCLEAR", + 2020 ], [ - "R2-R1", + "R1", 2030, "fall", "day", - "E_TRANS", - 2015 + "R_NGH", + 2025 ], [ "R2", - 2025, - "spring", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, + 2030, "winter", "day", - "E_NUCLEAR", + "T_BLND", 2020 ], [ @@ -31308,59 +31164,75 @@ 2030, "summer", "day", - "E_BATT", - 2030 + "T_GSL", + 2020 ], [ - "R1-R2", - 2020, + "R2", + 2030, "fall", "day", - "E_TRANS", - 2015 + "R_NGH", + 2025 ], [ "R1", 2030, - "spring", + "fall", "night", - "E_NUCLEAR", - 2025 + "T_DSL", + 2020 ], [ "R2", - 2025, - "summer", + 2030, + "fall", "night", - "R_EH", - 2025 + "T_GSL", + 2030 + ], + [ + "R2", + 2030, + "fall", + "night", + "T_DSL", + 2020 ], [ "R1", - 2025, - "spring", + 2030, + "fall", "night", - "E_NGCC", - 2025 + "T_GSL", + 2020 ], [ - "R2", + "R1", 2025, "fall", "night", - "T_EV", + "R_NGH", 2025 ], [ "R1", - 2030, - "winter", + 2020, + "fall", "night", - "E_NUCLEAR", - 2030 + "T_EV", + 2020 ], [ "R1", + 2025, + "fall", + "night", + "S_OILREF", + 2020 + ], + [ + "R2", 2030, "fall", "night", @@ -31369,104 +31241,128 @@ ], [ "R1", - 2025, + 2030, + "fall", + "day", + "E_NGCC", + 2030 + ], + [ + "R2-R1", + 2030, "winter", "day", + "E_TRANS", + 2015 + ], + [ + "R1", + 2020, + "fall", + "night", "T_DSL", 2020 ], [ "R2", - 2020, + 2030, + "fall", + "day", + "E_NGCC", + 2030 + ], + [ + "R2", + 2030, "summer", "day", - "E_NUCLEAR", - 2015 + "E_SOLPV", + 2025 ], [ "R2-R1", - 2025, - "spring", + 2020, + "winter", "night", "E_TRANS", 2015 ], [ "R2", + 2025, + "fall", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R1", 2030, "summer", "night", - "E_BATT", + "E_SOLPV", 2030 ], [ "R1", 2025, - "summer", + "fall", "day", - "R_EH", + "E_NGCC", 2025 ], [ "R2", - 2025, + 2020, "spring", - "day", - "R_NGH", - 2025 + "night", + "E_NGCC", + 2020 ], [ "R1", 2030, "fall", - "day", - "R_EH", - 2030 - ], - [ - "R1", - 2025, - "winter", "night", - "E_NGCC", - 2020 + "E_SOLPV", + 2025 ], [ - "R1-R2", - 2030, - "winter", + "R1", + 2020, + "spring", "day", - "E_TRANS", - 2015 + "R_NGH", + 2020 ], [ - "R2", - 2030, - "winter", + "R1", + 2025, + "summer", "night", - "T_DSL", - 2030 + "E_NUCLEAR", + 2025 ], [ - "R2", - 2020, + "R1", + 2025, "summer", "night", - "E_NUCLEAR", - 2015 + "T_EV", + 2025 ], [ "R1", - 2030, + 2025, "fall", "day", - "S_OILREF", + "R_EH", 2020 ], [ - "R2", + "R1", 2025, - "summer", + "spring", "day", "T_GSL", 2020 @@ -31474,991 +31370,183 @@ [ "R2", 2030, - "fall", + "winter", "day", - "E_SOLPV", - 2020 + "T_DSL", + 2025 ], [ "R2", 2030, - "winter", + "spring", "day", - "E_NUCLEAR", + "T_DSL", 2030 ], [ "R2", - 2030, - "fall", + 2025, + "spring", "day", - "E_NUCLEAR", - 2015 + "T_GSL", + 2020 ], [ "R2", - 2030, + 2025, "spring", "day", - "T_DSL", - 2025 + "S_OILREF", + 2020 ], [ - "R1-R2", + "R2", 2030, - "summer", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", - 2020, - "spring", + "winter", "day", "E_SOLPV", - 2020 + 2025 ], [ - "R1", + "R2", 2020, "spring", "day", - "E_BATT", - 2020 + "E_NUCLEAR", + 2015 ], [ "R2", 2030, - "winter", - "night", - "T_EV", - 2025 + "spring", + "day", + "E_SOLPV", + 2030 ], [ "R2", - 2025, + 2030, "spring", "day", - "R_EH", - 2025 + "T_GSL", + 2030 ], [ - "R2", + "R1", 2025, - "fall", - "day", - "T_DSL", + "summer", + "night", + "R_EH", 2025 ], [ "R1", - 2020, - "winter", + 2030, + "fall", "day", - "E_NGCC", + "R_NGH", 2020 ], [ "R1", - 2020, + 2025, "winter", + "night", + "R_NGH", + 2025 + ], + [ + "R1", + 2030, + "fall", "day", - "T_BLND", - 2020 + "E_NUCLEAR", + 2030 ], [ "R2", 2030, - "spring", + "fall", "day", - "T_EV", - 2020 + "E_NUCLEAR", + 2030 ], [ "R2", 2025, - "summer", + "winter", "night", - "T_GSL", - 2020 + "R_NGH", + 2025 ], [ - "R1", + "R2", 2030, - "summer", - "day", - "E_NGCC", - 2030 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2020, - "fall", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_SOLPV", - 2020 + "fall", + "night", + "T_GSL", + 2025 ], [ "R2", 2030, - "winter", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2020, "fall", "day", "T_EV", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_SOLPV", 2030 ], - [ - "R2", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "winter", - "night", - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "R_EH", - 2025 - ], - [ - "R2", - 2025, - "fall", - "night", - "T_DSL", - 2025 - ], [ "R1", 2025, - "winter", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, "spring", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NGCC", - 2030 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "summer", "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "summer", - "night", - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", "E_SOLPV", - 2030 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1-R2", - 2020, - "summer", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2020, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "R_NGH", 2025 ], - [ - "R2", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "summer", - "day", - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_SOLPV", - 2030 - ], - [ - "R2", - 2025, - "winter", - "night", - "S_OILREF", - 2020 - ], - [ - "R1-R2", - 2020, - "summer", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "winter", - "night", - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NGCC", - 2030 - ], - [ - "R2", - 2030, - "spring", - "day", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_SOLPV", - 2030 - ], - [ - "R2", - 2030, - "winter", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_SOLPV", - 2030 - ], - [ - "R2", - 2025, - "spring", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R1-R2", - 2025, - "fall", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NGCC", - 2025 - ], - [ - "R1", - 2020, - "fall", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_SOLPV", - 2030 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "summer", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2020, - "fall", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_BATT", - 2030 - ], - [ - "R2", - 2025, - "summer", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "T_EV", - 2025 - ], - [ - "R2", - 2030, - "fall", - "night", - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "fall", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2020, - "fall", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "summer", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_BATT", - 2030 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NGCC", - 2020 - ], - [ - "R1", - 2020, - "winter", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_BATT", - 2030 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "T_DSL", - 2025 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], [ "R1", 2025, "fall", - "night", - "E_NGCC", + "day", + "E_NUCLEAR", 2025 ], [ - "R1", + "R1-R2", 2020, - "winter", + "spring", "day", - "R_EH", - 2020 + "E_TRANS", + 2015 ], [ "R1", - 2020, + 2030, "summer", - "night", - "E_NUCLEAR", - 2015 + "day", + "E_NGCC", + 2030 ], [ - "R2", + "R1", 2025, - "spring", - "day", - "T_EV", + "fall", + "night", + "R_NGH", 2020 ], [ "R1", 2030, "summer", - "day", - "R_EH", - 2030 + "night", + "S_OILREF", + 2020 ], [ "R1", 2025, - "summer", + "fall", "day", "T_EV", 2025 @@ -32468,183 +31556,247 @@ 2030, "fall", "day", - "T_EV", - 2030 + "E_NGCC", + 2025 ], [ "R2", 2030, - "fall", - "night", - "T_GSL", + "summer", + "day", + "E_SOLPV", 2020 ], [ "R2", 2030, - "summer", + "fall", "day", - "E_SOLPV", - 2020 + "E_NGCC", + 2025 ], [ "R2", - 2020, + 2030, "fall", "day", - "T_BLND", - 2020 + "R_EH", + 2030 ], [ "R2", - 2030, + 2020, "spring", "day", - "T_GSL", - 2030 + "T_EV", + 2020 ], [ - "R1", + "R1-R2", 2030, "winter", + "night", + "E_TRANS", + 2015 + ], + [ + "R1", + 2025, + "fall", "day", - "S_OILREF", + "E_NGCC", 2020 ], [ "R1", 2030, - "summer", + "fall", "night", - "R_EH", - 2030 + "E_SOLPV", + 2020 ], [ "R2", - 2030, + 2025, "winter", + "night", + "T_EV", + 2020 + ], + [ + "R1-R2", + 2025, + "summer", "day", - "E_NUCLEAR", + "E_TRANS", 2015 ], [ "R1", - 2030, - "fall", + 2025, + "summer", "night", - "T_EV", - 2030 + "E_NUCLEAR", + 2020 ], [ - "R1", + "R2", 2025, "winter", "night", - "T_BLND", + "R_EH", + 2025 + ], + [ + "R1", + 2025, + "summer", + "night", + "T_EV", 2020 ], [ "R2", 2030, - "spring", - "night", - "E_NGCC", + "winter", + "day", + "T_GSL", + 2030 + ], + [ + "R2", + 2030, + "winter", + "day", + "T_DSL", 2020 ], [ "R2", 2030, "spring", + "day", + "T_DSL", + 2025 + ], + [ + "R1", + 2020, + "fall", "night", - "T_BLND", + "E_SOLPV", 2020 ], [ "R1", - 2030, + 2020, "summer", - "night", - "S_OILREF", + "day", + "T_GSL", 2020 ], [ - "R1", - 2030, - "spring", + "R2", + 2020, + "fall", "day", - "E_SOLPV", + "S_OILREF", 2020 ], [ "R2", 2030, - "summer", - "night", + "winter", + "day", "E_SOLPV", 2020 ], [ "R1", - 2025, + 2030, + "fall", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2030, "spring", - "night", - "R_NGH", + "day", + "T_GSL", 2025 ], + [ + "R2", + 2020, + "winter", + "night", + "S_OILREF", + 2020 + ], [ "R1", 2025, - "spring", + "summer", "night", "R_EH", 2020 ], [ "R1", - 2020, - "fall", - "day", - "E_BATT", + 2025, + "winter", + "night", + "R_NGH", 2020 ], [ "R2", - 2020, + 2030, "fall", - "night", - "E_NGCC", - 2020 + "day", + "E_NUCLEAR", + 2025 ], [ "R2", 2020, - "fall", - "night", - "T_BLND", + "winter", + "day", + "E_SOLPV", 2020 ], [ - "R2", + "R1", 2030, "spring", - "night", - "T_GSL", + "day", + "E_NGCC", 2030 ], [ - "R1", - 2030, + "R2", + 2020, "winter", "day", - "E_BATT", - 2025 + "T_GSL", + 2020 ], [ - "R1", - 2030, + "R2", + 2025, "winter", "night", - "S_OILREF", + "R_NGH", + 2020 + ], + [ + "R2", + 2030, + "fall", + "night", + "T_GSL", 2020 ], [ @@ -32652,39 +31804,39 @@ 2025, "spring", "day", - "T_GSL", - 2025 + "E_SOLPV", + 2020 ], [ - "R2", - 2025, - "summer", + "R2-R1", + 2030, + "spring", "night", - "T_DSL", - 2025 + "E_TRANS", + 2015 ], [ - "R2", + "R1", 2025, - "spring", - "night", - "T_EV", - 2025 + "fall", + "day", + "E_NUCLEAR", + 2020 ], [ "R1", 2030, - "spring", + "summer", "night", - "E_SOLPV", + "R_NGH", 2020 ], [ "R1", 2030, - "winter", - "night", - "E_BATT", + "summer", + "day", + "E_NGCC", 2025 ], [ @@ -32692,109 +31844,101 @@ 2025, "fall", "day", - "T_BLND", + "T_EV", 2020 ], [ - "R2", + "R1", 2030, - "summer", + "fall", "day", - "S_OILREF", + "E_NGCC", 2020 ], [ "R1", - 2025, - "spring", + 2020, + "fall", "night", "T_GSL", - 2025 + 2020 ], [ "R1", 2025, - "summer", - "day", - "T_DSL", + "winter", + "night", + "E_NGCC", 2025 ], [ "R2", - 2025, - "spring", - "day", - "T_DSL", - 2020 - ], - [ - "R1", 2030, - "spring", + "fall", "day", - "E_BATT", + "E_NGCC", 2020 ], - [ - "R2-R1", - 2030, - "spring", - "night", - "E_TRANS", - 2015 - ], [ "R1", 2030, "fall", "day", - "T_DSL", + "T_EV", 2030 ], [ "R2", 2025, - "summer", + "winter", "night", - "E_NUCLEAR", + "E_NGCC", 2025 ], [ "R1", - 2025, + 2020, "fall", - "night", + "day", "E_NGCC", 2020 ], [ "R1", 2025, - "fall", + "summer", "night", - "T_BLND", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2025, + "winter", + "night", + "R_EH", 2020 ], [ "R1", - 2020, - "winter", + 2030, + "fall", "day", - "R_NGH", - 2020 + "R_EH", + 2030 ], [ "R2", - 2030, - "summer", - "night", - "S_OILREF", - 2020 + 2025, + "fall", + "day", + "R_NGH", + 2025 ], [ - "R1", - 2030, - "spring", + "R2", + 2025, + "fall", "day", "S_OILREF", 2020 @@ -32802,57 +31946,65 @@ [ "R1", 2025, - "summer", + "fall", "day", - "T_EV", - 2020 + "T_DSL", + 2025 ], [ - "R1", + "R2", 2030, - "summer", + "winter", "day", - "R_EH", + "T_GSL", 2025 ], [ - "R1", + "R2-R1", 2030, - "summer", - "day", - "R_NGH", - 2030 + "winter", + "night", + "E_TRANS", + 2015 ], [ - "R1", + "R2", 2030, - "fall", + "spring", "day", - "T_EV", - 2025 + "T_DSL", + 2020 ], [ "R2", - 2030, - "winter", - "night", - "T_GSL", - 2030 + 2020, + "spring", + "day", + "T_DSL", + 2020 + ], + [ + "R2", + 2020, + "fall", + "day", + "R_NGH", + 2020 ], [ "R1", 2025, "winter", - "day", - "T_GSL", + "night", + "R_EH", 2025 ], [ "R1", - 2020, - "spring", + 2030, + "fall", "day", - "R_EH", + "E_NUCLEAR", 2020 ], [ @@ -32861,70 +32013,94 @@ "spring", "day", "T_GSL", - 2025 + 2020 + ], + [ + "R2", + 2020, + "fall", + "night", + "S_OILREF", + 2020 + ], + [ + "R1-R2", + 2020, + "fall", + "day", + "E_TRANS", + 2015 ], [ "R1", 2025, - "summer", + "winter", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2030, + "spring", "day", "E_NGCC", 2025 ], [ - "R1", + "R2", 2030, "summer", - "night", - "R_EH", - 2025 + "day", + "E_NGCC", + 2030 ], [ - "R1", + "R2", 2025, - "spring", + "winter", "night", - "R_NGH", - 2020 + "E_NUCLEAR", + 2025 ], [ "R1", - 2020, + 2025, "winter", - "night", + "day", "E_NGCC", - 2020 + 2025 ], [ "R1", - 2020, - "winter", - "night", - "T_BLND", - 2020 + 2025, + "fall", + "day", + "E_NUCLEAR", + 2015 ], [ "R2", - 2030, - "spring", + 2025, + "winter", "night", - "T_GSL", + "T_EV", 2025 ], [ "R1", - 2025, + 2020, "summer", "night", - "E_NGCC", - 2025 + "S_OILREF", + 2020 ], [ "R1", 2030, - "winter", + "summer", "day", - "E_BATT", + "E_NGCC", 2020 ], [ @@ -32935,188 +32111,204 @@ "E_SOLPV", 2020 ], + [ + "R2", + 2025, + "fall", + "night", + "E_SOLPV", + 2025 + ], [ "R1", 2025, - "winter", + "spring", "night", - "T_GSL", + "E_NGCC", 2025 ], [ "R1", - 2020, - "summer", - "day", - "E_BATT", + 2025, + "winter", + "night", + "E_NGCC", 2020 ], [ "R1", + 2030, + "fall", + "day", + "T_EV", + 2025 + ], + [ + "R2", 2025, - "fall", + "winter", "night", - "S_OILREF", + "E_NGCC", 2020 ], [ "R2", 2020, - "summer", - "night", - "T_GSL", + "fall", + "day", + "R_EH", 2020 ], [ - "R2", + "R1", 2025, - "spring", - "day", + "fall", + "night", "E_NUCLEAR", 2025 ], [ "R1", - 2025, - "spring", + 2030, + "fall", "day", - "T_GSL", - 2020 + "R_EH", + 2025 ], [ - "R2", + "R1", 2025, - "summer", + "fall", "night", - "T_DSL", - 2020 + "T_EV", + 2025 ], [ "R2", 2025, - "spring", - "night", - "T_EV", + "fall", + "day", + "R_NGH", 2020 ], [ - "R2", + "R1", 2025, - "summer", + "fall", "day", - "E_NUCLEAR", + "T_DSL", 2020 ], [ "R1", 2020, - "summer", - "night", - "E_SOLPV", + "spring", + "day", + "T_BLND", 2020 ], [ "R2", - 2020, + 2030, "winter", "day", - "E_NGCC", + "T_GSL", 2020 ], [ "R1", - 2025, - "spring", + 2030, + "winter", "night", - "T_GSL", - 2020 + "R_NGH", + 2030 ], [ - "R2", - 2030, - "spring", + "R1", + 2025, + "fall", "night", "R_EH", 2025 ], [ - "R2", + "R1", 2025, - "spring", + "winter", "night", - "E_NGCC", - 2025 + "R_EH", + 2020 ], [ - "R2", - 2030, - "spring", + "R1", + 2025, + "summer", "night", - "R_NGH", - 2030 + "T_DSL", + 2025 ], [ "R2", 2030, - "fall", - "day", - "E_NGCC", + "winter", + "night", + "R_NGH", 2030 ], [ - "R2", + "R1", 2025, - "summer", + "winter", "night", "E_NUCLEAR", 2020 ], [ "R1", - 2030, - "summer", + 2020, + "spring", "day", - "R_EH", + "T_EV", 2020 ], [ "R1", 2030, - "summer", - "day", - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "fall", + "spring", "day", - "T_EV", + "E_NGCC", 2020 ], [ - "R1", - 2020, - "summer", - "day", - "S_OILREF", + "R2", + 2025, + "winter", + "night", + "E_NUCLEAR", 2020 ], [ "R2", 2030, - "winter", + "summer", "night", - "T_GSL", + "E_NGCC", + 2030 + ], + [ + "R1", + 2025, + "summer", + "night", + "E_SOLPV", 2025 ], [ "R1", 2025, - "fall", - "day", - "R_EH", + "summer", + "night", + "T_GSL", 2025 ], [ @@ -33124,92 +32316,108 @@ 2025, "winter", "day", - "T_GSL", + "E_NGCC", 2020 ], [ - "R2", + "R1", 2030, "spring", - "day", + "night", + "S_OILREF", + 2020 + ], + [ + "R2", + 2025, + "fall", + "night", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2025, + "fall", + "night", "T_GSL", 2020 ], [ "R1", 2025, - "summer", - "day", + "spring", + "night", "E_NGCC", 2020 ], [ "R1", 2030, - "summer", - "night", - "R_EH", + "fall", + "day", + "T_EV", 2020 ], [ "R1", + 2030, + "spring", + "day", + "R_EH", + 2030 + ], + [ + "R2", 2020, "summer", "night", - "S_OILREF", + "E_NGCC", 2020 ], [ "R1", 2025, - "fall", + "winter", "night", - "R_EH", + "T_EV", 2025 ], [ - "R1", + "R2-R1", 2025, - "winter", - "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2030, - "spring", + "summer", "night", - "T_GSL", - 2020 + "E_TRANS", + 2015 ], [ "R1", 2025, - "summer", + "fall", "night", - "E_NGCC", + "E_NUCLEAR", 2020 ], [ - "R2", + "R1", 2020, - "spring", + "fall", "day", - "E_NGCC", + "E_NUCLEAR", 2020 ], [ "R2", - 2020, - "spring", - "day", - "T_BLND", - 2020 + 2025, + "winter", + "night", + "T_DSL", + 2025 ], [ - "R2", - 2020, + "R1", + 2030, "fall", "day", "R_EH", @@ -33217,167 +32425,175 @@ ], [ "R2", - 2025, - "summer", + 2020, + "fall", "day", - "E_NUCLEAR", - 2015 + "T_BLND", + 2020 ], [ "R1", - 2020, - "spring", - "day", + 2025, + "fall", + "night", "T_EV", 2020 ], [ "R1", 2025, - "winter", + "fall", + "day", + "T_GSL", + 2025 + ], + [ + "R2", + 2030, + "summer", "night", "R_EH", - 2020 + 2030 ], [ - "R1", - 2025, + "R2", + 2020, "winter", "night", "R_NGH", - 2025 + 2020 ], [ "R2", - 2030, + 2020, "spring", "night", - "R_EH", + "S_OILREF", 2020 ], [ "R2", - 2030, - "winter", + 2020, + "spring", "day", - "T_GSL", + "E_SOLPV", 2020 ], [ "R2", - 2025, + 2020, "spring", - "night", - "E_NGCC", + "day", + "T_GSL", 2020 ], [ - "R2", - 2030, - "spring", - "night", + "R1", + 2025, + "summer", + "day", "R_NGH", 2025 ], [ "R2", - 2020, - "spring", + 2030, + "fall", "night", - "E_SOLPV", + "T_BLND", 2020 ], [ "R2", - 2030, + 2020, "fall", "day", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2020, + "spring", + "night", "E_NGCC", - 2025 + 2020 ], [ "R1", 2030, - "fall", + "spring", "night", - "E_NGCC", + "R_NGH", 2030 ], [ - "R2", + "R1", 2020, "spring", - "night", - "E_BATT", - 2020 + "day", + "E_NUCLEAR", + 2015 ], [ - "R2", - 2020, + "R1", + 2025, "fall", "night", "R_EH", 2020 ], [ - "R2", + "R1", 2025, "summer", "night", - "E_NUCLEAR", - 2015 + "T_DSL", + 2020 ], [ "R1", 2030, - "summer", - "day", - "T_EV", - 2030 - ], - [ - "R2", - 2025, "winter", - "day", - "E_NGCC", + "night", + "R_NGH", 2025 ], [ - "R1", + "R2", 2030, - "summer", - "day", + "winter", + "night", "R_NGH", - 2020 + 2025 ], [ "R1", - 2030, + 2025, "winter", - "day", - "T_EV", - 2030 + "night", + "E_NUCLEAR", + 2015 ], [ "R2", 2030, "winter", "night", - "T_GSL", + "S_OILREF", 2020 ], [ "R1", - 2025, - "spring", + 2030, + "winter", "night", - "T_DSL", - 2025 + "S_OILREF", + 2020 ], [ "R1", - 2025, + 2020, "fall", "day", "R_EH", @@ -33385,68 +32601,44 @@ ], [ "R2", - 2020, - "winter", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "R_NGH", - 2025 - ], - [ - "R1", 2030, "summer", "night", - "T_EV", - 2030 + "E_NGCC", + 2025 ], [ - "R2-R1", + "R1", 2025, "summer", - "day", - "E_TRANS", - 2015 + "night", + "E_SOLPV", + 2020 ], [ - "R2", + "R1", 2025, - "fall", + "summer", "night", "T_GSL", - 2025 + 2020 ], [ - "R1", + "R2", 2025, - "fall", + "spring", "night", - "R_EH", - 2020 + "E_NGCC", + 2025 ], [ "R2", 2020, - "winter", + "fall", "night", - "T_BLND", + "R_NGH", 2020 ], - [ - "R2", - 2025, - "summer", - "day", - "E_SOLPV", - 2025 - ], [ "R1", 2025, @@ -33456,137 +32648,129 @@ 2025 ], [ - "R2", + "R1", 2025, - "summer", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2020, "winter", "night", - "E_SOLPV", + "T_EV", 2020 ], [ - "R2", - 2030, + "R2-R1", + 2025, "fall", "night", - "E_SOLPV", - 2030 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_BATT", - 2025 + "E_TRANS", + 2015 ], [ "R1", 2020, - "summer", - "night", - "E_BATT", + "spring", + "day", + "T_DSL", 2020 ], [ - "R2", - 2020, - "winter", - "day", - "E_BATT", - 2020 + "R1", + 2030, + "spring", + "night", + "R_EH", + 2030 ], [ - "R2", + "R1", 2020, - "fall", - "day", - "R_NGH", + "winter", + "night", + "E_NGCC", 2020 ], [ "R2", 2030, - "fall", - "day", - "E_BATT", + "spring", + "night", + "R_EH", 2030 ], [ "R1", + 2025, + "fall", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R1-R2", 2020, - "winter", + "summer", "day", - "T_DSL", - 2020 + "E_TRANS", + 2015 ], [ - "R2-R1", + "R1", 2020, - "spring", - "night", - "E_TRANS", + "fall", + "day", + "E_NUCLEAR", 2015 ], [ "R1", 2030, - "summer", + "fall", "day", "T_DSL", 2030 ], [ - "R1-R2", + "R1", 2025, - "winter", - "day", - "E_TRANS", - 2015 + "spring", + "night", + "R_EH", + 2025 ], [ "R1", 2025, - "winter", - "night", - "R_NGH", + "fall", + "day", + "S_OILREF", 2020 ], [ "R2", - 2030, + 2025, "spring", "night", - "R_NGH", - 2020 + "R_EH", + 2025 ], [ "R1", 2025, "summer", - "night", - "T_BLND", + "day", + "R_NGH", 2020 ], [ - "R1", - 2030, + "R2", + 2020, "fall", - "night", - "E_NGCC", - 2025 + "day", + "E_NUCLEAR", + 2015 ], [ - "R2", + "R1", 2020, - "fall", + "summer", "night", "R_NGH", 2020 @@ -33594,73 +32778,57 @@ [ "R1", 2030, - "summer", - "day", - "T_EV", - 2025 - ], - [ - "R2", - 2025, "winter", - "day", - "E_NGCC", + "night", + "R_NGH", 2020 ], [ "R2", 2025, - "winter", + "summer", "day", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "winter", - "night", - "S_OILREF", + "E_NGCC", 2020 ], [ "R1", - 2030, - "summer", + 2025, + "winter", "night", "T_DSL", - 2030 + 2025 ], [ "R1", 2030, - "winter", - "day", - "T_EV", + "spring", + "night", + "R_NGH", 2025 ], [ - "R1", - 2020, + "R2", + 2030, "winter", - "day", - "E_NUCLEAR", + "night", + "R_NGH", 2020 ], [ - "R1", + "R2", 2030, - "summer", - "day", + "winter", + "night", "E_NUCLEAR", 2030 ], [ - "R1", + "R2", 2025, - "spring", + "summer", "night", - "T_DSL", + "S_OILREF", 2020 ], [ @@ -33668,37 +32836,37 @@ 2025, "fall", "day", - "T_GSL", - 2020 + "E_NUCLEAR", + 2025 ], [ "R1", + 2020, + "winter", + "night", + "R_EH", + 2020 + ], + [ + "R2", 2025, "fall", "day", - "R_NGH", - 2020 + "T_EV", + 2025 ], [ - "R1", + "R2", 2030, "summer", "night", - "T_EV", - 2025 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_NUCLEAR", + "E_NGCC", 2020 ], [ - "R2", + "R1", 2025, - "spring", + "fall", "night", "T_BLND", 2020 @@ -33706,89 +32874,97 @@ [ "R2", 2025, - "fall", + "spring", "night", - "T_GSL", + "E_NGCC", 2020 ], [ - "R2", + "R1", 2025, "summer", "day", - "E_SOLPV", - 2020 + "E_NGCC", + 2025 ], [ "R1", - 2025, + 2030, "spring", "night", - "E_NUCLEAR", - 2020 + "E_NGCC", + 2030 ], [ "R2", - 2025, - "summer", + 2020, + "fall", "day", - "E_BATT", + "T_EV", 2020 ], [ "R2", 2030, - "winter", + "spring", "night", - "R_NGH", - 2020 + "E_NGCC", + 2030 ], [ - "R2", - 2030, - "fall", + "R1", + 2025, + "spring", "night", - "E_SOLPV", - 2025 + "E_NUCLEAR", + 2020 ], [ - "R1-R2", + "R2", 2025, - "spring", + "fall", "day", - "E_TRANS", - 2015 + "R_EH", + 2025 ], [ "R2", - 2030, - "spring", - "night", + 2020, + "fall", + "day", "T_DSL", - 2030 + 2020 ], [ "R1", 2030, - "fall", - "day", - "E_NGCC", - 2020 + "spring", + "night", + "R_EH", + 2025 ], [ "R1", - 2030, + 2020, "fall", - "day", + "night", "T_BLND", 2020 ], [ - "R1", - 2025, + "R2", + 2020, "summer", - "day", - "T_GSL", + "night", + "T_EV", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "R_EH", 2025 ], [ @@ -33796,271 +32972,271 @@ 2030, "fall", "day", - "E_BATT", - 2025 + "S_OILREF", + 2020 ], [ "R2", 2020, + "winter", + "night", + "R_EH", + 2020 + ], + [ + "R1", + 2025, "spring", "night", - "S_OILREF", + "R_EH", 2020 ], [ - "R2", - 2030, - "summer", + "R2-R1", + 2020, + "spring", "day", - "E_NGCC", - 2030 + "E_TRANS", + 2015 ], [ "R1", - 2030, - "summer", + 2025, + "fall", "day", - "T_DSL", - 2025 + "R_NGH", + 2020 ], [ - "R1-R2", - 2030, + "R2", + 2025, "spring", "night", - "E_TRANS", - 2015 + "R_EH", + 2020 ], [ - "R1", - 2030, + "R1-R2", + 2025, "fall", - "night", - "E_NGCC", - 2020 + "day", + "E_TRANS", + 2015 ], [ - "R2", + "R1", 2030, - "spring", + "summer", "night", - "E_NUCLEAR", + "T_DSL", 2030 ], [ "R1", - 2030, - "fall", + 2025, + "winter", "night", - "T_BLND", + "T_DSL", 2020 ], [ "R1", - 2030, - "summer", - "day", - "T_EV", - 2020 + 2025, + "fall", + "night", + "T_DSL", + 2025 ], [ "R1", 2025, "summer", - "night", - "T_GSL", + "day", + "E_NUCLEAR", 2025 ], [ "R1", 2030, "spring", - "day", - "E_NGCC", + "night", + "E_NUCLEAR", 2030 ], [ - "R2", - 2030, + "R1", + 2025, "summer", - "night", - "E_NGCC", - 2030 + "day", + "T_EV", + 2025 ], [ - "R2-R1", - 2030, + "R2", + 2025, "summer", - "night", - "E_TRANS", - 2015 + "day", + "E_NUCLEAR", + 2025 ], [ "R2", - 2025, + 2030, "winter", "night", - "E_BATT", + "E_NUCLEAR", 2025 ], [ "R2", - 2020, + 2030, "spring", - "day", - "R_EH", - 2020 + "night", + "E_NUCLEAR", + 2030 ], [ "R2", 2025, - "summer", + "fall", "day", - "S_OILREF", + "E_NUCLEAR", 2020 ], [ - "R1", + "R2", 2020, - "winter", - "day", - "E_NUCLEAR", - 2015 + "fall", + "night", + "T_BLND", + 2020 ], [ - "R1-R2", - 2020, - "fall", + "R2", + 2030, + "spring", "night", - "E_TRANS", - 2015 + "T_EV", + 2030 ], [ "R1", 2030, "summer", - "day", - "E_NUCLEAR", - 2025 + "night", + "T_BLND", + 2020 ], [ "R1", 2025, "fall", - "day", - "T_EV", + "night", + "E_SOLPV", 2025 ], [ "R1", - 2030, - "summer", + 2025, + "fall", "night", + "T_GSL", + 2025 + ], + [ + "R2", + 2025, + "fall", + "day", "T_EV", 2020 ], [ "R1", 2025, - "spring", + "summer", "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "winter", - "night", - "E_BATT", + "E_NGCC", 2020 ], [ "R1", - 2020, - "winter", + 2025, + "spring", "night", - "R_EH", - 2020 + "T_EV", + 2025 ], [ "R1", 2025, "summer", - "night", + "day", "R_EH", 2025 ], [ - "R2", + "R1", 2030, - "fall", + "spring", "night", - "E_BATT", - 2030 + "E_NGCC", + 2025 ], [ - "R1", - 2020, + "R2", + 2025, "spring", - "day", - "E_NGCC", - 2020 + "night", + "T_EV", + 2025 ], [ - "R1", - 2020, - "spring", + "R2", + 2025, + "summer", "day", - "T_BLND", - 2020 + "R_EH", + 2025 ], [ - "R1", + "R2", 2030, - "fall", + "spring", "night", - "R_EH", - 2030 + "E_NGCC", + 2025 ], [ "R1", 2025, - "fall", + "spring", "night", - "T_EV", - 2025 + "E_NUCLEAR", + 2015 ], [ - "R1-R2", + "R1", 2030, "winter", "night", - "E_TRANS", - 2015 + "T_EV", + 2030 ], [ "R2", 2025, - "winter", + "fall", "day", "R_EH", - 2025 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2015 + 2020 ], [ "R2", - 2030, + 2020, "fall", "night", - "E_SOLPV", + "T_EV", 2020 ], [ @@ -34068,111 +33244,103 @@ 2030, "winter", "night", - "E_NUCLEAR", + "T_EV", 2030 ], [ - "R2", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2015 + "R1", + 2020, + "spring", + "day", + "E_SOLPV", + 2020 ], [ "R1", - 2025, - "winter", - "night", - "T_DSL", - 2025 + 2020, + "spring", + "day", + "T_GSL", + 2020 ], [ - "R2", + "R1", 2030, "spring", "night", - "T_DSL", - 2025 + "R_EH", + 2020 ], [ - "R1", - 2020, + "R2", + 2030, "spring", "night", - "E_NGCC", + "R_EH", 2020 ], [ - "R1", - 2020, + "R2", + 2030, "spring", - "night", + "day", "T_BLND", 2020 ], [ "R1", 2030, - "winter", + "fall", "day", - "E_NGCC", + "T_GSL", 2030 ], [ "R2", 2020, - "winter", - "day", - "R_EH", - 2020 - ], - [ - "R1", - 2025, "summer", "day", - "T_GSL", + "S_OILREF", 2020 ], [ "R2", - 2030, - "fall", - "day", - "E_BATT", + 2025, + "winter", + "night", + "S_OILREF", 2020 ], [ "R2", 2030, - "fall", - "day", + "winter", + "night", "R_EH", 2030 ], [ "R2", - 2030, - "summer", + 2025, + "spring", "day", - "E_NGCC", + "E_SOLPV", 2025 ], [ - "R1", - 2030, + "R2", + 2025, "summer", - "day", - "T_DSL", - 2020 + "night", + "R_NGH", + 2025 ], [ - "R2", + "R1", 2020, - "fall", + "summer", "night", - "T_EV", + "R_EH", 2020 ], [ @@ -34180,263 +33348,263 @@ 2030, "winter", "night", - "E_NGCC", - 2030 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2025 + "R_EH", + 2020 ], [ "R2", 2020, "winter", "night", - "R_EH", + "T_BLND", 2020 ], [ - "R2", + "R1", 2030, - "spring", + "summer", "night", - "E_NUCLEAR", + "T_DSL", 2025 ], [ "R1", 2025, + "winter", + "night", + "T_GSL", + 2025 + ], + [ + "R1", + 2030, "fall", "day", - "T_DSL", - 2025 + "S_OILREF", + 2020 ], [ "R1", 2025, - "spring", - "day", - "E_SOLPV", - 2025 + "fall", + "night", + "T_DSL", + 2020 ], [ "R1", 2030, "spring", - "day", - "E_NGCC", + "night", + "E_NUCLEAR", 2025 ], [ - "R2", - 2030, + "R1", + 2025, "summer", - "night", - "E_NGCC", - 2025 + "day", + "E_NUCLEAR", + 2020 ], [ - "R2", + "R1", 2025, - "winter", - "night", - "E_BATT", + "summer", + "day", + "T_EV", 2020 ], [ "R2", 2025, - "spring", + "summer", "day", - "R_NGH", + "E_NUCLEAR", 2020 ], + [ + "R2-R1", + 2020, + "winter", + "day", + "E_TRANS", + 2015 + ], [ "R2", 2030, - "fall", + "winter", "night", - "S_OILREF", + "E_NUCLEAR", 2020 ], [ - "R1", + "R2", 2030, - "summer", - "day", + "spring", + "night", "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "T_EV", - 2020 + 2025 ], [ - "R1", + "R2", 2025, "summer", - "day", - "R_NGH", + "night", + "E_NUCLEAR", 2025 ], [ - "R1", - 2030, + "R2", + 2025, "fall", "day", - "R_NGH", - 2030 + "E_NUCLEAR", + 2015 ], [ "R1", 2025, "fall", "night", - "T_DSL", - 2025 + "E_SOLPV", + 2020 ], [ - "R1", - 2025, + "R1-R2", + 2030, "fall", "day", - "E_NUCLEAR", - 2025 + "E_TRANS", + 2015 ], [ - "R1", + "R2", 2020, "winter", "night", - "R_NGH", + "E_NUCLEAR", 2020 ], [ "R1", 2025, - "summer", + "fall", "night", - "R_EH", + "T_GSL", 2020 ], - [ - "R1", - 2025, - "summer", - "night", - "R_NGH", - 2025 - ], [ "R2", - 2030, - "fall", + 2020, + "winter", "night", - "E_BATT", - 2025 + "T_EV", + 2020 ], [ "R1", 2025, - "fall", + "spring", "night", "T_EV", 2020 ], [ "R1", - 2030, + 2020, "fall", - "night", + "day", + "S_OILREF", + 2020 + ], + [ + "R1", + 2025, + "summer", + "day", "R_EH", - 2025 + 2020 ], [ "R1", 2030, - "fall", + "spring", "night", - "R_NGH", - 2030 + "E_NGCC", + 2020 ], [ - "R2-R1", + "R1", 2030, - "fall", + "winter", "night", - "E_TRANS", - 2015 + "E_NUCLEAR", + 2025 ], [ "R2", - 2025, - "winter", + 2030, + "summer", "day", - "R_EH", - 2020 + "R_NGH", + 2030 ], [ "R2", 2020, "fall", - "day", - "T_DSL", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_NGCC", 2020 ], [ "R2", 2025, - "winter", - "day", - "R_NGH", - 2025 + "summer", + "night", + "E_NGCC", + 2020 ], [ - "R2", + "R1", 2030, "winter", "night", - "E_NUCLEAR", + "T_EV", 2025 ], [ "R1", - 2025, - "winter", + 2030, + "spring", "night", - "T_DSL", - 2020 + "T_EV", + 2030 ], [ - "R1", - 2030, + "R2", + 2020, "fall", "day", "T_GSL", - 2030 + 2020 ], [ "R2", 2030, - "spring", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2025, "winter", - "day", - "E_SOLPV", + "night", + "T_EV", 2025 ], [ @@ -34444,229 +33612,229 @@ 2030, "winter", "day", - "E_NGCC", - 2025 + "R_EH", + 2030 ], [ - "R2", + "R1", 2030, "spring", - "day", - "E_NUCLEAR", + "night", + "T_DSL", + 2030 + ], + [ + "R1", + 2020, + "summer", + "night", + "E_NGCC", 2020 ], [ "R2", 2020, - "winter", + "summer", "day", "R_NGH", 2020 ], [ - "R2", - 2025, + "R1-R2", + 2030, "spring", "night", - "R_EH", - 2020 + "E_TRANS", + 2015 ], [ "R2", - 2020, - "fall", - "night", - "T_DSL", - 2020 + 2025, + "winter", + "day", + "E_NGCC", + 2025 ], [ - "R2", - 2020, - "summer", - "day", - "T_BLND", - 2020 + "R1-R2", + 2025, + "winter", + "night", + "E_TRANS", + 2015 ], [ "R1", - 2020, - "winter", + 2025, + "spring", "night", - "T_GSL", - 2020 + "T_DSL", + 2025 ], [ "R2", 2030, - "fall", - "day", + "winter", + "night", "R_EH", 2025 ], [ "R2", - 2030, - "fall", + 2025, + "spring", "day", - "R_NGH", - 2030 + "E_SOLPV", + 2020 ], [ - "R2", + "R1", 2020, - "fall", - "day", - "E_NUCLEAR", + "spring", + "night", + "S_OILREF", 2020 ], [ "R2", - 2030, + 2025, "summer", - "day", - "E_NGCC", + "night", + "R_NGH", 2020 ], [ - "R2", + "R1", 2030, "summer", "day", - "T_BLND", + "S_OILREF", 2020 ], [ - "R2", + "R1", 2030, "winter", - "day", - "E_BATT", + "night", + "T_DSL", 2030 ], [ - "R2", - 2025, - "spring", + "R1", + 2030, + "summer", "night", - "R_NGH", - 2025 + "T_GSL", + 2030 ], [ "R1", - 2025, - "winter", + 2030, + "summer", "night", - "E_SOLPV", - 2025 + "T_DSL", + 2020 ], [ - "R1", + "R2", 2020, - "winter", + "fall", "night", - "T_EV", + "T_DSL", 2020 ], [ "R1", - 2030, + 2025, "winter", "night", - "E_NGCC", - 2025 + "T_GSL", + 2020 ], [ "R2", - 2025, + 2020, "spring", - "day", - "T_GSL", - 2025 - ], - [ - "R1", - 2025, - "winter", "night", - "E_NUCLEAR", + "R_NGH", 2020 ], [ - "R1", - 2020, - "summer", + "R2", + 2030, + "fall", "day", - "T_EV", + "R_NGH", 2020 ], [ "R2", 2030, - "spring", + "winter", "night", "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "T_DSL", - 2020 + 2015 ], [ "R2", - 2020, + 2025, "summer", "night", - "E_SOLPV", + "E_NUCLEAR", 2020 ], [ "R1", - 2025, - "spring", - "day", - "E_SOLPV", + 2020, + "summer", + "night", + "T_BLND", 2020 ], [ "R1", 2030, - "spring", - "day", - "E_NGCC", + "winter", + "night", + "T_BLND", 2020 ], [ - "R1", - 2030, + "R2", + 2020, "spring", - "day", - "T_BLND", + "night", + "E_NUCLEAR", 2020 ], [ "R2", - 2030, - "summer", + 2020, + "winter", "night", - "E_BATT", - 2020 + "E_NUCLEAR", + 2015 ], [ - "R1", + "R1-R2", 2025, + "spring", + "night", + "E_TRANS", + 2015 + ], + [ + "R1", + 2030, "winter", "day", - "E_BATT", - 2025 + "E_NGCC", + 2030 ], [ - "R2", - 2025, - "fall", + "R1", + 2020, + "summer", "night", "E_NUCLEAR", 2020 @@ -34674,134 +33842,142 @@ [ "R1", 2030, - "spring", + "winter", "night", - "E_BATT", - 2030 + "E_NUCLEAR", + 2020 ], [ - "R1", - 2025, + "R2", + 2030, "summer", "day", "R_NGH", - 2020 + 2025 ], [ "R2", - 2025, + 2030, "winter", "night", - "R_EH", - 2025 + "T_DSL", + 2030 ], [ - "R2", - 2025, - "spring", + "R1", + 2020, + "summer", "night", - "T_GSL", - 2025 + "T_EV", + 2020 ], [ "R1", 2030, - "fall", - "day", - "R_NGH", + "spring", + "night", + "T_EV", 2025 ], [ "R1", - 2025, - "fall", - "day", - "E_NUCLEAR", + 2030, + "winter", + "night", + "T_EV", 2020 ], [ "R2", - 2030, + 2025, "fall", - "night", - "E_BATT", - 2020 + "day", + "T_DSL", + 2025 ], [ "R1", - 2025, + 2030, "summer", "night", - "R_NGH", - 2020 + "E_SOLPV", + 2025 ], [ - "R1", + "R2", 2030, - "fall", + "winter", "night", - "R_EH", + "T_EV", 2020 ], [ "R1", 2030, - "fall", - "night", - "R_NGH", + "winter", + "day", + "R_EH", 2025 ], [ "R2", - 2030, + 2020, "spring", - "day", - "E_SOLPV", - 2030 + "night", + "R_EH", + 2020 ], [ - "R1", + "R2-R1", 2020, "fall", "night", - "S_OILREF", - 2020 + "E_TRANS", + 2015 ], [ "R2", - 2030, - "spring", + 2025, + "fall", "day", - "E_BATT", - 2030 + "T_GSL", + 2025 ], [ "R2", - 2025, + 2020, "winter", "day", - "R_NGH", + "S_OILREF", 2020 ], + [ + "R1", + 2030, + "summer", + "day", + "R_NGH", + 2030 + ], [ "R2", 2020, - "summer", + "winter", "night", - "S_OILREF", + "T_DSL", 2020 ], [ "R2", - 2030, + 2025, "winter", - "night", - "E_NUCLEAR", + "day", + "E_NGCC", 2020 ], [ "R1", - 2025, + 2030, "spring", "day", "S_OILREF", @@ -34809,363 +33985,379 @@ ], [ "R1", - 2030, - "fall", + 2020, + "winter", "day", - "T_GSL", - 2025 + "R_NGH", + 2020 ], [ - "R1", - 2025, + "R2", + 2030, "winter", + "night", + "R_EH", + 2020 + ], + [ + "R2", + 2025, + "summer", + "night", + "R_EH", + 2025 + ], + [ + "R2", + 2020, + "fall", "day", "E_SOLPV", 2020 ], [ "R1", - 2030, + 2025, "winter", "day", - "E_NGCC", + "S_OILREF", 2020 ], [ "R1", - 2030, - "winter", - "day", + 2025, + "summer", + "night", "T_BLND", 2020 ], [ - "R2", + "R1", 2030, - "spring", + "summer", "day", "E_NUCLEAR", - 2015 + 2030 ], [ "R1", - 2020, + 2030, "winter", "night", "T_DSL", - 2020 + 2025 ], [ - "R2", + "R1", 2030, - "spring", - "night", - "E_BATT", - 2030 - ], - [ - "R2", - 2025, - "spring", + "summer", "night", - "R_NGH", - 2020 + "T_GSL", + 2025 ], [ "R2", 2030, - "winter", + "spring", "day", - "E_BATT", + "E_SOLPV", 2025 ], [ - "R2", - 2030, + "R1", + 2025, "fall", "day", - "R_EH", + "T_BLND", 2020 ], [ - "R2", + "R1", 2030, - "fall", - "day", - "R_NGH", - 2025 - ], - [ - "R2", - 2020, - "fall", + "winter", "day", "E_NUCLEAR", - 2015 + 2030 ], [ - "R1", + "R2", 2030, - "summer", + "fall", "night", "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "T_BLND", - 2020 + 2030 ], [ "R1", 2025, "spring", - "day", - "E_BATT", - 2025 + "night", + "S_OILREF", + 2020 ], [ - "R1-R2", + "R2", 2020, - "winter", + "summer", "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_SOLPV", + "E_NGCC", 2020 ], [ - "R1", - 2030, - "winter", + "R2", + 2025, + "spring", "night", - "E_NGCC", + "S_OILREF", 2020 ], [ - "R1", + "R2", 2025, - "winter", + "summer", "night", "E_NUCLEAR", 2015 ], [ "R2", - 2025, - "spring", + 2030, + "fall", "day", - "T_GSL", + "T_EV", + 2025 + ], + [ + "R2", + 2020, + "summer", + "night", + "S_OILREF", 2020 ], [ "R2", - 2030, + 2020, "spring", "night", "E_NUCLEAR", 2015 ], + [ + "R1", + 2030, + "winter", + "day", + "E_NGCC", + 2025 + ], [ "R2", - 2020, - "spring", + 2030, + "summer", "day", - "T_EV", - 2020 + "R_EH", + 2030 ], [ "R2", 2030, "winter", "day", - "E_SOLPV", + "R_NGH", 2030 ], [ - "R2", - 2025, - "fall", + "R1", + 2020, + "summer", "night", "E_NUCLEAR", 2015 ], + [ + "R1", + 2030, + "winter", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "fall", + "day", + "R_EH", + 2025 + ], [ "R2", - 2025, + 2030, "winter", "night", - "R_EH", - 2020 + "T_DSL", + 2025 ], [ "R1", - 2025, - "winter", - "day", - "E_BATT", + 2030, + "spring", + "night", + "T_EV", 2020 ], [ "R2", 2025, - "spring", - "night", + "fall", + "day", "T_DSL", - 2025 - ], - [ - "R1-R2", - 2020, - "winter", - "night", - "E_TRANS", - 2015 + 2020 ], [ "R1", 2030, - "spring", + "summer", "night", - "E_BATT", - 2025 + "E_SOLPV", + 2020 ], [ "R1", 2030, - "winter", + "spring", "day", - "R_EH", + "R_NGH", 2030 ], + [ + "R2", + 2025, + "fall", + "day", + "T_GSL", + 2020 + ], [ "R1", 2030, - "fall", + "summer", "day", "R_NGH", - 2020 + 2025 ], [ "R2", - 2025, - "spring", - "night", - "T_GSL", + 2020, + "summer", + "day", + "E_NUCLEAR", 2020 ], [ - "R1", + "R2-R1", 2025, - "winter", + "spring", "day", - "S_OILREF", - 2020 + "E_TRANS", + 2015 ], [ "R2", - 2030, + 2020, "spring", - "day", - "S_OILREF", + "night", + "T_BLND", 2020 ], [ - "R1", - 2025, + "R2", + 2030, "summer", "night", - "T_EV", - 2025 + "R_NGH", + 2030 ], [ - "R1", + "R2", 2025, - "fall", - "day", - "E_NUCLEAR", - 2015 + "summer", + "night", + "R_EH", + 2020 ], [ - "R2", + "R2-R1", 2030, - "winter", + "fall", "night", - "E_SOLPV", - 2030 + "E_TRANS", + 2015 ], [ - "R2", - 2030, - "winter", + "R1-R2", + 2020, + "spring", "night", - "E_BATT", - 2030 + "E_TRANS", + 2015 ], [ "R1", 2030, "winter", "night", - "R_EH", + "E_SOLPV", 2030 ], [ "R1", 2030, - "fall", - "night", - "R_NGH", - 2020 + "summer", + "day", + "E_NUCLEAR", + 2025 ], [ - "R2", - 2025, + "R1", + 2030, "winter", - "day", - "T_EV", - 2025 + "night", + "T_GSL", + 2030 ], [ "R1", - 2020, - "fall", - "day", - "E_NGCC", + 2030, + "winter", + "night", + "T_DSL", 2020 ], [ "R1", 2020, - "fall", - "day", - "T_BLND", + "summer", + "night", + "T_DSL", 2020 ], [ "R1", - 2025, - "winter", + 2030, + "summer", "night", - "S_OILREF", + "T_GSL", 2020 ], [ "R2", 2030, - "summer", + "winter", "night", - "T_BLND", - 2020 + "E_SOLPV", + 2030 ], [ "R2", @@ -35173,79 +34365,103 @@ "spring", "day", "E_SOLPV", - 2025 + 2020 ], [ "R2", - 2030, - "spring", - "day", - "E_BATT", - 2025 + 2020, + "fall", + "night", + "T_GSL", + 2020 ], [ - "R1", - 2030, - "spring", + "R2", + 2025, + "fall", "day", - "R_NGH", - 2030 + "E_SOLPV", + 2025 ], [ "R2", 2030, - "winter", + "fall", "night", - "E_NUCLEAR", - 2015 + "E_NGCC", + 2025 ], [ "R2", 2020, - "summer", - "day", - "E_BATT", + "spring", + "night", + "T_EV", 2020 ], [ "R2", - 2025, + 2030, "fall", "day", - "E_SOLPV", - 2025 + "E_NUCLEAR", + 2020 ], [ "R1", - 2030, + 2020, "fall", "day", - "T_GSL", + "R_NGH", 2020 ], [ "R2", - 2025, + 2030, "fall", "day", - "E_BATT", - 2025 + "T_EV", + 2020 ], [ - "R2", + "R1", 2020, "winter", "day", - "T_EV", + "E_NGCC", 2020 ], [ - "R1-R2", + "R2", 2020, - "spring", + "summer", + "night", + "R_NGH", + 2020 + ], + [ + "R1", + 2020, + "winter", + "night", + "S_OILREF", + 2020 + ], + [ + "R1", + 2030, + "winter", "day", - "E_TRANS", - 2015 + "E_NGCC", + 2020 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_NGCC", + 2030 ], [ "R2", @@ -35253,100 +34469,108 @@ "summer", "day", "R_EH", - 2030 + 2025 ], [ "R2", 2025, - "winter", + "summer", "night", "T_EV", 2025 ], - [ - "R1", - 2020, - "fall", - "night", - "E_SOLPV", - 2020 - ], [ "R2", 2030, "fall", "day", - "T_EV", - 2030 + "R_EH", + 2020 ], [ - "R1", - 2020, - "fall", + "R2", + 2030, + "winter", "night", - "E_BATT", - 2020 + "T_GSL", + 2030 ], [ "R2", 2030, "winter", - "day", - "E_BATT", + "night", + "T_DSL", 2020 ], [ - "R1", - 2025, + "R1-R2", + 2020, "winter", "night", - "E_BATT", - 2025 + "E_TRANS", + 2015 ], [ - "R2", + "R1", 2030, - "fall", + "spring", "day", "R_NGH", + 2025 + ], + [ + "R1", + 2025, + "summer", + "day", + "S_OILREF", 2020 ], [ - "R2", + "R1", 2020, - "summer", + "spring", "night", - "E_BATT", + "R_NGH", 2020 ], [ - "R2", + "R1", + 2030, + "summer", + "day", + "R_EH", + 2030 + ], + [ + "R1", 2025, - "fall", - "night", - "E_SOLPV", + "winter", + "day", + "R_NGH", 2025 ], [ "R2", - 2020, - "spring", + 2025, + "summer", "day", - "T_DSL", + "S_OILREF", 2020 ], [ "R2", - 2025, - "fall", + 2030, + "spring", "night", - "E_BATT", - 2025 + "R_NGH", + 2030 ], [ "R1", - 2020, - "spring", + 2030, + "summer", "day", "R_NGH", 2020 @@ -35354,130 +34578,122 @@ [ "R2", 2020, - "winter", - "night", - "T_EV", - 2020 - ], - [ - "R1-R2", - 2020, - "spring", - "night", - "E_TRANS", + "summer", + "day", + "E_NUCLEAR", 2015 ], [ "R2", - 2030, - "summer", + 2020, + "winter", "night", - "R_EH", - 2030 + "T_GSL", + 2020 ], [ "R1", - 2030, - "spring", + 2020, + "winter", "day", "R_EH", - 2030 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_BATT", 2020 ], [ "R2", 2030, - "winter", + "summer", "day", - "E_SOLPV", - 2025 + "E_NUCLEAR", + 2030 ], [ "R1", - 2020, + 2025, "spring", "night", "R_NGH", - 2020 + 2025 ], [ - "R1", - 2025, + "R2", + 2030, "summer", "night", - "T_DSL", + "R_NGH", 2025 ], [ - "R2", + "R1", 2025, - "spring", + "winter", "night", - "T_DSL", + "T_BLND", 2020 ], [ - "R1", + "R2", 2030, - "spring", + "summer", "night", - "E_BATT", + "S_OILREF", 2020 ], [ - "R1", + "R2", 2030, - "fall", - "night", - "T_DSL", + "summer", + "day", + "T_EV", 2030 ], [ - "R1", - 2030, + "R2", + 2025, "spring", "night", - "R_EH", - 2030 + "R_NGH", + 2025 ], [ "R1", - 2025, + 2030, "summer", "day", "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "winter", + "night", + "T_GSL", 2025 ], [ "R2", - 2020, - "summer", - "day", - "R_EH", + 2025, + "winter", + "night", + "T_BLND", 2020 ], [ "R1", 2030, "winter", - "day", - "R_EH", + "night", + "E_SOLPV", 2025 ], [ - "R1", + "R2", 2030, "winter", - "day", - "R_NGH", - 2030 + "night", + "E_SOLPV", + 2025 ], [ "R1", @@ -35485,70 +34701,86 @@ "fall", "day", "E_NUCLEAR", - 2030 + 2015 ], [ "R2", 2025, - "winter", + "fall", "day", - "T_DSL", - 2025 + "E_SOLPV", + 2020 ], [ - "R1", + "R2", 2030, - "spring", + "fall", "night", - "S_OILREF", + "E_NGCC", 2020 ], [ - "R1", + "R2-R1", 2025, - "summer", - "night", - "T_EV", - 2020 + "winter", + "day", + "E_TRANS", + 2015 ], [ - "R1", + "R2", 2030, - "summer", - "night", - "R_NGH", - 2030 + "fall", + "day", + "E_NUCLEAR", + 2015 ], [ "R2", 2030, - "winter", - "night", - "E_SOLPV", + "summer", + "day", + "E_NGCC", 2025 ], [ - "R1", - 2030, - "fall", - "night", + "R2", + 2020, + "summer", + "day", "T_EV", - 2025 + 2020 ], [ "R1", - 2030, - "winter", + 2020, + "spring", "night", "R_EH", - 2025 + 2020 ], [ - "R1", + "R2-R1", 2030, + "summer", + "day", + "E_TRANS", + 2015 + ], + [ + "R1", + 2020, "winter", "night", "R_NGH", + 2020 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_NGCC", 2030 ] ], diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index adfe54103..2e935ee92 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -15865,554 +15865,138 @@ ] ], "CapacityConstraint_rpsdtv": [ - [ - "utopia", - 2010, - "summer", - "day", - "E70", - 1980 - ], [ "utopia", 2000, - "winter", + "inter", "night", - "RHO", + "E21", 2000 ], [ "utopia", - 2000, + 1990, "inter", "night", "E70", 1990 ], - [ - "utopia", - 2000, - "inter", - "day", - "TXG", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E51", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "night", - "RL1", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "SRE", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E70", - 1960 - ], [ "utopia", 2010, - "inter", - "night", - "RHE", - 2010 - ], - [ - "utopia", - 2000, "summer", "night", - "E70", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "day", "RHO", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXG", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E70", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "night", - "SRE", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E70", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHE", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "RHO", - 1980 + 2010 ], [ "utopia", 2010, - "inter", - "night", - "E21", - 2000 - ], - [ - "utopia", - 2000, "winter", "day", - "TXD", + "E21", 2000 ], [ "utopia", 2010, - "winter", - "day", - "E70", - 1990 - ], - [ - "utopia", - 1990, "inter", "day", - "E70", - 1960 - ], - [ - "utopia", - 2000, - "winter", - "night", "E21", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E01", 1990 ], [ "utopia", 2010, - "winter", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E70", - 1990 - ], - [ - "utopia", - 2000, "inter", "night", - "RHE", + "RHO", 2000 ], - [ - "utopia", - 1990, - "inter", - "night", - "E70", - 1960 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E21", - 1990 - ], [ "utopia", 1990, "winter", "night", - "RL1", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXE", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E51", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", "E21", 1990 ], [ "utopia", 2010, - "inter", - "day", - "E70", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXG", - 1990 - ], - [ - "utopia", - 2000, - "winter", + "summer", "day", - "E70", - 1990 + "RHE", + 2000 ], [ "utopia", 2010, "summer", - "night", - "E70", - 1980 - ], - [ - "utopia", - 1990, - "winter", "day", - "TXG", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "night", "E21", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHO", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E70", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E51", - 1990 + 2010 ], [ "utopia", 2010, "summer", "day", - "SRE", - 2010 + "TXE", + 2000 ], [ "utopia", 2000, "winter", - "night", - "RHO", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E70", - 1970 - ], - [ - "utopia", - 1990, - "summer", "day", - "TXG", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "SRE", + "TXD", 2000 ], - [ - "utopia", - 1990, - "summer", - "night", - "RL1", - 1980 - ], [ "utopia", 2010, - "inter", - "night", - "RHE", - 2000 - ], - [ - "utopia", - 2000, "summer", "night", - "E70", - 1970 - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXG", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E70", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHE", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E70", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "day", - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E70", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "RL1", - 1980 + "SRE", + 2010 ], [ "utopia", 2010, "summer", - "day", - "E51", + "night", + "E31", 1980 ], [ "utopia", 1990, "inter", - "day", - "RL1", + "night", + "SRE", 1990 ], [ "utopia", - 2000, - "winter", + 1990, + "inter", "night", "TXG", - 1980 + 1990 ], [ "utopia", - 2000, - "winter", - "day", - "E70", + 1990, + "summer", + "night", + "E01", 1980 ], [ "utopia", - 1990, - "winter", + 2000, + "inter", "day", "TXG", 1980 @@ -16421,24 +16005,24 @@ "utopia", 2010, "winter", - "day", - "RL1", + "night", + "RHE", 2010 ], [ "utopia", - 1990, + 2010, "inter", "night", - "RL1", - 1990 + "RHE", + 2000 ], [ "utopia", - 2000, - "winter", - "day", - "RHO", + 1990, + "summer", + "night", + "TXD", 1980 ], [ @@ -16446,37 +16030,21 @@ 2010, "inter", "night", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "RL1", + "E21", 2010 ], [ "utopia", - 1990, + 2010, "summer", - "day", - "TXG", - 1980 - ], - [ - "utopia", - 2000, - "winter", "night", - "RHE", + "E01", 2000 ], [ "utopia", 2010, - "inter", + "winter", "night", "TXE", 2010 @@ -16484,81 +16052,65 @@ [ "utopia", 2010, - "summer", - "day", - "E21", - 2010 + "inter", + "night", + "TXE", + 2000 ], [ "utopia", 2000, "summer", "day", - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E31", + "E01", 1990 ], [ "utopia", - 1990, + 2000, "summer", "night", - "TXG", + "E31", 1980 ], [ "utopia", - 2010, + 1990, "summer", "night", - "RL1", - 2010 + "RHO", + 1990 ], [ "utopia", 1990, "winter", "day", - "RHE", - 1990 + "E70", + 1980 ], [ "utopia", - 2000, + 1990, "inter", "night", - "TXE", - 2000 + "E01", + 1970 ], [ "utopia", - 1990, - "inter", + 2000, + "summer", "day", - "E31", - 1990 + "TXD", + 1980 ], [ "utopia", 2010, "summer", - "day", - "TXG", + "night", + "E70", 2010 ], [ @@ -16566,31 +16118,15 @@ 2000, "summer", "day", - "RL1", + "E70", 2000 ], - [ - "utopia", - 1990, - "summer", - "day", - "RHE", - 1990 - ], [ "utopia", 1990, "inter", "night", - "TXD", - 1970 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E31", + "RL1", 1990 ], [ @@ -16598,184 +16134,184 @@ 2000, "summer", "night", - "RL1", + "RHE", 2000 ], [ "utopia", - 1990, + 2000, "summer", "night", - "RHE", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXD", - 2010 + "TXE", + 2000 ], [ "utopia", 2000, - "summer", + "inter", "day", - "TXG", - 2000 + "E70", + 1980 ], [ "utopia", 1990, - "inter", + "winter", "night", - "E51", + "TXD", 1990 ], [ "utopia", - 2010, + 2000, "inter", - "day", - "TXD", - 2000 + "night", + "E21", + 1990 ], [ "utopia", 1990, "inter", - "day", - "RL1", + "night", + "E70", 1980 ], [ "utopia", 2000, - "winter", + "summer", "day", - "E70", - 1970 + "SRE", + 2000 ], [ "utopia", - 1990, - "winter", - "day", - "TXG", - 1970 + 2010, + "summer", + "night", + "RHO", + 2000 ], [ "utopia", 2010, "winter", "day", - "TXG", - 2010 + "E21", + 1990 ], [ "utopia", 2000, - "inter", - "night", - "TXD", + "winter", + "day", + "E01", 2000 ], [ "utopia", 2010, - "inter", - "night", - "E01", + "summer", + "day", + "RHE", 1990 ], [ "utopia", 2010, - "inter", + "summer", "day", - "TXE", + "E21", 2000 ], [ "utopia", - 2000, + 1990, "inter", "night", - "E01", - 1990 + "RHO", + 1970 ], [ "utopia", - 1990, + 2010, "summer", - "day", + "night", "TXG", - 1970 + 2010 + ], + [ + "utopia", + 1990, + "inter", + "day", + "TXD", + 1990 ], [ "utopia", 2000, "winter", - "night", - "RHE", + "day", + "TXD", 1990 ], [ "utopia", 2010, - "inter", + "summer", "night", - "TXE", + "SRE", 2000 ], [ "utopia", - 1990, - "winter", + 2000, + "summer", "night", - "E31", - 1980 + "RHO", + 2000 ], [ "utopia", - 2000, - "summer", - "day", - "E21", - 2000 + 1990, + "inter", + "night", + "TXG", + 1980 ], [ "utopia", 1990, "summer", - "day", + "night", "E01", - 1990 + 1970 ], [ "utopia", - 2000, + 2010, "inter", "night", - "TXE", + "RHE", 1990 ], [ "utopia", - 2000, - "inter", + 1990, + "winter", "day", "RL1", - 2000 + 1980 ], [ "utopia", 1990, "summer", "night", - "E31", - 1980 + "TXD", + 1970 ], [ "utopia", @@ -16788,305 +16324,265 @@ [ "utopia", 2010, - "inter", + "summer", "night", - "RHO", + "E01", 1990 ], [ "utopia", - 1990, - "inter", + 2000, + "winter", "day", - "E51", + "E31", 1980 ], [ "utopia", - 1990, + 2000, "summer", "day", - "TXE", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXD", - 2000 + "E01", + 1980 ], [ "utopia", 2010, "winter", "night", - "E51", + "E31", 2010 ], - [ - "utopia", - 2000, - "summer", - "day", - "TXG", - 1990 - ], [ "utopia", 2010, "summer", - "day", - "E31", + "night", + "RL1", 2010 ], [ "utopia", 1990, - "inter", + "summer", "night", - "E51", + "RHO", 1980 ], [ "utopia", - 2010, + 2000, "summer", - "night", - "E31", - 2010 + "day", + "RL1", + 2000 ], [ "utopia", 1990, "winter", "day", - "E01", - 1990 + "E70", + 1970 ], [ "utopia", 1990, - "inter", + "summer", "day", - "SRE", + "E21", 1990 ], [ "utopia", 2010, - "summer", + "winter", "day", - "RHE", + "E70", 2010 ], [ "utopia", - 2000, - "inter", - "day", - "TXD", - 1990 - ], - [ - "utopia", - 2010, + 1990, "inter", - "day", + "night", "E01", - 1980 + 1960 ], [ "utopia", - 2010, + 2000, "inter", - "day", - "E51", - 2010 + "night", + "TXD", + 1990 ], [ "utopia", 1990, - "winter", + "summer", "night", - "E01", + "SRE", 1990 ], [ "utopia", 2000, "summer", - "night", - "E31", - 2000 + "day", + "E70", + 1990 ], [ "utopia", - 2010, + 1990, "inter", "night", - "E70", - 2000 + "RL1", + 1980 ], [ "utopia", 2000, - "inter", + "summer", "night", - "TXD", + "RHE", 1990 ], [ "utopia", - 2010, - "inter", + 1990, + "summer", "night", - "E01", - 1980 + "TXG", + 1990 ], [ "utopia", 2000, "summer", - "day", - "RHE", + "night", + "E21", 2000 ], [ "utopia", 2010, - "inter", - "night", - "E51", + "winter", + "day", + "RL1", 2010 ], [ "utopia", 2000, - "inter", - "day", - "E51", - 2000 + "summer", + "night", + "TXE", + 1990 ], [ "utopia", 2000, "inter", - "night", - "E01", - 1980 + "day", + "E70", + 1970 ], [ "utopia", 1990, - "summer", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2010, "winter", - "day", - "E31", - 2010 + "night", + "TXD", + 1980 ], [ "utopia", 1990, "inter", - "day", - "E01", - 1990 + "night", + "E70", + 1970 ], [ "utopia", 2000, - "inter", - "night", - "E51", - 2000 + "summer", + "day", + "SRE", + 1990 ], [ "utopia", - 2010, - "winter", + 1990, + "summer", "night", - "E31", - 2010 + "E21", + 1990 ], [ "utopia", - 1990, + 2000, "summer", "day", - "E01", - 1980 + "TXG", + 1990 ], [ "utopia", - 1990, - "winter", + 2010, + "summer", "night", "RHO", 1990 ], [ "utopia", - 1990, - "summer", - "night", - "E70", + 2000, + "winter", + "day", + "E01", 1990 ], [ "utopia", 2010, - "inter", + "winter", "day", - "E31", + "SRE", 2010 ], [ "utopia", - 2000, - "inter", + 2010, + "summer", "night", - "RHO", - 1980 + "E21", + 2010 ], [ "utopia", - 2000, + 2010, "winter", - "night", - "TXD", - 2000 + "day", + "TXG", + 2010 ], [ "utopia", 1990, - "summer", - "night", - "RHO", - 1990 - ], - [ - "utopia", - 2000, "winter", - "night", - "E01", + "day", + "TXD", 1990 ], [ "utopia", 2010, - "winter", + "summer", "night", - "E51", + "TXG", 2000 ], [ @@ -17094,15 +16590,23 @@ 1990, "inter", "day", - "RHO", - 1990 + "TXD", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXD", + 1980 ], [ "utopia", - 2010, - "summer", + 2000, + "winter", "day", - "E31", + "RHO", 2000 ], [ @@ -17110,15 +16614,15 @@ 1990, "inter", "night", - "SRE", - 1990 + "TXG", + 1970 ], [ "utopia", 1990, "winter", "day", - "TXD", + "E31", 1990 ], [ @@ -17126,142 +16630,102 @@ 1990, "winter", "night", - "E21", + "E01", 1990 ], - [ - "utopia", - 1990, - "summer", - "day", - "RHO", - 1980 - ], [ "utopia", 2010, - "summer", - "night", - "E31", - 2000 - ], - [ - "utopia", - 1990, "winter", "day", "E01", - 1980 + 1990 ], [ "utopia", 2000, - "summer", + "winter", "day", - "E31", - 1990 + "SRE", + 2000 ], [ "utopia", - 2000, + 2010, "summer", "day", "E01", - 2000 + 2010 ], [ "utopia", 2010, "summer", "night", - "E51", - 2000 + "E01", + 1980 ], [ "utopia", 2000, - "inter", + "summer", "day", - "TXD", - 1980 + "E01", + 1970 ], [ "utopia", 2000, "winter", - "night", - "TXE", - 1990 - ], - [ - "utopia", - 2010, - "inter", "day", - "E51", + "TXG", 2000 ], [ "utopia", - 1990, + 2010, "winter", "night", - "E01", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXD", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", "E31", 2000 ], [ "utopia", - 2000, + 1990, "summer", "night", - "E31", - 1990 + "RHO", + 1970 ], [ "utopia", 1990, "winter", "day", - "TXE", - 1990 + "E70", + 1960 ], [ "utopia", - 2000, + 2010, "summer", - "night", - "E01", + "day", + "TXD", 2000 ], [ "utopia", - 2000, - "inter", + 2010, + "winter", "day", - "E01", - 1970 + "E70", + 2000 ], [ "utopia", 2010, "inter", - "night", + "day", "E70", 1990 ], @@ -17273,165 +16737,141 @@ "TXD", 1980 ], - [ - "utopia", - 2000, - "summer", - "day", - "RHE", - 1990 - ], [ "utopia", 1990, - "summer", - "night", - "TXD", + "inter", + "day", + "E01", 1990 ], [ "utopia", - 1990, + 2000, "winter", "day", - "E70", - 1990 + "E21", + 2000 ], [ "utopia", - 1990, - "winter", - "night", - "TXG", - 1990 + 2000, + "summer", + "day", + "E70", + 1980 ], [ "utopia", - 2000, + 2010, "inter", "day", - "E51", - 1990 + "E31", + 2010 ], [ "utopia", 2000, - "inter", + "winter", "night", - "E01", - 1970 + "E70", + 1980 ], [ "utopia", 1990, "summer", "night", - "E01", + "TXG", 1980 ], [ "utopia", - 2000, + 2010, "inter", "night", - "E70", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E31", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "day", "E01", 2010 ], [ "utopia", 2000, - "inter", + "summer", "night", - "E51", + "E21", 1990 ], [ "utopia", - 1990, + 2000, "winter", - "day", - "RHO", - 1980 + "night", + "E31", + 2000 ], [ "utopia", 1990, - "summer", + "winter", "night", - "TXE", - 1990 + "TXD", + 1970 ], [ "utopia", - 2010, - "winter", + 1990, + "inter", "night", - "E31", - 2000 + "E70", + 1960 ], [ "utopia", 2000, - "summer", + "inter", "day", - "RHO", + "RHE", 2000 ], [ "utopia", - 1990, - "summer", + 2010, + "winter", "day", - "E01", - 1970 + "RHO", + 1990 ], [ "utopia", 2000, "inter", - "day", - "E70", - 1970 + "night", + "SRE", + 2000 ], [ "utopia", - 2000, - "summer", + 2010, + "winter", "night", - "SRE", - 2000 + "TXD", + 2010 ], [ "utopia", - 1990, + 2010, "inter", - "day", - "TXG", - 1990 + "night", + "TXD", + 2000 ], [ "utopia", - 2010, + 2000, "summer", "day", - "E01", - 2010 + "TXG", + 1980 ], [ "utopia", @@ -17444,9 +16884,9 @@ [ "utopia", 2000, - "summer", + "inter", "night", - "RHO", + "TXG", 2000 ], [ @@ -17454,31 +16894,39 @@ 2000, "winter", "day", - "TXD", - 1990 + "E01", + 1980 ], [ "utopia", 1990, "summer", - "night", - "E70", - 1980 + "day", + "E01", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "day", + "SRE", + 2000 ], [ "utopia", 2010, "summer", "night", - "E01", - 2010 + "E21", + 2000 ], [ "utopia", 2010, - "winter", + "inter", "day", - "E51", + "SRE", 1990 ], [ @@ -17486,206 +16934,182 @@ 2010, "winter", "day", - "SRE", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E31", + "TXG", 2000 ], [ "utopia", - 2000, + 1990, "winter", "night", - "TXD", + "SRE", 1990 ], [ "utopia", 1990, - "summer", + "winter", "night", - "RHO", - 1980 + "TXG", + 1990 ], [ "utopia", - 2010, - "summer", - "day", - "TXE", - 2010 + 2000, + "inter", + "night", + "E01", + 1990 ], [ "utopia", - 2000, - "winter", + 1990, + "inter", "day", - "E51", - 2000 + "TXD", + 1970 ], [ "utopia", - 2010, - "winter", + 1990, + "inter", "day", "RHO", - 2010 + 1990 ], [ "utopia", - 2000, - "winter", - "night", - "E01", + 1990, + "summer", + "day", + "TXD", 1980 ], [ "utopia", - 2010, + 2000, "winter", - "night", - "E51", + "day", + "RHO", 1990 ], [ "utopia", - 1990, + 2010, "inter", "day", - "RHO", - 1980 + "TXD", + 2010 ], [ "utopia", 2010, "winter", "night", - "SRE", - 2010 + "E70", + 1980 ], [ "utopia", - 2010, - "summer", + 1990, + "winter", "day", "E31", - 1990 + 1980 ], [ "utopia", 2010, - "summer", - "day", - "E70", + "winter", + "night", + "RHO", 2010 ], [ "utopia", 1990, "winter", - "day", - "TXD", + "night", + "E01", 1980 ], [ "utopia", - 2000, + 2010, "winter", - "night", - "E51", - 2000 + "day", + "E01", + 1980 ], [ "utopia", 2000, - "summer", - "day", - "TXD", + "inter", + "night", + "E70", 2000 ], [ "utopia", - 1990, - "summer", + 2000, + "winter", "day", - "RHO", - 1970 + "SRE", + 1990 ], [ "utopia", 2010, "summer", - "night", - "E31", - 1990 - ], - [ - "utopia", - 1990, - "winter", "day", "E01", - 1970 + 2000 ], [ "utopia", 2000, - "summer", + "winter", "day", - "E31", - 1980 + "TXG", + 1990 ], [ "utopia", 2010, - "summer", - "day", - "RHO", - 2010 + "winter", + "night", + "E31", + 1990 ], [ "utopia", - 2000, + 1990, "summer", "day", - "E01", + "RHO", 1990 ], [ "utopia", - 2010, + 2000, "inter", - "day", - "E70", - 1980 - ], - [ - "utopia", - 2010, - "summer", "night", - "SRE", - 2010 + "RL1", + 2000 ], [ "utopia", - 2010, - "summer", + 1990, + "winter", "night", - "E51", + "E70", 1990 ], [ "utopia", - 1990, + 2010, "winter", - "night", + "day", "E70", 1990 ], @@ -17694,47 +17118,63 @@ 2010, "inter", "day", - "E51", + "E70", + 1980 + ], + [ + "utopia", + 1990, + "winter", + "day", + "RHE", 1990 ], [ "utopia", 2010, - "inter", + "summer", "day", - "SRE", + "E70", 2010 ], [ "utopia", 1990, - "summer", + "inter", "day", - "TXD", + "E01", 1980 ], [ "utopia", - 1990, - "inter", + 2000, + "winter", "day", "E21", 1990 ], + [ + "utopia", + 1990, + "winter", + "day", + "TXE", + 1990 + ], [ "utopia", 2000, - "summer", + "winter", "night", - "E31", - 1980 + "E70", + 1970 ], [ "utopia", 2010, - "summer", + "winter", "night", - "RHO", + "E01", 2010 ], [ @@ -17742,40 +17182,40 @@ 2010, "inter", "night", - "E70", - 1980 + "E01", + 2000 ], [ "utopia", - 2000, + 1990, "summer", "day", - "TXE", - 2000 + "SRE", + 1990 ], [ "utopia", - 2000, - "summer", + 1990, + "winter", "night", - "E51", - 1980 + "RL1", + 1990 ], [ "utopia", - 2010, - "winter", - "day", - "E21", - 2010 + 2000, + "inter", + "night", + "RHO", + 1980 ], [ "utopia", 2000, "winter", "night", - "E70", - 1980 + "E31", + 1990 ], [ "utopia", @@ -17783,166 +17223,174 @@ "summer", "day", "SRE", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXG", - 1980 + 2010 ], [ "utopia", - 1990, + 2010, "summer", - "night", - "TXD", + "day", + "E31", 1980 ], [ "utopia", - 1990, + 2010, "winter", - "day", - "E70", - 1980 + "night", + "TXD", + 2000 ], [ "utopia", 2000, "inter", - "day", - "E51", - 1980 + "night", + "SRE", + 1990 ], [ "utopia", - 1990, + 2010, "summer", "day", - "E51", + "TXG", + 2010 + ], + [ + "utopia", + 1990, + "inter", + "night", + "RHE", 1990 ], [ "utopia", 2000, - "winter", + "inter", "night", - "RHO", - 1980 + "TXG", + 1990 ], [ "utopia", 1990, - "summer", + "winter", "night", - "E01", + "RHO", 1970 ], [ "utopia", - 2000, + 2010, "inter", "night", "E70", - 1970 + 2010 ], [ "utopia", - 1990, + 2000, "inter", "day", - "E70", - 1990 + "E31", + 2000 ], [ "utopia", 1990, - "inter", - "night", - "TXG", - 1990 + "summer", + "day", + "E01", + 1980 ], [ "utopia", 2010, "winter", "day", - "E31", + "SRE", 1990 ], [ "utopia", 2010, - "winter", - "day", + "summer", + "night", + "E21", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "night", "E01", 2000 ], [ "utopia", - 1990, - "winter", - "day", - "RHO", - 1970 + 2000, + "inter", + "night", + "E01", + 1980 ], [ "utopia", 2010, + "inter", + "night", + "SRE", + 2010 + ], + [ + "utopia", + 1990, "winter", "night", - "E31", - 1990 + "TXG", + 1980 ], [ "utopia", - 2000, + 1990, "inter", "day", - "SRE", - 2000 + "RHO", + 1980 ], [ "utopia", - 2010, + 1990, "summer", "day", "TXD", - 2010 + 1970 ], [ "utopia", 2000, - "summer", + "winter", "day", "RHO", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E01", - 1960 + 1980 ], [ "utopia", - 1990, + 2010, "inter", - "day", - "TXG", + "night", + "E31", 1980 ], [ "utopia", 2010, - "summer", + "inter", "night", - "E21", + "TXG", 2010 ], [ @@ -17950,7 +17398,7 @@ 2000, "summer", "night", - "SRE", + "TXD", 1990 ], [ @@ -17959,14 +17407,14 @@ "summer", "day", "E70", - 1970 + 1990 ], [ "utopia", 2010, - "summer", - "day", - "E01", + "winter", + "night", + "RHO", 2000 ], [ @@ -17974,374 +17422,358 @@ 1990, "winter", "night", - "RHO", + "E01", 1970 ], [ "utopia", 1990, - "winter", - "night", - "RHE", + "inter", + "day", + "TXG", 1990 ], [ "utopia", 2000, - "winter", - "day", - "TXD", - 1980 - ], - [ - "utopia", - 1990, - "summer", + "inter", "night", "E70", - 1970 + 1990 ], [ "utopia", - 2000, - "winter", + 2010, + "summer", "day", - "E31", - 2000 + "E01", + 1990 ], [ "utopia", 2000, "winter", "day", - "E01", - 1970 + "TXG", + 1980 ], [ "utopia", 2010, "winter", - "day", - "E51", + "night", + "E31", 1980 ], [ "utopia", 2010, "summer", - "night", - "E70", + "day", + "RL1", 2010 ], [ "utopia", - 2010, - "winter", + 1990, + "summer", "day", - "SRE", - 2000 + "RHO", + 1980 ], [ "utopia", - 2000, + 2010, "winter", "night", - "TXD", - 1980 + "TXG", + 2010 ], [ "utopia", 1990, "summer", "night", - "RHO", - 1970 + "E70", + 1990 ], [ "utopia", - 2010, - "summer", + 1990, + "winter", "night", - "TXG", - 2010 + "E70", + 1980 ], [ "utopia", 2010, - "summer", - "day", - "TXE", - 2000 - ], - [ - "utopia", - 2000, "winter", "day", - "E51", - 1990 + "E70", + 1980 ], [ "utopia", 2010, - "winter", + "summer", "day", "RHO", 2000 ], [ "utopia", - 2000, - "winter", - "night", + 1990, + "inter", + "day", "E01", 1970 ], [ "utopia", - 2010, - "winter", - "night", - "E51", - 1980 + 2000, + "inter", + "day", + "TXD", + 2000 ], [ "utopia", 2010, - "winter", - "night", - "SRE", - 2000 + "inter", + "day", + "RHE", + 2010 ], [ "utopia", - 2010, + 1990, "summer", "day", - "E31", - 1980 + "TXG", + 1990 ], [ "utopia", - 1990, + 2010, + "winter", + "night", + "E01", + 2000 + ], + [ + "utopia", + 2010, "inter", - "day", - "RHE", + "night", + "E01", 1990 ], [ "utopia", 2010, - "summer", + "inter", "day", - "E70", - 2000 + "TXE", + 2010 ], [ "utopia", 2000, "winter", "night", - "E51", - 1990 + "RHE", + 2000 ], [ "utopia", - 2000, - "summer", + 2010, + "inter", "night", - "TXG", - 2000 + "RL1", + 2010 ], [ "utopia", - 2000, + 2010, "summer", "day", - "E70", + "SRE", 2000 ], [ "utopia", - 1990, - "winter", + 2010, + "summer", "day", - "E01", - 1960 + "TXG", + 2000 ], [ "utopia", - 2010, - "winter", + 2000, + "inter", "night", - "E21", - 2010 + "TXG", + 1980 ], [ "utopia", - 1990, + 2000, "inter", - "night", - "RHE", + "day", + "E31", 1990 ], [ "utopia", - 2010, + 1990, "summer", "day", - "RHO", - 2000 + "E01", + 1970 ], [ "utopia", - 2000, - "summer", - "day", - "E01", - 1980 + 2010, + "inter", + "night", + "RHO", + 1990 ], [ "utopia", - 2010, + 2000, "summer", "night", - "E51", - 1980 + "E01", + 1990 ], [ "utopia", 2000, - "inter", - "day", - "TXG", + "winter", + "night", + "TXE", 2000 ], [ "utopia", - 2010, + 1990, "summer", - "night", - "SRE", - 2000 + "day", + "RL1", + 1990 ], [ "utopia", 1990, "winter", "night", - "E70", - 1980 + "TXG", + 1970 ], [ "utopia", 2000, - "summer", + "inter", "night", - "E70", - 2000 + "E01", + 1970 ], [ "utopia", 2010, "inter", - "day", + "night", "SRE", 2000 ], [ "utopia", 1990, - "summer", + "inter", "day", - "TXD", + "RHO", 1970 ], [ "utopia", - 1990, + 2010, "inter", "night", - "RL1", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E21", + "TXG", 2000 ], [ "utopia", 2000, - "winter", + "summer", "night", - "E70", - 1970 + "TXD", + 1980 ], [ "utopia", - 2010, + 1990, "summer", "day", - "SRE", - 1990 + "E70", + 1980 ], [ "utopia", 1990, - "winter", - "night", - "TXG", - 1970 + "inter", + "day", + "E21", + 1990 ], [ "utopia", - 1990, - "winter", - "day", + 2000, + "summer", + "night", "E70", - 1970 + 2000 ], [ "utopia", - 2010, - "winter", - "night", - "TXG", - 2010 + 2000, + "inter", + "day", + "E01", + 2000 ], [ "utopia", 2010, "winter", - "day", - "E70", - 2010 + "night", + "RHO", + 1990 ], [ "utopia", 1990, - "summer", - "day", - "E51", - 1980 + "winter", + "night", + "E01", + 1960 ], [ "utopia", - 1990, - "inter", + 2010, + "winter", "night", - "TXG", - 1980 + "RHE", + 2000 ], [ "utopia", - 1990, + 2000, "inter", - "day", + "night", "E70", 1980 ], @@ -18350,103 +17782,103 @@ 1990, "summer", "night", - "E01", - 1960 + "RL1", + 1990 ], [ "utopia", 2010, "winter", - "day", - "E31", - 1980 + "night", + "E21", + 2010 ], [ "utopia", 2010, - "summer", - "day", + "inter", + "night", "E21", 2000 ], [ "utopia", 2010, - "inter", + "summer", "day", - "RL1", - 2010 + "E01", + 1980 ], [ "utopia", - 1990, - "summer", + 2010, + "winter", "night", - "TXG", - 1970 + "TXE", + 2000 ], [ "utopia", 2000, "summer", - "day", - "RHO", - 1980 + "night", + "SRE", + 2000 ], [ "utopia", 1990, - "inter", + "summer", "day", - "TXG", + "RHO", 1970 ], [ "utopia", - 2010, + 2000, "summer", "night", - "E21", + "TXG", 2000 ], [ "utopia", - 2010, - "inter", + 1990, + "summer", "night", - "RL1", - 2010 + "E70", + 1980 ], [ "utopia", - 1990, + 2010, "summer", "day", - "E70", - 1960 + "RHO", + 1990 ], [ "utopia", 2010, "summer", - "day", - "E01", - 1990 + "night", + "E70", + 2000 ], [ "utopia", 2010, - "inter", + "winter", "day", - "TXG", + "RHE", 2010 ], [ "utopia", - 2000, - "summer", - "night", - "E21", + 2010, + "inter", + "day", + "RHE", 2000 ], [ @@ -18454,37 +17886,53 @@ 2000, "inter", "day", - "E21", - 2000 + "TXD", + 1990 ], [ "utopia", 1990, "summer", + "day", + "TXG", + 1980 + ], + [ + "utopia", + 2010, + "inter", "night", - "E70", - 1960 + "E01", + 1980 ], [ "utopia", 2010, - "summer", + "inter", "day", - "TXG", + "TXE", 2000 ], [ "utopia", 2000, - "inter", + "winter", "night", - "RL1", + "RHE", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "RHO", 2000 ], [ "utopia", 2010, - "winter", + "summer", "day", "SRE", 1990 @@ -18494,8 +17942,8 @@ 2010, "summer", "night", - "E70", - 2000 + "E31", + 2010 ], [ "utopia", @@ -18503,46 +17951,54 @@ "inter", "night", "E31", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E31", 1980 ], [ "utopia", - 2010, + 1990, "summer", - "night", - "TXG", - 2000 + "day", + "E01", + 1960 ], [ "utopia", 2000, - "winter", - "day", - "E51", + "summer", + "night", + "E01", 1980 ], [ "utopia", - 2010, + 2000, "winter", "night", - "SRE", + "TXE", 1990 ], [ "utopia", - 2010, - "winter", + 1990, + "summer", "day", - "RHE", - 2010 + "RL1", + 1980 ], [ "utopia", 2010, "summer", "day", - "E70", + "E21", 1990 ], [ @@ -18550,180 +18006,212 @@ 2000, "summer", "night", - "TXG", + "RL1", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "night", + "SRE", 1990 ], [ "utopia", - 2000, + 2010, "summer", - "day", - "E70", + "night", + "SRE", 1990 ], [ "utopia", - 2010, + 2000, "winter", - "night", - "E21", + "day", + "E70", 2000 ], [ "utopia", - 2010, - "summer", + 2000, + "inter", "day", + "TXE", + 2000 + ], + [ + "utopia", + 2000, + "summer", + "night", "RHO", 1990 ], [ "utopia", 2000, - "inter", - "day", - "TXG", + "summer", + "night", + "E70", 1990 ], [ "utopia", 2000, - "winter", + "inter", "day", - "SRE", - 2000 + "E01", + 1990 ], [ "utopia", - 2010, + 1990, "summer", "night", - "SRE", - 1990 + "E01", + 1960 ], [ "utopia", - 1990, + 2010, "winter", "night", - "E70", - 1970 + "RHE", + 1990 ], [ "utopia", 2010, "winter", - "day", - "TXG", + "night", + "E21", 2000 ], [ "utopia", - 2010, + 1990, "summer", "night", - "RHE", - 2010 + "RL1", + 1980 ], [ "utopia", 2010, - "winter", - "day", + "inter", + "night", "E21", 1990 ], [ "utopia", 1990, - "winter", - "day", - "E70", - 1960 + "inter", + "night", + "TXD", + 1990 ], [ "utopia", - 2010, - "inter", - "day", - "RHE", - 2010 + 2000, + "summer", + "night", + "SRE", + 1990 ], [ "utopia", - 2010, - "winter", + 2000, + "summer", "night", "TXG", - 2000 + 1990 ], [ "utopia", - 2010, - "winter", + 2000, + "summer", "day", - "E70", + "E31", 2000 ], [ "utopia", 1990, - "inter", + "summer", "night", - "TXG", + "E70", 1970 ], [ "utopia", - 2000, + 2010, + "inter", + "day", + "E21", + 2010 + ], + [ + "utopia", + 2010, "summer", "night", - "RHE", - 2000 + "E70", + 1990 ], [ "utopia", 2010, - "summer", + "inter", "day", - "E21", + "RHE", 1990 ], [ "utopia", 2000, "winter", - "day", - "RL1", + "night", + "E21", 2000 ], [ "utopia", 2000, - "summer", + "inter", "day", - "E21", + "RHO", 1990 ], + [ + "utopia", + 2010, + "summer", + "night", + "E31", + 2000 + ], [ "utopia", 1990, "inter", "night", - "E01", - 1990 + "E31", + 1980 ], [ "utopia", - 2010, - "summer", - "night", - "E21", + 1990, + "winter", + "day", + "E01", 1990 ], [ "utopia", - 2010, + 2000, "inter", "day", "TXG", @@ -18734,87 +18222,103 @@ 2000, "summer", "night", - "E21", - 1990 + "E01", + 1970 ], [ "utopia", 2000, "winter", "day", - "TXG", + "RL1", 2000 ], [ "utopia", - 2010, + 1990, "winter", - "night", - "RHE", - 2010 + "day", + "TXD", + 1980 ], [ "utopia", 2000, - "winter", - "night", - "TXG", + "inter", + "day", + "E21", 2000 ], [ "utopia", 2000, - "summer", + "winter", "day", - "TXG", + "E70", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "TXE", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "night", + "RHO", 1980 ], [ "utopia", 2010, - "inter", + "summer", "night", - "E31", + "TXD", 2010 ], [ "utopia", - 2010, - "winter", - "day", - "RHE", - 2000 + 1990, + "inter", + "night", + "E01", + 1990 ], [ "utopia", - 1990, + 2000, "summer", "day", - "RL1", - 1990 + "TXD", + 2000 ], [ "utopia", - 2000, - "summer", + 1990, + "inter", "night", - "TXG", - 1980 + "TXE", + 1990 ], [ "utopia", 2000, - "summer", + "inter", "day", - "E70", + "E01", 1980 ], [ "utopia", 1990, - "inter", + "summer", "night", - "RHO", + "E31", 1990 ], [ @@ -18828,73 +18332,97 @@ [ "utopia", 1990, - "winter", + "inter", "night", "TXD", - 1990 + 1980 ], [ "utopia", 2010, - "summer", + "winter", "day", - "RHE", + "TXD", + 2010 + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXD", 2000 ], [ "utopia", - 2010, + 2000, "summer", "night", - "RHE", - 2000 + "TXG", + 1980 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E70", + 1960 ], [ "utopia", 2000, - "winter", + "summer", "day", - "E21", - 2000 + "E31", + 1990 ], [ "utopia", 2010, - "inter", + "summer", "night", - "E51", - 2000 + "E70", + 1980 ], [ "utopia", 2000, - "inter", - "night", - "E31", - 2000 + "summer", + "day", + "E70", + 1970 ], [ "utopia", - 2000, + 2010, "winter", - "night", - "RL1", + "day", + "E31", + 2010 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E31", 2000 ], [ "utopia", 1990, - "winter", + "summer", "night", - "TXE", - 1990 + "TXG", + 1970 ], [ "utopia", 1990, "inter", - "day", - "TXD", + "night", + "RHO", 1990 ], [ @@ -18902,14 +18430,14 @@ 2000, "inter", "day", - "RHE", - 2000 + "RHO", + 1980 ], [ "utopia", 2000, - "summer", - "night", + "inter", + "day", "RHE", 1990 ], @@ -18918,230 +18446,310 @@ 1990, "inter", "day", + "E70", + 1990 + ], + [ + "utopia", + 1990, + "winter", + "day", "E01", 1980 ], [ "utopia", - 1990, + 2000, "winter", "day", - "RL1", - 1990 + "E01", + 1970 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E01", + 2010 ], [ "utopia", 1990, "inter", - "night", - "TXD", + "day", + "RL1", 1990 ], [ "utopia", - 2010, + 2000, "winter", - "night", + "day", + "E31", + 2000 + ], + [ + "utopia", + 2000, + "summer", + "day", "E01", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "night", + "TXE", 2010 ], [ "utopia", - 1990, - "inter", + 2000, + "winter", "night", "E01", - 1980 + 2000 ], [ "utopia", 1990, - "inter", + "winter", "day", - "TXE", - 1990 + "TXD", + 1970 ], [ "utopia", - 2000, + 1990, "winter", "day", - "TXG", + "RHO", 1990 ], [ "utopia", 1990, - "inter", - "night", - "TXE", + "winter", + "day", + "E70", 1990 ], [ "utopia", 2010, - "winter", - "night", - "RHE", + "inter", + "day", + "TXD", 2000 ], [ "utopia", - 2010, + 2000, "inter", "day", - "E01", - 2010 + "E21", + 1990 ], [ "utopia", - 2010, - "inter", - "night", - "E31", - 2000 + 2000, + "winter", + "day", + "E70", + 1980 ], [ "utopia", - 2010, + 1990, "inter", "night", "E01", - 2010 + 1980 ], [ "utopia", - 2010, - "winter", + 2000, + "summer", "day", - "RHE", + "TXD", 1990 ], [ "utopia", 1990, + "inter", + "day", + "SRE", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E01", + 1970 + ], + [ + "utopia", + 2000, "summer", "day", - "RL1", - 1980 + "RHO", + 2000 + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXD", + 1970 ], [ "utopia", 2010, "winter", "night", - "RHO", + "SRE", 2010 ], [ "utopia", - 1990, - "inter", - "night", - "RHO", - 1980 + 2010, + "winter", + "day", + "TXD", + 2000 ], [ "utopia", - 1990, + 2000, "winter", "night", "TXD", - 1980 + 1990 ], [ "utopia", 2010, + "inter", + "day", + "RHO", + 2010 + ], + [ + "utopia", + 2000, "summer", "day", - "RHE", - 1990 + "E31", + 1980 ], [ "utopia", 2000, "inter", - "day", + "night", "E31", - 1990 + 2000 ], [ "utopia", - 1990, + 2000, "winter", "night", - "E01", - 1970 + "RHO", + 2000 ], [ "utopia", - 2000, + 1990, "summer", "night", - "E01", + "RHE", 1990 ], [ "utopia", 2010, "summer", - "night", - "RHE", - 1990 + "day", + "E70", + 2000 ], [ "utopia", 2010, - "inter", + "winter", "day", - "RHO", - 2010 + "E31", + 2000 ], [ "utopia", - 2000, + 2010, "inter", - "night", + "day", "E31", 1990 ], [ "utopia", 2010, - "inter", + "summer", "night", - "SRE", + "RHE", 2010 ], [ "utopia", 1990, - "inter", + "winter", "night", - "E21", - 1990 + "RL1", + 1980 ], [ "utopia", - 2010, + 2000, + "summer", + "day", + "RHE", + 2000 + ], + [ + "utopia", + 1990, "inter", "night", - "E51", + "RHO", + 1980 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E31", 1990 ], [ "utopia", - 2010, + 2000, "winter", - "day", - "TXD", - 2010 + "night", + "E31", + 1980 ], [ "utopia", 2000, "summer", - "night", + "day", "TXE", 2000 ], @@ -19150,149 +18758,181 @@ 1990, "inter", "day", - "TXD", + "E70", 1980 ], [ "utopia", 2010, - "inter", + "winter", "night", - "RHO", + "E70", 2010 ], [ "utopia", 1990, - "inter", + "winter", "day", "E01", 1970 ], [ "utopia", - 2000, + 2010, "inter", "night", - "E51", - 1980 + "E70", + 2000 ], [ "utopia", 2010, "winter", - "night", - "TXD", + "day", + "E01", 2010 ], + [ + "utopia", + 2010, + "inter", + "day", + "E01", + 2000 + ], [ "utopia", 1990, "winter", "day", "RL1", - 1980 + 1990 + ], + [ + "utopia", + 2010, + "winter", + "day", + "TXE", + 2010 ], [ "utopia", 1990, "inter", - "night", - "TXD", + "day", + "RL1", 1980 ], [ "utopia", 1990, "inter", - "night", - "E70", + "day", + "E31", 1990 ], [ "utopia", - 2010, + 2000, "winter", + "day", + "E31", + 1990 + ], + [ + "utopia", + 2010, + "summer", "night", - "E01", + "TXE", 2000 ], [ "utopia", - 1990, - "inter", + 2000, + "winter", "night", "E01", - 1970 + 1990 ], [ "utopia", - 2010, + 1990, "winter", "day", - "TXE", - 2010 + "RHO", + 1980 ], [ "utopia", 2000, "winter", "day", - "TXG", - 1980 + "E70", + 1970 ], [ "utopia", 2010, - "summer", - "night", - "TXD", + "inter", + "day", + "E70", 2010 ], [ "utopia", - 2000, - "summer", - "night", - "RHO", + 1990, + "winter", + "day", + "SRE", 1990 ], [ "utopia", - 2010, - "winter", + 2000, + "inter", "night", - "TXE", - 2010 + "TXD", + 2000 ], [ "utopia", - 2010, - "inter", + 1990, + "winter", "day", - "TXD", - 2010 + "TXG", + 1990 ], [ "utopia", - 2010, + 2000, "winter", "night", - "RHE", - 1990 + "E70", + 2000 ], [ "utopia", - 2010, + 1990, + "inter", + "day", + "TXG", + 1980 + ], + [ + "utopia", + 2000, "summer", - "night", - "E01", - 2000 + "day", + "RHO", + 1990 ], [ "utopia", - 2010, - "inter", + 1990, + "summer", "day", "E31", 1990 @@ -19300,73 +18940,57 @@ [ "utopia", 2010, - "inter", - "day", - "E01", + "winter", + "night", + "SRE", 2000 ], [ "utopia", 2000, - "summer", + "winter", "night", "TXD", - 2000 + 1980 ], [ "utopia", 2000, "winter", "night", - "E31", + "RL1", 2000 ], [ "utopia", - 2000, - "inter", - "day", - "E01", + 2010, + "winter", + "night", + "TXG", 2000 ], [ "utopia", 2010, "summer", - "night", - "TXE", - 2010 - ], - [ - "utopia", - 1990, - "inter", "day", - "RHO", - 1970 - ], - [ - "utopia", - 2010, - "inter", - "night", "E31", - 1990 + 2010 ], [ "utopia", - 2000, - "winter", + 2010, + "inter", "day", - "RHE", + "RHO", 2000 ], [ "utopia", 2010, - "inter", + "winter", "day", - "TXE", + "RHO", 2010 ], [ @@ -19374,100 +18998,84 @@ 1990, "winter", "day", - "TXD", - 1970 + "E21", + 1990 ], [ "utopia", 2000, "inter", "night", - "E01", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "day", "E31", 1990 ], [ "utopia", - 2010, + 1990, "winter", "night", - "RHO", - 2000 + "E70", + 1970 ], [ "utopia", 2000, "summer", "day", - "TXD", - 1990 + "TXG", + 2000 ], [ "utopia", 1990, - "inter", + "summer", "night", - "RHO", - 1970 + "TXE", + 1990 ], [ "utopia", - 2010, - "summer", + 2000, + "winter", "night", - "E31", - 1980 + "RHO", + 1990 ], [ "utopia", 2010, "summer", "day", - "RL1", - 2010 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E51", + "E70", 1990 ], [ "utopia", 1990, - "winter", - "night", - "TXD", - 1970 + "inter", + "day", + "E01", + 1960 ], [ "utopia", - 2000, + 2010, "inter", "day", - "TXE", - 2000 + "SRE", + 2010 ], [ "utopia", 2010, - "inter", + "winter", "day", - "E51", - 1980 + "E31", + 1990 ], [ "utopia", - 2000, + 2010, "inter", "day", "E31", @@ -19475,67 +19083,67 @@ ], [ "utopia", - 1990, + 2010, "winter", "night", "E01", - 1960 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E51", 1990 ], [ "utopia", - 1990, - "summer", + 2010, + "inter", "day", - "E31", - 1990 + "TXG", + 2010 ], [ "utopia", 2010, "summer", "night", - "RHO", + "RHE", 2000 ], [ "utopia", 2000, "summer", - "night", - "E01", - 1980 + "day", + "RHE", + 1990 ], [ "utopia", 2000, - "inter", - "day", - "E70", + "winter", + "night", + "SRE", 2000 ], + [ + "utopia", + 1990, + "winter", + "night", + "E31", + 1980 + ], [ "utopia", 2000, "summer", - "night", - "E51", + "day", + "E21", 2000 ], [ "utopia", - 2000, - "inter", + 2010, + "winter", "night", - "TXG", - 2000 + "RL1", + 2010 ], [ "utopia", @@ -19547,10 +19155,10 @@ ], [ "utopia", - 2010, - "inter", - "day", - "RHO", + 2000, + "winter", + "night", + "TXG", 2000 ], [ @@ -19558,199 +19166,199 @@ 2010, "inter", "night", - "E51", - 1980 + "E31", + 2010 ], [ "utopia", - 2000, + 1990, "inter", "night", - "E31", - 1980 + "E21", + 1990 ], [ "utopia", 1990, - "summer", - "night", - "TXD", + "inter", + "day", + "E70", 1970 ], [ "utopia", 2010, - "inter", + "winter", "night", - "SRE", + "E70", 2000 ], [ "utopia", - 1990, - "summer", + 2010, + "inter", "night", - "E31", + "E70", 1990 ], [ "utopia", - 2000, - "inter", + 1990, + "winter", "day", - "RHO", - 2000 + "E01", + 1960 ], [ "utopia", - 2000, - "inter", - "night", - "SRE", + 2010, + "winter", + "day", + "E01", 2000 ], [ "utopia", 2010, - "winter", + "inter", "day", - "TXD", - 2000 + "E01", + 1990 ], [ "utopia", - 2000, - "summer", - "night", + 2010, + "winter", + "day", "TXE", - 1990 + 2000 ], [ "utopia", - 1990, + 2010, "inter", "day", - "TXD", - 1970 + "RL1", + 2010 ], [ "utopia", - 1990, - "summer", + 2000, + "winter", "night", - "E51", - 1990 + "E01", + 1980 ], [ "utopia", - 2010, - "inter", - "night", + 1990, + "winter", + "day", "RHO", - 2000 + 1970 ], [ "utopia", - 2010, - "winter", + 1990, + "summer", "day", - "E01", - 1990 + "E70", + 1970 ], [ "utopia", - 1990, - "inter", + 2010, + "summer", "day", - "E01", - 1960 + "TXD", + 2010 ], [ "utopia", - 1990, + 2010, "inter", "day", - "E51", - 1990 + "E70", + 2000 ], [ "utopia", 2000, - "inter", - "night", - "RHO", + "winter", + "day", + "RHE", 2000 ], [ "utopia", - 2010, + 1990, "winter", - "night", - "TXD", - 2000 + "day", + "TXG", + 1980 ], [ "utopia", - 2010, + 2000, "winter", "night", "E70", - 2010 + 1990 ], [ "utopia", 1990, "inter", - "night", - "E70", - 1980 + "day", + "TXG", + 1970 ], [ "utopia", - 2010, + 2000, "winter", - "night", - "E31", - 1980 + "day", + "TXE", + 2000 ], [ "utopia", - 2010, + 2000, "inter", - "day", - "E21", - 2010 + "night", + "E70", + 1970 ], [ "utopia", 2000, - "inter", + "summer", "day", - "SRE", - 1990 + "RHO", + 1980 ], [ "utopia", - 2010, - "summer", - "day", - "TXD", + 2000, + "inter", + "night", + "RHO", 2000 ], [ "utopia", 1990, - "inter", - "night", - "E01", - 1960 + "summer", + "day", + "E31", + 1980 ], [ "utopia", 2010, "winter", "night", - "E01", + "SRE", 1990 ], [ @@ -19758,87 +19366,79 @@ 2010, "winter", "day", - "TXE", + "RHO", 2000 ], [ "utopia", 2010, "summer", - "night", - "TXD", + "day", + "E31", 2000 ], [ "utopia", - 2000, - "summer", - "night", + 2010, + "inter", + "day", "RHO", - 1980 + 1990 ], [ "utopia", 2010, - "winter", + "inter", "night", - "TXE", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E51", + "TXD", 2010 ], [ "utopia", 2000, - "winter", - "day", + "inter", + "night", "E31", - 1990 + 1980 ], [ "utopia", - 2010, - "summer", + 1990, + "winter", "night", - "E01", - 1990 + "E70", + 1960 ], [ "utopia", - 2010, - "inter", + 1990, + "winter", "night", - "TXG", - 2010 + "RHO", + 1990 ], [ "utopia", - 2010, - "inter", - "day", - "E70", - 2010 + 2000, + "winter", + "night", + "RHO", + 1980 ], [ "utopia", 2010, - "inter", + "summer", "day", - "E31", + "E70", 1980 ], [ "utopia", - 2000, - "inter", + 2010, + "winter", "day", - "TXD", + "RHE", 2000 ], [ @@ -19846,157 +19446,133 @@ 2010, "inter", "day", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E21", + "SRE", 2000 ], [ "utopia", 2000, - "summer", - "night", + "inter", + "day", "TXD", - 1990 + 1980 ], [ "utopia", - 2000, + 2010, "winter", - "night", + "day", "E31", - 1990 + 1980 ], [ "utopia", - 2000, - "inter", + 1990, + "summer", "day", - "E01", - 1990 + "TXG", + 1970 ], [ "utopia", 2010, - "inter", + "winter", "night", - "E70", - 2010 + "E01", + 1980 ], [ "utopia", 2010, - "winter", + "inter", "day", - "RHO", - 1990 + "TXG", + 2000 ], [ "utopia", 2010, "summer", "night", - "TXE", - 2000 + "RHE", + 1990 ], [ "utopia", - 2010, - "inter", + 2000, + "winter", "night", - "E31", - 1980 + "SRE", + 1990 ], [ "utopia", 2000, - "winter", + "summer", "day", - "RHE", + "E21", 1990 ], [ "utopia", 2000, - "winter", + "inter", "night", - "E51", - 1980 + "E01", + 2000 ], [ "utopia", 1990, - "winter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2000, "summer", "day", "TXD", - 1980 + 1990 ], [ "utopia", - 2010, + 2000, "winter", "night", - "RHO", + "TXG", 1990 ], [ "utopia", - 2000, + 2010, "inter", "night", - "E70", + "E31", 2000 ], - [ - "utopia", - 1990, - "winter", - "day", - "E51", - 1980 - ], [ "utopia", 2000, - "summer", - "day", - "E01", - 1970 + "inter", + "night", + "TXE", + 2000 ], [ "utopia", - 2000, - "summer", + 1990, + "inter", "day", - "E51", - 2000 + "E70", + 1960 ], [ "utopia", 2000, "inter", "day", - "TXE", - 1990 + "SRE", + 2000 ], [ "utopia", - 2000, - "summer", + 2010, + "winter", "night", "E70", 1990 @@ -20005,30 +19581,30 @@ "utopia", 2010, "inter", - "day", - "SRE", - 1990 + "night", + "E70", + 1980 ], [ "utopia", 1990, "winter", "night", - "E51", - 1980 + "TXE", + 1990 ], [ "utopia", - 1990, - "summer", + 2010, + "inter", "day", - "E31", + "E01", 1980 ], [ "utopia", 2000, - "summer", + "winter", "night", "E01", 1970 @@ -20036,209 +19612,217 @@ [ "utopia", 2000, - "inter", + "summer", "night", - "TXG", - 1990 + "E31", + 2000 ], [ "utopia", - 2000, - "inter", + 1990, + "summer", "day", "E70", - 1990 + 1960 ], [ "utopia", 2000, - "winter", + "summer", "night", - "SRE", - 2000 + "E70", + 1980 ], [ "utopia", - 2010, - "summer", - "night", - "RHO", + 2000, + "winter", + "day", + "RHE", 1990 ], [ "utopia", - 2010, + 1990, "inter", "day", - "RHO", + "TXE", 1990 ], [ "utopia", - 2010, - "inter", - "night", - "SRE", - 1990 + 1990, + "winter", + "day", + "TXG", + 1970 ], [ "utopia", 2000, - "inter", + "winter", "day", - "RHO", + "TXE", 1990 ], [ "utopia", - 2010, + 2000, "inter", "night", - "E21", - 2010 + "RHO", + 1990 ], [ "utopia", 2000, "inter", - "night", - "SRE", - 1990 + "day", + "E70", + 2000 ], [ "utopia", - 1990, - "summer", + 2000, + "inter", "night", - "E51", - 1980 + "RHE", + 2000 ], [ "utopia", - 1990, - "winter", + 2010, + "summer", "day", - "SRE", + "E31", 1990 ], [ "utopia", - 1990, + 2000, "inter", "day", - "E70", - 1970 + "RL1", + 2000 ], [ "utopia", 2010, "winter", "day", - "E01", - 1980 + "E21", + 2010 ], [ "utopia", - 2000, - "winter", + 2010, + "inter", "day", - "E01", + "E21", 2000 ], + [ + "utopia", + 1990, + "winter", + "night", + "RHE", + 1990 + ], [ "utopia", 2010, "winter", "day", - "E51", - 2010 + "RHE", + 1990 ], [ "utopia", - 2000, + 2010, "inter", "night", "RHO", - 1990 + 2010 ], [ "utopia", - 2010, + 2000, "winter", "night", - "E70", - 2000 + "E21", + 1990 ], [ "utopia", - 1990, - "inter", - "night", - "E70", - 1970 + 2010, + "summer", + "day", + "RHE", + 2010 ], [ "utopia", 2010, - "winter", - "night", - "E01", - 1980 + "summer", + "day", + "TXE", + 2010 ], [ "utopia", 2000, "winter", "night", - "E01", - 2000 + "TXG", + 1980 ], [ "utopia", - 2010, + 2000, "inter", - "day", - "E21", - 2000 + "night", + "TXE", + 1990 ], [ "utopia", - 1990, - "summer", - "day", - "SRE", + 2010, + "inter", + "night", + "E31", 1990 ], [ "utopia", 2010, "summer", - "day", - "E01", - 1980 + "night", + "E31", + 1990 ], [ "utopia", 2000, - "winter", - "day", - "TXE", + "summer", + "night", + "TXD", 2000 ], [ "utopia", - 1990, - "summer", + 2000, + "inter", "day", - "RHO", + "SRE", 1990 ], [ "utopia", - 2000, + 1990, "inter", "day", - "E21", + "RHE", 1990 ], [ @@ -20246,136 +19830,120 @@ 1990, "summer", "night", - "SRE", + "E01", 1990 ], - [ - "utopia", - 2010, - "summer", - "day", - "E51", - 2000 - ], [ "utopia", 2000, - "winter", + "inter", "day", - "E31", - 1980 + "TXG", + 1990 ], [ "utopia", 2010, - "summer", + "inter", "night", - "E01", - 1980 + "RHE", + 2010 ], [ "utopia", - 2010, - "inter", + 1990, + "summer", "night", - "TXG", - 2000 + "TXD", + 1990 ], [ "utopia", 2010, "summer", "night", - "E51", + "E01", 2010 ], [ "utopia", 2010, "inter", - "day", - "E70", - 2000 + "night", + "TXE", + 2010 ], [ "utopia", 2000, "summer", - "day", + "night", "E31", - 2000 + 1990 ], [ "utopia", 2010, "summer", "night", - "E70", - 1990 + "TXD", + 2000 ], [ "utopia", - 2000, - "winter", + 2010, + "summer", "day", - "E70", - 2000 + "RHO", + 2010 ], [ "utopia", 2000, - "winter", + "summer", "night", - "TXE", - 2000 + "E70", + 1970 ], [ "utopia", - 2000, - "inter", - "night", - "E21", + 1990, + "summer", + "day", + "RHE", 1990 ], [ "utopia", - 2000, + 1990, "summer", "night", - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "night", "E31", 1980 ], [ "utopia", - 2000, - "inter", + 1990, + "summer", "day", - "E01", - 1980 + "TXE", + 1990 ], [ "utopia", 2000, - "winter", + "inter", "day", - "RHO", - 2000 + "E70", + 1990 ], [ "utopia", 2000, - "winter", + "inter", "night", - "E70", - 2000 + "RHE", + 1990 ] ], "CapacityAnnualConstraint_rptv": [], From 25e39184d56faf6e6909181b102c320baa0e106e Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 6 Jun 2025 11:30:28 -0400 Subject: [PATCH 088/587] Collapse max and min tables into limit tables with operators --- data_files/temoa_schema_v3_1.sql | 2 +- data_files/temoa_schema_v3_2.sql | 1090 +++++++++++++++++ temoa/temoa_model/hybrid_loader.py | 473 +++---- .../model_checking/pricing_check.py | 4 +- temoa/temoa_model/temoa_initialize.py | 260 +--- temoa/temoa_model/temoa_model.py | 423 ++----- temoa/temoa_model/temoa_rules.py | 1035 +++------------- temoa/utilities/db_migration_operator.py | 183 +++ 8 files changed, 1805 insertions(+), 1665 deletions(-) create mode 100644 data_files/temoa_schema_v3_2.sql create mode 100644 temoa/utilities/db_migration_operator.py diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index e6fa6689f..d5fb68eb7 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -628,7 +628,7 @@ CREATE TABLE IF NOT EXISTS OutputStorageLevel period INTEGER REFERENCES TimePeriod (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT diff --git a/data_files/temoa_schema_v3_2.sql b/data_files/temoa_schema_v3_2.sql new file mode 100644 index 000000000..843fce5c0 --- /dev/null +++ b/data_files/temoa_schema_v3_2.sql @@ -0,0 +1,1090 @@ +PRAGMA foreign_keys= OFF; +BEGIN TRANSACTION; + +CREATE TABLE IF NOT EXISTS MetaData +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +REPLACE INTO MetaData +VALUES ('myopic_base_year', 2000, 'Base Year for Myopic Analysis'); +REPLACE INTO MetaData +VALUES ('DB_MAJOR', 3, 'DB major version number'); +REPLACE INTO MetaData +VALUES ('DB_MINOR', 0, 'DB minor version number'); +REPLACE INTO MetaData +VALUES ('state_sequencing', 0, '0 = loop periods, 1 = loop seasons'); + +CREATE TABLE IF NOT EXISTS MetaDataReal +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +REPLACE INTO MetaDataReal +VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); +REPLACE INTO MetaDataReal +VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in LoanRate table'); + +CREATE TABLE IF NOT EXISTS OutputDualVariable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE IF NOT EXISTS OutputObjective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE IF NOT EXISTS SectorLabel +( + sector TEXT, + PRIMARY KEY (sector) +); + +CREATE TABLE IF NOT EXISTS CapacityCredit +( + region TEXT, + period INTEGER, + tech TEXT, + vintage INTEGER, + credit REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage), + CHECK (credit >= 0 AND credit <= 1) +); +CREATE TABLE IF NOT EXISTS CapacityFactorProcess +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS CapacityFactorTech +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS CapacityToActivity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + c2a REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS Commodity +( + name TEXT + PRIMARY KEY, + flag TEXT + REFERENCES CommodityType (label), + description TEXT +); +CREATE TABLE IF NOT EXISTS CommodityType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO CommodityType +VALUES ('p', 'physical commodity'); +REPLACE INTO CommodityType +VALUES ('a', 'annual commodity'); +REPLACE INTO CommodityType +VALUES ('e', 'emissions commodity'); +REPLACE INTO CommodityType +VALUES ('d', 'demand commodity'); +REPLACE INTO CommodityType +VALUES ('s', 'source commodity'); +REPLACE INTO CommodityType +VALUES ('w', 'waste commodity'); +REPLACE INTO CommodityType +VALUES ('wa', 'waste annual commodity'); +REPLACE INTO CommodityType +VALUES ('wp', 'waste physical commodity'); +CREATE TABLE IF NOT EXISTS ConstructionInput +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS CostEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT NOT NULL + REFERENCES Commodity (name), + cost REAL NOT NULL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE IF NOT EXISTS CostFixed +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS CostInvest +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS CostVariable +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS Demand +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + commodity TEXT + REFERENCES Commodity (name), + demand REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, commodity) +); +CREATE TABLE IF NOT EXISTS DemandSpecificDistribution +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + demand_name TEXT + REFERENCES Commodity (name), + dsd REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), + CHECK (dsd >= 0 AND dsd <= 1) +); +CREATE TABLE IF NOT EXISTS EndOfLifeOutput +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS Efficiency +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE IF NOT EXISTS EfficiencyVariable +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE IF NOT EXISTS EmissionActivity +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS EmissionEmbodied +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS EmissionEndOfLife +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS ExistingCapacity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS TechGroup +( + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE IF NOT EXISTS LoanLifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS LifetimeProcess +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS LifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS Operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +REPLACE INTO Operator VALUES('e','equal to'); +REPLACE INTO Operator VALUES('l','less than'); +REPLACE INTO Operator VALUES('g','greater than'); +REPLACE INTO Operator VALUES('le','less than or equal to'); +REPLACE INTO Operator VALUES('ge','greater than or equal to'); +CREATE TABLE IF NOT EXISTS LimitGrowthCapacity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE IF NOT EXISTS LimitDegrowthCapacity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE IF NOT EXISTS LimitGrowthNewCapacity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE IF NOT EXISTS LimitDegrowthNewCapacity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE IF NOT EXISTS LimitGrowthNewCapacityDelta +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE IF NOT EXISTS LimitDegrowthNewCapacityDelta +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE IF NOT EXISTS LimitStorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) +); +CREATE TABLE IF NOT EXISTS LimitActivity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator) +); +CREATE TABLE IF NOT EXISTS LimitActivityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name, operator) +); +CREATE TABLE IF NOT EXISTS LimitActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) +); +CREATE TABLE IF NOT EXISTS LimitAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + source TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS LimitCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator) +); +CREATE TABLE IF NOT EXISTS LimitCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name, operator) +); +CREATE TABLE IF NOT EXISTS LimitCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) +); +CREATE TABLE IF NOT EXISTS LimitNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator) +); +CREATE TABLE IF NOT EXISTS LimitNewCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name, operator) +); +CREATE TABLE IF NOT EXISTS LimitNewCapacityGroupShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) +); +CREATE TABLE IF NOT EXISTS LimitResource +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE IF NOT EXISTS LimitSeasonalActivity +( + region TEXT + REFERENCES Region (region), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY(region,period,season,tech, operator) +); +CREATE TABLE IF NOT EXISTS LimitTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE IF NOT EXISTS LimitTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE IF NOT EXISTS LimitTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE IF NOT EXISTS LimitTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE IF NOT EXISTS LimitEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE IF NOT EXISTS LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE IF NOT EXISTS OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputFlowOut +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); +CREATE TABLE IF NOT EXISTS PlanningReserveMargin +( + region TEXT + PRIMARY KEY + REFERENCES Region (region), + margin REAL +); +CREATE TABLE IF NOT EXISTS RampDown +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS RampUp +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS Region +( + region TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE IF NOT EXISTS TimeSegmentFraction +( + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + segfrac REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segfrac >= 0 AND segfrac <= 1) +); +CREATE TABLE IF NOT EXISTS StorageDuration +( + region TEXT, + tech TEXT, + duration REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS TechnologyType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO TechnologyType +VALUES ('r', 'resource technology'); +REPLACE INTO TechnologyType +VALUES ('p', 'production technology'); +REPLACE INTO TechnologyType +VALUES ('pb', 'baseload production technology'); +REPLACE INTO TechnologyType +VALUES ('ps', 'storage production technology'); +-- CREATE TABLE IF NOT EXISTS TimeNext +-- ( +-- period INTEGER +-- REFERENCES TimePeriod (period), +-- season TEXT +-- REFERENCES TimeSeason (season), +-- tod TEXT +-- REFERENCES TimeOfDay (tod), +-- season_next TEXT +-- REFERENCES TimeSeason (season), +-- tod_next TEXT +-- REFERENCES TimeOfDay (tod), +-- notes TEXT, +-- PRIMARY KEY (period, season, tod) +-- ); +CREATE TABLE IF NOT EXISTS TimeOfDay +( + sequence INTEGER UNIQUE, + tod TEXT + PRIMARY KEY +); +CREATE TABLE IF NOT EXISTS TimePeriod +( + sequence INTEGER UNIQUE, + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES TimePeriodType (label) +); +CREATE TABLE IF NOT EXISTS TimeSeason +( + season TEXT + PRIMARY KEY +); +CREATE TABLE IF NOT EXISTS PeriodSeasons +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT + REFERENCES TimeSeason (season), + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +CREATE TABLE IF NOT EXISTS TimePeriodType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO TimePeriodType +VALUES('e', 'existing vintages'); +REPLACE INTO TimePeriodType +VALUES('f', 'future'); +CREATE TABLE IF NOT EXISTS OutputEmission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS RPSRequirement +( + region TEXT NOT NULL + REFERENCES Region (region), + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech_group TEXT NOT NULL + REFERENCES TechGroup (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE IF NOT EXISTS TechGroupMember +( + group_name TEXT + REFERENCES TechGroup (group_name), + tech TEXT + REFERENCES Technology (tech), + PRIMARY KEY (group_name, tech) +); +CREATE TABLE IF NOT EXISTS Technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES TechnologyType (label) +); +CREATE TABLE OutputCost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES TimePeriod (period), + FOREIGN KEY (tech) REFERENCES Technology (tech) +); +COMMIT; +PRAGMA FOREIGN_KEYS = 1; \ No newline at end of file diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 4a16aa9dd..494bfbe35 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -53,38 +53,26 @@ # the tables below are ones in which we might find regional groups which should be captured # to make the members of the RegionalGlobalIndices Set in the model. They need to aggregated tables_with_regional_groups = { - 'MinAnnualCapacityFactor': 'region', - 'MaxAnnualCapacityFactor': 'region', - 'EmissionLimit': 'region', - 'MinActivityGroup': 'region', - 'MaxActivityGroup': 'region', - 'MinSeasonalActivity': 'region', - 'MaxSeasonalActivity': 'region', - 'MinCapacity': 'region', - 'MaxCapacity': 'region', - 'MinActivity': 'region', - 'MaxActivity': 'region', - 'MinNewCapacity': 'region', - 'MaxNewCapacity': 'region', - 'MinNewCapacityGroup': 'region', - 'MaxNewCapacityGroup': 'region', - 'MinCapacityGroup': 'region', - 'MaxCapacityGroup': 'region', - 'MinActivityShare': 'region', - 'MaxActivityShare': 'region', - 'MinCapacityShare': 'region', - 'MaxCapacityShare': 'region', - 'MinNewCapacityShare': 'region', - 'MaxNewCapacityShare': 'region', - 'MinNewCapacityGroupShare': 'region', - 'MaxNewCapacityGroupShare': 'region', - 'MaxResource': 'region', - 'GrowthCapacity': 'region', - 'DegrowthCapacity': 'region', - 'GrowthNewCapacity': 'region', - 'DegrowthNewCapacity': 'region', - 'GrowthNewCapacityDelta': 'region', - 'DegrowthNewCapacityDelta': 'region', + 'LimitAnnualCapacityFactor': 'region', + 'LimitEmission': 'region', + 'LimitActivityGroup': 'region', + 'LimitSeasonalActivity': 'region', + 'LimitCapacity': 'region', + 'LimitActivity': 'region', + 'LimitNewCapacity': 'region', + 'LimitNewCapacityGroup': 'region', + 'LimitCapacityGroup': 'region', + 'LimitActivityShare': 'region', + 'LimitCapacityShare': 'region', + 'LimitNewCapacityShare': 'region', + 'LimitNewCapacityGroupShare': 'region', + 'LimitResource': 'region', + 'LimitGrowthCapacity': 'region', + 'LimitDegrowthCapacity': 'region', + 'LimitGrowthNewCapacity': 'region', + 'LimitDegrowthNewCapacity': 'region', + 'LimitGrowthNewCapacityDelta': 'region', + 'LimitDegrowthNewCapacityDelta': 'region', } @@ -714,16 +702,16 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N raw = cur.execute('SELECT region, tech, lifetime FROM main.LoanLifetimeTech').fetchall() load_element(M.LoanLifetimeTech, raw, self.viable_rt, (0, 1)) - # MinTechInputSplit - if self.table_exists('MinTechInputSplit'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, input_comm, tech, min_proportion FROM main.MinTechInputSplit') - loaded = load_element(M.MinTechInputSplit, raw, self.viable_rpit, (0, 1, 2, 3)) + # LimitTechInputSplit + if self.table_exists('LimitTechInputSplit'): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, input_comm, tech, operator, proportion FROM main.LimitTechInputSplit') + loaded = load_element(M.LimitTechInputSplit, raw, self.viable_rpit, (0, 1, 2, 3)) # we need to see if anything was filtered out here and raise warning if so as it may have invalidated # a blending process and any missing items should be reviewed if len(loaded) < len(raw): missing = set(raw) - set(loaded) for item in sorted(missing, key=lambda x: (x[0], x[1], x[3], x[2])): - region, period, ic, tech, _ = item + region, period, ic, tech, _, _ = item logger.warning( 'Technology Input Split requirement in region %s, period %d for tech %s with input' 'commodity %s has ' @@ -736,16 +724,16 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N ic, ) - # MinTechInputSplitAnnual - if self.table_exists('MinTechInputSplitAnnual'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, input_comm, tech, min_proportion FROM main.MinTechInputSplitAnnual') - loaded = load_element(M.MinTechInputSplitAnnual, raw, self.viable_rpit, (0, 1, 2, 3)) + # LimitTechInputSplitAnnual + if self.table_exists('LimitTechInputSplitAnnual'): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, input_comm, tech, operator, proportion FROM main.LimitTechInputSplitAnnual') + loaded = load_element(M.LimitTechInputSplitAnnual, raw, self.viable_rpit, (0, 1, 2, 3)) # we need to see if anything was filtered out here and raise warning if so as it may have invalidated # a blending process and any missing items should be reviewed if len(loaded) < len(raw): missing = set(raw) - set(loaded) for item in sorted(missing, key=lambda x: (x[0], x[1], x[3], x[2])): - region, period, ic, tech, _ = item + region, period, ic, tech, _, _ = item logger.warning( 'Technology Input Split Annual requirement in region %s, period %d for tech %s with input' 'commodity %s has ' @@ -758,15 +746,15 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N ic, ) - # MinTechOutputSplit - if self.table_exists('MinTechOutputSplit'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, output_comm, min_proportion FROM main.MinTechOutputSplit') - loaded = load_element(M.MinTechOutputSplit, raw, self.viable_rpto, (0, 1, 2, 3)) + # LimitTechOutputSplit + if self.table_exists('LimitTechOutputSplit'): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, output_comm, operator, proportion FROM main.LimitTechOutputSplit') + loaded = load_element(M.LimitTechOutputSplit, raw, self.viable_rpto, (0, 1, 2, 3)) # raise warning regarding any deletions here... similar to input split above if len(loaded) < len(raw): missing = set(raw) - set(loaded) for item in sorted(missing): - region, period, tech, oc, _ = item + region, period, tech, oc, _, _ = item logger.warning( 'Technology Output Split requirement in region %s, period %d for tech %s with output' 'commodity %s has ' @@ -779,103 +767,16 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N oc, ) - # MinTechOutputSplitAnnual - if self.table_exists('MinTechOutputSplitAnnual'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, output_comm, min_proportion FROM main.MinTechOutputSplitAnnual') - loaded = load_element(M.MinTechOutputSplitAnnual, raw, self.viable_rpto, (0, 1, 2, 3)) + # LimitTechOutputSplitAnnual + if self.table_exists('LimitTechOutputSplitAnnual'): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, output_comm, operator, proportion FROM main.LimitTechOutputSplitAnnual') + loaded = load_element(M.LimitTechOutputSplitAnnual, raw, self.viable_rpto, (0, 1, 2, 3)) # we need to see if anything was filtered out here and raise warning if so as it may have invalidated # a blending process and any missing items should be reviewed if len(loaded) < len(raw): missing = set(raw) - set(loaded) for item in sorted(missing): - region, period, tech, oc, _ = item - logger.warning( - 'Technology Output Split Annual requirement in region %s, period %d for tech %s with output' - 'commodity %s has ' - 'been removed because the tech path with that output is ' - 'invalid/not available/orphan. See the other warnings for this TECH in ' - 'this region-period, and check for availability of all components in data.', - region, - period, - tech, - oc, - ) - - # MaxTechInputSplit - if self.table_exists('MaxTechInputSplit'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, input_comm, tech, max_proportion FROM main.MaxTechInputSplit') - loaded = load_element(M.MaxTechInputSplit, raw, self.viable_rpit, (0, 1, 2, 3)) - # we need to see if anything was filtered out here and raise warning if so as it may have invalidated - # a blending process and any missing items should be reviewed - if len(loaded) < len(raw): - missing = set(raw) - set(loaded) - for item in sorted(missing, key=lambda x: (x[0], x[1], x[3], x[2])): - region, period, ic, tech, _ = item - logger.warning( - 'Technology Input Split requirement in region %s, period %d for tech %s with input' - 'commodity %s has ' - 'been removed because the tech path with that input is ' - 'invalid/not available/orphan. See the other warnings for this TECH in ' - 'this region-period, and check for availability of all components in data.', - region, - period, - tech, - ic, - ) - - # MaxTechInputSplitAnnual - if self.table_exists('MaxTechInputSplitAnnual'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, input_comm, tech, max_proportion FROM main.MaxTechInputSplitAnnual') - loaded = load_element(M.MaxTechInputSplitAnnual, raw, self.viable_rpit, (0, 1, 2, 3)) - # we need to see if anything was filtered out here and raise warning if so as it may have invalidated - # a blending process and any missing items should be reviewed - if len(loaded) < len(raw): - missing = set(raw) - set(loaded) - for item in sorted(missing, key=lambda x: (x[0], x[1], x[3], x[2])): - region, period, ic, tech, _ = item - logger.warning( - 'Technology Input Split Annual requirement in region %s, period %d for tech %s with input' - 'commodity %s has ' - 'been removed because the tech path with that input is ' - 'invalid/not available/orphan. See the other warnings for this TECH in ' - 'this region-period, and check for availability of all components in data.', - region, - period, - tech, - ic, - ) - - # MaxTechOutputSplit - if self.table_exists('MaxTechOutputSplit'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, output_comm, max_proportion FROM main.MaxTechOutputSplit') - loaded = load_element(M.MaxTechOutputSplit, raw, self.viable_rpto, (0, 1, 2, 3)) - # raise warning regarding any deletions here... similar to input split above - if len(loaded) < len(raw): - missing = set(raw) - set(loaded) - for item in sorted(missing): - region, period, tech, oc, _ = item - logger.warning( - 'Technology Output Split requirement in region %s, period %d for tech %s with output' - 'commodity %s has ' - 'been removed because the tech path with that output is ' - 'invalid/not available/orphan. See the other warnings for this TECH in ' - 'this region-period, and check for availability of all components in data.', - region, - period, - tech, - oc, - ) - - # MaxTechOutputSplitAnnual - if self.table_exists('MaxTechOutputSplitAnnual'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, output_comm, max_proportion FROM main.MaxTechOutputSplitAnnual') - loaded = load_element(M.MaxTechOutputSplitAnnual, raw, self.viable_rpto, (0, 1, 2, 3)) - # we need to see if anything was filtered out here and raise warning if so as it may have invalidated - # a blending process and any missing items should be reviewed - if len(loaded) < len(raw): - missing = set(raw) - set(loaded) - for item in sorted(missing): - region, period, tech, oc, _ = item + region, period, tech, oc, _, _ = item logger.warning( 'Technology Output Split Annual requirement in region %s, period %d for tech %s with output' 'commodity %s has ' @@ -938,171 +839,111 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N load_element(M.LoanRate, raw, self.viable_rtv, (0, 1, 2)) - # MinCapacity - if self.table_exists('MinCapacity'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, min_cap FROM main.MinCapacity') - load_element(M.MinCapacity, raw, self.viable_rt, (0, 2)) - - # MaxCapacity - if self.table_exists('MaxCapacity'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, max_cap FROM main.MaxCapacity') - load_element(M.MaxCapacity, raw, self.viable_rt, (0, 2)) - - # MinNewCap - if self.table_exists('MinNewCapacity'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, min_cap FROM main.MinNewCapacity') - load_element(M.MinNewCapacity, raw, self.viable_rt, (0, 2)) - - # MaxNewCap - if self.table_exists('MaxNewCapacity'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, max_cap FROM main.MaxNewCapacity') - load_element(M.MaxNewCapacity, raw, self.viable_rt, (0, 2)) - - # MaxCapacityGroup - if self.table_exists('MaxCapacityGroup'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, max_cap FROM main.MaxCapacityGroup') - load_element(M.MaxCapacityGroup, raw) - - # MinCapacityGroup - if self.table_exists('MinCapacityGroup'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, min_cap FROM main.MinCapacityGroup') - load_element(M.MinCapacityGroup, raw) - - # MinNewCapacityGroup - if self.table_exists('MinNewCapacityGroup'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, min_new_cap FROM main.MinNewCapacityGroup') - load_element(M.MinNewCapacityGroup, raw) - - # MaxNewCapacityGroup - if self.table_exists('MaxNewCapacityGroup'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, max_new_cap FROM main.MaxNewCapacityGroup') - load_element(M.MaxNewCapacityGroup, raw) - - # MinCapacityShare - if self.table_exists('MinCapacityShare'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, group_name, min_proportion FROM main.MinCapacityShare') - load_element(M.MinCapacityShare, raw, self.viable_rt, (0, 2)) - - # MaxCapacityShare - if self.table_exists('MaxCapacityShare'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, group_name, max_proportion FROM main.MaxCapacityShare') - load_element(M.MaxCapacityShare, raw, self.viable_rt, (0, 2)) - - # MinNewCapacityShare - if self.table_exists('MinNewCapacityShare'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, group_name, min_proportion FROM main.MinNewCapacityShare') - load_element(M.MinNewCapacityShare, raw, self.viable_rt, (0, 2)) - - # MaxNewCapacityShare - if self.table_exists('MaxNewCapacityShare'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, group_name, max_proportion FROM main.MaxNewCapacityShare') - load_element(M.MaxNewCapacityShare, raw, self.viable_rt, (0, 2)) - - # MinNewCapacityGroupShare - if self.table_exists('MinNewCapacityGroupShare'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, sub_group, super_group, min_proportion FROM main.MinNewCapacityGroupShare') - load_element(M.MinNewCapacityGroupShare, raw) - - # MaxNewCapacityGroupShare - if self.table_exists('MaxNewCapacityGroupShare'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, sub_group, super_group, max_proportion FROM main.MaxNewCapacityGroupShare') - load_element(M.MaxNewCapacityGroupShare, raw) - - # MinActivityGroup - if self.table_exists('MinActivityGroup'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, min_act FROM main.MinActivityGroup') - load_element(M.MinActivityGroup, raw) - - # MaxActivityGroup - if self.table_exists('MaxActivityGroup'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, max_act FROM main.MaxActivityGroup') - load_element(M.MaxActivityGroup, raw) - - # MinActivityShare - if self.table_exists('MinActivityShare'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, group_name, min_proportion FROM main.MinActivityShare') - load_element(M.MinActivityShare, raw, self.viable_rt, (0, 2)) - - # MaxActivityShare - if self.table_exists('MaxActivityShare'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, group_name, max_proportion FROM main.MaxActivityShare') - load_element(M.MaxActivityShare, raw, self.viable_rt, (0, 2)) - - # MaxResource - if self.table_exists('MaxResource'): - raw = cur.execute('SELECT region, tech, max_res FROM main.MaxResource').fetchall() - load_element(M.MaxResource, raw, self.viable_rt, (0, 1)) - - # MaxActivity - if self.table_exists('MaxActivity'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, max_act FROM main.MaxActivity') - load_element(M.MaxActivity, raw, self.viable_rt, (0, 2)) - - # MinActivity - if self.table_exists('MinActivity'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, min_act FROM main.MinActivity') - load_element(M.MinActivity, raw, self.viable_rt, (0, 2)) - - # MaxSeasonalActivity - if self.table_exists('MaxSeasonalActivity'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tech, max_act FROM main.MaxSeasonalActivity') - load_element(M.MaxSeasonalActivity, raw, self.viable_rt, (0, 3)) - - # MinSeasonalActivity - if self.table_exists('MinSeasonalActivity'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tech, min_act FROM main.MinSeasonalActivity') - load_element(M.MinSeasonalActivity, raw, self.viable_rt, (0, 3)) - - # MinAnnualCapacityFactor - if self.table_exists('MinAnnualCapacityFactor'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, output_comm, factor FROM main.MinAnnualCapacityFactor') - load_element(M.MinAnnualCapacityFactor, raw, self.viable_rt, (0, 2)) - - # MaxAnnualCapacityFactor - if self.table_exists('MaxAnnualCapacityFactor'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, output_comm, factor FROM main.MaxAnnualCapacityFactor') - load_element(M.MaxAnnualCapacityFactor, raw, self.viable_rt, (0, 2)) - - # GrowthCapacity - if self.table_exists('GrowthCapacity'): - raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.GrowthCapacity').fetchall() + # LimitCapacity + if self.table_exists('LimitCapacity'): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, operator, capacity FROM main.LimitCapacity') + load_element(M.LimitCapacity, raw, self.viable_rt, (0, 2)) + + # LimitNewCap + if self.table_exists('LimitNewCapacity'): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, operator, new_cap FROM main.LimitNewCapacity') + load_element(M.LimitNewCapacity, raw, self.viable_rt, (0, 2)) + + # LimitCapacityGroup + if self.table_exists('LimitCapacityGroup'): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, operator, capacity FROM main.LimitCapacityGroup') + load_element(M.LimitCapacityGroup, raw) + + # LimitNewCapacityGroup + if self.table_exists('LimitNewCapacityGroup'): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, operator, new_cap FROM main.LimitNewCapacityGroup') + load_element(M.LimitNewCapacityGroup, raw) + + # LimitCapacityShare + if self.table_exists('LimitCapacityShare'): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, group_name, operator, share FROM main.LimitCapacityShare') + load_element(M.LimitCapacityShare, raw, self.viable_rt, (0, 2)) + + # LimitNewCapacityShare + if self.table_exists('LimitNewCapacityShare'): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, group_name, operator, share FROM main.LimitNewCapacityShare') + load_element(M.LimitNewCapacityShare, raw, self.viable_rt, (0, 2)) + + # LimitNewCapacityGroupShare + if self.table_exists('LimitNewCapacityGroupShare'): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitNewCapacityGroupShare') + load_element(M.LimitNewCapacityGroupShare, raw) + + # LimitActivityGroup + if self.table_exists('LimitActivityGroup'): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, operator, activity FROM main.LimitActivityGroup') + load_element(M.LimitActivityGroup, raw) + + # LimitActivityShare + if self.table_exists('LimitActivityShare'): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, group_name, operator, share FROM main.LimitActivityShare') + load_element(M.LimitActivityShare, raw, self.viable_rt, (0, 2)) + + # LimitResource + if self.table_exists('LimitResource'): + raw = cur.execute('SELECT region, tech, operator, cum_act FROM main.LimitResource').fetchall() + load_element(M.LimitResource, raw, self.viable_rt, (0, 1)) + + # LimitActivity + if self.table_exists('LimitActivity'): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, operator, activity FROM main.LimitActivity') + load_element(M.LimitActivity, raw, self.viable_rt, (0, 2)) + + # LimitSeasonalActivity + if self.table_exists('LimitSeasonalActivity'): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tech, operator, activity FROM main.LimitSeasonalActivity') + load_element(M.LimitSeasonalActivity, raw, self.viable_rt, (0, 3)) + + # LimitAnnualCapacityFactor + if self.table_exists('LimitAnnualCapacityFactor'): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, output_comm, operator, factor FROM main.LimitAnnualCapacityFactor') + load_element(M.LimitAnnualCapacityFactor, raw, self.viable_rt, (0, 2)) + + # LimitGrowthCapacity + if self.table_exists('LimitGrowthCapacity'): + raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.LimitGrowthCapacity').fetchall() raw = self.tuple_values(raw, 3) - load_element(M.GrowthCapacity, raw, self.viable_rt, (0, 1)) + load_element(M.LimitGrowthCapacity, raw, self.viable_rt, (0, 1)) - # DegrowthCapacity - if self.table_exists('DegrowthCapacity'): - raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.DegrowthCapacity').fetchall() + # LimitDegrowthCapacity + if self.table_exists('LimitDegrowthCapacity'): + raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.LimitDegrowthCapacity').fetchall() raw = self.tuple_values(raw, 3) - load_element(M.DegrowthCapacity, raw, self.viable_rt, (0, 1)) + load_element(M.LimitDegrowthCapacity, raw, self.viable_rt, (0, 1)) - # GrowthNewCapacity - if self.table_exists('GrowthNewCapacity'): - raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.GrowthNewCapacity').fetchall() + # LimitGrowthNewCapacity + if self.table_exists('LimitGrowthNewCapacity'): + raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.LimitGrowthNewCapacity').fetchall() raw = self.tuple_values(raw, 3) - load_element(M.GrowthNewCapacity, raw, self.viable_rt, (0, 1)) + load_element(M.LimitGrowthNewCapacity, raw, self.viable_rt, (0, 1)) - # DegrowthNewCapacity - if self.table_exists('DegrowthNewCapacity'): - raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.DegrowthNewCapacity').fetchall() + # LimitDegrowthNewCapacity + if self.table_exists('LimitDegrowthNewCapacity'): + raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.LimitDegrowthNewCapacity').fetchall() raw = self.tuple_values(raw, 3) - load_element(M.DegrowthNewCapacity, raw, self.viable_rt, (0, 1)) + load_element(M.LimitDegrowthNewCapacity, raw, self.viable_rt, (0, 1)) - # GrowthNewCapacityDelta - if self.table_exists('GrowthNewCapacityDelta'): - raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.GrowthNewCapacityDelta').fetchall() + # LimitGrowthNewCapacityDelta + if self.table_exists('LimitGrowthNewCapacityDelta'): + raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.LimitGrowthNewCapacityDelta').fetchall() raw = self.tuple_values(raw, 3) - load_element(M.GrowthNewCapacityDelta, raw, self.viable_rt, (0, 1)) + load_element(M.LimitGrowthNewCapacityDelta, raw, self.viable_rt, (0, 1)) - # DegrowthNewCapacityDelta - if self.table_exists('DegrowthNewCapacityDelta'): - raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.DegrowthNewCapacityDelta').fetchall() + # LimitDegrowthNewCapacityDelta + if self.table_exists('LimitDegrowthNewCapacityDelta'): + raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.LimitDegrowthNewCapacityDelta').fetchall() raw = self.tuple_values(raw, 3) - load_element(M.DegrowthNewCapacityDelta, raw, self.viable_rt, (0, 1)) + load_element(M.LimitDegrowthNewCapacityDelta, raw, self.viable_rt, (0, 1)) - # EmissionLimit - if self.table_exists('EmissionLimit'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, emis_comm, value FROM main.EmissionLimit') - load_element(M.EmissionLimit, raw) + # LimitEmission + if self.table_exists('LimitEmission'): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, emis_comm, operator, value FROM main.LimitEmission') + load_element(M.LimitEmission, raw) # EmissionActivity # The current emission constraint screens by valid inputs, so if it is NOT @@ -1197,9 +1038,9 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N load_element(M.StorageDuration, raw, self.viable_rt, (0, 1)) # StorageFraction - if self.table_exists('StorageLevelFraction'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tod, tech, vintage, fraction FROM main.StorageLevelFraction') - load_element(M.StorageFraction, raw, self.viable_rtv, (0,4,5)) + if self.table_exists('LimitStorageLevelFraction'): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tod, tech, vintage, fraction FROM main.LimitStorageLevelFraction') + load_element(M.LimitStorageFraction, raw, self.viable_rtv, (0,4,5)) # For T/S: dump the size of all data elements into the log if self.debugging: @@ -1248,35 +1089,23 @@ def load_param_idx_sets(self, data: dict) -> dict: param_idx_sets = { M.CostInvest.name: M.CostInvest_rtv.name, M.CostEmission.name: M.CostEmission_rpe.name, - M.EmissionLimit.name: M.EmissionLimitConstraint_rpe.name, - M.MaxActivity.name: M.MaxActivityConstraint_rpt.name, - M.MaxSeasonalActivity.name: M.MaxSeasonalActivityConstraint_rpst.name, - M.MaxActivityGroup.name: M.MaxActivityGroup_rpg.name, - M.MaxActivityShare.name: M.MaxActivityShareConstraint_rptg.name, - M.MaxAnnualCapacityFactor.name: M.MaxAnnualCapacityFactorConstraint_rpto.name, - M.MaxCapacity.name: M.MaxCapacityConstraint_rpt.name, - M.MaxCapacityGroup.name: M.MaxCapacityGroupConstraint_rpg.name, - M.MaxCapacityShare.name: M.MaxCapacityShareConstraint_rptg.name, - M.MaxNewCapacity.name: M.MaxNewCapacityConstraint_rpt.name, - M.MaxNewCapacityGroup.name: M.MaxNewCapacityGroupConstraint_rpg.name, - M.MaxNewCapacityShare.name: M.MaxNewCapacityShareConstraint_rptg.name, - M.MaxNewCapacityGroupShare.name: M.MaxNewCapacityGroupShareConstraint_rpgg.name, - M.MaxResource.name: M.MaxResourceConstraint_rt.name, - M.MinActivity.name: M.MinActivityConstraint_rpt.name, - M.MinSeasonalActivity.name: M.MinSeasonalActivityConstraint_rpst.name, - M.MinActivityGroup.name: M.MinActivityGroup_rpg.name, - M.MinActivityShare.name: M.MinActivityShareConstraint_rptg.name, - M.MinAnnualCapacityFactor.name: M.MinAnnualCapacityFactorConstraint_rpto.name, - M.MinCapacity.name: M.MinCapacityConstraint_rpt.name, - M.MinCapacityGroup.name: M.MinCapacityGroupConstraint_rpg.name, - M.MinCapacityShare.name: M.MinCapacityShareConstraint_rptg.name, - M.MinNewCapacity.name: M.MinNewCapacityConstraint_rpt.name, - M.MinNewCapacityGroup.name: M.MinNewCapacityGroupConstraint_rpg.name, - M.MinNewCapacityShare.name: M.MinNewCapacityShareConstraint_rptg.name, - M.MinNewCapacityGroupShare.name: M.MinNewCapacityGroupShareConstraint_rpgg.name, + M.LimitEmission.name: M.LimitEmissionConstraint_rpe.name, + M.LimitActivity.name: M.LimitActivityConstraint_rpt.name, + M.LimitSeasonalActivity.name: M.LimitSeasonalActivityConstraint_rpst.name, + M.LimitActivityGroup.name: M.LimitActivityGroup_rpg.name, + M.LimitActivityShare.name: M.LimitActivityShareConstraint_rptg.name, + M.LimitAnnualCapacityFactor.name: M.LimitAnnualCapacityFactorConstraint_rpto.name, + M.LimitCapacity.name: M.LimitCapacityConstraint_rpt.name, + M.LimitCapacityGroup.name: M.LimitCapacityGroupConstraint_rpg.name, + M.LimitCapacityShare.name: M.LimitCapacityShareConstraint_rptg.name, + M.LimitNewCapacity.name: M.LimitNewCapacityConstraint_rpt.name, + M.LimitNewCapacityGroup.name: M.LimitNewCapacityGroupConstraint_rpg.name, + M.LimitNewCapacityShare.name: M.LimitNewCapacityShareConstraint_rptg.name, + M.LimitNewCapacityGroupShare.name: M.LimitNewCapacityGroupShareConstraint_rpgg.name, + M.LimitResource.name: M.LimitResourceConstraint_rt.name, + M.LimitStorageFraction.name: M.LimitStorageFractionConstraint_rpsdtv.name, M.RenewablePortfolioStandard.name: M.RenewablePortfolioStandardConstraint_rpg.name, # M.ResourceBound.name: M.ResourceConstraint_rpr.name, - M.StorageFraction.name: M.StorageFractionConstraint_rpsdtv.name } res = {} diff --git a/temoa/temoa_model/model_checking/pricing_check.py b/temoa/temoa_model/model_checking/pricing_check.py index 1564bc499..3ade4dcb5 100644 --- a/temoa/temoa_model/model_checking/pricing_check.py +++ b/temoa/temoa_model/model_checking/pricing_check.py @@ -274,7 +274,7 @@ def check_tech_uncap(M: 'TemoaModel') -> bool: Check that the tech_uncap set members... 1. do not have fixed or invest costs 2. Either have no Var cost, or a Var cost in every year of their lifespan (similar to check #3 above) - 3. Are not in the MaxCapacity/MinCapacity parameters + 3. Are not in the LimitCapacity parameters :param M: :return: True if "clean" (no warnings), else False @@ -335,7 +335,7 @@ def check_tech_uncap(M: 'TemoaModel') -> bool: extra_periods, ) - capacity_params = (M.MaxCapacity, M.MinCapacity, M.ExistingCapacity) + capacity_params = (M.ExistingCapacity,) bad_cap_entries = False for param in capacity_params: bad_entries = {(r, t, v) for r, t, v in param.keys() if t in M.tech_uncap} diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 68b7e3379..e66d18185 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -404,8 +404,10 @@ def CreateCapacityFactors(M: 'TemoaModel'): processes = set((r, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) all_cfs = set( - (r, s, d, t, v) - for (r, t, v), s, d in cross_product(processes, M.time_season[p], M.time_of_day) + (r, p, s, d, t, v) + for (r, t, v) in processes + for p in M.processPeriods[r, t, v] + for s, d in cross_product(M.time_season[p], M.time_of_day) ) # Step 2 @@ -465,7 +467,7 @@ def get_default_capacity_factor(M: 'TemoaModel', r, p, s, d, t, v): return M.CapacityFactorTech[r, p, s, d, t] -def get_default_loan_rate(M, *_): +def get_default_loan_rate(M: 'TemoaModel', *_): """get the default loan rate from the DefaultLoanRate param""" return M.DefaultLoanRate() @@ -836,65 +838,35 @@ def CreateSparseDicts(M: 'TemoaModel'): if t in M.tech_downramping and (r, p, t) not in M.rampDownVintages: M.rampDownVintages[r, p, t] = set() - # min tech split - if (r, p, i, t) in M.MinTechInputSplit and ( - r, - p, - i, - t, - ) not in M.minInputSplitVintages: - M.minInputSplitVintages[r, p, i, t] = set() - if (r, p, i, t) in M.MinTechInputSplitAnnual and ( - r, - p, - i, - t, - ) not in M.minInputSplitAnnualVintages: - M.minInputSplitAnnualVintages[r, p, i, t] = set() - if (r, p, t, o) in M.MinTechOutputSplit and ( - r, - p, - t, - o, - ) not in M.minOutputSplitVintages: - M.minOutputSplitVintages[r, p, t, o] = set() - if (r, p, t, o) in M.MinTechOutputSplitAnnual and ( - r, - p, - t, - o, - ) not in M.minOutputSplitAnnualVintages: - M.minOutputSplitAnnualVintages[r, p, t, o] = set() - - # max tech split - if (r, p, i, t) in M.MaxTechInputSplit and ( + # tech split + if (r, p, i, t) in M.LimitTechInputSplit and ( r, p, i, t, - ) not in M.maxInputSplitVintages: - M.maxInputSplitVintages[r, p, i, t] = set() - if (r, p, i, t) in M.MaxTechInputSplitAnnual and ( + ) not in M.inputSplitVintages: + M.inputSplitVintages[r, p, i, t] = set() + if (r, p, i, t) in M.LimitTechInputSplitAnnual and ( r, p, i, t, - ) not in M.maxInputSplitAnnualVintages: - M.maxInputSplitAnnualVintages[r, p, i, t] = set() - if (r, p, t, o) in M.MaxTechOutputSplit and ( + ) not in M.inputSplitAnnualVintages: + M.inputSplitAnnualVintages[r, p, i, t] = set() + if (r, p, t, o) in M.LimitTechOutputSplit and ( r, p, t, o, - ) not in M.maxOutputSplitVintages: - M.maxOutputSplitVintages[r, p, t, o] = set() - if (r, p, t, o) in M.MaxTechOutputSplitAnnual and ( + ) not in M.outputSplitVintages: + M.outputSplitVintages[r, p, t, o] = set() + if (r, p, t, o) in M.LimitTechOutputSplitAnnual and ( r, p, t, o, - ) not in M.maxOutputSplitAnnualVintages: - M.maxOutputSplitAnnualVintages[r, p, t, o] = set() + ) not in M.outputSplitAnnualVintages: + M.outputSplitAnnualVintages[r, p, t, o] = set() if t in M.tech_resource and (r, p, o) not in M.processByPeriodAndOutput: M.processByPeriodAndOutput[r, p, o] = set() @@ -931,25 +903,15 @@ def CreateSparseDicts(M: 'TemoaModel'): if t in M.tech_downramping: M.rampDownVintages[r, p, t].add(v) - # min tech split - if (r, p, i, t) in M.MinTechInputSplit: - M.minInputSplitVintages[r, p, i, t].add(v) - if (r, p, i, t) in M.MinTechInputSplitAnnual: - M.minInputSplitAnnualVintages[r, p, i, t].add(v) - if (r, p, t, o) in M.MinTechOutputSplit: - M.minOutputSplitVintages[r, p, t, o].add(v) - if (r, p, t, o) in M.MinTechOutputSplitAnnual: - M.minOutputSplitAnnualVintages[r, p, t, o].add(v) - - # max tech split - if (r, p, i, t) in M.MaxTechInputSplit: - M.maxInputSplitVintages[r, p, i, t].add(v) - if (r, p, i, t) in M.MaxTechInputSplitAnnual: - M.maxInputSplitAnnualVintages[r, p, i, t].add(v) - if (r, p, t, o) in M.MaxTechOutputSplit: - M.maxOutputSplitVintages[r, p, t, o].add(v) - if (r, p, t, o) in M.MaxTechOutputSplitAnnual: - M.maxOutputSplitAnnualVintages[r, p, t, o].add(v) + # tech split + if (r, p, i, t) in M.LimitTechInputSplit: + M.inputSplitVintages[r, p, i, t].add(v) + if (r, p, i, t) in M.LimitTechInputSplitAnnual: + M.inputSplitAnnualVintages[r, p, i, t].add(v) + if (r, p, t, o) in M.LimitTechOutputSplit: + M.outputSplitVintages[r, p, t, o].add(v) + if (r, p, t, o) in M.LimitTechOutputSplitAnnual: + M.outputSplitAnnualVintages[r, p, t, o].add(v) if t in M.tech_resource: M.processByPeriodAndOutput[r, p, o].add((i, t, v)) @@ -1214,9 +1176,10 @@ def RegionalGlobalInitializedIndices(M: 'TemoaModel'): def GroupShareIndices(M: 'TemoaModel'): indices = set( - (r, p, t, g) + (r, p, t, g, op) for g in M.tech_group_names for r, p, t in M.groupRegionActiveFlow_rpt + for op in M.operator if t in M.tech_group_members[g] ) @@ -1225,10 +1188,11 @@ def GroupShareIndices(M: 'TemoaModel'): def TwoGroupShareIndices(M: 'TemoaModel'): indices = set( - (r, p, g1, g2) + (r, p, g1, g2, op) for g1 in M.tech_group_names for g2 in M.tech_group_names for r, p, _t in M.groupRegionActiveFlow_rpt + for op in M.operator if _t in M.tech_group_members[g2] ) @@ -1566,231 +1530,141 @@ def ReserveMarginIndices(M: 'TemoaModel'): return indices -def MinTechInputSplitConstraintIndices(M: 'TemoaModel'): - indices = set( - (r, p, s, d, i, t, v) - for r, p, i, t in M.minInputSplitVintages.keys() - if t not in M.tech_annual - for v in M.minInputSplitVintages[r, p, i, t] - for s in M.time_season[p] - for d in M.time_of_day - ) - ann_indices = set( - (r, p, i, t) - for r, p, i, t in M.minInputSplitVintages.keys() - if t in M.tech_annual - ) - if len(ann_indices) > 0: - msg = ( - "Warning: Annual technologies included in TechInputSplit table. " - "Use TechInputSplitAnnual table instead or these constraints will be ignored: {}" - ) - logger.warning(msg.format(ann_indices)) - - return indices - - -def MinTechInputSplitAnnualConstraintIndices(M: 'TemoaModel'): - indices = set( - (r, p, i, t, v) - for r, p, i, t in M.minInputSplitAnnualVintages.keys() - if t in M.tech_annual - for v in M.minInputSplitAnnualVintages[r, p, i, t] - ) - - return indices - - -def MinTechInputSplitAverageConstraintIndices(M: 'TemoaModel'): - indices = set( - (r, p, i, t, v) - for r, p, i, t in M.minInputSplitAnnualVintages.keys() - if t not in M.tech_annual - for v in M.minInputSplitAnnualVintages[r, p, i, t] - ) - return indices - - -def MinTechOutputSplitConstraintIndices(M: 'TemoaModel'): - indices = set( - (r, p, s, d, t, v, o) - for r, p, t, o in M.minOutputSplitVintages.keys() - if t not in M.tech_annual - for v in M.minOutputSplitVintages[r, p, t, o] - for s in M.time_season[p] - for d in M.time_of_day - ) - ann_indices = set( - (r, p, t, o) - for r, p, t, o in M.minOutputSplitVintages.keys() - if t in M.tech_annual - ) - if len(ann_indices) > 0: - msg = ( - "Warning: Annual technologies included in TechOutputSplit table. " - "Use TechOutputSplitAnnual table instead or these constraints will be ignored: {}" - ) - logger.warning(msg.format(ann_indices)) - - return indices - - -def MinTechOutputSplitAnnualConstraintIndices(M: 'TemoaModel'): - indices = set( - (r, p, t, v, o) - for r, p, t, o in M.minOutputSplitAnnualVintages.keys() - if t in M.tech_annual - for v in M.minOutputSplitAnnualVintages[r, p, t, o] - ) - - return indices - - -def MinTechOutputSplitAverageConstraintIndices(M: 'TemoaModel'): - indices = set( - (r, p, t, v, o) - for r, p, t, o in M.minOutputSplitAnnualVintages.keys() - if t not in M.tech_annual - for v in M.minOutputSplitAnnualVintages[r, p, t, o] - ) - return indices - - -def MaxTechInputSplitConstraintIndices(M: 'TemoaModel'): +def LimitTechInputSplitConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, s, d, i, t, v) - for r, p, i, t in M.maxInputSplitVintages.keys() + for r, p, i, t in M.inputSplitVintages.keys() if t not in M.tech_annual - for v in M.maxInputSplitVintages[r, p, i, t] + for v in M.inputSplitVintages[r, p, i, t] for s in M.time_season[p] for d in M.time_of_day ) ann_indices = set( (r, p, i, t) - for r, p, i, t in M.maxInputSplitVintages.keys() + for r, p, i, t in M.inputSplitVintages.keys() if t in M.tech_annual ) if len(ann_indices) > 0: msg = ( - "Warning: Annual technologies included in TechInputSplit table. " - "Use TechInputSplitAnnual table instead or these constraints will be ignored: {}" + "Warning: Annual technologies included in LimitTechInputSplit table. " + "Use LimitTechInputSplitAnnual table instead or these constraints will be ignored: {}" ) logger.warning(msg.format(ann_indices)) return indices -def MaxTechInputSplitAnnualConstraintIndices(M: 'TemoaModel'): +def LimitTechInputSplitAnnualConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, i, t, v) - for r, p, i, t in M.maxInputSplitAnnualVintages.keys() + for r, p, i, t in M.inputSplitAnnualVintages.keys() if t in M.tech_annual - for v in M.maxInputSplitAnnualVintages[r, p, i, t] + for v in M.inputSplitAnnualVintages[r, p, i, t] ) return indices -def MaxTechInputSplitAverageConstraintIndices(M: 'TemoaModel'): +def LimitTechInputSplitAverageConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, i, t, v) - for r, p, i, t in M.maxInputSplitAnnualVintages.keys() + for r, p, i, t in M.inputSplitAnnualVintages.keys() if t not in M.tech_annual - for v in M.maxInputSplitAnnualVintages[r, p, i, t] + for v in M.inputSplitAnnualVintages[r, p, i, t] ) return indices -def MaxTechOutputSplitConstraintIndices(M: 'TemoaModel'): +def LimitTechOutputSplitConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, s, d, t, v, o) - for r, p, t, o in M.maxOutputSplitVintages.keys() + for r, p, t, o in M.outputSplitVintages.keys() if t not in M.tech_annual - for v in M.maxOutputSplitVintages[r, p, t, o] + for v in M.outputSplitVintages[r, p, t, o] for s in M.time_season[p] for d in M.time_of_day ) ann_indices = set( (r, p, t, o) - for r, p, t, o in M.maxOutputSplitVintages.keys() + for r, p, t, o in M.outputSplitVintages.keys() if t in M.tech_annual ) if len(ann_indices) > 0: msg = ( - "Warning: Annual technologies included in TechOutputSplit table. " - "Use TechOutputSplitAnnual table instead or these constraints will be ignored: {}" + "Warning: Annual technologies included in LimitTechOutputSplit table. " + "Use LimitTechOutputSplitAnnual table instead or these constraints will be ignored: {}" ) logger.warning(msg.format(ann_indices)) return indices -def MaxTechOutputSplitAnnualConstraintIndices(M: 'TemoaModel'): +def LimitTechOutputSplitAnnualConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, t, v, o) - for r, p, t, o in M.maxOutputSplitAnnualVintages.keys() + for r, p, t, o in M.outputSplitAnnualVintages.keys() if t in M.tech_annual - for v in M.maxOutputSplitAnnualVintages[r, p, t, o] + for v in M.outputSplitAnnualVintages[r, p, t, o] ) return indices -def MaxTechOutputSplitAverageConstraintIndices(M: 'TemoaModel'): +def LimitTechOutputSplitAverageConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, t, v, o) - for r, p, t, o in M.maxOutputSplitAnnualVintages.keys() + for r, p, t, o in M.outputSplitAnnualVintages.keys() if t not in M.tech_annual - for v in M.maxOutputSplitAnnualVintages[r, p, t, o] + for v in M.outputSplitAnnualVintages[r, p, t, o] ) return indices -def GrowthCapacityIndices(M: 'TemoaModel'): +def LimitGrowthCapacityIndices(M: 'TemoaModel'): indices = set( (r, p, t, op) - for r, t, op in M.GrowthCapacity.sparse_iterkeys() + for r, t, op in M.LimitGrowthCapacity.sparse_iterkeys() for p in M.time_optimize ) return indices -def DegrowthCapacityIndices(M: 'TemoaModel'): +def LimitDegrowthCapacityIndices(M: 'TemoaModel'): indices = set( (r, p, t, op) - for r, t, op in M.DegrowthCapacity.sparse_iterkeys() + for r, t, op in M.LimitDegrowthCapacity.sparse_iterkeys() for p in M.time_optimize ) return indices -def GrowthNewCapacityIndices(M: 'TemoaModel'): +def LimitGrowthNewCapacityIndices(M: 'TemoaModel'): indices = set( (r, p, t, op) - for r, t, op in M.GrowthNewCapacity.sparse_iterkeys() + for r, t, op in M.LimitGrowthNewCapacity.sparse_iterkeys() for p in M.time_optimize ) return indices -def DegrowthNewCapacityIndices(M: 'TemoaModel'): +def LimitDegrowthNewCapacityIndices(M: 'TemoaModel'): indices = set( (r, p, t, op) - for r, t, op in M.DegrowthNewCapacity.sparse_iterkeys() + for r, t, op in M.LimitDegrowthNewCapacity.sparse_iterkeys() for p in M.time_optimize ) return indices -def GrowthNewCapacityDeltaIndices(M: 'TemoaModel'): +def LimitGrowthNewCapacityDeltaIndices(M: 'TemoaModel'): indices = set( (r, p, t, op) - for r, t, op in M.GrowthNewCapacityDelta.sparse_iterkeys() + for r, t, op in M.LimitGrowthNewCapacityDelta.sparse_iterkeys() for p in M.time_optimize ) return indices -def DegrowthNewCapacityDeltaIndices(M: 'TemoaModel'): +def LimitDegrowthNewCapacityDeltaIndices(M: 'TemoaModel'): indices = set( (r, p, t, op) - for r, t, op in M.DegrowthNewCapacityDelta.sparse_iterkeys() + for r, t, op in M.LimitDegrowthNewCapacityDelta.sparse_iterkeys() for p in M.time_optimize ) return indices diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 01da1e69a..91eec5842 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -115,14 +115,10 @@ def __init__(M, *args, **kwargs): M.storageVintages = dict() M.rampUpVintages = dict() M.rampDownVintages = dict() - M.minInputSplitVintages = dict() - M.minInputSplitAnnualVintages = dict() - M.maxInputSplitVintages = dict() - M.maxInputSplitAnnualVintages = dict() - M.minOutputSplitVintages = dict() - M.minOutputSplitAnnualVintages = dict() - M.maxOutputSplitVintages = dict() - M.maxOutputSplitAnnualVintages = dict() + M.inputSplitVintages = dict() + M.inputSplitAnnualVintages = dict() + M.outputSplitVintages = dict() + M.outputSplitAnnualVintages = dict() M.processByPeriodAndOutput = dict() M.exportRegions = dict() M.importRegions = dict() @@ -268,7 +264,7 @@ def __init__(M, *args, **kwargs): M.initialize_Demands = BuildAction(rule=CreateDemands) # Dev Note: This parameter is currently NOT implemented. Preserved for later refactoring - # MaxResource IS implemented but sums cumulatively for a technology rather than resource commodity + # LimitResource IS implemented but sums cumulatively for a technology rather than resource commodity # M.ResourceConstraint_rpr = Set(within=M.regions * M.time_optimize * M.commodity_physical) # M.ResourceBound = Param(M.ResourceConstraint_rpr) @@ -328,18 +324,11 @@ def __init__(M, *args, **kwargs): M.LoanLifetimeProcess = Param(M.LoanLifetimeProcess_rtv, default=get_loan_life) - # Min tech input split - M.MinTechInputSplit = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all, validate=validate_0to1) - M.MinTechInputSplitAnnual = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all, validate=validate_0to1) - # Min tech output split - M.MinTechOutputSplit = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier, validate=validate_0to1) - M.MinTechOutputSplitAnnual = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier, validate=validate_0to1) - # Max tech input split - M.MaxTechInputSplit = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all, validate=validate_0to1) - M.MaxTechInputSplitAnnual = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all, validate=validate_0to1) - # Max tech output split - M.MaxTechOutputSplit = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier, validate=validate_0to1) - M.MaxTechOutputSplitAnnual = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier, validate=validate_0to1) + M.LimitTechInputSplit = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all, M.operator, validate=validate_0to1) + M.LimitTechInputSplitAnnual = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all, M.operator, validate=validate_0to1) + + M.LimitTechOutputSplit = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier, M.operator, validate=validate_0to1) + M.LimitTechOutputSplitAnnual = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier, M.operator, validate=validate_0to1) M.RenewablePortfolioStandardConstraint_rpg = Set( within=M.regions * M.time_optimize * M.tech_group_names @@ -400,135 +389,82 @@ def __init__(M, *args, **kwargs): M.ProcessLifeFrac_rptv = Set(dimen=4, initialize=ModelProcessLifeIndices) M.ProcessLifeFrac = Param(M.ProcessLifeFrac_rptv, initialize=ParamProcessLifeFraction_rule) - M.MinCapacityConstraint_rpt = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_with_capacity + M.LimitCapacityConstraint_rpt = Set( + within=M.regionalGlobalIndices * M.time_optimize * M.tech_with_capacity * M.operator ) + M.LimitCapacity = Param(M.LimitCapacityConstraint_rpt) - M.MinCapacity = Param(M.MinCapacityConstraint_rpt) - - M.MaxCapacityConstraint_rpt = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_with_capacity + M.LimitNewCapacityConstraint_rpt = Set( + within=M.regionalGlobalIndices * M.time_optimize * M.tech_with_capacity * M.operator ) - M.MaxCapacity = Param(M.MaxCapacityConstraint_rpt) + M.LimitNewCapacity = Param(M.LimitNewCapacityConstraint_rpt) - M.MinNewCapacityConstraint_rpt = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_with_capacity - ) - M.MinNewCapacity = Param(M.MinNewCapacityConstraint_rpt) + M.LimitResourceConstraint_rt = Set(within=M.regionalGlobalIndices * M.tech_all * M.operator) + M.LimitResource = Param(M.LimitResourceConstraint_rt) - M.MaxNewCapacityConstraint_rpt = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_with_capacity + M.LimitActivityConstraint_rpt = Set( + within=M.regionalGlobalIndices * M.time_optimize * M.tech_all * M.operator ) - M.MaxNewCapacity = Param(M.MaxNewCapacityConstraint_rpt) + M.LimitActivity = Param(M.LimitActivityConstraint_rpt) - M.MaxResourceConstraint_rt = Set(within=M.regionalGlobalIndices * M.tech_all) - M.MaxResource = Param(M.MaxResourceConstraint_rt) - - M.MaxActivityConstraint_rpt = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_all + M.LimitSeasonalActivityConstraint_rpst = Set( + within=M.regionalGlobalIndices * M.time_optimize * M.time_season_all * M.tech_all * M.operator ) - M.MaxActivity = Param(M.MaxActivityConstraint_rpt) + M.LimitSeasonalActivity = Param(M.LimitSeasonalActivityConstraint_rpst) - M.MinActivityConstraint_rpt = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_all + M.LimitAnnualCapacityFactorConstraint_rpto = Set( + within=M.regionalGlobalIndices * M.time_optimize * M.tech_all * M.commodity_carrier * M.operator ) - M.MinActivity = Param(M.MinActivityConstraint_rpt) - - M.MaxSeasonalActivityConstraint_rpst = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.time_season_all * M.tech_all - ) - M.MaxSeasonalActivity = Param(M.MaxSeasonalActivityConstraint_rpst) - - M.MinSeasonalActivityConstraint_rpst = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.time_season_all * M.tech_all - ) - M.MinSeasonalActivity = Param(M.MinSeasonalActivityConstraint_rpst) - - M.MinAnnualCapacityFactorConstraint_rpto = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_all * M.commodity_carrier - ) - M.MinAnnualCapacityFactor = Param(M.MinAnnualCapacityFactorConstraint_rpto) - - M.MaxAnnualCapacityFactorConstraint_rpto = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_all * M.commodity_carrier - ) - M.MaxAnnualCapacityFactor = Param(M.MaxAnnualCapacityFactorConstraint_rpto) + M.LimitAnnualCapacityFactor = Param(M.LimitAnnualCapacityFactorConstraint_rpto) - M.GrowthCapacity = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) - M.DegrowthCapacity = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) - M.GrowthNewCapacity = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) - M.DegrowthNewCapacity = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) - M.GrowthNewCapacityDelta = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) - M.DegrowthNewCapacityDelta = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) + M.LimitGrowthCapacity = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) + M.LimitDegrowthCapacity = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) + M.LimitGrowthNewCapacity = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) + M.LimitDegrowthNewCapacity = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) + M.LimitGrowthNewCapacityDelta = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) + M.LimitDegrowthNewCapacityDelta = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) - M.EmissionLimitConstraint_rpe = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.commodity_emissions + M.LimitEmissionConstraint_rpe = Set( + within=M.regionalGlobalIndices * M.time_optimize * M.commodity_emissions * M.operator ) - M.EmissionLimit = Param(M.EmissionLimitConstraint_rpe) + M.LimitEmission = Param(M.LimitEmissionConstraint_rpe) M.EmissionActivity_reitvo = Set(dimen=6, initialize=EmissionActivityIndices) M.EmissionActivity = Param(M.EmissionActivity_reitvo) - M.MinActivityGroup_rpg = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names - ) - M.MinActivityGroup = Param(M.MinActivityGroup_rpg) - - M.MaxActivityGroup_rpg = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names - ) - M.MaxActivityGroup = Param(M.MaxActivityGroup_rpg) - - M.MinCapacityGroupConstraint_rpg = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names + M.LimitActivityGroup_rpg = Set( + within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names * M.operator ) - M.MinCapacityGroup = Param(M.MinCapacityGroupConstraint_rpg) + M.LimitActivityGroup = Param(M.LimitActivityGroup_rpg) - M.MaxCapacityGroupConstraint_rpg = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names + M.LimitCapacityGroupConstraint_rpg = Set( + within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names * M.operator ) - M.MaxCapacityGroup = Param(M.MaxCapacityGroupConstraint_rpg) + M.LimitCapacityGroup = Param(M.LimitCapacityGroupConstraint_rpg) - M.MinNewCapacityGroupConstraint_rpg = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names + M.LimitNewCapacityGroupConstraint_rpg = Set( + within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names * M.operator ) - M.MinNewCapacityGroup = Param(M.MinNewCapacityGroupConstraint_rpg) + M.LimitNewCapacityGroup = Param(M.LimitNewCapacityGroupConstraint_rpg) + M.GroupShareIndices = Set(dimen=5, initialize=GroupShareIndices) - M.MaxNewCapacityGroupConstraint_rpg = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names - ) - M.MaxNewCapacityGroup = Param(M.MaxNewCapacityGroupConstraint_rpg) - M.GroupShareIndices = Set(dimen=4, initialize=GroupShareIndices) + M.LimitCapacityShareConstraint_rptg = Set(within=M.GroupShareIndices) + M.LimitCapacityShare = Param(M.GroupShareIndices) - M.MinCapacityShareConstraint_rptg = Set(within=M.GroupShareIndices) - M.MinCapacityShare = Param(M.GroupShareIndices) + M.LimitActivityShareConstraint_rptg = Set(within=M.GroupShareIndices) + M.LimitActivityShare = Param(M.GroupShareIndices) - M.MaxCapacityShareConstraint_rptg = Set(within=M.GroupShareIndices) - M.MaxCapacityShare = Param(M.GroupShareIndices) + M.LimitNewCapacityShareConstraint_rptg = Set(within=M.GroupShareIndices) + M.LimitNewCapacityShare = Param(M.GroupShareIndices) - M.MinActivityShareConstraint_rptg = Set(within=M.GroupShareIndices) - M.MinActivityShare = Param(M.GroupShareIndices) - - M.MaxActivityShareConstraint_rptg = Set(within=M.GroupShareIndices) - M.MaxActivityShare = Param(M.GroupShareIndices) - - M.MinNewCapacityShareConstraint_rptg = Set(within=M.GroupShareIndices) - M.MinNewCapacityShare = Param(M.GroupShareIndices) - - M.MaxNewCapacityShareConstraint_rptg = Set(within=M.GroupShareIndices) - M.MaxNewCapacityShare = Param(M.GroupShareIndices) - - M.TwoGroupShareIndices = Set(dimen=4, initialize=TwoGroupShareIndices) - - M.MinNewCapacityGroupShareConstraint_rpgg = Set(within=M.TwoGroupShareIndices) - M.MinNewCapacityGroupShare = Param(M.TwoGroupShareIndices) + M.TwoGroupShareIndices = Set(dimen=5, initialize=TwoGroupShareIndices) - M.MaxNewCapacityGroupShareConstraint_rpgg = Set(within=M.TwoGroupShareIndices) - M.MaxNewCapacityGroupShare = Param(M.TwoGroupShareIndices) + M.LimitNewCapacityGroupShareConstraint_rpgg = Set(within=M.TwoGroupShareIndices) + M.LimitNewCapacityGroupShare = Param(M.TwoGroupShareIndices) # This set works for all storage-related constraints M.StorageConstraints_rpsdtv = Set(dimen=6, initialize=StorageConstraintIndices) - M.StorageFractionConstraint_rpsdtv = Set(within=M.StorageConstraints_rpsdtv) - M.StorageFraction = Param(M.StorageConstraints_rpsdtv, validate=validate_0to1) + M.LimitStorageFractionConstraint_rpsdtv = Set(within=M.StorageConstraints_rpsdtv * M.operator) + M.LimitStorageFraction = Param(M.LimitStorageFractionConstraint_rpsdtv, validate=validate_0to1) # Storage duration is expressed in hours M.StorageDuration = Param(M.regions, M.tech_storage, default=4) @@ -720,8 +656,8 @@ def __init__(M, *args, **kwargs): M.StorageConstraints_rpsdtv, rule=StorageThroughput_Constraint ) - M.StorageFractionConstraint = Constraint( - M.StorageFractionConstraint_rpsdtv, rule=StorageFraction_Constraint + M.LimitStorageFractionConstraint = Constraint( + M.LimitStorageFractionConstraint_rpsdtv, rule=LimitStorageFraction_Constraint ) M.RampUpConstraint_rpsdtv = Set(dimen=6, initialize=RampUpConstraintIndices) @@ -732,229 +668,138 @@ def __init__(M, *args, **kwargs): M.ReserveMargin_rpsd = Set(dimen=4, initialize=ReserveMarginIndices) M.ReserveMarginConstraint = Constraint(M.ReserveMargin_rpsd, rule=ReserveMargin_Constraint) - M.EmissionLimitConstraint = Constraint( - M.EmissionLimitConstraint_rpe, rule=EmissionLimit_Constraint + M.LimitEmissionConstraint = Constraint( + M.LimitEmissionConstraint_rpe, rule=LimitEmission_Constraint ) M.progress_marker_7 = BuildAction( - ['Starting Growth and Activity Constraints'], rule=progress_check - ) - - M.GrowthCapacityConstraint_rtpop = Set(dimen=4, initialize=GrowthCapacityIndices) - M.GrowthCapacityConstraint = Constraint( - M.GrowthCapacityConstraint_rtpop, rule=GrowthCapacityConstraint_rule - ) - M.DegrowthCapacityConstraint_rtpop = Set(dimen=4, initialize=DegrowthCapacityIndices) - M.DegrowthCapacityConstraint = Constraint( - M.DegrowthCapacityConstraint_rtpop, rule=DegrowthCapacityConstraint_rule + ['Starting LimitGrowth and Activity Constraints'], rule=progress_check ) - M.GrowthNewCapacityConstraint_rtpop = Set(dimen=4, initialize=GrowthNewCapacityIndices) - M.GrowthNewCapacityConstraint = Constraint( - M.GrowthNewCapacityConstraint_rtpop, rule=GrowthNewCapacityConstraint_rule + M.LimitGrowthCapacityConstraint_rpt = Set(dimen=4, initialize=LimitGrowthCapacityIndices) + M.LimitGrowthCapacityConstraint = Constraint( + M.LimitGrowthCapacityConstraint_rpt, rule=LimitGrowthCapacityConstraint_rule ) - M.DegrowthNewCapacityConstraint_rtpop = Set(dimen=4, initialize=DegrowthNewCapacityIndices) - M.DegrowthNewCapacityConstraint = Constraint( - M.DegrowthNewCapacityConstraint_rtpop, rule=DegrowthNewCapacityConstraint_rule + M.LimitDegrowthCapacityConstraint_rpt = Set(dimen=4, initialize=LimitDegrowthCapacityIndices) + M.LimitDegrowthCapacityConstraint = Constraint( + M.LimitDegrowthCapacityConstraint_rpt, rule=LimitDegrowthCapacityConstraint_rule ) - M.GrowthNewCapacityDeltaConstraint_rtpop = Set(dimen=4, initialize=GrowthNewCapacityDeltaIndices) - M.GrowthNewCapacityDeltaConstraint = Constraint( - M.GrowthNewCapacityDeltaConstraint_rtpop, rule=GrowthNewCapacityDeltaConstraint_rule + M.LimitGrowthNewCapacityConstraint_rpt = Set(dimen=4, initialize=LimitGrowthNewCapacityIndices) + M.LimitGrowthNewCapacityConstraint = Constraint( + M.LimitGrowthNewCapacityConstraint_rpt, rule=LimitGrowthNewCapacityConstraint_rule ) - M.DegrowthNewCapacityDeltaConstraint_rtpop = Set(dimen=4, initialize=DegrowthNewCapacityDeltaIndices) - M.DegrowthNewCapacityDeltaConstraint = Constraint( - M.DegrowthNewCapacityDeltaConstraint_rtpop, rule=DegrowthNewCapacityDeltaConstraint_rule + M.LimitDegrowthNewCapacityConstraint_rpt = Set(dimen=4, initialize=LimitDegrowthNewCapacityIndices) + M.LimitDegrowthNewCapacityConstraint = Constraint( + M.LimitDegrowthNewCapacityConstraint_rpt, rule=LimitDegrowthNewCapacityConstraint_rule ) - M.MaxActivityConstraint = Constraint( - M.MaxActivityConstraint_rpt, rule=MaxActivity_Constraint + M.LimitGrowthNewCapacityDeltaConstraint_rpt = Set(dimen=4, initialize=LimitGrowthNewCapacityDeltaIndices) + M.LimitGrowthNewCapacityDeltaConstraint = Constraint( + M.LimitGrowthNewCapacityDeltaConstraint_rpt, rule=LimitGrowthNewCapacityDeltaConstraint_rule ) - - M.MinActivityConstraint = Constraint( - M.MinActivityConstraint_rpt, rule=MinActivity_Constraint - ) - - M.MaxSeasonalActivityConstraint = Constraint( - M.MaxSeasonalActivityConstraint_rpst, rule=MaxSeasonalActivity_Constraint - ) - - M.MinSeasonalActivityConstraint = Constraint( - M.MinSeasonalActivityConstraint_rpst, rule=MinSeasonalActivity_Constraint - ) - - M.MinActivityGroupConstraint = Constraint( - M.MinActivityGroup_rpg, rule=MinActivityGroup_Constraint + M.LimitDegrowthNewCapacityDeltaConstraint_rpt = Set(dimen=4, initialize=LimitDegrowthNewCapacityDeltaIndices) + M.LimitDegrowthNewCapacityDeltaConstraint = Constraint( + M.LimitDegrowthNewCapacityDeltaConstraint_rpt, rule=LimitDegrowthNewCapacityDeltaConstraint_rule ) - M.MaxActivityGroupConstraint = Constraint( - M.MaxActivityGroup_rpg, rule=MaxActivityGroup_Constraint + M.LimitActivityConstraint = Constraint( + M.LimitActivityConstraint_rpt, rule=LimitActivity_Constraint ) - M.MaxCapacityConstraint = Constraint( - M.MaxCapacityConstraint_rpt, rule=MaxCapacity_Constraint + M.LimitSeasonalActivityConstraint = Constraint( + M.LimitSeasonalActivityConstraint_rpst, rule=LimitSeasonalActivity_Constraint ) - M.MaxNewCapacityConstraint = Constraint( - M.MaxNewCapacityConstraint_rpt, rule=MaxNewCapacity_Constraint + M.LimitActivityGroupConstraint = Constraint( + M.LimitActivityGroup_rpg, rule=LimitActivityGroup_Constraint ) - M.MaxCapacityGroupConstraint = Constraint( - M.MaxCapacityGroupConstraint_rpg, rule=MaxCapacityGroup_Constraint + M.LimitCapacityConstraint = Constraint( + M.LimitCapacityConstraint_rpt, rule=LimitCapacity_Constraint ) - M.MinCapacityGroupConstraint = Constraint( - M.MinCapacityGroupConstraint_rpg, rule=MinCapacityGroup_Constraint + M.LimitNewCapacityConstraint = Constraint( + M.LimitNewCapacityConstraint_rpt, rule=LimitNewCapacity_Constraint ) - M.MinNewCapacityGroupConstraint = Constraint( - M.MinNewCapacityGroupConstraint_rpg, rule=MinNewCapacityGroup_Constraint + M.LimitCapacityGroupConstraint = Constraint( + M.LimitCapacityGroupConstraint_rpg, rule=LimitCapacityGroup_Constraint ) - M.MaxNewCapacityGroupConstraint = Constraint( - M.MinNewCapacityGroupConstraint_rpg, rule=MaxNewCapacityGroup_Constraint + M.LimitNewCapacityGroupConstraint = Constraint( + M.LimitNewCapacityGroupConstraint_rpg, rule=LimitNewCapacityGroup_Constraint ) - M.MinCapacityShareConstraint = Constraint( - M.MinCapacityShareConstraint_rptg, rule=MinCapacityShare_Constraint + M.LimitCapacityShareConstraint = Constraint( + M.LimitCapacityShareConstraint_rptg, rule=LimitCapacityShare_Constraint ) - M.MaxCapacityShareConstraint = Constraint( - M.MaxCapacityShareConstraint_rptg, rule=MaxCapacityShare_Constraint + M.LimitActivityShareConstraint = Constraint( + M.LimitActivityShareConstraint_rptg, rule=LimitActivityShare_Constraint ) - M.MinActivityShareConstraint = Constraint( - M.MinActivityShareConstraint_rptg, rule=MinActivityShare_Constraint - ) - - M.MaxActivityShareConstraint = Constraint( - M.MaxActivityShareConstraint_rptg, rule=MaxActivityShare_Constraint - ) - - M.MinNewCapacityShareConstraint = Constraint( - M.MinNewCapacityShareConstraint_rptg, rule=MinNewCapacityShare_Constraint - ) - - M.MaxNewCapacityShareConstraint = Constraint( - M.MaxNewCapacityShareConstraint_rptg, rule=MaxNewCapacityShare_Constraint - ) - - M.MinNewCapacityGroupShareConstraint = Constraint( - M.MinNewCapacityGroupShareConstraint_rpgg, rule=MinNewCapacityGroupShare_Constraint - ) - M.MaxNewCapacityGroupShareConstraint = Constraint( - M.MaxNewCapacityGroupShareConstraint_rpgg, rule=MaxNewCapacityGroupShare_Constraint - ) - - M.progress_marker_8 = BuildAction( - ['Starting Max/Min Capacity and Tech Split ' 'Constraints'], rule=progress_check - ) - - M.MaxResourceConstraint = Constraint( - M.MaxResourceConstraint_rt, rule=MaxResource_Constraint - ) - - M.MinCapacityConstraint = Constraint( - M.MinCapacityConstraint_rpt, rule=MinCapacity_Constraint - ) - - M.MinNewCapacityConstraint = Constraint( - M.MinNewCapacityConstraint_rpt, rule=MinNewCapacity_Constraint - ) - - M.MinAnnualCapacityFactorConstraint = Constraint( - M.MinAnnualCapacityFactorConstraint_rpto, rule=MinAnnualCapacityFactor_Constraint - ) - - M.MaxAnnualCapacityFactorConstraint = Constraint( - M.MaxAnnualCapacityFactorConstraint_rpto, rule=MaxAnnualCapacityFactor_Constraint + M.LimitNewCapacityShareConstraint = Constraint( + M.LimitNewCapacityShareConstraint_rptg, rule=LimitNewCapacityShare_Constraint ) - ## Min tech input splits - M.MinTechInputSplitConstraint_rpsditv = Set( - dimen=7, initialize=MinTechInputSplitConstraintIndices - ) - M.MinTechInputSplitConstraint = Constraint( - M.MinTechInputSplitConstraint_rpsditv, rule=MinTechInputSplit_Constraint - ) - - M.MinTechInputSplitAnnualConstraint_rpitv = Set( - dimen=5, initialize=MinTechInputSplitAnnualConstraintIndices - ) - M.MinTechInputSplitAnnualConstraint = Constraint( - M.MinTechInputSplitAnnualConstraint_rpitv, rule=MinTechInputSplitAnnual_Constraint - ) - - M.MinTechInputSplitAverageConstraint_rpitv = Set( - dimen=5, initialize=MinTechInputSplitAverageConstraintIndices - ) - M.MinTechInputSplitAverageConstraint = Constraint( - M.MinTechInputSplitAverageConstraint_rpitv, rule=MinTechInputSplitAverage_Constraint + M.LimitNewCapacityGroupShareConstraint = Constraint( + M.LimitNewCapacityGroupShareConstraint_rpgg, rule=LimitNewCapacityGroupShare_Constraint ) - ## Min tech output splits - M.MinTechOutputSplitConstraint_rpsdtvo = Set( - dimen=7, initialize=MinTechOutputSplitConstraintIndices - ) - M.MinTechOutputSplitConstraint = Constraint( - M.MinTechOutputSplitConstraint_rpsdtvo, rule=MinTechOutputSplit_Constraint + M.progress_marker_8 = BuildAction( + ['Starting Limit Capacity and Tech Split ' 'Constraints'], rule=progress_check ) - M.MinTechOutputSplitAnnualConstraint_rptvo = Set( - dimen=5, initialize=MinTechOutputSplitAnnualConstraintIndices - ) - M.MinTechOutputSplitAnnualConstraint = Constraint( - M.MinTechOutputSplitAnnualConstraint_rptvo, rule=MinTechOutputSplitAnnual_Constraint + M.LimitResourceConstraint = Constraint( + M.LimitResourceConstraint_rt, rule=LimitResource_Constraint ) - M.MinTechOutputSplitAverageConstraint_rptvo = Set( - dimen=5, initialize=MinTechOutputSplitAverageConstraintIndices - ) - M.MinTechOutputSplitAverageConstraint = Constraint( - M.MinTechOutputSplitAverageConstraint_rptvo, rule=MinTechOutputSplitAverage_Constraint + M.LimitAnnualCapacityFactorConstraint = Constraint( + M.LimitAnnualCapacityFactorConstraint_rpto, rule=LimitAnnualCapacityFactor_Constraint ) - ## Max tech input splits - M.MaxTechInputSplitConstraint_rpsditv = Set( - dimen=7, initialize=MaxTechInputSplitConstraintIndices + ## Tech input splits + M.LimitTechInputSplitConstraint_rpsditv = Set( + dimen=7, initialize=LimitTechInputSplitConstraintIndices ) - M.MaxTechInputSplitConstraint = Constraint( - M.MaxTechInputSplitConstraint_rpsditv, rule=MaxTechInputSplit_Constraint + M.LimitTechInputSplitConstraint = Constraint( + M.LimitTechInputSplitConstraint_rpsditv, rule=LimitTechInputSplit_Constraint ) - M.MaxTechInputSplitAnnualConstraint_rpitv = Set( - dimen=5, initialize=MaxTechInputSplitAnnualConstraintIndices + M.LimitTechInputSplitAnnualConstraint_rpitv = Set( + dimen=5, initialize=LimitTechInputSplitAnnualConstraintIndices ) - M.MaxTechInputSplitAnnualConstraint = Constraint( - M.MaxTechInputSplitAnnualConstraint_rpitv, rule=MaxTechInputSplitAnnual_Constraint + M.LimitTechInputSplitAnnualConstraint = Constraint( + M.LimitTechInputSplitAnnualConstraint_rpitv, rule=LimitTechInputSplitAnnual_Constraint ) - M.MaxTechInputSplitAverageConstraint_rpitv = Set( - dimen=5, initialize=MaxTechInputSplitAverageConstraintIndices + M.LimitTechInputSplitAverageConstraint_rpitv = Set( + dimen=5, initialize=LimitTechInputSplitAverageConstraintIndices ) - M.MaxTechInputSplitAverageConstraint = Constraint( - M.MaxTechInputSplitAverageConstraint_rpitv, rule=MaxTechInputSplitAverage_Constraint + M.LimitTechInputSplitAverageConstraint = Constraint( + M.LimitTechInputSplitAverageConstraint_rpitv, rule=LimitTechInputSplitAverage_Constraint ) - ## Max tech output splits - M.MaxTechOutputSplitConstraint_rpsdtvo = Set( - dimen=7, initialize=MaxTechOutputSplitConstraintIndices + ## Tech output splits + M.LimitTechOutputSplitConstraint_rpsdtvo = Set( + dimen=7, initialize=LimitTechOutputSplitConstraintIndices ) - M.MaxTechOutputSplitConstraint = Constraint( - M.MaxTechOutputSplitConstraint_rpsdtvo, rule=MaxTechOutputSplit_Constraint + M.LimitTechOutputSplitConstraint = Constraint( + M.LimitTechOutputSplitConstraint_rpsdtvo, rule=LimitTechOutputSplit_Constraint ) - M.MaxTechOutputSplitAnnualConstraint_rptvo = Set( - dimen=5, initialize=MaxTechOutputSplitAnnualConstraintIndices + M.LimitTechOutputSplitAnnualConstraint_rptvo = Set( + dimen=5, initialize=LimitTechOutputSplitAnnualConstraintIndices ) - M.MaxTechOutputSplitAnnualConstraint = Constraint( - M.MaxTechOutputSplitAnnualConstraint_rptvo, rule=MaxTechOutputSplitAnnual_Constraint + M.LimitTechOutputSplitAnnualConstraint = Constraint( + M.LimitTechOutputSplitAnnualConstraint_rptvo, rule=LimitTechOutputSplitAnnual_Constraint ) - M.MaxTechOutputSplitAverageConstraint_rptvo = Set( - dimen=5, initialize=MaxTechOutputSplitAverageConstraintIndices + M.LimitTechOutputSplitAverageConstraint_rptvo = Set( + dimen=5, initialize=LimitTechOutputSplitAverageConstraintIndices ) - M.MaxTechOutputSplitAverageConstraint = Constraint( - M.MaxTechOutputSplitAverageConstraint_rptvo, rule=MaxTechOutputSplitAverage_Constraint + M.LimitTechOutputSplitAverageConstraint = Constraint( + M.LimitTechOutputSplitAverageConstraint_rptvo, rule=LimitTechOutputSplitAverage_Constraint ) M.RenewablePortfolioStandardConstraint = Constraint( diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 7c81600e0..a748ba1c8 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -217,7 +217,7 @@ def CapacityAvailableByPeriodAndTech_Constraint(M: 'TemoaModel', r, p, t): r""" The :math:`\textbf{CAPAVL}` variable is nominally for reporting solution values, -but is also used in the Max and Min constraint calculations. For any process +but is also used in the Limit constraint calculations. For any process with an end-of-life (EOL) on a period boundary, all of its capacity is available for use in all periods in which it is active (the process' PLF is 1). However, for any process with an EOL that falls between periods, Temoa makes the @@ -1127,7 +1127,7 @@ def ResourceExtraction_Constraint(M: 'TemoaModel', reg, p, r): # dev note: This constraint does not have a table in the current schema # Additionally, the below (incorrect) construct assumes that a resource cannot be used # by BOTH a non-annual and annual tech. It should be re-written to add these - # dev note: Cant think of a case where this would be needed but cant use MaxActivityGroup + # dev note: Cant think of a case where this would be needed but cant use LimitActivityGroup try: collected = sum( M.V_FlowOut[reg, p, S_s, S_d, S_i, S_t, S_v, r] # is r the input or the output!? @@ -1427,7 +1427,7 @@ def StorageThroughput_Constraint(M: 'TemoaModel', r, p, s, d, t, v): return expr -def StorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v): +def LimitStorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v, op): r""" This constraint is used if the users wishes to force a specific storage charge level @@ -1442,7 +1442,7 @@ def StorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v): .. math:: - :label: StorageFraction + :label: LimitStorageFraction \textbf{SF}_{r,p,s,d,t,v} \le \ SF_{r,p,s,d,t,v} @@ -1451,7 +1451,7 @@ def StorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v): \cdot \sum_{d} SEG_{s,d} \cdot 365 days/yr \cdot MPL_{r,p,t,v} \\ - \forall \{r, p, s, d, t, v\} \in \Theta_{\text{StorageFraction}} + \forall \{r, p, s, d, t, v\} \in \Theta_{\text{LimitStorageFraction}} """ energy_capacity = ( @@ -1463,7 +1463,7 @@ def StorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v): * value(M.ProcessLifeFrac[r, p, t, v]) ) - expr = M.V_StorageLevel[r, p, s, d, t, v] == energy_capacity * value(M.StorageFraction[r, p, s, d, t, v]) + expr = operator_expression(M.V_StorageLevel[r, p, s, d, t, v], op, energy_capacity * value(M.LimitStorageFraction[r, p, s, d, t, v, op])) return expr @@ -1732,19 +1732,19 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): return cap_avail >= cap_target -def EmissionLimit_Constraint(M: 'TemoaModel', r, p, e): +def LimitEmission_Constraint(M: 'TemoaModel', r, p, e, op): r""" A modeler can track emissions through use of the :code:`commodity_emissions` set and :code:`EmissionActivity` parameter. The :math:`EAC` parameter is analogous to the efficiency table, tying emissions to a unit of activity. The - EmissionLimit constraint allows the modeler to assign an upper bound per period + LimitEmission constraint allows the modeler to assign an upper bound per period to each emission commodity. Note that this constraint sums emissions from technologies with output varying at the time slice and those with constant annual output in separate terms. .. math:: - :label: EmissionLimit + :label: LimitEmission \sum_{S,D,I,T,V,O|{r,e,i,t,v,o} \in EAC} \left ( EAC_{r, e, i, t, v, o} \cdot \textbf{FO}_{r, p, s, d, i, t, v, o} @@ -1757,10 +1757,10 @@ def EmissionLimit_Constraint(M: 'TemoaModel', r, p, e): ELM_{r, p, e} \\ - & \forall \{r, p, e\} \in \Theta_{\text{EmissionLimit}} + & \forall \{r, p, e\} \in \Theta_{\text{LimitEmission}} """ - emission_limit = value(M.EmissionLimit[r, p, e]) + emission_limit = value(M.LimitEmission[r, p, e, op]) # 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 @@ -1814,13 +1814,13 @@ def EmissionLimit_Constraint(M: 'TemoaModel', r, p, e): if S_r == reg and S_e == e ) - expr = ( + lhs = ( process_emissions + process_emissions_annual + embodied_emissions + retirement_emissions # + emissions_flex # NO! flex is subtracted from flowout, already accounted by flowout # + emissions_curtail # NO! curtailed flows are not actual flows, just an accounting tool # + emissions_flex_annual # NO! flexannual is subtracted from flowoutannual, already accounted - <= emission_limit ) + expr = operator_expression(lhs, op, emission_limit) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated @@ -1834,15 +1834,15 @@ def EmissionLimit_Constraint(M: 'TemoaModel', r, p, e): return expr -def GrowthCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): +def LimitGrowthCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): r"""Constrain ramp down rate of available capacity""" - return GrowthCapacity(M, r, p, t, op, False) + return LimitGrowthCapacity(M, r, p, t, op, False) -def DegrowthCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): +def LimitDegrowthCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): r"""Constrain ramp up rate of available capacity""" - return GrowthCapacity(M, r, p, t, op, True) + return LimitGrowthCapacity(M, r, p, t, op, True) -def GrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): +def LimitGrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): r""" Constrain the change of capacity available between periods. Forces the model to ramp up and down the availability of new technologies @@ -1853,7 +1853,7 @@ def GrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): regions = gather_group_regions(M, r) - growth = M.DegrowthCapacity if degrowth else M.GrowthCapacity + growth = M.LimitDegrowthCapacity if degrowth else M.LimitGrowthCapacity RATE = 1 + value(growth[r, t, op][0]) SEED = value(growth[r, t, op][1]) CapRPT = M.V_CapacityAvailableByPeriodAndTech @@ -1922,15 +1922,15 @@ def GrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): return expr -def GrowthNewCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): +def LimitGrowthNewCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): r"""Constrain ramp down rate of new capacity deployment""" - return GrowthNewCapacity(M, r, p, t, op, False) + return LimitGrowthNewCapacity(M, r, p, t, op, False) -def DegrowthNewCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): +def LimitDegrowthNewCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): r"""Constrain ramp up rate of new capacity deployment""" - return GrowthNewCapacity(M, r, p, t, op, True) + return LimitGrowthNewCapacity(M, r, p, t, op, True) -def GrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): +def LimitGrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): r""" Constrain the change of new capacity deployed between periods. Forces the model to ramp up and down the deployment of new technologies @@ -1941,7 +1941,7 @@ def GrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): regions = gather_group_regions(M, r) - growth = M.DegrowthNewCapacity if degrowth else M.GrowthNewCapacity + growth = M.LimitDegrowthNewCapacity if degrowth else M.LimitGrowthNewCapacity RATE = 1 + value(growth[r, t, op][0]) SEED = value(growth[r, t, op][1]) NewCapRTV = M.V_NewCapacity @@ -2008,15 +2008,15 @@ def GrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): return expr -def GrowthNewCapacityDeltaConstraint_rule(M: 'TemoaModel', r, p, t, op): +def LimitGrowthNewCapacityDeltaConstraint_rule(M: 'TemoaModel', r, p, t, op): r"""Constrain ramp down rate of change in new capacity deployment""" - return GrowthNewCapacityDelta(M, r, p, t, op, False) + return LimitGrowthNewCapacityDelta(M, r, p, t, op, False) -def DegrowthNewCapacityDeltaConstraint_rule(M: 'TemoaModel', r, p, t, op): +def LimitDegrowthNewCapacityDeltaConstraint_rule(M: 'TemoaModel', r, p, t, op): r"""Constrain ramp up rate of change in new capacity deployment""" - return GrowthNewCapacityDelta(M, r, p, t, op, True) + return LimitGrowthNewCapacityDelta(M, r, p, t, op, True) -def GrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): +def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): r""" Constrain the acceleration of new capacity deployed between periods. Forces the model to ramp up and down the change in deployment of new technologies @@ -2027,7 +2027,7 @@ def GrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = False) regions = gather_group_regions(M, r) - growth = M.DegrowthNewCapacityDelta if degrowth else M.GrowthNewCapacityDelta + growth = M.LimitDegrowthNewCapacityDelta if degrowth else M.LimitGrowthNewCapacityDelta RATE = 1 + value(growth[r, t, op][0]) SEED = value(growth[r, t, op][1]) NewCapRTV = M.V_NewCapacity @@ -2120,10 +2120,10 @@ def GrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = False) return expr -def MaxActivity_Constraint(M: 'TemoaModel', r, p, t): +def LimitActivity_Constraint(M: 'TemoaModel', r, p, t, op): r""" - The MaxActivity sets an upper bound on the activity from a specific technology. + Sets a limit on the activity from a specific technology. Note that the indices for these constraints are region, period and tech, not tech and vintage. The first version of the constraint pertains to technologies with variable output at the time slice level, and the second version pertains to @@ -2131,15 +2131,15 @@ def MaxActivity_Constraint(M: 'TemoaModel', r, p, t): set. .. math:: - :label: MaxActivity + :label: LimitActivity \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le MAA_{r, p, t} - \forall \{r, p, t\} \in \Theta_{\text{MaxActivity}} + \forall \{r, p, t\} \in \Theta_{\text{LimitActivity}} \sum_{I,V,O} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} \le MAA_{r, p, t} - \forall \{r, p, t \in T^{a}\} \in \Theta_{\text{MaxActivity}} + \forall \{r, p, t \in T^{a}\} \in \Theta_{\text{LimitActivity}} """ # r can be an individual region (r='US'), or a combination of regions separated by # a + (r='Mexico+US+Canada'), or 'global'. @@ -2167,33 +2167,33 @@ def MaxActivity_Constraint(M: 'TemoaModel', r, p, t): if (_r, p, S_i, t, S_v, S_o) in M.V_FlowOutAnnual ) - max_act = value(M.MaxActivity[r, p, t]) - expr = activity_rpt <= max_act + act_lim = value(M.LimitActivity[r, p, t, op]) + expr = operator_expression(activity_rpt, op, act_lim) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated return Constraint.Skip return expr -def MaxSeasonalActivity_Constraint(M: 'TemoaModel', r, p, s, t): +def LimitSeasonalActivity_Constraint(M: 'TemoaModel', r, p, s, t, op): r""" - The MaxSeasonalActivity sets an upper bound on the activity from a specific technology. + Sets a limit on the activity from a specific technology. Note that the indices for these constraints are region, period, season, and tech. The first component of the constraint pertains to technologies with variable output at the time slice level, and the second component pertains to technologies with constant annual output belonging to the :code:`tech_annual` set. .. math:: - :label: MaxSeasonalActivity - \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le MAXSSNACT_{r, p, s, t} - \forall \{r, p, s, t\} \in \Theta_{\text{MaxSeasonalActivity}} - \sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \le MAXSSNACT_{r, p, s, t} - \forall \{r, p, s, t \in T^{a}\} \in \Theta_{\text{MaxSeasonalActivity}} + :label: LimitSeasonalActivity + \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMSSNACT_{r, p, s, t} + \forall \{r, p, s, t\} \in \Theta_{\text{LimitSeasonalActivity}} + \sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \le LIMSSNACT_{r, p, s, t} + \forall \{r, p, s, t \in T^{a}\} \in \Theta_{\text{LimitSeasonalActivity}} """ # Notice that this constraint follows the implementation of the - # MaxActivity_Constraint(). The difference is that this function is defined + # LimitActivity_Constraint(). The difference is that this function is defined # over each representative day, or "season", as opposed to the entire # year, or "period". @@ -2215,134 +2215,15 @@ def MaxSeasonalActivity_Constraint(M: 'TemoaModel', r, p, s, t): ) except: msg = ( - "\nWarning: MaxSeasonalActivity constraint can not be defined for " + "\nWarning: LimitSeasonalActivity constraint can not be defined for " "technologies in \"tech_annual\". Continuing by ignoring the constraint " "for '%s'.\n " ) SE.write(msg % (t)) return Constraint.Skip - max_act = value(M.MaxSeasonalActivity[r, p, s, t]) - expr = activity_rpst <= max_act - - # in the case that there is nothing to sum, skip - if isinstance(expr, bool): # an empty list was generated - return Constraint.Skip - - return expr - - -def MinActivity_Constraint(M: 'TemoaModel', r, p, t): - r""" - - The MinActivity sets a lower bound on the activity from a specific technology. - Note that the indices for these constraints are region, period and tech, not tech and - vintage. The first version of the constraint pertains to technologies with - variable output at the time slice level, and the second version pertains to - technologies with constant annual output belonging to the :code:`tech_annual` - set. - - .. math:: - :label: MinActivity - - \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \ge MIA_{r, p, t} - - \forall \{r, p, t\} \in \Theta_{\text{MinActivity}} - - \sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \ge MIA_{r, p, t} - - \forall \{r, p, t \in T^{a}\} \in \Theta_{\text{MinActivity}} - """ - # r can be an individual region (r='US'), or a combination of regions separated by - # a + (r='Mexico+US+Canada'), or 'global'. - # if r == 'global', the constraint is system-wide - regions = gather_group_regions(M, r) - - if t not in M.tech_annual: - activity_rpt = sum( - M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] - for _r in regions - for S_v in M.processVintages.get((_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[p] - for d in M.time_of_day - if (_r, p, s, d, S_i, t, S_v, S_o) in M.V_FlowOut - ) - else: - activity_rpt = sum( - M.V_FlowOutAnnual[_r, p, S_i, t, S_v, S_o] - for _r in regions - for S_v in M.processVintages.get((_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] - if (_r, p, S_i, t, S_v, S_o) in M.V_FlowOutAnnual - ) - - min_act = value(M.MinActivity[r, p, t]) - expr = activity_rpt >= min_act - # in the case that there is nothing to sum, skip - if isinstance(expr, bool): # an empty list was generated - logger.error( - 'No elements available to support min-activity: (%s, %d, %s).' - ' Check data/log for available/suppressed techs. Requirement IGNORED.', - r, - p, - t, - ) - return Constraint.Skip - return expr - - -def MinSeasonalActivity_Constraint(M: 'TemoaModel', r, p, s, t): - - r""" - The MinSeasonalActivity sets a lower bound on the activity from a specific technology - over a specific season. Note that the indices for these constraints are region, - period, season and tech, not tech and vintage. The first version of the constraint - pertains to technologies with variable output at the time slice level, and the - second version pertains to technologies with constant annual output belonging to - the :code:`tech_annual` set. - .. math:: - :label: MinSeasonalActivity - \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \ge MINSSNACT_{r, p, t} - \forall \{r, p, s, t\} \in \Theta_{\text{MinSeasonalActivity}} - \sum_{I,V,O} \textbf{FOA}_{r, p, s, i, t, v, o} \ge MINSSNACT_{r, p, s, t} - \forall \{r, p, s, t \in T^{a}\} \in \Theta_{\text{MinSeasonalActivity}} - """ - - # Notice that this constraint follows the implementation of the - # MinActivity_Constraint(). The difference is that this function is defined - # over each representative day, or "season", as opposed to the entire - # year, or "period". - - # The V_FlowOut variable is scaled by the weights of each representative day. - # In order to determine the daily, or "seasonal", flow, the V_FLowOut variable - # must be converted back to its un-scaled value. We do this using the - # weighting_factor below: - - regions = gather_group_regions(M, r) - - try: - activity_rpst = sum( - M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] / (value(M.SegFrac[p, s, d])*365*24) - for _r in regions - 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 d in M.time_of_day - ) - except: - msg = ( - "\nWarning: MinSeasonalActivity constraint can not be defined for " - "technologies in \"tech_annual\". Continuing by ignoring the constraint " - "for '%s'.\n " - ) - SE.write(msg % (t)) - return Constraint.Skip - - min_act = value(M.MinSeasonalActivity[r, p, s, t]) - expr = activity_rpst >= min_act + act_lim = value(M.LimitSeasonalActivity[r, p, s, t, op]) + expr = operator_expression(activity_rpst, op, act_lim) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated @@ -2351,76 +2232,18 @@ def MinSeasonalActivity_Constraint(M: 'TemoaModel', r, p, s, t): return expr -def MinActivityGroup_Constraint(M: 'TemoaModel', r, p, g): - r""" - - The MinActivityGroup constraint sets a minimum activity limit for a user-defined - technology group. - - .. math:: - :label: MinActivityGroup - - \sum_{R,S,D,I,T,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} + \sum_{I,T,V,O} - \textbf{FOA}_{r, p, i, t, v, o} - \ge MnAG_{r, p, g} - \forall \{r, p, g\} \in \Theta_{\text{MinActivityGroup}} - - where :math:`g` represents the assigned technology group and :math:`MnAG` - refers to the :code:`MinActivityGroup` parameter.""" - - regions = gather_group_regions(M, r) - - activity_p = 0 - activity_p_annual = 0 - for _r in regions: - activity_p += sum( - M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] - for S_t in M.tech_group_members[g] - if (_r, p, S_t) in M.processVintages and S_t not in M.tech_annual - for S_v in M.processVintages[_r, p, S_t] - for S_i in M.processInputs[_r, p, S_t, S_v] - for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - for s in M.time_season[p] - for d in M.time_of_day - if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut - ) - - activity_p_annual += sum( - M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] - for S_t in M.tech_group_members[g] - if (_r, p, S_t) in M.processVintages and S_t in M.tech_annual - for S_v in M.processVintages[_r, p, S_t] - for S_i in M.processInputs[_r, p, S_t, S_v] - for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual - ) - min_act = value(M.MinActivityGroup[r, p, g]) - expr = activity_p + activity_p_annual >= min_act - # in the case that there is nothing to sum, skip - if isinstance(expr, bool): # an empty list was generated - logger.error( - 'No elements available to support min-activity group: (%s, %d, %s).' - ' Check data/log for available/suppressed techs. Requirement IGNORED.', - r, - p, - g, - ) - return Constraint.Skip - return expr - - -def MaxActivityGroup_Constraint(M: 'TemoaModel', r, p, g): +def LimitActivityGroup_Constraint(M: 'TemoaModel', r, p, g, op): r""" - The MaxActivityGroup constraint sets a maximum activity limit for a user-defined + The LimitActivityGroup constraint sets an activity limit for a user-defined technology group. .. math:: - :label: MaxActivityGroup + :label: LimitActivityGroup \sum_{R,S,D,I,T,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} + \sum_{I,T,V,O} \textbf{FOA}_{r, p, i, t, v, o} \le MxAG_{r, p, g} - \forall \{r, p, g\} \in \Theta_{\text{MaxActivityGroup}} + \forall \{r, p, g\} \in \Theta_{\text{LimitActivityGroup}} where :math:`g` represents the assigned technology group and :math:`MxAG` - refers to the :code:`MaxActivityGroup` parameter.""" + refers to the :code:`LimitActivityGroup` parameter.""" regions = gather_group_regions(M, r) @@ -2448,71 +2271,71 @@ def MaxActivityGroup_Constraint(M: 'TemoaModel', r, p, g): if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual ) - max_act = value(M.MaxActivityGroup[r, p, g]) - expr = activity_p + activity_p_annual <= max_act + act_lim = value(M.LimitActivityGroup[r, p, g, op]) + expr = operator_expression(activity_p + activity_p_annual, op, act_lim) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated return Constraint.Skip return expr -def MaxNewCapacity_Constraint(M: 'TemoaModel', r, p, t): +def LimitNewCapacity_Constraint(M: 'TemoaModel', r, p, t, op): r""" - The MaxNewCapacity constraint sets a limit on the maximum newly installed capacity of a + The LimitNewCapacity constraint sets a limit on the 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}""" + :label: LimitNewCapacity + \textbf{CAP}_{r, t, p} \le LIM_{r, p, t}""" regions = gather_group_regions(M, r) - max_cap = value(M.MaxNewCapacity[r, p, t]) + cap_lim = value(M.LimitNewCapacity[r, p, t, op]) new_cap = sum( M.V_NewCapacity[_r, t, p] for _r in regions ) - expr = new_cap <= max_cap + expr = operator_expression(new_cap, op, cap_lim) return expr -def MaxCapacity_Constraint(M: 'TemoaModel', r, p, t): +def LimitCapacity_Constraint(M: 'TemoaModel', r, p, t, op): r""" - The MaxCapacity constraint sets a limit on the maximum available capacity of a + The LimitCapacity constraint sets a limit on the available capacity of a given technology. Note that the indices for these constraints are region, period and tech, not tech and vintage. .. math:: - :label: MaxCapacity + :label: LimitCapacity \textbf{CAPAVL}_{r, p, t} \le MAC_{r, p, t} - \forall \{r, p, t\} \in \Theta_{\text{MaxCapacity}}""" + \forall \{r, p, t\} \in \Theta_{\text{LimitCapacity}}""" regions = gather_group_regions(M, r) - max_cap = value(M.MaxCapacity[r, p, t]) + cap_lim = value(M.LimitCapacity[r, p, t, op]) capacity = sum( M.V_CapacityAvailableByPeriodAndTech[_r, p, t] for _r in regions ) - expr = capacity <= max_cap + expr = operator_expression(capacity, op, cap_lim) return expr -def MaxResource_Constraint(M: 'TemoaModel', r, t): +def LimitResource_Constraint(M: 'TemoaModel', r, t, op): r""" - The MaxResource constraint sets a limit on the maximum available resource of a + The LimitResource constraint sets a limit on the available resource of a given technology across all model time periods. Note that the indices for these constraints are region and tech. .. math:: - :label: MaxResource + :label: LimitResource \sum_{P} \textbf{CAPAVL}_{r, p, t} \le MAR_{r, t} - \forall \{r, t\} \in \Theta_{\text{MaxCapacity}}""" + \forall \{r, t\} \in \Theta_{\text{LimitCapacity}}""" # logger.warning( - # 'The MaxResource constraint is not currently supported in the model, pending review. Recommend ' - # 'removing data from the MaxResource Table' + # 'The LimitResource constraint is not currently supported in the model, pending review. Recommend ' + # 'removing data from the LimitResource Table' # ) # dev note: this constraint is a misnomer. It is actually a "global activity constraint on a tech" # regardless of whatever "resources" are consumed. @@ -2544,18 +2367,18 @@ def MaxResource_Constraint(M: 'TemoaModel', r, t): for d in M.time_of_day ) - max_resource = value(M.MaxResource[r, t]) - expr = activity_rt <= max_resource + resource_lim = value(M.LimitResource[r, t, op]) + expr = operator_expression(activity_rt, op, resource_lim) return expr -def MaxCapacityGroup_Constraint(M: 'TemoaModel', r, p, g): +def LimitCapacityGroup_Constraint(M: 'TemoaModel', r, p, g, op): r""" - Similar to the :code:`MaxCapacity` constraint, but works on a group of technologies. + Similar to the :code:`LimitCapacity` constraint, but works on a group of technologies. """ regions = gather_group_regions(M, r) - max_capgroup = value(M.MaxCapacityGroup[r, p, g]) + cap_lim = value(M.LimitCapacityGroup[r, p, g, op]) cap = sum( M.V_CapacityAvailableByPeriodAndTech[_r, p, t] @@ -2564,79 +2387,11 @@ def MaxCapacityGroup_Constraint(M: 'TemoaModel', r, p, g): if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech ) - expr = cap <= max_capgroup + expr = operator_expression(cap, op, cap_lim) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated logger.error( - 'No elements available to support max-capacity group: %s.' - ' Check data/log for available/suppressed techs. Constraint ignored.', - (r, p, g) - ) - return Constraint.Skip - return expr - - -def MinNewCapacity_Constraint(M: 'TemoaModel', 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}""" - regions = gather_group_regions(M, r) - min_cap = value(M.MinNewCapacity[r, p, t]) - new_cap = sum( - M.V_NewCapacity[_r, t, p] - for _r in regions - ) - expr = new_cap >= min_cap - return expr - - -def MinCapacity_Constraint(M: 'TemoaModel', r, p, t): - r""" - - The MinCapacity constraint sets a limit on the minimum available capacity of a - given technology. Note that the indices for these constraints are region, period and - tech, not tech and vintage. - - .. math:: - :label: MinCapacityCapacityAvailableByPeriodAndTech - - \textbf{CAPAVL}_{r, p, t} \ge MIC_{r, p, t} - - \forall \{r, p, t\} \in \Theta_{\text{MinCapacity}}""" - regions = gather_group_regions(M, r) - min_cap = value(M.MinCapacity[r, p, t]) - capacity = sum( - M.V_CapacityAvailableByPeriodAndTech[_r, p, t] - for _r in regions - ) - expr = capacity >= min_cap - return expr - - -def MinCapacityGroup_Constraint(M: 'TemoaModel', r, p, g): - r""" - Similar to the :code:`MinCapacity` constraint, but works on a group of technologies. - """ - regions = gather_group_regions(M, r) - - min_capgroup = value(M.MinCapacityGroup[r, p, g]) - - cap = sum( - M.V_CapacityAvailableByPeriodAndTech[r_i, p, t] - for t in M.tech_group_members[g] - for r_i in regions - if (r_i, p, t) in M.V_CapacityAvailableByPeriodAndTech - ) - - expr = cap >= min_capgroup - # in the case that there is nothing to sum, skip - if isinstance(expr, bool): # an empty list was generated - logger.error( - 'No elements available to support min-capacity group: %s.' + 'No elements available to support LimitCapacityGroup: %s.' ' Check data/log for available/suppressed techs. Constraint ignored.', (r, p, g) ) @@ -2644,49 +2399,23 @@ def MinCapacityGroup_Constraint(M: 'TemoaModel', r, p, g): return expr -def MinNewCapacityGroup_Constraint(M: 'TemoaModel', r, p, g): - r""" - Similar to the :code:`MinNewCapacity` constraint, but works on a group of technologies.""" - - regions = gather_group_regions(M, r) - - min_new_cap = value(M.MinNewCapacityGroup[r, p, g]) - agg_new_cap = sum( - M.V_NewCapacity[_r, t, p] - for t in M.tech_group_members[g] - for _r in regions - if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech - ) - expr = agg_new_cap >= min_new_cap - if isinstance(expr, bool): - logger.error( - 'No elements available to support min new capacity group: (%s, %d, %s).' - ' Check data/log for available/suppressed techs. Requirement IGNORED.', - r, - p, - g, - ) - return Constraint.Skip - return expr - - -def MaxNewCapacityGroup_Constraint(M: 'TemoaModel', r, p, g): +def LimitNewCapacityGroup_Constraint(M: 'TemoaModel', r, p, g, op): r""" - Similar to the :code:`MinNewCapacity` constraint, but works on a group of technologies.""" + Similar to the :code:`LimitNewCapacity` constraint, but works on a group of technologies.""" regions = gather_group_regions(M, r) - max_new_cap = value(M.MaxNewCapacityGroup[r, p, g]) + new_cap_lim = value(M.LimitNewCapacityGroup[r, p, g, op]) agg_new_cap = sum( M.V_NewCapacity[_r, t, p] for t in M.tech_group_members[g] for _r in regions if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech ) - expr = max_new_cap >= agg_new_cap + expr = operator_expression(agg_new_cap, op, new_cap_lim) if isinstance(expr, bool): logger.error( - 'No elements available to support max new capacity group: (%s, %d, %s).' + 'No elements available to support LimitNewCapacityGroup: (%s, %d, %s).' ' Check data/log for available/suppressed techs. Requirement IGNORED.', r, p, @@ -2696,13 +2425,13 @@ def MaxNewCapacityGroup_Constraint(M: 'TemoaModel', r, p, g): return expr -def MinActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): +def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, t, g, op): r""" - The MinActivityShare constraint sets a minimum capacity share for a given + The LimitActivityShare constraint limits the activity share for a given technology within a technology groups to which it belongs. For instance, you might define a tech_group of light-duty vehicles, whose members are different types for LDVs. This constraint could be used to enforce - that no less than 10% of LDVs must be of a certain type.""" + that no more than 10% of LDVs must be of a certain type.""" regions = gather_group_regions(M, r) @@ -2751,24 +2480,21 @@ def MinActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): ) activity_group = activity_group + activity_group_annual - min_activity_share = value(M.MinActivityShare[r, p, t, g]) - expr = activity_tech >= min_activity_share * activity_group + share_lim = value(M.LimitActivityShare[r, p, t, g, op]) + expr = operator_expression(activity_tech, op, share_lim * activity_group) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated - logger.error( - 'No elements available to support min-activity share group: (%s, %d, %s).' - ' Check data/log for available/suppressed techs. Requirement IGNORED.', - r, - p, - g, - ) return Constraint.Skip + logger.debug( + 'created limit activity share constraint for (%s, %d, %s, %s) of %0.2f', + r, p, t, g, share_lim, + ) return expr -def MaxActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): +def LimitCapacityShare_Constraint(M: 'TemoaModel', r, p, t, g, op): r""" - The MaxActivityShare constraint sets a maximum Activity share for a given + The LimitCapacityShare constraint limits the share for a given technology within a technology groups to which it belongs. For instance, you might define a tech_group of light-duty vehicles, whose members are different types for LDVs. This constraint could be used to enforce @@ -2776,164 +2502,27 @@ def MaxActivityShare_Constraint(M: 'TemoaModel', r, p, t, g): regions = gather_group_regions(M, r) - if t not in M.tech_annual: - activity_tech = sum( - M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] - for _r in regions - for S_v in M.processVintages.get((_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[p] - for d in M.time_of_day - if (_r, p, s, d, S_i, t, S_v, S_o) in M.V_FlowOut - ) - else: - activity_tech = sum( - M.V_FlowOutAnnual[_r, p, S_i, t, S_v, S_o] - for _r in regions - for S_v in M.processVintages.get((_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] - if (_r, p, S_i, t, S_v, S_o) in M.V_FlowOutAnnual - ) - - activity_group = sum( - M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] - for S_t in M.tech_group_members[g] + capacity_t = sum( + M.V_CapacityAvailableByPeriodAndTech[_r, p, t] for _r in regions - if (_r, p, S_t) in M.processVintages and S_t not in M.tech_annual - for S_v in M.processVintages[_r, p, S_t] - for S_i in M.processInputs[_r, p, S_t, S_v] - for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - for s in M.time_season[p] - for d in M.time_of_day - if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut ) - activity_group_annual = sum( - M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] + capacity_group = sum( + M.V_CapacityAvailableByPeriodAndTech[_r, p, S_t] for S_t in M.tech_group_members[g] for _r in regions - if (_r, p, S_t) in M.processVintages and S_t in M.tech_annual - for S_v in M.processVintages[_r, p, S_t] - for S_i in M.processInputs[_r, p, S_t, S_v] - for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual + if (_r, p, S_t) in M.processVintages ) - activity_group = activity_group + activity_group_annual - - max_activity_share = value(M.MaxActivityShare[r, p, t, g]) - expr = activity_tech <= max_activity_share * activity_group - # in the case that there is nothing to sum, skip - if isinstance(expr, bool): # an empty list was generated - return Constraint.Skip - logger.debug( - 'created max activity constraint for (%s, %d, %s, %s) of %0.2f', - (r, p, t, g, max_activity_share), - ) - return expr - - -def MinCapacityShare_Constraint(M: 'TemoaModel', r, p, t, g): - r""" - The MinCapacityShare constraint sets a minimum capacity share for a given - technology within a technology groups to which it belongs. - For instance, you might define a tech_group of light-duty vehicles, whose - members are different types for LDVs. This constraint could be used to enforce - that no less than 10% of LDVs must be of a certain type.""" - - regions = gather_group_regions(M, r) - - capacity_t = sum( - M.V_CapacityAvailableByPeriodAndTech[_r, p, t] - for _r in regions - ) - capacity_group = sum( - M.V_CapacityAvailableByPeriodAndTech[_r, p, S_t] - for S_t in M.tech_group_members[g] - for _r in regions - if (_r, p, S_t) in M.processVintages - ) - min_cap_share = value(M.MinCapacityShare[r, p, t, g]) - - expr = capacity_t >= min_cap_share * capacity_group - if isinstance(expr, bool): - logger.error( - 'No elements available to support min-capacity share: (%s, %d, %s).' - ' Check data/log for available/suppressed techs. Requirement IGNORED.', - r, - p, - g, - ) - return Constraint.Skip - return expr - - -def MaxCapacityShare_Constraint(M: 'TemoaModel', r, p, t, g): - r""" - The MaxCapacityShare constraint sets a maximum capacity share for a given - technology within a technology groups to which it belongs. - For instance, you might define a tech_group of light-duty vehicles, whose - members are different types for LDVs. This constraint could be used to enforce - that no more than 10% of LDVs must be of a certain type.""" + share_lim = value(M.LimitCapacityShare[r, p, t, g, op]) - regions = gather_group_regions(M, r) - - capacity_t = sum( - M.V_CapacityAvailableByPeriodAndTech[_r, p, t] - for _r in regions - ) - capacity_group = sum( - M.V_CapacityAvailableByPeriodAndTech[_r, p, S_t] - for S_t in M.tech_group_members[g] - for _r in regions - if (_r, p, S_t) in M.processVintages - ) - max_cap_share = value(M.MaxCapacityShare[r, p, t, g]) - - expr = capacity_t <= max_cap_share * capacity_group + expr = operator_expression(capacity_t, op, share_lim * capacity_group) if isinstance(expr, bool): return Constraint.Skip return expr -def MinNewCapacityShare_Constraint(M: 'TemoaModel', r, p, t, g): - r""" - The MinNewCapacityShare constraint sets a minimum new capacity share for a given - technology within a technology groups to which it belongs. - For instance, you might define a tech_group of light-duty vehicles, whose - members are different types for LDVs. This constraint could be used to enforce - that no less than 10% of new LDV purchases in a given year must be of a certain type.""" - - regions = gather_group_regions(M, r) - - capacity_t = sum( - M.V_NewCapacity[_r, t, p] - for _r in regions - ) - capacity_group = sum( - M.V_NewCapacity[_r, S_t, p] - for S_t in M.tech_group_members[g] - for _r in regions - if (_r, S_t, p) in M.V_NewCapacity - ) - min_cap_share = value(M.MinNewCapacityShare[r, p, t, g]) - - expr = capacity_t >= min_cap_share * capacity_group - if isinstance(expr, bool): - logger.error( - 'No elements available to support min-new capacity share: (%s, %d, %s).' - ' Check data/log for available/suppressed techs. Requirement IGNORED.', - r, - p, - g, - ) - return Constraint.Skip - return expr - - -def MaxNewCapacityShare_Constraint(M: 'TemoaModel', r, p, t, g): +def LimitNewCapacityShare_Constraint(M: 'TemoaModel', r, p, t, g, op): r""" - The MaxCapacityShare constraint sets a maximum new capacity share for a given + The LimitCapacityShare constraint limits the share for a given technology within a technology groups to which it belongs. For instance, you might define a tech_group of light-duty vehicles, whose members are different types for LDVs. This constraint could be used to enforce @@ -2941,33 +2530,33 @@ def MaxNewCapacityShare_Constraint(M: 'TemoaModel', r, p, t, g): regions = gather_group_regions(M, r) - capacity_t = sum( + new_cap_t = sum( M.V_NewCapacity[_r, t, p] for _r in regions ) - capacity_group = sum( + new_cap_group = sum( M.V_NewCapacity[_r, S_t, p] for S_t in M.tech_group_members[g] for _r in regions if (_r, S_t, p) in M.V_NewCapacity ) - max_cap_share = value(M.MaxNewCapacityShare[r, p, t, g]) + share_lim = value(M.LimitNewCapacityShare[r, p, t, g, op]) - expr = capacity_t <= max_cap_share * capacity_group + expr = operator_expression(new_cap_t, op, share_lim * new_cap_group) if isinstance(expr, bool): return Constraint.Skip return expr -def MinNewCapacityGroupShare_Constraint(M: 'TemoaModel', r, p, g1, g2): +def LimitNewCapacityGroupShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): r""" - Sets the minimum aggregate capacity of one group of technologies as a share of + Limits the aggregate capacity of one group of technologies as a share of another group of technologies. """ regions = gather_group_regions(M, r) - min_share = value(M.MinNewCapacityGroupShare[r, p, g1, g2]) + share_lim = value(M.LimitNewCapacityGroupShare[r, p, g1, g2, op]) agg_new_cap_g1 = sum( M.V_NewCapacity[_r, t, p] for t in M.tech_group_members[g1] @@ -2980,128 +2569,32 @@ def MinNewCapacityGroupShare_Constraint(M: 'TemoaModel', r, p, g1, g2): for _r in regions if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech ) - expr = agg_new_cap_g1 >= agg_new_cap_g2 * min_share + expr = operator_expression(agg_new_cap_g1, op, agg_new_cap_g2 * share_lim) if isinstance(expr, bool): # one side of expression was empty logger.error( - 'Missing group techs to support min new capacity group share constraint: %s.' + 'Missing group techs to support LimitNewCapacityGroupShare constraint: %s.' ' Check data/log for available/suppressed techs. Constraint ignored.', (r, p, g1, g2) ) return Constraint.Skip - - return expr - - -def MaxNewCapacityGroupShare_Constraint(M: 'TemoaModel', r, p, g1, g2): - r""" - Sets the maximum aggregate capacity of one group of technologies as a share of - another group of technologies. - """ - - regions = gather_group_regions(M, r) - - max_share = value(M.MaxNewCapacityGroupShare[r, p, g1, g2]) - agg_new_cap_g1 = sum( - M.V_NewCapacity[_r, t, p] - for t in M.tech_group_members[g1] - for _r in regions - if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech - ) - agg_new_cap_g2 = sum( - M.V_NewCapacity[_r, t, p] - for t in M.tech_group_members[g2] - for _r in regions - if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech - ) - expr = agg_new_cap_g1 <= agg_new_cap_g2 * max_share - - if isinstance(expr, bool): # one side of expression was empty - logger.error( - 'Missing group techs to support max new capacity group share constraint: %s.' - ' Check data/log for available/suppressed techs. Constraint ignored.', - (r, p, g1, g2) - ) - return Constraint.Skip - - return expr - - -def MinAnnualCapacityFactor_Constraint(M: 'TemoaModel', 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 plus (r='Mexico+US+Canada'), or 'global'. - # if r == 'global', the constraint is system-wide - regions = gather_group_regions(M, r) - # we need to screen here because it is possible that the restriction extends beyond the - # lifetime of any vintage of the tech... - if all( - (_r, p, t) not in M.V_CapacityAvailableByPeriodAndTech - for _r in regions - ): - return Constraint.Skip - if t not in M.tech_annual: - activity_rpt = sum( - M.V_FlowOut[_r, p, s, d, S_i, t, S_v, o] - for _r in regions - for S_v in M.processVintages.get((_r, p, t), []) - for S_i in M.processInputs[_r, p, t, S_v] - for s in M.time_season[p] - for d in M.time_of_day - if (_r, p, s, d, S_i, t, S_v, o) in M.V_FlowOut - ) - else: - activity_rpt = sum( - M.V_FlowOutAnnual[_r, p, S_i, t, S_v, o] - for _r in regions - for S_v in M.processVintages.get((_r, p, t), []) - for S_i in M.processInputs[_r, p, t, S_v] - if (_r, p, S_i, t, S_v, o) in M.V_FlowOutAnnual - ) - - max_possible_activity_rpt = sum( - M.V_CapacityAvailableByPeriodAndTech[_r, p, t] * value(M.CapacityToActivity[_r, t]) - for _r in regions - ) - min_annual_cf = value(M.MinAnnualCapacityFactor[r, p, t, o]) - expr = activity_rpt >= min_annual_cf * max_possible_activity_rpt - # in the case that there is nothing to sum, skip - if isinstance(expr, bool): # an empty list was generated - logger.error( - 'No elements available to support min-annual capacity factor: (%s, %d, %s).' - ' Check data/log for available/suppressed techs. Requirement IGNORED.', - r, - p, - t, - ) - return Constraint.Skip return expr -def MaxAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o): +def LimitAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o, op): r""" - The MaxAnnualCapacityFactor sets an upper bound on the annual capacity factor + The LimitAnnualCapacityFactor 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}}""" + :label: LimitAnnualCapacityFactor + \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMACF_{r, p, t} * \textbf{CAPAVL}_{r, p, t} * \text{C2A}_{r, t} + \forall \{r, p, t, o\} \in \Theta_{\text{LimitAnnualCapacityFactor}} + \sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \ge LIMACF_{r, p, t} * \textbf{CAPAVL}_{r, p, t} * \text{C2A}_{r, t} + \forall \{r, p, t, o \in T^{a}\} \in \Theta_{\text{LimitAnnualCapacityFactor}}""" # r can be an individual region (r='US'), or a combination of regions separated by plus (r='Mexico+US+Canada'), or 'global'. # if r == 'global', the constraint is system-wide regions = gather_group_regions(M, r) @@ -3132,204 +2625,23 @@ def MaxAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o): if (_r, p, S_i, t, S_v, o) in M.V_FlowOutAnnual ) - max_possible_activity_rpt = sum( + possible_activity_rpt = sum( M.V_CapacityAvailableByPeriodAndTech[_r, p, t] * value(M.CapacityToActivity[_r, t]) for _r in regions ) - max_annual_cf = value(M.MaxAnnualCapacityFactor[r, p, t, o]) - expr = activity_rpt <= max_annual_cf * max_possible_activity_rpt + annual_cf = value(M.LimitAnnualCapacityFactor[r, p, t, o, op]) + expr = operator_expression(activity_rpt, op, annual_cf * possible_activity_rpt) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated return Constraint.Skip return expr -def MinTechInputSplit_Constraint(M: 'TemoaModel', r, p, s, d, i, t, v): - r""" - Allows users to specify fixed or minimum shares of commodity inputs to a process - producing a single output. These shares can vary by model time period. See - MinTechOutputSplit_Constraint for an analogous explanation. Under this constraint, - only the technologies with variable output at the timeslice level (i.e., - NOT in the :code:`tech_annual` set) are considered.""" - inp = sum( - M.V_FlowOut[r, p, s, d, i, t, v, S_o] / get_variable_efficiency(M, r, p, s, d, i, t, v, S_o) - for S_o in M.processOutputsByInput[r, p, t, v, i] - ) - - total_inp = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] / get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - - expr = inp >= value(M.MinTechInputSplit[r, p, i, t]) * total_inp - return expr - - -def MinTechInputSplitAnnual_Constraint(M: 'TemoaModel', r, p, i, t, v): - r""" - Allows users to specify fixed or minimum shares of commodity inputs to a process - producing a single output. These shares can vary by model time period. See - MinTechOutputSplitAnnual_Constraint for an analogous explanation. Under this - function, only the technologies with constant annual output (i.e., members - of the :math:`tech_annual` set) are considered.""" - inp = sum( - M.V_FlowOutAnnual[r, p, i, t, v, S_o] / value(M.Efficiency[r, i, t, v, S_o]) - for S_o in M.processOutputsByInput[r, p, t, v, i] - ) - - total_inp = sum( - M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] / value(M.Efficiency[r, S_i, t, v, S_o]) - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - - expr = inp >= value(M.MinTechInputSplitAnnual[r, p, i, t]) * total_inp - return expr - - -def MinTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v): - r""" - Allows users to specify fixed or minimum shares of commodity inputs to a process - 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 MinTechInputSplit 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.""" - - inp = sum( - M.V_FlowOut[r, p, S_s, S_d, i, t, v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) - for S_s in M.time_season[p] - for S_d in M.time_of_day - for S_o in M.processOutputsByInput[r, p, t, v, i] - ) - - total_inp = sum( - M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) - for S_s in M.time_season[p] - for S_d in M.time_of_day - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, i] - ) - - expr = inp >= value(M.MinTechInputSplitAnnual[r, p, i, t]) * total_inp - return expr - - -def MinTechOutputSplit_Constraint(M: 'TemoaModel', r, p, s, d, t, v, o): - r""" - - Some processes take a single input and make multiple outputs, and the user would like to - specify either a constant or time-varying ratio of outputs per unit input. The most - canonical example is an oil refinery. Crude oil is used to produce many different refined - products. In many cases, the modeler would like to specify a minimum share of each refined - product produced by the refinery. - - For example, a hypothetical (and highly simplified) refinery might have a crude oil input - that produces 4 parts diesel, 3 parts gasoline, and 2 parts kerosene. The relative - ratios to the output then are: - - .. math:: - - d = \tfrac{4}{9} \cdot \text{total output}, \qquad - g = \tfrac{3}{9} \cdot \text{total output}, \qquad - k = \tfrac{2}{9} \cdot \text{total output} - - Note that it is possible to specify output shares that sum to less than unity. In such - cases, the model optimizes the remaining share. In addition, it is possible to change the - specified shares by model time period. Under this constraint, only the - technologies with variable output at the timeslice level (i.e., NOT in the - :code:`tech_annual` set) are considered. - - The constraint is formulated as follows: - - .. math:: - :label: MinTechOutputSplit - - \sum_{I, t \not \in T^{a}} \textbf{FO}_{r, p, s, d, i, t, v, o} - \geq - TOS_{r, p, t, o} \cdot \sum_{I, O, t \not \in T^{a}} \textbf{FO}_{r, p, s, d, i, t, v, o} - - \forall \{r, p, s, d, t, v, o\} \in \Theta_{\text{MinTechOutputSplit}}""" - out = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, o] - for S_i in M.processInputsByOutput[r, p, t, v, o] - ) - - total_out = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - - expr = out >= value(M.MinTechOutputSplit[r, p, t, o]) * total_out - return expr - - -def MinTechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o): - r""" - This constraint operates similarly to MinTechOutputSplit_Constraint. - However, under this function, only the technologies with constant annual - output (i.e., members of the :math:`tech_annual` set) are considered. - - .. math:: - :label: MinTechOutputSplitAnnual - - \sum_{I, T^{a}} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} - - \geq - - TOS_{r, p, t, o} \cdot \sum_{I, O, T^{a}} \textbf{FOA}_{r, p, s, d, i, t \in T^{a}, v, o} - - \forall \{r, p, t \in T^{a}, v, o\} \in \Theta_{\text{MinTechOutputSplitAnnual}}""" - out = sum( - M.V_FlowOutAnnual[r, p, S_i, t, v, o] - for S_i in M.processInputsByOutput[r, p, t, v, o] - ) - - total_out = sum( - M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - - expr = out >= value(M.MinTechOutputSplitAnnual[r, p, t, o]) * total_out - return expr - - -def MinTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o): +def LimitTechInputSplit_Constraint(M: 'TemoaModel', r, p, s, d, i, t, v, op): r""" - Allows users to specify fixed or minimum shares of commodity outputs from a process. - 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 MinTechOutputSplit 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 output shares over the course of a year.""" - - out = sum( - M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, o] - for S_i in M.processInputsByOutput[r, p, t, v, o] - for S_s in M.time_season[p] - for S_d in M.time_of_day - ) - - total_out = sum( - M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - for S_s in M.time_season[p] - for S_d in M.time_of_day - ) - - expr = out >= value(M.MinTechOutputSplitAnnual[r, p, t, o]) * total_out - return expr - - -def MaxTechInputSplit_Constraint(M: 'TemoaModel', r, p, s, d, i, t, v): - r""" - Allows users to specify fixed or minimum shares of commodity inputs to a process + Allows users to limit shares of commodity inputs to a process producing a single output. These shares can vary by model time period. See - MaxTechOutputSplit_Constraint for an analogous explanation. Under this constraint, + LimitTechOutputSplit_Constraint for an analogous explanation. Under this constraint, only the technologies with variable output at the timeslice level (i.e., NOT in the :code:`tech_annual` set) are considered.""" inp = sum( @@ -3343,15 +2655,15 @@ def MaxTechInputSplit_Constraint(M: 'TemoaModel', r, p, s, d, i, t, v): for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - expr = inp <= value(M.MaxTechInputSplit[r, p, i, t]) * total_inp + expr = operator_expression(inp, op, value(M.LimitTechInputSplit[r, p, i, t, op]) * total_inp) return expr -def MaxTechInputSplitAnnual_Constraint(M: 'TemoaModel', r, p, i, t, v): +def LimitTechInputSplitAnnual_Constraint(M: 'TemoaModel', r, p, i, t, v, op): r""" - Allows users to specify fixed or minimum shares of commodity inputs to a process + Allows users to limit shares of commodity inputs to a process producing a single output. These shares can vary by model time period. See - MaxTechOutputSplitAnnual_Constraint for an analogous explanation. Under this + LimitTechOutputSplitAnnual_Constraint for an analogous explanation. Under this function, only the technologies with constant annual output (i.e., members of the :math:`tech_annual` set) are considered.""" inp = sum( @@ -3365,16 +2677,16 @@ def MaxTechInputSplitAnnual_Constraint(M: 'TemoaModel', r, p, i, t, v): for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - expr = inp <= value(M.MaxTechInputSplitAnnual[r, p, i, t]) * total_inp + expr = operator_expression(inp, op, value(M.LimitTechInputSplitAnnual[r, p, i, t, op]) * total_inp) return expr -def MaxTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v): +def LimitTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v, op): r""" - Allows users to specify fixed or minimum shares of commodity inputs to a process + Allows users to limit shares of commodity inputs to a process 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 MaxTechInputSplit as it specifies shares on an annual basis, + This constraint differs from LimitTechInputSplit 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.""" @@ -3393,17 +2705,17 @@ def MaxTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v): for S_o in M.processOutputsByInput[r, p, t, v, i] ) - expr = inp <= value(M.MaxTechInputSplitAnnual[r, p, i, t]) * total_inp + expr = operator_expression(inp, op, value(M.LimitTechInputSplitAnnual[r, p, i, t, op]) * total_inp) return expr -def MaxTechOutputSplit_Constraint(M: 'TemoaModel', r, p, s, d, t, v, o): +def LimitTechOutputSplit_Constraint(M: 'TemoaModel', r, p, s, d, t, v, o, op): r""" Some processes take a single input and make multiple outputs, and the user would like to specify either a constant or time-varying ratio of outputs per unit input. The most canonical example is an oil refinery. Crude oil is used to produce many different refined - products. In many cases, the modeler would like to specify a minimum share of each refined + products. In many cases, the modeler would like to limit the share of each refined product produced by the refinery. For example, a hypothetical (and highly simplified) refinery might have a crude oil input @@ -3425,13 +2737,13 @@ def MaxTechOutputSplit_Constraint(M: 'TemoaModel', r, p, s, d, t, v, o): The constraint is formulated as follows: .. math:: - :label: MaxTechOutputSplit + :label: LimitTechOutputSplit \sum_{I, t \not \in T^{a}} \textbf{FO}_{r, p, s, d, i, t, v, o} \geq TOS_{r, p, t, o} \cdot \sum_{I, O, t \not \in T^{a}} \textbf{FO}_{r, p, s, d, i, t, v, o} - \forall \{r, p, s, d, t, v, o\} \in \Theta_{\text{MaxTechOutputSplit}}""" + \forall \{r, p, s, d, t, v, o\} \in \Theta_{\text{LimitTechOutputSplit}}""" out = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, o] for S_i in M.processInputsByOutput[r, p, t, v, o] @@ -3443,18 +2755,18 @@ def MaxTechOutputSplit_Constraint(M: 'TemoaModel', r, p, s, d, t, v, o): for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - expr = out <= value(M.MaxTechOutputSplit[r, p, t, o]) * total_out + expr = operator_expression(out, op, value(M.LimitTechOutputSplit[r, p, t, o, op]) * total_out) return expr -def MaxTechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o): +def LimitTechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o, op): r""" - This constraint operates similarly to MaxTechOutputSplit_Constraint. + This constraint operates similarly to LimitTechOutputSplit_Constraint. However, under this function, only the technologies with constant annual output (i.e., members of the :math:`tech_annual` set) are considered. .. math:: - :label: MaxTechOutputSplitAnnual + :label: LimitTechOutputSplitAnnual \sum_{I, T^{a}} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} @@ -3462,7 +2774,7 @@ def MaxTechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o): TOS_{r, p, t, o} \cdot \sum_{I, O, T^{a}} \textbf{FOA}_{r, p, s, d, i, t \in T^{a}, v, o} - \forall \{r, p, t \in T^{a}, v, o\} \in \Theta_{\text{MaxTechOutputSplitAnnual}}""" + \forall \{r, p, t \in T^{a}, v, o\} \in \Theta_{\text{LimitTechOutputSplitAnnual}}""" out = sum( M.V_FlowOutAnnual[r, p, S_i, t, v, o] for S_i in M.processInputsByOutput[r, p, t, v, o] @@ -3474,16 +2786,16 @@ def MaxTechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o): for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - expr = out <= value(M.MaxTechOutputSplitAnnual[r, p, t, o]) * total_out + expr = operator_expression(out, op, value(M.LimitTechOutputSplitAnnual[r, p, t, o, op]) * total_out) return expr -def MaxTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o): +def LimitTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o, op): r""" - Allows users to specify fixed or minimum shares of commodity outputs from a process. + Allows users to limit shares of commodity outputs from a process. 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 MaxTechOutputSplit as it specifies shares on an annual basis, + This constraint differs from LimitTechOutputSplit 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 output shares over the course of a year.""" @@ -3502,7 +2814,7 @@ def MaxTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o): for S_d in M.time_of_day ) - expr = out <= value(M.MaxTechOutputSplitAnnual[r, p, t, o]) * total_out + expr = operator_expression(out, op, value(M.LimitTechOutputSplitAnnual[r, p, t, o, op]) * total_out) return expr @@ -3655,28 +2967,35 @@ def operator_expression(lhs: Expression | None, operator: str | None, rhs: Expre """Returns an expression, applying a configured operator""" if any((lhs is None, operator is None, rhs is None)): msg = ( - 'Tried to build a constraint using a bad expression or operator. Constraint skipped: ' - '{} {} {}' + 'Tried to build a constraint using a bad expression or operator: {} {} {}' + ).format(lhs, operator, rhs) + logger.error(msg) + raise ValueError(msg) + try: + match operator: + case "e": + expr = lhs == rhs + case "l": + expr = lhs < rhs + case "g": + expr = lhs > rhs + case "le": + expr = lhs <= rhs + case "ge": + expr = lhs >= rhs + case _: + msg = ( + 'Tried to build a constraint using a bad operator: {} {} {}' + ).format(lhs, operator, rhs) + logger.error(msg) + raise ValueError(msg) + except Exception as e: + print(e) + msg = ( + 'Tried to build a constraint using a bad expression or operator: {} {} {}' ).format(lhs, operator, rhs) logger.error(msg) raise ValueError(msg) - match operator: - case "e": - expr = lhs == rhs - case "l": - expr = lhs < rhs - case "g": - expr = lhs > rhs - case "le": - expr = lhs <= rhs - case "ge": - expr = lhs >= rhs - case _: - msg = ( - 'Tried to build a constraint using a bad operator. Constraint skipped: {} {} {}' - ).format(lhs, operator, rhs) - logger.error(msg) - raise ValueError(msg) return expr diff --git a/temoa/utilities/db_migration_operator.py b/temoa/utilities/db_migration_operator.py new file mode 100644 index 000000000..a191c4449 --- /dev/null +++ b/temoa/utilities/db_migration_operator.py @@ -0,0 +1,183 @@ +""" +Tools for Energy Model Optimization and Analysis (Temoa): +An open source framework for energy systems optimization modeling + +Copyright (C) 2015, NC State University + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +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 +received this license file. If not, see . + +Written by: I. D. Elder +iandavidelder@gmail.com +Created on: 2025/03/14 + +Convert various constraints on the Max/Min separate tables paradigm +to the new operator-based single Limit table paradigm. +""" + +import argparse +import sqlite3 +import sys +from pathlib import Path + +parser = argparse.ArgumentParser() +parser.add_argument( + '--source', + help='Path to original database', + required=True, + action='store', + dest='source_db', +) +parser.add_argument( + '--schema', + help='Path to schema file (default=data_files/temoa_schema_v3_2)', + required=False, + dest='schema', + default='data_files/temoa_schema_v3_2.sql', +) +options = parser.parse_args() +legacy_db: Path = Path(options.source_db) +schema_file = Path(options.schema) + +new_db_name = legacy_db.stem + '_v3_2.sqlite' +new_db_path = Path(legacy_db.parent, new_db_name) + +con_old = sqlite3.connect(legacy_db) +con_new = sqlite3.connect(new_db_path) +cur = con_new.cursor() + +# bring in the new schema and execute +with open(schema_file, 'r') as src: + sql_script = src.read() +con_new.executescript(sql_script) + +# turn off FK verification while process executes +con_new.execute('PRAGMA foreign_keys = 0;') + +add_operator_tables = { + 'EmissionLimit': ('LimitEmission', 'le'), + 'MinTechOutputSplitAnnual': ('LimitTechOutputSplitAnnual', 'ge'), + 'MinTechOutputSplit': ('LimitTechOutputSplit', 'ge'), + 'MinTechInputSplitAnnual': ('LimitTechInputSplitAnnual', 'le'), + 'MinTechInputSplit': ('LimitTechInputSplit', 'ge'), + 'MinSeasonalActivity': ('LimitSeasonalActivity', 'ge'), + 'MinNewCapacityShare': ('LimitNewCapacityShare', 'ge'), + 'MinNewCapacityGroupShare': ('LimitNewCapacityGroupShare', 'ge'), + 'MinNewCapacityGroup': ('LimitNewCapacityGroup', 'ge'), + 'MinNewCapacity': ('LimitNewCapacity', 'ge'), + 'MinCapacityShare': ('LimitCapacityShare', 'ge'), + 'MinCapacityGroup': ('LimitCapacityGroup', 'ge'), + 'MinCapacity': ('LimitCapacity', 'ge'), + 'MinAnnualCapacityFactor': ('LimitAnnualCapacityFactor', 'ge'), + 'MinActivityShare': ('LimitActivityShare', 'ge'), + 'MinActivityGroup': ('LimitActivityGroup', 'ge'), + 'MinActivity': ('LimitActivity', 'ge'), + 'MaxTechOutputSplitAnnual': ('LimitTechOutputSplitAnnual', 'le'), + 'MaxTechOutputSplit': ('LimitTechOutputSplit', 'le'), + 'MaxTechInputSplitAnnual': ('LimitTechInputSplitAnnual', 'le'), + 'MaxTechInputSplit': ('LimitTechInputSplit', 'le'), + 'MaxSeasonalActivity': ('LimitSeasonalActivity', 'le'), + 'MaxNewCapacityShare': ('LimitNewCapacityShare', 'le'), + 'MaxNewCapacityGroupShare': ('LimitNewCapacityGroupShare', 'le'), + 'MaxNewCapacityGroup': ('LimitNewCapacityGroup', 'le'), + 'MaxNewCapacity': ('LimitNewCapacity', 'le'), + 'MaxCapacityShare': ('LimitCapacityShare', 'le'), + 'MaxCapacityGroup': ('LimitCapacityGroup', 'le'), + 'MaxCapacity': ('LimitCapacity', 'le'), + 'MaxAnnualCapacityFactor': ('LimitAnnualCapacityFactor', 'le'), + 'MaxActivityShare': ('LimitActivityShare', 'le'), + 'MaxActivityGroup': ('LimitActivityGroup', 'le'), + 'MaxActivity': ('LimitActivity', 'le'), + 'MaxResource': ('LimitResource', 'le'), + 'StorageLevelFraction': ('LimitStorageLevelFraction', 'e'), +} + + +# Collapse Max/Min constraint tables +print('\n --- Collapsing Max/Min tables and adding operators ---') +for old_name, (new_name, operator) in add_operator_tables.items(): + + try: + data = con_old.execute(f'SELECT * FROM {old_name}').fetchall() + except sqlite3.OperationalError: + print('TABLE NOT FOUND: ' + old_name) + continue + + if not data: + print('No data for: ' + old_name) + continue + + new_cols: tuple = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] + op_index = new_cols.index('operator') + data = [(*row[0:op_index], operator, *row[op_index::]) for row in data] + + # construct the query with correct number of placeholders + num_placeholders = len(data[0]) + placeholders = ','.join(['?' for _ in range(num_placeholders)]) + query = f'INSERT OR REPLACE INTO {new_name} VALUES ({placeholders})' + con_new.executemany(query, data) + print(f'Added operator index to {new_name} and inserted {len(data)} rows') + + +old_tables = set([t[1] for t in con_old.execute('SELECT * FROM sqlite_master WHERE type="table";')]) +new_tables = set([t[1] for t in con_new.execute('SELECT * FROM sqlite_master WHERE type="table";')]) +limit_tables = set(add_operator_tables.keys()) + +direct_transfer_tables = (new_tables & old_tables) - limit_tables + +print('\n --- Executing direct transfers ---') +for table in direct_transfer_tables: + + try: + con_old.execute(f'SELECT * FROM {table}').fetchone() + except sqlite3.OperationalError: + print('TABLE NOT FOUND: ' + table) + continue + + data = con_old.execute(f'SELECT * FROM {table}').fetchall() + + if not data: + print('No data for: ' + table) + continue + + # construct the query with correct number of placeholders + num_placeholders = len(data[0]) + placeholders = ','.join(['?' for _ in range(num_placeholders)]) + query = f'INSERT OR REPLACE INTO {table} VALUES ({placeholders})' + con_new.executemany(query, data) + print(f'Transferred {len(data)} rows from {table}') + + +print('\n --- Validating foreign keys ---') +con_new.commit() +con_new.execute('VACUUM;') +con_new.execute('PRAGMA FOREIGN_KEYS=1;') +try: + data = con_new.execute('PRAGMA FOREIGN_KEY_CHECK;').fetchall() + if not data: + print('No Foreign Key Failures. (Good news!)') + else: + print('\nFK check fails (MUST BE FIXED):') + print('(Table, Row ID, Reference Table, (fkid) )') + for row in data: + print(row) +except sqlite3.OperationalError as e: + print('Foreign Key Check FAILED on new DB. Something may be wrong with schema.') + print(e) + +print('\nFinished! Check your database for any missing data.' + ' If there was a mismatch of table names, something may have been lost.') + +con_new.close() +con_old.close() \ No newline at end of file From 19c2dc643a67353e92ae749af1363c1cc8a3b6f1 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 6 Jun 2025 15:13:49 -0400 Subject: [PATCH 089/587] Fix tech split constraints for operators --- temoa/temoa_model/temoa_initialize.py | 99 +++++++++++---------------- temoa/temoa_model/temoa_model.py | 12 ++-- 2 files changed, 45 insertions(+), 66 deletions(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index e66d18185..0d8037c04 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -839,34 +839,23 @@ def CreateSparseDicts(M: 'TemoaModel'): M.rampDownVintages[r, p, t] = set() # tech split - if (r, p, i, t) in M.LimitTechInputSplit and ( - r, - p, - i, - t, - ) not in M.inputSplitVintages: - M.inputSplitVintages[r, p, i, t] = set() - if (r, p, i, t) in M.LimitTechInputSplitAnnual and ( - r, - p, - i, - t, - ) not in M.inputSplitAnnualVintages: - M.inputSplitAnnualVintages[r, p, i, t] = set() - if (r, p, t, o) in M.LimitTechOutputSplit and ( - r, - p, - t, - o, - ) not in M.outputSplitVintages: - M.outputSplitVintages[r, p, t, o] = set() - if (r, p, t, o) in M.LimitTechOutputSplitAnnual and ( - r, - p, - t, - o, - ) not in M.outputSplitAnnualVintages: - M.outputSplitAnnualVintages[r, p, t, o] = set() + for op in M.operator: + if (r, p, i, t, op) in M.LimitTechInputSplit: + if (r, p, i, t, op) not in M.inputSplitVintages: + M.inputSplitVintages[r, p, i, t, op] = set() + M.inputSplitVintages[r, p, i, t, op].add(v) + if (r, p, i, t, op) in M.LimitTechInputSplitAnnual: + if (r, p, i, t, op) not in M.inputSplitAnnualVintages: + M.inputSplitAnnualVintages[r, p, i, t, op] = set() + M.inputSplitAnnualVintages[r, p, i, t, op].add(v) + if (r, p, t, o, op) in M.LimitTechOutputSplit: + if (r, p, t, o, op) not in M.outputSplitVintages: + M.outputSplitVintages[r, p, t, o, op] = set() + M.outputSplitVintages[r, p, t, o, op].add(v) + if (r, p, t, o, op) in M.LimitTechOutputSplitAnnual: + if (r, p, t, o, op) not in M.outputSplitAnnualVintages: + M.outputSplitAnnualVintages[r, p, t, o, op] = set() + M.outputSplitAnnualVintages[r, p, t, o, op].add(v) if t in M.tech_resource and (r, p, o) not in M.processByPeriodAndOutput: M.processByPeriodAndOutput[r, p, o] = set() @@ -903,16 +892,6 @@ def CreateSparseDicts(M: 'TemoaModel'): if t in M.tech_downramping: M.rampDownVintages[r, p, t].add(v) - # tech split - if (r, p, i, t) in M.LimitTechInputSplit: - M.inputSplitVintages[r, p, i, t].add(v) - if (r, p, i, t) in M.LimitTechInputSplitAnnual: - M.inputSplitAnnualVintages[r, p, i, t].add(v) - if (r, p, t, o) in M.LimitTechOutputSplit: - M.outputSplitVintages[r, p, t, o].add(v) - if (r, p, t, o) in M.LimitTechOutputSplitAnnual: - M.outputSplitAnnualVintages[r, p, t, o].add(v) - if t in M.tech_resource: M.processByPeriodAndOutput[r, p, o].add((i, t, v)) if t in M.tech_reserve: @@ -1532,16 +1511,16 @@ def ReserveMarginIndices(M: 'TemoaModel'): def LimitTechInputSplitConstraintIndices(M: 'TemoaModel'): indices = set( - (r, p, s, d, i, t, v) - for r, p, i, t in M.inputSplitVintages.keys() + (r, p, s, d, i, t, v, op) + for r, p, i, t, op in M.inputSplitVintages.keys() if t not in M.tech_annual - for v in M.inputSplitVintages[r, p, i, t] + for v in M.inputSplitVintages[r, p, i, t, op] for s in M.time_season[p] for d in M.time_of_day ) ann_indices = set( - (r, p, i, t) - for r, p, i, t in M.inputSplitVintages.keys() + (r, p, i, t, op) + for r, p, i, t, op in M.inputSplitVintages.keys() if t in M.tech_annual ) if len(ann_indices) > 0: @@ -1556,10 +1535,10 @@ def LimitTechInputSplitConstraintIndices(M: 'TemoaModel'): def LimitTechInputSplitAnnualConstraintIndices(M: 'TemoaModel'): indices = set( - (r, p, i, t, v) - for r, p, i, t in M.inputSplitAnnualVintages.keys() + (r, p, i, t, v, op) + for r, p, i, t, op in M.inputSplitAnnualVintages.keys() if t in M.tech_annual - for v in M.inputSplitAnnualVintages[r, p, i, t] + for v in M.inputSplitAnnualVintages[r, p, i, t, op] ) return indices @@ -1567,26 +1546,26 @@ def LimitTechInputSplitAnnualConstraintIndices(M: 'TemoaModel'): def LimitTechInputSplitAverageConstraintIndices(M: 'TemoaModel'): indices = set( - (r, p, i, t, v) - for r, p, i, t in M.inputSplitAnnualVintages.keys() + (r, p, i, t, v, op) + for r, p, i, t, op in M.inputSplitAnnualVintages.keys() if t not in M.tech_annual - for v in M.inputSplitAnnualVintages[r, p, i, t] + for v in M.inputSplitAnnualVintages[r, p, i, t, op] ) return indices def LimitTechOutputSplitConstraintIndices(M: 'TemoaModel'): indices = set( - (r, p, s, d, t, v, o) - for r, p, t, o in M.outputSplitVintages.keys() + (r, p, s, d, t, v, o, op) + for r, p, t, o, op in M.outputSplitVintages.keys() if t not in M.tech_annual - for v in M.outputSplitVintages[r, p, t, o] + for v in M.outputSplitVintages[r, p, t, o, op] for s in M.time_season[p] for d in M.time_of_day ) ann_indices = set( - (r, p, t, o) - for r, p, t, o in M.outputSplitVintages.keys() + (r, p, t, o, op) + for r, p, t, o, op in M.outputSplitVintages.keys() if t in M.tech_annual ) if len(ann_indices) > 0: @@ -1601,20 +1580,20 @@ def LimitTechOutputSplitConstraintIndices(M: 'TemoaModel'): def LimitTechOutputSplitAnnualConstraintIndices(M: 'TemoaModel'): indices = set( - (r, p, t, v, o) - for r, p, t, o in M.outputSplitAnnualVintages.keys() + (r, p, t, v, o, op) + for r, p, t, o, op in M.outputSplitAnnualVintages.keys() if t in M.tech_annual - for v in M.outputSplitAnnualVintages[r, p, t, o] + for v in M.outputSplitAnnualVintages[r, p, t, o, op] ) return indices def LimitTechOutputSplitAverageConstraintIndices(M: 'TemoaModel'): indices = set( - (r, p, t, v, o) - for r, p, t, o in M.outputSplitAnnualVintages.keys() + (r, p, t, v, o, op) + for r, p, t, o, op in M.outputSplitAnnualVintages.keys() if t not in M.tech_annual - for v in M.outputSplitAnnualVintages[r, p, t, o] + for v in M.outputSplitAnnualVintages[r, p, t, o, op] ) return indices diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 91eec5842..b0c1f07ba 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -760,21 +760,21 @@ def __init__(M, *args, **kwargs): ## Tech input splits M.LimitTechInputSplitConstraint_rpsditv = Set( - dimen=7, initialize=LimitTechInputSplitConstraintIndices + dimen=8, initialize=LimitTechInputSplitConstraintIndices ) M.LimitTechInputSplitConstraint = Constraint( M.LimitTechInputSplitConstraint_rpsditv, rule=LimitTechInputSplit_Constraint ) M.LimitTechInputSplitAnnualConstraint_rpitv = Set( - dimen=5, initialize=LimitTechInputSplitAnnualConstraintIndices + dimen=6, initialize=LimitTechInputSplitAnnualConstraintIndices ) M.LimitTechInputSplitAnnualConstraint = Constraint( M.LimitTechInputSplitAnnualConstraint_rpitv, rule=LimitTechInputSplitAnnual_Constraint ) M.LimitTechInputSplitAverageConstraint_rpitv = Set( - dimen=5, initialize=LimitTechInputSplitAverageConstraintIndices + dimen=6, initialize=LimitTechInputSplitAverageConstraintIndices ) M.LimitTechInputSplitAverageConstraint = Constraint( M.LimitTechInputSplitAverageConstraint_rpitv, rule=LimitTechInputSplitAverage_Constraint @@ -782,21 +782,21 @@ def __init__(M, *args, **kwargs): ## Tech output splits M.LimitTechOutputSplitConstraint_rpsdtvo = Set( - dimen=7, initialize=LimitTechOutputSplitConstraintIndices + dimen=8, initialize=LimitTechOutputSplitConstraintIndices ) M.LimitTechOutputSplitConstraint = Constraint( M.LimitTechOutputSplitConstraint_rpsdtvo, rule=LimitTechOutputSplit_Constraint ) M.LimitTechOutputSplitAnnualConstraint_rptvo = Set( - dimen=5, initialize=LimitTechOutputSplitAnnualConstraintIndices + dimen=6, initialize=LimitTechOutputSplitAnnualConstraintIndices ) M.LimitTechOutputSplitAnnualConstraint = Constraint( M.LimitTechOutputSplitAnnualConstraint_rptvo, rule=LimitTechOutputSplitAnnual_Constraint ) M.LimitTechOutputSplitAverageConstraint_rptvo = Set( - dimen=5, initialize=LimitTechOutputSplitAverageConstraintIndices + dimen=6, initialize=LimitTechOutputSplitAverageConstraintIndices ) M.LimitTechOutputSplitAverageConstraint = Constraint( M.LimitTechOutputSplitAverageConstraint_rptvo, rule=LimitTechOutputSplitAverage_Constraint From 26f95bf06efb6919db0571c9e172c485b63a38fc Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 9 Jun 2025 13:59:02 -0400 Subject: [PATCH 090/587] Removing strict inequality operators because solvers do not support them --- data_files/temoa_schema_v3_2.sql | 2 -- temoa/temoa_model/temoa_rules.py | 8 ++------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/data_files/temoa_schema_v3_2.sql b/data_files/temoa_schema_v3_2.sql index 843fce5c0..2ac50478d 100644 --- a/data_files/temoa_schema_v3_2.sql +++ b/data_files/temoa_schema_v3_2.sql @@ -388,8 +388,6 @@ CREATE TABLE IF NOT EXISTS Operator notes TEXT ); REPLACE INTO Operator VALUES('e','equal to'); -REPLACE INTO Operator VALUES('l','less than'); -REPLACE INTO Operator VALUES('g','greater than'); REPLACE INTO Operator VALUES('le','less than or equal to'); REPLACE INTO Operator VALUES('ge','greater than or equal to'); CREATE TABLE IF NOT EXISTS LimitGrowthCapacity diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index a748ba1c8..b4c8d8098 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -2975,18 +2975,14 @@ def operator_expression(lhs: Expression | None, operator: str | None, rhs: Expre match operator: case "e": expr = lhs == rhs - case "l": - expr = lhs < rhs - case "g": - expr = lhs > rhs case "le": expr = lhs <= rhs case "ge": expr = lhs >= rhs case _: msg = ( - 'Tried to build a constraint using a bad operator: {} {} {}' - ).format(lhs, operator, rhs) + 'Tried to build a constraint using a bad operator. Allowed operators are "e","le", or "ge". Got "{}": {} {} {}' + ).format(operator, lhs, operator, rhs) logger.error(msg) raise ValueError(msg) except Exception as e: From d2e2ced51d9e37b4933941f29ce6a7eb6d8fafcd Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 9 Jun 2025 15:57:15 -0400 Subject: [PATCH 091/587] Update tests for new operators scheme --- data_files/example_dbs/materials.sql | 4 +- temoa/temoa_model/hybrid_loader.py | 2 +- tests/test_material_results.py | 2 +- tests/test_storage.py | 37 +- tests/testing_data/emissions.sql | 973 +- tests/testing_data/materials.sql | 1582 +- tests/testing_data/mediumville.sql | 1038 +- tests/testing_data/mediumville_sets.json | 9386 +- tests/testing_data/simple_linked_tech.sql | 935 +- tests/testing_data/storageville.sql | 987 +- tests/testing_data/test_system.sql | 1438 +- tests/testing_data/test_system_sets.json | 93805 ++++++++++---------- tests/testing_data/utopia.sql | 1478 +- tests/testing_data/utopia_sets.json | 51764 +++++------ 14 files changed, 82016 insertions(+), 81415 deletions(-) diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index e1617d14b..9dc5b2e4e 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -208,8 +208,8 @@ INSERT INTO Commodity VALUES('phosphorous','a','phosphorous'); INSERT INTO Commodity VALUES('diesel','a','diesel'); INSERT INTO Commodity VALUES('heating','d','demand for residential heating'); INSERT INTO Commodity VALUES('nickel','a','nickel'); -INSERT INTO Commodity VALUES('used_batt_nmc','aw','used battery - lithium nickel manganese cobalt oxide'); -INSERT INTO Commodity VALUES('used_batt_lfp','aw','used battery - lithium iron phosphate'); +INSERT INTO Commodity VALUES('used_batt_nmc','wa','used battery - lithium nickel manganese cobalt oxide'); +INSERT INTO Commodity VALUES('used_batt_lfp','wa','used battery - lithium iron phosphate'); INSERT INTO Commodity VALUES('co2e','e','emitted co2-equivalent GHGs'); INSERT INTO Commodity VALUES('waste_steel','w','waste steel from cars'); CREATE TABLE CommodityType diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 494bfbe35..860848ce2 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -1039,7 +1039,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # StorageFraction if self.table_exists('LimitStorageLevelFraction'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tod, tech, vintage, fraction FROM main.LimitStorageLevelFraction') + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tod, tech, vintage, operator, fraction FROM main.LimitStorageLevelFraction') load_element(M.LimitStorageFraction, raw, self.viable_rtv, (0,4,5)) # For T/S: dump the size of all data elements into the log diff --git a/tests/test_material_results.py b/tests/test_material_results.py index 70676f61b..0f6282ca0 100644 --- a/tests/test_material_results.py +++ b/tests/test_material_results.py @@ -63,7 +63,7 @@ def solved_connection(request, tmp_path_factory): # List of tech archetypes to test and their correct flowout value flow_tests = [ - {'name': 'lithium import', 'tech': 'LI_IMPORT', 'period': 2005, 'target': 0.199}, + {'name': 'lithium import', 'tech': 'IMPORT_LI', 'period': 2000, 'target': 0.129291623}, ] # Flows diff --git a/tests/test_storage.py b/tests/test_storage.py index 9f2965cea..3b214536c 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -38,14 +38,14 @@ def test_storage_fraction(system_test_run): model: TemoaModel # helps with typing for some reason... data_name, results, model, _ = system_test_run - assert len(model.StorageFractionConstraint_rpsdtv) > 0, ( + assert len(model.LimitStorageFractionConstraint_rpsdtv) > 0, ( 'This model does not appear to have any StorageFraction constraints to test' ) - for r, p, s, d, t, v in model.StorageFractionConstraint_rpsdtv: + for r, p, s, d, t, v, op in model.LimitStorageFractionConstraint_rpsdtv: energy = ( - model.StorageFraction[r, p, s, d, t, v] + model.LimitStorageFraction[r, p, s, d, t, v, op] * model.V_Capacity[r, p, t, v].value * model.CapacityToActivity[r, t] * (model.StorageDuration[r, t] / 8760) @@ -141,18 +141,19 @@ def test_storage_flow_balance(system_test_run): ' - there is a discontinuity of storage states') -@pytest.mark.skip('not ready for primetime') -def test_hard_initialization(): - filename = 'config_storageville.toml' - options = {'silent': True, 'debug': True} - config_file = pathlib.Path(PROJECT_ROOT, 'tests', 'testing_configs', filename) - - sequencer = TemoaSequencer( - config_file=config_file, - output_path=tmp_path, - mode_override=TemoaMode.BUILD_ONLY, - **options, - ) - # get a built, unsolved model - model = sequencer.start() - model.V_StorageInit['electricville', 'batt', 2025] = 0.5 +# devnote: the StorageInit constraint was reworked into LimitStorageLevelFraction +# @pytest.mark.skip('not ready for primetime') +# def test_hard_initialization(): +# filename = 'config_storageville.toml' +# options = {'silent': True, 'debug': True} +# config_file = pathlib.Path(PROJECT_ROOT, 'tests', 'testing_configs', filename) + +# sequencer = TemoaSequencer( +# config_file=config_file, +# output_path=tmp_path, +# mode_override=TemoaMode.BUILD_ONLY, +# **options, +# ) +# # get a built, unsolved model +# model = sequencer.start() +# model.V_StorageInit['electricville', 'batt', 2025] = 0.5 diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 3946802ae..5a3900a93 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -128,6 +128,9 @@ CREATE TABLE CommodityType PRIMARY KEY, description TEXT ); +INSERT INTO CommodityType VALUES('w','waste commodity'); +INSERT INTO CommodityType VALUES('wa','waste annual commodity'); +INSERT INTO CommodityType VALUES('wp','waste physical commodity'); INSERT INTO CommodityType VALUES('a','annual commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); @@ -147,24 +150,9 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -CREATE TABLE EndOfLifeOutput -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); CREATE TABLE CostEmission ( - region TEXT - REFERENCES Region (region), + region TEXT, period INTEGER REFERENCES TimePeriod (period), emis_comm TEXT NOT NULL @@ -252,16 +240,19 @@ CREATE TABLE DemandSpecificDistribution PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -CREATE TABLE LoanRate +CREATE TABLE EndOfLifeOutput ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES TimePeriod (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); CREATE TABLE Efficiency ( @@ -381,25 +372,6 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE GrowthRateMax -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE GrowthRateSeed -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - seed REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) -); CREATE TABLE LoanLifetimeTech ( region TEXT, @@ -409,6 +381,17 @@ CREATE TABLE LoanLifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); +CREATE TABLE LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); CREATE TABLE LifetimeProcess ( region TEXT, @@ -429,196 +412,483 @@ CREATE TABLE LifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO LifetimeTech VALUES('TestRegion','TechEndOfLife',5,NULL); -CREATE TABLE LinkedTech +INSERT INTO LifetimeTech VALUES('TestRegion','TechEndOfLife',5.0,NULL); +CREATE TABLE Operator ( - primary_region TEXT, - primary_tech TEXT + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO Operator VALUES('e','equal to'); +INSERT INTO Operator VALUES('le','less than or equal to'); +INSERT INTO Operator VALUES('ge','greater than or equal to'); +CREATE TABLE LimitGrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - emis_comm TEXT - REFERENCES Commodity (name), - driven_tech TEXT + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxActivity +CREATE TABLE LimitGrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -INSERT INTO MaxActivity VALUES('TestRegion',2000,'TechFlex',1.0,NULL,NULL); -INSERT INTO MaxActivity VALUES('TestRegion',2000,'TechAnnualFlex',1.0,NULL,NULL); -CREATE TABLE MaxCapacity +CREATE TABLE LimitDegrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -INSERT INTO MaxCapacity VALUES('TestRegion',2000,'TechOrdinary',1.0,NULL,NULL); -INSERT INTO MaxCapacity VALUES('TestRegion',2000,'TechCurtailment',1.0,NULL,NULL); -CREATE TABLE MaxResource +CREATE TABLE LimitGrowthNewCapacityDelta ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_res REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthNewCapacityDelta +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitStorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE MinActivity +CREATE TABLE LimitActivity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_act REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech, operator) ); -INSERT INTO MinActivity VALUES('TestRegion',2000,'TechFlex',1.0,NULL,NULL); -INSERT INTO MinActivity VALUES('TestRegion',2000,'TechAnnualFlex',1.0,NULL,NULL); -CREATE TABLE MaxCapacityGroup +INSERT INTO LimitActivity VALUES('TestRegion',2000,'TechFlex','ge',1.0,NULL,NULL); +INSERT INTO LimitActivity VALUES('TestRegion',2000,'TechAnnualFlex','ge',1.0,NULL,NULL); +INSERT INTO LimitActivity VALUES('TestRegion',2000,'TechFlex','le',1.0,NULL,NULL); +INSERT INTO LimitActivity VALUES('TestRegion',2000,'TechAnnualFlex','le',1.0,NULL,NULL); +CREATE TABLE LimitActivityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - max_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) +); +CREATE TABLE LimitActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) +); +CREATE TABLE LimitAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + source TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator), + CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE MinCapacity +CREATE TABLE LimitCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech, operator) ); -INSERT INTO MinCapacity VALUES('TestRegion',2000,'TechOrdinary',1.0,NULL,NULL); -INSERT INTO MinCapacity VALUES('TestRegion',2000,'TechCurtailment',1.0,NULL,NULL); -CREATE TABLE MinCapacityGroup +INSERT INTO LimitCapacity VALUES('TestRegion',2000,'TechOrdinary','ge',1.0,NULL,NULL); +INSERT INTO LimitCapacity VALUES('TestRegion',2000,'TechCurtailment','ge',1.0,NULL,NULL); +INSERT INTO LimitCapacity VALUES('TestRegion',2000,'TechOrdinary','le',1.0,NULL,NULL); +INSERT INTO LimitCapacity VALUES('TestRegion',2000,'TechCurtailment','le',1.0,NULL,NULL); +CREATE TABLE LimitCapacityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) ); -CREATE TABLE OutputCurtailment +CREATE TABLE LimitCapacityShare ( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) ); -CREATE TABLE OutputNetCapacity +CREATE TABLE LimitNewCapacity ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator) +); +CREATE TABLE LimitNewCapacityGroup +( + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name, operator) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE LimitNewCapacityGroupShare ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE LimitNewCapacityShare ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) ); -CREATE TABLE OutputFlowIn +CREATE TABLE LimitResource ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitSeasonalActivity +( + region TEXT + REFERENCES Region (region), + period INTEGER REFERENCES TimePeriod (period), - season TEXT + season TEXT REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY(region,period,season,tech, operator) +); +CREATE TABLE LimitTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); CREATE TABLE OutputFlowOut ( @@ -652,7 +922,7 @@ CREATE TABLE OutputStorageLevel period INTEGER REFERENCES TimePeriod (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -717,23 +987,6 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE StorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage) -); CREATE TABLE TechnologyType ( label TEXT @@ -744,110 +997,6 @@ INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE MinTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MinTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MinTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MinTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -875,14 +1024,14 @@ CREATE TABLE TimeSeason ); INSERT INTO TimeSeason VALUES('S1'); CREATE TABLE PeriodSeasons -( +( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, season TEXT REFERENCES TimeSeason (season), notes TEXT, - PRIMARY KEY (period, sequence) + PRIMARY KEY (period, sequence, season) ); INSERT INTO PeriodSeasons VALUES(2000,1,'S1',NULL); INSERT INTO PeriodSeasons VALUES(2005,1,'S1',NULL); @@ -894,188 +1043,6 @@ CREATE TABLE TimePeriodType ); INSERT INTO TimePeriodType VALUES('e','existing vintages'); INSERT INTO TimePeriodType VALUES('f','future'); -CREATE TABLE MaxActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE MaxNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MaxNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MaxNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE MinCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MinNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MinNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); -CREATE TABLE MaxNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1093,72 +1060,6 @@ CREATE TABLE OutputEmission emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE MinActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE EmissionLimit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE MaxActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "min_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); -CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "max_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); CREATE TABLE RPSRequirement ( region TEXT NOT NULL @@ -1206,7 +1107,7 @@ INSERT INTO Technology VALUES('TechEndOfLife','p','energy',NULL,NULL,0,0,0,0,0,0 CREATE TABLE OutputCost ( scenario TEXT, - region TEXT REFERENCES Region (region), + region TEXT, sector TEXT REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index f3f7f93e0..be08a13bd 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -84,6 +84,102 @@ CREATE TABLE CapacityFactorTech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'spring','overnight','SOL_PV',0.0,NULL); CREATE TABLE CapacityToActivity ( region TEXT, @@ -101,17 +197,30 @@ CREATE TABLE Commodity REFERENCES CommodityType (label), description TEXT ); -INSERT INTO Commodity VALUES('ethos','s',NULL); -INSERT INTO Commodity VALUES('electricity','p',NULL); -INSERT INTO Commodity VALUES('li','a',NULL); -INSERT INTO Commodity VALUES('li_waste','a',NULL); -INSERT INTO Commodity VALUES('passenger_km','d',NULL); +INSERT INTO Commodity VALUES('ethos','s','import dummy source'); +INSERT INTO Commodity VALUES('electricity','p','grid electricity'); +INSERT INTO Commodity VALUES('passenger_km','d','demand for passenger km'); +INSERT INTO Commodity VALUES('battery_nmc','a','battery - lithium nickel manganese cobalt oxide'); +INSERT INTO Commodity VALUES('battery_lfp','a','battery - lithium iron phosphate'); +INSERT INTO Commodity VALUES('lithium','a','lithium'); +INSERT INTO Commodity VALUES('cobalt','a','cobalt'); +INSERT INTO Commodity VALUES('phosphorous','a','phosphorous'); +INSERT INTO Commodity VALUES('diesel','a','diesel'); +INSERT INTO Commodity VALUES('heating','d','demand for residential heating'); +INSERT INTO Commodity VALUES('nickel','a','nickel'); +INSERT INTO Commodity VALUES('used_batt_nmc','wa','used battery - lithium nickel manganese cobalt oxide'); +INSERT INTO Commodity VALUES('used_batt_lfp','wa','used battery - lithium iron phosphate'); +INSERT INTO Commodity VALUES('co2e','e','emitted co2-equivalent GHGs'); +INSERT INTO Commodity VALUES('waste_steel','w','waste steel from cars'); CREATE TABLE CommodityType ( label TEXT PRIMARY KEY, description TEXT ); +INSERT INTO CommodityType VALUES('w','waste commodity'); +INSERT INTO CommodityType VALUES('wa','waste annual commodity'); +INSERT INTO CommodityType VALUES('wp','waste physical commodity'); INSERT INTO CommodityType VALUES('a','annual commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); @@ -131,27 +240,21 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -INSERT INTO ConstructionInput VALUES('TestRegion','li','ELECTRIC_CAR',2000,1.0,NULL,NULL); -INSERT INTO ConstructionInput VALUES('TestRegion','li','ELECTRIC_CAR',2005,1.0,NULL,NULL); -CREATE TABLE EndOfLifeOutput -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -INSERT INTO EndOfLifeOutput VALUES('TestRegion','ELECTRIC_CAR',2000,'li_waste',1.0,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionA','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionA','battery_lfp','CAR_PHEV',2000,0.1000000000000000055,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionA','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionA','battery_lfp','CAR_PHEV',2010,0.1000000000000000055,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionA','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionA','battery_lfp','CAR_PHEV',2020,0.1000000000000000055,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionB','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionB','battery_lfp','CAR_PHEV',2000,0.1000000000000000055,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionB','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionB','battery_lfp','CAR_PHEV',2010,0.1000000000000000055,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionB','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionB','battery_lfp','CAR_PHEV',2020,0.1000000000000000055,NULL,NULL); CREATE TABLE CostEmission ( - region TEXT - REFERENCES Region (region), + region TEXT, period INTEGER REFERENCES TimePeriod (period), emis_comm TEXT NOT NULL @@ -161,6 +264,12 @@ CREATE TABLE CostEmission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); +INSERT INTO CostEmission VALUES('RegionA',2000,'co2e',1.0,NULL,NULL); +INSERT INTO CostEmission VALUES('RegionA',2010,'co2e',1.0,NULL,NULL); +INSERT INTO CostEmission VALUES('RegionA',2020,'co2e',1.0,NULL,NULL); +INSERT INTO CostEmission VALUES('RegionB',2000,'co2e',1.0,NULL,NULL); +INSERT INTO CostEmission VALUES('RegionB',2010,'co2e',1.0,NULL,NULL); +INSERT INTO CostEmission VALUES('RegionB',2020,'co2e',1.0,NULL,NULL); CREATE TABLE CostFixed ( region TEXT NOT NULL, @@ -187,6 +296,40 @@ CREATE TABLE CostInvest notes TEXT, PRIMARY KEY (region, tech, vintage) ); +INSERT INTO CostInvest VALUES('RegionA','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','CAR_PHEV',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','CAR_PHEV',2010,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','CAR_PHEV',2020,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','CAR_ICE',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','CAR_ICE',2010,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','CAR_ICE',2020,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','RECYCLE_NMC',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','RECYCLE_LFP',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','MANUFAC_NMC',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','MANUFAC_LFP',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','BATT_GRID',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','SOL_PV',2000,10.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA','GEN_DSL',2000,2.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','CAR_PHEV',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','CAR_PHEV',2010,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','CAR_PHEV',2020,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','CAR_ICE',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','CAR_ICE',2010,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','CAR_ICE',2020,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','RECYCLE_NMC',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','RECYCLE_LFP',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','MANUFAC_NMC',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','MANUFAC_LFP',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','BATT_GRID',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','GEN_DSL',2000,2.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionA-RegionB','ELEC_INTERTIE',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB-RegionA','ELEC_INTERTIE',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('RegionB','SOL_PV',2000,1.0,NULL,NULL); CREATE TABLE CostVariable ( region TEXT NOT NULL, @@ -201,10 +344,42 @@ CREATE TABLE CostVariable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostVariable VALUES('TestRegion',2000,'ELEC_IMPORT',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('TestRegion',2005,'ELEC_IMPORT',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('TestRegion',2000,'LI_IMPORT',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('TestRegion',2005,'LI_IMPORT',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2000,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2010,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2020,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2000,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2010,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2020,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2000,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2010,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2020,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2000,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2010,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2020,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionA',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2000,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2010,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2020,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2000,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2010,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2020,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2000,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2010,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2020,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2000,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2010,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2020,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO CostVariable VALUES('RegionB',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); CREATE TABLE Demand ( region TEXT, @@ -217,8 +392,18 @@ CREATE TABLE Demand notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO Demand VALUES('TestRegion',2000,'passenger_km',1.0,NULL,NULL); -INSERT INTO Demand VALUES('TestRegion',2005,'passenger_km',1.0,NULL,NULL); +INSERT INTO Demand VALUES('RegionA',2000,'passenger_km',1.0,NULL,NULL); +INSERT INTO Demand VALUES('RegionA',2010,'passenger_km',1.0,NULL,NULL); +INSERT INTO Demand VALUES('RegionA',2020,'passenger_km',1.0,NULL,NULL); +INSERT INTO Demand VALUES('RegionA',2000,'heating',1.0,NULL,NULL); +INSERT INTO Demand VALUES('RegionA',2010,'heating',1.0,NULL,NULL); +INSERT INTO Demand VALUES('RegionA',2020,'heating',1.0,NULL,NULL); +INSERT INTO Demand VALUES('RegionB',2000,'passenger_km',1.0,NULL,NULL); +INSERT INTO Demand VALUES('RegionB',2010,'passenger_km',1.0,NULL,NULL); +INSERT INTO Demand VALUES('RegionB',2020,'passenger_km',1.0,NULL,NULL); +INSERT INTO Demand VALUES('RegionB',2000,'heating',1.0,NULL,NULL); +INSERT INTO Demand VALUES('RegionB',2010,'heating',1.0,NULL,NULL); +INSERT INTO Demand VALUES('RegionB',2020,'heating',1.0,NULL,NULL); CREATE TABLE DemandSpecificDistribution ( region TEXT, @@ -235,17 +420,146 @@ CREATE TABLE DemandSpecificDistribution PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -CREATE TABLE LoanRate +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'summer','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','morning','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','morning','heating',0.1600000000000000033,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'spring','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'summer','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','afternoon','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','afternoon','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'spring','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'summer','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','evening','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','evening','heating',0.1600000000000000033,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'spring','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'summer','overnight','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','overnight','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','overnight','heating',0.1600000000000000033,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'spring','overnight','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'summer','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','morning','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','morning','heating',0.1600000000000000033,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'spring','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'summer','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','afternoon','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','afternoon','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'spring','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'summer','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','evening','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','evening','heating',0.1600000000000000033,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'spring','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'summer','overnight','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','overnight','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','overnight','heating',0.1600000000000000033,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'spring','overnight','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'summer','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','morning','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','morning','heating',0.1600000000000000033,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'spring','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'summer','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','afternoon','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','afternoon','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'spring','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'summer','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','evening','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','evening','heating',0.1600000000000000033,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'spring','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'summer','overnight','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','overnight','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','overnight','heating',0.1600000000000000033,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'spring','overnight','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'summer','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','morning','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','morning','heating',0.1600000000000000033,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'spring','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'summer','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','afternoon','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','afternoon','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'spring','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'summer','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','evening','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','evening','heating',0.1600000000000000033,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'spring','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'summer','overnight','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','overnight','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','overnight','heating',0.1600000000000000033,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'spring','overnight','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'summer','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','morning','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','morning','heating',0.1600000000000000033,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'spring','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'summer','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','afternoon','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','afternoon','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'spring','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'summer','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','evening','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','evening','heating',0.1600000000000000033,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'spring','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'summer','overnight','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','overnight','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','overnight','heating',0.1600000000000000033,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'spring','overnight','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'summer','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','morning','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','morning','heating',0.1600000000000000033,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'spring','morning','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'summer','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','afternoon','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','afternoon','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'spring','afternoon','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'summer','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','evening','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','evening','heating',0.1600000000000000033,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'spring','evening','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'summer','overnight','heating',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','overnight','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','overnight','heating',0.1600000000000000033,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'spring','overnight','heating',0.0,NULL); +CREATE TABLE EndOfLifeOutput ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES TimePeriod (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',1990,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2000,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2010,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',1990,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2000,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2010,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); CREATE TABLE Efficiency ( region TEXT, @@ -262,12 +576,84 @@ CREATE TABLE Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO Efficiency VALUES('TestRegion','electricity','ELECTRIC_CAR',2000,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('TestRegion','ethos','LI_IMPORT',2000,'li',1.0,NULL); -INSERT INTO Efficiency VALUES('TestRegion','ethos','ELEC_IMPORT',2000,'electricity',1.0,NULL); -INSERT INTO Efficiency VALUES('TestRegion','electricity','ELECTRIC_CAR',2005,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('TestRegion','li_waste','LI_RECYCLE',2005,'li',0.8,NULL); -INSERT INTO Efficiency VALUES('TestRegion','electricity','LI_RECYCLE',2005,'li',0.001,NULL); +INSERT INTO Efficiency VALUES('RegionA','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2000000000000000111,NULL); +INSERT INTO Efficiency VALUES('RegionA','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2000000000000000111,NULL); +INSERT INTO Efficiency VALUES('RegionA','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','electricity','RECYCLE_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionA','electricity','RECYCLE_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionA','electricity','MANUFAC_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionA','electricity','MANUFAC_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionA','diesel','GEN_DSL',2000,'electricity',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','ethos','SOL_PV',2000,'electricity',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','electricity','BATT_GRID',2000,'electricity',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','diesel','FURNACE',2000,'heating',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','electricity','HEATPUMP',2000,'heating',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2000000000000000111,NULL); +INSERT INTO Efficiency VALUES('RegionB','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2000000000000000111,NULL); +INSERT INTO Efficiency VALUES('RegionB','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','electricity','RECYCLE_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionB','electricity','RECYCLE_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionB','electricity','MANUFAC_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionB','electricity','MANUFAC_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionB','diesel','GEN_DSL',2000,'electricity',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','ethos','SOL_PV',2000,'electricity',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','electricity','BATT_GRID',2000,'electricity',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','diesel','FURNACE',2000,'heating',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','electricity','HEATPUMP',2000,'heating',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); +INSERT INTO Efficiency VALUES('RegionA-RegionB','electricity','ELEC_INTERTIE',2000,'electricity',0.9000000000000000222,NULL); +INSERT INTO Efficiency VALUES('RegionB-RegionA','electricity','ELEC_INTERTIE',2000,'electricity',0.9000000000000000222,NULL); CREATE TABLE EfficiencyVariable ( region TEXT, @@ -308,6 +694,8 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); +INSERT INTO EmissionActivity VALUES('RegionA','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); +INSERT INTO EmissionActivity VALUES('RegionB','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); CREATE TABLE EmissionEmbodied ( region TEXT, @@ -348,31 +736,18 @@ CREATE TABLE ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); +INSERT INTO ExistingCapacity VALUES('RegionA','CAR_BEV',1990,1.0,NULL,NULL); +INSERT INTO ExistingCapacity VALUES('RegionA','CAR_PHEV',1990,1.0,NULL,NULL); +INSERT INTO ExistingCapacity VALUES('RegionA','CAR_ICE',1990,1.0,NULL,NULL); +INSERT INTO ExistingCapacity VALUES('RegionB','CAR_BEV',1990,1.0,NULL,NULL); +INSERT INTO ExistingCapacity VALUES('RegionB','CAR_PHEV',1990,1.0,NULL,NULL); +INSERT INTO ExistingCapacity VALUES('RegionB','CAR_ICE',1990,1.0,NULL,NULL); CREATE TABLE TechGroup ( group_name TEXT PRIMARY KEY, notes TEXT ); -CREATE TABLE GrowthRateMax -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE GrowthRateSeed -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - seed REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) -); CREATE TABLE LoanLifetimeTech ( region TEXT, @@ -382,6 +757,17 @@ CREATE TABLE LoanLifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); +CREATE TABLE LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); CREATE TABLE LifetimeProcess ( region TEXT, @@ -402,188 +788,534 @@ CREATE TABLE LifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO LifetimeTech VALUES('TestRegion','ELECTRIC_CAR',5.0,NULL); -CREATE TABLE LinkedTech +INSERT INTO LifetimeTech VALUES('RegionA','CAR_BEV',10.0,NULL); +INSERT INTO LifetimeTech VALUES('RegionA','CAR_PHEV',10.0,NULL); +INSERT INTO LifetimeTech VALUES('RegionA','CAR_ICE',10.0,NULL); +INSERT INTO LifetimeTech VALUES('RegionB','CAR_BEV',10.0,NULL); +INSERT INTO LifetimeTech VALUES('RegionB','CAR_PHEV',10.0,NULL); +INSERT INTO LifetimeTech VALUES('RegionB','CAR_ICE',10.0,NULL); +CREATE TABLE Operator ( - primary_region TEXT, - primary_tech TEXT + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO Operator VALUES('e','equal to'); +INSERT INTO Operator VALUES('le','less than or equal to'); +INSERT INTO Operator VALUES('ge','greater than or equal to'); +CREATE TABLE LimitGrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - emis_comm TEXT - REFERENCES Commodity (name), - driven_tech TEXT + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxActivity +CREATE TABLE LimitGrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxCapacity +CREATE TABLE LimitDegrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxResource +CREATE TABLE LimitGrowthNewCapacityDelta ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_res REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthNewCapacityDelta +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitStorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE MinActivity +CREATE TABLE LimitActivity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_act REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech, operator) ); -CREATE TABLE MaxCapacityGroup +CREATE TABLE LimitActivityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - max_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) +); +CREATE TABLE LimitActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) +); +CREATE TABLE LimitAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + source TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator), + CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE MinCapacity +CREATE TABLE LimitCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech, operator) ); -CREATE TABLE MinCapacityGroup +CREATE TABLE LimitCapacityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) ); -CREATE TABLE OutputCurtailment +CREATE TABLE LimitCapacityShare ( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) ); -CREATE TABLE OutputNetCapacity +CREATE TABLE LimitNewCapacity ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator) +); +CREATE TABLE LimitNewCapacityGroup +( + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name, operator) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE LimitNewCapacityGroupShare ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE LimitNewCapacityShare ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) ); -CREATE TABLE OutputFlowIn +CREATE TABLE LimitResource ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitSeasonalActivity +( + region TEXT + REFERENCES Region (region), + period INTEGER REFERENCES TimePeriod (period), - season TEXT + season TEXT REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY(region,period,season,tech, operator) +); +CREATE TABLE LimitTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'diesel','CAR_PHEV','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'diesel','CAR_PHEV','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'diesel','CAR_PHEV','le',0.8000000000000000444,NULL); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'diesel','CAR_PHEV','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'diesel','CAR_PHEV','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'diesel','CAR_PHEV','le',0.8000000000000000444,NULL); +CREATE TABLE LimitTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); CREATE TABLE OutputFlowOut ( @@ -617,7 +1349,7 @@ CREATE TABLE OutputStorageLevel period INTEGER REFERENCES TimePeriod (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -656,7 +1388,8 @@ CREATE TABLE Region PRIMARY KEY, notes TEXT ); -INSERT INTO Region VALUES('TestRegion',NULL); +INSERT INTO Region VALUES('RegionA',NULL); +INSERT INTO Region VALUES('RegionB',NULL); CREATE TABLE TimeSegmentFraction ( period INTEGER @@ -670,10 +1403,54 @@ CREATE TABLE TimeSegmentFraction PRIMARY KEY (period, season, tod), CHECK (segfrac >= 0 AND segfrac <= 1) ); -INSERT INTO TimeSegmentFraction VALUES(2000,'S1','TOD1',0.5,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'S1','TOD2',0.5,NULL); -INSERT INTO TimeSegmentFraction VALUES(2005,'S1','TOD1',0.5,NULL); -INSERT INTO TimeSegmentFraction VALUES(2005,'S1','TOD2',0.5,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'summer','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'autumn','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'winter','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'spring','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'summer','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'autumn','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'winter','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'spring','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'summer','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'autumn','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'winter','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'spring','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'summer','overnight',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'autumn','overnight',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'winter','overnight',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'spring','overnight',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'summer','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'autumn','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'winter','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'spring','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'summer','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'autumn','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'winter','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'spring','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'summer','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'autumn','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'winter','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'spring','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'summer','overnight',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'autumn','overnight',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'winter','overnight',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2010,'spring','overnight',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'summer','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'autumn','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'winter','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'spring','morning',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'summer','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'autumn','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'winter','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'spring','afternoon',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'summer','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'autumn','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'winter','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'spring','evening',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'summer','overnight',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'autumn','overnight',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'winter','overnight',0.0625,NULL); +INSERT INTO TimeSegmentFraction VALUES(2020,'spring','overnight',0.0625,NULL); CREATE TABLE StorageDuration ( region TEXT, @@ -682,23 +1459,8 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE StorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage) -); +INSERT INTO StorageDuration VALUES('RegionA','BATT_GRID',2.0,'2 hours energy storage'); +INSERT INTO StorageDuration VALUES('RegionB','BATT_GRID',2.0,'2 hours energy storage'); CREATE TABLE TechnologyType ( label TEXT @@ -709,120 +1471,16 @@ INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE MinTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MinTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -INSERT INTO MinTechInputSplitAnnual VALUES('TestRegion',2005,'li_waste','LI_RECYCLE',0.5,''); -INSERT INTO MinTechInputSplitAnnual VALUES('TestRegion',2005,'electricity','LI_RECYCLE',0.5,NULL); -CREATE TABLE MinTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MinTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, tod TEXT PRIMARY KEY ); -INSERT INTO TimeOfDay VALUES(1,'TOD1'); -INSERT INTO TimeOfDay VALUES(2,'TOD2'); +INSERT INTO TimeOfDay VALUES(1,'morning'); +INSERT INTO TimeOfDay VALUES(2,'afternoon'); +INSERT INTO TimeOfDay VALUES(3,'evening'); +INSERT INTO TimeOfDay VALUES(4,'overnight'); CREATE TABLE TimePeriod ( sequence INTEGER UNIQUE, @@ -831,28 +1489,42 @@ CREATE TABLE TimePeriod flag TEXT REFERENCES TimePeriodType (label) ); -INSERT INTO TimePeriod VALUES(1,1999,'e'); +INSERT INTO TimePeriod VALUES(1,1990,'e'); INSERT INTO TimePeriod VALUES(2,2000,'f'); -INSERT INTO TimePeriod VALUES(3,2005,'f'); -INSERT INTO TimePeriod VALUES(4,2010,'f'); +INSERT INTO TimePeriod VALUES(3,2010,'f'); +INSERT INTO TimePeriod VALUES(4,2020,'f'); +INSERT INTO TimePeriod VALUES(5,2030,'f'); CREATE TABLE TimeSeason ( season TEXT PRIMARY KEY ); -INSERT INTO TimeSeason VALUES('S1'); +INSERT INTO TimeSeason VALUES('summer'); +INSERT INTO TimeSeason VALUES('autumn'); +INSERT INTO TimeSeason VALUES('winter'); +INSERT INTO TimeSeason VALUES('spring'); CREATE TABLE PeriodSeasons -( +( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, season TEXT REFERENCES TimeSeason (season), notes TEXT, - PRIMARY KEY (period, sequence) -); -INSERT INTO PeriodSeasons VALUES(2000,1,'S1',NULL); -INSERT INTO PeriodSeasons VALUES(2005,1,'S1',NULL); + PRIMARY KEY (period, sequence, season) +); +INSERT INTO PeriodSeasons VALUES(2000,1,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2000,2,'autumn',NULL); +INSERT INTO PeriodSeasons VALUES(2000,3,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2000,4,'spring',NULL); +INSERT INTO PeriodSeasons VALUES(2010,5,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2010,6,'autumn',NULL); +INSERT INTO PeriodSeasons VALUES(2010,7,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2010,8,'spring',NULL); +INSERT INTO PeriodSeasons VALUES(2020,9,'summer',NULL); +INSERT INTO PeriodSeasons VALUES(2020,10,'autumn',NULL); +INSERT INTO PeriodSeasons VALUES(2020,11,'winter',NULL); +INSERT INTO PeriodSeasons VALUES(2020,12,'spring',NULL); CREATE TABLE TimePeriodType ( label TEXT @@ -861,190 +1533,6 @@ CREATE TABLE TimePeriodType ); INSERT INTO TimePeriodType VALUES('e','existing vintages'); INSERT INTO TimePeriodType VALUES('f','future'); -CREATE TABLE MaxActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -INSERT INTO MaxAnnualCapacityFactor VALUES('TestRegion',2000,'ELECTRIC_CAR','passenger_km',0.2,NULL,NULL); -INSERT INTO MaxAnnualCapacityFactor VALUES('TestRegion',2005,'ELECTRIC_CAR','passenger_km',0.2,NULL,NULL); -CREATE TABLE MaxNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MaxNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MaxNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE MinCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MinNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MinNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); -CREATE TABLE MaxNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1062,72 +1550,6 @@ CREATE TABLE OutputEmission emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE MinActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE EmissionLimit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE MaxActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "min_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); -CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "max_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); CREATE TABLE RPSRequirement ( region TEXT NOT NULL @@ -1164,17 +1586,33 @@ CREATE TABLE Technology description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('LI_IMPORT','p','energy',NULL,NULL,1,1,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('LI_RECYCLE','p','energy',NULL,NULL,1,1,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('ELEC_IMPORT','p','energy',NULL,NULL,1,1,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('ELECTRIC_CAR','p','energy',NULL,NULL,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('IMPORT_LI','p','materials',NULL,NULL,1,1,0,0,0,0,0,'lithium importer'); +INSERT INTO Technology VALUES('IMPORT_CO','p','materials',NULL,NULL,1,1,0,0,0,0,0,'cobalt importer'); +INSERT INTO Technology VALUES('IMPORT_P','p','materials',NULL,NULL,1,1,0,0,0,0,0,'phosphorous importer'); +INSERT INTO Technology VALUES('CAR_BEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,'car - battery electric'); +INSERT INTO Technology VALUES('CAR_PHEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,'car - plug in hybrid'); +INSERT INTO Technology VALUES('CAR_ICE','p','transportation',NULL,NULL,0,0,0,0,0,0,0,'car - internal combustion'); +INSERT INTO Technology VALUES('RECYCLE_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,'nmc battery recycler'); +INSERT INTO Technology VALUES('RECYCLE_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,'lfp battery recycler'); +INSERT INTO Technology VALUES('MANUFAC_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,'nmc battery manufacturing'); +INSERT INTO Technology VALUES('MANUFAC_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,'lfp battery manufacturing'); +INSERT INTO Technology VALUES('IMPORT_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,'nickel importer'); +INSERT INTO Technology VALUES('DOMESTIC_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,'domestic nickel production'); +INSERT INTO Technology VALUES('GEN_DSL','p','electricity',NULL,NULL,0,0,0,0,0,0,0,'diesel generators'); +INSERT INTO Technology VALUES('SOL_PV','p','electricity',NULL,NULL,0,0,0,1,0,0,0,'solar panels'); +INSERT INTO Technology VALUES('BATT_GRID','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,'grid battery storage'); +INSERT INTO Technology VALUES('FURNACE','p','residential',NULL,NULL,1,0,0,0,0,0,0,'diesel furnace heater'); +INSERT INTO Technology VALUES('HEATPUMP','p','residential',NULL,NULL,1,0,0,0,0,0,0,'heat pump'); +INSERT INTO Technology VALUES('IMPORT_DSL','p','fuels',NULL,NULL,1,1,0,0,0,0,0,'diesel importer'); +INSERT INTO Technology VALUES('ELEC_INTERTIE','p','electricity',NULL,NULL,0,0,0,0,0,0,1,'dummy tech to make landfill feasible'); CREATE TABLE OutputCost ( scenario TEXT, region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), d_invest REAL, d_fixed REAL, d_var REAL, diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index d0dd0e0a6..66f59220d 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -57,7 +57,7 @@ CREATE TABLE CapacityCredit PRIMARY KEY (region, period, tech, vintage), CHECK (credit >= 0 AND credit <= 1) ); -INSERT INTO CapacityCredit VALUES('A',2025,'EF',2025,0.6,NULL); +INSERT INTO CapacityCredit VALUES('A',2025,'EF',2025,0.5999999999999999778,NULL); CREATE TABLE CapacityFactorProcess ( region TEXT, @@ -75,8 +75,8 @@ CREATE TABLE CapacityFactorProcess PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorProcess VALUES('A',2025,'s2','d1','EFL',2025,0.8,NULL); -INSERT INTO CapacityFactorProcess VALUES('A',2025,'s1','d2','EFL',2025,0.9,NULL); +INSERT INTO CapacityFactorProcess VALUES('A',2025,'s2','d1','EFL',2025,0.8000000000000000444,NULL); +INSERT INTO CapacityFactorProcess VALUES('A',2025,'s1','d2','EFL',2025,0.9000000000000000222,NULL); CREATE TABLE CapacityFactorTech ( region TEXT, @@ -93,7 +93,7 @@ CREATE TABLE CapacityFactorTech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('A',2025,'s1','d1','EF',0.8,NULL); +INSERT INTO CapacityFactorTech VALUES('A',2025,'s1','d1','EF',0.8000000000000000444,NULL); INSERT INTO CapacityFactorTech VALUES('B',2025,'s2','d2','bulbs',0.75,NULL); CREATE TABLE CapacityToActivity ( @@ -129,6 +129,9 @@ CREATE TABLE CommodityType PRIMARY KEY, description TEXT ); +INSERT INTO CommodityType VALUES('w','waste commodity'); +INSERT INTO CommodityType VALUES('wa','waste annual commodity'); +INSERT INTO CommodityType VALUES('wp','waste physical commodity'); INSERT INTO CommodityType VALUES('a','annual commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); @@ -148,24 +151,9 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -CREATE TABLE EndOfLifeOutput -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); CREATE TABLE CostEmission ( - region TEXT - REFERENCES Region (region), + region TEXT, period INTEGER REFERENCES TimePeriod (period), emis_comm TEXT NOT NULL @@ -175,7 +163,7 @@ CREATE TABLE CostEmission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -INSERT INTO CostEmission VALUES('A',2025,'co2',1.9900000000000000355,'dollars','none'); +INSERT INTO CostEmission VALUES('A',2025,'co2',1.989999999999999992,'dollars','none'); CREATE TABLE CostFixed ( region TEXT NOT NULL, @@ -190,7 +178,7 @@ CREATE TABLE CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostFixed VALUES('A',2025,'EH',2025,3.2999999999999998223,'',''); +INSERT INTO CostFixed VALUES('A',2025,'EH',2025,3.299999999999999823,'',''); INSERT INTO CostFixed VALUES('A',2025,'EF',2025,2.0,NULL,NULL); INSERT INTO CostFixed VALUES('A',2025,'EFL',2025,3.0,NULL,NULL); INSERT INTO CostFixed VALUES('B',2025,'batt',2025,1.0,NULL,NULL); @@ -201,7 +189,7 @@ INSERT INTO CostFixed VALUES('A',2025,'heater',2025,2.0,NULL,NULL); INSERT INTO CostFixed VALUES('B',2025,'heater',2025,2.0,NULL,NULL); INSERT INTO CostFixed VALUES('B',2025,'GeoThermal',2025,6.0,NULL,NULL); INSERT INTO CostFixed VALUES('B',2025,'GeoHeater',2025,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('B',2025,'EH',2025,3.2999999999999998223,NULL,NULL); +INSERT INTO CostFixed VALUES('B',2025,'EH',2025,3.299999999999999823,NULL,NULL); INSERT INTO CostFixed VALUES('A',2025,'GeoThermal',2025,4.0,NULL,NULL); INSERT INTO CostFixed VALUES('A',2025,'GeoHeater',2025,4.5,NULL,NULL); CREATE TABLE CostInvest @@ -227,9 +215,9 @@ INSERT INTO CostInvest VALUES('B','heater',2025,9.0,NULL,NULL); INSERT INTO CostInvest VALUES('A','EFL',2025,2.0,NULL,NULL); INSERT INTO CostInvest VALUES('B','GeoThermal',2025,3.0,NULL,NULL); INSERT INTO CostInvest VALUES('B','GeoHeater',2025,4.0,NULL,NULL); -INSERT INTO CostInvest VALUES('B','EH',2025,3.2999999999999998223,NULL,NULL); -INSERT INTO CostInvest VALUES('A','GeoThermal',2025,5.5999999999999996447,NULL,NULL); -INSERT INTO CostInvest VALUES('A','GeoHeater',2025,4.2000000000000001776,NULL,NULL); +INSERT INTO CostInvest VALUES('B','EH',2025,3.299999999999999823,NULL,NULL); +INSERT INTO CostInvest VALUES('A','GeoThermal',2025,5.599999999999999645,NULL,NULL); +INSERT INTO CostInvest VALUES('A','GeoHeater',2025,4.200000000000000177,NULL,NULL); CREATE TABLE CostVariable ( region TEXT NOT NULL, @@ -301,16 +289,19 @@ INSERT INTO DemandSpecificDistribution VALUES('A',2025,'s1','d2','RH',0.25,NULL) INSERT INTO DemandSpecificDistribution VALUES('A',2025,'s2','d2','RH',0.25,NULL); INSERT INTO DemandSpecificDistribution VALUES('B',2025,'s1','d2','RH',0.25,NULL); INSERT INTO DemandSpecificDistribution VALUES('B',2025,'s2','d2','RH',0.25,NULL); -CREATE TABLE LoanRate +CREATE TABLE EndOfLifeOutput ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES TimePeriod (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); CREATE TABLE Efficiency ( @@ -338,13 +329,13 @@ INSERT INTO Efficiency VALUES('B','HYD','EF',2025,'ELC',1.0,NULL); INSERT INTO Efficiency VALUES('A','earth','well',2025,'HYD',1.0,NULL); INSERT INTO Efficiency VALUES('B','earth','well',2025,'HYD',1.0,NULL); INSERT INTO Efficiency VALUES('A','earth','EFL',2025,'FusionGasFuel',1.0,NULL); -INSERT INTO Efficiency VALUES('A','FusionGasFuel','heater',2025,'RH',0.9,NULL); -INSERT INTO Efficiency VALUES('A-B','FusionGasFuel','FGF_pipe',2025,'FusionGasFuel',0.95,NULL); -INSERT INTO Efficiency VALUES('B','FusionGasFuel','heater',2025,'RH',0.9,NULL); -INSERT INTO Efficiency VALUES('B','GeoHyd','GeoHeater',2025,'RH',0.98000000000000007105,NULL); +INSERT INTO Efficiency VALUES('A','FusionGasFuel','heater',2025,'RH',0.9000000000000000222,NULL); +INSERT INTO Efficiency VALUES('A-B','FusionGasFuel','FGF_pipe',2025,'FusionGasFuel',0.949999999999999956,NULL); +INSERT INTO Efficiency VALUES('B','FusionGasFuel','heater',2025,'RH',0.9000000000000000222,NULL); +INSERT INTO Efficiency VALUES('B','GeoHyd','GeoHeater',2025,'RH',0.980000000000000094,NULL); INSERT INTO Efficiency VALUES('B','earth','GeoThermal',2025,'GeoHyd',1.0,NULL); -INSERT INTO Efficiency VALUES('B-A','FusionGasFuel','FGF_pipe',2025,'FusionGasFuel',0.95,NULL); -INSERT INTO Efficiency VALUES('A','GeoHyd','GeoHeater',2025,'RH',0.9,NULL); +INSERT INTO Efficiency VALUES('B-A','FusionGasFuel','FGF_pipe',2025,'FusionGasFuel',0.949999999999999956,NULL); +INSERT INTO Efficiency VALUES('A','GeoHyd','GeoHeater',2025,'RH',0.9000000000000000222,NULL); INSERT INTO Efficiency VALUES('A','earth','GeoThermal',2025,'GeoHyd',1.0,NULL); CREATE TABLE EfficiencyVariable ( @@ -386,8 +377,8 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('A','co2','HYD','EH',2025,'ELC',0.02,NULL,NULL); -INSERT INTO EmissionActivity VALUES('A','FusionGas','HYD','EF',2025,'ELC',-0.2,NULL,'needs to be negative as a driver of linked tech...don''t ask'); +INSERT INTO EmissionActivity VALUES('A','co2','HYD','EH',2025,'ELC',0.02000000000000000041,NULL,NULL); +INSERT INTO EmissionActivity VALUES('A','FusionGas','HYD','EF',2025,'ELC',-0.2000000000000000111,NULL,'needs to be negative as a driver of linked tech...don''t ask'); CREATE TABLE EmissionEmbodied ( region TEXT, @@ -402,6 +393,20 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); +CREATE TABLE EmissionEndOfLife +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); CREATE TABLE ExistingCapacity ( region TEXT, @@ -435,6 +440,17 @@ CREATE TABLE LoanLifetimeTech ); INSERT INTO LoanLifetimeTech VALUES('A','EF',57.0,NULL); INSERT INTO LoanLifetimeTech VALUES('A','EFL',68.0,NULL); +CREATE TABLE LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); CREATE TABLE LifetimeProcess ( region TEXT, @@ -458,200 +474,495 @@ CREATE TABLE LifetimeTech ); INSERT INTO LifetimeTech VALUES('A','EH',60.0,''); INSERT INTO LifetimeTech VALUES('B','bulbs',100.0,'super LED!'); -CREATE TABLE LinkedTech +CREATE TABLE Operator ( - primary_region TEXT, - primary_tech TEXT + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO Operator VALUES('e','equal to'); +INSERT INTO Operator VALUES('le','less than or equal to'); +INSERT INTO Operator VALUES('ge','greater than or equal to'); +CREATE TABLE LimitGrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - emis_comm TEXT - REFERENCES Commodity (name), - driven_tech TEXT + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -INSERT INTO LinkedTech VALUES('A','EF','FusionGas','EFL',NULL); -CREATE TABLE MaxActivity +CREATE TABLE LimitGrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -INSERT INTO MaxActivity VALUES('B',2025,'EH',10000.0,'stuff',NULL); -INSERT INTO MaxActivity VALUES('A',2025,'EF',10000.0,'stuff',NULL); -CREATE TABLE MaxCapacity +CREATE TABLE LimitDegrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -INSERT INTO MaxCapacity VALUES('A',2025,'EH',20000.0,'',''); -INSERT INTO MaxCapacity VALUES('B',2025,'EH',20000.0,'',''); -CREATE TABLE MaxResource +CREATE TABLE LimitGrowthNewCapacityDelta ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_res REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthNewCapacityDelta +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitStorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -INSERT INTO MaxResource VALUES('B','EF',9000.0,'clumps',NULL); -CREATE TABLE MinActivity +CREATE TABLE LimitActivity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_act REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech, operator) ); -INSERT INTO MinActivity VALUES('A',2025,'EF',0.001,'PJ/CY','goofy units'); -CREATE TABLE MaxCapacityGroup +INSERT INTO LimitActivity VALUES('A',2025,'EF','ge',0.00100000000000000002,'PJ/CY','goofy units'); +INSERT INTO LimitActivity VALUES('B',2025,'EH','le',10000.0,'stuff',NULL); +INSERT INTO LimitActivity VALUES('A',2025,'EF','le',10000.0,'stuff',NULL); +CREATE TABLE LimitActivityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - max_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) +); +INSERT INTO LimitActivityGroup VALUES('A',2025,'A_tech_grp_1','ge',0.05000000000000000277,'',NULL); +INSERT INTO LimitActivityGroup VALUES('A',2025,'A_tech_grp_1','le',10000.0,'',NULL); +CREATE TABLE LimitActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) +); +CREATE TABLE LimitAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + source TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator), + CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO MaxCapacityGroup VALUES('A',2025,'A_tech_grp_1',6000.0,'',NULL); -CREATE TABLE MinCapacity +CREATE TABLE LimitCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech, operator) ); -INSERT INTO MinCapacity VALUES('A',2025,'EH',0.1,'',''); -INSERT INTO MinCapacity VALUES('B',2025,'batt',0.1,'',''); -CREATE TABLE MinCapacityGroup +INSERT INTO LimitCapacity VALUES('A',2025,'EH','ge',0.1000000000000000055,'',''); +INSERT INTO LimitCapacity VALUES('B',2025,'batt','ge',0.1000000000000000055,'',''); +INSERT INTO LimitCapacity VALUES('A',2025,'EH','le',20000.0,'',''); +INSERT INTO LimitCapacity VALUES('B',2025,'EH','le',20000.0,'',''); +CREATE TABLE LimitCapacityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) ); -INSERT INTO MinCapacityGroup VALUES('A',2025,'A_tech_grp_1',0.2,'',NULL); -CREATE TABLE OutputCurtailment +INSERT INTO LimitCapacityGroup VALUES('A',2025,'A_tech_grp_1','ge',0.2000000000000000111,'',NULL); +INSERT INTO LimitCapacityGroup VALUES('A',2025,'A_tech_grp_1','le',6000.0,'',NULL); +CREATE TABLE LimitCapacityShare ( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) ); -CREATE TABLE OutputNetCapacity +CREATE TABLE LimitNewCapacity ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator) +); +CREATE TABLE LimitNewCapacityGroup +( + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name, operator) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE LimitNewCapacityGroupShare ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE OutputRetiredCapacity +INSERT INTO LimitNewCapacityGroupShare VALUES('A',2025,'RPS_common','A_tech_grp_1','ge',0.0,''); +INSERT INTO LimitNewCapacityGroupShare VALUES('global',2025,'RPS_common','A_tech_grp_1','le',1.0,''); +CREATE TABLE LimitNewCapacityShare ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) ); -CREATE TABLE OutputFlowIn +CREATE TABLE LimitResource ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +INSERT INTO LimitResource VALUES('B','EF','le',9000.0,'clumps',NULL); +CREATE TABLE LimitSeasonalActivity +( + region TEXT + REFERENCES Region (region), + period INTEGER REFERENCES TimePeriod (period), - season TEXT + season TEXT REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY(region,period,season,tech, operator) ); -CREATE TABLE OutputFlowOut +CREATE TABLE LimitTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +INSERT INTO LimitTechInputSplit VALUES('A',2025,'HYD','EH','ge',0.949999999999999956,'95% HYD reqt. (other not specified...)'); +CREATE TABLE LimitTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +INSERT INTO LimitTechInputSplitAnnual VALUES('A',2025,'GeoHyd','GeoHeater','le',0.8000000000000000444,'80% geothermal'); +CREATE TABLE LimitTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +INSERT INTO LimitTechOutputSplit VALUES('B',2025,'EH','ELC','ge',0.949999999999999956,'95% ELC output (there are not others, this is a min)'); +CREATE TABLE LimitTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +INSERT INTO LimitEmission VALUES('A',2025,'co2','le',10000.0,'gulps',NULL); +CREATE TABLE LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +INSERT INTO LinkedTech VALUES('A','EF','FusionGas','EFL',NULL); +CREATE TABLE OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputFlowOut ( scenario TEXT, region TEXT, @@ -683,7 +994,7 @@ CREATE TABLE OutputStorageLevel period INTEGER REFERENCES TimePeriod (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -700,7 +1011,7 @@ CREATE TABLE PlanningReserveMargin REFERENCES Region (region), margin REAL ); -INSERT INTO PlanningReserveMargin VALUES('A',0.05); +INSERT INTO PlanningReserveMargin VALUES('A',0.05000000000000000277); CREATE TABLE RampDown ( region TEXT, @@ -709,8 +1020,8 @@ CREATE TABLE RampDown rate REAL, PRIMARY KEY (region, tech) ); -INSERT INTO RampDown VALUES('A','EH',0.05); -INSERT INTO RampDown VALUES('B','EH',0.05); +INSERT INTO RampDown VALUES('A','EH',0.05000000000000000277); +INSERT INTO RampDown VALUES('B','EH',0.05000000000000000277); CREATE TABLE RampUp ( region TEXT, @@ -719,8 +1030,8 @@ CREATE TABLE RampUp rate REAL, PRIMARY KEY (region, tech) ); -INSERT INTO RampUp VALUES('B','EH',0.05); -INSERT INTO RampUp VALUES('A','EH',0.05); +INSERT INTO RampUp VALUES('B','EH',0.05000000000000000277); +INSERT INTO RampUp VALUES('A','EH',0.05000000000000000277); CREATE TABLE Region ( region TEXT @@ -755,23 +1066,6 @@ CREATE TABLE StorageDuration PRIMARY KEY (region, tech) ); INSERT INTO StorageDuration VALUES('B','batt',15.0,NULL); -CREATE TABLE StorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage) -); CREATE TABLE TechnologyType ( label TEXT @@ -782,113 +1076,6 @@ INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE MinTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -INSERT INTO MinTechInputSplit VALUES('A',2025,'HYD','EH',0.949999999999999956,'95% HYD reqt. (other not specified...)'); -CREATE TABLE MinTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -INSERT INTO MinTechInputSplitAnnual VALUES('A',2025,'GeoHyd','GeoHeater',0.8000000000000000444,'80% geothermal'); -CREATE TABLE MinTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -INSERT INTO MinTechOutputSplit VALUES('B',2025,'EH','ELC',0.949999999999999956,'95% ELC output (there are not others, this is a min)'); -CREATE TABLE MinTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -916,14 +1103,14 @@ CREATE TABLE TimeSeason INSERT INTO TimeSeason VALUES('s1'); INSERT INTO TimeSeason VALUES('s2'); CREATE TABLE PeriodSeasons -( +( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, season TEXT REFERENCES TimeSeason (season), notes TEXT, - PRIMARY KEY (period, sequence) + PRIMARY KEY (period, sequence, season) ); INSERT INTO PeriodSeasons VALUES(2025,1,'s1',NULL); INSERT INTO PeriodSeasons VALUES(2025,2,'s2',NULL); @@ -935,190 +1122,6 @@ CREATE TABLE TimePeriodType ); INSERT INTO TimePeriodType VALUES('e','existing vintages'); INSERT INTO TimePeriodType VALUES('f','future'); -CREATE TABLE MaxActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE MaxNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MaxNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MaxNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE MinCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MinNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MinNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); -INSERT INTO MinNewCapacityGroupShare VALUES('A',2025,'RPS_common','A_tech_grp_1',0.0,''); -CREATE TABLE MaxNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); -INSERT INTO MaxNewCapacityGroupShare VALUES('global',2025,'RPS_common','A_tech_grp_1',1.0,''); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1136,75 +1139,6 @@ CREATE TABLE OutputEmission emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE MinActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -INSERT INTO MinActivityGroup VALUES('A',2025,'A_tech_grp_1',0.05,'',NULL); -CREATE TABLE EmissionLimit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -INSERT INTO EmissionLimit VALUES('A',2025,'co2',10000.0,'gulps',NULL); -CREATE TABLE MaxActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -INSERT INTO MaxActivityGroup VALUES('A',2025,'A_tech_grp_1',10000.0,'',NULL); -CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "min_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); -CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "max_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); CREATE TABLE RPSRequirement ( region TEXT NOT NULL @@ -1216,7 +1150,7 @@ CREATE TABLE RPSRequirement requirement REAL NOT NULL, notes TEXT ); -INSERT INTO RPSRequirement VALUES('B',2025,'RPS_common',0.3,NULL); +INSERT INTO RPSRequirement VALUES('B',2025,'RPS_common',0.2999999999999999889,NULL); CREATE TABLE TechGroupMember ( group_name TEXT @@ -1258,7 +1192,7 @@ INSERT INTO Technology VALUES('GeoHeater','p','residential','hydro','',0,0,0,0,0 CREATE TABLE OutputCost ( scenario TEXT, - region TEXT REFERENCES Region (region), + region TEXT, sector TEXT REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index e410c7100..078bb5a38 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -1,4492 +1,4902 @@ { - "time_exist": [ - 2020 - ], - "time_future": [ - 2025, - 2030 - ], - "time_optimize": [ - 2025 - ], - "vintage_exist": [ - 2020 - ], - "vintage_optimize": [ - 2025 - ], - "vintage_all": [ - 2020, - 2025 - ], - "time_season_all": [ - "s1", - "s2" - ], - "time_season": [ - 2025 - ], - "TimeNext": [], - "time_of_day": [ - "d1", - "d2" - ], - "regions": [ - "A", - "B" - ], - "regionalIndices": [ - "A", - "A-B", - "B", - "B-A" - ], - "regionalGlobalIndices": [ - "global", - "A", - "B" - ], - "tech_resource": [ - "well" - ], - "tech_production": [ - "bulbs", - "EH", - "batt", - "EF", - "EFL", - "heater", - "FGF_pipe", - "GeoThermal", - "GeoHeater" - ], - "tech_all": [ - "well", - "bulbs", - "EH", - "batt", - "EF", - "EFL", - "heater", - "FGF_pipe", - "GeoThermal", - "GeoHeater" - ], - "tech_baseload": [ - "EH" - ], - "tech_annual": [ - "GeoThermal" - ], - "tech_storage": [ - "batt" - ], - "tech_reserve": [ - "EH" - ], - "tech_upramping": [ - "EH" - ], - "tech_downramping": [ - "EH" - ], - "tech_curtailment": [ - "EH" - ], - "tech_flex": [ - "EFL" - ], - "tech_exchange": [ - "FGF_pipe" - ], - "tech_group_names": [ - "A_tech_grp_1", - "RPS_common", - "RPS_global" - ], - "tech_group_members": [ - "A_tech_grp_1", - "RPS_common", - "RPS_global" - ], - "tech_uncap": [], - "tech_with_capacity": [ - "well", - "bulbs", - "EH", - "batt", - "EF", - "EFL", - "heater", - "FGF_pipe", - "GeoThermal", - "GeoHeater" - ], - "tech_retirement": [ - "EH" - ], - "commodity_demand": [ - "RL", - "RH" - ], - "commodity_emissions": [ - "co2", - "FusionGas" - ], - "commodity_flex" : [ - "FusionGasFuel" - ], - "commodity_physical": [ - "ELC", - "HYD", - "earth", - "FusionGasFuel", - "GeoHyd" - ], - "commodity_source": [], - "commodity_annual": [], - "commodity_carrier": [ - "ELC", - "HYD", - "earth", - "FusionGasFuel", - "GeoHyd", - "RL", - "RH" - ], - "commodity_all": [ - "ELC", - "HYD", - "earth", - "FusionGasFuel", - "GeoHyd", - "RL", - "RH", - "co2", - "FusionGas" - ], - "CapacityFactor_rpsdt": [ - [ - "B", - 2025, - "s1", - "d1", - "well" + "AnnualCommodityBalanceConstraint_rpc": [], + "AnnualRetirementVar_rptv": [], + "BaseloadDiurnalConstraint_rpsdtv": [ + [ + "B", + 2025, + "s1", + "d1", + "EH", + 2025 + ], + [ + "A", + 2025, + "s2", + "d2", + "EH", + 2025 + ], + [ + "B", + 2025, + "s1", + "d2", + "EH", + 2025 + ], + [ + "A", + 2025, + "s1", + "d1", + "EH", + 2025 + ], + [ + "B", + 2025, + "s2", + "d2", + "EH", + 2025 + ], + [ + "A", + 2025, + "s1", + "d2", + "EH", + 2025 + ], + [ + "B", + 2025, + "s2", + "d1", + "EH", + 2025 + ], + [ + "A", + 2025, + "s2", + "d1", + "EH", + 2025 + ] + ], + "CapacityAnnualConstraint_rptv": [ + [ + "A", + 2025, + "GeoThermal", + 2025 + ], + [ + "B", + 2025, + "GeoThermal", + 2025 + ] + ], + "CapacityAvailableVar_rpt": [ + [ + "A-B", + 2025, + "FGF_pipe" + ], + [ + "B", + 2025, + "bulbs" + ], + [ + "A", + 2025, + "GeoThermal" + ], + [ + "B", + 2025, + "well" + ], + [ + "B", + 2025, + "GeoThermal" + ], + [ + "A", + 2025, + "GeoHeater" + ], + [ + "B", + 2025, + "heater" + ], + [ + "A", + 2025, + "EH" + ], + [ + "A", + 2025, + "EFL" + ], + [ + "A", + 2025, + "EF" + ], + [ + "A", + 2025, + "heater" + ], + [ + "A", + 2025, + "bulbs" + ], + [ + "B-A", + 2025, + "FGF_pipe" + ], + [ + "B", + 2025, + "batt" + ], + [ + "B", + 2025, + "GeoHeater" + ], + [ + "B", + 2025, + "EF" + ], + [ + "B", + 2025, + "EH" + ], + [ + "A", + 2025, + "well" + ] + ], + "CapacityConstraint_rpsdtv": [ + [ + "A", + 2025, + "s2", + "d2", + "heater", + 2025 + ], + [ + "A", + 2025, + "s2", + "d1", + "EFL", + 2025 + ], + [ + "B", + 2025, + "s1", + "d1", + "EF", + 2025 + ], + [ + "B", + 2025, + "s2", + "d2", + "heater", + 2025 + ], + [ + "B", + 2025, + "s2", + "d1", + "bulbs", + 2025 + ], + [ + "B-A", + 2025, + "s2", + "d1", + "FGF_pipe", + 2025 + ], + [ + "A", + 2025, + "s1", + "d2", + "heater", + 2025 + ], + [ + "A", + 2025, + "s2", + "d1", + "well", + 2025 + ], + [ + "B", + 2025, + "s2", + "d2", + "EH", + 2025 + ], + [ + "A-B", + 2025, + "s2", + "d1", + "FGF_pipe", + 2025 + ], + [ + "B", + 2025, + "s1", + "d1", + "well", + 2025 + ], + [ + "B", + 2025, + "s1", + "d2", + "bulbs", + 2025 + ], + [ + "A", + 2025, + "s2", + "d1", + "EF", + 2025 + ], + [ + "A", + 2025, + "s1", + "d2", + "EH", + 2025 + ], + [ + "A", + 2025, + "s1", + "d2", + "GeoHeater", + 2025 + ], + [ + "B", + 2025, + "s2", + "d1", + "EH", + 2025 + ], + [ + "A-B", + 2025, + "s1", + "d1", + "FGF_pipe", + 2025 + ], + [ + "B", + 2025, + "s2", + "d1", + "GeoHeater", + 2025 + ], + [ + "A", + 2025, + "s2", + "d1", + "bulbs", + 2025 + ], + [ + "B", + 2025, + "s1", + "d2", + "EH", + 2025 + ], + [ + "B", + 2025, + "s2", + "d2", + "GeoHeater", + 2025 + ], + [ + "B", + 2025, + "s2", + "d1", + "heater", + 2025 + ], + [ + "B", + 2025, + "s1", + "d2", + "GeoHeater", + 2025 + ], + [ + "A", + 2025, + "s1", + "d1", + "EF", + 2025 + ], + [ + "A", + 2025, + "s2", + "d2", + "EFL", + 2025 + ], + [ + "B-A", + 2025, + "s1", + "d2", + "FGF_pipe", + 2025 + ], + [ + "B", + 2025, + "s1", + "d2", + "heater", + 2025 + ], + [ + "A", + 2025, + "s1", + "d1", + "EFL", + 2025 + ], + [ + "B", + 2025, + "s1", + "d1", + "bulbs", + 2025 + ], + [ + "B-A", + 2025, + "s1", + "d1", + "FGF_pipe", + 2025 + ], + [ + "A", + 2025, + "s1", + "d1", + "well", + 2025 + ], + [ + "A", + 2025, + "s2", + "d2", + "EF", + 2025 + ], + [ + "A-B", + 2025, + "s2", + "d2", + "FGF_pipe", + 2025 + ], + [ + "A", + 2025, + "s2", + "d1", + "EH", + 2025 + ], + [ + "A", + 2025, + "s2", + "d2", + "GeoHeater", + 2025 + ], + [ + "A", + 2025, + "s2", + "d2", + "well", + 2025 + ], + [ + "B", + 2025, + "s1", + "d1", + "EH", + 2025 + ], + [ + "B", + 2025, + "s1", + "d1", + "heater", + 2025 + ], + [ + "A", + 2025, + "s2", + "d1", + "heater", + 2025 + ], + [ + "B", + 2025, + "s1", + "d1", + "GeoHeater", + 2025 + ], + [ + "A", + 2025, + "s2", + "d1", + "GeoHeater", + 2025 + ], + [ + "A", + 2025, + "s1", + "d1", + "bulbs", + 2025 + ], + [ + "B", + 2025, + "s2", + "d2", + "well", + 2025 + ], + [ + "A", + 2025, + "s1", + "d2", + "EFL", + 2025 + ], + [ + "A", + 2025, + "s1", + "d2", + "well", + 2025 + ], + [ + "A", + 2025, + "s1", + "d2", + "EF", + 2025 + ], + [ + "B", + 2025, + "s2", + "d2", + "EF", + 2025 + ], + [ + "A", + 2025, + "s2", + "d2", + "bulbs", + 2025 + ], + [ + "B", + 2025, + "s2", + "d1", + "well", + 2025 + ], + [ + "A", + 2025, + "s1", + "d1", + "heater", + 2025 + ], + [ + "A", + 2025, + "s2", + "d2", + "EH", + 2025 + ], + [ + "B", + 2025, + "s1", + "d2", + "EF", + 2025 + ], + [ + "A-B", + 2025, + "s1", + "d2", + "FGF_pipe", + 2025 + ], + [ + "B", + 2025, + "s2", + "d1", + "EF", + 2025 + ], + [ + "A", + 2025, + "s1", + "d1", + "GeoHeater", + 2025 + ], + [ + "A", + 2025, + "s1", + "d1", + "EH", + 2025 + ], + [ + "B", + 2025, + "s1", + "d2", + "well", + 2025 + ], + [ + "A", + 2025, + "s1", + "d2", + "bulbs", + 2025 + ], + [ + "B-A", + 2025, + "s2", + "d2", + "FGF_pipe", + 2025 + ], + [ + "B", + 2025, + "s2", + "d2", + "bulbs", + 2025 + ] + ], + "CapacityFactor_rpsdt": [ + [ + "A", + 2025, + "s2", + "d2", + "bulbs" + ], + [ + "B", + 2025, + "s1", + "d1", + "well" + ], + [ + "B", + 2025, + "s2", + "d1", + "heater" + ], + [ + "B", + 2025, + "s2", + "d1", + "EH" + ], + [ + "A", + 2025, + "s1", + "d2", + "bulbs" + ], + [ + "B", + 2025, + "s1", + "d2", + "well" + ], + [ + "B", + 2025, + "s2", + "d1", + "EF" + ], + [ + "B", + 2025, + "s2", + "d2", + "EH" + ], + [ + "B", + 2025, + "s2", + "d2", + "EF" + ], + [ + "B", + 2025, + "s2", + "d2", + "heater" + ], + [ + "A", + 2025, + "s2", + "d1", + "well" + ], + [ + "B", + 2025, + "s1", + "d1", + "EH" + ], + [ + "B", + 2025, + "s1", + "d1", + "EF" + ], + [ + "B", + 2025, + "s1", + "d1", + "heater" + ], + [ + "A", + 2025, + "s1", + "d1", + "well" + ], + [ + "B", + 2025, + "s1", + "d2", + "heater" + ], + [ + "B", + 2025, + "s1", + "d2", + "EH" + ], + [ + "A", + 2025, + "s2", + "d1", + "heater" + ], + [ + "B", + 2025, + "s1", + "d2", + "EF" + ], + [ + "A", + 2025, + "s2", + "d1", + "EH" + ], + [ + "A", + 2025, + "s2", + "d1", + "EF" + ], + [ + "B", + 2025, + "s2", + "d1", + "GeoHeater" + ], + [ + "B-A", + 2025, + "s2", + "d1", + "FGF_pipe" + ], + [ + "A", + 2025, + "s1", + "d1", + "EH" + ], + [ + "B", + 2025, + "s2", + "d2", + "GeoHeater" + ], + [ + "B-A", + 2025, + "s2", + "d2", + "FGF_pipe" + ], + [ + "A", + 2025, + "s2", + "d2", + "well" + ], + [ + "A", + 2025, + "s1", + "d1", + "EF" + ], + [ + "A", + 2025, + "s1", + "d1", + "heater" + ], + [ + "B", + 2025, + "s1", + "d1", + "GeoHeater" + ], + [ + "B-A", + 2025, + "s1", + "d1", + "FGF_pipe" + ], + [ + "B", + 2025, + "s2", + "d1", + "GeoThermal" + ], + [ + "A", + 2025, + "s1", + "d2", + "well" + ], + [ + "B-A", + 2025, + "s1", + "d2", + "FGF_pipe" + ], + [ + "A", + 2025, + "s2", + "d2", + "heater" + ], + [ + "B", + 2025, + "s1", + "d2", + "GeoHeater" + ], + [ + "A", + 2025, + "s2", + "d2", + "EH" + ], + [ + "B", + 2025, + "s2", + "d2", + "GeoThermal" + ], + [ + "A", + 2025, + "s2", + "d1", + "GeoHeater" + ], + [ + "A", + 2025, + "s2", + "d2", + "EF" + ], + [ + "A", + 2025, + "s2", + "d1", + "EFL" + ], + [ + "B", + 2025, + "s1", + "d1", + "GeoThermal" + ], + [ + "A", + 2025, + "s1", + "d2", + "EH" + ], + [ + "B", + 2025, + "s1", + "d2", + "GeoThermal" + ], + [ + "A", + 2025, + "s1", + "d1", + "GeoHeater" + ], + [ + "A", + 2025, + "s1", + "d2", + "EF" + ], + [ + "A", + 2025, + "s2", + "d1", + "GeoThermal" + ], + [ + "A", + 2025, + "s1", + "d1", + "EFL" + ], + [ + "A", + 2025, + "s1", + "d2", + "heater" + ], + [ + "B", + 2025, + "s2", + "d1", + "bulbs" + ], + [ + "B", + 2025, + "s2", + "d2", + "bulbs" + ], + [ + "B", + 2025, + "s1", + "d1", + "bulbs" + ], + [ + "A", + 2025, + "s2", + "d2", + "GeoHeater" + ], + [ + "A", + 2025, + "s1", + "d1", + "GeoThermal" + ], + [ + "A", + 2025, + "s2", + "d2", + "EFL" + ], + [ + "B", + 2025, + "s2", + "d1", + "batt" + ], + [ + "A-B", + 2025, + "s2", + "d2", + "FGF_pipe" + ], + [ + "B", + 2025, + "s1", + "d2", + "bulbs" + ], + [ + "A", + 2025, + "s1", + "d2", + "GeoHeater" + ], + [ + "A", + 2025, + "s2", + "d1", + "bulbs" + ], + [ + "A", + 2025, + "s2", + "d2", + "GeoThermal" + ], + [ + "A", + 2025, + "s1", + "d2", + "EFL" + ], + [ + "B", + 2025, + "s1", + "d1", + "batt" + ], + [ + "A-B", + 2025, + "s1", + "d2", + "FGF_pipe" + ], + [ + "B", + 2025, + "s2", + "d2", + "batt" + ], + [ + "A", + 2025, + "s1", + "d1", + "bulbs" + ], + [ + "A-B", + 2025, + "s2", + "d1", + "FGF_pipe" + ], + [ + "B", + 2025, + "s1", + "d2", + "batt" + ], + [ + "B", + 2025, + "s2", + "d1", + "well" + ], + [ + "A", + 2025, + "s1", + "d2", + "GeoThermal" + ], + [ + "A-B", + 2025, + "s1", + "d1", + "FGF_pipe" + ], + [ + "B", + 2025, + "s2", + "d2", + "well" + ] + ], + "CapacityVar_rptv": [ + [ + "A", + 2025, + "GeoThermal", + 2025 + ], + [ + "A", + 2025, + "EF", + 2025 + ], + [ + "A", + 2025, + "GeoHeater", + 2025 + ], + [ + "A-B", + 2025, + "FGF_pipe", + 2025 + ], + [ + "B", + 2025, + "well", + 2025 + ], + [ + "A", + 2025, + "heater", + 2025 + ], + [ + "B", + 2025, + "bulbs", + 2025 + ], + [ + "B", + 2025, + "GeoThermal", + 2025 + ], + [ + "B", + 2025, + "EF", + 2025 + ], + [ + "A", + 2025, + "EH", + 2025 + ], + [ + "B", + 2025, + "heater", + 2025 + ], + [ + "B", + 2025, + "GeoHeater", + 2025 + ], + [ + "A", + 2025, + "EFL", + 2025 + ], + [ + "A", + 2025, + "bulbs", + 2025 + ], + [ + "B", + 2025, + "batt", + 2025 + ], + [ + "B-A", + 2025, + "FGF_pipe", + 2025 + ], + [ + "B", + 2025, + "EH", + 2025 + ], + [ + "A", + 2025, + "well", + 2025 + ] + ], + "CommodityBalanceConstraint_rpsdc": [ + [ + "B", + 2025, + "s1", + "d1", + "ELC" + ], + [ + "B", + 2025, + "s2", + "d1", + "GeoHyd" + ], + [ + "A", + 2025, + "s1", + "d1", + "HYD" + ], + [ + "B", + 2025, + "s1", + "d2", + "ELC" + ], + [ + "A", + 2025, + "s2", + "d1", + "ELC" + ], + [ + "B", + 2025, + "s1", + "d1", + "GeoHyd" + ], + [ + "B", + 2025, + "s2", + "d2", + "GeoHyd" + ], + [ + "B", + 2025, + "s2", + "d1", + "FusionGasFuel" + ], + [ + "A", + 2025, + "s1", + "d1", + "ELC" + ], + [ + "A", + 2025, + "s2", + "d2", + "HYD" + ], + [ + "B", + 2025, + "s1", + "d2", + "GeoHyd" + ], + [ + "B", + 2025, + "s1", + "d1", + "FusionGasFuel" + ], + [ + "A", + 2025, + "s2", + "d1", + "GeoHyd" + ], + [ + "B", + 2025, + "s2", + "d2", + "FusionGasFuel" + ], + [ + "A", + 2025, + "s1", + "d2", + "HYD" + ], + [ + "B", + 2025, + "s1", + "d2", + "FusionGasFuel" + ], + [ + "A", + 2025, + "s1", + "d1", + "GeoHyd" + ], + [ + "A", + 2025, + "s2", + "d2", + "ELC" + ], + [ + "A", + 2025, + "s2", + "d1", + "FusionGasFuel" + ], + [ + "A", + 2025, + "s1", + "d2", + "ELC" + ], + [ + "A", + 2025, + "s1", + "d1", + "FusionGasFuel" + ], + [ + "A", + 2025, + "s2", + "d2", + "GeoHyd" + ], + [ + "A", + 2025, + "s1", + "d2", + "GeoHyd" + ], + [ + "A", + 2025, + "s2", + "d2", + "FusionGasFuel" + ], + [ + "A", + 2025, + "s1", + "d2", + "FusionGasFuel" + ], + [ + "B", + 2025, + "s2", + "d1", + "HYD" + ], + [ + "B", + 2025, + "s1", + "d1", + "HYD" + ], + [ + "B", + 2025, + "s2", + "d2", + "HYD" + ], + [ + "B", + 2025, + "s2", + "d1", + "ELC" + ], + [ + "B", + 2025, + "s2", + "d2", + "ELC" + ], + [ + "B", + 2025, + "s1", + "d2", + "HYD" + ], + [ + "A", + 2025, + "s2", + "d1", + "HYD" + ] + ], + "CostEmission_rpe": [ + [ + "A", + 2025, + "co2" + ] + ], + "CostFixed_rptv": [ + [ + "A", + 2025, + "GeoThermal", + 2025 + ], + [ + "A", + 2025, + "EF", + 2025 + ], + [ + "A", + 2025, + "GeoHeater", + 2025 + ], + [ + "A-B", + 2025, + "FGF_pipe", + 2025 + ], + [ + "B", + 2025, + "well", + 2025 + ], + [ + "A", + 2025, + "heater", + 2025 + ], + [ + "B", + 2025, + "bulbs", + 2025 + ], + [ + "B", + 2025, + "GeoThermal", + 2025 + ], + [ + "B", + 2025, + "EF", + 2025 + ], + [ + "A", + 2025, + "EH", + 2025 + ], + [ + "B", + 2025, + "heater", + 2025 + ], + [ + "B", + 2025, + "GeoHeater", + 2025 + ], + [ + "A", + 2025, + "EFL", + 2025 + ], + [ + "A", + 2025, + "bulbs", + 2025 + ], + [ + "B", + 2025, + "batt", + 2025 + ], + [ + "B-A", + 2025, + "FGF_pipe", + 2025 + ], + [ + "B", + 2025, + "EH", + 2025 + ], + [ + "A", + 2025, + "well", + 2025 + ] + ], + "CostInvest_rtv": [ + [ + "A", + "heater", + 2025 + ], + [ + "B", + "EF", + 2025 + ], + [ + "A", + "EH", + 2025 + ], + [ + "B", + "GeoHeater", + 2025 + ], + [ + "A", + "GeoHeater", + 2025 + ], + [ + "B", + "heater", + 2025 + ], + [ + "A", + "EFL", + 2025 + ], + [ + "B", + "EH", + 2025 + ], + [ + "B", + "batt", + 2025 + ], + [ + "A", + "bulbs", + 2025 + ], + [ + "A", + "GeoThermal", + 2025 + ], + [ + "A", + "EF", + 2025 + ], + [ + "B", + "bulbs", + 2025 + ], + [ + "B", + "GeoThermal", + 2025 + ] + ], + "CostVariable_rptv": [ + [ + "A", + 2025, + "GeoThermal", + 2025 + ], + [ + "A", + 2025, + "EF", + 2025 + ], + [ + "A", + 2025, + "GeoHeater", + 2025 + ], + [ + "B", + 2025, + "well", + 2025 + ], + [ + "A-B", + 2025, + "FGF_pipe", + 2025 + ], + [ + "A", + 2025, + "heater", + 2025 + ], + [ + "B", + 2025, + "bulbs", + 2025 + ], + [ + "B", + 2025, + "GeoThermal", + 2025 + ], + [ + "B", + 2025, + "EF", + 2025 + ], + [ + "A", + 2025, + "EH", + 2025 + ], + [ + "B", + 2025, + "heater", + 2025 + ], + [ + "B", + 2025, + "GeoHeater", + 2025 + ], + [ + "A", + 2025, + "EFL", + 2025 + ], + [ + "A", + 2025, + "bulbs", + 2025 + ], + [ + "B", + 2025, + "batt", + 2025 + ], + [ + "B-A", + 2025, + "FGF_pipe", + 2025 + ], + [ + "B", + 2025, + "EH", + 2025 + ], + [ + "A", + 2025, + "well", + 2025 + ] + ], + "CurtailmentVar_rpsditvo": [ + [ + "A", + 2025, + "s1", + "d2", + "HYD", + "EH", + 2025, + "ELC" + ], + [ + "A", + 2025, + "s2", + "d1", + "HYD", + "EH", + 2025, + "ELC" + ], + [ + "B", + 2025, + "s2", + "d1", + "HYD", + "EH", + 2025, + "ELC" + ], + [ + "B", + 2025, + "s1", + "d1", + "HYD", + "EH", + 2025, + "ELC" + ], + [ + "A", + 2025, + "s2", + "d2", + "HYD", + "EH", + 2025, + "ELC" + ], + [ + "B", + 2025, + "s1", + "d2", + "HYD", + "EH", + 2025, + "ELC" + ], + [ + "A", + 2025, + "s1", + "d1", + "HYD", + "EH", + 2025, + "ELC" + ], + [ + "B", + 2025, + "s2", + "d2", + "HYD", + "EH", + 2025, + "ELC" + ] + ], + "DemandActivityConstraint_rpsdtv_dem_s0d0": [ + [ + "A", + 2025, + "s2", + "d2", + "heater", + 2025, + "RH", + "s1", + "d1" + ], + [ + "A", + 2025, + "s1", + "d2", + "heater", + 2025, + "RH", + "s1", + "d1" + ], + [ + "A", + 2025, + "s2", + "d1", + "heater", + 2025, + "RH", + "s1", + "d1" + ], + [ + "B", + 2025, + "s2", + "d1", + "GeoHeater", + 2025, + "RH", + "s1", + "d1" + ], + [ + "B", + 2025, + "s2", + "d2", + "heater", + 2025, + "RH", + "s1", + "d1" + ], + [ + "B", + 2025, + "s2", + "d1", + "heater", + 2025, + "RH", + "s1", + "d1" + ], + [ + "A", + 2025, + "s2", + "d1", + "GeoHeater", + 2025, + "RH", + "s1", + "d1" + ], + [ + "B", + 2025, + "s1", + "d2", + "heater", + 2025, + "RH", + "s1", + "d1" + ], + [ + "A", + 2025, + "s1", + "d2", + "GeoHeater", + 2025, + "RH", + "s1", + "d1" + ], + [ + "A", + 2025, + "s2", + "d2", + "GeoHeater", + 2025, + "RH", + "s1", + "d1" + ], + [ + "B", + 2025, + "s1", + "d2", + "GeoHeater", + 2025, + "RH", + "s1", + "d1" + ], + [ + "B", + 2025, + "s2", + "d2", + "GeoHeater", + 2025, + "RH", + "s1", + "d1" + ] + ], + "DemandConstraint_rpsdc": [ + [ + "A", + 2025, + "s1", + "d2", + "RL" + ], + [ + "B", + 2025, + "s2", + "d1", + "RL" + ], + [ + "A", + 2025, + "s1", + "d2", + "RH" + ], + [ + "B", + 2025, + "s2", + "d1", + "RH" + ], + [ + "A", + 2025, + "s1", + "d1", + "RL" + ], + [ + "A", + 2025, + "s1", + "d1", + "RH" + ], + [ + "A", + 2025, + "s2", + "d2", + "RH" + ], + [ + "B", + 2025, + "s1", + "d1", + "RL" + ], + [ + "B", + 2025, + "s2", + "d2", + "RL" + ], + [ + "B", + 2025, + "s1", + "d1", + "RH" + ], + [ + "B", + 2025, + "s2", + "d2", + "RH" + ], + [ + "A", + 2025, + "s2", + "d2", + "RL" + ], + [ + "B", + 2025, + "s1", + "d2", + "RL" + ], + [ + "B", + 2025, + "s1", + "d2", + "RH" + ], + [ + "A", + 2025, + "s2", + "d1", + "RL" + ], + [ + "A", + 2025, + "s2", + "d1", + "RH" + ] + ], + "EmissionActivity_reitvo": [ + [ + "B", + "FusionGas", + "earth", + "GeoThermal", + 2025, + "GeoHyd" + ], + [ + "A", + "FusionGas", + "ELC", + "bulbs", + 2025, + "RL" + ], + [ + "B", + "FusionGas", + "ELC", + "batt", + 2025, + "ELC" + ], + [ + "B", + "FusionGas", + "HYD", + "EF", + 2025, + "ELC" + ], + [ + "A", + "FusionGas", + "HYD", + "EH", + 2025, + "ELC" + ], + [ + "A", + "co2", + "GeoHyd", + "GeoHeater", + 2025, + "RH" + ], + [ + "A", + "FusionGas", + "earth", + "EFL", + 2025, + "FusionGasFuel" + ], + [ + "B", + "co2", + "FusionGasFuel", + "heater", + 2025, + "RH" + ], + [ + "A", + "FusionGas", + "HYD", + "EF", + 2025, + "ELC" + ], + [ + "B", + "FusionGas", + "FusionGasFuel", + "heater", + 2025, + "RH" + ], + [ + "B", + "FusionGas", + "ELC", + "bulbs", + 2025, + "RL" + ], + [ + "B", + "FusionGas", + "GeoHyd", + "GeoHeater", + 2025, + "RH" + ], + [ + "B", + "co2", + "earth", + "GeoThermal", + 2025, + "GeoHyd" + ], + [ + "B", + "co2", + "GeoHyd", + "GeoHeater", + 2025, + "RH" + ], + [ + "A", + "FusionGas", + "FusionGasFuel", + "heater", + 2025, + "RH" + ], + [ + "A", + "co2", + "earth", + "well", + 2025, + "HYD" + ], + [ + "B", + "co2", + "ELC", + "batt", + 2025, + "ELC" + ], + [ + "A", + "co2", + "FusionGasFuel", + "heater", + 2025, + "RH" + ], + [ + "B", + "co2", + "earth", + "well", + 2025, + "HYD" + ], + [ + "A", + "co2", + "HYD", + "EH", + 2025, + "ELC" + ], + [ + "A", + "FusionGas", + "GeoHyd", + "GeoHeater", + 2025, + "RH" + ], + [ + "B", + "co2", + "HYD", + "EF", + 2025, + "ELC" + ], + [ + "B", + "FusionGas", + "earth", + "well", + 2025, + "HYD" + ], + [ + "A", + "co2", + "earth", + "GeoThermal", + 2025, + "GeoHyd" + ], + [ + "A", + "co2", + "earth", + "EFL", + 2025, + "FusionGasFuel" + ], + [ + "A", + "FusionGas", + "earth", + "GeoThermal", + 2025, + "GeoHyd" + ], + [ + "B", + "co2", + "ELC", + "bulbs", + 2025, + "RL" + ], + [ + "A", + "FusionGas", + "earth", + "well", + 2025, + "HYD" + ], + [ + "A", + "co2", + "HYD", + "EF", + 2025, + "ELC" + ], + [ + "B", + "FusionGas", + "HYD", + "EH", + 2025, + "ELC" + ], + [ + "B", + "co2", + "HYD", + "EH", + 2025, + "ELC" + ], + [ + "A", + "co2", + "ELC", + "bulbs", + 2025, + "RL" + ] + ], + "FlexVarAnnual_rpitvo": [], + "FlexVar_rpsditvo": [ + [ + "A", + 2025, + "s2", + "d2", + "earth", + "EFL", + 2025, + "FusionGasFuel" + ], + [ + "A", + 2025, + "s2", + "d1", + "earth", + "EFL", + 2025, + "FusionGasFuel" + ], + [ + "A", + 2025, + "s1", + "d2", + "earth", + "EFL", + 2025, + "FusionGasFuel" + ], + [ + "A", + 2025, + "s1", + "d1", + "earth", + "EFL", + 2025, + "FusionGasFuel" + ] + ], + "FlowInStorage_rpsditvo": [ + [ + "B", + 2025, + "s1", + "d1", + "ELC", + "batt", + 2025, + "ELC" + ], + [ + "B", + 2025, + "s2", + "d1", + "ELC", + "batt", + 2025, + "ELC" + ], + [ + "B", + 2025, + "s2", + "d2", + "ELC", + "batt", + 2025, + "ELC" + ], + [ + "B", + 2025, + "s1", + "d2", + "ELC", + "batt", + 2025, + "ELC" + ] + ], + "FlowVarAnnual_rpitvo": [ + [ + "A", + 2025, + "earth", + "GeoThermal", + 2025, + "GeoHyd" + ], + [ + "B", + 2025, + "earth", + "GeoThermal", + 2025, + "GeoHyd" + ] + ], + "FlowVar_rpsditvo": [ + [ + "B", + 2025, + "s1", + "d1", + "GeoHyd", + "GeoHeater", + 2025, + "RH" + ], + [ + "A", + 2025, + "s2", + "d1", + "GeoHyd", + "GeoHeater", + 2025, + "RH" + ], + [ + "A-B", + 2025, + "s2", + "d1", + "FusionGasFuel", + "FGF_pipe", + 2025, + "FusionGasFuel" + ], + [ + "B", + 2025, + "s1", + "d2", + "ELC", + "bulbs", + 2025, + "RL" + ], + [ + "A", + 2025, + "s1", + "d1", + "ELC", + "bulbs", + 2025, + "RL" + ], + [ + "A", + 2025, + "s2", + "d1", + "earth", + "EFL", + 2025, + "FusionGasFuel" + ], + [ + "A", + 2025, + "s2", + "d2", + "ELC", + "bulbs", + 2025, + "RL" + ], + [ + "B", + 2025, + "s1", + "d1", + "HYD", + "EH", + 2025, + "ELC" + ], + [ + "A-B", + 2025, + "s1", + "d2", + "FusionGasFuel", + "FGF_pipe", + 2025, + "FusionGasFuel" + ], + [ + "A", + 2025, + "s2", + "d1", + "earth", + "well", + 2025, + "HYD" + ], + [ + "A", + 2025, + "s2", + "d2", + "HYD", + "EH", + 2025, + "ELC" + ], + [ + "A", + 2025, + "s1", + "d2", + "FusionGasFuel", + "heater", + 2025, + "RH" + ], + [ + "B-A", + 2025, + "s2", + "d2", + "FusionGasFuel", + "FGF_pipe", + 2025, + "FusionGasFuel" + ], + [ + "A", + 2025, + "s2", + "d1", + "HYD", + "EF", + 2025, + "ELC" + ], + [ + "A", + 2025, + "s2", + "d2", + "earth", + "EFL", + 2025, + "FusionGasFuel" + ], + [ + "B", + 2025, + "s2", + "d1", + "ELC", + "batt", + 2025, + "ELC" + ], + [ + "A", + 2025, + "s1", + "d1", + "FusionGasFuel", + "heater", + 2025, + "RH" + ], + [ + "A", + 2025, + "s1", + "d2", + "GeoHyd", + "GeoHeater", + 2025, + "RH" + ], + [ + "B", + 2025, + "s2", + "d2", + "ELC", + "bulbs", + 2025, + "RL" + ], + [ + "B", + 2025, + "s2", + "d1", + "FusionGasFuel", + "heater", + 2025, + "RH" + ], + [ + "B", + 2025, + "s1", + "d2", + "earth", + "well", + 2025, + "HYD" + ], + [ + "B", + 2025, + "s1", + "d1", + "earth", + "well", + 2025, + "HYD" + ], + [ + "B", + 2025, + "s1", + "d2", + "FusionGasFuel", + "heater", + 2025, + "RH" + ], + [ + "B", + 2025, + "s2", + "d1", + "earth", + "well", + 2025, + "HYD" + ], + [ + "A", + 2025, + "s2", + "d1", + "ELC", + "bulbs", + 2025, + "RL" + ], + [ + "B", + 2025, + "s2", + "d1", + "GeoHyd", + "GeoHeater", + 2025, + "RH" + ], + [ + "A", + 2025, + "s2", + "d2", + "HYD", + "EF", + 2025, + "ELC" + ], + [ + "A", + 2025, + "s1", + "d2", + "earth", + "well", + 2025, + "HYD" + ], + [ + "B", + 2025, + "s2", + "d2", + "FusionGasFuel", + "heater", + 2025, + "RH" + ], + [ + "B", + 2025, + "s1", + "d2", + "HYD", + "EH", + 2025, + "ELC" + ], + [ + "A", + 2025, + "s2", + "d1", + "HYD", + "EH", + 2025, + "ELC" + ], + [ + "B", + 2025, + "s2", + "d1", + "HYD", + "EF", + 2025, + "ELC" + ], + [ + "A", + 2025, + "s1", + "d1", + "GeoHyd", + "GeoHeater", + 2025, + "RH" + ], + [ + "B", + 2025, + "s1", + "d1", + "ELC", + "bulbs", + 2025, + "RL" + ], + [ + "A", + 2025, + "s1", + "d2", + "HYD", + "EF", + 2025, + "ELC" + ], + [ + "B", + 2025, + "s2", + "d2", + "GeoHyd", + "GeoHeater", + 2025, + "RH" + ], + [ + "B", + 2025, + "s1", + "d2", + "GeoHyd", + "GeoHeater", + 2025, + "RH" + ], + [ + "A-B", + 2025, + "s2", + "d2", + "FusionGasFuel", + "FGF_pipe", + 2025, + "FusionGasFuel" + ], + [ + "A", + 2025, + "s2", + "d2", + "FusionGasFuel", + "heater", + 2025, + "RH" + ], + [ + "A", + 2025, + "s2", + "d2", + "GeoHyd", + "GeoHeater", + 2025, + "RH" + ], + [ + "B", + 2025, + "s1", + "d2", + "ELC", + "batt", + 2025, + "ELC" + ], + [ + "B", + 2025, + "s2", + "d1", + "HYD", + "EH", + 2025, + "ELC" + ], + [ + "A-B", + 2025, + "s1", + "d1", + "FusionGasFuel", + "FGF_pipe", + 2025, + "FusionGasFuel" + ], + [ + "A", + 2025, + "s1", + "d1", + "HYD", + "EF", + 2025, + "ELC" + ], + [ + "A", + 2025, + "s1", + "d1", + "earth", + "EFL", + 2025, + "FusionGasFuel" + ], + [ + "B-A", + 2025, + "s2", + "d1", + "FusionGasFuel", + "FGF_pipe", + 2025, + "FusionGasFuel" + ], + [ + "A", + 2025, + "s1", + "d2", + "HYD", + "EH", + 2025, + "ELC" + ], + [ + "B", + 2025, + "s2", + "d2", + "HYD", + "EF", + 2025, + "ELC" + ], + [ + "A", + 2025, + "s2", + "d1", + "FusionGasFuel", + "heater", + 2025, + "RH" + ], + [ + "A", + 2025, + "s1", + "d1", + "earth", + "well", + 2025, + "HYD" + ], + [ + "A", + 2025, + "s1", + "d2", + "ELC", + "bulbs", + 2025, + "RL" + ], + [ + "B", + 2025, + "s2", + "d2", + "earth", + "well", + 2025, + "HYD" + ], + [ + "B", + 2025, + "s1", + "d2", + "HYD", + "EF", + 2025, + "ELC" + ], + [ + "B", + 2025, + "s2", + "d2", + "ELC", + "batt", + 2025, + "ELC" + ], + [ + "B-A", + 2025, + "s1", + "d2", + "FusionGasFuel", + "FGF_pipe", + 2025, + "FusionGasFuel" + ], + [ + "A", + 2025, + "s1", + "d2", + "earth", + "EFL", + 2025, + "FusionGasFuel" + ], + [ + "B", + 2025, + "s2", + "d1", + "ELC", + "bulbs", + 2025, + "RL" + ], + [ + "A", + 2025, + "s2", + "d2", + "earth", + "well", + 2025, + "HYD" + ], + [ + "B", + 2025, + "s1", + "d1", + "HYD", + "EF", + 2025, + "ELC" + ], + [ + "B", + 2025, + "s1", + "d1", + "ELC", + "batt", + 2025, + "ELC" + ], + [ + "B-A", + 2025, + "s1", + "d1", + "FusionGasFuel", + "FGF_pipe", + 2025, + "FusionGasFuel" + ], + [ + "B", + 2025, + "s1", + "d1", + "FusionGasFuel", + "heater", + 2025, + "RH" + ], + [ + "B", + 2025, + "s2", + "d2", + "HYD", + "EH", + 2025, + "ELC" + ], + [ + "A", + 2025, + "s1", + "d1", + "HYD", + "EH", + 2025, + "ELC" + ] + ], + "GroupShareIndices": [ + [ + "global", + 2025, + "EH", + "A_tech_grp_1", + "le" + ], + [ + "A", + 2025, + "EH", + "A_tech_grp_1", + "e" + ], + [ + "B", + 2025, + "EF", + "A_tech_grp_1", + "le" + ], + [ + "global", + 2025, + "EF", + "RPS_common", + "e" + ], + [ + "A", + 2025, + "EH", + "A_tech_grp_1", + "ge" + ], + [ + "B", + 2025, + "EF", + "RPS_common", + "e" + ], + [ + "global", + 2025, + "EF", + "A_tech_grp_1", + "le" + ], + [ + "global", + 2025, + "EF", + "RPS_common", + "ge" + ], + [ + "B", + 2025, + "EF", + "RPS_common", + "ge" + ], + [ + "A", + 2025, + "EF", + "RPS_common", + "le" + ], + [ + "B", + 2025, + "EH", + "A_tech_grp_1", + "le" + ], + [ + "global", + 2025, + "EH", + "A_tech_grp_1", + "e" + ], + [ + "global", + 2025, + "EH", + "A_tech_grp_1", + "ge" + ], + [ + "A", + 2025, + "EF", + "A_tech_grp_1", + "le" + ], + [ + "B", + 2025, + "EF", + "A_tech_grp_1", + "e" + ], + [ + "global", + 2025, + "EF", + "A_tech_grp_1", + "e" + ], + [ + "B", + 2025, + "EF", + "A_tech_grp_1", + "ge" + ], + [ + "global", + 2025, + "EF", + "A_tech_grp_1", + "ge" + ], + [ + "A", + 2025, + "EH", + "A_tech_grp_1", + "le" + ], + [ + "A", + 2025, + "EF", + "RPS_common", + "e" + ], + [ + "global", + 2025, + "EF", + "RPS_common", + "le" + ], + [ + "B", + 2025, + "EH", + "A_tech_grp_1", + "e" + ], + [ + "A", + 2025, + "EF", + "RPS_common", + "ge" + ], + [ + "B", + 2025, + "EF", + "RPS_common", + "le" + ], + [ + "A", + 2025, + "EF", + "A_tech_grp_1", + "e" + ], + [ + "B", + 2025, + "EH", + "A_tech_grp_1", + "ge" + ], + [ + "A", + 2025, + "EF", + "A_tech_grp_1", + "ge" + ] + ], + "LifetimeProcess_rtv": [ + [ + "A", + "heater", + 2025 + ], + [ + "B", + "EF", + 2025 + ], + [ + "B-A", + "FGF_pipe", + 2025 + ], + [ + "A-B", + "FGF_pipe", + 2025 + ], + [ + "A", + "EH", + 2025 + ], + [ + "B", + "bulbs", + 2025 + ], + [ + "A", + "GeoHeater", + 2025 + ], + [ + "B", + "heater", + 2025 + ], + [ + "A", + "EFL", + 2025 + ], + [ + "B", + "EH", + 2025 + ], + [ + "B", + "batt", + 2025 + ], + [ + "A", + "well", + 2025 + ], + [ + "A", + "GeoThermal", + 2025 + ], + [ + "B", + "GeoHeater", + 2025 + ], + [ + "B", + "well", + 2025 + ], + [ + "A", + "EF", + 2025 + ], + [ + "A", + "bulbs", + 2025 + ], + [ + "B", + "GeoThermal", + 2025 + ] + ], + "LimitActivityConstraint_rpt": [ + [ + "B", + 2025, + "EH", + "le" + ], + [ + "A", + 2025, + "EF", + "le" + ], + [ + "A", + 2025, + "EF", + "ge" + ] + ], + "LimitActivityGroup_rpg": [ + [ + "A", + 2025, + "A_tech_grp_1", + "le" + ], + [ + "A", + 2025, + "A_tech_grp_1", + "ge" + ] + ], + "LimitActivityShareConstraint_rptg": [], + "LimitAnnualCapacityFactorConstraint_rpto": [], + "LimitCapacityConstraint_rpt": [ + [ + "B", + 2025, + "batt", + "ge" + ], + [ + "A", + 2025, + "EH", + "ge" + ], + [ + "B", + 2025, + "EH", + "le" + ], + [ + "A", + 2025, + "EH", + "le" + ] + ], + "LimitCapacityGroupConstraint_rpg": [ + [ + "A", + 2025, + "A_tech_grp_1", + "le" + ], + [ + "A", + 2025, + "A_tech_grp_1", + "ge" + ] + ], + "LimitCapacityShareConstraint_rptg": [], + "LimitDegrowthCapacityConstraint_rpt": [], + "LimitDegrowthNewCapacityConstraint_rpt": [], + "LimitDegrowthNewCapacityDeltaConstraint_rpt": [], + "LimitEmissionConstraint_rpe": [ + [ + "A", + 2025, + "co2", + "le" + ] + ], + "LimitGrowthCapacityConstraint_rpt": [], + "LimitGrowthNewCapacityConstraint_rpt": [], + "LimitGrowthNewCapacityDeltaConstraint_rpt": [], + "LimitNewCapacityConstraint_rpt": [], + "LimitNewCapacityGroupConstraint_rpg": [], + "LimitNewCapacityGroupShareConstraint_rpgg": [ + [ + "A", + 2025, + "RPS_common", + "A_tech_grp_1", + "ge" + ], + [ + "global", + 2025, + "RPS_common", + "A_tech_grp_1", + "le" + ] + ], + "LimitNewCapacityShareConstraint_rptg": [], + "LimitResourceConstraint_rt": [ + [ + "B", + "EF", + "le" + ] + ], + "LimitSeasonalActivityConstraint_rpst": [], + "LimitStorageFractionConstraint_rpsdtv": [], + "LimitTechInputSplitAnnualConstraint_rpitv": [], + "LimitTechInputSplitAverageConstraint_rpitv": [ + [ + "A", + 2025, + "GeoHyd", + "GeoHeater", + 2025, + "le" + ] + ], + "LimitTechInputSplitConstraint_rpsditv": [ + [ + "A", + 2025, + "s1", + "d1", + "HYD", + "EH", + 2025, + "ge" + ], + [ + "A", + 2025, + "s2", + "d1", + "HYD", + "EH", + 2025, + "ge" + ], + [ + "A", + 2025, + "s2", + "d2", + "HYD", + "EH", + 2025, + "ge" + ], + [ + "A", + 2025, + "s1", + "d2", + "HYD", + "EH", + 2025, + "ge" + ] + ], + "LimitTechOutputSplitAnnualConstraint_rptvo": [], + "LimitTechOutputSplitAverageConstraint_rptvo": [], + "LimitTechOutputSplitConstraint_rpsdtvo": [ + [ + "B", + 2025, + "s2", + "d1", + "EH", + 2025, + "ELC", + "ge" + ], + [ + "B", + 2025, + "s2", + "d2", + "EH", + 2025, + "ELC", + "ge" + ], + [ + "B", + 2025, + "s1", + "d1", + "EH", + 2025, + "ELC", + "ge" + ], + [ + "B", + 2025, + "s1", + "d2", + "EH", + 2025, + "ELC", + "ge" + ] + ], + "LinkedEmissionsTechConstraint_rpsdtve": [ + [ + "A", + 2025, + "s1", + "d2", + "EF", + 2025, + "FusionGas" + ], + [ + "A", + 2025, + "s2", + "d2", + "EF", + 2025, + "FusionGas" + ], + [ + "A", + 2025, + "s1", + "d1", + "EF", + 2025, + "FusionGas" + ], + [ + "A", + 2025, + "s2", + "d1", + "EF", + 2025, + "FusionGas" + ] + ], + "LoanLifetimeProcess_rtv": [ + [ + "A", + "heater", + 2025 + ], + [ + "B", + "EF", + 2025 + ], + [ + "B-A", + "FGF_pipe", + 2025 + ], + [ + "A-B", + "FGF_pipe", + 2025 + ], + [ + "A", + "EH", + 2025 + ], + [ + "B", + "bulbs", + 2025 + ], + [ + "A", + "GeoHeater", + 2025 + ], + [ + "B", + "heater", + 2025 + ], + [ + "A", + "EFL", + 2025 + ], + [ + "B", + "EH", + 2025 + ], + [ + "B", + "batt", + 2025 + ], + [ + "A", + "well", + 2025 + ], + [ + "A", + "GeoThermal", + 2025 + ], + [ + "B", + "GeoHeater", + 2025 + ], + [ + "B", + "well", + 2025 + ], + [ + "A", + "EF", + 2025 + ], + [ + "A", + "bulbs", + 2025 + ], + [ + "B", + "GeoThermal", + 2025 + ] + ], + "ModelProcessLife_rptv": [ + [ + "A", + 2025, + "GeoThermal", + 2025 + ], + [ + "A", + 2025, + "EF", + 2025 + ], + [ + "A", + 2025, + "GeoHeater", + 2025 + ], + [ + "B", + 2025, + "well", + 2025 + ], + [ + "A-B", + 2025, + "FGF_pipe", + 2025 + ], + [ + "A", + 2025, + "heater", + 2025 + ], + [ + "B", + 2025, + "bulbs", + 2025 + ], + [ + "B", + 2025, + "GeoThermal", + 2025 + ], + [ + "B", + 2025, + "EF", + 2025 + ], + [ + "A", + 2025, + "EH", + 2025 + ], + [ + "B", + 2025, + "heater", + 2025 + ], + [ + "B", + 2025, + "GeoHeater", + 2025 + ], + [ + "A", + 2025, + "EFL", + 2025 + ], + [ + "A", + 2025, + "bulbs", + 2025 + ], + [ + "B", + 2025, + "batt", + 2025 + ], + [ + "B-A", + 2025, + "FGF_pipe", + 2025 + ], + [ + "B", + 2025, + "EH", + 2025 + ], + [ + "A", + 2025, + "well", + 2025 + ] + ], + "NewCapacityVar_rtv": [ + [ + "A", + "heater", + 2025 + ], + [ + "B", + "EF", + 2025 + ], + [ + "B-A", + "FGF_pipe", + 2025 + ], + [ + "A-B", + "FGF_pipe", + 2025 + ], + [ + "A", + "EH", + 2025 + ], + [ + "B", + "bulbs", + 2025 + ], + [ + "A", + "GeoHeater", + 2025 + ], + [ + "B", + "heater", + 2025 + ], + [ + "A", + "EFL", + 2025 + ], + [ + "B", + "EH", + 2025 + ], + [ + "B", + "batt", + 2025 + ], + [ + "A", + "well", + 2025 + ], + [ + "A", + "GeoThermal", + 2025 + ], + [ + "B", + "GeoHeater", + 2025 + ], + [ + "B", + "well", + 2025 + ], + [ + "A", + "EF", + 2025 + ], + [ + "A", + "bulbs", + 2025 + ], + [ + "B", + "GeoThermal", + 2025 + ] + ], + "ProcessLifeFrac_rptv": [ + [ + "A", + 2025, + "GeoThermal", + 2025 + ], + [ + "A", + 2025, + "EF", + 2025 + ], + [ + "A", + 2025, + "GeoHeater", + 2025 + ], + [ + "B", + 2025, + "well", + 2025 + ], + [ + "A-B", + 2025, + "FGF_pipe", + 2025 + ], + [ + "A", + 2025, + "heater", + 2025 + ], + [ + "B", + 2025, + "bulbs", + 2025 + ], + [ + "B", + 2025, + "GeoThermal", + 2025 + ], + [ + "B", + 2025, + "EF", + 2025 + ], + [ + "A", + 2025, + "EH", + 2025 + ], + [ + "B", + 2025, + "heater", + 2025 + ], + [ + "B", + 2025, + "GeoHeater", + 2025 + ], + [ + "A", + 2025, + "EFL", + 2025 + ], + [ + "A", + 2025, + "bulbs", + 2025 + ], + [ + "B", + 2025, + "batt", + 2025 + ], + [ + "B-A", + 2025, + "FGF_pipe", + 2025 + ], + [ + "B", + 2025, + "EH", + 2025 + ], + [ + "A", + 2025, + "well", + 2025 + ] + ], + "RampDownConstraint_rpsdtv": [ + [ + "B", + 2025, + "s1", + "d1", + "EH", + 2025 + ], + [ + "A", + 2025, + "s2", + "d2", + "EH", + 2025 + ], + [ + "B", + 2025, + "s1", + "d2", + "EH", + 2025 + ], + [ + "A", + 2025, + "s1", + "d1", + "EH", + 2025 + ], + [ + "B", + 2025, + "s2", + "d2", + "EH", + 2025 + ], + [ + "A", + 2025, + "s1", + "d2", + "EH", + 2025 + ], + [ + "B", + 2025, + "s2", + "d1", + "EH", + 2025 + ], + [ + "A", + 2025, + "s2", + "d1", + "EH", + 2025 + ] + ], + "RampUpConstraint_rpsdtv": [ + [ + "B", + 2025, + "s1", + "d1", + "EH", + 2025 + ], + [ + "A", + 2025, + "s2", + "d2", + "EH", + 2025 + ], + [ + "B", + 2025, + "s1", + "d2", + "EH", + 2025 + ], + [ + "A", + 2025, + "s1", + "d1", + "EH", + 2025 + ], + [ + "B", + 2025, + "s2", + "d2", + "EH", + 2025 + ], + [ + "A", + 2025, + "s1", + "d2", + "EH", + 2025 + ], + [ + "B", + 2025, + "s2", + "d1", + "EH", + 2025 + ], + [ + "A", + 2025, + "s2", + "d1", + "EH", + 2025 + ] + ], + "RegionalExchangeCapacityConstraint_rrptv": [ + [ + "B", + "A", + 2025, + "FGF_pipe", + 2025 + ], + [ + "A", + "B", + 2025, + "FGF_pipe", + 2025 + ] + ], + "RenewablePortfolioStandardConstraint_rpg": [ + [ + "B", + 2025, + "RPS_common" + ] + ], + "ReserveMargin_rpsd": [ + [ + "B", + 2025, + "s2", + "d1" + ], + [ + "A", + 2025, + "s1", + "d2" + ], + [ + "A", + 2025, + "s2", + "d2" + ], + [ + "A", + 2025, + "s1", + "d1" + ], + [ + "A", + 2025, + "s2", + "d1" + ], + [ + "B", + 2025, + "s1", + "d2" + ], + [ + "B", + 2025, + "s2", + "d2" + ], + [ + "B", + 2025, + "s1", + "d1" + ] + ], + "RetiredCapacityVar_rptv": [], + "StorageConstraints_rpsdtv": [ + [ + "B", + 2025, + "s1", + "d1", + "batt", + 2025 + ], + [ + "B", + 2025, + "s1", + "d2", + "batt", + 2025 + ], + [ + "B", + 2025, + "s2", + "d1", + "batt", + 2025 + ], + [ + "B", + 2025, + "s2", + "d2", + "batt", + 2025 + ] + ], + "StorageLevel_rpsdtv": [ + [ + "B", + 2025, + "s1", + "d1", + "batt", + 2025 + ], + [ + "B", + 2025, + "s1", + "d2", + "batt", + 2025 + ], + [ + "B", + 2025, + "s2", + "d1", + "batt", + 2025 + ], + [ + "B", + 2025, + "s2", + "d2", + "batt", + 2025 + ] + ], + "TimeNext": [], + "TwoGroupShareIndices": [ + [ + "A", + 2025, + "A_tech_grp_1", + "RPS_common", + "ge" + ], + [ + "global", + 2025, + "RPS_global", + "A_tech_grp_1", + "ge" + ], + [ + "A", + 2025, + "RPS_global", + "RPS_common", + "e" + ], + [ + "A", + 2025, + "A_tech_grp_1", + "A_tech_grp_1", + "e" + ], + [ + "global", + 2025, + "A_tech_grp_1", + "RPS_common", + "e" + ], + [ + "B", + 2025, + "RPS_global", + "A_tech_grp_1", + "ge" + ], + [ + "A", + 2025, + "RPS_global", + "RPS_common", + "ge" + ], + [ + "A", + 2025, + "A_tech_grp_1", + "A_tech_grp_1", + "ge" + ], + [ + "global", + 2025, + "RPS_global", + "RPS_common", + "le" + ], + [ + "B", + 2025, + "RPS_global", + "RPS_common", + "le" + ], + [ + "global", + 2025, + "A_tech_grp_1", + "RPS_common", + "ge" + ], + [ + "B", + 2025, + "RPS_common", + "RPS_common", + "le" + ], + [ + "A", + 2025, + "RPS_global", + "A_tech_grp_1", + "e" + ], + [ + "A", + 2025, + "RPS_common", + "A_tech_grp_1", + "e" + ], + [ + "B", + 2025, + "A_tech_grp_1", + "RPS_common", + "le" + ], + [ + "A", + 2025, + "RPS_common", + "A_tech_grp_1", + "ge" + ], + [ + "A", + 2025, + "RPS_global", + "A_tech_grp_1", + "ge" + ], + [ + "global", + 2025, + "RPS_common", + "RPS_common", + "le" + ], + [ + "global", + 2025, + "A_tech_grp_1", + "A_tech_grp_1", + "e" + ], + [ + "A", + 2025, + "RPS_common", + "RPS_common", + "le" + ], + [ + "B", + 2025, + "A_tech_grp_1", + "A_tech_grp_1", + "le" + ], + [ + "global", + 2025, + "A_tech_grp_1", + "A_tech_grp_1", + "ge" + ], + [ + "B", + 2025, + "RPS_common", + "A_tech_grp_1", + "le" + ], + [ + "global", + 2025, + "RPS_common", + "A_tech_grp_1", + "le" + ], + [ + "A", + 2025, + "A_tech_grp_1", + "RPS_common", + "le" + ], + [ + "global", + 2025, + "RPS_global", + "RPS_common", + "e" + ], + [ + "global", + 2025, + "RPS_global", + "A_tech_grp_1", + "le" + ], + [ + "B", + 2025, + "RPS_common", + "RPS_common", + "e" + ], + [ + "B", + 2025, + "A_tech_grp_1", + "RPS_common", + "e" + ], + [ + "B", + 2025, + "RPS_global", + "RPS_common", + "e" + ], + [ + "B", + 2025, + "RPS_global", + "A_tech_grp_1", + "le" + ], + [ + "global", + 2025, + "RPS_global", + "RPS_common", + "ge" + ], + [ + "B", + 2025, + "RPS_common", + "RPS_common", + "ge" + ], + [ + "global", + 2025, + "A_tech_grp_1", + "RPS_common", + "le" + ], + [ + "A", + 2025, + "RPS_global", + "RPS_common", + "le" + ], + [ + "B", + 2025, + "RPS_global", + "RPS_common", + "ge" + ], + [ + "A", + 2025, + "A_tech_grp_1", + "A_tech_grp_1", + "le" + ], + [ + "global", + 2025, + "RPS_common", + "RPS_common", + "e" + ], + [ + "B", + 2025, + "A_tech_grp_1", + "RPS_common", + "ge" + ], + [ + "A", + 2025, + "RPS_common", + "RPS_common", + "e" + ], + [ + "B", + 2025, + "A_tech_grp_1", + "A_tech_grp_1", + "e" + ], + [ + "A", + 2025, + "RPS_common", + "A_tech_grp_1", + "le" + ], + [ + "global", + 2025, + "RPS_common", + "RPS_common", + "ge" + ], + [ + "A", + 2025, + "RPS_global", + "A_tech_grp_1", + "le" + ], + [ + "B", + 2025, + "RPS_common", + "A_tech_grp_1", + "e" + ], + [ + "B", + 2025, + "A_tech_grp_1", + "A_tech_grp_1", + "ge" + ], + [ + "A", + 2025, + "RPS_common", + "RPS_common", + "ge" + ], + [ + "global", + 2025, + "RPS_common", + "A_tech_grp_1", + "e" + ], + [ + "B", + 2025, + "RPS_common", + "A_tech_grp_1", + "ge" + ], + [ + "global", + 2025, + "RPS_common", + "A_tech_grp_1", + "ge" + ], + [ + "A", + 2025, + "A_tech_grp_1", + "RPS_common", + "e" + ], + [ + "global", + 2025, + "A_tech_grp_1", + "A_tech_grp_1", + "le" + ], + [ + "global", + 2025, + "RPS_global", + "A_tech_grp_1", + "e" + ], + [ + "B", + 2025, + "RPS_global", + "A_tech_grp_1", + "e" + ] + ], + "commodity_all": [ + "FusionGas", + "RH", + "HYD", + "GeoHyd", + "RL", + "ELC", + "co2", + "FusionGasFuel", + "earth" + ], + "commodity_annual": [], + "commodity_carrier": [ + "RH", + "HYD", + "GeoHyd", + "RL", + "ELC", + "FusionGasFuel", + "earth" + ], + "commodity_demand": [ + "RL", + "RH" + ], + "commodity_emissions": [ + "FusionGas", + "co2" + ], + "commodity_flex": [ + "FusionGasFuel" + ], + "commodity_physical": [ + "HYD", + "GeoHyd", + "ELC", + "FusionGasFuel", + "earth" + ], + "commodity_source": [], + "commodity_waste": [], + "operator": [ + "ge", + "e", + "le" + ], + "regionalGlobalIndices": [ + "B", + "A", + "global" + ], + "regionalIndices": [ + "B", + "A", + "A-B", + "B-A" + ], + "regions": [ + "B", + "A" + ], + "tech_all": [ + "GeoHeater", + "bulbs", + "EH", + "GeoThermal", + "EFL", + "well", + "heater", + "EF", + "FGF_pipe", + "batt" + ], + "tech_annual": [ + "GeoThermal" + ], + "tech_baseload": [ + "EH" + ], + "tech_curtailment": [ + "EH" + ], + "tech_downramping": [ + "EH" + ], + "tech_exchange": [ + "FGF_pipe" + ], + "tech_exist": [ + "EH" + ], + "tech_flex": [ + "EFL" + ], + "tech_group_members": [ + "A_tech_grp_1", + "RPS_common", + "RPS_global" + ], + "tech_group_names": [ + "A_tech_grp_1", + "RPS_common", + "RPS_global" + ], + "tech_production": [ + "GeoHeater", + "bulbs", + "EH", + "GeoThermal", + "EFL", + "heater", + "EF", + "FGF_pipe", + "batt" + ], + "tech_reserve": [ + "EH" + ], + "tech_resource": [ + "well" + ], + "tech_retirement": [ + "EH" + ], + "tech_storage": [ + "batt" + ], + "tech_uncap": [], + "tech_upramping": [ + "EH" + ], + "tech_with_capacity": [ + "GeoHeater", + "bulbs", + "EH", + "GeoThermal", + "EFL", + "well", + "heater", + "EF", + "FGF_pipe", + "batt" + ], + "time_exist": [ + 2020 + ], + "time_future": [ + 2025, + 2030 + ], + "time_of_day": [ + "d2", + "d1" + ], + "time_optimize": [ + 2025 + ], + "time_season": [ + 2025 + ], + "time_season_all": [ + "s1", + "s2" + ], + "vintage_all": [ + 2025, + 2020 + ], + "vintage_exist": [ + 2020 ], - [ - "B", - 2025, - "s1", - "d2", - "EF" - ], - [ - "B", - 2025, - "s2", - "d2", - "batt" - ], - [ - "B", - 2025, - "s2", - "d2", - "EH" - ], - [ - "B", - 2025, - "s1", - "d2", - "bulbs" - ], - [ - "A-B", - 2025, - "s2", - "d1", - "FGF_pipe" - ], - [ - "A", - 2025, - "s1", - "d1", - "EFL" - ], - [ - "A", - 2025, - "s1", - "d2", - "EFL" - ], - [ - "B-A", - 2025, - "s1", - "d1", - "FGF_pipe" - ], - [ - "B", - 2025, - "s1", - "d1", - "heater" - ], - [ - "A", - 2025, - "s2", - "d2", - "EH" - ], - [ - "A", - 2025, - "s2", - "d1", - "GeoThermal" - ], - [ - "A", - 2025, - "s2", - "d1", - "GeoHeater" - ], - [ - "A-B", - 2025, - "s1", - "d1", - "FGF_pipe" - ], - [ - "B", - 2025, - "s1", - "d2", - "well" - ], - [ - "A", - 2025, - "s1", - "d1", - "GeoHeater" - ], - [ - "B", - 2025, - "s1", - "d1", - "batt" - ], - [ - "A", - 2025, - "s1", - "d1", - "GeoThermal" - ], - [ - "A-B", - 2025, - "s1", - "d2", - "FGF_pipe" - ], - [ - "B", - 2025, - "s2", - "d1", - "GeoThermal" - ], - [ - "A", - 2025, - "s1", - "d2", - "GeoThermal" - ], - [ - "B", - 2025, - "s2", - "d1", - "GeoHeater" - ], - [ - "B", - 2025, - "s1", - "d1", - "EH" - ], - [ - "A", - 2025, - "s1", - "d2", - "GeoHeater" - ], - [ - "A", - 2025, - "s2", - "d1", - "EF" - ], - [ - "B", - 2025, - "s1", - "d2", - "heater" - ], - [ - "A", - 2025, - "s2", - "d1", - "bulbs" - ], - [ - "A", - 2025, - "s2", - "d2", - "EFL" - ], - [ - "A", - 2025, - "s1", - "d1", - "EF" - ], - [ - "B-A", - 2025, - "s1", - "d2", - "FGF_pipe" - ], - [ - "B", - 2025, - "s2", - "d1", - "EF" - ], - [ - "A", - 2025, - "s1", - "d2", - "EF" - ], - [ - "A", - 2025, - "s1", - "d1", - "bulbs" - ], - [ - "B", - 2025, - "s1", - "d2", - "EH" - ], - [ - "B", - 2025, - "s2", - "d1", - "bulbs" - ], - [ - "A", - 2025, - "s1", - "d2", - "bulbs" - ], - [ - "A-B", - 2025, - "s2", - "d2", - "FGF_pipe" - ], - [ - "A", - 2025, - "s2", - "d1", - "well" - ], - [ - "A", - 2025, - "s2", - "d2", - "GeoThermal" - ], - [ - "B", - 2025, - "s2", - "d2", - "GeoHeater" - ], - [ - "A", - 2025, - "s2", - "d2", - "GeoHeater" - ], - [ - "B", - 2025, - "s1", - "d2", - "batt" - ], - [ - "B", - 2025, - "s2", - "d2", - "GeoThermal" - ], - [ - "A", - 2025, - "s2", - "d1", - "heater" - ], - [ - "A", - 2025, - "s1", - "d1", - "well" - ], - [ - "B", - 2025, - "s2", - "d1", - "well" - ], - [ - "B", - 2025, - "s2", - "d2", - "EF" - ], - [ - "A", - 2025, - "s1", - "d2", - "well" - ], - [ - "A", - 2025, - "s2", - "d2", - "EF" - ], - [ - "B", - 2025, - "s1", - "d1", - "GeoThermal" - ], - [ - "B", - 2025, - "s2", - "d2", - "bulbs" - ], - [ - "B", - 2025, - "s1", - "d1", - "GeoHeater" - ], - [ - "A", - 2025, - "s2", - "d2", - "bulbs" - ], - [ - "B-A", - 2025, - "s2", - "d1", - "FGF_pipe" - ], - [ - "A", - 2025, - "s1", - "d1", - "heater" - ], - [ - "B", - 2025, - "s2", - "d1", - "heater" - ], - [ - "A", - 2025, - "s1", - "d2", - "heater" - ], - [ - "A", - 2025, - "s2", - "d1", - "EH" - ], - [ - "B", - 2025, - "s1", - "d1", - "EF" - ], - [ - "B", - 2025, - "s2", - "d2", - "well" - ], - [ - "A", - 2025, - "s1", - "d1", - "EH" - ], - [ - "A", - 2025, - "s2", - "d2", - "well" - ], - [ - "B", - 2025, - "s2", - "d1", - "EH" - ], - [ - "B", - 2025, - "s1", - "d1", - "bulbs" - ], - [ - "B", - 2025, - "s2", - "d1", - "batt" - ], - [ - "B", - 2025, - "s1", - "d2", - "GeoThermal" - ], - [ - "B", - 2025, - "s1", - "d2", - "GeoHeater" - ], - [ - "B-A", - 2025, - "s2", - "d2", - "FGF_pipe" - ], - [ - "A", - 2025, - "s1", - "d2", - "EH" - ], - [ - "B", - 2025, - "s2", - "d2", - "heater" - ], - [ - "A", - 2025, - "s2", - "d2", - "heater" - ], - [ - "A", - 2025, - "s2", - "d1", - "EFL" - ] - ], - "LifetimeProcess_rtv": [ - [ - "A", - "EH", - 2025 - ], - [ - "A", - "GeoThermal", - 2025 - ], - [ - "A", - "EF", - 2025 - ], - [ - "B", - "heater", - 2025 - ], - [ - "B", - "EF", - 2025 - ], - [ - "A", - "bulbs", - 2025 - ], - [ - "A-B", - "FGF_pipe", - 2025 - ], - [ - "B", - "GeoHeater", - 2025 - ], - [ - "B", - "batt", - 2025 - ], - [ - "A", - "heater", - 2025 - ], - [ - "B-A", - "FGF_pipe", - 2025 - ], - [ - "B", - "GeoThermal", - 2025 - ], - [ - "A", - "GeoHeater", - 2025 - ], - [ - "B", - "well", - 2025 - ], - [ - "B", - "EH", - 2025 - ], - [ - "A", - "EFL", - 2025 - ], - [ - "A", - "well", - 2025 - ], - [ - "B", - "bulbs", - 2025 - ] - ], - "LoanLifetimeProcess_rtv": [ - [ - "A", - "EH", - 2025 - ], - [ - "A", - "GeoThermal", - 2025 - ], - [ - "A", - "EF", - 2025 - ], - [ - "B", - "heater", - 2025 - ], - [ - "B", - "EF", - 2025 - ], - [ - "A", - "bulbs", - 2025 - ], - [ - "A-B", - "FGF_pipe", - 2025 - ], - [ - "B", - "GeoHeater", - 2025 - ], - [ - "B", - "batt", - 2025 - ], - [ - "A", - "heater", - 2025 - ], - [ - "B-A", - "FGF_pipe", - 2025 - ], - [ - "B", - "GeoThermal", - 2025 - ], - [ - "A", - "GeoHeater", - 2025 - ], - [ - "B", - "well", - 2025 - ], - [ - "B", - "EH", - 2025 - ], - [ - "A", - "EFL", - 2025 - ], - [ - "A", - "well", - 2025 - ], - [ - "B", - "bulbs", - 2025 - ] - ], - "RenewablePortfolioStandardConstraint_rpg": [ - [ - "B", - 2025, - "RPS_common" - ] - ], - "CostFixed_rptv": [ - [ - "B", - 2025, - "EH", - 2025 - ], - [ - "B", - 2025, - "bulbs", - 2025 - ], - [ - "A", - 2025, - "EF", - 2025 - ], - [ - "A", - 2025, - "well", - 2025 - ], - [ - "A-B", - 2025, - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "EF", - 2025 - ], - [ - "A", - 2025, - "bulbs", - 2025 - ], - [ - "A", - 2025, - "EH", - 2025 - ], - [ - "B", - 2025, - "GeoHeater", - 2025 - ], - [ - "B", - 2025, - "heater", - 2025 - ], - [ - "B", - 2025, - "batt", - 2025 - ], - [ - "A", - 2025, - "GeoHeater", - 2025 - ], - [ - "A", - 2025, - "heater", - 2025 - ], - [ - "B-A", - 2025, - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "GeoThermal", - 2025 - ], - [ - "B", - 2025, - "well", - 2025 - ], - [ - "A", - 2025, - "GeoThermal", - 2025 - ], - [ - "A", - 2025, - "EFL", - 2025 - ] - ], - "CostInvest_rtv": [ - [ - "A", - "EF", - 2025 - ], - [ - "A", - "EH", - 2025 - ], - [ - "A", - "bulbs", - 2025 - ], - [ - "A", - "heater", - 2025 - ], - [ - "B", - "EF", - 2025 - ], - [ - "B", - "batt", - 2025 - ], - [ - "B", - "bulbs", - 2025 - ], - [ - "B", - "heater", - 2025 - ], - [ - "A", - "EFL", - 2025 - ], - [ - "B", - "GeoThermal", - 2025 - ], - [ - "B", - "GeoHeater", - 2025 - ], - [ - "B", - "EH", - 2025 - ], - [ - "A", - "GeoThermal", - 2025 - ], - [ - "A", - "GeoHeater", - 2025 - ] - ], - "CostVariable_rptv": [ - [ - "B", - 2025, - "EH", - 2025 - ], - [ - "A", - 2025, - "GeoHeater", - 2025 - ], - [ - "B", - 2025, - "bulbs", - 2025 - ], - [ - "A", - 2025, - "GeoThermal", - 2025 - ], - [ - "A", - 2025, - "EF", - 2025 - ], - [ - "A", - 2025, - "well", - 2025 - ], - [ - "A-B", - 2025, - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "EF", - 2025 - ], - [ - "A", - 2025, - "bulbs", - 2025 - ], - [ - "A", - 2025, - "EH", - 2025 - ], - [ - "B", - 2025, - "GeoHeater", - 2025 - ], - [ - "B", - 2025, - "heater", - 2025 - ], - [ - "B", - 2025, - "batt", - 2025 - ], - [ - "A", - 2025, - "heater", - 2025 - ], - [ - "B-A", - 2025, - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "GeoThermal", - 2025 - ], - [ - "B", - 2025, - "well", - 2025 - ], - [ - "A", - 2025, - "EFL", - 2025 - ] - ], - "CostEmission_rpe": [ - [ - "A", - 2025, - "co2" - ] - ], - "ModelProcessLife_rptv": [ - [ - "B", - 2025, - "EH", - 2025 - ], - [ - "A", - 2025, - "GeoHeater", - 2025 - ], - [ - "B", - 2025, - "bulbs", - 2025 - ], - [ - "A", - 2025, - "GeoThermal", - 2025 - ], - [ - "A", - 2025, - "EF", - 2025 - ], - [ - "A", - 2025, - "well", - 2025 - ], - [ - "A-B", - 2025, - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "EF", - 2025 - ], - [ - "A", - 2025, - "bulbs", - 2025 - ], - [ - "A", - 2025, - "EH", - 2025 - ], - [ - "B", - 2025, - "GeoHeater", - 2025 - ], - [ - "B", - 2025, - "heater", - 2025 - ], - [ - "B", - 2025, - "batt", - 2025 - ], - [ - "A", - 2025, - "heater", - 2025 - ], - [ - "B-A", - 2025, - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "GeoThermal", - 2025 - ], - [ - "B", - 2025, - "well", - 2025 - ], - [ - "A", - 2025, - "EFL", - 2025 - ] - ], - "ProcessLifeFrac_rptv": [ - [ - "B", - 2025, - "EH", - 2025 - ], - [ - "A", - 2025, - "GeoHeater", - 2025 - ], - [ - "B", - 2025, - "bulbs", - 2025 - ], - [ - "A", - 2025, - "GeoThermal", - 2025 - ], - [ - "A", - 2025, - "EF", - 2025 - ], - [ - "A", - 2025, - "well", - 2025 - ], - [ - "A-B", - 2025, - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "EF", - 2025 - ], - [ - "A", - 2025, - "bulbs", - 2025 - ], - [ - "A", - 2025, - "EH", - 2025 - ], - [ - "B", - 2025, - "GeoHeater", - 2025 - ], - [ - "B", - 2025, - "heater", - 2025 - ], - [ - "B", - 2025, - "batt", - 2025 - ], - [ - "A", - 2025, - "heater", - 2025 - ], - [ - "B-A", - 2025, - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "GeoThermal", - 2025 - ], - [ - "B", - 2025, - "well", - 2025 - ], - [ - "A", - 2025, - "EFL", - 2025 - ] - ], - "MinCapacityConstraint_rpt": [ - [ - "A", - 2025, - "EH" - ], - [ - "B", - 2025, - "batt" - ] - ], - "MaxCapacityConstraint_rpt": [ - [ - "A", - 2025, - "EH" - ], - [ - "B", - 2025, - "EH" - ] - ], - "MinNewCapacityConstraint_rpt": [], - "MaxNewCapacityConstraint_rpt": [], - "MaxResourceConstraint_rt": [ - [ - "B", - "EF" - ] - ], - "MaxActivityConstraint_rpt": [ - [ - "B", - 2025, - "EH" - ], - [ - "A", - 2025, - "EF" - ] - ], - "MinActivityConstraint_rpt": [ - [ - "A", - 2025, - "EF" - ] - ], - "MinAnnualCapacityFactorConstraint_rpto": [], - "MaxAnnualCapacityFactorConstraint_rpto": [], - "EmissionLimitConstraint_rpe": [ - [ - "A", - 2025, - "co2" - ] - ], - "EmissionActivity_reitvo": [ - [ - "B", - "FusionGas", - "earth", - "GeoThermal", - 2025, - "GeoHyd" - ], - [ - "A", - "co2", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "B", - "co2", - "earth", - "well", - 2025, - "HYD" - ], - [ - "A", - "co2", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "B", - "co2", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "A", - "co2", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "B", - "FusionGas", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A", - "co2", - "earth", - "GeoThermal", - 2025, - "GeoHyd" - ], - [ - "B", - "FusionGas", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "A", - "FusionGas", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "B", - "FusionGas", - "earth", - "well", - 2025, - "HYD" - ], - [ - "B", - "co2", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "A", - "FusionGas", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "B", - "FusionGas", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "A", - "FusionGas", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "B", - "FusionGas", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "B", - "FusionGas", - "ELC", - "batt", - 2025, - "ELC" - ], - [ - "A", - "co2", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A", - "co2", - "earth", - "EFL", - 2025, - "FusionGasFuel" - ], - [ - "A", - "FusionGas", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "B", - "co2", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "A", - "co2", - "earth", - "well", - 2025, - "HYD" - ], - [ - "B", - "co2", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "A", - "FusionGas", - "earth", - "GeoThermal", - 2025, - "GeoHyd" - ], - [ - "B", - "co2", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "B", - "co2", - "ELC", - "batt", - 2025, - "ELC" - ], - [ - "B", - "co2", - "earth", - "GeoThermal", - 2025, - "GeoHyd" - ], - [ - "A", - "co2", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "A", - "FusionGas", - "earth", - "EFL", - 2025, - "FusionGasFuel" - ], - [ - "A", - "FusionGas", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A", - "FusionGas", - "earth", - "well", - 2025, - "HYD" - ], - [ - "B", - "FusionGas", - "FusionGasFuel", - "heater", - 2025, - "RH" - ] - ], - "MinActivityGroup_rpg": [ - [ - "A", - 2025, - "A_tech_grp_1" - ] - ], - "MaxActivityGroup_rpg": [ - [ - "A", - 2025, - "A_tech_grp_1" - ] - ], - "MinCapacityGroupConstraint_rpg": [ - [ - "A", - 2025, - "A_tech_grp_1" - ] - ], - "MaxCapacityGroupConstraint_rpg": [ - [ - "A", - 2025, - "A_tech_grp_1" - ] - ], - "MinNewCapacityGroupConstraint_rpg": [], - "MaxNewCapacityGroupConstraint_rpg": [], - "GroupShareIndices": [ - [ - "B", - 2025, - "EH", - "A_tech_grp_1" - ], - [ - "B", - 2025, - "EF", - "RPS_common" - ], - [ - "A", - 2025, - "EF", - "A_tech_grp_1" - ], - [ - "B", - 2025, - "EF", - "A_tech_grp_1" - ], - [ - "A", - 2025, - "EH", - "A_tech_grp_1" - ], - [ - "A", - 2025, - "EF", - "RPS_common" - ], - [ - "global", - 2025, - "EH", - "A_tech_grp_1" - ], - [ - "global", - 2025, - "EF", - "A_tech_grp_1" - ], - [ - "global", - 2025, - "EF", - "RPS_common" - ] - ], - "MinCapacityShareConstraint_rptg": [], - "MaxCapacityShareConstraint_rptg": [], - "TwoGroupShareIndices": [ - [ - "B", - 2025, - "RPS_global", - "RPS_common" - ], - [ - "A", - 2025, - "A_tech_grp_1", - "RPS_common" - ], - [ - "B", - 2025, - "A_tech_grp_1", - "A_tech_grp_1" - ], - [ - "A", - 2025, - "A_tech_grp_1", - "A_tech_grp_1" - ], - [ - "A", - 2025, - "RPS_global", - "A_tech_grp_1" - ], - [ - "A", - 2025, - "RPS_common", - "RPS_common" - ], - [ - "B", - 2025, - "RPS_global", - "A_tech_grp_1" - ], - [ - "A", - 2025, - "RPS_common", - "A_tech_grp_1" - ], - [ - "B", - 2025, - "A_tech_grp_1", - "RPS_common" - ], - [ - "B", - 2025, - "RPS_common", - "RPS_common" - ], - [ - "B", - 2025, - "RPS_common", - "A_tech_grp_1" - ], - [ - "A", - 2025, - "RPS_global", - "RPS_common" - ], - [ - "global", - 2025, - "RPS_global", - "A_tech_grp_1" - ], - [ - "global", - 2025, - "A_tech_grp_1", - "A_tech_grp_1" - ], - [ - "global", - 2025, - "RPS_common", - "A_tech_grp_1" - ], - [ - "global", - 2025, - "RPS_global", - "RPS_common" - ], - [ - "global", - 2025, - "A_tech_grp_1", - "RPS_common" - ], - [ - "global", - 2025, - "RPS_common", - "RPS_common" - ] - ], - "MaxNewCapacityGroupShareConstraint_rpgg": [ - [ - "global", - 2025, - "RPS_common", - "A_tech_grp_1" - ] - ], - "MinNewCapacityGroupShareConstraint_rpgg": [ - [ - "A", - 2025, - "RPS_common", - "A_tech_grp_1" - ] - ], - "MinActivityShareConstraint_rptg": [], - "MaxActivityShareConstraint_rptg": [], - "MinNewCapacityShareConstraint_rptg": [], - "MaxNewCapacityShareConstraint_rptg": [], - "FlowVar_rpsditvo": [ - [ - "A-B", - 2025, - "s1", - "d2", - "FusionGasFuel", - "FGF_pipe", - 2025, - "FusionGasFuel" - ], - [ - "B", - 2025, - "s2", - "d2", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s1", - "d1", - "earth", - "well", - 2025, - "HYD" - ], - [ - "B", - 2025, - "s2", - "d2", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "B", - 2025, - "s2", - "d2", - "ELC", - "batt", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s2", - "d1", - "earth", - "well", - 2025, - "HYD" - ], - [ - "A", - 2025, - "s2", - "d2", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s2", - "d1", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "B-A", - 2025, - "s2", - "d1", - "FusionGasFuel", - "FGF_pipe", - 2025, - "FusionGasFuel" - ], - [ - "A-B", - 2025, - "s2", - "d1", - "FusionGasFuel", - "FGF_pipe", - 2025, - "FusionGasFuel" - ], - [ - "A", - 2025, - "s2", - "d1", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s1", - "d1", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "A", - 2025, - "s1", - "d1", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "A", - 2025, - "s2", - "d2", - "earth", - "well", - 2025, - "HYD" - ], - [ - "B", - 2025, - "s2", - "d1", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "B", - 2025, - "s2", - "d1", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s1", - "d1", - "earth", - "well", - 2025, - "HYD" - ], - [ - "A", - 2025, - "s2", - "d2", - "earth", - "EFL", - 2025, - "FusionGasFuel" - ], - [ - "A", - 2025, - "s2", - "d2", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s1", - "d1", - "ELC", - "batt", - 2025, - "ELC" - ], - [ - "A-B", - 2025, - "s1", - "d1", - "FusionGasFuel", - "FGF_pipe", - 2025, - "FusionGasFuel" - ], - [ - "A", - 2025, - "s1", - "d2", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "A", - 2025, - "s1", - "d2", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "A", - 2025, - "s1", - "d2", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s1", - "d2", - "earth", - "EFL", - 2025, - "FusionGasFuel" - ], - [ - "B", - 2025, - "s2", - "d1", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "B-A", - 2025, - "s1", - "d1", - "FusionGasFuel", - "FGF_pipe", - 2025, - "FusionGasFuel" - ], - [ - "B", - 2025, - "s1", - "d2", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "A-B", - 2025, - "s2", - "d2", - "FusionGasFuel", - "FGF_pipe", - 2025, - "FusionGasFuel" - ], - [ - "B", - 2025, - "s2", - "d1", - "ELC", - "batt", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s1", - "d2", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "A", - 2025, - "s1", - "d2", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s1", - "d2", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s2", - "d2", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "A", - 2025, - "s2", - "d1", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "B", - 2025, - "s1", - "d2", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s1", - "d2", - "ELC", - "batt", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s2", - "d2", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s1", - "d1", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s1", - "d1", - "earth", - "EFL", - 2025, - "FusionGasFuel" - ], - [ - "A", - 2025, - "s2", - "d1", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "A", - 2025, - "s2", - "d1", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s1", - "d1", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s1", - "d1", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s1", - "d1", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s2", - "d1", - "earth", - "EFL", - 2025, - "FusionGasFuel" - ], - [ - "A", - 2025, - "s2", - "d2", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "B", - 2025, - "s2", - "d1", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s2", - "d2", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s2", - "d2", - "earth", - "well", - 2025, - "HYD" - ], - [ - "A", - 2025, - "s1", - "d1", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "A", - 2025, - "s2", - "d2", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s2", - "d2", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s2", - "d1", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s1", - "d1", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s2", - "d1", - "earth", - "well", - 2025, - "HYD" - ], - [ - "B", - 2025, - "s1", - "d2", - "earth", - "well", - 2025, - "HYD" - ], - [ - "B-A", - 2025, - "s2", - "d2", - "FusionGasFuel", - "FGF_pipe", - 2025, - "FusionGasFuel" - ], - [ - "B-A", - 2025, - "s1", - "d2", - "FusionGasFuel", - "FGF_pipe", - 2025, - "FusionGasFuel" - ], - [ - "A", - 2025, - "s1", - "d2", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s1", - "d1", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s1", - "d1", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s1", - "d2", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "A", - 2025, - "s1", - "d2", - "earth", - "well", - 2025, - "HYD" - ] - ], - "FlowVarAnnual_rpitvo": [ - [ - "A", - 2025, - "earth", - "GeoThermal", - 2025, - "GeoHyd" - ], - [ - "B", - 2025, - "earth", - "GeoThermal", - 2025, - "GeoHyd" - ] - ], - "FlexVar_rpsditvo": [ - [ - "A", - 2025, - "s2", - "d2", - "earth", - "EFL", - 2025, - "FusionGasFuel" - ], - [ - "A", - 2025, - "s1", - "d2", - "earth", - "EFL", - 2025, - "FusionGasFuel" - ], - [ - "A", - 2025, - "s1", - "d1", - "earth", - "EFL", - 2025, - "FusionGasFuel" - ], - [ - "A", - 2025, - "s2", - "d1", - "earth", - "EFL", - 2025, - "FusionGasFuel" - ] - ], - "FlexVarAnnual_rpitvo": [], - "CurtailmentVar_rpsditvo": [ - [ - "B", - 2025, - "s2", - "d1", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s1", - "d2", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s2", - "d2", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s1", - "d1", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s1", - "d2", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s2", - "d2", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s2", - "d1", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s1", - "d1", - "HYD", - "EH", - 2025, - "ELC" - ] - ], - "FlowInStorage_rpsditvo": [ - [ - "B", - 2025, - "s2", - "d2", - "ELC", - "batt", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s1", - "d1", - "ELC", - "batt", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s1", - "d2", - "ELC", - "batt", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s2", - "d1", - "ELC", - "batt", - 2025, - "ELC" - ] - ], - "StorageLevel_rpsdtv": [ - [ - "B", - 2025, - "s2", - "d2", - "batt", - 2025 - ], - [ - "B", - 2025, - "s1", - "d2", - "batt", - 2025 - ], - [ - "B", - 2025, - "s2", - "d1", - "batt", - 2025 - ], - [ - "B", - 2025, - "s1", - "d1", - "batt", - 2025 - ] - ], - "CapacityVar_rptv": [ - [ - "B", - 2025, - "EH", - 2025 - ], - [ - "B", - 2025, - "bulbs", - 2025 - ], - [ - "A", - 2025, - "EF", - 2025 - ], - [ - "A", - 2025, - "well", - 2025 - ], - [ - "A-B", - 2025, - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "EF", - 2025 - ], - [ - "A", - 2025, - "bulbs", - 2025 - ], - [ - "A", - 2025, - "EH", - 2025 - ], - [ - "B", - 2025, - "GeoHeater", - 2025 - ], - [ - "B", - 2025, - "heater", - 2025 - ], - [ - "B", - 2025, - "batt", - 2025 - ], - [ - "A", - 2025, - "GeoHeater", - 2025 - ], - [ - "A", - 2025, - "heater", - 2025 - ], - [ - "B-A", - 2025, - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "GeoThermal", - 2025 - ], - [ - "B", - 2025, - "well", - 2025 - ], - [ - "A", - 2025, - "GeoThermal", - 2025 - ], - [ - "A", - 2025, - "EFL", - 2025 - ] - ], - "NewCapacityVar_rtv": [ - [ - "A", - "EH", - 2025 - ], - [ - "A", - "GeoThermal", - 2025 - ], - [ - "A", - "EF", - 2025 - ], - [ - "B", - "heater", - 2025 - ], - [ - "B", - "EF", - 2025 - ], - [ - "A", - "bulbs", - 2025 - ], - [ - "A-B", - "FGF_pipe", - 2025 - ], - [ - "B", - "GeoHeater", - 2025 - ], - [ - "B", - "batt", - 2025 - ], - [ - "A", - "heater", - 2025 - ], - [ - "B-A", - "FGF_pipe", - 2025 - ], - [ - "B", - "GeoThermal", - 2025 - ], - [ - "A", - "GeoHeater", - 2025 - ], - [ - "B", - "well", - 2025 - ], - [ - "B", - "EH", - 2025 - ], - [ - "A", - "EFL", - 2025 - ], - [ - "A", - "well", - 2025 - ], - [ - "B", - "bulbs", - 2025 - ] - ], - "RetiredCapacityVar_rptv": [], - "AnnualRetirementVar_rptv": [], - "CapacityAvailableVar_rpt": [ - [ - "B", - 2025, - "heater" - ], - [ - "A", - 2025, - "EF" - ], - [ - "A", - 2025, - "GeoThermal" - ], - [ - "A", - 2025, - "bulbs" - ], - [ - "A", - 2025, - "EFL" - ], - [ - "A", - 2025, - "heater" - ], - [ - "B-A", - 2025, - "FGF_pipe" - ], - [ - "A", - 2025, - "GeoHeater" - ], - [ - "B", - 2025, - "EH" - ], - [ - "B", - 2025, - "GeoHeater" - ], - [ - "B", - 2025, - "batt" - ], - [ - "B", - 2025, - "well" - ], - [ - "B", - 2025, - "GeoThermal" - ], - [ - "B", - 2025, - "bulbs" - ], - [ - "A", - 2025, - "EH" - ], - [ - "A-B", - 2025, - "FGF_pipe" - ], - [ - "B", - 2025, - "EF" - ], - [ - "A", - 2025, - "well" - ] - ], - "CapacityConstraint_rpsdtv": [ - [ - "A", - 2025, - "s2", - "d2", - "heater", - 2025 - ], - [ - "A", - 2025, - "s2", - "d1", - "heater", - 2025 - ], - [ - "B-A", - 2025, - "s2", - "d2", - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "s1", - "d2", - "well", - 2025 - ], - [ - "B", - 2025, - "s1", - "d2", - "EH", - 2025 - ], - [ - "A", - 2025, - "s1", - "d2", - "bulbs", - 2025 - ], - [ - "B", - 2025, - "s1", - "d1", - "well", - 2025 - ], - [ - "B-A", - 2025, - "s2", - "d1", - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "s1", - "d1", - "EH", - 2025 - ], - [ - "A", - 2025, - "s1", - "d2", - "GeoHeater", - 2025 - ], - [ - "B", - 2025, - "s1", - "d2", - "heater", - 2025 - ], - [ - "A", - 2025, - "s1", - "d1", - "bulbs", - 2025 - ], - [ - "A", - 2025, - "s1", - "d1", - "GeoHeater", - 2025 - ], - [ - "B", - 2025, - "s1", - "d1", - "heater", - 2025 - ], - [ - "B", - 2025, - "s2", - "d1", - "GeoHeater", - 2025 - ], - [ - "B", - 2025, - "s2", - "d2", - "bulbs", - 2025 - ], - [ - "A", - 2025, - "s1", - "d2", - "EF", - 2025 - ], - [ - "B", - 2025, - "s2", - "d2", - "EF", - 2025 - ], - [ - "B", - 2025, - "s2", - "d1", - "bulbs", - 2025 - ], - [ - "A", - 2025, - "s2", - "d1", - "bulbs", - 2025 - ], - [ - "B", - 2025, - "s2", - "d1", - "EF", - 2025 - ], - [ - "A", - 2025, - "s1", - "d1", - "EF", - 2025 - ], - [ - "A", - 2025, - "s1", - "d1", - "well", - 2025 - ], - [ - "A", - 2025, - "s2", - "d2", - "bulbs", - 2025 - ], - [ - "A", - 2025, - "s1", - "d2", - "EFL", - 2025 - ], - [ - "A-B", - 2025, - "s1", - "d1", - "FGF_pipe", - 2025 - ], - [ - "A", - 2025, - "s1", - "d2", - "well", - 2025 - ], - [ - "A", - 2025, - "s2", - "d2", - "GeoHeater", - 2025 - ], - [ - "B", - 2025, - "s2", - "d2", - "GeoHeater", - 2025 - ], - [ - "A", - 2025, - "s1", - "d1", - "EFL", - 2025 - ], - [ - "A", - 2025, - "s1", - "d2", - "EH", - 2025 - ], - [ - "A", - 2025, - "s1", - "d1", - "EH", - 2025 - ], - [ - "A", - 2025, - "s2", - "d1", - "EF", - 2025 - ], - [ - "B", - 2025, - "s2", - "d1", - "well", - 2025 - ], - [ - "A-B", - 2025, - "s1", - "d2", - "FGF_pipe", - 2025 - ], - [ - "A", - 2025, - "s2", - "d1", - "GeoHeater", - 2025 - ], - [ - "B", - 2025, - "s2", - "d1", - "EH", - 2025 - ], - [ - "B", - 2025, - "s1", - "d2", - "bulbs", - 2025 - ], - [ - "A", - 2025, - "s2", - "d2", - "EF", - 2025 - ], - [ - "A", - 2025, - "s1", - "d2", - "heater", - 2025 - ], - [ - "B", - 2025, - "s1", - "d1", - "EF", - 2025 - ], - [ - "B", - 2025, - "s1", - "d2", - "GeoHeater", - 2025 - ], - [ - "B", - 2025, - "s1", - "d1", - "bulbs", - 2025 - ], - [ - "A", - 2025, - "s2", - "d2", - "well", - 2025 - ], - [ - "B", - 2025, - "s2", - "d2", - "well", - 2025 - ], - [ - "A", - 2025, - "s1", - "d1", - "heater", - 2025 - ], - [ - "B", - 2025, - "s2", - "d2", - "EH", - 2025 - ], - [ - "A", - 2025, - "s2", - "d2", - "EH", - 2025 - ], - [ - "B", - 2025, - "s1", - "d1", - "GeoHeater", - 2025 - ], - [ - "B", - 2025, - "s2", - "d1", - "heater", - 2025 - ], - [ - "A", - 2025, - "s2", - "d1", - "well", - 2025 - ], - [ - "A", - 2025, - "s2", - "d1", - "EH", - 2025 - ], - [ - "A", - 2025, - "s2", - "d2", - "EFL", - 2025 - ], - [ - "B", - 2025, - "s1", - "d2", - "EF", - 2025 - ], - [ - "B", - 2025, - "s2", - "d2", - "heater", - 2025 - ], - [ - "A-B", - 2025, - "s2", - "d1", - "FGF_pipe", - 2025 - ], - [ - "B-A", - 2025, - "s1", - "d2", - "FGF_pipe", - 2025 - ], - [ - "A", - 2025, - "s2", - "d1", - "EFL", - 2025 - ], - [ - "A-B", - 2025, - "s2", - "d2", - "FGF_pipe", - 2025 - ], - [ - "B-A", - 2025, - "s1", - "d1", - "FGF_pipe", - 2025 - ] - ], - "CapacityAnnualConstraint_rptv": [ - [ - "B", - 2025, - "GeoThermal", - 2025 - ], - [ - "A", - 2025, - "GeoThermal", - 2025 - ] - ], - "commodity_waste": [], - "tech_exist": [ - "EH" - ], - "operator": [], - "DegrowthCapacityConstraint_rtpop": [], - "DegrowthNewCapacityConstraint_rtpop": [], - "DegrowthNewCapacityDeltaConstraint_rtpop": [], - "GrowthCapacityConstraint_rtpop": [], - "GrowthNewCapacityConstraint_rtpop": [], - "GrowthNewCapacityDeltaConstraint_rtpop": [], - "DemandConstraint_rpsdc": [ - [ - "B", - 2025, - "s2", - "d2", - "RH" - ], - [ - "B", - 2025, - "s1", - "d1", - "RL" - ], - [ - "A", - 2025, - "s1", - "d1", - "RH" - ], - [ - "A", - 2025, - "s2", - "d2", - "RH" - ], - [ - "B", - 2025, - "s1", - "d2", - "RH" - ], - [ - "B", - 2025, - "s2", - "d1", - "RL" - ], - [ - "A", - 2025, - "s2", - "d1", - "RL" - ], - [ - "A", - 2025, - "s1", - "d2", - "RH" - ], - [ - "A", - 2025, - "s1", - "d2", - "RL" - ], - [ - "B", - 2025, - "s1", - "d1", - "RH" - ], - [ - "B", - 2025, - "s2", - "d1", - "RH" - ], - [ - "A", - 2025, - "s2", - "d1", - "RH" - ], - [ - "A", - 2025, - "s1", - "d1", - "RL" - ], - [ - "B", - 2025, - "s1", - "d2", - "RL" - ], - [ - "B", - 2025, - "s2", - "d2", - "RL" - ], - [ - "A", - 2025, - "s2", - "d2", - "RL" - ] - ], - "DemandActivityConstraint_rpsdtv_dem_s0d0": [ - [ - "B", - 2025, - "s1", - "d2", - "heater", - 2025, - "RH", - "s1", - "d1" - ], - [ - "B", - 2025, - "s2", - "d1", - "heater", - 2025, - "RH", - "s1", - "d1" - ], - [ - "B", - 2025, - "s2", - "d2", - "heater", - 2025, - "RH", - "s1", - "d1" - ], - [ - "B", - 2025, - "s1", - "d2", - "GeoHeater", - 2025, - "RH", - "s1", - "d1" - ], - [ - "B", - 2025, - "s2", - "d1", - "GeoHeater", - 2025, - "RH", - "s1", - "d1" - ], - [ - "B", - 2025, - "s2", - "d2", - "GeoHeater", - 2025, - "RH", - "s1", - "d1" - ], - [ - "A", - 2025, - "s1", - "d2", - "heater", - 2025, - "RH", - "s1", - "d1" - ], - [ - "A", - 2025, - "s2", - "d1", - "heater", - 2025, - "RH", - "s1", - "d1" - ], - [ - "A", - 2025, - "s2", - "d2", - "heater", - 2025, - "RH", - "s1", - "d1" - ], - [ - "A", - 2025, - "s1", - "d2", - "GeoHeater", - 2025, - "RH", - "s1", - "d1" - ], - [ - "A", - 2025, - "s2", - "d1", - "GeoHeater", - 2025, - "RH", - "s1", - "d1" - ], - [ - "A", - 2025, - "s2", - "d2", - "GeoHeater", - 2025, - "RH", - "s1", - "d1" - ] - ], - "CommodityBalanceConstraint_rpsdc": [ - [ - "B", - 2025, - "s1", - "d2", - "FusionGasFuel" - ], - [ - "B", - 2025, - "s1", - "d1", - "FusionGasFuel" - ], - [ - "B", - 2025, - "s2", - "d2", - "FusionGasFuel" - ], - [ - "B", - 2025, - "s2", - "d1", - "FusionGasFuel" - ], - [ - "A", - 2025, - "s1", - "d1", - "FusionGasFuel" - ], - [ - "A", - 2025, - "s2", - "d1", - "HYD" - ], - [ - "A", - 2025, - "s1", - "d2", - "HYD" - ], - [ - "A", - 2025, - "s2", - "d2", - "ELC" - ], - [ - "B", - 2025, - "s1", - "d2", - "HYD" - ], - [ - "A", - 2025, - "s2", - "d2", - "FusionGasFuel" - ], - [ - "B", - 2025, - "s2", - "d1", - "HYD" - ], - [ - "B", - 2025, - "s2", - "d2", - "ELC" - ], - [ - "A", - 2025, - "s1", - "d1", - "HYD" - ], - [ - "A", - 2025, - "s2", - "d1", - "ELC" - ], - [ - "B", - 2025, - "s1", - "d1", - "HYD" - ], - [ - "A", - 2025, - "s1", - "d2", - "ELC" - ], - [ - "A", - 2025, - "s2", - "d1", - "FusionGasFuel" - ], - [ - "B", - 2025, - "s1", - "d2", - "ELC" - ], - [ - "A", - 2025, - "s1", - "d2", - "FusionGasFuel" - ], - [ - "A", - 2025, - "s2", - "d2", - "HYD" - ], - [ - "B", - 2025, - "s2", - "d1", - "ELC" - ], - [ - "A", - 2025, - "s1", - "d1", - "ELC" - ], - [ - "B", - 2025, - "s2", - "d2", - "HYD" - ], - [ - "B", - 2025, - "s1", - "d1", - "ELC" - ], - [ - "A", - 2025, - "s1", - "d1", - "GeoHyd" - ], - [ - "A", - 2025, - "s1", - "d2", - "GeoHyd" - ], - [ - "A", - 2025, - "s2", - "d1", - "GeoHyd" - ], - [ - "A", - 2025, - "s2", - "d2", - "GeoHyd" - ], - [ - "B", - 2025, - "s1", - "d1", - "GeoHyd" - ], - [ - "B", - 2025, - "s1", - "d2", - "GeoHyd" - ], - [ - "B", - 2025, - "s2", - "d1", - "GeoHyd" - ], - [ - "B", - 2025, - "s2", - "d2", - "GeoHyd" - ] - ], - "AnnualCommodityBalanceConstraint_rpc": [], - "BaseloadDiurnalConstraint_rpsdtv": [ - [ - "A", - 2025, - "s2", - "d2", - "EH", - 2025 - ], - [ - "B", - 2025, - "s2", - "d2", - "EH", - 2025 - ], - [ - "A", - 2025, - "s1", - "d2", - "EH", - 2025 - ], - [ - "A", - 2025, - "s2", - "d1", - "EH", - 2025 - ], - [ - "A", - 2025, - "s1", - "d1", - "EH", - 2025 - ], - [ - "B", - 2025, - "s1", - "d2", - "EH", - 2025 - ], - [ - "B", - 2025, - "s2", - "d1", - "EH", - 2025 - ], - [ - "B", - 2025, - "s1", - "d1", - "EH", - 2025 - ] - ], - "RegionalExchangeCapacityConstraint_rrptv": [ - [ - "B", - "A", - 2025, - "FGF_pipe", - 2025 - ], - [ - "A", - "B", - 2025, - "FGF_pipe", - 2025 - ] - ], - "StorageConstraints_rpsdtv": [ - [ - "B", - 2025, - "s2", - "d2", - "batt", - 2025 - ], - [ - "B", - 2025, - "s2", - "d1", - "batt", - 2025 - ], - [ - "B", - 2025, - "s1", - "d1", - "batt", - 2025 - ], - [ - "B", - 2025, - "s1", - "d2", - "batt", - 2025 - ] - ], - "StorageFractionConstraint_rpsdtv": [], - "RampUpConstraint_rpsdtv": [ - [ - "B", - 2025, - "s2", - "d1", - "EH", - 2025 - ], - [ - "B", - 2025, - "s1", - "d1", - "EH", - 2025 - ], - [ - "A", - 2025, - "s1", - "d2", - "EH", - 2025 - ], - [ - "B", - 2025, - "s2", - "d2", - "EH", - 2025 - ], - [ - "A", - 2025, - "s2", - "d2", - "EH", - 2025 - ], - [ - "A", - 2025, - "s1", - "d1", - "EH", - 2025 - ], - [ - "B", - 2025, - "s1", - "d2", - "EH", - 2025 - ], - [ - "A", - 2025, - "s2", - "d1", - "EH", - 2025 - ] - ], - "RampDownConstraint_rpsdtv": [ - [ - "B", - 2025, - "s2", - "d1", - "EH", - 2025 - ], - [ - "B", - 2025, - "s1", - "d1", - "EH", - 2025 - ], - [ - "A", - 2025, - "s1", - "d2", - "EH", - 2025 - ], - [ - "B", - 2025, - "s2", - "d2", - "EH", - 2025 - ], - [ - "A", - 2025, - "s2", - "d2", - "EH", - 2025 - ], - [ - "A", - 2025, - "s1", - "d1", - "EH", - 2025 - ], - [ - "B", - 2025, - "s1", - "d2", - "EH", - 2025 - ], - [ - "A", - 2025, - "s2", - "d1", - "EH", - 2025 - ] - ], - "ReserveMargin_rpsd": [ - [ - "A", - 2025, - "s2", - "d2" - ], - [ - "A", - 2025, - "s2", - "d1" - ], - [ - "B", - 2025, - "s1", - "d2" - ], - [ - "A", - 2025, - "s1", - "d2" - ], - [ - "B", - 2025, - "s1", - "d1" - ], - [ - "A", - 2025, - "s1", - "d1" - ], - [ - "B", - 2025, - "s2", - "d2" - ], - [ - "B", - 2025, - "s2", - "d1" - ] - ], - "MinTechInputSplitConstraint_rpsditv": [ - [ - "A", - 2025, - "s1", - "d2", - "HYD", - "EH", - 2025 - ], - [ - "A", - 2025, - "s1", - "d1", - "HYD", - "EH", - 2025 - ], - [ - "A", - 2025, - "s2", - "d2", - "HYD", - "EH", - 2025 - ], - [ - "A", - 2025, - "s2", - "d1", - "HYD", - "EH", - 2025 - ] - ], - "MinTechInputSplitAnnualConstraint_rpitv": [], - "MinTechInputSplitAverageConstraint_rpitv": [ - [ - "A", - 2025, - "GeoHyd", - "GeoHeater", - 2025 - ] - ], - "MinTechOutputSplitConstraint_rpsdtvo": [ - [ - "B", - 2025, - "s2", - "d1", - "EH", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s1", - "d2", - "EH", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s2", - "d2", - "EH", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s1", - "d1", - "EH", - 2025, - "ELC" - ] - ], - "MinTechOutputSplitAnnualConstraint_rptvo": [], - "MinTechOutputSplitAverageConstraint_rptvo": [], - "MaxTechInputSplitConstraint_rpsditv": [], - "MaxTechInputSplitAnnualConstraint_rpitv": [], - "MaxTechInputSplitAverageConstraint_rpitv": [], - "MaxTechOutputSplitConstraint_rpsdtvo": [], - "MaxTechOutputSplitAnnualConstraint_rptvo": [], - "MaxTechOutputSplitAverageConstraint_rptvo": [], - "MaxSeasonalActivityConstraint_rpst": [], - "MinSeasonalActivityConstraint_rpst": [], - "LinkedEmissionsTechConstraint_rpsdtve": [ - [ - "A", - 2025, - "s1", - "d2", - "EF", - 2025, - "FusionGas" - ], - [ - "A", - 2025, - "s1", - "d1", - "EF", - 2025, - "FusionGas" - ], - [ - "A", - 2025, - "s2", - "d2", - "EF", - 2025, - "FusionGas" - ], - [ - "A", - 2025, - "s2", - "d1", - "EF", - 2025, - "FusionGas" + "vintage_optimize": [ + 2025 ] - ] } \ No newline at end of file diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index c40ce6ee9..ca1aae5e1 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -118,6 +118,9 @@ CREATE TABLE CommodityType PRIMARY KEY, description TEXT ); +INSERT INTO CommodityType VALUES('w','waste commodity'); +INSERT INTO CommodityType VALUES('wa','waste annual commodity'); +INSERT INTO CommodityType VALUES('wp','waste physical commodity'); INSERT INTO CommodityType VALUES('a','annual commodity'); INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); @@ -137,24 +140,9 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -CREATE TABLE EndOfLifeOutput -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); CREATE TABLE CostEmission ( - region TEXT - REFERENCES Region (region), + region TEXT, period INTEGER REFERENCES TimePeriod (period), emis_comm TEXT NOT NULL @@ -242,16 +230,19 @@ CREATE TABLE DemandSpecificDistribution ); INSERT INTO DemandSpecificDistribution VALUES('linkville',2000,'summer','day','ELC',0.5,''); INSERT INTO DemandSpecificDistribution VALUES('linkville',2000,'winter','day','ELC',0.5,''); -CREATE TABLE LoanRate +CREATE TABLE EndOfLifeOutput ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES TimePeriod (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); CREATE TABLE Efficiency ( @@ -328,6 +319,20 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); +CREATE TABLE EmissionEndOfLife +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); CREATE TABLE ExistingCapacity ( region TEXT, @@ -346,25 +351,6 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE GrowthRateMax -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE GrowthRateSeed -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - seed REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) -); CREATE TABLE LoanLifetimeTech ( region TEXT, @@ -374,6 +360,17 @@ CREATE TABLE LoanLifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); +CREATE TABLE LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); CREATE TABLE LifetimeProcess ( region TEXT, @@ -396,167 +393,454 @@ CREATE TABLE LifetimeTech ); INSERT INTO LifetimeTech VALUES('linkville','CCS',100.0,''); INSERT INTO LifetimeTech VALUES('linkville','PLANT',100.0,''); -CREATE TABLE LinkedTech +CREATE TABLE Operator ( - primary_region TEXT, - primary_tech TEXT + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO Operator VALUES('e','equal to'); +INSERT INTO Operator VALUES('le','less than or equal to'); +INSERT INTO Operator VALUES('ge','greater than or equal to'); +CREATE TABLE LimitGrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - emis_comm TEXT - REFERENCES Commodity (name), - driven_tech TEXT + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -INSERT INTO LinkedTech VALUES('linkville','PLANT','CO2','CCS',NULL); -CREATE TABLE MaxActivity +CREATE TABLE LimitGrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxCapacity +CREATE TABLE LimitDegrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxResource +CREATE TABLE LimitGrowthNewCapacityDelta ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_res REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthNewCapacityDelta +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitStorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE MinActivity +CREATE TABLE LimitActivity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_act REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech, operator) ); -CREATE TABLE MaxCapacityGroup +CREATE TABLE LimitActivityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - max_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) +); +CREATE TABLE LimitActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) +); +CREATE TABLE LimitAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + source TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator), + CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE MinCapacity +CREATE TABLE LimitCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech, operator) ); -CREATE TABLE MinCapacityGroup +CREATE TABLE LimitCapacityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) ); -CREATE TABLE OutputCurtailment +CREATE TABLE LimitCapacityShare ( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) ); -CREATE TABLE OutputNetCapacity +CREATE TABLE LimitNewCapacity ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator) +); +CREATE TABLE LimitNewCapacityGroup +( + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name, operator) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE LimitNewCapacityGroupShare ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE LimitNewCapacityShare ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) +); +CREATE TABLE LimitResource +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitSeasonalActivity +( + region TEXT + REFERENCES Region (region), + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + season TEXT + REFERENCES TimeSeason (season), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY(region,period,season,tech, operator) ); -CREATE TABLE OutputFlowIn +CREATE TABLE LimitTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +INSERT INTO LinkedTech VALUES('linkville','PLANT','CO2','CCS',NULL); +CREATE TABLE OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputFlowIn ( scenario TEXT, region TEXT, @@ -611,7 +895,7 @@ CREATE TABLE OutputStorageLevel period INTEGER REFERENCES TimePeriod (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -674,23 +958,6 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE StorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage) -); CREATE TABLE TechnologyType ( label TEXT @@ -701,110 +968,6 @@ INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE MinTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MinTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MinTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MinTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -831,14 +994,14 @@ CREATE TABLE TimeSeason INSERT INTO TimeSeason VALUES('summer'); INSERT INTO TimeSeason VALUES('winter'); CREATE TABLE PeriodSeasons -( +( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, season TEXT REFERENCES TimeSeason (season), notes TEXT, - PRIMARY KEY (period, sequence) + PRIMARY KEY (period, sequence, season) ); INSERT INTO PeriodSeasons VALUES(2000,1,'summer',NULL); INSERT INTO PeriodSeasons VALUES(2000,2,'winter',NULL); @@ -850,188 +1013,6 @@ CREATE TABLE TimePeriodType ); INSERT INTO TimePeriodType VALUES('e','existing vintages'); INSERT INTO TimePeriodType VALUES('f','future'); -CREATE TABLE MaxActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE MaxNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MaxNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MaxNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE MinCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MinNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MinNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); -CREATE TABLE MaxNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1049,72 +1030,6 @@ CREATE TABLE OutputEmission emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE MinActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE EmissionLimit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE MaxActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "min_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); -CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "max_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); CREATE TABLE RPSRequirement ( region TEXT NOT NULL @@ -1158,7 +1073,7 @@ INSERT INTO Technology VALUES('FAKE_SOURCE','r','supply',NULL,NULL,1,0,0,0,0,0,0 CREATE TABLE OutputCost ( scenario TEXT, - region TEXT REFERENCES Region (region), + region TEXT, sector TEXT REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index 2a9bbd3e1..a85c79b36 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -119,6 +119,9 @@ CREATE TABLE CommodityType PRIMARY KEY, description TEXT ); +INSERT INTO CommodityType VALUES('w','waste commodity'); +INSERT INTO CommodityType VALUES('wa','waste annual commodity'); +INSERT INTO CommodityType VALUES('wp','waste physical commodity'); INSERT INTO CommodityType VALUES('a','annual commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); @@ -138,24 +141,9 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -CREATE TABLE EndOfLifeOutput -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); CREATE TABLE CostEmission ( - region TEXT - REFERENCES Region (region), + region TEXT, period INTEGER REFERENCES TimePeriod (period), emis_comm TEXT NOT NULL @@ -240,26 +228,29 @@ CREATE TABLE DemandSpecificDistribution PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s1','d1','RL',0.075,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s1','d2','RL',0.075,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s1','d3','RL',0.075,NULL); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s2','d1','RL',0.075,NULL); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s2','d2','RL',0.075,NULL); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s2','d3','RL',0.075,NULL); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s1','d4','RL',0.075,NULL); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s1','d5','RL',0.2,NULL); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s2','d4','RL',0.2,NULL); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s2','d5','RL',0.075,NULL); -CREATE TABLE LoanRate +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s1','d1','RL',0.07499999999999999723,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s1','d2','RL',0.07499999999999999723,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s1','d3','RL',0.07499999999999999723,NULL); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s2','d1','RL',0.07499999999999999723,NULL); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s2','d2','RL',0.07499999999999999723,NULL); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s2','d3','RL',0.07499999999999999723,NULL); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s1','d4','RL',0.07499999999999999723,NULL); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s1','d5','RL',0.2000000000000000111,NULL); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s2','d4','RL',0.2000000000000000111,NULL); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s2','d5','RL',0.07499999999999999723,NULL); +CREATE TABLE EndOfLifeOutput ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES TimePeriod (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); CREATE TABLE Efficiency ( @@ -321,7 +312,7 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('electricville','co2','HYD','EH',2025,'ELC',0.02,NULL,NULL); +INSERT INTO EmissionActivity VALUES('electricville','co2','HYD','EH',2025,'ELC',0.02000000000000000041,NULL,NULL); CREATE TABLE EmissionEmbodied ( region TEXT, @@ -336,6 +327,20 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); +CREATE TABLE EmissionEndOfLife +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); CREATE TABLE ExistingCapacity ( region TEXT, @@ -354,25 +359,6 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE GrowthRateMax -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE GrowthRateSeed -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - seed REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) -); CREATE TABLE LoanLifetimeTech ( region TEXT, @@ -382,6 +368,17 @@ CREATE TABLE LoanLifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); +CREATE TABLE LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); CREATE TABLE LifetimeProcess ( region TEXT, @@ -404,172 +401,460 @@ CREATE TABLE LifetimeTech ); INSERT INTO LifetimeTech VALUES('electricville','EH',60.0,''); INSERT INTO LifetimeTech VALUES('electricville','bulbs',100.0,'super LED!'); -CREATE TABLE LinkedTech +CREATE TABLE Operator ( - primary_region TEXT, - primary_tech TEXT + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO Operator VALUES('e','equal to'); +INSERT INTO Operator VALUES('le','less than or equal to'); +INSERT INTO Operator VALUES('ge','greater than or equal to'); +CREATE TABLE LimitGrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - emis_comm TEXT - REFERENCES Commodity (name), - driven_tech TEXT + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxActivity +CREATE TABLE LimitGrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxCapacity +CREATE TABLE LimitDegrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -INSERT INTO MaxCapacity VALUES('electricville',2025,'EH',200.0,'',''); -INSERT INTO MaxCapacity VALUES('electricville',2025,'batt',100.0,'',''); -CREATE TABLE MaxResource +CREATE TABLE LimitGrowthNewCapacityDelta ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_res REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthNewCapacityDelta +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitStorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE MinActivity +INSERT INTO LimitStorageLevelFraction VALUES('electricville',2025,'s1','d1','batt',2025,'e',0.5,NULL); +CREATE TABLE LimitActivity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_act REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech, operator) ); -CREATE TABLE MaxCapacityGroup +CREATE TABLE LimitActivityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - max_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) +); +CREATE TABLE LimitActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) +); +CREATE TABLE LimitAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + source TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator), + CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE MinCapacity +CREATE TABLE LimitCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech, operator) ); -INSERT INTO MinCapacity VALUES('electricville',2025,'EH',0.1,'',''); -INSERT INTO MinCapacity VALUES('electricville',2025,'batt',0.1,'',''); -CREATE TABLE MinCapacityGroup +INSERT INTO LimitCapacity VALUES('electricville',2025,'EH','ge',0.1000000000000000055,'',''); +INSERT INTO LimitCapacity VALUES('electricville',2025,'batt','ge',0.1000000000000000055,'',''); +INSERT INTO LimitCapacity VALUES('electricville',2025,'EH','le',200.0,'',''); +INSERT INTO LimitCapacity VALUES('electricville',2025,'batt','le',100.0,'',''); +CREATE TABLE LimitCapacityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) ); -CREATE TABLE OutputCurtailment +CREATE TABLE LimitCapacityShare ( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) ); -CREATE TABLE OutputNetCapacity +CREATE TABLE LimitNewCapacity ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator) +); +CREATE TABLE LimitNewCapacityGroup +( + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name, operator) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE LimitNewCapacityGroupShare ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE LimitNewCapacityShare ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) +); +CREATE TABLE LimitResource +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitSeasonalActivity +( + region TEXT + REFERENCES Region (region), + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + season TEXT + REFERENCES TimeSeason (season), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY(region,period,season,tech, operator) ); -CREATE TABLE OutputFlowIn +CREATE TABLE LimitTechInputSplit ( - scenario TEXT, + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputFlowIn +( + scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), @@ -622,7 +907,7 @@ CREATE TABLE OutputStorageLevel period INTEGER REFERENCES TimePeriod (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -675,16 +960,16 @@ CREATE TABLE TimeSegmentFraction PRIMARY KEY (period, season, tod), CHECK (segfrac >= 0 AND segfrac <= 1) ); -INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d3',0.1,NULL); -INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d1',0.1,NULL); -INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d2',0.1,NULL); -INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d3',0.1,NULL); -INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d1',0.1,NULL); -INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d2',0.1,NULL); -INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d4',0.1,NULL); -INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d5',0.1,NULL); -INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d4',0.1,NULL); -INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d5',0.1,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d3',0.1000000000000000055,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d1',0.1000000000000000055,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d2',0.1000000000000000055,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d3',0.1000000000000000055,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d1',0.1000000000000000055,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d2',0.1000000000000000055,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d4',0.1000000000000000055,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d5',0.1000000000000000055,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d4',0.1000000000000000055,NULL); +INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d5',0.1000000000000000055,NULL); CREATE TABLE StorageDuration ( region TEXT, @@ -694,24 +979,6 @@ CREATE TABLE StorageDuration PRIMARY KEY (region, tech) ); INSERT INTO StorageDuration VALUES('electricville','batt',10.0,NULL); -CREATE TABLE StorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage) -); -INSERT INTO StorageLevelFraction VALUES('electricville',2025,'s1','d1','batt',2025,0.5,NULL); CREATE TABLE TechnologyType ( label TEXT @@ -722,110 +989,6 @@ INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE MinTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MinTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MinTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MinTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -856,14 +1019,14 @@ CREATE TABLE TimeSeason INSERT INTO TimeSeason VALUES('s1'); INSERT INTO TimeSeason VALUES('s2'); CREATE TABLE PeriodSeasons -( +( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, season TEXT REFERENCES TimeSeason (season), notes TEXT, - PRIMARY KEY (period, sequence) + PRIMARY KEY (period, sequence, season) ); INSERT INTO PeriodSeasons VALUES(2025,1,'s1',NULL); INSERT INTO PeriodSeasons VALUES(2025,2,'s2',NULL); @@ -875,188 +1038,6 @@ CREATE TABLE TimePeriodType ); INSERT INTO TimePeriodType VALUES('e','existing vintages'); INSERT INTO TimePeriodType VALUES('f','future'); -CREATE TABLE MaxActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE MaxNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MaxNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MaxNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE MinCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MinNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MinNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); -CREATE TABLE MaxNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1074,72 +1055,6 @@ CREATE TABLE OutputEmission emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE MinActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE EmissionLimit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE MaxActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "min_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); -CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "max_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); CREATE TABLE RPSRequirement ( region TEXT NOT NULL @@ -1183,7 +1098,7 @@ INSERT INTO Technology VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0 CREATE TABLE OutputCost ( scenario TEXT, - region TEXT REFERENCES Region (region), + region TEXT, sector TEXT REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 6ba6abc41..5ed006207 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -90,53 +90,53 @@ CREATE TABLE CapacityFactorTech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'spring','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'spring','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2020,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'summer','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'summer','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2020,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'fall','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'fall','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2020,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'winter','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'winter','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2020,'winter','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'spring','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'spring','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2020,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'summer','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'summer','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2020,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'fall','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'fall','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2020,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'winter','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'winter','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2020,'winter','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'spring','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'spring','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2025,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'summer','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'summer','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2025,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'fall','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'fall','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2025,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'winter','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'winter','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2025,'winter','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'spring','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'spring','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2025,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'summer','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'summer','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2025,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'fall','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'fall','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2025,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'winter','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'winter','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2025,'winter','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'spring','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'spring','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2030,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'summer','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'summer','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2030,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'fall','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'fall','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2030,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'winter','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'winter','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2030,'winter','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'spring','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'spring','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2030,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'summer','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'summer','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2030,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'fall','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'fall','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2030,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'winter','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'winter','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2030,'winter','night','E_SOLPV',0.0,''); CREATE TABLE CapacityToActivity ( @@ -152,10 +152,10 @@ INSERT INTO CapacityToActivity VALUES('R1','S_IMPOIL',1.0,''); INSERT INTO CapacityToActivity VALUES('R1','S_IMPNG',1.0,''); INSERT INTO CapacityToActivity VALUES('R1','S_IMPURN',1.0,''); INSERT INTO CapacityToActivity VALUES('R1','S_OILREF',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1','E_NGCC',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('R1','E_SOLPV',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('R1','E_BATT',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('R1','E_NUCLEAR',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('R1','E_NGCC',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('R1','E_SOLPV',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('R1','E_BATT',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('R1','E_NUCLEAR',31.53999999999999915,''); INSERT INTO CapacityToActivity VALUES('R1','T_BLND',1.0,''); INSERT INTO CapacityToActivity VALUES('R1','T_DSL',1.0,''); INSERT INTO CapacityToActivity VALUES('R1','T_GSL',1.0,''); @@ -167,18 +167,18 @@ INSERT INTO CapacityToActivity VALUES('R2','S_IMPOIL',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','S_IMPNG',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','S_IMPURN',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','S_OILREF',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','E_NGCC',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('R2','E_SOLPV',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('R2','E_BATT',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('R2','E_NUCLEAR',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('R2','E_NGCC',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('R2','E_SOLPV',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('R2','E_BATT',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('R2','E_NUCLEAR',31.53999999999999915,''); INSERT INTO CapacityToActivity VALUES('R2','T_BLND',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','T_DSL',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','T_GSL',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','T_EV',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','R_EH',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','R_NGH',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1-R2','E_TRANS',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('R2-R1','E_TRANS',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('R1-R2','E_TRANS',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('R2-R1','E_TRANS',31.53999999999999915,''); CREATE TABLE Commodity ( name TEXT @@ -192,7 +192,7 @@ INSERT INTO Commodity VALUES('OIL','p','crude oil'); INSERT INTO Commodity VALUES('NG','p','natural gas'); INSERT INTO Commodity VALUES('URN','p','uranium'); INSERT INTO Commodity VALUES('ETH','p','ethanol'); -INSERT INTO Commodity VALUES('SOL','s','solar insolation'); +INSERT INTO Commodity VALUES('SOL','p','solar insolation'); INSERT INTO Commodity VALUES('GSL','p','gasoline'); INSERT INTO Commodity VALUES('DSL','p','diesel'); INSERT INTO Commodity VALUES('ELC','p','electricity'); @@ -206,6 +206,9 @@ CREATE TABLE CommodityType PRIMARY KEY, description TEXT ); +INSERT INTO CommodityType VALUES('w','waste commodity'); +INSERT INTO CommodityType VALUES('wa','waste annual commodity'); +INSERT INTO CommodityType VALUES('wp','waste physical commodity'); INSERT INTO CommodityType VALUES('a','annual commodity'); INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); @@ -225,24 +228,9 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -CREATE TABLE EndOfLifeOutput -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); CREATE TABLE CostEmission ( - region TEXT - REFERENCES Region (region), + region TEXT, period INTEGER REFERENCES TimePeriod (period), emis_comm TEXT NOT NULL @@ -266,54 +254,54 @@ CREATE TABLE CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostFixed VALUES('R1',2020,'E_NGCC',2020,30.600000000000000532,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_NGCC',2020,9.7799999999999993605,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_NGCC',2025,9.7799999999999993605,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2020,9.7799999999999993605,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2025,9.7799999999999993605,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2030,9.7799999999999993605,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2020,'E_SOLPV',2020,10.400000000000000355,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_SOLPV',2020,10.400000000000000355,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_SOLPV',2025,9.0999999999999996447,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2020,10.400000000000000355,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2025,9.0999999999999996447,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2030,9.0999999999999996447,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2020,'E_NUCLEAR',2020,98.09999999999998721,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_NUCLEAR',2020,98.09999999999998721,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_NUCLEAR',2025,98.09999999999998721,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2020,98.09999999999998721,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2025,98.09999999999998721,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2030,98.09999999999998721,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2020,'E_BATT',2020,7.0499999999999998223,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_BATT',2020,7.0499999999999998223,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_BATT',2025,7.0499999999999998223,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2020,7.0499999999999998223,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2025,7.0499999999999998223,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2030,7.0499999999999998223,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2020,'E_NGCC',2020,24.479999999999999538,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_NGCC',2020,7.8239999999999998436,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_NGCC',2025,7.8239999999999998436,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2020,7.8239999999999998436,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2025,7.8239999999999998436,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2030,7.8239999999999998436,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2020,'E_SOLPV',2020,8.3200000000000002842,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_SOLPV',2020,8.3200000000000002842,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_SOLPV',2025,7.2800000000000002486,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2020,8.3200000000000002842,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2025,7.2800000000000002486,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2030,7.2800000000000002486,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2020,'E_NUCLEAR',2020,78.480000000000007531,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_NUCLEAR',2020,78.480000000000007531,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_NUCLEAR',2025,78.480000000000007531,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2020,78.480000000000007531,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2025,78.480000000000007531,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2030,78.480000000000007531,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2020,'E_BATT',2020,5.6399999999999996802,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_BATT',2020,5.6399999999999996802,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_BATT',2025,5.6399999999999996802,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2020,5.6399999999999996802,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2025,5.6399999999999996802,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2030,5.6399999999999996802,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2020,'E_NGCC',2020,30.60000000000000142,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_NGCC',2020,9.77999999999999937,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_NGCC',2025,9.77999999999999937,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2020,9.77999999999999937,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2025,9.77999999999999937,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2030,9.77999999999999937,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2020,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_SOLPV',2025,9.099999999999999645,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2025,9.099999999999999645,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2030,9.099999999999999645,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2020,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_NUCLEAR',2025,98.0999999999999801,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2025,98.0999999999999801,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2030,98.0999999999999801,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2020,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_BATT',2025,7.049999999999999823,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2025,7.049999999999999823,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2030,7.049999999999999823,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2020,'E_NGCC',2020,24.48000000000000042,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_NGCC',2020,7.823999999999999844,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_NGCC',2025,7.823999999999999844,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2020,7.823999999999999844,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2025,7.823999999999999844,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2030,7.823999999999999844,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2020,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_SOLPV',2025,7.280000000000000248,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2025,7.280000000000000248,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2030,7.280000000000000248,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2020,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_NUCLEAR',2025,78.48000000000000397,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2025,78.48000000000000397,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2030,78.48000000000000397,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2020,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_BATT',2025,5.639999999999999681,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2025,5.639999999999999681,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2030,5.639999999999999681,'$M/GWyr',''); CREATE TABLE CostInvest ( region TEXT, @@ -347,12 +335,12 @@ INSERT INTO CostInvest VALUES('R1','T_DSL',2030,2810.0,'$/bvmt/yr',''); INSERT INTO CostInvest VALUES('R1','T_EV',2020,3100.0,'$/bvmt/yr',''); INSERT INTO CostInvest VALUES('R1','T_EV',2025,3030.0,'$/bvmt/yr',''); INSERT INTO CostInvest VALUES('R1','T_EV',2030,2925.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R1','R_EH',2020,4.0999999999999996447,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_EH',2025,4.0999999999999996447,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_EH',2030,4.0999999999999996447,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_NGH',2020,7.5999999999999996447,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_NGH',2025,7.5999999999999996447,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_NGH',2030,7.5999999999999996447,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R1','R_EH',2020,4.099999999999999644,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R1','R_EH',2025,4.099999999999999644,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R1','R_EH',2030,4.099999999999999644,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R1','R_NGH',2020,7.599999999999999645,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R1','R_NGH',2025,7.599999999999999645,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R1','R_NGH',2030,7.599999999999999645,'$/PJ/yr',''); INSERT INTO CostInvest VALUES('R2','E_NGCC',2020,840.0,'$M/GW',''); INSERT INTO CostInvest VALUES('R2','E_NGCC',2025,820.0,'$M/GW',''); INSERT INTO CostInvest VALUES('R2','E_NGCC',2030,800.0,'$M/GW',''); @@ -374,9 +362,9 @@ INSERT INTO CostInvest VALUES('R2','T_DSL',2030,2248.0,'$/bvmt/yr',''); INSERT INTO CostInvest VALUES('R2','T_EV',2020,2480.0,'$/bvmt/yr',''); INSERT INTO CostInvest VALUES('R2','T_EV',2025,2424.0,'$/bvmt/yr',''); INSERT INTO CostInvest VALUES('R2','T_EV',2030,2340.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R2','R_EH',2020,3.2799999999999998046,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R2','R_EH',2025,3.2799999999999998046,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R2','R_EH',2030,3.2799999999999998046,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R2','R_EH',2020,3.279999999999999805,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R2','R_EH',2025,3.279999999999999805,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R2','R_EH',2030,3.279999999999999805,'$/PJ/yr',''); INSERT INTO CostInvest VALUES('R2','R_NGH',2020,6.080000000000000071,'$/PJ/yr',''); INSERT INTO CostInvest VALUES('R2','R_NGH',2025,6.080000000000000071,'$/PJ/yr',''); INSERT INTO CostInvest VALUES('R2','R_NGH',2030,6.080000000000000071,'$/PJ/yr',''); @@ -406,48 +394,48 @@ INSERT INTO CostVariable VALUES('R1',2030,'S_IMPNG',2020,4.0,'$M/PJ',''); INSERT INTO CostVariable VALUES('R1',2020,'S_OILREF',2020,1.0,'$M/PJ',''); INSERT INTO CostVariable VALUES('R1',2025,'S_OILREF',2020,1.0,'$M/PJ',''); INSERT INTO CostVariable VALUES('R1',2030,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2020,'E_NGCC',2020,1.6000000000000000888,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'E_NGCC',2020,1.6000000000000000888,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'E_NGCC',2025,1.7,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2020,1.6000000000000000888,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2025,1.7,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2030,1.8,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2020,'E_NUCLEAR',2020,0.23999999999999999111,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'E_NUCLEAR',2020,0.23999999999999999111,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2020,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2025,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2025,'E_NGCC',2025,1.699999999999999956,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2025,1.699999999999999956,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2030,1.800000000000000044,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2020,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2025,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); INSERT INTO CostVariable VALUES('R1',2025,'E_NUCLEAR',2025,0.25,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2020,0.23999999999999999111,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2025,0.25,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2030,0.26000000000000000888,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'S_IMPETH',2020,25.600000000000000532,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'S_IMPETH',2020,25.600000000000000532,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'S_IMPETH',2020,25.600000000000000532,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2030,0.2600000000000000088,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2020,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); INSERT INTO CostVariable VALUES('R2',2020,'S_IMPOIL',2020,16.0,'$M/PJ',''); INSERT INTO CostVariable VALUES('R2',2025,'S_IMPOIL',2020,16.0,'$M/PJ',''); INSERT INTO CostVariable VALUES('R2',2030,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'S_IMPNG',2020,3.2000000000000001776,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'S_IMPNG',2020,3.2000000000000001776,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'S_IMPNG',2020,3.2000000000000001776,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'S_OILREF',2020,0.8,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'S_OILREF',2020,0.8,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'S_OILREF',2020,0.8,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'E_NGCC',2020,1.2800000000000000355,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'E_NGCC',2020,1.2800000000000000355,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'E_NGCC',2025,1.3600000000000000976,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2020,1.2800000000000000355,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2025,1.3600000000000000976,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2030,1.4399999999999999467,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'E_NUCLEAR',2020,0.19199999999999999289,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'E_NUCLEAR',2020,0.19199999999999999289,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'E_NUCLEAR',2025,0.2,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2020,0.19199999999999999289,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2025,0.2,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2030,0.2080000000000000071,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1-R2',2020,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1-R2',2025,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1-R2',2030,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2-R1',2020,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2-R1',2025,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2-R1',2030,'E_TRANS',2015,0.1,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2020,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2020,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2020,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'E_NGCC',2025,1.360000000000000097,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2025,1.360000000000000097,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2030,1.439999999999999947,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2020,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'E_NUCLEAR',2025,0.2000000000000000111,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2025,0.2000000000000000111,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2030,0.2080000000000000183,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1-R2',2020,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1-R2',2025,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1-R2',2030,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2-R1',2020,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2-R1',2025,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2-R1',2030,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); CREATE TABLE Demand ( region TEXT, @@ -488,64 +476,67 @@ CREATE TABLE DemandSpecificDistribution PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'spring','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'spring','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'spring','night','RH',0.1000000000000000055,''); INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'summer','day','RH',0.0,''); INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'fall','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'fall','night','RH',0.1,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'winter','day','RH',0.3,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'winter','night','RH',0.4,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'spring','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'fall','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'fall','night','RH',0.1000000000000000055,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'winter','day','RH',0.2999999999999999889,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'winter','night','RH',0.4000000000000000222,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'spring','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'spring','night','RH',0.1000000000000000055,''); INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'summer','day','RH',0.0,''); INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'fall','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'fall','night','RH',0.1,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'winter','day','RH',0.3,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'winter','night','RH',0.4,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'spring','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'fall','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'fall','night','RH',0.1000000000000000055,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'winter','day','RH',0.2999999999999999889,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'winter','night','RH',0.4000000000000000222,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'spring','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'spring','night','RH',0.1000000000000000055,''); INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'summer','day','RH',0.0,''); INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'fall','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'fall','night','RH',0.1,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'winter','day','RH',0.3,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'winter','night','RH',0.4,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'spring','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'fall','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'fall','night','RH',0.1000000000000000055,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'winter','day','RH',0.2999999999999999889,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'winter','night','RH',0.4000000000000000222,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'spring','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'spring','night','RH',0.1000000000000000055,''); INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'summer','day','RH',0.0,''); INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'fall','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'fall','night','RH',0.1,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'winter','day','RH',0.3,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'winter','night','RH',0.4,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'spring','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'fall','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'fall','night','RH',0.1000000000000000055,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'winter','day','RH',0.2999999999999999889,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'winter','night','RH',0.4000000000000000222,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'spring','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'spring','night','RH',0.1000000000000000055,''); INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'summer','day','RH',0.0,''); INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'fall','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'fall','night','RH',0.1,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'winter','day','RH',0.3,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'winter','night','RH',0.4,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'spring','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'fall','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'fall','night','RH',0.1000000000000000055,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'winter','day','RH',0.2999999999999999889,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'winter','night','RH',0.4000000000000000222,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'spring','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'spring','night','RH',0.1000000000000000055,''); INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'summer','day','RH',0.0,''); INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'fall','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'fall','night','RH',0.1,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'winter','day','RH',0.3,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'winter','night','RH',0.4,''); -CREATE TABLE LoanRate +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'fall','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'fall','night','RH',0.1000000000000000055,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'winter','day','RH',0.2999999999999999889,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'winter','night','RH',0.4000000000000000222,''); +CREATE TABLE EndOfLifeOutput ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES TimePeriod (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); CREATE TABLE Efficiency ( @@ -571,34 +562,34 @@ INSERT INTO Efficiency VALUES('R1','OIL','S_OILREF',2020,'GSL',1.0,''); INSERT INTO Efficiency VALUES('R1','OIL','S_OILREF',2020,'DSL',1.0,''); INSERT INTO Efficiency VALUES('R1','ETH','T_BLND',2020,'E10',1.0,''); INSERT INTO Efficiency VALUES('R1','GSL','T_BLND',2020,'E10',1.0,''); -INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2020,'ELC',0.55,''); -INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2025,'ELC',0.55,''); -INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2030,'ELC',0.55,''); +INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2020,'ELC',0.5500000000000000444,''); +INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2025,'ELC',0.5500000000000000444,''); +INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2030,'ELC',0.5500000000000000444,''); INSERT INTO Efficiency VALUES('R1','SOL','E_SOLPV',2020,'ELC',1.0,''); INSERT INTO Efficiency VALUES('R1','SOL','E_SOLPV',2025,'ELC',1.0,''); INSERT INTO Efficiency VALUES('R1','SOL','E_SOLPV',2030,'ELC',1.0,''); -INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2015,'ELC',0.4,''); -INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2020,'ELC',0.4,''); -INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2025,'ELC',0.4,''); -INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2030,'ELC',0.4,''); -INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2020,'ELC',0.85,''); -INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2025,'ELC',0.85,''); -INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2030,'ELC',0.85,''); +INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2015,'ELC',0.4000000000000000222,''); +INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2020,'ELC',0.4000000000000000222,''); +INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2025,'ELC',0.4000000000000000222,''); +INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2030,'ELC',0.4000000000000000222,''); +INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2020,'ELC',0.8499999999999999778,''); +INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2025,'ELC',0.8499999999999999778,''); +INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2030,'ELC',0.8499999999999999778,''); INSERT INTO Efficiency VALUES('R1','E10','T_GSL',2020,'VMT',0.25,''); INSERT INTO Efficiency VALUES('R1','E10','T_GSL',2025,'VMT',0.25,''); INSERT INTO Efficiency VALUES('R1','E10','T_GSL',2030,'VMT',0.25,''); -INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2020,'VMT',0.3,''); -INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2025,'VMT',0.3,''); -INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2030,'VMT',0.3,''); -INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2020,'VMT',0.89000000000000003552,''); -INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2025,'VMT',0.89000000000000003552,''); -INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2030,'VMT',0.89000000000000003552,''); +INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2020,'VMT',0.2999999999999999889,''); +INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2025,'VMT',0.2999999999999999889,''); +INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2030,'VMT',0.2999999999999999889,''); +INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2020,'VMT',0.8900000000000000133,''); +INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2025,'VMT',0.8900000000000000133,''); +INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2030,'VMT',0.8900000000000000133,''); INSERT INTO Efficiency VALUES('R1','ELC','R_EH',2020,'RH',1.0,''); INSERT INTO Efficiency VALUES('R1','ELC','R_EH',2025,'RH',1.0,''); INSERT INTO Efficiency VALUES('R1','ELC','R_EH',2030,'RH',1.0,''); -INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2020,'RH',0.85,''); -INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2025,'RH',0.85,''); -INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2030,'RH',0.85,''); +INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2020,'RH',0.8499999999999999778,''); +INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2025,'RH',0.8499999999999999778,''); +INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2030,'RH',0.8499999999999999778,''); INSERT INTO Efficiency VALUES('R2','ethos','S_IMPETH',2020,'ETH',1.0,''); INSERT INTO Efficiency VALUES('R2','ethos','S_IMPOIL',2020,'OIL',1.0,''); INSERT INTO Efficiency VALUES('R2','ethos','S_IMPNG',2020,'NG',1.0,''); @@ -607,36 +598,36 @@ INSERT INTO Efficiency VALUES('R2','OIL','S_OILREF',2020,'GSL',1.0,''); INSERT INTO Efficiency VALUES('R2','OIL','S_OILREF',2020,'DSL',1.0,''); INSERT INTO Efficiency VALUES('R2','ETH','T_BLND',2020,'E10',1.0,''); INSERT INTO Efficiency VALUES('R2','GSL','T_BLND',2020,'E10',1.0,''); -INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2020,'ELC',0.55,''); -INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2025,'ELC',0.55,''); -INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2030,'ELC',0.55,''); +INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2020,'ELC',0.5500000000000000444,''); +INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2025,'ELC',0.5500000000000000444,''); +INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2030,'ELC',0.5500000000000000444,''); INSERT INTO Efficiency VALUES('R2','SOL','E_SOLPV',2020,'ELC',1.0,''); INSERT INTO Efficiency VALUES('R2','SOL','E_SOLPV',2025,'ELC',1.0,''); INSERT INTO Efficiency VALUES('R2','SOL','E_SOLPV',2030,'ELC',1.0,''); -INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2015,'ELC',0.4,''); -INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2020,'ELC',0.4,''); -INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2025,'ELC',0.4,''); -INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2030,'ELC',0.4,''); -INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2020,'ELC',0.85,''); -INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2025,'ELC',0.85,''); -INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2030,'ELC',0.85,''); +INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2015,'ELC',0.4000000000000000222,''); +INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2020,'ELC',0.4000000000000000222,''); +INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2025,'ELC',0.4000000000000000222,''); +INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2030,'ELC',0.4000000000000000222,''); +INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2020,'ELC',0.8499999999999999778,''); +INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2025,'ELC',0.8499999999999999778,''); +INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2030,'ELC',0.8499999999999999778,''); INSERT INTO Efficiency VALUES('R2','E10','T_GSL',2020,'VMT',0.25,''); INSERT INTO Efficiency VALUES('R2','E10','T_GSL',2025,'VMT',0.25,''); INSERT INTO Efficiency VALUES('R2','E10','T_GSL',2030,'VMT',0.25,''); -INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2020,'VMT',0.3,''); -INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2025,'VMT',0.3,''); -INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2030,'VMT',0.3,''); -INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2020,'VMT',0.89000000000000003552,''); -INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2025,'VMT',0.89000000000000003552,''); -INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2030,'VMT',0.89000000000000003552,''); +INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2020,'VMT',0.2999999999999999889,''); +INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2025,'VMT',0.2999999999999999889,''); +INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2030,'VMT',0.2999999999999999889,''); +INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2020,'VMT',0.8900000000000000133,''); +INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2025,'VMT',0.8900000000000000133,''); +INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2030,'VMT',0.8900000000000000133,''); INSERT INTO Efficiency VALUES('R2','ELC','R_EH',2020,'RH',1.0,''); INSERT INTO Efficiency VALUES('R2','ELC','R_EH',2025,'RH',1.0,''); INSERT INTO Efficiency VALUES('R2','ELC','R_EH',2030,'RH',1.0,''); -INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2020,'RH',0.85,''); -INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2025,'RH',0.85,''); -INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2030,'RH',0.85,''); -INSERT INTO Efficiency VALUES('R1-R2','ELC','E_TRANS',2015,'ELC',0.9,''); -INSERT INTO Efficiency VALUES('R2-R1','ELC','E_TRANS',2015,'ELC',0.9,''); +INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2020,'RH',0.8499999999999999778,''); +INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2025,'RH',0.8499999999999999778,''); +INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2030,'RH',0.8499999999999999778,''); +INSERT INTO Efficiency VALUES('R1-R2','ELC','E_TRANS',2015,'ELC',0.9000000000000000222,''); +INSERT INTO Efficiency VALUES('R2-R1','ELC','E_TRANS',2015,'ELC',0.9000000000000000222,''); CREATE TABLE EfficiencyVariable ( region TEXT, @@ -677,12 +668,12 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('R1','CO2','ethos','S_IMPNG',2020,'NG',50.299999999999993605,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R1','CO2','OIL','S_OILREF',2020,'GSL',67.200000000000006394,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R1','CO2','OIL','S_OILREF',2020,'DSL',69.400000000000003907,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R2','CO2','ethos','S_IMPNG',2020,'NG',50.299999999999993605,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R2','CO2','OIL','S_OILREF',2020,'GSL',67.200000000000006394,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R2','CO2','OIL','S_OILREF',2020,'DSL',69.400000000000003907,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO EmissionActivity VALUES('R1','CO2','ethos','S_IMPNG',2020,'NG',50.29999999999999005,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO EmissionActivity VALUES('R1','CO2','OIL','S_OILREF',2020,'GSL',67.20000000000000284,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO EmissionActivity VALUES('R1','CO2','OIL','S_OILREF',2020,'DSL',69.40000000000000569,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO EmissionActivity VALUES('R2','CO2','ethos','S_IMPNG',2020,'NG',50.29999999999999005,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO EmissionActivity VALUES('R2','CO2','OIL','S_OILREF',2020,'GSL',67.20000000000000284,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO EmissionActivity VALUES('R2','CO2','OIL','S_OILREF',2020,'DSL',69.40000000000000569,'kT/PJ','taken from MIT Energy Fact Sheet'); CREATE TABLE EmissionEmbodied ( region TEXT, @@ -697,6 +688,20 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); +CREATE TABLE EmissionEndOfLife +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); CREATE TABLE ExistingCapacity ( region TEXT, @@ -709,8 +714,8 @@ CREATE TABLE ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO ExistingCapacity VALUES('R1','E_NUCLEAR',2015,0.070000000000000008881,'GW',''); -INSERT INTO ExistingCapacity VALUES('R2','E_NUCLEAR',2015,0.03,'GW',''); +INSERT INTO ExistingCapacity VALUES('R1','E_NUCLEAR',2015,0.07000000000000000667,'GW',''); +INSERT INTO ExistingCapacity VALUES('R2','E_NUCLEAR',2015,0.02999999999999999889,'GW',''); INSERT INTO ExistingCapacity VALUES('R1-R2','E_TRANS',2015,10.0,'GW',''); INSERT INTO ExistingCapacity VALUES('R2-R1','E_TRANS',2015,10.0,'GW',''); CREATE TABLE TechGroup @@ -719,25 +724,6 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE GrowthRateMax -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE GrowthRateSeed -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - seed REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) -); CREATE TABLE LoanLifetimeTech ( region TEXT, @@ -777,6 +763,17 @@ INSERT INTO LoanLifetimeTech VALUES('R2','T_GSL',12.0,''); INSERT INTO LoanLifetimeTech VALUES('R2','T_EV',12.0,''); INSERT INTO LoanLifetimeTech VALUES('R2','R_EH',20.0,''); INSERT INTO LoanLifetimeTech VALUES('R2','R_NGH',20.0,''); +CREATE TABLE LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); CREATE TABLE LifetimeProcess ( region TEXT, @@ -829,174 +826,493 @@ INSERT INTO LifetimeTech VALUES('R2','R_EH',20.0,''); INSERT INTO LifetimeTech VALUES('R2','R_NGH',20.0,''); INSERT INTO LifetimeTech VALUES('R1-R2','E_TRANS',30.0,''); INSERT INTO LifetimeTech VALUES('R2-R1','E_TRANS',30.0,''); -CREATE TABLE LinkedTech +CREATE TABLE Operator ( - primary_region TEXT, - primary_tech TEXT + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO Operator VALUES('e','equal to'); +INSERT INTO Operator VALUES('le','less than or equal to'); +INSERT INTO Operator VALUES('ge','greater than or equal to'); +CREATE TABLE LimitGrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - emis_comm TEXT - REFERENCES Commodity (name), - driven_tech TEXT + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxActivity +CREATE TABLE LimitGrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxCapacity +CREATE TABLE LimitDegrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxResource +CREATE TABLE LimitGrowthNewCapacityDelta ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_res REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthNewCapacityDelta +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitStorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE MinActivity +INSERT INTO LimitStorageLevelFraction VALUES('R1',2025,'winter','day','E_BATT',2025,'e',0.5,''); +INSERT INTO LimitStorageLevelFraction VALUES('R2',2020,'summer','day','E_BATT',2020,'e',0.5,''); +CREATE TABLE LimitActivity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_act REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech, operator) ); -INSERT INTO MinActivity VALUES('R1',2020,'T_GSL',35.0,'',''); -INSERT INTO MinActivity VALUES('R1',2025,'T_GSL',35.0,'',''); -INSERT INTO MinActivity VALUES('R1',2030,'T_GSL',35.0,'',''); -INSERT INTO MinActivity VALUES('R2',2020,'T_GSL',15.0,'',''); -INSERT INTO MinActivity VALUES('R2',2025,'T_GSL',15.0,'',''); -INSERT INTO MinActivity VALUES('R2',2030,'T_GSL',15.0,'',''); -CREATE TABLE MaxCapacityGroup +INSERT INTO LimitActivity VALUES('R1',2020,'T_GSL','ge',35.0,'',''); +INSERT INTO LimitActivity VALUES('R1',2025,'T_GSL','ge',35.0,'',''); +INSERT INTO LimitActivity VALUES('R1',2030,'T_GSL','ge',35.0,'',''); +INSERT INTO LimitActivity VALUES('R2',2020,'T_GSL','ge',15.0,'',''); +INSERT INTO LimitActivity VALUES('R2',2025,'T_GSL','ge',15.0,'',''); +INSERT INTO LimitActivity VALUES('R2',2030,'T_GSL','ge',15.0,'',''); +CREATE TABLE LimitActivityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - max_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) +); +CREATE TABLE LimitActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) +); +CREATE TABLE LimitAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + source TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator), + CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE MinCapacity +CREATE TABLE LimitCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech, operator) ); -CREATE TABLE MinCapacityGroup +CREATE TABLE LimitCapacityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) ); -CREATE TABLE OutputCurtailment +CREATE TABLE LimitCapacityShare ( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) ); -CREATE TABLE OutputNetCapacity +CREATE TABLE LimitNewCapacity ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator) +); +CREATE TABLE LimitNewCapacityGroup +( + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name, operator) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE LimitNewCapacityGroupShare ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE LimitNewCapacityShare ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) +); +CREATE TABLE LimitResource +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitSeasonalActivity +( + region TEXT + REFERENCES Region (region), + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + season TEXT + REFERENCES TimeSeason (season), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY(region,period,season,tech, operator) ); -CREATE TABLE OutputFlowIn +CREATE TABLE LimitTechInputSplit ( - scenario TEXT, + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +INSERT INTO LimitTechInputSplit VALUES('R1',2020,'GSL','T_BLND','ge',0.9000000000000000222,''); +INSERT INTO LimitTechInputSplit VALUES('R1',2020,'ETH','T_BLND','ge',0.1000000000000000055,''); +INSERT INTO LimitTechInputSplit VALUES('R1',2025,'GSL','T_BLND','ge',0.9000000000000000222,''); +INSERT INTO LimitTechInputSplit VALUES('R1',2025,'ETH','T_BLND','ge',0.1000000000000000055,''); +INSERT INTO LimitTechInputSplit VALUES('R1',2030,'GSL','T_BLND','ge',0.9000000000000000222,''); +INSERT INTO LimitTechInputSplit VALUES('R1',2030,'ETH','T_BLND','ge',0.1000000000000000055,''); +INSERT INTO LimitTechInputSplit VALUES('R2',2020,'GSL','T_BLND','ge',0.7199999999999999734,''); +INSERT INTO LimitTechInputSplit VALUES('R2',2020,'ETH','T_BLND','ge',0.08000000000000000166,''); +INSERT INTO LimitTechInputSplit VALUES('R2',2025,'GSL','T_BLND','ge',0.7199999999999999734,''); +INSERT INTO LimitTechInputSplit VALUES('R2',2025,'ETH','T_BLND','ge',0.08000000000000000166,''); +INSERT INTO LimitTechInputSplit VALUES('R2',2030,'GSL','T_BLND','ge',0.7199999999999999734,''); +INSERT INTO LimitTechInputSplit VALUES('R2',2030,'ETH','T_BLND','ge',0.08000000000000000166,''); +CREATE TABLE LimitTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +INSERT INTO LimitTechOutputSplit VALUES('R1',2020,'S_OILREF','GSL','ge',0.9000000000000000222,''); +INSERT INTO LimitTechOutputSplit VALUES('R1',2020,'S_OILREF','DSL','ge',0.1000000000000000055,''); +INSERT INTO LimitTechOutputSplit VALUES('R1',2025,'S_OILREF','GSL','ge',0.9000000000000000222,''); +INSERT INTO LimitTechOutputSplit VALUES('R1',2025,'S_OILREF','DSL','ge',0.1000000000000000055,''); +INSERT INTO LimitTechOutputSplit VALUES('R1',2030,'S_OILREF','GSL','ge',0.9000000000000000222,''); +INSERT INTO LimitTechOutputSplit VALUES('R1',2030,'S_OILREF','DSL','ge',0.1000000000000000055,''); +INSERT INTO LimitTechOutputSplit VALUES('R2',2020,'S_OILREF','GSL','ge',0.7199999999999999734,''); +INSERT INTO LimitTechOutputSplit VALUES('R2',2020,'S_OILREF','DSL','ge',0.08000000000000000166,''); +INSERT INTO LimitTechOutputSplit VALUES('R2',2025,'S_OILREF','GSL','ge',0.7199999999999999734,''); +INSERT INTO LimitTechOutputSplit VALUES('R2',2025,'S_OILREF','DSL','ge',0.08000000000000000166,''); +INSERT INTO LimitTechOutputSplit VALUES('R2',2030,'S_OILREF','GSL','ge',0.7199999999999999734,''); +INSERT INTO LimitTechOutputSplit VALUES('R2',2030,'S_OILREF','DSL','ge',0.08000000000000000166,''); +CREATE TABLE LimitTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +INSERT INTO LimitEmission VALUES('R1',2020,'CO2','le',25000.0,'kT CO2',''); +INSERT INTO LimitEmission VALUES('R1',2025,'CO2','le',24000.0,'kT CO2',''); +INSERT INTO LimitEmission VALUES('R1',2030,'CO2','le',23000.0,'kT CO2',''); +INSERT INTO LimitEmission VALUES('global',2020,'CO2','le',37500.0,'kT CO2',''); +INSERT INTO LimitEmission VALUES('global',2025,'CO2','le',36000.0,'kT CO2',''); +INSERT INTO LimitEmission VALUES('global',2030,'CO2','le',34500.0,'kT CO2',''); +CREATE TABLE LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputFlowIn +( + scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), @@ -1049,7 +1365,7 @@ CREATE TABLE OutputStorageLevel period INTEGER REFERENCES TimePeriod (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1137,25 +1453,6 @@ CREATE TABLE StorageDuration ); INSERT INTO StorageDuration VALUES('R1','E_BATT',8.0,'8-hour duration specified as fraction of a day'); INSERT INTO StorageDuration VALUES('R2','E_BATT',8.0,'8-hour duration specified as fraction of a day'); -CREATE TABLE StorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage) -); -INSERT INTO StorageLevelFraction VALUES('R1',2025,'winter','day','E_BATT',2025,0.5,''); -INSERT INTO StorageLevelFraction VALUES('R2',2020,'summer','day','E_BATT',2020,0.5,''); CREATE TABLE TechnologyType ( label TEXT @@ -1166,134 +1463,6 @@ INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE MinTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -INSERT INTO MinTechInputSplit VALUES('R1',2020,'GSL','T_BLND',0.9000000000000000222,''); -INSERT INTO MinTechInputSplit VALUES('R1',2020,'ETH','T_BLND',0.1000000000000000055,''); -INSERT INTO MinTechInputSplit VALUES('R1',2025,'GSL','T_BLND',0.9000000000000000222,''); -INSERT INTO MinTechInputSplit VALUES('R1',2025,'ETH','T_BLND',0.1000000000000000055,''); -INSERT INTO MinTechInputSplit VALUES('R1',2030,'GSL','T_BLND',0.9000000000000000222,''); -INSERT INTO MinTechInputSplit VALUES('R1',2030,'ETH','T_BLND',0.1000000000000000055,''); -INSERT INTO MinTechInputSplit VALUES('R2',2020,'GSL','T_BLND',0.7199999999999999734,''); -INSERT INTO MinTechInputSplit VALUES('R2',2020,'ETH','T_BLND',0.08000000000000000166,''); -INSERT INTO MinTechInputSplit VALUES('R2',2025,'GSL','T_BLND',0.7199999999999999734,''); -INSERT INTO MinTechInputSplit VALUES('R2',2025,'ETH','T_BLND',0.08000000000000000166,''); -INSERT INTO MinTechInputSplit VALUES('R2',2030,'GSL','T_BLND',0.7199999999999999734,''); -INSERT INTO MinTechInputSplit VALUES('R2',2030,'ETH','T_BLND',0.08000000000000000166,''); -CREATE TABLE MinTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MinTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -INSERT INTO MinTechOutputSplit VALUES('R1',2020,'S_OILREF','GSL',0.9000000000000000222,''); -INSERT INTO MinTechOutputSplit VALUES('R1',2020,'S_OILREF','DSL',0.1000000000000000055,''); -INSERT INTO MinTechOutputSplit VALUES('R1',2025,'S_OILREF','GSL',0.9000000000000000222,''); -INSERT INTO MinTechOutputSplit VALUES('R1',2025,'S_OILREF','DSL',0.1000000000000000055,''); -INSERT INTO MinTechOutputSplit VALUES('R1',2030,'S_OILREF','GSL',0.9000000000000000222,''); -INSERT INTO MinTechOutputSplit VALUES('R1',2030,'S_OILREF','DSL',0.1000000000000000055,''); -INSERT INTO MinTechOutputSplit VALUES('R2',2020,'S_OILREF','GSL',0.7199999999999999734,''); -INSERT INTO MinTechOutputSplit VALUES('R2',2020,'S_OILREF','DSL',0.08000000000000000166,''); -INSERT INTO MinTechOutputSplit VALUES('R2',2025,'S_OILREF','GSL',0.7199999999999999734,''); -INSERT INTO MinTechOutputSplit VALUES('R2',2025,'S_OILREF','DSL',0.08000000000000000166,''); -INSERT INTO MinTechOutputSplit VALUES('R2',2030,'S_OILREF','GSL',0.7199999999999999734,''); -INSERT INTO MinTechOutputSplit VALUES('R2',2030,'S_OILREF','DSL',0.08000000000000000166,''); -CREATE TABLE MinTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -1325,14 +1494,14 @@ INSERT INTO TimeSeason VALUES('summer'); INSERT INTO TimeSeason VALUES('fall'); INSERT INTO TimeSeason VALUES('winter'); CREATE TABLE PeriodSeasons -( +( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, season TEXT REFERENCES TimeSeason (season), notes TEXT, - PRIMARY KEY (period, sequence) + PRIMARY KEY (period, sequence, season) ); INSERT INTO PeriodSeasons VALUES(2020,1,'spring',NULL); INSERT INTO PeriodSeasons VALUES(2020,2,'summer',NULL); @@ -1354,188 +1523,6 @@ CREATE TABLE TimePeriodType ); INSERT INTO TimePeriodType VALUES('e','existing vintages'); INSERT INTO TimePeriodType VALUES('f','future'); -CREATE TABLE MaxActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE MaxNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MaxNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MaxNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE MinCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MinNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MinNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); -CREATE TABLE MaxNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1553,78 +1540,6 @@ CREATE TABLE OutputEmission emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE MinActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE EmissionLimit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -INSERT INTO EmissionLimit VALUES('R1',2020,'CO2',25000.0,'kT CO2',''); -INSERT INTO EmissionLimit VALUES('R1',2025,'CO2',24000.0,'kT CO2',''); -INSERT INTO EmissionLimit VALUES('R1',2030,'CO2',23000.0,'kT CO2',''); -INSERT INTO EmissionLimit VALUES('global',2020,'CO2',37500.0,'kT CO2',''); -INSERT INTO EmissionLimit VALUES('global',2025,'CO2',36000.0,'kT CO2',''); -INSERT INTO EmissionLimit VALUES('global',2030,'CO2',34500.0,'kT CO2',''); -CREATE TABLE MaxActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "min_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); -CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "max_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); CREATE TABLE RPSRequirement ( region TEXT NOT NULL @@ -1680,7 +1595,7 @@ INSERT INTO Technology VALUES('E_TRANS','p','electric','','',0,0,0,0,0,0,1,'elec CREATE TABLE OutputCost ( scenario TEXT, - region TEXT REFERENCES Region (region), + region TEXT, sector TEXT REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), @@ -1698,4 +1613,3 @@ CREATE TABLE OutputCost FOREIGN KEY (tech) REFERENCES Technology (tech) ); COMMIT; -PRAGMA FOREIGN_KEYS = 1; \ No newline at end of file diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 0f51eda9e..67a7775bd 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -1,46810 +1,47001 @@ { - "time_exist": [ - 2015 - ], - "time_future": [ - 2020, - 2025, - 2030, - 2035 - ], - "time_optimize": [ - 2020, - 2025, - 2030 - ], - "vintage_exist": [ - 2015 - ], - "vintage_optimize": [ - 2020, - 2025, - 2030 - ], - "vintage_all": [ - 2015, - 2020, - 2025, - 2030 - ], - "time_season_all": [ - "spring", - "summer", - "fall", - "winter" - ], - "time_season": [ - 2020, - 2025, - 2030 - ], - "TimeNext": [], - "time_of_day": [ - "day", - "night" - ], - "regions": [ - "R1", - "R2" - ], - "regionalIndices": [ - "R1", - "R1-R2", - "R2", - "R2-R1" - ], - "regionalGlobalIndices": [ - "R1", - "R2", - "global" - ], - "tech_resource": [ - "S_IMPETH", - "S_IMPOIL", - "S_IMPNG", - "S_IMPURN" - ], - "tech_production": [ - "S_OILREF", - "E_NGCC", - "E_SOLPV", - "E_BATT", - "E_NUCLEAR", - "T_BLND", - "T_DSL", - "T_GSL", - "T_EV", - "R_EH", - "R_NGH", - "E_TRANS" - ], - "tech_all": [ - "S_IMPETH", - "S_IMPOIL", - "S_IMPNG", - "S_IMPURN", - "S_OILREF", - "E_NGCC", - "E_SOLPV", - "E_BATT", - "E_NUCLEAR", - "T_BLND", - "T_DSL", - "T_GSL", - "T_EV", - "R_EH", - "R_NGH", - "E_TRANS" - ], - "tech_baseload": [ - "E_NUCLEAR" - ], - "tech_annual": [], - "tech_storage": [ - "E_BATT" - ], - "tech_reserve": [], - "tech_upramping": [], - "tech_downramping": [], - "tech_curtailment": [ - "S_OILREF" - ], - "tech_flex": [], - "tech_exchange": [ - "E_TRANS" - ], - "tech_group_names": [], - "tech_group_members": [], - "tech_uncap": [ - "S_IMPETH", - "S_IMPOIL", - "S_IMPNG", - "S_IMPURN" - ], - "tech_with_capacity": [ - "S_OILREF", - "E_NGCC", - "E_SOLPV", - "E_BATT", - "E_NUCLEAR", - "T_BLND", - "T_DSL", - "T_GSL", - "T_EV", - "R_EH", - "R_NGH", - "E_TRANS" - ], - "tech_retirement": [], - "commodity_demand": [ - "VMT", - "RH" - ], - "commodity_emissions": [ - "CO2" - ], - "commodity_flex": [], - "commodity_physical": [ - "ethos", - "OIL", - "NG", - "URN", - "ETH", - "SOL", - "GSL", - "DSL", - "ELC", - "E10" - ], - "commodity_source": [ - "ethos", - "SOL" - ], - "commodity_annual": [], - "commodity_carrier": [ - "ethos", - "OIL", - "NG", - "URN", - "ETH", - "SOL", - "GSL", - "DSL", - "ELC", - "E10", - "VMT", - "RH" - ], - "commodity_all": [ - "ethos", - "OIL", - "NG", - "URN", - "ETH", - "SOL", - "GSL", - "DSL", - "ELC", - "E10", - "VMT", - "RH", - "CO2" - ], - "CapacityFactor_rpsdt": [ - [ - "R1", - 2030, - "spring", - "night", - "E_NUCLEAR" - ], - [ - "R1", - 2030, - "spring", - "day", - "E_SOLPV" - ], - [ - "R1", - 2020, - "spring", - "night", - "T_EV" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_DSL" - ], - [ - "R2", - 2020, - "fall", - "night", - "R_NGH" - ], - [ - "R2", - 2020, - "summer", - "night", - "E_BATT" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_DSL" - ], - [ - "R1", - 2025, - "summer", - "night", - "R_NGH" - ], - [ - "R1", - 2020, - "winter", - "night", - "T_DSL" - ], - [ - "R1", - 2020, - "spring", - "day", - "T_GSL" - ], - [ - "R2", - 2020, - "summer", - "day", - "E_NGCC" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_DSL" - ], - [ - "R2", - 2020, - "summer", - "night", - "T_GSL" - ], - [ - "R2", - 2020, - "fall", - "day", - "S_OILREF" - ], - [ - "R1", - 2020, - "summer", - "day", - "S_OILREF" - ], - [ - "R2", - 2020, - "spring", - "night", - "T_BLND" - ], - [ - "R2", - 2020, - "fall", - "night", - "E_NUCLEAR" - ], - [ - "R2", - 2020, - "fall", - "day", - "E_SOLPV" - ], - [ - "R1", - 2020, - "summer", - "day", - "E_SOLPV" - ], - [ - "R1", - 2025, - "summer", - "night", - "R_EH" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_BLND" - ], - [ - "R1", - 2025, - "summer", - "night", - "E_NUCLEAR" - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NGCC" - ], - [ - "R1", - 2025, - "fall", - "night", - "E_NGCC" - ], - [ - "R2", - 2020, - "winter", - "night", - "T_GSL" - ], - [ - "R2-R1", - 2030, - "winter", - "night", - "E_TRANS" - ], - [ - "R2", - 2030, - "summer", - "night", - "E_BATT" - ], - [ - "R2", - 2030, - "spring", - "night", - "E_BATT" - ], - [ - "R1", - 2030, - "winter", - "day", - "E_BATT" - ], - [ - "R2", - 2020, - "winter", - "day", - "T_EV" - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NGCC" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_EV" - ], - [ - "R2", - 2025, - "spring", - "day", - "E_NGCC" - ], - [ - "R1", - 2020, - "summer", - "day", - "R_NGH" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_GSL" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_GSL" - ], - [ - "R1", - 2020, - "winter", - "day", - "E_NGCC" - ], - [ - "R1", - 2025, - "spring", - "day", - "E_NGCC" - ], - [ - "R1-R2", - 2020, - "spring", - "night", - "E_TRANS" - ], - [ - "R1", - 2020, - "summer", - "day", - "R_EH" - ], - [ - "R1", - 2030, - "summer", - "day", - "S_OILREF" - ], - [ - "R1", - 2020, - "fall", - "night", - "E_SOLPV" - ], - [ - "R1", - 2030, - "summer", - "day", - "E_SOLPV" - ], - [ - "R1", - 2020, - "fall", - "day", - "R_NGH" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_DSL" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_DSL" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_EV" - ], - [ - "R1", - 2020, - "winter", - "night", - "T_EV" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_DSL" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_EV" - ], - [ - "R2-R1", - 2020, - "spring", - "night", - "E_TRANS" - ], - [ - "R1", - 2020, - "fall", - "day", - "R_EH" - ], - [ - "R1", - 2020, - "fall", - "day", - "E_NUCLEAR" - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NGCC" - ], - [ - "R2", - 2020, - "summer", - "night", - "T_BLND" - ], - [ - "R1-R2", - 2025, - "fall", - "day", - "E_TRANS" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_DSL" - ], - [ - "R2", - 2020, - "spring", - "night", - "R_NGH" - ], - [ - "R1-R2", - 2030, - "summer", - "day", - "E_TRANS" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_DSL" - ], - [ - "R2", - 2030, - "fall", - "night", - "R_NGH" - ], - [ - "R2", - 2025, - "summer", - "day", - "E_NGCC" - ], - [ - "R2", - 2025, - "winter", - "night", - "E_BATT" - ], - [ - "R2", - 2025, - "fall", - "day", - "S_OILREF" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_BLND" - ], - [ - "R2", - 2020, - "spring", - "night", - "R_EH" - ], - [ - "R2", - 2020, - "spring", - "night", - "E_NUCLEAR" - ], - [ - "R1", - 2025, - "summer", - "day", - "E_NGCC" - ], - [ - "R2", - 2030, - "fall", - "night", - "R_EH" - ], - [ - "R2", - 2025, - "winter", - "day", - "E_NGCC" - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NUCLEAR" - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NUCLEAR" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_BLND" - ], - [ - "R1", - 2025, - "winter", - "night", - "E_BATT" - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NGCC" - ], - [ - "R1", - 2025, - "fall", - "day", - "S_OILREF" - ], - [ - "R1", - 2020, - "winter", - "night", - "T_BLND" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_GSL" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_BLND" - ], - [ - "R1", - 2025, - "fall", - "day", - "E_SOLPV" - ], - [ - "R1", - 2025, - "winter", - "day", - "E_NGCC" - ], - [ - "R1-R2", - 2020, - "winter", - "night", - "E_TRANS" - ], - [ - "R1", - 2030, - "fall", - "day", - "E_BATT" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_DSL" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_EV" - ], - [ - "R2", - 2025, - "fall", - "day", - "R_NGH" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_EV" - ], - [ - "R1", - 2020, - "spring", - "day", - "S_OILREF" - ], - [ - "R1", - 2025, - "fall", - "day", - "R_NGH" - ], - [ - "R2", - 2025, - "fall", - "day", - "R_EH" - ], - [ - "R2", - 2020, - "winter", - "night", - "S_OILREF" - ], - [ - "R2", - 2020, - "winter", - "night", - "E_SOLPV" - ], - [ - "R1", - 2025, - "fall", - "day", - "R_EH" - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NGCC" - ], - [ - "R1", - 2020, - "spring", - "day", - "R_NGH" - ], - [ - "R1", - 2020, - "summer", - "day", - "T_DSL" - ], - [ - "R2", - 2020, - "summer", - "night", - "R_NGH" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_EV" - ], - [ - "R1", - 2030, - "spring", - "day", - "E_BATT" - ], - [ - "R2", - 2020, - "winter", - "day", - "E_NUCLEAR" - ], - [ - "R2", - 2020, - "winter", - "night", - "R_NGH" - ], - [ - "R1", - 2020, - "spring", - "day", - "R_EH" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_BLND" - ], - [ - "R2", - 2020, - "summer", - "night", - "R_EH" - ], - [ - "R2", - 2020, - "summer", - "night", - "E_NUCLEAR" - ], - [ - "R1-R2", - 2025, - "spring", - "day", - "E_TRANS" - ], - [ - "R2", - 2020, - "fall", - "night", - "E_NGCC" - ], - [ - "R1", - 2030, - "spring", - "day", - "T_GSL" - ], - [ - "R1", - 2020, - "summer", - "night", - "E_NGCC" - ], - [ - "R1", - 2030, - "winter", - "night", - "S_OILREF" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_BLND" - ], - [ - "R1", - 2020, - "fall", - "day", - "T_DSL" - ], - [ - "R2", - 2020, - "winter", - "night", - "R_EH" - ], - [ - "R2", - 2030, - "summer", - "night", - "R_NGH" - ], - [ - "R1", - 2020, - "summer", - "day", - "E_BATT" - ], - [ - "R1", - 2030, - "winter", - "night", - "E_SOLPV" - ], - [ - "R2", - 2020, - "fall", - "day", - "E_BATT" - ], - [ - "R2", - 2020, - "fall", - "night", - "T_EV" - ], - [ - "R2", - 2030, - "spring", - "night", - "R_NGH" - ], - [ - "R1", - 2030, - "winter", - "day", - "R_NGH" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_EV" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_BLND" - ], - [ - "R2", - 2025, - "spring", - "day", - "S_OILREF" - ], - [ - "R2", - 2030, - "summer", - "night", - "R_EH" - ], - [ - "R2", - 2020, - "fall", - "day", - "T_GSL" - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NUCLEAR" - ], - [ - "R2-R1", - 2030, - "fall", - "day", - "E_TRANS" - ], - [ - "R2", - 2025, - "spring", - "night", - "E_NUCLEAR" - ], - [ - "R2", - 2025, - "spring", - "day", - "E_SOLPV" - ], - [ - "R2", - 2030, - "spring", - "night", - "R_EH" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_BLND" - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NUCLEAR" - ], - [ - "R1", - 2020, - "winter", - "day", - "S_OILREF" - ], - [ - "R1", - 2025, - "spring", - "day", - "S_OILREF" - ], - [ - "R1", - 2020, - "winter", - "night", - "E_NUCLEAR" - ], - [ - "R1", - 2020, - "winter", - "day", - "E_SOLPV" - ], - [ - "R1", - 2025, - "spring", - "night", - "E_NUCLEAR" - ], - [ - "R1", - 2025, - "spring", - "day", - "E_SOLPV" - ], - [ - "R2", - 2020, - "spring", - "night", - "T_DSL" - ], - [ - "R2-R1", - 2020, - "summer", - "day", - "E_TRANS" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_DSL" - ], - [ - "R1-R2", - 2020, - "summer", - "day", - "E_TRANS" - ], - [ - "R1", - 2020, - "summer", - "day", - "T_EV" - ], - [ - "R2-R1", - 2030, - "spring", - "day", - "E_TRANS" - ], - [ - "R1", - 2020, - "fall", - "night", - "E_BATT" - ], - [ - "R1", - 2030, - "summer", - "day", - "E_BATT" - ], - [ - "R1", - 2020, - "fall", - "night", - "T_GSL" - ], - [ - "R2", - 2030, - "winter", - "night", - "S_OILREF" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_GSL" - ], - [ - "R2-R1", - 2025, - "winter", - "night", - "E_TRANS" - ], - [ - "R2-R1", - 2020, - "fall", - "night", - "E_TRANS" - ], - [ - "R1", - 2030, - "spring", - "day", - "T_BLND" - ], - [ - "R2", - 2030, - "winter", - "night", - "E_SOLPV" - ], - [ - "R1", - 2020, - "fall", - "day", - "T_EV" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_DSL" - ], - [ - "R2", - 2020, - "spring", - "day", - "E_NGCC" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_DSL" - ], - [ - "R2", - 2025, - "winter", - "night", - "R_NGH" - ], - [ - "R2", - 2025, - "summer", - "day", - "S_OILREF" - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NUCLEAR" - ], - [ - "R2", - 2025, - "summer", - "night", - "E_NUCLEAR" - ], - [ - "R1-R2", - 2030, - "spring", - "day", - "E_TRANS" - ], - [ - "R1", - 2020, - "summer", - "day", - "T_BLND" - ], - [ - "R2", - 2025, - "summer", - "day", - "E_SOLPV" - ], - [ - "R2", - 2025, - "fall", - "night", - "E_NGCC" - ], - [ - "R1", - 2025, - "winter", - "night", - "R_NGH" - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NGCC" - ], - [ - "R1", - 2025, - "summer", - "day", - "S_OILREF" - ], - [ - "R2", - 2025, - "winter", - "day", - "S_OILREF" - ], - [ - "R1", - 2030, - "fall", - "night", - "S_OILREF" - ], - [ - "R2", - 2025, - "winter", - "night", - "E_NUCLEAR" - ], - [ - "R1", - 2020, - "spring", - "day", - "T_DSL" - ], - [ - "R1", - 2025, - "summer", - "day", - "E_SOLPV" - ], - [ - "R2", - 2025, - "winter", - "day", - "E_SOLPV" - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NGCC" - ], - [ - "R2", - 2030, - "winter", - "night", - "R_EH" - ], - [ - "R2", - 2025, - "fall", - "day", - "E_BATT" - ], - [ - "R2", - 2020, - "summer", - "night", - "T_DSL" - ], - [ - "R1", - 2030, - "fall", - "night", - "E_SOLPV" - ], - [ - "R2", - 2020, - "spring", - "night", - "T_EV" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_EV" - ], - [ - "R1", - 2025, - "winter", - "night", - "E_NUCLEAR" - ], - [ - "R2-R1", - 2030, - "summer", - "day", - "E_TRANS" - ], - [ - "R1", - 2025, - "winter", - "day", - "E_SOLPV" - ], - [ - "R1", - 2025, - "fall", - "day", - "E_BATT" - ], - [ - "R2", - 2020, - "winter", - "night", - "T_DSL" - ], - [ - "R2", - 2020, - "spring", - "day", - "T_GSL" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_GSL" - ], - [ - "R1", - 2020, - "spring", - "night", - "E_NGCC" - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NUCLEAR" - ], - [ - "R1-R2", - 2020, - "fall", - "day", - "E_TRANS" - ], - [ - "R2", - 2025, - "summer", - "day", - "R_EH" - ], - [ - "R1", - 2020, - "spring", - "day", - "E_BATT" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_DSL" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_BLND" - ], - [ - "R1", - 2025, - "summer", - "day", - "R_EH" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_DSL" - ], - [ - "R1-R2", - 2025, - "summer", - "day", - "E_TRANS" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_EV" - ], - [ - "R2", - 2030, - "spring", - "day", - "T_GSL" - ], - [ - "R2", - 2020, - "winter", - "night", - "E_BATT" - ], - [ - "R1", - 2030, - "spring", - "day", - "R_NGH" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_EV" - ], - [ - "R2", - 2020, - "winter", - "day", - "E_NGCC" - ], - [ - "R1-R2", - 2030, - "winter", - "night", - "E_TRANS" - ], - [ - "R1", - 2030, - "spring", - "day", - "R_EH" - ], - [ - "R1", - 2020, - "summer", - "night", - "S_OILREF" - ], - [ - "R1", - 2020, - "spring", - "day", - "T_EV" - ], - [ - "R1", - 2020, - "summer", - "night", - "E_SOLPV" - ], - [ - "R2", - 2020, - "fall", - "day", - "R_NGH" - ], - [ - "R2", - 2020, - "summer", - "night", - "T_EV" - ], - [ - "R2", - 2020, - "summer", - "day", - "T_GSL" - ], - [ - "R1", - 2030, - "winter", - "night", - "E_BATT" - ], - [ - "R2", - 2020, - "winter", - "night", - "T_EV" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_BLND" - ], - [ - "R2", - 2020, - "fall", - "day", - "R_EH" - ], - [ - "R1", - 2020, - "summer", - "day", - "E_NUCLEAR" - ], - [ - "R2", - 2025, - "spring", - "night", - "E_NGCC" - ], - [ - "R1", - 2020, - "fall", - "night", - "S_OILREF" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_GSL" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_BLND" - ], - [ - "R1", - 2020, - "winter", - "night", - "E_NGCC" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_GSL" - ], - [ - "R1", - 2025, - "spring", - "night", - "E_NGCC" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_EV" - ], - [ - "R2", - 2025, - "spring", - "day", - "E_BATT" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_EV" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_EV" - ], - [ - "R1", - 2020, - "winter", - "day", - "E_BATT" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_GSL" - ], - [ - "R1", - 2025, - "spring", - "day", - "E_BATT" - ], - [ - "R2", - 2025, - "spring", - "day", - "T_GSL" - ], - [ - "R1", - 2020, - "spring", - "day", - "T_BLND" - ], - [ - "R1", - 2020, - "fall", - "night", - "R_NGH" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_DSL" - ], - [ - "R1", - 2030, - "summer", - "day", - "R_NGH" - ], - [ - "R2-R1", - 2025, - "summer", - "day", - "E_TRANS" - ], - [ - "R1", - 2020, - "winter", - "day", - "T_GSL" - ], - [ - "R1-R2", - 2020, - "spring", - "day", - "E_TRANS" - ], - [ - "R1", - 2025, - "spring", - "day", - "T_GSL" - ], - [ - "R2", - 2020, - "winter", - "night", - "T_BLND" - ], - [ - "R1", - 2020, - "fall", - "night", - "R_EH" - ], - [ - "R1", - 2030, - "summer", - "day", - "R_EH" - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NUCLEAR" - ], - [ - "R1-R2", - 2025, - "fall", - "night", - "E_TRANS" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_DSL" - ], - [ - "R2", - 2020, - "spring", - "day", - "S_OILREF" - ], - [ - "R2", - 2030, - "winter", - "night", - "E_BATT" - ], - [ - "R2", - 2030, - "fall", - "day", - "S_OILREF" - ], - [ - "R2-R1", - 2025, - "fall", - "day", - "E_TRANS" - ], - [ - "R2", - 2020, - "spring", - "day", - "E_SOLPV" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_BLND" - ], - [ - "R1-R2", - 2030, - "summer", - "night", - "E_TRANS" - ], - [ - "R2", - 2030, - "fall", - "day", - "E_SOLPV" - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NGCC" - ], - [ - "R2", - 2025, - "summer", - "night", - "E_NGCC" - ], - [ - "R2", - 2025, - "fall", - "night", - "S_OILREF" - ], - [ - "R1", - 2030, - "summer", - "night", - "S_OILREF" - ], - [ - "R2", - 2025, - "fall", - "night", - "E_SOLPV" - ], - [ - "R2", - 2025, - "summer", - "day", - "E_BATT" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_BLND" - ], - [ - "R1", - 2030, - "summer", - "night", - "E_SOLPV" - ], - [ - "R2", - 2030, - "spring", - "day", - "S_OILREF" - ], - [ - "R2", - 2030, - "fall", - "day", - "R_NGH" - ], - [ - "R2-R1", - 2025, - "spring", - "day", - "E_TRANS" - ], - [ - "R1", - 2030, - "spring", - "day", - "T_DSL" - ], - [ - "R2", - 2030, - "spring", - "day", - "E_SOLPV" - ], - [ - "R1", - 2025, - "summer", - "day", - "E_BATT" - ], - [ - "R2", - 2025, - "winter", - "day", - "E_BATT" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_GSL" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_EV" - ], - [ - "R1", - 2030, - "fall", - "night", - "E_BATT" - ], - [ - "R2", - 2025, - "spring", - "day", - "T_BLND" - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NUCLEAR" - ], - [ - "R2", - 2020, - "spring", - "day", - "R_EH" - ], - [ - "R2", - 2030, - "fall", - "day", - "R_EH" - ], - [ - "R1", - 2020, - "spring", - "night", - "S_OILREF" - ], - [ - "R1", - 2025, - "winter", - "day", - "E_BATT" - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NGCC" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_GSL" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_EV" - ], - [ - "R2-R1", - 2020, - "winter", - "night", - "E_TRANS" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_GSL" - ], - [ - "R1", - 2020, - "winter", - "day", - "T_BLND" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_GSL" - ], - [ - "R1", - 2020, - "spring", - "night", - "E_SOLPV" - ], - [ - "R1", - 2025, - "fall", - "day", - "E_NUCLEAR" - ], - [ - "R1", - 2025, - "spring", - "day", - "T_BLND" - ], - [ - "R2", - 2020, - "fall", - "day", - "T_DSL" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_GSL" - ], - [ - "R2", - 2030, - "spring", - "day", - "R_EH" - ], - [ - "R2", - 2020, - "summer", - "day", - "S_OILREF" - ], - [ - "R1", - 2020, - "spring", - "day", - "E_NUCLEAR" - ], - [ - "R2", - 2020, - "summer", - "day", - "E_SOLPV" - ], - [ - "R1", - 2025, - "summer", - "night", - "E_NGCC" - ], - [ - "R2", - 2020, - "winter", - "day", - "S_OILREF" - ], - [ - "R1", - 2025, - "fall", - "night", - "S_OILREF" - ], - [ - "R2", - 2020, - "winter", - "night", - "E_NUCLEAR" - ], - [ - "R2", - 2020, - "winter", - "day", - "E_SOLPV" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_BLND" - ], - [ - "R1", - 2025, - "fall", - "night", - "E_SOLPV" - ], - [ - "R1-R2", - 2030, - "fall", - "night", - "E_TRANS" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_GSL" - ], - [ - "R2", - 2030, - "summer", - "day", - "S_OILREF" - ], - [ - "R1", - 2020, - "fall", - "night", - "T_DSL" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_DSL" - ], - [ - "R1", - 2030, - "spring", - "day", - "T_EV" - ], - [ - "R2", - 2030, - "summer", - "day", - "E_SOLPV" - ], - [ - "R1", - 2020, - "summer", - "night", - "E_BATT" - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NUCLEAR" - ], - [ - "R1", - 2030, - "winter", - "night", - "R_NGH" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_BLND" - ], - [ - "R2", - 2020, - "summer", - "day", - "R_EH" - ], - [ - "R1", - 2020, - "summer", - "day", - "E_NGCC" - ], - [ - "R2", - 2025, - "spring", - "night", - "S_OILREF" - ], - [ - "R2", - 2020, - "fall", - "night", - "T_GSL" - ], - [ - "R1", - 2020, - "summer", - "night", - "T_GSL" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_BLND" - ], - [ - "R2", - 2025, - "spring", - "night", - "E_SOLPV" - ], - [ - "R1", - 2030, - "winter", - "night", - "R_EH" - ], - [ - "R2", - 2025, - "spring", - "day", - "R_NGH" - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NUCLEAR" - ], - [ - "R1", - 2025, - "fall", - "night", - "R_EH" - ], - [ - "R1", - 2020, - "winter", - "night", - "S_OILREF" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_BLND" - ], - [ - "R2", - 2020, - "fall", - "day", - "T_EV" - ], - [ - "R1", - 2025, - "spring", - "night", - "S_OILREF" - ], - [ - "R1", - 2020, - "winter", - "night", - "E_SOLPV" - ], - [ - "R1", - 2020, - "winter", - "day", - "R_NGH" - ], - [ - "R1", - 2025, - "spring", - "night", - "E_SOLPV" - ], - [ - "R1", - 2025, - "spring", - "day", - "R_NGH" - ], - [ - "R2", - 2030, - "summer", - "day", - "R_EH" - ], - [ - "R2-R1", - 2020, - "summer", - "night", - "E_TRANS" - ], - [ - "R2", - 2025, - "spring", - "day", - "R_EH" - ], - [ - "R2", - 2025, - "spring", - "day", - "E_NUCLEAR" - ], - [ - "R1", - 2020, - "fall", - "day", - "E_NGCC" - ], - [ - "R2-R1", - 2030, - "spring", - "night", - "E_TRANS" - ], - [ - "R1", - 2020, - "winter", - "day", - "R_EH" - ], - [ - "R1", - 2020, - "winter", - "day", - "E_NUCLEAR" - ], - [ - "R1", - 2025, - "spring", - "day", - "R_EH" - ], - [ - "R1", - 2025, - "spring", - "day", - "E_NUCLEAR" - ], - [ - "R1-R2", - 2025, - "winter", - "day", - "E_TRANS" - ], - [ - "R2", - 2020, - "spring", - "day", - "T_DSL" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_DSL" - ], - [ - "R2", - 2030, - "winter", - "night", - "R_NGH" - ], - [ - "R1", - 2020, - "fall", - "night", - "T_EV" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_EV" - ], - [ - "R2", - 2020, - "fall", - "day", - "T_BLND" - ], - [ - "R2", - 2020, - "spring", - "night", - "E_NGCC" - ], - [ - "R2-R1", - 2030, - "fall", - "night", - "E_TRANS" - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NGCC" - ], - [ - "R2", - 2030, - "spring", - "day", - "T_DSL" - ], - [ - "R2", - 2025, - "summer", - "night", - "S_OILREF" - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NUCLEAR" - ], - [ - "R2", - 2020, - "spring", - "day", - "E_BATT" - ], - [ - "R2", - 2030, - "winter", - "day", - "E_SOLPV" - ], - [ - "R2", - 2030, - "fall", - "day", - "E_BATT" - ], - [ - "R1", - 2025, - "winter", - "day", - "S_OILREF" - ], - [ - "R1", - 2020, - "summer", - "night", - "T_BLND" - ], - [ - "R1-R2", - 2030, - "spring", - "night", - "E_TRANS" - ], - [ - "R2", - 2025, - "summer", - "night", - "E_SOLPV" - ], - [ - "R2", - 2025, - "summer", - "day", - "R_NGH" - ], - [ - "R1", - 2025, - "summer", - "day", - "R_NGH" - ], - [ - "R2", - 2025, - "winter", - "day", - "R_NGH" - ], - [ - "R2", - 2025, - "fall", - "night", - "E_BATT" - ], - [ - "R1", - 2030, - "summer", - "night", - "E_BATT" - ], - [ - "R1", - 2030, - "fall", - "night", - "R_NGH" - ], - [ - "R2", - 2025, - "summer", - "day", - "E_NUCLEAR" - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NGCC" - ], - [ - "R1", - 2025, - "winter", - "day", - "R_NGH" - ], - [ - "R2", - 2030, - "spring", - "day", - "E_BATT" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_GSL" - ], - [ - "R1", - 2020, - "fall", - "night", - "T_BLND" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_GSL" - ], - [ - "R2", - 2025, - "winter", - "day", - "R_EH" - ], - [ - "R1", - 2025, - "summer", - "day", - "E_NUCLEAR" - ], - [ - "R1", - 2025, - "fall", - "day", - "E_NGCC" - ], - [ - "R1", - 2030, - "fall", - "night", - "R_EH" - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NUCLEAR" - ], - [ - "R1-R2", - 2020, - "fall", - "night", - "E_TRANS" - ], - [ - "R2", - 2020, - "summer", - "day", - "T_DSL" - ], - [ - "R1", - 2030, - "spring", - "night", - "S_OILREF" - ], - [ - "R1", - 2030, - "fall", - "day", - "E_SOLPV" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_EV" - ], - [ - "R1", - 2025, - "winter", - "day", - "R_EH" - ], - [ - "R1", - 2030, - "spring", - "night", - "E_SOLPV" - ], - [ - "R1", - 2020, - "spring", - "night", - "E_BATT" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_DSL" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_DSL" - ], - [ - "R1", - 2020, - "spring", - "day", - "E_NGCC" - ], - [ - "R1", - 2020, - "spring", - "night", - "T_GSL" - ], - [ - "R2", - 2020, - "summer", - "night", - "E_NGCC" - ], - [ - "R2", - 2020, - "fall", - "night", - "S_OILREF" - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NUCLEAR" - ], - [ - "R1", - 2030, - "spring", - "night", - "R_NGH" - ], - [ - "R1", - 2025, - "summer", - "night", - "S_OILREF" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_DSL" - ], - [ - "R2", - 2025, - "spring", - "day", - "T_DSL" - ], - [ - "R2", - 2020, - "fall", - "night", - "E_SOLPV" - ], - [ - "R2", - 2020, - "winter", - "night", - "E_NGCC" - ], - [ - "R2", - 2020, - "summer", - "day", - "E_BATT" - ], - [ - "R1", - 2025, - "summer", - "night", - "E_SOLPV" - ], - [ - "R2-R1", - 2020, - "spring", - "day", - "E_TRANS" - ], - [ - "R1", - 2020, - "winter", - "day", - "T_DSL" - ], - [ - "R1", - 2025, - "spring", - "day", - "T_DSL" - ], - [ - "R1", - 2030, - "spring", - "night", - "R_EH" - ], - [ - "R2", - 2020, - "winter", - "day", - "E_BATT" - ], - [ - "R2-R1", - 2030, - "summer", - "night", - "E_TRANS" - ], - [ - "R1", - 2025, - "fall", - "night", - "E_BATT" - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NGCC" - ], - [ - "R2", - 2020, - "spring", - "day", - "T_BLND" - ], - [ - "R2", - 2020, - "fall", - "day", - "E_NUCLEAR" - ], - [ - "R1", - 2020, - "summer", - "night", - "R_NGH" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_BLND" - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NGCC" - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NGCC" - ], - [ - "R2", - 2020, - "winter", - "day", - "T_GSL" - ], - [ - "R2-R1", - 2030, - "winter", - "day", - "E_TRANS" - ], - [ - "R2", - 2030, - "summer", - "day", - "E_BATT" - ], - [ - "R1-R2", - 2030, - "winter", - "day", - "E_TRANS" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_BLND" - ], - [ - "R2", - 2020, - "fall", - "night", - "R_EH" - ], - [ - "R1", - 2020, - "summer", - "night", - "R_EH" - ], - [ - "R1", - 2020, - "summer", - "night", - "E_NUCLEAR" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_BLND" - ], - [ - "R2", - 2020, - "summer", - "day", - "T_EV" - ], - [ - "R2", - 2030, - "spring", - "day", - "T_BLND" - ], - [ - "R2", - 2025, - "spring", - "night", - "E_BATT" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_EV" - ], - [ - "R1", - 2020, - "winter", - "night", - "E_BATT" - ], - [ - "R1", - 2020, - "fall", - "day", - "S_OILREF" - ], - [ - "R1-R2", - 2025, - "summer", - "night", - "E_TRANS" - ], - [ - "R1", - 2025, - "spring", - "night", - "E_BATT" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_GSL" - ], - [ - "R1", - 2020, - "spring", - "night", - "T_BLND" - ], - [ - "R1", - 2020, - "fall", - "night", - "E_NUCLEAR" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_GSL" - ], - [ - "R1", - 2020, - "fall", - "day", - "E_SOLPV" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_EV" - ], - [ - "R2-R1", - 2025, - "summer", - "night", - "E_TRANS" - ], - [ - "R1", - 2020, - "winter", - "night", - "T_GSL" - ], - [ - "R2", - 2025, - "spring", - "day", - "T_EV" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_GSL" - ], - [ - "R1", - 2020, - "winter", - "day", - "T_EV" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_DSL" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_DSL" - ], - [ - "R1", - 2025, - "spring", - "day", - "T_EV" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_DSL" - ], - [ - "R2", - 2020, - "summer", - "day", - "T_BLND" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_DSL" - ], - [ - "R2", - 2020, - "spring", - "night", - "S_OILREF" - ], - [ - "R2", - 2030, - "fall", - "night", - "S_OILREF" - ], - [ - "R2", - 2020, - "winter", - "day", - "T_BLND" - ], - [ - "R2", - 2025, - "winter", - "night", - "E_NGCC" - ], - [ - "R2", - 2020, - "spring", - "night", - "E_SOLPV" - ], - [ - "R2", - 2020, - "spring", - "day", - "R_NGH" - ], - [ - "R2", - 2030, - "fall", - "night", - "E_SOLPV" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_BLND" - ], - [ - "R1", - 2025, - "winter", - "night", - "E_NGCC" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_BLND" - ], - [ - "R2", - 2030, - "winter", - "day", - "E_BATT" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_EV" - ], - [ - "R2", - 2025, - "fall", - "night", - "R_NGH" - ], - [ - "R2", - 2025, - "summer", - "night", - "E_BATT" - ], - [ - "R2", - 2020, - "spring", - "day", - "E_NUCLEAR" - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NUCLEAR" - ], - [ - "R1", - 2030, - "summer", - "night", - "R_NGH" - ], - [ - "R2-R1", - 2025, - "spring", - "night", - "E_TRANS" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_DSL" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_GSL" - ], - [ - "R2", - 2030, - "spring", - "day", - "R_NGH" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_GSL" - ], - [ - "R1-R2", - 2020, - "winter", - "day", - "E_TRANS" - ], - [ - "R2", - 2025, - "fall", - "night", - "R_EH" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_BLND" - ], - [ - "R2", - 2025, - "fall", - "night", - "E_NUCLEAR" - ], - [ - "R2", - 2025, - "fall", - "day", - "E_SOLPV" - ], - [ - "R1", - 2030, - "summer", - "night", - "R_EH" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_EV" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_GSL" - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NUCLEAR" - ], - [ - "R1", - 2020, - "spring", - "night", - "R_NGH" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_EV" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_EV" - ], - [ - "R2", - 2020, - "fall", - "night", - "T_DSL" - ], - [ - "R1", - 2020, - "summer", - "night", - "T_DSL" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_GSL" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_EV" - ], - [ - "R2-R1", - 2025, - "fall", - "night", - "E_TRANS" - ], - [ - "R1", - 2030, - "spring", - "night", - "E_BATT" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_EV" - ], - [ - "R2-R1", - 2020, - "winter", - "day", - "E_TRANS" - ], - [ - "R1", - 2020, - "spring", - "night", - "R_EH" - ], - [ - "R2", - 2020, - "summer", - "night", - "S_OILREF" - ], - [ - "R1", - 2020, - "spring", - "night", - "E_NUCLEAR" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_GSL" - ], - [ - "R1", - 2020, - "spring", - "day", - "E_SOLPV" - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NGCC" - ], - [ - "R1-R2", - 2025, - "spring", - "night", - "E_TRANS" - ], - [ - "R2", - 2020, - "summer", - "night", - "E_SOLPV" - ], - [ - "R2", - 2020, - "summer", - "day", - "R_NGH" - ], - [ - "R2", - 2020, - "fall", - "night", - "E_BATT" - ], - [ - "R2", - 2020, - "winter", - "day", - "R_NGH" - ], - [ - "R1", - 2025, - "fall", - "night", - "R_NGH" - ], - [ - "R1", - 2025, - "summer", - "night", - "E_BATT" - ], - [ - "R2", - 2020, - "summer", - "day", - "E_NUCLEAR" - ], - [ - "R2", - 2020, - "fall", - "day", - "E_NGCC" - ], - [ - "R2", - 2030, - "summer", - "night", - "S_OILREF" - ], - [ - "R2", - 2030, - "spring", - "night", - "S_OILREF" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_EV" - ], - [ - "R2", - 2030, - "summer", - "night", - "E_SOLPV" - ], - [ - "R1", - 2030, - "winter", - "day", - "S_OILREF" - ], - [ - "R2", - 2020, - "winter", - "day", - "R_EH" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_GSL" - ], - [ - "R2", - 2030, - "summer", - "day", - "R_NGH" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_BLND" - ], - [ - "R2", - 2030, - "spring", - "night", - "E_SOLPV" - ], - [ - "R1", - 2025, - "fall", - "night", - "E_NUCLEAR" - ], - [ - "R1", - 2030, - "winter", - "day", - "E_SOLPV" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_BLND" - ], - [ - "R1-R2", - 2030, - "fall", - "day", - "E_TRANS" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_BLND" - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NUCLEAR" - ], - [ - "R2", - 2025, - "spring", - "night", - "R_NGH" - ], - [ - "R1", - 2020, - "summer", - "night", - "T_EV" - ], - [ - "R1", - 2020, - "winter", - "night", - "R_NGH" - ], - [ - "R1", - 2025, - "spring", - "night", - "R_NGH" - ], - [ - "R1", - 2020, - "summer", - "day", - "T_GSL" - ], - [ - "R2", - 2025, - "spring", - "night", - "R_EH" - ], - [ - "R1", - 2020, - "fall", - "night", - "E_NGCC" - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NGCC" - ], - [ - "R1", - 2030, - "winter", - "day", - "R_EH" - ], - [ - "R1", - 2020, - "winter", - "night", - "R_EH" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_BLND" - ], - [ - "R1", - 2025, - "spring", - "night", - "R_EH" - ], - [ - "R1", - 2020, - "fall", - "day", - "E_BATT" - ], - [ - "R1-R2", - 2025, - "winter", - "night", - "E_TRANS" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_DSL" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_DSL" - ], - [ - "R1", - 2020, - "fall", - "day", - "T_GSL" - ], - [ - "R2", - 2030, - "winter", - "day", - "S_OILREF" - ], - [ - "R2-R1", - 2025, - "winter", - "day", - "E_TRANS" - ], - [ - "R2-R1", - 2020, - "fall", - "day", - "E_TRANS" - ], - [ - "R2", - 2020, - "fall", - "night", - "T_BLND" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_BLND" - ], - [ - "R2", - 2025, - "winter", - "night", - "S_OILREF" - ], - [ - "R1", - 2020, - "spring", - "night", - "T_DSL" - ], - [ - "R2", - 2025, - "winter", - "night", - "E_SOLPV" - ], - [ - "R2", - 2020, - "spring", - "night", - "E_BATT" - ], - [ - "R2", - 2030, - "fall", - "night", - "E_BATT" - ], - [ - "R1", - 2025, - "winter", - "night", - "S_OILREF" - ], - [ - "R2", - 2030, - "winter", - "day", - "R_NGH" - ], - [ - "R2", - 2025, - "summer", - "night", - "R_NGH" - ], - [ - "R1", - 2025, - "winter", - "night", - "E_SOLPV" - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NGCC" - ], - [ - "R1-R2", - 2020, - "summer", - "night", - "E_TRANS" - ], - [ - "R2", - 2020, - "spring", - "night", - "T_GSL" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_GSL" - ], - [ - "R1", - 2030, - "fall", - "day", - "S_OILREF" - ], - [ - "R2", - 2025, - "winter", - "day", - "E_NUCLEAR" - ], - [ - "R2", - 2030, - "winter", - "day", - "R_EH" - ], - [ - "R2", - 2025, - "summer", - "night", - "R_EH" - ], - [ - "R2", - 2020, - "spring", - "day", - "T_EV" - ], - [ - "R1", - 2025, - "winter", - "day", - "E_NUCLEAR" - ], - [ - "R2", - 2020, - "winter", - "day", - "T_DSL" - ], - [ - "R2", - 2025, - "winter", - "night", - "R_EH" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_EV" - ], - [ - "R1", - 2030, - "fall", - "day", - "R_NGH" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_EV" - ], - [ - "R1", - 2025, - "winter", - "night", - "R_EH" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_GSL" - ], - [ - "R2", - 2030, - "spring", - "day", - "T_EV" - ], - [ - "R1", - 2020, - "fall", - "day", - "T_BLND" - ], - [ - "R1", - 2030, - "fall", - "day", - "R_EH" - ], - [ - "R1", - 2030, - "spring", - "day", - "S_OILREF" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_GSL" - ] - ], - "LifetimeProcess_rtv": [ - [ - "R2", - "T_BLND", - 2020 - ], - [ - "R2", - "E_BATT", - 2030 - ], - [ - "R2", - "S_IMPURN", - 2020 - ], - [ - "R1", - "E_BATT", - 2020 - ], - [ - "R1", - "T_EV", - 2030 - ], - [ - "R1", - "E_NGCC", - 2020 - ], - [ - "R1", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - "T_DSL", - 2020 - ], - [ - "R1", - "R_NGH", - 2020 - ], - [ - "R1", - "T_GSL", - 2030 - ], - [ - "R2", - "T_EV", - 2030 - ], - [ - "R2", - "E_NGCC", - 2020 - ], - [ - "R1", - "R_EH", - 2030 - ], - [ - "R2", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - "R_NGH", - 2020 - ], - [ - "R1", - "S_OILREF", - 2020 - ], - [ - "R1", - "E_SOLPV", - 2025 - ], - [ - "R1", - "T_DSL", - 2025 - ], - [ - "R1", - "S_IMPOIL", - 2020 - ], - [ - "R2", - "E_BATT", - 2020 - ], - [ - "R2", - "T_GSL", - 2030 - ], - [ - "R2", - "E_SOLPV", - 2025 - ], - [ - "R1", - "T_EV", - 2020 - ], - [ - "R2", - "R_EH", - 2030 - ], - [ - "R2", - "R_NGH", - 2030 - ], - [ - "R2", - "S_OILREF", - 2020 - ], - [ - "R2", - "S_IMPOIL", - 2020 - ], - [ - "R1", - "E_BATT", - 2025 - ], - [ - "R2", - "T_EV", - 2020 - ], - [ - "R1", - "S_IMPNG", - 2020 - ], - [ - "R1", - "E_NGCC", - 2025 - ], - [ - "R1", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - "T_GSL", - 2020 - ], - [ - "R1", - "S_IMPETH", - 2020 - ], - [ - "R1", - "R_EH", - 2020 - ], - [ - "R1", - "R_NGH", - 2025 - ], - [ - "R2", - "T_GSL", - 2020 - ], - [ - "R2", - "T_DSL", - 2025 - ], - [ - "R2", - "S_IMPNG", - 2020 - ], - [ - "R2", - "E_NGCC", - 2025 - ], - [ - "R2", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - "R_EH", - 2020 - ], - [ - "R2", - "S_IMPETH", - 2020 - ], - [ - "R2", - "R_NGH", - 2025 - ], - [ - "R1", - "E_SOLPV", - 2030 - ], - [ - "R1", - "T_DSL", - 2030 - ], - [ - "R2", - "E_BATT", - 2025 - ], - [ - "R2", - "E_SOLPV", - 2030 - ], - [ - "R1", - "T_EV", - 2025 - ], - [ - "R1", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - "E_BATT", - 2030 - ], - [ - "R1", - "T_GSL", - 2025 - ], - [ - "R2", - "T_EV", - 2025 - ], - [ - "R1", - "E_NGCC", - 2030 - ], - [ - "R1", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - "E_NUCLEAR", - 2015 - ], - [ - "R2-R1", - "E_TRANS", - 2015 - ], - [ - "R2", - "T_DSL", - 2030 - ], - [ - "R1", - "R_EH", - 2025 - ], - [ - "R1", - "R_NGH", - 2030 - ], - [ - "R1", - "E_SOLPV", - 2020 - ], - [ - "R1", - "T_DSL", - 2020 - ], - [ - "R2", - "T_GSL", - 2025 - ], - [ - "R2", - "E_NGCC", - 2030 - ], - [ - "R2", - "R_EH", - 2025 - ], - [ - "R2", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - "S_IMPURN", - 2020 - ], - [ - "R1-R2", - "E_TRANS", - 2015 - ], - [ - "R1", - "T_BLND", - 2020 - ], - [ - "R2", - "E_SOLPV", - 2020 - ] - ], - "LoanLifetimeProcess_rtv": [ - [ - "R2", - "T_BLND", - 2020 - ], - [ - "R2", - "E_BATT", - 2030 - ], - [ - "R2", - "S_IMPURN", - 2020 - ], - [ - "R1", - "E_BATT", - 2020 - ], - [ - "R1", - "T_EV", - 2030 - ], - [ - "R1", - "E_NGCC", - 2020 - ], - [ - "R1", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - "T_DSL", - 2020 - ], - [ - "R1", - "R_NGH", - 2020 - ], - [ - "R1", - "T_GSL", - 2030 - ], - [ - "R2", - "T_EV", - 2030 - ], - [ - "R2", - "E_NGCC", - 2020 - ], - [ - "R1", - "R_EH", - 2030 - ], - [ - "R2", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - "R_NGH", - 2020 - ], - [ - "R1", - "S_OILREF", - 2020 - ], - [ - "R1", - "E_SOLPV", - 2025 - ], - [ - "R1", - "T_DSL", - 2025 - ], - [ - "R1", - "S_IMPOIL", - 2020 - ], - [ - "R2", - "E_BATT", - 2020 - ], - [ - "R2", - "T_GSL", - 2030 - ], - [ - "R2", - "E_SOLPV", - 2025 - ], - [ - "R1", - "T_EV", - 2020 - ], - [ - "R2", - "R_EH", - 2030 - ], - [ - "R2", - "R_NGH", - 2030 - ], - [ - "R2", - "S_OILREF", - 2020 - ], - [ - "R2", - "S_IMPOIL", - 2020 - ], - [ - "R1", - "E_BATT", - 2025 - ], - [ - "R2", - "T_EV", - 2020 - ], - [ - "R1", - "S_IMPNG", - 2020 - ], - [ - "R1", - "E_NGCC", - 2025 - ], - [ - "R1", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - "T_GSL", - 2020 - ], - [ - "R1", - "S_IMPETH", - 2020 - ], - [ - "R1", - "R_EH", - 2020 - ], - [ - "R1", - "R_NGH", - 2025 - ], - [ - "R2", - "T_GSL", - 2020 - ], - [ - "R2", - "T_DSL", - 2025 - ], - [ - "R2", - "S_IMPNG", - 2020 - ], - [ - "R2", - "E_NGCC", - 2025 - ], - [ - "R2", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - "R_EH", - 2020 - ], - [ - "R2", - "S_IMPETH", - 2020 - ], - [ - "R2", - "R_NGH", - 2025 - ], - [ - "R1", - "E_SOLPV", - 2030 - ], - [ - "R1", - "T_DSL", - 2030 - ], - [ - "R2", - "E_BATT", - 2025 - ], - [ - "R2", - "E_SOLPV", - 2030 - ], - [ - "R1", - "T_EV", - 2025 - ], - [ - "R1", - "E_BATT", - 2030 - ], - [ - "R1", - "T_GSL", - 2025 - ], - [ - "R2", - "T_EV", - 2025 - ], - [ - "R1", - "E_NGCC", - 2030 - ], - [ - "R1", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - "T_DSL", - 2030 - ], - [ - "R1", - "R_EH", - 2025 - ], - [ - "R1", - "R_NGH", - 2030 - ], - [ - "R1", - "E_SOLPV", - 2020 - ], - [ - "R1", - "T_DSL", - 2020 - ], - [ - "R2", - "T_GSL", - 2025 - ], - [ - "R2", - "E_NGCC", - 2030 - ], - [ - "R2", - "R_EH", - 2025 - ], - [ - "R2", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - "S_IMPURN", - 2020 - ], - [ - "R1", - "T_BLND", - 2020 - ], - [ - "R2", - "E_SOLPV", - 2020 - ] - ], - "RenewablePortfolioStandardConstraint_rpg": [], - "CostFixed_rptv": [ - [ - "R1", - 2020, - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2030 - ], - [ - "R1", - 2030, - "T_EV", - 2025 - ], - [ - "R1", - 2020, - "R_NGH", - 2020 - ], - [ - "R2", - 2020, - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "T_DSL", - 2030 - ], - [ - "R1", - 2025, - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "E_NGCC", - 2030 - ], - [ - "R2", - 2020, - "T_GSL", - 2020 - ], - [ - "R1", - 2025, - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "T_EV", - 2025 - ], - [ - "R1", - 2025, - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2020, - "T_EV", - 2020 - ], - [ - "R1-R2", - 2030, - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "R_NGH", - 2020 - ], - [ - "R2", - 2025, - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2020, - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "E_NGCC", - 2020 - ], - [ - "R2", - 2020, - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "R_EH", - 2020 - ], - [ - "R1", - 2020, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2025 - ], - [ - "R2", - 2020, - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "T_EV", - 2025 - ], - [ - "R1", - 2020, - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "T_DSL", - 2030 - ], - [ - "R1", - 2020, - "E_NGCC", - 2020 - ], - [ - "R1", - 2020, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "T_GSL", - 2025 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "E_NGCC", - 2030 - ], - [ - "R2-R1", - 2030, - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2030 - ], - [ - "R1", - 2020, - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2030, - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2020 - ], - [ - "R2-R1", - 2020, - "E_TRANS", - 2015 - ], - [ - "R1", - 2020, - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "T_GSL", - 2030 - ], - [ - "R1-R2", - 2020, - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "R_EH", - 2025 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "T_GSL", - 2020 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "R_EH", - 2030 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "T_GSL", - 2020 - ], - [ - "R2", - 2020, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "T_GSL", - 2025 - ], - [ - "R2", - 2025, - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "R_EH", - 2030 - ], - [ - "R2", - 2030, - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "R_NGH", - 2030 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "S_OILREF", - 2020 - ], - [ - "R2", - 2020, - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "T_EV", - 2030 - ], - [ - "R1", - 2025, - "T_EV", - 2025 - ], - [ - "R1", - 2020, - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "R_NGH", - 2020 - ], - [ - "R1-R2", - 2025, - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2030 - ], - [ - "R2", - 2030, - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "R_NGH", - 2030 - ], - [ - "R1", - 2025, - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "T_EV", - 2030 - ], - [ - "R1", - 2020, - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "T_GSL", - 2030 - ], - [ - "R2-R1", - 2025, - "E_TRANS", - 2015 - ], - [ - "R2", - 2020, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2020, - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "E_SOLPV", - 2020 - ], - [ - "R1", - 2025, - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "R_EH", - 2025 - ] - ], - "CostInvest_rtv": [ - [ - "R1", - "E_NGCC", - 2020 - ], - [ - "R1", - "E_NGCC", - 2025 - ], - [ - "R1", - "E_NGCC", - 2030 - ], - [ - "R1", - "E_SOLPV", - 2020 - ], - [ - "R1", - "E_SOLPV", - 2025 - ], - [ - "R1", - "E_SOLPV", - 2030 - ], - [ - "R1", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - "E_BATT", - 2020 - ], - [ - "R1", - "E_BATT", - 2025 - ], - [ - "R1", - "E_BATT", - 2030 - ], - [ - "R1", - "T_GSL", - 2020 - ], - [ - "R1", - "T_GSL", - 2025 - ], - [ - "R1", - "T_GSL", - 2030 - ], - [ - "R1", - "T_DSL", - 2020 - ], - [ - "R1", - "T_DSL", - 2025 - ], - [ - "R1", - "T_DSL", - 2030 - ], - [ - "R1", - "T_EV", - 2020 - ], - [ - "R1", - "T_EV", - 2025 - ], - [ - "R1", - "T_EV", - 2030 - ], - [ - "R1", - "R_EH", - 2020 - ], - [ - "R1", - "R_EH", - 2025 - ], - [ - "R1", - "R_EH", - 2030 - ], - [ - "R1", - "R_NGH", - 2020 - ], - [ - "R1", - "R_NGH", - 2025 - ], - [ - "R1", - "R_NGH", - 2030 - ], - [ - "R2", - "E_NGCC", - 2020 - ], - [ - "R2", - "E_NGCC", - 2025 - ], - [ - "R2", - "E_NGCC", - 2030 - ], - [ - "R2", - "E_SOLPV", - 2020 - ], - [ - "R2", - "E_SOLPV", - 2025 - ], - [ - "R2", - "E_SOLPV", - 2030 - ], - [ - "R2", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - "E_BATT", - 2020 - ], - [ - "R2", - "E_BATT", - 2025 - ], - [ - "R2", - "E_BATT", - 2030 - ], - [ - "R2", - "T_GSL", - 2020 - ], - [ - "R2", - "T_GSL", - 2025 - ], - [ - "R2", - "T_GSL", - 2030 - ], - [ - "R2", - "T_DSL", - 2020 - ], - [ - "R2", - "T_DSL", - 2025 - ], - [ - "R2", - "T_DSL", - 2030 - ], - [ - "R2", - "T_EV", - 2020 - ], - [ - "R2", - "T_EV", - 2025 - ], - [ - "R2", - "T_EV", - 2030 - ], - [ - "R2", - "R_EH", - 2020 - ], - [ - "R2", - "R_EH", - 2025 - ], - [ - "R2", - "R_EH", - 2030 - ], - [ - "R2", - "R_NGH", - 2020 - ], - [ - "R2", - "R_NGH", - 2025 - ], - [ - "R2", - "R_NGH", - 2030 - ] - ], - "CostVariable_rptv": [ - [ - "R1", - 2020, - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2030 - ], - [ - "R1", - 2030, - "T_EV", - 2025 - ], - [ - "R1", - 2020, - "R_NGH", - 2020 - ], - [ - "R2", - 2020, - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "T_DSL", - 2030 - ], - [ - "R1", - 2025, - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2030 - ], - [ - "R2", - 2020, - "T_GSL", - 2020 - ], - [ - "R1", - 2025, - "E_NGCC", - 2025 - ], - [ - "R2", - 2020, - "S_IMPNG", - 2020 - ], - [ - "R2", - 2030, - "T_EV", - 2025 - ], - [ - "R1", - 2025, - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "T_EV", - 2020 - ], - [ - "R1-R2", - 2030, - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "R_NGH", - 2020 - ], - [ - "R1", - 2020, - "S_IMPNG", - 2020 - ], - [ - "R2", - 2025, - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2020, - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "E_NGCC", - 2020 - ], - [ - "R2", - 2020, - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "S_IMPNG", - 2020 - ], - [ - "R1", - 2020, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "T_DSL", - 2020 - ], - [ - "R1", - 2020, - "S_IMPURN", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2025 - ], - [ - "R1", - 2025, - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "T_EV", - 2025 - ], - [ - "R2", - 2030, - "T_EV", - 2020 - ], - [ - "R1", - 2020, - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "T_DSL", - 2030 - ], - [ - "R1", - 2020, - "E_NGCC", - 2020 - ], - [ - "R1", - 2020, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "T_GSL", - 2025 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "E_NGCC", - 2030 - ], - [ - "R2-R1", - 2030, - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2020, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2025, - "S_IMPURN", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2030 - ], - [ - "R1", - 2020, - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2020, - "S_IMPOIL", - 2020 - ], - [ - "R1", - 2030, - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "S_IMPURN", - 2020 - ], - [ - "R2-R1", - 2020, - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "T_GSL", - 2030 - ], - [ - "R1-R2", - 2020, - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "R_EH", - 2025 - ], - [ - "R1", - 2030, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "E_NGCC", - 2025 - ], - [ - "R2", - 2025, - "S_IMPNG", - 2020 - ], - [ - "R2", - 2030, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "R_EH", - 2030 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "T_GSL", - 2020 - ], - [ - "R2", - 2020, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "S_IMPETH", - 2020 - ], - [ - "R2", - 2025, - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "T_GSL", - 2025 - ], - [ - "R2", - 2025, - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "S_IMPETH", - 2020 - ], - [ - "R1", - 2030, - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "S_IMPETH", - 2020 - ], - [ - "R1", - 2030, - "R_EH", - 2030 - ], - [ - "R2", - 2030, - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "R_NGH", - 2030 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2020, - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "T_EV", - 2030 - ], - [ - "R1", - 2025, - "T_EV", - 2025 - ], - [ - "R1", - 2020, - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "S_IMPNG", - 2020 - ], - [ - "R2", - 2020, - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "S_IMPETH", - 2020 - ], - [ - "R1-R2", - 2025, - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2030 - ], - [ - "R2", - 2030, - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "R_NGH", - 2030 - ], - [ - "R1", - 2025, - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "S_IMPURN", - 2020 - ], - [ - "R1", - 2025, - "S_IMPNG", - 2020 - ], - [ - "R1", - 2030, - "T_EV", - 2030 - ], - [ - "R1", - 2020, - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "T_GSL", - 2030 - ], - [ - "R2", - 2025, - "S_IMPETH", - 2020 - ], - [ - "R2-R1", - 2025, - "E_TRANS", - 2015 - ], - [ - "R2", - 2020, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2020, - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2020, - "S_IMPURN", - 2020 - ], - [ - "R2", - 2025, - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "S_IMPETH", - 2020 - ], - [ - "R1", - 2025, - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "E_SOLPV", - 2020 - ], - [ - "R1", - 2025, - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "S_IMPURN", - 2020 - ], - [ - "R1", - 2030, - "R_NGH", - 2025 - ], - [ - "R2", - 2025, - "R_EH", - 2025 - ] - ], - "CostEmission_rpe": [], - "ModelProcessLife_rptv": [ - [ - "R1", - 2020, - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2030 - ], - [ - "R1", - 2030, - "T_EV", - 2025 - ], - [ - "R1", - 2020, - "R_NGH", - 2020 - ], - [ - "R2", - 2020, - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "T_DSL", - 2030 - ], - [ - "R1", - 2025, - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2030 - ], - [ - "R2", - 2020, - "T_GSL", - 2020 - ], - [ - "R1", - 2025, - "E_NGCC", - 2025 - ], - [ - "R2", - 2020, - "S_IMPNG", - 2020 - ], - [ - "R2", - 2030, - "T_EV", - 2025 - ], - [ - "R1", - 2025, - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "T_EV", - 2020 - ], - [ - "R1-R2", - 2030, - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "R_NGH", - 2020 - ], - [ - "R1", - 2020, - "S_IMPNG", - 2020 - ], - [ - "R2", - 2025, - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2020, - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "E_NGCC", - 2020 - ], - [ - "R2", - 2020, - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "S_IMPNG", - 2020 - ], - [ - "R1", - 2020, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "T_DSL", - 2020 - ], - [ - "R1", - 2020, - "S_IMPURN", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2025 - ], - [ - "R1", - 2025, - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "T_EV", - 2025 - ], - [ - "R2", - 2030, - "T_EV", - 2020 - ], - [ - "R1", - 2020, - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "T_DSL", - 2030 - ], - [ - "R1", - 2020, - "E_NGCC", - 2020 - ], - [ - "R1", - 2020, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "T_GSL", - 2025 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "E_NGCC", - 2030 - ], - [ - "R2-R1", - 2030, - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2020, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2025, - "S_IMPURN", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2030 - ], - [ - "R1", - 2020, - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2020, - "S_IMPOIL", - 2020 - ], - [ - "R1", - 2030, - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "S_IMPURN", - 2020 - ], - [ - "R2-R1", - 2020, - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "T_GSL", - 2030 - ], - [ - "R1-R2", - 2020, - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "R_EH", - 2025 - ], - [ - "R1", - 2030, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "E_NGCC", - 2025 - ], - [ - "R2", - 2025, - "S_IMPNG", - 2020 - ], - [ - "R2", - 2030, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "R_EH", - 2030 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "T_GSL", - 2020 - ], - [ - "R2", - 2020, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "S_IMPETH", - 2020 - ], - [ - "R2", - 2025, - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "T_GSL", - 2025 - ], - [ - "R2", - 2025, - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "S_IMPETH", - 2020 - ], - [ - "R1", - 2030, - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "S_IMPETH", - 2020 - ], - [ - "R1", - 2030, - "R_EH", - 2030 - ], - [ - "R2", - 2030, - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "R_NGH", - 2030 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2020, - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "T_EV", - 2030 - ], - [ - "R1", - 2025, - "T_EV", - 2025 - ], - [ - "R1", - 2020, - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "S_IMPNG", - 2020 - ], - [ - "R2", - 2020, - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "S_IMPETH", - 2020 - ], - [ - "R1-R2", - 2025, - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2030 - ], - [ - "R2", - 2030, - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "R_NGH", - 2030 - ], - [ - "R1", - 2025, - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "S_IMPURN", - 2020 - ], - [ - "R1", - 2025, - "S_IMPNG", - 2020 - ], - [ - "R1", - 2030, - "T_EV", - 2030 - ], - [ - "R1", - 2020, - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "T_GSL", - 2030 - ], - [ - "R2", - 2025, - "S_IMPETH", - 2020 - ], - [ - "R2-R1", - 2025, - "E_TRANS", - 2015 - ], - [ - "R2", - 2020, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2020, - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2020, - "S_IMPURN", - 2020 - ], - [ - "R2", - 2025, - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "S_IMPETH", - 2020 - ], - [ - "R1", - 2025, - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "E_SOLPV", - 2020 - ], - [ - "R1", - 2025, - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "S_IMPURN", - 2020 - ], - [ - "R1", - 2030, - "R_NGH", - 2025 - ], - [ - "R2", - 2025, - "R_EH", - 2025 - ] - ], - "ProcessLifeFrac_rptv": [ - [ - "R1", - 2020, - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2030 - ], - [ - "R1", - 2030, - "T_EV", - 2025 - ], - [ - "R1", - 2020, - "R_NGH", - 2020 - ], - [ - "R2", - 2020, - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "T_DSL", - 2030 - ], - [ - "R1", - 2025, - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2030 - ], - [ - "R2", - 2020, - "T_GSL", - 2020 - ], - [ - "R1", - 2025, - "E_NGCC", - 2025 - ], - [ - "R2", - 2020, - "S_IMPNG", - 2020 - ], - [ - "R2", - 2030, - "T_EV", - 2025 - ], - [ - "R1", - 2025, - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "T_EV", - 2020 - ], - [ - "R1-R2", - 2030, - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "R_NGH", - 2020 - ], - [ - "R1", - 2020, - "S_IMPNG", - 2020 - ], - [ - "R2", - 2025, - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2020, - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "E_NGCC", - 2020 - ], - [ - "R2", - 2020, - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "S_IMPNG", - 2020 - ], - [ - "R1", - 2020, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "T_DSL", - 2020 - ], - [ - "R1", - 2020, - "S_IMPURN", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2025 - ], - [ - "R1", - 2025, - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "T_EV", - 2025 - ], - [ - "R2", - 2030, - "T_EV", - 2020 - ], - [ - "R1", - 2020, - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "T_DSL", - 2030 - ], - [ - "R1", - 2020, - "E_NGCC", - 2020 - ], - [ - "R1", - 2020, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "T_GSL", - 2025 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "E_NGCC", - 2030 - ], - [ - "R2-R1", - 2030, - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2020, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2025, - "S_IMPURN", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2030 - ], - [ - "R1", - 2020, - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2020, - "S_IMPOIL", - 2020 - ], - [ - "R1", - 2030, - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "S_IMPURN", - 2020 - ], - [ - "R2-R1", - 2020, - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "T_GSL", - 2030 - ], - [ - "R1-R2", - 2020, - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "R_EH", - 2025 - ], - [ - "R1", - 2030, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "E_NGCC", - 2025 - ], - [ - "R2", - 2025, - "S_IMPNG", - 2020 - ], - [ - "R2", - 2030, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "R_EH", - 2030 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "T_GSL", - 2020 - ], - [ - "R2", - 2020, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "S_IMPETH", - 2020 - ], - [ - "R2", - 2025, - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "T_GSL", - 2025 - ], - [ - "R2", - 2025, - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "S_IMPETH", - 2020 - ], - [ - "R1", - 2030, - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "S_IMPETH", - 2020 - ], - [ - "R1", - 2030, - "R_EH", - 2030 - ], - [ - "R2", - 2030, - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "R_NGH", - 2030 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2020, - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "T_EV", - 2030 - ], - [ - "R1", - 2025, - "T_EV", - 2025 - ], - [ - "R1", - 2020, - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "S_IMPNG", - 2020 - ], - [ - "R2", - 2020, - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "S_IMPETH", - 2020 - ], - [ - "R1-R2", - 2025, - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2030 - ], - [ - "R2", - 2030, - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "R_NGH", - 2030 - ], - [ - "R1", - 2025, - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "S_IMPURN", - 2020 - ], - [ - "R1", - 2025, - "S_IMPNG", - 2020 - ], - [ - "R1", - 2030, - "T_EV", - 2030 - ], - [ - "R1", - 2020, - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "T_GSL", - 2030 - ], - [ - "R2", - 2025, - "S_IMPETH", - 2020 - ], - [ - "R2-R1", - 2025, - "E_TRANS", - 2015 - ], - [ - "R2", - 2020, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2020, - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2020, - "S_IMPURN", - 2020 - ], - [ - "R2", - 2025, - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "S_IMPETH", - 2020 - ], - [ - "R1", - 2025, - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "E_SOLPV", - 2020 - ], - [ - "R1", - 2025, - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "S_IMPURN", - 2020 - ], - [ - "R1", - 2030, - "R_NGH", - 2025 - ], - [ - "R2", - 2025, - "R_EH", - 2025 - ] - ], - "MinCapacityConstraint_rpt": [], - "MaxCapacityConstraint_rpt": [], - "MinNewCapacityConstraint_rpt": [], - "MaxNewCapacityConstraint_rpt": [], - "MaxResourceConstraint_rt": [], - "MaxActivityConstraint_rpt": [], - "MinActivityConstraint_rpt": [ - [ - "R1", - 2020, - "T_GSL" - ], - [ - "R1", - 2025, - "T_GSL" - ], - [ - "R1", - 2030, - "T_GSL" - ], - [ - "R2", - 2020, - "T_GSL" - ], - [ - "R2", - 2025, - "T_GSL" - ], - [ - "R2", - 2030, - "T_GSL" - ] - ], - "MinAnnualCapacityFactorConstraint_rpto": [], - "MaxAnnualCapacityFactorConstraint_rpto": [], - "EmissionLimitConstraint_rpe": [ - [ - "R1", - 2020, - "CO2" - ], - [ - "R1", - 2025, - "CO2" - ], - [ - "R1", - 2030, - "CO2" - ], - [ - "global", - 2020, - "CO2" - ], - [ - "global", - 2025, - "CO2" - ], - [ - "global", - 2030, - "CO2" - ] - ], - "EmissionActivity_reitvo": [ - [ - "R1", - "CO2", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - "CO2", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - "CO2", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - "CO2", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R2", - "CO2", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - "CO2", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - "CO2", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - "CO2", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - "CO2", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - "CO2", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - "CO2", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - "CO2", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - "CO2", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - "CO2", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - "CO2", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - "CO2", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - "CO2", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - "CO2", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - "CO2", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - "CO2", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - "CO2", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - "CO2", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - "CO2", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - "CO2", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - "CO2", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - "CO2", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - "CO2", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - "CO2", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - "CO2", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - "CO2", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - "CO2", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - "CO2", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - "CO2", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - "CO2", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - "CO2", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - "CO2", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - "CO2", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - "CO2", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R2", - "CO2", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - "CO2", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - "CO2", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - "CO2", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - "CO2", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - "CO2", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - "CO2", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R1", - "CO2", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - "CO2", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R2", - "CO2", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - "CO2", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - "CO2", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - "CO2", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - "CO2", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - "CO2", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R2", - "CO2", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - "CO2", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - "CO2", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - "CO2", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - "CO2", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - "CO2", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - "CO2", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - "CO2", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - "CO2", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - "CO2", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - "CO2", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R1", - "CO2", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - "CO2", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - "CO2", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - "CO2", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - "CO2", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - "CO2", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - "CO2", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - "CO2", - "NG", - "E_NGCC", - 2025, - "ELC" - ] - ], - "MinActivityGroup_rpg": [], - "MaxActivityGroup_rpg": [], - "MinCapacityGroupConstraint_rpg": [], - "MaxCapacityGroupConstraint_rpg": [], - "MinNewCapacityGroupConstraint_rpg": [], - "MaxNewCapacityGroupConstraint_rpg": [], - "GroupShareIndices": [], - "MinCapacityShareConstraint_rptg": [], - "MaxCapacityShareConstraint_rptg": [], - "TwoGroupShareIndices": [], - "MaxNewCapacityGroupShareConstraint_rpgg": [], - "MinNewCapacityGroupShareConstraint_rpgg": [], - "MinActivityShareConstraint_rptg": [], - "MaxActivityShareConstraint_rptg": [], - "MinNewCapacityShareConstraint_rptg": [], - "MaxNewCapacityShareConstraint_rptg": [], - "FlowVar_rpsditvo": [ - [ - "R1", - 2025, - "summer", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2025, - "spring", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "winter", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "summer", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "summer", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2030, - "summer", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "winter", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "summer", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "winter", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2030, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "fall", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "fall", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2020, - "fall", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2020, - "fall", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2025, - "fall", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "winter", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "fall", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2030, - "fall", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "fall", - "night", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "spring", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2030, - "spring", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2020, - "winter", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "winter", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "winter", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1-R2", - 2020, - "winter", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2030, - "summer", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "spring", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "winter", - "night", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "fall", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "spring", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "summer", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2020, - "winter", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2030, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "spring", - "day", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2025, - "fall", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2020, - "spring", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "summer", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2025, - "summer", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2025, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "spring", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "winter", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "spring", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2025, - "summer", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2025, - "summer", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "winter", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "spring", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "fall", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2025, - "spring", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "winter", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "fall", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "spring", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2030, - "summer", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2030, - "fall", - "night", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2-R1", - 2030, - "winter", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "spring", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "spring", - "day", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2020, - "fall", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "fall", - "day", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "spring", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "summer", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "fall", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "winter", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1-R2", - 2020, - "winter", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2025, - "winter", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "winter", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2025, - "fall", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "fall", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2-R1", - 2020, - "winter", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2020, - "spring", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2030, - "spring", - "night", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "day", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2020, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1-R2", - 2020, - "spring", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2030, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "summer", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1-R2", - 2025, - "spring", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2030, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "fall", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2020, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2030, - "winter", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "winter", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "spring", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1-R2", - 2030, - "spring", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2020, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "spring", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1-R2", - 2025, - "winter", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "night", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2025, - "fall", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "fall", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "winter", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2025, - "winter", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "fall", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2020, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "fall", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2020, - "spring", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "fall", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "fall", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "summer", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "summer", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2025, - "summer", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "summer", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "spring", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2025, - "winter", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "winter", - "night", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2020, - "winter", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "summer", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2020, - "winter", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2025, - "spring", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2020, - "winter", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "fall", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2025, - "spring", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "winter", - "night", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2030, - "fall", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "summer", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2025, - "winter", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "spring", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2-R1", - 2025, - "fall", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "summer", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2030, - "winter", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2-R1", - 2025, - "winter", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "winter", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2025, - "fall", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "winter", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2-R1", - 2020, - "fall", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2025, - "winter", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "spring", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "winter", - "night", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "spring", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2020, - "spring", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2020, - "winter", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "fall", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1-R2", - 2030, - "winter", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2030, - "summer", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1-R2", - 2025, - "summer", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "winter", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2030, - "summer", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "spring", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2025, - "winter", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "winter", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "winter", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2025, - "summer", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2030, - "winter", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2025, - "summer", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "winter", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "fall", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1-R2", - 2020, - "fall", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2-R1", - 2020, - "spring", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1-R2", - 2025, - "fall", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "winter", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2020, - "spring", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2030, - "fall", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "spring", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2025, - "summer", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "summer", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "summer", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2-R1", - 2020, - "summer", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2-R1", - 2030, - "fall", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "spring", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "fall", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "winter", - "day", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2020, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "winter", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "fall", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "fall", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "spring", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2030, - "summer", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2020, - "spring", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "fall", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1-R2", - 2025, - "fall", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "spring", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2020, - "summer", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2025, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2025, - "spring", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2030, - "spring", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2020, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2025, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "summer", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2030, - "summer", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2020, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "winter", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "spring", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2025, - "fall", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2025, - "summer", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "summer", - "night", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2030, - "fall", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2025, - "fall", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2020, - "summer", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2020, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2020, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "winter", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2020, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "spring", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1-R2", - 2020, - "spring", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2030, - "summer", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "winter", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2-R1", - 2030, - "summer", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2020, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "fall", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1-R2", - 2030, - "winter", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "summer", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "spring", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "winter", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2025, - "summer", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R1-R2", - 2030, - "summer", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "spring", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "summer", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "fall", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "spring", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2025, - "summer", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2030, - "summer", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "summer", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2030, - "spring", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2030, - "fall", - "day", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2025, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2020, - "spring", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "spring", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "summer", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "winter", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2020, - "summer", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2020, - "spring", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2030, - "spring", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "spring", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "fall", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "summer", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "spring", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "summer", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "spring", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2030, - "fall", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2020, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "winter", - "day", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "winter", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2025, - "summer", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "fall", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "summer", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2030, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "spring", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2020, - "winter", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "spring", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "summer", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "spring", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2030, - "winter", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2-R1", - 2020, - "summer", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2020, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "fall", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "fall", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "spring", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "summer", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2030, - "fall", - "day", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2025, - "spring", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "fall", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2020, - "winter", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "summer", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2-R1", - 2025, - "winter", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2025, - "spring", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2020, - "summer", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2025, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "winter", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "fall", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2020, - "winter", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2020, - "fall", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2-R1", - 2030, - "summer", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2-R1", - 2025, - "summer", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2030, - "fall", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "winter", - "day", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2020, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "spring", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "fall", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2025, - "fall", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "summer", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "winter", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "winter", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "winter", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2025, - "spring", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1-R2", - 2030, - "summer", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2020, - "summer", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2030, - "spring", - "night", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "winter", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2025, - "winter", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "fall", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "fall", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "fall", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "fall", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "winter", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2020, - "spring", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "winter", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "fall", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2020, - "winter", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "winter", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2025, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2030, - "fall", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "winter", - "day", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2025, - "winter", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2030, - "spring", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1-R2", - 2030, - "spring", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "winter", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "winter", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1-R2", - 2020, - "summer", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1-R2", - 2020, - "summer", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2030, - "summer", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2020, - "fall", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "spring", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2020, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "summer", - "night", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2-R1", - 2030, - "winter", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "winter", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2-R1", - 2020, - "winter", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2025, - "fall", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2020, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "winter", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2030, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "spring", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2025, - "spring", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "spring", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "winter", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1-R2", - 2030, - "fall", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R2", - 2020, - "spring", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2030, - "spring", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2020, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "summer", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "winter", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2030, - "summer", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "winter", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "winter", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "fall", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2030, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2020, - "spring", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2020, - "winter", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "fall", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "spring", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2020, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "summer", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2-R1", - 2030, - "fall", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "summer", - "night", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2025, - "fall", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2025, - "spring", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "spring", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2030, - "summer", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2020, - "winter", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1-R2", - 2025, - "winter", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2020, - "spring", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "winter", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "winter", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2025, - "spring", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2025, - "summer", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2-R1", - 2025, - "spring", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "winter", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2030, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2025, - "fall", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "winter", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2025, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "winter", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2020, - "spring", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2025, - "winter", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "winter", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "winter", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "fall", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2030, - "spring", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2030, - "winter", - "day", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "fall", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2-R1", - 2025, - "fall", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "spring", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2030, - "spring", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "winter", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2020, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2020, - "fall", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2030, - "winter", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2025, - "spring", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "spring", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2025, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "spring", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "summer", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2-R1", - 2030, - "spring", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2030, - "winter", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2030, - "spring", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "fall", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2025, - "spring", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "spring", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "fall", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2025, - "fall", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2020, - "fall", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "summer", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1-R2", - 2020, - "fall", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "fall", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2025, - "winter", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "spring", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2030, - "spring", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "fall", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "summer", - "night", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "fall", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "summer", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2025, - "summer", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "winter", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "fall", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "fall", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2030, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2025, - "winter", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2-R1", - 2020, - "fall", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "winter", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2020, - "winter", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "spring", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "winter", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "spring", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "fall", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "summer", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "fall", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2020, - "spring", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "fall", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2030, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "summer", - "day", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2020, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "spring", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2030, - "summer", - "day", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2020, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "winter", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2025, - "spring", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2025, - "fall", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "spring", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2030, - "summer", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "summer", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2030, - "winter", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2020, - "winter", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1-R2", - 2025, - "summer", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "fall", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2020, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R2-R1", - 2030, - "spring", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "summer", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2025, - "spring", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2025, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2-R1", - 2020, - "spring", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2025, - "fall", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "summer", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2025, - "fall", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2020, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2025, - "summer", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2025, - "fall", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2025, - "spring", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "winter", - "night", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2025, - "winter", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2030, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "fall", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "summer", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2025, - "winter", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1-R2", - 2025, - "spring", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "summer", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "fall", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2-R1", - 2025, - "summer", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "summer", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2030, - "winter", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2030, - "spring", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2020, - "spring", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "winter", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2025, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "fall", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2025, - "summer", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2020, - "winter", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "fall", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2025, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2030, - "spring", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2020, - "summer", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "winter", - "day", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "winter", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "spring", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "spring", - "night", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "winter", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2025, - "spring", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "spring", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "winter", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "summer", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2030, - "spring", - "day", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2025, - "winter", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "winter", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "summer", - "night", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2020, - "winter", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "summer", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "fall", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1-R2", - 2030, - "fall", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2020, - "fall", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "summer", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "spring", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2025, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2025, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2-R1", - 2025, - "spring", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ] - ], - "FlowVarAnnual_rpitvo": [], - "FlexVar_rpsditvo": [], - "FlexVarAnnual_rpitvo": [], - "CurtailmentVar_rpsditvo": [ - [ - "R1", - 2030, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ] - ], - "FlowInStorage_rpsditvo": [ - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ] - ], - "StorageLevel_rpsdtv": [ - [ - "R2", - 2030, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_BATT", - 2030 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2020, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2020, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2020, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_BATT", - 2030 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2020, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_BATT", - 2030 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_BATT", - 2030 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2020, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_BATT", - 2030 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_BATT", - 2030 - ], - [ - "R1", - 2020, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_BATT", - 2030 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2020, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_BATT", - 2030 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_BATT", - 2030 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2020, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_BATT", - 2030 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_BATT", - 2030 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_BATT", - 2030 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2020, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_BATT", - 2030 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2020, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_BATT", - 2025 - ] - ], - "CapacityVar_rptv": [ - [ - "R1", - 2020, - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2030 - ], - [ - "R1", - 2030, - "T_EV", - 2025 - ], - [ - "R1", - 2020, - "R_NGH", - 2020 - ], - [ - "R2", - 2020, - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "T_DSL", - 2030 - ], - [ - "R1", - 2025, - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "E_NGCC", - 2030 - ], - [ - "R2", - 2020, - "T_GSL", - 2020 - ], - [ - "R1", - 2025, - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "T_EV", - 2025 - ], - [ - "R1", - 2025, - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2020, - "T_EV", - 2020 - ], - [ - "R1-R2", - 2030, - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "R_NGH", - 2020 - ], - [ - "R2", - 2025, - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2020, - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "E_NGCC", - 2020 - ], - [ - "R2", - 2020, - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "R_EH", - 2020 - ], - [ - "R1", - 2020, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2025 - ], - [ - "R2", - 2020, - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "T_EV", - 2025 - ], - [ - "R1", - 2020, - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "T_DSL", - 2030 - ], - [ - "R1", - 2020, - "E_NGCC", - 2020 - ], - [ - "R1", - 2020, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "T_GSL", - 2025 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "E_NGCC", - 2030 - ], - [ - "R2-R1", - 2030, - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2030 - ], - [ - "R1", - 2020, - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2030, - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2020 - ], - [ - "R2-R1", - 2020, - "E_TRANS", - 2015 - ], - [ - "R1", - 2020, - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "T_GSL", - 2030 - ], - [ - "R1-R2", - 2020, - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "R_EH", - 2025 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "T_GSL", - 2020 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "R_EH", - 2030 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "T_GSL", - 2020 - ], - [ - "R2", - 2020, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "T_GSL", - 2025 - ], - [ - "R2", - 2025, - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "R_EH", - 2030 - ], - [ - "R2", - 2030, - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "R_NGH", - 2030 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "S_OILREF", - 2020 - ], - [ - "R2", - 2020, - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "T_EV", - 2030 - ], - [ - "R1", - 2025, - "T_EV", - 2025 - ], - [ - "R1", - 2020, - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "R_NGH", - 2020 - ], - [ - "R1-R2", - 2025, - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2030 - ], - [ - "R2", - 2030, - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "R_NGH", - 2030 - ], - [ - "R1", - 2025, - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "T_EV", - 2030 - ], - [ - "R1", - 2020, - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "T_GSL", - 2030 - ], - [ - "R2-R1", - 2025, - "E_TRANS", - 2015 - ], - [ - "R2", - 2020, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2020, - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "E_SOLPV", - 2020 - ], - [ - "R1", - 2025, - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "R_EH", - 2025 - ] - ], - "NewCapacityVar_rtv": [ - [ - "R2", - "T_BLND", - 2020 - ], - [ - "R2", - "E_BATT", - 2030 - ], - [ - "R1", - "E_BATT", - 2020 - ], - [ - "R1", - "T_EV", - 2030 - ], - [ - "R1", - "E_NGCC", - 2020 - ], - [ - "R1", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - "T_DSL", - 2020 - ], - [ - "R1", - "R_NGH", - 2020 - ], - [ - "R1", - "T_GSL", - 2030 - ], - [ - "R2", - "T_EV", - 2030 - ], - [ - "R2", - "E_NGCC", - 2020 - ], - [ - "R1", - "R_EH", - 2030 - ], - [ - "R2", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - "R_NGH", - 2020 - ], - [ - "R1", - "S_OILREF", - 2020 - ], - [ - "R1", - "E_SOLPV", - 2025 - ], - [ - "R1", - "T_DSL", - 2025 - ], - [ - "R2", - "E_BATT", - 2020 - ], - [ - "R2", - "T_GSL", - 2030 - ], - [ - "R2", - "R_EH", - 2030 - ], - [ - "R2", - "E_SOLPV", - 2025 - ], - [ - "R1", - "T_EV", - 2020 - ], - [ - "R2", - "R_NGH", - 2030 - ], - [ - "R2", - "S_OILREF", - 2020 - ], - [ - "R1", - "E_BATT", - 2025 - ], - [ - "R2", - "T_EV", - 2020 - ], - [ - "R1", - "E_NGCC", - 2025 - ], - [ - "R1", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - "T_GSL", - 2020 - ], - [ - "R2", - "T_DSL", - 2025 - ], - [ - "R1", - "R_EH", - 2020 - ], - [ - "R1", - "R_NGH", - 2025 - ], - [ - "R2", - "T_GSL", - 2020 - ], - [ - "R2", - "E_NGCC", - 2025 - ], - [ - "R2", - "R_EH", - 2020 - ], - [ - "R2", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - "R_NGH", - 2025 - ], - [ - "R1", - "E_SOLPV", - 2030 - ], - [ - "R1", - "T_DSL", - 2030 - ], - [ - "R2", - "E_BATT", - 2025 - ], - [ - "R2", - "E_SOLPV", - 2030 - ], - [ - "R1", - "T_EV", - 2025 - ], - [ - "R1", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - "E_BATT", - 2030 - ], - [ - "R1", - "T_GSL", - 2025 - ], - [ - "R2", - "T_EV", - 2025 - ], - [ - "R1", - "E_NGCC", - 2030 - ], - [ - "R1", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - "E_NUCLEAR", - 2015 - ], - [ - "R2-R1", - "E_TRANS", - 2015 - ], - [ - "R2", - "T_DSL", - 2030 - ], - [ - "R1", - "R_EH", - 2025 - ], - [ - "R1", - "R_NGH", - 2030 - ], - [ - "R1", - "E_SOLPV", - 2020 - ], - [ - "R1", - "T_DSL", - 2020 - ], - [ - "R2", - "T_GSL", - 2025 - ], - [ - "R2", - "E_NGCC", - 2030 - ], - [ - "R2", - "R_EH", - 2025 - ], - [ - "R2", - "E_NUCLEAR", - 2030 - ], - [ - "R1-R2", - "E_TRANS", - 2015 - ], - [ - "R1", - "T_BLND", - 2020 - ], - [ - "R2", - "E_SOLPV", - 2020 - ] - ], - "RetiredCapacityVar_rptv": [], - "AnnualRetirementVar_rptv": [ - [ - "R2", - 2030, - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "T_GSL", - 2020 - ] - ], - "CapacityAvailableVar_rpt": [ - [ - "R1-R2", - 2025, - "E_TRANS" - ], - [ - "R2", - 2025, - "E_SOLPV" - ], - [ - "R1", - 2030, - "E_NGCC" - ], - [ - "R2", - 2030, - "R_EH" - ], - [ - "R2", - 2025, - "E_BATT" - ], - [ - "R2", - 2030, - "T_EV" - ], - [ - "R1", - 2020, - "S_OILREF" - ], - [ - "R1", - 2025, - "T_EV" - ], - [ - "R2", - 2030, - "E_NUCLEAR" - ], - [ - "R2", - 2025, - "T_DSL" - ], - [ - "R1", - 2025, - "E_NUCLEAR" - ], - [ - "R2-R1", - 2025, - "E_TRANS" - ], - [ - "R1", - 2025, - "R_EH" - ], - [ - "R1", - 2020, - "T_GSL" - ], - [ - "R2", - 2025, - "T_BLND" - ], - [ - "R2", - 2020, - "S_OILREF" - ], - [ - "R1", - 2030, - "R_NGH" - ], - [ - "R2", - 2020, - "T_GSL" - ], - [ - "R1", - 2020, - "E_BATT" - ], - [ - "R1", - 2020, - "E_SOLPV" - ], - [ - "R1", - 2020, - "T_DSL" - ], - [ - "R1-R2", - 2020, - "E_TRANS" - ], - [ - "R2", - 2030, - "E_NGCC" - ], - [ - "R2", - 2020, - "E_SOLPV" - ], - [ - "R1", - 2025, - "E_NGCC" - ], - [ - "R1", - 2020, - "T_BLND" - ], - [ - "R2", - 2020, - "E_BATT" - ], - [ - "R2", - 2025, - "T_EV" - ], - [ - "R2-R1", - 2020, - "E_TRANS" - ], - [ - "R2", - 2025, - "E_NUCLEAR" - ], - [ - "R2", - 2020, - "T_DSL" - ], - [ - "R2", - 2025, - "R_EH" - ], - [ - "R1", - 2030, - "S_OILREF" - ], - [ - "R2", - 2020, - "T_BLND" - ], - [ - "R2", - 2030, - "R_NGH" - ], - [ - "R1", - 2030, - "T_GSL" - ], - [ - "R1", - 2025, - "R_NGH" - ], - [ - "R1", - 2020, - "T_EV" - ], - [ - "R1", - 2030, - "E_SOLPV" - ], - [ - "R1", - 2020, - "R_EH" - ], - [ - "R2", - 2025, - "E_NGCC" - ], - [ - "R1", - 2020, - "E_NUCLEAR" - ], - [ - "R1", - 2030, - "E_BATT" - ], - [ - "R2", - 2020, - "R_EH" - ], - [ - "R2", - 2020, - "T_EV" - ], - [ - "R1", - 2030, - "T_DSL" - ], - [ - "R2", - 2020, - "E_NUCLEAR" - ], - [ - "R2", - 2030, - "S_OILREF" - ], - [ - "R1", - 2030, - "T_BLND" - ], - [ - "R1", - 2025, - "S_OILREF" - ], - [ - "R2", - 2030, - "T_GSL" - ], - [ - "R1", - 2020, - "E_NGCC" - ], - [ - "R1", - 2025, - "T_GSL" - ], - [ - "R2", - 2025, - "R_NGH" - ], - [ - "R1-R2", - 2030, - "E_TRANS" - ], - [ - "R2", - 2030, - "E_SOLPV" - ], - [ - "R1", - 2025, - "E_SOLPV" - ], - [ - "R2", - 2030, - "E_BATT" - ], - [ - "R2", - 2020, - "E_NGCC" - ], - [ - "R2-R1", - 2030, - "E_TRANS" - ], - [ - "R1", - 2025, - "E_BATT" - ], - [ - "R1", - 2030, - "T_EV" - ], - [ - "R2", - 2030, - "T_DSL" - ], - [ - "R1", - 2030, - "E_NUCLEAR" - ], - [ - "R1", - 2025, - "T_DSL" - ], - [ - "R1", - 2030, - "R_EH" - ], - [ - "R2", - 2030, - "T_BLND" - ], - [ - "R1", - 2020, - "R_NGH" - ], - [ - "R1", - 2025, - "T_BLND" - ], - [ - "R2", - 2025, - "S_OILREF" - ], - [ - "R2", - 2025, - "T_GSL" - ], - [ - "R2", - 2020, - "R_NGH" - ] - ], - "CapacityConstraint_rpsdtv": [ - [ - "R2", - 2020, - "fall", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "summer", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "T_DSL", - 2030 - ], - [ - "R2", - 2030, - "winter", - "night", - "T_GSL", - 2025 - ], - [ - "R2", - 2020, - "summer", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2020, - "spring", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "fall", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "R_EH", - 2025 - ], - [ - "R1", - 2025, - "winter", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NGCC", - 2030 - ], - [ - "R2", - 2030, - "spring", - "night", - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "spring", - "night", - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "summer", - "day", - "T_EV", - 2025 - ], - [ - "R2", - 2025, - "summer", - "night", - "T_DSL", - 2025 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "summer", - "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1-R2", - 2025, - "spring", - "day", - "E_TRANS", - 2015 - ], - [ - "R2-R1", - 2020, - "summer", - "day", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NGCC", - 2030 - ], - [ - "R2", - 2020, - "winter", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "summer", - "day", - "T_EV", - 2030 - ], - [ - "R2", - 2020, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2020, - "winter", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "T_DSL", - 2030 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "T_DSL", - 2030 - ], - [ - "R1-R2", - 2030, - "summer", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", - 2020, - "spring", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "T_DSL", - 2025 - ], - [ - "R2", - 2025, - "summer", - "day", - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "spring", - "day", - "R_EH", - 2025 - ], - [ - "R2", - 2020, - "summer", - "night", - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "winter", - "day", - "R_EH", - 2025 - ], - [ - "R1", - 2030, - "summer", - "day", - "R_EH", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "fall", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "R_NGH", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "R_NGH", - 2025 - ], - [ - "R1", - 2025, - "fall", - "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "summer", - "night", - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2020, - "winter", - "day", - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "T_EV", - 2030 - ], - [ - "R2", - 2025, - "summer", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_SOLPV", - 2030 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_SOLPV", - 2030 - ], - [ - "R1", - 2030, - "spring", - "day", - "T_EV", - 2030 - ], - [ - "R1", - 2020, - "winter", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NGCC", - 2025 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "winter", - "day", - "R_EH", - 2030 - ], - [ - "R2", - 2020, - "spring", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "T_EV", - 2025 - ], - [ - "R2", - 2020, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2020, - "fall", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "T_EV", - 2030 - ], - [ - "R1", - 2030, - "spring", - "day", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "fall", - "day", - "T_GSL", - 2030 - ], - [ - "R2", - 2030, - "fall", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "winter", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2020, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2020, - "spring", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "fall", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "R_NGH", - 2030 - ], - [ - "R1", - 2025, - "winter", - "day", - "R_EH", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "winter", - "night", - "T_GSL", - 2025 - ], - [ - "R2", - 2025, - "spring", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "T_DSL", - 2025 - ], - [ - "R2", - 2020, - "summer", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "winter", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_SOLPV", - 2030 - ], - [ - "R2", - 2020, - "spring", - "day", - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "T_EV", - 2025 - ], - [ - "R2", - 2025, - "summer", - "night", - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2020, - "summer", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "R_NGH", - 2020 - ], - [ - "R1-R2", - 2030, - "spring", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "spring", - "day", - "T_EV", - 2025 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "T_EV", - 2025 - ], - [ - "R2", - 2030, - "winter", - "day", - "R_EH", - 2025 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "summer", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "summer", - "day", - "T_GSL", - 2030 - ], - [ - "R1", - 2030, - "summer", - "day", - "T_DSL", - 2020 - ], - [ - "R1", - 2020, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "summer", - "night", - "T_EV", - 2025 - ], - [ - "R1-R2", - 2020, - "summer", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "summer", - "day", - "T_GSL", - 2030 - ], - [ - "R2", - 2030, - "summer", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "fall", - "day", - "T_GSL", - 2025 - ], - [ - "R2", - 2025, - "winter", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2020, - "summer", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "T_DSL", - 2025 - ], - [ - "R1", - 2030, - "spring", - "day", - "T_DSL", - 2030 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "winter", - "day", - "R_NGH", - 2025 - ], - [ - "R1", - 2020, - "summer", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2020, - "summer", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2020, - "summer", - "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "R_EH", - 2025 - ], - [ - "R2", - 2025, - "winter", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "winter", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "T_DSL", - 2030 - ], - [ - "R1", - 2025, - "winter", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2025, - "summer", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_NGCC", - 2025 - ], - [ - "R2", - 2020, - "winter", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "spring", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2020, - "fall", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "T_EV", - 2025 - ], - [ - "R1", - 2020, - "fall", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "T_GSL", - 2025 - ], - [ - "R2", - 2025, - "spring", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "T_DSL", - 2020 - ], - [ - "R2-R1", - 2030, - "spring", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "spring", - "day", - "T_DSL", - 2025 - ], - [ - "R2", - 2020, - "summer", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "T_DSL", - 2025 - ], - [ - "R1-R2", - 2025, - "fall", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "spring", - "night", - "T_DSL", - 2030 - ], - [ - "R2", - 2030, - "fall", - "night", - "R_NGH", - 2030 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_SOLPV", - 2030 - ], - [ - "R2", - 2025, - "fall", - "night", - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "T_GSL", - 2025 - ], - [ - "R2", - 2025, - "fall", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "winter", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "T_DSL", - 2025 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2020, - "winter", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "T_EV", - 2025 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2-R1", - 2030, - "fall", - "day", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "spring", - "night", - "T_EV", - 2020 - ], - [ - "R1-R2", - 2030, - "winter", - "day", - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "fall", - "night", - "T_EV", - 2025 - ], - [ - "R1", - 2020, - "winter", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "spring", - "day", - "R_EH", - 2020 - ], - [ - "R2-R1", - 2020, - "fall", - "day", - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "winter", - "day", - "R_EH", - 2025 - ], - [ - "R2", - 2020, - "winter", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_SOLPV", - 2030 - ], - [ - "R2", - 2025, - "spring", - "night", - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "spring", - "day", - "T_GSL", - 2030 - ], - [ - "R1", - 2030, - "spring", - "day", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "R_NGH", - 2030 - ], - [ - "R1", - 2025, - "summer", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "winter", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "fall", - "night", - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "fall", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_SOLPV", - 2030 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "T_GSL", - 2030 - ], - [ - "R2", - 2030, - "summer", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "R_NGH", - 2030 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "fall", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "T_EV", - 2030 - ], - [ - "R2", - 2020, - "summer", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "spring", - "day", - "R_NGH", - 2025 - ], - [ - "R2", - 2025, - "fall", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "T_DSL", - 2025 - ], - [ - "R2", - 2025, - "winter", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "T_DSL", - 2025 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2025, - "spring", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2020, - "summer", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "T_GSL", - 2030 - ], - [ - "R1", - 2030, - "spring", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "summer", - "night", - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "spring", - "night", - "T_GSL", - 2030 - ], - [ - "R2", - 2030, - "spring", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "R_NGH", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2025, - "fall", - "night", - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "spring", - "night", - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "T_GSL", - 2025 - ], - [ - "R2-R1", - 2025, - "summer", - "day", - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2025, - "winter", - "day", - "T_EV", - 2025 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "T_EV", - 2025 - ], - [ - "R1-R2", - 2020, - "winter", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2020, - "winter", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2020, - "winter", - "night", - "T_GSL", - 2020 - ], - [ - "R1-R2", - 2030, - "fall", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "spring", - "day", - "R_NGH", - 2020 - ], - [ - "R1-R2", - 2025, - "summer", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", - 2020, - "spring", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2020, - "fall", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "spring", - "day", - "R_NGH", - 2030 - ], - [ - "R2", - 2030, - "winter", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "T_DSL", - 2030 - ], - [ - "R1", - 2030, - "spring", - "night", - "T_GSL", - 2025 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "T_GSL", - 2025 - ], - [ - "R2", - 2025, - "fall", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2020, - "spring", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_SOLPV", - 2030 - ], - [ - "R1", - 2030, - "fall", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_SOLPV", - 2030 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2030, - "winter", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "R_EH", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "T_EV", - 2030 - ], - [ - "R2", - 2030, - "fall", - "night", - "T_EV", - 2030 - ], - [ - "R2", - 2025, - "spring", - "day", - "R_EH", - 2025 - ], - [ - "R2", - 2020, - "summer", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "R_EH", - 2030 - ], - [ - "R2", - 2030, - "winter", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "R_NGH", - 2025 - ], - [ - "R2", - 2025, - "winter", - "day", - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "spring", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "fall", - "night", - "R_EH", - 2030 - ], - [ - "R2", - 2020, - "winter", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2020, - "spring", - "day", - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "T_DSL", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "summer", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "T_GSL", - 2025 - ], - [ - "R1-R2", - 2020, - "fall", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2020, - "winter", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2030, - "summer", - "night", - "T_EV", - 2030 - ], - [ - "R1-R2", - 2030, - "summer", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "fall", - "night", - "T_EV", - 2025 - ], - [ - "R1", - 2025, - "spring", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "T_EV", - 2025 - ], - [ - "R2-R1", - 2025, - "fall", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "summer", - "night", - "R_EH", - 2030 - ], - [ - "R2", - 2030, - "spring", - "day", - "R_EH", - 2030 - ], - [ - "R1", - 2020, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "R_EH", - 2025 - ], - [ - "R2", - 2025, - "winter", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "fall", - "night", - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "T_GSL", - 2030 - ], - [ - "R1", - 2030, - "winter", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2020, - "fall", - "day", - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2020, - "summer", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "T_EV", - 2025 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NGCC", - 2025 - ], - [ - "R2", - 2025, - "fall", - "night", - "S_OILREF", - 2020 - ], - [ - "R2-R1", - 2025, - "spring", - "night", - "E_TRANS", - 2015 - ], - [ - "R2-R1", - 2030, - "summer", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "T_EV", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2020, - "fall", - "night", - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2020, - "winter", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "R_EH", - 2025 - ], - [ - "R1", - 2020, - "summer", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "R_EH", - 2025 - ], - [ - "R1", - 2020, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "T_GSL", - 2025 - ], - [ - "R2", - 2025, - "spring", - "day", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "fall", - "night", - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "T_GSL", - 2025 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "R_NGH", - 2025 - ], - [ - "R1", - 2025, - "summer", - "night", - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NGCC", - 2030 - ], - [ - "R1", - 2020, - "fall", - "night", - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NGCC", - 2030 - ], - [ - "R2", - 2025, - "fall", - "night", - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "spring", - "day", - "T_EV", - 2030 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_SOLPV", - 2030 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "T_EV", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "summer", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2020, - "winter", - "night", - "E_NGCC", - 2020 - ], - [ - "R2-R1", - 2025, - "winter", - "night", - "E_TRANS", - 2015 - ], - [ - "R1-R2", - 2025, - "winter", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "spring", - "day", - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "fall", - "day", - "R_NGH", - 2025 - ], - [ - "R2", - 2025, - "spring", - "day", - "T_DSL", - 2025 - ], - [ - "R1", - 2030, - "winter", - "night", - "R_EH", - 2030 - ], - [ - "R2", - 2020, - "spring", - "day", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "R_EH", - 2020 - ], - [ - "R2", - 2020, - "fall", - "night", - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "R_EH", - 2020 - ], - [ - "R1", - 2020, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "T_DSL", - 2030 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "T_DSL", - 2030 - ], - [ - "R1", - 2020, - "summer", - "day", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "fall", - "night", - "T_GSL", - 2030 - ], - [ - "R1", - 2030, - "winter", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_SOLPV", - 2030 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NGCC", - 2025 - ], - [ - "R1", - 2020, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NGCC", - 2025 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "T_EV", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "spring", - "day", - "T_EV", - 2020 - ], - [ - "R2", - 2020, - "fall", - "night", - "E_NGCC", - 2020 - ], - [ - "R2-R1", - 2020, - "summer", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "spring", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "R_EH", - 2025 - ], - [ - "R1", - 2030, - "fall", - "day", - "R_NGH", - 2030 - ], - [ - "R2", - 2030, - "fall", - "day", - "R_NGH", - 2030 - ], - [ - "R1", - 2030, - "fall", - "night", - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "fall", - "night", - "T_DSL", - 2025 - ], - [ - "R2-R1", - 2020, - "spring", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "fall", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "T_GSL", - 2025 - ], - [ - "R1", - 2025, - "winter", - "night", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NGCC", - 2020 - ], - [ - "R1", - 2020, - "summer", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2020, - "winter", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2020, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "spring", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_SOLPV", - 2030 - ], - [ - "R1", - 2020, - "spring", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2020, - "spring", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "R_EH", - 2025 - ], - [ - "R1", - 2025, - "spring", - "day", - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "winter", - "day", - "T_DSL", - 2030 - ], - [ - "R1", - 2020, - "summer", - "day", - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "T_GSL", - 2025 - ], - [ - "R1", - 2020, - "summer", - "day", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_SOLPV", - 2030 - ], - [ - "R2", - 2020, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "winter", - "day", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "T_GSL", - 2030 - ], - [ - "R2", - 2030, - "fall", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "R_NGH", - 2025 - ], - [ - "R1", - 2020, - "fall", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NGCC", - 2030 - ], - [ - "R2-R1", - 2030, - "winter", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2020, - "fall", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NGCC", - 2030 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_SOLPV", - 2025 - ], - [ - "R2-R1", - 2020, - "winter", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_SOLPV", - 2030 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_NGCC", - 2025 - ], - [ - "R2", - 2020, - "spring", - "night", - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2020, - "spring", - "day", - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "summer", - "night", - "T_EV", - 2025 - ], - [ - "R1", - 2025, - "fall", - "day", - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "spring", - "day", - "T_DSL", - 2030 - ], - [ - "R2", - 2025, - "spring", - "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2020, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_SOLPV", - 2030 - ], - [ - "R2", - 2030, - "spring", - "day", - "T_GSL", - 2030 - ], - [ - "R1", - 2025, - "summer", - "night", - "R_EH", - 2025 - ], - [ - "R1", - 2030, - "fall", - "day", - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2025, - "winter", - "night", - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "fall", - "night", - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "fall", - "day", - "T_EV", - 2030 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1-R2", - 2020, - "spring", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NGCC", - 2030 - ], - [ - "R1", - 2025, - "fall", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "T_EV", - 2025 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "fall", - "day", - "R_EH", - 2030 - ], - [ - "R2", - 2020, - "spring", - "day", - "T_EV", - 2020 - ], - [ - "R1-R2", - 2030, - "winter", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "T_EV", - 2020 - ], - [ - "R1-R2", - 2025, - "summer", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "R_EH", - 2025 - ], - [ - "R1", - 2025, - "summer", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "T_GSL", - 2030 - ], - [ - "R2", - 2030, - "winter", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "T_DSL", - 2025 - ], - [ - "R1", - 2020, - "fall", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2020, - "summer", - "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2020, - "fall", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "spring", - "day", - "T_GSL", - 2025 - ], - [ - "R2", - 2020, - "winter", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2020, - "winter", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NGCC", - 2030 - ], - [ - "R2", - 2020, - "winter", - "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2-R1", - 2030, - "spring", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NGCC", - 2025 - ], - [ - "R1", - 2025, - "fall", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2020, - "fall", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "T_EV", - 2030 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_NGCC", - 2025 - ], - [ - "R1", - 2020, - "fall", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "winter", - "night", - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "R_EH", - 2030 - ], - [ - "R2", - 2025, - "fall", - "day", - "R_NGH", - 2025 - ], - [ - "R2", - 2025, - "fall", - "day", - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "winter", - "day", - "T_GSL", - 2025 - ], - [ - "R2-R1", - 2030, - "winter", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "spring", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "spring", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "fall", - "day", - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "R_EH", - 2025 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2020, - "fall", - "night", - "S_OILREF", - 2020 - ], - [ - "R1-R2", - 2020, - "fall", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NGCC", - 2030 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_NGCC", - 2025 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "winter", - "night", - "T_EV", - 2025 - ], - [ - "R1", - 2020, - "summer", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2020, - "summer", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_NGCC", - 2025 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "T_EV", - 2025 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2020, - "fall", - "day", - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "fall", - "day", - "R_EH", - 2025 - ], - [ - "R1", - 2025, - "fall", - "night", - "T_EV", - 2025 - ], - [ - "R2", - 2025, - "fall", - "day", - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "T_DSL", - 2020 - ], - [ - "R1", - 2020, - "spring", - "day", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "R_NGH", - 2030 - ], - [ - "R1", - 2025, - "fall", - "night", - "R_EH", - 2025 - ], - [ - "R1", - 2025, - "winter", - "night", - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "R_NGH", - 2030 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "spring", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NGCC", - 2030 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "summer", - "night", - "T_GSL", - 2025 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "R_EH", - 2030 - ], - [ - "R2", - 2020, - "summer", - "night", - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "T_EV", - 2025 - ], - [ - "R2-R1", - 2025, - "summer", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "T_DSL", - 2025 - ], - [ - "R1", - 2030, - "fall", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2020, - "fall", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "R_EH", - 2030 - ], - [ - "R2", - 2020, - "winter", - "night", - "R_NGH", - 2020 - ], - [ - "R2", - 2020, - "spring", - "night", - "S_OILREF", - 2020 - ], - [ - "R2", - 2020, - "spring", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2020, - "spring", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "fall", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "R_NGH", - 2030 - ], - [ - "R1", - 2020, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "fall", - "night", - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "R_NGH", - 2025 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "winter", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2020, - "fall", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NGCC", - 2025 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_NGCC", - 2025 - ], - [ - "R2", - 2020, - "fall", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "winter", - "night", - "T_EV", - 2020 - ], - [ - "R2-R1", - 2025, - "fall", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", - 2020, - "spring", - "day", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "R_EH", - 2030 - ], - [ - "R1", - 2020, - "winter", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "R_EH", - 2030 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1-R2", - 2020, - "summer", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2020, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "fall", - "day", - "T_DSL", - 2030 - ], - [ - "R1", - 2025, - "spring", - "night", - "R_EH", - 2025 - ], - [ - "R1", - 2025, - "fall", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "R_EH", - 2025 - ], - [ - "R1", - 2025, - "summer", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2020, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "summer", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "R_NGH", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "T_DSL", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2025, - "summer", - "night", - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2020, - "winter", - "night", - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "T_EV", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NGCC", - 2030 - ], - [ - "R2", - 2020, - "fall", - "day", - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NGCC", - 2030 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "R_EH", - 2025 - ], - [ - "R2", - 2020, - "fall", - "day", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "R_EH", - 2025 - ], - [ - "R1", - 2020, - "fall", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "summer", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "fall", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2020, - "winter", - "night", - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "R_EH", - 2020 - ], - [ - "R2-R1", - 2020, - "spring", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "fall", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "R_EH", - 2020 - ], - [ - "R1-R2", - 2025, - "fall", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "summer", - "night", - "T_DSL", - 2030 - ], - [ - "R1", - 2025, - "winter", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2025, - "summer", - "day", - "T_EV", - 2025 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2020, - "fall", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "T_EV", - 2030 - ], - [ - "R1", - 2030, - "summer", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "fall", - "night", - "T_GSL", - 2025 - ], - [ - "R2", - 2025, - "fall", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "T_EV", - 2025 - ], - [ - "R1", - 2025, - "summer", - "day", - "R_EH", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NGCC", - 2025 - ], - [ - "R2", - 2025, - "spring", - "night", - "T_EV", - 2025 - ], - [ - "R2", - 2025, - "summer", - "day", - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NGCC", - 2025 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "winter", - "night", - "T_EV", - 2030 - ], - [ - "R2", - 2025, - "fall", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2020, - "fall", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "T_EV", - 2030 - ], - [ - "R1", - 2020, - "spring", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2020, - "spring", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "T_GSL", - 2030 - ], - [ - "R2", - 2020, - "summer", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "R_EH", - 2030 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2025, - "summer", - "night", - "R_NGH", - 2025 - ], - [ - "R1", - 2020, - "summer", - "night", - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "R_EH", - 2020 - ], - [ - "R2", - 2020, - "winter", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "winter", - "night", - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "fall", - "day", - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2-R1", - 2020, - "winter", - "day", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1-R2", - 2030, - "fall", - "day", - "E_TRANS", - 2015 - ], - [ - "R2", - 2020, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2020, - "winter", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2020, - "fall", - "day", - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "summer", - "day", - "R_NGH", - 2030 - ], - [ - "R2", - 2020, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "T_EV", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "T_EV", - 2030 - ], - [ - "R2", - 2020, - "fall", - "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "T_EV", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "R_EH", - 2030 - ], - [ - "R1", - 2030, - "spring", - "night", - "T_DSL", - 2030 - ], - [ - "R1", - 2020, - "summer", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2020, - "summer", - "day", - "R_NGH", - 2020 - ], - [ - "R1-R2", - 2030, - "spring", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_NGCC", - 2025 - ], - [ - "R1-R2", - 2025, - "winter", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "spring", - "night", - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "R_EH", - 2025 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "T_DSL", - 2030 - ], - [ - "R1", - 2030, - "summer", - "night", - "T_GSL", - 2030 - ], - [ - "R1", - 2030, - "summer", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "fall", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2020, - "spring", - "night", - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "summer", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2020, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1-R2", - 2025, - "spring", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NGCC", - 2030 - ], - [ - "R1", - 2020, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "T_DSL", - 2030 - ], - [ - "R1", - 2020, - "summer", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "T_EV", - 2025 - ], - [ - "R1", - 2030, - "winter", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "T_DSL", - 2025 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "R_EH", - 2025 - ], - [ - "R2", - 2020, - "spring", - "night", - "R_EH", - 2020 - ], - [ - "R2-R1", - 2020, - "fall", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "fall", - "day", - "T_GSL", - 2025 - ], - [ - "R2", - 2020, - "winter", - "day", - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "R_NGH", - 2030 - ], - [ - "R2", - 2020, - "winter", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "S_OILREF", - 2020 - ], - [ - "R1", - 2020, - "winter", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "R_EH", - 2025 - ], - [ - "R2", - 2020, - "fall", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2030, - "winter", - "night", - "T_DSL", - 2025 - ], - [ - "R1", - 2030, - "summer", - "night", - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "fall", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NGCC", - 2030 - ], - [ - "R1", - 2025, - "spring", - "night", - "S_OILREF", - 2020 - ], - [ - "R2", - 2020, - "summer", - "day", - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "fall", - "day", - "T_EV", - 2025 - ], - [ - "R2", - 2020, - "summer", - "night", - "S_OILREF", - 2020 - ], - [ - "R2", - 2020, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "summer", - "day", - "R_EH", - 2030 - ], - [ - "R2", - 2030, - "winter", - "day", - "R_NGH", - 2030 - ], - [ - "R1", - 2020, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "fall", - "day", - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "T_DSL", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "R_NGH", - 2030 - ], - [ - "R2", - 2025, - "fall", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "R_NGH", - 2025 - ], - [ - "R2", - 2020, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2-R1", - 2025, - "spring", - "day", - "E_TRANS", - 2015 - ], - [ - "R2", - 2020, - "spring", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "R_NGH", - 2030 - ], - [ - "R2", - 2025, - "summer", - "night", - "R_EH", - 2020 - ], - [ - "R2-R1", - 2030, - "fall", - "night", - "E_TRANS", - 2015 - ], - [ - "R1-R2", - 2020, - "spring", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_SOLPV", - 2030 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "winter", - "night", - "T_GSL", - 2030 - ], - [ - "R1", - 2030, - "winter", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2020, - "summer", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_SOLPV", - 2030 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2020, - "fall", - "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NGCC", - 2025 - ], - [ - "R2", - 2020, - "spring", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "fall", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2020, - "winter", - "day", - "E_NGCC", - 2020 - ], - [ - "R2", - 2020, - "summer", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2020, - "winter", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NGCC", - 2030 - ], - [ - "R2", - 2030, - "summer", - "day", - "R_EH", - 2025 - ], - [ - "R2", - 2025, - "summer", - "night", - "T_EV", - 2025 - ], - [ - "R2", - 2030, - "fall", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "T_GSL", - 2030 - ], - [ - "R2", - 2030, - "winter", - "night", - "T_DSL", - 2020 - ], - [ - "R1-R2", - 2020, - "winter", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "spring", - "day", - "R_NGH", - 2025 - ], - [ - "R1", - 2025, - "summer", - "day", - "S_OILREF", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "R_EH", - 2030 - ], - [ - "R1", - 2025, - "winter", - "day", - "R_NGH", - 2025 - ], - [ - "R2", - 2025, - "summer", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "R_NGH", - 2030 - ], - [ - "R1", - 2030, - "summer", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2020, - "summer", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "winter", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "winter", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2025, - "spring", - "night", - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "R_NGH", - 2025 - ], - [ - "R1", - 2025, - "winter", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "T_EV", - 2030 - ], - [ - "R2", - 2025, - "spring", - "night", - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "T_GSL", - 2025 - ], - [ - "R2", - 2025, - "winter", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NGCC", - 2020 - ], - [ - "R2-R1", - 2025, - "winter", - "day", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NGCC", - 2025 - ], - [ - "R2", - 2020, - "summer", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "R_EH", - 2020 - ], - [ - "R2-R1", - 2030, - "summer", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2020, - "winter", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NGCC", - 2030 - ] - ], - "CapacityAnnualConstraint_rptv": [], - "commodity_waste": [], - "tech_exist": [ - "E_NUCLEAR", - "E_TRANS" - ], - "operator": [], - "DegrowthCapacityConstraint_rtpop": [], - "DegrowthNewCapacityConstraint_rtpop": [], - "DegrowthNewCapacityDeltaConstraint_rtpop": [], - "GrowthCapacityConstraint_rtpop": [], - "GrowthNewCapacityConstraint_rtpop": [], - "GrowthNewCapacityDeltaConstraint_rtpop": [], - "DemandConstraint_rpsdc": [ - [ - "R2", - 2020, - "summer", - "night", - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "RH" - ], - [ - "R1", - 2025, - "fall", - "day", - "RH" - ], - [ - "R1", - 2020, - "fall", - "day", - "RH" - ], - [ - "R2", - 2020, - "fall", - "night", - "RH" - ], - [ - "R1", - 2025, - "spring", - "night", - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "RH" - ], - [ - "R1", - 2020, - "spring", - "night", - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "RH" - ], - [ - "R1", - 2030, - "winter", - "night", - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "VMT" - ], - [ - "R2", - 2030, - "fall", - "day", - "VMT" - ], - [ - "R2", - 2025, - "winter", - "day", - "RH" - ], - [ - "R1", - 2020, - "summer", - "night", - "VMT" - ], - [ - "R1", - 2025, - "fall", - "day", - "VMT" - ], - [ - "R2", - 2025, - "summer", - "night", - "RH" - ], - [ - "R2", - 2020, - "spring", - "day", - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "RH" - ], - [ - "R1", - 2025, - "winter", - "day", - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "RH" - ], - [ - "R2", - 2030, - "winter", - "day", - "RH" - ], - [ - "R1", - 2025, - "fall", - "night", - "RH" - ], - [ - "R1", - 2020, - "fall", - "night", - "RH" - ], - [ - "R1", - 2030, - "spring", - "night", - "RH" - ], - [ - "R1", - 2030, - "summer", - "night", - "VMT" - ], - [ - "R1", - 2025, - "winter", - "night", - "RH" - ], - [ - "R2", - 2025, - "winter", - "night", - "RH" - ], - [ - "R2", - 2030, - "spring", - "day", - "VMT" - ], - [ - "R2", - 2020, - "spring", - "night", - "VMT" - ], - [ - "R2", - 2025, - "spring", - "day", - "RH" - ], - [ - "R1", - 2030, - "fall", - "night", - "RH" - ], - [ - "R2", - 2025, - "summer", - "day", - "VMT" - ], - [ - "R1", - 2025, - "winter", - "night", - "VMT" - ], - [ - "R2", - 2020, - "winter", - "day", - "RH" - ], - [ - "R2", - 2030, - "summer", - "day", - "RH" - ], - [ - "R2", - 2020, - "summer", - "night", - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "RH" - ], - [ - "R1", - 2020, - "fall", - "day", - "VMT" - ], - [ - "R2", - 2025, - "fall", - "day", - "RH" - ], - [ - "R2", - 2020, - "fall", - "night", - "VMT" - ], - [ - "R2", - 2020, - "winter", - "day", - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "VMT" - ], - [ - "R2", - 2025, - "winter", - "day", - "VMT" - ], - [ - "R1", - 2020, - "winter", - "night", - "RH" - ], - [ - "R2", - 2025, - "spring", - "night", - "RH" - ], - [ - "R2", - 2025, - "summer", - "night", - "VMT" - ], - [ - "R2", - 2020, - "winter", - "night", - "RH" - ], - [ - "R1", - 2030, - "fall", - "day", - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "VMT" - ], - [ - "R1", - 2020, - "winter", - "day", - "RH" - ], - [ - "R2", - 2030, - "winter", - "day", - "VMT" - ], - [ - "R1", - 2025, - "fall", - "night", - "VMT" - ], - [ - "R1", - 2020, - "fall", - "night", - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "RH" - ], - [ - "R1", - 2030, - "spring", - "night", - "VMT" - ], - [ - "R1", - 2025, - "spring", - "day", - "RH" - ], - [ - "R1", - 2020, - "spring", - "day", - "RH" - ], - [ - "R1", - 2030, - "winter", - "day", - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "RH" - ], - [ - "R2", - 2025, - "winter", - "night", - "VMT" - ], - [ - "R1", - 2020, - "summer", - "day", - "RH" - ], - [ - "R2", - 2025, - "spring", - "day", - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "VMT" - ], - [ - "R2", - 2030, - "winter", - "night", - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "VMT" - ], - [ - "R1", - 2025, - "spring", - "night", - "RH" - ], - [ - "R1", - 2020, - "spring", - "night", - "RH" - ], - [ - "R1", - 2030, - "winter", - "night", - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "RH" - ], - [ - "R2", - 2025, - "fall", - "day", - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "RH" - ], - [ - "R1", - 2025, - "summer", - "night", - "RH" - ], - [ - "R1", - 2020, - "summer", - "night", - "RH" - ], - [ - "R1", - 2020, - "winter", - "night", - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "VMT" - ], - [ - "R2", - 2020, - "spring", - "day", - "RH" - ], - [ - "R2", - 2020, - "winter", - "night", - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "VMT" - ], - [ - "R1", - 2025, - "winter", - "day", - "RH" - ], - [ - "R1", - 2020, - "winter", - "day", - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "VMT" - ], - [ - "R2", - 2020, - "summer", - "day", - "RH" - ], - [ - "R1", - 2030, - "summer", - "night", - "RH" - ], - [ - "R2", - 2025, - "fall", - "night", - "VMT" - ], - [ - "R2", - 2020, - "fall", - "day", - "RH" - ], - [ - "R1", - 2025, - "spring", - "day", - "VMT" - ], - [ - "R1", - 2020, - "spring", - "day", - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "RH" - ], - [ - "R1", - 2030, - "winter", - "day", - "VMT" - ], - [ - "R2", - 2020, - "summer", - "day", - "VMT" - ], - [ - "R2", - 2020, - "spring", - "night", - "RH" - ], - [ - "R1", - 2020, - "summer", - "day", - "VMT" - ], - [ - "R2", - 2025, - "summer", - "day", - "RH" - ], - [ - "R2", - 2020, - "fall", - "day", - "VMT" - ] - ], - "DemandActivityConstraint_rpsdtv_dem_s0d0": [ - [ - "R1", - 2020, - "spring", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "summer", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "summer", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "fall", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "fall", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "winter", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "winter", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "spring", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "summer", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "summer", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "fall", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "fall", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "winter", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "winter", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "spring", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "summer", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "summer", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "fall", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "fall", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "winter", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "winter", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "spring", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "summer", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "summer", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "fall", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "fall", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "winter", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "winter", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "spring", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "spring", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "spring", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "summer", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "summer", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "fall", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "fall", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "winter", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "winter", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "spring", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "spring", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "spring", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "summer", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "summer", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "fall", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "fall", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "winter", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "winter", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "spring", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "summer", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "summer", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "fall", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "fall", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "winter", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "winter", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "spring", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "summer", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "summer", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "fall", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "fall", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "winter", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "winter", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "spring", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "summer", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "summer", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "fall", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "fall", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "winter", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "winter", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "spring", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "spring", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "spring", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "summer", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "summer", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "fall", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "fall", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "winter", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "winter", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "spring", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "spring", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ] - ], - "CommodityBalanceConstraint_rpsdc": [ - [ - "R2", - 2025, - "winter", - "night", - "E10" - ], - [ - "R1", - 2020, - "fall", - "day", - "ELC" - ], - [ - "R2", - 2020, - "fall", - "night", - "ELC" - ], - [ - "R1", - 2020, - "fall", - "day", - "NG" - ], - [ - "R2", - 2020, - "fall", - "night", - "NG" - ], - [ - "R2", - 2020, - "summer", - "day", - "OIL" - ], - [ - "R2", - 2025, - "fall", - "day", - "GSL" - ], - [ - "R1", - 2025, - "fall", - "day", - "ETH" - ], - [ - "R2", - 2030, - "spring", - "day", - "OIL" - ], - [ - "R2", - 2030, - "winter", - "day", - "GSL" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC" - ], - [ - "R2", - 2020, - "spring", - "night", - "OIL" - ], - [ - "R1", - 2030, - "fall", - "day", - "NG" - ], - [ - "R2", - 2020, - "winter", - "night", - "GSL" - ], - [ - "R2", - 2025, - "summer", - "night", - "ETH" - ], - [ - "R1", - 2025, - "fall", - "night", - "ELC" - ], - [ - "R1", - 2020, - "fall", - "day", - "DSL" - ], - [ - "R2", - 2020, - "fall", - "night", - "DSL" - ], - [ - "R1", - 2025, - "fall", - "night", - "NG" - ], - [ - "R2", - 2020, - "spring", - "night", - "NG" - ], - [ - "R1", - 2025, - "winter", - "night", - "ELC" - ], - [ - "R1", - 2020, - "winter", - "night", - "E10" - ], - [ - "R2", - 2025, - "fall", - "day", - "URN" - ], - [ - "R1", - 2025, - "winter", - "night", - "NG" - ], - [ - "R2", - 2025, - "spring", - "day", - "GSL" - ], - [ - "R2", - 2030, - "summer", - "night", - "E10" - ], - [ - "R1", - 2030, - "spring", - "day", - "OIL" - ], - [ - "R1", - 2020, - "spring", - "day", - "GSL" - ], - [ - "R1", - 2030, - "winter", - "day", - "GSL" - ], - [ - "R2", - 2025, - "spring", - "day", - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "DSL" - ], - [ - "R2", - 2025, - "winter", - "day", - "OIL" - ], - [ - "R2", - 2030, - "winter", - "day", - "DSL" - ], - [ - "R2", - 2020, - "winter", - "night", - "URN" - ], - [ - "R1", - 2025, - "summer", - "day", - "GSL" - ], - [ - "R1", - 2030, - "spring", - "day", - "NG" - ], - [ - "R1", - 2025, - "fall", - "night", - "DSL" - ], - [ - "R2", - 2020, - "winter", - "night", - "DSL" - ], - [ - "R1", - 2025, - "spring", - "day", - "E10" - ], - [ - "R2", - 2030, - "fall", - "night", - "OIL" - ], - [ - "R2", - 2025, - "winter", - "day", - "NG" - ], - [ - "R1", - 2020, - "fall", - "night", - "OIL" - ], - [ - "R1", - 2020, - "spring", - "day", - "URN" - ], - [ - "R1", - 2025, - "spring", - "night", - "GSL" - ], - [ - "R1", - 2030, - "winter", - "day", - "URN" - ], - [ - "R2", - 2020, - "summer", - "day", - "URN" - ], - [ - "R2", - 2025, - "spring", - "day", - "DSL" - ], - [ - "R1", - 2030, - "winter", - "day", - "DSL" - ], - [ - "R2", - 2025, - "fall", - "day", - "ETH" - ], - [ - "R1", - 2020, - "fall", - "night", - "NG" - ], - [ - "R1", - 2025, - "summer", - "day", - "DSL" - ], - [ - "R1", - 2030, - "fall", - "night", - "OIL" - ], - [ - "R2", - 2030, - "fall", - "day", - "E10" - ], - [ - "R2", - 2020, - "winter", - "night", - "ETH" - ], - [ - "R2", - 2025, - "fall", - "night", - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "URN" - ], - [ - "R1", - 2030, - "fall", - "night", - "NG" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "NG" - ], - [ - "R2", - 2030, - "summer", - "day", - "NG" - ], - [ - "R1", - 2020, - "summer", - "day", - "ELC" - ], - [ - "R1", - 2020, - "summer", - "day", - "NG" - ], - [ - "R1", - 2020, - "spring", - "day", - "ETH" - ], - [ - "R1", - 2030, - "winter", - "day", - "ETH" - ], - [ - "R2", - 2025, - "summer", - "day", - "GSL" - ], - [ - "R1", - 2030, - "spring", - "night", - "OIL" - ], - [ - "R1", - 2020, - "spring", - "night", - "GSL" - ], - [ - "R2", - 2025, - "fall", - "night", - "DSL" - ], - [ - "R1", - 2025, - "summer", - "day", - "ETH" - ], - [ - "R2", - 2030, - "spring", - "day", - "E10" - ], - [ - "R2", - 2020, - "summer", - "night", - "GSL" - ], - [ - "R2", - 2025, - "spring", - "night", - "ELC" - ], - [ - "R1", - 2020, - "winter", - "day", - "OIL" - ], - [ - "R1", - 2020, - "spring", - "night", - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "NG" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "NG" - ], - [ - "R1", - 2030, - "summer", - "day", - "NG" - ], - [ - "R2", - 2020, - "spring", - "night", - "E10" - ], - [ - "R1", - 2025, - "winter", - "night", - "E10" - ], - [ - "R2", - 2030, - "spring", - "night", - "GSL" - ], - [ - "R1", - 2025, - "summer", - "night", - "ELC" - ], - [ - "R1", - 2020, - "winter", - "day", - "NG" - ], - [ - "R1", - 2025, - "summer", - "night", - "NG" - ], - [ - "R1", - 2025, - "spring", - "night", - "ETH" - ], - [ - "R2", - 2025, - "summer", - "day", - "URN" - ], - [ - "R1", - 2030, - "spring", - "day", - "E10" - ], - [ - "R2", - 2020, - "summer", - "night", - "URN" - ], - [ - "R1", - 2020, - "spring", - "night", - "DSL" - ], - [ - "R1", - 2030, - "winter", - "night", - "DSL" - ], - [ - "R2", - 2020, - "summer", - "night", - "DSL" - ], - [ - "R2", - 2025, - "winter", - "day", - "E10" - ], - [ - "R2", - 2020, - "fall", - "day", - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "URN" - ], - [ - "R2", - 2020, - "fall", - "day", - "NG" - ], - [ - "R1", - 2020, - "winter", - "night", - "OIL" - ], - [ - "R2", - 2030, - "summer", - "night", - "OIL" - ], - [ - "R2", - 2030, - "fall", - "night", - "E10" - ], - [ - "R1", - 2020, - "summer", - "night", - "OIL" - ], - [ - "R1", - 2020, - "fall", - "night", - "E10" - ], - [ - "R2", - 2020, - "spring", - "day", - "OIL" - ], - [ - "R2", - 2020, - "winter", - "day", - "GSL" - ], - [ - "R2", - 2025, - "summer", - "day", - "ETH" - ], - [ - "R1", - 2025, - "fall", - "day", - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "NG" - ], - [ - "R1", - 2030, - "spring", - "night", - "URN" - ], - [ - "R2", - 2020, - "spring", - "day", - "NG" - ], - [ - "R2", - 2020, - "summer", - "night", - "ETH" - ], - [ - "R1", - 2025, - "winter", - "day", - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "OIL" - ], - [ - "R1", - 2025, - "winter", - "day", - "NG" - ], - [ - "R2", - 2025, - "winter", - "night", - "URN" - ], - [ - "R1", - 2030, - "fall", - "night", - "E10" - ], - [ - "R2", - 2030, - "winter", - "night", - "E10" - ], - [ - "R2", - 2030, - "summer", - "day", - "E10" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "ETH" - ], - [ - "R2", - 2020, - "winter", - "day", - "DSL" - ], - [ - "R2", - 2030, - "fall", - "day", - "OIL" - ], - [ - "R2", - 2025, - "spring", - "night", - "E10" - ], - [ - "R1", - 2020, - "fall", - "day", - "OIL" - ], - [ - "R2", - 2020, - "fall", - "night", - "OIL" - ], - [ - "R1", - 2025, - "spring", - "day", - "GSL" - ], - [ - "R2", - 2025, - "summer", - "night", - "DSL" - ], - [ - "R1", - 2030, - "spring", - "night", - "ETH" - ], - [ - "R1", - 2020, - "winter", - "night", - "URN" - ], - [ - "R1", - 2020, - "winter", - "day", - "E10" - ], - [ - "R2", - 2030, - "summer", - "night", - "URN" - ], - [ - "R2", - 2025, - "winter", - "night", - "ETH" - ], - [ - "R1", - 2030, - "fall", - "day", - "OIL" - ], - [ - "R2", - 2020, - "winter", - "day", - "ETH" - ], - [ - "R2", - 2025, - "fall", - "day", - "ELC" - ], - [ - "R1", - 2025, - "fall", - "night", - "OIL" - ], - [ - "R1", - 2025, - "spring", - "day", - "URN" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "OIL" - ], - [ - "R2", - 2030, - "winter", - "day", - "NG" - ], - [ - "R2", - 2020, - "winter", - "night", - "ELC" - ], - [ - "R2", - 2020, - "winter", - "night", - "NG" - ], - [ - "R2", - 2025, - "spring", - "day", - "OIL" - ], - [ - "R1", - 2020, - "winter", - "night", - "ETH" - ], - [ - "R2", - 2025, - "fall", - "day", - "DSL" - ], - [ - "R2", - 2020, - "summer", - "day", - "GSL" - ], - [ - "R1", - 2020, - "spring", - "day", - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "NG" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC" - ], - [ - "R1", - 2020, - "summer", - "night", - "E10" - ], - [ - "R1", - 2030, - "winter", - "day", - "NG" - ], - [ - "R2", - 2030, - "fall", - "day", - "URN" - ], - [ - "R2", - 2020, - "spring", - "day", - "E10" - ], - [ - "R1", - 2025, - "winter", - "day", - "E10" - ], - [ - "R2", - 2030, - "spring", - "day", - "GSL" - ], - [ - "R1", - 2025, - "summer", - "day", - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "NG" - ], - [ - "R1", - 2025, - "spring", - "day", - "ETH" - ], - [ - "R2", - 2020, - "spring", - "night", - "GSL" - ], - [ - "R1", - 2030, - "summer", - "night", - "E10" - ], - [ - "R1", - 2025, - "spring", - "night", - "ELC" - ], - [ - "R1", - 2020, - "spring", - "day", - "DSL" - ], - [ - "R2", - 2020, - "summer", - "day", - "DSL" - ], - [ - "R2", - 2025, - "fall", - "night", - "OIL" - ], - [ - "R2", - 2030, - "spring", - "day", - "URN" - ], - [ - "R1", - 2030, - "spring", - "day", - "GSL" - ], - [ - "R2", - 2030, - "winter", - "night", - "OIL" - ], - [ - "R2", - 2030, - "summer", - "day", - "OIL" - ], - [ - "R2", - 2020, - "spring", - "night", - "URN" - ], - [ - "R2", - 2025, - "winter", - "day", - "GSL" - ], - [ - "R2", - 2025, - "fall", - "night", - "NG" - ], - [ - "R1", - 2020, - "summer", - "day", - "OIL" - ], - [ - "R1", - 2020, - "fall", - "day", - "E10" - ], - [ - "R2", - 2020, - "fall", - "night", - "E10" - ], - [ - "R2", - 2030, - "fall", - "night", - "GSL" - ], - [ - "R1", - 2025, - "spring", - "night", - "DSL" - ], - [ - "R1", - 2030, - "spring", - "day", - "URN" - ], - [ - "R1", - 2020, - "fall", - "night", - "GSL" - ], - [ - "R2", - 2025, - "spring", - "night", - "OIL" - ], - [ - "R2", - 2020, - "summer", - "day", - "ETH" - ], - [ - "R1", - 2020, - "spring", - "night", - "OIL" - ], - [ - "R1", - 2030, - "winter", - "night", - "OIL" - ], - [ - "R1", - 2030, - "summer", - "day", - "OIL" - ], - [ - "R2", - 2025, - "winter", - "day", - "URN" - ], - [ - "R1", - 2030, - "fall", - "day", - "E10" - ], - [ - "R2", - 2030, - "winter", - "day", - "E10" - ], - [ - "R2", - 2025, - "summer", - "day", - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "OIL" - ], - [ - "R2", - 2025, - "summer", - "day", - "NG" - ], - [ - "R2", - 2030, - "spring", - "day", - "ETH" - ], - [ - "R1", - 2025, - "fall", - "night", - "E10" - ], - [ - "R1", - 2020, - "spring", - "night", - "NG" - ], - [ - "R2", - 2030, - "fall", - "night", - "URN" - ], - [ - "R2", - 2020, - "summer", - "night", - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "GSL" - ], - [ - "R2", - 2020, - "summer", - "night", - "NG" - ], - [ - "R2", - 2020, - "spring", - "night", - "ETH" - ], - [ - "R2", - 2030, - "fall", - "night", - "DSL" - ], - [ - "R1", - 2020, - "fall", - "night", - "URN" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "E10" - ], - [ - "R2", - 2020, - "fall", - "day", - "OIL" - ], - [ - "R2", - 2025, - "summer", - "day", - "DSL" - ], - [ - "R1", - 2030, - "spring", - "day", - "ETH" - ], - [ - "R1", - 2025, - "summer", - "day", - "E10" - ], - [ - "R1", - 2030, - "fall", - "night", - "URN" - ], - [ - "R2", - 2030, - "summer", - "day", - "URN" - ], - [ - "R2", - 2025, - "winter", - "day", - "ETH" - ], - [ - "R1", - 2030, - "spring", - "night", - "GSL" - ], - [ - "R1", - 2020, - "winter", - "day", - "GSL" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "DSL" - ], - [ - "R2", - 2025, - "winter", - "night", - "GSL" - ], - [ - "R2", - 2030, - "fall", - "night", - "ETH" - ], - [ - "R2", - 2025, - "winter", - "night", - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "OIL" - ], - [ - "R1", - 2020, - "fall", - "night", - "ETH" - ], - [ - "R1", - 2025, - "winter", - "day", - "OIL" - ], - [ - "R2", - 2025, - "spring", - "night", - "URN" - ], - [ - "R2", - 2020, - "winter", - "day", - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "OIL" - ], - [ - "R2", - 2020, - "winter", - "day", - "NG" - ], - [ - "R2", - 2025, - "fall", - "night", - "E10" - ], - [ - "R1", - 2020, - "winter", - "day", - "URN" - ], - [ - "R1", - 2030, - "spring", - "night", - "DSL" - ], - [ - "R1", - 2030, - "fall", - "night", - "ETH" - ], - [ - "R2", - 2030, - "summer", - "day", - "ETH" - ], - [ - "R2", - 2025, - "winter", - "night", - "DSL" - ], - [ - "R2", - 2025, - "summer", - "night", - "NG" - ], - [ - "R1", - 2020, - "winter", - "night", - "GSL" - ], - [ - "R1", - 2020, - "summer", - "day", - "E10" - ], - [ - "R2", - 2030, - "summer", - "night", - "GSL" - ], - [ - "R1", - 2020, - "summer", - "night", - "GSL" - ], - [ - "R2", - 2020, - "spring", - "day", - "GSL" - ], - [ - "R1", - 2020, - "spring", - "night", - "E10" - ], - [ - "R2", - 2025, - "spring", - "night", - "ETH" - ], - [ - "R1", - 2030, - "winter", - "night", - "E10" - ], - [ - "R1", - 2030, - "summer", - "day", - "E10" - ], - [ - "R1", - 2025, - "spring", - "day", - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "E10" - ], - [ - "R1", - 2025, - "spring", - "day", - "NG" - ], - [ - "R1", - 2020, - "winter", - "day", - "ETH" - ], - [ - "R1", - 2030, - "summer", - "night", - "GSL" - ], - [ - "R1", - 2020, - "winter", - "night", - "DSL" - ], - [ - "R2", - 2025, - "fall", - "day", - "OIL" - ], - [ - "R2", - 2030, - "summer", - "night", - "DSL" - ], - [ - "R1", - 2020, - "summer", - "night", - "URN" - ], - [ - "R2", - 2030, - "winter", - "day", - "OIL" - ], - [ - "R2", - 2020, - "spring", - "day", - "URN" - ], - [ - "R1", - 2025, - "winter", - "day", - "URN" - ], - [ - "R2", - 2025, - "fall", - "day", - "NG" - ], - [ - "R2", - 2020, - "winter", - "night", - "OIL" - ], - [ - "R2", - 2020, - "fall", - "day", - "E10" - ], - [ - "R2", - 2030, - "fall", - "day", - "GSL" - ], - [ - "R1", - 2025, - "spring", - "day", - "DSL" - ], - [ - "R1", - 2030, - "summer", - "night", - "URN" - ], - [ - "R1", - 2020, - "fall", - "day", - "GSL" - ], - [ - "R2", - 2020, - "fall", - "night", - "GSL" - ], - [ - "R1", - 2020, - "spring", - "day", - "OIL" - ], - [ - "R1", - 2030, - "winter", - "day", - "OIL" - ], - [ - "R2", - 2030, - "summer", - "night", - "ETH" - ], - [ - "R1", - 2025, - "summer", - "day", - "OIL" - ], - [ - "R1", - 2025, - "fall", - "day", - "E10" - ], - [ - "R1", - 2020, - "spring", - "day", - "NG" - ], - [ - "R2", - 2020, - "winter", - "day", - "E10" - ], - [ - "R1", - 2020, - "summer", - "night", - "ETH" - ], - [ - "R1", - 2030, - "fall", - "day", - "GSL" - ], - [ - "R2", - 2020, - "summer", - "day", - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "NG" - ], - [ - "R2", - 2020, - "spring", - "day", - "ETH" - ], - [ - "R1", - 2025, - "winter", - "day", - "ETH" - ], - [ - "R2", - 2030, - "fall", - "day", - "DSL" - ], - [ - "R1", - 2020, - "fall", - "day", - "URN" - ], - [ - "R1", - 2025, - "fall", - "night", - "GSL" - ], - [ - "R2", - 2020, - "fall", - "night", - "URN" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "E10" - ], - [ - "R1", - 2025, - "spring", - "night", - "OIL" - ], - [ - "R2", - 2030, - "spring", - "day", - "NG" - ], - [ - "R1", - 2025, - "winter", - "night", - "GSL" - ], - [ - "R1", - 2030, - "summer", - "night", - "ETH" - ], - [ - "R2", - 2020, - "spring", - "night", - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "NG" - ], - [ - "R1", - 2030, - "fall", - "day", - "URN" - ], - [ - "R2", - 2030, - "winter", - "day", - "URN" - ], - [ - "R1", - 2025, - "fall", - "night", - "URN" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "DSL" - ], - [ - "R1", - 2025, - "winter", - "night", - "URN" - ], - [ - "R2", - 2030, - "fall", - "day", - "ETH" - ], - [ - "R2", - 2025, - "winter", - "day", - "ELC" - ], - [ - "R2", - 2020, - "spring", - "night", - "DSL" - ], - [ - "R1", - 2025, - "winter", - "night", - "DSL" - ], - [ - "R2", - 2020, - "fall", - "night", - "ETH" - ], - [ - "R1", - 2020, - "fall", - "day", - "ETH" - ], - [ - "R2", - 2025, - "spring", - "day", - "URN" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "NG" - ], - [ - "R2", - 2025, - "summer", - "day", - "OIL" - ], - [ - "R2", - 2025, - "fall", - "day", - "E10" - ], - [ - "R1", - 2025, - "summer", - "day", - "URN" - ], - [ - "R1", - 2020, - "fall", - "night", - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "DSL" - ], - [ - "R2", - 2020, - "summer", - "night", - "OIL" - ], - [ - "R1", - 2030, - "fall", - "day", - "ETH" - ], - [ - "R2", - 2030, - "winter", - "day", - "ETH" - ], - [ - "R2", - 2025, - "winter", - "day", - "DSL" - ], - [ - "R2", - 2025, - "fall", - "night", - "GSL" - ], - [ - "R1", - 2025, - "fall", - "night", - "ETH" - ], - [ - "R2", - 2020, - "winter", - "night", - "E10" - ], - [ - "R2", - 2030, - "spring", - "night", - "OIL" - ], - [ - "R2", - 2030, - "winter", - "night", - "GSL" - ], - [ - "R2", - 2030, - "summer", - "day", - "GSL" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "ETH" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC" - ], - [ - "R1", - 2020, - "summer", - "day", - "GSL" - ], - [ - "R2", - 2030, - "spring", - "night", - "NG" - ], - [ - "R1", - 2020, - "fall", - "night", - "DSL" - ], - [ - "R1", - 2020, - "spring", - "day", - "E10" - ], - [ - "R2", - 2025, - "spring", - "day", - "ETH" - ], - [ - "R1", - 2030, - "winter", - "day", - "E10" - ], - [ - "R2", - 2020, - "summer", - "day", - "E10" - ], - [ - "R2", - 2025, - "fall", - "night", - "URN" - ], - [ - "R2", - 2025, - "spring", - "night", - "GSL" - ], - [ - "R2", - 2030, - "winter", - "night", - "URN" - ], - [ - "R1", - 2030, - "summer", - "day", - "GSL" - ], - [ - "R1", - 2030, - "winter", - "night", - "GSL" - ], - [ - "R1", - 2030, - "fall", - "night", - "DSL" - ], - [ - "R2", - 2025, - "winter", - "night", - "OIL" - ], - [ - "R2", - 2030, - "winter", - "night", - "DSL" - ], - [ - "R2", - 2030, - "summer", - "day", - "DSL" - ], - [ - "R1", - 2020, - "summer", - "day", - "URN" - ], - [ - "R1", - 2025, - "summer", - "night", - "GSL" - ], - [ - "R1", - 2030, - "spring", - "night", - "NG" - ], - [ - "R1", - 2020, - "winter", - "day", - "ELC" - ], - [ - "R1", - 2020, - "summer", - "day", - "DSL" - ], - [ - "R1", - 2025, - "spring", - "night", - "E10" - ], - [ - "R2", - 2025, - "winter", - "night", - "NG" - ], - [ - "R2", - 2020, - "winter", - "day", - "OIL" - ], - [ - "R1", - 2020, - "spring", - "night", - "URN" - ], - [ - "R1", - 2030, - "winter", - "night", - "URN" - ], - [ - "R1", - 2030, - "summer", - "day", - "URN" - ], - [ - "R2", - 2025, - "spring", - "night", - "DSL" - ], - [ - "R2", - 2020, - "fall", - "day", - "GSL" - ], - [ - "R1", - 2030, - "summer", - "day", - "DSL" - ], - [ - "R1", - 2025, - "summer", - "night", - "URN" - ], - [ - "R2", - 2025, - "fall", - "night", - "ETH" - ], - [ - "R1", - 2020, - "winter", - "day", - "DSL" - ], - [ - "R1", - 2025, - "summer", - "night", - "DSL" - ], - [ - "R2", - 2030, - "winter", - "night", - "ETH" - ], - [ - "R1", - 2020, - "summer", - "day", - "ETH" - ], - [ - "R1", - 2020, - "winter", - "night", - "ELC" - ], - [ - "R1", - 2020, - "winter", - "night", - "NG" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "GSL" - ], - [ - "R2", - 2020, - "fall", - "day", - "URN" - ], - [ - "R2", - 2030, - "summer", - "night", - "NG" - ], - [ - "R2", - 2025, - "summer", - "day", - "E10" - ], - [ - "R1", - 2025, - "spring", - "day", - "OIL" - ], - [ - "R1", - 2020, - "summer", - "night", - "ELC" - ], - [ - "R2", - 2020, - "fall", - "day", - "DSL" - ], - [ - "R1", - 2025, - "winter", - "day", - "GSL" - ], - [ - "R1", - 2020, - "summer", - "night", - "NG" - ], - [ - "R1", - 2020, - "spring", - "night", - "ETH" - ], - [ - "R1", - 2030, - "winter", - "night", - "ETH" - ], - [ - "R1", - 2030, - "summer", - "day", - "ETH" - ], - [ - "R2", - 2020, - "spring", - "day", - "ELC" - ], - [ - "R2", - 2020, - "summer", - "night", - "E10" - ], - [ - "R2", - 2025, - "summer", - "night", - "GSL" - ], - [ - "R1", - 2025, - "summer", - "night", - "ETH" - ], - [ - "R2", - 2030, - "spring", - "night", - "E10" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "URN" - ], - [ - "R1", - 2030, - "summer", - "night", - "NG" - ], - [ - "R2", - 2020, - "winter", - "day", - "URN" - ], - [ - "R1", - 2020, - "summer", - "night", - "DSL" - ], - [ - "R1", - 2025, - "fall", - "day", - "DSL" - ], - [ - "R2", - 2020, - "spring", - "day", - "DSL" - ], - [ - "R1", - 2025, - "winter", - "day", - "DSL" - ], - [ - "R2", - 2025, - "summer", - "night", - "URN" - ], - [ - "R2", - 2020, - "fall", - "day", - "ETH" - ], - [ - "R1", - 2030, - "spring", - "night", - "E10" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "NG" - ], - [ - "R1", - 2030, - "summer", - "night", - "DSL" - ] - ], - "AnnualCommodityBalanceConstraint_rpc": [], - "BaseloadDiurnalConstraint_rpsdtv": [ - [ - "R1", - 2020, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2020, - "summer", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2020, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2020, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2020, - "summer", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2020, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2020, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2020, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2020, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2020, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2020, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2020, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2020, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2020, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2020, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2030 - ] - ], - "RegionalExchangeCapacityConstraint_rrptv": [ - [ - "R1", - "R2", - 2030, - "E_TRANS", - 2015 - ], - [ - "R2", - "R1", - 2020, - "E_TRANS", - 2015 - ], - [ - "R2", - "R1", - 2030, - "E_TRANS", - 2015 - ], - [ - "R1", - "R2", - 2025, - "E_TRANS", - 2015 - ], - [ - "R1", - "R2", - 2020, - "E_TRANS", - 2015 - ], - [ - "R2", - "R1", - 2025, - "E_TRANS", - 2015 - ] - ], - "StorageConstraints_rpsdtv": [ - [ - "R1", - 2030, - "fall", - "night", - "E_BATT", - 2030 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_BATT", - 2030 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_BATT", - 2030 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_BATT", - 2030 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2020, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_BATT", - 2030 - ], - [ - "R2", - 2020, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_BATT", - 2030 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_BATT", - 2030 - ], - [ - "R1", - 2020, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_BATT", - 2030 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_BATT", - 2030 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2020, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_BATT", - 2030 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2020, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_BATT", - 2030 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2020, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_BATT", - 2030 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_BATT", - 2030 - ], - [ - "R2", - 2020, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_BATT", - 2025 - ] - ], - "StorageFractionConstraint_rpsdtv": [ - [ - "R1", - 2025, - "winter", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2020, - "summer", - "day", - "E_BATT", - 2020 - ] - ], - "RampUpConstraint_rpsdtv": [], - "RampDownConstraint_rpsdtv": [], - "ReserveMargin_rpsd": [ - [ - "R2", - 2025, - "winter", - "night" - ], - [ - "R1", - 2020, - "spring", - "night" - ], - [ - "R2", - 2020, - "winter", - "day" - ], - [ - "R1", - 2030, - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "night" - ], - [ - "R1", - 2030, - "summer", - "day" - ], - [ - "R2", - 2030, - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "night" - ], - [ - "R1", - 2030, - "fall", - "day" - ], - [ - "R2", - 2030, - "summer", - "day" - ], - [ - "R2", - 2030, - "fall", - "day" - ], - [ - "R1", - 2020, - "winter", - "day" - ], - [ - "R1", - 2030, - "winter", - "night" - ], - [ - "R1", - 2020, - "summer", - "night" - ], - [ - "R1", - 2025, - "winter", - "day" - ], - [ - "R1", - 2020, - "fall", - "night" - ], - [ - "R2", - 2030, - "winter", - "night" - ], - [ - "R2", - 2025, - "spring", - "night" - ], - [ - "R2", - 2020, - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "night" - ], - [ - "R2", - 2025, - "fall", - "night" - ], - [ - "R2", - 2020, - "fall", - "day" - ], - [ - "R2", - 2025, - "summer", - "day" - ], - [ - "R2", - 2020, - "winter", - "night" - ], - [ - "R1", - 2030, - "spring", - "night" - ], - [ - "R1", - 2025, - "spring", - "day" - ], - [ - "R2", - 2020, - "summer", - "day" - ], - [ - "R1", - 2030, - "summer", - "night" - ], - [ - "R2", - 2030, - "spring", - "night" - ], - [ - "R2", - 2020, - "summer", - "night" - ], - [ - "R1", - 2030, - "fall", - "night" - ], - [ - "R1", - 2020, - "winter", - "night" - ], - [ - "R2", - 2030, - "summer", - "night" - ], - [ - "R2", - 2025, - "winter", - "day" - ], - [ - "R1", - 2020, - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night" - ], - [ - "R1", - 2025, - "winter", - "night" - ], - [ - "R1", - 2025, - "summer", - "day" - ], - [ - "R1", - 2025, - "fall", - "day" - ], - [ - "R2", - 2020, - "spring", - "night" - ], - [ - "R1", - 2030, - "winter", - "day" - ], - [ - "R1", - 2020, - "summer", - "day" - ], - [ - "R2", - 2020, - "fall", - "night" - ], - [ - "R1", - 2020, - "fall", - "day" - ], - [ - "R2", - 2030, - "winter", - "day" - ], - [ - "R2", - 2025, - "spring", - "day" - ], - [ - "R1", - 2025, - "spring", - "night" - ], - [ - "R2", - 2025, - "fall", - "day" - ] - ], - "MinTechInputSplitConstraint_rpsditv": [ - [ - "R2", - 2030, - "fall", - "day", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "spring", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "GSL", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "GSL", - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "winter", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "spring", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "winter", - "day", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "fall", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "winter", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "summer", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "fall", - "day", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "spring", - "day", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "summer", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "winter", - "day", - "GSL", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "summer", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "GSL", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "fall", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "fall", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "summer", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "winter", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "summer", - "day", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "summer", - "day", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "GSL", - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "fall", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "summer", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "winter", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "spring", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "fall", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "GSL", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "GSL", - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "winter", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "spring", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "fall", - "day", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "summer", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "GSL", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "GSL", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "fall", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "winter", - "day", - "ETH", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "GSL", - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "ETH", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "GSL", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "spring", - "day", - "GSL", - "T_BLND", - 2020 - ] - ], - "MinTechInputSplitAnnualConstraint_rpitv": [], - "MinTechInputSplitAverageConstraint_rpitv": [], - "MinTechOutputSplitConstraint_rpsdtvo": [ - [ - "R1", - 2030, - "summer", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "summer", - "night", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "winter", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "spring", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "fall", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "summer", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "spring", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "winter", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "winter", - "night", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "fall", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "fall", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "fall", - "night", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "winter", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "winter", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "fall", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "fall", - "night", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "fall", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "summer", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "fall", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "summer", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "fall", - "night", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "spring", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "winter", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "winter", - "night", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "summer", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "winter", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "spring", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "summer", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "spring", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "winter", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "fall", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "fall", - "night", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "winter", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "summer", - "night", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "fall", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "spring", - "night", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "spring", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "summer", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "spring", - "night", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "fall", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "winter", - "night", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "summer", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "summer", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "winter", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "spring", - "night", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "summer", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "spring", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "winter", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "spring", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "fall", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "winter", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "summer", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "winter", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "winter", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "spring", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "fall", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "spring", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "winter", - "night", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "winter", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "winter", - "night", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "fall", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "fall", - "night", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "fall", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "spring", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "winter", - "night", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "summer", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "fall", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "spring", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "winter", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "summer", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "summer", - "night", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "summer", - "night", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "summer", - "night", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "spring", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "fall", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "winter", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "spring", - "night", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "winter", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "winter", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "fall", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "spring", - "night", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "summer", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "spring", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "spring", - "night", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "summer", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "summer", - "night", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "summer", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "spring", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "fall", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "spring", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "fall", - "day", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "spring", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "summer", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "summer", - "night", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "spring", - "day", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "fall", - "night", - "S_OILREF", - 2020, - "GSL" + "AnnualCommodityBalanceConstraint_rpc": [], + "AnnualRetirementVar_rptv": [ + [ + "R1", + 2030, + "T_DSL", + 2020 + ], + [ + "R2", + 2030, + "T_EV", + 2020 + ], + [ + "R2", + 2030, + "T_DSL", + 2020 + ], + [ + "R1", + 2030, + "T_EV", + 2020 + ], + [ + "R2", + 2030, + "T_GSL", + 2020 + ], + [ + "R1", + 2030, + "T_GSL", + 2020 + ] + ], + "BaseloadDiurnalConstraint_rpsdtv": [ + [ + "R2", + 2025, + "spring", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "summer", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2020, + "fall", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2020, + "spring", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "winter", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2020, + "fall", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2025, + "spring", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2020, + "spring", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2020, + "winter", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "spring", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2020, + "summer", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "winter", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "fall", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2020, + "fall", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2020, + "winter", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2025, + "fall", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2025, + "spring", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2030, + "winter", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2025, + "summer", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2030, + "summer", + "night", + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2030, + "summer", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "fall", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2020, + "fall", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "winter", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2020, + "spring", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2020, + "winter", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "spring", + "night", + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2025, + "winter", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2025, + "summer", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2025, + "spring", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2030, + "winter", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "fall", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2020, + "winter", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2025, + "fall", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2025, + "winter", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2025, + "fall", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2025, + "winter", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2025, + "summer", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2025, + "fall", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2025, + "summer", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2030, + "fall", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "winter", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2020, + "fall", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "spring", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2025, + "winter", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2025, + "summer", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2025, + "spring", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "summer", + "day", + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2025, + "winter", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "spring", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2025, + "fall", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2025, + "spring", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2025, + "winter", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2020, + "winter", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "winter", + "night", + "E_NUCLEAR", + 2030 + ], + [ + "R1", + 2020, + "summer", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_NUCLEAR", + 2030 + ], + [ + "R1", + 2025, + "summer", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "spring", + "day", + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2030, + "fall", + "day", + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2025, + "summer", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2025, + "winter", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2025, + "fall", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2020, + "fall", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "spring", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "summer", + "day", + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2025, + "winter", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "winter", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2025, + "summer", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2025, + "spring", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2020, + "summer", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "summer", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2020, + "fall", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "summer", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2025, + "winter", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2020, + "winter", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "spring", + "day", + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2030, + "fall", + "night", + "E_NUCLEAR", + 2030 + ], + [ + "R1", + 2025, + "fall", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2025, + "spring", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2025, + "winter", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2020, + "summer", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2020, + "winter", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "winter", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2020, + "summer", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2025, + "summer", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "spring", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2020, + "spring", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "fall", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2025, + "summer", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2025, + "winter", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2025, + "spring", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2025, + "fall", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "spring", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "summer", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2030, + "winter", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2025, + "summer", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2025, + "fall", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "summer", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "summer", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "spring", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2020, + "winter", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "fall", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2030, + "winter", + "day", + "E_NUCLEAR", + 2030 + ], + [ + "R1", + 2030, + "fall", + "day", + "E_NUCLEAR", + 2030 + ], + [ + "R1", + 2020, + "summer", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2025, + "spring", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2020, + "spring", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "winter", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "spring", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2020, + "spring", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "fall", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2025, + "summer", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2025, + "winter", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2025, + "spring", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2025, + "fall", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "summer", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2020, + "spring", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "winter", + "day", + "E_NUCLEAR", + 2030 + ], + [ + "R1", + 2025, + "fall", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "summer", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "spring", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2020, + "summer", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "winter", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2030, + "fall", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2020, + "fall", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2025, + "fall", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2020, + "spring", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2025, + "spring", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "winter", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "winter", + "night", + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2030, + "fall", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2020, + "summer", + "day", + "E_NUCLEAR", + 2015 + ] + ], + "CapacityAnnualConstraint_rptv": [], + "CapacityAvailableVar_rpt": [ + [ + "R1", + 2020, + "R_EH" + ], + [ + "R2", + 2025, + "T_BLND" + ], + [ + "R1", + 2020, + "E_NGCC" + ], + [ + "R2", + 2020, + "R_NGH" + ], + [ + "R1", + 2030, + "T_GSL" + ], + [ + "R2", + 2020, + "E_NUCLEAR" + ], + [ + "R2", + 2025, + "R_EH" + ], + [ + "R2-R1", + 2020, + "E_TRANS" + ], + [ + "R1", + 2030, + "E_SOLPV" + ], + [ + "R2", + 2025, + "E_NGCC" + ], + [ + "R2", + 2030, + "S_OILREF" + ], + [ + "R1-R2", + 2020, + "E_TRANS" + ], + [ + "R1", + 2030, + "R_NGH" + ], + [ + "R1", + 2025, + "S_OILREF" + ], + [ + "R1", + 2020, + "T_DSL" + ], + [ + "R2", + 2020, + "T_EV" + ], + [ + "R1", + 2030, + "E_NUCLEAR" + ], + [ + "R2", + 2020, + "E_BATT" + ], + [ + "R2", + 2020, + "T_BLND" + ], + [ + "R2", + 2030, + "T_GSL" + ], + [ + "R2", + 2030, + "E_SOLPV" + ], + [ + "R2", + 2025, + "T_DSL" + ], + [ + "R1", + 2025, + "T_GSL" + ], + [ + "R1", + 2030, + "T_EV" + ], + [ + "R2", + 2020, + "R_EH" + ], + [ + "R1", + 2025, + "E_SOLPV" + ], + [ + "R1", + 2030, + "E_BATT" + ], + [ + "R1", + 2030, + "T_BLND" + ], + [ + "R2", + 2020, + "E_NGCC" + ], + [ + "R2", + 2030, + "R_NGH" + ], + [ + "R2", + 2030, + "E_NUCLEAR" + ], + [ + "R1", + 2025, + "R_NGH" + ], + [ + "R1", + 2020, + "S_OILREF" + ], + [ + "R1", + 2025, + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "R_EH" + ], + [ + "R1", + 2030, + "E_NGCC" + ], + [ + "R2", + 2030, + "T_BLND" + ], + [ + "R2", + 2020, + "T_DSL" + ], + [ + "R2", + 2030, + "T_EV" + ], + [ + "R1", + 2020, + "T_GSL" + ], + [ + "R2", + 2025, + "S_OILREF" + ], + [ + "R2-R1", + 2030, + "E_TRANS" + ], + [ + "R2", + 2030, + "E_BATT" + ], + [ + "R1", + 2025, + "T_EV" + ], + [ + "R1", + 2020, + "E_SOLPV" + ], + [ + "R1", + 2025, + "E_BATT" + ], + [ + "R1", + 2025, + "T_BLND" + ], + [ + "R1-R2", + 2030, + "E_TRANS" + ], + [ + "R2", + 2025, + "T_GSL" + ], + [ + "R1", + 2030, + "T_DSL" + ], + [ + "R1", + 2020, + "R_NGH" + ], + [ + "R2", + 2030, + "R_EH" + ], + [ + "R2", + 2025, + "E_SOLPV" + ], + [ + "R1", + 2020, + "E_NUCLEAR" + ], + [ + "R1", + 2025, + "R_EH" + ], + [ + "R2", + 2030, + "E_NGCC" + ], + [ + "R1", + 2025, + "E_NGCC" + ], + [ + "R2", + 2025, + "R_NGH" + ], + [ + "R2", + 2020, + "S_OILREF" + ], + [ + "R2", + 2025, + "E_NUCLEAR" + ], + [ + "R2-R1", + 2025, + "E_TRANS" + ], + [ + "R1", + 2020, + "T_EV" + ], + [ + "R1", + 2020, + "E_BATT" + ], + [ + "R1", + 2020, + "T_BLND" + ], + [ + "R1-R2", + 2025, + "E_TRANS" + ], + [ + "R2", + 2030, + "T_DSL" + ], + [ + "R2", + 2020, + "T_GSL" + ], + [ + "R1", + 2030, + "S_OILREF" + ], + [ + "R1", + 2025, + "T_DSL" + ], + [ + "R2", + 2025, + "T_EV" + ], + [ + "R2", + 2020, + "E_SOLPV" + ], + [ + "R2", + 2025, + "E_BATT" + ] + ], + "CapacityConstraint_rpsdtv": [ + [ + "R2", + 2025, + "spring", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2025, + "summer", + "night", + "T_EV", + 2020 + ], + [ + "R1", + 2020, + "fall", + "night", + "R_NGH", + 2020 + ], + [ + "R1", + 2025, + "spring", + "day", + "R_NGH", + 2025 + ], + [ + "R1", + 2030, + "spring", + "day", + "E_SOLPV", + 2030 + ], + [ + "R1", + 2030, + "fall", + "day", + "S_OILREF", + 2020 + ], + [ + "R2", + 2030, + "spring", + "day", + "T_BLND", + 2020 + ], + [ + "R1", + 2030, + "summer", + "day", + "T_EV", + 2025 + ], + [ + "R1", + 2025, + "spring", + "day", + "T_DSL", + 2025 + ], + [ + "R1", + 2025, + "summer", + "night", + "R_NGH", + 2025 + ], + [ + "R2", + 2025, + "fall", + "day", + "R_EH", + 2025 + ], + [ + "R2", + 2020, + "winter", + "night", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2020, + "fall", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2025, + "spring", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2030, + "spring", + "day", + "T_GSL", + 2030 + ], + [ + "R1", + 2030, + "summer", + "day", + "E_SOLPV", + 2030 + ], + [ + "R1", + 2025, + "fall", + "day", + "E_NGCC", + 2020 + ], + [ + "R1", + 2020, + "spring", + "night", + "E_NGCC", + 2020 + ], + [ + "R1-R2", + 2030, + "winter", + "day", + "E_TRANS", + 2015 + ], + [ + "R1", + 2030, + "spring", + "day", + "R_EH", + 2030 + ], + [ + "R2", + 2030, + "winter", + "day", + "T_EV", + 2025 + ], + [ + "R2", + 2020, + "winter", + "day", + "E_NGCC", + 2020 + ], + [ + "R2", + 2025, + "winter", + "night", + "R_NGH", + 2020 + ], + [ + "R2", + 2025, + "summer", + "night", + "R_EH", + 2025 + ], + [ + "R1", + 2020, + "fall", + "day", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "fall", + "day", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "R_NGH", + 2025 + ], + [ + "R1", + 2030, + "spring", + "day", + "T_GSL", + 2025 + ], + [ + "R1", + 2030, + "winter", + "day", + "T_EV", + 2030 + ], + [ + "R2", + 2020, + "summer", + "night", + "T_GSL", + 2020 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_NGCC", + 2025 + ], + [ + "R1", + 2030, + "summer", + "day", + "R_EH", + 2030 + ], + [ + "R2", + 2020, + "fall", + "day", + "T_GSL", + 2020 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_NGCC", + 2020 + ], + [ + "R2", + 2030, + "winter", + "night", + "R_EH", + 2020 + ], + [ + "R1", + 2025, + "summer", + "day", + "T_GSL", + 2025 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2020, + "summer", + "night", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2020, + "winter", + "day", + "T_EV", + 2020 + ], + [ + "R1", + 2020, + "fall", + "day", + "R_EH", + 2020 + ], + [ + "R1", + 2020, + "spring", + "night", + "S_OILREF", + 2020 + ], + [ + "R2", + 2030, + "summer", + "day", + "T_DSL", + 2030 + ], + [ + "R1", + 2030, + "fall", + "day", + "T_GSL", + 2030 + ], + [ + "R1", + 2020, + "fall", + "night", + "T_BLND", + 2020 + ], + [ + "R1", + 2030, + "summer", + "day", + "T_EV", + 2020 + ], + [ + "R1", + 2030, + "winter", + "day", + "T_BLND", + 2020 + ], + [ + "R1", + 2025, + "spring", + "day", + "T_DSL", + 2020 + ], + [ + "R1", + 2025, + "summer", + "night", + "R_NGH", + 2020 + ], + [ + "R1", + 2025, + "spring", + "night", + "T_GSL", + 2025 + ], + [ + "R2-R1", + 2020, + "summer", + "night", + "E_TRANS", + 2015 + ], + [ + "R1", + 2020, + "fall", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2-R1", + 2020, + "spring", + "night", + "E_TRANS", + 2015 + ], + [ + "R1-R2", + 2020, + "spring", + "day", + "E_TRANS", + 2015 + ], + [ + "R2", + 2030, + "spring", + "day", + "T_GSL", + 2025 + ], + [ + "R1", + 2030, + "summer", + "day", + "E_SOLPV", + 2025 + ], + [ + "R2", + 2025, + "fall", + "night", + "T_BLND", + 2020 + ], + [ + "R1", + 2030, + "winter", + "night", + "T_DSL", + 2030 + ], + [ + "R1", + 2030, + "fall", + "night", + "S_OILREF", + 2020 + ], + [ + "R1", + 2030, + "spring", + "day", + "R_EH", + 2025 + ], + [ + "R2", + 2030, + "winter", + "day", + "T_EV", + 2020 + ], + [ + "R2", + 2025, + "winter", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2025, + "summer", + "night", + "R_EH", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "R_NGH", + 2020 + ], + [ + "R1", + 2030, + "winter", + "day", + "T_EV", + 2025 + ], + [ + "R1", + 2030, + "spring", + "day", + "T_GSL", + 2020 + ], + [ + "R1", + 2030, + "spring", + "night", + "T_EV", + 2030 + ], + [ + "R2", + 2020, + "summer", + "day", + "S_OILREF", + 2020 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_NGCC", + 2020 + ], + [ + "R2", + 2025, + "spring", + "night", + "S_OILREF", + 2020 + ], + [ + "R1", + 2030, + "summer", + "day", + "R_EH", + 2025 + ], + [ + "R1-R2", + 2025, + "spring", + "night", + "E_TRANS", + 2015 + ], + [ + "R1", + 2025, + "winter", + "day", + "R_NGH", + 2025 + ], + [ + "R2", + 2025, + "fall", + "night", + "T_EV", + 2025 + ], + [ + "R1", + 2030, + "winter", + "day", + "E_SOLPV", + 2030 + ], + [ + "R2", + 2030, + "winter", + "night", + "E_NGCC", + 2030 + ], + [ + "R2", + 2030, + "winter", + "day", + "T_BLND", + 2020 + ], + [ + "R1", + 2025, + "summer", + "day", + "T_GSL", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2025, + "winter", + "day", + "T_DSL", + 2025 + ], + [ + "R1", + 2025, + "winter", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2030, + "winter", + "day", + "T_GSL", + 2030 + ], + [ + "R2", + 2020, + "winter", + "night", + "R_EH", + 2020 + ], + [ + "R1", + 2030, + "fall", + "day", + "T_GSL", + 2025 + ], + [ + "R1", + 2020, + "winter", + "night", + "T_DSL", + 2020 + ], + [ + "R2", + 2030, + "summer", + "day", + "E_NGCC", + 2020 + ], + [ + "R1", + 2020, + "fall", + "night", + "T_EV", + 2020 + ], + [ + "R1", + 2025, + "spring", + "day", + "T_BLND", + 2020 + ], + [ + "R1", + 2025, + "spring", + "day", + "T_EV", + 2025 + ], + [ + "R1", + 2030, + "winter", + "day", + "R_EH", + 2030 + ], + [ + "R1", + 2025, + "summer", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2020, + "spring", + "day", + "R_NGH", + 2020 + ], + [ + "R1", + 2025, + "spring", + "night", + "T_GSL", + 2020 + ], + [ + "R2", + 2030, + "spring", + "day", + "T_GSL", + 2020 + ], + [ + "R1", + 2030, + "summer", + "day", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2025, + "fall", + "day", + "R_NGH", + 2020 + ], + [ + "R1", + 2020, + "summer", + "day", + "T_BLND", + 2020 + ], + [ + "R1", + 2030, + "winter", + "night", + "T_DSL", + 2025 + ], + [ + "R2", + 2020, + "spring", + "night", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2025, + "spring", + "night", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2025, + "winter", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R2-R1", + 2030, + "spring", + "night", + "E_TRANS", + 2015 + ], + [ + "R2", + 2025, + "summer", + "day", + "T_BLND", + 2020 + ], + [ + "R1", + 2030, + "winter", + "day", + "T_EV", + 2020 + ], + [ + "R2", + 2020, + "spring", + "night", + "T_EV", + 2020 + ], + [ + "R1", + 2030, + "spring", + "night", + "T_EV", + 2025 + ], + [ + "R1", + 2020, + "winter", + "night", + "T_BLND", + 2020 + ], + [ + "R1", + 2020, + "summer", + "night", + "R_EH", + 2020 + ], + [ + "R1", + 2030, + "summer", + "day", + "R_EH", + 2020 + ], + [ + "R2", + 2025, + "spring", + "day", + "E_NGCC", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "S_OILREF", + 2020 + ], + [ + "R1", + 2025, + "winter", + "day", + "R_NGH", + 2020 + ], + [ + "R2", + 2025, + "fall", + "night", + "T_EV", + 2020 + ], + [ + "R2", + 2020, + "summer", + "night", + "T_DSL", + 2020 + ], + [ + "R1", + 2030, + "winter", + "day", + "E_SOLPV", + 2025 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2025, + "winter", + "day", + "T_DSL", + 2020 + ], + [ + "R1", + 2025, + "winter", + "night", + "T_GSL", + 2025 + ], + [ + "R2", + 2020, + "winter", + "day", + "S_OILREF", + 2020 + ], + [ + "R2", + 2025, + "fall", + "night", + "E_SOLPV", + 2025 + ], + [ + "R1", + 2025, + "winter", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "winter", + "day", + "T_GSL", + 2025 + ], + [ + "R1", + 2030, + "spring", + "day", + "R_NGH", + 2030 + ], + [ + "R2", + 2030, + "summer", + "day", + "T_EV", + 2030 + ], + [ + "R2", + 2025, + "summer", + "night", + "R_NGH", + 2025 + ], + [ + "R1", + 2025, + "spring", + "day", + "T_EV", + 2020 + ], + [ + "R1", + 2030, + "winter", + "day", + "R_EH", + 2025 + ], + [ + "R1", + 2025, + "summer", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "spring", + "day", + "E_NUCLEAR", + 2030 + ], + [ + "R1", + 2030, + "fall", + "day", + "T_DSL", + 2030 + ], + [ + "R1", + 2030, + "summer", + "day", + "R_NGH", + 2030 + ], + [ + "R2", + 2025, + "summer", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2030, + "fall", + "night", + "T_BLND", + 2020 + ], + [ + "R2", + 2025, + "fall", + "night", + "R_EH", + 2025 + ], + [ + "R2", + 2025, + "fall", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2030, + "winter", + "night", + "R_NGH", + 2020 + ], + [ + "R1", + 2025, + "spring", + "night", + "T_DSL", + 2025 + ], + [ + "R1", + 2020, + "summer", + "day", + "T_EV", + 2020 + ], + [ + "R2", + 2030, + "fall", + "day", + "E_NGCC", + 2030 + ], + [ + "R1", + 2030, + "winter", + "day", + "T_GSL", + 2020 + ], + [ + "R1", + 2030, + "winter", + "night", + "T_EV", + 2030 + ], + [ + "R2", + 2025, + "winter", + "night", + "S_OILREF", + 2020 + ], + [ + "R1", + 2030, + "winter", + "night", + "T_DSL", + 2020 + ], + [ + "R2", + 2020, + "fall", + "night", + "T_GSL", + 2020 + ], + [ + "R1", + 2030, + "summer", + "day", + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2025, + "winter", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "winter", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2025, + "fall", + "day", + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "spring", + "day", + "R_NGH", + 2030 + ], + [ + "R1", + 2030, + "spring", + "night", + "T_EV", + 2020 + ], + [ + "R2", + 2025, + "summer", + "day", + "T_GSL", + 2025 + ], + [ + "R1", + 2020, + "fall", + "night", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2025, + "spring", + "day", + "E_SOLPV", + 2025 + ], + [ + "R1", + 2025, + "fall", + "night", + "E_NGCC", + 2025 + ], + [ + "R2", + 2030, + "spring", + "day", + "E_NUCLEAR", + 2030 + ], + [ + "R2-R1", + 2030, + "winter", + "day", + "E_TRANS", + 2015 + ], + [ + "R1", + 2025, + "summer", + "night", + "E_SOLPV", + 2025 + ], + [ + "R1", + 2025, + "winter", + "night", + "T_GSL", + 2020 + ], + [ + "R2", + 2025, + "fall", + "night", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2020, + "fall", + "day", + "E_NGCC", + 2020 + ], + [ + "R1", + 2025, + "winter", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "spring", + "day", + "R_NGH", + 2025 + ], + [ + "R2", + 2030, + "winter", + "day", + "T_GSL", + 2020 + ], + [ + "R2", + 2030, + "summer", + "day", + "T_EV", + 2025 + ], + [ + "R2", + 2025, + "summer", + "night", + "R_NGH", + 2020 + ], + [ + "R1", + 2020, + "summer", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "fall", + "night", + "T_EV", + 2030 + ], + [ + "R1", + 2030, + "spring", + "night", + "T_GSL", + 2030 + ], + [ + "R1", + 2030, + "summer", + "night", + "S_OILREF", + 2020 + ], + [ + "R1", + 2030, + "winter", + "day", + "R_EH", + 2020 + ], + [ + "R1", + 2025, + "summer", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2020, + "spring", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "spring", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2020, + "spring", + "night", + "R_EH", + 2020 + ], + [ + "R1", + 2030, + "summer", + "day", + "R_NGH", + 2025 + ], + [ + "R2", + 2020, + "fall", + "day", + "T_DSL", + 2020 + ], + [ + "R1", + 2030, + "fall", + "day", + "T_DSL", + 2025 + ], + [ + "R2", + 2025, + "summer", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2020, + "winter", + "day", + "R_EH", + 2020 + ], + [ + "R1-R2", + 2030, + "spring", + "day", + "E_TRANS", + 2015 + ], + [ + "R1", + 2025, + "summer", + "day", + "T_DSL", + 2025 + ], + [ + "R2", + 2025, + "fall", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2025, + "spring", + "night", + "T_DSL", + 2020 + ], + [ + "R1", + 2030, + "winter", + "night", + "T_EV", + 2025 + ], + [ + "R2", + 2025, + "fall", + "night", + "R_EH", + 2020 + ], + [ + "R2", + 2030, + "fall", + "day", + "E_NGCC", + 2025 + ], + [ + "R1", + 2030, + "summer", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2030, + "winter", + "night", + "S_OILREF", + 2020 + ], + [ + "R2", + 2030, + "winter", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "spring", + "day", + "R_NGH", + 2025 + ], + [ + "R2", + 2030, + "summer", + "night", + "E_NGCC", + 2030 + ], + [ + "R1", + 2030, + "winter", + "day", + "R_NGH", + 2030 + ], + [ + "R2", + 2025, + "summer", + "day", + "T_GSL", + 2020 + ], + [ + "R1", + 2025, + "spring", + "day", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2025, + "fall", + "day", + "T_GSL", + 2025 + ], + [ + "R2", + 2030, + "fall", + "night", + "T_GSL", + 2030 + ], + [ + "R1", + 2025, + "fall", + "night", + "E_NGCC", + 2020 + ], + [ + "R2", + 2030, + "spring", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2025, + "summer", + "night", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2025, + "winter", + "day", + "T_EV", + 2020 + ], + [ + "R1", + 2025, + "spring", + "night", + "T_BLND", + 2020 + ], + [ + "R1", + 2030, + "winter", + "day", + "E_NUCLEAR", + 2030 + ], + [ + "R1", + 2030, + "spring", + "day", + "R_NGH", + 2020 + ], + [ + "R2", + 2020, + "winter", + "night", + "E_NGCC", + 2020 + ], + [ + "R1", + 2025, + "winter", + "night", + "T_DSL", + 2025 + ], + [ + "R1", + 2020, + "summer", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2020, + "summer", + "night", + "T_BLND", + 2020 + ], + [ + "R2", + 2020, + "spring", + "day", + "S_OILREF", + 2020 + ], + [ + "R1", + 2030, + "summer", + "night", + "T_GSL", + 2030 + ], + [ + "R1", + 2030, + "spring", + "night", + "T_GSL", + 2025 + ], + [ + "R2-R1", + 2025, + "spring", + "night", + "E_TRANS", + 2015 + ], + [ + "R2", + 2020, + "spring", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "spring", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2025, + "winter", + "day", + "E_NGCC", + 2025 + ], + [ + "R1", + 2030, + "summer", + "day", + "R_NGH", + 2020 + ], + [ + "R1", + 2030, + "fall", + "day", + "T_DSL", + 2020 + ], + [ + "R2", + 2025, + "summer", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2025, + "summer", + "day", + "T_DSL", + 2020 + ], + [ + "R2", + 2025, + "fall", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "winter", + "day", + "R_NGH", + 2030 + ], + [ + "R1", + 2030, + "winter", + "night", + "T_EV", + 2020 + ], + [ + "R2", + 2030, + "fall", + "day", + "E_NGCC", + 2020 + ], + [ + "R2", + 2030, + "summer", + "day", + "T_BLND", + 2020 + ], + [ + "R1", + 2030, + "summer", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2020, + "winter", + "night", + "T_EV", + 2020 + ], + [ + "R1", + 2020, + "fall", + "night", + "R_EH", + 2020 + ], + [ + "R1", + 2025, + "spring", + "day", + "R_EH", + 2025 + ], + [ + "R2", + 2020, + "spring", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "summer", + "day", + "T_GSL", + 2030 + ], + [ + "R2", + 2020, + "fall", + "night", + "T_DSL", + 2020 + ], + [ + "R2", + 2030, + "winter", + "day", + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2030, + "spring", + "day", + "R_NGH", + 2020 + ], + [ + "R2", + 2030, + "summer", + "night", + "E_NGCC", + 2025 + ], + [ + "R1-R2", + 2030, + "spring", + "night", + "E_TRANS", + 2015 + ], + [ + "R1", + 2030, + "winter", + "day", + "R_NGH", + 2025 + ], + [ + "R1", + 2030, + "winter", + "night", + "T_BLND", + 2020 + ], + [ + "R1", + 2020, + "summer", + "night", + "E_NGCC", + 2020 + ], + [ + "R2", + 2030, + "spring", + "day", + "T_DSL", + 2020 + ], + [ + "R1", + 2025, + "fall", + "day", + "T_GSL", + 2020 + ], + [ + "R1", + 2020, + "spring", + "day", + "T_BLND", + 2020 + ], + [ + "R1-R2", + 2020, + "spring", + "night", + "E_TRANS", + 2015 + ], + [ + "R2", + 2030, + "fall", + "night", + "T_GSL", + 2025 + ], + [ + "R2", + 2025, + "fall", + "night", + "R_NGH", + 2025 + ], + [ + "R1", + 2030, + "winter", + "night", + "T_GSL", + 2030 + ], + [ + "R2", + 2030, + "spring", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2020, + "summer", + "day", + "T_GSL", + 2020 + ], + [ + "R1", + 2030, + "winter", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2020, + "winter", + "day", + "T_GSL", + 2020 + ], + [ + "R2", + 2025, + "spring", + "day", + "T_BLND", + 2020 + ], + [ + "R1", + 2025, + "winter", + "night", + "T_DSL", + 2020 + ], + [ + "R2", + 2025, + "fall", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2030, + "spring", + "night", + "T_GSL", + 2020 + ], + [ + "R2-R1", + 2020, + "fall", + "day", + "E_TRANS", + 2015 + ], + [ + "R1", + 2030, + "spring", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2020, + "fall", + "day", + "T_EV", + 2020 + ], + [ + "R2", + 2025, + "winter", + "day", + "E_NGCC", + 2020 + ], + [ + "R2", + 2025, + "spring", + "night", + "E_NGCC", + 2025 + ], + [ + "R1", + 2030, + "spring", + "night", + "T_DSL", + 2030 + ], + [ + "R2", + 2030, + "winter", + "day", + "R_NGH", + 2025 + ], + [ + "R1", + 2020, + "summer", + "night", + "S_OILREF", + 2020 + ], + [ + "R1", + 2020, + "fall", + "day", + "S_OILREF", + 2020 + ], + [ + "R1", + 2030, + "summer", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2025, + "spring", + "night", + "E_SOLPV", + 2025 + ], + [ + "R1", + 2020, + "fall", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2025, + "spring", + "day", + "R_EH", + 2020 + ], + [ + "R2", + 2020, + "spring", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "winter", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2030, + "summer", + "day", + "T_GSL", + 2025 + ], + [ + "R2", + 2025, + "fall", + "day", + "S_OILREF", + 2020 + ], + [ + "R2", + 2030, + "summer", + "night", + "E_NGCC", + 2020 + ], + [ + "R1", + 2025, + "summer", + "night", + "R_EH", + 2020 + ], + [ + "R1", + 2025, + "spring", + "night", + "T_EV", + 2025 + ], + [ + "R1", + 2030, + "winter", + "day", + "R_NGH", + 2020 + ], + [ + "R1", + 2030, + "winter", + "night", + "R_EH", + 2030 + ], + [ + "R2", + 2020, + "spring", + "night", + "R_NGH", + 2020 + ], + [ + "R1", + 2020, + "winter", + "day", + "R_NGH", + 2020 + ], + [ + "R1", + 2025, + "winter", + "day", + "E_SOLPV", + 2025 + ], + [ + "R2", + 2030, + "fall", + "night", + "T_GSL", + 2020 + ], + [ + "R2", + 2025, + "fall", + "night", + "R_NGH", + 2020 + ], + [ + "R1", + 2030, + "winter", + "night", + "T_GSL", + 2025 + ], + [ + "R2", + 2030, + "spring", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "winter", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "fall", + "night", + "T_DSL", + 2030 + ], + [ + "R1", + 2030, + "fall", + "day", + "T_EV", + 2030 + ], + [ + "R1-R2", + 2025, + "summer", + "night", + "E_TRANS", + 2015 + ], + [ + "R1", + 2020, + "winter", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2025, + "fall", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2025, + "summer", + "day", + "R_NGH", + 2025 + ], + [ + "R2", + 2025, + "spring", + "day", + "T_GSL", + 2025 + ], + [ + "R2", + 2020, + "summer", + "day", + "E_NGCC", + 2020 + ], + [ + "R1", + 2025, + "winter", + "day", + "R_EH", + 2025 + ], + [ + "R2", + 2025, + "spring", + "night", + "E_NGCC", + 2020 + ], + [ + "R2", + 2025, + "summer", + "day", + "T_DSL", + 2025 + ], + [ + "R1", + 2030, + "spring", + "night", + "T_DSL", + 2025 + ], + [ + "R2", + 2025, + "summer", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2030, + "spring", + "day", + "E_SOLPV", + 2030 + ], + [ + "R2", + 2020, + "fall", + "day", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "winter", + "day", + "R_NGH", + 2020 + ], + [ + "R1", + 2025, + "spring", + "night", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2030, + "spring", + "night", + "R_NGH", + 2030 + ], + [ + "R1", + 2030, + "fall", + "day", + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "winter", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "summer", + "day", + "T_GSL", + 2020 + ], + [ + "R1", + 2025, + "summer", + "day", + "T_BLND", + 2020 + ], + [ + "R1", + 2025, + "spring", + "night", + "T_EV", + 2020 + ], + [ + "R2", + 2025, + "winter", + "day", + "T_BLND", + 2020 + ], + [ + "R1", + 2030, + "spring", + "night", + "E_NUCLEAR", + 2030 + ], + [ + "R1", + 2030, + "fall", + "night", + "T_DSL", + 2030 + ], + [ + "R2", + 2025, + "summer", + "night", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2025, + "winter", + "day", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "fall", + "day", + "S_OILREF", + 2020 + ], + [ + "R2-R1", + 2030, + "fall", + "day", + "E_TRANS", + 2015 + ], + [ + "R2-R1", + 2020, + "winter", + "day", + "E_TRANS", + 2015 + ], + [ + "R1", + 2025, + "summer", + "day", + "E_SOLPV", + 2025 + ], + [ + "R2", + 2020, + "fall", + "night", + "T_BLND", + 2020 + ], + [ + "R1", + 2030, + "winter", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "winter", + "night", + "T_GSL", + 2020 + ], + [ + "R2", + 2020, + "summer", + "night", + "T_EV", + 2020 + ], + [ + "R2", + 2025, + "winter", + "night", + "E_NGCC", + 2025 + ], + [ + "R2", + 2030, + "fall", + "night", + "T_DSL", + 2025 + ], + [ + "R1", + 2020, + "winter", + "night", + "T_GSL", + 2020 + ], + [ + "R1", + 2020, + "winter", + "day", + "S_OILREF", + 2020 + ], + [ + "R1", + 2030, + "fall", + "day", + "T_EV", + 2025 + ], + [ + "R1", + 2020, + "summer", + "day", + "T_DSL", + 2020 + ], + [ + "R1", + 2020, + "winter", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2025, + "fall", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_NGCC", + 2030 + ], + [ + "R1", + 2025, + "summer", + "day", + "T_EV", + 2025 + ], + [ + "R1", + 2025, + "fall", + "day", + "R_NGH", + 2025 + ], + [ + "R1", + 2030, + "fall", + "day", + "E_SOLPV", + 2030 + ], + [ + "R2", + 2025, + "spring", + "day", + "T_GSL", + 2020 + ], + [ + "R1", + 2030, + "summer", + "day", + "S_OILREF", + 2020 + ], + [ + "R2", + 2030, + "fall", + "night", + "R_NGH", + 2030 + ], + [ + "R2", + 2025, + "summer", + "day", + "T_DSL", + 2020 + ], + [ + "R1", + 2025, + "winter", + "day", + "R_EH", + 2020 + ], + [ + "R1", + 2025, + "fall", + "day", + "T_DSL", + 2025 + ], + [ + "R1", + 2030, + "spring", + "night", + "T_DSL", + 2020 + ], + [ + "R2", + 2025, + "summer", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "spring", + "day", + "E_SOLPV", + 2025 + ], + [ + "R1", + 2025, + "fall", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R1-R2", + 2025, + "winter", + "day", + "E_TRANS", + 2015 + ], + [ + "R1", + 2025, + "winter", + "night", + "T_BLND", + 2020 + ], + [ + "R1", + 2025, + "winter", + "night", + "T_EV", + 2025 + ], + [ + "R1-R2", + 2025, + "fall", + "day", + "E_TRANS", + 2015 + ], + [ + "R1", + 2020, + "fall", + "night", + "E_NGCC", + 2020 + ], + [ + "R1", + 2025, + "spring", + "day", + "E_NGCC", + 2025 + ], + [ + "R1", + 2030, + "spring", + "night", + "R_NGH", + 2025 + ], + [ + "R2", + 2030, + "winter", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2025, + "summer", + "night", + "E_NGCC", + 2025 + ], + [ + "R1", + 2030, + "summer", + "night", + "T_DSL", + 2030 + ], + [ + "R1", + 2030, + "spring", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2030, + "fall", + "night", + "T_DSL", + 2025 + ], + [ + "R2", + 2030, + "fall", + "day", + "T_GSL", + 2030 + ], + [ + "R1", + 2025, + "summer", + "day", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "summer", + "day", + "R_NGH", + 2030 + ], + [ + "R2", + 2030, + "fall", + "night", + "T_DSL", + 2020 + ], + [ + "R2", + 2025, + "winter", + "night", + "E_NGCC", + 2020 + ], + [ + "R1", + 2025, + "spring", + "day", + "R_NGH", + 2020 + ], + [ + "R1", + 2030, + "spring", + "day", + "E_SOLPV", + 2025 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_NGCC", + 2025 + ], + [ + "R2", + 2030, + "spring", + "day", + "R_EH", + 2030 + ], + [ + "R1", + 2025, + "summer", + "day", + "T_EV", + 2020 + ], + [ + "R2", + 2030, + "summer", + "day", + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2030, + "fall", + "night", + "R_NGH", + 2025 + ], + [ + "R1", + 2030, + "winter", + "night", + "R_NGH", + 2030 + ], + [ + "R1", + 2020, + "summer", + "day", + "R_NGH", + 2020 + ], + [ + "R1", + 2025, + "fall", + "day", + "T_DSL", + 2020 + ], + [ + "R1", + 2025, + "spring", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2025, + "fall", + "night", + "T_GSL", + 2025 + ], + [ + "R1", + 2020, + "spring", + "day", + "T_GSL", + 2020 + ], + [ + "R2-R1", + 2020, + "fall", + "night", + "E_TRANS", + 2015 + ], + [ + "R2", + 2030, + "spring", + "day", + "E_SOLPV", + 2020 + ], + [ + "R1-R2", + 2020, + "fall", + "day", + "E_TRANS", + 2015 + ], + [ + "R1", + 2025, + "winter", + "night", + "T_EV", + 2020 + ], + [ + "R2", + 2020, + "winter", + "day", + "T_DSL", + 2020 + ], + [ + "R1", + 2030, + "winter", + "night", + "E_NUCLEAR", + 2030 + ], + [ + "R1", + 2020, + "summer", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2020, + "summer", + "night", + "R_EH", + 2020 + ], + [ + "R1", + 2030, + "spring", + "night", + "R_NGH", + 2020 + ], + [ + "R1", + 2020, + "winter", + "night", + "R_NGH", + 2020 + ], + [ + "R2", + 2020, + "fall", + "day", + "R_EH", + 2020 + ], + [ + "R1", + 2025, + "summer", + "night", + "E_NGCC", + 2020 + ], + [ + "R2", + 2020, + "spring", + "night", + "S_OILREF", + 2020 + ], + [ + "R1", + 2025, + "summer", + "day", + "R_EH", + 2025 + ], + [ + "R1", + 2030, + "summer", + "night", + "T_DSL", + 2025 + ], + [ + "R1", + 2030, + "spring", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "fall", + "night", + "T_EV", + 2030 + ], + [ + "R2", + 2025, + "fall", + "night", + "S_OILREF", + 2020 + ], + [ + "R2", + 2025, + "fall", + "day", + "E_NGCC", + 2025 + ], + [ + "R1-R2", + 2025, + "fall", + "night", + "E_TRANS", + 2015 + ], + [ + "R2", + 2030, + "fall", + "day", + "T_GSL", + 2025 + ], + [ + "R1", + 2030, + "fall", + "day", + "R_EH", + 2030 + ], + [ + "R2", + 2030, + "summer", + "day", + "R_NGH", + 2025 + ], + [ + "R1", + 2025, + "winter", + "night", + "E_SOLPV", + 2025 + ], + [ + "R1", + 2025, + "spring", + "night", + "R_EH", + 2025 + ], + [ + "R1", + 2030, + "spring", + "day", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "summer", + "day", + "T_DSL", + 2025 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_NGCC", + 2020 + ], + [ + "R2", + 2030, + "summer", + "night", + "T_GSL", + 2030 + ], + [ + "R2", + 2030, + "spring", + "day", + "R_EH", + 2025 + ], + [ + "R2", + 2030, + "summer", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2025, + "spring", + "day", + "S_OILREF", + 2020 + ], + [ + "R2", + 2030, + "fall", + "night", + "R_NGH", + 2020 + ], + [ + "R1", + 2020, + "winter", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "fall", + "night", + "E_NUCLEAR", + 2030 + ], + [ + "R1", + 2025, + "winter", + "day", + "E_NGCC", + 2025 + ], + [ + "R1", + 2025, + "spring", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "winter", + "night", + "R_NGH", + 2025 + ], + [ + "R1", + 2025, + "fall", + "day", + "T_EV", + 2025 + ], + [ + "R2", + 2020, + "fall", + "day", + "R_NGH", + 2020 + ], + [ + "R1", + 2025, + "fall", + "night", + "T_GSL", + 2020 + ], + [ + "R2", + 2030, + "winter", + "day", + "E_SOLPV", + 2030 + ], + [ + "R1", + 2030, + "spring", + "day", + "R_EH", + 2020 + ], + [ + "R1", + 2030, + "winter", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2020, + "summer", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2020, + "winter", + "day", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2025, + "spring", + "day", + "R_NGH", + 2025 + ], + [ + "R1", + 2030, + "spring", + "night", + "T_BLND", + 2020 + ], + [ + "R1", + 2030, + "summer", + "night", + "T_DSL", + 2020 + ], + [ + "R2", + 2020, + "spring", + "day", + "E_NGCC", + 2020 + ], + [ + "R1", + 2025, + "summer", + "day", + "R_EH", + 2020 + ], + [ + "R2", + 2025, + "winter", + "day", + "T_GSL", + 2025 + ], + [ + "R2", + 2020, + "fall", + "night", + "T_EV", + 2020 + ], + [ + "R1", + 2030, + "fall", + "night", + "T_EV", + 2025 + ], + [ + "R1", + 2030, + "spring", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2025, + "fall", + "day", + "E_NGCC", + 2020 + ], + [ + "R2", + 2030, + "winter", + "night", + "E_NGCC", + 2025 + ], + [ + "R2", + 2030, + "winter", + "day", + "R_EH", + 2030 + ], + [ + "R1", + 2030, + "fall", + "day", + "R_EH", + 2025 + ], + [ + "R2", + 2030, + "summer", + "day", + "R_NGH", + 2020 + ], + [ + "R1", + 2020, + "fall", + "night", + "S_OILREF", + 2020 + ], + [ + "R1", + 2025, + "winter", + "night", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2025, + "summer", + "day", + "T_EV", + 2025 + ], + [ + "R1", + 2025, + "spring", + "night", + "R_EH", + 2020 + ], + [ + "R1-R2", + 2020, + "winter", + "day", + "E_TRANS", + 2015 + ], + [ + "R2", + 2030, + "summer", + "day", + "T_DSL", + 2020 + ], + [ + "R1", + 2030, + "fall", + "day", + "T_GSL", + 2020 + ], + [ + "R1-R2", + 2020, + "summer", + "night", + "E_TRANS", + 2015 + ], + [ + "R2", + 2030, + "summer", + "night", + "T_GSL", + 2025 + ], + [ + "R1", + 2030, + "fall", + "day", + "R_NGH", + 2030 + ], + [ + "R2", + 2030, + "spring", + "day", + "R_EH", + 2020 + ], + [ + "R2", + 2030, + "summer", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2020, + "winter", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "fall", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2030, + "spring", + "night", + "E_SOLPV", + 2030 + ], + [ + "R1", + 2025, + "winter", + "day", + "E_NGCC", + 2020 + ], + [ + "R1", + 2030, + "winter", + "night", + "R_NGH", + 2020 + ], + [ + "R1", + 2025, + "fall", + "day", + "T_EV", + 2020 + ], + [ + "R1", + 2030, + "fall", + "day", + "E_NUCLEAR", + 2030 + ], + [ + "R2-R1", + 2030, + "summer", + "day", + "E_TRANS", + 2015 + ], + [ + "R1", + 2025, + "spring", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2030, + "winter", + "day", + "E_SOLPV", + 2025 + ], + [ + "R1", + 2030, + "winter", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "spring", + "day", + "E_NGCC", + 2030 + ], + [ + "R1", + 2020, + "spring", + "day", + "T_DSL", + 2020 + ], + [ + "R2", + 2025, + "summer", + "night", + "E_NGCC", + 2025 + ], + [ + "R2", + 2025, + "winter", + "day", + "T_GSL", + 2020 + ], + [ + "R2", + 2025, + "spring", + "night", + "T_GSL", + 2025 + ], + [ + "R1", + 2030, + "summer", + "day", + "E_NGCC", + 2030 + ], + [ + "R1", + 2030, + "fall", + "night", + "T_EV", + 2020 + ], + [ + "R1", + 2025, + "winter", + "night", + "R_EH", + 2025 + ], + [ + "R2", + 2020, + "winter", + "day", + "T_BLND", + 2020 + ], + [ + "R1", + 2030, + "winter", + "day", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "winter", + "night", + "E_NGCC", + 2020 + ], + [ + "R2-R1", + 2025, + "winter", + "day", + "E_TRANS", + 2015 + ], + [ + "R2", + 2030, + "winter", + "day", + "R_EH", + 2025 + ], + [ + "R2", + 2030, + "fall", + "night", + "E_SOLPV", + 2030 + ], + [ + "R1", + 2025, + "winter", + "day", + "S_OILREF", + 2020 + ], + [ + "R1", + 2030, + "fall", + "day", + "R_EH", + 2020 + ], + [ + "R2-R1", + 2025, + "fall", + "day", + "E_TRANS", + 2015 + ], + [ + "R2", + 2025, + "summer", + "day", + "T_EV", + 2020 + ], + [ + "R2", + 2020, + "summer", + "night", + "R_NGH", + 2020 + ], + [ + "R1", + 2030, + "fall", + "night", + "T_BLND", + 2020 + ], + [ + "R1", + 2030, + "fall", + "day", + "R_NGH", + 2025 + ], + [ + "R1", + 2025, + "summer", + "night", + "S_OILREF", + 2020 + ], + [ + "R2", + 2030, + "spring", + "day", + "E_NGCC", + 2030 + ], + [ + "R2", + 2030, + "summer", + "night", + "T_GSL", + 2020 + ], + [ + "R2", + 2025, + "summer", + "day", + "E_SOLPV", + 2025 + ], + [ + "R1", + 2025, + "summer", + "day", + "R_NGH", + 2025 + ], + [ + "R1", + 2030, + "spring", + "night", + "E_SOLPV", + 2025 + ], + [ + "R2", + 2020, + "summer", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "fall", + "night", + "T_GSL", + 2030 + ], + [ + "R2", + 2030, + "summer", + "night", + "T_DSL", + 2030 + ], + [ + "R2", + 2020, + "fall", + "night", + "R_EH", + 2020 + ], + [ + "R2", + 2020, + "fall", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "fall", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2025, + "fall", + "day", + "R_EH", + 2020 + ], + [ + "R2", + 2030, + "fall", + "day", + "T_DSL", + 2030 + ], + [ + "R2-R1", + 2030, + "fall", + "night", + "E_TRANS", + 2015 + ], + [ + "R1-R2", + 2030, + "fall", + "day", + "E_TRANS", + 2015 + ], + [ + "R2", + 2030, + "winter", + "day", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2025, + "spring", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "winter", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "spring", + "day", + "E_NGCC", + 2025 + ], + [ + "R2", + 2025, + "spring", + "day", + "T_DSL", + 2025 + ], + [ + "R1", + 2020, + "winter", + "night", + "S_OILREF", + 2020 + ], + [ + "R1", + 2030, + "summer", + "night", + "T_EV", + 2030 + ], + [ + "R2", + 2025, + "summer", + "night", + "E_NGCC", + 2020 + ], + [ + "R2", + 2025, + "summer", + "day", + "R_EH", + 2025 + ], + [ + "R1", + 2025, + "spring", + "night", + "R_NGH", + 2025 + ], + [ + "R2", + 2020, + "summer", + "day", + "T_GSL", + 2020 + ], + [ + "R1", + 2020, + "spring", + "day", + "R_NGH", + 2020 + ], + [ + "R1", + 2030, + "summer", + "day", + "E_NGCC", + 2025 + ], + [ + "R2", + 2025, + "spring", + "night", + "T_GSL", + 2020 + ], + [ + "R2", + 2030, + "winter", + "night", + "T_EV", + 2030 + ], + [ + "R1", + 2025, + "winter", + "night", + "R_EH", + 2020 + ], + [ + "R1-R2", + 2030, + "summer", + "night", + "E_TRANS", + 2015 + ], + [ + "R1", + 2025, + "fall", + "night", + "T_DSL", + 2025 + ], + [ + "R2", + 2030, + "winter", + "day", + "R_EH", + 2020 + ], + [ + "R2", + 2030, + "fall", + "night", + "E_SOLPV", + 2025 + ], + [ + "R1", + 2020, + "spring", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2020, + "fall", + "day", + "T_DSL", + 2020 + ], + [ + "R1", + 2030, + "winter", + "night", + "E_SOLPV", + 2030 + ], + [ + "R1", + 2020, + "summer", + "day", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2030, + "summer", + "night", + "T_BLND", + 2020 + ], + [ + "R1", + 2030, + "spring", + "night", + "R_EH", + 2030 + ], + [ + "R2", + 2030, + "summer", + "day", + "T_EV", + 2020 + ], + [ + "R1", + 2030, + "fall", + "day", + "R_NGH", + 2020 + ], + [ + "R2", + 2030, + "fall", + "night", + "T_EV", + 2025 + ], + [ + "R2", + 2030, + "spring", + "day", + "E_NGCC", + 2025 + ], + [ + "R2", + 2025, + "summer", + "day", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2030, + "winter", + "day", + "E_NGCC", + 2030 + ], + [ + "R1", + 2025, + "summer", + "day", + "R_NGH", + 2020 + ], + [ + "R1", + 2025, + "fall", + "day", + "E_SOLPV", + 2025 + ], + [ + "R2", + 2020, + "fall", + "day", + "S_OILREF", + 2020 + ], + [ + "R2", + 2020, + "winter", + "day", + "T_EV", + 2020 + ], + [ + "R2", + 2020, + "summer", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "fall", + "night", + "T_GSL", + 2025 + ], + [ + "R1", + 2020, + "winter", + "night", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "summer", + "night", + "T_DSL", + 2025 + ], + [ + "R2", + 2020, + "fall", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "fall", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "spring", + "night", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "fall", + "day", + "T_DSL", + 2025 + ], + [ + "R1", + 2025, + "spring", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2025, + "winter", + "night", + "T_GSL", + 2025 + ], + [ + "R1", + 2030, + "summer", + "night", + "T_EV", + 2025 + ], + [ + "R2-R1", + 2030, + "winter", + "night", + "E_TRANS", + 2015 + ], + [ + "R2", + 2025, + "spring", + "day", + "T_DSL", + 2020 + ], + [ + "R2", + 2030, + "summer", + "night", + "R_NGH", + 2030 + ], + [ + "R1", + 2030, + "spring", + "day", + "E_NGCC", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "T_GSL", + 2030 + ], + [ + "R2", + 2025, + "summer", + "day", + "R_EH", + 2020 + ], + [ + "R1", + 2025, + "spring", + "night", + "R_NGH", + 2020 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_SOLPV", + 2030 + ], + [ + "R1", + 2025, + "fall", + "day", + "R_EH", + 2025 + ], + [ + "R2", + 2030, + "fall", + "night", + "R_EH", + 2030 + ], + [ + "R1-R2", + 2030, + "winter", + "night", + "E_TRANS", + 2015 + ], + [ + "R2", + 2030, + "summer", + "night", + "E_NUCLEAR", + 2030 + ], + [ + "R1", + 2030, + "summer", + "day", + "E_NGCC", + 2020 + ], + [ + "R1", + 2025, + "fall", + "night", + "T_DSL", + 2020 + ], + [ + "R2", + 2025, + "spring", + "night", + "T_DSL", + 2025 + ], + [ + "R2", + 2030, + "winter", + "day", + "E_NGCC", + 2030 + ], + [ + "R1", + 2020, + "spring", + "night", + "T_GSL", + 2020 + ], + [ + "R1-R2", + 2020, + "fall", + "night", + "E_TRANS", + 2015 + ], + [ + "R2", + 2030, + "fall", + "night", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2020, + "spring", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "winter", + "night", + "E_SOLPV", + 2025 + ], + [ + "R1", + 2030, + "summer", + "night", + "R_EH", + 2030 + ], + [ + "R1", + 2030, + "spring", + "night", + "R_EH", + 2025 + ], + [ + "R2", + 2030, + "summer", + "day", + "E_SOLPV", + 2030 + ], + [ + "R2", + 2025, + "fall", + "day", + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "fall", + "night", + "T_EV", + 2020 + ], + [ + "R2", + 2030, + "spring", + "day", + "E_NGCC", + 2020 + ], + [ + "R1", + 2030, + "summer", + "night", + "T_GSL", + 2025 + ], + [ + "R1", + 2030, + "winter", + "day", + "E_NGCC", + 2025 + ], + [ + "R2", + 2025, + "winter", + "day", + "T_DSL", + 2025 + ], + [ + "R1", + 2025, + "fall", + "day", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2025, + "summer", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2030, + "summer", + "night", + "T_DSL", + 2020 + ], + [ + "R1", + 2030, + "fall", + "night", + "T_GSL", + 2020 + ], + [ + "R1", + 2030, + "fall", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2025, + "winter", + "night", + "R_NGH", + 2025 + ], + [ + "R2", + 2025, + "fall", + "night", + "E_NGCC", + 2025 + ], + [ + "R2", + 2030, + "fall", + "day", + "T_DSL", + 2020 + ], + [ + "R2", + 2020, + "winter", + "day", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "summer", + "day", + "R_EH", + 2030 + ], + [ + "R2", + 2025, + "winter", + "night", + "T_GSL", + 2020 + ], + [ + "R1", + 2030, + "summer", + "night", + "T_EV", + 2020 + ], + [ + "R2", + 2025, + "spring", + "day", + "T_EV", + 2025 + ], + [ + "R1", + 2025, + "winter", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2030, + "spring", + "night", + "T_GSL", + 2025 + ], + [ + "R1", + 2025, + "fall", + "night", + "E_SOLPV", + 2025 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_SOLPV", + 2025 + ], + [ + "R1", + 2025, + "fall", + "day", + "R_EH", + 2020 + ], + [ + "R2-R1", + 2025, + "fall", + "night", + "E_TRANS", + 2015 + ], + [ + "R2", + 2030, + "fall", + "night", + "R_EH", + 2025 + ], + [ + "R1", + 2025, + "spring", + "night", + "S_OILREF", + 2020 + ], + [ + "R1", + 2020, + "summer", + "day", + "R_EH", + 2020 + ], + [ + "R1", + 2025, + "fall", + "night", + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "spring", + "day", + "S_OILREF", + 2020 + ], + [ + "R2", + 2020, + "winter", + "day", + "R_EH", + 2020 + ], + [ + "R2", + 2020, + "summer", + "day", + "T_DSL", + 2020 + ], + [ + "R1", + 2025, + "fall", + "night", + "T_EV", + 2025 + ], + [ + "R2", + 2025, + "spring", + "night", + "T_DSL", + 2020 + ], + [ + "R2", + 2030, + "winter", + "day", + "E_NGCC", + 2025 + ], + [ + "R2", + 2020, + "fall", + "night", + "R_NGH", + 2020 + ], + [ + "R2", + 2020, + "winter", + "night", + "T_BLND", + 2020 + ], + [ + "R1", + 2030, + "winter", + "night", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2020, + "summer", + "night", + "S_OILREF", + 2020 + ], + [ + "R1", + 2030, + "spring", + "night", + "R_EH", + 2020 + ], + [ + "R2", + 2025, + "summer", + "night", + "S_OILREF", + 2020 + ], + [ + "R2", + 2030, + "summer", + "day", + "E_SOLPV", + 2025 + ], + [ + "R2", + 2020, + "fall", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "summer", + "night", + "R_EH", + 2025 + ], + [ + "R1-R2", + 2020, + "summer", + "day", + "E_TRANS", + 2015 + ], + [ + "R1", + 2030, + "summer", + "night", + "T_GSL", + 2020 + ], + [ + "R2", + 2025, + "winter", + "day", + "T_DSL", + 2020 + ], + [ + "R2", + 2020, + "spring", + "night", + "E_NGCC", + 2020 + ], + [ + "R1", + 2030, + "winter", + "day", + "E_NGCC", + 2020 + ], + [ + "R1", + 2025, + "summer", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2020, + "fall", + "day", + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "winter", + "night", + "T_GSL", + 2030 + ], + [ + "R1", + 2020, + "winter", + "day", + "E_NGCC", + 2020 + ], + [ + "R2", + 2030, + "fall", + "day", + "T_BLND", + 2020 + ], + [ + "R1", + 2025, + "winter", + "night", + "R_NGH", + 2020 + ], + [ + "R2", + 2025, + "fall", + "night", + "E_NGCC", + 2020 + ], + [ + "R2", + 2030, + "summer", + "night", + "E_SOLPV", + 2030 + ], + [ + "R2-R1", + 2025, + "summer", + "day", + "E_TRANS", + 2015 + ], + [ + "R2", + 2030, + "summer", + "day", + "R_EH", + 2025 + ], + [ + "R2", + 2025, + "spring", + "day", + "T_EV", + 2020 + ], + [ + "R1", + 2025, + "winter", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "T_GSL", + 2020 + ], + [ + "R2", + 2025, + "summer", + "day", + "E_NGCC", + 2025 + ], + [ + "R1", + 2025, + "fall", + "night", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "summer", + "night", + "T_EV", + 2030 + ], + [ + "R2", + 2025, + "spring", + "day", + "E_SOLPV", + 2025 + ], + [ + "R1", + 2030, + "fall", + "night", + "R_NGH", + 2030 + ], + [ + "R2", + 2030, + "fall", + "night", + "R_EH", + 2020 + ], + [ + "R1", + 2030, + "winter", + "night", + "R_EH", + 2025 + ], + [ + "R2", + 2020, + "summer", + "night", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2025, + "fall", + "night", + "T_EV", + 2020 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2030, + "winter", + "day", + "E_NGCC", + 2020 + ], + [ + "R1", + 2030, + "spring", + "day", + "S_OILREF", + 2020 + ], + [ + "R2", + 2020, + "winter", + "night", + "T_EV", + 2020 + ], + [ + "R1", + 2020, + "spring", + "night", + "T_DSL", + 2020 + ], + [ + "R1", + 2030, + "spring", + "night", + "E_NGCC", + 2030 + ], + [ + "R2", + 2030, + "summer", + "day", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2020, + "fall", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2025, + "spring", + "day", + "R_EH", + 2025 + ], + [ + "R2", + 2020, + "summer", + "day", + "R_NGH", + 2020 + ], + [ + "R2", + 2025, + "summer", + "day", + "R_NGH", + 2020 + ], + [ + "R2", + 2020, + "spring", + "day", + "T_GSL", + 2020 + ], + [ + "R2", + 2030, + "fall", + "day", + "T_EV", + 2030 + ], + [ + "R1", + 2025, + "summer", + "day", + "S_OILREF", + 2020 + ], + [ + "R2", + 2025, + "winter", + "day", + "T_EV", + 2025 + ], + [ + "R1", + 2025, + "summer", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2020, + "summer", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "winter", + "night", + "T_GSL", + 2025 + ], + [ + "R2", + 2030, + "summer", + "night", + "E_SOLPV", + 2025 + ], + [ + "R1", + 2020, + "spring", + "day", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "summer", + "day", + "R_EH", + 2020 + ], + [ + "R1", + 2025, + "winter", + "night", + "S_OILREF", + 2020 + ], + [ + "R2", + 2030, + "winter", + "day", + "S_OILREF", + 2020 + ], + [ + "R1", + 2025, + "winter", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "summer", + "night", + "R_NGH", + 2030 + ], + [ + "R2", + 2030, + "summer", + "night", + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "summer", + "night", + "T_EV", + 2025 + ], + [ + "R2", + 2025, + "spring", + "day", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2030, + "fall", + "night", + "R_NGH", + 2025 + ], + [ + "R1", + 2020, + "spring", + "day", + "T_EV", + 2020 + ], + [ + "R2", + 2030, + "fall", + "night", + "E_NGCC", + 2030 + ], + [ + "R1", + 2030, + "winter", + "night", + "R_EH", + 2020 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_NUCLEAR", + 2030 + ], + [ + "R1", + 2020, + "winter", + "night", + "R_EH", + 2020 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R1-R2", + 2030, + "fall", + "night", + "E_TRANS", + 2015 + ], + [ + "R1", + 2030, + "fall", + "day", + "T_EV", + 2020 + ], + [ + "R1", + 2030, + "spring", + "night", + "E_NGCC", + 2025 + ], + [ + "R2", + 2025, + "summer", + "night", + "T_GSL", + 2025 + ], + [ + "R2", + 2025, + "spring", + "day", + "R_EH", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "T_DSL", + 2030 + ], + [ + "R2", + 2030, + "fall", + "day", + "T_EV", + 2025 + ], + [ + "R2", + 2020, + "summer", + "day", + "T_BLND", + 2020 + ], + [ + "R2", + 2025, + "spring", + "night", + "T_BLND", + 2020 + ], + [ + "R1", + 2030, + "summer", + "day", + "T_GSL", + 2030 + ], + [ + "R2", + 2025, + "winter", + "day", + "T_EV", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_NUCLEAR", + 2030 + ], + [ + "R1", + 2030, + "fall", + "day", + "E_SOLPV", + 2025 + ], + [ + "R1", + 2025, + "fall", + "day", + "R_NGH", + 2020 + ], + [ + "R2", + 2030, + "winter", + "night", + "T_GSL", + 2020 + ], + [ + "R2", + 2025, + "summer", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2020, + "winter", + "day", + "R_NGH", + 2020 + ], + [ + "R2", + 2025, + "winter", + "day", + "E_SOLPV", + 2025 + ], + [ + "R1", + 2025, + "fall", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "summer", + "night", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "summer", + "day", + "E_NGCC", + 2030 + ], + [ + "R1", + 2020, + "fall", + "day", + "T_GSL", + 2020 + ], + [ + "R1", + 2030, + "summer", + "night", + "R_NGH", + 2025 + ], + [ + "R1", + 2025, + "spring", + "day", + "E_NGCC", + 2020 + ], + [ + "R2", + 2030, + "summer", + "night", + "T_EV", + 2020 + ], + [ + "R1", + 2025, + "summer", + "night", + "T_DSL", + 2025 + ], + [ + "R1", + 2030, + "fall", + "night", + "R_NGH", + 2020 + ], + [ + "R1", + 2030, + "winter", + "day", + "S_OILREF", + 2020 + ], + [ + "R2", + 2030, + "fall", + "night", + "E_NGCC", + 2025 + ], + [ + "R2", + 2030, + "fall", + "day", + "R_EH", + 2030 + ], + [ + "R1", + 2030, + "winter", + "night", + "E_NGCC", + 2030 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2020, + "summer", + "day", + "E_NGCC", + 2020 + ], + [ + "R2", + 2020, + "fall", + "night", + "S_OILREF", + 2020 + ], + [ + "R1", + 2030, + "fall", + "night", + "T_DSL", + 2020 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2020, + "spring", + "night", + "T_EV", + 2020 + ], + [ + "R1", + 2030, + "spring", + "night", + "E_NGCC", + 2020 + ], + [ + "R2", + 2025, + "summer", + "night", + "T_GSL", + 2020 + ], + [ + "R1", + 2020, + "winter", + "night", + "E_NGCC", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "T_DSL", + 2025 + ], + [ + "R2", + 2030, + "fall", + "day", + "T_EV", + 2020 + ], + [ + "R1", + 2025, + "fall", + "night", + "R_EH", + 2025 + ], + [ + "R1", + 2020, + "spring", + "day", + "R_EH", + 2020 + ], + [ + "R1", + 2030, + "summer", + "day", + "T_GSL", + 2025 + ], + [ + "R1", + 2030, + "fall", + "day", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2025, + "fall", + "day", + "S_OILREF", + 2020 + ], + [ + "R1", + 2020, + "spring", + "night", + "T_BLND", + 2020 + ], + [ + "R2", + 2025, + "winter", + "day", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2025, + "fall", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2020, + "summer", + "day", + "S_OILREF", + 2020 + ], + [ + "R2", + 2030, + "summer", + "day", + "E_NGCC", + 2025 + ], + [ + "R2", + 2025, + "fall", + "day", + "T_GSL", + 2025 + ], + [ + "R2", + 2020, + "winter", + "night", + "T_GSL", + 2020 + ], + [ + "R2", + 2020, + "fall", + "night", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2030, + "summer", + "night", + "R_NGH", + 2020 + ], + [ + "R1", + 2025, + "summer", + "night", + "T_DSL", + 2020 + ], + [ + "R2", + 2025, + "fall", + "day", + "R_NGH", + 2025 + ], + [ + "R2", + 2030, + "winter", + "night", + "R_NGH", + 2030 + ], + [ + "R1", + 2030, + "winter", + "day", + "T_GSL", + 2030 + ], + [ + "R1", + 2030, + "spring", + "night", + "S_OILREF", + 2020 + ], + [ + "R2", + 2030, + "fall", + "night", + "E_NGCC", + 2020 + ], + [ + "R2", + 2030, + "fall", + "day", + "R_EH", + 2025 + ], + [ + "R1", + 2030, + "winter", + "night", + "E_NGCC", + 2025 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2025, + "winter", + "night", + "T_DSL", + 2025 + ], + [ + "R2", + 2020, + "fall", + "day", + "E_NGCC", + 2020 + ], + [ + "R2", + 2025, + "spring", + "night", + "E_SOLPV", + 2025 + ], + [ + "R2", + 2030, + "winter", + "night", + "T_DSL", + 2030 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "fall", + "day", + "T_GSL", + 2020 + ], + [ + "R2", + 2030, + "winter", + "night", + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2030, + "summer", + "night", + "R_EH", + 2030 + ], + [ + "R2", + 2025, + "spring", + "night", + "T_EV", + 2025 + ], + [ + "R2", + 2025, + "spring", + "day", + "E_NGCC", + 2025 + ], + [ + "R2", + 2025, + "summer", + "day", + "S_OILREF", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "T_EV", + 2030 + ], + [ + "R2", + 2030, + "spring", + "night", + "T_DSL", + 2020 + ], + [ + "R1-R2", + 2025, + "summer", + "day", + "E_TRANS", + 2015 + ], + [ + "R1", + 2025, + "fall", + "night", + "R_EH", + 2020 + ], + [ + "R1", + 2020, + "summer", + "night", + "T_GSL", + 2020 + ], + [ + "R1", + 2030, + "summer", + "day", + "T_GSL", + 2020 + ], + [ + "R2", + 2020, + "winter", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2-R1", + 2025, + "spring", + "day", + "E_TRANS", + 2015 + ], + [ + "R2", + 2025, + "fall", + "day", + "T_GSL", + 2020 + ], + [ + "R2", + 2025, + "winter", + "day", + "R_EH", + 2025 + ], + [ + "R2", + 2025, + "spring", + "day", + "R_NGH", + 2020 + ], + [ + "R1", + 2030, + "fall", + "day", + "E_NGCC", + 2030 + ], + [ + "R1", + 2025, + "summer", + "night", + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "winter", + "night", + "R_NGH", + 2025 + ], + [ + "R1", + 2030, + "winter", + "day", + "T_GSL", + 2025 + ], + [ + "R2", + 2030, + "fall", + "day", + "R_EH", + 2020 + ], + [ + "R2", + 2025, + "winter", + "night", + "T_DSL", + 2020 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2020, + "summer", + "day", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2030, + "winter", + "night", + "E_NGCC", + 2020 + ], + [ + "R2", + 2030, + "winter", + "night", + "T_DSL", + 2025 + ], + [ + "R2", + 2025, + "fall", + "night", + "T_GSL", + 2025 + ], + [ + "R2", + 2030, + "winter", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R2-R1", + 2025, + "summer", + "night", + "E_TRANS", + 2015 + ], + [ + "R2", + 2030, + "summer", + "night", + "R_EH", + 2025 + ], + [ + "R2", + 2020, + "summer", + "day", + "T_EV", + 2020 + ], + [ + "R2", + 2025, + "spring", + "night", + "T_EV", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "T_EV", + 2025 + ], + [ + "R2", + 2020, + "spring", + "day", + "T_DSL", + 2020 + ], + [ + "R2", + 2030, + "summer", + "day", + "S_OILREF", + 2020 + ], + [ + "R2", + 2030, + "summer", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "fall", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "fall", + "day", + "R_NGH", + 2030 + ], + [ + "R2", + 2025, + "winter", + "night", + "T_BLND", + 2020 + ], + [ + "R2", + 2020, + "winter", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "winter", + "night", + "S_OILREF", + 2020 + ], + [ + "R1", + 2030, + "spring", + "day", + "T_DSL", + 2030 + ], + [ + "R2", + 2025, + "winter", + "night", + "E_SOLPV", + 2025 + ], + [ + "R2", + 2020, + "summer", + "night", + "E_NGCC", + 2020 + ], + [ + "R2", + 2025, + "summer", + "night", + "T_DSL", + 2025 + ], + [ + "R2", + 2025, + "winter", + "day", + "R_EH", + 2020 + ], + [ + "R2", + 2025, + "spring", + "night", + "R_EH", + 2025 + ], + [ + "R2", + 2025, + "spring", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2030, + "fall", + "day", + "E_NGCC", + 2025 + ], + [ + "R2", + 2025, + "fall", + "day", + "T_DSL", + 2025 + ], + [ + "R2", + 2020, + "spring", + "day", + "T_BLND", + 2020 + ], + [ + "R2", + 2020, + "winter", + "night", + "T_DSL", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_SOLPV", + 2030 + ], + [ + "R2", + 2020, + "spring", + "night", + "T_GSL", + 2020 + ], + [ + "R1", + 2025, + "summer", + "day", + "E_NGCC", + 2025 + ], + [ + "R1", + 2030, + "summer", + "day", + "T_DSL", + 2030 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_SOLPV", + 2030 + ], + [ + "R2", + 2025, + "winter", + "night", + "T_EV", + 2025 + ], + [ + "R1", + 2025, + "fall", + "night", + "R_NGH", + 2025 + ], + [ + "R1", + 2020, + "winter", + "day", + "T_GSL", + 2020 + ], + [ + "R2", + 2030, + "winter", + "night", + "T_DSL", + 2020 + ], + [ + "R1", + 2020, + "fall", + "day", + "R_NGH", + 2020 + ], + [ + "R2", + 2025, + "fall", + "night", + "T_GSL", + 2020 + ], + [ + "R1", + 2025, + "fall", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2020, + "spring", + "night", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "summer", + "night", + "R_EH", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "T_EV", + 2020 + ], + [ + "R1", + 2025, + "spring", + "night", + "E_NGCC", + 2025 + ], + [ + "R1", + 2030, + "fall", + "night", + "R_EH", + 2030 + ], + [ + "R2", + 2030, + "spring", + "day", + "T_DSL", + 2030 + ], + [ + "R2", + 2030, + "fall", + "night", + "S_OILREF", + 2020 + ], + [ + "R2-R1", + 2020, + "winter", + "night", + "E_TRANS", + 2015 + ], + [ + "R1", + 2020, + "spring", + "day", + "E_NGCC", + 2020 + ], + [ + "R1", + 2025, + "winter", + "day", + "T_EV", + 2025 + ], + [ + "R2", + 2030, + "fall", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "fall", + "day", + "R_NGH", + 2025 + ], + [ + "R1", + 2020, + "summer", + "night", + "T_DSL", + 2020 + ], + [ + "R1", + 2025, + "summer", + "night", + "T_EV", + 2025 + ], + [ + "R1", + 2030, + "spring", + "day", + "T_DSL", + 2025 + ], + [ + "R2", + 2025, + "winter", + "night", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2025, + "summer", + "night", + "T_DSL", + 2020 + ], + [ + "R2", + 2020, + "summer", + "day", + "R_EH", + 2020 + ], + [ + "R2", + 2025, + "spring", + "night", + "R_EH", + 2020 + ], + [ + "R2", + 2025, + "spring", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2025, + "fall", + "day", + "T_DSL", + 2020 + ], + [ + "R1", + 2030, + "fall", + "day", + "E_NGCC", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_SOLPV", + 2025 + ], + [ + "R1-R2", + 2025, + "winter", + "night", + "E_TRANS", + 2015 + ], + [ + "R1", + 2025, + "summer", + "day", + "E_NGCC", + 2020 + ], + [ + "R1", + 2030, + "summer", + "day", + "T_DSL", + 2025 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_SOLPV", + 2025 + ], + [ + "R2", + 2025, + "winter", + "night", + "T_EV", + 2020 + ], + [ + "R1", + 2025, + "fall", + "night", + "R_NGH", + 2020 + ], + [ + "R2", + 2030, + "winter", + "night", + "T_EV", + 2025 + ], + [ + "R2", + 2020, + "winter", + "night", + "R_NGH", + 2020 + ], + [ + "R1", + 2025, + "fall", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2020, + "fall", + "night", + "T_GSL", + 2020 + ], + [ + "R1", + 2025, + "spring", + "day", + "T_GSL", + 2025 + ], + [ + "R2-R1", + 2020, + "spring", + "day", + "E_TRANS", + 2015 + ], + [ + "R2", + 2020, + "winter", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2025, + "spring", + "night", + "E_NGCC", + 2020 + ], + [ + "R2", + 2025, + "winter", + "day", + "R_NGH", + 2025 + ], + [ + "R2", + 2020, + "fall", + "day", + "T_BLND", + 2020 + ], + [ + "R1", + 2025, + "summer", + "night", + "T_GSL", + 2025 + ], + [ + "R1", + 2030, + "fall", + "night", + "R_EH", + 2025 + ], + [ + "R2", + 2030, + "spring", + "day", + "T_DSL", + 2025 + ], + [ + "R1", + 2030, + "winter", + "day", + "T_DSL", + 2030 + ], + [ + "R2", + 2030, + "fall", + "day", + "R_NGH", + 2020 + ], + [ + "R2", + 2030, + "fall", + "day", + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2025, + "winter", + "night", + "R_EH", + 2025 + ], + [ + "R2", + 2025, + "winter", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2030, + "winter", + "night", + "E_SOLPV", + 2030 + ], + [ + "R2", + 2030, + "spring", + "night", + "R_EH", + 2030 + ], + [ + "R1", + 2025, + "summer", + "night", + "T_EV", + 2020 + ], + [ + "R1", + 2030, + "spring", + "day", + "T_EV", + 2030 + ], + [ + "R1", + 2030, + "spring", + "day", + "T_DSL", + 2020 + ], + [ + "R2", + 2030, + "summer", + "night", + "R_NGH", + 2025 + ], + [ + "R2", + 2025, + "spring", + "day", + "S_OILREF", + 2020 + ], + [ + "R1-R2", + 2025, + "spring", + "day", + "E_TRANS", + 2015 + ], + [ + "R1", + 2020, + "summer", + "night", + "R_NGH", + 2020 + ], + [ + "R2", + 2025, + "fall", + "day", + "T_EV", + 2025 + ], + [ + "R2", + 2025, + "spring", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2025, + "winter", + "day", + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2030, + "summer", + "day", + "T_DSL", + 2020 + ], + [ + "R2", + 2030, + "summer", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2020, + "spring", + "night", + "R_EH", + 2020 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "winter", + "night", + "T_EV", + 2020 + ], + [ + "R1", + 2025, + "winter", + "night", + "E_NGCC", + 2025 + ], + [ + "R2", + 2020, + "spring", + "night", + "T_DSL", + 2020 + ], + [ + "R2", + 2030, + "winter", + "day", + "T_DSL", + 2030 + ], + [ + "R1", + 2025, + "fall", + "night", + "S_OILREF", + 2020 + ], + [ + "R1", + 2020, + "fall", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2025, + "fall", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2025, + "summer", + "night", + "R_EH", + 2025 + ], + [ + "R2", + 2020, + "winter", + "night", + "S_OILREF", + 2020 + ], + [ + "R1", + 2025, + "spring", + "day", + "T_GSL", + 2020 + ], + [ + "R2", + 2020, + "winter", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "spring", + "day", + "T_EV", + 2030 + ], + [ + "R1", + 2030, + "fall", + "night", + "R_EH", + 2020 + ], + [ + "R2", + 2025, + "spring", + "night", + "R_NGH", + 2025 + ], + [ + "R1", + 2025, + "summer", + "night", + "T_GSL", + 2020 + ], + [ + "R2", + 2030, + "winter", + "night", + "T_BLND", + 2020 + ], + [ + "R2", + 2025, + "winter", + "day", + "R_NGH", + 2020 + ], + [ + "R1", + 2030, + "winter", + "day", + "T_DSL", + 2025 + ], + [ + "R2", + 2020, + "spring", + "day", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "fall", + "day", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2025, + "winter", + "night", + "R_EH", + 2020 + ], + [ + "R2", + 2025, + "winter", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2025, + "spring", + "night", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2020, + "fall", + "night", + "E_NGCC", + 2020 + ], + [ + "R2", + 2025, + "fall", + "night", + "T_DSL", + 2025 + ], + [ + "R2", + 2030, + "winter", + "night", + "E_SOLPV", + 2025 + ], + [ + "R2-R1", + 2020, + "summer", + "day", + "E_TRANS", + 2015 + ], + [ + "R2", + 2030, + "spring", + "night", + "R_EH", + 2025 + ], + [ + "R2", + 2020, + "spring", + "day", + "T_EV", + 2020 + ], + [ + "R1", + 2030, + "spring", + "day", + "T_EV", + 2025 + ], + [ + "R2", + 2030, + "summer", + "night", + "R_NGH", + 2020 + ], + [ + "R2", + 2025, + "fall", + "day", + "T_EV", + 2020 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2020, + "summer", + "night", + "T_BLND", + 2020 + ], + [ + "R1", + 2020, + "spring", + "day", + "S_OILREF", + 2020 + ], + [ + "R2", + 2030, + "summer", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2025, + "winter", + "day", + "T_GSL", + 2025 + ], + [ + "R2", + 2025, + "fall", + "day", + "E_SOLPV", + 2025 + ], + [ + "R1", + 2025, + "winter", + "night", + "E_NGCC", + 2020 + ], + [ + "R2", + 2030, + "winter", + "day", + "T_DSL", + 2025 + ], + [ + "R2", + 2025, + "summer", + "night", + "T_BLND", + 2020 + ], + [ + "R1", + 2020, + "spring", + "night", + "R_NGH", + 2020 + ], + [ + "R2-R1", + 2030, + "summer", + "night", + "E_TRANS", + 2015 + ], + [ + "R2", + 2030, + "fall", + "day", + "E_SOLPV", + 2030 + ], + [ + "R1", + 2030, + "summer", + "night", + "R_EH", + 2020 + ], + [ + "R2", + 2030, + "spring", + "day", + "T_EV", + 2025 + ], + [ + "R1", + 2020, + "fall", + "night", + "T_DSL", + 2020 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_NGCC", + 2030 + ], + [ + "R2", + 2025, + "spring", + "night", + "R_NGH", + 2020 + ], + [ + "R1", + 2020, + "spring", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "winter", + "night", + "R_EH", + 2030 + ], + [ + "R2", + 2025, + "summer", + "night", + "E_SOLPV", + 2025 + ], + [ + "R1", + 2030, + "winter", + "day", + "T_DSL", + 2020 + ], + [ + "R2", + 2025, + "winter", + "day", + "S_OILREF", + 2020 + ], + [ + "R2", + 2030, + "fall", + "day", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2020, + "winter", + "day", + "T_DSL", + 2020 + ], + [ + "R2", + 2025, + "winter", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2025, + "spring", + "night", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2025, + "fall", + "night", + "T_DSL", + 2020 + ], + [ + "R2", + 2025, + "summer", + "night", + "T_EV", + 2025 + ], + [ + "R1-R2", + 2020, + "winter", + "night", + "E_TRANS", + 2015 + ], + [ + "R2", + 2030, + "winter", + "night", + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "R_EH", + 2020 + ], + [ + "R1", + 2030, + "spring", + "day", + "T_EV", + 2020 + ], + [ + "R1", + 2030, + "summer", + "day", + "T_EV", + 2030 + ], + [ + "R2", + 2025, + "summer", + "day", + "E_NGCC", + 2020 + ], + [ + "R1", + 2025, + "fall", + "day", + "E_NGCC", + 2025 + ], + [ + "R2", + 2030, + "summer", + "night", + "S_OILREF", + 2020 + ], + [ + "R1", + 2020, + "summer", + "night", + "T_EV", + 2020 + ], + [ + "R2", + 2030, + "summer", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2025, + "winter", + "day", + "T_GSL", + 2020 + ], + [ + "R1", + 2020, + "fall", + "day", + "T_EV", + 2020 + ], + [ + "R2", + 2025, + "fall", + "day", + "E_SOLPV", + 2020 + ], + [ + "R1", + 2030, + "spring", + "day", + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "winter", + "day", + "T_EV", + 2030 + ], + [ + "R2", + 2030, + "winter", + "day", + "T_DSL", + 2020 + ], + [ + "R2", + 2025, + "winter", + "night", + "R_NGH", + 2025 + ], + [ + "R1-R2", + 2030, + "summer", + "day", + "E_TRANS", + 2015 + ], + [ + "R2", + 2030, + "fall", + "day", + "E_SOLPV", + 2025 + ], + [ + "R2", + 2030, + "spring", + "night", + "R_NGH", + 2030 + ], + [ + "R1", + 2030, + "spring", + "day", + "T_GSL", + 2030 + ], + [ + "R2", + 2020, + "spring", + "day", + "R_EH", + 2020 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_NGCC", + 2030 + ], + [ + "R1", + 2030, + "summer", + "day", + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "spring", + "day", + "T_EV", + 2020 + ], + [ + "R2-R1", + 2030, + "spring", + "day", + "E_TRANS", + 2015 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_NGCC", + 2025 + ], + [ + "R2-R1", + 2025, + "winter", + "night", + "E_TRANS", + 2015 + ], + [ + "R2", + 2020, + "spring", + "night", + "T_BLND", + 2020 + ], + [ + "R1", + 2020, + "spring", + "night", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "winter", + "night", + "R_EH", + 2025 + ], + [ + "R1", + 2020, + "winter", + "day", + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "fall", + "day", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2020, + "summer", + "day", + "E_NUCLEAR", + 2015 + ] + ], + "CapacityFactor_rpsdt": [ + [ + "R1", + 2020, + "winter", + "night", + "E_NUCLEAR" + ], + [ + "R2", + 2030, + "spring", + "night", + "E_SOLPV" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_EV" + ], + [ + "R1", + 2020, + "fall", + "day", + "E_NGCC" + ], + [ + "R2", + 2025, + "winter", + "day", + "R_EH" + ], + [ + "R1", + 2025, + "fall", + "day", + "T_DSL" + ], + [ + "R2", + 2030, + "fall", + "night", + "R_NGH" + ], + [ + "R1", + 2030, + "summer", + "night", + "T_EV" + ], + [ + "R2", + 2030, + "fall", + "night", + "E_NUCLEAR" + ], + [ + "R2-R1", + 2030, + "spring", + "day", + "E_TRANS" + ], + [ + "R2", + 2025, + "spring", + "night", + "T_EV" + ], + [ + "R2", + 2030, + "spring", + "day", + "T_EV" + ], + [ + "R1", + 2025, + "fall", + "day", + "S_OILREF" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_DSL" + ], + [ + "R2", + 2030, + "spring", + "night", + "R_EH" + ], + [ + "R1", + 2030, + "summer", + "night", + "T_DSL" + ], + [ + "R1", + 2020, + "summer", + "night", + "R_NGH" + ], + [ + "R2", + 2020, + "winter", + "day", + "E_BATT" + ], + [ + "R2", + 2020, + "winter", + "day", + "T_BLND" + ], + [ + "R2", + 2030, + "spring", + "day", + "T_DSL" + ], + [ + "R1", + 2030, + "fall", + "night", + "S_OILREF" + ], + [ + "R1", + 2030, + "summer", + "night", + "S_OILREF" + ], + [ + "R2-R1", + 2030, + "winter", + "night", + "E_TRANS" + ], + [ + "R1-R2", + 2020, + "spring", + "night", + "E_TRANS" + ], + [ + "R2", + 2025, + "spring", + "night", + "S_OILREF" + ], + [ + "R1", + 2020, + "fall", + "night", + "T_EV" + ], + [ + "R1", + 2025, + "spring", + "day", + "E_SOLPV" + ], + [ + "R2", + 2025, + "winter", + "night", + "E_BATT" + ], + [ + "R2", + 2025, + "winter", + "night", + "T_BLND" + ], + [ + "R2", + 2030, + "spring", + "day", + "S_OILREF" + ], + [ + "R1", + 2020, + "winter", + "night", + "E_SOLPV" + ], + [ + "R2", + 2025, + "summer", + "day", + "R_EH" + ], + [ + "R1", + 2020, + "spring", + "night", + "R_NGH" + ], + [ + "R2-R1", + 2020, + "fall", + "day", + "E_TRANS" + ], + [ + "R1", + 2020, + "spring", + "night", + "E_NUCLEAR" + ], + [ + "R2", + 2030, + "winter", + "day", + "E_BATT" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_BLND" + ], + [ + "R2", + 2030, + "fall", + "day", + "T_GSL" + ], + [ + "R2", + 2025, + "spring", + "day", + "T_GSL" + ], + [ + "R2", + 2020, + "winter", + "night", + "T_GSL" + ], + [ + "R2", + 2030, + "winter", + "night", + "E_NGCC" + ], + [ + "R1", + 2030, + "spring", + "night", + "E_SOLPV" + ], + [ + "R1", + 2025, + "summer", + "night", + "T_BLND" + ], + [ + "R1", + 2020, + "winter", + "day", + "R_NGH" + ], + [ + "R1", + 2025, + "summer", + "day", + "E_BATT" + ], + [ + "R1", + 2025, + "summer", + "day", + "T_BLND" + ], + [ + "R1", + 2020, + "winter", + "day", + "E_NUCLEAR" + ], + [ + "R2", + 2020, + "spring", + "night", + "E_BATT" + ], + [ + "R2", + 2020, + "spring", + "night", + "T_BLND" + ], + [ + "R1", + 2025, + "spring", + "day", + "R_EH" + ], + [ + "R2-R1", + 2025, + "fall", + "night", + "E_TRANS" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_EV" + ], + [ + "R1", + 2020, + "winter", + "night", + "R_EH" + ], + [ + "R1", + 2025, + "summer", + "night", + "E_NGCC" + ], + [ + "R1", + 2020, + "fall", + "night", + "S_OILREF" + ], + [ + "R1", + 2030, + "spring", + "day", + "R_NGH" + ], + [ + "R2", + 2020, + "spring", + "night", + "E_NGCC" + ], + [ + "R1", + 2020, + "summer", + "day", + "T_GSL" + ], + [ + "R1", + 2030, + "spring", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2025, + "winter", + "night", + "R_NGH" + ], + [ + "R1", + 2020, + "winter", + "night", + "T_DSL" + ], + [ + "R2-R1", + 2020, + "winter", + "night", + "E_TRANS" + ], + [ + "R1", + 2025, + "winter", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "spring", + "night", + "R_EH" + ], + [ + "R1", + 2020, + "fall", + "day", + "T_GSL" + ], + [ + "R1", + 2020, + "summer", + "night", + "T_EV" + ], + [ + "R2", + 2030, + "summer", + "night", + "T_BLND" + ], + [ + "R1", + 2030, + "spring", + "night", + "T_DSL" + ], + [ + "R1", + 2020, + "spring", + "night", + "E_SOLPV" + ], + [ + "R1", + 2030, + "fall", + "day", + "S_OILREF" + ], + [ + "R2", + 2030, + "fall", + "night", + "S_OILREF" + ], + [ + "R2", + 2025, + "fall", + "night", + "T_BLND" + ], + [ + "R2", + 2025, + "fall", + "night", + "E_BATT" + ], + [ + "R2", + 2030, + "summer", + "night", + "E_NGCC" + ], + [ + "R1", + 2025, + "winter", + "day", + "E_NGCC" + ], + [ + "R1-R2", + 2020, + "winter", + "day", + "E_TRANS" + ], + [ + "R1", + 2020, + "spring", + "night", + "T_EV" + ], + [ + "R1", + 2020, + "spring", + "day", + "R_NGH" + ], + [ + "R1", + 2020, + "spring", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "winter", + "night", + "E_NGCC" + ], + [ + "R2-R1", + 2020, + "spring", + "day", + "E_TRANS" + ], + [ + "R1", + 2020, + "spring", + "night", + "R_EH" + ], + [ + "R1", + 2020, + "summer", + "night", + "S_OILREF" + ], + [ + "R1", + 2020, + "winter", + "day", + "T_EV" + ], + [ + "R1", + 2030, + "spring", + "day", + "E_SOLPV" + ], + [ + "R2", + 2020, + "spring", + "day", + "E_BATT" + ], + [ + "R1", + 2020, + "spring", + "night", + "T_DSL" + ], + [ + "R1", + 2025, + "fall", + "night", + "R_NGH" + ], + [ + "R1", + 2025, + "fall", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "spring", + "day", + "T_EV" + ], + [ + "R2-R1", + 2025, + "spring", + "night", + "E_TRANS" + ], + [ + "R2", + 2020, + "fall", + "night", + "E_SOLPV" + ], + [ + "R2", + 2020, + "summer", + "day", + "R_NGH" + ], + [ + "R1", + 2025, + "winter", + "night", + "T_EV" + ], + [ + "R2", + 2020, + "summer", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2020, + "winter", + "day", + "T_DSL" + ], + [ + "R2", + 2030, + "winter", + "night", + "T_GSL" + ], + [ + "R1-R2", + 2025, + "summer", + "day", + "E_TRANS" + ], + [ + "R2", + 2025, + "summer", + "night", + "E_BATT" + ], + [ + "R2", + 2025, + "summer", + "night", + "T_BLND" + ], + [ + "R2", + 2020, + "fall", + "day", + "R_NGH" + ], + [ + "R1", + 2025, + "summer", + "night", + "T_GSL" + ], + [ + "R2", + 2020, + "fall", + "day", + "E_NUCLEAR" + ], + [ + "R2", + 2030, + "summer", + "day", + "E_BATT" + ], + [ + "R1", + 2020, + "winter", + "day", + "S_OILREF" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_BLND" + ], + [ + "R1", + 2030, + "spring", + "day", + "T_DSL" + ], + [ + "R2", + 2020, + "spring", + "night", + "T_GSL" + ], + [ + "R1", + 2025, + "fall", + "day", + "E_NGCC" + ], + [ + "R2", + 2020, + "fall", + "night", + "R_EH" + ], + [ + "R2", + 2020, + "fall", + "night", + "T_DSL" + ], + [ + "R1", + 2030, + "summer", + "day", + "E_BATT" + ], + [ + "R1", + 2030, + "summer", + "day", + "T_BLND" + ], + [ + "R1", + 2030, + "spring", + "day", + "S_OILREF" + ], + [ + "R2", + 2025, + "spring", + "night", + "T_BLND" + ], + [ + "R1", + 2025, + "winter", + "night", + "S_OILREF" + ], + [ + "R1", + 2030, + "winter", + "day", + "E_BATT" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_BLND" + ], + [ + "R1", + 2030, + "fall", + "night", + "E_NGCC" + ], + [ + "R1", + 2020, + "spring", + "day", + "T_EV" + ], + [ + "R1", + 2030, + "summer", + "night", + "E_NGCC" + ], + [ + "R2", + 2025, + "spring", + "night", + "E_NGCC" + ], + [ + "R2", + 2030, + "summer", + "night", + "T_GSL" + ], + [ + "R1", + 2025, + "winter", + "day", + "T_GSL" + ], + [ + "R2", + 2030, + "spring", + "day", + "E_NGCC" + ], + [ + "R2", + 2020, + "summer", + "night", + "E_SOLPV" + ], + [ + "R2", + 2025, + "winter", + "night", + "E_SOLPV" + ], + [ + "R1-R2", + 2025, + "winter", + "day", + "E_TRANS" + ], + [ + "R1", + 2025, + "fall", + "night", + "T_EV" + ], + [ + "R2", + 2020, + "winter", + "day", + "R_EH" + ], + [ + "R2-R1", + 2025, + "spring", + "day", + "E_TRANS" + ], + [ + "R2", + 2020, + "fall", + "day", + "E_SOLPV" + ], + [ + "R1", + 2030, + "winter", + "night", + "T_GSL" + ], + [ + "R2", + 2020, + "summer", + "day", + "T_EV" + ], + [ + "R1", + 2020, + "fall", + "night", + "T_BLND" + ], + [ + "R1", + 2025, + "spring", + "night", + "E_NUCLEAR" + ], + [ + "R2", + 2025, + "winter", + "day", + "R_NGH" + ], + [ + "R2", + 2025, + "winter", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2025, + "summer", + "day", + "E_SOLPV" + ], + [ + "R1", + 2020, + "spring", + "day", + "S_OILREF" + ], + [ + "R2", + 2020, + "summer", + "night", + "R_EH" + ], + [ + "R1", + 2020, + "fall", + "night", + "E_NGCC" + ], + [ + "R2", + 2025, + "winter", + "night", + "R_EH" + ], + [ + "R1", + 2025, + "fall", + "night", + "T_DSL" + ], + [ + "R2", + 2020, + "fall", + "day", + "T_EV" + ], + [ + "R2", + 2020, + "summer", + "night", + "T_DSL" + ], + [ + "R2-R1", + 2030, + "spring", + "night", + "E_TRANS" + ], + [ + "R2", + 2030, + "winter", + "day", + "R_EH" + ], + [ + "R2", + 2030, + "spring", + "night", + "R_NGH" + ], + [ + "R2", + 2030, + "spring", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2025, + "fall", + "night", + "S_OILREF" + ], + [ + "R1-R2", + 2030, + "summer", + "night", + "E_TRANS" + ], + [ + "R1", + 2030, + "fall", + "day", + "E_BATT" + ], + [ + "R1", + 2030, + "fall", + "day", + "T_BLND" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_BLND" + ], + [ + "R1", + 2025, + "summer", + "day", + "R_EH" + ], + [ + "R2", + 2030, + "fall", + "day", + "E_BATT" + ], + [ + "R2", + 2020, + "fall", + "day", + "T_DSL" + ], + [ + "R2", + 2020, + "summer", + "day", + "S_OILREF" + ], + [ + "R2", + 2025, + "spring", + "day", + "T_BLND" + ], + [ + "R2", + 2025, + "spring", + "day", + "E_BATT" + ], + [ + "R2", + 2020, + "winter", + "night", + "E_BATT" + ], + [ + "R2", + 2030, + "fall", + "night", + "E_NGCC" + ], + [ + "R1", + 2025, + "fall", + "day", + "T_GSL" + ], + [ + "R1-R2", + 2030, + "fall", + "day", + "E_TRANS" + ], + [ + "R2", + 2025, + "summer", + "day", + "R_NGH" + ], + [ + "R2", + 2020, + "fall", + "day", + "S_OILREF" + ], + [ + "R2", + 2025, + "summer", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2020, + "summer", + "night", + "E_BATT" + ], + [ + "R1", + 2025, + "spring", + "night", + "E_SOLPV" + ], + [ + "R1", + 2020, + "summer", + "night", + "T_BLND" + ], + [ + "R2", + 2025, + "winter", + "day", + "E_SOLPV" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_GSL" + ], + [ + "R2", + 2025, + "fall", + "day", + "R_NGH" + ], + [ + "R1", + 2030, + "summer", + "night", + "T_GSL" + ], + [ + "R2", + 2025, + "fall", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2020, + "summer", + "night", + "E_NGCC" + ], + [ + "R2", + 2025, + "spring", + "night", + "T_GSL" + ], + [ + "R1", + 2025, + "spring", + "day", + "R_NGH" + ], + [ + "R1", + 2020, + "fall", + "day", + "E_BATT" + ], + [ + "R1", + 2020, + "fall", + "day", + "T_BLND" + ], + [ + "R2", + 2025, + "winter", + "day", + "T_EV" + ], + [ + "R2", + 2025, + "fall", + "night", + "R_EH" + ], + [ + "R1", + 2025, + "spring", + "day", + "E_NUCLEAR" + ], + [ + "R2", + 2030, + "spring", + "day", + "T_GSL" + ], + [ + "R1", + 2020, + "winter", + "night", + "R_NGH" + ], + [ + "R2", + 2020, + "spring", + "day", + "E_SOLPV" + ], + [ + "R1", + 2025, + "spring", + "night", + "R_EH" + ], + [ + "R1", + 2030, + "spring", + "night", + "R_NGH" + ], + [ + "R1", + 2025, + "spring", + "night", + "T_DSL" + ], + [ + "R1", + 2030, + "spring", + "night", + "E_NUCLEAR" + ], + [ + "R2", + 2025, + "winter", + "day", + "T_DSL" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_EV" + ], + [ + "R1", + 2020, + "winter", + "day", + "T_BLND" + ], + [ + "R2", + 2025, + "summer", + "night", + "E_SOLPV" + ], + [ + "R1", + 2020, + "winter", + "day", + "E_NGCC" + ], + [ + "R2", + 2020, + "spring", + "day", + "R_EH" + ], + [ + "R1", + 2020, + "fall", + "night", + "T_GSL" + ], + [ + "R2", + 2025, + "summer", + "day", + "E_SOLPV" + ], + [ + "R1-R2", + 2030, + "winter", + "day", + "E_TRANS" + ], + [ + "R2", + 2025, + "winter", + "day", + "S_OILREF" + ], + [ + "R1", + 2025, + "winter", + "night", + "E_BATT" + ], + [ + "R1", + 2025, + "winter", + "night", + "T_BLND" + ], + [ + "R2", + 2020, + "spring", + "day", + "T_DSL" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_DSL" + ], + [ + "R1", + 2030, + "spring", + "day", + "E_NGCC" + ], + [ + "R2", + 2025, + "fall", + "day", + "E_SOLPV" + ], + [ + "R2", + 2025, + "summer", + "day", + "T_EV" + ], + [ + "R1", + 2025, + "winter", + "night", + "E_NGCC" + ], + [ + "R2", + 2025, + "summer", + "night", + "R_EH" + ], + [ + "R2", + 2030, + "spring", + "night", + "S_OILREF" + ], + [ + "R1", + 2030, + "fall", + "day", + "T_GSL" + ], + [ + "R2", + 2030, + "winter", + "night", + "E_BATT" + ], + [ + "R2", + 2030, + "winter", + "night", + "T_BLND" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_GSL" + ], + [ + "R2", + 2030, + "summer", + "day", + "R_EH" + ], + [ + "R2", + 2025, + "fall", + "day", + "T_EV" + ], + [ + "R2", + 2025, + "summer", + "day", + "T_DSL" + ], + [ + "R2-R1", + 2020, + "spring", + "night", + "E_TRANS" + ], + [ + "R1", + 2025, + "spring", + "day", + "T_EV" + ], + [ + "R2", + 2025, + "fall", + "day", + "R_EH" + ], + [ + "R1", + 2025, + "summer", + "night", + "E_BATT" + ], + [ + "R1", + 2020, + "winter", + "night", + "T_EV" + ], + [ + "R1", + 2030, + "summer", + "day", + "R_EH" + ], + [ + "R1", + 2020, + "spring", + "day", + "T_BLND" + ], + [ + "R2", + 2025, + "fall", + "day", + "T_DSL" + ], + [ + "R1-R2", + 2020, + "summer", + "day", + "E_TRANS" + ], + [ + "R1", + 2030, + "winter", + "day", + "R_EH" + ], + [ + "R2", + 2025, + "summer", + "day", + "S_OILREF" + ], + [ + "R1", + 2020, + "summer", + "night", + "T_GSL" + ], + [ + "R1", + 2030, + "spring", + "night", + "T_EV" + ], + [ + "R1", + 2020, + "spring", + "day", + "E_NGCC" + ], + [ + "R1", + 2025, + "spring", + "day", + "T_DSL" + ], + [ + "R1-R2", + 2020, + "fall", + "day", + "E_TRANS" + ], + [ + "R1", + 2025, + "fall", + "night", + "T_BLND" + ], + [ + "R2", + 2020, + "fall", + "night", + "R_NGH" + ], + [ + "R1", + 2025, + "spring", + "day", + "S_OILREF" + ], + [ + "R2", + 2020, + "fall", + "night", + "E_NUCLEAR" + ], + [ + "R2", + 2020, + "summer", + "day", + "T_BLND" + ], + [ + "R1", + 2020, + "winter", + "night", + "S_OILREF" + ], + [ + "R2", + 2030, + "summer", + "night", + "E_BATT" + ], + [ + "R1", + 2025, + "winter", + "day", + "E_BATT" + ], + [ + "R1", + 2025, + "winter", + "day", + "T_BLND" + ], + [ + "R1", + 2025, + "fall", + "night", + "E_NGCC" + ], + [ + "R1-R2", + 2025, + "fall", + "night", + "E_TRANS" + ], + [ + "R2", + 2020, + "summer", + "day", + "E_NGCC" + ], + [ + "R2", + 2030, + "fall", + "day", + "E_SOLPV" + ], + [ + "R1", + 2020, + "winter", + "day", + "T_GSL" + ], + [ + "R1", + 2030, + "spring", + "night", + "S_OILREF" + ], + [ + "R1-R2", + 2020, + "winter", + "night", + "E_TRANS" + ], + [ + "R2", + 2020, + "winter", + "night", + "E_SOLPV" + ], + [ + "R1", + 2030, + "winter", + "night", + "E_BATT" + ], + [ + "R1", + 2030, + "winter", + "night", + "T_BLND" + ], + [ + "R2", + 2020, + "fall", + "day", + "E_NGCC" + ], + [ + "R1", + 2030, + "spring", + "day", + "T_GSL" + ], + [ + "R2-R1", + 2030, + "summer", + "day", + "E_TRANS" + ], + [ + "R1", + 2025, + "winter", + "night", + "T_GSL" + ], + [ + "R2", + 2020, + "winter", + "day", + "R_NGH" + ], + [ + "R2", + 2020, + "winter", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2020, + "summer", + "day", + "E_SOLPV" + ], + [ + "R2", + 2030, + "fall", + "day", + "R_EH" + ], + [ + "R2", + 2025, + "spring", + "day", + "R_EH" + ], + [ + "R2", + 2020, + "winter", + "night", + "R_EH" + ], + [ + "R2", + 2020, + "summer", + "night", + "R_NGH" + ], + [ + "R2", + 2020, + "summer", + "night", + "E_NUCLEAR" + ], + [ + "R2", + 2025, + "winter", + "night", + "R_NGH" + ], + [ + "R2-R1", + 2020, + "summer", + "night", + "E_TRANS" + ], + [ + "R2", + 2020, + "winter", + "night", + "T_DSL" + ], + [ + "R2", + 2025, + "winter", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2020, + "spring", + "night", + "S_OILREF" + ], + [ + "R2", + 2030, + "winter", + "day", + "R_NGH" + ], + [ + "R1-R2", + 2025, + "summer", + "night", + "E_TRANS" + ], + [ + "R1", + 2025, + "fall", + "day", + "E_BATT" + ], + [ + "R2", + 2030, + "winter", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2025, + "fall", + "day", + "T_BLND" + ], + [ + "R1", + 2020, + "summer", + "day", + "R_EH" + ], + [ + "R2", + 2020, + "fall", + "night", + "T_EV" + ], + [ + "R1", + 2025, + "summer", + "day", + "R_NGH" + ], + [ + "R1", + 2020, + "summer", + "day", + "T_DSL" + ], + [ + "R1", + 2020, + "spring", + "day", + "T_GSL" + ], + [ + "R1", + 2025, + "summer", + "day", + "E_NUCLEAR" + ], + [ + "R2", + 2020, + "spring", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2020, + "fall", + "day", + "R_EH" + ], + [ + "R1-R2", + 2025, + "fall", + "day", + "E_TRANS" + ], + [ + "R1", + 2030, + "fall", + "night", + "E_BATT" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_BLND" + ], + [ + "R2", + 2025, + "winter", + "day", + "E_NGCC" + ], + [ + "R1", + 2030, + "summer", + "night", + "E_BATT" + ], + [ + "R1", + 2030, + "summer", + "night", + "T_BLND" + ], + [ + "R2", + 2025, + "spring", + "night", + "E_BATT" + ], + [ + "R2", + 2020, + "winter", + "day", + "E_SOLPV" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_BLND" + ], + [ + "R2", + 2030, + "spring", + "day", + "E_BATT" + ], + [ + "R1", + 2025, + "fall", + "night", + "T_GSL" + ], + [ + "R2", + 2030, + "spring", + "day", + "T_BLND" + ], + [ + "R1-R2", + 2030, + "fall", + "night", + "E_TRANS" + ], + [ + "R2", + 2020, + "fall", + "night", + "S_OILREF" + ], + [ + "R2", + 2030, + "spring", + "night", + "E_NGCC" + ], + [ + "R2", + 2020, + "summer", + "day", + "T_GSL" + ], + [ + "R2", + 2020, + "winter", + "day", + "T_EV" + ], + [ + "R1-R2", + 2025, + "winter", + "night", + "E_TRANS" + ], + [ + "R2", + 2030, + "winter", + "night", + "E_SOLPV" + ], + [ + "R2", + 2025, + "fall", + "night", + "R_NGH" + ], + [ + "R2", + 2030, + "winter", + "day", + "E_SOLPV" + ], + [ + "R2", + 2020, + "fall", + "day", + "T_GSL" + ], + [ + "R2", + 2025, + "fall", + "night", + "E_NUCLEAR" + ], + [ + "R2", + 2020, + "summer", + "night", + "T_EV" + ], + [ + "R1", + 2025, + "spring", + "night", + "R_NGH" + ], + [ + "R1", + 2020, + "fall", + "night", + "E_BATT" + ], + [ + "R2", + 2025, + "winter", + "night", + "T_EV" + ], + [ + "R1", + 2025, + "summer", + "night", + "E_SOLPV" + ], + [ + "R2-R1", + 2020, + "summer", + "day", + "E_TRANS" + ], + [ + "R2", + 2020, + "winter", + "day", + "T_DSL" + ], + [ + "R2-R1", + 2025, + "winter", + "day", + "E_TRANS" + ], + [ + "R2", + 2025, + "summer", + "day", + "E_NGCC" + ], + [ + "R2", + 2020, + "spring", + "night", + "E_SOLPV" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_EV" + ], + [ + "R2", + 2030, + "winter", + "night", + "R_EH" + ], + [ + "R1", + 2025, + "spring", + "day", + "T_BLND" + ], + [ + "R2", + 2020, + "winter", + "day", + "S_OILREF" + ], + [ + "R1", + 2025, + "summer", + "day", + "T_EV" + ], + [ + "R2", + 2025, + "fall", + "day", + "E_NGCC" + ], + [ + "R1", + 2020, + "winter", + "night", + "E_BATT" + ], + [ + "R1", + 2020, + "winter", + "night", + "T_BLND" + ], + [ + "R2", + 2025, + "winter", + "night", + "T_DSL" + ], + [ + "R2", + 2020, + "spring", + "day", + "R_NGH" + ], + [ + "R2", + 2020, + "spring", + "day", + "E_NUCLEAR" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_DSL" + ], + [ + "R1", + 2025, + "summer", + "night", + "R_EH" + ], + [ + "R1", + 2025, + "spring", + "day", + "E_NGCC" + ], + [ + "R2", + 2030, + "fall", + "night", + "E_BATT" + ], + [ + "R1", + 2020, + "winter", + "night", + "E_NGCC" + ], + [ + "R2", + 2020, + "spring", + "night", + "R_EH" + ], + [ + "R2", + 2020, + "summer", + "night", + "S_OILREF" + ], + [ + "R1-R2", + 2025, + "spring", + "day", + "E_TRANS" + ], + [ + "R1", + 2030, + "spring", + "night", + "T_BLND" + ], + [ + "R2", + 2025, + "winter", + "night", + "S_OILREF" + ], + [ + "R2", + 2030, + "summer", + "night", + "E_SOLPV" + ], + [ + "R1", + 2025, + "summer", + "day", + "T_DSL" + ], + [ + "R2", + 2020, + "spring", + "night", + "T_DSL" + ], + [ + "R2", + 2030, + "winter", + "day", + "S_OILREF" + ], + [ + "R2", + 2025, + "summer", + "night", + "R_NGH" + ], + [ + "R1", + 2030, + "spring", + "night", + "E_NGCC" + ], + [ + "R2", + 2025, + "fall", + "night", + "E_SOLPV" + ], + [ + "R2", + 2025, + "summer", + "night", + "E_NUCLEAR" + ], + [ + "R1-R2", + 2030, + "spring", + "night", + "E_TRANS" + ], + [ + "R2", + 2025, + "winter", + "day", + "T_GSL" + ], + [ + "R2", + 2030, + "summer", + "day", + "R_NGH" + ], + [ + "R1", + 2025, + "summer", + "day", + "S_OILREF" + ], + [ + "R2", + 2030, + "summer", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "winter", + "night", + "E_SOLPV" + ], + [ + "R2-R1", + 2030, + "fall", + "day", + "E_TRANS" + ], + [ + "R2", + 2025, + "fall", + "night", + "T_EV" + ], + [ + "R2", + 2030, + "summer", + "night", + "R_EH" + ], + [ + "R1", + 2025, + "winter", + "day", + "R_EH" + ], + [ + "R1", + 2030, + "summer", + "day", + "R_NGH" + ], + [ + "R1", + 2030, + "summer", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2025, + "spring", + "night", + "T_EV" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_GSL" + ], + [ + "R2", + 2030, + "summer", + "night", + "T_DSL" + ], + [ + "R1", + 2030, + "winter", + "day", + "R_NGH" + ], + [ + "R1", + 2030, + "winter", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2020, + "spring", + "night", + "E_BATT" + ], + [ + "R1", + 2020, + "spring", + "night", + "T_BLND" + ], + [ + "R2", + 2025, + "fall", + "night", + "T_DSL" + ], + [ + "R1", + 2030, + "winter", + "night", + "R_EH" + ], + [ + "R1", + 2020, + "spring", + "night", + "E_NGCC" + ], + [ + "R1", + 2020, + "winter", + "day", + "E_BATT" + ], + [ + "R2", + 2020, + "spring", + "day", + "T_EV" + ], + [ + "R1-R2", + 2020, + "fall", + "night", + "E_TRANS" + ], + [ + "R2", + 2025, + "fall", + "night", + "S_OILREF" + ], + [ + "R2", + 2025, + "summer", + "day", + "T_GSL" + ], + [ + "R1-R2", + 2030, + "winter", + "night", + "E_TRANS" + ], + [ + "R1", + 2025, + "spring", + "night", + "S_OILREF" + ], + [ + "R1", + 2030, + "spring", + "day", + "E_BATT" + ], + [ + "R1", + 2030, + "spring", + "day", + "T_BLND" + ], + [ + "R2", + 2030, + "summer", + "day", + "E_SOLPV" + ], + [ + "R2", + 2025, + "summer", + "night", + "T_EV" + ], + [ + "R1", + 2025, + "spring", + "day", + "T_GSL" + ], + [ + "R2-R1", + 2025, + "summer", + "day", + "E_TRANS" + ], + [ + "R2", + 2020, + "fall", + "night", + "T_BLND" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_EV" + ], + [ + "R1-R2", + 2030, + "spring", + "day", + "E_TRANS" + ], + [ + "R1", + 2030, + "summer", + "day", + "E_SOLPV" + ], + [ + "R1", + 2020, + "winter", + "night", + "T_GSL" + ], + [ + "R2-R1", + 2030, + "winter", + "day", + "E_TRANS" + ], + [ + "R2", + 2025, + "spring", + "night", + "E_SOLPV" + ], + [ + "R1", + 2025, + "fall", + "day", + "R_EH" + ], + [ + "R2", + 2020, + "spring", + "day", + "S_OILREF" + ], + [ + "R1", + 2030, + "winter", + "day", + "E_SOLPV" + ], + [ + "R2", + 2030, + "spring", + "day", + "E_SOLPV" + ], + [ + "R1", + 2030, + "fall", + "day", + "R_NGH" + ], + [ + "R2", + 2020, + "fall", + "night", + "E_NGCC" + ], + [ + "R1", + 2030, + "fall", + "day", + "E_NUCLEAR" + ], + [ + "R2", + 2025, + "summer", + "night", + "T_DSL" + ], + [ + "R2", + 2030, + "fall", + "day", + "R_NGH" + ], + [ + "R1", + 2030, + "summer", + "day", + "T_EV" + ], + [ + "R1", + 2030, + "spring", + "night", + "T_GSL" + ], + [ + "R2", + 2030, + "fall", + "day", + "E_NUCLEAR" + ], + [ + "R2-R1", + 2030, + "summer", + "night", + "E_TRANS" + ], + [ + "R2", + 2025, + "spring", + "day", + "R_NGH" + ], + [ + "R2", + 2025, + "spring", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_EV" + ], + [ + "R1", + 2030, + "fall", + "night", + "R_EH" + ], + [ + "R2", + 2020, + "winter", + "night", + "R_NGH" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_DSL" + ], + [ + "R2", + 2020, + "winter", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "summer", + "night", + "R_EH" + ], + [ + "R1", + 2020, + "spring", + "day", + "E_BATT" + ], + [ + "R2", + 2025, + "spring", + "night", + "R_EH" + ], + [ + "R1-R2", + 2020, + "summer", + "night", + "E_TRANS" + ], + [ + "R2", + 2025, + "summer", + "night", + "S_OILREF" + ], + [ + "R2", + 2030, + "spring", + "day", + "R_EH" + ], + [ + "R2", + 2030, + "summer", + "day", + "S_OILREF" + ], + [ + "R1", + 2030, + "summer", + "day", + "T_DSL" + ], + [ + "R2", + 2025, + "spring", + "night", + "T_DSL" + ], + [ + "R1", + 2020, + "fall", + "night", + "E_SOLPV" + ], + [ + "R1", + 2020, + "summer", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2020, + "summer", + "day", + "R_NGH" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_DSL" + ], + [ + "R1", + 2020, + "summer", + "day", + "E_NUCLEAR" + ], + [ + "R2", + 2025, + "fall", + "day", + "S_OILREF" + ], + [ + "R1", + 2025, + "fall", + "night", + "E_BATT" + ], + [ + "R2", + 2020, + "winter", + "day", + "E_NGCC" + ], + [ + "R1", + 2030, + "summer", + "day", + "S_OILREF" + ], + [ + "R1", + 2020, + "fall", + "day", + "R_NGH" + ], + [ + "R2", + 2020, + "summer", + "night", + "E_BATT" + ], + [ + "R2", + 2020, + "summer", + "night", + "T_BLND" + ], + [ + "R1", + 2020, + "fall", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "winter", + "day", + "S_OILREF" + ], + [ + "R2", + 2020, + "summer", + "day", + "E_BATT" + ], + [ + "R1", + 2020, + "spring", + "night", + "T_GSL" + ], + [ + "R1", + 2020, + "fall", + "night", + "R_EH" + ], + [ + "R2", + 2020, + "summer", + "night", + "E_NGCC" + ], + [ + "R1", + 2030, + "fall", + "day", + "E_SOLPV" + ], + [ + "R2", + 2030, + "fall", + "night", + "E_SOLPV" + ], + [ + "R2", + 2025, + "winter", + "night", + "E_NGCC" + ], + [ + "R2", + 2020, + "fall", + "day", + "E_BATT" + ], + [ + "R2", + 2020, + "fall", + "day", + "T_BLND" + ], + [ + "R1", + 2020, + "fall", + "night", + "T_DSL" + ], + [ + "R2", + 2025, + "spring", + "day", + "E_SOLPV" + ], + [ + "R2", + 2030, + "winter", + "day", + "E_NGCC" + ], + [ + "R1", + 2030, + "fall", + "day", + "T_EV" + ], + [ + "R2", + 2030, + "fall", + "day", + "T_EV" + ], + [ + "R1", + 2025, + "summer", + "day", + "E_NGCC" + ], + [ + "R2", + 2025, + "spring", + "day", + "T_EV" + ], + [ + "R2", + 2020, + "winter", + "night", + "T_EV" + ], + [ + "R1", + 2030, + "fall", + "day", + "R_EH" + ], + [ + "R1", + 2020, + "summer", + "night", + "E_SOLPV" + ], + [ + "R2", + 2030, + "fall", + "night", + "R_EH" + ], + [ + "R2-R1", + 2020, + "winter", + "day", + "E_TRANS" + ], + [ + "R1", + 2030, + "fall", + "day", + "T_DSL" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_DSL" + ], + [ + "R2", + 2020, + "fall", + "night", + "T_GSL" + ], + [ + "R2", + 2030, + "fall", + "day", + "T_DSL" + ], + [ + "R2", + 2025, + "spring", + "day", + "T_DSL" + ], + [ + "R1", + 2020, + "fall", + "day", + "E_SOLPV" + ], + [ + "R1", + 2020, + "summer", + "day", + "T_EV" + ], + [ + "R2", + 2030, + "winter", + "night", + "R_NGH" + ], + [ + "R2", + 2030, + "winter", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2020, + "summer", + "night", + "R_EH" + ], + [ + "R2", + 2030, + "fall", + "day", + "S_OILREF" + ], + [ + "R1-R2", + 2020, + "spring", + "day", + "E_TRANS" + ], + [ + "R2", + 2025, + "spring", + "day", + "S_OILREF" + ], + [ + "R1", + 2020, + "fall", + "day", + "T_EV" + ], + [ + "R1", + 2025, + "spring", + "night", + "E_BATT" + ], + [ + "R1", + 2025, + "spring", + "night", + "T_BLND" + ], + [ + "R1", + 2025, + "summer", + "night", + "R_NGH" + ], + [ + "R1", + 2020, + "summer", + "night", + "T_DSL" + ], + [ + "R2", + 2020, + "winter", + "night", + "S_OILREF" + ], + [ + "R2", + 2025, + "winter", + "day", + "E_BATT" + ], + [ + "R2", + 2025, + "winter", + "day", + "T_BLND" + ], + [ + "R2", + 2025, + "fall", + "night", + "E_NGCC" + ], + [ + "R1", + 2025, + "summer", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2020, + "winter", + "day", + "E_SOLPV" + ], + [ + "R2", + 2020, + "spring", + "night", + "R_NGH" + ], + [ + "R1", + 2025, + "spring", + "night", + "E_NGCC" + ], + [ + "R1-R2", + 2025, + "spring", + "night", + "E_TRANS" + ], + [ + "R2", + 2020, + "winter", + "day", + "T_GSL" + ], + [ + "R1", + 2020, + "fall", + "day", + "T_DSL" + ], + [ + "R1", + 2020, + "summer", + "day", + "S_OILREF" + ], + [ + "R1", + 2025, + "winter", + "night", + "E_SOLPV" + ], + [ + "R2", + 2020, + "spring", + "day", + "T_BLND" + ], + [ + "R2", + 2030, + "spring", + "night", + "E_BATT" + ], + [ + "R2-R1", + 2025, + "fall", + "day", + "E_TRANS" + ], + [ + "R1", + 2020, + "winter", + "day", + "R_EH" + ], + [ + "R2", + 2020, + "summer", + "night", + "T_GSL" + ], + [ + "R1", + 2020, + "fall", + "day", + "S_OILREF" + ], + [ + "R2", + 2020, + "spring", + "day", + "E_NGCC" + ], + [ + "R2", + 2025, + "winter", + "night", + "T_GSL" + ], + [ + "R2", + 2030, + "summer", + "night", + "R_NGH" + ], + [ + "R1", + 2025, + "winter", + "day", + "R_NGH" + ], + [ + "R2", + 2030, + "summer", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2025, + "winter", + "day", + "E_NUCLEAR" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_GSL" + ], + [ + "R1", + 2030, + "spring", + "day", + "R_EH" + ], + [ + "R2-R1", + 2030, + "fall", + "night", + "E_TRANS" + ], + [ + "R1", + 2025, + "winter", + "night", + "R_EH" + ], + [ + "R2", + 2025, + "summer", + "day", + "E_BATT" + ], + [ + "R2", + 2025, + "summer", + "day", + "T_BLND" + ], + [ + "R1", + 2025, + "summer", + "day", + "T_GSL" + ], + [ + "R1", + 2030, + "winter", + "night", + "R_NGH" + ], + [ + "R1", + 2025, + "winter", + "night", + "T_DSL" + ], + [ + "R2-R1", + 2025, + "winter", + "night", + "E_TRANS" + ], + [ + "R2", + 2025, + "summer", + "night", + "E_NGCC" + ], + [ + "R1", + 2030, + "winter", + "night", + "E_NUCLEAR" + ], + [ + "R2", + 2030, + "winter", + "night", + "T_EV" + ], + [ + "R1", + 2020, + "spring", + "day", + "E_SOLPV" + ], + [ + "R2", + 2025, + "fall", + "day", + "E_BATT" + ], + [ + "R2", + 2025, + "fall", + "day", + "T_BLND" + ], + [ + "R2", + 2030, + "summer", + "day", + "E_NGCC" + ], + [ + "R1", + 2025, + "summer", + "night", + "T_EV" + ], + [ + "R1", + 2025, + "spring", + "day", + "E_BATT" + ], + [ + "R2", + 2020, + "spring", + "night", + "T_EV" + ], + [ + "R2", + 2030, + "winter", + "night", + "T_DSL" + ], + [ + "R1", + 2030, + "summer", + "day", + "E_NGCC" + ], + [ + "R1", + 2025, + "fall", + "night", + "E_SOLPV" + ], + [ + "R1", + 2030, + "winter", + "day", + "E_NGCC" + ], + [ + "R1", + 2020, + "spring", + "day", + "R_EH" + ], + [ + "R1", + 2030, + "spring", + "night", + "E_BATT" + ], + [ + "R2", + 2020, + "summer", + "day", + "E_SOLPV" + ], + [ + "R1", + 2025, + "summer", + "night", + "T_DSL" + ], + [ + "R1", + 2025, + "winter", + "day", + "E_SOLPV" + ], + [ + "R2", + 2030, + "winter", + "night", + "S_OILREF" + ], + [ + "R2", + 2025, + "fall", + "night", + "T_GSL" + ], + [ + "R1", + 2020, + "spring", + "day", + "T_DSL" + ], + [ + "R1", + 2025, + "fall", + "day", + "R_NGH" + ], + [ + "R1", + 2025, + "fall", + "day", + "E_NUCLEAR" + ], + [ + "R1", + 2025, + "spring", + "night", + "T_GSL" + ], + [ + "R2-R1", + 2025, + "summer", + "night", + "E_TRANS" + ], + [ + "R2", + 2030, + "summer", + "night", + "T_EV" + ], + [ + "R1", + 2025, + "summer", + "night", + "S_OILREF" + ], + [ + "R1", + 2025, + "winter", + "day", + "T_EV" + ], + [ + "R1", + 2025, + "fall", + "night", + "R_EH" + ], + [ + "R2", + 2020, + "spring", + "night", + "S_OILREF" + ], + [ + "R1", + 2030, + "fall", + "night", + "R_NGH" + ], + [ + "R2", + 2020, + "summer", + "day", + "R_EH" + ], + [ + "R1", + 2030, + "fall", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "summer", + "night", + "R_NGH" + ], + [ + "R1", + 2030, + "summer", + "night", + "E_NUCLEAR" + ], + [ + "R2", + 2025, + "spring", + "night", + "R_NGH" + ], + [ + "R2", + 2020, + "summer", + "day", + "T_DSL" + ], + [ + "R2", + 2025, + "spring", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "winter", + "night", + "T_EV" + ], + [ + "R2", + 2020, + "spring", + "day", + "T_GSL" + ], + [ + "R1", + 2025, + "winter", + "day", + "T_DSL" + ], + [ + "R2", + 2030, + "spring", + "day", + "R_NGH" + ], + [ + "R2", + 2020, + "fall", + "day", + "R_EH" + ], + [ + "R2", + 2030, + "spring", + "day", + "E_NUCLEAR" + ], + [ + "R1-R2", + 2030, + "summer", + "day", + "E_TRANS" + ], + [ + "R2", + 2030, + "fall", + "day", + "T_BLND" + ], + [ + "R2", + 2030, + "summer", + "night", + "S_OILREF" + ], + [ + "R1", + 2025, + "winter", + "day", + "S_OILREF" + ], + [ + "R2", + 2020, + "winter", + "night", + "T_BLND" + ], + [ + "R1", + 2030, + "fall", + "day", + "E_NGCC" + ], + [ + "R1", + 2030, + "winter", + "night", + "T_DSL" + ], + [ + "R2", + 2030, + "fall", + "day", + "E_NGCC" + ], + [ + "R2", + 2025, + "summer", + "night", + "T_GSL" + ], + [ + "R2", + 2025, + "spring", + "day", + "E_NGCC" + ], + [ + "R1", + 2025, + "fall", + "day", + "E_SOLPV" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_GSL" + ], + [ + "R2", + 2020, + "winter", + "night", + "E_NGCC" + ], + [ + "R1", + 2020, + "fall", + "night", + "R_NGH" + ], + [ + "R1", + 2020, + "fall", + "night", + "E_NUCLEAR" + ], + [ + "R1", + 2030, + "winter", + "night", + "S_OILREF" + ], + [ + "R1", + 2020, + "summer", + "day", + "E_BATT" + ], + [ + "R1", + 2020, + "summer", + "day", + "T_BLND" + ], + [ + "R2", + 2025, + "fall", + "day", + "T_GSL" + ], + [ + "R2-R1", + 2020, + "fall", + "night", + "E_TRANS" + ], + [ + "R1", + 2025, + "fall", + "day", + "T_EV" + ], + [ + "R1", + 2030, + "summer", + "day", + "T_GSL" + ], + [ + "R1", + 2030, + "fall", + "night", + "E_SOLPV" + ], + [ + "R1", + 2020, + "summer", + "day", + "E_NGCC" + ], + [ + "R1", + 2030, + "summer", + "night", + "E_SOLPV" + ], + [ + "R2", + 2020, + "fall", + "night", + "E_BATT" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_GSL" + ] + ], + "CapacityVar_rptv": [ + [ + "R2", + 2030, + "R_NGH", + 2030 + ], + [ + "R1", + 2030, + "E_BATT", + 2030 + ], + [ + "R1", + 2025, + "E_NGCC", + 2025 + ], + [ + "R2", + 2020, + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2025, + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "R_NGH", + 2025 + ], + [ + "R2", + 2030, + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "R_EH", + 2020 + ], + [ + "R2", + 2020, + "T_EV", + 2020 + ], + [ + "R2", + 2025, + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2030, + "T_EV", + 2030 + ], + [ + "R2", + 2030, + "T_DSL", + 2020 + ], + [ + "R2", + 2025, + "T_DSL", + 2020 + ], + [ + "R1", + 2030, + "T_EV", + 2025 + ], + [ + "R1", + 2025, + "T_GSL", + 2025 + ], + [ + "R2", + 2030, + "R_NGH", + 2025 + ], + [ + "R2", + 2020, + "S_OILREF", + 2020 + ], + [ + "R1", + 2030, + "E_BATT", + 2025 + ], + [ + "R1", + 2025, + "E_NGCC", + 2020 + ], + [ + "R2", + 2020, + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2025, + "R_NGH", + 2025 + ], + [ + "R1", + 2030, + "R_NGH", + 2020 + ], + [ + "R2", + 2020, + "T_GSL", + 2020 + ], + [ + "R1", + 2020, + "R_NGH", + 2020 + ], + [ + "R2", + 2030, + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "E_NUCLEAR", + 2025 + ], + [ + "R2-R1", + 2020, + "E_TRANS", + 2015 + ], + [ + "R2", + 2030, + "T_GSL", + 2030 + ], + [ + "R2-R1", + 2030, + "E_TRANS", + 2015 + ], + [ + "R1", + 2030, + "E_NGCC", + 2030 + ], + [ + "R2", + 2025, + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2030, + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "T_EV", + 2025 + ], + [ + "R1", + 2020, + "T_DSL", + 2020 + ], + [ + "R2", + 2020, + "E_SOLPV", + 2020 + ], + [ + "R2", + 2025, + "T_EV", + 2025 + ], + [ + "R1", + 2030, + "T_EV", + 2020 + ], + [ + "R1", + 2025, + "E_BATT", + 2025 + ], + [ + "R1", + 2025, + "S_OILREF", + 2020 + ], + [ + "R1", + 2025, + "T_GSL", + 2020 + ], + [ + "R1", + 2030, + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "R_NGH", + 2020 + ], + [ + "R1", + 2020, + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "E_SOLPV", + 2030 + ], + [ + "R2", + 2020, + "E_NGCC", + 2020 + ], + [ + "R1", + 2030, + "E_BATT", + 2020 + ], + [ + "R1", + 2020, + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "E_NGCC", + 2030 + ], + [ + "R1", + 2030, + "T_GSL", + 2030 + ], + [ + "R2", + 2025, + "R_NGH", + 2020 + ], + [ + "R2", + 2030, + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "T_GSL", + 2025 + ], + [ + "R1", + 2030, + "E_NGCC", + 2025 + ], + [ + "R2", + 2025, + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "T_EV", + 2020 + ], + [ + "R1-R2", + 2025, + "E_TRANS", + 2015 + ], + [ + "R2", + 2025, + "T_GSL", + 2025 + ], + [ + "R2", + 2025, + "T_EV", + 2020 + ], + [ + "R1", + 2025, + "T_DSL", + 2025 + ], + [ + "R2", + 2025, + "T_BLND", + 2020 + ], + [ + "R1", + 2030, + "R_EH", + 2030 + ], + [ + "R1", + 2025, + "E_SOLPV", + 2025 + ], + [ + "R2", + 2030, + "E_SOLPV", + 2025 + ], + [ + "R2", + 2030, + "S_OILREF", + 2020 + ], + [ + "R2", + 2030, + "E_NGCC", + 2025 + ], + [ + "R1", + 2030, + "T_GSL", + 2025 + ], + [ + "R2", + 2030, + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2020, + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "T_GSL", + 2020 + ], + [ + "R2", + 2025, + "S_OILREF", + 2020 + ], + [ + "R2", + 2025, + "E_NGCC", + 2025 + ], + [ + "R1", + 2030, + "E_NGCC", + 2020 + ], + [ + "R1", + 2020, + "E_NGCC", + 2020 + ], + [ + "R2", + 2025, + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2025, + "R_EH", + 2025 + ], + [ + "R2", + 2025, + "T_GSL", + 2020 + ], + [ + "R1", + 2020, + "T_EV", + 2020 + ], + [ + "R2-R1", + 2025, + "E_TRANS", + 2015 + ], + [ + "R2", + 2020, + "T_BLND", + 2020 + ], + [ + "R2", + 2020, + "E_BATT", + 2020 + ], + [ + "R2", + 2020, + "R_EH", + 2020 + ], + [ + "R1", + 2025, + "T_DSL", + 2020 + ], + [ + "R2", + 2030, + "R_EH", + 2030 + ], + [ + "R1", + 2030, + "T_DSL", + 2030 + ], + [ + "R1", + 2030, + "S_OILREF", + 2020 + ], + [ + "R1", + 2025, + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "E_NGCC", + 2020 + ], + [ + "R1", + 2030, + "T_GSL", + 2020 + ], + [ + "R1", + 2020, + "T_GSL", + 2020 + ], + [ + "R1", + 2020, + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "E_SOLPV", + 2030 + ], + [ + "R1", + 2025, + "R_NGH", + 2025 + ], + [ + "R2", + 2025, + "E_NGCC", + 2020 + ], + [ + "R1", + 2025, + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "R_EH", + 2020 + ], + [ + "R1", + 2025, + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2025, + "E_SOLPV", + 2025 + ], + [ + "R1", + 2020, + "E_SOLPV", + 2020 + ], + [ + "R1-R2", + 2030, + "E_TRANS", + 2015 + ], + [ + "R2", + 2020, + "T_DSL", + 2020 + ], + [ + "R1-R2", + 2020, + "E_TRANS", + 2015 + ], + [ + "R1", + 2025, + "T_EV", + 2025 + ], + [ + "R2", + 2030, + "T_DSL", + 2030 + ], + [ + "R2", + 2030, + "R_EH", + 2025 + ], + [ + "R2", + 2030, + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2025, + "R_EH", + 2025 + ], + [ + "R1", + 2030, + "T_DSL", + 2025 + ], + [ + "R1", + 2020, + "R_EH", + 2020 + ], + [ + "R1", + 2030, + "E_SOLPV", + 2025 + ], + [ + "R1", + 2025, + "R_NGH", + 2020 + ], + [ + "R1", + 2025, + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "R_NGH", + 2030 + ], + [ + "R2", + 2030, + "E_BATT", + 2030 + ], + [ + "R2", + 2025, + "E_SOLPV", + 2020 + ], + [ + "R1", + 2030, + "R_EH", + 2025 + ], + [ + "R1", + 2025, + "T_EV", + 2020 + ], + [ + "R1", + 2030, + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2030, + "T_DSL", + 2025 + ], + [ + "R2", + 2030, + "R_EH", + 2020 + ], + [ + "R1", + 2020, + "S_OILREF", + 2020 + ], + [ + "R2", + 2025, + "T_DSL", + 2025 + ], + [ + "R2", + 2025, + "R_EH", + 2020 + ], + [ + "R1", + 2030, + "T_EV", + 2030 + ], + [ + "R1", + 2030, + "T_DSL", + 2020 + ], + [ + "R1", + 2025, + "T_BLND", + 2020 + ], + [ + "R2", + 2020, + "R_NGH", + 2020 + ], + [ + "R1", + 2030, + "E_SOLPV", + 2020 + ] + ], + "CommodityBalanceConstraint_rpsdc": [ + [ + "R2", + 2020, + "winter", + "night", + "ETH" + ], + [ + "R1", + 2025, + "fall", + "night", + "GSL" + ], + [ + "R1", + 2030, + "summer", + "day", + "ELC" + ], + [ + "R1", + 2020, + "spring", + "day", + "E10" + ], + [ + "R2", + 2030, + "winter", + "night", + "NG" + ], + [ + "R2", + 2025, + "summer", + "night", + "URN" + ], + [ + "R1", + 2030, + "winter", + "day", + "ELC" + ], + [ + "R2", + 2020, + "summer", + "day", + "GSL" + ], + [ + "R2", + 2030, + "summer", + "day", + "URN" + ], + [ + "R1", + 2020, + "summer", + "day", + "ETH" + ], + [ + "R1", + 2025, + "summer", + "night", + "NG" + ], + [ + "R2", + 2020, + "fall", + "day", + "GSL" + ], + [ + "R2", + 2020, + "spring", + "night", + "NG" + ], + [ + "R1", + 2025, + "fall", + "night", + "E10" + ], + [ + "R1", + 2020, + "fall", + "day", + "ETH" + ], + [ + "R1", + 2030, + "summer", + "day", + "URN" + ], + [ + "R2", + 2020, + "summer", + "night", + "E10" + ], + [ + "R1", + 2030, + "winter", + "day", + "URN" + ], + [ + "R2", + 2030, + "fall", + "day", + "DSL" + ], + [ + "R2", + 2025, + "spring", + "day", + "DSL" + ], + [ + "R2", + 2020, + "winter", + "night", + "DSL" + ], + [ + "R2", + 2020, + "fall", + "day", + "E10" + ], + [ + "R2", + 2030, + "summer", + "night", + "NG" + ], + [ + "R1", + 2025, + "winter", + "day", + "NG" + ], + [ + "R1", + 2020, + "summer", + "day", + "DSL" + ], + [ + "R2", + 2020, + "fall", + "night", + "OIL" + ], + [ + "R1", + 2030, + "fall", + "day", + "ELC" + ], + [ + "R2", + 2030, + "fall", + "day", + "ELC" + ], + [ + "R1", + 2030, + "winter", + "night", + "NG" + ], + [ + "R1", + 2020, + "fall", + "day", + "DSL" + ], + [ + "R2", + 2025, + "spring", + "day", + "ELC" + ], + [ + "R2", + 2020, + "winter", + "night", + "ELC" + ], + [ + "R2", + 2030, + "winter", + "night", + "ETH" + ], + [ + "R1", + 2030, + "fall", + "day", + "URN" + ], + [ + "R1", + 2020, + "summer", + "night", + "ELC" + ], + [ + "R1", + 2020, + "summer", + "day", + "ELC" + ], + [ + "R2", + 2030, + "fall", + "day", + "URN" + ], + [ + "R2", + 2030, + "spring", + "night", + "GSL" + ], + [ + "R1", + 2025, + "summer", + "night", + "ETH" + ], + [ + "R2", + 2025, + "spring", + "day", + "URN" + ], + [ + "R1", + 2025, + "spring", + "night", + "E10" + ], + [ + "R2", + 2020, + "winter", + "night", + "URN" + ], + [ + "R2", + 2020, + "spring", + "night", + "ETH" + ], + [ + "R2", + 2025, + "winter", + "day", + "E10" + ], + [ + "R2", + 2020, + "winter", + "day", + "OIL" + ], + [ + "R1", + 2020, + "fall", + "day", + "ELC" + ], + [ + "R1", + 2025, + "fall", + "day", + "NG" + ], + [ + "R2", + 2020, + "summer", + "night", + "OIL" + ], + [ + "R1", + 2020, + "summer", + "day", + "URN" + ], + [ + "R2", + 2025, + "winter", + "night", + "OIL" + ], + [ + "R2", + 2030, + "spring", + "night", + "E10" + ], + [ + "R2", + 2025, + "summer", + "day", + "GSL" + ], + [ + "R2", + 2030, + "winter", + "day", + "OIL" + ], + [ + "R1", + 2030, + "fall", + "night", + "NG" + ], + [ + "R2", + 2030, + "summer", + "night", + "ETH" + ], + [ + "R1", + 2030, + "summer", + "night", + "NG" + ], + [ + "R1", + 2020, + "fall", + "day", + "URN" + ], + [ + "R1", + 2025, + "winter", + "day", + "ETH" + ], + [ + "R2", + 2030, + "winter", + "night", + "DSL" + ], + [ + "R1", + 2030, + "summer", + "day", + "NG" + ], + [ + "R2", + 2025, + "spring", + "night", + "NG" + ], + [ + "R1", + 2025, + "summer", + "day", + "OIL" + ], + [ + "R1", + 2030, + "winter", + "day", + "NG" + ], + [ + "R2", + 2020, + "spring", + "night", + "OIL" + ], + [ + "R2", + 2030, + "spring", + "day", + "NG" + ], + [ + "R1", + 2025, + "spring", + "day", + "GSL" + ], + [ + "R1", + 2025, + "summer", + "night", + "DSL" + ], + [ + "R1", + 2020, + "winter", + "night", + "GSL" + ], + [ + "R2", + 2020, + "spring", + "night", + "DSL" + ], + [ + "R2", + 2025, + "summer", + "day", + "E10" + ], + [ + "R1", + 2030, + "winter", + "night", + "ETH" + ], + [ + "R2", + 2025, + "fall", + "day", + "E10" + ], + [ + "R1", + 2030, + "spring", + "night", + "GSL" + ], + [ + "R2", + 2030, + "winter", + "night", + "ELC" + ], + [ + "R1", + 2025, + "spring", + "day", + "E10" + ], + [ + "R1", + 2020, + "fall", + "night", + "NG" + ], + [ + "R2", + 2030, + "summer", + "night", + "DSL" + ], + [ + "R1", + 2025, + "summer", + "night", + "ELC" + ], + [ + "R1", + 2025, + "winter", + "day", + "DSL" + ], + [ + "R2", + 2025, + "fall", + "night", + "OIL" + ], + [ + "R1", + 2030, + "spring", + "night", + "E10" + ], + [ + "R2", + 2030, + "winter", + "night", + "URN" + ], + [ + "R1", + 2030, + "winter", + "night", + "DSL" + ], + [ + "R1", + 2030, + "fall", + "day", + "NG" + ], + [ + "R2", + 2030, + "fall", + "night", + "NG" + ], + [ + "R1", + 2020, + "spring", + "night", + "GSL" + ], + [ + "R1", + 2025, + "summer", + "night", + "URN" + ], + [ + "R2", + 2020, + "spring", + "night", + "URN" + ], + [ + "R2", + 2020, + "spring", + "day", + "OIL" + ], + [ + "R1", + 2030, + "fall", + "night", + "ETH" + ], + [ + "R2", + 2030, + "summer", + "night", + "ELC" + ], + [ + "R1", + 2030, + "summer", + "night", + "ETH" + ], + [ + "R1", + 2025, + "winter", + "day", + "ELC" + ], + [ + "R1", + 2030, + "summer", + "day", + "ETH" + ], + [ + "R2", + 2025, + "spring", + "night", + "ETH" + ], + [ + "R1", + 2030, + "winter", + "day", + "ETH" + ], + [ + "R2", + 2030, + "spring", + "day", + "ETH" + ], + [ + "R1", + 2020, + "summer", + "night", + "NG" + ], + [ + "R1", + 2030, + "winter", + "night", + "ELC" + ], + [ + "R2", + 2025, + "summer", + "night", + "OIL" + ], + [ + "R2", + 2030, + "summer", + "night", + "URN" + ], + [ + "R1", + 2025, + "fall", + "day", + "DSL" + ], + [ + "R1", + 2025, + "winter", + "day", + "URN" + ], + [ + "R2", + 2030, + "summer", + "day", + "OIL" + ], + [ + "R2", + 2020, + "fall", + "night", + "GSL" + ], + [ + "R1", + 2020, + "fall", + "night", + "ETH" + ], + [ + "R1", + 2030, + "summer", + "day", + "OIL" + ], + [ + "R1", + 2030, + "fall", + "night", + "DSL" + ], + [ + "R1", + 2030, + "winter", + "night", + "URN" + ], + [ + "R1", + 2020, + "summer", + "day", + "E10" + ], + [ + "R1", + 2030, + "summer", + "night", + "DSL" + ], + [ + "R1", + 2020, + "winter", + "day", + "NG" + ], + [ + "R1", + 2030, + "winter", + "day", + "OIL" + ], + [ + "R2", + 2025, + "spring", + "night", + "DSL" + ], + [ + "R2", + 2030, + "spring", + "day", + "DSL" + ], + [ + "R2", + 2020, + "fall", + "night", + "E10" + ], + [ + "R1", + 2025, + "fall", + "day", + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "NG" + ], + [ + "R1", + 2025, + "winter", + "night", + "NG" + ], + [ + "R1", + 2030, + "fall", + "day", + "ETH" + ], + [ + "R2", + 2030, + "fall", + "night", + "ETH" + ], + [ + "R2", + 2020, + "winter", + "day", + "GSL" + ], + [ + "R1", + 2030, + "fall", + "night", + "ELC" + ], + [ + "R1", + 2030, + "summer", + "night", + "ELC" + ], + [ + "R1", + 2020, + "fall", + "night", + "DSL" + ], + [ + "R1", + 2025, + "fall", + "day", + "URN" + ], + [ + "R2", + 2025, + "spring", + "night", + "ELC" + ], + [ + "R2", + 2020, + "summer", + "night", + "GSL" + ], + [ + "R2", + 2025, + "winter", + "night", + "GSL" + ], + [ + "R2", + 2030, + "spring", + "day", + "ELC" + ], + [ + "R1", + 2020, + "summer", + "night", + "ETH" + ], + [ + "R2", + 2030, + "winter", + "day", + "GSL" + ], + [ + "R2", + 2020, + "winter", + "day", + "E10" + ], + [ + "R1", + 2020, + "spring", + "day", + "NG" + ], + [ + "R1", + 2030, + "fall", + "night", + "URN" + ], + [ + "R1", + 2030, + "fall", + "day", + "OIL" + ], + [ + "R1", + 2030, + "summer", + "night", + "URN" + ], + [ + "R1", + 2025, + "summer", + "day", + "GSL" + ], + [ + "R2", + 2030, + "fall", + "day", + "OIL" + ], + [ + "R2", + 2025, + "spring", + "night", + "URN" + ], + [ + "R2", + 2025, + "spring", + "day", + "OIL" + ], + [ + "R1", + 2030, + "fall", + "day", + "DSL" + ], + [ + "R2", + 2030, + "fall", + "night", + "DSL" + ], + [ + "R2", + 2025, + "winter", + "night", + "E10" + ], + [ + "R2", + 2020, + "winter", + "night", + "OIL" + ], + [ + "R2", + 2030, + "spring", + "day", + "URN" + ], + [ + "R1", + 2020, + "fall", + "night", + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "E10" + ], + [ + "R1", + 2025, + "fall", + "night", + "NG" + ], + [ + "R1", + 2020, + "winter", + "day", + "ETH" + ], + [ + "R2", + 2020, + "summer", + "day", + "NG" + ], + [ + "R1", + 2025, + "summer", + "day", + "E10" + ], + [ + "R1", + 2020, + "summer", + "day", + "OIL" + ], + [ + "R2", + 2020, + "spring", + "night", + "E10" + ], + [ + "R1", + 2020, + "summer", + "night", + "DSL" + ], + [ + "R1", + 2020, + "winter", + "night", + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "ETH" + ], + [ + "R1", + 2020, + "fall", + "night", + "URN" + ], + [ + "R1", + 2025, + "winter", + "night", + "ETH" + ], + [ + "R2", + 2020, + "fall", + "day", + "NG" + ], + [ + "R1", + 2020, + "fall", + "day", + "OIL" + ], + [ + "R2", + 2025, + "fall", + "night", + "GSL" + ], + [ + "R2", + 2030, + "fall", + "night", + "ELC" + ], + [ + "R1", + 2025, + "spring", + "night", + "GSL" + ], + [ + "R2", + 2025, + "winter", + "day", + "GSL" + ], + [ + "R2", + 2030, + "summer", + "night", + "E10" + ], + [ + "R1", + 2020, + "winter", + "day", + "DSL" + ], + [ + "R2", + 2025, + "fall", + "night", + "E10" + ], + [ + "R2", + 2030, + "fall", + "night", + "URN" + ], + [ + "R2", + 2020, + "spring", + "day", + "GSL" + ], + [ + "R1", + 2020, + "spring", + "day", + "ETH" + ], + [ + "R1", + 2030, + "spring", + "day", + "DSL" + ], + [ + "R1", + 2025, + "winter", + "night", + "DSL" + ], + [ + "R1", + 2020, + "spring", + "night", + "ELC" + ], + [ + "R1", + 2020, + "summer", + "night", + "URN" + ], + [ + "R2", + 2025, + "summer", + "night", + "GSL" + ], + [ + "R2", + 2020, + "spring", + "day", + "E10" + ], + [ + "R1", + 2025, + "fall", + "night", + "ETH" + ], + [ + "R2", + 2030, + "winter", + "night", + "OIL" + ], + [ + "R2", + 2030, + "summer", + "day", + "GSL" + ], + [ + "R1", + 2020, + "winter", + "day", + "ELC" + ], + [ + "R2", + 2020, + "summer", + "day", + "ETH" + ], + [ + "R2", + 2025, + "fall", + "day", + "GSL" + ], + [ + "R1", + 2025, + "summer", + "night", + "OIL" + ], + [ + "R1", + 2020, + "spring", + "night", + "URN" + ], + [ + "R2", + 2030, + "spring", + "night", + "NG" + ], + [ + "R1", + 2030, + "spring", + "day", + "ELC" + ], + [ + "R2", + 2020, + "fall", + "day", + "ETH" + ], + [ + "R1", + 2025, + "winter", + "night", + "ELC" + ], + [ + "R2", + 2025, + "summer", + "night", + "E10" + ], + [ + "R1", + 2020, + "spring", + "day", + "DSL" + ], + [ + "R2", + 2030, + "summer", + "day", + "E10" + ], + [ + "R1", + 2020, + "winter", + "day", + "URN" + ], + [ + "R2", + 2025, + "summer", + "day", + "NG" + ], + [ + "R1", + 2030, + "summer", + "day", + "E10" + ], + [ + "R1", + 2030, + "spring", + "day", + "URN" + ], + [ + "R1", + 2025, + "fall", + "night", + "DSL" + ], + [ + "R1", + 2025, + "winter", + "night", + "URN" + ], + [ + "R2", + 2030, + "summer", + "night", + "OIL" + ], + [ + "R1", + 2030, + "winter", + "day", + "E10" + ], + [ + "R1", + 2025, + "winter", + "day", + "OIL" + ], + [ + "R2", + 2020, + "summer", + "day", + "DSL" + ], + [ + "R1", + 2020, + "spring", + "day", + "ELC" + ], + [ + "R1", + 2025, + "spring", + "day", + "NG" + ], + [ + "R1", + 2020, + "winter", + "night", + "NG" + ], + [ + "R2", + 2020, + "fall", + "day", + "DSL" + ], + [ + "R1", + 2030, + "winter", + "night", + "OIL" + ], + [ + "R1", + 2025, + "fall", + "day", + "ETH" + ], + [ + "R1", + 2025, + "fall", + "night", + "ELC" + ], + [ + "R1", + 2030, + "spring", + "night", + "NG" + ], + [ + "R1", + 2020, + "spring", + "day", + "URN" + ], + [ + "R2", + 2030, + "fall", + "day", + "GSL" + ], + [ + "R2", + 2020, + "summer", + "night", + "ELC" + ], + [ + "R2", + 2025, + "spring", + "day", + "GSL" + ], + [ + "R2", + 2020, + "summer", + "day", + "ELC" + ], + [ + "R2", + 2020, + "winter", + "night", + "GSL" + ], + [ + "R2", + 2030, + "spring", + "night", + "ETH" + ], + [ + "R2", + 2020, + "fall", + "day", + "ELC" + ], + [ + "R1", + 2025, + "fall", + "night", + "URN" + ], + [ + "R1", + 2030, + "fall", + "day", + "E10" + ], + [ + "R1", + 2025, + "fall", + "day", + "OIL" + ], + [ + "R1", + 2020, + "summer", + "day", + "GSL" + ], + [ + "R2", + 2030, + "fall", + "day", + "E10" + ], + [ + "R2", + 2025, + "spring", + "day", + "E10" + ], + [ + "R2", + 2020, + "summer", + "day", + "URN" + ], + [ + "R2", + 2020, + "winter", + "night", + "E10" + ], + [ + "R1", + 2020, + "fall", + "day", + "GSL" + ], + [ + "R1", + 2020, + "spring", + "night", + "NG" + ], + [ + "R2", + 2025, + "summer", + "day", + "ETH" + ], + [ + "R1", + 2030, + "fall", + "night", + "OIL" + ], + [ + "R2", + 2020, + "fall", + "day", + "URN" + ], + [ + "R1", + 2030, + "summer", + "night", + "OIL" + ], + [ + "R1", + 2020, + "summer", + "night", + "E10" + ], + [ + "R2", + 2025, + "spring", + "night", + "OIL" + ], + [ + "R2", + 2030, + "spring", + "day", + "OIL" + ], + [ + "R2", + 2030, + "spring", + "night", + "DSL" + ], + [ + "R1", + 2025, + "spring", + "day", + "ETH" + ], + [ + "R1", + 2020, + "winter", + "night", + "ETH" + ], + [ + "R1", + 2020, + "fall", + "day", + "E10" + ], + [ + "R1", + 2025, + "spring", + "night", + "ELC" + ], + [ + "R2", + 2025, + "winter", + "day", + "ELC" + ], + [ + "R1", + 2030, + "spring", + "night", + "ETH" + ], + [ + "R2", + 2020, + "fall", + "night", + "NG" + ], + [ + "R1", + 2020, + "fall", + "night", + "OIL" + ], + [ + "R2", + 2025, + "summer", + "day", + "DSL" + ], + [ + "R2", + 2030, + "spring", + "night", + "ELC" + ], + [ + "R2", + 2030, + "winter", + "night", + "GSL" + ], + [ + "R2", + 2025, + "winter", + "day", + "URN" + ], + [ + "R1", + 2025, + "winter", + "night", + "E10" + ], + [ + "R1", + 2020, + "winter", + "night", + "OIL" + ], + [ + "R1", + 2025, + "spring", + "day", + "DSL" + ], + [ + "R1", + 2025, + "summer", + "night", + "GSL" + ], + [ + "R1", + 2020, + "winter", + "night", + "DSL" + ], + [ + "R2", + 2030, + "fall", + "night", + "OIL" + ], + [ + "R2", + 2020, + "spring", + "night", + "GSL" + ], + [ + "R2", + 2030, + "spring", + "night", + "URN" + ], + [ + "R2", + 2020, + "winter", + "day", + "NG" + ], + [ + "R1", + 2020, + "spring", + "night", + "ETH" + ], + [ + "R2", + 2025, + "summer", + "day", + "ELC" + ], + [ + "R2", + 2030, + "winter", + "night", + "E10" + ], + [ + "R1", + 2030, + "spring", + "night", + "DSL" + ], + [ + "R2", + 2025, + "fall", + "day", + "ELC" + ], + [ + "R2", + 2020, + "summer", + "night", + "NG" + ], + [ + "R1", + 2025, + "summer", + "night", + "E10" + ], + [ + "R1", + 2020, + "summer", + "night", + "OIL" + ], + [ + "R2", + 2025, + "winter", + "night", + "NG" + ], + [ + "R1", + 2025, + "spring", + "day", + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "NG" + ], + [ + "R2", + 2030, + "summer", + "night", + "GSL" + ], + [ + "R2", + 2025, + "summer", + "day", + "URN" + ], + [ + "R1", + 2025, + "winter", + "day", + "GSL" + ], + [ + "R1", + 2025, + "summer", + "day", + "NG" + ], + [ + "R2", + 2025, + "fall", + "day", + "URN" + ], + [ + "R1", + 2020, + "spring", + "night", + "OIL" + ], + [ + "R1", + 2030, + "spring", + "night", + "ELC" + ], + [ + "R2", + 2020, + "fall", + "night", + "ETH" + ], + [ + "R1", + 2030, + "winter", + "night", + "GSL" + ], + [ + "R1", + 2020, + "spring", + "night", + "DSL" + ], + [ + "R1", + 2025, + "spring", + "day", + "URN" + ], + [ + "R2", + 2020, + "summer", + "day", + "E10" + ], + [ + "R1", + 2020, + "winter", + "night", + "URN" + ], + [ + "R1", + 2025, + "winter", + "day", + "E10" + ], + [ + "R1", + 2020, + "winter", + "day", + "OIL" + ], + [ + "R1", + 2030, + "spring", + "night", + "URN" + ], + [ + "R1", + 2030, + "spring", + "day", + "OIL" + ], + [ + "R1", + 2030, + "winter", + "night", + "E10" + ], + [ + "R1", + 2025, + "winter", + "night", + "OIL" + ], + [ + "R2", + 2025, + "fall", + "night", + "NG" + ], + [ + "R2", + 2020, + "winter", + "day", + "ETH" + ], + [ + "R1", + 2025, + "fall", + "day", + "GSL" + ], + [ + "R1", + 2025, + "spring", + "night", + "NG" + ], + [ + "R2", + 2025, + "winter", + "day", + "NG" + ], + [ + "R2", + 2020, + "fall", + "night", + "DSL" + ], + [ + "R2", + 2020, + "summer", + "night", + "ETH" + ], + [ + "R2", + 2025, + "winter", + "night", + "ETH" + ], + [ + "R1", + 2030, + "fall", + "night", + "GSL" + ], + [ + "R2", + 2030, + "winter", + "day", + "ETH" + ], + [ + "R1", + 2030, + "summer", + "night", + "GSL" + ], + [ + "R2", + 2020, + "spring", + "day", + "NG" + ], + [ + "R1", + 2020, + "spring", + "day", + "OIL" + ], + [ + "R1", + 2030, + "summer", + "day", + "GSL" + ], + [ + "R2", + 2025, + "spring", + "night", + "GSL" + ], + [ + "R1", + 2025, + "fall", + "day", + "E10" + ], + [ + "R1", + 2030, + "winter", + "day", + "GSL" + ], + [ + "R2", + 2030, + "spring", + "day", + "GSL" + ], + [ + "R1", + 2025, + "summer", + "day", + "ETH" + ], + [ + "R2", + 2020, + "fall", + "night", + "ELC" + ], + [ + "R2", + 2020, + "winter", + "day", + "DSL" + ], + [ + "R1", + 2030, + "fall", + "night", + "E10" + ], + [ + "R1", + 2025, + "fall", + "night", + "OIL" + ], + [ + "R2", + 2025, + "summer", + "night", + "NG" + ], + [ + "R1", + 2030, + "summer", + "night", + "E10" + ], + [ + "R2", + 2025, + "spring", + "night", + "E10" + ], + [ + "R2", + 2030, + "summer", + "day", + "NG" + ], + [ + "R2", + 2020, + "summer", + "day", + "OIL" + ], + [ + "R2", + 2030, + "spring", + "day", + "E10" + ], + [ + "R2", + 2020, + "summer", + "night", + "DSL" + ], + [ + "R1", + 2020, + "fall", + "night", + "GSL" + ], + [ + "R2", + 2025, + "winter", + "night", + "DSL" + ], + [ + "R2", + 2025, + "fall", + "day", + "NG" + ], + [ + "R2", + 2020, + "fall", + "night", + "URN" + ], + [ + "R2", + 2020, + "fall", + "day", + "OIL" + ], + [ + "R2", + 2030, + "winter", + "day", + "DSL" + ], + [ + "R2", + 2025, + "fall", + "night", + "ETH" + ], + [ + "R2", + 2020, + "winter", + "day", + "ELC" + ], + [ + "R1", + 2025, + "summer", + "day", + "DSL" + ], + [ + "R1", + 2025, + "spring", + "night", + "ETH" + ], + [ + "R2", + 2025, + "winter", + "day", + "ETH" + ], + [ + "R1", + 2020, + "fall", + "night", + "E10" + ], + [ + "R1", + 2030, + "fall", + "day", + "GSL" + ], + [ + "R2", + 2030, + "fall", + "night", + "GSL" + ], + [ + "R2", + 2025, + "winter", + "night", + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "ELC" + ], + [ + "R2", + 2020, + "winter", + "day", + "URN" + ], + [ + "R2", + 2020, + "spring", + "day", + "ETH" + ], + [ + "R1", + 2020, + "winter", + "night", + "E10" + ], + [ + "R1", + 2020, + "summer", + "night", + "GSL" + ], + [ + "R1", + 2025, + "summer", + "day", + "ELC" + ], + [ + "R2", + 2020, + "spring", + "night", + "ELC" + ], + [ + "R2", + 2030, + "fall", + "night", + "E10" + ], + [ + "R2", + 2020, + "summer", + "night", + "URN" + ], + [ + "R2", + 2025, + "fall", + "night", + "DSL" + ], + [ + "R1", + 2025, + "spring", + "night", + "OIL" + ], + [ + "R2", + 2025, + "winter", + "night", + "URN" + ], + [ + "R2", + 2025, + "winter", + "day", + "OIL" + ], + [ + "R2", + 2025, + "summer", + "night", + "ETH" + ], + [ + "R2", + 2030, + "winter", + "day", + "URN" + ], + [ + "R1", + 2025, + "spring", + "night", + "DSL" + ], + [ + "R2", + 2025, + "winter", + "day", + "DSL" + ], + [ + "R2", + 2030, + "summer", + "day", + "ETH" + ], + [ + "R2", + 2030, + "fall", + "day", + "NG" + ], + [ + "R2", + 2025, + "spring", + "day", + "NG" + ], + [ + "R1", + 2025, + "summer", + "day", + "URN" + ], + [ + "R2", + 2020, + "winter", + "night", + "NG" + ], + [ + "R2", + 2025, + "fall", + "day", + "ETH" + ], + [ + "R2", + 2030, + "spring", + "night", + "OIL" + ], + [ + "R1", + 2020, + "winter", + "day", + "GSL" + ], + [ + "R2", + 2020, + "spring", + "day", + "DSL" + ], + [ + "R2", + 2025, + "fall", + "night", + "ELC" + ], + [ + "R1", + 2020, + "summer", + "day", + "NG" + ], + [ + "R1", + 2020, + "spring", + "night", + "E10" + ], + [ + "R1", + 2030, + "spring", + "day", + "GSL" + ], + [ + "R1", + 2025, + "winter", + "night", + "GSL" + ], + [ + "R2", + 2025, + "summer", + "day", + "OIL" + ], + [ + "R1", + 2020, + "fall", + "day", + "NG" + ], + [ + "R2", + 2025, + "summer", + "night", + "DSL" + ], + [ + "R1", + 2020, + "winter", + "day", + "E10" + ], + [ + "R2", + 2030, + "summer", + "day", + "DSL" + ], + [ + "R2", + 2025, + "fall", + "night", + "URN" + ], + [ + "R2", + 2025, + "fall", + "day", + "OIL" + ], + [ + "R2", + 2020, + "spring", + "day", + "ELC" + ], + [ + "R1", + 2025, + "spring", + "night", + "URN" + ], + [ + "R1", + 2030, + "spring", + "day", + "E10" + ], + [ + "R2", + 2025, + "fall", + "day", + "DSL" + ], + [ + "R1", + 2025, + "spring", + "day", + "OIL" + ], + [ + "R1", + 2030, + "summer", + "day", + "DSL" + ], + [ + "R1", + 2030, + "winter", + "day", + "DSL" + ], + [ + "R1", + 2020, + "spring", + "day", + "GSL" + ], + [ + "R2", + 2025, + "summer", + "night", + "ELC" + ], + [ + "R1", + 2030, + "spring", + "night", + "OIL" + ], + [ + "R2", + 2020, + "spring", + "day", + "URN" + ], + [ + "R2", + 2030, + "summer", + "day", + "ELC" + ], + [ + "R2", + 2030, + "fall", + "day", + "ETH" + ], + [ + "R2", + 2025, + "spring", + "day", + "ETH" + ] + ], + "CostEmission_rpe": [], + "CostFixed_rptv": [ + [ + "R2", + 2030, + "R_NGH", + 2030 + ], + [ + "R1", + 2030, + "E_BATT", + 2030 + ], + [ + "R1", + 2025, + "E_NGCC", + 2025 + ], + [ + "R2", + 2020, + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2025, + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "R_NGH", + 2025 + ], + [ + "R2", + 2030, + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "R_EH", + 2020 + ], + [ + "R2", + 2020, + "T_EV", + 2020 + ], + [ + "R2", + 2025, + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2030, + "T_EV", + 2030 + ], + [ + "R2", + 2030, + "T_DSL", + 2020 + ], + [ + "R2", + 2025, + "T_DSL", + 2020 + ], + [ + "R1", + 2030, + "T_EV", + 2025 + ], + [ + "R1", + 2025, + "T_GSL", + 2025 + ], + [ + "R2", + 2030, + "R_NGH", + 2025 + ], + [ + "R2", + 2020, + "S_OILREF", + 2020 + ], + [ + "R1", + 2030, + "E_BATT", + 2025 + ], + [ + "R1", + 2025, + "E_NGCC", + 2020 + ], + [ + "R2", + 2020, + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2025, + "R_NGH", + 2025 + ], + [ + "R1", + 2030, + "R_NGH", + 2020 + ], + [ + "R2", + 2020, + "T_GSL", + 2020 + ], + [ + "R1", + 2020, + "R_NGH", + 2020 + ], + [ + "R2", + 2030, + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "E_NUCLEAR", + 2025 + ], + [ + "R2-R1", + 2020, + "E_TRANS", + 2015 + ], + [ + "R2", + 2030, + "T_GSL", + 2030 + ], + [ + "R2-R1", + 2030, + "E_TRANS", + 2015 + ], + [ + "R1", + 2030, + "E_NGCC", + 2030 + ], + [ + "R2", + 2025, + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2030, + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "T_EV", + 2025 + ], + [ + "R1", + 2020, + "T_DSL", + 2020 + ], + [ + "R2", + 2020, + "E_SOLPV", + 2020 + ], + [ + "R2", + 2025, + "T_EV", + 2025 + ], + [ + "R1", + 2030, + "T_EV", + 2020 + ], + [ + "R1", + 2025, + "E_BATT", + 2025 + ], + [ + "R1", + 2025, + "S_OILREF", + 2020 + ], + [ + "R1", + 2025, + "T_GSL", + 2020 + ], + [ + "R1", + 2030, + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "R_NGH", + 2020 + ], + [ + "R1", + 2020, + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "E_SOLPV", + 2030 + ], + [ + "R2", + 2020, + "E_NGCC", + 2020 + ], + [ + "R1", + 2030, + "E_BATT", + 2020 + ], + [ + "R1", + 2020, + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "E_NGCC", + 2030 + ], + [ + "R1", + 2030, + "T_GSL", + 2030 + ], + [ + "R2", + 2025, + "R_NGH", + 2020 + ], + [ + "R2", + 2030, + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "T_GSL", + 2025 + ], + [ + "R1", + 2030, + "E_NGCC", + 2025 + ], + [ + "R2", + 2025, + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "T_EV", + 2020 + ], + [ + "R1-R2", + 2025, + "E_TRANS", + 2015 + ], + [ + "R2", + 2025, + "T_GSL", + 2025 + ], + [ + "R2", + 2025, + "T_EV", + 2020 + ], + [ + "R1", + 2025, + "T_DSL", + 2025 + ], + [ + "R2", + 2025, + "T_BLND", + 2020 + ], + [ + "R1", + 2030, + "R_EH", + 2030 + ], + [ + "R1", + 2025, + "E_SOLPV", + 2025 + ], + [ + "R2", + 2030, + "E_SOLPV", + 2025 + ], + [ + "R2", + 2030, + "S_OILREF", + 2020 + ], + [ + "R2", + 2030, + "E_NGCC", + 2025 + ], + [ + "R1", + 2030, + "T_GSL", + 2025 + ], + [ + "R2", + 2030, + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2020, + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "T_GSL", + 2020 + ], + [ + "R2", + 2025, + "S_OILREF", + 2020 + ], + [ + "R2", + 2025, + "E_NGCC", + 2025 + ], + [ + "R1", + 2030, + "E_NGCC", + 2020 + ], + [ + "R1", + 2020, + "E_NGCC", + 2020 + ], + [ + "R2", + 2025, + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2025, + "R_EH", + 2025 + ], + [ + "R2", + 2025, + "T_GSL", + 2020 + ], + [ + "R1", + 2020, + "T_EV", + 2020 + ], + [ + "R2-R1", + 2025, + "E_TRANS", + 2015 + ], + [ + "R2", + 2020, + "T_BLND", + 2020 + ], + [ + "R2", + 2020, + "E_BATT", + 2020 + ], + [ + "R2", + 2020, + "R_EH", + 2020 + ], + [ + "R1", + 2025, + "T_DSL", + 2020 + ], + [ + "R2", + 2030, + "R_EH", + 2030 + ], + [ + "R1", + 2030, + "T_DSL", + 2030 + ], + [ + "R1", + 2030, + "S_OILREF", + 2020 + ], + [ + "R1", + 2025, + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "E_NGCC", + 2020 + ], + [ + "R1", + 2030, + "T_GSL", + 2020 + ], + [ + "R1", + 2020, + "T_GSL", + 2020 + ], + [ + "R1", + 2020, + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "E_SOLPV", + 2030 + ], + [ + "R1", + 2025, + "R_NGH", + 2025 + ], + [ + "R2", + 2025, + "E_NGCC", + 2020 + ], + [ + "R1", + 2025, + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "R_EH", + 2020 + ], + [ + "R1", + 2025, + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2025, + "E_SOLPV", + 2025 + ], + [ + "R1", + 2020, + "E_SOLPV", + 2020 + ], + [ + "R1-R2", + 2030, + "E_TRANS", + 2015 + ], + [ + "R2", + 2020, + "T_DSL", + 2020 + ], + [ + "R1-R2", + 2020, + "E_TRANS", + 2015 + ], + [ + "R1", + 2025, + "T_EV", + 2025 + ], + [ + "R2", + 2030, + "T_DSL", + 2030 + ], + [ + "R2", + 2030, + "R_EH", + 2025 + ], + [ + "R2", + 2030, + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2025, + "R_EH", + 2025 + ], + [ + "R1", + 2030, + "T_DSL", + 2025 + ], + [ + "R1", + 2020, + "R_EH", + 2020 + ], + [ + "R1", + 2030, + "E_SOLPV", + 2025 + ], + [ + "R1", + 2025, + "R_NGH", + 2020 + ], + [ + "R1", + 2025, + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "R_NGH", + 2030 + ], + [ + "R2", + 2030, + "E_BATT", + 2030 + ], + [ + "R2", + 2025, + "E_SOLPV", + 2020 + ], + [ + "R1", + 2030, + "R_EH", + 2025 + ], + [ + "R1", + 2025, + "T_EV", + 2020 + ], + [ + "R1", + 2030, + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2030, + "T_DSL", + 2025 + ], + [ + "R2", + 2030, + "R_EH", + 2020 + ], + [ + "R1", + 2020, + "S_OILREF", + 2020 + ], + [ + "R2", + 2025, + "T_DSL", + 2025 + ], + [ + "R2", + 2025, + "R_EH", + 2020 + ], + [ + "R1", + 2030, + "T_EV", + 2030 + ], + [ + "R1", + 2030, + "T_DSL", + 2020 + ], + [ + "R1", + 2025, + "T_BLND", + 2020 + ], + [ + "R2", + 2020, + "R_NGH", + 2020 + ], + [ + "R1", + 2030, + "E_SOLPV", + 2020 + ] + ], + "CostInvest_rtv": [ + [ + "R2", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + "R_NGH", + 2020 + ], + [ + "R1", + "T_EV", + 2030 + ], + [ + "R2", + "T_GSL", + 2020 + ], + [ + "R1", + "E_BATT", + 2025 + ], + [ + "R1", + "E_SOLPV", + 2030 + ], + [ + "R2", + "E_NGCC", + 2025 + ], + [ + "R2", + "R_NGH", + 2030 + ], + [ + "R1", + "E_NGCC", + 2030 + ], + [ + "R2", + "R_EH", + 2025 + ], + [ + "R1", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + "R_EH", + 2030 + ], + [ + "R2", + "T_EV", + 2025 + ], + [ + "R1", + "T_DSL", + 2020 + ], + [ + "R2", + "E_BATT", + 2025 + ], + [ + "R2", + "E_SOLPV", + 2030 + ], + [ + "R1", + "T_GSL", + 2025 + ], + [ + "R2", + "T_DSL", + 2030 + ], + [ + "R1", + "T_EV", + 2020 + ], + [ + "R1", + "E_SOLPV", + 2020 + ], + [ + "R2", + "R_NGH", + 2020 + ], + [ + "R2", + "E_NUCLEAR", + 2030 + ], + [ + "R1", + "E_NGCC", + 2020 + ], + [ + "R1", + "R_NGH", + 2025 + ], + [ + "R2", + "T_GSL", + 2025 + ], + [ + "R1", + "R_EH", + 2020 + ], + [ + "R1", + "E_BATT", + 2030 + ], + [ + "R2", + "E_NGCC", + 2030 + ], + [ + "R2", + "R_EH", + 2030 + ], + [ + "R2", + "E_SOLPV", + 2020 + ], + [ + "R1", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + "T_DSL", + 2020 + ], + [ + "R2", + "T_EV", + 2030 + ], + [ + "R1", + "T_DSL", + 2025 + ], + [ + "R1", + "T_GSL", + 2030 + ], + [ + "R2", + "E_BATT", + 2030 + ], + [ + "R2", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + "T_EV", + 2025 + ], + [ + "R1", + "E_BATT", + 2020 + ], + [ + "R1", + "E_SOLPV", + 2025 + ], + [ + "R2", + "E_NGCC", + 2020 + ], + [ + "R2", + "R_NGH", + 2025 + ], + [ + "R1", + "E_NGCC", + 2025 + ], + [ + "R1", + "R_NGH", + 2030 + ], + [ + "R2", + "R_EH", + 2020 + ], + [ + "R2", + "T_GSL", + 2030 + ], + [ + "R1", + "R_EH", + 2025 + ], + [ + "R2", + "T_EV", + 2020 + ], + [ + "R2", + "E_BATT", + 2020 + ], + [ + "R2", + "E_SOLPV", + 2025 + ], + [ + "R1", + "E_NUCLEAR", + 2030 + ], + [ + "R1", + "T_GSL", + 2020 + ], + [ + "R2", + "T_DSL", + 2025 + ], + [ + "R1", + "T_DSL", + 2030 + ] + ], + "CostVariable_rptv": [ + [ + "R2", + 2030, + "R_NGH", + 2030 + ], + [ + "R2", + 2020, + "S_IMPETH", + 2020 + ], + [ + "R1", + 2030, + "E_BATT", + 2030 + ], + [ + "R1", + 2025, + "E_NGCC", + 2025 + ], + [ + "R2", + 2030, + "S_IMPNG", + 2020 + ], + [ + "R2", + 2020, + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2025, + "S_IMPURN", + 2020 + ], + [ + "R1", + 2025, + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "R_NGH", + 2025 + ], + [ + "R2", + 2030, + "E_BATT", + 2025 + ], + [ + "R2", + 2025, + "S_IMPNG", + 2020 + ], + [ + "R1", + 2030, + "R_EH", + 2020 + ], + [ + "R2", + 2020, + "T_EV", + 2020 + ], + [ + "R2", + 2025, + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2020, + "S_IMPOIL", + 2020 + ], + [ + "R2", + 2030, + "T_EV", + 2030 + ], + [ + "R2", + 2030, + "T_DSL", + 2020 + ], + [ + "R2", + 2025, + "T_DSL", + 2020 + ], + [ + "R1", + 2030, + "T_EV", + 2025 + ], + [ + "R1", + 2030, + "S_IMPNG", + 2020 + ], + [ + "R1", + 2020, + "S_IMPNG", + 2020 + ], + [ + "R1", + 2025, + "S_IMPETH", + 2020 + ], + [ + "R1", + 2025, + "T_GSL", + 2025 + ], + [ + "R1", + 2030, + "S_IMPURN", + 2020 + ], + [ + "R2", + 2030, + "R_NGH", + 2025 + ], + [ + "R1", + 2020, + "S_IMPURN", + 2020 + ], + [ + "R2", + 2020, + "S_OILREF", + 2020 + ], + [ + "R1", + 2030, + "E_BATT", + 2025 + ], + [ + "R1", + 2025, + "E_NGCC", + 2020 + ], + [ + "R2", + 2020, + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "S_IMPOIL", + 2020 + ], + [ + "R2", + 2025, + "R_NGH", + 2025 + ], + [ + "R1", + 2030, + "R_NGH", + 2020 + ], + [ + "R2", + 2020, + "T_GSL", + 2020 + ], + [ + "R1", + 2020, + "R_NGH", + 2020 + ], + [ + "R2", + 2030, + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "E_NUCLEAR", + 2025 + ], + [ + "R2-R1", + 2020, + "E_TRANS", + 2015 + ], + [ + "R2", + 2030, + "T_GSL", + 2030 + ], + [ + "R2-R1", + 2030, + "E_TRANS", + 2015 + ], + [ + "R1", + 2030, + "E_NGCC", + 2030 + ], + [ + "R2", + 2025, + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2030, + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "T_EV", + 2025 + ], + [ + "R1", + 2020, + "T_DSL", + 2020 + ], + [ + "R2", + 2020, + "E_SOLPV", + 2020 + ], + [ + "R2", + 2025, + "T_EV", + 2025 + ], + [ + "R1", + 2030, + "T_EV", + 2020 + ], + [ + "R1", + 2025, + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "S_IMPOIL", + 2020 + ], + [ + "R1", + 2025, + "S_OILREF", + 2020 + ], + [ + "R1", + 2025, + "T_GSL", + 2020 + ], + [ + "R1", + 2030, + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "R_NGH", + 2020 + ], + [ + "R1", + 2020, + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "E_SOLPV", + 2030 + ], + [ + "R2", + 2020, + "E_NGCC", + 2020 + ], + [ + "R1", + 2030, + "E_BATT", + 2020 + ], + [ + "R1", + 2020, + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "S_IMPETH", + 2020 + ], + [ + "R2", + 2030, + "E_NGCC", + 2030 + ], + [ + "R1", + 2030, + "T_GSL", + 2030 + ], + [ + "R2", + 2025, + "R_NGH", + 2020 + ], + [ + "R2", + 2030, + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "T_GSL", + 2025 + ], + [ + "R2", + 2025, + "S_IMPETH", + 2020 + ], + [ + "R1", + 2030, + "E_NGCC", + 2025 + ], + [ + "R2", + 2025, + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "T_EV", + 2020 + ], + [ + "R1-R2", + 2025, + "E_TRANS", + 2015 + ], + [ + "R2", + 2025, + "T_GSL", + 2025 + ], + [ + "R2", + 2020, + "S_IMPNG", + 2020 + ], + [ + "R2", + 2025, + "T_EV", + 2020 + ], + [ + "R2", + 2025, + "S_IMPOIL", + 2020 + ], + [ + "R1", + 2025, + "T_DSL", + 2025 + ], + [ + "R2", + 2025, + "T_BLND", + 2020 + ], + [ + "R1", + 2030, + "R_EH", + 2030 + ], + [ + "R1", + 2030, + "S_IMPETH", + 2020 + ], + [ + "R1", + 2025, + "E_SOLPV", + 2025 + ], + [ + "R2", + 2030, + "E_SOLPV", + 2025 + ], + [ + "R2", + 2030, + "S_OILREF", + 2020 + ], + [ + "R2", + 2030, + "E_NGCC", + 2025 + ], + [ + "R1", + 2030, + "T_GSL", + 2025 + ], + [ + "R2", + 2030, + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2020, + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2025, + "S_IMPURN", + 2020 + ], + [ + "R2", + 2030, + "T_GSL", + 2020 + ], + [ + "R2", + 2025, + "S_OILREF", + 2020 + ], + [ + "R2", + 2025, + "E_NGCC", + 2025 + ], + [ + "R1", + 2030, + "E_NGCC", + 2020 + ], + [ + "R1", + 2020, + "E_NGCC", + 2020 + ], + [ + "R2", + 2025, + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2025, + "R_EH", + 2025 + ], + [ + "R2", + 2025, + "T_GSL", + 2020 + ], + [ + "R1", + 2020, + "T_EV", + 2020 + ], + [ + "R2-R1", + 2025, + "E_TRANS", + 2015 + ], + [ + "R1", + 2020, + "S_IMPOIL", + 2020 + ], + [ + "R2", + 2020, + "T_BLND", + 2020 + ], + [ + "R2", + 2020, + "E_BATT", + 2020 + ], + [ + "R2", + 2020, + "R_EH", + 2020 + ], + [ + "R1", + 2025, + "T_DSL", + 2020 + ], + [ + "R2", + 2030, + "R_EH", + 2030 + ], + [ + "R1", + 2030, + "T_DSL", + 2030 + ], + [ + "R1", + 2030, + "S_OILREF", + 2020 + ], + [ + "R1", + 2025, + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "E_NGCC", + 2020 + ], + [ + "R1", + 2030, + "T_GSL", + 2020 + ], + [ + "R1", + 2020, + "T_GSL", + 2020 + ], + [ + "R2", + 2020, + "S_IMPURN", + 2020 + ], + [ + "R1", + 2020, + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "E_SOLPV", + 2030 + ], + [ + "R1", + 2025, + "R_NGH", + 2025 + ], + [ + "R2", + 2025, + "E_NGCC", + 2020 + ], + [ + "R1", + 2025, + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "R_EH", + 2020 + ], + [ + "R1", + 2025, + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2025, + "E_SOLPV", + 2025 + ], + [ + "R1", + 2020, + "E_SOLPV", + 2020 + ], + [ + "R1-R2", + 2030, + "E_TRANS", + 2015 + ], + [ + "R2", + 2020, + "T_DSL", + 2020 + ], + [ + "R1-R2", + 2020, + "E_TRANS", + 2015 + ], + [ + "R1", + 2025, + "T_EV", + 2025 + ], + [ + "R1", + 2025, + "S_IMPNG", + 2020 + ], + [ + "R2", + 2030, + "T_DSL", + 2030 + ], + [ + "R2", + 2030, + "R_EH", + 2025 + ], + [ + "R1", + 2020, + "S_IMPETH", + 2020 + ], + [ + "R2", + 2030, + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2025, + "R_EH", + 2025 + ], + [ + "R1", + 2030, + "T_DSL", + 2025 + ], + [ + "R1", + 2020, + "R_EH", + 2020 + ], + [ + "R1", + 2030, + "E_SOLPV", + 2025 + ], + [ + "R1", + 2025, + "R_NGH", + 2020 + ], + [ + "R1", + 2025, + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "R_NGH", + 2030 + ], + [ + "R2", + 2030, + "E_BATT", + 2030 + ], + [ + "R2", + 2025, + "E_SOLPV", + 2020 + ], + [ + "R1", + 2030, + "R_EH", + 2025 + ], + [ + "R1", + 2025, + "T_EV", + 2020 + ], + [ + "R1", + 2030, + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2030, + "T_DSL", + 2025 + ], + [ + "R1", + 2025, + "S_IMPOIL", + 2020 + ], + [ + "R2", + 2030, + "R_EH", + 2020 + ], + [ + "R1", + 2020, + "S_OILREF", + 2020 + ], + [ + "R2", + 2025, + "T_DSL", + 2025 + ], + [ + "R2", + 2025, + "R_EH", + 2020 + ], + [ + "R1", + 2030, + "T_EV", + 2030 + ], + [ + "R1", + 2030, + "T_DSL", + 2020 + ], + [ + "R1", + 2025, + "T_BLND", + 2020 + ], + [ + "R2", + 2020, + "R_NGH", + 2020 + ], + [ + "R1", + 2030, + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "S_IMPURN", + 2020 + ] + ], + "CurtailmentVar_rpsditvo": [ + [ + "R2", + 2025, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2025, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2020, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2020, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2020, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2025, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2020, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2025, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2020, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2025, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2030, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2020, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2025, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2030, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2030, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2025, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2030, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2025, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2025, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2025, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2030, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2030, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2030, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2020, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2030, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2020, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2030, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2030, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2030, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2030, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2030, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2030, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2020, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2020, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2025, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2025, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2025, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2025, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2020, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2020, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2030, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2025, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2020, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2020, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2030, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2020, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2020, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2025, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2030, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2025, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2020, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2020, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2020, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2020, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2025, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2020, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2020, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2025, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2025, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2030, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2030, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2020, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2030, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2020, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2025, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2030, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2030, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2030, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2025, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2025, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2025, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2020, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2025, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2020, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2025, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2020, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2020, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2030, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2020, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2030, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2020, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2025, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2025, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2020, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2020, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2025, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2025, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2030, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2030, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2025, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2025, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2030, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2030, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2030, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2030, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2030, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ] + ], + "DemandActivityConstraint_rpsdtv_dem_s0d0": [ + [ + "R1", + 2020, + "fall", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "spring", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "day", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "spring", + "night", + "R_EH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "fall", + "day", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "day", + "R_EH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "night", + "T_GSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "spring", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "winter", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "night", + "R_EH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "winter", + "day", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_DSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "fall", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "winter", + "day", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "night", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "night", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "day", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2020, + "fall", + "day", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "spring", + "night", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "night", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "night", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "spring", + "night", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2020, + "fall", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "winter", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "summer", + "day", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2020, + "winter", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "spring", + "night", + "R_NGH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "spring", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "spring", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "night", + "T_GSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_GSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "summer", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "fall", + "night", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_EV", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "winter", + "day", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "fall", + "night", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "night", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "winter", + "night", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "night", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "winter", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "day", + "T_GSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "summer", + "night", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "fall", + "day", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2020, + "winter", + "day", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "day", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "night", + "T_DSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "summer", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2020, + "winter", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "night", + "T_DSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "day", + "T_EV", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2020, + "fall", + "day", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "fall", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "spring", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "day", + "R_NGH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "day", + "T_EV", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "summer", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "night", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2020, + "summer", + "day", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2020, + "summer", + "day", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "fall", + "night", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "summer", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_EV", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "winter", + "day", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "fall", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_EV", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_GSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "night", + "R_NGH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "winter", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "summer", + "night", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "night", + "R_NGH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R1", + 2020, + "winter", + "day", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_EV", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "spring", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "spring", + "night", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "day", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "summer", + "day", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "summer", + "day", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "day", + "R_EH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "fall", + "day", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2020, + "fall", + "day", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2020, + "spring", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "winter", + "night", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2020, + "winter", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "spring", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_DSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "spring", + "night", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "fall", + "day", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "summer", + "night", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2020, + "summer", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "night", + "R_EH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "winter", + "day", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "fall", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "day", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "day", + "T_DSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "fall", + "day", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "day", + "R_NGH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "day", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "spring", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "winter", + "day", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "night", + "T_DSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "winter", + "day", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "winter", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "day", + "T_DSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "spring", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "night", + "T_GSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "day", + "T_GSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "spring", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "spring", + "night", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "night", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "spring", + "night", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "spring", + "night", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "night", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2020, + "winter", + "day", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2020, + "summer", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2020, + "summer", + "day", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "night", + "T_EV", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "night", + "R_EH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "fall", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2020, + "summer", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "day", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "spring", + "night", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "fall", + "night", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "summer", + "day", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2020, + "fall", + "day", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "winter", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "winter", + "day", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "fall", + "day", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2020, + "summer", + "day", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2020, + "summer", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2020, + "winter", + "day", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "day", + "R_EH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "night", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "summer", + "day", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "spring", + "night", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "day", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2020, + "summer", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2020, + "winter", + "day", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "winter", + "day", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "fall", + "day", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "day", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "winter", + "night", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2020, + "winter", + "day", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "fall", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "winter", + "day", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "summer", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "spring", + "night", + "T_EV", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2020, + "summer", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "spring", + "night", + "R_NGH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "summer", + "day", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "fall", + "night", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_DSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "spring", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "spring", + "night", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "winter", + "day", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "fall", + "night", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "day", + "R_EH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "night", + "R_NGH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "summer", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2020, + "spring", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "summer", + "day", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "night", + "R_NGH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "day", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2020, + "summer", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "winter", + "day", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "night", + "T_DSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "fall", + "night", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "spring", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2020, + "winter", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "night", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2020, + "fall", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "fall", + "day", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "day", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2020, + "summer", + "day", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "night", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "fall", + "night", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2020, + "fall", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "fall", + "day", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "summer", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "day", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "summer", + "night", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "summer", + "night", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2020, + "winter", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2020, + "winter", + "day", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "night", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "day", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "day", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "spring", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "spring", + "night", + "T_DSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "day", + "R_NGH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "night", + "R_EH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "spring", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2020, + "fall", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "day", + "R_EH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R1", + 2020, + "spring", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "summer", + "day", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "night", + "T_EV", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "spring", + "night", + "T_GSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2020, + "fall", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "fall", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "day", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "day", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "summer", + "day", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2020, + "fall", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "spring", + "night", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "day", + "R_NGH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "summer", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "summer", + "day", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_GSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_EV", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2020, + "summer", + "day", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2020, + "spring", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2020, + "summer", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "day", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2020, + "winter", + "day", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2020, + "spring", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_DSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "winter", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "night", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_GSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "fall", + "day", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "fall", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "night", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "day", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "night", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "fall", + "day", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "fall", + "day", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "day", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_GSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "spring", + "night", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "night", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "night", + "T_EV", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2020, + "fall", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "day", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "winter", + "day", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "night", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "fall", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2020, + "winter", + "day", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_DSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "night", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "summer", + "day", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2020, + "spring", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "day", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "fall", + "day", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "summer", + "day", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "day", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "summer", + "night", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "day", + "T_GSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "day", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "winter", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_GSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "fall", + "night", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "spring", + "night", + "R_EH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "summer", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2020, + "spring", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2020, + "winter", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "winter", + "day", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "day", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2020, + "fall", + "day", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "day", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2020, + "winter", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "winter", + "day", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "day", + "T_DSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2020, + "fall", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "night", + "R_NGH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "summer", + "day", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "day", + "T_EV", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2020, + "fall", + "day", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_EV", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "winter", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "spring", + "night", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "fall", + "day", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "day", + "R_NGH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "night", + "R_NGH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R2", + 2020, + "summer", + "day", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2020, + "fall", + "day", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "winter", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "fall", + "day", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2020, + "summer", + "day", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "spring", + "night", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "day", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "day", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2020, + "summer", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "day", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "winter", + "day", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "day", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2020, + "winter", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "summer", + "day", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "winter", + "night", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "summer", + "day", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "fall", + "night", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "day", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "night", + "R_EH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R1", + 2020, + "summer", + "day", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "winter", + "day", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "night", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2020, + "winter", + "day", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "winter", + "night", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "summer", + "day", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "spring", + "night", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "spring", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2020, + "spring", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "day", + "R_EH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "night", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "night", + "T_EV", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "day", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "summer", + "night", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "day", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "winter", + "day", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "fall", + "day", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "day", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "night", + "T_GSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2020, + "fall", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2020, + "spring", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "spring", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "winter", + "night", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "spring", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2020, + "summer", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2020, + "fall", + "day", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2020, + "spring", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "summer", + "night", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "day", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "winter", + "night", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "summer", + "day", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "fall", + "day", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "night", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "spring", + "night", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "summer", + "day", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "summer", + "night", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "night", + "R_EH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "night", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "summer", + "night", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "summer", + "night", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2020, + "summer", + "day", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "winter", + "night", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "winter", + "day", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_DSL", + 2030, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "winter", + "night", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "summer", + "day", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "night", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "day", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2020, + "fall", + "day", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "day", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "fall", + "day", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "day", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "winter", + "night", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2020, + "winter", + "night", + "R_EH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "fall", + "day", + "R_EH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "night", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2020, + "winter", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "day", + "T_GSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2025, + "spring", + "night", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "day", + "T_EV", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_DSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2030, + "summer", + "day", + "R_NGH", + 2030, + "RH", + "spring", + "day" + ], + [ + "R1", + 2025, + "fall", + "night", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "summer", + "day", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_EV", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2030, + "winter", + "day", + "R_NGH", + 2025, + "RH", + "spring", + "day" + ], + [ + "R2", + 2030, + "winter", + "night", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R1", + 2030, + "summer", + "day", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "winter", + "day", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ], + [ + "R2", + 2025, + "fall", + "day", + "T_GSL", + 2025, + "VMT", + "spring", + "day" + ], + [ + "R1", + 2025, + "fall", + "day", + "T_DSL", + 2020, + "VMT", + "spring", + "day" + ], + [ + "R2", + 2020, + "fall", + "day", + "R_NGH", + 2020, + "RH", + "spring", + "day" + ] + ], + "DemandConstraint_rpsdc": [ + [ + "R1", + 2030, + "spring", + "day", + "VMT" + ], + [ + "R1", + 2025, + "summer", + "day", + "RH" + ], + [ + "R1", + 2025, + "winter", + "night", + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "RH" + ], + [ + "R1", + 2030, + "fall", + "day", + "RH" + ], + [ + "R2", + 2030, + "summer", + "night", + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "RH" + ], + [ + "R2", + 2025, + "summer", + "night", + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "RH" + ], + [ + "R1", + 2025, + "winter", + "day", + "VMT" + ], + [ + "R2", + 2025, + "spring", + "day", + "RH" + ], + [ + "R2", + 2030, + "summer", + "day", + "VMT" + ], + [ + "R2", + 2020, + "winter", + "day", + "RH" + ], + [ + "R1", + 2030, + "winter", + "night", + "VMT" + ], + [ + "R1", + 2030, + "summer", + "day", + "VMT" + ], + [ + "R1", + 2020, + "summer", + "night", + "RH" + ], + [ + "R1", + 2030, + "winter", + "day", + "VMT" + ], + [ + "R2", + 2025, + "summer", + "day", + "RH" + ], + [ + "R1", + 2020, + "spring", + "day", + "VMT" + ], + [ + "R2", + 2030, + "winter", + "night", + "RH" + ], + [ + "R1", + 2020, + "fall", + "day", + "RH" + ], + [ + "R1", + 2025, + "spring", + "night", + "RH" + ], + [ + "R2", + 2030, + "winter", + "day", + "RH" + ], + [ + "R2", + 2025, + "winter", + "day", + "RH" + ], + [ + "R1", + 2025, + "spring", + "day", + "RH" + ], + [ + "R1", + 2025, + "summer", + "night", + "RH" + ], + [ + "R1", + 2020, + "winter", + "night", + "RH" + ], + [ + "R1", + 2025, + "fall", + "night", + "VMT" + ], + [ + "R2", + 2020, + "spring", + "night", + "RH" + ], + [ + "R1", + 2020, + "winter", + "day", + "RH" + ], + [ + "R1", + 2025, + "fall", + "day", + "VMT" + ], + [ + "R2", + 2020, + "summer", + "day", + "VMT" + ], + [ + "R2", + 2020, + "spring", + "day", + "RH" + ], + [ + "R2", + 2020, + "fall", + "night", + "VMT" + ], + [ + "R1", + 2030, + "spring", + "night", + "RH" + ], + [ + "R2", + 2020, + "fall", + "day", + "VMT" + ], + [ + "R1", + 2025, + "winter", + "night", + "RH" + ], + [ + "R1", + 2030, + "fall", + "night", + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "RH" + ], + [ + "R2", + 2025, + "spring", + "night", + "VMT" + ], + [ + "R1", + 2025, + "winter", + "day", + "RH" + ], + [ + "R1", + 2030, + "fall", + "day", + "VMT" + ], + [ + "R2", + 2025, + "summer", + "night", + "RH" + ], + [ + "R2", + 2030, + "fall", + "day", + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "VMT" + ], + [ + "R2", + 2025, + "spring", + "day", + "VMT" + ], + [ + "R2", + 2025, + "fall", + "night", + "RH" + ], + [ + "R2", + 2020, + "winter", + "night", + "VMT" + ], + [ + "R2", + 2025, + "fall", + "day", + "RH" + ], + [ + "R2", + 2020, + "winter", + "day", + "VMT" + ], + [ + "R1", + 2030, + "winter", + "night", + "RH" + ], + [ + "R1", + 2020, + "spring", + "night", + "RH" + ], + [ + "R1", + 2020, + "summer", + "day", + "VMT" + ], + [ + "R1", + 2020, + "spring", + "day", + "RH" + ], + [ + "R2", + 2020, + "summer", + "night", + "VMT" + ], + [ + "R1", + 2020, + "fall", + "night", + "VMT" + ], + [ + "R2", + 2025, + "winter", + "night", + "VMT" + ], + [ + "R1", + 2020, + "fall", + "day", + "VMT" + ], + [ + "R1", + 2025, + "spring", + "night", + "VMT" + ], + [ + "R2", + 2030, + "winter", + "day", + "VMT" + ], + [ + "R2", + 2025, + "winter", + "day", + "VMT" + ], + [ + "R1", + 2030, + "spring", + "day", + "RH" + ], + [ + "R1", + 2025, + "fall", + "night", + "RH" + ], + [ + "R1", + 2020, + "winter", + "night", + "VMT" + ], + [ + "R1", + 2025, + "summer", + "day", + "VMT" + ], + [ + "R2", + 2020, + "spring", + "night", + "VMT" + ], + [ + "R2", + 2020, + "summer", + "day", + "RH" + ], + [ + "R2", + 2030, + "fall", + "night", + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "VMT" + ], + [ + "R2", + 2020, + "fall", + "night", + "RH" + ], + [ + "R2", + 2030, + "summer", + "day", + "RH" + ], + [ + "R1", + 2030, + "fall", + "night", + "RH" + ], + [ + "R1", + 2030, + "summer", + "day", + "RH" + ], + [ + "R2", + 2025, + "spring", + "night", + "RH" + ], + [ + "R1", + 2020, + "summer", + "night", + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "RH" + ], + [ + "R2", + 2030, + "fall", + "day", + "RH" + ], + [ + "R2", + 2030, + "spring", + "day", + "RH" + ], + [ + "R2", + 2025, + "summer", + "day", + "VMT" + ], + [ + "R2", + 2020, + "winter", + "night", + "RH" + ], + [ + "R2", + 2025, + "fall", + "night", + "VMT" + ], + [ + "R2", + 2030, + "winter", + "night", + "VMT" + ], + [ + "R2", + 2025, + "fall", + "day", + "VMT" + ], + [ + "R1", + 2020, + "spring", + "night", + "VMT" + ], + [ + "R1", + 2025, + "spring", + "day", + "VMT" + ], + [ + "R1", + 2020, + "summer", + "day", + "RH" + ], + [ + "R1", + 2025, + "summer", + "night", + "VMT" + ], + [ + "R2", + 2020, + "summer", + "night", + "RH" + ], + [ + "R1", + 2020, + "fall", + "night", + "RH" + ], + [ + "R1", + 2025, + "fall", + "day", + "RH" + ], + [ + "R2", + 2025, + "winter", + "night", + "RH" + ], + [ + "R1", + 2020, + "winter", + "day", + "VMT" + ], + [ + "R2", + 2020, + "spring", + "day", + "VMT" + ], + [ + "R1", + 2030, + "spring", + "night", + "VMT" + ], + [ + "R2", + 2020, + "fall", + "day", + "RH" + ] + ], + "EmissionActivity_reitvo": [ + [ + "R1", + "CO2", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + "CO2", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + "CO2", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R1", + "CO2", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + "CO2", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R1", + "CO2", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + "CO2", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + "CO2", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + "CO2", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + "CO2", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + "CO2", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + "CO2", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + "CO2", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R2", + "CO2", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + "CO2", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R1", + "CO2", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + "CO2", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + "CO2", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + "CO2", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + "CO2", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + "CO2", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", + "CO2", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + "CO2", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + "CO2", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + "CO2", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", + "CO2", + "SOL", + "E_SOLPV", + 2030, + "ELC" + ], + [ + "R1", + "CO2", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + "CO2", + "URN", + "E_NUCLEAR", + 2030, + "ELC" + ], + [ + "R1", + "CO2", + "SOL", + "E_SOLPV", + 2030, + "ELC" + ], + [ + "R2", + "CO2", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + "CO2", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + "CO2", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + "CO2", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + "CO2", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + "CO2", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + "CO2", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + "CO2", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R1", + "CO2", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + "CO2", + "URN", + "E_NUCLEAR", + 2030, + "ELC" + ], + [ + "R2", + "CO2", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + "CO2", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + "CO2", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + "CO2", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R2", + "CO2", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + "CO2", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + "CO2", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R1", + "CO2", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R1", + "CO2", + "NG", + "E_NGCC", + 2030, + "ELC" + ], + [ + "R2", + "CO2", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + "CO2", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + "CO2", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + "CO2", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + "CO2", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + "CO2", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + "CO2", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + "CO2", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + "CO2", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R1", + "CO2", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + "CO2", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + "CO2", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + "CO2", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + "CO2", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + "CO2", + "NG", + "E_NGCC", + 2030, + "ELC" + ], + [ + "R2", + "CO2", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + "CO2", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + "CO2", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R1", + "CO2", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + "CO2", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + "CO2", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R2", + "CO2", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + "CO2", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + "CO2", + "ELC", + "R_EH", + 2020, + "RH" + ] + ], + "FlexVarAnnual_rpitvo": [], + "FlexVar_rpsditvo": [], + "FlowInStorage_rpsditvo": [ + [ + "R2", + 2030, + "summer", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2020, + "winter", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R1", + 2020, + "winter", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "summer", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "winter", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "winter", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "fall", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2020, + "summer", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2020, + "spring", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2020, + "winter", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "winter", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "summer", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "fall", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "fall", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "fall", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2020, + "spring", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "winter", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "winter", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2020, + "spring", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2020, + "spring", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2020, + "summer", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ] + ], + "FlowVarAnnual_rpitvo": [], + "FlowVar_rpsditvo": [ + [ + "R1", + 2030, + "winter", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2020, + "spring", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2025, + "fall", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2025, + "winter", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "fall", + "night", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2020, + "winter", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2020, + "winter", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "day", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2030, + "summer", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2025, + "fall", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "spring", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "spring", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2030, + "winter", + "night", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "night", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "winter", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "summer", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2-R1", + 2025, + "fall", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R1", + 2020, + "summer", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2030, + "summer", + "night", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2025, + "fall", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2025, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2025, + "spring", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2030, + "spring", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2025, + "winter", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "night", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R2", + 2020, + "summer", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "fall", + "day", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2020, + "winter", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2020, + "fall", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2020, + "fall", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2025, + "fall", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2025, + "winter", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2025, + "summer", + "day", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "fall", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "winter", + "night", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "spring", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "day", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "day", + "NG", + "E_NGCC", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "spring", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "summer", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "winter", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2020, + "fall", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "winter", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2020, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2030, + "winter", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "SOL", + "E_SOLPV", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "fall", + "day", + "NG", + "E_NGCC", + 2030, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2020, + "spring", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "summer", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "night", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "spring", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2025, + "spring", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R1", + 2030, + "winter", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2020, + "summer", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "summer", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R1", + 2030, + "fall", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R1", + 2030, + "fall", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2025, + "fall", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "spring", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2030, + "winter", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2-R1", + 2030, + "summer", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "summer", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2020, + "fall", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "winter", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2020, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2030, + "winter", + "night", + "URN", + "E_NUCLEAR", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2025, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2-R1", + 2020, + "summer", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R1", + 2025, + "spring", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2-R1", + 2025, + "summer", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2030, + "fall", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2025, + "winter", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2030, + "fall", + "day", + "URN", + "E_NUCLEAR", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R1", + 2030, + "spring", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2025, + "summer", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "winter", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "summer", + "day", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "NG", + "E_NGCC", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "night", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "winter", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2020, + "spring", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2025, + "summer", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + 2020, + "fall", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "winter", + "day", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "day", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "winter", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "summer", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "winter", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2030, + "spring", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2025, + "winter", + "night", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2-R1", + 2025, + "spring", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "day", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "spring", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R1", + 2025, + "winter", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2030, + "spring", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2025, + "fall", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2025, + "winter", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "fall", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2030, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2025, + "fall", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2020, + "fall", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R2", + 2020, + "winter", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "fall", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "night", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2025, + "summer", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2025, + "fall", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2025, + "fall", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "spring", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "summer", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "summer", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2030, + "fall", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2025, + "spring", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "spring", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2020, + "summer", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2025, + "winter", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "day", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2030, + "spring", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "summer", + "night", + "URN", + "E_NUCLEAR", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "summer", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2030, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2020, + "winter", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "fall", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2025, + "summer", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "SOL", + "E_SOLPV", + 2030, + "ELC" + ], + [ + "R1", + 2020, + "winter", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2030, + "fall", + "day", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2030, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2020, + "summer", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2030, + "winter", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2020, + "spring", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2030, + "spring", + "night", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "night", + "SOL", + "E_SOLPV", + 2030, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2030, + "spring", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "spring", + "day", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2020, + "fall", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "winter", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "winter", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "night", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "spring", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "spring", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "summer", + "day", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "day", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + 2025, + "spring", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2020, + "summer", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2030, + "fall", + "day", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R1", + 2020, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2030, + "fall", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2025, + "fall", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "day", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2020, + "summer", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "spring", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2020, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2030, + "winter", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2030, + "winter", + "day", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2-R1", + 2025, + "winter", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "night", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R1", + 2025, + "summer", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "day", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2030, + "summer", + "day", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "night", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "winter", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2-R1", + 2020, + "fall", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2", + 2020, + "summer", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2-R1", + 2020, + "fall", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "night", + "SOL", + "E_SOLPV", + 2030, + "ELC" + ], + [ + "R1", + 2020, + "spring", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "winter", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "fall", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2030, + "fall", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2020, + "summer", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "spring", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2030, + "spring", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "summer", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2025, + "summer", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2025, + "spring", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2030, + "winter", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "winter", + "day", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2030, + "fall", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", + 2020, + "summer", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "fall", + "day", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R1", + 2020, + "spring", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2020, + "summer", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2020, + "fall", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "fall", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2020, + "winter", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2020, + "winter", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "day", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R1", + 2025, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2025, + "fall", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "day", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R1", + 2030, + "summer", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", + 2020, + "spring", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R1", + 2025, + "winter", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2020, + "winter", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2025, + "spring", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2020, + "winter", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "winter", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2030, + "spring", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1-R2", + 2030, + "summer", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "spring", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1-R2", + 2030, + "winter", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2025, + "summer", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2030, + "spring", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2-R1", + 2025, + "spring", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "winter", + "night", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "night", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1-R2", + 2020, + "winter", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2020, + "summer", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2025, + "summer", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "winter", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "spring", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "day", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2020, + "summer", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "spring", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "summer", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "fall", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "day", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2025, + "summer", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "spring", + "day", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2030, + "summer", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2030, + "fall", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "spring", + "night", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "day", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2025, + "spring", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2030, + "fall", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R1", + 2025, + "summer", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "day", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "night", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2030, + "fall", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "night", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2020, + "winter", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2020, + "winter", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2020, + "fall", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1-R2", + 2020, + "spring", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2020, + "summer", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "night", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "spring", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "winter", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2020, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2030, + "summer", + "night", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "summer", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1-R2", + 2030, + "fall", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "night", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2025, + "summer", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "winter", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2030, + "fall", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2020, + "summer", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R1", + 2025, + "fall", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "spring", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "fall", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "fall", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2030, + "winter", + "day", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R1", + 2025, + "winter", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2020, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2030, + "fall", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "day", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2020, + "fall", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2025, + "fall", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "fall", + "day", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R2", + 2020, + "spring", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "day", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "night", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R1", + 2030, + "winter", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "summer", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "winter", + "day", + "NG", + "E_NGCC", + 2030, + "ELC" + ], + [ + "R2", + 2020, + "fall", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2025, + "winter", + "day", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2020, + "summer", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2020, + "winter", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R1-R2", + 2025, + "fall", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2030, + "fall", + "day", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R2", + 2020, + "fall", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2020, + "spring", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "summer", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "spring", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2025, + "fall", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "day", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2025, + "summer", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2020, + "summer", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2020, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2030, + "spring", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2030, + "summer", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2030, + "spring", + "night", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2025, + "summer", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2025, + "winter", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "fall", + "day", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2020, + "fall", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2020, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2025, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2030, + "winter", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "fall", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2-R1", + 2025, + "summer", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2", + 2020, + "fall", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2030, + "spring", + "night", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "day", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "night", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2020, + "spring", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "winter", + "day", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2-R1", + 2030, + "spring", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2", + 2020, + "winter", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "winter", + "day", + "URN", + "E_NUCLEAR", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "night", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R1", + 2025, + "spring", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "fall", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2030, + "summer", + "night", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2025, + "summer", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2025, + "fall", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "fall", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2030, + "spring", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2025, + "winter", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2020, + "summer", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2025, + "summer", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "night", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + 2020, + "summer", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "night", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2030, + "spring", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2020, + "summer", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "winter", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "winter", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2025, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2030, + "winter", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "winter", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2020, + "summer", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2025, + "winter", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2025, + "summer", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2025, + "spring", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "fall", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2030, + "winter", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2030, + "winter", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2025, + "fall", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "winter", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2030, + "fall", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2020, + "winter", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "fall", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2020, + "spring", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2025, + "summer", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2020, + "fall", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2025, + "winter", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2020, + "spring", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "summer", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2025, + "winter", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "fall", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2-R1", + 2030, + "winter", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2020, + "winter", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2025, + "fall", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "day", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "night", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "spring", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "spring", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2030, + "summer", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R1", + 2030, + "summer", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2-R1", + 2020, + "summer", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "night", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R2", + 2020, + "summer", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "day", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2030, + "winter", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "summer", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "fall", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "fall", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2030, + "summer", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1-R2", + 2020, + "spring", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "night", + "SOL", + "E_SOLPV", + 2030, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "summer", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2020, + "fall", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "summer", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "summer", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2025, + "fall", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "spring", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "fall", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "fall", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "NG", + "E_NGCC", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "night", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "spring", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2020, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2030, + "summer", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "spring", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "summer", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2030, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2025, + "spring", + "day", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "winter", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2025, + "summer", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "NG", + "E_NGCC", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "spring", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "winter", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2025, + "spring", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2020, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2030, + "spring", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2030, + "winter", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2025, + "spring", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "night", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "winter", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "spring", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "night", + "URN", + "E_NUCLEAR", + 2030, + "ELC" + ], + [ + "R1", + 2020, + "winter", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2030, + "summer", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "winter", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R1", + 2025, + "spring", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "winter", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2025, + "winter", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2030, + "winter", + "night", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2030, + "winter", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2020, + "winter", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2020, + "fall", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2020, + "winter", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2030, + "spring", + "day", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2030, + "fall", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "winter", + "day", + "URN", + "E_NUCLEAR", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2020, + "spring", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2030, + "fall", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1-R2", + 2030, + "spring", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2025, + "winter", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "fall", + "night", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2030, + "fall", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2020, + "summer", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2030, + "spring", + "day", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2030, + "winter", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "fall", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "summer", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "spring", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2020, + "spring", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2025, + "winter", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2030, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2025, + "winter", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "winter", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2025, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2020, + "summer", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "spring", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2020, + "fall", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "spring", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2025, + "spring", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "night", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2020, + "winter", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "summer", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2030, + "fall", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2030, + "spring", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "winter", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2030, + "winter", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2030, + "summer", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "night", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R1", + 2020, + "spring", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2-R1", + 2025, + "fall", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "day", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "winter", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "summer", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2020, + "fall", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "night", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + 2020, + "winter", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "winter", + "night", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2030, + "winter", + "day", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + 2020, + "spring", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "night", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "night", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R1", + 2030, + "spring", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "summer", + "night", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "summer", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2025, + "summer", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2025, + "winter", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "spring", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2030, + "spring", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "winter", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2025, + "spring", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "summer", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1-R2", + 2020, + "summer", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "fall", + "night", + "NG", + "E_NGCC", + 2030, + "ELC" + ], + [ + "R1", + 2020, + "spring", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "spring", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "summer", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "SOL", + "E_SOLPV", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2030, + "spring", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "winter", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "night", + "NG", + "E_NGCC", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "spring", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2025, + "winter", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "day", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2020, + "fall", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "spring", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", + 2020, + "winter", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "summer", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2020, + "fall", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "winter", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2020, + "fall", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1-R2", + 2025, + "spring", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "day", + "SOL", + "E_SOLPV", + 2030, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "night", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R1", + 2030, + "spring", + "day", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "summer", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "fall", + "night", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + 2025, + "spring", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "fall", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2030, + "spring", + "day", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2030, + "summer", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2020, + "winter", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "day", + "NG", + "E_NGCC", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "night", + "URN", + "E_NUCLEAR", + 2030, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "summer", + "day", + "URN", + "E_NUCLEAR", + 2030, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2020, + "fall", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2-R1", + 2020, + "winter", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2025, + "winter", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2030, + "spring", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "day", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "NG", + "E_NGCC", + 2030, + "ELC" + ], + [ + "R2", + 2020, + "spring", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2030, + "winter", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1-R2", + 2025, + "summer", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2020, + "winter", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "winter", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2020, + "winter", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "winter", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", + 2020, + "winter", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2020, + "summer", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "fall", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "SOL", + "E_SOLPV", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2025, + "fall", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2025, + "summer", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2-R1", + 2030, + "fall", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "day", + "SOL", + "E_SOLPV", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "summer", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "fall", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1-R2", + 2030, + "spring", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2020, + "fall", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "summer", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "winter", + "night", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2020, + "fall", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R1", + 2025, + "spring", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2030, + "fall", + "night", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "fall", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "day", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R2", + 2020, + "fall", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2025, + "fall", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2030, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2025, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2030, + "summer", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2-R1", + 2020, + "spring", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2", + 2020, + "spring", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2030, + "winter", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "day", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1-R2", + 2025, + "fall", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "day", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2025, + "spring", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "winter", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "day", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + 2020, + "spring", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "day", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2020, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2025, + "fall", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2030, + "summer", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "night", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R2", + 2020, + "winter", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2025, + "spring", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2020, + "summer", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2030, + "summer", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "night", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R1", + 2020, + "fall", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "summer", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2030, + "fall", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "summer", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + 2025, + "summer", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2030, + "spring", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2025, + "fall", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2020, + "summer", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "winter", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2020, + "spring", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2020, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2030, + "fall", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2030, + "summer", + "day", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R1", + 2030, + "spring", + "night", + "NG", + "E_NGCC", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "winter", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "spring", + "day", + "NG", + "E_NGCC", + 2030, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "night", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R1", + 2020, + "spring", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "fall", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2025, + "winter", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2020, + "spring", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2-R1", + 2030, + "winter", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "night", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "day", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R2", + 2020, + "spring", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2030, + "fall", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "winter", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2025, + "spring", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "night", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2020, + "fall", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2025, + "fall", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "night", + "SOL", + "E_SOLPV", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "day", + "URN", + "E_NUCLEAR", + 2030, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R1", + 2030, + "winter", + "night", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "summer", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2030, + "winter", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2030, + "spring", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "summer", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "day", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2020, + "winter", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2020, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2030, + "spring", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2025, + "summer", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "fall", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2025, + "fall", + "day", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "spring", + "day", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "winter", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2025, + "winter", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2020, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2025, + "fall", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "night", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R2", + 2020, + "spring", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1-R2", + 2030, + "winter", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2020, + "spring", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "winter", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2025, + "spring", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "day", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R1", + 2030, + "winter", + "night", + "NG", + "E_NGCC", + 2030, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "night", + "URN", + "E_NUCLEAR", + 2030, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "summer", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "winter", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2030, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2030, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2025, + "winter", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1-R2", + 2020, + "winter", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "night", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2025, + "winter", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1-R2", + 2030, + "summer", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2020, + "spring", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2025, + "fall", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "winter", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R1", + 2025, + "winter", + "night", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "summer", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2020, + "spring", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2020, + "fall", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "spring", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2030, + "fall", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2020, + "spring", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2025, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2025, + "spring", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2020, + "summer", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "spring", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2025, + "summer", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "winter", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2025, + "fall", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "fall", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "fall", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2020, + "fall", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "spring", + "day", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R1", + 2020, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2030, + "summer", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2025, + "spring", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2025, + "spring", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2020, + "fall", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "night", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2030, + "spring", + "day", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R1", + 2020, + "summer", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2020, + "winter", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "summer", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R1", + 2020, + "winter", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2030, + "winter", + "night", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2030, + "winter", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2020, + "spring", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2020, + "spring", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "day", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2020, + "winter", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2025, + "spring", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "spring", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2025, + "spring", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2030, + "winter", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2020, + "winter", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1-R2", + 2025, + "summer", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2", + 2020, + "winter", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2025, + "fall", + "night", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2020, + "summer", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2030, + "fall", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "spring", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2020, + "spring", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2020, + "winter", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2030, + "spring", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2020, + "spring", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "winter", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2025, + "winter", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2025, + "summer", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "spring", + "day", + "URN", + "E_NUCLEAR", + 2030, + "ELC" + ], + [ + "R2", + 2020, + "spring", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "summer", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "fall", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2020, + "summer", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R1", + 2025, + "summer", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2020, + "fall", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "day", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2020, + "fall", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2025, + "summer", + "night", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2020, + "spring", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2030, + "summer", + "night", + "SOL", + "E_SOLPV", + 2030, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "summer", + "night", + "SOL", + "E_SOLPV", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "night", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "summer", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "winter", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2025, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2025, + "winter", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2025, + "spring", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "day", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2020, + "fall", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2030, + "winter", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1-R2", + 2020, + "fall", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "summer", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "winter", + "night", + "NG", + "E_NGCC", + 2030, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "summer", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2025, + "spring", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2025, + "winter", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1-R2", + 2020, + "fall", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2020, + "fall", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2-R1", + 2030, + "spring", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1-R2", + 2030, + "fall", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2020, + "fall", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "spring", + "day", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "winter", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2025, + "winter", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2020, + "summer", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2025, + "winter", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "winter", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2025, + "winter", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2020, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2025, + "summer", + "night", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2025, + "winter", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "winter", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "fall", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2025, + "summer", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "summer", + "night", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "day", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "summer", + "night", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R2", + 2020, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2025, + "fall", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "winter", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1-R2", + 2020, + "summer", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "day", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R1", + 2020, + "summer", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "winter", + "day", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "day", + "URN", + "E_NUCLEAR", + 2030, + "ELC" + ], + [ + "R2", + 2020, + "fall", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2025, + "summer", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "night", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R1", + 2030, + "fall", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2030, + "winter", + "night", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "day", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "spring", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "fall", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "winter", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "winter", + "night", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2030, + "fall", + "day", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2020, + "winter", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2030, + "fall", + "night", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "day", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "summer", + "day", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "winter", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2020, + "spring", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "fall", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "fall", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "day", + "NG", + "E_NGCC", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "night", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R1", + 2020, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2020, + "winter", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2020, + "fall", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2030, + "summer", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "night", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2020, + "spring", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", + 2025, + "spring", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "URN", + "E_NUCLEAR", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2-R1", + 2025, + "winter", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2", + 2020, + "winter", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "summer", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2030, + "winter", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "spring", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2020, + "winter", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "summer", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "winter", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2020, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2020, + "fall", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2025, + "winter", + "day", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "fall", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R1", + 2025, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2020, + "summer", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2025, + "summer", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "night", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R2", + 2020, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2020, + "fall", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "day", + "NG", + "E_NGCC", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R2-R1", + 2030, + "summer", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2-R1", + 2020, + "spring", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2020, + "fall", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2030, + "summer", + "night", + "URN", + "E_NUCLEAR", + 2030, + "ELC" + ], + [ + "R2", + 2020, + "spring", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2030, + "summer", + "day", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R1-R2", + 2025, + "winter", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "day", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2030, + "spring", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1-R2", + 2025, + "winter", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2020, + "spring", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2025, + "winter", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2025, + "spring", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2020, + "spring", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "fall", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "summer", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "spring", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "spring", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2030, + "winter", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2020, + "fall", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2030, + "fall", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "winter", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2030, + "fall", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2030, + "winter", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2030, + "fall", + "day", + "SOL", + "E_SOLPV", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "fall", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2025, + "spring", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2030, + "summer", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "winter", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "SOL", + "E_SOLPV", + 2030, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2020, + "summer", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "SOL", + "E_SOLPV", + 2030, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2-R1", + 2020, + "winter", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1-R2", + 2025, + "spring", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2", + 2020, + "summer", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2030, + "summer", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "summer", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2025, + "spring", + "day", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "day", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + 2020, + "winter", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R1", + 2020, + "fall", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2020, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2020, + "spring", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "day", + "URN", + "E_NUCLEAR", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2030, + "fall", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2020, + "summer", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "summer", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2020, + "spring", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2030, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2030, + "summer", + "night", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R1", + 2030, + "winter", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "fall", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2025, + "winter", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "summer", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "spring", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R1", + 2020, + "summer", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "fall", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "fall", + "night", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + 2020, + "spring", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "summer", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2020, + "fall", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "fall", + "day", + "SOL", + "E_SOLPV", + 2030, + "ELC" + ], + [ + "R1", + 2020, + "winter", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2020, + "spring", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2-R1", + 2030, + "fall", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2030, + "summer", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "fall", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "spring", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "fall", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2025, + "summer", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2025, + "spring", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "summer", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2020, + "winter", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "fall", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2025, + "fall", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2025, + "fall", + "day", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "winter", + "night", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "winter", + "night", + "URN", + "E_NUCLEAR", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2025, + "fall", + "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2030, + "spring", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "summer", + "day", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "winter", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R1", + 2030, + "summer", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "spring", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ] + ], + "GroupShareIndices": [], + "LifetimeProcess_rtv": [ + [ + "R2", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + "S_IMPURN", + 2020 + ], + [ + "R1", + "R_NGH", + 2020 + ], + [ + "R1", + "T_EV", + 2030 + ], + [ + "R2", + "T_GSL", + 2020 + ], + [ + "R2", + "S_IMPNG", + 2020 + ], + [ + "R1", + "E_BATT", + 2025 + ], + [ + "R1", + "E_SOLPV", + 2030 + ], + [ + "R2", + "E_NGCC", + 2025 + ], + [ + "R2", + "R_NGH", + 2030 + ], + [ + "R1", + "E_NGCC", + 2030 + ], + [ + "R2", + "R_EH", + 2025 + ], + [ + "R1", + "E_NUCLEAR", + 2020 + ], + [ + "R1-R2", + "E_TRANS", + 2015 + ], + [ + "R2", + "T_EV", + 2025 + ], + [ + "R1", + "R_EH", + 2030 + ], + [ + "R1", + "S_IMPETH", + 2020 + ], + [ + "R1", + "T_DSL", + 2020 + ], + [ + "R2", + "E_BATT", + 2025 + ], + [ + "R2", + "S_IMPURN", + 2020 + ], + [ + "R2", + "E_SOLPV", + 2030 + ], + [ + "R1", + "T_GSL", + 2025 + ], + [ + "R2", + "T_DSL", + 2030 + ], + [ + "R2", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + "S_OILREF", + 2020 + ], + [ + "R2-R1", + "E_TRANS", + 2015 + ], + [ + "R1", + "T_EV", + 2020 + ], + [ + "R1", + "E_SOLPV", + 2020 + ], + [ + "R2", + "R_NGH", + 2020 + ], + [ + "R2", + "E_NUCLEAR", + 2030 + ], + [ + "R1", + "E_NGCC", + 2020 + ], + [ + "R1", + "R_NGH", + 2025 + ], + [ + "R2", + "T_GSL", + 2025 + ], + [ + "R1", + "R_EH", + 2020 + ], + [ + "R1", + "E_BATT", + 2030 + ], + [ + "R2", + "E_NGCC", + 2030 + ], + [ + "R1", + "S_IMPOIL", + 2020 + ], + [ + "R2", + "R_EH", + 2030 + ], + [ + "R2", + "E_SOLPV", + 2020 + ], + [ + "R1", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + "T_DSL", + 2020 + ], + [ + "R2", + "T_EV", + 2030 + ], + [ + "R1", + "T_DSL", + 2025 + ], + [ + "R1", + "T_GSL", + 2030 + ], + [ + "R2", + "E_BATT", + 2030 + ], + [ + "R2", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + "S_IMPETH", + 2020 + ], + [ + "R1", + "T_BLND", + 2020 + ], + [ + "R1", + "T_EV", + 2025 + ], + [ + "R1", + "E_BATT", + 2020 + ], + [ + "R1", + "E_SOLPV", + 2025 + ], + [ + "R2", + "E_NGCC", + 2020 + ], + [ + "R2", + "R_NGH", + 2025 + ], + [ + "R1", + "E_NGCC", + 2025 + ], + [ + "R1", + "R_NGH", + 2030 + ], + [ + "R2", + "R_EH", + 2020 + ], + [ + "R2", + "T_GSL", + 2030 + ], + [ + "R1", + "R_EH", + 2025 + ], + [ + "R1", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + "T_EV", + 2020 + ], + [ + "R1", + "S_IMPNG", + 2020 + ], + [ + "R2", + "S_IMPOIL", + 2020 + ], + [ + "R2", + "E_BATT", + 2020 + ], + [ + "R2", + "T_BLND", + 2020 + ], + [ + "R2", + "E_SOLPV", + 2025 + ], + [ + "R1", + "T_GSL", + 2020 + ], + [ + "R1", + "E_NUCLEAR", + 2030 + ], + [ + "R2", + "T_DSL", + 2025 + ], + [ + "R1", + "T_DSL", + 2030 + ], + [ + "R1", + "S_OILREF", + 2020 + ] + ], + "LimitActivityConstraint_rpt": [ + [ + "R1", + 2030, + "T_GSL", + "ge" + ], + [ + "R2", + 2025, + "T_GSL", + "ge" + ], + [ + "R1", + 2025, + "T_GSL", + "ge" + ], + [ + "R2", + 2020, + "T_GSL", + "ge" + ], + [ + "R2", + 2030, + "T_GSL", + "ge" + ], + [ + "R1", + 2020, + "T_GSL", + "ge" + ] + ], + "LimitActivityGroup_rpg": [], + "LimitActivityShareConstraint_rptg": [], + "LimitAnnualCapacityFactorConstraint_rpto": [], + "LimitCapacityConstraint_rpt": [], + "LimitCapacityGroupConstraint_rpg": [], + "LimitCapacityShareConstraint_rptg": [], + "LimitDegrowthCapacityConstraint_rpt": [], + "LimitDegrowthNewCapacityConstraint_rpt": [], + "LimitDegrowthNewCapacityDeltaConstraint_rpt": [], + "LimitEmissionConstraint_rpe": [ + [ + "R1", + 2025, + "CO2", + "le" + ], + [ + "global", + 2020, + "CO2", + "le" + ], + [ + "global", + 2030, + "CO2", + "le" + ], + [ + "global", + 2025, + "CO2", + "le" + ], + [ + "R1", + 2030, + "CO2", + "le" + ], + [ + "R1", + 2020, + "CO2", + "le" + ] + ], + "LimitGrowthCapacityConstraint_rpt": [], + "LimitGrowthNewCapacityConstraint_rpt": [], + "LimitGrowthNewCapacityDeltaConstraint_rpt": [], + "LimitNewCapacityConstraint_rpt": [], + "LimitNewCapacityGroupConstraint_rpg": [], + "LimitNewCapacityGroupShareConstraint_rpgg": [], + "LimitNewCapacityShareConstraint_rptg": [], + "LimitResourceConstraint_rt": [], + "LimitSeasonalActivityConstraint_rpst": [], + "LimitStorageFractionConstraint_rpsdtv": [ + [ + "R1", + 2025, + "winter", + "day", + "E_BATT", + 2025, + "e" + ], + [ + "R2", + 2020, + "summer", + "day", + "E_BATT", + 2020, + "e" + ] + ], + "LimitTechInputSplitAnnualConstraint_rpitv": [], + "LimitTechInputSplitAverageConstraint_rpitv": [], + "LimitTechInputSplitConstraint_rpsditv": [ + [ + "R2", + 2020, + "spring", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2020, + "spring", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2020, + "winter", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2030, + "spring", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2025, + "spring", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2025, + "fall", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2020, + "spring", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2030, + "fall", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2030, + "fall", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2025, + "spring", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2030, + "summer", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2030, + "spring", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2020, + "summer", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2030, + "summer", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2030, + "fall", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2025, + "winter", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2030, + "fall", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2030, + "winter", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2030, + "winter", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2030, + "summer", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2030, + "spring", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2025, + "winter", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2020, + "summer", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2025, + "fall", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2020, + "summer", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2025, + "summer", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2020, + "summer", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2025, + "winter", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2020, + "fall", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2020, + "fall", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2025, + "summer", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2025, + "winter", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2025, + "spring", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2020, + "fall", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2020, + "spring", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2025, + "winter", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2030, + "winter", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2020, + "spring", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2025, + "summer", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2025, + "summer", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2020, + "fall", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2020, + "winter", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2025, + "winter", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2030, + "winter", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2025, + "spring", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2025, + "winter", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2030, + "winter", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2025, + "fall", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2025, + "summer", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2025, + "spring", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2030, + "spring", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2020, + "fall", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2025, + "fall", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2030, + "summer", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2020, + "spring", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2025, + "spring", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2025, + "winter", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2020, + "winter", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2030, + "fall", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2025, + "summer", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2020, + "summer", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2030, + "fall", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2025, + "summer", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2025, + "fall", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2030, + "summer", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2020, + "summer", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2020, + "fall", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2020, + "spring", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2030, + "spring", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2030, + "spring", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2030, + "winter", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2025, + "fall", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2030, + "winter", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2025, + "fall", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2025, + "fall", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2025, + "summer", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2020, + "summer", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2030, + "spring", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2020, + "summer", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2030, + "summer", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2020, + "winter", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2020, + "spring", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2030, + "summer", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2020, + "fall", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2025, + "spring", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2030, + "fall", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2020, + "winter", + "night", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2020, + "winter", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2030, + "summer", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2020, + "winter", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2030, + "fall", + "day", + "GSL", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2030, + "spring", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2030, + "winter", + "night", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2020, + "winter", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R1", + 2020, + "fall", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ], + [ + "R2", + 2025, + "spring", + "day", + "ETH", + "T_BLND", + 2020, + "ge" + ] + ], + "LimitTechOutputSplitAnnualConstraint_rptvo": [], + "LimitTechOutputSplitAverageConstraint_rptvo": [], + "LimitTechOutputSplitConstraint_rpsdtvo": [ + [ + "R2", + 2020, + "fall", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2020, + "fall", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2020, + "fall", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2020, + "summer", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2025, + "summer", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2030, + "summer", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R1", + 2030, + "fall", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R2", + 2020, + "summer", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2030, + "winter", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2025, + "summer", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R1", + 2030, + "spring", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2025, + "summer", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R1", + 2030, + "spring", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2025, + "winter", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2025, + "winter", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R2", + 2020, + "summer", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2030, + "winter", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2025, + "winter", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2025, + "summer", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2030, + "winter", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R1", + 2025, + "summer", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R2", + 2030, + "winter", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2020, + "spring", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R2", + 2020, + "winter", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R1", + 2025, + "summer", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2025, + "summer", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R2", + 2030, + "fall", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R2", + 2020, + "spring", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2020, + "fall", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R1", + 2020, + "fall", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2030, + "summer", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R2", + 2030, + "summer", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R2", + 2025, + "fall", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R2", + 2025, + "spring", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2030, + "fall", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R1", + 2025, + "fall", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R2", + 2025, + "spring", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2025, + "spring", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2020, + "summer", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2020, + "spring", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2025, + "spring", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2025, + "fall", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R2", + 2030, + "fall", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R2", + 2030, + "spring", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2020, + "summer", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R1", + 2025, + "spring", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2025, + "summer", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R2", + 2025, + "winter", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R1", + 2030, + "winter", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2020, + "winter", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2025, + "winter", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2030, + "spring", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2020, + "summer", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2025, + "winter", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R2", + 2025, + "fall", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R2", + 2020, + "fall", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R2", + 2030, + "fall", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R1", + 2020, + "winter", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R1", + 2020, + "spring", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R1", + 2020, + "fall", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R1", + 2030, + "summer", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R1", + 2020, + "fall", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R2", + 2020, + "winter", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R2", + 2030, + "summer", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2020, + "spring", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R2", + 2025, + "fall", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2030, + "summer", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R2", + 2025, + "fall", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R1", + 2030, + "fall", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R2", + 2025, + "spring", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R1", + 2025, + "fall", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2025, + "spring", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2020, + "spring", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2030, + "winter", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2030, + "spring", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2025, + "spring", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R1", + 2020, + "spring", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R1", + 2030, + "fall", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R1", + 2025, + "fall", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2020, + "winter", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2030, + "fall", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2030, + "spring", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R1", + 2020, + "winter", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2030, + "spring", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R2", + 2025, + "winter", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R2", + 2020, + "summer", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2030, + "summer", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2030, + "winter", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2020, + "spring", + "night", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2030, + "winter", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R1", + 2020, + "winter", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2020, + "winter", + "day", + "S_OILREF", + 2020, + "GSL", + "ge" + ], + [ + "R1", + 2030, + "summer", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R2", + 2030, + "spring", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R1", + 2020, + "summer", + "day", + "S_OILREF", + 2020, + "DSL", + "ge" + ], + [ + "R1", + 2025, + "winter", + "night", + "S_OILREF", + 2020, + "DSL", + "ge" + ] + ], + "LinkedEmissionsTechConstraint_rpsdtve": [], + "LoanLifetimeProcess_rtv": [ + [ + "R2", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + "S_IMPURN", + 2020 + ], + [ + "R1", + "R_NGH", + 2020 + ], + [ + "R1", + "T_EV", + 2030 + ], + [ + "R2", + "T_GSL", + 2020 + ], + [ + "R2", + "S_IMPNG", + 2020 + ], + [ + "R1", + "E_BATT", + 2025 + ], + [ + "R1", + "E_SOLPV", + 2030 + ], + [ + "R2", + "E_NGCC", + 2025 + ], + [ + "R2", + "R_NGH", + 2030 + ], + [ + "R1", + "E_NGCC", + 2030 + ], + [ + "R2", + "R_EH", + 2025 + ], + [ + "R1", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + "T_EV", + 2025 + ], + [ + "R1", + "R_EH", + 2030 + ], + [ + "R1", + "S_IMPETH", + 2020 + ], + [ + "R1", + "T_DSL", + 2020 + ], + [ + "R2", + "E_BATT", + 2025 + ], + [ + "R2", + "S_IMPURN", + 2020 + ], + [ + "R2", + "E_SOLPV", + 2030 + ], + [ + "R1", + "T_GSL", + 2025 + ], + [ + "R2", + "T_DSL", + 2030 + ], + [ + "R2", + "S_OILREF", + 2020 + ], + [ + "R1", + "T_EV", + 2020 + ], + [ + "R1", + "E_SOLPV", + 2020 + ], + [ + "R2", + "R_NGH", + 2020 + ], + [ + "R2", + "E_NUCLEAR", + 2030 + ], + [ + "R1", + "E_NGCC", + 2020 + ], + [ + "R1", + "R_NGH", + 2025 + ], + [ + "R2", + "T_GSL", + 2025 + ], + [ + "R1", + "R_EH", + 2020 + ], + [ + "R1", + "E_BATT", + 2030 + ], + [ + "R2", + "E_NGCC", + 2030 + ], + [ + "R1", + "S_IMPOIL", + 2020 + ], + [ + "R2", + "R_EH", + 2030 + ], + [ + "R2", + "E_SOLPV", + 2020 + ], + [ + "R1", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + "T_DSL", + 2020 + ], + [ + "R2", + "T_EV", + 2030 + ], + [ + "R1", + "T_DSL", + 2025 + ], + [ + "R1", + "T_GSL", + 2030 + ], + [ + "R2", + "E_BATT", + 2030 + ], + [ + "R2", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + "S_IMPETH", + 2020 + ], + [ + "R1", + "T_BLND", + 2020 + ], + [ + "R1", + "T_EV", + 2025 + ], + [ + "R1", + "E_BATT", + 2020 + ], + [ + "R1", + "E_SOLPV", + 2025 + ], + [ + "R2", + "E_NGCC", + 2020 + ], + [ + "R2", + "R_NGH", + 2025 + ], + [ + "R1", + "E_NGCC", + 2025 + ], + [ + "R1", + "R_NGH", + 2030 + ], + [ + "R2", + "R_EH", + 2020 + ], + [ + "R2", + "T_GSL", + 2030 + ], + [ + "R1", + "R_EH", + 2025 + ], + [ + "R2", + "T_EV", + 2020 + ], + [ + "R1", + "S_IMPNG", + 2020 + ], + [ + "R2", + "S_IMPOIL", + 2020 + ], + [ + "R2", + "E_BATT", + 2020 + ], + [ + "R2", + "T_BLND", + 2020 + ], + [ + "R2", + "E_SOLPV", + 2025 + ], + [ + "R1", + "T_GSL", + 2020 + ], + [ + "R1", + "E_NUCLEAR", + 2030 + ], + [ + "R2", + "T_DSL", + 2025 + ], + [ + "R1", + "T_DSL", + 2030 + ], + [ + "R1", + "S_OILREF", + 2020 + ] + ], + "ModelProcessLife_rptv": [ + [ + "R2", + 2030, + "R_NGH", + 2030 + ], + [ + "R2", + 2020, + "S_IMPETH", + 2020 + ], + [ + "R1", + 2030, + "E_BATT", + 2030 + ], + [ + "R1", + 2025, + "E_NGCC", + 2025 + ], + [ + "R2", + 2030, + "S_IMPNG", + 2020 + ], + [ + "R2", + 2020, + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2025, + "S_IMPURN", + 2020 + ], + [ + "R1", + 2025, + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "R_NGH", + 2025 + ], + [ + "R2", + 2030, + "E_BATT", + 2025 + ], + [ + "R2", + 2025, + "S_IMPNG", + 2020 + ], + [ + "R1", + 2030, + "R_EH", + 2020 + ], + [ + "R2", + 2020, + "T_EV", + 2020 + ], + [ + "R2", + 2025, + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2020, + "S_IMPOIL", + 2020 + ], + [ + "R2", + 2030, + "T_EV", + 2030 + ], + [ + "R2", + 2030, + "T_DSL", + 2020 + ], + [ + "R2", + 2025, + "T_DSL", + 2020 + ], + [ + "R1", + 2030, + "T_EV", + 2025 + ], + [ + "R1", + 2030, + "S_IMPNG", + 2020 + ], + [ + "R1", + 2020, + "S_IMPNG", + 2020 + ], + [ + "R1", + 2025, + "S_IMPETH", + 2020 + ], + [ + "R1", + 2025, + "T_GSL", + 2025 + ], + [ + "R1", + 2030, + "S_IMPURN", + 2020 + ], + [ + "R2", + 2030, + "R_NGH", + 2025 + ], + [ + "R1", + 2020, + "S_IMPURN", + 2020 + ], + [ + "R2", + 2020, + "S_OILREF", + 2020 + ], + [ + "R1", + 2030, + "E_BATT", + 2025 + ], + [ + "R1", + 2025, + "E_NGCC", + 2020 + ], + [ + "R2", + 2020, + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "S_IMPOIL", + 2020 + ], + [ + "R2", + 2025, + "R_NGH", + 2025 + ], + [ + "R1", + 2030, + "R_NGH", + 2020 + ], + [ + "R2", + 2020, + "T_GSL", + 2020 + ], + [ + "R1", + 2020, + "R_NGH", + 2020 + ], + [ + "R2", + 2030, + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "E_NUCLEAR", + 2025 + ], + [ + "R2-R1", + 2020, + "E_TRANS", + 2015 + ], + [ + "R2", + 2030, + "T_GSL", + 2030 + ], + [ + "R2-R1", + 2030, + "E_TRANS", + 2015 + ], + [ + "R1", + 2030, + "E_NGCC", + 2030 + ], + [ + "R2", + 2025, + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2030, + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "T_EV", + 2025 + ], + [ + "R1", + 2020, + "T_DSL", + 2020 + ], + [ + "R2", + 2020, + "E_SOLPV", + 2020 + ], + [ + "R2", + 2025, + "T_EV", + 2025 + ], + [ + "R1", + 2030, + "T_EV", + 2020 + ], + [ + "R1", + 2025, + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "S_IMPOIL", + 2020 + ], + [ + "R1", + 2025, + "S_OILREF", + 2020 + ], + [ + "R1", + 2025, + "T_GSL", + 2020 + ], + [ + "R1", + 2030, + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "R_NGH", + 2020 + ], + [ + "R1", + 2020, + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "E_SOLPV", + 2030 + ], + [ + "R2", + 2020, + "E_NGCC", + 2020 + ], + [ + "R1", + 2030, + "E_BATT", + 2020 + ], + [ + "R1", + 2020, + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "S_IMPETH", + 2020 + ], + [ + "R2", + 2030, + "E_NGCC", + 2030 + ], + [ + "R1", + 2030, + "T_GSL", + 2030 + ], + [ + "R2", + 2025, + "R_NGH", + 2020 + ], + [ + "R2", + 2030, + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "T_GSL", + 2025 + ], + [ + "R2", + 2025, + "S_IMPETH", + 2020 + ], + [ + "R1", + 2030, + "E_NGCC", + 2025 + ], + [ + "R2", + 2025, + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "T_EV", + 2020 + ], + [ + "R1-R2", + 2025, + "E_TRANS", + 2015 + ], + [ + "R2", + 2025, + "T_GSL", + 2025 + ], + [ + "R2", + 2020, + "S_IMPNG", + 2020 + ], + [ + "R2", + 2025, + "T_EV", + 2020 + ], + [ + "R2", + 2025, + "S_IMPOIL", + 2020 + ], + [ + "R1", + 2025, + "T_DSL", + 2025 + ], + [ + "R2", + 2025, + "T_BLND", + 2020 + ], + [ + "R1", + 2030, + "R_EH", + 2030 + ], + [ + "R1", + 2030, + "S_IMPETH", + 2020 + ], + [ + "R1", + 2025, + "E_SOLPV", + 2025 + ], + [ + "R2", + 2030, + "E_SOLPV", + 2025 + ], + [ + "R2", + 2030, + "S_OILREF", + 2020 + ], + [ + "R2", + 2030, + "E_NGCC", + 2025 + ], + [ + "R1", + 2030, + "T_GSL", + 2025 + ], + [ + "R2", + 2030, + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2020, + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2025, + "S_IMPURN", + 2020 + ], + [ + "R2", + 2030, + "T_GSL", + 2020 + ], + [ + "R2", + 2025, + "S_OILREF", + 2020 + ], + [ + "R2", + 2025, + "E_NGCC", + 2025 + ], + [ + "R1", + 2030, + "E_NGCC", + 2020 + ], + [ + "R1", + 2020, + "E_NGCC", + 2020 + ], + [ + "R2", + 2025, + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2025, + "R_EH", + 2025 + ], + [ + "R2", + 2025, + "T_GSL", + 2020 + ], + [ + "R1", + 2020, + "T_EV", + 2020 + ], + [ + "R2-R1", + 2025, + "E_TRANS", + 2015 + ], + [ + "R1", + 2020, + "S_IMPOIL", + 2020 + ], + [ + "R2", + 2020, + "T_BLND", + 2020 + ], + [ + "R2", + 2020, + "E_BATT", + 2020 + ], + [ + "R2", + 2020, + "R_EH", + 2020 + ], + [ + "R1", + 2025, + "T_DSL", + 2020 + ], + [ + "R2", + 2030, + "R_EH", + 2030 + ], + [ + "R1", + 2030, + "T_DSL", + 2030 + ], + [ + "R1", + 2030, + "S_OILREF", + 2020 + ], + [ + "R1", + 2025, + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "E_NGCC", + 2020 + ], + [ + "R1", + 2030, + "T_GSL", + 2020 + ], + [ + "R1", + 2020, + "T_GSL", + 2020 + ], + [ + "R2", + 2020, + "S_IMPURN", + 2020 + ], + [ + "R1", + 2020, + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "E_SOLPV", + 2030 + ], + [ + "R1", + 2025, + "R_NGH", + 2025 + ], + [ + "R2", + 2025, + "E_NGCC", + 2020 + ], + [ + "R1", + 2025, + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "R_EH", + 2020 + ], + [ + "R1", + 2025, + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2025, + "E_SOLPV", + 2025 + ], + [ + "R1", + 2020, + "E_SOLPV", + 2020 + ], + [ + "R1-R2", + 2030, + "E_TRANS", + 2015 + ], + [ + "R2", + 2020, + "T_DSL", + 2020 + ], + [ + "R1-R2", + 2020, + "E_TRANS", + 2015 + ], + [ + "R1", + 2025, + "T_EV", + 2025 + ], + [ + "R1", + 2025, + "S_IMPNG", + 2020 + ], + [ + "R2", + 2030, + "T_DSL", + 2030 + ], + [ + "R2", + 2030, + "R_EH", + 2025 + ], + [ + "R1", + 2020, + "S_IMPETH", + 2020 + ], + [ + "R2", + 2030, + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2025, + "R_EH", + 2025 + ], + [ + "R1", + 2030, + "T_DSL", + 2025 + ], + [ + "R1", + 2020, + "R_EH", + 2020 + ], + [ + "R1", + 2030, + "E_SOLPV", + 2025 + ], + [ + "R1", + 2025, + "R_NGH", + 2020 + ], + [ + "R1", + 2025, + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "R_NGH", + 2030 + ], + [ + "R2", + 2030, + "E_BATT", + 2030 + ], + [ + "R2", + 2025, + "E_SOLPV", + 2020 + ], + [ + "R1", + 2030, + "R_EH", + 2025 + ], + [ + "R1", + 2025, + "T_EV", + 2020 + ], + [ + "R1", + 2030, + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2030, + "T_DSL", + 2025 + ], + [ + "R1", + 2025, + "S_IMPOIL", + 2020 + ], + [ + "R2", + 2030, + "R_EH", + 2020 + ], + [ + "R1", + 2020, + "S_OILREF", + 2020 + ], + [ + "R2", + 2025, + "T_DSL", + 2025 + ], + [ + "R2", + 2025, + "R_EH", + 2020 + ], + [ + "R1", + 2030, + "T_EV", + 2030 + ], + [ + "R1", + 2030, + "T_DSL", + 2020 + ], + [ + "R1", + 2025, + "T_BLND", + 2020 + ], + [ + "R2", + 2020, + "R_NGH", + 2020 + ], + [ + "R1", + 2030, + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "S_IMPURN", + 2020 + ] + ], + "NewCapacityVar_rtv": [ + [ + "R2", + "E_NUCLEAR", + 2025 + ], + [ + "R1", + "R_NGH", + 2020 + ], + [ + "R1", + "T_EV", + 2030 + ], + [ + "R2", + "T_GSL", + 2020 + ], + [ + "R1", + "E_BATT", + 2025 + ], + [ + "R1", + "E_SOLPV", + 2030 + ], + [ + "R2", + "E_NGCC", + 2025 + ], + [ + "R2", + "R_NGH", + 2030 + ], + [ + "R1", + "E_NGCC", + 2030 + ], + [ + "R2", + "R_EH", + 2025 + ], + [ + "R1", + "E_NUCLEAR", + 2020 + ], + [ + "R2", + "T_EV", + 2025 + ], + [ + "R1", + "R_EH", + 2030 + ], + [ + "R1-R2", + "E_TRANS", + 2015 + ], + [ + "R1", + "T_DSL", + 2020 + ], + [ + "R2", + "E_BATT", + 2025 + ], + [ + "R2", + "E_SOLPV", + 2030 + ], + [ + "R1", + "T_GSL", + 2025 + ], + [ + "R2", + "T_DSL", + 2030 + ], + [ + "R2", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + "S_OILREF", + 2020 + ], + [ + "R2-R1", + "E_TRANS", + 2015 + ], + [ + "R1", + "T_EV", + 2020 + ], + [ + "R1", + "E_SOLPV", + 2020 + ], + [ + "R2", + "R_NGH", + 2020 + ], + [ + "R2", + "E_NUCLEAR", + 2030 + ], + [ + "R1", + "E_NGCC", + 2020 + ], + [ + "R1", + "R_NGH", + 2025 + ], + [ + "R2", + "T_GSL", + 2025 + ], + [ + "R1", + "R_EH", + 2020 + ], + [ + "R1", + "E_BATT", + 2030 + ], + [ + "R2", + "E_NGCC", + 2030 + ], + [ + "R2", + "R_EH", + 2030 + ], + [ + "R2", + "E_SOLPV", + 2020 + ], + [ + "R1", + "E_NUCLEAR", + 2025 + ], + [ + "R2", + "T_DSL", + 2020 + ], + [ + "R2", + "T_EV", + 2030 + ], + [ + "R1", + "T_DSL", + 2025 + ], + [ + "R1", + "T_GSL", + 2030 + ], + [ + "R2", + "E_BATT", + 2030 + ], + [ + "R2", + "E_NUCLEAR", + 2020 + ], + [ + "R1", + "T_BLND", + 2020 + ], + [ + "R1", + "T_EV", + 2025 + ], + [ + "R1", + "E_BATT", + 2020 + ], + [ + "R1", + "E_SOLPV", + 2025 + ], + [ + "R2", + "E_NGCC", + 2020 + ], + [ + "R2", + "R_NGH", + 2025 + ], + [ + "R1", + "E_NGCC", + 2025 + ], + [ + "R1", + "R_NGH", + 2030 + ], + [ + "R2", + "R_EH", + 2020 + ], + [ + "R2", + "T_GSL", + 2030 + ], + [ + "R1", + "R_EH", + 2025 + ], + [ + "R1", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + "T_EV", + 2020 + ], + [ + "R2", + "E_BATT", + 2020 + ], + [ + "R2", + "T_BLND", + 2020 + ], + [ + "R2", + "E_SOLPV", + 2025 + ], + [ + "R1", + "T_GSL", + 2020 + ], + [ + "R1", + "E_NUCLEAR", + 2030 + ], + [ + "R2", + "T_DSL", + 2025 + ], + [ + "R1", + "T_DSL", + 2030 + ], + [ + "R1", + "S_OILREF", + 2020 + ] + ], + "ProcessLifeFrac_rptv": [ + [ + "R2", + 2030, + "R_NGH", + 2030 + ], + [ + "R2", + 2020, + "S_IMPETH", + 2020 + ], + [ + "R1", + 2030, + "E_BATT", + 2030 + ], + [ + "R1", + 2025, + "E_NGCC", + 2025 + ], + [ + "R2", + 2030, + "S_IMPNG", + 2020 + ], + [ + "R2", + 2020, + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2025, + "S_IMPURN", + 2020 + ], + [ + "R1", + 2025, + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "R_NGH", + 2025 + ], + [ + "R2", + 2030, + "E_BATT", + 2025 + ], + [ + "R2", + 2025, + "S_IMPNG", + 2020 + ], + [ + "R1", + 2030, + "R_EH", + 2020 + ], + [ + "R2", + 2020, + "T_EV", + 2020 + ], + [ + "R2", + 2025, + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2020, + "S_IMPOIL", + 2020 + ], + [ + "R2", + 2030, + "T_EV", + 2030 + ], + [ + "R2", + 2030, + "T_DSL", + 2020 + ], + [ + "R2", + 2025, + "T_DSL", + 2020 + ], + [ + "R1", + 2030, + "T_EV", + 2025 + ], + [ + "R1", + 2030, + "S_IMPNG", + 2020 + ], + [ + "R1", + 2020, + "S_IMPNG", + 2020 + ], + [ + "R1", + 2025, + "S_IMPETH", + 2020 + ], + [ + "R1", + 2025, + "T_GSL", + 2025 + ], + [ + "R1", + 2030, + "S_IMPURN", + 2020 + ], + [ + "R2", + 2030, + "R_NGH", + 2025 + ], + [ + "R1", + 2020, + "S_IMPURN", + 2020 + ], + [ + "R2", + 2020, + "S_OILREF", + 2020 + ], + [ + "R1", + 2030, + "E_BATT", + 2025 + ], + [ + "R1", + 2025, + "E_NGCC", + 2020 + ], + [ + "R2", + 2020, + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "S_IMPOIL", + 2020 + ], + [ + "R2", + 2025, + "R_NGH", + 2025 + ], + [ + "R1", + 2030, + "R_NGH", + 2020 + ], + [ + "R2", + 2020, + "T_GSL", + 2020 + ], + [ + "R1", + 2020, + "R_NGH", + 2020 + ], + [ + "R2", + 2030, + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "E_NUCLEAR", + 2025 + ], + [ + "R2-R1", + 2020, + "E_TRANS", + 2015 + ], + [ + "R2", + 2030, + "T_GSL", + 2030 + ], + [ + "R2-R1", + 2030, + "E_TRANS", + 2015 + ], + [ + "R1", + 2030, + "E_NGCC", + 2030 + ], + [ + "R2", + 2025, + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "E_NUCLEAR", + 2025 + ], + [ + "R1", + 2030, + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "T_EV", + 2025 + ], + [ + "R1", + 2020, + "T_DSL", + 2020 + ], + [ + "R2", + 2020, + "E_SOLPV", + 2020 + ], + [ + "R2", + 2025, + "T_EV", + 2025 + ], + [ + "R1", + 2030, + "T_EV", + 2020 + ], + [ + "R1", + 2025, + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "S_IMPOIL", + 2020 + ], + [ + "R1", + 2025, + "S_OILREF", + 2020 + ], + [ + "R1", + 2025, + "T_GSL", + 2020 + ], + [ + "R1", + 2030, + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "R_NGH", + 2020 + ], + [ + "R1", + 2020, + "T_BLND", + 2020 + ], + [ + "R2", + 2030, + "E_SOLPV", + 2030 + ], + [ + "R2", + 2020, + "E_NGCC", + 2020 + ], + [ + "R1", + 2030, + "E_BATT", + 2020 + ], + [ + "R1", + 2020, + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "S_IMPETH", + 2020 + ], + [ + "R2", + 2030, + "E_NGCC", + 2030 + ], + [ + "R1", + 2030, + "T_GSL", + 2030 + ], + [ + "R2", + 2025, + "R_NGH", + 2020 + ], + [ + "R2", + 2030, + "E_NUCLEAR", + 2020 + ], + [ + "R2", + 2030, + "T_GSL", + 2025 + ], + [ + "R2", + 2025, + "S_IMPETH", + 2020 + ], + [ + "R1", + 2030, + "E_NGCC", + 2025 + ], + [ + "R2", + 2025, + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "E_NUCLEAR", + 2015 + ], + [ + "R2", + 2030, + "T_EV", + 2020 + ], + [ + "R1-R2", + 2025, + "E_TRANS", + 2015 + ], + [ + "R2", + 2025, + "T_GSL", + 2025 + ], + [ + "R2", + 2020, + "S_IMPNG", + 2020 + ], + [ + "R2", + 2025, + "T_EV", + 2020 + ], + [ + "R2", + 2025, + "S_IMPOIL", + 2020 + ], + [ + "R1", + 2025, + "T_DSL", + 2025 + ], + [ + "R2", + 2025, + "T_BLND", + 2020 + ], + [ + "R1", + 2030, + "R_EH", + 2030 + ], + [ + "R1", + 2030, + "S_IMPETH", + 2020 + ], + [ + "R1", + 2025, + "E_SOLPV", + 2025 + ], + [ + "R2", + 2030, + "E_SOLPV", + 2025 + ], + [ + "R2", + 2030, + "S_OILREF", + 2020 + ], + [ + "R2", + 2030, + "E_NGCC", + 2025 + ], + [ + "R1", + 2030, + "T_GSL", + 2025 + ], + [ + "R2", + 2030, + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2020, + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2025, + "S_IMPURN", + 2020 + ], + [ + "R2", + 2030, + "T_GSL", + 2020 + ], + [ + "R2", + 2025, + "S_OILREF", + 2020 + ], + [ + "R2", + 2025, + "E_NGCC", + 2025 + ], + [ + "R1", + 2030, + "E_NGCC", + 2020 + ], + [ + "R1", + 2020, + "E_NGCC", + 2020 + ], + [ + "R2", + 2025, + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2025, + "R_EH", + 2025 + ], + [ + "R2", + 2025, + "T_GSL", + 2020 + ], + [ + "R1", + 2020, + "T_EV", + 2020 + ], + [ + "R2-R1", + 2025, + "E_TRANS", + 2015 + ], + [ + "R1", + 2020, + "S_IMPOIL", + 2020 + ], + [ + "R2", + 2020, + "T_BLND", + 2020 + ], + [ + "R2", + 2020, + "E_BATT", + 2020 + ], + [ + "R2", + 2020, + "R_EH", + 2020 + ], + [ + "R1", + 2025, + "T_DSL", + 2020 + ], + [ + "R2", + 2030, + "R_EH", + 2030 + ], + [ + "R1", + 2030, + "T_DSL", + 2030 + ], + [ + "R1", + 2030, + "S_OILREF", + 2020 + ], + [ + "R1", + 2025, + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "E_NGCC", + 2020 + ], + [ + "R1", + 2030, + "T_GSL", + 2020 + ], + [ + "R1", + 2020, + "T_GSL", + 2020 + ], + [ + "R2", + 2020, + "S_IMPURN", + 2020 + ], + [ + "R1", + 2020, + "E_NUCLEAR", + 2015 + ], + [ + "R1", + 2030, + "E_SOLPV", + 2030 + ], + [ + "R1", + 2025, + "R_NGH", + 2025 + ], + [ + "R2", + 2025, + "E_NGCC", + 2020 + ], + [ + "R1", + 2025, + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "R_EH", + 2020 + ], + [ + "R1", + 2025, + "E_NUCLEAR", + 2025 + ], + [ + "R2", + 2025, + "E_SOLPV", + 2025 + ], + [ + "R1", + 2020, + "E_SOLPV", + 2020 + ], + [ + "R1-R2", + 2030, + "E_TRANS", + 2015 + ], + [ + "R2", + 2020, + "T_DSL", + 2020 + ], + [ + "R1-R2", + 2020, + "E_TRANS", + 2015 + ], + [ + "R1", + 2025, + "T_EV", + 2025 + ], + [ + "R1", + 2025, + "S_IMPNG", + 2020 + ], + [ + "R2", + 2030, + "T_DSL", + 2030 + ], + [ + "R2", + 2030, + "R_EH", + 2025 + ], + [ + "R1", + 2020, + "S_IMPETH", + 2020 + ], + [ + "R2", + 2030, + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2025, + "R_EH", + 2025 + ], + [ + "R1", + 2030, + "T_DSL", + 2025 + ], + [ + "R1", + 2020, + "R_EH", + 2020 + ], + [ + "R1", + 2030, + "E_SOLPV", + 2025 + ], + [ + "R1", + 2025, + "R_NGH", + 2020 + ], + [ + "R1", + 2025, + "E_NUCLEAR", + 2020 + ], + [ + "R1", + 2030, + "R_NGH", + 2030 + ], + [ + "R2", + 2030, + "E_BATT", + 2030 + ], + [ + "R2", + 2025, + "E_SOLPV", + 2020 + ], + [ + "R1", + 2030, + "R_EH", + 2025 + ], + [ + "R1", + 2025, + "T_EV", + 2020 + ], + [ + "R1", + 2030, + "E_NUCLEAR", + 2030 + ], + [ + "R2", + 2030, + "T_DSL", + 2025 + ], + [ + "R1", + 2025, + "S_IMPOIL", + 2020 + ], + [ + "R2", + 2030, + "R_EH", + 2020 + ], + [ + "R1", + 2020, + "S_OILREF", + 2020 + ], + [ + "R2", + 2025, + "T_DSL", + 2025 + ], + [ + "R2", + 2025, + "R_EH", + 2020 + ], + [ + "R1", + 2030, + "T_EV", + 2030 + ], + [ + "R1", + 2030, + "T_DSL", + 2020 + ], + [ + "R1", + 2025, + "T_BLND", + 2020 + ], + [ + "R2", + 2020, + "R_NGH", + 2020 + ], + [ + "R1", + 2030, + "E_SOLPV", + 2020 + ], + [ + "R2", + 2030, + "S_IMPURN", + 2020 + ] + ], + "RampDownConstraint_rpsdtv": [], + "RampUpConstraint_rpsdtv": [], + "RegionalExchangeCapacityConstraint_rrptv": [ + [ + "R2", + "R1", + 2030, + "E_TRANS", + 2015 + ], + [ + "R1", + "R2", + 2030, + "E_TRANS", + 2015 + ], + [ + "R2", + "R1", + 2020, + "E_TRANS", + 2015 + ], + [ + "R2", + "R1", + 2025, + "E_TRANS", + 2015 + ], + [ + "R1", + "R2", + 2025, + "E_TRANS", + 2015 + ], + [ + "R1", + "R2", + 2020, + "E_TRANS", + 2015 + ] + ], + "RenewablePortfolioStandardConstraint_rpg": [], + "ReserveMargin_rpsd": [ + [ + "R1", + 2025, + "winter", + "day" + ], + [ + "R2", + 2025, + "summer", + "day" + ], + [ + "R1", + 2025, + "summer", + "night" + ], + [ + "R2", + 2030, + "winter", + "night" + ], + [ + "R2", + 2030, + "summer", + "night" + ], + [ + "R1", + 2020, + "spring", + "day" + ], + [ + "R2", + 2025, + "winter", + "night" + ], + [ + "R2", + 2020, + "spring", + "day" + ], + [ + "R1", + 2030, + "spring", + "day" + ], + [ + "R1", + 2025, + "winter", + "night" + ], + [ + "R2", + 2025, + "summer", + "night" + ], + [ + "R2", + 2025, + "fall", + "day" + ], + [ + "R1", + 2025, + "fall", + "day" + ], + [ + "R2", + 2030, + "fall", + "day" + ], + [ + "R1", + 2020, + "spring", + "night" + ], + [ + "R2", + 2020, + "spring", + "night" + ], + [ + "R1", + 2030, + "spring", + "night" + ], + [ + "R1", + 2030, + "winter", + "day" + ], + [ + "R1", + 2030, + "summer", + "day" + ], + [ + "R1", + 2020, + "summer", + "day" + ], + [ + "R2", + 2020, + "summer", + "day" + ], + [ + "R2", + 2025, + "fall", + "night" + ], + [ + "R1", + 2025, + "fall", + "night" + ], + [ + "R2", + 2030, + "fall", + "night" + ], + [ + "R1", + 2025, + "spring", + "night" + ], + [ + "R2", + 2020, + "winter", + "day" + ], + [ + "R1", + 2020, + "winter", + "day" + ], + [ + "R1", + 2030, + "summer", + "night" + ], + [ + "R1", + 2030, + "winter", + "night" + ], + [ + "R1", + 2020, + "summer", + "night" + ], + [ + "R2", + 2030, + "spring", + "day" + ], + [ + "R2", + 2020, + "summer", + "night" + ], + [ + "R1", + 2020, + "fall", + "day" + ], + [ + "R2", + 2020, + "fall", + "day" + ], + [ + "R1", + 2030, + "fall", + "day" + ], + [ + "R2", + 2025, + "spring", + "day" + ], + [ + "R2", + 2020, + "winter", + "night" + ], + [ + "R1", + 2025, + "spring", + "day" + ], + [ + "R1", + 2020, + "winter", + "night" + ], + [ + "R2", + 2030, + "spring", + "night" + ], + [ + "R1", + 2025, + "summer", + "day" + ], + [ + "R2", + 2030, + "winter", + "day" + ], + [ + "R1", + 2020, + "fall", + "night" + ], + [ + "R2", + 2020, + "fall", + "night" + ], + [ + "R2", + 2030, + "summer", + "day" + ], + [ + "R2", + 2025, + "spring", + "night" + ], + [ + "R2", + 2025, + "winter", + "day" + ], + [ + "R1", + 2030, + "fall", + "night" + ] + ], + "RetiredCapacityVar_rptv": [], + "StorageConstraints_rpsdtv": [ + [ + "R1", + 2025, + "fall", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "spring", + "day", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "fall", + "day", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "fall", + "day", + "E_BATT", + 2030 + ], + [ + "R1", + 2025, + "winter", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "winter", + "day", + "E_BATT", + 2025 + ], + [ + "R2", + 2025, + "fall", + "day", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "winter", + "night", + "E_BATT", + 2030 + ], + [ + "R2", + 2020, + "spring", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2020, + "fall", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "summer", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2020, + "spring", + "day", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "spring", + "day", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "winter", + "day", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "winter", + "day", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "fall", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2020, + "fall", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2020, + "spring", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "fall", + "day", + "E_BATT", + 2025 + ], + [ + "R2", + 2025, + "winter", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "fall", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "winter", + "night", + "E_BATT", + 2025 + ], + [ + "R2", + 2025, + "summer", + "day", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "summer", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "winter", + "day", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "spring", + "day", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "summer", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "spring", + "night", + "E_BATT", + 2030 + ], + [ + "R1", + 2030, + "spring", + "day", + "E_BATT", + 2030 + ], + [ + "R2", + 2025, + "summer", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2025, + "spring", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2020, + "summer", + "day", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "summer", + "day", + "E_BATT", + 2030 + ], + [ + "R2", + 2030, + "winter", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "winter", + "day", + "E_BATT", + 2025 + ], + [ + "R2", + 2025, + "summer", + "day", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "fall", + "day", + "E_BATT", + 2025 + ], + [ + "R1", + 2020, + "fall", + "day", + "E_BATT", + 2020 + ], + [ + "R1", + 2020, + "winter", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "fall", + "night", + "E_BATT", + 2030 + ], + [ + "R1", + 2020, + "summer", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "spring", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_BATT", + 2030 + ], + [ + "R2", + 2020, + "fall", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "summer", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "spring", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "spring", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "summer", + "day", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "summer", + "day", + "E_BATT", + 2030 + ], + [ + "R1", + 2025, + "winter", + "day", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "fall", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2020, + "winter", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "fall", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "winter", + "night", + "E_BATT", + 2030 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_BATT", + 2030 + ], + [ + "R2", + 2020, + "winter", + "day", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "winter", + "day", + "E_BATT", + 2030 + ], + [ + "R1", + 2030, + "spring", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2020, + "spring", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "fall", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2020, + "summer", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "spring", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "summer", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "summer", + "day", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "spring", + "day", + "E_BATT", + 2030 + ], + [ + "R2", + 2030, + "fall", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "winter", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "spring", + "day", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "winter", + "day", + "E_BATT", + 2025 + ], + [ + "R2", + 2025, + "winter", + "night", + "E_BATT", + 2025 + ], + [ + "R2", + 2025, + "fall", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2025, + "summer", + "day", + "E_BATT", + 2025 + ], + [ + "R2", + 2025, + "spring", + "day", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_BATT", + 2030 + ], + [ + "R2", + 2020, + "summer", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "fall", + "night", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "summer", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "spring", + "day", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "fall", + "day", + "E_BATT", + 2030 + ], + [ + "R1", + 2025, + "summer", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "winter", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "winter", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "spring", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "winter", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2020, + "winter", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "fall", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "summer", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "spring", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "summer", + "night", + "E_BATT", + 2030 + ], + [ + "R2", + 2030, + "winter", + "day", + "E_BATT", + 2030 + ] + ], + "StorageLevel_rpsdtv": [ + [ + "R1", + 2025, + "fall", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "spring", + "day", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "fall", + "day", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "fall", + "day", + "E_BATT", + 2030 + ], + [ + "R1", + 2025, + "winter", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "winter", + "day", + "E_BATT", + 2025 + ], + [ + "R2", + 2025, + "fall", + "day", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "winter", + "night", + "E_BATT", + 2030 + ], + [ + "R2", + 2020, + "spring", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2020, + "fall", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "summer", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2020, + "spring", + "day", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "spring", + "day", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "winter", + "day", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "winter", + "day", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "fall", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2020, + "fall", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2020, + "spring", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "fall", + "day", + "E_BATT", + 2025 + ], + [ + "R2", + 2025, + "winter", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "fall", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "winter", + "night", + "E_BATT", + 2025 + ], + [ + "R2", + 2025, + "summer", + "day", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "summer", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "winter", + "day", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "spring", + "day", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "summer", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "spring", + "night", + "E_BATT", + 2030 + ], + [ + "R1", + 2030, + "spring", + "day", + "E_BATT", + 2030 + ], + [ + "R2", + 2025, + "summer", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2025, + "spring", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2020, + "summer", + "day", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "summer", + "day", + "E_BATT", + 2030 + ], + [ + "R2", + 2030, + "winter", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "winter", + "day", + "E_BATT", + 2025 + ], + [ + "R2", + 2025, + "summer", + "day", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "fall", + "day", + "E_BATT", + 2025 + ], + [ + "R1", + 2020, + "fall", + "day", + "E_BATT", + 2020 + ], + [ + "R1", + 2020, + "winter", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "fall", + "night", + "E_BATT", + 2030 + ], + [ + "R1", + 2020, + "summer", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "spring", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_BATT", + 2030 + ], + [ + "R2", + 2020, + "fall", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "summer", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "spring", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "spring", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "summer", + "day", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "summer", + "day", + "E_BATT", + 2030 + ], + [ + "R1", + 2025, + "winter", + "day", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "fall", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2020, + "winter", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "fall", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "winter", + "night", + "E_BATT", + 2030 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_BATT", + 2030 + ], + [ + "R2", + 2020, + "winter", + "day", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "winter", + "day", + "E_BATT", + 2030 + ], + [ + "R1", + 2030, + "spring", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2020, + "spring", + "night", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "fall", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2020, + "summer", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "spring", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "summer", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "summer", + "day", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "spring", + "day", + "E_BATT", + 2030 + ], + [ + "R2", + 2030, + "fall", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "winter", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "spring", + "day", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "winter", + "day", + "E_BATT", + 2025 + ], + [ + "R2", + 2025, + "winter", + "night", + "E_BATT", + 2025 + ], + [ + "R2", + 2025, + "fall", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2025, + "summer", + "day", + "E_BATT", + 2025 + ], + [ + "R2", + 2025, + "spring", + "day", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_BATT", + 2030 + ], + [ + "R2", + 2020, + "summer", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "fall", + "night", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "summer", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "spring", + "day", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "fall", + "day", + "E_BATT", + 2030 + ], + [ + "R1", + 2025, + "summer", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "summer", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "winter", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "winter", + "night", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "fall", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "spring", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "winter", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2020, + "winter", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "fall", + "night", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "summer", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "spring", + "day", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "spring", + "night", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "summer", + "night", + "E_BATT", + 2030 + ], + [ + "R2", + 2030, + "winter", + "day", + "E_BATT", + 2030 + ] + ], + "TimeNext": [], + "TwoGroupShareIndices": [], + "commodity_all": [ + "ethos", + "RH", + "OIL", + "VMT", + "SOL", + "ELC", + "DSL", + "CO2", + "URN", + "E10", + "GSL", + "NG", + "ETH" + ], + "commodity_annual": [], + "commodity_carrier": [ + "ethos", + "RH", + "OIL", + "VMT", + "SOL", + "ELC", + "DSL", + "URN", + "E10", + "GSL", + "NG", + "ETH" + ], + "commodity_demand": [ + "VMT", + "RH" + ], + "commodity_emissions": [ + "CO2" + ], + "commodity_flex": [], + "commodity_physical": [ + "ethos", + "OIL", + "SOL", + "ELC", + "DSL", + "URN", + "E10", + "GSL", + "NG", + "ETH" + ], + "commodity_source": [ + "ethos" + ], + "commodity_waste": [], + "operator": [ + "ge", + "e", + "le" + ], + "regionalGlobalIndices": [ + "R2", + "R1", + "global" + ], + "regionalIndices": [ + "R2", + "R1-R2", + "R1", + "R2-R1" + ], + "regions": [ + "R2", + "R1" + ], + "tech_all": [ + "S_IMPETH", + "S_IMPNG", + "S_IMPOIL", + "T_BLND", + "R_NGH", + "S_OILREF", + "E_TRANS", + "T_EV", + "E_NGCC", + "R_EH", + "T_GSL", + "S_IMPURN", + "E_BATT", + "E_SOLPV", + "E_NUCLEAR", + "T_DSL" + ], + "tech_annual": [], + "tech_baseload": [ + "E_NUCLEAR" + ], + "tech_curtailment": [ + "S_OILREF" + ], + "tech_downramping": [], + "tech_exchange": [ + "E_TRANS" + ], + "tech_exist": [ + "E_TRANS", + "E_NUCLEAR" + ], + "tech_flex": [], + "tech_group_members": [], + "tech_group_names": [], + "tech_production": [ + "T_BLND", + "R_NGH", + "S_OILREF", + "E_TRANS", + "T_EV", + "E_NGCC", + "R_EH", + "T_GSL", + "E_BATT", + "E_SOLPV", + "E_NUCLEAR", + "T_DSL" + ], + "tech_reserve": [], + "tech_resource": [ + "S_IMPETH", + "S_IMPNG", + "S_IMPURN", + "S_IMPOIL" + ], + "tech_retirement": [], + "tech_storage": [ + "E_BATT" + ], + "tech_uncap": [ + "S_IMPETH", + "S_IMPNG", + "S_IMPURN", + "S_IMPOIL" + ], + "tech_upramping": [], + "tech_with_capacity": [ + "T_BLND", + "R_NGH", + "S_OILREF", + "E_TRANS", + "T_EV", + "E_NGCC", + "R_EH", + "T_GSL", + "E_BATT", + "E_SOLPV", + "E_NUCLEAR", + "T_DSL" + ], + "time_exist": [ + 2015 + ], + "time_future": [ + 2025, + 2035, + 2020, + 2030 + ], + "time_of_day": [ + "day", + "night" + ], + "time_optimize": [ + 2025, + 2020, + 2030 + ], + "time_season": [ + 2025, + 2020, + 2030 + ], + "time_season_all": [ + "summer", + "fall", + "spring", + "winter" + ], + "vintage_all": [ + 2025, + 2020, + 2030, + 2015 + ], + "vintage_exist": [ + 2015 + ], + "vintage_optimize": [ + 2025, + 2020, + 2030 ] - ], - "MinTechOutputSplitAnnualConstraint_rptvo": [], - "MinTechOutputSplitAverageConstraint_rptvo": [], - "MaxTechInputSplitConstraint_rpsditv": [], - "MaxTechInputSplitAnnualConstraint_rpitv": [], - "MaxTechInputSplitAverageConstraint_rpitv": [], - "MaxTechOutputSplitConstraint_rpsdtvo": [], - "MaxTechOutputSplitAnnualConstraint_rptvo": [], - "MaxTechOutputSplitAverageConstraint_rptvo": [], - "MaxSeasonalActivityConstraint_rpst": [], - "MinSeasonalActivityConstraint_rpst": [], - "LinkedEmissionsTechConstraint_rpsdtve": [] } \ No newline at end of file diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index aa664b5f4..07ba89719 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -73,24 +73,24 @@ CREATE TABLE CapacityFactorProcess PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','day','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','night','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','day','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','night','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','day','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','night','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2010,0.27560000000000002273,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2010,0.27560000000000002273,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2010,0.27560000000000002273,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2010,0.27560000000000002273,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2010,0.27560000000000002273,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2010,0.27560000000000002273,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2010,0.2756000000000000116,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2010,0.2756000000000000116,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2010,0.2756000000000000116,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2010,0.2756000000000000116,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2010,0.2756000000000000116,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2010,0.2756000000000000116,''); CREATE TABLE CapacityFactorTech ( region TEXT, @@ -107,96 +107,96 @@ CREATE TABLE CapacityFactorTech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E70',0.8000000000000000444,''); CREATE TABLE CapacityToActivity ( region TEXT, @@ -206,11 +206,11 @@ CREATE TABLE CapacityToActivity notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO CapacityToActivity VALUES('utopia','E01',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('utopia','E21',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('utopia','E31',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('utopia','E51',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('utopia','E70',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('utopia','E01',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('utopia','E21',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('utopia','E31',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('utopia','E51',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('utopia','E70',31.53999999999999915,''); INSERT INTO CapacityToActivity VALUES('utopia','RHE',1.0,''); INSERT INTO CapacityToActivity VALUES('utopia','RHO',1.0,''); INSERT INTO CapacityToActivity VALUES('utopia','RL1',1.0,''); @@ -246,6 +246,9 @@ CREATE TABLE CommodityType PRIMARY KEY, description TEXT ); +INSERT INTO CommodityType VALUES('w','waste commodity'); +INSERT INTO CommodityType VALUES('wa','waste annual commodity'); +INSERT INTO CommodityType VALUES('wp','waste physical commodity'); INSERT INTO CommodityType VALUES('a','annual commodity'); INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); @@ -265,24 +268,9 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -CREATE TABLE EndOfLifeOutput -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); CREATE TABLE CostEmission ( - region TEXT - REFERENCES Region (region), + region TEXT, period INTEGER REFERENCES TimePeriod (period), emis_comm TEXT NOT NULL @@ -363,10 +351,10 @@ INSERT INTO CostFixed VALUES('utopia',2000,'RHO',2000,1.0,'',''); INSERT INTO CostFixed VALUES('utopia',2010,'RHO',1990,1.0,'',''); INSERT INTO CostFixed VALUES('utopia',2010,'RHO',2000,1.0,'',''); INSERT INTO CostFixed VALUES('utopia',2010,'RHO',2010,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1980,9.4600000000000008526,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1990,9.4600000000000008526,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'RL1',2000,9.4600000000000008526,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'RL1',2010,9.4600000000000008526,'',''); +INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1980,9.46000000000000086,'',''); +INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1990,9.46000000000000086,'',''); +INSERT INTO CostFixed VALUES('utopia',2000,'RL1',2000,9.46000000000000086,'',''); +INSERT INTO CostFixed VALUES('utopia',2010,'RL1',2010,9.46000000000000086,'',''); INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1970,52.0,'',''); INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1980,52.0,'',''); INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1990,52.0,'',''); @@ -462,36 +450,36 @@ INSERT INTO CostVariable VALUES('utopia',2010,'IMPOIL1',1990,8.0,'',''); INSERT INTO CostVariable VALUES('utopia',1990,'IMPURN1',1990,2.0,'',''); INSERT INTO CostVariable VALUES('utopia',2000,'IMPURN1',1990,2.0,'',''); INSERT INTO CostVariable VALUES('utopia',2010,'IMPURN1',1990,2.0,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1960,0.3,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1970,0.3,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1980,0.3,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1990,0.3,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1970,0.3,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1980,0.3,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1990,0.3,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',2000,0.3,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',1980,0.3,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',1990,0.3,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',2000,0.3,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',2010,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1960,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1970,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1980,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1990,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',1970,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',1980,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',1990,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',2000,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',1980,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',1990,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',2000,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',2010,0.2999999999999999889,'',''); INSERT INTO CostVariable VALUES('utopia',1990,'E21',1990,1.5,'',''); INSERT INTO CostVariable VALUES('utopia',2000,'E21',1990,1.5,'',''); INSERT INTO CostVariable VALUES('utopia',2010,'E21',1990,1.5,'',''); INSERT INTO CostVariable VALUES('utopia',2000,'E21',2000,1.5,'',''); INSERT INTO CostVariable VALUES('utopia',2010,'E21',2000,1.5,'',''); INSERT INTO CostVariable VALUES('utopia',2010,'E21',2010,1.5,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1960,0.4,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1970,0.4,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1980,0.4,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1990,0.4,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1970,0.4,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1980,0.4,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1990,0.4,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',2000,0.4,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',1980,0.4,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',1990,0.4,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',2000,0.4,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',2010,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1960,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1970,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1980,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1990,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',1970,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',1980,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',1990,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',2000,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',1980,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',1990,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',2000,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',2010,0.4000000000000000222,'',''); INSERT INTO CostVariable VALUES('utopia',1990,'SRE',1990,10.0,'',''); INSERT INTO CostVariable VALUES('utopia',2000,'SRE',1990,10.0,'',''); INSERT INTO CostVariable VALUES('utopia',2000,'SRE',2000,10.0,'',''); @@ -510,15 +498,15 @@ CREATE TABLE Demand notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO Demand VALUES('utopia',1990,'RH',25.200000000000000177,'',''); -INSERT INTO Demand VALUES('utopia',2000,'RH',37.799999999999998046,'',''); -INSERT INTO Demand VALUES('utopia',2010,'RH',56.699999999999999289,'',''); -INSERT INTO Demand VALUES('utopia',1990,'RL',5.5999999999999996447,'',''); -INSERT INTO Demand VALUES('utopia',2000,'RL',8.4000000000000003552,'',''); -INSERT INTO Demand VALUES('utopia',2010,'RL',12.600000000000000088,'',''); -INSERT INTO Demand VALUES('utopia',1990,'TX',5.2000000000000001776,'',''); -INSERT INTO Demand VALUES('utopia',2000,'TX',7.7999999999999998223,'',''); -INSERT INTO Demand VALUES('utopia',2010,'TX',11.69000000000000039,'',''); +INSERT INTO Demand VALUES('utopia',1990,'RH',25.19999999999999929,'',''); +INSERT INTO Demand VALUES('utopia',2000,'RH',37.79999999999999715,'',''); +INSERT INTO Demand VALUES('utopia',2010,'RH',56.69999999999999574,'',''); +INSERT INTO Demand VALUES('utopia',1990,'RL',5.599999999999999645,'',''); +INSERT INTO Demand VALUES('utopia',2000,'RL',8.400000000000000355,'',''); +INSERT INTO Demand VALUES('utopia',2010,'RL',12.59999999999999965,'',''); +INSERT INTO Demand VALUES('utopia',1990,'TX',5.200000000000000177,'',''); +INSERT INTO Demand VALUES('utopia',2000,'TX',7.799999999999999823,'',''); +INSERT INTO Demand VALUES('utopia',2010,'TX',11.68999999999999951,'',''); CREATE TABLE DemandSpecificDistribution ( region TEXT, @@ -535,46 +523,49 @@ CREATE TABLE DemandSpecificDistribution PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RH',0.11999999999999999644,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RH',0.06,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','day','RH',0.54669999999999996376,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RH',0.27329999999999996518,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RL',0.15,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RL',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','day','RL',0.15,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RH',0.1199999999999999956,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RH',0.05999999999999999778,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','day','RH',0.5466999999999999638,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RH',0.2732999999999999874,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RL',0.1499999999999999945,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RL',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','day','RL',0.1499999999999999945,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','night','RL',0.05000000000000000277,''); INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','day','RL',0.5,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RL',0.1,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RH',0.11999999999999999644,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RH',0.06,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','day','RH',0.54669999999999996376,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RH',0.27329999999999996518,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RL',0.15,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RL',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','day','RL',0.15,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RL',0.1000000000000000055,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RH',0.1199999999999999956,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RH',0.05999999999999999778,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','day','RH',0.5466999999999999638,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RH',0.2732999999999999874,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RL',0.1499999999999999945,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RL',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','day','RL',0.1499999999999999945,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','night','RL',0.05000000000000000277,''); INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','day','RL',0.5,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RL',0.1,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RH',0.11999999999999999644,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RH',0.06,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RH',0.54669999999999996376,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RH',0.27329999999999996518,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RL',0.15,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RL',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','day','RL',0.15,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RL',0.1000000000000000055,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RH',0.1199999999999999956,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RH',0.05999999999999999778,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RH',0.5466999999999999638,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RH',0.2732999999999999874,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RL',0.1499999999999999945,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RL',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','day','RL',0.1499999999999999945,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','night','RL',0.05000000000000000277,''); INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RL',0.5,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RL',0.1,''); -CREATE TABLE LoanRate +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RL',0.1000000000000000055,''); +CREATE TABLE EndOfLifeOutput ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES TimePeriod (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); CREATE TABLE Efficiency ( @@ -599,40 +590,40 @@ INSERT INTO Efficiency VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,''); INSERT INTO Efficiency VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,''); INSERT INTO Efficiency VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,''); INSERT INTO Efficiency VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,''); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1960,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1970,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1980,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1990,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',2000,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',2010,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',1990,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2000,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2010,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','URN','E21',1990,'ELC',0.4,'# 1/2.5'); -INSERT INTO Efficiency VALUES('utopia','URN','E21',2000,'ELC',0.4,'# 1/2.5'); -INSERT INTO Efficiency VALUES('utopia','URN','E21',2010,'ELC',0.4,'# 1/2.5'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',1980,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',1990,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',2000,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',2010,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1960,'ELC',0.29399999999999998578,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1970,'ELC',0.29399999999999998578,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1980,'ELC',0.29399999999999998578,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1990,'ELC',0.29399999999999998578,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',2000,'ELC',0.29399999999999998578,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',2010,'ELC',0.29399999999999998578,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',1980,'ELC',0.71999999999999992894,'# 1/1.3889'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',1990,'ELC',0.71999999999999992894,'# 1/1.3889'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',2000,'ELC',0.71999999999999992894,'# 1/1.3889'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',2010,'ELC',0.71999999999999992894,'# 1/1.3889'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1960,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1970,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1980,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1990,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',2000,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',2010,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','FEQ','E21',1990,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2000,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2010,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','URN','E21',1990,'ELC',0.4000000000000000222,'# 1/2.5'); +INSERT INTO Efficiency VALUES('utopia','URN','E21',2000,'ELC',0.4000000000000000222,'# 1/2.5'); +INSERT INTO Efficiency VALUES('utopia','URN','E21',2010,'ELC',0.4000000000000000222,'# 1/2.5'); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',1980,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',1990,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',2000,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',2010,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1960,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1970,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1980,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1990,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',2000,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',2010,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',1980,'ELC',0.7199999999999999734,'# 1/1.3889'); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',1990,'ELC',0.7199999999999999734,'# 1/1.3889'); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',2000,'ELC',0.7199999999999999734,'# 1/1.3889'); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',2010,'ELC',0.7199999999999999734,'# 1/1.3889'); INSERT INTO Efficiency VALUES('utopia','ELC','RHE',1990,'RH',1.0,'# direct translation from DMD_EFF'); INSERT INTO Efficiency VALUES('utopia','ELC','RHE',2000,'RH',1.0,'# direct translation from DMD_EFF'); INSERT INTO Efficiency VALUES('utopia','ELC','RHE',2010,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1970,'RH',0.7,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1980,'RH',0.7,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1990,'RH',0.7,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2000,'RH',0.7,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2010,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1970,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1980,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1990,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2000,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2010,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); INSERT INTO Efficiency VALUES('utopia','ELC','RL1',1980,'RL',1.0,'# direct translation from DMD_EFF'); INSERT INTO Efficiency VALUES('utopia','ELC','RL1',1990,'RL',1.0,'# direct translation from DMD_EFF'); INSERT INTO Efficiency VALUES('utopia','ELC','RL1',2000,'RL',1.0,'# direct translation from DMD_EFF'); @@ -643,19 +634,19 @@ INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'# direct tran INSERT INTO Efficiency VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1970,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1980,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1990,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2000,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2010,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',1990,'TX',0.82699999999999995736,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2000,'TX',0.82699999999999995736,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2010,'TX',0.82699999999999995736,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1970,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1980,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1990,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2000,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2010,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','ELC','TXE',1990,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2000,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2010,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); CREATE TABLE EfficiencyVariable ( region TEXT, @@ -696,10 +687,10 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.075,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.075,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',0.088999999999999985789,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.075,'',''); +INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.07499999999999999723,'',''); +INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.07499999999999999723,'',''); +INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',0.0889999999999999819,'',''); +INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.07499999999999999723,'',''); INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1970,'TX',1.0,'',''); INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1980,'TX',1.0,'',''); INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1990,'TX',1.0,'',''); @@ -724,6 +715,20 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); +CREATE TABLE EmissionEndOfLife +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); CREATE TABLE ExistingCapacity ( region TEXT, @@ -736,20 +741,20 @@ CREATE TABLE ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1960,0.175,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1970,0.175,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1980,0.15,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E31',1980,0.1,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E01',1960,0.1749999999999999889,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E01',1970,0.1749999999999999889,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E01',1980,0.1499999999999999945,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E31',1980,0.1000000000000000055,'',''); INSERT INTO ExistingCapacity VALUES('utopia','E51',1980,0.5,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1960,0.05,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1970,0.05,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1980,0.2,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E70',1960,0.05000000000000000277,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E70',1970,0.05000000000000000277,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E70',1980,0.2000000000000000111,'',''); INSERT INTO ExistingCapacity VALUES('utopia','RHO',1970,12.5,'',''); INSERT INTO ExistingCapacity VALUES('utopia','RHO',1980,12.5,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','RL1',1980,5.5999999999999996447,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXD',1970,0.4,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXD',1980,0.2,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXG',1970,3.1000000000000000888,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','RL1',1980,5.599999999999999645,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','TXD',1970,0.4000000000000000222,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','TXD',1980,0.2000000000000000111,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','TXG',1970,3.100000000000000088,'',''); INSERT INTO ExistingCapacity VALUES('utopia','TXG',1980,1.5,'',''); CREATE TABLE TechGroup ( @@ -757,25 +762,6 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE GrowthRateMax -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE GrowthRateSeed -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - seed REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) -); CREATE TABLE LoanLifetimeTech ( region TEXT, @@ -797,6 +783,17 @@ INSERT INTO LoanLifetimeTech VALUES('utopia','SRE',50.0,''); INSERT INTO LoanLifetimeTech VALUES('utopia','TXD',15.0,''); INSERT INTO LoanLifetimeTech VALUES('utopia','TXE',15.0,''); INSERT INTO LoanLifetimeTech VALUES('utopia','TXG',15.0,''); +CREATE TABLE LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); CREATE TABLE LifetimeProcess ( region TEXT, @@ -841,177 +838,470 @@ INSERT INTO LifetimeTech VALUES('utopia','IMPOIL1',1000.0,''); INSERT INTO LifetimeTech VALUES('utopia','IMPURN1',1000.0,''); INSERT INTO LifetimeTech VALUES('utopia','IMPHYD',1000.0,''); INSERT INTO LifetimeTech VALUES('utopia','IMPFEQ',1000.0,''); -CREATE TABLE LinkedTech +CREATE TABLE Operator ( - primary_region TEXT, - primary_tech TEXT + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO Operator VALUES('e','equal to'); +INSERT INTO Operator VALUES('le','less than or equal to'); +INSERT INTO Operator VALUES('ge','greater than or equal to'); +CREATE TABLE LimitGrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - emis_comm TEXT - REFERENCES Commodity (name), - driven_tech TEXT + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxActivity +CREATE TABLE LimitGrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxCapacity +CREATE TABLE LimitDegrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -INSERT INTO MaxCapacity VALUES('utopia',1990,'E31',0.13000000000000000444,'',''); -INSERT INTO MaxCapacity VALUES('utopia',2000,'E31',0.17000000000000001776,'',''); -INSERT INTO MaxCapacity VALUES('utopia',2010,'E31',0.21000000000000000888,'',''); -INSERT INTO MaxCapacity VALUES('utopia',1990,'RHE',0.0,'',''); -INSERT INTO MaxCapacity VALUES('utopia',1990,'TXD',0.6,'',''); -INSERT INTO MaxCapacity VALUES('utopia',2000,'TXD',1.7599999999999999644,'',''); -INSERT INTO MaxCapacity VALUES('utopia',2010,'TXD',4.7599999999999997868,'',''); -CREATE TABLE MaxResource +CREATE TABLE LimitGrowthNewCapacityDelta ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_res REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthNewCapacityDelta +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitStorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE MinActivity +CREATE TABLE LimitActivity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_act REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech, operator) ); -CREATE TABLE MaxCapacityGroup +CREATE TABLE LimitActivityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - max_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) +); +CREATE TABLE LimitActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) +); +CREATE TABLE LimitAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + source TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator), + CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE MinCapacity +CREATE TABLE LimitCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) -); -INSERT INTO MinCapacity VALUES('utopia',1990,'E31',0.13000000000000000444,'',''); -INSERT INTO MinCapacity VALUES('utopia',2000,'E31',0.13000000000000000444,'',''); -INSERT INTO MinCapacity VALUES('utopia',2010,'E31',0.13000000000000000444,'',''); -INSERT INTO MinCapacity VALUES('utopia',1990,'SRE',0.1,'',''); -CREATE TABLE MinCapacityGroup + PRIMARY KEY (region, period, tech, operator) +); +INSERT INTO LimitCapacity VALUES('utopia',1990,'E31','ge',0.1300000000000000044,'',''); +INSERT INTO LimitCapacity VALUES('utopia',2000,'E31','ge',0.1300000000000000044,'',''); +INSERT INTO LimitCapacity VALUES('utopia',2010,'E31','ge',0.1300000000000000044,'',''); +INSERT INTO LimitCapacity VALUES('utopia',1990,'SRE','ge',0.1000000000000000055,'',''); +INSERT INTO LimitCapacity VALUES('utopia',1990,'E31','le',0.1300000000000000044,'',''); +INSERT INTO LimitCapacity VALUES('utopia',2000,'E31','le',0.1700000000000000122,'',''); +INSERT INTO LimitCapacity VALUES('utopia',2010,'E31','le',0.21000000000000002,'',''); +INSERT INTO LimitCapacity VALUES('utopia',1990,'RHE','le',0.0,'',''); +INSERT INTO LimitCapacity VALUES('utopia',1990,'TXD','le',0.5999999999999999778,'',''); +INSERT INTO LimitCapacity VALUES('utopia',2000,'TXD','le',1.760000000000000008,'',''); +INSERT INTO LimitCapacity VALUES('utopia',2010,'TXD','le',4.759999999999999787,'',''); +CREATE TABLE LimitCapacityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) ); -CREATE TABLE OutputCurtailment +CREATE TABLE LimitCapacityShare ( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) ); -CREATE TABLE OutputNetCapacity +CREATE TABLE LimitNewCapacity ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator) +); +CREATE TABLE LimitNewCapacityGroup +( + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name, operator) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE LimitNewCapacityGroupShare ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE LimitNewCapacityShare ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) +); +CREATE TABLE LimitResource +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitSeasonalActivity +( + region TEXT + REFERENCES Region (region), + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + season TEXT + REFERENCES TimeSeason (season), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY(region,period,season,tech, operator) ); -CREATE TABLE OutputFlowIn +CREATE TABLE LimitTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +INSERT INTO LimitTechOutputSplit VALUES('utopia',1990,'SRE','DSL','ge',0.6999999999999999556,''); +INSERT INTO LimitTechOutputSplit VALUES('utopia',2000,'SRE','DSL','ge',0.6999999999999999556,''); +INSERT INTO LimitTechOutputSplit VALUES('utopia',2010,'SRE','DSL','ge',0.6999999999999999556,''); +INSERT INTO LimitTechOutputSplit VALUES('utopia',1990,'SRE','GSL','ge',0.2999999999999999889,''); +INSERT INTO LimitTechOutputSplit VALUES('utopia',2000,'SRE','GSL','ge',0.2999999999999999889,''); +INSERT INTO LimitTechOutputSplit VALUES('utopia',2010,'SRE','GSL','ge',0.2999999999999999889,''); +CREATE TABLE LimitTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputFlowIn ( scenario TEXT, region TEXT, @@ -1066,7 +1356,7 @@ CREATE TABLE OutputStorageLevel period INTEGER REFERENCES TimePeriod (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1119,24 +1409,24 @@ CREATE TABLE TimeSegmentFraction PRIMARY KEY (period, season, tod), CHECK (segfrac >= 0 AND segfrac <= 1) ); -INSERT INTO TimeSegmentFraction VALUES(1990,'inter','day',0.16669999999999998152,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(1990,'inter','night',0.08330000000000000071,'# I-N'); -INSERT INTO TimeSegmentFraction VALUES(1990,'summer','day',0.16669999999999998152,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(1990,'summer','night',0.08330000000000000071,'# S-N'); -INSERT INTO TimeSegmentFraction VALUES(1990,'winter','day',0.33329999999999997406,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(1990,'winter','night',0.16669999999999998152,'# W-N'); -INSERT INTO TimeSegmentFraction VALUES(2000,'inter','day',0.16669999999999998152,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2000,'inter','night',0.08330000000000000071,'# I-N'); -INSERT INTO TimeSegmentFraction VALUES(2000,'summer','day',0.16669999999999998152,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2000,'summer','night',0.08330000000000000071,'# S-N'); -INSERT INTO TimeSegmentFraction VALUES(2000,'winter','day',0.33329999999999997406,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2000,'winter','night',0.16669999999999998152,'# W-N'); -INSERT INTO TimeSegmentFraction VALUES(2010,'inter','day',0.16669999999999998152,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'inter','night',0.08330000000000000071,'# I-N'); -INSERT INTO TimeSegmentFraction VALUES(2010,'summer','day',0.16669999999999998152,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'summer','night',0.08330000000000000071,'# S-N'); -INSERT INTO TimeSegmentFraction VALUES(2010,'winter','day',0.33329999999999997406,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'winter','night',0.16669999999999998152,'# W-N'); +INSERT INTO TimeSegmentFraction VALUES(1990,'inter','day',0.166699999999999987,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(1990,'inter','night',0.08329999999999999905,'# I-N'); +INSERT INTO TimeSegmentFraction VALUES(1990,'summer','day',0.166699999999999987,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(1990,'summer','night',0.08329999999999999905,'# S-N'); +INSERT INTO TimeSegmentFraction VALUES(1990,'winter','day',0.3332999999999999852,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(1990,'winter','night',0.166699999999999987,'# W-N'); +INSERT INTO TimeSegmentFraction VALUES(2000,'inter','day',0.166699999999999987,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'inter','night',0.08329999999999999905,'# I-N'); +INSERT INTO TimeSegmentFraction VALUES(2000,'summer','day',0.166699999999999987,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'summer','night',0.08329999999999999905,'# S-N'); +INSERT INTO TimeSegmentFraction VALUES(2000,'winter','day',0.3332999999999999852,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'winter','night',0.166699999999999987,'# W-N'); +INSERT INTO TimeSegmentFraction VALUES(2010,'inter','day',0.166699999999999987,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'inter','night',0.08329999999999999905,'# I-N'); +INSERT INTO TimeSegmentFraction VALUES(2010,'summer','day',0.166699999999999987,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'summer','night',0.08329999999999999905,'# S-N'); +INSERT INTO TimeSegmentFraction VALUES(2010,'winter','day',0.3332999999999999852,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'winter','night',0.166699999999999987,'# W-N'); CREATE TABLE StorageDuration ( region TEXT, @@ -1145,23 +1435,6 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE StorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage) -); CREATE TABLE TechnologyType ( label TEXT @@ -1172,116 +1445,6 @@ INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE MinTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MinTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MinTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -INSERT INTO MinTechOutputSplit VALUES('utopia',1990,'SRE','DSL',0.7,''); -INSERT INTO MinTechOutputSplit VALUES('utopia',2000,'SRE','DSL',0.7,''); -INSERT INTO MinTechOutputSplit VALUES('utopia',2010,'SRE','DSL',0.7,''); -INSERT INTO MinTechOutputSplit VALUES('utopia',1990,'SRE','GSL',0.3,''); -INSERT INTO MinTechOutputSplit VALUES('utopia',2000,'SRE','GSL',0.3,''); -INSERT INTO MinTechOutputSplit VALUES('utopia',2010,'SRE','GSL',0.3,''); -CREATE TABLE MinTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -1314,14 +1477,14 @@ INSERT INTO TimeSeason VALUES('inter'); INSERT INTO TimeSeason VALUES('summer'); INSERT INTO TimeSeason VALUES('winter'); CREATE TABLE PeriodSeasons -( +( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, season TEXT REFERENCES TimeSeason (season), notes TEXT, - PRIMARY KEY (period, sequence) + PRIMARY KEY (period, sequence, season) ); INSERT INTO PeriodSeasons VALUES(1990,1,'inter',NULL); INSERT INTO PeriodSeasons VALUES(1990,2,'summer',NULL); @@ -1340,188 +1503,6 @@ CREATE TABLE TimePeriodType ); INSERT INTO TimePeriodType VALUES('e','existing vintages'); INSERT INTO TimePeriodType VALUES('f','future'); -CREATE TABLE MaxActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE MaxNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MaxNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MaxNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE MinCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MinNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MinNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); -CREATE TABLE MaxNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1539,72 +1520,6 @@ CREATE TABLE OutputEmission emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE MinActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE EmissionLimit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE MaxActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "min_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); -CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "max_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); CREATE TABLE RPSRequirement ( region TEXT NOT NULL @@ -1663,7 +1578,7 @@ INSERT INTO Technology VALUES('TXG','p','transport','petroleum','',0,0,0,0,0,0,0 CREATE TABLE OutputCost ( scenario TEXT, - region TEXT REFERENCES Region (region), + region TEXT, sector TEXT REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), @@ -1681,4 +1596,3 @@ CREATE TABLE OutputCost FOREIGN KEY (tech) REFERENCES Technology (tech) ); COMMIT; -PRAGMA FOREIGN_KEYS = 1; \ No newline at end of file diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 2e935ee92..0d4b1fe86 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -1,25851 +1,25919 @@ { - "time_exist": [ - 1960, - 1970, - 1980 - ], - "time_future": [ - 1990, - 2000, - 2010, - 2020 - ], - "time_optimize": [ - 1990, - 2000, - 2010 - ], - "vintage_exist": [ - 1960, - 1970, - 1980 - ], - "vintage_optimize": [ - 1990, - 2000, - 2010 - ], - "vintage_all": [ - 1960, - 1970, - 1980, - 1990, - 2000, - 2010 - ], - "time_season_all": [ - "inter", - "summer", - "winter" - ], - "time_season": [ - 1990, - 2000, - 2010 - ], - "TimeNext": [], - "time_of_day": [ - "day", - "night" - ], - "regions": [ - "utopia" - ], - "regionalIndices": [ - "utopia" - ], - "regionalGlobalIndices": [ - "utopia" - ], - "tech_resource": [ - "IMPDSL1", - "IMPGSL1", - "IMPHCO1", - "IMPOIL1", - "IMPURN1", - "IMPFEQ", - "IMPHYD" - ], - "tech_production": [ - "E01", - "E21", - "E31", - "E51", - "E70", - "RHE", - "RHO", - "RL1", - "SRE", - "TXD", - "TXE", - "TXG" - ], - "tech_all": [ - "IMPDSL1", - "IMPGSL1", - "IMPHCO1", - "IMPOIL1", - "IMPURN1", - "IMPFEQ", - "IMPHYD", - "E01", - "E21", - "E31", - "E51", - "E70", - "RHE", - "RHO", - "RL1", - "SRE", - "TXD", - "TXE", - "TXG" - ], - "tech_baseload": [ - "E01", - "E21", - "E31" - ], - "tech_annual": [], - "tech_storage": [ - "E51" - ], - "tech_reserve": [], - "tech_upramping": [], - "tech_downramping": [], - "tech_curtailment": [], - "tech_flex": [], - "tech_exchange": [], - "tech_group_names": [], - "tech_group_members": [], - "tech_uncap": [ - "IMPDSL1", - "IMPGSL1", - "IMPHCO1", - "IMPOIL1", - "IMPURN1", - "IMPFEQ", - "IMPHYD" - ], - "tech_with_capacity": [ - "E01", - "E21", - "E31", - "E51", - "E70", - "RHE", - "RHO", - "RL1", - "SRE", - "TXD", - "TXE", - "TXG" - ], - "tech_retirement": [], - "commodity_demand": [ - "RH", - "RL", - "TX" - ], - "commodity_emissions": [ - "co2", - "nox" - ], - "commodity_flex": [], - "commodity_physical": [ - "ethos", - "DSL", - "ELC", - "FEQ", - "GSL", - "HCO", - "HYD", - "OIL", - "URN" - ], - "commodity_source": [ - "ethos" - ], - "commodity_annual": [], - "commodity_carrier": [ - "ethos", - "DSL", - "ELC", - "FEQ", - "GSL", - "HCO", - "HYD", - "OIL", - "URN", - "RH", - "RL", - "TX" - ], - "commodity_all": [ - "ethos", - "DSL", - "ELC", - "FEQ", - "GSL", - "HCO", - "HYD", - "OIL", - "URN", - "RH", - "RL", - "TX", - "co2", - "nox" - ], - "CapacityFactor_rpsdt": [ - [ - "utopia", - 2000, - "summer", - "day", - "E31" - ], - [ - "utopia", - 2010, - "inter", - "night", - "E51" - ], - [ - "utopia", - 2010, - "inter", - "night", - "E70" - ], - [ - "utopia", - 2000, - "summer", - "day", - "E01" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHO" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RHO" - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXE" - ], - [ - "utopia", - 1990, - "summer", - "night", - "SRE" - ], - [ - "utopia", - 1990, - "winter", - "night", - "E21" - ], - [ - "utopia", - 2000, - "summer", - "day", - "RL1" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHE" - ], - [ - "utopia", - 2000, - "inter", - "day", - "RHE" - ], - [ - "utopia", - 2000, - "inter", - "day", - "E21" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXD" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RHE" - ], - [ - "utopia", - 1990, - "summer", - "day", - "E21" - ], - [ - "utopia", - 1990, - "winter", - "night", - "E51" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHE" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXE" - ], - [ - "utopia", - 2000, - "summer", - "night", - "E21" - ], - [ - "utopia", - 2000, - "summer", - "day", - "E21" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXG" - ], - [ - "utopia", - 2000, - "inter", - "day", - "E51" - ], - [ - "utopia", - 2000, - "inter", - "day", - "E70" - ], - [ - "utopia", - 2000, - "inter", - "night", - "E70" - ], - [ - "utopia", - 1990, - "summer", - "night", - "E70" - ], - [ - "utopia", - 2010, - "summer", - "day", - "E31" - ], - [ - "utopia", - 1990, - "summer", - "day", - "E51" - ], - [ - "utopia", - 2010, - "summer", - "day", - "E01" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXE" - ], - [ - "utopia", - 2000, - "summer", - "night", - "E51" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXD" - ], - [ - "utopia", - 2000, - "summer", - "night", - "E70" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RL1" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXE" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXD" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHO" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHE" - ], - [ - "utopia", - 2010, - "summer", - "night", - "E21" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXG" - ], - [ - "utopia", - 2010, - "summer", - "day", - "E21" - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXG" - ], - [ - "utopia", - 2000, - "winter", - "night", - "E31" - ], - [ - "utopia", - 2000, - "winter", - "night", - "E01" - ], - [ - "utopia", - 2010, - "inter", - "night", - "SRE" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RL1" - ], - [ - "utopia", - 1990, - "winter", - "day", - "E31" - ], - [ - "utopia", - 2010, - "summer", - "night", - "E51" - ], - [ - "utopia", - 2010, - "summer", - "night", - "E70" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXD" - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHE" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXD" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXE" - ], - [ - "utopia", - 1990, - "winter", - "night", - "SRE" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXG" - ], - [ - "utopia", - 2000, - "inter", - "day", - "SRE" - ], - [ - "utopia", - 2010, - "inter", - "day", - "E51" - ], - [ - "utopia", - 2010, - "inter", - "day", - "E70" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHO" - ], - [ - "utopia", - 2010, - "winter", - "night", - "E31" - ], - [ - "utopia", - 1990, - "inter", - "day", - "RHO" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHE" - ], - [ - "utopia", - 2010, - "winter", - "night", - "E01" - ], - [ - "utopia", - 1990, - "inter", - "night", - "E31" - ], - [ - "utopia", - 1990, - "winter", - "day", - "E21" - ], - [ - "utopia", - 1990, - "inter", - "night", - "E01" - ], - [ - "utopia", - 1990, - "summer", - "day", - "SRE" - ], - [ - "utopia", - 2000, - "summer", - "night", - "SRE" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RL1" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXE" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RL1" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXG" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHE" - ], - [ - "utopia", - 1990, - "winter", - "night", - "E70" - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXG" - ], - [ - "utopia", - 1990, - "winter", - "day", - "E51" - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHE" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXE" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXG" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXG" - ], - [ - "utopia", - 1990, - "inter", - "night", - "E21" - ], - [ - "utopia", - 1990, - "summer", - "day", - "E70" - ], - [ - "utopia", - 2000, - "summer", - "day", - "E51" - ], - [ - "utopia", - 2000, - "summer", - "day", - "E70" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXD" - ], - [ - "utopia", - 2010, - "summer", - "night", - "SRE" - ], - [ - "utopia", - 1990, - "inter", - "night", - "E51" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXE" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXE" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHO" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHE" - ], - [ - "utopia", - 2000, - "winter", - "day", - "E31" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RHO" - ], - [ - "utopia", - 2000, - "winter", - "day", - "E01" - ], - [ - "utopia", - 2010, - "inter", - "day", - "SRE" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXG" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RL1" - ], - [ - "utopia", - 2010, - "summer", - "day", - "E70" - ], - [ - "utopia", - 2010, - "summer", - "day", - "E51" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXD" - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXD" - ], - [ - "utopia", - 1990, - "winter", - "day", - "SRE" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHE" - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXG" - ], - [ - "utopia", - 2000, - "winter", - "night", - "E21" - ], - [ - "utopia", - 2000, - "winter", - "day", - "E21" - ], - [ - "utopia", - 2010, - "winter", - "day", - "E31" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHE" - ], - [ - "utopia", - 2010, - "winter", - "day", - "E01" - ], - [ - "utopia", - 1990, - "inter", - "day", - "E31" - ], - [ - "utopia", - 2000, - "winter", - "night", - "E51" - ], - [ - "utopia", - 1990, - "inter", - "day", - "E01" - ], - [ - "utopia", - 2000, - "winter", - "day", - "E51" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXD" - ], - [ - "utopia", - 2000, - "summer", - "day", - "SRE" - ], - [ - "utopia", - 2000, - "winter", - "night", - "E70" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RL1" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXE" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXG" - ], - [ - "utopia", - 1990, - "inter", - "day", - "RL1" - ], - [ - "utopia", - 1990, - "winter", - "day", - "E70" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHO" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXG" - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHO" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHE" - ], - [ - "utopia", - 2010, - "winter", - "night", - "E21" - ], - [ - "utopia", - 2010, - "inter", - "night", - "E31" - ], - [ - "utopia", - 2010, - "winter", - "day", - "E21" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RHE" - ], - [ - "utopia", - 2010, - "inter", - "night", - "E01" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXG" - ], - [ - "utopia", - 1990, - "inter", - "day", - "E21" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXD" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RL1" - ], - [ - "utopia", - 2010, - "winter", - "night", - "E51" - ], - [ - "utopia", - 2010, - "winter", - "night", - "E70" - ], - [ - "utopia", - 2010, - "winter", - "day", - "E51" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXD" - ], - [ - "utopia", - 1990, - "inter", - "night", - "E70" - ], - [ - "utopia", - 2010, - "summer", - "day", - "SRE" - ], - [ - "utopia", - 1990, - "inter", - "day", - "E51" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXD" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXE" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHO" - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXE" - ], - [ - "utopia", - 2000, - "inter", - "day", - "RHO" - ], - [ - "utopia", - 2000, - "inter", - "night", - "E31" - ], - [ - "utopia", - 2000, - "inter", - "day", - "E31" - ], - [ - "utopia", - 2000, - "inter", - "night", - "E01" - ], - [ - "utopia", - 2000, - "inter", - "day", - "E01" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHO" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RL1" - ], - [ - "utopia", - 1990, - "summer", - "night", - "E31" - ], - [ - "utopia", - 2000, - "inter", - "day", - "RL1" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHO" - ], - [ - "utopia", - 1990, - "summer", - "night", - "E01" - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHO" - ], - [ - "utopia", - 1990, - "summer", - "day", - "E01" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXG" - ], - [ - "utopia", - 2000, - "summer", - "night", - "E31" - ], - [ - "utopia", - 2000, - "summer", - "night", - "E01" - ], - [ - "utopia", - 2000, - "winter", - "night", - "SRE" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RL1" - ], - [ - "utopia", - 2000, - "winter", - "day", - "SRE" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RL1" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXE" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RL1" - ], - [ - "utopia", - 2000, - "inter", - "night", - "E21" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXD" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHE" - ], - [ - "utopia", - 1990, - "summer", - "night", - "E21" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXG" - ], - [ - "utopia", - 2000, - "inter", - "night", - "E51" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXE" - ], - [ - "utopia", - 2000, - "winter", - "day", - "E70" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHO" - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXE" - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXD" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHO" - ], - [ - "utopia", - 2010, - "summer", - "night", - "E31" - ], - [ - "utopia", - 1990, - "summer", - "night", - "E51" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXG" - ], - [ - "utopia", - 2010, - "summer", - "night", - "E01" - ], - [ - "utopia", - 2010, - "winter", - "night", - "SRE" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXE" - ], - [ - "utopia", - 2010, - "winter", - "day", - "SRE" - ], - [ - "utopia", - 1990, - "inter", - "night", - "SRE" - ], - [ - "utopia", - 1990, - "inter", - "day", - "SRE" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RL1" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXE" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHE" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXD" - ], - [ - "utopia", - 2010, - "inter", - "day", - "E31" - ], - [ - "utopia", - 1990, - "inter", - "day", - "RHE" - ], - [ - "utopia", - 2010, - "inter", - "day", - "E01" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHO" - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXD" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXG" - ], - [ - "utopia", - 2010, - "inter", - "day", - "RL1" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXG" - ], - [ - "utopia", - 2010, - "winter", - "day", - "E70" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXD" - ], - [ - "utopia", - 1990, - "inter", - "day", - "E70" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHO" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXD" - ], - [ - "utopia", - 1990, - "winter", - "night", - "E31" - ], - [ - "utopia", - 1990, - "winter", - "night", - "E01" - ], - [ - "utopia", - 1990, - "winter", - "day", - "E01" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHE" - ], - [ - "utopia", - 2010, - "inter", - "night", - "E21" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXE" - ], - [ - "utopia", - 2010, - "inter", - "day", - "E21" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RL1" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RL1" - ], - [ - "utopia", - 1990, - "summer", - "day", - "E31" - ], - [ - "utopia", - 2000, - "inter", - "night", - "SRE" - ] - ], - "LifetimeProcess_rtv": [ - [ - "utopia", - "E70", - 1970 - ], - [ - "utopia", - "E01", - 1990 - ], - [ - "utopia", - "E21", - 1990 - ], - [ - "utopia", - "RHO", - 2010 - ], - [ - "utopia", - "TXD", - 2000 - ], - [ - "utopia", - "TXE", - 2010 - ], - [ - "utopia", - "TXG", - 2000 - ], - [ - "utopia", - "E31", - 1980 - ], - [ - "utopia", - "RHE", - 1990 - ], - [ - "utopia", - "E51", - 1980 - ], - [ - "utopia", - "RHO", - 1970 - ], - [ - "utopia", - "SRE", - 2000 - ], - [ - "utopia", - "RL1", - 1980 - ], - [ - "utopia", - "TXD", - 1990 - ], - [ - "utopia", - "E70", - 2000 - ], - [ - "utopia", - "TXE", - 2000 - ], - [ - "utopia", - "IMPHCO1", - 1990 - ], - [ - "utopia", - "IMPDSL1", - 1990 - ], - [ - "utopia", - "E70", - 1960 - ], - [ - "utopia", - "E01", - 1980 - ], - [ - "utopia", - "E31", - 2010 - ], - [ - "utopia", - "E51", - 2010 - ], - [ - "utopia", - "RHO", - 2000 - ], - [ - "utopia", - "RL1", - 2010 - ], - [ - "utopia", - "TXG", - 1990 - ], - [ - "utopia", - "IMPGSL1", - 1990 - ], - [ - "utopia", - "SRE", - 1990 - ], - [ - "utopia", - "E01", - 2010 - ], - [ - "utopia", - "E70", - 1990 - ], - [ - "utopia", - "E21", - 2010 - ], - [ - "utopia", - "TXE", - 1990 - ], - [ - "utopia", - "TXD", - 1980 - ], - [ - "utopia", - "E01", - 1970 - ], - [ - "utopia", - "E31", - 2000 - ], - [ - "utopia", - "RHE", - 2010 - ], - [ - "utopia", - "RHO", - 1990 - ], - [ - "utopia", - "E51", - 2000 - ], - [ - "utopia", - "RL1", - 2000 - ], - [ - "utopia", - "TXD", - 2010 - ], - [ - "utopia", - "TXG", - 1980 - ], - [ - "utopia", - "E70", - 1980 - ], - [ - "utopia", - "E01", - 2000 - ], - [ - "utopia", - "E21", - 2000 - ], - [ - "utopia", - "IMPHYD", - 1990 - ], - [ - "utopia", - "TXD", - 1970 - ], - [ - "utopia", - "E31", - 1990 - ], - [ - "utopia", - "TXG", - 2010 - ], - [ - "utopia", - "E01", - 1960 - ], - [ - "utopia", - "RHE", - 2000 - ], - [ - "utopia", - "E51", - 1990 - ], - [ - "utopia", - "E70", - 2010 - ], - [ - "utopia", - "RHO", - 1980 - ], - [ - "utopia", - "RL1", - 1990 - ], - [ - "utopia", - "SRE", - 2010 - ], - [ - "utopia", - "IMPURN1", - 1990 - ], - [ - "utopia", - "IMPFEQ", - 1990 - ], - [ - "utopia", - "TXG", - 1970 - ], - [ - "utopia", - "IMPOIL1", - 1990 - ] - ], - "LoanLifetimeProcess_rtv": [ - [ - "utopia", - "E01", - 1990 - ], - [ - "utopia", - "E21", - 1990 - ], - [ - "utopia", - "RHO", - 2010 - ], - [ - "utopia", - "TXD", - 2000 - ], - [ - "utopia", - "TXE", - 2010 - ], - [ - "utopia", - "TXG", - 2000 - ], - [ - "utopia", - "RHE", - 1990 - ], - [ - "utopia", - "SRE", - 2000 - ], - [ - "utopia", - "TXD", - 1990 - ], - [ - "utopia", - "E70", - 2000 - ], - [ - "utopia", - "TXE", - 2000 - ], - [ - "utopia", - "IMPHCO1", - 1990 - ], - [ - "utopia", - "IMPDSL1", - 1990 - ], - [ - "utopia", - "E31", - 2010 - ], - [ - "utopia", - "E51", - 2010 - ], - [ - "utopia", - "RHO", - 2000 - ], - [ - "utopia", - "RL1", - 2010 - ], - [ - "utopia", - "TXG", - 1990 - ], - [ - "utopia", - "IMPGSL1", - 1990 - ], - [ - "utopia", - "SRE", - 1990 - ], - [ - "utopia", - "E01", - 2010 - ], - [ - "utopia", - "E70", - 1990 - ], - [ - "utopia", - "E21", - 2010 - ], - [ - "utopia", - "TXE", - 1990 - ], - [ - "utopia", - "E31", - 2000 - ], - [ - "utopia", - "RHE", - 2010 - ], - [ - "utopia", - "RHO", - 1990 - ], - [ - "utopia", - "E51", - 2000 - ], - [ - "utopia", - "RL1", - 2000 - ], - [ - "utopia", - "TXD", - 2010 - ], - [ - "utopia", - "E01", - 2000 - ], - [ - "utopia", - "E21", - 2000 - ], - [ - "utopia", - "IMPHYD", - 1990 - ], - [ - "utopia", - "E31", - 1990 - ], - [ - "utopia", - "TXG", - 2010 - ], - [ - "utopia", - "RHE", - 2000 - ], - [ - "utopia", - "RL1", - 1990 - ], - [ - "utopia", - "E51", - 1990 - ], - [ - "utopia", - "E70", - 2010 - ], - [ - "utopia", - "SRE", - 2010 - ], - [ - "utopia", - "IMPURN1", - 1990 - ], - [ - "utopia", - "IMPFEQ", - 1990 - ], - [ - "utopia", - "IMPOIL1", - 1990 - ] - ], - "RenewablePortfolioStandardConstraint_rpg": [], - "CostFixed_rptv": [ - [ - "utopia", - 2010, - "E51", - 2010 - ], - [ - "utopia", - 2000, - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "TXG", - 1990 - ], - [ - "utopia", - 1990, - "TXD", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 2010 - ], - [ - "utopia", - 2010, - "E70", - 1990 - ], - [ - "utopia", - 2000, - "E70", - 1990 - ], - [ - "utopia", - 1990, - "E01", - 1980 - ], - [ - "utopia", - 2000, - "RHO", - 1990 - ], - [ - "utopia", - 1990, - "TXE", - 1990 - ], - [ - "utopia", - 2010, - "TXG", - 2010 - ], - [ - "utopia", - 2000, - "RL1", - 2000 - ], - [ - "utopia", - 2000, - "E31", - 1990 - ], - [ - "utopia", - 1990, - "E70", - 1990 - ], - [ - "utopia", - 2010, - "RHE", - 2000 - ], - [ - "utopia", - 2000, - "RHE", - 2000 - ], - [ - "utopia", - 1990, - "TXG", - 1980 - ], - [ - "utopia", - 2010, - "E70", - 2010 - ], - [ - "utopia", - 2010, - "E31", - 1980 - ], - [ - "utopia", - 2010, - "E51", - 1980 - ], - [ - "utopia", - 2000, - "E51", - 1980 - ], - [ - "utopia", - 1990, - "RHO", - 1980 - ], - [ - "utopia", - 2010, - "E31", - 2010 - ], - [ - "utopia", - 2010, - "RHO", - 2000 - ], - [ - "utopia", - 2000, - "TXD", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 1980 - ], - [ - "utopia", - 2000, - "E01", - 1980 - ], - [ - "utopia", - 2000, - "SRE", - 2000 - ], - [ - "utopia", - 1990, - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "E51", - 1980 - ], - [ - "utopia", - 2010, - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "E51", - 2000 - ], - [ - "utopia", - 2000, - "E51", - 2000 - ], - [ - "utopia", - 2010, - "E21", - 2010 - ], - [ - "utopia", - 2010, - "TXD", - 2010 - ], - [ - "utopia", - 2000, - "TXG", - 1980 - ], - [ - "utopia", - 1990, - "E70", - 1960 - ], - [ - "utopia", - 1990, - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "E01", - 2000 - ], - [ - "utopia", - 2010, - "E70", - 1980 - ], - [ - "utopia", - 2000, - "E70", - 1980 - ], - [ - "utopia", - 1990, - "E01", - 1970 - ], - [ - "utopia", - 1990, - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "TXE", - 2010 - ], - [ - "utopia", - 2000, - "RHO", - 1980 - ], - [ - "utopia", - 2010, - "TXG", - 2000 - ], - [ - "utopia", - 2000, - "E31", - 1980 - ], - [ - "utopia", - 1990, - "E70", - 1980 - ], - [ - "utopia", - 2010, - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "E70", - 2000 - ], - [ - "utopia", - 1990, - "RL1", - 1990 - ], - [ - "utopia", - 2000, - "RHO", - 2000 - ], - [ - "utopia", - 1990, - "E31", - 1980 - ], - [ - "utopia", - 1990, - "RHO", - 1970 - ], - [ - "utopia", - 2010, - "E31", - 2000 - ], - [ - "utopia", - 2000, - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "E01", - 1970 - ], - [ - "utopia", - 2000, - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "E51", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 2000 - ], - [ - "utopia", - 2010, - "E21", - 2000 - ], - [ - "utopia", - 2000, - "E21", - 2000 - ], - [ - "utopia", - 2010, - "TXD", - 2000 - ], - [ - "utopia", - 2010, - "SRE", - 2010 - ], - [ - "utopia", - 2000, - "E70", - 1970 - ], - [ - "utopia", - 1990, - "E01", - 1960 - ], - [ - "utopia", - 2010, - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "TXG", - 2000 - ], - [ - "utopia", - 2010, - "E70", - 2000 - ], - [ - "utopia", - 1990, - "TXG", - 1970 - ], - [ - "utopia", - 1990, - "E01", - 1990 - ], - [ - "utopia", - 1990, - "E21", - 1990 - ], - [ - "utopia", - 1990, - "E70", - 1970 - ], - [ - "utopia", - 2010, - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "RL1", - 2010 - ], - [ - "utopia", - 1990, - "RL1", - 1980 - ], - [ - "utopia", - 2000, - "E31", - 2000 - ], - [ - "utopia", - 2010, - "RHE", - 2010 - ], - [ - "utopia", - 1990, - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "E31", - 1990 - ], - [ - "utopia", - 2010, - "E51", - 1990 - ], - [ - "utopia", - 1990, - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "RHO", - 2010 - ], - [ - "utopia", - 2000, - "TXD", - 2000 - ], - [ - "utopia", - 1990, - "TXD", - 1970 - ], - [ - "utopia", - 2010, - "E01", - 1990 - ], - [ - "utopia", - 2010, - "E21", - 1990 - ], - [ - "utopia", - 2000, - "E01", - 1990 - ], - [ - "utopia", - 2000, - "E21", - 1990 - ], - [ - "utopia", - 1990, - "E31", - 1990 - ], - [ - "utopia", - 1990, - "E51", - 1990 - ], - [ - "utopia", - 2010, - "SRE", - 2000 - ] - ], - "CostInvest_rtv": [ - [ - "utopia", - "E01", - 1990 - ], - [ - "utopia", - "E01", - 2000 - ], - [ - "utopia", - "E01", - 2010 - ], - [ - "utopia", - "E21", - 1990 - ], - [ - "utopia", - "E21", - 2000 - ], - [ - "utopia", - "E21", - 2010 - ], - [ - "utopia", - "E31", - 1990 - ], - [ - "utopia", - "E31", - 2000 - ], - [ - "utopia", - "E31", - 2010 - ], - [ - "utopia", - "E51", - 1990 - ], - [ - "utopia", - "E51", - 2000 - ], - [ - "utopia", - "E51", - 2010 - ], - [ - "utopia", - "E70", - 1990 - ], - [ - "utopia", - "E70", - 2000 - ], - [ - "utopia", - "E70", - 2010 - ], - [ - "utopia", - "RHE", - 1990 - ], - [ - "utopia", - "RHE", - 2000 - ], - [ - "utopia", - "RHE", - 2010 - ], - [ - "utopia", - "RHO", - 1990 - ], - [ - "utopia", - "RHO", - 2000 - ], - [ - "utopia", - "RHO", - 2010 - ], - [ - "utopia", - "SRE", - 1990 - ], - [ - "utopia", - "SRE", - 2000 - ], - [ - "utopia", - "SRE", - 2010 - ], - [ - "utopia", - "TXD", - 1990 - ], - [ - "utopia", - "TXD", - 2000 - ], - [ - "utopia", - "TXD", - 2010 - ], - [ - "utopia", - "TXE", - 1990 - ], - [ - "utopia", - "TXE", - 2000 - ], - [ - "utopia", - "TXE", - 2010 - ], - [ - "utopia", - "TXG", - 1990 - ], - [ - "utopia", - "TXG", - 2000 - ], - [ - "utopia", - "TXG", - 2010 - ] - ], - "CostVariable_rptv": [ - [ - "utopia", - 2010, - "E51", - 2010 - ], - [ - "utopia", - 1990, - "IMPURN1", - 1990 - ], - [ - "utopia", - 1990, - "IMPOIL1", - 1990 - ], - [ - "utopia", - 2000, - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "TXG", - 1990 - ], - [ - "utopia", - 1990, - "TXD", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 2010 - ], - [ - "utopia", - 1990, - "IMPDSL1", - 1990 - ], - [ - "utopia", - 2010, - "E70", - 1990 - ], - [ - "utopia", - 2000, - "E70", - 1990 - ], - [ - "utopia", - 1990, - "E01", - 1980 - ], - [ - "utopia", - 2000, - "RHO", - 1990 - ], - [ - "utopia", - 1990, - "TXE", - 1990 - ], - [ - "utopia", - 2010, - "TXG", - 2010 - ], - [ - "utopia", - 2000, - "RL1", - 2000 - ], - [ - "utopia", - 2000, - "IMPHYD", - 1990 - ], - [ - "utopia", - 2000, - "E31", - 1990 - ], - [ - "utopia", - 1990, - "E70", - 1990 - ], - [ - "utopia", - 2010, - "RHE", - 2000 - ], - [ - "utopia", - 2010, - "E70", - 2010 - ], - [ - "utopia", - 2000, - "RHE", - 2000 - ], - [ - "utopia", - 1990, - "TXG", - 1980 - ], - [ - "utopia", - 2010, - "E31", - 1980 - ], - [ - "utopia", - 2010, - "E51", - 1980 - ], - [ - "utopia", - 2000, - "E51", - 1980 - ], - [ - "utopia", - 2010, - "IMPURN1", - 1990 - ], - [ - "utopia", - 2000, - "IMPURN1", - 1990 - ], - [ - "utopia", - 2010, - "IMPHCO1", - 1990 - ], - [ - "utopia", - 1990, - "RHO", - 1980 - ], - [ - "utopia", - 2010, - "IMPOIL1", - 1990 - ], - [ - "utopia", - 2000, - "IMPOIL1", - 1990 - ], - [ - "utopia", - 2010, - "E31", - 2010 - ], - [ - "utopia", - 2010, - "RHO", - 2000 - ], - [ - "utopia", - 2000, - "TXD", - 1990 - ], - [ - "utopia", - 2000, - "IMPDSL1", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 1980 - ], - [ - "utopia", - 2000, - "E01", - 1980 - ], - [ - "utopia", - 2000, - "SRE", - 2000 - ], - [ - "utopia", - 1990, - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "E51", - 1980 - ], - [ - "utopia", - 2010, - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "E51", - 2000 - ], - [ - "utopia", - 2000, - "E51", - 2000 - ], - [ - "utopia", - 2010, - "IMPGSL1", - 1990 - ], - [ - "utopia", - 1990, - "IMPHCO1", - 1990 - ], - [ - "utopia", - 2010, - "E21", - 2010 - ], - [ - "utopia", - 2010, - "TXD", - 2010 - ], - [ - "utopia", - 2000, - "IMPGSL1", - 1990 - ], - [ - "utopia", - 2000, - "TXG", - 1980 - ], - [ - "utopia", - 1990, - "E70", - 1960 - ], - [ - "utopia", - 1990, - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "E01", - 2000 - ], - [ - "utopia", - 2010, - "E70", - 1980 - ], - [ - "utopia", - 2000, - "E70", - 1980 - ], - [ - "utopia", - 1990, - "E01", - 1970 - ], - [ - "utopia", - 1990, - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "TXE", - 2010 - ], - [ - "utopia", - 1990, - "IMPGSL1", - 1990 - ], - [ - "utopia", - 2000, - "RHO", - 1980 - ], - [ - "utopia", - 2010, - "TXG", - 2000 - ], - [ - "utopia", - 2000, - "E31", - 1980 - ], - [ - "utopia", - 1990, - "E70", - 1980 - ], - [ - "utopia", - 2010, - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "E70", - 2000 - ], - [ - "utopia", - 1990, - "IMPFEQ", - 1990 - ], - [ - "utopia", - 2000, - "IMPHCO1", - 1990 - ], - [ - "utopia", - 1990, - "RL1", - 1990 - ], - [ - "utopia", - 2000, - "RHO", - 2000 - ], - [ - "utopia", - 1990, - "E31", - 1980 - ], - [ - "utopia", - 1990, - "RHO", - 1970 - ], - [ - "utopia", - 2010, - "E31", - 2000 - ], - [ - "utopia", - 2000, - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "E01", - 1970 - ], - [ - "utopia", - 2000, - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "E51", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 2000 - ], - [ - "utopia", - 2010, - "E21", - 2000 - ], - [ - "utopia", - 2000, - "E21", - 2000 - ], - [ - "utopia", - 2010, - "TXD", - 2000 - ], - [ - "utopia", - 2010, - "SRE", - 2010 - ], - [ - "utopia", - 2010, - "IMPFEQ", - 1990 - ], - [ - "utopia", - 2000, - "IMPFEQ", - 1990 - ], - [ - "utopia", - 2000, - "E70", - 1970 - ], - [ - "utopia", - 1990, - "E01", - 1960 - ], - [ - "utopia", - 2010, - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "TXG", - 2000 - ], - [ - "utopia", - 2010, - "E70", - 2000 - ], - [ - "utopia", - 1990, - "TXG", - 1970 - ], - [ - "utopia", - 1990, - "E01", - 1990 - ], - [ - "utopia", - 1990, - "E21", - 1990 - ], - [ - "utopia", - 1990, - "E70", - 1970 - ], - [ - "utopia", - 2010, - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "RL1", - 2010 - ], - [ - "utopia", - 1990, - "RL1", - 1980 - ], - [ - "utopia", - 2000, - "E31", - 2000 - ], - [ - "utopia", - 2010, - "RHE", - 2010 - ], - [ - "utopia", - 1990, - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "IMPHYD", - 1990 - ], - [ - "utopia", - 2010, - "E31", - 1990 - ], - [ - "utopia", - 2010, - "E51", - 1990 - ], - [ - "utopia", - 1990, - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "RHO", - 2010 - ], - [ - "utopia", - 2000, - "TXD", - 2000 - ], - [ - "utopia", - 1990, - "IMPHYD", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 1990 - ], - [ - "utopia", - 2010, - "E21", - 1990 - ], - [ - "utopia", - 2000, - "E01", - 1990 - ], - [ - "utopia", - 2000, - "E21", - 1990 - ], - [ - "utopia", - 1990, - "E31", - 1990 - ], - [ - "utopia", - 1990, - "TXD", - 1970 - ], - [ - "utopia", - 2010, - "IMPDSL1", - 1990 - ], - [ - "utopia", - 1990, - "E51", - 1990 - ], - [ - "utopia", - 2010, - "SRE", - 2000 - ] - ], - "CostEmission_rpe": [], - "ModelProcessLife_rptv": [ - [ - "utopia", - 2010, - "E51", - 2010 - ], - [ - "utopia", - 1990, - "IMPURN1", - 1990 - ], - [ - "utopia", - 1990, - "IMPOIL1", - 1990 - ], - [ - "utopia", - 2000, - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "TXG", - 1990 - ], - [ - "utopia", - 1990, - "TXD", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 2010 - ], - [ - "utopia", - 1990, - "IMPDSL1", - 1990 - ], - [ - "utopia", - 2010, - "E70", - 1990 - ], - [ - "utopia", - 2000, - "E70", - 1990 - ], - [ - "utopia", - 1990, - "E01", - 1980 - ], - [ - "utopia", - 2000, - "RHO", - 1990 - ], - [ - "utopia", - 1990, - "TXE", - 1990 - ], - [ - "utopia", - 2010, - "TXG", - 2010 - ], - [ - "utopia", - 2000, - "RL1", - 2000 - ], - [ - "utopia", - 2000, - "IMPHYD", - 1990 - ], - [ - "utopia", - 2000, - "E31", - 1990 - ], - [ - "utopia", - 1990, - "E70", - 1990 - ], - [ - "utopia", - 2010, - "RHE", - 2000 - ], - [ - "utopia", - 2010, - "E70", - 2010 - ], - [ - "utopia", - 2000, - "RHE", - 2000 - ], - [ - "utopia", - 1990, - "TXG", - 1980 - ], - [ - "utopia", - 2010, - "E31", - 1980 - ], - [ - "utopia", - 2010, - "E51", - 1980 - ], - [ - "utopia", - 2000, - "E51", - 1980 - ], - [ - "utopia", - 2010, - "IMPURN1", - 1990 - ], - [ - "utopia", - 2000, - "IMPURN1", - 1990 - ], - [ - "utopia", - 2010, - "IMPHCO1", - 1990 - ], - [ - "utopia", - 1990, - "RHO", - 1980 - ], - [ - "utopia", - 2010, - "IMPOIL1", - 1990 - ], - [ - "utopia", - 2000, - "IMPOIL1", - 1990 - ], - [ - "utopia", - 2010, - "E31", - 2010 - ], - [ - "utopia", - 2010, - "RHO", - 2000 - ], - [ - "utopia", - 2000, - "TXD", - 1990 - ], - [ - "utopia", - 2000, - "IMPDSL1", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 1980 - ], - [ - "utopia", - 2000, - "E01", - 1980 - ], - [ - "utopia", - 2000, - "SRE", - 2000 - ], - [ - "utopia", - 1990, - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "E51", - 1980 - ], - [ - "utopia", - 2010, - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "E51", - 2000 - ], - [ - "utopia", - 2000, - "E51", - 2000 - ], - [ - "utopia", - 2010, - "IMPGSL1", - 1990 - ], - [ - "utopia", - 1990, - "IMPHCO1", - 1990 - ], - [ - "utopia", - 2010, - "E21", - 2010 - ], - [ - "utopia", - 2010, - "TXD", - 2010 - ], - [ - "utopia", - 2000, - "IMPGSL1", - 1990 - ], - [ - "utopia", - 2000, - "TXG", - 1980 - ], - [ - "utopia", - 1990, - "E70", - 1960 - ], - [ - "utopia", - 1990, - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "E01", - 2000 - ], - [ - "utopia", - 2010, - "E70", - 1980 - ], - [ - "utopia", - 2000, - "E70", - 1980 - ], - [ - "utopia", - 1990, - "E01", - 1970 - ], - [ - "utopia", - 1990, - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "TXE", - 2010 - ], - [ - "utopia", - 1990, - "IMPGSL1", - 1990 - ], - [ - "utopia", - 2000, - "RHO", - 1980 - ], - [ - "utopia", - 2010, - "TXG", - 2000 - ], - [ - "utopia", - 2000, - "E31", - 1980 - ], - [ - "utopia", - 1990, - "E70", - 1980 - ], - [ - "utopia", - 2010, - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "E70", - 2000 - ], - [ - "utopia", - 1990, - "IMPFEQ", - 1990 - ], - [ - "utopia", - 2000, - "IMPHCO1", - 1990 - ], - [ - "utopia", - 1990, - "RL1", - 1990 - ], - [ - "utopia", - 2000, - "RHO", - 2000 - ], - [ - "utopia", - 1990, - "E31", - 1980 - ], - [ - "utopia", - 1990, - "RHO", - 1970 - ], - [ - "utopia", - 2010, - "E31", - 2000 - ], - [ - "utopia", - 2000, - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "E01", - 1970 - ], - [ - "utopia", - 2000, - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "E51", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 2000 - ], - [ - "utopia", - 2010, - "E21", - 2000 - ], - [ - "utopia", - 2000, - "E21", - 2000 - ], - [ - "utopia", - 2010, - "TXD", - 2000 - ], - [ - "utopia", - 2010, - "SRE", - 2010 - ], - [ - "utopia", - 2010, - "IMPFEQ", - 1990 - ], - [ - "utopia", - 2000, - "IMPFEQ", - 1990 - ], - [ - "utopia", - 2000, - "E70", - 1970 - ], - [ - "utopia", - 1990, - "E01", - 1960 - ], - [ - "utopia", - 2010, - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "TXG", - 2000 - ], - [ - "utopia", - 2010, - "E70", - 2000 - ], - [ - "utopia", - 1990, - "TXG", - 1970 - ], - [ - "utopia", - 1990, - "E01", - 1990 - ], - [ - "utopia", - 1990, - "E21", - 1990 - ], - [ - "utopia", - 1990, - "E70", - 1970 - ], - [ - "utopia", - 2010, - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "RL1", - 2010 - ], - [ - "utopia", - 1990, - "RL1", - 1980 - ], - [ - "utopia", - 2000, - "E31", - 2000 - ], - [ - "utopia", - 2010, - "RHE", - 2010 - ], - [ - "utopia", - 1990, - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "IMPHYD", - 1990 - ], - [ - "utopia", - 2010, - "E31", - 1990 - ], - [ - "utopia", - 2010, - "E51", - 1990 - ], - [ - "utopia", - 1990, - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "RHO", - 2010 - ], - [ - "utopia", - 2000, - "TXD", - 2000 - ], - [ - "utopia", - 1990, - "IMPHYD", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 1990 - ], - [ - "utopia", - 2010, - "E21", - 1990 - ], - [ - "utopia", - 2000, - "E01", - 1990 - ], - [ - "utopia", - 2000, - "E21", - 1990 - ], - [ - "utopia", - 1990, - "E31", - 1990 - ], - [ - "utopia", - 1990, - "TXD", - 1970 - ], - [ - "utopia", - 2010, - "IMPDSL1", - 1990 - ], - [ - "utopia", - 1990, - "E51", - 1990 - ], - [ - "utopia", - 2010, - "SRE", - 2000 - ] - ], - "ProcessLifeFrac_rptv": [ - [ - "utopia", - 2010, - "E51", - 2010 - ], - [ - "utopia", - 1990, - "IMPURN1", - 1990 - ], - [ - "utopia", - 1990, - "IMPOIL1", - 1990 - ], - [ - "utopia", - 2000, - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "TXG", - 1990 - ], - [ - "utopia", - 1990, - "TXD", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 2010 - ], - [ - "utopia", - 1990, - "IMPDSL1", - 1990 - ], - [ - "utopia", - 2010, - "E70", - 1990 - ], - [ - "utopia", - 2000, - "E70", - 1990 - ], - [ - "utopia", - 1990, - "E01", - 1980 - ], - [ - "utopia", - 2000, - "RHO", - 1990 - ], - [ - "utopia", - 1990, - "TXE", - 1990 - ], - [ - "utopia", - 2010, - "TXG", - 2010 - ], - [ - "utopia", - 2000, - "RL1", - 2000 - ], - [ - "utopia", - 2000, - "IMPHYD", - 1990 - ], - [ - "utopia", - 2000, - "E31", - 1990 - ], - [ - "utopia", - 1990, - "E70", - 1990 - ], - [ - "utopia", - 2010, - "RHE", - 2000 - ], - [ - "utopia", - 2010, - "E70", - 2010 - ], - [ - "utopia", - 2000, - "RHE", - 2000 - ], - [ - "utopia", - 1990, - "TXG", - 1980 - ], - [ - "utopia", - 2010, - "E31", - 1980 - ], - [ - "utopia", - 2010, - "E51", - 1980 - ], - [ - "utopia", - 2000, - "E51", - 1980 - ], - [ - "utopia", - 2010, - "IMPURN1", - 1990 - ], - [ - "utopia", - 2000, - "IMPURN1", - 1990 - ], - [ - "utopia", - 2010, - "IMPHCO1", - 1990 - ], - [ - "utopia", - 1990, - "RHO", - 1980 - ], - [ - "utopia", - 2010, - "IMPOIL1", - 1990 - ], - [ - "utopia", - 2000, - "IMPOIL1", - 1990 - ], - [ - "utopia", - 2010, - "E31", - 2010 - ], - [ - "utopia", - 2010, - "RHO", - 2000 - ], - [ - "utopia", - 2000, - "TXD", - 1990 - ], - [ - "utopia", - 2000, - "IMPDSL1", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 1980 - ], - [ - "utopia", - 2000, - "E01", - 1980 - ], - [ - "utopia", - 2000, - "SRE", - 2000 - ], - [ - "utopia", - 1990, - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "E51", - 1980 - ], - [ - "utopia", - 2010, - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "E51", - 2000 - ], - [ - "utopia", - 2000, - "E51", - 2000 - ], - [ - "utopia", - 2010, - "IMPGSL1", - 1990 - ], - [ - "utopia", - 1990, - "IMPHCO1", - 1990 - ], - [ - "utopia", - 2010, - "E21", - 2010 - ], - [ - "utopia", - 2010, - "TXD", - 2010 - ], - [ - "utopia", - 2000, - "IMPGSL1", - 1990 - ], - [ - "utopia", - 2000, - "TXG", - 1980 - ], - [ - "utopia", - 1990, - "E70", - 1960 - ], - [ - "utopia", - 1990, - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "E01", - 2000 - ], - [ - "utopia", - 2010, - "E70", - 1980 - ], - [ - "utopia", - 2000, - "E70", - 1980 - ], - [ - "utopia", - 1990, - "E01", - 1970 - ], - [ - "utopia", - 1990, - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "TXE", - 2010 - ], - [ - "utopia", - 1990, - "IMPGSL1", - 1990 - ], - [ - "utopia", - 2000, - "RHO", - 1980 - ], - [ - "utopia", - 2010, - "TXG", - 2000 - ], - [ - "utopia", - 2000, - "E31", - 1980 - ], - [ - "utopia", - 1990, - "E70", - 1980 - ], - [ - "utopia", - 2010, - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "E70", - 2000 - ], - [ - "utopia", - 1990, - "IMPFEQ", - 1990 - ], - [ - "utopia", - 2000, - "IMPHCO1", - 1990 - ], - [ - "utopia", - 1990, - "RL1", - 1990 - ], - [ - "utopia", - 2000, - "RHO", - 2000 - ], - [ - "utopia", - 1990, - "E31", - 1980 - ], - [ - "utopia", - 1990, - "RHO", - 1970 - ], - [ - "utopia", - 2010, - "E31", - 2000 - ], - [ - "utopia", - 2000, - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "E01", - 1970 - ], - [ - "utopia", - 2000, - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "E51", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 2000 - ], - [ - "utopia", - 2010, - "E21", - 2000 - ], - [ - "utopia", - 2000, - "E21", - 2000 - ], - [ - "utopia", - 2010, - "TXD", - 2000 - ], - [ - "utopia", - 2010, - "SRE", - 2010 - ], - [ - "utopia", - 2010, - "IMPFEQ", - 1990 - ], - [ - "utopia", - 2000, - "IMPFEQ", - 1990 - ], - [ - "utopia", - 2000, - "E70", - 1970 - ], - [ - "utopia", - 1990, - "E01", - 1960 - ], - [ - "utopia", - 2010, - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "TXG", - 2000 - ], - [ - "utopia", - 2010, - "E70", - 2000 - ], - [ - "utopia", - 1990, - "TXG", - 1970 - ], - [ - "utopia", - 1990, - "E01", - 1990 - ], - [ - "utopia", - 1990, - "E21", - 1990 - ], - [ - "utopia", - 1990, - "E70", - 1970 - ], - [ - "utopia", - 2010, - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "RL1", - 2010 - ], - [ - "utopia", - 1990, - "RL1", - 1980 - ], - [ - "utopia", - 2000, - "E31", - 2000 - ], - [ - "utopia", - 2010, - "RHE", - 2010 - ], - [ - "utopia", - 1990, - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "IMPHYD", - 1990 - ], - [ - "utopia", - 2010, - "E31", - 1990 - ], - [ - "utopia", - 2010, - "E51", - 1990 - ], - [ - "utopia", - 1990, - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "RHO", - 2010 - ], - [ - "utopia", - 2000, - "TXD", - 2000 - ], - [ - "utopia", - 1990, - "IMPHYD", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 1990 - ], - [ - "utopia", - 2010, - "E21", - 1990 - ], - [ - "utopia", - 2000, - "E01", - 1990 - ], - [ - "utopia", - 2000, - "E21", - 1990 - ], - [ - "utopia", - 1990, - "E31", - 1990 - ], - [ - "utopia", - 1990, - "TXD", - 1970 - ], - [ - "utopia", - 2010, - "IMPDSL1", - 1990 - ], - [ - "utopia", - 1990, - "E51", - 1990 - ], - [ - "utopia", - 2010, - "SRE", - 2000 - ] - ], - "MinCapacityConstraint_rpt": [ - [ - "utopia", - 1990, - "E31" - ], - [ - "utopia", - 2000, - "E31" - ], - [ - "utopia", - 2010, - "E31" - ], - [ - "utopia", - 1990, - "SRE" - ] - ], - "MaxCapacityConstraint_rpt": [ - [ - "utopia", - 1990, - "E31" - ], - [ - "utopia", - 2000, - "E31" - ], - [ - "utopia", - 2010, - "E31" - ], - [ - "utopia", - 1990, - "RHE" - ], - [ - "utopia", - 1990, - "TXD" - ], - [ - "utopia", - 2000, - "TXD" - ], - [ - "utopia", - 2010, - "TXD" - ] - ], - "MinNewCapacityConstraint_rpt": [], - "MaxNewCapacityConstraint_rpt": [], - "MaxResourceConstraint_rt": [], - "MaxActivityConstraint_rpt": [], - "MinActivityConstraint_rpt": [], - "MinAnnualCapacityFactorConstraint_rpto": [], - "MaxAnnualCapacityFactorConstraint_rpto": [], - "EmissionLimitConstraint_rpe": [], - "EmissionActivity_reitvo": [ - [ - "utopia", - "nox", - "ELC", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - "co2", - "DSL", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - "co2", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - "co2", - "ELC", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - "co2", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - "co2", - "GSL", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - "co2", - "OIL", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - "co2", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - "nox", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - "co2", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - "co2", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - "co2", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - "nox", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - "nox", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - "co2", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - "nox", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - "co2", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - "nox", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - "nox", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - "co2", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - "nox", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - "nox", - "URN", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - "co2", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - "nox", - "OIL", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - "co2", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - "nox", - "GSL", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - "nox", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - "co2", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - "nox", - "ELC", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - "nox", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - "co2", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - "nox", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - "nox", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - "co2", - "ELC", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - "co2", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - "co2", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - "nox", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - "nox", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - "co2", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - "nox", - "DSL", - "E70", - 2010, - "ELC" - ], - [ - "utopia", - "nox", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - "co2", - "DSL", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - "co2", - "ELC", - "RL1", - 2010, - "RL" - ], - [ - "utopia", - "nox", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - "nox", - "DSL", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - "nox", - "OIL", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - "nox", - "ELC", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - "co2", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - "co2", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - "nox", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - "nox", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - "nox", - "HCO", - "E01", - 2010, - "ELC" - ], - [ - "utopia", - "nox", - "FEQ", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - "nox", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - "nox", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - "nox", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - "nox", - "HYD", - "E31", - 2010, - "ELC" - ], - [ - "utopia", - "co2", - "ELC", - "RL1", - 2000, - "RL" - ], - [ - "utopia", - "co2", - "DSL", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - "co2", - "OIL", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - "co2", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - "co2", - "DSL", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - "co2", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - "nox", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - "nox", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - "co2", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - "nox", - "DSL", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - "nox", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - "co2", - "FEQ", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - "co2", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - "co2", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - "nox", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - "co2", - "GSL", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - "nox", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - "co2", - "DSL", - "E70", - 1960, - "ELC" - ], - [ - "utopia", - "co2", - "ELC", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - "co2", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - "co2", - "HCO", - "E01", - 1960, - "ELC" - ], - [ - "utopia", - "co2", - "URN", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - "co2", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - "nox", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - "nox", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - "co2", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - "nox", - "DSL", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - "co2", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - "nox", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - "nox", - "ELC", - "RL1", - 2010, - "RL" - ], - [ - "utopia", - "co2", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - "nox", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - "co2", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - "nox", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - "co2", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - "nox", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - "nox", - "DSL", - "E70", - 1960, - "ELC" - ], - [ - "utopia", - "co2", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - "nox", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - "co2", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - "nox", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - "nox", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - "co2", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - "co2", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - "co2", - "ELC", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - "nox", - "ELC", - "RL1", - 2000, - "RL" - ], - [ - "utopia", - "co2", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - "co2", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - "nox", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - "nox", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - "co2", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - "nox", - "HCO", - "E01", - 1960, - "ELC" - ], - [ - "utopia", - "nox", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - "co2", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - "nox", - "DSL", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - "co2", - "HYD", - "E31", - 2010, - "ELC" - ], - [ - "utopia", - "nox", - "GSL", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - "co2", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - "co2", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - "co2", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - "nox", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - "nox", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - "co2", - "HCO", - "E01", - 2010, - "ELC" - ], - [ - "utopia", - "nox", - "ELC", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - "co2", - "DSL", - "E70", - 2010, - "ELC" - ], - [ - "utopia", - "nox", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - "co2", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - "nox", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - "nox", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - "co2", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - "nox", - "HYD", - "E31", - 1990, - "ELC" - ] - ], - "MinActivityGroup_rpg": [], - "MaxActivityGroup_rpg": [], - "MinCapacityGroupConstraint_rpg": [], - "MaxCapacityGroupConstraint_rpg": [], - "MinNewCapacityGroupConstraint_rpg": [], - "MaxNewCapacityGroupConstraint_rpg": [], - "GroupShareIndices": [], - "MinCapacityShareConstraint_rptg": [], - "MaxCapacityShareConstraint_rptg": [], - "TwoGroupShareIndices": [], - "MaxNewCapacityGroupShareConstraint_rpgg": [], - "MinNewCapacityGroupShareConstraint_rpgg": [], - "MinActivityShareConstraint_rptg": [], - "MaxActivityShareConstraint_rptg": [], - "MinNewCapacityShareConstraint_rptg": [], - "MaxNewCapacityShareConstraint_rptg": [], - "FlowVar_rpsditvo": [ - [ - "utopia", - 2010, - "summer", - "day", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 1990, - "winter", - "night", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "GSL", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2010, - "summer", - "day", - "OIL", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "day", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL", - "E70", - 1960, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "HYD", - "E31", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "DSL", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 1990, - "summer", - "night", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "night", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "URN", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2000, - "summer", - "night", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "FEQ", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "DSL", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "day", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "OIL", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ELC", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "day", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "night", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "OIL", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "day", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "winter", - "night", - "DSL", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ELC", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "night", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "URN", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "HYD", - "E31", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2000, - "inter", - "day", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "OIL", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "DSL", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "winter", - "night", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "day", - "HCO", - "E01", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2010, - "summer", - "day", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 1990, - "inter", - "day", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "day", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "GSL", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "night", - "DSL", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - 2010, - "inter", - "day", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "night", - "OIL", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "day", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "night", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2000, - "summer", - "day", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "GSL", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "night", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "RL1", - 2000, - "RL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 1990, - "inter", - "day", - "HCO", - "E01", - 1960, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "DSL", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "day", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "DSL", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "night", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "RL1", - 2000, - "RL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2010, - "summer", - "night", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "OIL", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 1990, - "winter", - "night", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "DSL", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "day", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 1990, - "winter", - "day", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "DSL", - "E70", - 1960, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "RL1", - 2010, - "RL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ELC", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "inter", - "night", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 2010, - "inter", - "night", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "RL1", - 2000, - "RL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "OIL", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "day", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "night", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "night", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "day", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "DSL", - "E70", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "summer", - "night", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "URN", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2000, - "summer", - "night", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2010, - "summer", - "day", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "HCO", - "E01", - 1960, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 1990, - "summer", - "night", - "DSL", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "day", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2000, - "summer", - "day", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ELC", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "day", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "night", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "day", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "GSL", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 1990, - "summer", - "day", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 1990, - "inter", - "night", - "HCO", - "E01", - 1960, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "DSL", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "HCO", - "E01", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "night", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2010, - "inter", - "day", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ELC", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "OIL", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "RL1", - 2000, - "RL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "day", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "DSL", - "E70", - 1960, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "day", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2000, - "winter", - "night", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "night", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "day", - "DSL", - "E70", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2000, - "summer", - "night", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2000, - "inter", - "night", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "night", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "night", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "DSL", - "E70", - 1960, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 1990, - "summer", - "night", - "HCO", - "E01", - 1960, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "DSL", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "RL1", - 2000, - "RL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 1990, - "inter", - "night", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "day", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "OIL", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "night", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "FEQ", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 1990, - "summer", - "night", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "DSL", - "E70", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "FEQ", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "night", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ELC", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "night", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "HCO", - "E01", - 1960, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ELC", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "OIL", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL", - "E70", - 1960, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "OIL", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 1990, - "summer", - "day", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "DSL", - "E70", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 1990, - "winter", - "night", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 1990, - "inter", - "day", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "night", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "night", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "night", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - 2010, - "inter", - "night", - "DSL", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "day", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "day", - "GSL", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2010, - "summer", - "night", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "day", - "HCO", - "E01", - 1960, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "URN", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "RL1", - 2010, - "RL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "inter", - "night", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "day", - "HYD", - "E31", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "day", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "night", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "night", - "HCO", - "E01", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "night", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "day", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "RL1", - 2010, - "RL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 1990, - "summer", - "night", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "day", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "FEQ", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ELC", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "night", - "GSL", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2000, - "winter", - "day", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "RL1", - 2000, - "RL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2010, - "summer", - "day", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 1990, - "winter", - "night", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 1990, - "winter", - "night", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ELC", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "day", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2000, - "inter", - "night", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "night", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "day", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2000, - "winter", - "night", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "inter", - "day", - "HYD", - "E31", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "GSL", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2010, - "winter", - "night", - "OIL", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "GSL", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "day", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "day", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "GSL", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "DSL", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ELC", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - 1990, - "inter", - "day", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2010, - "summer", - "day", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "summer", - "night", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "RL1", - 2010, - "RL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2010, - "summer", - "day", - "HYD", - "E31", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2010, - "inter", - "day", - "HCO", - "E01", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "night", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 2010, - "inter", - "day", - "DSL", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "day", - "DSL", - "E70", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "day", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "URN", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "GSL", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 1990, - "inter", - "day", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "night", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2010, - "winter", - "night", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "RL1", - 2010, - "RL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "night", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "summer", - "night", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "night", - "HYD", - "E31", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2000, - "summer", - "day", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2010, - "winter", - "day", - "FEQ", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 1990, - "summer", - "night", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2010, - "inter", - "night", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "HCO", - "E01", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "GSL", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2010, - "winter", - "night", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "DSL", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "RL1", - 2010, - "RL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2000, - "inter", - "night", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 1990, - "inter", - "day", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "night", - "GSL", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ELC", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "day", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "DSL", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "DSL", - "E70", - 1960, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "day", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2010, - "inter", - "night", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "day", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2000, - "winter", - "night", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "DSL", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "day", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "day", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "DSL", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "day", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "DSL", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "night", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 1990, - "summer", - "night", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "HCO", - "E01", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - 2010, - "inter", - "night", - "DSL", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - 2010, - "inter", - "night", - "DSL", - "E70", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "URN", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "FEQ", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "day", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 2010, - "inter", - "night", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ELC", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2000, - "inter", - "day", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "RHE", - 2000, - "RH" - ] - ], - "FlowVarAnnual_rpitvo": [], - "FlexVar_rpsditvo": [], - "FlexVarAnnual_rpitvo": [], - "CurtailmentVar_rpsditvo": [], - "FlowInStorage_rpsditvo": [ - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "E51", - 2000, - "ELC" - ] - ], - "StorageLevel_rpsdtv": [ - [ - "utopia", - 2010, - "summer", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E51", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E51", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E51", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E51", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E51", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E51", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E51", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E51", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E51", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E51", - 2010 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E51", - 2010 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E51", - 1980 - ] - ], - "CapacityVar_rptv": [ - [ - "utopia", - 2010, - "E51", - 2010 - ], - [ - "utopia", - 2000, - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "TXG", - 1990 - ], - [ - "utopia", - 1990, - "TXD", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 2010 - ], - [ - "utopia", - 2010, - "E70", - 1990 - ], - [ - "utopia", - 2000, - "E70", - 1990 - ], - [ - "utopia", - 1990, - "E01", - 1980 - ], - [ - "utopia", - 2000, - "RHO", - 1990 - ], - [ - "utopia", - 1990, - "TXE", - 1990 - ], - [ - "utopia", - 2010, - "TXG", - 2010 - ], - [ - "utopia", - 2000, - "RL1", - 2000 - ], - [ - "utopia", - 2000, - "E31", - 1990 - ], - [ - "utopia", - 1990, - "E70", - 1990 - ], - [ - "utopia", - 2010, - "RHE", - 2000 - ], - [ - "utopia", - 2000, - "RHE", - 2000 - ], - [ - "utopia", - 1990, - "TXG", - 1980 - ], - [ - "utopia", - 2010, - "E70", - 2010 - ], - [ - "utopia", - 2010, - "E31", - 1980 - ], - [ - "utopia", - 2010, - "E51", - 1980 - ], - [ - "utopia", - 2000, - "E51", - 1980 - ], - [ - "utopia", - 1990, - "RHO", - 1980 - ], - [ - "utopia", - 2010, - "E31", - 2010 - ], - [ - "utopia", - 2010, - "RHO", - 2000 - ], - [ - "utopia", - 2000, - "TXD", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 1980 - ], - [ - "utopia", - 2000, - "E01", - 1980 - ], - [ - "utopia", - 2000, - "SRE", - 2000 - ], - [ - "utopia", - 1990, - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "E51", - 1980 - ], - [ - "utopia", - 2010, - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "E51", - 2000 - ], - [ - "utopia", - 2000, - "E51", - 2000 - ], - [ - "utopia", - 2010, - "E21", - 2010 - ], - [ - "utopia", - 2010, - "TXD", - 2010 - ], - [ - "utopia", - 2000, - "TXG", - 1980 - ], - [ - "utopia", - 1990, - "E70", - 1960 - ], - [ - "utopia", - 1990, - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "E01", - 2000 - ], - [ - "utopia", - 2010, - "E70", - 1980 - ], - [ - "utopia", - 2000, - "E70", - 1980 - ], - [ - "utopia", - 1990, - "E01", - 1970 - ], - [ - "utopia", - 1990, - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "TXE", - 2010 - ], - [ - "utopia", - 2000, - "RHO", - 1980 - ], - [ - "utopia", - 2010, - "TXG", - 2000 - ], - [ - "utopia", - 2000, - "E31", - 1980 - ], - [ - "utopia", - 1990, - "E70", - 1980 - ], - [ - "utopia", - 2010, - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "E70", - 2000 - ], - [ - "utopia", - 1990, - "RL1", - 1990 - ], - [ - "utopia", - 2000, - "RHO", - 2000 - ], - [ - "utopia", - 1990, - "E31", - 1980 - ], - [ - "utopia", - 1990, - "RHO", - 1970 - ], - [ - "utopia", - 2010, - "E31", - 2000 - ], - [ - "utopia", - 2000, - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "E01", - 1970 - ], - [ - "utopia", - 2000, - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "E51", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 2000 - ], - [ - "utopia", - 2010, - "E21", - 2000 - ], - [ - "utopia", - 2000, - "E21", - 2000 - ], - [ - "utopia", - 2010, - "TXD", - 2000 - ], - [ - "utopia", - 2010, - "SRE", - 2010 - ], - [ - "utopia", - 2000, - "E70", - 1970 - ], - [ - "utopia", - 1990, - "E01", - 1960 - ], - [ - "utopia", - 2010, - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "TXG", - 2000 - ], - [ - "utopia", - 2010, - "E70", - 2000 - ], - [ - "utopia", - 1990, - "TXG", - 1970 - ], - [ - "utopia", - 1990, - "E01", - 1990 - ], - [ - "utopia", - 1990, - "E21", - 1990 - ], - [ - "utopia", - 1990, - "E70", - 1970 - ], - [ - "utopia", - 2010, - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "RL1", - 2010 - ], - [ - "utopia", - 1990, - "RL1", - 1980 - ], - [ - "utopia", - 2000, - "E31", - 2000 - ], - [ - "utopia", - 2010, - "RHE", - 2010 - ], - [ - "utopia", - 1990, - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "E31", - 1990 - ], - [ - "utopia", - 2010, - "E51", - 1990 - ], - [ - "utopia", - 1990, - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "RHO", - 2010 - ], - [ - "utopia", - 2000, - "TXD", - 2000 - ], - [ - "utopia", - 1990, - "TXD", - 1970 - ], - [ - "utopia", - 2010, - "E01", - 1990 - ], - [ - "utopia", - 2010, - "E21", - 1990 - ], - [ - "utopia", - 2000, - "E01", - 1990 - ], - [ - "utopia", - 2000, - "E21", - 1990 - ], - [ - "utopia", - 1990, - "E31", - 1990 - ], - [ - "utopia", - 1990, - "E51", - 1990 - ], - [ - "utopia", - 2010, - "SRE", - 2000 - ] - ], - "NewCapacityVar_rtv": [ - [ - "utopia", - "E70", - 1970 - ], - [ - "utopia", - "E01", - 1990 - ], - [ - "utopia", - "E21", - 1990 - ], - [ - "utopia", - "RHO", - 2010 - ], - [ - "utopia", - "TXG", - 2000 - ], - [ - "utopia", - "E31", - 1980 - ], - [ - "utopia", - "RHE", - 1990 - ], - [ - "utopia", - "E51", - 1980 - ], - [ - "utopia", - "RHO", - 1970 - ], - [ - "utopia", - "SRE", - 2000 - ], - [ - "utopia", - "RL1", - 1980 - ], - [ - "utopia", - "TXD", - 1990 - ], - [ - "utopia", - "E70", - 2000 - ], - [ - "utopia", - "TXE", - 2000 - ], - [ - "utopia", - "E70", - 1960 - ], - [ - "utopia", - "E01", - 1980 - ], - [ - "utopia", - "E31", - 2010 - ], - [ - "utopia", - "E51", - 2010 - ], - [ - "utopia", - "RHO", - 2000 - ], - [ - "utopia", - "RL1", - 2010 - ], - [ - "utopia", - "TXG", - 1990 - ], - [ - "utopia", - "SRE", - 1990 - ], - [ - "utopia", - "E01", - 2010 - ], - [ - "utopia", - "E70", - 1990 - ], - [ - "utopia", - "E21", - 2010 - ], - [ - "utopia", - "TXE", - 1990 - ], - [ - "utopia", - "TXD", - 1980 - ], - [ - "utopia", - "E01", - 1970 - ], - [ - "utopia", - "E31", - 2000 - ], - [ - "utopia", - "RHE", - 2010 - ], - [ - "utopia", - "RHO", - 1990 - ], - [ - "utopia", - "E51", - 2000 - ], - [ - "utopia", - "RL1", - 2000 - ], - [ - "utopia", - "TXD", - 2010 - ], - [ - "utopia", - "TXG", - 1980 - ], - [ - "utopia", - "E70", - 1980 - ], - [ - "utopia", - "E01", - 2000 - ], - [ - "utopia", - "E21", - 2000 - ], - [ - "utopia", - "TXD", - 1970 - ], - [ - "utopia", - "E31", - 1990 - ], - [ - "utopia", - "TXG", - 2010 - ], - [ - "utopia", - "E01", - 1960 - ], - [ - "utopia", - "RHE", - 2000 - ], - [ - "utopia", - "E51", - 1990 - ], - [ - "utopia", - "E70", - 2010 - ], - [ - "utopia", - "RHO", - 1980 - ], - [ - "utopia", - "RL1", - 1990 - ], - [ - "utopia", - "SRE", - 2010 - ], - [ - "utopia", - "TXD", - 2000 - ], - [ - "utopia", - "TXE", - 2010 - ], - [ - "utopia", - "TXG", - 1970 - ] - ], - "RetiredCapacityVar_rptv": [], - "AnnualRetirementVar_rptv": [ - [ - "utopia", - 2000, - "RHO", - 1970 - ], - [ - "utopia", - 2010, - "TXG", - 1980 - ], - [ - "utopia", - 2010, - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "E70", - 1960 - ], - [ - "utopia", - 2000, - "RL1", - 1990 - ], - [ - "utopia", - 2000, - "TXE", - 1990 - ], - [ - "utopia", - 2010, - "E70", - 1970 - ], - [ - "utopia", - 2010, - "RL1", - 2000 - ], - [ - "utopia", - 2000, - "E01", - 1960 - ], - [ - "utopia", - 2010, - "RHO", - 1980 - ], - [ - "utopia", - 2000, - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "TXG", - 1970 - ], - [ - "utopia", - 2000, - "RL1", - 1980 - ], - [ - "utopia", - 2000, - "TXD", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 1970 - ], - [ - "utopia", - 2010, - "TXD", - 2000 - ], - [ - "utopia", - 2000, - "TXD", - 1970 - ], - [ - "utopia", - 2010, - "TXG", - 2000 - ] - ], - "CapacityAvailableVar_rpt": [ - [ - "utopia", - 2010, - "E51" - ], - [ - "utopia", - 1990, - "E51" - ], - [ - "utopia", - 2000, - "TXG" - ], - [ - "utopia", - 2010, - "RHE" - ], - [ - "utopia", - 2010, - "E31" - ], - [ - "utopia", - 2000, - "SRE" - ], - [ - "utopia", - 1990, - "RHE" - ], - [ - "utopia", - 2010, - "TXD" - ], - [ - "utopia", - 1990, - "E31" - ], - [ - "utopia", - 2000, - "E01" - ], - [ - "utopia", - 1990, - "TXD" - ], - [ - "utopia", - 2010, - "RHO" - ], - [ - "utopia", - 1990, - "RHO" - ], - [ - "utopia", - 2000, - "E21" - ], - [ - "utopia", - 2010, - "E70" - ], - [ - "utopia", - 1990, - "E70" - ], - [ - "utopia", - 2000, - "RL1" - ], - [ - "utopia", - 2010, - "TXE" - ], - [ - "utopia", - 1990, - "TXE" - ], - [ - "utopia", - 2000, - "E51" - ], - [ - "utopia", - 2010, - "TXG" - ], - [ - "utopia", - 1990, - "TXG" - ], - [ - "utopia", - 2000, - "RHE" - ], - [ - "utopia", - 2010, - "SRE" - ], - [ - "utopia", - 2000, - "E31" - ], - [ - "utopia", - 2010, - "E01" - ], - [ - "utopia", - 1990, - "SRE" - ], - [ - "utopia", - 2000, - "TXD" - ], - [ - "utopia", - 1990, - "E01" - ], - [ - "utopia", - 2000, - "RHO" - ], - [ - "utopia", - 2010, - "E21" - ], - [ - "utopia", - 1990, - "E21" - ], - [ - "utopia", - 2000, - "E70" - ], - [ - "utopia", - 2010, - "RL1" - ], - [ - "utopia", - 1990, - "RL1" - ], - [ - "utopia", - 2000, - "TXE" - ] - ], - "CapacityConstraint_rpsdtv": [ - [ - "utopia", - 2000, - "inter", - "night", - "E21", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E70", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHO", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E21", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHO", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHE", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E21", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXD", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "night", - "SRE", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E31", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "night", - "SRE", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXG", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXG", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHE", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHE", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXD", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E21", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXE", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E31", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "night", - "RHO", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E70", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E01", - 1970 - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXD", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E70", - 2010 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E70", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "night", - "RL1", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHE", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E70", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXD", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E70", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "SRE", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHO", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHE", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E21", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "night", - "RHO", - 1970 - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXG", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXD", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXD", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "SRE", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHO", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXG", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E01", - 1970 - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "day", - "RL1", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXD", - 1970 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E31", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "night", - "RL1", - 2010 - ], - [ - "utopia", - 1990, - "summer", - "night", - "RHO", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "RL1", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E70", - 1970 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E70", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E01", - 1960 - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXD", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "night", - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E70", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "night", - "RL1", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXG", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E21", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "day", - "RL1", - 2010 - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E70", - 1970 - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXD", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E70", - 1970 - ], - [ - "utopia", - 2000, - "summer", - "day", - "SRE", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHO", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "SRE", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E21", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXG", - 2010 - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXD", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXG", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHO", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXG", - 1970 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "SRE", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E01", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E01", - 1970 - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXG", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E31", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "night", - "RHO", - 1970 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E70", - 1960 - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXD", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E70", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E70", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXD", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E21", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E70", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E31", - 2010 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E70", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXG", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E01", - 2010 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E31", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXD", - 1970 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E70", - 1960 - ], - [ - "utopia", - 2000, - "inter", - "day", - "RHE", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHO", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "SRE", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXD", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXD", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXG", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHO", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXG", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "SRE", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E21", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXG", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "night", - "SRE", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXG", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXD", - 1970 - ], - [ - "utopia", - 1990, - "inter", - "day", - "RHO", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXD", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E70", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHO", - 2010 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E70", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "day", - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E01", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHO", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "RL1", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E70", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E70", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E70", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHE", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E70", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E70", - 1970 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E01", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E01", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "day", - "SRE", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "RL1", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHO", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "SRE", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXD", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "night", - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXG", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "night", - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXG", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHO", - 1970 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E70", - 2010 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E31", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "day", - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E01", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "SRE", - 2010 - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXG", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "day", - "RHO", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXD", - 1970 - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHO", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXG", - 2010 - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXD", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E70", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHO", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E01", - 1970 - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXG", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E70", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXG", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "day", - "RL1", - 2010 - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHO", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXG", - 2010 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E70", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E70", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E70", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHO", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E01", - 1970 - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXD", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHE", - 2010 - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXE", - 2010 - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHE", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "RL1", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "day", - "SRE", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXG", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXG", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E01", - 1970 - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHO", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXE", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "day", - "RL1", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXG", - 1970 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E01", - 1970 - ], - [ - "utopia", - 2010, - "inter", - "night", - "SRE", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "day", - "RHO", - 1970 - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXG", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXD", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E70", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E70", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHO", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E01", - 1960 - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHE", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E70", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "night", - "RL1", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E21", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E21", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "night", - "SRE", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHO", - 1970 - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXG", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E70", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E70", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHE", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHE", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXD", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXG", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "RHO", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E31", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E01", - 1960 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXE", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "RL1", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "RL1", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E70", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHO", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E70", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E01", - 1960 - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHE", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E21", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "night", - "RL1", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXD", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXG", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E31", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E70", - 1970 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E21", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E70", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E21", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E31", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXG", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E01", - 1970 - ], - [ - "utopia", - 2000, - "winter", - "day", - "RL1", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E21", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E70", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHO", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXD", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXD", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXD", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXD", - 2010 - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXD", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXG", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E70", - 1960 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E70", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E70", - 1970 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E31", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E31", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXG", - 1970 - ], - [ - "utopia", - 1990, - "inter", - "night", - "RHO", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "RHO", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "day", - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E70", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E01", - 1970 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E01", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "day", - "RL1", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E31", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXE", - 2010 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E01", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXD", - 1970 - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHO", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E70", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXD", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E70", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXD", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "day", - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E01", - 1970 - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHO", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXD", - 1970 - ], - [ - "utopia", - 2010, - "winter", - "night", - "SRE", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXD", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXD", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHO", - 2010 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E31", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHO", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "night", - "RHE", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E70", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E31", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHE", - 2010 - ], - [ - "utopia", - 1990, - "winter", - "night", - "RL1", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHE", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "night", - "RHO", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXE", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E70", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E70", - 2010 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E01", - 1970 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E70", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E01", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E01", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "day", - "RL1", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXE", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "day", - "RL1", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHO", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E70", - 1970 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E70", - 2010 - ], - [ - "utopia", - 1990, - "winter", - "day", - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXD", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXG", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E70", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXG", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHO", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "SRE", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "night", - "RL1", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXG", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E31", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHO", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHO", - 2010 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E70", - 1970 - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXG", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E70", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E01", - 1960 - ], - [ - "utopia", - 2010, - "inter", - "day", - "SRE", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXG", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHE", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "SRE", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E21", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "RL1", - 2010 - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXG", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E31", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E70", - 1970 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E70", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E70", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E01", - 1960 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXE", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "RL1", - 2010 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHO", - 1970 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E70", - 1970 - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXD", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E70", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHE", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXG", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E70", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXG", - 1970 - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E70", - 1970 - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHO", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHO", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHO", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E31", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXD", - 2010 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E70", - 1960 - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHO", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHO", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E70", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHE", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "SRE", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXD", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXG", - 1970 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXG", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E01", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXD", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E31", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXE", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E70", - 1960 - ], - [ - "utopia", - 2000, - "inter", - "day", - "SRE", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E70", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E70", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXE", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E01", - 1970 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E31", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E70", - 1960 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E70", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXE", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXG", - 1970 - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHO", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E70", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHE", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "RL1", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E21", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E21", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHE", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHE", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHO", - 2010 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHE", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXE", - 2010 - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXG", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXE", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXD", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "SRE", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "day", - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHE", - 2010 - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXD", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E01", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXE", - 2010 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXD", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHO", - 2010 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E70", - 1970 - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E31", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E70", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHE", - 1990 - ] - ], - "CapacityAnnualConstraint_rptv": [], - "commodity_waste": [], - "tech_exist": [ - "RL1", - "E01", - "TXG", - "E31", - "RHO", - "TXD", - "E70", - "E51" - ], - "operator": [], - "DegrowthCapacityConstraint_rtpop": [], - "DegrowthNewCapacityConstraint_rtpop": [], - "DegrowthNewCapacityDeltaConstraint_rtpop": [], - "GrowthCapacityConstraint_rtpop": [], - "GrowthNewCapacityConstraint_rtpop": [], - "GrowthNewCapacityDeltaConstraint_rtpop": [], - "DemandConstraint_rpsdc": [ - [ - "utopia", - 1990, - "winter", - "night", - "TX" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RH" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "RL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RH" - ], - [ - "utopia", - 2000, - "summer", - "day", - "RH" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RH" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RL" - ], - [ - "utopia", - 1990, - "inter", - "day", - "RH" - ], - [ - "utopia", - 2010, - "inter", - "day", - "TX" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RH" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RH" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RH" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TX" - ], - [ - "utopia", - 2000, - "inter", - "day", - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RH" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TX" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TX" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TX" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "RL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "RL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RH" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RH" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RH" - ], - [ - "utopia", - 2000, - "inter", - "day", - "RH" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RH" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RH" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TX" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RH" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TX" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TX" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "RL" - ] - ], - "DemandActivityConstraint_rpsdtv_dem_s0d0": [ - [ - "utopia", - 1990, - "inter", - "night", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHE", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHE", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHE", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHE", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHE", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHE", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHE", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHE", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHE", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHE", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHE", - 2010, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHE", - 2010, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHE", - 2010, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHE", - 2010, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHE", - 2010, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RHO", - 1970, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHO", - 1970, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RHO", - 1970, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHO", - 1970, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHO", - 1970, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RHO", - 1980, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHO", - 1980, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RHO", - 1980, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHO", - 1980, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHO", - 1980, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHO", - 1980, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHO", - 1980, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHO", - 1980, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHO", - 1980, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHO", - 1980, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHO", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHO", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHO", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHO", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHO", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHO", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHO", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHO", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHO", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHO", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHO", - 2010, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHO", - 2010, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHO", - 2010, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHO", - 2010, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHO", - 2010, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXD", - 1970, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXD", - 1970, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXD", - 1970, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXD", - 1970, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXD", - 1970, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXD", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXD", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXD", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXD", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXD", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXD", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXD", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXD", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXD", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXD", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXD", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXD", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXD", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXD", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXD", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXD", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXD", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXD", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXD", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXD", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXD", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXD", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXD", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXD", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXD", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXD", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXD", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXD", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXD", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXD", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXD", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXD", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXD", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXD", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXD", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXE", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXE", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXE", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXE", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXE", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXE", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXE", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXE", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXE", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXE", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXE", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXE", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXE", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXE", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXE", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXE", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXE", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXE", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXE", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXE", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXE", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXE", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXE", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXE", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXE", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXG", - 1970, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXG", - 1970, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXG", - 1970, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXG", - 1970, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXG", - 1970, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXG", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXG", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXG", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXG", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXG", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXG", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXG", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXG", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXG", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXG", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXG", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXG", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXG", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXG", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXG", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXG", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXG", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXG", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXG", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXG", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXG", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXG", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXG", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXG", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXG", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXG", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXG", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXG", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXG", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXG", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXG", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXG", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXG", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXG", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXG", - 2010, - "TX", - "inter", - "day" - ] - ], - "CommodityBalanceConstraint_rpsdc": [ - [ - "utopia", - 2010, - "winter", - "day", - "FEQ" - ], - [ - "utopia", - 2000, - "winter", - "day", - "DSL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "URN" - ], - [ - "utopia", - 1990, - "summer", - "day", - "HYD" - ], - [ - "utopia", - 1990, - "summer", - "day", - "DSL" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "FEQ" - ], - [ - "utopia", - 2010, - "winter", - "night", - "HYD" - ], - [ - "utopia", - 2010, - "winter", - "night", - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "HCO" - ], - [ - "utopia", - 2010, - "winter", - "night", - "OIL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "GSL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "URN" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "URN" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "FEQ" - ], - [ - "utopia", - 2000, - "inter", - "day", - "FEQ" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "HYD" - ], - [ - "utopia", - 1990, - "summer", - "day", - "FEQ" - ], - [ - "utopia", - 2010, - "winter", - "night", - "FEQ" - ], - [ - "utopia", - 1990, - "inter", - "day", - "HYD" - ], - [ - "utopia", - 2000, - "winter", - "night", - "DSL" - ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "DSL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "GSL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "FEQ" - ], - [ - "utopia", - 2000, - "summer", - "day", - "OIL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "URN" - ], - [ - "utopia", - 1990, - "inter", - "day", - "OIL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "URN" - ], - [ - "utopia", - 1990, - "winter", - "night", - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "FEQ" - ], - [ - "utopia", - 2010, - "winter", - "day", - "HCO" - ], - [ - "utopia", - 2000, - "winter", - "day", - "HYD" - ], - [ - "utopia", - 2000, - "inter", - "day", - "HYD" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "DSL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "HYD" - ], - [ - "utopia", - 2000, - "winter", - "night", - "FEQ" - ], - [ - "utopia", - 2000, - "inter", - "night", - "FEQ" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "HCO" - ], - [ - "utopia", - 1990, - "summer", - "night", - "FEQ" - ], - [ - "utopia", - 1990, - "inter", - "night", - "HYD" - ], - [ - "utopia", - 2010, - "summer", - "day", - "URN" - ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "GSL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "GSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "OIL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "OIL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "OIL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "URN" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "DSL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "OIL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "HCO" - ], - [ - "utopia", - 2000, - "inter", - "day", - "HCO" - ], - [ - "utopia", - 1990, - "winter", - "night", - "URN" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "HCO" - ], - [ - "utopia", - 1990, - "winter", - "day", - "FEQ" - ], - [ - "utopia", - 2000, - "summer", - "night", - "FEQ" - ], - [ - "utopia", - 2010, - "winter", - "night", - "HCO" - ], - [ - "utopia", - 2000, - "winter", - "night", - "HYD" - ], - [ - "utopia", - 2000, - "inter", - "night", - "HYD" - ], - [ - "utopia", - 2000, - "inter", - "night", - "DSL" - ], - [ - "utopia", - 1990, - "summer", - "night", - "HYD" - ], - [ - "utopia", - 2010, - "winter", - "day", - "GSL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "HCO" - ], - [ - "utopia", - 2010, - "summer", - "night", - "URN" - ], - [ - "utopia", - 2010, - "inter", - "night", - "GSL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "FEQ" - ], - [ - "utopia", - 2000, - "winter", - "night", - "OIL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "OIL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "HYD" - ], - [ - "utopia", - 2010, - "inter", - "day", - "DSL" - ], - [ - "utopia", - 1990, - "summer", - "night", - "OIL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "HCO" - ], - [ - "utopia", - 1990, - "winter", - "day", - "HYD" - ], - [ - "utopia", - 2000, - "winter", - "night", - "HCO" - ], - [ - "utopia", - 1990, - "winter", - "day", - "DSL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "HCO" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "HCO" - ], - [ - "utopia", - 1990, - "winter", - "night", - "FEQ" - ], - [ - "utopia", - 2010, - "inter", - "day", - "OIL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "URN" - ], - [ - "utopia", - 1990, - "winter", - "day", - "OIL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "OIL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "HYD" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "FEQ" - ], - [ - "utopia", - 2010, - "summer", - "night", - "FEQ" - ], - [ - "utopia", - 2010, - "inter", - "night", - "HYD" - ], - [ - "utopia", - 2010, - "inter", - "night", - "DSL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "HCO" - ], - [ - "utopia", - 2000, - "summer", - "night", - "HCO" - ], - [ - "utopia", - 2010, - "summer", - "day", - "OIL" - ], - [ - "utopia", - 1990, - "winter", - "night", - "HYD" - ], - [ - "utopia", - 1990, - "winter", - "night", - "DSL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "URN" - ], - [ - "utopia", - 1990, - "inter", - "day", - "GSL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "URN" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "HCO" - ], - [ - "utopia", - 1990, - "winter", - "night", - "OIL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "HYD" - ], - [ - "utopia", - 2010, - "summer", - "night", - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "FEQ" - ], - [ - "utopia", - 1990, - "winter", - "night", - "HCO" - ], - [ - "utopia", - 2000, - "winter", - "day", - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "URN" - ], - [ - "utopia", - 2000, - "inter", - "day", - "GSL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "OIL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "GSL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "GSL" - ], - [ - "utopia", - 1990, - "inter", - "day", - "URN" - ], - [ - "utopia", - 1990, - "summer", - "night", - "URN" - ], - [ - "utopia", - 1990, - "inter", - "night", - "GSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "HYD" - ], - [ - "utopia", - 2010, - "winter", - "day", - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "HCO" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "HCO" - ], - [ - "utopia", - 2010, - "winter", - "day", - "OIL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "GSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "URN" - ], - [ - "utopia", - 2000, - "inter", - "day", - "URN" - ], - [ - "utopia", - 2010, - "inter", - "night", - "OIL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "URN" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "GSL" - ] - ], - "AnnualCommodityBalanceConstraint_rpc": [], - "BaseloadDiurnalConstraint_rpsdtv": [ - [ - "utopia", - 2010, - "summer", - "day", - "E01", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E01", - 2010 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E21", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E31", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E31", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E01", - 2010 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E01", - 1970 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E01", - 1970 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E01", - 1970 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E21", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E01", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E01", - 1960 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E21", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E21", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E31", - 2010 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E31", - 2010 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E21", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E01", - 1970 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E31", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E01", - 1960 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E01", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E01", - 1970 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E21", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E01", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E31", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E21", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E21", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E01", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E31", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E31", - 2010 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E01", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E21", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E01", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E31", - 2010 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E01", - 1960 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E21", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E31", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E31", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E31", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E01", - 1960 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E31", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E01", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E01", - 1970 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E21", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E01", - 1960 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E01", - 1970 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E21", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E01", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E31", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E01", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E01", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E21", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E31", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E01", - 1970 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E01", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E21", - 2010 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E01", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E31", - 2010 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E01", - 1970 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E31", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E01", - 1970 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E21", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E31", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E01", - 1970 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E01", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E21", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E31", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E21", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E21", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E01", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E01", - 1970 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E01", - 2010 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E31", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E01", - 1960 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E21", - 2010 - ] - ], - "RegionalExchangeCapacityConstraint_rrptv": [], - "StorageConstraints_rpsdtv": [ - [ - "utopia", - 2010, - "summer", - "day", - "E51", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E51", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E51", - 2010 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E51", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E51", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E51", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E51", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E51", - 2010 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E51", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E51", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E51", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E51", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E51", - 2010 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E51", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E51", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E51", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E51", - 2000 - ] - ], - "StorageFractionConstraint_rpsdtv": [], - "RampUpConstraint_rpsdtv": [], - "RampDownConstraint_rpsdtv": [], - "ReserveMargin_rpsd": [ - [ - "utopia", - 2000, - "inter", - "night" - ], - [ - "utopia", - 2000, - "winter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night" - ], - [ - "utopia", - 1990, - "winter", - "night" - ], - [ - "utopia", - 1990, - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "day" - ], - [ - "utopia", - 2000, - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night" - ], - [ - "utopia", - 2010, - "summer", - "night" - ], - [ - "utopia", - 2010, - "winter", - "night" - ], - [ - "utopia", - 2000, - "winter", - "night" - ], - [ - "utopia", - 2010, - "summer", - "day" - ], - [ - "utopia", - 1990, - "inter", - "night" - ], - [ - "utopia", - 1990, - "summer", - "night" - ], - [ - "utopia", - 2010, - "winter", - "day" - ] - ], - "MinTechInputSplitConstraint_rpsditv": [], - "MinTechInputSplitAnnualConstraint_rpitv": [], - "MinTechInputSplitAverageConstraint_rpitv": [], - "MinTechOutputSplitConstraint_rpsdtvo": [ - [ - "utopia", - 2010, - "summer", - "night", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "summer", - "night", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "inter", - "day", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "inter", - "day", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "summer", - "night", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - 1990, - "winter", - "night", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "winter", - "night", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "SRE", - 1990, - "GSL" + "AnnualCommodityBalanceConstraint_rpc": [], + "AnnualRetirementVar_rptv": [ + [ + "utopia", + 2010, + "TXD", + 2000 + ], + [ + "utopia", + 2000, + "TXG", + 1970 + ], + [ + "utopia", + 2010, + "E70", + 1970 + ], + [ + "utopia", + 2010, + "TXG", + 1980 + ], + [ + "utopia", + 2000, + "TXE", + 1990 + ], + [ + "utopia", + 2000, + "E70", + 1960 + ], + [ + "utopia", + 2010, + "TXE", + 2000 + ], + [ + "utopia", + 2000, + "RHO", + 1970 + ], + [ + "utopia", + 2010, + "RL1", + 2000 + ], + [ + "utopia", + 2010, + "RHO", + 1980 + ], + [ + "utopia", + 2000, + "RL1", + 1990 + ], + [ + "utopia", + 2000, + "TXD", + 1970 + ], + [ + "utopia", + 2000, + "TXG", + 1990 + ], + [ + "utopia", + 2010, + "TXG", + 2000 + ], + [ + "utopia", + 2010, + "TXD", + 1980 + ], + [ + "utopia", + 2000, + "RL1", + 1980 + ], + [ + "utopia", + 2000, + "E01", + 1960 + ], + [ + "utopia", + 2010, + "E01", + 1970 + ], + [ + "utopia", + 2000, + "TXD", + 1990 + ] + ], + "BaseloadDiurnalConstraint_rpsdtv": [ + [ + "utopia", + 2010, + "inter", + "night", + "E21", + 2000 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E31", + 2010 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E01", + 1990 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E01", + 1970 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E01", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E21", + 1990 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E01", + 1960 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E01", + 1980 + ], + [ + "utopia", + 1990, + "winter", + "day", + "E01", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E01", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E01", + 1970 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E21", + 2000 + ], + [ + "utopia", + 1990, + "summer", + "day", + "E31", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E31", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E01", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E31", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E01", + 2000 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E21", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E31", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E21", + 1990 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E01", + 1980 + ], + [ + "utopia", + 1990, + "inter", + "day", + "E31", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E01", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E21", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E01", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E01", + 2010 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E01", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E01", + 1970 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E31", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E01", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E31", + 2010 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E31", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E31", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E31", + 2010 + ], + [ + "utopia", + 1990, + "winter", + "day", + "E31", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E31", + 2010 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E01", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E21", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E01", + 2000 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E31", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E21", + 1990 + ], + [ + "utopia", + 1990, + "summer", + "day", + "E01", + 1960 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E21", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E01", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E01", + 2000 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E01", + 2010 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E31", + 2000 + ], + [ + "utopia", + 1990, + "inter", + "day", + "E21", + 1990 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E31", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E01", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E01", + 2000 + ], + [ + "utopia", + 1990, + "summer", + "day", + "E01", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E31", + 1990 + ], + [ + "utopia", + 1990, + "inter", + "day", + "E01", + 1970 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E31", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E31", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E31", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E21", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E31", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E21", + 2010 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E21", + 1990 + ], + [ + "utopia", + 1990, + "winter", + "day", + "E21", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E21", + 2010 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E01", + 1960 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E21", + 2000 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E01", + 1970 + ], + [ + "utopia", + 1990, + "winter", + "day", + "E01", + 1970 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E01", + 1980 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E01", + 2010 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E21", + 2000 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E01", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E01", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E31", + 1980 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E01", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E31", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E31", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E21", + 2010 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E21", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E01", + 1970 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E01", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E21", + 2000 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E01", + 1970 + ], + [ + "utopia", + 1990, + "inter", + "day", + "E31", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E21", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E01", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E01", + 1970 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E31", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E31", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E31", + 2000 + ], + [ + "utopia", + 1990, + "winter", + "day", + "E31", + 1980 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E01", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E01", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E31", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E31", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E31", + 2010 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E21", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E01", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E31", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E01", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E01", + 1970 + ], + [ + "utopia", + 1990, + "summer", + "day", + "E01", + 1980 + ], + [ + "utopia", + 1990, + "inter", + "day", + "E01", + 1960 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E31", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E31", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E31", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E21", + 2000 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E31", + 2010 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E01", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E21", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E21", + 1990 + ], + [ + "utopia", + 1990, + "inter", + "day", + "E01", + 1990 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E01", + 1960 + ], + [ + "utopia", + 1990, + "winter", + "day", + "E01", + 1960 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E01", + 2000 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E21", + 1990 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E01", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E01", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E21", + 2000 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E01", + 1990 + ], + [ + "utopia", + 1990, + "winter", + "day", + "E01", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E01", + 1970 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E31", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E01", + 2000 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E01", + 1980 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E21", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E21", + 2010 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E21", + 2010 + ], + [ + "utopia", + 1990, + "summer", + "day", + "E31", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E31", + 1980 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E01", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E31", + 2000 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E21", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E31", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E21", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E01", + 2010 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E01", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E01", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E01", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E01", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E01", + 1980 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E31", + 1980 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E31", + 1980 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E21", + 2010 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E31", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E01", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E31", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E31", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E31", + 2000 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E31", + 2000 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E31", + 1980 + ], + [ + "utopia", + 1990, + "summer", + "day", + "E21", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E21", + 2000 + ], + [ + "utopia", + 1990, + "summer", + "day", + "E01", + 1970 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E01", + 2010 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E01", + 2010 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E31", + 1980 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E31", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E01", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E31", + 2000 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E31", + 2000 + ], + [ + "utopia", + 1990, + "inter", + "day", + "E01", + 1980 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E21", + 1990 + ] + ], + "CapacityAnnualConstraint_rptv": [], + "CapacityAvailableVar_rpt": [ + [ + "utopia", + 2000, + "E01" + ], + [ + "utopia", + 2000, + "E51" + ], + [ + "utopia", + 2010, + "E70" + ], + [ + "utopia", + 2010, + "RL1" + ], + [ + "utopia", + 2010, + "TXE" + ], + [ + "utopia", + 1990, + "E70" + ], + [ + "utopia", + 2000, + "TXG" + ], + [ + "utopia", + 1990, + "RL1" + ], + [ + "utopia", + 1990, + "TXE" + ], + [ + "utopia", + 2000, + "TXD" + ], + [ + "utopia", + 2000, + "E31" + ], + [ + "utopia", + 2000, + "E21" + ], + [ + "utopia", + 2000, + "SRE" + ], + [ + "utopia", + 2000, + "RHO" + ], + [ + "utopia", + 2000, + "E70" + ], + [ + "utopia", + 2010, + "RHE" + ], + [ + "utopia", + 2000, + "RL1" + ], + [ + "utopia", + 1990, + "E31" + ], + [ + "utopia", + 2000, + "TXE" + ], + [ + "utopia", + 1990, + "RHE" + ], + [ + "utopia", + 2010, + "E01" + ], + [ + "utopia", + 2010, + "E51" + ], + [ + "utopia", + 1990, + "E01" + ], + [ + "utopia", + 1990, + "E51" + ], + [ + "utopia", + 2010, + "TXG" + ], + [ + "utopia", + 2010, + "TXD" + ], + [ + "utopia", + 1990, + "TXG" + ], + [ + "utopia", + 1990, + "TXD" + ], + [ + "utopia", + 2000, + "RHE" + ], + [ + "utopia", + 2010, + "E31" + ], + [ + "utopia", + 2010, + "E21" + ], + [ + "utopia", + 2010, + "SRE" + ], + [ + "utopia", + 2010, + "RHO" + ], + [ + "utopia", + 1990, + "E21" + ], + [ + "utopia", + 1990, + "SRE" + ], + [ + "utopia", + 1990, + "RHO" + ] + ], + "CapacityConstraint_rpsdtv": [ + [ + "utopia", + 2010, + "winter", + "day", + "E01", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXE", + 2000 + ], + [ + "utopia", + 2000, + "inter", + "day", + "RHE", + 2000 + ], + [ + "utopia", + 2000, + "summer", + "night", + "TXE", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E01", + 1980 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E01", + 1980 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E70", + 2000 + ], + [ + "utopia", + 2010, + "winter", + "night", + "RHE", + 2000 + ], + [ + "utopia", + 1990, + "summer", + "day", + "E31", + 1980 + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXE", + 1990 + ], + [ + "utopia", + 1990, + "summer", + "night", + "TXD", + 1970 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E70", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E01", + 2010 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E01", + 1970 + ], + [ + "utopia", + 2010, + "winter", + "day", + "TXE", + 2010 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E31", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "day", + "TXD", + 2010 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E31", + 2010 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E31", + 2010 + ], + [ + "utopia", + 1990, + "winter", + "night", + "RHO", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "night", + "TXE", + 2000 + ], + [ + "utopia", + 2000, + "winter", + "night", + "RHE", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "day", + "RHO", + 2000 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E70", + 2000 + ], + [ + "utopia", + 1990, + "summer", + "day", + "E01", + 1960 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E21", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E01", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E01", + 2000 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E31", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E31", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXD", + 1980 + ], + [ + "utopia", + 1990, + "inter", + "day", + "SRE", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXD", + 2000 + ], + [ + "utopia", + 1990, + "winter", + "day", + "E21", + 1990 + ], + [ + "utopia", + 1990, + "inter", + "day", + "RHO", + 1990 + ], + [ + "utopia", + 1990, + "winter", + "day", + "E70", + 1980 + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXE", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "RHE", + 1990 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E01", + 1970 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E21", + 2000 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E70", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "night", + "RHE", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "day", + "RHE", + 2010 + ], + [ + "utopia", + 2010, + "winter", + "night", + "TXG", + 2010 + ], + [ + "utopia", + 1990, + "inter", + "day", + "TXD", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E21", + 2000 + ], + [ + "utopia", + 2000, + "inter", + "day", + "TXD", + 1980 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E70", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E70", + 2010 + ], + [ + "utopia", + 2000, + "inter", + "night", + "RHE", + 2000 + ], + [ + "utopia", + 2000, + "summer", + "night", + "RHE", + 2000 + ], + [ + "utopia", + 1990, + "winter", + "night", + "SRE", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "day", + "SRE", + 2000 + ], + [ + "utopia", + 2010, + "winter", + "day", + "TXD", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E31", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E31", + 2000 + ], + [ + "utopia", + 1990, + "winter", + "night", + "RHO", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "day", + "RHO", + 1990 + ], + [ + "utopia", + 1990, + "summer", + "night", + "TXE", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "day", + "RHE", + 2000 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E70", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E01", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E21", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "night", + "TXD", + 1990 + ], + [ + "utopia", + 1990, + "summer", + "day", + "E70", + 1990 + ], + [ + "utopia", + 1990, + "winter", + "night", + "TXD", + 1990 + ], + [ + "utopia", + 1990, + "winter", + "day", + "TXG", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "night", + "RHO", + 2010 + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXD", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "night", + "RHE", + 2000 + ], + [ + "utopia", + 1990, + "inter", + "day", + "RHO", + 1980 + ], + [ + "utopia", + 1990, + "winter", + "day", + "E70", + 1970 + ], + [ + "utopia", + 1990, + "inter", + "day", + "E01", + 1990 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E01", + 1960 + ], + [ + "utopia", + 2000, + "inter", + "day", + "TXG", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "day", + "RHE", + 2010 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E70", + 2000 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E21", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E70", + 1980 + ], + [ + "utopia", + 2010, + "winter", + "day", + "SRE", + 1990 + ], + [ + "utopia", + 1990, + "inter", + "day", + "RL1", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "day", + "RHE", + 2000 + ], + [ + "utopia", + 2010, + "winter", + "night", + "TXG", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "day", + "TXE", + 2010 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E21", + 1990 + ], + [ + "utopia", + 1990, + "inter", + "day", + "TXD", + 1980 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E21", + 2010 + ], + [ + "utopia", + 2010, + "summer", + "day", + "TXD", + 2010 + ], + [ + "utopia", + 1990, + "inter", + "night", + "RHO", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E70", + 1980 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E70", + 2000 + ], + [ + "utopia", + 2000, + "summer", + "day", + "SRE", + 2000 + ], + [ + "utopia", + 2000, + "inter", + "night", + "RHE", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "night", + "RHO", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "night", + "RHE", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "day", + "RHO", + 2000 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E70", + 2000 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E70", + 2000 + ], + [ + "utopia", + 2000, + "winter", + "day", + "SRE", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E21", + 2000 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E21", + 2000 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E01", + 1990 + ], + [ + "utopia", + 1990, + "winter", + "night", + "RHO", + 1970 + ], + [ + "utopia", + 1990, + "winter", + "day", + "RHO", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXG", + 2000 + ], + [ + "utopia", + 2000, + "winter", + "day", + "RHO", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E70", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E01", + 1990 + ], + [ + "utopia", + 1990, + "winter", + "night", + "RL1", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXD", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "day", + "RL1", + 2000 + ], + [ + "utopia", + 2000, + "summer", + "night", + "TXD", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXD", + 2000 + ], + [ + "utopia", + 1990, + "summer", + "day", + "E21", + 1990 + ], + [ + "utopia", + 1990, + "summer", + "day", + "E70", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E70", + 1970 + ], + [ + "utopia", + 2010, + "winter", + "night", + "SRE", + 2010 + ], + [ + "utopia", + 1990, + "winter", + "night", + "TXD", + 1980 + ], + [ + "utopia", + 1990, + "winter", + "day", + "TXG", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXD", + 1980 + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXD", + 1970 + ], + [ + "utopia", + 2010, + "summer", + "day", + "SRE", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "night", + "RHE", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "day", + "RHE", + 2010 + ], + [ + "utopia", + 1990, + "winter", + "day", + "E70", + 1960 + ], + [ + "utopia", + 1990, + "summer", + "night", + "RHE", + 1990 + ], + [ + "utopia", + 1990, + "inter", + "day", + "RHO", + 1970 + ], + [ + "utopia", + 1990, + "inter", + "day", + "E01", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "night", + "TXG", + 2010 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E21", + 2000 + ], + [ + "utopia", + 2000, + "inter", + "day", + "TXG", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "day", + "RHO", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "day", + "RHE", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E70", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E70", + 2010 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E70", + 2010 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E70", + 1970 + ], + [ + "utopia", + 1990, + "inter", + "day", + "RL1", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "day", + "RL1", + 2010 + ], + [ + "utopia", + 1990, + "inter", + "night", + "SRE", + 1990 + ], + [ + "utopia", + 1990, + "summer", + "night", + "RHO", + 1970 + ], + [ + "utopia", + 2010, + "inter", + "day", + "TXD", + 2000 + ], + [ + "utopia", + 1990, + "inter", + "day", + "TXD", + 1970 + ], + [ + "utopia", + 2010, + "summer", + "day", + "TXD", + 2000 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E21", + 2000 + ], + [ + "utopia", + 1990, + "inter", + "night", + "RHO", + 1980 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E70", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "day", + "SRE", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "day", + "RHO", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E70", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E70", + 1990 + ], + [ + "utopia", + 1990, + "winter", + "day", + "SRE", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E01", + 2000 + ], + [ + "utopia", + 2000, + "summer", + "night", + "TXG", + 2000 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E21", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E21", + 1990 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E01", + 1980 + ], + [ + "utopia", + 1990, + "inter", + "day", + "E31", + 1990 + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXD", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXG", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "TXE", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E01", + 1980 + ], + [ + "utopia", + 1990, + "winter", + "night", + "RL1", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "night", + "TXD", + 2010 + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXG", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "night", + "RHO", + 2010 + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXD", + 1990 + ], + [ + "utopia", + 1990, + "inter", + "night", + "RL1", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E31", + 2000 + ], + [ + "utopia", + 1990, + "summer", + "day", + "E70", + 1970 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E01", + 2010 + ], + [ + "utopia", + 1990, + "winter", + "day", + "TXG", + 1970 + ], + [ + "utopia", + 2010, + "inter", + "day", + "SRE", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "day", + "SRE", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "day", + "TXG", + 2010 + ], + [ + "utopia", + 2010, + "inter", + "day", + "RHE", + 2000 + ], + [ + "utopia", + 1990, + "inter", + "day", + "E01", + 1970 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E31", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "night", + "TXG", + 2000 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E31", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E31", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E21", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "TXG", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E21", + 2010 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E21", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E21", + 2010 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E70", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E70", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "night", + "SRE", + 2010 + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXE", + 2000 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E01", + 1990 + ], + [ + "utopia", + 1990, + "inter", + "night", + "RHO", + 1970 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E70", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "night", + "RHE", + 2010 + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXG", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "night", + "RHO", + 2000 + ], + [ + "utopia", + 2000, + "summer", + "day", + "RHO", + 1980 + ], + [ + "utopia", + 1990, + "summer", + "night", + "RL1", + 1980 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E70", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E01", + 1970 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E01", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "night", + "TXG", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "day", + "RL1", + 2000 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E01", + 1970 + ], + [ + "utopia", + 1990, + "inter", + "day", + "E31", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "night", + "SRE", + 2010 + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXD", + 1980 + ], + [ + "utopia", + 1990, + "inter", + "day", + "TXE", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E01", + 1970 + ], + [ + "utopia", + 2010, + "summer", + "night", + "TXD", + 2000 + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXG", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXD", + 1980 + ], + [ + "utopia", + 1990, + "inter", + "night", + "RL1", + 1980 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E31", + 1990 + ], + [ + "utopia", + 1990, + "summer", + "day", + "E70", + 1960 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E31", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E01", + 1980 + ], + [ + "utopia", + 2010, + "winter", + "day", + "TXG", + 2000 + ], + [ + "utopia", + 2000, + "summer", + "night", + "TXE", + 1990 + ], + [ + "utopia", + 1990, + "inter", + "day", + "E01", + 1960 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E31", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E31", + 1990 + ], + [ + "utopia", + 1990, + "winter", + "night", + "TXE", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E21", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "night", + "SRE", + 2000 + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXE", + 1990 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E01", + 1980 + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXG", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "night", + "RHO", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E01", + 2000 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E01", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "night", + "RL1", + 2010 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E21", + 2010 + ], + [ + "utopia", + 2010, + "winter", + "day", + "TXE", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E31", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E01", + 2010 + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXG", + 1970 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E01", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "day", + "TXG", + 2010 + ], + [ + "utopia", + 2010, + "summer", + "day", + "TXG", + 2010 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E31", + 1980 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E31", + 1980 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E31", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E31", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E31", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E31", + 2000 + ], + [ + "utopia", + 1990, + "summer", + "night", + "TXG", + 1990 + ], + [ + "utopia", + 1990, + "inter", + "day", + "RHE", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXE", + 2000 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E31", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "night", + "SRE", + 1990 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E01", + 1970 + ], + [ + "utopia", + 2010, + "summer", + "day", + "TXE", + 2010 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E01", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E01", + 1970 + ], + [ + "utopia", + 1990, + "winter", + "night", + "RHE", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E31", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E31", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "day", + "RHE", + 1990 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E70", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E70", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E01", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E21", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E01", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "day", + "TXG", + 2000 + ], + [ + "utopia", + 2000, + "inter", + "day", + "RHO", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "day", + "TXG", + 2000 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E31", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E31", + 2010 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E31", + 1990 + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXE", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "night", + "RHO", + 2000 + ], + [ + "utopia", + 1990, + "summer", + "night", + "TXG", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "night", + "TXE", + 2010 + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXE", + 1990 + ], + [ + "utopia", + 1990, + "inter", + "day", + "E70", + 1990 + ], + [ + "utopia", + 1990, + "inter", + "day", + "E21", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "night", + "TXD", + 2010 + ], + [ + "utopia", + 2010, + "winter", + "day", + "RHE", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "night", + "RHO", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "day", + "TXE", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "day", + "TXE", + 2000 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E01", + 1960 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E70", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "day", + "RHE", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E01", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E31", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E31", + 1980 + ], + [ + "utopia", + 1990, + "winter", + "day", + "RHO", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXD", + 2000 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E21", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "SRE", + 2000 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E70", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E70", + 1970 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E70", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E21", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "RHO", + 1990 + ], + [ + "utopia", + 1990, + "winter", + "night", + "TXD", + 1970 + ], + [ + "utopia", + 2010, + "winter", + "night", + "SRE", + 2000 + ], + [ + "utopia", + 1990, + "winter", + "day", + "TXD", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E31", + 2000 + ], + [ + "utopia", + 2010, + "winter", + "night", + "RHE", + 2010 + ], + [ + "utopia", + 2010, + "winter", + "night", + "RHO", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "day", + "RHO", + 2010 + ], + [ + "utopia", + 1990, + "summer", + "night", + "TXG", + 1970 + ], + [ + "utopia", + 2010, + "summer", + "night", + "TXE", + 2000 + ], + [ + "utopia", + 2000, + "inter", + "day", + "TXD", + 2000 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E70", + 2010 + ], + [ + "utopia", + 1990, + "inter", + "day", + "E70", + 1980 + ], + [ + "utopia", + 2010, + "winter", + "night", + "RL1", + 2010 + ], + [ + "utopia", + 1990, + "inter", + "day", + "TXG", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "day", + "RHE", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "night", + "SRE", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E70", + 2000 + ], + [ + "utopia", + 2010, + "winter", + "night", + "TXD", + 2000 + ], + [ + "utopia", + 1990, + "inter", + "night", + "RHE", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "night", + "RHO", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E01", + 2000 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E21", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E70", + 1980 + ], + [ + "utopia", + 1990, + "summer", + "day", + "RHO", + 1990 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E70", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "day", + "RHE", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E70", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E70", + 2000 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E21", + 2000 + ], + [ + "utopia", + 1990, + "winter", + "day", + "E01", + 1990 + ], + [ + "utopia", + 1990, + "winter", + "night", + "TXG", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXG", + 1980 + ], + [ + "utopia", + 1990, + "winter", + "day", + "RHO", + 1970 + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXG", + 2000 + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXD", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "SRE", + 1990 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E70", + 1970 + ], + [ + "utopia", + 1990, + "winter", + "day", + "E70", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E70", + 1980 + ], + [ + "utopia", + 1990, + "winter", + "day", + "RL1", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E01", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "night", + "RHO", + 2000 + ], + [ + "utopia", + 2000, + "inter", + "day", + "RHO", + 1980 + ], + [ + "utopia", + 2010, + "winter", + "night", + "SRE", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "day", + "SRE", + 2010 + ], + [ + "utopia", + 1990, + "winter", + "day", + "TXD", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E31", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "RL1", + 2000 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E01", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "night", + "TXD", + 2010 + ], + [ + "utopia", + 2010, + "winter", + "day", + "RHO", + 2000 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E21", + 2010 + ], + [ + "utopia", + 2010, + "inter", + "day", + "RHE", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "TXD", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "night", + "SRE", + 2000 + ], + [ + "utopia", + 2000, + "inter", + "night", + "RHO", + 2000 + ], + [ + "utopia", + 1990, + "inter", + "day", + "E70", + 1970 + ], + [ + "utopia", + 2000, + "summer", + "night", + "RHO", + 2000 + ], + [ + "utopia", + 1990, + "inter", + "day", + "TXG", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "night", + "SRE", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E21", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E70", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E70", + 1990 + ], + [ + "utopia", + 1990, + "summer", + "day", + "SRE", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "night", + "RHO", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E01", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "night", + "RL1", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "night", + "RHE", + 2000 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E21", + 1990 + ], + [ + "utopia", + 1990, + "summer", + "day", + "RHO", + 1980 + ], + [ + "utopia", + 1990, + "summer", + "day", + "RHE", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXD", + 2000 + ], + [ + "utopia", + 2000, + "summer", + "night", + "TXD", + 2000 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E70", + 1980 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E70", + 1970 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E31", + 2010 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E70", + 2010 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E70", + 1970 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E70", + 1970 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E70", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "night", + "TXG", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXG", + 2000 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E21", + 1990 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E01", + 1960 + ], + [ + "utopia", + 1990, + "winter", + "day", + "E01", + 1980 + ], + [ + "utopia", + 1990, + "winter", + "night", + "TXG", + 1980 + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXD", + 1970 + ], + [ + "utopia", + 2010, + "inter", + "night", + "SRE", + 2000 + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXG", + 1990 + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXD", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "night", + "RHE", + 2010 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E70", + 1960 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E70", + 1970 + ], + [ + "utopia", + 1990, + "winter", + "day", + "RL1", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "night", + "RHO", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E01", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "day", + "RHO", + 2010 + ], + [ + "utopia", + 2010, + "summer", + "day", + "RHO", + 2010 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E70", + 2010 + ], + [ + "utopia", + 1990, + "winter", + "day", + "TXD", + 1970 + ], + [ + "utopia", + 2010, + "inter", + "night", + "RL1", + 2010 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E31", + 1980 + ], + [ + "utopia", + 2010, + "winter", + "day", + "SRE", + 2000 + ], + [ + "utopia", + 2000, + "inter", + "night", + "SRE", + 2000 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E01", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "night", + "TXD", + 2000 + ], + [ + "utopia", + 1990, + "summer", + "night", + "RHO", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "day", + "RHO", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "night", + "SRE", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "night", + "RHO", + 1990 + ], + [ + "utopia", + 1990, + "inter", + "day", + "E70", + 1960 + ], + [ + "utopia", + 2000, + "summer", + "night", + "RHO", + 1990 + ], + [ + "utopia", + 1990, + "winter", + "day", + "E31", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "day", + "RL1", + 2010 + ], + [ + "utopia", + 1990, + "inter", + "day", + "TXG", + 1970 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E01", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E21", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E01", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E21", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E70", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E70", + 1980 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E31", + 2000 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E01", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E01", + 2000 + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXG", + 1990 + ], + [ + "utopia", + 1990, + "summer", + "day", + "E01", + 1990 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E70", + 1960 + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXG", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "night", + "RHE", + 1990 + ], + [ + "utopia", + 1990, + "summer", + "day", + "RHO", + 1970 + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXD", + 1990 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E70", + 1970 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E31", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E70", + 2000 + ], + [ + "utopia", + 2000, + "inter", + "night", + "RL1", + 2000 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E70", + 1980 + ], + [ + "utopia", + 2010, + "winter", + "night", + "TXE", + 2010 + ], + [ + "utopia", + 1990, + "summer", + "day", + "RL1", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXG", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E21", + 2000 + ], + [ + "utopia", + 1990, + "winter", + "day", + "E01", + 1970 + ], + [ + "utopia", + 1990, + "winter", + "night", + "TXG", + 1970 + ], + [ + "utopia", + 2010, + "inter", + "night", + "SRE", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "day", + "SRE", + 2010 + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXG", + 1980 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E01", + 2010 + ], + [ + "utopia", + 2010, + "summer", + "day", + "SRE", + 2010 + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXD", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E01", + 2000 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E01", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E31", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "day", + "RHO", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E21", + 2010 + ], + [ + "utopia", + 2010, + "summer", + "day", + "RHO", + 2000 + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXE", + 2000 + ], + [ + "utopia", + 2000, + "inter", + "night", + "SRE", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E01", + 1980 + ], + [ + "utopia", + 1990, + "summer", + "night", + "RHO", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "day", + "TXD", + 2010 + ], + [ + "utopia", + 1990, + "summer", + "night", + "TXD", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "night", + "RHO", + 1980 + ], + [ + "utopia", + 1990, + "winter", + "day", + "E31", + 1980 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E01", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E01", + 1990 + ], + [ + "utopia", + 1990, + "winter", + "day", + "TXE", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "night", + "RL1", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E31", + 2010 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E31", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "TXE", + 2000 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E01", + 1970 + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXG", + 1980 + ], + [ + "utopia", + 1990, + "summer", + "day", + "E01", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "night", + "TXG", + 2010 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E70", + 1960 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E31", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E70", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E31", + 2010 + ], + [ + "utopia", + 2010, + "winter", + "night", + "TXE", + 2000 + ], + [ + "utopia", + 1990, + "summer", + "day", + "RL1", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E21", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXG", + 1980 + ], + [ + "utopia", + 1990, + "summer", + "night", + "SRE", + 1990 + ], + [ + "utopia", + 1990, + "winter", + "day", + "E01", + 1960 + ], + [ + "utopia", + 2010, + "inter", + "day", + "SRE", + 2000 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E01", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E01", + 1990 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E01", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E01", + 1970 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E31", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "day", + "RHO", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "day", + "RL1", + 2010 + ], + [ + "utopia", + 1990, + "summer", + "day", + "E31", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E31", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXE", + 1990 + ], + [ + "utopia", + 1990, + "summer", + "night", + "TXD", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "night", + "RHO", + 2010 + ], + [ + "utopia", + 1990, + "summer", + "night", + "RL1", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E01", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E01", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E31", + 2000 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E31", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "night", + "TXE", + 2010 + ], + [ + "utopia", + 2000, + "winter", + "night", + "RHE", + 2000 + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXG", + 1970 + ], + [ + "utopia", + 1990, + "summer", + "day", + "E01", + 1970 + ], + [ + "utopia", + 2010, + "summer", + "night", + "TXG", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E01", + 2010 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E01", + 2010 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E31", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E70", + 1980 + ], + [ + "utopia", + 1990, + "winter", + "day", + "RHE", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E31", + 2000 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E31", + 2000 + ] + ], + "CapacityFactor_rpsdt": [ + [ + "utopia", + 2000, + "inter", + "day", + "RL1" + ], + [ + "utopia", + 2010, + "winter", + "day", + "E51" + ], + [ + "utopia", + 2000, + "winter", + "night", + "E01" + ], + [ + "utopia", + 2000, + "winter", + "night", + "E51" + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXG" + ], + [ + "utopia", + 2010, + "winter", + "night", + "TXG" + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXD" + ], + [ + "utopia", + 1990, + "winter", + "night", + "TXE" + ], + [ + "utopia", + 2010, + "winter", + "night", + "TXD" + ], + [ + "utopia", + 2010, + "winter", + "day", + "TXG" + ], + [ + "utopia", + 1990, + "winter", + "day", + "RL1" + ], + [ + "utopia", + 2000, + "summer", + "day", + "E31" + ], + [ + "utopia", + 2010, + "winter", + "night", + "E31" + ], + [ + "utopia", + 2000, + "summer", + "day", + "E21" + ], + [ + "utopia", + 2010, + "summer", + "night", + "E70" + ], + [ + "utopia", + 2010, + "winter", + "day", + "SRE" + ], + [ + "utopia", + 2010, + "winter", + "night", + "E21" + ], + [ + "utopia", + 2000, + "winter", + "night", + "SRE" + ], + [ + "utopia", + 2010, + "summer", + "day", + "E70" + ], + [ + "utopia", + 1990, + "inter", + "night", + "E70" + ], + [ + "utopia", + 2000, + "winter", + "day", + "RHO" + ], + [ + "utopia", + 1990, + "summer", + "night", + "E01" + ], + [ + "utopia", + 2000, + "summer", + "night", + "E70" + ], + [ + "utopia", + 1990, + "inter", + "day", + "E70" + ], + [ + "utopia", + 1990, + "summer", + "day", + "E01" + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXE" + ], + [ + "utopia", + 2000, + "winter", + "day", + "RL1" + ], + [ + "utopia", + 1990, + "summer", + "day", + "E51" + ], + [ + "utopia", + 2010, + "inter", + "night", + "RHO" + ], + [ + "utopia", + 2010, + "summer", + "night", + "RHE" + ], + [ + "utopia", + 1990, + "summer", + "night", + "SRE" + ], + [ + "utopia", + 1990, + "summer", + "night", + "RHO" + ], + [ + "utopia", + 2010, + "inter", + "day", + "E70" + ], + [ + "utopia", + 2010, + "summer", + "day", + "RHE" + ], + [ + "utopia", + 1990, + "inter", + "night", + "RHE" + ], + [ + "utopia", + 2010, + "inter", + "night", + "RL1" + ], + [ + "utopia", + 2000, + "inter", + "night", + "E70" + ], + [ + "utopia", + 1990, + "summer", + "day", + "SRE" + ], + [ + "utopia", + 2000, + "summer", + "night", + "RHE" + ], + [ + "utopia", + 1990, + "inter", + "night", + "E51" + ], + [ + "utopia", + 1990, + "inter", + "day", + "RHE" + ], + [ + "utopia", + 1990, + "summer", + "night", + "RL1" + ], + [ + "utopia", + 2010, + "summer", + "night", + "TXG" + ], + [ + "utopia", + 2010, + "summer", + "night", + "TXD" + ], + [ + "utopia", + 1990, + "summer", + "night", + "TXE" + ], + [ + "utopia", + 2000, + "inter", + "day", + "E70" + ], + [ + "utopia", + 2000, + "summer", + "day", + "E01" + ], + [ + "utopia", + 2010, + "winter", + "night", + "E01" + ], + [ + "utopia", + 2000, + "summer", + "night", + "E51" + ], + [ + "utopia", + 1990, + "winter", + "night", + "RHO" + ], + [ + "utopia", + 2010, + "winter", + "day", + "E01" + ], + [ + "utopia", + 2000, + "summer", + "day", + "E51" + ], + [ + "utopia", + 2010, + "winter", + "night", + "E51" + ], + [ + "utopia", + 2010, + "summer", + "night", + "E31" + ], + [ + "utopia", + 2010, + "summer", + "night", + "E21" + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXE" + ], + [ + "utopia", + 2010, + "summer", + "day", + "TXD" + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXG" + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXD" + ], + [ + "utopia", + 2010, + "inter", + "day", + "RHE" + ], + [ + "utopia", + 1990, + "winter", + "day", + "E70" + ], + [ + "utopia", + 2000, + "summer", + "night", + "TXG" + ], + [ + "utopia", + 2000, + "summer", + "night", + "TXD" + ], + [ + "utopia", + 2010, + "summer", + "day", + "E21" + ], + [ + "utopia", + 2010, + "summer", + "day", + "E31" + ], + [ + "utopia", + 1990, + "inter", + "night", + "E31" + ], + [ + "utopia", + 1990, + "inter", + "night", + "E21" + ], + [ + "utopia", + 2000, + "inter", + "night", + "RHE" + ], + [ + "utopia", + 1990, + "winter", + "night", + "RL1" + ], + [ + "utopia", + 1990, + "inter", + "day", + "TXG" + ], + [ + "utopia", + 1990, + "inter", + "day", + "TXD" + ], + [ + "utopia", + 2000, + "summer", + "night", + "E31" + ], + [ + "utopia", + 2000, + "summer", + "night", + "E21" + ], + [ + "utopia", + 2000, + "summer", + "day", + "SRE" + ], + [ + "utopia", + 2010, + "winter", + "night", + "SRE" + ], + [ + "utopia", + 1990, + "inter", + "day", + "E31" + ], + [ + "utopia", + 1990, + "inter", + "day", + "E21" + ], + [ + "utopia", + 2000, + "inter", + "night", + "E51" + ], + [ + "utopia", + 2000, + "inter", + "day", + "RHE" + ], + [ + "utopia", + 2010, + "winter", + "day", + "RHO" + ], + [ + "utopia", + 2000, + "winter", + "night", + "RHO" + ], + [ + "utopia", + 2010, + "inter", + "day", + "TXD" + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXG" + ], + [ + "utopia", + 2010, + "winter", + "night", + "TXE" + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXD" + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXE" + ], + [ + "utopia", + 1990, + "winter", + "day", + "RHE" + ], + [ + "utopia", + 2010, + "winter", + "day", + "RL1" + ], + [ + "utopia", + 2010, + "inter", + "day", + "E31" + ], + [ + "utopia", + 2010, + "winter", + "day", + "TXE" + ], + [ + "utopia", + 2000, + "winter", + "day", + "E70" + ], + [ + "utopia", + 2010, + "inter", + "day", + "E21" + ], + [ + "utopia", + 2000, + "inter", + "night", + "E31" + ], + [ + "utopia", + 2000, + "inter", + "night", + "E21" + ], + [ + "utopia", + 2000, + "winter", + "night", + "RL1" + ], + [ + "utopia", + 2000, + "inter", + "day", + "TXG" + ], + [ + "utopia", + 2000, + "inter", + "day", + "TXD" + ], + [ + "utopia", + 2000, + "inter", + "day", + "E31" + ], + [ + "utopia", + 2000, + "inter", + "day", + "E21" + ], + [ + "utopia", + 2010, + "inter", + "night", + "E70" + ], + [ + "utopia", + 2010, + "summer", + "night", + "E01" + ], + [ + "utopia", + 1990, + "winter", + "day", + "TXG" + ], + [ + "utopia", + 2010, + "summer", + "night", + "E51" + ], + [ + "utopia", + 1990, + "winter", + "day", + "TXD" + ], + [ + "utopia", + 1990, + "summer", + "night", + "E70" + ], + [ + "utopia", + 1990, + "inter", + "night", + "E01" + ], + [ + "utopia", + 1990, + "winter", + "day", + "E31" + ], + [ + "utopia", + 1990, + "winter", + "day", + "E21" + ], + [ + "utopia", + 1990, + "summer", + "day", + "RHO" + ], + [ + "utopia", + 2000, + "winter", + "day", + "RHE" + ], + [ + "utopia", + 2010, + "summer", + "day", + "E51" + ], + [ + "utopia", + 2000, + "summer", + "night", + "E01" + ], + [ + "utopia", + 1990, + "inter", + "day", + "E01" + ], + [ + "utopia", + 2010, + "summer", + "night", + "SRE" + ], + [ + "utopia", + 1990, + "inter", + "day", + "E51" + ], + [ + "utopia", + 1990, + "summer", + "day", + "RL1" + ], + [ + "utopia", + 2010, + "inter", + "night", + "RHE" + ], + [ + "utopia", + 2010, + "summer", + "day", + "TXG" + ], + [ + "utopia", + 1990, + "winter", + "night", + "E70" + ], + [ + "utopia", + 2010, + "summer", + "day", + "SRE" + ], + [ + "utopia", + 1990, + "inter", + "night", + "SRE" + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXG" + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXD" + ], + [ + "utopia", + 2010, + "summer", + "night", + "TXE" + ], + [ + "utopia", + 2000, + "summer", + "night", + "SRE" + ], + [ + "utopia", + 2010, + "inter", + "day", + "E51" + ], + [ + "utopia", + 2000, + "inter", + "night", + "E01" + ], + [ + "utopia", + 2000, + "winter", + "day", + "E31" + ], + [ + "utopia", + 2000, + "winter", + "day", + "E21" + ], + [ + "utopia", + 2000, + "summer", + "day", + "RHO" + ], + [ + "utopia", + 1990, + "inter", + "day", + "SRE" + ], + [ + "utopia", + 2010, + "winter", + "night", + "RHO" + ], + [ + "utopia", + 1990, + "inter", + "night", + "RL1" + ], + [ + "utopia", + 2010, + "inter", + "night", + "TXG" + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXE" + ], + [ + "utopia", + 2010, + "inter", + "night", + "TXD" + ], + [ + "utopia", + 2000, + "inter", + "day", + "E01" + ], + [ + "utopia", + 2010, + "inter", + "day", + "TXG" + ], + [ + "utopia", + 2010, + "winter", + "day", + "E70" + ], + [ + "utopia", + 2000, + "summer", + "night", + "TXE" + ], + [ + "utopia", + 2000, + "inter", + "day", + "E51" + ], + [ + "utopia", + 1990, + "winter", + "night", + "RHE" + ], + [ + "utopia", + 2000, + "summer", + "day", + "RL1" + ], + [ + "utopia", + 2010, + "winter", + "night", + "RL1" + ], + [ + "utopia", + 2010, + "inter", + "night", + "E31" + ], + [ + "utopia", + 2010, + "inter", + "night", + "E21" + ], + [ + "utopia", + 1990, + "inter", + "day", + "TXE" + ], + [ + "utopia", + 2000, + "winter", + "night", + "E70" + ], + [ + "utopia", + 2010, + "inter", + "day", + "SRE" + ], + [ + "utopia", + 2000, + "inter", + "night", + "SRE" + ], + [ + "utopia", + 1990, + "winter", + "day", + "E01" + ], + [ + "utopia", + 1990, + "summer", + "night", + "E31" + ], + [ + "utopia", + 1990, + "winter", + "day", + "E51" + ], + [ + "utopia", + 2000, + "inter", + "day", + "SRE" + ], + [ + "utopia", + 1990, + "winter", + "night", + "TXG" + ], + [ + "utopia", + 2000, + "inter", + "night", + "RL1" + ], + [ + "utopia", + 1990, + "winter", + "night", + "TXD" + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXE" + ], + [ + "utopia", + 2010, + "winter", + "day", + "RHE" + ], + [ + "utopia", + 1990, + "winter", + "night", + "E31" + ], + [ + "utopia", + 1990, + "winter", + "night", + "E21" + ], + [ + "utopia", + 1990, + "winter", + "day", + "SRE" + ], + [ + "utopia", + 2010, + "summer", + "day", + "E01" + ], + [ + "utopia", + 2000, + "winter", + "night", + "RHE" + ], + [ + "utopia", + 2000, + "inter", + "day", + "TXE" + ], + [ + "utopia", + 2000, + "winter", + "day", + "E01" + ], + [ + "utopia", + 1990, + "summer", + "day", + "E70" + ], + [ + "utopia", + 2000, + "winter", + "day", + "E51" + ], + [ + "utopia", + 2010, + "summer", + "night", + "RHO" + ], + [ + "utopia", + 1990, + "winter", + "day", + "TXE" + ], + [ + "utopia", + 2010, + "winter", + "day", + "TXD" + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXG" + ], + [ + "utopia", + 2010, + "inter", + "night", + "E01" + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXD" + ], + [ + "utopia", + 2010, + "winter", + "day", + "E31" + ], + [ + "utopia", + 2010, + "winter", + "day", + "E21" + ], + [ + "utopia", + 2010, + "summer", + "day", + "RHO" + ], + [ + "utopia", + 1990, + "inter", + "night", + "RHO" + ], + [ + "utopia", + 2010, + "inter", + "day", + "E01" + ], + [ + "utopia", + 1990, + "summer", + "night", + "RHE" + ], + [ + "utopia", + 2010, + "inter", + "night", + "E51" + ], + [ + "utopia", + 2010, + "summer", + "night", + "RL1" + ], + [ + "utopia", + 2000, + "winter", + "night", + "E31" + ], + [ + "utopia", + 2000, + "winter", + "night", + "E21" + ], + [ + "utopia", + 2000, + "summer", + "night", + "RHO" + ], + [ + "utopia", + 2000, + "winter", + "day", + "SRE" + ], + [ + "utopia", + 1990, + "inter", + "day", + "RHO" + ], + [ + "utopia", + 1990, + "summer", + "night", + "E51" + ], + [ + "utopia", + 1990, + "summer", + "day", + "RHE" + ], + [ + "utopia", + 2010, + "summer", + "day", + "RL1" + ], + [ + "utopia", + 2010, + "summer", + "day", + "TXE" + ], + [ + "utopia", + 2000, + "summer", + "day", + "E70" + ], + [ + "utopia", + 2010, + "winter", + "night", + "E70" + ], + [ + "utopia", + 2000, + "summer", + "night", + "RL1" + ], + [ + "utopia", + 2010, + "inter", + "night", + "SRE" + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXE" + ], + [ + "utopia", + 1990, + "summer", + "night", + "TXG" + ], + [ + "utopia", + 1990, + "inter", + "day", + "RL1" + ], + [ + "utopia", + 1990, + "summer", + "night", + "TXD" + ], + [ + "utopia", + 2010, + "inter", + "day", + "RHO" + ], + [ + "utopia", + 1990, + "winter", + "night", + "E01" + ], + [ + "utopia", + 2000, + "inter", + "night", + "RHO" + ], + [ + "utopia", + 1990, + "winter", + "night", + "E51" + ], + [ + "utopia", + 1990, + "summer", + "night", + "E21" + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXG" + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXD" + ], + [ + "utopia", + 2010, + "inter", + "night", + "TXE" + ], + [ + "utopia", + 2010, + "inter", + "day", + "RL1" + ], + [ + "utopia", + 2010, + "inter", + "day", + "TXE" + ], + [ + "utopia", + 2000, + "inter", + "day", + "RHO" + ], + [ + "utopia", + 1990, + "summer", + "day", + "E31" + ], + [ + "utopia", + 1990, + "summer", + "day", + "E21" + ], + [ + "utopia", + 2000, + "summer", + "day", + "RHE" + ], + [ + "utopia", + 2010, + "winter", + "night", + "RHE" + ], + [ + "utopia", + 1990, + "winter", + "night", + "SRE" + ], + [ + "utopia", + 1990, + "winter", + "day", + "RHO" + ] + ], + "CapacityVar_rptv": [ + [ + "utopia", + 2000, + "RL1", + 2000 + ], + [ + "utopia", + 2000, + "E21", + 2000 + ], + [ + "utopia", + 2000, + "TXE", + 1990 + ], + [ + "utopia", + 1990, + "RL1", + 1980 + ], + [ + "utopia", + 1990, + "RHO", + 1990 + ], + [ + "utopia", + 1990, + "TXG", + 1980 + ], + [ + "utopia", + 2010, + "E01", + 1980 + ], + [ + "utopia", + 2010, + "E51", + 1980 + ], + [ + "utopia", + 2000, + "TXG", + 1990 + ], + [ + "utopia", + 2010, + "TXG", + 2000 + ], + [ + "utopia", + 1990, + "E70", + 1960 + ], + [ + "utopia", + 2010, + "E21", + 1990 + ], + [ + "utopia", + 1990, + "RHE", + 1990 + ], + [ + "utopia", + 2010, + "RHE", + 2010 + ], + [ + "utopia", + 2000, + "E31", + 2000 + ], + [ + "utopia", + 2010, + "SRE", + 1990 + ], + [ + "utopia", + 2000, + "RHE", + 1990 + ], + [ + "utopia", + 1990, + "E01", + 1980 + ], + [ + "utopia", + 2000, + "E70", + 1970 + ], + [ + "utopia", + 1990, + "E51", + 1980 + ], + [ + "utopia", + 2010, + "E01", + 2000 + ], + [ + "utopia", + 2010, + "E51", + 2000 + ], + [ + "utopia", + 2010, + "RHO", + 1990 + ], + [ + "utopia", + 2010, + "TXD", + 2000 + ], + [ + "utopia", + 2000, + "E70", + 2000 + ], + [ + "utopia", + 2010, + "E31", + 1990 + ], + [ + "utopia", + 2000, + "SRE", + 2000 + ], + [ + "utopia", + 1990, + "TXD", + 1970 + ], + [ + "utopia", + 2010, + "TXE", + 2000 + ], + [ + "utopia", + 2000, + "TXD", + 1980 + ], + [ + "utopia", + 2000, + "RHO", + 2000 + ], + [ + "utopia", + 2010, + "RHO", + 2010 + ], + [ + "utopia", + 1990, + "E31", + 1990 + ], + [ + "utopia", + 1990, + "RHO", + 1980 + ], + [ + "utopia", + 2010, + "E70", + 1990 + ], + [ + "utopia", + 2010, + "E31", + 2010 + ], + [ + "utopia", + 1990, + "TXG", + 1970 + ], + [ + "utopia", + 2000, + "TXG", + 1980 + ], + [ + "utopia", + 2010, + "RHE", + 2000 + ], + [ + "utopia", + 2000, + "E31", + 1990 + ], + [ + "utopia", + 2010, + "E70", + 2010 + ], + [ + "utopia", + 1990, + "E21", + 1990 + ], + [ + "utopia", + 1990, + "E70", + 1980 + ], + [ + "utopia", + 2010, + "E21", + 2010 + ], + [ + "utopia", + 1990, + "E01", + 1970 + ], + [ + "utopia", + 2000, + "E01", + 1980 + ], + [ + "utopia", + 2010, + "E01", + 1990 + ], + [ + "utopia", + 2000, + "E51", + 1980 + ], + [ + "utopia", + 2010, + "E51", + 1990 + ], + [ + "utopia", + 2000, + "TXG", + 2000 + ], + [ + "utopia", + 1990, + "SRE", + 1990 + ], + [ + "utopia", + 2010, + "SRE", + 2010 + ], + [ + "utopia", + 2000, + "E70", + 1990 + ], + [ + "utopia", + 2010, + "E31", + 1980 + ], + [ + "utopia", + 2000, + "E21", + 1990 + ], + [ + "utopia", + 2000, + "SRE", + 1990 + ], + [ + "utopia", + 2000, + "E01", + 2000 + ], + [ + "utopia", + 2000, + "E51", + 2000 + ], + [ + "utopia", + 1990, + "TXD", + 1990 + ], + [ + "utopia", + 2000, + "RHO", + 1990 + ], + [ + "utopia", + 2000, + "TXD", + 2000 + ], + [ + "utopia", + 2010, + "TXD", + 2010 + ], + [ + "utopia", + 1990, + "E31", + 1980 + ], + [ + "utopia", + 1990, + "RHO", + 1970 + ], + [ + "utopia", + 2010, + "E70", + 1980 + ], + [ + "utopia", + 2010, + "E31", + 2000 + ], + [ + "utopia", + 1990, + "TXE", + 1990 + ], + [ + "utopia", + 2000, + "TXE", + 2000 + ], + [ + "utopia", + 2010, + "TXE", + 2010 + ], + [ + "utopia", + 1990, + "RL1", + 1990 + ], + [ + "utopia", + 2010, + "RL1", + 2010 + ], + [ + "utopia", + 2010, + "RHE", + 1990 + ], + [ + "utopia", + 2000, + "E31", + 1980 + ], + [ + "utopia", + 1990, + "TXG", + 1990 + ], + [ + "utopia", + 2010, + "E70", + 2000 + ], + [ + "utopia", + 2010, + "TXG", + 2010 + ], + [ + "utopia", + 1990, + "E70", + 1970 + ], + [ + "utopia", + 2010, + "E21", + 2000 + ], + [ + "utopia", + 1990, + "E01", + 1960 + ], + [ + "utopia", + 2000, + "E01", + 1970 + ], + [ + "utopia", + 2010, + "SRE", + 2000 + ], + [ + "utopia", + 2000, + "RHE", + 2000 + ], + [ + "utopia", + 1990, + "E01", + 1990 + ], + [ + "utopia", + 2000, + "E70", + 1980 + ], + [ + "utopia", + 1990, + "E51", + 1990 + ], + [ + "utopia", + 2010, + "E01", + 2010 + ], + [ + "utopia", + 2010, + "E51", + 2010 + ], + [ + "utopia", + 1990, + "E70", + 1990 + ], + [ + "utopia", + 2010, + "RHO", + 2000 + ], + [ + "utopia", + 2000, + "E01", + 1990 + ], + [ + "utopia", + 2000, + "E51", + 1990 + ], + [ + "utopia", + 1990, + "TXD", + 1980 + ], + [ + "utopia", + 2000, + "RHO", + 1980 + ], + [ + "utopia", + 2000, + "TXD", + 1990 + ] + ], + "CommodityBalanceConstraint_rpsdc": [ + [ + "utopia", + 2010, + "inter", + "night", + "HYD" + ], + [ + "utopia", + 1990, + "inter", + "night", + "HCO" + ], + [ + "utopia", + 2000, + "inter", + "day", + "FEQ" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "OIL" + ], + [ + "utopia", + 2000, + "summer", + "night", + "HCO" + ], + [ + "utopia", + 1990, + "summer", + "night", + "HYD" + ], + [ + "utopia", + 1990, + "inter", + "day", + "HCO" + ], + [ + "utopia", + 1990, + "winter", + "night", + "FEQ" + ], + [ + "utopia", + 2010, + "summer", + "day", + "URN" + ], + [ + "utopia", + 2000, + "winter", + "day", + "OIL" + ], + [ + "utopia", + 1990, + "winter", + "day", + "FEQ" + ], + [ + "utopia", + 2000, + "winter", + "night", + "DSL" + ], + [ + "utopia", + 2000, + "winter", + "day", + "URN" + ], + [ + "utopia", + 1990, + "inter", + "day", + "URN" + ], + [ + "utopia", + 2000, + "winter", + "day", + "GSL" + ], + [ + "utopia", + 2010, + "inter", + "night", + "OIL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "OIL" + ], + [ + "utopia", + 2000, + "inter", + "night", + "HCO" + ], + [ + "utopia", + 1990, + "winter", + "night", + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "DSL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "URN" + ], + [ + "utopia", + 2010, + "inter", + "night", + "GSL" + ], + [ + "utopia", + 2000, + "inter", + "day", + "HCO" + ], + [ + "utopia", + 2000, + "winter", + "night", + "FEQ" + ], + [ + "utopia", + 1990, + "summer", + "night", + "DSL" + ], + [ + "utopia", + 2000, + "winter", + "day", + "FEQ" + ], + [ + "utopia", + 1990, + "summer", + "night", + "GSL" + ], + [ + "utopia", + 2010, + "winter", + "day", + "HYD" + ], + [ + "utopia", + 2000, + "inter", + "day", + "URN" + ], + [ + "utopia", + 1990, + "winter", + "day", + "HCO" + ], + [ + "utopia", + 1990, + "summer", + "day", + "DSL" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "OIL" + ], + [ + "utopia", + 2010, + "inter", + "night", + "FEQ" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "URN" + ], + [ + "utopia", + 1990, + "winter", + "night", + "GSL" + ], + [ + "utopia", + 1990, + "summer", + "night", + "FEQ" + ], + [ + "utopia", + 2010, + "summer", + "day", + "HCO" + ], + [ + "utopia", + 2000, + "winter", + "day", + "HCO" + ], + [ + "utopia", + 2000, + "summer", + "day", + "DSL" + ], + [ + "utopia", + 2000, + "winter", + "night", + "OIL" + ], + [ + "utopia", + 1990, + "summer", + "night", + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "DSL" + ], + [ + "utopia", + 2010, + "winter", + "day", + "GSL" + ], + [ + "utopia", + 1990, + "summer", + "day", + "HYD" + ], + [ + "utopia", + 2000, + "winter", + "night", + "URN" + ], + [ + "utopia", + 2000, + "winter", + "night", + "GSL" + ], + [ + "utopia", + 1990, + "summer", + "day", + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "HCO" + ], + [ + "utopia", + 2010, + "inter", + "day", + "HCO" + ], + [ + "utopia", + 2010, + "inter", + "night", + "URN" + ], + [ + "utopia", + 2010, + "winter", + "day", + "FEQ" + ], + [ + "utopia", + 1990, + "summer", + "night", + "OIL" + ], + [ + "utopia", + 1990, + "inter", + "night", + "HYD" + ], + [ + "utopia", + 2000, + "summer", + "night", + "HYD" + ], + [ + "utopia", + 1990, + "summer", + "night", + "URN" + ], + [ + "utopia", + 1990, + "summer", + "day", + "OIL" + ], + [ + "utopia", + 2000, + "summer", + "day", + "HYD" + ], + [ + "utopia", + 2010, + "winter", + "night", + "HYD" + ], + [ + "utopia", + 1990, + "winter", + "night", + "HCO" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "day", + "URN" + ], + [ + "utopia", + 1990, + "summer", + "day", + "GSL" + ], + [ + "utopia", + 2010, + "summer", + "night", + "DSL" + ], + [ + "utopia", + 2000, + "inter", + "night", + "HYD" + ], + [ + "utopia", + 2000, + "summer", + "day", + "OIL" + ], + [ + "utopia", + 2010, + "winter", + "night", + "OIL" + ], + [ + "utopia", + 1990, + "inter", + "night", + "DSL" + ], + [ + "utopia", + 1990, + "summer", + "day", + "FEQ" + ], + [ + "utopia", + 1990, + "inter", + "night", + "GSL" + ], + [ + "utopia", + 2010, + "winter", + "day", + "OIL" + ], + [ + "utopia", + 2000, + "winter", + "night", + "HCO" + ], + [ + "utopia", + 2000, + "summer", + "night", + "DSL" + ], + [ + "utopia", + 2000, + "summer", + "day", + "URN" + ], + [ + "utopia", + 2000, + "summer", + "night", + "GSL" + ], + [ + "utopia", + 2010, + "winter", + "night", + "DSL" + ], + [ + "utopia", + 2000, + "summer", + "day", + "GSL" + ], + [ + "utopia", + 2010, + "winter", + "night", + "GSL" + ], + [ + "utopia", + 2010, + "winter", + "day", + "URN" + ], + [ + "utopia", + 1990, + "inter", + "night", + "FEQ" + ], + [ + "utopia", + 2010, + "summer", + "night", + "HYD" + ], + [ + "utopia", + 2000, + "summer", + "night", + "FEQ" + ], + [ + "utopia", + 2000, + "inter", + "night", + "DSL" + ], + [ + "utopia", + 1990, + "summer", + "night", + "HCO" + ], + [ + "utopia", + 2000, + "inter", + "night", + "GSL" + ], + [ + "utopia", + 2010, + "winter", + "night", + "FEQ" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "FEQ" + ], + [ + "utopia", + 2010, + "summer", + "day", + "HYD" + ], + [ + "utopia", + 1990, + "summer", + "day", + "HCO" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "HYD" + ], + [ + "utopia", + 2000, + "summer", + "night", + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "DSL" + ], + [ + "utopia", + 2000, + "inter", + "night", + "FEQ" + ], + [ + "utopia", + 2010, + "summer", + "night", + "OIL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "HYD" + ], + [ + "utopia", + 2010, + "summer", + "night", + "URN" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "OIL" + ], + [ + "utopia", + 2010, + "summer", + "night", + "GSL" + ], + [ + "utopia", + 2000, + "summer", + "day", + "HCO" + ], + [ + "utopia", + 2010, + "winter", + "night", + "HCO" + ], + [ + "utopia", + 2000, + "summer", + "night", + "OIL" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "HCO" + ], + [ + "utopia", + 2010, + "summer", + "day", + "DSL" + ], + [ + "utopia", + 1990, + "inter", + "night", + "URN" + ], + [ + "utopia", + 1990, + "inter", + "day", + "OIL" + ], + [ + "utopia", + 2010, + "summer", + "day", + "GSL" + ], + [ + "utopia", + 2000, + "inter", + "day", + "HYD" + ], + [ + "utopia", + 2000, + "summer", + "night", + "URN" + ], + [ + "utopia", + 2000, + "winter", + "day", + "DSL" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "URN" + ], + [ + "utopia", + 1990, + "inter", + "day", + "DSL" + ], + [ + "utopia", + 1990, + "winter", + "night", + "HYD" + ], + [ + "utopia", + 1990, + "inter", + "day", + "GSL" + ], + [ + "utopia", + 2010, + "summer", + "night", + "FEQ" + ], + [ + "utopia", + 1990, + "winter", + "day", + "HYD" + ], + [ + "utopia", + 1990, + "winter", + "day", + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "OIL" + ], + [ + "utopia", + 2010, + "summer", + "day", + "FEQ" + ], + [ + "utopia", + 2010, + "inter", + "day", + "DSL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "GSL" + ], + [ + "utopia", + 2000, + "inter", + "night", + "URN" + ], + [ + "utopia", + 2000, + "inter", + "day", + "OIL" + ], + [ + "utopia", + 1990, + "inter", + "day", + "FEQ" + ], + [ + "utopia", + 2000, + "inter", + "day", + "DSL" + ], + [ + "utopia", + 2000, + "winter", + "night", + "HYD" + ], + [ + "utopia", + 2000, + "inter", + "day", + "GSL" + ], + [ + "utopia", + 1990, + "winter", + "day", + "OIL" + ], + [ + "utopia", + 2000, + "winter", + "day", + "HYD" + ], + [ + "utopia", + 2010, + "inter", + "day", + "FEQ" + ], + [ + "utopia", + 2000, + "winter", + "day", + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "DSL" + ], + [ + "utopia", + 1990, + "winter", + "day", + "URN" + ], + [ + "utopia", + 2010, + "summer", + "night", + "HCO" + ], + [ + "utopia", + 1990, + "winter", + "day", + "GSL" + ] + ], + "CostEmission_rpe": [], + "CostFixed_rptv": [ + [ + "utopia", + 2000, + "RL1", + 2000 + ], + [ + "utopia", + 2000, + "E21", + 2000 + ], + [ + "utopia", + 2000, + "TXE", + 1990 + ], + [ + "utopia", + 1990, + "RL1", + 1980 + ], + [ + "utopia", + 1990, + "RHO", + 1990 + ], + [ + "utopia", + 1990, + "TXG", + 1980 + ], + [ + "utopia", + 2010, + "E01", + 1980 + ], + [ + "utopia", + 2010, + "E51", + 1980 + ], + [ + "utopia", + 2000, + "TXG", + 1990 + ], + [ + "utopia", + 2010, + "TXG", + 2000 + ], + [ + "utopia", + 1990, + "E70", + 1960 + ], + [ + "utopia", + 2010, + "E21", + 1990 + ], + [ + "utopia", + 1990, + "RHE", + 1990 + ], + [ + "utopia", + 2010, + "RHE", + 2010 + ], + [ + "utopia", + 2000, + "E31", + 2000 + ], + [ + "utopia", + 2010, + "SRE", + 1990 + ], + [ + "utopia", + 2000, + "RHE", + 1990 + ], + [ + "utopia", + 1990, + "E01", + 1980 + ], + [ + "utopia", + 2000, + "E70", + 1970 + ], + [ + "utopia", + 1990, + "E51", + 1980 + ], + [ + "utopia", + 2010, + "E01", + 2000 + ], + [ + "utopia", + 2010, + "E51", + 2000 + ], + [ + "utopia", + 2010, + "RHO", + 1990 + ], + [ + "utopia", + 2010, + "TXD", + 2000 + ], + [ + "utopia", + 2000, + "E70", + 2000 + ], + [ + "utopia", + 2010, + "E31", + 1990 + ], + [ + "utopia", + 2000, + "SRE", + 2000 + ], + [ + "utopia", + 1990, + "TXD", + 1970 + ], + [ + "utopia", + 2010, + "TXE", + 2000 + ], + [ + "utopia", + 2000, + "TXD", + 1980 + ], + [ + "utopia", + 2000, + "RHO", + 2000 + ], + [ + "utopia", + 2010, + "RHO", + 2010 + ], + [ + "utopia", + 1990, + "E31", + 1990 + ], + [ + "utopia", + 1990, + "RHO", + 1980 + ], + [ + "utopia", + 2010, + "E70", + 1990 + ], + [ + "utopia", + 2010, + "E31", + 2010 + ], + [ + "utopia", + 1990, + "TXG", + 1970 + ], + [ + "utopia", + 2000, + "TXG", + 1980 + ], + [ + "utopia", + 2010, + "RHE", + 2000 + ], + [ + "utopia", + 2000, + "E31", + 1990 + ], + [ + "utopia", + 2010, + "E70", + 2010 + ], + [ + "utopia", + 1990, + "E21", + 1990 + ], + [ + "utopia", + 1990, + "E70", + 1980 + ], + [ + "utopia", + 2010, + "E21", + 2010 + ], + [ + "utopia", + 1990, + "E01", + 1970 + ], + [ + "utopia", + 2000, + "E01", + 1980 + ], + [ + "utopia", + 2010, + "E01", + 1990 + ], + [ + "utopia", + 2000, + "E51", + 1980 + ], + [ + "utopia", + 2010, + "E51", + 1990 + ], + [ + "utopia", + 2000, + "TXG", + 2000 + ], + [ + "utopia", + 1990, + "SRE", + 1990 + ], + [ + "utopia", + 2010, + "SRE", + 2010 + ], + [ + "utopia", + 2000, + "E70", + 1990 + ], + [ + "utopia", + 2010, + "E31", + 1980 + ], + [ + "utopia", + 2000, + "E21", + 1990 + ], + [ + "utopia", + 2000, + "SRE", + 1990 + ], + [ + "utopia", + 2000, + "E01", + 2000 + ], + [ + "utopia", + 2000, + "E51", + 2000 + ], + [ + "utopia", + 1990, + "TXD", + 1990 + ], + [ + "utopia", + 2000, + "RHO", + 1990 + ], + [ + "utopia", + 2000, + "TXD", + 2000 + ], + [ + "utopia", + 2010, + "TXD", + 2010 + ], + [ + "utopia", + 1990, + "E31", + 1980 + ], + [ + "utopia", + 1990, + "RHO", + 1970 + ], + [ + "utopia", + 2010, + "E70", + 1980 + ], + [ + "utopia", + 2010, + "E31", + 2000 + ], + [ + "utopia", + 1990, + "TXE", + 1990 + ], + [ + "utopia", + 2000, + "TXE", + 2000 + ], + [ + "utopia", + 2010, + "TXE", + 2010 + ], + [ + "utopia", + 1990, + "RL1", + 1990 + ], + [ + "utopia", + 2010, + "RL1", + 2010 + ], + [ + "utopia", + 2010, + "RHE", + 1990 + ], + [ + "utopia", + 2000, + "E31", + 1980 + ], + [ + "utopia", + 1990, + "TXG", + 1990 + ], + [ + "utopia", + 2010, + "E70", + 2000 + ], + [ + "utopia", + 2010, + "TXG", + 2010 + ], + [ + "utopia", + 1990, + "E70", + 1970 + ], + [ + "utopia", + 2010, + "E21", + 2000 + ], + [ + "utopia", + 1990, + "E01", + 1960 + ], + [ + "utopia", + 2000, + "E01", + 1970 + ], + [ + "utopia", + 2010, + "SRE", + 2000 + ], + [ + "utopia", + 2000, + "RHE", + 2000 + ], + [ + "utopia", + 1990, + "E01", + 1990 + ], + [ + "utopia", + 2000, + "E70", + 1980 + ], + [ + "utopia", + 1990, + "E51", + 1990 + ], + [ + "utopia", + 2010, + "E01", + 2010 + ], + [ + "utopia", + 2010, + "E51", + 2010 + ], + [ + "utopia", + 1990, + "E70", + 1990 + ], + [ + "utopia", + 2010, + "RHO", + 2000 + ], + [ + "utopia", + 2000, + "E01", + 1990 + ], + [ + "utopia", + 2000, + "E51", + 1990 + ], + [ + "utopia", + 1990, + "TXD", + 1980 + ], + [ + "utopia", + 2000, + "RHO", + 1980 + ], + [ + "utopia", + 2000, + "TXD", + 1990 + ] + ], + "CostInvest_rtv": [ + [ + "utopia", + "TXD", + 1990 + ], + [ + "utopia", + "RHO", + 2010 + ], + [ + "utopia", + "E21", + 2000 + ], + [ + "utopia", + "TXE", + 1990 + ], + [ + "utopia", + "E51", + 2010 + ], + [ + "utopia", + "E70", + 1990 + ], + [ + "utopia", + "SRE", + 2000 + ], + [ + "utopia", + "TXG", + 2000 + ], + [ + "utopia", + "E31", + 2010 + ], + [ + "utopia", + "RHO", + 2000 + ], + [ + "utopia", + "E21", + 1990 + ], + [ + "utopia", + "E01", + 2010 + ], + [ + "utopia", + "RHE", + 2010 + ], + [ + "utopia", + "TXD", + 2010 + ], + [ + "utopia", + "E51", + 2000 + ], + [ + "utopia", + "SRE", + 1990 + ], + [ + "utopia", + "TXG", + 1990 + ], + [ + "utopia", + "E31", + 2000 + ], + [ + "utopia", + "RHO", + 1990 + ], + [ + "utopia", + "TXE", + 2010 + ], + [ + "utopia", + "RHE", + 2000 + ], + [ + "utopia", + "E01", + 2000 + ], + [ + "utopia", + "E70", + 2010 + ], + [ + "utopia", + "E21", + 2010 + ], + [ + "utopia", + "TXD", + 2000 + ], + [ + "utopia", + "E51", + 1990 + ], + [ + "utopia", + "E31", + 1990 + ], + [ + "utopia", + "TXE", + 2000 + ], + [ + "utopia", + "RHE", + 1990 + ], + [ + "utopia", + "E01", + 1990 + ], + [ + "utopia", + "SRE", + 2010 + ], + [ + "utopia", + "TXG", + 2010 + ], + [ + "utopia", + "E70", + 2000 + ] + ], + "CostVariable_rptv": [ + [ + "utopia", + 2000, + "RL1", + 2000 + ], + [ + "utopia", + 2000, + "E21", + 2000 + ], + [ + "utopia", + 2000, + "TXE", + 1990 + ], + [ + "utopia", + 1990, + "RL1", + 1980 + ], + [ + "utopia", + 1990, + "RHO", + 1990 + ], + [ + "utopia", + 2000, + "IMPDSL1", + 1990 + ], + [ + "utopia", + 2010, + "IMPURN1", + 1990 + ], + [ + "utopia", + 1990, + "TXG", + 1980 + ], + [ + "utopia", + 2010, + "E01", + 1980 + ], + [ + "utopia", + 2010, + "E51", + 1980 + ], + [ + "utopia", + 2000, + "TXG", + 1990 + ], + [ + "utopia", + 2010, + "TXG", + 2000 + ], + [ + "utopia", + 1990, + "E70", + 1960 + ], + [ + "utopia", + 2010, + "E21", + 1990 + ], + [ + "utopia", + 1990, + "RHE", + 1990 + ], + [ + "utopia", + 2000, + "IMPHCO1", + 1990 + ], + [ + "utopia", + 2010, + "RHE", + 2010 + ], + [ + "utopia", + 2000, + "E31", + 2000 + ], + [ + "utopia", + 2010, + "SRE", + 1990 + ], + [ + "utopia", + 2000, + "RHE", + 1990 + ], + [ + "utopia", + 1990, + "E01", + 1980 + ], + [ + "utopia", + 2000, + "E70", + 1970 + ], + [ + "utopia", + 1990, + "E51", + 1980 + ], + [ + "utopia", + 2010, + "E01", + 2000 + ], + [ + "utopia", + 2010, + "E51", + 2000 + ], + [ + "utopia", + 2010, + "RHO", + 1990 + ], + [ + "utopia", + 2010, + "TXD", + 2000 + ], + [ + "utopia", + 2000, + "E70", + 2000 + ], + [ + "utopia", + 2000, + "IMPHYD", + 1990 + ], + [ + "utopia", + 2010, + "E31", + 1990 + ], + [ + "utopia", + 2000, + "SRE", + 2000 + ], + [ + "utopia", + 1990, + "TXD", + 1970 + ], + [ + "utopia", + 2010, + "TXE", + 2000 + ], + [ + "utopia", + 2000, + "TXD", + 1980 + ], + [ + "utopia", + 1990, + "IMPFEQ", + 1990 + ], + [ + "utopia", + 2000, + "IMPOIL1", + 1990 + ], + [ + "utopia", + 2010, + "IMPGSL1", + 1990 + ], + [ + "utopia", + 2000, + "RHO", + 2000 + ], + [ + "utopia", + 2010, + "RHO", + 2010 + ], + [ + "utopia", + 1990, + "E31", + 1990 + ], + [ + "utopia", + 1990, + "RHO", + 1980 + ], + [ + "utopia", + 2010, + "E70", + 1990 + ], + [ + "utopia", + 2010, + "E31", + 2010 + ], + [ + "utopia", + 1990, + "IMPGSL1", + 1990 + ], + [ + "utopia", + 1990, + "TXG", + 1970 + ], + [ + "utopia", + 2000, + "TXG", + 1980 + ], + [ + "utopia", + 1990, + "IMPDSL1", + 1990 + ], + [ + "utopia", + 2010, + "RHE", + 2000 + ], + [ + "utopia", + 2000, + "E31", + 1990 + ], + [ + "utopia", + 2010, + "E70", + 2010 + ], + [ + "utopia", + 2000, + "IMPURN1", + 1990 + ], + [ + "utopia", + 1990, + "E21", + 1990 + ], + [ + "utopia", + 2010, + "IMPFEQ", + 1990 + ], + [ + "utopia", + 1990, + "E70", + 1980 + ], + [ + "utopia", + 2010, + "E21", + 2010 + ], + [ + "utopia", + 1990, + "E01", + 1970 + ], + [ + "utopia", + 2000, + "E01", + 1980 + ], + [ + "utopia", + 2010, + "E01", + 1990 + ], + [ + "utopia", + 2000, + "E51", + 1980 + ], + [ + "utopia", + 2010, + "E51", + 1990 + ], + [ + "utopia", + 2000, + "TXG", + 2000 + ], + [ + "utopia", + 1990, + "SRE", + 1990 + ], + [ + "utopia", + 2010, + "SRE", + 2010 + ], + [ + "utopia", + 2000, + "E70", + 1990 + ], + [ + "utopia", + 2010, + "E31", + 1980 + ], + [ + "utopia", + 2000, + "E21", + 1990 + ], + [ + "utopia", + 2000, + "SRE", + 1990 + ], + [ + "utopia", + 2010, + "IMPOIL1", + 1990 + ], + [ + "utopia", + 2000, + "E01", + 2000 + ], + [ + "utopia", + 2010, + "IMPDSL1", + 1990 + ], + [ + "utopia", + 2000, + "E51", + 2000 + ], + [ + "utopia", + 1990, + "TXD", + 1990 + ], + [ + "utopia", + 2000, + "RHO", + 1990 + ], + [ + "utopia", + 2010, + "IMPHCO1", + 1990 + ], + [ + "utopia", + 2000, + "TXD", + 2000 + ], + [ + "utopia", + 2010, + "TXD", + 2010 + ], + [ + "utopia", + 1990, + "E31", + 1980 + ], + [ + "utopia", + 1990, + "RHO", + 1970 + ], + [ + "utopia", + 2010, + "E70", + 1980 + ], + [ + "utopia", + 2010, + "E31", + 2000 + ], + [ + "utopia", + 1990, + "TXE", + 1990 + ], + [ + "utopia", + 2000, + "TXE", + 2000 + ], + [ + "utopia", + 2010, + "TXE", + 2010 + ], + [ + "utopia", + 1990, + "IMPOIL1", + 1990 + ], + [ + "utopia", + 1990, + "RL1", + 1990 + ], + [ + "utopia", + 2010, + "RL1", + 2010 + ], + [ + "utopia", + 2000, + "IMPGSL1", + 1990 + ], + [ + "utopia", + 1990, + "IMPHCO1", + 1990 + ], + [ + "utopia", + 2010, + "RHE", + 1990 + ], + [ + "utopia", + 1990, + "TXG", + 1990 + ], + [ + "utopia", + 2010, + "E70", + 2000 + ], + [ + "utopia", + 2000, + "E31", + 1980 + ], + [ + "utopia", + 2010, + "TXG", + 2010 + ], + [ + "utopia", + 1990, + "E70", + 1970 + ], + [ + "utopia", + 2010, + "E21", + 2000 + ], + [ + "utopia", + 1990, + "E01", + 1960 + ], + [ + "utopia", + 2000, + "E01", + 1970 + ], + [ + "utopia", + 2010, + "IMPHYD", + 1990 + ], + [ + "utopia", + 2010, + "SRE", + 2000 + ], + [ + "utopia", + 1990, + "IMPURN1", + 1990 + ], + [ + "utopia", + 2000, + "RHE", + 2000 + ], + [ + "utopia", + 1990, + "E01", + 1990 + ], + [ + "utopia", + 2000, + "E70", + 1980 + ], + [ + "utopia", + 1990, + "E51", + 1990 + ], + [ + "utopia", + 2010, + "E01", + 2010 + ], + [ + "utopia", + 2010, + "E51", + 2010 + ], + [ + "utopia", + 1990, + "E70", + 1990 + ], + [ + "utopia", + 2010, + "RHO", + 2000 + ], + [ + "utopia", + 1990, + "IMPHYD", + 1990 + ], + [ + "utopia", + 2000, + "E01", + 1990 + ], + [ + "utopia", + 2000, + "E51", + 1990 + ], + [ + "utopia", + 2000, + "IMPFEQ", + 1990 + ], + [ + "utopia", + 1990, + "TXD", + 1980 + ], + [ + "utopia", + 2000, + "RHO", + 1980 + ], + [ + "utopia", + 2000, + "TXD", + 1990 + ] + ], + "CurtailmentVar_rpsditvo": [], + "DemandActivityConstraint_rpsdtv_dem_s0d0": [ + [ + "utopia", + 2000, + "summer", + "day", + "RHE", + 2000, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "summer", + "night", + "TXG", + 1980, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "inter", + "night", + "RHO", + 1980, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "winter", + "day", + "RHO", + 1980, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "winter", + "night", + "RHO", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "night", + "RHO", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "night", + "RHE", + 2000, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "inter", + "night", + "RHO", + 2000, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "inter", + "night", + "TXE", + 2010, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "inter", + "night", + "RHE", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "inter", + "night", + "RHE", + 2010, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "day", + "RHO", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "winter", + "night", + "TXD", + 1980, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "night", + "TXG", + 2010, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "night", + "TXD", + 2010, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "day", + "RHE", + 2010, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "inter", + "night", + "TXE", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "summer", + "night", + "TXG", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "inter", + "night", + "RHO", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "day", + "TXD", + 2010, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "inter", + "night", + "RHO", + 1980, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXG", + 1970, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXG", + 1980, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "winter", + "day", + "TXG", + 1970, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXD", + 1980, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "night", + "RHO", + 2000, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "winter", + "day", + "RHO", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "day", + "RHO", + 1980, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "winter", + "day", + "RHO", + 1970, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "night", + "RHO", + 1980, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "inter", + "night", + "RHO", + 2010, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "night", + "RHE", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXD", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "day", + "TXD", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "night", + "RHE", + 2010, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "night", + "RHE", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "summer", + "day", + "RHO", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXD", + 1980, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "summer", + "night", + "TXE", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "day", + "TXD", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXG", + 1980, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXE", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "night", + "TXD", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "summer", + "night", + "TXD", + 1980, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXD", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXE", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXG", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "winter", + "day", + "RHE", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "day", + "RHO", + 2000, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXD", + 1970, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "day", + "RHO", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "night", + "TXD", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "winter", + "day", + "TXE", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "day", + "TXG", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "night", + "RHE", + 2000, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "night", + "RHO", + 2010, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXG", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXE", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "day", + "RHO", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXD", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXG", + 1980, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "inter", + "night", + "TXD", + 2010, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "summer", + "night", + "TXD", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXD", + 1980, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "summer", + "night", + "RHO", + 1970, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXD", + 1980, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "inter", + "night", + "RHE", + 2000, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "night", + "RHE", + 2010, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "night", + "TXG", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "summer", + "night", + "TXD", + 1970, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "day", + "RHE", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "winter", + "night", + "RHO", + 1980, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "day", + "TXG", + 2010, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "summer", + "night", + "RHO", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXG", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "winter", + "day", + "TXG", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "night", + "RHE", + 2000, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "night", + "RHO", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "night", + "TXE", + 2010, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "day", + "RHO", + 2000, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "day", + "TXE", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXG", + 1980, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "night", + "TXG", + 2010, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "night", + "RHE", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "winter", + "day", + "TXD", + 1980, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXG", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "winter", + "night", + "TXG", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXE", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "day", + "TXD", + 2010, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "night", + "TXG", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "night", + "RHO", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "summer", + "night", + "RHE", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "winter", + "night", + "TXG", + 1970, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "day", + "RHO", + 2010, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "inter", + "night", + "RHE", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "night", + "TXD", + 2010, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "winter", + "night", + "RHE", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "night", + "TXG", + 1980, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXG", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "inter", + "night", + "RHO", + 2000, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "summer", + "day", + "RHE", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXG", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "day", + "RHE", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXE", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "summer", + "night", + "RHO", + 1980, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "winter", + "night", + "TXG", + 1980, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "day", + "RHO", + 1980, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "night", + "RHE", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "day", + "RHE", + 2000, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXG", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "night", + "RHO", + 2000, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "night", + "RHO", + 2000, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "night", + "RHO", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXD", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXG", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "inter", + "night", + "TXG", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXE", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXD", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXD", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "inter", + "night", + "RHE", + 2000, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXE", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "day", + "RHE", + 2010, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "day", + "TXG", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "inter", + "night", + "TXD", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "night", + "TXD", + 1980, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "winter", + "night", + "TXD", + 1970, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXG", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "day", + "TXE", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXD", + 1980, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXD", + 1980, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "inter", + "night", + "RHE", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "winter", + "night", + "RHO", + 1970, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "night", + "TXG", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "day", + "RHE", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXD", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXE", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "night", + "RHE", + 2000, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXG", + 1980, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "night", + "TXE", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "night", + "TXE", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "day", + "RHO", + 2000, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "inter", + "night", + "TXG", + 2010, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXG", + 1970, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXG", + 1980, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "winter", + "day", + "TXD", + 1970, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXE", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "night", + "TXG", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "day", + "TXE", + 2010, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "inter", + "night", + "RHO", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXD", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "night", + "RHO", + 2000, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXD", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "night", + "RHO", + 1980, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "inter", + "night", + "RHO", + 1970, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "day", + "RHO", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "night", + "TXE", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "day", + "RHE", + 2000, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "night", + "TXD", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "day", + "TXE", + 2010, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "night", + "TXE", + 2010, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "day", + "RHO", + 2010, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "winter", + "day", + "TXG", + 1980, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "winter", + "day", + "TXD", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "day", + "RHE", + 2000, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "summer", + "night", + "TXG", + 1970, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "day", + "TXG", + 2010, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "summer", + "day", + "RHO", + 1970, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXD", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "night", + "TXD", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "winter", + "night", + "TXD", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "day", + "RHO", + 2000, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "night", + "RHO", + 2010, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXD", + 1970, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "day", + "RHE", + 1990, + "RH", + "inter", + "day" + ], + [ + "utopia", + 1990, + "summer", + "day", + "RHO", + 1980, + "RH", + "inter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "night", + "TXE", + 2000, + "TX", + "inter", + "day" + ], + [ + "utopia", + 1990, + "winter", + "night", + "TXE", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXE", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXG", + 1990, + "TX", + "inter", + "day" + ], + [ + "utopia", + 2000, + "inter", + "night", + "RHO", + 1990, + "RH", + "inter", + "day" + ] + ], + "DemandConstraint_rpsdc": [ + [ + "utopia", + 2010, + "inter", + "night", + "RH" + ], + [ + "utopia", + 2000, + "inter", + "night", + "RL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "RL" + ], + [ + "utopia", + 1990, + "winter", + "day", + "TX" + ], + [ + "utopia", + 1990, + "winter", + "night", + "TX" + ], + [ + "utopia", + 2000, + "inter", + "night", + "RH" + ], + [ + "utopia", + 1990, + "summer", + "night", + "RL" + ], + [ + "utopia", + 1990, + "summer", + "night", + "RH" + ], + [ + "utopia", + 2010, + "summer", + "night", + "TX" + ], + [ + "utopia", + 2000, + "inter", + "day", + "RL" + ], + [ + "utopia", + 2000, + "inter", + "day", + "RH" + ], + [ + "utopia", + 1990, + "summer", + "day", + "RL" + ], + [ + "utopia", + 1990, + "summer", + "day", + "RH" + ], + [ + "utopia", + 1990, + "winter", + "day", + "RL" + ], + [ + "utopia", + 1990, + "winter", + "night", + "RL" + ], + [ + "utopia", + 1990, + "inter", + "night", + "TX" + ], + [ + "utopia", + 2010, + "summer", + "day", + "TX" + ], + [ + "utopia", + 1990, + "winter", + "day", + "RH" + ], + [ + "utopia", + 1990, + "winter", + "night", + "RH" + ], + [ + "utopia", + 2000, + "summer", + "day", + "TX" + ], + [ + "utopia", + 2000, + "summer", + "night", + "TX" + ], + [ + "utopia", + 2010, + "summer", + "night", + "RL" + ], + [ + "utopia", + 2010, + "winter", + "day", + "TX" + ], + [ + "utopia", + 2010, + "winter", + "night", + "TX" + ], + [ + "utopia", + 2000, + "winter", + "day", + "TX" + ], + [ + "utopia", + 2000, + "winter", + "night", + "TX" + ], + [ + "utopia", + 2010, + "summer", + "night", + "RH" + ], + [ + "utopia", + 1990, + "inter", + "day", + "TX" + ], + [ + "utopia", + 1990, + "inter", + "night", + "RL" + ], + [ + "utopia", + 2010, + "summer", + "day", + "RL" + ], + [ + "utopia", + 2010, + "summer", + "day", + "RH" + ], + [ + "utopia", + 2000, + "summer", + "day", + "RL" + ], + [ + "utopia", + 1990, + "inter", + "night", + "RH" + ], + [ + "utopia", + 2000, + "summer", + "night", + "RL" + ], + [ + "utopia", + 2010, + "winter", + "day", + "RL" + ], + [ + "utopia", + 2010, + "winter", + "night", + "RL" + ], + [ + "utopia", + 2010, + "winter", + "day", + "RH" + ], + [ + "utopia", + 2010, + "winter", + "night", + "RH" + ], + [ + "utopia", + 2000, + "summer", + "day", + "RH" + ], + [ + "utopia", + 2000, + "summer", + "night", + "RH" + ], + [ + "utopia", + 2000, + "winter", + "day", + "RL" + ], + [ + "utopia", + 2000, + "winter", + "night", + "RL" + ], + [ + "utopia", + 2000, + "inter", + "night", + "TX" + ], + [ + "utopia", + 1990, + "inter", + "day", + "RL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "TX" + ], + [ + "utopia", + 1990, + "inter", + "day", + "RH" + ], + [ + "utopia", + 2000, + "winter", + "day", + "RH" + ], + [ + "utopia", + 2000, + "winter", + "night", + "RH" + ], + [ + "utopia", + 1990, + "summer", + "night", + "TX" + ], + [ + "utopia", + 2000, + "inter", + "day", + "TX" + ], + [ + "utopia", + 2010, + "inter", + "night", + "TX" + ], + [ + "utopia", + 1990, + "summer", + "day", + "TX" + ], + [ + "utopia", + 2010, + "inter", + "night", + "RL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "RH" + ] + ], + "EmissionActivity_reitvo": [ + [ + "utopia", + "co2", + "DSL", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + "co2", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + "co2", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + "nox", + "HCO", + "E01", + 1960, + "ELC" + ], + [ + "utopia", + "co2", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + "nox", + "ELC", + "RL1", + 1980, + "RL" + ], + [ + "utopia", + "co2", + "URN", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + "co2", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + "nox", + "ELC", + "RL1", + 2010, + "RL" + ], + [ + "utopia", + "co2", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + "nox", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + "nox", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + "co2", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + "co2", + "OIL", + "SRE", + 2010, + "DSL" + ], + [ + "utopia", + "co2", + "HCO", + "E01", + 1970, + "ELC" + ], + [ + "utopia", + "nox", + "URN", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + "co2", + "OIL", + "SRE", + 2010, + "GSL" + ], + [ + "utopia", + "co2", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + "co2", + "GSL", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + "nox", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + "nox", + "ELC", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + "co2", + "DSL", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + "nox", + "DSL", + "E70", + 1970, + "ELC" + ], + [ + "utopia", + "co2", + "DSL", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + "co2", + "HYD", + "E31", + 2000, + "ELC" + ], + [ + "utopia", + "nox", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + "nox", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + "co2", + "ELC", + "RHE", + 2010, + "RH" + ], + [ + "utopia", + "nox", + "OIL", + "SRE", + 2010, + "DSL" + ], + [ + "utopia", + "nox", + "URN", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + "nox", + "OIL", + "SRE", + 2010, + "GSL" + ], + [ + "utopia", + "nox", + "GSL", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + "co2", + "DSL", + "E70", + 2010, + "ELC" + ], + [ + "utopia", + "co2", + "GSL", + "TXG", + 1970, + "TX" + ], + [ + "utopia", + "nox", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + "co2", + "ELC", + "TXE", + 2010, + "TX" + ], + [ + "utopia", + "nox", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + "nox", + "ELC", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + "nox", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + "co2", + "DSL", + "TXD", + 1980, + "TX" + ], + [ + "utopia", + "nox", + "DSL", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + "nox", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + "co2", + "ELC", + "RL1", + 1990, + "RL" + ], + [ + "utopia", + "nox", + "HYD", + "E31", + 2010, + "ELC" + ], + [ + "utopia", + "co2", + "FEQ", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + "nox", + "DSL", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + "nox", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + "nox", + "OIL", + "SRE", + 2000, + "DSL" + ], + [ + "utopia", + "co2", + "GSL", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + "nox", + "ELC", + "RHE", + 2010, + "RH" + ], + [ + "utopia", + "nox", + "OIL", + "SRE", + 2000, + "GSL" + ], + [ + "utopia", + "nox", + "GSL", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + "co2", + "DSL", + "E70", + 2000, + "ELC" + ], + [ + "utopia", + "nox", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + "nox", + "DSL", + "E70", + 2010, + "ELC" + ], + [ + "utopia", + "co2", + "HCO", + "E01", + 2000, + "ELC" + ], + [ + "utopia", + "nox", + "DSL", + "TXD", + 1980, + "TX" + ], + [ + "utopia", + "nox", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + "nox", + "ELC", + "RL1", + 2000, + "RL" + ], + [ + "utopia", + "co2", + "HCO", + "E01", + 1960, + "ELC" + ], + [ + "utopia", + "co2", + "ELC", + "RL1", + 1980, + "RL" + ], + [ + "utopia", + "co2", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + "nox", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + "co2", + "GSL", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + "nox", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + "co2", + "OIL", + "SRE", + 2000, + "DSL" + ], + [ + "utopia", + "nox", + "DSL", + "E70", + 2000, + "ELC" + ], + [ + "utopia", + "co2", + "OIL", + "SRE", + 2000, + "GSL" + ], + [ + "utopia", + "co2", + "DSL", + "RHO", + 2010, + "RH" + ], + [ + "utopia", + "co2", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + "nox", + "HCO", + "E01", + 2010, + "ELC" + ], + [ + "utopia", + "co2", + "DSL", + "E70", + 1970, + "ELC" + ], + [ + "utopia", + "co2", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + "co2", + "ELC", + "RL1", + 2010, + "RL" + ], + [ + "utopia", + "nox", + "DSL", + "TXD", + 1970, + "TX" + ], + [ + "utopia", + "nox", + "HCO", + "E01", + 1970, + "ELC" + ], + [ + "utopia", + "co2", + "URN", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + "nox", + "ELC", + "RL1", + 1990, + "RL" + ], + [ + "utopia", + "nox", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + "co2", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + "co2", + "ELC", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + "co2", + "DSL", + "RHO", + 1970, + "RH" + ], + [ + "utopia", + "co2", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + "co2", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + "nox", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + "co2", + "DSL", + "TXD", + 2010, + "TX" + ], + [ + "utopia", + "co2", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + "co2", + "ELC", + "RHE", + 2000, + "RH" + ], + [ + "utopia", + "co2", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + "nox", + "DSL", + "RHO", + 2010, + "RH" + ], + [ + "utopia", + "nox", + "FEQ", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + "co2", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + "nox", + "HCO", + "E01", + 2000, + "ELC" + ], + [ + "utopia", + "co2", + "DSL", + "E70", + 1960, + "ELC" + ], + [ + "utopia", + "co2", + "GSL", + "TXG", + 2010, + "TX" + ], + [ + "utopia", + "co2", + "ELC", + "RL1", + 2000, + "RL" + ], + [ + "utopia", + "nox", + "GSL", + "TXG", + 2010, + "TX" + ], + [ + "utopia", + "co2", + "DSL", + "TXD", + 1970, + "TX" + ], + [ + "utopia", + "nox", + "GSL", + "TXG", + 1970, + "TX" + ], + [ + "utopia", + "nox", + "ELC", + "TXE", + 2010, + "TX" + ], + [ + "utopia", + "nox", + "HYD", + "E31", + 2000, + "ELC" + ], + [ + "utopia", + "co2", + "ELC", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + "co2", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + "co2", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + "nox", + "DSL", + "RHO", + 1970, + "RH" + ], + [ + "utopia", + "co2", + "DSL", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + "nox", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + "nox", + "DSL", + "TXD", + 2010, + "TX" + ], + [ + "utopia", + "co2", + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + "nox", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + "nox", + "ELC", + "RHE", + 2000, + "RH" + ], + [ + "utopia", + "nox", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + "nox", + "DSL", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + "co2", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + "co2", + "HCO", + "E01", + 2010, + "ELC" + ], + [ + "utopia", + "nox", + "FEQ", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + "nox", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + "nox", + "DSL", + "E70", + 1960, + "ELC" + ], + [ + "utopia", + "nox", + "GSL", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + "co2", + "HYD", + "E31", + 2010, + "ELC" + ], + [ + "utopia", + "nox", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + "co2", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + "co2", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + "nox", + "DSL", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + "nox", + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + "co2", + "FEQ", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + "co2", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + "nox", + "DSL", + "E70", + 1990, + "ELC" + ] + ], + "FlexVarAnnual_rpitvo": [], + "FlexVar_rpsditvo": [], + "FlowInStorage_rpsditvo": [ + [ + "utopia", + 2000, + "winter", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ELC", + "E51", + 1990, + "ELC" + ] + ], + "FlowVarAnnual_rpitvo": [], + "FlowVar_rpsditvo": [ + [ + "utopia", + 2000, + "inter", + "day", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "day", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "OIL", + "SRE", + 2000, + "DSL" + ], + [ + "utopia", + 2000, + "summer", + "day", + "HYD", + "E31", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "DSL", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "day", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "DSL", + "E70", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "DSL", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + 1990, + "summer", + "night", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "summer", + "day", + "DSL", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "night", + "DSL", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + 1990, + "inter", + "day", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 2000, + "inter", + "day", + "OIL", + "SRE", + 2000, + "DSL" + ], + [ + "utopia", + 2010, + "summer", + "day", + "OIL", + "SRE", + 2000, + "GSL" + ], + [ + "utopia", + 2010, + "winter", + "night", + "HYD", + "E31", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "inter", + "day", + "OIL", + "SRE", + 2000, + "DSL" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ELC", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "winter", + "day", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 1990, + "winter", + "night", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 2000, + "winter", + "night", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 2010, + "winter", + "night", + "GSL", + "TXG", + 2010, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "night", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "OIL", + "SRE", + 2000, + "DSL" + ], + [ + "utopia", + 2010, + "summer", + "night", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 1990, + "summer", + "night", + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "winter", + "day", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "night", + "HCO", + "E01", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 1990, + "summer", + "day", + "HCO", + "E01", + 1970, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 1990, + "inter", + "day", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 1990, + "summer", + "night", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 1990, + "inter", + "day", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "ELC", + "RL1", + 1990, + "RL" + ], + [ + "utopia", + 2010, + "winter", + "night", + "DSL", + "RHO", + 2010, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 2000, + "summer", + "night", + "DSL", + "E70", + 1970, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "OIL", + "SRE", + 2000, + "DSL" + ], + [ + "utopia", + 1990, + "summer", + "day", + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "summer", + "night", + "HYD", + "E31", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "URN", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + 1990, + "summer", + "night", + "GSL", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + 1990, + "winter", + "day", + "HCO", + "E01", + 1970, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "day", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ELC", + "RL1", + 2010, + "RL" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ELC", + "TXE", + 2010, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ELC", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "inter", + "day", + "DSL", + "TXD", + 2010, + "TX" + ], + [ + "utopia", + 1990, + "summer", + "day", + "DSL", + "E70", + 1960, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + 1990, + "inter", + "night", + "ELC", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "day", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "GSL", + "TXG", + 1970, + "TX" + ], + [ + "utopia", + 1990, + "winter", + "day", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 2010, + "winter", + "night", + "DSL", + "E70", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "ELC", + "RL1", + 1980, + "RL" + ], + [ + "utopia", + 2000, + "summer", + "night", + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "summer", + "night", + "DSL", + "E70", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "HYD", + "E31", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ELC", + "TXE", + 2010, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "night", + "HCO", + "E01", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "DSL", + "E70", + 1970, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "DSL", + "E70", + 2010, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "DSL", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + 1990, + "inter", + "night", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 2000, + "winter", + "night", + "GSL", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "day", + "DSL", + "RHO", + 2010, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "day", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 1990, + "inter", + "night", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + 1990, + "summer", + "day", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "HCO", + "E01", + 2010, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "DSL", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + 1990, + "summer", + "day", + "DSL", + "RHO", + 1970, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ELC", + "RL1", + 2000, + "RL" + ], + [ + "utopia", + 1990, + "summer", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 1990, + "inter", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 2010, + "summer", + "night", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 1990, + "summer", + "day", + "DSL", + "TXD", + 1980, + "TX" + ], + [ + "utopia", + 1990, + "winter", + "day", + "GSL", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "DSL", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "winter", + "day", + "GSL", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + 2000, + "summer", + "day", + "DSL", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "day", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "HCO", + "E01", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ELC", + "RHE", + 2000, + "RH" + ], + [ + "utopia", + 2010, + "inter", + "night", + "URN", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 1990, + "summer", + "day", + "ELC", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + 1990, + "summer", + "night", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "HCO", + "E01", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ELC", + "RHE", + 2010, + "RH" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 2010, + "winter", + "day", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "GSL", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + 1990, + "summer", + "day", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 2010, + "winter", + "day", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "GSL", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + 2010, + "inter", + "night", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "ELC", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + 2000, + "winter", + "day", + "ELC", + "RHE", + 2000, + "RH" + ], + [ + "utopia", + 2010, + "inter", + "day", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "DSL", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + 1990, + "inter", + "day", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 2000, + "winter", + "night", + "OIL", + "SRE", + 2000, + "DSL" + ], + [ + "utopia", + 2010, + "summer", + "day", + "FEQ", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "DSL", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + 1990, + "inter", + "day", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "URN", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 2000, + "winter", + "night", + "FEQ", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + 1990, + "summer", + "night", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 2000, + "summer", + "night", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 1990, + "winter", + "night", + "ELC", + "RL1", + 1990, + "RL" + ], + [ + "utopia", + 2010, + "inter", + "night", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 1990, + "inter", + "night", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "OIL", + "SRE", + 2000, + "DSL" + ], + [ + "utopia", + 2000, + "summer", + "night", + "ELC", + "RL1", + 2000, + "RL" + ], + [ + "utopia", + 1990, + "winter", + "night", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ELC", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ELC", + "RHE", + 2000, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "night", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "DSL", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + 2000, + "winter", + "day", + "OIL", + "SRE", + 2000, + "DSL" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 2010, + "winter", + "day", + "URN", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "FEQ", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "OIL", + "SRE", + 2010, + "GSL" + ], + [ + "utopia", + 1990, + "summer", + "night", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 1990, + "summer", + "night", + "HCO", + "E01", + 1960, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 1990, + "inter", + "day", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ELC", + "RHE", + 2000, + "RH" + ], + [ + "utopia", + 1990, + "winter", + "day", + "DSL", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + 1990, + "summer", + "day", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 2000, + "winter", + "night", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "summer", + "night", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "GSL", + "TXG", + 2010, + "TX" + ], + [ + "utopia", + 2010, + "inter", + "day", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "HCO", + "E01", + 1960, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "DSL", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + 2010, + "winter", + "day", + "HYD", + "E31", + 2010, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "DSL", + "E70", + 1970, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "OIL", + "SRE", + 2000, + "DSL" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ELC", + "RHE", + 2000, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "day", + "URN", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ELC", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 2000, + "winter", + "day", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "DSL", + "TXD", + 1980, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "day", + "HYD", + "E31", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "DSL", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "night", + "HYD", + "E31", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "HYD", + "E31", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "day", + "GSL", + "TXG", + 1970, + "TX" + ], + [ + "utopia", + 1990, + "inter", + "day", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 1990, + "inter", + "day", + "GSL", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 1990, + "inter", + "night", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 2010, + "summer", + "day", + "DSL", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "day", + "DSL", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 1990, + "inter", + "day", + "DSL", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ELC", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + 1990, + "inter", + "night", + "DSL", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + 2010, + "winter", + "day", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 2000, + "winter", + "night", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "DSL", + "TXD", + 1980, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "day", + "URN", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "DSL", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "night", + "DSL", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + 2000, + "summer", + "night", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 2010, + "summer", + "day", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 2000, + "inter", + "night", + "URN", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "DSL", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "day", + "DSL", + "TXD", + 1980, + "TX" + ], + [ + "utopia", + 2010, + "inter", + "night", + "OIL", + "SRE", + 2000, + "GSL" + ], + [ + "utopia", + 1990, + "inter", + "day", + "DSL", + "TXD", + 1980, + "TX" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ELC", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + 1990, + "winter", + "day", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "ELC", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 2010, + "winter", + "night", + "GSL", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "winter", + "day", + "ELC", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + 1990, + "summer", + "day", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 1990, + "summer", + "night", + "DSL", + "TXD", + 1980, + "TX" + ], + [ + "utopia", + 2000, + "summer", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "day", + "HCO", + "E01", + 1960, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "GSL", + "TXG", + 2010, + "TX" + ], + [ + "utopia", + 1990, + "inter", + "day", + "HCO", + "E01", + 1970, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + 1990, + "inter", + "night", + "DSL", + "TXD", + 1970, + "TX" + ], + [ + "utopia", + 2010, + "inter", + "day", + "HCO", + "E01", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 1990, + "winter", + "night", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 2000, + "winter", + "night", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 1990, + "summer", + "night", + "GSL", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + 2000, + "winter", + "day", + "HYD", + "E31", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "HCO", + "E01", + 1960, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 2010, + "inter", + "day", + "GSL", + "TXG", + 2010, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ELC", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "summer", + "night", + "OIL", + "SRE", + 2000, + "GSL" + ], + [ + "utopia", + 2000, + "summer", + "night", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 2010, + "inter", + "day", + "DSL", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + 1990, + "summer", + "day", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "OIL", + "SRE", + 2010, + "GSL" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ELC", + "RL1", + 2000, + "RL" + ], + [ + "utopia", + 2000, + "summer", + "day", + "GSL", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + 2000, + "summer", + "day", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "day", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ELC", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "night", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "DSL", + "E70", + 1960, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "DSL", + "E70", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 2000, + "summer", + "day", + "DSL", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "day", + "DSL", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + 1990, + "winter", + "day", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "HCO", + "E01", + 1970, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "GSL", + "TXG", + 2010, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "HYD", + "E31", + 2010, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 1990, + "inter", + "night", + "DSL", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + 1990, + "inter", + "day", + "ELC", + "RL1", + 1980, + "RL" + ], + [ + "utopia", + 1990, + "inter", + "night", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ELC", + "RL1", + 2000, + "RL" + ], + [ + "utopia", + 2010, + "summer", + "night", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "HYD", + "E31", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 1990, + "winter", + "day", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ELC", + "RHE", + 2010, + "RH" + ], + [ + "utopia", + 1990, + "winter", + "night", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 1990, + "winter", + "night", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + 2010, + "winter", + "night", + "DSL", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "day", + "HCO", + "E01", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "HCO", + "E01", + 1970, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ELC", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "night", + "OIL", + "SRE", + 2010, + "GSL" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ELC", + "RL1", + 2000, + "RL" + ], + [ + "utopia", + 1990, + "summer", + "day", + "DSL", + "TXD", + 1970, + "TX" + ], + [ + "utopia", + 2000, + "winter", + "day", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "URN", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + 2000, + "summer", + "day", + "DSL", + "E70", + 1970, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "DSL", + "TXD", + 2010, + "TX" + ], + [ + "utopia", + 1990, + "summer", + "day", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "day", + "DSL", + "E70", + 1970, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 2000, + "inter", + "night", + "HCO", + "E01", + 1970, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ELC", + "RHE", + 2010, + "RH" + ], + [ + "utopia", + 2010, + "inter", + "night", + "HCO", + "E01", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "DSL", + "E70", + 1970, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ELC", + "RL1", + 2010, + "RL" + ], + [ + "utopia", + 1990, + "summer", + "day", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "DSL", + "E70", + 1970, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ELC", + "RHE", + 2000, + "RH" + ], + [ + "utopia", + 2010, + "summer", + "night", + "HYD", + "E31", + 2010, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "day", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "HCO", + "E01", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "GSL", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + 2010, + "inter", + "night", + "HYD", + "E31", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "OIL", + "SRE", + 2000, + "GSL" + ], + [ + "utopia", + 1990, + "summer", + "day", + "DSL", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + 2000, + "summer", + "day", + "DSL", + "E70", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "DSL", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "day", + "DSL", + "E70", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "HCO", + "E01", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ELC", + "RL1", + 2010, + "RL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "inter", + "day", + "DSL", + "E70", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "HYD", + "E31", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 2010, + "inter", + "night", + "OIL", + "SRE", + 2010, + "DSL" + ], + [ + "utopia", + 2000, + "summer", + "day", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "night", + "DSL", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + 1990, + "inter", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "GSL", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 2010, + "inter", + "day", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ELC", + "RL1", + 2010, + "RL" + ], + [ + "utopia", + 2000, + "winter", + "night", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "inter", + "night", + "DSL", + "E70", + 2010, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 2010, + "summer", + "night", + "HCO", + "E01", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 1990, + "winter", + "night", + "ELC", + "RL1", + 1980, + "RL" + ], + [ + "utopia", + 1990, + "winter", + "night", + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ELC", + "TXE", + 2010, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "day", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 2000, + "summer", + "night", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 1990, + "winter", + "day", + "ELC", + "RL1", + 1990, + "RL" + ], + [ + "utopia", + 2000, + "winter", + "day", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 2000, + "summer", + "day", + "FEQ", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 2010, + "summer", + "night", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "ELC", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "night", + "DSL", + "TXD", + 1980, + "TX" + ], + [ + "utopia", + 2000, + "winter", + "day", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "DSL", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "night", + "FEQ", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "day", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "OIL", + "SRE", + 2000, + "GSL" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ELC", + "TXE", + 2010, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "day", + "FEQ", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "GSL", + "TXG", + 2010, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "day", + "OIL", + "SRE", + 2000, + "GSL" + ], + [ + "utopia", + 1990, + "winter", + "night", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "HCO", + "E01", + 1970, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "GSL", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "day", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 2000, + "winter", + "day", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "winter", + "day", + "HYD", + "E31", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 1990, + "winter", + "night", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ELC", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "FEQ", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "OIL", + "SRE", + 2010, + "GSL" + ], + [ + "utopia", + 2010, + "summer", + "night", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "FEQ", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "OIL", + "SRE", + 2000, + "GSL" + ], + [ + "utopia", + 1990, + "winter", + "day", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 1990, + "inter", + "night", + "ELC", + "RL1", + 1990, + "RL" + ], + [ + "utopia", + 2000, + "inter", + "day", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 1990, + "summer", + "day", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 2010, + "summer", + "night", + "URN", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 2000, + "inter", + "day", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "DSL", + "RHO", + 1970, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "night", + "URN", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "DSL", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "summer", + "night", + "GSL", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + 2000, + "summer", + "night", + "HCO", + "E01", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "HCO", + "E01", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "OIL", + "SRE", + 2000, + "GSL" + ], + [ + "utopia", + 1990, + "inter", + "night", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "OIL", + "SRE", + 2010, + "GSL" + ], + [ + "utopia", + 2010, + "inter", + "night", + "FEQ", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 1990, + "winter", + "day", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "HCO", + "E01", + 1970, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "DSL", + "RHO", + 1970, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "night", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "DSL", + "TXD", + 1970, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "day", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 2000, + "inter", + "day", + "GSL", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + 2000, + "winter", + "night", + "DSL", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "day", + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "winter", + "night", + "URN", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 1990, + "inter", + "night", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 2000, + "inter", + "night", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "DSL", + "E70", + 1970, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 1990, + "inter", + "night", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 1990, + "summer", + "night", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + 1990, + "winter", + "day", + "DSL", + "RHO", + 1970, + "RH" + ], + [ + "utopia", + 2010, + "inter", + "night", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 2000, + "inter", + "day", + "DSL", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + 1990, + "inter", + "day", + "DSL", + "TXD", + 1970, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "night", + "GSL", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + 2000, + "summer", + "day", + "HCO", + "E01", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "GSL", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + 2010, + "summer", + "day", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 1990, + "winter", + "day", + "ELC", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "day", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "GSL", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + 1990, + "summer", + "night", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ELC", + "RL1", + 2010, + "RL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "FEQ", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "inter", + "day", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "DSL", + "TXD", + 1970, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "night", + "OIL", + "SRE", + 2000, + "DSL" + ], + [ + "utopia", + 2000, + "inter", + "day", + "DSL", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "night", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ELC", + "RL1", + 2010, + "RL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "HYD", + "E31", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "summer", + "day", + "DSL", + "E70", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 2000, + "summer", + "day", + "GSL", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "day", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 1990, + "summer", + "day", + "GSL", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "GSL", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + 1990, + "inter", + "night", + "DSL", + "RHO", + 1970, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "day", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + 1990, + "summer", + "night", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 2010, + "summer", + "night", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 2000, + "summer", + "day", + "DSL", + "TXD", + 1980, + "TX" + ], + [ + "utopia", + 2000, + "summer", + "day", + "URN", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "GSL", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "summer", + "night", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 1990, + "summer", + "night", + "DSL", + "TXD", + 1970, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "day", + "DSL", + "TXD", + 2010, + "TX" + ], + [ + "utopia", + 1990, + "summer", + "day", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + 1990, + "inter", + "night", + "DSL", + "TXD", + 1980, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 1990, + "inter", + "day", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 1990, + "winter", + "day", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "ELC", + "RL1", + 1990, + "RL" + ], + [ + "utopia", + 2000, + "winter", + "day", + "ELC", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + 1990, + "winter", + "night", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ELC", + "RHE", + 2000, + "RH" + ], + [ + "utopia", + 1990, + "winter", + "night", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 1990, + "inter", + "day", + "HCO", + "E01", + 1960, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "DSL", + "TXD", + 1980, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "night", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "day", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "OIL", + "SRE", + 2000, + "GSL" + ], + [ + "utopia", + 1990, + "inter", + "day", + "GSL", + "TXG", + 1970, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "night", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 1990, + "summer", + "day", + "ELC", + "RL1", + 1990, + "RL" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ELC", + "RHE", + 2000, + "RH" + ], + [ + "utopia", + 1990, + "summer", + "night", + "GSL", + "TXG", + 1970, + "TX" + ], + [ + "utopia", + 2000, + "winter", + "day", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "FEQ", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 2000, + "summer", + "day", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 1990, + "inter", + "night", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 2010, + "winter", + "day", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ELC", + "RHE", + 2000, + "RH" + ], + [ + "utopia", + 1990, + "summer", + "night", + "DSL", + "RHO", + 1970, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "night", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 1990, + "summer", + "day", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 2000, + "winter", + "night", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 2000, + "summer", + "night", + "FEQ", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ELC", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + 1990, + "summer", + "day", + "DSL", + "E70", + 1970, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "OIL", + "SRE", + 2010, + "DSL" + ], + [ + "utopia", + 2010, + "inter", + "night", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 2010, + "winter", + "night", + "DSL", + "E70", + 2010, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "OIL", + "SRE", + 2000, + "GSL" + ], + [ + "utopia", + 2010, + "winter", + "day", + "OIL", + "SRE", + 2010, + "DSL" + ], + [ + "utopia", + 2000, + "inter", + "day", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "DSL", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "night", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "HYD", + "E31", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "DSL", + "E70", + 2010, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ELC", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "night", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "HCO", + "E01", + 2010, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 2010, + "summer", + "night", + "DSL", + "RHO", + 2010, + "RH" + ], + [ + "utopia", + 2010, + "summer", + "night", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "day", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 1990, + "summer", + "night", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 1990, + "summer", + "day", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 2000, + "summer", + "day", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "HYD", + "E31", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "OIL", + "SRE", + 2010, + "DSL" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 2010, + "inter", + "day", + "GSL", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + 1990, + "winter", + "day", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 2010, + "summer", + "night", + "OIL", + "SRE", + 2000, + "GSL" + ], + [ + "utopia", + 2000, + "winter", + "day", + "GSL", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "winter", + "day", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 1990, + "inter", + "day", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "DSL", + "E70", + 1960, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "DSL", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ELC", + "RHE", + 2000, + "RH" + ], + [ + "utopia", + 2000, + "summer", + "night", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "DSL", + "RHO", + 2010, + "RH" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 2000, + "summer", + "night", + "DSL", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + 2010, + "inter", + "night", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "DSL", + "E70", + 1960, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "GSL", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + 1990, + "summer", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "inter", + "day", + "URN", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 1990, + "winter", + "night", + "GSL", + "TXG", + 1970, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ELC", + "RHE", + 2010, + "RH" + ], + [ + "utopia", + 2010, + "winter", + "day", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 2000, + "winter", + "day", + "DSL", + "TXD", + 1980, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "night", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "day", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "GSL", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "ELC", + "RHE", + 2000, + "RH" + ], + [ + "utopia", + 2010, + "winter", + "day", + "FEQ", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "DSL", + "RHO", + 2010, + "RH" + ], + [ + "utopia", + 1990, + "winter", + "day", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + 2010, + "summer", + "day", + "GSL", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + 1990, + "inter", + "night", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 2000, + "winter", + "night", + "GSL", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "day", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 2010, + "inter", + "night", + "URN", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "OIL", + "SRE", + 2000, + "DSL" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 2010, + "inter", + "night", + "DSL", + "E70", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "HCO", + "E01", + 1970, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "DSL", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "night", + "DSL", + "TXD", + 1980, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "day", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ELC", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + 2010, + "inter", + "night", + "DSL", + "TXD", + 2010, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "night", + "URN", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + 2000, + "inter", + "day", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 1990, + "winter", + "night", + "HCO", + "E01", + 1960, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "HCO", + "E01", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 1990, + "winter", + "night", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 1990, + "summer", + "day", + "DSL", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + 1990, + "winter", + "day", + "ELC", + "RL1", + 1980, + "RL" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 2010, + "inter", + "night", + "DSL", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "summer", + "day", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "OIL", + "SRE", + 2000, + "DSL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "OIL", + "SRE", + 2000, + "GSL" + ], + [ + "utopia", + 2010, + "summer", + "day", + "OIL", + "SRE", + 2010, + "DSL" + ], + [ + "utopia", + 2000, + "inter", + "day", + "HCO", + "E01", + 1970, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "GSL", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + 2000, + "winter", + "day", + "ELC", + "RL1", + 2000, + "RL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "DSL", + "E70", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ELC", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "summer", + "night", + "GSL", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + 1990, + "winter", + "day", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 1990, + "winter", + "night", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 2010, + "winter", + "night", + "URN", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "ELC", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + 2000, + "summer", + "night", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 1990, + "winter", + "day", + "DSL", + "E70", + 1960, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "URN", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 2000, + "summer", + "day", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "GSL", + "TXG", + 1970, + "TX" + ], + [ + "utopia", + 1990, + "inter", + "day", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 2000, + "summer", + "night", + "GSL", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + 2000, + "winter", + "night", + "DSL", + "E70", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ELC", + "RHE", + 2000, + "RH" + ], + [ + "utopia", + 1990, + "winter", + "night", + "DSL", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "day", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 2000, + "inter", + "day", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "ELC", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + 2010, + "inter", + "day", + "FEQ", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "HCO", + "E01", + 1970, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "ELC", + "RL1", + 1980, + "RL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "DSL", + "E70", + 1970, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "HCO", + "E01", + 1970, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "DSL", + "TXD", + 2010, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "night", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 2010, + "summer", + "night", + "OIL", + "SRE", + 2010, + "DSL" + ], + [ + "utopia", + 2000, + "inter", + "day", + "FEQ", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "night", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 1990, + "inter", + "day", + "DSL", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "night", + "DSL", + "TXD", + 2010, + "TX" + ], + [ + "utopia", + 2000, + "summer", + "night", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 1990, + "winter", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "DSL", + "E70", + 1960, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "FEQ", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "HCO", + "E01", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "GSL", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + 2000, + "winter", + "day", + "DSL", + "E70", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "DSL", + "E70", + 1970, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "DSL", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + 1990, + "inter", + "night", + "GSL", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + 1990, + "winter", + "night", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "day", + "HCO", + "E01", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ELC", + "TXE", + 2010, + "TX" + ], + [ + "utopia", + 2000, + "winter", + "day", + "DSL", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ELC", + "RHE", + 2010, + "RH" + ], + [ + "utopia", + 2000, + "summer", + "day", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "DSL", + "RHO", + 2010, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "day", + "FEQ", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 2000, + "inter", + "night", + "DSL", + "E70", + 1970, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 1990, + "summer", + "night", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 1990, + "summer", + "day", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 1990, + "inter", + "night", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "day", + "DSL", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "day", + "URN", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "OIL", + "SRE", + 2010, + "GSL" + ], + [ + "utopia", + 2000, + "winter", + "night", + "DSL", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + 2010, + "summer", + "day", + "DSL", + "E70", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 1990, + "inter", + "day", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "DSL", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + 2000, + "winter", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "day", + "ELC", + "RL1", + 1980, + "RL" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ELC", + "RHE", + 2010, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "night", + "DSL", + "E70", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ELC", + "TXE", + 2010, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "night", + "FEQ", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "night", + "DSL", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + 2000, + "summer", + "day", + "GSL", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + 2000, + "summer", + "night", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "day", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 1990, + "summer", + "day", + "GSL", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 1990, + "inter", + "day", + "GSL", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ELC", + "E51", + 1990, + "ELC" + ] + ], + "GroupShareIndices": [], + "LifetimeProcess_rtv": [ + [ + "utopia", + "IMPURN1", + 1990 + ], + [ + "utopia", + "TXD", + 1990 + ], + [ + "utopia", + "RHO", + 2010 + ], + [ + "utopia", + "E21", + 2000 + ], + [ + "utopia", + "TXG", + 1970 + ], + [ + "utopia", + "E51", + 1980 + ], + [ + "utopia", + "E70", + 1960 + ], + [ + "utopia", + "E31", + 1980 + ], + [ + "utopia", + "IMPGSL1", + 1990 + ], + [ + "utopia", + "RHO", + 1970 + ], + [ + "utopia", + "IMPDSL1", + 1990 + ], + [ + "utopia", + "TXE", + 1990 + ], + [ + "utopia", + "E01", + 1980 + ], + [ + "utopia", + "IMPHYD", + 1990 + ], + [ + "utopia", + "IMPOIL1", + 1990 + ], + [ + "utopia", + "E51", + 2010 + ], + [ + "utopia", + "E70", + 1990 + ], + [ + "utopia", + "RL1", + 1990 + ], + [ + "utopia", + "TXD", + 1980 + ], + [ + "utopia", + "TXG", + 2000 + ], + [ + "utopia", + "SRE", + 2000 + ], + [ + "utopia", + "E31", + 2010 + ], + [ + "utopia", + "RHO", + 2000 + ], + [ + "utopia", + "RHE", + 2010 + ], + [ + "utopia", + "E21", + 1990 + ], + [ + "utopia", + "E01", + 2010 + ], + [ + "utopia", + "E01", + 1970 + ], + [ + "utopia", + "IMPHCO1", + 1990 + ], + [ + "utopia", + "TXD", + 2010 + ], + [ + "utopia", + "E51", + 2000 + ], + [ + "utopia", + "E70", + 1980 + ], + [ + "utopia", + "SRE", + 1990 + ], + [ + "utopia", + "TXG", + 1990 + ], + [ + "utopia", + "RL1", + 1980 + ], + [ + "utopia", + "E31", + 2000 + ], + [ + "utopia", + "RHO", + 1990 + ], + [ + "utopia", + "TXD", + 1970 + ], + [ + "utopia", + "TXE", + 2010 + ], + [ + "utopia", + "RHE", + 2000 + ], + [ + "utopia", + "E01", + 2000 + ], + [ + "utopia", + "E70", + 2010 + ], + [ + "utopia", + "RL1", + 2010 + ], + [ + "utopia", + "E01", + 1960 + ], + [ + "utopia", + "TXD", + 2000 + ], + [ + "utopia", + "E21", + 2010 + ], + [ + "utopia", + "E70", + 1970 + ], + [ + "utopia", + "IMPFEQ", + 1990 + ], + [ + "utopia", + "TXG", + 1980 + ], + [ + "utopia", + "E51", + 1990 + ], + [ + "utopia", + "E31", + 1990 + ], + [ + "utopia", + "RHO", + 1980 + ], + [ + "utopia", + "TXE", + 2000 + ], + [ + "utopia", + "RHE", + 1990 + ], + [ + "utopia", + "E01", + 1990 + ], + [ + "utopia", + "SRE", + 2010 + ], + [ + "utopia", + "TXG", + 2010 + ], + [ + "utopia", + "E70", + 2000 + ], + [ + "utopia", + "RL1", + 2000 + ] + ], + "LimitActivityConstraint_rpt": [], + "LimitActivityGroup_rpg": [], + "LimitActivityShareConstraint_rptg": [], + "LimitAnnualCapacityFactorConstraint_rpto": [], + "LimitCapacityConstraint_rpt": [ + [ + "utopia", + 1990, + "TXD", + "le" + ], + [ + "utopia", + 2000, + "E31", + "le" + ], + [ + "utopia", + 1990, + "E31", + "ge" + ], + [ + "utopia", + 2000, + "TXD", + "le" + ], + [ + "utopia", + 1990, + "E31", + "le" + ], + [ + "utopia", + 1990, + "RHE", + "le" + ], + [ + "utopia", + 2010, + "TXD", + "le" + ], + [ + "utopia", + 2010, + "E31", + "le" + ], + [ + "utopia", + 2010, + "E31", + "ge" + ], + [ + "utopia", + 2000, + "E31", + "ge" + ], + [ + "utopia", + 1990, + "SRE", + "ge" + ] + ], + "LimitCapacityGroupConstraint_rpg": [], + "LimitCapacityShareConstraint_rptg": [], + "LimitDegrowthCapacityConstraint_rpt": [], + "LimitDegrowthNewCapacityConstraint_rpt": [], + "LimitDegrowthNewCapacityDeltaConstraint_rpt": [], + "LimitEmissionConstraint_rpe": [], + "LimitGrowthCapacityConstraint_rpt": [], + "LimitGrowthNewCapacityConstraint_rpt": [], + "LimitGrowthNewCapacityDeltaConstraint_rpt": [], + "LimitNewCapacityConstraint_rpt": [], + "LimitNewCapacityGroupConstraint_rpg": [], + "LimitNewCapacityGroupShareConstraint_rpgg": [], + "LimitNewCapacityShareConstraint_rptg": [], + "LimitResourceConstraint_rt": [], + "LimitSeasonalActivityConstraint_rpst": [], + "LimitStorageFractionConstraint_rpsdtv": [], + "LimitTechInputSplitAnnualConstraint_rpitv": [], + "LimitTechInputSplitAverageConstraint_rpitv": [], + "LimitTechInputSplitConstraint_rpsditv": [], + "LimitTechOutputSplitAnnualConstraint_rptvo": [], + "LimitTechOutputSplitAverageConstraint_rptvo": [], + "LimitTechOutputSplitConstraint_rpsdtvo": [ + [ + "utopia", + 2010, + "summer", + "night", + "SRE", + 1990, + "GSL", + "ge" + ], + [ + "utopia", + 2010, + "winter", + "night", + "SRE", + 1990, + "DSL", + "ge" + ], + [ + "utopia", + 2010, + "summer", + "night", + "SRE", + 2000, + "GSL", + "ge" + ], + [ + "utopia", + 2010, + "winter", + "night", + "SRE", + 2010, + "DSL", + "ge" + ], + [ + "utopia", + 2000, + "summer", + "day", + "SRE", + 1990, + "DSL", + "ge" + ], + [ + "utopia", + 2000, + "inter", + "night", + "SRE", + 2000, + "DSL", + "ge" + ], + [ + "utopia", + 2000, + "winter", + "night", + "SRE", + 2000, + "DSL", + "ge" + ], + [ + "utopia", + 2000, + "summer", + "night", + "SRE", + 1990, + "GSL", + "ge" + ], + [ + "utopia", + 2010, + "inter", + "day", + "SRE", + 2010, + "DSL", + "ge" + ], + [ + "utopia", + 2000, + "winter", + "night", + "SRE", + 1990, + "DSL", + "ge" + ], + [ + "utopia", + 1990, + "summer", + "day", + "SRE", + 1990, + "DSL", + "ge" + ], + [ + "utopia", + 2010, + "inter", + "night", + "SRE", + 2010, + "GSL", + "ge" + ], + [ + "utopia", + 2010, + "summer", + "night", + "SRE", + 2000, + "DSL", + "ge" + ], + [ + "utopia", + 2010, + "summer", + "day", + "SRE", + 1990, + "DSL", + "ge" + ], + [ + "utopia", + 1990, + "summer", + "night", + "SRE", + 1990, + "DSL", + "ge" + ], + [ + "utopia", + 2000, + "inter", + "day", + "SRE", + 1990, + "DSL", + "ge" + ], + [ + "utopia", + 2010, + "summer", + "day", + "SRE", + 2000, + "DSL", + "ge" + ], + [ + "utopia", + 2010, + "summer", + "night", + "SRE", + 2010, + "DSL", + "ge" + ], + [ + "utopia", + 2000, + "summer", + "day", + "SRE", + 2000, + "GSL", + "ge" + ], + [ + "utopia", + 2000, + "inter", + "night", + "SRE", + 1990, + "DSL", + "ge" + ], + [ + "utopia", + 2000, + "inter", + "day", + "SRE", + 2000, + "GSL", + "ge" + ], + [ + "utopia", + 2010, + "winter", + "day", + "SRE", + 1990, + "GSL", + "ge" + ], + [ + "utopia", + 2010, + "summer", + "night", + "SRE", + 1990, + "DSL", + "ge" + ], + [ + "utopia", + 2010, + "winter", + "day", + "SRE", + 2010, + "GSL", + "ge" + ], + [ + "utopia", + 2000, + "summer", + "night", + "SRE", + 1990, + "DSL", + "ge" + ], + [ + "utopia", + 2000, + "summer", + "day", + "SRE", + 2000, + "DSL", + "ge" + ], + [ + "utopia", + 1990, + "inter", + "night", + "SRE", + 1990, + "GSL", + "ge" + ], + [ + "utopia", + 1990, + "winter", + "day", + "SRE", + 1990, + "GSL", + "ge" + ], + [ + "utopia", + 2010, + "winter", + "day", + "SRE", + 2000, + "GSL", + "ge" + ], + [ + "utopia", + 2010, + "inter", + "day", + "SRE", + 1990, + "GSL", + "ge" + ], + [ + "utopia", + 2010, + "inter", + "night", + "SRE", + 2000, + "GSL", + "ge" + ], + [ + "utopia", + 2000, + "summer", + "night", + "SRE", + 2000, + "GSL", + "ge" + ], + [ + "utopia", + 2000, + "inter", + "day", + "SRE", + 2000, + "DSL", + "ge" + ], + [ + "utopia", + 2010, + "inter", + "day", + "SRE", + 2000, + "GSL", + "ge" + ], + [ + "utopia", + 2000, + "winter", + "day", + "SRE", + 1990, + "GSL", + "ge" + ], + [ + "utopia", + 1990, + "inter", + "day", + "SRE", + 1990, + "GSL", + "ge" + ], + [ + "utopia", + 2010, + "inter", + "day", + "SRE", + 1990, + "DSL", + "ge" + ], + [ + "utopia", + 2000, + "winter", + "day", + "SRE", + 2000, + "GSL", + "ge" + ], + [ + "utopia", + 2010, + "inter", + "night", + "SRE", + 2010, + "DSL", + "ge" + ], + [ + "utopia", + 2010, + "winter", + "day", + "SRE", + 1990, + "DSL", + "ge" + ], + [ + "utopia", + 2010, + "summer", + "day", + "SRE", + 2010, + "GSL", + "ge" + ], + [ + "utopia", + 2010, + "inter", + "night", + "SRE", + 1990, + "GSL", + "ge" + ], + [ + "utopia", + 1990, + "winter", + "night", + "SRE", + 1990, + "GSL", + "ge" + ], + [ + "utopia", + 2010, + "winter", + "night", + "SRE", + 2000, + "GSL", + "ge" + ], + [ + "utopia", + 2010, + "winter", + "night", + "SRE", + 1990, + "GSL", + "ge" + ], + [ + "utopia", + 2010, + "winter", + "night", + "SRE", + 2010, + "GSL", + "ge" + ], + [ + "utopia", + 2000, + "winter", + "day", + "SRE", + 2000, + "DSL", + "ge" + ], + [ + "utopia", + 2000, + "summer", + "day", + "SRE", + 1990, + "GSL", + "ge" + ], + [ + "utopia", + 1990, + "inter", + "day", + "SRE", + 1990, + "DSL", + "ge" + ], + [ + "utopia", + 2010, + "winter", + "day", + "SRE", + 2010, + "DSL", + "ge" + ], + [ + "utopia", + 1990, + "inter", + "night", + "SRE", + 1990, + "DSL", + "ge" + ], + [ + "utopia", + 2010, + "winter", + "day", + "SRE", + 2000, + "DSL", + "ge" + ], + [ + "utopia", + 2010, + "summer", + "day", + "SRE", + 2010, + "DSL", + "ge" + ], + [ + "utopia", + 2010, + "inter", + "night", + "SRE", + 1990, + "DSL", + "ge" + ], + [ + "utopia", + 2000, + "winter", + "night", + "SRE", + 2000, + "GSL", + "ge" + ], + [ + "utopia", + 2000, + "inter", + "day", + "SRE", + 1990, + "GSL", + "ge" + ], + [ + "utopia", + 1990, + "summer", + "day", + "SRE", + 1990, + "GSL", + "ge" + ], + [ + "utopia", + 2010, + "inter", + "night", + "SRE", + 2000, + "DSL", + "ge" + ], + [ + "utopia", + 2010, + "summer", + "day", + "SRE", + 2000, + "GSL", + "ge" + ], + [ + "utopia", + 2010, + "inter", + "day", + "SRE", + 2010, + "GSL", + "ge" + ], + [ + "utopia", + 2000, + "summer", + "night", + "SRE", + 2000, + "DSL", + "ge" + ], + [ + "utopia", + 2010, + "inter", + "day", + "SRE", + 2000, + "DSL", + "ge" + ], + [ + "utopia", + 2010, + "summer", + "day", + "SRE", + 1990, + "GSL", + "ge" + ], + [ + "utopia", + 1990, + "winter", + "night", + "SRE", + 1990, + "DSL", + "ge" + ], + [ + "utopia", + 2000, + "winter", + "day", + "SRE", + 1990, + "DSL", + "ge" + ], + [ + "utopia", + 2010, + "winter", + "night", + "SRE", + 2000, + "DSL", + "ge" + ], + [ + "utopia", + 2000, + "inter", + "night", + "SRE", + 2000, + "GSL", + "ge" + ], + [ + "utopia", + 1990, + "winter", + "day", + "SRE", + 1990, + "DSL", + "ge" + ], + [ + "utopia", + 2000, + "inter", + "night", + "SRE", + 1990, + "GSL", + "ge" + ], + [ + "utopia", + 2010, + "summer", + "night", + "SRE", + 2010, + "GSL", + "ge" + ], + [ + "utopia", + 2000, + "winter", + "night", + "SRE", + 1990, + "GSL", + "ge" + ], + [ + "utopia", + 1990, + "summer", + "night", + "SRE", + 1990, + "GSL", + "ge" + ] + ], + "LinkedEmissionsTechConstraint_rpsdtve": [], + "LoanLifetimeProcess_rtv": [ + [ + "utopia", + "IMPURN1", + 1990 + ], + [ + "utopia", + "TXD", + 1990 + ], + [ + "utopia", + "RHO", + 2010 + ], + [ + "utopia", + "E21", + 2000 + ], + [ + "utopia", + "IMPGSL1", + 1990 + ], + [ + "utopia", + "IMPDSL1", + 1990 + ], + [ + "utopia", + "TXE", + 1990 + ], + [ + "utopia", + "IMPHYD", + 1990 + ], + [ + "utopia", + "IMPOIL1", + 1990 + ], + [ + "utopia", + "E51", + 2010 + ], + [ + "utopia", + "E70", + 1990 + ], + [ + "utopia", + "RL1", + 1990 + ], + [ + "utopia", + "SRE", + 2000 + ], + [ + "utopia", + "TXG", + 2000 + ], + [ + "utopia", + "E31", + 2010 + ], + [ + "utopia", + "RHO", + 2000 + ], + [ + "utopia", + "RHE", + 2010 + ], + [ + "utopia", + "E21", + 1990 + ], + [ + "utopia", + "E01", + 2010 + ], + [ + "utopia", + "IMPHCO1", + 1990 + ], + [ + "utopia", + "TXD", + 2010 + ], + [ + "utopia", + "E51", + 2000 + ], + [ + "utopia", + "SRE", + 1990 + ], + [ + "utopia", + "TXG", + 1990 + ], + [ + "utopia", + "E31", + 2000 + ], + [ + "utopia", + "RHO", + 1990 + ], + [ + "utopia", + "TXE", + 2010 + ], + [ + "utopia", + "RHE", + 2000 + ], + [ + "utopia", + "E01", + 2000 + ], + [ + "utopia", + "E70", + 2010 + ], + [ + "utopia", + "RL1", + 2010 + ], + [ + "utopia", + "TXD", + 2000 + ], + [ + "utopia", + "E21", + 2010 + ], + [ + "utopia", + "IMPFEQ", + 1990 + ], + [ + "utopia", + "E51", + 1990 + ], + [ + "utopia", + "E31", + 1990 + ], + [ + "utopia", + "TXE", + 2000 + ], + [ + "utopia", + "RHE", + 1990 + ], + [ + "utopia", + "E01", + 1990 + ], + [ + "utopia", + "SRE", + 2010 + ], + [ + "utopia", + "TXG", + 2010 + ], + [ + "utopia", + "E70", + 2000 + ], + [ + "utopia", + "RL1", + 2000 + ] + ], + "ModelProcessLife_rptv": [ + [ + "utopia", + 2000, + "RL1", + 2000 + ], + [ + "utopia", + 2000, + "E21", + 2000 + ], + [ + "utopia", + 2000, + "TXE", + 1990 + ], + [ + "utopia", + 1990, + "RL1", + 1980 + ], + [ + "utopia", + 1990, + "RHO", + 1990 + ], + [ + "utopia", + 2000, + "IMPDSL1", + 1990 + ], + [ + "utopia", + 2010, + "IMPURN1", + 1990 + ], + [ + "utopia", + 1990, + "TXG", + 1980 + ], + [ + "utopia", + 2010, + "E01", + 1980 + ], + [ + "utopia", + 2010, + "E51", + 1980 + ], + [ + "utopia", + 2000, + "TXG", + 1990 + ], + [ + "utopia", + 2010, + "TXG", + 2000 + ], + [ + "utopia", + 1990, + "E70", + 1960 + ], + [ + "utopia", + 2010, + "E21", + 1990 + ], + [ + "utopia", + 1990, + "RHE", + 1990 + ], + [ + "utopia", + 2000, + "IMPHCO1", + 1990 + ], + [ + "utopia", + 2010, + "RHE", + 2010 + ], + [ + "utopia", + 2000, + "E31", + 2000 + ], + [ + "utopia", + 2010, + "SRE", + 1990 + ], + [ + "utopia", + 2000, + "RHE", + 1990 + ], + [ + "utopia", + 1990, + "E01", + 1980 + ], + [ + "utopia", + 2000, + "E70", + 1970 + ], + [ + "utopia", + 1990, + "E51", + 1980 + ], + [ + "utopia", + 2010, + "E01", + 2000 + ], + [ + "utopia", + 2010, + "E51", + 2000 + ], + [ + "utopia", + 2010, + "RHO", + 1990 + ], + [ + "utopia", + 2010, + "TXD", + 2000 + ], + [ + "utopia", + 2000, + "E70", + 2000 + ], + [ + "utopia", + 2000, + "IMPHYD", + 1990 + ], + [ + "utopia", + 2010, + "E31", + 1990 + ], + [ + "utopia", + 2000, + "SRE", + 2000 + ], + [ + "utopia", + 1990, + "TXD", + 1970 + ], + [ + "utopia", + 2010, + "TXE", + 2000 + ], + [ + "utopia", + 2000, + "TXD", + 1980 + ], + [ + "utopia", + 1990, + "IMPFEQ", + 1990 + ], + [ + "utopia", + 2000, + "IMPOIL1", + 1990 + ], + [ + "utopia", + 2010, + "IMPGSL1", + 1990 + ], + [ + "utopia", + 2000, + "RHO", + 2000 + ], + [ + "utopia", + 2010, + "RHO", + 2010 + ], + [ + "utopia", + 1990, + "E31", + 1990 + ], + [ + "utopia", + 1990, + "RHO", + 1980 + ], + [ + "utopia", + 2010, + "E70", + 1990 + ], + [ + "utopia", + 2010, + "E31", + 2010 + ], + [ + "utopia", + 1990, + "IMPGSL1", + 1990 + ], + [ + "utopia", + 1990, + "TXG", + 1970 + ], + [ + "utopia", + 2000, + "TXG", + 1980 + ], + [ + "utopia", + 1990, + "IMPDSL1", + 1990 + ], + [ + "utopia", + 2010, + "RHE", + 2000 + ], + [ + "utopia", + 2000, + "E31", + 1990 + ], + [ + "utopia", + 2010, + "E70", + 2010 + ], + [ + "utopia", + 2000, + "IMPURN1", + 1990 + ], + [ + "utopia", + 1990, + "E21", + 1990 + ], + [ + "utopia", + 2010, + "IMPFEQ", + 1990 + ], + [ + "utopia", + 1990, + "E70", + 1980 + ], + [ + "utopia", + 2010, + "E21", + 2010 + ], + [ + "utopia", + 1990, + "E01", + 1970 + ], + [ + "utopia", + 2000, + "E01", + 1980 + ], + [ + "utopia", + 2010, + "E01", + 1990 + ], + [ + "utopia", + 2000, + "E51", + 1980 + ], + [ + "utopia", + 2010, + "E51", + 1990 + ], + [ + "utopia", + 2000, + "TXG", + 2000 + ], + [ + "utopia", + 1990, + "SRE", + 1990 + ], + [ + "utopia", + 2010, + "SRE", + 2010 + ], + [ + "utopia", + 2000, + "E70", + 1990 + ], + [ + "utopia", + 2010, + "E31", + 1980 + ], + [ + "utopia", + 2000, + "E21", + 1990 + ], + [ + "utopia", + 2000, + "SRE", + 1990 + ], + [ + "utopia", + 2010, + "IMPOIL1", + 1990 + ], + [ + "utopia", + 2000, + "E01", + 2000 + ], + [ + "utopia", + 2010, + "IMPDSL1", + 1990 + ], + [ + "utopia", + 2000, + "E51", + 2000 + ], + [ + "utopia", + 1990, + "TXD", + 1990 + ], + [ + "utopia", + 2000, + "RHO", + 1990 + ], + [ + "utopia", + 2010, + "IMPHCO1", + 1990 + ], + [ + "utopia", + 2000, + "TXD", + 2000 + ], + [ + "utopia", + 2010, + "TXD", + 2010 + ], + [ + "utopia", + 1990, + "E31", + 1980 + ], + [ + "utopia", + 1990, + "RHO", + 1970 + ], + [ + "utopia", + 2010, + "E70", + 1980 + ], + [ + "utopia", + 2010, + "E31", + 2000 + ], + [ + "utopia", + 1990, + "TXE", + 1990 + ], + [ + "utopia", + 2000, + "TXE", + 2000 + ], + [ + "utopia", + 2010, + "TXE", + 2010 + ], + [ + "utopia", + 1990, + "IMPOIL1", + 1990 + ], + [ + "utopia", + 1990, + "RL1", + 1990 + ], + [ + "utopia", + 2010, + "RL1", + 2010 + ], + [ + "utopia", + 2000, + "IMPGSL1", + 1990 + ], + [ + "utopia", + 1990, + "IMPHCO1", + 1990 + ], + [ + "utopia", + 2010, + "RHE", + 1990 + ], + [ + "utopia", + 1990, + "TXG", + 1990 + ], + [ + "utopia", + 2010, + "E70", + 2000 + ], + [ + "utopia", + 2000, + "E31", + 1980 + ], + [ + "utopia", + 2010, + "TXG", + 2010 + ], + [ + "utopia", + 1990, + "E70", + 1970 + ], + [ + "utopia", + 2010, + "E21", + 2000 + ], + [ + "utopia", + 1990, + "E01", + 1960 + ], + [ + "utopia", + 2000, + "E01", + 1970 + ], + [ + "utopia", + 2010, + "IMPHYD", + 1990 + ], + [ + "utopia", + 2010, + "SRE", + 2000 + ], + [ + "utopia", + 1990, + "IMPURN1", + 1990 + ], + [ + "utopia", + 2000, + "RHE", + 2000 + ], + [ + "utopia", + 1990, + "E01", + 1990 + ], + [ + "utopia", + 2000, + "E70", + 1980 + ], + [ + "utopia", + 1990, + "E51", + 1990 + ], + [ + "utopia", + 2010, + "E01", + 2010 + ], + [ + "utopia", + 2010, + "E51", + 2010 + ], + [ + "utopia", + 1990, + "E70", + 1990 + ], + [ + "utopia", + 2010, + "RHO", + 2000 + ], + [ + "utopia", + 1990, + "IMPHYD", + 1990 + ], + [ + "utopia", + 2000, + "E01", + 1990 + ], + [ + "utopia", + 2000, + "E51", + 1990 + ], + [ + "utopia", + 2000, + "IMPFEQ", + 1990 + ], + [ + "utopia", + 1990, + "TXD", + 1980 + ], + [ + "utopia", + 2000, + "RHO", + 1980 + ], + [ + "utopia", + 2000, + "TXD", + 1990 + ] + ], + "NewCapacityVar_rtv": [ + [ + "utopia", + "TXD", + 1990 + ], + [ + "utopia", + "RHO", + 2010 + ], + [ + "utopia", + "E21", + 2000 + ], + [ + "utopia", + "TXG", + 1970 + ], + [ + "utopia", + "E51", + 1980 + ], + [ + "utopia", + "E70", + 1960 + ], + [ + "utopia", + "E31", + 1980 + ], + [ + "utopia", + "RHO", + 1970 + ], + [ + "utopia", + "TXE", + 1990 + ], + [ + "utopia", + "E01", + 1980 + ], + [ + "utopia", + "E51", + 2010 + ], + [ + "utopia", + "E70", + 1990 + ], + [ + "utopia", + "RL1", + 1990 + ], + [ + "utopia", + "TXD", + 1980 + ], + [ + "utopia", + "TXG", + 2000 + ], + [ + "utopia", + "SRE", + 2000 + ], + [ + "utopia", + "E31", + 2010 + ], + [ + "utopia", + "RHO", + 2000 + ], + [ + "utopia", + "RHE", + 2010 + ], + [ + "utopia", + "E21", + 1990 + ], + [ + "utopia", + "E01", + 2010 + ], + [ + "utopia", + "E01", + 1970 + ], + [ + "utopia", + "TXD", + 2010 + ], + [ + "utopia", + "E51", + 2000 + ], + [ + "utopia", + "E70", + 1980 + ], + [ + "utopia", + "SRE", + 1990 + ], + [ + "utopia", + "TXG", + 1990 + ], + [ + "utopia", + "RL1", + 1980 + ], + [ + "utopia", + "E31", + 2000 + ], + [ + "utopia", + "RHO", + 1990 + ], + [ + "utopia", + "TXD", + 1970 + ], + [ + "utopia", + "TXE", + 2010 + ], + [ + "utopia", + "RHE", + 2000 + ], + [ + "utopia", + "E01", + 2000 + ], + [ + "utopia", + "E70", + 2010 + ], + [ + "utopia", + "RL1", + 2010 + ], + [ + "utopia", + "E01", + 1960 + ], + [ + "utopia", + "TXD", + 2000 + ], + [ + "utopia", + "E21", + 2010 + ], + [ + "utopia", + "E70", + 1970 + ], + [ + "utopia", + "TXG", + 1980 + ], + [ + "utopia", + "E51", + 1990 + ], + [ + "utopia", + "E31", + 1990 + ], + [ + "utopia", + "RHO", + 1980 + ], + [ + "utopia", + "TXE", + 2000 + ], + [ + "utopia", + "RHE", + 1990 + ], + [ + "utopia", + "E01", + 1990 + ], + [ + "utopia", + "SRE", + 2010 + ], + [ + "utopia", + "TXG", + 2010 + ], + [ + "utopia", + "E70", + 2000 + ], + [ + "utopia", + "RL1", + 2000 + ] + ], + "ProcessLifeFrac_rptv": [ + [ + "utopia", + 2000, + "RL1", + 2000 + ], + [ + "utopia", + 2000, + "E21", + 2000 + ], + [ + "utopia", + 2000, + "TXE", + 1990 + ], + [ + "utopia", + 1990, + "RL1", + 1980 + ], + [ + "utopia", + 1990, + "RHO", + 1990 + ], + [ + "utopia", + 2000, + "IMPDSL1", + 1990 + ], + [ + "utopia", + 2010, + "IMPURN1", + 1990 + ], + [ + "utopia", + 1990, + "TXG", + 1980 + ], + [ + "utopia", + 2010, + "E01", + 1980 + ], + [ + "utopia", + 2010, + "E51", + 1980 + ], + [ + "utopia", + 2000, + "TXG", + 1990 + ], + [ + "utopia", + 2010, + "TXG", + 2000 + ], + [ + "utopia", + 1990, + "E70", + 1960 + ], + [ + "utopia", + 2010, + "E21", + 1990 + ], + [ + "utopia", + 1990, + "RHE", + 1990 + ], + [ + "utopia", + 2000, + "IMPHCO1", + 1990 + ], + [ + "utopia", + 2010, + "RHE", + 2010 + ], + [ + "utopia", + 2000, + "E31", + 2000 + ], + [ + "utopia", + 2010, + "SRE", + 1990 + ], + [ + "utopia", + 2000, + "RHE", + 1990 + ], + [ + "utopia", + 1990, + "E01", + 1980 + ], + [ + "utopia", + 2000, + "E70", + 1970 + ], + [ + "utopia", + 1990, + "E51", + 1980 + ], + [ + "utopia", + 2010, + "E01", + 2000 + ], + [ + "utopia", + 2010, + "E51", + 2000 + ], + [ + "utopia", + 2010, + "RHO", + 1990 + ], + [ + "utopia", + 2010, + "TXD", + 2000 + ], + [ + "utopia", + 2000, + "E70", + 2000 + ], + [ + "utopia", + 2000, + "IMPHYD", + 1990 + ], + [ + "utopia", + 2010, + "E31", + 1990 + ], + [ + "utopia", + 2000, + "SRE", + 2000 + ], + [ + "utopia", + 1990, + "TXD", + 1970 + ], + [ + "utopia", + 2010, + "TXE", + 2000 + ], + [ + "utopia", + 2000, + "TXD", + 1980 + ], + [ + "utopia", + 1990, + "IMPFEQ", + 1990 + ], + [ + "utopia", + 2000, + "IMPOIL1", + 1990 + ], + [ + "utopia", + 2010, + "IMPGSL1", + 1990 + ], + [ + "utopia", + 2000, + "RHO", + 2000 + ], + [ + "utopia", + 2010, + "RHO", + 2010 + ], + [ + "utopia", + 1990, + "E31", + 1990 + ], + [ + "utopia", + 1990, + "RHO", + 1980 + ], + [ + "utopia", + 2010, + "E70", + 1990 + ], + [ + "utopia", + 2010, + "E31", + 2010 + ], + [ + "utopia", + 1990, + "IMPGSL1", + 1990 + ], + [ + "utopia", + 1990, + "TXG", + 1970 + ], + [ + "utopia", + 2000, + "TXG", + 1980 + ], + [ + "utopia", + 1990, + "IMPDSL1", + 1990 + ], + [ + "utopia", + 2010, + "RHE", + 2000 + ], + [ + "utopia", + 2000, + "E31", + 1990 + ], + [ + "utopia", + 2010, + "E70", + 2010 + ], + [ + "utopia", + 2000, + "IMPURN1", + 1990 + ], + [ + "utopia", + 1990, + "E21", + 1990 + ], + [ + "utopia", + 2010, + "IMPFEQ", + 1990 + ], + [ + "utopia", + 1990, + "E70", + 1980 + ], + [ + "utopia", + 2010, + "E21", + 2010 + ], + [ + "utopia", + 1990, + "E01", + 1970 + ], + [ + "utopia", + 2000, + "E01", + 1980 + ], + [ + "utopia", + 2010, + "E01", + 1990 + ], + [ + "utopia", + 2000, + "E51", + 1980 + ], + [ + "utopia", + 2010, + "E51", + 1990 + ], + [ + "utopia", + 2000, + "TXG", + 2000 + ], + [ + "utopia", + 1990, + "SRE", + 1990 + ], + [ + "utopia", + 2010, + "SRE", + 2010 + ], + [ + "utopia", + 2000, + "E70", + 1990 + ], + [ + "utopia", + 2010, + "E31", + 1980 + ], + [ + "utopia", + 2000, + "E21", + 1990 + ], + [ + "utopia", + 2000, + "SRE", + 1990 + ], + [ + "utopia", + 2010, + "IMPOIL1", + 1990 + ], + [ + "utopia", + 2000, + "E01", + 2000 + ], + [ + "utopia", + 2010, + "IMPDSL1", + 1990 + ], + [ + "utopia", + 2000, + "E51", + 2000 + ], + [ + "utopia", + 1990, + "TXD", + 1990 + ], + [ + "utopia", + 2000, + "RHO", + 1990 + ], + [ + "utopia", + 2010, + "IMPHCO1", + 1990 + ], + [ + "utopia", + 2000, + "TXD", + 2000 + ], + [ + "utopia", + 2010, + "TXD", + 2010 + ], + [ + "utopia", + 1990, + "E31", + 1980 + ], + [ + "utopia", + 1990, + "RHO", + 1970 + ], + [ + "utopia", + 2010, + "E70", + 1980 + ], + [ + "utopia", + 2010, + "E31", + 2000 + ], + [ + "utopia", + 1990, + "TXE", + 1990 + ], + [ + "utopia", + 2000, + "TXE", + 2000 + ], + [ + "utopia", + 2010, + "TXE", + 2010 + ], + [ + "utopia", + 1990, + "IMPOIL1", + 1990 + ], + [ + "utopia", + 1990, + "RL1", + 1990 + ], + [ + "utopia", + 2010, + "RL1", + 2010 + ], + [ + "utopia", + 2000, + "IMPGSL1", + 1990 + ], + [ + "utopia", + 1990, + "IMPHCO1", + 1990 + ], + [ + "utopia", + 2010, + "RHE", + 1990 + ], + [ + "utopia", + 1990, + "TXG", + 1990 + ], + [ + "utopia", + 2010, + "E70", + 2000 + ], + [ + "utopia", + 2000, + "E31", + 1980 + ], + [ + "utopia", + 2010, + "TXG", + 2010 + ], + [ + "utopia", + 1990, + "E70", + 1970 + ], + [ + "utopia", + 2010, + "E21", + 2000 + ], + [ + "utopia", + 1990, + "E01", + 1960 + ], + [ + "utopia", + 2000, + "E01", + 1970 + ], + [ + "utopia", + 2010, + "IMPHYD", + 1990 + ], + [ + "utopia", + 2010, + "SRE", + 2000 + ], + [ + "utopia", + 1990, + "IMPURN1", + 1990 + ], + [ + "utopia", + 2000, + "RHE", + 2000 + ], + [ + "utopia", + 1990, + "E01", + 1990 + ], + [ + "utopia", + 2000, + "E70", + 1980 + ], + [ + "utopia", + 1990, + "E51", + 1990 + ], + [ + "utopia", + 2010, + "E01", + 2010 + ], + [ + "utopia", + 2010, + "E51", + 2010 + ], + [ + "utopia", + 1990, + "E70", + 1990 + ], + [ + "utopia", + 2010, + "RHO", + 2000 + ], + [ + "utopia", + 1990, + "IMPHYD", + 1990 + ], + [ + "utopia", + 2000, + "E01", + 1990 + ], + [ + "utopia", + 2000, + "E51", + 1990 + ], + [ + "utopia", + 2000, + "IMPFEQ", + 1990 + ], + [ + "utopia", + 1990, + "TXD", + 1980 + ], + [ + "utopia", + 2000, + "RHO", + 1980 + ], + [ + "utopia", + 2000, + "TXD", + 1990 + ] + ], + "RampDownConstraint_rpsdtv": [], + "RampUpConstraint_rpsdtv": [], + "RegionalExchangeCapacityConstraint_rrptv": [], + "RenewablePortfolioStandardConstraint_rpg": [], + "ReserveMargin_rpsd": [ + [ + "utopia", + 1990, + "inter", + "night" + ], + [ + "utopia", + 1990, + "summer", + "day" + ], + [ + "utopia", + 2000, + "winter", + "day" + ], + [ + "utopia", + 2000, + "summer", + "night" + ], + [ + "utopia", + 1990, + "inter", + "day" + ], + [ + "utopia", + 2010, + "winter", + "night" + ], + [ + "utopia", + 2000, + "inter", + "night" + ], + [ + "utopia", + 2000, + "summer", + "day" + ], + [ + "utopia", + 2010, + "winter", + "day" + ], + [ + "utopia", + 2010, + "summer", + "night" + ], + [ + "utopia", + 2000, + "inter", + "day" + ], + [ + "utopia", + 2010, + "inter", + "night" + ], + [ + "utopia", + 2010, + "summer", + "day" + ], + [ + "utopia", + 1990, + "winter", + "night" + ], + [ + "utopia", + 2010, + "inter", + "day" + ], + [ + "utopia", + 1990, + "winter", + "day" + ], + [ + "utopia", + 1990, + "summer", + "night" + ], + [ + "utopia", + 2000, + "winter", + "night" + ] + ], + "RetiredCapacityVar_rptv": [], + "StorageConstraints_rpsdtv": [ + [ + "utopia", + 1990, + "winter", + "day", + "E51", + 1980 + ], + [ + "utopia", + 1990, + "summer", + "day", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E51", + 2000 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E51", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E51", + 2000 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E51", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E51", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E51", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E51", + 2010 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E51", + 1980 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E51", + 2000 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E51", + 2000 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E51", + 1990 + ], + [ + "utopia", + 1990, + "summer", + "day", + "E51", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E51", + 1980 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E51", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E51", + 2000 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E51", + 2000 + ], + [ + "utopia", + 1990, + "inter", + "day", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E51", + 2010 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E51", + 2010 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E51", + 2000 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E51", + 1980 + ], + [ + "utopia", + 1990, + "winter", + "day", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E51", + 2010 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E51", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E51", + 2000 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E51", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E51", + 2010 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E51", + 1980 + ], + [ + "utopia", + 1990, + "inter", + "day", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E51", + 2000 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E51", + 1980 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E51", + 2010 + ] + ], + "StorageLevel_rpsdtv": [ + [ + "utopia", + 1990, + "winter", + "day", + "E51", + 1980 + ], + [ + "utopia", + 1990, + "summer", + "day", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E51", + 2000 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E51", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E51", + 2000 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E51", + 2000 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E51", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E51", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E51", + 2010 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E51", + 1980 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E51", + 2000 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E51", + 2000 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E51", + 1990 + ], + [ + "utopia", + 1990, + "summer", + "day", + "E51", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E51", + 1980 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E51", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E51", + 2000 + ], + [ + "utopia", + 1990, + "winter", + "night", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E51", + 2000 + ], + [ + "utopia", + 1990, + "inter", + "day", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E51", + 2010 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E51", + 2010 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "inter", + "day", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "night", + "E51", + 2000 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "winter", + "day", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E51", + 1980 + ], + [ + "utopia", + 1990, + "winter", + "day", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "inter", + "day", + "E51", + 2010 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E51", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "night", + "E51", + 2000 + ], + [ + "utopia", + 2010, + "winter", + "day", + "E51", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "day", + "E51", + 2010 + ], + [ + "utopia", + 1990, + "inter", + "night", + "E51", + 1980 + ], + [ + "utopia", + 1990, + "inter", + "day", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "inter", + "night", + "E51", + 2000 + ], + [ + "utopia", + 2000, + "summer", + "day", + "E51", + 1980 + ], + [ + "utopia", + 1990, + "summer", + "night", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "night", + "E51", + 2010 + ] + ], + "TimeNext": [], + "TwoGroupShareIndices": [], + "commodity_all": [ + "ethos", + "RH", + "TX", + "HYD", + "OIL", + "RL", + "HCO", + "ELC", + "co2", + "DSL", + "FEQ", + "URN", + "GSL", + "nox" + ], + "commodity_annual": [], + "commodity_carrier": [ + "ethos", + "RH", + "TX", + "HYD", + "OIL", + "RL", + "HCO", + "ELC", + "DSL", + "FEQ", + "URN", + "GSL" + ], + "commodity_demand": [ + "RL", + "RH", + "TX" + ], + "commodity_emissions": [ + "co2", + "nox" + ], + "commodity_flex": [], + "commodity_physical": [ + "ethos", + "HYD", + "OIL", + "HCO", + "ELC", + "DSL", + "FEQ", + "URN", + "GSL" + ], + "commodity_source": [ + "ethos" + ], + "commodity_waste": [], + "operator": [ + "ge", + "e", + "le" + ], + "regionalGlobalIndices": [ + "utopia" + ], + "regionalIndices": [ + "utopia" + ], + "regions": [ + "utopia" + ], + "tech_all": [ + "E21", + "IMPHCO1", + "IMPOIL1", + "E31", + "IMPHYD", + "TXE", + "E51", + "TXD", + "IMPGSL1", + "IMPFEQ", + "IMPDSL1", + "E01", + "RHE", + "IMPURN1", + "RL1", + "SRE", + "E70", + "RHO", + "TXG" + ], + "tech_annual": [], + "tech_baseload": [ + "E31", + "E01", + "E21" + ], + "tech_curtailment": [], + "tech_downramping": [], + "tech_exchange": [], + "tech_exist": [ + "E01", + "E70", + "E51", + "TXD", + "RHO", + "TXG", + "E31", + "RL1" + ], + "tech_flex": [], + "tech_group_members": [], + "tech_group_names": [], + "tech_production": [ + "E01", + "E21", + "E70", + "E51", + "TXE", + "TXD", + "RHO", + "TXG", + "RHE", + "E31", + "RL1", + "SRE" + ], + "tech_reserve": [], + "tech_resource": [ + "IMPDSL1", + "IMPHYD", + "IMPHCO1", + "IMPGSL1", + "IMPFEQ", + "IMPURN1", + "IMPOIL1" + ], + "tech_retirement": [], + "tech_storage": [ + "E51" + ], + "tech_uncap": [ + "IMPDSL1", + "IMPHYD", + "IMPHCO1", + "IMPGSL1", + "IMPFEQ", + "IMPURN1", + "IMPOIL1" + ], + "tech_upramping": [], + "tech_with_capacity": [ + "E01", + "E21", + "E70", + "E51", + "TXE", + "TXD", + "RHO", + "TXG", + "RHE", + "E31", + "RL1", + "SRE" + ], + "time_exist": [ + 1960, + 1970, + 1980 + ], + "time_future": [ + 2000, + 2010, + 2020, + 1990 + ], + "time_of_day": [ + "day", + "night" + ], + "time_optimize": [ + 2000, + 2010, + 1990 + ], + "time_season": [ + 2000, + 2010, + 1990 + ], + "time_season_all": [ + "summer", + "inter", + "winter" + ], + "vintage_all": [ + 1990, + 1960, + 2000, + 1970, + 2010, + 1980 + ], + "vintage_exist": [ + 1960, + 1970, + 1980 + ], + "vintage_optimize": [ + 2000, + 2010, + 1990 ] - ], - "MinTechOutputSplitAnnualConstraint_rptvo": [], - "MinTechOutputSplitAverageConstraint_rptvo": [], - "MaxTechInputSplitConstraint_rpsditv": [], - "MaxTechInputSplitAnnualConstraint_rpitv": [], - "MaxTechInputSplitAverageConstraint_rpitv": [], - "MaxTechOutputSplitConstraint_rpsdtvo": [], - "MaxTechOutputSplitAnnualConstraint_rptvo": [], - "MaxTechOutputSplitAverageConstraint_rptvo": [], - "MaxSeasonalActivityConstraint_rpst": [], - "MinSeasonalActivityConstraint_rpst": [], - "LinkedEmissionsTechConstraint_rpsdtve": [] } \ No newline at end of file From af82704b379243d136f57e4a7033d77c73098268 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 9 Jun 2025 17:15:23 -0400 Subject: [PATCH 092/587] Change LimitSeasonalActivity to LimitSeasonalCapacityFactor --- data_files/example_dbs/materials.sql | 1322 ++++++++---------- data_files/example_dbs/morris_utopia.sql | 1539 ++++++++++----------- data_files/example_dbs/stepped_demand.sql | 1139 +++++++-------- data_files/example_dbs/test_system.sql | 1456 ++++++++++--------- data_files/example_dbs/utopia.sql | 1498 ++++++++++---------- data_files/temoa_schema_v3_2.sql | 8 +- temoa/temoa_model/hybrid_loader.py | 12 +- temoa/temoa_model/temoa_model.py | 10 +- temoa/temoa_model/temoa_rules.py | 162 ++- tests/testing_data/emissions.sql | 8 +- tests/testing_data/materials.sql | 8 +- tests/testing_data/mediumville.sql | 8 +- tests/testing_data/simple_linked_tech.sql | 8 +- tests/testing_data/storageville.sql | 8 +- tests/testing_data/test_system.sql | 8 +- tests/testing_data/utopia.sql | 8 +- 16 files changed, 3443 insertions(+), 3759 deletions(-) diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index 9dc5b2e4e..b967a956a 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -84,15 +84,15 @@ CREATE TABLE CapacityFactorTech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'summer','morning','SOL_PV',0.3,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'autumn','morning','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'winter','morning','SOL_PV',0.1,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'spring','morning','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'summer','afternoon','SOL_PV',0.3,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'autumn','afternoon','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'winter','afternoon','SOL_PV',0.1,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'spring','afternoon','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'summer','evening','SOL_PV',0.1000000000000000055,NULL); INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'autumn','evening','SOL_PV',0.0,NULL); INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'winter','evening','SOL_PV',0.0,NULL); INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'spring','evening','SOL_PV',0.0,NULL); @@ -100,15 +100,15 @@ INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'summer','overnight','SOL_P INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'autumn','overnight','SOL_PV',0.0,NULL); INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'winter','overnight','SOL_PV',0.0,NULL); INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'summer','morning','SOL_PV',0.3,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'autumn','morning','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'winter','morning','SOL_PV',0.1,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'spring','morning','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'summer','afternoon','SOL_PV',0.3,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'autumn','afternoon','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'winter','afternoon','SOL_PV',0.1,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'spring','afternoon','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'summer','evening','SOL_PV',0.1000000000000000055,NULL); INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'autumn','evening','SOL_PV',0.0,NULL); INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'winter','evening','SOL_PV',0.0,NULL); INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'spring','evening','SOL_PV',0.0,NULL); @@ -116,15 +116,15 @@ INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'summer','overnight','SOL_P INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'autumn','overnight','SOL_PV',0.0,NULL); INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'winter','overnight','SOL_PV',0.0,NULL); INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'summer','morning','SOL_PV',0.3,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'autumn','morning','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'winter','morning','SOL_PV',0.1,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'spring','morning','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'summer','afternoon','SOL_PV',0.3,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'autumn','afternoon','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'winter','afternoon','SOL_PV',0.1,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'spring','afternoon','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'summer','evening','SOL_PV',0.1000000000000000055,NULL); INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'autumn','evening','SOL_PV',0.0,NULL); INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'winter','evening','SOL_PV',0.0,NULL); INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'spring','evening','SOL_PV',0.0,NULL); @@ -132,15 +132,15 @@ INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'summer','overnight','SOL_P INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'autumn','overnight','SOL_PV',0.0,NULL); INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'winter','overnight','SOL_PV',0.0,NULL); INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'summer','morning','SOL_PV',0.3,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'autumn','morning','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'winter','morning','SOL_PV',0.1,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'spring','morning','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'summer','afternoon','SOL_PV',0.3,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'autumn','afternoon','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'winter','afternoon','SOL_PV',0.1,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'spring','afternoon','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'summer','evening','SOL_PV',0.1000000000000000055,NULL); INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'autumn','evening','SOL_PV',0.0,NULL); INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'winter','evening','SOL_PV',0.0,NULL); INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'spring','evening','SOL_PV',0.0,NULL); @@ -148,15 +148,15 @@ INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'summer','overnight','SOL_P INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'autumn','overnight','SOL_PV',0.0,NULL); INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'winter','overnight','SOL_PV',0.0,NULL); INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'summer','morning','SOL_PV',0.3,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'autumn','morning','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'winter','morning','SOL_PV',0.1,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'spring','morning','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'summer','afternoon','SOL_PV',0.3,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'autumn','afternoon','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'winter','afternoon','SOL_PV',0.1,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'spring','afternoon','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'summer','evening','SOL_PV',0.1000000000000000055,NULL); INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'autumn','evening','SOL_PV',0.0,NULL); INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'winter','evening','SOL_PV',0.0,NULL); INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'spring','evening','SOL_PV',0.0,NULL); @@ -164,15 +164,15 @@ INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'summer','overnight','SOL_P INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'autumn','overnight','SOL_PV',0.0,NULL); INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'winter','overnight','SOL_PV',0.0,NULL); INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'summer','morning','SOL_PV',0.3,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'autumn','morning','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'winter','morning','SOL_PV',0.1,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'spring','morning','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'summer','afternoon','SOL_PV',0.3,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'autumn','afternoon','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'winter','afternoon','SOL_PV',0.1,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'spring','afternoon','SOL_PV',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'summer','evening','SOL_PV',0.1000000000000000055,NULL); INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'autumn','evening','SOL_PV',0.0,NULL); INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'winter','evening','SOL_PV',0.0,NULL); INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'spring','evening','SOL_PV',0.0,NULL); @@ -218,6 +218,9 @@ CREATE TABLE CommodityType PRIMARY KEY, description TEXT ); +INSERT INTO CommodityType VALUES('w','waste commodity'); +INSERT INTO CommodityType VALUES('wa','waste annual commodity'); +INSERT INTO CommodityType VALUES('wp','waste physical commodity'); INSERT INTO CommodityType VALUES('a','annual commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); @@ -238,65 +241,20 @@ CREATE TABLE ConstructionInput PRIMARY KEY (region, input_comm, tech, vintage) ); INSERT INTO ConstructionInput VALUES('RegionA','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionA','battery_lfp','CAR_PHEV',2000,0.1,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionA','battery_lfp','CAR_PHEV',2000,0.1000000000000000055,NULL,NULL); INSERT INTO ConstructionInput VALUES('RegionA','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionA','battery_lfp','CAR_PHEV',2010,0.1,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionA','battery_lfp','CAR_PHEV',2010,0.1000000000000000055,NULL,NULL); INSERT INTO ConstructionInput VALUES('RegionA','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionA','battery_lfp','CAR_PHEV',2020,0.1,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionA','battery_lfp','CAR_PHEV',2020,0.1000000000000000055,NULL,NULL); INSERT INTO ConstructionInput VALUES('RegionB','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionB','battery_lfp','CAR_PHEV',2000,0.1,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionB','battery_lfp','CAR_PHEV',2000,0.1000000000000000055,NULL,NULL); INSERT INTO ConstructionInput VALUES('RegionB','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionB','battery_lfp','CAR_PHEV',2010,0.1,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionB','battery_lfp','CAR_PHEV',2010,0.1000000000000000055,NULL,NULL); INSERT INTO ConstructionInput VALUES('RegionB','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionB','battery_lfp','CAR_PHEV',2020,0.1,NULL,NULL); -CREATE TABLE EndOfLifeOutput -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',1990,'used_batt_lfp',0.1,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2000,'used_batt_lfp',0.1,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2010,'used_batt_lfp',0.1,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',1990,'used_batt_lfp',0.1,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2000,'used_batt_lfp',0.1,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2010,'used_batt_lfp',0.1,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO ConstructionInput VALUES('RegionB','battery_lfp','CAR_PHEV',2020,0.1000000000000000055,NULL,NULL); CREATE TABLE CostEmission ( - region TEXT - REFERENCES Region (region), + region TEXT, period INTEGER REFERENCES TimePeriod (period), emis_comm TEXT NOT NULL @@ -463,112 +421,145 @@ CREATE TABLE DemandSpecificDistribution CHECK (dsd >= 0 AND dsd <= 1) ); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'summer','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','morning','heating',0.11999999999999999644,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','morning','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','morning','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','morning','heating',0.1600000000000000033,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'spring','morning','heating',0.0,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'summer','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','afternoon','heating',0.08,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','afternoon','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','afternoon','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','afternoon','heating',0.1199999999999999956,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'spring','afternoon','heating',0.0,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'summer','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','evening','heating',0.08,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','evening','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','evening','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','evening','heating',0.1600000000000000033,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'spring','evening','heating',0.0,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'summer','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','overnight','heating',0.11999999999999999644,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','overnight','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','overnight','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','overnight','heating',0.1600000000000000033,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'spring','overnight','heating',0.0,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'summer','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','morning','heating',0.11999999999999999644,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','morning','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','morning','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','morning','heating',0.1600000000000000033,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'spring','morning','heating',0.0,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'summer','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','afternoon','heating',0.08,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','afternoon','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','afternoon','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','afternoon','heating',0.1199999999999999956,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'spring','afternoon','heating',0.0,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'summer','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','evening','heating',0.08,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','evening','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','evening','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','evening','heating',0.1600000000000000033,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'spring','evening','heating',0.0,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'summer','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','overnight','heating',0.11999999999999999644,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','overnight','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','overnight','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','overnight','heating',0.1600000000000000033,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'spring','overnight','heating',0.0,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'summer','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','morning','heating',0.11999999999999999644,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','morning','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','morning','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','morning','heating',0.1600000000000000033,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'spring','morning','heating',0.0,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'summer','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','afternoon','heating',0.08,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','afternoon','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','afternoon','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','afternoon','heating',0.1199999999999999956,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'spring','afternoon','heating',0.0,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'summer','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','evening','heating',0.08,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','evening','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','evening','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','evening','heating',0.1600000000000000033,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'spring','evening','heating',0.0,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'summer','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','overnight','heating',0.11999999999999999644,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','overnight','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','overnight','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','overnight','heating',0.1600000000000000033,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'spring','overnight','heating',0.0,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'summer','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','morning','heating',0.11999999999999999644,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','morning','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','morning','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','morning','heating',0.1600000000000000033,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'spring','morning','heating',0.0,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'summer','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','afternoon','heating',0.08,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','afternoon','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','afternoon','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','afternoon','heating',0.1199999999999999956,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'spring','afternoon','heating',0.0,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'summer','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','evening','heating',0.08,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','evening','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','evening','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','evening','heating',0.1600000000000000033,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'spring','evening','heating',0.0,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'summer','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','overnight','heating',0.11999999999999999644,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','overnight','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','overnight','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','overnight','heating',0.1600000000000000033,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'spring','overnight','heating',0.0,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'summer','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','morning','heating',0.11999999999999999644,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','morning','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','morning','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','morning','heating',0.1600000000000000033,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'spring','morning','heating',0.0,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'summer','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','afternoon','heating',0.08,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','afternoon','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','afternoon','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','afternoon','heating',0.1199999999999999956,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'spring','afternoon','heating',0.0,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'summer','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','evening','heating',0.08,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','evening','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','evening','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','evening','heating',0.1600000000000000033,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'spring','evening','heating',0.0,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'summer','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','overnight','heating',0.11999999999999999644,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','overnight','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','overnight','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','overnight','heating',0.1600000000000000033,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'spring','overnight','heating',0.0,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'summer','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','morning','heating',0.11999999999999999644,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','morning','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','morning','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','morning','heating',0.1600000000000000033,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'spring','morning','heating',0.0,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'summer','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','afternoon','heating',0.08,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','afternoon','heating',0.11999999999999999644,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','afternoon','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','afternoon','heating',0.1199999999999999956,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'spring','afternoon','heating',0.0,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'summer','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','evening','heating',0.08,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','evening','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','evening','heating',0.08000000000000000166,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','evening','heating',0.1600000000000000033,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'spring','evening','heating',0.0,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'summer','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','overnight','heating',0.11999999999999999644,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','overnight','heating',0.16000000000000000888,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','overnight','heating',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','overnight','heating',0.1600000000000000033,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'spring','overnight','heating',0.0,NULL); -CREATE TABLE LoanRate +CREATE TABLE EndOfLifeOutput ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES TimePeriod (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',1990,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2000,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2010,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',1990,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2000,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2010,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); CREATE TABLE Efficiency ( region TEXT, @@ -590,17 +581,17 @@ INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_LI',2000,'lithium',1.0,N INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2,NULL); -INSERT INTO Efficiency VALUES('RegionA','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2,NULL); +INSERT INTO Efficiency VALUES('RegionA','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2000000000000000111,NULL); +INSERT INTO Efficiency VALUES('RegionA','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2000000000000000111,NULL); INSERT INTO Efficiency VALUES('RegionA','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); INSERT INTO Efficiency VALUES('RegionA','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); INSERT INTO Efficiency VALUES('RegionA','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); INSERT INTO Efficiency VALUES('RegionA','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); INSERT INTO Efficiency VALUES('RegionA','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','electricity','RECYCLE_NMC',2000,'battery_nmc',0.001,'Effectively zero'); -INSERT INTO Efficiency VALUES('RegionA','electricity','RECYCLE_LFP',2000,'battery_lfp',0.001,'Effectively zero'); -INSERT INTO Efficiency VALUES('RegionA','electricity','MANUFAC_NMC',2000,'battery_nmc',0.001,'Effectively zero'); -INSERT INTO Efficiency VALUES('RegionA','electricity','MANUFAC_LFP',2000,'battery_lfp',0.001,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionA','electricity','RECYCLE_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionA','electricity','RECYCLE_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionA','electricity','MANUFAC_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionA','electricity','MANUFAC_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); INSERT INTO Efficiency VALUES('RegionA','diesel','GEN_DSL',2000,'electricity',1.0,NULL); INSERT INTO Efficiency VALUES('RegionA','ethos','SOL_PV',2000,'electricity',1.0,NULL); INSERT INTO Efficiency VALUES('RegionA','electricity','BATT_GRID',2000,'electricity',1.0,NULL); @@ -628,17 +619,17 @@ INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_LI',2000,'lithium',1.0,N INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2,NULL); -INSERT INTO Efficiency VALUES('RegionB','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2,NULL); +INSERT INTO Efficiency VALUES('RegionB','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2000000000000000111,NULL); +INSERT INTO Efficiency VALUES('RegionB','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2000000000000000111,NULL); INSERT INTO Efficiency VALUES('RegionB','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); INSERT INTO Efficiency VALUES('RegionB','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); INSERT INTO Efficiency VALUES('RegionB','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); INSERT INTO Efficiency VALUES('RegionB','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); INSERT INTO Efficiency VALUES('RegionB','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','electricity','RECYCLE_NMC',2000,'battery_nmc',0.001,'Effectively zero'); -INSERT INTO Efficiency VALUES('RegionB','electricity','RECYCLE_LFP',2000,'battery_lfp',0.001,'Effectively zero'); -INSERT INTO Efficiency VALUES('RegionB','electricity','MANUFAC_NMC',2000,'battery_nmc',0.001,'Effectively zero'); -INSERT INTO Efficiency VALUES('RegionB','electricity','MANUFAC_LFP',2000,'battery_lfp',0.001,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionB','electricity','RECYCLE_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionB','electricity','RECYCLE_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionB','electricity','MANUFAC_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); +INSERT INTO Efficiency VALUES('RegionB','electricity','MANUFAC_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); INSERT INTO Efficiency VALUES('RegionB','diesel','GEN_DSL',2000,'electricity',1.0,NULL); INSERT INTO Efficiency VALUES('RegionB','ethos','SOL_PV',2000,'electricity',1.0,NULL); INSERT INTO Efficiency VALUES('RegionB','electricity','BATT_GRID',2000,'electricity',1.0,NULL); @@ -661,8 +652,8 @@ INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_BEV',2020,'passenger_ INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA-RegionB','electricity','ELEC_INTERTIE',2000,'electricity',0.9,NULL); -INSERT INTO Efficiency VALUES('RegionB-RegionA','electricity','ELEC_INTERTIE',2000,'electricity',0.9,NULL); +INSERT INTO Efficiency VALUES('RegionA-RegionB','electricity','ELEC_INTERTIE',2000,'electricity',0.9000000000000000222,NULL); +INSERT INTO Efficiency VALUES('RegionB-RegionA','electricity','ELEC_INTERTIE',2000,'electricity',0.9000000000000000222,NULL); CREATE TABLE EfficiencyVariable ( region TEXT, @@ -757,25 +748,6 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE GrowthRateMax -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE GrowthRateSeed -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - seed REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) -); CREATE TABLE LoanLifetimeTech ( region TEXT, @@ -785,6 +757,17 @@ CREATE TABLE LoanLifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); +CREATE TABLE LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); CREATE TABLE LifetimeProcess ( region TEXT, @@ -811,155 +794,494 @@ INSERT INTO LifetimeTech VALUES('RegionA','CAR_ICE',10.0,NULL); INSERT INTO LifetimeTech VALUES('RegionB','CAR_BEV',10.0,NULL); INSERT INTO LifetimeTech VALUES('RegionB','CAR_PHEV',10.0,NULL); INSERT INTO LifetimeTech VALUES('RegionB','CAR_ICE',10.0,NULL); -CREATE TABLE LinkedTech +CREATE TABLE Operator ( - primary_region TEXT, - primary_tech TEXT + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO Operator VALUES('e','equal to'); +INSERT INTO Operator VALUES('le','less than or equal to'); +INSERT INTO Operator VALUES('ge','greater than or equal to'); +CREATE TABLE LimitGrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - emis_comm TEXT - REFERENCES Commodity (name), - driven_tech TEXT + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxActivity +CREATE TABLE LimitGrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxCapacity +CREATE TABLE LimitDegrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxResource +CREATE TABLE LimitGrowthNewCapacityDelta ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_res REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthNewCapacityDelta +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitStorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE MinActivity +CREATE TABLE LimitActivity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_act REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech, operator) ); -CREATE TABLE MaxCapacityGroup +CREATE TABLE LimitActivityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - max_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) +); +CREATE TABLE LimitActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) +); +CREATE TABLE LimitAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, operator), + CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE MinCapacity +CREATE TABLE LimitCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech, operator) ); -CREATE TABLE MinCapacityGroup +CREATE TABLE LimitCapacityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) ); -CREATE TABLE OutputCurtailment +CREATE TABLE LimitCapacityShare ( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) ); -CREATE TABLE OutputNetCapacity +CREATE TABLE LimitNewCapacity ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE LimitNewCapacityGroup ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name, operator) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE LimitNewCapacityGroupShare ( - scenario TEXT, - region TEXT, - sector TEXT + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE LimitNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) +); +CREATE TABLE LimitResource +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitSeasonalCapacityFactor +( + region TEXT + REFERENCES Region (region), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) +); +CREATE TABLE LimitTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'diesel','CAR_PHEV','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'diesel','CAR_PHEV','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'diesel','CAR_PHEV','le',0.8000000000000000444,NULL); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'diesel','CAR_PHEV','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'diesel','CAR_PHEV','le',0.8000000000000000444,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'diesel','CAR_PHEV','le',0.8000000000000000444,NULL); +CREATE TABLE LimitTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), @@ -1025,7 +1347,7 @@ CREATE TABLE OutputStorageLevel period INTEGER REFERENCES TimePeriod (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1137,23 +1459,6 @@ CREATE TABLE StorageDuration ); INSERT INTO StorageDuration VALUES('RegionA','BATT_GRID',2.0,'2 hours energy storage'); INSERT INTO StorageDuration VALUES('RegionB','BATT_GRID',2.0,'2 hours energy storage'); -CREATE TABLE StorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage) -); CREATE TABLE TechnologyType ( label TEXT @@ -1164,164 +1469,6 @@ INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE MinTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MinTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2000,'lithium','MANUFAC_NMC',0.8,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2000,'nickel','MANUFAC_NMC',0.15,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2000,'cobalt','MANUFAC_NMC',0.04,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2000,'electricity','MANUFAC_NMC',0.01,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2000,'lithium','MANUFAC_LFP',0.8,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2000,'phosphorous','MANUFAC_LFP',0.19,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2000,'electricity','MANUFAC_LFP',0.01,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2010,'lithium','MANUFAC_NMC',0.8,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2010,'nickel','MANUFAC_NMC',0.15,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2010,'cobalt','MANUFAC_NMC',0.04,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2010,'electricity','MANUFAC_NMC',0.01,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2010,'lithium','MANUFAC_LFP',0.8,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2010,'phosphorous','MANUFAC_LFP',0.19,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2010,'electricity','MANUFAC_LFP',0.01,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2020,'lithium','MANUFAC_NMC',0.8,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2020,'nickel','MANUFAC_NMC',0.15,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2020,'cobalt','MANUFAC_NMC',0.04,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2020,'electricity','MANUFAC_NMC',0.01,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2020,'lithium','MANUFAC_LFP',0.8,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2020,'phosphorous','MANUFAC_LFP',0.19,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2020,'electricity','MANUFAC_LFP',0.01,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2000,'electricity','CAR_PHEV',0.2,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2000,'diesel','CAR_PHEV',0.8,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2010,'electricity','CAR_PHEV',0.2,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2010,'diesel','CAR_PHEV',0.8,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2020,'electricity','CAR_PHEV',0.2,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionA',2020,'diesel','CAR_PHEV',0.8,NULL); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2000,'lithium','MANUFAC_NMC',0.8,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2000,'nickel','MANUFAC_NMC',0.15,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2000,'cobalt','MANUFAC_NMC',0.04,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2000,'electricity','MANUFAC_NMC',0.01,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2000,'lithium','MANUFAC_LFP',0.8,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2000,'phosphorous','MANUFAC_LFP',0.19,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2000,'electricity','MANUFAC_LFP',0.01,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2010,'lithium','MANUFAC_NMC',0.8,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2010,'nickel','MANUFAC_NMC',0.15,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2010,'cobalt','MANUFAC_NMC',0.04,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2010,'electricity','MANUFAC_NMC',0.01,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2010,'lithium','MANUFAC_LFP',0.8,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2010,'phosphorous','MANUFAC_LFP',0.19,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2010,'electricity','MANUFAC_LFP',0.01,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2020,'lithium','MANUFAC_NMC',0.8,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2020,'nickel','MANUFAC_NMC',0.15,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2020,'cobalt','MANUFAC_NMC',0.04,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2020,'electricity','MANUFAC_NMC',0.01,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2020,'lithium','MANUFAC_LFP',0.8,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2020,'phosphorous','MANUFAC_LFP',0.19,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2020,'electricity','MANUFAC_LFP',0.01,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2000,'electricity','CAR_PHEV',0.2,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2000,'diesel','CAR_PHEV',0.8,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2010,'electricity','CAR_PHEV',0.2,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2010,'diesel','CAR_PHEV',0.8,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2020,'electricity','CAR_PHEV',0.2,''); -INSERT INTO MinTechInputSplitAnnual VALUES('RegionB',2020,'diesel','CAR_PHEV',0.8,NULL); -CREATE TABLE MinTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MinTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -1355,14 +1502,14 @@ INSERT INTO TimeSeason VALUES('autumn'); INSERT INTO TimeSeason VALUES('winter'); INSERT INTO TimeSeason VALUES('spring'); CREATE TABLE PeriodSeasons -( +( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, season TEXT REFERENCES TimeSeason (season), notes TEXT, - PRIMARY KEY (period, sequence) + PRIMARY KEY (period, sequence, season) ); INSERT INTO PeriodSeasons VALUES(2000,1,'summer',NULL); INSERT INTO PeriodSeasons VALUES(2000,2,'autumn',NULL); @@ -1384,188 +1531,6 @@ CREATE TABLE TimePeriodType ); INSERT INTO TimePeriodType VALUES('e','existing vintages'); INSERT INTO TimePeriodType VALUES('f','future'); -CREATE TABLE MaxActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE MaxNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MaxNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MaxNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE MinCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MinNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MinNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); -CREATE TABLE MaxNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1583,72 +1548,6 @@ CREATE TABLE OutputEmission emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE MinActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE EmissionLimit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE MaxActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "min_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); -CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "max_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); CREATE TABLE RPSRequirement ( region TEXT NOT NULL @@ -1708,9 +1607,10 @@ CREATE TABLE OutputCost ( scenario TEXT, region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), d_invest REAL, d_fixed REAL, d_var REAL, diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index 8a993d4a5..20cee7086 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -19,8 +19,8 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,''); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -73,24 +73,24 @@ CREATE TABLE CapacityFactorProcess PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','day','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','night','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','day','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','night','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','day','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','night','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2010,0.27560000000000002273,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2010,0.27560000000000002273,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2010,0.27560000000000002273,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2010,0.27560000000000002273,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2010,0.27560000000000002273,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2010,0.27560000000000002273,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2010,0.2756000000000000116,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2010,0.2756000000000000116,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2010,0.2756000000000000116,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2010,0.2756000000000000116,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2010,0.2756000000000000116,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2010,0.2756000000000000116,''); CREATE TABLE CapacityFactorTech ( region TEXT, @@ -107,96 +107,96 @@ CREATE TABLE CapacityFactorTech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E70',0.8000000000000000444,''); CREATE TABLE CapacityToActivity ( region TEXT, @@ -206,11 +206,11 @@ CREATE TABLE CapacityToActivity notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO CapacityToActivity VALUES('utopia','E01',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('utopia','E21',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('utopia','E31',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('utopia','E51',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('utopia','E70',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('utopia','E01',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('utopia','E21',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('utopia','E31',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('utopia','E51',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('utopia','E70',31.53999999999999915,''); INSERT INTO CapacityToActivity VALUES('utopia','RHE',1.0,''); INSERT INTO CapacityToActivity VALUES('utopia','RHO',1.0,''); INSERT INTO CapacityToActivity VALUES('utopia','RL1',1.0,''); @@ -246,15 +246,31 @@ CREATE TABLE CommodityType PRIMARY KEY, description TEXT ); +INSERT INTO CommodityType VALUES('w','waste commodity'); +INSERT INTO CommodityType VALUES('wa','waste annual commodity'); +INSERT INTO CommodityType VALUES('wp','waste physical commodity'); INSERT INTO CommodityType VALUES('a','annual commodity'); INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); +CREATE TABLE ConstructionInput +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); CREATE TABLE CostEmission ( - region TEXT - REFERENCES Region (region), + region TEXT, period INTEGER REFERENCES TimePeriod (period), emis_comm TEXT NOT NULL @@ -337,10 +353,10 @@ INSERT INTO CostFixed VALUES('utopia',2000,'RHO',2000,1.0,'',''); INSERT INTO CostFixed VALUES('utopia',2010,'RHO',1990,1.0,'',''); INSERT INTO CostFixed VALUES('utopia',2010,'RHO',2000,1.0,'',''); INSERT INTO CostFixed VALUES('utopia',2010,'RHO',2010,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1980,9.4600000000000008526,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1990,9.4600000000000008526,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'RL1',2000,9.4600000000000008526,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'RL1',2010,9.4600000000000008526,'',''); +INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1980,9.46000000000000086,'',''); +INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1990,9.46000000000000086,'',''); +INSERT INTO CostFixed VALUES('utopia',2000,'RL1',2000,9.46000000000000086,'',''); +INSERT INTO CostFixed VALUES('utopia',2010,'RL1',2010,9.46000000000000086,'',''); INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1970,52.0,'',''); INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1980,52.0,'',''); INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1990,52.0,'',''); @@ -362,18 +378,18 @@ INSERT INTO CostFixed VALUES('utopia',2000,'TXG',1990,48.0,'',''); INSERT INTO CostFixed VALUES('utopia',2000,'TXG',2000,48.0,'',''); INSERT INTO CostFixed VALUES('utopia',2010,'TXG',2000,48.0,'',''); INSERT INTO CostFixed VALUES('utopia',2010,'TXG',2010,48.0,'',''); -CREATE TABLE IF NOT EXISTS "CostInvest" +CREATE TABLE CostInvest ( - region TEXT, - tech TEXT - references Technology, - vintage INTEGER - references TimePeriod, - cost REAL, - units TEXT, - notes TEXT, + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, MMAnalysis TEXT, - primary key (region, tech, vintage) + PRIMARY KEY (region, tech, vintage) ); INSERT INTO CostInvest VALUES('utopia','E01',1990,2000.0,'','',NULL); INSERT INTO CostInvest VALUES('utopia','E01',2000,1300.0,'','',NULL); @@ -408,20 +424,20 @@ INSERT INTO CostInvest VALUES('utopia','TXE',2010,1500.0,'','',NULL); INSERT INTO CostInvest VALUES('utopia','TXG',1990,1044.0,'','',NULL); INSERT INTO CostInvest VALUES('utopia','TXG',2000,1044.0,'','',NULL); INSERT INTO CostInvest VALUES('utopia','TXG',2010,1044.0,'','',NULL); -CREATE TABLE IF NOT EXISTS "CostVariable" -( - region TEXT not null, - period INTEGER not null - references TimePeriod, - tech TEXT not null - references Technology, - vintage INTEGER not null - references TimePeriod, - cost REAL, - units TEXT, - notes TEXT, +CREATE TABLE CostVariable +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, MMAnalysis TEXT, - primary key (region, period, tech, vintage) + PRIMARY KEY (region, period, tech, vintage) ); INSERT INTO CostVariable VALUES('utopia',1990,'IMPDSL1',1990,10.0,'','','OIL_COST'); INSERT INTO CostVariable VALUES('utopia',2000,'IMPDSL1',1990,10.0,'','','OIL_COST'); @@ -438,36 +454,36 @@ INSERT INTO CostVariable VALUES('utopia',2010,'IMPOIL1',1990,8.0,'','','OIL_COST INSERT INTO CostVariable VALUES('utopia',1990,'IMPURN1',1990,2.0,'','',NULL); INSERT INTO CostVariable VALUES('utopia',2000,'IMPURN1',1990,2.0,'','',NULL); INSERT INTO CostVariable VALUES('utopia',2010,'IMPURN1',1990,2.0,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1960,0.3,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1970,0.3,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1980,0.3,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1990,0.3,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1970,0.3,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1980,0.3,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1990,0.3,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',2000,0.3,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',1980,0.3,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',1990,0.3,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',2000,0.3,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',2010,0.3,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1960,0.2999999999999999889,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1970,0.2999999999999999889,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1980,0.2999999999999999889,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1990,0.2999999999999999889,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',1970,0.2999999999999999889,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',1980,0.2999999999999999889,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',1990,0.2999999999999999889,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',2000,0.2999999999999999889,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',1980,0.2999999999999999889,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',1990,0.2999999999999999889,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',2000,0.2999999999999999889,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',2010,0.2999999999999999889,'','',NULL); INSERT INTO CostVariable VALUES('utopia',1990,'E21',1990,1.5,'','',NULL); INSERT INTO CostVariable VALUES('utopia',2000,'E21',1990,1.5,'','',NULL); INSERT INTO CostVariable VALUES('utopia',2010,'E21',1990,1.5,'','',NULL); INSERT INTO CostVariable VALUES('utopia',2000,'E21',2000,1.5,'','',NULL); INSERT INTO CostVariable VALUES('utopia',2010,'E21',2000,1.5,'','',NULL); INSERT INTO CostVariable VALUES('utopia',2010,'E21',2010,1.5,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1960,0.4,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1970,0.4,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1980,0.4,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1990,0.4,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1970,0.4,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1980,0.4,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1990,0.4,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',2000,0.4,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',1980,0.4,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',1990,0.4,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',2000,0.4,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',2010,0.4,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1960,0.4000000000000000222,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1970,0.4000000000000000222,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1980,0.4000000000000000222,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1990,0.4000000000000000222,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',1970,0.4000000000000000222,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',1980,0.4000000000000000222,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',1990,0.4000000000000000222,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',2000,0.4000000000000000222,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',1980,0.4000000000000000222,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',1990,0.4000000000000000222,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',2000,0.4000000000000000222,'','',NULL); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',2010,0.4000000000000000222,'','',NULL); INSERT INTO CostVariable VALUES('utopia',1990,'SRE',1990,10.0,'','',NULL); INSERT INTO CostVariable VALUES('utopia',2000,'SRE',1990,10.0,'','',NULL); INSERT INTO CostVariable VALUES('utopia',2000,'SRE',2000,10.0,'','',NULL); @@ -486,15 +502,15 @@ CREATE TABLE Demand notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO Demand VALUES('utopia',1990,'RH',25.200000000000000177,'',''); -INSERT INTO Demand VALUES('utopia',2000,'RH',37.799999999999998046,'',''); -INSERT INTO Demand VALUES('utopia',2010,'RH',56.699999999999999289,'',''); -INSERT INTO Demand VALUES('utopia',1990,'RL',5.5999999999999996447,'',''); -INSERT INTO Demand VALUES('utopia',2000,'RL',8.4000000000000003552,'',''); -INSERT INTO Demand VALUES('utopia',2010,'RL',12.600000000000000088,'',''); -INSERT INTO Demand VALUES('utopia',1990,'TX',5.2000000000000001776,'',''); -INSERT INTO Demand VALUES('utopia',2000,'TX',7.7999999999999998223,'',''); -INSERT INTO Demand VALUES('utopia',2010,'TX',11.69000000000000039,'',''); +INSERT INTO Demand VALUES('utopia',1990,'RH',25.19999999999999929,'',''); +INSERT INTO Demand VALUES('utopia',2000,'RH',37.79999999999999715,'',''); +INSERT INTO Demand VALUES('utopia',2010,'RH',56.69999999999999574,'',''); +INSERT INTO Demand VALUES('utopia',1990,'RL',5.599999999999999645,'',''); +INSERT INTO Demand VALUES('utopia',2000,'RL',8.400000000000000355,'',''); +INSERT INTO Demand VALUES('utopia',2010,'RL',12.59999999999999965,'',''); +INSERT INTO Demand VALUES('utopia',1990,'TX',5.200000000000000177,'',''); +INSERT INTO Demand VALUES('utopia',2000,'TX',7.799999999999999823,'',''); +INSERT INTO Demand VALUES('utopia',2010,'TX',11.68999999999999951,'',''); CREATE TABLE DemandSpecificDistribution ( region TEXT, @@ -511,63 +527,66 @@ CREATE TABLE DemandSpecificDistribution PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RH',0.06,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','day','RH',0.54669999999999996376,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RH',0.27329999999999992077,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RL',0.15,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RL',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','day','RL',0.15,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RH',0.05999999999999999778,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','day','RH',0.5466999999999999638,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RH',0.2732999999999999319,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RL',0.1499999999999999945,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RL',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','day','RL',0.1499999999999999945,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','night','RL',0.05000000000000000277,''); INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','day','RL',0.5,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RL',0.1,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RH',0.11999999999999999644,NULL); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RH',0.06,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','day','RH',0.54669999999999996376,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RH',0.27329999999999992077,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RL',0.15,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RL',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','day','RL',0.15,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RL',0.1000000000000000055,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RH',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RH',0.05999999999999999778,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','day','RH',0.5466999999999999638,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RH',0.2732999999999999319,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RL',0.1499999999999999945,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RL',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','day','RL',0.1499999999999999945,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','night','RL',0.05000000000000000277,''); INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','day','RL',0.5,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RL',0.1,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RH',0.11999999999999999644,NULL); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RH',0.06,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RH',0.54669999999999996376,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RH',0.27329999999999992077,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RL',0.15,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RL',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','day','RL',0.15,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RL',0.1000000000000000055,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RH',0.1199999999999999956,NULL); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RH',0.05999999999999999778,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RH',0.5466999999999999638,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RH',0.2732999999999999319,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RL',0.1499999999999999945,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RL',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','day','RL',0.1499999999999999945,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','night','RL',0.05000000000000000277,''); INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RL',0.5,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RL',0.1,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RH',0.11999999999999999644,NULL); -CREATE TABLE LoanRate +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RL',0.1000000000000000055,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RH',0.1199999999999999956,NULL); +CREATE TABLE EndOfLifeOutput ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES TimePeriod (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); -CREATE TABLE IF NOT EXISTS "Efficiency" +CREATE TABLE Efficiency ( region TEXT, input_comm TEXT - references Commodity, + REFERENCES Commodity (name), tech TEXT - references Technology, + REFERENCES Technology (tech), vintage INTEGER - references TimePeriod, + REFERENCES TimePeriod (period), output_comm TEXT - references Commodity, + REFERENCES Commodity (name), efficiency REAL, notes TEXT, - MMAnalysis TEXT, - primary key (region, input_comm, tech, vintage, output_comm), - check (efficiency > 0) + MMAnalysis TEXT, + PRIMARY KEY (region, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) ); INSERT INTO Efficiency VALUES('utopia','ethos','IMPDSL1',1990,'DSL',1.0,'',NULL); INSERT INTO Efficiency VALUES('utopia','ethos','IMPGSL1',1990,'GSL',1.0,'',NULL); @@ -576,40 +595,40 @@ INSERT INTO Efficiency VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,'',NULL) INSERT INTO Efficiency VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,'',NULL); INSERT INTO Efficiency VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,'',NULL); INSERT INTO Efficiency VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,'',NULL); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1960,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1970,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1980,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1990,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',2000,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',2010,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',1990,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2000,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2010,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','URN','E21',1990,'ELC',0.4,'# 1/2.5',NULL); -INSERT INTO Efficiency VALUES('utopia','URN','E21',2000,'ELC',0.4,'# 1/2.5',NULL); -INSERT INTO Efficiency VALUES('utopia','URN','E21',2010,'ELC',0.4,'# 1/2.5',NULL); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',1980,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',1990,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',2000,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',2010,'ELC',0.32000000000000001776,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1960,'ELC',0.29399999999999998578,'# 1/3.4',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1970,'ELC',0.29399999999999998578,'# 1/3.4',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1980,'ELC',0.29399999999999998578,'# 1/3.4',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1990,'ELC',0.29399999999999998578,'# 1/3.4',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',2000,'ELC',0.29399999999999998578,'# 1/3.4',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',2010,'ELC',0.29399999999999998578,'# 1/3.4',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',1980,'ELC',0.71999999999999992894,'# 1/1.3889',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',1990,'ELC',0.71999999999999992894,'# 1/1.3889',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',2000,'ELC',0.71999999999999992894,'# 1/1.3889',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',2010,'ELC',0.71999999999999992894,'# 1/1.3889',NULL); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1960,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1970,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1980,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1990,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',2000,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',2010,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','FEQ','E21',1990,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2000,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2010,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','URN','E21',1990,'ELC',0.4000000000000000222,'# 1/2.5',NULL); +INSERT INTO Efficiency VALUES('utopia','URN','E21',2000,'ELC',0.4000000000000000222,'# 1/2.5',NULL); +INSERT INTO Efficiency VALUES('utopia','URN','E21',2010,'ELC',0.4000000000000000222,'# 1/2.5',NULL); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',1980,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',1990,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',2000,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',2010,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1960,'ELC',0.2939999999999999836,'# 1/3.4',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1970,'ELC',0.2939999999999999836,'# 1/3.4',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1980,'ELC',0.2939999999999999836,'# 1/3.4',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1990,'ELC',0.2939999999999999836,'# 1/3.4',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',2000,'ELC',0.2939999999999999836,'# 1/3.4',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',2010,'ELC',0.2939999999999999836,'# 1/3.4',NULL); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',1980,'ELC',0.7199999999999999734,'# 1/1.3889',NULL); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',1990,'ELC',0.7199999999999999734,'# 1/1.3889',NULL); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',2000,'ELC',0.7199999999999999734,'# 1/1.3889',NULL); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',2010,'ELC',0.7199999999999999734,'# 1/1.3889',NULL); INSERT INTO Efficiency VALUES('utopia','ELC','RHE',1990,'RH',1.0,'# direct translation from DMD_EFF',NULL); INSERT INTO Efficiency VALUES('utopia','ELC','RHE',2000,'RH',1.0,'# direct translation from DMD_EFF',NULL); INSERT INTO Efficiency VALUES('utopia','ELC','RHE',2010,'RH',1.0,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1970,'RH',0.7,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1980,'RH',0.7,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1990,'RH',0.7,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2000,'RH',0.7,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2010,'RH',0.7,'# direct translation from DMD_EFF','Res_heating_2010_eff'); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1970,'RH',0.6999999999999999556,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1980,'RH',0.6999999999999999556,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1990,'RH',0.6999999999999999556,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2000,'RH',0.6999999999999999556,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2010,'RH',0.6999999999999999556,'# direct translation from DMD_EFF','Res_heating_2010_eff'); INSERT INTO Efficiency VALUES('utopia','ELC','RL1',1980,'RL',1.0,'# direct translation from DMD_EFF','Res_lighting_eff'); INSERT INTO Efficiency VALUES('utopia','ELC','RL1',1990,'RL',1.0,'# direct translation from DMD_EFF','Res_lighting_eff'); INSERT INTO Efficiency VALUES('utopia','ELC','RL1',2000,'RL',1.0,'# direct translation from DMD_EFF','Res_lighting_eff'); @@ -620,19 +639,19 @@ INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'# direct tran INSERT INTO Efficiency VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1970,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1980,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1990,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2000,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2010,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',1990,'TX',0.82699999999999995736,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2000,'TX',0.82699999999999995736,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2010,'TX',0.82699999999999995736,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1970,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1980,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1990,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2000,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2010,'TX',0.23100000000000000532,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','ELC','TXE',1990,'TX',0.8269999999999999574,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2000,'TX',0.8269999999999999574,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2010,'TX',0.8269999999999999574,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); CREATE TABLE EfficiencyVariable ( region TEXT, @@ -673,10 +692,10 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.075,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.075,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',0.088999999999999985789,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.075,'',''); +INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.07499999999999999723,'',''); +INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.07499999999999999723,'',''); +INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',0.0889999999999999819,'',''); +INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.07499999999999999723,'',''); INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1970,'TX',1.0,'',''); INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1980,'TX',1.0,'',''); INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1990,'TX',1.0,'',''); @@ -701,6 +720,20 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); +CREATE TABLE EmissionEndOfLife +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); CREATE TABLE ExistingCapacity ( region TEXT, @@ -713,20 +746,20 @@ CREATE TABLE ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1960,0.175,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1970,0.175,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1980,0.15,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E31',1980,0.1,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E01',1960,0.1749999999999999889,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E01',1970,0.1749999999999999889,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E01',1980,0.1499999999999999945,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E31',1980,0.1000000000000000055,'',''); INSERT INTO ExistingCapacity VALUES('utopia','E51',1980,0.5,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1960,0.05,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1970,0.05,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1980,0.2,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E70',1960,0.05000000000000000277,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E70',1970,0.05000000000000000277,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E70',1980,0.2000000000000000111,'',''); INSERT INTO ExistingCapacity VALUES('utopia','RHO',1970,12.5,'',''); INSERT INTO ExistingCapacity VALUES('utopia','RHO',1980,12.5,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','RL1',1980,5.5999999999999996447,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXD',1970,0.4,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXD',1980,0.2,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXG',1970,3.1000000000000000888,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','RL1',1980,5.599999999999999645,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','TXD',1970,0.4000000000000000222,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','TXD',1980,0.2000000000000000111,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','TXG',1970,3.100000000000000088,'',''); INSERT INTO ExistingCapacity VALUES('utopia','TXG',1980,1.5,'',''); CREATE TABLE TechGroup ( @@ -734,25 +767,6 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE GrowthRateMax -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE GrowthRateSeed -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - seed REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) -); CREATE TABLE LoanLifetimeTech ( region TEXT, @@ -774,6 +788,17 @@ INSERT INTO LoanLifetimeTech VALUES('utopia','SRE',50.0,''); INSERT INTO LoanLifetimeTech VALUES('utopia','TXD',15.0,''); INSERT INTO LoanLifetimeTech VALUES('utopia','TXE',15.0,''); INSERT INTO LoanLifetimeTech VALUES('utopia','TXG',15.0,''); +CREATE TABLE LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); CREATE TABLE LifetimeProcess ( region TEXT, @@ -818,172 +843,463 @@ INSERT INTO LifetimeTech VALUES('utopia','IMPOIL1',1000.0,''); INSERT INTO LifetimeTech VALUES('utopia','IMPURN1',1000.0,''); INSERT INTO LifetimeTech VALUES('utopia','IMPHYD',1000.0,''); INSERT INTO LifetimeTech VALUES('utopia','IMPFEQ',1000.0,''); -CREATE TABLE LinkedTech +CREATE TABLE Operator ( - primary_region TEXT, - primary_tech TEXT + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO Operator VALUES('e','equal to'); +INSERT INTO Operator VALUES('le','less than or equal to'); +INSERT INTO Operator VALUES('ge','greater than or equal to'); +CREATE TABLE LimitGrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - emis_comm TEXT - REFERENCES Commodity (name), - driven_tech TEXT + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxActivity +CREATE TABLE LimitGrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxCapacity +CREATE TABLE LimitDegrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -INSERT INTO MaxCapacity VALUES('utopia',1990,'E31',0.13000000000000000444,'',''); -INSERT INTO MaxCapacity VALUES('utopia',2000,'E31',0.17000000000000001776,'',''); -INSERT INTO MaxCapacity VALUES('utopia',2010,'E31',0.21000000000000000888,'',''); -INSERT INTO MaxCapacity VALUES('utopia',1990,'RHE',0.0,'',''); -INSERT INTO MaxCapacity VALUES('utopia',1990,'TXD',0.6,'',''); -INSERT INTO MaxCapacity VALUES('utopia',2000,'TXD',1.7599999999999999644,'',''); -INSERT INTO MaxCapacity VALUES('utopia',2010,'TXD',4.7599999999999997868,'',''); -CREATE TABLE MaxResource +CREATE TABLE LimitGrowthNewCapacityDelta ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_res REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthNewCapacityDelta +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitStorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE MinActivity +CREATE TABLE LimitActivity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_act REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech, operator) ); -CREATE TABLE MaxCapacityGroup +CREATE TABLE LimitActivityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - max_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) +); +CREATE TABLE LimitActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) +); +CREATE TABLE LimitAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, operator), + CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE MinCapacity +CREATE TABLE LimitCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) -); -INSERT INTO MinCapacity VALUES('utopia',1990,'E31',0.13000000000000000444,'',''); -INSERT INTO MinCapacity VALUES('utopia',2000,'E31',0.13000000000000000444,'',''); -INSERT INTO MinCapacity VALUES('utopia',2010,'E31',0.13000000000000000444,'',''); -INSERT INTO MinCapacity VALUES('utopia',1990,'SRE',0.1,'',''); -CREATE TABLE MinCapacityGroup + PRIMARY KEY (region, period, tech, operator) +); +INSERT INTO LimitCapacity VALUES('utopia',1990,'E31','ge',0.1300000000000000044,'',''); +INSERT INTO LimitCapacity VALUES('utopia',2000,'E31','ge',0.1300000000000000044,'',''); +INSERT INTO LimitCapacity VALUES('utopia',2010,'E31','ge',0.1300000000000000044,'',''); +INSERT INTO LimitCapacity VALUES('utopia',1990,'SRE','ge',0.1000000000000000055,'',''); +INSERT INTO LimitCapacity VALUES('utopia',1990,'E31','le',0.1300000000000000044,'',''); +INSERT INTO LimitCapacity VALUES('utopia',2000,'E31','le',0.1700000000000000122,'',''); +INSERT INTO LimitCapacity VALUES('utopia',2010,'E31','le',0.21000000000000002,'',''); +INSERT INTO LimitCapacity VALUES('utopia',1990,'RHE','le',0.0,'',''); +INSERT INTO LimitCapacity VALUES('utopia',1990,'TXD','le',0.5999999999999999778,'',''); +INSERT INTO LimitCapacity VALUES('utopia',2000,'TXD','le',1.760000000000000008,'',''); +INSERT INTO LimitCapacity VALUES('utopia',2010,'TXD','le',4.759999999999999787,'',''); +CREATE TABLE LimitCapacityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) ); -CREATE TABLE OutputCurtailment +CREATE TABLE LimitCapacityShare ( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) ); -CREATE TABLE OutputNetCapacity +CREATE TABLE LimitNewCapacity ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE LimitNewCapacityGroup ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name, operator) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE LimitNewCapacityGroupShare ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE LimitNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) +); +CREATE TABLE LimitResource +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitSeasonalCapacityFactor +( + region TEXT + REFERENCES Region (region), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region,period,season,tech, operator) +); +CREATE TABLE LimitTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +INSERT INTO LimitTechOutputSplit VALUES('utopia',1990,'SRE','DSL','ge',0.6999999999999999556,''); +INSERT INTO LimitTechOutputSplit VALUES('utopia',2000,'SRE','DSL','ge',0.6999999999999999556,''); +INSERT INTO LimitTechOutputSplit VALUES('utopia',2010,'SRE','DSL','ge',0.6999999999999999556,''); +INSERT INTO LimitTechOutputSplit VALUES('utopia',1990,'SRE','GSL','ge',0.2999999999999999889,''); +INSERT INTO LimitTechOutputSplit VALUES('utopia',2000,'SRE','GSL','ge',0.2999999999999999889,''); +INSERT INTO LimitTechOutputSplit VALUES('utopia',2010,'SRE','GSL','ge',0.2999999999999999889,''); +CREATE TABLE LimitTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), capacity REAL, PRIMARY KEY (region, scenario, period, tech, vintage) @@ -1043,7 +1359,7 @@ CREATE TABLE OutputStorageLevel period INTEGER REFERENCES TimePeriod (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1096,24 +1412,24 @@ CREATE TABLE TimeSegmentFraction PRIMARY KEY (period, season, tod), CHECK (segfrac >= 0 AND segfrac <= 1) ); -INSERT INTO TimeSegmentFraction VALUES(1990,'inter','day',0.16669999999999998152,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(1990,'inter','night',0.08330000000000000071,'# I-N'); -INSERT INTO TimeSegmentFraction VALUES(1990,'summer','day',0.16669999999999998152,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(1990,'summer','night',0.08330000000000000071,'# S-N'); -INSERT INTO TimeSegmentFraction VALUES(1990,'winter','day',0.33329999999999997406,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(1990,'winter','night',0.16669999999999998152,'# W-N'); -INSERT INTO TimeSegmentFraction VALUES(2000,'inter','day',0.16669999999999998152,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2000,'inter','night',0.08330000000000000071,'# I-N'); -INSERT INTO TimeSegmentFraction VALUES(2000,'summer','day',0.16669999999999998152,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2000,'summer','night',0.08330000000000000071,'# S-N'); -INSERT INTO TimeSegmentFraction VALUES(2000,'winter','day',0.33329999999999997406,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2000,'winter','night',0.16669999999999998152,'# W-N'); -INSERT INTO TimeSegmentFraction VALUES(2010,'inter','day',0.16669999999999998152,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'inter','night',0.08330000000000000071,'# I-N'); -INSERT INTO TimeSegmentFraction VALUES(2010,'summer','day',0.16669999999999998152,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'summer','night',0.08330000000000000071,'# S-N'); -INSERT INTO TimeSegmentFraction VALUES(2010,'winter','day',0.33329999999999997406,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'winter','night',0.16669999999999998152,'# W-N'); +INSERT INTO TimeSegmentFraction VALUES(1990,'inter','day',0.166699999999999987,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(1990,'inter','night',0.08329999999999999905,'# I-N'); +INSERT INTO TimeSegmentFraction VALUES(1990,'summer','day',0.166699999999999987,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(1990,'summer','night',0.08329999999999999905,'# S-N'); +INSERT INTO TimeSegmentFraction VALUES(1990,'winter','day',0.3332999999999999852,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(1990,'winter','night',0.166699999999999987,'# W-N'); +INSERT INTO TimeSegmentFraction VALUES(2000,'inter','day',0.166699999999999987,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'inter','night',0.08329999999999999905,'# I-N'); +INSERT INTO TimeSegmentFraction VALUES(2000,'summer','day',0.166699999999999987,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'summer','night',0.08329999999999999905,'# S-N'); +INSERT INTO TimeSegmentFraction VALUES(2000,'winter','day',0.3332999999999999852,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'winter','night',0.166699999999999987,'# W-N'); +INSERT INTO TimeSegmentFraction VALUES(2010,'inter','day',0.166699999999999987,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'inter','night',0.08329999999999999905,'# I-N'); +INSERT INTO TimeSegmentFraction VALUES(2010,'summer','day',0.166699999999999987,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'summer','night',0.08329999999999999905,'# S-N'); +INSERT INTO TimeSegmentFraction VALUES(2010,'winter','day',0.3332999999999999852,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'winter','night',0.166699999999999987,'# W-N'); CREATE TABLE StorageDuration ( region TEXT, @@ -1122,23 +1438,6 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE StorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage) -); CREATE TABLE TechnologyType ( label TEXT @@ -1149,116 +1448,6 @@ INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE MinTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MinTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MinTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -INSERT INTO MinTechOutputSplit VALUES('utopia',1990,'SRE','DSL',0.7,''); -INSERT INTO MinTechOutputSplit VALUES('utopia',2000,'SRE','DSL',0.7,''); -INSERT INTO MinTechOutputSplit VALUES('utopia',2010,'SRE','DSL',0.7,''); -INSERT INTO MinTechOutputSplit VALUES('utopia',1990,'SRE','GSL',0.3,''); -INSERT INTO MinTechOutputSplit VALUES('utopia',2000,'SRE','GSL',0.3,''); -INSERT INTO MinTechOutputSplit VALUES('utopia',2010,'SRE','GSL',0.3,''); -CREATE TABLE MinTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -1291,14 +1480,14 @@ INSERT INTO TimeSeason VALUES('inter'); INSERT INTO TimeSeason VALUES('summer'); INSERT INTO TimeSeason VALUES('winter'); CREATE TABLE PeriodSeasons -( +( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, season TEXT REFERENCES TimeSeason (season), notes TEXT, - PRIMARY KEY (period, sequence) + PRIMARY KEY (period, sequence, season) ); INSERT INTO PeriodSeasons VALUES(1990,2,'summer',NULL); INSERT INTO PeriodSeasons VALUES(1990,3,'winter',NULL); @@ -1317,188 +1506,6 @@ CREATE TABLE TimePeriodType ); INSERT INTO TimePeriodType VALUES('e','existing vintages'); INSERT INTO TimePeriodType VALUES('f','future'); -CREATE TABLE MaxActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE MaxNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MaxNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MaxNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE MinCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MinNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MinNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); -CREATE TABLE MaxNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1516,72 +1523,6 @@ CREATE TABLE OutputEmission emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE MinActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE EmissionLimit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE MaxActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "min_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); -CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "max_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); CREATE TABLE RPSRequirement ( region TEXT NOT NULL @@ -1640,7 +1581,7 @@ INSERT INTO Technology VALUES('TXG','p','transport','petroleum','',0,0,0,1,1,0,0 CREATE TABLE OutputCost ( scenario TEXT, - region TEXT REFERENCES Region (region), + region TEXT, sector TEXT REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index 2172b7234..1b404bd62 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -19,8 +19,8 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,''); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -184,15 +184,31 @@ CREATE TABLE CommodityType PRIMARY KEY, description TEXT ); +INSERT INTO CommodityType VALUES('w','waste commodity'); +INSERT INTO CommodityType VALUES('wa','waste annual commodity'); +INSERT INTO CommodityType VALUES('wp','waste physical commodity'); INSERT INTO CommodityType VALUES('a','annual commodity'); INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); +CREATE TABLE ConstructionInput +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); CREATE TABLE CostEmission ( - region TEXT - REFERENCES Region (region), + region TEXT, period INTEGER REFERENCES TimePeriod (period), emis_comm TEXT NOT NULL @@ -346,49 +362,52 @@ CREATE TABLE DemandSpecificDistribution PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2000,'inter','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2000,'summer','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2000,'winter','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2005,'inter','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2005,'summer','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2005,'winter','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2010,'inter','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2010,'summer','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2010,'winter','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2015,'inter','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2015,'summer','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2015,'winter','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2020,'inter','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2020,'summer','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2020,'winter','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'inter','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'summer','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'winter','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2030,'inter','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2030,'summer','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2030,'winter','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2035,'inter','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2035,'summer','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2035,'winter','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2040,'inter','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2040,'summer','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2040,'winter','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2045,'inter','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2045,'summer','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2045,'winter','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2050,'inter','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2050,'summer','day','RL',0.33329999999999997406,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2050,'winter','day','RL',0.33329999999999997406,''); -CREATE TABLE LoanRate +INSERT INTO DemandSpecificDistribution VALUES('electricville',2000,'inter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2000,'summer','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2000,'winter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2005,'inter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2005,'summer','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2005,'winter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2010,'inter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2010,'summer','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2010,'winter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2015,'inter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2015,'summer','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2015,'winter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2020,'inter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2020,'summer','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2020,'winter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'inter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'summer','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'winter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2030,'inter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2030,'summer','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2030,'winter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2035,'inter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2035,'summer','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2035,'winter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2040,'inter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2040,'summer','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2040,'winter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2045,'inter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2045,'summer','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2045,'winter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2050,'inter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2050,'summer','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville',2050,'winter','day','RL',0.3332999999999999852,''); +CREATE TABLE EndOfLifeOutput ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES TimePeriod (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); CREATE TABLE Efficiency ( @@ -452,9 +471,9 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('electricville','co2','HYD','EH',1995,'ELC',0.05,'',''); -INSERT INTO EmissionActivity VALUES('electricville','co2','HYD','EF',2010,'ELC',0.01,'',''); -INSERT INTO EmissionActivity VALUES('electricville','co2','HYD','EH',2000,'ELC',0.02,NULL,NULL); +INSERT INTO EmissionActivity VALUES('electricville','co2','HYD','EH',1995,'ELC',0.05000000000000000277,'',''); +INSERT INTO EmissionActivity VALUES('electricville','co2','HYD','EF',2010,'ELC',0.0100000000000000002,'',''); +INSERT INTO EmissionActivity VALUES('electricville','co2','HYD','EH',2000,'ELC',0.02000000000000000041,NULL,NULL); CREATE TABLE EmissionEmbodied ( region TEXT, @@ -469,6 +488,20 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); +CREATE TABLE EmissionEndOfLife +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); CREATE TABLE ExistingCapacity ( region TEXT, @@ -490,25 +523,6 @@ CREATE TABLE TechGroup ); INSERT INTO TechGroup VALUES('RPS_global',''); INSERT INTO TechGroup VALUES('RPS_common',''); -CREATE TABLE GrowthRateMax -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE GrowthRateSeed -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - seed REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) -); CREATE TABLE LoanLifetimeTech ( region TEXT, @@ -519,6 +533,17 @@ CREATE TABLE LoanLifetimeTech PRIMARY KEY (region, tech) ); INSERT INTO LoanLifetimeTech VALUES('electricville','EF',50.0,''); +CREATE TABLE LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); CREATE TABLE LifetimeProcess ( region TEXT, @@ -544,189 +569,475 @@ INSERT INTO LifetimeTech VALUES('electricville','EH',100.0,''); INSERT INTO LifetimeTech VALUES('electricville','EF',100.0,''); INSERT INTO LifetimeTech VALUES('electricville','bulbs',100.0,'super LED!'); INSERT INTO LifetimeTech VALUES('electricville','well',100.0,NULL); -CREATE TABLE LinkedTech +CREATE TABLE Operator ( - primary_region TEXT, - primary_tech TEXT + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO Operator VALUES('e','equal to'); +INSERT INTO Operator VALUES('le','less than or equal to'); +INSERT INTO Operator VALUES('ge','greater than or equal to'); +CREATE TABLE LimitGrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - emis_comm TEXT - REFERENCES Commodity (name), - driven_tech TEXT + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxActivity +CREATE TABLE LimitGrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxCapacity +CREATE TABLE LimitDegrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -INSERT INTO MaxCapacity VALUES('electricville',2000,'EH',5.0,'',''); -INSERT INTO MaxCapacity VALUES('electricville',2005,'EH',5.0,'',''); -INSERT INTO MaxCapacity VALUES('electricville',2010,'EH',5.0,'',''); -INSERT INTO MaxCapacity VALUES('electricville',2015,'EH',5.0,'',''); -INSERT INTO MaxCapacity VALUES('electricville',2020,'EH',5.0,'',''); -INSERT INTO MaxCapacity VALUES('electricville',2025,'EH',5.0,'',''); -INSERT INTO MaxCapacity VALUES('electricville',2030,'EH',5.0,'',''); -CREATE TABLE MaxResource +CREATE TABLE LimitGrowthNewCapacityDelta ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_res REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthNewCapacityDelta +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitStorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE MinActivity +CREATE TABLE LimitActivity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_act REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech, operator) ); -CREATE TABLE MaxCapacityGroup +CREATE TABLE LimitActivityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - max_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) +); +CREATE TABLE LimitActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) +); +CREATE TABLE LimitAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + source TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator), + CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE MinCapacity +CREATE TABLE LimitCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) -); -INSERT INTO MinCapacity VALUES('electricville',2000,'EH',0.2,'',''); -INSERT INTO MinCapacity VALUES('electricville',2005,'EH',0.2,'',''); -INSERT INTO MinCapacity VALUES('electricville',2010,'EH',0.2,'',''); -INSERT INTO MinCapacity VALUES('electricville',2015,'EH',0.2,'',''); -CREATE TABLE MinCapacityGroup + PRIMARY KEY (region, period, tech, operator) +); +INSERT INTO LimitCapacity VALUES('electricville',2000,'EH','ge',0.2000000000000000111,'',''); +INSERT INTO LimitCapacity VALUES('electricville',2005,'EH','ge',0.2000000000000000111,'',''); +INSERT INTO LimitCapacity VALUES('electricville',2010,'EH','ge',0.2000000000000000111,'',''); +INSERT INTO LimitCapacity VALUES('electricville',2015,'EH','ge',0.2000000000000000111,'',''); +INSERT INTO LimitCapacity VALUES('electricville',2000,'EH','le',5.0,'',''); +INSERT INTO LimitCapacity VALUES('electricville',2005,'EH','le',5.0,'',''); +INSERT INTO LimitCapacity VALUES('electricville',2010,'EH','le',5.0,'',''); +INSERT INTO LimitCapacity VALUES('electricville',2015,'EH','le',5.0,'',''); +INSERT INTO LimitCapacity VALUES('electricville',2020,'EH','le',5.0,'',''); +INSERT INTO LimitCapacity VALUES('electricville',2025,'EH','le',5.0,'',''); +INSERT INTO LimitCapacity VALUES('electricville',2030,'EH','le',5.0,'',''); +CREATE TABLE LimitCapacityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) ); -CREATE TABLE OutputCurtailment +CREATE TABLE LimitCapacityShare ( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) ); -CREATE TABLE OutputNetCapacity +CREATE TABLE LimitNewCapacity ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator) +); +CREATE TABLE LimitNewCapacityGroup +( + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name, operator) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE LimitNewCapacityGroupShare ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE LimitNewCapacityShare ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) ); -CREATE TABLE OutputFlowIn +CREATE TABLE LimitResource ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitSeasonalCapacityFactor +( + region TEXT + REFERENCES Region (region), + period INTEGER REFERENCES TimePeriod (period), - season TEXT + season TEXT REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region,period,season,tech, operator) +); +CREATE TABLE LimitTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT REFERENCES Commodity (name), tech TEXT REFERENCES Technology (tech), @@ -769,7 +1080,7 @@ CREATE TABLE OutputStorageLevel period INTEGER REFERENCES TimePeriod (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -822,39 +1133,39 @@ CREATE TABLE TimeSegmentFraction PRIMARY KEY (period, season, tod), CHECK (segfrac >= 0 AND segfrac <= 1) ); -INSERT INTO TimeSegmentFraction VALUES(2000,'inter','day',0.33329999999999997406,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2000,'summer','day',0.33329999999999997406,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2000,'winter','day',0.33329999999999997406,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2005,'inter','day',0.33329999999999997406,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2005,'summer','day',0.33329999999999997406,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2005,'winter','day',0.33329999999999997406,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'inter','day',0.33329999999999997406,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'summer','day',0.33329999999999997406,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'winter','day',0.33329999999999997406,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2015,'inter','day',0.33329999999999997406,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2015,'summer','day',0.33329999999999997406,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2015,'winter','day',0.33329999999999997406,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2020,'inter','day',0.33329999999999997406,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2020,'summer','day',0.33329999999999997406,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2020,'winter','day',0.33329999999999997406,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2025,'inter','day',0.33329999999999997406,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2025,'summer','day',0.33329999999999997406,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2025,'winter','day',0.33329999999999997406,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2030,'inter','day',0.33329999999999997406,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2030,'summer','day',0.33329999999999997406,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2030,'winter','day',0.33329999999999997406,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2035,'inter','day',0.33329999999999997406,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2035,'summer','day',0.33329999999999997406,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2035,'winter','day',0.33329999999999997406,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2040,'inter','day',0.33329999999999997406,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2040,'summer','day',0.33329999999999997406,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2040,'winter','day',0.33329999999999997406,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2045,'inter','day',0.33329999999999997406,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2045,'summer','day',0.33329999999999997406,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2045,'winter','day',0.33329999999999997406,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2050,'inter','day',0.33329999999999997406,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2050,'summer','day',0.33329999999999997406,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2050,'winter','day',0.33329999999999997406,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'inter','day',0.3332999999999999852,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'summer','day',0.3332999999999999852,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'winter','day',0.3332999999999999852,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2005,'inter','day',0.3332999999999999852,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2005,'summer','day',0.3332999999999999852,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2005,'winter','day',0.3332999999999999852,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'inter','day',0.3332999999999999852,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'summer','day',0.3332999999999999852,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'winter','day',0.3332999999999999852,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2015,'inter','day',0.3332999999999999852,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2015,'summer','day',0.3332999999999999852,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2015,'winter','day',0.3332999999999999852,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2020,'inter','day',0.3332999999999999852,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2020,'summer','day',0.3332999999999999852,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2020,'winter','day',0.3332999999999999852,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2025,'inter','day',0.3332999999999999852,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2025,'summer','day',0.3332999999999999852,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2025,'winter','day',0.3332999999999999852,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2030,'inter','day',0.3332999999999999852,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2030,'summer','day',0.3332999999999999852,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2030,'winter','day',0.3332999999999999852,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2035,'inter','day',0.3332999999999999852,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2035,'summer','day',0.3332999999999999852,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2035,'winter','day',0.3332999999999999852,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2040,'inter','day',0.3332999999999999852,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2040,'summer','day',0.3332999999999999852,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2040,'winter','day',0.3332999999999999852,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2045,'inter','day',0.3332999999999999852,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2045,'summer','day',0.3332999999999999852,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2045,'winter','day',0.3332999999999999852,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2050,'inter','day',0.3332999999999999852,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2050,'summer','day',0.3332999999999999852,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2050,'winter','day',0.3332999999999999852,'# W-D'); CREATE TABLE StorageDuration ( region TEXT, @@ -863,23 +1174,6 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE StorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage) -); CREATE TABLE TechnologyType ( label TEXT @@ -890,110 +1184,6 @@ INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE MinTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MinTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MinTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MinTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -1031,14 +1221,14 @@ INSERT INTO TimeSeason VALUES('inter'); INSERT INTO TimeSeason VALUES('summer'); INSERT INTO TimeSeason VALUES('winter'); CREATE TABLE PeriodSeasons -( +( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, season TEXT REFERENCES TimeSeason (season), notes TEXT, - PRIMARY KEY (period, sequence) + PRIMARY KEY (period, sequence, season) ); INSERT INTO PeriodSeasons VALUES(2000,1,'inter',NULL); INSERT INTO PeriodSeasons VALUES(2000,2,'summer',NULL); @@ -1081,188 +1271,6 @@ CREATE TABLE TimePeriodType ); INSERT INTO TimePeriodType VALUES('e','existing vintages'); INSERT INTO TimePeriodType VALUES('f','future'); -CREATE TABLE MaxActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE MaxNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MaxNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MaxNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE MinCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MinNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MinNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); -CREATE TABLE MaxNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1280,72 +1288,6 @@ CREATE TABLE OutputEmission emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE MinActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE EmissionLimit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE MaxActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "min_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); -CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "max_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); CREATE TABLE RPSRequirement ( region TEXT NOT NULL @@ -1389,7 +1331,7 @@ INSERT INTO Technology VALUES('EF','p','electric','electric','',0,0,0,0,0,0,0,'f CREATE TABLE OutputCost ( scenario TEXT, - region TEXT REFERENCES Region (region), + region TEXT, sector TEXT REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), @@ -1406,25 +1348,4 @@ CREATE TABLE OutputCost FOREIGN KEY (vintage) REFERENCES TimePeriod (period), FOREIGN KEY (tech) REFERENCES Technology (tech) ); -CREATE TABLE MyopicEfficiency -( - base_year integer, - region text, - input_comm text, - tech text, - vintage integer, - output_comm text, - efficiency real, - lifetime integer, - - FOREIGN KEY (tech) REFERENCES Technology (tech), - PRIMARY KEY (region, input_comm, tech, vintage, output_comm) -); -INSERT INTO MyopicEfficiency VALUES(-1,'electricville','HYD','EH',1995,'ELC',1.0,80); -INSERT INTO MyopicEfficiency VALUES(2000,'electricville','HYD','EH',2000,'ELC',1.0,100); -INSERT INTO MyopicEfficiency VALUES(2000,'electricville','ELC','bulbs',2000,'RL',1.0,100); -INSERT INTO MyopicEfficiency VALUES(2000,'electricville','earth','well',2000,'HYD',1.0,100); -INSERT INTO MyopicEfficiency VALUES(2010,'electricville','HYD','EF',2010,'ELC',10.0,100); -INSERT INTO MyopicEfficiency VALUES(2010,'electricville','HYD','EH',2020,'ELC',1.0,100); -CREATE INDEX region_tech_vintage ON MyopicEfficiency (region, tech, vintage); COMMIT; diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index d24811d5d..a666111eb 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -90,53 +90,53 @@ CREATE TABLE CapacityFactorTech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'spring','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'spring','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2020,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'summer','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'summer','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2020,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'fall','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'fall','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2020,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'winter','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2020,'winter','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2020,'winter','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'spring','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'spring','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2020,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'summer','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'summer','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2020,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'fall','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'fall','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2020,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'winter','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2020,'winter','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2020,'winter','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'spring','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'spring','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2025,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'summer','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'summer','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2025,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'fall','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'fall','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2025,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'winter','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2025,'winter','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2025,'winter','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'spring','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'spring','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2025,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'summer','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'summer','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2025,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'fall','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'fall','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2025,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'winter','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2025,'winter','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2025,'winter','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'spring','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'spring','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2030,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'summer','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'summer','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2030,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'fall','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'fall','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2030,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'winter','day','E_SOLPV',0.6,''); +INSERT INTO CapacityFactorTech VALUES('R1',2030,'winter','day','E_SOLPV',0.5999999999999999778,''); INSERT INTO CapacityFactorTech VALUES('R1',2030,'winter','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'spring','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'spring','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2030,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'summer','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'summer','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2030,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'fall','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'fall','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2030,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'winter','day','E_SOLPV',0.47999999999999998223,''); +INSERT INTO CapacityFactorTech VALUES('R2',2030,'winter','day','E_SOLPV',0.4799999999999999823,''); INSERT INTO CapacityFactorTech VALUES('R2',2030,'winter','night','E_SOLPV',0.0,''); CREATE TABLE CapacityToActivity ( @@ -152,10 +152,10 @@ INSERT INTO CapacityToActivity VALUES('R1','S_IMPOIL',1.0,''); INSERT INTO CapacityToActivity VALUES('R1','S_IMPNG',1.0,''); INSERT INTO CapacityToActivity VALUES('R1','S_IMPURN',1.0,''); INSERT INTO CapacityToActivity VALUES('R1','S_OILREF',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1','E_NGCC',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('R1','E_SOLPV',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('R1','E_BATT',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('R1','E_NUCLEAR',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('R1','E_NGCC',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('R1','E_SOLPV',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('R1','E_BATT',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('R1','E_NUCLEAR',31.53999999999999915,''); INSERT INTO CapacityToActivity VALUES('R1','T_BLND',1.0,''); INSERT INTO CapacityToActivity VALUES('R1','T_DSL',1.0,''); INSERT INTO CapacityToActivity VALUES('R1','T_GSL',1.0,''); @@ -167,18 +167,18 @@ INSERT INTO CapacityToActivity VALUES('R2','S_IMPOIL',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','S_IMPNG',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','S_IMPURN',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','S_OILREF',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','E_NGCC',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('R2','E_SOLPV',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('R2','E_BATT',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('R2','E_NUCLEAR',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('R2','E_NGCC',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('R2','E_SOLPV',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('R2','E_BATT',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('R2','E_NUCLEAR',31.53999999999999915,''); INSERT INTO CapacityToActivity VALUES('R2','T_BLND',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','T_DSL',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','T_GSL',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','T_EV',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','R_EH',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','R_NGH',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1-R2','E_TRANS',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('R2-R1','E_TRANS',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('R1-R2','E_TRANS',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('R2-R1','E_TRANS',31.53999999999999915,''); CREATE TABLE Commodity ( name TEXT @@ -206,15 +206,31 @@ CREATE TABLE CommodityType PRIMARY KEY, description TEXT ); +INSERT INTO CommodityType VALUES('w','waste commodity'); +INSERT INTO CommodityType VALUES('wa','waste annual commodity'); +INSERT INTO CommodityType VALUES('wp','waste physical commodity'); INSERT INTO CommodityType VALUES('a','annual commodity'); INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); +CREATE TABLE ConstructionInput +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); CREATE TABLE CostEmission ( - region TEXT - REFERENCES Region (region), + region TEXT, period INTEGER REFERENCES TimePeriod (period), emis_comm TEXT NOT NULL @@ -238,54 +254,54 @@ CREATE TABLE CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostFixed VALUES('R1',2020,'E_NGCC',2020,30.600000000000000532,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_NGCC',2020,9.7799999999999993605,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_NGCC',2025,9.7799999999999993605,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2020,9.7799999999999993605,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2025,9.7799999999999993605,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2030,9.7799999999999993605,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2020,'E_SOLPV',2020,10.400000000000000355,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_SOLPV',2020,10.400000000000000355,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_SOLPV',2025,9.0999999999999996447,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2020,10.400000000000000355,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2025,9.0999999999999996447,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2030,9.0999999999999996447,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2020,'E_NUCLEAR',2020,98.09999999999998721,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_NUCLEAR',2020,98.09999999999998721,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_NUCLEAR',2025,98.09999999999998721,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2020,98.09999999999998721,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2025,98.09999999999998721,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2030,98.09999999999998721,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2020,'E_BATT',2020,7.0499999999999998223,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_BATT',2020,7.0499999999999998223,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_BATT',2025,7.0499999999999998223,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2020,7.0499999999999998223,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2025,7.0499999999999998223,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2030,7.0499999999999998223,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2020,'E_NGCC',2020,24.479999999999999538,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_NGCC',2020,7.8239999999999998436,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_NGCC',2025,7.8239999999999998436,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2020,7.8239999999999998436,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2025,7.8239999999999998436,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2030,7.8239999999999998436,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2020,'E_SOLPV',2020,8.3200000000000002842,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_SOLPV',2020,8.3200000000000002842,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_SOLPV',2025,7.2800000000000002486,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2020,8.3200000000000002842,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2025,7.2800000000000002486,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2030,7.2800000000000002486,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2020,'E_NUCLEAR',2020,78.480000000000007531,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_NUCLEAR',2020,78.480000000000007531,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_NUCLEAR',2025,78.480000000000007531,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2020,78.480000000000007531,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2025,78.480000000000007531,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2030,78.480000000000007531,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2020,'E_BATT',2020,5.6399999999999996802,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_BATT',2020,5.6399999999999996802,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_BATT',2025,5.6399999999999996802,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2020,5.6399999999999996802,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2025,5.6399999999999996802,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2030,5.6399999999999996802,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2020,'E_NGCC',2020,30.60000000000000142,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_NGCC',2020,9.77999999999999937,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_NGCC',2025,9.77999999999999937,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2020,9.77999999999999937,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2025,9.77999999999999937,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2030,9.77999999999999937,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2020,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_SOLPV',2025,9.099999999999999645,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2025,9.099999999999999645,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2030,9.099999999999999645,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2020,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_NUCLEAR',2025,98.0999999999999801,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2025,98.0999999999999801,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2030,98.0999999999999801,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2020,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2025,'E_BATT',2025,7.049999999999999823,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2025,7.049999999999999823,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2030,7.049999999999999823,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2020,'E_NGCC',2020,24.48000000000000042,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_NGCC',2020,7.823999999999999844,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_NGCC',2025,7.823999999999999844,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2020,7.823999999999999844,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2025,7.823999999999999844,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2030,7.823999999999999844,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2020,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_SOLPV',2025,7.280000000000000248,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2025,7.280000000000000248,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2030,7.280000000000000248,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2020,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_NUCLEAR',2025,78.48000000000000397,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2025,78.48000000000000397,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2030,78.48000000000000397,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2020,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2025,'E_BATT',2025,5.639999999999999681,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2025,5.639999999999999681,'$M/GWyr',''); +INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2030,5.639999999999999681,'$M/GWyr',''); CREATE TABLE CostInvest ( region TEXT, @@ -319,12 +335,12 @@ INSERT INTO CostInvest VALUES('R1','T_DSL',2030,2810.0,'$/bvmt/yr',''); INSERT INTO CostInvest VALUES('R1','T_EV',2020,3100.0,'$/bvmt/yr',''); INSERT INTO CostInvest VALUES('R1','T_EV',2025,3030.0,'$/bvmt/yr',''); INSERT INTO CostInvest VALUES('R1','T_EV',2030,2925.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R1','R_EH',2020,4.0999999999999996447,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_EH',2025,4.0999999999999996447,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_EH',2030,4.0999999999999996447,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_NGH',2020,7.5999999999999996447,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_NGH',2025,7.5999999999999996447,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_NGH',2030,7.5999999999999996447,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R1','R_EH',2020,4.099999999999999644,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R1','R_EH',2025,4.099999999999999644,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R1','R_EH',2030,4.099999999999999644,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R1','R_NGH',2020,7.599999999999999645,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R1','R_NGH',2025,7.599999999999999645,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R1','R_NGH',2030,7.599999999999999645,'$/PJ/yr',''); INSERT INTO CostInvest VALUES('R2','E_NGCC',2020,840.0,'$M/GW',''); INSERT INTO CostInvest VALUES('R2','E_NGCC',2025,820.0,'$M/GW',''); INSERT INTO CostInvest VALUES('R2','E_NGCC',2030,800.0,'$M/GW',''); @@ -346,9 +362,9 @@ INSERT INTO CostInvest VALUES('R2','T_DSL',2030,2248.0,'$/bvmt/yr',''); INSERT INTO CostInvest VALUES('R2','T_EV',2020,2480.0,'$/bvmt/yr',''); INSERT INTO CostInvest VALUES('R2','T_EV',2025,2424.0,'$/bvmt/yr',''); INSERT INTO CostInvest VALUES('R2','T_EV',2030,2340.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R2','R_EH',2020,3.2799999999999998046,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R2','R_EH',2025,3.2799999999999998046,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R2','R_EH',2030,3.2799999999999998046,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R2','R_EH',2020,3.279999999999999805,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R2','R_EH',2025,3.279999999999999805,'$/PJ/yr',''); +INSERT INTO CostInvest VALUES('R2','R_EH',2030,3.279999999999999805,'$/PJ/yr',''); INSERT INTO CostInvest VALUES('R2','R_NGH',2020,6.080000000000000071,'$/PJ/yr',''); INSERT INTO CostInvest VALUES('R2','R_NGH',2025,6.080000000000000071,'$/PJ/yr',''); INSERT INTO CostInvest VALUES('R2','R_NGH',2030,6.080000000000000071,'$/PJ/yr',''); @@ -378,48 +394,48 @@ INSERT INTO CostVariable VALUES('R1',2030,'S_IMPNG',2020,4.0,'$M/PJ',''); INSERT INTO CostVariable VALUES('R1',2020,'S_OILREF',2020,1.0,'$M/PJ',''); INSERT INTO CostVariable VALUES('R1',2025,'S_OILREF',2020,1.0,'$M/PJ',''); INSERT INTO CostVariable VALUES('R1',2030,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2020,'E_NGCC',2020,1.6000000000000000888,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'E_NGCC',2020,1.6000000000000000888,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'E_NGCC',2025,1.7,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2020,1.6000000000000000888,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2025,1.7,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2030,1.8,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2020,'E_NUCLEAR',2020,0.23999999999999999111,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'E_NUCLEAR',2020,0.23999999999999999111,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2020,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2025,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2025,'E_NGCC',2025,1.699999999999999956,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2025,1.699999999999999956,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2030,1.800000000000000044,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2020,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2025,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); INSERT INTO CostVariable VALUES('R1',2025,'E_NUCLEAR',2025,0.25,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2020,0.23999999999999999111,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2025,0.25,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2030,0.26000000000000000888,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'S_IMPETH',2020,25.600000000000000532,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'S_IMPETH',2020,25.600000000000000532,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'S_IMPETH',2020,25.600000000000000532,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2030,0.2600000000000000088,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2020,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); INSERT INTO CostVariable VALUES('R2',2020,'S_IMPOIL',2020,16.0,'$M/PJ',''); INSERT INTO CostVariable VALUES('R2',2025,'S_IMPOIL',2020,16.0,'$M/PJ',''); INSERT INTO CostVariable VALUES('R2',2030,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'S_IMPNG',2020,3.2000000000000001776,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'S_IMPNG',2020,3.2000000000000001776,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'S_IMPNG',2020,3.2000000000000001776,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'S_OILREF',2020,0.8,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'S_OILREF',2020,0.8,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'S_OILREF',2020,0.8,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'E_NGCC',2020,1.2800000000000000355,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'E_NGCC',2020,1.2800000000000000355,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'E_NGCC',2025,1.3600000000000000976,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2020,1.2800000000000000355,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2025,1.3600000000000000976,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2030,1.4399999999999999467,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'E_NUCLEAR',2020,0.19199999999999999289,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'E_NUCLEAR',2020,0.19199999999999999289,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'E_NUCLEAR',2025,0.2,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2020,0.19199999999999999289,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2025,0.2,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2030,0.2080000000000000071,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1-R2',2020,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1-R2',2025,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1-R2',2030,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2-R1',2020,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2-R1',2025,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2-R1',2030,'E_TRANS',2015,0.1,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2020,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2020,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2020,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'E_NGCC',2025,1.360000000000000097,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2025,1.360000000000000097,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2030,1.439999999999999947,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2020,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2025,'E_NUCLEAR',2025,0.2000000000000000111,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2025,0.2000000000000000111,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2030,0.2080000000000000183,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1-R2',2020,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1-R2',2025,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R1-R2',2030,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2-R1',2020,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2-R1',2025,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO CostVariable VALUES('R2-R1',2030,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); CREATE TABLE Demand ( region TEXT, @@ -460,64 +476,67 @@ CREATE TABLE DemandSpecificDistribution PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'spring','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'spring','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'spring','night','RH',0.1000000000000000055,''); INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'summer','day','RH',0.0,''); INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'fall','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'fall','night','RH',0.1,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'winter','day','RH',0.3,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'winter','night','RH',0.4,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'spring','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'fall','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'fall','night','RH',0.1000000000000000055,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'winter','day','RH',0.2999999999999999889,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'winter','night','RH',0.4000000000000000222,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'spring','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'spring','night','RH',0.1000000000000000055,''); INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'summer','day','RH',0.0,''); INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'fall','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'fall','night','RH',0.1,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'winter','day','RH',0.3,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'winter','night','RH',0.4,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'spring','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'fall','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'fall','night','RH',0.1000000000000000055,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'winter','day','RH',0.2999999999999999889,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'winter','night','RH',0.4000000000000000222,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'spring','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'spring','night','RH',0.1000000000000000055,''); INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'summer','day','RH',0.0,''); INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'fall','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'fall','night','RH',0.1,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'winter','day','RH',0.3,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'winter','night','RH',0.4,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'spring','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'fall','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'fall','night','RH',0.1000000000000000055,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'winter','day','RH',0.2999999999999999889,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'winter','night','RH',0.4000000000000000222,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'spring','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'spring','night','RH',0.1000000000000000055,''); INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'summer','day','RH',0.0,''); INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'fall','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'fall','night','RH',0.1,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'winter','day','RH',0.3,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'winter','night','RH',0.4,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'spring','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'fall','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'fall','night','RH',0.1000000000000000055,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'winter','day','RH',0.2999999999999999889,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'winter','night','RH',0.4000000000000000222,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'spring','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'spring','night','RH',0.1000000000000000055,''); INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'summer','day','RH',0.0,''); INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'fall','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'fall','night','RH',0.1,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'winter','day','RH',0.3,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'winter','night','RH',0.4,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'spring','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'spring','night','RH',0.1,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'fall','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'fall','night','RH',0.1000000000000000055,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'winter','day','RH',0.2999999999999999889,''); +INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'winter','night','RH',0.4000000000000000222,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'spring','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'spring','night','RH',0.1000000000000000055,''); INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'summer','day','RH',0.0,''); INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'fall','day','RH',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'fall','night','RH',0.1,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'winter','day','RH',0.3,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'winter','night','RH',0.4,''); -CREATE TABLE LoanRate +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'fall','day','RH',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'fall','night','RH',0.1000000000000000055,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'winter','day','RH',0.2999999999999999889,''); +INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'winter','night','RH',0.4000000000000000222,''); +CREATE TABLE EndOfLifeOutput ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES TimePeriod (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); CREATE TABLE Efficiency ( @@ -543,34 +562,34 @@ INSERT INTO Efficiency VALUES('R1','OIL','S_OILREF',2020,'GSL',1.0,''); INSERT INTO Efficiency VALUES('R1','OIL','S_OILREF',2020,'DSL',1.0,''); INSERT INTO Efficiency VALUES('R1','ETH','T_BLND',2020,'E10',1.0,''); INSERT INTO Efficiency VALUES('R1','GSL','T_BLND',2020,'E10',1.0,''); -INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2020,'ELC',0.55,''); -INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2025,'ELC',0.55,''); -INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2030,'ELC',0.55,''); +INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2020,'ELC',0.5500000000000000444,''); +INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2025,'ELC',0.5500000000000000444,''); +INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2030,'ELC',0.5500000000000000444,''); INSERT INTO Efficiency VALUES('R1','SOL','E_SOLPV',2020,'ELC',1.0,''); INSERT INTO Efficiency VALUES('R1','SOL','E_SOLPV',2025,'ELC',1.0,''); INSERT INTO Efficiency VALUES('R1','SOL','E_SOLPV',2030,'ELC',1.0,''); -INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2015,'ELC',0.4,''); -INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2020,'ELC',0.4,''); -INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2025,'ELC',0.4,''); -INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2030,'ELC',0.4,''); -INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2020,'ELC',0.85,''); -INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2025,'ELC',0.85,''); -INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2030,'ELC',0.85,''); +INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2015,'ELC',0.4000000000000000222,''); +INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2020,'ELC',0.4000000000000000222,''); +INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2025,'ELC',0.4000000000000000222,''); +INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2030,'ELC',0.4000000000000000222,''); +INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2020,'ELC',0.8499999999999999778,''); +INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2025,'ELC',0.8499999999999999778,''); +INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2030,'ELC',0.8499999999999999778,''); INSERT INTO Efficiency VALUES('R1','E10','T_GSL',2020,'VMT',0.25,''); INSERT INTO Efficiency VALUES('R1','E10','T_GSL',2025,'VMT',0.25,''); INSERT INTO Efficiency VALUES('R1','E10','T_GSL',2030,'VMT',0.25,''); -INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2020,'VMT',0.3,''); -INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2025,'VMT',0.3,''); -INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2030,'VMT',0.3,''); -INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2020,'VMT',0.89000000000000003552,''); -INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2025,'VMT',0.89000000000000003552,''); -INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2030,'VMT',0.89000000000000003552,''); +INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2020,'VMT',0.2999999999999999889,''); +INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2025,'VMT',0.2999999999999999889,''); +INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2030,'VMT',0.2999999999999999889,''); +INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2020,'VMT',0.8900000000000000133,''); +INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2025,'VMT',0.8900000000000000133,''); +INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2030,'VMT',0.8900000000000000133,''); INSERT INTO Efficiency VALUES('R1','ELC','R_EH',2020,'RH',1.0,''); INSERT INTO Efficiency VALUES('R1','ELC','R_EH',2025,'RH',1.0,''); INSERT INTO Efficiency VALUES('R1','ELC','R_EH',2030,'RH',1.0,''); -INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2020,'RH',0.85,''); -INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2025,'RH',0.85,''); -INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2030,'RH',0.85,''); +INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2020,'RH',0.8499999999999999778,''); +INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2025,'RH',0.8499999999999999778,''); +INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2030,'RH',0.8499999999999999778,''); INSERT INTO Efficiency VALUES('R2','ethos','S_IMPETH',2020,'ETH',1.0,''); INSERT INTO Efficiency VALUES('R2','ethos','S_IMPOIL',2020,'OIL',1.0,''); INSERT INTO Efficiency VALUES('R2','ethos','S_IMPNG',2020,'NG',1.0,''); @@ -579,36 +598,36 @@ INSERT INTO Efficiency VALUES('R2','OIL','S_OILREF',2020,'GSL',1.0,''); INSERT INTO Efficiency VALUES('R2','OIL','S_OILREF',2020,'DSL',1.0,''); INSERT INTO Efficiency VALUES('R2','ETH','T_BLND',2020,'E10',1.0,''); INSERT INTO Efficiency VALUES('R2','GSL','T_BLND',2020,'E10',1.0,''); -INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2020,'ELC',0.55,''); -INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2025,'ELC',0.55,''); -INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2030,'ELC',0.55,''); +INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2020,'ELC',0.5500000000000000444,''); +INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2025,'ELC',0.5500000000000000444,''); +INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2030,'ELC',0.5500000000000000444,''); INSERT INTO Efficiency VALUES('R2','SOL','E_SOLPV',2020,'ELC',1.0,''); INSERT INTO Efficiency VALUES('R2','SOL','E_SOLPV',2025,'ELC',1.0,''); INSERT INTO Efficiency VALUES('R2','SOL','E_SOLPV',2030,'ELC',1.0,''); -INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2015,'ELC',0.4,''); -INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2020,'ELC',0.4,''); -INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2025,'ELC',0.4,''); -INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2030,'ELC',0.4,''); -INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2020,'ELC',0.85,''); -INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2025,'ELC',0.85,''); -INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2030,'ELC',0.85,''); +INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2015,'ELC',0.4000000000000000222,''); +INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2020,'ELC',0.4000000000000000222,''); +INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2025,'ELC',0.4000000000000000222,''); +INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2030,'ELC',0.4000000000000000222,''); +INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2020,'ELC',0.8499999999999999778,''); +INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2025,'ELC',0.8499999999999999778,''); +INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2030,'ELC',0.8499999999999999778,''); INSERT INTO Efficiency VALUES('R2','E10','T_GSL',2020,'VMT',0.25,''); INSERT INTO Efficiency VALUES('R2','E10','T_GSL',2025,'VMT',0.25,''); INSERT INTO Efficiency VALUES('R2','E10','T_GSL',2030,'VMT',0.25,''); -INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2020,'VMT',0.3,''); -INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2025,'VMT',0.3,''); -INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2030,'VMT',0.3,''); -INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2020,'VMT',0.89000000000000003552,''); -INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2025,'VMT',0.89000000000000003552,''); -INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2030,'VMT',0.89000000000000003552,''); +INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2020,'VMT',0.2999999999999999889,''); +INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2025,'VMT',0.2999999999999999889,''); +INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2030,'VMT',0.2999999999999999889,''); +INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2020,'VMT',0.8900000000000000133,''); +INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2025,'VMT',0.8900000000000000133,''); +INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2030,'VMT',0.8900000000000000133,''); INSERT INTO Efficiency VALUES('R2','ELC','R_EH',2020,'RH',1.0,''); INSERT INTO Efficiency VALUES('R2','ELC','R_EH',2025,'RH',1.0,''); INSERT INTO Efficiency VALUES('R2','ELC','R_EH',2030,'RH',1.0,''); -INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2020,'RH',0.85,''); -INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2025,'RH',0.85,''); -INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2030,'RH',0.85,''); -INSERT INTO Efficiency VALUES('R1-R2','ELC','E_TRANS',2015,'ELC',0.9,''); -INSERT INTO Efficiency VALUES('R2-R1','ELC','E_TRANS',2015,'ELC',0.9,''); +INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2020,'RH',0.8499999999999999778,''); +INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2025,'RH',0.8499999999999999778,''); +INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2030,'RH',0.8499999999999999778,''); +INSERT INTO Efficiency VALUES('R1-R2','ELC','E_TRANS',2015,'ELC',0.9000000000000000222,''); +INSERT INTO Efficiency VALUES('R2-R1','ELC','E_TRANS',2015,'ELC',0.9000000000000000222,''); CREATE TABLE EfficiencyVariable ( region TEXT, @@ -649,12 +668,12 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('R1','CO2','ethos','S_IMPNG',2020,'NG',50.299999999999993605,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R1','CO2','OIL','S_OILREF',2020,'GSL',67.200000000000006394,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R1','CO2','OIL','S_OILREF',2020,'DSL',69.400000000000003907,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R2','CO2','ethos','S_IMPNG',2020,'NG',50.299999999999993605,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R2','CO2','OIL','S_OILREF',2020,'GSL',67.200000000000006394,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R2','CO2','OIL','S_OILREF',2020,'DSL',69.400000000000003907,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO EmissionActivity VALUES('R1','CO2','ethos','S_IMPNG',2020,'NG',50.29999999999999005,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO EmissionActivity VALUES('R1','CO2','OIL','S_OILREF',2020,'GSL',67.20000000000000284,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO EmissionActivity VALUES('R1','CO2','OIL','S_OILREF',2020,'DSL',69.40000000000000569,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO EmissionActivity VALUES('R2','CO2','ethos','S_IMPNG',2020,'NG',50.29999999999999005,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO EmissionActivity VALUES('R2','CO2','OIL','S_OILREF',2020,'GSL',67.20000000000000284,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO EmissionActivity VALUES('R2','CO2','OIL','S_OILREF',2020,'DSL',69.40000000000000569,'kT/PJ','taken from MIT Energy Fact Sheet'); CREATE TABLE EmissionEmbodied ( region TEXT, @@ -669,6 +688,20 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); +CREATE TABLE EmissionEndOfLife +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); CREATE TABLE ExistingCapacity ( region TEXT, @@ -681,8 +714,8 @@ CREATE TABLE ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO ExistingCapacity VALUES('R1','E_NUCLEAR',2015,0.070000000000000008881,'GW',''); -INSERT INTO ExistingCapacity VALUES('R2','E_NUCLEAR',2015,0.03,'GW',''); +INSERT INTO ExistingCapacity VALUES('R1','E_NUCLEAR',2015,0.07000000000000000667,'GW',''); +INSERT INTO ExistingCapacity VALUES('R2','E_NUCLEAR',2015,0.02999999999999999889,'GW',''); INSERT INTO ExistingCapacity VALUES('R1-R2','E_TRANS',2015,10.0,'GW',''); INSERT INTO ExistingCapacity VALUES('R2-R1','E_TRANS',2015,10.0,'GW',''); CREATE TABLE TechGroup @@ -691,25 +724,6 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE GrowthRateMax -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE GrowthRateSeed -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - seed REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) -); CREATE TABLE LoanLifetimeTech ( region TEXT, @@ -749,6 +763,17 @@ INSERT INTO LoanLifetimeTech VALUES('R2','T_GSL',12.0,''); INSERT INTO LoanLifetimeTech VALUES('R2','T_EV',12.0,''); INSERT INTO LoanLifetimeTech VALUES('R2','R_EH',20.0,''); INSERT INTO LoanLifetimeTech VALUES('R2','R_NGH',20.0,''); +CREATE TABLE LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); CREATE TABLE LifetimeProcess ( region TEXT, @@ -801,186 +826,503 @@ INSERT INTO LifetimeTech VALUES('R2','R_EH',20.0,''); INSERT INTO LifetimeTech VALUES('R2','R_NGH',20.0,''); INSERT INTO LifetimeTech VALUES('R1-R2','E_TRANS',30.0,''); INSERT INTO LifetimeTech VALUES('R2-R1','E_TRANS',30.0,''); -CREATE TABLE LinkedTech +CREATE TABLE Operator ( - primary_region TEXT, - primary_tech TEXT + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO Operator VALUES('e','equal to'); +INSERT INTO Operator VALUES('le','less than or equal to'); +INSERT INTO Operator VALUES('ge','greater than or equal to'); +CREATE TABLE LimitGrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - emis_comm TEXT - REFERENCES Commodity (name), - driven_tech TEXT + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxActivity +CREATE TABLE LimitGrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxCapacity +CREATE TABLE LimitDegrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxResource +CREATE TABLE LimitGrowthNewCapacityDelta ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_res REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthNewCapacityDelta +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitStorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE MinActivity +INSERT INTO LimitStorageLevelFraction VALUES('R1',2025,'winter','day','E_BATT',2025,'e',0.5,''); +INSERT INTO LimitStorageLevelFraction VALUES('R2',2020,'summer','day','E_BATT',2020,'e',0.5,''); +CREATE TABLE LimitActivity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_act REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech, operator) ); -INSERT INTO MinActivity VALUES('R1',2020,'T_GSL',35.0,'',''); -INSERT INTO MinActivity VALUES('R1',2025,'T_GSL',35.0,'',''); -INSERT INTO MinActivity VALUES('R1',2030,'T_GSL',35.0,'',''); -INSERT INTO MinActivity VALUES('R2',2020,'T_GSL',15.0,'',''); -INSERT INTO MinActivity VALUES('R2',2025,'T_GSL',15.0,'',''); -INSERT INTO MinActivity VALUES('R2',2030,'T_GSL',15.0,'',''); -CREATE TABLE MaxCapacityGroup +INSERT INTO LimitActivity VALUES('R1',2020,'T_GSL','ge',35.0,'',''); +INSERT INTO LimitActivity VALUES('R1',2025,'T_GSL','ge',35.0,'',''); +INSERT INTO LimitActivity VALUES('R1',2030,'T_GSL','ge',35.0,'',''); +INSERT INTO LimitActivity VALUES('R2',2020,'T_GSL','ge',15.0,'',''); +INSERT INTO LimitActivity VALUES('R2',2025,'T_GSL','ge',15.0,'',''); +INSERT INTO LimitActivity VALUES('R2',2030,'T_GSL','ge',15.0,'',''); +CREATE TABLE LimitActivityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - max_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) +); +CREATE TABLE LimitActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) +); +CREATE TABLE LimitAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, operator), + CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE MinCapacity +CREATE TABLE LimitCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech, operator) ); -CREATE TABLE MinCapacityGroup +CREATE TABLE LimitCapacityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) ); -CREATE TABLE OutputCurtailment +CREATE TABLE LimitCapacityShare ( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) ); -CREATE TABLE OutputNetCapacity +CREATE TABLE LimitNewCapacity ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator) +); +CREATE TABLE LimitNewCapacityGroup +( + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name, operator) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE LimitNewCapacityGroupShare ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE LimitNewCapacityShare ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) ); -CREATE TABLE OutputFlowIn +CREATE TABLE LimitResource ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitSeasonalCapacityFactor +( + region TEXT + REFERENCES Region (region), + period INTEGER REFERENCES TimePeriod (period), - season TEXT + season TEXT REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) +); +CREATE TABLE LimitTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +INSERT INTO LimitTechInputSplit VALUES('R1',2020,'GSL','T_BLND','ge',0.9000000000000000222,''); +INSERT INTO LimitTechInputSplit VALUES('R1',2020,'ETH','T_BLND','ge',0.1000000000000000055,''); +INSERT INTO LimitTechInputSplit VALUES('R1',2025,'GSL','T_BLND','ge',0.9000000000000000222,''); +INSERT INTO LimitTechInputSplit VALUES('R1',2025,'ETH','T_BLND','ge',0.1000000000000000055,''); +INSERT INTO LimitTechInputSplit VALUES('R1',2030,'GSL','T_BLND','ge',0.9000000000000000222,''); +INSERT INTO LimitTechInputSplit VALUES('R1',2030,'ETH','T_BLND','ge',0.1000000000000000055,''); +INSERT INTO LimitTechInputSplit VALUES('R2',2020,'GSL','T_BLND','ge',0.7199999999999999734,''); +INSERT INTO LimitTechInputSplit VALUES('R2',2020,'ETH','T_BLND','ge',0.08000000000000000166,''); +INSERT INTO LimitTechInputSplit VALUES('R2',2025,'GSL','T_BLND','ge',0.7199999999999999734,''); +INSERT INTO LimitTechInputSplit VALUES('R2',2025,'ETH','T_BLND','ge',0.08000000000000000166,''); +INSERT INTO LimitTechInputSplit VALUES('R2',2030,'GSL','T_BLND','ge',0.7199999999999999734,''); +INSERT INTO LimitTechInputSplit VALUES('R2',2030,'ETH','T_BLND','ge',0.08000000000000000166,''); +CREATE TABLE LimitTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +INSERT INTO LimitTechOutputSplit VALUES('R1',2020,'S_OILREF','GSL','ge',0.9000000000000000222,''); +INSERT INTO LimitTechOutputSplit VALUES('R1',2020,'S_OILREF','DSL','ge',0.1000000000000000055,''); +INSERT INTO LimitTechOutputSplit VALUES('R1',2025,'S_OILREF','GSL','ge',0.9000000000000000222,''); +INSERT INTO LimitTechOutputSplit VALUES('R1',2025,'S_OILREF','DSL','ge',0.1000000000000000055,''); +INSERT INTO LimitTechOutputSplit VALUES('R1',2030,'S_OILREF','GSL','ge',0.9000000000000000222,''); +INSERT INTO LimitTechOutputSplit VALUES('R1',2030,'S_OILREF','DSL','ge',0.1000000000000000055,''); +INSERT INTO LimitTechOutputSplit VALUES('R2',2020,'S_OILREF','GSL','ge',0.7199999999999999734,''); +INSERT INTO LimitTechOutputSplit VALUES('R2',2020,'S_OILREF','DSL','ge',0.08000000000000000166,''); +INSERT INTO LimitTechOutputSplit VALUES('R2',2025,'S_OILREF','GSL','ge',0.7199999999999999734,''); +INSERT INTO LimitTechOutputSplit VALUES('R2',2025,'S_OILREF','DSL','ge',0.08000000000000000166,''); +INSERT INTO LimitTechOutputSplit VALUES('R2',2030,'S_OILREF','GSL','ge',0.7199999999999999734,''); +INSERT INTO LimitTechOutputSplit VALUES('R2',2030,'S_OILREF','DSL','ge',0.08000000000000000166,''); +CREATE TABLE LimitTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +INSERT INTO LimitEmission VALUES('R1',2020,'CO2','le',25000.0,'kT CO2',''); +INSERT INTO LimitEmission VALUES('R1',2025,'CO2','le',24000.0,'kT CO2',''); +INSERT INTO LimitEmission VALUES('R1',2030,'CO2','le',23000.0,'kT CO2',''); +INSERT INTO LimitEmission VALUES('global',2020,'CO2','le',37500.0,'kT CO2',''); +INSERT INTO LimitEmission VALUES('global',2025,'CO2','le',36000.0,'kT CO2',''); +INSERT INTO LimitEmission VALUES('global',2030,'CO2','le',34500.0,'kT CO2',''); +CREATE TABLE LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT REFERENCES Technology (tech), vintage INTEGER REFERENCES TimePeriod (period), @@ -1021,7 +1363,7 @@ CREATE TABLE OutputStorageLevel period INTEGER REFERENCES TimePeriod (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1109,25 +1451,6 @@ CREATE TABLE StorageDuration ); INSERT INTO StorageDuration VALUES('R1','E_BATT',8.0,'8-hour duration specified as fraction of a day'); INSERT INTO StorageDuration VALUES('R2','E_BATT',8.0,'8-hour duration specified as fraction of a day'); -CREATE TABLE StorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage) -); -INSERT INTO StorageLevelFraction VALUES('R1',2025,'winter','day','E_BATT',2025,0.5,''); -INSERT INTO StorageLevelFraction VALUES('R2',2020,'summer','day','E_BATT',2020,0.5,''); CREATE TABLE TechnologyType ( label TEXT @@ -1138,134 +1461,6 @@ INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE MinTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -INSERT INTO MinTechInputSplit VALUES('R1',2020,'GSL','T_BLND',0.9000000000000000222,''); -INSERT INTO MinTechInputSplit VALUES('R1',2020,'ETH','T_BLND',0.1000000000000000055,''); -INSERT INTO MinTechInputSplit VALUES('R1',2025,'GSL','T_BLND',0.9000000000000000222,''); -INSERT INTO MinTechInputSplit VALUES('R1',2025,'ETH','T_BLND',0.1000000000000000055,''); -INSERT INTO MinTechInputSplit VALUES('R1',2030,'GSL','T_BLND',0.9000000000000000222,''); -INSERT INTO MinTechInputSplit VALUES('R1',2030,'ETH','T_BLND',0.1000000000000000055,''); -INSERT INTO MinTechInputSplit VALUES('R2',2020,'GSL','T_BLND',0.7199999999999999734,''); -INSERT INTO MinTechInputSplit VALUES('R2',2020,'ETH','T_BLND',0.08000000000000000166,''); -INSERT INTO MinTechInputSplit VALUES('R2',2025,'GSL','T_BLND',0.7199999999999999734,''); -INSERT INTO MinTechInputSplit VALUES('R2',2025,'ETH','T_BLND',0.08000000000000000166,''); -INSERT INTO MinTechInputSplit VALUES('R2',2030,'GSL','T_BLND',0.7199999999999999734,''); -INSERT INTO MinTechInputSplit VALUES('R2',2030,'ETH','T_BLND',0.08000000000000000166,''); -CREATE TABLE MinTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MinTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -INSERT INTO MinTechOutputSplit VALUES('R1',2020,'S_OILREF','GSL',0.9000000000000000222,''); -INSERT INTO MinTechOutputSplit VALUES('R1',2020,'S_OILREF','DSL',0.1000000000000000055,''); -INSERT INTO MinTechOutputSplit VALUES('R1',2025,'S_OILREF','GSL',0.9000000000000000222,''); -INSERT INTO MinTechOutputSplit VALUES('R1',2025,'S_OILREF','DSL',0.1000000000000000055,''); -INSERT INTO MinTechOutputSplit VALUES('R1',2030,'S_OILREF','GSL',0.9000000000000000222,''); -INSERT INTO MinTechOutputSplit VALUES('R1',2030,'S_OILREF','DSL',0.1000000000000000055,''); -INSERT INTO MinTechOutputSplit VALUES('R2',2020,'S_OILREF','GSL',0.7199999999999999734,''); -INSERT INTO MinTechOutputSplit VALUES('R2',2020,'S_OILREF','DSL',0.08000000000000000166,''); -INSERT INTO MinTechOutputSplit VALUES('R2',2025,'S_OILREF','GSL',0.7199999999999999734,''); -INSERT INTO MinTechOutputSplit VALUES('R2',2025,'S_OILREF','DSL',0.08000000000000000166,''); -INSERT INTO MinTechOutputSplit VALUES('R2',2030,'S_OILREF','GSL',0.7199999999999999734,''); -INSERT INTO MinTechOutputSplit VALUES('R2',2030,'S_OILREF','DSL',0.08000000000000000166,''); -CREATE TABLE MinTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -1297,14 +1492,14 @@ INSERT INTO TimeSeason VALUES('summer'); INSERT INTO TimeSeason VALUES('fall'); INSERT INTO TimeSeason VALUES('winter'); CREATE TABLE PeriodSeasons -( +( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, season TEXT REFERENCES TimeSeason (season), notes TEXT, - PRIMARY KEY (period, sequence) + PRIMARY KEY (period, sequence, season) ); INSERT INTO PeriodSeasons VALUES(2020,1,'spring',NULL); INSERT INTO PeriodSeasons VALUES(2020,2,'summer',NULL); @@ -1326,188 +1521,6 @@ CREATE TABLE TimePeriodType ); INSERT INTO TimePeriodType VALUES('e','existing vintages'); INSERT INTO TimePeriodType VALUES('f','future'); -CREATE TABLE MaxActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE MaxNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MaxNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MaxNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE MinCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MinNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MinNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); -CREATE TABLE MaxNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1525,78 +1538,6 @@ CREATE TABLE OutputEmission emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE MinActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE EmissionLimit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -INSERT INTO EmissionLimit VALUES('R1',2020,'CO2',25000.0,'kT CO2',''); -INSERT INTO EmissionLimit VALUES('R1',2025,'CO2',24000.0,'kT CO2',''); -INSERT INTO EmissionLimit VALUES('R1',2030,'CO2',23000.0,'kT CO2',''); -INSERT INTO EmissionLimit VALUES('global',2020,'CO2',37500.0,'kT CO2',''); -INSERT INTO EmissionLimit VALUES('global',2025,'CO2',36000.0,'kT CO2',''); -INSERT INTO EmissionLimit VALUES('global',2030,'CO2',34500.0,'kT CO2',''); -CREATE TABLE MaxActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "min_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); -CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "max_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); CREATE TABLE RPSRequirement ( region TEXT NOT NULL @@ -1652,7 +1593,7 @@ INSERT INTO Technology VALUES('E_TRANS','p','electric','','',0,0,0,0,0,0,1,'elec CREATE TABLE OutputCost ( scenario TEXT, - region TEXT REFERENCES Region (region), + region TEXT, sector TEXT REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), @@ -1670,4 +1611,3 @@ CREATE TABLE OutputCost FOREIGN KEY (tech) REFERENCES Technology (tech) ); COMMIT; -PRAGMA FOREIGN_KEYS = 1; \ No newline at end of file diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index c06426a32..2c96d4867 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -73,24 +73,24 @@ CREATE TABLE CapacityFactorProcess PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','day','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','night','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','day','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','night','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','day','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','night','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2000,0.27530000000000001136,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2010,0.27560000000000002273,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2010,0.27560000000000002273,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2010,0.27560000000000002273,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2010,0.27560000000000002273,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2010,0.27560000000000002273,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2010,0.27560000000000002273,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2000,0.2752999999999999892,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2010,0.2756000000000000116,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2010,0.2756000000000000116,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2010,0.2756000000000000116,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2010,0.2756000000000000116,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2010,0.2756000000000000116,''); +INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2010,0.2756000000000000116,''); CREATE TABLE CapacityFactorTech ( region TEXT, @@ -107,96 +107,96 @@ CREATE TABLE CapacityFactorTech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E01',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E21',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E31',0.275,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E51',0.17000000000000001776,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E70',0.8,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E70',0.8,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E01',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E21',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E31',0.2750000000000000222,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E51',0.1700000000000000122,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E70',0.8000000000000000444,''); +INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E70',0.8000000000000000444,''); CREATE TABLE CapacityToActivity ( region TEXT, @@ -206,11 +206,11 @@ CREATE TABLE CapacityToActivity notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO CapacityToActivity VALUES('utopia','E01',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('utopia','E21',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('utopia','E31',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('utopia','E51',31.539999999999999147,''); -INSERT INTO CapacityToActivity VALUES('utopia','E70',31.539999999999999147,''); +INSERT INTO CapacityToActivity VALUES('utopia','E01',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('utopia','E21',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('utopia','E31',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('utopia','E51',31.53999999999999915,''); +INSERT INTO CapacityToActivity VALUES('utopia','E70',31.53999999999999915,''); INSERT INTO CapacityToActivity VALUES('utopia','RHE',1.0,''); INSERT INTO CapacityToActivity VALUES('utopia','RHO',1.0,''); INSERT INTO CapacityToActivity VALUES('utopia','RL1',1.0,''); @@ -246,15 +246,31 @@ CREATE TABLE CommodityType PRIMARY KEY, description TEXT ); +INSERT INTO CommodityType VALUES('w','waste commodity'); +INSERT INTO CommodityType VALUES('wa','waste annual commodity'); +INSERT INTO CommodityType VALUES('wp','waste physical commodity'); INSERT INTO CommodityType VALUES('a','annual commodity'); INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); +CREATE TABLE ConstructionInput +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); CREATE TABLE CostEmission ( - region TEXT - REFERENCES Region (region), + region TEXT, period INTEGER REFERENCES TimePeriod (period), emis_comm TEXT NOT NULL @@ -335,10 +351,10 @@ INSERT INTO CostFixed VALUES('utopia',2000,'RHO',2000,1.0,'',''); INSERT INTO CostFixed VALUES('utopia',2010,'RHO',1990,1.0,'',''); INSERT INTO CostFixed VALUES('utopia',2010,'RHO',2000,1.0,'',''); INSERT INTO CostFixed VALUES('utopia',2010,'RHO',2010,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1980,9.4600000000000008526,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1990,9.4600000000000008526,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'RL1',2000,9.4600000000000008526,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'RL1',2010,9.4600000000000008526,'',''); +INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1980,9.46000000000000086,'',''); +INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1990,9.46000000000000086,'',''); +INSERT INTO CostFixed VALUES('utopia',2000,'RL1',2000,9.46000000000000086,'',''); +INSERT INTO CostFixed VALUES('utopia',2010,'RL1',2010,9.46000000000000086,'',''); INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1970,52.0,'',''); INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1980,52.0,'',''); INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1990,52.0,'',''); @@ -434,36 +450,36 @@ INSERT INTO CostVariable VALUES('utopia',2010,'IMPOIL1',1990,8.0,'',''); INSERT INTO CostVariable VALUES('utopia',1990,'IMPURN1',1990,2.0,'',''); INSERT INTO CostVariable VALUES('utopia',2000,'IMPURN1',1990,2.0,'',''); INSERT INTO CostVariable VALUES('utopia',2010,'IMPURN1',1990,2.0,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1960,0.3,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1970,0.3,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1980,0.3,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1990,0.3,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1970,0.3,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1980,0.3,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1990,0.3,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',2000,0.3,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',1980,0.3,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',1990,0.3,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',2000,0.3,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',2010,0.3,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1960,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1970,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1980,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E01',1990,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',1970,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',1980,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',1990,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E01',2000,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',1980,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',1990,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',2000,0.2999999999999999889,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E01',2010,0.2999999999999999889,'',''); INSERT INTO CostVariable VALUES('utopia',1990,'E21',1990,1.5,'',''); INSERT INTO CostVariable VALUES('utopia',2000,'E21',1990,1.5,'',''); INSERT INTO CostVariable VALUES('utopia',2010,'E21',1990,1.5,'',''); INSERT INTO CostVariable VALUES('utopia',2000,'E21',2000,1.5,'',''); INSERT INTO CostVariable VALUES('utopia',2010,'E21',2000,1.5,'',''); INSERT INTO CostVariable VALUES('utopia',2010,'E21',2010,1.5,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1960,0.4,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1970,0.4,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1980,0.4,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1990,0.4,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1970,0.4,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1980,0.4,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1990,0.4,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',2000,0.4,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',1980,0.4,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',1990,0.4,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',2000,0.4,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',2010,0.4,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1960,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1970,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1980,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',1990,'E70',1990,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',1970,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',1980,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',1990,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',2000,'E70',2000,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',1980,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',1990,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',2000,0.4000000000000000222,'',''); +INSERT INTO CostVariable VALUES('utopia',2010,'E70',2010,0.4000000000000000222,'',''); INSERT INTO CostVariable VALUES('utopia',1990,'SRE',1990,10.0,'',''); INSERT INTO CostVariable VALUES('utopia',2000,'SRE',1990,10.0,'',''); INSERT INTO CostVariable VALUES('utopia',2000,'SRE',2000,10.0,'',''); @@ -482,15 +498,15 @@ CREATE TABLE Demand notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO Demand VALUES('utopia',1990,'RH',25.200000000000000177,'',''); -INSERT INTO Demand VALUES('utopia',2000,'RH',37.799999999999998046,'',''); -INSERT INTO Demand VALUES('utopia',2010,'RH',56.699999999999999289,'',''); -INSERT INTO Demand VALUES('utopia',1990,'RL',5.5999999999999996447,'',''); -INSERT INTO Demand VALUES('utopia',2000,'RL',8.4000000000000003552,'',''); -INSERT INTO Demand VALUES('utopia',2010,'RL',12.600000000000000088,'',''); -INSERT INTO Demand VALUES('utopia',1990,'TX',5.2000000000000001776,'',''); -INSERT INTO Demand VALUES('utopia',2000,'TX',7.7999999999999998223,'',''); -INSERT INTO Demand VALUES('utopia',2010,'TX',11.69000000000000039,'',''); +INSERT INTO Demand VALUES('utopia',1990,'RH',25.19999999999999929,'',''); +INSERT INTO Demand VALUES('utopia',2000,'RH',37.79999999999999715,'',''); +INSERT INTO Demand VALUES('utopia',2010,'RH',56.69999999999999574,'',''); +INSERT INTO Demand VALUES('utopia',1990,'RL',5.599999999999999645,'',''); +INSERT INTO Demand VALUES('utopia',2000,'RL',8.400000000000000355,'',''); +INSERT INTO Demand VALUES('utopia',2010,'RL',12.59999999999999965,'',''); +INSERT INTO Demand VALUES('utopia',1990,'TX',5.200000000000000177,'',''); +INSERT INTO Demand VALUES('utopia',2000,'TX',7.799999999999999823,'',''); +INSERT INTO Demand VALUES('utopia',2010,'TX',11.68999999999999951,'',''); CREATE TABLE DemandSpecificDistribution ( region TEXT, @@ -507,46 +523,49 @@ CREATE TABLE DemandSpecificDistribution PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RH',0.11999999999999999644,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RH',0.06,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','day','RH',0.54669999999999996376,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RH',0.27329999999999996518,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RL',0.15,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RL',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','day','RL',0.15,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RH',0.1199999999999999956,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RH',0.05999999999999999778,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','day','RH',0.5466999999999999638,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RH',0.2732999999999999874,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RL',0.1499999999999999945,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RL',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','day','RL',0.1499999999999999945,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','night','RL',0.05000000000000000277,''); INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','day','RL',0.5,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RL',0.1,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RH',0.11999999999999999644,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RH',0.06,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','day','RH',0.54669999999999996376,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RH',0.27329999999999996518,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RL',0.15,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RL',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','day','RL',0.15,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RL',0.1000000000000000055,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RH',0.1199999999999999956,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RH',0.05999999999999999778,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','day','RH',0.5466999999999999638,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RH',0.2732999999999999874,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RL',0.1499999999999999945,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RL',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','day','RL',0.1499999999999999945,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','night','RL',0.05000000000000000277,''); INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','day','RL',0.5,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RL',0.1,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RH',0.11999999999999999644,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RH',0.06,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RH',0.54669999999999996376,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RH',0.27329999999999996518,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RL',0.15,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RL',0.05,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','day','RL',0.15,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','night','RL',0.05,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RL',0.1000000000000000055,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RH',0.1199999999999999956,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RH',0.05999999999999999778,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RH',0.5466999999999999638,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RH',0.2732999999999999874,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RL',0.1499999999999999945,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RL',0.05000000000000000277,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','day','RL',0.1499999999999999945,''); +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','night','RL',0.05000000000000000277,''); INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RL',0.5,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RL',0.1,''); -CREATE TABLE LoanRate +INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RL',0.1000000000000000055,''); +CREATE TABLE EndOfLifeOutput ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES TimePeriod (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); CREATE TABLE Efficiency ( @@ -571,40 +590,40 @@ INSERT INTO Efficiency VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,''); INSERT INTO Efficiency VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,''); INSERT INTO Efficiency VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,''); INSERT INTO Efficiency VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,''); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1960,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1970,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1980,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1990,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',2000,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',2010,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',1990,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2000,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2010,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','URN','E21',1990,'ELC',0.4,'# 1/2.5'); -INSERT INTO Efficiency VALUES('utopia','URN','E21',2000,'ELC',0.4,'# 1/2.5'); -INSERT INTO Efficiency VALUES('utopia','URN','E21',2010,'ELC',0.4,'# 1/2.5'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',1980,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',1990,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',2000,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',2010,'ELC',0.32000000000000001776,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1960,'ELC',0.29399999999999998578,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1970,'ELC',0.29399999999999998578,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1980,'ELC',0.29399999999999998578,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1990,'ELC',0.29399999999999998578,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',2000,'ELC',0.29399999999999998578,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',2010,'ELC',0.29399999999999998578,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',1980,'ELC',0.71999999999999992894,'# 1/1.3889'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',1990,'ELC',0.71999999999999992894,'# 1/1.3889'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',2000,'ELC',0.71999999999999992894,'# 1/1.3889'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',2010,'ELC',0.71999999999999992894,'# 1/1.3889'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1960,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1970,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1980,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',1990,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',2000,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HCO','E01',2010,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','FEQ','E21',1990,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2000,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2010,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','URN','E21',1990,'ELC',0.4000000000000000222,'# 1/2.5'); +INSERT INTO Efficiency VALUES('utopia','URN','E21',2000,'ELC',0.4000000000000000222,'# 1/2.5'); +INSERT INTO Efficiency VALUES('utopia','URN','E21',2010,'ELC',0.4000000000000000222,'# 1/2.5'); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',1980,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',1990,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',2000,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','HYD','E31',2010,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1960,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1970,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1980,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',1990,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',2000,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','DSL','E70',2010,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',1980,'ELC',0.7199999999999999734,'# 1/1.3889'); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',1990,'ELC',0.7199999999999999734,'# 1/1.3889'); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',2000,'ELC',0.7199999999999999734,'# 1/1.3889'); +INSERT INTO Efficiency VALUES('utopia','ELC','E51',2010,'ELC',0.7199999999999999734,'# 1/1.3889'); INSERT INTO Efficiency VALUES('utopia','ELC','RHE',1990,'RH',1.0,'# direct translation from DMD_EFF'); INSERT INTO Efficiency VALUES('utopia','ELC','RHE',2000,'RH',1.0,'# direct translation from DMD_EFF'); INSERT INTO Efficiency VALUES('utopia','ELC','RHE',2010,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1970,'RH',0.7,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1980,'RH',0.7,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1990,'RH',0.7,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2000,'RH',0.7,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2010,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1970,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1980,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1990,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2000,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2010,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); INSERT INTO Efficiency VALUES('utopia','ELC','RL1',1980,'RL',1.0,'# direct translation from DMD_EFF'); INSERT INTO Efficiency VALUES('utopia','ELC','RL1',1990,'RL',1.0,'# direct translation from DMD_EFF'); INSERT INTO Efficiency VALUES('utopia','ELC','RL1',2000,'RL',1.0,'# direct translation from DMD_EFF'); @@ -615,19 +634,19 @@ INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'# direct tran INSERT INTO Efficiency VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1970,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1980,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1990,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2000,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2010,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',1990,'TX',0.82699999999999995736,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2000,'TX',0.82699999999999995736,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2010,'TX',0.82699999999999995736,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1970,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1980,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1990,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2000,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2010,'TX',0.23100000000000000532,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','ELC','TXE',1990,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2000,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2010,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); CREATE TABLE EfficiencyVariable ( region TEXT, @@ -668,10 +687,10 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.075,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.075,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',0.088999999999999985789,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.075,'',''); +INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.07499999999999999723,'',''); +INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.07499999999999999723,'',''); +INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',0.0889999999999999819,'',''); +INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.07499999999999999723,'',''); INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1970,'TX',1.0,'',''); INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1980,'TX',1.0,'',''); INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1990,'TX',1.0,'',''); @@ -696,6 +715,20 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); +CREATE TABLE EmissionEndOfLife +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); CREATE TABLE ExistingCapacity ( region TEXT, @@ -708,20 +741,20 @@ CREATE TABLE ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1960,0.175,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1970,0.175,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1980,0.15,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E31',1980,0.1,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E01',1960,0.1749999999999999889,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E01',1970,0.1749999999999999889,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E01',1980,0.1499999999999999945,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E31',1980,0.1000000000000000055,'',''); INSERT INTO ExistingCapacity VALUES('utopia','E51',1980,0.5,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1960,0.05,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1970,0.05,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1980,0.2,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E70',1960,0.05000000000000000277,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E70',1970,0.05000000000000000277,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','E70',1980,0.2000000000000000111,'',''); INSERT INTO ExistingCapacity VALUES('utopia','RHO',1970,12.5,'',''); INSERT INTO ExistingCapacity VALUES('utopia','RHO',1980,12.5,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','RL1',1980,5.5999999999999996447,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXD',1970,0.4,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXD',1980,0.2,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXG',1970,3.1000000000000000888,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','RL1',1980,5.599999999999999645,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','TXD',1970,0.4000000000000000222,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','TXD',1980,0.2000000000000000111,'',''); +INSERT INTO ExistingCapacity VALUES('utopia','TXG',1970,3.100000000000000088,'',''); INSERT INTO ExistingCapacity VALUES('utopia','TXG',1980,1.5,'',''); CREATE TABLE TechGroup ( @@ -729,25 +762,6 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE GrowthRateMax -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE GrowthRateSeed -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - seed REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) -); CREATE TABLE LoanLifetimeTech ( region TEXT, @@ -769,6 +783,17 @@ INSERT INTO LoanLifetimeTech VALUES('utopia','SRE',50.0,''); INSERT INTO LoanLifetimeTech VALUES('utopia','TXD',15.0,''); INSERT INTO LoanLifetimeTech VALUES('utopia','TXE',15.0,''); INSERT INTO LoanLifetimeTech VALUES('utopia','TXG',15.0,''); +CREATE TABLE LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); CREATE TABLE LifetimeProcess ( region TEXT, @@ -813,190 +838,481 @@ INSERT INTO LifetimeTech VALUES('utopia','IMPOIL1',1000.0,''); INSERT INTO LifetimeTech VALUES('utopia','IMPURN1',1000.0,''); INSERT INTO LifetimeTech VALUES('utopia','IMPHYD',1000.0,''); INSERT INTO LifetimeTech VALUES('utopia','IMPFEQ',1000.0,''); -CREATE TABLE LinkedTech +CREATE TABLE Operator ( - primary_region TEXT, - primary_tech TEXT + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO Operator VALUES('e','equal to'); +INSERT INTO Operator VALUES('le','less than or equal to'); +INSERT INTO Operator VALUES('ge','greater than or equal to'); +CREATE TABLE LimitGrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - emis_comm TEXT - REFERENCES Commodity (name), - driven_tech TEXT + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthCapacity +( + region TEXT, + tech TEXT REFERENCES Technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxActivity +CREATE TABLE LimitGrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -CREATE TABLE MaxCapacity +CREATE TABLE LimitDegrowthNewCapacity ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) ); -INSERT INTO MaxCapacity VALUES('utopia',1990,'E31',0.13000000000000000444,'',''); -INSERT INTO MaxCapacity VALUES('utopia',2000,'E31',0.17000000000000001776,'',''); -INSERT INTO MaxCapacity VALUES('utopia',2010,'E31',0.21000000000000000888,'',''); -INSERT INTO MaxCapacity VALUES('utopia',1990,'RHE',0.0,'',''); -INSERT INTO MaxCapacity VALUES('utopia',1990,'TXD',0.6,'',''); -INSERT INTO MaxCapacity VALUES('utopia',2000,'TXD',1.7599999999999999644,'',''); -INSERT INTO MaxCapacity VALUES('utopia',2010,'TXD',4.7599999999999997868,'',''); -CREATE TABLE MaxResource +CREATE TABLE LimitGrowthNewCapacityDelta ( - region TEXT, - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - max_res REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitDegrowthNewCapacityDelta +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitStorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE MinActivity +CREATE TABLE LimitActivity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_act REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech, operator) ); -CREATE TABLE MaxCapacityGroup +CREATE TABLE LimitActivityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - max_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) +); +CREATE TABLE LimitActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) +); +CREATE TABLE LimitAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, operator), + CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE MinCapacity +CREATE TABLE LimitCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) -); -INSERT INTO MinCapacity VALUES('utopia',1990,'E31',0.13000000000000000444,'',''); -INSERT INTO MinCapacity VALUES('utopia',2000,'E31',0.13000000000000000444,'',''); -INSERT INTO MinCapacity VALUES('utopia',2010,'E31',0.13000000000000000444,'',''); -INSERT INTO MinCapacity VALUES('utopia',1990,'SRE',0.1,'',''); -CREATE TABLE MinCapacityGroup + PRIMARY KEY (region, period, tech, operator) +); +INSERT INTO LimitCapacity VALUES('utopia',1990,'E31','ge',0.1300000000000000044,'',''); +INSERT INTO LimitCapacity VALUES('utopia',2000,'E31','ge',0.1300000000000000044,'',''); +INSERT INTO LimitCapacity VALUES('utopia',2010,'E31','ge',0.1300000000000000044,'',''); +INSERT INTO LimitCapacity VALUES('utopia',1990,'SRE','ge',0.1000000000000000055,'',''); +INSERT INTO LimitCapacity VALUES('utopia',1990,'E31','le',0.1300000000000000044,'',''); +INSERT INTO LimitCapacity VALUES('utopia',2000,'E31','le',0.1700000000000000122,'',''); +INSERT INTO LimitCapacity VALUES('utopia',2010,'E31','le',0.21000000000000002,'',''); +INSERT INTO LimitCapacity VALUES('utopia',1990,'RHE','le',0.0,'',''); +INSERT INTO LimitCapacity VALUES('utopia',1990,'TXD','le',0.5999999999999999778,'',''); +INSERT INTO LimitCapacity VALUES('utopia',2000,'TXD','le',1.760000000000000008,'',''); +INSERT INTO LimitCapacity VALUES('utopia',2010,'TXD','le',4.759999999999999787,'',''); +CREATE TABLE LimitCapacityGroup ( region TEXT, period INTEGER REFERENCES TimePeriod (period), group_name TEXT REFERENCES TechGroup (group_name), - min_cap REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, group_name) + PRIMARY KEY (region, period, group_name, operator) ); -CREATE TABLE OutputCurtailment +CREATE TABLE LimitCapacityShare ( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) ); -CREATE TABLE OutputNetCapacity +CREATE TABLE LimitNewCapacity ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, operator) +); +CREATE TABLE LimitNewCapacityGroup +( + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name, operator) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE LimitNewCapacityGroupShare ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + sub_group TEXT + REFERENCES TechGroup (group_name), + super_group TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE LimitNewCapacityShare ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + group_name TEXT + REFERENCES TechGroup (group_name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name, operator) ); -CREATE TABLE OutputFlowIn +CREATE TABLE LimitResource ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + region TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, operator) +); +CREATE TABLE LimitSeasonalCapacityFactor +( + region TEXT + REFERENCES Region (region), + period INTEGER REFERENCES TimePeriod (period), - season TEXT + season TEXT REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) +); +CREATE TABLE LimitTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +INSERT INTO LimitTechOutputSplit VALUES('utopia',1990,'SRE','DSL','ge',0.6999999999999999556,''); +INSERT INTO LimitTechOutputSplit VALUES('utopia',2000,'SRE','DSL','ge',0.6999999999999999556,''); +INSERT INTO LimitTechOutputSplit VALUES('utopia',2010,'SRE','DSL','ge',0.6999999999999999556,''); +INSERT INTO LimitTechOutputSplit VALUES('utopia',1990,'SRE','GSL','ge',0.2999999999999999889,''); +INSERT INTO LimitTechOutputSplit VALUES('utopia',2000,'SRE','GSL','ge',0.2999999999999999889,''); +INSERT INTO LimitTechOutputSplit VALUES('utopia',2010,'SRE','GSL','ge',0.2999999999999999889,''); +CREATE TABLE LimitTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), tech TEXT REFERENCES Technology (tech), vintage INTEGER @@ -1038,7 +1354,7 @@ CREATE TABLE OutputStorageLevel period INTEGER REFERENCES TimePeriod (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1091,24 +1407,24 @@ CREATE TABLE TimeSegmentFraction PRIMARY KEY (period, season, tod), CHECK (segfrac >= 0 AND segfrac <= 1) ); -INSERT INTO TimeSegmentFraction VALUES(1990,'inter','day',0.16669999999999998152,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(1990,'inter','night',0.08330000000000000071,'# I-N'); -INSERT INTO TimeSegmentFraction VALUES(1990,'summer','day',0.16669999999999998152,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(1990,'summer','night',0.08330000000000000071,'# S-N'); -INSERT INTO TimeSegmentFraction VALUES(1990,'winter','day',0.33329999999999997406,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(1990,'winter','night',0.16669999999999998152,'# W-N'); -INSERT INTO TimeSegmentFraction VALUES(2000,'inter','day',0.16669999999999998152,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2000,'inter','night',0.08330000000000000071,'# I-N'); -INSERT INTO TimeSegmentFraction VALUES(2000,'summer','day',0.16669999999999998152,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2000,'summer','night',0.08330000000000000071,'# S-N'); -INSERT INTO TimeSegmentFraction VALUES(2000,'winter','day',0.33329999999999997406,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2000,'winter','night',0.16669999999999998152,'# W-N'); -INSERT INTO TimeSegmentFraction VALUES(2010,'inter','day',0.16669999999999998152,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'inter','night',0.08330000000000000071,'# I-N'); -INSERT INTO TimeSegmentFraction VALUES(2010,'summer','day',0.16669999999999998152,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'summer','night',0.08330000000000000071,'# S-N'); -INSERT INTO TimeSegmentFraction VALUES(2010,'winter','day',0.33329999999999997406,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'winter','night',0.16669999999999998152,'# W-N'); +INSERT INTO TimeSegmentFraction VALUES(1990,'inter','day',0.166699999999999987,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(1990,'inter','night',0.08329999999999999905,'# I-N'); +INSERT INTO TimeSegmentFraction VALUES(1990,'summer','day',0.166699999999999987,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(1990,'summer','night',0.08329999999999999905,'# S-N'); +INSERT INTO TimeSegmentFraction VALUES(1990,'winter','day',0.3332999999999999852,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(1990,'winter','night',0.166699999999999987,'# W-N'); +INSERT INTO TimeSegmentFraction VALUES(2000,'inter','day',0.166699999999999987,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'inter','night',0.08329999999999999905,'# I-N'); +INSERT INTO TimeSegmentFraction VALUES(2000,'summer','day',0.166699999999999987,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'summer','night',0.08329999999999999905,'# S-N'); +INSERT INTO TimeSegmentFraction VALUES(2000,'winter','day',0.3332999999999999852,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2000,'winter','night',0.166699999999999987,'# W-N'); +INSERT INTO TimeSegmentFraction VALUES(2010,'inter','day',0.166699999999999987,'# I-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'inter','night',0.08329999999999999905,'# I-N'); +INSERT INTO TimeSegmentFraction VALUES(2010,'summer','day',0.166699999999999987,'# S-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'summer','night',0.08329999999999999905,'# S-N'); +INSERT INTO TimeSegmentFraction VALUES(2010,'winter','day',0.3332999999999999852,'# W-D'); +INSERT INTO TimeSegmentFraction VALUES(2010,'winter','night',0.166699999999999987,'# W-N'); CREATE TABLE StorageDuration ( region TEXT, @@ -1117,23 +1433,6 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE StorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage) -); CREATE TABLE TechnologyType ( label TEXT @@ -1144,116 +1443,6 @@ INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE MinTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MinTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MinTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -INSERT INTO MinTechOutputSplit VALUES('utopia',1990,'SRE','DSL',0.7,''); -INSERT INTO MinTechOutputSplit VALUES('utopia',2000,'SRE','DSL',0.7,''); -INSERT INTO MinTechOutputSplit VALUES('utopia',2010,'SRE','DSL',0.7,''); -INSERT INTO MinTechOutputSplit VALUES('utopia',1990,'SRE','GSL',0.3,''); -INSERT INTO MinTechOutputSplit VALUES('utopia',2000,'SRE','GSL',0.3,''); -INSERT INTO MinTechOutputSplit VALUES('utopia',2010,'SRE','GSL',0.3,''); -CREATE TABLE MinTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE MaxTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE MaxTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -1286,14 +1475,14 @@ INSERT INTO TimeSeason VALUES('inter'); INSERT INTO TimeSeason VALUES('summer'); INSERT INTO TimeSeason VALUES('winter'); CREATE TABLE PeriodSeasons -( +( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, season TEXT REFERENCES TimeSeason (season), notes TEXT, - PRIMARY KEY (period, sequence) + PRIMARY KEY (period, sequence, season) ); INSERT INTO PeriodSeasons VALUES(1990,1,'inter',NULL); INSERT INTO PeriodSeasons VALUES(1990,2,'summer',NULL); @@ -1312,188 +1501,6 @@ CREATE TABLE TimePeriodType ); INSERT INTO TimePeriodType VALUES('e','existing vintages'); INSERT INTO TimePeriodType VALUES('f','future'); -CREATE TABLE MaxActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MaxAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE MaxNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MaxNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MaxNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE MinCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE MinNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE MinNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE MinNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); -CREATE TABLE MaxNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1511,72 +1518,6 @@ CREATE TABLE OutputEmission emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE MinActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE EmissionLimit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE MaxActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS "MinSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "min_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); -CREATE TABLE IF NOT EXISTS "MaxSeasonalActivity" -( - "region" TEXT - REFERENCES Region (region), - "period" INTEGER - REFERENCES TimePeriod (period), - "season" TEXT - REFERENCES TimeSeason (season), - "tech" TEXT - REFERENCES Technology (tech), - "max_act" REAL, - "units" TEXT, - "notes" TEXT, - PRIMARY KEY("region","period","season","tech") -); CREATE TABLE RPSRequirement ( region TEXT NOT NULL @@ -1635,7 +1576,7 @@ INSERT INTO Technology VALUES('TXG','p','transport','petroleum','',0,0,0,0,0,0,0 CREATE TABLE OutputCost ( scenario TEXT, - region TEXT REFERENCES Region (region), + region TEXT, sector TEXT REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), @@ -1653,4 +1594,3 @@ CREATE TABLE OutputCost FOREIGN KEY (tech) REFERENCES Technology (tech) ); COMMIT; -PRAGMA FOREIGN_KEYS = 1; \ No newline at end of file diff --git a/data_files/temoa_schema_v3_2.sql b/data_files/temoa_schema_v3_2.sql index 2ac50478d..01477ff8b 100644 --- a/data_files/temoa_schema_v3_2.sql +++ b/data_files/temoa_schema_v3_2.sql @@ -542,7 +542,6 @@ CREATE TABLE IF NOT EXISTS LimitAnnualCapacityFactor operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, - source TEXT, notes TEXT, PRIMARY KEY (region, period, tech, operator), CHECK (factor >= 0 AND factor <= 1) @@ -660,7 +659,7 @@ CREATE TABLE IF NOT EXISTS LimitResource notes TEXT, PRIMARY KEY (region, tech, operator) ); -CREATE TABLE IF NOT EXISTS LimitSeasonalActivity +CREATE TABLE IF NOT EXISTS LimitSeasonalCapacityFactor ( region TEXT REFERENCES Region (region), @@ -672,10 +671,9 @@ CREATE TABLE IF NOT EXISTS LimitSeasonalActivity REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), - activity REAL, - units TEXT, + factor REAL, notes TEXT, - PRIMARY KEY(region,period,season,tech, operator) + PRIMARY KEY(region, period, season, tech, operator) ); CREATE TABLE IF NOT EXISTS LimitTechInputSplit ( diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 860848ce2..0f78a4f32 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -56,7 +56,7 @@ 'LimitAnnualCapacityFactor': 'region', 'LimitEmission': 'region', 'LimitActivityGroup': 'region', - 'LimitSeasonalActivity': 'region', + 'LimitSeasonalCapacityFactor': 'region', 'LimitCapacity': 'region', 'LimitActivity': 'region', 'LimitNewCapacity': 'region', @@ -894,10 +894,10 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, operator, activity FROM main.LimitActivity') load_element(M.LimitActivity, raw, self.viable_rt, (0, 2)) - # LimitSeasonalActivity - if self.table_exists('LimitSeasonalActivity'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tech, operator, activity FROM main.LimitSeasonalActivity') - load_element(M.LimitSeasonalActivity, raw, self.viable_rt, (0, 3)) + # LimitSeasonalCapacityFactor + if self.table_exists('LimitSeasonalCapacityFactor'): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tech, operator, factor FROM main.LimitSeasonalCapacityFactor') + load_element(M.LimitSeasonalCapacityFactor, raw, self.viable_rt, (0, 3)) # LimitAnnualCapacityFactor if self.table_exists('LimitAnnualCapacityFactor'): @@ -1091,7 +1091,7 @@ def load_param_idx_sets(self, data: dict) -> dict: M.CostEmission.name: M.CostEmission_rpe.name, M.LimitEmission.name: M.LimitEmissionConstraint_rpe.name, M.LimitActivity.name: M.LimitActivityConstraint_rpt.name, - M.LimitSeasonalActivity.name: M.LimitSeasonalActivityConstraint_rpst.name, + M.LimitSeasonalCapacityFactor.name: M.LimitSeasonalCapacityFactorConstraint_rpst.name, M.LimitActivityGroup.name: M.LimitActivityGroup_rpg.name, M.LimitActivityShare.name: M.LimitActivityShareConstraint_rptg.name, M.LimitAnnualCapacityFactor.name: M.LimitAnnualCapacityFactorConstraint_rpto.name, diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index b0c1f07ba..720277dbc 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -407,15 +407,15 @@ def __init__(M, *args, **kwargs): ) M.LimitActivity = Param(M.LimitActivityConstraint_rpt) - M.LimitSeasonalActivityConstraint_rpst = Set( + M.LimitSeasonalCapacityFactorConstraint_rpst = Set( within=M.regionalGlobalIndices * M.time_optimize * M.time_season_all * M.tech_all * M.operator ) - M.LimitSeasonalActivity = Param(M.LimitSeasonalActivityConstraint_rpst) + M.LimitSeasonalCapacityFactor = Param(M.LimitSeasonalCapacityFactorConstraint_rpst, validate=validate_0to1) M.LimitAnnualCapacityFactorConstraint_rpto = Set( within=M.regionalGlobalIndices * M.time_optimize * M.tech_all * M.commodity_carrier * M.operator ) - M.LimitAnnualCapacityFactor = Param(M.LimitAnnualCapacityFactorConstraint_rpto) + M.LimitAnnualCapacityFactor = Param(M.LimitAnnualCapacityFactorConstraint_rpto, validate=validate_0to1) M.LimitGrowthCapacity = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) M.LimitDegrowthCapacity = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) @@ -706,8 +706,8 @@ def __init__(M, *args, **kwargs): M.LimitActivityConstraint_rpt, rule=LimitActivity_Constraint ) - M.LimitSeasonalActivityConstraint = Constraint( - M.LimitSeasonalActivityConstraint_rpst, rule=LimitSeasonalActivity_Constraint + M.LimitSeasonalCapacityFactorConstraint = Constraint( + M.LimitSeasonalCapacityFactorConstraint_rpst, rule=LimitSeasonalCapacityFactor_Constraint ) M.LimitActivityGroupConstraint = Constraint( diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index b4c8d8098..cae827b59 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -2175,61 +2175,60 @@ def LimitActivity_Constraint(M: 'TemoaModel', r, p, t, op): return expr -def LimitSeasonalActivity_Constraint(M: 'TemoaModel', r, p, s, t, op): - - r""" - Sets a limit on the activity from a specific technology. - Note that the indices for these constraints are region, period, season, and tech. - The first component of the constraint pertains to technologies with - variable output at the time slice level, and the second component pertains to - technologies with constant annual output belonging to the :code:`tech_annual` - set. - .. math:: - :label: LimitSeasonalActivity - \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMSSNACT_{r, p, s, t} - \forall \{r, p, s, t\} \in \Theta_{\text{LimitSeasonalActivity}} - \sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \le LIMSSNACT_{r, p, s, t} - \forall \{r, p, s, t \in T^{a}\} \in \Theta_{\text{LimitSeasonalActivity}} - """ - - # Notice that this constraint follows the implementation of the - # LimitActivity_Constraint(). The difference is that this function is defined - # over each representative day, or "season", as opposed to the entire - # year, or "period". - - # The V_FlowOut variable is scaled by the weights of each representative day. - # In order to determine the daily, or "seasonal", flow, the V_FLowOut variable - # must be converted back to its un-scaled value. We do this by dividing the - # V_FlowOut value by M.SegFrac[p, s, d]*365*24. - - regions = gather_group_regions(M, r) - - try: - activity_rpst = sum( - M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] / (value(M.SegFrac[p, s, d])*365*24) - for _r in regions - 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 d in M.time_of_day - ) - except: - msg = ( - "\nWarning: LimitSeasonalActivity constraint can not be defined for " - "technologies in \"tech_annual\". Continuing by ignoring the constraint " - "for '%s'.\n " - ) - SE.write(msg % (t)) - return Constraint.Skip +# def LimitSeasonalCapacityFactor_Constraint(M: 'TemoaModel', r, p, s, t, op): + +# r""" +# Sets a limit on the capacity factor of a specific technology in a season. +# Note that the indices for these constraints are region, period, season, and tech. +# The first component of the constraint pertains to technologies with +# variable output at the time slice level, and the second component pertains to +# technologies with constant annual output belonging to the :code:`tech_annual` +# set. +# .. math:: +# :label: LimitSeasonalCapacityFactor +# \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMSSNACT_{r, p, s, t} +# \forall \{r, p, s, t\} \in \Theta_{\text{LimitSeasonalCapacityFactor}} +# \sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \le LIMSSNACT_{r, p, s, t} +# \forall \{r, p, s, t \in T^{a}\} \in \Theta_{\text{LimitSeasonalCapacityFactor}} +# """ + +# # Notice that this constraint follows the implementation of the +# # LimitAnnualCapacityFactor_Constraint(). The difference is that this function is defined +# # over each "season" as opposed to the entire year, or "period" + +# # The V_FlowOut variable is scaled by the weights of each season. +# # In order to determine the daily flow, the V_FlowOut variable +# # must be converted back to its un-scaled value. We do this by dividing the +# # V_FlowOut value by M.SegFracPerSeason[p, s, d]*365 (how many days are in this season). + +# regions = gather_group_regions(M, r) + +# try: +# activity_rpst = sum( +# M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] / (value(M.SegFracPerSeason[p, s, d])*365) +# for _r in regions +# 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 d in M.time_of_day +# ) +# except: +# msg = ( +# "\nWarning: LimitSeasonalCapacityFactor constraint cannot be defined for " +# "technologies in \"tech_annual\". Continuing by ignoring the constraint " +# "for '%s'.\n " +# ) +# SE.write(msg % (t)) +# return Constraint.Skip - act_lim = value(M.LimitSeasonalActivity[r, p, s, t, op]) - expr = operator_expression(activity_rpst, op, act_lim) +# act_lim = value(M.LimitSeasonalCapacityFactor[r, p, s, t, op]) +# expr = operator_expression(activity_rpst, op, act_lim) - # in the case that there is nothing to sum, skip - if isinstance(expr, bool): # an empty list was generated - return Constraint.Skip +# # in the case that there is nothing to sum, skip +# if isinstance(expr, bool): # an empty list was generated +# return Constraint.Skip - return expr + # return expr def LimitActivityGroup_Constraint(M: 'TemoaModel', r, p, g, op): @@ -2637,6 +2636,65 @@ def LimitAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o, op): return expr +def LimitSeasonalCapacityFactor_Constraint(M: 'TemoaModel', r, p, s, t, op): + r""" + The LimitSeasonalCapacityFactor sets an upper bound on the seasonal 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: LimitSeasonalCapacityFactor + \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMACF_{r, p, t} * \textbf{CAPAVL}_{r, p, t} * \text{C2A}_{r, t} + \forall \{r, p, t, o\} \in \Theta_{\text{LimitSeasonalCapacityFactor}} + \sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \ge LIMACF_{r, p, t} * \textbf{CAPAVL}_{r, p, t} * \text{C2A}_{r, t} + \forall \{r, p, t, o \in T^{a}\} \in \Theta_{\text{LimitSeasonalCapacityFactor}}""" + # r can be an individual region (r='US'), or a combination of regions separated by plus (r='Mexico+US+Canada'), or 'global'. + # if r == 'global', the constraint is system-wide + regions = gather_group_regions(M, r) + # we need to screen here because it is possible that the restriction extends beyond the + # lifetime of any vintage of the tech... + if all( + (_r, p, t) not in M.V_CapacityAvailableByPeriodAndTech + for _r in regions + ): + return Constraint.Skip + + # The V_FlowOut variable is scaled by the number of days in the season. + # To adjust for this, we divide by M.SegFracPerSeason[p, s, d]*365, + # the number of days this season represents. + if t not in M.tech_annual: + activity_rpst = sum( + M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] + for _r in regions + 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 d in M.time_of_day + ) + else: + activity_rpst = sum( + M.V_FlowOutAnnual[_r, p, S_i, t, S_v, S_o] * M.SegFracPerSeason[p, s] + for _r in regions + 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] + ) + + possible_activity_rpst = sum( + M.V_CapacityAvailableByPeriodAndTech[_r, p, t] + * value(M.CapacityToActivity[_r, t]) + * value(M.SegFracPerSeason[p, s]) + for _r in regions + ) + seasonal_cf = value(M.LimitSeasonalCapacityFactor[r, p, s, t, op]) + expr = operator_expression(activity_rpst, op, seasonal_cf * possible_activity_rpst) + # in the case that there is nothing to sum, skip + if isinstance(expr, bool): # an empty list was generated + return Constraint.Skip + return expr + + def LimitTechInputSplit_Constraint(M: 'TemoaModel', r, p, s, d, i, t, v, op): r""" Allows users to limit shares of commodity inputs to a process diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 5a3900a93..1768f89b3 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -577,7 +577,6 @@ CREATE TABLE LimitAnnualCapacityFactor operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, - source TEXT, notes TEXT, PRIMARY KEY (region, period, tech, operator), CHECK (factor >= 0 AND factor <= 1) @@ -699,7 +698,7 @@ CREATE TABLE LimitResource notes TEXT, PRIMARY KEY (region, tech, operator) ); -CREATE TABLE LimitSeasonalActivity +CREATE TABLE LimitSeasonalCapacityFactor ( region TEXT REFERENCES Region (region), @@ -711,10 +710,9 @@ CREATE TABLE LimitSeasonalActivity REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), - activity REAL, - units TEXT, + factor REAL, notes TEXT, - PRIMARY KEY(region,period,season,tech, operator) + PRIMARY KEY(region, period, season, tech, operator) ); CREATE TABLE LimitTechInputSplit ( diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index be08a13bd..b967a956a 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -954,7 +954,6 @@ CREATE TABLE LimitAnnualCapacityFactor operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, - source TEXT, notes TEXT, PRIMARY KEY (region, period, tech, operator), CHECK (factor >= 0 AND factor <= 1) @@ -1072,7 +1071,7 @@ CREATE TABLE LimitResource notes TEXT, PRIMARY KEY (region, tech, operator) ); -CREATE TABLE LimitSeasonalActivity +CREATE TABLE LimitSeasonalCapacityFactor ( region TEXT REFERENCES Region (region), @@ -1084,10 +1083,9 @@ CREATE TABLE LimitSeasonalActivity REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), - activity REAL, - units TEXT, + factor REAL, notes TEXT, - PRIMARY KEY(region,period,season,tech, operator) + PRIMARY KEY(region, period, season, tech, operator) ); CREATE TABLE LimitTechInputSplit ( diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 66f59220d..61425e1c5 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -639,7 +639,6 @@ CREATE TABLE LimitAnnualCapacityFactor operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, - source TEXT, notes TEXT, PRIMARY KEY (region, period, tech, operator), CHECK (factor >= 0 AND factor <= 1) @@ -766,7 +765,7 @@ CREATE TABLE LimitResource PRIMARY KEY (region, tech, operator) ); INSERT INTO LimitResource VALUES('B','EF','le',9000.0,'clumps',NULL); -CREATE TABLE LimitSeasonalActivity +CREATE TABLE LimitSeasonalCapacityFactor ( region TEXT REFERENCES Region (region), @@ -778,10 +777,9 @@ CREATE TABLE LimitSeasonalActivity REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), - activity REAL, - units TEXT, + factor REAL, notes TEXT, - PRIMARY KEY(region,period,season,tech, operator) + PRIMARY KEY(region, period, season, tech, operator) ); CREATE TABLE LimitTechInputSplit ( diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index ca1aae5e1..2b529454e 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -553,7 +553,6 @@ CREATE TABLE LimitAnnualCapacityFactor operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, - source TEXT, notes TEXT, PRIMARY KEY (region, period, tech, operator), CHECK (factor >= 0 AND factor <= 1) @@ -671,7 +670,7 @@ CREATE TABLE LimitResource notes TEXT, PRIMARY KEY (region, tech, operator) ); -CREATE TABLE LimitSeasonalActivity +CREATE TABLE LimitSeasonalCapacityFactor ( region TEXT REFERENCES Region (region), @@ -683,10 +682,9 @@ CREATE TABLE LimitSeasonalActivity REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), - activity REAL, - units TEXT, + factor REAL, notes TEXT, - PRIMARY KEY(region,period,season,tech, operator) + PRIMARY KEY(region, period, season, tech, operator) ); CREATE TABLE LimitTechInputSplit ( diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index a85c79b36..9aa28b895 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -562,7 +562,6 @@ CREATE TABLE LimitAnnualCapacityFactor operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, - source TEXT, notes TEXT, PRIMARY KEY (region, period, tech, operator), CHECK (factor >= 0 AND factor <= 1) @@ -684,7 +683,7 @@ CREATE TABLE LimitResource notes TEXT, PRIMARY KEY (region, tech, operator) ); -CREATE TABLE LimitSeasonalActivity +CREATE TABLE LimitSeasonalCapacityFactor ( region TEXT REFERENCES Region (region), @@ -696,10 +695,9 @@ CREATE TABLE LimitSeasonalActivity REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), - activity REAL, - units TEXT, + factor REAL, notes TEXT, - PRIMARY KEY(region,period,season,tech, operator) + PRIMARY KEY(region, period, season, tech, operator) ); CREATE TABLE LimitTechInputSplit ( diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 5ed006207..a666111eb 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -994,7 +994,6 @@ CREATE TABLE LimitAnnualCapacityFactor operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, - source TEXT, notes TEXT, PRIMARY KEY (region, period, tech, operator), CHECK (factor >= 0 AND factor <= 1) @@ -1112,7 +1111,7 @@ CREATE TABLE LimitResource notes TEXT, PRIMARY KEY (region, tech, operator) ); -CREATE TABLE LimitSeasonalActivity +CREATE TABLE LimitSeasonalCapacityFactor ( region TEXT REFERENCES Region (region), @@ -1124,10 +1123,9 @@ CREATE TABLE LimitSeasonalActivity REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), - activity REAL, - units TEXT, + factor REAL, notes TEXT, - PRIMARY KEY(region,period,season,tech, operator) + PRIMARY KEY(region, period, season, tech, operator) ); CREATE TABLE LimitTechInputSplit ( diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 07ba89719..2c96d4867 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -998,7 +998,6 @@ CREATE TABLE LimitAnnualCapacityFactor operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, - source TEXT, notes TEXT, PRIMARY KEY (region, period, tech, operator), CHECK (factor >= 0 AND factor <= 1) @@ -1127,7 +1126,7 @@ CREATE TABLE LimitResource notes TEXT, PRIMARY KEY (region, tech, operator) ); -CREATE TABLE LimitSeasonalActivity +CREATE TABLE LimitSeasonalCapacityFactor ( region TEXT REFERENCES Region (region), @@ -1139,10 +1138,9 @@ CREATE TABLE LimitSeasonalActivity REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), - activity REAL, - units TEXT, + factor REAL, notes TEXT, - PRIMARY KEY(region,period,season,tech, operator) + PRIMARY KEY(region, period, season, tech, operator) ); CREATE TABLE LimitTechInputSplit ( From a233b011fe623bff4a94703aa9496803314ceb23 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 9 Jun 2025 17:28:49 -0400 Subject: [PATCH 093/587] Update test sets for LimitSeasonalCapacityFactor --- tests/testing_data/mediumville_sets.json | 2 +- tests/testing_data/test_system_sets.json | 2 +- tests/testing_data/utopia_sets.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 078bb5a38..9a5e34913 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -3529,7 +3529,7 @@ "le" ] ], - "LimitSeasonalActivityConstraint_rpst": [], + "LimitSeasonalCapacityFactorConstraint_rpst": [], "LimitStorageFractionConstraint_rpsdtv": [], "LimitTechInputSplitAnnualConstraint_rpitv": [], "LimitTechInputSplitAverageConstraint_rpitv": [ diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 67a7775bd..1bb9ca415 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -40449,7 +40449,7 @@ "LimitNewCapacityGroupShareConstraint_rpgg": [], "LimitNewCapacityShareConstraint_rptg": [], "LimitResourceConstraint_rt": [], - "LimitSeasonalActivityConstraint_rpst": [], + "LimitSeasonalCapacityFactorConstraint_rpst": [], "LimitStorageFractionConstraint_rpsdtv": [ [ "R1", diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 0d4b1fe86..c73999d5d 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -22130,7 +22130,7 @@ "LimitNewCapacityGroupShareConstraint_rpgg": [], "LimitNewCapacityShareConstraint_rptg": [], "LimitResourceConstraint_rt": [], - "LimitSeasonalActivityConstraint_rpst": [], + "LimitSeasonalCapacityFactorConstraint_rpst": [], "LimitStorageFractionConstraint_rpsdtv": [], "LimitTechInputSplitAnnualConstraint_rpitv": [], "LimitTechInputSplitAverageConstraint_rpitv": [], From 6be7725a83127837e7ceb4b74b1a4bd6d4b89694 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 9 Jun 2025 18:19:40 -0400 Subject: [PATCH 094/587] Rationalise the objective function and remove ancient 1 year shift bug --- temoa/temoa_model/temoa_rules.py | 75 ++++++++++++++++++++------------ tests/legacy_test_values.py | 24 +++++++--- tests/test_emission_results.py | 12 ++--- tests/test_full_runs.py | 3 +- tests/test_table_writer.py | 2 +- 5 files changed, 74 insertions(+), 42 deletions(-) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index cae827b59..aa5e8add7 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -407,6 +407,19 @@ def TotalCost_rule(M): return sum(PeriodCost_rule(M, p) for p in M.time_optimize) +def annuity_to_pv(rate: float, periods: int) -> float | Expression: + """Multiplication factor to convert an annuity to present value""" + return ((1 + rate)**periods - 1) / (rate * (1 + rate)**periods) + +def pv_to_annuity(rate: float, periods: int) -> float | Expression: + """Multiplication factor to convert present value to an annuity""" + return (rate * (1 + rate)**periods) / ((1 + rate)**periods - 1) + +def fv_to_pv(rate: float, periods: int) -> float | Expression: + """Multiplication factor to convert a future value to present value""" + return 1 / (1 + rate)**periods + + def loan_cost( capacity: float | Var, invest_cost: float, @@ -431,27 +444,30 @@ def loan_cost( :param vintage: the base year of the loan :return: fixed number or pyomo expression based on input types """ - if GDR == 0: # return the non-discounted result - annuity = capacity * invest_cost * loan_annualize * lifetime_loan_process / lifetime_process - payments_made = min(lifetime_process, P_e - vintage) - return annuity * payments_made - x = 1 + GDR # a convenience - res = ( - capacity - * ( - invest_cost - * loan_annualize - * ( - lifetime_loan_process - if not GDR - else (x ** (P_0 - vintage + 1) * (1 - x ** (-lifetime_loan_process)) / GDR) - ) + + # calculate the annualised loan repayment (annuity) + annuity = ( + capacity * invest_cost # lump investment cost is capacity times CostInvest + * loan_annualize # calculate loan annuities for investment cost, if used + ) + + if not GDR: + # Undiscounted result + res = ( + annuity + * lifetime_loan_process # sum of loan payments over loan period + / lifetime_process # redistributed over lifetime of process + * min(lifetime_process, P_e - vintage) # sum of distributed costs within planning horizon ) - * ( - (1 - x ** (-min(lifetime_process, P_e - vintage))) - / (1 - x ** (-lifetime_process)) + else: + # Discounted result + res = ( + annuity + * annuity_to_pv(GDR, lifetime_loan_process) # PV of all loan payments in vintage year using GDR + * pv_to_annuity(GDR, lifetime_process) # reannualise costs over lifetime of process using GDR + * annuity_to_pv(GDR, min(lifetime_process, P_e - vintage)) # sum reannualised costs within planning horizon + * fv_to_pv(GDR, vintage - P_0) # finally, discount from vintage year to P_0 ) - ) return res @@ -474,16 +490,19 @@ def fixed_or_variable_cost( :param p: the period under evaluation :return: """ - x = 1 + GDR - res = cap_or_flow * ( - cost_factor - * ( - cost_years - if not GDR - else (x ** (P_0 - p + 1) * (1 - x ** (-cost_years)) / GDR) + + annual_cost = cap_or_flow * cost_factor # annual fixed, variable, or emission cost + + if not GDR: + # Undiscounted result + return annual_cost * cost_years # annual cost times years paying this cost + else: + # Discounted result + return ( + annual_cost + * annuity_to_pv(GDR, cost_years) # PV of annual costs over this period, in period p + * fv_to_pv(GDR, p - P_0) # discount to p_0 ) - ) - return res def PeriodCost_rule(M: 'TemoaModel', p): diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index c0b23b6b9..98e6314e9 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -41,17 +41,29 @@ class ExpectedVals(Enum): # these values were captured on base level runs of the .dat files in the tests/testing_data folder test_vals = { 'test_system': { - ExpectedVals.OBJ_VALUE: 491977.7000753, + # reduced after removing ancient 1-year-shift obj function bug + ExpectedVals.OBJ_VALUE: 468550.1905, ExpectedVals.EFF_DOMAIN_SIZE: 30720, ExpectedVals.EFF_INDEX_SIZE: 74, - ExpectedVals.CONSTR_COUNT: 2834, # increased by 2 when reworking storageinit. Increased after making annualretirement derived var - ExpectedVals.VAR_COUNT: 1904, # reduced by 6 when reworking storageinit. Increased after making annualretirement derived var + # increased by 2 when reworking storageinit. + # increased after making annualretirement derived var + ExpectedVals.CONSTR_COUNT: 2834, + # reduced by 6 when reworking storageinit. + # increased after making annualretirement derived var + ExpectedVals.VAR_COUNT: 1904, }, 'utopia': { - ExpectedVals.OBJ_VALUE: 36468.56, # reduced after reworking storageinit -> storage was less constrained + # reduced after reworking storageinit -> storage was less constrained + # reduced after removing ancient 1-year-shift obj function bug + ExpectedVals.OBJ_VALUE: 34731.9619, ExpectedVals.EFF_DOMAIN_SIZE: 12312, ExpectedVals.EFF_INDEX_SIZE: 64, - ExpectedVals.CONSTR_COUNT: 1471, # reduced 3/27: unlim_cap techs now employed. Increased after making annualretirement derived var - ExpectedVals.VAR_COUNT: 1070, # reduced 3/27: unlim_cap techs now employed. Reduced by 4 storageinit. Increased after making annualretirement derived var + # reduced 3/27: unlim_cap techs now employed. + # increased after making annualretirement derived var + ExpectedVals.CONSTR_COUNT: 1471, + # reduced 3/27: unlim_cap techs now employed. + # reduced by 4 in storageinit rework. + # increased after making annualretirement derived var + ExpectedVals.VAR_COUNT: 1070, }, } diff --git a/tests/test_emission_results.py b/tests/test_emission_results.py index cd72c6eca..52b9fbb56 100644 --- a/tests/test_emission_results.py +++ b/tests/test_emission_results.py @@ -141,8 +141,8 @@ def test_emissions_costs_discounted(solved_connection): .fetchone()[0] ) cost_target = ( - 0.7 * emis_target * 4.32947667063082 * 1.05 - ) # emission cost x emissions x P/A(5%, 5y, 1) [x F/P(5%, 1y) legacy bug?] + 0.7 * emis_target * 4.32947667063082 + ) # emission cost x emissions x P/A(5%, 5y, 1) assert ec == pytest.approx( cost_target ), f'{name} discounted emission costs were incorrect. Should be {cost_target}, got {ec}' @@ -211,8 +211,8 @@ def test_embodied_emissions_costs_discounted(solved_connection): .fetchone()[0] ) cost_target = ( - 0.7 * emis_target * 1/5 * (1.05**5-1)/(0.05*1.05**5) * 1.05 - ) # emission cost x embodied emissions x annual distribution x P/A(5%, 5y, 1) [x F/P(5%, 1y) legacy bug?] + 0.7 * emis_target * 1/5 * (1.05**5-1)/(0.05*1.05**5) + ) # emission cost x embodied emissions x annual distribution x P/A(5%, 5y, 1) assert ec == pytest.approx( cost_target ), f'{name} discounted emission costs were incorrect. Should be {cost_target}, got {ec}' @@ -281,8 +281,8 @@ def test_endoflife_emissions_costs_discounted(solved_connection): .fetchone()[0] ) cost_target = ( - 0.7 * emis_target * 1/5 * (1.05**5-1)/(0.05*1.05**5) / 1.05**5 * 1.05 - ) # emission cost x end of life emissions x annual distribution x P/A(5%, 5y, 1) x P/F(5%, 1y) [x F/P(5%, 1y) legacy bug?] + 0.7 * emis_target * 1/5 * (1.05**5-1)/(0.05*1.05**5) / 1.05**5 + ) # emission cost x end of life emissions x annual distribution x P/A(5%, 5y, 1) x P/F(5%, 1y) assert ec == pytest.approx( cost_target ), f'{name} discounted emission costs were incorrect. Should be {cost_target}, got {ec}' diff --git a/tests/test_full_runs.py b/tests/test_full_runs.py index 09e75809a..c8a064a44 100644 --- a/tests/test_full_runs.py +++ b/tests/test_full_runs.py @@ -109,5 +109,6 @@ def test_myopic_utopia(system_test_run): res = cur.execute('SELECT SUM(d_invest) FROM main.OutputCost').fetchone() invest_sum = res[0] # reduced this target after storageinit rework - assert invest_sum == pytest.approx(11525.19), 'sum of investment costs did not match expected' + # reduced after removing ancient 1-year shift bug from objective function + assert invest_sum == pytest.approx(10976.37143), 'sum of investment costs did not match expected' con.close() diff --git a/tests/test_table_writer.py b/tests/test_table_writer.py index e966ae7b3..22728d6d4 100644 --- a/tests/test_table_writer.py +++ b/tests/test_table_writer.py @@ -56,7 +56,7 @@ 'p_0': 2020, 'vintage': 2030, 'p_e': 2035, - 'model_cost': 21997.72, + 'model_cost': 20950.20952, # reduced after fixing 1 year shift obj function bug 'undiscounted_cost': 33544.06, }, ] From de318313adcd818b8342beb54882f37fb9ae1fe5 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 10 Jun 2025 10:55:39 -0400 Subject: [PATCH 095/587] Update objective function commenting a little --- temoa/temoa_model/temoa_rules.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index aa5e8add7..4300e25b7 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -457,16 +457,16 @@ def loan_cost( annuity * lifetime_loan_process # sum of loan payments over loan period / lifetime_process # redistributed over lifetime of process - * min(lifetime_process, P_e - vintage) # sum of distributed costs within planning horizon + * min(lifetime_process, P_e - vintage) # sum of redistributed costs for life of process (within planning horizon) ) else: # Discounted result res = ( annuity - * annuity_to_pv(GDR, lifetime_loan_process) # PV of all loan payments in vintage year using GDR - * pv_to_annuity(GDR, lifetime_process) # reannualise costs over lifetime of process using GDR - * annuity_to_pv(GDR, min(lifetime_process, P_e - vintage)) # sum reannualised costs within planning horizon - * fv_to_pv(GDR, vintage - P_0) # finally, discount from vintage year to P_0 + * annuity_to_pv(GDR, lifetime_loan_process) # PV of all loan payments, discounted to vintage year using GDR + * pv_to_annuity(GDR, lifetime_process) # reannualised over lifetime of process using GDR + * annuity_to_pv(GDR, min(lifetime_process, P_e - vintage)) # PV of all reannualised costs (within planning horizon) + * fv_to_pv(GDR, vintage - P_0) # finally, discounted from vintage year to P_0 ) return res @@ -495,13 +495,13 @@ def fixed_or_variable_cost( if not GDR: # Undiscounted result - return annual_cost * cost_years # annual cost times years paying this cost + return annual_cost * cost_years # annual cost times years paying that cost else: # Discounted result return ( annual_cost - * annuity_to_pv(GDR, cost_years) # PV of annual costs over this period, in period p - * fv_to_pv(GDR, p - P_0) # discount to p_0 + * annuity_to_pv(GDR, cost_years) # PV of annual costs over this period, discounted to period p + * fv_to_pv(GDR, p - P_0) # discounted from p to p_0 ) From b15236ef4857911e797cd3cf87793ed239dabe28 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 10 Jun 2025 11:41:18 -0400 Subject: [PATCH 096/587] Add LimitActivityGroupShare constraint and add deprecation warnings for RPSRequirement --- temoa/temoa_model/hybrid_loader.py | 14 ++++ temoa/temoa_model/temoa_model.py | 7 ++ temoa/temoa_model/temoa_rules.py | 108 ++++++++++++++++++++++++++--- 3 files changed, 118 insertions(+), 11 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 0f78a4f32..5fe4dbaf6 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -66,6 +66,7 @@ 'LimitCapacityShare': 'region', 'LimitNewCapacityShare': 'region', 'LimitNewCapacityGroupShare': 'region', + 'LimitActivityGroupShare': 'region', 'LimitResource': 'region', 'LimitGrowthCapacity': 'region', 'LimitDegrowthCapacity': 'region', @@ -793,6 +794,13 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N if self.table_exists('RPSRequirement'): raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech_group, requirement FROM main.RPSRequirement') load_element(M.RenewablePortfolioStandard, raw) + if len(raw) > 0: + logger.warning( + 'The RenewablePortfolioStandard constraint has been deprecated. Use the ' + 'LimitActivityGroupShare constraint instead, using the same sub group and ' + 'constructing a new super group for all relevant generators. The constraint ' + 'has been applied but this feature will be removed in the future.' + ) # CostFixed raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, vintage, cost FROM main.CostFixed') @@ -874,6 +882,11 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitNewCapacityGroupShare') load_element(M.LimitNewCapacityGroupShare, raw) + # LimitActivityGroupShare + if self.table_exists('LimitActivityGroupShare'): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitActivityGroupShare') + load_element(M.LimitActivityGroupShare, raw) + # LimitActivityGroup if self.table_exists('LimitActivityGroup'): raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, operator, activity FROM main.LimitActivityGroup') @@ -1102,6 +1115,7 @@ def load_param_idx_sets(self, data: dict) -> dict: M.LimitNewCapacityGroup.name: M.LimitNewCapacityGroupConstraint_rpg.name, M.LimitNewCapacityShare.name: M.LimitNewCapacityShareConstraint_rptg.name, M.LimitNewCapacityGroupShare.name: M.LimitNewCapacityGroupShareConstraint_rpgg.name, + M.LimitActivityGroupShare.name: M.LimitActivityGroupShareConstraint_rpgg.name, M.LimitResource.name: M.LimitResourceConstraint_rt.name, M.LimitStorageFraction.name: M.LimitStorageFractionConstraint_rpsdtv.name, M.RenewablePortfolioStandard.name: M.RenewablePortfolioStandardConstraint_rpg.name, diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 720277dbc..6b95254bb 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -461,6 +461,9 @@ def __init__(M, *args, **kwargs): M.LimitNewCapacityGroupShareConstraint_rpgg = Set(within=M.TwoGroupShareIndices) M.LimitNewCapacityGroupShare = Param(M.TwoGroupShareIndices) + M.LimitActivityGroupShareConstraint_rpgg = Set(within=M.TwoGroupShareIndices) + M.LimitActivityGroupShare = Param(M.TwoGroupShareIndices) + # This set works for all storage-related constraints M.StorageConstraints_rpsdtv = Set(dimen=6, initialize=StorageConstraintIndices) M.LimitStorageFractionConstraint_rpsdtv = Set(within=M.StorageConstraints_rpsdtv * M.operator) @@ -746,6 +749,10 @@ def __init__(M, *args, **kwargs): M.LimitNewCapacityGroupShareConstraint_rpgg, rule=LimitNewCapacityGroupShare_Constraint ) + M.LimitActivityGroupShareConstraint = Constraint( + M.LimitActivityGroupShareConstraint_rpgg, rule=LimitActivityGroupShare_Constraint + ) + M.progress_marker_8 = BuildAction( ['Starting Limit Capacity and Tech Split ' 'Constraints'], rule=progress_check ) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 4300e25b7..a6ca099c3 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -22,6 +22,7 @@ from logging import getLogger from sys import stderr as SE from typing import TYPE_CHECKING +from deprecated import deprecated from pyomo.core import Var, Expression from pyomo.environ import Constraint, value @@ -2194,25 +2195,28 @@ def LimitActivity_Constraint(M: 'TemoaModel', r, p, t, op): return expr -# def LimitSeasonalCapacityFactor_Constraint(M: 'TemoaModel', r, p, s, t, op): +# devnote: this constraint did not translate well between representative periods +# and seasonal time slicing paradigms. It was replaced with the LimitSeasonalCapacityFactor +# constraint, which works well in either paradigm and pairs with LimitAnnualCapacityFactor +# def LimitSeasonalActivity_Constraint(M: 'TemoaModel', r, p, s, t, op): # r""" -# Sets a limit on the capacity factor of a specific technology in a season. +# Sets a limit on the activity of a specific technology in a season. # Note that the indices for these constraints are region, period, season, and tech. # The first component of the constraint pertains to technologies with # variable output at the time slice level, and the second component pertains to # technologies with constant annual output belonging to the :code:`tech_annual` # set. # .. math:: -# :label: LimitSeasonalCapacityFactor +# :label: LimitSeasonalActivity # \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMSSNACT_{r, p, s, t} -# \forall \{r, p, s, t\} \in \Theta_{\text{LimitSeasonalCapacityFactor}} +# \forall \{r, p, s, t\} \in \Theta_{\text{LimitSeasonalActivity}} # \sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \le LIMSSNACT_{r, p, s, t} -# \forall \{r, p, s, t \in T^{a}\} \in \Theta_{\text{LimitSeasonalCapacityFactor}} +# \forall \{r, p, s, t \in T^{a}\} \in \Theta_{\text{LimitSeasonalActivity}} # """ # # Notice that this constraint follows the implementation of the -# # LimitAnnualCapacityFactor_Constraint(). The difference is that this function is defined +# # LimitActivity_Constraint(). The difference is that this function is defined # # over each "season" as opposed to the entire year, or "period" # # The V_FlowOut variable is scaled by the weights of each season. @@ -2233,21 +2237,21 @@ def LimitActivity_Constraint(M: 'TemoaModel', r, p, t, op): # ) # except: # msg = ( -# "\nWarning: LimitSeasonalCapacityFactor constraint cannot be defined for " +# "\nWarning: LimitSeasonalActivity constraint cannot be defined for " # "technologies in \"tech_annual\". Continuing by ignoring the constraint " # "for '%s'.\n " # ) # SE.write(msg % (t)) # return Constraint.Skip -# act_lim = value(M.LimitSeasonalCapacityFactor[r, p, s, t, op]) +# act_lim = value(M.LimitSeasonalActivity[r, p, s, t, op]) # expr = operator_expression(activity_rpst, op, act_lim) # # in the case that there is nothing to sum, skip # if isinstance(expr, bool): # an empty list was generated # return Constraint.Skip - # return expr +# return expr def LimitActivityGroup_Constraint(M: 'TemoaModel', r, p, g, op): @@ -2293,6 +2297,83 @@ def LimitActivityGroup_Constraint(M: 'TemoaModel', r, p, g, op): expr = operator_expression(activity_p + activity_p_annual, op, act_lim) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated + logger.warning( + 'Missing group techs to support LimitActivityGroup constraint: %s.' + ' Check data/log for available/suppressed techs. Constraint ignored.', + (r, p, g) + ) + return Constraint.Skip + return expr + + +def LimitActivityGroupShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): + r""" + The LimitActivityGroup constraint sets an activity limit for a user-defined + technology group. + .. math:: + :label: LimitActivityGroup + \sum_{R,S,D,I,T,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} + \sum_{I,T,V,O} + \textbf{FOA}_{r, p, i, t, v, o} + \le MxAG_{r, p, g} + \forall \{r, p, g\} \in \Theta_{\text{LimitActivityGroup}} + where :math:`g` represents the assigned technology group and :math:`MxAG` + refers to the :code:`LimitActivityGroup` parameter.""" + + regions = gather_group_regions(M, r) + + activity_g1 = 0 + activity_g2 = 0 + for _r in regions: + activity_g1 += sum( + M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] + for S_t in M.tech_group_members[g1] + if (_r, p, S_t) in M.processVintages and S_t not in M.tech_annual + for S_v in M.processVintages[_r, p, S_t] + for S_i in M.processInputs[_r, p, S_t, S_v] + for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] + for s in M.time_season[p] + for d in M.time_of_day + if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut + ) + activity_g1 += sum( + M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] + for S_t in M.tech_group_members[g1] + if (_r, p, S_t) in M.processVintages and S_t in M.tech_annual + for S_v in M.processVintages[_r, p, S_t] + for S_i in M.processInputs[_r, p, S_t, S_v] + for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] + if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual + ) + activity_g2 += sum( + M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] + for S_t in M.tech_group_members[g2] + if (_r, p, S_t) in M.processVintages and S_t not in M.tech_annual + for S_v in M.processVintages[_r, p, S_t] + for S_i in M.processInputs[_r, p, S_t, S_v] + for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] + for s in M.time_season[p] + for d in M.time_of_day + if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut + ) + activity_g2 += sum( + M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] + for S_t in M.tech_group_members[g2] + if (_r, p, S_t) in M.processVintages and S_t in M.tech_annual + for S_v in M.processVintages[_r, p, S_t] + for S_i in M.processInputs[_r, p, S_t, S_v] + for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] + if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual + ) + + share_lim = value(M.LimitActivityGroupShare[r, p, g1, g2, op]) + expr = operator_expression(activity_g1, op, share_lim * activity_g2) + # in the case that there is nothing to sum, skip + if isinstance(expr, bool): # an empty list was generated + logger.warning( + 'Missing group techs to support LimitActivityGroupShare constraint: %s.' + ' Check data/log for available/suppressed techs. Constraint ignored.', + (r, p, g1, g2) + ) return Constraint.Skip return expr @@ -2592,7 +2673,7 @@ def LimitNewCapacityGroupShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): if isinstance(expr, bool): # one side of expression was empty logger.error( 'Missing group techs to support LimitNewCapacityGroupShare constraint: %s.' - ' Check data/log for available/suppressed techs. Constraint ignored.', + ' Check data/log for available/suppressed techs. Constraint ignored.', (r, p, g1, g2) ) return Constraint.Skip @@ -2895,10 +2976,15 @@ def LimitTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o, op): return expr +#@deprecated('Deprecated. Use LimitActivityGroupShare instead') # doesn't play well with pyomo def RenewablePortfolioStandard_Constraint(M: 'TemoaModel', r, p, g): r""" Allows users to specify the share of electricity generation in a region - coming from RPS-eligible technologies.""" + coming from RPS-eligible technologies. + """ + # devnote: this formulation leans on the reserve set, which is not necessarily + # the super set we want. We can also generalise this to all groups and so + # it has been deprecated in favour of the LimitActivityGroupShare constraint. inp = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] From 529d2122c66124a567297f28eba04781d22bf2d7 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 10 Jun 2025 12:14:05 -0400 Subject: [PATCH 097/587] Update sets --- temoa/temoa_model/hybrid_loader.py | 2 +- temoa/temoa_model/temoa_model.py | 6 +++--- tests/testing_data/mediumville_sets.json | 3 ++- tests/testing_data/test_system_sets.json | 3 ++- tests/testing_data/utopia_sets.json | 3 ++- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 5fe4dbaf6..5d768957a 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -1105,7 +1105,7 @@ def load_param_idx_sets(self, data: dict) -> dict: M.LimitEmission.name: M.LimitEmissionConstraint_rpe.name, M.LimitActivity.name: M.LimitActivityConstraint_rpt.name, M.LimitSeasonalCapacityFactor.name: M.LimitSeasonalCapacityFactorConstraint_rpst.name, - M.LimitActivityGroup.name: M.LimitActivityGroup_rpg.name, + M.LimitActivityGroup.name: M.LimitActivityGroupConstraint_rpg.name, M.LimitActivityShare.name: M.LimitActivityShareConstraint_rptg.name, M.LimitAnnualCapacityFactor.name: M.LimitAnnualCapacityFactorConstraint_rpto.name, M.LimitCapacity.name: M.LimitCapacityConstraint_rpt.name, diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 6b95254bb..8147a6a0f 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -431,10 +431,10 @@ def __init__(M, *args, **kwargs): M.EmissionActivity_reitvo = Set(dimen=6, initialize=EmissionActivityIndices) M.EmissionActivity = Param(M.EmissionActivity_reitvo) - M.LimitActivityGroup_rpg = Set( + M.LimitActivityGroupConstraint_rpg = Set( within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names * M.operator ) - M.LimitActivityGroup = Param(M.LimitActivityGroup_rpg) + M.LimitActivityGroup = Param(M.LimitActivityGroupConstraint_rpg) M.LimitCapacityGroupConstraint_rpg = Set( within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names * M.operator @@ -714,7 +714,7 @@ def __init__(M, *args, **kwargs): ) M.LimitActivityGroupConstraint = Constraint( - M.LimitActivityGroup_rpg, rule=LimitActivityGroup_Constraint + M.LimitActivityGroupConstraint_rpg, rule=LimitActivityGroup_Constraint ) M.LimitCapacityConstraint = Constraint( diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 9a5e34913..4819ad732 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -3432,7 +3432,7 @@ "ge" ] ], - "LimitActivityGroup_rpg": [ + "LimitActivityGroupConstraint_rpg": [ [ "A", 2025, @@ -3446,6 +3446,7 @@ "ge" ] ], + "LimitActivityGroupShareConstraint_rpgg": [], "LimitActivityShareConstraint_rptg": [], "LimitAnnualCapacityFactorConstraint_rpto": [], "LimitCapacityConstraint_rpt": [ diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 1bb9ca415..fc86cbcb3 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -40394,7 +40394,8 @@ "ge" ] ], - "LimitActivityGroup_rpg": [], + "LimitActivityGroupConstraint_rpg": [], + "LimitActivityGroupShareConstraint_rpgg": [], "LimitActivityShareConstraint_rptg": [], "LimitAnnualCapacityFactorConstraint_rpto": [], "LimitCapacityConstraint_rpt": [], diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index c73999d5d..398186281 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -22045,7 +22045,8 @@ ] ], "LimitActivityConstraint_rpt": [], - "LimitActivityGroup_rpg": [], + "LimitActivityGroupConstraint_rpg": [], + "LimitActivityGroupShareConstraint_rpgg": [], "LimitActivityShareConstraint_rptg": [], "LimitAnnualCapacityFactorConstraint_rpto": [], "LimitCapacityConstraint_rpt": [ From 1c01c0c1a0a316e2d7932a303c673c8975fbb330 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 10 Jun 2025 15:27:48 -0400 Subject: [PATCH 098/587] Generalise techs and groups in Limit tables --- data_files/example_dbs/utopia.sql | 194 +++--- temoa/temoa_model/hybrid_loader.py | 114 ++-- .../temoa_model/model_checking/validators.py | 1 + temoa/temoa_model/temoa_initialize.py | 63 +- temoa/temoa_model/temoa_model.py | 115 ++-- temoa/temoa_model/temoa_rules.py | 614 +++++++++--------- 6 files changed, 571 insertions(+), 530 deletions(-) diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 2c96d4867..9b22db885 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -849,80 +849,74 @@ INSERT INTO Operator VALUES('ge','greater than or equal to'); CREATE TABLE LimitGrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitStorageLevelFraction ( @@ -948,43 +942,40 @@ CREATE TABLE LimitActivity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); + PRIMARY KEY (region, period, tech_or_group, operator) +); +-- CREATE TABLE LimitActivityGroup +-- ( +-- region TEXT, +-- period INTEGER +-- REFERENCES TimePeriod (period), +-- group_name TEXT +-- REFERENCES TechGroup (group_name), +-- operator TEXT NOT NULL DEFAULT "le" +-- REFERENCES Operator (operator), +-- activity REAL, +-- units TEXT, +-- notes TEXT, +-- PRIMARY KEY (region, period, group_name, operator) +-- ); CREATE TABLE LimitActivityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitAnnualCapacityFactor ( @@ -1007,14 +998,13 @@ CREATE TABLE LimitCapacity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); INSERT INTO LimitCapacity VALUES('utopia',1990,'E31','ge',0.1300000000000000044,'',''); INSERT INTO LimitCapacity VALUES('utopia',2000,'E31','ge',0.1300000000000000044,'',''); @@ -1027,104 +1017,98 @@ INSERT INTO LimitCapacity VALUES('utopia',1990,'RHE','le',0.0,'',''); INSERT INTO LimitCapacity VALUES('utopia',1990,'TXD','le',0.5999999999999999778,'',''); INSERT INTO LimitCapacity VALUES('utopia',2000,'TXD','le',1.760000000000000008,'',''); INSERT INTO LimitCapacity VALUES('utopia',2010,'TXD','le',4.759999999999999787,'',''); -CREATE TABLE LimitCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); +-- CREATE TABLE LimitCapacityGroup +-- ( +-- region TEXT, +-- period INTEGER +-- REFERENCES TimePeriod (period), +-- group_name TEXT +-- REFERENCES TechGroup (group_name), +-- operator TEXT NOT NULL DEFAULT "le" +-- REFERENCES Operator (operator), +-- capacity REAL, +-- units TEXT, +-- notes TEXT, +-- PRIMARY KEY (region, period, group_name, operator) +-- ); CREATE TABLE LimitCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitNewCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), new_cap REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); -CREATE TABLE LimitNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); + PRIMARY KEY (region, period, tech_or_group, operator) +); +-- CREATE TABLE LimitNewCapacityGroup +-- ( +-- region TEXT, +-- period INTEGER +-- REFERENCES TimePeriod (period), +-- group_name TEXT +-- REFERENCES TechGroup (group_name), +-- operator TEXT NOT NULL DEFAULT "le" +-- REFERENCES Operator (operator), +-- new_cap REAL, +-- units TEXT, +-- notes TEXT, +-- PRIMARY KEY (region, period, group_name, operator) +-- ); +-- CREATE TABLE LimitNewCapacityGroupShare +-- ( +-- region TEXT, +-- period INTEGER +-- REFERENCES TimePeriod (period), +-- sub_group TEXT +-- REFERENCES TechGroup (group_name), +-- super_group TEXT +-- REFERENCES TechGroup (group_name), +-- operator TEXT NOT NULL DEFAULT "le" +-- REFERENCES Operator (operator), +-- share REAL, +-- notes TEXT, +-- PRIMARY KEY (region, period, sub_group, super_group, operator) +-- ); CREATE TABLE LimitNewCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitResource ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), cum_act REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitSeasonalCapacityFactor ( diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 5d768957a..fdfda4468 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -797,9 +797,9 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N if len(raw) > 0: logger.warning( 'The RenewablePortfolioStandard constraint has been deprecated. Use the ' - 'LimitActivityGroupShare constraint instead, using the same sub group and ' + 'LimitActivityShare constraint instead, using the same sub group and ' 'constructing a new super group for all relevant generators. The constraint ' - 'has been applied but this feature will be removed in the future.' + 'has been applied for now but this feature will be removed in the future.' ) # CostFixed @@ -849,63 +849,63 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # LimitCapacity if self.table_exists('LimitCapacity'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, operator, capacity FROM main.LimitCapacity') - load_element(M.LimitCapacity, raw, self.viable_rt, (0, 2)) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech_or_group, operator, capacity FROM main.LimitCapacity') + load_element(M.LimitCapacity, raw)#, self.viable_rt, (0, 2)) - # LimitNewCap + # LimitNewCapacity if self.table_exists('LimitNewCapacity'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, operator, new_cap FROM main.LimitNewCapacity') - load_element(M.LimitNewCapacity, raw, self.viable_rt, (0, 2)) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech_or_group, operator, new_cap FROM main.LimitNewCapacity') + load_element(M.LimitNewCapacity, raw)#, self.viable_rt, (0, 2)) - # LimitCapacityGroup - if self.table_exists('LimitCapacityGroup'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, operator, capacity FROM main.LimitCapacityGroup') - load_element(M.LimitCapacityGroup, raw) + # # LimitCapacityGroup + # if self.table_exists('LimitCapacityGroup'): + # raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, operator, capacity FROM main.LimitCapacityGroup') + # load_element(M.LimitCapacityGroup, raw) - # LimitNewCapacityGroup - if self.table_exists('LimitNewCapacityGroup'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, operator, new_cap FROM main.LimitNewCapacityGroup') - load_element(M.LimitNewCapacityGroup, raw) + # # LimitNewCapacityGroup + # if self.table_exists('LimitNewCapacityGroup'): + # raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, operator, new_cap FROM main.LimitNewCapacityGroup') + # load_element(M.LimitNewCapacityGroup, raw) # LimitCapacityShare if self.table_exists('LimitCapacityShare'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, group_name, operator, share FROM main.LimitCapacityShare') - load_element(M.LimitCapacityShare, raw, self.viable_rt, (0, 2)) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitCapacityShare') + load_element(M.LimitCapacityShare, raw)#, self.viable_rt, (0, 2)) # LimitNewCapacityShare if self.table_exists('LimitNewCapacityShare'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, group_name, operator, share FROM main.LimitNewCapacityShare') - load_element(M.LimitNewCapacityShare, raw, self.viable_rt, (0, 2)) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitNewCapacityShare') + load_element(M.LimitNewCapacityShare, raw)#, self.viable_rt, (0, 2)) - # LimitNewCapacityGroupShare - if self.table_exists('LimitNewCapacityGroupShare'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitNewCapacityGroupShare') - load_element(M.LimitNewCapacityGroupShare, raw) + # # LimitNewCapacityGroupShare + # if self.table_exists('LimitNewCapacityGroupShare'): + # raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitNewCapacityGroupShare') + # load_element(M.LimitNewCapacityGroupShare, raw) - # LimitActivityGroupShare - if self.table_exists('LimitActivityGroupShare'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitActivityGroupShare') - load_element(M.LimitActivityGroupShare, raw) + # # LimitActivityGroupShare + # if self.table_exists('LimitActivityGroupShare'): + # raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitActivityGroupShare') + # load_element(M.LimitActivityGroupShare, raw) - # LimitActivityGroup - if self.table_exists('LimitActivityGroup'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, operator, activity FROM main.LimitActivityGroup') - load_element(M.LimitActivityGroup, raw) + # # LimitActivityGroup + # if self.table_exists('LimitActivityGroup'): + # raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, operator, activity FROM main.LimitActivityGroup') + # load_element(M.LimitActivityGroup, raw) # LimitActivityShare if self.table_exists('LimitActivityShare'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, group_name, operator, share FROM main.LimitActivityShare') - load_element(M.LimitActivityShare, raw, self.viable_rt, (0, 2)) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitActivityShare') + load_element(M.LimitActivityShare, raw)#, self.viable_rt, (0, 2)) # LimitResource if self.table_exists('LimitResource'): - raw = cur.execute('SELECT region, tech, operator, cum_act FROM main.LimitResource').fetchall() - load_element(M.LimitResource, raw, self.viable_rt, (0, 1)) + raw = cur.execute('SELECT region, tech_or_group, operator, cum_act FROM main.LimitResource').fetchall() + load_element(M.LimitResource, raw)#, self.viable_rt, (0, 1)) # LimitActivity if self.table_exists('LimitActivity'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, operator, activity FROM main.LimitActivity') - load_element(M.LimitActivity, raw, self.viable_rt, (0, 2)) + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech_or_group, operator, activity FROM main.LimitActivity') + load_element(M.LimitActivity, raw)#, self.viable_rt, (0, 2)) # LimitSeasonalCapacityFactor if self.table_exists('LimitSeasonalCapacityFactor'): @@ -919,39 +919,39 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # LimitGrowthCapacity if self.table_exists('LimitGrowthCapacity'): - raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.LimitGrowthCapacity').fetchall() + raw = cur.execute('SELECT region, tech_or_group, operator, rate, seed FROM main.LimitGrowthCapacity').fetchall() raw = self.tuple_values(raw, 3) - load_element(M.LimitGrowthCapacity, raw, self.viable_rt, (0, 1)) + load_element(M.LimitGrowthCapacity, raw)#, self.viable_rt, (0, 1)) # LimitDegrowthCapacity if self.table_exists('LimitDegrowthCapacity'): - raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.LimitDegrowthCapacity').fetchall() + raw = cur.execute('SELECT region, tech_or_group, operator, rate, seed FROM main.LimitDegrowthCapacity').fetchall() raw = self.tuple_values(raw, 3) - load_element(M.LimitDegrowthCapacity, raw, self.viable_rt, (0, 1)) + load_element(M.LimitDegrowthCapacity, raw)#, self.viable_rt, (0, 1)) # LimitGrowthNewCapacity if self.table_exists('LimitGrowthNewCapacity'): - raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.LimitGrowthNewCapacity').fetchall() + raw = cur.execute('SELECT region, tech_or_group, operator, rate, seed FROM main.LimitGrowthNewCapacity').fetchall() raw = self.tuple_values(raw, 3) - load_element(M.LimitGrowthNewCapacity, raw, self.viable_rt, (0, 1)) + load_element(M.LimitGrowthNewCapacity, raw)#, self.viable_rt, (0, 1)) # LimitDegrowthNewCapacity if self.table_exists('LimitDegrowthNewCapacity'): - raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.LimitDegrowthNewCapacity').fetchall() + raw = cur.execute('SELECT region, tech_or_group, operator, rate, seed FROM main.LimitDegrowthNewCapacity').fetchall() raw = self.tuple_values(raw, 3) - load_element(M.LimitDegrowthNewCapacity, raw, self.viable_rt, (0, 1)) + load_element(M.LimitDegrowthNewCapacity, raw)#, self.viable_rt, (0, 1)) # LimitGrowthNewCapacityDelta if self.table_exists('LimitGrowthNewCapacityDelta'): - raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.LimitGrowthNewCapacityDelta').fetchall() + raw = cur.execute('SELECT region, tech_or_group, operator, rate, seed FROM main.LimitGrowthNewCapacityDelta').fetchall() raw = self.tuple_values(raw, 3) - load_element(M.LimitGrowthNewCapacityDelta, raw, self.viable_rt, (0, 1)) + load_element(M.LimitGrowthNewCapacityDelta, raw)#, self.viable_rt, (0, 1)) # LimitDegrowthNewCapacityDelta if self.table_exists('LimitDegrowthNewCapacityDelta'): - raw = cur.execute('SELECT region, tech, operator, rate, seed FROM main.LimitDegrowthNewCapacityDelta').fetchall() + raw = cur.execute('SELECT region, tech_or_group, operator, rate, seed FROM main.LimitDegrowthNewCapacityDelta').fetchall() raw = self.tuple_values(raw, 3) - load_element(M.LimitDegrowthNewCapacityDelta, raw, self.viable_rt, (0, 1)) + load_element(M.LimitDegrowthNewCapacityDelta, raw)#, self.viable_rt, (0, 1)) # LimitEmission if self.table_exists('LimitEmission'): @@ -1105,17 +1105,17 @@ def load_param_idx_sets(self, data: dict) -> dict: M.LimitEmission.name: M.LimitEmissionConstraint_rpe.name, M.LimitActivity.name: M.LimitActivityConstraint_rpt.name, M.LimitSeasonalCapacityFactor.name: M.LimitSeasonalCapacityFactorConstraint_rpst.name, - M.LimitActivityGroup.name: M.LimitActivityGroupConstraint_rpg.name, - M.LimitActivityShare.name: M.LimitActivityShareConstraint_rptg.name, + # M.LimitActivityGroup.name: M.LimitActivityGroupConstraint_rpg.name, + M.LimitActivityShare.name: M.LimitActivityShareConstraint_rpgg.name, M.LimitAnnualCapacityFactor.name: M.LimitAnnualCapacityFactorConstraint_rpto.name, M.LimitCapacity.name: M.LimitCapacityConstraint_rpt.name, - M.LimitCapacityGroup.name: M.LimitCapacityGroupConstraint_rpg.name, - M.LimitCapacityShare.name: M.LimitCapacityShareConstraint_rptg.name, + # M.LimitCapacityGroup.name: M.LimitCapacityGroupConstraint_rpg.name, + M.LimitCapacityShare.name: M.LimitCapacityShareConstraint_rpgg.name, M.LimitNewCapacity.name: M.LimitNewCapacityConstraint_rpt.name, - M.LimitNewCapacityGroup.name: M.LimitNewCapacityGroupConstraint_rpg.name, - M.LimitNewCapacityShare.name: M.LimitNewCapacityShareConstraint_rptg.name, - M.LimitNewCapacityGroupShare.name: M.LimitNewCapacityGroupShareConstraint_rpgg.name, - M.LimitActivityGroupShare.name: M.LimitActivityGroupShareConstraint_rpgg.name, + # M.LimitNewCapacityGroup.name: M.LimitNewCapacityGroupConstraint_rpg.name, + M.LimitNewCapacityShare.name: M.LimitNewCapacityShareConstraint_rpgg.name, + # M.LimitNewCapacityGroupShare.name: M.LimitNewCapacityGroupShareConstraint_rpgg.name, + # M.LimitActivityGroupShare.name: M.LimitActivityGroupShareConstraint_rpgg.name, M.LimitResource.name: M.LimitResourceConstraint_rt.name, M.LimitStorageFraction.name: M.LimitStorageFractionConstraint_rpsdtv.name, M.RenewablePortfolioStandard.name: M.RenewablePortfolioStandardConstraint_rpg.name, diff --git a/temoa/temoa_model/model_checking/validators.py b/temoa/temoa_model/model_checking/validators.py index 996ccfd25..4aab12ff2 100644 --- a/temoa/temoa_model/model_checking/validators.py +++ b/temoa/temoa_model/model_checking/validators.py @@ -317,6 +317,7 @@ def validate_tech_sets(M: 'TemoaModel'): check_no_intersection(M.tech_annual, M.tech_downramping), check_no_intersection(M.tech_annual, M.tech_curtailment), check_no_intersection(M.tech_curtailment, M.tech_flex), + check_no_intersection(M.tech_all, M.tech_group_names), ) ): raise ValueError("Technology sets failed to validate. Check log file for details.") diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 0d8037c04..fb05d6a5e 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1153,29 +1153,44 @@ def RegionalGlobalInitializedIndices(M: 'TemoaModel'): return indices -def GroupShareIndices(M: 'TemoaModel'): - indices = set( - (r, p, t, g, op) - for g in M.tech_group_names - for r, p, t in M.groupRegionActiveFlow_rpt - for op in M.operator - if t in M.tech_group_members[g] - ) +# def GroupShareIndices(M: 'TemoaModel'): +# indices = set( +# (r, p, t, g, op) +# for g in M.tech_group_names +# for r, p, t in M.groupRegionActiveFlow_rpt +# for op in M.operator +# if t in M.tech_group_members[g] +# ) - return indices +# return indices -def TwoGroupShareIndices(M: 'TemoaModel'): - indices = set( - (r, p, g1, g2, op) - for g1 in M.tech_group_names - for g2 in M.tech_group_names - for r, p, _t in M.groupRegionActiveFlow_rpt - for op in M.operator - if _t in M.tech_group_members[g2] - ) +# def GroupShareIndices(M: 'TemoaModel'): +# indices = set( +# (r, p, g1, g2, op) +# for op in M.operator +# for g1 in M.tech_or_group +# for g2 in M.tech_or_group +# for r, p, t in M.groupRegionActiveFlow_rpt +# for _r, _p, _t in M.groupRegionActiveFlow_rpt +# if r==_r and p==_p +# if t in gather_group_techs(M, g1) and _t in gather_group_techs(M, g2) +# ) - return indices +# return indices + + +# def TwoGroupShareIndices(M: 'TemoaModel'): +# indices = set( +# (r, p, g1, g2, op) +# for g1 in M.tech_group_names +# for g2 in M.tech_group_names +# for r, p, _t in M.groupRegionActiveFlow_rpt +# for op in M.operator +# if _t in M.tech_group_members[g2] +# ) + +# return indices def EmissionActivityIndices(M: 'TemoaModel'): @@ -1705,6 +1720,16 @@ def gather_group_regions(M: 'TemoaModel', region: str) -> Iterable[str]: return regions +def gather_group_techs(M: 'TemoaModel', t_or_g: str) -> Iterable[str]: + if t_or_g in M.tech_group_names: + techs = M.tech_group_members[t_or_g] + elif '+' in t_or_g: + techs = t_or_g.split('+') + else: + techs = (t_or_g,) + return techs + + def get_loan_life(M, r, t, _): return M.LoanLifetimeTech[r, t] diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 8147a6a0f..621637eb7 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -179,11 +179,11 @@ def __init__(M, *args, **kwargs): M.tech_flex = Set(within=M.tech_all) # ensure there is no overlap flex <=> curtailable technologies M.tech_exchange = Set(within=M.tech_all) - M.validate_techs = BuildAction(rule=validate_tech_sets) # Define groups for technologies M.tech_group_names = Set() M.tech_group_members = Set(M.tech_group_names, within=M.tech_all) + M.tech_or_group = Set(initialize=M.tech_group_names | M.tech_all) M.tech_uncap = Set(within=M.tech_all - M.tech_reserve) """techs with unlimited capacity, ALWAYS available within lifespan""" @@ -199,6 +199,8 @@ def __init__(M, *args, **kwargs): # process, which is currently incapable of reducing initializations on retirements. M.tech_retirement = Set(within=M.tech_all - M.tech_storage) + M.validate_techs = BuildAction(rule=validate_tech_sets) + # Define commodity-related sets M.commodity_demand = Set() M.commodity_emissions = Set() @@ -390,20 +392,20 @@ def __init__(M, *args, **kwargs): M.ProcessLifeFrac = Param(M.ProcessLifeFrac_rptv, initialize=ParamProcessLifeFraction_rule) M.LimitCapacityConstraint_rpt = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_with_capacity * M.operator + within=M.regionalGlobalIndices * M.time_optimize * M.tech_or_group * M.operator ) M.LimitCapacity = Param(M.LimitCapacityConstraint_rpt) M.LimitNewCapacityConstraint_rpt = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_with_capacity * M.operator + within=M.regionalGlobalIndices * M.time_optimize * M.tech_or_group * M.operator ) M.LimitNewCapacity = Param(M.LimitNewCapacityConstraint_rpt) - M.LimitResourceConstraint_rt = Set(within=M.regionalGlobalIndices * M.tech_all * M.operator) + M.LimitResourceConstraint_rt = Set(within=M.regionalGlobalIndices * M.tech_or_group * M.operator) M.LimitResource = Param(M.LimitResourceConstraint_rt) M.LimitActivityConstraint_rpt = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_all * M.operator + within=M.regionalGlobalIndices * M.time_optimize * M.tech_or_group * M.operator ) M.LimitActivity = Param(M.LimitActivityConstraint_rpt) @@ -417,12 +419,12 @@ def __init__(M, *args, **kwargs): ) M.LimitAnnualCapacityFactor = Param(M.LimitAnnualCapacityFactorConstraint_rpto, validate=validate_0to1) - M.LimitGrowthCapacity = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) - M.LimitDegrowthCapacity = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) - M.LimitGrowthNewCapacity = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) - M.LimitDegrowthNewCapacity = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) - M.LimitGrowthNewCapacityDelta = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) - M.LimitDegrowthNewCapacityDelta = Param(M.regionalGlobalIndices, M.tech_all, M.operator, domain=Any) + M.LimitGrowthCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any) + M.LimitDegrowthCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any) + M.LimitGrowthNewCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any) + M.LimitDegrowthNewCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any) + M.LimitGrowthNewCapacityDelta = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any) + M.LimitDegrowthNewCapacityDelta = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any) M.LimitEmissionConstraint_rpe = Set( within=M.regionalGlobalIndices * M.time_optimize * M.commodity_emissions * M.operator @@ -431,38 +433,40 @@ def __init__(M, *args, **kwargs): M.EmissionActivity_reitvo = Set(dimen=6, initialize=EmissionActivityIndices) M.EmissionActivity = Param(M.EmissionActivity_reitvo) - M.LimitActivityGroupConstraint_rpg = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names * M.operator - ) - M.LimitActivityGroup = Param(M.LimitActivityGroupConstraint_rpg) + # devnote: deprecated when generalising tech/group columns in Limit tables + # M.LimitActivityGroupConstraint_rpg = Set( + # within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names * M.operator + # ) + # M.LimitActivityGroup = Param(M.LimitActivityGroupConstraint_rpg) - M.LimitCapacityGroupConstraint_rpg = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names * M.operator - ) - M.LimitCapacityGroup = Param(M.LimitCapacityGroupConstraint_rpg) + # M.LimitCapacityGroupConstraint_rpg = Set( + # within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names * M.operator + # ) + # M.LimitCapacityGroup = Param(M.LimitCapacityGroupConstraint_rpg) - M.LimitNewCapacityGroupConstraint_rpg = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names * M.operator - ) - M.LimitNewCapacityGroup = Param(M.LimitNewCapacityGroupConstraint_rpg) - M.GroupShareIndices = Set(dimen=5, initialize=GroupShareIndices) + # M.LimitNewCapacityGroupConstraint_rpg = Set( + # within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names * M.operator + # ) + # M.LimitNewCapacityGroup = Param(M.LimitNewCapacityGroupConstraint_rpg) + # M.GroupShareIndices = Set(dimen=5, initialize=GroupShareIndices) # doesn't feel worth it - M.LimitCapacityShareConstraint_rptg = Set(within=M.GroupShareIndices) - M.LimitCapacityShare = Param(M.GroupShareIndices) + M.LimitCapacityShareConstraint_rpgg = Set(within=M.regionalGlobalIndices * M.time_optimize * M.tech_or_group * M.tech_or_group * M.operator) + M.LimitCapacityShare = Param(M.LimitCapacityShareConstraint_rpgg) - M.LimitActivityShareConstraint_rptg = Set(within=M.GroupShareIndices) - M.LimitActivityShare = Param(M.GroupShareIndices) + M.LimitActivityShareConstraint_rpgg = Set(within=M.regionalGlobalIndices * M.time_optimize * M.tech_or_group * M.tech_or_group * M.operator) + M.LimitActivityShare = Param(M.LimitActivityShareConstraint_rpgg) - M.LimitNewCapacityShareConstraint_rptg = Set(within=M.GroupShareIndices) - M.LimitNewCapacityShare = Param(M.GroupShareIndices) + M.LimitNewCapacityShareConstraint_rpgg = Set(within=M.regionalGlobalIndices * M.time_optimize * M.tech_or_group * M.tech_or_group * M.operator) + M.LimitNewCapacityShare = Param(M.LimitNewCapacityShareConstraint_rpgg) - M.TwoGroupShareIndices = Set(dimen=5, initialize=TwoGroupShareIndices) + # devnote: deprecated when generalising tech/group columns in Limit tables + # M.TwoGroupShareIndices = Set(dimen=5, initialize=TwoGroupShareIndices) - M.LimitNewCapacityGroupShareConstraint_rpgg = Set(within=M.TwoGroupShareIndices) - M.LimitNewCapacityGroupShare = Param(M.TwoGroupShareIndices) + # M.LimitNewCapacityGroupShareConstraint_rpgg = Set(within=M.TwoGroupShareIndices) + # M.LimitNewCapacityGroupShare = Param(M.TwoGroupShareIndices) - M.LimitActivityGroupShareConstraint_rpgg = Set(within=M.TwoGroupShareIndices) - M.LimitActivityGroupShare = Param(M.TwoGroupShareIndices) + # M.LimitActivityGroupShareConstraint_rpgg = Set(within=M.TwoGroupShareIndices) + # M.LimitActivityGroupShare = Param(M.TwoGroupShareIndices) # This set works for all storage-related constraints M.StorageConstraints_rpsdtv = Set(dimen=6, initialize=StorageConstraintIndices) @@ -614,7 +618,7 @@ def __init__(M, *args, **kwargs): M.AnnualCommodityBalanceConstraint = Constraint( M.AnnualCommodityBalanceConstraint_rpc, rule=AnnualCommodityBalance_Constraint ) - + # M.ResourceExtractionConstraint = Constraint( # M.ResourceConstraint_rpr, rule=ResourceExtraction_Constraint # ) @@ -713,9 +717,10 @@ def __init__(M, *args, **kwargs): M.LimitSeasonalCapacityFactorConstraint_rpst, rule=LimitSeasonalCapacityFactor_Constraint ) - M.LimitActivityGroupConstraint = Constraint( - M.LimitActivityGroupConstraint_rpg, rule=LimitActivityGroup_Constraint - ) + # devnote: deprecated when generalising tech/group columns in Limit tables + # M.LimitActivityGroupConstraint = Constraint( + # M.LimitActivityGroupConstraint_rpg, rule=LimitActivityGroup_Constraint + # ) M.LimitCapacityConstraint = Constraint( M.LimitCapacityConstraint_rpt, rule=LimitCapacity_Constraint @@ -725,33 +730,35 @@ def __init__(M, *args, **kwargs): M.LimitNewCapacityConstraint_rpt, rule=LimitNewCapacity_Constraint ) - M.LimitCapacityGroupConstraint = Constraint( - M.LimitCapacityGroupConstraint_rpg, rule=LimitCapacityGroup_Constraint - ) + # devnote: deprecated when generalising tech/group columns in Limit tables + # M.LimitCapacityGroupConstraint = Constraint( + # M.LimitCapacityGroupConstraint_rpg, rule=LimitCapacityGroup_Constraint + # ) - M.LimitNewCapacityGroupConstraint = Constraint( - M.LimitNewCapacityGroupConstraint_rpg, rule=LimitNewCapacityGroup_Constraint - ) + # M.LimitNewCapacityGroupConstraint = Constraint( + # M.LimitNewCapacityGroupConstraint_rpg, rule=LimitNewCapacityGroup_Constraint + # ) M.LimitCapacityShareConstraint = Constraint( - M.LimitCapacityShareConstraint_rptg, rule=LimitCapacityShare_Constraint + M.LimitCapacityShareConstraint_rpgg, rule=LimitCapacityShare_Constraint ) M.LimitActivityShareConstraint = Constraint( - M.LimitActivityShareConstraint_rptg, rule=LimitActivityShare_Constraint + M.LimitActivityShareConstraint_rpgg, rule=LimitActivityShare_Constraint ) M.LimitNewCapacityShareConstraint = Constraint( - M.LimitNewCapacityShareConstraint_rptg, rule=LimitNewCapacityShare_Constraint + M.LimitNewCapacityShareConstraint_rpgg, rule=LimitNewCapacityShare_Constraint ) - M.LimitNewCapacityGroupShareConstraint = Constraint( - M.LimitNewCapacityGroupShareConstraint_rpgg, rule=LimitNewCapacityGroupShare_Constraint - ) + # devnote: deprecated when generalising tech/group columns in Limit tables + # M.LimitNewCapacityGroupShareConstraint = Constraint( + # M.LimitNewCapacityGroupShareConstraint_rpgg, rule=LimitNewCapacityGroupShare_Constraint + # ) - M.LimitActivityGroupShareConstraint = Constraint( - M.LimitActivityGroupShareConstraint_rpgg, rule=LimitActivityGroupShare_Constraint - ) + # M.LimitActivityGroupShareConstraint = Constraint( + # M.LimitActivityGroupShareConstraint_rpgg, rule=LimitActivityGroupShare_Constraint + # ) M.progress_marker_8 = BuildAction( ['Starting Limit Capacity and Tech Split ' 'Constraints'], rule=progress_check diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index a6ca099c3..155c4a98b 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -22,7 +22,6 @@ from logging import getLogger from sys import stderr as SE from typing import TYPE_CHECKING -from deprecated import deprecated from pyomo.core import Var, Expression from pyomo.environ import Constraint, value @@ -32,6 +31,7 @@ CommodityBalanceConstraintErrorCheck, AnnualCommodityBalanceConstraintErrorCheck, gather_group_regions, + gather_group_techs, ) if TYPE_CHECKING: @@ -1872,6 +1872,7 @@ def LimitGrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): """ regions = gather_group_regions(M, r) + techs = gather_group_techs(M, t) growth = M.LimitDegrowthCapacity if degrowth else M.LimitGrowthCapacity RATE = 1 + value(growth[r, t, op][0]) @@ -1879,7 +1880,7 @@ def LimitGrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): CapRPT = M.V_CapacityAvailableByPeriodAndTech # relevant r, p, t indices - cap_rpt = set((_r, _p, _t) for _r, _p, _t in CapRPT if _t == t and _r in regions) + cap_rpt = set((_r, _p, _t) for _r, _p, _t in CapRPT if _t in techs and _r in regions) # periods the technology can have capacity in this region (sorted) periods = sorted(set(_p for _r, _p, _t in cap_rpt)) @@ -1920,7 +1921,7 @@ def LimitGrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): value(M.ExistingCapacity[_r, _t, _v]) \ * min( 1.0, (_v + value(M.LifetimeProcess[_r, _t, _v]) - p_prev)/(p - p_prev) ) for _r, _t, _v in M.ExistingCapacity - if _r in regions and _t == t and _v + value(M.LifetimeProcess[_r, _t, _v]) > p_prev + if _r in regions and _t in techs and _v + value(M.LifetimeProcess[_r, _t, _v]) > p_prev ) else: # Otherwise, grab previous future period @@ -1960,6 +1961,7 @@ def LimitGrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False) """ regions = gather_group_regions(M, r) + techs = gather_group_techs(M, t) growth = M.LimitDegrowthNewCapacity if degrowth else M.LimitGrowthNewCapacity RATE = 1 + value(growth[r, t, op][0]) @@ -1967,7 +1969,7 @@ def LimitGrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False) NewCapRTV = M.V_NewCapacity # relevant r, t, v indices - cap_rtv = set((_r, _t, _v) for _r, _t, _v in NewCapRTV if _t == t and _r in regions) + cap_rtv = set((_r, _t, _v) for _r, _t, _v in NewCapRTV if _t in techs and _r in regions) # periods the technology can be built in this region (sorted) periods = sorted(set(_v for _r, _t, _v in NewCapRTV if _v in M.time_optimize)) @@ -2006,7 +2008,7 @@ def LimitGrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False) new_cap_prev = sum( value(M.ExistingCapacity[_r, _t, _v]) for _r, _t, _v in M.ExistingCapacity - if _r in regions and _t == t and _v == p_prev + if _r in regions and _t in techs and _v == p_prev ) else: # Otherwise, grab previous future vintage @@ -2046,6 +2048,7 @@ def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = F """ regions = gather_group_regions(M, r) + techs = gather_group_techs(M, t) growth = M.LimitDegrowthNewCapacityDelta if degrowth else M.LimitGrowthNewCapacityDelta RATE = 1 + value(growth[r, t, op][0]) @@ -2053,7 +2056,7 @@ def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = F NewCapRTV = M.V_NewCapacity # relevant r, t, v indices - cap_rtv = set((_r, _t, _v) for _r, _t, _v in NewCapRTV if _t == t and _r in regions) + cap_rtv = set((_r, _t, _v) for _r, _t, _v in NewCapRTV if _t in techs and _r in regions) # periods the technology can be built in this region (sorted) periods = sorted(set(_v for _r, _t, _v in cap_rtv if _v in M.time_optimize)) @@ -2093,13 +2096,13 @@ def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = F new_cap_prev = sum( value(M.ExistingCapacity[_r, _t, _v]) for _r, _t, _v in M.ExistingCapacity - if _r in regions and _t == t and _v == p_prev + if _r in regions and _t in techs and _v == p_prev ) p_prev2 = M.time_exist.prev(p_prev) new_cap_prev2 = sum( value(M.ExistingCapacity[_r, _t, _v]) for _r, _t, _v in M.ExistingCapacity - if _r in regions and _t == t and _v == p_prev2 + if _r in regions and _t in techs and _v == p_prev2 ) else: # Not the first future period. Grab previous future period @@ -2115,7 +2118,7 @@ def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = F new_cap_prev2 = sum( value(M.ExistingCapacity[_r, _t, _v]) for _r, _t, _v in M.ExistingCapacity - if _r in regions and _t == t and _v == p_prev2 + if _r in regions and _t in techs and _v == p_prev2 ) else: # At least the third future period. Grab last two future vintages @@ -2164,31 +2167,32 @@ def LimitActivity_Constraint(M: 'TemoaModel', r, p, t, op): # r can be an individual region (r='US'), or a combination of regions separated by # a + (r='Mexico+US+Canada'), or 'global'. # if r == 'global', the constraint is system-wide - regions = gather_group_regions(M=M, region=r) + regions = gather_group_regions(M, r) + techs = gather_group_techs(M, t) - if t not in M.tech_annual: - activity_rpt = sum( - M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] - for _r in regions - for S_v in M.processVintages.get((_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[p] - for d in M.time_of_day - if (_r, p, s, d, S_i, t, S_v, S_o) in M.V_FlowOut - ) - else: - activity_rpt = sum( - M.V_FlowOutAnnual[_r, p, S_i, t, S_v, S_o] - for _r in regions - for S_v in M.processVintages.get((_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] - if (_r, p, S_i, t, S_v, S_o) in M.V_FlowOutAnnual - ) + activity = sum( + M.V_FlowOut[_r, p, s, d, S_i, _t, S_v, S_o] + for _t in techs if _t not in M.tech_annual + for _r in regions + for S_v in M.processVintages.get((_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[p] + for d in M.time_of_day + if (_r, p, s, d, S_i, _t, S_v, S_o) in M.V_FlowOut + ) + activity += sum( + M.V_FlowOutAnnual[_r, p, S_i, _t, S_v, S_o] + for _t in techs if _t in M.tech_annual + for _r in regions + for S_v in M.processVintages.get((_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] + if (_r, p, S_i, _t, S_v, S_o) in M.V_FlowOutAnnual + ) act_lim = value(M.LimitActivity[r, p, t, op]) - expr = operator_expression(activity_rpt, op, act_lim) + expr = operator_expression(activity, op, act_lim) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated return Constraint.Skip @@ -2254,128 +2258,130 @@ def LimitActivity_Constraint(M: 'TemoaModel', r, p, t, op): # return expr -def LimitActivityGroup_Constraint(M: 'TemoaModel', r, p, g, op): - r""" - The LimitActivityGroup constraint sets an activity limit for a user-defined - technology group. - .. math:: - :label: LimitActivityGroup - \sum_{R,S,D,I,T,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} + \sum_{I,T,V,O} - \textbf{FOA}_{r, p, i, t, v, o} - \le MxAG_{r, p, g} - \forall \{r, p, g\} \in \Theta_{\text{LimitActivityGroup}} - where :math:`g` represents the assigned technology group and :math:`MxAG` - refers to the :code:`LimitActivityGroup` parameter.""" +# devnote: deprecated when generalising tech/group columns in Limit tables +# def LimitActivityGroup_Constraint(M: 'TemoaModel', r, p, g, op): +# r""" +# The LimitActivityGroup constraint sets an activity limit for a user-defined +# technology group. +# .. math:: +# :label: LimitActivityGroup +# \sum_{R,S,D,I,T,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} + \sum_{I,T,V,O} +# \textbf{FOA}_{r, p, i, t, v, o} +# \le MxAG_{r, p, g} +# \forall \{r, p, g\} \in \Theta_{\text{LimitActivityGroup}} +# where :math:`g` represents the assigned technology group and :math:`MxAG` +# refers to the :code:`LimitActivityGroup` parameter.""" - regions = gather_group_regions(M, r) +# regions = gather_group_regions(M, r) - activity_p = 0 - activity_p_annual = 0 - for _r in regions: - activity_p += sum( - M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] - for S_t in M.tech_group_members[g] - if (_r, p, S_t) in M.processVintages and S_t not in M.tech_annual - for S_v in M.processVintages[_r, p, S_t] - for S_i in M.processInputs[_r, p, S_t, S_v] - for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - for s in M.time_season[p] - for d in M.time_of_day - if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut - ) - activity_p_annual += sum( - M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] - for S_t in M.tech_group_members[g] - if (_r, p, S_t) in M.processVintages and S_t in M.tech_annual - for S_v in M.processVintages[_r, p, S_t] - for S_i in M.processInputs[_r, p, S_t, S_v] - for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual - ) +# activity_p = 0 +# activity_p_annual = 0 +# for _r in regions: +# activity_p += sum( +# M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] +# for S_t in M.tech_group_members[g] +# if (_r, p, S_t) in M.processVintages and S_t not in M.tech_annual +# for S_v in M.processVintages[_r, p, S_t] +# for S_i in M.processInputs[_r, p, S_t, S_v] +# for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] +# for s in M.time_season[p] +# for d in M.time_of_day +# if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut +# ) +# activity_p_annual += sum( +# M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] +# for S_t in M.tech_group_members[g] +# if (_r, p, S_t) in M.processVintages and S_t in M.tech_annual +# for S_v in M.processVintages[_r, p, S_t] +# for S_i in M.processInputs[_r, p, S_t, S_v] +# for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] +# if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual +# ) - act_lim = value(M.LimitActivityGroup[r, p, g, op]) - expr = operator_expression(activity_p + activity_p_annual, op, act_lim) - # in the case that there is nothing to sum, skip - if isinstance(expr, bool): # an empty list was generated - logger.warning( - 'Missing group techs to support LimitActivityGroup constraint: %s.' - ' Check data/log for available/suppressed techs. Constraint ignored.', - (r, p, g) - ) - return Constraint.Skip - return expr +# act_lim = value(M.LimitActivityGroup[r, p, g, op]) +# expr = operator_expression(activity_p + activity_p_annual, op, act_lim) +# # in the case that there is nothing to sum, skip +# if isinstance(expr, bool): # an empty list was generated +# logger.warning( +# 'Missing group techs to support LimitActivityGroup constraint: %s.' +# ' Check data/log for available/suppressed techs. Constraint ignored.', +# (r, p, g) +# ) +# return Constraint.Skip +# return expr -def LimitActivityGroupShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): - r""" - The LimitActivityGroup constraint sets an activity limit for a user-defined - technology group. - .. math:: - :label: LimitActivityGroup - \sum_{R,S,D,I,T,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} + \sum_{I,T,V,O} - \textbf{FOA}_{r, p, i, t, v, o} - \le MxAG_{r, p, g} - \forall \{r, p, g\} \in \Theta_{\text{LimitActivityGroup}} - where :math:`g` represents the assigned technology group and :math:`MxAG` - refers to the :code:`LimitActivityGroup` parameter.""" +# devnote: deprecated when generalising tech/group columns in Limit tables +# def LimitActivityGroupShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): +# r""" +# The LimitActivityGroup constraint sets an activity limit for a user-defined +# technology group. +# .. math:: +# :label: LimitActivityGroup +# \sum_{R,S,D,I,T,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} + \sum_{I,T,V,O} +# \textbf{FOA}_{r, p, i, t, v, o} +# \le MxAG_{r, p, g} +# \forall \{r, p, g\} \in \Theta_{\text{LimitActivityGroup}} +# where :math:`g` represents the assigned technology group and :math:`MxAG` +# refers to the :code:`LimitActivityGroup` parameter.""" - regions = gather_group_regions(M, r) +# regions = gather_group_regions(M, r) - activity_g1 = 0 - activity_g2 = 0 - for _r in regions: - activity_g1 += sum( - M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] - for S_t in M.tech_group_members[g1] - if (_r, p, S_t) in M.processVintages and S_t not in M.tech_annual - for S_v in M.processVintages[_r, p, S_t] - for S_i in M.processInputs[_r, p, S_t, S_v] - for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - for s in M.time_season[p] - for d in M.time_of_day - if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut - ) - activity_g1 += sum( - M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] - for S_t in M.tech_group_members[g1] - if (_r, p, S_t) in M.processVintages and S_t in M.tech_annual - for S_v in M.processVintages[_r, p, S_t] - for S_i in M.processInputs[_r, p, S_t, S_v] - for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual - ) - activity_g2 += sum( - M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] - for S_t in M.tech_group_members[g2] - if (_r, p, S_t) in M.processVintages and S_t not in M.tech_annual - for S_v in M.processVintages[_r, p, S_t] - for S_i in M.processInputs[_r, p, S_t, S_v] - for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - for s in M.time_season[p] - for d in M.time_of_day - if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut - ) - activity_g2 += sum( - M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] - for S_t in M.tech_group_members[g2] - if (_r, p, S_t) in M.processVintages and S_t in M.tech_annual - for S_v in M.processVintages[_r, p, S_t] - for S_i in M.processInputs[_r, p, S_t, S_v] - for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual - ) +# activity_g1 = 0 +# activity_g2 = 0 +# for _r in regions: +# activity_g1 += sum( +# M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] +# for S_t in M.tech_group_members[g1] +# if (_r, p, S_t) in M.processVintages and S_t not in M.tech_annual +# for S_v in M.processVintages[_r, p, S_t] +# for S_i in M.processInputs[_r, p, S_t, S_v] +# for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] +# for s in M.time_season[p] +# for d in M.time_of_day +# if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut +# ) +# activity_g1 += sum( +# M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] +# for S_t in M.tech_group_members[g1] +# if (_r, p, S_t) in M.processVintages and S_t in M.tech_annual +# for S_v in M.processVintages[_r, p, S_t] +# for S_i in M.processInputs[_r, p, S_t, S_v] +# for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] +# if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual +# ) +# activity_g2 += sum( +# M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] +# for S_t in M.tech_group_members[g2] +# if (_r, p, S_t) in M.processVintages and S_t not in M.tech_annual +# for S_v in M.processVintages[_r, p, S_t] +# for S_i in M.processInputs[_r, p, S_t, S_v] +# for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] +# for s in M.time_season[p] +# for d in M.time_of_day +# if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut +# ) +# activity_g2 += sum( +# M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] +# for S_t in M.tech_group_members[g2] +# if (_r, p, S_t) in M.processVintages and S_t in M.tech_annual +# for S_v in M.processVintages[_r, p, S_t] +# for S_i in M.processInputs[_r, p, S_t, S_v] +# for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] +# if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual +# ) - share_lim = value(M.LimitActivityGroupShare[r, p, g1, g2, op]) - expr = operator_expression(activity_g1, op, share_lim * activity_g2) - # in the case that there is nothing to sum, skip - if isinstance(expr, bool): # an empty list was generated - logger.warning( - 'Missing group techs to support LimitActivityGroupShare constraint: %s.' - ' Check data/log for available/suppressed techs. Constraint ignored.', - (r, p, g1, g2) - ) - return Constraint.Skip - return expr +# share_lim = value(M.LimitActivityGroupShare[r, p, g1, g2, op]) +# expr = operator_expression(activity_g1, op, share_lim * activity_g2) +# # in the case that there is nothing to sum, skip +# if isinstance(expr, bool): # an empty list was generated +# logger.warning( +# 'Missing group techs to support LimitActivityGroupShare constraint: %s.' +# ' Check data/log for available/suppressed techs. Constraint ignored.', +# (r, p, g1, g2) +# ) +# return Constraint.Skip +# return expr def LimitNewCapacity_Constraint(M: 'TemoaModel', r, p, t, op): @@ -2387,9 +2393,11 @@ def LimitNewCapacity_Constraint(M: 'TemoaModel', r, p, t, op): :label: LimitNewCapacity \textbf{CAP}_{r, t, p} \le LIM_{r, p, t}""" regions = gather_group_regions(M, r) + techs = gather_group_techs(M, t) cap_lim = value(M.LimitNewCapacity[r, p, t, op]) new_cap = sum( - M.V_NewCapacity[_r, t, p] + M.V_NewCapacity[_r, _t, p] + for _t in techs for _r in regions ) expr = operator_expression(new_cap, op, cap_lim) @@ -2410,9 +2418,11 @@ def LimitCapacity_Constraint(M: 'TemoaModel', r, p, t, op): \forall \{r, p, t\} \in \Theta_{\text{LimitCapacity}}""" regions = gather_group_regions(M, r) + techs = gather_group_techs(M, t) cap_lim = value(M.LimitCapacity[r, p, t, op]) capacity = sum( - M.V_CapacityAvailableByPeriodAndTech[_r, p, t] + M.V_CapacityAvailableByPeriodAndTech[_r, p, _t] + for _t in techs for _r in regions ) expr = operator_expression(capacity, op, cap_lim) @@ -2442,156 +2452,159 @@ def LimitResource_Constraint(M: 'TemoaModel', r, t, op): # oil/mineral extraction across all model periods. Looks fine to me. regions = gather_group_regions(M, r) + techs = gather_group_techs(M, t) - if t in M.tech_annual: - activity_rt = sum( - M.V_FlowOutAnnual[_r, p, S_i, t, S_v, S_o] - for p in M.time_optimize - for _r in regions - if (_r, p, t) in M.processVintages - 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] - ) - else: - activity_rt = sum( - M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] - for p in M.time_optimize - for _r in regions - if (_r, p, t) in M.processVintages - 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[p] - for d in M.time_of_day - ) + activity = sum( + M.V_FlowOutAnnual[_r, p, S_i, _t, S_v, S_o] + for _t in techs if _t in M.tech_annual + for p in M.time_optimize + for _r in regions + if (_r, p, _t) in M.processVintages + 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] + ) + activity += sum( + M.V_FlowOut[_r, p, s, d, S_i, _t, S_v, S_o] + for _t in techs if _t not in M.tech_annual + for p in M.time_optimize + for _r in regions + if (_r, p, _t) in M.processVintages + 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[p] + for d in M.time_of_day + ) resource_lim = value(M.LimitResource[r, t, op]) - expr = operator_expression(activity_rt, op, resource_lim) + expr = operator_expression(activity, op, resource_lim) return expr -def LimitCapacityGroup_Constraint(M: 'TemoaModel', r, p, g, op): - r""" - Similar to the :code:`LimitCapacity` constraint, but works on a group of technologies. - """ - regions = gather_group_regions(M, r) +# devnote: deprecated when generalising tech/group columns in Limit tables +# def LimitCapacityGroup_Constraint(M: 'TemoaModel', r, p, g, op): +# r""" +# Similar to the :code:`LimitCapacity` constraint, but works on a group of technologies. +# """ +# regions = gather_group_regions(M, r) - cap_lim = value(M.LimitCapacityGroup[r, p, g, op]) +# cap_lim = value(M.LimitCapacityGroup[r, p, g, op]) - cap = sum( - M.V_CapacityAvailableByPeriodAndTech[_r, p, t] - for t in M.tech_group_members[g] - for _r in regions - if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech - ) +# cap = sum( +# M.V_CapacityAvailableByPeriodAndTech[_r, p, t] +# for t in M.tech_group_members[g] +# for _r in regions +# if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech +# ) - expr = operator_expression(cap, op, cap_lim) - # in the case that there is nothing to sum, skip - if isinstance(expr, bool): # an empty list was generated - logger.error( - 'No elements available to support LimitCapacityGroup: %s.' - ' Check data/log for available/suppressed techs. Constraint ignored.', - (r, p, g) - ) - return Constraint.Skip - return expr +# expr = operator_expression(cap, op, cap_lim) +# # in the case that there is nothing to sum, skip +# if isinstance(expr, bool): # an empty list was generated +# logger.error( +# 'No elements available to support LimitCapacityGroup: %s.' +# ' Check data/log for available/suppressed techs. Constraint ignored.', +# (r, p, g) +# ) +# return Constraint.Skip +# return expr -def LimitNewCapacityGroup_Constraint(M: 'TemoaModel', r, p, g, op): - r""" - Similar to the :code:`LimitNewCapacity` constraint, but works on a group of technologies.""" +# devnote: deprecated when generalising tech/group columns in Limit tables +# def LimitNewCapacityGroup_Constraint(M: 'TemoaModel', r, p, g, op): +# r""" +# Similar to the :code:`LimitNewCapacity` constraint, but works on a group of technologies.""" - regions = gather_group_regions(M, r) +# regions = gather_group_regions(M, r) - new_cap_lim = value(M.LimitNewCapacityGroup[r, p, g, op]) - agg_new_cap = sum( - M.V_NewCapacity[_r, t, p] - for t in M.tech_group_members[g] - for _r in regions - if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech - ) - expr = operator_expression(agg_new_cap, op, new_cap_lim) - if isinstance(expr, bool): - logger.error( - 'No elements available to support LimitNewCapacityGroup: (%s, %d, %s).' - ' Check data/log for available/suppressed techs. Requirement IGNORED.', - r, - p, - g, - ) - return Constraint.Skip - return expr +# new_cap_lim = value(M.LimitNewCapacityGroup[r, p, g, op]) +# agg_new_cap = sum( +# M.V_NewCapacity[_r, t, p] +# for t in M.tech_group_members[g] +# for _r in regions +# if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech +# ) +# expr = operator_expression(agg_new_cap, op, new_cap_lim) +# if isinstance(expr, bool): +# logger.error( +# 'No elements available to support LimitNewCapacityGroup: (%s, %d, %s).' +# ' Check data/log for available/suppressed techs. Requirement IGNORED.', +# r, +# p, +# g, +# ) +# return Constraint.Skip +# return expr -def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, t, g, op): +def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): r""" The LimitActivityShare constraint limits the activity share for a given technology within a technology groups to which it belongs. For instance, you might define a tech_group of light-duty vehicles, whose members are different types for LDVs. This constraint could be used to enforce - that no more than 10% of LDVs must be of a certain type.""" + that no more than 10% of LDVs must be of a certain type. + """ regions = gather_group_regions(M, r) - if t not in M.tech_annual: - activity_tech = sum( - M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] - for _r in regions - for S_v in M.processVintages.get((_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[p] - for d in M.time_of_day - if (_r, p, s, d, S_i, t, S_v, S_o) in M.V_FlowOut - ) - else: - activity_tech = sum( - M.V_FlowOutAnnual[_r, p, S_i, t, S_v, S_o] - for _r in regions - for S_v in M.processVintages.get((_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] - if (_r, p, S_i, t, S_v, S_o) in M.V_FlowOutAnnual - ) + sub_group = gather_group_techs(M, g1) + sub_activity = sum( + M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] + for S_t in sub_group if S_t not in M.tech_annual + for _r in regions + for S_v in M.processVintages.get((_r, p, S_t), []) + for S_i in M.processInputs[_r, p, S_t, S_v] + for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] + for s in M.time_season[p] + for d in M.time_of_day + if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut + ) + sub_activity += sum( + M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] + for S_t in sub_group if S_t in M.tech_annual + for _r in regions + for S_v in M.processVintages.get((_r, p, S_t), []) + for S_i in M.processInputs[_r, p, S_t, S_v] + for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] + if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual + ) - activity_group = sum( + super_group = gather_group_techs(M, g2) + super_activity = sum( M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] - for S_t in M.tech_group_members[g] + for S_t in super_group if S_t not in M.tech_annual for _r in regions - if (_r, p, S_t) in M.processVintages and S_t not in M.tech_annual - for S_v in M.processVintages[_r, p, S_t] + for S_v in M.processVintages.get((_r, p, S_t), []) for S_i in M.processInputs[_r, p, S_t, S_v] for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] for s in M.time_season[p] for d in M.time_of_day if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut ) - activity_group_annual = sum( + super_activity += sum( M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] - for S_t in M.tech_group_members[g] + for S_t in super_group if S_t not in M.tech_annual for _r in regions - if (_r, p, S_t) in M.processVintages and S_t in M.tech_annual - for S_v in M.processVintages[_r, p, S_t] + for S_v in M.processVintages.get((_r, p, S_t), []) for S_i in M.processInputs[_r, p, S_t, S_v] for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual ) - activity_group = activity_group + activity_group_annual - share_lim = value(M.LimitActivityShare[r, p, t, g, op]) - expr = operator_expression(activity_tech, op, share_lim * activity_group) + share_lim = value(M.LimitActivityShare[r, p, g1, g2, op]) + expr = operator_expression(sub_activity, op, share_lim * super_activity) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated return Constraint.Skip logger.debug( 'created limit activity share constraint for (%s, %d, %s, %s) of %0.2f', - r, p, t, g, share_lim, + r, p, g1, g2, share_lim, ) return expr -def LimitCapacityShare_Constraint(M: 'TemoaModel', r, p, t, g, op): +def LimitCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): r""" The LimitCapacityShare constraint limits the share for a given technology within a technology groups to which it belongs. @@ -2601,25 +2614,30 @@ def LimitCapacityShare_Constraint(M: 'TemoaModel', r, p, t, g, op): regions = gather_group_regions(M, r) - capacity_t = sum( - M.V_CapacityAvailableByPeriodAndTech[_r, p, t] + sub_group = gather_group_techs(M, g1) + sub_capacity = sum( + M.V_CapacityAvailableByPeriodAndTech[_r, p, _t] + for _t in sub_group for _r in regions + if (_r, p, _t) in M.processVintages ) - capacity_group = sum( - M.V_CapacityAvailableByPeriodAndTech[_r, p, S_t] - for S_t in M.tech_group_members[g] + + super_group = gather_group_techs(M, g2) + super_capacity = sum( + M.V_CapacityAvailableByPeriodAndTech[_r, p, _t] + for _t in super_group for _r in regions - if (_r, p, S_t) in M.processVintages + if (_r, p, _t) in M.processVintages ) - share_lim = value(M.LimitCapacityShare[r, p, t, g, op]) + share_lim = value(M.LimitCapacityShare[r, p, g1, g2, op]) - expr = operator_expression(capacity_t, op, share_lim * capacity_group) + expr = operator_expression(sub_capacity, op, share_lim * super_capacity) if isinstance(expr, bool): return Constraint.Skip return expr -def LimitNewCapacityShare_Constraint(M: 'TemoaModel', r, p, t, g, op): +def LimitNewCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): r""" The LimitCapacityShare constraint limits the share for a given technology within a technology groups to which it belongs. @@ -2629,56 +2647,62 @@ def LimitNewCapacityShare_Constraint(M: 'TemoaModel', r, p, t, g, op): regions = gather_group_regions(M, r) - new_cap_t = sum( - M.V_NewCapacity[_r, t, p] + sub_group = gather_group_techs(M, g1) + sub_new_cap = sum( + M.V_NewCapacity[_r, _t, p] + for _t in sub_group for _r in regions + if (_r, _t, p) in M.processPeriods ) - new_cap_group = sum( - M.V_NewCapacity[_r, S_t, p] - for S_t in M.tech_group_members[g] + + super_group = gather_group_techs(M, g2) + super_new_cap = sum( + M.V_NewCapacity[_r, _t, p] + for _t in super_group for _r in regions - if (_r, S_t, p) in M.V_NewCapacity + if (_r, _t, p) in M.processPeriods ) - share_lim = value(M.LimitNewCapacityShare[r, p, t, g, op]) - expr = operator_expression(new_cap_t, op, share_lim * new_cap_group) + share_lim = value(M.LimitNewCapacityShare[r, p, g1, g2, op]) + expr = operator_expression(sub_new_cap, op, share_lim * super_new_cap) if isinstance(expr, bool): return Constraint.Skip return expr -def LimitNewCapacityGroupShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): - r""" - Limits the aggregate capacity of one group of technologies as a share of - another group of technologies. - """ - - regions = gather_group_regions(M, r) +# devnote: deprecated when generalising tech/group columns in Limit tables +# def LimitNewCapacityGroupShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): +# r""" +# Limits the aggregate capacity of one group of technologies as a share of +# another group of technologies. +# """ - share_lim = value(M.LimitNewCapacityGroupShare[r, p, g1, g2, op]) - agg_new_cap_g1 = sum( - M.V_NewCapacity[_r, t, p] - for t in M.tech_group_members[g1] - for _r in regions - if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech - ) - agg_new_cap_g2 = sum( - M.V_NewCapacity[_r, t, p] - for t in M.tech_group_members[g2] - for _r in regions - if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech - ) - expr = operator_expression(agg_new_cap_g1, op, agg_new_cap_g2 * share_lim) +# regions = gather_group_regions(M, r) - if isinstance(expr, bool): # one side of expression was empty - logger.error( - 'Missing group techs to support LimitNewCapacityGroupShare constraint: %s.' - ' Check data/log for available/suppressed techs. Constraint ignored.', - (r, p, g1, g2) - ) - return Constraint.Skip +# share_lim = value(M.LimitNewCapacityGroupShare[r, p, g1, g2, op]) +# agg_new_cap_g1 = sum( +# M.V_NewCapacity[_r, t, p] +# for t in M.tech_group_members[g1] +# for _r in regions +# if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech +# ) +# agg_new_cap_g2 = sum( +# M.V_NewCapacity[_r, t, p] +# for t in M.tech_group_members[g2] +# for _r in regions +# if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech +# ) +# expr = operator_expression(agg_new_cap_g1, op, agg_new_cap_g2 * share_lim) + +# if isinstance(expr, bool): # one side of expression was empty +# logger.error( +# 'Missing group techs to support LimitNewCapacityGroupShare constraint: %s.' +# ' Check data/log for available/suppressed techs. Constraint ignored.', +# (r, p, g1, g2) +# ) +# return Constraint.Skip - return expr +# return expr def LimitAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o, op): From ea93b10aa8a36a37b95f8e8a5125b4b948734249 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 10 Jun 2025 16:31:16 -0400 Subject: [PATCH 099/587] Update tests and databases for tech group generalisation --- data_files/example_dbs/materials.sql | 135 +-- data_files/example_dbs/morris_utopia.sql | 133 +-- data_files/example_dbs/stepped_demand.sql | 134 +-- data_files/example_dbs/test_system.sql | 135 +-- data_files/example_dbs/utopia.sql | 63 +- data_files/temoa_schema_v3_3.sql | 1013 +++++++++++++++++++++ temoa/utilities/db_migration_tg.py | 127 +++ tests/testing_data/emissions.sql | 153 +--- tests/testing_data/materials.sql | 135 +-- tests/testing_data/mediumville.sql | 147 +-- tests/testing_data/mediumville_sets.json | 606 +----------- tests/testing_data/simple_linked_tech.sql | 135 +-- tests/testing_data/storageville.sql | 135 +-- tests/testing_data/test_system.sql | 135 +-- tests/testing_data/test_system_sets.json | 31 +- tests/testing_data/utopia.sql | 135 +-- tests/testing_data/utopia_sets.json | 34 +- 17 files changed, 1563 insertions(+), 1823 deletions(-) create mode 100644 data_files/temoa_schema_v3_3.sql create mode 100644 temoa/utilities/db_migration_tg.py diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index b967a956a..8dafbf3c6 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -20,8 +20,8 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,'Discount Rate for future costs'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -805,80 +805,74 @@ INSERT INTO Operator VALUES('ge','greater than or equal to'); CREATE TABLE LimitGrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitStorageLevelFraction ( @@ -904,43 +898,26 @@ CREATE TABLE LimitActivity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); CREATE TABLE LimitActivityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitAnnualCapacityFactor ( @@ -963,113 +940,63 @@ CREATE TABLE LimitCapacity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); CREATE TABLE LimitCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitNewCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), new_cap REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); -CREATE TABLE LimitNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); CREATE TABLE LimitNewCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitResource ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), cum_act REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitSeasonalCapacityFactor ( diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index 20cee7086..1e3d5cb51 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -854,80 +854,74 @@ INSERT INTO Operator VALUES('ge','greater than or equal to'); CREATE TABLE LimitGrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitStorageLevelFraction ( @@ -953,43 +947,26 @@ CREATE TABLE LimitActivity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); CREATE TABLE LimitActivityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitAnnualCapacityFactor ( @@ -1012,14 +989,13 @@ CREATE TABLE LimitCapacity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); INSERT INTO LimitCapacity VALUES('utopia',1990,'E31','ge',0.1300000000000000044,'',''); INSERT INTO LimitCapacity VALUES('utopia',2000,'E31','ge',0.1300000000000000044,'',''); @@ -1032,104 +1008,55 @@ INSERT INTO LimitCapacity VALUES('utopia',1990,'RHE','le',0.0,'',''); INSERT INTO LimitCapacity VALUES('utopia',1990,'TXD','le',0.5999999999999999778,'',''); INSERT INTO LimitCapacity VALUES('utopia',2000,'TXD','le',1.760000000000000008,'',''); INSERT INTO LimitCapacity VALUES('utopia',2010,'TXD','le',4.759999999999999787,'',''); -CREATE TABLE LimitCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); CREATE TABLE LimitCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitNewCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), new_cap REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); -CREATE TABLE LimitNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); CREATE TABLE LimitNewCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitResource ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), cum_act REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitSeasonalCapacityFactor ( @@ -1145,7 +1072,7 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Operator (operator), factor REAL, notes TEXT, - PRIMARY KEY(region,period,season,tech, operator) + PRIMARY KEY(region, period, season, tech, operator) ); CREATE TABLE LimitTechInputSplit ( diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index 1b404bd62..27e3dab7a 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -580,80 +580,74 @@ INSERT INTO Operator VALUES('ge','greater than or equal to'); CREATE TABLE LimitGrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitStorageLevelFraction ( @@ -679,43 +673,26 @@ CREATE TABLE LimitActivity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); CREATE TABLE LimitActivityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitAnnualCapacityFactor ( @@ -729,7 +706,6 @@ CREATE TABLE LimitAnnualCapacityFactor operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, - source TEXT, notes TEXT, PRIMARY KEY (region, period, tech, operator), CHECK (factor >= 0 AND factor <= 1) @@ -739,14 +715,13 @@ CREATE TABLE LimitCapacity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); INSERT INTO LimitCapacity VALUES('electricville',2000,'EH','ge',0.2000000000000000111,'',''); INSERT INTO LimitCapacity VALUES('electricville',2005,'EH','ge',0.2000000000000000111,'',''); @@ -759,104 +734,55 @@ INSERT INTO LimitCapacity VALUES('electricville',2015,'EH','le',5.0,'',''); INSERT INTO LimitCapacity VALUES('electricville',2020,'EH','le',5.0,'',''); INSERT INTO LimitCapacity VALUES('electricville',2025,'EH','le',5.0,'',''); INSERT INTO LimitCapacity VALUES('electricville',2030,'EH','le',5.0,'',''); -CREATE TABLE LimitCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); CREATE TABLE LimitCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitNewCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), new_cap REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); -CREATE TABLE LimitNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); CREATE TABLE LimitNewCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitResource ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), cum_act REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitSeasonalCapacityFactor ( @@ -872,7 +798,7 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Operator (operator), factor REAL, notes TEXT, - PRIMARY KEY(region,period,season,tech, operator) + PRIMARY KEY(region, period, season, tech, operator) ); CREATE TABLE LimitTechInputSplit ( diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index a666111eb..122cfac17 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -20,8 +20,8 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,''); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -837,80 +837,74 @@ INSERT INTO Operator VALUES('ge','greater than or equal to'); CREATE TABLE LimitGrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitStorageLevelFraction ( @@ -938,14 +932,13 @@ CREATE TABLE LimitActivity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); INSERT INTO LimitActivity VALUES('R1',2020,'T_GSL','ge',35.0,'',''); INSERT INTO LimitActivity VALUES('R1',2025,'T_GSL','ge',35.0,'',''); @@ -953,34 +946,18 @@ INSERT INTO LimitActivity VALUES('R1',2030,'T_GSL','ge',35.0,'',''); INSERT INTO LimitActivity VALUES('R2',2020,'T_GSL','ge',15.0,'',''); INSERT INTO LimitActivity VALUES('R2',2025,'T_GSL','ge',15.0,'',''); INSERT INTO LimitActivity VALUES('R2',2030,'T_GSL','ge',15.0,'',''); -CREATE TABLE LimitActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); CREATE TABLE LimitActivityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitAnnualCapacityFactor ( @@ -1003,113 +980,63 @@ CREATE TABLE LimitCapacity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); CREATE TABLE LimitCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitNewCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), new_cap REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); -CREATE TABLE LimitNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); CREATE TABLE LimitNewCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitResource ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), cum_act REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitSeasonalCapacityFactor ( diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 9b22db885..7cacd5e6a 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -19,8 +19,8 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,''); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -950,20 +950,6 @@ CREATE TABLE LimitActivity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); --- CREATE TABLE LimitActivityGroup --- ( --- region TEXT, --- period INTEGER --- REFERENCES TimePeriod (period), --- group_name TEXT --- REFERENCES TechGroup (group_name), --- operator TEXT NOT NULL DEFAULT "le" --- REFERENCES Operator (operator), --- activity REAL, --- units TEXT, --- notes TEXT, --- PRIMARY KEY (region, period, group_name, operator) --- ); CREATE TABLE LimitActivityShare ( region TEXT, @@ -971,7 +957,7 @@ CREATE TABLE LimitActivityShare REFERENCES TimePeriod (period), sub_group TEXT, super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" + operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, @@ -1017,20 +1003,6 @@ INSERT INTO LimitCapacity VALUES('utopia',1990,'RHE','le',0.0,'',''); INSERT INTO LimitCapacity VALUES('utopia',1990,'TXD','le',0.5999999999999999778,'',''); INSERT INTO LimitCapacity VALUES('utopia',2000,'TXD','le',1.760000000000000008,'',''); INSERT INTO LimitCapacity VALUES('utopia',2010,'TXD','le',4.759999999999999787,'',''); --- CREATE TABLE LimitCapacityGroup --- ( --- region TEXT, --- period INTEGER --- REFERENCES TimePeriod (period), --- group_name TEXT --- REFERENCES TechGroup (group_name), --- operator TEXT NOT NULL DEFAULT "le" --- REFERENCES Operator (operator), --- capacity REAL, --- units TEXT, --- notes TEXT, --- PRIMARY KEY (region, period, group_name, operator) --- ); CREATE TABLE LimitCapacityShare ( region TEXT, @@ -1057,35 +1029,6 @@ CREATE TABLE LimitNewCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); --- CREATE TABLE LimitNewCapacityGroup --- ( --- region TEXT, --- period INTEGER --- REFERENCES TimePeriod (period), --- group_name TEXT --- REFERENCES TechGroup (group_name), --- operator TEXT NOT NULL DEFAULT "le" --- REFERENCES Operator (operator), --- new_cap REAL, --- units TEXT, --- notes TEXT, --- PRIMARY KEY (region, period, group_name, operator) --- ); --- CREATE TABLE LimitNewCapacityGroupShare --- ( --- region TEXT, --- period INTEGER --- REFERENCES TimePeriod (period), --- sub_group TEXT --- REFERENCES TechGroup (group_name), --- super_group TEXT --- REFERENCES TechGroup (group_name), --- operator TEXT NOT NULL DEFAULT "le" --- REFERENCES Operator (operator), --- share REAL, --- notes TEXT, --- PRIMARY KEY (region, period, sub_group, super_group, operator) --- ); CREATE TABLE LimitNewCapacityShare ( region TEXT, diff --git a/data_files/temoa_schema_v3_3.sql b/data_files/temoa_schema_v3_3.sql new file mode 100644 index 000000000..caecad42d --- /dev/null +++ b/data_files/temoa_schema_v3_3.sql @@ -0,0 +1,1013 @@ +PRAGMA foreign_keys= OFF; +BEGIN TRANSACTION; + +CREATE TABLE IF NOT EXISTS MetaData +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +REPLACE INTO MetaData +VALUES ('myopic_base_year', 2000, 'Base Year for Myopic Analysis'); +REPLACE INTO MetaData +VALUES ('DB_MAJOR', 3, 'DB major version number'); +REPLACE INTO MetaData +VALUES ('DB_MINOR', 0, 'DB minor version number'); +REPLACE INTO MetaData +VALUES ('state_sequencing', 0, '0 = loop periods, 1 = loop seasons'); + +CREATE TABLE IF NOT EXISTS MetaDataReal +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +REPLACE INTO MetaDataReal +VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); +REPLACE INTO MetaDataReal +VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in LoanRate table'); + +CREATE TABLE IF NOT EXISTS OutputDualVariable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE IF NOT EXISTS OutputObjective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE IF NOT EXISTS SectorLabel +( + sector TEXT, + PRIMARY KEY (sector) +); + +CREATE TABLE IF NOT EXISTS CapacityCredit +( + region TEXT, + period INTEGER, + tech TEXT, + vintage INTEGER, + credit REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage), + CHECK (credit >= 0 AND credit <= 1) +); +CREATE TABLE IF NOT EXISTS CapacityFactorProcess +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS CapacityFactorTech +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS CapacityToActivity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + c2a REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS Commodity +( + name TEXT + PRIMARY KEY, + flag TEXT + REFERENCES CommodityType (label), + description TEXT +); +CREATE TABLE IF NOT EXISTS CommodityType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO CommodityType +VALUES ('p', 'physical commodity'); +REPLACE INTO CommodityType +VALUES ('a', 'annual commodity'); +REPLACE INTO CommodityType +VALUES ('e', 'emissions commodity'); +REPLACE INTO CommodityType +VALUES ('d', 'demand commodity'); +REPLACE INTO CommodityType +VALUES ('s', 'source commodity'); +REPLACE INTO CommodityType +VALUES ('w', 'waste commodity'); +REPLACE INTO CommodityType +VALUES ('wa', 'waste annual commodity'); +REPLACE INTO CommodityType +VALUES ('wp', 'waste physical commodity'); +CREATE TABLE IF NOT EXISTS ConstructionInput +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS CostEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT NOT NULL + REFERENCES Commodity (name), + cost REAL NOT NULL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE IF NOT EXISTS CostFixed +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS CostInvest +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS CostVariable +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS Demand +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + commodity TEXT + REFERENCES Commodity (name), + demand REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, commodity) +); +CREATE TABLE IF NOT EXISTS DemandSpecificDistribution +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + demand_name TEXT + REFERENCES Commodity (name), + dsd REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), + CHECK (dsd >= 0 AND dsd <= 1) +); +CREATE TABLE IF NOT EXISTS EndOfLifeOutput +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS Efficiency +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE IF NOT EXISTS EfficiencyVariable +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE IF NOT EXISTS EmissionActivity +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS EmissionEmbodied +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS EmissionEndOfLife +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS ExistingCapacity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS TechGroup +( + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE IF NOT EXISTS LoanLifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS LifetimeProcess +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS LifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS Operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +REPLACE INTO Operator VALUES('e','equal to'); +REPLACE INTO Operator VALUES('le','less than or equal to'); +REPLACE INTO Operator VALUES('ge','greater than or equal to'); +CREATE TABLE IF NOT EXISTS LimitGrowthCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitDegrowthCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitGrowthNewCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitDegrowthNewCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitGrowthNewCapacityDelta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitDegrowthNewCapacityDelta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitStorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) +); +CREATE TABLE IF NOT EXISTS LimitActivity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, operator), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS LimitCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitResource +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitSeasonalCapacityFactor +( + region TEXT + REFERENCES Region (region), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) +); +CREATE TABLE IF NOT EXISTS LimitTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE IF NOT EXISTS LimitTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE IF NOT EXISTS LimitTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE IF NOT EXISTS LimitTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE IF NOT EXISTS LimitEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE IF NOT EXISTS LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE IF NOT EXISTS OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputFlowOut +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); +CREATE TABLE IF NOT EXISTS PlanningReserveMargin +( + region TEXT + PRIMARY KEY + REFERENCES Region (region), + margin REAL +); +CREATE TABLE IF NOT EXISTS RampDown +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS RampUp +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS Region +( + region TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE IF NOT EXISTS TimeSegmentFraction +( + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + segfrac REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segfrac >= 0 AND segfrac <= 1) +); +CREATE TABLE IF NOT EXISTS StorageDuration +( + region TEXT, + tech TEXT, + duration REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS TechnologyType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO TechnologyType +VALUES ('r', 'resource technology'); +REPLACE INTO TechnologyType +VALUES ('p', 'production technology'); +REPLACE INTO TechnologyType +VALUES ('pb', 'baseload production technology'); +REPLACE INTO TechnologyType +VALUES ('ps', 'storage production technology'); +-- CREATE TABLE IF NOT EXISTS TimeNext +-- ( +-- period INTEGER +-- REFERENCES TimePeriod (period), +-- season TEXT +-- REFERENCES TimeSeason (season), +-- tod TEXT +-- REFERENCES TimeOfDay (tod), +-- season_next TEXT +-- REFERENCES TimeSeason (season), +-- tod_next TEXT +-- REFERENCES TimeOfDay (tod), +-- notes TEXT, +-- PRIMARY KEY (period, season, tod) +-- ); +CREATE TABLE IF NOT EXISTS TimeOfDay +( + sequence INTEGER UNIQUE, + tod TEXT + PRIMARY KEY +); +CREATE TABLE IF NOT EXISTS TimePeriod +( + sequence INTEGER UNIQUE, + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES TimePeriodType (label) +); +CREATE TABLE IF NOT EXISTS TimeSeason +( + season TEXT + PRIMARY KEY +); +CREATE TABLE IF NOT EXISTS PeriodSeasons +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT + REFERENCES TimeSeason (season), + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +CREATE TABLE IF NOT EXISTS TimePeriodType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO TimePeriodType +VALUES('e', 'existing vintages'); +REPLACE INTO TimePeriodType +VALUES('f', 'future'); +CREATE TABLE IF NOT EXISTS OutputEmission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS RPSRequirement +( + region TEXT NOT NULL + REFERENCES Region (region), + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech_group TEXT NOT NULL + REFERENCES TechGroup (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE IF NOT EXISTS TechGroupMember +( + group_name TEXT + REFERENCES TechGroup (group_name), + tech TEXT + REFERENCES Technology (tech), + PRIMARY KEY (group_name, tech) +); +CREATE TABLE IF NOT EXISTS Technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES TechnologyType (label) +); +CREATE TABLE OutputCost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES TimePeriod (period), + FOREIGN KEY (tech) REFERENCES Technology (tech) +); +COMMIT; +PRAGMA FOREIGN_KEYS = 1; \ No newline at end of file diff --git a/temoa/utilities/db_migration_tg.py b/temoa/utilities/db_migration_tg.py new file mode 100644 index 000000000..2d8bf1412 --- /dev/null +++ b/temoa/utilities/db_migration_tg.py @@ -0,0 +1,127 @@ +""" +Tools for Energy Model Optimization and Analysis (Temoa): +An open source framework for energy systems optimization modeling + +Copyright (C) 2015, NC State University + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +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 +received this license file. If not, see . + +Written by: I. D. Elder +iandavidelder@gmail.com +Created on: 2025/06/10 + +Collapses group/non-group Limit tables +""" + +import argparse +import sqlite3 +import sys +from pathlib import Path + +parser = argparse.ArgumentParser() +parser.add_argument( + '--source', + help='Path to original database', + required=True, + action='store', + dest='source_db', +) +parser.add_argument( + '--schema', + help='Path to schema file (default=data_files/temoa_schema_v3_3)', + required=False, + dest='schema', + default='data_files/temoa_schema_v3_3.sql', +) +options = parser.parse_args() +legacy_db: Path = Path(options.source_db) +schema_file = Path(options.schema) + +new_db_name = legacy_db.stem + '_v3_3.sqlite' +new_db_path = Path(legacy_db.parent, new_db_name) + +con_old = sqlite3.connect(legacy_db) +con_new = sqlite3.connect(new_db_path) +cur = con_new.cursor() + +# bring in the new schema and execute +with open(schema_file, 'r') as src: + sql_script = src.read() +con_new.executescript(sql_script) + +# turn off FK verification while process executes +con_new.execute('PRAGMA foreign_keys = 0;') + +tables_to_collapse = { + 'LimitActivityGroup': 'LimitActivity', + 'LimitCapacityGroup': 'LimitCapacity', + 'LimitNewCapacityGroup': 'LimitNewCapacity', + 'LimitNewCapacityGroupShare': 'LimitNewCapacityShare', +} + +old_tables = set([t[1] for t in con_old.execute('SELECT * FROM sqlite_master WHERE type="table";')]) +new_tables = set([t[1] for t in con_new.execute('SELECT * FROM sqlite_master WHERE type="table";')]) +collapsed_tables = set(tables_to_collapse.keys()) + +direct_transfer_tables = (new_tables & old_tables) - collapsed_tables + +transfers: dict = {t: t for t in direct_transfer_tables} +transfers.update(tables_to_collapse) + +print('\n --- Executing direct transfers ---') +for old_table, new_table in transfers.items(): + + try: + con_old.execute(f'SELECT * FROM {old_table}').fetchone() + except sqlite3.OperationalError: + print('TABLE NOT FOUND: ' + old_table) + continue + + data = con_old.execute(f'SELECT * FROM {old_table}').fetchall() + + if not data: + print('No data for: ' + old_table) + continue + + # construct the query with correct number of placeholders + num_placeholders = len(data[0]) + placeholders = ','.join(['?' for _ in range(num_placeholders)]) + query = f'INSERT OR REPLACE INTO {new_table} VALUES ({placeholders})' + con_new.executemany(query, data) + print(f'Transferred {len(data)} rows from {old_table} to {new_table}') + + +print('\n --- Validating foreign keys ---') +con_new.commit() +con_new.execute('VACUUM;') +con_new.execute('PRAGMA FOREIGN_KEYS=1;') +try: + data = con_new.execute('PRAGMA FOREIGN_KEY_CHECK;').fetchall() + if not data: + print('No Foreign Key Failures. (Good news!)') + else: + print('\nFK check fails (MUST BE FIXED):') + print('(Table, Row ID, Reference Table, (fkid) )') + for row in data: + print(row) +except sqlite3.OperationalError as e: + print('Foreign Key Check FAILED on new DB. Something may be wrong with schema.') + print(e) + +print('\nFinished! Check your database for any missing data.' + ' If there was a mismatch of table names, something may have been lost.') + +con_new.close() +con_old.close() \ No newline at end of file diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 1768f89b3..414aa5807 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -20,8 +20,8 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,'Discount Rate for future costs'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -162,8 +162,8 @@ CREATE TABLE CostEmission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -INSERT INTO CostEmission VALUES('TestRegion',2000,'emission',0.7,NULL,NULL); -INSERT INTO CostEmission VALUES('TestRegion',2005,'emission',0.7,NULL,NULL); +INSERT INTO CostEmission VALUES('TestRegion',2000,'emission',0.6999999999999999556,NULL,NULL); +INSERT INTO CostEmission VALUES('TestRegion',2005,'emission',0.6999999999999999556,NULL,NULL); CREATE TABLE CostFixed ( region TEXT NOT NULL, @@ -217,13 +217,13 @@ CREATE TABLE Demand PRIMARY KEY (region, period, commodity) ); INSERT INTO Demand VALUES('TestRegion',2000,'annual_out',1.0,NULL,NULL); -INSERT INTO Demand VALUES('TestRegion',2000,'ordinary_out',0.3,NULL,NULL); -INSERT INTO Demand VALUES('TestRegion',2000,'curtailment_out',0.3,NULL,NULL); -INSERT INTO Demand VALUES('TestRegion',2000,'flex_null',0.3,NULL,NULL); -INSERT INTO Demand VALUES('TestRegion',2000,'annual_flex_null',0.3,NULL,NULL); -INSERT INTO Demand VALUES('TestRegion',2000,'embodied_out',0.6,NULL,NULL); -INSERT INTO Demand VALUES('TestRegion',2000,'eol_out',0.6,NULL,NULL); -INSERT INTO Demand VALUES('TestRegion',2005,'ordinary_out',0.3,NULL,NULL); +INSERT INTO Demand VALUES('TestRegion',2000,'ordinary_out',0.2999999999999999889,NULL,NULL); +INSERT INTO Demand VALUES('TestRegion',2000,'curtailment_out',0.2999999999999999889,NULL,NULL); +INSERT INTO Demand VALUES('TestRegion',2000,'flex_null',0.2999999999999999889,NULL,NULL); +INSERT INTO Demand VALUES('TestRegion',2000,'annual_flex_null',0.2999999999999999889,NULL,NULL); +INSERT INTO Demand VALUES('TestRegion',2000,'embodied_out',0.5999999999999999778,NULL,NULL); +INSERT INTO Demand VALUES('TestRegion',2000,'eol_out',0.5999999999999999778,NULL,NULL); +INSERT INTO Demand VALUES('TestRegion',2005,'ordinary_out',0.2999999999999999889,NULL,NULL); CREATE TABLE DemandSpecificDistribution ( region TEXT, @@ -424,80 +424,74 @@ INSERT INTO Operator VALUES('ge','greater than or equal to'); CREATE TABLE LimitGrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitStorageLevelFraction ( @@ -523,47 +517,30 @@ CREATE TABLE LimitActivity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); INSERT INTO LimitActivity VALUES('TestRegion',2000,'TechFlex','ge',1.0,NULL,NULL); INSERT INTO LimitActivity VALUES('TestRegion',2000,'TechAnnualFlex','ge',1.0,NULL,NULL); INSERT INTO LimitActivity VALUES('TestRegion',2000,'TechFlex','le',1.0,NULL,NULL); INSERT INTO LimitActivity VALUES('TestRegion',2000,'TechAnnualFlex','le',1.0,NULL,NULL); -CREATE TABLE LimitActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); CREATE TABLE LimitActivityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitAnnualCapacityFactor ( @@ -586,117 +563,67 @@ CREATE TABLE LimitCapacity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); INSERT INTO LimitCapacity VALUES('TestRegion',2000,'TechOrdinary','ge',1.0,NULL,NULL); INSERT INTO LimitCapacity VALUES('TestRegion',2000,'TechCurtailment','ge',1.0,NULL,NULL); INSERT INTO LimitCapacity VALUES('TestRegion',2000,'TechOrdinary','le',1.0,NULL,NULL); INSERT INTO LimitCapacity VALUES('TestRegion',2000,'TechCurtailment','le',1.0,NULL,NULL); -CREATE TABLE LimitCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); CREATE TABLE LimitCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitNewCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), new_cap REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); -CREATE TABLE LimitNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); CREATE TABLE LimitNewCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitResource ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), cum_act REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitSeasonalCapacityFactor ( diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index b967a956a..8dafbf3c6 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -20,8 +20,8 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,'Discount Rate for future costs'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -805,80 +805,74 @@ INSERT INTO Operator VALUES('ge','greater than or equal to'); CREATE TABLE LimitGrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitStorageLevelFraction ( @@ -904,43 +898,26 @@ CREATE TABLE LimitActivity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); CREATE TABLE LimitActivityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitAnnualCapacityFactor ( @@ -963,113 +940,63 @@ CREATE TABLE LimitCapacity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); CREATE TABLE LimitCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitNewCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), new_cap REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); -CREATE TABLE LimitNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); CREATE TABLE LimitNewCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitResource ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), cum_act REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitSeasonalCapacityFactor ( diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 61425e1c5..874941a19 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -20,8 +20,8 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.42000000000000001776,''); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.42000000000000004,''); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -485,80 +485,74 @@ INSERT INTO Operator VALUES('ge','greater than or equal to'); CREATE TABLE LimitGrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitStorageLevelFraction ( @@ -584,48 +578,31 @@ CREATE TABLE LimitActivity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); INSERT INTO LimitActivity VALUES('A',2025,'EF','ge',0.00100000000000000002,'PJ/CY','goofy units'); INSERT INTO LimitActivity VALUES('B',2025,'EH','le',10000.0,'stuff',NULL); INSERT INTO LimitActivity VALUES('A',2025,'EF','le',10000.0,'stuff',NULL); -CREATE TABLE LimitActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); -INSERT INTO LimitActivityGroup VALUES('A',2025,'A_tech_grp_1','ge',0.05000000000000000277,'',NULL); -INSERT INTO LimitActivityGroup VALUES('A',2025,'A_tech_grp_1','le',10000.0,'',NULL); +INSERT INTO LimitActivity VALUES('A',2025,'A_tech_grp_1','ge',0.05000000000000000277,'',NULL); +INSERT INTO LimitActivity VALUES('A',2025,'A_tech_grp_1','le',10000.0,'',NULL); CREATE TABLE LimitActivityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitAnnualCapacityFactor ( @@ -648,121 +625,71 @@ CREATE TABLE LimitCapacity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); INSERT INTO LimitCapacity VALUES('A',2025,'EH','ge',0.1000000000000000055,'',''); INSERT INTO LimitCapacity VALUES('B',2025,'batt','ge',0.1000000000000000055,'',''); INSERT INTO LimitCapacity VALUES('A',2025,'EH','le',20000.0,'',''); INSERT INTO LimitCapacity VALUES('B',2025,'EH','le',20000.0,'',''); -CREATE TABLE LimitCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); -INSERT INTO LimitCapacityGroup VALUES('A',2025,'A_tech_grp_1','ge',0.2000000000000000111,'',NULL); -INSERT INTO LimitCapacityGroup VALUES('A',2025,'A_tech_grp_1','le',6000.0,'',NULL); +INSERT INTO LimitCapacity VALUES('A',2025,'A_tech_grp_1','ge',0.2000000000000000111,'',NULL); +INSERT INTO LimitCapacity VALUES('A',2025,'A_tech_grp_1','le',6000.0,'',NULL); CREATE TABLE LimitCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitNewCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), new_cap REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -INSERT INTO LimitNewCapacityGroupShare VALUES('A',2025,'RPS_common','A_tech_grp_1','ge',0.0,''); -INSERT INTO LimitNewCapacityGroupShare VALUES('global',2025,'RPS_common','A_tech_grp_1','le',1.0,''); CREATE TABLE LimitNewCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); +INSERT INTO LimitNewCapacityShare VALUES('A',2025,'RPS_common','A_tech_grp_1','ge',0.0,''); +INSERT INTO LimitNewCapacityShare VALUES('global',2025,'RPS_common','A_tech_grp_1','le',1.0,''); CREATE TABLE LimitResource ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), cum_act REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); INSERT INTO LimitResource VALUES('B','EF','le',9000.0,'clumps',NULL); CREATE TABLE LimitSeasonalCapacityFactor diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 4819ad732..3a018febd 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -3129,197 +3129,6 @@ "ELC" ] ], - "GroupShareIndices": [ - [ - "global", - 2025, - "EH", - "A_tech_grp_1", - "le" - ], - [ - "A", - 2025, - "EH", - "A_tech_grp_1", - "e" - ], - [ - "B", - 2025, - "EF", - "A_tech_grp_1", - "le" - ], - [ - "global", - 2025, - "EF", - "RPS_common", - "e" - ], - [ - "A", - 2025, - "EH", - "A_tech_grp_1", - "ge" - ], - [ - "B", - 2025, - "EF", - "RPS_common", - "e" - ], - [ - "global", - 2025, - "EF", - "A_tech_grp_1", - "le" - ], - [ - "global", - 2025, - "EF", - "RPS_common", - "ge" - ], - [ - "B", - 2025, - "EF", - "RPS_common", - "ge" - ], - [ - "A", - 2025, - "EF", - "RPS_common", - "le" - ], - [ - "B", - 2025, - "EH", - "A_tech_grp_1", - "le" - ], - [ - "global", - 2025, - "EH", - "A_tech_grp_1", - "e" - ], - [ - "global", - 2025, - "EH", - "A_tech_grp_1", - "ge" - ], - [ - "A", - 2025, - "EF", - "A_tech_grp_1", - "le" - ], - [ - "B", - 2025, - "EF", - "A_tech_grp_1", - "e" - ], - [ - "global", - 2025, - "EF", - "A_tech_grp_1", - "e" - ], - [ - "B", - 2025, - "EF", - "A_tech_grp_1", - "ge" - ], - [ - "global", - 2025, - "EF", - "A_tech_grp_1", - "ge" - ], - [ - "A", - 2025, - "EH", - "A_tech_grp_1", - "le" - ], - [ - "A", - 2025, - "EF", - "RPS_common", - "e" - ], - [ - "global", - 2025, - "EF", - "RPS_common", - "le" - ], - [ - "B", - 2025, - "EH", - "A_tech_grp_1", - "e" - ], - [ - "A", - 2025, - "EF", - "RPS_common", - "ge" - ], - [ - "B", - 2025, - "EF", - "RPS_common", - "le" - ], - [ - "A", - 2025, - "EF", - "A_tech_grp_1", - "e" - ], - [ - "B", - 2025, - "EH", - "A_tech_grp_1", - "ge" - ], - [ - "A", - 2025, - "EF", - "A_tech_grp_1", - "ge" - ] - ], "LifetimeProcess_rtv": [ [ "A", @@ -3430,9 +3239,7 @@ 2025, "EF", "ge" - ] - ], - "LimitActivityGroupConstraint_rpg": [ + ], [ "A", 2025, @@ -3446,8 +3253,7 @@ "ge" ] ], - "LimitActivityGroupShareConstraint_rpgg": [], - "LimitActivityShareConstraint_rptg": [], + "LimitActivityShareConstraint_rpgg": [], "LimitAnnualCapacityFactorConstraint_rpto": [], "LimitCapacityConstraint_rpt": [ [ @@ -3473,9 +3279,7 @@ 2025, "EH", "le" - ] - ], - "LimitCapacityGroupConstraint_rpg": [ + ], [ "A", 2025, @@ -3489,7 +3293,7 @@ "ge" ] ], - "LimitCapacityShareConstraint_rptg": [], + "LimitCapacityShareConstraint_rpgg": [], "LimitDegrowthCapacityConstraint_rpt": [], "LimitDegrowthNewCapacityConstraint_rpt": [], "LimitDegrowthNewCapacityDeltaConstraint_rpt": [], @@ -3505,8 +3309,7 @@ "LimitGrowthNewCapacityConstraint_rpt": [], "LimitGrowthNewCapacityDeltaConstraint_rpt": [], "LimitNewCapacityConstraint_rpt": [], - "LimitNewCapacityGroupConstraint_rpg": [], - "LimitNewCapacityGroupShareConstraint_rpgg": [ + "LimitNewCapacityShareConstraint_rpgg": [ [ "A", 2025, @@ -3522,7 +3325,6 @@ "le" ] ], - "LimitNewCapacityShareConstraint_rptg": [], "LimitResourceConstraint_rt": [ [ "B", @@ -4346,386 +4148,6 @@ ] ], "TimeNext": [], - "TwoGroupShareIndices": [ - [ - "A", - 2025, - "A_tech_grp_1", - "RPS_common", - "ge" - ], - [ - "global", - 2025, - "RPS_global", - "A_tech_grp_1", - "ge" - ], - [ - "A", - 2025, - "RPS_global", - "RPS_common", - "e" - ], - [ - "A", - 2025, - "A_tech_grp_1", - "A_tech_grp_1", - "e" - ], - [ - "global", - 2025, - "A_tech_grp_1", - "RPS_common", - "e" - ], - [ - "B", - 2025, - "RPS_global", - "A_tech_grp_1", - "ge" - ], - [ - "A", - 2025, - "RPS_global", - "RPS_common", - "ge" - ], - [ - "A", - 2025, - "A_tech_grp_1", - "A_tech_grp_1", - "ge" - ], - [ - "global", - 2025, - "RPS_global", - "RPS_common", - "le" - ], - [ - "B", - 2025, - "RPS_global", - "RPS_common", - "le" - ], - [ - "global", - 2025, - "A_tech_grp_1", - "RPS_common", - "ge" - ], - [ - "B", - 2025, - "RPS_common", - "RPS_common", - "le" - ], - [ - "A", - 2025, - "RPS_global", - "A_tech_grp_1", - "e" - ], - [ - "A", - 2025, - "RPS_common", - "A_tech_grp_1", - "e" - ], - [ - "B", - 2025, - "A_tech_grp_1", - "RPS_common", - "le" - ], - [ - "A", - 2025, - "RPS_common", - "A_tech_grp_1", - "ge" - ], - [ - "A", - 2025, - "RPS_global", - "A_tech_grp_1", - "ge" - ], - [ - "global", - 2025, - "RPS_common", - "RPS_common", - "le" - ], - [ - "global", - 2025, - "A_tech_grp_1", - "A_tech_grp_1", - "e" - ], - [ - "A", - 2025, - "RPS_common", - "RPS_common", - "le" - ], - [ - "B", - 2025, - "A_tech_grp_1", - "A_tech_grp_1", - "le" - ], - [ - "global", - 2025, - "A_tech_grp_1", - "A_tech_grp_1", - "ge" - ], - [ - "B", - 2025, - "RPS_common", - "A_tech_grp_1", - "le" - ], - [ - "global", - 2025, - "RPS_common", - "A_tech_grp_1", - "le" - ], - [ - "A", - 2025, - "A_tech_grp_1", - "RPS_common", - "le" - ], - [ - "global", - 2025, - "RPS_global", - "RPS_common", - "e" - ], - [ - "global", - 2025, - "RPS_global", - "A_tech_grp_1", - "le" - ], - [ - "B", - 2025, - "RPS_common", - "RPS_common", - "e" - ], - [ - "B", - 2025, - "A_tech_grp_1", - "RPS_common", - "e" - ], - [ - "B", - 2025, - "RPS_global", - "RPS_common", - "e" - ], - [ - "B", - 2025, - "RPS_global", - "A_tech_grp_1", - "le" - ], - [ - "global", - 2025, - "RPS_global", - "RPS_common", - "ge" - ], - [ - "B", - 2025, - "RPS_common", - "RPS_common", - "ge" - ], - [ - "global", - 2025, - "A_tech_grp_1", - "RPS_common", - "le" - ], - [ - "A", - 2025, - "RPS_global", - "RPS_common", - "le" - ], - [ - "B", - 2025, - "RPS_global", - "RPS_common", - "ge" - ], - [ - "A", - 2025, - "A_tech_grp_1", - "A_tech_grp_1", - "le" - ], - [ - "global", - 2025, - "RPS_common", - "RPS_common", - "e" - ], - [ - "B", - 2025, - "A_tech_grp_1", - "RPS_common", - "ge" - ], - [ - "A", - 2025, - "RPS_common", - "RPS_common", - "e" - ], - [ - "B", - 2025, - "A_tech_grp_1", - "A_tech_grp_1", - "e" - ], - [ - "A", - 2025, - "RPS_common", - "A_tech_grp_1", - "le" - ], - [ - "global", - 2025, - "RPS_common", - "RPS_common", - "ge" - ], - [ - "A", - 2025, - "RPS_global", - "A_tech_grp_1", - "le" - ], - [ - "B", - 2025, - "RPS_common", - "A_tech_grp_1", - "e" - ], - [ - "B", - 2025, - "A_tech_grp_1", - "A_tech_grp_1", - "ge" - ], - [ - "A", - 2025, - "RPS_common", - "RPS_common", - "ge" - ], - [ - "global", - 2025, - "RPS_common", - "A_tech_grp_1", - "e" - ], - [ - "B", - 2025, - "RPS_common", - "A_tech_grp_1", - "ge" - ], - [ - "global", - 2025, - "RPS_common", - "A_tech_grp_1", - "ge" - ], - [ - "A", - 2025, - "A_tech_grp_1", - "RPS_common", - "e" - ], - [ - "global", - 2025, - "A_tech_grp_1", - "A_tech_grp_1", - "le" - ], - [ - "global", - 2025, - "RPS_global", - "A_tech_grp_1", - "e" - ], - [ - "B", - 2025, - "RPS_global", - "A_tech_grp_1", - "e" - ] - ], "commodity_all": [ "FusionGas", "RH", @@ -4822,14 +4244,28 @@ ], "tech_group_members": [ "A_tech_grp_1", - "RPS_common", - "RPS_global" + "RPS_common" ], "tech_group_names": [ "A_tech_grp_1", "RPS_common", "RPS_global" ], + "tech_or_group": [ + "A_tech_grp_1", + "RPS_common", + "EH", + "RPS_global", + "EF", + "GeoThermal", + "well", + "heater", + "EFL", + "GeoHeater", + "bulbs", + "FGF_pipe", + "batt" + ], "tech_production": [ "GeoHeater", "bulbs", diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index 2b529454e..9994d7a3d 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -20,8 +20,8 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,''); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -404,80 +404,74 @@ INSERT INTO Operator VALUES('ge','greater than or equal to'); CREATE TABLE LimitGrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitStorageLevelFraction ( @@ -503,43 +497,26 @@ CREATE TABLE LimitActivity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); CREATE TABLE LimitActivityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitAnnualCapacityFactor ( @@ -562,113 +539,63 @@ CREATE TABLE LimitCapacity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); CREATE TABLE LimitCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitNewCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), new_cap REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); -CREATE TABLE LimitNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); CREATE TABLE LimitNewCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitResource ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), cum_act REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitSeasonalCapacityFactor ( diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index 9aa28b895..3e8b2ab01 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -20,8 +20,8 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,''); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -412,80 +412,74 @@ INSERT INTO Operator VALUES('ge','greater than or equal to'); CREATE TABLE LimitGrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitStorageLevelFraction ( @@ -512,43 +506,26 @@ CREATE TABLE LimitActivity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); CREATE TABLE LimitActivityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitAnnualCapacityFactor ( @@ -571,117 +548,67 @@ CREATE TABLE LimitCapacity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); INSERT INTO LimitCapacity VALUES('electricville',2025,'EH','ge',0.1000000000000000055,'',''); INSERT INTO LimitCapacity VALUES('electricville',2025,'batt','ge',0.1000000000000000055,'',''); INSERT INTO LimitCapacity VALUES('electricville',2025,'EH','le',200.0,'',''); INSERT INTO LimitCapacity VALUES('electricville',2025,'batt','le',100.0,'',''); -CREATE TABLE LimitCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); CREATE TABLE LimitCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitNewCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), new_cap REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); -CREATE TABLE LimitNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); CREATE TABLE LimitNewCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitResource ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), cum_act REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitSeasonalCapacityFactor ( diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index a666111eb..122cfac17 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -20,8 +20,8 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,''); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -837,80 +837,74 @@ INSERT INTO Operator VALUES('ge','greater than or equal to'); CREATE TABLE LimitGrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitStorageLevelFraction ( @@ -938,14 +932,13 @@ CREATE TABLE LimitActivity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); INSERT INTO LimitActivity VALUES('R1',2020,'T_GSL','ge',35.0,'',''); INSERT INTO LimitActivity VALUES('R1',2025,'T_GSL','ge',35.0,'',''); @@ -953,34 +946,18 @@ INSERT INTO LimitActivity VALUES('R1',2030,'T_GSL','ge',35.0,'',''); INSERT INTO LimitActivity VALUES('R2',2020,'T_GSL','ge',15.0,'',''); INSERT INTO LimitActivity VALUES('R2',2025,'T_GSL','ge',15.0,'',''); INSERT INTO LimitActivity VALUES('R2',2030,'T_GSL','ge',15.0,'',''); -CREATE TABLE LimitActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); CREATE TABLE LimitActivityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitAnnualCapacityFactor ( @@ -1003,113 +980,63 @@ CREATE TABLE LimitCapacity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); CREATE TABLE LimitCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitNewCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), new_cap REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); -CREATE TABLE LimitNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); CREATE TABLE LimitNewCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitResource ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), cum_act REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitSeasonalCapacityFactor ( diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index fc86cbcb3..a775e5465 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -40003,7 +40003,6 @@ "ELC" ] ], - "GroupShareIndices": [], "LifetimeProcess_rtv": [ [ "R2", @@ -40394,13 +40393,10 @@ "ge" ] ], - "LimitActivityGroupConstraint_rpg": [], - "LimitActivityGroupShareConstraint_rpgg": [], - "LimitActivityShareConstraint_rptg": [], + "LimitActivityShareConstraint_rpgg": [], "LimitAnnualCapacityFactorConstraint_rpto": [], "LimitCapacityConstraint_rpt": [], - "LimitCapacityGroupConstraint_rpg": [], - "LimitCapacityShareConstraint_rptg": [], + "LimitCapacityShareConstraint_rpgg": [], "LimitDegrowthCapacityConstraint_rpt": [], "LimitDegrowthNewCapacityConstraint_rpt": [], "LimitDegrowthNewCapacityDeltaConstraint_rpt": [], @@ -40446,9 +40442,7 @@ "LimitGrowthNewCapacityConstraint_rpt": [], "LimitGrowthNewCapacityDeltaConstraint_rpt": [], "LimitNewCapacityConstraint_rpt": [], - "LimitNewCapacityGroupConstraint_rpg": [], - "LimitNewCapacityGroupShareConstraint_rpgg": [], - "LimitNewCapacityShareConstraint_rptg": [], + "LimitNewCapacityShareConstraint_rpgg": [], "LimitResourceConstraint_rt": [], "LimitSeasonalCapacityFactorConstraint_rpst": [], "LimitStorageFractionConstraint_rpsdtv": [ @@ -46799,7 +46793,6 @@ ] ], "TimeNext": [], - "TwoGroupShareIndices": [], "commodity_all": [ "ethos", "RH", @@ -46910,6 +46903,24 @@ "tech_flex": [], "tech_group_members": [], "tech_group_names": [], + "tech_or_group": [ + "E_BATT", + "R_EH", + "S_OILREF", + "T_GSL", + "S_IMPURN", + "S_IMPNG", + "T_EV", + "E_SOLPV", + "T_DSL", + "R_NGH", + "E_NGCC", + "S_IMPETH", + "S_IMPOIL", + "T_BLND", + "E_TRANS", + "E_NUCLEAR" + ], "tech_production": [ "T_BLND", "R_NGH", diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 2c96d4867..7cacd5e6a 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -19,8 +19,8 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,''); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -849,80 +849,74 @@ INSERT INTO Operator VALUES('ge','greater than or equal to'); CREATE TABLE LimitGrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitGrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitDegrowthNewCapacityDelta ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitStorageLevelFraction ( @@ -948,43 +942,26 @@ CREATE TABLE LimitActivity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); CREATE TABLE LimitActivityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitAnnualCapacityFactor ( @@ -1007,14 +984,13 @@ CREATE TABLE LimitCapacity region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); INSERT INTO LimitCapacity VALUES('utopia',1990,'E31','ge',0.1300000000000000044,'',''); INSERT INTO LimitCapacity VALUES('utopia',2000,'E31','ge',0.1300000000000000044,'',''); @@ -1027,104 +1003,55 @@ INSERT INTO LimitCapacity VALUES('utopia',1990,'RHE','le',0.0,'',''); INSERT INTO LimitCapacity VALUES('utopia',1990,'TXD','le',0.5999999999999999778,'',''); INSERT INTO LimitCapacity VALUES('utopia',2000,'TXD','le',1.760000000000000008,'',''); INSERT INTO LimitCapacity VALUES('utopia',2010,'TXD','le',4.759999999999999787,'',''); -CREATE TABLE LimitCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); CREATE TABLE LimitCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitNewCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), new_cap REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE LimitNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); -CREATE TABLE LimitNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) + PRIMARY KEY (region, period, tech_or_group, operator) ); CREATE TABLE LimitNewCapacityShare ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), + sub_group TEXT, + super_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) + PRIMARY KEY (region, period, sub_group, super_group, operator) ); CREATE TABLE LimitResource ( region TEXT, - tech TEXT - REFERENCES Technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), cum_act REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, tech, operator) + PRIMARY KEY (region, tech_or_group, operator) ); CREATE TABLE LimitSeasonalCapacityFactor ( diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 398186281..b74d28e57 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -21751,7 +21751,6 @@ "ELC" ] ], - "GroupShareIndices": [], "LifetimeProcess_rtv": [ [ "utopia", @@ -22045,9 +22044,7 @@ ] ], "LimitActivityConstraint_rpt": [], - "LimitActivityGroupConstraint_rpg": [], - "LimitActivityGroupShareConstraint_rpgg": [], - "LimitActivityShareConstraint_rptg": [], + "LimitActivityShareConstraint_rpgg": [], "LimitAnnualCapacityFactorConstraint_rpto": [], "LimitCapacityConstraint_rpt": [ [ @@ -22117,8 +22114,7 @@ "ge" ] ], - "LimitCapacityGroupConstraint_rpg": [], - "LimitCapacityShareConstraint_rptg": [], + "LimitCapacityShareConstraint_rpgg": [], "LimitDegrowthCapacityConstraint_rpt": [], "LimitDegrowthNewCapacityConstraint_rpt": [], "LimitDegrowthNewCapacityDeltaConstraint_rpt": [], @@ -22127,9 +22123,7 @@ "LimitGrowthNewCapacityConstraint_rpt": [], "LimitGrowthNewCapacityDeltaConstraint_rpt": [], "LimitNewCapacityConstraint_rpt": [], - "LimitNewCapacityGroupConstraint_rpg": [], - "LimitNewCapacityGroupShareConstraint_rpgg": [], - "LimitNewCapacityShareConstraint_rptg": [], + "LimitNewCapacityShareConstraint_rpgg": [], "LimitResourceConstraint_rt": [], "LimitSeasonalCapacityFactorConstraint_rpst": [], "LimitStorageFractionConstraint_rpsdtv": [], @@ -25703,7 +25697,6 @@ ] ], "TimeNext": [], - "TwoGroupShareIndices": [], "commodity_all": [ "ethos", "RH", @@ -25817,6 +25810,27 @@ "tech_flex": [], "tech_group_members": [], "tech_group_names": [], + "tech_or_group": [ + "IMPOIL1", + "IMPHYD", + "E21", + "RL1", + "TXG", + "E51", + "IMPDSL1", + "IMPHCO1", + "E01", + "SRE", + "RHE", + "E70", + "IMPFEQ", + "TXE", + "IMPURN1", + "IMPGSL1", + "TXD", + "RHO", + "E31" + ], "tech_production": [ "E01", "E21", From 7376ab29250ee0e5ecbceff167ca07a572803ead Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 10 Jun 2025 17:14:29 -0400 Subject: [PATCH 100/587] Collapse database migrators for v3.1 --- data_files/temoa_schema_v3_1.sql | 742 +++++-------- data_files/temoa_schema_v3_2.sql | 1086 -------------------- data_files/temoa_schema_v3_3.sql | 1013 ------------------ temoa/utilities/db_migration_operator.py | 183 ---- temoa/utilities/db_migration_tg.py | 127 --- temoa/utilities/db_migration_v3_to_v3_1.py | 109 +- 6 files changed, 351 insertions(+), 2909 deletions(-) delete mode 100644 data_files/temoa_schema_v3_2.sql delete mode 100644 data_files/temoa_schema_v3_3.sql delete mode 100644 temoa/utilities/db_migration_operator.py delete mode 100644 temoa/utilities/db_migration_tg.py diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index d5fb68eb7..caecad42d 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -126,6 +126,12 @@ REPLACE INTO CommodityType VALUES ('d', 'demand commodity'); REPLACE INTO CommodityType VALUES ('s', 'source commodity'); +REPLACE INTO CommodityType +VALUES ('w', 'waste commodity'); +REPLACE INTO CommodityType +VALUES ('wa', 'waste annual commodity'); +REPLACE INTO CommodityType +VALUES ('wp', 'waste physical commodity'); CREATE TABLE IF NOT EXISTS ConstructionInput ( region TEXT, @@ -336,44 +342,6 @@ CREATE TABLE IF NOT EXISTS TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE IF NOT EXISTS GrowthRateMax -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS GrowthRateSeed -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - seed REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE GrowthRateChangeMax -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE GrowthRateChangeSeed -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - seed REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) -); CREATE TABLE IF NOT EXISTS LoanLifetimeTech ( region TEXT, @@ -414,99 +382,311 @@ CREATE TABLE IF NOT EXISTS LifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE IF NOT EXISTS LinkedTech +CREATE TABLE IF NOT EXISTS Operator ( - primary_region TEXT, - primary_tech TEXT - REFERENCES Technology (tech), - emis_comm TEXT - REFERENCES Commodity (name), - driven_tech TEXT + operator TEXT PRIMARY KEY, + notes TEXT +); +REPLACE INTO Operator VALUES('e','equal to'); +REPLACE INTO Operator VALUES('le','less than or equal to'); +REPLACE INTO Operator VALUES('ge','greater than or equal to'); +CREATE TABLE IF NOT EXISTS LimitGrowthCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitDegrowthCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitGrowthNewCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitDegrowthNewCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitGrowthNewCapacityDelta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitDegrowthNewCapacityDelta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitStorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT REFERENCES Technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) + vintage INTEGER + REFERENCES TimePeriod (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE IF NOT EXISTS MaxActivity +CREATE TABLE IF NOT EXISTS LimitActivity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_act REAL, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE IF NOT EXISTS MaxCapacity +CREATE TABLE IF NOT EXISTS LimitActivityShare ( - region TEXT, - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, operator), + CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE IF NOT EXISTS MaxResource +CREATE TABLE IF NOT EXISTS LimitCapacity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), - max_res REAL, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, tech) + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE IF NOT EXISTS MinActivity +CREATE TABLE IF NOT EXISTS LimitNewCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_act REAL, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE IF NOT EXISTS MaxCapacityGroup +CREATE TABLE IF NOT EXISTS LimitNewCapacityShare ( - region TEXT, - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE IF NOT EXISTS MinCapacity +CREATE TABLE IF NOT EXISTS LimitResource ( region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_cap REAL, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + cum_act REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE IF NOT EXISTS MinCapacityGroup +CREATE TABLE IF NOT EXISTS LimitSeasonalCapacityFactor ( - region TEXT, - period INTEGER + region TEXT + REFERENCES Region (region), + period INTEGER REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) + season TEXT + REFERENCES TimeSeason (season), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) +); +CREATE TABLE IF NOT EXISTS LimitTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE IF NOT EXISTS LimitTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE IF NOT EXISTS LimitTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE IF NOT EXISTS LimitTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE IF NOT EXISTS LimitEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE IF NOT EXISTS LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) ); CREATE TABLE IF NOT EXISTS OutputCurtailment ( @@ -688,23 +868,6 @@ CREATE TABLE IF NOT EXISTS StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE IF NOT EXISTS StorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage) -); CREATE TABLE IF NOT EXISTS TechnologyType ( label TEXT @@ -719,111 +882,6 @@ REPLACE INTO TechnologyType VALUES ('pb', 'baseload production technology'); REPLACE INTO TechnologyType VALUES ('ps', 'storage production technology'); - -CREATE TABLE IF NOT EXISTS MinTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE IF NOT EXISTS MinTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE IF NOT EXISTS MinTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE IF NOT EXISTS MinTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE IF NOT EXISTS MaxTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE IF NOT EXISTS MaxTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE IF NOT EXISTS MaxTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE IF NOT EXISTS MaxTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -- CREATE TABLE IF NOT EXISTS TimeNext -- ( -- period INTEGER @@ -859,14 +917,14 @@ CREATE TABLE IF NOT EXISTS TimeSeason PRIMARY KEY ); CREATE TABLE IF NOT EXISTS PeriodSeasons -( +( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, season TEXT REFERENCES TimeSeason (season), notes TEXT, - PRIMARY KEY (period, sequence) + PRIMARY KEY (period, sequence, season) ); CREATE TABLE IF NOT EXISTS TimePeriodType ( @@ -878,188 +936,6 @@ REPLACE INTO TimePeriodType VALUES('e', 'existing vintages'); REPLACE INTO TimePeriodType VALUES('f', 'future'); -CREATE TABLE IF NOT EXISTS MaxActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE IF NOT EXISTS MaxCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE IF NOT EXISTS MaxAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS MaxNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE IF NOT EXISTS MaxNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS MaxNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE IF NOT EXISTS MinActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE IF NOT EXISTS MinAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS MinCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE IF NOT EXISTS MinNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE IF NOT EXISTS MinNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS MinNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE IF NOT EXISTS MinNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); -CREATE TABLE IF NOT EXISTS MaxNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group) -); CREATE TABLE IF NOT EXISTS OutputEmission ( scenario TEXT, @@ -1077,70 +953,6 @@ CREATE TABLE IF NOT EXISTS OutputEmission emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE IF NOT EXISTS MinActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS EmissionLimit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE IF NOT EXISTS MaxActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS MinSeasonalActivity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tech TEXT - REFERENCES Technology (tech), - min_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY(region,period,season,tech) -); -CREATE TABLE IF NOT EXISTS MaxSeasonalActivity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tech TEXT - REFERENCES Technology (tech), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY(region,period,season,tech) -); CREATE TABLE IF NOT EXISTS RPSRequirement ( region TEXT NOT NULL diff --git a/data_files/temoa_schema_v3_2.sql b/data_files/temoa_schema_v3_2.sql deleted file mode 100644 index 01477ff8b..000000000 --- a/data_files/temoa_schema_v3_2.sql +++ /dev/null @@ -1,1086 +0,0 @@ -PRAGMA foreign_keys= OFF; -BEGIN TRANSACTION; - -CREATE TABLE IF NOT EXISTS MetaData -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -REPLACE INTO MetaData -VALUES ('myopic_base_year', 2000, 'Base Year for Myopic Analysis'); -REPLACE INTO MetaData -VALUES ('DB_MAJOR', 3, 'DB major version number'); -REPLACE INTO MetaData -VALUES ('DB_MINOR', 0, 'DB minor version number'); -REPLACE INTO MetaData -VALUES ('state_sequencing', 0, '0 = loop periods, 1 = loop seasons'); - -CREATE TABLE IF NOT EXISTS MetaDataReal -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -REPLACE INTO MetaDataReal -VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); -REPLACE INTO MetaDataReal -VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in LoanRate table'); - -CREATE TABLE IF NOT EXISTS OutputDualVariable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE IF NOT EXISTS OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE IF NOT EXISTS SectorLabel -( - sector TEXT, - PRIMARY KEY (sector) -); - -CREATE TABLE IF NOT EXISTS CapacityCredit -( - region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -CREATE TABLE IF NOT EXISTS CapacityFactorProcess -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS CapacityFactorTech -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS CapacityToActivity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS Commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES CommodityType (label), - description TEXT -); -CREATE TABLE IF NOT EXISTS CommodityType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO CommodityType -VALUES ('p', 'physical commodity'); -REPLACE INTO CommodityType -VALUES ('a', 'annual commodity'); -REPLACE INTO CommodityType -VALUES ('e', 'emissions commodity'); -REPLACE INTO CommodityType -VALUES ('d', 'demand commodity'); -REPLACE INTO CommodityType -VALUES ('s', 'source commodity'); -REPLACE INTO CommodityType -VALUES ('w', 'waste commodity'); -REPLACE INTO CommodityType -VALUES ('wa', 'waste annual commodity'); -REPLACE INTO CommodityType -VALUES ('wp', 'waste physical commodity'); -CREATE TABLE IF NOT EXISTS ConstructionInput -( - region TEXT, - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS CostEmission -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT NOT NULL - REFERENCES Commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE IF NOT EXISTS CostFixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS CostInvest -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS CostVariable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS Demand -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - commodity TEXT - REFERENCES Commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -CREATE TABLE IF NOT EXISTS DemandSpecificDistribution -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - demand_name TEXT - REFERENCES Commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -CREATE TABLE IF NOT EXISTS EndOfLifeOutput -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS Efficiency -( - region TEXT, - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE IF NOT EXISTS EfficiencyVariable -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE IF NOT EXISTS EmissionActivity -( - region TEXT, - emis_comm TEXT - REFERENCES Commodity (name), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS EmissionEmbodied -( - region TEXT, - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS EmissionEndOfLife -( - region TEXT, - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS ExistingCapacity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS LoanLifetimeTech -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS LoanRate -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS LifetimeProcess -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS LifetimeTech -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS Operator -( - operator TEXT PRIMARY KEY, - notes TEXT -); -REPLACE INTO Operator VALUES('e','equal to'); -REPLACE INTO Operator VALUES('le','less than or equal to'); -REPLACE INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE IF NOT EXISTS LimitGrowthCapacity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, operator) -); -CREATE TABLE IF NOT EXISTS LimitDegrowthCapacity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, operator) -); -CREATE TABLE IF NOT EXISTS LimitGrowthNewCapacity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, operator) -); -CREATE TABLE IF NOT EXISTS LimitDegrowthNewCapacity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, operator) -); -CREATE TABLE IF NOT EXISTS LimitGrowthNewCapacityDelta -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, operator) -); -CREATE TABLE IF NOT EXISTS LimitDegrowthNewCapacityDelta -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, operator) -); -CREATE TABLE IF NOT EXISTS LimitStorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -CREATE TABLE IF NOT EXISTS LimitActivity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE IF NOT EXISTS LimitActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); -CREATE TABLE IF NOT EXISTS LimitActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) -); -CREATE TABLE IF NOT EXISTS LimitAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS LimitCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE IF NOT EXISTS LimitCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); -CREATE TABLE IF NOT EXISTS LimitCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) -); -CREATE TABLE IF NOT EXISTS LimitNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, operator) -); -CREATE TABLE IF NOT EXISTS LimitNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name, operator) -); -CREATE TABLE IF NOT EXISTS LimitNewCapacityGroupShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT - REFERENCES TechGroup (group_name), - super_group TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name, operator) -); -CREATE TABLE IF NOT EXISTS LimitResource -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, operator) -); -CREATE TABLE IF NOT EXISTS LimitSeasonalCapacityFactor -( - region TEXT - REFERENCES Region (region), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) -); -CREATE TABLE IF NOT EXISTS LimitTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE IF NOT EXISTS LimitTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE IF NOT EXISTS LimitTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE IF NOT EXISTS LimitTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE IF NOT EXISTS LimitEmission -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE IF NOT EXISTS LinkedTech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES Technology (tech), - emis_comm TEXT - REFERENCES Commodity (name), - driven_tech TEXT - REFERENCES Technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -CREATE TABLE IF NOT EXISTS OutputCurtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputNetCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputBuiltCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputRetiredCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputFlowIn -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputFlowOut -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputStorageLevel -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE IF NOT EXISTS PlanningReserveMargin -( - region TEXT - PRIMARY KEY - REFERENCES Region (region), - margin REAL -); -CREATE TABLE IF NOT EXISTS RampDown -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS RampUp -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS Region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS TimeSegmentFraction -( - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) -); -CREATE TABLE IF NOT EXISTS StorageDuration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS TechnologyType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO TechnologyType -VALUES ('r', 'resource technology'); -REPLACE INTO TechnologyType -VALUES ('p', 'production technology'); -REPLACE INTO TechnologyType -VALUES ('pb', 'baseload production technology'); -REPLACE INTO TechnologyType -VALUES ('ps', 'storage production technology'); --- CREATE TABLE IF NOT EXISTS TimeNext --- ( --- period INTEGER --- REFERENCES TimePeriod (period), --- season TEXT --- REFERENCES TimeSeason (season), --- tod TEXT --- REFERENCES TimeOfDay (tod), --- season_next TEXT --- REFERENCES TimeSeason (season), --- tod_next TEXT --- REFERENCES TimeOfDay (tod), --- notes TEXT, --- PRIMARY KEY (period, season, tod) --- ); -CREATE TABLE IF NOT EXISTS TimeOfDay -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY -); -CREATE TABLE IF NOT EXISTS TimePeriod -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES TimePeriodType (label) -); -CREATE TABLE IF NOT EXISTS TimeSeason -( - season TEXT - PRIMARY KEY -); -CREATE TABLE IF NOT EXISTS PeriodSeasons -( - period INTEGER - REFERENCES TimePeriod (period), - sequence INTEGER, - season TEXT - REFERENCES TimeSeason (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); -CREATE TABLE IF NOT EXISTS TimePeriodType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO TimePeriodType -VALUES('e', 'existing vintages'); -REPLACE INTO TimePeriodType -VALUES('f', 'future'); -CREATE TABLE IF NOT EXISTS OutputEmission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS RPSRequirement -( - region TEXT NOT NULL - REFERENCES Region (region), - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech_group TEXT NOT NULL - REFERENCES TechGroup (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE IF NOT EXISTS TechGroupMember -( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES Technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE IF NOT EXISTS Technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) -); -CREATE TABLE OutputCost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) -); -COMMIT; -PRAGMA FOREIGN_KEYS = 1; \ No newline at end of file diff --git a/data_files/temoa_schema_v3_3.sql b/data_files/temoa_schema_v3_3.sql deleted file mode 100644 index caecad42d..000000000 --- a/data_files/temoa_schema_v3_3.sql +++ /dev/null @@ -1,1013 +0,0 @@ -PRAGMA foreign_keys= OFF; -BEGIN TRANSACTION; - -CREATE TABLE IF NOT EXISTS MetaData -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -REPLACE INTO MetaData -VALUES ('myopic_base_year', 2000, 'Base Year for Myopic Analysis'); -REPLACE INTO MetaData -VALUES ('DB_MAJOR', 3, 'DB major version number'); -REPLACE INTO MetaData -VALUES ('DB_MINOR', 0, 'DB minor version number'); -REPLACE INTO MetaData -VALUES ('state_sequencing', 0, '0 = loop periods, 1 = loop seasons'); - -CREATE TABLE IF NOT EXISTS MetaDataReal -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -REPLACE INTO MetaDataReal -VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); -REPLACE INTO MetaDataReal -VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in LoanRate table'); - -CREATE TABLE IF NOT EXISTS OutputDualVariable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE IF NOT EXISTS OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE IF NOT EXISTS SectorLabel -( - sector TEXT, - PRIMARY KEY (sector) -); - -CREATE TABLE IF NOT EXISTS CapacityCredit -( - region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -CREATE TABLE IF NOT EXISTS CapacityFactorProcess -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS CapacityFactorTech -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS CapacityToActivity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS Commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES CommodityType (label), - description TEXT -); -CREATE TABLE IF NOT EXISTS CommodityType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO CommodityType -VALUES ('p', 'physical commodity'); -REPLACE INTO CommodityType -VALUES ('a', 'annual commodity'); -REPLACE INTO CommodityType -VALUES ('e', 'emissions commodity'); -REPLACE INTO CommodityType -VALUES ('d', 'demand commodity'); -REPLACE INTO CommodityType -VALUES ('s', 'source commodity'); -REPLACE INTO CommodityType -VALUES ('w', 'waste commodity'); -REPLACE INTO CommodityType -VALUES ('wa', 'waste annual commodity'); -REPLACE INTO CommodityType -VALUES ('wp', 'waste physical commodity'); -CREATE TABLE IF NOT EXISTS ConstructionInput -( - region TEXT, - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS CostEmission -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT NOT NULL - REFERENCES Commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE IF NOT EXISTS CostFixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS CostInvest -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS CostVariable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS Demand -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - commodity TEXT - REFERENCES Commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -CREATE TABLE IF NOT EXISTS DemandSpecificDistribution -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - demand_name TEXT - REFERENCES Commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -CREATE TABLE IF NOT EXISTS EndOfLifeOutput -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS Efficiency -( - region TEXT, - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE IF NOT EXISTS EfficiencyVariable -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE IF NOT EXISTS EmissionActivity -( - region TEXT, - emis_comm TEXT - REFERENCES Commodity (name), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS EmissionEmbodied -( - region TEXT, - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS EmissionEndOfLife -( - region TEXT, - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS ExistingCapacity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS LoanLifetimeTech -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS LoanRate -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS LifetimeProcess -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS LifetimeTech -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS Operator -( - operator TEXT PRIMARY KEY, - notes TEXT -); -REPLACE INTO Operator VALUES('e','equal to'); -REPLACE INTO Operator VALUES('le','less than or equal to'); -REPLACE INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE IF NOT EXISTS LimitGrowthCapacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitDegrowthCapacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitGrowthNewCapacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitDegrowthNewCapacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitGrowthNewCapacityDelta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitDegrowthNewCapacityDelta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitStorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -CREATE TABLE IF NOT EXISTS LimitActivity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS LimitCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitResource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitSeasonalCapacityFactor -( - region TEXT - REFERENCES Region (region), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) -); -CREATE TABLE IF NOT EXISTS LimitTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE IF NOT EXISTS LimitTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE IF NOT EXISTS LimitTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE IF NOT EXISTS LimitTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE IF NOT EXISTS LimitEmission -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE IF NOT EXISTS LinkedTech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES Technology (tech), - emis_comm TEXT - REFERENCES Commodity (name), - driven_tech TEXT - REFERENCES Technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -CREATE TABLE IF NOT EXISTS OutputCurtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputNetCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputBuiltCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputRetiredCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputFlowIn -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputFlowOut -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputStorageLevel -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE IF NOT EXISTS PlanningReserveMargin -( - region TEXT - PRIMARY KEY - REFERENCES Region (region), - margin REAL -); -CREATE TABLE IF NOT EXISTS RampDown -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS RampUp -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS Region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS TimeSegmentFraction -( - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) -); -CREATE TABLE IF NOT EXISTS StorageDuration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS TechnologyType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO TechnologyType -VALUES ('r', 'resource technology'); -REPLACE INTO TechnologyType -VALUES ('p', 'production technology'); -REPLACE INTO TechnologyType -VALUES ('pb', 'baseload production technology'); -REPLACE INTO TechnologyType -VALUES ('ps', 'storage production technology'); --- CREATE TABLE IF NOT EXISTS TimeNext --- ( --- period INTEGER --- REFERENCES TimePeriod (period), --- season TEXT --- REFERENCES TimeSeason (season), --- tod TEXT --- REFERENCES TimeOfDay (tod), --- season_next TEXT --- REFERENCES TimeSeason (season), --- tod_next TEXT --- REFERENCES TimeOfDay (tod), --- notes TEXT, --- PRIMARY KEY (period, season, tod) --- ); -CREATE TABLE IF NOT EXISTS TimeOfDay -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY -); -CREATE TABLE IF NOT EXISTS TimePeriod -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES TimePeriodType (label) -); -CREATE TABLE IF NOT EXISTS TimeSeason -( - season TEXT - PRIMARY KEY -); -CREATE TABLE IF NOT EXISTS PeriodSeasons -( - period INTEGER - REFERENCES TimePeriod (period), - sequence INTEGER, - season TEXT - REFERENCES TimeSeason (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); -CREATE TABLE IF NOT EXISTS TimePeriodType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO TimePeriodType -VALUES('e', 'existing vintages'); -REPLACE INTO TimePeriodType -VALUES('f', 'future'); -CREATE TABLE IF NOT EXISTS OutputEmission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS RPSRequirement -( - region TEXT NOT NULL - REFERENCES Region (region), - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech_group TEXT NOT NULL - REFERENCES TechGroup (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE IF NOT EXISTS TechGroupMember -( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES Technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE IF NOT EXISTS Technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) -); -CREATE TABLE OutputCost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) -); -COMMIT; -PRAGMA FOREIGN_KEYS = 1; \ No newline at end of file diff --git a/temoa/utilities/db_migration_operator.py b/temoa/utilities/db_migration_operator.py deleted file mode 100644 index a191c4449..000000000 --- a/temoa/utilities/db_migration_operator.py +++ /dev/null @@ -1,183 +0,0 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - -Written by: I. D. Elder -iandavidelder@gmail.com -Created on: 2025/03/14 - -Convert various constraints on the Max/Min separate tables paradigm -to the new operator-based single Limit table paradigm. -""" - -import argparse -import sqlite3 -import sys -from pathlib import Path - -parser = argparse.ArgumentParser() -parser.add_argument( - '--source', - help='Path to original database', - required=True, - action='store', - dest='source_db', -) -parser.add_argument( - '--schema', - help='Path to schema file (default=data_files/temoa_schema_v3_2)', - required=False, - dest='schema', - default='data_files/temoa_schema_v3_2.sql', -) -options = parser.parse_args() -legacy_db: Path = Path(options.source_db) -schema_file = Path(options.schema) - -new_db_name = legacy_db.stem + '_v3_2.sqlite' -new_db_path = Path(legacy_db.parent, new_db_name) - -con_old = sqlite3.connect(legacy_db) -con_new = sqlite3.connect(new_db_path) -cur = con_new.cursor() - -# bring in the new schema and execute -with open(schema_file, 'r') as src: - sql_script = src.read() -con_new.executescript(sql_script) - -# turn off FK verification while process executes -con_new.execute('PRAGMA foreign_keys = 0;') - -add_operator_tables = { - 'EmissionLimit': ('LimitEmission', 'le'), - 'MinTechOutputSplitAnnual': ('LimitTechOutputSplitAnnual', 'ge'), - 'MinTechOutputSplit': ('LimitTechOutputSplit', 'ge'), - 'MinTechInputSplitAnnual': ('LimitTechInputSplitAnnual', 'le'), - 'MinTechInputSplit': ('LimitTechInputSplit', 'ge'), - 'MinSeasonalActivity': ('LimitSeasonalActivity', 'ge'), - 'MinNewCapacityShare': ('LimitNewCapacityShare', 'ge'), - 'MinNewCapacityGroupShare': ('LimitNewCapacityGroupShare', 'ge'), - 'MinNewCapacityGroup': ('LimitNewCapacityGroup', 'ge'), - 'MinNewCapacity': ('LimitNewCapacity', 'ge'), - 'MinCapacityShare': ('LimitCapacityShare', 'ge'), - 'MinCapacityGroup': ('LimitCapacityGroup', 'ge'), - 'MinCapacity': ('LimitCapacity', 'ge'), - 'MinAnnualCapacityFactor': ('LimitAnnualCapacityFactor', 'ge'), - 'MinActivityShare': ('LimitActivityShare', 'ge'), - 'MinActivityGroup': ('LimitActivityGroup', 'ge'), - 'MinActivity': ('LimitActivity', 'ge'), - 'MaxTechOutputSplitAnnual': ('LimitTechOutputSplitAnnual', 'le'), - 'MaxTechOutputSplit': ('LimitTechOutputSplit', 'le'), - 'MaxTechInputSplitAnnual': ('LimitTechInputSplitAnnual', 'le'), - 'MaxTechInputSplit': ('LimitTechInputSplit', 'le'), - 'MaxSeasonalActivity': ('LimitSeasonalActivity', 'le'), - 'MaxNewCapacityShare': ('LimitNewCapacityShare', 'le'), - 'MaxNewCapacityGroupShare': ('LimitNewCapacityGroupShare', 'le'), - 'MaxNewCapacityGroup': ('LimitNewCapacityGroup', 'le'), - 'MaxNewCapacity': ('LimitNewCapacity', 'le'), - 'MaxCapacityShare': ('LimitCapacityShare', 'le'), - 'MaxCapacityGroup': ('LimitCapacityGroup', 'le'), - 'MaxCapacity': ('LimitCapacity', 'le'), - 'MaxAnnualCapacityFactor': ('LimitAnnualCapacityFactor', 'le'), - 'MaxActivityShare': ('LimitActivityShare', 'le'), - 'MaxActivityGroup': ('LimitActivityGroup', 'le'), - 'MaxActivity': ('LimitActivity', 'le'), - 'MaxResource': ('LimitResource', 'le'), - 'StorageLevelFraction': ('LimitStorageLevelFraction', 'e'), -} - - -# Collapse Max/Min constraint tables -print('\n --- Collapsing Max/Min tables and adding operators ---') -for old_name, (new_name, operator) in add_operator_tables.items(): - - try: - data = con_old.execute(f'SELECT * FROM {old_name}').fetchall() - except sqlite3.OperationalError: - print('TABLE NOT FOUND: ' + old_name) - continue - - if not data: - print('No data for: ' + old_name) - continue - - new_cols: tuple = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] - op_index = new_cols.index('operator') - data = [(*row[0:op_index], operator, *row[op_index::]) for row in data] - - # construct the query with correct number of placeholders - num_placeholders = len(data[0]) - placeholders = ','.join(['?' for _ in range(num_placeholders)]) - query = f'INSERT OR REPLACE INTO {new_name} VALUES ({placeholders})' - con_new.executemany(query, data) - print(f'Added operator index to {new_name} and inserted {len(data)} rows') - - -old_tables = set([t[1] for t in con_old.execute('SELECT * FROM sqlite_master WHERE type="table";')]) -new_tables = set([t[1] for t in con_new.execute('SELECT * FROM sqlite_master WHERE type="table";')]) -limit_tables = set(add_operator_tables.keys()) - -direct_transfer_tables = (new_tables & old_tables) - limit_tables - -print('\n --- Executing direct transfers ---') -for table in direct_transfer_tables: - - try: - con_old.execute(f'SELECT * FROM {table}').fetchone() - except sqlite3.OperationalError: - print('TABLE NOT FOUND: ' + table) - continue - - data = con_old.execute(f'SELECT * FROM {table}').fetchall() - - if not data: - print('No data for: ' + table) - continue - - # construct the query with correct number of placeholders - num_placeholders = len(data[0]) - placeholders = ','.join(['?' for _ in range(num_placeholders)]) - query = f'INSERT OR REPLACE INTO {table} VALUES ({placeholders})' - con_new.executemany(query, data) - print(f'Transferred {len(data)} rows from {table}') - - -print('\n --- Validating foreign keys ---') -con_new.commit() -con_new.execute('VACUUM;') -con_new.execute('PRAGMA FOREIGN_KEYS=1;') -try: - data = con_new.execute('PRAGMA FOREIGN_KEY_CHECK;').fetchall() - if not data: - print('No Foreign Key Failures. (Good news!)') - else: - print('\nFK check fails (MUST BE FIXED):') - print('(Table, Row ID, Reference Table, (fkid) )') - for row in data: - print(row) -except sqlite3.OperationalError as e: - print('Foreign Key Check FAILED on new DB. Something may be wrong with schema.') - print(e) - -print('\nFinished! Check your database for any missing data.' - ' If there was a mismatch of table names, something may have been lost.') - -con_new.close() -con_old.close() \ No newline at end of file diff --git a/temoa/utilities/db_migration_tg.py b/temoa/utilities/db_migration_tg.py deleted file mode 100644 index 2d8bf1412..000000000 --- a/temoa/utilities/db_migration_tg.py +++ /dev/null @@ -1,127 +0,0 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - -Written by: I. D. Elder -iandavidelder@gmail.com -Created on: 2025/06/10 - -Collapses group/non-group Limit tables -""" - -import argparse -import sqlite3 -import sys -from pathlib import Path - -parser = argparse.ArgumentParser() -parser.add_argument( - '--source', - help='Path to original database', - required=True, - action='store', - dest='source_db', -) -parser.add_argument( - '--schema', - help='Path to schema file (default=data_files/temoa_schema_v3_3)', - required=False, - dest='schema', - default='data_files/temoa_schema_v3_3.sql', -) -options = parser.parse_args() -legacy_db: Path = Path(options.source_db) -schema_file = Path(options.schema) - -new_db_name = legacy_db.stem + '_v3_3.sqlite' -new_db_path = Path(legacy_db.parent, new_db_name) - -con_old = sqlite3.connect(legacy_db) -con_new = sqlite3.connect(new_db_path) -cur = con_new.cursor() - -# bring in the new schema and execute -with open(schema_file, 'r') as src: - sql_script = src.read() -con_new.executescript(sql_script) - -# turn off FK verification while process executes -con_new.execute('PRAGMA foreign_keys = 0;') - -tables_to_collapse = { - 'LimitActivityGroup': 'LimitActivity', - 'LimitCapacityGroup': 'LimitCapacity', - 'LimitNewCapacityGroup': 'LimitNewCapacity', - 'LimitNewCapacityGroupShare': 'LimitNewCapacityShare', -} - -old_tables = set([t[1] for t in con_old.execute('SELECT * FROM sqlite_master WHERE type="table";')]) -new_tables = set([t[1] for t in con_new.execute('SELECT * FROM sqlite_master WHERE type="table";')]) -collapsed_tables = set(tables_to_collapse.keys()) - -direct_transfer_tables = (new_tables & old_tables) - collapsed_tables - -transfers: dict = {t: t for t in direct_transfer_tables} -transfers.update(tables_to_collapse) - -print('\n --- Executing direct transfers ---') -for old_table, new_table in transfers.items(): - - try: - con_old.execute(f'SELECT * FROM {old_table}').fetchone() - except sqlite3.OperationalError: - print('TABLE NOT FOUND: ' + old_table) - continue - - data = con_old.execute(f'SELECT * FROM {old_table}').fetchall() - - if not data: - print('No data for: ' + old_table) - continue - - # construct the query with correct number of placeholders - num_placeholders = len(data[0]) - placeholders = ','.join(['?' for _ in range(num_placeholders)]) - query = f'INSERT OR REPLACE INTO {new_table} VALUES ({placeholders})' - con_new.executemany(query, data) - print(f'Transferred {len(data)} rows from {old_table} to {new_table}') - - -print('\n --- Validating foreign keys ---') -con_new.commit() -con_new.execute('VACUUM;') -con_new.execute('PRAGMA FOREIGN_KEYS=1;') -try: - data = con_new.execute('PRAGMA FOREIGN_KEY_CHECK;').fetchall() - if not data: - print('No Foreign Key Failures. (Good news!)') - else: - print('\nFK check fails (MUST BE FIXED):') - print('(Table, Row ID, Reference Table, (fkid) )') - for row in data: - print(row) -except sqlite3.OperationalError as e: - print('Foreign Key Check FAILED on new DB. Something may be wrong with schema.') - print(e) - -print('\nFinished! Check your database for any missing data.' - ' If there was a mismatch of table names, something may have been lost.') - -con_new.close() -con_old.close() \ No newline at end of file diff --git a/temoa/utilities/db_migration_v3_to_v3_1.py b/temoa/utilities/db_migration_v3_to_v3_1.py index 28425a210..536abae84 100644 --- a/temoa/utilities/db_migration_v3_to_v3_1.py +++ b/temoa/utilities/db_migration_v3_to_v3_1.py @@ -100,42 +100,14 @@ def column_check(old_name: str, new_name: str) -> bool: ('', 'Demand'), ('', 'Efficiency'), ('', 'EmissionActivity'), - ('', 'EmissionLimit'), ('', 'ExistingCapacity'), - ('', 'GrowthRateMax'), - ('', 'GrowthRateSeed'), ('', 'LifetimeProcess'), ('', 'LifetimeTech'), ('', 'LinkedTech'), ('', 'LoanLifetimeTech'), ('', 'LoanRate'), - ('', 'MaxActivity'), - ('', 'MaxActivityGroup'), - ('', 'MaxActivityShare'), - ('', 'MaxAnnualCapacityFactor'), - ('', 'MaxCapacity'), - ('', 'MaxCapacityGroup'), - ('', 'MaxCapacityShare'), - ('', 'MaxNewCapacity'), - ('', 'MaxNewCapacityGroup'), - ('', 'MaxNewCapacityShare'), - ('', 'MaxResource'), - ('', 'MaxSeasonalActivity'), ('', 'MetaData'), ('', 'MetaDataReal'), - ('', 'MinActivity'), - ('', 'MinActivityGroup'), - ('', 'MinActivityShare'), - ('', 'MinAnnualCapacityFactor'), - ('', 'MinCapacity'), - ('', 'MinCapacityGroup'), - ('', 'MinCapacityShare'), - ('', 'MinNewCapacity'), - ('', 'MinNewCapacityGroup'), - ('', 'MinNewCapacityShare'), - ('', 'MinNewCapacityGroupShare'), - ('', 'MaxNewCapacityGroupShare'), - ('', 'MinSeasonalActivity'), ('', 'PlanningReserveMargin'), ('', 'RampDown'), ('', 'RampUp'), @@ -145,12 +117,8 @@ def column_check(old_name: str, new_name: str) -> bool: ('', 'StorageDuration'), ('', 'TechGroup'), ('', 'TechGroupMember'), - ('TechInputSplit', 'MinTechInputSplit'), - ('TechInputSplitAnnual', 'MinTechInputSplitAnnual'), - ('TechInputSplitAverage', 'MinTechInputSplitAnnual'), ('', 'Technology'), ('', 'TechnologyType'), - ('TechOutputSplit', 'MinTechOutputSplit'), ('', 'TimeOfDay'), ('', 'TimePeriod'), ('', 'TimePeriodType'), @@ -164,6 +132,44 @@ def column_check(old_name: str, new_name: str) -> bool: ('', 'TimeSegmentFraction'), ] +operator_added_tables = { + 'EmissionLimit': ('LimitEmission', 'le'), + 'TechOutputSplit': ('LimitTechOutputSplit', 'ge'), + 'TechInputSplitAnnual': ('LimitTechInputSplitAnnual', 'le'), + 'TechInputSplitAverage': ('LimitTechInputSplitAnnual', 'le'), + 'TechInputSplit': ('LimitTechInputSplit', 'ge'), + 'MinNewCapacityShare': ('LimitNewCapacityShare', 'ge'), + 'MinNewCapacityGroupShare': ('LimitNewCapacityShare', 'ge'), + 'MinNewCapacityGroup': ('LimitNewCapacity', 'ge'), + 'MinNewCapacity': ('LimitNewCapacity', 'ge'), + 'MinCapacityShare': ('LimitCapacityShare', 'ge'), + 'MinCapacityGroup': ('LimitCapacity', 'ge'), + 'MinCapacity': ('LimitCapacity', 'ge'), + 'MinAnnualCapacityFactor': ('LimitAnnualCapacityFactor', 'ge'), + 'MinActivityShare': ('LimitActivityShare', 'ge'), + 'MinActivityGroup': ('LimitActivity', 'ge'), + 'MinActivity': ('LimitActivity', 'ge'), + 'MaxNewCapacityShare': ('LimitNewCapacityShare', 'le'), + 'MaxNewCapacityGroupShare': ('LimitNewCapacityShare', 'le'), + 'MaxNewCapacityGroup': ('LimitNewCapacity', 'le'), + 'MaxNewCapacity': ('LimitNewCapacity', 'le'), + 'MaxCapacityShare': ('LimitCapacityShare', 'le'), + 'MaxCapacityGroup': ('LimitCapacity', 'le'), + 'MaxCapacity': ('LimitCapacity', 'le'), + 'MaxAnnualCapacityFactor': ('LimitAnnualCapacityFactor', 'le'), + 'MaxActivityShare': ('LimitActivityShare', 'le'), + 'MaxActivityGroup': ('LimitActivity', 'le'), + 'MaxActivity': ('LimitActivity', 'le'), + 'MaxResource': ('LimitResource', 'le'), +} + +no_transfer = { + 'MinSeasonalActivity': 'LimitSeasonalCapacityFactor', + 'MaxSeasonalActivity': 'LimitSeasonalCapacityFactor', + 'StorageInit': 'LimitStorageLevelFraction', +} + + all_good = True for old_name, new_name in direct_transfer_tables: good = column_check(old_name, new_name) @@ -173,8 +179,34 @@ def column_check(old_name: str, new_name: str) -> bool: all_good = all_good and good if not all_good: sys.exit(-1) + +# Collapse Max/Min constraint tables +print('\n --- Collapsing Max/Min tables and adding operators ---') +for old_name, (new_name, operator) in operator_added_tables.items(): + + try: + data = con_old.execute(f'SELECT * FROM {old_name}').fetchall() + except sqlite3.OperationalError: + print('TABLE NOT FOUND: ' + old_name) + continue + + if not data: + print('No data for: ' + old_name) + continue + + new_cols: tuple = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] + op_index = new_cols.index('operator') + data = [(*row[0:op_index], operator, *row[op_index:len(new_cols)-1]) for row in data] + + # construct the query with correct number of placeholders + num_placeholders = len(data[0]) + placeholders = ','.join(['?' for _ in range(num_placeholders)]) + query = f'INSERT OR REPLACE INTO {new_name} VALUES ({placeholders})' + con_new.executemany(query, data) + print(f'Transfered {len(data)} rows from {old_name} to {new_name}') + # It wasn't active anyway... can't be bothered -# StorageInit -> StorageFraction +# StorageInit -> LimitStorageLevelFraction # TimeSeason try: @@ -208,7 +240,7 @@ def column_check(old_name: str, new_name: str) -> bool: placeholders = ','.join(['?' for _ in range(num_placeholders)]) query = f'INSERT OR REPLACE INTO {new_name} VALUES ({placeholders})' con_new.executemany(query, data) - print(f'inserted {len(data)} rows into {new_name}') + print(f'Transfered {len(data)} rows from {old_name} to {new_name}') # get lifetimes. Major headache but needs to be done data = cur.execute('SELECT region, tech, lifetime FROM LifetimeTech').fetchall() @@ -265,7 +297,13 @@ def column_check(old_name: str, new_name: str) -> bool: placeholders = ','.join(['?' for _ in range(num_placeholders)]) query = f'INSERT OR REPLACE INTO {new_name} VALUES ({placeholders})' con_new.executemany(query, data_new) - print(f'Added period index to {new_name} and inserted {len(data_new)} rows') + print(f'Transfered {len(data)} rows from {old_name} to {new_name}') + + +# Warn about incompatible changes +print('\n --- The following transfers were impossible due to incompatible changes. Transfer manually. ---') +for old_name, new_name in no_transfer.items(): + print(f'{old_name} to {new_name}') # state_sequencing parameter @@ -280,6 +318,7 @@ def column_check(old_name: str, new_name: str) -> bool: cur.execute("UPDATE MetaData SET value = 1 WHERE element == 'DB_MINOR'") print("Updated database version to 3.1") + print('\n --- Validating foreign keys ---') con_new.commit() con_new.execute('VACUUM;') From bcc383e546af3ed1261f1d3d63d2165411fd2410 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 12 Jun 2025 11:32:10 -0400 Subject: [PATCH 101/587] Move time sequencing parameter to the config file --- data_files/example_dbs/materials.sql | 2 -- data_files/example_dbs/morris_utopia.sql | 1 - data_files/example_dbs/stepped_demand.sql | 1 - data_files/example_dbs/test_system.sql | 2 -- data_files/example_dbs/utopia.sql | 1 - data_files/my_configs/config_sample.toml | 17 ++++++++++ data_files/my_configs/mga_utopia.toml | 17 ++++++++++ data_files/my_configs/monte_carlo_utopia.toml | 17 ++++++++++ data_files/my_configs/morris_utopia.toml | 17 ++++++++++ data_files/my_configs/stepped_demand.toml | 17 ++++++++++ data_files/temoa_schema_v3_1.sql | 2 -- temoa/temoa_model/hybrid_loader.py | 34 +++++++++---------- temoa/temoa_model/temoa_config.py | 3 ++ temoa/temoa_model/temoa_initialize.py | 24 +++++++------ temoa/temoa_model/temoa_model.py | 4 +-- tests/testing_configs/config_emissions.toml | 17 ++++++++++ tests/testing_configs/config_link_test.toml | 17 ++++++++++ tests/testing_configs/config_materials.toml | 17 ++++++++++ tests/testing_configs/config_mediumville.toml | 17 ++++++++++ .../testing_configs/config_storageville.toml | 17 ++++++++++ tests/testing_configs/config_test_system.toml | 17 ++++++++++ tests/testing_configs/config_utopia.toml | 17 ++++++++++ .../testing_configs/config_utopia_myopic.toml | 19 ++++++++++- tests/testing_data/emissions.sql | 2 -- tests/testing_data/materials.sql | 2 -- tests/testing_data/mediumville.sql | 2 -- tests/testing_data/mediumville_sets.json | 3 ++ tests/testing_data/simple_linked_tech.sql | 2 -- tests/testing_data/storageville.sql | 2 -- tests/testing_data/test_system.sql | 2 -- tests/testing_data/test_system_sets.json | 3 ++ tests/testing_data/utopia.sql | 1 - tests/testing_data/utopia_sets.json | 3 ++ 33 files changed, 266 insertions(+), 53 deletions(-) diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index 8dafbf3c6..3140295bf 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -10,8 +10,6 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES('link_seasons',1,'Carry storage states between seasons'); -INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); CREATE TABLE MetaDataReal ( element TEXT, diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index 1e3d5cb51..76a8fa0ac 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -10,7 +10,6 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); CREATE TABLE MetaDataReal ( element TEXT, diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index 27e3dab7a..e65e7ba06 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -10,7 +10,6 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES('myopic_base_year',2000,''); -INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); CREATE TABLE MetaDataReal ( element TEXT, diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index 122cfac17..8994fa8bd 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -10,8 +10,6 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES('link_seasons',1,'Carry storage states between seasons'); -INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); CREATE TABLE MetaDataReal ( element TEXT, diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 7cacd5e6a..38cf05bca 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -10,7 +10,6 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('myopic_base_year',1990,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); CREATE TABLE MetaDataReal ( element TEXT, diff --git a/data_files/my_configs/config_sample.toml b/data_files/my_configs/config_sample.toml index 1ab39cfa1..d3bd6322c 100644 --- a/data_files/my_configs/config_sample.toml +++ b/data_files/my_configs/config_sample.toml @@ -77,6 +77,23 @@ save_storage_levels = true # save a copy of the pyomo-generated lp file(s) to the outputs folder (maybe a large file(s)!) save_lp_file = false +# ------------------------------------ +# MODEL PARAMETERS +# these are specific to each model +# ------------------------------------ + +# How to sequence time slices in the model. Options: +# 'loop_periods' +# Time slices sequence through seasons and between seasons, looping from the end of each +# period back to its start. Compatible with seasonal time-slicing databases. +# 'loop_seasons' +# Time slices sequence through seasons but loop from the end of each season back to its start. +# Time slices do not connect between seasons. Compatible with representative periods databases. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out in +# the schema). This is an advanced feature and not recommended for most users. +time_sequencing = 'loop_periods' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/data_files/my_configs/mga_utopia.toml b/data_files/my_configs/mga_utopia.toml index 250f00159..524df743e 100644 --- a/data_files/my_configs/mga_utopia.toml +++ b/data_files/my_configs/mga_utopia.toml @@ -71,6 +71,23 @@ save_duals = false # save a copy of the pyomo-generated lp file(s) to the outputs folder (maybe a large file(s)!) save_lp_file = false +# ------------------------------------ +# MODEL PARAMETERS +# these are specific to each model +# ------------------------------------ + +# How to sequence time slices in the model. Options: +# 'loop_periods' +# Time slices sequence through seasons and between seasons, looping from the end of each +# period back to its start. Compatible with seasonal time-slicing databases. +# 'loop_seasons' +# Time slices sequence through seasons but loop from the end of each season back to its start. +# Time slices do not connect between seasons. Compatible with representative periods databases. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out in +# the schema). This is an advanced feature and not recommended for most users. +time_sequencing = 'loop_periods' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/data_files/my_configs/monte_carlo_utopia.toml b/data_files/my_configs/monte_carlo_utopia.toml index 263afb912..793b1538a 100644 --- a/data_files/my_configs/monte_carlo_utopia.toml +++ b/data_files/my_configs/monte_carlo_utopia.toml @@ -74,6 +74,23 @@ save_duals = true # save a copy of the pyomo-generated lp file(s) to the outputs folder (maybe a large file(s)!) save_lp_file = false +# ------------------------------------ +# MODEL PARAMETERS +# these are specific to each model +# ------------------------------------ + +# How to sequence time slices in the model. Options: +# 'loop_periods' +# Time slices sequence through seasons and between seasons, looping from the end of each +# period back to its start. Compatible with seasonal time-slicing databases. +# 'loop_seasons' +# Time slices sequence through seasons but loop from the end of each season back to its start. +# Time slices do not connect between seasons. Compatible with representative periods databases. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out in +# the schema). This is an advanced feature and not recommended for most users. +time_sequencing = 'loop_periods' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/data_files/my_configs/morris_utopia.toml b/data_files/my_configs/morris_utopia.toml index d9d64fa68..257cc70ba 100644 --- a/data_files/my_configs/morris_utopia.toml +++ b/data_files/my_configs/morris_utopia.toml @@ -71,6 +71,23 @@ save_duals = false # save a copy of the pyomo-generated lp file(s) to the outputs folder (maybe a large file(s)!) save_lp_file = false +# ------------------------------------ +# MODEL PARAMETERS +# these are specific to each model +# ------------------------------------ + +# How to sequence time slices in the model. Options: +# 'loop_periods' +# Time slices sequence through seasons and between seasons, looping from the end of each +# period back to its start. Compatible with seasonal time-slicing databases. +# 'loop_seasons' +# Time slices sequence through seasons but loop from the end of each season back to its start. +# Time slices do not connect between seasons. Compatible with representative periods databases. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out in +# the schema). This is an advanced feature and not recommended for most users. +time_sequencing = 'loop_periods' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/data_files/my_configs/stepped_demand.toml b/data_files/my_configs/stepped_demand.toml index fe401af28..122ee669b 100644 --- a/data_files/my_configs/stepped_demand.toml +++ b/data_files/my_configs/stepped_demand.toml @@ -71,6 +71,23 @@ save_duals = false # save a copy of the pyomo-generated lp file(s) to the outputs folder (maybe a large file(s)!) save_lp_file = false +# ------------------------------------ +# MODEL PARAMETERS +# these are specific to each model +# ------------------------------------ + +# How to sequence time slices in the model. Options: +# 'loop_periods' +# Time slices sequence through seasons and between seasons, looping from the end of each +# period back to its start. Compatible with seasonal time-slicing databases. +# 'loop_seasons' +# Time slices sequence through seasons but loop from the end of each season back to its start. +# Time slices do not connect between seasons. Compatible with representative periods databases. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out in +# the schema). This is an advanced feature and not recommended for most users. +time_sequencing = 'loop_periods' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index caecad42d..116e6c5ee 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -14,8 +14,6 @@ REPLACE INTO MetaData VALUES ('DB_MAJOR', 3, 'DB major version number'); REPLACE INTO MetaData VALUES ('DB_MINOR', 0, 'DB minor version number'); -REPLACE INTO MetaData -VALUES ('state_sequencing', 0, '0 = loop periods, 1 = loop seasons'); CREATE TABLE IF NOT EXISTS MetaDataReal ( diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index fdfda4468..e224ba607 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -426,32 +426,32 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N load_element(M.time_season_all, [('S',)]) # StateSequencing - raw = cur.execute("SELECT value from MetaData WHERE element == 'state_sequencing'").fetchall() - if raw: - seq = int(raw[0][0]) - data[M.StateSequencing.name] = {None: seq} - if seq == 2: - # TimeNext - # This is a hidden feature allowing the user to manually specify the sequence of states. + time_sequencing = self.config.time_sequencing + match time_sequencing: + case 'loop_periods' | 'loop_seasons': + pass + case 'manual': + # This is a hidden feature allowing the user to manually specify the sequence of states using the TimeNext table if self.table_exists("TimeNext"): raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT period, season, tod, season_next, tod_next FROM main.TimeNext') load_element(M.TimeNext, raw) else: - # Hidden feature unlocked! Give a nice long explanation + # Hidden feature unlocked but not setup! Give a nice long explanation msg = ( - 'Tried to manually sequence states (time slices) using TimeNext but the table did not exist. ' - 'With state_sequencing set to 2 in the MetaData table, the sequence of states will be pulled ' - 'directly from the TimeNext table, where each row defines the next state in the order. ' + 'Tried to manually sequence time slices using TimeNext but the table did not exist. ' + "With time_sequencing set to 'manual' in the config file, the sequence of time slices will be pulled " + 'directly from the TimeNext table, where each row defines the next time slice in the order. ' 'This is an advanced feature and not recommended for most users. If you do NOT want to ' - 'manually define the sequence of states, change the state_sequencing parameter. Otherwise ' - 'add the TimeNext table to the database with the following columns then fill it out: ' - '(period, season, tod, season_next, tod_next). The sql code can also be found commented ' - 'out in the v3.1 schema.' + 'manually define the sequence of time slices, change the time_sequencing parameter. Otherwise ' + 'the TimeNext table can be found commented out in the v3.1 schema.' ) logger.error(msg) raise ValueError(msg) - else: - logger.warning("state_sequencing parameter missing from MetaData table. By default, states will loop each period.") + case _: + msg = f"Invalid time sequencing parameter '{time_sequencing}'. Check the config file." + logger.error(msg) + raise ValueError(msg) + load_element(M.TimeSequencing, [(time_sequencing,)]) # myopic_base_year if mi: diff --git a/temoa/temoa_model/temoa_config.py b/temoa/temoa_model/temoa_config.py index eb0539bf3..98d2a51ff 100644 --- a/temoa/temoa_model/temoa_config.py +++ b/temoa/temoa_model/temoa_config.py @@ -47,6 +47,7 @@ def __init__( save_duals: bool = False, save_storage_levels: bool = False, save_lp_file: bool = False, + time_sequencing: str = None, MGA: dict | None = None, SVMGA: dict | None = None, myopic: dict | None = None, @@ -120,6 +121,7 @@ def __init__( self.save_duals = save_duals self.save_storage_levels = save_storage_levels self.save_lp_file = save_lp_file + self.time_sequencing = time_sequencing self.mga_inputs = MGA self.svmga_inputs = SVMGA @@ -193,6 +195,7 @@ def __repr__(self): msg += '{:>{}s}: {}\n'.format('Pyomo LP write status', width, self.save_lp_file) msg += '{:>{}s}: {}\n'.format('Save duals to output db', width, self.save_duals) msg += '{:>{}s}: {}\n'.format('Save storage to output db', width, self.save_storage_levels) + msg += '{:>{}s}: {}\n'.format('Time sequencing method', width, self.time_sequencing) if self.scenario_mode == TemoaMode.MYOPIC: msg += spacer diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index fb05d6a5e..875fdae7a 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -236,7 +236,7 @@ def validate_TimeNext(M: 'TemoaModel'): TimeSegmentFraction is already compared to other tables so just compare to SegFrac. """ # Only check TimeNext if it is actually being used - if M.StateSequencing != 2: + if M.TimeSequencing != 2: return segfrac_psd = set(M.SegFrac.sparse_iterkeys()) @@ -1064,31 +1064,33 @@ def CreateSparseDicts(M: 'TemoaModel'): logger.debug('Completed creation of SparseDicts') -def CreateStateSequence(M: 'TemoaModel'): +def CreateTimeSequence(M: 'TemoaModel'): # Establishing sequence of states - match M.StateSequencing: - case 0: + match M.TimeSequencing[1]: + case 'loop_periods': msg = 'Looping state each period, chaining between seasons.' for p in M.time_optimize: for s, d in M.time_season[p] * M.time_of_day: M.time_next[p, s, d] = loop_period_next_timeslice(M, p, s, d) - case 1: + case 'loop_seasons': msg = 'Looping state each season.' for p in M.time_optimize: for s, d in M.time_season[p] * M.time_of_day: M.time_next[p, s, d] = loop_season_next_timeslice(M, p, s, d) - case 2: + case 'manual': # Hidden feature. Define the sequence directly in the TimeNext table msg = 'Pulling state sequence from TimeNext table.' for p, s, d, s_next, d_next in M.TimeNext: M.time_next[p, s, d] = s_next, d_next + case _: + # This should have been caught in hybrid_loader + msg = f"Invalid time sequencing parameter loaded '{M.TimeSequencing[1]}'. Likely code error." + logger.error(msg) + raise ValueError(msg) - msg += (' This behaviour can be changed using the' - ' state_sequencing parameter in the MetaData table. ' - '0 = loop periods, ' - '1 = loop seasons, ' - '2 = define manually in TimeNext.') + msg += (' This behaviour can be changed using the ' + 'time_sequencing parameter in the config file. ') logger.info(msg) logger.debug('Created sequence of states.') diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 621637eb7..15a9f6c01 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -243,7 +243,7 @@ def __init__(M, *args, **kwargs): M.PeriodLength = Param(M.time_optimize, initialize=ParamPeriodLength) M.SegFrac = Param(M.time_optimize, M.time_season_all, M.time_of_day) M.validate_SegFrac = BuildAction(rule=validate_SegFrac) - M.StateSequencing = Param(default=0) # How do states carry between time segments? + M.TimeSequencing = Set() # How do states carry between time segments? M.TimeNext = Set() # This is just to get data from the table. Hidden feature and usually not used M.validate_TimeNext = BuildAction(rule=validate_TimeNext) @@ -341,7 +341,7 @@ def __init__(M, *args, **kwargs): # perform the sparse matrix of indexing for the parameters, variables, and # equations below. M.Create_SparseDicts = BuildAction(rule=CreateSparseDicts) - M.Create_StateSequence = BuildAction(rule=CreateStateSequence) + M.Create_StateSequence = BuildAction(rule=CreateTimeSequence) M.CapacityFactor_rpsdt = Set(dimen=5, initialize=CapacityFactorTechIndices) M.CapacityFactorTech = Param(M.CapacityFactor_rpsdt, default=1, validate=validate_0to1) diff --git a/tests/testing_configs/config_emissions.toml b/tests/testing_configs/config_emissions.toml index ae37576d3..638b5ee3f 100644 --- a/tests/testing_configs/config_emissions.toml +++ b/tests/testing_configs/config_emissions.toml @@ -18,6 +18,23 @@ save_duals = false # save a copy of the pyomo-generated lp file to the outputs folder (may be large file!) save_lp_file = false +# ------------------------------------ +# MODEL PARAMETERS +# these are specific to each model +# ------------------------------------ + +# How to sequence time slices in the model. Options: +# 'loop_periods' +# Time slices sequence through seasons and between seasons, looping from the end of each +# period back to its start. Compatible with seasonal time-slicing databases. +# 'loop_seasons' +# Time slices sequence through seasons but loop from the end of each season back to its start. +# Time slices do not connect between seasons. Compatible with representative periods databases. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out in +# the schema). This is an advanced feature and not recommended for most users. +time_sequencing = 'loop_periods' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/tests/testing_configs/config_link_test.toml b/tests/testing_configs/config_link_test.toml index 2c5e1ec37..749cc7375 100644 --- a/tests/testing_configs/config_link_test.toml +++ b/tests/testing_configs/config_link_test.toml @@ -71,6 +71,23 @@ save_duals = false # save a copy of the pyomo-generated lp file(s) to the outputs folder (maybe a large file(s)!) save_lp_file = false +# ------------------------------------ +# MODEL PARAMETERS +# these are specific to each model +# ------------------------------------ + +# How to sequence time slices in the model. Options: +# 'loop_periods' +# Time slices sequence through seasons and between seasons, looping from the end of each +# period back to its start. Compatible with seasonal time-slicing databases. +# 'loop_seasons' +# Time slices sequence through seasons but loop from the end of each season back to its start. +# Time slices do not connect between seasons. Compatible with representative periods databases. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out in +# the schema). This is an advanced feature and not recommended for most users. +time_sequencing = 'loop_periods' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/tests/testing_configs/config_materials.toml b/tests/testing_configs/config_materials.toml index b21821b82..7af903bdd 100644 --- a/tests/testing_configs/config_materials.toml +++ b/tests/testing_configs/config_materials.toml @@ -18,6 +18,23 @@ save_duals = false # save a copy of the pyomo-generated lp file to the outputs folder (may be large file!) save_lp_file = false +# ------------------------------------ +# MODEL PARAMETERS +# these are specific to each model +# ------------------------------------ + +# How to sequence time slices in the model. Options: +# 'loop_periods' +# Time slices sequence through seasons and between seasons, looping from the end of each +# period back to its start. Compatible with seasonal time-slicing databases. +# 'loop_seasons' +# Time slices sequence through seasons but loop from the end of each season back to its start. +# Time slices do not connect between seasons. Compatible with representative periods databases. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out in +# the schema). This is an advanced feature and not recommended for most users. +time_sequencing = 'loop_periods' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/tests/testing_configs/config_mediumville.toml b/tests/testing_configs/config_mediumville.toml index 3b677ece3..937f157c9 100644 --- a/tests/testing_configs/config_mediumville.toml +++ b/tests/testing_configs/config_mediumville.toml @@ -52,6 +52,23 @@ save_duals = false # save a copy of the pyomo-generated lp file to the outputs folder (may be large file!) save_lp_file = false +# ------------------------------------ +# MODEL PARAMETERS +# these are specific to each model +# ------------------------------------ + +# How to sequence time slices in the model. Options: +# 'loop_periods' +# Time slices sequence through seasons and between seasons, looping from the end of each +# period back to its start. Compatible with seasonal time-slicing databases. +# 'loop_seasons' +# Time slices sequence through seasons but loop from the end of each season back to its start. +# Time slices do not connect between seasons. Compatible with representative periods databases. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out in +# the schema). This is an advanced feature and not recommended for most users. +time_sequencing = 'loop_periods' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/tests/testing_configs/config_storageville.toml b/tests/testing_configs/config_storageville.toml index 6bfb3986e..dee493ba6 100644 --- a/tests/testing_configs/config_storageville.toml +++ b/tests/testing_configs/config_storageville.toml @@ -52,6 +52,23 @@ save_duals = false # save a copy of the pyomo-generated lp file to the outputs folder (may be large file!) save_lp_file = false +# ------------------------------------ +# MODEL PARAMETERS +# these are specific to each model +# ------------------------------------ + +# How to sequence time slices in the model. Options: +# 'loop_periods' +# Time slices sequence through seasons and between seasons, looping from the end of each +# period back to its start. Compatible with seasonal time-slicing databases. +# 'loop_seasons' +# Time slices sequence through seasons but loop from the end of each season back to its start. +# Time slices do not connect between seasons. Compatible with representative periods databases. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out in +# the schema). This is an advanced feature and not recommended for most users. +time_sequencing = 'loop_periods' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/tests/testing_configs/config_test_system.toml b/tests/testing_configs/config_test_system.toml index 10c504964..89e27d997 100644 --- a/tests/testing_configs/config_test_system.toml +++ b/tests/testing_configs/config_test_system.toml @@ -18,6 +18,23 @@ save_duals = false # save a copy of the pyomo-generated lp file to the outputs folder (may be large file!) save_lp_file = false +# ------------------------------------ +# MODEL PARAMETERS +# these are specific to each model +# ------------------------------------ + +# How to sequence time slices in the model. Options: +# 'loop_periods' +# Time slices sequence through seasons and between seasons, looping from the end of each +# period back to its start. Compatible with seasonal time-slicing databases. +# 'loop_seasons' +# Time slices sequence through seasons but loop from the end of each season back to its start. +# Time slices do not connect between seasons. Compatible with representative periods databases. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out in +# the schema). This is an advanced feature and not recommended for most users. +time_sequencing = 'loop_periods' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/tests/testing_configs/config_utopia.toml b/tests/testing_configs/config_utopia.toml index 58ef1d25f..91c5646e6 100644 --- a/tests/testing_configs/config_utopia.toml +++ b/tests/testing_configs/config_utopia.toml @@ -18,6 +18,23 @@ save_duals = false # save a copy of the pyomo-generated lp file to the outputs folder (may be large file!) save_lp_file = false +# ------------------------------------ +# MODEL PARAMETERS +# these are specific to each model +# ------------------------------------ + +# How to sequence time slices in the model. Options: +# 'loop_periods' +# Time slices sequence through seasons and between seasons, looping from the end of each +# period back to its start. Compatible with seasonal time-slicing databases. +# 'loop_seasons' +# Time slices sequence through seasons but loop from the end of each season back to its start. +# Time slices do not connect between seasons. Compatible with representative periods databases. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out in +# the schema). This is an advanced feature and not recommended for most users. +time_sequencing = 'loop_periods' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/tests/testing_configs/config_utopia_myopic.toml b/tests/testing_configs/config_utopia_myopic.toml index 89f198fe0..a1b82931a 100644 --- a/tests/testing_configs/config_utopia_myopic.toml +++ b/tests/testing_configs/config_utopia_myopic.toml @@ -18,7 +18,24 @@ save_excel = true save_duals = true # save a copy of the pyomo-generated lp file to the outputs folder (may be large file!) -save_lp_file = true +save_lp_file = false + +# ------------------------------------ +# MODEL PARAMETERS +# these are specific to each model +# ------------------------------------ + +# How to sequence time slices in the model. Options: +# 'loop_periods' +# Time slices sequence through seasons and between seasons, looping from the end of each +# period back to its start. Compatible with seasonal time-slicing databases. +# 'loop_seasons' +# Time slices sequence through seasons but loop from the end of each season back to its start. +# Time slices do not connect between seasons. Compatible with representative periods databases. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out in +# the schema). This is an advanced feature and not recommended for most users. +time_sequencing = 'loop_periods' # --------------------------------------------------- # MODE OPTIONS diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 414aa5807..2f7462c40 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -10,8 +10,6 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES('link_seasons',1,'Carry storage states between seasons'); -INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); CREATE TABLE MetaDataReal ( element TEXT, diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index 8dafbf3c6..3140295bf 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -10,8 +10,6 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES('link_seasons',1,'Carry storage states between seasons'); -INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); CREATE TABLE MetaDataReal ( element TEXT, diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 874941a19..885c9e561 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -10,8 +10,6 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES('myopic_base_year',2000,''); -INSERT INTO MetaData VALUES('link_seasons',1,'Carry storage states between seasons'); -INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); CREATE TABLE MetaDataReal ( element TEXT, diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 3a018febd..3f03af9f8 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -4326,6 +4326,9 @@ "s1", "s2" ], + "TimeSequencing": [ + "loop_periods" + ], "vintage_all": [ 2025, 2020 diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index 9994d7a3d..cac3613d9 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -10,8 +10,6 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES('myopic_base_year',1990,''); -INSERT INTO MetaData VALUES('link_seasons',1,'Carry storage states between seasons'); -INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); CREATE TABLE MetaDataReal ( element TEXT, diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index 3e8b2ab01..fe5c8f73c 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -10,8 +10,6 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES('myopic_base_year',2000,''); -INSERT INTO MetaData VALUES('link_seasons',1,'Carry storage states between seasons'); -INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); CREATE TABLE MetaDataReal ( element TEXT, diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 122cfac17..8994fa8bd 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -10,8 +10,6 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES('link_seasons',1,'Carry storage states between seasons'); -INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); CREATE TABLE MetaDataReal ( element TEXT, diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index a775e5465..02e3b5d0a 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -46996,6 +46996,9 @@ "spring", "winter" ], + "TimeSequencing": [ + "loop_periods" + ], "vintage_all": [ 2025, 2020, diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 7cacd5e6a..38cf05bca 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -10,7 +10,6 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('myopic_base_year',1990,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES('state_sequencing',0,'0 = loop periods, 1 = loop seasons'); CREATE TABLE MetaDataReal ( element TEXT, diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index b74d28e57..f8098ee3c 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -25913,6 +25913,9 @@ "inter", "winter" ], + "TimeSequencing": [ + "loop_periods" + ], "vintage_all": [ 1990, 1960, From bec5310d14906dc770281352efa67af1e832de6f Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 12 Jun 2025 12:11:49 -0400 Subject: [PATCH 102/587] Change naming scheme for time sequencing --- data_files/my_configs/config_sample.toml | 18 +++++++++++++++--- data_files/my_configs/mga_utopia.toml | 6 +++--- data_files/my_configs/monte_carlo_utopia.toml | 6 +++--- data_files/my_configs/morris_utopia.toml | 6 +++--- data_files/my_configs/stepped_demand.toml | 6 +++--- temoa/temoa_model/hybrid_loader.py | 2 +- temoa/temoa_model/temoa_initialize.py | 8 ++++---- tests/testing_configs/config_emissions.toml | 6 +++--- tests/testing_configs/config_link_test.toml | 6 +++--- tests/testing_configs/config_materials.toml | 6 +++--- tests/testing_configs/config_mediumville.toml | 6 +++--- tests/testing_configs/config_storageville.toml | 6 +++--- tests/testing_configs/config_test_system.toml | 6 +++--- tests/testing_configs/config_utopia.toml | 6 +++--- .../testing_configs/config_utopia_myopic.toml | 6 +++--- 15 files changed, 56 insertions(+), 44 deletions(-) diff --git a/data_files/my_configs/config_sample.toml b/data_files/my_configs/config_sample.toml index d3bd6322c..87602f31a 100644 --- a/data_files/my_configs/config_sample.toml +++ b/data_files/my_configs/config_sample.toml @@ -83,16 +83,28 @@ save_lp_file = false # ------------------------------------ # How to sequence time slices in the model. Options: -# 'loop_periods' +# 'seasonal_timeslicing' # Time slices sequence through seasons and between seasons, looping from the end of each # period back to its start. Compatible with seasonal time-slicing databases. -# 'loop_seasons' +# 'representative_periods' # Time slices sequence through seasons but loop from the end of each season back to its start. # Time slices do not connect between seasons. Compatible with representative periods databases. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out in # the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'loop_periods' +time_sequencing = 'seasonal_timeslicing' + +# How contributions to the planning reserve margin are calculated. Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit +reserve_margin = 'static' # --------------------------------------------------- # MODE OPTIONS diff --git a/data_files/my_configs/mga_utopia.toml b/data_files/my_configs/mga_utopia.toml index 524df743e..fc6bd0e1e 100644 --- a/data_files/my_configs/mga_utopia.toml +++ b/data_files/my_configs/mga_utopia.toml @@ -77,16 +77,16 @@ save_lp_file = false # ------------------------------------ # How to sequence time slices in the model. Options: -# 'loop_periods' +# 'seasonal_timeslicing' # Time slices sequence through seasons and between seasons, looping from the end of each # period back to its start. Compatible with seasonal time-slicing databases. -# 'loop_seasons' +# 'representative_periods' # Time slices sequence through seasons but loop from the end of each season back to its start. # Time slices do not connect between seasons. Compatible with representative periods databases. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out in # the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'loop_periods' +time_sequencing = 'seasonal_timeslicing' # --------------------------------------------------- # MODE OPTIONS diff --git a/data_files/my_configs/monte_carlo_utopia.toml b/data_files/my_configs/monte_carlo_utopia.toml index 793b1538a..2e021ed55 100644 --- a/data_files/my_configs/monte_carlo_utopia.toml +++ b/data_files/my_configs/monte_carlo_utopia.toml @@ -80,16 +80,16 @@ save_lp_file = false # ------------------------------------ # How to sequence time slices in the model. Options: -# 'loop_periods' +# 'seasonal_timeslicing' # Time slices sequence through seasons and between seasons, looping from the end of each # period back to its start. Compatible with seasonal time-slicing databases. -# 'loop_seasons' +# 'representative_periods' # Time slices sequence through seasons but loop from the end of each season back to its start. # Time slices do not connect between seasons. Compatible with representative periods databases. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out in # the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'loop_periods' +time_sequencing = 'seasonal_timeslicing' # --------------------------------------------------- # MODE OPTIONS diff --git a/data_files/my_configs/morris_utopia.toml b/data_files/my_configs/morris_utopia.toml index 257cc70ba..abf97ba0e 100644 --- a/data_files/my_configs/morris_utopia.toml +++ b/data_files/my_configs/morris_utopia.toml @@ -77,16 +77,16 @@ save_lp_file = false # ------------------------------------ # How to sequence time slices in the model. Options: -# 'loop_periods' +# 'seasonal_timeslicing' # Time slices sequence through seasons and between seasons, looping from the end of each # period back to its start. Compatible with seasonal time-slicing databases. -# 'loop_seasons' +# 'representative_periods' # Time slices sequence through seasons but loop from the end of each season back to its start. # Time slices do not connect between seasons. Compatible with representative periods databases. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out in # the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'loop_periods' +time_sequencing = 'seasonal_timeslicing' # --------------------------------------------------- # MODE OPTIONS diff --git a/data_files/my_configs/stepped_demand.toml b/data_files/my_configs/stepped_demand.toml index 122ee669b..f4ebfcf83 100644 --- a/data_files/my_configs/stepped_demand.toml +++ b/data_files/my_configs/stepped_demand.toml @@ -77,16 +77,16 @@ save_lp_file = false # ------------------------------------ # How to sequence time slices in the model. Options: -# 'loop_periods' +# 'seasonal_timeslicing' # Time slices sequence through seasons and between seasons, looping from the end of each # period back to its start. Compatible with seasonal time-slicing databases. -# 'loop_seasons' +# 'representative_periods' # Time slices sequence through seasons but loop from the end of each season back to its start. # Time slices do not connect between seasons. Compatible with representative periods databases. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out in # the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'loop_periods' +time_sequencing = 'seasonal_timeslicing' # --------------------------------------------------- # MODE OPTIONS diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index e224ba607..3f8b96c9b 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -428,7 +428,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # StateSequencing time_sequencing = self.config.time_sequencing match time_sequencing: - case 'loop_periods' | 'loop_seasons': + case 'seasonal_timeslicing' | 'representative_periods': pass case 'manual': # This is a hidden feature allowing the user to manually specify the sequence of states using the TimeNext table diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 875fdae7a..22f895e0b 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1068,13 +1068,13 @@ def CreateTimeSequence(M: 'TemoaModel'): # Establishing sequence of states match M.TimeSequencing[1]: - case 'loop_periods': - msg = 'Looping state each period, chaining between seasons.' + case 'seasonal_timeslicing': + msg = 'Running a season time slicing database, looping state each period, chaining between seasons.' for p in M.time_optimize: for s, d in M.time_season[p] * M.time_of_day: M.time_next[p, s, d] = loop_period_next_timeslice(M, p, s, d) - case 'loop_seasons': - msg = 'Looping state each season.' + case 'representative_periods': + msg = 'Running a representative periods database, looping state each season.' for p in M.time_optimize: for s, d in M.time_season[p] * M.time_of_day: M.time_next[p, s, d] = loop_season_next_timeslice(M, p, s, d) diff --git a/tests/testing_configs/config_emissions.toml b/tests/testing_configs/config_emissions.toml index 638b5ee3f..1b5354e2f 100644 --- a/tests/testing_configs/config_emissions.toml +++ b/tests/testing_configs/config_emissions.toml @@ -24,16 +24,16 @@ save_lp_file = false # ------------------------------------ # How to sequence time slices in the model. Options: -# 'loop_periods' +# 'seasonal_timeslicing' # Time slices sequence through seasons and between seasons, looping from the end of each # period back to its start. Compatible with seasonal time-slicing databases. -# 'loop_seasons' +# 'representative_periods' # Time slices sequence through seasons but loop from the end of each season back to its start. # Time slices do not connect between seasons. Compatible with representative periods databases. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out in # the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'loop_periods' +time_sequencing = 'seasonal_timeslicing' # --------------------------------------------------- # MODE OPTIONS diff --git a/tests/testing_configs/config_link_test.toml b/tests/testing_configs/config_link_test.toml index 749cc7375..c5324ba1a 100644 --- a/tests/testing_configs/config_link_test.toml +++ b/tests/testing_configs/config_link_test.toml @@ -77,16 +77,16 @@ save_lp_file = false # ------------------------------------ # How to sequence time slices in the model. Options: -# 'loop_periods' +# 'seasonal_timeslicing' # Time slices sequence through seasons and between seasons, looping from the end of each # period back to its start. Compatible with seasonal time-slicing databases. -# 'loop_seasons' +# 'representative_periods' # Time slices sequence through seasons but loop from the end of each season back to its start. # Time slices do not connect between seasons. Compatible with representative periods databases. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out in # the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'loop_periods' +time_sequencing = 'seasonal_timeslicing' # --------------------------------------------------- # MODE OPTIONS diff --git a/tests/testing_configs/config_materials.toml b/tests/testing_configs/config_materials.toml index 7af903bdd..958b91aa2 100644 --- a/tests/testing_configs/config_materials.toml +++ b/tests/testing_configs/config_materials.toml @@ -24,16 +24,16 @@ save_lp_file = false # ------------------------------------ # How to sequence time slices in the model. Options: -# 'loop_periods' +# 'seasonal_timeslicing' # Time slices sequence through seasons and between seasons, looping from the end of each # period back to its start. Compatible with seasonal time-slicing databases. -# 'loop_seasons' +# 'representative_periods' # Time slices sequence through seasons but loop from the end of each season back to its start. # Time slices do not connect between seasons. Compatible with representative periods databases. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out in # the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'loop_periods' +time_sequencing = 'seasonal_timeslicing' # --------------------------------------------------- # MODE OPTIONS diff --git a/tests/testing_configs/config_mediumville.toml b/tests/testing_configs/config_mediumville.toml index 937f157c9..eebf08312 100644 --- a/tests/testing_configs/config_mediumville.toml +++ b/tests/testing_configs/config_mediumville.toml @@ -58,16 +58,16 @@ save_lp_file = false # ------------------------------------ # How to sequence time slices in the model. Options: -# 'loop_periods' +# 'seasonal_timeslicing' # Time slices sequence through seasons and between seasons, looping from the end of each # period back to its start. Compatible with seasonal time-slicing databases. -# 'loop_seasons' +# 'representative_periods' # Time slices sequence through seasons but loop from the end of each season back to its start. # Time slices do not connect between seasons. Compatible with representative periods databases. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out in # the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'loop_periods' +time_sequencing = 'seasonal_timeslicing' # --------------------------------------------------- # MODE OPTIONS diff --git a/tests/testing_configs/config_storageville.toml b/tests/testing_configs/config_storageville.toml index dee493ba6..489108ed3 100644 --- a/tests/testing_configs/config_storageville.toml +++ b/tests/testing_configs/config_storageville.toml @@ -58,16 +58,16 @@ save_lp_file = false # ------------------------------------ # How to sequence time slices in the model. Options: -# 'loop_periods' +# 'seasonal_timeslicing' # Time slices sequence through seasons and between seasons, looping from the end of each # period back to its start. Compatible with seasonal time-slicing databases. -# 'loop_seasons' +# 'representative_periods' # Time slices sequence through seasons but loop from the end of each season back to its start. # Time slices do not connect between seasons. Compatible with representative periods databases. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out in # the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'loop_periods' +time_sequencing = 'seasonal_timeslicing' # --------------------------------------------------- # MODE OPTIONS diff --git a/tests/testing_configs/config_test_system.toml b/tests/testing_configs/config_test_system.toml index 89e27d997..796c314fa 100644 --- a/tests/testing_configs/config_test_system.toml +++ b/tests/testing_configs/config_test_system.toml @@ -24,16 +24,16 @@ save_lp_file = false # ------------------------------------ # How to sequence time slices in the model. Options: -# 'loop_periods' +# 'seasonal_timeslicing' # Time slices sequence through seasons and between seasons, looping from the end of each # period back to its start. Compatible with seasonal time-slicing databases. -# 'loop_seasons' +# 'representative_periods' # Time slices sequence through seasons but loop from the end of each season back to its start. # Time slices do not connect between seasons. Compatible with representative periods databases. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out in # the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'loop_periods' +time_sequencing = 'seasonal_timeslicing' # --------------------------------------------------- # MODE OPTIONS diff --git a/tests/testing_configs/config_utopia.toml b/tests/testing_configs/config_utopia.toml index 91c5646e6..281ec827f 100644 --- a/tests/testing_configs/config_utopia.toml +++ b/tests/testing_configs/config_utopia.toml @@ -24,16 +24,16 @@ save_lp_file = false # ------------------------------------ # How to sequence time slices in the model. Options: -# 'loop_periods' +# 'seasonal_timeslicing' # Time slices sequence through seasons and between seasons, looping from the end of each # period back to its start. Compatible with seasonal time-slicing databases. -# 'loop_seasons' +# 'representative_periods' # Time slices sequence through seasons but loop from the end of each season back to its start. # Time slices do not connect between seasons. Compatible with representative periods databases. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out in # the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'loop_periods' +time_sequencing = 'seasonal_timeslicing' # --------------------------------------------------- # MODE OPTIONS diff --git a/tests/testing_configs/config_utopia_myopic.toml b/tests/testing_configs/config_utopia_myopic.toml index a1b82931a..887389b28 100644 --- a/tests/testing_configs/config_utopia_myopic.toml +++ b/tests/testing_configs/config_utopia_myopic.toml @@ -26,16 +26,16 @@ save_lp_file = false # ------------------------------------ # How to sequence time slices in the model. Options: -# 'loop_periods' +# 'seasonal_timeslicing' # Time slices sequence through seasons and between seasons, looping from the end of each # period back to its start. Compatible with seasonal time-slicing databases. -# 'loop_seasons' +# 'representative_periods' # Time slices sequence through seasons but loop from the end of each season back to its start. # Time slices do not connect between seasons. Compatible with representative periods databases. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out in # the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'loop_periods' +time_sequencing = 'seasonal_timeslicing' # --------------------------------------------------- # MODE OPTIONS From 792c441ec7eca72fc79194ce0548af195438f6a6 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 12 Jun 2025 12:48:33 -0400 Subject: [PATCH 103/587] Add optional dynamic reserve margin activated in config file --- data_files/my_configs/mga_utopia.toml | 12 + data_files/my_configs/monte_carlo_utopia.toml | 12 + data_files/my_configs/morris_utopia.toml | 12 + data_files/my_configs/stepped_demand.toml | 12 + temoa/temoa_model/hybrid_loader.py | 6 +- temoa/temoa_model/temoa_config.py | 5 +- temoa/temoa_model/temoa_initialize.py | 3 +- temoa/temoa_model/temoa_model.py | 3 +- temoa/temoa_model/temoa_rules.py | 185 +++++++---- tests/testing_configs/config_emissions.toml | 12 + tests/testing_configs/config_link_test.toml | 12 + tests/testing_configs/config_materials.toml | 12 + tests/testing_configs/config_mediumville.toml | 12 + .../testing_configs/config_storageville.toml | 12 + tests/testing_configs/config_test_system.toml | 12 + tests/testing_configs/config_utopia.toml | 12 + .../testing_configs/config_utopia_myopic.toml | 12 + tests/testing_data/mediumville_sets.json | 33 +- tests/testing_data/test_system_sets.json | 294 +----------------- tests/testing_data/utopia_sets.json | 114 +------ 20 files changed, 304 insertions(+), 483 deletions(-) diff --git a/data_files/my_configs/mga_utopia.toml b/data_files/my_configs/mga_utopia.toml index fc6bd0e1e..79fc5248f 100644 --- a/data_files/my_configs/mga_utopia.toml +++ b/data_files/my_configs/mga_utopia.toml @@ -88,6 +88,18 @@ save_lp_file = false # the schema). This is an advanced feature and not recommended for most users. time_sequencing = 'seasonal_timeslicing' +# How contributions to the planning reserve margin are calculated. Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit +reserve_margin = 'static' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/data_files/my_configs/monte_carlo_utopia.toml b/data_files/my_configs/monte_carlo_utopia.toml index 2e021ed55..15e745149 100644 --- a/data_files/my_configs/monte_carlo_utopia.toml +++ b/data_files/my_configs/monte_carlo_utopia.toml @@ -91,6 +91,18 @@ save_lp_file = false # the schema). This is an advanced feature and not recommended for most users. time_sequencing = 'seasonal_timeslicing' +# How contributions to the planning reserve margin are calculated. Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit +reserve_margin = 'static' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/data_files/my_configs/morris_utopia.toml b/data_files/my_configs/morris_utopia.toml index abf97ba0e..d6f617d71 100644 --- a/data_files/my_configs/morris_utopia.toml +++ b/data_files/my_configs/morris_utopia.toml @@ -88,6 +88,18 @@ save_lp_file = false # the schema). This is an advanced feature and not recommended for most users. time_sequencing = 'seasonal_timeslicing' +# How contributions to the planning reserve margin are calculated. Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit +reserve_margin = 'static' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/data_files/my_configs/stepped_demand.toml b/data_files/my_configs/stepped_demand.toml index f4ebfcf83..49253a586 100644 --- a/data_files/my_configs/stepped_demand.toml +++ b/data_files/my_configs/stepped_demand.toml @@ -88,6 +88,18 @@ save_lp_file = false # the schema). This is an advanced feature and not recommended for most users. time_sequencing = 'seasonal_timeslicing' +# How contributions to the planning reserve margin are calculated. Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit +reserve_margin = 'static' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 3f8b96c9b..d932fa4f8 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -425,7 +425,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N logger.warning('No PeriodSeasons table found. Loading a single filler season "S" (assume this is an annual model)') load_element(M.time_season_all, [('S',)]) - # StateSequencing + # TimeSequencing time_sequencing = self.config.time_sequencing match time_sequencing: case 'seasonal_timeslicing' | 'representative_periods': @@ -453,6 +453,10 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N raise ValueError(msg) load_element(M.TimeSequencing, [(time_sequencing,)]) + # ReserveMargin + # This is the method for calculating contributions + load_element(M.ReserveMargin, [(self.config.reserve_margin,)]) + # myopic_base_year if mi: raw = cur.execute( diff --git a/temoa/temoa_model/temoa_config.py b/temoa/temoa_model/temoa_config.py index 98d2a51ff..21b5e393c 100644 --- a/temoa/temoa_model/temoa_config.py +++ b/temoa/temoa_model/temoa_config.py @@ -48,6 +48,7 @@ def __init__( save_storage_levels: bool = False, save_lp_file: bool = False, time_sequencing: str = None, + reserve_margin: str = None, MGA: dict | None = None, SVMGA: dict | None = None, myopic: dict | None = None, @@ -122,6 +123,7 @@ def __init__( self.save_storage_levels = save_storage_levels self.save_lp_file = save_lp_file self.time_sequencing = time_sequencing + self.reserve_margin = reserve_margin self.mga_inputs = MGA self.svmga_inputs = SVMGA @@ -195,7 +197,8 @@ def __repr__(self): msg += '{:>{}s}: {}\n'.format('Pyomo LP write status', width, self.save_lp_file) msg += '{:>{}s}: {}\n'.format('Save duals to output db', width, self.save_duals) msg += '{:>{}s}: {}\n'.format('Save storage to output db', width, self.save_storage_levels) - msg += '{:>{}s}: {}\n'.format('Time sequencing method', width, self.time_sequencing) + msg += '{:>{}s}: {}\n'.format('Time sequencing', width, self.time_sequencing) + msg += '{:>{}s}: {}\n'.format('Planning reserve margin', width, self.reserve_margin) if self.scenario_mode == TemoaMode.MYOPIC: msg += spacer diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 22f895e0b..795026321 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1518,11 +1518,12 @@ def RampDownConstraintIndices(M: 'TemoaModel'): def ReserveMarginIndices(M: 'TemoaModel'): indices = set( (r, p, s, d) - for r in M.regions + for r in M.PlanningReserveMargin for p in M.time_optimize for s in M.time_season[p] for d in M.time_of_day ) + return indices diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 15a9f6c01..4da8236fd 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -482,10 +482,11 @@ def __init__(M, *args, **kwargs): M.RampUp = Param(M.regions, M.tech_upramping, validate=validate_0to1) M.RampDown = Param(M.regions, M.tech_downramping, validate=validate_0to1) + M.ReserveMargin = Set() # How contributions to the reserve margin are calculated M.CapacityCredit = Param( M.regionalIndices, M.time_optimize, M.tech_all, M.vintage_all, default=0, validate=validate_0to1 ) - M.PlanningReserveMargin = Param(M.regions, default=0.2) + M.PlanningReserveMargin = Param(M.regions) M.EmissionEmbodied = Param(M.regions, M.commodity_emissions, M.tech_with_capacity, M.vintage_optimize) M.EmissionEndOfLife = Param(M.regions, M.commodity_emissions, M.tech_with_capacity, M.vintage_all) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 155c4a98b..35e236e81 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1627,6 +1627,71 @@ def RampDown_Constraint(M: 'TemoaModel', r, p, s, d, t, v): def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): + + # Get available generation in this time slice depending on method specified in config file + match M.ReserveMargin[1]: + case 'static': + available = ReserveMarginStatic(M, r, p, s, d) + case 'dynamic': + available = ReserveMarginDynamic(M, r, p, s, d) + case _: + msg = f"Invalid reserve margin parameter '{M.ReserveMargin[1]}'. Check the config file." + logger.error(msg) + raise ValueError(msg) + + # In most Temoa input databases, demand is endogenous, so we use electricity + # generation instead as a proxy for electricity demand. + total_generation = sum( + M.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] + for (t, S_v) in M.processReservePeriods[r, p] + for S_i in M.processInputs[r, p, t, S_v] + for S_o in M.processOutputsByInput[r, p, t, S_v, S_i] + ) + + # We must take into account flows into storage technologies. + # Flows into storage technologies need to be subtracted from the + # load calculation. + total_generation -= sum( + M.V_FlowIn[r, p, s, d, S_i, t, S_v, S_o] + for (t, S_v) in M.processReservePeriods[r, p] + if t in M.tech_storage + for S_i in M.processInputs[r, p, t, S_v] + for S_o in M.processOutputsByInput[r, p, t, S_v, S_i] + ) + + # Electricity imports and exports via exchange techs are accounted + # for below: + for r1r2 in M.regionalIndices: # ensure the region is of the form r1-r2 + if '-' not in r1r2: + continue + if (r1r2, p) not in M.processReservePeriods: # ensure r1r2 is a valid reserve provider in p + continue + r1, r2 = r1r2.split('-') + # First, determine the exports, and subtract this value from the + # total generation. + if r1 == r: + total_generation -= sum( + M.V_FlowOut[r1r2, p, s, d, S_i, t, S_v, S_o] + / get_variable_efficiency(M, r1r2, p, s, d, S_i, t, S_v, S_o) + for (t, S_v) in M.processReservePeriods[r1r2, p] + for S_i in M.processInputs[r1r2, p, t, S_v] + for S_o in M.processOutputsByInput[r1r2, p, t, S_v, S_i] + ) + # Second, determine the imports, and add this value from the + # total generation. + elif r2 == r: + total_generation += sum( + M.V_FlowOut[r1r2, p, s, d, S_i, t, S_v, S_o] + for (t, S_v) in M.processReservePeriods[r1r2, p] + for S_i in M.processInputs[r1r2, p, t, S_v] + for S_o in M.processOutputsByInput[r1r2, p, t, S_v, S_i] + ) + + requirement = total_generation * (1 + value(M.PlanningReserveMargin[r])) + return available >= requirement + + +def ReserveMarginStatic(M: 'TemoaModel', r, p, s, d): r""" During each period :math:`p`, the sum of the available capacity of all reserve @@ -1654,17 +1719,14 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): ): # If reserve set empty or if r,p not in M.processReservePeriod, skip the constraint return Constraint.Skip - cap_avail = sum( + available = sum( value(M.CapacityCredit[r, p, t, v]) * value(M.ProcessLifeFrac[r, p, t, v]) * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[p, s, d]) - for t in M.tech_reserve - if (r, p, t) in M.processVintages - for v in M.processVintages[r, p, t] - # Make sure (r,p,t,v) combinations are defined - if (r, p, t, v) in M.activeCapacityAvailable_rptv + for (t, v) in M.processReservePeriods[r, p] + if t not in M.tech_uncap ) # The above code does not consider exchange techs, e.g. electricity @@ -1678,6 +1740,8 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): for r1r2 in M.regionalIndices: if '-' not in r1r2: continue + if (r1r2, p) not in M.processReservePeriods: # ensure r1r2 is a valid reserve provider in p + continue r1, r2 = r1r2.split('-') # Only consider the capacity of technologies that import to @@ -1686,70 +1750,87 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): continue # add the available capacity of the exchange tech. - cap_avail += sum( + available += sum( value(M.CapacityCredit[r1r2, p, t, v]) * value(M.ProcessLifeFrac[r1r2, p, t, v]) * M.V_Capacity[r1r2, p, t, v] * value(M.CapacityToActivity[r1r2, t]) * value(M.SegFrac[p, s, d]) + for (t, v) in M.processReservePeriods[r1r2, p] for t in M.tech_reserve - if (r1r2, p, t) in M.processVintages - for v in M.processVintages[r1r2, p, t] - # Make sure (r,p,t,v) combinations are defined - if (r1r2, p, t, v) in M.activeCapacityAvailable_rptv ) - # In most Temoa input databases, demand is endogenous, so we use electricity - # generation instead as a proxy for electricity demand. - total_generation = sum( - M.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] - for (t, S_v) in M.processReservePeriods[r, p] - for S_i in M.processInputs[r, p, t, S_v] - for S_o in M.processOutputsByInput[r, p, t, S_v, S_i] + return available + + +def ReserveMarginDynamic(M: 'TemoaModel', r, p, s, d): + r""" + A dynamic alternative to the traditional, static reserve margin constraint. Capacity values + are calculated from availability of generation in each hour, like an operating reserve margin, + accounting for a capacity derate factor representing the forced outage rate. + """ + if (not M.tech_reserve) or ( + (r, p) not in M.processReservePeriods + ): # If reserve set empty or if r,p not in M.processReservePeriod, skip the constraint + return Constraint.Skip + + # Everything but storage and exchange techs + # Derated available generation + available = sum( + M.V_Capacity[r, p, t, v] + * value(M.CapacityCredit[r, p, t, v]) + * value(M.ProcessLifeFrac[r, p, t, v]) + * value(M.CapacityFactorProcess[r, p, s, d, t, v]) + * value(M.CapacityToActivity[r, t]) + * value(M.SegFrac[p, s, d]) + for (t, v) in M.processReservePeriods[r, p] + if t not in M.tech_uncap and t not in M.tech_storage ) - # We must take into account flows into storage technologies. - # Flows into storage technologies need to be subtracted from the - # load calculation. - total_generation -= sum( - M.V_FlowIn[r, p, s, d, S_i, t, S_v, S_o] - for (t, S_v) in M.processReservePeriods[r, p] + # Storage (not exchange) + # Derated output flow (discharge) + available += sum( + M.V_FlowOut[r, p, s, d, i, t, v, o] + * value(M.CapacityCredit[r, p, t, v]) + for (t, v) in M.processReservePeriods[r, p] if t in M.tech_storage - 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 i in M.processInputs[r, p, t, v] + for o in M.processOutputsByInput[r, p, t, v, i] ) - # Electricity imports and exports via exchange techs are accounted - # for below: - for r1r2 in M.regionalIndices: # ensure the region is of the form r1-r2 + # The above code does not consider exchange techs, e.g. electricity + # transmission between two distinct regions. + # We take exchange takes into account below. + # Note that a single exchange tech linking regions Ri and Rj is twice + # defined: once for region "Ri-Rj" and once for region "Rj-Ri". + + # First, determine the amount of firm capacity each exchange tech + # contributes. + for r1r2 in M.regionalIndices: if '-' not in r1r2: continue - if (r1r2, p) not in M.processReservePeriods: # ensure the technology in question exists + if (r1r2, p) not in M.processReservePeriods: # ensure r1r2 is a valid reserve provider in p continue r1, r2 = r1r2.split('-') - # First, determine the exports, and subtract this value from the - # total generation. - if r1 == r: - total_generation -= sum( - M.V_FlowOut[r1r2, p, s, d, S_i, t, S_v, S_o] - / get_variable_efficiency(M, r1r2, p, s, d, S_i, t, S_v, S_o) - for (t, S_v) in M.processReservePeriods[r1r2, p] - for S_i in M.processInputs[r1r2, p, t, S_v] - for S_o in M.processOutputsByInput[r1r2, p, t, S_v, S_i] - ) - # Second, determine the imports, and add this value from the - # total generation. - elif r2 == r: - total_generation += sum( - M.V_FlowOut[r1r2, p, s, d, S_i, t, S_v, S_o] - for (t, S_v) in M.processReservePeriods[r1r2, p] - for S_i in M.processInputs[r1r2, p, t, S_v] - for S_o in M.processOutputsByInput[r1r2, p, t, S_v, S_i] - if (t, S_v) in M.processReservePeriods[r1r2, p] - ) - cap_target = total_generation * (1 + value(M.PlanningReserveMargin[r])) - return cap_avail >= cap_target + # Only consider the capacity of technologies that import to + # the region in question -- i.e. for cases where r2 == r. + if r2 != r: + continue + + # add the available output of the exchange tech. + available += sum( + M.V_Capacity[r1r2, p, t, v] + * value(M.CapacityCredit[r1r2, p, t, v]) + * value(M.ProcessLifeFrac[r1r2, p, t, v]) + * value(M.CapacityFactorProcess[r, p, s, d, t, v]) + * value(M.CapacityToActivity[r1r2, t]) + * value(M.SegFrac[p, s, d]) + for (t, v) in M.processReservePeriods[r1r2, p] + for t in M.tech_reserve + ) + + return available def LimitEmission_Constraint(M: 'TemoaModel', r, p, e, op): diff --git a/tests/testing_configs/config_emissions.toml b/tests/testing_configs/config_emissions.toml index 1b5354e2f..3e8ea8509 100644 --- a/tests/testing_configs/config_emissions.toml +++ b/tests/testing_configs/config_emissions.toml @@ -35,6 +35,18 @@ save_lp_file = false # the schema). This is an advanced feature and not recommended for most users. time_sequencing = 'seasonal_timeslicing' +# How contributions to the planning reserve margin are calculated. Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit +reserve_margin = 'static' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/tests/testing_configs/config_link_test.toml b/tests/testing_configs/config_link_test.toml index c5324ba1a..9d0c32074 100644 --- a/tests/testing_configs/config_link_test.toml +++ b/tests/testing_configs/config_link_test.toml @@ -88,6 +88,18 @@ save_lp_file = false # the schema). This is an advanced feature and not recommended for most users. time_sequencing = 'seasonal_timeslicing' +# How contributions to the planning reserve margin are calculated. Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit +reserve_margin = 'static' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/tests/testing_configs/config_materials.toml b/tests/testing_configs/config_materials.toml index 958b91aa2..3ed591861 100644 --- a/tests/testing_configs/config_materials.toml +++ b/tests/testing_configs/config_materials.toml @@ -35,6 +35,18 @@ save_lp_file = false # the schema). This is an advanced feature and not recommended for most users. time_sequencing = 'seasonal_timeslicing' +# How contributions to the planning reserve margin are calculated. Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit +reserve_margin = 'static' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/tests/testing_configs/config_mediumville.toml b/tests/testing_configs/config_mediumville.toml index eebf08312..d759fc61e 100644 --- a/tests/testing_configs/config_mediumville.toml +++ b/tests/testing_configs/config_mediumville.toml @@ -69,6 +69,18 @@ save_lp_file = false # the schema). This is an advanced feature and not recommended for most users. time_sequencing = 'seasonal_timeslicing' +# How contributions to the planning reserve margin are calculated. Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit +reserve_margin = 'static' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/tests/testing_configs/config_storageville.toml b/tests/testing_configs/config_storageville.toml index 489108ed3..6df7158a9 100644 --- a/tests/testing_configs/config_storageville.toml +++ b/tests/testing_configs/config_storageville.toml @@ -69,6 +69,18 @@ save_lp_file = false # the schema). This is an advanced feature and not recommended for most users. time_sequencing = 'seasonal_timeslicing' +# How contributions to the planning reserve margin are calculated. Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit +reserve_margin = 'static' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/tests/testing_configs/config_test_system.toml b/tests/testing_configs/config_test_system.toml index 796c314fa..74393a515 100644 --- a/tests/testing_configs/config_test_system.toml +++ b/tests/testing_configs/config_test_system.toml @@ -35,6 +35,18 @@ save_lp_file = false # the schema). This is an advanced feature and not recommended for most users. time_sequencing = 'seasonal_timeslicing' +# How contributions to the planning reserve margin are calculated. Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit +reserve_margin = 'static' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/tests/testing_configs/config_utopia.toml b/tests/testing_configs/config_utopia.toml index 281ec827f..60642a838 100644 --- a/tests/testing_configs/config_utopia.toml +++ b/tests/testing_configs/config_utopia.toml @@ -35,6 +35,18 @@ save_lp_file = false # the schema). This is an advanced feature and not recommended for most users. time_sequencing = 'seasonal_timeslicing' +# How contributions to the planning reserve margin are calculated. Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit +reserve_margin = 'static' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/tests/testing_configs/config_utopia_myopic.toml b/tests/testing_configs/config_utopia_myopic.toml index 887389b28..c64636ebf 100644 --- a/tests/testing_configs/config_utopia_myopic.toml +++ b/tests/testing_configs/config_utopia_myopic.toml @@ -37,6 +37,18 @@ save_lp_file = false # the schema). This is an advanced feature and not recommended for most users. time_sequencing = 'seasonal_timeslicing' +# How contributions to the planning reserve margin are calculated. Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit +reserve_margin = 'static' + # --------------------------------------------------- # MODE OPTIONS # options below are mode-specific and will be ignored diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 3f03af9f8..00403d39e 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -4030,7 +4030,7 @@ ], "ReserveMargin_rpsd": [ [ - "B", + "A", 2025, "s2", "d1" @@ -4039,7 +4039,7 @@ "A", 2025, "s1", - "d2" + "d1" ], [ "A", @@ -4051,33 +4051,12 @@ "A", 2025, "s1", - "d1" - ], - [ - "A", - 2025, - "s2", - "d1" - ], - [ - "B", - 2025, - "s1", - "d2" - ], - [ - "B", - 2025, - "s2", "d2" - ], - [ - "B", - 2025, - "s1", - "d1" ] ], + "ReserveMargin": [ + "static" + ], "RetiredCapacityVar_rptv": [], "StorageConstraints_rpsdtv": [ [ @@ -4327,7 +4306,7 @@ "s2" ], "TimeSequencing": [ - "loop_periods" + "seasonal_timeslicing" ], "vintage_all": [ 2025, diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 02e3b5d0a..09f9ed836 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -44961,295 +44961,9 @@ ] ], "RenewablePortfolioStandardConstraint_rpg": [], - "ReserveMargin_rpsd": [ - [ - "R1", - 2025, - "winter", - "day" - ], - [ - "R2", - 2025, - "summer", - "day" - ], - [ - "R1", - 2025, - "summer", - "night" - ], - [ - "R2", - 2030, - "winter", - "night" - ], - [ - "R2", - 2030, - "summer", - "night" - ], - [ - "R1", - 2020, - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "night" - ], - [ - "R2", - 2020, - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "night" - ], - [ - "R2", - 2025, - "summer", - "night" - ], - [ - "R2", - 2025, - "fall", - "day" - ], - [ - "R1", - 2025, - "fall", - "day" - ], - [ - "R2", - 2030, - "fall", - "day" - ], - [ - "R1", - 2020, - "spring", - "night" - ], - [ - "R2", - 2020, - "spring", - "night" - ], - [ - "R1", - 2030, - "spring", - "night" - ], - [ - "R1", - 2030, - "winter", - "day" - ], - [ - "R1", - 2030, - "summer", - "day" - ], - [ - "R1", - 2020, - "summer", - "day" - ], - [ - "R2", - 2020, - "summer", - "day" - ], - [ - "R2", - 2025, - "fall", - "night" - ], - [ - "R1", - 2025, - "fall", - "night" - ], - [ - "R2", - 2030, - "fall", - "night" - ], - [ - "R1", - 2025, - "spring", - "night" - ], - [ - "R2", - 2020, - "winter", - "day" - ], - [ - "R1", - 2020, - "winter", - "day" - ], - [ - "R1", - 2030, - "summer", - "night" - ], - [ - "R1", - 2030, - "winter", - "night" - ], - [ - "R1", - 2020, - "summer", - "night" - ], - [ - "R2", - 2030, - "spring", - "day" - ], - [ - "R2", - 2020, - "summer", - "night" - ], - [ - "R1", - 2020, - "fall", - "day" - ], - [ - "R2", - 2020, - "fall", - "day" - ], - [ - "R1", - 2030, - "fall", - "day" - ], - [ - "R2", - 2025, - "spring", - "day" - ], - [ - "R2", - 2020, - "winter", - "night" - ], - [ - "R1", - 2025, - "spring", - "day" - ], - [ - "R1", - 2020, - "winter", - "night" - ], - [ - "R2", - 2030, - "spring", - "night" - ], - [ - "R1", - 2025, - "summer", - "day" - ], - [ - "R2", - 2030, - "winter", - "day" - ], - [ - "R1", - 2020, - "fall", - "night" - ], - [ - "R2", - 2020, - "fall", - "night" - ], - [ - "R2", - 2030, - "summer", - "day" - ], - [ - "R2", - 2025, - "spring", - "night" - ], - [ - "R2", - 2025, - "winter", - "day" - ], - [ - "R1", - 2030, - "fall", - "night" - ] + "ReserveMargin_rpsd": [], + "ReserveMargin": [ + "static" ], "RetiredCapacityVar_rptv": [], "StorageConstraints_rpsdtv": [ @@ -46997,7 +46711,7 @@ "winter" ], "TimeSequencing": [ - "loop_periods" + "seasonal_timeslicing" ], "vintage_all": [ 2025, diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index f8098ee3c..327a4130f 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -24717,115 +24717,9 @@ "RampUpConstraint_rpsdtv": [], "RegionalExchangeCapacityConstraint_rrptv": [], "RenewablePortfolioStandardConstraint_rpg": [], - "ReserveMargin_rpsd": [ - [ - "utopia", - 1990, - "inter", - "night" - ], - [ - "utopia", - 1990, - "summer", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night" - ], - [ - "utopia", - 1990, - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night" - ], - [ - "utopia", - 2000, - "inter", - "night" - ], - [ - "utopia", - 2000, - "summer", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night" - ], - [ - "utopia", - 2000, - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night" - ], - [ - "utopia", - 2010, - "summer", - "day" - ], - [ - "utopia", - 1990, - "winter", - "night" - ], - [ - "utopia", - 2010, - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "night" - ], - [ - "utopia", - 2000, - "winter", - "night" - ] + "ReserveMargin_rpsd": [], + "ReserveMargin": [ + "static" ], "RetiredCapacityVar_rptv": [], "StorageConstraints_rpsdtv": [ @@ -25914,7 +25808,7 @@ "winter" ], "TimeSequencing": [ - "loop_periods" + "seasonal_timeslicing" ], "vintage_all": [ 1990, From 7bdad63fe6b32c9bfaaccf704b833f0751efea45 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 12 Jun 2025 13:21:45 -0400 Subject: [PATCH 104/587] Add mediumville to legacy outputs test --- temoa/temoa_model/temoa_initialize.py | 6 +++--- temoa/temoa_model/temoa_rules.py | 4 ++-- tests/legacy_test_values.py | 8 ++++++++ tests/test_full_runs.py | 1 + tests/testing_data/mediumville.sql | 4 +--- tests/testing_data/mediumville_sets.json | 19 +++++-------------- 6 files changed, 20 insertions(+), 22 deletions(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 795026321..149afce38 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -236,7 +236,7 @@ def validate_TimeNext(M: 'TemoaModel'): TimeSegmentFraction is already compared to other tables so just compare to SegFrac. """ # Only check TimeNext if it is actually being used - if M.TimeSequencing != 2: + if M.TimeSequencing.first() != 'manual': return segfrac_psd = set(M.SegFrac.sparse_iterkeys()) @@ -1067,7 +1067,7 @@ def CreateSparseDicts(M: 'TemoaModel'): def CreateTimeSequence(M: 'TemoaModel'): # Establishing sequence of states - match M.TimeSequencing[1]: + match M.TimeSequencing.first(): case 'seasonal_timeslicing': msg = 'Running a season time slicing database, looping state each period, chaining between seasons.' for p in M.time_optimize: @@ -1085,7 +1085,7 @@ def CreateTimeSequence(M: 'TemoaModel'): M.time_next[p, s, d] = s_next, d_next case _: # This should have been caught in hybrid_loader - msg = f"Invalid time sequencing parameter loaded '{M.TimeSequencing[1]}'. Likely code error." + msg = f"Invalid time sequencing parameter loaded '{M.TimeSequencing.first()}'. Likely code error." logger.error(msg) raise ValueError(msg) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 35e236e81..800fcbf8f 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1629,13 +1629,13 @@ def RampDown_Constraint(M: 'TemoaModel', r, p, s, d, t, v): def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): # Get available generation in this time slice depending on method specified in config file - match M.ReserveMargin[1]: + match M.ReserveMargin.first(): case 'static': available = ReserveMarginStatic(M, r, p, s, d) case 'dynamic': available = ReserveMarginDynamic(M, r, p, s, d) case _: - msg = f"Invalid reserve margin parameter '{M.ReserveMargin[1]}'. Check the config file." + msg = f"Invalid reserve margin parameter '{M.ReserveMargin.first()}'. Check the config file." logger.error(msg) raise ValueError(msg) diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index 98e6314e9..fc6851c19 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -66,4 +66,12 @@ class ExpectedVals(Enum): # increased after making annualretirement derived var ExpectedVals.VAR_COUNT: 1070, }, + 'mediumville': { + # added 2025/06/12 prior to addition of dynamic reserve margin + ExpectedVals.OBJ_VALUE: 8139.1913, + ExpectedVals.EFF_DOMAIN_SIZE: 2800, + ExpectedVals.EFF_INDEX_SIZE: 18, + ExpectedVals.CONSTR_COUNT: 232, + ExpectedVals.VAR_COUNT: 140, + }, } diff --git a/tests/test_full_runs.py b/tests/test_full_runs.py index c8a064a44..e2288a6ac 100644 --- a/tests/test_full_runs.py +++ b/tests/test_full_runs.py @@ -41,6 +41,7 @@ legacy_config_files = [ {'name': 'utopia', 'filename': 'config_utopia.toml'}, {'name': 'test_system', 'filename': 'config_test_system.toml'}, + {'name': 'mediumville', 'filename': 'config_mediumville.toml'}, ] myopic_files = [{'name': 'myopic utopia', 'filename': 'config_utopia_myopic.toml'}] diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 885c9e561..239c191be 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -116,7 +116,7 @@ INSERT INTO Commodity VALUES('ELC','p','electricity'); INSERT INTO Commodity VALUES('HYD','p','water'); INSERT INTO Commodity VALUES('co2','e','CO2 emissions'); INSERT INTO Commodity VALUES('RL','d','residential lighting'); -INSERT INTO Commodity VALUES('earth','p','the source of stuff'); +INSERT INTO Commodity VALUES('earth','s','the source of stuff'); INSERT INTO Commodity VALUES('RH','d','residential heat'); INSERT INTO Commodity VALUES('FusionGas','e','mystery emission'); INSERT INTO Commodity VALUES('FusionGasFuel','p','converted mystery gas to fuel'); @@ -424,7 +424,6 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -INSERT INTO TechGroup VALUES('RPS_global',''); INSERT INTO TechGroup VALUES('RPS_common',''); INSERT INTO TechGroup VALUES('A_tech_grp_1','converted from old db'); CREATE TABLE LoanLifetimeTech @@ -737,7 +736,6 @@ CREATE TABLE LimitTechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -INSERT INTO LimitTechInputSplitAnnual VALUES('A',2025,'GeoHyd','GeoHeater','le',0.8000000000000000444,'80% geothermal'); CREATE TABLE LimitTechOutputSplit ( region TEXT, diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 00403d39e..0bd966f47 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -3335,16 +3335,7 @@ "LimitSeasonalCapacityFactorConstraint_rpst": [], "LimitStorageFractionConstraint_rpsdtv": [], "LimitTechInputSplitAnnualConstraint_rpitv": [], - "LimitTechInputSplitAverageConstraint_rpitv": [ - [ - "A", - 2025, - "GeoHyd", - "GeoHeater", - 2025, - "le" - ] - ], + "LimitTechInputSplitAverageConstraint_rpitv": [], "LimitTechInputSplitConstraint_rpsditv": [ [ "A", @@ -4166,7 +4157,9 @@ "FusionGasFuel", "earth" ], - "commodity_source": [], + "commodity_source": [ + "earth" + ], "commodity_waste": [], "operator": [ "ge", @@ -4227,14 +4220,12 @@ ], "tech_group_names": [ "A_tech_grp_1", - "RPS_common", - "RPS_global" + "RPS_common" ], "tech_or_group": [ "A_tech_grp_1", "RPS_common", "EH", - "RPS_global", "EF", "GeoThermal", "well", From 4c8cd239b0acad0913f6d6d1d1d3bfc13ea89f63 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 12 Jun 2025 17:33:12 -0400 Subject: [PATCH 105/587] Add LDES --- temoa/temoa_model/hybrid_loader.py | 8 ++++ temoa/temoa_model/temoa_initialize.py | 30 ++++++++++++++ temoa/temoa_model/temoa_model.py | 29 ++++++++++++-- temoa/temoa_model/temoa_rules.py | 57 +++++++++++++++++++++++++++ 4 files changed, 120 insertions(+), 4 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index d932fa4f8..e616e8295 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -425,6 +425,10 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N logger.warning('No PeriodSeasons table found. Loading a single filler season "S" (assume this is an annual model)') load_element(M.time_season_all, [('S',)]) + if self.table_exists("TimeStorageSeason"): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT period, storage_season, season FROM main.TimeStorageSeason ORDER BY period, sequence') + load_element(M.TimeStorageSeason, raw) + # TimeSequencing time_sequencing = self.config.time_sequencing match time_sequencing: @@ -517,6 +521,10 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N raw = cur.execute("SELECT tech FROM main.Technology WHERE flag = 'ps'").fetchall() load_element(M.tech_storage, raw, self.viable_techs) + # tech_storage_seatech_seasonal_storagesonal + raw = cur.execute("SELECT tech FROM main.Technology WHERE flag = 'ps' AND seasonal_storage > 0").fetchall() + load_element(M.tech_seasonal_storage, raw, self.viable_techs) + # tech_reserve raw = cur.execute('SELECT tech FROM Technology WHERE reserve > 0').fetchall() load_element(M.tech_reserve, raw, self.viable_techs) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 149afce38..8fd571e5f 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1061,6 +1061,15 @@ def CreateSparseDicts(M: 'TemoaModel'): for d in M.time_of_day ) + M.seasonalStorageLevelIndices_rpstv = set( + (r, p, s_stor, t, v) + for r, p, t in M.storageVintages.keys() + if t in M.tech_seasonal_storage + for v in M.storageVintages[r, p, t] + for _p, s_stor in M.time_storage_season + if _p == p + ) + logger.debug('Completed creation of SparseDicts') @@ -1088,6 +1097,14 @@ def CreateTimeSequence(M: 'TemoaModel'): msg = f"Invalid time sequencing parameter loaded '{M.TimeSequencing.first()}'. Likely code error." logger.error(msg) raise ValueError(msg) + + # Seasonal storage superimposed sequencing + for p, s_stor, s in M.TimeStorageSeason: + M.time_storage_season[p, s_stor] = s + if (p, s_stor, s) == M.TimeStorageSeason.last(): + M.time_next_storage_season[p, s_stor] = M.TimeStorageSeason.first()[1] + else: + M.time_next_storage_season[p, s_stor] = M.TimeStorageSeason.next((p, s_stor, s))[1] msg += (' This behaviour can be changed using the ' 'time_sequencing parameter in the config file. ') @@ -1312,6 +1329,19 @@ def CurtailmentVariableIndices(M: 'TemoaModel'): def StorageLevelVariableIndices(M: 'TemoaModel'): return M.storageLevelIndices_rpsdtv +def SeasonalStorageLevelVariableIndices(M: 'TemoaModel'): + return M.seasonalStorageLevelIndices_rpstv + + +def SeasonalStorageEnergyUpperBoundConstraintIndices(M: 'TemoaModel'): + indices = set( + (r, p, s, d, t, v) + for r, p, s, t, v in M.seasonalStorageLevelIndices_rpstv + for d in M.time_of_day + ) + + return indices + def StorageConstraintIndices(M: 'TemoaModel'): return M.storageLevelIndices_rpsdtv diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 4da8236fd..8a27c88bf 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -87,6 +87,7 @@ def __init__(M, *args, **kwargs): M.activeCurtailment_rpsditvo = None M.activeActivity_rptv = None M.storageLevelIndices_rpsdtv = None + M.seasonalStorageLevelIndices_rpstv = None """currently available (within lifespan) (r, p, t, v) tuples (from M.processVintages)""" M.activeRegionsForTech = None @@ -122,7 +123,9 @@ def __init__(M, *args, **kwargs): M.processByPeriodAndOutput = dict() M.exportRegions = dict() M.importRegions = dict() - M.time_next = dict() # {(s, d): (s_next, d_next)} sequence of following time slices + M.time_next = dict() # {(p, s, d): (s_next, d_next)} sequence of following time slices + M.time_next_storage_season = dict() # {(p, s_stor): (s_stor_next)} + M.time_storage_season = dict() # {(p, s_stor): (s)} ################################################ # Switching Sets # @@ -185,6 +188,9 @@ def __init__(M, *args, **kwargs): M.tech_group_members = Set(M.tech_group_names, within=M.tech_all) M.tech_or_group = Set(initialize=M.tech_group_names | M.tech_all) + M.tech_seasonal_storage = Set(within=M.tech_storage) + """storage technologies using the interseasonal storage feature""" + M.tech_uncap = Set(within=M.tech_all - M.tech_reserve) """techs with unlimited capacity, ALWAYS available within lifespan""" @@ -244,8 +250,9 @@ def __init__(M, *args, **kwargs): M.SegFrac = Param(M.time_optimize, M.time_season_all, M.time_of_day) M.validate_SegFrac = BuildAction(rule=validate_SegFrac) M.TimeSequencing = Set() # How do states carry between time segments? - M.TimeNext = Set() # This is just to get data from the table. Hidden feature and usually not used + M.TimeNext = Set(ordered=True) # This is just to get data from the table. Hidden feature and usually not used M.validate_TimeNext = BuildAction(rule=validate_TimeNext) + M.TimeStorageSeason = Set(ordered=True) # Season sequence for seasonal storage # Define demand- and resource-related parameters # Dev Note: There does not appear to be a DB table supporting DemandDefaultDistro. This does not @@ -340,8 +347,8 @@ def __init__(M, *args, **kwargs): # The method below creates a series of helper functions that are used to # perform the sparse matrix of indexing for the parameters, variables, and # equations below. - M.Create_SparseDicts = BuildAction(rule=CreateSparseDicts) M.Create_StateSequence = BuildAction(rule=CreateTimeSequence) + M.Create_SparseDicts = BuildAction(rule=CreateSparseDicts) M.CapacityFactor_rpsdt = Set(dimen=5, initialize=CapacityFactorTechIndices) M.CapacityFactorTech = Param(M.CapacityFactor_rpsdt, default=1, validate=validate_0to1) @@ -531,6 +538,9 @@ def __init__(M, *args, **kwargs): M.StorageLevel_rpsdtv = Set(dimen=6, initialize=StorageLevelVariableIndices) M.V_StorageLevel = Var(M.StorageLevel_rpsdtv, domain=NonNegativeReals) + M.SeasonalStorageLevel_rpstv = Set(dimen=5, initialize=SeasonalStorageLevelVariableIndices) + M.V_SeasonalStorageLevel = Var(M.SeasonalStorageLevel_rpstv, domain=NonNegativeReals) + # Derived decision variables M.CapacityVar_rptv = Set(dimen=4, initialize=CostFixedIndices) M.V_Capacity = Var(M.CapacityVar_rptv, domain=NonNegativeReals) @@ -644,6 +654,17 @@ def __init__(M, *args, **kwargs): # Pre-computing it is considerably faster. M.SegFracPerSeason = Param(M.time_optimize, M.time_season_all, initialize=SegFracPerSeason_rule) + M.SeasonalStorageEnergyConstraint = Constraint( + M.SeasonalStorageLevel_rpstv, rule=SeasonalStorageEnergy_Constraint + ) + + M.SeasonalStorageUpperBoundConstraint_rpsdtv = Set( + dimen=6, initialize=SeasonalStorageEnergyUpperBoundConstraintIndices + ) + M.SeasonalStorageEnergyUpperBoundConstraint = Constraint( + M.SeasonalStorageUpperBoundConstraint_rpsdtv, rule=SeasonalStorageEnergyUpperBound_Constraint + ) + M.StorageEnergyConstraint = Constraint( M.StorageConstraints_rpsdtv, rule=StorageEnergy_Constraint ) @@ -675,7 +696,7 @@ def __init__(M, *args, **kwargs): M.ReserveMargin_rpsd = Set(dimen=4, initialize=ReserveMarginIndices) M.ReserveMarginConstraint = Constraint(M.ReserveMargin_rpsd, rule=ReserveMargin_Constraint) - + M.LimitEmissionConstraint = Constraint( M.LimitEmissionConstraint_rpe, rule=LimitEmission_Constraint ) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 800fcbf8f..ab881ac72 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1287,6 +1287,41 @@ def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): return expr +def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_stor, t, v): + """ + This constraint enforces the continuity of state of charge between seasons for seasonal + storage. Virtual seasonal storage level increases by the matched real season's net charge + over that entire day. + """ + + s = M.time_storage_season[p, s_stor] + + # This is the sum of all input=i sent TO storage tech t of vintage v with + # output=o in p,s,d + charge = sum( + M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] * get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + for d in M.time_of_day + ) + + # This is the sum of all output=o withdrawn FROM storage tech t of vintage v + # with input=i in p,s,d + discharge = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_o in M.processOutputs[r, p, t, v] + for S_i in M.processInputsByOutput[r, p, t, v, S_o] + for d in M.time_of_day + ) + + stored_energy = charge - discharge + + s_stor_next = M.time_next_storage_season[p, s_stor] + + expr = M.V_SeasonalStorageLevel[r, p, s_stor, t, v] + stored_energy == M.V_SeasonalStorageLevel[r, p, s_stor_next, t, v] + return expr + + def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): r""" @@ -1330,6 +1365,28 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): return expr +def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_stor, d, t, v): + r""" + Builds off of StorageEnergyUpperBound_Constraint. Enforces the max charge capacity of seasonal storage, + summing the superimposed real storage level with the virtual seasonal storage level. + """ + + s = M.time_storage_season[p, s_stor] + + energy_capacity = ( + M.V_Capacity[r, p, t, v] + * value(M.CapacityToActivity[r, t]) + * (value(M.StorageDuration[r, t]) / 8760) + * M.SegFracPerSeason[p, s] + * 365 + * value(M.ProcessLifeFrac[r, p, t, v]) + ) + + expr = M.V_SeasonalStorageLevel[r, p, s_stor, t, v] + M.V_StorageLevel[r, p, s, d, t, v] <= energy_capacity + + return expr + + def StorageChargeRate_Constraint(M: 'TemoaModel', r, p, s, d, t, v): r""" From a5be373e3d9abdd3364354cf2ef3c16fa2e3b222 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 12 Jun 2025 18:15:46 -0400 Subject: [PATCH 106/587] Update tests and databases for LDES --- data_files/example_dbs/materials.sql | 33 +++----- data_files/example_dbs/morris_utopia.sql | 26 ++---- data_files/example_dbs/stepped_demand.sql | 82 ++++++++++--------- data_files/example_dbs/test_system.sql | 41 +++++----- data_files/example_dbs/utopia.sql | 45 ++++++---- data_files/temoa_schema_v3_1.sql | 14 +++- temoa/temoa_model/hybrid_loader.py | 23 ++++-- temoa/temoa_model/table_data_puller.py | 8 ++ temoa/utilities/db_migration_v3_to_v3_1.py | 12 +-- tests/testing_data/emissions.sql | 34 ++++---- tests/testing_data/emissions.sqlite | Bin 0 -> 667648 bytes tests/testing_data/materials.sql | 79 +++++++++--------- tests/testing_data/materials.sqlite | Bin 0 -> 684032 bytes tests/testing_data/mediumville.sql | 39 +++++---- tests/testing_data/mediumville.sqlite | Bin 0 -> 667648 bytes tests/testing_data/mediumville_sets.json | 4 + tests/testing_data/simple_linked_tech.sql | 27 +++--- tests/testing_data/simple_linked_tech.sqlite | Bin 0 -> 667648 bytes tests/testing_data/storageville.sql | 27 +++--- tests/testing_data/storageville.sqlite | Bin 0 -> 667648 bytes tests/testing_data/test_system.sql | 73 +++++++++-------- tests/testing_data/test_system.sqlite | Bin 0 -> 667648 bytes tests/testing_data/test_system_sets.json | 4 + tests/testing_data/utopia.sql | 72 ++++++++-------- tests/testing_data/utopia.sqlite | Bin 0 -> 667648 bytes tests/testing_data/utopia_sets.json | 4 + 26 files changed, 354 insertions(+), 293 deletions(-) create mode 100644 tests/testing_data/emissions.sqlite create mode 100644 tests/testing_data/materials.sqlite create mode 100644 tests/testing_data/mediumville.sqlite create mode 100644 tests/testing_data/simple_linked_tech.sqlite create mode 100644 tests/testing_data/storageville.sqlite create mode 100644 tests/testing_data/test_system.sqlite create mode 100644 tests/testing_data/utopia.sqlite diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index 3140295bf..21db50885 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -1418,15 +1418,6 @@ INSERT INTO TimePeriod VALUES(3,2010,'f'); INSERT INTO TimePeriod VALUES(4,2020,'f'); INSERT INTO TimePeriod VALUES(5,2030,'f'); CREATE TABLE TimeSeason -( - season TEXT - PRIMARY KEY -); -INSERT INTO TimeSeason VALUES('summer'); -INSERT INTO TimeSeason VALUES('autumn'); -INSERT INTO TimeSeason VALUES('winter'); -INSERT INTO TimeSeason VALUES('spring'); -CREATE TABLE PeriodSeasons ( period INTEGER REFERENCES TimePeriod (period), @@ -1436,18 +1427,18 @@ CREATE TABLE PeriodSeasons notes TEXT, PRIMARY KEY (period, sequence, season) ); -INSERT INTO PeriodSeasons VALUES(2000,1,'summer',NULL); -INSERT INTO PeriodSeasons VALUES(2000,2,'autumn',NULL); -INSERT INTO PeriodSeasons VALUES(2000,3,'winter',NULL); -INSERT INTO PeriodSeasons VALUES(2000,4,'spring',NULL); -INSERT INTO PeriodSeasons VALUES(2010,5,'summer',NULL); -INSERT INTO PeriodSeasons VALUES(2010,6,'autumn',NULL); -INSERT INTO PeriodSeasons VALUES(2010,7,'winter',NULL); -INSERT INTO PeriodSeasons VALUES(2010,8,'spring',NULL); -INSERT INTO PeriodSeasons VALUES(2020,9,'summer',NULL); -INSERT INTO PeriodSeasons VALUES(2020,10,'autumn',NULL); -INSERT INTO PeriodSeasons VALUES(2020,11,'winter',NULL); -INSERT INTO PeriodSeasons VALUES(2020,12,'spring',NULL); +INSERT INTO TimeSeason VALUES(2000,1,'summer',NULL); +INSERT INTO TimeSeason VALUES(2000,2,'autumn',NULL); +INSERT INTO TimeSeason VALUES(2000,3,'winter',NULL); +INSERT INTO TimeSeason VALUES(2000,4,'spring',NULL); +INSERT INTO TimeSeason VALUES(2010,5,'summer',NULL); +INSERT INTO TimeSeason VALUES(2010,6,'autumn',NULL); +INSERT INTO TimeSeason VALUES(2010,7,'winter',NULL); +INSERT INTO TimeSeason VALUES(2010,8,'spring',NULL); +INSERT INTO TimeSeason VALUES(2020,9,'summer',NULL); +INSERT INTO TimeSeason VALUES(2020,10,'autumn',NULL); +INSERT INTO TimeSeason VALUES(2020,11,'winter',NULL); +INSERT INTO TimeSeason VALUES(2020,12,'spring',NULL); CREATE TABLE TimePeriodType ( label TEXT diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index 76a8fa0ac..ed0fb269e 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -1398,14 +1398,6 @@ INSERT INTO TimePeriod VALUES(5,2000,'f'); INSERT INTO TimePeriod VALUES(6,2010,'f'); INSERT INTO TimePeriod VALUES(7,2020,'f'); CREATE TABLE TimeSeason -( - season TEXT - PRIMARY KEY -); -INSERT INTO TimeSeason VALUES('inter'); -INSERT INTO TimeSeason VALUES('summer'); -INSERT INTO TimeSeason VALUES('winter'); -CREATE TABLE PeriodSeasons ( period INTEGER REFERENCES TimePeriod (period), @@ -1415,15 +1407,15 @@ CREATE TABLE PeriodSeasons notes TEXT, PRIMARY KEY (period, sequence, season) ); -INSERT INTO PeriodSeasons VALUES(1990,2,'summer',NULL); -INSERT INTO PeriodSeasons VALUES(1990,3,'winter',NULL); -INSERT INTO PeriodSeasons VALUES(1990,1,'inter',NULL); -INSERT INTO PeriodSeasons VALUES(2000,2,'summer',NULL); -INSERT INTO PeriodSeasons VALUES(2000,3,'winter',NULL); -INSERT INTO PeriodSeasons VALUES(2000,1,'inter',NULL); -INSERT INTO PeriodSeasons VALUES(2010,2,'summer',NULL); -INSERT INTO PeriodSeasons VALUES(2010,3,'winter',NULL); -INSERT INTO PeriodSeasons VALUES(2010,1,'inter',NULL); +INSERT INTO TimeSeason VALUES(1990,2,'summer',NULL); +INSERT INTO TimeSeason VALUES(1990,3,'winter',NULL); +INSERT INTO TimeSeason VALUES(1990,1,'inter',NULL); +INSERT INTO TimeSeason VALUES(2000,2,'summer',NULL); +INSERT INTO TimeSeason VALUES(2000,3,'winter',NULL); +INSERT INTO TimeSeason VALUES(2000,1,'inter',NULL); +INSERT INTO TimeSeason VALUES(2010,2,'summer',NULL); +INSERT INTO TimeSeason VALUES(2010,3,'winter',NULL); +INSERT INTO TimeSeason VALUES(2010,1,'inter',NULL); CREATE TABLE TimePeriodType ( label TEXT diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index e65e7ba06..d92613480 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -1139,55 +1139,58 @@ INSERT INTO TimePeriod VALUES(12,2050,'f'); INSERT INTO TimePeriod VALUES(13,2055,'f'); CREATE TABLE TimeSeason ( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, season TEXT - PRIMARY KEY + REFERENCES TimeSeason (season), + notes TEXT, + PRIMARY KEY (period, sequence, season) ); -INSERT INTO TimeSeason VALUES('inter'); -INSERT INTO TimeSeason VALUES('summer'); -INSERT INTO TimeSeason VALUES('winter'); -CREATE TABLE PeriodSeasons +INSERT INTO TimeSeason VALUES(2000,1,'inter',NULL); +INSERT INTO TimeSeason VALUES(2000,2,'summer',NULL); +INSERT INTO TimeSeason VALUES(2000,3,'winter',NULL); +INSERT INTO TimeSeason VALUES(2005,1,'inter',NULL); +INSERT INTO TimeSeason VALUES(2005,2,'summer',NULL); +INSERT INTO TimeSeason VALUES(2005,3,'winter',NULL); +INSERT INTO TimeSeason VALUES(2010,1,'inter',NULL); +INSERT INTO TimeSeason VALUES(2010,2,'summer',NULL); +INSERT INTO TimeSeason VALUES(2010,3,'winter',NULL); +INSERT INTO TimeSeason VALUES(2015,1,'inter',NULL); +INSERT INTO TimeSeason VALUES(2015,2,'summer',NULL); +INSERT INTO TimeSeason VALUES(2015,3,'winter',NULL); +INSERT INTO TimeSeason VALUES(2020,1,'inter',NULL); +INSERT INTO TimeSeason VALUES(2020,2,'summer',NULL); +INSERT INTO TimeSeason VALUES(2020,3,'winter',NULL); +INSERT INTO TimeSeason VALUES(2025,1,'inter',NULL); +INSERT INTO TimeSeason VALUES(2025,2,'summer',NULL); +INSERT INTO TimeSeason VALUES(2025,3,'winter',NULL); +INSERT INTO TimeSeason VALUES(2030,1,'inter',NULL); +INSERT INTO TimeSeason VALUES(2030,2,'summer',NULL); +INSERT INTO TimeSeason VALUES(2030,3,'winter',NULL); +INSERT INTO TimeSeason VALUES(2035,1,'inter',NULL); +INSERT INTO TimeSeason VALUES(2035,2,'summer',NULL); +INSERT INTO TimeSeason VALUES(2035,3,'winter',NULL); +INSERT INTO TimeSeason VALUES(2040,1,'inter',NULL); +INSERT INTO TimeSeason VALUES(2040,2,'summer',NULL); +INSERT INTO TimeSeason VALUES(2040,3,'winter',NULL); +INSERT INTO TimeSeason VALUES(2045,1,'inter',NULL); +INSERT INTO TimeSeason VALUES(2045,2,'summer',NULL); +INSERT INTO TimeSeason VALUES(2045,3,'winter',NULL); +INSERT INTO TimeSeason VALUES(2050,1,'inter',NULL); +INSERT INTO TimeSeason VALUES(2050,2,'summer',NULL); +INSERT INTO TimeSeason VALUES(2050,3,'winter',NULL); +CREATE TABLE IF NOT EXISTS TimeStorageSeason ( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, + storage_season TEXT, season TEXT REFERENCES TimeSeason (season), notes TEXT, - PRIMARY KEY (period, sequence, season) + PRIMARY KEY (period, sequence, storage_season, season) ); -INSERT INTO PeriodSeasons VALUES(2000,1,'inter',NULL); -INSERT INTO PeriodSeasons VALUES(2000,2,'summer',NULL); -INSERT INTO PeriodSeasons VALUES(2000,3,'winter',NULL); -INSERT INTO PeriodSeasons VALUES(2005,1,'inter',NULL); -INSERT INTO PeriodSeasons VALUES(2005,2,'summer',NULL); -INSERT INTO PeriodSeasons VALUES(2005,3,'winter',NULL); -INSERT INTO PeriodSeasons VALUES(2010,1,'inter',NULL); -INSERT INTO PeriodSeasons VALUES(2010,2,'summer',NULL); -INSERT INTO PeriodSeasons VALUES(2010,3,'winter',NULL); -INSERT INTO PeriodSeasons VALUES(2015,1,'inter',NULL); -INSERT INTO PeriodSeasons VALUES(2015,2,'summer',NULL); -INSERT INTO PeriodSeasons VALUES(2015,3,'winter',NULL); -INSERT INTO PeriodSeasons VALUES(2020,1,'inter',NULL); -INSERT INTO PeriodSeasons VALUES(2020,2,'summer',NULL); -INSERT INTO PeriodSeasons VALUES(2020,3,'winter',NULL); -INSERT INTO PeriodSeasons VALUES(2025,1,'inter',NULL); -INSERT INTO PeriodSeasons VALUES(2025,2,'summer',NULL); -INSERT INTO PeriodSeasons VALUES(2025,3,'winter',NULL); -INSERT INTO PeriodSeasons VALUES(2030,1,'inter',NULL); -INSERT INTO PeriodSeasons VALUES(2030,2,'summer',NULL); -INSERT INTO PeriodSeasons VALUES(2030,3,'winter',NULL); -INSERT INTO PeriodSeasons VALUES(2035,1,'inter',NULL); -INSERT INTO PeriodSeasons VALUES(2035,2,'summer',NULL); -INSERT INTO PeriodSeasons VALUES(2035,3,'winter',NULL); -INSERT INTO PeriodSeasons VALUES(2040,1,'inter',NULL); -INSERT INTO PeriodSeasons VALUES(2040,2,'summer',NULL); -INSERT INTO PeriodSeasons VALUES(2040,3,'winter',NULL); -INSERT INTO PeriodSeasons VALUES(2045,1,'inter',NULL); -INSERT INTO PeriodSeasons VALUES(2045,2,'summer',NULL); -INSERT INTO PeriodSeasons VALUES(2045,3,'winter',NULL); -INSERT INTO PeriodSeasons VALUES(2050,1,'inter',NULL); -INSERT INTO PeriodSeasons VALUES(2050,2,'summer',NULL); -INSERT INTO PeriodSeasons VALUES(2050,3,'winter',NULL); CREATE TABLE TimePeriodType ( label TEXT @@ -1246,6 +1249,7 @@ CREATE TABLE Technology retire INTEGER NOT NULL DEFAULT 0, flex INTEGER NOT NULL DEFAULT 0, exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index 8994fa8bd..203577caf 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -1409,35 +1409,37 @@ INSERT INTO TimePeriod VALUES(4,2030,'f'); INSERT INTO TimePeriod VALUES(5,2035,'f'); CREATE TABLE TimeSeason ( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, season TEXT - PRIMARY KEY + REFERENCES TimeSeason (season), + notes TEXT, + PRIMARY KEY (period, sequence, season) ); -INSERT INTO TimeSeason VALUES('spring'); -INSERT INTO TimeSeason VALUES('summer'); -INSERT INTO TimeSeason VALUES('fall'); -INSERT INTO TimeSeason VALUES('winter'); -CREATE TABLE PeriodSeasons +INSERT INTO TimeSeason VALUES(2020,1,'spring',NULL); +INSERT INTO TimeSeason VALUES(2020,2,'summer',NULL); +INSERT INTO TimeSeason VALUES(2020,3,'fall',NULL); +INSERT INTO TimeSeason VALUES(2020,4,'winter',NULL); +INSERT INTO TimeSeason VALUES(2025,1,'spring',NULL); +INSERT INTO TimeSeason VALUES(2025,2,'summer',NULL); +INSERT INTO TimeSeason VALUES(2025,3,'fall',NULL); +INSERT INTO TimeSeason VALUES(2025,4,'winter',NULL); +INSERT INTO TimeSeason VALUES(2030,1,'spring',NULL); +INSERT INTO TimeSeason VALUES(2030,2,'summer',NULL); +INSERT INTO TimeSeason VALUES(2030,3,'fall',NULL); +INSERT INTO TimeSeason VALUES(2030,4,'winter',NULL); +CREATE TABLE IF NOT EXISTS TimeStorageSeason ( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, + storage_season TEXT, season TEXT REFERENCES TimeSeason (season), notes TEXT, - PRIMARY KEY (period, sequence, season) + PRIMARY KEY (period, sequence, storage_season, season) ); -INSERT INTO PeriodSeasons VALUES(2020,1,'spring',NULL); -INSERT INTO PeriodSeasons VALUES(2020,2,'summer',NULL); -INSERT INTO PeriodSeasons VALUES(2020,3,'fall',NULL); -INSERT INTO PeriodSeasons VALUES(2020,4,'winter',NULL); -INSERT INTO PeriodSeasons VALUES(2025,1,'spring',NULL); -INSERT INTO PeriodSeasons VALUES(2025,2,'summer',NULL); -INSERT INTO PeriodSeasons VALUES(2025,3,'fall',NULL); -INSERT INTO PeriodSeasons VALUES(2025,4,'winter',NULL); -INSERT INTO PeriodSeasons VALUES(2030,1,'spring',NULL); -INSERT INTO PeriodSeasons VALUES(2030,2,'summer',NULL); -INSERT INTO PeriodSeasons VALUES(2030,3,'fall',NULL); -INSERT INTO PeriodSeasons VALUES(2030,4,'winter',NULL); CREATE TABLE TimePeriodType ( label TEXT @@ -1496,6 +1498,7 @@ CREATE TABLE Technology retire INTEGER NOT NULL DEFAULT 0, flex INTEGER NOT NULL DEFAULT 0, exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 38cf05bca..4619a0c77 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -1394,31 +1394,45 @@ INSERT INTO TimePeriod VALUES(6,2010,'f'); INSERT INTO TimePeriod VALUES(7,2020,'f'); CREATE TABLE TimeSeason ( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, season TEXT - PRIMARY KEY + REFERENCES TimeSeason (season), + notes TEXT, + PRIMARY KEY (period, sequence, season) ); -INSERT INTO TimeSeason VALUES('inter'); -INSERT INTO TimeSeason VALUES('summer'); -INSERT INTO TimeSeason VALUES('winter'); -CREATE TABLE PeriodSeasons +INSERT INTO TimeSeason VALUES(1990,1,'inter',NULL); +INSERT INTO TimeSeason VALUES(1990,2,'summer',NULL); +INSERT INTO TimeSeason VALUES(1990,3,'winter',NULL); +INSERT INTO TimeSeason VALUES(2000,1,'inter',NULL); +INSERT INTO TimeSeason VALUES(2000,2,'summer',NULL); +INSERT INTO TimeSeason VALUES(2000,3,'winter',NULL); +INSERT INTO TimeSeason VALUES(2010,1,'inter',NULL); +INSERT INTO TimeSeason VALUES(2010,2,'summer',NULL); +INSERT INTO TimeSeason VALUES(2010,3,'winter',NULL); +CREATE TABLE IF NOT EXISTS TimeStorageSeason ( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, + storage_season TEXT, season TEXT REFERENCES TimeSeason (season), notes TEXT, - PRIMARY KEY (period, sequence, season) + PRIMARY KEY (period, sequence, storage_season, season) +); +CREATE TABLE TimeStorageSeason +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + storage_season TEXT, + season TEXT + REFERENCES TimeSeason (season), + notes TEXT, + PRIMARY KEY (period, sequence, storage_season, season) ); -INSERT INTO PeriodSeasons VALUES(1990,1,'inter',NULL); -INSERT INTO PeriodSeasons VALUES(1990,2,'summer',NULL); -INSERT INTO PeriodSeasons VALUES(1990,3,'winter',NULL); -INSERT INTO PeriodSeasons VALUES(2000,1,'inter',NULL); -INSERT INTO PeriodSeasons VALUES(2000,2,'summer',NULL); -INSERT INTO PeriodSeasons VALUES(2000,3,'winter',NULL); -INSERT INTO PeriodSeasons VALUES(2010,1,'inter',NULL); -INSERT INTO PeriodSeasons VALUES(2010,2,'summer',NULL); -INSERT INTO PeriodSeasons VALUES(2010,3,'winter',NULL); CREATE TABLE TimePeriodType ( label TEXT @@ -1477,6 +1491,7 @@ CREATE TABLE Technology retire INTEGER NOT NULL DEFAULT 0, flex INTEGER NOT NULL DEFAULT 0, exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index 116e6c5ee..f1cbaacff 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -911,18 +911,23 @@ CREATE TABLE IF NOT EXISTS TimePeriod ); CREATE TABLE IF NOT EXISTS TimeSeason ( - season TEXT - PRIMARY KEY + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT, + notes TEXT, + PRIMARY KEY (period, sequence, season) ); -CREATE TABLE IF NOT EXISTS PeriodSeasons +CREATE TABLE IF NOT EXISTS TimeStorageSeason ( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, + storage_season TEXT, season TEXT REFERENCES TimeSeason (season), notes TEXT, - PRIMARY KEY (period, sequence, season) + PRIMARY KEY (period, sequence, storage_season, season) ); CREATE TABLE IF NOT EXISTS TimePeriodType ( @@ -984,6 +989,7 @@ CREATE TABLE IF NOT EXISTS Technology retire INTEGER NOT NULL DEFAULT 0, flex INTEGER NOT NULL DEFAULT 0, exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index e616e8295..6484f7aa1 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -398,16 +398,16 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N logger.warning('No TimeOfDay table found. Loading a single filler time of day "D" (assume this is an annual model)') load_element(M.time_of_day, [('D',)]) - # PeriodSeasons - if self.table_exists("PeriodSeasons"): + # TimeSeason + if self.table_exists("TimeSeason"): if mi: raw = cur.execute( - 'SELECT period, season FROM main.PeriodSeasons WHERE' + 'SELECT period, season FROM main.TimeSeason WHERE' ' period >= ? AND period <= ? ORDER BY period, sequence', (mi.base_year, mi.last_demand_year) ).fetchall() else: - raw = cur.execute('SELECT period, season FROM main.PeriodSeasons ORDER BY period, sequence').fetchall() + raw = cur.execute('SELECT period, season FROM main.TimeSeason ORDER BY period, sequence').fetchall() for row in raw: load_indexed_set( M.time_season, @@ -422,11 +422,18 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N index_value=period, element='S' ) - logger.warning('No PeriodSeasons table found. Loading a single filler season "S" (assume this is an annual model)') + logger.warning('No TimeSeason table found. Loading a single filler season "S" (assume this is an annual model)') load_element(M.time_season_all, [('S',)]) if self.table_exists("TimeStorageSeason"): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT period, storage_season, season FROM main.TimeStorageSeason ORDER BY period, sequence') + if mi: + raw = cur.execute( + 'SELECT period, storage_season, season FROM main.TimeStorageSeason WHERE' + ' period >= ? AND period <= ? ORDER BY period, sequence', + (mi.base_year, mi.last_demand_year) + ).fetchall() + else: + raw = cur.execute('SELECT period, storage_season, season FROM main.TimeStorageSeason ORDER BY period, sequence').fetchall() load_element(M.TimeStorageSeason, raw) # TimeSequencing @@ -521,8 +528,8 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N raw = cur.execute("SELECT tech FROM main.Technology WHERE flag = 'ps'").fetchall() load_element(M.tech_storage, raw, self.viable_techs) - # tech_storage_seatech_seasonal_storagesonal - raw = cur.execute("SELECT tech FROM main.Technology WHERE flag = 'ps' AND seasonal_storage > 0").fetchall() + # tech_seasonal_storage + raw = cur.execute("SELECT tech FROM main.Technology WHERE flag = 'ps' AND seas_stor > 0").fetchall() load_element(M.tech_seasonal_storage, raw, self.viable_techs) # tech_reserve diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index 393c713eb..5371c1ac7 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -247,6 +247,14 @@ def poll_storage_level_results(M: TemoaModel, epsilon=1e-5) -> dict[SLI, float]: if abs(state) < epsilon: state = 0 # still want to know but decimals are ugly res[sli] = state + for r, p, s_stor, t, v in M.SeasonalStorageLevel_rpstv: + s = M.time_storage_season[p, s_stor] + for d in M.time_of_day: + state = value(M.V_SeasonalStorageLevel[r, p, s_stor, t, v]) + value(M.V_StorageLevel[r, p, s, d, t, v]) + sli = SLI(r, p, s_stor, d, t, v) + if abs(state) < epsilon: state = 0 # still want to know but decimals are ugly + res[sli] = state + return res diff --git a/temoa/utilities/db_migration_v3_to_v3_1.py b/temoa/utilities/db_migration_v3_to_v3_1.py index 536abae84..5dc980dc7 100644 --- a/temoa/utilities/db_migration_v3_to_v3_1.py +++ b/temoa/utilities/db_migration_v3_to_v3_1.py @@ -124,11 +124,11 @@ def column_check(old_name: str, new_name: str) -> bool: ('', 'TimePeriodType'), ] -period_added_tables =[ +period_added_tables = [ ('', 'CapacityFactorProcess'), ('', 'CapacityFactorTech'), ('', 'DemandSpecificDistribution'), - ('TimeSeason', 'PeriodSeasons'), + ('', 'TimeSeason'), ('', 'TimeSegmentFraction'), ] @@ -208,14 +208,6 @@ def column_check(old_name: str, new_name: str) -> bool: # It wasn't active anyway... can't be bothered # StorageInit -> LimitStorageLevelFraction -# TimeSeason -try: - data = con_old.execute('SELECT DISTINCT season FROM TimeSeason ORDER BY sequence').fetchall() - query = 'INSERT OR REPLACE INTO TimeSeason(season) VALUES(?)' - con_new.executemany(query, data) -except sqlite3.OperationalError: - print('TABLE NOT FOUND: TimeSeason') - # execute the direct transfers print('\n --- Executing direct transfers ---') for old_name, new_name in direct_transfer_tables: diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 2f7462c40..db4106917 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -942,22 +942,27 @@ INSERT INTO TimePeriod VALUES(3,2005,'f'); INSERT INTO TimePeriod VALUES(4,2010,'f'); CREATE TABLE TimeSeason ( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, season TEXT - PRIMARY KEY + REFERENCES TimeSeason (season), + notes TEXT, + PRIMARY KEY (period, sequence, season) ); -INSERT INTO TimeSeason VALUES('S1'); -CREATE TABLE PeriodSeasons +INSERT INTO TimeSeason VALUES(2000,1,'S1',NULL); +INSERT INTO TimeSeason VALUES(2005,1,'S1',NULL); +CREATE TABLE IF NOT EXISTS TimeStorageSeason ( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, + storage_season TEXT, season TEXT REFERENCES TimeSeason (season), notes TEXT, - PRIMARY KEY (period, sequence, season) + PRIMARY KEY (period, sequence, storage_season, season) ); -INSERT INTO PeriodSeasons VALUES(2000,1,'S1',NULL); -INSERT INTO PeriodSeasons VALUES(2005,1,'S1',NULL); CREATE TABLE TimePeriodType ( label TEXT @@ -1016,17 +1021,18 @@ CREATE TABLE Technology retire INTEGER NOT NULL DEFAULT 0, flex INTEGER NOT NULL DEFAULT 0, exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('TechAnnual','p','energy',NULL,NULL,0,1,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('TechFlex','p','energy',NULL,NULL,0,0,0,0,0,1,0,NULL); -INSERT INTO Technology VALUES('TechOrdinary','p','energy',NULL,NULL,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('TechCurtailment','p','energy',NULL,NULL,0,0,0,1,0,0,0,NULL); -INSERT INTO Technology VALUES('TechFlexNull','p','energy',NULL,NULL,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('TechAnnualFlex','p','energy',NULL,NULL,0,1,0,0,0,1,0,NULL); -INSERT INTO Technology VALUES('TechEmbodied','p','energy',NULL,NULL,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('TechEndOfLife','p','energy',NULL,NULL,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('TechAnnual','p','energy',NULL,NULL,0,1,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('TechFlex','p','energy',NULL,NULL,0,0,0,0,0,1,0,0,NULL); +INSERT INTO Technology VALUES('TechOrdinary','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('TechCurtailment','p','energy',NULL,NULL,0,0,0,1,0,0,0,0,NULL); +INSERT INTO Technology VALUES('TechFlexNull','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('TechAnnualFlex','p','energy',NULL,NULL,0,1,0,0,0,1,0,0,NULL); +INSERT INTO Technology VALUES('TechEmbodied','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('TechEndOfLife','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); CREATE TABLE OutputCost ( scenario TEXT, diff --git a/tests/testing_data/emissions.sqlite b/tests/testing_data/emissions.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..2d7f7fd9d5bb80ad4943fbec895fcea20d6742f3 GIT binary patch literal 667648 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'); -INSERT INTO Technology VALUES('GeoThermal','p','residential','hydro','',0,1,0,0,0,0,0,'geothermal hot water source'); -INSERT INTO Technology VALUES('GeoHeater','p','residential','hydro','',0,0,0,0,0,0,0,'geothermal heater from geo hyd'); +INSERT INTO Technology VALUES('well','r','supply','water','',0,0,0,0,0,0,0,0,'plain old water'); +INSERT INTO Technology VALUES('bulbs','p','residential','electric','',0,0,0,0,0,0,0,0,'residential lighting'); +INSERT INTO Technology VALUES('EH','pb','electric','hydro','',0,0,1,1,1,0,0,0,'hydro power electric plant'); +INSERT INTO Technology VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0,0,'big battery'); +INSERT INTO Technology VALUES('EF','p','electric','electric','',0,0,0,0,0,0,0,0,'fusion plant'); +INSERT INTO Technology VALUES('EFL','p','electric','electric','',0,0,0,0,0,1,0,0,'linked (to Fusion) producer'); +INSERT INTO Technology VALUES('heater','p','residential','electric','',0,0,0,0,0,0,0,0,'heater'); +INSERT INTO Technology VALUES('FGF_pipe','p','transport',NULL,'',0,0,0,0,0,0,1,0,'transportation line A->B'); +INSERT INTO Technology VALUES('GeoThermal','p','residential','hydro','',0,1,0,0,0,0,0,0,'geothermal hot water source'); +INSERT INTO Technology VALUES('GeoHeater','p','residential','hydro','',0,0,0,0,0,0,0,0,'geothermal heater from geo hyd'); CREATE TABLE OutputCost ( scenario TEXT, diff --git a/tests/testing_data/mediumville.sqlite b/tests/testing_data/mediumville.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..8f4dfb6d7c278da0c74bc539d474d19af6e4495a GIT binary patch literal 667648 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 YA%Fk^2q1s}0tg_000Iagu(JaHKYN_c>Hq)$ literal 0 HcmV?d00001 diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index fe5c8f73c..5a4730456 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -936,23 +936,27 @@ INSERT INTO TimePeriod VALUES(2,2025,'f'); INSERT INTO TimePeriod VALUES(3,2030,'f'); CREATE TABLE TimeSeason ( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, season TEXT - PRIMARY KEY + REFERENCES TimeSeason (season), + notes TEXT, + PRIMARY KEY (period, sequence, season) ); -INSERT INTO TimeSeason VALUES('s1'); -INSERT INTO TimeSeason VALUES('s2'); -CREATE TABLE PeriodSeasons +INSERT INTO TimeSeason VALUES(2025,1,'s1',NULL); +INSERT INTO TimeSeason VALUES(2025,2,'s2',NULL); +CREATE TABLE IF NOT EXISTS TimeStorageSeason ( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, + storage_season TEXT, season TEXT REFERENCES TimeSeason (season), notes TEXT, - PRIMARY KEY (period, sequence, season) + PRIMARY KEY (period, sequence, storage_season, season) ); -INSERT INTO PeriodSeasons VALUES(2025,1,'s1',NULL); -INSERT INTO PeriodSeasons VALUES(2025,2,'s2',NULL); CREATE TABLE TimePeriodType ( label TEXT @@ -1011,13 +1015,14 @@ CREATE TABLE Technology retire INTEGER NOT NULL DEFAULT 0, flex INTEGER NOT NULL DEFAULT 0, exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('well','r','supply','water','',0,0,0,0,0,0,0,'plain old water'); -INSERT INTO Technology VALUES('bulbs','p','residential','electric','',0,0,0,0,0,0,0,' residential lighting'); -INSERT INTO Technology VALUES('EH','pb','electric','hydro','',0,0,0,0,0,0,0,'hydro power electric plant'); -INSERT INTO Technology VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0,'big battery'); +INSERT INTO Technology VALUES('well','r','supply','water','',0,0,0,0,0,0,0,0,'plain old water'); +INSERT INTO Technology VALUES('bulbs','p','residential','electric','',0,0,0,0,0,0,0,0,' residential lighting'); +INSERT INTO Technology VALUES('EH','pb','electric','hydro','',0,0,0,0,0,0,0,0,'hydro power electric plant'); +INSERT INTO Technology VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0,0,'big battery'); CREATE TABLE OutputCost ( scenario TEXT, diff --git a/tests/testing_data/storageville.sqlite b/tests/testing_data/storageville.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..414d8062ce2e24ca7af34996ff90e69e35f93961 GIT binary patch literal 667648 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%0A7WVsB@^P4D$T$i~?L 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 V0w4eaAOHd&00JNY0w4ea{{cLN^^5=j literal 0 HcmV?d00001 diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 327a4130f..12b5d6e69 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -24722,6 +24722,8 @@ "static" ], "RetiredCapacityVar_rptv": [], + "SeasonalStorageLevel_rpstv": [], + "SeasonalStorageUpperBoundConstraint_rpsdtv": [], "StorageConstraints_rpsdtv": [ [ "utopia", @@ -25591,6 +25593,7 @@ ] ], "TimeNext": [], + "TimeStorageSeason": [], "commodity_all": [ "ethos", "RH", @@ -25750,6 +25753,7 @@ "IMPOIL1" ], "tech_retirement": [], + "tech_seasonal_storage": [], "tech_storage": [ "E51" ], From 471ef8b6fa456089b79a208b64fd6619285f393e Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 13 Jun 2025 07:02:01 -0400 Subject: [PATCH 107/587] Fix some bugs in LDES but still not working right --- temoa/temoa_model/hybrid_loader.py | 7 ++++++- temoa/temoa_model/temoa_initialize.py | 13 +++++++------ temoa/temoa_model/temoa_model.py | 2 +- temoa/temoa_model/temoa_rules.py | 9 ++++++++- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 6484f7aa1..e7cde368e 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -434,7 +434,12 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N ).fetchall() else: raw = cur.execute('SELECT period, storage_season, season FROM main.TimeStorageSeason ORDER BY period, sequence').fetchall() - load_element(M.TimeStorageSeason, raw) + for row in raw: + load_indexed_set( + M.TimeStorageSeason, + index_value=row[0], + element=(row[1], row[2]) + ) # TimeSequencing time_sequencing = self.config.time_sequencing diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 8fd571e5f..14804a416 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1099,12 +1099,13 @@ def CreateTimeSequence(M: 'TemoaModel'): raise ValueError(msg) # Seasonal storage superimposed sequencing - for p, s_stor, s in M.TimeStorageSeason: - M.time_storage_season[p, s_stor] = s - if (p, s_stor, s) == M.TimeStorageSeason.last(): - M.time_next_storage_season[p, s_stor] = M.TimeStorageSeason.first()[1] - else: - M.time_next_storage_season[p, s_stor] = M.TimeStorageSeason.next((p, s_stor, s))[1] + for p, seasons in M.TimeStorageSeason.items(): + for (s_stor, s) in seasons: + M.time_storage_season[p, s_stor] = s + if (s_stor, s) == seasons.last(): + M.time_next_storage_season[p, s_stor] = seasons.first()[0] + else: + M.time_next_storage_season[p, s_stor] = seasons.next((s_stor, s))[0] msg += (' This behaviour can be changed using the ' 'time_sequencing parameter in the config file. ') diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 8a27c88bf..f7880e1ef 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -252,7 +252,7 @@ def __init__(M, *args, **kwargs): M.TimeSequencing = Set() # How do states carry between time segments? M.TimeNext = Set(ordered=True) # This is just to get data from the table. Hidden feature and usually not used M.validate_TimeNext = BuildAction(rule=validate_TimeNext) - M.TimeStorageSeason = Set(ordered=True) # Season sequence for seasonal storage + M.TimeStorageSeason = Set(M.time_optimize, ordered=True) # Season sequence for seasonal storage # Define demand- and resource-related parameters # Dev Note: There does not appear to be a DB table supporting DemandDefaultDistro. This does not diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index ab881ac72..93c7839ef 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1317,8 +1317,12 @@ def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_stor, t, v): stored_energy = charge - discharge s_stor_next = M.time_next_storage_season[p, s_stor] + s_next = M.time_storage_season[p, s_stor_next] - expr = M.V_SeasonalStorageLevel[r, p, s_stor, t, v] + stored_energy == M.V_SeasonalStorageLevel[r, p, s_stor_next, t, v] + start = M.V_SeasonalStorageLevel[r, p, s_stor, t, v] + M.V_StorageLevel[r, p, s, M.time_of_day.first(), t, v] + end = M.V_SeasonalStorageLevel[r, p, s_stor_next, t, v] + M.V_StorageLevel[r, p, s_next, M.time_of_day.first(), t, v] + + expr = start + stored_energy == end return expr @@ -1351,6 +1355,9 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): """ + if t in M.tech_seasonal_storage: + return Constraint.Skip # redundant on SeasonalStorageEnergyUpperBound + energy_capacity = ( M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) From bdb998f58399cb06009b1012ec6dfe2fb23fe188 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 13 Jun 2025 13:16:40 -0400 Subject: [PATCH 108/587] Trying to make sense of interseason storage boundaries --- temoa/temoa_model/temoa_rules.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 93c7839ef..88c221122 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1262,6 +1262,9 @@ def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): StorageLevel in the next time slice is equal to current StorageLevel plus net charge in the current time slice. """ + if d == M.time_of_day.last() and t in M.tech_seasonal_storage: + return Constraint.Skip # handled by SeasonalStorageEnergy_Constraint + # This is the sum of all input=i sent TO storage tech t of vintage v with # output=o in p,s,d charge = sum( @@ -1362,8 +1365,7 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * (value(M.StorageDuration[r, t]) / 8760) - * M.SegFracPerSeason[p, s] - * 365 + * value(M.SegFracPerSeason[p, s]) * 365 * value(M.ProcessLifeFrac[r, p, t, v]) ) @@ -1384,10 +1386,17 @@ def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_stor, d, M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * (value(M.StorageDuration[r, t]) / 8760) - * M.SegFracPerSeason[p, s] - * 365 * value(M.ProcessLifeFrac[r, p, t, v]) ) + + # this bit is tricky. A season can represent many days. Within each season, flows are multiplied + # by the number of days each season represents, and so the upper bound needs to be adjusted to + # allow day-scale flows. However, between seasons, whole-day charge deltas have built up, multiplied + # by the number of days that season represents. We carry multiple days' worth of deltas + # between seasons, so we need to cap the storage level at the inter-season boundary to the actual, + # unadjusted storage capacity, so we arent multiplying the charge carriable between seasons. + if d != M.time_of_day.first(): + energy_capacity *= value(M.SegFracPerSeason[p, s]) * 365 expr = M.V_SeasonalStorageLevel[r, p, s_stor, t, v] + M.V_StorageLevel[r, p, s, d, t, v] <= energy_capacity From e7b4318e2748018486d3cd7919fc40bb744dfd38 Mon Sep 17 00:00:00 2001 From: Ian David Elder Date: Sat, 14 Jun 2025 12:22:00 -0400 Subject: [PATCH 109/587] Get LDES working and add example db still needs testing and tidying --- data_files/example_dbs/ldes.sql | 1247 ++++++++++++++++++++++++ data_files/temoa_schema_v3_1.sql | 2 + temoa/temoa_model/hybrid_loader.py | 34 +- temoa/temoa_model/table_data_puller.py | 8 +- temoa/temoa_model/temoa_initialize.py | 16 +- temoa/temoa_model/temoa_model.py | 2 +- temoa/temoa_model/temoa_rules.py | 28 +- 7 files changed, 1298 insertions(+), 39 deletions(-) create mode 100644 data_files/example_dbs/ldes.sql diff --git a/data_files/example_dbs/ldes.sql b/data_files/example_dbs/ldes.sql new file mode 100644 index 000000000..5aeb1127d --- /dev/null +++ b/data_files/example_dbs/ldes.sql @@ -0,0 +1,1247 @@ +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE MetaData +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); +INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); +INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); +CREATE TABLE MetaDataReal +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); +CREATE TABLE OutputDualVariable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,d,generator,2000]',-0.085703001173645247945); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,d,demand,2000]',-0.00023042368874485079643); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,d,demand,2000]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,b,generator,2000]',-0.085357366392446838432); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,a,demand,2000]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,c,generator,2000]',-0.085703001174349608959); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,b,generator,2000]',-0.11558070679412910664); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,c,demand,2000]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,c,demand,2000]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,b,demand,2000]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,b,demand,2000]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,c,generator,2000]',-0.11558070712241454991); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,a,generator,2000]',-0.08535736638981534341); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,a,generator,2000]',-0.11558070668246853696); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,d,generator,2000]',-0.11558070724338096457); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,a,demand,2000]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityAvailableByPeriodAndTechConstraint[region,2000,seas_stor]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityAvailableByPeriodAndTechConstraint[region,2000,generator]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityAvailableByPeriodAndTechConstraint[region,2000,demand]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityAvailableByPeriodAndTechConstraint[region,2000,dly_stor]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','AdjustedCapacityConstraint[region,2000,seas_stor,2000]',-25.231393917561169004); +INSERT INTO OutputDualVariable VALUES('zulu','AdjustedCapacityConstraint[region,2000,demand,2000]',-0.25231393917561169004); +INSERT INTO OutputDualVariable VALUES('zulu','AdjustedCapacityConstraint[region,2000,dly_stor,2000]',-0.25231393917561169004); +INSERT INTO OutputDualVariable VALUES('zulu','AdjustedCapacityConstraint[region,2000,generator,2000]',-252.31393917561164563); +INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,charge,b,demand]',8.7443107076524206888); +INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,charge,c,demand]',8.7446563424276391174); +INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,charge,a,demand]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,discharge,a,demand]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,discharge,d,demand]',8.7747644720271349427); +INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,discharge,b,demand]',8.7745340480390616733); +INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,discharge,c,demand]',8.7745340482176992225); +INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,charge,d,demand]',8.7446563424269339037); +INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,charge,b,electricity]',4.4148340370215981565); +INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,charge,c,electricity]',4.4151796717968148087); +INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,discharge,a,electricity]',4.44505737729657735); +INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,charge,a,electricity]',4.4148340370189664838); +INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,discharge,d,electricity]',4.4450573777075668147); +INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,discharge,b,electricity]',4.4450573774082373645); +INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,discharge,c,electricity]',4.4450573775868758019); +INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,charge,d,electricity]',4.4151796717961104832); +INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyConstraint[region,2000,winter,seas_stor,2000]',-4.4329123900165026128); +INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyConstraint[region,2000,summer,seas_stor,2000]',-4.4329123900150158021); +INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,winter,c,seas_stor,2000]',-9.9285300719515330314e-13); +INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,winter,a,seas_stor,2000]',-2.2220266853952255203e-12); +INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,summer,d,seas_stor,2000]',-1.3760422345105398633e-12); +INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,winter,d,seas_stor,2000]',-7.7749544304990836351e-13); +INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,summer,c,seas_stor,2000]',-9.928636176739285446e-13); +INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,summer,a,seas_stor,2000]',-6.3758520034707890644e-13); +INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,winter,b,seas_stor,2000]',-1.3731094778566776959e-12); +INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,summer,b,seas_stor,2000]',-7.7654566423139437247e-13); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,c,seas_stor,2000]',6.4416949203073858853e-13); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,b,seas_stor,2000]',6.6523075894421745957e-13); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,b,seas_stor,2000]',-4.7138287749897429534e-13); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,c,dly_stor,2000]',4.4151796717729769881); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,b,dly_stor,2000]',4.4148340370445753322); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,a,dly_stor,2000]',4.4148340370562451084); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,a,seas_stor,2000]',8.1624677449077918112e-14); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,a,seas_stor,2000]',8.8939163809495713763e-14); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,d,dly_stor,2000]',4.415179671760228075); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,c,dly_stor,2000]',4.4450573775854937963); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,a,dly_stor,2000]',4.4450573773388573073); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,c,seas_stor,2000]',-5.821732668700695612e-13); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,b,dly_stor,2000]',4.4450573774107144942); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,d,dly_stor,2000]',4.4450573776637751777); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,charge,c,dly_stor,2000]',-0.00034563473280713847834); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,charge,b,dly_stor,2000]',-4.5045066420029851173e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,charge,a,dly_stor,2000]',-1.8570385267138625806e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,charge,d,dly_stor,2000]',-4.4825967675597020445e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,discharge,c,dly_stor,2000]',-1.7883284614710022175e-10); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,discharge,a,dly_stor,2000]',-3.7581557153964029183e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,discharge,b,dly_stor,2000]',-7.6405648911312447069e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,discharge,d,dly_stor,2000]',-8.2734689766129356769e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,c,seas_stor,2000]',-3.5654595609390025146e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,b,seas_stor,2000]',-3.565273019415246658e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,d,seas_stor,2000]',-3.5649814908001054014e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,b,seas_stor,2000]',-0.0019150055793566611583); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,c,dly_stor,2000]',-4.1883387800486087115e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,b,dly_stor,2000]',-1.2069762722145627176e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,a,dly_stor,2000]',-1.7983916895994889628e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,a,seas_stor,2000]',-3.5651827068338381998e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,a,seas_stor,2000]',-0.0019557996514695448198); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,d,dly_stor,2000]',-3.9485685665929972643e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,d,seas_stor,2000]',-0.0018038898687766034001); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,c,dly_stor,2000]',-5.2294209073905513207e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,a,dly_stor,2000]',-2.016437280362393114e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,c,seas_stor,2000]',-0.0017703732824977256754); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,b,dly_stor,2000]',-5.7797571613751692609e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,d,dly_stor,2000]',-3.87006737036306383e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,c,seas_stor,2000]',-7.0883085262919003355e-09); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,b,seas_stor,2000]',-7.1579661355912342912e-09); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,d,seas_stor,2000]',-7.3829319339268231203e-09); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,b,seas_stor,2000]',-3.5613176789246074882e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,c,dly_stor,2000]',-1.2349788608388929667e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,b,dly_stor,2000]',-4.1884293092433901861e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,a,dly_stor,2000]',-3.9481261846979931462e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,a,seas_stor,2000]',-7.1347346464973728785e-09); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,a,seas_stor,2000]',-3.5613135641518733898e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,d,dly_stor,2000]',-1.7515961681002181649e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,d,seas_stor,2000]',-3.5610586195680133947e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,c,dly_stor,2000]',-5.7082184017434425271e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,a,dly_stor,2000]',-3.8795740106759190268e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,c,seas_stor,2000]',-3.5610355629010550515e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,b,dly_stor,2000]',-5.1906403614485796538e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,d,dly_stor,2000]',-2.0711911733338417285e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,c,seas_stor,2000]',-1.5032898104432781849e-08); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,b,seas_stor,2000]',-1.4784579164256117067e-08); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,d,seas_stor,2000]',-1.4859608725011574925e-08); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,b,seas_stor,2000]',-0.0040183819650553598279); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,c,dly_stor,2000]',-1.5889638444455924215e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,b,dly_stor,2000]',-1.5380000139594174335e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,a,dly_stor,2000]',-2.2855346485298646541e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,a,seas_stor,2000]',-1.4696732922444764035e-08); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,a,seas_stor,2000]',-0.0039775878961343966722); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,d,dly_stor,2000]',-2.1971314167586482035e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,d,seas_stor,2000]',-0.0037838629015935030253); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,c,dly_stor,2000]',-8.1736320692959303357e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,a,dly_stor,2000]',-2.5498616661417998763e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,c,seas_stor,2000]',-0.0038173794865856454094); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,b,dly_stor,2000]',-8.2337089532251290791e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,d,dly_stor,2000]',-2.6432678697009204249e-11); +CREATE TABLE OutputObjective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +INSERT INTO OutputObjective VALUES('zulu','TotalCost',76813.228544347014192); +CREATE TABLE SectorLabel +( + sector TEXT, + PRIMARY KEY (sector) +); +INSERT INTO SectorLabel VALUES('electricity'); +CREATE TABLE CapacityCredit +( + region TEXT, + period INTEGER, + tech TEXT, + vintage INTEGER, + credit REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage), + CHECK (credit >= 0 AND credit <= 1) +); +CREATE TABLE CapacityFactorProcess +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE CapacityFactorTech +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech), + CHECK (factor >= 0 AND factor <= 1) +); +INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','a','generator',1.0,NULL); +INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','b','generator',1.0,NULL); +INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','c','generator',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','d','generator',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','a','generator',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','b','generator',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','c','generator',0.01,NULL); +INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','d','generator',0.01,NULL); +CREATE TABLE CapacityToActivity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + c2a REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +INSERT INTO CapacityToActivity VALUES('region','generator',8760.0,'MWh/MWy'); +INSERT INTO CapacityToActivity VALUES('region','dly_stor',8760.0,'MWh/MWy'); +INSERT INTO CapacityToActivity VALUES('region','seas_stor',8760.0,'MWh/MWy'); +INSERT INTO CapacityToActivity VALUES('region','demand',8760.0,'MWh/MWy'); +CREATE TABLE Commodity +( + name TEXT + PRIMARY KEY, + flag TEXT + REFERENCES CommodityType (label), + description TEXT +); +INSERT INTO Commodity VALUES('ethos','s',NULL); +INSERT INTO Commodity VALUES('electricity','p',NULL); +INSERT INTO Commodity VALUES('demand','d',NULL); +CREATE TABLE CommodityType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO CommodityType VALUES('p','physical commodity'); +INSERT INTO CommodityType VALUES('a','annual commodity'); +INSERT INTO CommodityType VALUES('e','emissions commodity'); +INSERT INTO CommodityType VALUES('d','demand commodity'); +INSERT INTO CommodityType VALUES('s','source commodity'); +INSERT INTO CommodityType VALUES('w','waste commodity'); +INSERT INTO CommodityType VALUES('wa','waste annual commodity'); +INSERT INTO CommodityType VALUES('wp','waste physical commodity'); +CREATE TABLE ConstructionInput +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); +CREATE TABLE CostEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT NOT NULL + REFERENCES Commodity (name), + cost REAL NOT NULL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE CostFixed +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE CostInvest +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +INSERT INTO CostInvest VALUES('region','generator',2000,1000.0,'',NULL); +INSERT INTO CostInvest VALUES('region','dly_stor',2000,1.0,'',NULL); +INSERT INTO CostInvest VALUES('region','seas_stor',2000,100.0,'',NULL); +INSERT INTO CostInvest VALUES('region','demand',2000,1.0,'',NULL); +CREATE TABLE CostVariable +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +INSERT INTO CostVariable VALUES('region',2000,'generator',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2000,'demand',2000,1.0,NULL,NULL); +CREATE TABLE Demand +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + commodity TEXT + REFERENCES Commodity (name), + demand REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, commodity) +); +INSERT INTO Demand VALUES('region',2000,'demand',8760.0,'MWh',NULL); +CREATE TABLE DemandSpecificDistribution +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + demand_name TEXT + REFERENCES Commodity (name), + dsd REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), + CHECK (dsd >= 0 AND dsd <= 1) +); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','a','demand',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','b','demand',0.05,NULL); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','c','demand',0.05,NULL); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','d','demand',0.1,NULL); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','a','demand',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','b','demand',0.2,NULL); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','c','demand',0.2,NULL); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','d','demand',0.4,NULL); +CREATE TABLE EndOfLifeOutput +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) +); +CREATE TABLE Efficiency +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +INSERT INTO Efficiency VALUES('region','ethos','generator',2000,'electricity',1.0,NULL); +INSERT INTO Efficiency VALUES('region','electricity','dly_stor',2000,'electricity',1.0,NULL); +INSERT INTO Efficiency VALUES('region','electricity','seas_stor',2000,'electricity',1.0,NULL); +INSERT INTO Efficiency VALUES('region','electricity','demand',2000,'demand',1.0,NULL); +CREATE TABLE EfficiencyVariable +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE EmissionActivity +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) +); +CREATE TABLE EmissionEmbodied +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE EmissionEndOfLife +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE ExistingCapacity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE TechGroup +( + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE LoanLifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE LifetimeProcess +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE LifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE Operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO Operator VALUES('e','equal to'); +INSERT INTO Operator VALUES('le','less than or equal to'); +INSERT INTO Operator VALUES('ge','greater than or equal to'); +CREATE TABLE LimitGrowthCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitDegrowthCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitGrowthNewCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitDegrowthNewCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitGrowthNewCapacityDelta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitDegrowthNewCapacityDelta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitStorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) +); +CREATE TABLE LimitActivity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE LimitActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE LimitAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, operator), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE LimitCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE LimitCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE LimitNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE LimitNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE LimitResource +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitSeasonalCapacityFactor +( + region TEXT + REFERENCES Region (region), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) +); +CREATE TABLE LimitTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +INSERT INTO OutputNetCapacity VALUES('zulu','region','electricity',2000,'seas_stor',2000,1.4392656320725425445); +INSERT INTO OutputNetCapacity VALUES('zulu','region','electricity',2000,'demand',2000,3.2000000000000001776); +INSERT INTO OutputNetCapacity VALUES('zulu','region','electricity',2000,'dly_stor',2000,4.2785306855583380425); +INSERT INTO OutputNetCapacity VALUES('zulu','region','electricity',2000,'generator',2000,3.0654425023163081043); +CREATE TABLE OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +INSERT INTO OutputBuiltCapacity VALUES('zulu','region','electricity','seas_stor',2000,1.4392656320725425445); +INSERT INTO OutputBuiltCapacity VALUES('zulu','region','electricity','demand',2000,3.2000000000000001776); +INSERT INTO OutputBuiltCapacity VALUES('zulu','region','electricity','generator',2000,3.0654425023163081043); +INSERT INTO OutputBuiltCapacity VALUES('zulu','region','electricity','dly_stor',2000,4.2785306855583380425); +CREATE TABLE OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','d','electricity','seas_stor',2000,'electricity',1.6658229082653559061); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','b','electricity','seas_stor',2000,'electricity',1575.9958575418115955); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','a','electricity','seas_stor',2000,'electricity',1575.9958579731961236); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','d','electricity','seas_stor',2000,'electricity',1575.9956575478158313); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','c','electricity','seas_stor',2000,'electricity',1.8910884059675414192); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','c','electricity','dly_stor',2000,'electricity',1204.7596747035338449); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','a','electricity','dly_stor',2000,'electricity',2618.5087591179661004); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','c','electricity','dly_stor',2000,'electricity',851.96387645265332366); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','b','electricity','dly_stor',2000,'electricity',2188.5411244155807963); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','c','electricity','seas_stor',2000,'electricity',1575.9956514181672204); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','b','electricity','seas_stor',2000,'electricity',1.798751859454663915); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','d','electricity','dly_stor',2000,'electricity',735.89264698708465317); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','a','electricity','seas_stor',2000,'electricity',1.7546442646897240535); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','a','electricity','dly_stor',2000,'electricity',2523.3859171065073923); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','d','electricity','dly_stor',2000,'electricity',719.1263802165781982); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','b','electricity','dly_stor',2000,'electricity',1363.0051112588996709); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','c','electricity','demand',2000,'demand',1752.0); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','d','electricity','demand',2000,'demand',3504.0); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','c','ethos','generator',2000,'electricity',33.566595265745142739); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','d','electricity','demand',2000,'demand',876.0); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','b','electricity','demand',2000,'demand',1752.0); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','a','ethos','generator',2000,'electricity',3356.6595399160439328); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','b','electricity','demand',2000,'demand',438.0); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','b','ethos','generator',2000,'electricity',3356.6595399162086899); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','d','ethos','generator',2000,'electricity',33.566595289722491735); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','a','ethos','generator',2000,'electricity',335.66595390483335847); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','d','ethos','generator',2000,'electricity',671.33190787721055414); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','b','ethos','generator',2000,'electricity',335.66595390600832971); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','c','ethos','generator',2000,'electricity',671.33190787684080547); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','c','electricity','demand',2000,'demand',438.0); +CREATE TABLE OutputFlowOut +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','d','electricity','seas_stor',2000,'electricity',1568.9482946398751295); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','d','electricity','seas_stor',2000,'electricity',5.895025229563088942e-05); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','c','electricity','seas_stor',2000,'electricity',1568.6232908987555845); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','c','electricity','dly_stor',2000,'electricity',1356.4608769452966008); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','a','electricity','dly_stor',2000,'electricity',714.83103160110816887); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','c','electricity','dly_stor',2000,'electricity',2194.6275577242486676); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','b','electricity','dly_stor',2000,'electricity',845.87743847871745828); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','c','electricity','seas_stor',2000,'electricity',6.2268121432416947413e-05); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','b','electricity','seas_stor',2000,'electricity',1569.3072056574608907); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','d','electricity','dly_stor',2000,'electricity',2516.5563377074744444); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','a','electricity','seas_stor',2000,'electricity',1569.7664178764727083); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','a','electricity','dly_stor',2000,'electricity',742.72223105128469811); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','d','electricity','dly_stor',2000,'electricity',2622.2773131962147097); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','b','electricity','dly_stor',2000,'electricity',1211.8307035541360239); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','c','electricity','demand',2000,'demand',1752.0); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','d','electricity','demand',2000,'demand',3504.0); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','c','ethos','generator',2000,'electricity',33.566595265745142739); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','d','electricity','demand',2000,'demand',876.0); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','b','electricity','demand',2000,'demand',1752.0); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','a','ethos','generator',2000,'electricity',3356.6595399160439328); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','b','electricity','demand',2000,'demand',438.0); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','b','ethos','generator',2000,'electricity',3356.6595399162086899); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','d','ethos','generator',2000,'electricity',33.566595289722491735); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','a','ethos','generator',2000,'electricity',335.66595390483335847); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','d','ethos','generator',2000,'electricity',671.33190787721055414); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','b','ethos','generator',2000,'electricity',335.66595390600832971); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','c','ethos','generator',2000,'electricity',671.33190787684080547); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','c','electricity','demand',2000,'demand',438.0); +CREATE TABLE OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'charge','c','dly_stor',2000,17.114122593311056341); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'charge','b','dly_stor',2000,9.7570613005062956091); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'charge','a','dly_stor',2000,0.0); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'charge','d','dly_stor',2000,9.7570613260688681123); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'discharge','c','dly_stor',2000,14.713232852985489884); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'discharge','a','dly_stor',2000,3.4537690983471556194); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'discharge','b','dly_stor',2000,13.884879934054414896); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'discharge','d','dly_stor',2000,13.881993388646614029); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'winter','a','seas_stor',2000,10085.458960857824894); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'winter','b','seas_stor',2000,8517.4471872485479906); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'winter','c','seas_stor',2000,6949.9387334479445499); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'winter','d','seas_stor',2000,5383.206530959131264); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'summer','a','seas_stor',2000,3798.7472513029865162); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'summer','b','seas_stor',2000,5374.7431051676910485); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'summer','c','seas_stor',2000,6950.7389591488673019); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'summer','d','seas_stor',2000,8526.734548299248928); +CREATE TABLE PlanningReserveMargin +( + region TEXT + PRIMARY KEY + REFERENCES Region (region), + margin REAL +); +CREATE TABLE RampDown +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE RampUp +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE Region +( + region TEXT + PRIMARY KEY, + notes TEXT +); +INSERT INTO Region VALUES('region',NULL); +CREATE TABLE TimeSegmentFraction +( + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + segfrac REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segfrac >= 0 AND segfrac <= 1) +); +INSERT INTO TimeSegmentFraction VALUES(2000,'charge','a',0.125,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'charge','b',0.125,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'charge','c',0.125,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'charge','d',0.125,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','a',0.125,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','b',0.125,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','c',0.125,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','d',0.125,NULL); +CREATE TABLE StorageDuration +( + region TEXT, + tech TEXT, + duration REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +INSERT INTO StorageDuration VALUES('region','dly_stor',4.0,NULL); +INSERT INTO StorageDuration VALUES('region','seas_stor',8760.0,NULL); +CREATE TABLE TechnologyType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO TechnologyType VALUES('r','resource technology'); +INSERT INTO TechnologyType VALUES('p','production technology'); +INSERT INTO TechnologyType VALUES('pb','baseload production technology'); +INSERT INTO TechnologyType VALUES('ps','storage production technology'); +CREATE TABLE TimeOfDay +( + sequence INTEGER UNIQUE, + tod TEXT + PRIMARY KEY +); +INSERT INTO TimeOfDay VALUES(0,'a'); +INSERT INTO TimeOfDay VALUES(1,'b'); +INSERT INTO TimeOfDay VALUES(2,'c'); +INSERT INTO TimeOfDay VALUES(3,'d'); +CREATE TABLE TimePeriod +( + sequence INTEGER UNIQUE, + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES TimePeriodType (label) +); +INSERT INTO TimePeriod VALUES(0,2000,'f'); +INSERT INTO TimePeriod VALUES(1,2005,'f'); +CREATE TABLE TimeSeason +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT, + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +INSERT INTO TimeSeason VALUES(2000,0,'charge',NULL); +INSERT INTO TimeSeason VALUES(2000,1,'discharge',NULL); +CREATE TABLE TimePeriodType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO TimePeriodType VALUES('e','existing vintages'); +INSERT INTO TimePeriodType VALUES('f','future'); +CREATE TABLE OutputEmission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE RPSRequirement +( + region TEXT NOT NULL + REFERENCES Region (region), + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech_group TEXT NOT NULL + REFERENCES TechGroup (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE TechGroupMember +( + group_name TEXT + REFERENCES TechGroup (group_name), + tech TEXT + REFERENCES Technology (tech), + PRIMARY KEY (group_name, tech) +); +CREATE TABLE Technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES TechnologyType (label) +); +INSERT INTO Technology VALUES('generator','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('dly_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('seas_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,1,NULL); +INSERT INTO Technology VALUES('demand','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +CREATE TABLE OutputCost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES TimePeriod (period), + FOREIGN KEY (tech) REFERENCES Technology (tech) +); +INSERT INTO OutputCost VALUES('zulu','region','electricity',2000,'demand',2000,0.80740460536195755025,0.0,37926.215634726010428,0.0,0.51801829986182648113,0.0,43800.0,0.0); +INSERT INTO OutputCost VALUES('zulu','region','electricity',2000,'dly_stor',2000,1.0795329311569543673,0.0,0.0,0.0,0.69261162238737030705,0.0,0.0,0.0); +INSERT INTO OutputCost VALUES('zulu','region','electricity',2000,'generator',2000,773.45387307577189162,0.0,38075.357420893887194,0.0,496.23603542939909161,0.0,43972.239969763071698,0.0); +INSERT INTO OutputCost VALUES('zulu','region','electricity',2000,'seas_stor',2000,36.314678114829974653,0.0,0.0,0.0,23.298935492992982609,0.0,0.0,0.0); +CREATE TABLE TimeStorageSeason +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + storage_season TEXT, + season TEXT + REFERENCES TimeSeason (season), + count INT NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, storage_season, season) + CHECK (count > 0) +); +INSERT INTO TimeStorageSeason VALUES(2000,1,'summer','charge',182,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,3,'winter','discharge',183,NULL); +COMMIT; diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index f1cbaacff..c93fa5c9b 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -926,8 +926,10 @@ CREATE TABLE IF NOT EXISTS TimeStorageSeason storage_season TEXT, season TEXT REFERENCES TimeSeason (season), + count INT NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, storage_season, season) + CHECK (count > 0) ); CREATE TABLE IF NOT EXISTS TimePeriodType ( diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index e7cde368e..fd53268f0 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -398,6 +398,19 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N logger.warning('No TimeOfDay table found. Loading a single filler time of day "D" (assume this is an annual model)') load_element(M.time_of_day, [('D',)]) + all_seasons = set() # includes all regular and virtual seasonal storage seasons + if self.table_exists("TimeStorageSeason"): + if mi: + raw = cur.execute( + 'SELECT period, storage_season, season, count FROM main.TimeStorageSeason WHERE' + ' period >= ? AND period <= ? ORDER BY period, sequence', + (mi.base_year, mi.last_demand_year) + ).fetchall() + else: + raw = cur.execute('SELECT period, storage_season, season, count FROM main.TimeStorageSeason ORDER BY period, sequence').fetchall() + all_seasons = all_seasons | set((row[1],) for row in raw) + load_element(M.TimeStorageSeason, raw) + # TimeSeason if self.table_exists("TimeSeason"): if mi: @@ -414,7 +427,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N index_value=row[0], element=row[1] ) - load_element(M.time_season_all, list(set((row[1],) for row in raw))) # unique seasons into time_season_all set + all_seasons = all_seasons | set((row[1],) for row in raw) else: for period in time_optimize: load_indexed_set( @@ -423,23 +436,8 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N element='S' ) logger.warning('No TimeSeason table found. Loading a single filler season "S" (assume this is an annual model)') - load_element(M.time_season_all, [('S',)]) - - if self.table_exists("TimeStorageSeason"): - if mi: - raw = cur.execute( - 'SELECT period, storage_season, season FROM main.TimeStorageSeason WHERE' - ' period >= ? AND period <= ? ORDER BY period, sequence', - (mi.base_year, mi.last_demand_year) - ).fetchall() - else: - raw = cur.execute('SELECT period, storage_season, season FROM main.TimeStorageSeason ORDER BY period, sequence').fetchall() - for row in raw: - load_indexed_set( - M.TimeStorageSeason, - index_value=row[0], - element=(row[1], row[2]) - ) + all_seasons.add(('S',)) + load_element(M.time_season_all, list(all_seasons)) # TimeSequencing time_sequencing = self.config.time_sequencing diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index 5371c1ac7..491fe8fc2 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -241,9 +241,11 @@ def poll_storage_level_results(M: TemoaModel, epsilon=1e-5) -> dict[SLI, float]: res: dict[SLI, float] = defaultdict(float) # Storage level, the state variable for all but last time slice of each season - for sli in M.StorageLevel_rpsdtv: - state = value(M.V_StorageLevel[sli]) - sli = SLI(*sli) + for r, p, s, d, t, v in M.StorageLevel_rpsdtv: + if t in M.tech_seasonal_storage: + continue + state = value(M.V_StorageLevel[r, p, s, d, t, v]) / (value(M.SegFracPerSeason[p, s]) * 365) + sli = SLI(r, p, s, d, t, v) if abs(state) < epsilon: state = 0 # still want to know but decimals are ugly res[sli] = state diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 14804a416..f96c5593e 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1099,13 +1099,19 @@ def CreateTimeSequence(M: 'TemoaModel'): raise ValueError(msg) # Seasonal storage superimposed sequencing - for p, seasons in M.TimeStorageSeason.items(): - for (s_stor, s) in seasons: + for p in M.time_optimize: + seasons = [ + (s_stor, s) + for _p, s_stor, s in M.TimeStorageSeason + if _p == p + ] + for i, (s_stor, s) in enumerate(seasons): + s_stor, s = seasons[i] M.time_storage_season[p, s_stor] = s - if (s_stor, s) == seasons.last(): - M.time_next_storage_season[p, s_stor] = seasons.first()[0] + if (s_stor, s) == seasons[-1]: + M.time_next_storage_season[p, s_stor] = seasons[0][0] else: - M.time_next_storage_season[p, s_stor] = seasons.next((s_stor, s))[0] + M.time_next_storage_season[p, s_stor] = seasons[i+1][0] msg += (' This behaviour can be changed using the ' 'time_sequencing parameter in the config file. ') diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index f7880e1ef..2fc48a9e5 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -252,7 +252,7 @@ def __init__(M, *args, **kwargs): M.TimeSequencing = Set() # How do states carry between time segments? M.TimeNext = Set(ordered=True) # This is just to get data from the table. Hidden feature and usually not used M.validate_TimeNext = BuildAction(rule=validate_TimeNext) - M.TimeStorageSeason = Set(M.time_optimize, ordered=True) # Season sequence for seasonal storage + M.TimeStorageSeason = Param(M.time_optimize, M.time_season_all, M.time_season_all) # Season sequence for seasonal storage # Define demand- and resource-related parameters # Dev Note: There does not appear to be a DB table supporting DemandDefaultDistro. This does not diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 88c221122..be40168d4 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1317,7 +1317,9 @@ def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_stor, t, v): for d in M.time_of_day ) - stored_energy = charge - discharge + # The virtual season delta is the actual season delta, adjusted to actual DAILY delta + # times the number of those delta between these virtual seasons + stored_energy = (charge - discharge) / (M.SegFracPerSeason[p, s] * 365) * value(M.TimeStorageSeason[p, s_stor, s]) s_stor_next = M.time_next_storage_season[p, s_stor] s_next = M.time_storage_season[p, s_stor_next] @@ -1376,8 +1378,19 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_stor, d, t, v): r""" - Builds off of StorageEnergyUpperBound_Constraint. Enforces the max charge capacity of seasonal storage, - summing the superimposed real storage level with the virtual seasonal storage level. + Builds off of StorageEnergyUpperBound_Constraint. Enforces the max charge capacity + of seasonal storage, summing the superimposed real storage level with the virtual + seasonal storage level. A season can represent many days. Within each season, flows + are multiplied by the number of days each season represents, and so the upper bound + needs to be adjusted to allow day-scale flows (e.g., charge in the morning, discharge + in the afternoon). However, between seasons, whole-day charge deltas have built up, + multiplied by the number of days the season represents. These deltas stack, + possibly exceeding our upper bound by a factor of (N-1)/N where N is the number of + days the season represents. Additionally, if we allowed these stacked deltas to + carry between seasons then we would be multiplying the effective energy capacity of + the storage. So, we do not adjust the bound for seasonal storage. Seasonal storage + therefore cannot do much arbitrage within each season, but can carry energy between + seasons. """ s = M.time_storage_season[p, s_stor] @@ -1388,15 +1401,6 @@ def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_stor, d, * (value(M.StorageDuration[r, t]) / 8760) * value(M.ProcessLifeFrac[r, p, t, v]) ) - - # this bit is tricky. A season can represent many days. Within each season, flows are multiplied - # by the number of days each season represents, and so the upper bound needs to be adjusted to - # allow day-scale flows. However, between seasons, whole-day charge deltas have built up, multiplied - # by the number of days that season represents. We carry multiple days' worth of deltas - # between seasons, so we need to cap the storage level at the inter-season boundary to the actual, - # unadjusted storage capacity, so we arent multiplying the charge carriable between seasons. - if d != M.time_of_day.first(): - energy_capacity *= value(M.SegFracPerSeason[p, s]) * 365 expr = M.V_SeasonalStorageLevel[r, p, s_stor, t, v] + M.V_StorageLevel[r, p, s, d, t, v] <= energy_capacity From 7e8dcbe71464ed857a4988eef6f75cae2379a856 Mon Sep 17 00:00:00 2001 From: Ian David Elder Date: Sat, 14 Jun 2025 16:50:05 -0400 Subject: [PATCH 110/587] Generalise to non-annual periods --- temoa/temoa_model/hybrid_loader.py | 12 +++++++++++ temoa/temoa_model/table_data_puller.py | 2 +- temoa/temoa_model/temoa_model.py | 1 + temoa/temoa_model/temoa_rules.py | 28 +++++++++++++------------- temoa/utilities/unit_cost_explorer.py | 2 +- tests/test_storage.py | 3 +-- 6 files changed, 30 insertions(+), 18 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index fd53268f0..d25ba0cb8 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -481,6 +481,18 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N raise ValueError('No myopic_base_year found in MetaData table.') data[M.MyopicBaseyear.name] = {None: int(raw[0][0])} + # days_per_season + raw = cur.execute( + "SELECT value from MetaData WHERE element == 'days_per_season'" + ).fetchall() + if not raw: + logger.warning( + 'No value found for days_per_period in the MetaData table. ' + 'Assuming this is an annual database (365 day periods)' + ) + raw = [(365,)] + data[M.DaysPerPeriod.name] = {None: int(raw[0][0])} + # === REGION SETS === # regions diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index 491fe8fc2..d0a112fea 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -244,7 +244,7 @@ def poll_storage_level_results(M: TemoaModel, epsilon=1e-5) -> dict[SLI, float]: for r, p, s, d, t, v in M.StorageLevel_rpsdtv: if t in M.tech_seasonal_storage: continue - state = value(M.V_StorageLevel[r, p, s, d, t, v]) / (value(M.SegFracPerSeason[p, s]) * 365) + state = value(M.V_StorageLevel[r, p, s, d, t, v]) / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) sli = SLI(r, p, s, d, t, v) if abs(state) < epsilon: state = 0 # still want to know but decimals are ugly res[sli] = state diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 2fc48a9e5..7d37b6f2b 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -499,6 +499,7 @@ def __init__(M, *args, **kwargs): M.EmissionEndOfLife = Param(M.regions, M.commodity_emissions, M.tech_with_capacity, M.vintage_all) M.MyopicBaseyear = Param(default=0) + M.DaysPerPeriod = Param() ################################################ # Model Variables # diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index be40168d4..c4f809a9d 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1319,7 +1319,11 @@ def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_stor, t, v): # The virtual season delta is the actual season delta, adjusted to actual DAILY delta # times the number of those delta between these virtual seasons - stored_energy = (charge - discharge) / (M.SegFracPerSeason[p, s] * 365) * value(M.TimeStorageSeason[p, s_stor, s]) + stored_energy = ( + (charge - discharge) + / (M.SegFracPerSeason[p, s] * M.DaysPerPeriod) # number of days in the actual season + * value(M.TimeStorageSeason[p, s_stor, s]) # number of days in the virtual season + ) s_stor_next = M.time_next_storage_season[p, s_stor] s_next = M.time_storage_season[p, s_stor_next] @@ -1343,7 +1347,7 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): by the number of hours in a year to obtain the duration as a fraction of the year. Since the :math:`C2A` parameter assumes the conversion of capacity to annual activity, we need to express the storage duration as fraction of a year. Then, :math:`SEG_{s,d}` - summed over the time-of-day slices (:math:`d`) multiplied by 365 days / yr yields the + summed over the time-of-day slices (:math:`d`) multiplied by M.DaysPerPeriod yields the number of days per season. This step is necessary because conventional time sliced models use a single day to represent many days within a given season. Thus, it is necessary to scale the storage duration to account for the number of days in each season. @@ -1353,7 +1357,7 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): \textbf{SL}_{r, p, s, d, t, v} \le \textbf{CAP}_{r,t,v} \cdot C2A_{r,t} \cdot \frac {SD_{r,t}}{8760 hrs/yr} - \cdot \sum_{d} SEG_{s,d} \cdot 365 days/yr + \cdot \sum_{d} SEG_{s,d} \cdot M.DaysPerPeriod \\ \forall \{r, p, s, d, t, v\} \in \Theta_{\text{StorageEnergyUpperBound}} @@ -1367,7 +1371,7 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * (value(M.StorageDuration[r, t]) / 8760) - * value(M.SegFracPerSeason[p, s]) * 365 + * value(M.SegFracPerSeason[p, s]) * M.DaysPerPeriod * value(M.ProcessLifeFrac[r, p, t, v]) ) @@ -1545,7 +1549,7 @@ def LimitStorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v, op): \ SF_{r,p,s,d,t,v} \cdot \textbf{CAP}_{r,p,t,v} \cdot C2A_{r,t} \cdot \frac {SD_{r,t}}{8760 hrs/yr} - \cdot \sum_{d} SEG_{s,d} \cdot 365 days/yr \cdot MPL_{r,p,t,v} + \cdot \sum_{d} SEG_{s,d} \cdot M.DaysPerPeriod days/yr \cdot MPL_{r,p,t,v} \\ \forall \{r, p, s, d, t, v\} \in \Theta_{\text{LimitStorageFraction}} @@ -1555,8 +1559,7 @@ def LimitStorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v, op): M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * (value(M.StorageDuration[r, t]) / 8760) - * M.SegFracPerSeason[p, s] - * 365 + * M.SegFracPerSeason[p, s] * M.DaysPerPeriod * value(M.ProcessLifeFrac[r, p, t, v]) ) @@ -1628,7 +1631,7 @@ def RampUp_Constraint(M: 'TemoaModel', r, p, s, d, t, v): ) / value(M.SegFrac[p, s_next, d_next]) hours_elapsed = 8760 * ( value(M.SegFrac[p, s, d]) + value(M.SegFrac[p, s_next, d_next]) ) / 2 - hours_elapsed /= M.SegFracPerSeason[p, s] * 365 # adjust for how many days this season represents + hours_elapsed /= M.SegFracPerSeason[p, s] * M.DaysPerPeriod # adjust for how many days this season represents ramp_fraction = hours_elapsed * value(M.RampUp[r, t]) if ramp_fraction >= 1: @@ -1686,7 +1689,7 @@ def RampDown_Constraint(M: 'TemoaModel', r, p, s, d, t, v): ) / value(M.SegFrac[p, s_next, d_next]) hours_elapsed = 8760 * ( value(M.SegFrac[p, s, d]) + value(M.SegFrac[p, s_next, d_next]) ) / 2 - hours_elapsed /= M.SegFracPerSeason[p, s] * 365 # adjust for how many days this season represents + hours_elapsed /= M.SegFracPerSeason[p, s] * M.DaysPerPeriod # adjust for how many days this season represents ramp_fraction = hours_elapsed * value(M.RampDown[r, t]) if ramp_fraction >= 1: @@ -2384,13 +2387,13 @@ def LimitActivity_Constraint(M: 'TemoaModel', r, p, t, op): # # The V_FlowOut variable is scaled by the weights of each season. # # In order to determine the daily flow, the V_FlowOut variable # # must be converted back to its un-scaled value. We do this by dividing the -# # V_FlowOut value by M.SegFracPerSeason[p, s, d]*365 (how many days are in this season). +# # V_FlowOut value by M.SegFracPerSeason[p, s, d] * M.DaysPerPeriod (how many days are in this season). # regions = gather_group_regions(M, r) # try: # activity_rpst = sum( -# M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] / (value(M.SegFracPerSeason[p, s, d])*365) +# M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] / (value(M.SegFracPerSeason[p, s, d]) * M.DaysPerPeriod) # for _r in regions # for S_v in M.processVintages[_r, p, t] # for S_i in M.processInputs[_r, p, t, S_v] @@ -2942,9 +2945,6 @@ def LimitSeasonalCapacityFactor_Constraint(M: 'TemoaModel', r, p, s, t, op): ): return Constraint.Skip - # The V_FlowOut variable is scaled by the number of days in the season. - # To adjust for this, we divide by M.SegFracPerSeason[p, s, d]*365, - # the number of days this season represents. if t not in M.tech_annual: activity_rpst = sum( M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] diff --git a/temoa/utilities/unit_cost_explorer.py b/temoa/utilities/unit_cost_explorer.py index c33552cd7..94fd8fc9c 100644 --- a/temoa/utilities/unit_cost_explorer.py +++ b/temoa/utilities/unit_cost_explorer.py @@ -125,7 +125,7 @@ print('The storage level constraint for the single period in the "super day":\n', upper_limit) # cross-check the multiplier... -mulitplier = storage_dur * M.SegFracPerSeason['winter'] * 365 * c2a * c +mulitplier = storage_dur * M.SegFracPerSeason[2020, 'winter'] * M.DaysPerPeriod * c2a * c print(f'The multiplier for the storage should be: {mulitplier}') M.StorageEnergyUpperBoundConstraint.construct() diff --git a/tests/test_storage.py b/tests/test_storage.py index 3b214536c..9c8cdc16c 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -49,8 +49,7 @@ def test_storage_fraction(system_test_run): * model.V_Capacity[r, p, t, v].value * model.CapacityToActivity[r, t] * (model.StorageDuration[r, t] / 8760) - * model.SegFracPerSeason[p, s] - * 365 + * model.SegFracPerSeason[p, s] * model.DaysPerPeriod * model.ProcessLifeFrac[r, p, t, v] ) From 701ca66ebe5815e050382a6d32e775e0f03018ae Mon Sep 17 00:00:00 2001 From: Ian David Elder Date: Sat, 14 Jun 2025 17:49:21 -0400 Subject: [PATCH 111/587] Add a validator on TimeStorageSeason --- temoa/temoa_model/hybrid_loader.py | 6 +-- .../temoa_model/model_checking/validators.py | 41 ++++++++++++++++++- temoa/temoa_model/temoa_model.py | 4 +- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index d25ba0cb8..68cca16b9 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -483,12 +483,12 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # days_per_season raw = cur.execute( - "SELECT value from MetaData WHERE element == 'days_per_season'" + "SELECT value from MetaData WHERE element == 'days_per_period'" ).fetchall() if not raw: - logger.warning( + logger.info( 'No value found for days_per_period in the MetaData table. ' - 'Assuming this is an annual database (365 day periods)' + 'Assuming this is an annual database (365 days per period)' ) raw = [(365,)] data[M.DaysPerPeriod.name] = {None: int(raw[0][0])} diff --git a/temoa/temoa_model/model_checking/validators.py b/temoa/temoa_model/model_checking/validators.py index 4aab12ff2..04d4a8368 100644 --- a/temoa/temoa_model/model_checking/validators.py +++ b/temoa/temoa_model/model_checking/validators.py @@ -31,7 +31,7 @@ from typing import TYPE_CHECKING import deprecated -from pyomo.environ import NonNegativeReals +from pyomo.environ import NonNegativeReals, value if TYPE_CHECKING: from temoa.temoa_model.temoa_model import TemoaModel @@ -305,6 +305,45 @@ def validate_Efficiency(M: 'TemoaModel', val, r, si, t, v, so) -> bool: return False +def validate_StorageSeason(M: 'TemoaModel'): + storage = dict() + for p, s_stor, s in M.TimeStorageSeason: + if (p, s) not in storage: + storage[p, s] = 0 + storage[p, s] += value(M.TimeStorageSeason[p, s_stor, s]) + if abs(sum(storage.values()) - value(M.DaysPerPeriod)) >= 0.001: + logger.warning( + f'Sum of day count in TimeStorageSeason ({sum(storage.values())}) ' + f'does not sum to days_per_season ({value(M.DaysPerPeriod)}) from the ' + 'MetaData table.' + ) + for (p, s) in storage: + if (p, s) not in M.SegFracPerSeason: + msg = ( + f'Period-season index {(p, s)} referenced in TimeStorageSeason that ' + 'does not exist in TimeSegmentFraction.' + ) + logger.error(msg) + raise ValueError(msg) + for (p, s) in M.SegFracPerSeason: + if s not in M.time_season[p]: + continue + if (p, s) not in storage: + msg = (f'Period-season index {(p, s)} absent from TimeStorageSeason') + logger.warning(msg) + segfrac = value(M.SegFracPerSeason[p, s]) + segfracstorage = storage[p, s] / value(M.DaysPerPeriod) + if abs(segfrac - segfracstorage) >= 0.001: + msg = ( + 'Discrepancy of seasonal composition between ' + 'TimeSegmentFraction and TimeStorageSeason. Fraction of each ' + 'period assigned to each season should match: ' + f'TimeSegmentFraction: {(p, s, value(M.SegFracPerSeason[p, s]))}' + f', TimeStorageSeason: {(p, s, segfracstorage)}' + ) + logger.warning(msg) + + def validate_tech_sets(M: 'TemoaModel'): """ Check tech sets for any forbidden intersections diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 7d37b6f2b..590d7e4aa 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -42,6 +42,7 @@ validate_Efficiency, validate_tech_sets, no_slash_or_pipe, + validate_StorageSeason, ) from temoa.temoa_model.temoa_initialize import * from temoa.temoa_model.temoa_initialize import get_loan_life @@ -252,7 +253,6 @@ def __init__(M, *args, **kwargs): M.TimeSequencing = Set() # How do states carry between time segments? M.TimeNext = Set(ordered=True) # This is just to get data from the table. Hidden feature and usually not used M.validate_TimeNext = BuildAction(rule=validate_TimeNext) - M.TimeStorageSeason = Param(M.time_optimize, M.time_season_all, M.time_season_all) # Season sequence for seasonal storage # Define demand- and resource-related parameters # Dev Note: There does not appear to be a DB table supporting DemandDefaultDistro. This does not @@ -654,6 +654,8 @@ def __init__(M, *args, **kwargs): # We make use of this following set in some of the storage constraints. # Pre-computing it is considerably faster. M.SegFracPerSeason = Param(M.time_optimize, M.time_season_all, initialize=SegFracPerSeason_rule) + M.TimeStorageSeason = Param(M.time_optimize, M.time_season_all, M.time_season_all) + M.validate_StorageSeason = BuildAction(rule=validate_StorageSeason) M.SeasonalStorageEnergyConstraint = Constraint( M.SeasonalStorageLevel_rpstv, rule=SeasonalStorageEnergy_Constraint From 3ca7231b6daec739b663d8500c4944a5f4e2e69b Mon Sep 17 00:00:00 2001 From: Ian David Elder Date: Sun, 15 Jun 2025 10:12:47 -0400 Subject: [PATCH 112/587] Add default storage seasons and update tests and databases --- data_files/example_dbs/ldes.sql | 2495 +++++++++-------- data_files/example_dbs/materials.sql | 14 + data_files/example_dbs/morris_utopia.sql | 14 + data_files/example_dbs/stepped_demand.sql | 7 +- data_files/example_dbs/test_system.sql | 7 +- data_files/example_dbs/utopia.sql | 7 +- data_files/temoa_schema_v3_1.sql | 6 +- temoa/temoa_model/hybrid_loader.py | 93 +- .../temoa_model/model_checking/validators.py | 23 +- temoa/temoa_model/temoa_initialize.py | 21 +- temoa/temoa_model/temoa_model.py | 15 +- tests/testing_data/emissions.sql | 7 +- tests/testing_data/materials.sql | 7 +- tests/testing_data/mediumville.sql | 7 +- tests/testing_data/mediumville_sets.json | 1 - tests/testing_data/simple_linked_tech.sql | 7 +- tests/testing_data/storageville.sql | 7 +- tests/testing_data/test_system.sql | 7 +- tests/testing_data/test_system_sets.json | 1 - tests/testing_data/utopia.sql | 7 +- tests/testing_data/utopia_sets.json | 1 - 21 files changed, 1419 insertions(+), 1335 deletions(-) diff --git a/data_files/example_dbs/ldes.sql b/data_files/example_dbs/ldes.sql index 5aeb1127d..b318b87ae 100644 --- a/data_files/example_dbs/ldes.sql +++ b/data_files/example_dbs/ldes.sql @@ -1,1247 +1,1248 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE MetaData -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); -INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); -CREATE TABLE MetaDataReal -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); -CREATE TABLE OutputDualVariable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,d,generator,2000]',-0.085703001173645247945); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,d,demand,2000]',-0.00023042368874485079643); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,d,demand,2000]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,b,generator,2000]',-0.085357366392446838432); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,a,demand,2000]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,c,generator,2000]',-0.085703001174349608959); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,b,generator,2000]',-0.11558070679412910664); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,c,demand,2000]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,c,demand,2000]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,b,demand,2000]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,b,demand,2000]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,c,generator,2000]',-0.11558070712241454991); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,a,generator,2000]',-0.08535736638981534341); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,a,generator,2000]',-0.11558070668246853696); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,d,generator,2000]',-0.11558070724338096457); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,a,demand,2000]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityAvailableByPeriodAndTechConstraint[region,2000,seas_stor]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityAvailableByPeriodAndTechConstraint[region,2000,generator]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityAvailableByPeriodAndTechConstraint[region,2000,demand]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityAvailableByPeriodAndTechConstraint[region,2000,dly_stor]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','AdjustedCapacityConstraint[region,2000,seas_stor,2000]',-25.231393917561169004); -INSERT INTO OutputDualVariable VALUES('zulu','AdjustedCapacityConstraint[region,2000,demand,2000]',-0.25231393917561169004); -INSERT INTO OutputDualVariable VALUES('zulu','AdjustedCapacityConstraint[region,2000,dly_stor,2000]',-0.25231393917561169004); -INSERT INTO OutputDualVariable VALUES('zulu','AdjustedCapacityConstraint[region,2000,generator,2000]',-252.31393917561164563); -INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,charge,b,demand]',8.7443107076524206888); -INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,charge,c,demand]',8.7446563424276391174); -INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,charge,a,demand]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,discharge,a,demand]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,discharge,d,demand]',8.7747644720271349427); -INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,discharge,b,demand]',8.7745340480390616733); -INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,discharge,c,demand]',8.7745340482176992225); -INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,charge,d,demand]',8.7446563424269339037); -INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,charge,b,electricity]',4.4148340370215981565); -INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,charge,c,electricity]',4.4151796717968148087); -INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,discharge,a,electricity]',4.44505737729657735); -INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,charge,a,electricity]',4.4148340370189664838); -INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,discharge,d,electricity]',4.4450573777075668147); -INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,discharge,b,electricity]',4.4450573774082373645); -INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,discharge,c,electricity]',4.4450573775868758019); -INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,charge,d,electricity]',4.4151796717961104832); -INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyConstraint[region,2000,winter,seas_stor,2000]',-4.4329123900165026128); -INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyConstraint[region,2000,summer,seas_stor,2000]',-4.4329123900150158021); -INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,winter,c,seas_stor,2000]',-9.9285300719515330314e-13); -INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,winter,a,seas_stor,2000]',-2.2220266853952255203e-12); -INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,summer,d,seas_stor,2000]',-1.3760422345105398633e-12); -INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,winter,d,seas_stor,2000]',-7.7749544304990836351e-13); -INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,summer,c,seas_stor,2000]',-9.928636176739285446e-13); -INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,summer,a,seas_stor,2000]',-6.3758520034707890644e-13); -INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,winter,b,seas_stor,2000]',-1.3731094778566776959e-12); -INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,summer,b,seas_stor,2000]',-7.7654566423139437247e-13); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,c,seas_stor,2000]',6.4416949203073858853e-13); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,b,seas_stor,2000]',6.6523075894421745957e-13); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,b,seas_stor,2000]',-4.7138287749897429534e-13); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,c,dly_stor,2000]',4.4151796717729769881); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,b,dly_stor,2000]',4.4148340370445753322); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,a,dly_stor,2000]',4.4148340370562451084); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,a,seas_stor,2000]',8.1624677449077918112e-14); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,a,seas_stor,2000]',8.8939163809495713763e-14); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,d,dly_stor,2000]',4.415179671760228075); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,c,dly_stor,2000]',4.4450573775854937963); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,a,dly_stor,2000]',4.4450573773388573073); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,c,seas_stor,2000]',-5.821732668700695612e-13); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,b,dly_stor,2000]',4.4450573774107144942); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,d,dly_stor,2000]',4.4450573776637751777); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,charge,c,dly_stor,2000]',-0.00034563473280713847834); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,charge,b,dly_stor,2000]',-4.5045066420029851173e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,charge,a,dly_stor,2000]',-1.8570385267138625806e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,charge,d,dly_stor,2000]',-4.4825967675597020445e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,discharge,c,dly_stor,2000]',-1.7883284614710022175e-10); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,discharge,a,dly_stor,2000]',-3.7581557153964029183e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,discharge,b,dly_stor,2000]',-7.6405648911312447069e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,discharge,d,dly_stor,2000]',-8.2734689766129356769e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,c,seas_stor,2000]',-3.5654595609390025146e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,b,seas_stor,2000]',-3.565273019415246658e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,d,seas_stor,2000]',-3.5649814908001054014e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,b,seas_stor,2000]',-0.0019150055793566611583); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,c,dly_stor,2000]',-4.1883387800486087115e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,b,dly_stor,2000]',-1.2069762722145627176e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,a,dly_stor,2000]',-1.7983916895994889628e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,a,seas_stor,2000]',-3.5651827068338381998e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,a,seas_stor,2000]',-0.0019557996514695448198); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,d,dly_stor,2000]',-3.9485685665929972643e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,d,seas_stor,2000]',-0.0018038898687766034001); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,c,dly_stor,2000]',-5.2294209073905513207e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,a,dly_stor,2000]',-2.016437280362393114e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,c,seas_stor,2000]',-0.0017703732824977256754); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,b,dly_stor,2000]',-5.7797571613751692609e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,d,dly_stor,2000]',-3.87006737036306383e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,c,seas_stor,2000]',-7.0883085262919003355e-09); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,b,seas_stor,2000]',-7.1579661355912342912e-09); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,d,seas_stor,2000]',-7.3829319339268231203e-09); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,b,seas_stor,2000]',-3.5613176789246074882e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,c,dly_stor,2000]',-1.2349788608388929667e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,b,dly_stor,2000]',-4.1884293092433901861e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,a,dly_stor,2000]',-3.9481261846979931462e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,a,seas_stor,2000]',-7.1347346464973728785e-09); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,a,seas_stor,2000]',-3.5613135641518733898e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,d,dly_stor,2000]',-1.7515961681002181649e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,d,seas_stor,2000]',-3.5610586195680133947e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,c,dly_stor,2000]',-5.7082184017434425271e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,a,dly_stor,2000]',-3.8795740106759190268e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,c,seas_stor,2000]',-3.5610355629010550515e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,b,dly_stor,2000]',-5.1906403614485796538e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,d,dly_stor,2000]',-2.0711911733338417285e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,c,seas_stor,2000]',-1.5032898104432781849e-08); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,b,seas_stor,2000]',-1.4784579164256117067e-08); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,d,seas_stor,2000]',-1.4859608725011574925e-08); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,b,seas_stor,2000]',-0.0040183819650553598279); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,c,dly_stor,2000]',-1.5889638444455924215e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,b,dly_stor,2000]',-1.5380000139594174335e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,a,dly_stor,2000]',-2.2855346485298646541e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,a,seas_stor,2000]',-1.4696732922444764035e-08); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,a,seas_stor,2000]',-0.0039775878961343966722); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,d,dly_stor,2000]',-2.1971314167586482035e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,d,seas_stor,2000]',-0.0037838629015935030253); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,c,dly_stor,2000]',-8.1736320692959303357e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,a,dly_stor,2000]',-2.5498616661417998763e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,c,seas_stor,2000]',-0.0038173794865856454094); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,b,dly_stor,2000]',-8.2337089532251290791e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,d,dly_stor,2000]',-2.6432678697009204249e-11); -CREATE TABLE OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -INSERT INTO OutputObjective VALUES('zulu','TotalCost',76813.228544347014192); -CREATE TABLE SectorLabel -( - sector TEXT, - PRIMARY KEY (sector) -); -INSERT INTO SectorLabel VALUES('electricity'); -CREATE TABLE CapacityCredit -( - region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -CREATE TABLE CapacityFactorProcess -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE CapacityFactorTech -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','a','generator',1.0,NULL); -INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','b','generator',1.0,NULL); -INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','c','generator',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','d','generator',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','a','generator',0.1,NULL); -INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','b','generator',0.1,NULL); -INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','c','generator',0.01,NULL); -INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','d','generator',0.01,NULL); -CREATE TABLE CapacityToActivity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO CapacityToActivity VALUES('region','generator',8760.0,'MWh/MWy'); -INSERT INTO CapacityToActivity VALUES('region','dly_stor',8760.0,'MWh/MWy'); -INSERT INTO CapacityToActivity VALUES('region','seas_stor',8760.0,'MWh/MWy'); -INSERT INTO CapacityToActivity VALUES('region','demand',8760.0,'MWh/MWy'); -CREATE TABLE Commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES CommodityType (label), - description TEXT -); -INSERT INTO Commodity VALUES('ethos','s',NULL); -INSERT INTO Commodity VALUES('electricity','p',NULL); -INSERT INTO Commodity VALUES('demand','d',NULL); -CREATE TABLE CommodityType -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO CommodityType VALUES('p','physical commodity'); -INSERT INTO CommodityType VALUES('a','annual commodity'); -INSERT INTO CommodityType VALUES('e','emissions commodity'); -INSERT INTO CommodityType VALUES('d','demand commodity'); -INSERT INTO CommodityType VALUES('s','source commodity'); -INSERT INTO CommodityType VALUES('w','waste commodity'); -INSERT INTO CommodityType VALUES('wa','waste annual commodity'); -INSERT INTO CommodityType VALUES('wp','waste physical commodity'); -CREATE TABLE ConstructionInput -( - region TEXT, - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage) -); -CREATE TABLE CostEmission -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT NOT NULL - REFERENCES Commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE CostFixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE CostInvest -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO CostInvest VALUES('region','generator',2000,1000.0,'',NULL); -INSERT INTO CostInvest VALUES('region','dly_stor',2000,1.0,'',NULL); -INSERT INTO CostInvest VALUES('region','seas_stor',2000,100.0,'',NULL); -INSERT INTO CostInvest VALUES('region','demand',2000,1.0,'',NULL); -CREATE TABLE CostVariable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO CostVariable VALUES('region',2000,'generator',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2000,'demand',2000,1.0,NULL,NULL); -CREATE TABLE Demand -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - commodity TEXT - REFERENCES Commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -INSERT INTO Demand VALUES('region',2000,'demand',8760.0,'MWh',NULL); -CREATE TABLE DemandSpecificDistribution -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - demand_name TEXT - REFERENCES Commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','a','demand',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','b','demand',0.05,NULL); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','c','demand',0.05,NULL); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','d','demand',0.1,NULL); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','a','demand',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','b','demand',0.2,NULL); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','c','demand',0.2,NULL); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','d','demand',0.4,NULL); -CREATE TABLE EndOfLifeOutput -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -CREATE TABLE Efficiency -( - region TEXT, - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -INSERT INTO Efficiency VALUES('region','ethos','generator',2000,'electricity',1.0,NULL); -INSERT INTO Efficiency VALUES('region','electricity','dly_stor',2000,'electricity',1.0,NULL); -INSERT INTO Efficiency VALUES('region','electricity','seas_stor',2000,'electricity',1.0,NULL); -INSERT INTO Efficiency VALUES('region','electricity','demand',2000,'demand',1.0,NULL); -CREATE TABLE EfficiencyVariable -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE EmissionActivity -( - region TEXT, - emis_comm TEXT - REFERENCES Commodity (name), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -CREATE TABLE EmissionEmbodied -( - region TEXT, - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE EmissionEndOfLife -( - region TEXT, - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE ExistingCapacity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE LoanLifetimeTech -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE LoanRate -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE LifetimeProcess -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE LifetimeTech -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE Operator -( - operator TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO Operator VALUES('e','equal to'); -INSERT INTO Operator VALUES('le','less than or equal to'); -INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE LimitGrowthCapacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE LimitDegrowthCapacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE LimitGrowthNewCapacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE LimitDegrowthNewCapacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE LimitGrowthNewCapacityDelta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE LimitDegrowthNewCapacityDelta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE LimitStorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -CREATE TABLE LimitActivity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE LimitActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE LimitAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE LimitCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE LimitCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE LimitNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE LimitNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE LimitResource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE LimitSeasonalCapacityFactor -( - region TEXT - REFERENCES Region (region), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) -); -CREATE TABLE LimitTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE LimitTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE LimitTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE LimitTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE LimitEmission -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE LinkedTech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES Technology (tech), - emis_comm TEXT - REFERENCES Commodity (name), - driven_tech TEXT - REFERENCES Technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -CREATE TABLE OutputCurtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE OutputNetCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -INSERT INTO OutputNetCapacity VALUES('zulu','region','electricity',2000,'seas_stor',2000,1.4392656320725425445); -INSERT INTO OutputNetCapacity VALUES('zulu','region','electricity',2000,'demand',2000,3.2000000000000001776); -INSERT INTO OutputNetCapacity VALUES('zulu','region','electricity',2000,'dly_stor',2000,4.2785306855583380425); -INSERT INTO OutputNetCapacity VALUES('zulu','region','electricity',2000,'generator',2000,3.0654425023163081043); -CREATE TABLE OutputBuiltCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -INSERT INTO OutputBuiltCapacity VALUES('zulu','region','electricity','seas_stor',2000,1.4392656320725425445); -INSERT INTO OutputBuiltCapacity VALUES('zulu','region','electricity','demand',2000,3.2000000000000001776); -INSERT INTO OutputBuiltCapacity VALUES('zulu','region','electricity','generator',2000,3.0654425023163081043); -INSERT INTO OutputBuiltCapacity VALUES('zulu','region','electricity','dly_stor',2000,4.2785306855583380425); -CREATE TABLE OutputRetiredCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE OutputFlowIn -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','d','electricity','seas_stor',2000,'electricity',1.6658229082653559061); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','b','electricity','seas_stor',2000,'electricity',1575.9958575418115955); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','a','electricity','seas_stor',2000,'electricity',1575.9958579731961236); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','d','electricity','seas_stor',2000,'electricity',1575.9956575478158313); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','c','electricity','seas_stor',2000,'electricity',1.8910884059675414192); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','c','electricity','dly_stor',2000,'electricity',1204.7596747035338449); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','a','electricity','dly_stor',2000,'electricity',2618.5087591179661004); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','c','electricity','dly_stor',2000,'electricity',851.96387645265332366); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','b','electricity','dly_stor',2000,'electricity',2188.5411244155807963); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','c','electricity','seas_stor',2000,'electricity',1575.9956514181672204); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','b','electricity','seas_stor',2000,'electricity',1.798751859454663915); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','d','electricity','dly_stor',2000,'electricity',735.89264698708465317); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','a','electricity','seas_stor',2000,'electricity',1.7546442646897240535); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','a','electricity','dly_stor',2000,'electricity',2523.3859171065073923); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','d','electricity','dly_stor',2000,'electricity',719.1263802165781982); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','b','electricity','dly_stor',2000,'electricity',1363.0051112588996709); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','c','electricity','demand',2000,'demand',1752.0); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','d','electricity','demand',2000,'demand',3504.0); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','c','ethos','generator',2000,'electricity',33.566595265745142739); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','d','electricity','demand',2000,'demand',876.0); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','b','electricity','demand',2000,'demand',1752.0); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','a','ethos','generator',2000,'electricity',3356.6595399160439328); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','b','electricity','demand',2000,'demand',438.0); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','b','ethos','generator',2000,'electricity',3356.6595399162086899); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','d','ethos','generator',2000,'electricity',33.566595289722491735); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','a','ethos','generator',2000,'electricity',335.66595390483335847); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','d','ethos','generator',2000,'electricity',671.33190787721055414); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','b','ethos','generator',2000,'electricity',335.66595390600832971); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','c','ethos','generator',2000,'electricity',671.33190787684080547); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','c','electricity','demand',2000,'demand',438.0); -CREATE TABLE OutputFlowOut -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','d','electricity','seas_stor',2000,'electricity',1568.9482946398751295); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','d','electricity','seas_stor',2000,'electricity',5.895025229563088942e-05); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','c','electricity','seas_stor',2000,'electricity',1568.6232908987555845); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','c','electricity','dly_stor',2000,'electricity',1356.4608769452966008); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','a','electricity','dly_stor',2000,'electricity',714.83103160110816887); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','c','electricity','dly_stor',2000,'electricity',2194.6275577242486676); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','b','electricity','dly_stor',2000,'electricity',845.87743847871745828); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','c','electricity','seas_stor',2000,'electricity',6.2268121432416947413e-05); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','b','electricity','seas_stor',2000,'electricity',1569.3072056574608907); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','d','electricity','dly_stor',2000,'electricity',2516.5563377074744444); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','a','electricity','seas_stor',2000,'electricity',1569.7664178764727083); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','a','electricity','dly_stor',2000,'electricity',742.72223105128469811); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','d','electricity','dly_stor',2000,'electricity',2622.2773131962147097); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','b','electricity','dly_stor',2000,'electricity',1211.8307035541360239); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','c','electricity','demand',2000,'demand',1752.0); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','d','electricity','demand',2000,'demand',3504.0); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','c','ethos','generator',2000,'electricity',33.566595265745142739); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','d','electricity','demand',2000,'demand',876.0); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','b','electricity','demand',2000,'demand',1752.0); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','a','ethos','generator',2000,'electricity',3356.6595399160439328); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','b','electricity','demand',2000,'demand',438.0); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','b','ethos','generator',2000,'electricity',3356.6595399162086899); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','d','ethos','generator',2000,'electricity',33.566595289722491735); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','a','ethos','generator',2000,'electricity',335.66595390483335847); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','d','ethos','generator',2000,'electricity',671.33190787721055414); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','b','ethos','generator',2000,'electricity',335.66595390600832971); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','c','ethos','generator',2000,'electricity',671.33190787684080547); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','c','electricity','demand',2000,'demand',438.0); -CREATE TABLE OutputStorageLevel -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'charge','c','dly_stor',2000,17.114122593311056341); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'charge','b','dly_stor',2000,9.7570613005062956091); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'charge','a','dly_stor',2000,0.0); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'charge','d','dly_stor',2000,9.7570613260688681123); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'discharge','c','dly_stor',2000,14.713232852985489884); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'discharge','a','dly_stor',2000,3.4537690983471556194); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'discharge','b','dly_stor',2000,13.884879934054414896); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'discharge','d','dly_stor',2000,13.881993388646614029); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'winter','a','seas_stor',2000,10085.458960857824894); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'winter','b','seas_stor',2000,8517.4471872485479906); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'winter','c','seas_stor',2000,6949.9387334479445499); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'winter','d','seas_stor',2000,5383.206530959131264); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'summer','a','seas_stor',2000,3798.7472513029865162); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'summer','b','seas_stor',2000,5374.7431051676910485); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'summer','c','seas_stor',2000,6950.7389591488673019); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'summer','d','seas_stor',2000,8526.734548299248928); -CREATE TABLE PlanningReserveMargin -( - region TEXT - PRIMARY KEY - REFERENCES Region (region), - margin REAL -); -CREATE TABLE RampDown -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - PRIMARY KEY (region, tech) -); -CREATE TABLE RampUp -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - PRIMARY KEY (region, tech) -); -CREATE TABLE Region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -INSERT INTO Region VALUES('region',NULL); -CREATE TABLE TimeSegmentFraction -( - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) -); -INSERT INTO TimeSegmentFraction VALUES(2000,'charge','a',0.125,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'charge','b',0.125,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'charge','c',0.125,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'charge','d',0.125,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','a',0.125,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','b',0.125,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','c',0.125,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','d',0.125,NULL); -CREATE TABLE StorageDuration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO StorageDuration VALUES('region','dly_stor',4.0,NULL); -INSERT INTO StorageDuration VALUES('region','seas_stor',8760.0,NULL); -CREATE TABLE TechnologyType -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO TechnologyType VALUES('r','resource technology'); -INSERT INTO TechnologyType VALUES('p','production technology'); -INSERT INTO TechnologyType VALUES('pb','baseload production technology'); -INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE TimeOfDay -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY -); -INSERT INTO TimeOfDay VALUES(0,'a'); -INSERT INTO TimeOfDay VALUES(1,'b'); -INSERT INTO TimeOfDay VALUES(2,'c'); -INSERT INTO TimeOfDay VALUES(3,'d'); -CREATE TABLE TimePeriod -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES TimePeriodType (label) -); -INSERT INTO TimePeriod VALUES(0,2000,'f'); -INSERT INTO TimePeriod VALUES(1,2005,'f'); -CREATE TABLE TimeSeason -( - period INTEGER - REFERENCES TimePeriod (period), - sequence INTEGER, - season TEXT, - notes TEXT, - PRIMARY KEY (period, sequence, season) -); -INSERT INTO TimeSeason VALUES(2000,0,'charge',NULL); -INSERT INTO TimeSeason VALUES(2000,1,'discharge',NULL); -CREATE TABLE TimePeriodType -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO TimePeriodType VALUES('e','existing vintages'); -INSERT INTO TimePeriodType VALUES('f','future'); -CREATE TABLE OutputEmission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE RPSRequirement -( - region TEXT NOT NULL - REFERENCES Region (region), - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech_group TEXT NOT NULL - REFERENCES TechGroup (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE TechGroupMember -( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES Technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE Technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) -); -INSERT INTO Technology VALUES('generator','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('dly_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('seas_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,1,NULL); -INSERT INTO Technology VALUES('demand','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -CREATE TABLE OutputCost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) -); -INSERT INTO OutputCost VALUES('zulu','region','electricity',2000,'demand',2000,0.80740460536195755025,0.0,37926.215634726010428,0.0,0.51801829986182648113,0.0,43800.0,0.0); -INSERT INTO OutputCost VALUES('zulu','region','electricity',2000,'dly_stor',2000,1.0795329311569543673,0.0,0.0,0.0,0.69261162238737030705,0.0,0.0,0.0); -INSERT INTO OutputCost VALUES('zulu','region','electricity',2000,'generator',2000,773.45387307577189162,0.0,38075.357420893887194,0.0,496.23603542939909161,0.0,43972.239969763071698,0.0); -INSERT INTO OutputCost VALUES('zulu','region','electricity',2000,'seas_stor',2000,36.314678114829974653,0.0,0.0,0.0,23.298935492992982609,0.0,0.0,0.0); -CREATE TABLE TimeStorageSeason -( - period INTEGER - REFERENCES TimePeriod (period), - sequence INTEGER, - storage_season TEXT, - season TEXT - REFERENCES TimeSeason (season), - count INT NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season) - CHECK (count > 0) -); -INSERT INTO TimeStorageSeason VALUES(2000,1,'summer','charge',182,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,3,'winter','discharge',183,NULL); -COMMIT; +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE MetaData +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); +INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); +INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); +INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); +CREATE TABLE MetaDataReal +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); +CREATE TABLE OutputDualVariable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,d,generator,2000]',-0.085703001173645247945); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,d,demand,2000]',-0.00023042368874485079643); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,d,demand,2000]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,b,generator,2000]',-0.085357366392446838432); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,a,demand,2000]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,c,generator,2000]',-0.085703001174349608959); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,b,generator,2000]',-0.11558070679412910664); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,c,demand,2000]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,c,demand,2000]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,b,demand,2000]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,b,demand,2000]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,c,generator,2000]',-0.11558070712241454991); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,a,generator,2000]',-0.08535736638981534341); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,a,generator,2000]',-0.11558070668246853696); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,d,generator,2000]',-0.11558070724338096457); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,a,demand,2000]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityAvailableByPeriodAndTechConstraint[region,2000,seas_stor]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityAvailableByPeriodAndTechConstraint[region,2000,generator]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityAvailableByPeriodAndTechConstraint[region,2000,demand]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','CapacityAvailableByPeriodAndTechConstraint[region,2000,dly_stor]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','AdjustedCapacityConstraint[region,2000,seas_stor,2000]',-25.231393917561169004); +INSERT INTO OutputDualVariable VALUES('zulu','AdjustedCapacityConstraint[region,2000,demand,2000]',-0.25231393917561169004); +INSERT INTO OutputDualVariable VALUES('zulu','AdjustedCapacityConstraint[region,2000,dly_stor,2000]',-0.25231393917561169004); +INSERT INTO OutputDualVariable VALUES('zulu','AdjustedCapacityConstraint[region,2000,generator,2000]',-252.31393917561164563); +INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,charge,b,demand]',8.7443107076524206888); +INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,charge,c,demand]',8.7446563424276391174); +INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,charge,a,demand]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,discharge,a,demand]',0.0); +INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,discharge,d,demand]',8.7747644720271349427); +INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,discharge,b,demand]',8.7745340480390616733); +INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,discharge,c,demand]',8.7745340482176992225); +INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,charge,d,demand]',8.7446563424269339037); +INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,charge,b,electricity]',4.4148340370215981565); +INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,charge,c,electricity]',4.4151796717968148087); +INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,discharge,a,electricity]',4.44505737729657735); +INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,charge,a,electricity]',4.4148340370189664838); +INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,discharge,d,electricity]',4.4450573777075668147); +INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,discharge,b,electricity]',4.4450573774082373645); +INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,discharge,c,electricity]',4.4450573775868758019); +INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,charge,d,electricity]',4.4151796717961104832); +INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyConstraint[region,2000,winter,seas_stor,2000]',-4.4329123900165026128); +INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyConstraint[region,2000,summer,seas_stor,2000]',-4.4329123900150158021); +INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,winter,c,seas_stor,2000]',-9.9285300719515330314e-13); +INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,winter,a,seas_stor,2000]',-2.2220266853952255203e-12); +INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,summer,d,seas_stor,2000]',-1.3760422345105398633e-12); +INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,winter,d,seas_stor,2000]',-7.7749544304990836351e-13); +INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,summer,c,seas_stor,2000]',-9.928636176739285446e-13); +INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,summer,a,seas_stor,2000]',-6.3758520034707890644e-13); +INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,winter,b,seas_stor,2000]',-1.3731094778566776959e-12); +INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,summer,b,seas_stor,2000]',-7.7654566423139437247e-13); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,c,seas_stor,2000]',6.4416949203073858853e-13); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,b,seas_stor,2000]',6.6523075894421745957e-13); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,b,seas_stor,2000]',-4.7138287749897429534e-13); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,c,dly_stor,2000]',4.4151796717729769881); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,b,dly_stor,2000]',4.4148340370445753322); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,a,dly_stor,2000]',4.4148340370562451084); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,a,seas_stor,2000]',8.1624677449077918112e-14); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,a,seas_stor,2000]',8.8939163809495713763e-14); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,d,dly_stor,2000]',4.415179671760228075); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,c,dly_stor,2000]',4.4450573775854937963); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,a,dly_stor,2000]',4.4450573773388573073); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,c,seas_stor,2000]',-5.821732668700695612e-13); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,b,dly_stor,2000]',4.4450573774107144942); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,d,dly_stor,2000]',4.4450573776637751777); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,charge,c,dly_stor,2000]',-0.00034563473280713847834); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,charge,b,dly_stor,2000]',-4.5045066420029851173e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,charge,a,dly_stor,2000]',-1.8570385267138625806e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,charge,d,dly_stor,2000]',-4.4825967675597020445e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,discharge,c,dly_stor,2000]',-1.7883284614710022175e-10); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,discharge,a,dly_stor,2000]',-3.7581557153964029183e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,discharge,b,dly_stor,2000]',-7.6405648911312447069e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,discharge,d,dly_stor,2000]',-8.2734689766129356769e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,c,seas_stor,2000]',-3.5654595609390025146e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,b,seas_stor,2000]',-3.565273019415246658e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,d,seas_stor,2000]',-3.5649814908001054014e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,b,seas_stor,2000]',-0.0019150055793566611583); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,c,dly_stor,2000]',-4.1883387800486087115e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,b,dly_stor,2000]',-1.2069762722145627176e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,a,dly_stor,2000]',-1.7983916895994889628e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,a,seas_stor,2000]',-3.5651827068338381998e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,a,seas_stor,2000]',-0.0019557996514695448198); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,d,dly_stor,2000]',-3.9485685665929972643e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,d,seas_stor,2000]',-0.0018038898687766034001); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,c,dly_stor,2000]',-5.2294209073905513207e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,a,dly_stor,2000]',-2.016437280362393114e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,c,seas_stor,2000]',-0.0017703732824977256754); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,b,dly_stor,2000]',-5.7797571613751692609e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,d,dly_stor,2000]',-3.87006737036306383e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,c,seas_stor,2000]',-7.0883085262919003355e-09); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,b,seas_stor,2000]',-7.1579661355912342912e-09); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,d,seas_stor,2000]',-7.3829319339268231203e-09); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,b,seas_stor,2000]',-3.5613176789246074882e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,c,dly_stor,2000]',-1.2349788608388929667e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,b,dly_stor,2000]',-4.1884293092433901861e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,a,dly_stor,2000]',-3.9481261846979931462e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,a,seas_stor,2000]',-7.1347346464973728785e-09); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,a,seas_stor,2000]',-3.5613135641518733898e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,d,dly_stor,2000]',-1.7515961681002181649e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,d,seas_stor,2000]',-3.5610586195680133947e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,c,dly_stor,2000]',-5.7082184017434425271e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,a,dly_stor,2000]',-3.8795740106759190268e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,c,seas_stor,2000]',-3.5610355629010550515e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,b,dly_stor,2000]',-5.1906403614485796538e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,d,dly_stor,2000]',-2.0711911733338417285e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,c,seas_stor,2000]',-1.5032898104432781849e-08); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,b,seas_stor,2000]',-1.4784579164256117067e-08); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,d,seas_stor,2000]',-1.4859608725011574925e-08); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,b,seas_stor,2000]',-0.0040183819650553598279); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,c,dly_stor,2000]',-1.5889638444455924215e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,b,dly_stor,2000]',-1.5380000139594174335e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,a,dly_stor,2000]',-2.2855346485298646541e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,a,seas_stor,2000]',-1.4696732922444764035e-08); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,a,seas_stor,2000]',-0.0039775878961343966722); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,d,dly_stor,2000]',-2.1971314167586482035e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,d,seas_stor,2000]',-0.0037838629015935030253); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,c,dly_stor,2000]',-8.1736320692959303357e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,a,dly_stor,2000]',-2.5498616661417998763e-11); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,c,seas_stor,2000]',-0.0038173794865856454094); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,b,dly_stor,2000]',-8.2337089532251290791e-12); +INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,d,dly_stor,2000]',-2.6432678697009204249e-11); +CREATE TABLE OutputObjective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +INSERT INTO OutputObjective VALUES('zulu','TotalCost',76813.228544347014192); +CREATE TABLE SectorLabel +( + sector TEXT, + PRIMARY KEY (sector) +); +INSERT INTO SectorLabel VALUES('electricity'); +CREATE TABLE CapacityCredit +( + region TEXT, + period INTEGER, + tech TEXT, + vintage INTEGER, + credit REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage), + CHECK (credit >= 0 AND credit <= 1) +); +CREATE TABLE CapacityFactorProcess +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE CapacityFactorTech +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech), + CHECK (factor >= 0 AND factor <= 1) +); +INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','a','generator',1.0,NULL); +INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','b','generator',1.0,NULL); +INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','c','generator',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','d','generator',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','a','generator',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','b','generator',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','c','generator',0.01,NULL); +INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','d','generator',0.01,NULL); +CREATE TABLE CapacityToActivity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + c2a REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +INSERT INTO CapacityToActivity VALUES('region','generator',8760.0,'MWh/MWy'); +INSERT INTO CapacityToActivity VALUES('region','dly_stor',8760.0,'MWh/MWy'); +INSERT INTO CapacityToActivity VALUES('region','seas_stor',8760.0,'MWh/MWy'); +INSERT INTO CapacityToActivity VALUES('region','demand',8760.0,'MWh/MWy'); +CREATE TABLE Commodity +( + name TEXT + PRIMARY KEY, + flag TEXT + REFERENCES CommodityType (label), + description TEXT +); +INSERT INTO Commodity VALUES('ethos','s',NULL); +INSERT INTO Commodity VALUES('electricity','p',NULL); +INSERT INTO Commodity VALUES('demand','d',NULL); +CREATE TABLE CommodityType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO CommodityType VALUES('p','physical commodity'); +INSERT INTO CommodityType VALUES('a','annual commodity'); +INSERT INTO CommodityType VALUES('e','emissions commodity'); +INSERT INTO CommodityType VALUES('d','demand commodity'); +INSERT INTO CommodityType VALUES('s','source commodity'); +INSERT INTO CommodityType VALUES('w','waste commodity'); +INSERT INTO CommodityType VALUES('wa','waste annual commodity'); +INSERT INTO CommodityType VALUES('wp','waste physical commodity'); +CREATE TABLE ConstructionInput +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); +CREATE TABLE CostEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT NOT NULL + REFERENCES Commodity (name), + cost REAL NOT NULL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE CostFixed +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE CostInvest +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +INSERT INTO CostInvest VALUES('region','generator',2000,1000.0,'',NULL); +INSERT INTO CostInvest VALUES('region','dly_stor',2000,1.0,'',NULL); +INSERT INTO CostInvest VALUES('region','seas_stor',2000,100.0,'',NULL); +INSERT INTO CostInvest VALUES('region','demand',2000,1.0,'',NULL); +CREATE TABLE CostVariable +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +INSERT INTO CostVariable VALUES('region',2000,'generator',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2000,'demand',2000,1.0,NULL,NULL); +CREATE TABLE Demand +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + commodity TEXT + REFERENCES Commodity (name), + demand REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, commodity) +); +INSERT INTO Demand VALUES('region',2000,'demand',8760.0,'MWh',NULL); +CREATE TABLE DemandSpecificDistribution +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + demand_name TEXT + REFERENCES Commodity (name), + dsd REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), + CHECK (dsd >= 0 AND dsd <= 1) +); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','a','demand',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','b','demand',0.05,NULL); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','c','demand',0.05,NULL); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','d','demand',0.1,NULL); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','a','demand',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','b','demand',0.2,NULL); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','c','demand',0.2,NULL); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','d','demand',0.4,NULL); +CREATE TABLE EndOfLifeOutput +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) +); +CREATE TABLE Efficiency +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +INSERT INTO Efficiency VALUES('region','ethos','generator',2000,'electricity',1.0,NULL); +INSERT INTO Efficiency VALUES('region','electricity','dly_stor',2000,'electricity',1.0,NULL); +INSERT INTO Efficiency VALUES('region','electricity','seas_stor',2000,'electricity',1.0,NULL); +INSERT INTO Efficiency VALUES('region','electricity','demand',2000,'demand',1.0,NULL); +CREATE TABLE EfficiencyVariable +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE EmissionActivity +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) +); +CREATE TABLE EmissionEmbodied +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE EmissionEndOfLife +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE ExistingCapacity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE TechGroup +( + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE LoanLifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE LifetimeProcess +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE LifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE Operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO Operator VALUES('e','equal to'); +INSERT INTO Operator VALUES('le','less than or equal to'); +INSERT INTO Operator VALUES('ge','greater than or equal to'); +CREATE TABLE LimitGrowthCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitDegrowthCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitGrowthNewCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitDegrowthNewCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitGrowthNewCapacityDelta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitDegrowthNewCapacityDelta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitStorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) +); +CREATE TABLE LimitActivity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE LimitActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE LimitAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, operator), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE LimitCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE LimitCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE LimitNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE LimitNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE LimitResource +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitSeasonalCapacityFactor +( + region TEXT + REFERENCES Region (region), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) +); +CREATE TABLE LimitTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +INSERT INTO OutputNetCapacity VALUES('zulu','region','electricity',2000,'seas_stor',2000,1.4392656320725425445); +INSERT INTO OutputNetCapacity VALUES('zulu','region','electricity',2000,'demand',2000,3.2000000000000001776); +INSERT INTO OutputNetCapacity VALUES('zulu','region','electricity',2000,'dly_stor',2000,4.2785306855583380425); +INSERT INTO OutputNetCapacity VALUES('zulu','region','electricity',2000,'generator',2000,3.0654425023163081043); +CREATE TABLE OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +INSERT INTO OutputBuiltCapacity VALUES('zulu','region','electricity','seas_stor',2000,1.4392656320725425445); +INSERT INTO OutputBuiltCapacity VALUES('zulu','region','electricity','demand',2000,3.2000000000000001776); +INSERT INTO OutputBuiltCapacity VALUES('zulu','region','electricity','generator',2000,3.0654425023163081043); +INSERT INTO OutputBuiltCapacity VALUES('zulu','region','electricity','dly_stor',2000,4.2785306855583380425); +CREATE TABLE OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','d','electricity','seas_stor',2000,'electricity',1.6658229082653559061); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','b','electricity','seas_stor',2000,'electricity',1575.9958575418115955); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','a','electricity','seas_stor',2000,'electricity',1575.9958579731961236); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','d','electricity','seas_stor',2000,'electricity',1575.9956575478158313); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','c','electricity','seas_stor',2000,'electricity',1.8910884059675414192); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','c','electricity','dly_stor',2000,'electricity',1204.7596747035338449); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','a','electricity','dly_stor',2000,'electricity',2618.5087591179661004); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','c','electricity','dly_stor',2000,'electricity',851.96387645265332366); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','b','electricity','dly_stor',2000,'electricity',2188.5411244155807963); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','c','electricity','seas_stor',2000,'electricity',1575.9956514181672204); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','b','electricity','seas_stor',2000,'electricity',1.798751859454663915); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','d','electricity','dly_stor',2000,'electricity',735.89264698708465317); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','a','electricity','seas_stor',2000,'electricity',1.7546442646897240535); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','a','electricity','dly_stor',2000,'electricity',2523.3859171065073923); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','d','electricity','dly_stor',2000,'electricity',719.1263802165781982); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','b','electricity','dly_stor',2000,'electricity',1363.0051112588996709); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','c','electricity','demand',2000,'demand',1752.0); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','d','electricity','demand',2000,'demand',3504.0); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','c','ethos','generator',2000,'electricity',33.566595265745142739); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','d','electricity','demand',2000,'demand',876.0); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','b','electricity','demand',2000,'demand',1752.0); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','a','ethos','generator',2000,'electricity',3356.6595399160439328); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','b','electricity','demand',2000,'demand',438.0); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','b','ethos','generator',2000,'electricity',3356.6595399162086899); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','d','ethos','generator',2000,'electricity',33.566595289722491735); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','a','ethos','generator',2000,'electricity',335.66595390483335847); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','d','ethos','generator',2000,'electricity',671.33190787721055414); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','b','ethos','generator',2000,'electricity',335.66595390600832971); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','c','ethos','generator',2000,'electricity',671.33190787684080547); +INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','c','electricity','demand',2000,'demand',438.0); +CREATE TABLE OutputFlowOut +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','d','electricity','seas_stor',2000,'electricity',1568.9482946398751295); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','d','electricity','seas_stor',2000,'electricity',5.895025229563088942e-05); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','c','electricity','seas_stor',2000,'electricity',1568.6232908987555845); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','c','electricity','dly_stor',2000,'electricity',1356.4608769452966008); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','a','electricity','dly_stor',2000,'electricity',714.83103160110816887); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','c','electricity','dly_stor',2000,'electricity',2194.6275577242486676); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','b','electricity','dly_stor',2000,'electricity',845.87743847871745828); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','c','electricity','seas_stor',2000,'electricity',6.2268121432416947413e-05); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','b','electricity','seas_stor',2000,'electricity',1569.3072056574608907); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','d','electricity','dly_stor',2000,'electricity',2516.5563377074744444); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','a','electricity','seas_stor',2000,'electricity',1569.7664178764727083); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','a','electricity','dly_stor',2000,'electricity',742.72223105128469811); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','d','electricity','dly_stor',2000,'electricity',2622.2773131962147097); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','b','electricity','dly_stor',2000,'electricity',1211.8307035541360239); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','c','electricity','demand',2000,'demand',1752.0); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','d','electricity','demand',2000,'demand',3504.0); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','c','ethos','generator',2000,'electricity',33.566595265745142739); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','d','electricity','demand',2000,'demand',876.0); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','b','electricity','demand',2000,'demand',1752.0); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','a','ethos','generator',2000,'electricity',3356.6595399160439328); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','b','electricity','demand',2000,'demand',438.0); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','b','ethos','generator',2000,'electricity',3356.6595399162086899); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','d','ethos','generator',2000,'electricity',33.566595289722491735); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','a','ethos','generator',2000,'electricity',335.66595390483335847); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','d','ethos','generator',2000,'electricity',671.33190787721055414); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','b','ethos','generator',2000,'electricity',335.66595390600832971); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','c','ethos','generator',2000,'electricity',671.33190787684080547); +INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','c','electricity','demand',2000,'demand',438.0); +CREATE TABLE OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'charge','c','dly_stor',2000,17.114122593311056341); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'charge','b','dly_stor',2000,9.7570613005062956091); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'charge','a','dly_stor',2000,0.0); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'charge','d','dly_stor',2000,9.7570613260688681123); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'discharge','c','dly_stor',2000,14.713232852985489884); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'discharge','a','dly_stor',2000,3.4537690983471556194); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'discharge','b','dly_stor',2000,13.884879934054414896); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'discharge','d','dly_stor',2000,13.881993388646614029); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'winter','a','seas_stor',2000,10085.458960857824894); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'winter','b','seas_stor',2000,8517.4471872485479906); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'winter','c','seas_stor',2000,6949.9387334479445499); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'winter','d','seas_stor',2000,5383.206530959131264); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'summer','a','seas_stor',2000,3798.7472513029865162); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'summer','b','seas_stor',2000,5374.7431051676910485); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'summer','c','seas_stor',2000,6950.7389591488673019); +INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'summer','d','seas_stor',2000,8526.734548299248928); +CREATE TABLE PlanningReserveMargin +( + region TEXT + PRIMARY KEY + REFERENCES Region (region), + margin REAL +); +CREATE TABLE RampDown +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE RampUp +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE Region +( + region TEXT + PRIMARY KEY, + notes TEXT +); +INSERT INTO Region VALUES('region',NULL); +CREATE TABLE TimeSegmentFraction +( + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + segfrac REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segfrac >= 0 AND segfrac <= 1) +); +INSERT INTO TimeSegmentFraction VALUES(2000,'charge','a',0.125,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'charge','b',0.125,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'charge','c',0.125,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'charge','d',0.125,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','a',0.125,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','b',0.125,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','c',0.125,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','d',0.125,NULL); +CREATE TABLE StorageDuration +( + region TEXT, + tech TEXT, + duration REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +INSERT INTO StorageDuration VALUES('region','dly_stor',4.0,NULL); +INSERT INTO StorageDuration VALUES('region','seas_stor',8760.0,NULL); +CREATE TABLE TechnologyType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO TechnologyType VALUES('r','resource technology'); +INSERT INTO TechnologyType VALUES('p','production technology'); +INSERT INTO TechnologyType VALUES('pb','baseload production technology'); +INSERT INTO TechnologyType VALUES('ps','storage production technology'); +CREATE TABLE TimeOfDay +( + sequence INTEGER UNIQUE, + tod TEXT + PRIMARY KEY +); +INSERT INTO TimeOfDay VALUES(0,'a'); +INSERT INTO TimeOfDay VALUES(1,'b'); +INSERT INTO TimeOfDay VALUES(2,'c'); +INSERT INTO TimeOfDay VALUES(3,'d'); +CREATE TABLE TimePeriod +( + sequence INTEGER UNIQUE, + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES TimePeriodType (label) +); +INSERT INTO TimePeriod VALUES(0,2000,'f'); +INSERT INTO TimePeriod VALUES(1,2005,'f'); +CREATE TABLE TimeSeason +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT, + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +INSERT INTO TimeSeason VALUES(2000,0,'charge',NULL); +INSERT INTO TimeSeason VALUES(2000,1,'discharge',NULL); +CREATE TABLE TimePeriodType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO TimePeriodType VALUES('e','existing vintages'); +INSERT INTO TimePeriodType VALUES('f','future'); +CREATE TABLE OutputEmission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE RPSRequirement +( + region TEXT NOT NULL + REFERENCES Region (region), + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech_group TEXT NOT NULL + REFERENCES TechGroup (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE TechGroupMember +( + group_name TEXT + REFERENCES TechGroup (group_name), + tech TEXT + REFERENCES Technology (tech), + PRIMARY KEY (group_name, tech) +); +CREATE TABLE Technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES TechnologyType (label) +); +INSERT INTO Technology VALUES('generator','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('dly_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('seas_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,1,NULL); +INSERT INTO Technology VALUES('demand','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +CREATE TABLE OutputCost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES TimePeriod (period), + FOREIGN KEY (tech) REFERENCES Technology (tech) +); +INSERT INTO OutputCost VALUES('zulu','region','electricity',2000,'demand',2000,0.80740460536195755025,0.0,37926.215634726010428,0.0,0.51801829986182648113,0.0,43800.0,0.0); +INSERT INTO OutputCost VALUES('zulu','region','electricity',2000,'dly_stor',2000,1.0795329311569543673,0.0,0.0,0.0,0.69261162238737030705,0.0,0.0,0.0); +INSERT INTO OutputCost VALUES('zulu','region','electricity',2000,'generator',2000,773.45387307577189162,0.0,38075.357420893887194,0.0,496.23603542939909161,0.0,43972.239969763071698,0.0); +INSERT INTO OutputCost VALUES('zulu','region','electricity',2000,'seas_stor',2000,36.314678114829974653,0.0,0.0,0.0,23.298935492992982609,0.0,0.0,0.0); +CREATE TABLE TimeStorageSeason +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + storage_season TEXT, + season TEXT + REFERENCES TimeSeason (season), + count NUMERIC NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, storage_season, season), + CHECK (count > 0) +); +INSERT INTO TimeStorageSeason VALUES(2000,1,'summer','charge',182.5,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,3,'winter','discharge',182.5,NULL); +COMMIT; diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index 21db50885..cc68f9fd0 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -10,6 +10,7 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); CREATE TABLE MetaDataReal ( element TEXT, @@ -1439,6 +1440,19 @@ INSERT INTO TimeSeason VALUES(2020,9,'summer',NULL); INSERT INTO TimeSeason VALUES(2020,10,'autumn',NULL); INSERT INTO TimeSeason VALUES(2020,11,'winter',NULL); INSERT INTO TimeSeason VALUES(2020,12,'spring',NULL); +CREATE TABLE TimeStorageSeason +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + storage_season TEXT, + season TEXT + REFERENCES TimeSeason (season), + count NUMERIC NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, storage_season, season), + CHECK (count > 0) +); CREATE TABLE TimePeriodType ( label TEXT diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index ed0fb269e..5769b42ad 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -10,6 +10,7 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); CREATE TABLE MetaDataReal ( element TEXT, @@ -1416,6 +1417,19 @@ INSERT INTO TimeSeason VALUES(2000,1,'inter',NULL); INSERT INTO TimeSeason VALUES(2010,2,'summer',NULL); INSERT INTO TimeSeason VALUES(2010,3,'winter',NULL); INSERT INTO TimeSeason VALUES(2010,1,'inter',NULL); +CREATE TABLE TimeStorageSeason +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + storage_season TEXT, + season TEXT + REFERENCES TimeSeason (season), + count NUMERIC NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, storage_season, season), + CHECK (count > 0) +); CREATE TABLE TimePeriodType ( label TEXT diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index d92613480..34a89c616 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -10,6 +10,7 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES('myopic_base_year',2000,''); +INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); CREATE TABLE MetaDataReal ( element TEXT, @@ -1180,7 +1181,7 @@ INSERT INTO TimeSeason VALUES(2045,3,'winter',NULL); INSERT INTO TimeSeason VALUES(2050,1,'inter',NULL); INSERT INTO TimeSeason VALUES(2050,2,'summer',NULL); INSERT INTO TimeSeason VALUES(2050,3,'winter',NULL); -CREATE TABLE IF NOT EXISTS TimeStorageSeason +CREATE TABLE TimeStorageSeason ( period INTEGER REFERENCES TimePeriod (period), @@ -1188,8 +1189,10 @@ CREATE TABLE IF NOT EXISTS TimeStorageSeason storage_season TEXT, season TEXT REFERENCES TimeSeason (season), + count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season) + PRIMARY KEY (period, sequence, storage_season, season), + CHECK (count > 0) ); CREATE TABLE TimePeriodType ( diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index 203577caf..89950301c 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -10,6 +10,7 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); CREATE TABLE MetaDataReal ( element TEXT, @@ -1429,7 +1430,7 @@ INSERT INTO TimeSeason VALUES(2030,1,'spring',NULL); INSERT INTO TimeSeason VALUES(2030,2,'summer',NULL); INSERT INTO TimeSeason VALUES(2030,3,'fall',NULL); INSERT INTO TimeSeason VALUES(2030,4,'winter',NULL); -CREATE TABLE IF NOT EXISTS TimeStorageSeason +CREATE TABLE TimeStorageSeason ( period INTEGER REFERENCES TimePeriod (period), @@ -1437,8 +1438,10 @@ CREATE TABLE IF NOT EXISTS TimeStorageSeason storage_season TEXT, season TEXT REFERENCES TimeSeason (season), + count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season) + PRIMARY KEY (period, sequence, storage_season, season), + CHECK (count > 0) ); CREATE TABLE TimePeriodType ( diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 4619a0c77..0b48b7b1e 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -10,6 +10,7 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('myopic_base_year',1990,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); CREATE TABLE MetaDataReal ( element TEXT, @@ -1411,7 +1412,7 @@ INSERT INTO TimeSeason VALUES(2000,3,'winter',NULL); INSERT INTO TimeSeason VALUES(2010,1,'inter',NULL); INSERT INTO TimeSeason VALUES(2010,2,'summer',NULL); INSERT INTO TimeSeason VALUES(2010,3,'winter',NULL); -CREATE TABLE IF NOT EXISTS TimeStorageSeason +CREATE TABLE TimeStorageSeason ( period INTEGER REFERENCES TimePeriod (period), @@ -1419,8 +1420,10 @@ CREATE TABLE IF NOT EXISTS TimeStorageSeason storage_season TEXT, season TEXT REFERENCES TimeSeason (season), + count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season) + PRIMARY KEY (period, sequence, storage_season, season), + CHECK (count > 0) ); CREATE TABLE TimeStorageSeason ( diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index c93fa5c9b..497e8e651 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -14,6 +14,8 @@ REPLACE INTO MetaData VALUES ('DB_MAJOR', 3, 'DB major version number'); REPLACE INTO MetaData VALUES ('DB_MINOR', 0, 'DB minor version number'); +REPLACE INTO MetaData +VALUES ('days_per_period', 365, 'count of days in each period'); CREATE TABLE IF NOT EXISTS MetaDataReal ( @@ -926,9 +928,9 @@ CREATE TABLE IF NOT EXISTS TimeStorageSeason storage_season TEXT, season TEXT REFERENCES TimeSeason (season), - count INT NOT NULL, + count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season) + PRIMARY KEY (period, sequence, storage_season, season), CHECK (count > 0) ); CREATE TABLE IF NOT EXISTS TimePeriodType diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 68cca16b9..8434bac5c 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -398,47 +398,6 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N logger.warning('No TimeOfDay table found. Loading a single filler time of day "D" (assume this is an annual model)') load_element(M.time_of_day, [('D',)]) - all_seasons = set() # includes all regular and virtual seasonal storage seasons - if self.table_exists("TimeStorageSeason"): - if mi: - raw = cur.execute( - 'SELECT period, storage_season, season, count FROM main.TimeStorageSeason WHERE' - ' period >= ? AND period <= ? ORDER BY period, sequence', - (mi.base_year, mi.last_demand_year) - ).fetchall() - else: - raw = cur.execute('SELECT period, storage_season, season, count FROM main.TimeStorageSeason ORDER BY period, sequence').fetchall() - all_seasons = all_seasons | set((row[1],) for row in raw) - load_element(M.TimeStorageSeason, raw) - - # TimeSeason - if self.table_exists("TimeSeason"): - if mi: - raw = cur.execute( - 'SELECT period, season FROM main.TimeSeason WHERE' - ' period >= ? AND period <= ? ORDER BY period, sequence', - (mi.base_year, mi.last_demand_year) - ).fetchall() - else: - raw = cur.execute('SELECT period, season FROM main.TimeSeason ORDER BY period, sequence').fetchall() - for row in raw: - load_indexed_set( - M.time_season, - index_value=row[0], - element=row[1] - ) - all_seasons = all_seasons | set((row[1],) for row in raw) - else: - for period in time_optimize: - load_indexed_set( - M.time_season, - index_value=period, - element='S' - ) - logger.warning('No TimeSeason table found. Loading a single filler season "S" (assume this is an annual model)') - all_seasons.add(('S',)) - load_element(M.time_season_all, list(all_seasons)) - # TimeSequencing time_sequencing = self.config.time_sequencing match time_sequencing: @@ -689,14 +648,58 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # SegFrac if self.table_exists("TimeSegmentFraction"): raw = self.raw_check_mi_period(mi=mi, cur=cur, qry='SELECT period, season, tod, segfrac FROM main.TimeSegmentFraction') - load_element(M.SegFrac, raw) else: logger.warning( 'No TimeSegmentFraction table found. Loading filler SegFrac ("S", "D") for one time segment per period' - ' (assume this is an annual model)' + ' (assume this is a periodic model)' ) - filler_segfrac = [(p, "S", "D", 1) for p in time_optimize] # if no segfrac table, assume this is an annual model - load_element(M.SegFrac, filler_segfrac) + raw = [ + (p, "S", "D", 1) + for p in time_optimize + if mi.base_year <= p <= mi.last_demand_year + ] # if no segfrac table, assume this is a periodic model + load_element(M.SegFrac, raw) + + all_seasons = set() # includes all regular and virtual seasonal storage seasons + if self.table_exists("TimeStorageSeason"): + if mi: + raw = cur.execute( + 'SELECT period, storage_season, season, count FROM main.TimeStorageSeason WHERE' + ' period >= ? AND period <= ? ORDER BY period, sequence', + (mi.base_year, mi.last_demand_year) + ).fetchall() + else: + raw = cur.execute('SELECT period, storage_season, season, count FROM main.TimeStorageSeason ORDER BY period, sequence').fetchall() + all_seasons = all_seasons | set((row[1],) for row in raw) + load_element(M.TimeStorageSeason, raw) + + # TimeSeason + if self.table_exists("TimeSeason"): + if mi: + raw = cur.execute( + 'SELECT period, season FROM main.TimeSeason WHERE' + ' period >= ? AND period <= ? ORDER BY period, sequence', + (mi.base_year, mi.last_demand_year) + ).fetchall() + else: + raw = cur.execute('SELECT period, season FROM main.TimeSeason ORDER BY period, sequence').fetchall() + for row in raw: + load_indexed_set( + M.time_season, + index_value=row[0], + element=row[1] + ) + all_seasons = all_seasons | set((row[1],) for row in raw) + else: + for period in time_optimize: + load_indexed_set( + M.time_season, + index_value=period, + element='S' + ) + logger.warning('No TimeSeason table found. Loading a single filler season "S" (assume this is an annual model)') + all_seasons.add(('S',)) + load_element(M.time_season_all, list(all_seasons)) # DemandSpecificDistribution if self.table_exists('DemandSpecificDistribution'): diff --git a/temoa/temoa_model/model_checking/validators.py b/temoa/temoa_model/model_checking/validators.py index 04d4a8368..12372f5bf 100644 --- a/temoa/temoa_model/model_checking/validators.py +++ b/temoa/temoa_model/model_checking/validators.py @@ -306,17 +306,31 @@ def validate_Efficiency(M: 'TemoaModel', val, r, si, t, v, so) -> bool: def validate_StorageSeason(M: 'TemoaModel'): + + if not M.TimeStorageSeason: + logger.info( + 'No data in TimeStorageSeason. By default, assume storage seasons ' + 'match TimeSeason and fill using TimeSegmentFraction.' + ) + for p in M.time_season: + for s in M.time_season[p]: + M.TimeStorageSeason[p, s, s] = value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod) + storage = dict() for p, s_stor, s in M.TimeStorageSeason: if (p, s) not in storage: storage[p, s] = 0 storage[p, s] += value(M.TimeStorageSeason[p, s_stor, s]) + + # Check that TimeStorageSeason day counts total to number of days in each period if abs(sum(storage.values()) - value(M.DaysPerPeriod)) >= 0.001: logger.warning( f'Sum of day count in TimeStorageSeason ({sum(storage.values())}) ' f'does not sum to days_per_season ({value(M.DaysPerPeriod)}) from the ' 'MetaData table.' ) + + # Check that seasons using in storage seasons are actual seasons for (p, s) in storage: if (p, s) not in M.SegFracPerSeason: msg = ( @@ -325,18 +339,23 @@ def validate_StorageSeason(M: 'TemoaModel'): ) logger.error(msg) raise ValueError(msg) + for (p, s) in M.SegFracPerSeason: if s not in M.time_season[p]: continue + + # Check that all seasons are using in storage seasons if (p, s) not in storage: msg = (f'Period-season index {(p, s)} absent from TimeStorageSeason') logger.warning(msg) + + # Check that the two tables agree on the total seasonal composition of each period segfrac = value(M.SegFracPerSeason[p, s]) segfracstorage = storage[p, s] / value(M.DaysPerPeriod) if abs(segfrac - segfracstorage) >= 0.001: msg = ( - 'Discrepancy of seasonal composition between ' - 'TimeSegmentFraction and TimeStorageSeason. Fraction of each ' + 'Discrepancy of total period-season composition between ' + 'TimeSegmentFraction and TimeStorageSeason. Total fraction of each ' 'period assigned to each season should match: ' f'TimeSegmentFraction: {(p, s, value(M.SegFracPerSeason[p, s]))}' f', TimeStorageSeason: {(p, s, segfracstorage)}' diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index f96c5593e..1859b283e 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1075,21 +1075,23 @@ def CreateSparseDicts(M: 'TemoaModel'): def CreateTimeSequence(M: 'TemoaModel'): + logger.debug('Creating sequence of time slices.') + # Establishing sequence of states match M.TimeSequencing.first(): case 'seasonal_timeslicing': - msg = 'Running a season time slicing database, looping state each period, chaining between seasons.' + msg = 'Running a season time slicing database, looping time each period, chaining between seasons.' for p in M.time_optimize: for s, d in M.time_season[p] * M.time_of_day: M.time_next[p, s, d] = loop_period_next_timeslice(M, p, s, d) case 'representative_periods': - msg = 'Running a representative periods database, looping state each season.' + msg = 'Running a representative periods database, looping time each season.' for p in M.time_optimize: for s, d in M.time_season[p] * M.time_of_day: M.time_next[p, s, d] = loop_season_next_timeslice(M, p, s, d) case 'manual': # Hidden feature. Define the sequence directly in the TimeNext table - msg = 'Pulling state sequence from TimeNext table.' + msg = 'Pulling time sequence from TimeNext table.' for p, s, d, s_next, d_next in M.TimeNext: M.time_next[p, s, d] = s_next, d_next case _: @@ -1097,6 +1099,12 @@ def CreateTimeSequence(M: 'TemoaModel'): msg = f"Invalid time sequencing parameter loaded '{M.TimeSequencing.first()}'. Likely code error." logger.error(msg) raise ValueError(msg) + + msg += (' This behaviour can be changed using the ' + 'time_sequencing parameter in the config file. ') + logger.info(msg) + + logger.debug('Creating sequence of virtual storage seasons.') # Seasonal storage superimposed sequencing for p in M.time_optimize: @@ -1112,11 +1120,8 @@ def CreateTimeSequence(M: 'TemoaModel'): M.time_next_storage_season[p, s_stor] = seasons[0][0] else: M.time_next_storage_season[p, s_stor] = seasons[i+1][0] - - msg += (' This behaviour can be changed using the ' - 'time_sequencing parameter in the config file. ') - logger.info(msg) - logger.debug('Created sequence of states.') + + logger.debug('Created time sequence.') # --------------------------------------------------------------- diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 590d7e4aa..6d570d965 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -344,10 +344,16 @@ def __init__(M, *args, **kwargs): ) M.RenewablePortfolioStandard = Param(M.RenewablePortfolioStandardConstraint_rpg, validate=validate_0to1) + # Set up representation of time + M.DaysPerPeriod = Param() + M.SegFracPerSeason = Param(M.time_optimize, M.time_season_all, initialize=SegFracPerSeason_rule) + M.TimeStorageSeason = Param(M.time_optimize, M.time_season_all, M.time_season_all, mutable=True) + M.validate_StorageSeason = BuildAction(rule=validate_StorageSeason) + M.Create_TimeSequence = BuildAction(rule=CreateTimeSequence) + # The method below creates a series of helper functions that are used to # perform the sparse matrix of indexing for the parameters, variables, and # equations below. - M.Create_StateSequence = BuildAction(rule=CreateTimeSequence) M.Create_SparseDicts = BuildAction(rule=CreateSparseDicts) M.CapacityFactor_rpsdt = Set(dimen=5, initialize=CapacityFactorTechIndices) @@ -499,7 +505,6 @@ def __init__(M, *args, **kwargs): M.EmissionEndOfLife = Param(M.regions, M.commodity_emissions, M.tech_with_capacity, M.vintage_all) M.MyopicBaseyear = Param(default=0) - M.DaysPerPeriod = Param() ################################################ # Model Variables # @@ -651,12 +656,6 @@ def __init__(M, *args, **kwargs): M.progress_marker_6 = BuildAction(['Starting Storage Constraints'], rule=progress_check) - # We make use of this following set in some of the storage constraints. - # Pre-computing it is considerably faster. - M.SegFracPerSeason = Param(M.time_optimize, M.time_season_all, initialize=SegFracPerSeason_rule) - M.TimeStorageSeason = Param(M.time_optimize, M.time_season_all, M.time_season_all) - M.validate_StorageSeason = BuildAction(rule=validate_StorageSeason) - M.SeasonalStorageEnergyConstraint = Constraint( M.SeasonalStorageLevel_rpstv, rule=SeasonalStorageEnergy_Constraint ) diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index db4106917..a9302826e 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -10,6 +10,7 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); CREATE TABLE MetaDataReal ( element TEXT, @@ -952,7 +953,7 @@ CREATE TABLE TimeSeason ); INSERT INTO TimeSeason VALUES(2000,1,'S1',NULL); INSERT INTO TimeSeason VALUES(2005,1,'S1',NULL); -CREATE TABLE IF NOT EXISTS TimeStorageSeason +CREATE TABLE TimeStorageSeason ( period INTEGER REFERENCES TimePeriod (period), @@ -960,8 +961,10 @@ CREATE TABLE IF NOT EXISTS TimeStorageSeason storage_season TEXT, season TEXT REFERENCES TimeSeason (season), + count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season) + PRIMARY KEY (period, sequence, storage_season, season), + CHECK (count > 0) ); CREATE TABLE TimePeriodType ( diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index b989ba6d8..5471f850c 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -10,6 +10,7 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); CREATE TABLE MetaDataReal ( element TEXT, @@ -1439,7 +1440,7 @@ INSERT INTO TimeSeason VALUES(2020,9,'summer',NULL); INSERT INTO TimeSeason VALUES(2020,10,'autumn',NULL); INSERT INTO TimeSeason VALUES(2020,11,'winter',NULL); INSERT INTO TimeSeason VALUES(2020,12,'spring',NULL); -CREATE TABLE IF NOT EXISTS TimeStorageSeason +CREATE TABLE TimeStorageSeason ( period INTEGER REFERENCES TimePeriod (period), @@ -1447,8 +1448,10 @@ CREATE TABLE IF NOT EXISTS TimeStorageSeason storage_season TEXT, season TEXT REFERENCES TimeSeason (season), + count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season) + PRIMARY KEY (period, sequence, storage_season, season), + CHECK (count > 0) ); CREATE TABLE TimePeriodType ( diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 1b8c05f19..afd0e5ccd 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -10,6 +10,7 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES('myopic_base_year',2000,''); +INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); CREATE TABLE MetaDataReal ( element TEXT, @@ -1028,7 +1029,7 @@ CREATE TABLE TimeSeason ); INSERT INTO TimeSeason VALUES(2025,1,'s1',NULL); INSERT INTO TimeSeason VALUES(2025,2,'s2',NULL); -CREATE TABLE IF NOT EXISTS TimeStorageSeason +CREATE TABLE TimeStorageSeason ( period INTEGER REFERENCES TimePeriod (period), @@ -1036,8 +1037,10 @@ CREATE TABLE IF NOT EXISTS TimeStorageSeason storage_season TEXT, season TEXT REFERENCES TimeSeason (season), + count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season) + PRIMARY KEY (period, sequence, storage_season, season), + CHECK (count > 0) ); CREATE TABLE TimePeriodType ( diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 16c6e80d7..61b36479d 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -4120,7 +4120,6 @@ ] ], "TimeNext": [], - "TimeStorageSeason": [], "commodity_all": [ "FusionGas", "RH", diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index fb007620e..bf1946f84 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -10,6 +10,7 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES('myopic_base_year',1990,''); +INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); CREATE TABLE MetaDataReal ( element TEXT, @@ -921,7 +922,7 @@ CREATE TABLE TimeSeason ); INSERT INTO TimeSeason VALUES(2000,1,'summer',NULL); INSERT INTO TimeSeason VALUES(2000,2,'winter',NULL); -CREATE TABLE IF NOT EXISTS TimeStorageSeason +CREATE TABLE TimeStorageSeason ( period INTEGER REFERENCES TimePeriod (period), @@ -929,8 +930,10 @@ CREATE TABLE IF NOT EXISTS TimeStorageSeason storage_season TEXT, season TEXT REFERENCES TimeSeason (season), + count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season) + PRIMARY KEY (period, sequence, storage_season, season), + CHECK (count > 0) ); CREATE TABLE TimePeriodType ( diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index 5a4730456..efecfde22 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -10,6 +10,7 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES('myopic_base_year',2000,''); +INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); CREATE TABLE MetaDataReal ( element TEXT, @@ -946,7 +947,7 @@ CREATE TABLE TimeSeason ); INSERT INTO TimeSeason VALUES(2025,1,'s1',NULL); INSERT INTO TimeSeason VALUES(2025,2,'s2',NULL); -CREATE TABLE IF NOT EXISTS TimeStorageSeason +CREATE TABLE TimeStorageSeason ( period INTEGER REFERENCES TimePeriod (period), @@ -954,8 +955,10 @@ CREATE TABLE IF NOT EXISTS TimeStorageSeason storage_season TEXT, season TEXT REFERENCES TimeSeason (season), + count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season) + PRIMARY KEY (period, sequence, storage_season, season), + CHECK (count > 0) ); CREATE TABLE TimePeriodType ( diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index ec89ca1a6..f2fbb2f72 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -10,6 +10,7 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); CREATE TABLE MetaDataReal ( element TEXT, @@ -1429,7 +1430,7 @@ INSERT INTO TimeSeason VALUES(2030,1,'spring',NULL); INSERT INTO TimeSeason VALUES(2030,2,'summer',NULL); INSERT INTO TimeSeason VALUES(2030,3,'fall',NULL); INSERT INTO TimeSeason VALUES(2030,4,'winter',NULL); -CREATE TABLE IF NOT EXISTS TimeStorageSeason +CREATE TABLE TimeStorageSeason ( period INTEGER REFERENCES TimePeriod (period), @@ -1437,8 +1438,10 @@ CREATE TABLE IF NOT EXISTS TimeStorageSeason storage_season TEXT, season TEXT REFERENCES TimeSeason (season), + count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season) + PRIMARY KEY (period, sequence, storage_season, season), + CHECK (count > 0) ); CREATE TABLE TimePeriodType ( diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 8553ebd2b..b8639c41f 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -46509,7 +46509,6 @@ ] ], "TimeNext": [], - "TimeStorageSeason": [], "commodity_all": [ "ethos", "RH", diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 8792b0ca7..952e49218 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -10,6 +10,7 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('myopic_base_year',1990,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); CREATE TABLE MetaDataReal ( element TEXT, @@ -1411,7 +1412,7 @@ INSERT INTO TimeSeason VALUES(2000,3,'winter',NULL); INSERT INTO TimeSeason VALUES(2010,1,'inter',NULL); INSERT INTO TimeSeason VALUES(2010,2,'summer',NULL); INSERT INTO TimeSeason VALUES(2010,3,'winter',NULL); -CREATE TABLE IF NOT EXISTS TimeStorageSeason +CREATE TABLE TimeStorageSeason ( period INTEGER REFERENCES TimePeriod (period), @@ -1419,8 +1420,10 @@ CREATE TABLE IF NOT EXISTS TimeStorageSeason storage_season TEXT, season TEXT REFERENCES TimeSeason (season), + count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season) + PRIMARY KEY (period, sequence, storage_season, season), + CHECK (count > 0) ); CREATE TABLE TimePeriodType ( diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 12b5d6e69..9c177e8b0 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -25593,7 +25593,6 @@ ] ], "TimeNext": [], - "TimeStorageSeason": [], "commodity_all": [ "ethos", "RH", From 46a8c6339dc6f1580fd95f4a4fc9f5cdb900e610 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 16 Jun 2025 16:24:25 -0400 Subject: [PATCH 113/587] Fix some bugs in LDES and example database appears to be working as intended --- data_files/example_dbs/ldes.sql | 225 ++--------------------- temoa/temoa_model/hybrid_loader.py | 1 + temoa/temoa_model/table_data_puller.py | 8 +- temoa/temoa_model/temoa_initialize.py | 17 +- temoa/temoa_model/temoa_model.py | 26 ++- temoa/temoa_model/temoa_rules.py | 44 +++-- tests/testing_data/mediumville_sets.json | 1 + tests/testing_data/test_system_sets.json | 1 + tests/testing_data/utopia_sets.json | 1 + 9 files changed, 79 insertions(+), 245 deletions(-) diff --git a/data_files/example_dbs/ldes.sql b/data_files/example_dbs/ldes.sql index b318b87ae..e116b5cdf 100644 --- a/data_files/example_dbs/ldes.sql +++ b/data_files/example_dbs/ldes.sql @@ -10,7 +10,7 @@ CREATE TABLE MetaData INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); -INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); +INSERT INTO MetaData VALUES('days_per_period',365,'count of days in each period'); CREATE TABLE MetaDataReal ( element TEXT, @@ -28,133 +28,12 @@ CREATE TABLE OutputDualVariable dual REAL, PRIMARY KEY (constraint_name, scenario) ); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,d,generator,2000]',-0.085703001173645247945); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,d,demand,2000]',-0.00023042368874485079643); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,d,demand,2000]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,b,generator,2000]',-0.085357366392446838432); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,a,demand,2000]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,c,generator,2000]',-0.085703001174349608959); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,b,generator,2000]',-0.11558070679412910664); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,c,demand,2000]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,c,demand,2000]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,b,demand,2000]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,b,demand,2000]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,c,generator,2000]',-0.11558070712241454991); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,a,generator,2000]',-0.08535736638981534341); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,a,generator,2000]',-0.11558070668246853696); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,discharge,d,generator,2000]',-0.11558070724338096457); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityConstraint[region,2000,charge,a,demand,2000]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityAvailableByPeriodAndTechConstraint[region,2000,seas_stor]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityAvailableByPeriodAndTechConstraint[region,2000,generator]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityAvailableByPeriodAndTechConstraint[region,2000,demand]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','CapacityAvailableByPeriodAndTechConstraint[region,2000,dly_stor]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','AdjustedCapacityConstraint[region,2000,seas_stor,2000]',-25.231393917561169004); -INSERT INTO OutputDualVariable VALUES('zulu','AdjustedCapacityConstraint[region,2000,demand,2000]',-0.25231393917561169004); -INSERT INTO OutputDualVariable VALUES('zulu','AdjustedCapacityConstraint[region,2000,dly_stor,2000]',-0.25231393917561169004); -INSERT INTO OutputDualVariable VALUES('zulu','AdjustedCapacityConstraint[region,2000,generator,2000]',-252.31393917561164563); -INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,charge,b,demand]',8.7443107076524206888); -INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,charge,c,demand]',8.7446563424276391174); -INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,charge,a,demand]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,discharge,a,demand]',0.0); -INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,discharge,d,demand]',8.7747644720271349427); -INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,discharge,b,demand]',8.7745340480390616733); -INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,discharge,c,demand]',8.7745340482176992225); -INSERT INTO OutputDualVariable VALUES('zulu','DemandConstraint[region,2000,charge,d,demand]',8.7446563424269339037); -INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,charge,b,electricity]',4.4148340370215981565); -INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,charge,c,electricity]',4.4151796717968148087); -INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,discharge,a,electricity]',4.44505737729657735); -INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,charge,a,electricity]',4.4148340370189664838); -INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,discharge,d,electricity]',4.4450573777075668147); -INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,discharge,b,electricity]',4.4450573774082373645); -INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,discharge,c,electricity]',4.4450573775868758019); -INSERT INTO OutputDualVariable VALUES('zulu','CommodityBalanceConstraint[region,2000,charge,d,electricity]',4.4151796717961104832); -INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyConstraint[region,2000,winter,seas_stor,2000]',-4.4329123900165026128); -INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyConstraint[region,2000,summer,seas_stor,2000]',-4.4329123900150158021); -INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,winter,c,seas_stor,2000]',-9.9285300719515330314e-13); -INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,winter,a,seas_stor,2000]',-2.2220266853952255203e-12); -INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,summer,d,seas_stor,2000]',-1.3760422345105398633e-12); -INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,winter,d,seas_stor,2000]',-7.7749544304990836351e-13); -INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,summer,c,seas_stor,2000]',-9.928636176739285446e-13); -INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,summer,a,seas_stor,2000]',-6.3758520034707890644e-13); -INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,winter,b,seas_stor,2000]',-1.3731094778566776959e-12); -INSERT INTO OutputDualVariable VALUES('zulu','SeasonalStorageEnergyUpperBoundConstraint[region,2000,summer,b,seas_stor,2000]',-7.7654566423139437247e-13); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,c,seas_stor,2000]',6.4416949203073858853e-13); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,b,seas_stor,2000]',6.6523075894421745957e-13); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,b,seas_stor,2000]',-4.7138287749897429534e-13); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,c,dly_stor,2000]',4.4151796717729769881); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,b,dly_stor,2000]',4.4148340370445753322); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,a,dly_stor,2000]',4.4148340370562451084); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,a,seas_stor,2000]',8.1624677449077918112e-14); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,a,seas_stor,2000]',8.8939163809495713763e-14); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,d,dly_stor,2000]',4.415179671760228075); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,c,dly_stor,2000]',4.4450573775854937963); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,a,dly_stor,2000]',4.4450573773388573073); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,charge,c,seas_stor,2000]',-5.821732668700695612e-13); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,b,dly_stor,2000]',4.4450573774107144942); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyConstraint[region,2000,discharge,d,dly_stor,2000]',4.4450573776637751777); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,charge,c,dly_stor,2000]',-0.00034563473280713847834); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,charge,b,dly_stor,2000]',-4.5045066420029851173e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,charge,a,dly_stor,2000]',-1.8570385267138625806e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,charge,d,dly_stor,2000]',-4.4825967675597020445e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,discharge,c,dly_stor,2000]',-1.7883284614710022175e-10); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,discharge,a,dly_stor,2000]',-3.7581557153964029183e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,discharge,b,dly_stor,2000]',-7.6405648911312447069e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageEnergyUpperBoundConstraint[region,2000,discharge,d,dly_stor,2000]',-8.2734689766129356769e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,c,seas_stor,2000]',-3.5654595609390025146e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,b,seas_stor,2000]',-3.565273019415246658e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,d,seas_stor,2000]',-3.5649814908001054014e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,b,seas_stor,2000]',-0.0019150055793566611583); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,c,dly_stor,2000]',-4.1883387800486087115e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,b,dly_stor,2000]',-1.2069762722145627176e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,a,dly_stor,2000]',-1.7983916895994889628e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,a,seas_stor,2000]',-3.5651827068338381998e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,a,seas_stor,2000]',-0.0019557996514695448198); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,d,dly_stor,2000]',-3.9485685665929972643e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,d,seas_stor,2000]',-0.0018038898687766034001); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,c,dly_stor,2000]',-5.2294209073905513207e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,a,dly_stor,2000]',-2.016437280362393114e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,charge,c,seas_stor,2000]',-0.0017703732824977256754); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,b,dly_stor,2000]',-5.7797571613751692609e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageChargeRateConstraint[region,2000,discharge,d,dly_stor,2000]',-3.87006737036306383e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,c,seas_stor,2000]',-7.0883085262919003355e-09); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,b,seas_stor,2000]',-7.1579661355912342912e-09); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,d,seas_stor,2000]',-7.3829319339268231203e-09); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,b,seas_stor,2000]',-3.5613176789246074882e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,c,dly_stor,2000]',-1.2349788608388929667e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,b,dly_stor,2000]',-4.1884293092433901861e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,a,dly_stor,2000]',-3.9481261846979931462e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,a,seas_stor,2000]',-7.1347346464973728785e-09); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,a,seas_stor,2000]',-3.5613135641518733898e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,d,dly_stor,2000]',-1.7515961681002181649e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,d,seas_stor,2000]',-3.5610586195680133947e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,c,dly_stor,2000]',-5.7082184017434425271e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,a,dly_stor,2000]',-3.8795740106759190268e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,charge,c,seas_stor,2000]',-3.5610355629010550515e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,b,dly_stor,2000]',-5.1906403614485796538e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageDischargeRateConstraint[region,2000,discharge,d,dly_stor,2000]',-2.0711911733338417285e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,c,seas_stor,2000]',-1.5032898104432781849e-08); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,b,seas_stor,2000]',-1.4784579164256117067e-08); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,d,seas_stor,2000]',-1.4859608725011574925e-08); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,b,seas_stor,2000]',-0.0040183819650553598279); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,c,dly_stor,2000]',-1.5889638444455924215e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,b,dly_stor,2000]',-1.5380000139594174335e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,a,dly_stor,2000]',-2.2855346485298646541e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,a,seas_stor,2000]',-1.4696732922444764035e-08); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,a,seas_stor,2000]',-0.0039775878961343966722); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,d,dly_stor,2000]',-2.1971314167586482035e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,d,seas_stor,2000]',-0.0037838629015935030253); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,c,dly_stor,2000]',-8.1736320692959303357e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,a,dly_stor,2000]',-2.5498616661417998763e-11); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,charge,c,seas_stor,2000]',-0.0038173794865856454094); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,b,dly_stor,2000]',-8.2337089532251290791e-12); -INSERT INTO OutputDualVariable VALUES('zulu','StorageThroughputConstraint[region,2000,discharge,d,dly_stor,2000]',-2.6432678697009204249e-11); CREATE TABLE OutputObjective ( scenario TEXT, objective_name TEXT, total_system_cost REAL ); -INSERT INTO OutputObjective VALUES('zulu','TotalCost',76813.228544347014192); CREATE TABLE SectorLabel ( sector TEXT, @@ -863,10 +742,6 @@ CREATE TABLE OutputNetCapacity capacity REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); -INSERT INTO OutputNetCapacity VALUES('zulu','region','electricity',2000,'seas_stor',2000,1.4392656320725425445); -INSERT INTO OutputNetCapacity VALUES('zulu','region','electricity',2000,'demand',2000,3.2000000000000001776); -INSERT INTO OutputNetCapacity VALUES('zulu','region','electricity',2000,'dly_stor',2000,4.2785306855583380425); -INSERT INTO OutputNetCapacity VALUES('zulu','region','electricity',2000,'generator',2000,3.0654425023163081043); CREATE TABLE OutputBuiltCapacity ( scenario TEXT, @@ -880,10 +755,6 @@ CREATE TABLE OutputBuiltCapacity capacity REAL, PRIMARY KEY (region, scenario, tech, vintage) ); -INSERT INTO OutputBuiltCapacity VALUES('zulu','region','electricity','seas_stor',2000,1.4392656320725425445); -INSERT INTO OutputBuiltCapacity VALUES('zulu','region','electricity','demand',2000,3.2000000000000001776); -INSERT INTO OutputBuiltCapacity VALUES('zulu','region','electricity','generator',2000,3.0654425023163081043); -INSERT INTO OutputBuiltCapacity VALUES('zulu','region','electricity','dly_stor',2000,4.2785306855583380425); CREATE TABLE OutputRetiredCapacity ( scenario TEXT, @@ -922,36 +793,6 @@ CREATE TABLE OutputFlowIn flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','d','electricity','seas_stor',2000,'electricity',1.6658229082653559061); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','b','electricity','seas_stor',2000,'electricity',1575.9958575418115955); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','a','electricity','seas_stor',2000,'electricity',1575.9958579731961236); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','d','electricity','seas_stor',2000,'electricity',1575.9956575478158313); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','c','electricity','seas_stor',2000,'electricity',1.8910884059675414192); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','c','electricity','dly_stor',2000,'electricity',1204.7596747035338449); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','a','electricity','dly_stor',2000,'electricity',2618.5087591179661004); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','c','electricity','dly_stor',2000,'electricity',851.96387645265332366); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','b','electricity','dly_stor',2000,'electricity',2188.5411244155807963); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','c','electricity','seas_stor',2000,'electricity',1575.9956514181672204); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','b','electricity','seas_stor',2000,'electricity',1.798751859454663915); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','d','electricity','dly_stor',2000,'electricity',735.89264698708465317); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','a','electricity','seas_stor',2000,'electricity',1.7546442646897240535); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','a','electricity','dly_stor',2000,'electricity',2523.3859171065073923); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','d','electricity','dly_stor',2000,'electricity',719.1263802165781982); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','b','electricity','dly_stor',2000,'electricity',1363.0051112588996709); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','c','electricity','demand',2000,'demand',1752.0); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','d','electricity','demand',2000,'demand',3504.0); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','c','ethos','generator',2000,'electricity',33.566595265745142739); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','d','electricity','demand',2000,'demand',876.0); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','b','electricity','demand',2000,'demand',1752.0); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','a','ethos','generator',2000,'electricity',3356.6595399160439328); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','b','electricity','demand',2000,'demand',438.0); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','b','ethos','generator',2000,'electricity',3356.6595399162086899); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','d','ethos','generator',2000,'electricity',33.566595289722491735); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','a','ethos','generator',2000,'electricity',335.66595390483335847); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','d','ethos','generator',2000,'electricity',671.33190787721055414); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'discharge','b','ethos','generator',2000,'electricity',335.66595390600832971); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','c','ethos','generator',2000,'electricity',671.33190787684080547); -INSERT INTO OutputFlowIn VALUES('zulu','region','electricity',2000,'charge','c','electricity','demand',2000,'demand',438.0); CREATE TABLE OutputFlowOut ( scenario TEXT, @@ -975,34 +816,6 @@ CREATE TABLE OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','d','electricity','seas_stor',2000,'electricity',1568.9482946398751295); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','d','electricity','seas_stor',2000,'electricity',5.895025229563088942e-05); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','c','electricity','seas_stor',2000,'electricity',1568.6232908987555845); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','c','electricity','dly_stor',2000,'electricity',1356.4608769452966008); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','a','electricity','dly_stor',2000,'electricity',714.83103160110816887); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','c','electricity','dly_stor',2000,'electricity',2194.6275577242486676); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','b','electricity','dly_stor',2000,'electricity',845.87743847871745828); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','c','electricity','seas_stor',2000,'electricity',6.2268121432416947413e-05); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','b','electricity','seas_stor',2000,'electricity',1569.3072056574608907); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','d','electricity','dly_stor',2000,'electricity',2516.5563377074744444); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','a','electricity','seas_stor',2000,'electricity',1569.7664178764727083); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','a','electricity','dly_stor',2000,'electricity',742.72223105128469811); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','d','electricity','dly_stor',2000,'electricity',2622.2773131962147097); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','b','electricity','dly_stor',2000,'electricity',1211.8307035541360239); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','c','electricity','demand',2000,'demand',1752.0); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','d','electricity','demand',2000,'demand',3504.0); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','c','ethos','generator',2000,'electricity',33.566595265745142739); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','d','electricity','demand',2000,'demand',876.0); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','b','electricity','demand',2000,'demand',1752.0); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','a','ethos','generator',2000,'electricity',3356.6595399160439328); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','b','electricity','demand',2000,'demand',438.0); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','b','ethos','generator',2000,'electricity',3356.6595399162086899); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','d','ethos','generator',2000,'electricity',33.566595289722491735); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','a','ethos','generator',2000,'electricity',335.66595390483335847); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','d','ethos','generator',2000,'electricity',671.33190787721055414); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'discharge','b','ethos','generator',2000,'electricity',335.66595390600832971); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','c','ethos','generator',2000,'electricity',671.33190787684080547); -INSERT INTO OutputFlowOut VALUES('zulu','region','electricity',2000,'charge','c','electricity','demand',2000,'demand',438.0); CREATE TABLE OutputStorageLevel ( scenario TEXT, @@ -1022,22 +835,6 @@ CREATE TABLE OutputStorageLevel level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'charge','c','dly_stor',2000,17.114122593311056341); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'charge','b','dly_stor',2000,9.7570613005062956091); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'charge','a','dly_stor',2000,0.0); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'charge','d','dly_stor',2000,9.7570613260688681123); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'discharge','c','dly_stor',2000,14.713232852985489884); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'discharge','a','dly_stor',2000,3.4537690983471556194); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'discharge','b','dly_stor',2000,13.884879934054414896); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'discharge','d','dly_stor',2000,13.881993388646614029); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'winter','a','seas_stor',2000,10085.458960857824894); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'winter','b','seas_stor',2000,8517.4471872485479906); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'winter','c','seas_stor',2000,6949.9387334479445499); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'winter','d','seas_stor',2000,5383.206530959131264); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'summer','a','seas_stor',2000,3798.7472513029865162); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'summer','b','seas_stor',2000,5374.7431051676910485); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'summer','c','seas_stor',2000,6950.7389591488673019); -INSERT INTO OutputStorageLevel VALUES('zulu','region','electricity',2000,'summer','d','seas_stor',2000,8526.734548299248928); CREATE TABLE PlanningReserveMargin ( region TEXT @@ -1226,10 +1023,6 @@ CREATE TABLE OutputCost FOREIGN KEY (vintage) REFERENCES TimePeriod (period), FOREIGN KEY (tech) REFERENCES Technology (tech) ); -INSERT INTO OutputCost VALUES('zulu','region','electricity',2000,'demand',2000,0.80740460536195755025,0.0,37926.215634726010428,0.0,0.51801829986182648113,0.0,43800.0,0.0); -INSERT INTO OutputCost VALUES('zulu','region','electricity',2000,'dly_stor',2000,1.0795329311569543673,0.0,0.0,0.0,0.69261162238737030705,0.0,0.0,0.0); -INSERT INTO OutputCost VALUES('zulu','region','electricity',2000,'generator',2000,773.45387307577189162,0.0,38075.357420893887194,0.0,496.23603542939909161,0.0,43972.239969763071698,0.0); -INSERT INTO OutputCost VALUES('zulu','region','electricity',2000,'seas_stor',2000,36.314678114829974653,0.0,0.0,0.0,23.298935492992982609,0.0,0.0,0.0); CREATE TABLE TimeStorageSeason ( period INTEGER @@ -1243,6 +1036,18 @@ CREATE TABLE TimeStorageSeason PRIMARY KEY (period, sequence, storage_season, season), CHECK (count > 0) ); -INSERT INTO TimeStorageSeason VALUES(2000,1,'summer','charge',182.5,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,3,'winter','discharge',182.5,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,1,'summer','charge',152.5,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,2,'sept_w1','discharge',7,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,3,'sept_w2','charge',7,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,4,'sept_w3','discharge',7,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,5,'sept_w4','charge',7,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,6,'sept_29th','discharge',1,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,7,'sept_30th','charge',1,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,8,'winter','discharge',152.5,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,9,'apr_w1','charge',7,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,10,'apr_w2','discharge',7,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,11,'apr_w3','charge',7,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,12,'apr_w4','discharge',7,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,13,'apr_29th','charge',1,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,14,'apr_30th','discharge',1,NULL); COMMIT; diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 8434bac5c..04db2a2a9 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -672,6 +672,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N raw = cur.execute('SELECT period, storage_season, season, count FROM main.TimeStorageSeason ORDER BY period, sequence').fetchall() all_seasons = all_seasons | set((row[1],) for row in raw) load_element(M.TimeStorageSeason, raw) + load_element(M.ordered_storage_season, [(row[0:3]) for row in raw]) # TimeSeason if self.table_exists("TimeSeason"): diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index d0a112fea..46e6aefce 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -250,9 +250,13 @@ def poll_storage_level_results(M: TemoaModel, epsilon=1e-5) -> dict[SLI, float]: res[sli] = state for r, p, s_stor, t, v in M.SeasonalStorageLevel_rpstv: - s = M.time_storage_season[p, s_stor] + s = M.storage_to_season[p, s_stor] + # Ratio of days in virtual storage season to days in actual season + # Flows and StorageLevel are normalised to the number of days in the ACTUAL season, so must + # be adjusted to the number of days in the virtual storage season + days_adjust = value(M.TimeStorageSeason[p, s_stor, s]) / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) for d in M.time_of_day: - state = value(M.V_SeasonalStorageLevel[r, p, s_stor, t, v]) + value(M.V_StorageLevel[r, p, s, d, t, v]) + state = value(M.V_SeasonalStorageLevel[r, p, s_stor, t, v]) + value(M.V_StorageLevel[r, p, s, d, t, v]) * days_adjust sli = SLI(r, p, s_stor, d, t, v) if abs(state) < epsilon: state = 0 # still want to know but decimals are ugly res[sli] = state diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 1859b283e..f609ac830 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -954,6 +954,12 @@ def CreateSparseDicts(M: 'TemoaModel'): commodityDownstream_rpo = set(M.commodityDStreamProcess.keys() | M.capacityConsumptionTechs.keys() | M.exportRegions.keys()) M.commodityBalance_rpc = commodityUpstream_rpi.intersection(commodityDownstream_rpo) + # A dictionary of whether a storage tech is seasonal, just to speed things up + for t in M.tech_storage: + M.is_seasonal_storage[t] = False + for t in M.tech_seasonal_storage: + M.is_seasonal_storage[t] = True + M.activeFlow_rpsditvo = set( (r, p, s, d, i, t, v, o) for r, p, t in M.processVintages.keys() @@ -1066,7 +1072,7 @@ def CreateSparseDicts(M: 'TemoaModel'): for r, p, t in M.storageVintages.keys() if t in M.tech_seasonal_storage for v in M.storageVintages[r, p, t] - for _p, s_stor in M.time_storage_season + for _p, s_stor in M.storage_to_season if _p == p ) @@ -1110,16 +1116,15 @@ def CreateTimeSequence(M: 'TemoaModel'): for p in M.time_optimize: seasons = [ (s_stor, s) - for _p, s_stor, s in M.TimeStorageSeason + for _p, s_stor, s in M.ordered_storage_season if _p == p ] for i, (s_stor, s) in enumerate(seasons): - s_stor, s = seasons[i] - M.time_storage_season[p, s_stor] = s + M.storage_to_season[p, s_stor] = s if (s_stor, s) == seasons[-1]: - M.time_next_storage_season[p, s_stor] = seasons[0][0] + M.time_next_storage[p, s_stor] = seasons[0][0] else: - M.time_next_storage_season[p, s_stor] = seasons[i+1][0] + M.time_next_storage[p, s_stor] = seasons[i+1][0] logger.debug('Created time sequence.') diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 6d570d965..539cd6097 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -124,9 +124,12 @@ def __init__(M, *args, **kwargs): M.processByPeriodAndOutput = dict() M.exportRegions = dict() M.importRegions = dict() + + # These establish time sequencing M.time_next = dict() # {(p, s, d): (s_next, d_next)} sequence of following time slices - M.time_next_storage_season = dict() # {(p, s_stor): (s_stor_next)} - M.time_storage_season = dict() # {(p, s_stor): (s)} + M.time_next_storage = dict() # {(p, s_stor): (s_stor_next)} next virtual storage season + M.storage_to_season = dict() # {(p, s_stor): (s)} season matching this virtual storage season + M.is_seasonal_storage = dict() # to avoid slow O(n2) behaviour in storage constraints ################################################ # Switching Sets # @@ -161,6 +164,9 @@ def __init__(M, *args, **kwargs): M.time_season = Set(M.time_optimize, within=M.time_season_all, ordered=True) M.time_of_day = Set(ordered=True, validate=no_slash_or_pipe) + # This is just to get the TimeStorageSeason table sequentially. There must be a better way but this works for now + M.ordered_storage_season = Set(dimen=3, within=M.time_optimize * M.time_season_all * M.time_season_all, ordered=True) + # Define regions M.regions = Set(validate=region_check) # RegionalIndices is the set of all the possible combinations of interregional exchanges @@ -656,6 +662,14 @@ def __init__(M, *args, **kwargs): M.progress_marker_6 = BuildAction(['Starting Storage Constraints'], rule=progress_check) + M.StorageEnergyConstraint = Constraint( + M.StorageConstraints_rpsdtv, rule=StorageEnergy_Constraint + ) + + M.StorageEnergyUpperBoundConstraint = Constraint( + M.StorageConstraints_rpsdtv, rule=StorageEnergyUpperBound_Constraint + ) + M.SeasonalStorageEnergyConstraint = Constraint( M.SeasonalStorageLevel_rpstv, rule=SeasonalStorageEnergy_Constraint ) @@ -667,14 +681,6 @@ def __init__(M, *args, **kwargs): M.SeasonalStorageUpperBoundConstraint_rpsdtv, rule=SeasonalStorageEnergyUpperBound_Constraint ) - M.StorageEnergyConstraint = Constraint( - M.StorageConstraints_rpsdtv, rule=StorageEnergy_Constraint - ) - - M.StorageEnergyUpperBoundConstraint = Constraint( - M.StorageConstraints_rpsdtv, rule=StorageEnergyUpperBound_Constraint - ) - M.StorageChargeRateConstraint = Constraint( M.StorageConstraints_rpsdtv, rule=StorageChargeRate_Constraint ) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index c4f809a9d..e08381d03 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1262,7 +1262,8 @@ def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): StorageLevel in the next time slice is equal to current StorageLevel plus net charge in the current time slice. """ - if d == M.time_of_day.last() and t in M.tech_seasonal_storage: + # We allow a non-zero daily delta only in the case of seasonal storage + if M.is_seasonal_storage[t] and d == M.time_of_day.last(): return Constraint.Skip # handled by SeasonalStorageEnergy_Constraint # This is the sum of all input=i sent TO storage tech t of vintage v with @@ -1297,7 +1298,7 @@ def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_stor, t, v): over that entire day. """ - s = M.time_storage_season[p, s_stor] + s = M.storage_to_season[p, s_stor] # This is the sum of all input=i sent TO storage tech t of vintage v with # output=o in p,s,d @@ -1317,19 +1318,19 @@ def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_stor, t, v): for d in M.time_of_day ) - # The virtual season delta is the actual season delta, adjusted to actual DAILY delta - # times the number of those delta between these virtual seasons - stored_energy = ( - (charge - discharge) - / (M.SegFracPerSeason[p, s] * M.DaysPerPeriod) # number of days in the actual season - * value(M.TimeStorageSeason[p, s_stor, s]) # number of days in the virtual season - ) + s_stor_next = M.time_next_storage[p, s_stor] + s_next = M.storage_to_season[p, s_stor_next] + + # Ratio of days in virtual storage season to days in actual season + # Flows and StorageLevel are normalised to the number of days in the ACTUAL season, so must + # be adjusted to the number of days in the virtual storage season + days_adjust = value(M.TimeStorageSeason[p, s_stor, s]) / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) + days_adjust_next = value(M.TimeStorageSeason[p, s_stor_next, s_next]) / (value(M.SegFracPerSeason[p, s_next]) * value(M.DaysPerPeriod)) - s_stor_next = M.time_next_storage_season[p, s_stor] - s_next = M.time_storage_season[p, s_stor_next] + stored_energy = (charge - discharge) * days_adjust - start = M.V_SeasonalStorageLevel[r, p, s_stor, t, v] + M.V_StorageLevel[r, p, s, M.time_of_day.first(), t, v] - end = M.V_SeasonalStorageLevel[r, p, s_stor_next, t, v] + M.V_StorageLevel[r, p, s_next, M.time_of_day.first(), t, v] + start = M.V_SeasonalStorageLevel[r, p, s_stor, t, v] + M.V_StorageLevel[r, p, s, M.time_of_day.first(), t, v] * days_adjust + end = M.V_SeasonalStorageLevel[r, p, s_stor_next, t, v] + M.V_StorageLevel[r, p, s_next, M.time_of_day.first(), t, v] * days_adjust_next expr = start + stored_energy == end return expr @@ -1364,14 +1365,14 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): """ - if t in M.tech_seasonal_storage: + if M.is_seasonal_storage[t]: return Constraint.Skip # redundant on SeasonalStorageEnergyUpperBound energy_capacity = ( M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * (value(M.StorageDuration[r, t]) / 8760) - * value(M.SegFracPerSeason[p, s]) * M.DaysPerPeriod + * value(M.SegFracPerSeason[p, s]) * M.DaysPerPeriod # adjust for days in season * value(M.ProcessLifeFrac[r, p, t, v]) ) @@ -1397,7 +1398,7 @@ def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_stor, d, seasons. """ - s = M.time_storage_season[p, s_stor] + s = M.storage_to_season[p, s_stor] energy_capacity = ( M.V_Capacity[r, p, t, v] @@ -1405,8 +1406,17 @@ def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_stor, d, * (value(M.StorageDuration[r, t]) / 8760) * value(M.ProcessLifeFrac[r, p, t, v]) ) + + # Ratio of days in virtual storage season to days in actual season + # Flows and StorageLevel are normalised to the number of days in the ACTUAL season, so must + # be adjusted to the number of days in the virtual storage season + days_adjust = value(M.TimeStorageSeason[p, s_stor, s]) / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) + + # V_StorageLevel tracks the running cumulative delta in the actual season, so must be adjusted + # to the size of the virtual, storage season + running_day_delta = M.V_StorageLevel[r, p, s, d, t, v] * days_adjust - expr = M.V_SeasonalStorageLevel[r, p, s_stor, t, v] + M.V_StorageLevel[r, p, s, d, t, v] <= energy_capacity + expr = M.V_SeasonalStorageLevel[r, p, s_stor, t, v] + running_day_delta <= energy_capacity return expr diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 61b36479d..a14c3b9cf 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -4168,6 +4168,7 @@ "e", "le" ], + "ordered_storage_season": [], "regionalGlobalIndices": [ "B", "A", diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index b8639c41f..ad90c13fa 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -46568,6 +46568,7 @@ "e", "le" ], + "ordered_storage_season": [], "regionalGlobalIndices": [ "R2", "R1", diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 9c177e8b0..e960d8451 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -25654,6 +25654,7 @@ "e", "le" ], + "ordered_storage_season": [], "regionalGlobalIndices": [ "utopia" ], From 1611d049236f2d5da030a1043ab84505af20c094 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 16 Jun 2025 16:33:30 -0400 Subject: [PATCH 114/587] Add test for seasonal storage --- .../{ldes.sql => seasonal_storage.sql} | 0 tests/conftest.py | 1 + tests/legacy_test_values.py | 8 + tests/test_full_runs.py | 1 + .../config_seasonal_storage.toml | 67 ++ tests/testing_data/seasonal_storage.sql | 1053 +++++++++++++++++ 6 files changed, 1130 insertions(+) rename data_files/example_dbs/{ldes.sql => seasonal_storage.sql} (100%) create mode 100644 tests/testing_configs/config_seasonal_storage.toml create mode 100644 tests/testing_data/seasonal_storage.sql diff --git a/data_files/example_dbs/ldes.sql b/data_files/example_dbs/seasonal_storage.sql similarity index 100% rename from data_files/example_dbs/ldes.sql rename to data_files/example_dbs/seasonal_storage.sql diff --git a/tests/conftest.py b/tests/conftest.py index 8f1929e07..9946cb06a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -76,6 +76,7 @@ def refresh_databases() -> None: ('emissions.sql', 'emissions.sqlite'), ('materials.sql', 'materials.sqlite'), ('simple_linked_tech.sql', 'simple_linked_tech.sqlite'), + ('seasonal_storage.sql', 'seasonal_storage.sqlite'), ) for src, db in databases: if Path.exists(data_output_path / db): diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index fc6851c19..6fbbd8345 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -74,4 +74,12 @@ class ExpectedVals(Enum): ExpectedVals.CONSTR_COUNT: 232, ExpectedVals.VAR_COUNT: 140, }, + 'seasonal_storage': { + # added 2025/06/16 after addition of seasonal storage + ExpectedVals.OBJ_VALUE: 76660.8720, + ExpectedVals.EFF_DOMAIN_SIZE: 24, + ExpectedVals.EFF_INDEX_SIZE: 4, + ExpectedVals.CONSTR_COUNT: 180, + ExpectedVals.VAR_COUNT: 90, + }, } diff --git a/tests/test_full_runs.py b/tests/test_full_runs.py index e2288a6ac..260fe9f29 100644 --- a/tests/test_full_runs.py +++ b/tests/test_full_runs.py @@ -42,6 +42,7 @@ {'name': 'utopia', 'filename': 'config_utopia.toml'}, {'name': 'test_system', 'filename': 'config_test_system.toml'}, {'name': 'mediumville', 'filename': 'config_mediumville.toml'}, + {'name': 'seasonal_storage', 'filename': 'config_seasonal_storage.toml'}, ] myopic_files = [{'name': 'myopic utopia', 'filename': 'config_utopia_myopic.toml'}] diff --git a/tests/testing_configs/config_seasonal_storage.toml b/tests/testing_configs/config_seasonal_storage.toml new file mode 100644 index 000000000..e36bba34a --- /dev/null +++ b/tests/testing_configs/config_seasonal_storage.toml @@ -0,0 +1,67 @@ +# this config is used for testing in test_full_runs.py +scenario = "test run" +scenario_mode = "perfect_foresight" + +input_database = "tests/testing_outputs/seasonal_storage.sqlite" +output_database = "tests/testing_outputs/seasonal_storage.sqlite" +neos = false + +# solver +solver_name = "gurobi" + +# generate an excel file in the output_files folder +save_excel = false + +# save the duals in the output .sqlite database +save_duals = false + +# save a copy of the pyomo-generated lp file to the outputs folder (may be large file!) +save_lp_file = false + +# ------------------------------------ +# MODEL PARAMETERS +# these are specific to each model +# ------------------------------------ + +# How to sequence time slices in the model. Options: +# 'seasonal_timeslicing' +# Time slices sequence through seasons and between seasons, looping from the end of each +# period back to its start. Compatible with seasonal time-slicing databases. +# 'representative_periods' +# Time slices sequence through seasons but loop from the end of each season back to its start. +# Time slices do not connect between seasons. Compatible with representative periods databases. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out in +# the schema). This is an advanced feature and not recommended for most users. +time_sequencing = 'representative_periods' + +# How contributions to the planning reserve margin are calculated. Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit +reserve_margin = 'static' + +# --------------------------------------------------- +# MODE OPTIONS +# options below are mode-specific and will be ignored +# if the run is not executed in that mode. +# --------------------------------------------------- +[MGA] +cost_epsilon = 0.03 # 3% relaxation on optimal cost +iteration_limit = 15 # max iterations to perform +time_limit_hrs = 1 # max time +axis = "tech_category_activity" # use the tech activity Manager to control exploration based on categories in Tech +weighting = "hull_expansion" # use a convex hull expansion algorithm to weight exploration + +[myopic] +myopic_view = 2 # number of periods seen at one iteration + + + + diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql new file mode 100644 index 000000000..e116b5cdf --- /dev/null +++ b/tests/testing_data/seasonal_storage.sql @@ -0,0 +1,1053 @@ +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE MetaData +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); +INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); +INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); +INSERT INTO MetaData VALUES('days_per_period',365,'count of days in each period'); +CREATE TABLE MetaDataReal +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); +CREATE TABLE OutputDualVariable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE OutputObjective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE SectorLabel +( + sector TEXT, + PRIMARY KEY (sector) +); +INSERT INTO SectorLabel VALUES('electricity'); +CREATE TABLE CapacityCredit +( + region TEXT, + period INTEGER, + tech TEXT, + vintage INTEGER, + credit REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage), + CHECK (credit >= 0 AND credit <= 1) +); +CREATE TABLE CapacityFactorProcess +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE CapacityFactorTech +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech), + CHECK (factor >= 0 AND factor <= 1) +); +INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','a','generator',1.0,NULL); +INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','b','generator',1.0,NULL); +INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','c','generator',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','d','generator',0.2,NULL); +INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','a','generator',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','b','generator',0.1,NULL); +INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','c','generator',0.01,NULL); +INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','d','generator',0.01,NULL); +CREATE TABLE CapacityToActivity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + c2a REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +INSERT INTO CapacityToActivity VALUES('region','generator',8760.0,'MWh/MWy'); +INSERT INTO CapacityToActivity VALUES('region','dly_stor',8760.0,'MWh/MWy'); +INSERT INTO CapacityToActivity VALUES('region','seas_stor',8760.0,'MWh/MWy'); +INSERT INTO CapacityToActivity VALUES('region','demand',8760.0,'MWh/MWy'); +CREATE TABLE Commodity +( + name TEXT + PRIMARY KEY, + flag TEXT + REFERENCES CommodityType (label), + description TEXT +); +INSERT INTO Commodity VALUES('ethos','s',NULL); +INSERT INTO Commodity VALUES('electricity','p',NULL); +INSERT INTO Commodity VALUES('demand','d',NULL); +CREATE TABLE CommodityType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO CommodityType VALUES('p','physical commodity'); +INSERT INTO CommodityType VALUES('a','annual commodity'); +INSERT INTO CommodityType VALUES('e','emissions commodity'); +INSERT INTO CommodityType VALUES('d','demand commodity'); +INSERT INTO CommodityType VALUES('s','source commodity'); +INSERT INTO CommodityType VALUES('w','waste commodity'); +INSERT INTO CommodityType VALUES('wa','waste annual commodity'); +INSERT INTO CommodityType VALUES('wp','waste physical commodity'); +CREATE TABLE ConstructionInput +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); +CREATE TABLE CostEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT NOT NULL + REFERENCES Commodity (name), + cost REAL NOT NULL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE CostFixed +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE CostInvest +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +INSERT INTO CostInvest VALUES('region','generator',2000,1000.0,'',NULL); +INSERT INTO CostInvest VALUES('region','dly_stor',2000,1.0,'',NULL); +INSERT INTO CostInvest VALUES('region','seas_stor',2000,100.0,'',NULL); +INSERT INTO CostInvest VALUES('region','demand',2000,1.0,'',NULL); +CREATE TABLE CostVariable +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +INSERT INTO CostVariable VALUES('region',2000,'generator',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2000,'demand',2000,1.0,NULL,NULL); +CREATE TABLE Demand +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + commodity TEXT + REFERENCES Commodity (name), + demand REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, commodity) +); +INSERT INTO Demand VALUES('region',2000,'demand',8760.0,'MWh',NULL); +CREATE TABLE DemandSpecificDistribution +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + demand_name TEXT + REFERENCES Commodity (name), + dsd REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), + CHECK (dsd >= 0 AND dsd <= 1) +); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','a','demand',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','b','demand',0.05,NULL); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','c','demand',0.05,NULL); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','d','demand',0.1,NULL); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','a','demand',0.0,NULL); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','b','demand',0.2,NULL); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','c','demand',0.2,NULL); +INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','d','demand',0.4,NULL); +CREATE TABLE EndOfLifeOutput +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) +); +CREATE TABLE Efficiency +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +INSERT INTO Efficiency VALUES('region','ethos','generator',2000,'electricity',1.0,NULL); +INSERT INTO Efficiency VALUES('region','electricity','dly_stor',2000,'electricity',1.0,NULL); +INSERT INTO Efficiency VALUES('region','electricity','seas_stor',2000,'electricity',1.0,NULL); +INSERT INTO Efficiency VALUES('region','electricity','demand',2000,'demand',1.0,NULL); +CREATE TABLE EfficiencyVariable +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE EmissionActivity +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) +); +CREATE TABLE EmissionEmbodied +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE EmissionEndOfLife +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE ExistingCapacity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE TechGroup +( + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE LoanLifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE LifetimeProcess +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE LifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE Operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO Operator VALUES('e','equal to'); +INSERT INTO Operator VALUES('le','less than or equal to'); +INSERT INTO Operator VALUES('ge','greater than or equal to'); +CREATE TABLE LimitGrowthCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitDegrowthCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitGrowthNewCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitDegrowthNewCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitGrowthNewCapacityDelta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitDegrowthNewCapacityDelta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitStorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) +); +CREATE TABLE LimitActivity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE LimitActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE LimitAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, operator), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE LimitCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE LimitCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE LimitNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE LimitNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE LimitResource +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitSeasonalCapacityFactor +( + region TEXT + REFERENCES Region (region), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) +); +CREATE TABLE LimitTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputFlowOut +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); +CREATE TABLE PlanningReserveMargin +( + region TEXT + PRIMARY KEY + REFERENCES Region (region), + margin REAL +); +CREATE TABLE RampDown +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE RampUp +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE Region +( + region TEXT + PRIMARY KEY, + notes TEXT +); +INSERT INTO Region VALUES('region',NULL); +CREATE TABLE TimeSegmentFraction +( + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + segfrac REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segfrac >= 0 AND segfrac <= 1) +); +INSERT INTO TimeSegmentFraction VALUES(2000,'charge','a',0.125,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'charge','b',0.125,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'charge','c',0.125,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'charge','d',0.125,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','a',0.125,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','b',0.125,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','c',0.125,NULL); +INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','d',0.125,NULL); +CREATE TABLE StorageDuration +( + region TEXT, + tech TEXT, + duration REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +INSERT INTO StorageDuration VALUES('region','dly_stor',4.0,NULL); +INSERT INTO StorageDuration VALUES('region','seas_stor',8760.0,NULL); +CREATE TABLE TechnologyType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO TechnologyType VALUES('r','resource technology'); +INSERT INTO TechnologyType VALUES('p','production technology'); +INSERT INTO TechnologyType VALUES('pb','baseload production technology'); +INSERT INTO TechnologyType VALUES('ps','storage production technology'); +CREATE TABLE TimeOfDay +( + sequence INTEGER UNIQUE, + tod TEXT + PRIMARY KEY +); +INSERT INTO TimeOfDay VALUES(0,'a'); +INSERT INTO TimeOfDay VALUES(1,'b'); +INSERT INTO TimeOfDay VALUES(2,'c'); +INSERT INTO TimeOfDay VALUES(3,'d'); +CREATE TABLE TimePeriod +( + sequence INTEGER UNIQUE, + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES TimePeriodType (label) +); +INSERT INTO TimePeriod VALUES(0,2000,'f'); +INSERT INTO TimePeriod VALUES(1,2005,'f'); +CREATE TABLE TimeSeason +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT, + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +INSERT INTO TimeSeason VALUES(2000,0,'charge',NULL); +INSERT INTO TimeSeason VALUES(2000,1,'discharge',NULL); +CREATE TABLE TimePeriodType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO TimePeriodType VALUES('e','existing vintages'); +INSERT INTO TimePeriodType VALUES('f','future'); +CREATE TABLE OutputEmission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE RPSRequirement +( + region TEXT NOT NULL + REFERENCES Region (region), + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech_group TEXT NOT NULL + REFERENCES TechGroup (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE TechGroupMember +( + group_name TEXT + REFERENCES TechGroup (group_name), + tech TEXT + REFERENCES Technology (tech), + PRIMARY KEY (group_name, tech) +); +CREATE TABLE Technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES TechnologyType (label) +); +INSERT INTO Technology VALUES('generator','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('dly_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('seas_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,1,NULL); +INSERT INTO Technology VALUES('demand','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +CREATE TABLE OutputCost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES TimePeriod (period), + FOREIGN KEY (tech) REFERENCES Technology (tech) +); +CREATE TABLE TimeStorageSeason +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + storage_season TEXT, + season TEXT + REFERENCES TimeSeason (season), + count NUMERIC NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, storage_season, season), + CHECK (count > 0) +); +INSERT INTO TimeStorageSeason VALUES(2000,1,'summer','charge',152.5,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,2,'sept_w1','discharge',7,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,3,'sept_w2','charge',7,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,4,'sept_w3','discharge',7,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,5,'sept_w4','charge',7,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,6,'sept_29th','discharge',1,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,7,'sept_30th','charge',1,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,8,'winter','discharge',152.5,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,9,'apr_w1','charge',7,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,10,'apr_w2','discharge',7,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,11,'apr_w3','charge',7,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,12,'apr_w4','discharge',7,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,13,'apr_29th','charge',1,NULL); +INSERT INTO TimeStorageSeason VALUES(2000,14,'apr_30th','discharge',1,NULL); +COMMIT; From e77917ff6443f5b8e1e95b6a27f211a6e7b2c3ac Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 16 Jun 2025 17:00:58 -0400 Subject: [PATCH 115/587] Fix utopia in example dbs --- data_files/example_dbs/utopia.sql | 49 ++++++++++++------------------- 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 0b48b7b1e..952e49218 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -1425,17 +1425,6 @@ CREATE TABLE TimeStorageSeason PRIMARY KEY (period, sequence, storage_season, season), CHECK (count > 0) ); -CREATE TABLE TimeStorageSeason -( - period INTEGER - REFERENCES TimePeriod (period), - sequence INTEGER, - storage_season TEXT, - season TEXT - REFERENCES TimeSeason (season), - notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season) -); CREATE TABLE TimePeriodType ( label TEXT @@ -1498,25 +1487,25 @@ CREATE TABLE Technology description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('IMPDSL1','r','supply','petroleum','',1,0,0,0,0,0,0,' imported diesel'); -INSERT INTO Technology VALUES('IMPGSL1','r','supply','petroleum','',1,0,0,0,0,0,0,' imported gasoline'); -INSERT INTO Technology VALUES('IMPHCO1','r','supply','coal','',1,0,0,0,0,0,0,' imported coal'); -INSERT INTO Technology VALUES('IMPOIL1','r','supply','petroleum','',1,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO Technology VALUES('IMPURN1','r','supply','nuclear','',1,0,0,0,0,0,0,' imported uranium'); -INSERT INTO Technology VALUES('IMPFEQ','r','supply','petroleum','',1,0,0,0,0,0,0,' imported fossil equivalent'); -INSERT INTO Technology VALUES('IMPHYD','r','supply','hydro','',1,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); -INSERT INTO Technology VALUES('E01','pb','electric','coal','',0,0,0,0,0,0,0,' coal power plant'); -INSERT INTO Technology VALUES('E21','pb','electric','nuclear','',0,0,0,0,0,0,0,' nuclear power plant'); -INSERT INTO Technology VALUES('E31','pb','electric','hydro','',0,0,0,0,0,0,0,' hydro power'); -INSERT INTO Technology VALUES('E51','ps','electric','electric','',0,0,0,0,0,0,0,' electric storage'); -INSERT INTO Technology VALUES('E70','p','electric','petroleum','',0,0,0,0,0,0,0,' diesel power plant'); -INSERT INTO Technology VALUES('RHE','p','residential','electric','',0,0,0,0,0,0,0,' electric residential heating'); -INSERT INTO Technology VALUES('RHO','p','residential','petroleum','',0,0,0,0,0,0,0,' diesel residential heating'); -INSERT INTO Technology VALUES('RL1','p','residential','electric','',0,0,0,0,0,0,0,' residential lighting'); -INSERT INTO Technology VALUES('SRE','p','supply','petroleum','',0,0,0,0,0,0,0,' crude oil processor'); -INSERT INTO Technology VALUES('TXD','p','transport','petroleum','',0,0,0,0,0,0,0,' diesel powered vehicles'); -INSERT INTO Technology VALUES('TXE','p','transport','electric','',0,0,0,0,0,0,0,' electric powered vehicles'); -INSERT INTO Technology VALUES('TXG','p','transport','petroleum','',0,0,0,0,0,0,0,' gasoline powered vehicles'); +INSERT INTO Technology VALUES('IMPDSL1','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported diesel'); +INSERT INTO Technology VALUES('IMPGSL1','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported gasoline'); +INSERT INTO Technology VALUES('IMPHCO1','r','supply','coal','',1,0,0,0,0,0,0,0,' imported coal'); +INSERT INTO Technology VALUES('IMPOIL1','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported crude oil'); +INSERT INTO Technology VALUES('IMPURN1','r','supply','nuclear','',1,0,0,0,0,0,0,0,' imported uranium'); +INSERT INTO Technology VALUES('IMPFEQ','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported fossil equivalent'); +INSERT INTO Technology VALUES('IMPHYD','r','supply','hydro','',1,0,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); +INSERT INTO Technology VALUES('E01','pb','electric','coal','',0,0,0,0,0,0,0,0,' coal power plant'); +INSERT INTO Technology VALUES('E21','pb','electric','nuclear','',0,0,0,0,0,0,0,0,' nuclear power plant'); +INSERT INTO Technology VALUES('E31','pb','electric','hydro','',0,0,0,0,0,0,0,0,' hydro power'); +INSERT INTO Technology VALUES('E51','ps','electric','electric','',0,0,0,0,0,0,0,0,' electric storage'); +INSERT INTO Technology VALUES('E70','p','electric','petroleum','',0,0,0,0,0,0,0,0,' diesel power plant'); +INSERT INTO Technology VALUES('RHE','p','residential','electric','',0,0,0,0,0,0,0,0,' electric residential heating'); +INSERT INTO Technology VALUES('RHO','p','residential','petroleum','',0,0,0,0,0,0,0,0,' diesel residential heating'); +INSERT INTO Technology VALUES('RL1','p','residential','electric','',0,0,0,0,0,0,0,0,' residential lighting'); +INSERT INTO Technology VALUES('SRE','p','supply','petroleum','',0,0,0,0,0,0,0,0,' crude oil processor'); +INSERT INTO Technology VALUES('TXD','p','transport','petroleum','',0,0,0,0,0,0,0,0,' diesel powered vehicles'); +INSERT INTO Technology VALUES('TXE','p','transport','electric','',0,0,0,0,0,0,0,0,' electric powered vehicles'); +INSERT INTO Technology VALUES('TXG','p','transport','petroleum','',0,0,0,0,0,0,0,0,' gasoline powered vehicles'); CREATE TABLE OutputCost ( scenario TEXT, From 5b4f3bb20c2f7b95e042c4960e652d7ea58b2c9c Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 16 Jun 2025 17:53:43 -0400 Subject: [PATCH 116/587] Audit reserve margin a bit --- .../temoa_model/model_checking/validators.py | 25 +++++++++++++++---- temoa/temoa_model/temoa_initialize.py | 3 ++- temoa/temoa_model/temoa_model.py | 4 ++- temoa/temoa_model/temoa_rules.py | 12 +++++++-- tests/legacy_test_values.py | 2 +- tests/testing_data/mediumville.sql | 4 +-- tests/testing_data/mediumville_sets.json | 2 +- 7 files changed, 39 insertions(+), 13 deletions(-) diff --git a/temoa/temoa_model/model_checking/validators.py b/temoa/temoa_model/model_checking/validators.py index 12372f5bf..02d8b1c83 100644 --- a/temoa/temoa_model/model_checking/validators.py +++ b/temoa/temoa_model/model_checking/validators.py @@ -323,12 +323,18 @@ def validate_StorageSeason(M: 'TemoaModel'): storage[p, s] += value(M.TimeStorageSeason[p, s_stor, s]) # Check that TimeStorageSeason day counts total to number of days in each period - if abs(sum(storage.values()) - value(M.DaysPerPeriod)) >= 0.001: - logger.warning( - f'Sum of day count in TimeStorageSeason ({sum(storage.values())}) ' - f'does not sum to days_per_season ({value(M.DaysPerPeriod)}) from the ' - 'MetaData table.' + for p in M.time_optimize: + count_total = sum( + storage[p, s] + for _p, s in storage + if _p == p ) + if abs(count_total - value(M.DaysPerPeriod)) >= 0.001: + logger.warning( + f'Sum of day count in TimeStorageSeason ({sum(storage.values())}) ' + f'does not sum to days_per_season ({value(M.DaysPerPeriod)}) from the ' + 'MetaData table.' + ) # Check that seasons using in storage seasons are actual seasons for (p, s) in storage: @@ -363,6 +369,15 @@ def validate_StorageSeason(M: 'TemoaModel'): logger.warning(msg) +def validate_ReserveMargin(M: 'TemoaModel'): + for r in M.PlanningReserveMargin: + if all((r, p) not in M.processReservePeriods for p in M.time_optimize): + logger.warning( + 'Planning reserve margin provided but there are no reserve ' + f'technologies serving this region: {r, M.PlanningReserveMargin[r]}' + ) + + def validate_tech_sets(M: 'TemoaModel'): """ Check tech sets for any forbidden intersections diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index f609ac830..0481c83fc 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -581,7 +581,7 @@ def CreateDemands(M: 'TemoaModel'): for d in M.time_of_day if (r, p, s, d, dem) not in keys ) - logger.warning( + logger.info( 'Missing some time slices for Demand Specific Distribution %s: %s', (r, p, dem), missing, ) @@ -1567,6 +1567,7 @@ def ReserveMarginIndices(M: 'TemoaModel'): (r, p, s, d) for r in M.PlanningReserveMargin for p in M.time_optimize + if (r, p) in M.processReservePeriods for s in M.time_season[p] for d in M.time_of_day ) diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 539cd6097..b5ffd50d0 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -43,6 +43,7 @@ validate_tech_sets, no_slash_or_pipe, validate_StorageSeason, + validate_ReserveMargin, ) from temoa.temoa_model.temoa_initialize import * from temoa.temoa_model.temoa_initialize import get_loan_life @@ -503,7 +504,7 @@ def __init__(M, *args, **kwargs): M.ReserveMargin = Set() # How contributions to the reserve margin are calculated M.CapacityCredit = Param( - M.regionalIndices, M.time_optimize, M.tech_all, M.vintage_all, default=0, validate=validate_0to1 + M.regionalIndices, M.time_optimize, M.tech_all, M.vintage_all, default=1, validate=validate_0to1 ) M.PlanningReserveMargin = Param(M.regions) @@ -703,6 +704,7 @@ def __init__(M, *args, **kwargs): M.RampDownConstraint = Constraint(M.RampDownConstraint_rpsdtv, rule=RampDown_Constraint) M.ReserveMargin_rpsd = Set(dimen=4, initialize=ReserveMarginIndices) + M.validate_ReserveMargin = BuildAction(rule=validate_ReserveMargin) M.ReserveMarginConstraint = Constraint(M.ReserveMargin_rpsd, rule=ReserveMargin_Constraint) M.LimitEmissionConstraint = Constraint( diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index e08381d03..ff46b655f 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1877,8 +1877,8 @@ def ReserveMarginDynamic(M: 'TemoaModel', r, p, s, d): if t not in M.tech_uncap and t not in M.tech_storage ) - # Storage (not exchange) - # Derated output flow (discharge) + # Storage + # Derated net output flow available += sum( M.V_FlowOut[r, p, s, d, i, t, v, o] * value(M.CapacityCredit[r, p, t, v]) @@ -1887,6 +1887,14 @@ def ReserveMarginDynamic(M: 'TemoaModel', r, p, s, d): for i in M.processInputs[r, p, t, v] for o in M.processOutputsByInput[r, p, t, v, i] ) + available -= sum( + M.V_FlowIn[r, p, s, d, i, t, v, o] + * value(M.CapacityCredit[r, p, t, v]) + for (t, v) in M.processReservePeriods[r, p] + if t in M.tech_storage + for i in M.processInputs[r, p, t, v] + for o in M.processOutputsByInput[r, p, t, v, i] + ) # The above code does not consider exchange techs, e.g. electricity # transmission between two distinct regions. diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index 6fbbd8345..9767e625d 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -68,7 +68,7 @@ class ExpectedVals(Enum): }, 'mediumville': { # added 2025/06/12 prior to addition of dynamic reserve margin - ExpectedVals.OBJ_VALUE: 8139.1913, + ExpectedVals.OBJ_VALUE: 7035.7275, # reduced 2025/06/16 after fixing bug in db ExpectedVals.EFF_DOMAIN_SIZE: 2800, ExpectedVals.EFF_INDEX_SIZE: 18, ExpectedVals.CONSTR_COUNT: 232, diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index afd0e5ccd..e53fafbd6 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -1110,9 +1110,9 @@ CREATE TABLE Technology ); INSERT INTO Technology VALUES('well','r','supply','water','',0,0,0,0,0,0,0,0,'plain old water'); INSERT INTO Technology VALUES('bulbs','p','residential','electric','',0,0,0,0,0,0,0,0,'residential lighting'); -INSERT INTO Technology VALUES('EH','pb','electric','hydro','',0,0,1,1,1,0,0,0,'hydro power electric plant'); +INSERT INTO Technology VALUES('EH','pb','electric','hydro','',0,0,0,1,1,0,0,0,'hydro power electric plant'); INSERT INTO Technology VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0,0,'big battery'); -INSERT INTO Technology VALUES('EF','p','electric','electric','',0,0,0,0,0,0,0,0,'fusion plant'); +INSERT INTO Technology VALUES('EF','p','electric','electric','',0,0,1,0,0,0,0,0,'fusion plant'); INSERT INTO Technology VALUES('EFL','p','electric','electric','',0,0,0,0,0,1,0,0,'linked (to Fusion) producer'); INSERT INTO Technology VALUES('heater','p','residential','electric','',0,0,0,0,0,0,0,0,'heater'); INSERT INTO Technology VALUES('FGF_pipe','p','transport',NULL,'',0,0,0,0,0,0,1,0,'transportation line A->B'); diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index a14c3b9cf..cbd56f3ce 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -4251,7 +4251,7 @@ "batt" ], "tech_reserve": [ - "EH" + "EF" ], "tech_resource": [ "well" From 9afed7384bc531c9bbe5606f3e93fcbe1d73950b Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 16 Jun 2025 18:44:05 -0400 Subject: [PATCH 117/587] Update LimitStorageLevelFraction constraint to work with seasonal storage --- data_files/example_dbs/seasonal_storage.sql | 2 ++ temoa/temoa_model/temoa_initialize.py | 2 +- temoa/temoa_model/temoa_model.py | 8 ++---- temoa/temoa_model/temoa_rules.py | 31 ++++++++++++++------- tests/legacy_test_values.py | 4 +-- tests/testing_data/mediumville_sets.json | 2 +- tests/testing_data/seasonal_storage.sql | 2 ++ tests/testing_data/test_system_sets.json | 2 +- tests/testing_data/utopia_sets.json | 2 +- 9 files changed, 34 insertions(+), 21 deletions(-) diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql index e116b5cdf..f782a8fec 100644 --- a/data_files/example_dbs/seasonal_storage.sql +++ b/data_files/example_dbs/seasonal_storage.sql @@ -498,6 +498,8 @@ CREATE TABLE LimitStorageLevelFraction notes TEXT, PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); +INSERT INTO LimitStorageLevelFraction VALUES('region', 2000, 'winter', 'b', 'seas_stor', 2000, 'e', 0.5, NULL); +INSERT INTO LimitStorageLevelFraction VALUES('region', 2000, 'charge', 'b', 'dly_stor', 2000, 'e', 0.5, NULL); CREATE TABLE LimitActivity ( region TEXT, diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 0481c83fc..6f7a42cd2 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1350,7 +1350,7 @@ def SeasonalStorageLevelVariableIndices(M: 'TemoaModel'): return M.seasonalStorageLevelIndices_rpstv -def SeasonalStorageEnergyUpperBoundConstraintIndices(M: 'TemoaModel'): +def SeasonalStorageConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, s, d, t, v) for r, p, s, t, v in M.seasonalStorageLevelIndices_rpstv diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index b5ffd50d0..15f57f836 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -490,7 +490,8 @@ def __init__(M, *args, **kwargs): # This set works for all storage-related constraints M.StorageConstraints_rpsdtv = Set(dimen=6, initialize=StorageConstraintIndices) - M.LimitStorageFractionConstraint_rpsdtv = Set(within=M.StorageConstraints_rpsdtv * M.operator) + M.SeasonalStorageConstraints_rpsdtv = Set(dimen=6, initialize=SeasonalStorageConstraintIndices) + M.LimitStorageFractionConstraint_rpsdtv = Set(within=(M.StorageConstraints_rpsdtv | M.SeasonalStorageConstraints_rpsdtv) * M.operator) M.LimitStorageFraction = Param(M.LimitStorageFractionConstraint_rpsdtv, validate=validate_0to1) # Storage duration is expressed in hours @@ -675,11 +676,8 @@ def __init__(M, *args, **kwargs): M.SeasonalStorageLevel_rpstv, rule=SeasonalStorageEnergy_Constraint ) - M.SeasonalStorageUpperBoundConstraint_rpsdtv = Set( - dimen=6, initialize=SeasonalStorageEnergyUpperBoundConstraintIndices - ) M.SeasonalStorageEnergyUpperBoundConstraint = Constraint( - M.SeasonalStorageUpperBoundConstraint_rpsdtv, rule=SeasonalStorageEnergyUpperBound_Constraint + M.SeasonalStorageConstraints_rpsdtv, rule=SeasonalStorageEnergyUpperBound_Constraint ) M.StorageChargeRateConstraint = Constraint( diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index ff46b655f..640bc1bbb 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1357,7 +1357,7 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): :label: StorageEnergyUpperBound \textbf{SL}_{r, p, s, d, t, v} \le - \textbf{CAP}_{r,t,v} \cdot C2A_{r,t} \cdot \frac {SD_{r,t}}{8760 hrs/yr} + \textbf{CAP}_{r,t,v} \cdot C2A_{r,t} \cdot \frac {SD_{r,t}}{24 * value(M.DaysPerPeriod) hrs/yr} \cdot \sum_{d} SEG_{s,d} \cdot M.DaysPerPeriod \\ @@ -1371,7 +1371,7 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): energy_capacity = ( M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) - * (value(M.StorageDuration[r, t]) / 8760) + * (value(M.StorageDuration[r, t]) / (24 * value(M.DaysPerPeriod))) * value(M.SegFracPerSeason[p, s]) * M.DaysPerPeriod # adjust for days in season * value(M.ProcessLifeFrac[r, p, t, v]) ) @@ -1403,7 +1403,7 @@ def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_stor, d, energy_capacity = ( M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) - * (value(M.StorageDuration[r, t]) / 8760) + * (value(M.StorageDuration[r, t]) / (24 * value(M.DaysPerPeriod))) * value(M.ProcessLifeFrac[r, p, t, v]) ) @@ -1558,22 +1558,33 @@ def LimitStorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v, op): \textbf{SF}_{r,p,s,d,t,v} \le \ SF_{r,p,s,d,t,v} \cdot - \textbf{CAP}_{r,p,t,v} \cdot C2A_{r,t} \cdot \frac {SD_{r,t}}{8760 hrs/yr} + \textbf{CAP}_{r,p,t,v} \cdot C2A_{r,t} \cdot \frac {SD_{r,t}}{(24 \cdot DPP hrs/yr} \cdot \sum_{d} SEG_{s,d} \cdot M.DaysPerPeriod days/yr \cdot MPL_{r,p,t,v} \\ \forall \{r, p, s, d, t, v\} \in \Theta_{\text{LimitStorageFraction}} """ - energy_capacity = ( + energy_limit = ( M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) - * (value(M.StorageDuration[r, t]) / 8760) - * M.SegFracPerSeason[p, s] * M.DaysPerPeriod + * (value(M.StorageDuration[r, t]) / (24 * value(M.DaysPerPeriod))) * value(M.ProcessLifeFrac[r, p, t, v]) + * value(M.LimitStorageFraction[r, p, s, d, t, v, op]) ) - expr = operator_expression(M.V_StorageLevel[r, p, s, d, t, v], op, energy_capacity * value(M.LimitStorageFraction[r, p, s, d, t, v, op])) + if M.is_seasonal_storage[t]: + s_stor = s # virtual storage season + s = M.storage_to_season[p, s_stor] # actual season + + # adjust the storage level to the individual-day level + energy_level = M.V_StorageLevel[r, p, s, d, t, v] / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) + + if M.is_seasonal_storage[t]: + # seasonal storage upper energy limit is absolute + energy_level = M.V_SeasonalStorageLevel[r, p, s_stor, t, v] + energy_level * value(M.TimeStorageSeason[p, s_stor, s]) + + expr = operator_expression(energy_level, op, energy_limit) return expr @@ -1640,7 +1651,7 @@ def RampUp_Constraint(M: 'TemoaModel', r, p, s, d, t, v): for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) / value(M.SegFrac[p, s_next, d_next]) - hours_elapsed = 8760 * ( value(M.SegFrac[p, s, d]) + value(M.SegFrac[p, s_next, d_next]) ) / 2 + hours_elapsed = 24 * value(M.DaysPerPeriod) * value(M.SegFrac[p, s, d]) / 2 hours_elapsed /= M.SegFracPerSeason[p, s] * M.DaysPerPeriod # adjust for how many days this season represents ramp_fraction = hours_elapsed * value(M.RampUp[r, t]) @@ -1698,7 +1709,7 @@ def RampDown_Constraint(M: 'TemoaModel', r, p, s, d, t, v): for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) / value(M.SegFrac[p, s_next, d_next]) - hours_elapsed = 8760 * ( value(M.SegFrac[p, s, d]) + value(M.SegFrac[p, s_next, d_next]) ) / 2 + hours_elapsed = 24 * value(M.DaysPerPeriod) * ( value(M.SegFrac[p, s, d]) + value(M.SegFrac[p, s_next, d_next]) ) / 2 hours_elapsed /= M.SegFracPerSeason[p, s] * M.DaysPerPeriod # adjust for how many days this season represents ramp_fraction = hours_elapsed * value(M.RampDown[r, t]) diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index 9767e625d..c1487d100 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -76,10 +76,10 @@ class ExpectedVals(Enum): }, 'seasonal_storage': { # added 2025/06/16 after addition of seasonal storage - ExpectedVals.OBJ_VALUE: 76660.8720, + ExpectedVals.OBJ_VALUE: 76661.0231, ExpectedVals.EFF_DOMAIN_SIZE: 24, ExpectedVals.EFF_INDEX_SIZE: 4, - ExpectedVals.CONSTR_COUNT: 180, + ExpectedVals.CONSTR_COUNT: 182, ExpectedVals.VAR_COUNT: 90, }, } diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index cbd56f3ce..787ba8ce6 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -4050,7 +4050,7 @@ ], "RetiredCapacityVar_rptv": [], "SeasonalStorageLevel_rpstv": [], - "SeasonalStorageUpperBoundConstraint_rpsdtv": [], + "SeasonalStorageConstraints_rpsdtv": [], "StorageConstraints_rpsdtv": [ [ "B", diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index e116b5cdf..f782a8fec 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -498,6 +498,8 @@ CREATE TABLE LimitStorageLevelFraction notes TEXT, PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); +INSERT INTO LimitStorageLevelFraction VALUES('region', 2000, 'winter', 'b', 'seas_stor', 2000, 'e', 0.5, NULL); +INSERT INTO LimitStorageLevelFraction VALUES('region', 2000, 'charge', 'b', 'dly_stor', 2000, 'e', 0.5, NULL); CREATE TABLE LimitActivity ( region TEXT, diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index ad90c13fa..af3768ee7 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -44967,7 +44967,7 @@ ], "RetiredCapacityVar_rptv": [], "SeasonalStorageLevel_rpstv": [], - "SeasonalStorageUpperBoundConstraint_rpsdtv": [], + "SeasonalStorageConstraints_rpsdtv": [], "StorageConstraints_rpsdtv": [ [ "R1", diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index e960d8451..be83827f3 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -24723,7 +24723,7 @@ ], "RetiredCapacityVar_rptv": [], "SeasonalStorageLevel_rpstv": [], - "SeasonalStorageUpperBoundConstraint_rpsdtv": [], + "SeasonalStorageConstraints_rpsdtv": [], "StorageConstraints_rpsdtv": [ [ "utopia", From 84fdae3c9660a1a2a5d324d933dde51ef6e5f5eb Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 16 Jun 2025 18:49:29 -0400 Subject: [PATCH 118/587] Update ramp constraints --- temoa/temoa_model/temoa_rules.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 640bc1bbb..b5157b052 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1651,8 +1651,7 @@ def RampUp_Constraint(M: 'TemoaModel', r, p, s, d, t, v): for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) / value(M.SegFrac[p, s_next, d_next]) - hours_elapsed = 24 * value(M.DaysPerPeriod) * value(M.SegFrac[p, s, d]) / 2 - hours_elapsed /= M.SegFracPerSeason[p, s] * M.DaysPerPeriod # adjust for how many days this season represents + hours_elapsed = 24 * value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) ramp_fraction = hours_elapsed * value(M.RampUp[r, t]) if ramp_fraction >= 1: @@ -1709,8 +1708,7 @@ def RampDown_Constraint(M: 'TemoaModel', r, p, s, d, t, v): for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) / value(M.SegFrac[p, s_next, d_next]) - hours_elapsed = 24 * value(M.DaysPerPeriod) * ( value(M.SegFrac[p, s, d]) + value(M.SegFrac[p, s_next, d_next]) ) / 2 - hours_elapsed /= M.SegFracPerSeason[p, s] * M.DaysPerPeriod # adjust for how many days this season represents + hours_elapsed = 24 * value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) ramp_fraction = hours_elapsed * value(M.RampDown[r, t]) if ramp_fraction >= 1: From e559174b18acce968a1276ca952a20e299a30218 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Jun 2025 09:16:54 -0400 Subject: [PATCH 119/587] Generalise inter-season sequencing --- data_files/example_dbs/materials.sql | 45 +++++----- data_files/example_dbs/morris_utopia.sql | 6 +- data_files/example_dbs/seasonal_storage.sql | 34 +++---- data_files/example_dbs/stepped_demand.sql | 6 +- data_files/example_dbs/test_system.sql | 38 ++++---- data_files/example_dbs/utopia.sql | 6 +- data_files/my_configs/config_sample.toml | 54 ++++++----- data_files/my_configs/mga_utopia.toml | 54 ++++++----- data_files/my_configs/monte_carlo_utopia.toml | 54 ++++++----- data_files/my_configs/morris_utopia.toml | 54 ++++++----- data_files/my_configs/stepped_demand.toml | 54 ++++++----- data_files/temoa_schema_v3_1.sql | 6 +- temoa/temoa_model/hybrid_loader.py | 12 +-- .../temoa_model/model_checking/validators.py | 89 ++++++++++++------- temoa/temoa_model/table_data_puller.py | 4 +- temoa/temoa_model/temoa_config.py | 2 + temoa/temoa_model/temoa_initialize.py | 31 ++++--- temoa/temoa_model/temoa_model.py | 19 ++-- temoa/temoa_model/temoa_rules.py | 18 ++-- tests/legacy_test_values.py | 3 +- tests/test_full_runs.py | 3 +- tests/test_storage.py | 2 +- tests/testing_configs/config_emissions.toml | 52 ++++++----- tests/testing_configs/config_link_test.toml | 54 ++++++----- tests/testing_configs/config_materials.toml | 52 ++++++----- tests/testing_configs/config_mediumville.toml | 54 ++++++----- .../config_seasonal_storage.toml | 50 ++++++----- .../testing_configs/config_storageville.toml | 54 ++++++----- tests/testing_configs/config_test_system.toml | 52 ++++++----- tests/testing_configs/config_utopia.toml | 52 ++++++----- .../testing_configs/config_utopia_myopic.toml | 52 ++++++----- tests/testing_data/emissions.sql | 6 +- tests/testing_data/materials.sql | 6 +- tests/testing_data/mediumville.sql | 6 +- tests/testing_data/mediumville_sets.json | 15 +++- tests/testing_data/seasonal_storage.sql | 34 +++---- tests/testing_data/simple_linked_tech.sql | 6 +- tests/testing_data/storageville.sql | 6 +- tests/testing_data/test_system.sql | 6 +- tests/testing_data/test_system_sets.json | 4 +- tests/testing_data/utopia.sql | 6 +- tests/testing_data/utopia_sets.json | 4 +- 42 files changed, 678 insertions(+), 487 deletions(-) diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index cc68f9fd0..f2a2a73f8 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -1440,17 +1440,17 @@ INSERT INTO TimeSeason VALUES(2020,9,'summer',NULL); INSERT INTO TimeSeason VALUES(2020,10,'autumn',NULL); INSERT INTO TimeSeason VALUES(2020,11,'winter',NULL); INSERT INTO TimeSeason VALUES(2020,12,'spring',NULL); -CREATE TABLE TimeStorageSeason +CREATE TABLE TimeSeasonSequential ( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - storage_season TEXT, + seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season), + PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) ); CREATE TABLE TimePeriodType @@ -1511,28 +1511,29 @@ CREATE TABLE Technology retire INTEGER NOT NULL DEFAULT 0, flex INTEGER NOT NULL DEFAULT 0, exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('IMPORT_LI','p','materials',NULL,NULL,1,1,0,0,0,0,0,'lithium importer'); -INSERT INTO Technology VALUES('IMPORT_CO','p','materials',NULL,NULL,1,1,0,0,0,0,0,'cobalt importer'); -INSERT INTO Technology VALUES('IMPORT_P','p','materials',NULL,NULL,1,1,0,0,0,0,0,'phosphorous importer'); -INSERT INTO Technology VALUES('CAR_BEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,'car - battery electric'); -INSERT INTO Technology VALUES('CAR_PHEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,'car - plug in hybrid'); -INSERT INTO Technology VALUES('CAR_ICE','p','transportation',NULL,NULL,0,0,0,0,0,0,0,'car - internal combustion'); -INSERT INTO Technology VALUES('RECYCLE_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,'nmc battery recycler'); -INSERT INTO Technology VALUES('RECYCLE_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,'lfp battery recycler'); -INSERT INTO Technology VALUES('MANUFAC_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,'nmc battery manufacturing'); -INSERT INTO Technology VALUES('MANUFAC_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,'lfp battery manufacturing'); -INSERT INTO Technology VALUES('IMPORT_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,'nickel importer'); -INSERT INTO Technology VALUES('DOMESTIC_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,'domestic nickel production'); -INSERT INTO Technology VALUES('GEN_DSL','p','electricity',NULL,NULL,0,0,0,0,0,0,0,'diesel generators'); -INSERT INTO Technology VALUES('SOL_PV','p','electricity',NULL,NULL,0,0,0,1,0,0,0,'solar panels'); -INSERT INTO Technology VALUES('BATT_GRID','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,'grid battery storage'); -INSERT INTO Technology VALUES('FURNACE','p','residential',NULL,NULL,1,0,0,0,0,0,0,'diesel furnace heater'); -INSERT INTO Technology VALUES('HEATPUMP','p','residential',NULL,NULL,1,0,0,0,0,0,0,'heat pump'); -INSERT INTO Technology VALUES('IMPORT_DSL','p','fuels',NULL,NULL,1,1,0,0,0,0,0,'diesel importer'); -INSERT INTO Technology VALUES('ELEC_INTERTIE','p','electricity',NULL,NULL,0,0,0,0,0,0,1,'dummy tech to make landfill feasible'); +INSERT INTO Technology VALUES('IMPORT_LI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'lithium importer'); +INSERT INTO Technology VALUES('IMPORT_CO','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'cobalt importer'); +INSERT INTO Technology VALUES('IMPORT_P','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'phosphorous importer'); +INSERT INTO Technology VALUES('CAR_BEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - battery electric'); +INSERT INTO Technology VALUES('CAR_PHEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - plug in hybrid'); +INSERT INTO Technology VALUES('CAR_ICE','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - internal combustion'); +INSERT INTO Technology VALUES('RECYCLE_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'nmc battery recycler'); +INSERT INTO Technology VALUES('RECYCLE_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'lfp battery recycler'); +INSERT INTO Technology VALUES('MANUFAC_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'nmc battery manufacturing'); +INSERT INTO Technology VALUES('MANUFAC_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'lfp battery manufacturing'); +INSERT INTO Technology VALUES('IMPORT_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'nickel importer'); +INSERT INTO Technology VALUES('DOMESTIC_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'domestic nickel production'); +INSERT INTO Technology VALUES('GEN_DSL','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,'diesel generators'); +INSERT INTO Technology VALUES('SOL_PV','p','electricity',NULL,NULL,0,0,0,1,0,0,0,0,'solar panels'); +INSERT INTO Technology VALUES('BATT_GRID','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,0,'grid battery storage'); +INSERT INTO Technology VALUES('FURNACE','p','residential',NULL,NULL,1,0,0,0,0,0,0,0,'diesel furnace heater'); +INSERT INTO Technology VALUES('HEATPUMP','p','residential',NULL,NULL,1,0,0,0,0,0,0,0,'heat pump'); +INSERT INTO Technology VALUES('IMPORT_DSL','p','fuels',NULL,NULL,1,1,0,0,0,0,0,0,'diesel importer'); +INSERT INTO Technology VALUES('ELEC_INTERTIE','p','electricity',NULL,NULL,0,0,0,0,0,0,1,0,'dummy tech to make landfill feasible'); CREATE TABLE OutputCost ( scenario TEXT, diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index 5769b42ad..e466af358 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -1417,17 +1417,17 @@ INSERT INTO TimeSeason VALUES(2000,1,'inter',NULL); INSERT INTO TimeSeason VALUES(2010,2,'summer',NULL); INSERT INTO TimeSeason VALUES(2010,3,'winter',NULL); INSERT INTO TimeSeason VALUES(2010,1,'inter',NULL); -CREATE TABLE TimeStorageSeason +CREATE TABLE TimeSeasonSequential ( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - storage_season TEXT, + seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season), + PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) ); CREATE TABLE TimePeriodType diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql index f782a8fec..9290ae980 100644 --- a/data_files/example_dbs/seasonal_storage.sql +++ b/data_files/example_dbs/seasonal_storage.sql @@ -1025,31 +1025,31 @@ CREATE TABLE OutputCost FOREIGN KEY (vintage) REFERENCES TimePeriod (period), FOREIGN KEY (tech) REFERENCES Technology (tech) ); -CREATE TABLE TimeStorageSeason +CREATE TABLE TimeSeasonSequential ( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - storage_season TEXT, + seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season), + PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) ); -INSERT INTO TimeStorageSeason VALUES(2000,1,'summer','charge',152.5,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,2,'sept_w1','discharge',7,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,3,'sept_w2','charge',7,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,4,'sept_w3','discharge',7,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,5,'sept_w4','charge',7,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,6,'sept_29th','discharge',1,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,7,'sept_30th','charge',1,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,8,'winter','discharge',152.5,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,9,'apr_w1','charge',7,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,10,'apr_w2','discharge',7,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,11,'apr_w3','charge',7,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,12,'apr_w4','discharge',7,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,13,'apr_29th','charge',1,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,14,'apr_30th','discharge',1,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,1,'summer','charge',152.5,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,2,'sept_w1','discharge',7,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,3,'sept_w2','charge',7,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,4,'sept_w3','discharge',7,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,5,'sept_w4','charge',7,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,6,'sept_29th','discharge',1,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,7,'sept_30th','charge',1,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,8,'winter','discharge',152.5,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,9,'apr_w1','charge',7,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,10,'apr_w2','discharge',7,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,11,'apr_w3','charge',7,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,12,'apr_w4','discharge',7,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,13,'apr_29th','charge',1,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,14,'apr_30th','discharge',1,NULL); COMMIT; diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index 34a89c616..cf3b36c37 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -1181,17 +1181,17 @@ INSERT INTO TimeSeason VALUES(2045,3,'winter',NULL); INSERT INTO TimeSeason VALUES(2050,1,'inter',NULL); INSERT INTO TimeSeason VALUES(2050,2,'summer',NULL); INSERT INTO TimeSeason VALUES(2050,3,'winter',NULL); -CREATE TABLE TimeStorageSeason +CREATE TABLE TimeSeasonSequential ( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - storage_season TEXT, + seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season), + PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) ); CREATE TABLE TimePeriodType diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index 89950301c..9c135ee97 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -1430,17 +1430,17 @@ INSERT INTO TimeSeason VALUES(2030,1,'spring',NULL); INSERT INTO TimeSeason VALUES(2030,2,'summer',NULL); INSERT INTO TimeSeason VALUES(2030,3,'fall',NULL); INSERT INTO TimeSeason VALUES(2030,4,'winter',NULL); -CREATE TABLE TimeStorageSeason +CREATE TABLE TimeSeasonSequential ( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - storage_season TEXT, + seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season), + PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) ); CREATE TABLE TimePeriodType @@ -1505,22 +1505,22 @@ CREATE TABLE Technology description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('S_IMPETH','r','supply','','',1,0,0,0,0,0,0,' imported ethanol'); -INSERT INTO Technology VALUES('S_IMPOIL','r','supply','','',1,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO Technology VALUES('S_IMPNG','r','supply','','',1,0,0,0,0,0,0,' imported natural gas'); -INSERT INTO Technology VALUES('S_IMPURN','r','supply','','',1,0,0,0,0,0,0,' imported uranium'); -INSERT INTO Technology VALUES('S_OILREF','p','supply','','',0,0,0,1,0,0,0,' crude oil refinery'); -INSERT INTO Technology VALUES('E_NGCC','p','electric','','',0,0,0,0,0,0,0,' natural gas combined-cycle'); -INSERT INTO Technology VALUES('E_SOLPV','p','electric','','',0,0,0,0,0,0,0,' solar photovoltaic'); -INSERT INTO Technology VALUES('E_BATT','ps','electric','','',0,0,0,0,0,0,0,' lithium-ion battery'); -INSERT INTO Technology VALUES('E_NUCLEAR','pb','electric','','',0,0,0,0,0,0,0,' nuclear power plant'); -INSERT INTO Technology VALUES('T_BLND','p','transport','','',0,0,0,0,0,0,0,'ethanol - gasoline blending process'); -INSERT INTO Technology VALUES('T_DSL','p','transport','','',0,0,0,0,0,0,0,'diesel vehicle'); -INSERT INTO Technology VALUES('T_GSL','p','transport','','',0,0,0,0,0,0,0,'gasoline vehicle'); -INSERT INTO Technology VALUES('T_EV','p','transport','','',0,0,0,0,0,0,0,'electric vehicle'); -INSERT INTO Technology VALUES('R_EH','p','residential','','',0,0,0,0,0,0,0,' electric residential heating'); -INSERT INTO Technology VALUES('R_NGH','p','residential','','',0,0,0,0,0,0,0,' natural gas residential heating'); -INSERT INTO Technology VALUES('E_TRANS','p','electric','','',0,0,0,0,0,0,1,'electric transmission'); +INSERT INTO Technology VALUES('S_IMPETH','r','supply','','',1,0,0,0,0,0,0,0,' imported ethanol'); +INSERT INTO Technology VALUES('S_IMPOIL','r','supply','','',1,0,0,0,0,0,0,0,' imported crude oil'); +INSERT INTO Technology VALUES('S_IMPNG','r','supply','','',1,0,0,0,0,0,0,0,' imported natural gas'); +INSERT INTO Technology VALUES('S_IMPURN','r','supply','','',1,0,0,0,0,0,0,0,' imported uranium'); +INSERT INTO Technology VALUES('S_OILREF','p','supply','','',0,0,0,1,0,0,0,0,' crude oil refinery'); +INSERT INTO Technology VALUES('E_NGCC','p','electric','','',0,0,0,0,0,0,0,0,' natural gas combined-cycle'); +INSERT INTO Technology VALUES('E_SOLPV','p','electric','','',0,0,0,0,0,0,0,0,' solar photovoltaic'); +INSERT INTO Technology VALUES('E_BATT','ps','electric','','',0,0,0,0,0,0,0,0,' lithium-ion battery'); +INSERT INTO Technology VALUES('E_NUCLEAR','pb','electric','','',0,0,0,0,0,0,0,0,' nuclear power plant'); +INSERT INTO Technology VALUES('T_BLND','p','transport','','',0,0,0,0,0,0,0,0,'ethanol - gasoline blending process'); +INSERT INTO Technology VALUES('T_DSL','p','transport','','',0,0,0,0,0,0,0,0,'diesel vehicle'); +INSERT INTO Technology VALUES('T_GSL','p','transport','','',0,0,0,0,0,0,0,0,'gasoline vehicle'); +INSERT INTO Technology VALUES('T_EV','p','transport','','',0,0,0,0,0,0,0,0,'electric vehicle'); +INSERT INTO Technology VALUES('R_EH','p','residential','','',0,0,0,0,0,0,0,0,' electric residential heating'); +INSERT INTO Technology VALUES('R_NGH','p','residential','','',0,0,0,0,0,0,0,0,' natural gas residential heating'); +INSERT INTO Technology VALUES('E_TRANS','p','electric','','',0,0,0,0,0,0,1,0,'electric transmission'); CREATE TABLE OutputCost ( scenario TEXT, diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 952e49218..738e18d9c 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -1412,17 +1412,17 @@ INSERT INTO TimeSeason VALUES(2000,3,'winter',NULL); INSERT INTO TimeSeason VALUES(2010,1,'inter',NULL); INSERT INTO TimeSeason VALUES(2010,2,'summer',NULL); INSERT INTO TimeSeason VALUES(2010,3,'winter',NULL); -CREATE TABLE TimeStorageSeason +CREATE TABLE TimeSeasonSequential ( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - storage_season TEXT, + seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season), + PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) ); CREATE TABLE TimePeriodType diff --git a/data_files/my_configs/config_sample.toml b/data_files/my_configs/config_sample.toml index 87602f31a..fac2e2406 100644 --- a/data_files/my_configs/config_sample.toml +++ b/data_files/my_configs/config_sample.toml @@ -82,28 +82,38 @@ save_lp_file = false # these are specific to each model # ------------------------------------ -# How to sequence time slices in the model. Options: -# 'seasonal_timeslicing' -# Time slices sequence through seasons and between seasons, looping from the end of each -# period back to its start. Compatible with seasonal time-slicing databases. -# 'representative_periods' -# Time slices sequence through seasons but loop from the end of each season back to its start. -# Time slices do not connect between seasons. Compatible with representative periods databases. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out in -# the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'seasonal_timeslicing' - -# How contributions to the planning reserve margin are calculated. Options: -# 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. -# 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# What seasons represent in the model +# Options: +# 'sequential_days' +# Seasons are a set of days in order, with each season representing only one day. Examples +# might be a model of a representative week with 7 days or a whole-year model with 365 days. +# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# 'representative_periods' +# Each season represents a number of days, though not necessarily in any particular order. +# If using inter-season constraints like seasonal storage or ramp rates, the true sequence +# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# the Technology table. +# 'seasonal_timeslices' +# Each season represents a sequential slice of the year, with one or many days represented per +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out +# in the schema). This is an advanced feature and not recommended for most users. Seasonal +# storage must be tagged and the TimeSeasonSequential table filled. +time_sequencing = 'seasonal_timeslices' + +# How contributions to the planning reserve margin are calculated +# Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit reserve_margin = 'static' # --------------------------------------------------- diff --git a/data_files/my_configs/mga_utopia.toml b/data_files/my_configs/mga_utopia.toml index 79fc5248f..ac4aa659e 100644 --- a/data_files/my_configs/mga_utopia.toml +++ b/data_files/my_configs/mga_utopia.toml @@ -76,28 +76,38 @@ save_lp_file = false # these are specific to each model # ------------------------------------ -# How to sequence time slices in the model. Options: -# 'seasonal_timeslicing' -# Time slices sequence through seasons and between seasons, looping from the end of each -# period back to its start. Compatible with seasonal time-slicing databases. -# 'representative_periods' -# Time slices sequence through seasons but loop from the end of each season back to its start. -# Time slices do not connect between seasons. Compatible with representative periods databases. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out in -# the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'seasonal_timeslicing' - -# How contributions to the planning reserve margin are calculated. Options: -# 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. -# 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# What seasons represent in the model +# Options: +# 'sequential_days' +# Seasons are a set of days in order, with each season representing only one day. Examples +# might be a model of a representative week with 7 days or a whole-year model with 365 days. +# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# 'representative_periods' +# Each season represents a number of days, though not necessarily in any particular order. +# If using inter-season constraints like seasonal storage or ramp rates, the true sequence +# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# the Technology table. +# 'seasonal_timeslices' +# Each season represents a sequential slice of the year, with one or many days represented per +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out +# in the schema). This is an advanced feature and not recommended for most users. Seasonal +# storage must be tagged and the TimeSeasonSequential table filled. +time_sequencing = 'seasonal_timeslices' + +# How contributions to the planning reserve margin are calculated +# Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit reserve_margin = 'static' # --------------------------------------------------- diff --git a/data_files/my_configs/monte_carlo_utopia.toml b/data_files/my_configs/monte_carlo_utopia.toml index 15e745149..e82d6000d 100644 --- a/data_files/my_configs/monte_carlo_utopia.toml +++ b/data_files/my_configs/monte_carlo_utopia.toml @@ -79,28 +79,38 @@ save_lp_file = false # these are specific to each model # ------------------------------------ -# How to sequence time slices in the model. Options: -# 'seasonal_timeslicing' -# Time slices sequence through seasons and between seasons, looping from the end of each -# period back to its start. Compatible with seasonal time-slicing databases. -# 'representative_periods' -# Time slices sequence through seasons but loop from the end of each season back to its start. -# Time slices do not connect between seasons. Compatible with representative periods databases. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out in -# the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'seasonal_timeslicing' - -# How contributions to the planning reserve margin are calculated. Options: -# 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. -# 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# What seasons represent in the model +# Options: +# 'sequential_days' +# Seasons are a set of days in order, with each season representing only one day. Examples +# might be a model of a representative week with 7 days or a whole-year model with 365 days. +# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# 'representative_periods' +# Each season represents a number of days, though not necessarily in any particular order. +# If using inter-season constraints like seasonal storage or ramp rates, the true sequence +# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# the Technology table. +# 'seasonal_timeslices' +# Each season represents a sequential slice of the year, with one or many days represented per +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out +# in the schema). This is an advanced feature and not recommended for most users. Seasonal +# storage must be tagged and the TimeSeasonSequential table filled. +time_sequencing = 'seasonal_timeslices' + +# How contributions to the planning reserve margin are calculated +# Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit reserve_margin = 'static' # --------------------------------------------------- diff --git a/data_files/my_configs/morris_utopia.toml b/data_files/my_configs/morris_utopia.toml index d6f617d71..80a61f2fd 100644 --- a/data_files/my_configs/morris_utopia.toml +++ b/data_files/my_configs/morris_utopia.toml @@ -76,28 +76,38 @@ save_lp_file = false # these are specific to each model # ------------------------------------ -# How to sequence time slices in the model. Options: -# 'seasonal_timeslicing' -# Time slices sequence through seasons and between seasons, looping from the end of each -# period back to its start. Compatible with seasonal time-slicing databases. -# 'representative_periods' -# Time slices sequence through seasons but loop from the end of each season back to its start. -# Time slices do not connect between seasons. Compatible with representative periods databases. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out in -# the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'seasonal_timeslicing' - -# How contributions to the planning reserve margin are calculated. Options: -# 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. -# 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# What seasons represent in the model +# Options: +# 'sequential_days' +# Seasons are a set of days in order, with each season representing only one day. Examples +# might be a model of a representative week with 7 days or a whole-year model with 365 days. +# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# 'representative_periods' +# Each season represents a number of days, though not necessarily in any particular order. +# If using inter-season constraints like seasonal storage or ramp rates, the true sequence +# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# the Technology table. +# 'seasonal_timeslices' +# Each season represents a sequential slice of the year, with one or many days represented per +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out +# in the schema). This is an advanced feature and not recommended for most users. Seasonal +# storage must be tagged and the TimeSeasonSequential table filled. +time_sequencing = 'seasonal_timeslices' + +# How contributions to the planning reserve margin are calculated +# Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit reserve_margin = 'static' # --------------------------------------------------- diff --git a/data_files/my_configs/stepped_demand.toml b/data_files/my_configs/stepped_demand.toml index 49253a586..ac551a710 100644 --- a/data_files/my_configs/stepped_demand.toml +++ b/data_files/my_configs/stepped_demand.toml @@ -76,28 +76,38 @@ save_lp_file = false # these are specific to each model # ------------------------------------ -# How to sequence time slices in the model. Options: -# 'seasonal_timeslicing' -# Time slices sequence through seasons and between seasons, looping from the end of each -# period back to its start. Compatible with seasonal time-slicing databases. -# 'representative_periods' -# Time slices sequence through seasons but loop from the end of each season back to its start. -# Time slices do not connect between seasons. Compatible with representative periods databases. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out in -# the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'seasonal_timeslicing' - -# How contributions to the planning reserve margin are calculated. Options: -# 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. -# 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# What seasons represent in the model +# Options: +# 'sequential_days' +# Seasons are a set of days in order, with each season representing only one day. Examples +# might be a model of a representative week with 7 days or a whole-year model with 365 days. +# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# 'representative_periods' +# Each season represents a number of days, though not necessarily in any particular order. +# If using inter-season constraints like seasonal storage or ramp rates, the true sequence +# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# the Technology table. +# 'seasonal_timeslices' +# Each season represents a sequential slice of the year, with one or many days represented per +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out +# in the schema). This is an advanced feature and not recommended for most users. Seasonal +# storage must be tagged and the TimeSeasonSequential table filled. +time_sequencing = 'seasonal_timeslices' + +# How contributions to the planning reserve margin are calculated +# Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit reserve_margin = 'static' # --------------------------------------------------- diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index 497e8e651..9da9fd398 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -920,17 +920,17 @@ CREATE TABLE IF NOT EXISTS TimeSeason notes TEXT, PRIMARY KEY (period, sequence, season) ); -CREATE TABLE IF NOT EXISTS TimeStorageSeason +CREATE TABLE IF NOT EXISTS TimeSeasonSequential ( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - storage_season TEXT, + seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season), + PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) ); CREATE TABLE IF NOT EXISTS TimePeriodType diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 04db2a2a9..48921738d 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -401,7 +401,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # TimeSequencing time_sequencing = self.config.time_sequencing match time_sequencing: - case 'seasonal_timeslicing' | 'representative_periods': + case 'seasonal_timeslices' | 'representative_periods' | 'sequential_days': pass case 'manual': # This is a hidden feature allowing the user to manually specify the sequence of states using the TimeNext table @@ -661,18 +661,18 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N load_element(M.SegFrac, raw) all_seasons = set() # includes all regular and virtual seasonal storage seasons - if self.table_exists("TimeStorageSeason"): + if self.table_exists("TimeSeasonSequential"): if mi: raw = cur.execute( - 'SELECT period, storage_season, season, count FROM main.TimeStorageSeason WHERE' + 'SELECT period, seas_seq, season, count FROM main.TimeSeasonSequential WHERE' ' period >= ? AND period <= ? ORDER BY period, sequence', (mi.base_year, mi.last_demand_year) ).fetchall() else: - raw = cur.execute('SELECT period, storage_season, season, count FROM main.TimeStorageSeason ORDER BY period, sequence').fetchall() + raw = cur.execute('SELECT period, seas_seq, season, count FROM main.TimeSeasonSequential ORDER BY period, sequence').fetchall() all_seasons = all_seasons | set((row[1],) for row in raw) - load_element(M.TimeStorageSeason, raw) - load_element(M.ordered_storage_season, [(row[0:3]) for row in raw]) + load_element(M.TimeSeasonSequential, raw) + load_element(M.ordered_season_sequential, [(row[0:3]) for row in raw]) # TimeSeason if self.table_exists("TimeSeason"): diff --git a/temoa/temoa_model/model_checking/validators.py b/temoa/temoa_model/model_checking/validators.py index 02d8b1c83..c86360391 100644 --- a/temoa/temoa_model/model_checking/validators.py +++ b/temoa/temoa_model/model_checking/validators.py @@ -305,43 +305,72 @@ def validate_Efficiency(M: 'TemoaModel', val, r, si, t, v, so) -> bool: return False -def validate_StorageSeason(M: 'TemoaModel'): - - if not M.TimeStorageSeason: - logger.info( - 'No data in TimeStorageSeason. By default, assume storage seasons ' - 'match TimeSeason and fill using TimeSegmentFraction.' - ) - for p in M.time_season: - for s in M.time_season[p]: - M.TimeStorageSeason[p, s, s] = value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod) +def validate_SeasonSequential(M: 'TemoaModel'): - storage = dict() - for p, s_stor, s in M.TimeStorageSeason: - if (p, s) not in storage: - storage[p, s] = 0 - storage[p, s] += value(M.TimeStorageSeason[p, s_stor, s]) + if all(( + not M.tech_seasonal_storage, + not M.RampUp, + not M.RampDown, + )): + # Don't need it anyway + return + + if not M.TimeSeasonSequential: + if M.TimeSequencing.first() in ('sequential_days', 'seasonal_timeslices'): + logger.info( + 'No data in TimeSeasonSequential. By default, assuming sequential seasons ' + 'match TimeSeason and TimeSegmentFraction.' + ) + for p in M.time_season: + for s in M.time_season[p]: + M.ordered_season_sequential.add((p, s, s)) + M.TimeSeasonSequential[p, s, s] = value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod) + + else: + msg = ( + f'No data in TimeSeasonSequential but time_sequencing parameter set to {M.TimeSequencing.first()} ' + 'and inter-season features used. TimeSeasonSequential must be filled for this type of time ' + 'sequencing if seasonal storage or inter-season constraints like RampUp/RampDown are used. Check ' + 'the config file.' + ) + logger.error(msg) + raise ValueError(msg) + + sequential = dict() + for p, s_seq, s in M.TimeSeasonSequential: + count = value(M.TimeSeasonSequential[p, s_seq, s]) + if M.TimeSequencing.first() == 'sequential_days' and abs(count - 1.0) >= 0.01: + msg = ( + 'TimeSequencing set to sequential_days but a season in the TimeSegmentFraction table does not ' + f'represent exactly one day. This would lead to bad model behaviour: {p, s}, days: {count}. ' + 'Check the config file.' + ) + logger.error(msg) + raise ValueError(msg) + if (p, s) not in sequential: + sequential[p, s] = 0 + sequential[p, s] += count - # Check that TimeStorageSeason day counts total to number of days in each period + # Check that TimeSeasonSequential day counts total to number of days in each period for p in M.time_optimize: count_total = sum( - storage[p, s] - for _p, s in storage + sequential[p, s] + for _p, s in sequential if _p == p ) if abs(count_total - value(M.DaysPerPeriod)) >= 0.001: logger.warning( - f'Sum of day count in TimeStorageSeason ({sum(storage.values())}) ' - f'does not sum to days_per_season ({value(M.DaysPerPeriod)}) from the ' + f'Sum of day count in TimeSeasonSequential ({sum(sequential.values())}) ' + f'does not sum to days_per_period ({value(M.DaysPerPeriod)}) from the ' 'MetaData table.' ) # Check that seasons using in storage seasons are actual seasons - for (p, s) in storage: + for (p, s) in sequential: if (p, s) not in M.SegFracPerSeason: msg = ( - f'Period-season index {(p, s)} referenced in TimeStorageSeason that ' - 'does not exist in TimeSegmentFraction.' + f'Period-season index {(p, s)} that does not exist in ' + 'TimeSegmentFraction referenced in TimeSeasonSequential .' ) logger.error(msg) raise ValueError(msg) @@ -350,21 +379,21 @@ def validate_StorageSeason(M: 'TemoaModel'): if s not in M.time_season[p]: continue - # Check that all seasons are using in storage seasons - if (p, s) not in storage: - msg = (f'Period-season index {(p, s)} absent from TimeStorageSeason') + # Check that all seasons are used in sequential seasons + if (p, s) not in sequential: + msg = (f'Period-season index {(p, s)} absent from TimeSeasonSequential') logger.warning(msg) # Check that the two tables agree on the total seasonal composition of each period segfrac = value(M.SegFracPerSeason[p, s]) - segfracstorage = storage[p, s] / value(M.DaysPerPeriod) - if abs(segfrac - segfracstorage) >= 0.001: + segfracseq = sequential[p, s] / value(M.DaysPerPeriod) + if abs(segfrac - segfracseq) >= 0.001: msg = ( 'Discrepancy of total period-season composition between ' - 'TimeSegmentFraction and TimeStorageSeason. Total fraction of each ' + 'TimeSegmentFraction and TimeSeasonSequential. Total fraction of each ' 'period assigned to each season should match: ' f'TimeSegmentFraction: {(p, s, value(M.SegFracPerSeason[p, s]))}' - f', TimeStorageSeason: {(p, s, segfracstorage)}' + f', TimeSeasonSequential: {(p, s, segfracseq)}' ) logger.warning(msg) diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index 46e6aefce..e86b1c71a 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -250,11 +250,11 @@ def poll_storage_level_results(M: TemoaModel, epsilon=1e-5) -> dict[SLI, float]: res[sli] = state for r, p, s_stor, t, v in M.SeasonalStorageLevel_rpstv: - s = M.storage_to_season[p, s_stor] + s = M.sequential_to_season[p, s_stor] # Ratio of days in virtual storage season to days in actual season # Flows and StorageLevel are normalised to the number of days in the ACTUAL season, so must # be adjusted to the number of days in the virtual storage season - days_adjust = value(M.TimeStorageSeason[p, s_stor, s]) / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) + days_adjust = value(M.TimeSeasonSequential[p, s_stor, s]) / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) for d in M.time_of_day: state = value(M.V_SeasonalStorageLevel[r, p, s_stor, t, v]) + value(M.V_StorageLevel[r, p, s, d, t, v]) * days_adjust sli = SLI(r, p, s_stor, d, t, v) diff --git a/temoa/temoa_model/temoa_config.py b/temoa/temoa_model/temoa_config.py index 21b5e393c..5940f391b 100644 --- a/temoa/temoa_model/temoa_config.py +++ b/temoa/temoa_model/temoa_config.py @@ -197,6 +197,8 @@ def __repr__(self): msg += '{:>{}s}: {}\n'.format('Pyomo LP write status', width, self.save_lp_file) msg += '{:>{}s}: {}\n'.format('Save duals to output db', width, self.save_duals) msg += '{:>{}s}: {}\n'.format('Save storage to output db', width, self.save_storage_levels) + + msg += spacer msg += '{:>{}s}: {}\n'.format('Time sequencing', width, self.time_sequencing) msg += '{:>{}s}: {}\n'.format('Planning reserve margin', width, self.reserve_margin) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 6f7a42cd2..270cb8345 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1072,7 +1072,7 @@ def CreateSparseDicts(M: 'TemoaModel'): for r, p, t in M.storageVintages.keys() if t in M.tech_seasonal_storage for v in M.storageVintages[r, p, t] - for _p, s_stor in M.storage_to_season + for _p, s_stor in M.sequential_to_season if _p == p ) @@ -1085,13 +1085,18 @@ def CreateTimeSequence(M: 'TemoaModel'): # Establishing sequence of states match M.TimeSequencing.first(): - case 'seasonal_timeslicing': - msg = 'Running a season time slicing database, looping time each period, chaining between seasons.' + case 'sequential_days': + msg = 'Running a sequential days database.' for p in M.time_optimize: for s, d in M.time_season[p] * M.time_of_day: M.time_next[p, s, d] = loop_period_next_timeslice(M, p, s, d) + case 'seasonal_timeslices': + msg = 'Running a seasonal time slice database.' + for p in M.time_optimize: + for s, d in M.time_season[p] * M.time_of_day: + M.time_next[p, s, d] = loop_season_next_timeslice(M, p, s, d) case 'representative_periods': - msg = 'Running a representative periods database, looping time each season.' + msg = 'Running a representative periods database.' for p in M.time_optimize: for s, d in M.time_season[p] * M.time_of_day: M.time_next[p, s, d] = loop_season_next_timeslice(M, p, s, d) @@ -1110,21 +1115,21 @@ def CreateTimeSequence(M: 'TemoaModel'): 'time_sequencing parameter in the config file. ') logger.info(msg) - logger.debug('Creating sequence of virtual storage seasons.') + logger.debug('Creating superimposed sequential seasons.') - # Seasonal storage superimposed sequencing + # Superimposed sequential seasons for p in M.time_optimize: seasons = [ - (s_stor, s) - for _p, s_stor, s in M.ordered_storage_season + (s_seq, s) + for _p, s_seq, s in M.ordered_season_sequential if _p == p ] - for i, (s_stor, s) in enumerate(seasons): - M.storage_to_season[p, s_stor] = s - if (s_stor, s) == seasons[-1]: - M.time_next_storage[p, s_stor] = seasons[0][0] + for i, (s_seq, s) in enumerate(seasons): + M.sequential_to_season[p, s_seq] = s + if (s_seq, s) == seasons[-1]: + M.time_next_sequential[p, s_seq] = seasons[0][0] else: - M.time_next_storage[p, s_stor] = seasons[i+1][0] + M.time_next_sequential[p, s_seq] = seasons[i+1][0] logger.debug('Created time sequence.') diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 15f57f836..03337f8c1 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -42,7 +42,7 @@ validate_Efficiency, validate_tech_sets, no_slash_or_pipe, - validate_StorageSeason, + validate_SeasonSequential, validate_ReserveMargin, ) from temoa.temoa_model.temoa_initialize import * @@ -128,8 +128,8 @@ def __init__(M, *args, **kwargs): # These establish time sequencing M.time_next = dict() # {(p, s, d): (s_next, d_next)} sequence of following time slices - M.time_next_storage = dict() # {(p, s_stor): (s_stor_next)} next virtual storage season - M.storage_to_season = dict() # {(p, s_stor): (s)} season matching this virtual storage season + M.time_next_sequential = dict() # {(p, s_stor): (s_stor_next)} next virtual storage season + M.sequential_to_season = dict() # {(p, s_stor): (s)} season matching this virtual storage season M.is_seasonal_storage = dict() # to avoid slow O(n2) behaviour in storage constraints ################################################ @@ -166,7 +166,7 @@ def __init__(M, *args, **kwargs): M.time_of_day = Set(ordered=True, validate=no_slash_or_pipe) # This is just to get the TimeStorageSeason table sequentially. There must be a better way but this works for now - M.ordered_storage_season = Set(dimen=3, within=M.time_optimize * M.time_season_all * M.time_season_all, ordered=True) + M.ordered_season_sequential = Set(dimen=3, within=M.time_optimize * M.time_season_all * M.time_season_all, ordered=True) # Define regions M.regions = Set(validate=region_check) @@ -351,11 +351,15 @@ def __init__(M, *args, **kwargs): ) M.RenewablePortfolioStandard = Param(M.RenewablePortfolioStandardConstraint_rpg, validate=validate_0to1) + # These need to come before validate_SeasonSequential + M.RampUp = Param(M.regions, M.tech_upramping, validate=validate_0to1) + M.RampDown = Param(M.regions, M.tech_downramping, validate=validate_0to1) + # Set up representation of time M.DaysPerPeriod = Param() M.SegFracPerSeason = Param(M.time_optimize, M.time_season_all, initialize=SegFracPerSeason_rule) - M.TimeStorageSeason = Param(M.time_optimize, M.time_season_all, M.time_season_all, mutable=True) - M.validate_StorageSeason = BuildAction(rule=validate_StorageSeason) + M.TimeSeasonSequential = Param(M.time_optimize, M.time_season_all, M.time_season_all, mutable=True) + M.validate_SeasonSequential = BuildAction(rule=validate_SeasonSequential) M.Create_TimeSequence = BuildAction(rule=CreateTimeSequence) # The method below creates a series of helper functions that are used to @@ -500,9 +504,6 @@ def __init__(M, *args, **kwargs): M.LinkedTechs = Param(M.regionalIndices, M.tech_all, M.commodity_emissions, within=Any) # Define parameters associated with electric sector operation - M.RampUp = Param(M.regions, M.tech_upramping, validate=validate_0to1) - M.RampDown = Param(M.regions, M.tech_downramping, validate=validate_0to1) - M.ReserveMargin = Set() # How contributions to the reserve margin are calculated M.CapacityCredit = Param( M.regionalIndices, M.time_optimize, M.tech_all, M.vintage_all, default=1, validate=validate_0to1 diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index b5157b052..57c60aef4 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1298,7 +1298,7 @@ def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_stor, t, v): over that entire day. """ - s = M.storage_to_season[p, s_stor] + s = M.sequential_to_season[p, s_stor] # This is the sum of all input=i sent TO storage tech t of vintage v with # output=o in p,s,d @@ -1318,14 +1318,14 @@ def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_stor, t, v): for d in M.time_of_day ) - s_stor_next = M.time_next_storage[p, s_stor] - s_next = M.storage_to_season[p, s_stor_next] + s_stor_next = M.time_next_sequential[p, s_stor] + s_next = M.sequential_to_season[p, s_stor_next] # Ratio of days in virtual storage season to days in actual season # Flows and StorageLevel are normalised to the number of days in the ACTUAL season, so must # be adjusted to the number of days in the virtual storage season - days_adjust = value(M.TimeStorageSeason[p, s_stor, s]) / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) - days_adjust_next = value(M.TimeStorageSeason[p, s_stor_next, s_next]) / (value(M.SegFracPerSeason[p, s_next]) * value(M.DaysPerPeriod)) + days_adjust = value(M.TimeSeasonSequential[p, s_stor, s]) / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) + days_adjust_next = value(M.TimeSeasonSequential[p, s_stor_next, s_next]) / (value(M.SegFracPerSeason[p, s_next]) * value(M.DaysPerPeriod)) stored_energy = (charge - discharge) * days_adjust @@ -1398,7 +1398,7 @@ def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_stor, d, seasons. """ - s = M.storage_to_season[p, s_stor] + s = M.sequential_to_season[p, s_stor] energy_capacity = ( M.V_Capacity[r, p, t, v] @@ -1410,7 +1410,7 @@ def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_stor, d, # Ratio of days in virtual storage season to days in actual season # Flows and StorageLevel are normalised to the number of days in the ACTUAL season, so must # be adjusted to the number of days in the virtual storage season - days_adjust = value(M.TimeStorageSeason[p, s_stor, s]) / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) + days_adjust = value(M.TimeSeasonSequential[p, s_stor, s]) / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) # V_StorageLevel tracks the running cumulative delta in the actual season, so must be adjusted # to the size of the virtual, storage season @@ -1575,14 +1575,14 @@ def LimitStorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v, op): if M.is_seasonal_storage[t]: s_stor = s # virtual storage season - s = M.storage_to_season[p, s_stor] # actual season + s = M.sequential_to_season[p, s_stor] # actual season # adjust the storage level to the individual-day level energy_level = M.V_StorageLevel[r, p, s, d, t, v] / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) if M.is_seasonal_storage[t]: # seasonal storage upper energy limit is absolute - energy_level = M.V_SeasonalStorageLevel[r, p, s_stor, t, v] + energy_level * value(M.TimeStorageSeason[p, s_stor, s]) + energy_level = M.V_SeasonalStorageLevel[r, p, s_stor, t, v] + energy_level * value(M.TimeSeasonSequential[p, s_stor, s]) expr = operator_expression(energy_level, op, energy_limit) diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index c1487d100..6b740341e 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -55,7 +55,8 @@ class ExpectedVals(Enum): 'utopia': { # reduced after reworking storageinit -> storage was less constrained # reduced after removing ancient 1-year-shift obj function bug - ExpectedVals.OBJ_VALUE: 34731.9619, + # increased after rework of inter-season sequencing + ExpectedVals.OBJ_VALUE: 34764.3349, ExpectedVals.EFF_DOMAIN_SIZE: 12312, ExpectedVals.EFF_INDEX_SIZE: 64, # reduced 3/27: unlim_cap techs now employed. diff --git a/tests/test_full_runs.py b/tests/test_full_runs.py index 260fe9f29..f9b977113 100644 --- a/tests/test_full_runs.py +++ b/tests/test_full_runs.py @@ -112,5 +112,6 @@ def test_myopic_utopia(system_test_run): invest_sum = res[0] # reduced this target after storageinit rework # reduced after removing ancient 1-year shift bug from objective function - assert invest_sum == pytest.approx(10976.37143), 'sum of investment costs did not match expected' + # increased after rework of inter-season sequencing + assert invest_sum == pytest.approx(11004.8335), 'sum of investment costs did not match expected' con.close() diff --git a/tests/test_storage.py b/tests/test_storage.py index 9c8cdc16c..52d2c612c 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -94,7 +94,7 @@ def test_state_sequencing(system_test_run): next_state = model.V_StorageLevel[r, p, s_next, d_next, t, v].value assert state + charge - discharge == pytest.approx( - next_state, rel=1e-2 + next_state, abs=1e-5 ), f'model fails to correctly sequence storage states {r, p, s, t, v} sequenced {s, d} to {s_next, d_next}' diff --git a/tests/testing_configs/config_emissions.toml b/tests/testing_configs/config_emissions.toml index 3e8ea8509..0dcaec2c1 100644 --- a/tests/testing_configs/config_emissions.toml +++ b/tests/testing_configs/config_emissions.toml @@ -23,28 +23,38 @@ save_lp_file = false # these are specific to each model # ------------------------------------ -# How to sequence time slices in the model. Options: -# 'seasonal_timeslicing' -# Time slices sequence through seasons and between seasons, looping from the end of each -# period back to its start. Compatible with seasonal time-slicing databases. -# 'representative_periods' -# Time slices sequence through seasons but loop from the end of each season back to its start. -# Time slices do not connect between seasons. Compatible with representative periods databases. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out in -# the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'seasonal_timeslicing' +# What seasons represent in the model +# Options: +# 'sequential_days' +# Seasons are a set of days in order, with each season representing only one day. Examples +# might be a model of a representative week with 7 days or a whole-year model with 365 days. +# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# 'representative_periods' +# Each season represents a number of days, though not necessarily in any particular order. +# If using inter-season constraints like seasonal storage or ramp rates, the true sequence +# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# the Technology table. +# 'seasonal_timeslices' +# Each season represents a sequential slice of the year, with one or many days represented per +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out +# in the schema). This is an advanced feature and not recommended for most users. Seasonal +# storage must be tagged and the TimeSeasonSequential table filled. +time_sequencing = 'seasonal_timeslices' -# How contributions to the planning reserve margin are calculated. Options: -# 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. -# 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# How contributions to the planning reserve margin are calculated +# Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit reserve_margin = 'static' # --------------------------------------------------- diff --git a/tests/testing_configs/config_link_test.toml b/tests/testing_configs/config_link_test.toml index 9d0c32074..8484b482f 100644 --- a/tests/testing_configs/config_link_test.toml +++ b/tests/testing_configs/config_link_test.toml @@ -76,28 +76,38 @@ save_lp_file = false # these are specific to each model # ------------------------------------ -# How to sequence time slices in the model. Options: -# 'seasonal_timeslicing' -# Time slices sequence through seasons and between seasons, looping from the end of each -# period back to its start. Compatible with seasonal time-slicing databases. -# 'representative_periods' -# Time slices sequence through seasons but loop from the end of each season back to its start. -# Time slices do not connect between seasons. Compatible with representative periods databases. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out in -# the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'seasonal_timeslicing' - -# How contributions to the planning reserve margin are calculated. Options: -# 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. -# 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# What seasons represent in the model +# Options: +# 'sequential_days' +# Seasons are a set of days in order, with each season representing only one day. Examples +# might be a model of a representative week with 7 days or a whole-year model with 365 days. +# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# 'representative_periods' +# Each season represents a number of days, though not necessarily in any particular order. +# If using inter-season constraints like seasonal storage or ramp rates, the true sequence +# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# the Technology table. +# 'seasonal_timeslices' +# Each season represents a sequential slice of the year, with one or many days represented per +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out +# in the schema). This is an advanced feature and not recommended for most users. Seasonal +# storage must be tagged and the TimeSeasonSequential table filled. +time_sequencing = 'seasonal_timeslices' + +# How contributions to the planning reserve margin are calculated +# Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit reserve_margin = 'static' # --------------------------------------------------- diff --git a/tests/testing_configs/config_materials.toml b/tests/testing_configs/config_materials.toml index 3ed591861..e2bac02ed 100644 --- a/tests/testing_configs/config_materials.toml +++ b/tests/testing_configs/config_materials.toml @@ -23,28 +23,38 @@ save_lp_file = false # these are specific to each model # ------------------------------------ -# How to sequence time slices in the model. Options: -# 'seasonal_timeslicing' -# Time slices sequence through seasons and between seasons, looping from the end of each -# period back to its start. Compatible with seasonal time-slicing databases. -# 'representative_periods' -# Time slices sequence through seasons but loop from the end of each season back to its start. -# Time slices do not connect between seasons. Compatible with representative periods databases. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out in -# the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'seasonal_timeslicing' +# What seasons represent in the model +# Options: +# 'sequential_days' +# Seasons are a set of days in order, with each season representing only one day. Examples +# might be a model of a representative week with 7 days or a whole-year model with 365 days. +# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# 'representative_periods' +# Each season represents a number of days, though not necessarily in any particular order. +# If using inter-season constraints like seasonal storage or ramp rates, the true sequence +# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# the Technology table. +# 'seasonal_timeslices' +# Each season represents a sequential slice of the year, with one or many days represented per +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out +# in the schema). This is an advanced feature and not recommended for most users. Seasonal +# storage must be tagged and the TimeSeasonSequential table filled. +time_sequencing = 'seasonal_timeslices' -# How contributions to the planning reserve margin are calculated. Options: -# 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. -# 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# How contributions to the planning reserve margin are calculated +# Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit reserve_margin = 'static' # --------------------------------------------------- diff --git a/tests/testing_configs/config_mediumville.toml b/tests/testing_configs/config_mediumville.toml index d759fc61e..4466f1ad7 100644 --- a/tests/testing_configs/config_mediumville.toml +++ b/tests/testing_configs/config_mediumville.toml @@ -57,28 +57,38 @@ save_lp_file = false # these are specific to each model # ------------------------------------ -# How to sequence time slices in the model. Options: -# 'seasonal_timeslicing' -# Time slices sequence through seasons and between seasons, looping from the end of each -# period back to its start. Compatible with seasonal time-slicing databases. -# 'representative_periods' -# Time slices sequence through seasons but loop from the end of each season back to its start. -# Time slices do not connect between seasons. Compatible with representative periods databases. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out in -# the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'seasonal_timeslicing' - -# How contributions to the planning reserve margin are calculated. Options: -# 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. -# 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# What seasons represent in the model +# Options: +# 'sequential_days' +# Seasons are a set of days in order, with each season representing only one day. Examples +# might be a model of a representative week with 7 days or a whole-year model with 365 days. +# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# 'representative_periods' +# Each season represents a number of days, though not necessarily in any particular order. +# If using inter-season constraints like seasonal storage or ramp rates, the true sequence +# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# the Technology table. +# 'seasonal_timeslices' +# Each season represents a sequential slice of the year, with one or many days represented per +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out +# in the schema). This is an advanced feature and not recommended for most users. Seasonal +# storage must be tagged and the TimeSeasonSequential table filled. +time_sequencing = 'seasonal_timeslices' + +# How contributions to the planning reserve margin are calculated +# Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit reserve_margin = 'static' # --------------------------------------------------- diff --git a/tests/testing_configs/config_seasonal_storage.toml b/tests/testing_configs/config_seasonal_storage.toml index e36bba34a..52179f64e 100644 --- a/tests/testing_configs/config_seasonal_storage.toml +++ b/tests/testing_configs/config_seasonal_storage.toml @@ -23,28 +23,38 @@ save_lp_file = false # these are specific to each model # ------------------------------------ -# How to sequence time slices in the model. Options: -# 'seasonal_timeslicing' -# Time slices sequence through seasons and between seasons, looping from the end of each -# period back to its start. Compatible with seasonal time-slicing databases. -# 'representative_periods' -# Time slices sequence through seasons but loop from the end of each season back to its start. -# Time slices do not connect between seasons. Compatible with representative periods databases. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out in -# the schema). This is an advanced feature and not recommended for most users. +# What seasons represent in the model +# Options: +# 'sequential_days' +# Seasons are a set of days in order, with each season representing only one day. Examples +# might be a model of a representative week with 7 days or a whole-year model with 365 days. +# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# 'representative_periods' +# Each season represents a number of days, though not necessarily in any particular order. +# If using inter-season constraints like seasonal storage or ramp rates, the true sequence +# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# the Technology table. +# 'seasonal_timeslices' +# Each season represents a sequential slice of the year, with one or many days represented per +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out +# in the schema). This is an advanced feature and not recommended for most users. Seasonal +# storage must be tagged and the TimeSeasonSequential table filled. time_sequencing = 'representative_periods' -# How contributions to the planning reserve margin are calculated. Options: -# 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. -# 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# How contributions to the planning reserve margin are calculated +# Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit reserve_margin = 'static' # --------------------------------------------------- diff --git a/tests/testing_configs/config_storageville.toml b/tests/testing_configs/config_storageville.toml index 6df7158a9..2add2d9d3 100644 --- a/tests/testing_configs/config_storageville.toml +++ b/tests/testing_configs/config_storageville.toml @@ -57,28 +57,38 @@ save_lp_file = false # these are specific to each model # ------------------------------------ -# How to sequence time slices in the model. Options: -# 'seasonal_timeslicing' -# Time slices sequence through seasons and between seasons, looping from the end of each -# period back to its start. Compatible with seasonal time-slicing databases. -# 'representative_periods' -# Time slices sequence through seasons but loop from the end of each season back to its start. -# Time slices do not connect between seasons. Compatible with representative periods databases. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out in -# the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'seasonal_timeslicing' - -# How contributions to the planning reserve margin are calculated. Options: -# 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. -# 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# What seasons represent in the model +# Options: +# 'sequential_days' +# Seasons are a set of days in order, with each season representing only one day. Examples +# might be a model of a representative week with 7 days or a whole-year model with 365 days. +# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# 'representative_periods' +# Each season represents a number of days, though not necessarily in any particular order. +# If using inter-season constraints like seasonal storage or ramp rates, the true sequence +# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# the Technology table. +# 'seasonal_timeslices' +# Each season represents a sequential slice of the year, with one or many days represented per +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out +# in the schema). This is an advanced feature and not recommended for most users. Seasonal +# storage must be tagged and the TimeSeasonSequential table filled. +time_sequencing = 'seasonal_timeslices' + +# How contributions to the planning reserve margin are calculated +# Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit reserve_margin = 'static' # --------------------------------------------------- diff --git a/tests/testing_configs/config_test_system.toml b/tests/testing_configs/config_test_system.toml index 74393a515..18e46d531 100644 --- a/tests/testing_configs/config_test_system.toml +++ b/tests/testing_configs/config_test_system.toml @@ -23,28 +23,38 @@ save_lp_file = false # these are specific to each model # ------------------------------------ -# How to sequence time slices in the model. Options: -# 'seasonal_timeslicing' -# Time slices sequence through seasons and between seasons, looping from the end of each -# period back to its start. Compatible with seasonal time-slicing databases. -# 'representative_periods' -# Time slices sequence through seasons but loop from the end of each season back to its start. -# Time slices do not connect between seasons. Compatible with representative periods databases. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out in -# the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'seasonal_timeslicing' +# What seasons represent in the model +# Options: +# 'sequential_days' +# Seasons are a set of days in order, with each season representing only one day. Examples +# might be a model of a representative week with 7 days or a whole-year model with 365 days. +# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# 'representative_periods' +# Each season represents a number of days, though not necessarily in any particular order. +# If using inter-season constraints like seasonal storage or ramp rates, the true sequence +# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# the Technology table. +# 'seasonal_timeslices' +# Each season represents a sequential slice of the year, with one or many days represented per +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out +# in the schema). This is an advanced feature and not recommended for most users. Seasonal +# storage must be tagged and the TimeSeasonSequential table filled. +time_sequencing = 'seasonal_timeslices' -# How contributions to the planning reserve margin are calculated. Options: -# 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. -# 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# How contributions to the planning reserve margin are calculated +# Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit reserve_margin = 'static' # --------------------------------------------------- diff --git a/tests/testing_configs/config_utopia.toml b/tests/testing_configs/config_utopia.toml index 60642a838..ab7ff5dea 100644 --- a/tests/testing_configs/config_utopia.toml +++ b/tests/testing_configs/config_utopia.toml @@ -23,28 +23,38 @@ save_lp_file = false # these are specific to each model # ------------------------------------ -# How to sequence time slices in the model. Options: -# 'seasonal_timeslicing' -# Time slices sequence through seasons and between seasons, looping from the end of each -# period back to its start. Compatible with seasonal time-slicing databases. -# 'representative_periods' -# Time slices sequence through seasons but loop from the end of each season back to its start. -# Time slices do not connect between seasons. Compatible with representative periods databases. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out in -# the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'seasonal_timeslicing' +# What seasons represent in the model +# Options: +# 'sequential_days' +# Seasons are a set of days in order, with each season representing only one day. Examples +# might be a model of a representative week with 7 days or a whole-year model with 365 days. +# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# 'representative_periods' +# Each season represents a number of days, though not necessarily in any particular order. +# If using inter-season constraints like seasonal storage or ramp rates, the true sequence +# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# the Technology table. +# 'seasonal_timeslices' +# Each season represents a sequential slice of the year, with one or many days represented per +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out +# in the schema). This is an advanced feature and not recommended for most users. Seasonal +# storage must be tagged and the TimeSeasonSequential table filled. +time_sequencing = 'seasonal_timeslices' -# How contributions to the planning reserve margin are calculated. Options: -# 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. -# 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# How contributions to the planning reserve margin are calculated +# Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit reserve_margin = 'static' # --------------------------------------------------- diff --git a/tests/testing_configs/config_utopia_myopic.toml b/tests/testing_configs/config_utopia_myopic.toml index c64636ebf..9051b91a0 100644 --- a/tests/testing_configs/config_utopia_myopic.toml +++ b/tests/testing_configs/config_utopia_myopic.toml @@ -25,28 +25,38 @@ save_lp_file = false # these are specific to each model # ------------------------------------ -# How to sequence time slices in the model. Options: -# 'seasonal_timeslicing' -# Time slices sequence through seasons and between seasons, looping from the end of each -# period back to its start. Compatible with seasonal time-slicing databases. -# 'representative_periods' -# Time slices sequence through seasons but loop from the end of each season back to its start. -# Time slices do not connect between seasons. Compatible with representative periods databases. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out in -# the schema). This is an advanced feature and not recommended for most users. -time_sequencing = 'seasonal_timeslicing' +# What seasons represent in the model +# Options: +# 'sequential_days' +# Seasons are a set of days in order, with each season representing only one day. Examples +# might be a model of a representative week with 7 days or a whole-year model with 365 days. +# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# 'representative_periods' +# Each season represents a number of days, though not necessarily in any particular order. +# If using inter-season constraints like seasonal storage or ramp rates, the true sequence +# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# the Technology table. +# 'seasonal_timeslices' +# Each season represents a sequential slice of the year, with one or many days represented per +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out +# in the schema). This is an advanced feature and not recommended for most users. Seasonal +# storage must be tagged and the TimeSeasonSequential table filled. +time_sequencing = 'seasonal_timeslices' -# How contributions to the planning reserve margin are calculated. Options: -# 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. -# 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# How contributions to the planning reserve margin are calculated +# Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit reserve_margin = 'static' # --------------------------------------------------- diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index a9302826e..61f7cec33 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -953,17 +953,17 @@ CREATE TABLE TimeSeason ); INSERT INTO TimeSeason VALUES(2000,1,'S1',NULL); INSERT INTO TimeSeason VALUES(2005,1,'S1',NULL); -CREATE TABLE TimeStorageSeason +CREATE TABLE TimeSeasonSequential ( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - storage_season TEXT, + seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season), + PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) ); CREATE TABLE TimePeriodType diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index 5471f850c..f2a2a73f8 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -1440,17 +1440,17 @@ INSERT INTO TimeSeason VALUES(2020,9,'summer',NULL); INSERT INTO TimeSeason VALUES(2020,10,'autumn',NULL); INSERT INTO TimeSeason VALUES(2020,11,'winter',NULL); INSERT INTO TimeSeason VALUES(2020,12,'spring',NULL); -CREATE TABLE TimeStorageSeason +CREATE TABLE TimeSeasonSequential ( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - storage_season TEXT, + seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season), + PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) ); CREATE TABLE TimePeriodType diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index e53fafbd6..1c91fc8a9 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -1029,17 +1029,17 @@ CREATE TABLE TimeSeason ); INSERT INTO TimeSeason VALUES(2025,1,'s1',NULL); INSERT INTO TimeSeason VALUES(2025,2,'s2',NULL); -CREATE TABLE TimeStorageSeason +CREATE TABLE TimeSeasonSequential ( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - storage_season TEXT, + seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season), + PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) ); CREATE TABLE TimePeriodType diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 787ba8ce6..3a25af5e2 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -4168,7 +4168,18 @@ "e", "le" ], - "ordered_storage_season": [], + "ordered_season_sequential": [ + [ + 2025, + "s1", + "s1" + ], + [ + 2025, + "s2", + "s2" + ] + ], "regionalGlobalIndices": [ "B", "A", @@ -4301,7 +4312,7 @@ "s2" ], "TimeSequencing": [ - "seasonal_timeslicing" + "seasonal_timeslices" ], "vintage_all": [ 2025, diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index f782a8fec..9290ae980 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -1025,31 +1025,31 @@ CREATE TABLE OutputCost FOREIGN KEY (vintage) REFERENCES TimePeriod (period), FOREIGN KEY (tech) REFERENCES Technology (tech) ); -CREATE TABLE TimeStorageSeason +CREATE TABLE TimeSeasonSequential ( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - storage_season TEXT, + seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season), + PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) ); -INSERT INTO TimeStorageSeason VALUES(2000,1,'summer','charge',152.5,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,2,'sept_w1','discharge',7,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,3,'sept_w2','charge',7,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,4,'sept_w3','discharge',7,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,5,'sept_w4','charge',7,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,6,'sept_29th','discharge',1,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,7,'sept_30th','charge',1,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,8,'winter','discharge',152.5,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,9,'apr_w1','charge',7,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,10,'apr_w2','discharge',7,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,11,'apr_w3','charge',7,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,12,'apr_w4','discharge',7,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,13,'apr_29th','charge',1,NULL); -INSERT INTO TimeStorageSeason VALUES(2000,14,'apr_30th','discharge',1,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,1,'summer','charge',152.5,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,2,'sept_w1','discharge',7,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,3,'sept_w2','charge',7,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,4,'sept_w3','discharge',7,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,5,'sept_w4','charge',7,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,6,'sept_29th','discharge',1,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,7,'sept_30th','charge',1,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,8,'winter','discharge',152.5,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,9,'apr_w1','charge',7,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,10,'apr_w2','discharge',7,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,11,'apr_w3','charge',7,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,12,'apr_w4','discharge',7,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,13,'apr_29th','charge',1,NULL); +INSERT INTO TimeSeasonSequential VALUES(2000,14,'apr_30th','discharge',1,NULL); COMMIT; diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index bf1946f84..6a4e4fe82 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -922,17 +922,17 @@ CREATE TABLE TimeSeason ); INSERT INTO TimeSeason VALUES(2000,1,'summer',NULL); INSERT INTO TimeSeason VALUES(2000,2,'winter',NULL); -CREATE TABLE TimeStorageSeason +CREATE TABLE TimeSeasonSequential ( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - storage_season TEXT, + seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season), + PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) ); CREATE TABLE TimePeriodType diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index efecfde22..e2377e6c1 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -947,17 +947,17 @@ CREATE TABLE TimeSeason ); INSERT INTO TimeSeason VALUES(2025,1,'s1',NULL); INSERT INTO TimeSeason VALUES(2025,2,'s2',NULL); -CREATE TABLE TimeStorageSeason +CREATE TABLE TimeSeasonSequential ( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - storage_season TEXT, + seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season), + PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) ); CREATE TABLE TimePeriodType diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index f2fbb2f72..9c135ee97 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -1430,17 +1430,17 @@ INSERT INTO TimeSeason VALUES(2030,1,'spring',NULL); INSERT INTO TimeSeason VALUES(2030,2,'summer',NULL); INSERT INTO TimeSeason VALUES(2030,3,'fall',NULL); INSERT INTO TimeSeason VALUES(2030,4,'winter',NULL); -CREATE TABLE TimeStorageSeason +CREATE TABLE TimeSeasonSequential ( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - storage_season TEXT, + seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season), + PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) ); CREATE TABLE TimePeriodType diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index af3768ee7..f46e0747b 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -46568,7 +46568,7 @@ "e", "le" ], - "ordered_storage_season": [], + "ordered_season_sequential": [], "regionalGlobalIndices": [ "R2", "R1", @@ -46715,7 +46715,7 @@ "winter" ], "TimeSequencing": [ - "seasonal_timeslicing" + "seasonal_timeslices" ], "vintage_all": [ 2025, diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 952e49218..738e18d9c 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -1412,17 +1412,17 @@ INSERT INTO TimeSeason VALUES(2000,3,'winter',NULL); INSERT INTO TimeSeason VALUES(2010,1,'inter',NULL); INSERT INTO TimeSeason VALUES(2010,2,'summer',NULL); INSERT INTO TimeSeason VALUES(2010,3,'winter',NULL); -CREATE TABLE TimeStorageSeason +CREATE TABLE TimeSeasonSequential ( period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - storage_season TEXT, + seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), count NUMERIC NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, storage_season, season), + PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) ); CREATE TABLE TimePeriodType diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index be83827f3..670332847 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -25654,7 +25654,7 @@ "e", "le" ], - "ordered_storage_season": [], + "ordered_season_sequential": [], "regionalGlobalIndices": [ "utopia" ], @@ -25812,7 +25812,7 @@ "winter" ], "TimeSequencing": [ - "seasonal_timeslicing" + "seasonal_timeslices" ], "vintage_all": [ 1990, From b61980777f4a6313a9eb9054771cbeef2fbf836a Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Jun 2025 09:25:07 -0400 Subject: [PATCH 120/587] Rename Ramp constraints to RampHourly --- data_files/example_dbs/materials.sql | 4 ++-- data_files/example_dbs/morris_utopia.sql | 4 ++-- data_files/example_dbs/seasonal_storage.sql | 4 ++-- data_files/example_dbs/stepped_demand.sql | 4 ++-- data_files/example_dbs/test_system.sql | 4 ++-- data_files/example_dbs/utopia.sql | 4 ++-- temoa/temoa_model/hybrid_loader.py | 24 +++++++++---------- .../temoa_model/model_checking/validators.py | 4 ++-- temoa/temoa_model/temoa_model.py | 4 ++-- temoa/temoa_model/temoa_rules.py | 4 ++-- tests/testing_data/emissions.sql | 4 ++-- tests/testing_data/materials.sql | 4 ++-- tests/testing_data/mediumville.sql | 12 +++++----- tests/testing_data/seasonal_storage.sql | 4 ++-- tests/testing_data/simple_linked_tech.sql | 4 ++-- tests/testing_data/storageville.sql | 4 ++-- tests/testing_data/test_system.sql | 4 ++-- tests/testing_data/utopia.sql | 4 ++-- 18 files changed, 50 insertions(+), 50 deletions(-) diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index f2a2a73f8..74d1ad1d0 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -1290,7 +1290,7 @@ CREATE TABLE PlanningReserveMargin REFERENCES Region (region), margin REAL ); -CREATE TABLE RampDown +CREATE TABLE RampDownHourly ( region TEXT, tech TEXT @@ -1298,7 +1298,7 @@ CREATE TABLE RampDown rate REAL, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUp +CREATE TABLE RampUpHourly ( region TEXT, tech TEXT diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index e466af358..16e5cd184 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -1303,7 +1303,7 @@ CREATE TABLE PlanningReserveMargin REFERENCES Region (region), margin REAL ); -CREATE TABLE RampDown +CREATE TABLE RampDownHourly ( region TEXT, tech TEXT @@ -1311,7 +1311,7 @@ CREATE TABLE RampDown rate REAL, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUp +CREATE TABLE RampUpHourly ( region TEXT, tech TEXT diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql index 9290ae980..3af77d8e2 100644 --- a/data_files/example_dbs/seasonal_storage.sql +++ b/data_files/example_dbs/seasonal_storage.sql @@ -844,7 +844,7 @@ CREATE TABLE PlanningReserveMargin REFERENCES Region (region), margin REAL ); -CREATE TABLE RampDown +CREATE TABLE RampDownHourly ( region TEXT, tech TEXT @@ -852,7 +852,7 @@ CREATE TABLE RampDown rate REAL, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUp +CREATE TABLE RampUpHourly ( region TEXT, tech TEXT diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index cf3b36c37..a59e97284 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -1023,7 +1023,7 @@ CREATE TABLE PlanningReserveMargin REFERENCES Region (region), margin REAL ); -CREATE TABLE RampDown +CREATE TABLE RampDownHourly ( region TEXT, tech TEXT @@ -1031,7 +1031,7 @@ CREATE TABLE RampDown rate REAL, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUp +CREATE TABLE RampUpHourly ( region TEXT, tech TEXT diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index 9c135ee97..04a9b0848 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -1306,7 +1306,7 @@ CREATE TABLE PlanningReserveMargin REFERENCES Region (region), margin REAL ); -CREATE TABLE RampDown +CREATE TABLE RampDownHourly ( region TEXT, tech TEXT @@ -1314,7 +1314,7 @@ CREATE TABLE RampDown rate REAL, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUp +CREATE TABLE RampUpHourly ( region TEXT, tech TEXT diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 738e18d9c..fe6ce9bea 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -1298,7 +1298,7 @@ CREATE TABLE PlanningReserveMargin REFERENCES Region (region), margin REAL ); -CREATE TABLE RampDown +CREATE TABLE RampDownHourly ( region TEXT, tech TEXT @@ -1306,7 +1306,7 @@ CREATE TABLE RampDown rate REAL, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUp +CREATE TABLE RampUpHourly ( region TEXT, tech TEXT diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 48921738d..e8a3abd35 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -511,12 +511,12 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N load_element(M.tech_reserve, raw, self.viable_techs) # tech_ramping - if self.table_exists('RampUp'): - ramp_up_techs = cur.execute('SELECT tech FROM main.RampUp').fetchall() + if self.table_exists('RampUpHourly'): + ramp_up_techs = cur.execute('SELECT tech FROM main.RampUpHourly').fetchall() techs = {t[0] for t in ramp_up_techs} load_element(M.tech_upramping, sorted((t,) for t in techs), self.viable_techs) # sort for deterministic behavior - if self.table_exists('RampDown'): - ramp_dn_techs = cur.execute('SELECT tech FROM main.RampDown').fetchall() + if self.table_exists('RampDownHourly'): + ramp_dn_techs = cur.execute('SELECT tech FROM main.RampDownHourly').fetchall() techs = {t[0] for t in ramp_dn_techs} load_element(M.tech_downramping, sorted((t,) for t in techs), self.viable_techs) # sort for deterministic behavior @@ -1063,15 +1063,15 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N print('problem loading linked tech. See log file') sys.exit(-1) - # RampUp - if self.table_exists('RampUp'): - raw = cur.execute('SELECT region, tech, rate FROM main.RampUp').fetchall() - load_element(M.RampUp, raw, self.viable_rt, (0, 1)) + # RampUpHourly + if self.table_exists('RampUpHourly'): + raw = cur.execute('SELECT region, tech, rate FROM main.RampUpHourly').fetchall() + load_element(M.RampUpHourly, raw, self.viable_rt, (0, 1)) - # RampDown - if self.table_exists('RampDown'): - raw = cur.execute('SELECT region, tech, rate FROM main.RampDown').fetchall() - load_element(M.RampDown, raw, self.viable_rt, (0, 1)) + # RampDownHourly + if self.table_exists('RampDownHourly'): + raw = cur.execute('SELECT region, tech, rate FROM main.RampDownHourly').fetchall() + load_element(M.RampDownHourly, raw, self.viable_rt, (0, 1)) # CapacityCredit if self.table_exists('CapacityCredit'): diff --git a/temoa/temoa_model/model_checking/validators.py b/temoa/temoa_model/model_checking/validators.py index c86360391..e5b4a60be 100644 --- a/temoa/temoa_model/model_checking/validators.py +++ b/temoa/temoa_model/model_checking/validators.py @@ -309,8 +309,8 @@ def validate_SeasonSequential(M: 'TemoaModel'): if all(( not M.tech_seasonal_storage, - not M.RampUp, - not M.RampDown, + not M.RampUpHourly, + not M.RampDownHourly, )): # Don't need it anyway return diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 03337f8c1..d5d93fbd3 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -352,8 +352,8 @@ def __init__(M, *args, **kwargs): M.RenewablePortfolioStandard = Param(M.RenewablePortfolioStandardConstraint_rpg, validate=validate_0to1) # These need to come before validate_SeasonSequential - M.RampUp = Param(M.regions, M.tech_upramping, validate=validate_0to1) - M.RampDown = Param(M.regions, M.tech_downramping, validate=validate_0to1) + M.RampUpHourly = Param(M.regions, M.tech_upramping, validate=validate_0to1) + M.RampDownHourly = Param(M.regions, M.tech_downramping, validate=validate_0to1) # Set up representation of time M.DaysPerPeriod = Param() diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 57c60aef4..2497664c6 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1652,7 +1652,7 @@ def RampUp_Constraint(M: 'TemoaModel', r, p, s, d, t, v): ) / value(M.SegFrac[p, s_next, d_next]) hours_elapsed = 24 * value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) - ramp_fraction = hours_elapsed * value(M.RampUp[r, t]) + ramp_fraction = hours_elapsed * value(M.RampUpHourly[r, t]) if ramp_fraction >= 1: msg = ( @@ -1709,7 +1709,7 @@ def RampDown_Constraint(M: 'TemoaModel', r, p, s, d, t, v): ) / value(M.SegFrac[p, s_next, d_next]) hours_elapsed = 24 * value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) - ramp_fraction = hours_elapsed * value(M.RampDown[r, t]) + ramp_fraction = hours_elapsed * value(M.RampDownHourly[r, t]) if ramp_fraction >= 1: msg = ( diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 61f7cec33..453d42d0b 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -863,7 +863,7 @@ CREATE TABLE PlanningReserveMargin REFERENCES Region (region), margin REAL ); -CREATE TABLE RampDown +CREATE TABLE RampDownHourly ( region TEXT, tech TEXT @@ -871,7 +871,7 @@ CREATE TABLE RampDown rate REAL, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUp +CREATE TABLE RampUpHourly ( region TEXT, tech TEXT diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index f2a2a73f8..74d1ad1d0 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -1290,7 +1290,7 @@ CREATE TABLE PlanningReserveMargin REFERENCES Region (region), margin REAL ); -CREATE TABLE RampDown +CREATE TABLE RampDownHourly ( region TEXT, tech TEXT @@ -1298,7 +1298,7 @@ CREATE TABLE RampDown rate REAL, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUp +CREATE TABLE RampUpHourly ( region TEXT, tech TEXT diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 1c91fc8a9..c32366cfe 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -934,7 +934,7 @@ CREATE TABLE PlanningReserveMargin margin REAL ); INSERT INTO PlanningReserveMargin VALUES('A',0.05000000000000000277); -CREATE TABLE RampDown +CREATE TABLE RampDownHourly ( region TEXT, tech TEXT @@ -942,9 +942,9 @@ CREATE TABLE RampDown rate REAL, PRIMARY KEY (region, tech) ); -INSERT INTO RampDown VALUES('A','EH',0.05000000000000000277); -INSERT INTO RampDown VALUES('B','EH',0.05000000000000000277); -CREATE TABLE RampUp +INSERT INTO RampDownHourly VALUES('A','EH',0.05000000000000000277); +INSERT INTO RampDownHourly VALUES('B','EH',0.05000000000000000277); +CREATE TABLE RampUpHourly ( region TEXT, tech TEXT @@ -952,8 +952,8 @@ CREATE TABLE RampUp rate REAL, PRIMARY KEY (region, tech) ); -INSERT INTO RampUp VALUES('B','EH',0.05000000000000000277); -INSERT INTO RampUp VALUES('A','EH',0.05000000000000000277); +INSERT INTO RampUpHourly VALUES('B','EH',0.05000000000000000277); +INSERT INTO RampUpHourly VALUES('A','EH',0.05000000000000000277); CREATE TABLE Region ( region TEXT diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index 9290ae980..3af77d8e2 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -844,7 +844,7 @@ CREATE TABLE PlanningReserveMargin REFERENCES Region (region), margin REAL ); -CREATE TABLE RampDown +CREATE TABLE RampDownHourly ( region TEXT, tech TEXT @@ -852,7 +852,7 @@ CREATE TABLE RampDown rate REAL, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUp +CREATE TABLE RampUpHourly ( region TEXT, tech TEXT diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index 6a4e4fe82..1ecff1002 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -836,7 +836,7 @@ CREATE TABLE PlanningReserveMargin REFERENCES Region (region), margin REAL ); -CREATE TABLE RampDown +CREATE TABLE RampDownHourly ( region TEXT, tech TEXT @@ -844,7 +844,7 @@ CREATE TABLE RampDown rate REAL, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUp +CREATE TABLE RampUpHourly ( region TEXT, tech TEXT diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index e2377e6c1..43450bc5b 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -848,7 +848,7 @@ CREATE TABLE PlanningReserveMargin REFERENCES Region (region), margin REAL ); -CREATE TABLE RampDown +CREATE TABLE RampDownHourly ( region TEXT, tech TEXT @@ -856,7 +856,7 @@ CREATE TABLE RampDown rate REAL, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUp +CREATE TABLE RampUpHourly ( region TEXT, tech TEXT diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 9c135ee97..04a9b0848 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -1306,7 +1306,7 @@ CREATE TABLE PlanningReserveMargin REFERENCES Region (region), margin REAL ); -CREATE TABLE RampDown +CREATE TABLE RampDownHourly ( region TEXT, tech TEXT @@ -1314,7 +1314,7 @@ CREATE TABLE RampDown rate REAL, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUp +CREATE TABLE RampUpHourly ( region TEXT, tech TEXT diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 738e18d9c..fe6ce9bea 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -1298,7 +1298,7 @@ CREATE TABLE PlanningReserveMargin REFERENCES Region (region), margin REAL ); -CREATE TABLE RampDown +CREATE TABLE RampDownHourly ( region TEXT, tech TEXT @@ -1306,7 +1306,7 @@ CREATE TABLE RampDown rate REAL, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUp +CREATE TABLE RampUpHourly ( region TEXT, tech TEXT From 34cee7b939e141e4423f140f186b587c00807329 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Jun 2025 09:30:14 -0400 Subject: [PATCH 121/587] Missed some bits in generalising inter-season sequencing --- temoa/temoa_model/table_data_puller.py | 10 ++++----- temoa/temoa_model/temoa_rules.py | 30 +++++++++++++------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index e86b1c71a..293d040f2 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -249,15 +249,15 @@ def poll_storage_level_results(M: TemoaModel, epsilon=1e-5) -> dict[SLI, float]: if abs(state) < epsilon: state = 0 # still want to know but decimals are ugly res[sli] = state - for r, p, s_stor, t, v in M.SeasonalStorageLevel_rpstv: - s = M.sequential_to_season[p, s_stor] + for r, p, s_seq, t, v in M.SeasonalStorageLevel_rpstv: + s = M.sequential_to_season[p, s_seq] # Ratio of days in virtual storage season to days in actual season # Flows and StorageLevel are normalised to the number of days in the ACTUAL season, so must # be adjusted to the number of days in the virtual storage season - days_adjust = value(M.TimeSeasonSequential[p, s_stor, s]) / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) + days_adjust = value(M.TimeSeasonSequential[p, s_seq, s]) / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) for d in M.time_of_day: - state = value(M.V_SeasonalStorageLevel[r, p, s_stor, t, v]) + value(M.V_StorageLevel[r, p, s, d, t, v]) * days_adjust - sli = SLI(r, p, s_stor, d, t, v) + state = value(M.V_SeasonalStorageLevel[r, p, s_seq, t, v]) + value(M.V_StorageLevel[r, p, s, d, t, v]) * days_adjust + sli = SLI(r, p, s_seq, d, t, v) if abs(state) < epsilon: state = 0 # still want to know but decimals are ugly res[sli] = state diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 2497664c6..b8d436b7b 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1291,14 +1291,14 @@ def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): return expr -def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_stor, t, v): +def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_seq, t, v): """ This constraint enforces the continuity of state of charge between seasons for seasonal storage. Virtual seasonal storage level increases by the matched real season's net charge over that entire day. """ - s = M.sequential_to_season[p, s_stor] + s = M.sequential_to_season[p, s_seq] # This is the sum of all input=i sent TO storage tech t of vintage v with # output=o in p,s,d @@ -1318,19 +1318,19 @@ def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_stor, t, v): for d in M.time_of_day ) - s_stor_next = M.time_next_sequential[p, s_stor] - s_next = M.sequential_to_season[p, s_stor_next] + s_seq_next = M.time_next_sequential[p, s_seq] + s_next = M.sequential_to_season[p, s_seq_next] # Ratio of days in virtual storage season to days in actual season # Flows and StorageLevel are normalised to the number of days in the ACTUAL season, so must # be adjusted to the number of days in the virtual storage season - days_adjust = value(M.TimeSeasonSequential[p, s_stor, s]) / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) - days_adjust_next = value(M.TimeSeasonSequential[p, s_stor_next, s_next]) / (value(M.SegFracPerSeason[p, s_next]) * value(M.DaysPerPeriod)) + days_adjust = value(M.TimeSeasonSequential[p, s_seq, s]) / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) + days_adjust_next = value(M.TimeSeasonSequential[p, s_seq_next, s_next]) / (value(M.SegFracPerSeason[p, s_next]) * value(M.DaysPerPeriod)) stored_energy = (charge - discharge) * days_adjust - start = M.V_SeasonalStorageLevel[r, p, s_stor, t, v] + M.V_StorageLevel[r, p, s, M.time_of_day.first(), t, v] * days_adjust - end = M.V_SeasonalStorageLevel[r, p, s_stor_next, t, v] + M.V_StorageLevel[r, p, s_next, M.time_of_day.first(), t, v] * days_adjust_next + start = M.V_SeasonalStorageLevel[r, p, s_seq, t, v] + M.V_StorageLevel[r, p, s, M.time_of_day.first(), t, v] * days_adjust + end = M.V_SeasonalStorageLevel[r, p, s_seq_next, t, v] + M.V_StorageLevel[r, p, s_next, M.time_of_day.first(), t, v] * days_adjust_next expr = start + stored_energy == end return expr @@ -1381,7 +1381,7 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): return expr -def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_stor, d, t, v): +def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_seq, d, t, v): r""" Builds off of StorageEnergyUpperBound_Constraint. Enforces the max charge capacity of seasonal storage, summing the superimposed real storage level with the virtual @@ -1398,7 +1398,7 @@ def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_stor, d, seasons. """ - s = M.sequential_to_season[p, s_stor] + s = M.sequential_to_season[p, s_seq] energy_capacity = ( M.V_Capacity[r, p, t, v] @@ -1410,13 +1410,13 @@ def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_stor, d, # Ratio of days in virtual storage season to days in actual season # Flows and StorageLevel are normalised to the number of days in the ACTUAL season, so must # be adjusted to the number of days in the virtual storage season - days_adjust = value(M.TimeSeasonSequential[p, s_stor, s]) / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) + days_adjust = value(M.TimeSeasonSequential[p, s_seq, s]) / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) # V_StorageLevel tracks the running cumulative delta in the actual season, so must be adjusted # to the size of the virtual, storage season running_day_delta = M.V_StorageLevel[r, p, s, d, t, v] * days_adjust - expr = M.V_SeasonalStorageLevel[r, p, s_stor, t, v] + running_day_delta <= energy_capacity + expr = M.V_SeasonalStorageLevel[r, p, s_seq, t, v] + running_day_delta <= energy_capacity return expr @@ -1574,15 +1574,15 @@ def LimitStorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v, op): ) if M.is_seasonal_storage[t]: - s_stor = s # virtual storage season - s = M.sequential_to_season[p, s_stor] # actual season + s_seq = s # virtual storage season + s = M.sequential_to_season[p, s_seq] # actual season # adjust the storage level to the individual-day level energy_level = M.V_StorageLevel[r, p, s, d, t, v] / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) if M.is_seasonal_storage[t]: # seasonal storage upper energy limit is absolute - energy_level = M.V_SeasonalStorageLevel[r, p, s_stor, t, v] + energy_level * value(M.TimeSeasonSequential[p, s_stor, s]) + energy_level = M.V_SeasonalStorageLevel[r, p, s_seq, t, v] + energy_level * value(M.TimeSeasonSequential[p, s_seq, s]) expr = operator_expression(energy_level, op, energy_limit) From 29aa342e45ef82ff2fe64d8731a67f7b5ed76268 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Jun 2025 10:53:54 -0400 Subject: [PATCH 122/587] Revive day vs season ramping constraints --- temoa/temoa_model/temoa_initialize.py | 40 +++++- temoa/temoa_model/temoa_model.py | 17 ++- temoa/temoa_model/temoa_rules.py | 169 +++++++++++++++++++---- tests/legacy_test_values.py | 6 +- tests/testing_data/mediumville_sets.json | 72 +++++++++- tests/testing_data/test_system_sets.json | 6 +- tests/testing_data/utopia_sets.json | 6 +- 7 files changed, 268 insertions(+), 48 deletions(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 270cb8345..7017ddbb8 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1543,25 +1543,55 @@ def AnnualCommodityBalanceConstraintIndices(M: 'TemoaModel'): return indices -def RampUpConstraintIndices(M: 'TemoaModel'): +def RampUpDayConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, s, d, t, v) - for r, p, t in M.rampUpVintages.keys() + for r, p, t in M.rampUpVintages + for v in M.rampUpVintages[r, p, t] for s in M.time_season[p] for d in M.time_of_day - for v in M.rampUpVintages[r, p, t] ) return indices -def RampDownConstraintIndices(M: 'TemoaModel'): +def RampDownDayConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, s, d, t, v) - for r, p, t in M.rampDownVintages.keys() + for r, p, t in M.rampDownVintages + for v in M.rampDownVintages[r, p, t] for s in M.time_season[p] for d in M.time_of_day + ) + + return indices + + +def RampUpSeasonConstraintIndices(M: 'TemoaModel'): + if M.TimeSequencing.first() == 'sequential_days': + return {} # dont need this constraint + + indices = set( + (r, p, s_seq, M.time_of_day.last(), t, v) + for r, p, t in M.rampUpVintages + for v in M.rampUpVintages[r, p, t] + for _p, s_seq, _ in M.ordered_season_sequential + if _p == p + ) + + return indices + + +def RampDownSeasonConstraintIndices(M: 'TemoaModel'): + if M.TimeSequencing.first() == 'sequential_days': + return {} # dont need this constraint + + indices = set( + (r, p, s_seq, M.time_of_day.last(), t, v) + for r, p, t in M.rampDownVintages for v in M.rampDownVintages[r, p, t] + for _p, s_seq, _ in M.ordered_season_sequential + if _p == p ) return indices diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index d5d93fbd3..f9587e622 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -128,8 +128,8 @@ def __init__(M, *args, **kwargs): # These establish time sequencing M.time_next = dict() # {(p, s, d): (s_next, d_next)} sequence of following time slices - M.time_next_sequential = dict() # {(p, s_stor): (s_stor_next)} next virtual storage season - M.sequential_to_season = dict() # {(p, s_stor): (s)} season matching this virtual storage season + M.time_next_sequential = dict() # {(p, s_seq): (s_seq_next)} next virtual storage season + M.sequential_to_season = dict() # {(p, s_seq): (s)} season matching this virtual storage season M.is_seasonal_storage = dict() # to avoid slow O(n2) behaviour in storage constraints ################################################ @@ -697,10 +697,15 @@ def __init__(M, *args, **kwargs): M.LimitStorageFractionConstraint_rpsdtv, rule=LimitStorageFraction_Constraint ) - M.RampUpConstraint_rpsdtv = Set(dimen=6, initialize=RampUpConstraintIndices) - M.RampUpConstraint = Constraint(M.RampUpConstraint_rpsdtv, rule=RampUp_Constraint) - M.RampDownConstraint_rpsdtv = Set(dimen=6, initialize=RampDownConstraintIndices) - M.RampDownConstraint = Constraint(M.RampDownConstraint_rpsdtv, rule=RampDown_Constraint) + M.RampUpDayConstraint_rpsdtv = Set(dimen=6, initialize=RampUpDayConstraintIndices) + M.RampUpDayConstraint = Constraint(M.RampUpDayConstraint_rpsdtv, rule=RampUpDay_Constraint) + M.RampDownDayConstraint_rpsdtv = Set(dimen=6, initialize=RampDownDayConstraintIndices) + M.RampDownDayConstraint = Constraint(M.RampDownDayConstraint_rpsdtv, rule=RampDownDay_Constraint) + + M.RampUpSeasonConstraint_rpsdtv = Set(dimen=6, initialize=RampUpSeasonConstraintIndices) + M.RampUpSeasonConstraint = Constraint(M.RampUpSeasonConstraint_rpsdtv, rule=RampUpSeason_Constraint) + M.RampDownSeasonConstraint_rpsdtv = Set(dimen=6, initialize=RampDownSeasonConstraintIndices) + M.RampDownSeasonConstraint = Constraint(M.RampDownSeasonConstraint_rpsdtv, rule=RampDownSeason_Constraint) M.ReserveMargin_rpsd = Set(dimen=4, initialize=ReserveMarginIndices) M.validate_ReserveMargin = BuildAction(rule=validate_ReserveMargin) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index b8d436b7b..366a81db2 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1294,8 +1294,9 @@ def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_seq, t, v): """ This constraint enforces the continuity of state of charge between seasons for seasonal - storage. Virtual seasonal storage level increases by the matched real season's net charge - over that entire day. + storage. Sequential season storage level increases by the matched season's net charge + over that entire day, adjusted for number of days represented by sequential vs non-sequential + seasons. """ s = M.sequential_to_season[p, s_seq] @@ -1321,9 +1322,8 @@ def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_seq, t, v): s_seq_next = M.time_next_sequential[p, s_seq] s_next = M.sequential_to_season[p, s_seq_next] - # Ratio of days in virtual storage season to days in actual season - # Flows and StorageLevel are normalised to the number of days in the ACTUAL season, so must - # be adjusted to the number of days in the virtual storage season + # Flows and StorageLevel are normalised to the number of days in the non-sequential season, so must + # be adjusted to the number of days in the sequential season days_adjust = value(M.TimeSeasonSequential[p, s_seq, s]) / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) days_adjust_next = value(M.TimeSeasonSequential[p, s_seq_next, s_next]) / (value(M.SegFracPerSeason[p, s_next]) * value(M.DaysPerPeriod)) @@ -1384,7 +1384,7 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_seq, d, t, v): r""" Builds off of StorageEnergyUpperBound_Constraint. Enforces the max charge capacity - of seasonal storage, summing the superimposed real storage level with the virtual + of seasonal storage, summing the superimposed real storage level with the sequential seasonal storage level. A season can represent many days. Within each season, flows are multiplied by the number of days each season represents, and so the upper bound needs to be adjusted to allow day-scale flows (e.g., charge in the morning, discharge @@ -1407,13 +1407,12 @@ def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_seq, d, * value(M.ProcessLifeFrac[r, p, t, v]) ) - # Ratio of days in virtual storage season to days in actual season - # Flows and StorageLevel are normalised to the number of days in the ACTUAL season, so must - # be adjusted to the number of days in the virtual storage season + # Flows and StorageLevel are normalised to the number of days in the non-sequential season, so must + # be adjusted to the number of days in the sequential season days_adjust = value(M.TimeSeasonSequential[p, s_seq, s]) / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) - # V_StorageLevel tracks the running cumulative delta in the actual season, so must be adjusted - # to the size of the virtual, storage season + # V_StorageLevel tracks the running cumulative delta in the non-sequential season, so must be adjusted + # to the size of the sequential season running_day_delta = M.V_StorageLevel[r, p, s, d, t, v] * days_adjust expr = M.V_SeasonalStorageLevel[r, p, s_seq, t, v] + running_day_delta <= energy_capacity @@ -1574,8 +1573,8 @@ def LimitStorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v, op): ) if M.is_seasonal_storage[t]: - s_seq = s # virtual storage season - s = M.sequential_to_season[p, s_seq] # actual season + s_seq = s # sequential season + s = M.sequential_to_season[p, s_seq] # non-sequential season # adjust the storage level to the individual-day level energy_level = M.V_StorageLevel[r, p, s, d, t, v] / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) @@ -1589,7 +1588,7 @@ def LimitStorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v, op): return expr -def RampUp_Constraint(M: 'TemoaModel', r, p, s, d, t, v): +def RampUpDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): # M.time_of_day is a sorted set, and M.time_of_day.first() returns the first # element in the set, similarly, M.time_of_day.last() returns the last element. # M.time_of_day.prev(d) function will return the previous element before s, and @@ -1639,36 +1638,44 @@ def RampUp_Constraint(M: 'TemoaModel', r, p, s, d, t, v): s_next, d_next = M.time_next[p, s, d] - activity_sd = sum( + # How many hours does this time slice represent + hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 + + hourly_activity_sd = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) / value(M.SegFrac[p, s, d]) + ) / hours_adjust - activity_sd_next = sum( + hourly_activity_sd_next = sum( M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) / value(M.SegFrac[p, s_next, d_next]) + ) / hours_adjust - hours_elapsed = 24 * value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) + # elapsed hours from middle of this time slice to middle of next time slice + hours_elapsed = 24 / 2 * ( + value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) + + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + ) ramp_fraction = hours_elapsed * value(M.RampUpHourly[r, t]) if ramp_fraction >= 1: msg = ( - "Warning: Hourly ramp up rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). Constraint skipped." + "Warning: Hourly ramp up rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). " + f"Should be less than {1/hours_elapsed:.4f}. Constraint skipped." ) logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) return Constraint.Skip - activity_increase = activity_sd_next - activity_sd # opposite sign from rampdown + activity_increase = hourly_activity_sd_next - hourly_activity_sd # opposite sign from rampdown rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.ProcessLifeFrac[r, p, t, v]) expr = activity_increase <= rampable_activity return expr -def RampDown_Constraint(M: 'TemoaModel', r, p, s, d, t, v): +def RampDownDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): r""" Similar to the :code`RampUpDay` constraint, we use the :code:`RampDownDay` @@ -1696,35 +1703,139 @@ def RampDown_Constraint(M: 'TemoaModel', r, p, s, d, t, v): s_next, d_next = M.time_next[p, s, d] - activity_sd = sum( + # How many hours does this time slice represent + hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 + + hourly_activity_sd = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) / value(M.SegFrac[p, s, d]) + ) / hours_adjust - activity_sd_next = sum( + hourly_activity_sd_next = sum( M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) / value(M.SegFrac[p, s_next, d_next]) + ) / hours_adjust - hours_elapsed = 24 * value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) + # elapsed hours from middle of this time slice to middle of next time slice + hours_elapsed = 24 / 2 * ( + value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) + + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + ) ramp_fraction = hours_elapsed * value(M.RampDownHourly[r, t]) if ramp_fraction >= 1: msg = ( - "Warning: Hourly ramp down rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). Constraint skipped." + "Warning: Hourly ramp down rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). " + f"Should be less than {1/hours_elapsed:.4f}. Constraint skipped." ) logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) return Constraint.Skip - activity_decrease = activity_sd - activity_sd_next # opposite sign from rampup + activity_decrease = hourly_activity_sd - hourly_activity_sd_next # opposite sign from rampup rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.ProcessLifeFrac[r, p, t, v]) expr = activity_decrease <= rampable_activity return expr +def RampUpSeason_Constraint(M: 'TemoaModel', r, p, s_seq, d, t, v): + r""" + Constrains the ramp up rate of activity between time slices at the boundary + of sequential seasons. + """ + + s = M.sequential_to_season[p, s_seq] + s_seq_next = M.time_next_sequential[p, s_seq] + s_next = M.sequential_to_season[p, s_seq_next] + _, d_next = M.time_next[p, s, d] + + # How many hours does this time slice represent + hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 + + hourly_activity_sd = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) / hours_adjust + + hourly_activity_sd_next = sum( + M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) / hours_adjust + + # elapsed hours from middle of this time slice to middle of next time slice + hours_elapsed = 24 / 2 * ( + value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) + + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + ) + ramp_fraction = hours_elapsed * value(M.RampUpHourly[r, t]) + + if ramp_fraction >= 1: + msg = ( + "Warning: Hourly ramp up rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). " + f"Should be less than {1/hours_elapsed:.4f}. Constraint skipped." + ) + logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) + return Constraint.Skip + + activity_increase = hourly_activity_sd_next - hourly_activity_sd # opposite sign from rampdown + rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.ProcessLifeFrac[r, p, t, v]) + expr = activity_increase <= rampable_activity + + return expr + + +def RampDownSeason_Constraint(M: 'TemoaModel', r, p, s_seq, d, t, v): + r""" + Constrains the ramp down rate of activity between time slices at the boundary + of sequential seasons. + """ + + s = M.sequential_to_season[p, s_seq] + s_seq_next = M.time_next_sequential[p, s_seq] + s_next = M.sequential_to_season[p, s_seq_next] + _, d_next = M.time_next[p, s, d] + + # How many hours does this time slice represent + hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 + + hourly_activity_sd = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) / hours_adjust + + hourly_activity_sd_next = sum( + M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) / hours_adjust + + # elapsed hours from middle of this time slice to middle of next time slice + hours_elapsed = 24 / 2 * ( + value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) + + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + ) + ramp_fraction = hours_elapsed * value(M.RampDownHourly[r, t]) + + if ramp_fraction >= 1: + msg = ( + "Warning: Hourly ramp down rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). " + f"Should be less than {1/hours_elapsed:.4f}. Constraint skipped." + ) + logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) + return Constraint.Skip + + activity_decrease = hourly_activity_sd - hourly_activity_sd_next # opposite sign from rampup + rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.ProcessLifeFrac[r, p, t, v]) + expr = activity_decrease <= rampable_activity + + return expr + + def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): # Get available generation in this time slice depending on method specified in config file diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index 6b740341e..b591c7b79 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -69,10 +69,12 @@ class ExpectedVals(Enum): }, 'mediumville': { # added 2025/06/12 prior to addition of dynamic reserve margin - ExpectedVals.OBJ_VALUE: 7035.7275, # reduced 2025/06/16 after fixing bug in db + # reduced 2025/06/16 after fixing bug in db + ExpectedVals.OBJ_VALUE: 7035.7275, ExpectedVals.EFF_DOMAIN_SIZE: 2800, ExpectedVals.EFF_INDEX_SIZE: 18, - ExpectedVals.CONSTR_COUNT: 232, + # increased after reviving RampSeason constraints + ExpectedVals.CONSTR_COUNT: 240, ExpectedVals.VAR_COUNT: 140, }, 'seasonal_storage': { diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 3a25af5e2..a8957e3d2 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -3864,7 +3864,7 @@ 2025 ] ], - "RampDownConstraint_rpsdtv": [ + "RampDownDayConstraint_rpsdtv": [ [ "B", 2025, @@ -3930,7 +3930,41 @@ 2025 ] ], - "RampUpConstraint_rpsdtv": [ + "RampDownSeasonConstraint_rpsdtv": [ + [ + "A", + 2025, + "s1", + "d2", + "EH", + 2025 + ], + [ + "A", + 2025, + "s2", + "d2", + "EH", + 2025 + ], + [ + "B", + 2025, + "s1", + "d2", + "EH", + 2025 + ], + [ + "B", + 2025, + "s2", + "d2", + "EH", + 2025 + ] + ], + "RampUpDayConstraint_rpsdtv": [ [ "B", 2025, @@ -3996,6 +4030,40 @@ 2025 ] ], + "RampUpSeasonConstraint_rpsdtv": [ + [ + "A", + 2025, + "s1", + "d2", + "EH", + 2025 + ], + [ + "A", + 2025, + "s2", + "d2", + "EH", + 2025 + ], + [ + "B", + 2025, + "s1", + "d2", + "EH", + 2025 + ], + [ + "B", + 2025, + "s2", + "d2", + "EH", + 2025 + ] + ], "RegionalExchangeCapacityConstraint_rrptv": [ [ "B", diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index f46e0747b..867c86a63 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -44914,8 +44914,10 @@ 2020 ] ], - "RampDownConstraint_rpsdtv": [], - "RampUpConstraint_rpsdtv": [], + "RampDownDayConstraint_rpsdtv": [], + "RampDownSeasonConstraint_rpsdtv": [], + "RampUpDayConstraint_rpsdtv": [], + "RampUpSeasonConstraint_rpsdtv": [], "RegionalExchangeCapacityConstraint_rrptv": [ [ "R2", diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 670332847..3b85e3590 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -24713,8 +24713,10 @@ 1990 ] ], - "RampDownConstraint_rpsdtv": [], - "RampUpConstraint_rpsdtv": [], + "RampDownDayConstraint_rpsdtv": [], + "RampDownSeasonConstraint_rpsdtv": [], + "RampUpDayConstraint_rpsdtv": [], + "RampUpSeasonConstraint_rpsdtv": [], "RegionalExchangeCapacityConstraint_rrptv": [], "RenewablePortfolioStandardConstraint_rpg": [], "ReserveMargin_rpsd": [], From d50d96442f6e93d1a7215625a97fc83e86195475 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Jun 2025 11:20:54 -0400 Subject: [PATCH 123/587] Clean up a couple things --- temoa/temoa_model/hybrid_loader.py | 49 ++--- temoa/temoa_model/temoa_rules.py | 281 +---------------------------- 2 files changed, 13 insertions(+), 317 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index e8a3abd35..2b29e31c0 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -893,57 +893,32 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # LimitNewCapacity if self.table_exists('LimitNewCapacity'): raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech_or_group, operator, new_cap FROM main.LimitNewCapacity') - load_element(M.LimitNewCapacity, raw)#, self.viable_rt, (0, 2)) - - # # LimitCapacityGroup - # if self.table_exists('LimitCapacityGroup'): - # raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, operator, capacity FROM main.LimitCapacityGroup') - # load_element(M.LimitCapacityGroup, raw) - - # # LimitNewCapacityGroup - # if self.table_exists('LimitNewCapacityGroup'): - # raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, operator, new_cap FROM main.LimitNewCapacityGroup') - # load_element(M.LimitNewCapacityGroup, raw) + load_element(M.LimitNewCapacity, raw) # LimitCapacityShare if self.table_exists('LimitCapacityShare'): raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitCapacityShare') - load_element(M.LimitCapacityShare, raw)#, self.viable_rt, (0, 2)) + load_element(M.LimitCapacityShare, raw) # LimitNewCapacityShare if self.table_exists('LimitNewCapacityShare'): raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitNewCapacityShare') - load_element(M.LimitNewCapacityShare, raw)#, self.viable_rt, (0, 2)) - - # # LimitNewCapacityGroupShare - # if self.table_exists('LimitNewCapacityGroupShare'): - # raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitNewCapacityGroupShare') - # load_element(M.LimitNewCapacityGroupShare, raw) - - # # LimitActivityGroupShare - # if self.table_exists('LimitActivityGroupShare'): - # raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitActivityGroupShare') - # load_element(M.LimitActivityGroupShare, raw) - - # # LimitActivityGroup - # if self.table_exists('LimitActivityGroup'): - # raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, group_name, operator, activity FROM main.LimitActivityGroup') - # load_element(M.LimitActivityGroup, raw) + load_element(M.LimitNewCapacityShare, raw) # LimitActivityShare if self.table_exists('LimitActivityShare'): raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitActivityShare') - load_element(M.LimitActivityShare, raw)#, self.viable_rt, (0, 2)) + load_element(M.LimitActivityShare, raw) # LimitResource if self.table_exists('LimitResource'): raw = cur.execute('SELECT region, tech_or_group, operator, cum_act FROM main.LimitResource').fetchall() - load_element(M.LimitResource, raw)#, self.viable_rt, (0, 1)) + load_element(M.LimitResource, raw) # LimitActivity if self.table_exists('LimitActivity'): raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech_or_group, operator, activity FROM main.LimitActivity') - load_element(M.LimitActivity, raw)#, self.viable_rt, (0, 2)) + load_element(M.LimitActivity, raw) # LimitSeasonalCapacityFactor if self.table_exists('LimitSeasonalCapacityFactor'): @@ -959,37 +934,37 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N if self.table_exists('LimitGrowthCapacity'): raw = cur.execute('SELECT region, tech_or_group, operator, rate, seed FROM main.LimitGrowthCapacity').fetchall() raw = self.tuple_values(raw, 3) - load_element(M.LimitGrowthCapacity, raw)#, self.viable_rt, (0, 1)) + load_element(M.LimitGrowthCapacity, raw) # LimitDegrowthCapacity if self.table_exists('LimitDegrowthCapacity'): raw = cur.execute('SELECT region, tech_or_group, operator, rate, seed FROM main.LimitDegrowthCapacity').fetchall() raw = self.tuple_values(raw, 3) - load_element(M.LimitDegrowthCapacity, raw)#, self.viable_rt, (0, 1)) + load_element(M.LimitDegrowthCapacity, raw) # LimitGrowthNewCapacity if self.table_exists('LimitGrowthNewCapacity'): raw = cur.execute('SELECT region, tech_or_group, operator, rate, seed FROM main.LimitGrowthNewCapacity').fetchall() raw = self.tuple_values(raw, 3) - load_element(M.LimitGrowthNewCapacity, raw)#, self.viable_rt, (0, 1)) + load_element(M.LimitGrowthNewCapacity, raw) # LimitDegrowthNewCapacity if self.table_exists('LimitDegrowthNewCapacity'): raw = cur.execute('SELECT region, tech_or_group, operator, rate, seed FROM main.LimitDegrowthNewCapacity').fetchall() raw = self.tuple_values(raw, 3) - load_element(M.LimitDegrowthNewCapacity, raw)#, self.viable_rt, (0, 1)) + load_element(M.LimitDegrowthNewCapacity, raw) # LimitGrowthNewCapacityDelta if self.table_exists('LimitGrowthNewCapacityDelta'): raw = cur.execute('SELECT region, tech_or_group, operator, rate, seed FROM main.LimitGrowthNewCapacityDelta').fetchall() raw = self.tuple_values(raw, 3) - load_element(M.LimitGrowthNewCapacityDelta, raw)#, self.viable_rt, (0, 1)) + load_element(M.LimitGrowthNewCapacityDelta, raw) # LimitDegrowthNewCapacityDelta if self.table_exists('LimitDegrowthNewCapacityDelta'): raw = cur.execute('SELECT region, tech_or_group, operator, rate, seed FROM main.LimitDegrowthNewCapacityDelta').fetchall() raw = self.tuple_values(raw, 3) - load_element(M.LimitDegrowthNewCapacityDelta, raw)#, self.viable_rt, (0, 1)) + load_element(M.LimitDegrowthNewCapacityDelta, raw) # LimitEmission if self.table_exists('LimitEmission'): diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 366a81db2..bb9bff1ea 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -287,7 +287,7 @@ def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): # If it naturally retires at the beginning of or during this period, all capacity minus already retired l = value(M.LifetimeProcess[r, t, v]) - if v+l == p or value(M.ModelProcessLife[r, p, t, v]) < value(M.PeriodLength[p]): + if v+l == p or value(M.ProcessLifeFrac[r, p, t, v]) < 1.0: if v in M.time_optimize: retired = M.V_NewCapacity[r, t, v] - already_retired elif v in M.time_exist: @@ -2498,191 +2498,6 @@ def LimitActivity_Constraint(M: 'TemoaModel', r, p, t, op): return expr -# devnote: this constraint did not translate well between representative periods -# and seasonal time slicing paradigms. It was replaced with the LimitSeasonalCapacityFactor -# constraint, which works well in either paradigm and pairs with LimitAnnualCapacityFactor -# def LimitSeasonalActivity_Constraint(M: 'TemoaModel', r, p, s, t, op): - -# r""" -# Sets a limit on the activity of a specific technology in a season. -# Note that the indices for these constraints are region, period, season, and tech. -# The first component of the constraint pertains to technologies with -# variable output at the time slice level, and the second component pertains to -# technologies with constant annual output belonging to the :code:`tech_annual` -# set. -# .. math:: -# :label: LimitSeasonalActivity -# \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMSSNACT_{r, p, s, t} -# \forall \{r, p, s, t\} \in \Theta_{\text{LimitSeasonalActivity}} -# \sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \le LIMSSNACT_{r, p, s, t} -# \forall \{r, p, s, t \in T^{a}\} \in \Theta_{\text{LimitSeasonalActivity}} -# """ - -# # Notice that this constraint follows the implementation of the -# # LimitActivity_Constraint(). The difference is that this function is defined -# # over each "season" as opposed to the entire year, or "period" - -# # The V_FlowOut variable is scaled by the weights of each season. -# # In order to determine the daily flow, the V_FlowOut variable -# # must be converted back to its un-scaled value. We do this by dividing the -# # V_FlowOut value by M.SegFracPerSeason[p, s, d] * M.DaysPerPeriod (how many days are in this season). - -# regions = gather_group_regions(M, r) - -# try: -# activity_rpst = sum( -# M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] / (value(M.SegFracPerSeason[p, s, d]) * M.DaysPerPeriod) -# for _r in regions -# 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 d in M.time_of_day -# ) -# except: -# msg = ( -# "\nWarning: LimitSeasonalActivity constraint cannot be defined for " -# "technologies in \"tech_annual\". Continuing by ignoring the constraint " -# "for '%s'.\n " -# ) -# SE.write(msg % (t)) -# return Constraint.Skip - -# act_lim = value(M.LimitSeasonalActivity[r, p, s, t, op]) -# expr = operator_expression(activity_rpst, op, act_lim) - -# # in the case that there is nothing to sum, skip -# if isinstance(expr, bool): # an empty list was generated -# return Constraint.Skip - -# return expr - - -# devnote: deprecated when generalising tech/group columns in Limit tables -# def LimitActivityGroup_Constraint(M: 'TemoaModel', r, p, g, op): -# r""" -# The LimitActivityGroup constraint sets an activity limit for a user-defined -# technology group. -# .. math:: -# :label: LimitActivityGroup -# \sum_{R,S,D,I,T,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} + \sum_{I,T,V,O} -# \textbf{FOA}_{r, p, i, t, v, o} -# \le MxAG_{r, p, g} -# \forall \{r, p, g\} \in \Theta_{\text{LimitActivityGroup}} -# where :math:`g` represents the assigned technology group and :math:`MxAG` -# refers to the :code:`LimitActivityGroup` parameter.""" - -# regions = gather_group_regions(M, r) - -# activity_p = 0 -# activity_p_annual = 0 -# for _r in regions: -# activity_p += sum( -# M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] -# for S_t in M.tech_group_members[g] -# if (_r, p, S_t) in M.processVintages and S_t not in M.tech_annual -# for S_v in M.processVintages[_r, p, S_t] -# for S_i in M.processInputs[_r, p, S_t, S_v] -# for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] -# for s in M.time_season[p] -# for d in M.time_of_day -# if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut -# ) -# activity_p_annual += sum( -# M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] -# for S_t in M.tech_group_members[g] -# if (_r, p, S_t) in M.processVintages and S_t in M.tech_annual -# for S_v in M.processVintages[_r, p, S_t] -# for S_i in M.processInputs[_r, p, S_t, S_v] -# for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] -# if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual -# ) - -# act_lim = value(M.LimitActivityGroup[r, p, g, op]) -# expr = operator_expression(activity_p + activity_p_annual, op, act_lim) -# # in the case that there is nothing to sum, skip -# if isinstance(expr, bool): # an empty list was generated -# logger.warning( -# 'Missing group techs to support LimitActivityGroup constraint: %s.' -# ' Check data/log for available/suppressed techs. Constraint ignored.', -# (r, p, g) -# ) -# return Constraint.Skip -# return expr - - -# devnote: deprecated when generalising tech/group columns in Limit tables -# def LimitActivityGroupShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): -# r""" -# The LimitActivityGroup constraint sets an activity limit for a user-defined -# technology group. -# .. math:: -# :label: LimitActivityGroup -# \sum_{R,S,D,I,T,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} + \sum_{I,T,V,O} -# \textbf{FOA}_{r, p, i, t, v, o} -# \le MxAG_{r, p, g} -# \forall \{r, p, g\} \in \Theta_{\text{LimitActivityGroup}} -# where :math:`g` represents the assigned technology group and :math:`MxAG` -# refers to the :code:`LimitActivityGroup` parameter.""" - -# regions = gather_group_regions(M, r) - -# activity_g1 = 0 -# activity_g2 = 0 -# for _r in regions: -# activity_g1 += sum( -# M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] -# for S_t in M.tech_group_members[g1] -# if (_r, p, S_t) in M.processVintages and S_t not in M.tech_annual -# for S_v in M.processVintages[_r, p, S_t] -# for S_i in M.processInputs[_r, p, S_t, S_v] -# for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] -# for s in M.time_season[p] -# for d in M.time_of_day -# if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut -# ) -# activity_g1 += sum( -# M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] -# for S_t in M.tech_group_members[g1] -# if (_r, p, S_t) in M.processVintages and S_t in M.tech_annual -# for S_v in M.processVintages[_r, p, S_t] -# for S_i in M.processInputs[_r, p, S_t, S_v] -# for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] -# if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual -# ) -# activity_g2 += sum( -# M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] -# for S_t in M.tech_group_members[g2] -# if (_r, p, S_t) in M.processVintages and S_t not in M.tech_annual -# for S_v in M.processVintages[_r, p, S_t] -# for S_i in M.processInputs[_r, p, S_t, S_v] -# for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] -# for s in M.time_season[p] -# for d in M.time_of_day -# if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut -# ) -# activity_g2 += sum( -# M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] -# for S_t in M.tech_group_members[g2] -# if (_r, p, S_t) in M.processVintages and S_t in M.tech_annual -# for S_v in M.processVintages[_r, p, S_t] -# for S_i in M.processInputs[_r, p, S_t, S_v] -# for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] -# if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual -# ) - -# share_lim = value(M.LimitActivityGroupShare[r, p, g1, g2, op]) -# expr = operator_expression(activity_g1, op, share_lim * activity_g2) -# # in the case that there is nothing to sum, skip -# if isinstance(expr, bool): # an empty list was generated -# logger.warning( -# 'Missing group techs to support LimitActivityGroupShare constraint: %s.' -# ' Check data/log for available/suppressed techs. Constraint ignored.', -# (r, p, g1, g2) -# ) -# return Constraint.Skip -# return expr - - def LimitNewCapacity_Constraint(M: 'TemoaModel', r, p, t, op): r""" The LimitNewCapacity constraint sets a limit on the newly installed capacity of a @@ -2741,10 +2556,6 @@ def LimitResource_Constraint(M: 'TemoaModel', r, t, op): \sum_{P} \textbf{CAPAVL}_{r, p, t} \le MAR_{r, t} \forall \{r, t\} \in \Theta_{\text{LimitCapacity}}""" - # logger.warning( - # 'The LimitResource constraint is not currently supported in the model, pending review. Recommend ' - # 'removing data from the LimitResource Table' - # ) # dev note: this constraint is a misnomer. It is actually a "global activity constraint on a tech" # regardless of whatever "resources" are consumed. # dev note: this would generally be applied to a "dummy import" technology to restrict something like @@ -2781,61 +2592,6 @@ def LimitResource_Constraint(M: 'TemoaModel', r, t, op): return expr -# devnote: deprecated when generalising tech/group columns in Limit tables -# def LimitCapacityGroup_Constraint(M: 'TemoaModel', r, p, g, op): -# r""" -# Similar to the :code:`LimitCapacity` constraint, but works on a group of technologies. -# """ -# regions = gather_group_regions(M, r) - -# cap_lim = value(M.LimitCapacityGroup[r, p, g, op]) - -# cap = sum( -# M.V_CapacityAvailableByPeriodAndTech[_r, p, t] -# for t in M.tech_group_members[g] -# for _r in regions -# if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech -# ) - -# expr = operator_expression(cap, op, cap_lim) -# # in the case that there is nothing to sum, skip -# if isinstance(expr, bool): # an empty list was generated -# logger.error( -# 'No elements available to support LimitCapacityGroup: %s.' -# ' Check data/log for available/suppressed techs. Constraint ignored.', -# (r, p, g) -# ) -# return Constraint.Skip -# return expr - - -# devnote: deprecated when generalising tech/group columns in Limit tables -# def LimitNewCapacityGroup_Constraint(M: 'TemoaModel', r, p, g, op): -# r""" -# Similar to the :code:`LimitNewCapacity` constraint, but works on a group of technologies.""" - -# regions = gather_group_regions(M, r) - -# new_cap_lim = value(M.LimitNewCapacityGroup[r, p, g, op]) -# agg_new_cap = sum( -# M.V_NewCapacity[_r, t, p] -# for t in M.tech_group_members[g] -# for _r in regions -# if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech -# ) -# expr = operator_expression(agg_new_cap, op, new_cap_lim) -# if isinstance(expr, bool): -# logger.error( -# 'No elements available to support LimitNewCapacityGroup: (%s, %d, %s).' -# ' Check data/log for available/suppressed techs. Requirement IGNORED.', -# r, -# p, -# g, -# ) -# return Constraint.Skip -# return expr - - def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): r""" The LimitActivityShare constraint limits the activity share for a given @@ -2969,41 +2725,6 @@ def LimitNewCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): return expr -# devnote: deprecated when generalising tech/group columns in Limit tables -# def LimitNewCapacityGroupShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): -# r""" -# Limits the aggregate capacity of one group of technologies as a share of -# another group of technologies. -# """ - -# regions = gather_group_regions(M, r) - -# share_lim = value(M.LimitNewCapacityGroupShare[r, p, g1, g2, op]) -# agg_new_cap_g1 = sum( -# M.V_NewCapacity[_r, t, p] -# for t in M.tech_group_members[g1] -# for _r in regions -# if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech -# ) -# agg_new_cap_g2 = sum( -# M.V_NewCapacity[_r, t, p] -# for t in M.tech_group_members[g2] -# for _r in regions -# if (_r, p, t) in M.V_CapacityAvailableByPeriodAndTech -# ) -# expr = operator_expression(agg_new_cap_g1, op, agg_new_cap_g2 * share_lim) - -# if isinstance(expr, bool): # one side of expression was empty -# logger.error( -# 'Missing group techs to support LimitNewCapacityGroupShare constraint: %s.' -# ' Check data/log for available/suppressed techs. Constraint ignored.', -# (r, p, g1, g2) -# ) -# return Constraint.Skip - -# return expr - - def LimitAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o, op): r""" The LimitAnnualCapacityFactor sets an upper bound on the annual capacity factor From 9d7a2abda97a4d6476a85b06ecdef3807ca26f90 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Jun 2025 11:55:37 -0400 Subject: [PATCH 124/587] Block early retirement in the period the tech naturally retires --- temoa/temoa_model/temoa_initialize.py | 10 +++++----- temoa/temoa_model/temoa_model.py | 4 +++- temoa/temoa_model/temoa_rules.py | 4 +++- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 7017ddbb8..24b57b604 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -791,10 +791,10 @@ def CreateSparseDicts(M: 'TemoaModel'): # Get all periods where the process can retire if t not in M.tech_uncap and any(( - p==v and l_lifetime v and t not in M.tech_uncap + if v < p <= v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[p]) ) diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index f9587e622..e839b9d76 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -211,7 +211,9 @@ def __init__(M, *args, **kwargs): # Define techs for which economic retirement is an option # Note: Storage techs cannot (currently) be retired due to linkage to initialization # process, which is currently incapable of reducing initializations on retirements. - M.tech_retirement = Set(within=M.tech_all - M.tech_storage) + # Note2: I think this has been fixed but I can't tell what the problem was. Suspect + # it was the old StorageInit constraint + M.tech_retirement = Set(within=M.tech_with_capacity)# - M.tech_storage) M.validate_techs = BuildAction(rule=validate_tech_sets) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index bb9bff1ea..090c6a20f 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -58,7 +58,9 @@ def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): else: retired_cap = sum( - M.V_RetiredCapacity[r, S_p, t, v] for S_p in M.time_optimize if p >= S_p > v + M.V_RetiredCapacity[r, S_p, t, v] + for S_p in M.time_optimize + if v < S_p <= p and S_p < v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[S_p]) ) if v in M.time_exist: return M.V_Capacity[r, p, t, v] == value(M.ExistingCapacity[r, t, v]) - retired_cap From 49580b2384392bf35f0f88eee7e1afe3eda292d9 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Jun 2025 12:04:21 -0400 Subject: [PATCH 125/587] Clean up some little things --- data_files/example_dbs/materials.sql | 2 +- data_files/example_dbs/morris_utopia.sql | 4 ++-- data_files/example_dbs/seasonal_storage.sql | 2 +- data_files/example_dbs/stepped_demand.sql | 2 +- data_files/example_dbs/test_system.sql | 2 +- data_files/example_dbs/utopia.sql | 2 +- data_files/temoa_schema_v3_1.sql | 2 +- temoa/temoa_model/temoa_initialize.py | 4 +--- tests/testing_data/emissions.sql | 2 +- tests/testing_data/materials.sql | 2 +- tests/testing_data/mediumville.sql | 2 +- tests/testing_data/seasonal_storage.sql | 2 +- tests/testing_data/simple_linked_tech.sql | 2 +- tests/testing_data/storageville.sql | 2 +- tests/testing_data/test_system.sql | 2 +- tests/testing_data/utopia.sql | 2 +- 16 files changed, 17 insertions(+), 19 deletions(-) diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index 74d1ad1d0..ad970c5c9 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -1448,7 +1448,7 @@ CREATE TABLE TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count NUMERIC NOT NULL, + count REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index 16e5cd184..45fddee12 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -1303,7 +1303,7 @@ CREATE TABLE PlanningReserveMargin REFERENCES Region (region), margin REAL ); -CREATE TABLE RampDownHourly +CREATE TABLE RampDown ( region TEXT, tech TEXT @@ -1425,7 +1425,7 @@ CREATE TABLE TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count NUMERIC NOT NULL, + count REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql index 3af77d8e2..fb12a486b 100644 --- a/data_files/example_dbs/seasonal_storage.sql +++ b/data_files/example_dbs/seasonal_storage.sql @@ -1033,7 +1033,7 @@ CREATE TABLE TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count NUMERIC NOT NULL, + count REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index a59e97284..7a190177b 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -1189,7 +1189,7 @@ CREATE TABLE TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count NUMERIC NOT NULL, + count REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index 04a9b0848..014661f33 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -1438,7 +1438,7 @@ CREATE TABLE TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count NUMERIC NOT NULL, + count REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index fe6ce9bea..edccba130 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -1420,7 +1420,7 @@ CREATE TABLE TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count NUMERIC NOT NULL, + count REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index 9da9fd398..7736e4530 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -928,7 +928,7 @@ CREATE TABLE IF NOT EXISTS TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count NUMERIC NOT NULL, + count REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 24b57b604..d295e9a98 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -791,9 +791,7 @@ def CreateSparseDicts(M: 'TemoaModel'): # Get all periods where the process can retire if t not in M.tech_uncap and any(( - p==v and l_lifetime < value(M.PeriodLength[p]), # eol the period it is constructed - p==v+l_lifetime, # natural eol at start of this period - (p < v+l_lifetime < p + value(M.PeriodLength[p])), # eol mid-period + (p <= v+l_lifetime < p + value(M.PeriodLength[p])), # natural eol this period t in M.tech_retirement and v < p <= v+l_lifetime - value(M.PeriodLength[p]), # allowed early retirement )): if (r, t, v) not in M.retirementPeriods: diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 453d42d0b..cf8b86656 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -961,7 +961,7 @@ CREATE TABLE TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count NUMERIC NOT NULL, + count REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index 74d1ad1d0..ad970c5c9 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -1448,7 +1448,7 @@ CREATE TABLE TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count NUMERIC NOT NULL, + count REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index c32366cfe..39c59269c 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -1037,7 +1037,7 @@ CREATE TABLE TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count NUMERIC NOT NULL, + count REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index 3af77d8e2..fb12a486b 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -1033,7 +1033,7 @@ CREATE TABLE TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count NUMERIC NOT NULL, + count REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index 1ecff1002..b6c94e727 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -930,7 +930,7 @@ CREATE TABLE TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count NUMERIC NOT NULL, + count REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index 43450bc5b..f26880e10 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -955,7 +955,7 @@ CREATE TABLE TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count NUMERIC NOT NULL, + count REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 04a9b0848..014661f33 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -1438,7 +1438,7 @@ CREATE TABLE TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count NUMERIC NOT NULL, + count REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index fe6ce9bea..edccba130 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -1420,7 +1420,7 @@ CREATE TABLE TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count NUMERIC NOT NULL, + count REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (count > 0) From 76305746cfbc0d74b7a6edce08a37b967ac914d7 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Jun 2025 12:21:41 -0400 Subject: [PATCH 126/587] Split end of life from early retirement in OutputRetirement --- data_files/example_dbs/materials.sql | 3 ++- data_files/example_dbs/morris_utopia.sql | 3 ++- data_files/example_dbs/seasonal_storage.sql | 3 ++- data_files/example_dbs/stepped_demand.sql | 3 ++- data_files/example_dbs/test_system.sql | 3 ++- data_files/example_dbs/utopia.sql | 3 ++- data_files/temoa_schema_v3_1.sql | 3 ++- temoa/temoa_model/table_data_puller.py | 13 ++++++++++--- temoa/temoa_model/table_writer.py | 7 ++++--- tests/testing_data/emissions.sql | 3 ++- tests/testing_data/materials.sql | 3 ++- tests/testing_data/mediumville.sql | 3 ++- tests/testing_data/seasonal_storage.sql | 3 ++- tests/testing_data/simple_linked_tech.sql | 3 ++- tests/testing_data/storageville.sql | 3 ++- tests/testing_data/test_system.sql | 3 ++- tests/testing_data/utopia.sql | 3 ++- 17 files changed, 44 insertions(+), 21 deletions(-) diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index ad970c5c9..b582bb7a2 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -1215,7 +1215,8 @@ CREATE TABLE OutputRetiredCapacity REFERENCES Technology (tech), vintage INTEGER REFERENCES TimePeriod (period), - capacity REAL, + cap_eol REAL, + cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); CREATE TABLE OutputFlowIn diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index 45fddee12..7be30d0a7 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -1228,7 +1228,8 @@ CREATE TABLE OutputRetiredCapacity REFERENCES Technology (tech), vintage INTEGER REFERENCES TimePeriod (period), - capacity REAL, + cap_eol REAL, + cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); CREATE TABLE OutputFlowIn diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql index fb12a486b..bbd32562a 100644 --- a/data_files/example_dbs/seasonal_storage.sql +++ b/data_files/example_dbs/seasonal_storage.sql @@ -769,7 +769,8 @@ CREATE TABLE OutputRetiredCapacity REFERENCES Technology (tech), vintage INTEGER REFERENCES TimePeriod (period), - capacity REAL, + cap_eol REAL, + cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); CREATE TABLE OutputFlowIn diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index 7a190177b..580750d23 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -948,7 +948,8 @@ CREATE TABLE OutputRetiredCapacity REFERENCES Technology (tech), vintage INTEGER REFERENCES TimePeriod (period), - capacity REAL, + cap_eol REAL, + cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); CREATE TABLE OutputFlowIn diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index 014661f33..78e5d6b47 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -1231,7 +1231,8 @@ CREATE TABLE OutputRetiredCapacity REFERENCES Technology (tech), vintage INTEGER REFERENCES TimePeriod (period), - capacity REAL, + cap_eol REAL, + cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); CREATE TABLE OutputFlowIn diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index edccba130..43ec455d7 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -1223,7 +1223,8 @@ CREATE TABLE OutputRetiredCapacity REFERENCES Technology (tech), vintage INTEGER REFERENCES TimePeriod (period), - capacity REAL, + cap_eol REAL, + cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); CREATE TABLE OutputFlowIn diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index 7736e4530..cea7f4e7f 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -750,7 +750,8 @@ CREATE TABLE IF NOT EXISTS OutputRetiredCapacity REFERENCES Technology (tech), vintage INTEGER REFERENCES TimePeriod (period), - capacity REAL, + cap_eol REAL, + cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); CREATE TABLE IF NOT EXISTS OutputFlowIn diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index 293d040f2..16ad0fb2e 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -116,12 +116,19 @@ def poll_capacity_results(M: TemoaModel, epsilon=1e-5) -> CapData: # Retired Capacity ret = [] for r, t, v in M.retirementPeriods: + lifetime = value(M.LifetimeProcess[r, t, v]) for p in M.retirementPeriods[r, t, v]: # We want to output period retirement, not annual retirement, so multiply by PeriodLength - val = value(M.PeriodLength[p]) * value(M.V_AnnualRetirement[r, p, t, v]) - if abs(val) < epsilon: + eol = value(M.PeriodLength[p]) * value(M.V_AnnualRetirement[r, p, t, v]) + early = 0 + if t in M.tech_retirement and v < p <= v + lifetime - value(M.PeriodLength[p]): + early = value(M.V_RetiredCapacity[r, p, t, v]) + eol -= early + early = 0 if abs(early) < epsilon else early + eol = 0 if abs(eol) < epsilon else eol + if early == 0 and eol == 0: continue - new_retired_cap = (r, p, t, v, val) + new_retired_cap = (r, p, t, v, eol, early) ret.append(new_retired_cap) return CapData(built=built, net=net, retired=ret) diff --git a/temoa/temoa_model/table_writer.py b/temoa/temoa_model/table_writer.py index 81d7ba632..94e088299 100644 --- a/temoa/temoa_model/table_writer.py +++ b/temoa/temoa_model/table_writer.py @@ -317,6 +317,7 @@ def _insert_capacity_results(self, cap_data: CapData, iteration: int | None) -> scenario = self.config.scenario if iteration is not None: scenario = scenario + f'-{iteration}' + # Built Capacity data = [] for r, t, v, val in cap_data.built: @@ -337,11 +338,11 @@ def _insert_capacity_results(self, cap_data: CapData, iteration: int | None) -> # Retired Capacity data = [] - for r, p, t, v, val in cap_data.retired: + for r, p, t, v, eol, early in cap_data.retired: s = self.tech_sectors.get(t) - new_retired_cap = (scenario, r, s, p, t, v, val) + new_retired_cap = (scenario, r, s, p, t, v, eol, early) data.append(new_retired_cap) - qry = 'INSERT INTO OutputRetiredCapacity VALUES (?, ?, ?, ?, ?, ?, ?)' + qry = 'INSERT INTO OutputRetiredCapacity VALUES (?, ?, ?, ?, ?, ?, ?, ?)' self.con.executemany(qry, data) self.con.commit() diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index cf8b86656..6dd835255 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -788,7 +788,8 @@ CREATE TABLE OutputRetiredCapacity REFERENCES Technology (tech), vintage INTEGER REFERENCES TimePeriod (period), - capacity REAL, + cap_eol REAL, + cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); CREATE TABLE OutputFlowIn diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index ad970c5c9..b582bb7a2 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -1215,7 +1215,8 @@ CREATE TABLE OutputRetiredCapacity REFERENCES Technology (tech), vintage INTEGER REFERENCES TimePeriod (period), - capacity REAL, + cap_eol REAL, + cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); CREATE TABLE OutputFlowIn diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 39c59269c..6db7897ae 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -858,7 +858,8 @@ CREATE TABLE OutputRetiredCapacity REFERENCES Technology (tech), vintage INTEGER REFERENCES TimePeriod (period), - capacity REAL, + cap_eol REAL, + cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); CREATE TABLE OutputFlowIn diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index fb12a486b..bbd32562a 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -769,7 +769,8 @@ CREATE TABLE OutputRetiredCapacity REFERENCES Technology (tech), vintage INTEGER REFERENCES TimePeriod (period), - capacity REAL, + cap_eol REAL, + cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); CREATE TABLE OutputFlowIn diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index b6c94e727..495682bbe 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -761,7 +761,8 @@ CREATE TABLE OutputRetiredCapacity REFERENCES Technology (tech), vintage INTEGER REFERENCES TimePeriod (period), - capacity REAL, + cap_eol REAL, + cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); CREATE TABLE OutputFlowIn diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index f26880e10..69430f763 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -773,7 +773,8 @@ CREATE TABLE OutputRetiredCapacity REFERENCES Technology (tech), vintage INTEGER REFERENCES TimePeriod (period), - capacity REAL, + cap_eol REAL, + cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); CREATE TABLE OutputFlowIn diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 014661f33..78e5d6b47 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -1231,7 +1231,8 @@ CREATE TABLE OutputRetiredCapacity REFERENCES Technology (tech), vintage INTEGER REFERENCES TimePeriod (period), - capacity REAL, + cap_eol REAL, + cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); CREATE TABLE OutputFlowIn diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index edccba130..43ec455d7 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -1223,7 +1223,8 @@ CREATE TABLE OutputRetiredCapacity REFERENCES Technology (tech), vintage INTEGER REFERENCES TimePeriod (period), - capacity REAL, + cap_eol REAL, + cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); CREATE TABLE OutputFlowIn From 027806ded3ef2307d494f5821b35d5c0e4a1f721 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Jun 2025 13:38:17 -0400 Subject: [PATCH 127/587] Move PLF adjustment inside V_Capacity and clean up --- .../model_checking/network_model_data.py | 6 ++-- temoa/temoa_model/table_data_puller.py | 2 +- temoa/temoa_model/temoa_initialize.py | 2 +- temoa/temoa_model/temoa_model.py | 7 ++-- temoa/temoa_model/temoa_rules.py | 35 +++++++------------ 5 files changed, 20 insertions(+), 32 deletions(-) diff --git a/temoa/temoa_model/model_checking/network_model_data.py b/temoa/temoa_model/model_checking/network_model_data.py index ba9f86ea4..cc2856bcd 100644 --- a/temoa/temoa_model/model_checking/network_model_data.py +++ b/temoa/temoa_model/model_checking/network_model_data.py @@ -272,10 +272,8 @@ def _build_from_db( # End of life output if any(( - p==v and lifetime= useful_activity ) @@ -171,7 +169,6 @@ def CapacityAnnual_Constraint(M: 'TemoaModel', r, p, t, v): return ( CF * value(M.CapacityToActivity[r, t]) - * value(M.ProcessLifeFrac[r, p, t, v]) * M.V_Capacity[r, p, t, v] >= activity_rptv ) @@ -240,7 +237,7 @@ def CapacityAvailableByPeriodAndTech_Constraint(M: 'TemoaModel', r, p, t): \forall p \in \text{P}^o, r \in R, t \in T """ cap_avail = sum( - value(M.ProcessLifeFrac[r, p, t, S_v]) * M.V_Capacity[r, p, t, S_v] + M.V_Capacity[r, p, t, S_v] for S_v in M.processVintages[r, p, t] ) @@ -248,6 +245,8 @@ def CapacityAvailableByPeriodAndTech_Constraint(M: 'TemoaModel', r, p, t): return expr +# devnote: I don't think this constraint is necessary as if this were violated +# then V_Capacity would be negative, which isn't allowed anyway def RetiredCapacity_Constraint(M: 'TemoaModel', r, p, t, v): r""" @@ -535,7 +534,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): fixed_costs = sum( fixed_or_variable_cost( - M.V_Capacity[r, p, S_t, S_v], + M.V_Capacity[r, p, S_t, S_v] / value(M.ProcessLifeFrac[r, p, S_t, S_v]), value(M.CostFixed[r, p, S_t, S_v]), value(MPL[r, p, S_t, S_v]), GDR, @@ -1375,7 +1374,6 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): * value(M.CapacityToActivity[r, t]) * (value(M.StorageDuration[r, t]) / (24 * value(M.DaysPerPeriod))) * value(M.SegFracPerSeason[p, s]) * M.DaysPerPeriod # adjust for days in season - * value(M.ProcessLifeFrac[r, p, t, v]) ) expr = M.V_StorageLevel[r, p, s, d, t, v] <= energy_capacity @@ -1406,7 +1404,6 @@ def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_seq, d, M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * (value(M.StorageDuration[r, t]) / (24 * value(M.DaysPerPeriod))) - * value(M.ProcessLifeFrac[r, p, t, v]) ) # Flows and StorageLevel are normalised to the number of days in the non-sequential season, so must @@ -1451,7 +1448,6 @@ def StorageChargeRate_Constraint(M: 'TemoaModel', r, p, s, d, t, v): M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[p, s, d]) - * value(M.ProcessLifeFrac[r, p, t, v]) ) # Energy charge cannot exceed the power capacity of the storage unit @@ -1488,7 +1484,6 @@ def StorageDischargeRate_Constraint(M: 'TemoaModel', r, p, s, d, t, v): M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[p, s, d]) - * value(M.ProcessLifeFrac[r, p, t, v]) ) # Energy discharge cannot exceed the capacity of the storage unit @@ -1533,7 +1528,6 @@ def StorageThroughput_Constraint(M: 'TemoaModel', r, p, s, d, t, v): M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[p, s, d]) - * value(M.ProcessLifeFrac[r, p, t, v]) ) expr = throughput <= max_throughput return expr @@ -1570,7 +1564,6 @@ def LimitStorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v, op): M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * (value(M.StorageDuration[r, t]) / (24 * value(M.DaysPerPeriod))) - * value(M.ProcessLifeFrac[r, p, t, v]) * value(M.LimitStorageFraction[r, p, s, d, t, v, op]) ) @@ -1671,7 +1664,7 @@ def RampUpDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): return Constraint.Skip activity_increase = hourly_activity_sd_next - hourly_activity_sd # opposite sign from rampdown - rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.ProcessLifeFrac[r, p, t, v]) + rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) expr = activity_increase <= rampable_activity return expr @@ -1736,7 +1729,7 @@ def RampDownDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): return Constraint.Skip activity_decrease = hourly_activity_sd - hourly_activity_sd_next # opposite sign from rampup - rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.ProcessLifeFrac[r, p, t, v]) + rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) expr = activity_decrease <= rampable_activity return expr @@ -1784,7 +1777,7 @@ def RampUpSeason_Constraint(M: 'TemoaModel', r, p, s_seq, d, t, v): return Constraint.Skip activity_increase = hourly_activity_sd_next - hourly_activity_sd # opposite sign from rampdown - rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.ProcessLifeFrac[r, p, t, v]) + rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) expr = activity_increase <= rampable_activity return expr @@ -1832,7 +1825,7 @@ def RampDownSeason_Constraint(M: 'TemoaModel', r, p, s_seq, d, t, v): return Constraint.Skip activity_decrease = hourly_activity_sd - hourly_activity_sd_next # opposite sign from rampup - rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.ProcessLifeFrac[r, p, t, v]) + rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) expr = activity_decrease <= rampable_activity return expr @@ -1933,7 +1926,6 @@ def ReserveMarginStatic(M: 'TemoaModel', r, p, s, d): available = sum( value(M.CapacityCredit[r, p, t, v]) - * value(M.ProcessLifeFrac[r, p, t, v]) * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[p, s, d]) @@ -1964,7 +1956,6 @@ def ReserveMarginStatic(M: 'TemoaModel', r, p, s, d): # add the available capacity of the exchange tech. available += sum( value(M.CapacityCredit[r1r2, p, t, v]) - * value(M.ProcessLifeFrac[r1r2, p, t, v]) * M.V_Capacity[r1r2, p, t, v] * value(M.CapacityToActivity[r1r2, t]) * value(M.SegFrac[p, s, d]) @@ -1991,7 +1982,6 @@ def ReserveMarginDynamic(M: 'TemoaModel', r, p, s, d): available = sum( M.V_Capacity[r, p, t, v] * value(M.CapacityCredit[r, p, t, v]) - * value(M.ProcessLifeFrac[r, p, t, v]) * value(M.CapacityFactorProcess[r, p, s, d, t, v]) * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[p, s, d]) @@ -2042,7 +2032,6 @@ def ReserveMarginDynamic(M: 'TemoaModel', r, p, s, d): available += sum( M.V_Capacity[r1r2, p, t, v] * value(M.CapacityCredit[r1r2, p, t, v]) - * value(M.ProcessLifeFrac[r1r2, p, t, v]) * value(M.CapacityFactorProcess[r, p, s, d, t, v]) * value(M.CapacityToActivity[r1r2, t]) * value(M.SegFrac[p, s, d]) From 90471e37efc36c34fbb031a28f8681f30e39ec70 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Jun 2025 18:02:23 -0400 Subject: [PATCH 128/587] Fix AnnualRetirement --- temoa/temoa_model/temoa_rules.py | 41 ++++++++++++++++---------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 39ebd7f61..94668e227 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -278,27 +278,28 @@ def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): is evenly distributed over the model period, in the same way we assume capacity is deployed evenly over the model period. """ - - # Need to know what already (before period p) retired economically so we don't double count - already_retired = 0 - if t in M.tech_retirement: - already_retired = sum( - M.V_RetiredCapacity[r, S_p, t, v] for S_p in M.time_optimize if v < S_p < p - ) - - # If it naturally retires at the beginning of or during this period, all capacity minus already retired - l = value(M.LifetimeProcess[r, t, v]) - if v+l == p or value(M.ProcessLifeFrac[r, p, t, v]) < 1.0: - if v in M.time_optimize: - retired = M.V_NewCapacity[r, t, v] - already_retired - elif v in M.time_exist: - retired = M.ExistingCapacity[r, t, v] - already_retired - # Otherwise if not the vintage period then just early (economic) retirement in this period - elif t in M.tech_retirement and v < p: - retired = M.V_RetiredCapacity[r, p, t, v] - # Neither natural retirement nor early economic retirement possible + + if p <= v + value(M.LifetimeProcess[r, t, v]) < p + value(M.PeriodLength[p]): + # EOL this period + if p == M.time_optimize.first() and v in M.time_exist: + # Existing capacity in first period. Remaining existing capacity + retired = value(M.ExistingCapacity[r, t, v]) * value(M.LifetimeSurvivalCurve[r, p, t, v]) + elif p == v: + # New capacity in its vintage period. Remaining new capacity + retired = M.V_NewCapacity[r, t, v] * value(M.LifetimeSurvivalCurve[r, p, t, v]) + else: + # Mid-horizon retirement + retired = M.V_Capacity[r, M.time_optimize.prev(p), t, v] else: - retired = 0.0 + if p == M.time_optimize.first() and v in M.time_exist: + # Existing capacity in first period. Existing capacity minus remaining capacity + retired = value(M.ExistingCapacity[r, t, v]) - M.V_Capacity[r, p, t, v] + elif p == v: + # New capacity in its vintage period. New capacity minus remaining capacity + retired = M.V_NewCapacity[r, t, v] - M.V_Capacity[r, p, t, v] + else: + # Existing or new capacity in some mid-life period. Previous minus current remaining + retired = M.V_Capacity[r, M.time_optimize.prev(p), t, v] - M.V_Capacity[r, p, t, v] # Distribute retirement evenly over planning period retired /= value(M.PeriodLength[p]) From 0f633375736a21fd7e67a6ee5140f485b2d4f306 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Jun 2025 22:02:38 -0400 Subject: [PATCH 129/587] Add survival curves --- data_files/example_dbs/materials.sql | 12 ++ data_files/example_dbs/morris_utopia.sql | 12 ++ data_files/example_dbs/seasonal_storage.sql | 12 ++ data_files/example_dbs/stepped_demand.sql | 12 ++ data_files/example_dbs/test_system.sql | 12 ++ data_files/example_dbs/utopia.sql | 12 ++ data_files/temoa_schema_v3_1.sql | 12 ++ temoa/temoa_model/hybrid_loader.py | 7 ++ .../model_checking/network_model_data.py | 3 + .../temoa_model/model_checking/validators.py | 36 ++++++ temoa/temoa_model/table_data_puller.py | 83 +++++++++++-- temoa/temoa_model/temoa_initialize.py | 3 + temoa/temoa_model/temoa_model.py | 8 +- temoa/temoa_model/temoa_rules.py | 115 ++++++++++++++++-- tests/test_network_model_data.py | 3 + tests/testing_data/emissions.sql | 12 ++ tests/testing_data/materials.sql | 12 ++ tests/testing_data/mediumville.sql | 12 ++ tests/testing_data/mediumville_sets.json | 1 + tests/testing_data/seasonal_storage.sql | 12 ++ tests/testing_data/simple_linked_tech.sql | 12 ++ tests/testing_data/storageville.sql | 12 ++ tests/testing_data/test_system.sql | 12 ++ tests/testing_data/test_system_sets.json | 1 + tests/testing_data/utopia.sql | 12 ++ tests/testing_data/utopia_sets.json | 1 + 26 files changed, 416 insertions(+), 25 deletions(-) diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index b582bb7a2..2f7b6214d 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -1386,6 +1386,18 @@ CREATE TABLE StorageDuration ); INSERT INTO StorageDuration VALUES('RegionA','BATT_GRID',2.0,'2 hours energy storage'); INSERT INTO StorageDuration VALUES('RegionB','BATT_GRID',2.0,'2 hours energy storage'); +CREATE TABLE SurvivalCurve +( + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); CREATE TABLE TechnologyType ( label TEXT diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index 7be30d0a7..fc1c6b059 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -1366,6 +1366,18 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); +CREATE TABLE SurvivalCurve +( + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); CREATE TABLE TechnologyType ( label TEXT diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql index bbd32562a..157a85e45 100644 --- a/data_files/example_dbs/seasonal_storage.sql +++ b/data_files/example_dbs/seasonal_storage.sql @@ -899,6 +899,18 @@ CREATE TABLE StorageDuration ); INSERT INTO StorageDuration VALUES('region','dly_stor',4.0,NULL); INSERT INTO StorageDuration VALUES('region','seas_stor',8760.0,NULL); +CREATE TABLE SurvivalCurve +( + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); CREATE TABLE TechnologyType ( label TEXT diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index 580750d23..594e7d27a 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -1101,6 +1101,18 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); +CREATE TABLE SurvivalCurve +( + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); CREATE TABLE TechnologyType ( label TEXT diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index 78e5d6b47..c33972ec4 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -1378,6 +1378,18 @@ CREATE TABLE StorageDuration ); INSERT INTO StorageDuration VALUES('R1','E_BATT',8.0,'8-hour duration specified as fraction of a day'); INSERT INTO StorageDuration VALUES('R2','E_BATT',8.0,'8-hour duration specified as fraction of a day'); +CREATE TABLE SurvivalCurve +( + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); CREATE TABLE TechnologyType ( label TEXT diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 43ec455d7..fa91f786a 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -1361,6 +1361,18 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); +CREATE TABLE SurvivalCurve +( + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); CREATE TABLE TechnologyType ( label TEXT diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index cea7f4e7f..90b5f8c32 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -869,6 +869,18 @@ CREATE TABLE IF NOT EXISTS StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); +CREATE TABLE SurvivalCurve +( + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); CREATE TABLE IF NOT EXISTS TechnologyType ( label TEXT diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 2b29e31c0..611fdf5cc 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -736,6 +736,13 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N raw = cur.execute('SELECT region, tech, vintage, lifetime FROM main.LifetimeProcess').fetchall() load_element(M.LifetimeProcess, raw, self.viable_rtv, val_loc=(0, 1, 2)) + # SurvivalCurve + if self.table_exists("SurvivalCurve"): + raw = cur.execute('SELECT region, period, tech, vintage, fraction FROM main.SurvivalCurve').fetchall() + load_element(M.SurvivalCurve, raw, self.viable_rtv, val_loc=(0, 2, 3)) + raw = cur.execute('SELECT DISTINCT region, tech, vintage, fraction FROM main.SurvivalCurve').fetchall() + load_element(M.tech_survival_curve, set(raw)) + # LoanLifetimeTech if self.table_exists("LoanLifetimeTech"): raw = cur.execute('SELECT region, tech, lifetime FROM main.LoanLifetimeTech').fetchall() diff --git a/temoa/temoa_model/model_checking/network_model_data.py b/temoa/temoa_model/model_checking/network_model_data.py index cc2856bcd..88a92e35a 100644 --- a/temoa/temoa_model/model_checking/network_model_data.py +++ b/temoa/temoa_model/model_checking/network_model_data.py @@ -181,6 +181,8 @@ def _build_from_db( cur = con.cursor() raw = cur.execute('SELECT tech FROM Technology WHERE retire==1').fetchall() tech_retire = {t[0] for t in raw} + raw = cur.execute('SELECT DISTINCT region, tech, vintage FROM SurvivalCurve').fetchall() + tech_survival_curve = set(raw) raw = cur.execute('SELECT period FROM TimePeriod').fetchall() periods = [p[0] for p in sorted(raw)] period_length = {periods[i]: periods[i+1] - periods[i] for i in range(len(periods)-1)} @@ -274,6 +276,7 @@ def _build_from_db( if any(( p <= v+lifetime < p + period_length[p], # natural eol this period tech in tech_retire and v < p <= v+lifetime - period_length[p], # allowed early retirement + tech in tech_survival_curve and v <= p <= v+lifetime )): try: raw_eol = cur.execute( diff --git a/temoa/temoa_model/model_checking/validators.py b/temoa/temoa_model/model_checking/validators.py index e5b4a60be..4d329ea81 100644 --- a/temoa/temoa_model/model_checking/validators.py +++ b/temoa/temoa_model/model_checking/validators.py @@ -407,6 +407,42 @@ def validate_ReserveMargin(M: 'TemoaModel'): ) +def validate_SurvivalCurve(M: 'TemoaModel'): + rptv = set( + (r, p, t, v) + for r, t, v in M.retirementPeriods + if (r, t, v) in M.tech_survival_curve + for p in M.retirementPeriods[r, t, v] + ) + rptv = rptv | M.SurvivalCurve.sparse_iterkeys() + for r, p, t, v in rptv: + if (r, t, v) not in M.survivalCurvePeriods: + M.survivalCurvePeriods[r, t, v] = list() + M.survivalCurvePeriods[r, t, v].append(p) + if M.time_exist.first() < p < M.time_future.last() and p not in M.time_exist | M.time_future: + msg = ( + 'A row in the SurvivalCurve table used a period that was within the bounds of ' + 'defined periods but was not one of those periods. This value was ignored: ' + f'({r}, >{p}<, {t}, {v})): {M.SurvivalCurve[r, p, t, v]}' + ) + logger.warning(msg) + for r, t, v in M.survivalCurvePeriods: + M.survivalCurvePeriods[r, t, v] = sorted(M.survivalCurvePeriods[r, t, v]) + for i, p in enumerate(M.survivalCurvePeriods[r, t, v]): + if i == 0: + continue + p_prev = M.survivalCurvePeriods[r, t, v][i-1] + lsc = M.SurvivalCurve[r, p, t, v] + lsc_prev = M.SurvivalCurve[r, p_prev, t, v] + if lsc > lsc_prev: + msg = ( + 'SurvivalCurve fraction increases going forward in time from {} to {}. ' + 'This is not allowed.' + ).format((r, p_prev, t, v), (r, p, t, v)) + logger.error(msg) + raise ValueError(msg) + + def validate_tech_sets(M: 'TemoaModel'): """ Check tech sets for any forbidden intersections diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index 15885d000..3192533a5 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -313,18 +313,31 @@ def poll_cost_results( continue loan_life = value(LLN[r, t, v]) loan_rate = value(M.LoanRate[r, t, v]) - - model_loan_cost, undiscounted_cost = loan_costs( - loan_rate=loan_rate, - loan_life=loan_life, - capacity=cap, - invest_cost=value(M.CostInvest[r, t, v]), - process_life=value(M.LifetimeProcess[r, t, v]), - p_0=p_0, - p_e=p_e, - global_discount_rate=GDR, - vintage=v, - ) + + if (r, t, v) in M.tech_survival_curve: + model_loan_cost, undiscounted_cost = loan_costs_survival_curve( + M=M, + loan_rate=loan_rate, + loan_life=loan_life, + capacity=cap, + invest_cost=value(M.CostInvest[r, t, v]), + p_0=p_0, + p_e=p_e, + global_discount_rate=GDR, + vintage=v, + ) + else: + model_loan_cost, undiscounted_cost = loan_costs( + loan_rate=loan_rate, + loan_life=loan_life, + capacity=cap, + invest_cost=value(M.CostInvest[r, t, v]), + process_life=value(M.LifetimeProcess[r, t, v]), + p_0=p_0, + p_e=p_e, + global_discount_rate=GDR, + vintage=v, + ) # screen for linked region... if '-' in r: exchange_costs.add_cost_record( @@ -477,6 +490,52 @@ def loan_costs( return model_ic, undiscounted_cost +def loan_costs_survival_curve( + M, + loan_rate, # this is referred to as LoanRate in parameters + loan_life, + capacity, + invest_cost, + p_0, + p_e, + global_discount_rate, + vintage, + **kwargs, +) -> tuple[float, float]: + """ + Calculate Loan costs by calling the loan annualize and loan cost functions in temoa_rules + :return: tuple of [model-view discounted cost, un-discounted annuity] + """ + # dev note: this is a passthrough function. Sole intent is to use the EXACT formula the + # model uses for these costs + loan_ar = temoa_rules.loan_annualization_rate(loan_rate=loan_rate, loan_life=loan_life) + model_ic = temoa_rules.loan_cost_survival_curve( + M, + capacity, + invest_cost, + loan_annualize=loan_ar, + lifetime_loan_process=loan_life, + P_0=p_0, + P_e=p_e, + GDR=global_discount_rate, + vintage=vintage, + ) + # Override the GDR to get the undiscounted value + global_discount_rate = 0 + undiscounted_cost = temoa_rules.loan_cost_survival_curve( + M, + capacity, + invest_cost, + loan_annualize=loan_ar, + lifetime_loan_process=loan_life, + P_0=p_0, + P_e=p_e, + GDR=global_discount_rate, + vintage=vintage, + ) + return model_ic, undiscounted_cost + + def poll_emissions( M: 'TemoaModel', p_0=None, epsilon=1e-5 ) -> tuple[dict[tuple, dict], dict[EI, float]]: diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 9a022b298..a92fb5f0b 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -445,6 +445,8 @@ def get_default_process_lifetime(M: 'TemoaModel', r, t, v): :param v: vintage :return: the final lifetime value """ + if (r, t, v) in M.tech_survival_curve: + return M.time_future.last() - v # arbitrary return M.LifetimeTech[r, t] @@ -793,6 +795,7 @@ def CreateSparseDicts(M: 'TemoaModel'): if t not in M.tech_uncap and any(( p <= v+l_lifetime < p + value(M.PeriodLength[p]), # natural eol this period t in M.tech_retirement and v < p <= v+l_lifetime - value(M.PeriodLength[p]), # allowed early retirement + (r, t, v) in M.tech_survival_curve and v <= p <= v+l_lifetime )): if (r, t, v) not in M.retirementPeriods: M.retirementPeriods[r, t, v] = set() diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 5abaf3fc0..91b22b225 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -26,6 +26,7 @@ from pyomo.environ import ( Any, NonNegativeReals, + Integers, AbstractModel, BuildAction, Param, @@ -44,9 +45,9 @@ no_slash_or_pipe, validate_SeasonSequential, validate_ReserveMargin, + validate_SurvivalCurve, ) from temoa.temoa_model.temoa_initialize import * -from temoa.temoa_model.temoa_initialize import get_loan_life from temoa.temoa_model.temoa_rules import * logger = logging.getLogger(__name__) @@ -111,6 +112,7 @@ def __init__(M, *args, **kwargs): M.processPeriods = dict() # {(r, t, v): set(p)} M.retirementPeriods = dict() # {(r, t, v): set(p)} periods in which a process can economically or naturally retire M.processVintages = dict() + M.survivalCurvePeriods = dict() # {(r, t, v): set(p)} periods for which the process has a defined survival fraction """current available (within lifespan) vintages {(r, p, t) : set(v)}""" M.baseloadVintages = dict() @@ -214,6 +216,7 @@ def __init__(M, *args, **kwargs): # Note2: I think this has been fixed but I can't tell what the problem was. Suspect # it was the old StorageInit constraint M.tech_retirement = Set(within=M.tech_with_capacity)# - M.tech_storage) + M.tech_survival_curve = Set(within=M.regionalIndices * M.tech_with_capacity * M.vintage_all) M.validate_techs = BuildAction(rule=validate_tech_sets) @@ -390,6 +393,9 @@ def __init__(M, *args, **kwargs): M.initialize_CapacityFactors = BuildAction(rule=CheckCapacityFactorProcess) M.initialize_EfficiencyVariable = BuildAction(rule=CheckEfficiencyVariable) + M.SurvivalCurve = Param(M.regionalIndices, Integers, M.tech_all, M.vintage_all, default=1, validate=validate_0to1) + M.validate_SurvivalCurve = BuildAction(rule=validate_SurvivalCurve) + # Define technology cost parameters # dev note: the CostFixed_rptv isn't truly needed, but it is included in a constraint, so # let it go for now diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 94668e227..3b47d0b17 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -50,11 +50,15 @@ def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): For a given :code:`(r,p,t,v)` index, this constraint sets the capacity equal to the amount installed in period :code:`v` and subtracts from it any and all retirements that occurred up until the period in question, :code:`p`.""" + + PLF = value(M.ProcessLifeFrac[r, p, t, v]) + LSC = value(M.SurvivalCurve[r, p, t, v]) + if t not in M.tech_retirement: if v in M.time_exist: - return M.V_Capacity[r, p, t, v] == value(M.ExistingCapacity[r, t, v]) * value(M.ProcessLifeFrac[r, p, t, v]) + return M.V_Capacity[r, p, t, v] == value(M.ExistingCapacity[r, t, v]) * LSC * PLF else: - return M.V_Capacity[r, p, t, v] == M.V_NewCapacity[r, t, v] * value(M.ProcessLifeFrac[r, p, t, v]) + return M.V_Capacity[r, p, t, v] == M.V_NewCapacity[r, t, v] * LSC * PLF else: retired_cap = sum( @@ -63,9 +67,9 @@ def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): if v < S_p <= p and S_p < v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[S_p]) ) if v in M.time_exist: - return M.V_Capacity[r, p, t, v] == value(M.ExistingCapacity[r, t, v]) * value(M.ProcessLifeFrac[r, p, t, v]) - retired_cap + return M.V_Capacity[r, p, t, v] == (value(M.ExistingCapacity[r, t, v]) * LSC - retired_cap) * PLF else: - return M.V_Capacity[r, p, t, v] == M.V_NewCapacity[r, t, v] * value(M.ProcessLifeFrac[r, p, t, v]) - retired_cap + return M.V_Capacity[r, p, t, v] == (M.V_NewCapacity[r, t, v] * LSC - retired_cap) * PLF def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): @@ -283,17 +287,22 @@ def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): # EOL this period if p == M.time_optimize.first() and v in M.time_exist: # Existing capacity in first period. Remaining existing capacity - retired = value(M.ExistingCapacity[r, t, v]) * value(M.LifetimeSurvivalCurve[r, p, t, v]) + retired = value(M.ExistingCapacity[r, t, v]) * value(M.SurvivalCurve[r, p, t, v]) elif p == v: # New capacity in its vintage period. Remaining new capacity - retired = M.V_NewCapacity[r, t, v] * value(M.LifetimeSurvivalCurve[r, p, t, v]) + retired = M.V_NewCapacity[r, t, v] * value(M.SurvivalCurve[r, p, t, v]) else: # Mid-horizon retirement retired = M.V_Capacity[r, M.time_optimize.prev(p), t, v] else: if p == M.time_optimize.first() and v in M.time_exist: - # Existing capacity in first period. Existing capacity minus remaining capacity - retired = value(M.ExistingCapacity[r, t, v]) - M.V_Capacity[r, p, t, v] + # Existing capacity in first period. Remaining existing capacity in last + # existing period minus remaining capacity + retired = ( + value(M.ExistingCapacity[r, t, v]) + * value(M.SurvivalCurve[r, M.time_exist.last(), t, v]) + - M.V_Capacity[r, p, t, v] + ) elif p == v: # New capacity in its vintage period. New capacity minus remaining capacity retired = M.V_NewCapacity[r, t, v] - M.V_Capacity[r, p, t, v] @@ -448,7 +457,7 @@ def loan_cost( :return: fixed number or pyomo expression based on input types """ - # calculate the annualised loan repayment (annuity) + # calculate the amortised loan repayment (annuity) annuity = ( capacity * invest_cost # lump investment cost is capacity times CostInvest * loan_annualize # calculate loan annuities for investment cost, if used @@ -467,8 +476,75 @@ def loan_cost( res = ( annuity * annuity_to_pv(GDR, lifetime_loan_process) # PV of all loan payments, discounted to vintage year using GDR - * pv_to_annuity(GDR, lifetime_process) # reannualised over lifetime of process using GDR - * annuity_to_pv(GDR, min(lifetime_process, P_e - vintage)) # PV of all reannualised costs (within planning horizon) + * pv_to_annuity(GDR, lifetime_process) # reamortised over lifetime of process using GDR + * annuity_to_pv(GDR, min(lifetime_process, P_e - vintage)) # PV of all reamortised costs (within planning horizon) + * fv_to_pv(GDR, vintage - P_0) # finally, discounted from vintage year to P_0 + ) + return res + + +def loan_cost_survival_curve( + M: 'TemoaModel', + capacity: float | Var, + invest_cost: float, + loan_annualize: float, + lifetime_loan_process: float | int, + P_0: int, + P_e: int, + GDR: float, + vintage: int, +) -> float | Expression: + """ + function to calculate the loan cost. It can be used with fixed values to produce a hard number or + pyomo variables/params to make a pyomo Expression + :param capacity: The capacity to use to calculate cost + :param invest_cost: the cost/capacity + :param loan_annualize: parameter + :param lifetime_loan_process: lifetime of the loan + :param P_0: the year to discount the costs back to + :param P_e: the 'end year' or cutoff year for loan payments + :param GDR: Global Discount Rate + :param vintage: the base year of the loan + :return: fixed number or pyomo expression based on input types + """ + + # calculate the amortised loan repayment (annuity) + annuity = ( + capacity * invest_cost # lump investment cost is capacity times CostInvest + * loan_annualize # calculate loan annuities for investment cost, if used + ) + + if not GDR: + # Undiscounted result + res = ( + annuity + * lifetime_loan_process # sum of loan payments over loan period + / sum( # redistributed over survival curve within horizon + M.SurvivalCurve[r, p, t, v] + for r, t, v in M.survivalCurvePeriods + for p in M.survivalCurvePeriods[r, t, v] + if v <= p < P_e + ) + ) + else: + # Discounted result + res = ( + annuity + * annuity_to_pv(GDR, lifetime_loan_process) # PV of all loan payments, discounted to vintage year using GDR + / sum( # redistributed over survival curve within horizon + M.SurvivalCurve[r, p, t, v] # reamortised over survival curve of process using GDR + * fv_to_pv(GDR, p - vintage) + for r, t, v in M.survivalCurvePeriods + for p in M.survivalCurvePeriods[r, t, v] + if v <= p + ) + * sum( # PV of all reamortised costs (within planning horizon) + M.SurvivalCurve[r, p, t, v] + * fv_to_pv(GDR, p - vintage) + for r, t, v in M.survivalCurvePeriods + for p in M.survivalCurvePeriods[r, t, v] + if v <= p < P_e + ) * fv_to_pv(GDR, vintage - P_0) # finally, discounted from vintage year to P_0 ) return res @@ -530,7 +606,22 @@ def PeriodCost_rule(M: 'TemoaModel', p): vintage=S_v, ) for r, S_t, S_v in M.CostInvest.sparse_iterkeys() - if S_v == p + if S_v == p and (r, S_t, S_v) not in M.tech_survival_curve + ) + loan_costs += sum( + loan_cost_survival_curve( + M, + M.V_NewCapacity[r, S_t, S_v], + value(M.CostInvest[r, S_t, S_v]), + value(M.LoanAnnualize[r, S_t, S_v]), + value(M.LoanLifetimeProcess[r, S_t, S_v]), + P_0, + P_e, + GDR, + vintage=S_v, + ) + for r, S_t, S_v in M.CostInvest.sparse_iterkeys() + if S_v == p and (r, S_t, S_v) in M.tech_survival_curve ) fixed_costs = sum( diff --git a/tests/test_network_model_data.py b/tests/test_network_model_data.py index 2bd6a3e01..e9b4e7a19 100644 --- a/tests/test_network_model_data.py +++ b/tests/test_network_model_data.py @@ -52,6 +52,7 @@ 'name': 'basic', 'data': [ [], # retirement techs + [], # survival curve techs [ (2020,), (2025,), @@ -100,6 +101,7 @@ 'name': 'bad linked tech', 'data': [ [], # retirement techs + [], # survival curve techs [ (2020,), (2025,), @@ -147,6 +149,7 @@ 'name': 'good linked tech', 'data': [ [], # retirement techs + [], # survival curve techs [ (2020,), (2025,), diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 6dd835255..373b28b14 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -912,6 +912,18 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); +CREATE TABLE SurvivalCurve +( + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); CREATE TABLE TechnologyType ( label TEXT diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index b582bb7a2..2f7b6214d 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -1386,6 +1386,18 @@ CREATE TABLE StorageDuration ); INSERT INTO StorageDuration VALUES('RegionA','BATT_GRID',2.0,'2 hours energy storage'); INSERT INTO StorageDuration VALUES('RegionB','BATT_GRID',2.0,'2 hours energy storage'); +CREATE TABLE SurvivalCurve +( + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); CREATE TABLE TechnologyType ( label TEXT diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 6db7897ae..65e7c9f22 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -989,6 +989,18 @@ CREATE TABLE StorageDuration PRIMARY KEY (region, tech) ); INSERT INTO StorageDuration VALUES('B','batt',15.0,NULL); +CREATE TABLE SurvivalCurve +( + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); CREATE TABLE TechnologyType ( label TEXT diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index a8957e3d2..a14d8abc2 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -4342,6 +4342,7 @@ "tech_storage": [ "batt" ], + "tech_survival_curve": [], "tech_uncap": [], "tech_upramping": [ "EH" diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index bbd32562a..157a85e45 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -899,6 +899,18 @@ CREATE TABLE StorageDuration ); INSERT INTO StorageDuration VALUES('region','dly_stor',4.0,NULL); INSERT INTO StorageDuration VALUES('region','seas_stor',8760.0,NULL); +CREATE TABLE SurvivalCurve +( + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); CREATE TABLE TechnologyType ( label TEXT diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index 495682bbe..686ed6c79 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -883,6 +883,18 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); +CREATE TABLE SurvivalCurve +( + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); CREATE TABLE TechnologyType ( label TEXT diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index 69430f763..08f707ad3 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -904,6 +904,18 @@ CREATE TABLE StorageDuration PRIMARY KEY (region, tech) ); INSERT INTO StorageDuration VALUES('electricville','batt',10.0,NULL); +CREATE TABLE SurvivalCurve +( + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); CREATE TABLE TechnologyType ( label TEXT diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 78e5d6b47..c33972ec4 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -1378,6 +1378,18 @@ CREATE TABLE StorageDuration ); INSERT INTO StorageDuration VALUES('R1','E_BATT',8.0,'8-hour duration specified as fraction of a day'); INSERT INTO StorageDuration VALUES('R2','E_BATT',8.0,'8-hour duration specified as fraction of a day'); +CREATE TABLE SurvivalCurve +( + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); CREATE TABLE TechnologyType ( label TEXT diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 867c86a63..56bff7119 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -46666,6 +46666,7 @@ "tech_storage": [ "E_BATT" ], + "tech_survival_curve": [], "tech_uncap": [ "S_IMPETH", "S_IMPNG", diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 43ec455d7..fa91f786a 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -1361,6 +1361,18 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); +CREATE TABLE SurvivalCurve +( + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); CREATE TABLE TechnologyType ( label TEXT diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 3b85e3590..ecff3bebc 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -25759,6 +25759,7 @@ "tech_storage": [ "E51" ], + "tech_survival_curve": [], "tech_uncap": [ "IMPDSL1", "IMPHYD", From 343b9d558aedc7eb46663bdcc8969e125faef763 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 18 Jun 2025 11:13:32 -0400 Subject: [PATCH 130/587] Get survival curves working in the objective function --- data_files/example_dbs/materials.sql | 12 +- data_files/example_dbs/morris_utopia.sql | 24 ++-- data_files/example_dbs/seasonal_storage.sql | 6 +- data_files/example_dbs/stepped_demand.sql | 14 ++- data_files/example_dbs/test_system.sql | 42 ++----- data_files/example_dbs/utopia.sql | 22 +--- data_files/temoa_schema_v3_1.sql | 12 +- temoa/temoa_model/hybrid_loader.py | 25 ++-- .../model_checking/network_model_data.py | 9 +- .../model_checking/pricing_check.py | 3 +- .../temoa_model/model_checking/validators.py | 112 ++++++++++++++---- temoa/temoa_model/table_data_puller.py | 16 ++- temoa/temoa_model/temoa_initialize.py | 6 +- temoa/temoa_model/temoa_model.py | 7 +- temoa/temoa_model/temoa_rules.py | 65 ++++++---- temoa/utilities/db_migration_v3_to_v3_1.py | 21 +++- tests/testing_data/emissions.sql | 12 +- tests/testing_data/emissions.sqlite | Bin 667648 -> 0 bytes tests/testing_data/materials.sql | 12 +- tests/testing_data/materials.sqlite | Bin 684032 -> 0 bytes tests/testing_data/mediumville.sql | 32 +++-- tests/testing_data/mediumville.sqlite | Bin 667648 -> 0 bytes tests/testing_data/seasonal_storage.sql | 6 +- tests/testing_data/simple_linked_tech.sql | 12 +- tests/testing_data/simple_linked_tech.sqlite | Bin 667648 -> 0 bytes tests/testing_data/storageville.sql | 12 +- tests/testing_data/storageville.sqlite | Bin 667648 -> 0 bytes tests/testing_data/test_system.sql | 42 ++----- tests/testing_data/test_system.sqlite | Bin 667648 -> 0 bytes tests/testing_data/utopia.sql | 22 +--- tests/testing_data/utopia.sqlite | Bin 667648 -> 0 bytes 31 files changed, 303 insertions(+), 243 deletions(-) delete mode 100644 tests/testing_data/emissions.sqlite delete mode 100644 tests/testing_data/materials.sqlite delete mode 100644 tests/testing_data/mediumville.sqlite delete mode 100644 tests/testing_data/simple_linked_tech.sqlite delete mode 100644 tests/testing_data/storageville.sqlite delete mode 100644 tests/testing_data/test_system.sqlite delete mode 100644 tests/testing_data/utopia.sqlite diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index 2f7b6214d..4a6820023 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -747,14 +747,16 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE LoanLifetimeTech +CREATE TABLE LoanLifetimeProcess ( region TEXT, tech TEXT REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), lifetime REAL, notes TEXT, - PRIMARY KEY (region, tech) + PRIMARY KEY (region, tech, vintage) ); CREATE TABLE LoanRate ( @@ -1386,7 +1388,7 @@ CREATE TABLE StorageDuration ); INSERT INTO StorageDuration VALUES('RegionA','BATT_GRID',2.0,'2 hours energy storage'); INSERT INTO StorageDuration VALUES('RegionB','BATT_GRID',2.0,'2 hours energy storage'); -CREATE TABLE SurvivalCurve +CREATE TABLE LifetimeSurvivalCurve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -1461,10 +1463,10 @@ CREATE TABLE TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count REAL NOT NULL, + num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (count > 0) + CHECK (num_days > 0) ); CREATE TABLE TimePeriodType ( diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index fc1c6b059..ae2e2b26a 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -767,27 +767,17 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE LoanLifetimeTech +CREATE TABLE LoanLifetimeProcess ( region TEXT, tech TEXT REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), lifetime REAL, notes TEXT, - PRIMARY KEY (region, tech) + PRIMARY KEY (region, tech, vintage) ); -INSERT INTO LoanLifetimeTech VALUES('utopia','E01',40.0,''); -INSERT INTO LoanLifetimeTech VALUES('utopia','E21',40.0,''); -INSERT INTO LoanLifetimeTech VALUES('utopia','E31',100.0,''); -INSERT INTO LoanLifetimeTech VALUES('utopia','E51',100.0,''); -INSERT INTO LoanLifetimeTech VALUES('utopia','E70',40.0,''); -INSERT INTO LoanLifetimeTech VALUES('utopia','RHE',30.0,''); -INSERT INTO LoanLifetimeTech VALUES('utopia','RHO',30.0,''); -INSERT INTO LoanLifetimeTech VALUES('utopia','RL1',10.0,''); -INSERT INTO LoanLifetimeTech VALUES('utopia','SRE',50.0,''); -INSERT INTO LoanLifetimeTech VALUES('utopia','TXD',15.0,''); -INSERT INTO LoanLifetimeTech VALUES('utopia','TXE',15.0,''); -INSERT INTO LoanLifetimeTech VALUES('utopia','TXG',15.0,''); CREATE TABLE LoanRate ( region TEXT, @@ -1366,7 +1356,7 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE SurvivalCurve +CREATE TABLE LifetimeSurvivalCurve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -1438,10 +1428,10 @@ CREATE TABLE TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count REAL NOT NULL, + num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (count > 0) + CHECK (num_days > 0) ); CREATE TABLE TimePeriodType ( diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql index 157a85e45..774d6e79b 100644 --- a/data_files/example_dbs/seasonal_storage.sql +++ b/data_files/example_dbs/seasonal_storage.sql @@ -899,7 +899,7 @@ CREATE TABLE StorageDuration ); INSERT INTO StorageDuration VALUES('region','dly_stor',4.0,NULL); INSERT INTO StorageDuration VALUES('region','seas_stor',8760.0,NULL); -CREATE TABLE SurvivalCurve +CREATE TABLE LifetimeSurvivalCurve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -1046,10 +1046,10 @@ CREATE TABLE TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count REAL NOT NULL, + num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (count > 0) + CHECK (num_days > 0) ); INSERT INTO TimeSeasonSequential VALUES(2000,1,'summer','charge',152.5,NULL); INSERT INTO TimeSeasonSequential VALUES(2000,2,'sept_w1','discharge',7,NULL); diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index 594e7d27a..94221d317 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -523,16 +523,18 @@ CREATE TABLE TechGroup ); INSERT INTO TechGroup VALUES('RPS_global',''); INSERT INTO TechGroup VALUES('RPS_common',''); -CREATE TABLE LoanLifetimeTech +CREATE TABLE LoanLifetimeProcess ( region TEXT, tech TEXT REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), lifetime REAL, notes TEXT, - PRIMARY KEY (region, tech) + PRIMARY KEY (region, tech, vintage) ); -INSERT INTO LoanLifetimeTech VALUES('electricville','EF',50.0,''); +INSERT INTO LoanLifetimeProcess VALUES('electricville','EF',2010,50.0,''); CREATE TABLE LoanRate ( region TEXT, @@ -1101,7 +1103,7 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE SurvivalCurve +CREATE TABLE LifetimeSurvivalCurve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -1202,10 +1204,10 @@ CREATE TABLE TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count REAL NOT NULL, + num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (count > 0) + CHECK (num_days > 0) ); CREATE TABLE TimePeriodType ( diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index c33972ec4..3a2efbe88 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -723,45 +723,17 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE LoanLifetimeTech +CREATE TABLE LoanLifetimeProcess ( region TEXT, tech TEXT REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), lifetime REAL, notes TEXT, - PRIMARY KEY (region, tech) + PRIMARY KEY (region, tech, vintage) ); -INSERT INTO LoanLifetimeTech VALUES('R1','S_IMPETH',100.0,''); -INSERT INTO LoanLifetimeTech VALUES('R1','S_IMPOIL',100.0,''); -INSERT INTO LoanLifetimeTech VALUES('R1','S_IMPNG',100.0,''); -INSERT INTO LoanLifetimeTech VALUES('R1','S_IMPURN',100.0,''); -INSERT INTO LoanLifetimeTech VALUES('R1','S_OILREF',100.0,''); -INSERT INTO LoanLifetimeTech VALUES('R1','E_NGCC',30.0,''); -INSERT INTO LoanLifetimeTech VALUES('R1','E_SOLPV',30.0,''); -INSERT INTO LoanLifetimeTech VALUES('R1','E_BATT',20.0,''); -INSERT INTO LoanLifetimeTech VALUES('R1','E_NUCLEAR',50.0,''); -INSERT INTO LoanLifetimeTech VALUES('R1','T_BLND',100.0,''); -INSERT INTO LoanLifetimeTech VALUES('R1','T_DSL',12.0,''); -INSERT INTO LoanLifetimeTech VALUES('R1','T_GSL',12.0,''); -INSERT INTO LoanLifetimeTech VALUES('R1','T_EV',12.0,''); -INSERT INTO LoanLifetimeTech VALUES('R1','R_EH',20.0,''); -INSERT INTO LoanLifetimeTech VALUES('R1','R_NGH',20.0,''); -INSERT INTO LoanLifetimeTech VALUES('R2','S_IMPETH',100.0,''); -INSERT INTO LoanLifetimeTech VALUES('R2','S_IMPOIL',100.0,''); -INSERT INTO LoanLifetimeTech VALUES('R2','S_IMPNG',100.0,''); -INSERT INTO LoanLifetimeTech VALUES('R2','S_IMPURN',100.0,''); -INSERT INTO LoanLifetimeTech VALUES('R2','S_OILREF',100.0,''); -INSERT INTO LoanLifetimeTech VALUES('R2','E_NGCC',30.0,''); -INSERT INTO LoanLifetimeTech VALUES('R2','E_SOLPV',30.0,''); -INSERT INTO LoanLifetimeTech VALUES('R2','E_BATT',20.0,''); -INSERT INTO LoanLifetimeTech VALUES('R2','E_NUCLEAR',50.0,''); -INSERT INTO LoanLifetimeTech VALUES('R2','T_BLND',100.0,''); -INSERT INTO LoanLifetimeTech VALUES('R2','T_DSL',12.0,''); -INSERT INTO LoanLifetimeTech VALUES('R2','T_GSL',12.0,''); -INSERT INTO LoanLifetimeTech VALUES('R2','T_EV',12.0,''); -INSERT INTO LoanLifetimeTech VALUES('R2','R_EH',20.0,''); -INSERT INTO LoanLifetimeTech VALUES('R2','R_NGH',20.0,''); CREATE TABLE LoanRate ( region TEXT, @@ -1378,7 +1350,7 @@ CREATE TABLE StorageDuration ); INSERT INTO StorageDuration VALUES('R1','E_BATT',8.0,'8-hour duration specified as fraction of a day'); INSERT INTO StorageDuration VALUES('R2','E_BATT',8.0,'8-hour duration specified as fraction of a day'); -CREATE TABLE SurvivalCurve +CREATE TABLE LifetimeSurvivalCurve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -1451,10 +1423,10 @@ CREATE TABLE TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count REAL NOT NULL, + num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (count > 0) + CHECK (num_days > 0) ); CREATE TABLE TimePeriodType ( diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index fa91f786a..351076e13 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -762,27 +762,17 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE LoanLifetimeTech +CREATE TABLE LoanLifetimeProcess ( region TEXT, tech TEXT REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), lifetime REAL, notes TEXT, - PRIMARY KEY (region, tech) + PRIMARY KEY (region, tech, vintage) ); -INSERT INTO LoanLifetimeTech VALUES('utopia','E01',40.0,''); -INSERT INTO LoanLifetimeTech VALUES('utopia','E21',40.0,''); -INSERT INTO LoanLifetimeTech VALUES('utopia','E31',100.0,''); -INSERT INTO LoanLifetimeTech VALUES('utopia','E51',100.0,''); -INSERT INTO LoanLifetimeTech VALUES('utopia','E70',40.0,''); -INSERT INTO LoanLifetimeTech VALUES('utopia','RHE',30.0,''); -INSERT INTO LoanLifetimeTech VALUES('utopia','RHO',30.0,''); -INSERT INTO LoanLifetimeTech VALUES('utopia','RL1',10.0,''); -INSERT INTO LoanLifetimeTech VALUES('utopia','SRE',50.0,''); -INSERT INTO LoanLifetimeTech VALUES('utopia','TXD',15.0,''); -INSERT INTO LoanLifetimeTech VALUES('utopia','TXE',15.0,''); -INSERT INTO LoanLifetimeTech VALUES('utopia','TXG',15.0,''); CREATE TABLE LoanRate ( region TEXT, @@ -1433,10 +1423,10 @@ CREATE TABLE TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count REAL NOT NULL, + num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (count > 0) + CHECK (num_days > 0) ); CREATE TABLE TimePeriodType ( diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index 90b5f8c32..65f774d83 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -342,14 +342,16 @@ CREATE TABLE IF NOT EXISTS TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE IF NOT EXISTS LoanLifetimeTech +CREATE TABLE IF NOT EXISTS LoanLifetimeProcess ( region TEXT, tech TEXT REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), lifetime REAL, notes TEXT, - PRIMARY KEY (region, tech) + PRIMARY KEY (region, tech, vintage) ); CREATE TABLE IF NOT EXISTS LoanRate ( @@ -869,7 +871,7 @@ CREATE TABLE IF NOT EXISTS StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE SurvivalCurve +CREATE TABLE LifetimeSurvivalCurve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -941,10 +943,10 @@ CREATE TABLE IF NOT EXISTS TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count REAL NOT NULL, + num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (count > 0) + CHECK (num_days > 0) ); CREATE TABLE IF NOT EXISTS TimePeriodType ( diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 611fdf5cc..91417736d 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -664,12 +664,12 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N if self.table_exists("TimeSeasonSequential"): if mi: raw = cur.execute( - 'SELECT period, seas_seq, season, count FROM main.TimeSeasonSequential WHERE' + 'SELECT period, seas_seq, season, num_days FROM main.TimeSeasonSequential WHERE' ' period >= ? AND period <= ? ORDER BY period, sequence', (mi.base_year, mi.last_demand_year) ).fetchall() else: - raw = cur.execute('SELECT period, seas_seq, season, count FROM main.TimeSeasonSequential ORDER BY period, sequence').fetchall() + raw = cur.execute('SELECT period, seas_seq, season, num_days FROM main.TimeSeasonSequential ORDER BY period, sequence').fetchall() all_seasons = all_seasons | set((row[1],) for row in raw) load_element(M.TimeSeasonSequential, raw) load_element(M.ordered_season_sequential, [(row[0:3]) for row in raw]) @@ -736,17 +736,16 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N raw = cur.execute('SELECT region, tech, vintage, lifetime FROM main.LifetimeProcess').fetchall() load_element(M.LifetimeProcess, raw, self.viable_rtv, val_loc=(0, 1, 2)) - # SurvivalCurve - if self.table_exists("SurvivalCurve"): - raw = cur.execute('SELECT region, period, tech, vintage, fraction FROM main.SurvivalCurve').fetchall() - load_element(M.SurvivalCurve, raw, self.viable_rtv, val_loc=(0, 2, 3)) - raw = cur.execute('SELECT DISTINCT region, tech, vintage, fraction FROM main.SurvivalCurve').fetchall() - load_element(M.tech_survival_curve, set(raw)) - - # LoanLifetimeTech - if self.table_exists("LoanLifetimeTech"): - raw = cur.execute('SELECT region, tech, lifetime FROM main.LoanLifetimeTech').fetchall() - load_element(M.LoanLifetimeTech, raw, self.viable_rt, (0, 1)) + # LifetimeSurvivalCurve + if self.table_exists("LifetimeSurvivalCurve"): + raw = cur.execute('SELECT region, period, tech, vintage, fraction FROM main.LifetimeSurvivalCurve').fetchall() + load_element(M.LifetimeSurvivalCurve, raw, self.viable_rtv, val_loc=(0, 2, 3)) + load_element(M.tech_survival_curve, list(set([(row[0], row[2], row[3]) for row in raw]))) + + # LoanLifetimeProcess + if self.table_exists("LoanLifetimeProcess"): + raw = cur.execute('SELECT region, tech, vintage, lifetime FROM main.LoanLifetimeProcess').fetchall() + load_element(M.LoanLifetimeProcess, raw, self.viable_rtv, (0, 1)) # LimitTechInputSplit if self.table_exists('LimitTechInputSplit'): diff --git a/temoa/temoa_model/model_checking/network_model_data.py b/temoa/temoa_model/model_checking/network_model_data.py index 88a92e35a..522211b05 100644 --- a/temoa/temoa_model/model_checking/network_model_data.py +++ b/temoa/temoa_model/model_checking/network_model_data.py @@ -181,8 +181,13 @@ def _build_from_db( cur = con.cursor() raw = cur.execute('SELECT tech FROM Technology WHERE retire==1').fetchall() tech_retire = {t[0] for t in raw} - raw = cur.execute('SELECT DISTINCT region, tech, vintage FROM SurvivalCurve').fetchall() - tech_survival_curve = set(raw) + tech_survival_curve = set() + try: + raw = cur.execute('SELECT DISTINCT region, tech, vintage FROM SurvivalCurve').fetchall() + tech_survival_curve = set(raw) + except: + # table didn't exist + pass raw = cur.execute('SELECT period FROM TimePeriod').fetchall() periods = [p[0] for p in sorted(raw)] period_length = {periods[i]: periods[i+1] - periods[i] for i in range(len(periods)-1)} diff --git a/temoa/temoa_model/model_checking/pricing_check.py b/temoa/temoa_model/model_checking/pricing_check.py index 3ade4dcb5..61e7a377c 100644 --- a/temoa/temoa_model/model_checking/pricing_check.py +++ b/temoa/temoa_model/model_checking/pricing_check.py @@ -43,6 +43,7 @@ from collections import defaultdict from logging import getLogger from typing import TYPE_CHECKING +from pyomo.environ import value if TYPE_CHECKING: from temoa.temoa_model.temoa_model import TemoaModel @@ -226,7 +227,7 @@ def price_checker(M: 'TemoaModel') -> bool: continue # get the lifetime of the tech, or default - lifetime = M.LifetimeProcess[region, tech, vintage] + lifetime = value(M.LifetimeProcess[region, tech, vintage]) # get all applicable future periods that should be priced for this item expected_periods = {p for p in M.time_optimize if vintage <= p < vintage + lifetime} missing_fixed_costs = ( diff --git a/temoa/temoa_model/model_checking/validators.py b/temoa/temoa_model/model_checking/validators.py index 4d329ea81..e4241d36e 100644 --- a/temoa/temoa_model/model_checking/validators.py +++ b/temoa/temoa_model/model_checking/validators.py @@ -408,40 +408,106 @@ def validate_ReserveMargin(M: 'TemoaModel'): def validate_SurvivalCurve(M: 'TemoaModel'): - rptv = set( - (r, p, t, v) - for r, t, v in M.retirementPeriods - if (r, t, v) in M.tech_survival_curve - for p in M.retirementPeriods[r, t, v] - ) - rptv = rptv | M.SurvivalCurve.sparse_iterkeys() - for r, p, t, v in rptv: + + # Collect rptv indices into (r, t, v): p dictionary + for r, p, t, v in M.LifetimeSurvivalCurve: if (r, t, v) not in M.survivalCurvePeriods: M.survivalCurvePeriods[r, t, v] = list() M.survivalCurvePeriods[r, t, v].append(p) - if M.time_exist.first() < p < M.time_future.last() and p not in M.time_exist | M.time_future: + + # Go through all the periods for each (r, t, v) in order + for r, t, v in M.survivalCurvePeriods: + periods_rtv = sorted(M.survivalCurvePeriods[r, t, v]) + + p_first = periods_rtv[0] + p_last = periods_rtv[-1] + + if p_first != v: msg = ( - 'A row in the SurvivalCurve table used a period that was within the bounds of ' - 'defined periods but was not one of those periods. This value was ignored: ' - f'({r}, >{p}<, {t}, {v})): {M.SurvivalCurve[r, p, t, v]}' + 'LifetimeSurvivalCurve must be defined starting in the vintage period. Must ' + f'define ({r}, >{v}<, {t}, {v})' ) - logger.warning(msg) - for r, t, v in M.survivalCurvePeriods: - M.survivalCurvePeriods[r, t, v] = sorted(M.survivalCurvePeriods[r, t, v]) - for i, p in enumerate(M.survivalCurvePeriods[r, t, v]): + logger.error(msg) + raise ValueError(msg) + + # Let them know about the linear interpolation + if periods_rtv != list(range(p_first, p_last, 1)): + msg = ( + 'For the purposes of investment cost accounting, LifetimeSurvivalCurve must be defined ' + f'for each individual year. For process ({r, t, v}), these yearly fractions will be linearly ' + 'interpolated between defined survival curve periods. Otherwise, these individual years ' + 'can be defined manually.' + ) + logger.info(msg) + + between_periods = [] + for i, p in enumerate(periods_rtv): + + if p < v: + msg = ( + 'LifetimeSurvivalCurve defined for a period that comes before its vintage. ' + f'This is not allowed: ({r, p, t, v})' + ) + logger.error(msg) + raise ValueError(msg) + if i == 0: - continue - p_prev = M.survivalCurvePeriods[r, t, v][i-1] - lsc = M.SurvivalCurve[r, p, t, v] - lsc_prev = M.SurvivalCurve[r, p_prev, t, v] - if lsc > lsc_prev: + continue # Cant look back from first period. Could be zero but hey why not + + # Check that the survival curve monotonically decreases + p_prev = periods_rtv[i-1] + lsc = value(M.LifetimeSurvivalCurve[r, p, t, v]) + lsc_prev = value(M.LifetimeSurvivalCurve[r, p_prev, t, v]) + if lsc - lsc_prev > 0.0001: msg = ( - 'SurvivalCurve fraction increases going forward in time from {} to {}. ' + 'LifetimeSurvivalCurve fraction increases going forward in time from {} to {}. ' 'This is not allowed.' ).format((r, p_prev, t, v), (r, p, t, v)) logger.error(msg) raise ValueError(msg) - + + if p - p_prev > 1: + _between_periods = list(range(p_prev+1, p, 1)) + for _p in _between_periods: + x = (_p - p_prev) / (p - p_prev) + lsc_x = lsc_prev + x * (lsc - lsc_prev) + M.LifetimeSurvivalCurve[r, _p, t, v] = lsc_x + between_periods.extend(_between_periods) + + if lsc < 0.0001: + if p != p_last: + msg = ( + 'There is no need to continue a survival curve beyond fraction ~= 0. ' + f'ignoring periods beyond {p} for ({r, t, v})' + ) + logger.info(msg) + + # Make sure the lifetime for this process aligns with survival curve end + if value(M.LifetimeProcess[r, t, v]) < p - v: + msg = ( + f'The LifetimeProcess parameter for process ({r, t, v}) with survival curve ' + f'does not extend beyond the end of that survival curve in {p}. To agree with ' + f'the survival curve, set LifetimeProcess[{r, t, v}] >= {p-v}' + ) + logger.error(msg) + raise ValueError(msg) + + continue + + # Check that the last period is zero. This is important for investment costs + if p == p_last: + if lsc > 0.0001: + msg = ( + 'Any defined survival curve must continue to zero for the purposes of ' + 'investment cost accounting, even if this period would extend beyond ' + f'defined future periods. Continue ({r, t, v}) to fraction == 0.' + ) + logger.error(msg) + raise ValueError(msg) + + M.survivalCurvePeriods[r, t, v].extend(between_periods) + M.survivalCurvePeriods[r, t, v] = set(M.survivalCurvePeriods[r, t, v]) + def validate_tech_sets(M: 'TemoaModel'): """ diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index 3192533a5..a34826b51 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -317,6 +317,9 @@ def poll_cost_results( if (r, t, v) in M.tech_survival_curve: model_loan_cost, undiscounted_cost = loan_costs_survival_curve( M=M, + r=r, + t=t, + v=v, loan_rate=loan_rate, loan_life=loan_life, capacity=cap, @@ -462,7 +465,7 @@ def loan_costs( """ # dev note: this is a passthrough function. Sole intent is to use the EXACT formula the # model uses for these costs - loan_ar = temoa_rules.loan_annualization_rate(loan_rate=loan_rate, loan_life=loan_life) + loan_ar = temoa_rules.pv_to_annuity(rate=loan_rate, periods=loan_life) model_ic = temoa_rules.loan_cost( capacity, invest_cost, @@ -492,6 +495,9 @@ def loan_costs( def loan_costs_survival_curve( M, + r, + t, + v, loan_rate, # this is referred to as LoanRate in parameters loan_life, capacity, @@ -508,9 +514,12 @@ def loan_costs_survival_curve( """ # dev note: this is a passthrough function. Sole intent is to use the EXACT formula the # model uses for these costs - loan_ar = temoa_rules.loan_annualization_rate(loan_rate=loan_rate, loan_life=loan_life) + loan_ar = temoa_rules.pv_to_annuity(rate=loan_rate, periods=loan_life) model_ic = temoa_rules.loan_cost_survival_curve( M, + r, + t, + v, capacity, invest_cost, loan_annualize=loan_ar, @@ -524,6 +533,9 @@ def loan_costs_survival_curve( global_discount_rate = 0 undiscounted_cost = temoa_rules.loan_cost_survival_curve( M, + r, + t, + v, capacity, invest_cost, loan_annualize=loan_ar, diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index a92fb5f0b..facd8d58d 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -445,8 +445,6 @@ def get_default_process_lifetime(M: 'TemoaModel', r, t, v): :param v: vintage :return: the final lifetime value """ - if (r, t, v) in M.tech_survival_curve: - return M.time_future.last() - v # arbitrary return M.LifetimeTech[r, t] @@ -1817,8 +1815,8 @@ def gather_group_techs(M: 'TemoaModel', t_or_g: str) -> Iterable[str]: return techs -def get_loan_life(M, r, t, _): - return M.LoanLifetimeTech[r, t] +def get_loan_life(M: 'TemoaModel', r, t, v): + return M.LifetimeProcess[r, t, v] def copy_from(other_set): diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 91b22b225..e3fed6e5d 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -336,7 +336,9 @@ def __init__(M, *args, **kwargs): M.LifetimeProcess_rtv = Set(dimen=3, initialize=LifetimeProcessIndices) M.LifetimeProcess = Param(M.LifetimeProcess_rtv, default=get_default_process_lifetime) - M.LoanLifetimeTech = Param(M.regionalIndices, M.tech_all, default=10) + M.LifetimeSurvivalCurve = Param(M.regionalIndices, Integers, M.tech_all, M.vintage_all, default=1, validate=validate_0to1, mutable=True) + M.validate_SurvivalCurve = BuildAction(rule=validate_SurvivalCurve) + M.LoanLifetimeProcess_rtv = Set(dimen=3, initialize=LifetimeLoanProcessIndices) # Dev Note: The LoanLifetimeProcess table *could* be removed. There is no longer a supporting @@ -393,9 +395,6 @@ def __init__(M, *args, **kwargs): M.initialize_CapacityFactors = BuildAction(rule=CheckCapacityFactorProcess) M.initialize_EfficiencyVariable = BuildAction(rule=CheckEfficiencyVariable) - M.SurvivalCurve = Param(M.regionalIndices, Integers, M.tech_all, M.vintage_all, default=1, validate=validate_0to1) - M.validate_SurvivalCurve = BuildAction(rule=validate_SurvivalCurve) - # Define technology cost parameters # dev note: the CostFixed_rptv isn't truly needed, but it is included in a constraint, so # let it go for now diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 3b47d0b17..38ff195ab 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -52,7 +52,7 @@ def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): that occurred up until the period in question, :code:`p`.""" PLF = value(M.ProcessLifeFrac[r, p, t, v]) - LSC = value(M.SurvivalCurve[r, p, t, v]) + LSC = value(M.LifetimeSurvivalCurve[r, p, t, v]) if t not in M.tech_retirement: if v in M.time_exist: @@ -287,10 +287,10 @@ def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): # EOL this period if p == M.time_optimize.first() and v in M.time_exist: # Existing capacity in first period. Remaining existing capacity - retired = value(M.ExistingCapacity[r, t, v]) * value(M.SurvivalCurve[r, p, t, v]) + retired = value(M.ExistingCapacity[r, t, v]) * value(M.LifetimeSurvivalCurve[r, p, t, v]) elif p == v: # New capacity in its vintage period. Remaining new capacity - retired = M.V_NewCapacity[r, t, v] * value(M.SurvivalCurve[r, p, t, v]) + retired = M.V_NewCapacity[r, t, v] * value(M.LifetimeSurvivalCurve[r, p, t, v]) else: # Mid-horizon retirement retired = M.V_Capacity[r, M.time_optimize.prev(p), t, v] @@ -300,7 +300,7 @@ def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): # existing period minus remaining capacity retired = ( value(M.ExistingCapacity[r, t, v]) - * value(M.SurvivalCurve[r, M.time_exist.last(), t, v]) + * value(M.LifetimeSurvivalCurve[r, M.time_exist.last(), t, v]) - M.V_Capacity[r, p, t, v] ) elif p == v: @@ -421,14 +421,20 @@ def TotalCost_rule(M): def annuity_to_pv(rate: float, periods: int) -> float | Expression: """Multiplication factor to convert an annuity to present value""" + if rate == 0: + return periods return ((1 + rate)**periods - 1) / (rate * (1 + rate)**periods) def pv_to_annuity(rate: float, periods: int) -> float | Expression: """Multiplication factor to convert present value to an annuity""" + if rate == 0: + return 1 / periods return (rate * (1 + rate)**periods) / ((1 + rate)**periods - 1) def fv_to_pv(rate: float, periods: int) -> float | Expression: """Multiplication factor to convert a future value to present value""" + if rate == 0: + return 1 return 1 / (1 + rate)**periods @@ -485,6 +491,9 @@ def loan_cost( def loan_cost_survival_curve( M: 'TemoaModel', + r: str, + t: str, + v: str, capacity: float | Var, invest_cost: float, loan_annualize: float, @@ -520,8 +529,12 @@ def loan_cost_survival_curve( annuity * lifetime_loan_process # sum of loan payments over loan period / sum( # redistributed over survival curve within horizon - M.SurvivalCurve[r, p, t, v] - for r, t, v in M.survivalCurvePeriods + value(M.LifetimeSurvivalCurve[r, p, t, v]) + for p in M.survivalCurvePeriods[r, t, v] + if v <= p + ) + * sum( # summed over survival curve within horizon + value(M.LifetimeSurvivalCurve[r, p, t, v]) for p in M.survivalCurvePeriods[r, t, v] if v <= p < P_e ) @@ -532,16 +545,14 @@ def loan_cost_survival_curve( annuity * annuity_to_pv(GDR, lifetime_loan_process) # PV of all loan payments, discounted to vintage year using GDR / sum( # redistributed over survival curve within horizon - M.SurvivalCurve[r, p, t, v] # reamortised over survival curve of process using GDR - * fv_to_pv(GDR, p - vintage) - for r, t, v in M.survivalCurvePeriods + value(M.LifetimeSurvivalCurve[r, p, t, v]) # reamortised over survival curve of process using GDR + * fv_to_pv(GDR, p - vintage + 1) for p in M.survivalCurvePeriods[r, t, v] if v <= p ) * sum( # PV of all reamortised costs (within planning horizon) - M.SurvivalCurve[r, p, t, v] - * fv_to_pv(GDR, p - vintage) - for r, t, v in M.survivalCurvePeriods + value(M.LifetimeSurvivalCurve[r, p, t, v]) + * fv_to_pv(GDR, p - vintage + 1) for p in M.survivalCurvePeriods[r, t, v] if v <= p < P_e ) @@ -611,6 +622,9 @@ def PeriodCost_rule(M: 'TemoaModel', p): loan_costs += sum( loan_cost_survival_curve( M, + r, + S_t, + S_v, M.V_NewCapacity[r, S_t, S_v], value(M.CostInvest[r, S_t, S_v]), value(M.LoanAnnualize[r, S_t, S_v]), @@ -3181,25 +3195,26 @@ def ParamProcessLifeFraction_rule(M: 'TemoaModel', r, p, t, v): return frac -def loan_annualization_rate(loan_rate: float | None, loan_life: int | float) -> float: - """ - This calculation is broken out specifically so that it can be used for param creation - and separately to calculate loan costs rather than rely on fully-built model parameters - :param loan_rate: - :param loan_life: +# devnote: made redundant by time-value equations for objective function +# def loan_annualization_rate(loan_rate: float | None, loan_life: int | float) -> float: +# """ +# This calculation is broken out specifically so that it can be used for param creation +# and separately to calculate loan costs rather than rely on fully-built model parameters +# :param loan_rate: +# :param loan_life: - """ - if not loan_rate: - # dev note: this should not be needed as the LoanRate param has a default (see the definition) - return 1.0 / loan_life - annualized_rate = loan_rate / (1.0 - (1.0 + loan_rate) ** (-loan_life)) - return annualized_rate +# """ +# if not loan_rate: +# # dev note: this should not be needed as the LoanRate param has a default (see the definition) +# return 1.0 / loan_life +# annualized_rate = loan_rate / (1.0 - (1.0 + loan_rate) ** (-loan_life)) +# return annualized_rate def ParamLoanAnnualize_rule(M: 'TemoaModel', r, t, v): dr = value(M.LoanRate[r, t, v]) lln = value(M.LoanLifetimeProcess[r, t, v]) - annualized_rate = loan_annualization_rate(dr, lln) + annualized_rate = pv_to_annuity(dr, lln) return annualized_rate diff --git a/temoa/utilities/db_migration_v3_to_v3_1.py b/temoa/utilities/db_migration_v3_to_v3_1.py index 5dc980dc7..d92340f79 100644 --- a/temoa/utilities/db_migration_v3_to_v3_1.py +++ b/temoa/utilities/db_migration_v3_to_v3_1.py @@ -104,7 +104,7 @@ def column_check(old_name: str, new_name: str) -> bool: ('', 'LifetimeProcess'), ('', 'LifetimeTech'), ('', 'LinkedTech'), - ('', 'LoanLifetimeTech'), + # ('', 'LoanLifetimeTech'), ('', 'LoanRate'), ('', 'MetaData'), ('', 'MetaDataReal'), @@ -292,6 +292,25 @@ def column_check(old_name: str, new_name: str) -> bool: print(f'Transfered {len(data)} rows from {old_name} to {new_name}') +# LoanLifetimeTech -> LoanLifetimeProcess +try: + data = con_old.execute('SELECT * FROM LoanLifetimeTech').fetchall() + + if not data: + print('No data for: ' + old_name) + else: + new_data = [] + for r, t, l, note in data: + vints = [v[0] for v in con_old.execute(f'SELECT vintage FROM Efficiency WHERE region=="{r}" AND tech="{t}"').fetchall()] + for v in vints: + data.append((r, t, v, l, note)) + query = f'INSERT OR REPLACE INTO LoanLifetimeProcess VALUES (?,?,?,?,?)' + con_new.executemany(query, new_data) + print(f'Transfered {len(new_data)} rows from LifetimeLoanTech to LifetimeLoanProcess') + +except sqlite3.OperationalError: + print('TABLE NOT FOUND: ' + old_name) + # Warn about incompatible changes print('\n --- The following transfers were impossible due to incompatible changes. Transfer manually. ---') for old_name, new_name in no_transfer.items(): diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 373b28b14..310233029 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -371,14 +371,16 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE LoanLifetimeTech +CREATE TABLE LoanLifetimeProcess ( region TEXT, tech TEXT REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), lifetime REAL, notes TEXT, - PRIMARY KEY (region, tech) + PRIMARY KEY (region, tech, vintage) ); CREATE TABLE LoanRate ( @@ -912,7 +914,7 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE SurvivalCurve +CREATE TABLE LifetimeSurvivalCurve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -974,10 +976,10 @@ CREATE TABLE TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count REAL NOT NULL, + num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (count > 0) + CHECK (num_days > 0) ); CREATE TABLE TimePeriodType ( diff --git a/tests/testing_data/emissions.sqlite b/tests/testing_data/emissions.sqlite deleted file mode 100644 index 2d7f7fd9d5bb80ad4943fbec895fcea20d6742f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 667648 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 0) + CHECK (num_days > 0) ); CREATE TABLE TimePeriodType ( diff --git a/tests/testing_data/materials.sqlite b/tests/testing_data/materials.sqlite deleted file mode 100644 index 8d03a52b2e0f40f1755f2690792599a333cdc724..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 684032 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 0) + CHECK (num_days > 0) ); CREATE TABLE TimePeriodType ( diff --git a/tests/testing_data/mediumville.sqlite b/tests/testing_data/mediumville.sqlite deleted file mode 100644 index 8f4dfb6d7c278da0c74bc539d474d19af6e4495a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 667648 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 0) + CHECK (num_days > 0) ); INSERT INTO TimeSeasonSequential VALUES(2000,1,'summer','charge',152.5,NULL); INSERT INTO TimeSeasonSequential VALUES(2000,2,'sept_w1','discharge',7,NULL); diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index 686ed6c79..2e36648e6 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -350,14 +350,16 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE LoanLifetimeTech +CREATE TABLE LoanLifetimeProcess ( region TEXT, tech TEXT REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), lifetime REAL, notes TEXT, - PRIMARY KEY (region, tech) + PRIMARY KEY (region, tech, vintage) ); CREATE TABLE LoanRate ( @@ -883,7 +885,7 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE SurvivalCurve +CREATE TABLE LifetimeSurvivalCurve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -943,10 +945,10 @@ CREATE TABLE TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count REAL NOT NULL, + num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (count > 0) + CHECK (num_days > 0) ); CREATE TABLE TimePeriodType ( diff --git a/tests/testing_data/simple_linked_tech.sqlite b/tests/testing_data/simple_linked_tech.sqlite deleted file mode 100644 index d0828f711ace5de6292c87ee73928b141b7df019..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 667648 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 YA%Fk^2q1s}0tg_000Iagu(JaHKYN_c>Hq)$ diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index 08f707ad3..7b3074139 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -358,14 +358,16 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE LoanLifetimeTech +CREATE TABLE LoanLifetimeProcess ( region TEXT, tech TEXT REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), lifetime REAL, notes TEXT, - PRIMARY KEY (region, tech) + PRIMARY KEY (region, tech, vintage) ); CREATE TABLE LoanRate ( @@ -904,7 +906,7 @@ CREATE TABLE StorageDuration PRIMARY KEY (region, tech) ); INSERT INTO StorageDuration VALUES('electricville','batt',10.0,NULL); -CREATE TABLE SurvivalCurve +CREATE TABLE LifetimeSurvivalCurve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -968,10 +970,10 @@ CREATE TABLE TimeSeasonSequential seas_seq TEXT, season TEXT REFERENCES TimeSeason (season), - count REAL NOT NULL, + num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (count > 0) + CHECK (num_days > 0) ); CREATE TABLE TimePeriodType ( diff --git a/tests/testing_data/storageville.sqlite b/tests/testing_data/storageville.sqlite deleted file mode 100644 index 414d8062ce2e24ca7af34996ff90e69e35f93961..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 667648 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 0) + CHECK (num_days > 0) ); CREATE TABLE TimePeriodType ( diff --git a/tests/testing_data/test_system.sqlite b/tests/testing_data/test_system.sqlite deleted file mode 100644 index ff2eaf7a5390bc71b852c038f2941376a17e93d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 667648 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 0) + CHECK (num_days > 0) ); CREATE TABLE TimePeriodType ( diff --git a/tests/testing_data/utopia.sqlite b/tests/testing_data/utopia.sqlite deleted file mode 100644 index 98cfc05f6855c8eb0804224a7d33114d1a171527..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 667648 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%0A7WVsB@^P4D$T$i~?L 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 V0w4eaAOHd&00JNY0w4ea{{cLN^^5=j From 544dbc012f3a026116777ebf85164dafd60da28e Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 18 Jun 2025 11:40:05 -0400 Subject: [PATCH 131/587] Update v3.1 migrator for loan lifetime change --- data_files/example_dbs/materials.sql | 36 +++++++------------ data_files/example_dbs/morris_utopia.sql | 36 +++++++------------ data_files/example_dbs/seasonal_storage.sql | 33 ++++++----------- data_files/example_dbs/stepped_demand.sql | 36 +++++++------------ data_files/example_dbs/test_system.sql | 36 +++++++------------ data_files/example_dbs/utopia.sql | 36 +++++++------------ data_files/temoa_schema_v3_1.sql | 39 +++++++-------------- temoa/utilities/db_migration_v3_to_v3_1.py | 31 ++++++++-------- tests/testing_data/emissions.sql | 36 +++++++------------ tests/testing_data/materials.sql | 36 +++++++------------ tests/testing_data/mediumville.sql | 36 +++++++------------ tests/testing_data/seasonal_storage.sql | 33 ++++++----------- tests/testing_data/simple_linked_tech.sql | 36 +++++++------------ tests/testing_data/storageville.sql | 36 +++++++------------ tests/testing_data/test_system.sql | 36 +++++++------------ tests/testing_data/utopia.sql | 36 +++++++------------ 16 files changed, 194 insertions(+), 374 deletions(-) diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index 4a6820023..d4795509e 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -55,8 +55,7 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -72,8 +71,7 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -408,8 +406,7 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -658,8 +655,7 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -880,8 +876,7 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1005,8 +1000,7 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -1229,8 +1223,7 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1252,8 +1245,7 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1275,8 +1267,7 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1321,8 +1312,7 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -1438,8 +1428,7 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -1461,8 +1450,7 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index ae2e2b26a..befc915d1 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -61,8 +61,7 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -96,8 +95,7 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -516,8 +514,7 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -657,8 +654,7 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -918,8 +914,7 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1054,8 +1049,7 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -1230,8 +1224,7 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1253,8 +1246,7 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1276,8 +1268,7 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1321,8 +1312,7 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -1406,8 +1396,7 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -1426,8 +1415,7 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql index 774d6e79b..896dea4cc 100644 --- a/data_files/example_dbs/seasonal_storage.sql +++ b/data_files/example_dbs/seasonal_storage.sql @@ -56,8 +56,7 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -73,8 +72,7 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -220,8 +218,7 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -278,8 +275,7 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -484,8 +480,7 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -611,8 +606,7 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -781,8 +775,7 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -804,8 +797,7 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -827,8 +819,7 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -872,8 +863,7 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -1044,8 +1034,7 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index 94221d317..bf3d42b8a 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -61,8 +61,7 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -78,8 +77,7 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -351,8 +349,7 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -436,8 +433,7 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -656,8 +652,7 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -792,8 +787,7 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -962,8 +956,7 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -985,8 +978,7 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1008,8 +1000,7 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1053,8 +1044,7 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -1158,8 +1148,7 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -1202,8 +1191,7 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index 3a2efbe88..e87cae734 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -61,8 +61,7 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -78,8 +77,7 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -464,8 +462,7 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -632,8 +629,7 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -882,8 +878,7 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1015,8 +1010,7 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -1215,8 +1209,7 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1238,8 +1231,7 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1261,8 +1253,7 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1307,8 +1298,7 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -1398,8 +1388,7 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -1421,8 +1410,7 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 351076e13..93d653cb1 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -61,8 +61,7 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -96,8 +95,7 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -512,8 +510,7 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -652,8 +649,7 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -913,8 +909,7 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1049,8 +1044,7 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -1225,8 +1219,7 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1248,8 +1241,7 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1271,8 +1263,7 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1316,8 +1307,7 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -1401,8 +1391,7 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -1421,8 +1410,7 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index 65f774d83..f3392c1d4 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -65,8 +65,7 @@ CREATE TABLE IF NOT EXISTS CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -82,8 +81,7 @@ CREATE TABLE IF NOT EXISTS CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -215,8 +213,7 @@ CREATE TABLE IF NOT EXISTS DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -261,8 +258,7 @@ CREATE TABLE IF NOT EXISTS EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -469,8 +465,7 @@ CREATE TABLE IF NOT EXISTS LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -594,8 +589,7 @@ CREATE TABLE IF NOT EXISTS LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -764,8 +758,7 @@ CREATE TABLE IF NOT EXISTS OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -787,8 +780,7 @@ CREATE TABLE IF NOT EXISTS OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -810,8 +802,7 @@ CREATE TABLE IF NOT EXISTS OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -854,8 +845,7 @@ CREATE TABLE IF NOT EXISTS TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -901,12 +891,10 @@ VALUES ('ps', 'storage production technology'); -- ( -- period INTEGER -- REFERENCES TimePeriod (period), --- season TEXT --- REFERENCES TimeSeason (season), +-- season TEXT, -- tod TEXT -- REFERENCES TimeOfDay (tod), --- season_next TEXT --- REFERENCES TimeSeason (season), +-- season_next TEXT, -- tod_next TEXT -- REFERENCES TimeOfDay (tod), -- notes TEXT, @@ -941,8 +929,7 @@ CREATE TABLE IF NOT EXISTS TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/temoa/utilities/db_migration_v3_to_v3_1.py b/temoa/utilities/db_migration_v3_to_v3_1.py index d92340f79..0603fa871 100644 --- a/temoa/utilities/db_migration_v3_to_v3_1.py +++ b/temoa/utilities/db_migration_v3_to_v3_1.py @@ -104,7 +104,6 @@ def column_check(old_name: str, new_name: str) -> bool: ('', 'LifetimeProcess'), ('', 'LifetimeTech'), ('', 'LinkedTech'), - # ('', 'LoanLifetimeTech'), ('', 'LoanRate'), ('', 'MetaData'), ('', 'MetaDataReal'), @@ -294,22 +293,22 @@ def column_check(old_name: str, new_name: str) -> bool: # LoanLifetimeTech -> LoanLifetimeProcess try: - data = con_old.execute('SELECT * FROM LoanLifetimeTech').fetchall() - - if not data: - print('No data for: ' + old_name) - else: - new_data = [] - for r, t, l, note in data: - vints = [v[0] for v in con_old.execute(f'SELECT vintage FROM Efficiency WHERE region=="{r}" AND tech="{t}"').fetchall()] - for v in vints: - data.append((r, t, v, l, note)) - query = f'INSERT OR REPLACE INTO LoanLifetimeProcess VALUES (?,?,?,?,?)' - con_new.executemany(query, new_data) - print(f'Transfered {len(new_data)} rows from LifetimeLoanTech to LifetimeLoanProcess') - + data = con_old.execute('SELECT region, tech, lifetime, notes FROM LoanLifetimeTech').fetchall() except sqlite3.OperationalError: - print('TABLE NOT FOUND: ' + old_name) + print('TABLE NOT FOUND: LoanLifetimeTech') + +if not data: + print('No data for: LoanLifetimeTech') +else: + new_data = [] + for row in data: + vints = [v[0] for v in con_old.execute(f'SELECT vintage FROM Efficiency WHERE region=="{row[0]}" AND tech="{row[1]}"').fetchall()] + for v in vints: + new_data.append((row[0], row[1], v, row[2], row[3])) + query = f'INSERT OR REPLACE INTO LoanLifetimeProcess VALUES (?,?,?,?,?)' + con_new.executemany(query, new_data) + print(f'Transfered {len(new_data)} rows from LifetimeLoanTech to LifetimeLoanProcess') + # Warn about incompatible changes print('\n --- The following transfers were impossible due to incompatible changes. Transfer manually. ---') diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 310233029..f969bab54 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -55,8 +55,7 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -72,8 +71,7 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -228,8 +226,7 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -283,8 +280,7 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -499,8 +495,7 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -632,8 +627,7 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -802,8 +796,7 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -825,8 +818,7 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -848,8 +840,7 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -893,8 +884,7 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -961,8 +951,7 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -974,8 +963,7 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index 4a6820023..d4795509e 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -55,8 +55,7 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -72,8 +71,7 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -408,8 +406,7 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -658,8 +655,7 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -880,8 +876,7 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1005,8 +1000,7 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -1229,8 +1223,7 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1252,8 +1245,7 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1275,8 +1267,7 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1321,8 +1312,7 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -1438,8 +1428,7 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -1461,8 +1450,7 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 2ba346157..482de2802 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -62,8 +62,7 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -81,8 +80,7 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -261,8 +259,7 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -341,8 +338,7 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -575,8 +571,7 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -714,8 +709,7 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -888,8 +882,7 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -911,8 +904,7 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -934,8 +926,7 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -985,8 +976,7 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -1053,8 +1043,7 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -1066,8 +1055,7 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index 774d6e79b..896dea4cc 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -56,8 +56,7 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -73,8 +72,7 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -220,8 +218,7 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -278,8 +275,7 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -484,8 +480,7 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -611,8 +606,7 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -781,8 +775,7 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -804,8 +797,7 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -827,8 +819,7 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -872,8 +863,7 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -1044,8 +1034,7 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index 2e36648e6..00a7ee6ec 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -61,8 +61,7 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -78,8 +77,7 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -216,8 +214,7 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -268,8 +265,7 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -479,8 +475,7 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -604,8 +599,7 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -775,8 +769,7 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -798,8 +791,7 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -821,8 +813,7 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -866,8 +857,7 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -930,8 +920,7 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -943,8 +932,7 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index 7b3074139..d09f04d76 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -61,8 +61,7 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -78,8 +77,7 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -216,8 +214,7 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -276,8 +273,7 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -487,8 +483,7 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -617,8 +612,7 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -787,8 +781,7 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -810,8 +803,7 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -833,8 +825,7 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -878,8 +869,7 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -955,8 +945,7 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -968,8 +957,7 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 3a2efbe88..e87cae734 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -61,8 +61,7 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -78,8 +77,7 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -464,8 +462,7 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -632,8 +629,7 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -882,8 +878,7 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1015,8 +1010,7 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -1215,8 +1209,7 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1238,8 +1231,7 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1261,8 +1253,7 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1307,8 +1298,7 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -1398,8 +1388,7 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -1421,8 +1410,7 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 351076e13..93d653cb1 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -61,8 +61,7 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -96,8 +95,7 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -512,8 +510,7 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -652,8 +649,7 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -913,8 +909,7 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1049,8 +1044,7 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -1225,8 +1219,7 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1248,8 +1241,7 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1271,8 +1263,7 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1316,8 +1307,7 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -1401,8 +1391,7 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -1421,8 +1410,7 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES TimeSeason (season), + season TEXT, num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), From d69d36068aa4927dcef9ed66baed365c3f34fd8e Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 19 Jun 2025 08:08:09 -0400 Subject: [PATCH 132/587] Rename tech_survival_curve to survival_curve_processes --- temoa/temoa_model/hybrid_loader.py | 2 +- temoa/temoa_model/table_data_puller.py | 2 +- temoa/temoa_model/temoa_initialize.py | 2 +- temoa/temoa_model/temoa_model.py | 2 +- temoa/temoa_model/temoa_rules.py | 4 ++-- tests/testing_data/mediumville_sets.json | 2 +- tests/testing_data/test_system_sets.json | 2 +- tests/testing_data/utopia_sets.json | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 91417736d..fcb9a2cd7 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -740,7 +740,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N if self.table_exists("LifetimeSurvivalCurve"): raw = cur.execute('SELECT region, period, tech, vintage, fraction FROM main.LifetimeSurvivalCurve').fetchall() load_element(M.LifetimeSurvivalCurve, raw, self.viable_rtv, val_loc=(0, 2, 3)) - load_element(M.tech_survival_curve, list(set([(row[0], row[2], row[3]) for row in raw]))) + load_element(M.survival_curve_processes, list(set([(row[0], row[2], row[3]) for row in raw]))) # LoanLifetimeProcess if self.table_exists("LoanLifetimeProcess"): diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index a34826b51..3b4652570 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -314,7 +314,7 @@ def poll_cost_results( loan_life = value(LLN[r, t, v]) loan_rate = value(M.LoanRate[r, t, v]) - if (r, t, v) in M.tech_survival_curve: + if (r, t, v) in M.survival_curve_processes: model_loan_cost, undiscounted_cost = loan_costs_survival_curve( M=M, r=r, diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index facd8d58d..0709ca1b3 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -793,7 +793,7 @@ def CreateSparseDicts(M: 'TemoaModel'): if t not in M.tech_uncap and any(( p <= v+l_lifetime < p + value(M.PeriodLength[p]), # natural eol this period t in M.tech_retirement and v < p <= v+l_lifetime - value(M.PeriodLength[p]), # allowed early retirement - (r, t, v) in M.tech_survival_curve and v <= p <= v+l_lifetime + (r, t, v) in M.survival_curve_processes and v <= p <= v+l_lifetime )): if (r, t, v) not in M.retirementPeriods: M.retirementPeriods[r, t, v] = set() diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index e3fed6e5d..1db5005fd 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -216,7 +216,7 @@ def __init__(M, *args, **kwargs): # Note2: I think this has been fixed but I can't tell what the problem was. Suspect # it was the old StorageInit constraint M.tech_retirement = Set(within=M.tech_with_capacity)# - M.tech_storage) - M.tech_survival_curve = Set(within=M.regionalIndices * M.tech_with_capacity * M.vintage_all) + M.survival_curve_processes = Set(within=M.regionalIndices * M.tech_with_capacity * M.vintage_all) M.validate_techs = BuildAction(rule=validate_tech_sets) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 38ff195ab..a2c1b73aa 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -617,7 +617,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): vintage=S_v, ) for r, S_t, S_v in M.CostInvest.sparse_iterkeys() - if S_v == p and (r, S_t, S_v) not in M.tech_survival_curve + if S_v == p and (r, S_t, S_v) not in M.survival_curve_processes ) loan_costs += sum( loan_cost_survival_curve( @@ -635,7 +635,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): vintage=S_v, ) for r, S_t, S_v in M.CostInvest.sparse_iterkeys() - if S_v == p and (r, S_t, S_v) in M.tech_survival_curve + if S_v == p and (r, S_t, S_v) in M.survival_curve_processes ) fixed_costs = sum( diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index a14d8abc2..9cd374b51 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -4342,7 +4342,7 @@ "tech_storage": [ "batt" ], - "tech_survival_curve": [], + "survival_curve_processes": [], "tech_uncap": [], "tech_upramping": [ "EH" diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 56bff7119..83a81c5db 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -46666,7 +46666,7 @@ "tech_storage": [ "E_BATT" ], - "tech_survival_curve": [], + "survival_curve_processes": [], "tech_uncap": [ "S_IMPETH", "S_IMPNG", diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index ecff3bebc..a41eabed6 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -25759,7 +25759,7 @@ "tech_storage": [ "E51" ], - "tech_survival_curve": [], + "survival_curve_processes": [], "tech_uncap": [ "IMPDSL1", "IMPHYD", From 7d3cb8d537664f3ff58f651b131d5edde1e821bd Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 19 Jun 2025 09:08:23 -0400 Subject: [PATCH 133/587] Rearrange survival curves a little --- temoa/temoa_model/hybrid_loader.py | 1 - .../temoa_model/model_checking/validators.py | 102 ----------- temoa/temoa_model/table_data_puller.py | 2 +- temoa/temoa_model/temoa_initialize.py | 160 +++++++++++++----- temoa/temoa_model/temoa_model.py | 15 +- temoa/temoa_model/temoa_rules.py | 16 +- tests/testing_data/mediumville_sets.json | 1 - tests/testing_data/test_system_sets.json | 1 - tests/testing_data/utopia_sets.json | 1 - 9 files changed, 129 insertions(+), 170 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index fcb9a2cd7..68958eddb 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -740,7 +740,6 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N if self.table_exists("LifetimeSurvivalCurve"): raw = cur.execute('SELECT region, period, tech, vintage, fraction FROM main.LifetimeSurvivalCurve').fetchall() load_element(M.LifetimeSurvivalCurve, raw, self.viable_rtv, val_loc=(0, 2, 3)) - load_element(M.survival_curve_processes, list(set([(row[0], row[2], row[3]) for row in raw]))) # LoanLifetimeProcess if self.table_exists("LoanLifetimeProcess"): diff --git a/temoa/temoa_model/model_checking/validators.py b/temoa/temoa_model/model_checking/validators.py index e4241d36e..e5b4a60be 100644 --- a/temoa/temoa_model/model_checking/validators.py +++ b/temoa/temoa_model/model_checking/validators.py @@ -407,108 +407,6 @@ def validate_ReserveMargin(M: 'TemoaModel'): ) -def validate_SurvivalCurve(M: 'TemoaModel'): - - # Collect rptv indices into (r, t, v): p dictionary - for r, p, t, v in M.LifetimeSurvivalCurve: - if (r, t, v) not in M.survivalCurvePeriods: - M.survivalCurvePeriods[r, t, v] = list() - M.survivalCurvePeriods[r, t, v].append(p) - - # Go through all the periods for each (r, t, v) in order - for r, t, v in M.survivalCurvePeriods: - periods_rtv = sorted(M.survivalCurvePeriods[r, t, v]) - - p_first = periods_rtv[0] - p_last = periods_rtv[-1] - - if p_first != v: - msg = ( - 'LifetimeSurvivalCurve must be defined starting in the vintage period. Must ' - f'define ({r}, >{v}<, {t}, {v})' - ) - logger.error(msg) - raise ValueError(msg) - - # Let them know about the linear interpolation - if periods_rtv != list(range(p_first, p_last, 1)): - msg = ( - 'For the purposes of investment cost accounting, LifetimeSurvivalCurve must be defined ' - f'for each individual year. For process ({r, t, v}), these yearly fractions will be linearly ' - 'interpolated between defined survival curve periods. Otherwise, these individual years ' - 'can be defined manually.' - ) - logger.info(msg) - - between_periods = [] - for i, p in enumerate(periods_rtv): - - if p < v: - msg = ( - 'LifetimeSurvivalCurve defined for a period that comes before its vintage. ' - f'This is not allowed: ({r, p, t, v})' - ) - logger.error(msg) - raise ValueError(msg) - - if i == 0: - continue # Cant look back from first period. Could be zero but hey why not - - # Check that the survival curve monotonically decreases - p_prev = periods_rtv[i-1] - lsc = value(M.LifetimeSurvivalCurve[r, p, t, v]) - lsc_prev = value(M.LifetimeSurvivalCurve[r, p_prev, t, v]) - if lsc - lsc_prev > 0.0001: - msg = ( - 'LifetimeSurvivalCurve fraction increases going forward in time from {} to {}. ' - 'This is not allowed.' - ).format((r, p_prev, t, v), (r, p, t, v)) - logger.error(msg) - raise ValueError(msg) - - if p - p_prev > 1: - _between_periods = list(range(p_prev+1, p, 1)) - for _p in _between_periods: - x = (_p - p_prev) / (p - p_prev) - lsc_x = lsc_prev + x * (lsc - lsc_prev) - M.LifetimeSurvivalCurve[r, _p, t, v] = lsc_x - between_periods.extend(_between_periods) - - if lsc < 0.0001: - if p != p_last: - msg = ( - 'There is no need to continue a survival curve beyond fraction ~= 0. ' - f'ignoring periods beyond {p} for ({r, t, v})' - ) - logger.info(msg) - - # Make sure the lifetime for this process aligns with survival curve end - if value(M.LifetimeProcess[r, t, v]) < p - v: - msg = ( - f'The LifetimeProcess parameter for process ({r, t, v}) with survival curve ' - f'does not extend beyond the end of that survival curve in {p}. To agree with ' - f'the survival curve, set LifetimeProcess[{r, t, v}] >= {p-v}' - ) - logger.error(msg) - raise ValueError(msg) - - continue - - # Check that the last period is zero. This is important for investment costs - if p == p_last: - if lsc > 0.0001: - msg = ( - 'Any defined survival curve must continue to zero for the purposes of ' - 'investment cost accounting, even if this period would extend beyond ' - f'defined future periods. Continue ({r, t, v}) to fraction == 0.' - ) - logger.error(msg) - raise ValueError(msg) - - M.survivalCurvePeriods[r, t, v].extend(between_periods) - M.survivalCurvePeriods[r, t, v] = set(M.survivalCurvePeriods[r, t, v]) - - def validate_tech_sets(M: 'TemoaModel'): """ Check tech sets for any forbidden intersections diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index 3b4652570..1fbbc9d06 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -314,7 +314,7 @@ def poll_cost_results( loan_life = value(LLN[r, t, v]) loan_rate = value(M.LoanRate[r, t, v]) - if (r, t, v) in M.survival_curve_processes: + if M.isSurvivalCurveProcess[r, t, v]: model_loan_cost, undiscounted_cost = loan_costs_survival_curve( M=M, r=r, diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 0709ca1b3..ff190b8d3 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -314,7 +314,7 @@ def CheckEfficiencyVariable(M: 'TemoaModel'): # Still want it for end of life flows continue for p in M.processPeriods[r, t, v]: - M.efficiencyVariables[r, p, i, t, v, o] = False + M.isEfficiencyVariable[r, p, i, t, v, o] = False count_rpitvo[r, p, i, t, v, o] = 0 annual = set() @@ -346,7 +346,7 @@ def CheckEfficiencyVariable(M: 'TemoaModel'): for (r, p, i, t, v, o), count in count_rpitvo.items(): if count > 0: - M.efficiencyVariables[r, p, i, t, v, o] = True + M.isEfficiencyVariable[r, p, i, t, v, o] = True if count < num_seg: logger.warning( 'Some but not all EfficiencyVariable values were set (%i out of a possible %i) for: %s' @@ -361,7 +361,7 @@ def CheckCapacityFactorProcess(M: 'TemoaModel'): # Pull CapacityFactorTech by default for r, p, s, d, t in M.CapacityFactor_rpsdt: for v in M.processVintages[r, p, t]: - M.capacityFactorProcesses[r, p, t, v] = False + M.isCapacityFactorProcess[r, p, t, v] = False count_rptv[r, p, t, v] = 0 # Check for bad values and count up the good ones @@ -380,7 +380,7 @@ def CheckCapacityFactorProcess(M: 'TemoaModel'): num_seg = len(M.time_season[p]) * len(M.time_of_day) for (r, p, t, v), count in count_rptv.items(): if count > 0: - M.capacityFactorProcesses[r, p, t, v] = True + M.isCapacityFactorProcess[r, p, t, v] = True if count < num_seg: logger.warning( 'Some but not all processes were set in CapacityFactorProcess (%i out of a possible %i) for: %s' @@ -793,7 +793,7 @@ def CreateSparseDicts(M: 'TemoaModel'): if t not in M.tech_uncap and any(( p <= v+l_lifetime < p + value(M.PeriodLength[p]), # natural eol this period t in M.tech_retirement and v < p <= v+l_lifetime - value(M.PeriodLength[p]), # allowed early retirement - (r, t, v) in M.survival_curve_processes and v <= p <= v+l_lifetime + M.isSurvivalCurveProcess[r, t, v] and v <= p <= v+l_lifetime )): if (r, t, v) not in M.retirementPeriods: M.retirementPeriods[r, t, v] = set() @@ -955,9 +955,9 @@ def CreateSparseDicts(M: 'TemoaModel'): # A dictionary of whether a storage tech is seasonal, just to speed things up for t in M.tech_storage: - M.is_seasonal_storage[t] = False + M.isSeasonalStorage[t] = False for t in M.tech_seasonal_storage: - M.is_seasonal_storage[t] = True + M.isSeasonalStorage[t] = True M.activeFlow_rpsditvo = set( (r, p, s, d, i, t, v, o) @@ -1132,6 +1132,112 @@ def CreateTimeSequence(M: 'TemoaModel'): logger.debug('Created time sequence.') + +def CreateSurvivalCurve(M: 'TemoaModel'): + + for (r, _, t, v, _) in M.Efficiency: + M.isSurvivalCurveProcess[r, t, v] = False # by default + + # Collect rptv indices into (r, t, v): p dictionary + for r, p, t, v in M.LifetimeSurvivalCurve: + if (r, t, v) not in M.survivalCurvePeriods: + M.survivalCurvePeriods[r, t, v] = list() + M.survivalCurvePeriods[r, t, v].append(p) + M.isSurvivalCurveProcess[r, t, v] = True + + # Go through all the periods for each (r, t, v) in order + for r, t, v in M.survivalCurvePeriods: + periods_rtv = sorted(M.survivalCurvePeriods[r, t, v]) + + p_first = periods_rtv[0] + p_last = periods_rtv[-1] + + if p_first != v: + msg = ( + 'LifetimeSurvivalCurve must be defined starting in the vintage period. Must ' + f'define ({r}, >{v}<, {t}, {v})' + ) + logger.error(msg) + raise ValueError(msg) + + # Let them know about the linear interpolation + if periods_rtv != list(range(p_first, p_last, 1)): + msg = ( + 'For the purposes of investment cost accounting, LifetimeSurvivalCurve must be defined ' + f'for each individual year. For process ({r, t, v}), these yearly fractions will be linearly ' + 'interpolated between defined survival curve periods. Otherwise, these individual years ' + 'can be defined manually.' + ) + logger.info(msg) + + between_periods = [] + for i, p in enumerate(periods_rtv): + + if p < v: + msg = ( + 'LifetimeSurvivalCurve defined for a period that comes before its vintage. ' + f'This is not allowed: ({r, p, t, v})' + ) + logger.error(msg) + raise ValueError(msg) + + if i == 0: + continue # Cant look back from first period. Could be zero but hey why not + + # Check that the survival curve monotonically decreases + p_prev = periods_rtv[i-1] + lsc = value(M.LifetimeSurvivalCurve[r, p, t, v]) + lsc_prev = value(M.LifetimeSurvivalCurve[r, p_prev, t, v]) + if lsc - lsc_prev > 0.0001: + msg = ( + 'LifetimeSurvivalCurve fraction increases going forward in time from {} to {}. ' + 'This is not allowed.' + ).format((r, p_prev, t, v), (r, p, t, v)) + logger.error(msg) + raise ValueError(msg) + + if p - p_prev > 1: + _between_periods = list(range(p_prev+1, p, 1)) + for _p in _between_periods: + x = (_p - p_prev) / (p - p_prev) + lsc_x = lsc_prev + x * (lsc - lsc_prev) + M.LifetimeSurvivalCurve[r, _p, t, v] = lsc_x + between_periods.extend(_between_periods) + + if lsc < 0.0001: + if p != p_last: + msg = ( + 'There is no need to continue a survival curve beyond fraction ~= 0. ' + f'ignoring periods beyond {p} for ({r, t, v})' + ) + logger.info(msg) + + # Make sure the lifetime for this process aligns with survival curve end + if value(M.LifetimeProcess[r, t, v]) < p - v: + msg = ( + f'The LifetimeProcess parameter for process ({r, t, v}) with survival curve ' + f'does not extend beyond the end of that survival curve in {p}. To agree with ' + f'the survival curve, set LifetimeProcess[{r, t, v}] >= {p-v}' + ) + logger.error(msg) + raise ValueError(msg) + + continue + + # Check that the last period is zero. This is important for investment costs + if p == p_last: + if lsc > 0.0001: + msg = ( + 'Any defined survival curve must continue to zero for the purposes of ' + 'investment cost accounting, even if this period would extend beyond ' + f'defined future periods. Continue ({r, t, v}) to fraction == 0.' + ) + logger.error(msg) + raise ValueError(msg) + + M.survivalCurvePeriods[r, t, v].extend(between_periods) + M.survivalCurvePeriods[r, t, v] = set(M.survivalCurvePeriods[r, t, v]) + # --------------------------------------------------------------- # Create sparse parameter indices. @@ -1193,46 +1299,6 @@ def RegionalGlobalInitializedIndices(M: 'TemoaModel'): return indices -# def GroupShareIndices(M: 'TemoaModel'): -# indices = set( -# (r, p, t, g, op) -# for g in M.tech_group_names -# for r, p, t in M.groupRegionActiveFlow_rpt -# for op in M.operator -# if t in M.tech_group_members[g] -# ) - -# return indices - - -# def GroupShareIndices(M: 'TemoaModel'): -# indices = set( -# (r, p, g1, g2, op) -# for op in M.operator -# for g1 in M.tech_or_group -# for g2 in M.tech_or_group -# for r, p, t in M.groupRegionActiveFlow_rpt -# for _r, _p, _t in M.groupRegionActiveFlow_rpt -# if r==_r and p==_p -# if t in gather_group_techs(M, g1) and _t in gather_group_techs(M, g2) -# ) - -# return indices - - -# def TwoGroupShareIndices(M: 'TemoaModel'): -# indices = set( -# (r, p, g1, g2, op) -# for g1 in M.tech_group_names -# for g2 in M.tech_group_names -# for r, p, _t in M.groupRegionActiveFlow_rpt -# for op in M.operator -# if _t in M.tech_group_members[g2] -# ) - -# return indices - - def EmissionActivityIndices(M: 'TemoaModel'): indices = set( (r, e, i, t, v, o) diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 1db5005fd..243c9bfc5 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -45,7 +45,6 @@ no_slash_or_pipe, validate_SeasonSequential, validate_ReserveMargin, - validate_SurvivalCurve, ) from temoa.temoa_model.temoa_initialize import * from temoa.temoa_model.temoa_rules import * @@ -112,7 +111,7 @@ def __init__(M, *args, **kwargs): M.processPeriods = dict() # {(r, t, v): set(p)} M.retirementPeriods = dict() # {(r, t, v): set(p)} periods in which a process can economically or naturally retire M.processVintages = dict() - M.survivalCurvePeriods = dict() # {(r, t, v): set(p)} periods for which the process has a defined survival fraction + M.survivalCurvePeriods: dict[tuple, set] = dict() # {(r, t, v): set(p)} periods for which the process has a defined survival fraction """current available (within lifespan) vintages {(r, p, t) : set(v)}""" M.baseloadVintages = dict() @@ -132,15 +131,16 @@ def __init__(M, *args, **kwargs): M.time_next = dict() # {(p, s, d): (s_next, d_next)} sequence of following time slices M.time_next_sequential = dict() # {(p, s_seq): (s_seq_next)} next virtual storage season M.sequential_to_season = dict() # {(p, s_seq): (s)} season matching this virtual storage season - M.is_seasonal_storage = dict() # to avoid slow O(n2) behaviour in storage constraints ################################################ # Switching Sets # - # (used to optimize big tables/params) # + # (to avoid slow searches in initialisation) # ################################################ - M.efficiencyVariables: dict[tuple, bool] = dict() # which efficiencies have variable indexing - M.capacityFactorProcesses: dict[tuple, bool] = dict() # which capacity factors have have period-vintage indexing + M.isEfficiencyVariable: dict[tuple, bool] = dict() # {(r, p, i, t, v, o): bool} which efficiencies have variable indexing + M.isCapacityFactorProcess: dict[tuple, bool] = dict() # {(r, p, t, v): bool} which capacity factors have have period-vintage indexing + M.isSeasonalStorage: dict[tuple, bool] = dict() # {t: bool} whether a storage tech is seasonal storage + M.isSurvivalCurveProcess: dict[str, bool] = dict() # {(r, t, v): bool} whether a process uses survival curves. ################################################ # Model Sets # @@ -216,7 +216,6 @@ def __init__(M, *args, **kwargs): # Note2: I think this has been fixed but I can't tell what the problem was. Suspect # it was the old StorageInit constraint M.tech_retirement = Set(within=M.tech_with_capacity)# - M.tech_storage) - M.survival_curve_processes = Set(within=M.regionalIndices * M.tech_with_capacity * M.vintage_all) M.validate_techs = BuildAction(rule=validate_tech_sets) @@ -337,7 +336,7 @@ def __init__(M, *args, **kwargs): M.LifetimeProcess = Param(M.LifetimeProcess_rtv, default=get_default_process_lifetime) M.LifetimeSurvivalCurve = Param(M.regionalIndices, Integers, M.tech_all, M.vintage_all, default=1, validate=validate_0to1, mutable=True) - M.validate_SurvivalCurve = BuildAction(rule=validate_SurvivalCurve) + M.Create_SurvivalCurve = BuildAction(rule=CreateSurvivalCurve) M.LoanLifetimeProcess_rtv = Set(dimen=3, initialize=LifetimeLoanProcessIndices) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index a2c1b73aa..e5b5f3262 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -617,7 +617,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): vintage=S_v, ) for r, S_t, S_v in M.CostInvest.sparse_iterkeys() - if S_v == p and (r, S_t, S_v) not in M.survival_curve_processes + if S_v == p and not M.isSurvivalCurveProcess[r, S_t, S_v] ) loan_costs += sum( loan_cost_survival_curve( @@ -635,7 +635,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): vintage=S_v, ) for r, S_t, S_v in M.CostInvest.sparse_iterkeys() - if S_v == p and (r, S_t, S_v) in M.survival_curve_processes + if S_v == p and M.isSurvivalCurveProcess[r, S_t, S_v] ) fixed_costs = sum( @@ -1370,7 +1370,7 @@ def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): """ # We allow a non-zero daily delta only in the case of seasonal storage - if M.is_seasonal_storage[t] and d == M.time_of_day.last(): + if M.isSeasonalStorage[t] and d == M.time_of_day.last(): return Constraint.Skip # handled by SeasonalStorageEnergy_Constraint # This is the sum of all input=i sent TO storage tech t of vintage v with @@ -1472,7 +1472,7 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): """ - if M.is_seasonal_storage[t]: + if M.isSeasonalStorage[t]: return Constraint.Skip # redundant on SeasonalStorageEnergyUpperBound energy_capacity = ( @@ -1673,14 +1673,14 @@ def LimitStorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v, op): * value(M.LimitStorageFraction[r, p, s, d, t, v, op]) ) - if M.is_seasonal_storage[t]: + if M.isSeasonalStorage[t]: s_seq = s # sequential season s = M.sequential_to_season[p, s_seq] # non-sequential season # adjust the storage level to the individual-day level energy_level = M.V_StorageLevel[r, p, s, d, t, v] / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) - if M.is_seasonal_storage[t]: + if M.isSeasonalStorage[t]: # seasonal storage upper energy limit is absolute energy_level = M.V_SeasonalStorageLevel[r, p, s_seq, t, v] + energy_level * value(M.TimeSeasonSequential[p, s_seq, s]) @@ -3302,13 +3302,13 @@ def operator_expression(lhs: Expression | None, operator: str | None, rhs: Expre # Much faster to build a dictionary and check that than check the parameter # indices directly every time - saves build time def get_variable_efficiency(M: 'TemoaModel', r, p, s, d, i, t, v, o): - if M.efficiencyVariables[r, p, i, t, v, o]: + if M.isEfficiencyVariable[r, p, i, t, v, o]: return value(M.Efficiency[r, i, t, v, o]) * value(M.EfficiencyVariable[r, p, s, d, i, t, v, o]) else: return value(M.Efficiency[r, i, t, v, o]) def get_capacity_factor(M: 'TemoaModel', r, p, s, d, t, v): - if M.capacityFactorProcesses[r, p, t, v]: + if M.isCapacityFactorProcess[r, p, t, v]: return value(M.CapacityFactorProcess[r, p, s, d, t, v]) else: return value(M.CapacityFactorTech[r, p, s, d, t]) \ No newline at end of file diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 9cd374b51..a8957e3d2 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -4342,7 +4342,6 @@ "tech_storage": [ "batt" ], - "survival_curve_processes": [], "tech_uncap": [], "tech_upramping": [ "EH" diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 83a81c5db..867c86a63 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -46666,7 +46666,6 @@ "tech_storage": [ "E_BATT" ], - "survival_curve_processes": [], "tech_uncap": [ "S_IMPETH", "S_IMPNG", diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index a41eabed6..3b85e3590 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -25759,7 +25759,6 @@ "tech_storage": [ "E51" ], - "survival_curve_processes": [], "tech_uncap": [ "IMPDSL1", "IMPHYD", From 332f2500fd1b0c4b5b1065aacce798d509d6006d Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 19 Jun 2025 10:03:13 -0400 Subject: [PATCH 134/587] Some code cleanup --- temoa/temoa_model/table_data_puller.py | 2 -- temoa/temoa_model/temoa_initialize.py | 28 ++++++++++++++++++-------- temoa/temoa_model/temoa_rules.py | 11 ++++------ 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index 1fbbc9d06..b79c83214 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -527,7 +527,6 @@ def loan_costs_survival_curve( P_0=p_0, P_e=p_e, GDR=global_discount_rate, - vintage=vintage, ) # Override the GDR to get the undiscounted value global_discount_rate = 0 @@ -543,7 +542,6 @@ def loan_costs_survival_curve( P_0=p_0, P_e=p_e, GDR=global_discount_rate, - vintage=vintage, ) return model_ic, undiscounted_cost diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index ff190b8d3..f0f756edc 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1134,6 +1134,8 @@ def CreateTimeSequence(M: 'TemoaModel'): def CreateSurvivalCurve(M: 'TemoaModel'): + + rtv_interpolated = set() # so we only need one warning for (r, _, t, v, _) in M.Efficiency: M.isSurvivalCurveProcess[r, t, v] = False # by default @@ -1161,14 +1163,8 @@ def CreateSurvivalCurve(M: 'TemoaModel'): raise ValueError(msg) # Let them know about the linear interpolation - if periods_rtv != list(range(p_first, p_last, 1)): - msg = ( - 'For the purposes of investment cost accounting, LifetimeSurvivalCurve must be defined ' - f'for each individual year. For process ({r, t, v}), these yearly fractions will be linearly ' - 'interpolated between defined survival curve periods. Otherwise, these individual years ' - 'can be defined manually.' - ) - logger.info(msg) + if periods_rtv != list(range(p_first, p_last+1, 1)): + rtv_interpolated.add((r, t, v)) between_periods = [] for i, p in enumerate(periods_rtv): @@ -1221,6 +1217,14 @@ def CreateSurvivalCurve(M: 'TemoaModel'): ) logger.error(msg) raise ValueError(msg) + elif value(M.LifetimeProcess[r, t, v]) != p - v: + msg = ( + f'The LifetimeProcess parameter for process ({r, t, v}) with survival curve ' + f'does match the end of that survival curve in {p}. To agree with ' + f'the survival curve and suppress some warnings, set ' + f'LifetimeProcess[{r, t, v}] = {p-v}' + ) + logger.info(msg) continue @@ -1238,6 +1242,14 @@ def CreateSurvivalCurve(M: 'TemoaModel'): M.survivalCurvePeriods[r, t, v].extend(between_periods) M.survivalCurvePeriods[r, t, v] = set(M.survivalCurvePeriods[r, t, v]) + if rtv_interpolated: + msg = ( + 'For the purposes of investment cost accounting, LifetimeSurvivalCurve must be defined ' + f'for each individual year. Gaps between defined years will be filled by linear interpolation. ' + 'Otherwise, these individual years can be defined manually. Interpolated processes: {}' + ).format([rtv for rtv in rtv_interpolated]) + logger.info(msg) + # --------------------------------------------------------------- # Create sparse parameter indices. diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index e5b5f3262..478c6390f 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -501,7 +501,6 @@ def loan_cost_survival_curve( P_0: int, P_e: int, GDR: float, - vintage: int, ) -> float | Expression: """ function to calculate the loan cost. It can be used with fixed values to produce a hard number or @@ -513,7 +512,6 @@ def loan_cost_survival_curve( :param P_0: the year to discount the costs back to :param P_e: the 'end year' or cutoff year for loan payments :param GDR: Global Discount Rate - :param vintage: the base year of the loan :return: fixed number or pyomo expression based on input types """ @@ -546,17 +544,17 @@ def loan_cost_survival_curve( * annuity_to_pv(GDR, lifetime_loan_process) # PV of all loan payments, discounted to vintage year using GDR / sum( # redistributed over survival curve within horizon value(M.LifetimeSurvivalCurve[r, p, t, v]) # reamortised over survival curve of process using GDR - * fv_to_pv(GDR, p - vintage + 1) + * fv_to_pv(GDR, p - v + 1) for p in M.survivalCurvePeriods[r, t, v] - if v <= p + if v <= p # this shouldnt be possible but play it safe ) * sum( # PV of all reamortised costs (within planning horizon) value(M.LifetimeSurvivalCurve[r, p, t, v]) - * fv_to_pv(GDR, p - vintage + 1) + * fv_to_pv(GDR, p - v + 1) for p in M.survivalCurvePeriods[r, t, v] if v <= p < P_e ) - * fv_to_pv(GDR, vintage - P_0) # finally, discounted from vintage year to P_0 + * fv_to_pv(GDR, v - P_0) # finally, discounted from vintage year to P_0 ) return res @@ -632,7 +630,6 @@ def PeriodCost_rule(M: 'TemoaModel', p): P_0, P_e, GDR, - vintage=S_v, ) for r, S_t, S_v in M.CostInvest.sparse_iterkeys() if S_v == p and M.isSurvivalCurveProcess[r, S_t, S_v] From 98057a1500f5e04a62a1bf1c813daef8fcdf9fd1 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 19 Jun 2025 10:12:54 -0400 Subject: [PATCH 135/587] Add survival curves example db and test --- data_files/example_dbs/survival_curve.sql | 1148 +++++++++++++++++ tests/conftest.py | 1 + tests/legacy_test_values.py | 8 + tests/test_full_runs.py | 1 + .../config_survival_curve.toml | 73 ++ tests/testing_data/survival_curve.sql | 1148 +++++++++++++++++ 6 files changed, 2379 insertions(+) create mode 100644 data_files/example_dbs/survival_curve.sql create mode 100644 tests/testing_configs/config_survival_curve.toml create mode 100644 tests/testing_data/survival_curve.sql diff --git a/data_files/example_dbs/survival_curve.sql b/data_files/example_dbs/survival_curve.sql new file mode 100644 index 000000000..45bb3541e --- /dev/null +++ b/data_files/example_dbs/survival_curve.sql @@ -0,0 +1,1148 @@ +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE MetaData +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); +INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); +INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); +INSERT INTO MetaData VALUES('days_per_period',365,'count of days in each period'); +CREATE TABLE MetaDataReal +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); +CREATE TABLE OutputDualVariable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE OutputObjective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE SectorLabel +( + sector TEXT, + PRIMARY KEY (sector) +); +CREATE TABLE CapacityCredit +( + region TEXT, + period INTEGER, + tech TEXT, + vintage INTEGER, + credit REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage), + CHECK (credit >= 0 AND credit <= 1) +); +CREATE TABLE CapacityFactorProcess +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE CapacityFactorTech +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE CapacityToActivity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + c2a REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE Commodity +( + name TEXT + PRIMARY KEY, + flag TEXT + REFERENCES CommodityType (label), + description TEXT +); +INSERT INTO Commodity VALUES('source','s',NULL); +INSERT INTO Commodity VALUES('demand','d',NULL); +CREATE TABLE CommodityType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO CommodityType VALUES('p','physical commodity'); +INSERT INTO CommodityType VALUES('a','annual commodity'); +INSERT INTO CommodityType VALUES('e','emissions commodity'); +INSERT INTO CommodityType VALUES('d','demand commodity'); +INSERT INTO CommodityType VALUES('s','source commodity'); +INSERT INTO CommodityType VALUES('w','waste commodity'); +INSERT INTO CommodityType VALUES('wa','waste annual commodity'); +INSERT INTO CommodityType VALUES('wp','waste physical commodity'); +CREATE TABLE ConstructionInput +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); +CREATE TABLE CostEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT NOT NULL + REFERENCES Commodity (name), + cost REAL NOT NULL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE CostFixed +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +INSERT INTO CostFixed VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); +CREATE TABLE CostInvest +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +INSERT INTO CostInvest VALUES('region','tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('region','tech_future',2030,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('region','tech_future',2035,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('region','tech_future',2040,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('region','tech_future',2045,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('region','tech_future',2050,1.0,NULL,NULL); +CREATE TABLE CostVariable +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +INSERT INTO CostVariable VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); +CREATE TABLE Demand +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + commodity TEXT + REFERENCES Commodity (name), + demand REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, commodity) +); +INSERT INTO Demand VALUES('region',2025,'demand',1.0,NULL,NULL); +INSERT INTO Demand VALUES('region',2030,'demand',1.0,NULL,NULL); +INSERT INTO Demand VALUES('region',2035,'demand',1.0,NULL,NULL); +INSERT INTO Demand VALUES('region',2040,'demand',1.0,NULL,NULL); +INSERT INTO Demand VALUES('region',2045,'demand',1.0,NULL,NULL); +INSERT INTO Demand VALUES('region',2050,'demand',1.0,NULL,NULL); +CREATE TABLE DemandSpecificDistribution +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + demand_name TEXT + REFERENCES Commodity (name), + dsd REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), + CHECK (dsd >= 0 AND dsd <= 1) +); +CREATE TABLE EndOfLifeOutput +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) +); +CREATE TABLE Efficiency +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +INSERT INTO Efficiency VALUES('region','source','tech_ancient',1994,'demand',1.0,NULL); +INSERT INTO Efficiency VALUES('region','source','tech_old',2010,'demand',1.0,NULL); +INSERT INTO Efficiency VALUES('region','source','tech_current',2025,'demand',1.0,NULL); +INSERT INTO Efficiency VALUES('region','source','tech_future',2030,'demand',1.0,NULL); +INSERT INTO Efficiency VALUES('region','source','tech_future',2035,'demand',1.0,NULL); +INSERT INTO Efficiency VALUES('region','source','tech_future',2040,'demand',1.0,NULL); +INSERT INTO Efficiency VALUES('region','source','tech_future',2045,'demand',1.0,NULL); +INSERT INTO Efficiency VALUES('region','source','tech_future',2050,'demand',1.0,NULL); +CREATE TABLE EfficiencyVariable +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE EmissionActivity +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) +); +CREATE TABLE EmissionEmbodied +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE EmissionEndOfLife +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE ExistingCapacity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +INSERT INTO ExistingCapacity VALUES('region','tech_ancient',1994,3.0,NULL,NULL); +INSERT INTO ExistingCapacity VALUES('region','tech_old',2010,0.7,NULL,NULL); +CREATE TABLE TechGroup +( + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE LoanLifetimeProcess +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE LifetimeProcess +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE LifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +INSERT INTO LifetimeTech VALUES('region','tech_ancient',35.0,NULL); +INSERT INTO LifetimeTech VALUES('region','tech_old',35.0,NULL); +INSERT INTO LifetimeTech VALUES('region','tech_current',35.0,NULL); +INSERT INTO LifetimeTech VALUES('region','tech_future',35.0,NULL); +CREATE TABLE Operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO Operator VALUES('e','equal to'); +INSERT INTO Operator VALUES('le','less than or equal to'); +INSERT INTO Operator VALUES('ge','greater than or equal to'); +CREATE TABLE LimitGrowthCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitDegrowthCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitGrowthNewCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitDegrowthNewCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitGrowthNewCapacityDelta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitDegrowthNewCapacityDelta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitStorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) +); +CREATE TABLE LimitActivity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE LimitActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE LimitAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, operator), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE LimitCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE LimitCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE LimitNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE LimitNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE LimitResource +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitSeasonalCapacityFactor +( + region TEXT + REFERENCES Region (region), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) +); +CREATE TABLE LimitTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputFlowOut +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); +CREATE TABLE PlanningReserveMargin +( + region TEXT + PRIMARY KEY + REFERENCES Region (region), + margin REAL +); +CREATE TABLE RampDown +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE RampUp +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE Region +( + region TEXT + PRIMARY KEY, + notes TEXT +); +INSERT INTO Region VALUES('region',NULL); +CREATE TABLE TimeSegmentFraction +( + period INTEGER + REFERENCES TimePeriod (period), + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + segfrac REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segfrac >= 0 AND segfrac <= 1) +); +INSERT INTO TimeSegmentFraction VALUES(2025,'s','d',1.0,NULL); +INSERT INTO TimeSegmentFraction VALUES(2030,'s','d',1.0,NULL); +INSERT INTO TimeSegmentFraction VALUES(2035,'s','d',1.0,NULL); +INSERT INTO TimeSegmentFraction VALUES(2040,'s','d',1.0,NULL); +INSERT INTO TimeSegmentFraction VALUES(2045,'s','d',1.0,NULL); +INSERT INTO TimeSegmentFraction VALUES(2050,'s','d',1.0,NULL); +CREATE TABLE StorageDuration +( + region TEXT, + tech TEXT, + duration REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE LifetimeSurvivalCurve +( + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +INSERT INTO LifetimeSurvivalCurve VALUES('region',1994,'tech_ancient',1994,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',1999,'tech_ancient',1994,0.96999999999999992894,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2004,'tech_ancient',1994,0.88000000000000007105,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2009,'tech_ancient',1994,0.62000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2014,'tech_ancient',1994,0.27000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2019,'tech_ancient',1994,0.08,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2029,'tech_ancient',1994,0.0,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2010,'tech_old',2010,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2015,'tech_old',2010,0.96999999999999992894,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2020,'tech_old',2010,0.88000000000000007105,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2025,'tech_old',2010,0.62000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2030,'tech_old',2010,0.27000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_old',2010,0.08,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_old',2010,0.0,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2025,'tech_current',2025,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2030,'tech_current',2025,0.96999999999999992894,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_current',2025,0.88000000000000007105,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_current',2025,0.62000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_current',2025,0.27000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_current',2025,0.08,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_current',2025,0.0,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2030,'tech_future',2030,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_future',2030,0.96999999999999992894,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_future',2030,0.88000000000000007105,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2030,0.62000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2030,0.27000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2030,0.08,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2030,0.0,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_future',2035,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_future',2035,0.96999999999999992894,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2035,0.88000000000000007105,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2035,0.62000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2035,0.27000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2035,0.08,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2070,'tech_future',2035,0.0,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_future',2040,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2040,0.96999999999999992894,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2040,0.88000000000000007105,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2040,0.62000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2040,0.27000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2040,0.08,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2075,'tech_future',2040,0.0,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2045,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2045,0.96999999999999992894,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2045,0.88000000000000007105,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2045,0.62000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2045,0.27000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2070,'tech_future',2045,0.08,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2080,'tech_future',2045,0.0,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2050,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2050,0.96999999999999992894,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2050,0.88000000000000007105,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2050,0.62000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2070,'tech_future',2050,0.27000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2075,'tech_future',2050,0.08,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2085,'tech_future',2050,0.0,NULL); +CREATE TABLE TechnologyType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO TechnologyType VALUES('r','resource technology'); +INSERT INTO TechnologyType VALUES('p','production technology'); +INSERT INTO TechnologyType VALUES('pb','baseload production technology'); +INSERT INTO TechnologyType VALUES('ps','storage production technology'); +CREATE TABLE TimeOfDay +( + sequence INTEGER UNIQUE, + tod TEXT + PRIMARY KEY +); +INSERT INTO TimeOfDay VALUES(0,'d'); +CREATE TABLE TimePeriod +( + sequence INTEGER UNIQUE, + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES TimePeriodType (label) +); +INSERT INTO TimePeriod VALUES(-2,1994,'e'); +INSERT INTO TimePeriod VALUES(-1,2010,'e'); +INSERT INTO TimePeriod VALUES(0,2025,'f'); +INSERT INTO TimePeriod VALUES(1,2030,'f'); +INSERT INTO TimePeriod VALUES(2,2035,'f'); +INSERT INTO TimePeriod VALUES(3,2040,'f'); +INSERT INTO TimePeriod VALUES(4,2045,'f'); +INSERT INTO TimePeriod VALUES(5,2050,'f'); +INSERT INTO TimePeriod VALUES(6,2055,'f'); +CREATE TABLE TimeSeason +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT, + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +INSERT INTO TimeSeason VALUES(2025,0,'s',NULL); +INSERT INTO TimeSeason VALUES(2030,1,'s',NULL); +INSERT INTO TimeSeason VALUES(2035,2,'s',NULL); +INSERT INTO TimeSeason VALUES(2040,3,'s',NULL); +INSERT INTO TimeSeason VALUES(2045,4,'s',NULL); +INSERT INTO TimeSeason VALUES(2050,5,'s',NULL); +CREATE TABLE TimeSeasonSequential +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + seas_seq TEXT, + season TEXT, + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) +); +CREATE TABLE TimePeriodType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO TimePeriodType VALUES('e','existing vintages'); +INSERT INTO TimePeriodType VALUES('f','future'); +CREATE TABLE OutputEmission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE RPSRequirement +( + region TEXT NOT NULL + REFERENCES Region (region), + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech_group TEXT NOT NULL + REFERENCES TechGroup (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE TechGroupMember +( + group_name TEXT + REFERENCES TechGroup (group_name), + tech TEXT + REFERENCES Technology (tech), + PRIMARY KEY (group_name, tech) +); +CREATE TABLE Technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES TechnologyType (label) +); +INSERT INTO Technology VALUES('tech_ancient','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('tech_old','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('tech_current','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('tech_future','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +CREATE TABLE OutputCost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES TimePeriod (period), + FOREIGN KEY (tech) REFERENCES Technology (tech) +); +COMMIT; diff --git a/tests/conftest.py b/tests/conftest.py index 9946cb06a..eefc25cd7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -77,6 +77,7 @@ def refresh_databases() -> None: ('materials.sql', 'materials.sqlite'), ('simple_linked_tech.sql', 'simple_linked_tech.sqlite'), ('seasonal_storage.sql', 'seasonal_storage.sqlite'), + ('survival_curve.sql', 'survival_curve.sqlite'), ) for src, db in databases: if Path.exists(data_output_path / db): diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index b591c7b79..e583f12b5 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -85,4 +85,12 @@ class ExpectedVals(Enum): ExpectedVals.CONSTR_COUNT: 182, ExpectedVals.VAR_COUNT: 90, }, + 'survival_curve': { + # added 2025/06/19 after addition of survival curves + ExpectedVals.OBJ_VALUE: 31.8083, + ExpectedVals.EFF_DOMAIN_SIZE: 64, + ExpectedVals.EFF_INDEX_SIZE: 8, + ExpectedVals.CONSTR_COUNT: 101, + ExpectedVals.VAR_COUNT: 103, + }, } diff --git a/tests/test_full_runs.py b/tests/test_full_runs.py index f9b977113..203a2b748 100644 --- a/tests/test_full_runs.py +++ b/tests/test_full_runs.py @@ -43,6 +43,7 @@ {'name': 'test_system', 'filename': 'config_test_system.toml'}, {'name': 'mediumville', 'filename': 'config_mediumville.toml'}, {'name': 'seasonal_storage', 'filename': 'config_seasonal_storage.toml'}, + {'name': 'survival_curve', 'filename': 'config_survival_curve.toml'}, ] myopic_files = [{'name': 'myopic utopia', 'filename': 'config_utopia_myopic.toml'}] diff --git a/tests/testing_configs/config_survival_curve.toml b/tests/testing_configs/config_survival_curve.toml new file mode 100644 index 000000000..3c449e41c --- /dev/null +++ b/tests/testing_configs/config_survival_curve.toml @@ -0,0 +1,73 @@ +# this config is used for testing in test_full_runs.py +scenario = "test run" +scenario_mode = "perfect_foresight" + +input_database = "tests/testing_outputs/survival_curve.sqlite" +output_database = "tests/testing_outputs/survival_curve.sqlite" +neos = false + +# solver +solver_name = "gurobi" + +# generate an excel file in the output_files folder +save_excel = false + +# save the duals in the output .sqlite database +save_duals = false + +# save a copy of the pyomo-generated lp file to the outputs folder (may be large file!) +save_lp_file = false + +# ------------------------------------ +# MODEL PARAMETERS +# these are specific to each model +# ------------------------------------ + +# What seasons represent in the model +# Options: +# 'sequential_days' +# Seasons are a set of days in order, with each season representing only one day. Examples +# might be a model of a representative week with 7 days or a whole-year model with 365 days. +# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# 'representative_periods' +# Each season represents a number of days, though not necessarily in any particular order. +# If using inter-season constraints like seasonal storage or ramp rates, the true sequence +# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# the Technology table. +# 'seasonal_timeslices' +# Each season represents a sequential slice of the year, with one or many days represented per +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out +# in the schema). This is an advanced feature and not recommended for most users. Seasonal +# storage must be tagged and the TimeSeasonSequential table filled. +time_sequencing = 'seasonal_timeslices' + +# How contributions to the planning reserve margin are calculated +# Options: +# 'static' +# Traditional planning reserve. Contributions are independent of hourly availability: +# capacity value = available capacity * capacity credit. +# 'dynamic' +# The capacity credit is treated as a capacity derate factor (forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = available capacity * capacity credit * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * capacity credit +reserve_margin = 'static' + +# --------------------------------------------------- +# MODE OPTIONS +# options below are mode-specific and will be ignored +# if the run is not executed in that mode. +# --------------------------------------------------- +[MGA] +cost_epsilon = 0.03 # 3% relaxation on optimal cost +iteration_limit = 15 # max iterations to perform +time_limit_hrs = 1 # max time +axis = "tech_category_activity" # use the tech activity Manager to control exploration based on categories in Tech +weighting = "hull_expansion" # use a convex hull expansion algorithm to weight exploration + +[myopic] +myopic_view = 2 # number of periods seen at one iteration \ No newline at end of file diff --git a/tests/testing_data/survival_curve.sql b/tests/testing_data/survival_curve.sql new file mode 100644 index 000000000..45bb3541e --- /dev/null +++ b/tests/testing_data/survival_curve.sql @@ -0,0 +1,1148 @@ +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE MetaData +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); +INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); +INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); +INSERT INTO MetaData VALUES('days_per_period',365,'count of days in each period'); +CREATE TABLE MetaDataReal +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); +CREATE TABLE OutputDualVariable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE OutputObjective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE SectorLabel +( + sector TEXT, + PRIMARY KEY (sector) +); +CREATE TABLE CapacityCredit +( + region TEXT, + period INTEGER, + tech TEXT, + vintage INTEGER, + credit REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage), + CHECK (credit >= 0 AND credit <= 1) +); +CREATE TABLE CapacityFactorProcess +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE CapacityFactorTech +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE CapacityToActivity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + c2a REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE Commodity +( + name TEXT + PRIMARY KEY, + flag TEXT + REFERENCES CommodityType (label), + description TEXT +); +INSERT INTO Commodity VALUES('source','s',NULL); +INSERT INTO Commodity VALUES('demand','d',NULL); +CREATE TABLE CommodityType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO CommodityType VALUES('p','physical commodity'); +INSERT INTO CommodityType VALUES('a','annual commodity'); +INSERT INTO CommodityType VALUES('e','emissions commodity'); +INSERT INTO CommodityType VALUES('d','demand commodity'); +INSERT INTO CommodityType VALUES('s','source commodity'); +INSERT INTO CommodityType VALUES('w','waste commodity'); +INSERT INTO CommodityType VALUES('wa','waste annual commodity'); +INSERT INTO CommodityType VALUES('wp','waste physical commodity'); +CREATE TABLE ConstructionInput +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); +CREATE TABLE CostEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT NOT NULL + REFERENCES Commodity (name), + cost REAL NOT NULL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE CostFixed +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +INSERT INTO CostFixed VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO CostFixed VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); +CREATE TABLE CostInvest +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +INSERT INTO CostInvest VALUES('region','tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('region','tech_future',2030,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('region','tech_future',2035,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('region','tech_future',2040,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('region','tech_future',2045,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('region','tech_future',2050,1.0,NULL,NULL); +CREATE TABLE CostVariable +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +INSERT INTO CostVariable VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); +CREATE TABLE Demand +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + commodity TEXT + REFERENCES Commodity (name), + demand REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, commodity) +); +INSERT INTO Demand VALUES('region',2025,'demand',1.0,NULL,NULL); +INSERT INTO Demand VALUES('region',2030,'demand',1.0,NULL,NULL); +INSERT INTO Demand VALUES('region',2035,'demand',1.0,NULL,NULL); +INSERT INTO Demand VALUES('region',2040,'demand',1.0,NULL,NULL); +INSERT INTO Demand VALUES('region',2045,'demand',1.0,NULL,NULL); +INSERT INTO Demand VALUES('region',2050,'demand',1.0,NULL,NULL); +CREATE TABLE DemandSpecificDistribution +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + demand_name TEXT + REFERENCES Commodity (name), + dsd REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), + CHECK (dsd >= 0 AND dsd <= 1) +); +CREATE TABLE EndOfLifeOutput +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) +); +CREATE TABLE Efficiency +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +INSERT INTO Efficiency VALUES('region','source','tech_ancient',1994,'demand',1.0,NULL); +INSERT INTO Efficiency VALUES('region','source','tech_old',2010,'demand',1.0,NULL); +INSERT INTO Efficiency VALUES('region','source','tech_current',2025,'demand',1.0,NULL); +INSERT INTO Efficiency VALUES('region','source','tech_future',2030,'demand',1.0,NULL); +INSERT INTO Efficiency VALUES('region','source','tech_future',2035,'demand',1.0,NULL); +INSERT INTO Efficiency VALUES('region','source','tech_future',2040,'demand',1.0,NULL); +INSERT INTO Efficiency VALUES('region','source','tech_future',2045,'demand',1.0,NULL); +INSERT INTO Efficiency VALUES('region','source','tech_future',2050,'demand',1.0,NULL); +CREATE TABLE EfficiencyVariable +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE EmissionActivity +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) +); +CREATE TABLE EmissionEmbodied +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE EmissionEndOfLife +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE ExistingCapacity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +INSERT INTO ExistingCapacity VALUES('region','tech_ancient',1994,3.0,NULL,NULL); +INSERT INTO ExistingCapacity VALUES('region','tech_old',2010,0.7,NULL,NULL); +CREATE TABLE TechGroup +( + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE LoanLifetimeProcess +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE LifetimeProcess +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE LifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +INSERT INTO LifetimeTech VALUES('region','tech_ancient',35.0,NULL); +INSERT INTO LifetimeTech VALUES('region','tech_old',35.0,NULL); +INSERT INTO LifetimeTech VALUES('region','tech_current',35.0,NULL); +INSERT INTO LifetimeTech VALUES('region','tech_future',35.0,NULL); +CREATE TABLE Operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO Operator VALUES('e','equal to'); +INSERT INTO Operator VALUES('le','less than or equal to'); +INSERT INTO Operator VALUES('ge','greater than or equal to'); +CREATE TABLE LimitGrowthCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitDegrowthCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitGrowthNewCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitDegrowthNewCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitGrowthNewCapacityDelta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitDegrowthNewCapacityDelta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitStorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) +); +CREATE TABLE LimitActivity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE LimitActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE LimitAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, operator), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE LimitCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE LimitCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE LimitNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE LimitNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE LimitResource +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitSeasonalCapacityFactor +( + region TEXT + REFERENCES Region (region), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT, + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) +); +CREATE TABLE LimitTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputFlowOut +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); +CREATE TABLE PlanningReserveMargin +( + region TEXT + PRIMARY KEY + REFERENCES Region (region), + margin REAL +); +CREATE TABLE RampDown +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE RampUp +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE Region +( + region TEXT + PRIMARY KEY, + notes TEXT +); +INSERT INTO Region VALUES('region',NULL); +CREATE TABLE TimeSegmentFraction +( + period INTEGER + REFERENCES TimePeriod (period), + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + segfrac REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segfrac >= 0 AND segfrac <= 1) +); +INSERT INTO TimeSegmentFraction VALUES(2025,'s','d',1.0,NULL); +INSERT INTO TimeSegmentFraction VALUES(2030,'s','d',1.0,NULL); +INSERT INTO TimeSegmentFraction VALUES(2035,'s','d',1.0,NULL); +INSERT INTO TimeSegmentFraction VALUES(2040,'s','d',1.0,NULL); +INSERT INTO TimeSegmentFraction VALUES(2045,'s','d',1.0,NULL); +INSERT INTO TimeSegmentFraction VALUES(2050,'s','d',1.0,NULL); +CREATE TABLE StorageDuration +( + region TEXT, + tech TEXT, + duration REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE LifetimeSurvivalCurve +( + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +INSERT INTO LifetimeSurvivalCurve VALUES('region',1994,'tech_ancient',1994,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',1999,'tech_ancient',1994,0.96999999999999992894,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2004,'tech_ancient',1994,0.88000000000000007105,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2009,'tech_ancient',1994,0.62000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2014,'tech_ancient',1994,0.27000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2019,'tech_ancient',1994,0.08,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2029,'tech_ancient',1994,0.0,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2010,'tech_old',2010,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2015,'tech_old',2010,0.96999999999999992894,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2020,'tech_old',2010,0.88000000000000007105,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2025,'tech_old',2010,0.62000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2030,'tech_old',2010,0.27000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_old',2010,0.08,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_old',2010,0.0,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2025,'tech_current',2025,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2030,'tech_current',2025,0.96999999999999992894,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_current',2025,0.88000000000000007105,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_current',2025,0.62000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_current',2025,0.27000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_current',2025,0.08,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_current',2025,0.0,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2030,'tech_future',2030,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_future',2030,0.96999999999999992894,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_future',2030,0.88000000000000007105,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2030,0.62000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2030,0.27000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2030,0.08,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2030,0.0,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_future',2035,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_future',2035,0.96999999999999992894,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2035,0.88000000000000007105,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2035,0.62000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2035,0.27000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2035,0.08,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2070,'tech_future',2035,0.0,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_future',2040,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2040,0.96999999999999992894,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2040,0.88000000000000007105,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2040,0.62000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2040,0.27000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2040,0.08,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2075,'tech_future',2040,0.0,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2045,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2045,0.96999999999999992894,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2045,0.88000000000000007105,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2045,0.62000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2045,0.27000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2070,'tech_future',2045,0.08,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2080,'tech_future',2045,0.0,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2050,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2050,0.96999999999999992894,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2050,0.88000000000000007105,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2050,0.62000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2070,'tech_future',2050,0.27000000000000001776,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2075,'tech_future',2050,0.08,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2085,'tech_future',2050,0.0,NULL); +CREATE TABLE TechnologyType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO TechnologyType VALUES('r','resource technology'); +INSERT INTO TechnologyType VALUES('p','production technology'); +INSERT INTO TechnologyType VALUES('pb','baseload production technology'); +INSERT INTO TechnologyType VALUES('ps','storage production technology'); +CREATE TABLE TimeOfDay +( + sequence INTEGER UNIQUE, + tod TEXT + PRIMARY KEY +); +INSERT INTO TimeOfDay VALUES(0,'d'); +CREATE TABLE TimePeriod +( + sequence INTEGER UNIQUE, + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES TimePeriodType (label) +); +INSERT INTO TimePeriod VALUES(-2,1994,'e'); +INSERT INTO TimePeriod VALUES(-1,2010,'e'); +INSERT INTO TimePeriod VALUES(0,2025,'f'); +INSERT INTO TimePeriod VALUES(1,2030,'f'); +INSERT INTO TimePeriod VALUES(2,2035,'f'); +INSERT INTO TimePeriod VALUES(3,2040,'f'); +INSERT INTO TimePeriod VALUES(4,2045,'f'); +INSERT INTO TimePeriod VALUES(5,2050,'f'); +INSERT INTO TimePeriod VALUES(6,2055,'f'); +CREATE TABLE TimeSeason +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT, + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +INSERT INTO TimeSeason VALUES(2025,0,'s',NULL); +INSERT INTO TimeSeason VALUES(2030,1,'s',NULL); +INSERT INTO TimeSeason VALUES(2035,2,'s',NULL); +INSERT INTO TimeSeason VALUES(2040,3,'s',NULL); +INSERT INTO TimeSeason VALUES(2045,4,'s',NULL); +INSERT INTO TimeSeason VALUES(2050,5,'s',NULL); +CREATE TABLE TimeSeasonSequential +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + seas_seq TEXT, + season TEXT, + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) +); +CREATE TABLE TimePeriodType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO TimePeriodType VALUES('e','existing vintages'); +INSERT INTO TimePeriodType VALUES('f','future'); +CREATE TABLE OutputEmission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE RPSRequirement +( + region TEXT NOT NULL + REFERENCES Region (region), + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech_group TEXT NOT NULL + REFERENCES TechGroup (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE TechGroupMember +( + group_name TEXT + REFERENCES TechGroup (group_name), + tech TEXT + REFERENCES Technology (tech), + PRIMARY KEY (group_name, tech) +); +CREATE TABLE Technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES TechnologyType (label) +); +INSERT INTO Technology VALUES('tech_ancient','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('tech_old','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('tech_current','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('tech_future','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +CREATE TABLE OutputCost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES TimePeriod (period), + FOREIGN KEY (tech) REFERENCES Technology (tech) +); +COMMIT; From 470cc7d39b9651b26898d6f278a55b6c42363909 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 19 Jun 2025 10:23:26 -0400 Subject: [PATCH 136/587] Knock off some TODOs --- temoa/temoa_model/table_writer.py | 46 ++-------------------- temoa/utilities/db_migration_v3_to_v3_1.py | 3 +- 2 files changed, 5 insertions(+), 44 deletions(-) diff --git a/temoa/temoa_model/table_writer.py b/temoa/temoa_model/table_writer.py index 94e088299..967858d92 100644 --- a/temoa/temoa_model/table_writer.py +++ b/temoa/temoa_model/table_writer.py @@ -232,26 +232,6 @@ def clear_iterative_runs(self): def write_storage_level(self, M: TemoaModel, iteration=None) -> None: """Write the storage level table to the DB""" - # ----- - # TODO for backwards compatibility, make the output table if it doesn't exist - # remove this one day when it is no longer needed - self.con.execute( - f"""CREATE TABLE IF NOT EXISTS - OutputStorageLevel( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - season TEXT REFERENCES TimePeriod (period), - tod TEXT REFERENCES TimeOfDay (tod), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) - );""" - ) - # ----- - storage_levels = poll_storage_level_results(M=M) scenario_name = ( @@ -538,11 +518,6 @@ def _insert_cost_results(self, regular_entries, exchange_entries, emission_entri def _write_cost_rows(self, entries, iteration=None): """Write the entries to the OutputCost table""" cur = self.con.cursor() - # ----- - # TODO remove one day (see below) - cols = [c[1] for c in cur.execute('PRAGMA table_info(OutputCost);').fetchall()] - include_sector = cols[2] == 'sector' - # ----- scenario_name = ( self.config.scenario + f'-{iteration}' if iteration is not None @@ -552,6 +527,7 @@ def _write_cost_rows(self, entries, iteration=None): ( scenario_name, r, + self.tech_sectors[t], p, t, v, @@ -566,24 +542,8 @@ def _write_cost_rows(self, entries, iteration=None): ) for (r, p, t, v) in entries ] - # ----- - # TODO This was done for backwards-compatibility. Make this the only behaviour one day when - # this is no longer needed - if include_sector: - rows = [ - ( - *r[0:2], - self.tech_sectors[r[3]], - *r[2::], - ) - for r in rows - ] - rows.sort(key=lambda r: (r[0], r[1], r[2], r[3], r[4], r[5])) - qry = 'INSERT INTO OutputCost VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' - # ----- - else: - rows.sort(key=lambda r: (r[0], r[1], r[2], r[3], r[4])) - qry = 'INSERT INTO OutputCost VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' + rows.sort(key=lambda r: (r[0:5])) + qry = 'INSERT INTO OutputCost VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' cur.executemany(qry, rows) self.con.commit() diff --git a/temoa/utilities/db_migration_v3_to_v3_1.py b/temoa/utilities/db_migration_v3_to_v3_1.py index 0603fa871..3713e58b6 100644 --- a/temoa/utilities/db_migration_v3_to_v3_1.py +++ b/temoa/utilities/db_migration_v3_to_v3_1.py @@ -28,6 +28,7 @@ import argparse import sqlite3 import sys +from temoa.temoa_model.temoa_model import TemoaModel from pathlib import Path parser = argparse.ArgumentParser() @@ -275,7 +276,7 @@ def column_check(old_name: str, new_name: str) -> bool: if row[v] > p: continue # v <= p if (row[r], row[t], row[v]) in lifetime_process: life = lifetime_process[row[r], row[t], row[v]] elif (row[r], row[t]) in lifetime_tech: life = lifetime_tech[row[r], row[t]] - else: life = 40 # TODO replace by calling default lifetime from TemoaModel + else: life = TemoaModel.default_lifetime_tech if row[v] + life <= p: continue # v+l > p if old_name[0:5] == 'TimeS': # horrible but covers TimeSeason and TimeSegmentFraction From 97bf94e19adfda4c57f92980ad82b5dcb45bfee3 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 19 Jun 2025 10:52:03 -0400 Subject: [PATCH 137/587] Wee fix to objective output in myopic --- temoa/extensions/myopic/myopic_sequencer.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index add584f38..21ab54250 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -288,7 +288,9 @@ def start(self): self.output_con.execute('VACUUM;') # Total system cost is, theoretically, sum of discounted costs from OutputCost table - total_cost = self.output_con.execute('SELECT SUM(d_invest)+SUM(d_fixed)+SUM(d_var)+SUM(d_emiss) FROM OutputCost').fetchone()[0] + total_cost = self.output_con.execute( + f'SELECT SUM(d_invest)+SUM(d_fixed)+SUM(d_var)+SUM(d_emiss) FROM OutputCost WHERE scenario == "{self.config.scenario}"' + ).fetchone()[0] self.output_con.execute( f"""INSERT INTO OutputObjective(scenario, objective_name, total_system_cost) From 8940c82724f2992b0ffa568d1c8fa60e2acafa97 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 19 Jun 2025 12:11:43 -0400 Subject: [PATCH 138/587] Fix wee bug in CapacityCredit tables --- data_files/example_dbs/materials.sql | 6 ++++-- data_files/example_dbs/morris_utopia.sql | 6 ++++-- data_files/example_dbs/seasonal_storage.sql | 6 ++++-- data_files/example_dbs/stepped_demand.sql | 6 ++++-- data_files/example_dbs/survival_curve.sql | 6 ++++-- data_files/example_dbs/test_system.sql | 6 ++++-- data_files/example_dbs/utopia.sql | 6 ++++-- data_files/temoa_schema_v3_1.sql | 6 ++++-- tests/testing_data/emissions.sql | 6 ++++-- tests/testing_data/materials.sql | 6 ++++-- tests/testing_data/mediumville.sql | 6 ++++-- tests/testing_data/seasonal_storage.sql | 6 ++++-- tests/testing_data/simple_linked_tech.sql | 6 ++++-- tests/testing_data/storageville.sql | 6 ++++-- tests/testing_data/survival_curve.sql | 6 ++++-- tests/testing_data/test_system.sql | 6 ++++-- tests/testing_data/utopia.sql | 6 ++++-- 17 files changed, 68 insertions(+), 34 deletions(-) diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index d4795509e..7585fee39 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -42,8 +42,10 @@ CREATE TABLE SectorLabel CREATE TABLE CapacityCredit ( region TEXT, - period INTEGER, - tech TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), vintage INTEGER, credit REAL, notes TEXT, diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index befc915d1..a884e12ca 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -48,8 +48,10 @@ INSERT INTO SectorLabel VALUES('industrial'); CREATE TABLE CapacityCredit ( region TEXT, - period INTEGER, - tech TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), vintage INTEGER, credit REAL, notes TEXT, diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql index 896dea4cc..324b48fc5 100644 --- a/data_files/example_dbs/seasonal_storage.sql +++ b/data_files/example_dbs/seasonal_storage.sql @@ -43,8 +43,10 @@ INSERT INTO SectorLabel VALUES('electricity'); CREATE TABLE CapacityCredit ( region TEXT, - period INTEGER, - tech TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), vintage INTEGER, credit REAL, notes TEXT, diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index bf3d42b8a..4e632e754 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -48,8 +48,10 @@ INSERT INTO SectorLabel VALUES('industrial'); CREATE TABLE CapacityCredit ( region TEXT, - period INTEGER, - tech TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), vintage INTEGER, credit REAL, notes TEXT, diff --git a/data_files/example_dbs/survival_curve.sql b/data_files/example_dbs/survival_curve.sql index 45bb3541e..8f253e9b1 100644 --- a/data_files/example_dbs/survival_curve.sql +++ b/data_files/example_dbs/survival_curve.sql @@ -42,8 +42,10 @@ CREATE TABLE SectorLabel CREATE TABLE CapacityCredit ( region TEXT, - period INTEGER, - tech TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), vintage INTEGER, credit REAL, notes TEXT, diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index e87cae734..3b610dd17 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -48,8 +48,10 @@ INSERT INTO SectorLabel VALUES('industrial'); CREATE TABLE CapacityCredit ( region TEXT, - period INTEGER, - tech TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), vintage INTEGER, credit REAL, notes TEXT, diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 93d653cb1..e357d094e 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -48,8 +48,10 @@ INSERT INTO SectorLabel VALUES('industrial'); CREATE TABLE CapacityCredit ( region TEXT, - period INTEGER, - tech TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), vintage INTEGER, credit REAL, notes TEXT, diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index f3392c1d4..57bf130b9 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -52,8 +52,10 @@ CREATE TABLE IF NOT EXISTS SectorLabel CREATE TABLE IF NOT EXISTS CapacityCredit ( region TEXT, - period INTEGER, - tech TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), vintage INTEGER, credit REAL, notes TEXT, diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index f969bab54..14f70478f 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -42,8 +42,10 @@ CREATE TABLE SectorLabel CREATE TABLE CapacityCredit ( region TEXT, - period INTEGER, - tech TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), vintage INTEGER, credit REAL, notes TEXT, diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index d4795509e..7585fee39 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -42,8 +42,10 @@ CREATE TABLE SectorLabel CREATE TABLE CapacityCredit ( region TEXT, - period INTEGER, - tech TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), vintage INTEGER, credit REAL, notes TEXT, diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 482de2802..5352e8158 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -48,8 +48,10 @@ INSERT INTO SectorLabel VALUES('industrial'); CREATE TABLE CapacityCredit ( region TEXT, - period INTEGER, - tech TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), vintage INTEGER, credit REAL, notes TEXT, diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index 896dea4cc..324b48fc5 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -43,8 +43,10 @@ INSERT INTO SectorLabel VALUES('electricity'); CREATE TABLE CapacityCredit ( region TEXT, - period INTEGER, - tech TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), vintage INTEGER, credit REAL, notes TEXT, diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index 00a7ee6ec..0662ffb13 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -48,8 +48,10 @@ INSERT INTO SectorLabel VALUES('industrial'); CREATE TABLE CapacityCredit ( region TEXT, - period INTEGER, - tech TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), vintage INTEGER, credit REAL, notes TEXT, diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index d09f04d76..28e89ac5b 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -48,8 +48,10 @@ INSERT INTO SectorLabel VALUES('industrial'); CREATE TABLE CapacityCredit ( region TEXT, - period INTEGER, - tech TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), vintage INTEGER, credit REAL, notes TEXT, diff --git a/tests/testing_data/survival_curve.sql b/tests/testing_data/survival_curve.sql index 45bb3541e..8f253e9b1 100644 --- a/tests/testing_data/survival_curve.sql +++ b/tests/testing_data/survival_curve.sql @@ -42,8 +42,10 @@ CREATE TABLE SectorLabel CREATE TABLE CapacityCredit ( region TEXT, - period INTEGER, - tech TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), vintage INTEGER, credit REAL, notes TEXT, diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index e87cae734..3b610dd17 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -48,8 +48,10 @@ INSERT INTO SectorLabel VALUES('industrial'); CREATE TABLE CapacityCredit ( region TEXT, - period INTEGER, - tech TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), vintage INTEGER, credit REAL, notes TEXT, diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 93d653cb1..e357d094e 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -48,8 +48,10 @@ INSERT INTO SectorLabel VALUES('industrial'); CREATE TABLE CapacityCredit ( region TEXT, - period INTEGER, - tech TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), vintage INTEGER, credit REAL, notes TEXT, From d180fe76ef9f33fda1ed5c950140c418382ccd05 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 19 Jun 2025 13:13:02 -0400 Subject: [PATCH 139/587] Split CapacityCredit from ReserveCapacityDerate --- data_files/my_configs/config_sample.toml | 12 +- data_files/my_configs/mga_utopia.toml | 10 +- data_files/my_configs/monte_carlo_utopia.toml | 10 +- data_files/my_configs/morris_utopia.toml | 10 +- data_files/my_configs/stepped_demand.toml | 10 +- .../single_vector_mga/sv_mga_sequencer.py | 2 +- .../temoa_model/exchange_tech_cost_ledger.py | 4 +- temoa/temoa_model/hybrid_loader.py | 47 +++--- .../temoa_model/model_checking/validators.py | 95 +---------- temoa/temoa_model/table_data_puller.py | 12 +- temoa/temoa_model/temoa_initialize.py | 159 ++++++++++++++---- temoa/temoa_model/temoa_model.py | 33 ++-- temoa/temoa_model/temoa_rules.py | 54 +++--- temoa/utilities/unit_cost_explorer.py | 4 +- tests/test_exchange_cost_ledger.py | 2 +- tests/testing_configs/config_emissions.toml | 10 +- tests/testing_configs/config_link_test.toml | 10 +- tests/testing_configs/config_materials.toml | 10 +- tests/testing_configs/config_mediumville.toml | 10 +- .../config_seasonal_storage.toml | 10 +- .../testing_configs/config_storageville.toml | 10 +- .../config_survival_curve.toml | 10 +- tests/testing_configs/config_test_system.toml | 10 +- tests/testing_configs/config_utopia.toml | 10 +- .../testing_configs/config_utopia_myopic.toml | 10 +- tests/testing_data/mediumville_sets.json | 10 +- tests/testing_data/test_system_sets.json | 7 +- tests/testing_data/utopia_sets.json | 7 +- 28 files changed, 301 insertions(+), 287 deletions(-) diff --git a/data_files/my_configs/config_sample.toml b/data_files/my_configs/config_sample.toml index fac2e2406..572e43104 100644 --- a/data_files/my_configs/config_sample.toml +++ b/data_files/my_configs/config_sample.toml @@ -106,15 +106,15 @@ time_sequencing = 'seasonal_timeslices' # How contributions to the planning reserve margin are calculated # Options: # 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. +# Traditional planning reserve formulation. Contributions are independent of hourly availability: +# capacity value = net capacity * capacity credit # 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). +# Contributions are available output including a capacity derate factor (e.g., forced outage rate). # For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor +# capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit -reserve_margin = 'static' +# capacity value = flow out * reserve capacity derate +reserve_margin = 'dynamic' # --------------------------------------------------- # MODE OPTIONS diff --git a/data_files/my_configs/mga_utopia.toml b/data_files/my_configs/mga_utopia.toml index ac4aa659e..5508f0007 100644 --- a/data_files/my_configs/mga_utopia.toml +++ b/data_files/my_configs/mga_utopia.toml @@ -100,14 +100,14 @@ time_sequencing = 'seasonal_timeslices' # How contributions to the planning reserve margin are calculated # Options: # 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. +# Traditional planning reserve formulation. Contributions are independent of hourly availability: +# capacity value = net capacity * capacity credit # 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). +# Contributions are available output including a capacity derate factor (e.g., forced outage rate). # For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor +# capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# capacity value = flow out * reserve capacity derate reserve_margin = 'static' # --------------------------------------------------- diff --git a/data_files/my_configs/monte_carlo_utopia.toml b/data_files/my_configs/monte_carlo_utopia.toml index e82d6000d..69144713f 100644 --- a/data_files/my_configs/monte_carlo_utopia.toml +++ b/data_files/my_configs/monte_carlo_utopia.toml @@ -103,14 +103,14 @@ time_sequencing = 'seasonal_timeslices' # How contributions to the planning reserve margin are calculated # Options: # 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. +# Traditional planning reserve formulation. Contributions are independent of hourly availability: +# capacity value = net capacity * capacity credit # 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). +# Contributions are available output including a capacity derate factor (e.g., forced outage rate). # For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor +# capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# capacity value = flow out * reserve capacity derate reserve_margin = 'static' # --------------------------------------------------- diff --git a/data_files/my_configs/morris_utopia.toml b/data_files/my_configs/morris_utopia.toml index 80a61f2fd..820caa1ed 100644 --- a/data_files/my_configs/morris_utopia.toml +++ b/data_files/my_configs/morris_utopia.toml @@ -100,14 +100,14 @@ time_sequencing = 'seasonal_timeslices' # How contributions to the planning reserve margin are calculated # Options: # 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. +# Traditional planning reserve formulation. Contributions are independent of hourly availability: +# capacity value = net capacity * capacity credit # 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). +# Contributions are available output including a capacity derate factor (e.g., forced outage rate). # For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor +# capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# capacity value = flow out * reserve capacity derate reserve_margin = 'static' # --------------------------------------------------- diff --git a/data_files/my_configs/stepped_demand.toml b/data_files/my_configs/stepped_demand.toml index ac551a710..85136ee6b 100644 --- a/data_files/my_configs/stepped_demand.toml +++ b/data_files/my_configs/stepped_demand.toml @@ -100,14 +100,14 @@ time_sequencing = 'seasonal_timeslices' # How contributions to the planning reserve margin are calculated # Options: # 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. +# Traditional planning reserve formulation. Contributions are independent of hourly availability: +# capacity value = net capacity * capacity credit # 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). +# Contributions are available output including a capacity derate factor (e.g., forced outage rate). # For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor +# capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# capacity value = flow out * reserve capacity derate reserve_margin = 'static' # --------------------------------------------------- diff --git a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py index 3c2aa3e4b..611e46c1e 100644 --- a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py +++ b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py @@ -198,7 +198,7 @@ def flow_idxs_from_eac_idx(M: TemoaModel, reitvo: tuple) -> tuple[list[tuple], . for membership later """ r, _, i, t, v, o = reitvo - psd_set = [(p, s, d) for p in M.time_optimize for s in M.time_season[p] for d in M.time_of_day] + psd_set = [(p, s, d) for p in M.time_optimize for s in M.TimeSeason[p] for d in M.time_of_day] flow_idxs = [(r, *psd, i, t, v, o) for psd in psd_set] annual_flow_idxs = [(r, p, i, t, v, o) for p in M.time_optimize] diff --git a/temoa/temoa_model/exchange_tech_cost_ledger.py b/temoa/temoa_model/exchange_tech_cost_ledger.py index 846f8cc95..1256ae9e9 100644 --- a/temoa/temoa_model/exchange_tech_cost_ledger.py +++ b/temoa/temoa_model/exchange_tech_cost_ledger.py @@ -94,7 +94,7 @@ def get_use_ratio(self, exporter, importer, period, tech, vintage) -> float: act_dir1 = value( sum( M.V_FlowOut[rr1, period, s, d, S_i, tech, vintage, S_o] - for s in M.time_season[period] + for s in M.TimeSeason[period] for d in M.time_of_day for S_i in M.processInputs[rr1, period, tech, vintage] for S_o in M.processOutputsByInput[rr1, period, tech, vintage, S_i] @@ -103,7 +103,7 @@ def get_use_ratio(self, exporter, importer, period, tech, vintage) -> float: act_dir2 = value( sum( M.V_FlowOut[rr2, period, s, d, S_i, tech, vintage, S_o] - for s in M.time_season[period] + for s in M.TimeSeason[period] for d in M.time_of_day for S_i in M.processInputs[rr2, period, tech, vintage] for S_o in M.processOutputsByInput[rr2, period, tech, vintage, S_i] diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 68958eddb..b0aa705de 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -426,9 +426,8 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N raise ValueError(msg) load_element(M.TimeSequencing, [(time_sequencing,)]) - # ReserveMargin - # This is the method for calculating contributions - load_element(M.ReserveMargin, [(self.config.reserve_margin,)]) + # ReserveMarginMethod + load_element(M.ReserveMarginMethod, [(self.config.reserve_margin,)]) # myopic_base_year if mi: @@ -660,20 +659,6 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N ] # if no segfrac table, assume this is a periodic model load_element(M.SegFrac, raw) - all_seasons = set() # includes all regular and virtual seasonal storage seasons - if self.table_exists("TimeSeasonSequential"): - if mi: - raw = cur.execute( - 'SELECT period, seas_seq, season, num_days FROM main.TimeSeasonSequential WHERE' - ' period >= ? AND period <= ? ORDER BY period, sequence', - (mi.base_year, mi.last_demand_year) - ).fetchall() - else: - raw = cur.execute('SELECT period, seas_seq, season, num_days FROM main.TimeSeasonSequential ORDER BY period, sequence').fetchall() - all_seasons = all_seasons | set((row[1],) for row in raw) - load_element(M.TimeSeasonSequential, raw) - load_element(M.ordered_season_sequential, [(row[0:3]) for row in raw]) - # TimeSeason if self.table_exists("TimeSeason"): if mi: @@ -686,21 +671,34 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N raw = cur.execute('SELECT period, season FROM main.TimeSeason ORDER BY period, sequence').fetchall() for row in raw: load_indexed_set( - M.time_season, + M.TimeSeason, index_value=row[0], element=row[1] ) - all_seasons = all_seasons | set((row[1],) for row in raw) + load_element(M.time_season, list(set((row[1],) for row in raw))) else: for period in time_optimize: load_indexed_set( - M.time_season, + M.TimeSeason, index_value=period, element='S' ) logger.warning('No TimeSeason table found. Loading a single filler season "S" (assume this is an annual model)') - all_seasons.add(('S',)) - load_element(M.time_season_all, list(all_seasons)) + load_element(M.time_season, [('S',)]) + + if self.table_exists("TimeSeasonSequential"): + if mi: + raw = cur.execute( + 'SELECT period, seas_seq, season, num_days FROM main.TimeSeasonSequential WHERE' + ' period >= ? AND period <= ? ORDER BY period, sequence', + (mi.base_year, mi.last_demand_year) + ).fetchall() + else: + raw = cur.execute('SELECT period, seas_seq, season, num_days FROM main.TimeSeasonSequential ORDER BY period, sequence').fetchall() + load_element(M.TimeSeasonSequential, raw) + if raw: + load_element(M.ordered_season_sequential, [(row[0:3]) for row in raw]) + load_element(M.time_season_sequential, list(set((row[1],) for row in raw))) # DemandSpecificDistribution if self.table_exists('DemandSpecificDistribution'): @@ -1058,6 +1056,11 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, vintage, credit FROM main.CapacityCredit') load_element(M.CapacityCredit, raw, self.viable_rtv, (0, 2, 3)) + # ReserveCapacityDerate + if self.table_exists('ReserveCapacityDerate'): + raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tech, vintage, factor FROM main.ReserveCapacityDerate') + load_element(M.ReserveCapacityDerate, raw, self.viable_rtv, (0, 3, 4)) + # PlanningReserveMargin if self.table_exists('PlanningReserveMargin'): raw = cur.execute('SELECT region, margin FROM main.PlanningReserveMargin').fetchall() diff --git a/temoa/temoa_model/model_checking/validators.py b/temoa/temoa_model/model_checking/validators.py index e5b4a60be..5ed4371be 100644 --- a/temoa/temoa_model/model_checking/validators.py +++ b/temoa/temoa_model/model_checking/validators.py @@ -272,7 +272,7 @@ def validate_CapacityFactorProcess(M: 'TemoaModel', val, r, p, s, d, t, v) -> bo ( r in M.regions, p in M.time_optimize, - s in M.time_season[p], + s in M.TimeSeason[p], d in M.time_of_day, t in M.tech_with_capacity, v in M.vintage_all, @@ -305,99 +305,6 @@ def validate_Efficiency(M: 'TemoaModel', val, r, si, t, v, so) -> bool: return False -def validate_SeasonSequential(M: 'TemoaModel'): - - if all(( - not M.tech_seasonal_storage, - not M.RampUpHourly, - not M.RampDownHourly, - )): - # Don't need it anyway - return - - if not M.TimeSeasonSequential: - if M.TimeSequencing.first() in ('sequential_days', 'seasonal_timeslices'): - logger.info( - 'No data in TimeSeasonSequential. By default, assuming sequential seasons ' - 'match TimeSeason and TimeSegmentFraction.' - ) - for p in M.time_season: - for s in M.time_season[p]: - M.ordered_season_sequential.add((p, s, s)) - M.TimeSeasonSequential[p, s, s] = value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod) - - else: - msg = ( - f'No data in TimeSeasonSequential but time_sequencing parameter set to {M.TimeSequencing.first()} ' - 'and inter-season features used. TimeSeasonSequential must be filled for this type of time ' - 'sequencing if seasonal storage or inter-season constraints like RampUp/RampDown are used. Check ' - 'the config file.' - ) - logger.error(msg) - raise ValueError(msg) - - sequential = dict() - for p, s_seq, s in M.TimeSeasonSequential: - count = value(M.TimeSeasonSequential[p, s_seq, s]) - if M.TimeSequencing.first() == 'sequential_days' and abs(count - 1.0) >= 0.01: - msg = ( - 'TimeSequencing set to sequential_days but a season in the TimeSegmentFraction table does not ' - f'represent exactly one day. This would lead to bad model behaviour: {p, s}, days: {count}. ' - 'Check the config file.' - ) - logger.error(msg) - raise ValueError(msg) - if (p, s) not in sequential: - sequential[p, s] = 0 - sequential[p, s] += count - - # Check that TimeSeasonSequential day counts total to number of days in each period - for p in M.time_optimize: - count_total = sum( - sequential[p, s] - for _p, s in sequential - if _p == p - ) - if abs(count_total - value(M.DaysPerPeriod)) >= 0.001: - logger.warning( - f'Sum of day count in TimeSeasonSequential ({sum(sequential.values())}) ' - f'does not sum to days_per_period ({value(M.DaysPerPeriod)}) from the ' - 'MetaData table.' - ) - - # Check that seasons using in storage seasons are actual seasons - for (p, s) in sequential: - if (p, s) not in M.SegFracPerSeason: - msg = ( - f'Period-season index {(p, s)} that does not exist in ' - 'TimeSegmentFraction referenced in TimeSeasonSequential .' - ) - logger.error(msg) - raise ValueError(msg) - - for (p, s) in M.SegFracPerSeason: - if s not in M.time_season[p]: - continue - - # Check that all seasons are used in sequential seasons - if (p, s) not in sequential: - msg = (f'Period-season index {(p, s)} absent from TimeSeasonSequential') - logger.warning(msg) - - # Check that the two tables agree on the total seasonal composition of each period - segfrac = value(M.SegFracPerSeason[p, s]) - segfracseq = sequential[p, s] / value(M.DaysPerPeriod) - if abs(segfrac - segfracseq) >= 0.001: - msg = ( - 'Discrepancy of total period-season composition between ' - 'TimeSegmentFraction and TimeSeasonSequential. Total fraction of each ' - 'period assigned to each season should match: ' - f'TimeSegmentFraction: {(p, s, value(M.SegFracPerSeason[p, s]))}' - f', TimeSeasonSequential: {(p, s, segfracseq)}' - ) - logger.warning(msg) - - def validate_ReserveMargin(M: 'TemoaModel'): for r in M.PlanningReserveMargin: if all((r, p) not in M.processReservePeriods for p in M.time_optimize): diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index b79c83214..7d3a2e2c5 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -189,7 +189,7 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl # basic annual flows for r, p, i, t, v, o in M.V_FlowOutAnnual: - for s in M.time_season[p]: + for s in M.TimeSeason[p]: for d in M.time_of_day: fi = FI(r, p, s, d, i, t, v, o) flow = value(M.V_FlowOutAnnual[r, p, i, t, v, o]) * value(M.SegFrac[p, s, d]) @@ -201,7 +201,7 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl # flex annual for r, p, i, t, v, o in M.V_FlexAnnual: - for s in M.time_season[p]: + for s in M.TimeSeason[p]: for d in M.time_of_day: fi = FI(r, p, s, d, i, t, v, o) flow = value(M.V_FlexAnnual[r, p, i, t, v, o]) * value(M.SegFrac[p, s, d]) @@ -213,7 +213,7 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl # construction flows for (r, i, t, v) in M.ConstructionInput.sparse_iterkeys(): annual = value(M.ConstructionInput[r, i, t, v]) * value(M.V_NewCapacity[r, t, v]) / value(M.PeriodLength[v]) - for s in M.time_season[v]: + for s in M.TimeSeason[v]: for d in M.time_of_day: fi = FI(r, v, s, d, i, t, v, 'ConstructionInput') flow = annual * value(M.SegFrac[v, s, d]) @@ -227,7 +227,7 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl continue for p in M.retirementPeriods[r, t, v]: annual = value(M.EndOfLifeOutput[r, t, v, o]) * value(M.V_AnnualRetirement[r, p, t, v]) - for s in M.time_season[p]: + for s in M.TimeSeason[p]: for d in M.time_of_day: fi = FI(r, p, s, d, 'EndOfLifeOutput', t, v, o) flow = annual * value(M.SegFrac[p, s, d]) @@ -404,7 +404,7 @@ def poll_cost_results( value(M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o]) for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] - for S_s in M.time_season[p] + for S_s in M.TimeSeason[p] for S_d in M.time_of_day ) else: @@ -579,7 +579,7 @@ def poll_emissions( normal = [ (r, p, e, s, d, i, t, v, o) for (r, p, e, i, t, v, o) in base - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day if t not in M.tech_annual ] diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index f0f756edc..7376e6f74 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -183,7 +183,7 @@ def validate_SegFrac(M: 'TemoaModel'): expected_keys = set( (p, s, d) - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day ) keys = set( @@ -342,7 +342,7 @@ def CheckEfficiencyVariable(M: 'TemoaModel'): # Check if all possible values have been set as variable # log a warning if some are missing (allowed but maybe accidental) - num_seg = len(M.time_season[p]) * len(M.time_of_day) + num_seg = len(M.TimeSeason[p]) * len(M.time_of_day) for (r, p, i, t, v, o), count in count_rpitvo.items(): if count > 0: @@ -377,7 +377,7 @@ def CheckCapacityFactorProcess(M: 'TemoaModel'): # Check if all possible values have been set by process # log a warning if some are missing (allowed but maybe accidental) - num_seg = len(M.time_season[p]) * len(M.time_of_day) + num_seg = len(M.TimeSeason[p]) * len(M.time_of_day) for (r, p, t, v), count in count_rptv.items(): if count > 0: M.isCapacityFactorProcess[r, p, t, v] = True @@ -407,7 +407,7 @@ def CreateCapacityFactors(M: 'TemoaModel'): (r, p, s, d, t, v) for (r, t, v) in processes for p in M.processPeriods[r, t, v] - for s, d in cross_product(M.time_season[p], M.time_of_day) + for s, d in cross_product(M.TimeSeason[p], M.time_of_day) ) # Step 2 @@ -556,7 +556,7 @@ def CreateDemands(M: 'TemoaModel'): if unset_demand_distributions: for p in M.time_optimize: unset_distributions = set( - cross_product(M.regions, (p,), M.time_season[p], M.time_of_day, unset_demand_distributions) + cross_product(M.regions, (p,), M.TimeSeason[p], M.time_of_day, unset_demand_distributions) ) for r, p, s, d, dem in unset_distributions: DSD[r, p, s, d, dem] = M.SegFrac[p, s, d] # DSD._constructed = True @@ -567,7 +567,7 @@ def CreateDemands(M: 'TemoaModel'): # and we need to ensure even the zeros are passed in used_rp_dems = set((r, p, dem) for r, p, dem in M.Demand.sparse_iterkeys()) for r, p, dem in used_rp_dems: - expected_key_length = len(M.time_season[p]) * len(M.time_of_day) + expected_key_length = len(M.TimeSeason[p]) * len(M.time_of_day) keys = [ k for k in DSD.sparse_iterkeys() @@ -577,7 +577,7 @@ def CreateDemands(M: 'TemoaModel'): # this could be very slow but only calls when there's a problem missing = set( (s, d) - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day if (r, p, s, d, dem) not in keys ) @@ -966,7 +966,7 @@ def CreateSparseDicts(M: 'TemoaModel'): for v in M.processVintages[r, p, t] for i in M.processInputs[r, p, t, v] for o in M.processOutputsByInput[r, p, t, v, i] - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -986,7 +986,7 @@ def CreateSparseDicts(M: 'TemoaModel'): for v in M.processVintages[r, p, t] for i in M.processInputs[r, p, t, v] for o in M.processOutputsByInput[r, p, t, v, i] - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -1006,7 +1006,7 @@ def CreateSparseDicts(M: 'TemoaModel'): for v in M.processVintages[r, p, t] for i in M.processInputs[r, p, t, v] for o in M.processOutputsByInput[r, p, t, v, i] - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -1016,7 +1016,7 @@ def CreateSparseDicts(M: 'TemoaModel'): for v in M.curtailmentVintages[r, p, t] for i in M.processInputs[r, p, t, v] for o in M.processOutputsByInput[r, p, t, v, i] - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -1062,7 +1062,7 @@ def CreateSparseDicts(M: 'TemoaModel'): (r, p, s, d, t, v) for r, p, t in M.storageVintages.keys() for v in M.storageVintages[r, p, t] - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -1087,17 +1087,17 @@ def CreateTimeSequence(M: 'TemoaModel'): case 'sequential_days': msg = 'Running a sequential days database.' for p in M.time_optimize: - for s, d in M.time_season[p] * M.time_of_day: + for s, d in M.TimeSeason[p] * M.time_of_day: M.time_next[p, s, d] = loop_period_next_timeslice(M, p, s, d) case 'seasonal_timeslices': msg = 'Running a seasonal time slice database.' for p in M.time_optimize: - for s, d in M.time_season[p] * M.time_of_day: + for s, d in M.TimeSeason[p] * M.time_of_day: M.time_next[p, s, d] = loop_season_next_timeslice(M, p, s, d) case 'representative_periods': msg = 'Running a representative periods database.' for p in M.time_optimize: - for s, d in M.time_season[p] * M.time_of_day: + for s, d in M.TimeSeason[p] * M.time_of_day: M.time_next[p, s, d] = loop_season_next_timeslice(M, p, s, d) case 'manual': # Hidden feature. Define the sequence directly in the TimeNext table @@ -1133,6 +1133,101 @@ def CreateTimeSequence(M: 'TemoaModel'): logger.debug('Created time sequence.') +def CreateTimeSeasonSequential(M: 'TemoaModel'): + + if all(( + not M.tech_seasonal_storage, + not M.RampUpHourly, + not M.RampDownHourly, + )): + # Don't need it anyway + return + + if not M.TimeSeasonSequential: + if M.TimeSequencing.first() in ('sequential_days', 'seasonal_timeslices'): + logger.info( + 'No data in TimeSeasonSequential. By default, assuming sequential seasons ' + 'match TimeSeason and TimeSegmentFraction.' + ) + for s in M.time_season: + M.time_season_sequential.add(s) + for p in M.TimeSeason: + for s in M.TimeSeason[p]: + M.ordered_season_sequential.add((p, s, s)) + M.TimeSeasonSequential[p, s, s] = value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod) + + else: + msg = ( + f'No data in TimeSeasonSequential but time_sequencing parameter set to {M.TimeSequencing.first()} ' + 'and inter-season features used. TimeSeasonSequential must be filled for this type of time ' + 'sequencing if seasonal storage or inter-season constraints like RampUp/RampDown are used. Check ' + 'the config file.' + ) + logger.error(msg) + raise ValueError(msg) + + sequential = dict() + for p, s_seq, s in M.TimeSeasonSequential: + count = value(M.TimeSeasonSequential[p, s_seq, s]) + if M.TimeSequencing.first() == 'sequential_days' and abs(count - 1.0) >= 0.01: + msg = ( + 'TimeSequencing set to sequential_days but a season in the TimeSegmentFraction table does not ' + f'represent exactly one day. This would lead to bad model behaviour: {p, s}, days: {count}. ' + 'Check the config file.' + ) + logger.error(msg) + raise ValueError(msg) + if (p, s) not in sequential: + sequential[p, s] = 0 + sequential[p, s] += count + + # Check that TimeSeasonSequential day counts total to number of days in each period + for p in M.time_optimize: + count_total = sum( + sequential[p, s] + for _p, s in sequential + if _p == p + ) + if abs(count_total - value(M.DaysPerPeriod)) >= 0.001: + logger.warning( + f'Sum of day count in TimeSeasonSequential ({sum(sequential.values())}) ' + f'does not sum to days_per_period ({value(M.DaysPerPeriod)}) from the ' + 'MetaData table.' + ) + + # Check that seasons using in storage seasons are actual seasons + for (p, s) in sequential: + if (p, s) not in M.SegFracPerSeason: + msg = ( + f'Period-season index {(p, s)} that does not exist in ' + 'TimeSegmentFraction referenced in TimeSeasonSequential .' + ) + logger.error(msg) + raise ValueError(msg) + + for (p, s) in M.SegFracPerSeason: + if s not in M.TimeSeason[p]: + continue + + # Check that all seasons are used in sequential seasons + if (p, s) not in sequential: + msg = (f'Period-season index {(p, s)} absent from TimeSeasonSequential') + logger.warning(msg) + + # Check that the two tables agree on the total seasonal composition of each period + segfrac = value(M.SegFracPerSeason[p, s]) + segfracseq = sequential[p, s] / value(M.DaysPerPeriod) + if abs(segfrac - segfracseq) >= 0.001: + msg = ( + 'Discrepancy of total period-season composition between ' + 'TimeSegmentFraction and TimeSeasonSequential. Total fraction of each ' + 'period assigned to each season should match: ' + f'TimeSegmentFraction: {(p, s, value(M.SegFracPerSeason[p, s]))}' + f', TimeSeasonSequential: {(p, s, segfracseq)}' + ) + logger.warning(msg) + + def CreateSurvivalCurve(M: 'TemoaModel'): rtv_interpolated = set() # so we only need one warning @@ -1264,7 +1359,7 @@ def CapacityFactorProcessIndices(M: 'TemoaModel'): (r, s, d, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys() for p in M.time_optimize - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day ) return indices @@ -1274,7 +1369,7 @@ def CapacityFactorTechIndices(M: 'TemoaModel'): all_cfs = set( (r, p, s, d, t) for r, p, t in M.activeCapacityAvailable_rpt - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day ) return all_cfs @@ -1453,7 +1548,7 @@ def CapacityConstraintIndices(M: 'TemoaModel'): if t not in M.tech_annual if t not in M.tech_uncap if t not in M.tech_storage - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -1468,7 +1563,7 @@ def LinkedTechConstraintIndices(M: 'TemoaModel'): if (r, p, t) in M.processVintages for v in M.processVintages[r, p, t] if (r, p, t, v) in M.activeActivity_rptv - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -1529,7 +1624,7 @@ def DemandActivityConstraintIndices(M: 'TemoaModel'): for r, p, dem in anchor_season_tod: found_flag = False s0, d0 = None, None - for s0, d0 in ((ss, dd) for ss in M.time_season[p] for dd in M.time_of_day): + for s0, d0 in ((ss, dd) for ss in M.TimeSeason[p] for dd in M.time_of_day): if (r, p, s0, d0, dem) in M.DemandSpecificDistribution: if value(M.DemandSpecificDistribution[r, p, s0, d0, dem]) >= appreciable_size: found_flag = True @@ -1551,7 +1646,7 @@ def DemandActivityConstraintIndices(M: 'TemoaModel'): for r, p, dem in anchor_season_tod: s0, d0 = anchor_season_tod[r, p, dem] for t, v in viable_tech_vintage[r, p, dem]: - for s in M.time_season[p]: + for s in M.TimeSeason[p]: for d in M.time_of_day: if s != s0 or d != d0: yield r, p, s, d, t, v, dem, s0, d0 @@ -1561,7 +1656,7 @@ def DemandConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, s, d, dem) for r, p, dem in M.Demand.sparse_iterkeys() - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -1573,7 +1668,7 @@ def BaseloadDiurnalConstraintIndices(M: 'TemoaModel'): (r, p, s, d, t, v) for r, p, t in M.baseloadVintages.keys() for v in M.baseloadVintages[r, p, t] - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -1599,7 +1694,7 @@ def CommodityBalanceConstraintIndices(M: 'TemoaModel'): # r in this line includes interregional transfer combinations (not needed). if r in M.regions # this line ensures only the regions are included. and c not in M.commodity_annual - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -1625,7 +1720,7 @@ def RampUpDayConstraintIndices(M: 'TemoaModel'): (r, p, s, d, t, v) for r, p, t in M.rampUpVintages for v in M.rampUpVintages[r, p, t] - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -1637,7 +1732,7 @@ def RampDownDayConstraintIndices(M: 'TemoaModel'): (r, p, s, d, t, v) for r, p, t in M.rampDownVintages for v in M.rampDownVintages[r, p, t] - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -1680,7 +1775,7 @@ def ReserveMarginIndices(M: 'TemoaModel'): for r in M.PlanningReserveMargin for p in M.time_optimize if (r, p) in M.processReservePeriods - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -1693,7 +1788,7 @@ def LimitTechInputSplitConstraintIndices(M: 'TemoaModel'): for r, p, i, t, op in M.inputSplitVintages.keys() if t not in M.tech_annual for v in M.inputSplitVintages[r, p, i, t, op] - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day ) ann_indices = set( @@ -1738,7 +1833,7 @@ def LimitTechOutputSplitConstraintIndices(M: 'TemoaModel'): for r, p, t, o, op in M.outputSplitVintages.keys() if t not in M.tech_annual for v in M.outputSplitVintages[r, p, t, o, op] - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day ) ann_indices = set( @@ -1832,15 +1927,15 @@ def loop_period_next_timeslice(M: 'TemoaModel', p, s, d) -> tuple[str, str]: # Final time slice of final season (end of period) # Loop state back to initial state of first season # Loop the period - if s == M.time_season[p].last() and d == M.time_of_day.last(): - s_next = M.time_season[p].first() + if s == M.TimeSeason[p].last() and d == M.time_of_day.last(): + s_next = M.TimeSeason[p].first() d_next = M.time_of_day.first() # Last time slice of any season that is NOT the last season # Carry state to initial state of next season # Carry state between seasons elif d == M.time_of_day.last(): - s_next = M.time_season[p].next(s) + s_next = M.TimeSeason[p].next(s) d_next = M.time_of_day.first() # Any other time slice diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 243c9bfc5..b11f6c3f9 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -37,13 +37,12 @@ from temoa.temoa_model.model_checking.validators import ( validate_linked_tech, region_check, - validate_CapacityFactorProcess, + # validate_CapacityFactorProcess, validate_0to1, region_group_check, validate_Efficiency, validate_tech_sets, no_slash_or_pipe, - validate_SeasonSequential, validate_ReserveMargin, ) from temoa.temoa_model.temoa_initialize import * @@ -163,12 +162,13 @@ def __init__(M, *args, **kwargs): M.validate_time = BuildAction(rule=validate_time) # Define the model time slices - M.time_season_all = Set(ordered=True, validate=no_slash_or_pipe) - M.time_season = Set(M.time_optimize, within=M.time_season_all, ordered=True) + M.time_season = Set(ordered=True, validate=no_slash_or_pipe) + M.time_season_sequential = Set(ordered=True, validate=no_slash_or_pipe) + M.TimeSeason = Set(M.time_optimize, within=M.time_season, ordered=True) M.time_of_day = Set(ordered=True, validate=no_slash_or_pipe) # This is just to get the TimeStorageSeason table sequentially. There must be a better way but this works for now - M.ordered_season_sequential = Set(dimen=3, within=M.time_optimize * M.time_season_all * M.time_season_all, ordered=True) + M.ordered_season_sequential = Set(dimen=3, within=M.time_optimize * M.time_season_sequential * M.time_season, ordered=True) # Define regions M.regions = Set(validate=region_check) @@ -259,7 +259,7 @@ def __init__(M, *args, **kwargs): # Define time-related parameters M.PeriodLength = Param(M.time_optimize, initialize=ParamPeriodLength) - M.SegFrac = Param(M.time_optimize, M.time_season_all, M.time_of_day) + M.SegFrac = Param(M.time_optimize, M.time_season, M.time_of_day) M.validate_SegFrac = BuildAction(rule=validate_SegFrac) M.TimeSequencing = Set() # How do states carry between time segments? M.TimeNext = Set(ordered=True) # This is just to get data from the table. Hidden feature and usually not used @@ -273,7 +273,7 @@ def __init__(M, *args, **kwargs): M.DemandSpecificDistribution = Param( M.regions, M.time_optimize, - M.time_season_all, + M.time_season, M.time_of_day, M.commodity_demand, mutable=True, @@ -318,7 +318,7 @@ def __init__(M, *args, **kwargs): M.EfficiencyVariable = Param( M.regionalIndices, M.time_optimize, - M.time_season_all, + M.time_season, M.time_of_day, M.commodity_physical, M.tech_all, @@ -363,9 +363,9 @@ def __init__(M, *args, **kwargs): # Set up representation of time M.DaysPerPeriod = Param() - M.SegFracPerSeason = Param(M.time_optimize, M.time_season_all, initialize=SegFracPerSeason_rule) - M.TimeSeasonSequential = Param(M.time_optimize, M.time_season_all, M.time_season_all, mutable=True) - M.validate_SeasonSequential = BuildAction(rule=validate_SeasonSequential) + M.SegFracPerSeason = Param(M.time_optimize, M.time_season, initialize=SegFracPerSeason_rule) + M.TimeSeasonSequential = Param(M.time_optimize, M.time_season_sequential, M.time_season, mutable=True) + M.validate_SeasonSequential = BuildAction(rule=CreateTimeSeasonSequential) M.Create_TimeSequence = BuildAction(rule=CreateTimeSequence) # The method below creates a series of helper functions that are used to @@ -381,7 +381,7 @@ def __init__(M, *args, **kwargs): M.CapacityFactorProcess = Param( M.regionalIndices, M.time_optimize, - M.time_season_all, + M.time_season, M.time_of_day, M.tech_with_capacity, M.vintage_all, @@ -440,7 +440,7 @@ def __init__(M, *args, **kwargs): M.LimitActivity = Param(M.LimitActivityConstraint_rpt) M.LimitSeasonalCapacityFactorConstraint_rpst = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.time_season_all * M.tech_all * M.operator + within=M.regionalGlobalIndices * M.time_optimize * M.time_season * M.tech_all * M.operator ) M.LimitSeasonalCapacityFactor = Param(M.LimitSeasonalCapacityFactorConstraint_rpst, validate=validate_0to1) @@ -510,9 +510,12 @@ def __init__(M, *args, **kwargs): M.LinkedTechs = Param(M.regionalIndices, M.tech_all, M.commodity_emissions, within=Any) # Define parameters associated with electric sector operation - M.ReserveMargin = Set() # How contributions to the reserve margin are calculated + M.ReserveMarginMethod = Set() # How contributions to the reserve margin are calculated M.CapacityCredit = Param( - M.regionalIndices, M.time_optimize, M.tech_all, M.vintage_all, default=1, validate=validate_0to1 + M.regionalIndices, M.time_optimize, M.tech_reserve, M.vintage_all, default=0, validate=validate_0to1 + ) + M.ReserveCapacityDerate = Param( + M.regionalIndices, M.time_optimize, M.time_season, M.tech_reserve, M.vintage_all, default=1, validate=validate_0to1 ) M.PlanningReserveMargin = Param(M.regions) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 478c6390f..bb5650c69 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -661,7 +661,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): if S_p == p and S_t not in M.tech_annual for S_i in M.processInputs[r, S_p, S_t, S_v] for S_o in M.processOutputsByInput[r, S_p, S_t, S_v, S_i] - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -703,7 +703,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): normal = [ (r, p, e, s, d, i, t, v, o) for (r, p, e, i, t, v, o) in base - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day if t not in M.tech_annual ] @@ -1104,7 +1104,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): # For other techs, it would be redundant as in = out / eff consumed += sum( M.V_FlowIn[r, p, S_s, S_d, c, S_t, S_v, S_o] - for S_s in M.time_season[p] + for S_s in M.TimeSeason[p] for S_d in M.time_of_day for S_t, S_v in M.commodityDStreamProcess[r, p, c] if S_t in M.tech_storage @@ -1113,7 +1113,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): consumed += sum( M.V_FlowOut[r, p, S_s, S_d, c, S_t, S_v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, c, S_t, S_v, S_o) - for S_s in M.time_season[p] + for S_s in M.TimeSeason[p] for S_d in M.time_of_day for S_t, S_v in M.commodityDStreamProcess[r, p, c] if S_t not in M.tech_storage and S_t not in M.tech_annual @@ -1139,7 +1139,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): # Includes output from storage produced += sum( M.V_FlowOut[r, p, S_s, S_d, S_i, S_t, S_v, c] - for S_s in M.time_season[p] + for S_s in M.TimeSeason[p] for S_d in M.time_of_day for S_t, S_v in M.commodityUStreamProcess[r, p, c] if S_t not in M.tech_annual @@ -1156,7 +1156,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): if c in M.commodity_flex: consumed += sum( M.V_Flex[r, p, S_s, S_d, S_i, S_t, S_v, c] - for S_s in M.time_season[p] + for S_s in M.TimeSeason[p] for S_d in M.time_of_day for S_t, S_v in M.commodityUStreamProcess[r, p, c] if S_t not in M.tech_annual and S_t in M.tech_flex @@ -1182,7 +1182,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): consumed += sum( M.V_FlowOut[r + '-' + S_r, p, S_s, S_d, c, S_t, S_v, S_o] / get_variable_efficiency(M, r + '-' + S_r, p, S_s, S_d, c, S_t, S_v, S_o) - for S_s in M.time_season[p] + for S_s in M.TimeSeason[p] for S_d in M.time_of_day for S_r, S_t, S_v, S_o in M.exportRegions[r, p, c] if S_t not in M.tech_annual @@ -1198,7 +1198,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): if (r, p, c) in M.importRegions: produced += sum( M.V_FlowOut[S_r + '-' + r, p, S_s, S_d, S_i, S_t, S_v, c] - for S_s in M.time_season[p] + for S_s in M.TimeSeason[p] for S_d in M.time_of_day for S_r, S_t, S_v, S_i in M.importRegions[r, p, c] if S_t not in M.tech_annual @@ -1256,7 +1256,7 @@ def ResourceExtraction_Constraint(M: 'TemoaModel', reg, p, r): collected = sum( M.V_FlowOut[reg, p, S_s, S_d, S_i, S_t, S_v, r] # is r the input or the output!? for S_i, S_t, S_v in M.processByPeriodAndOutput.keys() - for S_s in M.time_season[p] + for S_s in M.TimeSeason[p] for S_d in M.time_of_day ) except KeyError: @@ -1937,13 +1937,13 @@ def RampDownSeason_Constraint(M: 'TemoaModel', r, p, s_seq, d, t, v): def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): # Get available generation in this time slice depending on method specified in config file - match M.ReserveMargin.first(): + match M.ReserveMarginMethod.first(): case 'static': available = ReserveMarginStatic(M, r, p, s, d) case 'dynamic': available = ReserveMarginDynamic(M, r, p, s, d) case _: - msg = f"Invalid reserve margin parameter '{M.ReserveMargin.first()}'. Check the config file." + msg = f"Invalid reserve margin parameter '{M.ReserveMarginMethod.first()}'. Check the config file." logger.error(msg) raise ValueError(msg) @@ -2084,7 +2084,7 @@ def ReserveMarginDynamic(M: 'TemoaModel', r, p, s, d): # Derated available generation available = sum( M.V_Capacity[r, p, t, v] - * value(M.CapacityCredit[r, p, t, v]) + * value(M.ReserveCapacityDerate[r, p, s, t, v]) * value(M.CapacityFactorProcess[r, p, s, d, t, v]) * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[p, s, d]) @@ -2096,7 +2096,7 @@ def ReserveMarginDynamic(M: 'TemoaModel', r, p, s, d): # Derated net output flow available += sum( M.V_FlowOut[r, p, s, d, i, t, v, o] - * value(M.CapacityCredit[r, p, t, v]) + * value(M.ReserveCapacityDerate[r, p, s, t, v]) for (t, v) in M.processReservePeriods[r, p] if t in M.tech_storage for i in M.processInputs[r, p, t, v] @@ -2104,7 +2104,7 @@ def ReserveMarginDynamic(M: 'TemoaModel', r, p, s, d): ) available -= sum( M.V_FlowIn[r, p, s, d, i, t, v, o] - * value(M.CapacityCredit[r, p, t, v]) + * value(M.ReserveCapacityDerate[r, p, s, t, v]) for (t, v) in M.processReservePeriods[r, p] if t in M.tech_storage for i in M.processInputs[r, p, t, v] @@ -2134,7 +2134,7 @@ def ReserveMarginDynamic(M: 'TemoaModel', r, p, s, d): # add the available output of the exchange tech. available += sum( M.V_Capacity[r1r2, p, t, v] - * value(M.CapacityCredit[r1r2, p, t, v]) + * value(M.ReserveCapacityDerate[r, p, s, t, v]) * value(M.CapacityFactorProcess[r, p, s, d, t, v]) * value(M.CapacityToActivity[r1r2, t]) * value(M.SegFrac[p, s, d]) @@ -2195,7 +2195,7 @@ def LimitEmission_Constraint(M: 'TemoaModel', r, p, e, op): if tmp_e == e and tmp_r == reg and S_t not in M.tech_annual # EmissionsActivity not indexed by p, so make sure (r,p,t,v) combos valid if (reg, p, S_t, S_v) in M.processInputs - for S_s in M.time_season[p] + for S_s in M.TimeSeason[p] for S_d in M.time_of_day ) @@ -2570,7 +2570,7 @@ def LimitActivity_Constraint(M: 'TemoaModel', r, p, t, op): for S_v in M.processVintages.get((_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[p] + for s in M.TimeSeason[p] for d in M.time_of_day if (_r, p, s, d, S_i, _t, S_v, S_o) in M.V_FlowOut ) @@ -2677,7 +2677,7 @@ def LimitResource_Constraint(M: 'TemoaModel', r, t, op): 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[p] + for s in M.TimeSeason[p] for d in M.time_of_day ) @@ -2705,7 +2705,7 @@ def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): for S_v in M.processVintages.get((_r, p, S_t), []) for S_i in M.processInputs[_r, p, S_t, S_v] for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut ) @@ -2727,7 +2727,7 @@ def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): for S_v in M.processVintages.get((_r, p, S_t), []) for S_i in M.processInputs[_r, p, S_t, S_v] for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut ) @@ -2849,7 +2849,7 @@ def LimitAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o, op): for _r in regions for S_v in M.processVintages.get((_r, p, t), []) for S_i in M.processInputs[_r, p, t, S_v] - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day if (_r, p, s, d, S_i, t, S_v, o) in M.V_FlowOut ) @@ -2985,14 +2985,14 @@ def LimitTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v, op): inp = sum( M.V_FlowOut[r, p, S_s, S_d, i, t, v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) - for S_s in M.time_season[p] + for S_s in M.TimeSeason[p] for S_d in M.time_of_day for S_o in M.processOutputsByInput[r, p, t, v, i] ) total_inp = sum( M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) - for S_s in M.time_season[p] + for S_s in M.TimeSeason[p] for S_d in M.time_of_day for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, i] @@ -3095,7 +3095,7 @@ def LimitTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o, op): out = sum( M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, o] for S_i in M.processInputsByOutput[r, p, t, v, o] - for S_s in M.time_season[p] + for S_s in M.TimeSeason[p] for S_d in M.time_of_day ) @@ -3103,7 +3103,7 @@ def LimitTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o, op): M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] - for S_s in M.time_season[p] + for S_s in M.TimeSeason[p] for S_d in M.time_of_day ) @@ -3126,7 +3126,7 @@ def RenewablePortfolioStandard_Constraint(M: 'TemoaModel', r, p, g): for t in M.tech_group_members[g] for (_t, v) in M.processReservePeriods[r, p] if _t == t - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] @@ -3135,7 +3135,7 @@ def RenewablePortfolioStandard_Constraint(M: 'TemoaModel', r, p, g): total_inp = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] for (t, v) in M.processReservePeriods[r, p] - for s in M.time_season[p] + for s in M.TimeSeason[p] for d in M.time_of_day for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] diff --git a/temoa/utilities/unit_cost_explorer.py b/temoa/utilities/unit_cost_explorer.py index 94fd8fc9c..8e77d067a 100644 --- a/temoa/utilities/unit_cost_explorer.py +++ b/temoa/utilities/unit_cost_explorer.py @@ -90,7 +90,7 @@ print('building storage level constraint...') # More SETS -M.time_season.construct(data=['winter', 'summer']) +M.TimeSeason.construct(data=['winter', 'summer']) tod_slices = 2 M.time_of_day.construct(data=range(1, tod_slices + 1)) M.tech_storage.construct(data=['battery']) @@ -111,7 +111,7 @@ M.StorageDuration.construct(data={('A', 'battery'): 4}) seasonal_fractions = {'winter': 0.4, 'summer': 0.6} M.SegFrac.construct( - data={(s, d): seasonal_fractions[s] / tod_slices for d in M.time_of_day for s in M.time_season} + data={(s, d): seasonal_fractions[s] / tod_slices for d in M.time_of_day for s in M.TimeSeason} ) # QA the total print(f'quality check. Total of all SegFrac: {sum(M.SegFrac.values()):0.3f}') diff --git a/tests/test_exchange_cost_ledger.py b/tests/test_exchange_cost_ledger.py index aab73ce90..29a26d2e2 100644 --- a/tests/test_exchange_cost_ledger.py +++ b/tests/test_exchange_cost_ledger.py @@ -33,7 +33,7 @@ # these are the necessary Temoa elements to make the ledger work data = { - 'time_season': {2000: [1]}, + 'TimeSeason': {2000: [1]}, 'time_of_day': {1}, 'tech_annual': set(), 'LifetimeProcess': {('A-B', 't1', 2000): 30, ('B-A', 't1', 2000): 30}, diff --git a/tests/testing_configs/config_emissions.toml b/tests/testing_configs/config_emissions.toml index 0dcaec2c1..050c2ca67 100644 --- a/tests/testing_configs/config_emissions.toml +++ b/tests/testing_configs/config_emissions.toml @@ -47,14 +47,14 @@ time_sequencing = 'seasonal_timeslices' # How contributions to the planning reserve margin are calculated # Options: # 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. +# Traditional planning reserve formulation. Contributions are independent of hourly availability: +# capacity value = net capacity * capacity credit # 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). +# Contributions are available output including a capacity derate factor (e.g., forced outage rate). # For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor +# capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# capacity value = flow out * reserve capacity derate reserve_margin = 'static' # --------------------------------------------------- diff --git a/tests/testing_configs/config_link_test.toml b/tests/testing_configs/config_link_test.toml index 8484b482f..ee370ac60 100644 --- a/tests/testing_configs/config_link_test.toml +++ b/tests/testing_configs/config_link_test.toml @@ -100,14 +100,14 @@ time_sequencing = 'seasonal_timeslices' # How contributions to the planning reserve margin are calculated # Options: # 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. +# Traditional planning reserve formulation. Contributions are independent of hourly availability: +# capacity value = net capacity * capacity credit # 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). +# Contributions are available output including a capacity derate factor (e.g., forced outage rate). # For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor +# capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# capacity value = flow out * reserve capacity derate reserve_margin = 'static' # --------------------------------------------------- diff --git a/tests/testing_configs/config_materials.toml b/tests/testing_configs/config_materials.toml index e2bac02ed..9182010cc 100644 --- a/tests/testing_configs/config_materials.toml +++ b/tests/testing_configs/config_materials.toml @@ -47,14 +47,14 @@ time_sequencing = 'seasonal_timeslices' # How contributions to the planning reserve margin are calculated # Options: # 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. +# Traditional planning reserve formulation. Contributions are independent of hourly availability: +# capacity value = net capacity * capacity credit # 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). +# Contributions are available output including a capacity derate factor (e.g., forced outage rate). # For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor +# capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# capacity value = flow out * reserve capacity derate reserve_margin = 'static' # --------------------------------------------------- diff --git a/tests/testing_configs/config_mediumville.toml b/tests/testing_configs/config_mediumville.toml index 4466f1ad7..077472f4c 100644 --- a/tests/testing_configs/config_mediumville.toml +++ b/tests/testing_configs/config_mediumville.toml @@ -81,14 +81,14 @@ time_sequencing = 'seasonal_timeslices' # How contributions to the planning reserve margin are calculated # Options: # 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. +# Traditional planning reserve formulation. Contributions are independent of hourly availability: +# capacity value = net capacity * capacity credit # 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). +# Contributions are available output including a capacity derate factor (e.g., forced outage rate). # For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor +# capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# capacity value = flow out * reserve capacity derate reserve_margin = 'static' # --------------------------------------------------- diff --git a/tests/testing_configs/config_seasonal_storage.toml b/tests/testing_configs/config_seasonal_storage.toml index 52179f64e..c1546cb1a 100644 --- a/tests/testing_configs/config_seasonal_storage.toml +++ b/tests/testing_configs/config_seasonal_storage.toml @@ -47,14 +47,14 @@ time_sequencing = 'representative_periods' # How contributions to the planning reserve margin are calculated # Options: # 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. +# Traditional planning reserve formulation. Contributions are independent of hourly availability: +# capacity value = net capacity * capacity credit # 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). +# Contributions are available output including a capacity derate factor (e.g., forced outage rate). # For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor +# capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# capacity value = flow out * reserve capacity derate reserve_margin = 'static' # --------------------------------------------------- diff --git a/tests/testing_configs/config_storageville.toml b/tests/testing_configs/config_storageville.toml index 2add2d9d3..964ccf896 100644 --- a/tests/testing_configs/config_storageville.toml +++ b/tests/testing_configs/config_storageville.toml @@ -81,14 +81,14 @@ time_sequencing = 'seasonal_timeslices' # How contributions to the planning reserve margin are calculated # Options: # 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. +# Traditional planning reserve formulation. Contributions are independent of hourly availability: +# capacity value = net capacity * capacity credit # 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). +# Contributions are available output including a capacity derate factor (e.g., forced outage rate). # For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor +# capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# capacity value = flow out * reserve capacity derate reserve_margin = 'static' # --------------------------------------------------- diff --git a/tests/testing_configs/config_survival_curve.toml b/tests/testing_configs/config_survival_curve.toml index 3c449e41c..11066e81f 100644 --- a/tests/testing_configs/config_survival_curve.toml +++ b/tests/testing_configs/config_survival_curve.toml @@ -47,14 +47,14 @@ time_sequencing = 'seasonal_timeslices' # How contributions to the planning reserve margin are calculated # Options: # 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. +# Traditional planning reserve formulation. Contributions are independent of hourly availability: +# capacity value = net capacity * capacity credit # 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). +# Contributions are available output including a capacity derate factor (e.g., forced outage rate). # For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor +# capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# capacity value = flow out * reserve capacity derate reserve_margin = 'static' # --------------------------------------------------- diff --git a/tests/testing_configs/config_test_system.toml b/tests/testing_configs/config_test_system.toml index 18e46d531..12032f9c0 100644 --- a/tests/testing_configs/config_test_system.toml +++ b/tests/testing_configs/config_test_system.toml @@ -47,14 +47,14 @@ time_sequencing = 'seasonal_timeslices' # How contributions to the planning reserve margin are calculated # Options: # 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. +# Traditional planning reserve formulation. Contributions are independent of hourly availability: +# capacity value = net capacity * capacity credit # 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). +# Contributions are available output including a capacity derate factor (e.g., forced outage rate). # For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor +# capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# capacity value = flow out * reserve capacity derate reserve_margin = 'static' # --------------------------------------------------- diff --git a/tests/testing_configs/config_utopia.toml b/tests/testing_configs/config_utopia.toml index ab7ff5dea..a58535cc7 100644 --- a/tests/testing_configs/config_utopia.toml +++ b/tests/testing_configs/config_utopia.toml @@ -47,14 +47,14 @@ time_sequencing = 'seasonal_timeslices' # How contributions to the planning reserve margin are calculated # Options: # 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. +# Traditional planning reserve formulation. Contributions are independent of hourly availability: +# capacity value = net capacity * capacity credit # 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). +# Contributions are available output including a capacity derate factor (e.g., forced outage rate). # For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor +# capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# capacity value = flow out * reserve capacity derate reserve_margin = 'static' # --------------------------------------------------- diff --git a/tests/testing_configs/config_utopia_myopic.toml b/tests/testing_configs/config_utopia_myopic.toml index 9051b91a0..a50593022 100644 --- a/tests/testing_configs/config_utopia_myopic.toml +++ b/tests/testing_configs/config_utopia_myopic.toml @@ -49,14 +49,14 @@ time_sequencing = 'seasonal_timeslices' # How contributions to the planning reserve margin are calculated # Options: # 'static' -# Traditional planning reserve. Contributions are independent of hourly availability: -# capacity value = available capacity * capacity credit. +# Traditional planning reserve formulation. Contributions are independent of hourly availability: +# capacity value = net capacity * capacity credit # 'dynamic' -# The capacity credit is treated as a capacity derate factor (forced outage rate). +# Contributions are available output including a capacity derate factor (e.g., forced outage rate). # For most generators, contributions are available (derated) output in each time slice: -# capacity value = available capacity * capacity credit * capacity factor +# capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * capacity credit +# capacity value = flow out * reserve capacity derate reserve_margin = 'static' # --------------------------------------------------- diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index a8957e3d2..56431b7ba 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -4113,7 +4113,7 @@ "d2" ] ], - "ReserveMargin": [ + "ReserveMarginMethod": [ "static" ], "RetiredCapacityVar_rptv": [], @@ -4372,10 +4372,14 @@ "time_optimize": [ 2025 ], - "time_season": [ + "TimeSeason": [ 2025 ], - "time_season_all": [ + "time_season": [ + "s1", + "s2" + ], + "time_season_sequential": [ "s1", "s2" ], diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 867c86a63..d87299a17 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -44964,7 +44964,7 @@ ], "RenewablePortfolioStandardConstraint_rpg": [], "ReserveMargin_rpsd": [], - "ReserveMargin": [ + "ReserveMarginMethod": [ "static" ], "RetiredCapacityVar_rptv": [], @@ -46705,17 +46705,18 @@ 2020, 2030 ], - "time_season": [ + "TimeSeason": [ 2025, 2020, 2030 ], - "time_season_all": [ + "time_season": [ "summer", "fall", "spring", "winter" ], + "time_season_sequential": [], "TimeSequencing": [ "seasonal_timeslices" ], diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 3b85e3590..f48de8e13 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -24720,7 +24720,7 @@ "RegionalExchangeCapacityConstraint_rrptv": [], "RenewablePortfolioStandardConstraint_rpg": [], "ReserveMargin_rpsd": [], - "ReserveMargin": [ + "ReserveMarginMethod": [ "static" ], "RetiredCapacityVar_rptv": [], @@ -25803,16 +25803,17 @@ 2010, 1990 ], - "time_season": [ + "TimeSeason": [ 2000, 2010, 1990 ], - "time_season_all": [ + "time_season": [ "summer", "inter", "winter" ], + "time_season_sequential": [], "TimeSequencing": [ "seasonal_timeslices" ], From 8ab0822c615d30dcdd50240e61f912e1a685c364 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 19 Jun 2025 14:05:48 -0400 Subject: [PATCH 140/587] Remove vestigial tech_resource set --- data_files/example_dbs/materials.sql | 1 - data_files/example_dbs/morris_utopia.sql | 15 ++-- data_files/example_dbs/seasonal_storage.sql | 1 - data_files/example_dbs/stepped_demand.sql | 3 +- data_files/example_dbs/survival_curve.sql | 1 - data_files/example_dbs/test_system.sql | 9 +-- data_files/example_dbs/utopia.sql | 15 ++-- data_files/temoa_schema_v3_1.sql | 4 +- temoa/temoa_model/hybrid_loader.py | 6 +- .../model_checking/pricing_check.py | 6 +- temoa/temoa_model/temoa_initialize.py | 8 +- temoa/temoa_model/temoa_model.py | 6 +- temoa/temoa_model/temoa_rules.py | 75 ++++++++++--------- temoa/utilities/db_migration_v3_to_v3_1.py | 5 ++ tests/testing_data/emissions.sql | 1 - tests/testing_data/materials.sql | 1 - tests/testing_data/mediumville.sql | 3 +- tests/testing_data/mediumville_sets.json | 6 +- tests/testing_data/seasonal_storage.sql | 1 - tests/testing_data/simple_linked_tech.sql | 7 +- tests/testing_data/storageville.sql | 3 +- tests/testing_data/survival_curve.sql | 1 - tests/testing_data/test_system.sql | 9 +-- tests/testing_data/test_system_sets.json | 6 +- tests/testing_data/utopia.sql | 15 ++-- tests/testing_data/utopia_sets.json | 6 +- 26 files changed, 99 insertions(+), 115 deletions(-) diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index 7585fee39..3a129f01f 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -1398,7 +1398,6 @@ CREATE TABLE TechnologyType PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index a884e12ca..6d698f4aa 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -1366,7 +1366,6 @@ CREATE TABLE TechnologyType PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); @@ -1484,13 +1483,13 @@ CREATE TABLE Technology description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('IMPDSL1','r','supply','petroleum','',1,0,0,0,0,0,0,' imported diesel'); -INSERT INTO Technology VALUES('IMPGSL1','r','supply','petroleum','',1,0,0,0,0,0,0,' imported gasoline'); -INSERT INTO Technology VALUES('IMPHCO1','r','supply','coal','',1,0,0,0,0,0,0,' imported coal'); -INSERT INTO Technology VALUES('IMPOIL1','r','supply','petroleum','',1,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO Technology VALUES('IMPURN1','r','supply','nuclear','',1,0,0,0,0,0,0,' imported uranium'); -INSERT INTO Technology VALUES('IMPFEQ','r','supply','petroleum','',1,0,0,0,0,0,0,' imported fossil equivalent'); -INSERT INTO Technology VALUES('IMPHYD','r','supply','','',1,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); +INSERT INTO Technology VALUES('IMPDSL1','p','supply','petroleum','',1,0,0,0,0,0,0,' imported diesel'); +INSERT INTO Technology VALUES('IMPGSL1','p','supply','petroleum','',1,0,0,0,0,0,0,' imported gasoline'); +INSERT INTO Technology VALUES('IMPHCO1','p','supply','coal','',1,0,0,0,0,0,0,' imported coal'); +INSERT INTO Technology VALUES('IMPOIL1','p','supply','petroleum','',1,0,0,0,0,0,0,' imported crude oil'); +INSERT INTO Technology VALUES('IMPURN1','p','supply','nuclear','',1,0,0,0,0,0,0,' imported uranium'); +INSERT INTO Technology VALUES('IMPFEQ','p','supply','petroleum','',1,0,0,0,0,0,0,' imported fossil equivalent'); +INSERT INTO Technology VALUES('IMPHYD','p','supply','','',1,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); INSERT INTO Technology VALUES('E01','pb','electric','coal','',0,0,0,1,1,0,0,' coal power plant'); INSERT INTO Technology VALUES('E21','pb','electric','nuclear','',0,0,0,1,1,0,0,' nuclear power plant'); INSERT INTO Technology VALUES('E31','pb','electric','hydro','',0,0,0,1,1,0,0,' hydro power'); diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql index 324b48fc5..9301b930e 100644 --- a/data_files/example_dbs/seasonal_storage.sql +++ b/data_files/example_dbs/seasonal_storage.sql @@ -909,7 +909,6 @@ CREATE TABLE TechnologyType PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index 4e632e754..422a97155 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -1113,7 +1113,6 @@ CREATE TABLE TechnologyType PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); @@ -1261,7 +1260,7 @@ CREATE TABLE Technology description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('well','r','supply','water','',1,0,0,0,0,0,0,'plain old water'); +INSERT INTO Technology VALUES('well','p','supply','water','',1,0,0,0,0,0,0,'plain old water'); INSERT INTO Technology VALUES('bulbs','p','residential','electric','',1,0,0,0,0,0,0,' residential lighting'); INSERT INTO Technology VALUES('EH','p','electric','hydro','',0,0,0,0,0,0,0,'hydro power electric plant'); INSERT INTO Technology VALUES('EF','p','electric','electric','',0,0,0,0,0,0,0,'fusion plant'); diff --git a/data_files/example_dbs/survival_curve.sql b/data_files/example_dbs/survival_curve.sql index 8f253e9b1..2684f7b4a 100644 --- a/data_files/example_dbs/survival_curve.sql +++ b/data_files/example_dbs/survival_curve.sql @@ -1006,7 +1006,6 @@ CREATE TABLE TechnologyType PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index 3b610dd17..fce105206 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -1360,7 +1360,6 @@ CREATE TABLE TechnologyType PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); @@ -1480,10 +1479,10 @@ CREATE TABLE Technology description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('S_IMPETH','r','supply','','',1,0,0,0,0,0,0,0,' imported ethanol'); -INSERT INTO Technology VALUES('S_IMPOIL','r','supply','','',1,0,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO Technology VALUES('S_IMPNG','r','supply','','',1,0,0,0,0,0,0,0,' imported natural gas'); -INSERT INTO Technology VALUES('S_IMPURN','r','supply','','',1,0,0,0,0,0,0,0,' imported uranium'); +INSERT INTO Technology VALUES('S_IMPETH','p','supply','','',1,0,0,0,0,0,0,0,' imported ethanol'); +INSERT INTO Technology VALUES('S_IMPOIL','p','supply','','',1,0,0,0,0,0,0,0,' imported crude oil'); +INSERT INTO Technology VALUES('S_IMPNG','p','supply','','',1,0,0,0,0,0,0,0,' imported natural gas'); +INSERT INTO Technology VALUES('S_IMPURN','p','supply','','',1,0,0,0,0,0,0,0,' imported uranium'); INSERT INTO Technology VALUES('S_OILREF','p','supply','','',0,0,0,1,0,0,0,0,' crude oil refinery'); INSERT INTO Technology VALUES('E_NGCC','p','electric','','',0,0,0,0,0,0,0,0,' natural gas combined-cycle'); INSERT INTO Technology VALUES('E_SOLPV','p','electric','','',0,0,0,0,0,0,0,0,' solar photovoltaic'); diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index e357d094e..2ebdc3b19 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -1361,7 +1361,6 @@ CREATE TABLE TechnologyType PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); @@ -1480,13 +1479,13 @@ CREATE TABLE Technology description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('IMPDSL1','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported diesel'); -INSERT INTO Technology VALUES('IMPGSL1','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported gasoline'); -INSERT INTO Technology VALUES('IMPHCO1','r','supply','coal','',1,0,0,0,0,0,0,0,' imported coal'); -INSERT INTO Technology VALUES('IMPOIL1','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO Technology VALUES('IMPURN1','r','supply','nuclear','',1,0,0,0,0,0,0,0,' imported uranium'); -INSERT INTO Technology VALUES('IMPFEQ','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported fossil equivalent'); -INSERT INTO Technology VALUES('IMPHYD','r','supply','hydro','',1,0,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); +INSERT INTO Technology VALUES('IMPDSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported diesel'); +INSERT INTO Technology VALUES('IMPGSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported gasoline'); +INSERT INTO Technology VALUES('IMPHCO1','p','supply','coal','',1,0,0,0,0,0,0,0,' imported coal'); +INSERT INTO Technology VALUES('IMPOIL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported crude oil'); +INSERT INTO Technology VALUES('IMPURN1','p','supply','nuclear','',1,0,0,0,0,0,0,0,' imported uranium'); +INSERT INTO Technology VALUES('IMPFEQ','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported fossil equivalent'); +INSERT INTO Technology VALUES('IMPHYD','p','supply','hydro','',1,0,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); INSERT INTO Technology VALUES('E01','pb','electric','coal','',0,0,0,0,0,0,0,0,' coal power plant'); INSERT INTO Technology VALUES('E21','pb','electric','nuclear','',0,0,0,0,0,0,0,0,' nuclear power plant'); INSERT INTO Technology VALUES('E31','pb','electric','hydro','',0,0,0,0,0,0,0,0,' hydro power'); diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index 57bf130b9..056d95e1f 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -13,7 +13,7 @@ VALUES ('myopic_base_year', 2000, 'Base Year for Myopic Analysis'); REPLACE INTO MetaData VALUES ('DB_MAJOR', 3, 'DB major version number'); REPLACE INTO MetaData -VALUES ('DB_MINOR', 0, 'DB minor version number'); +VALUES ('DB_MINOR', 1, 'DB minor version number'); REPLACE INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); @@ -882,8 +882,6 @@ CREATE TABLE IF NOT EXISTS TechnologyType description TEXT ); REPLACE INTO TechnologyType -VALUES ('r', 'resource technology'); -REPLACE INTO TechnologyType VALUES ('p', 'production technology'); REPLACE INTO TechnologyType VALUES ('pb', 'baseload production technology'); diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index b0aa705de..fa06ebde9 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -476,9 +476,9 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # === TECH SETS === - # tech_resource - raw = cur.execute("SELECT tech FROM main.Technology WHERE flag = 'r'").fetchall() - load_element(M.tech_resource, raw, self.viable_techs) + # tech_resource # devnote: not used anywhere + # raw = cur.execute("SELECT tech FROM main.Technology WHERE flag = 'r'").fetchall() + # load_element(M.tech_resource, raw, self.viable_techs) # tech_production raw = cur.execute("SELECT tech FROM main.Technology WHERE flag LIKE 'p%'").fetchall() diff --git a/temoa/temoa_model/model_checking/pricing_check.py b/temoa/temoa_model/model_checking/pricing_check.py index 61e7a377c..b2a66fcf9 100644 --- a/temoa/temoa_model/model_checking/pricing_check.py +++ b/temoa/temoa_model/model_checking/pricing_check.py @@ -223,8 +223,10 @@ def price_checker(M: 'TemoaModel') -> bool: logger.debug(' Starting price check #3') for region, tech, vintage in sorted_efficiency_rtv: # skip resources - if tech in M.tech_resource: - continue + # devnote: this feels like an OEO specific use case and not generally applicable. + # also, the tech_resource set isn't used ANYWHERE else + # if tech in M.tech_resource: + # continue # get the lifetime of the tech, or default lifetime = value(M.LifetimeProcess[region, tech, vintage]) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 7376e6f74..884a22712 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -856,8 +856,8 @@ def CreateSparseDicts(M: 'TemoaModel'): M.outputSplitAnnualVintages[r, p, t, o, op] = set() M.outputSplitAnnualVintages[r, p, t, o, op].add(v) - if t in M.tech_resource and (r, p, o) not in M.processByPeriodAndOutput: - M.processByPeriodAndOutput[r, p, o] = set() + # if t in M.tech_resource and (r, p, o) not in M.processByPeriodAndOutput: # not currently used + # M.processByPeriodAndOutput[r, p, o] = set() if t in M.tech_reserve and (r, p) not in M.processReservePeriods: M.processReservePeriods[r, p] = set() @@ -891,8 +891,8 @@ def CreateSparseDicts(M: 'TemoaModel'): if t in M.tech_downramping: M.rampDownVintages[r, p, t].add(v) - if t in M.tech_resource: - M.processByPeriodAndOutput[r, p, o].add((i, t, v)) + # if t in M.tech_resource: + # M.processByPeriodAndOutput[r, p, o].add((i, t, v)) # not currently used if t in M.tech_reserve: M.processReservePeriods[r, p].add((t, v)) if t in M.tech_exchange: diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index b11f6c3f9..826d2543e 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -122,7 +122,7 @@ def __init__(M, *args, **kwargs): M.inputSplitAnnualVintages = dict() M.outputSplitVintages = dict() M.outputSplitAnnualVintages = dict() - M.processByPeriodAndOutput = dict() + # M.processByPeriodAndOutput = dict() # not currently used M.exportRegions = dict() M.importRegions = dict() @@ -178,9 +178,9 @@ def __init__(M, *args, **kwargs): M.regionalGlobalIndices = Set(validate=region_group_check) # Define technology-related sets - M.tech_resource = Set() + # M.tech_resource = Set() # not actually used by anything M.tech_production = Set() - M.tech_all = Set(initialize=M.tech_resource | M.tech_production, validate=no_slash_or_pipe) + M.tech_all = Set(initialize=M.tech_production, validate=no_slash_or_pipe) # was M.tech_resource | M.tech_production M.tech_baseload = Set(within=M.tech_all) M.tech_annual = Set(within=M.tech_all) # annual storage not supported in Storage constraint or TableWriter, so exclude from domain diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index bb5650c69..5b924bd04 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1225,48 +1225,49 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): return expr -def ResourceExtraction_Constraint(M: 'TemoaModel', reg, p, r): - r""" - The ResourceExtraction constraint allows a modeler to specify an annual limit on - the amount of a particular resource Temoa may use in a period. The first version - of the constraint pertains to technologies with variable output at the time slice - level, and the second version pertains to technologies with constant annual output - belonging to the :code:`tech_annual` set. +# Devnote: Not currently active +# def ResourceExtraction_Constraint(M: 'TemoaModel', reg, p, r): +# r""" +# The ResourceExtraction constraint allows a modeler to specify an annual limit on +# the amount of a particular resource Temoa may use in a period. The first version +# of the constraint pertains to technologies with variable output at the time slice +# level, and the second version pertains to technologies with constant annual output +# belonging to the :code:`tech_annual` set. - .. math:: - :label: ResourceExtraction +# .. math:: +# :label: ResourceExtraction - \sum_{S, D, I, t \in T^r \& t \not \in T^{a}, V} \textbf{FO}_{r, p, s, d, i, t, v, c} \le RSC_{r, p, c} +# \sum_{S, D, I, t \in T^r \& t \not \in T^{a}, V} \textbf{FO}_{r, p, s, d, i, t, v, c} \le RSC_{r, p, c} - \forall \{r, p, c\} \in \Theta_{\text{ResourceExtraction}} +# \forall \{r, p, c\} \in \Theta_{\text{ResourceExtraction}} - \sum_{I, t \in T^r \& t \in T^{a}, V} \textbf{FOA}_{r, p, i, t, v, c} \le RSC_{r, p, c} +# \sum_{I, t \in T^r \& t \in T^{a}, V} \textbf{FOA}_{r, p, i, t, v, c} \le RSC_{r, p, c} - \forall \{r, p, c\} \in \Theta_{\text{ResourceExtraction}} - """ - logger.warning( - 'The ResourceBound parameter / ResourceExtraction constraint is not currently supported. ' - 'Recommend removing data from supporting table' - ) - # dev note: This constraint does not have a table in the current schema - # Additionally, the below (incorrect) construct assumes that a resource cannot be used - # by BOTH a non-annual and annual tech. It should be re-written to add these - # dev note: Cant think of a case where this would be needed but cant use LimitActivityGroup - try: - collected = sum( - M.V_FlowOut[reg, p, S_s, S_d, S_i, S_t, S_v, r] # is r the input or the output!? - for S_i, S_t, S_v in M.processByPeriodAndOutput.keys() - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day - ) - except KeyError: - collected = sum( - M.V_FlowOutAnnual[reg, p, S_i, S_t, S_v, r] - for S_i, S_t, S_v in M.processByPeriodAndOutput.keys() - ) - - expr = collected <= value(M.ResourceBound[reg, p, r]) - return expr +# \forall \{r, p, c\} \in \Theta_{\text{ResourceExtraction}} +# """ +# logger.warning( +# 'The ResourceBound parameter / ResourceExtraction constraint is not currently supported. ' +# 'Recommend removing data from supporting table' +# ) +# # dev note: This constraint does not have a table in the current schema +# # Additionally, the below (incorrect) construct assumes that a resource cannot be used +# # by BOTH a non-annual and annual tech. It should be re-written to add these +# # dev note: Cant think of a case where this would be needed but cant use LimitActivityGroup +# try: +# collected = sum( +# M.V_FlowOut[reg, p, S_s, S_d, S_i, S_t, S_v, r] # is r the input or the output!? +# for S_i, S_t, S_v in M.processByPeriodAndOutput.keys() +# for S_s in M.TimeSeason[p] +# for S_d in M.time_of_day +# ) +# except KeyError: +# collected = sum( +# M.V_FlowOutAnnual[reg, p, S_i, S_t, S_v, r] +# for S_i, S_t, S_v in M.processByPeriodAndOutput.keys() +# ) + +# expr = collected <= value(M.ResourceBound[reg, p, r]) +# return expr def BaseloadDiurnal_Constraint(M: 'TemoaModel', r, p, s, d, t, v): diff --git a/temoa/utilities/db_migration_v3_to_v3_1.py b/temoa/utilities/db_migration_v3_to_v3_1.py index 3713e58b6..60f551d97 100644 --- a/temoa/utilities/db_migration_v3_to_v3_1.py +++ b/temoa/utilities/db_migration_v3_to_v3_1.py @@ -292,6 +292,11 @@ def column_check(old_name: str, new_name: str) -> bool: print(f'Transfered {len(data)} rows from {old_name} to {new_name}') +# Removal of tech_resource +con_new.execute("UPDATE Technology SET flag='p' WHERE flag=='r';") +print('Converted all resource techs to production techs.') + + # LoanLifetimeTech -> LoanLifetimeProcess try: data = con_old.execute('SELECT region, tech, lifetime, notes FROM LoanLifetimeTech').fetchall() diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 14f70478f..a82bf2298 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -924,7 +924,6 @@ CREATE TABLE TechnologyType PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index 7585fee39..3a129f01f 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -1398,7 +1398,6 @@ CREATE TABLE TechnologyType PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 5352e8158..cbc21fd4e 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -1017,7 +1017,6 @@ CREATE TABLE TechnologyType PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); @@ -1129,7 +1128,7 @@ CREATE TABLE Technology description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('well','r','supply','water','',0,0,0,0,0,0,0,0,'plain old water'); +INSERT INTO Technology VALUES('well','p','supply','water','',0,0,0,0,0,0,0,0,'plain old water'); INSERT INTO Technology VALUES('bulbs','p','residential','electric','',0,0,0,0,0,0,0,0,'residential lighting'); INSERT INTO Technology VALUES('EH','pb','electric','hydro','',0,0,0,1,1,0,0,0,'hydro power electric plant'); INSERT INTO Technology VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0,0,'big battery'); diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 56431b7ba..030cf35c5 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -4327,14 +4327,12 @@ "heater", "EF", "FGF_pipe", - "batt" + "batt", + "well" ], "tech_reserve": [ "EF" ], - "tech_resource": [ - "well" - ], "tech_retirement": [ "EH" ], diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index 324b48fc5..9301b930e 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -909,7 +909,6 @@ CREATE TABLE TechnologyType PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index 0662ffb13..b2d45c249 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -895,7 +895,6 @@ CREATE TABLE TechnologyType PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); @@ -1003,9 +1002,9 @@ CREATE TABLE Technology FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); INSERT INTO Technology VALUES('PLANT','p','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('CCS','r','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('MINE','r','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('FAKE_SOURCE','r','supply',NULL,NULL,1,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('CCS','p','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('MINE','p','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('FAKE_SOURCE','p','supply',NULL,NULL,1,0,0,0,0,0,0,0,NULL); CREATE TABLE OutputCost ( scenario TEXT, diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index 28e89ac5b..fa13a1c21 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -916,7 +916,6 @@ CREATE TABLE TechnologyType PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); @@ -1027,7 +1026,7 @@ CREATE TABLE Technology description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('well','r','supply','water','',0,0,0,0,0,0,0,0,'plain old water'); +INSERT INTO Technology VALUES('well','p','supply','water','',0,0,0,0,0,0,0,0,'plain old water'); INSERT INTO Technology VALUES('bulbs','p','residential','electric','',0,0,0,0,0,0,0,0,' residential lighting'); INSERT INTO Technology VALUES('EH','pb','electric','hydro','',0,0,0,0,0,0,0,0,'hydro power electric plant'); INSERT INTO Technology VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0,0,'big battery'); diff --git a/tests/testing_data/survival_curve.sql b/tests/testing_data/survival_curve.sql index 8f253e9b1..2684f7b4a 100644 --- a/tests/testing_data/survival_curve.sql +++ b/tests/testing_data/survival_curve.sql @@ -1006,7 +1006,6 @@ CREATE TABLE TechnologyType PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 3b610dd17..fce105206 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -1360,7 +1360,6 @@ CREATE TABLE TechnologyType PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); @@ -1480,10 +1479,10 @@ CREATE TABLE Technology description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('S_IMPETH','r','supply','','',1,0,0,0,0,0,0,0,' imported ethanol'); -INSERT INTO Technology VALUES('S_IMPOIL','r','supply','','',1,0,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO Technology VALUES('S_IMPNG','r','supply','','',1,0,0,0,0,0,0,0,' imported natural gas'); -INSERT INTO Technology VALUES('S_IMPURN','r','supply','','',1,0,0,0,0,0,0,0,' imported uranium'); +INSERT INTO Technology VALUES('S_IMPETH','p','supply','','',1,0,0,0,0,0,0,0,' imported ethanol'); +INSERT INTO Technology VALUES('S_IMPOIL','p','supply','','',1,0,0,0,0,0,0,0,' imported crude oil'); +INSERT INTO Technology VALUES('S_IMPNG','p','supply','','',1,0,0,0,0,0,0,0,' imported natural gas'); +INSERT INTO Technology VALUES('S_IMPURN','p','supply','','',1,0,0,0,0,0,0,0,' imported uranium'); INSERT INTO Technology VALUES('S_OILREF','p','supply','','',0,0,0,1,0,0,0,0,' crude oil refinery'); INSERT INTO Technology VALUES('E_NGCC','p','electric','','',0,0,0,0,0,0,0,0,' natural gas combined-cycle'); INSERT INTO Technology VALUES('E_SOLPV','p','electric','','',0,0,0,0,0,0,0,0,' solar photovoltaic'); diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index d87299a17..fa72f8f84 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -46652,15 +46652,13 @@ "E_BATT", "E_SOLPV", "E_NUCLEAR", - "T_DSL" - ], - "tech_reserve": [], - "tech_resource": [ + "T_DSL", "S_IMPETH", "S_IMPNG", "S_IMPURN", "S_IMPOIL" ], + "tech_reserve": [], "tech_retirement": [], "tech_seasonal_storage": [], "tech_storage": [ diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index e357d094e..2ebdc3b19 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -1361,7 +1361,6 @@ CREATE TABLE TechnologyType PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('r','resource technology'); INSERT INTO TechnologyType VALUES('p','production technology'); INSERT INTO TechnologyType VALUES('pb','baseload production technology'); INSERT INTO TechnologyType VALUES('ps','storage production technology'); @@ -1480,13 +1479,13 @@ CREATE TABLE Technology description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -INSERT INTO Technology VALUES('IMPDSL1','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported diesel'); -INSERT INTO Technology VALUES('IMPGSL1','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported gasoline'); -INSERT INTO Technology VALUES('IMPHCO1','r','supply','coal','',1,0,0,0,0,0,0,0,' imported coal'); -INSERT INTO Technology VALUES('IMPOIL1','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO Technology VALUES('IMPURN1','r','supply','nuclear','',1,0,0,0,0,0,0,0,' imported uranium'); -INSERT INTO Technology VALUES('IMPFEQ','r','supply','petroleum','',1,0,0,0,0,0,0,0,' imported fossil equivalent'); -INSERT INTO Technology VALUES('IMPHYD','r','supply','hydro','',1,0,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); +INSERT INTO Technology VALUES('IMPDSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported diesel'); +INSERT INTO Technology VALUES('IMPGSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported gasoline'); +INSERT INTO Technology VALUES('IMPHCO1','p','supply','coal','',1,0,0,0,0,0,0,0,' imported coal'); +INSERT INTO Technology VALUES('IMPOIL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported crude oil'); +INSERT INTO Technology VALUES('IMPURN1','p','supply','nuclear','',1,0,0,0,0,0,0,0,' imported uranium'); +INSERT INTO Technology VALUES('IMPFEQ','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported fossil equivalent'); +INSERT INTO Technology VALUES('IMPHYD','p','supply','hydro','',1,0,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); INSERT INTO Technology VALUES('E01','pb','electric','coal','',0,0,0,0,0,0,0,0,' coal power plant'); INSERT INTO Technology VALUES('E21','pb','electric','nuclear','',0,0,0,0,0,0,0,0,' nuclear power plant'); INSERT INTO Technology VALUES('E31','pb','electric','hydro','',0,0,0,0,0,0,0,0,' hydro power'); diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index f48de8e13..2b870d5a3 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -25742,10 +25742,7 @@ "RHE", "E31", "RL1", - "SRE" - ], - "tech_reserve": [], - "tech_resource": [ + "SRE", "IMPDSL1", "IMPHYD", "IMPHCO1", @@ -25754,6 +25751,7 @@ "IMPURN1", "IMPOIL1" ], + "tech_reserve": [], "tech_retirement": [], "tech_seasonal_storage": [], "tech_storage": [ From a951e048bebd6791282ab2e0123050730dc620af Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 19 Jun 2025 15:05:38 -0400 Subject: [PATCH 141/587] Update temoa basics 0 --- data_files/temoa_basics_0.sql | 302 ++++++++++-------- temoa/extensions/myopic/myopic_sequencer.py | 6 +- temoa/temoa_model/hybrid_loader.py | 17 +- .../model_checking/network_model_data.py | 9 +- 4 files changed, 186 insertions(+), 148 deletions(-) diff --git a/data_files/temoa_basics_0.sql b/data_files/temoa_basics_0.sql index 52d82fd33..aa659931a 100644 --- a/data_files/temoa_basics_0.sql +++ b/data_files/temoa_basics_0.sql @@ -11,13 +11,20 @@ CREATE TABLE IF NOT EXISTS MetaData REPLACE INTO MetaData VALUES ('DB_MAJOR', 3, 'DB major version number'); REPLACE INTO MetaData -VALUES ('DB_MINOR', 0, 'DB minor version number'); -CREATE TABLE IF NOT EXISTS OutputObjective +VALUES ('DB_MINOR', 1, 'DB minor version number'); +CREATE TABLE IF NOT EXISTS MetaDataReal ( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) ); +REPLACE INTO MetaDataReal +VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); +REPLACE INTO MetaDataReal +VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in LoanRate table'); + CREATE TABLE IF NOT EXISTS Commodity ( name TEXT @@ -26,14 +33,6 @@ CREATE TABLE IF NOT EXISTS Commodity REFERENCES CommodityType (label), description TEXT ); -REPLACE INTO Commodity -VALUES ('ethos', 's', NULL); -REPLACE INTO Commodity -VALUES ('fuel', 'p', NULL); -REPLACE INTO Commodity -VALUES ('carrier', 'p', NULL); -REPLACE INTO Commodity -VALUES ('demand', 'd', NULL); CREATE TABLE IF NOT EXISTS CommodityType ( label TEXT @@ -98,8 +97,6 @@ CREATE TABLE IF NOT EXISTS Demand notes TEXT, PRIMARY KEY (region, period, commodity) ); -REPLACE INTO Demand -VALUES ('region', 2000, 'demand', 1, NULL, NULL); CREATE TABLE IF NOT EXISTS Efficiency ( region TEXT, @@ -116,48 +113,25 @@ CREATE TABLE IF NOT EXISTS Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -REPLACE INTO Efficiency -VALUES ('region', 'ethos', 'importer', 2000, 'fuel', 1, NULL); -REPLACE INTO Efficiency -VALUES ('region', 'fuel', 'producer', 2000, 'carrier', 1, NULL); -REPLACE INTO Efficiency -VALUES ('region', 'carrier', 'consumer', 2000, 'demand', 1, NULL); -CREATE TABLE IF NOT EXISTS OutputCurtailment +CREATE TABLE IF NOT EXISTS LifetimeProcess ( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT + region TEXT, + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE IF NOT EXISTS OutputNetCapacity +CREATE TABLE IF NOT EXISTS LifetimeTech ( - scenario TEXT, region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) ); CREATE TABLE IF NOT EXISTS OutputBuiltCapacity ( @@ -172,20 +146,71 @@ CREATE TABLE IF NOT EXISTS OutputBuiltCapacity capacity REAL, PRIMARY KEY (region, scenario, tech, vintage) ); -CREATE TABLE IF NOT EXISTS OutputRetiredCapacity +CREATE TABLE OutputCost ( scenario TEXT, region TEXT, - sector TEXT + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES TimePeriod (period), + FOREIGN KEY (tech) REFERENCES Technology (tech) +); +CREATE TABLE IF NOT EXISTS OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputDualVariable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE IF NOT EXISTS OutputEmission +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES SectorLabel (sector), - period INTEGER + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); CREATE TABLE IF NOT EXISTS OutputFlowIn ( @@ -195,8 +220,7 @@ CREATE TABLE IF NOT EXISTS OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -218,8 +242,7 @@ CREATE TABLE IF NOT EXISTS OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -233,75 +256,76 @@ CREATE TABLE IF NOT EXISTS OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE IF NOT EXISTS OutputDualVariable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE IF NOT EXISTS Region +CREATE TABLE IF NOT EXISTS OutputNetCapacity ( - region TEXT - PRIMARY KEY, - notes TEXT + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) ); -REPLACE INTO Region -VALUES ('region', NULL); -CREATE TABLE IF NOT EXISTS TechnologyType +CREATE TABLE IF NOT EXISTS OutputObjective ( - label TEXT - PRIMARY KEY, - description TEXT + scenario TEXT, + objective_name TEXT, + total_system_cost REAL ); -REPLACE INTO TechnologyType -VALUES ('r', 'resource technology'); -REPLACE INTO TechnologyType -VALUES ('p', 'production technology'); -REPLACE INTO TechnologyType -VALUES ('pb', 'baseload production technology'); -REPLACE INTO TechnologyType -VALUES ('ps', 'storage production technology'); -CREATE TABLE IF NOT EXISTS TimePeriod +CREATE TABLE IF NOT EXISTS OutputRetiredCapacity ( - sequence INTEGER UNIQUE, + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES TimePeriodType (label) -); -REPLACE INTO TimePeriod -VALUES (0, 2000, 'f'); -REPLACE INTO TimePeriod -VALUES (1, 2001, 'f'); -CREATE TABLE IF NOT EXISTS TimePeriodType -( - label TEXT - PRIMARY KEY, - description TEXT + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) ); -REPLACE INTO TimePeriodType VALUES ('f', 'future'); -CREATE TABLE IF NOT EXISTS OutputEmission +CREATE TABLE IF NOT EXISTS OutputStorageLevel ( - scenario TEXT, - region TEXT, - sector TEXT + scenario TEXT, + region TEXT, + sector TEXT REFERENCES SectorLabel (sector), - period INTEGER + period INTEGER REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES TimePeriod (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); +CREATE TABLE IF NOT EXISTS Region +( + region TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE IF NOT EXISTS SectorLabel +( + sector TEXT, + PRIMARY KEY (sector) ); CREATE TABLE IF NOT EXISTS Technology ( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, sector TEXT, category TEXT, sub_category TEXT, @@ -312,34 +336,36 @@ CREATE TABLE IF NOT EXISTS Technology retire INTEGER NOT NULL DEFAULT 0, flex INTEGER NOT NULL DEFAULT 0, exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -REPLACE INTO Technology -VALUES ('importer', 'r', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); -REPLACE INTO Technology -VALUES ('producer', 'p', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); -REPLACE INTO Technology -VALUES ('consumer', 'p', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); -CREATE TABLE OutputCost +CREATE TABLE IF NOT EXISTS TechnologyType ( - scenario TEXT, - region TEXT REFERENCES Region (region), - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO TechnologyType +VALUES ('p', 'production technology'); +CREATE TABLE IF NOT EXISTS TimePeriod +( + sequence INTEGER UNIQUE, + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES TimePeriodType (label) ); +CREATE TABLE IF NOT EXISTS TimePeriodType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO TimePeriodType +VALUES('e', 'existing vintages'); +REPLACE INTO TimePeriodType +VALUES('f', 'future'); + COMMIT; PRAGMA FOREIGN_KEYS = 1; diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index 21ab54250..8576e0806 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -475,8 +475,10 @@ def characterize_run(self, future_periods: list[int] | None = None) -> None: # check that we have enough periods to do myopic run # 2 iterations, excluding end year, will be via shortened depth, if reqd. - if len(future_periods) < 3: - logger.error('Not enough future years to run myopic mode: %d', len(future_periods)) + if len(future_periods) < self.view_depth+1: + logger.error( + 'Not enough future years to run myopic mode. Need %d including end year. Got %d.', self.view_depth+1, len(future_periods) + ) sys.exit(-1) self.optimization_periods = future_periods.copy() last_idx = len(future_periods) - 1 diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index fa06ebde9..d0de51479 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -652,11 +652,18 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N 'No TimeSegmentFraction table found. Loading filler SegFrac ("S", "D") for one time segment per period' ' (assume this is a periodic model)' ) - raw = [ - (p, "S", "D", 1) - for p in time_optimize - if mi.base_year <= p <= mi.last_demand_year - ] # if no segfrac table, assume this is a periodic model + # if no segfrac table, assume this is a periodic model + if mi: + raw = [ + (p, "S", "D", 1) + for p in time_optimize + if mi.base_year <= p <= mi.last_demand_year + ] + else: + raw = [ + (p, "S", "D", 1) + for p in time_optimize + ] load_element(M.SegFrac, raw) # TimeSeason diff --git a/temoa/temoa_model/model_checking/network_model_data.py b/temoa/temoa_model/model_checking/network_model_data.py index 522211b05..2a93a625d 100644 --- a/temoa/temoa_model/model_checking/network_model_data.py +++ b/temoa/temoa_model/model_checking/network_model_data.py @@ -318,9 +318,12 @@ def _build_from_db( res.waste_commodities = waste_dict # pick up the linked techs... - raw = cur.execute( - 'SELECT primary_region, primary_tech, emis_comm, driven_tech FROM main.LinkedTech' - ).fetchall() + try: + raw = cur.execute( + 'SELECT primary_region, primary_tech, emis_comm, driven_tech FROM main.LinkedTech' + ).fetchall() + except: + raw = [] res.available_linked_techs = { LinkedTech(region=r, driver=driver, emission=emiss, driven=driven) for (r, driver, emiss, driven) in raw From 9b439081a6bd0981f26dab83fdb370effcc08227 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 19 Jun 2025 16:13:53 -0400 Subject: [PATCH 142/587] Remove myopic_base_year from MetaData table --- data_files/example_dbs/materials.sql | 1 - data_files/example_dbs/morris_utopia.sql | 1 - data_files/example_dbs/seasonal_storage.sql | 1 - data_files/example_dbs/stepped_demand.sql | 1 - data_files/example_dbs/survival_curve.sql | 1 - data_files/example_dbs/test_system.sql | 1 - data_files/example_dbs/utopia.sql | 1 - data_files/temoa_schema_v3_1.sql | 2 -- temoa/extensions/myopic/myopic_sequencer.py | 2 +- temoa/temoa_model/hybrid_loader.py | 15 +++++++-------- temoa/temoa_model/table_writer.py | 4 ++-- temoa/temoa_model/temoa_model.py | 2 +- temoa/temoa_model/temoa_rules.py | 4 ++-- temoa/utilities/unit_cost_explorer.py | 2 +- tests/testing_data/emissions.sql | 1 - tests/testing_data/materials.sql | 1 - tests/testing_data/mediumville.sql | 1 - tests/testing_data/seasonal_storage.sql | 1 - tests/testing_data/storageville.sql | 1 - tests/testing_data/survival_curve.sql | 1 - tests/testing_data/test_system.sql | 1 - tests/testing_data/utopia.sql | 1 - 22 files changed, 14 insertions(+), 32 deletions(-) diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index 3a129f01f..d7c1b5891 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -7,7 +7,6 @@ CREATE TABLE MetaData notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index 6d698f4aa..e12b9ce58 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -7,7 +7,6 @@ CREATE TABLE MetaData notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql index 9301b930e..a4491ce98 100644 --- a/data_files/example_dbs/seasonal_storage.sql +++ b/data_files/example_dbs/seasonal_storage.sql @@ -7,7 +7,6 @@ CREATE TABLE MetaData notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); INSERT INTO MetaData VALUES('days_per_period',365,'count of days in each period'); diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index 422a97155..d8563ad42 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -9,7 +9,6 @@ CREATE TABLE MetaData ); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES('myopic_base_year',2000,''); INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); CREATE TABLE MetaDataReal ( diff --git a/data_files/example_dbs/survival_curve.sql b/data_files/example_dbs/survival_curve.sql index 2684f7b4a..7a3fa2e2d 100644 --- a/data_files/example_dbs/survival_curve.sql +++ b/data_files/example_dbs/survival_curve.sql @@ -7,7 +7,6 @@ CREATE TABLE MetaData notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); INSERT INTO MetaData VALUES('days_per_period',365,'count of days in each period'); diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index fce105206..162d6517d 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -7,7 +7,6 @@ CREATE TABLE MetaData notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 2ebdc3b19..0c148eee9 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -7,7 +7,6 @@ CREATE TABLE MetaData notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('myopic_base_year',1990,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index 056d95e1f..74c334448 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -9,8 +9,6 @@ CREATE TABLE IF NOT EXISTS MetaData PRIMARY KEY (element) ); REPLACE INTO MetaData -VALUES ('myopic_base_year', 2000, 'Base Year for Myopic Analysis'); -REPLACE INTO MetaData VALUES ('DB_MAJOR', 3, 'DB major version number'); REPLACE INTO MetaData VALUES ('DB_MINOR', 1, 'DB minor version number'); diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index 8576e0806..65d8cdbee 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -281,7 +281,7 @@ def start(self): last_base_year = idx.base_year # update # delete anything in the OutputObjective table, it is nonsensical... - self.output_con.execute('DELETE FROM OutputObjective WHERE 1') + self.output_con.execute(f'DELETE FROM OutputObjective WHERE scenario == "{self.config.scenario}"') self.output_con.commit() # 11. Compact the db... lots of writes/deletes leads to bloat diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index d0de51479..99198f837 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -367,7 +367,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # time_exist if mi: raw = cur.execute( - 'SELECT period FROM main.TimePeriod WHERE period < ? ORDER BY sequence', + 'SELECT period FROM main.TimePeriod WHERE period < ? ORDER BY sequence', (mi.base_year,), ).fetchall() else: @@ -380,7 +380,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N if mi: raw = cur.execute( 'SELECT period FROM main.TimePeriod WHERE ' - 'period >= ? AND period <= ? ORDER BY sequence', + 'flag = "f" AND period >= ? AND period <= ? ORDER BY sequence', (mi.base_year, mi.last_year), ).fetchall() else: @@ -431,13 +431,12 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # myopic_base_year if mi: - raw = cur.execute( - "SELECT value from MetaData WHERE element == 'myopic_base_year'" - ).fetchall() + # assume first future period by default + p0 = cur.execute( + "SELECT min(period) FROM TimePeriod WHERE flag == 'f'" + ).fetchone() # load as a singleton... - if not raw: - raise ValueError('No myopic_base_year found in MetaData table.') - data[M.MyopicBaseyear.name] = {None: int(raw[0][0])} + data[M.MyopicDiscountingP0.name] = {None: int(p0[0])} # days_per_season raw = cur.execute( diff --git a/temoa/temoa_model/table_writer.py b/temoa/temoa_model/table_writer.py index 967858d92..8c4685f14 100644 --- a/temoa/temoa_model/table_writer.py +++ b/temoa/temoa_model/table_writer.py @@ -127,7 +127,7 @@ def write_results( self.write_capacity_tables(M, iteration=iteration) # analyze the emissions to get the costs and flows if self.config.scenario_mode == TemoaMode.MYOPIC: - p_0 = M.MyopicBaseyear + p_0 = M.MyopicDiscountingP0 else: p_0 = None # min year will be used in poll e_costs, e_flows = poll_emissions(M=M, p_0=p_0) @@ -498,7 +498,7 @@ def write_costs(self, M: TemoaModel, emission_entries=None, iteration=None): # P_0 is usually the first optimization year, but if running myopic, we could assign it via # table entry. Perhaps in future it is just always the first optimization year of the 1st iter. if self.config.scenario_mode == TemoaMode.MYOPIC: - p_0 = M.MyopicBaseyear + p_0 = M.MyopicDiscountingP0 else: p_0 = min(M.time_optimize) diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 826d2543e..ab4508fc1 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -522,7 +522,7 @@ def __init__(M, *args, **kwargs): M.EmissionEmbodied = Param(M.regions, M.commodity_emissions, M.tech_with_capacity, M.vintage_optimize) M.EmissionEndOfLife = Param(M.regions, M.commodity_emissions, M.tech_with_capacity, M.vintage_all) - M.MyopicBaseyear = Param(default=0) + M.MyopicDiscountingP0 = Param(default=0) ################################################ # Model Variables # diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 5b924bd04..515af4681 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -599,8 +599,8 @@ def PeriodCost_rule(M: 'TemoaModel', p): GDR = value(M.GlobalDiscountRate) MPL = M.ModelProcessLife - if value(M.MyopicBaseyear) != 0: - P_0 = value(M.MyopicBaseyear) + if value(M.MyopicDiscountingP0) != 0: + P_0 = value(M.MyopicDiscountingP0) loan_costs = sum( loan_cost( diff --git a/temoa/utilities/unit_cost_explorer.py b/temoa/utilities/unit_cost_explorer.py index 8e77d067a..05ec057b7 100644 --- a/temoa/utilities/unit_cost_explorer.py +++ b/temoa/utilities/unit_cost_explorer.py @@ -38,7 +38,7 @@ M.LoanRate_rtv.construct(data=rtv) M.LifetimeProcess_rtv.construct(data=rtv) M.regionalIndices.construct(data=['A']) -M.MyopicBaseyear.construct(data={None: 0}) +M.MyopicDiscountingP0.construct(data={None: 0}) M.ModelProcessLife_rptv.construct(data=rptv) diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index a82bf2298..1719a6bd6 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -7,7 +7,6 @@ CREATE TABLE MetaData notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index 3a129f01f..d7c1b5891 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -7,7 +7,6 @@ CREATE TABLE MetaData notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index cbc21fd4e..96a071a90 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -9,7 +9,6 @@ CREATE TABLE MetaData ); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES('myopic_base_year',2000,''); INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); CREATE TABLE MetaDataReal ( diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index 9301b930e..a4491ce98 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -7,7 +7,6 @@ CREATE TABLE MetaData notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); INSERT INTO MetaData VALUES('days_per_period',365,'count of days in each period'); diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index fa13a1c21..181be5d2c 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -9,7 +9,6 @@ CREATE TABLE MetaData ); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES('myopic_base_year',2000,''); INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); CREATE TABLE MetaDataReal ( diff --git a/tests/testing_data/survival_curve.sql b/tests/testing_data/survival_curve.sql index 2684f7b4a..7a3fa2e2d 100644 --- a/tests/testing_data/survival_curve.sql +++ b/tests/testing_data/survival_curve.sql @@ -7,7 +7,6 @@ CREATE TABLE MetaData notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); INSERT INTO MetaData VALUES('days_per_period',365,'count of days in each period'); diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index fce105206..162d6517d 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -7,7 +7,6 @@ CREATE TABLE MetaData notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 2ebdc3b19..0c148eee9 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -7,7 +7,6 @@ CREATE TABLE MetaData notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('myopic_base_year',1990,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); From b87084a7900b7bd4d423682bc98e2088df7ab2b4 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 19 Jun 2025 16:17:46 -0400 Subject: [PATCH 143/587] Update DB_MINOR to 1 --- data_files/example_dbs/seasonal_storage.sql | 2 +- data_files/example_dbs/stepped_demand.sql | 2 +- data_files/example_dbs/survival_curve.sql | 2 +- tests/testing_data/seasonal_storage.sql | 2 +- tests/testing_data/simple_linked_tech.sql | 1 - 5 files changed, 4 insertions(+), 5 deletions(-) diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql index a4491ce98..899d680f0 100644 --- a/data_files/example_dbs/seasonal_storage.sql +++ b/data_files/example_dbs/seasonal_storage.sql @@ -8,7 +8,7 @@ CREATE TABLE MetaData PRIMARY KEY (element) ); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); +INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES('days_per_period',365,'count of days in each period'); CREATE TABLE MetaDataReal ( diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index d8563ad42..622b75ee0 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -9,7 +9,7 @@ CREATE TABLE MetaData ); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); +INSERT INTO MetaData VALUES('days_per_period', 365, 'count of days in each period'); CREATE TABLE MetaDataReal ( element TEXT, diff --git a/data_files/example_dbs/survival_curve.sql b/data_files/example_dbs/survival_curve.sql index 7a3fa2e2d..6301485ed 100644 --- a/data_files/example_dbs/survival_curve.sql +++ b/data_files/example_dbs/survival_curve.sql @@ -8,7 +8,7 @@ CREATE TABLE MetaData PRIMARY KEY (element) ); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); +INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES('days_per_period',365,'count of days in each period'); CREATE TABLE MetaDataReal ( diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index a4491ce98..899d680f0 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -8,7 +8,7 @@ CREATE TABLE MetaData PRIMARY KEY (element) ); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); +INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES('days_per_period',365,'count of days in each period'); CREATE TABLE MetaDataReal ( diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index b2d45c249..f2b462066 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -9,7 +9,6 @@ CREATE TABLE MetaData ); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES('myopic_base_year',1990,''); INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); CREATE TABLE MetaDataReal ( From 87d25bbf0c514b09abdd864627c190abad37767f Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 19 Jun 2025 16:44:25 -0400 Subject: [PATCH 144/587] Update all basics schemas --- data_files/temoa_basics_0.sql | 6 +- data_files/temoa_basics_1.sql | 398 +++++++++--------- data_files/temoa_basics_2.sql | 689 ++++++++++++++++--------------- data_files/temoa_schema_v3_1.sql | 6 +- 4 files changed, 543 insertions(+), 556 deletions(-) diff --git a/data_files/temoa_basics_0.sql b/data_files/temoa_basics_0.sql index aa659931a..40591a1dc 100644 --- a/data_files/temoa_basics_0.sql +++ b/data_files/temoa_basics_0.sql @@ -40,11 +40,11 @@ CREATE TABLE IF NOT EXISTS CommodityType description TEXT ); REPLACE INTO CommodityType +VALUES ('s', 'source commodity'); +REPLACE INTO CommodityType VALUES ('p', 'physical commodity'); REPLACE INTO CommodityType VALUES ('d', 'demand commodity'); -REPLACE INTO CommodityType -VALUES ('s', 'source commodity'); CREATE TABLE IF NOT EXISTS CostFixed ( region TEXT NOT NULL, @@ -368,4 +368,4 @@ REPLACE INTO TimePeriodType VALUES('f', 'future'); COMMIT; -PRAGMA FOREIGN_KEYS = 1; +PRAGMA FOREIGN_KEYS = 1; \ No newline at end of file diff --git a/data_files/temoa_basics_1.sql b/data_files/temoa_basics_1.sql index 361a58ae6..d0a9c779e 100644 --- a/data_files/temoa_basics_1.sql +++ b/data_files/temoa_basics_1.sql @@ -11,38 +11,46 @@ CREATE TABLE IF NOT EXISTS MetaData REPLACE INTO MetaData VALUES ('DB_MAJOR', 3, 'DB major version number'); REPLACE INTO MetaData -VALUES ('DB_MINOR', 0, 'DB minor version number'); -CREATE TABLE IF NOT EXISTS OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE IF NOT EXISTS CapacityToActivity +VALUES ('DB_MINOR', 1, 'DB minor version number'); +REPLACE INTO MetaData +VALUES ('days_per_period', 365, 'count of days in each period'); +CREATE TABLE IF NOT EXISTS MetaDataReal ( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) ); +REPLACE INTO MetaDataReal +VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); +REPLACE INTO MetaDataReal +VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in LoanRate table'); + CREATE TABLE IF NOT EXISTS CapacityFactorTech ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), tech TEXT REFERENCES Technology (tech), factor REAL, notes TEXT, - PRIMARY KEY (region, season, tod, tech), + PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); +CREATE TABLE IF NOT EXISTS CapacityToActivity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + c2a REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); CREATE TABLE IF NOT EXISTS Commodity ( name TEXT @@ -51,14 +59,6 @@ CREATE TABLE IF NOT EXISTS Commodity REFERENCES CommodityType (label), description TEXT ); -REPLACE INTO Commodity -VALUES ('ethos', 's', NULL); -REPLACE INTO Commodity -VALUES ('fuel', 'p', NULL); -REPLACE INTO Commodity -VALUES ('carrier', 'p', NULL); -REPLACE INTO Commodity -VALUES ('demand', 'd', NULL); CREATE TABLE IF NOT EXISTS CommodityType ( label TEXT @@ -66,15 +66,18 @@ CREATE TABLE IF NOT EXISTS CommodityType description TEXT ); REPLACE INTO CommodityType +VALUES ('s', 'source commodity'); +REPLACE INTO CommodityType +VALUES ('a', 'annual commodity'); +REPLACE INTO CommodityType VALUES ('p', 'physical commodity'); REPLACE INTO CommodityType VALUES ('d', 'demand commodity'); REPLACE INTO CommodityType -VALUES ('s', 'source commodity'); +VALUES ('e', 'emissions commodity'); CREATE TABLE IF NOT EXISTS CostEmission ( - region TEXT - REFERENCES Region (region), + region TEXT, period INTEGER REFERENCES TimePeriod (period), emis_comm TEXT NOT NULL @@ -136,32 +139,21 @@ CREATE TABLE IF NOT EXISTS Demand notes TEXT, PRIMARY KEY (region, period, commodity) ); -REPLACE INTO Demand -VALUES ('region', 2000, 'demand', 1, NULL, NULL); CREATE TABLE IF NOT EXISTS DemandSpecificDistribution ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT REFERENCES Commodity (name), dsd REAL, - dsd_notes TEXT, + notes TEXT, PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -REPLACE INTO DemandSpecificDistribution -VALUES ('region', 2000, 'S1', 'D1', 'demand', 0.25, NULL); -REPLACE INTO DemandSpecificDistribution -VALUES ('region', 2000, 'S1', 'D2', 'demand', 0.25, NULL); -REPLACE INTO DemandSpecificDistribution -VALUES ('region', 2000, 'S2', 'D1', 'demand', 0.25, NULL); -REPLACE INTO DemandSpecificDistribution -VALUES ('region', 2000, 'S2', 'D2', 'demand', 0.25, NULL); CREATE TABLE IF NOT EXISTS Efficiency ( region TEXT, @@ -178,12 +170,6 @@ CREATE TABLE IF NOT EXISTS Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -REPLACE INTO Efficiency -VALUES ('region', 'ethos', 'importer', 2000, 'fuel', 1, NULL); -REPLACE INTO Efficiency -VALUES ('region', 'fuel', 'producer', 2000, 'carrier', 1, NULL); -REPLACE INTO Efficiency -VALUES ('region', 'carrier', 'consumer', 2000, 'demand', 1, NULL); CREATE TABLE IF NOT EXISTS EmissionActivity ( region TEXT, @@ -214,6 +200,17 @@ CREATE TABLE IF NOT EXISTS ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); +CREATE TABLE IF NOT EXISTS LifetimeProcess +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); CREATE TABLE IF NOT EXISTS LifetimeTech ( region TEXT, @@ -223,6 +220,39 @@ CREATE TABLE IF NOT EXISTS LifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); +CREATE TABLE IF NOT EXISTS OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE OutputCost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES TimePeriod (period), + FOREIGN KEY (tech) REFERENCES Technology (tech) +); CREATE TABLE IF NOT EXISTS OutputCurtailment ( scenario TEXT, @@ -245,48 +275,29 @@ CREATE TABLE IF NOT EXISTS OutputCurtailment curtailment REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE IF NOT EXISTS OutputNetCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputBuiltCapacity +CREATE TABLE IF NOT EXISTS OutputDualVariable ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) ); -CREATE TABLE IF NOT EXISTS OutputRetiredCapacity +CREATE TABLE IF NOT EXISTS OutputEmission ( - scenario TEXT, - region TEXT, - sector TEXT + scenario TEXT, + region TEXT, + sector TEXT REFERENCES SectorLabel (sector), - period INTEGER + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); CREATE TABLE IF NOT EXISTS OutputFlowIn ( @@ -296,8 +307,7 @@ CREATE TABLE IF NOT EXISTS OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -319,8 +329,7 @@ CREATE TABLE IF NOT EXISTS OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -334,35 +343,67 @@ CREATE TABLE IF NOT EXISTS OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE IF NOT EXISTS OutputDualVariable +CREATE TABLE IF NOT EXISTS OutputNetCapacity ( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) ); -CREATE TABLE IF NOT EXISTS PeriodSeasons -( +CREATE TABLE IF NOT EXISTS OutputObjective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE IF NOT EXISTS OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - sequence INTEGER, - season TEXT - REFERENCES TimeSeason (season), - notes TEXT, - PRIMARY KEY (period, sequence) + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); -REPLACE INTO PeriodSeasons -VALUES (2000, 1, 'S1', NULL); -REPLACE INTO PeriodSeasons -VALUES (2000, 2, 'S2', NULL); CREATE TABLE IF NOT EXISTS Region ( region TEXT PRIMARY KEY, notes TEXT ); -REPLACE INTO Region -VALUES ('region', NULL); CREATE TABLE IF NOT EXISTS SectorLabel ( sector TEXT, @@ -376,27 +417,24 @@ CREATE TABLE IF NOT EXISTS StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE IF NOT EXISTS TimeSegmentFraction -( - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) +CREATE TABLE IF NOT EXISTS Technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -REPLACE INTO TimeSegmentFraction -VALUES (2000, 'S1', 'D1', 0.25, NULL); -REPLACE INTO TimeSegmentFraction -VALUES (2000, 'S1', 'D2', 0.25, NULL); -REPLACE INTO TimeSegmentFraction -VALUES (2000, 'S2', 'D1', 0.25, NULL); -REPLACE INTO TimeSegmentFraction -VALUES (2000, 'S2', 'D2', 0.25, NULL); CREATE TABLE IF NOT EXISTS TechnologyType ( label TEXT @@ -404,112 +442,56 @@ CREATE TABLE IF NOT EXISTS TechnologyType description TEXT ); REPLACE INTO TechnologyType -VALUES ('r', 'resource technology'); -REPLACE INTO TechnologyType VALUES ('p', 'production technology'); REPLACE INTO TechnologyType VALUES ('pb', 'baseload production technology'); REPLACE INTO TechnologyType VALUES ('ps', 'storage production technology'); -CREATE TABLE IF NOT EXISTS TimePeriod -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES TimePeriodType (label) -); -REPLACE INTO TimePeriod -VALUES (0, 2000, 'f'); -REPLACE INTO TimePeriod -VALUES (1, 2001, 'f'); CREATE TABLE IF NOT EXISTS TimeOfDay ( sequence INTEGER UNIQUE, tod TEXT PRIMARY KEY ); -REPLACE INTO TimeOfDay -VALUES (0, 'D1'); -REPLACE INTO TimeOfDay -VALUES (1, 'D2'); -CREATE TABLE IF NOT EXISTS TimeSeason +CREATE TABLE IF NOT EXISTS TimePeriod ( sequence INTEGER UNIQUE, - season TEXT - PRIMARY KEY + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES TimePeriodType (label) ); -REPLACE INTO TimeSeason -VALUES (0, 'S1'); -REPLACE INTO TimeSeason -VALUES (1, 'S2'); CREATE TABLE IF NOT EXISTS TimePeriodType ( label TEXT PRIMARY KEY, description TEXT ); -REPLACE INTO TimePeriodType VALUES ('e', 'existing'); -REPLACE INTO TimePeriodType VALUES ('f', 'future'); -CREATE TABLE IF NOT EXISTS OutputEmission +REPLACE INTO TimePeriodType +VALUES('e', 'existing vintages'); +REPLACE INTO TimePeriodType +VALUES('f', 'future'); +CREATE TABLE IF NOT EXISTS TimeSeason ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER + period INTEGER REFERENCES TimePeriod (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS Technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) + sequence INTEGER, + season TEXT, + notes TEXT, + PRIMARY KEY (period, sequence, season) ); -REPLACE INTO Technology -VALUES ('importer', 'r', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); -REPLACE INTO Technology -VALUES ('producer', 'p', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); -REPLACE INTO Technology -VALUES ('consumer', 'p', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); -CREATE TABLE OutputCost -( - scenario TEXT, - region TEXT REFERENCES Region (region), - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) +CREATE TABLE IF NOT EXISTS TimeSegmentFraction +( + period INTEGER + REFERENCES TimePeriod (period), + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + segfrac REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segfrac >= 0 AND segfrac <= 1) ); + COMMIT; -PRAGMA FOREIGN_KEYS = 1; +PRAGMA FOREIGN_KEYS = 1; \ No newline at end of file diff --git a/data_files/temoa_basics_2.sql b/data_files/temoa_basics_2.sql index 5b1a809e5..51cfc916d 100644 --- a/data_files/temoa_basics_2.sql +++ b/data_files/temoa_basics_2.sql @@ -11,35 +11,45 @@ CREATE TABLE IF NOT EXISTS MetaData REPLACE INTO MetaData VALUES ('DB_MAJOR', 3, 'DB major version number'); REPLACE INTO MetaData -VALUES ('DB_MINOR', 0, 'DB minor version number'); -CREATE TABLE IF NOT EXISTS OutputObjective +VALUES ('DB_MINOR', 1, 'DB minor version number'); +REPLACE INTO MetaData +VALUES ('days_per_period', 365, 'count of days in each period'); +CREATE TABLE IF NOT EXISTS MetaDataReal ( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) ); -CREATE TABLE IF NOT EXISTS CapacityToActivity +REPLACE INTO MetaDataReal +VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); +REPLACE INTO MetaDataReal +VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in LoanRate table'); + +CREATE TABLE IF NOT EXISTS CapacityFactorTech ( region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), tech TEXT REFERENCES Technology (tech), - c2a REAL, + factor REAL, notes TEXT, - PRIMARY KEY (region, tech) + PRIMARY KEY (region, period, season, tod, tech), + CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE IF NOT EXISTS CapacityFactorTech +CREATE TABLE IF NOT EXISTS CapacityToActivity ( region TEXT, - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), tech TEXT REFERENCES Technology (tech), - factor REAL, + c2a REAL, notes TEXT, - PRIMARY KEY (region, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) + PRIMARY KEY (region, tech) ); CREATE TABLE IF NOT EXISTS Commodity ( @@ -49,14 +59,6 @@ CREATE TABLE IF NOT EXISTS Commodity REFERENCES CommodityType (label), description TEXT ); -REPLACE INTO Commodity -VALUES ('ethos', 's', NULL); -REPLACE INTO Commodity -VALUES ('fuel', 'p', NULL); -REPLACE INTO Commodity -VALUES ('carrier', 'p', NULL); -REPLACE INTO Commodity -VALUES ('demand', 'd', NULL); CREATE TABLE IF NOT EXISTS CommodityType ( label TEXT @@ -64,15 +66,18 @@ CREATE TABLE IF NOT EXISTS CommodityType description TEXT ); REPLACE INTO CommodityType +VALUES ('s', 'source commodity'); +REPLACE INTO CommodityType +VALUES ('a', 'annual commodity'); +REPLACE INTO CommodityType VALUES ('p', 'physical commodity'); REPLACE INTO CommodityType VALUES ('d', 'demand commodity'); REPLACE INTO CommodityType -VALUES ('s', 'source commodity'); +VALUES ('e', 'emissions commodity'); CREATE TABLE IF NOT EXISTS CostEmission ( - region TEXT - REFERENCES Region (region), + region TEXT, period INTEGER REFERENCES TimePeriod (period), emis_comm TEXT NOT NULL @@ -134,32 +139,21 @@ CREATE TABLE IF NOT EXISTS Demand notes TEXT, PRIMARY KEY (region, period, commodity) ); -REPLACE INTO Demand -VALUES ('region', 2000, 'demand', 1, NULL, NULL); CREATE TABLE IF NOT EXISTS DemandSpecificDistribution ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT REFERENCES Commodity (name), dsd REAL, - dsd_notes TEXT, + notes TEXT, PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -REPLACE INTO DemandSpecificDistribution -VALUES ('region', 2000, 'S1', 'D1', 'demand', 0.25, NULL); -REPLACE INTO DemandSpecificDistribution -VALUES ('region', 2000, 'S1', 'D2', 'demand', 0.25, NULL); -REPLACE INTO DemandSpecificDistribution -VALUES ('region', 2000, 'S2', 'D1', 'demand', 0.25, NULL); -REPLACE INTO DemandSpecificDistribution -VALUES ('region', 2000, 'S2', 'D2', 'demand', 0.25, NULL); CREATE TABLE IF NOT EXISTS Efficiency ( region TEXT, @@ -176,12 +170,6 @@ CREATE TABLE IF NOT EXISTS Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -REPLACE INTO Efficiency -VALUES ('region', 'ethos', 'importer', 2000, 'fuel', 1, NULL); -REPLACE INTO Efficiency -VALUES ('region', 'fuel', 'producer', 2000, 'carrier', 1, NULL); -REPLACE INTO Efficiency -VALUES ('region', 'carrier', 'consumer', 2000, 'demand', 1, NULL); CREATE TABLE IF NOT EXISTS EmissionActivity ( region TEXT, @@ -200,18 +188,6 @@ CREATE TABLE IF NOT EXISTS EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -CREATE TABLE IF NOT EXISTS EmissionLimit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); CREATE TABLE IF NOT EXISTS ExistingCapacity ( region TEXT, @@ -224,35 +200,18 @@ CREATE TABLE IF NOT EXISTS ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE IF NOT EXISTS GrowthRateMax -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS GrowthRateSeed -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - seed REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS LifetimeTech +CREATE TABLE IF NOT EXISTS LifetimeProcess ( region TEXT, tech TEXT REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), lifetime REAL, notes TEXT, - PRIMARY KEY (region, tech) + PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE IF NOT EXISTS LoanLifetimeTech +CREATE TABLE IF NOT EXISTS LifetimeTech ( region TEXT, tech TEXT @@ -261,124 +220,183 @@ CREATE TABLE IF NOT EXISTS LoanLifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE IF NOT EXISTS LoanRate +CREATE TABLE IF NOT EXISTS LimitActivity ( region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER + period INTEGER REFERENCES TimePeriod (period), - rate REAL, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, + units TEXT, notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE IF NOT EXISTS MaxResource +CREATE TABLE IF NOT EXISTS LimitActivityShare ( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - max_res REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE IF NOT EXISTS MinActivity +CREATE TABLE IF NOT EXISTS LimitAnnualCapacityFactor ( - region TEXT, - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + tech TEXT REFERENCES Technology (tech), - min_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, operator), + CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE IF NOT EXISTS MaxActivity +CREATE TABLE IF NOT EXISTS LimitCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_act REAL, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE IF NOT EXISTS MinCapacity +CREATE TABLE IF NOT EXISTS LimitCapacityShare ( - region TEXT, - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitDegrowthCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE IF NOT EXISTS LimitGrowthCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE IF NOT EXISTS MaxCapacity +CREATE TABLE IF NOT EXISTS LimitNewCapacity ( region TEXT, period INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_cap REAL, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech) + PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE IF NOT EXISTS MinCapacityGroup +CREATE TABLE IF NOT EXISTS LimitNewCapacityShare ( - region TEXT, - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE IF NOT EXISTS MaxCapacityGroup +CREATE TABLE IF NOT EXISTS LimitResource ( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE IF NOT EXISTS MinNewCapacity +CREATE TABLE IF NOT EXISTS LimitSeasonalCapacityFactor ( - region TEXT, - period INTEGER + region TEXT + REFERENCES Region (region), + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + season TEXT, + tech TEXT REFERENCES Technology (tech), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE IF NOT EXISTS MaxNewCapacity +CREATE TABLE IF NOT EXISTS LimitStorageLevelFraction ( - region TEXT, - period INTEGER + region TEXT, + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) + vintage INTEGER + REFERENCES TimePeriod (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE IF NOT EXISTS MinTechInputSplit +CREATE TABLE IF NOT EXISTS LimitTechInputSplit ( region TEXT, period INTEGER @@ -387,11 +405,13 @@ CREATE TABLE IF NOT EXISTS MinTechInputSplit REFERENCES Commodity (name), tech TEXT REFERENCES Technology (tech), - min_proportion REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) + PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE IF NOT EXISTS MaxTechInputSplit +CREATE TABLE IF NOT EXISTS LimitTechInputSplitAnnual ( region TEXT, period INTEGER @@ -400,11 +420,13 @@ CREATE TABLE IF NOT EXISTS MaxTechInputSplit REFERENCES Commodity (name), tech TEXT REFERENCES Technology (tech), - max_proportion REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) + PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE IF NOT EXISTS MinTechOutputSplit +CREATE TABLE IF NOT EXISTS LimitTechOutputSplit ( region TEXT, period INTEGER @@ -413,11 +435,13 @@ CREATE TABLE IF NOT EXISTS MinTechOutputSplit REFERENCES Technology (tech), output_comm TEXT REFERENCES Commodity (name), - min_proportion REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) + PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE IF NOT EXISTS MaxTechOutputSplit +CREATE TABLE IF NOT EXISTS LimitTechOutputSplitAnnual ( region TEXT, period INTEGER @@ -426,9 +450,52 @@ CREATE TABLE IF NOT EXISTS MaxTechOutputSplit REFERENCES Technology (tech), output_comm TEXT REFERENCES Commodity (name), - max_proportion REAL, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE IF NOT EXISTS Operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +REPLACE INTO Operator VALUES('e','equal to'); +REPLACE INTO Operator VALUES('le','less than or equal to'); +REPLACE INTO Operator VALUES('ge','greater than or equal to'); +CREATE TABLE IF NOT EXISTS OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE OutputCost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES TimePeriod (period), + FOREIGN KEY (tech) REFERENCES Technology (tech) ); CREATE TABLE IF NOT EXISTS OutputCurtailment ( @@ -452,48 +519,29 @@ CREATE TABLE IF NOT EXISTS OutputCurtailment curtailment REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE IF NOT EXISTS OutputNetCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputBuiltCapacity +CREATE TABLE IF NOT EXISTS OutputDualVariable ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) ); -CREATE TABLE IF NOT EXISTS OutputRetiredCapacity +CREATE TABLE IF NOT EXISTS OutputEmission ( - scenario TEXT, - region TEXT, - sector TEXT + scenario TEXT, + region TEXT, + sector TEXT REFERENCES SectorLabel (sector), - period INTEGER + period INTEGER REFERENCES TimePeriod (period), - tech TEXT + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT REFERENCES Technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); CREATE TABLE IF NOT EXISTS OutputFlowIn ( @@ -503,8 +551,7 @@ CREATE TABLE IF NOT EXISTS OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -526,8 +573,7 @@ CREATE TABLE IF NOT EXISTS OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), + season TEXT, tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -541,35 +587,67 @@ CREATE TABLE IF NOT EXISTS OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE IF NOT EXISTS OutputDualVariable +CREATE TABLE IF NOT EXISTS OutputNetCapacity ( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) ); -CREATE TABLE IF NOT EXISTS PeriodSeasons -( +CREATE TABLE IF NOT EXISTS OutputObjective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE IF NOT EXISTS OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - sequence INTEGER, - season TEXT - REFERENCES TimeSeason (season), - notes TEXT, - PRIMARY KEY (period, sequence) + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); -REPLACE INTO PeriodSeasons -VALUES (2000, 1, 'S1', NULL); -REPLACE INTO PeriodSeasons -VALUES (2000, 2, 'S2', NULL); CREATE TABLE IF NOT EXISTS Region ( region TEXT PRIMARY KEY, notes TEXT ); -REPLACE INTO Region -VALUES ('region', NULL); CREATE TABLE IF NOT EXISTS SectorLabel ( sector TEXT, @@ -583,40 +661,23 @@ CREATE TABLE IF NOT EXISTS StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE IF NOT EXISTS TimeSegmentFraction -( - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) -); -REPLACE INTO TimeSegmentFraction -VALUES (2000, 'S1', 'D1', 0.25, NULL); -REPLACE INTO TimeSegmentFraction -VALUES (2000, 'S1', 'D2', 0.25, NULL); -REPLACE INTO TimeSegmentFraction -VALUES (2000, 'S2', 'D1', 0.25, NULL); -REPLACE INTO TimeSegmentFraction -VALUES (2000, 'S2', 'D2', 0.25, NULL); -CREATE TABLE IF NOT EXISTS TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS TechGroupMember +CREATE TABLE IF NOT EXISTS Technology ( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES Technology (tech), - PRIMARY KEY (group_name, tech) + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); CREATE TABLE IF NOT EXISTS TechnologyType ( @@ -625,112 +686,56 @@ CREATE TABLE IF NOT EXISTS TechnologyType description TEXT ); REPLACE INTO TechnologyType -VALUES ('r', 'resource technology'); -REPLACE INTO TechnologyType VALUES ('p', 'production technology'); REPLACE INTO TechnologyType VALUES ('pb', 'baseload production technology'); REPLACE INTO TechnologyType VALUES ('ps', 'storage production technology'); -CREATE TABLE IF NOT EXISTS TimePeriod -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES TimePeriodType (label) -); -REPLACE INTO TimePeriod -VALUES (0, 2000, 'f'); -REPLACE INTO TimePeriod -VALUES (1, 2001, 'f'); CREATE TABLE IF NOT EXISTS TimeOfDay ( sequence INTEGER UNIQUE, tod TEXT PRIMARY KEY ); -REPLACE INTO TimeOfDay -VALUES (0, 'D1'); -REPLACE INTO TimeOfDay -VALUES (1, 'D2'); -CREATE TABLE IF NOT EXISTS TimeSeason +CREATE TABLE IF NOT EXISTS TimePeriod ( sequence INTEGER UNIQUE, - season TEXT - PRIMARY KEY + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES TimePeriodType (label) ); -REPLACE INTO TimeSeason -VALUES (0, 'S1'); -REPLACE INTO TimeSeason -VALUES (1, 'S2'); CREATE TABLE IF NOT EXISTS TimePeriodType ( label TEXT PRIMARY KEY, description TEXT ); -REPLACE INTO TimePeriodType VALUES ('e', 'existing'); -REPLACE INTO TimePeriodType VALUES ('f', 'future'); -CREATE TABLE IF NOT EXISTS OutputEmission +REPLACE INTO TimePeriodType +VALUES('e', 'existing vintages'); +REPLACE INTO TimePeriodType +VALUES('f', 'future'); +CREATE TABLE IF NOT EXISTS TimeSeason ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER + period INTEGER REFERENCES TimePeriod (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS Technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) + sequence INTEGER, + season TEXT, + notes TEXT, + PRIMARY KEY (period, sequence, season) ); -REPLACE INTO Technology -VALUES ('importer', 'r', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); -REPLACE INTO Technology -VALUES ('producer', 'p', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); -REPLACE INTO Technology -VALUES ('consumer', 'p', 'sector', NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, NULL); -CREATE TABLE OutputCost -( - scenario TEXT, - region TEXT REFERENCES Region (region), - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) +CREATE TABLE IF NOT EXISTS TimeSegmentFraction +( + period INTEGER + REFERENCES TimePeriod (period), + season TEXT, + tod TEXT + REFERENCES TimeOfDay (tod), + segfrac REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segfrac >= 0 AND segfrac <= 1) ); + COMMIT; -PRAGMA FOREIGN_KEYS = 1; +PRAGMA FOREIGN_KEYS = 1; \ No newline at end of file diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index 74c334448..c19c1f2e7 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -115,15 +115,15 @@ CREATE TABLE IF NOT EXISTS CommodityType description TEXT ); REPLACE INTO CommodityType -VALUES ('p', 'physical commodity'); +VALUES ('s', 'source commodity'); REPLACE INTO CommodityType VALUES ('a', 'annual commodity'); REPLACE INTO CommodityType -VALUES ('e', 'emissions commodity'); +VALUES ('p', 'physical commodity'); REPLACE INTO CommodityType VALUES ('d', 'demand commodity'); REPLACE INTO CommodityType -VALUES ('s', 'source commodity'); +VALUES ('e', 'emissions commodity'); REPLACE INTO CommodityType VALUES ('w', 'waste commodity'); REPLACE INTO CommodityType From 3b598a2231cf278497f4e163833b60acaf1f88dd Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 19 Jun 2025 16:51:42 -0400 Subject: [PATCH 145/587] Fix small bug in basics schemas --- data_files/temoa_basics_0.sql | 2 +- data_files/temoa_basics_1.sql | 2 +- data_files/temoa_basics_2.sql | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/data_files/temoa_basics_0.sql b/data_files/temoa_basics_0.sql index 40591a1dc..e1fa6667e 100644 --- a/data_files/temoa_basics_0.sql +++ b/data_files/temoa_basics_0.sql @@ -146,7 +146,7 @@ CREATE TABLE IF NOT EXISTS OutputBuiltCapacity capacity REAL, PRIMARY KEY (region, scenario, tech, vintage) ); -CREATE TABLE OutputCost +CREATE TABLE IF NOT EXISTS OutputCost ( scenario TEXT, region TEXT, diff --git a/data_files/temoa_basics_1.sql b/data_files/temoa_basics_1.sql index d0a9c779e..ff92afff6 100644 --- a/data_files/temoa_basics_1.sql +++ b/data_files/temoa_basics_1.sql @@ -233,7 +233,7 @@ CREATE TABLE IF NOT EXISTS OutputBuiltCapacity capacity REAL, PRIMARY KEY (region, scenario, tech, vintage) ); -CREATE TABLE OutputCost +CREATE TABLE IF NOT EXISTS OutputCost ( scenario TEXT, region TEXT, diff --git a/data_files/temoa_basics_2.sql b/data_files/temoa_basics_2.sql index 51cfc916d..147c5c1d0 100644 --- a/data_files/temoa_basics_2.sql +++ b/data_files/temoa_basics_2.sql @@ -477,7 +477,7 @@ CREATE TABLE IF NOT EXISTS OutputBuiltCapacity capacity REAL, PRIMARY KEY (region, scenario, tech, vintage) ); -CREATE TABLE OutputCost +CREATE TABLE IF NOT EXISTS OutputCost ( scenario TEXT, region TEXT, From 505a97479aff4daa079695fbe628a2762633dea2 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 19 Jun 2025 17:03:52 -0400 Subject: [PATCH 146/587] Fix same bug in v3.1 schema sigh --- data_files/temoa_schema_v3_1.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index c19c1f2e7..2cfb7c8a8 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -861,7 +861,7 @@ CREATE TABLE IF NOT EXISTS StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE LifetimeSurvivalCurve +CREATE TABLE IF NOT EXISTS LifetimeSurvivalCurve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -997,7 +997,7 @@ CREATE TABLE IF NOT EXISTS Technology description TEXT, FOREIGN KEY (flag) REFERENCES TechnologyType (label) ); -CREATE TABLE OutputCost +CREATE TABLE IF NOT EXISTS OutputCost ( scenario TEXT, region TEXT, From a3dff5c6282a876a845f6ee0d2ebbf5c612a1fc5 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 20 Jun 2025 12:38:43 -0400 Subject: [PATCH 147/587] Fix to LoanLifetimeProcess in hybrid_loader --- temoa/temoa_model/hybrid_loader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 99198f837..949dfd218 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -748,7 +748,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # LoanLifetimeProcess if self.table_exists("LoanLifetimeProcess"): raw = cur.execute('SELECT region, tech, vintage, lifetime FROM main.LoanLifetimeProcess').fetchall() - load_element(M.LoanLifetimeProcess, raw, self.viable_rtv, (0, 1)) + load_element(M.LoanLifetimeProcess, raw, self.viable_rtv, (0, 1, 2)) # LimitTechInputSplit if self.table_exists('LimitTechInputSplit'): From bbd2e7518e2fa0957acf2cefd7d433e7e7ecebd2 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 20 Jun 2025 12:58:58 -0400 Subject: [PATCH 148/587] Block redundant constraint formation in ramp constraints --- data_files/example_dbs/survival_curve.sql | 4 ++-- data_files/temoa_schema_v3_1.sql | 4 ++-- temoa/temoa_model/hybrid_loader.py | 12 ++---------- temoa/temoa_model/temoa_initialize.py | 21 ++++++++++++++------- temoa/temoa_model/temoa_model.py | 8 ++++---- temoa/temoa_model/temoa_rules.py | 16 ++++++---------- tests/testing_data/mediumville_sets.json | 20 ++++++++++---------- tests/testing_data/survival_curve.sql | 4 ++-- tests/testing_data/test_system_sets.json | 4 ++-- tests/testing_data/utopia_sets.json | 4 ++-- 10 files changed, 46 insertions(+), 51 deletions(-) diff --git a/data_files/example_dbs/survival_curve.sql b/data_files/example_dbs/survival_curve.sql index 6301485ed..897827572 100644 --- a/data_files/example_dbs/survival_curve.sql +++ b/data_files/example_dbs/survival_curve.sql @@ -882,7 +882,7 @@ CREATE TABLE PlanningReserveMargin REFERENCES Region (region), margin REAL ); -CREATE TABLE RampDown +CREATE TABLE RampDownHourly ( region TEXT, tech TEXT @@ -890,7 +890,7 @@ CREATE TABLE RampDown rate REAL, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUp +CREATE TABLE RampUpHourly ( region TEXT, tech TEXT diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index 2cfb7c8a8..339223d9c 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -819,7 +819,7 @@ CREATE TABLE IF NOT EXISTS PlanningReserveMargin REFERENCES Region (region), margin REAL ); -CREATE TABLE IF NOT EXISTS RampDown +CREATE TABLE IF NOT EXISTS RampDownHourly ( region TEXT, tech TEXT @@ -827,7 +827,7 @@ CREATE TABLE IF NOT EXISTS RampDown rate REAL, PRIMARY KEY (region, tech) ); -CREATE TABLE IF NOT EXISTS RampUp +CREATE TABLE IF NOT EXISTS RampUpHourly ( region TEXT, tech TEXT diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 949dfd218..e6ddd773c 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -508,16 +508,6 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N raw = cur.execute('SELECT tech FROM Technology WHERE reserve > 0').fetchall() load_element(M.tech_reserve, raw, self.viable_techs) - # tech_ramping - if self.table_exists('RampUpHourly'): - ramp_up_techs = cur.execute('SELECT tech FROM main.RampUpHourly').fetchall() - techs = {t[0] for t in ramp_up_techs} - load_element(M.tech_upramping, sorted((t,) for t in techs), self.viable_techs) # sort for deterministic behavior - if self.table_exists('RampDownHourly'): - ramp_dn_techs = cur.execute('SELECT tech FROM main.RampDownHourly').fetchall() - techs = {t[0] for t in ramp_dn_techs} - load_element(M.tech_downramping, sorted((t,) for t in techs), self.viable_techs) # sort for deterministic behavior - # tech_curtailment raw = cur.execute('SELECT tech FROM Technology WHERE curtail > 0').fetchall() load_element(M.tech_curtailment, raw, self.viable_techs) @@ -1051,11 +1041,13 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N if self.table_exists('RampUpHourly'): raw = cur.execute('SELECT region, tech, rate FROM main.RampUpHourly').fetchall() load_element(M.RampUpHourly, raw, self.viable_rt, (0, 1)) + load_element(M.tech_upramping, sorted((row[1],) for row in raw), self.viable_techs) # sort for deterministic behavior # RampDownHourly if self.table_exists('RampDownHourly'): raw = cur.execute('SELECT region, tech, rate FROM main.RampDownHourly').fetchall() load_element(M.RampDownHourly, raw, self.viable_rt, (0, 1)) + load_element(M.tech_downramping, sorted((row[1],) for row in raw), self.viable_techs) # sort for deterministic behavior # CapacityCredit if self.table_exists('CapacityCredit'): diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 884a22712..c99148e30 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1741,14 +1741,18 @@ def RampDownDayConstraintIndices(M: 'TemoaModel'): def RampUpSeasonConstraintIndices(M: 'TemoaModel'): if M.TimeSequencing.first() == 'sequential_days': - return {} # dont need this constraint + return Set.Skip # dont need this constraint + # s, s_next indexing ensures we dont build redundant constraints indices = set( - (r, p, s_seq, M.time_of_day.last(), t, v) + (r, p, s, s_next, t, v) for r, p, t in M.rampUpVintages for v in M.rampUpVintages[r, p, t] - for _p, s_seq, _ in M.ordered_season_sequential + for _p, s_seq, s in M.ordered_season_sequential if _p == p + for s_seq_next in (M.time_next_sequential[p, s_seq],) # next sequential season + for s_next in (M.sequential_to_season[p, s_seq_next],) # next sequential season's matching season + if s_next != M.time_next[p, s, M.time_of_day.last()][0] # to avoid redundancy on RampDay constraint ) return indices @@ -1756,14 +1760,17 @@ def RampUpSeasonConstraintIndices(M: 'TemoaModel'): def RampDownSeasonConstraintIndices(M: 'TemoaModel'): if M.TimeSequencing.first() == 'sequential_days': - return {} # dont need this constraint + return Set.Skip # dont need this constraint + # s, s_next indexing ensures we dont build redundant constraints indices = set( - (r, p, s_seq, M.time_of_day.last(), t, v) + (r, p, s, s_next, t, v) for r, p, t in M.rampDownVintages for v in M.rampDownVintages[r, p, t] - for _p, s_seq, _ in M.ordered_season_sequential - if _p == p + for _p, s_seq, s in M.ordered_season_sequential + for s_seq_next in (M.time_next_sequential[p, s_seq],) # next sequential season + for s_next in (M.sequential_to_season[p, s_seq_next],) # next sequential season's matching season + if s_next != M.time_next[p, s, M.time_of_day.last()][0] # to avoid redundancy on RampDay constraint ) return indices diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index ab4508fc1..d06ddabc1 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -712,10 +712,10 @@ def __init__(M, *args, **kwargs): M.RampDownDayConstraint_rpsdtv = Set(dimen=6, initialize=RampDownDayConstraintIndices) M.RampDownDayConstraint = Constraint(M.RampDownDayConstraint_rpsdtv, rule=RampDownDay_Constraint) - M.RampUpSeasonConstraint_rpsdtv = Set(dimen=6, initialize=RampUpSeasonConstraintIndices) - M.RampUpSeasonConstraint = Constraint(M.RampUpSeasonConstraint_rpsdtv, rule=RampUpSeason_Constraint) - M.RampDownSeasonConstraint_rpsdtv = Set(dimen=6, initialize=RampDownSeasonConstraintIndices) - M.RampDownSeasonConstraint = Constraint(M.RampDownSeasonConstraint_rpsdtv, rule=RampDownSeason_Constraint) + M.RampUpSeasonConstraint_rpsstv = Set(dimen=6, initialize=RampUpSeasonConstraintIndices) + M.RampUpSeasonConstraint = Constraint(M.RampUpSeasonConstraint_rpsstv, rule=RampUpSeason_Constraint) + M.RampDownSeasonConstraint_rpsstv = Set(dimen=6, initialize=RampDownSeasonConstraintIndices) + M.RampDownSeasonConstraint = Constraint(M.RampDownSeasonConstraint_rpsstv, rule=RampDownSeason_Constraint) M.ReserveMargin_rpsd = Set(dimen=4, initialize=ReserveMarginIndices) M.validate_ReserveMargin = BuildAction(rule=validate_ReserveMargin) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 515af4681..8af9c69ed 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1839,16 +1839,14 @@ def RampDownDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): return expr -def RampUpSeason_Constraint(M: 'TemoaModel', r, p, s_seq, d, t, v): +def RampUpSeason_Constraint(M: 'TemoaModel', r, p, s, s_next, t, v): r""" Constrains the ramp up rate of activity between time slices at the boundary of sequential seasons. """ - s = M.sequential_to_season[p, s_seq] - s_seq_next = M.time_next_sequential[p, s_seq] - s_next = M.sequential_to_season[p, s_seq_next] - _, d_next = M.time_next[p, s, d] + d = M.time_of_day.last() + d_next = M.time_of_day.first() # How many hours does this time slice represent hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 @@ -1887,16 +1885,14 @@ def RampUpSeason_Constraint(M: 'TemoaModel', r, p, s_seq, d, t, v): return expr -def RampDownSeason_Constraint(M: 'TemoaModel', r, p, s_seq, d, t, v): +def RampDownSeason_Constraint(M: 'TemoaModel', r, p, s, s_next, t, v): r""" Constrains the ramp down rate of activity between time slices at the boundary of sequential seasons. """ - s = M.sequential_to_season[p, s_seq] - s_seq_next = M.time_next_sequential[p, s_seq] - s_next = M.sequential_to_season[p, s_seq_next] - _, d_next = M.time_next[p, s, d] + d = M.time_of_day.last() + d_next = M.time_of_day.first() # How many hours does this time slice represent hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 030cf35c5..9742ba18d 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -3930,12 +3930,12 @@ 2025 ] ], - "RampDownSeasonConstraint_rpsdtv": [ + "RampDownSeasonConstraint_rpsstv": [ [ "A", 2025, "s1", - "d2", + "s2", "EH", 2025 ], @@ -3943,7 +3943,7 @@ "A", 2025, "s2", - "d2", + "s1", "EH", 2025 ], @@ -3951,7 +3951,7 @@ "B", 2025, "s1", - "d2", + "s2", "EH", 2025 ], @@ -3959,7 +3959,7 @@ "B", 2025, "s2", - "d2", + "s1", "EH", 2025 ] @@ -4030,12 +4030,12 @@ 2025 ] ], - "RampUpSeasonConstraint_rpsdtv": [ + "RampUpSeasonConstraint_rpsstv": [ [ "A", 2025, "s1", - "d2", + "s2", "EH", 2025 ], @@ -4043,7 +4043,7 @@ "A", 2025, "s2", - "d2", + "s1", "EH", 2025 ], @@ -4051,7 +4051,7 @@ "B", 2025, "s1", - "d2", + "s2", "EH", 2025 ], @@ -4059,7 +4059,7 @@ "B", 2025, "s2", - "d2", + "s1", "EH", 2025 ] diff --git a/tests/testing_data/survival_curve.sql b/tests/testing_data/survival_curve.sql index 7a3fa2e2d..d9fea7b0a 100644 --- a/tests/testing_data/survival_curve.sql +++ b/tests/testing_data/survival_curve.sql @@ -882,7 +882,7 @@ CREATE TABLE PlanningReserveMargin REFERENCES Region (region), margin REAL ); -CREATE TABLE RampDown +CREATE TABLE RampDownHourly ( region TEXT, tech TEXT @@ -890,7 +890,7 @@ CREATE TABLE RampDown rate REAL, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUp +CREATE TABLE RampUpHourly ( region TEXT, tech TEXT diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index fa72f8f84..45b6714ab 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -44915,9 +44915,9 @@ ] ], "RampDownDayConstraint_rpsdtv": [], - "RampDownSeasonConstraint_rpsdtv": [], + "RampDownSeasonConstraint_rpsstv": [], "RampUpDayConstraint_rpsdtv": [], - "RampUpSeasonConstraint_rpsdtv": [], + "RampUpSeasonConstraint_rpsstv": [], "RegionalExchangeCapacityConstraint_rrptv": [ [ "R2", diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 2b870d5a3..9cefb9196 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -24714,9 +24714,9 @@ ] ], "RampDownDayConstraint_rpsdtv": [], - "RampDownSeasonConstraint_rpsdtv": [], + "RampDownSeasonConstraint_rpsstv": [], "RampUpDayConstraint_rpsdtv": [], - "RampUpSeasonConstraint_rpsdtv": [], + "RampUpSeasonConstraint_rpsstv": [], "RegionalExchangeCapacityConstraint_rrptv": [], "RenewablePortfolioStandardConstraint_rpg": [], "ReserveMargin_rpsd": [], From 8088367f9c1acf0f53c96236469aeefe0222eb5e Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 23 Jun 2025 11:26:39 -0400 Subject: [PATCH 149/587] Add SeasonLabel table for foreign key relation --- data_files/example_dbs/materials.sql | 45 ++++++++++++------ data_files/example_dbs/morris_utopia.sql | 46 ++++++++++++------ data_files/example_dbs/seasonal_storage.sql | 45 ++++++++++++------ data_files/example_dbs/stepped_demand.sql | 45 ++++++++++++------ data_files/example_dbs/survival_curve.sql | 45 ++++++++++++------ data_files/example_dbs/test_system.sql | 45 ++++++++++++------ data_files/example_dbs/utopia.sql | 45 ++++++++++++------ data_files/temoa_basics_0.sql | 13 ++++-- data_files/temoa_basics_1.sql | 30 ++++++++---- data_files/temoa_basics_2.sql | 36 +++++++++----- data_files/temoa_schema_v3_1.sql | 52 ++++++++++++++------- temoa/temoa_model/hybrid_loader.py | 10 ---- temoa/utilities/db_migration_v3_to_v3_1.py | 42 +++++++++++------ tests/testing_data/emissions.sql | 45 ++++++++++++------ tests/testing_data/materials.sql | 45 ++++++++++++------ tests/testing_data/mediumville.sql | 45 ++++++++++++------ tests/testing_data/seasonal_storage.sql | 45 ++++++++++++------ tests/testing_data/simple_linked_tech.sql | 45 ++++++++++++------ tests/testing_data/storageville.sql | 45 ++++++++++++------ tests/testing_data/survival_curve.sql | 45 ++++++++++++------ tests/testing_data/test_system.sql | 45 ++++++++++++------ tests/testing_data/utopia.sql | 45 ++++++++++++------ 22 files changed, 614 insertions(+), 290 deletions(-) diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index d7c1b5891..73adfddb9 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -33,10 +33,15 @@ CREATE TABLE OutputObjective objective_name TEXT, total_system_cost REAL ); +CREATE TABLE SeasonLabel +( + season TEXT PRIMARY KEY, + notes TEXT +); CREATE TABLE SectorLabel ( - sector TEXT, - PRIMARY KEY (sector) + sector TEXT PRIMARY KEY, + notes TEXT ); CREATE TABLE CapacityCredit ( @@ -56,7 +61,8 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -72,7 +78,8 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -407,7 +414,8 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -656,7 +664,8 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -877,7 +886,8 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1001,7 +1011,8 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -1224,7 +1235,8 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1246,7 +1258,8 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1268,7 +1281,8 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1313,7 +1327,8 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -1428,7 +1443,8 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -1450,7 +1466,8 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index e12b9ce58..b626a1f80 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -7,6 +7,7 @@ CREATE TABLE MetaData notes TEXT, PRIMARY KEY (element) ); +INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); @@ -33,10 +34,15 @@ CREATE TABLE OutputObjective objective_name TEXT, total_system_cost REAL ); +CREATE TABLE SeasonLabel +( + season TEXT PRIMARY KEY, + notes TEXT +); CREATE TABLE SectorLabel ( - sector TEXT, - PRIMARY KEY (sector) + sector TEXT PRIMARY KEY, + notes TEXT ); INSERT INTO SectorLabel VALUES('supply'); INSERT INTO SectorLabel VALUES('electric'); @@ -62,7 +68,8 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -96,7 +103,8 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -515,7 +523,8 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -655,7 +664,8 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -915,7 +925,8 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1050,7 +1061,8 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -1225,7 +1237,8 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1247,7 +1260,8 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1269,7 +1283,8 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1313,7 +1328,8 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -1396,7 +1412,8 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -1415,7 +1432,8 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql index 899d680f0..60fa804df 100644 --- a/data_files/example_dbs/seasonal_storage.sql +++ b/data_files/example_dbs/seasonal_storage.sql @@ -33,10 +33,15 @@ CREATE TABLE OutputObjective objective_name TEXT, total_system_cost REAL ); +CREATE TABLE SeasonLabel +( + season TEXT PRIMARY KEY, + notes TEXT +); CREATE TABLE SectorLabel ( - sector TEXT, - PRIMARY KEY (sector) + sector TEXT PRIMARY KEY, + notes TEXT ); INSERT INTO SectorLabel VALUES('electricity'); CREATE TABLE CapacityCredit @@ -57,7 +62,8 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -73,7 +79,8 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -219,7 +226,8 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -276,7 +284,8 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -481,7 +490,8 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -607,7 +617,8 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -776,7 +787,8 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -798,7 +810,8 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -820,7 +833,8 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -864,7 +878,8 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -936,7 +951,8 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -1034,7 +1050,8 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index 622b75ee0..85910ea8d 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -33,10 +33,15 @@ CREATE TABLE OutputObjective objective_name TEXT, total_system_cost REAL ); +CREATE TABLE SeasonLabel +( + season TEXT PRIMARY KEY, + notes TEXT +); CREATE TABLE SectorLabel ( - sector TEXT, - PRIMARY KEY (sector) + sector TEXT PRIMARY KEY, + notes TEXT ); INSERT INTO SectorLabel VALUES('supply'); INSERT INTO SectorLabel VALUES('electric'); @@ -62,7 +67,8 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -78,7 +84,8 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -350,7 +357,8 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -434,7 +442,8 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -653,7 +662,8 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -788,7 +798,8 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -957,7 +968,8 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -979,7 +991,8 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1001,7 +1014,8 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1045,7 +1059,8 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -1148,7 +1163,8 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -1191,7 +1207,8 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/data_files/example_dbs/survival_curve.sql b/data_files/example_dbs/survival_curve.sql index 897827572..b2935ddb9 100644 --- a/data_files/example_dbs/survival_curve.sql +++ b/data_files/example_dbs/survival_curve.sql @@ -33,10 +33,15 @@ CREATE TABLE OutputObjective objective_name TEXT, total_system_cost REAL ); +CREATE TABLE SeasonLabel +( + season TEXT PRIMARY KEY, + notes TEXT +); CREATE TABLE SectorLabel ( - sector TEXT, - PRIMARY KEY (sector) + sector TEXT PRIMARY KEY, + notes TEXT ); CREATE TABLE CapacityCredit ( @@ -56,7 +61,8 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -72,7 +78,8 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -262,7 +269,8 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -315,7 +323,8 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -528,7 +537,8 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -652,7 +662,8 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -821,7 +832,8 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -843,7 +855,8 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -865,7 +878,8 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -909,7 +923,8 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -1037,7 +1052,8 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -1053,7 +1069,8 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index 162d6517d..6a8242cb9 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -33,10 +33,15 @@ CREATE TABLE OutputObjective objective_name TEXT, total_system_cost REAL ); +CREATE TABLE SeasonLabel +( + season TEXT PRIMARY KEY, + notes TEXT +); CREATE TABLE SectorLabel ( - sector TEXT, - PRIMARY KEY (sector) + sector TEXT PRIMARY KEY, + notes TEXT ); INSERT INTO SectorLabel VALUES('supply'); INSERT INTO SectorLabel VALUES('electric'); @@ -62,7 +67,8 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -78,7 +84,8 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -463,7 +470,8 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -630,7 +638,8 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -879,7 +888,8 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1011,7 +1021,8 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -1210,7 +1221,8 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1232,7 +1244,8 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1254,7 +1267,8 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1299,7 +1313,8 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -1388,7 +1403,8 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -1410,7 +1426,8 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 0c148eee9..cc8346429 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -33,10 +33,15 @@ CREATE TABLE OutputObjective objective_name TEXT, total_system_cost REAL ); +CREATE TABLE SeasonLabel +( + season TEXT PRIMARY KEY, + notes TEXT +); CREATE TABLE SectorLabel ( - sector TEXT, - PRIMARY KEY (sector) + sector TEXT PRIMARY KEY, + notes TEXT ); INSERT INTO SectorLabel VALUES('supply'); INSERT INTO SectorLabel VALUES('electric'); @@ -62,7 +67,8 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -96,7 +102,8 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -511,7 +518,8 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -650,7 +658,8 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -910,7 +919,8 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1045,7 +1055,8 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -1220,7 +1231,8 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1242,7 +1254,8 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1264,7 +1277,8 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1308,7 +1322,8 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -1391,7 +1406,8 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -1410,7 +1426,8 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/data_files/temoa_basics_0.sql b/data_files/temoa_basics_0.sql index e1fa6667e..280e3e6a4 100644 --- a/data_files/temoa_basics_0.sql +++ b/data_files/temoa_basics_0.sql @@ -220,7 +220,8 @@ CREATE TABLE IF NOT EXISTS OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -242,7 +243,8 @@ CREATE TABLE IF NOT EXISTS OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -301,7 +303,8 @@ CREATE TABLE IF NOT EXISTS OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -319,8 +322,8 @@ CREATE TABLE IF NOT EXISTS Region ); CREATE TABLE IF NOT EXISTS SectorLabel ( - sector TEXT, - PRIMARY KEY (sector) + sector TEXT PRIMARY KEY, + notes TEXT ); CREATE TABLE IF NOT EXISTS Technology ( diff --git a/data_files/temoa_basics_1.sql b/data_files/temoa_basics_1.sql index ff92afff6..717c9ee18 100644 --- a/data_files/temoa_basics_1.sql +++ b/data_files/temoa_basics_1.sql @@ -32,7 +32,8 @@ CREATE TABLE IF NOT EXISTS CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -144,7 +145,8 @@ CREATE TABLE IF NOT EXISTS DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -307,7 +309,8 @@ CREATE TABLE IF NOT EXISTS OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -329,7 +332,8 @@ CREATE TABLE IF NOT EXISTS OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -388,7 +392,8 @@ CREATE TABLE IF NOT EXISTS OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -404,10 +409,15 @@ CREATE TABLE IF NOT EXISTS Region PRIMARY KEY, notes TEXT ); +CREATE TABLE IF NOT EXISTS SeasonLabel +( + season TEXT PRIMARY KEY, + notes TEXT +); CREATE TABLE IF NOT EXISTS SectorLabel ( - sector TEXT, - PRIMARY KEY (sector) + sector TEXT PRIMARY KEY, + notes TEXT ); CREATE TABLE IF NOT EXISTS StorageDuration ( @@ -476,7 +486,8 @@ CREATE TABLE IF NOT EXISTS TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -484,7 +495,8 @@ CREATE TABLE IF NOT EXISTS TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, diff --git a/data_files/temoa_basics_2.sql b/data_files/temoa_basics_2.sql index 147c5c1d0..3606512d7 100644 --- a/data_files/temoa_basics_2.sql +++ b/data_files/temoa_basics_2.sql @@ -32,7 +32,8 @@ CREATE TABLE IF NOT EXISTS CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -144,7 +145,8 @@ CREATE TABLE IF NOT EXISTS DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -369,7 +371,8 @@ CREATE TABLE IF NOT EXISTS LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -383,7 +386,8 @@ CREATE TABLE IF NOT EXISTS LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -551,7 +555,8 @@ CREATE TABLE IF NOT EXISTS OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -573,7 +578,8 @@ CREATE TABLE IF NOT EXISTS OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -632,7 +638,8 @@ CREATE TABLE IF NOT EXISTS OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -648,10 +655,15 @@ CREATE TABLE IF NOT EXISTS Region PRIMARY KEY, notes TEXT ); +CREATE TABLE IF NOT EXISTS SeasonLabel +( + season TEXT PRIMARY KEY, + notes TEXT +); CREATE TABLE IF NOT EXISTS SectorLabel ( - sector TEXT, - PRIMARY KEY (sector) + sector TEXT PRIMARY KEY, + notes TEXT ); CREATE TABLE IF NOT EXISTS StorageDuration ( @@ -720,7 +732,8 @@ CREATE TABLE IF NOT EXISTS TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -728,7 +741,8 @@ CREATE TABLE IF NOT EXISTS TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index 339223d9c..37e8fdd31 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -41,12 +41,16 @@ CREATE TABLE IF NOT EXISTS OutputObjective objective_name TEXT, total_system_cost REAL ); +CREATE TABLE IF NOT EXISTS SeasonLabel +( + season TEXT PRIMARY KEY, + notes TEXT +); CREATE TABLE IF NOT EXISTS SectorLabel ( - sector TEXT, - PRIMARY KEY (sector) + sector TEXT PRIMARY KEY, + notes TEXT ); - CREATE TABLE IF NOT EXISTS CapacityCredit ( region TEXT, @@ -65,7 +69,8 @@ CREATE TABLE IF NOT EXISTS CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -81,7 +86,8 @@ CREATE TABLE IF NOT EXISTS CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -213,7 +219,8 @@ CREATE TABLE IF NOT EXISTS DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -258,7 +265,8 @@ CREATE TABLE IF NOT EXISTS EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -465,7 +473,8 @@ CREATE TABLE IF NOT EXISTS LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -589,7 +598,8 @@ CREATE TABLE IF NOT EXISTS LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -758,7 +768,8 @@ CREATE TABLE IF NOT EXISTS OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -780,7 +791,8 @@ CREATE TABLE IF NOT EXISTS OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -802,7 +814,8 @@ CREATE TABLE IF NOT EXISTS OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -845,7 +858,8 @@ CREATE TABLE IF NOT EXISTS TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -889,10 +903,12 @@ VALUES ('ps', 'storage production technology'); -- ( -- period INTEGER -- REFERENCES TimePeriod (period), --- season TEXT, +-- season TEXT +-- REFERENCES SeasonLabel (season), -- tod TEXT -- REFERENCES TimeOfDay (tod), --- season_next TEXT, +-- season_next TEXT +-- REFERENCES SeasonLabel (season), -- tod_next TEXT -- REFERENCES TimeOfDay (tod), -- notes TEXT, @@ -917,7 +933,8 @@ CREATE TABLE IF NOT EXISTS TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -927,7 +944,8 @@ CREATE TABLE IF NOT EXISTS TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index e6ddd773c..a80637962 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -55,18 +55,13 @@ tables_with_regional_groups = { 'LimitAnnualCapacityFactor': 'region', 'LimitEmission': 'region', - 'LimitActivityGroup': 'region', 'LimitSeasonalCapacityFactor': 'region', 'LimitCapacity': 'region', 'LimitActivity': 'region', 'LimitNewCapacity': 'region', - 'LimitNewCapacityGroup': 'region', - 'LimitCapacityGroup': 'region', 'LimitActivityShare': 'region', 'LimitCapacityShare': 'region', 'LimitNewCapacityShare': 'region', - 'LimitNewCapacityGroupShare': 'region', - 'LimitActivityGroupShare': 'region', 'LimitResource': 'region', 'LimitGrowthCapacity': 'region', 'LimitDegrowthCapacity': 'region', @@ -1124,17 +1119,12 @@ def load_param_idx_sets(self, data: dict) -> dict: M.LimitEmission.name: M.LimitEmissionConstraint_rpe.name, M.LimitActivity.name: M.LimitActivityConstraint_rpt.name, M.LimitSeasonalCapacityFactor.name: M.LimitSeasonalCapacityFactorConstraint_rpst.name, - # M.LimitActivityGroup.name: M.LimitActivityGroupConstraint_rpg.name, M.LimitActivityShare.name: M.LimitActivityShareConstraint_rpgg.name, M.LimitAnnualCapacityFactor.name: M.LimitAnnualCapacityFactorConstraint_rpto.name, M.LimitCapacity.name: M.LimitCapacityConstraint_rpt.name, - # M.LimitCapacityGroup.name: M.LimitCapacityGroupConstraint_rpg.name, M.LimitCapacityShare.name: M.LimitCapacityShareConstraint_rpgg.name, M.LimitNewCapacity.name: M.LimitNewCapacityConstraint_rpt.name, - # M.LimitNewCapacityGroup.name: M.LimitNewCapacityGroupConstraint_rpg.name, M.LimitNewCapacityShare.name: M.LimitNewCapacityShareConstraint_rpgg.name, - # M.LimitNewCapacityGroupShare.name: M.LimitNewCapacityGroupShareConstraint_rpgg.name, - # M.LimitActivityGroupShare.name: M.LimitActivityGroupShareConstraint_rpgg.name, M.LimitResource.name: M.LimitResourceConstraint_rt.name, M.LimitStorageFraction.name: M.LimitStorageFractionConstraint_rpsdtv.name, M.RenewablePortfolioStandard.name: M.RenewablePortfolioStandardConstraint_rpg.name, diff --git a/temoa/utilities/db_migration_v3_to_v3_1.py b/temoa/utilities/db_migration_v3_to_v3_1.py index 60f551d97..78eb628ba 100644 --- a/temoa/utilities/db_migration_v3_to_v3_1.py +++ b/temoa/utilities/db_migration_v3_to_v3_1.py @@ -25,12 +25,18 @@ Transition a v3.0 database to a v3.1 database. """ +import os +import sys import argparse import sqlite3 -import sys -from temoa.temoa_model.temoa_model import TemoaModel from pathlib import Path +# Just to get the default lifetime... +this_dir = os.path.dirname(__file__) +root_dir = os.path.abspath(os.path.join(this_dir, '../..')) +sys.path.append(root_dir) +from temoa.temoa_model.temoa_model import TemoaModel + parser = argparse.ArgumentParser() parser.add_argument( '--source', @@ -77,7 +83,7 @@ def column_check(old_name: str, new_name: str) -> bool: new_columns = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] old_columns = [c[1] for c in con_old.execute(f'PRAGMA table_info({old_name});').fetchall()] - missing = [c for c in new_columns if c not in old_columns and c != 'period'] + missing = [c for c in new_columns if c not in old_columns and c not in ('period','notes')] if len(missing) > 0: msg = ( f'Columns of {new_name} in the new database missing from {old_name} in old database. Try adding or renaming the column in the old database:' @@ -109,8 +115,8 @@ def column_check(old_name: str, new_name: str) -> bool: ('', 'MetaData'), ('', 'MetaDataReal'), ('', 'PlanningReserveMargin'), - ('', 'RampDown'), - ('', 'RampUp'), + ('RampDown', 'RampDownHourly'), + ('RampUp', 'RampUpHourly'), ('', 'Region'), ('', 'RPSRequirement'), ('', 'SectorLabel'), @@ -220,8 +226,10 @@ def column_check(old_name: str, new_name: str) -> bool: print('TABLE NOT FOUND: ' + old_name) continue + old_columns = [c[1] for c in con_old.execute(f'PRAGMA table_info({old_name});').fetchall()] new_columns = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] - data = con_old.execute(f'SELECT {str(new_columns)[1:-1].replace("'","")} FROM {old_name}').fetchall() + cols = [c for c in new_columns if c in old_columns] + data = con_old.execute(f'SELECT {str(cols)[1:-1].replace("'","")} FROM {old_name}').fetchall() if not data: print('No data for: ' + old_name) @@ -230,7 +238,11 @@ def column_check(old_name: str, new_name: str) -> bool: # construct the query with correct number of placeholders num_placeholders = len(data[0]) placeholders = ','.join(['?' for _ in range(num_placeholders)]) - query = f'INSERT OR REPLACE INTO {new_name} VALUES ({placeholders})' + query = ( + 'INSERT OR REPLACE INTO ' + f'{new_name}{tuple(c for c in cols) if len(cols)>1 else f'({cols[0]})'} ' + f'VALUES ({placeholders})' + ) con_new.executemany(query, data) print(f'Transfered {len(data)} rows from {old_name} to {new_name}') @@ -292,6 +304,10 @@ def column_check(old_name: str, new_name: str) -> bool: print(f'Transfered {len(data)} rows from {old_name} to {new_name}') +# TimeSeason unique seasons to SeasonLabel +con_new.execute("INSERT OR REPLACE INTO SeasonLabel(season) SELECT DISTINCT season FROM TimeSeason") + + # Removal of tech_resource con_new.execute("UPDATE Technology SET flag='p' WHERE flag=='r';") print('Converted all resource techs to production techs.') @@ -322,19 +338,17 @@ def column_check(old_name: str, new_name: str) -> bool: print(f'{old_name} to {new_name}') -# state_sequencing parameter print('\n --- Updating MetaData ---') -cur.execute( - """REPLACE INTO - MetaData(element, value, notes) - VALUES('state_sequencing', 0, '0 = loop periods, 1 = loop seasons')""" +cur.execute("DELETE FROM MetaData WHERE element == 'myopic_base_year'") +print( + "myopic_base_year removed from MetaData. This parameter is no longer used. " \ + "Costs will discount to the first future period." ) -print("Added state_sequencing parameter") -# new database version cur.execute("UPDATE MetaData SET value = 1 WHERE element == 'DB_MINOR'") print("Updated database version to 3.1") + print('\n --- Validating foreign keys ---') con_new.commit() con_new.execute('VACUUM;') diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 1719a6bd6..29a1ec6fc 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -33,10 +33,15 @@ CREATE TABLE OutputObjective objective_name TEXT, total_system_cost REAL ); +CREATE TABLE SeasonLabel +( + season TEXT PRIMARY KEY, + notes TEXT +); CREATE TABLE SectorLabel ( - sector TEXT, - PRIMARY KEY (sector) + sector TEXT PRIMARY KEY, + notes TEXT ); CREATE TABLE CapacityCredit ( @@ -56,7 +61,8 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -72,7 +78,8 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -227,7 +234,8 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -281,7 +289,8 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -496,7 +505,8 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -628,7 +638,8 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -797,7 +808,8 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -819,7 +831,8 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -841,7 +854,8 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -885,7 +899,8 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -951,7 +966,8 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -963,7 +979,8 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index d7c1b5891..73adfddb9 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -33,10 +33,15 @@ CREATE TABLE OutputObjective objective_name TEXT, total_system_cost REAL ); +CREATE TABLE SeasonLabel +( + season TEXT PRIMARY KEY, + notes TEXT +); CREATE TABLE SectorLabel ( - sector TEXT, - PRIMARY KEY (sector) + sector TEXT PRIMARY KEY, + notes TEXT ); CREATE TABLE CapacityCredit ( @@ -56,7 +61,8 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -72,7 +78,8 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -407,7 +414,8 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -656,7 +664,8 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -877,7 +886,8 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1001,7 +1011,8 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -1224,7 +1235,8 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1246,7 +1258,8 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1268,7 +1281,8 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1313,7 +1327,8 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -1428,7 +1443,8 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -1450,7 +1466,8 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 96a071a90..bf3223098 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -33,10 +33,15 @@ CREATE TABLE OutputObjective objective_name TEXT, total_system_cost REAL ); +CREATE TABLE SeasonLabel +( + season TEXT PRIMARY KEY, + notes TEXT +); CREATE TABLE SectorLabel ( - sector TEXT, - PRIMARY KEY (sector) + sector TEXT PRIMARY KEY, + notes TEXT ); INSERT INTO SectorLabel VALUES('supply'); INSERT INTO SectorLabel VALUES('electric'); @@ -63,7 +68,8 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -81,7 +87,8 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -260,7 +267,8 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -339,7 +347,8 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -572,7 +581,8 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -710,7 +720,8 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -883,7 +894,8 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -905,7 +917,8 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -927,7 +940,8 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -977,7 +991,8 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -1043,7 +1058,8 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -1055,7 +1071,8 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index 899d680f0..60fa804df 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -33,10 +33,15 @@ CREATE TABLE OutputObjective objective_name TEXT, total_system_cost REAL ); +CREATE TABLE SeasonLabel +( + season TEXT PRIMARY KEY, + notes TEXT +); CREATE TABLE SectorLabel ( - sector TEXT, - PRIMARY KEY (sector) + sector TEXT PRIMARY KEY, + notes TEXT ); INSERT INTO SectorLabel VALUES('electricity'); CREATE TABLE CapacityCredit @@ -57,7 +62,8 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -73,7 +79,8 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -219,7 +226,8 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -276,7 +284,8 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -481,7 +490,8 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -607,7 +617,8 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -776,7 +787,8 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -798,7 +810,8 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -820,7 +833,8 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -864,7 +878,8 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -936,7 +951,8 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -1034,7 +1050,8 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index f2b462066..543bc3051 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -33,10 +33,15 @@ CREATE TABLE OutputObjective objective_name TEXT, total_system_cost REAL ); +CREATE TABLE SeasonLabel +( + season TEXT PRIMARY KEY, + notes TEXT +); CREATE TABLE SectorLabel ( - sector TEXT, - PRIMARY KEY (sector) + sector TEXT PRIMARY KEY, + notes TEXT ); INSERT INTO SectorLabel VALUES('supply'); INSERT INTO SectorLabel VALUES('electric'); @@ -62,7 +67,8 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -78,7 +84,8 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -215,7 +222,8 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -266,7 +274,8 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -476,7 +485,8 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -600,7 +610,8 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -770,7 +781,8 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -792,7 +804,8 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -814,7 +827,8 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -858,7 +872,8 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -920,7 +935,8 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -932,7 +948,8 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index 181be5d2c..e057bb8a3 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -33,10 +33,15 @@ CREATE TABLE OutputObjective objective_name TEXT, total_system_cost REAL ); +CREATE TABLE SeasonLabel +( + season TEXT PRIMARY KEY, + notes TEXT +); CREATE TABLE SectorLabel ( - sector TEXT, - PRIMARY KEY (sector) + sector TEXT PRIMARY KEY, + notes TEXT ); INSERT INTO SectorLabel VALUES('supply'); INSERT INTO SectorLabel VALUES('electric'); @@ -62,7 +67,8 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -78,7 +84,8 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -215,7 +222,8 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -274,7 +282,8 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -484,7 +493,8 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -613,7 +623,8 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -782,7 +793,8 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -804,7 +816,8 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -826,7 +839,8 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -870,7 +884,8 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -945,7 +960,8 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -957,7 +973,8 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/tests/testing_data/survival_curve.sql b/tests/testing_data/survival_curve.sql index d9fea7b0a..898718538 100644 --- a/tests/testing_data/survival_curve.sql +++ b/tests/testing_data/survival_curve.sql @@ -33,10 +33,15 @@ CREATE TABLE OutputObjective objective_name TEXT, total_system_cost REAL ); +CREATE TABLE SeasonLabel +( + season TEXT PRIMARY KEY, + notes TEXT +); CREATE TABLE SectorLabel ( - sector TEXT, - PRIMARY KEY (sector) + sector TEXT PRIMARY KEY, + notes TEXT ); CREATE TABLE CapacityCredit ( @@ -56,7 +61,8 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -72,7 +78,8 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -262,7 +269,8 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -315,7 +323,8 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -528,7 +537,8 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -652,7 +662,8 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -821,7 +832,8 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -843,7 +855,8 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -865,7 +878,8 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -909,7 +923,8 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -1037,7 +1052,8 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -1053,7 +1069,8 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 162d6517d..6a8242cb9 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -33,10 +33,15 @@ CREATE TABLE OutputObjective objective_name TEXT, total_system_cost REAL ); +CREATE TABLE SeasonLabel +( + season TEXT PRIMARY KEY, + notes TEXT +); CREATE TABLE SectorLabel ( - sector TEXT, - PRIMARY KEY (sector) + sector TEXT PRIMARY KEY, + notes TEXT ); INSERT INTO SectorLabel VALUES('supply'); INSERT INTO SectorLabel VALUES('electric'); @@ -62,7 +67,8 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -78,7 +84,8 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -463,7 +470,8 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -630,7 +638,8 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -879,7 +888,8 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1011,7 +1021,8 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -1210,7 +1221,8 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1232,7 +1244,8 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1254,7 +1267,8 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1299,7 +1313,8 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -1388,7 +1403,8 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -1410,7 +1426,8 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 0c148eee9..cc8346429 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -33,10 +33,15 @@ CREATE TABLE OutputObjective objective_name TEXT, total_system_cost REAL ); +CREATE TABLE SeasonLabel +( + season TEXT PRIMARY KEY, + notes TEXT +); CREATE TABLE SectorLabel ( - sector TEXT, - PRIMARY KEY (sector) + sector TEXT PRIMARY KEY, + notes TEXT ); INSERT INTO SectorLabel VALUES('supply'); INSERT INTO SectorLabel VALUES('electric'); @@ -62,7 +67,8 @@ CREATE TABLE CapacityFactorProcess region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -96,7 +102,8 @@ CREATE TABLE CapacityFactorTech region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -511,7 +518,8 @@ CREATE TABLE DemandSpecificDistribution region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT @@ -650,7 +658,8 @@ CREATE TABLE EfficiencyVariable region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -910,7 +919,8 @@ CREATE TABLE LimitStorageLevelFraction region TEXT, period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1045,7 +1055,8 @@ CREATE TABLE LimitSeasonalCapacityFactor REFERENCES Region (region), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tech TEXT REFERENCES Technology (tech), operator TEXT NOT NULL DEFAULT "le" @@ -1220,7 +1231,8 @@ CREATE TABLE OutputFlowIn REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1242,7 +1254,8 @@ CREATE TABLE OutputFlowOut REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT @@ -1264,7 +1277,8 @@ CREATE TABLE OutputStorageLevel REFERENCES SectorLabel (sector), period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT @@ -1308,7 +1322,8 @@ CREATE TABLE TimeSegmentFraction ( period INTEGER REFERENCES TimePeriod (period), - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), segfrac REAL, @@ -1391,7 +1406,8 @@ CREATE TABLE TimeSeason period INTEGER REFERENCES TimePeriod (period), sequence INTEGER, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); @@ -1410,7 +1426,8 @@ CREATE TABLE TimeSeasonSequential REFERENCES TimePeriod (period), sequence INTEGER, seas_seq TEXT, - season TEXT, + season TEXT + REFERENCES SeasonLabel (season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), From 6ee0c4625b4f4f6e46a50630c16861a2b589fa80 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 23 Jun 2025 11:36:47 -0400 Subject: [PATCH 150/587] Remember to add NULL to SectorLabel notes --- data_files/example_dbs/morris_utopia.sql | 12 ++++++------ data_files/example_dbs/seasonal_storage.sql | 2 +- data_files/example_dbs/stepped_demand.sql | 12 ++++++------ data_files/example_dbs/test_system.sql | 12 ++++++------ data_files/example_dbs/utopia.sql | 12 ++++++------ tests/testing_data/mediumville.sql | 12 ++++++------ tests/testing_data/seasonal_storage.sql | 2 +- tests/testing_data/simple_linked_tech.sql | 12 ++++++------ tests/testing_data/storageville.sql | 12 ++++++------ tests/testing_data/test_system.sql | 12 ++++++------ tests/testing_data/utopia.sql | 12 ++++++------ 11 files changed, 56 insertions(+), 56 deletions(-) diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index b626a1f80..ba013397e 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -44,12 +44,12 @@ CREATE TABLE SectorLabel sector TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO SectorLabel VALUES('supply'); -INSERT INTO SectorLabel VALUES('electric'); -INSERT INTO SectorLabel VALUES('transport'); -INSERT INTO SectorLabel VALUES('commercial'); -INSERT INTO SectorLabel VALUES('residential'); -INSERT INTO SectorLabel VALUES('industrial'); +INSERT INTO SectorLabel VALUES('supply',NULL); +INSERT INTO SectorLabel VALUES('electric',NULL); +INSERT INTO SectorLabel VALUES('transport',NULL); +INSERT INTO SectorLabel VALUES('commercial',NULL); +INSERT INTO SectorLabel VALUES('residential',NULL); +INSERT INTO SectorLabel VALUES('industrial',NULL); CREATE TABLE CapacityCredit ( region TEXT, diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql index 60fa804df..12f36c1f0 100644 --- a/data_files/example_dbs/seasonal_storage.sql +++ b/data_files/example_dbs/seasonal_storage.sql @@ -43,7 +43,7 @@ CREATE TABLE SectorLabel sector TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO SectorLabel VALUES('electricity'); +INSERT INTO SectorLabel VALUES('electricity',NULL); CREATE TABLE CapacityCredit ( region TEXT, diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index 85910ea8d..440c32691 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -43,12 +43,12 @@ CREATE TABLE SectorLabel sector TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO SectorLabel VALUES('supply'); -INSERT INTO SectorLabel VALUES('electric'); -INSERT INTO SectorLabel VALUES('transport'); -INSERT INTO SectorLabel VALUES('commercial'); -INSERT INTO SectorLabel VALUES('residential'); -INSERT INTO SectorLabel VALUES('industrial'); +INSERT INTO SectorLabel VALUES('supply',NULL); +INSERT INTO SectorLabel VALUES('electric',NULL); +INSERT INTO SectorLabel VALUES('transport',NULL); +INSERT INTO SectorLabel VALUES('commercial',NULL); +INSERT INTO SectorLabel VALUES('residential',NULL); +INSERT INTO SectorLabel VALUES('industrial',NULL); CREATE TABLE CapacityCredit ( region TEXT, diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index 6a8242cb9..656874af9 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -43,12 +43,12 @@ CREATE TABLE SectorLabel sector TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO SectorLabel VALUES('supply'); -INSERT INTO SectorLabel VALUES('electric'); -INSERT INTO SectorLabel VALUES('transport'); -INSERT INTO SectorLabel VALUES('commercial'); -INSERT INTO SectorLabel VALUES('residential'); -INSERT INTO SectorLabel VALUES('industrial'); +INSERT INTO SectorLabel VALUES('supply',NULL); +INSERT INTO SectorLabel VALUES('electric',NULL); +INSERT INTO SectorLabel VALUES('transport',NULL); +INSERT INTO SectorLabel VALUES('commercial',NULL); +INSERT INTO SectorLabel VALUES('residential',NULL); +INSERT INTO SectorLabel VALUES('industrial',NULL); CREATE TABLE CapacityCredit ( region TEXT, diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index cc8346429..2812dcff1 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -43,12 +43,12 @@ CREATE TABLE SectorLabel sector TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO SectorLabel VALUES('supply'); -INSERT INTO SectorLabel VALUES('electric'); -INSERT INTO SectorLabel VALUES('transport'); -INSERT INTO SectorLabel VALUES('commercial'); -INSERT INTO SectorLabel VALUES('residential'); -INSERT INTO SectorLabel VALUES('industrial'); +INSERT INTO SectorLabel VALUES('supply',NULL); +INSERT INTO SectorLabel VALUES('electric',NULL); +INSERT INTO SectorLabel VALUES('transport',NULL); +INSERT INTO SectorLabel VALUES('commercial',NULL); +INSERT INTO SectorLabel VALUES('residential',NULL); +INSERT INTO SectorLabel VALUES('industrial',NULL); CREATE TABLE CapacityCredit ( region TEXT, diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index bf3223098..566e804d9 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -43,12 +43,12 @@ CREATE TABLE SectorLabel sector TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO SectorLabel VALUES('supply'); -INSERT INTO SectorLabel VALUES('electric'); -INSERT INTO SectorLabel VALUES('transport'); -INSERT INTO SectorLabel VALUES('commercial'); -INSERT INTO SectorLabel VALUES('residential'); -INSERT INTO SectorLabel VALUES('industrial'); +INSERT INTO SectorLabel VALUES('supply',NULL); +INSERT INTO SectorLabel VALUES('electric',NULL); +INSERT INTO SectorLabel VALUES('transport',NULL); +INSERT INTO SectorLabel VALUES('commercial',NULL); +INSERT INTO SectorLabel VALUES('residential',NULL); +INSERT INTO SectorLabel VALUES('industrial',NULL); CREATE TABLE CapacityCredit ( region TEXT, diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index 60fa804df..12f36c1f0 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -43,7 +43,7 @@ CREATE TABLE SectorLabel sector TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO SectorLabel VALUES('electricity'); +INSERT INTO SectorLabel VALUES('electricity',NULL); CREATE TABLE CapacityCredit ( region TEXT, diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index 543bc3051..8732075c8 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -43,12 +43,12 @@ CREATE TABLE SectorLabel sector TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO SectorLabel VALUES('supply'); -INSERT INTO SectorLabel VALUES('electric'); -INSERT INTO SectorLabel VALUES('transport'); -INSERT INTO SectorLabel VALUES('commercial'); -INSERT INTO SectorLabel VALUES('residential'); -INSERT INTO SectorLabel VALUES('industrial'); +INSERT INTO SectorLabel VALUES('supply',NULL); +INSERT INTO SectorLabel VALUES('electric',NULL); +INSERT INTO SectorLabel VALUES('transport',NULL); +INSERT INTO SectorLabel VALUES('commercial',NULL); +INSERT INTO SectorLabel VALUES('residential',NULL); +INSERT INTO SectorLabel VALUES('industrial',NULL); CREATE TABLE CapacityCredit ( region TEXT, diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index e057bb8a3..4025757a7 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -43,12 +43,12 @@ CREATE TABLE SectorLabel sector TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO SectorLabel VALUES('supply'); -INSERT INTO SectorLabel VALUES('electric'); -INSERT INTO SectorLabel VALUES('transport'); -INSERT INTO SectorLabel VALUES('commercial'); -INSERT INTO SectorLabel VALUES('residential'); -INSERT INTO SectorLabel VALUES('industrial'); +INSERT INTO SectorLabel VALUES('supply',NULL); +INSERT INTO SectorLabel VALUES('electric',NULL); +INSERT INTO SectorLabel VALUES('transport',NULL); +INSERT INTO SectorLabel VALUES('commercial',NULL); +INSERT INTO SectorLabel VALUES('residential',NULL); +INSERT INTO SectorLabel VALUES('industrial',NULL); CREATE TABLE CapacityCredit ( region TEXT, diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 6a8242cb9..656874af9 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -43,12 +43,12 @@ CREATE TABLE SectorLabel sector TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO SectorLabel VALUES('supply'); -INSERT INTO SectorLabel VALUES('electric'); -INSERT INTO SectorLabel VALUES('transport'); -INSERT INTO SectorLabel VALUES('commercial'); -INSERT INTO SectorLabel VALUES('residential'); -INSERT INTO SectorLabel VALUES('industrial'); +INSERT INTO SectorLabel VALUES('supply',NULL); +INSERT INTO SectorLabel VALUES('electric',NULL); +INSERT INTO SectorLabel VALUES('transport',NULL); +INSERT INTO SectorLabel VALUES('commercial',NULL); +INSERT INTO SectorLabel VALUES('residential',NULL); +INSERT INTO SectorLabel VALUES('industrial',NULL); CREATE TABLE CapacityCredit ( region TEXT, diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index cc8346429..2812dcff1 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -43,12 +43,12 @@ CREATE TABLE SectorLabel sector TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO SectorLabel VALUES('supply'); -INSERT INTO SectorLabel VALUES('electric'); -INSERT INTO SectorLabel VALUES('transport'); -INSERT INTO SectorLabel VALUES('commercial'); -INSERT INTO SectorLabel VALUES('residential'); -INSERT INTO SectorLabel VALUES('industrial'); +INSERT INTO SectorLabel VALUES('supply',NULL); +INSERT INTO SectorLabel VALUES('electric',NULL); +INSERT INTO SectorLabel VALUES('transport',NULL); +INSERT INTO SectorLabel VALUES('commercial',NULL); +INSERT INTO SectorLabel VALUES('residential',NULL); +INSERT INTO SectorLabel VALUES('industrial',NULL); CREATE TABLE CapacityCredit ( region TEXT, From ec933255fb44eb5d5b0a4866b2bd12558f67eefc Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 23 Jun 2025 15:04:35 -0400 Subject: [PATCH 151/587] Change terminology in warning message on TimeSequential --- temoa/temoa_model/temoa_initialize.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index c99148e30..dfc74f68e 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1168,20 +1168,20 @@ def CreateTimeSeasonSequential(M: 'TemoaModel'): sequential = dict() for p, s_seq, s in M.TimeSeasonSequential: - count = value(M.TimeSeasonSequential[p, s_seq, s]) - if M.TimeSequencing.first() == 'sequential_days' and abs(count - 1.0) >= 0.01: + num_days = value(M.TimeSeasonSequential[p, s_seq, s]) + if M.TimeSequencing.first() == 'sequential_days' and abs(num_days - 1.0) >= 0.01: msg = ( 'TimeSequencing set to sequential_days but a season in the TimeSegmentFraction table does not ' - f'represent exactly one day. This would lead to bad model behaviour: {p, s}, days: {count}. ' + f'represent exactly one day. This would lead to bad model behaviour: {p, s}, days: {num_days}. ' 'Check the config file.' ) logger.error(msg) raise ValueError(msg) if (p, s) not in sequential: sequential[p, s] = 0 - sequential[p, s] += count + sequential[p, s] += num_days - # Check that TimeSeasonSequential day counts total to number of days in each period + # Check that TimeSeasonSequential num_days total to number of days in each period for p in M.time_optimize: count_total = sum( sequential[p, s] @@ -1190,7 +1190,7 @@ def CreateTimeSeasonSequential(M: 'TemoaModel'): ) if abs(count_total - value(M.DaysPerPeriod)) >= 0.001: logger.warning( - f'Sum of day count in TimeSeasonSequential ({sum(sequential.values())}) ' + f'Sum of num_days in TimeSeasonSequential ({sum(sequential.values())}) ' f'does not sum to days_per_period ({value(M.DaysPerPeriod)}) from the ' 'MetaData table.' ) From 53a409e78ddaf50e6ffe13bf683409f3e9013344 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 23 Jun 2025 15:49:33 -0400 Subject: [PATCH 152/587] Remember to add ReserveCapacityDerate to the databases --- data_files/example_dbs/materials.sql | 15 +++++++++++++++ data_files/example_dbs/morris_utopia.sql | 15 +++++++++++++++ data_files/example_dbs/seasonal_storage.sql | 15 +++++++++++++++ data_files/example_dbs/stepped_demand.sql | 15 +++++++++++++++ data_files/example_dbs/survival_curve.sql | 15 +++++++++++++++ data_files/example_dbs/test_system.sql | 15 +++++++++++++++ data_files/example_dbs/utopia.sql | 15 +++++++++++++++ data_files/temoa_schema_v3_1.sql | 15 +++++++++++++++ tests/testing_data/emissions.sql | 15 +++++++++++++++ tests/testing_data/materials.sql | 15 +++++++++++++++ tests/testing_data/mediumville.sql | 15 +++++++++++++++ tests/testing_data/seasonal_storage.sql | 15 +++++++++++++++ tests/testing_data/simple_linked_tech.sql | 15 +++++++++++++++ tests/testing_data/storageville.sql | 15 +++++++++++++++ tests/testing_data/survival_curve.sql | 15 +++++++++++++++ tests/testing_data/test_system.sql | 15 +++++++++++++++ tests/testing_data/utopia.sql | 15 +++++++++++++++ 17 files changed, 255 insertions(+) diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index 73adfddb9..cc53c7b55 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -1323,6 +1323,21 @@ CREATE TABLE Region ); INSERT INTO Region VALUES('RegionA',NULL); INSERT INTO Region VALUES('RegionB',NULL); +CREATE TABLE ReserveCapacityDerate +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); CREATE TABLE TimeSegmentFraction ( period INTEGER diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index ba013397e..918ad8255 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -1324,6 +1324,21 @@ CREATE TABLE Region notes TEXT ); INSERT INTO Region VALUES('utopia',NULL); +CREATE TABLE ReserveCapacityDerate +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); CREATE TABLE TimeSegmentFraction ( period INTEGER diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql index 12f36c1f0..c3f522121 100644 --- a/data_files/example_dbs/seasonal_storage.sql +++ b/data_files/example_dbs/seasonal_storage.sql @@ -874,6 +874,21 @@ CREATE TABLE Region notes TEXT ); INSERT INTO Region VALUES('region',NULL); +CREATE TABLE ReserveCapacityDerate +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); CREATE TABLE TimeSegmentFraction ( period INTEGER diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index 440c32691..6f17b146e 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -1055,6 +1055,21 @@ CREATE TABLE Region notes TEXT ); INSERT INTO Region VALUES('electricville',NULL); +CREATE TABLE ReserveCapacityDerate +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); CREATE TABLE TimeSegmentFraction ( period INTEGER diff --git a/data_files/example_dbs/survival_curve.sql b/data_files/example_dbs/survival_curve.sql index b2935ddb9..6213f0ddd 100644 --- a/data_files/example_dbs/survival_curve.sql +++ b/data_files/example_dbs/survival_curve.sql @@ -919,6 +919,21 @@ CREATE TABLE Region notes TEXT ); INSERT INTO Region VALUES('region',NULL); +CREATE TABLE ReserveCapacityDerate +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); CREATE TABLE TimeSegmentFraction ( period INTEGER diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index 656874af9..a82e2a244 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -1309,6 +1309,21 @@ CREATE TABLE Region ); INSERT INTO Region VALUES('R1',NULL); INSERT INTO Region VALUES('R2',NULL); +CREATE TABLE ReserveCapacityDerate +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); CREATE TABLE TimeSegmentFraction ( period INTEGER diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 2812dcff1..3771366f4 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -1318,6 +1318,21 @@ CREATE TABLE Region notes TEXT ); INSERT INTO Region VALUES('utopia',NULL); +CREATE TABLE ReserveCapacityDerate +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); CREATE TABLE TimeSegmentFraction ( period INTEGER diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index 37e8fdd31..11ca1e82d 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -854,6 +854,21 @@ CREATE TABLE IF NOT EXISTS Region PRIMARY KEY, notes TEXT ); +CREATE TABLE IF NOT EXISTS ReserveCapacityDerate +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); CREATE TABLE IF NOT EXISTS TimeSegmentFraction ( period INTEGER diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 29a1ec6fc..48f529152 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -895,6 +895,21 @@ CREATE TABLE Region notes TEXT ); INSERT INTO Region VALUES('TestRegion',NULL); +CREATE TABLE ReserveCapacityDerate +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); CREATE TABLE TimeSegmentFraction ( period INTEGER diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index 73adfddb9..cc53c7b55 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -1323,6 +1323,21 @@ CREATE TABLE Region ); INSERT INTO Region VALUES('RegionA',NULL); INSERT INTO Region VALUES('RegionB',NULL); +CREATE TABLE ReserveCapacityDerate +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); CREATE TABLE TimeSegmentFraction ( period INTEGER diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 566e804d9..9fc711e66 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -987,6 +987,21 @@ CREATE TABLE Region ); INSERT INTO Region VALUES('A','main region'); INSERT INTO Region VALUES('B','just a 2nd region'); +CREATE TABLE ReserveCapacityDerate +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); CREATE TABLE TimeSegmentFraction ( period INTEGER diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index 12f36c1f0..c3f522121 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -874,6 +874,21 @@ CREATE TABLE Region notes TEXT ); INSERT INTO Region VALUES('region',NULL); +CREATE TABLE ReserveCapacityDerate +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); CREATE TABLE TimeSegmentFraction ( period INTEGER diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index 8732075c8..8441da994 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -868,6 +868,21 @@ CREATE TABLE Region notes TEXT ); INSERT INTO Region VALUES('linkville',NULL); +CREATE TABLE ReserveCapacityDerate +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); CREATE TABLE TimeSegmentFraction ( period INTEGER diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index 4025757a7..1848c1f1d 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -880,6 +880,21 @@ CREATE TABLE Region notes TEXT ); INSERT INTO Region VALUES('electricville',NULL); +CREATE TABLE ReserveCapacityDerate +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); CREATE TABLE TimeSegmentFraction ( period INTEGER diff --git a/tests/testing_data/survival_curve.sql b/tests/testing_data/survival_curve.sql index 898718538..ef6dc9f88 100644 --- a/tests/testing_data/survival_curve.sql +++ b/tests/testing_data/survival_curve.sql @@ -919,6 +919,21 @@ CREATE TABLE Region notes TEXT ); INSERT INTO Region VALUES('region',NULL); +CREATE TABLE ReserveCapacityDerate +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); CREATE TABLE TimeSegmentFraction ( period INTEGER diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 656874af9..a82e2a244 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -1309,6 +1309,21 @@ CREATE TABLE Region ); INSERT INTO Region VALUES('R1',NULL); INSERT INTO Region VALUES('R2',NULL); +CREATE TABLE ReserveCapacityDerate +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); CREATE TABLE TimeSegmentFraction ( period INTEGER diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 2812dcff1..3771366f4 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -1318,6 +1318,21 @@ CREATE TABLE Region notes TEXT ); INSERT INTO Region VALUES('utopia',NULL); +CREATE TABLE ReserveCapacityDerate +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); CREATE TABLE TimeSegmentFraction ( period INTEGER From 7aac316c5edf4b6b96b4c7032442166035d61a13 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 23 Jun 2025 16:13:01 -0400 Subject: [PATCH 153/587] Make an attempt at updating the docs --- .gitignore | 5 +- docs/README.md | 6 +- docs/source/Documentation.rst | 119 +++++---- temoa/temoa_model/temoa_rules.py | 404 +++++++++++++++++++------------ 4 files changed, 321 insertions(+), 213 deletions(-) diff --git a/.gitignore b/.gitignore index 8d142742a..0f1c98b36 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,7 @@ other_notebooks/ /temoa/temoa_model/config_sample_9R # ignore cached vscode settings -.vscode \ No newline at end of file +.vscode + +# ignore built docs +docs/_build \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 3e05d2c3b..a164ab936 100644 --- a/docs/README.md +++ b/docs/README.md @@ -25,7 +25,11 @@ Sometimes this automatic PDF generation fails. If that is the case, navigate to ```$ pdflatex toolsforenergymodeloptimizationandanalysistemoa.pdf``` +## In Windows +With the Temoa virtual environment active (see README in root folder), navigate to this directory: +```cd C://temoa3/``` +Then build the documentation with Sphinx: - +```python -m sphinx source _build/html`` \ No newline at end of file diff --git a/docs/source/Documentation.rst b/docs/source/Documentation.rst index 1c144a34c..862323a34 100644 --- a/docs/source/Documentation.rst +++ b/docs/source/Documentation.rst @@ -313,6 +313,7 @@ recommend that you populate input tables in the following order: and sub-categorizing can be done in the Technology table itself. * TimePeriodType: Used to distinguish which time periods are simply used to specify pre-existing vintages and which represent future optimization periods. + * SeasonLabel: Unordered unique labels defining seasons in the model. **Group 2: sets used within Temoa** @@ -324,33 +325,32 @@ recommend that you populate input tables in the following order: **Group 3: parameters used to define processes within Temoa** - * GlobalDiscountRate + * MetaDataReal (global_discount_rate) + * MetaData (days_per_period) * Demand * DemandSpecificDistribution * Efficiency * ExistingCapacity * CapacityFactor * CapacityFactorProcess (only if CF varies by vintage; overwrites CapacityFactor) - * Capacity2Activity + * CapacityToActivity * CostFixed * CostInvest * CostVariable - * EmissionsActivity - * LoanLifetimeTech - * LifetimeProcess + * EmissionActivity * LifetimeTech + * LifetimeProcess (only if LT varies by vintage; overwrites LifetimeTech) + * TimeSegmentFraction: proportion of each period represented by each time slice **Group 4: parameters used to define constraints within Temoa** - * GrowthRateSeed - * GrowthRateMax - * MinCapacity - * MaxCapacity - * MinActivity - * MaxActivity - * RampUp - * RampDown - * TechOutputSplit - * TechInputSplit + * LimitActivity + * LimitCapacity + * LimitEmission + * LimitGrowthCapacity + * LimitNewCapacity + * LimitResource + * LimitTechInputSplit + * LimitTechOutputSplit For help getting started, take a look at how :code:`data_files/temoa_utopia.sql` is constructed. Use :code:`data_files/temoa_schema.sql` (a database file with the requisite @@ -645,10 +645,10 @@ Conventions Take, for example, this excerpt from the Temoa default objective function: .. math:: - C_{variable} = \sum_{p, s, d, i, t, v, o \in \Theta_{VC}} \left ( - {VC}_{p, t, v} + C_{variable} = \sum_{r, p, s, d, i, t, v, o \in \Theta_{VC}} \left ( + {VC}_{r, p, t, v} \cdot R_p - \cdot \textbf{FO}_{p, s, d, i, t, v, o} + \cdot \textbf{FO}_{r, p, s, d, i, t, v, o} \right ) Note that :math:`C_{variable}` is not bold, as it is a temporary variable @@ -678,7 +678,6 @@ Conventions \text{CFP}_{r, t, v} \cdot \text{C2A}_{r, t} \cdot \text{SEG}_{s, d} - \cdot \text{TLF}_{r, p, t, v} \right ) \cdot \textbf{CAP}_{r, t, v} = @@ -729,6 +728,8 @@ Sets ":math:`\text{C}^d`",":code:`commodity_demand`","string","end-use demand commodities" ":math:`\text{C}^e`",":code:`commodity_emissions`","string","emission commodities (e.g. :math:`\text{CO}_\text{2}` :math:`\text{NO}_\text{x}`)" ":math:`\text{C}^p`",":code:`commodity_physical`","string","general energy forms (e.g. electricity, coal, uranium, oil)" + ":math:`\text{C}^a`",":code:`commodity_annual`","string","same as commodity physical but flows are only balanced over each period" + ":math:`\text{C}^w`",":code:`commodity_waste`","string","physical or annual commodity for which production can be greater than consumption" ":math:`{}^*\text{C}^c`",":code:`commodity_carrier`","string","physical energy carriers and end-use demands (:math:`\text{C}_p \cup \text{C}_d`)" ":math:`\text{I}`",,"string","alias of :math:`\text{C}^p`; used in documentation only to mean ""input""" ":math:`\text{O}`",,"string","alias of :math:`\text{C}^c`; used in documentation only to mean ""output""" @@ -740,20 +741,22 @@ Sets ":math:`\text{S}`",":code:`time_season`","string","seasonal divisions (e.g. winter, summer)" ":math:`\text{D}`",":code:`time_of_day`","string","time-of-day divisions (e.g. morning)" ":math:`{}^*\text{T}`",":code:`tech_all`","string","all technologies to be modeled; (:math:`{T}^r \cup {T}^p`)" - ":math:`\text{T}^u`",":code:`tech_unlim_cap`","string","technologies that have no bound on capacity, and can have variable costs only (imports, taxes, etc.); (:math:`{T}^a \subset (T - T^{res}`)" + ":math:`\text{T}^u`",":code:`tech_unlim_cap`","string","technologies that have no bound on capacity, and can have variable costs only (imports, taxes, etc.); (:math:`{T}^u \subset (T - T^{res})`)" ":math:`\text{T}^a`",":code:`tech_annual`","string","technologies that produce constant annual output; (:math:`{T}^a \subset T`)" ":math:`\text{T}^b`",":code:`tech_baseload`","string","baseload electric generators; (:math:`{T}^b \subset T`)" ":math:`\text{T}^c`",":code:`tech_curtailment`","string","technologies with curtailable output and no upstream cost; (:math:`{T}^c \subset (T - T^{res})`)" - ":math:`\text{T}^e`",":code:`tech_exchange`","string","technologies used for interregional commodity flow; (:math:`{T}^e \subset T`). See Note 1 below on capacity and cost application for `tech_exchange`" + ":math:`\text{T}^x`",":code:`tech_exchange`","string","technologies used for interregional commodity flow; (:math:`{T}^x \subset T`). See Note 1 below on capacity and cost application for `tech_exchange`" + ":math:`\text{T}^e`",":code:`tech_existing`","string","technologies constructed in an existing (past) vintage; (:math:`{T}^e \subset T`)." ":math:`\text{T}^f`",":code:`tech_flex`","string","technologies producing excess commodity flows; (:math:`{T}^f \subset T`)" - "",":code:`TechGroupName`","string","named groups for use in group parameters or RegionalPortfolioStandard" - "",":code:`TechGroupMember`","(TechGroupName, tech)","technologies belonging to each group defined above" + "",":code:`TechGroupName`","string","named groups for use in group constraints" + "",":code:`TechGroupMember`","(TechGroupName, tech)","Each technology belonging to each group defined above" ":math:`\text{T}^p`",":code:`tech_production`","string","techs producing intermediate commodities" - ":math:`\text{T}^r`",":code:`tech_resource`","string","resource extraction technologies" - ":math:`\text{T}^m`",":code:`tech_ramping`","string","electric generators with a ramp rate limit; (:math:`{T}^m \subset T`)" - ":math:`\text{T}^{res}`",":code:`tech_reserve`","string","electric generators contributing to the reserve margin requirement; (:math:`{T}^e \subset T`)" - ":math:`\text{T}^s`",":code:`tech_storage`","string","storage technologies; (:math:`{T}^s \subset T`)" - ":math:`\text{T}^v`",":code:`tech_variable`","string","technologies used in TechInputSplitAverage constraint; (:math:`{T}^v \subset T`)" + ":math:`\text{T}^{ur}`",":code:`tech_upramping`","string","electric generators with a ramp up hourly rate limit; (:math:`{T}^{ur} \subset T`)" + ":math:`\text{T}^{dr}`",":code:`tech_downramping`","string","electric generators with a ramp down hourly rate limit; (:math:`{T}^{dr} \subset T`)" + ":math:`\text{T}^{res}`",":code:`tech_reserve`","string","electric generators contributing to the reserve margin requirement; (:math:`{T}^res \subset T`)" + ":math:`\text{T}^{ret}`",":code:`tech_retirement`","string","technologies allowed to retire before end of life; (:math:`{T}^{ret} \subset (T - T^{u})`)" + ":math:`\text{T}^s`",":code:`tech_storage`","string","all storage technologies; (:math:`{T}^s \subset T`)" + ":math:`\text{T}^{ss}`",":code:`tech_seasonal_storage`","string","seasonal storage technologies; (:math:`{T}^{ss} \subset T^s`)" Note 1: Temoa sets Capacity for Exchange Technologies to be equal in both directions on the link automatically. Costs are apportioned as follows: If both directions of the link have a cost parameter, costs are accrued to @@ -783,16 +786,17 @@ and demand is balanced at each of these levels: * **Periods** - consecutive blocks of years, marked by the first year in the period. For example, a two-period model might consist of :math:`\text{P}^f = - \{2010, 2015, 2025\}`, representing the two periods of years from 2010 - through 2014, and from 2015 through 2024. Note the that last period element - \(2025\) does not represent a new time period, but rather defines the upper bound - for the second time period. + \{2010, 2015, 2025\}`, representing the two periods of years from beginning 2010 + through 2014 end, and from beginning 2015 through 2024 end. Note the that last period element + \(2025\) does not represent a new time period, but rather defines the end of the second time + period and therefore the planning horizon. * **Seasonal** - Each year may have multiple seasons. In a conventional time-sliced model, the seasons may typically represent the four seasons: winter, spring summer, and fall. However, the seasonal slices can represent any amount of time at the sub-period scale. For example, in a database with representative days, the seasonal - slices can be used as generic containers to represent blocks of days. + slices can be used as generic containers to represent blocks of days. The type of + seasonal representation in use should be defined in the config file. * **Daily** - Within a season, a given day can be further subdivided into different time segments. Less detailed databases may include larger blocks of time, such as morning, @@ -905,7 +909,6 @@ the :code:`Capacity` :eq:`Capacity` Constraint: \text{CFP}_{r, s, d, t, v} \cdot \text{C2A}_{r, t} \cdot \text{SEG}_{s, d} - \cdot \text{TLF}_{r, p, t, v} \right ) \cdot \textbf{CAP}_{r, t, v} = @@ -950,13 +953,15 @@ Parameters ":math:`\text{EAC}_{r,i,t,v,o,e}`","EmissionActivity",":math:`\mathbb{R}`","Tech-specific emissions rate" ":math:`\text{ELM}_{r,p,e}`","EmissionLimit",":math:`\mathbb{R}^+_0`","Emissions limit by region and period" ":math:`\text{ECAP}_{r,t,v}`","ExistingCapacity",":math:`\mathbb{R}^+_0`","Pre-existing capacity" + ":math:`\text{RCAP}_{r,p,t,v}`","RetiredCapacity",":math:`\mathbb{R}^+_0`","Capacity retired before end of life" ":math:`\text{GDR}`","GlobalDiscountRate",":math:`\mathbb{R}`","Global rate used to calculate present cost" ":math:`\text{GRM}_{r,t}`","GrowthRateMax",":math:`\mathbb{R}`","Global rate used to calculate present cost" ":math:`\text{GRS}_{r,t}`","GrowthRateSeed",":math:`\mathbb{R}`","Global rate used to calculate present cost" ":math:`\text{LTP}_{r,t,v}`","LifetimeProcess",":math:`\mathbb{N}`","Tech- and vintage-specific lifetime (default=LifetimeTech)" - ":math:`\text{LTT}_{r,t}`","LifetimeTech",":math:`\mathbb{N}`","Tech-specific lifetime (default=40 periods)" + ":math:`\text{LTT}_{r,t}`","LifetimeTech",":math:`\mathbb{N}`","Tech-specific lifetime (default=40 years)" + ":math:`\text{LTS}_{r,p,t,v}`","LifetimeSurvivalCurve",":math:`\mathbb{R}^+_0`","Surviving fraction of original capacity" ":math:`\text{LIT}_{r,t,e,t}`","LinkedTechs","text","Dummy techs used to convert CO2 emissions to physical commodity" - ":math:`\text{LLT}_{r,t}`","LoanLifetimeTech",":math:`\mathbb{N}`","Tech-specific loan term (default=10 periods)" + ":math:`\text{LLT}_{r,t}`","LoanLifetimeTech",":math:`\mathbb{N}`","Tech-specific loan term (default=10 years)" ":math:`\text{LR}_{r,t,v}`","LoanRate",":math:`\mathbb{R}`","Tech-specific interest rate on investment cost" ":math:`\text{MAA}_{r,p,t}`","MaxActivity",":math:`\mathbb{R}^+_0`","Maximum tech-specific activity by region and period" ":math:`\text{MAC}_{r,p,t}`","MaxCapacity",":math:`\mathbb{R}^+_0`","Maximum tech-specific capacity by period" @@ -1872,13 +1877,11 @@ capacity and allowable commodity flow. .. autofunction:: temoa_rules.Capacity_Constraint -.. autofunction:: temoa_rules.AdjustedCapacity_Constraint - .. autofunction:: temoa_rules.CapacityAnnual_Constraint -.. autofunction:: temoa_rules.CapacityAvailableByPeriodAndTech_Constraint +.. autofunction:: temoa_rules.AdjustedCapacity_Constraint -.. autofunction:: temoa_rules.ActivityByTech_Constraint +.. autofunction:: temoa_rules.CapacityAvailableByPeriodAndTech_Constraint .. _NetworkConstraints: @@ -1893,7 +1896,7 @@ define the algebraic energy system network. .. autofunction:: temoa_rules.CommodityBalance_Constraint -.. autofunction:: temoa_rules.CommodityBalanceAnnual_Constraint +.. autofunction:: temoa_rules.AnnualCommodityBalance_Constraint Physical and Operational Constraints @@ -1908,8 +1911,12 @@ various physical and operational real-world phenomena. .. autofunction:: temoa_rules.StorageEnergy_Constraint +.. autofunction:: temoa_rules.SeasonalStorageEnergy_Constraint + .. autofunction:: temoa_rules.StorageEnergyUpperBound_Constraint +.. autofunction:: temoa_rules.SeasonalStorageEnergyUpperBound_Constraint + .. autofunction:: temoa_rules.StorageChargeRate_Constraint .. autofunction:: temoa_rules.StorageDischargeRate_Constraint @@ -1926,7 +1933,9 @@ various physical and operational real-world phenomena. .. autofunction:: temoa_rules.RampDownSeason_Constraint -.. autofunction:: temoa_rules.ReserveMargin_Constraint +.. autofunction:: temoa_rules.ReserveMarginStatic + +.. autofunction:: temoa_rules.ReserveMarginDynamic Objective Function @@ -1944,35 +1953,23 @@ operation, but allow the modeler some further degree of system specification. .. commented out... not used? .. autofunction:: temoa_rules.ExistingCapacity_Constraint -.. autofunction:: temoa_rules.EmissionLimit_Constraint - -.. autofunction:: temoa_rules.GrowthRateConstraint_rule +.. autofunction:: temoa_rules.LimitEmission_Constraint -.. autofunction:: temoa_rules.MaxActivity_Constraint +.. autofunction:: temoa_rules.LimitGrowthCapacity -.. autofunction:: temoa_rules.MinActivity_Constraint - -.. autofunction:: temoa_rules.MinActivityGroup_Constraint +.. autofunction:: temoa_rules.LimitActivity_Constraint .. _MaxCapacity_Constraint: -.. autofunction:: temoa_rules.MaxCapacity_Constraint - -.. commented out... not used? - .. autofunction:: temoa_rules.MaxCapacitySet_Constraint - -.. autofunction:: temoa_rules.MinCapacity_Constraint - -.. commented out... not used? - .. autofunction:: temoa_rules.MinCapacitySet_Constraint +.. autofunction:: temoa_rules.LimitCapacity_Constraint -.. autofunction:: temoa_rules.ResourceExtraction_Constraint +.. autofunction:: temoa_rules.LimitResource_Constraint .. _TechOutputSplit_Constraint: -.. autofunction:: temoa_rules.TechInputSplit_Constraint +.. autofunction:: temoa_rules.LimitTechInputSplit_Constraint -.. autofunction:: temoa_rules.TechOutputSplit_Constraint +.. autofunction:: temoa_rules.LimitTechOutputSplit_Constraint diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 8af9c69ed..adf237e47 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -49,16 +49,38 @@ def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): This constraint updates the capacity of a process by taking into account retirements. For a given :code:`(r,p,t,v)` index, this constraint sets the capacity equal to the amount installed in period :code:`v` and subtracts from it any and all retirements - that occurred up until the period in question, :code:`p`.""" + that occurred up until the period in question, :code:`p`, and end of life from the + survival curve if defined. It finally adjusts for the process life fraction, which + accounts for a possible mid-period end of life. + + .. math:: + :label: Adjusted Capacity + + \text{CAP}_{r,p,t,v} = + \begin{cases} + \text{ECAP}_{r,t,v} \cdot \text{LTS}_{r,p,t,v} \cdot \text{PLF}_{r,p,t,v} + & \text{if } t \notin T^\text{ret},\ v \in T^\text{e} \\ + \text{NCAP}_{r,t,v} \cdot \text{LTS}_{r,p,t,v} \cdot \text{PLF}_{r,p,t,v} + & \text{if } t \notin T^\text{ret},\ v \notin T^\text{e} \\ + \left( \text{ECAP}_{r,t,v} \cdot \text{LTS}_{r,p,t,v} + - \sum\limits_{p^* = v}^{p} + \text{RCAP}_{r,p^*,t,v} \right) \cdot \text{PLF}_{r,p,t,v} + & \text{if } t \in T^\text{ret},\ v \in T^\text{e} \\ + \left( \text{NCAP}_{r,t,v} \cdot \text{LTS}_{r,p,t,v} + - \sum\limits_{p^* = v}^{p} + \text{RCAP}_{r,p^*,t,v} \right) \cdot \text{PLF}_{r,p,t,v} + & \text{if } t \in T^\text{ret},\ v \notin T^\text{e} + \end{cases} + """ PLF = value(M.ProcessLifeFrac[r, p, t, v]) - LSC = value(M.LifetimeSurvivalCurve[r, p, t, v]) + LTS = value(M.LifetimeSurvivalCurve[r, p, t, v]) if t not in M.tech_retirement: if v in M.time_exist: - return M.V_Capacity[r, p, t, v] == value(M.ExistingCapacity[r, t, v]) * LSC * PLF + return M.V_Capacity[r, p, t, v] == value(M.ExistingCapacity[r, t, v]) * LTS * PLF else: - return M.V_Capacity[r, p, t, v] == M.V_NewCapacity[r, t, v] * LSC * PLF + return M.V_Capacity[r, p, t, v] == M.V_NewCapacity[r, t, v] * LTS * PLF else: retired_cap = sum( @@ -67,9 +89,9 @@ def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): if v < S_p <= p and S_p < v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[S_p]) ) if v in M.time_exist: - return M.V_Capacity[r, p, t, v] == (value(M.ExistingCapacity[r, t, v]) * LSC - retired_cap) * PLF + return M.V_Capacity[r, p, t, v] == (value(M.ExistingCapacity[r, t, v]) * LTS - retired_cap) * PLF else: - return M.V_Capacity[r, p, t, v] == (M.V_NewCapacity[r, t, v] * LSC - retired_cap) * PLF + return M.V_Capacity[r, p, t, v] == (M.V_NewCapacity[r, t, v] * LTS - retired_cap) * PLF def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): @@ -89,10 +111,9 @@ def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): :label: Capacity \left ( - \text{CFP}_{r, t, v} + \text{CFP}_{r, p, s, d, t, v} \cdot \text{C2A}_{r, t} \cdot \text{SEG}_{s, d} - \cdot \text{PLF}_{r, p, t, v} \right ) \cdot \textbf{CAP}_{r, t, v} = @@ -111,13 +132,12 @@ def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - capacity = get_capacity_factor(M, r, p, s, d, t, v) if t in M.tech_curtailment: # If technologies are present in the curtailment set, then enough # capacity must be available to cover both activity and curtailment. return ( - capacity + get_capacity_factor(M, r, p, s, d, t, v) * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[p, s, d]) * M.V_Capacity[r, p, t, v] == useful_activity + sum( @@ -128,7 +148,7 @@ def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): ) else: return ( - capacity + get_capacity_factor(M, r, p, s, d, t, v) * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[p, s, d]) * M.V_Capacity[r, p, t, v] @@ -178,43 +198,44 @@ def CapacityAnnual_Constraint(M: 'TemoaModel', r, p, t, v): ) -def ActivityByTech_Constraint(M: 'TemoaModel', t): - r""" - This constraint is utilized by the MGA objective function and defines - the total activity of a technology over the planning horizon. The first version - below applies to technologies with variable output at the timeslice level, - and the second version applies to technologies with constant annual output - in the :code:`tech_annual` set. - - .. math:: - :label: ActivityByTech - - \textbf{ACT}_{t} = \sum_{R, P, S, D, I, V, O} \textbf{FO}_{r, p, s, d,i, t, v, o} - \; - \forall t \not\in T^{a} +# devnote: long dead +# def ActivityByTech_Constraint(M: 'TemoaModel', t): +# r""" +# This constraint is utilized by the MGA objective function and defines +# the total activity of a technology over the planning horizon. The first version +# below applies to technologies with variable output at the timeslice level, +# and the second version applies to technologies with constant annual output +# in the :code:`tech_annual` set. - \textbf{ACT}_{t} = \sum_{R, P, I, V, O} \textbf{FOA}_{r, p, i, t, v, o} - \; - \forall t \in T^{a} - """ - if t not in M.tech_annual: - indices = [] - for s_index in M.FlowVar_rpsditvo: - if t in s_index: - indices.append(s_index) - activity = sum(M.V_FlowOut[s_index] for s_index in indices) - else: - indices = [] - for s_index in M.FlowVarAnnual_rpitvo: - if t in s_index: - indices.append(s_index) - activity = sum(M.V_FlowOutAnnual[s_index] for s_index in indices) +# .. math:: +# :label: ActivityByTech - if int is type(activity): - return Constraint.Skip +# \textbf{ACT}_{t} = \sum_{R, P, S, D, I, V, O} \textbf{FO}_{r, p, s, d,i, t, v, o} +# \; +# \forall t \not\in T^{a} - expr = M.V_ActivityByTech[t] == activity - return expr +# \textbf{ACT}_{t} = \sum_{R, P, I, V, O} \textbf{FOA}_{r, p, i, t, v, o} +# \; +# \forall t \in T^{a} +# """ +# if t not in M.tech_annual: +# indices = [] +# for s_index in M.FlowVar_rpsditvo: +# if t in s_index: +# indices.append(s_index) +# activity = sum(M.V_FlowOut[s_index] for s_index in indices) +# else: +# indices = [] +# for s_index in M.FlowVarAnnual_rpitvo: +# if t in s_index: +# indices.append(s_index) +# activity = sum(M.V_FlowOutAnnual[s_index] for s_index in indices) + +# if int is type(activity): +# return Constraint.Skip + +# expr = M.V_ActivityByTech[t] == activity +# return expr def CapacityAvailableByPeriodAndTech_Constraint(M: 'TemoaModel', r, p, t): @@ -251,28 +272,28 @@ def CapacityAvailableByPeriodAndTech_Constraint(M: 'TemoaModel', r, p, t): # devnote: I don't think this constraint is necessary as if this were violated # then V_Capacity would be negative, which isn't allowed anyway -def RetiredCapacity_Constraint(M: 'TemoaModel', r, p, t, v): - r""" - -Temoa allows for the economic retirement of technologies presented in the -:code:`tech_retirement` set. This constraint sets the upper limit of retired -capacity to the total installed capacity. -In the equation below, we set the upper bound of the retired capacity to the -previous period's total installed capacity (CAPAVL) - -.. math:: - :label: RetiredCapacity +# def RetiredCapacity_Constraint(M: 'TemoaModel', r, p, t, v): +# r""" - \textbf{CAPRET}_{r, p, t, v} \leq \sum_{V} {PLF}_{r, p, t, v} \cdot \textbf{CAP}_{r, t, v} - \\ - \forall \{r, p, t, v\} \in \Theta_{\text{RetiredCapacity}} -""" - if p == M.time_optimize.first(): - cap_avail = value(M.ExistingCapacity[r, t, v]) - else: - cap_avail = M.V_Capacity[r, M.time_optimize.prev(p), t, v] - expr = M.V_RetiredCapacity[r, p, t, v] <= cap_avail - return expr +# Temoa allows for the economic retirement of technologies presented in the +# :code:`tech_retirement` set. This constraint sets the upper limit of retired +# capacity to the total installed capacity. +# In the equation below, we set the upper bound of the retired capacity to the +# previous period's total installed capacity (CAPAVL) + +# .. math:: +# :label: RetiredCapacity + +# \textbf{CAPRET}_{r, p, t, v} \leq \sum_{V} {PLF}_{r, p, t, v} \cdot \textbf{CAP}_{r, t, v} +# \\ +# \forall \{r, p, t, v\} \in \Theta_{\text{RetiredCapacity}} +# """ +# if p == M.time_optimize.first(): +# cap_avail = value(M.ExistingCapacity[r, t, v]) +# else: +# cap_avail = M.V_Capacity[r, M.time_optimize.prev(p), t, v] +# expr = M.V_RetiredCapacity[r, p, t, v] <= cap_avail +# return expr def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): @@ -1089,8 +1110,8 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): r""" Similar to CommodityBalance_Constraint but only balances the supply and demand of the commodity - at the annual level, summing all flows over the year. Applies only to commodities tagged as annual - 'a' in the Commodity table. + at the period level, summing all flows over the period but allowing imbalances at the time slice + or seasonal level. Applies only to commodities in the :code:`commodity_annual` set. """ if c in M.commodity_demand: # Is this necessary? Demand comms have no downstream process no shouldnt be in indices @@ -1363,8 +1384,17 @@ def RegionalExchangeCapacity_Constraint(M: 'TemoaModel', r_e, r_i, p, t, v): def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): """ - This constraint enforces the continuity of state of charge (StorageLevel) between time slices. - StorageLevel in the next time slice is equal to current StorageLevel plus net charge in the current time slice. + This constraint enforces the continuity of storage level between time slices. + storage level in the next time slice (:math:`s_{next}, d_{next}`) is equal to + current storage level plus net charge in the current time slice. + + .. math:: + :label: Storage Energy + + {SL}_{r,p,s,d,t,v} + + \sum\limits_{I,O} \mathbf{FIS}_{r,p,s,d,i,t,v,o} \cdot {EFF}_{r,i,t,v,o} + - \sum\limits_{I,O} \mathbf{FO}_{r,p,s,d,i,t,v,o} + = {SL}_{r,p,s_{{next}},d_{{next}},t,v} """ # We allow a non-zero daily delta only in the case of seasonal storage @@ -1397,17 +1427,34 @@ def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_seq, t, v): - """ + r""" This constraint enforces the continuity of state of charge between seasons for seasonal storage. Sequential season storage level increases by the matched season's net charge over that entire day, adjusted for number of days represented by sequential vs non-sequential - seasons. + seasons. Only applies to storage technologies in the :code:`tech_seasonal_storage` set. + :math:`s^*` represents the matching non-sequential season for the sequential season + :math:`s_{seq}`. + + .. math:: + :label: Storage Energy (Sequential Seasons) + + \mathbf{SSL}_{r,p,s_{seq},t,v} + + DA_{r,p,s_{seq}} \cdot \left(\mathbf{SL}_{r,p,s^*,d_{first},t,v} + + \sum_{I,O} \mathbf{FI}_{r,p,s^*,d_{first},i,t,v,o} \cdot EFF_{r,p,i,t,v,o} + - \sum_{I,O} \mathbf{FO}_{r,p,s^*,d_{first},i,t,v,o} + \right) + + = DA_{r,p,s_{seq,next}} \cdot \mathbf{SL}_{r,p,s^*_{next},d_{first},t,v} + + \mathbf{SSL}_{r,p,s_{seq}^{next},t,v} + + \\ + \text{where } DA_{r,p,s_{seq}} = \frac{\#days_{s_{seq}}}{SEG_{r,p,s^*} \cdot DPP} """ s = M.sequential_to_season[p, s_seq] # This is the sum of all input=i sent TO storage tech t of vintage v with - # output=o in p,s,d + # output=o in p,s charge = sum( M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] * get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) for S_i in M.processInputs[r, p, t, v] @@ -1416,7 +1463,7 @@ def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_seq, t, v): ) # This is the sum of all output=o withdrawn FROM storage tech t of vintage v - # with input=i in p,s,d + # with input=i in p,s discharge = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] for S_o in M.processOutputs[r, p, t, v] @@ -1453,7 +1500,7 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): by the number of hours in a year to obtain the duration as a fraction of the year. Since the :math:`C2A` parameter assumes the conversion of capacity to annual activity, we need to express the storage duration as fraction of a year. Then, :math:`SEG_{s,d}` - summed over the time-of-day slices (:math:`d`) multiplied by M.DaysPerPeriod yields the + summed over the time-of-day slices (:math:`d`) multiplied by :math:`DPP` yields the number of days per season. This step is necessary because conventional time sliced models use a single day to represent many days within a given season. Thus, it is necessary to scale the storage duration to account for the number of days in each season. @@ -1462,8 +1509,8 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): :label: StorageEnergyUpperBound \textbf{SL}_{r, p, s, d, t, v} \le - \textbf{CAP}_{r,t,v} \cdot C2A_{r,t} \cdot \frac {SD_{r,t}}{24 * value(M.DaysPerPeriod) hrs/yr} - \cdot \sum_{d} SEG_{s,d} \cdot M.DaysPerPeriod + \textbf{CAP}_{r,t,v} \cdot C2A_{r,t} \cdot \frac {SD_{r,t}}{24 \cdot DPP} + \cdot \sum_{d} SEG_{s,d} \cdot DPP \\ \forall \{r, p, s, d, t, v\} \in \Theta_{\text{StorageEnergyUpperBound}} @@ -1488,18 +1535,30 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_seq, d, t, v): r""" Builds off of StorageEnergyUpperBound_Constraint. Enforces the max charge capacity - of seasonal storage, summing the superimposed real storage level with the sequential + of seasonal storage, summing the real storage level with the superimposed sequential seasonal storage level. A season can represent many days. Within each season, flows are multiplied by the number of days each season represents, and so the upper bound needs to be adjusted to allow day-scale flows (e.g., charge in the morning, discharge in the afternoon). However, between seasons, whole-day charge deltas have built up, multiplied by the number of days the season represents. These deltas stack, - possibly exceeding our upper bound by a factor of (N-1)/N where N is the number of - days the season represents. Additionally, if we allowed these stacked deltas to - carry between seasons then we would be multiplying the effective energy capacity of - the storage. So, we do not adjust the bound for seasonal storage. Seasonal storage - therefore cannot do much arbitrage within each season, but can carry energy between - seasons. + possibly exceeding our upper bound by a factor of :math:`\frac{N-1}{N}` where :math:`N` + is the number of days the season represents. Additionally, if we allowed these stacked + deltas to carry between seasons then we would be multiplying the effective energy + capacity of the storage. So, we do not adjust the bound for seasonal storage. This + limits the ability of seasonal storage to perform arbitrage within each season, but + allows it to carry energy between seasons. :math:`s^*` represents the matching + non-sequential season for the sequential season :math:`s_{seq}`. + + .. math:: + :label: Seasonal Storage Energy Capacity + + \mathbf{SSL}_{r,p,s_{seq},t,v} + + \mathbf{SL}_{r,p,s^*,d,t,v} \cdot DA_{r,p,s_{seq}} + \leq \mathbf{CAP}_{r,p,t,v} \cdot C2A_{r,t} \cdot \frac{SD_{r,t}}{24 \cdot DPP} + + \\ + + \text{where } DA_{r,p,s_{seq}} = \frac{\#days_{s_{seq}}}{SEG_{r,p,s^*} \cdot DPP} """ s = M.sequential_to_season[p, s_seq] @@ -1688,51 +1747,51 @@ def LimitStorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v, op): def RampUpDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): - # M.time_of_day is a sorted set, and M.time_of_day.first() returns the first - # element in the set, similarly, M.time_of_day.last() returns the last element. - # M.time_of_day.prev(d) function will return the previous element before s, and - # M.time_of_day.next(d) function will return the next element after s. - r""" + One of two constraints built from the RampUpHourly table, along with the + RampUpSeason_Constraint. RampUpDay constrains ramp rates between time slices + within each season and RampUpSeason constrains ramp rates between sequential + seasons. If the :code:`time_sequencing` parameter is set to :code:`sequential_days` + then the RampUpSeason constraint is skipped as seasons already connect together. The ramp rate constraint is utilized to limit the rate of electricity generation increase and decrease between two adjacent time slices in order to account for - physical limits associated with thermal power plants. Note that this constraint - only applies to technologies with ramp capability, which is defined in the set - :math:`T^{m}`. We assume for simplicity the rate limits for both - ramp up and down are equal and they do not vary with technology vintage. The - ramp rate limits (:math:`r_t`) for technology :math:`t` should be expressed in - percentage of its rated capacity. - - Note that when :math:`d_{nd}` is the last time-of-day, :math:`d_{nd + 1} \not \in - \textbf{D}`, i.e., if one time slice is the last time-of-day in a season and the - other time slice is the first time-of-day in the next season, the ramp rate - limits between these two time slices can not be expressed by :code:`RampUpDay`. - Therefore, the ramp rate constraints between two adjacent seasons are - represented in :code:`RampUpSeason`. - - In the :code:`RampUpDay` and :code:`RampUpSeason` constraints, we assume - :math:`\textbf{S} = \{s_i, i = 1, 2, \cdots, ns\}` and - :math:`\textbf{D} = \{d_i, i = 1, 2, \cdots, nd\}`. + physical limits associated with thermal power plants. This constraint is only + applied to technologies in the set :code:`tech_upramping`. We assume for + simplicity the rate limits do not vary with technology vintage. The ramp rate + limits for a technology should be expressed in percentage of its rated capacity + per hour. + + In a representative periods or seasonal time slices model, the next time slice, + :math:`(s_{next},d_{next})`, from the end of each season, :math:`(s,d_{last})` + is the beginning of the same season, :math:`(s,d_{first})` .. math:: :label: RampUpDay - \frac{ - \sum_{I, O} \textbf{FO}_{r, p, s, d_{i + 1}, i, t, v, o} - }{ - SEG_{s, d_{i + 1}} \cdot C2A_{r,t} - } - - - \frac{ - \sum_{I, O} \textbf{FO}_{r, p, s, d_i, i, t, v, o} - }{ - SEG_{s, d_i} \cdot C2A_{r,t} - } - \leq - r_t \cdot \textbf{CAPAVL}_{r,p,t} - \\ - \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampUpDay}} + \frac{ + \sum_{I,O} \mathbf{FO}_{r,p,s_{next},d_{next},i,t,v,o} + }{ + SEG_{r,p,s_{next},d_{next}} \cdot 24 \cdot DPP + } + - + \frac{ + \sum_{I,O} \mathbf{FO}_{r,p,s,d,i,t,v,o} + }{ + SEG_{r,p,s,d} \cdot 24 \cdot DPP + } + \leq + R_{r,t} \cdot \Delta H_{r,p,s,d,s_{next},d_{next}} \cdot CAP_{r,p,t,v} \cdot C2A_{r,t} + \\ + \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampUpDay}} + + where: + + - :math:`SEG_{r,p,s,d}` is the fraction of the period in time slice :math:`(s,d)` + - :math:`DPP` is the number of days in each period + - :math:`R_{r,t}` is the ramp rate per hour + - :math:`\Delta H_{r,p,s,d,s_{next},d_{next}}` is the number of elapsed hours between midpoints of time slices + - :math:`CAP \cdot C2A` gives the maximum hourly change in activity """ s_next, d_next = M.time_next[p, s, d] @@ -1783,21 +1842,21 @@ def RampDownDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): .. math:: :label: RampDownDay - \frac{ - \sum_{I, O} \textbf{FO}_{r, p, s, d_{i + 1}, i, t, v, o} - }{ - SEG_{s, d_{i + 1}} \cdot C2A_{r,t} - } - - - \frac{ - \sum_{I, O} \textbf{FO}_{r, p, s, d_i, i, t, v, o} - }{ - SEG_{s, d_i} \cdot C2A_{r,t} - } - \geq - -r_t \cdot \textbf{CAPAVL}_{r,p,t} - \\ - \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampDownDay}} + \frac{ + \sum_{I,O} \mathbf{FO}_{r,p,s,d,i,t,v,o} + }{ + SEG_{r,p,s,d} \cdot 24 \cdot DPP + } + - + \frac{ + \sum_{I,O} \mathbf{FO}_{r,p,s_{next},d_{next},i,t,v,o} + }{ + SEG_{r,p,s_{next},d_{next}} \cdot 24 \cdot DPP + } + \leq + R_{r,t} \cdot \Delta H_{r,p,s,d,s_{next},d_{next}} \cdot CAP_{r,p,t,v} \cdot C2A_{r,t} + \\ + \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampDownDay}} """ s_next, d_next = M.time_next[p, s, d] @@ -1842,7 +1901,10 @@ def RampDownDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): def RampUpSeason_Constraint(M: 'TemoaModel', r, p, s, s_next, t, v): r""" Constrains the ramp up rate of activity between time slices at the boundary - of sequential seasons. + of sequential seasons. Same as RampDay but only applies to the boundary + between seasons, i.e., :math:`(s,d_{last})` to :math:`(s_{next},d_{first})` + and :math:`s_{next}` is based on the TimeSequential table rather than the + TimeSeason table. """ d = M.time_of_day.last() @@ -1888,7 +1950,10 @@ def RampUpSeason_Constraint(M: 'TemoaModel', r, p, s, s_next, t, v): def RampDownSeason_Constraint(M: 'TemoaModel', r, p, s, s_next, t, v): r""" Constrains the ramp down rate of activity between time slices at the boundary - of sequential seasons. + of sequential seasons. Same as RampDay but only applies to the boundary + between seasons, i.e., :math:`(s,d_{last})` to :math:`(s_{next},d_{first})` + and :math:`s_{next}` is based on the TimeSequential table rather than the + TimeSeason table. """ d = M.time_of_day.last() @@ -1999,25 +2064,29 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): def ReserveMarginStatic(M: 'TemoaModel', r, p, s, d): r""" - During each period :math:`p`, the sum of the available capacity of all reserve - technologies :math:`\sum_{t \in T^{e}} \textbf{CAPAVL}_{r,p,t}`, which are - defined in the set :math:`\textbf{T}^{r,e}`, should exceed the peak load by + During each period :math:`p`, the sum of capacity values of all reserve + technologies :math:`\sum_{t \in T^{res}} \textbf{CAPAVL}_{r,p,t}`, which are + defined in the set :math:`\textbf{T}^{res}`, should exceed the peak load by :math:`PRM`, the regional reserve margin. Note that the reserve margin is expressed in percentage of the peak load. Generally speaking, in a database we may not know the peak demand before running the model, therefore, we write this equation for all the time-slices defined in the database in each region. + Each generator is allowed to contribute its available capacity times a pre-defined + capacity credit, :math:`CC_{t,r}` .. math:: :label: reserve_margin - &\sum_{t \in T^{res} \setminus T^{e}} {CC_{t,r} \cdot \textbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*} \cdot C2A_{r,t} }\\ - &+ \sum_{t \in T^{res} \cap T^{e}} {CC_{t,r_i-r} \cdot \textbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*} \cdot C2A_{r_i-r,t} }\\ - &- \sum_{t \in T^{res} \cap T^{e}} {CC_{t,r-r_i} \cdot \textbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*} \cdot C2A_{r_i-r,t} }\\ - &\geq \left [ \sum_{ t \in T^{res} \setminus T^{e},V,I,O } \textbf{FO}_{r, p, s, d, i, t, v, o}\right.\\ - &+ \sum_{ t \in T^{res} \cap T^{e},V,I,O } \textbf{FO}_{r_i-r, p, s, d, i, t, v, o}\\ - &- \sum_{ t \in T^{res} \cap T^{e},V,I,O } \textbf{FI}_{r-r_i, p, s, d, i, t, v, o}\\ + &\sum_{t \in T^{res} \setminus T^{x}} {CC_{t,r} \cdot \textbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*} \cdot C2A_{r,t} }\\ + &+ \sum_{t \in T^{res} \cap T^{x}} {CC_{t,r_i-r} \cdot \textbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*} \cdot C2A_{r_i-r,t} }\\ + &- \sum_{t \in T^{res} \cap T^{x}} {CC_{t,r-r_i} \cdot \textbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*} \cdot C2A_{r-r_i,t} }\\ + &\geq \left [ \sum_{ t \in T^{res} \setminus T^{x},V,I,O } \textbf{FO}_{r, p, s, d, i, t, v, o}\right.\\ + &+ \sum_{ t \in T^{res} \cap T^{x},V,I,O } \textbf{FO}_{r_i-r, p, s, d, i, t, v, o}\\ + &- \sum_{ t \in T^{res} \cap T^{x},V,I,O } \textbf{FI}_{r-r_i, p, s, d, i, t, v, o}\\ &- \left.\sum_{ t \in T^{res} \cap T^{s},V,I,O } \textbf{FI}_{r, p, s, d, i, t, v, o} \right] \cdot (1 + PRM_r)\\ - &\qquad \qquad \forall \{r, p, s, d\} \in \Theta_{\text{ReserveMargin}} \text{and} \forall r_i \in R + + \\ + &\qquad\qquad\forall \{r, p, s, d\} \in \Theta_{\text{ReserveMargin}} \text{and} \forall r_i \in R """ if (not M.tech_reserve) or ( (r, p) not in M.processReservePeriods @@ -2069,8 +2138,43 @@ def ReserveMarginStatic(M: 'TemoaModel', r, p, s, d): def ReserveMarginDynamic(M: 'TemoaModel', r, p, s, d): r""" A dynamic alternative to the traditional, static reserve margin constraint. Capacity values - are calculated from availability of generation in each hour, like an operating reserve margin, - accounting for a capacity derate factor representing the forced outage rate. + are calculated from availability of generation in each hour—like an operating reserve margin—\ + accounting for a capacity derate factor subtracting, for example, forced outage due to icing. + + .. math:: + :label: reserve_margin + + &\sum_{t \in T^{res} \setminus T^{x} \setminus T^s,\ V} CFP_{r,p,s^*,d^*,t,v}\ + \cdot RCD_{r,p,s^*,t,v}\ + \cdot \mathbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*}\ + \cdot C2A_{r,t} \\ + &+ \sum_{t \in T^{res} \cap T^{x} \setminus T^s,\ V} CFP_{r_i - r, p, s^*, d^*, t, v}\ + \cdot RCD_{r_i - r, p, s^*, t, v}\ + \cdot \mathbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*}\ + \cdot C2A_{r_i - r, t} \\ + &- \sum_{t \in T^{res} \cap T^{x} \setminus T^s,\ V} CFP_{r - r_i, p, s^*, d^*, t, v}\ + \cdot RCD_{r - r_i, p, s^*, t, v}\ + \cdot \mathbf{CAPAVL}_{p,t}\ + \cdot SEG_{s^*,d^*} \cdot C2A_{r - r_i, t} \\ + &+ \sum_{t \in T^s, V, I, O} \ + \left(\ + \mathbf{FO}_{r,p,s,d,i,t,v,o} - \mathbf{FI}_{r,p,s,d,i,t,v,o}\ + \right)\ + \cdot RCD_{r,p,s,t,v} \\ + &\geq\ + \left[\ + \sum_{t \in T^{res} \setminus T^{x}, V, I, O}\ + \mathbf{FO}_{r, p, s, d, i, t, v, o}\ + \right. \\ + &+ \sum_{t \in T^{res} \cap T^{x}, V, I, O} \ + \mathbf{FO}_{r_i - r, p, s, d, i, t, v, o} \\ + &- \sum_{t \in T^{res} \cap T^{x}, V, I, O} \ + \mathbf{FI}_{r - r_i, p, s, d, i, t, v, o} \\ + &- \left. \sum_{t \in T^{res} \cap T^{s}, V, I, O} \ + \mathbf{FI}_{r, p, s, d, i, t, v, o} \right] \cdot (1 + PRM_r) \\ + \\ + &\qquad \qquad \forall \{r, p, s, d\} \in \ + \Theta_{\text{ReserveMargin}} \text{ and } \forall r_i \in R """ if (not M.tech_reserve) or ( (r, p) not in M.processReservePeriods From bdb02574db72ad9e80b9ab4ae5aa1220ad34b0e0 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 23 Jun 2025 19:25:54 -0400 Subject: [PATCH 154/587] Fix annual retirement calculation --- temoa/temoa_model/temoa_rules.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index adf237e47..6a662bf13 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -307,11 +307,14 @@ def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): if p <= v + value(M.LifetimeProcess[r, t, v]) < p + value(M.PeriodLength[p]): # EOL this period if p == M.time_optimize.first() and v in M.time_exist: - # Existing capacity in first period. Remaining existing capacity - retired = value(M.ExistingCapacity[r, t, v]) * value(M.LifetimeSurvivalCurve[r, p, t, v]) + # Existing capacity in first period. Remaining existing capacity in last existing period + retired = ( + value(M.ExistingCapacity[r, t, v]) + * M.LifetimeSurvivalCurve[r, M.time_exist.last(), t, v] + ) elif p == v: - # New capacity in its vintage period. Remaining new capacity - retired = M.V_NewCapacity[r, t, v] * value(M.LifetimeSurvivalCurve[r, p, t, v]) + # New capacity in its vintage period. All new capacity + retired = M.V_NewCapacity[r, t, v] else: # Mid-horizon retirement retired = M.V_Capacity[r, M.time_optimize.prev(p), t, v] From e0c954c1a24cf0c6e3e41663ba8e228f433da2bd Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 23 Jun 2025 20:57:47 -0400 Subject: [PATCH 155/587] Update more Limit constraints in docs --- docs/README.md | 2 +- docs/source/Documentation.rst | 30 ++++- temoa/temoa_model/temoa_rules.py | 211 ++++++++++++++++++++++--------- 3 files changed, 181 insertions(+), 62 deletions(-) diff --git a/docs/README.md b/docs/README.md index a164ab936..cac3838e0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -28,7 +28,7 @@ Sometimes this automatic PDF generation fails. If that is the case, navigate to ## In Windows With the Temoa virtual environment active (see README in root folder), navigate to this directory: -```cd C://temoa3/``` +```cd C://temoa3/docs/``` Then build the documentation with Sphinx: diff --git a/docs/source/Documentation.rst b/docs/source/Documentation.rst index 862323a34..9308d2f56 100644 --- a/docs/source/Documentation.rst +++ b/docs/source/Documentation.rst @@ -1955,14 +1955,20 @@ operation, but allow the modeler some further degree of system specification. .. autofunction:: temoa_rules.LimitEmission_Constraint -.. autofunction:: temoa_rules.LimitGrowthCapacity - .. autofunction:: temoa_rules.LimitActivity_Constraint +.. autofunction:: temoa_rules.LimitActivityShare_Constraint + .. _MaxCapacity_Constraint: .. autofunction:: temoa_rules.LimitCapacity_Constraint +.. autofunction:: temoa_rules.LimitNewCapacity_Constraint + +.. autofunction:: temoa_rules.LimitCapacityShare_Constraint + +.. autofunction:: temoa_rules.LimitNewCapacityShare_Constraint + .. autofunction:: temoa_rules.LimitResource_Constraint .. _TechOutputSplit_Constraint: @@ -1971,6 +1977,26 @@ operation, but allow the modeler some further degree of system specification. .. autofunction:: temoa_rules.LimitTechOutputSplit_Constraint +.. autofunction:: temoa_rules.LimitTechInputSplitAnnual_Constraint + +.. autofunction:: temoa_rules.LimitTechOutputSplitAnnual_Constraint + +.. autofunction:: temoa_rules.LimitTechInputSplitAverage_Constraint + +.. autofunction:: temoa_rules.LimitTechOutputSplitAverage_Constraint + +.. autofunction:: temoa_rules.LimitAnnualCapacityFactor_Constraint + +.. autofunction:: temoa_rules.LimitSeasonalCapacityFactor_Constraint + +.. autofunction:: temoa_rules.LimitStorageLevelFraction_Constraint + +.. autofunction:: temoa_rules.LimitGrowthCapacity + +.. autofunction:: temoa_rules.LimitGrowthNewCapacity + +.. autofunction:: temoa_rules.LimitGrowthNewCapacityDelta + General Caveats diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 6a662bf13..0397dcd89 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -299,9 +299,10 @@ def CapacityAvailableByPeriodAndTech_Constraint(M: 'TemoaModel', r, p, t): def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): r""" Get the annualised retirement rate for a process in a given period. - Used to model end of life flows and emissions. Assumes that retirement - is evenly distributed over the model period, in the same way we assume - capacity is deployed evenly over the model period. + Used to output retirement and model end of life flows and emissions. + Assumes that retirement is evenly distributed over the model period, + in the same way we assume capacity is deployed evenly over the model + period. """ if p <= v + value(M.LifetimeProcess[r, t, v]) < p + value(M.PeriodLength[p]): @@ -568,7 +569,7 @@ def loan_cost_survival_curve( * annuity_to_pv(GDR, lifetime_loan_process) # PV of all loan payments, discounted to vintage year using GDR / sum( # redistributed over survival curve within horizon value(M.LifetimeSurvivalCurve[r, p, t, v]) # reamortised over survival curve of process using GDR - * fv_to_pv(GDR, p - v + 1) + * fv_to_pv(GDR, p - v + 1) # the +1 makes its return because LSC is indexed to start of p not end of p for p in M.survivalCurvePeriods[r, t, v] if v <= p # this shouldnt be possible but play it safe ) @@ -578,7 +579,7 @@ def loan_cost_survival_curve( for p in M.survivalCurvePeriods[r, t, v] if v <= p < P_e ) - * fv_to_pv(GDR, v - P_0) # finally, discounted from vintage year to P_0 + * fv_to_pv(GDR, v - P_0) # finally, discounted from vintage year to P_0 ) return res @@ -2352,20 +2353,41 @@ def LimitEmission_Constraint(M: 'TemoaModel', r, p, e, op): def LimitGrowthCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): - r"""Constrain ramp down rate of available capacity""" + r"""Constrain ramp up rate of available capacity""" return LimitGrowthCapacity(M, r, p, t, op, False) def LimitDegrowthCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): - r"""Constrain ramp up rate of available capacity""" + r"""Constrain ramp down rate of available capacity""" return LimitGrowthCapacity(M, r, p, t, op, True) def LimitGrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): r""" Constrain the change of capacity available between periods. Forces the model to ramp up and down the availability of new technologies - more smoothly. Has constant (seed) and proportional (rate) terms. + more smoothly. Has constant (seed, :math:`S_{r,t}`) and proportional + (rate, :math:`R_{r,t}`) terms. This can be defined for a technology group + instead of one technology, in which case, capacity available is summed over + all technologies in the group. In the first period, previous available + capacity :math:`\mathbf{CAPAVL}_{r,p,t}` is replaced by previous existing + capacity, if any can be found. - CapacityAvailable_(p) <= SEED + RATE * CapacityAvailable_(p-1) + .. math:: + :label: Limit (De)Growth Capacity + + \begin{aligned}\text{Growth:}\\ + &\mathbf{CAPAVL}_{r,p,t} + \leq S_{r,t} + (1+R_{r,t}) \cdot \mathbf{CAPAVL}_{r,p_{prev},t} + \end{aligned} + + \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitGrowthCapacity}} + + + \begin{aligned}\text{Degrowth:}\\ + &\mathbf{CAPAVL}_{r,p_{prev},t} + \leq S_{r,t} + (1+R_{r,t}) \cdot \mathbf{CAPAVL}_{r,p,t} + \end{aligned} + + \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitDegrowthCapacity}} """ regions = gather_group_regions(M, r) @@ -2441,20 +2463,42 @@ def LimitGrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): def LimitGrowthNewCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): - r"""Constrain ramp down rate of new capacity deployment""" + r"""Constrain ramp up rate of new capacity deployment""" return LimitGrowthNewCapacity(M, r, p, t, op, False) def LimitDegrowthNewCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): - r"""Constrain ramp up rate of new capacity deployment""" + r"""Constrain ramp down rate of new capacity deployment""" return LimitGrowthNewCapacity(M, r, p, t, op, True) def LimitGrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): r""" Constrain the change of new capacity deployed between periods. Forces the model to ramp up and down the deployment of new technologies - more smoothly. Has constant (seed) and proportional (rate) terms. + more smoothly. Has constant (seed, :math:`S_{r,t}`) and proportional + (rate, :math:`R_{r,t}`) terms. This can be defined for a technology group + instead of one technology, in which case, new capacity is summed over + all technologies in the group. In the first period, previous new capacity + :math:`\mathbf{NCAP}_{r,t,v_prev}` is replaced by previous existing capacity, + if any can be found. - NewCapacity_(p) <= SEED + RATE * NewCapacity_(p-1) + .. math:: + :label: Limit (De)Growth Capacity + + \begin{aligned}\text{Growth:}\\ + &\mathbf{NCAP}_{r,t,v} + \leq S_{r,t} + (1+R_{r,t}) \cdot \mathbf{NCAP}_{r,t,v_{prev}} + \text{ where } v=p + \end{aligned} + + \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitGrowthCapacity}} + + \begin{aligned}\text{Degrowth:}\\ + &\mathbf{NCAP}_{r,t,v_{prev}} + \leq S_{r,t} + (1+R_{r,t}) \cdot \mathbf{NCAP}_{r,t,v} + \text{ where } v=p + \end{aligned} + + \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitDegrowthCapacity}} """ regions = gather_group_regions(M, r) @@ -2528,20 +2572,45 @@ def LimitGrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False) def LimitGrowthNewCapacityDeltaConstraint_rule(M: 'TemoaModel', r, p, t, op): - r"""Constrain ramp down rate of change in new capacity deployment""" + r"""Constrain ramp up rate of change in new capacity deployment""" return LimitGrowthNewCapacityDelta(M, r, p, t, op, False) def LimitDegrowthNewCapacityDeltaConstraint_rule(M: 'TemoaModel', r, p, t, op): - r"""Constrain ramp up rate of change in new capacity deployment""" + r"""Constrain ramp down rate of change in new capacity deployment""" return LimitGrowthNewCapacityDelta(M, r, p, t, op, True) def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): r""" Constrain the acceleration of new capacity deployed between periods. Forces the model to ramp up and down the change in deployment of new technologies - more smoothly. Has constant (seed) and proportional (rate) terms. + more smoothly. Has constant (seed, :math:`S_{r,t}`) and proportional + (rate, :math:`R_{r,t}`) terms. It is recommended to leave the rate term empty + as it would prevent the possibility of inflection in the rate of deployment. + This constraint can be defined for a technology group instead of one technology, + in which case, new capacity is summed over all technologies in the group. In the + first period, previous new capacities are replaced by previous existing capacities, + if any can be found. - (NewCapacity_(p) - NewCapacity_(p-1)) <= SEED + RATE * (NewCapacity_(p-1) - NewCapacity_(p-2)) + .. math:: + :label: Limit (De)Growth Capacity + + \begin{aligned}\text{Growth:}\\ + &\mathbf{NCAP}_{r,t,v_i} - \mathbf{NCAP}_{r,t,v_{i-1}} + \leq S_{r,t} + (1+R_{r,t}) \cdot (\mathbf{NCAP}_{r,t,v_{i-1}} - \mathbf{NCAP}_{r,t,v_{i-2}}) + \end{aligned} + + \text{ where } v_i=p + + \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitGrowthCapacityDelta}} + + \begin{aligned}\text{Degrowth:}\\ + &\mathbf{NCAP}_{r,t,v_{i-1}} - \mathbf{NCAP}_{r,t,v_{i-2}} + \leq S_{r,t} + (1+R_{r,t}) \cdot (\mathbf{NCAP}_{r,t,v_i} - \mathbf{NCAP}_{r,t,v_{i-1}}) + \end{aligned} + + \text{ where } v_i=p + + \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitDegrowthCapacityDelta}} """ regions = gather_group_regions(M, r) @@ -2653,13 +2722,15 @@ def LimitActivity_Constraint(M: 'TemoaModel', r, p, t, op): .. math:: :label: LimitActivity - \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le MAA_{r, p, t} + \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} - \forall \{r, p, t\} \in \Theta_{\text{LimitActivity}} + \forall \{r, p, t \notin T^{a}\} \in \Theta_{\text{LimitActivity}} - \sum_{I,V,O} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} \le MAA_{r, p, t} + +\sum_{I,V,O} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} \forall \{r, p, t \in T^{a}\} \in \Theta_{\text{LimitActivity}} + + \le LA_{r, p, t} """ # r can be an individual region (r='US'), or a combination of regions separated by # a + (r='Mexico+US+Canada'), or 'global'. @@ -2699,11 +2770,16 @@ def LimitActivity_Constraint(M: 'TemoaModel', r, p, t, op): def LimitNewCapacity_Constraint(M: 'TemoaModel', r, p, t, op): r""" The LimitNewCapacity constraint sets a limit on the newly installed capacity of a - given technology in a given year. Note that the indices for these constraints are region, + given technology or group in a given year. Note that the indices for these constraints are region, period and tech. + .. math:: - :label: LimitNewCapacity - \textbf{CAP}_{r, t, p} \le LIM_{r, p, t}""" + :label: LimitNewCapacity + + \textbf{NCAP}_{r, t, v} \le LNC_{r, p, t} + + \text{where }v=p + """ regions = gather_group_regions(M, r) techs = gather_group_techs(M, t) cap_lim = value(M.LimitNewCapacity[r, p, t, op]) @@ -2726,7 +2802,7 @@ def LimitCapacity_Constraint(M: 'TemoaModel', r, p, t, op): .. math:: :label: LimitCapacity - \textbf{CAPAVL}_{r, p, t} \le MAC_{r, p, t} + \textbf{CAPAVL}_{r, p, t} \le LC_{r, p, t} \forall \{r, p, t\} \in \Theta_{\text{LimitCapacity}}""" regions = gather_group_regions(M, r) @@ -2751,9 +2827,13 @@ def LimitResource_Constraint(M: 'TemoaModel', r, t, op): .. math:: :label: LimitResource - \sum_{P} \textbf{CAPAVL}_{r, p, t} \le MAR_{r, t} + \sum_{P,S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t \notin T^a, v, o} - \forall \{r, t\} \in \Theta_{\text{LimitCapacity}}""" + +\sum_{P,I,V,O} \textbf{FO}_{r, p, i, t \in T^a, v, o} + + \le LR_{r, t} + + \forall \{r, t\} \in \Theta_{\text{LimitResource}}""" # dev note: this constraint is a misnomer. It is actually a "global activity constraint on a tech" # regardless of whatever "resources" are consumed. # dev note: this would generally be applied to a "dummy import" technology to restrict something like @@ -2792,11 +2872,18 @@ def LimitResource_Constraint(M: 'TemoaModel', r, t, op): def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): r""" - The LimitActivityShare constraint limits the activity share for a given - technology within a technology groups to which it belongs. - For instance, you might define a tech_group of light-duty vehicles, whose - members are different types for LDVs. This constraint could be used to enforce - that no more than 10% of LDVs must be of a certain type. + The LimitActivityShare constraint limits the activity of a given + technology or group as a fraction of another technology or group. This + can be used to set, for example, a renewable portfolio scheme constraint. + + .. math:: + :label: Limit Activity Share + + \sum_{R' \in R_g,\ T \in g_1,\ V,\ I,\ O,\ S,\ D} \mathbf{FO}_{r',p,s,d,i,t,v,o} + \leq LAS_{r,p,g_1,g_2} \cdot + \sum_{R' \in R_g,\ T \in g_2,\ V,\ I,\ O,\ S,\ D} \mathbf{FO}_{r',p,s,d,i,t,v,o} + + \qquad \forall \{r, p, g_1, g_2\} \in \Theta_{\text{LimitActivityShare}} """ regions = gather_group_regions(M, r) @@ -2859,11 +2946,9 @@ def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): def LimitCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): r""" - The LimitCapacityShare constraint limits the share for a given - technology within a technology groups to which it belongs. - For instance, you might define a tech_group of light-duty vehicles, whose - members are different types for LDVs. This constraint could be used to enforce - that no more than 10% of LDVs must be of a certain type.""" + The LimitCapacityShare constraint limits the available capacity of a given + technology or technology group as a fraction of another technology or group. + """ regions = gather_group_regions(M, r) @@ -2892,11 +2977,9 @@ def LimitCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): def LimitNewCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): r""" - The LimitCapacityShare constraint limits the share for a given - technology within a technology groups to which it belongs. - For instance, you might define a tech_group of light-duty vehicles, whose - members are different types for LDVs. This constraint could be used to enforce - that no more than 10% of LDV purchases in a given year must be of a certain type.""" + The LimitNewCapacityShare constraint limits the share of new capacity + of a given technology or group as a fraction of another technology or + group.""" regions = gather_group_regions(M, r) @@ -2930,12 +3013,18 @@ def LimitAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o, op): 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: LimitAnnualCapacityFactor - \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMACF_{r, p, t} * \textbf{CAPAVL}_{r, p, t} * \text{C2A}_{r, t} - \forall \{r, p, t, o\} \in \Theta_{\text{LimitAnnualCapacityFactor}} - \sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \ge LIMACF_{r, p, t} * \textbf{CAPAVL}_{r, p, t} * \text{C2A}_{r, t} - \forall \{r, p, t, o \in T^{a}\} \in \Theta_{\text{LimitAnnualCapacityFactor}}""" + :label: LimitAnnualCapacityFactor + + \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMACF_{r, p, t} * \textbf{CAPAVL}_{r, p, t} * \text{C2A}_{r, t} + + \forall \{r, p, t \notin T^{a}, o\} \in \Theta_{\text{LimitAnnualCapacityFactor}} + + \\\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \ge LIMACF_{r, p, t} * \textbf{CAPAVL}_{r, p, t} * \text{C2A}_{r, t} + + \forall \{r, p, t \in T^{a}, o\} \in \Theta_{\text{LimitAnnualCapacityFactor}} + """ # r can be an individual region (r='US'), or a combination of regions separated by plus (r='Mexico+US+Canada'), or 'global'. # if r == 'global', the constraint is system-wide regions = gather_group_regions(M, r) @@ -2985,12 +3074,18 @@ def LimitSeasonalCapacityFactor_Constraint(M: 'TemoaModel', r, p, s, t, op): 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: LimitSeasonalCapacityFactor - \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMACF_{r, p, t} * \textbf{CAPAVL}_{r, p, t} * \text{C2A}_{r, t} - \forall \{r, p, t, o\} \in \Theta_{\text{LimitSeasonalCapacityFactor}} - \sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \ge LIMACF_{r, p, t} * \textbf{CAPAVL}_{r, p, t} * \text{C2A}_{r, t} - \forall \{r, p, t, o \in T^{a}\} \in \Theta_{\text{LimitSeasonalCapacityFactor}}""" + :label: Limit Seasonal Capacity Factor + + \sum_{D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMSCF_{r, p, s, t} * \textbf{CAPAVL}_{r, p, t} * \text{C2A}_{r, t} + + \forall \{r, p, t \notin T^{a}, o\} \in \Theta_{\text{LimitSeasonalCapacityFactor}} + + \\\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \cdot \sum_{D} SEG_{s,d} \le LIMSCF_{r, p, s, t} * \textbf{CAPAVL}_{r, p, t} * \text{C2A}_{r, t} + + \forall \{r, p, t \in T^{a}, o\} \in \Theta_{\text{LimitSeasonalCapacityFactor}} + """ # r can be an individual region (r='US'), or a combination of regions separated by plus (r='Mexico+US+Canada'), or 'global'. # if r == 'global', the constraint is system-wide regions = gather_group_regions(M, r) @@ -3062,7 +3157,7 @@ def LimitTechInputSplitAnnual_Constraint(M: 'TemoaModel', r, p, i, t, v, op): producing a single output. These shares can vary by model time period. See LimitTechOutputSplitAnnual_Constraint for an analogous explanation. Under this function, only the technologies with constant annual output (i.e., members - of the :math:`tech_annual` set) are considered.""" + of the :code:`tech_annual` set) are considered.""" inp = sum( M.V_FlowOutAnnual[r, p, i, t, v, S_o] / value(M.Efficiency[r, i, t, v, S_o]) for S_o in M.processOutputsByInput[r, p, t, v, i] @@ -3160,18 +3255,16 @@ def LimitTechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o, op): r""" This constraint operates similarly to LimitTechOutputSplit_Constraint. However, under this function, only the technologies with constant annual - output (i.e., members of the :math:`tech_annual` set) are considered. + output (i.e., members of the :code:`tech_annual` set) are considered. .. math:: :label: LimitTechOutputSplitAnnual - \sum_{I, T^{a}} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} - - \geq - - TOS_{r, p, t, o} \cdot \sum_{I, O, T^{a}} \textbf{FOA}_{r, p, s, d, i, t \in T^{a}, v, o} + \sum_{I, T^{a}} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} + \geq + TOS_{r, p, t, o} \cdot \sum_{I, O, T^{a}} \textbf{FOA}_{r, p, s, d, i, t \in T^{a}, v, o} - \forall \{r, p, t \in T^{a}, v, o\} \in \Theta_{\text{LimitTechOutputSplitAnnual}}""" + \forall \{r, p, t \in T^{a}, v, o\} \in \Theta_{\text{LimitTechOutputSplitAnnual}}""" out = sum( M.V_FlowOutAnnual[r, p, S_i, t, v, o] for S_i in M.processInputsByOutput[r, p, t, v, o] From 677e1b7706ee3e02bbf2a34515c9a7969afcdf0d Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 24 Jun 2025 16:35:08 -0400 Subject: [PATCH 156/587] Improve robustness of v3.1 migrator --- temoa/utilities/db_migration_v3_to_v3_1.py | 42 +++++++++++++++++----- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/temoa/utilities/db_migration_v3_to_v3_1.py b/temoa/utilities/db_migration_v3_to_v3_1.py index 78eb628ba..c2897fb12 100644 --- a/temoa/utilities/db_migration_v3_to_v3_1.py +++ b/temoa/utilities/db_migration_v3_to_v3_1.py @@ -268,38 +268,64 @@ def column_check(old_name: str, new_name: str) -> bool: print('TABLE NOT FOUND: ' + old_name) continue - columns = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall() if c[1] != 'period'] - data = con_old.execute(f'SELECT {str(columns)[1:-1].replace("'","")} FROM {old_name}').fetchall() + old_columns = [c[1] for c in con_old.execute(f'PRAGMA table_info({old_name});').fetchall()] + new_columns = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] + cols = [c for c in new_columns if c in old_columns] + data = con_old.execute(f'SELECT {str(cols)[1:-1].replace("'","")} FROM {old_name}').fetchall() if not data: print('No data for: ' + old_name) continue - if 'vintage' in columns: - r = columns.index('region') - t = columns.index('tech') - v = columns.index('vintage') + if 'vintage' in cols: + r = cols.index('region') + t = cols.index('tech') + v = cols.index('vintage') + elif 'tech' in cols: + r = cols.index('region') + t = cols.index('tech') data_new = [] for p in time_optimize: for row in data: # Remove infeasible rows - if 'vintage' in columns: + if 'vintage' in cols: if row[v] > p: continue # v <= p if (row[r], row[t], row[v]) in lifetime_process: life = lifetime_process[row[r], row[t], row[v]] elif (row[r], row[t]) in lifetime_tech: life = lifetime_tech[row[r], row[t]] else: life = TemoaModel.default_lifetime_tech if row[v] + life <= p: continue # v+l > p + elif 'tech' in cols: + vints = [v[0] for v in con_old.execute(f'SELECT vintage FROM Efficiency WHERE tech == "{row[t]}"').fetchall()] + good = False + for v in vints: + # Can any of these vintages make p good? + if v > p: continue # Nope, need v <= p + if (row[r], row[t], v) in lifetime_process: life = lifetime_process[row[r], row[t], v] + elif (row[r], row[t]) in lifetime_tech: life = lifetime_tech[row[r], row[t]] + else: life = TemoaModel.default_lifetime_tech + if v + life <= p: continue # Nope, need v+l > p + good = True + if not good: continue if old_name[0:5] == 'TimeS': # horrible but covers TimeSeason and TimeSegmentFraction data_new.append((p, *row)) else: data_new.append((row[0], p, *row[1::])) + if old_name[0:5] == 'TimeS': # horrible but covers TimeSeason and TimeSegmentFraction + cols = ['period',*cols] + else: + cols = [cols[0],'period',*cols[1::]] + # construct the query with correct number of placeholders num_placeholders = len(data_new[0]) placeholders = ','.join(['?' for _ in range(num_placeholders)]) - query = f'INSERT OR REPLACE INTO {new_name} VALUES ({placeholders})' + query = ( + 'INSERT OR REPLACE INTO ' + f'{new_name}{tuple(c for c in cols) if len(cols)>1 else f'({cols[0]})'} ' + f'VALUES ({placeholders})' + ) con_new.executemany(query, data_new) print(f'Transfered {len(data)} rows from {old_name} to {new_name}') From 535c1f0f67e1c1907e411844d492e1dda0763a84 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 24 Jun 2025 16:45:46 -0400 Subject: [PATCH 157/587] Fill SeasonLabel table in databases --- data_files/example_dbs/materials.sql | 4 ++++ data_files/example_dbs/morris_utopia.sql | 3 +++ data_files/example_dbs/seasonal_storage.sql | 16 ++++++++++++++++ data_files/example_dbs/stepped_demand.sql | 3 +++ data_files/example_dbs/survival_curve.sql | 3 ++- data_files/example_dbs/test_system.sql | 4 ++++ data_files/example_dbs/utopia.sql | 3 +++ tests/testing_data/emissions.sql | 1 + tests/testing_data/materials.sql | 4 ++++ tests/testing_data/mediumville.sql | 2 ++ tests/testing_data/seasonal_storage.sql | 16 ++++++++++++++++ tests/testing_data/simple_linked_tech.sql | 2 ++ tests/testing_data/storageville.sql | 2 ++ tests/testing_data/survival_curve.sql | 1 + tests/testing_data/test_system.sql | 4 ++++ tests/testing_data/utopia.sql | 3 +++ 16 files changed, 70 insertions(+), 1 deletion(-) diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index cc53c7b55..2de7189c4 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -38,6 +38,10 @@ CREATE TABLE SeasonLabel season TEXT PRIMARY KEY, notes TEXT ); +INSERT INTO SeasonLabel VALUES('summer',NULL); +INSERT INTO SeasonLabel VALUES('autumn',NULL); +INSERT INTO SeasonLabel VALUES('winter',NULL); +INSERT INTO SeasonLabel VALUES('spring',NULL); CREATE TABLE SectorLabel ( sector TEXT PRIMARY KEY, diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index 918ad8255..5d09eb949 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -39,6 +39,9 @@ CREATE TABLE SeasonLabel season TEXT PRIMARY KEY, notes TEXT ); +INSERT INTO SeasonLabel VALUES('inter',NULL); +INSERT INTO SeasonLabel VALUES('summer',NULL); +INSERT INTO SeasonLabel VALUES('winter',NULL); CREATE TABLE SectorLabel ( sector TEXT PRIMARY KEY, diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql index c3f522121..644cb9359 100644 --- a/data_files/example_dbs/seasonal_storage.sql +++ b/data_files/example_dbs/seasonal_storage.sql @@ -38,6 +38,22 @@ CREATE TABLE SeasonLabel season TEXT PRIMARY KEY, notes TEXT ); +INSERT INTO SeasonLabel VALUES('charge','non-sequential season - charging day'); +INSERT INTO SeasonLabel VALUES('discharge','non-sequential season - discharging day'); +INSERT INTO SeasonLabel VALUES('summer','sequential season - summer day'); +INSERT INTO SeasonLabel VALUES('sept_w1','sequential season - day in first week of September'); +INSERT INTO SeasonLabel VALUES('sept_w2','sequential season - day in second week of September'); +INSERT INTO SeasonLabel VALUES('sept_w3','sequential season - day in third week of September'); +INSERT INTO SeasonLabel VALUES('sept_w4','sequential season - day in fourth week of September'); +INSERT INTO SeasonLabel VALUES('sept_29th','sequential season - 29th of September'); +INSERT INTO SeasonLabel VALUES('sept_30th','sequential season - 30th of September'); +INSERT INTO SeasonLabel VALUES('winter','sequential season - winter day'); +INSERT INTO SeasonLabel VALUES('apr_w1','sequential season - day in first week of September'); +INSERT INTO SeasonLabel VALUES('apr_w2','sequential season - day in second week of September'); +INSERT INTO SeasonLabel VALUES('apr_w3','sequential season - day in third week of September'); +INSERT INTO SeasonLabel VALUES('apr_w4','sequential season - day in fourth week of September'); +INSERT INTO SeasonLabel VALUES('apr_29th','sequential season - 29th of April'); +INSERT INTO SeasonLabel VALUES('apr_30th','sequential season - 30th of April'); CREATE TABLE SectorLabel ( sector TEXT PRIMARY KEY, diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index 6f17b146e..e6689a95a 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -38,6 +38,9 @@ CREATE TABLE SeasonLabel season TEXT PRIMARY KEY, notes TEXT ); +INSERT INTO SeasonLabel VALUES('inter',NULL); +INSERT INTO SeasonLabel VALUES('summer',NULL); +INSERT INTO SeasonLabel VALUES('winter',NULL); CREATE TABLE SectorLabel ( sector TEXT PRIMARY KEY, diff --git a/data_files/example_dbs/survival_curve.sql b/data_files/example_dbs/survival_curve.sql index 6213f0ddd..e67cdfb67 100644 --- a/data_files/example_dbs/survival_curve.sql +++ b/data_files/example_dbs/survival_curve.sql @@ -8,7 +8,7 @@ CREATE TABLE MetaData PRIMARY KEY (element) ); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); INSERT INTO MetaData VALUES('days_per_period',365,'count of days in each period'); CREATE TABLE MetaDataReal ( @@ -38,6 +38,7 @@ CREATE TABLE SeasonLabel season TEXT PRIMARY KEY, notes TEXT ); +INSERT INTO SeasonLabel VALUES('s',NULL); CREATE TABLE SectorLabel ( sector TEXT PRIMARY KEY, diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index a82e2a244..52d4d4fc3 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -38,6 +38,10 @@ CREATE TABLE SeasonLabel season TEXT PRIMARY KEY, notes TEXT ); +INSERT INTO SeasonLabel VALUES('summer',NULL); +INSERT INTO SeasonLabel VALUES('fall',NULL); +INSERT INTO SeasonLabel VALUES('winter',NULL); +INSERT INTO SeasonLabel VALUES('spring',NULL); CREATE TABLE SectorLabel ( sector TEXT PRIMARY KEY, diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 3771366f4..78869facb 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -38,6 +38,9 @@ CREATE TABLE SeasonLabel season TEXT PRIMARY KEY, notes TEXT ); +INSERT INTO SeasonLabel VALUES('inter',NULL); +INSERT INTO SeasonLabel VALUES('summer',NULL); +INSERT INTO SeasonLabel VALUES('winter',NULL); CREATE TABLE SectorLabel ( sector TEXT PRIMARY KEY, diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 48f529152..cb23bfd75 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -38,6 +38,7 @@ CREATE TABLE SeasonLabel season TEXT PRIMARY KEY, notes TEXT ); +INSERT INTO SeasonLabel VALUES('S1',NULL); CREATE TABLE SectorLabel ( sector TEXT PRIMARY KEY, diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index cc53c7b55..2de7189c4 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -38,6 +38,10 @@ CREATE TABLE SeasonLabel season TEXT PRIMARY KEY, notes TEXT ); +INSERT INTO SeasonLabel VALUES('summer',NULL); +INSERT INTO SeasonLabel VALUES('autumn',NULL); +INSERT INTO SeasonLabel VALUES('winter',NULL); +INSERT INTO SeasonLabel VALUES('spring',NULL); CREATE TABLE SectorLabel ( sector TEXT PRIMARY KEY, diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 9fc711e66..78f69ff70 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -38,6 +38,8 @@ CREATE TABLE SeasonLabel season TEXT PRIMARY KEY, notes TEXT ); +INSERT INTO SeasonLabel VALUES('s1',NULL); +INSERT INTO SeasonLabel VALUES('s2',NULL); CREATE TABLE SectorLabel ( sector TEXT PRIMARY KEY, diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index c3f522121..644cb9359 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -38,6 +38,22 @@ CREATE TABLE SeasonLabel season TEXT PRIMARY KEY, notes TEXT ); +INSERT INTO SeasonLabel VALUES('charge','non-sequential season - charging day'); +INSERT INTO SeasonLabel VALUES('discharge','non-sequential season - discharging day'); +INSERT INTO SeasonLabel VALUES('summer','sequential season - summer day'); +INSERT INTO SeasonLabel VALUES('sept_w1','sequential season - day in first week of September'); +INSERT INTO SeasonLabel VALUES('sept_w2','sequential season - day in second week of September'); +INSERT INTO SeasonLabel VALUES('sept_w3','sequential season - day in third week of September'); +INSERT INTO SeasonLabel VALUES('sept_w4','sequential season - day in fourth week of September'); +INSERT INTO SeasonLabel VALUES('sept_29th','sequential season - 29th of September'); +INSERT INTO SeasonLabel VALUES('sept_30th','sequential season - 30th of September'); +INSERT INTO SeasonLabel VALUES('winter','sequential season - winter day'); +INSERT INTO SeasonLabel VALUES('apr_w1','sequential season - day in first week of September'); +INSERT INTO SeasonLabel VALUES('apr_w2','sequential season - day in second week of September'); +INSERT INTO SeasonLabel VALUES('apr_w3','sequential season - day in third week of September'); +INSERT INTO SeasonLabel VALUES('apr_w4','sequential season - day in fourth week of September'); +INSERT INTO SeasonLabel VALUES('apr_29th','sequential season - 29th of April'); +INSERT INTO SeasonLabel VALUES('apr_30th','sequential season - 30th of April'); CREATE TABLE SectorLabel ( sector TEXT PRIMARY KEY, diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index 8441da994..6beca00a1 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -38,6 +38,8 @@ CREATE TABLE SeasonLabel season TEXT PRIMARY KEY, notes TEXT ); +INSERT INTO SeasonLabel VALUES('summer',NULL); +INSERT INTO SeasonLabel VALUES('winter',NULL); CREATE TABLE SectorLabel ( sector TEXT PRIMARY KEY, diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index 1848c1f1d..18692c467 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -38,6 +38,8 @@ CREATE TABLE SeasonLabel season TEXT PRIMARY KEY, notes TEXT ); +INSERT INTO SeasonLabel VALUES('s1',NULL); +INSERT INTO SeasonLabel VALUES('s2',NULL); CREATE TABLE SectorLabel ( sector TEXT PRIMARY KEY, diff --git a/tests/testing_data/survival_curve.sql b/tests/testing_data/survival_curve.sql index ef6dc9f88..e67cdfb67 100644 --- a/tests/testing_data/survival_curve.sql +++ b/tests/testing_data/survival_curve.sql @@ -38,6 +38,7 @@ CREATE TABLE SeasonLabel season TEXT PRIMARY KEY, notes TEXT ); +INSERT INTO SeasonLabel VALUES('s',NULL); CREATE TABLE SectorLabel ( sector TEXT PRIMARY KEY, diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index a82e2a244..52d4d4fc3 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -38,6 +38,10 @@ CREATE TABLE SeasonLabel season TEXT PRIMARY KEY, notes TEXT ); +INSERT INTO SeasonLabel VALUES('summer',NULL); +INSERT INTO SeasonLabel VALUES('fall',NULL); +INSERT INTO SeasonLabel VALUES('winter',NULL); +INSERT INTO SeasonLabel VALUES('spring',NULL); CREATE TABLE SectorLabel ( sector TEXT PRIMARY KEY, diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 3771366f4..78869facb 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -38,6 +38,9 @@ CREATE TABLE SeasonLabel season TEXT PRIMARY KEY, notes TEXT ); +INSERT INTO SeasonLabel VALUES('inter',NULL); +INSERT INTO SeasonLabel VALUES('summer',NULL); +INSERT INTO SeasonLabel VALUES('winter',NULL); CREATE TABLE SectorLabel ( sector TEXT PRIMARY KEY, From 4ff443d2728599dd11895f3963eb5ed346b58ab1 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 24 Jun 2025 16:47:41 -0400 Subject: [PATCH 158/587] Rename to MyopicDiscountingYear --- temoa/temoa_model/hybrid_loader.py | 4 ++-- temoa/temoa_model/table_writer.py | 4 ++-- temoa/temoa_model/temoa_model.py | 2 +- temoa/temoa_model/temoa_rules.py | 4 ++-- temoa/utilities/unit_cost_explorer.py | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index a80637962..484e311b5 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -431,7 +431,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N "SELECT min(period) FROM TimePeriod WHERE flag == 'f'" ).fetchone() # load as a singleton... - data[M.MyopicDiscountingP0.name] = {None: int(p0[0])} + data[M.MyopicDiscountingYear.name] = {None: int(p0[0])} # days_per_season raw = cur.execute( @@ -922,7 +922,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # LimitAnnualCapacityFactor if self.table_exists('LimitAnnualCapacityFactor'): raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, output_comm, operator, factor FROM main.LimitAnnualCapacityFactor') - load_element(M.LimitAnnualCapacityFactor, raw, self.viable_rt, (0, 2)) + load_element(M.LimitAnnualCapacityFactor, raw, self.viable_rpto, (0, 1, 2, 3)) # LimitGrowthCapacity if self.table_exists('LimitGrowthCapacity'): diff --git a/temoa/temoa_model/table_writer.py b/temoa/temoa_model/table_writer.py index 8c4685f14..d94fb330c 100644 --- a/temoa/temoa_model/table_writer.py +++ b/temoa/temoa_model/table_writer.py @@ -127,7 +127,7 @@ def write_results( self.write_capacity_tables(M, iteration=iteration) # analyze the emissions to get the costs and flows if self.config.scenario_mode == TemoaMode.MYOPIC: - p_0 = M.MyopicDiscountingP0 + p_0 = M.MyopicDiscountingYear else: p_0 = None # min year will be used in poll e_costs, e_flows = poll_emissions(M=M, p_0=p_0) @@ -498,7 +498,7 @@ def write_costs(self, M: TemoaModel, emission_entries=None, iteration=None): # P_0 is usually the first optimization year, but if running myopic, we could assign it via # table entry. Perhaps in future it is just always the first optimization year of the 1st iter. if self.config.scenario_mode == TemoaMode.MYOPIC: - p_0 = M.MyopicDiscountingP0 + p_0 = M.MyopicDiscountingYear else: p_0 = min(M.time_optimize) diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index d06ddabc1..315b4b755 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -522,7 +522,7 @@ def __init__(M, *args, **kwargs): M.EmissionEmbodied = Param(M.regions, M.commodity_emissions, M.tech_with_capacity, M.vintage_optimize) M.EmissionEndOfLife = Param(M.regions, M.commodity_emissions, M.tech_with_capacity, M.vintage_all) - M.MyopicDiscountingP0 = Param(default=0) + M.MyopicDiscountingYear = Param(default=0) ################################################ # Model Variables # diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 0397dcd89..2e7353c60 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -624,8 +624,8 @@ def PeriodCost_rule(M: 'TemoaModel', p): GDR = value(M.GlobalDiscountRate) MPL = M.ModelProcessLife - if value(M.MyopicDiscountingP0) != 0: - P_0 = value(M.MyopicDiscountingP0) + if value(M.MyopicDiscountingYear) != 0: + P_0 = value(M.MyopicDiscountingYear) loan_costs = sum( loan_cost( diff --git a/temoa/utilities/unit_cost_explorer.py b/temoa/utilities/unit_cost_explorer.py index 05ec057b7..4cf40786a 100644 --- a/temoa/utilities/unit_cost_explorer.py +++ b/temoa/utilities/unit_cost_explorer.py @@ -38,7 +38,7 @@ M.LoanRate_rtv.construct(data=rtv) M.LifetimeProcess_rtv.construct(data=rtv) M.regionalIndices.construct(data=['A']) -M.MyopicDiscountingP0.construct(data={None: 0}) +M.MyopicDiscountingYear.construct(data={None: 0}) M.ModelProcessLife_rptv.construct(data=rptv) From 0bdcad138e6e577d0dabaf176eb2f74b22071bd0 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 24 Jun 2025 17:07:05 -0400 Subject: [PATCH 159/587] More progress on documentation --- docs/source/Documentation.rst | 21 ++--- temoa/temoa_model/temoa_rules.py | 155 ++++++++++++++++--------------- 2 files changed, 87 insertions(+), 89 deletions(-) diff --git a/docs/source/Documentation.rst b/docs/source/Documentation.rst index 9308d2f56..d8633a7a4 100644 --- a/docs/source/Documentation.rst +++ b/docs/source/Documentation.rst @@ -951,28 +951,23 @@ Parameters ":math:`\text{DSD}_{r,p,s,d,c}`","DemandSpecificDistribution",":math:`\mathbb{I}`","Demand-specific distribution" ":math:`\text{EFF}_{r,i,t,v,o}`","Efficiency",":math:`\mathbb{R}^+_0`","Tech- and commodity-specific efficiency" ":math:`\text{EAC}_{r,i,t,v,o,e}`","EmissionActivity",":math:`\mathbb{R}`","Tech-specific emissions rate" - ":math:`\text{ELM}_{r,p,e}`","EmissionLimit",":math:`\mathbb{R}^+_0`","Emissions limit by region and period" ":math:`\text{ECAP}_{r,t,v}`","ExistingCapacity",":math:`\mathbb{R}^+_0`","Pre-existing capacity" ":math:`\text{RCAP}_{r,p,t,v}`","RetiredCapacity",":math:`\mathbb{R}^+_0`","Capacity retired before end of life" + ":math:`\text{ART}_{r,p,t,v}`","AnnualRetirement",":math:`\mathbb{R}^+_0`","Annualised capacity retiring or reaching end of life" ":math:`\text{GDR}`","GlobalDiscountRate",":math:`\mathbb{R}`","Global rate used to calculate present cost" ":math:`\text{GRM}_{r,t}`","GrowthRateMax",":math:`\mathbb{R}`","Global rate used to calculate present cost" ":math:`\text{GRS}_{r,t}`","GrowthRateSeed",":math:`\mathbb{R}`","Global rate used to calculate present cost" ":math:`\text{LTP}_{r,t,v}`","LifetimeProcess",":math:`\mathbb{N}`","Tech- and vintage-specific lifetime (default=LifetimeTech)" ":math:`\text{LTT}_{r,t}`","LifetimeTech",":math:`\mathbb{N}`","Tech-specific lifetime (default=40 years)" - ":math:`\text{LTS}_{r,p,t,v}`","LifetimeSurvivalCurve",":math:`\mathbb{R}^+_0`","Surviving fraction of original capacity" + ":math:`\text{LSC}_{r,p,t,v}`","LifetimeSurvivalCurve",":math:`\mathbb{R}^+_0`","Surviving fraction of original capacity" ":math:`\text{LIT}_{r,t,e,t}`","LinkedTechs","text","Dummy techs used to convert CO2 emissions to physical commodity" ":math:`\text{LLT}_{r,t}`","LoanLifetimeTech",":math:`\mathbb{N}`","Tech-specific loan term (default=10 years)" ":math:`\text{LR}_{r,t,v}`","LoanRate",":math:`\mathbb{R}`","Tech-specific interest rate on investment cost" - ":math:`\text{MAA}_{r,p,t}`","MaxActivity",":math:`\mathbb{R}^+_0`","Maximum tech-specific activity by region and period" - ":math:`\text{MAC}_{r,p,t}`","MaxCapacity",":math:`\mathbb{R}^+_0`","Maximum tech-specific capacity by period" - ":math:`\text{MCS}_{t}`","MaxCapacitySum",":math:`\mathbb{R}^+_0`","Maximum capacity for a technology group" - ":math:`\text{MAR}_{r,t}`","MaxResource",":math:`\mathbb{R}^+_0`","Maximum resource production by tech across time periods (currently not supported)" - ":math:`\text{MIA}_{r,p,t}`","MinActivity",":math:`\mathbb{R}^+_0`","Minimum tech-specific activity by region and period" - ":math:`\text{MIC}_{r,p,t}`","MinCapacity",":math:`\mathbb{R}^+_0`","Minimum tech-specific capacity by period" - ":math:`\text{MCS}_{t}`","MinCapacitySum",":math:`\mathbb{R}^+_0`","Minimum capacity for a technology group" - ":math:`\text{MGT}_{r}`","MinGenGroupTarget",":math:`\mathbb{R}^+_0`","Target applied to techs in MinActivityGroup constraint" - ":math:`\text{MGW}_{r,t}`","MinGenGroupWeight",":math:`\mathbb{R}^+_0`","Weight applied to techs in MinActivityGroup constraint" - ":math:`\text{MBY}`","MyopicBaseYear",":math:`\mathbb{N}`","Objective function base year when running myopically" + ":math:`\text{LE}_{r,p,e}`","LimitEmission",":math:`\mathbb{R}^+_0`","Emissions limit by region and period" + ":math:`\text{LA}_{r,p,t}`","LimitActivity",":math:`\mathbb{R}^+_0`","Limit tech-specific activity by region and period" + ":math:`\text{LC}_{r,p,t}`","LimitCapacity",":math:`\mathbb{R}^+_0`","Limit tech-specific capacity by period" + ":math:`\text{LR}_{r,t}`","LimitResource",":math:`\mathbb{R}^+_0`","Limit resource production by tech across time periods" + ":math:`\text{MDP}`","MyopicDiscountingPeriod",":math:`\mathbb{N}`","Objective function NPV year when running myopically" ":math:`\text{PRM}_{r}`","PlanningReserveMargin",":math:`\mathbb{I}`","Margin used to ensure sufficient generating capacity" ":math:`\text{RMD}_{r,t}`","RampDown",":math:`\mathbb{R}`","Rate at which generation techs can ramp output down" ":math:`\text{RMU}_{r,t}`","RampUp",":math:`\mathbb{R}`","Rate at which generation techs can ramp output up" @@ -1881,6 +1876,8 @@ capacity and allowable commodity flow. .. autofunction:: temoa_rules.AdjustedCapacity_Constraint +.. autofunction:: temoa_rules.AnnualRetirement_Constraint + .. autofunction:: temoa_rules.CapacityAvailableByPeriodAndTech_Constraint diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 2e7353c60..c69293d22 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -46,41 +46,42 @@ def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): r""" - This constraint updates the capacity of a process by taking into account retirements. - For a given :code:`(r,p,t,v)` index, this constraint sets the capacity equal to - the amount installed in period :code:`v` and subtracts from it any and all retirements + This constraint updates the capacity of a process by taking into account retirements + and end of life. For a given :code:`(r,p,t,v)` index, this constraint sets the capacity + equal to the amount installed in period :code:`v` and subtracts from it any and all retirements that occurred up until the period in question, :code:`p`, and end of life from the survival curve if defined. It finally adjusts for the process life fraction, which - accounts for a possible mid-period end of life. + accounts for a possible mid-period end of life where, for example, EOL 3 years into a 5-year + period would be treated as :math:`\frac{3}{5}` capacity for all 5 years. .. math:: :label: Adjusted Capacity - \text{CAP}_{r,p,t,v} = + \textbf{CAP}_{r,p,t,v} = \begin{cases} - \text{ECAP}_{r,t,v} \cdot \text{LTS}_{r,p,t,v} \cdot \text{PLF}_{r,p,t,v} + \text{ECAP}_{r,t,v} \cdot \text{LSC}_{r,p,t,v} \cdot \text{PLF}_{r,p,t,v} & \text{if } t \notin T^\text{ret},\ v \in T^\text{e} \\ - \text{NCAP}_{r,t,v} \cdot \text{LTS}_{r,p,t,v} \cdot \text{PLF}_{r,p,t,v} + \textbf{NCAP}_{r,t,v} \cdot \text{LSC}_{r,p,t,v} \cdot \text{PLF}_{r,p,t,v} & \text{if } t \notin T^\text{ret},\ v \notin T^\text{e} \\ - \left( \text{ECAP}_{r,t,v} \cdot \text{LTS}_{r,p,t,v} + \left( \text{ECAP}_{r,t,v} \cdot \text{LSC}_{r,p,t,v} - \sum\limits_{p^* = v}^{p} - \text{RCAP}_{r,p^*,t,v} \right) \cdot \text{PLF}_{r,p,t,v} + \textbf{RCAP}_{r,p^*,t,v} \right) \cdot \text{PLF}_{r,p,t,v} & \text{if } t \in T^\text{ret},\ v \in T^\text{e} \\ - \left( \text{NCAP}_{r,t,v} \cdot \text{LTS}_{r,p,t,v} + \left( \textbf{NCAP}_{r,t,v} \cdot \text{LSC}_{r,p,t,v} - \sum\limits_{p^* = v}^{p} - \text{RCAP}_{r,p^*,t,v} \right) \cdot \text{PLF}_{r,p,t,v} + \textbf{RCAP}_{r,p^*,t,v} \right) \cdot \text{PLF}_{r,p,t,v} & \text{if } t \in T^\text{ret},\ v \notin T^\text{e} \end{cases} """ PLF = value(M.ProcessLifeFrac[r, p, t, v]) - LTS = value(M.LifetimeSurvivalCurve[r, p, t, v]) + LSC = value(M.LifetimeSurvivalCurve[r, p, t, v]) if t not in M.tech_retirement: if v in M.time_exist: - return M.V_Capacity[r, p, t, v] == value(M.ExistingCapacity[r, t, v]) * LTS * PLF + return M.V_Capacity[r, p, t, v] == value(M.ExistingCapacity[r, t, v]) * LSC * PLF else: - return M.V_Capacity[r, p, t, v] == M.V_NewCapacity[r, t, v] * LTS * PLF + return M.V_Capacity[r, p, t, v] == M.V_NewCapacity[r, t, v] * LSC * PLF else: retired_cap = sum( @@ -89,9 +90,9 @@ def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): if v < S_p <= p and S_p < v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[S_p]) ) if v in M.time_exist: - return M.V_Capacity[r, p, t, v] == (value(M.ExistingCapacity[r, t, v]) * LTS - retired_cap) * PLF + return M.V_Capacity[r, p, t, v] == (value(M.ExistingCapacity[r, t, v]) * LSC - retired_cap) * PLF else: - return M.V_Capacity[r, p, t, v] == (M.V_NewCapacity[r, t, v] * LTS - retired_cap) * PLF + return M.V_Capacity[r, p, t, v] == (M.V_NewCapacity[r, t, v] * LSC - retired_cap) * PLF def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): @@ -158,32 +159,26 @@ def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): def CapacityAnnual_Constraint(M: 'TemoaModel', r, p, t, v): r""" -Similar to Capacity_Constraint, but for technologies belonging to the -:code:`tech_annual` set. Technologies in the tech_annual set have constant output -across different timeslices within a year, so we do not need to ensure -that installed capacity is sufficient across all timeslices, thus saving -some computational effort. Instead, annual output is sufficient to calculate -capacity. - -.. math:: - :label: CapacityAnnual - - \left ( - \text{CFP}_{r, t, v} - \cdot \text{C2A}_{r, t} - \cdot \text{PLF}_{r, p, t, v} - \right ) - \cdot \textbf{CAP}_{r, t, v} - = - \sum_{I, O} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} - - \\ - \forall \{r, p, t \in T^{a}, v\} \in \Theta_{\text{Activity}} + Similar to Capacity_Constraint, but for technologies belonging to the + :code:`tech_annual` set. Technologies in the tech_annual set have constant output + across different timeslices within a year, so we do not need to ensure + that installed capacity is sufficient across all timeslices, thus saving + some computational effort. Instead, annual output is sufficient to calculate + capacity. Hourly capacity factors cannot be defined to annual technologies + but annual capacity factors can be set using LimitAnnualCapacityFactor, + which will be implicitly accounted for here. + .. math:: + :label: CapacityAnnual -""" - CF = 1 # placeholder CF + \text{C2A}_{r, t} + \cdot \textbf{CAP}_{r, t, v} + = + \sum_{I, O} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} + \\ + \forall \{r, p, t \in T^{a}, v\} \in \Theta_{\text{Activity}} + """ activity_rptv = sum( M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] @@ -191,8 +186,7 @@ def CapacityAnnual_Constraint(M: 'TemoaModel', r, p, t, v): ) return ( - CF - * value(M.CapacityToActivity[r, t]) + value(M.CapacityToActivity[r, t]) * M.V_Capacity[r, p, t, v] >= activity_rptv ) @@ -241,26 +235,17 @@ def CapacityAnnual_Constraint(M: 'TemoaModel', r, p, t, v): def CapacityAvailableByPeriodAndTech_Constraint(M: 'TemoaModel', r, p, t): r""" -The :math:`\textbf{CAPAVL}` variable is nominally for reporting solution values, -but is also used in the Limit constraint calculations. For any process -with an end-of-life (EOL) on a period boundary, all of its capacity is available -for use in all periods in which it is active (the process' PLF is 1). However, -for any process with an EOL that falls between periods, Temoa makes the -simplifying assumption that the available capacity from the expiring technology -is available through the whole period in proportion to its remaining lifetime. -For example, if a process expires 3 years into an 8-year model time period, -then only :math:`\frac{3}{8}` of the installed capacity is available for use -throughout the period. - -.. math:: - :label: CapacityAvailable - - \textbf{CAPAVL}_{r, p, t} = \sum_{v, p_i \leq p} {PLF}_{r, p, t, v} \cdot \left - ( \textbf{CAP}_{r, t, v} - \textbf{CAPRET}_{r, p_i, t, v} \right ) - - \\ - \forall p \in \text{P}^o, r \in R, t \in T -""" + The :math:`\textbf{CAPAVL}` variable is nominally for reporting solution values, + but is also used in the Limit constraint calculations. + + .. math:: + :label: CapacityAvailable + + \textbf{CAPAVL}_{r, p, t} = \sum_{v, p_i \leq p} \textbf{CAP}_{r, p, t, v} + + \\ + \forall p \in \text{P}^o, r \in R, t \in T + """ cap_avail = sum( M.V_Capacity[r, p, t, S_v] for S_v in M.processVintages[r, p, t] @@ -299,10 +284,26 @@ def CapacityAvailableByPeriodAndTech_Constraint(M: 'TemoaModel', r, p, t): def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): r""" Get the annualised retirement rate for a process in a given period. - Used to output retirement and model end of life flows and emissions. - Assumes that retirement is evenly distributed over the model period, - in the same way we assume capacity is deployed evenly over the model - period. + Used to output retirement (including end of life, EOL) and model end of + life flows and emissions. Assumes that retirement is evenly distributed over + the model period in which that retirement occurs, in the same way we assume + capacity is deployed evenly over the model period. Note that + :math:`\textbf{CAP}_{r,p,t,v}` already accounts for retirement, survival + curves, and process life fraction via the AdjustedCapacity constraint. + + .. math:: + :label: Annual Retirement + + ART_{r,p,t,v} = + \frac{1}{PL_{p}} \cdot + \begin{cases} + \textbf{ECAP}_{r,t,v} \cdot LSC_{r,p,t,v}^{\text{final}}, & \text{if } p = P_0,\ v \in T^{\text{exist}}, \text{ and EOL} \\ + \textbf{NCAP}_{r,t,v}, & \text{if } p = v, \text{ and EOL} \\ + \textbf{CAP}_{r,p{-}1,t,v}, & \text{if } v < p < v + LT_{r,t,v}, \text{ and EOL} \\ + \textbf{ECAP}_{r,t,v} \cdot LSC_{r,p,t,v}^{\text{final}} - \textbf{CAP}_{r,p,t,v}, & \text{if } p = P_0,\ v \in T^{\text{exist}} \text{, and not EOL} \\ + \textbf{NCAP}_{r,t,v} - \textbf{CAP}_{r,p,t,v}, & \text{if } p = v \text{, and not EOL} \\ + \textbf{CAP}_{r,p{-}1,t,v} - \textbf{CAP}_{r,p,t,v}, & \text{if not EOL otherwise} + \end{cases} """ if p <= v + value(M.LifetimeProcess[r, t, v]) < p + value(M.PeriodLength[p]): @@ -1387,7 +1388,7 @@ def RegionalExchangeCapacity_Constraint(M: 'TemoaModel', r_e, r_i, p, t, v): def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): - """ + r""" This constraint enforces the continuity of storage level between time slices. storage level in the next time slice (:math:`s_{next}, d_{next}`) is equal to current storage level plus net charge in the current time slice. @@ -2482,7 +2483,7 @@ def LimitGrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False) if any can be found. .. math:: - :label: Limit (De)Growth Capacity + :label: Limit (De)Growth New Capacity \begin{aligned}\text{Growth:}\\ &\mathbf{NCAP}_{r,t,v} @@ -2592,7 +2593,7 @@ def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = F if any can be found. .. math:: - :label: Limit (De)Growth Capacity + :label: Limit (De)Growth New Capacity Delta \begin{aligned}\text{Growth:}\\ &\mathbf{NCAP}_{r,t,v_i} - \mathbf{NCAP}_{r,t,v_{i-1}} @@ -2872,16 +2873,16 @@ def LimitResource_Constraint(M: 'TemoaModel', r, t, op): def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): r""" - The LimitActivityShare constraint limits the activity of a given - technology or group as a fraction of another technology or group. This - can be used to set, for example, a renewable portfolio scheme constraint. + Limits the activity of a given technology or group as a fraction of another + technology or group, summed over a period. This can be used to set, for example, + a renewable portfolio scheme constraint. .. math:: :label: Limit Activity Share - \sum_{R' \in R_g,\ T \in g_1,\ V,\ I,\ O,\ S,\ D} \mathbf{FO}_{r',p,s,d,i,t,v,o} + \sum_{R_g \subseteq R,\ S,\ D,\ I,\ T^{g_1} \subseteq T,\ V,\ O} \mathbf{FO}_{r,p,s,d,i,t,v,o} \leq LAS_{r,p,g_1,g_2} \cdot - \sum_{R' \in R_g,\ T \in g_2,\ V,\ I,\ O,\ S,\ D} \mathbf{FO}_{r',p,s,d,i,t,v,o} + \sum_{R_g \subseteq R,\ S,\ D,\ I,\ T^{g_2} \subseteq T,\ V,\ O} \mathbf{FO}_{r,p,s,d,i,t,v,o} \qquad \forall \{r, p, g_1, g_2\} \in \Theta_{\text{LimitActivityShare}} """ @@ -3017,11 +3018,11 @@ def LimitAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o, op): .. math:: :label: LimitAnnualCapacityFactor - \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMACF_{r, p, t} * \textbf{CAPAVL}_{r, p, t} * \text{C2A}_{r, t} + \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMACF_{r, p, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} \forall \{r, p, t \notin T^{a}, o\} \in \Theta_{\text{LimitAnnualCapacityFactor}} - \\\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \ge LIMACF_{r, p, t} * \textbf{CAPAVL}_{r, p, t} * \text{C2A}_{r, t} + \\\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \ge LIMACF_{r, p, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} \forall \{r, p, t \in T^{a}, o\} \in \Theta_{\text{LimitAnnualCapacityFactor}} """ @@ -3078,11 +3079,11 @@ def LimitSeasonalCapacityFactor_Constraint(M: 'TemoaModel', r, p, s, t, op): .. math:: :label: Limit Seasonal Capacity Factor - \sum_{D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMSCF_{r, p, s, t} * \textbf{CAPAVL}_{r, p, t} * \text{C2A}_{r, t} + \sum_{D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMSCF_{r, p, s, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} \forall \{r, p, t \notin T^{a}, o\} \in \Theta_{\text{LimitSeasonalCapacityFactor}} - \\\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \cdot \sum_{D} SEG_{s,d} \le LIMSCF_{r, p, s, t} * \textbf{CAPAVL}_{r, p, t} * \text{C2A}_{r, t} + \\\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \cdot \sum_{D} SEG_{s,d} \le LIMSCF_{r, p, s, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} \forall \{r, p, t \in T^{a}, o\} \in \Theta_{\text{LimitSeasonalCapacityFactor}} """ From 9ad573891188f5ce847c8a3e187c507d6bf97c10 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Jun 2025 14:25:23 -0400 Subject: [PATCH 160/587] Fix foreign key reference v3 schema --- data_files/temoa_schema_v3.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_files/temoa_schema_v3.sql b/data_files/temoa_schema_v3.sql index a85c1e086..3c03e7b80 100644 --- a/data_files/temoa_schema_v3.sql +++ b/data_files/temoa_schema_v3.sql @@ -500,7 +500,7 @@ CREATE TABLE IF NOT EXISTS OutputFlowOut period INTEGER REFERENCES TimePeriod (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES TimeSeason (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT From 7e629e865e67d630808dccb1d2ec6c7f95343d71 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Jun 2025 14:46:40 -0400 Subject: [PATCH 161/587] Assign value of SegFrac to DSD not actual SegFrac param --- temoa/temoa_model/temoa_initialize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index dfc74f68e..5df539981 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -559,7 +559,7 @@ def CreateDemands(M: 'TemoaModel'): cross_product(M.regions, (p,), M.TimeSeason[p], M.time_of_day, unset_demand_distributions) ) for r, p, s, d, dem in unset_distributions: - DSD[r, p, s, d, dem] = M.SegFrac[p, s, d] # DSD._constructed = True + DSD[r, p, s, d, dem] = value(M.SegFrac[p, s, d]) # DSD._constructed = True # Step 5: A final "sum to 1" check for all DSD members (which now should be everything) # Also check that all keys are made... The demand distro should be supported From 98d4714598ad1d9699fd5604161bab2d62cb2c01 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Jun 2025 14:47:36 -0400 Subject: [PATCH 162/587] Update PeriodSeasons to TimeSeason in warning --- temoa/temoa_model/temoa_initialize.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 5df539981..4141bb65e 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -196,9 +196,9 @@ def validate_SegFrac(M: 'TemoaModel'): extra = keys.difference(expected_keys) missing = expected_keys.difference(keys) msg = ( - 'TimeSegmentFraction elements for period {} do not match PeriodSeasons and TimeOfDay.' + 'TimeSegmentFraction elements for period {} do not match TimeSeason and TimeOfDay.' '\n\nIndices missing from TimeSegmentFraction:\n{}' - '\n\nIndices in TimeSegmentFraction missing from PeriodSeasons/TimeOfDay:\n{}' + '\n\nIndices in TimeSegmentFraction missing from TimeSeason/TimeOfDay:\n{}' ).format(p, missing, extra) logger.error(msg) raise ValueError(msg) From 2a433471d54ee306fbffef9c61d19db298f76066 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Jun 2025 14:48:56 -0400 Subject: [PATCH 163/587] Change warnings for allowed missing indices to info --- temoa/temoa_model/temoa_initialize.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 4141bb65e..30753135d 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -348,7 +348,7 @@ def CheckEfficiencyVariable(M: 'TemoaModel'): if count > 0: M.isEfficiencyVariable[r, p, i, t, v, o] = True if count < num_seg: - logger.warning( + logger.info( 'Some but not all EfficiencyVariable values were set (%i out of a possible %i) for: %s' ' Missing values will default to value set in Efficiency table.' , count, num_seg, (r, p, i, t, v, o) @@ -382,7 +382,7 @@ def CheckCapacityFactorProcess(M: 'TemoaModel'): if count > 0: M.isCapacityFactorProcess[r, p, t, v] = True if count < num_seg: - logger.warning( + logger.info( 'Some but not all processes were set in CapacityFactorProcess (%i out of a possible %i) for: %s' ' Missing values will default to CapacityFactorTech value or 1 if that is not set either.' , count, num_seg, (r, p, t, v) From b001c72444c453da9c24ea7e2c0349b5e8bd223c Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Jun 2025 16:22:11 -0400 Subject: [PATCH 164/587] Align fixed costs to PLF assumption --- temoa/temoa_model/temoa_rules.py | 4 ++-- tests/legacy_test_values.py | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index c69293d22..798d5877b 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -663,9 +663,9 @@ def PeriodCost_rule(M: 'TemoaModel', p): fixed_costs = sum( fixed_or_variable_cost( - M.V_Capacity[r, p, S_t, S_v] / value(M.ProcessLifeFrac[r, p, S_t, S_v]), + M.V_Capacity[r, p, S_t, S_v], value(M.CostFixed[r, p, S_t, S_v]), - value(MPL[r, p, S_t, S_v]), + value(M.PeriodLength[p]), GDR, P_0, p=p, diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index e583f12b5..185a329cb 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -56,7 +56,8 @@ class ExpectedVals(Enum): # reduced after reworking storageinit -> storage was less constrained # reduced after removing ancient 1-year-shift obj function bug # increased after rework of inter-season sequencing - ExpectedVals.OBJ_VALUE: 34764.3349, + # reduced after changing fixed costs from MLP to PL + ExpectedVals.OBJ_VALUE: 34711.5173, ExpectedVals.EFF_DOMAIN_SIZE: 12312, ExpectedVals.EFF_INDEX_SIZE: 64, # reduced 3/27: unlim_cap techs now employed. @@ -87,7 +88,8 @@ class ExpectedVals(Enum): }, 'survival_curve': { # added 2025/06/19 after addition of survival curves - ExpectedVals.OBJ_VALUE: 31.8083, + # reduced after changing fixed costs from MLP to PL + ExpectedVals.OBJ_VALUE: 31.8004, ExpectedVals.EFF_DOMAIN_SIZE: 64, ExpectedVals.EFF_INDEX_SIZE: 8, ExpectedVals.CONSTR_COUNT: 101, From 040054cef1b2757e2a1539dff026052fc02555bd Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Jun 2025 17:08:50 -0400 Subject: [PATCH 165/587] Update objective function documentation --- docs/source/Documentation.rst | 38 ++--- temoa/temoa_model/temoa_rules.py | 230 +++++++++++++++++++------------ 2 files changed, 164 insertions(+), 104 deletions(-) diff --git a/docs/source/Documentation.rst b/docs/source/Documentation.rst index d8633a7a4..7dce8492a 100644 --- a/docs/source/Documentation.rst +++ b/docs/source/Documentation.rst @@ -951,33 +951,33 @@ Parameters ":math:`\text{DSD}_{r,p,s,d,c}`","DemandSpecificDistribution",":math:`\mathbb{I}`","Demand-specific distribution" ":math:`\text{EFF}_{r,i,t,v,o}`","Efficiency",":math:`\mathbb{R}^+_0`","Tech- and commodity-specific efficiency" ":math:`\text{EAC}_{r,i,t,v,o,e}`","EmissionActivity",":math:`\mathbb{R}`","Tech-specific emissions rate" + ":math:`\text{EE}_{r,t,v,e}`","EmissionEmbodied",":math:`\mathbb{R}`","Emissions associated with the creation of capacity" + ":math:`\text{EE}_{r,t,v,e}`","EmissionEndOfLife",":math:`\mathbb{R}`","Emissions associated with the retirement/end of life of capacity" ":math:`\text{ECAP}_{r,t,v}`","ExistingCapacity",":math:`\mathbb{R}^+_0`","Pre-existing capacity" ":math:`\text{RCAP}_{r,p,t,v}`","RetiredCapacity",":math:`\mathbb{R}^+_0`","Capacity retired before end of life" ":math:`\text{ART}_{r,p,t,v}`","AnnualRetirement",":math:`\mathbb{R}^+_0`","Annualised capacity retiring or reaching end of life" ":math:`\text{GDR}`","GlobalDiscountRate",":math:`\mathbb{R}`","Global rate used to calculate present cost" - ":math:`\text{GRM}_{r,t}`","GrowthRateMax",":math:`\mathbb{R}`","Global rate used to calculate present cost" - ":math:`\text{GRS}_{r,t}`","GrowthRateSeed",":math:`\mathbb{R}`","Global rate used to calculate present cost" ":math:`\text{LTP}_{r,t,v}`","LifetimeProcess",":math:`\mathbb{N}`","Tech- and vintage-specific lifetime (default=LifetimeTech)" ":math:`\text{LTT}_{r,t}`","LifetimeTech",":math:`\mathbb{N}`","Tech-specific lifetime (default=40 years)" ":math:`\text{LSC}_{r,p,t,v}`","LifetimeSurvivalCurve",":math:`\mathbb{R}^+_0`","Surviving fraction of original capacity" ":math:`\text{LIT}_{r,t,e,t}`","LinkedTechs","text","Dummy techs used to convert CO2 emissions to physical commodity" - ":math:`\text{LLT}_{r,t}`","LoanLifetimeTech",":math:`\mathbb{N}`","Tech-specific loan term (default=10 years)" - ":math:`\text{LR}_{r,t,v}`","LoanRate",":math:`\mathbb{R}`","Tech-specific interest rate on investment cost" - ":math:`\text{LE}_{r,p,e}`","LimitEmission",":math:`\mathbb{R}^+_0`","Emissions limit by region and period" + ":math:`\text{LLP}_{r,t,v}`","LoanLifetimeProcess",":math:`\mathbb{N}`","Process-specific loan term (default=LifetimeProcess)" + ":math:`\text{LR}_{r,t,v}`","LoanRate",":math:`\mathbb{R}`","Process-specific interest rate on investment cost" + ":math:`\text{LE}_{r,p,e}`","LimitEmission",":math:`\mathbb{R}^+_0`","Limit emissions by region and period" ":math:`\text{LA}_{r,p,t}`","LimitActivity",":math:`\mathbb{R}^+_0`","Limit tech-specific activity by region and period" ":math:`\text{LC}_{r,p,t}`","LimitCapacity",":math:`\mathbb{R}^+_0`","Limit tech-specific capacity by period" ":math:`\text{LR}_{r,t}`","LimitResource",":math:`\mathbb{R}^+_0`","Limit resource production by tech across time periods" - ":math:`\text{MDP}`","MyopicDiscountingPeriod",":math:`\mathbb{N}`","Objective function NPV year when running myopically" + ":math:`\text{LSF}_{r,p,s,d,t,v}`","LimitStorageLevelFraction",":math:`\mathbb{R}^+_0`","Limit storage level in any time slice" + ":math:`\text{MDY}`","MyopicDiscountingYear",":math:`\mathbb{N}`","Objective function NPV year when running myopically" ":math:`\text{PRM}_{r}`","PlanningReserveMargin",":math:`\mathbb{I}`","Margin used to ensure sufficient generating capacity" - ":math:`\text{RMD}_{r,t}`","RampDown",":math:`\mathbb{R}`","Rate at which generation techs can ramp output down" - ":math:`\text{RMU}_{r,t}`","RampUp",":math:`\mathbb{R}`","Rate at which generation techs can ramp output up" - ":math:`\text{RSC}_{r.p,c}`","ResourceBound",":math:`\mathbb{R}^+_0`","Maximum resource production by tech and period (currently not supported)" + ":math:`\text{RDH}_{r,t}`","RampDownHourly",":math:`\mathbb{R}`","Hourly rate at which generation techs can ramp output down" + ":math:`\text{RUH}_{r,t}`","RampUpHourly",":math:`\mathbb{R}`","Hourly rate at which generation techs can ramp output up" ":math:`\text{SD}_{r,t}`","StorageDuration",":math:`\mathbb{N}`","Storage duration per technology, specified in hours" ":math:`\text{SEG}_{s,d}`","SegFrac",":math:`\mathbb{I}`","Fraction of year represented by each (s, d) tuple" - ":math:`\text{SIF}_{t}`","StorageInitFrac",":math:`\mathbb{I}`","Initial storage charge level expressed as fraction of full charge" ":math:`\text{TIS}_{r,i,t}`","TechInputSplit",":math:`\mathbb{I}`","Technology input fuel ratio at time slice level" - ":math:`\text{TISA}_{r,i,t}`","TechInputSplitAverage",":math:`\mathbb{I}`","Average annual technology input fuel ratio" + ":math:`\text{TISA}_{r,i,t}`","TechInputSplitAnnual",":math:`\mathbb{I}`","Average annual technology input fuel ratio" ":math:`\text{TOS}_{r,t,o}`","TechOutputSplit",":math:`\mathbb{I}`","Technology output fuel ratio at time slice level" + ":math:`\text{TISA}_{r,i,t}`","TechOutputSplitAnnual",":math:`\mathbb{I}`","Average annual technology output fuel ratio" ":math:`{}^*\text{LA}_{t,v}`","LoanAnnualize",":math:`\mathbb{R}^+_0`","Loan amortization by tech and vintage; based on :math:`DR_t`" ":math:`{}^*\text{MPL}_{p,t,v}`","ModelProcessLife",":math:`\mathbb{N}`","Smaller of remaining model horizon or process tech life" ":math:`{}^*\text{PLF}_{r,p,t,v}`","ProcessLifeFrac",":math:`\mathbb{I}`","Fraction of available process capacity by region and period " @@ -1840,7 +1840,7 @@ demand in every time slice. For each process, the :code:`Capacity_Constraint` : ensures that there is sufficient capacity to meet the optimal commodity flows across all time slices. Between processes, the :code:`CommodityBalance_Constraint` :eq:`CommodityBalance` ensures that global commodity production across the energy system is sufficient to meet the -endogenous demands for that commodity. Finally, the objective function :eq:`obj_loan` drives +endogenous demands for that commodity. Finally, the objective function :eq:`obj_invest` drives the model to minimize the system-wide cost of energy supply by optimizing the deployment and utilization of energy technologies across the system. @@ -1850,8 +1850,8 @@ While not required, doing so improves computational performance by eliminating t season and time of day :code:`(s,d)` indices associated with these technologies. In order to ensure the model functions correctly with these simplified technologies, slightly different formulations of the capacity and commodity balance constraints -are required. See the :code:`CommodityBalanceAnnual_Constraint` :eq:`CommodityBalanceAnnual` -and :code:`CapacityAnnual_Constraint` :eq:`CapacityAnnual` below for details. +are required. See the :code:`AnnualCommodityBalance_Constraint` and +:code:`CapacityAnnual_Constraint` :eq:`CapacityAnnual` below for details. The rest of this section defines each model constraint, with a rationale for existence. We use the implementation-specific names for the constraints to @@ -1920,8 +1920,6 @@ various physical and operational real-world phenomena. .. autofunction:: temoa_rules.StorageThroughput_Constraint -.. autofunction:: temoa_rules.StorageInit_Constraint - .. autofunction:: temoa_rules.RampUpDay_Constraint .. autofunction:: temoa_rules.RampDownDay_Constraint @@ -1938,6 +1936,12 @@ various physical and operational real-world phenomena. Objective Function ^^^^^^^^^^^^^^^^^^ +.. autofunction:: temoa_rules.annuity_to_pv + +.. autofunction:: temoa_rules.pv_to_annuity + +.. autofunction:: temoa_rules.fv_to_pv + .. autofunction:: temoa_rules.TotalCost_rule @@ -1986,7 +1990,7 @@ operation, but allow the modeler some further degree of system specification. .. autofunction:: temoa_rules.LimitSeasonalCapacityFactor_Constraint -.. autofunction:: temoa_rules.LimitStorageLevelFraction_Constraint +.. autofunction:: temoa_rules.LimitStorageFraction_Constraint .. autofunction:: temoa_rules.LimitGrowthCapacity diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 798d5877b..b9a8335b4 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -351,114 +351,169 @@ def TotalCost_rule(M): Using the :code:`FlowOut` and :code:`Capacity` variables, the Temoa objective function calculates the cost of energy supply, under the assumption that capital costs are paid through loans. This implementation sums up all the costs incurred, - and is defined as :math:`C_{tot} = C_{loans} + C_{fixed} + C_{variable}`. Each - term on the right-hand side represents the cost incurred over the model + and is defined as :math:`C_{tot} = C_{loans} + C_{fixed} + C_{variable} + C_{emission}`. + Each term on the right-hand side represents the cost incurred over the model time horizon and discounted to the initial year in the horizon (:math:`{P}_0`). The calculation of each term is given below. .. math:: - :label: obj_loan - - C_{loans} = \sum_{r, t, v \in \Theta_{IC}} \left ( - \left [ - CI_{r, t, v} \cdot LA_{r, t, v} - \cdot \frac{(1 + GDR)^{P_0 - v +1} \cdot (1 - (1 + GDR)^{-LLP_{r, t, v}})}{GDR} \right. \right. - \\ \left. \left. \cdot \frac{ 1-(1+GDR)^{-LPA_{r,t,v}} }{ 1-(1+GDR)^{-LTP_{r,t,v}} } - \right ] - \cdot \textbf{CAP}_{r, t, v} - \right ) - - Note that capital costs (:math:`{IC}_{r,t,v}`) are handled in several steps. First, each capital cost - is amortized using the loan rate (i.e., technology-specific discount rate) and loan - period. Second, the annual stream of payments is converted into a lump sum using - the global discount rate and loan period. Third, the new lump sum is amortized - 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 - :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 - beginning of the horizon (:math:`P_0`) using the global discount rate. While an - explicit salvage term is not included, this approach properly captures the capital - costs incurred within the model time horizon, accounting for technology-specific - loan rates and periods. + :label: obj_invest + + \begin{aligned} + C_{loans} =& \sum_{r, t, v \in \Theta_{CI}} CI_{r, t, v} \cdot \textbf{NCAP}_{r, t, v} + && \text{overnight capital cost} \\ + &\cdot \frac{A}{P}(i=\text{LR}_{r,t,v}, N=\text{LLP}_{r,t,v}) + && \text{overnight cost amortised into annual loan payments} \\ + &\cdot \frac{P}{A}(i=GDR, N=\text{LLP}_{r,t,v}) + && \text{annual loan payments discounted to NPV in vintage year} \\ + &\cdot \frac{A}{P}(i=GDR, N=\text{LTP}_{r,t,v}) + && \text{NPV reamortised over lifetime of process using GDR} \\ + &\cdot \frac{P}{A}(i=GDR, N=\min(\text{LTP}_{r,t,v}, P_e - v)) + && \text{costs within planning horizon discounted to NPV in vintage year} \\ + &\cdot \frac{P}{F}(i=GDR, N=v - P_0) + && \text{NPV in vintage year discounted to base year } P_0 \\ + \end{aligned} + + Note that capital costs (:math:`{CI}_{r,t,v}`) are handled in several steps. + + 1. Each capital cost is amortized using the loan rate (i.e., technology-specific discount rate) and loan period. - .. math:: - :label: obj_fixed + 2. The annual stream of payments is converted into a lump sum using the global discount rate and loan period. + + 3. The new lump sum is amortized at the global discount rate over the process lifetime. + + 4. Loan payments beyond the model time horizon are removed and the lump sum recalculated. - C_{fixed} = \sum_{r, p, t, v \in \Theta_{CF}} \left ( - \left [ - CF_{r, p, t, v} - \cdot \frac{(1 + GDR)^{P_0 - p +1} \cdot (1 - (1 + GDR)^{-{MPL}_{r, t, v}})}{GDR} - \right ] - \cdot \textbf{CAP}_{r, t, v} - \right ) + 5. Finally, the lump sum is discounted back to the beginning of the horizon (:math:`P_0`) using the global discount rate. + + Steps 3 and 4 serve to correctly balance the cost-benefit of technologies whose useful lives + would extend beyond the planning horizon. While an explicit salvage term is not included, this approach properly + captures the capital costs incurred within the model time horizon, accounting for process-specific loan rates + and periods. + + In the case of processes using survival curves, steps 3 and 4 do not reamortise costs uniformly over the process lifetime. + Instead, costs are amortised over the life of the process in proportion to the survival fraction in each year. + Note that, for this calculation, a survival curve :math:`{LSC}_{r,y,t,v}` must be defined out to the year in which the + surviving fraction is zero, even if that extends beyond the planning horizon. It must also be defined for each integer + year between model periods and, if not, these gaps will be filled by linear interpolation ahead of this calculation. .. math:: - :label: obj_variable - - &C_{variable} = \\ &\quad \sum_{r, p, t, v \in \Theta_{CV}} \left ( - CV_{r, p, t, v} - \cdot - \frac{ - (1 + GDR)^{P_0 - p + 1} \cdot (1 - (1 + GDR)^{-{MPL}_{r,p,t,v}}) - }{ - GDR - }\cdot \sum_{S,D,I, O} \textbf{FO}_{r, p, s, d,i, t, v, o} - \right ) \\ &\quad + \sum_{r, p, t \not \in T^{a}, v \in \Theta_{VC}} \left ( - CV_{r, p, t, v} - \cdot - \frac{ - (1 + GDR)^{P_0 - p + 1} \cdot (1 - (1 + GDR)^{-{MPL}_{r,p,t,v}}) - }{ - GDR - } - \cdot \sum_{I, O} \textbf{FOA}_{r, p,i, t \in T^{a}, v, o} - \right ) + :label: obj_invest_survival_curve + + \begin{aligned} + C_{loans,LSC} =& \sum_{r, t, v \in \Theta_{CI}} CI_{r, t, v} \cdot \textbf{NCAP}_{r, t, v} + && \text{overnight capital cost} \\ + &\cdot \frac{A}{P}(i=\text{LR}_{r,t,v}, N=\text{LLP}_{r,t,v}) + && \text{overnight cost amortised into annual loan payments} \\ + &\cdot \frac{P}{A}(i=GDR, N=\text{LLP}_{r,t,v}) + && \text{annual loan payments discounted to NPV in vintage year} \\ + &\cdot \left( + \sum_{v < Y} LSC_{r,y,t,v} \cdot \frac{P}{F}(i=GDR, N=P - v + 1) + \right)^{-1} + && \text{reamortised over survival curve (normalized)} \\ + &\cdot \sum_{v < Y < P_e} LSC_{r,y,t,v} \cdot \frac{P}{F}(i=GDR, N=P - v + 1) + && \text{costs within planning horizon discounted to NPV in vintage year} \\ + &\cdot \frac{P}{F}(i=GDR, N=v - P_0) + && \text{NPV in vintage year discounted to base year } P_0 + \end{aligned} + + Where :math:`Y` is the set of each integer year :math:`y` within the planning horizon. + + Fixed, variable, and emissions annual cost factors are determined by: .. math:: - :label: obj_emissions - - &C_{emissions} = \\ &\quad \sum_{r, p, t, v \in \Theta_{CV}} \left ( - CE_{r, p, c} \cdot EAC_{r,e,i,t,v,o} - \cdot - \frac{ - (1 + GDR)^{P_0 - p + 1} \cdot (1 - (1 + GDR)^{-{MPL}_{r,p,t,v}}) - }{ - GDR - }\cdot \sum_{S,D,I, O} \textbf{FO}_{r, p, s, d,i, t, v, o} - \right ) \\ &\quad + \sum_{r, p, t \not \in T^{a}, v \in \Theta_{CE}} \left ( - CE_{r, p, c} \cdot EAC_{r,e,i,t,v,o} - \cdot - \frac{ - (1 + GDR)^{P_0 - p + 1} \cdot (1 - (1 + GDR)^{-{MPL}_{r,p,t,v}}) - }{ - GDR - } - \cdot \sum_{I, O} \textbf{FOA}_{r, p,i, t \in T^{a}, v, o} - \right ) + :label: annual_fixed_variable_emission + + \begin{aligned} + C_{fixed} =& \sum_{r, p, t, v \in \Theta_{CF}} CF_{r, p, t, v} \cdot \textbf{CAP}_{r, p, t, v} + && \text{annual fixed cost} \\ + \\ + C_{variable} =& \sum_{r, p, t \notin T^a, v \in \Theta_{CV}} + CV_{r, p, t, v} \cdot \sum_{S, D, I, O} \mathbf{FO}_{r, p, s, d, i, t, v, o} + && \text{annual variable cost on flow} \\ + & \text{where } t \notin T^a \\ + &+\\ + & \sum_{r, p, t \in T^a,\ v \in \Theta_{VC}} CV_{r, p, t, v} + \cdot \sum_{I, O} \mathbf{FOA}_{r, p, i, t, v, o} + && \text{annual variable cost on annual flows} \\ + & \text{where } t \in T^a \\ + &+\\ + C_{emissions} =& \sum_{r, p, e \in \Theta_{CE}} CE_{r, p, e} + \cdot EAC_{r, i, t, v, o, e} \cdot \sum_{S, D, I, O} \mathbf{FO}_{r, p, s, d, i, t, v, o} + && \text{annual emission cost on flow} \\ + & \text{where } t \notin T^a \\ + &+\\ + & \sum_{r, p, e \in \Theta_{CE}} CE_{r, p, e} + \cdot EAC_{r, i, t, v, o, e} \cdot \sum_{I, O} \mathbf{FOA}_{r, p, i, t, v, o} + && \text{annual emission cost on annual flows} \\ + & \text{where } t \in T^a \\ + &+\\ + & \sum_{r, p, e \in \Theta_{CE}} \frac{CE_{r, p, e} + \cdot EE_{r, e, t, v} \cdot \mathbf{NCAP}_{r, t, v=p}}{{LEN}_p} + && \text{annual embodied emission cost} \\ + &+\\ + & \sum_{r, p, e \in \Theta_{CE}, v} CE_{r, p, e} + \cdot EEOL_{r, e, t, v} \cdot \mathbf{ART}_{r, p, t, v} + && \text{annual retirement/end of life emission cost} \\ + \end{aligned} + + Each of these costs are then discounted within each period then to the base year: + .. math:: + :label: obj_fixed_variable_emission + + \begin{aligned} + C_{fix,var,emiss} =& C_{fixed} + C_{variable} + C_{emissions} \\ + &\cdot \frac{P}{A}(i=GDR,\ N=LEN_p) + && \text{for each year in period } p \text{ discounted to NPV in } p \\ + &\cdot \frac{P}{F}(i=GDR,\ N=p - P_0) + && \text{discounted from period } p \text{ to NPV in base year } P_0 + \end{aligned} """ return sum(PeriodCost_rule(M, p) for p in M.time_optimize) def annuity_to_pv(rate: float, periods: int) -> float | Expression: - """Multiplication factor to convert an annuity to present value""" + r""" + Multiplication factor to convert an annuity to net present value + + .. math:: + :label: annuity_to_pv + + \frac{P}{A}(i, N) = \frac{(1 + i)^N - 1}{i \cdot (1 + i)^N} + + where: + + - :math:`i` is the interest/discount rate + - :math:`N` is the number of periods + """ if rate == 0: return periods return ((1 + rate)**periods - 1) / (rate * (1 + rate)**periods) def pv_to_annuity(rate: float, periods: int) -> float | Expression: - """Multiplication factor to convert present value to an annuity""" + r""" + Multiplication factor to convert net present value to an annuity + + .. math:: + :label: pv_to_annuity + + \frac{A}{P}(i, N) = \frac{i + (1 + i)^N}{(1 + i)^N - 1} + """ if rate == 0: return 1 / periods return (rate * (1 + rate)**periods) / ((1 + rate)**periods - 1) def fv_to_pv(rate: float, periods: int) -> float | Expression: - """Multiplication factor to convert a future value to present value""" + r""" + Multiplication factor to convert a future value to net present value + + .. math:: + :label: fv_to_pv + + \frac{P}{F}(i, N) = \frac{1}{(1 + i)^N} + """ if rate == 0: return 1 return 1 / (1 + rate)**periods @@ -529,8 +584,9 @@ def loan_cost_survival_curve( GDR: float, ) -> float | Expression: """ - function to calculate the loan cost. It can be used with fixed values to produce a hard number or - pyomo variables/params to make a pyomo Expression + function to calculate the loan cost only in the case of processes :math:`(r, t, v)` using + survival curves. It can be used with fixed values to produce a hard number or pyomo + variables/params to make a pyomo Expression :param capacity: The capacity to use to calculate cost :param invest_cost: the cost/capacity :param loan_annualize: parameter @@ -570,7 +626,7 @@ def loan_cost_survival_curve( * annuity_to_pv(GDR, lifetime_loan_process) # PV of all loan payments, discounted to vintage year using GDR / sum( # redistributed over survival curve within horizon value(M.LifetimeSurvivalCurve[r, p, t, v]) # reamortised over survival curve of process using GDR - * fv_to_pv(GDR, p - v + 1) # the +1 makes its return because LSC is indexed to start of p not end of p + * fv_to_pv(GDR, p - v + 1) # +1 because LSC is indexed to start of p not end of p for p in M.survivalCurvePeriods[r, t, v] if v <= p # this shouldnt be possible but play it safe ) @@ -2080,7 +2136,7 @@ def ReserveMarginStatic(M: 'TemoaModel', r, p, s, d): capacity credit, :math:`CC_{t,r}` .. math:: - :label: reserve_margin + :label: reserve_margin_static &\sum_{t \in T^{res} \setminus T^{x}} {CC_{t,r} \cdot \textbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*} \cdot C2A_{r,t} }\\ &+ \sum_{t \in T^{res} \cap T^{x}} {CC_{t,r_i-r} \cdot \textbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*} \cdot C2A_{r_i-r,t} }\\ @@ -2147,7 +2203,7 @@ def ReserveMarginDynamic(M: 'TemoaModel', r, p, s, d): accounting for a capacity derate factor subtracting, for example, forced outage due to icing. .. math:: - :label: reserve_margin + :label: reserve_margin_dynamic &\sum_{t \in T^{res} \setminus T^{x} \setminus T^s,\ V} CFP_{r,p,s^*,d^*,t,v}\ \cdot RCD_{r,p,s^*,t,v}\ @@ -2161,7 +2217,7 @@ def ReserveMarginDynamic(M: 'TemoaModel', r, p, s, d): \cdot RCD_{r - r_i, p, s^*, t, v}\ \cdot \mathbf{CAPAVL}_{p,t}\ \cdot SEG_{s^*,d^*} \cdot C2A_{r - r_i, t} \\ - &+ \sum_{t \in T^s, V, I, O} \ + &+ \sum_{t \in (T^s \cap T^{res}), V, I, O} \ \left(\ \mathbf{FO}_{r,p,s,d,i,t,v,o} - \mathbf{FI}_{r,p,s,d,i,t,v,o}\ \right)\ From 53d3ade6710a3fc545e7abb856b3584c834c715a Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Jun 2025 18:08:18 -0400 Subject: [PATCH 166/587] Add LDES and survival curve figures to docs --- docs/source/Documentation.rst | 10 + docs/source/images/ldes_chain.pdf | Bin 0 -> 4214 bytes docs/source/images/ldes_chain.png | Bin 0 -> 36835 bytes docs/source/images/ldes_chain.svg | 251 ++++ .../images/survival_curve_discounting.pdf | Bin 0 -> 21131 bytes .../images/survival_curve_discounting.png | Bin 0 -> 60355 bytes .../images/survival_curve_discounting.svg | 1148 +++++++++++++++++ temoa/temoa_model/temoa_rules.py | 8 + 8 files changed, 1417 insertions(+) create mode 100644 docs/source/images/ldes_chain.pdf create mode 100644 docs/source/images/ldes_chain.png create mode 100644 docs/source/images/ldes_chain.svg create mode 100644 docs/source/images/survival_curve_discounting.pdf create mode 100644 docs/source/images/survival_curve_discounting.png create mode 100644 docs/source/images/survival_curve_discounting.svg diff --git a/docs/source/Documentation.rst b/docs/source/Documentation.rst index 7dce8492a..0691c5470 100644 --- a/docs/source/Documentation.rst +++ b/docs/source/Documentation.rst @@ -1910,6 +1910,16 @@ various physical and operational real-world phenomena. .. autofunction:: temoa_rules.SeasonalStorageEnergy_Constraint +.. figure:: images/ldes_chain.* + :align: center + :width: 100% + :figclass: align-center + :figwidth: 60% + + How sequential seasons chain together for seasonal storage. Hatched area + is SeasonalStorageLevel and grey lines are non-sequential season states. + Dashed line is SeasonalStorageEnergyUpperBound. + .. autofunction:: temoa_rules.StorageEnergyUpperBound_Constraint .. autofunction:: temoa_rules.SeasonalStorageEnergyUpperBound_Constraint diff --git a/docs/source/images/ldes_chain.pdf b/docs/source/images/ldes_chain.pdf new file mode 100644 index 0000000000000000000000000000000000000000..9f7372aa5036dbd249c4f0a6781adf51d529dfaa GIT binary patch literal 4214 zcmd6q3piBiAIDvCX^Mzxm(Wq9RA$Z?W2julU14%dE)Rn-W{jCJ4k22lkit%P#fFHA zE{c-7|I*6kFO)5m$|VV1H-EDI&pAfg(*FPZJiE{C`<&;T_wswrd4Hex_xrx@(WIJN zt^;-SFq*|97bY=801t3|S(ptQ0NiFehXDlwdT^H`1^@t@C6f)&`S6oXgXrdTKdwI= zV`PL0h4^$@FeW0s&~;OaivGf$Va4)TgKTrb@+~Co%u+ z?kVNkl-FcZhfNIcqTp_h*&b|MNKoUzzMXm3`fUOSD#Po1#uOf<>8lartRx3&6+S2! zzROn$(VEg@O!%_n4Ao!hMhm(5Sd~G8%NJx5q{5!4lQnAM zMFiOQ^jOy;9@-}6GV{|?_EeXz3Ph%rBKC zFKoK06W#4sKKXX4^Ww6~=Qc6@l( z9}(tInfc-9cRNQ;`ErBpMK{;E4PBMoSpQloay)zQNwNWEb#~zB=1H}ul`mcvwNf)S zY5vgAazE7Urm3vMk_(3eE*0O6JfC|3pUP0S9u@eP7}PI5RNL`0BMGqP+IU^jJigv= znRMQ6drZR;%2;OV`jj%0d8QCq!LyEU>}U|>KdM+glBp^q9($5P*^v~HC0XR&Ror5M zmx*TkG_lvkg-Zp?kM9dg;NI}8<{W1_9gIH|gI%WhMqIi1nd-iK%cqQPtN7nwOv&MF zjJ_Q%;w=^JG*mk>TsOX+8`1a_(M9p+`HB#OW5dAY%vB?F_jHi|tPmJF#%5!ejvQ$b5$N*i$ z>0%?*t`obo?RXV~yryjl%bSDWSWEC$N_5B?AEc&KS9<4Kxsa>QDgDs@y29Q8^EyA3 zt2@D$Y z_b5xo?Crwj#acCX-9IsyCeM~qZ{j@NFH$ek-9NmPM=h$Wt~j@#dcQ|wc$JvvJ^65} zE4?MVS1magvR=1u^0?#+^}B`3<6=C16+cB?*@&TY{DtBG*AQ7jv;=v=Y69Yk1jGPo z>V8xmRA($AAS)*b))-*J2BZTnI2s;q05~&K00eM;H24lH4?Hk^$5CkzEKMBLhDQQO zh-Lveo<5*2tdRjST7&K3OZZ*H>@&3kLBtH5hVY%vkvuv8qCFG}Hv;g04e$UFkB42r z177HWn-fImA$@3T8`^?L(Uvol&EzmXc?*@sJMf5KWA_{7m|=%T@aOQ*j7KwXuJa0_C1~#9gz11< zI)(W{NSfm;x%^2~HkUXuLZ{V{Vh7;tVGn3*0Ow>! z3k^b=9M~;HHg)jR!U;d&WQV^2m*11sS(!v*{d3F)9~1nq#*7O0pNJWmIpPiM|0kGd z^YCxOJjdaiFuNW7#h3}`Zt&+}MrZy7X7nr5q4alQo>_k6I5DjR4!$fWXgckM|2za# z-O(A^3-^9YCO;Gch-lwjOEJ5FMx<|S1{c)g73cL+{Fv2| z05NUblBV9R6c|3ZS+-qlZM$+^aE5eU?hg6zUM0D>(;<>laW=d&gROUdiQ5547Bfo8 zFN&OdJ^O7jni^_DS1&(Nxuy2%At%FYWuU5AQ&nBgQm?ohoHtIMqn*hP$9pIqtlB$* z2WAdu3Rk$gOmKhds(ahF(z#JcOC;>UTj+Yak*e_JFPs z4gw0)|G!AtrEXlb8?R`weP>->OWla3N{uClszwE3URW7BVDpO~WF44v;fa4dVdeKOf;K zlQ5&}vmo6Z=>aGoVZ4EOy|3az*g7$z=m3F?+H3_pK!5-crca)ZTrLCdNC5MNO+e+7dk gxl>P4#^XyUp%9G^Met#Nbq#b4Fq)bc4wjhz0x*)Lpa1{> literal 0 HcmV?d00001 diff --git a/docs/source/images/ldes_chain.png b/docs/source/images/ldes_chain.png new file mode 100644 index 0000000000000000000000000000000000000000..acc9ed459f954dc462d8e61290f00cbc129de6f9 GIT binary patch literal 36835 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 Roh1IVS2)?GjGw>h{{d*ei4p(+ literal 0 HcmV?d00001 diff --git a/docs/source/images/ldes_chain.svg b/docs/source/images/ldes_chain.svg new file mode 100644 index 000000000..2319b0107 --- /dev/null +++ b/docs/source/images/ldes_chain.svg @@ -0,0 +1,251 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/source/images/survival_curve_discounting.pdf b/docs/source/images/survival_curve_discounting.pdf new file mode 100644 index 0000000000000000000000000000000000000000..05948488447865ceb3933ce697a976001d04570b GIT binary patch literal 21131 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 aJ9JrbGuYE-2*y$hg>tg_q@N}@e*53iYqwhf literal 0 HcmV?d00001 diff --git a/docs/source/images/survival_curve_discounting.svg b/docs/source/images/survival_curve_discounting.svg new file mode 100644 index 000000000..81c83fefe --- /dev/null +++ b/docs/source/images/survival_curve_discounting.svg @@ -0,0 +1,1148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Factor = + Survival curve + PE + P0 + Area + Area + Defined in each period + Intermediate years linearly interpolated + Each year discounted to P0 + + diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index b9a8335b4..d24171831 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -419,6 +419,14 @@ def TotalCost_rule(M): Where :math:`Y` is the set of each integer year :math:`y` within the planning horizon. + .. figure:: images/survival_curve_discounting.* + :align: center + :width: 100% + :figclass: align-center + :figwidth: 60% + + Steps 3 and 4 for processes with survival curves. + Fixed, variable, and emissions annual cost factors are determined by: .. math:: From 9cf8bf79259b527b969288f5d13f7f7d9ff21f82 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 26 Jun 2025 11:36:04 -0400 Subject: [PATCH 167/587] Document seasonal storage representation --- docs/README.md | 8 +- docs/source/Documentation.rst | 10 - .../images/daily_storage_representation.pdf | Bin 0 -> 19247 bytes .../images/daily_storage_representation.png | Bin 0 -> 52279 bytes .../images/daily_storage_representation.svg | 188 +++++++++ docs/source/images/ldes_chain.pdf | Bin 4214 -> 7064 bytes docs/source/images/ldes_chain.png | Bin 36835 -> 38206 bytes docs/source/images/ldes_chain.svg | 219 +++++----- docs/source/images/ldes_delta_problem.pdf | Bin 0 -> 20576 bytes docs/source/images/ldes_delta_problem.png | Bin 0 -> 95959 bytes docs/source/images/ldes_delta_problem.svg | 390 ++++++++++++++++++ .../images/ldes_delta_representation.pdf | Bin 0 -> 18088 bytes .../images/ldes_delta_representation.png | Bin 0 -> 30291 bytes .../images/ldes_delta_representation.svg | 203 +++++++++ temoa/temoa_model/temoa_rules.py | 127 ++++-- 15 files changed, 986 insertions(+), 159 deletions(-) create mode 100644 docs/source/images/daily_storage_representation.pdf create mode 100644 docs/source/images/daily_storage_representation.png create mode 100644 docs/source/images/daily_storage_representation.svg create mode 100644 docs/source/images/ldes_delta_problem.pdf create mode 100644 docs/source/images/ldes_delta_problem.png create mode 100644 docs/source/images/ldes_delta_problem.svg create mode 100644 docs/source/images/ldes_delta_representation.pdf create mode 100644 docs/source/images/ldes_delta_representation.png create mode 100644 docs/source/images/ldes_delta_representation.svg diff --git a/docs/README.md b/docs/README.md index cac3838e0..94c59c64d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -26,10 +26,6 @@ Sometimes this automatic PDF generation fails. If that is the case, navigate to ```$ pdflatex toolsforenergymodeloptimizationandanalysistemoa.pdf``` ## In Windows -With the Temoa virtual environment active (see README in root folder), navigate to this directory: +With the Temoa virtual environment active and the current directory set to the Temoa root directory (see README in root dir), build the documentation with Sphinx: -```cd C://temoa3/docs/``` - -Then build the documentation with Sphinx: - -```python -m sphinx source _build/html`` \ No newline at end of file +```python -m sphinx docs/source docs/_build/html`` \ No newline at end of file diff --git a/docs/source/Documentation.rst b/docs/source/Documentation.rst index 0691c5470..7dce8492a 100644 --- a/docs/source/Documentation.rst +++ b/docs/source/Documentation.rst @@ -1910,16 +1910,6 @@ various physical and operational real-world phenomena. .. autofunction:: temoa_rules.SeasonalStorageEnergy_Constraint -.. figure:: images/ldes_chain.* - :align: center - :width: 100% - :figclass: align-center - :figwidth: 60% - - How sequential seasons chain together for seasonal storage. Hatched area - is SeasonalStorageLevel and grey lines are non-sequential season states. - Dashed line is SeasonalStorageEnergyUpperBound. - .. autofunction:: temoa_rules.StorageEnergyUpperBound_Constraint .. autofunction:: temoa_rules.SeasonalStorageEnergyUpperBound_Constraint diff --git a/docs/source/images/daily_storage_representation.pdf b/docs/source/images/daily_storage_representation.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d208c75b7567852147b32b245dcbb55d836e9658 GIT binary patch literal 19247 zcmaI71F$GTvnF_K+qP}{9^1Cfdu-dbZQHhO+n)Qsd2eDic4Ip-vXmX!m04d_Rd+S1 zyoeYrBONOgY4df>Clm_-1A(2PB@_=20ll<|t(mhq0qegiMJNIS0(vnEYiAS3f2p;B zvx$g_k)5##6dxayle43Vfen;<>1YzmOC}{!&jQ zeD=;l*bf(+q3nYhKY6p_jz~b<#tvEZV_h2B2iD8`(?mJVtQ& za{XhF-~LX?A_&8pPJnrn9m{j4F;XQZO9`nWf=JbbyQ9&R+sCR;aaWNFMGV76J_B^9 z?p=cdj6oNBOjhUmtz#FFEnvZ%O5P9MT{wncamq8?x`A9Y-&)_f>1Ef}?CzgNdncLC)9u9rAD1>9ez#vB zx5+h3C=*-b|AyPY+<$=jA9VgF{fAEuHje+a|EI+Ke_;Gyz!i0O7FTlq2U-Fip8r(* zyXXxV{uK!5g#`&13FwUs{_%fM{@3uoIlY*jt@HmSZA!~P%Rs>PKcV2C&_DWbW$gb) z83DbrhrI~_y_}(?lC#Z!ss8UE!tp;P>!zug>$zSOurW}O zzK13O;hZSPqtg}jWB+zypMrdb6cVU^k|eZf0t()J6Wij!B;0WCwr1nZ99K}BZ=`}- z$KU4fqmw!wYwp~-wd7aj&&rV9!#*7?P@2iNUL!MA?mFOMnOVITU)JXTw@3cd)&KSg zBP;v=7>SYL|FY758-3zC2f=}dL>k(UtZHaI>$#getdp^UrbE-m>)gtPNuzP(mez*2uTXr zh6ugaKS;5E@8*z+5i;&jL*1VueUgs;|YwOM|z-Fg~A$k>QVgx6}e zx*YHFWhTJOxr63U&Q$Bx8^4#@*}mfkomj}TnX;m^QPJQF{5X!GSLya1m%vI@(F^+E z9%UysKx|+;S=_nd?#eGMbJIxLQLnvdUzkYP_ywZd)yd}*@=v)hCp0b0iZvr z3L$qw@=;4dK9t1=gZ$8h8i(^o#_tkAnL)Y*MG2{XQQ-M|Fg(OvsH6)?@Cm zRg${u{Q|;8W9*M+vc9B23-W;Oq9B{gjo8pMZ=qpxRCWSU+k-$qX&BIMl1SoEyr*7x zx|#Ie^}cw0!;h66hgXFN?MVxWeUc-Cz840!>$=4gnM*q2ykVJZKt4{Ok(?Z1OTT*& z@+|gl(80LI!|h6#NkgtaAItH}>B98TwTF1#dSK8jmAK zi8x+zw{*mEWD9W(EkZ2n;~QX(iE3ew`}>LV+O(JKSm>Sn4SY{Li~bfMJh+}EJge9+yvHEI3xTISy1R1#IZ5h~-*AB~UO3SRcC#SPfi3L}$;%B2)C<>!x(z zT4J&5!Li->9X&%!7r8y-K4K!p7(3aoZtGiEDX_2rQ_M(X5X6QOFx--Q+SZwwd5)zL>yY>)1jMwlF~wo+4Af7NraD!E{z+f-Fx~q^VbR zVoeib>1kzUZm$ZQ9)%UIc~^qgL^;=QLf*zCtUF4%wlC0t$$%}eyB&H@t{7%H~I$Xc$>-oLWdTZ`oR#hqId;Edj z^E*Jx&fEML?n%$v2<~+4bP;wKNjdbqg3a&qy`(iNAQ|}O)!_?=2hK7|h`#g3q9&3< z@gZCaxP?Vu4mjp%EPu~eFvlUJyhYV@ngXj-;cXJNIRKLTjsDgqE<#EG;SrPYfkkfrR8W~sW& zsvsf)UQD0i)SWEhv~m_@t1(1|R=P^jUvP7Mt)0O~uE1K4H&WxO0QgFV{dhLBg%aK-WYqy@ z(){g)nWx1+t8{SE9#QwSMd*}f@L!e`p1H+Q+FDA}CAl&laJ8IQ71?14qD>HJvP#c~ znwy%QZcUvMv=L}1s4&<{b@H~VDdMTwE$S@$=$1lo;Vry__q$9*=$2F6r?fur_rQ3PzfOiJ$Ce%^vCT05$;6Rc4V zfQH#ZSlyuKCoFNGFnPR1eSjN(wn?-G7t7Ggu)KYfyTdA!ypo|j*ssGb^19{IG1O!R zH|*Ie-b)c{L>v3s9%3u1452zr7NeT1OQrD^3A$~`4qa5+!l@ph19^5maqqZ`n!7X0 z9KZ+mJJvL+V@U}BvZP_%Wd!w6U}qyCZWhXvoGdi3$WJz(0UFSx0BK-CDQ02U>xhvA z-Vr;enP8Gc9O6~bjJyDXo3;SN=5n#BN21Ec!jgwt>~>?Atf97mPR{iK6RAUBz+7vP zqEBM>`rSF|Y=aJF$H!+t+njV-KorSTbyXFxfhP+GG;~x2o28RSn{XovM2W}FCKy$W z%2f96B^4}Xi~~UesAG*gMX6FPxtBZb)?F9R2JE_j&Z;`sik#MNq+xG28qX`>rHmC_fa*1^D_gsU=5%L52x;uBjp z2F{7%O=BsU%mZV|Ek7vmwZLzLTg;y^b<+~}&a0RY{ux)atF}vK3m|XMI*2cll9O~O z7w4k%7lvk|P+>+YR+sccdLAq5h?lNp0c9XYDoavm7Fn(n8rMWhNBz?tikTcbrYXN| z#HDI#PRO;6J`><6oGcsd`XU6|NbuR`M{T^EAWV`EorO zfqKf@ES_0+V9{`;OH+N>d%M$PH%&2Z&_Zk}k#qPcuxcFGdtmSr!5$Q_z6aj|LAwGv z0d<3A5a<$YI4(;vn-RhVFrp203}&Hy^wE76{AmcsKfyY~Po;jE5wC=vb*Ooii>-a2 zncGO>p6IUhBI-C_N(irdt$S-NS7}xl`UtYTy^)AD&%%e0MCv@2RADWa_GBCbgvzoz z4)qX$4wLl=EOIc-VBcjiSXw!6wT3*--;mz8xL*9-s8lXyHX(~|3CfAqYUC*!26ZuD zPAUU`BuXV7Vn61@@m~C1_8pxAMcW;dS8O3AmENHdt?6%!lB8VH9o>{Jy$v0KV3qU) z15Pp~G2V|8M?j24R#y(Jn7r=?P(NhKa0xQeXWTwEg?5qvu>1s=o>hGf`o65V*jgU4 zUcKbnPaB4Wu;Z-LHzsP%wh^{5XG;<#4aj>&f`oX$3jZvBb;(i`y(EEFI_`z$r06aR z$3RHTOsItIq(a}*QA~4EMPaoLq8!q#{Fk6KglYnDt-*lI*&bsG=b}N|yX@%}{CD9O z()IVgb~ZGo&o=VDAir_!$*6_W+xdpj zHSlq5`*+5HGXNx*C}bdy1I5@rI1n}om2U{-ksLCH`rJ=IBGZboux;|Dv98%o?aY>5 zdWBH6wsczXod2fz?pjAH@*-Aq*j2jN1{p0}j5} zcZ8bZMtv6Kar$U&sw#%Z=>L#XZQ6T>pF?~&O~?d{=@eR0U8ExZOK6GeyFJ;vLbn7i zsh@!PGi*u*iG<9Fu9?fkEvUA=S7-d-`5lAzv3%WFxFA`Dh?1Vaj<(G80Zp7tiRFYV zGF4+lmUhTy=jFNsd`-{g(Z;3RZo{2F;>@XS+xhWntM$#99`RS5_e_>&Vl2<1?|BaO z$g|Et4zJJE^ls1l$ZgurI^fVF*IYERRFvgNs)<4LC}K}S?$GR^+Jlz+{6&*Gt*U3r zqNR8iD7E!Kyfy8PO@E3PFSJ>_m)YOB>~jnI63h(^hy;%70)a#ca9gfG_as+^Ilst& zw8#JvEMl_aLzZalmOGS@0>0ClcT(PEX^&?9X+j-x7Q%=_(*Vsut&X-(Fe5Zb>*M~=J~n^mcsW4kiidusQuxB z9Z;k(lLbD5N> zF8R{5PO&JKD#C3-*|b$Cvd2CXzWM7-*5LF=D0xmqX28fFAsqERFlbM(Rf5OtA5gMX z0;eGh6-|^~?Jq@Z6o-^i_b8ID*7*R+tVTSf)9wIS1|0$hH?&&xYXR9Lyw@c|ySryq z0yR&H^tmbT<&Y=qFsd*#DMhLxeoE~^LOnT3pNpEb(+w>!DK4-E>$5!*4SXXFwuvT> zC2%Sjm^70UGY!cVwRf~8n;ZS0l_-aX8cuVfmEL`AUFJ1v;Yf_Dl@*I{HXuCoRDL323Prr|$;x&ZH&^;c5)VsYuA!Z;r6)Kt4wztX&Jhc#9g z==Vls(odznSzP^6C4%80jE zpptbWRo?HO8rxG616zjDM2$mZ>PAjV&PO2Q_k5N6_2X^*dd^w=?gr;}yS}>GsIN>k z-Y@vHJM-jxd4DN)y$cL)yq~k8PN7 zLT?nw(Y$$&=yt3O!Jn7?n0ZU!(`{|TwT-2wkmv5B+r(uXMIbyHBR~`%k<2LU8(o?6 zilRYjNhoPsS0vT>ITsi zW7(ww*?GjiimQSgX7>ToO+g_-1YN*E%T(UHOOF2JJu%lBDkBm(AO2aECnB{UDJlgjb|75o@KY7`N@_a&LWjJ*t72R zDBU9>RN`q;4HjB|>W(?QP*BA|%4-MhXpZPb&KS?(_ij&0x27kZt7W>Eh181t7q>j< z^1da$6?z=fnTZNU71TT*LBPOY#}Dq_topmLmuk^e(Y^1FQ=I->gV9~NXC1Eft)IF5 zfARjqW$2>_2=+HHmMD72JU52ma}N&oSg2Ohv;%={Q?FazJIr_Nq3n>cS^Nyqvxr@#($c-c zsg1^}g;yLqdX#eW{yU<0%7t{7hLu_-CiI^8fp`Kiq3&DTWAHx3HR7}SS?z`29Dj^X zEp+T7e=TmZ{NqaClnC_{4yv4p$dzPL#28o{7W+=q9Em|Sf{0wBN|h!;)&I1wTa6XL zKwae;>uo^QP>my#ERssW_Tj80`c>5Zw7UPqjh>@T$Oqh5fR2P6L!2& zdyRG4CzDoBH8pHy6Nb|t7#zl-Wo@K|og5P`yEFP|HXuLuWNQSbAqBdd^QR}J2S=~= z#osmmbr9{0MrVxCs6%wU;Zn6lbltJi6=wdX@`7%%UI*?v4O5tivnc~hN`@H$JZ#uD zl)hCn|FHTV5WiY|rmhn7)O<>g`8w_^rq5Qrk~&oZ;5*`%*kI zHQn>(hfjDZ`)jLwhLyC>m}d~)URPw&iDFREo454&dq7zG0V6i6T8OA|r=`-Pv4^^= zZrm(38cN7Iv1{gRY`m1&NEDsux+PJb_@v?JIevFsWk-wZ<#O5U#%IS%N2Mk=8g(h4 z!~zE88t=>BPg!og+pYx(1djLla*Z>wQc+tdcmdZ+6Q&+YB~SYP`^?A0pmpXlxH)17w*q}_c_XSFZv%^XL5 zLE8?Ob@rPsrQO#?mF!7$emw%AJx-83PbgO$F5%UawBQ#LKU4(j7O+^hEwRG7ddb%6t7BSUL zRpHzEnk_5g2k;oS1+`9Ee05vXf#esTzK|Z4kWk(c%!<}VI|ev_>1eGeI3w_J0KqAlWLY39x-Bi zV_j2J8XX$f}e; zfj7NDr_dUBP)>6jtVS`;e{ao7oI+{*&q1q?xQ81Hkp3lb4cFN>onF6Xa zfv~%bfPhPE)Qp@_s@boWYN~I_$>dZIEjzm1{jRAq=u!=Ap3puXCKt$LG&T|_rPjM< zMj8SN4qJa3Bds?@a9G)l z^4X5*bk1aKuoe<_0L3FQIqTv1@^JpLfk|T-af6#+vfDAaAuZrcsvaAr;Ryq}T>=~! zGGW!h@iL1q6Dh<-Z67i>r;g_Y2reh9RB#Y^vaf0$p*(hR1)xb5(^vfXmK9`C&UYtdr* ze1Z@8Hx+NQuFUH@V_8nz=~kWL_!yVDb=H~tiW4;Wp?Q$rYUgOvSuU{N_#-THMsLGm zUH!|}L7qBC!PVnZrID^P{vy`?7w6_yzwsz8x1n2d?&Bn=ZP8ZD73;1D5H)HNzj(+# zLb5D1kxwoT%o_L&7;dgNTPja$oF9v7dpi0=x{*T7wK8h}^t(bzd5C7P_#(n!QRyVU zmnP-WHs;nnMz0W3%gX>6<4iG7z4))EQ(ec}cG*ob=b)`0Yyo;~)si{MdKF#l_9>NO zgth1kV+-TUe2jRuWPK&arK4P9C1)k4XS9{fO2$?70qjflOy)Mb*==1b_pQrzrc3K5 z;ydVZnCqIy*mwO`{HKypTxfCRryGz60(uwjP|5S$5Fzsbp zO5h4f6`PF3;{?Q0H!~B|4r6v>0S#`O;0Ty4A~OZVvalyWiZakY8h7S#Ajn0oxlqK0 zZOFzw`AZ!z=o(jC7eqB6Ic<8w?`3=hi&Si;A-32SnI?y(n+a?{$PD$B(!q#C&D((9 zo057kA$75McR-inIkyiM=rbS9jeS_0eATIf0z2J-B}u_KFGzhUjz!kxI#c#sD+q2= zR$-rDvu?OzEk~S1B(n;`t2oTp6@h!Dy{)|!nlrT(V1%BwdaljP{GD7TdUX; z`9bK)bEWK2L%RM6G)##lZYZIa$Y~lsz-hM;MP{gIpklyy==W}JA4*x#y>b->EcE`6 z-;O*8*Ymr*)>cwuv{%3V-D9CKZ*Wfr5`Ni=9>-9a_6TXJ_^)A0% z+Wq`px6A+b!6Edof!BmI_?muSfHCvOG?*x9oG)fzW~1(0IB4`31BzMqBeU-h zEYfsrBQ&1>3jWprILXkb^IJ#xsv_pTw%lXUlW!56THd39kU}%whvY^|-?!wTW-u>; zaOL}9j=}j@PyHUqm)d;a>`fbJ)v+{k_5l}Bd7{DEvCR>Y%FR9oC~GW@S@B6XXz=2+ ze^LEYTL#47w~=Zv|5O}HkHqJV1M3%6TB2qH7L^MeJ%Ca11=_Kx#@doloLo5Vd_=)K zO>bPTkak_I?7#5}Q3~pVCUOc&M`De#5meM?6l6S*z6tpBC(5URT1@RmunjyLJn`l7 z1+0f*)iac)tqqe>Lva)Md%HY2#W;V7uTNbxFp!A}AVEE}8Y z48JtFJ%taAHUe150u-8)H#vp{X2Kg`FxlS#b13ig>ih=w$zw05kgP;T(8sT@3KQf6 zgJ-mQ1B^lYTybRyAcQ51uv8{-3GjX?lk<_8VFs2bP;SsKztj!+VSgHja_N;xwgSGd z#M?3MWkj1XNm^J(`WnAy8pk5%g99o!t7Ezfz)H&ql~)WiI16lYQWlOF+nk!Ff+^ve zEj}T8IvkSzQ8wK)>pT%wmO&>Le|3kmrW@Bt4F1^Bv=we5*l%B9yDbQxEb)A%GV7I_ z^TW~l_W_1jiw~CLe4~ODrDiFhUG(W{#N$w)EH44wW`%}P|G5(c@4moL1qUrPq=BOq zr3oZSTO5!oNs@+9oD_>Tx-rU4`lKWxgk^9cPg=2*tF*I5@wB5RK1EBly(NNON{a@3 zSop$cwe*10s{VjRZ1{ypyk7H&$|+VN-Selus3J`O$U)cSMI=RWT6^o#r8 zw)*tV=|a2)`T%_;k7xmJQ@tv@M9LJ8)9@3Pa*&#UTX`oq3vFDHqC6O`1NJhGgS!QF zqkodIf&zW>4MQX5%&`w@Hq0nrtX1W1z6jhOJ3G z^qu(QhQ{A?S&%PK7Z&6#A1%LhVVXZzE=QWL2ZGBlSngkIDG@S~` zS^7?TOV=&SU30reCxPi%>;^um5$vN)6QGklph2$5aCQzmHze|D$_ziP^t>Ywft^r# zQyuN`m+~)Wx~8VL4^6gyd>wVGdv6Y7!D!vPi}FDj=TYPX9pO z*$BbOMAe-0IOoO%)~Ck6z^C(1m25WiKO}OllEfCw+2%By#%%m^2YuH&Q=8f2%sLG- zmtiaHrPG??57*x{mda3o#scDKD$CP>SbpahGPLKkDbln*&Akj54O21G4~j-?1E>yd z`M-Dh=vMC$=UvBT9MP zx}e=R!tY0}ru`v05x|`zAm|~gnk%91)ZAd^2K7b7aHcPH-s+tmA4nt$Sn>-1Fsr#8 z+MLO8Ikyw^70wGh5(u=(73C-wzopddmMg$LDUuf5jIe$}qfdLz-Z>2vZG7(8&t#*j zE}>qjA9dfNtob=kUPYFB+!wOTusBD`{Z`O%_A%mUIeEvHR?Vk9BVA>O4vgLdiqhCgL^^*T8d)L9 ztcTFL^^F9z0M+7di7Asg?Z;NhnPH_@{hhylO^YLb=Ov?~dgnzo;}a=*-f%{;en8^v$ z{~9b@-kXZHAr?_!0kRWI%W3`l?!I3t@mb$$>vPD?9D%MK-*uM=x~j{`vvtSkV>v3! zjPFz8TV!v(GTX}cBWr8WKXv)ZzOUf6!>t~= zm&cr})Ea`;1!io%>|4*mk8x>L)@SEUG%&Vl>qU51u>Flw~{{+Y~%b;KU<5r)TZ zU$mEgR9r-~W!yC#xslgaE+rHhIEy_>2QJJjMIXb{*bIY_P#LKAde6g^0M_g3#)Tog z9RNn!kcQR!Nxy=6QwE1b5u@aXEt@@U=nnbqF%^AhrOV`TDzn$aOWYT{=I7*9e0kR0 zeS1pna~BED3699^z&0sTk+>2P2t(s<7Ut|`6!*~f{ww_YR!!SDgJl+Qv&8Y zCH8~(=l3eME*7+Ris7zjM~)Fc1B~RN{q48$bO7()gbC%-EuPq5rsOB$ozC*~D~emg3U-{Ksl*!-&_0*Dg7Z)p*<7rt#(vYIZ$Ywc}Vs|M?-L87gzn zJf*?zSy;f>WPvgTfe-vI3I3_)8*|s%VD2g8fy)ockvre@(;aZ<6pzzi_mii)sq_75 zRtK=BQrNMi&cWFx7#Fv*ezcRzrKOhR= z8{3~+a#`((lfqP4K>Fo<5Dlpn;BM^^j;-E!>!UFk9$=V!2qMk_F@c9i?AyYGN9)KJ zLaNMpXs`z|f;-ubkXo8k4l9Bz9r2L;p&sujIP#a-eZCX&JRW7Ckb3e~s)#*06{u}B zif7yTjLTVCm4cfEiDsq|UY+y<+oX)7NL<$NX8hg-F)geVgYNk9S3R z7GpumL{r_D?p(J$Pk#E(o!LtRm#3_#_xCvJ=l8hx?%Y&c;=0+eiz67fS?Id;lIrv<)r0QlHp{Kq8 z7^Ja5!X#9bHC>#jHrm|l;r_D7b&X-`WPa*Hdt;cSje|-pzlbhnvWDhSBE|%{DSD9Z zLh7uO{qLzmM(S6p*1NYCz3wPPEXaVy1uZ4PAYzdX59Kj?o7xFJVk=x zz}qni?s&QZb_1>Z;NzD^v455E%VQVyAWz8?pE4buNOB^z@_$y8z0sD`;Fo?+@k7{t z!te)U56SobGP!iatO)VAA`JmT z_+TK4^nL;&H4{P?sge*N-UE2_3E6+ImVWzw0P|jj#u4+t6R}8|5x*k_Ik8;pCGv=0 zT1fJN9f?p8JOTYhtre^-C_E#7$Nev3GIHb>-|-u17T zLp{@MLTn|?On4>7m*$J?iG_3I2VbrN7^V%pbbq)V_$B!b3mL@S6^t!dd=tFnGZvt> z@q6cW#{C;*weR4F3c&~$JRdy=jyEkZ>Hr_!zo?cMTL*7W^bDm1@-%UlY!(WQ};F6;$euf$B?&N1TKs1Zz-B^s{QYMKyrTYV)nm>#ANMf z@8};>hqiv0|A0?Ppm?Ku!+&FJ?#sAzVfq612L4Ku#Sb5K9?5OBzN5eENlEQh*NR=v zd!Ly+(O(T1-Q#$n>PENj>%3*YDR|-J4xLKirpwh3=Gs@b%WT2FhucpdvOl^(a0h!1 zIep7~kAC{l%?Y>GYSC&D$Mx!TN@TR_}*vbH*8gzN59@4!Iqa zJ4C;WY{S;%4F3)K4fqY`A5Mi};6j9a3nam>foPA}lIW4aBPZYE`tu{kciN@RhkhvL z#H!8Q3i!7G>CTqdSG%uF6gm9<^#-~-p>17TJO)U=Xcp} z%}?kD_h)C~Z6M4&unedI#InF`YF{(j$tPi6TlX3J8kkXPpwu0R7iiR!VHcVm(EA6h z7rDgbZDY?b0KUJ%2ksBZhc&t2$|<5TOS*(G;N4xyesQmH*v>U6Tb zQahS0XlwB11nZJN>@o0~7wi<2wcZVd+EU`{g_NTkKnGkmx|>0C)jS z4Z2$d>=}(Yfa8(=nXk)SMFEB7t)yr zqvp&sfk62Ys26%Ws#_w^KA8g#W~^DkqZi7^hf71KHpyW-W*gwFu+=!lqeVfcFJuDN z59`t-zQ5ZiDbG9Ee25)!ZW!BAIAVDSo9{&Qk8HyVg%v$LjzB{I;1HDI1Cam(E zuus5T(7@K=8Tb~N7xjkth2XGu!xpqN4{|SvqX8e?Xs*MbA^)FCF_o>{dE7Is2mUhj zw>P>c2Hlxjq1QsFE?DoN9N-!ZGHvRVu=O`|W7u8U277j*ugE*st+vr2 zxv|^%=Q9xc!q+ynyjSuu_%_Th4+A<~SR8xmjc_*7*1~EbrV-Y2aCpcs)XC zLb4D_34?#Q-+9x;@vyjh88(8~Lis{2!Q;{iaKx^^Zs&NEGrQQ|weoHZ%=aB@z*U}RNpQz0x5V6c7tLiK-i;w9&0QREGlFCCZl!=UiH7xK4&PSqdRp^P zjcpyFTMK+)qXvN)punP5o(X(!PT23=?s5w~{ZH|MJRV8zrltBglV0N;mSbo$Yd4!5 z2AeNebsAl#FI1@2XlyJx8XWq+G?*`=HXu`%qwv*uTP&STMBmHeO^8EMMYW1TqF!W7VHt%KaXup7(e!DvUj|Yz_h{AT{g0b>8taK7tE={8HYv5D^EpM4d`=&M=%YEmiroWMc4_DqX^nM%YVGV~qHPAh2ss;l zt^{v5{dI&WDs5Br|$%R{0r)D}d;=uj# z?<7g&l)BX$-?b>SA08SCKOTl2g*wl!%m{`GcC$_Ct?kgk|2x^ljGdJt>31;yRZ_=C z8G{C3hBlx_w9cFoaw4$hN0=#s==U>KpzI1^NC3({7^`@Cw?Ij7wy{|%@;=^Q28a`(0J2LO?!o;ct(W6@x*^Mux#3xck|XZ5Q@HekGH zC43qeRDRW29$ckg5|Xw!n5A$L#Kf%!e)F@Wt78+yAe=1 zDFabc8L}iC;Ej7!2icw`&Y7RtjL9(M)(Ybe1dg#>M&^Juu(ak1n>-kAsW~Qmz{?c6 z9>W_LG#Z44*Sk|_7tNRgsWi(dSOh%f)Qh|3xC+?dIEVcv?ER1Q* z{nb%59RbQAFioyf9nF_{tWZs*nUVCL8!LIQ4qm9y>-d*GqZlZRo8YuIY#Tjg-h^{T z963_hvd_Q`G5XA&Ku<@AE67txi%fNps*1V`<#E7_nCUx$rX%VR8XJ7PioG}t<^aXq zSY*^y^mZlch!ZSHcfZ6)GXez>LA+f$*ts+N$}`5hFK-q3>&w9Flq`PHiW~zd$ai#6 zCWH6Q{%;*8YXB2SA2Zi|n}-yEu}182#rdd9GfVE94Wx6TbL@*LqIvpUC}%QK(}+b8 z9od?)lPP^R&PhtN!?n?{9wcKRFho#zB6{RIY+80UD_Vjfdz=hwfV^}96}2Fblnp@> z(d#FlQ(*h>;|VVw_VfjdXkk(Wv#N9&i1`Dovgg}4-W%e0e?w1LhZXX=d4X6!bZD}G z#_rzCwWDMUA-`;*L{qBrQnn>6*Qyz0;Lhl_yh;8|dqr{4q%b%P8;V%8R;8{+ zQdTfx1M4@ItCgGn`&t63_wy#v)dZ`~GPwnf<+@0II4}b&8CD_S>0v8E5fHD9z2;ut zRfVEdI5Y;n*oI^c!Mw?si1+IjDB<6Lb(Co2JN5E^^zdeN#-4zrQE++k?Xh5L0hLkn z+1pW?8ZRQnmRs;C$a6{eeG%}O!7qnFx+^7IztnEuXNiD#CMC|JH zs8_!)A=NR!AD;80C(k{3|131ozr0j0#F@YqP}_1e*MQfvQDMCJh|U5FQ0^y*BDs zWHATULgr_2I6uP(wfkWQG<>NB6%0ebW=6|H!iZ7wSiNmRs0>i6_8*SA60_XUK%8TJ z@C&SKfsgYk2kr zA7c%*3Y!Pkp${lPkQ0V65O`FnhSmWN;6a#~!=_GxazDqZstvvG>+*N`O?b?cBP1Yj zoRy+$J{M>ppb5JJ{1YS^EF{Gy*n-=q2zsm<+3U)NR~6Xp&VH>cvbyeYOwlnkMQ^UN zUQM1h5lT>!@2g zJC$=>r-1XfH>?=i)7AlZiNRgD<(Ef4!LRInneOBLqhRIn#XDFPYI-fFTDlYGW zU_%p%0%Z)K?!c6N$CPq$dTu^^Fcef!%&;gfX_Ml}@}Q}^8XQn#v#T17WJ&+lTnk3| zJ5RHUQLTeC$AZNIKJAyU{uEOp}LO4M3m_t|~* z@dz;g#MH;eWzES1Wu3*yLoRrZQvdzH22Jdf^_5j@7r(0ULH15521Tfk>aWeO*=ax-VdhT4A9rp<=iwzA(w?XU&I7W$xt zXUlZ2Wzd}lMiiT^BhVfJKSMu*KG_28bzqa9t)hOkg?&O8|_ zCI~GWto%Y-d> zWHH68PRv49!YWu7oOe!&x&FUq&T?+9ME#1yxZvk6rpKL{dqYM)y}*dG!1+&f$;#IX z|J3c`?SCr#WA~jko3BXtgZ=C0mx}TZJ$d%5jU_Lo!sGaV1{;OB^#(TF8JS(}CEoKo zzt89l=lISX$LPy&KFhV0XZ?k&)C!wr6|%FrU#XXih#1JM?=v%=b2iRa_<66>0ZpA0 zi+N^W*bY}7zU)@`NLa$lfJ39wv8|~%V8TL{LO$nA85d3Og?DTlip;Y+4>wyl3Lmdi z>rJ+2w)p>a#ghy7yE->Yypy`WCr2<=EvNU&`i2Wq`=7U6wR`pPh3x5B!LQpdUR!!P z?6OGCzh@`9PJT?Cc(UsF57+qMy&Ylw{XXv;x?epvFV!&$^LZze-?P47XXc$drln=6 zS0`+HCzr9h=-YLh9JAU8)!gi?tJg!qFTPs2Wv$k&FwxxXRfbcywo0r#pZ99Rg3hy( z#b#!T2c{_84*M`!t!hiJumo>E|L;6*8K%omS(hA{^?2KfBRgc7)=I^h@97I;%)Y3_ z9?R_)`ZG^jo=@hG{*qND8f9*3i*8JNZ64oW^EF#-cKz&!?5@%4mNVxa+j#c>OZL*Q zg~=zMoJ}w^KjQt&^how|ot#$_R5Wszt{0J?t`|Jzm&>N(Ix>u{k24gH^D120Bo&pm zb(z5b+JEc)m%fommbSdp+H13iH8=0sqe|Y-oE|MdSGsO@PKXGM-MCXSuE4nO;n|nz zOLooub$|`nM0>g6=`WEfQr)^Muj~=dyE#X0Qlq@=ni~f?aufSg4@*X033>kDSV8Iv zzMSV1C-AkGSS)!uVOnu&o3_*=kI)lYE4eg3J(-~5$G3F;Eg9$k>=jn_lQDOdgZGNV zx0PEMTf#S%8)4a44%+`u+?gG*lg{TIR^U1I-iGz~y8u;H&B&!1m#)MX-H=~oNB zc1f$kB)L!DHWyy?v{w0-xbM8tj7K-@zb8hde4M9N-Q@a9aRQ#HBB+ULHu^DJ~p;mSfY2XSweS>Lae{-ufppKbvLcr>f(+H-Vc-dRtQtvART0 zo13%uJqyeCe1Fp%%j(~`lQLe*dYu+(&M2KL$-F7i?8I3+W40$y=~i|5?BC`PNuYm>wy3J!bQ= zS+_Rbo3t;nwt3I3$3 z4j>XBTz@s26 z4NSpYkgGs^T_Z!tIS$T=1su zb0Z@?Lo;(rGfONwFeEVqu-k&<5F{pw196EPC>SAJgv3M<$7K?Vp-4ew3QU|x!Hl8| z$x9$*APi2zz|@l;nwJSWoJheCR5k`79aRDfEYw8ik8xCqA?Q34NJ{WiFb2mtqdnmY&?O|Q#r1LcuM@JzV$(%yIp&J zwmh3^%z_u`oSu_YcD7j9S@UiT@BPNfu+ezyaZaHYWJt9`R}Q<&r3T;Y!^Smk2cmWuB%ab1C>$bud2 z0xYr&EfAFs?2r>gZjA^^O#_Dy^l%e%OPrwvI@lyQvkDkL5H;Zn(ZCZ<6pSE6P*8q8 zuq=TeHKXsDmzJ+!2swocSX{tQn@Ubd`0;;!XXE6?#?HpMjg1q3N=-<3z`l`>fpfc` z!of#8DiO^MEyt||w3$6D)-wpQH@0N+b!4zf9yob`LurP@-Y1PoacMj}48Fg)-7tM# YT#{H+Qc(o-6wu$67F?>TuKsRZ07c%P4gdfE literal 0 HcmV?d00001 diff --git a/docs/source/images/daily_storage_representation.png b/docs/source/images/daily_storage_representation.png new file mode 100644 index 0000000000000000000000000000000000000000..e7e750ab3e61f8438eaec8d7e4eb0bcd1c61c255 GIT binary patch literal 52279 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 + + + + + + + + + Adjustedupper bound(x 3 days) + No seasonaldelta allowed + + + + Represents + + + + + + + + + + + + + + Daily (non-seasonal) storage + + diff --git a/docs/source/images/ldes_chain.pdf b/docs/source/images/ldes_chain.pdf index 9f7372aa5036dbd249c4f0a6781adf51d529dfaa..83ddc5177bbe80f66d3b59885863dc6be2c5473d 100644 GIT binary patch literal 7064 zcmdUz2~-o;8plOtF_cXrB8ZHIutR1hD>hJNM}z6V=w^XIu18b5Cl+=Q|>qb0El+Mp#n}M@*Bz)aBMh! zJbw<((h|oPL~__+IAP|{hSp?F+9%PczUxprXqD ze|eI9%TLI-ylLSV2C2Gb$vJh07>5sc%Mo7hBaG>E4t`~!IrO68w~VX0eaRb6YL~vX zQhK8L<~eNGZ1qd-x>A>TOJ`n@-S%CFyZ$(SJ!a9x4@z$Ic>+|qN}Ql&vw|~R}WN+A39WEw6V*hdgSH<(%A@F_JKgB zL-2b2(6vW%D6lYNN5$@eiY4Pk1zv>nhbZNraH^@5rpdMJq!$Nzc)bxr1Gkvp?Fj8V zbe=laPvK`bl^i_gdG*mlIO=**c3EqGC~gc&yTu($JE4EN{$WQ!b6M-NUa)D&Eg5?9 zRzT4weEab$xB>aIe3j7jdx|_Ml@*T)^t+bJ(l1D_DwwaenOJ#3HQ|rMJoEcsS3KJ0 z%iMTK!C*n9OaOoVFm%)8KQ)%6RfJ{7h74Y+J<&g2t|gBTNRh5Elv`JMe97qj(WkH8 zG=HakV{dMoyv6IG(c~~c+cDDySt9MJYnzAx9pVs?szQl5HG(IA`@`T?-*(9&zc@MnuV;4)a z=C@u_jB8}5Rm7F^Oo%#P6d7Mg%+{0gpl;o*c(1zP`lDoGJU;DD0 zwDrLgreH(6J-OW_<4TndyuIMQ_d^|dC5kI;XTGEVdMBo}>C=GgVXM9^)(N&YVdWD? z?zn~4hUeU^?LV8>Z%)%svUym!HQr4%FCdM|)?9Hk#5z}@7#!YT;N3z^GjP&&Bs?fw z{zs$3wuIk`)FaY$czm<89L?LwhOr90H+pv3L?`Ix=iF@4?HX$e(On9*7H&!PjIDDR zw~&o(e9SOPd)$`a^|L#>PGb-lz0>wtVo$XUKge&j)Yyfu6knYm~f?Szk7=Xo zqWo==RFq=g+f%Vu41H9DF&%`HTs&RmwFSG(U}F#cMhc9t7HRZV(9U5cKL(L(<- zD~6JjM&`X`eSXO~NGK)epHsI-Z#a3U()xK)_SWf){?(}mdmL`4f4X34kdkeFMehb- z@`0rWcAtK!c7|vxe=b_P{Y51=R*stxYw%^yFITdw-Q1 zU(`Dk=i@@R8HE`#PwQ7{>pxbuWJc!&W;$+5YYFhpi8t2vtls>};&!^g$W$wz$me9NW(G#Vs{&qu7sM{Jyl3x8$4gFu7Al zU;R6=x=*{($MrCd!}S-d3{pb%2^A&u7m+0hf+*+(XqEI%zA(YE6$e300d)YOeA}^+I2**!=m4y%)Kn@gxr6tM}ImELD z5Ya{(9)O!Zl~~^sa|uo`LUB)JgiQf9xR00-6@WxRH4`K1Y>XywAb|?KV}u6cR7O}x ze(a3s03=#uGclsi#t0qyv^bhLIVqumvE})ZGlD??Ic8aFNXyJ?4IBD2MwoU@2_zVm zQc>FXw~LKDgCHU2FuMPbAc0hnN)-vx-xmKzse)kuIcCEL&xUWpU;eTTF}a_L?>+VW zW5q`X;8~R(X_+PZCcE}K6~i2ID!%uW`i~VK6@X_o0iCiq72$TyN@D}Cbe>$NV#)NZ0G<$T?10{Nm0&&nAfx*$VghXO>FGn>C1t#Xm^p{bu4C`$g2UnEOG`anK^ml{fvH_W}K z@FqzdWsZ51FwLI>-q;Y(VId$Sys_>+Fz*?%9FoMG=9)KV5_7?Ol9f#2jdu58d1G0{ z)cBUT*`PC*IR1i);-|dR)YtOm@MMd;vhl9(yLyk!6CooT>lmK<>yHm!#O?uPz7H&+KP~p?*xa)gN6=l-cd4jr`Rx@Wzi_j* z=mlw6-zly7R&z`2HSQ>D^Kf$#^LU%prjUvUY31RKc=pGC@ zy@o7Tr-CysS}c#Zzic?RXE8r6AhGVo!|3Js9`l4?HRTN30ZPm7=0=5Q1~U@p6~=P4 z%#?x5aD}=ihK$mRFlr3lyTMX}qe64vwBYLzqXOlZ?J3+UFNe>Jt9@u@l*>-(QAwWl zCl|FU(VA=eOqis`&t3L)E<5{nS=g6Zqqt{Wf&<d-TWQM38|MvoR>Q%0OKQ$H;5+M$($*$P`0e#-5h{S z$NsVb*aQK{>$zx))1AjdqEeE7IC2Ac0C{?ru;hM$V#R9Zg&ieMF(a&>Mo!^;P6OdW zhDIXqoU)g29$77RWw|d%KL9+EmRlrad%)H;;LfohYKI3`>^Hd>Cnc{0-aA^>+_yTC zl)m*}6=_$M+#?-!*%&$1-%xq-?W!$rViK_BM@wvcDO$Q&!d7dOTX1{2LpF)j^8qGIMZV;IW)F4vHC`JgZ^G&7)gb)KXK<@1lZ2B9f{$%3?QO3W-dbzac)KpK)~gb*^acZC__#$^FW_mBfU6 zhpwfZ=ZYuk<6O0?1JkE(9_g&Ik6(Q^VbA!;8-Dh&ygtN~yy}YG@KoP8{&eGPPQj-` z)@_5dJb&La#!Iyw05)#0D9z>F0P|Pf9H~i*3musv8DO;$mwRI*=XeuFE#7=E* zITU`ostz_bGJCIr*x1;W;XqoT1$()1obdG0^VQL8^c}=ne`AfqGatU`;eaH~2o_XU zS8hNeJtK>&Zol~Wn$2D2fB2zv$}g-)qvyYchI&ySs zBZR?RWdzk7Js6m#0DYmtO^dR~;U$!`Jt{b}`Efcn+MZXkd6CIXTDW#HJk$a2mA>?RU4$%TOjn^`&WEEawrf7-{5=}O zTj#)ko%5pNMQmO3>A~#1S$M{~V^#s^zVn{V8o=)Sp&NLnH{Zu>=EKFGASN0lJbRr_ z_A8OcZfv8|v^iGUlo+*-|3oG`8&1MU9 z3rtSW%SJfVb+xxviM3~Y^v1LadOnegv8aFEm~4DtPgSHI>D5{xd|B~vwNgr=$0z7D zhyA?>|1iJPj3|HK(Ct(B$zX&Qj)2?VaX1{2KnA|JNnkBf34AML3DRJS5F$7vydN|~ zFckR=m$3_i12HOogL^86SFvCrP%>tr7B69wz2T}X0AY`pCa%|Dn zB9p-saTNHA@c*N1>0*eK$NgInut`Kg>>Dny2AKkON}yrHtx!&&q_oUV$^coX_Wd*=M@=O9p^8!VY!Sg%xW5aQ;Q|i|| zPSBn_=nlfXVJ(b5VAhOAT%3Vv7z`x*F4eqF>TdMFkcUInEG;jK^<2VJZG$L^k9fJQ zE)@03^lD{=hIWffk#n$nc(c-fb_}3=Q|{Ie_j#~^FO58M1gGg77vYc7baV0#*dBCE z&>JfvNYL7re#br@6z`7%!1GucCb0b=oOZlcVFBSdfV^Yt>mxqDo7iGZKM`qYCNZv4my6Lo+2^%>yWaaund%kyS zEsG`3TRl;8%P_!9{_JI3t$DXJI~aw!i5hzC0aX^`iYn85;YnI>2@fz*R!)pWB~cM7 KDrWZPh`#{XGECn9 diff --git a/docs/source/images/ldes_chain.png b/docs/source/images/ldes_chain.png index acc9ed459f954dc462d8e61290f00cbc129de6f9..a2884a6b6ad5fdcc5705f6614f009b341bfd2afe 100644 GIT binary patch literal 38206 zcmX`T1z40_+crvfcL+!*NOy;HBM8XQ-Q7rcr%FjTNDa~*LyAg=bcl3GO8$%Y+27{C zJe-+zueh$WmNDvT^4J&@7;tcK*oq1=Z{gq&j^;|9v&XoU!>gM{+Sb3ARW~d)D`p?XklgbHb7vm z*0`IRB0;XwYao_5Ln5e4@%C45X%F*`f7PQ32?-h27&kjnkws2?3D}5XY&*QulHlCOr4mL`Rvx_^ zv$wN@+DsHWi9Et^CF0lC)-K1qk5>|wmJGfeGhSelvdgHetKV+7dmZ*APzu}_c1pdF zt}n!=FAERdDu3PDLN@ck%|Q9PoTnnyZ)Wn}cH~6N@R9Ux;`g$ru^s_TI?Gk?H`@1;CCUl2&MO_Q#xoqcU;AzD)7bP;wC-oC^&9s{IgFNS z_nRFTOSQYfB*1HTyR1tUT`V>`AM0G;O58ywZm2}O&cEE$JnZfL^FCUt(C#+r4GlEx zwx46KzWH~yeYJnH-0p2Z1Jayz?@Cz++zs&&9OwFE-uf*j)zf>?&*qv!^XMqlS$3Z zSHTr|BHrx&{{C3As{z_I-P5->H*fEckGhyq8w_JE&dw;+FTzl9kK8)Dj&+>7{#iBW zbeHXIkLBS81qFp&cpI1Oaa_Q|!v_@Rnv(fn%;*SjI(J^YYrb&5(q_&-{PufUhX6(D zep$!rM*lu9>Hgn03+Gx~v=e!+3u1=U?4FswXTx75kjrdQMrmCp9+qAjcpo_VZ`aI_ za_XGGN>~o_>J1GzZGSQO{6gvZv4HuEM848!b?$civ1r-war^kR^vj$L@Ab`o?FF?t zI7iVkbi)?h)rfB^i0D#=O%TI9!UxQD<6{QQAiBDl1(Z@~Tq>(qEG2JkPgFIfgbOEZ zde&V$1~Vm8y{%ZJ9QFuow#~CW+Q;V?}IcQ{cHE9Je?X()xq$=JmX*w5)GMec2D`y-@&^+^c zynk=P%6hq4`x#FPjW!%_l8u{L)8%CF<+G8+SYO) z#8_~$^&NsXGb5rwDGEX&8b5+xHPnV48Wq)esfW5`ptHo(9kO+n23wrN{O3tN{6$UH zN}IVxhhg2Sb6vaX*lX)j$e=X<$7$BcNBA!lE7=W$&$GZG+yi+gR)YTxL&}5q+a6S8 z-}>O^4Y@3KWV0=2|3n`#y%_cD;%%AuzuD2x%Uqzk4i3w0!~)-(dse-euAfQbdOV;~ zM$}V#0Roqaz%f5M$OLZ^)C$ff& z^NJ5FWBC7OpkcIJrFZt6#)a2eKb@q)v|cd!JUe-ydBuFL7x;wt83MdHtSS8I3g?G)#bnX!e5I$96@8j6~GH{x{xkN*}8?Sf!|}J;scIMLgI|61yTnAO9PEveSzc0aM34(&&E! zxW_a>g_@EnWB4YYAN{L7H&R;X*7W-?rmvNtg}oRXM54NShCfFT7bO-YmSkaa7)qES z>cbBiH-tM(Bt&lKvX*AzFRexhdua6`Hq`xZek_73(%+fe-{8(?T+)DTCVY{hp01HW z_?KxTG`-j8_Y#ciGcG2pjGwA>!yNDLIjgmyPj8ZwyEUDkf2t_H-uPZAnAVM$_XC2< zp&!KKvE=@LE6)A;6Cd$LI*YNn@nxIZauV21Lw5ylOirQOYv!ajp*Vi&uggrYbq>6W zb&UGvwpV%@|6=;?*Q6Tv6#k$;ZLWBfHaOuX^#1k#zvJYXwzAXaHjA;T{NNk)@-3>_ z#meP6k834S@dsiEMwRNg=`qO>KMEyDj`l zagO}|jWHlzuShEHEfyS}OE{iO!m)-N8hHzar6(F7GExTk<6%HFl-8;5C`ryVMoJ5kElZMlXvILqt zDrx);QG}30Q=*sX6?Z(XuHVM z6vSQ@HG@|pG=&9?gErN~t0>BSc|%3?MiCz)vSNe}BqBwUhK?-fPF*+71V1;cZu_Vz zBU7*Pkymbbna9s*@p$+={x|(r#k1v4gYdGf9%wD3SGU(%4tzNOrmRrg5pG=LkBmP? zu-QS=|EbrVOUwkm>N>!$!cS_LhCMa6kJQ>&HqbG0LYO6ljhf~k3U!PR`8x!CLeDt~ zUCe`%v8X1qmRrc(*;1CU^Iyf^syHfdKk<5cp8p? z_`Ni@k7CZ1Uy&J|j|N7v{GKX`3Y92ny)^XzqBu{l)x_m!__?g5YQ**SKLOW5ljaFw zartOVe2$HZ@@7*;4_*y#L>N8H7&HTg4p$#8yOLDBp-*G|y-nBs9o2`$R;nAGZ9muL#9me5J3UQ|rbr%Ol zSM=WgeBXrZ}a1AD??*ZA*h}76zHc#r6{2f0LR+>=(`&nc^{&cQzCpjsq z+ODZ{mqn&b)Gb0HY#+`}r#gxRFZ=VBGJ}|EsL>WFHm- zA$Sm#abPJ*(zN|FpVf&|FA%==u|M@?XYB{P!Z`Ras?18RtL6f^u)_Kh5%G*mLVh+i zsc`)UbP)z`LYHs|pFM6VR&J5INbq~WQc-_9I*ZHoAW0Y> z019gyxOarGCAljf2>?Vi!d}wbjawkis`ONZ-rHQXChU8X=9}{R(iBZH)v?_N&8K%# zCnfk}zme~f&hj8MGyB&_etq(rr^P7K0U9}mzcztiyOCLbWirytZ|dET2by)zfYZ>% z%mkBqu`Sg{rq8E+55MM{&bhPMmVZo}4()t5;Q3#QmRpPUr0rlu&Se3UzKhsx@lOk zHLCUpUXHmfG3n|0i1qhz?d>Ooh$q#CkBCB(?SnB=!gxU?QnW+*c%V!a4J2fd>%tM2&u>-(J1gopZk^4jf`wLTMvJo4 z4JiP&3AUA--ka*#9j!wqIn9P}X(Am_3cJrBrw*#~w5`TJ>2U8voJf71b^WXhV(1Dk zj1=YZurxS+u$2Y4^qh7G(`)^<7}sO4)q$F1z8gtmK!L}@^B5F9ANRg)=ynPg5(d_l zk$QTByjT2C(yP4JuyXLmwD&N86Cf>?3|)d}%z8v-oqVD=G-FBsL@vcYpi2a1#E38~ zTejQ^c8Hy>3U5|_BkA~fQr`P&=#P|X3V>_7C^KwZPg~fRH1MC#jb3=nU{*op(YiTl zv`FI zZ(A!7P7kl|eFD!{FVu<<0=uQYzDIidjX-sYiZ&oh<;B2Qg|XSCGwpnO{mR;2A3z7! z4uif`hAs$Qm%T5KKAabKtKP$RT}ldX+P{^M4>T+#7oJS|U+HwqyR@o>ffnXDSoUvh zNZDM1OIltmY7F1Z@;qw(>u&-nL%H2*Tbt?u9zU}uL{8`}uW&pV+*@}?l~GSiv})wD zxb{htKQ7@H=zU%C^_+~qxu8AVu4Tn#x+hg9mfv3j+EndYq8HMg=ks+=Ww-2qkGT{D z`o^k(kFxdBuSqJJH^z(mr1h;j(%DhwqaQ4uD&Rb8;!oF9xfonE(FEgKf5*rpwA}#q z^qfI}Q+zg0%s$1%Vb4ai#rOSrF>)h@-gp=PpSz>Eo19{&1nLD0~j0Yxg*{#4s4^HjD&UXe3!EQFtd4U zu{_hL`hTAmsCG~AwnWBWr3Zf_)ip1(g8t04$z!M%m(grCdCND+x%EM8MdASoS#I)J z8*reB5o`Q*c07PWrK>f_t8)HG;NDXIkjg%s!sASPdGO);D~!R#X5p{Oad+xs;Jodfrv#=kPXzt_sm~~>sZPJFY~H%_uhma+WVWzK zsT377qJUjO>AD{VrFU<;g`MNXuHqaI@zi;a~3!xkFDL zkLmwFgd1*?uq9@`TP7O7mPLFoZ$GWvYZkUZA!+= z&tF(oh2_@zjE|2`y>jug{^N*+NgV{pgm`F3(59wH1%}YDFhro^^sG0qiE1u*5K>M( zgi(=8NEW0~28h!RA&f?LM_U)J%w(D=4CkQ>N{JF)us@_+ht6JC^aTu8s>&y8wv6}{ z{#Sn{QaY-I&DWjG@is*Ju$IrAFi|8BqqXKUnw0Dfsx{Vs6rIkuT+<;?!M;yZ?H=## z?WybO#R4&`C_f+W$B!T5Hb;&rFH);;^CWCwhbNU;P)`EF!VWn72FChXV$ z0}+j&FZSnB($XS7fBu|EGmc)(%H@P! zlm9vyL1^?Ol+XKw4E~N-1MNdX*q=gd=4W;$#5Qwmoyj3_Lj)#JQG(V!cfHN_ud^Ef z|Aze7$fzRy4+)TFvk4dTkPt$Lv2xDE0EzM!u$I_pPLwQC@$+4)`QC`;f%U{|o<>n? zV`KB$&5gUpupOmj^28`I^2A3}P*AYv=T96jFE2cd2qx{7o{BxHmbcy%6mrY!LNf8# zp%&&`5H1XZ(!vR}y#FC+Zc7$!8FzPW+`I5Y5J^X0Nv#Q&=8 zq#_?1F<>2~JmS3^vtZY%8Z|vU6`0%w9xA0qsr`8!>($_9N4V-_rSmT}HG?A`8B_A| za3f8H?**-`t*@`IdlnZdkB*L9JUo!%20~?4!ovjkP5lPnfb(%Y-FhHYgO-*MC9ljR zh+-tC%s`;PKmfP%HZOchwSV5^(F8|s#}E#Wjm`NbmX^M((r?BACPH|3cTibwda?+e;maqA={fo3lB-oOvcE4NL+rQ4 z$MgUC&u($$*0$%MoZuTyX~uh)K4JGjb)*51l*cJJ?1o{Ox7Ox|p__PaY@k4Kk(RuT zi6iCM*cgaYXCjibZ#7_##HNg#D3XW$_@TN_hKORjMOr6dO$92BbX;Lr07u}q!){{9 zI!hhXLFOf!;bd}U^X$L?@@N{Hw5cgA0Re%!wswi;)WSlnY8JmKFkVhh3v|(n&*oWi zfXK7kQQ^hl420mPVlVK@o>`{xchf8xssYl1Y(_;chH>2@ez#}*PcMciq<^zM zaD80Wxdz?c`u17_0*OXM#mTR$o3P1IXX@XXDB`mEP6mP4bQh@8viCk@W6$T+OKz{G za^WAD@b#dQTw~bp!z3tum;LrKh2W5VA{;BngTCW|nZ0`Gdz`w$_T(PVwVuJx%C~ z%b?!Uwz2%kOU#31T?v@lPV^kj^(5H1xoJ5$3BbrGY;2q{!A=^I_VC~xOrpUJ$v?!V zz%G(g`epm<+j4k#XiiS96$Tu&Xpj#t_JHx9pwRJrPUx?L+XvwzGEpB+|9}7ub@hCA zmFjoqi%pKvNlEgrU%ze^W8CeAn3&3~NmaGqa8#cbyO;F{Q)+oF-#;^Jaa zjhf#ZjRd){fZI#ct#7Hqn5TG!W73k!o_%IYx^!Rkzpb0?P85x){>N~_vo3^$&H3%D zc|0bA-oJ{Xqw`=2{C1bg0kCU;%qxgDi$3Pi%8G2@&ll2>a>F)N_N7@>f;!~gP7Buej2Ef#g7dP zBzf5gukus{hWU1Hjx=^d43fANINCvM&xG*wY6+z*r=}!ZGHf-XgTb%Sq<-hEyX|aG z4LRhct{8=$eZ!z2D|;31CFsYGv8Rcs<`w;WpWb*TQhi?z2b|(Dei;Q`-X`*B_@0@a zeK3Vy{=A05H|q8Cp7Y(Q^#kX)A_0Mo;mqpcYQ_D@GoWRe1Cj*v@f^L47;wd5V$RtKVYswJJ1L)pHyYP_a zH-b6~WrlY@R>JVM@vU}}J<_z82Y^4B^5FwQqn>xfTNEq`!L9Np*4NeAw9KDlL)Z;u ze!E_i9TOtn3L8U}98Pwi#Aqj2JA9I-IKVUS9~dw_Ug^}^q)0$ve3Q$osZ-2>?v)r^ zIrAK7WeZP=CICw2zCEGTen$T_M$~VgF+2xBJGI)eFnJFE{XE9uX;MF_2TA7>0ZMV) zgmT|Vi*oI$LUlb-n*~xvEEJTKqyUZ}!ibpVLc!W=DJfsuDu_?VMsM#r4AvTpIX9`F zk9MJn1Il|ec5GBw1ZI=tVx+;~wYIW*Ty*qnHMPW_q2j>fJ~=;s8e*+UNQ7cwJydK{ zzWS6$HtN6Q`p2WaRl)juqIBG1M&E|%SZ}Cx#8sjMd}E>!e9ix50p$Gju|Y#}=IBTm zwJbY54U@RK{t{el&Yg*s&TjZLN(*k?TR}wZy%tNRElV&;WODtZgS+VxB4Nas2KB;pLXzQo#A()VxViA>FKPb4Vh|Er>We3XS3(X83<%}PT5>J_?9je%|V zhjOb|8ofW{g(OI~Iz*Xh_t#k4?i{1&_$^+Ug_6MLx{jSKoGmRQUTK!Dovg$3Hknhu z_0TIgGp3Jf7#k-=MxuO5PnTvT0pHEtx^$^Zw5d&o{1X1xoT8$lJzH+;ySwNtEG#~L zez3m2Ld`M0L3?H-1N`4#Bvu^C)8Ekp52MeZsO>Qh@xPKSeN)4_;BKg%@N!Ck=XJtG zZldF9`sv@0e=Qn*hTAPN6Y*ne-Qi)al&8H7d3XmhagiBPva-nR#$EB}=N{!VcEbvcX5Mjl7EZ9*7=u!#5qRB z{~8lQeh(524V{YKn#`%g-@nV)*)e|`9i8Z}kwfOdB_?@azWHhI-j6Ht$HwzMF$%7b zI8J&Od;?aog(J!7^CLgJW8$nIgP&e$LP35Y$6Q-m`{e3MKw77tEK?;iJ|64$pFf3w zT?A+^)*#86gLl?2GD=iVXYXBEp%$ecGdW~f70iM9+{{W=#Xp>M-HtyQ)Ib1{aWxm` zjlX10{P~W0t?vZaebODQ*GkqMmAYMmSmWw$=ap);hN<}i^Rw^E(WFCx@v^34!LZVF z(W}bRQk05{iWXln;*!0liV|Y}_coRS-gj#f_%7jO+dPOs4K?|?>Hx$@-~7!L`kcU}go2n*eA@Acay~Qc_S}u5fJEB?jUt1@~94UcG`gH%EoRfU^Jc zW&l2BA!($dEB2*sK+>H=;c+(5Kcn&AH@5k8{u2pD@Q6#%MaGbOE_a8Z*N5Ty)uU{s zQWu(2jxc^z!vr6FLIqC)o%F#^aBZ%Y&D_8>CaP7MMDWPzqMNe*AoU;v|MJo zax%m@!hu5~T1mar;tV)-bbP#wlvL=fkFD)1EoS0t|E^47`iqMT1!ZLzpi_%wS)Y{y z1I7QIopCuX@XE-_hKy~)mKP`=a0*&<^OlWUHh{RSl zkv8i*bX91#sMJ(v1mcSR)X1K?zWaaoxlhk?QMqRQgh8!lS;(qGv}>dga9-)Ju$On~ z`i=HYP^jE89j>q@Z&c1C3Dm8gT95G3VT7as@s;Bv$qpS@6z))kW?2JCvj!8<@V9S$ z(fH@i)5*Da&F;ICFP1vq6H+9UZf>*#_SMqb+B-6WetCHbt*;LQ!ht#yQWUJW&U{E6 ztWyjjV_#n%0yZ{wc}Lla#5B*b}+d}E}3JjT@rv0@FwJ0TFz$V_V5dJg%=0j?k^D%HJ z0AT1#rj<_4%&g$c&B{_Xod^fwgUhYgV!$pkGICBEY6@)qb@e-XW@Zd}`NZ(JxVQ;C z79tFII3pt?0N`Bw*kGJbPiAC9&CSiNuBmB$@(hGUC1aIU!L0sb_xiG&(q-nC-rYKIa>!9AZQ?};*mn=_SkR6ML_b znL5cDnT1cLfH|zuxsJyjI}JAoJt^sKG#FwbTa&!L(=fSjK{hohH^f32>LCz##j{r2tK^C06^V-WQ^IXw;0VwN>EE$D44<$lF_ zcrYG1c*zx^m-zjQ7KoILSBqVIgEDC=xfGfRs1YAY>;03RR$>vk5RB>RIvS6%pF-70hgtcrEg_A0eFUJ|ElNmE$$x> zTI1j+X8JIv!v2_p!bwYi5 z%59ST_H%TA&_3{~1&WoHOQ6R(K;gpq^i|O&naHitb=0rxW;-pw3n_nTephHS2+SChsf))acWymp zo#X1)c)96xi_azzj-`XF(#$KZ%DBgj4~r4O!&a_%Hk66GA!l4X7Wj7uQ4KUKiVL$p z3~>!;X=#N`Pk(m0H{hvX**G}#1AznRH_i=-W83t?!W0t|6NgvipFe*5NSN#YSCQf6 z%Z+$FDlsO{KqwgUbg+wcf^-#@3OAkxTCejo~MO!9tIZfe_ zb`cSx4o$Yzke{n&o2@lmOSiJd*Nwzl>k#Xc%oq~zPT1Rw{B7$Ic}P5facT{K~` z((xV*2j@teHfO-hbfLkPjMoP5@@RRn%lFI2Z~A5Y)pY1sWY9KY#~!r$$bo%g#p}yH z5rxixKe=PQ2+GIU2Zq{HZ$p3;2jy}k1||dy;9NR>L23j3Wdjv7TEvN_?~l9jvVN*z zIpY&p%gIMQ=19@F{=_Vdok<{5(DU;=AU9&k7Q&ZnCL1Rknmi6WQ9zopxLruUZ8K-&vG-B-f!LlsDA7>Y zzLDg6dzQgW?2ox_80aW?q#anm98G*)=0fPbRI0cT9H!H>uGK4U!OvKLJb2vB9X@)p z?u-v8Ks~338Tp+7LS4YE*YD{+!9UEr-RFvVSlQSB*#qL!OV!U7rHMD}k*4GG^IjZz zb@@Bn+fh-}zGy#x{+w^~tgKjQ=TK8qgVdQJ&(<2_g4v>M#M~1s(c^2Ku?-MmT`BKO zY)%pny=zk`@&vg(5OIm0U$aE>rbHB%hl86p?4%^$!}5XL0QNIuG-g$|=nQSbpNFl| z62bLwxJb+CqWodYMvSrKd+Wrw@pku>g^qDVqz2_-0hq|KH{J1hZy!SBqq<{3@i!T0 zZq4J!1Fe&$V3H}M-AF)0w}tklP2E2Vy5*lUc6cj!f5md+{V^*w#RqZ^j29nPF4RG) zA-$d&_(#td{Dj}d`%`TOn6-JfrHf|{=+s>;I4iJABobJ%^Kw2c4B*)d()B&Sf5*}d zpU21S-NtBZ)pV11nyf*m)h_G=IYj;}1b^$9>FG5Pqb~pQg&SgSYa5f1K^7hnaWTTO zlbD$3b9Xva=d>(5|HZ(wZ)3zhigPB&saY&f5w;Psw0hDTQ&yl(X;jL;Hp6Ts)+@@rPexN~p#u9lVN;sqoC?fBiNzl_(OjOz z4#{;ywyaq$H#O^iY=B3tagsIb4Yc5YVb7MZN^B5`t21LF)21eQhxms6dlLWq;~z)} z%O^GODxW08V7P^wYI*=9L1-KX2!6pk%0OvLaH=x6%;jn!9e)CW5N|T_;f2Dg2Sw0| z$)=qK0kAIG95L!g`Zj8Hx&{TdSGffbr$?FLYTw)uOd)PxUAKF@UYr?vax;OWXagL` zwFK4q%({gg;x{oJ=ufM7c}{aWIsXP~Gtbiy%1j%M1xJ_r0vO%SNBj!7fHV!Pmfi(# z%ROQrJH01Ke=(GAMjpu13IwhoiBqD7_eZMVF$11~Kq98`ZH=?HOXm(Zj=^fY@)o0d z;cx`S7r(t#5_U2x5t5Jh*3yPAUrVm2_9w;2=R2>7x|$DS z4(M&G`}Sp}gz}p=Z@xd{!L6`e&=-yQ)i_^ojceq)TXM-JcqE?`C5wX9C44I!*na7Z zh<(D@;K{s_`M@WI67`vZ=^+!u(MRcx`u;|zpB%I0tq&irs{d>^<(%jLws!)OUk;I)2vR4i*H(K{88z?JYINdO686w#E3Dx}Ci@088*2+>&$~ z-U`V1srG^*Z2I*W#PiwQ&=ZXo6Q=&5x>i51QkeRD%jS9(87JBCJl-WUSO|X@V@?QH+9-y^D5)F0OqmU1Fop!oyro>;$0XXMekg?$2l1a@LEnkdT(R)8$_8Tq=DHTeySsQu^-04e{kxm4Hv})>G=+z?a}n;tfk~tZ!KW7d43K?f|uu2m=|gz)wmq zz|Y_t{PDM&kk*$bflUi;a*)9Pq;xnSdvw6)xozOq`fv=hlS4+HdRI9~`9^&C!kjJai9t+EjAB3Uz<+RXpl)o83%&@wtbJLboWoX}PSZwn z6zR}?T8G9yK>ncMw!*D%A~j|l$eo}5+D*Tp))&9C?BF|H6t5Gl2cqm#k}Q|#tNObn9_!q;wgr2TwPs#*iG8ZFFm;s|0hkZ zVVEJA`GrlYGVPSYVl&s|>#%o?NO1X~g<{Z(c{fgz9!{)JRZT8srndPH_g$QPTI%(m zx+T=mvG=cr>VA*sA0pr63~{ldDD4=B7mGCfetf{M4xYgN+1~a~Xy)qp=GMA*{&~MI z@5_G!rkCYDf{SfUj*c4X(zJDXn{KVbSwq0H6BNWcus!j9P*KYkG;R0^gCT+&6N9@` zWg5oLK6^ev88-<_jzjbp~fIzqpH8TH-A*!v1~xP^#{+ysaU+}s=Sbf)2Pb2c#bCs!2P zXgB5Su0)fxlKq&Jn~t#`pMRSKW{0<#Ukc3AJ4^i>gI8fH^btzccVZ_M1tueKoa#^u zll+j_lHkaaNQ|8M+O!oo#$siN2`u3-N+EqDgS-iiP>SY&(7F8Mk+r#bQN6mdv@|Rj zI}UJLaFM9DTE97dw(ge$kg$n22NNh=oXd9>HR~c~`0FK$Cf4?5Dl-6c5X7BWDxiHlo)*;L#zi`Z@gS(= z4NmgojDX^CadEi-jZee7Gp@a{`6q;>to8nCWMl+5QT}D6tNT-jrmlc*x>THh`gskw z^}h@$${ z7mRm;)&BLzj)$bNE$qYY?z8vxRq$rAgnC3j^aM%?rEZ!t*^}t3cBH1ao9F}>Nl#&$ z>stz#zf<^cNa$^C#yjDrj9(F96qlAh*^f51Tn{MaSy_|-#f8&KM`o0_uZ+M3Pf}&! zY#beBB_-iQ!`i#5amRm{)`8gUDq~PN&ym?y%$T(UT$JNiM=I66Sm!XZ_8}A9qnNC) zpBq*mkEjzsJ`GZ5PWM3EPDSWX!!4a2p6oZlR4FZOj}6R{iE+I!VO!!oef#m})skUV z?^y1Z(S!Rtd>r6?s+xqL;P!@H2@1doAkFL2Dhh?LLR_kP5Gd&qUw|O&yaUd)1N_(I za`&#us%7YS`!_}e00yBoxD(p=0fm?Y&R$**t;CnA*ZUBaOd$CvwaFZV=Ep- zBg)Se9G6qC;PJi_1PA0frEx9#$i_}&(XgfGUrB<0%&y97Yp{L$`=w{yZH;OJhmuj* z<^9dAjjf&RQAv|ykzv5I_1~7x4M`oN&Ci{Z`vxa4sNvb64SXF-0q-UGm@({o2wm2} z3t9Z0UbrgeT$BD>qLB=4O?;j_G1m((`g|)<^mdlyTF*WRH)!V2 z6l$cG&^Bww+caC))i}78CRCgdZH|nSg{Yj14IH_u>n0og=GScIYeyUKj3T6H?@91Z zS-~Yq1Q95t>QWDG_}j3Yp*A8ga@V$wu-A_p0e15_Xd*p*=TGS}@5u2mmZt(38T_B0 zIZ*{6FyP|$nxD~b>>88!4<%9!|NJTEZy<_*h=|=)4yv393}czphJ)i4^V(m$#<)AN zGs17NOgJJuyk~ay-Ek|(r9iEIP+a@onqHr*M<*smR#sN_N(_OUbonECi3K6+8A9$a zpPYuxUEG4Fq2&er_X$_wr3HmbW*o`QtMYFD%svH!O$)pMQzn04HFSYwwNCYaFh02+Fp$}S(`aHuvX*vkp@hu zmpB|keZYq*FnsXS+bLb_GXsL&!Pu{So-Y6EQ8Fk&Q$t| zzP63CPdQ4^yq<1^0Y%cjlpTFH=(EKI@RMIxHxTf#ZIwG#$Xp!L*z0}MV5yc$Emql1 zsCtOS#%aN#5tTz@_gUio1?R!cR0IA6bLy8V$vTin1Ilj>W-Oyx@X)5GFcZR# zhdS%4S0Q})K3ef=lbb39)X4+GmcgrS(8goH%c{GN;T%Zy{Q^WkzkDMm!!4zUzT z9I~>qGKdKQvPpg?E~Ne|F1yDXeX%(SVc{KZdL08Ex8rIa9|bly4-Y;S)$-Pvw?5?V z)s|)si`^w1BZ$CCdW*^CaROt&tKYcS{njkSxUw^d0THE=y$dz-OXC>FxwOI?5Em=A zVV49eoBH7`xZDP=KuD$j<_B8tVXu14QEN4!N(`pB4+VTnJe)sT?@U9$Z!X8~ZAmzB zdZcvx;Gu>Y^ydiru!#CF7SWu}HH%FIKM_=jzCLVl5QU$gAKK915VRh|_?<1MohT$E zgetNc!AOXLm%ByJr?Fgpph(bByWmT7U_MMto`Q%ZHoLLhxz5q;=k*g$W7RX6EKxHsjC3LQ<1|PF`7s$Ut(}+K>maO1C@5y&?SY%s4{kQA%vj}_54lPv(AoR@`=9gjHfTz6(a{x7NlwhnG=kOnZ;im~M6hDPgFGpUR^Kz=0bK~I z+%g0c58?`_VB!yc)vq5P*Lu_9osf+}H5(NGvsMGEfu?1D8|;G%`#ya+VW5k|3nE zyEe7|%L4SYBhcPbU*-Vg5L(|HR#Ze!K|!IeqZ0)T_2;atSRms_1gF|F4)7fnifkQZ zN&JErTzRTU0n^^3g-zWQ-(Ha+1YERB)Noz!8A_H&5?o_ z5RdT1IS8)^y8pqFq0_h(iyaKzxVhMe_h4tLG3ulML=O!Ms~@oCgf6Bx3JR}*Zd_Ge zjSq^Nv$OMOU!}Ix&dyFXNL5YEk-Mn|dpbQE8}?IwnU1Y-;HLz*B!knmFL+t!uhB1e z59jylXfIm)>@9#j2V%9LczNzFT~Uz`+X;DD-xu;wZxXK_zmqs*7MBm^uyzV9ieLe^ zL??wF26lB!dh7e{#u>klQ_)_PwUs;r_ume?m9j82W|uB+Kc`{1Hjh5g2eSfm(M+ zbKIe@+Um{-jK8(LJtfJBa4bXJY<|bj6BT7XKh2ngoXxQ;Au;;r+Y)j%k%LJ>kM(5iTm6(V-Q>Mv7c;y(mX#u zggs?j#6|yM0qcNkLSR;fil8v>ZS`x=i&>CX&?5#C-gjC#zXmF;egR@On^?Xbik9kY z3me|ZYpk%i5>$uqOP9Ly;HZS8**;cJPtSSn22A3w7}JdQ>P75r`&C!eM7pdbpir#u z?Ztv>J3T%9oShv9cx5fy*sh9WZz)^8+Bk4g21riKoAHA>3A{wBpV{aF0s>)`|CXtU z%+1X~IM0F;Iy*CC3h<2~M(q3d@Aa;jC@^Eu(b3o3TB(dQs>;iE+|*f_nM0p?tZEj@ z)5|4Kzi09sO4b!slno3F97>*spi=KlPfz8dJ-x$xlV?`1JHAkq9gG@NzlN zp9-{)7dnr)O(D_9Br92esXkF4ds)`Z2$#;5pWGD4UO!&0hzKVhh@J(uQ3`F34-4U^ zpdt051;hPHn1Fm0on`hZZY)W0JhVGZeKxq#IJbZHzNAs-Ys0>|Hczn77^ggE7&($8 zUJ9BFgPYp&&iOsOb{*x8(sPQCjxizO&w%TB2kXyV>5RFrdLJLJ$SA%3iII@JBc0l7 z)01_|-;mHHweKRfAV+cPTa15Lq)L|Ik4PWS!q1P+;F99o<1|ZN*Q*$f5iK8V&*`6y zu(r<{mE;b0m%U|mTlgkNIAUQ%&!6D_7Ub>>q1Oj{ds5QUh~OxEr{nU_=CAvpRC025 z7G}Wybm0*I@%8QPp%&Sv$Zk&$9Pot|Im)$J#p3FRQDT8n26C4f+1WBmN*EkWfu{qc zSWJ@>ng#h}q@+XWv1e4W?A9Mq2J-WtAI#Swy0vCEW?*B-a%aZF%Ql(ugYa)Y6Gkv} z=M{D=s2?E53s4;#3v{K`9ktncH4@Z9pq6nkrKP1I;NirA|5xMx74{zBRQLb?xGlSM zvO@|6QV+rO$Z$-E6JYOvNI$6o^SX4`COmte|@j( z-*w;J?uhsM^?tpc<1wCZB@kV@`bE$66yQBjaoloWu|jCHyz!fl1D%~=eSLk`dd|U) zqXP-FR$X#kozn2q%Ektg+P1g1{BuCcZ!C8tLkr1Q*JlahZNxpJIN*&Vt6dK zPBZTBseBfa=;lXbuebh^oMCfOZ+1Ig*=W*n(GdUir_2ZL+cyfIGH;xt-m3h3WQ;q? zs!VfBhPu8-t?jR8ys4CMT6HuWqQ8M}Zf+d~QJ*|ilJqe#F>E|M)B98`m-v}`2L@C? zC<>fCs7J=VZbo*;_NJ&^NlrYS{KYwTNGaU}*lH7;Wa(AJh*vFmu{=J9N z+G7S(L`1|3gV%%(2a1p}C_UNqvNCg=30pHAd{n3_moFbae!LYP(1;pvAPY&N`i)orr1z&~+**DvBUWJ3EAl z3!a&A;8Fe8ZFPm-4fi*#moa6f%Q8PzRhBvbW?+`c=o1u0Q%sa8uzk?R(WLnZr>! z@EBAFH2F+4hGoL5kES-uFuqo$RY>Hes8Um2WO=|_=C)Nuk@-hWmdYY-OxAKYPVe(mz0!1(>aybt65z7Y3giS zPgQV+@{3VQBFxAk_npJMU(n~`=B859|K=b86L>&G$argQ4Z;zy&oJ!fFb&tJa$q$DC5?)-cPYisKd1mDd?^TC<`PLSQSaI2lyo1dAv zF^cgB8Cx8xYE^`Uyc(K;$J1SHd655*a0+t=Y#~vXqVjBc(PIy_PO1QN4_da?*b5R8 zd2DBYdC4G_pvp=P@Y-n2Kh}jJ9Vt#B*h-~eRb4s>q2$7rt)6|&RKm7n$oW;zf&Tt? zH}T7f#!D3VGLv>;snWJnOb<`I54L%PIya#c5IS9FNeHO_V5tR1AkhD((^l(}SxCOK zH<3QlC{f*>>YLP!n5h>W5)56VT~?AN4}OW}r<#?DN%hM#92~ z?TbbI_^R**9sAl*KOM=GP<2b$9^PTv422JfjPKbqcKs1(-0|PO>8Yx#qoEpt-kD!! zJ47?GNJ>(Y^2z1!s3;nKLBZ9~u|&(j3I{#N3as=v&hyTPDR3SY{$G?5GB8vqadGi` zN-H31fgwqVD1W;7X_e2?7)_%QeL4@*)8{Mo(#RPdrNkt`$U?W)! z{XR%!L*WNLDm~ZC@3X6XBc+&=!fKCeX=Wz4&g$^RI2Hyx#}GZYmzky8#V@B=ZLM72 zU83maSXjB&=(_ClWW;!M>*8!>czZzrE`3Rc?29a_j~A?3 zwrP<@0v(EpN1lFE2!q99m2)hI7D6J8%FYrgVD?Z)f4`%*PhnXZ>+Y^+bu3I7M^QE(c z`o)I3Z&WhTVk0aev6?5)+=FFAwwmEl(bUc>;aZsodT|baa|ZV-lr#BE?yyH=y`oD; zpG2AVN^Oyu+vbb1g{#T2oMH9zQT1&+@m-ws(U3{Y+RVzO6`%OT_s3&PyWL3=4fy!@ z%6(VRMHOkfa8Na&bcXKa>({S(rlxe3mX_}~m&sYK(|0jrOis%y;i=T%&xUQzx2G#K z0TfL_0@JR>qSIodqk}UrAWv25=!8|xeDNZLln8*5j@}24NgS`<{M=mF<(Hv#R*HaD zh+w!c`s#^dhO2yZMKRDJB!}3jt5XSL7W;}KNQqF<+S2TcMkRlS2m2COqAPp7v$6FX?8-TK6&f(LIBxYv#qmy|p^ z4tw*R{Mq59^2*WP?nq|Mlb0y2y&Cg3SP6P8xFUG#3PC)ns<8In@3>_jnnuAd>G|Jg zBJ%|D16j0HMDz#t>DPCkyjlo)F!jR3!E4Oskq!S7%_B1$58T>ssA2_p>%|#=rnyJ1 zT@H@x90*@RSd>ovFso@yZ?jR*quUUIGd1FV2fl+6?*u5(0HMh{CLASiR!G##$(_^GcwflBSQA#J#F2&5Y$tA)8a zay9)7#X_)hILDz`F(8OJ3TFVur=@gswzcWZ56Sk77-KMZy}eI>EC^hQ)6q#IM4sk}h_*kvCIQb+EizHD>e26trCEh3ZEp z_ht7?`*?)6`W1$^k4p7b68QH_&xoGOcp2YDP#gGs=Eu5%ip#z@@*ndNafda>+`ku1 zpB+~o$~>}=df#eOGrCyE_JeuYQsBCHF3V$Mn%1_qv8|Qy6s8YgpF%)KU_k8lPaMhh zIxF_$`*#C;z|lfdVb=C*xRc;;>sC`R+EncMAHru=xtB^}prZtz%lQ1X?|35vXu%u61w|Vk z%8Ft-p6qm7T`}Ra31q=AAo`5&A0`1EvT;qA<@oq`xz7?eWGprEjMUWQW8>oqNlB6L z_#S>XzWF}nxUyMBhx`go+W!6#z70A*ue&}z`0_=xL^ij2vtE9m7!Cgok&$RwktLC- zhdjkK$!k0vl6xG;HnneJP$!qK-8kiJSK7pOFf-7qO(<{9??Lv9 zWXiWI2AU@em9nm1%&6`;(Je?RHavHDyok}G%&n;UZH}LArn;qVN$9yVuK`0Olyvtg)$HtS?>lR95lnYa51**$VQ6wv7R1sn-U~f*{jDN8VL8+$C`bVq)yvw%{0_+|DiVhR8q~NqQnjz@4Zgog z2U}88#T}jdxx1SM6w|&N^UwNLe*JR1A5P<1a$ZU*^2Li2Bp<`+Sgl0aC~6g-Tz-kD znL&9@UZ9$LeeQ#2i`5YllP<~l6QAdAz~y+!9G|;&|1}FG{@9QY%X}toLnk!x=uQON zk+Q(YJ4`drWeS)_`+_DivmB*C?MK{rROOYN*8K)&bm7 zHZo#?O6=PU6^Glml|Tu5cfPj{3g-_WxGvlogfhY0+?*Z*PO1b}6f*em?OS1}HGYSV z0jdY`M@B(GLGUl>=sCN%n2%!Khh$iYNmH3Il` zKo8Bv#f94SoF#L!-0AO$kB?uj%e&BB*?n(%)Mh}b$X0}!=Y-0(pZ$VPv^t*zN6fla zVYcf}w2-*(oQ<&Bn&~CpI)%kvx|lmu*PrVo2WaP}6XV)~DEBQp0_SnNjkGb#4Nr#& z4RZK3+u9OPwvI}o49`cS;e|#PN@NW;_*E2LLHLsVw{CB9*@6x(t z<*v4-ndCoE&#arDKfAgQJRbBzuuLt~M&90%CMG7Z86XP0=$s{V&cgDOS6eXU8_~t6 zH~34X$#`G>*1oy9sbOi!6P3ao#XOKk1i8G<0V;k}ZqgHF`N6mD;Au!Jxx;BV{e%_@ zFQlEJBt8<<#T|rZkmL6D-l!uarKSoULa8V#KjlJg&i9d9F`~rJo%2;HEGjw*kS>%c z)6Q}3h*7)BhY2KVS_&GaGq;_b&M&Hn}U;ABKll{A-X}~7|*APd8x&+ z=d6dn|GKr3c)ce4#jL!)>_XESiFziDhR)qrzXCo>MU(^_yHeTyt@#VnrNFrp$L~HU zZK4|KTMw9cdB?Qlf{(;IQY(TEw0-vW58T%sZs`{EKocll__Q-eSA67*>Z+fHP&hv` z4bWPuOLe^HbMK_^X2Ews!D4vrnwTGooQzEB04*W8AA*K9F)fXS9tU6!J;tM?$#;A0 z)Hno(G3e%x${i!aMKJNO%wvXYgVIUWDu2yh4n@Mo>WGzJU1zj(b@4T&02kQUpdUVbIQsKvA*w;ZM5&_h-idx$8f_I< z*{f{UpR%s-WHn3$jX;0_LZr3!6B(@F^9UzaF8uGyW-Tuxr@rXe$5}q{kK#$YHhR0q zrKo^Cn(A+X>^^0xZT?oXP;IcGGMe#L?qO+}@skMfd9CCto%ytrdHh1m_i(nQ9%AkB3uJpblim3_Q?Wad|e*Z3|r2o?3ML_`*q~<(Z0W>ooV3+=& zF9dbPr_chqpgpr6+^QtNVIr=0(odU)#&rWoRIdCMtmiB$t6sZ2{m9|QkD0C+4nLQ> zT4XfnYUWQCxJb2)^RZj&8n;%OZXNU8v$w7zG+e8#A2np!d*Q~EvT&A_pLY!6hsyXU z-NkuKLuT7KL$8r=BZZx|9`AUm1~uUFB87TU*CYA&wW#Pvu1WkL^>iI*YHAXblZ$!% z`jnQAj*X)u?$30e@#_9lfZhez8yt_Br^b9lci4O~8f|MPT(3@3?wi50GRF zq=C%6WJ^1D}3-Q=a5pY@sUr@*sX;IR2yuX99Bb_ zx)po$r20$(M~@2W2;aTayW2IlwK44SD*fL3(K!gs8Sd{mYV}f7qji7NM!PM%4jh&K zI`DSXeVXCo(!J%j00x(=QqAQn8jgy>-zPW|xXX`BUgyaKYgGEDpwRMisX8XxYKu5H zCt6xsR{s860GYCJayHD&U>-z7h)GJ`oEjdg-T!&*cqzDVU}gtIg2u*1t6R6IIXO9@ z>$Qa>XlF^;k@1ohlH&5oZTX3L`A3uH%-qlVfr(ndQGznxfRM+9Ye}Xo3MeRj3V?&9nWLyUt3__Pl^YhLYdd?ti2SDnd z!etzs`NC!r zXFeiiBrGhvHDA=e+-$k`J@37M5bPubS~+oo6j-IaSm}-(Aq~@8&h$eeruow?u|9oW z^|z*k&c?>X&{U@R-rzDngg>#UZzH0@ug9#JAeO0m_q#fm(_U9-fEPzKM{W83_3|z( zW00kyknx0jzN400w4Y0&d+s{dVwq*#MBbL8RdL1#=ASPTRAfd&U6;1xOK;8Fncr_| zYqJ5Y;kEq6+U(Vf{#%FPECA{m+)*yE!;^n1N|o%H7FDVa!ch78`hM)_Nch9U5R`q` zce?F3M0(MeC4Vl9rh|;Jp`iibEmaUf6s%qrk=Gu#1Hen`aa=IE!yr=R0e0{2y*k3y z@5w9TdT{Dc6Bwv9ZGdA7RZ18>Q}LZ}1KLPB91P07r3eiT&O2`G`2|;k!D|u{0F^!h zjV7I$^YZ0Oq__YR7%eTW)POAl)&W^MZYd zW7Dl#I^;of_R=E9gOqP%&WBDZ>S)RXKQKl6&8tUok&85}E;u3K$lB(nt(6rCtQgd* zc4jJ9s{?nFCv(omL7YiRO+~6eque9h+>9WrE3d3ft{d?`48^zvSYq{V+`t@~;^N{W zX;I?r+gB_$dO7ZEkKm+$$lLp&Dil}nA~hr*moPe7T8b|XtUWvo4kKi5a#Y%HXC!9QQE>Txn@3H0Xe~LNNn2rBFq&ix<%;h6 zd%OP>J5aL&@Ci)Ax*0m-<#$Nx9mB)1v$MA$Z`j${#kX6b#gC~6G3@)!>AvW$&X3Pc z(8_EorBUklCGk{m0&Dl&YJB&@k2bITihG+63n^FG)P_*hdj0+LazthITRpB=CX9tT zZJ#WWBW|qy!Y)0JfPa%S-`oy=SVwSE>IL_=dn9*?{cj&3{F#`Y37a2X&`g{@p;AK= z6*x!QGIWugocxvZE4zMCvl@SP$a(MCc5VoNu{)>v(!im_|M2}W@0)8*Nsj+$ zre6e}!!{=&nzIjls#BH_tMW-mBfUFW4ro_DR5>VFNfIx zMh^uZ)W~D~B~Awg9;^=(cqG;xox3}mnfduKeVM@eex$(xWyL~)TUc0tJ=kA-$!$#n zPI55%$dQgWKbmOLg@cI}&+WA|BSsyQ{Mt4)H${Zb>Np8f*@?3MM+?v)+3ko_Y<)%L zE$_?RKUv=SLrI%agWI>*hyZe_)Yrm%U;OV+R?1%Hw;$78w%Khy^a!nLCaSBmt-Kni zV!XC{X0fIQ^Jf1=X1@6Qurk}LGs1bEZN#wWy5DkV)dK!FU9A3H`?U2Gg3*G66dH)p zsi{U1t83SeS=0u`fIM>!@Jrrh4b@^Y8~h6dn0;-C#$Y0kqGrji`4gn1rD^^_*R!&+ zU=!_nKt~oAmG(Zw28f*lJc15&?er5Xy^D9}*$)1n33c-v`#9$Pv7$m)Qe>?mS89O& zIS1t(;USa`MDdU13mCbr@hScu_0MWwc5w zkx2|FC~db0lUOl(nK4u13#f8grHoH->w_tl_LR5-UCrN(E05)OZoNv|dt@x!XXrB^ z{Nlsz>6(Yj$Nit~mN`)^N@6A7*2sj&9aB(gc1s;yqVu9rOKv}@+Lv9YaXfbKEvdvc zhOs9r3+k3v7JpW0q7y{BqycV3&^%~Uky!=J&3NyS9#G7aP%uYD8tFNU{Q$9m&?#t_ zh{0nJb^v;S{?wQ%;Wl@N6(2xR+;OvZ|zyY0UqX^K& z{i7(*|2>D1Og2*7EK?;FHa)nShV z4}x~Oayns5A?xp{z`L96EwN>N3K|($y7`#4nfdvN>R8N;yam(VUfJOb+ARW+Pj3J* zi7dz#=BMn|h|m6+w--$B)LDuCa?gH?n&xEunYraUPHh|%rWe;$(PMb)+gNjDz*a5O ze%0u!*O@JpG&+5Ul668=$}W7PT(jl~IL!DgG%z-k4|tBBrNmkc|jlq7s)lkI}zML&WKQ@uvyQYdnk$R@93xtMjw}( zBqPFS>8Oy_3(AN1brbMtt2VzVI2p)P8@M&n;^;RcidWyE*3@581USpy-d-xV4I`QG3FCXV87;lM}xyzF%e!4v)fu&C{X~B2LJ&wt127;u+kc{D!>&v zU3YFnb7DY=bdFGN+r+4&my(jH`%2c*FTaw1g9O0fvw4+JVN z8)~-t;TZ;8cz8GzD~r>gDREGZlP`DcPvFuPhpRbBdZnUw4T6b7Uj2dqaQ8pEYmC^8s zC3GFTogN(;#l!2BORZD9i>>3nYJv@8oc_f$s@!m5K620eFJ_bH@K1KvmBC59o*QTO zHnunQtgT~P6Laf0JCeEXx1DTg+q%PW>o^zJ==3zA&EMMDX=ra}3JeTvL9c*92^Qx* zz@)CXtwCW{a;ioipZz93p9sSVNJ!u=KM*waA7ha2@%%t0-0gH*tJ>TjE+UjJP+K7k z3c>g9mitNU*J+G=;NK*`?B#I4FaOJ{wzW-B5@C)L;7&5w(?9~AJ4X>>V`vE9a`0tu zc>3O2PF{}yoFx;+0M}hzx4i96_aH>h+EYv`K21l?xgFVV)%~AD@U0hfnbI&$|vsgDBF#BRMiM zvZy`d^;DP*D6{6oKQUvdC@9`pJU<|m=KD+NkQ$(%=oDtLzXV_OYxeW!L;n^4SXd4T z2?^2vAVXiDoQeNp2XoAjr9{zFg+T~%ae>$ZRY0}hCWVHstgNhB$XJ@3AB8Lq;7}_? zeIyM?MXpyKoF4&K!JxkuznR>Y|A@54mi1oeHFy-&*r*QTy`sQcs~aD_x%t)=wh;2) zC71-xT`Kd3#VH$<}Qk+{~OWhBg<(zL1(a`j>ak^V1f; zskcA04C$7;C|I?3X?!6RCyM3{7xYp1$n9|c`Gb_pkd&cyIg!{5|NNYo_%wfto}S*$ z+zb*$zzycHv!E>!`=|49hZF`v2s%`IigW`K5pI$b0fG=mh@xo%q!jCv9$uyJtE%K9}2slZ0cnC#}cxp%B4ZwUXTuZ)sAMs)OLr+2w- zARW{Sc_U{Iv6O5Zc+ zL;2rdY;Qlv#Ku^wZQW_qjpsBepRi5t)){MJt$7e}yvMkGrBjXfX7-^p?B4qcWV%*V zloGtG2Q)s$w${kgTO}HeJ}@#jKdzH@k!CbM^YcdZv$QmjC;-TSh$esk{wnplNx*RqJ@B`#42#_$C@*grt5nxn!49{jxabo1}{l0%d3vptgvQc?yKtn}T ziC{c<3V#$k+S+2>QGIXHU^(B~oCnN6O-*b;tQTRAQlX`Q)rR!~NPT9lp34cA4DHlB z@P#Mn@p{kJlL#c0R{>d%M=yKcLw_BMl zwe@8N`$u(p78}!W>DE?XJx*}(MVF5R9@`u!K(`4VOSk_kjdI_&zLYZYx{tj|}e)qk8g91rHtk z&W2!v1jEzPI~W`#H0Nx3ga1q504+4(9Jey@KcVB4`n4+CXWr^d_sfhA z+*W9Osry`Seueto1(UttmtDYir(5ozWUpiru-m$9&)9FQwV!8W*jjlua+8vH*oB!^ zP+o;_zHz=Bna%0YMD42xhq4T}2e(u&Fj84mVyu2JbZ*}rzH3L;W(p_lu*LJPMp zgNObs!zIhTZbd0vP-RWmXE9P^H%A9o40OJcp8v{NI6LMfKmWVX zvEE)bSf=cp92l|M2n4Hc8svE0borYH@%H@rr$?cfhGhhD{y#uOQhIuOpGF7jK)nS` zxJHvtZkskNgPqGU)m=uMO--zmb`Bskz1{BunR1Gxvbh`gYc?NIHm%mlcCFhdySq$c5rT5$oeBX_K5BT=h79t|!m0Q z!5%A1YBm&RF2=C+_dimfcfj!^zA&)-_`@!Nx1S0Met(f7TpFZ zNAMFWB4A@6ngIy89twJPJ$gDiTS_9}apT|WRPq!O;qn{=O4?2^T??CZDD$iH6Fzfx zZ>T~cT**;F_T-b#@l&OgtZ9Xt#N1y2xVzr6i{~pcZvGPBH(1=Vy0&!G>y<2v``$4L zU891xt2uA(jXzxS2<)7|ACs=t+|%Z-x>Mg*X&}MW;EvVN?U6^Tg3&6uzx+$Qm}BogO??H{Cwx;M z$%6SobI6LS{p%t8R#z71+|jwR;to#&xED}po`7=!c?4GaM|U?G_8g)sg1%E{sEBK1s=IqL}TS9TDk+4%_BH1$ACh@&rtEQBzY( zxuy%(9}L1^#BqcqS{%+MCJlgas?%MABhv6vMEKlvbQ*x-8P(P1hcUx70j8pu(vlJ} zLiz2^lZbj%Rkip#NK52LmR+~-zemDYis))|1Zgi_l|f1pG@A6gg9LODfTODeegu^{ z0QUfF{zI$&`3;O|3SiThU)m_bth$&K0#L2DsZhsgDFrd|P`M!V>T5lX4i18*EKXU; z9bPRMsstb=7mOVPc_%>DQZh0bSy>d2R#FJ%AZ;S~h>$1`lj~)u;Kyfl5i~bd|Eg`& zk~M}~iUXDH=otD5jPg)Mipf^RW1^5#8YyphTY`gX5hf2H<-a?SLE!7K+qF0lg#Zk5 z@6T_6nyoQ95=DLeBQOxmnC~6f5J8Qg zDfIXELlGDf8cGHVJkM!H7zNX+s$0QD+}ODL81(2#_%z7d00Ys@u%pi`-fabA#)C)7|sDUCq29D0Q|#KNr58 z5(Wd!m~(8__x0aQ%lFuEQAKgbbJPXG7Y!(qMZFW_w2NnZc}1R)h9s)1@kIC!-lI~C zH2m1UhjA+6g>ECcVR)hFvjuVd>NNZhh|#upgxyn}HvO6cavt?ly|F}LD8yD5|8nk_YI`>H06Pr@b(Vp>E@iSJVsaHzlm1)W8KdjmojwkIb**?Fb&K9HI z%eD|C%eXuE$Ex7-S@C}52Nmu!0{s;`36sAJJ`cx|n>a|yu&q69hhE_rC5~0t40LGi z`gyNkAEE!hJP5h8sIbsbim(i=lVLEufD-550g|Ye1A9TRmEMF0YC6ou#DoJJWH*|W zkYoRp|IwEzEB%uRN=%+s(NR&zEW$R4V;xu4cUkPrxTr?e=2L(0E6z4UYd?!pWKoUD=+=u@Z$sic{^g zFnqydgGM~H6QF)5m-9A_Y;E~skIPb#Ai`Qeh>Vx=CvmeY>nVIRZyA9VXQqfo2Af5$_We9sk5+L3%o?N*(4Wo^sr>*nIs(OOFXun~a3KLxoSbHOI^3f6TS;2M=8I%* z%dAWEm}H~QqwilCy*8X#SWpAWu?WVZ>aI2@G_dP9XmNEsLo#mv1a*d7;Z8*!DGn^) zy%nB0R(ggQR7$wQ*$NS$Q=G({I65vjx3$z;D*%tV2hsc485K`Q>{V z%y$um-n7n-gVWsr1;ae}cQ>0^lt45xTj7XAtL20INBY4V)i<>UUxC4ef|_CN_xL~N z0caHde;flXDfU%m001@zqjytS$Z%^ZCkdLWs%tf`gWfzp&XSsv(rqY`334`=@Yr>F z5f2p?_+P9x!_cQ z*3H{NmnILJcv^yF$YC?wMW^6t((qsDY9m{$ncQ@@qgFc#HM?u(Z1CF9cXf&(BQx{f zBOWN+K#vdOgzO1P4;%x>~9J+-SGd_@KfN}+1W#t z!0eD&UY_Ksga4=PZaGjVz&GUs!z8q$DNb?!3i*+dum@sv{<)OJnHkXaF~>eUzBqhm ztAEo+NJ_pVv(B)V%7Bw*F!Z?9v<>;|mfzkIM`b`aOHN`&Hve<e=3gFuvP-XMH@v z;?}3-+)Fbh>QcVF^?mKJo?N!a#go`O>Km14dw8jPrN7+Rv23Srx5>LIcOjOSTB>|N z(cbAESEVue0}Ji?SJYh9EKa3KH^m0eh4)>Ob56bK#^4p4|LC#zaoN6{ zI=ccYX7*9;i9@E>IX^p}P0vmJZu{!q9j>;(4Y#%T;W2U$pI_ak?Y}KIZ|*Y6Y{kT> zvEhCetFtrEP=~kG;f!W;OlH2A(^Pp&RQ%P=sp3@e9W#SCN3nkS3pwUw3qNP9>DZg4 z=w~CgitErzVj>)8l zTZ!){rQVut?>`^Y_Pta^ygAGTAnpG=#xtE&# zzH~=f7UxeWzp<&NspVR@*z6cJyHX(nT1EoK@!F>~E!Hk&MfZH-nwFBgP}AC{Q1pQ3 zHdHab%cG>Lzr&pHidU~5jpdRiQ%uU#JR>ik=A#4B#Uo&hg~84?Br$X--PGhA(J68w zRNP4C7Z(Sb4`UF_9GD~4m6!fwj-WXG1V>6_;5_dppA*NU&~~7HOhloykE=NaqZbhM zT}^;zz*UH8zLtUSE-kX&uip1+nTIzFvoDU+G9}uvPD!_xZa`bu2pTd{ODhQB5N55- z{bsympyVfQBK_3VWDD;-fUOQQn}31?efh>x2uOTjq-jyxY-OcP%Ef!k%jwTMFI~En z=Ls+<2WU)MZbm=rG~4Wk*E=lN|D*(>=9wRUA>0D^zqT|vy3Zkq;T7(DU0O~?h89qa z@$+FYH5-)TA*<2>W1nb#$o_a<{nx6hj9Vcv8qpXZ^#z~($FLD}iIxu{mWIUwCy zLe&ow)hf9vThcn6H@m?quLoLNSPo$Cf$%9DHifATQXqXEr9)oY3kv4E&8HRxpz59R z`K1B2i=wx;I)QdWKsP1NN|4V)|O5YYu;N|*huTSE02WshphCi5)g*Z8L(@NWc+}&T%re z{(vL2IGaJ%!mhPXo;&j51Ki0w23Re2$U`cLj~o`(aZMZ^0JVCw!iMs1UTr1)48%(K3>sxc_mL#E!vu zH$;jAUd$;XdLSk6@0J)jZjDZ^R9ai)4FeT<(W|NCPHHA@$SeRmm`WfB9PD5CxOuze zPbIW8To~GSXjtYT77= z02_pXl<)_hreA@h+2_LiZiR+Q?jm5WU?Tp+giFemtC!4S*W)^Vb4o%4V{{E>Hn2kX zmoi`h(;n(tW>aN-JlbXp3&r5PLYCka5{mKBNxyjS;WJpy_i{P6-GjPRZSee&?v_Tj zTJ0u__;~fU>_xhfPZnB|a$<{Dw6$Xhl#v3P;o4qnKl(+fq-s!LTz+|uTJoTb*CJu!1o4GR1ly+CA&g0904eX+0I{J=j6`;s z$sp@nsS7r(z$>7Wg<#4easFwz(R^OW)!r0%u z3A_t93k0Z%a(){~(+=FBg&yFEc9raI`EqxLKSV*WrTJz54PHD1EGStLEH?THRTwE~ zK!GF;Ra^mf5R{-VUMPXK%2VclpiQ})@KAKm({r%@yrDivL@#p>+gU}<3acehh%Gi7 zte-PsP-Ax3RCCaZyKC8f8uR;FC;8M=gig-U$r=!S=W}d^i|A-Kt!a%I7RlvZ$M2kj zWn^9)+cKA7%QvDJ*{>JiMOwlxET=t;2A2MOe!M;|2*52g30Jv z8h6Y4XWt~sW;d0*Iv+EurlGOgxOP8u%rSZv`n2%%i=+8FWApPZb2Z2o3JrX!*kQ7G z#lYYp=HIJ3_-S;cMA#VqB5NQ)`zi&s1HjK8RdoT9j86r5MT$HO10u)ydviciZb!;! zi%WW0)5QQ~%-Mq{0%SnoD{sLWzMq9f1JYRxaExcuYX&9NnN{qOE`Cj{Id4JaESl3N zFEVq7N?B>;$Lp)WR3A#QWB1#d^EWe^atSj1gzFX0^_l+alsoEzNV1_;)J-G$AogT-HwV%_M{CBU9f-%8QkvY z2@oS3a{Guj|4^T-#%$Cda4+#-H6}bNFvuai9=2oi=Eo1iI>?c+V~*~YPvH=LUu=f3 z{f#bu^HjEmhHek6(VTQOmzdnP^zj2Vmd%D|tEJ)U!t}4DCDyh1b1}0|9zXuzBPIu| zKMHk8tKIA=oO9eLcu|bJE$Ar*c?eGS@kY zcXAqML;mSf&B-q!ug^c+lE!gaZt~1y8 z>x!3~462a2;mn>j4eEM*z_S8CVd-LLI~M6!G2a*QhxLlHchK-}G-((9SErG*HUv zgdr)9SW$6Y()GY-O!{!3TwGj$)s@;=L>ON``~iONJW^wB7~}=9_2u3S)KRqxGCg>; zN(C@f%Xadl(xJ4g*q7He(nnf@VbS#T{0|`2tSWXeauzE+*=u~BL{I#-9PAc%7Ok(pK!y(%4o)9k^4 z8X6n~en@p)!?Ns7>Z`pOe*$z4x2GO@hK&71mbSciZ)Odz_7;9mu|Im|EUa+BGc*m< zrw5$bb?t*iL-x-V50Cc{65TpY51ASkwNhTmu*GIi`u`bZeQo%)>Q(8F^kxpE=$SAd zg2Pgu4GHJXEc9VClthTrE0WbE_VB$3n(eop8rPnBDD+fSiol}{Qb_#ve$I@5xvS6v z`&A7xXy}+n5X+ zS>fYJGPTOzve2l3zP&tfx6(>4%P9_CUGw|Ssmz_s&LR5y8yeGo#>3s+P+5_Rc67pA zZVSB+cNaLg<*;@}es-s}Gfk5_&762SQ28A^0rD8!Y+TzDMX?3Q(uSX~+TC*aJ9q9l zWhWk4sDT}t+7nP{pKyPYgwp=e#PC{{;hHd^Ie_%`3>uYg|Uyn=5H3W zZQgv1=g+h2G=;Y10Gk4Np2glHm}VFm4iCTVr|x zp24nNZ1&eHe!5dX`LOm1QWpH1ctI{9Dl2=24P{x41sb%ce;l$3&=1r&{A`>~7}_$G zN^G~|Iv>;^*w;Ime)sO>Czty8yZ-`XJ*8)|ODfr+nIb96+`_~J$stxTHRimoweI9a zm{vRCZOJmQ_LPZ*b-d7xFfiBiE07BN{y?M)4uJR zW%q*@|6$Xby1Kfi7E?1%=h3m6Z*bd4fJNZ{IqxZ_3YIRfH#jGKx!Pswfoe4*X+lxa z?60Bktfd>h!_3LqjCD2sH{L;;Ws&$7?x`HMA~_B!ee>;1RusyOLnM2*~q zPUW4<&9$|pW3TNVCGE{Xn9o(He4UBOQjlT5EvW>pfo{Ef4j-!K1m&yn!*@Rx@d6qh zCb0cxYbYovB0VhOE+!8??Ui*&OH222iiHs19!}UQqoKqS=1xG2mz=a*D{^OPuIcH0 z!!@mKJ>+o`Lo(*bX3{WFsm292-;^xYKpzQZCgeZ7xnXB@78C+nruPenOd&@K>lwZ_ z3{_eI+!0C_&txW4xM5%!1rD~Gr-0tnrUtm4S-W^r0XE#!xb^6EkXOy+8i4jfl{$)_ zhrsgru4MEbWWd$wVo4=^%^)vDinGj{llfYl_utxe4nPT(?T3Qe(lX(`&u#3P#(%{?8Olr$mB~q02&%#8QTUqN`gRVkpS#;;FmdwqLtZKr?8@a3^zlwpA?Qtp zgCk%6Q+}<$`)7=NELo0r9v!cVbU9cBli)~bBk+zj($z`XW!-t%w_=jgdb7)TY#{Og z02@5!_$s?+V4xYB`iJ?db~~KC|4)|E{~RbBu3U%J{^+kSghD~Z{coBgAx^^MR)jGq zz#oDyf>%&b0~X_;X@gmQpf<^PrM9jyoh#?@&)AuPJWYY?L0+BGLRm;|h6)El>2Ju^ zOgOVm76x2eS{eunp$rm)o%AcNjT#3=GkalafH{`pgi$C`##Daiq%;I7c z)Y_UlIuKi^5TdgQd>~RVmIKC0L?kA%g0X!KyBoTC`pg;kKfiB+X;q>RhC+SV7#-z> zx3bW|2n=ZAz}MH%)%C=i3x?#Xzyu0-S$8222ENGXluoF?grqiM6PLS>Q-PEdhF;u< z00e`WU@^ca35)UNixP0wW@ctm(-OPcSm39Tx7E$h=Mg=Z1}nlqbq3_~IZu<*PfR}C z_4AWGn$rgB2Z&lqO3K+ZCkc*1pCya6jSXORIgocCE-zbEm%)U)w(odOSV`D=G#1k@948(}Y>qlVtTX*eG;GXoaAI$Pbv9Q#4c0Tgfxejh;Pb{Ea zDV|sdheOEUN=;S6Vr2}jUX`9+gBOu~`~E!?76QQvEi5eZ+Gk-5<@fVPRojIxFDNy=AUE;yLgE z;9;3ZO60prSuqMbA2I!>A`Y^)G zDd4>(tIH6G>%+GJDA17+4@>#LvcVTCgP0yjcJLCWY<9y7s=P|EwaaC#~IyGXsl;GLJcZ*L#O7sj2FrShUq2Zn407M=I+#Fu2Y1hpScv4MG+PzDupmLMW0mlV$ zYC+|KD2-qST8iiP-#@FMO$aF{5CL>mx`!L0ObcB#42HcQ5m6+cqoJ-2e}%ThBnBGB ztehNA`5a{89n2|%Q8zY#r@~JJw{`{$A_B||WLb1m#j~5>{uzgNyC7q?;5~~_5)-74 zb8z6`y5a9HjnpD+QvLAo@Vr3QOD7+1Z?VQJVBiMr1ne>prvcE0xFydy@s>&lfD-{3 z=LP;PMAQgxx-*{kg82li53#FLt&w=VZGg_4mkbh8z+4NqLL{j$OUv#Sf h$}0Z-8xA3RL61=WV^LFO6(sQMlA4a{TV<=z{|7U`nA`vW literal 36835 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 Roh1IVS2)?GjGw>h{{d*ei4p(+ diff --git a/docs/source/images/ldes_chain.svg b/docs/source/images/ldes_chain.svg index 2319b0107..129f8a652 100644 --- a/docs/source/images/ldes_chain.svg +++ b/docs/source/images/ldes_chain.svg @@ -8,7 +8,10 @@ version="1.1" id="svg1" inkscape:version="1.3 (0e150ed6c4, 2023-07-21)" - sodipodi:docname="seasonal_storage.svg" + sodipodi:docname="ldes_chain.svg" + inkscape:export-filename="ldes_chain.png" + inkscape:export-xdpi="96" + inkscape:export-ydpi="96" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:xlink="http://www.w3.org/1999/xlink" @@ -25,9 +28,9 @@ inkscape:deskcolor="#d1d1d1" inkscape:document-units="px" showgrid="true" - inkscape:zoom="0.58760574" - inkscape:cx="1167.4495" - inkscape:cy="-778.58328" + inkscape:zoom="0.83100001" + inkscape:cx="444.04332" + inkscape:cy="153.4296" inkscape:window-width="1920" inkscape:window-height="1009" inkscape:window-x="-8" @@ -56,78 +59,71 @@ id="defs1"> + id="pattern57" + patternTransform="scale(2)" + x="0" + y="0" /> + id="pattern56" + patternTransform="scale(2)" /> + id="pattern55" + patternTransform="scale(2)" /> + - - + inkscape:label="Stripes 06 (1:5)"> + - - + id="pattern37" + patternTransform="matrix(1.4142136,1.4142136,-1.4142136,1.4142136,0,0)" + x="0" + y="0" /> - - + inkscape:label="Stripes 04 (1:3)"> + + + + + - - + style="fill:url(#pattern57);fill-opacity:1;stroke:#2b9000;stroke-width:5;stroke-linecap:square;stroke-opacity:1;paint-order:fill markers stroke;stroke-dasharray:none" + d="m 706.49906,-752.70371 c 6.71263,-7.29803 7.55145,-15.11983 8.50094,-22.79782 0.62274,-5.03509 2.22743,-10.25369 4.11811,-15.22233 6.13942,-16.13398 26.94251,-31.92037 62.94812,-9.27611 14.03714,8.82809 17.4099,20.11964 31.17991,28.77971 9.45,5.9432 29.26644,15.30787 39.91614,18.51655 z" + id="path102-4-4" /> + + style="fill:url(#pattern54);fill-opacity:1;stroke:#2b9000;stroke-width:5;stroke-linecap:square;stroke-opacity:1;paint-order:fill markers stroke;stroke-dasharray:none" + d="m 1602.8357,-753.1385 c -13.7159,-15.55752 -15.4297,-32.23162 -17.3697,-48.59916 -1.2724,-10.73352 -4.5512,-21.85821 -8.4145,-32.45012 -12.5444,-34.39361 -55.0509,-68.04606 -128.6203,-19.77429 -41.0562,26.26448 -84.918,36.18165 -145.2686,53.96207 l -1e-4,50 h 300.0001 z" + id="path17" + sodipodi:nodetypes="cssscccc" /> - - + style="fill:none;stroke:#000000;stroke-width:1.99999;stroke-linecap:square;stroke-dasharray:5.99999, 5.99999;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke" + d="M 1599.9921,-879 H 703.74821" + id="path98-0-2" /> + + + style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:square;stroke-opacity:1;paint-order:fill markers stroke" + d="m 853.16238,-877.5 v 150 h 150.00002" + id="path110-7-3" + sodipodi:nodetypes="ccc" /> diff --git a/docs/source/images/ldes_delta_problem.pdf b/docs/source/images/ldes_delta_problem.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6d1dad0ca2d54c3c802cfba125ec2c9c6b83beff GIT binary patch literal 20576 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 ap_9m-!Q{|jc2w+5jz9^isF?0E6Z#K;P8`ty literal 0 HcmV?d00001 diff --git a/docs/source/images/ldes_delta_problem.png b/docs/source/images/ldes_delta_problem.png new file mode 100644 index 0000000000000000000000000000000000000000..704f6e64b224a630169e8fa4061d779df3e476af GIT binary patch literal 95959 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%0At+8m6wk^NyRp3uc7fLbNRAZZf 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + Adjustedupper bound(x 3 days) + Upper boundviolated + Allowedpositiveseasonaldelta + + + + + + Represents + + + + + + + + + Adjustedupper bound(x 3 days) + Non-negativeviolated + Allowednegativeseasonaldelta + + + + + + Represents + + + + + + + diff --git a/docs/source/images/ldes_delta_representation.pdf b/docs/source/images/ldes_delta_representation.pdf new file mode 100644 index 0000000000000000000000000000000000000000..dda4708036fbdf474f2765df107bb88362a6852a GIT binary patch literal 18088 zcma&O1CVUZx~|){Ioq0T+qP}nwr$(CZQHhOYqq=Z{MTB0#lCS)+_)80nd3uMR%X7L zF~*2`idaragqog)8H%|1y5<9l37-z%*1!UaiwmDt%Gk!#$qb+QuS)?6A0MAq#N5is z*x_$&rSD`cWNc__WDLc_1Lf%CV61Nq<(8GLByGD%2h)A2dbfr%AhGmf4;%sr%#v4a zI}FEv2m*UmQr-A`8{1+u+MEq$7O;j$&cnkUuY~{BsqiTmL&sr=-7iS36Lh83%Dd-5 zt-lHpy)%%B|2kgN-Sz{FL~Ir0uX_hnv6-ENEwiEz117}>g=ldGJ0bpLRnFHLW-^}; zNYNIEm0vgQ0Uxsad03V8=+GlvQ2vp76+zMTPHy3R$N1tdeqUP%bd#X`z#PGdE1#^8V-V8B${lYB2$r;a%|j?C zhU)O%_@V}Y%w>2*lLVYt=BgS46hT$Wbe_KTM6aF$eV(ZTY05!IDgr2SUtp9bd@9)t+s{Kc*|I~lQ%EG|>Py8Q? z@xPk>mx_hmoJ19!{wf%si|Zf9-v_Ne-CqNrR*)Z`9-r1w|8MzM*M9^5E@?$&3o^E_#p%0mbHEf-y7$={bhFm+&_^4p)-tP~#xHe&RVP4P?JZ ziE>yxGQ8LGUt2XR(SeHvAl_PkITu!{ZpzLC9qVtu2CdUH6_4oRoO8o1H9PlJMEr0% zc+>;4hqax*K?BJ!kNux>@=s^~Gbi-S?Ef=N^mPAgoc=Q`^z{E7m;c*N^Upl}JCh!t zfsvJs?*Fy-Y$P8N~OSG|ms9T~LZH-VTzL zzlMUs;*|pZFnVJ})0*G9d!?Zr0MNQPS))?Htg>Z;V$DEUlj2#jJYxJiC%rL~%G#Uv z_Vn@lWiv6|-Qp*eE(XaC~XCu$Ca>^F3(POrM}cX8qi zp_4kLz(MomYONaQ4R{WlK;kanScY2t$;fdj&--+!-=|>E$gJ*qz1upk?(U~&kcoA0 zLp^1FpE5yifEV5ov`Wo(SMish6Uu{MpvG#IX2-91P7cHjZOFGj&5^BD=+`r|_&?NR zmzS(ARlZfHQ>1aBFV@CkbNx_veP+Z=<*|E<1xvEHEDdpexhHXi_oeg?lLdAecC-oe zV*z+0MDesWI%ODT>E$`K>GX1e7Jw?f0cKBST-36W0zrteJqztbx)?wmVNTx=0>8MS zyn}-W#{|R-JiFRcAJ?sT`@t*(93EgA2(bQ&Mr-B!2vKl+q9)0k1zx@HnRNE4*zZw9 zXpw|E&YFq@yHv74Gr@?^KFew!vR;f~cDZ~!(!_F(A@vhRJ)Rk~bmE28zJmBasAg_d;Z!rKr=bA#@W`$w612C z2|jME{3c6Q={lyf-w54yGjq*_MU}GZ?UCq+>yAT{=I_K)R=fasF6X%tJUsvk{&zL*oGggjJ+dMemRfo6; zaoY@b+q5H~6mB-PoQ=T^W^Kxc<%>LifvI z?gIIZTpJDCZd9&pNI4!hkl8e%b4LI{V|t&HD3PlNe|U|9rJI zzu4(*3O_y&{G!AA+TT~-`wc%c{D)P?_i&Zh_lsFXbvD#f6e zTaIf$M@!2ZFH;*8TbHZ4ZF)zgYon*4&08tedo)axYZsEsaF(WENtCoEP9Zl}K=wVC znq$v5|E%oCZQizFmonj!n=Q40GFql|QrNIxSX1?>ZZ$vkNL;Ix3E@ag_E8RHD%dT%4xfIq(~JOzevyoc5}=JwkNiDXx(W2 z?0tElV^`eg!td$8y6>bNY(97IBv|${{4FPA9F~p=xcG&1qLdOeJk8}VK5BxQP1&65 z=j1e_L$iluvWX(l9@|bq0!UbIXbUo>3BfGqAp>Xn0B(DIGgc{PKN9t)N`QB4fEXg-;ND?ktS}pYwGK`sj6lg5Q)a^ic2P${~eweDusE zqawq9hJ!5Dz`fzX)e$abd#r&3HH%xxSvoTAO*&*NVwDoRm)ka=x3P<&J&pgog%pot zJs+nQzsRX)tV}9+idj-nx`}hqB-E)PV3Acl#WKKS$%hspW=VU+fc} zWYF0GaF2!rO>OmfA{%1CyJB8*#R>pNM33FHib4F+I`3z$TM33zoza`Qc=QmoX;~Mr zYD`X5?u%K>ySLbzp_wQzbebFsWbcu2kW{ zoox5+PdaUx-C|k1t^`V-1tIxt>GiX8)P!Nu%9()WIMQ^%BmvL@;=l1TqYWI-?YAP22O z!Mvfi&X>&R=nW~?wTvy(QB9c?Dx@kQB*|(GsfUA@8cGlPbzw8Vc3jne9@_jI5Syuj zUH=rOkb|)(oH5!Ig^9he!b4!N!o=)aqjV%RT?vvAvatP3W?`+T=yz#&(gQPzDO1Ue zT)-lB(iFjuYl|nqYnC|nb@0;}9Fuvbw)uc-G34&C7`?lye^JTA?__-pIeN%Ea#Fi6OiR$iF7pgD@+)OY+;DC^0d&y z;9}9wFigi_ZL~(`H+MR0o-xuzAF@GUV{)V+P?@Ix@5@b7n z-dpgahFz2H3uCz#P)h4lh2R9~r-Tj|dJIBuKxol~JZ-tp&`WMZPY_kGVp|y6j)+%I z63B3D#p>+VQA71ql6TRxU(>M6Ha@OW;;k-FGEzRr)KKooQ5or}YIowUmJ+U;_*+?7 zSASEzJi06D>mM@CnpPdaBx8cZ;ynAV`&pP~RabLkg`zsi-zZJ5C8@~QD<=2rqxXY6 zQN73X^e4X=4k{adP+Z_iXJ04#t?jJXWK>;AYpuG(BzlyJj62j)lT6D02k? z;ge9U??@Dwx>NAibD6$s-%Pln(Zn@!v1A?l`=G-9VXwH;YVhX9h{z}HPL7sKB)xdV zL^Y%Y2HURKAw=su1Mv(6$xDUgqllY=y)dgb%kzU zX*z|guM)0vQAS7{&6xj0D7h6hUVCNgn3iS-%rl$D6HkE-Tw=crxNe=hfRF*1P)CQe zs}tJLYPlO%0w4;gZKK*&`)i15dBb$MCY$ke2huzCk9LpCN}BZ1xBrf(h-^0FZI5=* z`$1>eMo}{#_;wz2%z@*&&7Ts|nN+Y(fFC|v2!TH~{9ox@mn?xM^oUDv1qMt}qs>?&T> z4wc2q=FKe|8rPM_%PGqf7MB*A7M{9QwR7sfD9NaP(YNU3FBoW}X{t1_H?-$9?qyCC zwtPh5Qoa2tyQQ36%OU&pk+;1%rI$ri9z0_>E%g_}BohOM2}Kg}!3-<%4`7NDq!v@P zc@}7=vrv5X!<{^-CUOMIGsS%SMk1N|Z2ngN7XJ4BKJ=MChyPf8lYM`y`{Cie|M}H4 zVx`wUO92~~zJx&>4d5=7 zr=yxo&q!Y5M3AU@9{>*JHJVD-nBBWOOG3VPHtKxk$@7fn?(#{xS7!Htad`Sx{}0L1 ziuzi?+qklr#G~I1NqOF{jZM4?9{H$9^VOzw0}IBvf6i#hODH(3%U^?^3SL-H!PnFt zpdu+ZCu5TmHy&mj6lx5jpb@Z86w<3pGAH@a==@^hfWXi3pOa=T%om`uruLi~;O#F^ zcE!`XGU0~K^9t=4SZ+|HzmzQeXh%aFapO$;_(jG+1&?ojjUlo4BH zs#t4Z-zS0Ix}EozDA#T|eByYipJhbjJf{kK%|DoLn#gq5lVSIMo}l)$S36b`=4VkA z=M~skUJh`pe#hNc1{|3dsk!}fzi&>`T|OU6!NxYgUx87Z@hgT=oAN_lfF)%is`#p>&K6Bkv76e~pJr zT*mJhb)lV&6L6}Z%~hFY$X6`P;n5vr8Uvie(^fi^^JVu~iqiqqC@RgRye*XY4FsSB zUA1|)%f0hX1V&uV-j zR|BIq>32Zq!;VSwfB95}8BkI%|!knWn8?|XEg<-gon2D4t(#@eW!NxpbMON}`F$JG5 zKhU+5a4~A#&BI>Y4u1~Av$M2#E!}f=gAdn`6ClV9sxBM%)0sb?6EH=Dtz;%E$6-d{ z%U|*dy4Vwo@8k>+A0gI}DCWT{B84++$0}U#3Np|+uOn3UV}q7P-qeo0L9QSTIq>N# zRV|v6MD$MCvYD1TD*Yh@_4u3?!|%)AglBvH<;tA<@SK4m)vL$|m5xO;ScH`}J_Qg5 z$;`~02Rb7+TVcvfy9lbdkvDiU6VYz1fzWxio>ZI(2JooA_qzJ&7hEa92lyq|WWoqK zPod66kKUKVTrl20sed^z>%?Np=yF{w--0$zAzd?#4*;<7ruLRtS?f#Zb!oZl*}}TO zVgJ?oo{_3uZ_S1G@n=d{G6VjWlTJ>or_*Hq)z;T{kAI=jc=AfLhyD)kS&)fj_O89I zwoxALo{l$&HA-OJ2ym68NgYj%v&}NdIR&mVOPX7oWc{}+mLqu*a)EvRCCVVj1+bee?Ti2wLX~7+Ppcm}UcQ95fHAd)?yA^UR+n&lOKL*|B!b?Mfu& z<3Ivoflz7daC?msRC;g#W&ECO)PrgrI;|O4YY|&8!}}6eZQI1vx);))F}8+m2Wt)< z&Se!c={560v^iNM7c2Onav-#5<%K7F=lWp#wMT)BA8fM+rLyzt{E~7N>GV2vX$yZN z6cp8xZV2;7RR-@FkuLECMr>#T62i1m4Jdm3J{0;3wXz92Dml|8@nku$k}*(|m?<&$ zJaE4fnbjQ7?xJcFJwez;QF7Fha_hm7y!gO5t0r9Mf^D&1$v`oA$YMfas@zMDdb)*# z&PfstY|8tMX^;M`6#OMzWaO#Ml^*lU*2ebL1y$C-2>5>(dYelMA{;~x~q z7uqV}Q$N4vMgwyVUhsAY;69fzicLQjI>C2{9jy*CZnoZGY#w;#LkH6aS+tm5zxU89 zdT#F|KCf{SRe9KdYqs?Qz*KUlx);2F z+$Gmt7`<%R-2c-i07NGlt6k4&6(d=tDGCA;JmULphk2s`Us@w!FYPwftWEWM(#zlRi(^zE-csELF=9U80Jp5`#+X zp_g_7saLcwR@0@w>w$$>vz)72Lxrbfld+?3AxX2M4lFMIti|}WIz3$NUj1IPQa-2b zIeCzly{`v2F&NDj)6WRW?R))mS$D^>GsDSNX@KaqW8yki@OvE~MK}{g zNU)niM#Q?q$Wah=pG_l0dXg=>wSAvjvIc*wosjfT;&TY-cuOp703>@K7h(HSu|Tl?gsOXeSosYQnAa*sKScc5VP5gKchf&K^$@R3CwXM_5-Ec z4FE<>87E1Cp*rB1LG?+E5K0^>(UnH#$G;eHm^Y*z3#ph3{$5U$BB1?&AO-b76FLQ< zp{hdX2rlXa{vr!9?22k0dX;w>PMhF{z~evVd;Vo0Va|$cXvF^0f3y`fK2FYTTSq&* zop6o?p^H&6!J61RRBx(r+qdr*xU4`g?)Xz*)twhizuGyT(zN+;MwspZSyW;d7fXsCkoTc$VELYGNRWynL${cKx5;HVjI!TC%gCD1LQ%J&v1r}LnpPATLAswwp z1ugdPUA7)?DQ`v}nB|OC{x$bvaq$w{kwd3L1D_y)5=&L{7Ypn!w)mJm6e3L?STm*E z`k+UOWjPswXZYewRYQNJHM?{;KM_+!L@!+Xf-0LG!Q8o z&^aQqf@>IF*p!Yt_;(0+hq%o=p?IZpT6oMiW8uO=acUoIBX8Aa?o6}r+GiqlH3U@R zW7b9tl$l}=q*t*zTMcyf=mR1K$2;RlBps9-L~v@z1mMCO4K-0vZd;=%IwG%sM?{kQ zU9V+>Iw(Yv+gtPSs+upam}xfCNYA6>2&U15w$lwNZjb!(Qvc-oobU3;;3?6B`wj@n zLvtXP#cqwYox$lf0FcVN9Wv3H@#$8Sf}+*Rtn#fDSnFbB@`-vEdx! zohvwqxC&W~=hLeii}vS4plWwpFJH%YVc|;MHc2!VCj^P4DNW2dY^N=A*|O2Ky=`*j zo0i3h;F0XVOxi>#cuE8fF-{3tHE%T+DrB#u*mD^nV+V|TIfPb6Phk}7<304!%(Tt3 z2L1&71P1s4eWJY}U^0AflY(yANOD2A&FZ&NkY|6zgOod#3H4BNC}U=lOA8qha@&cc zYr15~?n>hVCEQ23`a$+KOHy*OfFZaDezhu=7LSULc#Ac;stPfss_vaIer@ zn3h;AHh4j>{_;~S#hLgTN9JB2+mMFG6ot#&hJR*z>R^3zrgpDTop;BXe@D~1NYqp> zw8gbkE<}Rp1MX-%ORh=LhwQs?vNn^{UB=j`)_s{AL{;CZS5`+51R?B>8;lO5#r7#l zsdYP<%b`!jSz}#$8DJ#x865@dan$gP*5bUIyBr;Rh`ddx{^;eHnbDY^=~wo`U1Oq2 zirh6&nKsGPsL&~4sqm`KnG;vT(~mq#GEF^|nozI3T{*trx$i&UIqye%qtL8uWp2~x z8EKKwzU(G(6Z)zC;NJE0-#y83$(`XYCUuq#imklAqW^SrhT_%MF7q+_vYg4YSjN^< z2`zgZLv~P$AM_nxru7}MkM=#gP%RtRwG-&CFd(~@C>^+*qF9JVk^O>pHUK)3Jnl8J zkqOpVbt0lHkxc?LEo*_8Gs#lsr}&PXWIn#UXO%y(13BDwqm|inOoKnv;DV+SqL@kt z@=G5CXAFfm5d}=ko;0+;keBw$Zy4mBO47M1n1c8iRIK!3TP$Mn=DvF0e_Oohvnw}O zSv>4+)NsCt!nKdLTyRyXgBBHffO^KF(pWQaL) z_3{1uqIAtx^WGlMMBiam@O*fup5<AV@@8mAxU8}vd@Qh{_Wyh zde!KCGj2zmOE80cLJ!ViV-f6E9Vk5PrA~-yTs&c*mP(vnJg8I_hHIbmxK}s;^A*JI)*rK z!m)14Ee)myq;mvzYa+RL;u57o`iWz+iUkl7>&PuD^_bK|JcM8x!i(092HndmV_wz6Y?!j>;&LJ6sbFDdsk)X4xIt4-q7RqM0-N?Z$ zJ~lL7G*ROzgP=G13Ka2_LbPG)da^LA1y&HyB)mu}#b*HpsytXoV?C17$q;>jab!te zxEoeJcl(ihfabm)Sq2nS^zD#W=q@{)Wx}Ub8V6~v~Zle*-kF}(oYug|JxWJp| z?t6wjNwPME545w!&U&kBa|3q{?$&9ob%%QC!wDH2dAtKbk=tCs;L=>MYKs76(7qSW zpcDk$tC_lLrT_>V6X~~8&oy;^Tp*ZnR|_DTswZes~^aF41+di zb++rmzi1~WXN_G)yz_7-+VO)zW3wF?K^$xz0?c`CY$u}GaZwjZuMOT0y2Wa@-q*FI zN~|KSJ^J4RW`Jt&cSXMs_eAv3$hvk3}%B-VW-()|e z?$ZgY{V`p%cmUEb7)o+IDqT55MuIh$3NgS_$&m`L=Pj2atk^2EFWjb?b1baf1SK*( zcOhOYo4tISp#ugXlq=tCAoL*wSD!TlxY2r3aeXvaU%&L|#>7V6;%?OkKN;?mbVs^s zaz~4r$mR`isvuYsP(}z5VIxKv%(Gv9opZd8NY{S3h|C92CY<`V>}^m=K4S9r#ajF7 zodn9l#2~@VdOVMa?#_gxO?BDW0pog)ZXZ@H^f_w@FGnk?-strNT=PBE`t_9Rhs%Ei zHBePOunnj_B)++SI`}ZsYA~%6YF?>l49BoxXr>o{X?B~nMjd-`Lz~8XQFmu(Xm~Fy z#OO~um87laF=TgOd?zk3mnHoO8GR>8&Wxo^1g(WLC9EsVI!SYTlut=$dn;_t*m6m? zv!97BE$BT!m-lX+w;hu$r?4Ef?D2bq8Se{O^0KlVUQs-5O;FZjwHmaveBFmvTGV!U z92AKo*SMTM)Q_@g@qCvLls8{vf$tPKu4R0N{Z!s*GDTDx>S)8Fnz%h0V%Rak0xy@+ zy1y^-0r+*;UBI}k9qUc{Rb$wZ0mH#{60_-A5Qt&+k?5f?Qy-^1WVTIn;Zb7`Duy0L?QYNCF3&;}5u$hFkr|ddkv=3XZs{ z2U6%m6&dBABzm3?X$baEG~#!Pc5eQ{9CdIFy%o8X{*#&2TDFR66>+oIQRTYPne|e( z32hU*W9!@Z#^+)qQIvc#tktj9hlJ&C2oVj@_WCeSzXS-grQ>0EH-ir;!u@AqYk({U z3fCVg?%ZsKy7}nDgY6GI(b?A+%OY5*I94a2qRWa`fQWfhpMEQpdw$kd9#uG(s1P>w zSSW-17;Fj{j6}r?sNG%_cydD^?;rSdrK-dAHk?{;O8%iQHvKgT$LFdlacHwqAmb>P zj6y+w+B6$L8c&|VYu+hiYI6hjIiv7=L^qJ-y)zn&{uyU8QzD>a_jBu%)E$5K6F9Cp z5XT@xns-@%GtC+%JZIRqQSC?a&gWPik7V~tvk~((Uek5&y>utT=4m?HvBgQ@yHdEO zdQIUHEMPU_&M!Fp=$W)BCzGj(9e{+OFGVnvma zn$M#IsKoAhXeW9X@bBH5&pVwF)P5K8ux8vQT94-x=h>OeZ4Q0A=`3YRo3ATPS+9CQ zwkxmi^dZCL!#mFDY}V_x*KJ*x@7uvw*Nf&CEp~H7@4<*LSNpDu@EB)a?UsvZ>zK}) zZI|V$hzQFFlB?eDj>AkAU#pFQM6gr4TmaiC;b9|?!iCh9XdHP>hG7okTK%EV zt~VkTammM&7&F>)D)-hqshwS-Tr>-v*tBigj*kcdb)*vXKT0^!0@qh;Nw^^rWw~1h zWddYJN|+CVEW?S~h}Cj5^vTIlk$8fthtUBf#21g*cLvLrZkyfNIz1p~p;To0BMqtB zmM?IBUk#quI`EZ+KRFX!B$pD}iOjdnp5(43tHzf}Fs?P|dX2K0iLQ;vqVhg$(y9AR zMi8Y}=C+D$d&H;qr{bmyH4sZG$y8~^^T`iFoPU$Pn~BMEO~mg-ANWWc0QJo})@;C&bNDz9P+D zxy@b=Cz>vA*st$Hcr)4`m!3LZ=i@QFS6}0#@VxGmE2X);=97!l{_OJ)#?X~WuKO7; zxC5^@p&Y#$UvKx+v-ZQiJP!+4w7m}u0wt@tg$1Z+0i=us)4~)3-hS3jXW)4FKg)$h%`Im19!a6w!MOdbqCjzA;uS2n16tO@a;EGf|J zKe?hGKZ|&40zMFc`{YNZt}p$2-w*>B8E`ccIr+~_#JKwW04p0g=UoRXd94~^#~F-LXP{0d7qkVxmSY5dV%%`F@QJ8XDUv=-0NuH z=;a<+1i29euX~F!P0@@ zPVSsMF}>#SJW+ZDVPUVas7aDynwW!Bgk(6Mk)ENSfyC_P zCO8L3lcB@xmmFpCRTs_!{km4XJJG%C9jm_E8tER86_)|3*oo=kH^utG_VxpAgP9$W zHUd!>?HRQOp`i756)iM2L!EjNoO}OZi-AYLVxQse=N;8WaRiek#;GHuf5Lgvep0jw zrCq)!`Q&}I{xoGsry|@X@IB}m<{kVI(SXtQX4Z(j;h)X-)knt-J>9FkljuUd9op@K zKQw#=;SszT^KyWFOVS*--t(D~4KT&+4e!-nBiJI&!LY*R;&{F6_a&Z8->$E1F;ph%gZEC|(!T|2N1qc`>zA$`q zR=X$u0EKt*`1T9$wDckJ_44)h9`7CxvU=chAhdw62Gup}>wveYenH5*g-O&R@g@;Y z%y#0MFPpaT>rC$?XSB4%>oH@GOo7bE*vH^}w_wW&+EX$&X#C@yqOmqv(3wlEq6G4Gy z!W9^2c4!tzH!XJZ{!|Oe9{=ZE4)w*ZVA>x)$y$v4m8{@UZLd%c6Kl-N6dW-0w^a#fZhhv8F%=;#k?)~scbPMJ? ziw?au2*(b3!=L4MYd%)6$v3MT=mFiD+b8*+jb^(85B$QWUu6@JEGIzc2i=`NhYeWL ztDi#+K!+Lt_5q?BE)Y*YFlcoEw-2#hy>32_JP+c_?!%r4G1G&xs9yS31HBqp5fklIhqCp&gm5M`K|-`nHlTOO}F ziDohnrU|id>YaJOgGj!p6!T^C~vabZnWutby%*}w3|FvBvYoiQkh%!G?@2) zsxw|jZG@*TOa0R2uCb6Z7JfUEHztyl{Cnve0cAKJAm)>UJ2MRl3ha}MeicZSTEcjw)a<=D4NQ;b zhgE8Dh$)1wzG5{mV*#m~pnx=HS@g-L%T9)|?`26;<7r48Y*z2i25b{>W-<`{32b-5 zgWG@eIblpBeL+s_8;|N$4iP+k~^EKQ-iY&)an2(T`4N(N?zRGJDr^#WKA?KFM$1 zIPqW_3q2aLYJ`b|l$|QAg9{)XNM<+D?%e)<_GIo*pqNiJZ`1KzLe_K(4Q)J2*CN`E zwpY(s9X|^h3kf#LjHE4_`%-``o+NYhN~8E8GWjFzf{c;pVT6l*_(<;xI3f$!{>Uz^3mk&46yN?)V} z_{E6?3W4uTSz)8d!^25JMdNiPbR*$Zyd_OX?>Ez@V0COLI&QN4BxI@c+LY0N5;u^rI`St3h{YK;^CeXa zjxjA-N#4o7B4fzYUZxu5NvH%olS4LtIWXGDKRkTX>R!m^6x!Asy*4k=As-&5o{(xK z^cuOf(7=Jg95ma157f{cCvf01Hx8PYgOK4)+s-VKlFk9GrOUrw%Hm>(3QE%H_a#Y} zK=ApR$WwSi8qk5Z_QfignvbLCIcaMv622$Z{HYoK8lNFX)Q)z-A><|Ez0}y9%OT17 zKHBdL2q$-K?bE6rI+T1Ce~wR~MxI~X6lda; z!5{srq$G3_V2^@V@JpdTk-;ZArP8hB^^ zbbD1Bo~w&2T|lUsq@!Y5wx9SUN9cs!5eju7!P)HR9q6ELou0nqtq{m{<1adrdA#E$ zy09tkpHS%=syexZ*e0DO@8o;r)4@dI?;f*Plz4NM$7H_RuC=psr$rm4T$=s z*r-9X_1L#1IgB0pNQf3Y$EVmN=_NZ$L@`qU!C>*7M*9qo&nGp=RDx_UC0=zSgBat= z@b#lz%aIq@vnJ9vTPf=g7Op1puTU`gM8jj4)sm(_ zVR>@8xspR%5I7Z)vnA075%_ncG%@`H&gJr0Y3WVlpe|@C*r~N)YUkBuo|D>Ge8dy` zkm>5k%))$R3LIN@b_!a7;rku+8Uj58{FHRzE)Q+2jMv3g+LQ1LW3 zmf*akRiDW@G%tqv$NGOu6}F?9jR`dgkrQ^!ej9{0-`}v1b7&2GuMA5Yr8iF`g$-RX zMGSodtRcuE+_IGw;l-ZP7&!oeQ0w{x?Z`MVgln#ZweKWmV&~@vbSjsIV zpaJmRZp(LBx{#1sNw;C1>YxUNQyV8}Cio~JZoRA%nojc`=S@*Xjs9qarLI@Ag&J})=D9Kt2iIobb1^C8$ zVJ~dD2U+BI@qv86KSU$AKuM1SenLBOc9AY{^>qT!0=$imHJWwK1!?4aDOAKV_o?Cq zr_5&Z`ydirk_B1i5}hDTN%(01v3+|41=JEI0Uy812R&>eQUtt2>S$shA)M#*cF#;C&xIZpVxycKXwl<`wjbcq zlWxtTK96|qBhxw%&5=U{Va+4YLgF1jwP)o(>KEolK6NxqW;+*Sa}Sam*2CR%Kz!hL zf%uC?wrP>667;|dkOp}p=mgjS1%x3CHK~Nw!42R-l$yb&4hDNX)oG}Xz3prBdif z-K9R=+S+h^hf;IOX#|_GI@hEinsr`8HDj2FG~HZ3JiVjfIGaiN>R9xGD+`=w0T@^p zo}NTB9@((2^TlDE4A9@spkioGs~fcbft%KzYXEznP9tPsoCy1--tyQPN<2X}9y)k@ zcU-+OB?Ig0Cn6LOX$K#J)vELk3W*0{BO<2$e_hcj~@=YvMbgXW9=mFxRcz z%FD;0zYu680r$?6ypCvFcFL!563+#$;G}6mxfw(AFCasjYBv2{NS!+f zM6`LUe(u5I@b78GvIV2YMpbZF_2Ybg9MJ}cw7?Jr-0wNR=ndexVAL^(Z@TgD|CVi7 ze@mMUFob9W%Np=7k$U4wzyf)zeL_DoluTwk{IK`&7dSMOkV+Hnz-JE9c0iMJu(V<< zy%ZZhu6BQ(Gw7U{YfkRrVLHRuU-yW^`!aKoxZA;Xfz8-+Hgc6if+T5hjbuTjSs=)Y2cGWE9GHC32;JL z>OX&>B$#W23mmbFO?nDQ-(@tCsvz-1;XG9X@6!sD4&sHrL;9Ht&<6RIzC5;(exfCD zx#EACoXyE(zw_@1N=#mTl%8#OK^qGqEG|5Hm4*Nrx#rrJ<_Y z24wBS%tlkg=)zquho%HYOV6G7+gYDo*hPmkhx9n&b3uh5u=X4Lx(Y+MWJ-W0_THz5 zMpJq|Ocn`$@>`;sP8g9mRtQfb4KBteCu=uOt(t&aC!uVhie#Wg#u&HpKqiz4?$I=A z&^_!4X8a(z1(OWIq4LQ$r(e z*3rAVc7<8KGDqP@x8RRbmVMS$C&)~Cl3Sj=j^k{aY3_9TQUaN&9RsAD;X&q7urq{j z$Sm^`-oQ`Z-#d#0HiX|*`ZUz1BrB~=On(kZLPDKB;roCW-oOVF`6U#&iYD7hc8ExH zPi`VUGGh+4Y=w z-1~lWkPIKTxe81!s9bzo#xgnanaOTBe@Wmq8$I0=Q_%%~ov^yLV&Xh=BS%5P#t%PJcPpBzs%S5)W(#^N&wSHHPnZ1t znOska%2(A7$Z>iUMzG=8}dU1fu8l>1~FLC5HB8DbH|azy@pZ57PuuZQl6# zyCAOJ>i)sJ4zB2``;;JR26FvSzDkKpiAyt7D{777Jf0n;_YS-z=HF4n&zUSlOKD^|t7&D~jdkss33*M~ zJ_-h29a9$8XR^5T(4qqSZW?3uf?-WnAt~xqDNKbH#Roj&X0I%mToG&@l&&355i zBX1yV1D{EZ*K}kmN-9r!tHeF>I}C9PJF-8I-^~9?8Tc38;gcuooO^rtF3Xu*;z|k1Fbv%i$#r zyxF!bB(cAI`@h6#|4;t)UsUV=0I*E#Z2!fQ=^6en2<$(s^8Y{BUOS=FW{?g>*wq_! z)CuA<3=cx@7umwFAYR!fyxeaNdb!DfE12((1cNvr94lOHZ3U3xqor;q8!du2h{kjK zV0|Z+J%-%?ezrqnCyL4b7?bYWgI%eO%AkY~YjyjJExO7Q|D!~fRA#F>&z47wToi!c zw|}>QZBUopQk|mjlP`FgGZiuA&46M5iEfLZ64IdGB)6QBABP>+5HH_xt zQ)uY5uwd6TWf@G?`4}N8`Heq+9<&r@0^2Y0GJwW2N>G#(VdKfmNMwl=@wt(?4QYa) zO{lBFFBup>4+8J})jyq|H19P{?p3d9i$Wtj$&RWBbBu*pwMtVsm>Zu|Mt5Qk*c)`h zbr4hCji8F4SEq`fR2*!Rmx}rVJ7k0YlAIrH(2mglH3U3A4V}yTm-Ty%0LdK4U4(4`FwhsSBxBt3i^sWCw-%?U? z!eUaC{0`>&R?~zfkGXMEj|Jc+F^#8`o z1@-O3jLl8Woc{GO|H@HxGPYL1{|iz7gH``yi2aZ8Prv@30ry|08UYo9QzK$?J7~*0 zC@F*X$|C{+Vnk_D33$7ENKt7jNDeIOlvtb!-aL;rKtP+`oih@PV7~WBgz^myEy3DR zgIK{36bX>r;hG0LeIhe2T|qxQGtV)vI1?rS))$_cQj$>&3`8Syb3F@VBLid5)^f_A znVFfMrKORf1!zM%c4%&7q-SVmZfRx-Re&Twgmwc3Q&TfNLsKJT6OczyxF|9x93zCK zNK69-B#wo#v7Ui}xrL!IvJFV4ATbRTjFD6W6CP3!A}KQk${_g;oG^iDB0n@Q6Lc(y z0=RGsLOK@#6eOrg#~yF;d zV3)FbI5tC`hbJ;klb^TwRaZxKFHbWbL8Ca(~HgID%Y+pe=sTiDbG*SV|r&=Ju)Ac zmTxW9n491ADE4u0-@4;wZ*{NivOoQlWx0I1{l|tm|0G}E+Se9vgcB?(~y1UpUvkp&}yQq#b} z13gB;9GZ8q9M%HP>zP%+=z*vSSBM6lrJ!I0DOZB>^MM5f{8$Tp&%CsJ1w+X3FTgSY ze#}d9Lc)*#^E(?SH#T-Q&TVX*_|kAf!UOh==a@LvV-*g{FsMWbHMV%Ob%gS%ym5^A zt)=i#gF)$vBU=GeDI=$v+jU6?!|Pvpco;a0x%4o7UR;t`R8mm{^pv5wg|Q`J*MvBY2QxT0uyMaS9t$~Ch~R>ZYy*Mx1I>@QoGxmXE1U%C+Y zOPY-!I0;pS$>g=Q7_Esw!5OC{m%? zTF-bgfK5a2dQPHwcGc}5np|HKI_=}O{EAxc2fnY=T=-u9s?=Al*-fUSz@XFPkt;b2|AxWB)DjHnfL zq4U7q#?`>ndV2n0VcWfzCM5Us@wJ(4=}KQ+{-e3Dut2!|UD7cy$ey*RaGR!-U0v9t zuAwpg=aX#5;xwy8NV!bZq7#At+6})6?0k7)JMp@^o2}-~c4b_enT<_AWF(`s+Z5q3 z|4Z@eRfz|}CPB-~o*Aa)C6CX17&CrxDxQ{uBkcO0Z*A9f@Ns;v8#Y?}jHhQ~YA&%*4y~v?MHSL*a{O8BpGt(pHMC!oBHFAm`!u?hDY)7Nl8gulB>1BEN|bx_j~Yw`ThI%1VKkf_sV-kN>o(zyqOt=fq?<* zjvac}f4rl#%}6!g1sgW~7JM02i%a!N|;a>Cu;zb~CFzO(_~`?j(1=DmA# z-Gz?9r{bj=mhaw=h|t#3^2JvWa!N`Y%`Ge_2nh)Z(IsJFVI@OD*5u@5EiEmAfq~)h z(W5nujcR6RhDSyyhzAcIgsbozzVwA^x2*S84-b!-v9>MrfeO0&1O&F2nVG4msK{Ac z^RkKA_*#E>m~^Jdsj0m^Yo<4lYG`Q4ZEBDrFE6jD?E2-Ii5?c*vfJwN5&VrprOx$< za`##OU%kb*GBN~XVqy~Uz%FHPun1{8Vjhxv?QOp8XDULKhrYyn#XV|TRaG_e;X}1& z&z@Z>s;{q)C@noo5q@3Vw#9F5qUVLnz^BK@o~TCf-h24)VeevhcX$5zDoTCudzVmQ+@{=c4 z-4XZhalKJcP|&LMUQw9kJ@sh+8=33B{p#-SI*GM>DJ<#53+2kS)zaPp7P{uYf4(7y4^;w?2quv)1vem9R z*}v%l_FK!FKnB~Er>Zl}${d08H?Ts3$E>Za?iCb>Q*i3(>9I+>9rT)QGY~VYUf--S zyD&ZSwXhhEPd?Jmy}yM-<@R9+lW;^tO6b?P~< z#zU&F$J}Q)4;(n~dv1=Gg@t8^m9UxUE)f0h{rijRkb8Q1dPH0tJ9(R5hKIR%G+V}n z4|Ey6v<`LI>gDCNIP+Q4c5&v1nA_BO)YQF%rGta|y?giCR=p0^8ETAJ-V&MnnCcd> zzr5J>>ec7xd{&}_&%TnYt*zDj^&}-l<(2j!QPE^PoZ!Om-@e^{@#2Mx4hu6gZ};j% z(ExSNww;GLU#_7%VG+?$aBkVMrMZwvK%Yue20Lm`xBl6)g1xWRc<7rY$MKQ!H=p2* z{8`T>DH&ZC%D(Sx^w)RM!G$LyXnuScAMjZdav!7Lv4fB2oV&Yw^3%k!vPZ^6PC`8U zFJ8Qu>=hjy{kg<-+;7DPx0*cR{LtZ5NeOksStq9~n=_|R-wzinuxnF$?sRJ-4Hbdj zqiNl9n}*$Q&U1OX9))smxA#~ppXkAZoJ4EBtxjV@16?5=I1&Ex*sYv;7zyr6ue>KM%DzV`}<1JjKw+sJYx@UZDr8oS)~+@B5)S zIS08^$9swnJbUpXxNxBOvT|o-e7s4)YJyovZufuvL&w-y?PRntQ=fyLr>(7RbK>z^ zHh;c-h>VWjca4LBfdCVTuD1W2c}9{eFwJe1DI)Zo_g_UP zFI(>QaxjqAG3k%p4p9=YNE^KG%qQ+u#5A_I3{8 zKc)JS4tQ+$o;}-3!HIh7-`7UDZrxX2C#DD*tgFViZ^Kj17#gbJRb67p4tm;0S&*Nv z@D&T0nf{|eLWWA_xk^*BJQ15FPOjz;A3r`gv-Uprko?N7qgVGk>_Khd{Z|_@-oIBj zF1;#5!zLDxpP&DQcelR2J|iO|k50#j4;rK9Iokwzv28__M1hTJQ%1py?jiSu|X1pf0gn+Kscwsn*Gk z<$x(;z2<)I@V|5CbHqMP#yUZh65UP%RnZF-hvo_8-cmhTEzoVdOIv+w)7PS5>#k)Y28`^Jy#H4&LzJf;O9$dphXE5fx!=^+*L?Uuvot?>CoV2dYaYd(F#X7T1*_S= zK5;Em%k=EokbnTHE931n#Cc0go zF+JMX)Xa<@YWK$NyF*aD&kw%7(bUp%zvlsNn1U#|Hfj1p&;jR>*+C>lwMWT z(h5&mMqSx2Ai!YGzvLMg6T>MbWxU`ZQfFxLuhN+|H8uIBrwg1lF&P>k4+e@cpB}C? z#QIY^d2;$|^toi8wN-o#LB}N|MDzOH(J~8PQ3wmG2Hz8)SEYN zmcMj57ME)F?t#$4?{^38MMT^JxLjCTsu>vI00I~tsFYQ@yE72Q{sh|8w*_Wq=BQtQ zakTiy{rmTa+a4lp?Ck~0RI?3*T&(WsC~CA&Tk|;| zl3P;u502i8j=uBejl$Ds&yw(Bqq4pO0^Sg}ZA7f=npZPvX<33Jc#l z0JO1n(%YwJvAPnR`^y4R%DDOXRQK!X>now&kxQVz++z@9`qA`UgZ;|SPC7irn#I}ii{Jo~-Idb7F$+tRmH25}9r{X` z0Pz$R6xI`*d-ra@W1af*r{+R}*G5^{N;?zwAFh$VDn*&Hqsr`!x-Lu&*9NnSnEQ%a{}tQr}K1I}~kmFKMD8zS~u{AhVba0>p!3)mc`N(5#>N@tJ&4z*swFy?2&g zn^eMPB=Ib{Za6uK*YBL0bxxoDB9oc2Us96g`t|DsCl9}~fVA|^b6&GdD2Qf`j-j!K zE>zdnZkU^!OJ<(~k=rjlP}E%FYAE1zr4Mta`NP@yLY!$tjwLk z6>l;rxpD({PFrNt%sq7Bhxq5VHYS+_u#~9X%KcZ@ty?#A;oP}%uU@^!v6~=n-n!+_ zijGIDbtIg-7u1uPnJEyODJ&~1i~hUCf~Z(sw9j`QF#XoxJM&23@nnx1elEEYz$23~ zfNH0H|E|U=r`x?-I6tXGQ}<~H-9lyV(IAzg%3rR%Ma~J~DH&&qw#lx{Fu2eC}{>gvw{&BNIHFqlYd(!{xX!!JrMT1*w`eEqqV{EVASq|cpE{&st z82yUbfv#gl>5FC&TvDzV`QX8A({lGD$DTs$O9iG2Z_r6^MbOlB9z9`Xv_p1n`H*k) zt(QwPKW^}BK<57Y=tkZ3q zo46WlNKcCP9f;f8hXZX^G*_RhS`Ne5n zxNsq9`Q;}Wh7#hshX<;(>GNN}v7vpX*VYkWQdA};Cb2P+T*tnn)lhF%R0MxyJ?5T& zP_BaavBTjbM>cnOVyl91M+P48UVhaSm4e!o?AT&dj+UqR6@4N`#!JdKy0Q|qQNy|t z8-(@fRlxu%yr!7L7l-W&%F{lnn3-{rsFm%YDIOq)>~3JeO;f*L&X0Y!1R;$%a`}1n z2!6v(&@wRG`XsZYF1BsG+h1MFYQN3Z452#?S?kWXqFPzEjpUbxi0~TJ&T>yx>Xq%< zxzlE9uu9BjP|mI^@0pE9{oP$(g&hjLmad*gWzzri7}w_5mFKUYX{>nS&bGaQ3i8BT zzzF=SpZks-JF3S9)6&w!P<5%dZhg8(`EFCovy%-UKi(z6v8kGFqm@$6a$p~3?95C{ zQ!_O+&3B)*>&~}jSedHXZfS1LEjV+PBwcaacT4Zj*qWK1eo{t8Cg18EvvIk5L5{?_ z)gr^bbOEQ6*>R5_Kd!d-SekP*3%rS7w7IR_IJxRbW+l4?S6^)C?Fx^=7H zry#(+6em!2hy+`foZ8ZugpBh8C@CpzhN}IOM^KJ)yDPUtXR`e#psA9d4(+4C^x3~_7k^ffcu*25IW`CJ}R#w)`%nzMdcR(BF`*c6XfnKZU9zEI#x?dLVQn8qq zpU=2A@N}E1L_omJn>STZ^nXO)Z{7?}4b`ACpMVr|@X{BR z*sd2~mv^w2hd?aRzDAAz%ARhDe3DoLzHF8VxebYxs#HzAJ>?Ol~&C;^+4zhx0Dnc30%_j(!aE8 zsH?vLNTj8sy8$LRIyP3_-@hA`LIG=zu`phwZj5ptdk6shuF@+%=r3Km)C5rCzxnvZ ziz1}fhnBmrxM+^u=h~}QhpsIx_Xvt=x&=gM*26BGkR`3GKi`M`7|`ONW-Yz~4G(lts?b^g28?|y`@qokag?Krp2?MQ)>EAuN$z&E;U;Ayy$sxJ)@ zLz9ybbM^ETN9sb8Qd0wgkH38TM(I}kT*<}7B~+;YEvtoVDB2O~>2BZ!k_rguXUOU5 zM%u&`7asvVxdV|&UQ;vsu`#~ZIqbi$eGE>vyMWSb zI&&=qXe#hfp-13g+D6I2!2$GJ zU0t0l)2)-9k&!X@{rep}$Br%$TuE42S((&PQ^(E%dzPT!;PKKO|E}xju{~@r%`7eb zu&O*)|9+osdu(iFZhrHV?Ap#-o3>|7KL79O&1LU%&m-Lfi>jL&sHmx{p@9reOqfjU z!ev`@WSQXa zS1(<^seE5zerZEvWAnyHJ}N4z*Vta+APDGE7O0dq-T8cYF*$Z^{AbJD z=%9s`SYM{3r}ZHPw+5m8XfA$#gV$I*RKit z_Kd2`Gew;DRGJFx4M?2ykDwRx;+oeXl zt*uoID2JR!kw~#_Bb628h&==;JIBs_`T7;D9<)UZ%9GNG+grJar;zDE^?0BJQ_4Z; z&A;$zH#c|C-Mh@)Ceus|3?~#6*x1;xP!+J0c!{S^o}57IsTL0o2uMVMqbFKEe`fgD z+}wN*vV!8oS+qkwKEBNza_%2c2}i?ZS7~drj9%U*nzqX>%fYb`U6K?Rf3~pT#?38t z?boB;%WkvRUjN&@G18(s19t(6$(o3=`dmGhk~@vxs0xMqBG3-{5SO?(6V!;eA3xST zI&yjHXV)RJu^GP>x0FPW%w;Hf1$6>O#k!+wgBZS7tk)w44B~KdwMZ z9mF7r3MY4GcXv>?&!2A^aHKf*?b`%Mp$zazwmW5IWmb0f5$GZCg{lFP&77R>zKcGv zM@&q&Q~CUPPJkpDSU-PIuUFyR{%L|yUs8@ngm2)*5t8VX8ElmyriER=nbVemv{m#5YN zs-K-OiVL8^oh!q9Ac)1q#i{9O3IZkH3?^w#ZY~9p@6<=W^YsMGO1aMZn;W(e1kkEN zf{d5nrG5MMkvfKgAM|>?Z=G1UP*7eRG_1h(oSL28FqLP&_fHh@v5GNO-KAQ;9!D*#=IE>&>?(L z;YrmB3mrW<@qGm(zs)eb&Q^Htz-vr)gm@SA*9*{lD`9E=--UZHP#e&4h}$vBtS(qs zUbtY;9k2Ed6Ag@IPVySJK^68LUjKl-q1XaWj9_gqRx(d8PH1~IBeQZzbU}durQ({H`^+Tn% zGC?Wl@zL0MiY_h((E<)gChh0vrzHGW7R1HG2!cNFX=B}^!xt&x)iG5RJA*NI7deN4 zm~B0B8lzk=3?!V zTSrV>JYD)Z2;;Y^4F><41*jfB9Y3yTXh=2qHL|uP%P>gAXZz`vH~#;Mac=i%NdM@G zc<_UtHDzmmcD>BShsLu0U=4+vT)Y(i;N%M(J-GXufD6#yHhM2lD?_K&%U^hW<-M}4 zZK}&zFoma2pOONgHGezcwZ6MF-`;1@+pj^Mu`IN@a6usB`|vO&j4Svs93&106T4Gj z-@$$OFe?`H8>m6)uFFMSUi``F>A}Z5=34*x__#!mUDT!8s@L7zUf0yD!;@K9U7EBi zJSrsxmE`Oz&Z1QSDWYuW9<5kdFqW2nxIv7 zYCdf&4_p#-qYS6&ZX3W+V@&GATYc4sKKzU@EAF_7M9xsGVhFj|KiW)^-`5uCK? z^XD31daDYPN}zJ)1EyO86}Y!D8YnCZd4Wy*{_{t%2k7+{U044;?x*ov^m7%qs)a8%YIvYp1kPAR+hxJNNFLIHlLO zPbm9@h6WAbEGM`6V`(Gn^YiElF2ip&L&YuEE8_ccglF&Gay^fKyR7rhvlb`a({*)q z@C#|sm@Ny%v1P!6Z=zsHA3K)oI<8O3sW9L=ORpWE-m*o+XVsHb<=nS!+O+8ko)@09 z0*cr{>-Vha273?+Km|JiHb4uPFa(<)C244|>Q-l^kF3;{QDXb{?PQrlc^9={WV8jv z-nnbn#lOF;$e%+tIaSro+jdJ+p*{e^1XVOANV)PaFE0;HPKH6;tcFgAj(pf-PEh{D z3DT}ne{@(oAo`TaQJ5Pfs9IfJ1rkru?@6-&hr}+d{qgyQnX~hDgk}(4;KH&)Uf`gl zWIc-KtbRSJZ57(UL8MklAq>Rf(x#k4|DZLmyuwVI!MS@#O#ssBl~4{sCRRdRfi#q3 z9pNWEg{>bR6cm)xas@)0&D!cpo2l7B8JWi$x3bFF+1XXweSrp+2==ODYs+`!@L{cV z{Y=QP1}UT?h$6}ZizDeSEQ!8Kp9FZ)Hmxbz@)>1JZvq3**KB7-n*m0+GE8OcTKB7| zswRP!>0o6lP6J(t!MY+H=Z|f#U;6?W$V0VA?tJ=`XQ;%+#-<4hUtmCr>v%iL=f2A{ zzxvBhl9zt8ox{7E?X! zJ6w+c=Wc$494Mi3H=BDfK_`F#zZs}Q9*)iXIRqDyCfX*h&Mg1E40!Y!9g5Y#^jrWH zegG$T%)^K6_GkWw$>>X_b%1s8U8A|vk(80KthAJpW*>Hi_Eoa&MU+;{jn56fwz-Oq zMJRBmUTQz^A3qvX3*E;)nT*=REiAkZC1*W>b&~w}43tA`+|J5@P4^rey7D$a7ui6t z0_1LV`S1PL*(ryHb-A(NibtT?XzA$Gpo5r}rZfK6Tz}4b(f(h;^{Z`iM)hAI2+8#k zBF)Wze<-;5kKp0=hM9wK+y7mYzQF(EbV1wA<3ShGx1ebu>O>dS)zfoA(SI$~%Gn8U zSTsQZTW0laZc!c-07xQ1jY^?x8}{y9-Tkn<7*Ua+{*yfPj~5?+)&}L~iU4{lT48tH z%FVratRP^89iKVWCff!?M6RuWe+6M8HV-1q=;&zc3H#1U3c3ajeLd_>-_cPUMi!PW z{>a4KL@%GJxHj1zBX0j-Y88U4VTEUL^{sM8PZbra)rFDm{?i;@GjwR5MiUFz2e0ev zmEC;c=4BY>Cf5z437W26!gOM{Z&dv>BEG2Fon{JT$Zd-j?gVvUrVm z6)I3?j@hkhH`E4{%i`{7GUD}AHNtP6G@wvg6-9nmFrZg+lk&~4eGpo(b*RIRn!llP z^YEy=xD3JhmPVWeUkJyMOFZDBX}i|Y=PY16RWGgEwCz0L@ud1Pwrws+ji(ble{beh zkD02QCd;IpoNu)oUT+A8Y(@L8^)BQ58dwWTkHU=(S&O;62$3dL#M* z%Qxd{S)>~BVr1L#$A(}o??62*_W`-z#vzm8@&ayt0b6!<_L}iD&{_f8xoM?kjbXGi zflx^?vGoMpIWAdQ4kWvx>W~Mi29k2~L6K4$!T;_>M)H(Z!dihWmVQtMG7pwCVd}kw z9o@tlC^7(|)mc_`j2xvw@eisa%0fJATMkQk|4+{)TZFW0)wA47%`SbG+_O(ThJ^C}a$P(j(bO5pPHgAYU z_Tv3jRYL{CJq7mr+}F^y*g_%ft=QL&kB`^9d9xmHbw8N@jdh#&LqC1`qzs7~q66u_ z!6X~5_TNH10)QSw2A)=6SX^9LboHNx|6Pq`vZt&PR01X}V_kh+-SF!h>#CQKQ{&?0 zRWd7!eAC|k08zjF{LA1nijwJ}?2<}gDE{-BkEN^d2gYBmEiLqDCW8yq=)*Y!UIV#SvF^SdKxmJ)~ioNp<%(nHStHUG1m2Tb_O`@@1I|QiZS$#_Bym8 z-ja(R9K(HmeO6W!Cm_xNn0>nQ!S>i*%RMmuzn!7yJqI`eeIbMt ze%HKyf7wiWfPfQ!FEcVTw_np4H$mtSu_FCFOO5Z}uctc>v#C|_t6q!qc2b02O~s`U zmI>#}v!7~~p#~(TrWy@=_?tK#L!-~`_I_hJ&Dxv@J9$xf{@|L<-0YM zATC2rB4eh|s%B*yUq|MGR%+T>TN9CGEsJiCN;5Rzz86r!9QEKqHQ6!B4qy1V zvw5)IU{i^K7;-SuKC5SSdA;(cBw$U`(b5t?y&<5^V9WItUP}rujY#G0=L!=$doWx$ zGKLCE-0Q{U2h+Xf1`+)}sVOOPU~X4@^ru%c1c+DN${@gK+*TP9syT|wkG!JLLp zEpK4Jg6Ae5TTUr3-17t*Dg%#F?f{vyBw;t!pC{+o&;U6c!0a5>kCMIY!H8lm# zRqXUxTao;y*mio1fgT^e`jZu^x<6_LEbG=E(~!i^+t^SYJ9ccS|0KTWm8_0#R%Rv* z^tqIj6x}1YXHF!hlr96b0Lqildf|J54=p|Y>5+9e-hcSejC5N}T-+1j?wtI5KWNT^ zLP9{i6buXz?yAiF`oP1!(GB%z=;JR$*7n42@@`5zKH6J+$idO^;*XZSy%k<(tQ$)@ z5Tvv~tch{osYh~<10YB?zr3J{5SMa{5HEzH1n)&YJRVX?(q2IY9fGdq8y_G4zJwP& zl8khCFAQxW&HmT#_<|4@4@5uY?LNp-n&sT#zj>Dft^*g23yi@(3Wk_-Xc=R6WI z#@la`{O{bG+FCBOT(TD<JP8z`}gG$TiFX0>b?q(==X(^1K|2&T`%`(JQNFjAZR3y zl*=@64iu?FgkOF3~LtHe!fkFmy}3>7ib0` z=e>`ZnHoCLECc*NMc})%jvv2a6NjuMWJ7I8Zgh0do5*+t<>Ff7F9U;d~gvyqMvWX`Hg|$GhvH=QZ+_6Iymd31?yK7ob zPB=sgtE>-rm1%mF68A$vyXc9<*}@1S$9H$kA|y$Ri${S*kVd+ES2))RDnbJc zQRPuU02yqBit#in>(oD2zjAR5VL#+-X!pLVT$zh=Q9mUy#<7n*LjvB3-3b$3cHkGW z>%T2Qvb;w;4uJsSf*4m&q0w9w&@T&G^yj{TdILap^iq)3F893 zH)CI<_gi^+`7fr~xN-e-Z$}<>Xo%~5A#L*TBg%4sA`uGA+t$=mdASJwQp!P8e&Epy z`<9+Szh$PQBlD?5cxh=VEd!n>VS}8|dSBeUfI|<;HbvsIlhO2a&CpY^JZxJOzHO$W zYYt)(KnylU4~(8I>)o6S7`tfZMyRILV;1}!O|v2MPLt@!Qjs>p9I^YARx~3Un|9yKv0M4 zYy=(&xs{N>-!=y&cth&^I>odNB#v!0rn{gL{zsCqzFJH!mLzLQ@elU@s;Br zFd;#_#;OWWNZ1a=Y4pdBhBw>U#HgT^xKI4CMwhg!0UDg@yEahXKER7!zm-E~C&FSU zfYJKjaANNCMjh%}(~fi?%@d?_ zTxCXXUO5jbRSLqrU^ilx>j|K!*9aW}5QTMgU&HqGjaE&O2KP=rjFb;{hdJV=R9m*3 zzy_g%@D3yQbywF8gk#9$A7X~BZEfV=LujuCy(gwHs6o62oxeCWc-(&itDKMEJaS|Q z(e&z~Me#*cm~7Vy5&<~kK~$rzqibTq;y3>YVC*KcgA^B60Sjz1emhp<5#<2ngR~zD zYGGzOw+FCg9T*SkTQx7zW?WKKRK#UOmkI&rlZ|zPeX)oHTEK(y-1lIz>;yg+6)`q8 z1`ex70B@kfiG9U6P2%)HtGFvplR-N3CB?;N=_UyBZ_yv4tE0$3c z2#}QBu5`^wjl7GXoBzc2tYAPuKd{h2@V|Pn^u*-f{f~x^l7bXmdFrA&etxaCc^3y? zQy`F5jmQ1{Q$jR51Mo1k-JgA>ETl_|pk#Xa8u&E@fvJT0}2vZ~! zn#d#R>+}c;JhCa{QZz|<`qX0QSWx~JJ*zGAptm%z{sDgJhtt!+*a=_I*mr&2n8+Y# zkNHE~mV+`yl98W1McWBK%O_xCO>J$ps4*^x%0XyL2JM#bL$Hd%tyoxDU;n}T>8rnb zH>16RIiBcDz=)4i?<=k=U(-^C7ia;%GP1}KA1sP2v1S|eo4H?o!RXWH$68Y#*?0!@ zf9*=a2dIKjMtw9)ghO`u+xwv%=j^nQ^c5)ohUKGcXlVFD#?DS64W;@XJUiek_vvB9 zXSvX1_Yke{q0JV%$4+?(#23!JNbsiD@G1p|CZ`xc{epm|cR7PyuP-}$rv@5Qz9V*M z^>rluOrB@9*dw3m0z}W)I5|*xK)t5aW8Nvrv%l>6dSCbXUqTO~Y9JWIe7$wyNt%x| zJ5xH%zh8c@R#bj;(1ifXO#|a>o*L33}(fFBU8PKj6 zz$;9?^p3*S9_%aq#jrawuB*#`)#i0{8tRa#*-V7)Jd)Sg+1jf6Z~g)@rwDi2YO*&V znWc@53IQuDsJFKl_T4F!EPmm!eE`NvXoBl~p%ZX+^O`WMCt!|ZvccRuxk&<$g$-$v zV$42_*OWa>L?_b1%iT=uU}I|m81zr|^_Us0YN$I3;YpvJtn)*T_d|p1r5ijTrB9uv zzgw>#xWF++X-|sgRB&JQXodyVYxq3BgmUKp|YHFSs>vTVii8+sF z7Z4J{xbYrYPyt+6K0FpjWMn^Ipa<<$tUz)U4sMtWa_MJZxlkaa5+mWrM!I28+vLBw z!9IDDVf2!muEPcnDx}#Vx*iIuA0&D*1*rpgMGwEd2CA$-89+g^#}f62Gzv@pHmYCn zFeE;5xh~IFt|`jN5m~0?)JUJBr6i%5EFk%_u(kAAZ&j{C+%D@#laXgf?r563Curm$uaP`<3k_ zV7FrfJjpp_6{rO2mE*JK4S?QZ$lkT&A7EMWenWo}#V~3eTB$*dO~{Tz8=>ipDE!k3 zGwzZk+bkLUAruVZlvvE!Nrk*z#N;49Z5iL83p8^V9nTzcQdx^6sW}?%+5*uV(?xvO zdXRG@F-2@a5^F@-yk!l_KAvwuZxk=qco5np8J?bP60NhuI|d{FYKj0FqZ;OA;mUNb57r)kU~( zW@jH*T^v84{TCFAtp3f_zCr)NOi)|G#dH$-K9LprL6t^?9Fp0~EXjm!-HBO6kPfh7VINC{|4I?gb`g6Yq3SEKtTCMVy- z7y+rP;k}>0>;}OpDoPKj$)+P~7t9jH+^()Js0TODgAlFbE21H#Vt)Rc<>lq09KT@} zJvw@A8|kw{Q*SE0=KT0n6e%~yBKY~fdr*0Dz#lWT2z-1TXQlkx>`BiH`nJw+$De zx{$woS(&(>#p#V=THI5)^sCg}N!%lv&-i%R$3=b+jw%E&z-vT%NE6Gl;eLr7wTI^4 zg$2$-hZr_(+bIVL26>n}V03uPbSMMzX8|~GZ{2YdUUU^AXryuqSUuHo&gVD`HPW~L z_9@}O8(GBuk>J@xSB3f@>C{VN8B9td`9bC8=JwW$eiJ#)in-&k9I9_*DT8$TcGrt$ zXb5Cf1HK*NfA_j7E`L7-E#DjoT(H`W#CxQ3D_0i<$Z}=-nU`#>7!r@Sk%B@#;y{#g&@h>6A4Es%KzMAZtGf*h6sR)S za9bBui^?}gQ!y8vdM|;%8}H@EB*TH1`E!q`=zSjg&ES~ffHw-c5X>xXZB?=AuAnb9 z9^gzrv}}2+ZKF3h)vYoQ(s$^t^r`H11l!J>NxQl(HR0ZfVL+bTN1qfkE=)!5Kf5KDa4aQT@ z+>`9=Fl4?+kqiYk{azttiKQGmI%eUs`*nUH5T+^f_vvoqH>)&uUcL)JT_R+r=n|q& zKl{tiylS?{;KxYCrFUlv9RjhW$bFq@TtH8M8`!=v^qPwcG4*>R$3Hp)c8R!1byXDw zu7g#=ffXDF;Tv};5+jKu(J~Yby471(k;yYe)dJh`>`U9ub2Y%J}hZO^h_S`~5S* z@lkx(Bt&?8Jk7rp1p5IYDBZ}DH`HN6pj-$0tp42u9rFz+W{!C+HMB7cgxJMPg36Jc z_Vn_~gRvtb`1WVnfp&J7K5y@8EGL7)Ues!De8Y57OT`s?7aST%wnHUU4l+t4f( zrL;NelJPQBM$1M>Gk%!bY5kVeRjF0$q|Ai+i)bdn?)JBJD?tVlZ9QvKm&g+UFeJ$d zeHeT4HDDJxy8_F*3JT-sB|Qe?e487PMoBgRxfO_gD|BG;*{1bja;ukHG#w(cty5pRB0IAtNHhj@t9pd9$NVCf>N-D;m~1kobSrBVuie-tE;P^`L3+IycrSgN3uS<;YC)1OVi=$ z!HiBs0V5A62n!24X#KXQhaG7EvO`0^yNQyy2cvmpss#EI`YI&^bG07cU6Q|%h9)^L zh7zLc#*s2cq6CWMaqxCv5X2Z2L@;ITi_`;ZSX1%k3uL^C?8dM<$*zExkxXJt(7k~{ zJCIY0AT+J>c!RTjTj!j$K94(~v18A~zn6i2I|};meC*DF^fQw!QtXJ(KSfyNt!EaQ zlh@fNBovCz)7ztl<|y#2IB7yJw%UH zz!jS;`i~~~VVMLdEvc2C22r!^fs=Hd=FYXP*)OZ?){(!|q$i{roLjeXYsw^V-h4>1 ztAw4WL>hz-YOhg&#g+L1a{lUJ45hFm%a4SjYNfRt6=sc##pwCmUE1&=d-V7*zD=28eCmwnS zH!tr-ENXu!p77Y1>ePx~y&6QA6^43*k*tE6iODX!)mrGs0l>J36TL>56%@nZFw;RG z+PT7o)FbJ9;t$DzWHVqyQF0{yHQIySZ>^u}ker@1UL(4@x;C%NOizCC;tt4y0oxvA zQxViJ?m^w>f4Pv5+?h5vn}%{jMseGMtbVQ)UHd*H67R+Fy7Ewj*Y?e-JY4K~iS$WS zTvs)OGN)`f3JTn8)AiJ%ey4n&ZAnWjl+V;_vnxnR_S2<3X)(^w9KM08nX2opgzB&P z?H!Nmzo;{J@di$QFZsq@c{yQe*;+IqX0`7d&;X{futonME`4 z(2>Qp1SL`=+8Sd*eE!y^OOskRoim#@6cB+87%O z`GX5#B!TBz`*R>EcaJ`X!WA%f9J1eRJf*lu!D$Ebw1d1(K=)5C+3*nxp(@a}{{5r4 zumsF5TsT*7<=<~{;u8;5E+OqhMuzdDL3!#iKNURR@39?m52>DnV;;=#yl-JP87j93 zMvol&%XR>4O7$o!DUo<-v@>@P{)r?+s0t&n@be1czmY?{8@KHYAVo7&1+eQ*Oxk^{ z!0`n+m@(v=hsQD$D%sz3q|O%noE67SpateS^-0bA>SO=)>lfA5t#8&=C)bA2LG!%G zOpjU3M!(y)lX3gF%sZ8pKE?HjG4gK@rb%-ZH#zQ!G)FDNMZ=G}oxd^0pFvaTlS@^2vUaT&8ku1Sg_M3eX!`y>UtnrEkoU%hm|c6B$qB>g@88h0 zOvIJ!bseC%Xd(RDICrkx-F4T%uCxO*Nu6%E;SB`la5wXjhe4Qn&FXb+`VJ(AD^NuE zSOH9d@zaM7Or#7?yg}!F=BBP5f+bts(4dOw;mK)Gw&|fe9MlAv@d#RjT|nvUHssIZ zXPo(97#)%Uw^|K<8ZoCWTz)u@h7oTQUjk-}u))37RV+&u{wOs-;{XhNoSep-rP_f7 zh*gopfHE&;imuL#YV+YVA#(~jYzcK(pC_l0@Fc~)t`)0X?IJ@5EtB)P$6b$i+^I%> zeDtW0-J3=M2|F?NHYBHlq55UUki#8e9OojO0`t$pW95&chKhGu{n=?V#L%XursO~X zpDsXQ&_=8crH&PS?fx)E!jV8(M@F)tGYJ~z5b&|clq8l$sL%2UhYgONXf;jMHAk*+ z0h`A7TOEeEzzn8-~GWd3K z^lvNT-L2iL{T`FH8pk@Z5=d(mzSUk}{bv-O*hr%-&$d8~hh4~!T8?-uf@L?6%Nqnd z*YnN@40x=Mi63$R7-&~pSJw|w13a*Gq{@*mTqA^Id~hO1`zj{(eDQ+3g%SCHI2jd| z5Fa1f($d1#cLzCrQY!OU!@yhX=z>B?Yf5KliEFyx+$Wz^280pBe>_k*Nh&4C-Ge$Z z;UJbO?DJ;yWe^o=?2?FXa;gMqnxMs55dwZuYJ0Jt{K!KSpnsE5W`G(I$WvV+BPoaJ(e)@8RG0@v-urm^b`4>y!KUk#kbnKjNG#O;JjYMce?kPm z{rtIgusQBAsc%_+K9$~Pw~P^?!$>m`qdUJJS7ox` z%Z-77f#hfn;0#JH<-bt4Qpjt->Si4BLA-|QfZ2{s1ZJQe{k>#X9V^i^NV^0I8W+$o z#0UV$8~J^ZdKP_Pa^zSx&@YdlTdM{>&Bdr9!22HLtnh;0oIFsz9(pf<+#)~m8mDhu z*ap4Xcw+YpKEd5D8b+p_KN5og(d2q1<6mTa8#bh|qaQ7k46}m5qCPeliVt~o0-i59 z)VjLnCb)O6;#H*^c4XDu(k3iXv9{{bB}viW-w(_Aa%cp%`=j9CEyAW{#WL95W|CCO9~@6E*`C#}Mtm zec|!-jX*teSUQ#*?SLi$Bq)V2M1Cex45a$M^RNp+dRT!B`vwOGIpZ%Gr0Oz#Gsk%g z!N@hXwSdTV~5a`{r|eJ=hmwP*6Uh-N4=83=6Sx?W>SKtcTxauM~jLT3;6u@wE>d*R`}NT9zPhOL!#QC=bJ zq=tqf!ZS!0kiHaOKX&JpU%fj3Q38U4Phb&|fkHTXgNOi-;w%Ee&)cGnGnKToXvu*J ztUhu*BVIrdWU62;>D=YmL|RJR?Plhj0uNPWnTTc`pY&@5^&aVuiqE||(m zQc!a2i*?5iv)^AD+T0zC3+y)d%ilnqLZhwe>oe)Tiq9gk9I-n-iHkdp2E_`op*rvY z7xYLZHlFu?LLW7J4Y3~PFBvdFMi}(+S%PaV_9q5A~4qf;Nw!V)%DT5SI&>T^j7Eq*zF!7HJ z5Lv5$(rnr@cA!azk*DGuy}A|Ujr1rH^C1H`pdh5EhqJu+eU&Yg$wCGAXO77W^7z8# zl@)T!qc)TCZ#YyAr-r1rTUglJ2a^f+@$5<^yblrg85`tL29X3Lb3Hhne`eN?AM~^~~ipY#P zooWf_VU0yZ8q50zpq)|hjyEs{~v<>nIu)ja{0G@gdj$a`QCa{vi z@#7SL-MPTh@fgB8SSI8!&9QBO z!6bbwur8wBzWol4Q6ViuTw&Gw_gjHX1j)(^=2n9M04c1(H$Qv!?BM8V0K&5dQfFA` zj`abtlcQc1z|xraj28QRPUEnY6p8l%`C734XmB!O>RhKdx7`9G;1@R+*Kq;2*|D}u z2Lj2Q$#fmNvrR3IH_E!qcGhm09CRc*1bI>I)zpIYe}X2$Z^)cr3}hn@ z8^mylO)WA%7$eAj5t72E#UGVtGz}ShXmr$YydEF8n;b6#L4I(wSkVge{=j(pAJ?G)UX*o?=sk-DUC;c2UEsL2&%xIb=9aqr&5*QR(&!YF4 zRn$@?bMJ}P@DO&%ZP;C(uYrRWaN|Nz7Rccg7jgykAbd4~;72Xqk_(c;I7|v1K4tfz zy~)p?Hb!ehS$y&{LysI%!+3n=KE+nr$oLiifRtPu{U}AA;{+MxK@WLiLd?-?!p~2| z^Pi!K3rHzRJL`axcg`}8cNdK7l>X*zljT|ujq48D_7i+DM)eJzErFbjK(&R-tAyKX z!dWdS6S}W7adZb#{z92$@feVZQu7DOw$IFZhzKv4ZA8lMKOO;Vd!51gy~!KDLboPW zGAu?{Cq%N}pzP&d`EmNxXLW^wtj1a;@F_v&ojcE_H_%4y0|GoyK0{9?jcSq6Ita5m ze&Qq!IKc6xp1&LR;WbANqqEdQJPpBQaim8Eu#vq`Ar3o`C0?U+H6fY{xGRd80Abk zlv8{(Vx@eFr9#P}#F|qmY*8uXl;c9tkyue0g;5MsbW(E2DH5u$YUZ$h&%5pWef;*9 z$EwfgeY{`SeO=dmy>gn2_zo=^T*=2FGU76em+ATooMSz6IMJ&|(7wu#c-xhA2mrb) zlso$M4tyFtt&U%ar2-1$EQ}(RE*7;SYxyf9sls#~ch;JOhaV8=HGuJ*m<^%SIM)-N zn}7d(f}xR0eHy7qQ%SAhcI7?h*XQ`FEuw){or+KS-_3F&JEf;XP~1mq(wu_5oS?dQ zm>jmE%Z)0Hc=qH;8{SEcF(dxGyTo|}@0OyA9B9UvncqPUt1T|p**-o!My}-_n##kf zs)UkEz;gQeFxoWx;Ac;tF35mq{~SU`U!nE(%6Q$|Y7w1N`m&_3@Mc-C-t)sE#;$HmwDx^4gdqqV1!^m_O0Tk=e{ZF1cm1|R*-L2vo>z9_2{U+araj08&s;a9u3J8Ak zMD3SguC1-jqUuG70hg8Bnaju^xBrtsOV{<`6S^`uun7=aJ>t?G9vT_)gP}RxWl*=c zM5pM>3!fWxzR#lW<`|lE45d;yd7KW~qJi}L_@*fGK?A`gqVbh#vv5&bX*tV>0>VPzej zbUz0TJ-zW4q z6U!`gc1^LP`EXi=%TUdAI5=Gc7v9*vga}RjBKK8KYifG?$+!lHSVO_d-}@z%G?Qg^ z7QIY*7P==-SkL{vLc)_qxwtKyuT?SXb-iXm_=`KtVM$&Y1iLqmlq|w?EVJHYcG#97 zNU;?ma#)C%8!`oHt$2OccIi?}A@K2I$ipO@cwH73>Jvq*&6JOEH0TnETc=l={NB)5rJi|zZFBH~po+)mKKy6Wf*e@D;N(+f!x+`?Q&n3#v*%Ua z>Ow{lS+&K;M+ub-SYe+fI0nXLXU5P$gDwKjBbXc!Hk{*Fhcyo4i`eQv{mNROcO-Od zEC+{^8uBn#$Z%e(hr}1{v0Tsz6I}o^^^Dql5*ivRiOu)dy!V$Z4+aWbDYP`VuX@|6 z8nS57M3hN?3*Yx4_v9-*y^;+&R~8EM00mzXVXm*k+WM=*4l|3RH~>kOxBwW{!{09C zKZG!mv;qK;GF*8JR)1)!Sj>rb-qLmS7Nq}SHa21&OZO_jc(D}~dROXxJwrn+tgbW% zT5@Pibndk8A@j=O3Fq*$);5pgu7+SSy>RQ69<)bYQ&W|ZrApl&2DO{va>EP%tjKHva{%$bgM;19R3rOI&I|@kU^LQ{{^^QR^ zgokT)7*8R)Azmb*&deo;LX7suH?r^G!_@N3f+r8(hVHtyU(q4Pghv>v3MNaqoQ>Lr5`_nq~ zG&3tanO<8U%P+HV4LjTGIsJ95?+`}2=M3~X`Zb!swl&|9L_o3zxD=q8D_8D%ejVHOl5ZEtza1>@Kdp2%tOZO&M!zuon zhwX=e?DY{`Ch6cp;M&g>afCZgFr8J3QYs%D{J<(_0e=3L%eURaKpLE7G1|cUPQDpN zNQGGhwSZE#9yqWCTMdIkV$PO=honhbJA~uZ!;2dy4yAk*Pgf_GRXWzH%@oBTTlNT; ztmff~;`J4-2>9)G8tzd(W8_GW2j-(1dA1v3TIo4O^M}$0)r{br4kW{SJ{#R^OIk27 zi<>BO-2j*@+qZ{1tTXEHNr**G@Mn6}9`Pq!Ayc3)Qli}XyADj<8{ojcNZaruLrplR zo&1z#-gEvTSbD+C&zLbOV8d9`{pt6Zv4a428%QzgrLXhddAtx-`8Ns+(=U(zkv^Tc zev96J!_N2>_t$d@PHu1^acI}io>AdRdS?jSk+c%a@pJ#GV5OaO&3J5abw$v z7%iZcdI^S&w;sO5IawuWK5l$F;iZXZlcL_ab7#RC#H~$~?8sQ>ftA3#>(ooW4tpoP;qm+vJadaVib*A6Jhq3yRURM zv;q@CoeuU~{mP2@t=rzq9m9C#exq%6aBz6%@H9EW^=LgJuQ$GSA_7$z+DmPQ4>zS5 z{U_^Gv^C`Q;a{%{5BJrKZ11av7TmgXXX}63kL#I!2`@*0vLw8SYBq~CXB9E{ZbSr7 zuR~a`42@S2C=&uxq9a2=g;$pb^(W}|zq>Gh?vPe?$nGjOc9?AI z(`dD``H;8Jlmlee3$W~XV@%U<7jb82K9ewa%l;h}+`m%v05y zd@(9$*nzcwuXONmpvQJukoNH9OZToTbxSOm#AndO@Sj=At^Uo35g`yo?q`;^rLmDv zPkJx$GNvxa0sppY|6+vl2-ug0hoeSa1cWlV6v|Ca=6GXj5JHb^J|STM z)U!C#J%i_Mu}o?L50;_(Baa?(P8PzTa_!&G*5a_~eZ3LS5-$8Jz#NH1=2?p6*fD6N z=MNsTyZ=nPz`$XQv#fjc$cx#7N72(fw{2ebE2FoWi|&c76EE5<7+#!_`WUfVJ{#?G z9sV4p5;|pinwO^7GnES>9dQra)@HxyfHp7M6nf`F`ayaSGkqORR>``;N&RCf$&O9e zyG_IpN`TEKQZ91}Ghy*XNEK@mZB=RT4^r8o+{~5d*~w}PYFVG>)fx0E8e{O;)o*NC z5)iO$L#FNbGqwGPg(MfkgO$E~%tb|hbqK#1E1*gnJe;P&li3PS*PZMX;3=iZY^g))fk zg-14};m?vx{}~Toys%K(Fw2*Q%$w@Iw)x`k5j2rXu;>a6|p|bv9s~-nC^OpTx}B2HmkpfgXsWI>cFM zjKR03gX=#4H>Bx$T~qxvXK}6AT zXubbz{O(O>Bl1IOf+l};*Vva5x#8uCgZuWS(DiLAYTUQ||22Rg*SI*PK~N>tW=||I znvup3hY6gX3U#ElLj3hnmjTSItEj(1l?Q;v%~5;%-XhRTW6Uv+v#t?-5$zR8#5QB$ zYh$V+_Hxg#fH=j3rlnuTZGB^SUR=nLkniGu6cvEeVva&rQSrd%@=6@}NGH1<^YZ|h zKxS}viO+d#?38dCg$ZfUis3x0<=TIVAncsHo^na%)H;1f!UM5*AP7U|$7dy!DJB5m z_&9TtGd5wKQgpFE6|M^6TP&3M!C9N}b1N$3E!Fbnnfk;GoT8J`1&uy}b141mJxLsg z%S4ds^6Wp0m?ZIHM+BC>v@NgOT6M<|(eIbCLw8(Ly$<8?d6&Px;aIGpF#-!W&i9_> zgWvrYVLUDzT5H6sVW8yFn)n1Ga=Rp{Etq>Ui_y5LZw!pvtze)a4Nb}Ra4WBRy%bMJ35G(wqr-P znxn^H_B9kCXKALSCuF>dEq10Rih;KCdl$_sQC%fIiD{O&C1+`<*H8#PF!ShE;0J^a z-IS+gWxp?ZvDImsA5rf(TGpTqZmFR^{@C2#~#!jgOPP?tF-WLEVbb&;9-wd~BAJ@3k!>Pr~6Mz)A(YsGOge4s6)wgf-)2X|v-g4T} z`8SVD>7__7lnb4f#=rx1SYxXE6@;6XnJpw;S>JF#9_iQsM2o(EI(_Z!Gd~17PukVz zH|94Sg?JF%Rx(yan2>NoiOB-qojb5od_R)QzI5*E05Bp67&f%|abbS|4SbJZ^a?5J z>Fhn2GTG9<2G*H)uBz@KOF7@AC^j}W3hsop9d5?q)g=dsdA%)%`m-VUxVfz+;&YU4T9pPB_qQ%BA zng`idceUriN?QMm^loWP=B_G8j(v|MMclWLkbp69f3oU~oMQ*hvL(%2F3Fl_;- zY*`35kfVV?Gp{&+ehahlIODcwh;A$7F+oBs<$W>+!c8zJ`wQwE?R_^w;zcUEpFLbo zhIU65<xUkosX7$!7Sg);cXOr{<*?A6xdQW z?2_Y>7dHd2avWmEzq>sp@m%Ucr}Io3+)8xpsxd|uO|GkH?%`@*j=9gbf4!sPL}II* zSn~sxOuvz}R#PAN8Wysv%n7mXsqjU_XUrFmP7}q*X6f@ogHPa@6|kZ)!fi?&H}x~Z zb`mhE?M~RgCMY#RV!jnw0!4j(gzjMg)2GXyvVGbHlT8eQqAEjPfp@0dU-wOKA5yF-^rLJi1YML1wQ}u74KK>0m=*W+XiB%2ej2cB znF0Gx=rXF1E*mm@&gxodZHCILd1Fj2dSO!GsrlQDe_c4(zGYW$G=|^C4{BK1@sHSXg;^&_@y&KB~7Oj3OGLr?|_doa6Oh7x9 zUPXLbM{J*2G4G`vZLjI={n#R-AU{7eKHeu<>-6Ua2DYiLyH`JW5rI(yaSG?)HUGg& zpHC4P_`=~YbEE_xI%LvN`=Bel^5&*aW}NYV_0f2Z52UaNmi4Hb%U*j7rW}SWYmBzA zG6O8St^TGPt2*w8RoBAzwYu>|_LZkqRjzOEe5=+oU7ugj^J%_a{K_Rq60ZX(;~P!Z zH6On!aDnkAhlq;u@`-+vE$8wKy8M0Ugwu=-T1vUss%Z1GzswrXaFef(TSZTw`SahZ zPR?eMNU~zkvZtS46THJ>)HOGc-49=yq!!z9W&+M$Vz#QU7@@$1r5xkOK~Q zg*8b`bYPtndS@nngS{a-8?6XVf!?f(C23hVJ+*Nj8L}c`-XFFq=e5hxTY**xGs;az| z@+PXk^+c7bSU-Bk!sqXA>}^O)pLB#t=bE0|uEPmnB7$ z1}_@7J8?m_mX!x9khG`5EAyC)OLe_no`#TU8hL|ng#%i)e6j$rpS*`mNc_)b|L5M> zT2B6fADmO50ZJ?U+~L$p3-~==1FxLU`=M?hOkcRw;i-p3d{jMwoR1>=x1j&)X~|9K z>Ba9%>eCxs+||r?4#WqtS7<+oU3c4`mlkfS=w z1Dr~cZE-SlhjPqMmsJj3>^Rh;#{YXxq5J0etiYec!n6+rH+?7Ms7k%~(`)%3J18tX z0|pH$9A{m;b>~-dZH_o@PRr_5)3y0+m@s-~Dbuuk66dt;5*+fax@o()!^%mG$!HHg zEfi$p=KR6NRO(d|HW=+oe>_Cor@r%#uDLygau0MC&eSY!Rs6}a%DwGdox0*r-8lr= z{?1|JzO4zK?mMkWMiZh`rLJA-Y3Fk5#jS>=w>DK&2DVT6b~GDgz@Ih7*ya4=BbTFD zVec`Iuh|+}RcIcZdcyYGq9RxEvD6JxnVGG!fZ7F>ESP`Uzb>ScQ{%GQ`(NR?6?ztp ziXRRe^Rp$0yAB_70C%ZFe&-wvdb@lu21LmQ`f+Wyeqz8IANJ1f#BkSYlzVv zsR;=o`&n||)blWGOqo7Csn${`?N4L8p>UsHt+qbNEp4zY8g6W$r#EshD_&jWPM)*< zzX9a}(Dx9=g}j9!ra##*HumOl3!mGu%_?kzW=xU$#!)^4RA))Hdek*U<`cb-9U``tuZRePPQvZ-(9G!sab!0Zi)+tu(_j0mi<|? Ut11UJgjFVvcTgQ4JL{+a15k0moB#j- literal 0 HcmV?d00001 diff --git a/docs/source/images/ldes_delta_representation.svg b/docs/source/images/ldes_delta_representation.svg new file mode 100644 index 000000000..dfec1a541 --- /dev/null +++ b/docs/source/images/ldes_delta_representation.svg @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + No adjustment + Allowedpositiveseasonaldelta + + + + + + + Represents + + + + + Seasonal storage + + diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index d24171831..e4387ace8 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -351,7 +351,7 @@ def TotalCost_rule(M): Using the :code:`FlowOut` and :code:`Capacity` variables, the Temoa objective function calculates the cost of energy supply, under the assumption that capital costs are paid through loans. This implementation sums up all the costs incurred, - and is defined as :math:`C_{tot} = C_{loans} + C_{fixed} + C_{variable} + C_{emission}`. + and is defined as :math:`C_{tot} = C_{loans} + C_{fixed} + C_{variable} + C_{emissions}`. Each term on the right-hand side represents the cost incurred over the model time horizon and discounted to the initial year in the horizon (:math:`{P}_0`). The calculation of each term is given below. @@ -489,7 +489,7 @@ def annuity_to_pv(rate: float, periods: int) -> float | Expression: .. math:: :label: annuity_to_pv - \frac{P}{A}(i, N) = \frac{(1 + i)^N - 1}{i \cdot (1 + i)^N} + \frac{P}{A}(i, N) = \frac{(1 + i)^N - 1}{i (1 + i)^N} where: @@ -1003,7 +1003,7 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): that the supply exceeds the endogenous demand. Refineries represent a common example, where the share of different refined products are governed by TechOutputSplit, but total production is driven by a particular commodity - like gasoline. Such a situtation can result in the overproduction of other + like gasoline. Such a situation can result in the overproduction of other refined products, such as diesel or kerosene. In such cases, we need to track the excess production of these commodities. To do so, the technology producing the excess commodity should be added to the :code:`tech_flex` set. @@ -1464,6 +1464,10 @@ def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): + \sum\limits_{I,O} \mathbf{FIS}_{r,p,s,d,i,t,v,o} \cdot {EFF}_{r,i,t,v,o} - \sum\limits_{I,O} \mathbf{FO}_{r,p,s,d,i,t,v,o} = {SL}_{r,p,s_{{next}},d_{{next}},t,v} + + Note that for all seasonal representations except sequential days, the last time slice + of each season will loop back to the first time slice of the same season, preventing + seasonal deltas for non-seasonal storage (see SeasonalStorageEnergyUpperBound). """ # We allow a non-zero daily delta only in the case of seasonal storage @@ -1502,22 +1506,37 @@ def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_seq, t, v): over that entire day, adjusted for number of days represented by sequential vs non-sequential seasons. Only applies to storage technologies in the :code:`tech_seasonal_storage` set. :math:`s^*` represents the matching non-sequential season for the sequential season - :math:`s_{seq}`. + :math:`s^{seq}`. .. math:: :label: Storage Energy (Sequential Seasons) - \mathbf{SSL}_{r,p,s_{seq},t,v} - + DA_{r,p,s_{seq}} \cdot \left(\mathbf{SL}_{r,p,s^*,d_{first},t,v} + - \sum_{I,O} \mathbf{FI}_{r,p,s^*,d_{first},i,t,v,o} \cdot EFF_{r,p,i,t,v,o} - - \sum_{I,O} \mathbf{FO}_{r,p,s^*,d_{first},i,t,v,o} - \right) + \mathbf{SSL}_{r,p,s^{seq},t,v} + + DA_{r,p,s^{seq}} \cdot \left(\mathbf{SL}_{r,p,s^*,d_{first},t,v} + + \sum_{D,I,O} \mathbf{FI}_{r,p,s^*,d,i,t,v,o} \cdot EFF_{r,i,t,v,o} + - \sum_{D,I,O} \mathbf{FO}_{r,p,s^*,d,i,t,v,o} + \right) - = DA_{r,p,s_{seq,next}} \cdot \mathbf{SL}_{r,p,s^*_{next},d_{first},t,v} - + \mathbf{SSL}_{r,p,s_{seq}^{next},t,v} + = DA_{r,p,s^{seq}_{next}} \cdot \mathbf{SL}_{r,p,s_{next}^*,d_{first},t,v} + + \mathbf{SSL}_{r,p,s^{seq}_{next},t,v} - \\ - \text{where } DA_{r,p,s_{seq}} = \frac{\#days_{s_{seq}}}{SEG_{r,p,s^*} \cdot DPP} + \\ + \text{where } DA_{r,p,s^{seq}} = \frac{\#days_{s^{seq}}}{SEG_{r,p,s^*} \cdot DPP} + + .. figure:: images/ldes_chain.* + :align: center + :width: 100% + :figclass: align-center + :figwidth: 60% + + How sequential seasons chain together for seasonal storage. Hatched area is + SeasonalStorageLevel :math:`SSL_{r,p,s^{seq},t,v}`. Vertical lines are + StorageLevel :math:`SL_{r,p,s^*,d,t,v}`. Green line is net seasonal storage + level :math:`SSL_{r,p,s^{seq},t,v} + SL_{r,p,s^*,d,t,v}`. Background grey + lines show how storage levels from non-sequential seasons are combined + in sequential seasons. Dashed line is SeasonalStorageEnergyUpperBound. + Sequential seasons two and four here are each two days while one and three + are each one day. """ s = M.sequential_to_season[p, s_seq] @@ -1559,7 +1578,6 @@ def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_seq, t, v): def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): r""" - This constraint ensures that the amount of energy stored does not exceed the upper bound set by the energy capacity of the storage device, as calculated on the right-hand side. @@ -1584,6 +1602,17 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): \\ \forall \{r, p, s, d, t, v\} \in \Theta_{\text{StorageEnergyUpperBound}} + A season can represent many days. Within each season, flows are multiplied by the + number of days each season represents and, so, the upper bound needs to be adjusted + to allow day-scale flows (e.g., charge in the morning, discharge in the afternoon). + + .. figure:: images/daily_storage_representation.* + :align: center + :width: 100% + :figclass: center + :figwidth: 40% + + Representation of a 3-day season for non-seasonal (daily) storage. """ if M.isSeasonalStorage[t]: @@ -1605,29 +1634,53 @@ def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_seq, d, r""" Builds off of StorageEnergyUpperBound_Constraint. Enforces the max charge capacity of seasonal storage, summing the real storage level with the superimposed sequential - seasonal storage level. A season can represent many days. Within each season, flows - are multiplied by the number of days each season represents, and so the upper bound - needs to be adjusted to allow day-scale flows (e.g., charge in the morning, discharge - in the afternoon). However, between seasons, whole-day charge deltas have built up, - multiplied by the number of days the season represents. These deltas stack, - possibly exceeding our upper bound by a factor of :math:`\frac{N-1}{N}` where :math:`N` - is the number of days the season represents. Additionally, if we allowed these stacked - deltas to carry between seasons then we would be multiplying the effective energy - capacity of the storage. So, we do not adjust the bound for seasonal storage. This - limits the ability of seasonal storage to perform arbitrage within each season, but - allows it to carry energy between seasons. :math:`s^*` represents the matching - non-sequential season for the sequential season :math:`s_{seq}`. + seasonal storage level. :math:`s^*` represents the matching non-sequential season for + the sequential season :math:`s^{seq}`. .. math:: :label: Seasonal Storage Energy Capacity - \mathbf{SSL}_{r,p,s_{seq},t,v} - + \mathbf{SL}_{r,p,s^*,d,t,v} \cdot DA_{r,p,s_{seq}} + \mathbf{SSL}_{r,p,s^{seq},t,v} + + \mathbf{SL}_{r,p,s^*,d,t,v} \cdot DA_{r,p,s^{seq}} \leq \mathbf{CAP}_{r,p,t,v} \cdot C2A_{r,t} \cdot \frac{SD_{r,t}}{24 \cdot DPP} \\ - \text{where } DA_{r,p,s_{seq}} = \frac{\#days_{s_{seq}}}{SEG_{r,p,s^*} \cdot DPP} + \text{where } DA_{r,p,s^{seq}} = \frac{\#days_{s^{seq}}}{SEG_{r,p,s^*} \cdot DPP} + + + + Unlike non-seasonal (daily) storage, seasonal storage is allowed to carry energy + between seasons. However, through seasons representing multiple days, many days' + charge deltas have accumulated, multiplied by the number of days the season + represents. If we allowed these stacked deltas to carry between seasons then we would + be multiplying the effective energy capacity of the storage. We could just constrain + the seasonal delta to the unadjusted energy capacity, but then the final day in the + season would sit atop a season's worth of deltas, possibly exceeding our upper or + lower bound by a factor of :math:`\frac{N-1}{N}` where :math:`N` is the number of + days the sequential season represents. + + .. figure:: images/ldes_delta_problem.* + :align: center + :width: 100% + :figclass: center + :figwidth: 100% + + The energy upper bound or non-negative lower bound could be violated in a + season representing multiple days if we both adjusted the upper bound to + the number of days and allowed a seasonal delta. + + So, we do not adjust the upper energy bound for seasonal storage. This limits the + ability of seasonal storage to perform arbitrage within each season, but allows it to + carry energy between seasons realistically. + + .. figure:: images/ldes_delta_representation.* + :align: center + :width: 100% + :figclass: center + :figwidth: 40% + + Unadjusted energy upper bound constraint for seasonal storage. """ s = M.sequential_to_season[p, s_seq] @@ -1853,6 +1906,10 @@ def RampUpDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): R_{r,t} \cdot \Delta H_{r,p,s,d,s_{next},d_{next}} \cdot CAP_{r,p,t,v} \cdot C2A_{r,t} \\ \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampUpDay}} + \\ + \text{where: } \Delta H_{r,p,s,d,s_{next},d_{next}} = \frac{24}{2} + \left ( \frac{SEG_{r,p,s,d}}{\sum_{D} SEG_{r,p,s,d'}} + + \frac{SEG_{r,p,s_{next},d_{next}}}{\sum_{D} SEG_{r,p,s_{next},d'}} \right ) where: @@ -1970,9 +2027,9 @@ def RampDownDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): def RampUpSeason_Constraint(M: 'TemoaModel', r, p, s, s_next, t, v): r""" Constrains the ramp up rate of activity between time slices at the boundary - of sequential seasons. Same as RampDay but only applies to the boundary - between seasons, i.e., :math:`(s,d_{last})` to :math:`(s_{next},d_{first})` - and :math:`s_{next}` is based on the TimeSequential table rather than the + of sequential seasons. Same as RampUpDay but only applies to the boundary + between sequential seasons, i.e., :math:`(s^{seq},d_{last})` to :math:`(s^{seq}_{next},d_{first})` + and :math:`s^{seq}_{next}` is based on the TimeSequential table rather than the TimeSeason table. """ @@ -2019,9 +2076,9 @@ def RampUpSeason_Constraint(M: 'TemoaModel', r, p, s, s_next, t, v): def RampDownSeason_Constraint(M: 'TemoaModel', r, p, s, s_next, t, v): r""" Constrains the ramp down rate of activity between time slices at the boundary - of sequential seasons. Same as RampDay but only applies to the boundary - between seasons, i.e., :math:`(s,d_{last})` to :math:`(s_{next},d_{first})` - and :math:`s_{next}` is based on the TimeSequential table rather than the + of sequential seasons. Same as RampDownDay but only applies to the boundary + between sequential seasons, i.e., :math:`(s^{seq},d_{last})` to :math:`(s^{seq}_{next},d_{first})` + and :math:`s^{seq}_{next}` is based on the TimeSequential table rather than the TimeSeason table. """ From 74ca124eff97c3dd3570cfdbc736ca9502f783dc Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 26 Jun 2025 12:39:30 -0400 Subject: [PATCH 168/587] Start updating param and variable lists --- docs/source/Documentation.rst | 78 ++++++++++++++++++++++---- temoa/temoa_model/temoa_rules.py | 94 +++++++++++++++++++------------- 2 files changed, 123 insertions(+), 49 deletions(-) diff --git a/docs/source/Documentation.rst b/docs/source/Documentation.rst index 7dce8492a..f1d3ac238 100644 --- a/docs/source/Documentation.rst +++ b/docs/source/Documentation.rst @@ -725,11 +725,12 @@ Sets :widths: 8, 28, 14, 50 ":math:`{}^*\text{C}`",":code:`commodity_all`","string","union of all commodity sets" + ":math:`\text{C}^s`",":code:`commodity_source`","string","input sources (not balanced by CommodityBalance_Constraint)" ":math:`\text{C}^d`",":code:`commodity_demand`","string","end-use demand commodities" ":math:`\text{C}^e`",":code:`commodity_emissions`","string","emission commodities (e.g. :math:`\text{CO}_\text{2}` :math:`\text{NO}_\text{x}`)" ":math:`\text{C}^p`",":code:`commodity_physical`","string","general energy forms (e.g. electricity, coal, uranium, oil)" - ":math:`\text{C}^a`",":code:`commodity_annual`","string","same as commodity physical but flows are only balanced over each period" - ":math:`\text{C}^w`",":code:`commodity_waste`","string","physical or annual commodity for which production can be greater than consumption" + ":math:`\text{C}^a`",":code:`commodity_annual`","string","same as commodity physical but flows are only balanced over each period (:math:`\text{C}^a \subset \text{C}^p`)" + ":math:`\text{C}^w`",":code:`commodity_waste`","string","production can be greater than consumption. can be physical, annual, or neither (not balanced)" ":math:`{}^*\text{C}^c`",":code:`commodity_carrier`","string","physical energy carriers and end-use demands (:math:`\text{C}_p \cup \text{C}_d`)" ":math:`\text{I}`",,"string","alias of :math:`\text{C}^p`; used in documentation only to mean ""input""" ":math:`\text{O}`",,"string","alias of :math:`\text{C}^c`; used in documentation only to mean ""output""" @@ -946,16 +947,16 @@ Parameters ":math:`\text{CF}_{r,p,t,v}`","CostFixed",":math:`\mathbb{R}`","Fixed operations \& maintenance cost" ":math:`\text{CI}_{r,t,v}`","CostInvest",":math:`\mathbb{R}`","Tech-specific investment cost" ":math:`\text{CV}_{r,p,t,v}`","CostVariable",":math:`\mathbb{R}`","Variable operations \& maintenance cost" + ":math:`\text{CON}_{r,i,t,v}`","ConstructionInput",":math:`\mathbb{R}`","Commodities consumed by creation of process capacity" ":math:`\text{DEM}_{r,p,c}`","Demand",":math:`\mathbb{R}^+_0`","End-use demands, by period" ":math:`\text{DDD}_{p,s,d}`","DemandDefaultDistribution",":math:`\mathbb{I}`","Default demand distribution (currently not supported)" ":math:`\text{DSD}_{r,p,s,d,c}`","DemandSpecificDistribution",":math:`\mathbb{I}`","Demand-specific distribution" ":math:`\text{EFF}_{r,i,t,v,o}`","Efficiency",":math:`\mathbb{R}^+_0`","Tech- and commodity-specific efficiency" ":math:`\text{EAC}_{r,i,t,v,o,e}`","EmissionActivity",":math:`\mathbb{R}`","Tech-specific emissions rate" ":math:`\text{EE}_{r,t,v,e}`","EmissionEmbodied",":math:`\mathbb{R}`","Emissions associated with the creation of capacity" - ":math:`\text{EE}_{r,t,v,e}`","EmissionEndOfLife",":math:`\mathbb{R}`","Emissions associated with the retirement/end of life of capacity" + ":math:`\text{EEOL}_{r,t,v,e}`","EmissionEndOfLife",":math:`\mathbb{R}`","Emissions associated with the retirement/end of life of capacity" + ":math:`\text{EOLO}_{r,t,v,o}`","EndOfLifeOutput",":math:`\mathbb{R}`","Commodities produced by retirement/end of life of capacity" ":math:`\text{ECAP}_{r,t,v}`","ExistingCapacity",":math:`\mathbb{R}^+_0`","Pre-existing capacity" - ":math:`\text{RCAP}_{r,p,t,v}`","RetiredCapacity",":math:`\mathbb{R}^+_0`","Capacity retired before end of life" - ":math:`\text{ART}_{r,p,t,v}`","AnnualRetirement",":math:`\mathbb{R}^+_0`","Annualised capacity retiring or reaching end of life" ":math:`\text{GDR}`","GlobalDiscountRate",":math:`\mathbb{R}`","Global rate used to calculate present cost" ":math:`\text{LTP}_{r,t,v}`","LifetimeProcess",":math:`\mathbb{N}`","Tech- and vintage-specific lifetime (default=LifetimeTech)" ":math:`\text{LTT}_{r,t}`","LifetimeTech",":math:`\mathbb{N}`","Tech-specific lifetime (default=40 years)" @@ -1106,6 +1107,17 @@ of activity. Thus the incurred variable costs are proportional to the activity of the process. +ConstructionInput +^^^^^^^^^^^^^^^^^ + +:math:`{CON}_{r \in R, i \in C^p,t \in T \setminus T^u,v \in V}` + +The :code:`ConstructionInput` parameter allows the modeller to attach commodity +input flows to the production of new capacity, in units of activity per unit +capacity. Assumes that capacity is produced evenly over years in its vintage +period. + + .. _Demand: Demand @@ -1185,14 +1197,44 @@ to account for emissions per unit activity, but it more accurately describes :math:`e \in C^e` set restriction). -EmissionLimit -^^^^^^^^^^^^^ +EmissionEmbodied +^^^^^^^^^^^^^^^^ + +:math:`{EE}_{r \in R,t \in T \setminus T^u, v \in V,e \in C_e}` + +Like the EmissionActivity parameter, but attaches emission outputs to the creation +of capacity instead of activity flows. Assumes that capacity is produced evenly +over each year in the deployment vintage. + + +EmissionEndOfLife +^^^^^^^^^^^^^^^^^ + +:math:`{EEOL}_{r \in R,t \in T \setminus T^u, v \in V,e \in C_e}` + +Like EmissionEmbodied, but attaches emissions to the retirement/end of life of +capacity rather than production of capacity. Assumes that retirement or end of +life occur evenly over years in that period. + + +EndOfLifeOutput +^^^^^^^^^^^^^^^ + +:math:`{EOLO}_{r \in R,t \in T \setminus T^u, v \in V,o \in C_p}` + +Like ConstructionInput, but attaches flows to the retirement/end of life of +capacity rather than production of capacity. Assumes that retirement or end of +life occur evenly over years in that period. -:math:`{ELM}_{r \in R, p \in P, e \in C^e}` -The :code:`EmissionLimit` parameter ensures that Temoa finds a solution that -fits within the modeler-specified limit of emission :math:`e` in time period -:math:`p`. +.. LimitEmission +.. ^^^^^^^^^^^^^ + +.. :math:`{LE}_{r \in R, p \in P, e \in C^e}` + +.. The :code:`EmissionLimit` parameter ensures that Temoa finds a solution that +.. fits within the modeler-specified limit of emission :math:`e` in time period +.. :math:`p`. ExistingCapacity @@ -1205,6 +1247,16 @@ beginning of :code:`time_optimize`. Note that processes with existing capacity require all of the engineering-economic characteristics of a standard process, with the exception of an investment cost. +RetiredCapacity +^^^^^^^^^^^^^^^^ + +:math:`{ECAP}_{r \in R, t \in T, v \in \text{P}^e}` + +The :code:`ExistingCapacity` parameter defines the capacity installed prior to the +beginning of :code:`time_optimize`. Note that processes with existing capacity +require all of the engineering-economic characteristics of a standard process, +with the exception of an investment cost. + .. _GDR: GlobalDiscountRate @@ -1692,6 +1744,10 @@ Variables ":math:`CAPAVL_{r,p,t}`","V_CapacityAvailable ByPeriodAndTech",":math:`\mathbb{R}^+_0`","Derived variable representing the capacity of technology :math:`t` available in period :math:`p`" ":math:`SI_{r,t,v}`","V_StorageInit",":math:`\mathbb{R}^+_0`","Initial charge level associated with storage techs" ":math:`SL_{r,p,s,d,t,v}`","V_StorageLevel",":math:`\mathbb{R}^+_0`","Charge level each time slice associated with storage techs" + ":math:`SSL_{r,p,s,t,v}`","V_SeasonalStorageLevel",":math:`\mathbb{R}^+_0`","Base charge level of sequential seasons for seasonal storage" + ":math:`RCAP_{r,p,t,v}`","V_RetiredCapacity",":math:`\mathbb{R}^+_0`","Capacity retired before end of life" + ":math:`ART_{r,p,t,v}`","V_AnnualRetirement",":math:`\mathbb{R}^+_0`","Annualised capacity retiring or reaching end of life" + ":math:`NCAP_{r,t,v}`","V_NewCapacity",":math:`\mathbb{R}^+_0`","New deployed capacity" V_FlowOut ^^^^^^^^^ diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index e4387ace8..42ab8ec96 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -361,17 +361,17 @@ def TotalCost_rule(M): \begin{aligned} C_{loans} =& \sum_{r, t, v \in \Theta_{CI}} CI_{r, t, v} \cdot \textbf{NCAP}_{r, t, v} - && \text{overnight capital cost} \\ + && \text{(overnight capital cost)} \\ &\cdot \frac{A}{P}(i=\text{LR}_{r,t,v}, N=\text{LLP}_{r,t,v}) - && \text{overnight cost amortised into annual loan payments} \\ + && \text{(overnight cost amortised into annual loan payments)} \\ &\cdot \frac{P}{A}(i=GDR, N=\text{LLP}_{r,t,v}) - && \text{annual loan payments discounted to NPV in vintage year} \\ + && \text{(annual loan payments discounted to NPV in vintage year)} \\ &\cdot \frac{A}{P}(i=GDR, N=\text{LTP}_{r,t,v}) - && \text{NPV reamortised over lifetime of process using GDR} \\ + && \text{(NPV reamortised over lifetime of process using GDR)} \\ &\cdot \frac{P}{A}(i=GDR, N=\min(\text{LTP}_{r,t,v}, P_e - v)) - && \text{costs within planning horizon discounted to NPV in vintage year} \\ + && \text{(costs within planning horizon discounted to NPV in vintage year)} \\ &\cdot \frac{P}{F}(i=GDR, N=v - P_0) - && \text{NPV in vintage year discounted to base year } P_0 \\ + && \text{(NPV in vintage year discounted to base year } P_0\text{)} \\ \end{aligned} Note that capital costs (:math:`{CI}_{r,t,v}`) are handled in several steps. @@ -402,19 +402,19 @@ def TotalCost_rule(M): \begin{aligned} C_{loans,LSC} =& \sum_{r, t, v \in \Theta_{CI}} CI_{r, t, v} \cdot \textbf{NCAP}_{r, t, v} - && \text{overnight capital cost} \\ + && \text{(overnight capital cost)} \\ &\cdot \frac{A}{P}(i=\text{LR}_{r,t,v}, N=\text{LLP}_{r,t,v}) - && \text{overnight cost amortised into annual loan payments} \\ + && \text{(overnight cost amortised into annual loan payments)} \\ &\cdot \frac{P}{A}(i=GDR, N=\text{LLP}_{r,t,v}) - && \text{annual loan payments discounted to NPV in vintage year} \\ + && \text{(annual loan payments discounted to NPV in vintage year)} \\ &\cdot \left( \sum_{v < Y} LSC_{r,y,t,v} \cdot \frac{P}{F}(i=GDR, N=P - v + 1) \right)^{-1} - && \text{reamortised over survival curve (normalized)} \\ + && \text{(reamortised over survival curve (normalized)} \\ &\cdot \sum_{v < Y < P_e} LSC_{r,y,t,v} \cdot \frac{P}{F}(i=GDR, N=P - v + 1) - && \text{costs within planning horizon discounted to NPV in vintage year} \\ + && \text{(costs within planning horizon discounted to NPV in vintage year)} \\ &\cdot \frac{P}{F}(i=GDR, N=v - P_0) - && \text{NPV in vintage year discounted to base year } P_0 + && \text{(NPV in vintage year discounted to base year } P_0 \text{)} \end{aligned} Where :math:`Y` is the set of each integer year :math:`y` within the planning horizon. @@ -434,35 +434,35 @@ def TotalCost_rule(M): \begin{aligned} C_{fixed} =& \sum_{r, p, t, v \in \Theta_{CF}} CF_{r, p, t, v} \cdot \textbf{CAP}_{r, p, t, v} - && \text{annual fixed cost} \\ + && \text{(annual fixed cost)} \\ \\ C_{variable} =& \sum_{r, p, t \notin T^a, v \in \Theta_{CV}} CV_{r, p, t, v} \cdot \sum_{S, D, I, O} \mathbf{FO}_{r, p, s, d, i, t, v, o} - && \text{annual variable cost on flow} \\ + && \text{(annual variable cost on flow)} \\ & \text{where } t \notin T^a \\ &+\\ & \sum_{r, p, t \in T^a,\ v \in \Theta_{VC}} CV_{r, p, t, v} \cdot \sum_{I, O} \mathbf{FOA}_{r, p, i, t, v, o} - && \text{annual variable cost on annual flows} \\ + && \text{(annual variable cost on annual flows)} \\ & \text{where } t \in T^a \\ &+\\ C_{emissions} =& \sum_{r, p, e \in \Theta_{CE}} CE_{r, p, e} \cdot EAC_{r, i, t, v, o, e} \cdot \sum_{S, D, I, O} \mathbf{FO}_{r, p, s, d, i, t, v, o} - && \text{annual emission cost on flow} \\ + && \text{(annual emission cost on flow)} \\ & \text{where } t \notin T^a \\ &+\\ & \sum_{r, p, e \in \Theta_{CE}} CE_{r, p, e} \cdot EAC_{r, i, t, v, o, e} \cdot \sum_{I, O} \mathbf{FOA}_{r, p, i, t, v, o} - && \text{annual emission cost on annual flows} \\ + && \text{(annual emission cost on annual flows)} \\ & \text{where } t \in T^a \\ &+\\ & \sum_{r, p, e \in \Theta_{CE}} \frac{CE_{r, p, e} \cdot EE_{r, e, t, v} \cdot \mathbf{NCAP}_{r, t, v=p}}{{LEN}_p} - && \text{annual embodied emission cost} \\ + && \text{(annual embodied emission cost)} \\ &+\\ & \sum_{r, p, e \in \Theta_{CE}, v} CE_{r, p, e} \cdot EEOL_{r, e, t, v} \cdot \mathbf{ART}_{r, p, t, v} - && \text{annual retirement/end of life emission cost} \\ + && \text{(annual retirement/end of life emission cost)} \\ \end{aligned} Each of these costs are then discounted within each period then to the base year: @@ -473,9 +473,9 @@ def TotalCost_rule(M): \begin{aligned} C_{fix,var,emiss} =& C_{fixed} + C_{variable} + C_{emissions} \\ &\cdot \frac{P}{A}(i=GDR,\ N=LEN_p) - && \text{for each year in period } p \text{ discounted to NPV in } p \\ + && \text{(for each year in period } p \text{ discounted to NPV in } p \text{)}\\ &\cdot \frac{P}{F}(i=GDR,\ N=p - P_0) - && \text{discounted from period } p \text{ to NPV in base year } P_0 + && \text{(discounted from period } p \text{ to NPV in base year } P_0 \text{)} \end{aligned} """ @@ -1014,7 +1014,10 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): the latter is technology- rather than commodity-focused and is used in the :code:`Capacity_Constraint` to track output that is used to produce useful output and the amount curtailed, and to ensure that the installed capacity - covers both. + covers both. Alternatively, the commodity can be added to the + :code:`commodity_waste` set, for which this equality constraint becomes an + inequality constraint, allowing production to exceed consumption for a single + commodity. This constraint also accounts for imports and exports between regions when solving multi-regional systems. The import (:math:`\textbf{FIM}`) and export @@ -1023,30 +1026,45 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): respectively, which are defined in :code:`temoa_initialize.py` by parsing the :code:`tech_exchange` processes. + Consumption of the commodity by construction inputs is annualised using the period + length. Production of the commodity by end-of-life outputs uses the AnnualRetirement + variable, which is already annualised. + Finally, for annual commodities, AnnualCommodityBalance is used which balances the sum of flows over each year. - *production + imports = consumption + exports + flex waste* + *process outputs + imports + end of life outputs = process inputs + construction inputs + exports + flex waste* .. math:: :label: CommodityBalance - \sum_{I, T, V} \textbf{FO}_{r, p, s, d, i, t, v, c} - + - &\sum_{reg} \textbf{FIM}_{r-reg, p, s, d, i, t, v, c} \; \forall reg \neq r - \\ - = &\sum_{T^{s}, V, I} \textbf{FIS}_{r, p, s, d, c, t, v, o} - \\ &\quad + - \sum_{T-T^{s}, V, O} \textbf{FO}_{r, p, s, d, c, t, v, o} /EFF_{r, c,t,v,o} - \\ - &\quad + \; SEG_{s,d} \cdot - \sum_{I, T^{a}, V} \textbf{FOA}_{r, p, c, t \in T^{a}, v, o} /EFF_{r, c,t,v,o} \\ - &\quad + \sum_{reg} \textbf{FEX}_{r-reg, p, s, d, c, t, v, o} \; \forall reg \neq r - \\ &\quad + \; - \textbf{FLX}_{r, p, s, d, i, t, v, c} + \begin{aligned} + &\sum_{I, t \notin T^a, V} \mathbf{FO}_{r, p, s, d, i, t, v, c} + && \text{(processes outputting commodity)} \\ + &+ SEG_{s,d} \cdot \sum_{I, t \in T^a, V} \frac{\mathbf{FOA}_{r, p, i, t, v, c}}{EFF_{r, i, t, v, c}} + && \text{(annual processes outputting commodity)} \\ + &+ \sum_{\text{reg} \neq r, I, t \in T^x, V} \mathbf{FIM}_{r - \text{reg}, p, s, d, i, t, v, c} + && \text{(inter-regional imports of commodity)} \\ + &+ SEG_{s,d} \sum_{T, V} \left ( EOLO_{r, t, v, c} \cdot \textbf{ART}_{r, p, t, v} \right ) + && \text{(end-of-life outputs of commodity)} \\ + &\begin{cases} + &= \text{if } c \notin C^w \\ + &>= \text{if } c \in C^w \end{cases} \\ + &\sum_{t \in T^s, V, O} \mathbf{FIS}_{r, p, s, d, c, t, v, o} + && \text{(commodity stored)} \\ + &+ \sum_{t \notin T^s, V, O} \frac{\mathbf{FO}_{r, p, s, d, c, t, v, o}}{EFF_{r, c, t, v, o}} + && \text{(commodity consumed by processes)} \\ + &+ SEG_{s,d} \cdot \sum_{t \in T^a, V, O} \frac{\mathbf{FOA}_{r, p, c, t, v, o}}{EFF_{r, c, t, v, o}} + && \text{(commodity consumed by annual processes)} \\ + &+ \sum_{\text{reg} \neq r, t \in T^x, V, O} \mathbf{FEX}_{r - \text{reg}, p, s, d, c, t, v, o} + && \text{(inter-regional exports of commodity)} \\ + &+ \sum_{I, t \in T^f, V} \mathbf{FLX}_{r, p, s, d, i, t, v, c} + && \text{(flex wastes of commodity)} \\ + &+ SEG_{s,d} \cdot \sum_{T, V} \left ( CON_{r, c, t, v} \cdot \frac{\textbf{NCAP}_{r, t, v}}{LEN_p} \right ) + && \text{(consumed annually by construction inputs)} + \end{aligned} - \\ - &\forall \{r, p, s, d, c\} \in \Theta_{\text{CommodityBalance}} + \qquad \forall \{r, p, s, d, c\} \in \Theta_{\text{CommodityBalance}} """ if c in M.commodity_demand: # Is this necessary? Demand comms have no downstream process no shouldnt be in indices From 11134d68f6928618e992141c5e414388078babc7 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 26 Jun 2025 17:24:41 -0400 Subject: [PATCH 169/587] Average survival curves over each period --- temoa/temoa_model/temoa_initialize.py | 49 +++++++++++++++------------ temoa/temoa_model/temoa_model.py | 12 ++++++- temoa/temoa_model/temoa_rules.py | 20 +++++++++-- tests/legacy_test_values.py | 3 +- 4 files changed, 57 insertions(+), 27 deletions(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 30753135d..8a570cbfd 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1257,20 +1257,12 @@ def CreateSurvivalCurve(M: 'TemoaModel'): logger.error(msg) raise ValueError(msg) - # Let them know about the linear interpolation + # Collect a list of processes that needed to be interpolated, for warning if periods_rtv != list(range(p_first, p_last+1, 1)): rtv_interpolated.add((r, t, v)) between_periods = [] for i, p in enumerate(periods_rtv): - - if p < v: - msg = ( - 'LifetimeSurvivalCurve defined for a period that comes before its vintage. ' - f'This is not allowed: ({r, p, t, v})' - ) - logger.error(msg) - raise ValueError(msg) if i == 0: continue # Cant look back from first period. Could be zero but hey why not @@ -1315,24 +1307,23 @@ def CreateSurvivalCurve(M: 'TemoaModel'): elif value(M.LifetimeProcess[r, t, v]) != p - v: msg = ( f'The LifetimeProcess parameter for process ({r, t, v}) with survival curve ' - f'does match the end of that survival curve in {p}. To agree with ' - f'the survival curve and suppress some warnings, set ' + f'does match the end of that survival curve in {p}. This will waste compute. ' + 'To agree with the survival curve and suppress this warning, set ' f'LifetimeProcess[{r, t, v}] = {p-v}' ) - logger.info(msg) + logger.warning(msg) continue - # Check that the last period is zero. This is important for investment costs - if p == p_last: - if lsc > 0.0001: - msg = ( - 'Any defined survival curve must continue to zero for the purposes of ' - 'investment cost accounting, even if this period would extend beyond ' - f'defined future periods. Continue ({r, t, v}) to fraction == 0.' - ) - logger.error(msg) - raise ValueError(msg) + # Flag if the last period is not fraction = 0. This is important for investment costs + if p == p_last and lsc > 0.0001: + msg = ( + 'Any defined survival curve must continue to zero for the purposes of ' + 'investment cost accounting, even if this period would extend beyond ' + f'defined future periods. Continue ({r, t, v}) to fraction == 0.' + ) + logger.error(msg) + raise ValueError(msg) M.survivalCurvePeriods[r, t, v].extend(between_periods) M.survivalCurvePeriods[r, t, v] = set(M.survivalCurvePeriods[r, t, v]) @@ -1427,6 +1418,20 @@ def EmissionActivityIndices(M: 'TemoaModel'): # return indices +def PeriodSurvivalCurveIndices(M: 'TemoaModel'): + """ + (region, period, tech, vintage) tuples where a process with a survival curve is + active with non-zero surviving capacity + """ + indices = set( + (r, p, t, v) + for r, t, v in M.survivalCurvePeriods + for p in M.survivalCurvePeriods[r, t, v] + ) + + return indices + + def ModelProcessLifeIndices(M: 'TemoaModel'): """\ Returns the set of sensical (region, period, tech, vintage) tuples. The tuple indicates diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 315b4b755..84e624991 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -335,7 +335,15 @@ def __init__(M, *args, **kwargs): M.LifetimeProcess_rtv = Set(dimen=3, initialize=LifetimeProcessIndices) M.LifetimeProcess = Param(M.LifetimeProcess_rtv, default=get_default_process_lifetime) - M.LifetimeSurvivalCurve = Param(M.regionalIndices, Integers, M.tech_all, M.vintage_all, default=1, validate=validate_0to1, mutable=True) + M.LifetimeSurvivalCurve = Param( + M.regionalIndices, + Integers, + M.tech_all, + M.vintage_all, + default=1, + validate=validate_0to1, + mutable=True + ) M.Create_SurvivalCurve = BuildAction(rule=CreateSurvivalCurve) M.LoanLifetimeProcess_rtv = Set(dimen=3, initialize=LifetimeLoanProcessIndices) @@ -421,6 +429,8 @@ def __init__(M, *args, **kwargs): M.ProcessLifeFrac_rptv = Set(dimen=4, initialize=ModelProcessLifeIndices) M.ProcessLifeFrac = Param(M.ProcessLifeFrac_rptv, initialize=ParamProcessLifeFraction_rule) + M.PeriodSurvivalCurve = Param(M.CostFixed_rptv, initialize=PeriodSurvivalCurve_rule) + M.LimitCapacityConstraint_rpt = Set( within=M.regionalGlobalIndices * M.time_optimize * M.tech_or_group * M.operator ) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 42ab8ec96..d2ba21c9f 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -75,7 +75,7 @@ def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): """ PLF = value(M.ProcessLifeFrac[r, p, t, v]) - LSC = value(M.LifetimeSurvivalCurve[r, p, t, v]) + LSC = value(M.PeriodSurvivalCurve[r, p, t, v]) if t not in M.tech_retirement: if v in M.time_exist: @@ -295,7 +295,7 @@ def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): :label: Annual Retirement ART_{r,p,t,v} = - \frac{1}{PL_{p}} \cdot + \frac{1}{LEN_{p}} \cdot \begin{cases} \textbf{ECAP}_{r,t,v} \cdot LSC_{r,p,t,v}^{\text{final}}, & \text{if } p = P_0,\ v \in T^{\text{exist}}, \text{ and EOL} \\ \textbf{NCAP}_{r,t,v}, & \text{if } p = v, \text{ and EOL} \\ @@ -1049,7 +1049,7 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): && \text{(end-of-life outputs of commodity)} \\ &\begin{cases} &= \text{if } c \notin C^w \\ - &>= \text{if } c \in C^w \end{cases} \\ + &\geq \text{if } c \in C^w \end{cases} \\ &\sum_{t \in T^s, V, O} \mathbf{FIS}_{r, p, s, d, c, t, v, o} && \text{(commodity stored)} \\ &+ \sum_{t \notin T^s, V, O} \frac{\mathbf{FO}_{r, p, s, d, c, t, v, o}}{EFF_{r, c, t, v, o}} @@ -3516,6 +3516,11 @@ def ParamProcessLifeFraction_rule(M: 'TemoaModel', r, p, t, v): calculate the fraction of the period that the technology is able to create useful output. """ + if M.isSurvivalCurveProcess[r, t, v]: + # survival curves handle this problem separately, by averaging survival + # over the period + return 1 + eol_year = v + value(M.LifetimeProcess[r, t, v]) frac = eol_year - p period_length = value(M.PeriodLength[p]) @@ -3529,6 +3534,15 @@ def ParamProcessLifeFraction_rule(M: 'TemoaModel', r, p, t, v): return frac +def PeriodSurvivalCurve_rule(M: 'TemoaModel', r, p, t, v): + """Get the average fraction of the survival curve in period p""" + if not M.isSurvivalCurveProcess[r, t, v]: + return 1 + LSC = M.LifetimeSurvivalCurve + PL = value(M.PeriodLength[p]) + return sum(value(LSC[r, _p, t, v]) for _p in range(p, p + PL, 1)) / PL + + # devnote: made redundant by time-value equations for objective function # def loan_annualization_rate(loan_rate: float | None, loan_life: int | float) -> float: # """ diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index 185a329cb..1c107805d 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -89,7 +89,8 @@ class ExpectedVals(Enum): 'survival_curve': { # added 2025/06/19 after addition of survival curves # reduced after changing fixed costs from MLP to PL - ExpectedVals.OBJ_VALUE: 31.8004, + # increased after adding PeriodSurvivalCurve + ExpectedVals.OBJ_VALUE: 31.9452, ExpectedVals.EFF_DOMAIN_SIZE: 64, ExpectedVals.EFF_INDEX_SIZE: 8, ExpectedVals.CONSTR_COUNT: 101, From 592c3b55a7b76cc3015c3a9e94733f1bea1e8e96 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 26 Jun 2025 18:28:17 -0400 Subject: [PATCH 170/587] Rework AdjustedCapacity and AnnualRetirement to better handle survival curves --- temoa/temoa_model/temoa_rules.py | 148 +++++++++++++++---------------- 1 file changed, 71 insertions(+), 77 deletions(-) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index d2ba21c9f..6a611c151 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -44,6 +44,30 @@ # --------------------------------------------------------------- +def get_capacity(M: 'TemoaModel', r, p, t, v, sc_frac, pl_frac): + """ + Utility function to get the remaining capacity at the beginning of a period + or during a period, based on the survival curve and process life fractions supplied. + Used in the AdjustedCapacity_Constraint and AnnualRetirement_Constraint + """ + + if t not in M.tech_retirement: + if v in M.time_exist: + return value(M.ExistingCapacity[r, t, v]) * sc_frac * pl_frac + else: + return M.V_NewCapacity[r, t, v] * sc_frac * pl_frac + else: + previous_retirements = sum( + M.V_RetiredCapacity[r, S_p, t, v] + for S_p in M.time_optimize + if v < S_p < p and S_p < v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[S_p]) + ) + if v in M.time_exist: + return (value(M.ExistingCapacity[r, t, v]) * sc_frac - previous_retirements) * pl_frac + else: + return (M.V_NewCapacity[r, t, v] * sc_frac - previous_retirements) * pl_frac + + def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): r""" This constraint updates the capacity of a process by taking into account retirements @@ -73,26 +97,57 @@ def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): & \text{if } t \in T^\text{ret},\ v \notin T^\text{e} \end{cases} """ + + sc_frac = value(M.PeriodSurvivalCurve[r, p, t, v]) + pl_frac = value(M.ProcessLifeFrac[r, p, t, v]) + return M.V_Capacity[r, p, t, v] == get_capacity(M, r, p, t, v, sc_frac, pl_frac) + - PLF = value(M.ProcessLifeFrac[r, p, t, v]) - LSC = value(M.PeriodSurvivalCurve[r, p, t, v]) +def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): + r""" + Get the annualised retirement rate for a process in a given period. + Used to output retirement (including end of life, EOL) and model end of + life flows and emissions. Assumes that retirement is evenly distributed over + the model period in which that retirement occurs, in the same way we assume + capacity is deployed evenly over the model period. Note that + :math:`\textbf{CAP}_{r,p,t,v}` already accounts for retirement, survival + curves, and process life fraction via the AdjustedCapacity constraint. - if t not in M.tech_retirement: - if v in M.time_exist: - return M.V_Capacity[r, p, t, v] == value(M.ExistingCapacity[r, t, v]) * LSC * PLF - else: - return M.V_Capacity[r, p, t, v] == M.V_NewCapacity[r, t, v] * LSC * PLF + .. math:: + :label: Annual Retirement + ART_{r,p,t,v} = + \frac{1}{LEN_{p}} \cdot + \begin{cases} + \textbf{ECAP}_{r,t,v} \cdot LSC_{r,p,t,v}^{\text{final}}, & \text{if } p = P_0,\ v \in T^{\text{exist}}, \text{ and EOL} \\ + \textbf{NCAP}_{r,t,v}, & \text{if } p = v, \text{ and EOL} \\ + \textbf{CAP}_{r,p{-}1,t,v}, & \text{if } v < p < v + LT_{r,t,v}, \text{ and EOL} \\ + \textbf{ECAP}_{r,t,v} \cdot LSC_{r,p,t,v}^{\text{final}} - \textbf{CAP}_{r,p,t,v}, & \text{if } p = P_0,\ v \in T^{\text{exist}} \text{, and not EOL} \\ + \textbf{NCAP}_{r,t,v} - \textbf{CAP}_{r,p,t,v}, & \text{if } p = v \text{, and not EOL} \\ + \textbf{CAP}_{r,p{-}1,t,v} - \textbf{CAP}_{r,p,t,v}, & \text{if not EOL otherwise} + \end{cases} + """ + + # First, get the remaining capacity at the beginning of this period + sc_frac_begin = value(M.LifetimeSurvivalCurve[r, p, t, v]) + capacity_begin = get_capacity(M, r, p, t, v, sc_frac_begin, 1) + + if p <= v + value(M.LifetimeProcess[r, t, v]) < p + value(M.PeriodLength[p]): + # If this is the end-of-life period, just return the beginning capacity. It all retires + retired = capacity_begin else: - retired_cap = sum( - M.V_RetiredCapacity[r, S_p, t, v] - for S_p in M.time_optimize - if v < S_p <= p and S_p < v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[S_p]) - ) - if v in M.time_exist: - return M.V_Capacity[r, p, t, v] == (value(M.ExistingCapacity[r, t, v]) * LSC - retired_cap) * PLF - else: - return M.V_Capacity[r, p, t, v] == (M.V_NewCapacity[r, t, v] * LSC - retired_cap) * PLF + # If not EOL period, need capacity at the end of this period too + # (i.e., at the beginning of the next period) + p_next = M.time_future.next(p) + sc_frac_end = value(M.LifetimeSurvivalCurve[r, p_next, t, v]) + capacity_end = get_capacity(M, r, p_next, t, v, sc_frac_end, 1) + + retired = capacity_begin - capacity_end + + # Distribute retirement evenly over planning period + retired /= value(M.PeriodLength[p]) + + return M.V_AnnualRetirement[r, p, t, v] == retired def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): @@ -281,67 +336,6 @@ def CapacityAvailableByPeriodAndTech_Constraint(M: 'TemoaModel', r, p, t): # return expr -def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): - r""" - Get the annualised retirement rate for a process in a given period. - Used to output retirement (including end of life, EOL) and model end of - life flows and emissions. Assumes that retirement is evenly distributed over - the model period in which that retirement occurs, in the same way we assume - capacity is deployed evenly over the model period. Note that - :math:`\textbf{CAP}_{r,p,t,v}` already accounts for retirement, survival - curves, and process life fraction via the AdjustedCapacity constraint. - - .. math:: - :label: Annual Retirement - - ART_{r,p,t,v} = - \frac{1}{LEN_{p}} \cdot - \begin{cases} - \textbf{ECAP}_{r,t,v} \cdot LSC_{r,p,t,v}^{\text{final}}, & \text{if } p = P_0,\ v \in T^{\text{exist}}, \text{ and EOL} \\ - \textbf{NCAP}_{r,t,v}, & \text{if } p = v, \text{ and EOL} \\ - \textbf{CAP}_{r,p{-}1,t,v}, & \text{if } v < p < v + LT_{r,t,v}, \text{ and EOL} \\ - \textbf{ECAP}_{r,t,v} \cdot LSC_{r,p,t,v}^{\text{final}} - \textbf{CAP}_{r,p,t,v}, & \text{if } p = P_0,\ v \in T^{\text{exist}} \text{, and not EOL} \\ - \textbf{NCAP}_{r,t,v} - \textbf{CAP}_{r,p,t,v}, & \text{if } p = v \text{, and not EOL} \\ - \textbf{CAP}_{r,p{-}1,t,v} - \textbf{CAP}_{r,p,t,v}, & \text{if not EOL otherwise} - \end{cases} - """ - - if p <= v + value(M.LifetimeProcess[r, t, v]) < p + value(M.PeriodLength[p]): - # EOL this period - if p == M.time_optimize.first() and v in M.time_exist: - # Existing capacity in first period. Remaining existing capacity in last existing period - retired = ( - value(M.ExistingCapacity[r, t, v]) - * M.LifetimeSurvivalCurve[r, M.time_exist.last(), t, v] - ) - elif p == v: - # New capacity in its vintage period. All new capacity - retired = M.V_NewCapacity[r, t, v] - else: - # Mid-horizon retirement - retired = M.V_Capacity[r, M.time_optimize.prev(p), t, v] - else: - if p == M.time_optimize.first() and v in M.time_exist: - # Existing capacity in first period. Remaining existing capacity in last - # existing period minus remaining capacity - retired = ( - value(M.ExistingCapacity[r, t, v]) - * value(M.LifetimeSurvivalCurve[r, M.time_exist.last(), t, v]) - - M.V_Capacity[r, p, t, v] - ) - elif p == v: - # New capacity in its vintage period. New capacity minus remaining capacity - retired = M.V_NewCapacity[r, t, v] - M.V_Capacity[r, p, t, v] - else: - # Existing or new capacity in some mid-life period. Previous minus current remaining - retired = M.V_Capacity[r, M.time_optimize.prev(p), t, v] - M.V_Capacity[r, p, t, v] - - # Distribute retirement evenly over planning period - retired /= value(M.PeriodLength[p]) - - return M.V_AnnualRetirement[r, p, t, v] == retired - - # --------------------------------------------------------------- # Define the Objective Function # --------------------------------------------------------------- From c2de93247152833ec029ae1e3b1bfb39cf06457a Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 27 Jun 2025 08:17:55 -0400 Subject: [PATCH 171/587] Rework adjustedcapacity and annualretirement some more --- data_files/example_dbs/survival_curve.sql | 16 +-- temoa/temoa_model/temoa_initialize.py | 20 ++++ temoa/temoa_model/temoa_model.py | 2 +- temoa/temoa_model/temoa_rules.py | 119 ++++++++++++---------- tests/legacy_test_values.py | 2 +- tests/testing_data/survival_curve.sql | 16 +-- 6 files changed, 103 insertions(+), 72 deletions(-) diff --git a/data_files/example_dbs/survival_curve.sql b/data_files/example_dbs/survival_curve.sql index e67cdfb67..f0ad9eeae 100644 --- a/data_files/example_dbs/survival_curve.sql +++ b/data_files/example_dbs/survival_curve.sql @@ -974,56 +974,56 @@ CREATE TABLE LifetimeSurvivalCurve notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO LifetimeSurvivalCurve VALUES('region',1994,'tech_ancient',1994,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',1994,'tech_ancient',1994,1,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',1999,'tech_ancient',1994,0.96999999999999992894,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2004,'tech_ancient',1994,0.88000000000000007105,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2009,'tech_ancient',1994,0.62000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2014,'tech_ancient',1994,0.27000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2019,'tech_ancient',1994,0.08,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2029,'tech_ancient',1994,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2010,'tech_old',2010,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2010,'tech_old',2010,1,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2015,'tech_old',2010,0.96999999999999992894,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2020,'tech_old',2010,0.88000000000000007105,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2025,'tech_old',2010,0.62000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2030,'tech_old',2010,0.27000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_old',2010,0.08,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_old',2010,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2025,'tech_current',2025,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2025,'tech_current',2025,1,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2030,'tech_current',2025,0.96999999999999992894,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_current',2025,0.88000000000000007105,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_current',2025,0.62000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_current',2025,0.27000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_current',2025,0.08,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_current',2025,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2030,'tech_future',2030,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2030,'tech_future',2030,1,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_future',2030,0.96999999999999992894,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_future',2030,0.88000000000000007105,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2030,0.62000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2030,0.27000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2030,0.08,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2030,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_future',2035,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_future',2035,1,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_future',2035,0.96999999999999992894,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2035,0.88000000000000007105,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2035,0.62000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2035,0.27000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2035,0.08,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2070,'tech_future',2035,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_future',2040,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_future',2040,1,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2040,0.96999999999999992894,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2040,0.88000000000000007105,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2040,0.62000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2040,0.27000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2040,0.08,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2075,'tech_future',2040,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2045,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2045,1,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2045,0.96999999999999992894,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2045,0.88000000000000007105,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2045,0.62000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2045,0.27000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2070,'tech_future',2045,0.08,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2080,'tech_future',2045,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2050,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2050,1,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2050,0.96999999999999992894,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2050,0.88000000000000007105,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2050,0.62000000000000001776,NULL); diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 8a570cbfd..009617e55 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -431,6 +431,18 @@ def CreateCapacityFactors(M: 'TemoaModel'): # CFP._constructed = True +def get_default_survival(M: 'TemoaModel', r, p, t, v): + """ + Getting LifetimeSurvivalCurve where it is not defined + If this is a survival curve process, return 0 (likely beyond EOL) + Otherwise return 1 (no survival curve based EOL) + """ + if M.isSurvivalCurveProcess[r, t, v]: + return 0 + else: + return 1 + + def get_default_process_lifetime(M: 'TemoaModel', r, t, v): """ This initializer used to initialize the LifetimeProcess parameter from LifetimeTech where needed @@ -1256,6 +1268,14 @@ def CreateSurvivalCurve(M: 'TemoaModel'): ) logger.error(msg) raise ValueError(msg) + + if value(M.LifetimeSurvivalCurve[r, v, t, v]) != 1: + msg = ( + 'LifetimeSurvivalCurve must begin at 1 for calculating annual retirements. ', + f'Got {value(M.LifetimeSurvivalCurve[r, v, t, v])} for ({r}, {v}, {t}, {v})' + ) + logger.error(msg) + raise ValueError(msg) # Collect a list of processes that needed to be interpolated, for warning if periods_rtv != list(range(p_first, p_last+1, 1)): diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 84e624991..d4abfece2 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -340,7 +340,7 @@ def __init__(M, *args, **kwargs): Integers, M.tech_all, M.vintage_all, - default=1, + default=get_default_survival, validate=validate_0to1, mutable=True ) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 6a611c151..15d4bf8ca 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -44,30 +44,6 @@ # --------------------------------------------------------------- -def get_capacity(M: 'TemoaModel', r, p, t, v, sc_frac, pl_frac): - """ - Utility function to get the remaining capacity at the beginning of a period - or during a period, based on the survival curve and process life fractions supplied. - Used in the AdjustedCapacity_Constraint and AnnualRetirement_Constraint - """ - - if t not in M.tech_retirement: - if v in M.time_exist: - return value(M.ExistingCapacity[r, t, v]) * sc_frac * pl_frac - else: - return M.V_NewCapacity[r, t, v] * sc_frac * pl_frac - else: - previous_retirements = sum( - M.V_RetiredCapacity[r, S_p, t, v] - for S_p in M.time_optimize - if v < S_p < p and S_p < v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[S_p]) - ) - if v in M.time_exist: - return (value(M.ExistingCapacity[r, t, v]) * sc_frac - previous_retirements) * pl_frac - else: - return (M.V_NewCapacity[r, t, v] * sc_frac - previous_retirements) * pl_frac - - def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): r""" This constraint updates the capacity of a process by taking into account retirements @@ -97,10 +73,23 @@ def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): & \text{if } t \in T^\text{ret},\ v \notin T^\text{e} \end{cases} """ - - sc_frac = value(M.PeriodSurvivalCurve[r, p, t, v]) - pl_frac = value(M.ProcessLifeFrac[r, p, t, v]) - return M.V_Capacity[r, p, t, v] == get_capacity(M, r, p, t, v, sc_frac, pl_frac) + + if v in M.time_exist: + built_capacity = value(M.ExistingCapacity[r, t, v]) + else: + built_capacity = M.V_NewCapacity[r, t, v] + + previous_retirements = 0 + if t in M.tech_retirement: + previous_retirements = sum( + M.V_RetiredCapacity[r, S_p, t, v] + for S_p in M.time_optimize + if v < S_p < p and S_p < v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[S_p]) + ) + + remaining_capacity = (built_capacity * value(M.PeriodSurvivalCurve[r, p, t, v]) - previous_retirements) + plf_adjusted = remaining_capacity * value(M.ProcessLifeFrac[r, p, t, v]) + return M.V_Capacity[r, p, t, v] == plf_adjusted def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): @@ -109,45 +98,67 @@ def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): Used to output retirement (including end of life, EOL) and model end of life flows and emissions. Assumes that retirement is evenly distributed over the model period in which that retirement occurs, in the same way we assume - capacity is deployed evenly over the model period. Note that - :math:`\textbf{CAP}_{r,p,t,v}` already accounts for retirement, survival - curves, and process life fraction via the AdjustedCapacity constraint. + capacity is deployed evenly over the model period. This formulation is + similar to the AdjustedCapacity constraint defining \textbf{CAP}_{r,p,t,v} + except that the AdjustedCapacity constraint uses PeriodSurvivalCurve, which + is the LifetimeSurvivalCurve averaged over each planning period. This + constraint uses LifetimeSurvivalCurve directly, which is the surviving + fraction at the beginning of each period. .. math:: :label: Annual Retirement - ART_{r,p,t,v} = - \frac{1}{LEN_{p}} \cdot + \textbf{ART}_{r,p,t,v} = \begin{cases} - \textbf{ECAP}_{r,t,v} \cdot LSC_{r,p,t,v}^{\text{final}}, & \text{if } p = P_0,\ v \in T^{\text{exist}}, \text{ and EOL} \\ - \textbf{NCAP}_{r,t,v}, & \text{if } p = v, \text{ and EOL} \\ - \textbf{CAP}_{r,p{-}1,t,v}, & \text{if } v < p < v + LT_{r,t,v}, \text{ and EOL} \\ - \textbf{ECAP}_{r,t,v} \cdot LSC_{r,p,t,v}^{\text{final}} - \textbf{CAP}_{r,p,t,v}, & \text{if } p = P_0,\ v \in T^{\text{exist}} \text{, and not EOL} \\ - \textbf{NCAP}_{r,t,v} - \textbf{CAP}_{r,p,t,v}, & \text{if } p = v \text{, and not EOL} \\ - \textbf{CAP}_{r,p{-}1,t,v} - \textbf{CAP}_{r,p,t,v}, & \text{if not EOL otherwise} + \text{ECAP}_{r,t,v} \cdot \text{LSC}_{r,p,t,v} \cdot \text{PLF}_{r,p,t,v} + & \text{if } t \notin T^\text{ret},\ v \in T^\text{e} \\ + \textbf{NCAP}_{r,t,v} \cdot \text{LSC}_{r,p,t,v} \cdot \text{PLF}_{r,p,t,v} + & \text{if } t \notin T^\text{ret},\ v \notin T^\text{e} \\ + \left( \text{ECAP}_{r,t,v} \cdot \text{LSC}_{r,p,t,v} + - \sum\limits_{p^* = v}^{p} + \textbf{RCAP}_{r,p^*,t,v} \right) \cdot \text{PLF}_{r,p,t,v} + & \text{if } t \in T^\text{ret},\ v \in T^\text{e} \\ + \left( \textbf{NCAP}_{r,t,v} \cdot \text{LSC}_{r,p,t,v} + - \sum\limits_{p^* = v}^{p} + \textbf{RCAP}_{r,p^*,t,v} \right) \cdot \text{PLF}_{r,p,t,v} + & \text{if } t \in T^\text{ret},\ v \notin T^\text{e} \end{cases} """ - # First, get the remaining capacity at the beginning of this period - sc_frac_begin = value(M.LifetimeSurvivalCurve[r, p, t, v]) - capacity_begin = get_capacity(M, r, p, t, v, sc_frac_begin, 1) - + lsc = value(M.LifetimeSurvivalCurve[r, p, t, v]) + + if v in M.time_exist: + built_capacity = value(M.ExistingCapacity[r, t, v]) + else: + built_capacity = M.V_NewCapacity[r, t, v] + + # Handle end of life period if p <= v + value(M.LifetimeProcess[r, t, v]) < p + value(M.PeriodLength[p]): - # If this is the end-of-life period, just return the beginning capacity. It all retires - retired = capacity_begin + + previous_retirements = 0 + if t in M.tech_retirement: + previous_retirements = sum( + M.V_RetiredCapacity[r, S_p, t, v] + for S_p in M.time_optimize + if v < S_p < p and S_p < v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[S_p]) + ) + + # Retire everything surviving to this point + retired = built_capacity * lsc - previous_retirements + + # Handle mid-life periods else: - # If not EOL period, need capacity at the end of this period too - # (i.e., at the beginning of the next period) - p_next = M.time_future.next(p) - sc_frac_end = value(M.LifetimeSurvivalCurve[r, p_next, t, v]) - capacity_end = get_capacity(M, r, p_next, t, v, sc_frac_end, 1) + lsc_next = value(M.LifetimeSurvivalCurve[r, M.time_future.next(p), t, v]) - retired = capacity_begin - capacity_end + early_retirement = 0 + if t in M.tech_retirement: + early_retirement = M.V_RetiredCapacity[r, p, t, v] - # Distribute retirement evenly over planning period - retired /= value(M.PeriodLength[p]) + # Anything that does not survive this period plus early retirement in this period + retired = built_capacity * (lsc - lsc_next) + early_retirement - return M.V_AnnualRetirement[r, p, t, v] == retired + annualised_retirement = retired / M.PeriodLength[p] + return M.V_AnnualRetirement[r, p, t, v] == annualised_retirement def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index 1c107805d..2362b37c4 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -90,7 +90,7 @@ class ExpectedVals(Enum): # added 2025/06/19 after addition of survival curves # reduced after changing fixed costs from MLP to PL # increased after adding PeriodSurvivalCurve - ExpectedVals.OBJ_VALUE: 31.9452, + ExpectedVals.OBJ_VALUE: 31.9423, ExpectedVals.EFF_DOMAIN_SIZE: 64, ExpectedVals.EFF_INDEX_SIZE: 8, ExpectedVals.CONSTR_COUNT: 101, diff --git a/tests/testing_data/survival_curve.sql b/tests/testing_data/survival_curve.sql index e67cdfb67..f0ad9eeae 100644 --- a/tests/testing_data/survival_curve.sql +++ b/tests/testing_data/survival_curve.sql @@ -974,56 +974,56 @@ CREATE TABLE LifetimeSurvivalCurve notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO LifetimeSurvivalCurve VALUES('region',1994,'tech_ancient',1994,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',1994,'tech_ancient',1994,1,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',1999,'tech_ancient',1994,0.96999999999999992894,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2004,'tech_ancient',1994,0.88000000000000007105,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2009,'tech_ancient',1994,0.62000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2014,'tech_ancient',1994,0.27000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2019,'tech_ancient',1994,0.08,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2029,'tech_ancient',1994,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2010,'tech_old',2010,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2010,'tech_old',2010,1,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2015,'tech_old',2010,0.96999999999999992894,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2020,'tech_old',2010,0.88000000000000007105,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2025,'tech_old',2010,0.62000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2030,'tech_old',2010,0.27000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_old',2010,0.08,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_old',2010,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2025,'tech_current',2025,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2025,'tech_current',2025,1,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2030,'tech_current',2025,0.96999999999999992894,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_current',2025,0.88000000000000007105,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_current',2025,0.62000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_current',2025,0.27000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_current',2025,0.08,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_current',2025,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2030,'tech_future',2030,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2030,'tech_future',2030,1,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_future',2030,0.96999999999999992894,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_future',2030,0.88000000000000007105,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2030,0.62000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2030,0.27000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2030,0.08,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2030,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_future',2035,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_future',2035,1,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_future',2035,0.96999999999999992894,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2035,0.88000000000000007105,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2035,0.62000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2035,0.27000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2035,0.08,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2070,'tech_future',2035,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_future',2040,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_future',2040,1,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2040,0.96999999999999992894,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2040,0.88000000000000007105,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2040,0.62000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2040,0.27000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2040,0.08,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2075,'tech_future',2040,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2045,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2045,1,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2045,0.96999999999999992894,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2045,0.88000000000000007105,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2045,0.62000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2045,0.27000000000000001776,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2070,'tech_future',2045,0.08,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2080,'tech_future',2045,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2050,0.99000000000000003552,NULL); +INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2050,1,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2050,0.96999999999999992894,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2050,0.88000000000000007105,NULL); INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2050,0.62000000000000001776,NULL); From 4b396092e13c6fe4f23c433eb8c0cec1cba4eb39 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 27 Jun 2025 09:33:41 -0400 Subject: [PATCH 172/587] Update docs for adjusted capacity and annual retirement --- docs/source/images/adjusted_capacity_plf.pdf | Bin 0 -> 16284 bytes docs/source/images/adjusted_capacity_plf.png | Bin 0 -> 19933 bytes docs/source/images/adjusted_capacity_plf.svg | 290 ++++ docs/source/images/adjusted_capacity_sc.pdf | Bin 0 -> 35850 bytes docs/source/images/adjusted_capacity_sc.png | Bin 0 -> 23187 bytes docs/source/images/adjusted_capacity_sc.svg | 1246 +++++++++++++++++ .../images/survival_curve_discounting.pdf | Bin 21131 -> 21145 bytes .../images/survival_curve_discounting.png | Bin 60355 -> 58598 bytes .../images/survival_curve_discounting.svg | 1060 +++----------- temoa/temoa_model/temoa_rules.py | 79 +- 10 files changed, 1776 insertions(+), 899 deletions(-) create mode 100644 docs/source/images/adjusted_capacity_plf.pdf create mode 100644 docs/source/images/adjusted_capacity_plf.png create mode 100644 docs/source/images/adjusted_capacity_plf.svg create mode 100644 docs/source/images/adjusted_capacity_sc.pdf create mode 100644 docs/source/images/adjusted_capacity_sc.png create mode 100644 docs/source/images/adjusted_capacity_sc.svg diff --git a/docs/source/images/adjusted_capacity_plf.pdf b/docs/source/images/adjusted_capacity_plf.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6170567f1c7cedf81507e0232779a82e502f4028 GIT binary patch literal 16284 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 literal 0 HcmV?d00001 diff --git a/docs/source/images/adjusted_capacity_plf.png b/docs/source/images/adjusted_capacity_plf.png new file mode 100644 index 0000000000000000000000000000000000000000..36b4cac5632ab0c904a9e4476c3e604677a61fd0 GIT binary patch literal 19933 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 + + + + + + + + + + + + + + PE + P0 + Process reaches EOL mid-period + ProcessLifeFraction adjustment + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/source/images/adjusted_capacity_sc.pdf b/docs/source/images/adjusted_capacity_sc.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0282149cb4b89a757caf7f1e2c89de32bd3618ae GIT binary patch literal 35850 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 Ol43GvlTKg0_x}Lmt*46s literal 0 HcmV?d00001 diff --git a/docs/source/images/adjusted_capacity_sc.svg b/docs/source/images/adjusted_capacity_sc.svg new file mode 100644 index 000000000..96c253874 --- /dev/null +++ b/docs/source/images/adjusted_capacity_sc.svg @@ -0,0 +1,1246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PE + P0 + Survival curve in each integer year + Averaged over each period + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/source/images/survival_curve_discounting.pdf b/docs/source/images/survival_curve_discounting.pdf index 05948488447865ceb3933ce697a976001d04570b..65006352e8b3dcdad6a3c6b2c382d16a7ab2a63c 100644 GIT binary patch delta 3511 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 delta 3446 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 aJ9JrbGuYE-2*y$hg>tg_q@N}@e*53iYqwhf diff --git a/docs/source/images/survival_curve_discounting.svg b/docs/source/images/survival_curve_discounting.svg index 81c83fefe..06c7f314c 100644 --- a/docs/source/images/survival_curve_discounting.svg +++ b/docs/source/images/survival_curve_discounting.svg @@ -2,13 +2,13 @@ - - - - - - - + id="defs1" /> + id="layer1" + transform="translate(-1412,-110)"> - - - - - - + x="1564.5" + y="112.5" /> - - + x="1614.5" + y="112.5" /> + d="m 1464.5,137.5 v 175" + id="path63-4" /> + d="M 1514.5,147.5 V 312.50001" + id="path64-9" /> + d="M 1564.5,312.5 V 185.21875" + id="path65-6" /> + d="M 1614.5,312.50002 V 237.5" + id="path66-6" /> + d="M 1664.5,312.50002 V 282.5" + id="path67-7" /> + d="m 1714.5,312.50005 v -7.12501" + id="path68-7" /> + d="m 1424.5,137.50002 v 175" + id="path69-4" /> + d="m 1434.5,137.5 v 175" + id="path70-8" /> + d="m 1444.5,137.5 v 175" + id="path71-9" /> + d="m 1454.5,137.5 v 175" + id="path72-9" /> + d="M 1474.5,139.5 V 312.50002" + id="path73-2" /> + d="M 1484.5,140.9532 V 312.5" + id="path74-6" /> + d="M 1494.5,143.41159 V 312.49997" + id="path75-2" /> + d="M 1504.5,145.46707 V 312.5" + id="path76-3" /> + d="M 1524.5,155.08037 V 312.50002" + id="path77-3" /> + d="M 1534.5,162.66072 V 312.5" + id="path78-6" /> + d="M 1544.5,170.24108 V 312.5" + id="path79-4" /> + d="M 1554.5,177.5 V 312.49999" + id="path80-0" /> + d="M 1574.5,195.82141 V 312.49999" + id="path81-8" /> + d="M 1584.5,206.24107 V 312.5" + id="path82-6" /> + d="M 1594.5,216.66072 V 312.5" + id="path83-7" /> + d="M 1604.5,227.08037 V 312.5" + id="path84-3" /> + d="m 1624.5,247.5 v 65.00002" + id="path85-5" /> + d="m 1634.5,255.5 v 57.00001" + id="path86-0" /> + d="m 1644.5,264.5 v 47.99999" + id="path87-3" /> + d="m 1654.5,273.5 v 39" + id="path88-5" /> + d="m 1674.5,287.5 v 25.00002" + id="path89-3" /> + d="m 1684.5,292.49999 v 20" + id="path90-4" /> + d="M 1694.5,296.2143 V 312.5" + id="path91-5" /> + d="m 1704.5,302.5 v 10" + id="path92-0" /> + d="m 1724.5,306.78572 v 5.7143" + id="path93-7" /> - - - - - + d="m 1734.5,308.2143 v 4.28569" + id="path94-7" /> - - + d="m 1614.5,312.5 v -200" + id="path105-4" /> + x="1414.5" + y="137.5" /> + x="1424.5" + y="137.5" /> + x="1434.5" + y="137.5" /> + x="1444.5" + y="137.5" /> + x="1454.5" + y="137.5" /> + x="1464.5" + y="139.5" /> + x="1474.5" + y="141.35095" /> + x="1484.5" + y="143.41162" /> + x="1494.5" + y="145.4671" /> + x="1504.5" + y="147.5" /> + x="1514.5" + y="155.08038" /> + x="1524.5" + y="162.66071" /> + x="1534.5" + y="170.24109" /> + x="1544.5" + y="177.5" /> + x="1554.5" + y="185.21875" /> + x="1564.5" + y="195.82141" /> + x="1574.5" + y="206.24109" /> + x="1584.5" + y="216.66071" /> + x="1594.5" + y="227.08038" /> + x="1604.5" + y="237.5" /> + x="1654.5" + y="282.5" /> + x="1644.5" + y="273.5" /> + x="1634.5" + y="264.5" /> + x="1624.5" + y="255.5" /> + x="1614.5" + y="247.5" /> + x="1704.5" + y="305.375" /> + x="1694.5" + y="302.5" /> + x="1684.5" + y="296.21429" /> + x="1674.5" + y="292.5" /> + x="1664.5" + y="287.5" /> + x="1714.5" + y="306.78571" /> + x="1724.5" + y="308.21429" /> + x="1734.5" + y="309.29565" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + x="1744.5" + y="310.00275" /> - + - - Factor = - Survival curve - PE - P0 - Area - Area - Defined in each period - Intermediate years linearly interpolated - Each year discounted to P0 diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 15d4bf8ca..ce4bdb463 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -49,29 +49,52 @@ def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): This constraint updates the capacity of a process by taking into account retirements and end of life. For a given :code:`(r,p,t,v)` index, this constraint sets the capacity equal to the amount installed in period :code:`v` and subtracts from it any and all retirements - that occurred up until the period in question, :code:`p`, and end of life from the + that occurred prior to the period in question, :code:`p`, and end of life from the survival curve if defined. It finally adjusts for the process life fraction, which accounts for a possible mid-period end of life where, for example, EOL 3 years into a 5-year period would be treated as :math:`\frac{3}{5}` capacity for all 5 years. + + .. figure:: images/adjusted_capacity_plf.* + :align: center + :width: 100% + :figclass: align-center + :figwidth: 50% + + For processes reaching end of life mid-period, the process life fraction adjustment is applied, + distributing the effective capacity over the whole period. + + For processes using survival curves, the yearly survival curve is averaged over the period + to get the effective remaining capacity for that period :math:`(\text{LSC}_{r,p,t,v} \to + \text{PSC}_{r,p,t,v})`. Because this implicitly handles mid-period end of life, the process + life fraction parameter :math:`\text{PLF}_{r,p,t,v} = 1` for survival curve processes. + For processes not using survival curves, :math:`\text{PSC}_{r,p,t,v} = 1` + + .. figure:: images/adjusted_capacity_sc.* + :align: center + :width: 100% + :figclass: align-center + :figwidth: 50% + + For processes with a defined survival curve, the surviving capacity is averaged over each + period to get the adjusted capacity. This implicitly handles mid-period end of life as a + survival curve will always be zero after the end of life of a process. .. math:: :label: Adjusted Capacity \textbf{CAP}_{r,p,t,v} = \begin{cases} - \text{ECAP}_{r,t,v} \cdot \text{LSC}_{r,p,t,v} \cdot \text{PLF}_{r,p,t,v} - & \text{if } t \notin T^\text{ret},\ v \in T^\text{e} \\ - \textbf{NCAP}_{r,t,v} \cdot \text{LSC}_{r,p,t,v} \cdot \text{PLF}_{r,p,t,v} - & \text{if } t \notin T^\text{ret},\ v \notin T^\text{e} \\ - \left( \text{ECAP}_{r,t,v} \cdot \text{LSC}_{r,p,t,v} - - \sum\limits_{p^* = v}^{p} - \textbf{RCAP}_{r,p^*,t,v} \right) \cdot \text{PLF}_{r,p,t,v} - & \text{if } t \in T^\text{ret},\ v \in T^\text{e} \\ - \left( \textbf{NCAP}_{r,t,v} \cdot \text{LSC}_{r,p,t,v} - - \sum\limits_{p^* = v}^{p} - \textbf{RCAP}_{r,p^*,t,v} \right) \cdot \text{PLF}_{r,p,t,v} - & \text{if } t \in T^\text{ret},\ v \notin T^\text{e} + \left( \text{ECAP}_{r,t,v} \cdot \text{PSC}_{r,p,t,v} + - \sum\limits_{v < p' < p} + \textbf{RCAP}_{r,p',t,v} \right) \cdot \text{PLF}_{r,p,t,v} + & \text{if } \ v \in T^\text{e} \\ + \left( \textbf{NCAP}_{r,t,v} \cdot \text{PSC}_{r,p,t,v} + - \sum\limits_{v < p' < p} + \textbf{RCAP}_{r,p',t,v} \right) \cdot \text{PLF}_{r,p,t,v} + & \text{if } \ v \notin T^\text{e} \end{cases} + + """ if v in M.time_exist: @@ -99,8 +122,8 @@ def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): life flows and emissions. Assumes that retirement is evenly distributed over the model period in which that retirement occurs, in the same way we assume capacity is deployed evenly over the model period. This formulation is - similar to the AdjustedCapacity constraint defining \textbf{CAP}_{r,p,t,v} - except that the AdjustedCapacity constraint uses PeriodSurvivalCurve, which + similar to the :code:`AdjustedCapacity_Constraint` defining \textbf{CAP}_{r,p,t,v} + except that the :code:`AdjustedCapacity_Constraint` uses PeriodSurvivalCurve, which is the LifetimeSurvivalCurve averaged over each planning period. This constraint uses LifetimeSurvivalCurve directly, which is the surviving fraction at the beginning of each period. @@ -110,19 +133,21 @@ def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): \textbf{ART}_{r,p,t,v} = \begin{cases} - \text{ECAP}_{r,t,v} \cdot \text{LSC}_{r,p,t,v} \cdot \text{PLF}_{r,p,t,v} - & \text{if } t \notin T^\text{ret},\ v \in T^\text{e} \\ - \textbf{NCAP}_{r,t,v} \cdot \text{LSC}_{r,p,t,v} \cdot \text{PLF}_{r,p,t,v} - & \text{if } t \notin T^\text{ret},\ v \notin T^\text{e} \\ - \left( \text{ECAP}_{r,t,v} \cdot \text{LSC}_{r,p,t,v} - - \sum\limits_{p^* = v}^{p} - \textbf{RCAP}_{r,p^*,t,v} \right) \cdot \text{PLF}_{r,p,t,v} - & \text{if } t \in T^\text{ret},\ v \in T^\text{e} \\ - \left( \textbf{NCAP}_{r,t,v} \cdot \text{LSC}_{r,p,t,v} - - \sum\limits_{p^* = v}^{p} - \textbf{RCAP}_{r,p^*,t,v} \right) \cdot \text{PLF}_{r,p,t,v} - & \text{if } t \in T^\text{ret},\ v \notin T^\text{e} + \text{ECAP}_{r,t,v} \cdot \text{LSC}_{r,p,t,v} + - \sum\limits_{v < p' < p} \textbf{RCAP}_{r,p',t,v} + & \text{if } v \in T^\text{e} \text{ and EOL} \\ + \textbf{NCAP}_{r,t,v} \cdot \text{LSC}_{r,p,t,v} + - \sum\limits_{v < p' < p} \textbf{RCAP}_{r,p',t,v} + & \text{if } v \notin T^\text{e} \text{ and EOL} \\ + \text{ECAP}_{r,t,v} \cdot \left( \text{LSC}_{r,p,t,v} + - \text{LSC}_{r,p_{next},t,v} \right) + \textbf{RCAP}_{r,p,t,v} + & \text{if } v \in T^\text{e} \text{ and not EOL} \\ + \text{NCAP}_{r,t,v} \cdot \left( \text{LSC}_{r,p,t,v} + - \text{LSC}_{r,p_{next},t,v} \right) + \textbf{RCAP}_{r,p,t,v} + & \text{if } v \notin T^\text{e} \text{ and not EOL} \\ \end{cases} + + \\\text{where EOL when } p \leq v + LFP_{r,t,v} < p + LEN_p """ lsc = value(M.LifetimeSurvivalCurve[r, p, t, v]) From 546958e2abd716e12b46243d90f3a2c495c689b7 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 2 Jul 2025 10:46:53 -0400 Subject: [PATCH 173/587] Reconcile early retirement with survival curves --- .../images/survival_curve_discounting.pdf | Bin 21145 -> 21692 bytes .../images/survival_curve_discounting.png | Bin 58598 -> 58999 bytes .../images/survival_curve_discounting.svg | 1053 ++++++++++++++--- temoa/temoa_model/temoa_initialize.py | 14 - temoa/temoa_model/temoa_model.py | 2 - temoa/temoa_model/temoa_rules.py | 213 ++-- 6 files changed, 978 insertions(+), 304 deletions(-) diff --git a/docs/source/images/survival_curve_discounting.pdf b/docs/source/images/survival_curve_discounting.pdf index 65006352e8b3dcdad6a3c6b2c382d16a7ab2a63c..e2943effff1aad748186696c665aca1dce08e45e 100644 GIT binary patch delta 4176 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 b*fFdCCz^z@7UKY)S3S>u=8Tc0G5h}k1vG(% delta 3779 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 diff --git a/docs/source/images/survival_curve_discounting.png b/docs/source/images/survival_curve_discounting.png index 1890437057927760e22c364ea0e1d11daeba1203..b2717197054c94b49742b4d2ef674f51d6a7e47d 100644 GIT binary patch literal 58999 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 + id="defs1"> + + + + transform="translate(-63.186523)"> + x="639.31348" + y="512.57977" /> + + + + + + x="689.31348" + y="62.579777" /> + + + + d="m 539.31348,537.57977 v 175" + id="path63" /> + d="M 589.31348,547.57977 V 712.57978" + id="path64" /> + d="M 639.31347,712.57977 V 585.29852" + id="path65" /> + d="M 689.31348,712.57979 V 637.57977" + id="path66" /> + d="M 739.31348,712.57979 V 682.57977" + id="path67" /> + d="m 789.31348,712.57982 v -7.12501" + id="path68" /> + d="m 499.31348,537.57979 v 175" + id="path69" /> + d="m 509.31348,537.57977 v 175" + id="path70" /> + d="m 519.31348,537.57977 v 175" + id="path71" /> + d="m 529.31348,537.57977 v 175" + id="path72" /> + d="M 549.31348,539.57977 V 712.57979" + id="path73" /> + d="m 559.31348,541.03297 v 171.5468" + id="path74" /> + d="M 569.31347,543.49136 V 712.57974" + id="path75" /> + d="M 579.31348,545.54684 V 712.57977" + id="path76" /> + d="M 599.31348,555.16014 V 712.57979" + id="path77" /> + d="M 609.31348,562.74049 V 712.57977" + id="path78" /> + d="M 619.31348,570.32085 V 712.57977" + id="path79" /> + d="M 629.31348,577.57977 V 712.57976" + id="path80" /> + d="M 649.31348,595.90118 V 712.57976" + id="path81" /> + d="M 659.31348,606.32084 V 712.57977" + id="path82" /> + d="m 669.31348,616.74049 v 95.83928" + id="path83" /> + d="m 679.31348,627.16014 v 85.41963" + id="path84" /> + d="m 699.31348,647.57977 v 65.00002" + id="path85" /> + d="m 709.31348,655.57977 v 57.00001" + id="path86" /> + d="m 719.31348,664.57977 v 47.99999" + id="path87" /> + d="m 729.31348,673.57977 v 39" + id="path88" /> + d="m 749.31348,687.57977 v 25.00002" + id="path89" /> + d="m 759.31348,692.57976 v 20" + id="path90" /> + d="m 769.31348,696.29407 v 16.2857" + id="path91" /> + d="m 779.31348,702.57977 v 10" + id="path92" /> + d="m 799.31348,706.86549 v 5.7143" + id="path93" /> + d="m 809.31348,708.29407 v 4.28569" + id="path94" /> + + + + + + d="m 689.31348,712.57977 v -200" + id="path105" /> + + + x="489.31348" + y="537.57977" /> + x="499.31348" + y="537.57977" /> + x="509.31348" + y="537.57977" /> + x="519.31348" + y="537.57977" /> + x="529.31348" + y="537.57977" /> + x="539.31348" + y="539.57977" /> + x="549.31348" + y="541.43073" /> + x="559.31348" + y="543.49139" /> + x="569.31348" + y="545.54688" /> + x="579.31348" + y="547.57977" /> + x="589.31348" + y="555.16016" /> + x="599.31348" + y="562.74048" /> + x="609.31348" + y="570.32086" /> + x="619.31348" + y="577.57977" /> + x="629.31348" + y="585.29852" /> + x="639.31348" + y="595.90118" /> + x="649.31348" + y="606.32086" /> + x="659.31348" + y="616.74048" /> + x="669.31348" + y="627.16016" /> + x="679.31348" + y="637.57977" /> + x="729.31348" + y="682.57977" /> + x="719.31348" + y="673.57977" /> + x="709.31348" + y="664.57977" /> + x="699.31348" + y="655.57977" /> + x="689.31348" + y="647.57977" /> + x="779.31348" + y="705.45477" /> + x="769.31348" + y="702.57977" /> + x="759.31348" + y="696.29407" /> + x="749.31348" + y="692.57977" /> + x="739.31348" + y="687.57977" /> + x="789.31348" + y="706.86548" /> + x="799.31348" + y="708.29407" /> + x="809.31348" + y="709.37543" /> + x="819.31348" + y="710.08252" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Factor = + Survival curve + PE + P0 + Area + Area + Defined in each period + Intermediate years linearly interpolated + Each year discounted to P0 + diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 009617e55..4f6a391f7 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1438,20 +1438,6 @@ def EmissionActivityIndices(M: 'TemoaModel'): # return indices -def PeriodSurvivalCurveIndices(M: 'TemoaModel'): - """ - (region, period, tech, vintage) tuples where a process with a survival curve is - active with non-zero surviving capacity - """ - indices = set( - (r, p, t, v) - for r, t, v in M.survivalCurvePeriods - for p in M.survivalCurvePeriods[r, t, v] - ) - - return indices - - def ModelProcessLifeIndices(M: 'TemoaModel'): """\ Returns the set of sensical (region, period, tech, vintage) tuples. The tuple indicates diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index d4abfece2..07917bb92 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -429,8 +429,6 @@ def __init__(M, *args, **kwargs): M.ProcessLifeFrac_rptv = Set(dimen=4, initialize=ModelProcessLifeIndices) M.ProcessLifeFrac = Param(M.ProcessLifeFrac_rptv, initialize=ParamProcessLifeFraction_rule) - M.PeriodSurvivalCurve = Param(M.CostFixed_rptv, initialize=PeriodSurvivalCurve_rule) - M.LimitCapacityConstraint_rpt = Set( within=M.regionalGlobalIndices * M.time_optimize * M.tech_or_group * M.operator ) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index ce4bdb463..13e79972b 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -63,11 +63,10 @@ def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): For processes reaching end of life mid-period, the process life fraction adjustment is applied, distributing the effective capacity over the whole period. - For processes using survival curves, the yearly survival curve is averaged over the period - to get the effective remaining capacity for that period :math:`(\text{LSC}_{r,p,t,v} \to - \text{PSC}_{r,p,t,v})`. Because this implicitly handles mid-period end of life, the process - life fraction parameter :math:`\text{PLF}_{r,p,t,v} = 1` for survival curve processes. - For processes not using survival curves, :math:`\text{PSC}_{r,p,t,v} = 1` + For processes using survival curves, the yearly survival curve :math:`\text{LSC}_{r,p,t,v}` is + averaged over the period to get the effective remaining capacity for that period Because this + implicitly handles mid-period end of life, :math:`\text{PLF}_{r,p,t,v}` is used to account for both + phenomena. .. figure:: images/adjusted_capacity_sc.* :align: center @@ -84,105 +83,131 @@ def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): \textbf{CAP}_{r,p,t,v} = \begin{cases} - \left( \text{ECAP}_{r,t,v} \cdot \text{PSC}_{r,p,t,v} - - \sum\limits_{v < p' < p} - \textbf{RCAP}_{r,p',t,v} \right) \cdot \text{PLF}_{r,p,t,v} - & \text{if } \ v \in T^\text{e} \\ - \left( \textbf{NCAP}_{r,t,v} \cdot \text{PSC}_{r,p,t,v} - - \sum\limits_{v < p' < p} - \textbf{RCAP}_{r,p',t,v} \right) \cdot \text{PLF}_{r,p,t,v} - & \text{if } \ v \notin T^\text{e} + \text{PLF}_{r,p,t,v} \cdot + \left( + \text{ECAP}_{r,t,v} - \sum\limits_{v < p' <= p} + \frac{\textbf{RCAP}_{r,p',t,v}}{\text{LSC}_{r,p',t,v}} + \right) + & \text{if } \ v \in T^e \\ + \text{PLF}_{r,p,t,v} \cdot + \left( + \textbf{NCAP}_{r,t,v} - \sum\limits_{v < p' <= p} + \frac{\textbf{RCAP}_{r,p',t,v}}{\text{LSC}_{r,p',t,v}} + \right) + & \text{if } \ v \notin T^e \end{cases} - - """ + \\\text{where } + \text{PLF}_{r,p,t,v} = + \begin{cases} + \frac{1}{\text{LEN}_p} \cdot \left( + \sum\limits_{y = p}^{p+\text{LEN}_{p}-1}{\text{LSC}_{r,y,t,v}} + \right) + & \text{if } t \in T^{sc} \\ + \frac{1}{\text{LEN}_p} \cdot \left( v + \text{LTP}_{r,t,v} - p \right) + & \text{if } t \notin T^{sc} \\ + \end{cases} + + We divide :math:`\frac{\textbf{RCAP}_{r,p',t,v}}{\text{LSC}_{r,p',t,v}}` + because the average survival factor in :math:`\text{PLF}_{r,p,t,v}` is indexed to the vintage + period (the beginning of the survival curve). So, we adjust for the relative survival from + the time when that retirement occurred (treated here as at the beginning of each period). + """ if v in M.time_exist: built_capacity = value(M.ExistingCapacity[r, t, v]) else: built_capacity = M.V_NewCapacity[r, t, v] - previous_retirements = 0 + early_retirements = 0 if t in M.tech_retirement: - previous_retirements = sum( - M.V_RetiredCapacity[r, S_p, t, v] + early_retirements = sum( + M.V_RetiredCapacity[r, S_p, t, v] / value(M.LifetimeSurvivalCurve[r, S_p, t, v]) for S_p in M.time_optimize - if v < S_p < p and S_p < v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[S_p]) + if v < S_p <= p and S_p < v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[S_p]) ) - remaining_capacity = (built_capacity * value(M.PeriodSurvivalCurve[r, p, t, v]) - previous_retirements) - plf_adjusted = remaining_capacity * value(M.ProcessLifeFrac[r, p, t, v]) - return M.V_Capacity[r, p, t, v] == plf_adjusted + remaining_capacity = (built_capacity - early_retirements) * value(M.ProcessLifeFrac[r, p, t, v]) + return M.V_Capacity[r, p, t, v] == remaining_capacity def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): r""" Get the annualised retirement rate for a process in a given period. - Used to output retirement (including end of life, EOL) and model end of - life flows and emissions. Assumes that retirement is evenly distributed over - the model period in which that retirement occurs, in the same way we assume - capacity is deployed evenly over the model period. This formulation is - similar to the :code:`AdjustedCapacity_Constraint` defining \textbf{CAP}_{r,p,t,v} - except that the :code:`AdjustedCapacity_Constraint` uses PeriodSurvivalCurve, which - is the LifetimeSurvivalCurve averaged over each planning period. This - constraint uses LifetimeSurvivalCurve directly, which is the surviving - fraction at the beginning of each period. + Used to output retirement (including end of life, EOL) and to model end of + life flows and emissions. Assumes that retirement from the beginning of each period + is evenly distributed over that model period :math:`\frac{1}{\text{LEN}_p}` + for the accounting of retirement flows (in the same way we assume capacity is + deployed evenly over the model period for construction inputs and embodied emissions). + The factor :math:`\frac{\text{LSC}_{r,p,t,v}}{\text{PLF}_{r,p,t,v}}` + adjusts the average survival during a period to the survival at the beginning + of that period. .. math:: :label: Annual Retirement \textbf{ART}_{r,p,t,v} = \begin{cases} - \text{ECAP}_{r,t,v} \cdot \text{LSC}_{r,p,t,v} - - \sum\limits_{v < p' < p} \textbf{RCAP}_{r,p',t,v} - & \text{if } v \in T^\text{e} \text{ and EOL} \\ - \textbf{NCAP}_{r,t,v} \cdot \text{LSC}_{r,p,t,v} - - \sum\limits_{v < p' < p} \textbf{RCAP}_{r,p',t,v} - & \text{if } v \notin T^\text{e} \text{ and EOL} \\ - \text{ECAP}_{r,t,v} \cdot \left( \text{LSC}_{r,p,t,v} - - \text{LSC}_{r,p_{next},t,v} \right) + \textbf{RCAP}_{r,p,t,v} - & \text{if } v \in T^\text{e} \text{ and not EOL} \\ - \text{NCAP}_{r,t,v} \cdot \left( \text{LSC}_{r,p,t,v} - - \text{LSC}_{r,p_{next},t,v} \right) + \textbf{RCAP}_{r,p,t,v} - & \text{if } v \notin T^\text{e} \text{ and not EOL} \\ + \frac{1}{\text{LEN}_p} \cdot + \frac{\text{LSC}_{r,p,t,v}}{\text{PLF}_{r,p,t,v}} \cdot \textbf{CAP}_{r,p,t,v} + & \text{if EOL} \\ + \frac{1}{\text{LEN}_p} \cdot + \left( + \frac{\text{LSC}_{r,p,t,v}}{\text{PLF}_{r,p,t,v}} \cdot \textbf{CAP}_{r,p,t,v} + - \frac{\text{LSC}_{r,p_{next},t,v}}{\text{PLF}_{r,p_{next},t,v}} \cdot \textbf{CAP}_{r,p_{next},t,v} + \right) + & \text{otherwise} \\ \end{cases} - \\\text{where EOL when } p \leq v + LFP_{r,t,v} < p + LEN_p + \\\text{where EOL when } p \leq v + LTP_{r,t,v} < p + LEN_p """ - - lsc = value(M.LifetimeSurvivalCurve[r, p, t, v]) - - if v in M.time_exist: - built_capacity = value(M.ExistingCapacity[r, t, v]) + + ## Get the capacity at the start of this period + if p == v + value(M.LifetimeProcess[r, t, v]): + # Exact EOL. No V_Capacity or V_RetiredCapacity for this period. + if p == M.time_optimize.first(): + # Must be existing capacity. Apply survival curve to existing cap + cap_begin = M.ExistingCapacity[r, t, v] * M.LifetimeSurvivalCurve[r, p, t, v] + else: + # Get previous capacity and continue survival curve + p_prev = M.time_optimize.prev(p) + cap_begin = ( + M.V_Capacity[r, p_prev, t, v] + * value(M.LifetimeSurvivalCurve[r, p, t, v]) + / value(M.ProcessLifeFrac[r, p_prev, t, v]) + ) else: - built_capacity = M.V_NewCapacity[r, t, v] + # The capacity at the beginning of the period + cap_begin = ( + M.V_Capacity[r, p, t, v] + * value(M.LifetimeSurvivalCurve[r, p, t, v]) + / value(M.ProcessLifeFrac[r, p, t, v]) + ) - # Handle end of life period + ## Get the capacity at the end of this period if p <= v + value(M.LifetimeProcess[r, t, v]) < p + value(M.PeriodLength[p]): - - previous_retirements = 0 - if t in M.tech_retirement: - previous_retirements = sum( - M.V_RetiredCapacity[r, S_p, t, v] - for S_p in M.time_optimize - if v < S_p < p and S_p < v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[S_p]) - ) - - # Retire everything surviving to this point - retired = built_capacity * lsc - previous_retirements - - # Handle mid-life periods + # EOL so capacity ends on zero + cap_end = 0 else: - lsc_next = value(M.LifetimeSurvivalCurve[r, M.time_future.next(p), t, v]) - - early_retirement = 0 - if t in M.tech_retirement: - early_retirement = M.V_RetiredCapacity[r, p, t, v] - - # Anything that does not survive this period plus early retirement in this period - retired = built_capacity * (lsc - lsc_next) + early_retirement + # Mid-life period, ending capacity is beginning capacity of next period + p_next = M.time_future.next(p) + + if p == M.time_optimize.last() or p_next == v + value(M.LifetimeProcess[r, t, v]): + # No V_Capacity or V_RetiredCapacity for next period so just continue down the survival curve + cap_end = ( + cap_begin + * value(M.LifetimeSurvivalCurve[r, p_next, t, v]) + / value(M.LifetimeSurvivalCurve[r, p, t, v]) + ) + else: + # Get the next period's beginning capacity + cap_end = ( + M.V_Capacity[r, p_next, t, v] + * value(M.LifetimeSurvivalCurve[r, p_next, t, v]) + / value(M.ProcessLifeFrac[r, p_next, t, v]) + ) - annualised_retirement = retired / M.PeriodLength[p] + annualised_retirement = (cap_begin - cap_end) / M.PeriodLength[p] return M.V_AnnualRetirement[r, p, t, v] == annualised_retirement @@ -495,7 +520,7 @@ def TotalCost_rule(M): && \text{(annual retirement/end of life emission cost)} \\ \end{aligned} - Each of these costs are then discounted within each period then to the base year: + Each of these costs are then discounted within each period and then to the base year: .. math:: :label: obj_fixed_variable_emission @@ -3538,41 +3563,31 @@ def ParamPeriodLength(M: 'TemoaModel', p): def ParamProcessLifeFraction_rule(M: 'TemoaModel', r, p, t, v): r""" + Get the effective capacity of a process :math:`` in a period :math:`p`. - Calculate the fraction of period p that process :math:`` operates. - - For most processes and periods, this will likely be one, but for any process - that will cease operation (rust out, be decommissioned, etc.) between periods, - calculate the fraction of the period that the technology is able to - create useful output. + Accounts for mid-period end of life or average survival over the period + for processes using survival curves. """ - if M.isSurvivalCurveProcess[r, t, v]: - # survival curves handle this problem separately, by averaging survival - # over the period - return 1 - eol_year = v + value(M.LifetimeProcess[r, t, v]) - frac = eol_year - p period_length = value(M.PeriodLength[p]) - if frac >= period_length: + + if M.isSurvivalCurveProcess[r, t, v]: + # Sum survival fraction over the period + years_remaining = sum( + value(M.LifetimeSurvivalCurve[r, _p, t, v]) for _p in range(p, p + period_length, 1) + ) + else: + # Remaining life years within the EOL period + years_remaining = v + value(M.LifetimeProcess[r, t, v]) - p + + if years_remaining >= period_length: # try to avoid floating point round-off errors for the common case. return 1 - # number of years into final period loan is complete - - frac /= float(period_length) + frac = years_remaining / float(period_length) return frac -def PeriodSurvivalCurve_rule(M: 'TemoaModel', r, p, t, v): - """Get the average fraction of the survival curve in period p""" - if not M.isSurvivalCurveProcess[r, t, v]: - return 1 - LSC = M.LifetimeSurvivalCurve - PL = value(M.PeriodLength[p]) - return sum(value(LSC[r, _p, t, v]) for _p in range(p, p + PL, 1)) / PL - - # devnote: made redundant by time-value equations for objective function # def loan_annualization_rate(loan_rate: float | None, loan_life: int | float) -> float: # """ From 7467ca14e48977bcb237b6f1a7b07f839aaa3f50 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 2 Jul 2025 15:27:51 -0400 Subject: [PATCH 174/587] Rename sequential_days to consecutive_days for accuracy --- data_files/my_configs/config_sample.toml | 2 +- data_files/my_configs/mga_utopia.toml | 2 +- data_files/my_configs/monte_carlo_utopia.toml | 2 +- data_files/my_configs/morris_utopia.toml | 2 +- data_files/my_configs/stepped_demand.toml | 2 +- temoa/temoa_model/hybrid_loader.py | 2 +- temoa/temoa_model/temoa_initialize.py | 14 +++++++------- temoa/temoa_model/temoa_rules.py | 4 ++-- tests/testing_configs/config_emissions.toml | 2 +- tests/testing_configs/config_link_test.toml | 2 +- tests/testing_configs/config_materials.toml | 2 +- tests/testing_configs/config_mediumville.toml | 2 +- tests/testing_configs/config_seasonal_storage.toml | 2 +- tests/testing_configs/config_storageville.toml | 2 +- tests/testing_configs/config_survival_curve.toml | 2 +- tests/testing_configs/config_test_system.toml | 2 +- tests/testing_configs/config_utopia.toml | 2 +- tests/testing_configs/config_utopia_myopic.toml | 2 +- 18 files changed, 25 insertions(+), 25 deletions(-) diff --git a/data_files/my_configs/config_sample.toml b/data_files/my_configs/config_sample.toml index 572e43104..204e09857 100644 --- a/data_files/my_configs/config_sample.toml +++ b/data_files/my_configs/config_sample.toml @@ -84,7 +84,7 @@ save_lp_file = false # What seasons represent in the model # Options: -# 'sequential_days' +# 'consecutive_days' # Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. # Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. diff --git a/data_files/my_configs/mga_utopia.toml b/data_files/my_configs/mga_utopia.toml index 5508f0007..255c2febf 100644 --- a/data_files/my_configs/mga_utopia.toml +++ b/data_files/my_configs/mga_utopia.toml @@ -78,7 +78,7 @@ save_lp_file = false # What seasons represent in the model # Options: -# 'sequential_days' +# 'consecutive_days' # Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. # Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. diff --git a/data_files/my_configs/monte_carlo_utopia.toml b/data_files/my_configs/monte_carlo_utopia.toml index 69144713f..7394fb291 100644 --- a/data_files/my_configs/monte_carlo_utopia.toml +++ b/data_files/my_configs/monte_carlo_utopia.toml @@ -81,7 +81,7 @@ save_lp_file = false # What seasons represent in the model # Options: -# 'sequential_days' +# 'consecutive_days' # Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. # Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. diff --git a/data_files/my_configs/morris_utopia.toml b/data_files/my_configs/morris_utopia.toml index 820caa1ed..f9a722bcd 100644 --- a/data_files/my_configs/morris_utopia.toml +++ b/data_files/my_configs/morris_utopia.toml @@ -78,7 +78,7 @@ save_lp_file = false # What seasons represent in the model # Options: -# 'sequential_days' +# 'consecutive_days' # Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. # Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. diff --git a/data_files/my_configs/stepped_demand.toml b/data_files/my_configs/stepped_demand.toml index 85136ee6b..6df63a370 100644 --- a/data_files/my_configs/stepped_demand.toml +++ b/data_files/my_configs/stepped_demand.toml @@ -78,7 +78,7 @@ save_lp_file = false # What seasons represent in the model # Options: -# 'sequential_days' +# 'consecutive_days' # Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. # Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 484e311b5..35fee7d5d 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -396,7 +396,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # TimeSequencing time_sequencing = self.config.time_sequencing match time_sequencing: - case 'seasonal_timeslices' | 'representative_periods' | 'sequential_days': + case 'seasonal_timeslices' | 'representative_periods' | 'consecutive_days': pass case 'manual': # This is a hidden feature allowing the user to manually specify the sequence of states using the TimeNext table diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 4f6a391f7..7fa588945 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1096,8 +1096,8 @@ def CreateTimeSequence(M: 'TemoaModel'): # Establishing sequence of states match M.TimeSequencing.first(): - case 'sequential_days': - msg = 'Running a sequential days database.' + case 'consecutive_days': + msg = 'Running a consecutive days database.' for p in M.time_optimize: for s, d in M.TimeSeason[p] * M.time_of_day: M.time_next[p, s, d] = loop_period_next_timeslice(M, p, s, d) @@ -1156,7 +1156,7 @@ def CreateTimeSeasonSequential(M: 'TemoaModel'): return if not M.TimeSeasonSequential: - if M.TimeSequencing.first() in ('sequential_days', 'seasonal_timeslices'): + if M.TimeSequencing.first() in ('consecutive_days', 'seasonal_timeslices'): logger.info( 'No data in TimeSeasonSequential. By default, assuming sequential seasons ' 'match TimeSeason and TimeSegmentFraction.' @@ -1181,9 +1181,9 @@ def CreateTimeSeasonSequential(M: 'TemoaModel'): sequential = dict() for p, s_seq, s in M.TimeSeasonSequential: num_days = value(M.TimeSeasonSequential[p, s_seq, s]) - if M.TimeSequencing.first() == 'sequential_days' and abs(num_days - 1.0) >= 0.01: + if M.TimeSequencing.first() == 'consecutive_days' and abs(num_days - 1.0) >= 0.01: msg = ( - 'TimeSequencing set to sequential_days but a season in the TimeSegmentFraction table does not ' + 'TimeSequencing set to consecutive_days but a season in the TimeSegmentFraction table does not ' f'represent exactly one day. This would lead to bad model behaviour: {p, s}, days: {num_days}. ' 'Check the config file.' ) @@ -1751,7 +1751,7 @@ def RampDownDayConstraintIndices(M: 'TemoaModel'): def RampUpSeasonConstraintIndices(M: 'TemoaModel'): - if M.TimeSequencing.first() == 'sequential_days': + if M.TimeSequencing.first() == 'consecutive_days': return Set.Skip # dont need this constraint # s, s_next indexing ensures we dont build redundant constraints @@ -1770,7 +1770,7 @@ def RampUpSeasonConstraintIndices(M: 'TemoaModel'): def RampDownSeasonConstraintIndices(M: 'TemoaModel'): - if M.TimeSequencing.first() == 'sequential_days': + if M.TimeSequencing.first() == 'consecutive_days': return Set.Skip # dont need this constraint # s, s_next indexing ensures we dont build redundant constraints diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 13e79972b..263e72095 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1538,7 +1538,7 @@ def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): - \sum\limits_{I,O} \mathbf{FO}_{r,p,s,d,i,t,v,o} = {SL}_{r,p,s_{{next}},d_{{next}},t,v} - Note that for all seasonal representations except sequential days, the last time slice + Note that for all seasonal representations except consecutive_days, the last time slice of each season will loop back to the first time slice of the same season, preventing seasonal deltas for non-seasonal storage (see SeasonalStorageEnergyUpperBound). """ @@ -1946,7 +1946,7 @@ def RampUpDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): One of two constraints built from the RampUpHourly table, along with the RampUpSeason_Constraint. RampUpDay constrains ramp rates between time slices within each season and RampUpSeason constrains ramp rates between sequential - seasons. If the :code:`time_sequencing` parameter is set to :code:`sequential_days` + seasons. If the :code:`time_sequencing` parameter is set to :code:`consecutive_days` then the RampUpSeason constraint is skipped as seasons already connect together. The ramp rate constraint is utilized to limit the rate of electricity generation diff --git a/tests/testing_configs/config_emissions.toml b/tests/testing_configs/config_emissions.toml index 050c2ca67..368abd3f1 100644 --- a/tests/testing_configs/config_emissions.toml +++ b/tests/testing_configs/config_emissions.toml @@ -25,7 +25,7 @@ save_lp_file = false # What seasons represent in the model # Options: -# 'sequential_days' +# 'consecutive_days' # Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. # Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. diff --git a/tests/testing_configs/config_link_test.toml b/tests/testing_configs/config_link_test.toml index ee370ac60..a93fb6d88 100644 --- a/tests/testing_configs/config_link_test.toml +++ b/tests/testing_configs/config_link_test.toml @@ -78,7 +78,7 @@ save_lp_file = false # What seasons represent in the model # Options: -# 'sequential_days' +# 'consecutive_days' # Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. # Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. diff --git a/tests/testing_configs/config_materials.toml b/tests/testing_configs/config_materials.toml index 9182010cc..51a038bec 100644 --- a/tests/testing_configs/config_materials.toml +++ b/tests/testing_configs/config_materials.toml @@ -25,7 +25,7 @@ save_lp_file = false # What seasons represent in the model # Options: -# 'sequential_days' +# 'consecutive_days' # Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. # Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. diff --git a/tests/testing_configs/config_mediumville.toml b/tests/testing_configs/config_mediumville.toml index 077472f4c..e2e9a94c9 100644 --- a/tests/testing_configs/config_mediumville.toml +++ b/tests/testing_configs/config_mediumville.toml @@ -59,7 +59,7 @@ save_lp_file = false # What seasons represent in the model # Options: -# 'sequential_days' +# 'consecutive_days' # Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. # Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. diff --git a/tests/testing_configs/config_seasonal_storage.toml b/tests/testing_configs/config_seasonal_storage.toml index c1546cb1a..3ba26b442 100644 --- a/tests/testing_configs/config_seasonal_storage.toml +++ b/tests/testing_configs/config_seasonal_storage.toml @@ -25,7 +25,7 @@ save_lp_file = false # What seasons represent in the model # Options: -# 'sequential_days' +# 'consecutive_days' # Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. # Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. diff --git a/tests/testing_configs/config_storageville.toml b/tests/testing_configs/config_storageville.toml index 964ccf896..93617d301 100644 --- a/tests/testing_configs/config_storageville.toml +++ b/tests/testing_configs/config_storageville.toml @@ -59,7 +59,7 @@ save_lp_file = false # What seasons represent in the model # Options: -# 'sequential_days' +# 'consecutive_days' # Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. # Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. diff --git a/tests/testing_configs/config_survival_curve.toml b/tests/testing_configs/config_survival_curve.toml index 11066e81f..b4e48f2f8 100644 --- a/tests/testing_configs/config_survival_curve.toml +++ b/tests/testing_configs/config_survival_curve.toml @@ -25,7 +25,7 @@ save_lp_file = false # What seasons represent in the model # Options: -# 'sequential_days' +# 'consecutive_days' # Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. # Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. diff --git a/tests/testing_configs/config_test_system.toml b/tests/testing_configs/config_test_system.toml index 12032f9c0..8bd7fa82b 100644 --- a/tests/testing_configs/config_test_system.toml +++ b/tests/testing_configs/config_test_system.toml @@ -25,7 +25,7 @@ save_lp_file = false # What seasons represent in the model # Options: -# 'sequential_days' +# 'consecutive_days' # Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. # Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. diff --git a/tests/testing_configs/config_utopia.toml b/tests/testing_configs/config_utopia.toml index a58535cc7..7cd349d20 100644 --- a/tests/testing_configs/config_utopia.toml +++ b/tests/testing_configs/config_utopia.toml @@ -25,7 +25,7 @@ save_lp_file = false # What seasons represent in the model # Options: -# 'sequential_days' +# 'consecutive_days' # Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. # Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. diff --git a/tests/testing_configs/config_utopia_myopic.toml b/tests/testing_configs/config_utopia_myopic.toml index a50593022..c59b56534 100644 --- a/tests/testing_configs/config_utopia_myopic.toml +++ b/tests/testing_configs/config_utopia_myopic.toml @@ -27,7 +27,7 @@ save_lp_file = false # What seasons represent in the model # Options: -# 'sequential_days' +# 'consecutive_days' # Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. # Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. From 8c3f82cc576f521fca336bdf9c569d48076b8342 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 9 Jul 2025 10:37:26 -0400 Subject: [PATCH 175/587] Fix a bug in CheckCapacityFactorProcess --- temoa/temoa_model/temoa_initialize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 7fa588945..e0be2c8b2 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -377,8 +377,8 @@ def CheckCapacityFactorProcess(M: 'TemoaModel'): # Check if all possible values have been set by process # log a warning if some are missing (allowed but maybe accidental) - num_seg = len(M.TimeSeason[p]) * len(M.time_of_day) for (r, p, t, v), count in count_rptv.items(): + num_seg = len(M.TimeSeason[p]) * len(M.time_of_day) if count > 0: M.isCapacityFactorProcess[r, p, t, v] = True if count < num_seg: From 69d3833337d4c0df7312b399f6cfb3e1f9c265e0 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 15 Jul 2025 16:39:23 -0400 Subject: [PATCH 176/587] Add notes column to PlanningReserveMargin and Ramp tables --- data_files/example_dbs/materials.sql | 5 ++++- data_files/example_dbs/morris_utopia.sql | 7 +++++-- data_files/example_dbs/seasonal_storage.sql | 5 ++++- data_files/example_dbs/stepped_demand.sql | 5 ++++- data_files/example_dbs/survival_curve.sql | 5 ++++- data_files/example_dbs/test_system.sql | 5 ++++- data_files/example_dbs/utopia.sql | 5 ++++- data_files/temoa_schema_v3_1.sql | 5 ++++- tests/testing_data/emissions.sql | 5 ++++- tests/testing_data/materials.sql | 5 ++++- tests/testing_data/mediumville.sql | 15 +++++++++------ tests/testing_data/seasonal_storage.sql | 5 ++++- tests/testing_data/simple_linked_tech.sql | 5 ++++- tests/testing_data/storageville.sql | 5 ++++- tests/testing_data/survival_curve.sql | 5 ++++- tests/testing_data/test_system.sql | 5 ++++- tests/testing_data/utopia.sql | 5 ++++- 17 files changed, 74 insertions(+), 23 deletions(-) diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index 2de7189c4..b0242fd4a 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -1301,7 +1301,8 @@ CREATE TABLE PlanningReserveMargin region TEXT PRIMARY KEY REFERENCES Region (region), - margin REAL + margin REAL, + notes TEXT ); CREATE TABLE RampDownHourly ( @@ -1309,6 +1310,7 @@ CREATE TABLE RampDownHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE RampUpHourly @@ -1317,6 +1319,7 @@ CREATE TABLE RampUpHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE Region diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index 5d09eb949..e9c503a47 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -1302,14 +1302,16 @@ CREATE TABLE PlanningReserveMargin region TEXT PRIMARY KEY REFERENCES Region (region), - margin REAL + margin REAL, + notes TEXT ); -CREATE TABLE RampDown +CREATE TABLE RampDownHourly ( region TEXT, tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE RampUpHourly @@ -1318,6 +1320,7 @@ CREATE TABLE RampUpHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE Region diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql index 644cb9359..370e84415 100644 --- a/data_files/example_dbs/seasonal_storage.sql +++ b/data_files/example_dbs/seasonal_storage.sql @@ -865,7 +865,8 @@ CREATE TABLE PlanningReserveMargin region TEXT PRIMARY KEY REFERENCES Region (region), - margin REAL + margin REAL, + notes TEXT ); CREATE TABLE RampDownHourly ( @@ -873,6 +874,7 @@ CREATE TABLE RampDownHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE RampUpHourly @@ -881,6 +883,7 @@ CREATE TABLE RampUpHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE Region diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index e6689a95a..3f146a143 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -1033,7 +1033,8 @@ CREATE TABLE PlanningReserveMargin region TEXT PRIMARY KEY REFERENCES Region (region), - margin REAL + margin REAL, + notes TEXT ); CREATE TABLE RampDownHourly ( @@ -1041,6 +1042,7 @@ CREATE TABLE RampDownHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE RampUpHourly @@ -1049,6 +1051,7 @@ CREATE TABLE RampUpHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE Region diff --git a/data_files/example_dbs/survival_curve.sql b/data_files/example_dbs/survival_curve.sql index f0ad9eeae..d0b689103 100644 --- a/data_files/example_dbs/survival_curve.sql +++ b/data_files/example_dbs/survival_curve.sql @@ -895,7 +895,8 @@ CREATE TABLE PlanningReserveMargin region TEXT PRIMARY KEY REFERENCES Region (region), - margin REAL + margin REAL, + notes TEXT ); CREATE TABLE RampDownHourly ( @@ -903,6 +904,7 @@ CREATE TABLE RampDownHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE RampUpHourly @@ -911,6 +913,7 @@ CREATE TABLE RampUpHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE Region diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index 52d4d4fc3..8a09f21a5 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -1287,7 +1287,8 @@ CREATE TABLE PlanningReserveMargin region TEXT PRIMARY KEY REFERENCES Region (region), - margin REAL + margin REAL, + notes TEXT ); CREATE TABLE RampDownHourly ( @@ -1295,6 +1296,7 @@ CREATE TABLE RampDownHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE RampUpHourly @@ -1303,6 +1305,7 @@ CREATE TABLE RampUpHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE Region diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 78869facb..a7de4caf0 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -1296,7 +1296,8 @@ CREATE TABLE PlanningReserveMargin region TEXT PRIMARY KEY REFERENCES Region (region), - margin REAL + margin REAL, + notes TEXT ); CREATE TABLE RampDownHourly ( @@ -1304,6 +1305,7 @@ CREATE TABLE RampDownHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE RampUpHourly @@ -1312,6 +1314,7 @@ CREATE TABLE RampUpHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE Region diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index 11ca1e82d..b53b48dfc 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -830,7 +830,8 @@ CREATE TABLE IF NOT EXISTS PlanningReserveMargin region TEXT PRIMARY KEY REFERENCES Region (region), - margin REAL + margin REAL, + notes TEXT ); CREATE TABLE IF NOT EXISTS RampDownHourly ( @@ -838,6 +839,7 @@ CREATE TABLE IF NOT EXISTS RampDownHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE IF NOT EXISTS RampUpHourly @@ -846,6 +848,7 @@ CREATE TABLE IF NOT EXISTS RampUpHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT PRIMARY KEY (region, tech) ); CREATE TABLE IF NOT EXISTS Region diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index cb23bfd75..5ec4decea 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -871,7 +871,8 @@ CREATE TABLE PlanningReserveMargin region TEXT PRIMARY KEY REFERENCES Region (region), - margin REAL + margin REAL, + notes TEXT ); CREATE TABLE RampDownHourly ( @@ -879,6 +880,7 @@ CREATE TABLE RampDownHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE RampUpHourly @@ -887,6 +889,7 @@ CREATE TABLE RampUpHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE Region diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index 2de7189c4..b0242fd4a 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -1301,7 +1301,8 @@ CREATE TABLE PlanningReserveMargin region TEXT PRIMARY KEY REFERENCES Region (region), - margin REAL + margin REAL, + notes TEXT ); CREATE TABLE RampDownHourly ( @@ -1309,6 +1310,7 @@ CREATE TABLE RampDownHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE RampUpHourly @@ -1317,6 +1319,7 @@ CREATE TABLE RampUpHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE Region diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 78f69ff70..6739e0d03 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -958,29 +958,32 @@ CREATE TABLE PlanningReserveMargin region TEXT PRIMARY KEY REFERENCES Region (region), - margin REAL + margin REAL, + notes TEXT ); -INSERT INTO PlanningReserveMargin VALUES('A',0.05000000000000000277); +INSERT INTO PlanningReserveMargin VALUES('A',0.05000000000000000277,NULL); CREATE TABLE RampDownHourly ( region TEXT, tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO RampDownHourly VALUES('A','EH',0.05000000000000000277); -INSERT INTO RampDownHourly VALUES('B','EH',0.05000000000000000277); +INSERT INTO RampDownHourly VALUES('A','EH',0.05000000000000000277,NULL); +INSERT INTO RampDownHourly VALUES('B','EH',0.05000000000000000277,NULL); CREATE TABLE RampUpHourly ( region TEXT, tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO RampUpHourly VALUES('B','EH',0.05000000000000000277); -INSERT INTO RampUpHourly VALUES('A','EH',0.05000000000000000277); +INSERT INTO RampUpHourly VALUES('B','EH',0.05000000000000000277,NULL); +INSERT INTO RampUpHourly VALUES('A','EH',0.05000000000000000277,NULL); CREATE TABLE Region ( region TEXT diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index 644cb9359..370e84415 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -865,7 +865,8 @@ CREATE TABLE PlanningReserveMargin region TEXT PRIMARY KEY REFERENCES Region (region), - margin REAL + margin REAL, + notes TEXT ); CREATE TABLE RampDownHourly ( @@ -873,6 +874,7 @@ CREATE TABLE RampDownHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE RampUpHourly @@ -881,6 +883,7 @@ CREATE TABLE RampUpHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE Region diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index 6beca00a1..fc762787c 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -845,7 +845,8 @@ CREATE TABLE PlanningReserveMargin region TEXT PRIMARY KEY REFERENCES Region (region), - margin REAL + margin REAL, + notes TEXT ); CREATE TABLE RampDownHourly ( @@ -853,6 +854,7 @@ CREATE TABLE RampDownHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE RampUpHourly @@ -861,6 +863,7 @@ CREATE TABLE RampUpHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE Region diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index 18692c467..ae3f2979d 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -857,7 +857,8 @@ CREATE TABLE PlanningReserveMargin region TEXT PRIMARY KEY REFERENCES Region (region), - margin REAL + margin REAL, + notes TEXT ); CREATE TABLE RampDownHourly ( @@ -865,6 +866,7 @@ CREATE TABLE RampDownHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE RampUpHourly @@ -873,6 +875,7 @@ CREATE TABLE RampUpHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE Region diff --git a/tests/testing_data/survival_curve.sql b/tests/testing_data/survival_curve.sql index f0ad9eeae..d0b689103 100644 --- a/tests/testing_data/survival_curve.sql +++ b/tests/testing_data/survival_curve.sql @@ -895,7 +895,8 @@ CREATE TABLE PlanningReserveMargin region TEXT PRIMARY KEY REFERENCES Region (region), - margin REAL + margin REAL, + notes TEXT ); CREATE TABLE RampDownHourly ( @@ -903,6 +904,7 @@ CREATE TABLE RampDownHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE RampUpHourly @@ -911,6 +913,7 @@ CREATE TABLE RampUpHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE Region diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 52d4d4fc3..8a09f21a5 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -1287,7 +1287,8 @@ CREATE TABLE PlanningReserveMargin region TEXT PRIMARY KEY REFERENCES Region (region), - margin REAL + margin REAL, + notes TEXT ); CREATE TABLE RampDownHourly ( @@ -1295,6 +1296,7 @@ CREATE TABLE RampDownHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE RampUpHourly @@ -1303,6 +1305,7 @@ CREATE TABLE RampUpHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE Region diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 78869facb..a7de4caf0 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -1296,7 +1296,8 @@ CREATE TABLE PlanningReserveMargin region TEXT PRIMARY KEY REFERENCES Region (region), - margin REAL + margin REAL, + notes TEXT ); CREATE TABLE RampDownHourly ( @@ -1304,6 +1305,7 @@ CREATE TABLE RampDownHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE RampUpHourly @@ -1312,6 +1314,7 @@ CREATE TABLE RampUpHourly tech TEXT REFERENCES Technology (tech), rate REAL, + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE Region From c36e67037af943388b56b5392e03967594d31c5e Mon Sep 17 00:00:00 2001 From: Anil Radhakrishnan Date: Fri, 18 Jul 2025 15:09:43 -0400 Subject: [PATCH 177/587] uv based dependency management (#7) * re: changing gitignore to reject files by default * feat: uv based dependency management * adding pre-commit based dependency tracking and adding autogenerated requirement files --- .gitignore | 37 +- .pre-commit-config.yaml | 27 + .pre-commit-config.yaml.yml | 17 - environment.yml | 49 - environment_minimal.yml | 49 - pyproject.toml | 90 +- requirements-dev.txt | 671 +++++++ requirements.in | 44 - requirements.txt | 404 ++--- uv.lock | 3307 +++++++++++++++++++++++++++++++++++ 10 files changed, 4293 insertions(+), 402 deletions(-) create mode 100644 .pre-commit-config.yaml delete mode 100644 .pre-commit-config.yaml.yml delete mode 100644 environment.yml delete mode 100644 environment_minimal.yml create mode 100644 requirements-dev.txt delete mode 100644 requirements.in create mode 100644 uv.lock diff --git a/.gitignore b/.gitignore index 0f1c98b36..b0093ecfb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,22 +1,29 @@ -*.pyc -data_files/debug_logs/*.log -data_files/debug_logs/lp_files/* -data_files/untracked_data/* -.DS_Store -*.ipynb_checkpoints +# ignore all root items +/* -# ignore the .idea folder from pycharm -- a pycharm specific config folder -.idea/* +# unignore folders +!temoa/ +!tests/ +!docs/ +!data_files/ +!notebooks/ +!output_files/ +!.github/ -# ignore goings-on in the venv -/venv/* +# unignore files +!.gitignore +!README.md +!pyproject.toml +!uv.lock +!requirements*.txt +!LICENSE.txt +!CHANGELOG.md +!CONTRIBUTING.md +!.pre-commit-config.yaml -# ignore (for now) associated jupyter notebooks -other_notebooks/ -/temoa/temoa_model/config_sample_9R -# ignore cached vscode settings -.vscode +# recursively re-ignore +__pycache__ # ignore built docs docs/_build \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..6eb1cd44b --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,27 @@ +repos: + - repo: https://github.com/astral-sh/uv-pre-commit + # uv version. + rev: 0.7.21 + hooks: + # Dependency management + - id: uv-lock + name: uv-lock (Update uv.lock if pyproject.toml changed) + files: ^pyproject\.toml$ + + # Compile requirements + - id: pip-compile + name: pip-compile requirements.txt (core dependencies) + args: + - pyproject.toml # Input file + - -o # Output flag + - requirements.txt # Output file name + files: ^pyproject\.toml$ + + - id: pip-compile + name: pip-compile requirements-dev.txt (core + all optional dependencies) + args: + - pyproject.toml + - --all-extras # Include all optional dependency groups + - -o + - requirements-dev.txt # Output file name + files: ^pyproject\.toml$ diff --git a/.pre-commit-config.yaml.yml b/.pre-commit-config.yaml.yml deleted file mode 100644 index 63d4fee13..000000000 --- a/.pre-commit-config.yaml.yml +++ /dev/null @@ -1,17 +0,0 @@ -# repos: -# - repo: https://github.com/pre-commit/pre-commit-hooks -# rev: v4.4.0 -# hooks: -# - id: check-yaml -# # - id: end-of-file-fixer -# - id: trailing-whitespace -# - id: check-added-large-files -# args: ['--maxkb=80000'] -# - repo: https://github.com/psf/black -# rev: 23.3.0 -# hooks: -# - id: black -# - repo: https://github.com/PyCQA/isort -# rev: 5.12.0 -# hooks: -# - id: isort diff --git a/environment.yml b/environment.yml deleted file mode 100644 index 2d4c34998..000000000 --- a/environment.yml +++ /dev/null @@ -1,49 +0,0 @@ -# NOTE: This environment is UNTESTED. It is just a couple version updates on the old conda environment -# file. Development has moved forward with pip and the requirements.txt -# file without using conda. Feedback/corrections/pull requests to tighten up this file for conda -# users are welcome. - -name: temoa-py3 -channels: - - defaults - - conda-forge -dependencies: - # Requirements for core model functionality - - python=3.12 - - pyomo=6.7 -# - pyomo.extras - - xlwt - - ipython - - matplotlib - - pandas - - numpy - - scipy - - joblib - - salib - - pydoe - - pyutilib -# - glpk - - python-graphviz - - ipykernel - - jupyter - - jupyter_contrib_nbextensions - - seaborn - - tabulate - - xlsxwriter - - plotly - - pyam - # cbc solver below cannot be installed via Conda on Windows -# - coincbc - - pytest - - deprecated - - openpyxl - - networkx - - gravis - - gurobi - - # Below required to update documentation - - sphinx - - sphinx_rtd_theme - - sphinxcontrib-htmlhelp - - sphinxcontrib-serializinghtml - - sphinxcontrib-bibtex diff --git a/environment_minimal.yml b/environment_minimal.yml deleted file mode 100644 index a6b2c257d..000000000 --- a/environment_minimal.yml +++ /dev/null @@ -1,49 +0,0 @@ -# NOTE: This environment is UNTESTED. It is just a couple version updates on the old conda environment -# file. Development has moved forward with pip and the requirements.txt -# file without using conda. Feedback/corrections/pull requests to tighten up this file for conda -# users are welcome. - -name: temoa_min -channels: - - defaults - - conda-forge -dependencies: - # Requirements for core model functionality - - python=3.12 - - pyomo=6.7 -# - pyomo.extras - - xlwt -# - ipython -# - matplotlib - - pandas - - numpy - - scipy - - joblib - - salib - - pydoe - - pyutilib -# - glpk -# - python-graphviz -# - ipykernel -# - jupyter -# - jupyter_contrib_nbextensions -# - seaborn - - tabulate - - xlsxwriter -# - plotly - - pyam - # cbc solver below cannot be installed via Conda on Windows -# - coincbc - - pytest - - deprecated - - openpyxl - - networkx - - gravis - - gurobi - - # Below required to update documentation -# - sphinx -# - sphinx_rtd_theme -# - sphinxcontrib-htmlhelp -# - sphinxcontrib-serializinghtml -# - sphinxcontrib-bibtex diff --git a/pyproject.toml b/pyproject.toml index 19e473efb..f406b47f8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,96 @@ -[tool.ruff] +[project] +name = "temoa" +version = "3.0.0" +description = "Tools for Energy Model Optimization and Analysis" +readme = "README.md" +requires-python = ">=3.12" +license = { file = "LICENSE.txt" } +authors = [ + { name = "TemoaProject Team", email = "info@temoaproject.org" } +] + +dependencies = [ + "pyomo>=6.8.0", + "ipython", + "matplotlib==3.9.2", + "pandas>=2.2.2", + "numpy>=2.1.0", + "joblib", + "salib>=1.5.1", + "pydoe>=0.3.8", + "pyutilib>=6.0.0", + "graphviz>=0.20.3", + "ipykernel", + "jupyter", + "jupyter_contrib_nbextensions", + "seaborn>=0.13.2", + "tabulate>=0.9.0", + "xlsxwriter>=3.2.0", + "pyam-iamc>=2.2.4", + "pytest>=8.3.2", + "deprecated>=1.2.14", + "openpyxl>=3.1.5", + "networkx>=3.3", + "highspy>=1.7.2", + "scipy>=1.14.1", + "gurobipy>=11.0.3", + "nx-vis-visualizer>=0.1.1", + "gravis>=0.1.0", +] + +[project.optional-dependencies] +docs = [ + "sphinx>=7.4.7", + "sphinx-rtd-theme>=2.0.0", + "sphinxcontrib-htmlhelp>=2.1.0", + "sphinxcontrib-serializinghtml>=2.0.0", + "sphinxcontrib-bibtex>=2.6.2", +] + +dev = [ + "ruff>=0.2.0", + "pre-commit", + "pytest", + "pytest-cov", +] +plotting = [ + "matplotlib>=3.9.2", + "seaborn>=0.13.2", +] +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.ruff] line-length = 100 indent-width = 4 [tool.ruff.format] -# Single quote strings quote-style = "single" +[tool.ruff.lint] +select = [ + "E", # pycodestyle errors + "W", # pycodestyle warnings + "F", # pyflakes + "I", # isort + "B", # flake8-bugbear +] + +[tool.pytest.ini_options] +minversion = "8.0" +addopts = "-ra -q" +testpaths = [ + "tests", +] + +[dependency-groups] +dev = [ + "gurobipy>=12.0.3", +] +[project.urls] +Homepage = "https://temoaproject.org" +Documentation = "https://temoaproject.github.io/temoa" +Repository = "https://github.com/TemoaProject/temoa" diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 000000000..00db4ec30 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,671 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile pyproject.toml --all-extras -o requirements-dev.txt +alabaster==1.0.0 + # via sphinx +alembic==1.16.4 + # via ixmp4 +annotated-types==0.7.0 + # via pydantic +anyio==4.9.0 + # via + # httpx + # jupyter-server + # starlette +argon2-cffi==25.1.0 + # via jupyter-server +argon2-cffi-bindings==21.2.0 + # via argon2-cffi +arrow==1.3.0 + # via isoduration +asttokens==3.0.0 + # via stack-data +async-lru==2.0.5 + # via jupyterlab +attrs==25.3.0 + # via + # jsonschema + # referencing +babel==2.17.0 + # via + # jupyterlab-server + # sphinx +beautifulsoup4==4.13.4 + # via nbconvert +bleach==6.2.0 + # via nbconvert +certifi==2025.7.14 + # via + # httpcore + # httpx + # requests +cffi==1.17.1 + # via argon2-cffi-bindings +cfgv==3.4.0 + # via pre-commit +charset-normalizer==3.4.2 + # via requests +click==8.2.1 + # via typer +comm==0.2.2 + # via + # ipykernel + # ipywidgets +contourpy==1.3.2 + # via matplotlib +coverage==7.9.2 + # via pytest-cov +cycler==0.12.1 + # via matplotlib +debugpy==1.8.15 + # via ipykernel +decorator==5.2.1 + # via ipython +defusedxml==0.7.1 + # via nbconvert +deprecated==1.2.18 + # via temoa (pyproject.toml) +dill==0.4.0 + # via multiprocess +distlib==0.3.9 + # via virtualenv +docutils==0.21.2 + # via + # pybtex-docutils + # sphinx + # sphinx-rtd-theme + # sphinxcontrib-bibtex +et-xmlfile==2.0.0 + # via openpyxl +executing==2.2.0 + # via stack-data +fastapi==0.116.1 + # via ixmp4 +fastjsonschema==2.21.1 + # via nbformat +filelock==3.18.0 + # via virtualenv +flexcache==0.3 + # via pint +flexparser==0.4 + # via pint +fonttools==4.59.0 + # via matplotlib +fqdn==1.5.1 + # via jsonschema +graphviz==0.21 + # via temoa (pyproject.toml) +gravis==0.1.0 + # via temoa (pyproject.toml) +greenlet==3.2.3 + # via sqlalchemy +gurobipy==12.0.3 + # via temoa (pyproject.toml) +h11==0.16.0 + # via httpcore +h2==4.2.0 + # via httpx +highspy==1.11.0 + # via temoa (pyproject.toml) +hpack==4.1.0 + # via h2 +httpcore==1.0.9 + # via httpx +httpx==0.28.1 + # via + # ixmp4 + # jupyterlab +hyperframe==6.1.0 + # via h2 +iam-units==2023.9.12 + # via pyam-iamc +identify==2.6.12 + # via pre-commit +idna==3.10 + # via + # anyio + # httpx + # jsonschema + # requests +imagesize==1.4.1 + # via sphinx +iniconfig==2.1.0 + # via pytest +ipykernel==6.29.5 + # via + # temoa (pyproject.toml) + # jupyter + # jupyter-console + # jupyterlab +ipython==9.4.0 + # via + # temoa (pyproject.toml) + # ipykernel + # ipywidgets + # jupyter-console +ipython-genutils==0.2.0 + # via jupyter-contrib-nbextensions +ipython-pygments-lexers==1.1.1 + # via ipython +ipywidgets==8.1.7 + # via jupyter +isoduration==20.11.0 + # via jsonschema +ixmp4==0.11.1 + # via pyam-iamc +jedi==0.19.2 + # via ipython +jinja2==3.1.6 + # via + # jupyter-server + # jupyterlab + # jupyterlab-server + # nbconvert + # sphinx +joblib==1.5.1 + # via temoa (pyproject.toml) +json5==0.12.0 + # via jupyterlab-server +jsonpointer==3.0.0 + # via jsonschema +jsonschema==4.24.0 + # via + # jupyter-events + # jupyterlab-server + # nbformat +jsonschema-specifications==2025.4.1 + # via jsonschema +jupyter==1.1.1 + # via temoa (pyproject.toml) +jupyter-client==8.6.3 + # via + # ipykernel + # jupyter-console + # jupyter-server + # nbclient +jupyter-console==6.6.3 + # via jupyter +jupyter-contrib-core==0.4.2 + # via + # jupyter-contrib-nbextensions + # jupyter-nbextensions-configurator +jupyter-contrib-nbextensions==0.7.0 + # via temoa (pyproject.toml) +jupyter-core==5.8.1 + # via + # ipykernel + # jupyter-client + # jupyter-console + # jupyter-contrib-core + # jupyter-contrib-nbextensions + # jupyter-nbextensions-configurator + # jupyter-server + # jupyterlab + # nbclient + # nbconvert + # nbformat +jupyter-events==0.12.0 + # via jupyter-server +jupyter-highlight-selected-word==0.2.0 + # via jupyter-contrib-nbextensions +jupyter-lsp==2.2.5 + # via jupyterlab +jupyter-nbextensions-configurator==0.6.4 + # via jupyter-contrib-nbextensions +jupyter-server==2.16.0 + # via + # jupyter-lsp + # jupyter-nbextensions-configurator + # jupyterlab + # jupyterlab-server + # notebook + # notebook-shim +jupyter-server-terminals==0.5.3 + # via jupyter-server +jupyterlab==4.4.4 + # via + # jupyter + # notebook +jupyterlab-pygments==0.3.0 + # via nbconvert +jupyterlab-server==2.27.3 + # via + # jupyterlab + # notebook +jupyterlab-widgets==3.0.15 + # via ipywidgets +kiwisolver==1.4.8 + # via matplotlib +latexcodec==3.0.1 + # via pybtex +lxml==6.0.0 + # via jupyter-contrib-nbextensions +mako==1.3.10 + # via alembic +markdown-it-py==3.0.0 + # via rich +markupsafe==3.0.2 + # via + # jinja2 + # mako + # nbconvert +matplotlib==3.9.2 + # via + # temoa (pyproject.toml) + # pyam-iamc + # salib + # seaborn +matplotlib-inline==0.1.7 + # via + # ipykernel + # ipython +mdurl==0.1.2 + # via markdown-it-py +mistune==3.1.3 + # via nbconvert +multiprocess==0.70.18 + # via salib +mypy==1.17.0 + # via sqlalchemy +mypy-extensions==1.1.0 + # via + # mypy + # typing-inspect +nbclient==0.10.2 + # via nbconvert +nbconvert==7.16.6 + # via + # jupyter + # jupyter-contrib-nbextensions + # jupyter-server +nbformat==5.10.4 + # via + # jupyter-server + # nbclient + # nbconvert +nest-asyncio==1.6.0 + # via ipykernel +networkx==3.5 + # via + # temoa (pyproject.toml) + # nx-vis-visualizer +nodeenv==1.9.1 + # via pre-commit +nose==1.3.7 + # via pyutilib +notebook==7.4.4 + # via + # jupyter + # jupyter-contrib-core + # jupyter-contrib-nbextensions + # jupyter-nbextensions-configurator +notebook-shim==0.2.4 + # via + # jupyterlab + # notebook +numpy==2.3.1 + # via + # temoa (pyproject.toml) + # contourpy + # highspy + # matplotlib + # pandas + # pyam-iamc + # pydoe + # salib + # scipy + # seaborn + # wquantiles +nx-vis-visualizer==0.2.0 + # via temoa (pyproject.toml) +openpyxl==3.1.5 + # via + # temoa (pyproject.toml) + # ixmp4 + # pyam-iamc +overrides==7.7.0 + # via jupyter-server +packaging==25.0 + # via + # ipykernel + # jupyter-events + # jupyter-server + # jupyterlab + # jupyterlab-server + # matplotlib + # nbconvert + # pandera + # pytest + # sphinx +pandas==2.3.1 + # via + # temoa (pyproject.toml) + # ixmp4 + # pyam-iamc + # salib + # seaborn +pandera==0.25.0 + # via ixmp4 +pandocfilters==1.5.1 + # via nbconvert +parso==0.8.4 + # via jedi +pathspec==0.12.1 + # via mypy +pexpect==4.9.0 + # via ipython +pillow==11.3.0 + # via matplotlib +pint==0.24.4 + # via + # iam-units + # pyam-iamc +platformdirs==4.3.8 + # via + # jupyter-core + # pint + # virtualenv +pluggy==1.6.0 + # via + # pytest + # pytest-cov +ply==3.11 + # via pyomo +pre-commit==4.2.0 + # via temoa (pyproject.toml) +prometheus-client==0.22.1 + # via jupyter-server +prompt-toolkit==3.0.51 + # via + # ipython + # jupyter-console +psutil==7.0.0 + # via ipykernel +psycopg==3.2.9 + # via ixmp4 +psycopg-binary==3.2.9 + # via psycopg +ptyprocess==0.7.0 + # via + # pexpect + # terminado +pure-eval==0.2.3 + # via stack-data +pyam-iamc==3.0.0 + # via temoa (pyproject.toml) +pybtex==0.25.1 + # via + # pybtex-docutils + # sphinxcontrib-bibtex +pybtex-docutils==1.0.3 + # via sphinxcontrib-bibtex +pycparser==2.22 + # via cffi +pydantic==2.11.7 + # via + # fastapi + # ixmp4 + # pandera + # pydantic-settings +pydantic-core==2.33.2 + # via pydantic +pydantic-settings==2.10.1 + # via ixmp4 +pydoe==0.3.8 + # via temoa (pyproject.toml) +pygments==2.19.2 + # via + # ipython + # ipython-pygments-lexers + # jupyter-console + # nbconvert + # pytest + # rich + # sphinx +pyjwt==2.10.1 + # via ixmp4 +pyomo==6.9.2 + # via temoa (pyproject.toml) +pyparsing==3.2.3 + # via matplotlib +pytest==8.4.1 + # via + # temoa (pyproject.toml) + # pytest-cov +pytest-cov==6.2.1 + # via temoa (pyproject.toml) +python-dateutil==2.9.0.post0 + # via + # arrow + # jupyter-client + # matplotlib + # pandas +python-dotenv==1.1.1 + # via + # ixmp4 + # pydantic-settings +python-json-logger==3.3.0 + # via jupyter-events +pytz==2025.2 + # via pandas +pyutilib==6.0.0 + # via temoa (pyproject.toml) +pyyaml==6.0.2 + # via + # jupyter-events + # jupyter-nbextensions-configurator + # pre-commit + # pyam-iamc + # pybtex +pyzmq==27.0.0 + # via + # ipykernel + # jupyter-client + # jupyter-console + # jupyter-server +referencing==0.36.2 + # via + # jsonschema + # jsonschema-specifications + # jupyter-events +requests==2.32.4 + # via + # jupyterlab-server + # pyam-iamc + # sphinx +rfc3339-validator==0.1.4 + # via + # jsonschema + # jupyter-events +rfc3986-validator==0.1.1 + # via + # jsonschema + # jupyter-events +rich==14.0.0 + # via + # ixmp4 + # typer +roman-numerals-py==3.1.0 + # via sphinx +rpds-py==0.26.0 + # via + # jsonschema + # referencing +ruff==0.12.3 + # via temoa (pyproject.toml) +salib==1.5.1 + # via temoa (pyproject.toml) +scipy==1.16.0 + # via + # temoa (pyproject.toml) + # pyam-iamc + # pydoe + # salib +seaborn==0.13.2 + # via + # temoa (pyproject.toml) + # pyam-iamc +send2trash==1.8.3 + # via jupyter-server +setuptools==80.9.0 + # via + # gravis + # jupyter-contrib-core + # jupyterlab +shellingham==1.5.4 + # via typer +six==1.17.0 + # via + # python-dateutil + # pyutilib + # rfc3339-validator +sniffio==1.3.1 + # via anyio +snowballstemmer==3.0.1 + # via sphinx +soupsieve==2.7 + # via beautifulsoup4 +sphinx==8.2.3 + # via + # temoa (pyproject.toml) + # sphinx-rtd-theme + # sphinxcontrib-bibtex + # sphinxcontrib-jquery +sphinx-rtd-theme==3.0.2 + # via temoa (pyproject.toml) +sphinxcontrib-applehelp==2.0.0 + # via sphinx +sphinxcontrib-bibtex==2.6.5 + # via temoa (pyproject.toml) +sphinxcontrib-devhelp==2.0.0 + # via sphinx +sphinxcontrib-htmlhelp==2.1.0 + # via + # temoa (pyproject.toml) + # sphinx +sphinxcontrib-jquery==4.1 + # via sphinx-rtd-theme +sphinxcontrib-jsmath==1.0.1 + # via sphinx +sphinxcontrib-qthelp==2.0.0 + # via sphinx +sphinxcontrib-serializinghtml==2.0.0 + # via + # temoa (pyproject.toml) + # sphinx +sqlalchemy==2.0.41 + # via + # alembic + # ixmp4 + # sqlalchemy-continuum + # sqlalchemy-utils +sqlalchemy-continuum==1.4.2 + # via ixmp4 +sqlalchemy-utils==0.41.2 + # via + # ixmp4 + # sqlalchemy-continuum +stack-data==0.6.3 + # via ipython +starlette==0.47.1 + # via fastapi +tabulate==0.9.0 + # via temoa (pyproject.toml) +terminado==0.18.1 + # via + # jupyter-server + # jupyter-server-terminals +tinycss2==1.4.0 + # via bleach +toml==0.10.2 + # via ixmp4 +tornado==6.5.1 + # via + # ipykernel + # jupyter-client + # jupyter-contrib-core + # jupyter-contrib-nbextensions + # jupyter-nbextensions-configurator + # jupyter-server + # jupyterlab + # notebook + # terminado +traitlets==5.14.3 + # via + # comm + # ipykernel + # ipython + # ipywidgets + # jupyter-client + # jupyter-console + # jupyter-contrib-core + # jupyter-contrib-nbextensions + # jupyter-core + # jupyter-events + # jupyter-nbextensions-configurator + # jupyter-server + # jupyterlab + # matplotlib-inline + # nbclient + # nbconvert + # nbformat +typeguard==4.4.4 + # via pandera +typer==0.16.0 + # via ixmp4 +types-python-dateutil==2.9.0.20250708 + # via arrow +typing-extensions==4.14.1 + # via + # alembic + # anyio + # beautifulsoup4 + # fastapi + # flexcache + # flexparser + # mypy + # pandera + # pint + # psycopg + # pydantic + # pydantic-core + # referencing + # sqlalchemy + # starlette + # typeguard + # typer + # typing-inspect + # typing-inspection +typing-inspect==0.9.0 + # via pandera +typing-inspection==0.4.1 + # via + # pydantic + # pydantic-settings +tzdata==2025.2 + # via pandas +uri-template==1.3.0 + # via jsonschema +urllib3==2.5.0 + # via requests +virtualenv==20.31.2 + # via pre-commit +wcwidth==0.2.13 + # via prompt-toolkit +webcolors==24.11.1 + # via jsonschema +webencodings==0.5.1 + # via + # bleach + # tinycss2 +websocket-client==1.8.0 + # via jupyter-server +widgetsnbextension==4.0.14 + # via ipywidgets +wquantiles==0.6 + # via pyam-iamc +wrapt==1.17.2 + # via deprecated +xlsxwriter==3.2.5 + # via + # temoa (pyproject.toml) + # pyam-iamc diff --git a/requirements.in b/requirements.in deleted file mode 100644 index b5e948a6b..000000000 --- a/requirements.in +++ /dev/null @@ -1,44 +0,0 @@ -# Requirements for core model functionality -# python used = 3.12 - -# to use pip to install (in a venv, if desired): -# $: pip install -r requirements.txt - -pyomo -ipython -matplotlib -pandas -numpy -joblib -salib -pydoe -pyutilib - -graphviz -ipykernel -jupyter -jupyter_contrib_nbextensions -seaborn -tabulate -xlsxwriter -plotly -pyam-iamc - -# Below required to update documentation -sphinx -# sphisphinx_rtd_theme <-- not available on PyPi -sphinx-rtd-theme -sphinxcontrib-htmlhelp -sphinxcontrib-serializinghtml -sphinxcontrib-bibtex -# nxcontrib-bibtex <-- not available on pypi - -# new requirements -pytest -Deprecated -openpyxl -networkx -gravis -highspy -scipy -gurobipy diff --git a/requirements.txt b/requirements.txt index bba2cd778..6dcd06c11 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,176 +1,159 @@ -# -# This file is autogenerated by pip-compile with Python 3.12 -# by the following command: -# -# pip-compile -# -alabaster==0.7.16 - # via sphinx -alembic==1.13.2 +# This file was autogenerated by uv via the following command: +# uv pip compile pyproject.toml -o requirements.txt +alembic==1.16.4 # via ixmp4 annotated-types==0.7.0 # via pydantic -anyio==4.4.0 +anyio==4.9.0 # via # httpx # jupyter-server # starlette -appdirs==1.4.4 - # via pint -appnope==0.1.4 - # via ipykernel -argon2-cffi==23.1.0 +argon2-cffi==25.1.0 # via jupyter-server argon2-cffi-bindings==21.2.0 # via argon2-cffi arrow==1.3.0 # via isoduration -asttokens==2.4.1 +asttokens==3.0.0 # via stack-data -async-lru==2.0.4 +async-lru==2.0.5 # via jupyterlab -attrs==24.2.0 +attrs==25.3.0 # via # jsonschema # referencing -babel==2.16.0 - # via - # jupyterlab-server - # sphinx -beautifulsoup4==4.12.3 +babel==2.17.0 + # via jupyterlab-server +beautifulsoup4==4.13.4 # via nbconvert -bleach==6.1.0 +bleach==6.2.0 # via nbconvert -certifi==2024.8.30 +certifi==2025.7.14 # via # httpcore # httpx # requests -cffi==1.17.0 +cffi==1.17.1 # via argon2-cffi-bindings -charset-normalizer==3.3.2 +charset-normalizer==3.4.2 # via requests -click==8.1.7 +click==8.2.1 # via typer comm==0.2.2 # via # ipykernel # ipywidgets -contourpy==1.3.0 +contourpy==1.3.2 # via matplotlib cycler==0.12.1 # via matplotlib -debugpy==1.8.5 +debugpy==1.8.15 # via ipykernel -decorator==5.1.1 +decorator==5.2.1 # via ipython defusedxml==0.7.1 # via nbconvert -deprecated==1.2.14 - # via -r requirements.in -dill==0.3.8 +deprecated==1.2.18 + # via temoa (pyproject.toml) +dill==0.4.0 # via multiprocess -docutils==0.20.1 - # via - # pybtex-docutils - # sphinx - # sphinx-rtd-theme - # sphinxcontrib-bibtex -et-xmlfile==1.1.0 +et-xmlfile==2.0.0 # via openpyxl -executing==2.0.1 +executing==2.2.0 # via stack-data -fastapi==0.112.2 +fastapi==0.116.1 # via ixmp4 -fastjsonschema==2.20.0 +fastjsonschema==2.21.1 # via nbformat flexcache==0.3 # via pint -flexparser==0.3.1 +flexparser==0.4 # via pint -fonttools==4.53.1 +fonttools==4.59.0 # via matplotlib fqdn==1.5.1 # via jsonschema -graphviz==0.20.3 - # via -r requirements.in +graphviz==0.21 + # via temoa (pyproject.toml) gravis==0.1.0 - # via -r requirements.in -gurobipy==11.0.3 - # via -r requirements.in -h11==0.14.0 + # via temoa (pyproject.toml) +greenlet==3.2.3 + # via sqlalchemy +gurobipy==12.0.3 + # via temoa (pyproject.toml) +h11==0.16.0 # via httpcore -h2==4.1.0 +h2==4.2.0 # via httpx -highspy==1.7.2 - # via -r requirements.in -hpack==4.0.0 +highspy==1.11.0 + # via temoa (pyproject.toml) +hpack==4.1.0 # via h2 -httpcore==1.0.5 +httpcore==1.0.9 # via httpx -httpx[http2]==0.27.2 +httpx==0.28.1 # via # ixmp4 # jupyterlab -hyperframe==6.0.1 +hyperframe==6.1.0 # via h2 iam-units==2023.9.12 # via pyam-iamc -idna==3.8 +idna==3.10 # via # anyio # httpx # jsonschema # requests -imagesize==1.4.1 - # via sphinx -iniconfig==2.0.0 +iniconfig==2.1.0 # via pytest ipykernel==6.29.5 # via - # -r requirements.in + # temoa (pyproject.toml) # jupyter # jupyter-console # jupyterlab -ipython==8.26.0 +ipython==9.4.0 # via - # -r requirements.in + # temoa (pyproject.toml) # ipykernel # ipywidgets # jupyter-console ipython-genutils==0.2.0 # via jupyter-contrib-nbextensions -ipywidgets==8.1.5 +ipython-pygments-lexers==1.1.1 + # via ipython +ipywidgets==8.1.7 # via jupyter isoduration==20.11.0 # via jsonschema -ixmp4==0.9.2 +ixmp4==0.11.1 # via pyam-iamc -jedi==0.19.1 +jedi==0.19.2 # via ipython -jinja2==3.1.4 +jinja2==3.1.6 # via # jupyter-server # jupyterlab # jupyterlab-server # nbconvert - # sphinx -joblib==1.4.2 - # via -r requirements.in -json5==0.9.25 +joblib==1.5.1 + # via temoa (pyproject.toml) +json5==0.12.0 # via jupyterlab-server jsonpointer==3.0.0 # via jsonschema -jsonschema[format-nongpl]==4.23.0 +jsonschema==4.24.0 # via # jupyter-events # jupyterlab-server # nbformat -jsonschema-specifications==2023.12.1 +jsonschema-specifications==2025.4.1 # via jsonschema -jupyter==1.1.0 - # via -r requirements.in -jupyter-client==8.6.2 +jupyter==1.1.1 + # via temoa (pyproject.toml) +jupyter-client==8.6.3 # via # ipykernel # jupyter-console @@ -183,8 +166,8 @@ jupyter-contrib-core==0.4.2 # jupyter-contrib-nbextensions # jupyter-nbextensions-configurator jupyter-contrib-nbextensions==0.7.0 - # via -r requirements.in -jupyter-core==5.7.2 + # via temoa (pyproject.toml) +jupyter-core==5.8.1 # via # ipykernel # jupyter-client @@ -197,7 +180,7 @@ jupyter-core==5.7.2 # nbclient # nbconvert # nbformat -jupyter-events==0.10.0 +jupyter-events==0.12.0 # via jupyter-server jupyter-highlight-selected-word==0.2.0 # via jupyter-contrib-nbextensions @@ -205,7 +188,7 @@ jupyter-lsp==2.2.5 # via jupyterlab jupyter-nbextensions-configurator==0.6.4 # via jupyter-contrib-nbextensions -jupyter-server==2.14.2 +jupyter-server==2.16.0 # via # jupyter-lsp # jupyter-nbextensions-configurator @@ -215,7 +198,7 @@ jupyter-server==2.14.2 # notebook-shim jupyter-server-terminals==0.5.3 # via jupyter-server -jupyterlab==4.2.5 +jupyterlab==4.4.4 # via # jupyter # notebook @@ -225,26 +208,24 @@ jupyterlab-server==2.27.3 # via # jupyterlab # notebook -jupyterlab-widgets==3.0.13 +jupyterlab-widgets==3.0.15 # via ipywidgets -kiwisolver==1.4.5 +kiwisolver==1.4.8 # via matplotlib -latexcodec==3.0.0 - # via pybtex -lxml==5.3.0 +lxml==6.0.0 # via jupyter-contrib-nbextensions -mako==1.3.5 +mako==1.3.10 # via alembic markdown-it-py==3.0.0 # via rich -markupsafe==2.1.5 +markupsafe==3.0.2 # via # jinja2 # mako # nbconvert matplotlib==3.9.2 # via - # -r requirements.in + # temoa (pyproject.toml) # pyam-iamc # salib # seaborn @@ -254,21 +235,19 @@ matplotlib-inline==0.1.7 # ipython mdurl==0.1.2 # via markdown-it-py -mistune==3.0.2 +mistune==3.1.3 # via nbconvert -multimethod==1.10 - # via pandera -multiprocess==0.70.16 +multiprocess==0.70.18 # via salib -mypy==1.11.2 +mypy==1.17.0 # via sqlalchemy -mypy-extensions==1.0.0 +mypy-extensions==1.1.0 # via # mypy # typing-inspect -nbclient==0.10.0 +nbclient==0.10.2 # via nbconvert -nbconvert==7.16.4 +nbconvert==7.16.6 # via # jupyter # jupyter-contrib-nbextensions @@ -280,11 +259,13 @@ nbformat==5.10.4 # nbconvert nest-asyncio==1.6.0 # via ipykernel -networkx==3.3 - # via -r requirements.in +networkx==3.5 + # via + # temoa (pyproject.toml) + # nx-vis-visualizer nose==1.3.7 # via pyutilib -notebook==7.2.2 +notebook==7.4.4 # via # jupyter # jupyter-contrib-core @@ -294,80 +275,81 @@ notebook-shim==0.2.4 # via # jupyterlab # notebook -numpy==2.1.0 +numpy==2.3.1 # via - # -r requirements.in + # temoa (pyproject.toml) # contourpy # highspy # matplotlib # pandas - # pandera # pyam-iamc # pydoe # salib # scipy # seaborn # wquantiles +nx-vis-visualizer==0.2.0 + # via temoa (pyproject.toml) openpyxl==3.1.5 # via - # -r requirements.in + # temoa (pyproject.toml) # ixmp4 # pyam-iamc overrides==7.7.0 # via jupyter-server -packaging==24.1 +packaging==25.0 # via # ipykernel + # jupyter-events # jupyter-server # jupyterlab # jupyterlab-server # matplotlib # nbconvert # pandera - # plotly # pytest - # sphinx -pandas==2.2.2 +pandas==2.3.1 # via - # -r requirements.in + # temoa (pyproject.toml) # ixmp4 - # pandera # pyam-iamc # salib # seaborn -pandera==0.20.3 +pandera==0.25.0 # via ixmp4 pandocfilters==1.5.1 # via nbconvert parso==0.8.4 # via jedi +pathspec==0.12.1 + # via mypy pexpect==4.9.0 # via ipython -pillow==10.4.0 +pillow==11.3.0 # via matplotlib -pint==0.24.3 +pint==0.24.4 # via # iam-units # pyam-iamc -platformdirs==4.2.2 - # via jupyter-core -plotly==5.24.0 - # via -r requirements.in -pluggy==1.5.0 +platformdirs==4.3.8 + # via + # jupyter-core + # pint +pluggy==1.6.0 # via pytest ply==3.11 # via pyomo -prometheus-client==0.20.0 +prometheus-client==0.22.1 # via jupyter-server -prompt-toolkit==3.0.47 +prompt-toolkit==3.0.51 # via # ipython # jupyter-console -psutil==6.0.0 +psutil==7.0.0 # via ipykernel -psycopg[binary]==3.2.1 +psycopg==3.2.9 # via ixmp4 -psycopg-binary==3.2.1 +psycopg-binary==3.2.9 # via psycopg ptyprocess==0.7.0 # via @@ -375,81 +357,74 @@ ptyprocess==0.7.0 # terminado pure-eval==0.2.3 # via stack-data -pyam-iamc==2.2.4 - # via -r requirements.in -pybtex==0.24.0 - # via - # pybtex-docutils - # sphinxcontrib-bibtex -pybtex-docutils==1.0.3 - # via sphinxcontrib-bibtex +pyam-iamc==3.0.0 + # via temoa (pyproject.toml) pycparser==2.22 # via cffi -pydantic==2.8.2 +pydantic==2.11.7 # via # fastapi # ixmp4 # pandera # pydantic-settings -pydantic-core==2.20.1 +pydantic-core==2.33.2 # via pydantic -pydantic-settings==2.4.0 +pydantic-settings==2.10.1 # via ixmp4 pydoe==0.3.8 - # via -r requirements.in -pygments==2.18.0 + # via temoa (pyproject.toml) +pygments==2.19.2 # via # ipython + # ipython-pygments-lexers # jupyter-console # nbconvert + # pytest # rich - # sphinx -pyjwt==2.9.0 +pyjwt==2.10.1 # via ixmp4 -pyomo==6.8.0 - # via -r requirements.in -pyparsing==3.1.4 +pyomo==6.9.2 + # via temoa (pyproject.toml) +pyparsing==3.2.3 # via matplotlib -pytest==8.3.2 - # via -r requirements.in +pytest==8.4.1 + # via temoa (pyproject.toml) python-dateutil==2.9.0.post0 # via # arrow # jupyter-client # matplotlib # pandas -python-dotenv==1.0.1 +python-dotenv==1.1.1 # via # ixmp4 # pydantic-settings -python-json-logger==2.0.7 +python-json-logger==3.3.0 # via jupyter-events -pytz==2024.1 +pytz==2025.2 # via pandas pyutilib==6.0.0 - # via -r requirements.in + # via temoa (pyproject.toml) pyyaml==6.0.2 # via # jupyter-events # jupyter-nbextensions-configurator # pyam-iamc - # pybtex -pyzmq==26.2.0 +pyzmq==27.0.0 # via # ipykernel # jupyter-client # jupyter-console # jupyter-server -referencing==0.35.1 +referencing==0.36.2 # via # jsonschema # jsonschema-specifications # jupyter-events -requests==2.32.3 +requests==2.32.4 # via # jupyterlab-server # pyam-iamc - # sphinx rfc3339-validator==0.1.4 # via # jsonschema @@ -458,99 +433,71 @@ rfc3986-validator==0.1.1 # via # jsonschema # jupyter-events -rich==13.8.0 +rich==14.0.0 # via # ixmp4 # typer -rpds-py==0.20.0 +rpds-py==0.26.0 # via # jsonschema # referencing salib==1.5.1 - # via -r requirements.in -scipy==1.14.1 + # via temoa (pyproject.toml) +scipy==1.16.0 # via - # -r requirements.in + # temoa (pyproject.toml) # pyam-iamc # pydoe # salib seaborn==0.13.2 # via - # -r requirements.in + # temoa (pyproject.toml) # pyam-iamc send2trash==1.8.3 # via jupyter-server +setuptools==80.9.0 + # via + # gravis + # jupyter-contrib-core + # jupyterlab shellingham==1.5.4 # via typer -six==1.16.0 +six==1.17.0 # via - # asttokens - # bleach - # pybtex # python-dateutil # pyutilib # rfc3339-validator sniffio==1.3.1 - # via - # anyio - # httpx -snowballstemmer==2.2.0 - # via sphinx -soupsieve==2.6 + # via anyio +soupsieve==2.7 # via beautifulsoup4 -sphinx==7.4.7 - # via - # -r requirements.in - # sphinx-rtd-theme - # sphinxcontrib-bibtex - # sphinxcontrib-jquery -sphinx-rtd-theme==2.0.0 - # via -r requirements.in -sphinxcontrib-applehelp==2.0.0 - # via sphinx -sphinxcontrib-bibtex==2.6.2 - # via -r requirements.in -sphinxcontrib-devhelp==2.0.0 - # via sphinx -sphinxcontrib-htmlhelp==2.1.0 - # via - # -r requirements.in - # sphinx -sphinxcontrib-jquery==4.1 - # via sphinx-rtd-theme -sphinxcontrib-jsmath==1.0.1 - # via sphinx -sphinxcontrib-qthelp==2.0.0 - # via sphinx -sphinxcontrib-serializinghtml==2.0.0 - # via - # -r requirements.in - # sphinx -sqlalchemy[mypy]==2.0.32 +sqlalchemy==2.0.41 # via # alembic # ixmp4 - # sqlalchemy + # sqlalchemy-continuum # sqlalchemy-utils -sqlalchemy-utils==0.41.2 +sqlalchemy-continuum==1.4.2 # via ixmp4 +sqlalchemy-utils==0.41.2 + # via + # ixmp4 + # sqlalchemy-continuum stack-data==0.6.3 # via ipython -starlette==0.38.2 +starlette==0.47.1 # via fastapi tabulate==0.9.0 - # via -r requirements.in -tenacity==9.0.0 - # via plotly + # via temoa (pyproject.toml) terminado==0.18.1 # via # jupyter-server # jupyter-server-terminals -tinycss2==1.3.0 - # via nbconvert +tinycss2==1.4.0 + # via bleach toml==0.10.2 # via ixmp4 -tornado==6.4.1 +tornado==6.5.1 # via # ipykernel # jupyter-client @@ -580,38 +527,48 @@ traitlets==5.14.3 # nbclient # nbconvert # nbformat -typeguard==4.3.0 +typeguard==4.4.4 # via pandera -typer==0.12.5 +typer==0.16.0 # via ixmp4 -types-python-dateutil==2.9.0.20240821 +types-python-dateutil==2.9.0.20250708 # via arrow -typing-extensions==4.12.2 +typing-extensions==4.14.1 # via # alembic + # anyio + # beautifulsoup4 # fastapi # flexcache # flexparser # mypy + # pandera # pint # psycopg # pydantic # pydantic-core + # referencing # sqlalchemy + # starlette # typeguard # typer # typing-inspect + # typing-inspection typing-inspect==0.9.0 # via pandera -tzdata==2024.1 +typing-inspection==0.4.1 + # via + # pydantic + # pydantic-settings +tzdata==2025.2 # via pandas uri-template==1.3.0 # via jsonschema -urllib3==2.2.2 +urllib3==2.5.0 # via requests wcwidth==0.2.13 # via prompt-toolkit -webcolors==24.8.0 +webcolors==24.11.1 # via jsonschema webencodings==0.5.1 # via @@ -619,18 +576,13 @@ webencodings==0.5.1 # tinycss2 websocket-client==1.8.0 # via jupyter-server -widgetsnbextension==4.0.13 +widgetsnbextension==4.0.14 # via ipywidgets wquantiles==0.6 # via pyam-iamc -wrapt==1.16.0 - # via - # deprecated - # pandera -xlsxwriter==3.2.0 +wrapt==1.17.2 + # via deprecated +xlsxwriter==3.2.5 # via - # -r requirements.in + # temoa (pyproject.toml) # pyam-iamc - -# The following packages are considered to be unsafe in a requirements file: -# setuptools diff --git a/uv.lock b/uv.lock new file mode 100644 index 000000000..b9b838f28 --- /dev/null +++ b/uv.lock @@ -0,0 +1,3307 @@ +version = 1 +revision = 2 +requires-python = ">=3.12" + +[[package]] +name = "alabaster" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210, upload-time = "2024-07-26T18:15:03.762Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929, upload-time = "2024-07-26T18:15:02.05Z" }, +] + +[[package]] +name = "alembic" +version = "1.16.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mako" }, + { name = "sqlalchemy" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/83/52/72e791b75c6b1efa803e491f7cbab78e963695e76d4ada05385252927e76/alembic-1.16.4.tar.gz", hash = "sha256:efab6ada0dd0fae2c92060800e0bf5c1dc26af15a10e02fb4babff164b4725e2", size = 1968161, upload-time = "2025-07-10T16:17:20.192Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/62/96b5217b742805236614f05904541000f55422a6060a90d7fd4ce26c172d/alembic-1.16.4-py3-none-any.whl", hash = "sha256:b05e51e8e82efc1abd14ba2af6392897e145930c3e0a2faf2b0da2f7f7fd660d", size = 247026, upload-time = "2025-07-10T16:17:21.845Z" }, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "anyio" +version = "4.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "sniffio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949, upload-time = "2025-03-17T00:02:54.77Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916, upload-time = "2025-03-17T00:02:52.713Z" }, +] + +[[package]] +name = "appnope" +version = "0.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170, upload-time = "2024-02-06T09:43:11.258Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321, upload-time = "2024-02-06T09:43:09.663Z" }, +] + +[[package]] +name = "argon2-cffi" +version = "25.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "argon2-cffi-bindings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706, upload-time = "2025-06-03T06:55:32.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741", size = 14657, upload-time = "2025-06-03T06:55:30.804Z" }, +] + +[[package]] +name = "argon2-cffi-bindings" +version = "21.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/e9/184b8ccce6683b0aa2fbb7ba5683ea4b9c5763f1356347f1312c32e3c66e/argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3", size = 1779911, upload-time = "2021-12-01T08:52:55.68Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d4/13/838ce2620025e9666aa8f686431f67a29052241692a3dd1ae9d3692a89d3/argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367", size = 29658, upload-time = "2021-12-01T09:09:17.016Z" }, + { url = "https://files.pythonhosted.org/packages/b3/02/f7f7bb6b6af6031edb11037639c697b912e1dea2db94d436e681aea2f495/argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d", size = 80583, upload-time = "2021-12-01T09:09:19.546Z" }, + { url = "https://files.pythonhosted.org/packages/ec/f7/378254e6dd7ae6f31fe40c8649eea7d4832a42243acaf0f1fff9083b2bed/argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae", size = 86168, upload-time = "2021-12-01T09:09:21.445Z" }, + { url = "https://files.pythonhosted.org/packages/74/f6/4a34a37a98311ed73bb80efe422fed95f2ac25a4cacc5ae1d7ae6a144505/argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c", size = 82709, upload-time = "2021-12-01T09:09:18.182Z" }, + { url = "https://files.pythonhosted.org/packages/74/2b/73d767bfdaab25484f7e7901379d5f8793cccbb86c6e0cbc4c1b96f63896/argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86", size = 83613, upload-time = "2021-12-01T09:09:22.741Z" }, + { url = "https://files.pythonhosted.org/packages/4f/fd/37f86deef67ff57c76f137a67181949c2d408077e2e3dd70c6c42912c9bf/argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f", size = 84583, upload-time = "2021-12-01T09:09:24.177Z" }, + { url = "https://files.pythonhosted.org/packages/6f/52/5a60085a3dae8fded8327a4f564223029f5f54b0cb0455a31131b5363a01/argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e", size = 88475, upload-time = "2021-12-01T09:09:26.673Z" }, + { url = "https://files.pythonhosted.org/packages/8b/95/143cd64feb24a15fa4b189a3e1e7efbaeeb00f39a51e99b26fc62fbacabd/argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082", size = 27698, upload-time = "2021-12-01T09:09:27.87Z" }, + { url = "https://files.pythonhosted.org/packages/37/2c/e34e47c7dee97ba6f01a6203e0383e15b60fb85d78ac9a15cd066f6fe28b/argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f", size = 30817, upload-time = "2021-12-01T09:09:30.267Z" }, + { url = "https://files.pythonhosted.org/packages/5a/e4/bf8034d25edaa495da3c8a3405627d2e35758e44ff6eaa7948092646fdcc/argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93", size = 53104, upload-time = "2021-12-01T09:09:31.335Z" }, +] + +[[package]] +name = "arrow" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, + { name = "types-python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2e/00/0f6e8fcdb23ea632c866620cc872729ff43ed91d284c866b515c6342b173/arrow-1.3.0.tar.gz", hash = "sha256:d4540617648cb5f895730f1ad8c82a65f2dad0166f57b75f3ca54759c4d67a85", size = 131960, upload-time = "2023-09-30T22:11:18.25Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/ed/e97229a566617f2ae958a6b13e7cc0f585470eac730a73e9e82c32a3cdd2/arrow-1.3.0-py3-none-any.whl", hash = "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80", size = 66419, upload-time = "2023-09-30T22:11:16.072Z" }, +] + +[[package]] +name = "asttokens" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4a/e7/82da0a03e7ba5141f05cce0d302e6eed121ae055e0456ca228bf693984bc/asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", size = 61978, upload-time = "2024-11-30T04:30:14.439Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918, upload-time = "2024-11-30T04:30:10.946Z" }, +] + +[[package]] +name = "async-lru" +version = "2.0.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/4d/71ec4d3939dc755264f680f6c2b4906423a304c3d18e96853f0a595dfe97/async_lru-2.0.5.tar.gz", hash = "sha256:481d52ccdd27275f42c43a928b4a50c3bfb2d67af4e78b170e3e0bb39c66e5bb", size = 10380, upload-time = "2025-03-16T17:25:36.919Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/03/49/d10027df9fce941cb8184e78a02857af36360d33e1721df81c5ed2179a1a/async_lru-2.0.5-py3-none-any.whl", hash = "sha256:ab95404d8d2605310d345932697371a5f40def0487c03d6d0ad9138de52c9943", size = 6069, upload-time = "2025-03-16T17:25:35.422Z" }, +] + +[[package]] +name = "attrs" +version = "25.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, +] + +[[package]] +name = "babel" +version = "2.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, +] + +[[package]] +name = "beautifulsoup4" +version = "4.13.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d8/e4/0c4c39e18fd76d6a628d4dd8da40543d136ce2d1752bd6eeeab0791f4d6b/beautifulsoup4-4.13.4.tar.gz", hash = "sha256:dbb3c4e1ceae6aefebdaf2423247260cd062430a410e38c66f2baa50a8437195", size = 621067, upload-time = "2025-04-15T17:05:13.836Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/50/cd/30110dc0ffcf3b131156077b90e9f60ed75711223f306da4db08eff8403b/beautifulsoup4-4.13.4-py3-none-any.whl", hash = "sha256:9bbbb14bfde9d79f38b8cd5f8c7c85f4b8f2523190ebed90e950a8dea4cb1c4b", size = 187285, upload-time = "2025-04-15T17:05:12.221Z" }, +] + +[[package]] +name = "bleach" +version = "6.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "webencodings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/76/9a/0e33f5054c54d349ea62c277191c020c2d6ef1d65ab2cb1993f91ec846d1/bleach-6.2.0.tar.gz", hash = "sha256:123e894118b8a599fd80d3ec1a6d4cc7ce4e5882b1317a7e1ba69b56e95f991f", size = 203083, upload-time = "2024-10-29T18:30:40.477Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/55/96142937f66150805c25c4d0f31ee4132fd33497753400734f9dfdcbdc66/bleach-6.2.0-py3-none-any.whl", hash = "sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e", size = 163406, upload-time = "2024-10-29T18:30:38.186Z" }, +] + +[package.optional-dependencies] +css = [ + { name = "tinycss2" }, +] + +[[package]] +name = "certifi" +version = "2025.7.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/76/52c535bcebe74590f296d6c77c86dabf761c41980e1347a2422e4aa2ae41/certifi-2025.7.14.tar.gz", hash = "sha256:8ea99dbdfaaf2ba2f9bac77b9249ef62ec5218e7c2b2e903378ed5fccf765995", size = 163981, upload-time = "2025-07-14T03:29:28.449Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4f/52/34c6cf5bb9285074dc3531c437b3919e825d976fde097a7a73f79e726d03/certifi-2025.7.14-py3-none-any.whl", hash = "sha256:6b31f564a415d79ee77df69d757bb49a5bb53bd9f756cbbe24394ffd6fc1f4b2", size = 162722, upload-time = "2025-07-14T03:29:26.863Z" }, +] + +[[package]] +name = "cffi" +version = "1.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621, upload-time = "2024-09-04T20:45:21.852Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178, upload-time = "2024-09-04T20:44:12.232Z" }, + { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840, upload-time = "2024-09-04T20:44:13.739Z" }, + { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803, upload-time = "2024-09-04T20:44:15.231Z" }, + { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850, upload-time = "2024-09-04T20:44:17.188Z" }, + { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729, upload-time = "2024-09-04T20:44:18.688Z" }, + { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256, upload-time = "2024-09-04T20:44:20.248Z" }, + { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424, upload-time = "2024-09-04T20:44:21.673Z" }, + { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568, upload-time = "2024-09-04T20:44:23.245Z" }, + { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736, upload-time = "2024-09-04T20:44:24.757Z" }, + { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448, upload-time = "2024-09-04T20:44:26.208Z" }, + { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976, upload-time = "2024-09-04T20:44:27.578Z" }, + { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989, upload-time = "2024-09-04T20:44:28.956Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802, upload-time = "2024-09-04T20:44:30.289Z" }, + { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792, upload-time = "2024-09-04T20:44:32.01Z" }, + { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893, upload-time = "2024-09-04T20:44:33.606Z" }, + { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810, upload-time = "2024-09-04T20:44:35.191Z" }, + { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200, upload-time = "2024-09-04T20:44:36.743Z" }, + { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447, upload-time = "2024-09-04T20:44:38.492Z" }, + { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358, upload-time = "2024-09-04T20:44:40.046Z" }, + { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469, upload-time = "2024-09-04T20:44:41.616Z" }, + { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475, upload-time = "2024-09-04T20:44:43.733Z" }, + { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009, upload-time = "2024-09-04T20:44:45.309Z" }, +] + +[[package]] +name = "cfgv" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114, upload-time = "2023-08-12T20:38:17.776Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249, upload-time = "2023-08-12T20:38:16.269Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload-time = "2025-05-02T08:32:33.712Z" }, + { url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload-time = "2025-05-02T08:32:35.768Z" }, + { url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload-time = "2025-05-02T08:32:37.284Z" }, + { url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload-time = "2025-05-02T08:32:38.803Z" }, + { url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload-time = "2025-05-02T08:32:40.251Z" }, + { url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload-time = "2025-05-02T08:32:41.705Z" }, + { url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload-time = "2025-05-02T08:32:43.709Z" }, + { url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload-time = "2025-05-02T08:32:46.197Z" }, + { url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload-time = "2025-05-02T08:32:48.105Z" }, + { url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload-time = "2025-05-02T08:32:49.719Z" }, + { url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload-time = "2025-05-02T08:32:51.404Z" }, + { url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload-time = "2025-05-02T08:32:53.079Z" }, + { url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload-time = "2025-05-02T08:32:54.573Z" }, + { url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload-time = "2025-05-02T08:32:56.363Z" }, + { url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload-time = "2025-05-02T08:32:58.551Z" }, + { url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload-time = "2025-05-02T08:33:00.342Z" }, + { url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload-time = "2025-05-02T08:33:02.081Z" }, + { url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload-time = "2025-05-02T08:33:04.063Z" }, + { url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload-time = "2025-05-02T08:33:06.418Z" }, + { url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload-time = "2025-05-02T08:33:08.183Z" }, + { url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload-time = "2025-05-02T08:33:09.986Z" }, + { url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload-time = "2025-05-02T08:33:11.814Z" }, + { url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload-time = "2025-05-02T08:33:13.707Z" }, + { url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload-time = "2025-05-02T08:33:15.458Z" }, + { url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload-time = "2025-05-02T08:33:17.06Z" }, + { url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload-time = "2025-05-02T08:33:18.753Z" }, + { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, +] + +[[package]] +name = "click" +version = "8.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "comm" +version = "0.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/a8/fb783cb0abe2b5fded9f55e5703015cdf1c9c85b3669087c538dd15a6a86/comm-0.2.2.tar.gz", hash = "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e", size = 6210, upload-time = "2024-03-12T16:53:41.133Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/75/49e5bfe642f71f272236b5b2d2691cf915a7283cc0ceda56357b61daa538/comm-0.2.2-py3-none-any.whl", hash = "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3", size = 7180, upload-time = "2024-03-12T16:53:39.226Z" }, +] + +[[package]] +name = "contourpy" +version = "1.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130, upload-time = "2025-04-15T17:47:53.79Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/f7/44785876384eff370c251d58fd65f6ad7f39adce4a093c934d4a67a7c6b6/contourpy-1.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4caf2bcd2969402bf77edc4cb6034c7dd7c0803213b3523f111eb7460a51b8d2", size = 271580, upload-time = "2025-04-15T17:37:03.105Z" }, + { url = "https://files.pythonhosted.org/packages/93/3b/0004767622a9826ea3d95f0e9d98cd8729015768075d61f9fea8eeca42a8/contourpy-1.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:82199cb78276249796419fe36b7386bd8d2cc3f28b3bc19fe2454fe2e26c4c15", size = 255530, upload-time = "2025-04-15T17:37:07.026Z" }, + { url = "https://files.pythonhosted.org/packages/e7/bb/7bd49e1f4fa805772d9fd130e0d375554ebc771ed7172f48dfcd4ca61549/contourpy-1.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:106fab697af11456fcba3e352ad50effe493a90f893fca6c2ca5c033820cea92", size = 307688, upload-time = "2025-04-15T17:37:11.481Z" }, + { url = "https://files.pythonhosted.org/packages/fc/97/e1d5dbbfa170725ef78357a9a0edc996b09ae4af170927ba8ce977e60a5f/contourpy-1.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d14f12932a8d620e307f715857107b1d1845cc44fdb5da2bc8e850f5ceba9f87", size = 347331, upload-time = "2025-04-15T17:37:18.212Z" }, + { url = "https://files.pythonhosted.org/packages/6f/66/e69e6e904f5ecf6901be3dd16e7e54d41b6ec6ae3405a535286d4418ffb4/contourpy-1.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:532fd26e715560721bb0d5fc7610fce279b3699b018600ab999d1be895b09415", size = 318963, upload-time = "2025-04-15T17:37:22.76Z" }, + { url = "https://files.pythonhosted.org/packages/a8/32/b8a1c8965e4f72482ff2d1ac2cd670ce0b542f203c8e1d34e7c3e6925da7/contourpy-1.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b383144cf2d2c29f01a1e8170f50dacf0eac02d64139dcd709a8ac4eb3cfe", size = 323681, upload-time = "2025-04-15T17:37:33.001Z" }, + { url = "https://files.pythonhosted.org/packages/30/c6/12a7e6811d08757c7162a541ca4c5c6a34c0f4e98ef2b338791093518e40/contourpy-1.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c49f73e61f1f774650a55d221803b101d966ca0c5a2d6d5e4320ec3997489441", size = 1308674, upload-time = "2025-04-15T17:37:48.64Z" }, + { url = "https://files.pythonhosted.org/packages/2a/8a/bebe5a3f68b484d3a2b8ffaf84704b3e343ef1addea528132ef148e22b3b/contourpy-1.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3d80b2c0300583228ac98d0a927a1ba6a2ba6b8a742463c564f1d419ee5b211e", size = 1380480, upload-time = "2025-04-15T17:38:06.7Z" }, + { url = "https://files.pythonhosted.org/packages/34/db/fcd325f19b5978fb509a7d55e06d99f5f856294c1991097534360b307cf1/contourpy-1.3.2-cp312-cp312-win32.whl", hash = "sha256:90df94c89a91b7362e1142cbee7568f86514412ab8a2c0d0fca72d7e91b62912", size = 178489, upload-time = "2025-04-15T17:38:10.338Z" }, + { url = "https://files.pythonhosted.org/packages/01/c8/fadd0b92ffa7b5eb5949bf340a63a4a496a6930a6c37a7ba0f12acb076d6/contourpy-1.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:8c942a01d9163e2e5cfb05cb66110121b8d07ad438a17f9e766317bcb62abf73", size = 223042, upload-time = "2025-04-15T17:38:14.239Z" }, + { url = "https://files.pythonhosted.org/packages/2e/61/5673f7e364b31e4e7ef6f61a4b5121c5f170f941895912f773d95270f3a2/contourpy-1.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:de39db2604ae755316cb5967728f4bea92685884b1e767b7c24e983ef5f771cb", size = 271630, upload-time = "2025-04-15T17:38:19.142Z" }, + { url = "https://files.pythonhosted.org/packages/ff/66/a40badddd1223822c95798c55292844b7e871e50f6bfd9f158cb25e0bd39/contourpy-1.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3f9e896f447c5c8618f1edb2bafa9a4030f22a575ec418ad70611450720b5b08", size = 255670, upload-time = "2025-04-15T17:38:23.688Z" }, + { url = "https://files.pythonhosted.org/packages/1e/c7/cf9fdee8200805c9bc3b148f49cb9482a4e3ea2719e772602a425c9b09f8/contourpy-1.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71e2bd4a1c4188f5c2b8d274da78faab884b59df20df63c34f74aa1813c4427c", size = 306694, upload-time = "2025-04-15T17:38:28.238Z" }, + { url = "https://files.pythonhosted.org/packages/dd/e7/ccb9bec80e1ba121efbffad7f38021021cda5be87532ec16fd96533bb2e0/contourpy-1.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de425af81b6cea33101ae95ece1f696af39446db9682a0b56daaa48cfc29f38f", size = 345986, upload-time = "2025-04-15T17:38:33.502Z" }, + { url = "https://files.pythonhosted.org/packages/dc/49/ca13bb2da90391fa4219fdb23b078d6065ada886658ac7818e5441448b78/contourpy-1.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:977e98a0e0480d3fe292246417239d2d45435904afd6d7332d8455981c408b85", size = 318060, upload-time = "2025-04-15T17:38:38.672Z" }, + { url = "https://files.pythonhosted.org/packages/c8/65/5245ce8c548a8422236c13ffcdcdada6a2a812c361e9e0c70548bb40b661/contourpy-1.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:434f0adf84911c924519d2b08fc10491dd282b20bdd3fa8f60fd816ea0b48841", size = 322747, upload-time = "2025-04-15T17:38:43.712Z" }, + { url = "https://files.pythonhosted.org/packages/72/30/669b8eb48e0a01c660ead3752a25b44fdb2e5ebc13a55782f639170772f9/contourpy-1.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c66c4906cdbc50e9cba65978823e6e00b45682eb09adbb78c9775b74eb222422", size = 1308895, upload-time = "2025-04-15T17:39:00.224Z" }, + { url = "https://files.pythonhosted.org/packages/05/5a/b569f4250decee6e8d54498be7bdf29021a4c256e77fe8138c8319ef8eb3/contourpy-1.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8b7fc0cd78ba2f4695fd0a6ad81a19e7e3ab825c31b577f384aa9d7817dc3bef", size = 1379098, upload-time = "2025-04-15T17:43:29.649Z" }, + { url = "https://files.pythonhosted.org/packages/19/ba/b227c3886d120e60e41b28740ac3617b2f2b971b9f601c835661194579f1/contourpy-1.3.2-cp313-cp313-win32.whl", hash = "sha256:15ce6ab60957ca74cff444fe66d9045c1fd3e92c8936894ebd1f3eef2fff075f", size = 178535, upload-time = "2025-04-15T17:44:44.532Z" }, + { url = "https://files.pythonhosted.org/packages/12/6e/2fed56cd47ca739b43e892707ae9a13790a486a3173be063681ca67d2262/contourpy-1.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e1578f7eafce927b168752ed7e22646dad6cd9bca673c60bff55889fa236ebf9", size = 223096, upload-time = "2025-04-15T17:44:48.194Z" }, + { url = "https://files.pythonhosted.org/packages/54/4c/e76fe2a03014a7c767d79ea35c86a747e9325537a8b7627e0e5b3ba266b4/contourpy-1.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0475b1f6604896bc7c53bb070e355e9321e1bc0d381735421a2d2068ec56531f", size = 285090, upload-time = "2025-04-15T17:43:34.084Z" }, + { url = "https://files.pythonhosted.org/packages/7b/e2/5aba47debd55d668e00baf9651b721e7733975dc9fc27264a62b0dd26eb8/contourpy-1.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c85bb486e9be652314bb5b9e2e3b0d1b2e643d5eec4992c0fbe8ac71775da739", size = 268643, upload-time = "2025-04-15T17:43:38.626Z" }, + { url = "https://files.pythonhosted.org/packages/a1/37/cd45f1f051fe6230f751cc5cdd2728bb3a203f5619510ef11e732109593c/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:745b57db7758f3ffc05a10254edd3182a2a83402a89c00957a8e8a22f5582823", size = 310443, upload-time = "2025-04-15T17:43:44.522Z" }, + { url = "https://files.pythonhosted.org/packages/8b/a2/36ea6140c306c9ff6dd38e3bcec80b3b018474ef4d17eb68ceecd26675f4/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:970e9173dbd7eba9b4e01aab19215a48ee5dd3f43cef736eebde064a171f89a5", size = 349865, upload-time = "2025-04-15T17:43:49.545Z" }, + { url = "https://files.pythonhosted.org/packages/95/b7/2fc76bc539693180488f7b6cc518da7acbbb9e3b931fd9280504128bf956/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6c4639a9c22230276b7bffb6a850dfc8258a2521305e1faefe804d006b2e532", size = 321162, upload-time = "2025-04-15T17:43:54.203Z" }, + { url = "https://files.pythonhosted.org/packages/f4/10/76d4f778458b0aa83f96e59d65ece72a060bacb20cfbee46cf6cd5ceba41/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc829960f34ba36aad4302e78eabf3ef16a3a100863f0d4eeddf30e8a485a03b", size = 327355, upload-time = "2025-04-15T17:44:01.025Z" }, + { url = "https://files.pythonhosted.org/packages/43/a3/10cf483ea683f9f8ab096c24bad3cce20e0d1dd9a4baa0e2093c1c962d9d/contourpy-1.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d32530b534e986374fc19eaa77fcb87e8a99e5431499949b828312bdcd20ac52", size = 1307935, upload-time = "2025-04-15T17:44:17.322Z" }, + { url = "https://files.pythonhosted.org/packages/78/73/69dd9a024444489e22d86108e7b913f3528f56cfc312b5c5727a44188471/contourpy-1.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e298e7e70cf4eb179cc1077be1c725b5fd131ebc81181bf0c03525c8abc297fd", size = 1372168, upload-time = "2025-04-15T17:44:33.43Z" }, + { url = "https://files.pythonhosted.org/packages/0f/1b/96d586ccf1b1a9d2004dd519b25fbf104a11589abfd05484ff12199cca21/contourpy-1.3.2-cp313-cp313t-win32.whl", hash = "sha256:d0e589ae0d55204991450bb5c23f571c64fe43adaa53f93fc902a84c96f52fe1", size = 189550, upload-time = "2025-04-15T17:44:37.092Z" }, + { url = "https://files.pythonhosted.org/packages/b0/e6/6000d0094e8a5e32ad62591c8609e269febb6e4db83a1c75ff8868b42731/contourpy-1.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:78e9253c3de756b3f6a5174d024c4835acd59eb3f8e2ca13e775dbffe1558f69", size = 238214, upload-time = "2025-04-15T17:44:40.827Z" }, +] + +[[package]] +name = "coverage" +version = "7.9.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/04/b7/c0465ca253df10a9e8dae0692a4ae6e9726d245390aaef92360e1d6d3832/coverage-7.9.2.tar.gz", hash = "sha256:997024fa51e3290264ffd7492ec97d0690293ccd2b45a6cd7d82d945a4a80c8b", size = 813556, upload-time = "2025-07-03T10:54:15.101Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/53/d7/7deefc6fd4f0f1d4c58051f4004e366afc9e7ab60217ac393f247a1de70a/coverage-7.9.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ae9eb07f1cfacd9cfe8eaee6f4ff4b8a289a668c39c165cd0c8548484920ffc0", size = 212344, upload-time = "2025-07-03T10:53:09.3Z" }, + { url = "https://files.pythonhosted.org/packages/95/0c/ee03c95d32be4d519e6a02e601267769ce2e9a91fc8faa1b540e3626c680/coverage-7.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9ce85551f9a1119f02adc46d3014b5ee3f765deac166acf20dbb851ceb79b6f3", size = 212580, upload-time = "2025-07-03T10:53:11.52Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9f/826fa4b544b27620086211b87a52ca67592622e1f3af9e0a62c87aea153a/coverage-7.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8f6389ac977c5fb322e0e38885fbbf901743f79d47f50db706e7644dcdcb6e1", size = 246383, upload-time = "2025-07-03T10:53:13.134Z" }, + { url = "https://files.pythonhosted.org/packages/7f/b3/4477aafe2a546427b58b9c540665feff874f4db651f4d3cb21b308b3a6d2/coverage-7.9.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff0d9eae8cdfcd58fe7893b88993723583a6ce4dfbfd9f29e001922544f95615", size = 243400, upload-time = "2025-07-03T10:53:14.614Z" }, + { url = "https://files.pythonhosted.org/packages/f8/c2/efffa43778490c226d9d434827702f2dfbc8041d79101a795f11cbb2cf1e/coverage-7.9.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fae939811e14e53ed8a9818dad51d434a41ee09df9305663735f2e2d2d7d959b", size = 245591, upload-time = "2025-07-03T10:53:15.872Z" }, + { url = "https://files.pythonhosted.org/packages/c6/e7/a59888e882c9a5f0192d8627a30ae57910d5d449c80229b55e7643c078c4/coverage-7.9.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:31991156251ec202c798501e0a42bbdf2169dcb0f137b1f5c0f4267f3fc68ef9", size = 245402, upload-time = "2025-07-03T10:53:17.124Z" }, + { url = "https://files.pythonhosted.org/packages/92/a5/72fcd653ae3d214927edc100ce67440ed8a0a1e3576b8d5e6d066ed239db/coverage-7.9.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d0d67963f9cbfc7c7f96d4ac74ed60ecbebd2ea6eeb51887af0f8dce205e545f", size = 243583, upload-time = "2025-07-03T10:53:18.781Z" }, + { url = "https://files.pythonhosted.org/packages/5c/f5/84e70e4df28f4a131d580d7d510aa1ffd95037293da66fd20d446090a13b/coverage-7.9.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:49b752a2858b10580969ec6af6f090a9a440a64a301ac1528d7ca5f7ed497f4d", size = 244815, upload-time = "2025-07-03T10:53:20.168Z" }, + { url = "https://files.pythonhosted.org/packages/39/e7/d73d7cbdbd09fdcf4642655ae843ad403d9cbda55d725721965f3580a314/coverage-7.9.2-cp312-cp312-win32.whl", hash = "sha256:88d7598b8ee130f32f8a43198ee02edd16d7f77692fa056cb779616bbea1b355", size = 214719, upload-time = "2025-07-03T10:53:21.521Z" }, + { url = "https://files.pythonhosted.org/packages/9f/d6/7486dcc3474e2e6ad26a2af2db7e7c162ccd889c4c68fa14ea8ec189c9e9/coverage-7.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:9dfb070f830739ee49d7c83e4941cc767e503e4394fdecb3b54bfdac1d7662c0", size = 215509, upload-time = "2025-07-03T10:53:22.853Z" }, + { url = "https://files.pythonhosted.org/packages/b7/34/0439f1ae2593b0346164d907cdf96a529b40b7721a45fdcf8b03c95fcd90/coverage-7.9.2-cp312-cp312-win_arm64.whl", hash = "sha256:4e2c058aef613e79df00e86b6d42a641c877211384ce5bd07585ed7ba71ab31b", size = 213910, upload-time = "2025-07-03T10:53:24.472Z" }, + { url = "https://files.pythonhosted.org/packages/94/9d/7a8edf7acbcaa5e5c489a646226bed9591ee1c5e6a84733c0140e9ce1ae1/coverage-7.9.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:985abe7f242e0d7bba228ab01070fde1d6c8fa12f142e43debe9ed1dde686038", size = 212367, upload-time = "2025-07-03T10:53:25.811Z" }, + { url = "https://files.pythonhosted.org/packages/e8/9e/5cd6f130150712301f7e40fb5865c1bc27b97689ec57297e568d972eec3c/coverage-7.9.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82c3939264a76d44fde7f213924021ed31f55ef28111a19649fec90c0f109e6d", size = 212632, upload-time = "2025-07-03T10:53:27.075Z" }, + { url = "https://files.pythonhosted.org/packages/a8/de/6287a2c2036f9fd991c61cefa8c64e57390e30c894ad3aa52fac4c1e14a8/coverage-7.9.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae5d563e970dbe04382f736ec214ef48103d1b875967c89d83c6e3f21706d5b3", size = 245793, upload-time = "2025-07-03T10:53:28.408Z" }, + { url = "https://files.pythonhosted.org/packages/06/cc/9b5a9961d8160e3cb0b558c71f8051fe08aa2dd4b502ee937225da564ed1/coverage-7.9.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdd612e59baed2a93c8843c9a7cb902260f181370f1d772f4842987535071d14", size = 243006, upload-time = "2025-07-03T10:53:29.754Z" }, + { url = "https://files.pythonhosted.org/packages/49/d9/4616b787d9f597d6443f5588619c1c9f659e1f5fc9eebf63699eb6d34b78/coverage-7.9.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:256ea87cb2a1ed992bcdfc349d8042dcea1b80436f4ddf6e246d6bee4b5d73b6", size = 244990, upload-time = "2025-07-03T10:53:31.098Z" }, + { url = "https://files.pythonhosted.org/packages/48/83/801cdc10f137b2d02b005a761661649ffa60eb173dcdaeb77f571e4dc192/coverage-7.9.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f44ae036b63c8ea432f610534a2668b0c3aee810e7037ab9d8ff6883de480f5b", size = 245157, upload-time = "2025-07-03T10:53:32.717Z" }, + { url = "https://files.pythonhosted.org/packages/c8/a4/41911ed7e9d3ceb0ffb019e7635468df7499f5cc3edca5f7dfc078e9c5ec/coverage-7.9.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:82d76ad87c932935417a19b10cfe7abb15fd3f923cfe47dbdaa74ef4e503752d", size = 243128, upload-time = "2025-07-03T10:53:34.009Z" }, + { url = "https://files.pythonhosted.org/packages/10/41/344543b71d31ac9cb00a664d5d0c9ef134a0fe87cb7d8430003b20fa0b7d/coverage-7.9.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:619317bb86de4193debc712b9e59d5cffd91dc1d178627ab2a77b9870deb2868", size = 244511, upload-time = "2025-07-03T10:53:35.434Z" }, + { url = "https://files.pythonhosted.org/packages/d5/81/3b68c77e4812105e2a060f6946ba9e6f898ddcdc0d2bfc8b4b152a9ae522/coverage-7.9.2-cp313-cp313-win32.whl", hash = "sha256:0a07757de9feb1dfafd16ab651e0f628fd7ce551604d1bf23e47e1ddca93f08a", size = 214765, upload-time = "2025-07-03T10:53:36.787Z" }, + { url = "https://files.pythonhosted.org/packages/06/a2/7fac400f6a346bb1a4004eb2a76fbff0e242cd48926a2ce37a22a6a1d917/coverage-7.9.2-cp313-cp313-win_amd64.whl", hash = "sha256:115db3d1f4d3f35f5bb021e270edd85011934ff97c8797216b62f461dd69374b", size = 215536, upload-time = "2025-07-03T10:53:38.188Z" }, + { url = "https://files.pythonhosted.org/packages/08/47/2c6c215452b4f90d87017e61ea0fd9e0486bb734cb515e3de56e2c32075f/coverage-7.9.2-cp313-cp313-win_arm64.whl", hash = "sha256:48f82f889c80af8b2a7bb6e158d95a3fbec6a3453a1004d04e4f3b5945a02694", size = 213943, upload-time = "2025-07-03T10:53:39.492Z" }, + { url = "https://files.pythonhosted.org/packages/a3/46/e211e942b22d6af5e0f323faa8a9bc7c447a1cf1923b64c47523f36ed488/coverage-7.9.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:55a28954545f9d2f96870b40f6c3386a59ba8ed50caf2d949676dac3ecab99f5", size = 213088, upload-time = "2025-07-03T10:53:40.874Z" }, + { url = "https://files.pythonhosted.org/packages/d2/2f/762551f97e124442eccd907bf8b0de54348635b8866a73567eb4e6417acf/coverage-7.9.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cdef6504637731a63c133bb2e6f0f0214e2748495ec15fe42d1e219d1b133f0b", size = 213298, upload-time = "2025-07-03T10:53:42.218Z" }, + { url = "https://files.pythonhosted.org/packages/7a/b7/76d2d132b7baf7360ed69be0bcab968f151fa31abe6d067f0384439d9edb/coverage-7.9.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bcd5ebe66c7a97273d5d2ddd4ad0ed2e706b39630ed4b53e713d360626c3dbb3", size = 256541, upload-time = "2025-07-03T10:53:43.823Z" }, + { url = "https://files.pythonhosted.org/packages/a0/17/392b219837d7ad47d8e5974ce5f8dc3deb9f99a53b3bd4d123602f960c81/coverage-7.9.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9303aed20872d7a3c9cb39c5d2b9bdbe44e3a9a1aecb52920f7e7495410dfab8", size = 252761, upload-time = "2025-07-03T10:53:45.19Z" }, + { url = "https://files.pythonhosted.org/packages/d5/77/4256d3577fe1b0daa8d3836a1ebe68eaa07dd2cbaf20cf5ab1115d6949d4/coverage-7.9.2-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc18ea9e417a04d1920a9a76fe9ebd2f43ca505b81994598482f938d5c315f46", size = 254917, upload-time = "2025-07-03T10:53:46.931Z" }, + { url = "https://files.pythonhosted.org/packages/53/99/fc1a008eef1805e1ddb123cf17af864743354479ea5129a8f838c433cc2c/coverage-7.9.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6406cff19880aaaadc932152242523e892faff224da29e241ce2fca329866584", size = 256147, upload-time = "2025-07-03T10:53:48.289Z" }, + { url = "https://files.pythonhosted.org/packages/92/c0/f63bf667e18b7f88c2bdb3160870e277c4874ced87e21426128d70aa741f/coverage-7.9.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2d0d4f6ecdf37fcc19c88fec3e2277d5dee740fb51ffdd69b9579b8c31e4232e", size = 254261, upload-time = "2025-07-03T10:53:49.99Z" }, + { url = "https://files.pythonhosted.org/packages/8c/32/37dd1c42ce3016ff8ec9e4b607650d2e34845c0585d3518b2a93b4830c1a/coverage-7.9.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c33624f50cf8de418ab2b4d6ca9eda96dc45b2c4231336bac91454520e8d1fac", size = 255099, upload-time = "2025-07-03T10:53:51.354Z" }, + { url = "https://files.pythonhosted.org/packages/da/2e/af6b86f7c95441ce82f035b3affe1cd147f727bbd92f563be35e2d585683/coverage-7.9.2-cp313-cp313t-win32.whl", hash = "sha256:1df6b76e737c6a92210eebcb2390af59a141f9e9430210595251fbaf02d46926", size = 215440, upload-time = "2025-07-03T10:53:52.808Z" }, + { url = "https://files.pythonhosted.org/packages/4d/bb/8a785d91b308867f6b2e36e41c569b367c00b70c17f54b13ac29bcd2d8c8/coverage-7.9.2-cp313-cp313t-win_amd64.whl", hash = "sha256:f5fd54310b92741ebe00d9c0d1d7b2b27463952c022da6d47c175d246a98d1bd", size = 216537, upload-time = "2025-07-03T10:53:54.273Z" }, + { url = "https://files.pythonhosted.org/packages/1d/a0/a6bffb5e0f41a47279fd45a8f3155bf193f77990ae1c30f9c224b61cacb0/coverage-7.9.2-cp313-cp313t-win_arm64.whl", hash = "sha256:c48c2375287108c887ee87d13b4070a381c6537d30e8487b24ec721bf2a781cb", size = 214398, upload-time = "2025-07-03T10:53:56.715Z" }, + { url = "https://files.pythonhosted.org/packages/3c/38/bbe2e63902847cf79036ecc75550d0698af31c91c7575352eb25190d0fb3/coverage-7.9.2-py3-none-any.whl", hash = "sha256:e425cd5b00f6fc0ed7cdbd766c70be8baab4b7839e4d4fe5fac48581dd968ea4", size = 204005, upload-time = "2025-07-03T10:54:13.491Z" }, +] + +[[package]] +name = "cycler" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, +] + +[[package]] +name = "debugpy" +version = "1.8.15" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/3a9a28ddb750a76eaec445c7f4d3147ea2c579a97dbd9e25d39001b92b21/debugpy-1.8.15.tar.gz", hash = "sha256:58d7a20b7773ab5ee6bdfb2e6cf622fdf1e40c9d5aef2857d85391526719ac00", size = 1643279, upload-time = "2025-07-15T16:43:29.135Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/4a/4508d256e52897f5cdfee6a6d7580974811e911c6d01321df3264508a5ac/debugpy-1.8.15-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:3dcc7225cb317469721ab5136cda9ff9c8b6e6fb43e87c9e15d5b108b99d01ba", size = 2511197, upload-time = "2025-07-15T16:43:42.343Z" }, + { url = "https://files.pythonhosted.org/packages/99/8d/7f6ef1097e7fecf26b4ef72338d08e41644a41b7ee958a19f494ffcffc29/debugpy-1.8.15-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:047a493ca93c85ccede1dbbaf4e66816794bdc214213dde41a9a61e42d27f8fc", size = 4229517, upload-time = "2025-07-15T16:43:44.14Z" }, + { url = "https://files.pythonhosted.org/packages/3f/e8/e8c6a9aa33a9c9c6dacbf31747384f6ed2adde4de2e9693c766bdf323aa3/debugpy-1.8.15-cp312-cp312-win32.whl", hash = "sha256:b08e9b0bc260cf324c890626961dad4ffd973f7568fbf57feb3c3a65ab6b6327", size = 5276132, upload-time = "2025-07-15T16:43:45.529Z" }, + { url = "https://files.pythonhosted.org/packages/e9/ad/231050c6177b3476b85fcea01e565dac83607b5233d003ff067e2ee44d8f/debugpy-1.8.15-cp312-cp312-win_amd64.whl", hash = "sha256:e2a4fe357c92334272eb2845fcfcdbec3ef9f22c16cf613c388ac0887aed15fa", size = 5317645, upload-time = "2025-07-15T16:43:46.968Z" }, + { url = "https://files.pythonhosted.org/packages/28/70/2928aad2310726d5920b18ed9f54b9f06df5aa4c10cf9b45fa18ff0ab7e8/debugpy-1.8.15-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:f5e01291ad7d6649aed5773256c5bba7a1a556196300232de1474c3c372592bf", size = 2495538, upload-time = "2025-07-15T16:43:48.927Z" }, + { url = "https://files.pythonhosted.org/packages/9e/c6/9b8ffb4ca91fac8b2877eef63c9cc0e87dd2570b1120054c272815ec4cd0/debugpy-1.8.15-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94dc0f0d00e528d915e0ce1c78e771475b2335b376c49afcc7382ee0b146bab6", size = 4221874, upload-time = "2025-07-15T16:43:50.282Z" }, + { url = "https://files.pythonhosted.org/packages/55/8a/9b8d59674b4bf489318c7c46a1aab58e606e583651438084b7e029bf3c43/debugpy-1.8.15-cp313-cp313-win32.whl", hash = "sha256:fcf0748d4f6e25f89dc5e013d1129ca6f26ad4da405e0723a4f704583896a709", size = 5275949, upload-time = "2025-07-15T16:43:52.079Z" }, + { url = "https://files.pythonhosted.org/packages/72/83/9e58e6fdfa8710a5e6ec06c2401241b9ad48b71c0a7eb99570a1f1edb1d3/debugpy-1.8.15-cp313-cp313-win_amd64.whl", hash = "sha256:73c943776cb83e36baf95e8f7f8da765896fd94b05991e7bc162456d25500683", size = 5317720, upload-time = "2025-07-15T16:43:53.703Z" }, + { url = "https://files.pythonhosted.org/packages/07/d5/98748d9860e767a1248b5e31ffa7ce8cb7006e97bf8abbf3d891d0a8ba4e/debugpy-1.8.15-py2.py3-none-any.whl", hash = "sha256:bce2e6c5ff4f2e00b98d45e7e01a49c7b489ff6df5f12d881c67d2f1ac635f3d", size = 5282697, upload-time = "2025-07-15T16:44:07.996Z" }, +] + +[[package]] +name = "decorator" +version = "5.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, +] + +[[package]] +name = "defusedxml" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, +] + +[[package]] +name = "deprecated" +version = "1.2.18" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/97/06afe62762c9a8a86af0cfb7bfdab22a43ad17138b07af5b1a58442690a2/deprecated-1.2.18.tar.gz", hash = "sha256:422b6f6d859da6f2ef57857761bfb392480502a64c3028ca9bbe86085d72115d", size = 2928744, upload-time = "2025-01-27T10:46:25.7Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6e/c6/ac0b6c1e2d138f1002bcf799d330bd6d85084fece321e662a14223794041/Deprecated-1.2.18-py2.py3-none-any.whl", hash = "sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec", size = 9998, upload-time = "2025-01-27T10:46:09.186Z" }, +] + +[[package]] +name = "dill" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/12/80/630b4b88364e9a8c8c5797f4602d0f76ef820909ee32f0bacb9f90654042/dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", size = 186976, upload-time = "2025-04-16T00:41:48.867Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668, upload-time = "2025-04-16T00:41:47.671Z" }, +] + +[[package]] +name = "distlib" +version = "0.3.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0d/dd/1bec4c5ddb504ca60fc29472f3d27e8d4da1257a854e1d96742f15c1d02d/distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403", size = 613923, upload-time = "2024-10-09T18:35:47.551Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/a1/cf2472db20f7ce4a6be1253a81cfdf85ad9c7885ffbed7047fb72c24cf87/distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", size = 468973, upload-time = "2024-10-09T18:35:44.272Z" }, +] + +[[package]] +name = "docutils" +version = "0.21.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444, upload-time = "2024-04-23T18:57:18.24Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408, upload-time = "2024-04-23T18:57:14.835Z" }, +] + +[[package]] +name = "et-xmlfile" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d3/38/af70d7ab1ae9d4da450eeec1fa3918940a5fafb9055e934af8d6eb0c2313/et_xmlfile-2.0.0.tar.gz", hash = "sha256:dab3f4764309081ce75662649be815c4c9081e88f0837825f90fd28317d4da54", size = 17234, upload-time = "2024-10-25T17:25:40.039Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/8b/5fe2cc11fee489817272089c4203e679c63b570a5aaeb18d852ae3cbba6a/et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa", size = 18059, upload-time = "2024-10-25T17:25:39.051Z" }, +] + +[[package]] +name = "executing" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/91/50/a9d80c47ff289c611ff12e63f7c5d13942c65d68125160cefd768c73e6e4/executing-2.2.0.tar.gz", hash = "sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755", size = 978693, upload-time = "2025-01-22T15:41:29.403Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa", size = 26702, upload-time = "2025-01-22T15:41:25.929Z" }, +] + +[[package]] +name = "fastapi" +version = "0.116.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "starlette" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/78/d7/6c8b3bfe33eeffa208183ec037fee0cce9f7f024089ab1c5d12ef04bd27c/fastapi-0.116.1.tar.gz", hash = "sha256:ed52cbf946abfd70c5a0dccb24673f0670deeb517a88b3544d03c2a6bf283143", size = 296485, upload-time = "2025-07-11T16:22:32.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/47/d63c60f59a59467fda0f93f46335c9d18526d7071f025cb5b89d5353ea42/fastapi-0.116.1-py3-none-any.whl", hash = "sha256:c46ac7c312df840f0c9e220f7964bada936781bc4e2e6eb71f1c4d7553786565", size = 95631, upload-time = "2025-07-11T16:22:30.485Z" }, +] + +[[package]] +name = "fastjsonschema" +version = "2.21.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8b/50/4b769ce1ac4071a1ef6d86b1a3fb56cdc3a37615e8c5519e1af96cdac366/fastjsonschema-2.21.1.tar.gz", hash = "sha256:794d4f0a58f848961ba16af7b9c85a3e88cd360df008c59aac6fc5ae9323b5d4", size = 373939, upload-time = "2024-12-02T10:55:15.133Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/2b/0817a2b257fe88725c25589d89aec060581aabf668707a8d03b2e9e0cb2a/fastjsonschema-2.21.1-py3-none-any.whl", hash = "sha256:c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667", size = 23924, upload-time = "2024-12-02T10:55:07.599Z" }, +] + +[[package]] +name = "filelock" +version = "3.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0a/10/c23352565a6544bdc5353e0b15fc1c563352101f30e24bf500207a54df9a/filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2", size = 18075, upload-time = "2025-03-14T07:11:40.47Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215, upload-time = "2025-03-14T07:11:39.145Z" }, +] + +[[package]] +name = "flexcache" +version = "0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/b0/8a21e330561c65653d010ef112bf38f60890051d244ede197ddaa08e50c1/flexcache-0.3.tar.gz", hash = "sha256:18743bd5a0621bfe2cf8d519e4c3bfdf57a269c15d1ced3fb4b64e0ff4600656", size = 15816, upload-time = "2024-03-09T03:21:07.555Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/cd/c883e1a7c447479d6e13985565080e3fea88ab5a107c21684c813dba1875/flexcache-0.3-py3-none-any.whl", hash = "sha256:d43c9fea82336af6e0115e308d9d33a185390b8346a017564611f1466dcd2e32", size = 13263, upload-time = "2024-03-09T03:21:05.635Z" }, +] + +[[package]] +name = "flexparser" +version = "0.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/82/99/b4de7e39e8eaf8207ba1a8fa2241dd98b2ba72ae6e16960d8351736d8702/flexparser-0.4.tar.gz", hash = "sha256:266d98905595be2ccc5da964fe0a2c3526fbbffdc45b65b3146d75db992ef6b2", size = 31799, upload-time = "2024-11-07T02:00:56.249Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/5e/3be305568fe5f34448807976dc82fc151d76c3e0e03958f34770286278c1/flexparser-0.4-py3-none-any.whl", hash = "sha256:3738b456192dcb3e15620f324c447721023c0293f6af9955b481e91d00179846", size = 27625, upload-time = "2024-11-07T02:00:54.523Z" }, +] + +[[package]] +name = "fonttools" +version = "4.59.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8a/27/ec3c723bfdf86f34c5c82bf6305df3e0f0d8ea798d2d3a7cb0c0a866d286/fonttools-4.59.0.tar.gz", hash = "sha256:be392ec3529e2f57faa28709d60723a763904f71a2b63aabe14fee6648fe3b14", size = 3532521, upload-time = "2025-07-16T12:04:54.613Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e2/77/b1c8af22f4265e951cd2e5535dbef8859efcef4fb8dee742d368c967cddb/fonttools-4.59.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f9b3a78f69dcbd803cf2fb3f972779875b244c1115481dfbdd567b2c22b31f6b", size = 2767562, upload-time = "2025-07-16T12:04:06.895Z" }, + { url = "https://files.pythonhosted.org/packages/ff/5a/aeb975699588176bb357e8b398dfd27e5d3a2230d92b81ab8cbb6187358d/fonttools-4.59.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:57bb7e26928573ee7c6504f54c05860d867fd35e675769f3ce01b52af38d48e2", size = 2335168, upload-time = "2025-07-16T12:04:08.695Z" }, + { url = "https://files.pythonhosted.org/packages/54/97/c6101a7e60ae138c4ef75b22434373a0da50a707dad523dd19a4889315bf/fonttools-4.59.0-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4536f2695fe5c1ffb528d84a35a7d3967e5558d2af58b4775e7ab1449d65767b", size = 4909850, upload-time = "2025-07-16T12:04:10.761Z" }, + { url = "https://files.pythonhosted.org/packages/bd/6c/fa4d18d641054f7bff878cbea14aa9433f292b9057cb1700d8e91a4d5f4f/fonttools-4.59.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:885bde7d26e5b40e15c47bd5def48b38cbd50830a65f98122a8fb90962af7cd1", size = 4955131, upload-time = "2025-07-16T12:04:12.846Z" }, + { url = "https://files.pythonhosted.org/packages/20/5c/331947fc1377deb928a69bde49f9003364f5115e5cbe351eea99e39412a2/fonttools-4.59.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6801aeddb6acb2c42eafa45bc1cb98ba236871ae6f33f31e984670b749a8e58e", size = 4899667, upload-time = "2025-07-16T12:04:14.558Z" }, + { url = "https://files.pythonhosted.org/packages/8a/46/b66469dfa26b8ff0baa7654b2cc7851206c6d57fe3abdabbaab22079a119/fonttools-4.59.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:31003b6a10f70742a63126b80863ab48175fb8272a18ca0846c0482968f0588e", size = 5051349, upload-time = "2025-07-16T12:04:16.388Z" }, + { url = "https://files.pythonhosted.org/packages/2e/05/ebfb6b1f3a4328ab69787d106a7d92ccde77ce66e98659df0f9e3f28d93d/fonttools-4.59.0-cp312-cp312-win32.whl", hash = "sha256:fbce6dae41b692a5973d0f2158f782b9ad05babc2c2019a970a1094a23909b1b", size = 2201315, upload-time = "2025-07-16T12:04:18.557Z" }, + { url = "https://files.pythonhosted.org/packages/09/45/d2bdc9ea20bbadec1016fd0db45696d573d7a26d95ab5174ffcb6d74340b/fonttools-4.59.0-cp312-cp312-win_amd64.whl", hash = "sha256:332bfe685d1ac58ca8d62b8d6c71c2e52a6c64bc218dc8f7825c9ea51385aa01", size = 2249408, upload-time = "2025-07-16T12:04:20.489Z" }, + { url = "https://files.pythonhosted.org/packages/f3/bb/390990e7c457d377b00890d9f96a3ca13ae2517efafb6609c1756e213ba4/fonttools-4.59.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:78813b49d749e1bb4db1c57f2d4d7e6db22c253cb0a86ad819f5dc197710d4b2", size = 2758704, upload-time = "2025-07-16T12:04:22.217Z" }, + { url = "https://files.pythonhosted.org/packages/df/6f/d730d9fcc9b410a11597092bd2eb9ca53e5438c6cb90e4b3047ce1b723e9/fonttools-4.59.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:401b1941ce37e78b8fd119b419b617277c65ae9417742a63282257434fd68ea2", size = 2330764, upload-time = "2025-07-16T12:04:23.985Z" }, + { url = "https://files.pythonhosted.org/packages/75/b4/b96bb66f6f8cc4669de44a158099b249c8159231d254ab6b092909388be5/fonttools-4.59.0-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:efd7e6660674e234e29937bc1481dceb7e0336bfae75b856b4fb272b5093c5d4", size = 4890699, upload-time = "2025-07-16T12:04:25.664Z" }, + { url = "https://files.pythonhosted.org/packages/b5/57/7969af50b26408be12baa317c6147588db5b38af2759e6df94554dbc5fdb/fonttools-4.59.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51ab1ff33c19e336c02dee1e9fd1abd974a4ca3d8f7eef2a104d0816a241ce97", size = 4952934, upload-time = "2025-07-16T12:04:27.733Z" }, + { url = "https://files.pythonhosted.org/packages/d6/e2/dd968053b6cf1f46c904f5bd409b22341477c017d8201619a265e50762d3/fonttools-4.59.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a9bf8adc9e1f3012edc8f09b08336272aec0c55bc677422273e21280db748f7c", size = 4892319, upload-time = "2025-07-16T12:04:30.074Z" }, + { url = "https://files.pythonhosted.org/packages/6b/95/a59810d8eda09129f83467a4e58f84205dc6994ebaeb9815406363e07250/fonttools-4.59.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:37e01c6ec0c98599778c2e688350d624fa4770fbd6144551bd5e032f1199171c", size = 5034753, upload-time = "2025-07-16T12:04:32.292Z" }, + { url = "https://files.pythonhosted.org/packages/a5/84/51a69ee89ff8d1fea0c6997e946657e25a3f08513de8435fe124929f3eef/fonttools-4.59.0-cp313-cp313-win32.whl", hash = "sha256:70d6b3ceaa9cc5a6ac52884f3b3d9544e8e231e95b23f138bdb78e6d4dc0eae3", size = 2199688, upload-time = "2025-07-16T12:04:34.444Z" }, + { url = "https://files.pythonhosted.org/packages/a0/ee/f626cd372932d828508137a79b85167fdcf3adab2e3bed433f295c596c6a/fonttools-4.59.0-cp313-cp313-win_amd64.whl", hash = "sha256:26731739daa23b872643f0e4072d5939960237d540c35c14e6a06d47d71ca8fe", size = 2248560, upload-time = "2025-07-16T12:04:36.034Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9c/df0ef2c51845a13043e5088f7bb988ca6cd5bb82d5d4203d6a158aa58cf2/fonttools-4.59.0-py3-none-any.whl", hash = "sha256:241313683afd3baacb32a6bd124d0bce7404bc5280e12e291bae1b9bba28711d", size = 1128050, upload-time = "2025-07-16T12:04:52.687Z" }, +] + +[[package]] +name = "fqdn" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/3e/a80a8c077fd798951169626cde3e239adeba7dab75deb3555716415bd9b0/fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", size = 6015, upload-time = "2021-03-11T07:16:29.08Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121, upload-time = "2021-03-11T07:16:28.351Z" }, +] + +[[package]] +name = "graphviz" +version = "0.21" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/b3/3ac91e9be6b761a4b30d66ff165e54439dcd48b83f4e20d644867215f6ca/graphviz-0.21.tar.gz", hash = "sha256:20743e7183be82aaaa8ad6c93f8893c923bd6658a04c32ee115edb3c8a835f78", size = 200434, upload-time = "2025-06-15T09:35:05.824Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/4c/e0ce1ef95d4000ebc1c11801f9b944fa5910ecc15b5e351865763d8657f8/graphviz-0.21-py3-none-any.whl", hash = "sha256:54f33de9f4f911d7e84e4191749cac8cc5653f815b06738c54db9a15ab8b1e42", size = 47300, upload-time = "2025-06-15T09:35:04.433Z" }, +] + +[[package]] +name = "gravis" +version = "0.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/73/76/10b6264a45fffb565b9ad26b9fbc4ba91c2ca700f8dbfba84dcdebf5cbdd/gravis-0.1.0.tar.gz", hash = "sha256:a36342602aa7da3bbd674c970439717926a8f7ca0678aa82cc5d756e8c2a529b", size = 648634, upload-time = "2021-12-08T21:43:19.456Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9b/fb/6a1659424cfab2d8df49f3f02ca11bf7ca303775681f105239b556c9146c/gravis-0.1.0-py3-none-any.whl", hash = "sha256:ccfb4dbba13c7570f1f33b35ab5d536868acf5ce8a0c427fd898340cf4e414f4", size = 659146, upload-time = "2021-12-08T21:43:15.348Z" }, +] + +[[package]] +name = "greenlet" +version = "3.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/92/bb85bd6e80148a4d2e0c59f7c0c2891029f8fd510183afc7d8d2feeed9b6/greenlet-3.2.3.tar.gz", hash = "sha256:8b0dd8ae4c0d6f5e54ee55ba935eeb3d735a9b58a8a1e5b5cbab64e01a39f365", size = 185752, upload-time = "2025-06-05T16:16:09.955Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/94/ad0d435f7c48debe960c53b8f60fb41c2026b1d0fa4a99a1cb17c3461e09/greenlet-3.2.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:25ad29caed5783d4bd7a85c9251c651696164622494c00802a139c00d639242d", size = 271992, upload-time = "2025-06-05T16:11:23.467Z" }, + { url = "https://files.pythonhosted.org/packages/93/5d/7c27cf4d003d6e77749d299c7c8f5fd50b4f251647b5c2e97e1f20da0ab5/greenlet-3.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88cd97bf37fe24a6710ec6a3a7799f3f81d9cd33317dcf565ff9950c83f55e0b", size = 638820, upload-time = "2025-06-05T16:38:52.882Z" }, + { url = "https://files.pythonhosted.org/packages/c6/7e/807e1e9be07a125bb4c169144937910bf59b9d2f6d931578e57f0bce0ae2/greenlet-3.2.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:baeedccca94880d2f5666b4fa16fc20ef50ba1ee353ee2d7092b383a243b0b0d", size = 653046, upload-time = "2025-06-05T16:41:36.343Z" }, + { url = "https://files.pythonhosted.org/packages/9d/ab/158c1a4ea1068bdbc78dba5a3de57e4c7aeb4e7fa034320ea94c688bfb61/greenlet-3.2.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:be52af4b6292baecfa0f397f3edb3c6092ce071b499dd6fe292c9ac9f2c8f264", size = 647701, upload-time = "2025-06-05T16:48:19.604Z" }, + { url = "https://files.pythonhosted.org/packages/cc/0d/93729068259b550d6a0288da4ff72b86ed05626eaf1eb7c0d3466a2571de/greenlet-3.2.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0cc73378150b8b78b0c9fe2ce56e166695e67478550769536a6742dca3651688", size = 649747, upload-time = "2025-06-05T16:13:04.628Z" }, + { url = "https://files.pythonhosted.org/packages/f6/f6/c82ac1851c60851302d8581680573245c8fc300253fc1ff741ae74a6c24d/greenlet-3.2.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:706d016a03e78df129f68c4c9b4c4f963f7d73534e48a24f5f5a7101ed13dbbb", size = 605461, upload-time = "2025-06-05T16:12:50.792Z" }, + { url = "https://files.pythonhosted.org/packages/98/82/d022cf25ca39cf1200650fc58c52af32c90f80479c25d1cbf57980ec3065/greenlet-3.2.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:419e60f80709510c343c57b4bb5a339d8767bf9aef9b8ce43f4f143240f88b7c", size = 1121190, upload-time = "2025-06-05T16:36:48.59Z" }, + { url = "https://files.pythonhosted.org/packages/f5/e1/25297f70717abe8104c20ecf7af0a5b82d2f5a980eb1ac79f65654799f9f/greenlet-3.2.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:93d48533fade144203816783373f27a97e4193177ebaaf0fc396db19e5d61163", size = 1149055, upload-time = "2025-06-05T16:12:40.457Z" }, + { url = "https://files.pythonhosted.org/packages/1f/8f/8f9e56c5e82eb2c26e8cde787962e66494312dc8cb261c460e1f3a9c88bc/greenlet-3.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:7454d37c740bb27bdeddfc3f358f26956a07d5220818ceb467a483197d84f849", size = 297817, upload-time = "2025-06-05T16:29:49.244Z" }, + { url = "https://files.pythonhosted.org/packages/b1/cf/f5c0b23309070ae93de75c90d29300751a5aacefc0a3ed1b1d8edb28f08b/greenlet-3.2.3-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:500b8689aa9dd1ab26872a34084503aeddefcb438e2e7317b89b11eaea1901ad", size = 270732, upload-time = "2025-06-05T16:10:08.26Z" }, + { url = "https://files.pythonhosted.org/packages/48/ae/91a957ba60482d3fecf9be49bc3948f341d706b52ddb9d83a70d42abd498/greenlet-3.2.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a07d3472c2a93117af3b0136f246b2833fdc0b542d4a9799ae5f41c28323faef", size = 639033, upload-time = "2025-06-05T16:38:53.983Z" }, + { url = "https://files.pythonhosted.org/packages/6f/df/20ffa66dd5a7a7beffa6451bdb7400d66251374ab40b99981478c69a67a8/greenlet-3.2.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:8704b3768d2f51150626962f4b9a9e4a17d2e37c8a8d9867bbd9fa4eb938d3b3", size = 652999, upload-time = "2025-06-05T16:41:37.89Z" }, + { url = "https://files.pythonhosted.org/packages/51/b4/ebb2c8cb41e521f1d72bf0465f2f9a2fd803f674a88db228887e6847077e/greenlet-3.2.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:5035d77a27b7c62db6cf41cf786cfe2242644a7a337a0e155c80960598baab95", size = 647368, upload-time = "2025-06-05T16:48:21.467Z" }, + { url = "https://files.pythonhosted.org/packages/8e/6a/1e1b5aa10dced4ae876a322155705257748108b7fd2e4fae3f2a091fe81a/greenlet-3.2.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2d8aa5423cd4a396792f6d4580f88bdc6efcb9205891c9d40d20f6e670992efb", size = 650037, upload-time = "2025-06-05T16:13:06.402Z" }, + { url = "https://files.pythonhosted.org/packages/26/f2/ad51331a157c7015c675702e2d5230c243695c788f8f75feba1af32b3617/greenlet-3.2.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2c724620a101f8170065d7dded3f962a2aea7a7dae133a009cada42847e04a7b", size = 608402, upload-time = "2025-06-05T16:12:51.91Z" }, + { url = "https://files.pythonhosted.org/packages/26/bc/862bd2083e6b3aff23300900a956f4ea9a4059de337f5c8734346b9b34fc/greenlet-3.2.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:873abe55f134c48e1f2a6f53f7d1419192a3d1a4e873bace00499a4e45ea6af0", size = 1119577, upload-time = "2025-06-05T16:36:49.787Z" }, + { url = "https://files.pythonhosted.org/packages/86/94/1fc0cc068cfde885170e01de40a619b00eaa8f2916bf3541744730ffb4c3/greenlet-3.2.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:024571bbce5f2c1cfff08bf3fbaa43bbc7444f580ae13b0099e95d0e6e67ed36", size = 1147121, upload-time = "2025-06-05T16:12:42.527Z" }, + { url = "https://files.pythonhosted.org/packages/27/1a/199f9587e8cb08a0658f9c30f3799244307614148ffe8b1e3aa22f324dea/greenlet-3.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:5195fb1e75e592dd04ce79881c8a22becdfa3e6f500e7feb059b1e6fdd54d3e3", size = 297603, upload-time = "2025-06-05T16:20:12.651Z" }, + { url = "https://files.pythonhosted.org/packages/d8/ca/accd7aa5280eb92b70ed9e8f7fd79dc50a2c21d8c73b9a0856f5b564e222/greenlet-3.2.3-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:3d04332dddb10b4a211b68111dabaee2e1a073663d117dc10247b5b1642bac86", size = 271479, upload-time = "2025-06-05T16:10:47.525Z" }, + { url = "https://files.pythonhosted.org/packages/55/71/01ed9895d9eb49223280ecc98a557585edfa56b3d0e965b9fa9f7f06b6d9/greenlet-3.2.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8186162dffde068a465deab08fc72c767196895c39db26ab1c17c0b77a6d8b97", size = 683952, upload-time = "2025-06-05T16:38:55.125Z" }, + { url = "https://files.pythonhosted.org/packages/ea/61/638c4bdf460c3c678a0a1ef4c200f347dff80719597e53b5edb2fb27ab54/greenlet-3.2.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f4bfbaa6096b1b7a200024784217defedf46a07c2eee1a498e94a1b5f8ec5728", size = 696917, upload-time = "2025-06-05T16:41:38.959Z" }, + { url = "https://files.pythonhosted.org/packages/22/cc/0bd1a7eb759d1f3e3cc2d1bc0f0b487ad3cc9f34d74da4b80f226fde4ec3/greenlet-3.2.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:ed6cfa9200484d234d8394c70f5492f144b20d4533f69262d530a1a082f6ee9a", size = 692443, upload-time = "2025-06-05T16:48:23.113Z" }, + { url = "https://files.pythonhosted.org/packages/67/10/b2a4b63d3f08362662e89c103f7fe28894a51ae0bc890fabf37d1d780e52/greenlet-3.2.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:02b0df6f63cd15012bed5401b47829cfd2e97052dc89da3cfaf2c779124eb892", size = 692995, upload-time = "2025-06-05T16:13:07.972Z" }, + { url = "https://files.pythonhosted.org/packages/5a/c6/ad82f148a4e3ce9564056453a71529732baf5448ad53fc323e37efe34f66/greenlet-3.2.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:86c2d68e87107c1792e2e8d5399acec2487a4e993ab76c792408e59394d52141", size = 655320, upload-time = "2025-06-05T16:12:53.453Z" }, + { url = "https://files.pythonhosted.org/packages/5c/4f/aab73ecaa6b3086a4c89863d94cf26fa84cbff63f52ce9bc4342b3087a06/greenlet-3.2.3-cp314-cp314-win_amd64.whl", hash = "sha256:8c47aae8fbbfcf82cc13327ae802ba13c9c36753b67e760023fd116bc124a62a", size = 301236, upload-time = "2025-06-05T16:15:20.111Z" }, +] + +[[package]] +name = "gurobipy" +version = "12.0.3" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/bb/b3784497115c64c2bd122cc9d411f167026d4ec42a26b1ff3c43a779275d/gurobipy-12.0.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:020f23277f630e079eac114385eabd1bd9fb4ac22f8796ed5ba6d915ce4f141b", size = 12222234, upload-time = "2025-07-15T07:19:24.64Z" }, + { url = "https://files.pythonhosted.org/packages/18/ea/c065984de5287c99fd30ee8d700fd78f83692e992471f9667ab5d36612b9/gurobipy-12.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:72bbf544bc05060bb93909b79715ace4c0f416198f7622a985cabb9e8e99aa1c", size = 62583866, upload-time = "2025-07-15T07:20:17.576Z" }, + { url = "https://files.pythonhosted.org/packages/9b/8b/2b9f26e4e19a258229b8a8ffc377ca372cc2059a22a0a7c67572efe308d8/gurobipy-12.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b3f971caf270f671b6ffcf5b937b3c0430a5264b0f01529dc8681d61c221f215", size = 14268480, upload-time = "2025-07-15T07:20:26.898Z" }, + { url = "https://files.pythonhosted.org/packages/26/0f/3544a323635f37cdfe1e011d2903b7ef94ba18e10224fa1419f64d0c1968/gurobipy-12.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:af18fd03d5dc3f6e5f590c372ad288b8430a6d88a5b5e66cfcd8432f86ee8650", size = 11121565, upload-time = "2025-07-15T07:20:34.576Z" }, + { url = "https://files.pythonhosted.org/packages/5e/95/f0e5b5cf85298f42482cf4e53d8114c45bb962f55195d531fe4e62b5afa1/gurobipy-12.0.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a8552e47673cb6f1fd351edf8fcad86b02f832cbfb57d90ef21e0397e96d138e", size = 12183439, upload-time = "2025-07-15T07:20:44.224Z" }, + { url = "https://files.pythonhosted.org/packages/61/6e/aea725b4143faa4eb6878414a91fa74e7871aba0ab9453803a9eeef781c2/gurobipy-12.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:be05c074141c8a126c8aaeccc41795ab091a666eabb39ca1ff98a74bde81e663", size = 62583451, upload-time = "2025-07-15T07:21:38.825Z" }, + { url = "https://files.pythonhosted.org/packages/75/47/7b9c63ce2cd85d796403b91a6d211d5c8baac7b694edd94e2151f365d6a9/gurobipy-12.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:79a333766e27fef7902ceeefbcf0279a1ca393a27a72ea62f8e301b21aa17d59", size = 14271076, upload-time = "2025-07-15T07:21:55.102Z" }, + { url = "https://files.pythonhosted.org/packages/2a/93/b10cd6112c05675fed5c817fd7933c9d4ba3a7039e42cba844a9ac09242a/gurobipy-12.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:e0f9ed55077e622021369bb9df2ca3b00c86b678792a3b1556cc59f67348fab0", size = 11111414, upload-time = "2025-07-15T07:22:05.079Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "h2" +version = "4.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "hpack" }, + { name = "hyperframe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1b/38/d7f80fd13e6582fb8e0df8c9a653dcc02b03ca34f4d72f34869298c5baf8/h2-4.2.0.tar.gz", hash = "sha256:c8a52129695e88b1a0578d8d2cc6842bbd79128ac685463b887ee278126ad01f", size = 2150682, upload-time = "2025-02-02T07:43:51.815Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/9e/984486f2d0a0bd2b024bf4bc1c62688fcafa9e61991f041fb0e2def4a982/h2-4.2.0-py3-none-any.whl", hash = "sha256:479a53ad425bb29af087f3458a61d30780bc818e4ebcf01f0b536ba916462ed0", size = 60957, upload-time = "2025-02-01T11:02:26.481Z" }, +] + +[[package]] +name = "highspy" +version = "1.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b4/fc/aa1325331c320598ce60cc31060087681cd05123b6fb2a8a571e882b7f05/highspy-1.11.0.tar.gz", hash = "sha256:771e58c076122d207ff1b19759c21d3227f0da5b80dfd89a4145681524969cef", size = 1285415, upload-time = "2025-06-06T00:47:22.562Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/ad/b54ad6740b950faab3b7f1465fbb5c740fc522928a8d9f01cac181f8f9a6/highspy-1.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28fffd3e733833a7b2569df6761088046e8aca868ab328828711dbe15b102ad4", size = 2232856, upload-time = "2025-06-06T00:46:11.161Z" }, + { url = "https://files.pythonhosted.org/packages/a3/0c/3921a207f47d52abc81a9d00d8f4d579b05b85670e23bc7140e39268490d/highspy-1.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:20a3adf8820a5f7a9cee6fc76df625e651ecfd8b5898af2a77042e79269ce0bc", size = 1908641, upload-time = "2025-06-06T00:46:12.706Z" }, + { url = "https://files.pythonhosted.org/packages/0a/b6/ea7ea6c4c3f781b007fe928b2aefa40c49287b4689985d04c3b20d383475/highspy-1.11.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d4bc0a84cf613bb8565f9b5f610eb0655384162f509b5d86f9c888570275fdc", size = 2119574, upload-time = "2025-06-06T00:46:14.261Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0c/94f1ccb6606e8445a7a0c68d983e47f64899582c64fcea651f488eaaaea0/highspy-1.11.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:543789b75c396a904cb550de34eb333f1a184e123dadc9903b5e6dbca18a007b", size = 2441487, upload-time = "2025-06-06T00:46:16.286Z" }, + { url = "https://files.pythonhosted.org/packages/ad/aa/e7c4ac05162187c484bb121f50d8e037c13bf894ed5cf4e781e1cff68762/highspy-1.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a23949e4f44b6df0ed8c387a7c733d683a0fa66e3ff15d65719979ce2099ee99", size = 2302302, upload-time = "2025-06-06T00:46:18.819Z" }, + { url = "https://files.pythonhosted.org/packages/04/ce/fd2473bed635eb06d116f987767d5c5fe3c62b317fb1a788c31966d7fa0a/highspy-1.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:50dacf300ebe7c4dca92891c0bf61b694f2ca744207cf7d0d24f2a30ffb5608c", size = 3101885, upload-time = "2025-06-06T00:46:20.774Z" }, + { url = "https://files.pythonhosted.org/packages/6e/e1/bf174389656de5d302ed53dd5cdeb5f7e9ad84156ad2fc95d5a63ba023f2/highspy-1.11.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a782c242b4b047f86110787b0dafce9d77cc10f079adab1fd51c5331e5760127", size = 3647952, upload-time = "2025-06-06T00:46:22.847Z" }, + { url = "https://files.pythonhosted.org/packages/f3/f5/42f6f2ce99c5b9d7aa864ac3abeaf8a2b66da707821ab42b0a31ec2a0dc1/highspy-1.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:15b804387089a389e5f01b056a4b3ad74c7d1cf00ab00a0faaf3b4a582bb664c", size = 3309616, upload-time = "2025-06-06T00:46:24.888Z" }, + { url = "https://files.pythonhosted.org/packages/47/f5/cf13640ed65ea934b45e0c3e786497f4696f286faf45e8e62579a0f15462/highspy-1.11.0-cp312-cp312-win32.whl", hash = "sha256:8c33f68df8ab9666d379b0d64d04775c0a9db31882d4f87b3ec8cece0003b47d", size = 1710641, upload-time = "2025-06-06T00:46:26.462Z" }, + { url = "https://files.pythonhosted.org/packages/b7/2f/7acfea5b8d32b86bdec018f858bc195236b804a22a7cd3349da711498692/highspy-1.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0aed8c80d33e2fc2eb1def75dbd34c9fa463acb589d19a5ed5dcc0178ae7062", size = 1985767, upload-time = "2025-06-06T00:46:28.144Z" }, + { url = "https://files.pythonhosted.org/packages/96/84/3e899c5d95dc9d5400a308e0aaf4a5143f69016a4f46dd528ff7cd65d341/highspy-1.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f675cda73860c7c8a22546db3c80db985720baea84866b08a971cfa03cc7a156", size = 2232867, upload-time = "2025-06-06T00:46:29.651Z" }, + { url = "https://files.pythonhosted.org/packages/74/e2/2853095a74e9fc2c2081340647be8edba7122696534ebbaf159ceb53f9b4/highspy-1.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7babebfc01b7682c69c95e0520614ec9400e10cec1b84d3fb7cd48535c606244", size = 1908601, upload-time = "2025-06-06T00:46:31.232Z" }, + { url = "https://files.pythonhosted.org/packages/e6/36/3cabdd3ae8610912962bad96f4d4d6702255d6c01d050754e4050a9eaa4a/highspy-1.11.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39fb60d84d7a58e58f923ea6f0641e6978eb9049033b84de1a2add723e01cd3f", size = 2119726, upload-time = "2025-06-06T00:46:32.796Z" }, + { url = "https://files.pythonhosted.org/packages/a9/da/200d3f13ca9ad3f9fc11a1f3f76cc2734de42dae064510365d42caeb5ed4/highspy-1.11.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c2e7cf4d504287cd8910de322a726d58428af43bb985d6bae602bf84a7454b9", size = 2441449, upload-time = "2025-06-06T00:46:35.147Z" }, + { url = "https://files.pythonhosted.org/packages/6c/58/fc3775850dc668006039637a4f23f03a9c0eb533643c9d3a7370f9d63de2/highspy-1.11.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79682aa7855d94106ccbbb750082d156dcbb57dff9d489f167320ae0ce768867", size = 2302685, upload-time = "2025-06-06T00:46:36.791Z" }, + { url = "https://files.pythonhosted.org/packages/b5/16/e13326a9706c407d32e39ad14aa79a696c1eb49bb13d50fde5d96afb02b5/highspy-1.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:65232aa496fb27be56cc85b2c7c785fac866107c32ea00cc38ec474d6a9f6494", size = 3102306, upload-time = "2025-06-06T00:46:38.341Z" }, + { url = "https://files.pythonhosted.org/packages/0e/93/468e63b16d9bf123174e7f8f7b8bd5a2f96b18d7370a2cc35e6485871749/highspy-1.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f78f27e18275d3c7868dcd0314ea535ed361322e7f0817363872d75a4cc15abc", size = 3648234, upload-time = "2025-06-06T00:46:40.895Z" }, + { url = "https://files.pythonhosted.org/packages/dc/c5/37b849a69c9cbccf533a9a51e309a49e83d704f06bf45370c2e78ceb15d4/highspy-1.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6156a7d643268456427b6fe310626ad9ee9d908ff812cc64ee8bad7b9872ea98", size = 3309724, upload-time = "2025-06-06T00:46:43.083Z" }, + { url = "https://files.pythonhosted.org/packages/90/0f/89c579b2f718dc419fd76067a03ecb3c96e6919b7cffee1b9f5a2dfe4f56/highspy-1.11.0-cp313-cp313-win32.whl", hash = "sha256:e61facebb0127eb3661db79a11c7665e47229ec63d2b425996d04aeede26d46b", size = 1710676, upload-time = "2025-06-06T00:46:45.132Z" }, + { url = "https://files.pythonhosted.org/packages/20/ca/ba2af91f2418bee0d0e99df71dcd171ca863675de6a5260bbf06c120f084/highspy-1.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:ceac08be37f75dc0af95669a0cfb073e5db5f07ead05cdcc81fd4b4394708d53", size = 1985967, upload-time = "2025-06-06T00:46:46.767Z" }, +] + +[[package]] +name = "hpack" +version = "4.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/48/71de9ed269fdae9c8057e5a4c0aa7402e8bb16f2c6e90b3aa53327b113f8/hpack-4.1.0.tar.gz", hash = "sha256:ec5eca154f7056aa06f196a557655c5b009b382873ac8d1e66e79e87535f1dca", size = 51276, upload-time = "2025-01-22T21:44:58.347Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/c6/80c95b1b2b94682a72cbdbfb85b81ae2daffa4291fbfa1b1464502ede10d/hpack-4.1.0-py3-none-any.whl", hash = "sha256:157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496", size = 34357, upload-time = "2025-01-22T21:44:56.92Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[package.optional-dependencies] +http2 = [ + { name = "h2" }, +] + +[[package]] +name = "hyperframe" +version = "6.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/02/e7/94f8232d4a74cc99514c13a9f995811485a6903d48e5d952771ef6322e30/hyperframe-6.1.0.tar.gz", hash = "sha256:f630908a00854a7adeabd6382b43923a4c4cd4b821fcb527e6ab9e15382a3b08", size = 26566, upload-time = "2025-01-22T21:41:49.302Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl", hash = "sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5", size = 13007, upload-time = "2025-01-22T21:41:47.295Z" }, +] + +[[package]] +name = "iam-units" +version = "2023.9.12" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pint" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cb/24/7c77cbbbdc077954c89d2a110c4847a0ab5fed61f5c7bc704274eda22912/iam_units-2023.9.12.tar.gz", hash = "sha256:89cfbcf5ab88d0dfd0b0639cabffe29ddf9f967f851184b3f3d86cd5ba7f43c9", size = 60039, upload-time = "2023-09-12T11:06:51.165Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/78/3335cc52bc960c567328ed4a62ca030d93a98e393e75c127ac130fc8bbb3/iam_units-2023.9.12-py3-none-any.whl", hash = "sha256:dbd6065d6a991796ff7cfaf63a8e46c5d3b264d532a567251dd1f57d5d44547a", size = 49408, upload-time = "2023-09-12T11:06:49.37Z" }, +] + +[[package]] +name = "identify" +version = "2.6.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/88/d193a27416618628a5eea64e3223acd800b40749a96ffb322a9b55a49ed1/identify-2.6.12.tar.gz", hash = "sha256:d8de45749f1efb108badef65ee8386f0f7bb19a7f26185f74de6367bffbaf0e6", size = 99254, upload-time = "2025-05-23T20:37:53.3Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/cd/18f8da995b658420625f7ef13f037be53ae04ec5ad33f9b718240dcfd48c/identify-2.6.12-py2.py3-none-any.whl", hash = "sha256:ad9672d5a72e0d2ff7c5c8809b62dfa60458626352fb0eb7b55e69bdc45334a2", size = 99145, upload-time = "2025-05-23T20:37:51.495Z" }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, +] + +[[package]] +name = "imagesize" +version = "1.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026, upload-time = "2022-07-01T12:21:05.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769, upload-time = "2022-07-01T12:21:02.467Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, +] + +[[package]] +name = "ipykernel" +version = "6.29.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "appnope", marker = "sys_platform == 'darwin'" }, + { name = "comm" }, + { name = "debugpy" }, + { name = "ipython" }, + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "matplotlib-inline" }, + { name = "nest-asyncio" }, + { name = "packaging" }, + { name = "psutil" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/5c/67594cb0c7055dc50814b21731c22a601101ea3b1b50a9a1b090e11f5d0f/ipykernel-6.29.5.tar.gz", hash = "sha256:f093a22c4a40f8828f8e330a9c297cb93dcab13bd9678ded6de8e5cf81c56215", size = 163367, upload-time = "2024-07-01T14:07:22.543Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/5c/368ae6c01c7628438358e6d337c19b05425727fbb221d2a3c4303c372f42/ipykernel-6.29.5-py3-none-any.whl", hash = "sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5", size = 117173, upload-time = "2024-07-01T14:07:19.603Z" }, +] + +[[package]] +name = "ipython" +version = "9.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "decorator" }, + { name = "ipython-pygments-lexers" }, + { name = "jedi" }, + { name = "matplotlib-inline" }, + { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "prompt-toolkit" }, + { name = "pygments" }, + { name = "stack-data" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/54/80/406f9e3bde1c1fd9bf5a0be9d090f8ae623e401b7670d8f6fdf2ab679891/ipython-9.4.0.tar.gz", hash = "sha256:c033c6d4e7914c3d9768aabe76bbe87ba1dc66a92a05db6bfa1125d81f2ee270", size = 4385338, upload-time = "2025-07-01T11:11:30.606Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/f8/0031ee2b906a15a33d6bfc12dd09c3dfa966b3cb5b284ecfb7549e6ac3c4/ipython-9.4.0-py3-none-any.whl", hash = "sha256:25850f025a446d9b359e8d296ba175a36aedd32e83ca9b5060430fe16801f066", size = 611021, upload-time = "2025-07-01T11:11:27.85Z" }, +] + +[[package]] +name = "ipython-genutils" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/69/fbeffffc05236398ebfcfb512b6d2511c622871dca1746361006da310399/ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8", size = 22208, upload-time = "2017-03-13T22:12:26.393Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/bc/9bd3b5c2b4774d5f33b2d544f1460be9df7df2fe42f352135381c347c69a/ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8", size = 26343, upload-time = "2017-03-13T22:12:25.412Z" }, +] + +[[package]] +name = "ipython-pygments-lexers" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" }, +] + +[[package]] +name = "ipywidgets" +version = "8.1.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "comm" }, + { name = "ipython" }, + { name = "jupyterlab-widgets" }, + { name = "traitlets" }, + { name = "widgetsnbextension" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3e/48/d3dbac45c2814cb73812f98dd6b38bbcc957a4e7bb31d6ea9c03bf94ed87/ipywidgets-8.1.7.tar.gz", hash = "sha256:15f1ac050b9ccbefd45dccfbb2ef6bed0029d8278682d569d71b8dd96bee0376", size = 116721, upload-time = "2025-05-05T12:42:03.489Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/6a/9166369a2f092bd286d24e6307de555d63616e8ddb373ebad2b5635ca4cd/ipywidgets-8.1.7-py3-none-any.whl", hash = "sha256:764f2602d25471c213919b8a1997df04bef869251db4ca8efba1b76b1bd9f7bb", size = 139806, upload-time = "2025-05-05T12:41:56.833Z" }, +] + +[[package]] +name = "isoduration" +version = "20.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "arrow" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7c/1a/3c8edc664e06e6bd06cce40c6b22da5f1429aa4224d0c590f3be21c91ead/isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", size = 11649, upload-time = "2020-11-01T11:00:00.312Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321, upload-time = "2020-11-01T10:59:58.02Z" }, +] + +[[package]] +name = "ixmp4" +version = "0.11.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "alembic" }, + { name = "fastapi" }, + { name = "httpx", extra = ["http2"] }, + { name = "openpyxl" }, + { name = "pandas" }, + { name = "pandera" }, + { name = "psycopg", extra = ["binary"] }, + { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "pyjwt" }, + { name = "python-dotenv" }, + { name = "rich" }, + { name = "sqlalchemy", extra = ["mypy"] }, + { name = "sqlalchemy-continuum" }, + { name = "sqlalchemy-utils" }, + { name = "toml" }, + { name = "typer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/e5/ad234fadbb0cd0fbe89b8c1eb23cf1797a1f1b56d34f235bf01efcaf94e8/ixmp4-0.11.1.tar.gz", hash = "sha256:8197ce437cbf32784ca6ae588eb09a17074e2c201c187bb14b3bbfe91a30ce19", size = 119459, upload-time = "2025-07-09T10:05:37.015Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ac/f2/20254152f70c1388e628625a76bd098bd295bdd8c2d4ddd7491c2a495994/ixmp4-0.11.1-py3-none-any.whl", hash = "sha256:c4033554c58ba5fa19cdf3159b3925520de9af37003d96027c2a709590b9841b", size = 246401, upload-time = "2025-07-09T10:05:35.009Z" }, +] + +[[package]] +name = "jedi" +version = "0.19.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "parso" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "joblib" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/fe/0f5a938c54105553436dbff7a61dc4fed4b1b2c98852f8833beaf4d5968f/joblib-1.5.1.tar.gz", hash = "sha256:f4f86e351f39fe3d0d32a9f2c3d8af1ee4cec285aafcb27003dda5205576b444", size = 330475, upload-time = "2025-05-23T12:04:37.097Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/4f/1195bbac8e0c2acc5f740661631d8d750dc38d4a32b23ee5df3cde6f4e0d/joblib-1.5.1-py3-none-any.whl", hash = "sha256:4719a31f054c7d766948dcd83e9613686b27114f190f717cec7eaa2084f8a74a", size = 307746, upload-time = "2025-05-23T12:04:35.124Z" }, +] + +[[package]] +name = "json5" +version = "0.12.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/12/be/c6c745ec4c4539b25a278b70e29793f10382947df0d9efba2fa09120895d/json5-0.12.0.tar.gz", hash = "sha256:0b4b6ff56801a1c7dc817b0241bca4ce474a0e6a163bfef3fc594d3fd263ff3a", size = 51907, upload-time = "2025-04-03T16:33:13.201Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/9f/3500910d5a98549e3098807493851eeef2b89cdd3032227558a104dfe926/json5-0.12.0-py3-none-any.whl", hash = "sha256:6d37aa6c08b0609f16e1ec5ff94697e2cbbfbad5ac112afa05794da9ab7810db", size = 36079, upload-time = "2025-04-03T16:33:11.927Z" }, +] + +[[package]] +name = "jsonpointer" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, +] + +[[package]] +name = "jsonschema" +version = "4.24.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bf/d3/1cf5326b923a53515d8f3a2cd442e6d7e94fcc444716e879ea70a0ce3177/jsonschema-4.24.0.tar.gz", hash = "sha256:0b4e8069eb12aedfa881333004bccaec24ecef5a8a6a4b6df142b2cc9599d196", size = 353480, upload-time = "2025-05-26T18:48:10.459Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/3d/023389198f69c722d039351050738d6755376c8fd343e91dc493ea485905/jsonschema-4.24.0-py3-none-any.whl", hash = "sha256:a462455f19f5faf404a7902952b6f0e3ce868f3ee09a359b05eca6673bd8412d", size = 88709, upload-time = "2025-05-26T18:48:08.417Z" }, +] + +[package.optional-dependencies] +format-nongpl = [ + { name = "fqdn" }, + { name = "idna" }, + { name = "isoduration" }, + { name = "jsonpointer" }, + { name = "rfc3339-validator" }, + { name = "rfc3986-validator" }, + { name = "uri-template" }, + { name = "webcolors" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2025.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bf/ce/46fbd9c8119cfc3581ee5643ea49464d168028cfb5caff5fc0596d0cf914/jsonschema_specifications-2025.4.1.tar.gz", hash = "sha256:630159c9f4dbea161a6a2205c3011cc4f18ff381b189fff48bb39b9bf26ae608", size = 15513, upload-time = "2025-04-23T12:34:07.418Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/01/0e/b27cdbaccf30b890c40ed1da9fd4a3593a5cf94dae54fb34f8a4b74fcd3f/jsonschema_specifications-2025.4.1-py3-none-any.whl", hash = "sha256:4653bffbd6584f7de83a67e0d620ef16900b390ddc7939d56684d6c81e33f1af", size = 18437, upload-time = "2025-04-23T12:34:05.422Z" }, +] + +[[package]] +name = "jupyter" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ipykernel" }, + { name = "ipywidgets" }, + { name = "jupyter-console" }, + { name = "jupyterlab" }, + { name = "nbconvert" }, + { name = "notebook" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/f3/af28ea964ab8bc1e472dba2e82627d36d470c51f5cd38c37502eeffaa25e/jupyter-1.1.1.tar.gz", hash = "sha256:d55467bceabdea49d7e3624af7e33d59c37fff53ed3a350e1ac957bed731de7a", size = 5714959, upload-time = "2024-08-30T07:15:48.299Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl", hash = "sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83", size = 2657, upload-time = "2024-08-30T07:15:47.045Z" }, +] + +[[package]] +name = "jupyter-client" +version = "8.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-core" }, + { name = "python-dateutil" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/22/bf9f12fdaeae18019a468b68952a60fe6dbab5d67cd2a103cac7659b41ca/jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419", size = 342019, upload-time = "2024-09-17T10:44:17.613Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/85/b0394e0b6fcccd2c1eeefc230978a6f8cb0c5df1e4cd3e7625735a0d7d1e/jupyter_client-8.6.3-py3-none-any.whl", hash = "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f", size = 106105, upload-time = "2024-09-17T10:44:15.218Z" }, +] + +[[package]] +name = "jupyter-console" +version = "6.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ipykernel" }, + { name = "ipython" }, + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "prompt-toolkit" }, + { name = "pygments" }, + { name = "pyzmq" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bd/2d/e2fd31e2fc41c14e2bcb6c976ab732597e907523f6b2420305f9fc7fdbdb/jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539", size = 34363, upload-time = "2023-03-06T14:13:31.02Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485", size = 24510, upload-time = "2023-03-06T14:13:28.229Z" }, +] + +[[package]] +name = "jupyter-contrib-core" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-core" }, + { name = "notebook" }, + { name = "setuptools" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/94/0d37e5b49ea1c8bf204c46f9b0257c1f3319a4ab88acbd401da2cab25e55/jupyter_contrib_core-0.4.2.tar.gz", hash = "sha256:1887212f3ca9d4487d624c0705c20dfdf03d5a0b9ea2557d3aaeeb4c38bdcabb", size = 17490, upload-time = "2022-11-15T16:21:53.357Z" } + +[[package]] +name = "jupyter-contrib-nbextensions" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ipython-genutils" }, + { name = "jupyter-contrib-core" }, + { name = "jupyter-core" }, + { name = "jupyter-highlight-selected-word" }, + { name = "jupyter-nbextensions-configurator" }, + { name = "lxml" }, + { name = "nbconvert" }, + { name = "notebook" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/91/78cc4362611dbde2b0cd068204aaf1b8899d0459c50d8ff9daca8c069791/jupyter_contrib_nbextensions-0.7.0.tar.gz", hash = "sha256:06e33f005885eb92f89cbe82711e921278201298d08ab0d886d1ba09e8c3e9ca", size = 23462252, upload-time = "2022-11-15T17:31:27.754Z" } + +[[package]] +name = "jupyter-core" +version = "5.8.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "platformdirs" }, + { name = "pywin32", marker = "platform_python_implementation != 'PyPy' and sys_platform == 'win32'" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/99/1b/72906d554acfeb588332eaaa6f61577705e9ec752ddb486f302dafa292d9/jupyter_core-5.8.1.tar.gz", hash = "sha256:0a5f9706f70e64786b75acba995988915ebd4601c8a52e534a40b51c95f59941", size = 88923, upload-time = "2025-05-27T07:38:16.655Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2f/57/6bffd4b20b88da3800c5d691e0337761576ee688eb01299eae865689d2df/jupyter_core-5.8.1-py3-none-any.whl", hash = "sha256:c28d268fc90fb53f1338ded2eb410704c5449a358406e8a948b75706e24863d0", size = 28880, upload-time = "2025-05-27T07:38:15.137Z" }, +] + +[[package]] +name = "jupyter-events" +version = "0.12.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonschema", extra = ["format-nongpl"] }, + { name = "packaging" }, + { name = "python-json-logger" }, + { name = "pyyaml" }, + { name = "referencing" }, + { name = "rfc3339-validator" }, + { name = "rfc3986-validator" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9d/c3/306d090461e4cf3cd91eceaff84bede12a8e52cd821c2d20c9a4fd728385/jupyter_events-0.12.0.tar.gz", hash = "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b", size = 62196, upload-time = "2025-02-03T17:23:41.485Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl", hash = "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb", size = 19430, upload-time = "2025-02-03T17:23:38.643Z" }, +] + +[[package]] +name = "jupyter-highlight-selected-word" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/a5/3dfeb7c8643ef502e82969fdebb201b63b33ded15a7761b27299bacebc3a/jupyter_highlight_selected_word-0.2.0.tar.gz", hash = "sha256:9fa740424859a807950ca08d2bfd28a35154cd32dd6d50ac4e0950022adc0e7b", size = 12592, upload-time = "2018-04-07T13:56:22.498Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/50/d7/19ab7cfd60bf268d2abbacc52d4295a40f52d74dfc0d938e4761ee5e598b/jupyter_highlight_selected_word-0.2.0-py2.py3-none-any.whl", hash = "sha256:9545dfa9cb057eebe3a5795604dcd3a5294ea18637e553f61a0b67c1b5903c58", size = 11699, upload-time = "2018-04-07T13:56:20.715Z" }, +] + +[[package]] +name = "jupyter-lsp" +version = "2.2.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-server" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/85/b4/3200b0b09c12bc3b72d943d923323c398eff382d1dcc7c0dbc8b74630e40/jupyter-lsp-2.2.5.tar.gz", hash = "sha256:793147a05ad446f809fd53ef1cd19a9f5256fd0a2d6b7ce943a982cb4f545001", size = 48741, upload-time = "2024-04-09T17:59:44.918Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/e0/7bd7cff65594fd9936e2f9385701e44574fc7d721331ff676ce440b14100/jupyter_lsp-2.2.5-py3-none-any.whl", hash = "sha256:45fbddbd505f3fbfb0b6cb2f1bc5e15e83ab7c79cd6e89416b248cb3c00c11da", size = 69146, upload-time = "2024-04-09T17:59:43.388Z" }, +] + +[[package]] +name = "jupyter-nbextensions-configurator" +version = "0.6.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-contrib-core" }, + { name = "jupyter-core" }, + { name = "jupyter-server" }, + { name = "notebook" }, + { name = "pyyaml" }, + { name = "tornado" }, + { name = "traitlets" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/fe/cffb14a4fbb43cf276aa3047e42c3f9ecfda851ba3c466295401f6b1e085/jupyter_nbextensions_configurator-0.6.4-py2.py3-none-any.whl", hash = "sha256:fe7a7b0805b5926449692fb077e0e659bab8b27563bc68cba26854532fdf99c7", size = 466890, upload-time = "2024-06-05T16:08:37.236Z" }, +] + +[[package]] +name = "jupyter-server" +version = "2.16.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "argon2-cffi" }, + { name = "jinja2" }, + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "jupyter-events" }, + { name = "jupyter-server-terminals" }, + { name = "nbconvert" }, + { name = "nbformat" }, + { name = "overrides" }, + { name = "packaging" }, + { name = "prometheus-client" }, + { name = "pywinpty", marker = "os_name == 'nt'" }, + { name = "pyzmq" }, + { name = "send2trash" }, + { name = "terminado" }, + { name = "tornado" }, + { name = "traitlets" }, + { name = "websocket-client" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/41/c8/ba2bbcd758c47f1124c4ca14061e8ce60d9c6fd537faee9534a95f83521a/jupyter_server-2.16.0.tar.gz", hash = "sha256:65d4b44fdf2dcbbdfe0aa1ace4a842d4aaf746a2b7b168134d5aaed35621b7f6", size = 728177, upload-time = "2025-05-12T16:44:46.245Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/1f/5ebbced977171d09a7b0c08a285ff9a20aafb9c51bde07e52349ff1ddd71/jupyter_server-2.16.0-py3-none-any.whl", hash = "sha256:3d8db5be3bc64403b1c65b400a1d7f4647a5ce743f3b20dbdefe8ddb7b55af9e", size = 386904, upload-time = "2025-05-12T16:44:43.335Z" }, +] + +[[package]] +name = "jupyter-server-terminals" +version = "0.5.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pywinpty", marker = "os_name == 'nt'" }, + { name = "terminado" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/d5/562469734f476159e99a55426d697cbf8e7eb5efe89fb0e0b4f83a3d3459/jupyter_server_terminals-0.5.3.tar.gz", hash = "sha256:5ae0295167220e9ace0edcfdb212afd2b01ee8d179fe6f23c899590e9b8a5269", size = 31430, upload-time = "2024-03-12T14:37:03.049Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/2d/2b32cdbe8d2a602f697a649798554e4f072115438e92249624e532e8aca6/jupyter_server_terminals-0.5.3-py3-none-any.whl", hash = "sha256:41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa", size = 13656, upload-time = "2024-03-12T14:37:00.708Z" }, +] + +[[package]] +name = "jupyterlab" +version = "4.4.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "async-lru" }, + { name = "httpx" }, + { name = "ipykernel" }, + { name = "jinja2" }, + { name = "jupyter-core" }, + { name = "jupyter-lsp" }, + { name = "jupyter-server" }, + { name = "jupyterlab-server" }, + { name = "notebook-shim" }, + { name = "packaging" }, + { name = "setuptools" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e2/4d/7ca5b46ea56742880d71a768a9e6fb8f8482228427eb89492d55c5d0bb7d/jupyterlab-4.4.4.tar.gz", hash = "sha256:163fee1ef702e0a057f75d2eed3ed1da8a986d59eb002cbeb6f0c2779e6cd153", size = 23044296, upload-time = "2025-06-28T13:07:20.708Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/82/66910ce0995dbfdb33609f41c99fe32ce483b9624a3e7d672af14ff63b9f/jupyterlab-4.4.4-py3-none-any.whl", hash = "sha256:711611e4f59851152eb93316c3547c3ec6291f16bb455f1f4fa380d25637e0dd", size = 12296310, upload-time = "2025-06-28T13:07:15.676Z" }, +] + +[[package]] +name = "jupyterlab-pygments" +version = "0.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/90/51/9187be60d989df97f5f0aba133fa54e7300f17616e065d1ada7d7646b6d6/jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", size = 512900, upload-time = "2023-11-23T09:26:37.44Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", size = 15884, upload-time = "2023-11-23T09:26:34.325Z" }, +] + +[[package]] +name = "jupyterlab-server" +version = "2.27.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "babel" }, + { name = "jinja2" }, + { name = "json5" }, + { name = "jsonschema" }, + { name = "jupyter-server" }, + { name = "packaging" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0a/c9/a883ce65eb27905ce77ace410d83587c82ea64dc85a48d1f7ed52bcfa68d/jupyterlab_server-2.27.3.tar.gz", hash = "sha256:eb36caca59e74471988f0ae25c77945610b887f777255aa21f8065def9e51ed4", size = 76173, upload-time = "2024-07-16T17:02:04.149Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/09/2032e7d15c544a0e3cd831c51d77a8ca57f7555b2e1b2922142eddb02a84/jupyterlab_server-2.27.3-py3-none-any.whl", hash = "sha256:e697488f66c3db49df675158a77b3b017520d772c6e1548c7d9bcc5df7944ee4", size = 59700, upload-time = "2024-07-16T17:02:01.115Z" }, +] + +[[package]] +name = "jupyterlab-widgets" +version = "3.0.15" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b9/7d/160595ca88ee87ac6ba95d82177d29ec60aaa63821d3077babb22ce031a5/jupyterlab_widgets-3.0.15.tar.gz", hash = "sha256:2920888a0c2922351a9202817957a68c07d99673504d6cd37345299e971bb08b", size = 213149, upload-time = "2025-05-05T12:32:31.004Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/6a/ca128561b22b60bd5a0c4ea26649e68c8556b82bc70a0c396eebc977fe86/jupyterlab_widgets-3.0.15-py3-none-any.whl", hash = "sha256:d59023d7d7ef71400d51e6fee9a88867f6e65e10a4201605d2d7f3e8f012a31c", size = 216571, upload-time = "2025-05-05T12:32:29.534Z" }, +] + +[[package]] +name = "kiwisolver" +version = "1.4.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/59/7c91426a8ac292e1cdd53a63b6d9439abd573c875c3f92c146767dd33faf/kiwisolver-1.4.8.tar.gz", hash = "sha256:23d5f023bdc8c7e54eb65f03ca5d5bb25b601eac4d7f1a042888a1f45237987e", size = 97538, upload-time = "2024-12-24T18:30:51.519Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/aa/cea685c4ab647f349c3bc92d2daf7ae34c8e8cf405a6dcd3a497f58a2ac3/kiwisolver-1.4.8-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d6af5e8815fd02997cb6ad9bbed0ee1e60014438ee1a5c2444c96f87b8843502", size = 124152, upload-time = "2024-12-24T18:29:16.85Z" }, + { url = "https://files.pythonhosted.org/packages/c5/0b/8db6d2e2452d60d5ebc4ce4b204feeb16176a851fd42462f66ade6808084/kiwisolver-1.4.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bade438f86e21d91e0cf5dd7c0ed00cda0f77c8c1616bd83f9fc157fa6760d31", size = 66555, upload-time = "2024-12-24T18:29:19.146Z" }, + { url = "https://files.pythonhosted.org/packages/60/26/d6a0db6785dd35d3ba5bf2b2df0aedc5af089962c6eb2cbf67a15b81369e/kiwisolver-1.4.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b83dc6769ddbc57613280118fb4ce3cd08899cc3369f7d0e0fab518a7cf37fdb", size = 65067, upload-time = "2024-12-24T18:29:20.096Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ed/1d97f7e3561e09757a196231edccc1bcf59d55ddccefa2afc9c615abd8e0/kiwisolver-1.4.8-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:111793b232842991be367ed828076b03d96202c19221b5ebab421ce8bcad016f", size = 1378443, upload-time = "2024-12-24T18:29:22.843Z" }, + { url = "https://files.pythonhosted.org/packages/29/61/39d30b99954e6b46f760e6289c12fede2ab96a254c443639052d1b573fbc/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:257af1622860e51b1a9d0ce387bf5c2c4f36a90594cb9514f55b074bcc787cfc", size = 1472728, upload-time = "2024-12-24T18:29:24.463Z" }, + { url = "https://files.pythonhosted.org/packages/0c/3e/804163b932f7603ef256e4a715e5843a9600802bb23a68b4e08c8c0ff61d/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69b5637c3f316cab1ec1c9a12b8c5f4750a4c4b71af9157645bf32830e39c03a", size = 1478388, upload-time = "2024-12-24T18:29:25.776Z" }, + { url = "https://files.pythonhosted.org/packages/8a/9e/60eaa75169a154700be74f875a4d9961b11ba048bef315fbe89cb6999056/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:782bb86f245ec18009890e7cb8d13a5ef54dcf2ebe18ed65f795e635a96a1c6a", size = 1413849, upload-time = "2024-12-24T18:29:27.202Z" }, + { url = "https://files.pythonhosted.org/packages/bc/b3/9458adb9472e61a998c8c4d95cfdfec91c73c53a375b30b1428310f923e4/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc978a80a0db3a66d25767b03688f1147a69e6237175c0f4ffffaaedf744055a", size = 1475533, upload-time = "2024-12-24T18:29:28.638Z" }, + { url = "https://files.pythonhosted.org/packages/e4/7a/0a42d9571e35798de80aef4bb43a9b672aa7f8e58643d7bd1950398ffb0a/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:36dbbfd34838500a31f52c9786990d00150860e46cd5041386f217101350f0d3", size = 2268898, upload-time = "2024-12-24T18:29:30.368Z" }, + { url = "https://files.pythonhosted.org/packages/d9/07/1255dc8d80271400126ed8db35a1795b1a2c098ac3a72645075d06fe5c5d/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:eaa973f1e05131de5ff3569bbba7f5fd07ea0595d3870ed4a526d486fe57fa1b", size = 2425605, upload-time = "2024-12-24T18:29:33.151Z" }, + { url = "https://files.pythonhosted.org/packages/84/df/5a3b4cf13780ef6f6942df67b138b03b7e79e9f1f08f57c49957d5867f6e/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a66f60f8d0c87ab7f59b6fb80e642ebb29fec354a4dfad687ca4092ae69d04f4", size = 2375801, upload-time = "2024-12-24T18:29:34.584Z" }, + { url = "https://files.pythonhosted.org/packages/8f/10/2348d068e8b0f635c8c86892788dac7a6b5c0cb12356620ab575775aad89/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:858416b7fb777a53f0c59ca08190ce24e9abbd3cffa18886a5781b8e3e26f65d", size = 2520077, upload-time = "2024-12-24T18:29:36.138Z" }, + { url = "https://files.pythonhosted.org/packages/32/d8/014b89fee5d4dce157d814303b0fce4d31385a2af4c41fed194b173b81ac/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:085940635c62697391baafaaeabdf3dd7a6c3643577dde337f4d66eba021b2b8", size = 2338410, upload-time = "2024-12-24T18:29:39.991Z" }, + { url = "https://files.pythonhosted.org/packages/bd/72/dfff0cc97f2a0776e1c9eb5bef1ddfd45f46246c6533b0191887a427bca5/kiwisolver-1.4.8-cp312-cp312-win_amd64.whl", hash = "sha256:01c3d31902c7db5fb6182832713d3b4122ad9317c2c5877d0539227d96bb2e50", size = 71853, upload-time = "2024-12-24T18:29:42.006Z" }, + { url = "https://files.pythonhosted.org/packages/dc/85/220d13d914485c0948a00f0b9eb419efaf6da81b7d72e88ce2391f7aed8d/kiwisolver-1.4.8-cp312-cp312-win_arm64.whl", hash = "sha256:a3c44cb68861de93f0c4a8175fbaa691f0aa22550c331fefef02b618a9dcb476", size = 65424, upload-time = "2024-12-24T18:29:44.38Z" }, + { url = "https://files.pythonhosted.org/packages/79/b3/e62464a652f4f8cd9006e13d07abad844a47df1e6537f73ddfbf1bc997ec/kiwisolver-1.4.8-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1c8ceb754339793c24aee1c9fb2485b5b1f5bb1c2c214ff13368431e51fc9a09", size = 124156, upload-time = "2024-12-24T18:29:45.368Z" }, + { url = "https://files.pythonhosted.org/packages/8d/2d/f13d06998b546a2ad4f48607a146e045bbe48030774de29f90bdc573df15/kiwisolver-1.4.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a62808ac74b5e55a04a408cda6156f986cefbcf0ada13572696b507cc92fa1", size = 66555, upload-time = "2024-12-24T18:29:46.37Z" }, + { url = "https://files.pythonhosted.org/packages/59/e3/b8bd14b0a54998a9fd1e8da591c60998dc003618cb19a3f94cb233ec1511/kiwisolver-1.4.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:68269e60ee4929893aad82666821aaacbd455284124817af45c11e50a4b42e3c", size = 65071, upload-time = "2024-12-24T18:29:47.333Z" }, + { url = "https://files.pythonhosted.org/packages/f0/1c/6c86f6d85ffe4d0ce04228d976f00674f1df5dc893bf2dd4f1928748f187/kiwisolver-1.4.8-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34d142fba9c464bc3bbfeff15c96eab0e7310343d6aefb62a79d51421fcc5f1b", size = 1378053, upload-time = "2024-12-24T18:29:49.636Z" }, + { url = "https://files.pythonhosted.org/packages/4e/b9/1c6e9f6dcb103ac5cf87cb695845f5fa71379021500153566d8a8a9fc291/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc373e0eef45b59197de815b1b28ef89ae3955e7722cc9710fb91cd77b7f47", size = 1472278, upload-time = "2024-12-24T18:29:51.164Z" }, + { url = "https://files.pythonhosted.org/packages/ee/81/aca1eb176de671f8bda479b11acdc42c132b61a2ac861c883907dde6debb/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77e6f57a20b9bd4e1e2cedda4d0b986ebd0216236f0106e55c28aea3d3d69b16", size = 1478139, upload-time = "2024-12-24T18:29:52.594Z" }, + { url = "https://files.pythonhosted.org/packages/49/f4/e081522473671c97b2687d380e9e4c26f748a86363ce5af48b4a28e48d06/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08e77738ed7538f036cd1170cbed942ef749137b1311fa2bbe2a7fda2f6bf3cc", size = 1413517, upload-time = "2024-12-24T18:29:53.941Z" }, + { url = "https://files.pythonhosted.org/packages/8f/e9/6a7d025d8da8c4931522922cd706105aa32b3291d1add8c5427cdcd66e63/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5ce1e481a74b44dd5e92ff03ea0cb371ae7a0268318e202be06c8f04f4f1246", size = 1474952, upload-time = "2024-12-24T18:29:56.523Z" }, + { url = "https://files.pythonhosted.org/packages/82/13/13fa685ae167bee5d94b415991c4fc7bb0a1b6ebea6e753a87044b209678/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fc2ace710ba7c1dfd1a3b42530b62b9ceed115f19a1656adefce7b1782a37794", size = 2269132, upload-time = "2024-12-24T18:29:57.989Z" }, + { url = "https://files.pythonhosted.org/packages/ef/92/bb7c9395489b99a6cb41d502d3686bac692586db2045adc19e45ee64ed23/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:3452046c37c7692bd52b0e752b87954ef86ee2224e624ef7ce6cb21e8c41cc1b", size = 2425997, upload-time = "2024-12-24T18:29:59.393Z" }, + { url = "https://files.pythonhosted.org/packages/ed/12/87f0e9271e2b63d35d0d8524954145837dd1a6c15b62a2d8c1ebe0f182b4/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7e9a60b50fe8b2ec6f448fe8d81b07e40141bfced7f896309df271a0b92f80f3", size = 2376060, upload-time = "2024-12-24T18:30:01.338Z" }, + { url = "https://files.pythonhosted.org/packages/02/6e/c8af39288edbce8bf0fa35dee427b082758a4b71e9c91ef18fa667782138/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:918139571133f366e8362fa4a297aeba86c7816b7ecf0bc79168080e2bd79957", size = 2520471, upload-time = "2024-12-24T18:30:04.574Z" }, + { url = "https://files.pythonhosted.org/packages/13/78/df381bc7b26e535c91469f77f16adcd073beb3e2dd25042efd064af82323/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e063ef9f89885a1d68dd8b2e18f5ead48653176d10a0e324e3b0030e3a69adeb", size = 2338793, upload-time = "2024-12-24T18:30:06.25Z" }, + { url = "https://files.pythonhosted.org/packages/d0/dc/c1abe38c37c071d0fc71c9a474fd0b9ede05d42f5a458d584619cfd2371a/kiwisolver-1.4.8-cp313-cp313-win_amd64.whl", hash = "sha256:a17b7c4f5b2c51bb68ed379defd608a03954a1845dfed7cc0117f1cc8a9b7fd2", size = 71855, upload-time = "2024-12-24T18:30:07.535Z" }, + { url = "https://files.pythonhosted.org/packages/a0/b6/21529d595b126ac298fdd90b705d87d4c5693de60023e0efcb4f387ed99e/kiwisolver-1.4.8-cp313-cp313-win_arm64.whl", hash = "sha256:3cd3bc628b25f74aedc6d374d5babf0166a92ff1317f46267f12d2ed54bc1d30", size = 65430, upload-time = "2024-12-24T18:30:08.504Z" }, + { url = "https://files.pythonhosted.org/packages/34/bd/b89380b7298e3af9b39f49334e3e2a4af0e04819789f04b43d560516c0c8/kiwisolver-1.4.8-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:370fd2df41660ed4e26b8c9d6bbcad668fbe2560462cba151a721d49e5b6628c", size = 126294, upload-time = "2024-12-24T18:30:09.508Z" }, + { url = "https://files.pythonhosted.org/packages/83/41/5857dc72e5e4148eaac5aa76e0703e594e4465f8ab7ec0fc60e3a9bb8fea/kiwisolver-1.4.8-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:84a2f830d42707de1d191b9490ac186bf7997a9495d4e9072210a1296345f7dc", size = 67736, upload-time = "2024-12-24T18:30:11.039Z" }, + { url = "https://files.pythonhosted.org/packages/e1/d1/be059b8db56ac270489fb0b3297fd1e53d195ba76e9bbb30e5401fa6b759/kiwisolver-1.4.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7a3ad337add5148cf51ce0b55642dc551c0b9d6248458a757f98796ca7348712", size = 66194, upload-time = "2024-12-24T18:30:14.886Z" }, + { url = "https://files.pythonhosted.org/packages/e1/83/4b73975f149819eb7dcf9299ed467eba068ecb16439a98990dcb12e63fdd/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7506488470f41169b86d8c9aeff587293f530a23a23a49d6bc64dab66bedc71e", size = 1465942, upload-time = "2024-12-24T18:30:18.927Z" }, + { url = "https://files.pythonhosted.org/packages/c7/2c/30a5cdde5102958e602c07466bce058b9d7cb48734aa7a4327261ac8e002/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f0121b07b356a22fb0414cec4666bbe36fd6d0d759db3d37228f496ed67c880", size = 1595341, upload-time = "2024-12-24T18:30:22.102Z" }, + { url = "https://files.pythonhosted.org/packages/ff/9b/1e71db1c000385aa069704f5990574b8244cce854ecd83119c19e83c9586/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d6d6bd87df62c27d4185de7c511c6248040afae67028a8a22012b010bc7ad062", size = 1598455, upload-time = "2024-12-24T18:30:24.947Z" }, + { url = "https://files.pythonhosted.org/packages/85/92/c8fec52ddf06231b31cbb779af77e99b8253cd96bd135250b9498144c78b/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:291331973c64bb9cce50bbe871fb2e675c4331dab4f31abe89f175ad7679a4d7", size = 1522138, upload-time = "2024-12-24T18:30:26.286Z" }, + { url = "https://files.pythonhosted.org/packages/0b/51/9eb7e2cd07a15d8bdd976f6190c0164f92ce1904e5c0c79198c4972926b7/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:893f5525bb92d3d735878ec00f781b2de998333659507d29ea4466208df37bed", size = 1582857, upload-time = "2024-12-24T18:30:28.86Z" }, + { url = "https://files.pythonhosted.org/packages/0f/95/c5a00387a5405e68ba32cc64af65ce881a39b98d73cc394b24143bebc5b8/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b47a465040146981dc9db8647981b8cb96366fbc8d452b031e4f8fdffec3f26d", size = 2293129, upload-time = "2024-12-24T18:30:30.34Z" }, + { url = "https://files.pythonhosted.org/packages/44/83/eeb7af7d706b8347548313fa3a3a15931f404533cc54fe01f39e830dd231/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:99cea8b9dd34ff80c521aef46a1dddb0dcc0283cf18bde6d756f1e6f31772165", size = 2421538, upload-time = "2024-12-24T18:30:33.334Z" }, + { url = "https://files.pythonhosted.org/packages/05/f9/27e94c1b3eb29e6933b6986ffc5fa1177d2cd1f0c8efc5f02c91c9ac61de/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:151dffc4865e5fe6dafce5480fab84f950d14566c480c08a53c663a0020504b6", size = 2390661, upload-time = "2024-12-24T18:30:34.939Z" }, + { url = "https://files.pythonhosted.org/packages/d9/d4/3c9735faa36ac591a4afcc2980d2691000506050b7a7e80bcfe44048daa7/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:577facaa411c10421314598b50413aa1ebcf5126f704f1e5d72d7e4e9f020d90", size = 2546710, upload-time = "2024-12-24T18:30:37.281Z" }, + { url = "https://files.pythonhosted.org/packages/4c/fa/be89a49c640930180657482a74970cdcf6f7072c8d2471e1babe17a222dc/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:be4816dc51c8a471749d664161b434912eee82f2ea66bd7628bd14583a833e85", size = 2349213, upload-time = "2024-12-24T18:30:40.019Z" }, +] + +[[package]] +name = "latexcodec" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/27/dd/4270b2c5e2ee49316c3859e62293bd2ea8e382339d63ab7bbe9f39c0ec3b/latexcodec-3.0.1.tar.gz", hash = "sha256:e78a6911cd72f9dec35031c6ec23584de6842bfbc4610a9678868d14cdfb0357", size = 31222, upload-time = "2025-06-17T18:47:34.051Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b5/40/23569737873cc9637fd488606347e9dd92b9fa37ba4fcda1f98ee5219a97/latexcodec-3.0.1-py3-none-any.whl", hash = "sha256:a9eb8200bff693f0437a69581f7579eb6bca25c4193515c09900ce76451e452e", size = 18532, upload-time = "2025-06-17T18:47:30.726Z" }, +] + +[[package]] +name = "lxml" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c5/ed/60eb6fa2923602fba988d9ca7c5cdbd7cf25faa795162ed538b527a35411/lxml-6.0.0.tar.gz", hash = "sha256:032e65120339d44cdc3efc326c9f660f5f7205f3a535c1fdbf898b29ea01fb72", size = 4096938, upload-time = "2025-06-26T16:28:19.373Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/c3/d01d735c298d7e0ddcedf6f028bf556577e5ab4f4da45175ecd909c79378/lxml-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78718d8454a6e928470d511bf8ac93f469283a45c354995f7d19e77292f26108", size = 8429515, upload-time = "2025-06-26T16:26:06.776Z" }, + { url = "https://files.pythonhosted.org/packages/06/37/0e3eae3043d366b73da55a86274a590bae76dc45aa004b7042e6f97803b1/lxml-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:84ef591495ffd3f9dcabffd6391db7bb70d7230b5c35ef5148354a134f56f2be", size = 4601387, upload-time = "2025-06-26T16:26:09.511Z" }, + { url = "https://files.pythonhosted.org/packages/a3/28/e1a9a881e6d6e29dda13d633885d13acb0058f65e95da67841c8dd02b4a8/lxml-6.0.0-cp312-cp312-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:2930aa001a3776c3e2601cb8e0a15d21b8270528d89cc308be4843ade546b9ab", size = 5228928, upload-time = "2025-06-26T16:26:12.337Z" }, + { url = "https://files.pythonhosted.org/packages/9a/55/2cb24ea48aa30c99f805921c1c7860c1f45c0e811e44ee4e6a155668de06/lxml-6.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:219e0431ea8006e15005767f0351e3f7f9143e793e58519dc97fe9e07fae5563", size = 4952289, upload-time = "2025-06-28T18:47:25.602Z" }, + { url = "https://files.pythonhosted.org/packages/31/c0/b25d9528df296b9a3306ba21ff982fc5b698c45ab78b94d18c2d6ae71fd9/lxml-6.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bd5913b4972681ffc9718bc2d4c53cde39ef81415e1671ff93e9aa30b46595e7", size = 5111310, upload-time = "2025-06-28T18:47:28.136Z" }, + { url = "https://files.pythonhosted.org/packages/e9/af/681a8b3e4f668bea6e6514cbcb297beb6de2b641e70f09d3d78655f4f44c/lxml-6.0.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:390240baeb9f415a82eefc2e13285016f9c8b5ad71ec80574ae8fa9605093cd7", size = 5025457, upload-time = "2025-06-26T16:26:15.068Z" }, + { url = "https://files.pythonhosted.org/packages/99/b6/3a7971aa05b7be7dfebc7ab57262ec527775c2c3c5b2f43675cac0458cad/lxml-6.0.0-cp312-cp312-manylinux_2_27_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d6e200909a119626744dd81bae409fc44134389e03fbf1d68ed2a55a2fb10991", size = 5657016, upload-time = "2025-07-03T19:19:06.008Z" }, + { url = "https://files.pythonhosted.org/packages/69/f8/693b1a10a891197143c0673fcce5b75fc69132afa81a36e4568c12c8faba/lxml-6.0.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ca50bd612438258a91b5b3788c6621c1f05c8c478e7951899f492be42defc0da", size = 5257565, upload-time = "2025-06-26T16:26:17.906Z" }, + { url = "https://files.pythonhosted.org/packages/a8/96/e08ff98f2c6426c98c8964513c5dab8d6eb81dadcd0af6f0c538ada78d33/lxml-6.0.0-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:c24b8efd9c0f62bad0439283c2c795ef916c5a6b75f03c17799775c7ae3c0c9e", size = 4713390, upload-time = "2025-06-26T16:26:20.292Z" }, + { url = "https://files.pythonhosted.org/packages/a8/83/6184aba6cc94d7413959f6f8f54807dc318fdcd4985c347fe3ea6937f772/lxml-6.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:afd27d8629ae94c5d863e32ab0e1d5590371d296b87dae0a751fb22bf3685741", size = 5066103, upload-time = "2025-06-26T16:26:22.765Z" }, + { url = "https://files.pythonhosted.org/packages/ee/01/8bf1f4035852d0ff2e36a4d9aacdbcc57e93a6cd35a54e05fa984cdf73ab/lxml-6.0.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:54c4855eabd9fc29707d30141be99e5cd1102e7d2258d2892314cf4c110726c3", size = 4791428, upload-time = "2025-06-26T16:26:26.461Z" }, + { url = "https://files.pythonhosted.org/packages/29/31/c0267d03b16954a85ed6b065116b621d37f559553d9339c7dcc4943a76f1/lxml-6.0.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c907516d49f77f6cd8ead1322198bdfd902003c3c330c77a1c5f3cc32a0e4d16", size = 5678523, upload-time = "2025-07-03T19:19:09.837Z" }, + { url = "https://files.pythonhosted.org/packages/5c/f7/5495829a864bc5f8b0798d2b52a807c89966523140f3d6fa3a58ab6720ea/lxml-6.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:36531f81c8214e293097cd2b7873f178997dae33d3667caaae8bdfb9666b76c0", size = 5281290, upload-time = "2025-06-26T16:26:29.406Z" }, + { url = "https://files.pythonhosted.org/packages/79/56/6b8edb79d9ed294ccc4e881f4db1023af56ba451909b9ce79f2a2cd7c532/lxml-6.0.0-cp312-cp312-win32.whl", hash = "sha256:690b20e3388a7ec98e899fd54c924e50ba6693874aa65ef9cb53de7f7de9d64a", size = 3613495, upload-time = "2025-06-26T16:26:31.588Z" }, + { url = "https://files.pythonhosted.org/packages/0b/1e/cc32034b40ad6af80b6fd9b66301fc0f180f300002e5c3eb5a6110a93317/lxml-6.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:310b719b695b3dd442cdfbbe64936b2f2e231bb91d998e99e6f0daf991a3eba3", size = 4014711, upload-time = "2025-06-26T16:26:33.723Z" }, + { url = "https://files.pythonhosted.org/packages/55/10/dc8e5290ae4c94bdc1a4c55865be7e1f31dfd857a88b21cbba68b5fea61b/lxml-6.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:8cb26f51c82d77483cdcd2b4a53cda55bbee29b3c2f3ddeb47182a2a9064e4eb", size = 3674431, upload-time = "2025-06-26T16:26:35.959Z" }, + { url = "https://files.pythonhosted.org/packages/79/21/6e7c060822a3c954ff085e5e1b94b4a25757c06529eac91e550f3f5cd8b8/lxml-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6da7cd4f405fd7db56e51e96bff0865b9853ae70df0e6720624049da76bde2da", size = 8414372, upload-time = "2025-06-26T16:26:39.079Z" }, + { url = "https://files.pythonhosted.org/packages/a4/f6/051b1607a459db670fc3a244fa4f06f101a8adf86cda263d1a56b3a4f9d5/lxml-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b34339898bb556a2351a1830f88f751679f343eabf9cf05841c95b165152c9e7", size = 4593940, upload-time = "2025-06-26T16:26:41.891Z" }, + { url = "https://files.pythonhosted.org/packages/8e/74/dd595d92a40bda3c687d70d4487b2c7eff93fd63b568acd64fedd2ba00fe/lxml-6.0.0-cp313-cp313-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:51a5e4c61a4541bd1cd3ba74766d0c9b6c12d6a1a4964ef60026832aac8e79b3", size = 5214329, upload-time = "2025-06-26T16:26:44.669Z" }, + { url = "https://files.pythonhosted.org/packages/52/46/3572761efc1bd45fcafb44a63b3b0feeb5b3f0066886821e94b0254f9253/lxml-6.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d18a25b19ca7307045581b18b3ec9ead2b1db5ccd8719c291f0cd0a5cec6cb81", size = 4947559, upload-time = "2025-06-28T18:47:31.091Z" }, + { url = "https://files.pythonhosted.org/packages/94/8a/5e40de920e67c4f2eef9151097deb9b52d86c95762d8ee238134aff2125d/lxml-6.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d4f0c66df4386b75d2ab1e20a489f30dc7fd9a06a896d64980541506086be1f1", size = 5102143, upload-time = "2025-06-28T18:47:33.612Z" }, + { url = "https://files.pythonhosted.org/packages/7c/4b/20555bdd75d57945bdabfbc45fdb1a36a1a0ff9eae4653e951b2b79c9209/lxml-6.0.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9f4b481b6cc3a897adb4279216695150bbe7a44c03daba3c894f49d2037e0a24", size = 5021931, upload-time = "2025-06-26T16:26:47.503Z" }, + { url = "https://files.pythonhosted.org/packages/b6/6e/cf03b412f3763d4ca23b25e70c96a74cfece64cec3addf1c4ec639586b13/lxml-6.0.0-cp313-cp313-manylinux_2_27_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a78d6c9168f5bcb20971bf3329c2b83078611fbe1f807baadc64afc70523b3a", size = 5645469, upload-time = "2025-07-03T19:19:13.32Z" }, + { url = "https://files.pythonhosted.org/packages/d4/dd/39c8507c16db6031f8c1ddf70ed95dbb0a6d466a40002a3522c128aba472/lxml-6.0.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ae06fbab4f1bb7db4f7c8ca9897dc8db4447d1a2b9bee78474ad403437bcc29", size = 5247467, upload-time = "2025-06-26T16:26:49.998Z" }, + { url = "https://files.pythonhosted.org/packages/4d/56/732d49def0631ad633844cfb2664563c830173a98d5efd9b172e89a4800d/lxml-6.0.0-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:1fa377b827ca2023244a06554c6e7dc6828a10aaf74ca41965c5d8a4925aebb4", size = 4720601, upload-time = "2025-06-26T16:26:52.564Z" }, + { url = "https://files.pythonhosted.org/packages/8f/7f/6b956fab95fa73462bca25d1ea7fc8274ddf68fb8e60b78d56c03b65278e/lxml-6.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1676b56d48048a62ef77a250428d1f31f610763636e0784ba67a9740823988ca", size = 5060227, upload-time = "2025-06-26T16:26:55.054Z" }, + { url = "https://files.pythonhosted.org/packages/97/06/e851ac2924447e8b15a294855caf3d543424364a143c001014d22c8ca94c/lxml-6.0.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:0e32698462aacc5c1cf6bdfebc9c781821b7e74c79f13e5ffc8bfe27c42b1abf", size = 4790637, upload-time = "2025-06-26T16:26:57.384Z" }, + { url = "https://files.pythonhosted.org/packages/06/d4/fd216f3cd6625022c25b336c7570d11f4a43adbaf0a56106d3d496f727a7/lxml-6.0.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4d6036c3a296707357efb375cfc24bb64cd955b9ec731abf11ebb1e40063949f", size = 5662049, upload-time = "2025-07-03T19:19:16.409Z" }, + { url = "https://files.pythonhosted.org/packages/52/03/0e764ce00b95e008d76b99d432f1807f3574fb2945b496a17807a1645dbd/lxml-6.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7488a43033c958637b1a08cddc9188eb06d3ad36582cebc7d4815980b47e27ef", size = 5272430, upload-time = "2025-06-26T16:27:00.031Z" }, + { url = "https://files.pythonhosted.org/packages/5f/01/d48cc141bc47bc1644d20fe97bbd5e8afb30415ec94f146f2f76d0d9d098/lxml-6.0.0-cp313-cp313-win32.whl", hash = "sha256:5fcd7d3b1d8ecb91445bd71b9c88bdbeae528fefee4f379895becfc72298d181", size = 3612896, upload-time = "2025-06-26T16:27:04.251Z" }, + { url = "https://files.pythonhosted.org/packages/f4/87/6456b9541d186ee7d4cb53bf1b9a0d7f3b1068532676940fdd594ac90865/lxml-6.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:2f34687222b78fff795feeb799a7d44eca2477c3d9d3a46ce17d51a4f383e32e", size = 4013132, upload-time = "2025-06-26T16:27:06.415Z" }, + { url = "https://files.pythonhosted.org/packages/b7/42/85b3aa8f06ca0d24962f8100f001828e1f1f1a38c954c16e71154ed7d53a/lxml-6.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:21db1ec5525780fd07251636eb5f7acb84003e9382c72c18c542a87c416ade03", size = 3672642, upload-time = "2025-06-26T16:27:09.888Z" }, +] + +[[package]] +name = "mako" +version = "1.3.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9e/38/bd5b78a920a64d708fe6bc8e0a2c075e1389d53bef8413725c63ba041535/mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28", size = 392474, upload-time = "2025-04-10T12:44:31.16Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59", size = 78509, upload-time = "2025-04-10T12:50:53.297Z" }, +] + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, + { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, + { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, + { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, + { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, + { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, + { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, + { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, + { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, + { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, + { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, + { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, + { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, + { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, + { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, + { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, + { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, + { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, + { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, + { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, + { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, + { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, + { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, + { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, + { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, + { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, + { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, + { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, + { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, +] + +[[package]] +name = "matplotlib" +version = "3.9.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "contourpy" }, + { name = "cycler" }, + { name = "fonttools" }, + { name = "kiwisolver" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pillow" }, + { name = "pyparsing" }, + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9e/d8/3d7f706c69e024d4287c1110d74f7dabac91d9843b99eadc90de9efc8869/matplotlib-3.9.2.tar.gz", hash = "sha256:96ab43906269ca64a6366934106fa01534454a69e471b7bf3d79083981aaab92", size = 36088381, upload-time = "2024-08-13T01:45:36.875Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/de/54f7f38ce6de79cb77d513bb3eaa4e0b1031e9fd6022214f47943fa53a88/matplotlib-3.9.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ac43031375a65c3196bee99f6001e7fa5bdfb00ddf43379d3c0609bdca042df9", size = 7892511, upload-time = "2024-08-13T01:44:46.59Z" }, + { url = "https://files.pythonhosted.org/packages/35/3e/5713b84a02b24b2a4bd4d6673bfc03017e6654e1d8793ece783b7ed4d484/matplotlib-3.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:be0fc24a5e4531ae4d8e858a1a548c1fe33b176bb13eff7f9d0d38ce5112a27d", size = 7769370, upload-time = "2024-08-13T01:44:48.084Z" }, + { url = "https://files.pythonhosted.org/packages/5b/bd/c404502aa1824456d2862dd6b9b0c1917761a51a32f7f83ff8cf94b6d117/matplotlib-3.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf81de2926c2db243c9b2cbc3917619a0fc85796c6ba4e58f541df814bbf83c7", size = 8193260, upload-time = "2024-08-13T01:44:49.663Z" }, + { url = "https://files.pythonhosted.org/packages/27/75/de5b9cd67648051cae40039da0c8cbc497a0d99acb1a1f3d087cd66d27b7/matplotlib-3.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6ee45bc4245533111ced13f1f2cace1e7f89d1c793390392a80c139d6cf0e6c", size = 8306310, upload-time = "2024-08-13T01:44:51.329Z" }, + { url = "https://files.pythonhosted.org/packages/de/e3/2976e4e54d7ee76eaf54b7639fdc10a223d05c2bdded7045233e9871e469/matplotlib-3.9.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:306c8dfc73239f0e72ac50e5a9cf19cc4e8e331dd0c54f5e69ca8758550f1e1e", size = 9086717, upload-time = "2024-08-13T01:44:53.772Z" }, + { url = "https://files.pythonhosted.org/packages/d2/92/c2b9464a0562feb6ae780bdc152364810862e07ef5e6affa2b7686028db2/matplotlib-3.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:5413401594cfaff0052f9d8b1aafc6d305b4bd7c4331dccd18f561ff7e1d3bd3", size = 7832805, upload-time = "2024-08-13T01:44:55.947Z" }, + { url = "https://files.pythonhosted.org/packages/5c/7f/8932eac316b32f464b8f9069f151294dcd892c8fbde61fe8bcd7ba7f7f7e/matplotlib-3.9.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:18128cc08f0d3cfff10b76baa2f296fc28c4607368a8402de61bb3f2eb33c7d9", size = 7893012, upload-time = "2024-08-13T01:44:57.63Z" }, + { url = "https://files.pythonhosted.org/packages/90/89/9db9db3dd0ff3e2c49e452236dfe29e60b5586a88f8928ca1d153d0da8b5/matplotlib-3.9.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4876d7d40219e8ae8bb70f9263bcbe5714415acfdf781086601211335e24f8aa", size = 7769810, upload-time = "2024-08-13T01:44:59.652Z" }, + { url = "https://files.pythonhosted.org/packages/67/26/d2661cdc2e1410b8929c5f12dfd521e4528abfed1b3c3d5a28ac48258b43/matplotlib-3.9.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d9f07a80deab4bb0b82858a9e9ad53d1382fd122be8cde11080f4e7dfedb38b", size = 8193779, upload-time = "2024-08-13T01:45:01.453Z" }, + { url = "https://files.pythonhosted.org/packages/95/70/4839eaa672bf4eacc98ebc8d23633e02b6daf39e294e7433c4ab11a689be/matplotlib-3.9.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7c0410f181a531ec4e93bbc27692f2c71a15c2da16766f5ba9761e7ae518413", size = 8306260, upload-time = "2024-08-13T01:45:03.107Z" }, + { url = "https://files.pythonhosted.org/packages/88/62/7b263b2cb2724b45d3a4f9c8c6137696cc3ef037d44383fb01ac2a9555c2/matplotlib-3.9.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:909645cce2dc28b735674ce0931a4ac94e12f5b13f6bb0b5a5e65e7cea2c192b", size = 9086073, upload-time = "2024-08-13T01:45:04.757Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6d/3572fe243c74112fef120f0bc86f5edd21f49b60e8322fc7f6a01fe945dd/matplotlib-3.9.2-cp313-cp313-win_amd64.whl", hash = "sha256:f32c7410c7f246838a77d6d1eff0c0f87f3cb0e7c4247aebea71a6d5a68cab49", size = 7833041, upload-time = "2024-08-13T01:45:07.406Z" }, + { url = "https://files.pythonhosted.org/packages/03/8f/9d505be3eb2f40ec731674fb6b47d10cc3147bbd6a9ea7a08c8da55415c6/matplotlib-3.9.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:37e51dd1c2db16ede9cfd7b5cabdfc818b2c6397c83f8b10e0e797501c963a03", size = 7933657, upload-time = "2024-08-13T01:45:08.967Z" }, + { url = "https://files.pythonhosted.org/packages/5d/68/44b458b9794bcff2a66921f8c9a8110a50a0bb099bd5f7cabb428a1dc765/matplotlib-3.9.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b82c5045cebcecd8496a4d694d43f9cc84aeeb49fe2133e036b207abe73f4d30", size = 7799276, upload-time = "2024-08-13T01:45:10.607Z" }, + { url = "https://files.pythonhosted.org/packages/47/79/8486d4ddcaaf676314b5fb58e8fe19d1a6210a443a7c31fa72d4215fcb87/matplotlib-3.9.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f053c40f94bc51bc03832a41b4f153d83f2062d88c72b5e79997072594e97e51", size = 8221027, upload-time = "2024-08-13T01:45:12.204Z" }, + { url = "https://files.pythonhosted.org/packages/56/62/72a472181578c3d035dcda0d0fa2e259ba2c4cb91132588a348bb705b70d/matplotlib-3.9.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbe196377a8248972f5cede786d4c5508ed5f5ca4a1e09b44bda889958b33f8c", size = 8329097, upload-time = "2024-08-13T01:45:13.877Z" }, + { url = "https://files.pythonhosted.org/packages/01/8a/760f7fce66b39f447ad160800619d0bd5d0936d2b4633587116534a4afe0/matplotlib-3.9.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5816b1e1fe8c192cbc013f8f3e3368ac56fbecf02fb41b8f8559303f24c5015e", size = 9093770, upload-time = "2024-08-13T01:45:15.562Z" }, +] + +[[package]] +name = "matplotlib-inline" +version = "0.1.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/99/5b/a36a337438a14116b16480db471ad061c36c3694df7c2084a0da7ba538b7/matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", size = 8159, upload-time = "2024-04-15T13:44:44.803Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899, upload-time = "2024-04-15T13:44:43.265Z" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + +[[package]] +name = "mistune" +version = "3.1.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c4/79/bda47f7dd7c3c55770478d6d02c9960c430b0cf1773b72366ff89126ea31/mistune-3.1.3.tar.gz", hash = "sha256:a7035c21782b2becb6be62f8f25d3df81ccb4d6fa477a6525b15af06539f02a0", size = 94347, upload-time = "2025-03-19T14:27:24.955Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/01/4d/23c4e4f09da849e127e9f123241946c23c1e30f45a88366879e064211815/mistune-3.1.3-py3-none-any.whl", hash = "sha256:1a32314113cff28aa6432e99e522677c8587fd83e3d51c29b82a52409c842bd9", size = 53410, upload-time = "2025-03-19T14:27:23.451Z" }, +] + +[[package]] +name = "multiprocess" +version = "0.70.18" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dill" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/fd/2ae3826f5be24c6ed87266bc4e59c46ea5b059a103f3d7e7eb76a52aeecb/multiprocess-0.70.18.tar.gz", hash = "sha256:f9597128e6b3e67b23956da07cf3d2e5cba79e2f4e0fba8d7903636663ec6d0d", size = 1798503, upload-time = "2025-04-17T03:11:27.742Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/d8/0cba6cf51a1a31f20471fbc823a716170c73012ddc4fb85d706630ed6e8f/multiprocess-0.70.18-py310-none-any.whl", hash = "sha256:60c194974c31784019c1f459d984e8f33ee48f10fcf42c309ba97b30d9bd53ea", size = 134948, upload-time = "2025-04-17T03:11:20.223Z" }, + { url = "https://files.pythonhosted.org/packages/4b/88/9039f2fed1012ef584751d4ceff9ab4a51e5ae264898f0b7cbf44340a859/multiprocess-0.70.18-py311-none-any.whl", hash = "sha256:5aa6eef98e691281b3ad923be2832bf1c55dd2c859acd73e5ec53a66aae06a1d", size = 144462, upload-time = "2025-04-17T03:11:21.657Z" }, + { url = "https://files.pythonhosted.org/packages/bf/b6/5f922792be93b82ec6b5f270bbb1ef031fd0622847070bbcf9da816502cc/multiprocess-0.70.18-py312-none-any.whl", hash = "sha256:9b78f8e5024b573730bfb654783a13800c2c0f2dfc0c25e70b40d184d64adaa2", size = 150287, upload-time = "2025-04-17T03:11:22.69Z" }, + { url = "https://files.pythonhosted.org/packages/ee/25/7d7e78e750bc1aecfaf0efbf826c69a791d2eeaf29cf20cba93ff4cced78/multiprocess-0.70.18-py313-none-any.whl", hash = "sha256:871743755f43ef57d7910a38433cfe41319e72be1bbd90b79c7a5ac523eb9334", size = 151917, upload-time = "2025-04-17T03:11:24.044Z" }, + { url = "https://files.pythonhosted.org/packages/3b/c3/ca84c19bd14cdfc21c388fdcebf08b86a7a470ebc9f5c3c084fc2dbc50f7/multiprocess-0.70.18-py38-none-any.whl", hash = "sha256:dbf705e52a154fe5e90fb17b38f02556169557c2dd8bb084f2e06c2784d8279b", size = 132636, upload-time = "2025-04-17T03:11:24.936Z" }, + { url = "https://files.pythonhosted.org/packages/6c/28/dd72947e59a6a8c856448a5e74da6201cb5502ddff644fbc790e4bd40b9a/multiprocess-0.70.18-py39-none-any.whl", hash = "sha256:e78ca805a72b1b810c690b6b4cc32579eba34f403094bbbae962b7b5bf9dfcb8", size = 133478, upload-time = "2025-04-17T03:11:26.253Z" }, +] + +[[package]] +name = "mypy" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mypy-extensions" }, + { name = "pathspec" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1e/e3/034322d5a779685218ed69286c32faa505247f1f096251ef66c8fd203b08/mypy-1.17.0.tar.gz", hash = "sha256:e5d7ccc08ba089c06e2f5629c660388ef1fee708444f1dee0b9203fa031dee03", size = 3352114, upload-time = "2025-07-14T20:34:30.181Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/e9/e6824ed620bbf51d3bf4d6cbbe4953e83eaf31a448d1b3cfb3620ccb641c/mypy-1.17.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f986f1cab8dbec39ba6e0eaa42d4d3ac6686516a5d3dccd64be095db05ebc6bb", size = 11086395, upload-time = "2025-07-14T20:34:11.452Z" }, + { url = "https://files.pythonhosted.org/packages/ba/51/a4afd1ae279707953be175d303f04a5a7bd7e28dc62463ad29c1c857927e/mypy-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:51e455a54d199dd6e931cd7ea987d061c2afbaf0960f7f66deef47c90d1b304d", size = 10120052, upload-time = "2025-07-14T20:33:09.897Z" }, + { url = "https://files.pythonhosted.org/packages/8a/71/19adfeac926ba8205f1d1466d0d360d07b46486bf64360c54cb5a2bd86a8/mypy-1.17.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3204d773bab5ff4ebbd1f8efa11b498027cd57017c003ae970f310e5b96be8d8", size = 11861806, upload-time = "2025-07-14T20:32:16.028Z" }, + { url = "https://files.pythonhosted.org/packages/0b/64/d6120eca3835baf7179e6797a0b61d6c47e0bc2324b1f6819d8428d5b9ba/mypy-1.17.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1051df7ec0886fa246a530ae917c473491e9a0ba6938cfd0ec2abc1076495c3e", size = 12744371, upload-time = "2025-07-14T20:33:33.503Z" }, + { url = "https://files.pythonhosted.org/packages/1f/dc/56f53b5255a166f5bd0f137eed960e5065f2744509dfe69474ff0ba772a5/mypy-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f773c6d14dcc108a5b141b4456b0871df638eb411a89cd1c0c001fc4a9d08fc8", size = 12914558, upload-time = "2025-07-14T20:33:56.961Z" }, + { url = "https://files.pythonhosted.org/packages/69/ac/070bad311171badc9add2910e7f89271695a25c136de24bbafc7eded56d5/mypy-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:1619a485fd0e9c959b943c7b519ed26b712de3002d7de43154a489a2d0fd817d", size = 9585447, upload-time = "2025-07-14T20:32:20.594Z" }, + { url = "https://files.pythonhosted.org/packages/be/7b/5f8ab461369b9e62157072156935cec9d272196556bdc7c2ff5f4c7c0f9b/mypy-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c41aa59211e49d717d92b3bb1238c06d387c9325d3122085113c79118bebb06", size = 11070019, upload-time = "2025-07-14T20:32:07.99Z" }, + { url = "https://files.pythonhosted.org/packages/9c/f8/c49c9e5a2ac0badcc54beb24e774d2499748302c9568f7f09e8730e953fa/mypy-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e69db1fb65b3114f98c753e3930a00514f5b68794ba80590eb02090d54a5d4a", size = 10114457, upload-time = "2025-07-14T20:33:47.285Z" }, + { url = "https://files.pythonhosted.org/packages/89/0c/fb3f9c939ad9beed3e328008b3fb90b20fda2cddc0f7e4c20dbefefc3b33/mypy-1.17.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:03ba330b76710f83d6ac500053f7727270b6b8553b0423348ffb3af6f2f7b889", size = 11857838, upload-time = "2025-07-14T20:33:14.462Z" }, + { url = "https://files.pythonhosted.org/packages/4c/66/85607ab5137d65e4f54d9797b77d5a038ef34f714929cf8ad30b03f628df/mypy-1.17.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:037bc0f0b124ce46bfde955c647f3e395c6174476a968c0f22c95a8d2f589bba", size = 12731358, upload-time = "2025-07-14T20:32:25.579Z" }, + { url = "https://files.pythonhosted.org/packages/73/d0/341dbbfb35ce53d01f8f2969facbb66486cee9804048bf6c01b048127501/mypy-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c38876106cb6132259683632b287238858bd58de267d80defb6f418e9ee50658", size = 12917480, upload-time = "2025-07-14T20:34:21.868Z" }, + { url = "https://files.pythonhosted.org/packages/64/63/70c8b7dbfc520089ac48d01367a97e8acd734f65bd07813081f508a8c94c/mypy-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:d30ba01c0f151998f367506fab31c2ac4527e6a7b2690107c7a7f9e3cb419a9c", size = 9589666, upload-time = "2025-07-14T20:34:16.841Z" }, + { url = "https://files.pythonhosted.org/packages/e3/fc/ee058cc4316f219078464555873e99d170bde1d9569abd833300dbeb484a/mypy-1.17.0-py3-none-any.whl", hash = "sha256:15d9d0018237ab058e5de3d8fce61b6fa72cc59cc78fd91f1b474bce12abf496", size = 2283195, upload-time = "2025-07-14T20:31:54.753Z" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + +[[package]] +name = "nbclient" +version = "0.10.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "nbformat" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/87/66/7ffd18d58eae90d5721f9f39212327695b749e23ad44b3881744eaf4d9e8/nbclient-0.10.2.tar.gz", hash = "sha256:90b7fc6b810630db87a6d0c2250b1f0ab4cf4d3c27a299b0cde78a4ed3fd9193", size = 62424, upload-time = "2024-12-19T10:32:27.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/6d/e7fa07f03a4a7b221d94b4d586edb754a9b0dc3c9e2c93353e9fa4e0d117/nbclient-0.10.2-py3-none-any.whl", hash = "sha256:4ffee11e788b4a27fabeb7955547e4318a5298f34342a4bfd01f2e1faaeadc3d", size = 25434, upload-time = "2024-12-19T10:32:24.139Z" }, +] + +[[package]] +name = "nbconvert" +version = "7.16.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "beautifulsoup4" }, + { name = "bleach", extra = ["css"] }, + { name = "defusedxml" }, + { name = "jinja2" }, + { name = "jupyter-core" }, + { name = "jupyterlab-pygments" }, + { name = "markupsafe" }, + { name = "mistune" }, + { name = "nbclient" }, + { name = "nbformat" }, + { name = "packaging" }, + { name = "pandocfilters" }, + { name = "pygments" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/59/f28e15fc47ffb73af68a8d9b47367a8630d76e97ae85ad18271b9db96fdf/nbconvert-7.16.6.tar.gz", hash = "sha256:576a7e37c6480da7b8465eefa66c17844243816ce1ccc372633c6b71c3c0f582", size = 857715, upload-time = "2025-01-28T09:29:14.724Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/9a/cd673b2f773a12c992f41309ef81b99da1690426bd2f96957a7ade0d3ed7/nbconvert-7.16.6-py3-none-any.whl", hash = "sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b", size = 258525, upload-time = "2025-01-28T09:29:12.551Z" }, +] + +[[package]] +name = "nbformat" +version = "5.10.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "fastjsonschema" }, + { name = "jsonschema" }, + { name = "jupyter-core" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/91545e604bc3dad7dca9ed03284086039b294c6b3d75c0d2fa45f9e9caf3/nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", size = 142749, upload-time = "2024-04-04T11:20:37.371Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454, upload-time = "2024-04-04T11:20:34.895Z" }, +] + +[[package]] +name = "nest-asyncio" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418, upload-time = "2024-01-21T14:25:19.227Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, +] + +[[package]] +name = "networkx" +version = "3.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/4f/ccdb8ad3a38e583f214547fd2f7ff1fc160c43a75af88e6aec213404b96a/networkx-3.5.tar.gz", hash = "sha256:d4c6f9cf81f52d69230866796b82afbccdec3db7ae4fbd1b65ea750feed50037", size = 2471065, upload-time = "2025-05-29T11:35:07.804Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/8d/776adee7bbf76365fdd7f2552710282c79a4ead5d2a46408c9043a2b70ba/networkx-3.5-py3-none-any.whl", hash = "sha256:0030d386a9a06dee3565298b4a734b68589749a544acbb6c412dc9e2489ec6ec", size = 2034406, upload-time = "2025-05-29T11:35:04.961Z" }, +] + +[[package]] +name = "nodeenv" +version = "1.9.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, +] + +[[package]] +name = "nose" +version = "1.3.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/a5/0dc93c3ec33f4e281849523a5a913fa1eea9a3068acfa754d44d88107a44/nose-1.3.7.tar.gz", hash = "sha256:f1bffef9cbc82628f6e7d7b40d7e255aefaa1adb6a1b1d26c69a8b79e6208a98", size = 280488, upload-time = "2015-06-02T09:12:32.961Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/d8/dd071918c040f50fa1cf80da16423af51ff8ce4a0f2399b7bf8de45ac3d9/nose-1.3.7-py3-none-any.whl", hash = "sha256:9ff7c6cc443f8c51994b34a667bbcf45afd6d945be7477b52e97516fd17c53ac", size = 154731, upload-time = "2015-06-02T09:12:40.57Z" }, +] + +[[package]] +name = "notebook" +version = "7.4.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-server" }, + { name = "jupyterlab" }, + { name = "jupyterlab-server" }, + { name = "notebook-shim" }, + { name = "tornado" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/4e/a40b5a94eb01fc51746db7854296d88b84905ab18ee0fcef853a60d708a3/notebook-7.4.4.tar.gz", hash = "sha256:392fd501e266f2fb3466c6fcd3331163a2184968cb5c5accf90292e01dfe528c", size = 13883628, upload-time = "2025-06-30T13:04:18.099Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/c0/e64d2047fd752249b0b69f6aee2a7049eb94e7273e5baabc8b8ad05cc068/notebook-7.4.4-py3-none-any.whl", hash = "sha256:32840f7f777b6bff79bb101159336e9b332bdbfba1495b8739e34d1d65cbc1c0", size = 14288000, upload-time = "2025-06-30T13:04:14.584Z" }, +] + +[[package]] +name = "notebook-shim" +version = "0.2.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-server" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/54/d2/92fa3243712b9a3e8bafaf60aac366da1cada3639ca767ff4b5b3654ec28/notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb", size = 13167, upload-time = "2024-02-14T23:35:18.353Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", size = 13307, upload-time = "2024-02-14T23:35:16.286Z" }, +] + +[[package]] +name = "numpy" +version = "2.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/19/d7c972dfe90a353dbd3efbbe1d14a5951de80c99c9dc1b93cd998d51dc0f/numpy-2.3.1.tar.gz", hash = "sha256:1ec9ae20a4226da374362cca3c62cd753faf2f951440b0e3b98e93c235441d2b", size = 20390372, upload-time = "2025-06-21T12:28:33.469Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/56/71ad5022e2f63cfe0ca93559403d0edef14aea70a841d640bd13cdba578e/numpy-2.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2959d8f268f3d8ee402b04a9ec4bb7604555aeacf78b360dc4ec27f1d508177d", size = 20896664, upload-time = "2025-06-21T12:15:30.845Z" }, + { url = "https://files.pythonhosted.org/packages/25/65/2db52ba049813670f7f987cc5db6dac9be7cd95e923cc6832b3d32d87cef/numpy-2.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:762e0c0c6b56bdedfef9a8e1d4538556438288c4276901ea008ae44091954e29", size = 14131078, upload-time = "2025-06-21T12:15:52.23Z" }, + { url = "https://files.pythonhosted.org/packages/57/dd/28fa3c17b0e751047ac928c1e1b6990238faad76e9b147e585b573d9d1bd/numpy-2.3.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:867ef172a0976aaa1f1d1b63cf2090de8b636a7674607d514505fb7276ab08fc", size = 5112554, upload-time = "2025-06-21T12:16:01.434Z" }, + { url = "https://files.pythonhosted.org/packages/c9/fc/84ea0cba8e760c4644b708b6819d91784c290288c27aca916115e3311d17/numpy-2.3.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:4e602e1b8682c2b833af89ba641ad4176053aaa50f5cacda1a27004352dde943", size = 6646560, upload-time = "2025-06-21T12:16:11.895Z" }, + { url = "https://files.pythonhosted.org/packages/61/b2/512b0c2ddec985ad1e496b0bd853eeb572315c0f07cd6997473ced8f15e2/numpy-2.3.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:8e333040d069eba1652fb08962ec5b76af7f2c7bce1df7e1418c8055cf776f25", size = 14260638, upload-time = "2025-06-21T12:16:32.611Z" }, + { url = "https://files.pythonhosted.org/packages/6e/45/c51cb248e679a6c6ab14b7a8e3ead3f4a3fe7425fc7a6f98b3f147bec532/numpy-2.3.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e7cbf5a5eafd8d230a3ce356d892512185230e4781a361229bd902ff403bc660", size = 16632729, upload-time = "2025-06-21T12:16:57.439Z" }, + { url = "https://files.pythonhosted.org/packages/e4/ff/feb4be2e5c09a3da161b412019caf47183099cbea1132fd98061808c2df2/numpy-2.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5f1b8f26d1086835f442286c1d9b64bb3974b0b1e41bb105358fd07d20872952", size = 15565330, upload-time = "2025-06-21T12:17:20.638Z" }, + { url = "https://files.pythonhosted.org/packages/bc/6d/ceafe87587101e9ab0d370e4f6e5f3f3a85b9a697f2318738e5e7e176ce3/numpy-2.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ee8340cb48c9b7a5899d1149eece41ca535513a9698098edbade2a8e7a84da77", size = 18361734, upload-time = "2025-06-21T12:17:47.938Z" }, + { url = "https://files.pythonhosted.org/packages/2b/19/0fb49a3ea088be691f040c9bf1817e4669a339d6e98579f91859b902c636/numpy-2.3.1-cp312-cp312-win32.whl", hash = "sha256:e772dda20a6002ef7061713dc1e2585bc1b534e7909b2030b5a46dae8ff077ab", size = 6320411, upload-time = "2025-06-21T12:17:58.475Z" }, + { url = "https://files.pythonhosted.org/packages/b1/3e/e28f4c1dd9e042eb57a3eb652f200225e311b608632bc727ae378623d4f8/numpy-2.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:cfecc7822543abdea6de08758091da655ea2210b8ffa1faf116b940693d3df76", size = 12734973, upload-time = "2025-06-21T12:18:17.601Z" }, + { url = "https://files.pythonhosted.org/packages/04/a8/8a5e9079dc722acf53522b8f8842e79541ea81835e9b5483388701421073/numpy-2.3.1-cp312-cp312-win_arm64.whl", hash = "sha256:7be91b2239af2658653c5bb6f1b8bccafaf08226a258caf78ce44710a0160d30", size = 10191491, upload-time = "2025-06-21T12:18:33.585Z" }, + { url = "https://files.pythonhosted.org/packages/d4/bd/35ad97006d8abff8631293f8ea6adf07b0108ce6fec68da3c3fcca1197f2/numpy-2.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:25a1992b0a3fdcdaec9f552ef10d8103186f5397ab45e2d25f8ac51b1a6b97e8", size = 20889381, upload-time = "2025-06-21T12:19:04.103Z" }, + { url = "https://files.pythonhosted.org/packages/f1/4f/df5923874d8095b6062495b39729178eef4a922119cee32a12ee1bd4664c/numpy-2.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7dea630156d39b02a63c18f508f85010230409db5b2927ba59c8ba4ab3e8272e", size = 14152726, upload-time = "2025-06-21T12:19:25.599Z" }, + { url = "https://files.pythonhosted.org/packages/8c/0f/a1f269b125806212a876f7efb049b06c6f8772cf0121139f97774cd95626/numpy-2.3.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:bada6058dd886061f10ea15f230ccf7dfff40572e99fef440a4a857c8728c9c0", size = 5105145, upload-time = "2025-06-21T12:19:34.782Z" }, + { url = "https://files.pythonhosted.org/packages/6d/63/a7f7fd5f375b0361682f6ffbf686787e82b7bbd561268e4f30afad2bb3c0/numpy-2.3.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:a894f3816eb17b29e4783e5873f92faf55b710c2519e5c351767c51f79d8526d", size = 6639409, upload-time = "2025-06-21T12:19:45.228Z" }, + { url = "https://files.pythonhosted.org/packages/bf/0d/1854a4121af895aab383f4aa233748f1df4671ef331d898e32426756a8a6/numpy-2.3.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:18703df6c4a4fee55fd3d6e5a253d01c5d33a295409b03fda0c86b3ca2ff41a1", size = 14257630, upload-time = "2025-06-21T12:20:06.544Z" }, + { url = "https://files.pythonhosted.org/packages/50/30/af1b277b443f2fb08acf1c55ce9d68ee540043f158630d62cef012750f9f/numpy-2.3.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:5902660491bd7a48b2ec16c23ccb9124b8abfd9583c5fdfa123fe6b421e03de1", size = 16627546, upload-time = "2025-06-21T12:20:31.002Z" }, + { url = "https://files.pythonhosted.org/packages/6e/ec/3b68220c277e463095342d254c61be8144c31208db18d3fd8ef02712bcd6/numpy-2.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:36890eb9e9d2081137bd78d29050ba63b8dab95dff7912eadf1185e80074b2a0", size = 15562538, upload-time = "2025-06-21T12:20:54.322Z" }, + { url = "https://files.pythonhosted.org/packages/77/2b/4014f2bcc4404484021c74d4c5ee8eb3de7e3f7ac75f06672f8dcf85140a/numpy-2.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a780033466159c2270531e2b8ac063704592a0bc62ec4a1b991c7c40705eb0e8", size = 18360327, upload-time = "2025-06-21T12:21:21.053Z" }, + { url = "https://files.pythonhosted.org/packages/40/8d/2ddd6c9b30fcf920837b8672f6c65590c7d92e43084c25fc65edc22e93ca/numpy-2.3.1-cp313-cp313-win32.whl", hash = "sha256:39bff12c076812595c3a306f22bfe49919c5513aa1e0e70fac756a0be7c2a2b8", size = 6312330, upload-time = "2025-06-21T12:25:07.447Z" }, + { url = "https://files.pythonhosted.org/packages/dd/c8/beaba449925988d415efccb45bf977ff8327a02f655090627318f6398c7b/numpy-2.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d5ee6eec45f08ce507a6570e06f2f879b374a552087a4179ea7838edbcbfa42", size = 12731565, upload-time = "2025-06-21T12:25:26.444Z" }, + { url = "https://files.pythonhosted.org/packages/0b/c3/5c0c575d7ec78c1126998071f58facfc124006635da75b090805e642c62e/numpy-2.3.1-cp313-cp313-win_arm64.whl", hash = "sha256:0c4d9e0a8368db90f93bd192bfa771ace63137c3488d198ee21dfb8e7771916e", size = 10190262, upload-time = "2025-06-21T12:25:42.196Z" }, + { url = "https://files.pythonhosted.org/packages/ea/19/a029cd335cf72f79d2644dcfc22d90f09caa86265cbbde3b5702ccef6890/numpy-2.3.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:b0b5397374f32ec0649dd98c652a1798192042e715df918c20672c62fb52d4b8", size = 20987593, upload-time = "2025-06-21T12:21:51.664Z" }, + { url = "https://files.pythonhosted.org/packages/25/91/8ea8894406209107d9ce19b66314194675d31761fe2cb3c84fe2eeae2f37/numpy-2.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c5bdf2015ccfcee8253fb8be695516ac4457c743473a43290fd36eba6a1777eb", size = 14300523, upload-time = "2025-06-21T12:22:13.583Z" }, + { url = "https://files.pythonhosted.org/packages/a6/7f/06187b0066eefc9e7ce77d5f2ddb4e314a55220ad62dd0bfc9f2c44bac14/numpy-2.3.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d70f20df7f08b90a2062c1f07737dd340adccf2068d0f1b9b3d56e2038979fee", size = 5227993, upload-time = "2025-06-21T12:22:22.53Z" }, + { url = "https://files.pythonhosted.org/packages/e8/ec/a926c293c605fa75e9cfb09f1e4840098ed46d2edaa6e2152ee35dc01ed3/numpy-2.3.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:2fb86b7e58f9ac50e1e9dd1290154107e47d1eef23a0ae9145ded06ea606f992", size = 6736652, upload-time = "2025-06-21T12:22:33.629Z" }, + { url = "https://files.pythonhosted.org/packages/e3/62/d68e52fb6fde5586650d4c0ce0b05ff3a48ad4df4ffd1b8866479d1d671d/numpy-2.3.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:23ab05b2d241f76cb883ce8b9a93a680752fbfcbd51c50eff0b88b979e471d8c", size = 14331561, upload-time = "2025-06-21T12:22:55.056Z" }, + { url = "https://files.pythonhosted.org/packages/fc/ec/b74d3f2430960044bdad6900d9f5edc2dc0fb8bf5a0be0f65287bf2cbe27/numpy-2.3.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:ce2ce9e5de4703a673e705183f64fd5da5bf36e7beddcb63a25ee2286e71ca48", size = 16693349, upload-time = "2025-06-21T12:23:20.53Z" }, + { url = "https://files.pythonhosted.org/packages/0d/15/def96774b9d7eb198ddadfcbd20281b20ebb510580419197e225f5c55c3e/numpy-2.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c4913079974eeb5c16ccfd2b1f09354b8fed7e0d6f2cab933104a09a6419b1ee", size = 15642053, upload-time = "2025-06-21T12:23:43.697Z" }, + { url = "https://files.pythonhosted.org/packages/2b/57/c3203974762a759540c6ae71d0ea2341c1fa41d84e4971a8e76d7141678a/numpy-2.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:010ce9b4f00d5c036053ca684c77441f2f2c934fd23bee058b4d6f196efd8280", size = 18434184, upload-time = "2025-06-21T12:24:10.708Z" }, + { url = "https://files.pythonhosted.org/packages/22/8a/ccdf201457ed8ac6245187850aff4ca56a79edbea4829f4e9f14d46fa9a5/numpy-2.3.1-cp313-cp313t-win32.whl", hash = "sha256:6269b9edfe32912584ec496d91b00b6d34282ca1d07eb10e82dfc780907d6c2e", size = 6440678, upload-time = "2025-06-21T12:24:21.596Z" }, + { url = "https://files.pythonhosted.org/packages/f1/7e/7f431d8bd8eb7e03d79294aed238b1b0b174b3148570d03a8a8a8f6a0da9/numpy-2.3.1-cp313-cp313t-win_amd64.whl", hash = "sha256:2a809637460e88a113e186e87f228d74ae2852a2e0c44de275263376f17b5bdc", size = 12870697, upload-time = "2025-06-21T12:24:40.644Z" }, + { url = "https://files.pythonhosted.org/packages/d4/ca/af82bf0fad4c3e573c6930ed743b5308492ff19917c7caaf2f9b6f9e2e98/numpy-2.3.1-cp313-cp313t-win_arm64.whl", hash = "sha256:eccb9a159db9aed60800187bc47a6d3451553f0e1b08b068d8b277ddfbb9b244", size = 10260376, upload-time = "2025-06-21T12:24:56.884Z" }, +] + +[[package]] +name = "nx-vis-visualizer" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "networkx" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c3/f5/9ed4f232274c23786a241db69d21dd5f17f55eb3cd7f024fe9b1289f34b6/nx_vis_visualizer-0.2.0.tar.gz", hash = "sha256:96b04a21473d1079c98eb49411d9557e76edf152a0565502d42718779ee6dfe7", size = 17849, upload-time = "2025-06-12T00:29:20.942Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/5e/ef8786748d6b015d70941979adf611600df3e999667ec6955903338347f7/nx_vis_visualizer-0.2.0-py3-none-any.whl", hash = "sha256:d334366863f0a5acd6fcce604e2ef16d555f7472e2b5ea7d889e1afa77362168", size = 12072, upload-time = "2025-06-12T00:29:19.765Z" }, +] + +[[package]] +name = "openpyxl" +version = "3.1.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "et-xmlfile" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/f9/88d94a75de065ea32619465d2f77b29a0469500e99012523b91cc4141cd1/openpyxl-3.1.5.tar.gz", hash = "sha256:cf0e3cf56142039133628b5acffe8ef0c12bc902d2aadd3e0fe5878dc08d1050", size = 186464, upload-time = "2024-06-28T14:03:44.161Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/da/977ded879c29cbd04de313843e76868e6e13408a94ed6b987245dc7c8506/openpyxl-3.1.5-py2.py3-none-any.whl", hash = "sha256:5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2", size = 250910, upload-time = "2024-06-28T14:03:41.161Z" }, +] + +[[package]] +name = "overrides" +version = "7.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812, upload-time = "2024-01-27T21:01:33.423Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832, upload-time = "2024-01-27T21:01:31.393Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "pandas" +version = "2.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "python-dateutil" }, + { name = "pytz" }, + { name = "tzdata" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d1/6f/75aa71f8a14267117adeeed5d21b204770189c0a0025acbdc03c337b28fc/pandas-2.3.1.tar.gz", hash = "sha256:0a95b9ac964fe83ce317827f80304d37388ea77616b1425f0ae41c9d2d0d7bb2", size = 4487493, upload-time = "2025-07-07T19:20:04.079Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/de/b8445e0f5d217a99fe0eeb2f4988070908979bec3587c0633e5428ab596c/pandas-2.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:689968e841136f9e542020698ee1c4fbe9caa2ed2213ae2388dc7b81721510d3", size = 11588172, upload-time = "2025-07-07T19:18:52.054Z" }, + { url = "https://files.pythonhosted.org/packages/1e/e0/801cdb3564e65a5ac041ab99ea6f1d802a6c325bb6e58c79c06a3f1cd010/pandas-2.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:025e92411c16cbe5bb2a4abc99732a6b132f439b8aab23a59fa593eb00704232", size = 10717365, upload-time = "2025-07-07T19:18:54.785Z" }, + { url = "https://files.pythonhosted.org/packages/51/a5/c76a8311833c24ae61a376dbf360eb1b1c9247a5d9c1e8b356563b31b80c/pandas-2.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b7ff55f31c4fcb3e316e8f7fa194566b286d6ac430afec0d461163312c5841e", size = 11280411, upload-time = "2025-07-07T19:18:57.045Z" }, + { url = "https://files.pythonhosted.org/packages/da/01/e383018feba0a1ead6cf5fe8728e5d767fee02f06a3d800e82c489e5daaf/pandas-2.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7dcb79bf373a47d2a40cf7232928eb7540155abbc460925c2c96d2d30b006eb4", size = 11988013, upload-time = "2025-07-07T19:18:59.771Z" }, + { url = "https://files.pythonhosted.org/packages/5b/14/cec7760d7c9507f11c97d64f29022e12a6cc4fc03ac694535e89f88ad2ec/pandas-2.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:56a342b231e8862c96bdb6ab97170e203ce511f4d0429589c8ede1ee8ece48b8", size = 12767210, upload-time = "2025-07-07T19:19:02.944Z" }, + { url = "https://files.pythonhosted.org/packages/50/b9/6e2d2c6728ed29fb3d4d4d302504fb66f1a543e37eb2e43f352a86365cdf/pandas-2.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ca7ed14832bce68baef331f4d7f294411bed8efd032f8109d690df45e00c4679", size = 13440571, upload-time = "2025-07-07T19:19:06.82Z" }, + { url = "https://files.pythonhosted.org/packages/80/a5/3a92893e7399a691bad7664d977cb5e7c81cf666c81f89ea76ba2bff483d/pandas-2.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:ac942bfd0aca577bef61f2bc8da8147c4ef6879965ef883d8e8d5d2dc3e744b8", size = 10987601, upload-time = "2025-07-07T19:19:09.589Z" }, + { url = "https://files.pythonhosted.org/packages/32/ed/ff0a67a2c5505e1854e6715586ac6693dd860fbf52ef9f81edee200266e7/pandas-2.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9026bd4a80108fac2239294a15ef9003c4ee191a0f64b90f170b40cfb7cf2d22", size = 11531393, upload-time = "2025-07-07T19:19:12.245Z" }, + { url = "https://files.pythonhosted.org/packages/c7/db/d8f24a7cc9fb0972adab0cc80b6817e8bef888cfd0024eeb5a21c0bb5c4a/pandas-2.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6de8547d4fdb12421e2d047a2c446c623ff4c11f47fddb6b9169eb98ffba485a", size = 10668750, upload-time = "2025-07-07T19:19:14.612Z" }, + { url = "https://files.pythonhosted.org/packages/0f/b0/80f6ec783313f1e2356b28b4fd8d2148c378370045da918c73145e6aab50/pandas-2.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:782647ddc63c83133b2506912cc6b108140a38a37292102aaa19c81c83db2928", size = 11342004, upload-time = "2025-07-07T19:19:16.857Z" }, + { url = "https://files.pythonhosted.org/packages/e9/e2/20a317688435470872885e7fc8f95109ae9683dec7c50be29b56911515a5/pandas-2.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ba6aff74075311fc88504b1db890187a3cd0f887a5b10f5525f8e2ef55bfdb9", size = 12050869, upload-time = "2025-07-07T19:19:19.265Z" }, + { url = "https://files.pythonhosted.org/packages/55/79/20d746b0a96c67203a5bee5fb4e00ac49c3e8009a39e1f78de264ecc5729/pandas-2.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e5635178b387bd2ba4ac040f82bc2ef6e6b500483975c4ebacd34bec945fda12", size = 12750218, upload-time = "2025-07-07T19:19:21.547Z" }, + { url = "https://files.pythonhosted.org/packages/7c/0f/145c8b41e48dbf03dd18fdd7f24f8ba95b8254a97a3379048378f33e7838/pandas-2.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6f3bf5ec947526106399a9e1d26d40ee2b259c66422efdf4de63c848492d91bb", size = 13416763, upload-time = "2025-07-07T19:19:23.939Z" }, + { url = "https://files.pythonhosted.org/packages/b2/c0/54415af59db5cdd86a3d3bf79863e8cc3fa9ed265f0745254061ac09d5f2/pandas-2.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:1c78cf43c8fde236342a1cb2c34bcff89564a7bfed7e474ed2fffa6aed03a956", size = 10987482, upload-time = "2025-07-07T19:19:42.699Z" }, + { url = "https://files.pythonhosted.org/packages/48/64/2fd2e400073a1230e13b8cd604c9bc95d9e3b962e5d44088ead2e8f0cfec/pandas-2.3.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8dfc17328e8da77be3cf9f47509e5637ba8f137148ed0e9b5241e1baf526e20a", size = 12029159, upload-time = "2025-07-07T19:19:26.362Z" }, + { url = "https://files.pythonhosted.org/packages/d8/0a/d84fd79b0293b7ef88c760d7dca69828d867c89b6d9bc52d6a27e4d87316/pandas-2.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:ec6c851509364c59a5344458ab935e6451b31b818be467eb24b0fe89bd05b6b9", size = 11393287, upload-time = "2025-07-07T19:19:29.157Z" }, + { url = "https://files.pythonhosted.org/packages/50/ae/ff885d2b6e88f3c7520bb74ba319268b42f05d7e583b5dded9837da2723f/pandas-2.3.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:911580460fc4884d9b05254b38a6bfadddfcc6aaef856fb5859e7ca202e45275", size = 11309381, upload-time = "2025-07-07T19:19:31.436Z" }, + { url = "https://files.pythonhosted.org/packages/85/86/1fa345fc17caf5d7780d2699985c03dbe186c68fee00b526813939062bb0/pandas-2.3.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f4d6feeba91744872a600e6edbbd5b033005b431d5ae8379abee5bcfa479fab", size = 11883998, upload-time = "2025-07-07T19:19:34.267Z" }, + { url = "https://files.pythonhosted.org/packages/81/aa/e58541a49b5e6310d89474333e994ee57fea97c8aaa8fc7f00b873059bbf/pandas-2.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:fe37e757f462d31a9cd7580236a82f353f5713a80e059a29753cf938c6775d96", size = 12704705, upload-time = "2025-07-07T19:19:36.856Z" }, + { url = "https://files.pythonhosted.org/packages/d5/f9/07086f5b0f2a19872554abeea7658200824f5835c58a106fa8f2ae96a46c/pandas-2.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5db9637dbc24b631ff3707269ae4559bce4b7fd75c1c4d7e13f40edc42df4444", size = 13189044, upload-time = "2025-07-07T19:19:39.999Z" }, +] + +[[package]] +name = "pandera" +version = "0.25.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "pydantic" }, + { name = "typeguard" }, + { name = "typing-extensions" }, + { name = "typing-inspect" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/13/c1/02f78cd18cd32a009405c847dcf430a97d1a8c162f6e8872acae928c8f20/pandera-0.25.0.tar.gz", hash = "sha256:af3bbaa163672c91b83d59d70715f25c4134dbccfc8bc89a642a2f0e23db951e", size = 555391, upload-time = "2025-07-08T19:20:22.106Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/e0/234707103c742555e1c23bff51f3f0e496c144cd76fcf5a6b800dfe193f2/pandera-0.25.0-py3-none-any.whl", hash = "sha256:365a555accc46404466641203e297722d424d74a1315f077ab899e1344f82303", size = 293336, upload-time = "2025-07-08T19:20:20.44Z" }, +] + +[[package]] +name = "pandocfilters" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/70/6f/3dd4940bbe001c06a65f88e36bad298bc7a0de5036115639926b0c5c0458/pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", size = 8454, upload-time = "2024-01-18T20:08:13.726Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663, upload-time = "2024-01-18T20:08:11.28Z" }, +] + +[[package]] +name = "parso" +version = "0.8.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/94/68e2e17afaa9169cf6412ab0f28623903be73d1b32e208d9e8e541bb086d/parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d", size = 400609, upload-time = "2024-04-05T09:43:55.897Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", size = 103650, upload-time = "2024-04-05T09:43:53.299Z" }, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, +] + +[[package]] +name = "pexpect" +version = "4.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ptyprocess" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, +] + +[[package]] +name = "pillow" +version = "11.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/d0d6dea55cd152ce3d6767bb38a8fc10e33796ba4ba210cbab9354b6d238/pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523", size = 47113069, upload-time = "2025-07-01T09:16:30.666Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/fe/1bc9b3ee13f68487a99ac9529968035cca2f0a51ec36892060edcc51d06a/pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4", size = 5278800, upload-time = "2025-07-01T09:14:17.648Z" }, + { url = "https://files.pythonhosted.org/packages/2c/32/7e2ac19b5713657384cec55f89065fb306b06af008cfd87e572035b27119/pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69", size = 4686296, upload-time = "2025-07-01T09:14:19.828Z" }, + { url = "https://files.pythonhosted.org/packages/8e/1e/b9e12bbe6e4c2220effebc09ea0923a07a6da1e1f1bfbc8d7d29a01ce32b/pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d", size = 5871726, upload-time = "2025-07-03T13:10:04.448Z" }, + { url = "https://files.pythonhosted.org/packages/8d/33/e9200d2bd7ba00dc3ddb78df1198a6e80d7669cce6c2bdbeb2530a74ec58/pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6", size = 7644652, upload-time = "2025-07-03T13:10:10.391Z" }, + { url = "https://files.pythonhosted.org/packages/41/f1/6f2427a26fc683e00d985bc391bdd76d8dd4e92fac33d841127eb8fb2313/pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7", size = 5977787, upload-time = "2025-07-01T09:14:21.63Z" }, + { url = "https://files.pythonhosted.org/packages/e4/c9/06dd4a38974e24f932ff5f98ea3c546ce3f8c995d3f0985f8e5ba48bba19/pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024", size = 6645236, upload-time = "2025-07-01T09:14:23.321Z" }, + { url = "https://files.pythonhosted.org/packages/40/e7/848f69fb79843b3d91241bad658e9c14f39a32f71a301bcd1d139416d1be/pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809", size = 6086950, upload-time = "2025-07-01T09:14:25.237Z" }, + { url = "https://files.pythonhosted.org/packages/0b/1a/7cff92e695a2a29ac1958c2a0fe4c0b2393b60aac13b04a4fe2735cad52d/pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d", size = 6723358, upload-time = "2025-07-01T09:14:27.053Z" }, + { url = "https://files.pythonhosted.org/packages/26/7d/73699ad77895f69edff76b0f332acc3d497f22f5d75e5360f78cbcaff248/pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149", size = 6275079, upload-time = "2025-07-01T09:14:30.104Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ce/e7dfc873bdd9828f3b6e5c2bbb74e47a98ec23cc5c74fc4e54462f0d9204/pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d", size = 6986324, upload-time = "2025-07-01T09:14:31.899Z" }, + { url = "https://files.pythonhosted.org/packages/16/8f/b13447d1bf0b1f7467ce7d86f6e6edf66c0ad7cf44cf5c87a37f9bed9936/pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542", size = 2423067, upload-time = "2025-07-01T09:14:33.709Z" }, + { url = "https://files.pythonhosted.org/packages/1e/93/0952f2ed8db3a5a4c7a11f91965d6184ebc8cd7cbb7941a260d5f018cd2d/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd", size = 2128328, upload-time = "2025-07-01T09:14:35.276Z" }, + { url = "https://files.pythonhosted.org/packages/4b/e8/100c3d114b1a0bf4042f27e0f87d2f25e857e838034e98ca98fe7b8c0a9c/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8", size = 2170652, upload-time = "2025-07-01T09:14:37.203Z" }, + { url = "https://files.pythonhosted.org/packages/aa/86/3f758a28a6e381758545f7cdb4942e1cb79abd271bea932998fc0db93cb6/pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f", size = 2227443, upload-time = "2025-07-01T09:14:39.344Z" }, + { url = "https://files.pythonhosted.org/packages/01/f4/91d5b3ffa718df2f53b0dc109877993e511f4fd055d7e9508682e8aba092/pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c", size = 5278474, upload-time = "2025-07-01T09:14:41.843Z" }, + { url = "https://files.pythonhosted.org/packages/f9/0e/37d7d3eca6c879fbd9dba21268427dffda1ab00d4eb05b32923d4fbe3b12/pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd", size = 4686038, upload-time = "2025-07-01T09:14:44.008Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b0/3426e5c7f6565e752d81221af9d3676fdbb4f352317ceafd42899aaf5d8a/pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e", size = 5864407, upload-time = "2025-07-03T13:10:15.628Z" }, + { url = "https://files.pythonhosted.org/packages/fc/c1/c6c423134229f2a221ee53f838d4be9d82bab86f7e2f8e75e47b6bf6cd77/pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1", size = 7639094, upload-time = "2025-07-03T13:10:21.857Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c9/09e6746630fe6372c67c648ff9deae52a2bc20897d51fa293571977ceb5d/pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805", size = 5973503, upload-time = "2025-07-01T09:14:45.698Z" }, + { url = "https://files.pythonhosted.org/packages/d5/1c/a2a29649c0b1983d3ef57ee87a66487fdeb45132df66ab30dd37f7dbe162/pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8", size = 6642574, upload-time = "2025-07-01T09:14:47.415Z" }, + { url = "https://files.pythonhosted.org/packages/36/de/d5cc31cc4b055b6c6fd990e3e7f0f8aaf36229a2698501bcb0cdf67c7146/pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2", size = 6084060, upload-time = "2025-07-01T09:14:49.636Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ea/502d938cbaeec836ac28a9b730193716f0114c41325db428e6b280513f09/pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b", size = 6721407, upload-time = "2025-07-01T09:14:51.962Z" }, + { url = "https://files.pythonhosted.org/packages/45/9c/9c5e2a73f125f6cbc59cc7087c8f2d649a7ae453f83bd0362ff7c9e2aee2/pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3", size = 6273841, upload-time = "2025-07-01T09:14:54.142Z" }, + { url = "https://files.pythonhosted.org/packages/23/85/397c73524e0cd212067e0c969aa245b01d50183439550d24d9f55781b776/pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51", size = 6978450, upload-time = "2025-07-01T09:14:56.436Z" }, + { url = "https://files.pythonhosted.org/packages/17/d2/622f4547f69cd173955194b78e4d19ca4935a1b0f03a302d655c9f6aae65/pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580", size = 2423055, upload-time = "2025-07-01T09:14:58.072Z" }, + { url = "https://files.pythonhosted.org/packages/dd/80/a8a2ac21dda2e82480852978416cfacd439a4b490a501a288ecf4fe2532d/pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e", size = 5281110, upload-time = "2025-07-01T09:14:59.79Z" }, + { url = "https://files.pythonhosted.org/packages/44/d6/b79754ca790f315918732e18f82a8146d33bcd7f4494380457ea89eb883d/pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d", size = 4689547, upload-time = "2025-07-01T09:15:01.648Z" }, + { url = "https://files.pythonhosted.org/packages/49/20/716b8717d331150cb00f7fdd78169c01e8e0c219732a78b0e59b6bdb2fd6/pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced", size = 5901554, upload-time = "2025-07-03T13:10:27.018Z" }, + { url = "https://files.pythonhosted.org/packages/74/cf/a9f3a2514a65bb071075063a96f0a5cf949c2f2fce683c15ccc83b1c1cab/pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c", size = 7669132, upload-time = "2025-07-03T13:10:33.01Z" }, + { url = "https://files.pythonhosted.org/packages/98/3c/da78805cbdbee9cb43efe8261dd7cc0b4b93f2ac79b676c03159e9db2187/pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8", size = 6005001, upload-time = "2025-07-01T09:15:03.365Z" }, + { url = "https://files.pythonhosted.org/packages/6c/fa/ce044b91faecf30e635321351bba32bab5a7e034c60187fe9698191aef4f/pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59", size = 6668814, upload-time = "2025-07-01T09:15:05.655Z" }, + { url = "https://files.pythonhosted.org/packages/7b/51/90f9291406d09bf93686434f9183aba27b831c10c87746ff49f127ee80cb/pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe", size = 6113124, upload-time = "2025-07-01T09:15:07.358Z" }, + { url = "https://files.pythonhosted.org/packages/cd/5a/6fec59b1dfb619234f7636d4157d11fb4e196caeee220232a8d2ec48488d/pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c", size = 6747186, upload-time = "2025-07-01T09:15:09.317Z" }, + { url = "https://files.pythonhosted.org/packages/49/6b/00187a044f98255225f172de653941e61da37104a9ea60e4f6887717e2b5/pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788", size = 6277546, upload-time = "2025-07-01T09:15:11.311Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5c/6caaba7e261c0d75bab23be79f1d06b5ad2a2ae49f028ccec801b0e853d6/pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31", size = 6985102, upload-time = "2025-07-01T09:15:13.164Z" }, + { url = "https://files.pythonhosted.org/packages/f3/7e/b623008460c09a0cb38263c93b828c666493caee2eb34ff67f778b87e58c/pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e", size = 2424803, upload-time = "2025-07-01T09:15:15.695Z" }, + { url = "https://files.pythonhosted.org/packages/73/f4/04905af42837292ed86cb1b1dabe03dce1edc008ef14c473c5c7e1443c5d/pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12", size = 5278520, upload-time = "2025-07-01T09:15:17.429Z" }, + { url = "https://files.pythonhosted.org/packages/41/b0/33d79e377a336247df6348a54e6d2a2b85d644ca202555e3faa0cf811ecc/pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a", size = 4686116, upload-time = "2025-07-01T09:15:19.423Z" }, + { url = "https://files.pythonhosted.org/packages/49/2d/ed8bc0ab219ae8768f529597d9509d184fe8a6c4741a6864fea334d25f3f/pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632", size = 5864597, upload-time = "2025-07-03T13:10:38.404Z" }, + { url = "https://files.pythonhosted.org/packages/b5/3d/b932bb4225c80b58dfadaca9d42d08d0b7064d2d1791b6a237f87f661834/pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673", size = 7638246, upload-time = "2025-07-03T13:10:44.987Z" }, + { url = "https://files.pythonhosted.org/packages/09/b5/0487044b7c096f1b48f0d7ad416472c02e0e4bf6919541b111efd3cae690/pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027", size = 5973336, upload-time = "2025-07-01T09:15:21.237Z" }, + { url = "https://files.pythonhosted.org/packages/a8/2d/524f9318f6cbfcc79fbc004801ea6b607ec3f843977652fdee4857a7568b/pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77", size = 6642699, upload-time = "2025-07-01T09:15:23.186Z" }, + { url = "https://files.pythonhosted.org/packages/6f/d2/a9a4f280c6aefedce1e8f615baaa5474e0701d86dd6f1dede66726462bbd/pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874", size = 6083789, upload-time = "2025-07-01T09:15:25.1Z" }, + { url = "https://files.pythonhosted.org/packages/fe/54/86b0cd9dbb683a9d5e960b66c7379e821a19be4ac5810e2e5a715c09a0c0/pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a", size = 6720386, upload-time = "2025-07-01T09:15:27.378Z" }, + { url = "https://files.pythonhosted.org/packages/e7/95/88efcaf384c3588e24259c4203b909cbe3e3c2d887af9e938c2022c9dd48/pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214", size = 6370911, upload-time = "2025-07-01T09:15:29.294Z" }, + { url = "https://files.pythonhosted.org/packages/2e/cc/934e5820850ec5eb107e7b1a72dd278140731c669f396110ebc326f2a503/pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635", size = 7117383, upload-time = "2025-07-01T09:15:31.128Z" }, + { url = "https://files.pythonhosted.org/packages/d6/e9/9c0a616a71da2a5d163aa37405e8aced9a906d574b4a214bede134e731bc/pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6", size = 2511385, upload-time = "2025-07-01T09:15:33.328Z" }, + { url = "https://files.pythonhosted.org/packages/1a/33/c88376898aff369658b225262cd4f2659b13e8178e7534df9e6e1fa289f6/pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae", size = 5281129, upload-time = "2025-07-01T09:15:35.194Z" }, + { url = "https://files.pythonhosted.org/packages/1f/70/d376247fb36f1844b42910911c83a02d5544ebd2a8bad9efcc0f707ea774/pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653", size = 4689580, upload-time = "2025-07-01T09:15:37.114Z" }, + { url = "https://files.pythonhosted.org/packages/eb/1c/537e930496149fbac69efd2fc4329035bbe2e5475b4165439e3be9cb183b/pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6", size = 5902860, upload-time = "2025-07-03T13:10:50.248Z" }, + { url = "https://files.pythonhosted.org/packages/bd/57/80f53264954dcefeebcf9dae6e3eb1daea1b488f0be8b8fef12f79a3eb10/pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36", size = 7670694, upload-time = "2025-07-03T13:10:56.432Z" }, + { url = "https://files.pythonhosted.org/packages/70/ff/4727d3b71a8578b4587d9c276e90efad2d6fe0335fd76742a6da08132e8c/pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b", size = 6005888, upload-time = "2025-07-01T09:15:39.436Z" }, + { url = "https://files.pythonhosted.org/packages/05/ae/716592277934f85d3be51d7256f3636672d7b1abfafdc42cf3f8cbd4b4c8/pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477", size = 6670330, upload-time = "2025-07-01T09:15:41.269Z" }, + { url = "https://files.pythonhosted.org/packages/e7/bb/7fe6cddcc8827b01b1a9766f5fdeb7418680744f9082035bdbabecf1d57f/pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50", size = 6114089, upload-time = "2025-07-01T09:15:43.13Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f5/06bfaa444c8e80f1a8e4bff98da9c83b37b5be3b1deaa43d27a0db37ef84/pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b", size = 6748206, upload-time = "2025-07-01T09:15:44.937Z" }, + { url = "https://files.pythonhosted.org/packages/f0/77/bc6f92a3e8e6e46c0ca78abfffec0037845800ea38c73483760362804c41/pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12", size = 6377370, upload-time = "2025-07-01T09:15:46.673Z" }, + { url = "https://files.pythonhosted.org/packages/4a/82/3a721f7d69dca802befb8af08b7c79ebcab461007ce1c18bd91a5d5896f9/pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db", size = 7121500, upload-time = "2025-07-01T09:15:48.512Z" }, + { url = "https://files.pythonhosted.org/packages/89/c7/5572fa4a3f45740eaab6ae86fcdf7195b55beac1371ac8c619d880cfe948/pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa", size = 2512835, upload-time = "2025-07-01T09:15:50.399Z" }, +] + +[[package]] +name = "pint" +version = "0.24.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "flexcache" }, + { name = "flexparser" }, + { name = "platformdirs" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/20/bb/52b15ddf7b7706ed591134a895dbf6e41c8348171fb635e655e0a4bbb0ea/pint-0.24.4.tar.gz", hash = "sha256:35275439b574837a6cd3020a5a4a73645eb125ce4152a73a2f126bf164b91b80", size = 342225, upload-time = "2024-11-07T16:29:46.061Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/16/bd2f5904557265882108dc2e04f18abc05ab0c2b7082ae9430091daf1d5c/Pint-0.24.4-py3-none-any.whl", hash = "sha256:aa54926c8772159fcf65f82cc0d34de6768c151b32ad1deb0331291c38fe7659", size = 302029, upload-time = "2024-11-07T16:29:43.976Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.3.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/8b/3c73abc9c759ecd3f1f7ceff6685840859e8070c4d947c93fae71f6a0bf2/platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc", size = 21362, upload-time = "2025-05-07T22:47:42.121Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/39/979e8e21520d4e47a0bbe349e2713c0aac6f3d853d0e5b34d76206c439aa/platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4", size = 18567, upload-time = "2025-05-07T22:47:40.376Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "ply" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e5/69/882ee5c9d017149285cab114ebeab373308ef0f874fcdac9beb90e0ac4da/ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3", size = 159130, upload-time = "2018-02-15T19:01:31.097Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/58/35da89ee790598a0700ea49b2a66594140f44dec458c07e8e3d4979137fc/ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce", size = 49567, upload-time = "2018-02-15T19:01:27.172Z" }, +] + +[[package]] +name = "pre-commit" +version = "4.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cfgv" }, + { name = "identify" }, + { name = "nodeenv" }, + { name = "pyyaml" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/08/39/679ca9b26c7bb2999ff122d50faa301e49af82ca9c066ec061cfbc0c6784/pre_commit-4.2.0.tar.gz", hash = "sha256:601283b9757afd87d40c4c4a9b2b5de9637a8ea02eaff7adc2d0fb4e04841146", size = 193424, upload-time = "2025-03-18T21:35:20.987Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/74/a88bf1b1efeae488a0c0b7bdf71429c313722d1fc0f377537fbe554e6180/pre_commit-4.2.0-py2.py3-none-any.whl", hash = "sha256:a009ca7205f1eb497d10b845e52c838a98b6cdd2102a6c8e4540e94ee75c58bd", size = 220707, upload-time = "2025-03-18T21:35:19.343Z" }, +] + +[[package]] +name = "prometheus-client" +version = "0.22.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/cf/40dde0a2be27cc1eb41e333d1a674a74ce8b8b0457269cc640fd42b07cf7/prometheus_client-0.22.1.tar.gz", hash = "sha256:190f1331e783cf21eb60bca559354e0a4d4378facecf78f5428c39b675d20d28", size = 69746, upload-time = "2025-06-02T14:29:01.152Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/ae/ec06af4fe3ee72d16973474f122541746196aaa16cea6f66d18b963c6177/prometheus_client-0.22.1-py3-none-any.whl", hash = "sha256:cca895342e308174341b2cbf99a56bef291fbc0ef7b9e5412a0f26d653ba7094", size = 58694, upload-time = "2025-06-02T14:29:00.068Z" }, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.51" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bb/6e/9d084c929dfe9e3bfe0c6a47e31f78a25c54627d64a66e884a8bf5474f1c/prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed", size = 428940, upload-time = "2025-04-15T09:18:47.731Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/4f/5249960887b1fbe561d9ff265496d170b55a735b76724f10ef19f9e40716/prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07", size = 387810, upload-time = "2025-04-15T09:18:44.753Z" }, +] + +[[package]] +name = "psutil" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2a/80/336820c1ad9286a4ded7e845b2eccfcb27851ab8ac6abece774a6ff4d3de/psutil-7.0.0.tar.gz", hash = "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456", size = 497003, upload-time = "2025-02-13T21:54:07.946Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/e6/2d26234410f8b8abdbf891c9da62bee396583f713fb9f3325a4760875d22/psutil-7.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25", size = 238051, upload-time = "2025-02-13T21:54:12.36Z" }, + { url = "https://files.pythonhosted.org/packages/04/8b/30f930733afe425e3cbfc0e1468a30a18942350c1a8816acfade80c005c4/psutil-7.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da", size = 239535, upload-time = "2025-02-13T21:54:16.07Z" }, + { url = "https://files.pythonhosted.org/packages/2a/ed/d362e84620dd22876b55389248e522338ed1bf134a5edd3b8231d7207f6d/psutil-7.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91", size = 275004, upload-time = "2025-02-13T21:54:18.662Z" }, + { url = "https://files.pythonhosted.org/packages/bf/b9/b0eb3f3cbcb734d930fdf839431606844a825b23eaf9a6ab371edac8162c/psutil-7.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34", size = 277986, upload-time = "2025-02-13T21:54:21.811Z" }, + { url = "https://files.pythonhosted.org/packages/eb/a2/709e0fe2f093556c17fbafda93ac032257242cabcc7ff3369e2cb76a97aa/psutil-7.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993", size = 279544, upload-time = "2025-02-13T21:54:24.68Z" }, + { url = "https://files.pythonhosted.org/packages/50/e6/eecf58810b9d12e6427369784efe814a1eec0f492084ce8eb8f4d89d6d61/psutil-7.0.0-cp37-abi3-win32.whl", hash = "sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99", size = 241053, upload-time = "2025-02-13T21:54:34.31Z" }, + { url = "https://files.pythonhosted.org/packages/50/1b/6921afe68c74868b4c9fa424dad3be35b095e16687989ebbb50ce4fceb7c/psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553", size = 244885, upload-time = "2025-02-13T21:54:37.486Z" }, +] + +[[package]] +name = "psycopg" +version = "3.2.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/27/4a/93a6ab570a8d1a4ad171a1f4256e205ce48d828781312c0bbaff36380ecb/psycopg-3.2.9.tar.gz", hash = "sha256:2fbb46fcd17bc81f993f28c47f1ebea38d66ae97cc2dbc3cad73b37cefbff700", size = 158122, upload-time = "2025-05-13T16:11:15.533Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/b0/a73c195a56eb6b92e937a5ca58521a5c3346fb233345adc80fd3e2f542e2/psycopg-3.2.9-py3-none-any.whl", hash = "sha256:01a8dadccdaac2123c916208c96e06631641c0566b22005493f09663c7a8d3b6", size = 202705, upload-time = "2025-05-13T16:06:26.584Z" }, +] + +[package.optional-dependencies] +binary = [ + { name = "psycopg-binary", marker = "implementation_name != 'pypy'" }, +] + +[[package]] +name = "psycopg-binary" +version = "3.2.9" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/29/6f/ec9957e37a606cd7564412e03f41f1b3c3637a5be018d0849914cb06e674/psycopg_binary-3.2.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:be7d650a434921a6b1ebe3fff324dbc2364393eb29d7672e638ce3e21076974e", size = 4022205, upload-time = "2025-05-13T16:07:48.195Z" }, + { url = "https://files.pythonhosted.org/packages/6b/ba/497b8bea72b20a862ac95a94386967b745a472d9ddc88bc3f32d5d5f0d43/psycopg_binary-3.2.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6a76b4722a529390683c0304501f238b365a46b1e5fb6b7249dbc0ad6fea51a0", size = 4083795, upload-time = "2025-05-13T16:07:50.917Z" }, + { url = "https://files.pythonhosted.org/packages/42/07/af9503e8e8bdad3911fd88e10e6a29240f9feaa99f57d6fac4a18b16f5a0/psycopg_binary-3.2.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96a551e4683f1c307cfc3d9a05fec62c00a7264f320c9962a67a543e3ce0d8ff", size = 4655043, upload-time = "2025-05-13T16:07:54.857Z" }, + { url = "https://files.pythonhosted.org/packages/28/ed/aff8c9850df1648cc6a5cc7a381f11ee78d98a6b807edd4a5ae276ad60ad/psycopg_binary-3.2.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:61d0a6ceed8f08c75a395bc28cb648a81cf8dee75ba4650093ad1a24a51c8724", size = 4477972, upload-time = "2025-05-13T16:07:57.925Z" }, + { url = "https://files.pythonhosted.org/packages/5c/bd/8e9d1b77ec1a632818fe2f457c3a65af83c68710c4c162d6866947d08cc5/psycopg_binary-3.2.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad280bbd409bf598683dda82232f5215cfc5f2b1bf0854e409b4d0c44a113b1d", size = 4737516, upload-time = "2025-05-13T16:08:01.616Z" }, + { url = "https://files.pythonhosted.org/packages/46/ec/222238f774cd5a0881f3f3b18fb86daceae89cc410f91ef6a9fb4556f236/psycopg_binary-3.2.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76eddaf7fef1d0994e3d536ad48aa75034663d3a07f6f7e3e601105ae73aeff6", size = 4436160, upload-time = "2025-05-13T16:08:04.278Z" }, + { url = "https://files.pythonhosted.org/packages/37/78/af5af2a1b296eeca54ea7592cd19284739a844974c9747e516707e7b3b39/psycopg_binary-3.2.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:52e239cd66c4158e412318fbe028cd94b0ef21b0707f56dcb4bdc250ee58fd40", size = 3753518, upload-time = "2025-05-13T16:08:07.567Z" }, + { url = "https://files.pythonhosted.org/packages/ec/ac/8a3ed39ea069402e9e6e6a2f79d81a71879708b31cc3454283314994b1ae/psycopg_binary-3.2.9-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:08bf9d5eabba160dd4f6ad247cf12f229cc19d2458511cab2eb9647f42fa6795", size = 3313598, upload-time = "2025-05-13T16:08:09.999Z" }, + { url = "https://files.pythonhosted.org/packages/da/43/26549af068347c808fbfe5f07d2fa8cef747cfff7c695136172991d2378b/psycopg_binary-3.2.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1b2cf018168cad87580e67bdde38ff5e51511112f1ce6ce9a8336871f465c19a", size = 3407289, upload-time = "2025-05-13T16:08:12.66Z" }, + { url = "https://files.pythonhosted.org/packages/67/55/ea8d227c77df8e8aec880ded398316735add8fda5eb4ff5cc96fac11e964/psycopg_binary-3.2.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:14f64d1ac6942ff089fc7e926440f7a5ced062e2ed0949d7d2d680dc5c00e2d4", size = 3472493, upload-time = "2025-05-13T16:08:15.672Z" }, + { url = "https://files.pythonhosted.org/packages/3c/02/6ff2a5bc53c3cd653d281666728e29121149179c73fddefb1e437024c192/psycopg_binary-3.2.9-cp312-cp312-win_amd64.whl", hash = "sha256:7a838852e5afb6b4126f93eb409516a8c02a49b788f4df8b6469a40c2157fa21", size = 2927400, upload-time = "2025-05-13T16:08:18.652Z" }, + { url = "https://files.pythonhosted.org/packages/28/0b/f61ff4e9f23396aca674ed4d5c9a5b7323738021d5d72d36d8b865b3deaf/psycopg_binary-3.2.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:98bbe35b5ad24a782c7bf267596638d78aa0e87abc7837bdac5b2a2ab954179e", size = 4017127, upload-time = "2025-05-13T16:08:21.391Z" }, + { url = "https://files.pythonhosted.org/packages/bc/00/7e181fb1179fbfc24493738b61efd0453d4b70a0c4b12728e2b82db355fd/psycopg_binary-3.2.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:72691a1615ebb42da8b636c5ca9f2b71f266be9e172f66209a361c175b7842c5", size = 4080322, upload-time = "2025-05-13T16:08:24.049Z" }, + { url = "https://files.pythonhosted.org/packages/58/fd/94fc267c1d1392c4211e54ccb943be96ea4032e761573cf1047951887494/psycopg_binary-3.2.9-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25ab464bfba8c401f5536d5aa95f0ca1dd8257b5202eede04019b4415f491351", size = 4655097, upload-time = "2025-05-13T16:08:27.376Z" }, + { url = "https://files.pythonhosted.org/packages/41/17/31b3acf43de0b2ba83eac5878ff0dea5a608ca2a5c5dd48067999503a9de/psycopg_binary-3.2.9-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e8aeefebe752f46e3c4b769e53f1d4ad71208fe1150975ef7662c22cca80fab", size = 4482114, upload-time = "2025-05-13T16:08:30.781Z" }, + { url = "https://files.pythonhosted.org/packages/85/78/b4d75e5fd5a85e17f2beb977abbba3389d11a4536b116205846b0e1cf744/psycopg_binary-3.2.9-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7e4e4dd177a8665c9ce86bc9caae2ab3aa9360b7ce7ec01827ea1baea9ff748", size = 4737693, upload-time = "2025-05-13T16:08:34.625Z" }, + { url = "https://files.pythonhosted.org/packages/3b/95/7325a8550e3388b00b5e54f4ced5e7346b531eb4573bf054c3dbbfdc14fe/psycopg_binary-3.2.9-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fc2915949e5c1ea27a851f7a472a7da7d0a40d679f0a31e42f1022f3c562e87", size = 4437423, upload-time = "2025-05-13T16:08:37.444Z" }, + { url = "https://files.pythonhosted.org/packages/1a/db/cef77d08e59910d483df4ee6da8af51c03bb597f500f1fe818f0f3b925d3/psycopg_binary-3.2.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a1fa38a4687b14f517f049477178093c39c2a10fdcced21116f47c017516498f", size = 3758667, upload-time = "2025-05-13T16:08:40.116Z" }, + { url = "https://files.pythonhosted.org/packages/95/3e/252fcbffb47189aa84d723b54682e1bb6d05c8875fa50ce1ada914ae6e28/psycopg_binary-3.2.9-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5be8292d07a3ab828dc95b5ee6b69ca0a5b2e579a577b39671f4f5b47116dfd2", size = 3320576, upload-time = "2025-05-13T16:08:43.243Z" }, + { url = "https://files.pythonhosted.org/packages/1c/cd/9b5583936515d085a1bec32b45289ceb53b80d9ce1cea0fef4c782dc41a7/psycopg_binary-3.2.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:778588ca9897b6c6bab39b0d3034efff4c5438f5e3bd52fda3914175498202f9", size = 3411439, upload-time = "2025-05-13T16:08:47.321Z" }, + { url = "https://files.pythonhosted.org/packages/45/6b/6f1164ea1634c87956cdb6db759e0b8c5827f989ee3cdff0f5c70e8331f2/psycopg_binary-3.2.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f0d5b3af045a187aedbd7ed5fc513bd933a97aaff78e61c3745b330792c4345b", size = 3477477, upload-time = "2025-05-13T16:08:51.166Z" }, + { url = "https://files.pythonhosted.org/packages/7b/1d/bf54cfec79377929da600c16114f0da77a5f1670f45e0c3af9fcd36879bc/psycopg_binary-3.2.9-cp313-cp313-win_amd64.whl", hash = "sha256:2290bc146a1b6a9730350f695e8b670e1d1feb8446597bed0bbe7c3c30e0abcb", size = 2928009, upload-time = "2025-05-13T16:08:53.67Z" }, +] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, +] + +[[package]] +name = "pure-eval" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, +] + +[[package]] +name = "pyam-iamc" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "iam-units" }, + { name = "ixmp4" }, + { name = "matplotlib" }, + { name = "numpy" }, + { name = "openpyxl" }, + { name = "pandas" }, + { name = "pint" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "scipy" }, + { name = "seaborn" }, + { name = "wquantiles" }, + { name = "xlsxwriter" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/da/8d/9598f38cceed935f83778b53c7368408b5c293e84d33734b3a34c1a54ffe/pyam_iamc-3.0.0.tar.gz", hash = "sha256:ef333da4d239e66516ff31801879cac38384e8ebed70fe7705eec77af1305530", size = 91089, upload-time = "2024-12-19T13:40:52.289Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9b/a9/10d819bad953f2a83b01e602c1f64cb3c3b3ad0366f3198b995be76910c3/pyam_iamc-3.0.0-py3-none-any.whl", hash = "sha256:54f2b79b286e8c78083184c3b275bd8de7f8107bf6c0694ce4e1f1c9ad561378", size = 99422, upload-time = "2024-12-19T13:40:49.564Z" }, +] + +[[package]] +name = "pybtex" +version = "0.25.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "latexcodec" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5f/bc/c2be05ca72f8c103670e983df8be26d1e288bc6556f487fa8cccaa27779f/pybtex-0.25.1.tar.gz", hash = "sha256:9eaf90267c7e83e225af89fea65c370afbf65f458220d3946a9e3049e1eca491", size = 406157, upload-time = "2025-06-26T13:27:41.903Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/68/ceb5d6679baa326261f5d3e5113d9cfed6efef2810afd9f18bffb8ed312b/pybtex-0.25.1-py2.py3-none-any.whl", hash = "sha256:9053b0d619409a0a83f38abad5d9921de5f7b3ede00742beafcd9f10ad0d8c5c", size = 127437, upload-time = "2025-06-26T13:27:43.585Z" }, +] + +[[package]] +name = "pybtex-docutils" +version = "1.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docutils" }, + { name = "pybtex" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7e/84/796ea94d26188a853660f81bded39f8de4cfe595130aef0dea1088705a11/pybtex-docutils-1.0.3.tar.gz", hash = "sha256:3a7ebdf92b593e00e8c1c538aa9a20bca5d92d84231124715acc964d51d93c6b", size = 18348, upload-time = "2023-08-22T18:47:54.833Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/b1/ce1f4596211efb5410e178a803f08e59b20bedb66837dcf41e21c54f9ec1/pybtex_docutils-1.0.3-py3-none-any.whl", hash = "sha256:8fd290d2ae48e32fcb54d86b0efb8d573198653c7e2447d5bec5847095f430b9", size = 6385, upload-time = "2023-08-22T06:43:20.513Z" }, +] + +[[package]] +name = "pycparser" +version = "2.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736, upload-time = "2024-03-30T13:22:22.564Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552, upload-time = "2024-03-30T13:22:20.476Z" }, +] + +[[package]] +name = "pydantic" +version = "2.11.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350, upload-time = "2025-06-14T08:33:17.137Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782, upload-time = "2025-06-14T08:33:14.905Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.33.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" }, + { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" }, + { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" }, + { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" }, + { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" }, + { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" }, + { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" }, + { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" }, + { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" }, + { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" }, + { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" }, + { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" }, + { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" }, + { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" }, + { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" }, + { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" }, + { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" }, + { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" }, + { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" }, + { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" }, + { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" }, + { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" }, + { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" }, + { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" }, + { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" }, + { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" }, + { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" }, + { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" }, + { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" }, +] + +[[package]] +name = "pydantic-settings" +version = "2.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/68/85/1ea668bbab3c50071ca613c6ab30047fb36ab0da1b92fa8f17bbc38fd36c/pydantic_settings-2.10.1.tar.gz", hash = "sha256:06f0062169818d0f5524420a360d632d5857b83cffd4d42fe29597807a1614ee", size = 172583, upload-time = "2025-06-24T13:26:46.841Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/f0/427018098906416f580e3cf1366d3b1abfb408a0652e9f31600c24a1903c/pydantic_settings-2.10.1-py3-none-any.whl", hash = "sha256:a60952460b99cf661dc25c29c0ef171721f98bfcb52ef8d9ea4c943d7c8cc796", size = 45235, upload-time = "2025-06-24T13:26:45.485Z" }, +] + +[[package]] +name = "pydoe" +version = "0.3.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/ac/91fe4c039e2744466621343d3b8af4a485193ed0aab53af5b1db03be0989/pyDOE-0.3.8.zip", hash = "sha256:cbd6f14ae26d3c9f736013205f53ea1191add4567033c3ee77b7dd356566c4b6", size = 22283, upload-time = "2015-07-13T20:56:28.603Z" } + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pyjwt" +version = "2.10.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785, upload-time = "2024-11-28T03:43:29.933Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" }, +] + +[[package]] +name = "pyomo" +version = "6.9.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ply" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/53/69/84bbedd016eb8a4ab2bcc9dbffd346b266ff631d44552baea01b87862555/pyomo-6.9.2.tar.gz", hash = "sha256:81b2b14ea619244824e1c547cc12602fe9a6e19309cbf0742868c5b1ef37cb35", size = 2946406, upload-time = "2025-04-16T18:55:23.354Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/db/67f81a488173406b71cc8e2bcdb92b4598377a791d598ed5f540c86b2c8a/pyomo-6.9.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3a2f80da2afa3f6eadd17f9d897b15459c91b299325aa5b788f961e28d2802ab", size = 4133679, upload-time = "2025-04-16T18:55:38.504Z" }, + { url = "https://files.pythonhosted.org/packages/85/50/4b7f748c9983b39f4f8cabded63b17677e79211ac5238b6399d21c4b5b3b/pyomo-6.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:afd6944ff800554944fe5d5bc07d071c69c5d96df22b1edac4f784d3fbe2ff37", size = 4124480, upload-time = "2025-04-16T18:55:40.116Z" }, + { url = "https://files.pythonhosted.org/packages/85/00/894a72c888791dd381d179c43c52bf2138e71603fb970d78608eaa760c9f/pyomo-6.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d91d84c0632d98e417313c00612be87d04e59cc7056308b40901c4607bc206a", size = 4186850, upload-time = "2025-04-16T19:03:11.246Z" }, + { url = "https://files.pythonhosted.org/packages/00/2a/cd77620274a8c7053d637aa6cdbd76427f53217432f07aaf41110bc40a60/pyomo-6.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d890f67053d10d89a3a2b8bc3901dc7d926fbf225b4bd219167c00f9550a5ff", size = 4208175, upload-time = "2025-04-16T18:55:41.735Z" }, + { url = "https://files.pythonhosted.org/packages/dc/38/efe3c09a335869fa4d9a68f83ed207e73e8594eb4cccb753703ae4ec7d6b/pyomo-6.9.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f5f50e8247ffe2b26c44c496b2324b255b53e2d663d2f3f7db62ee376acfe9b2", size = 4133861, upload-time = "2025-04-16T18:55:43.489Z" }, + { url = "https://files.pythonhosted.org/packages/c8/4e/25d6eae73a8c4636fd8ac6e4a4f7d636d091a3aa4bc75ce3074c17e735c3/pyomo-6.9.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:58d830239f193d9f0a272602a35d1d1e39e72cac9ef26f7d88a0564862d56b2c", size = 4124667, upload-time = "2025-04-16T18:55:46.144Z" }, + { url = "https://files.pythonhosted.org/packages/a7/6e/575252f1cd70a39dc718f93235e1ad7d25bfbf8e558ac116a95c55139226/pyomo-6.9.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74776a900757c47b4269e4461766925e7cd4eb8f34a8565abfdec171e3fd73ed", size = 4186741, upload-time = "2025-04-16T19:03:12.767Z" }, + { url = "https://files.pythonhosted.org/packages/9f/1b/9929f2e8573b3486ea9fdb1d6b9018fe7199c64d96bf98e2f16cae725e60/pyomo-6.9.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16122a46beeff66f98f03a0291058bb956796da1fd93c82fb9c41336e3f2912f", size = 4208224, upload-time = "2025-04-16T18:55:47.732Z" }, + { url = "https://files.pythonhosted.org/packages/7f/88/0a07233e39357d3d620186485b927074d6d0ae0f64ad72cc5222ae05844e/pyomo-6.9.2-py3-none-any.whl", hash = "sha256:13ebb2f974f97afa626c2712d4f27e09a1c3d18ca11755676b743504a76e5161", size = 3799154, upload-time = "2025-04-16T18:55:52.044Z" }, +] + +[[package]] +name = "pyparsing" +version = "3.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/22/f1129e69d94ffff626bdb5c835506b3a5b4f3d070f17ea295e12c2c6f60f/pyparsing-3.2.3.tar.gz", hash = "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be", size = 1088608, upload-time = "2025-03-25T05:01:28.114Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/e7/df2285f3d08fee213f2d041540fa4fc9ca6c2d44cf36d3a035bf2a8d2bcc/pyparsing-3.2.3-py3-none-any.whl", hash = "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf", size = 111120, upload-time = "2025-03-25T05:01:24.908Z" }, +] + +[[package]] +name = "pytest" +version = "8.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/08/ba/45911d754e8eba3d5a841a5ce61a65a685ff1798421ac054f85aa8747dfb/pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c", size = 1517714, upload-time = "2025-06-18T05:48:06.109Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/29/16/c8a903f4c4dffe7a12843191437d7cd8e32751d5de349d45d3fe69544e87/pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7", size = 365474, upload-time = "2025-06-18T05:48:03.955Z" }, +] + +[[package]] +name = "pytest-cov" +version = "6.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage" }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/18/99/668cade231f434aaa59bbfbf49469068d2ddd945000621d3d165d2e7dd7b/pytest_cov-6.2.1.tar.gz", hash = "sha256:25cc6cc0a5358204b8108ecedc51a9b57b34cc6b8c967cc2c01a4e00d8a67da2", size = 69432, upload-time = "2025-06-12T10:47:47.684Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/16/4ea354101abb1287856baa4af2732be351c7bee728065aed451b678153fd/pytest_cov-6.2.1-py3-none-any.whl", hash = "sha256:f5bc4c23f42f1cdd23c70b1dab1bbaef4fc505ba950d53e0081d0730dd7e86d5", size = 24644, upload-time = "2025-06-12T10:47:45.932Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "python-dotenv" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/b0/4bc07ccd3572a2f9df7e6782f52b0c6c90dcbb803ac4a167702d7d0dfe1e/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab", size = 41978, upload-time = "2025-06-24T04:21:07.341Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" }, +] + +[[package]] +name = "python-json-logger" +version = "3.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9e/de/d3144a0bceede957f961e975f3752760fbe390d57fbe194baf709d8f1f7b/python_json_logger-3.3.0.tar.gz", hash = "sha256:12b7e74b17775e7d565129296105bbe3910842d9d0eb083fc83a6a617aa8df84", size = 16642, upload-time = "2025-03-07T07:08:27.301Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/20/0f2523b9e50a8052bc6a8b732dfc8568abbdc42010aef03a2d750bdab3b2/python_json_logger-3.3.0-py3-none-any.whl", hash = "sha256:dd980fae8cffb24c13caf6e158d3d61c0d6d22342f932cb6e9deedab3d35eec7", size = 15163, upload-time = "2025-03-07T07:08:25.627Z" }, +] + +[[package]] +name = "pytz" +version = "2025.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, +] + +[[package]] +name = "pyutilib" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nose" }, + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c6/fd/9cf9313b26398d1a77ee8b86b5e467ccae55b066cdc4a466186903e4000b/PyUtilib-6.0.0.tar.gz", hash = "sha256:d3c14f8ed9028a831b2bf51b8ab7776eba87e66cfc58a06b99c359aaa640f040", size = 178746, upload-time = "2020-06-19T14:30:52.51Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/e7/c3e5994b4e5c90280b5c14ffef409875ec5436d1d0d9f8585794993a7d77/PyUtilib-6.0.0-py2.py3-none-any.whl", hash = "sha256:f1f82d05ad8c42baeef915c8d3d97c0a3cbed6c506c857ab0ab7694dea50ebd8", size = 254187, upload-time = "2020-06-19T14:30:50.656Z" }, +] + +[[package]] +name = "pywin32" +version = "311" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/ab/01ea1943d4eba0f850c3c61e78e8dd59757ff815ff3ccd0a84de5f541f42/pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31", size = 8706543, upload-time = "2025-07-14T20:13:20.765Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a8/a0e8d07d4d051ec7502cd58b291ec98dcc0c3fff027caad0470b72cfcc2f/pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067", size = 9495040, upload-time = "2025-07-14T20:13:22.543Z" }, + { url = "https://files.pythonhosted.org/packages/ba/3a/2ae996277b4b50f17d61f0603efd8253cb2d79cc7ae159468007b586396d/pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852", size = 8710102, upload-time = "2025-07-14T20:13:24.682Z" }, + { url = "https://files.pythonhosted.org/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700, upload-time = "2025-07-14T20:13:26.471Z" }, + { url = "https://files.pythonhosted.org/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700, upload-time = "2025-07-14T20:13:28.243Z" }, + { url = "https://files.pythonhosted.org/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318, upload-time = "2025-07-14T20:13:30.348Z" }, + { url = "https://files.pythonhosted.org/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload-time = "2025-07-14T20:13:32.449Z" }, + { url = "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload-time = "2025-07-14T20:13:34.312Z" }, + { url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" }, +] + +[[package]] +name = "pywinpty" +version = "2.0.15" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/7c/917f9c4681bb8d34bfbe0b79d36bbcd902651aeab48790df3d30ba0202fb/pywinpty-2.0.15.tar.gz", hash = "sha256:312cf39153a8736c617d45ce8b6ad6cd2107de121df91c455b10ce6bba7a39b2", size = 29017, upload-time = "2025-02-03T21:53:23.265Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/e5/9714def18c3a411809771a3fbcec70bffa764b9675afb00048a620fca604/pywinpty-2.0.15-cp312-cp312-win_amd64.whl", hash = "sha256:83a8f20b430bbc5d8957249f875341a60219a4e971580f2ba694fbfb54a45ebc", size = 1405243, upload-time = "2025-02-03T21:56:52.476Z" }, + { url = "https://files.pythonhosted.org/packages/fb/16/2ab7b3b7f55f3c6929e5f629e1a68362981e4e5fed592a2ed1cb4b4914a5/pywinpty-2.0.15-cp313-cp313-win_amd64.whl", hash = "sha256:ab5920877dd632c124b4ed17bc6dd6ef3b9f86cd492b963ffdb1a67b85b0f408", size = 1405020, upload-time = "2025-02-03T21:56:04.753Z" }, + { url = "https://files.pythonhosted.org/packages/7c/16/edef3515dd2030db2795dbfbe392232c7a0f3dc41b98e92b38b42ba497c7/pywinpty-2.0.15-cp313-cp313t-win_amd64.whl", hash = "sha256:a4560ad8c01e537708d2790dbe7da7d986791de805d89dd0d3697ca59e9e4901", size = 1404151, upload-time = "2025-02-03T21:55:53.628Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, + { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, + { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, + { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, + { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, + { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, + { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, + { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, + { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, + { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, + { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, + { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, + { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, + { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, + { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, + { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, +] + +[[package]] +name = "pyzmq" +version = "27.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "implementation_name == 'pypy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f1/06/50a4e9648b3e8b992bef8eb632e457307553a89d294103213cfd47b3da69/pyzmq-27.0.0.tar.gz", hash = "sha256:b1f08eeb9ce1510e6939b6e5dcd46a17765e2333daae78ecf4606808442e52cf", size = 280478, upload-time = "2025-06-13T14:09:07.087Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/a7/9ad68f55b8834ede477842214feba6a4c786d936c022a67625497aacf61d/pyzmq-27.0.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:cbabc59dcfaac66655c040dfcb8118f133fb5dde185e5fc152628354c1598e52", size = 1305438, upload-time = "2025-06-13T14:07:31.676Z" }, + { url = "https://files.pythonhosted.org/packages/ba/ee/26aa0f98665a22bc90ebe12dced1de5f3eaca05363b717f6fb229b3421b3/pyzmq-27.0.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:cb0ac5179cba4b2f94f1aa208fbb77b62c4c9bf24dd446278b8b602cf85fcda3", size = 895095, upload-time = "2025-06-13T14:07:33.104Z" }, + { url = "https://files.pythonhosted.org/packages/cf/85/c57e7ab216ecd8aa4cc7e3b83b06cc4e9cf45c87b0afc095f10cd5ce87c1/pyzmq-27.0.0-cp312-abi3-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53a48f0228eab6cbf69fde3aa3c03cbe04e50e623ef92ae395fce47ef8a76152", size = 651826, upload-time = "2025-06-13T14:07:34.831Z" }, + { url = "https://files.pythonhosted.org/packages/69/9a/9ea7e230feda9400fb0ae0d61d7d6ddda635e718d941c44eeab22a179d34/pyzmq-27.0.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:111db5f395e09f7e775f759d598f43cb815fc58e0147623c4816486e1a39dc22", size = 839750, upload-time = "2025-06-13T14:07:36.553Z" }, + { url = "https://files.pythonhosted.org/packages/08/66/4cebfbe71f3dfbd417011daca267539f62ed0fbc68105357b68bbb1a25b7/pyzmq-27.0.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c8878011653dcdc27cc2c57e04ff96f0471e797f5c19ac3d7813a245bcb24371", size = 1641357, upload-time = "2025-06-13T14:07:38.21Z" }, + { url = "https://files.pythonhosted.org/packages/ac/f6/b0f62578c08d2471c791287149cb8c2aaea414ae98c6e995c7dbe008adfb/pyzmq-27.0.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:c0ed2c1f335ba55b5fdc964622254917d6b782311c50e138863eda409fbb3b6d", size = 2020281, upload-time = "2025-06-13T14:07:39.599Z" }, + { url = "https://files.pythonhosted.org/packages/37/b9/4f670b15c7498495da9159edc374ec09c88a86d9cd5a47d892f69df23450/pyzmq-27.0.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e918d70862d4cfd4b1c187310015646a14e1f5917922ab45b29f28f345eeb6be", size = 1877110, upload-time = "2025-06-13T14:07:41.027Z" }, + { url = "https://files.pythonhosted.org/packages/66/31/9dee25c226295b740609f0d46db2fe972b23b6f5cf786360980524a3ba92/pyzmq-27.0.0-cp312-abi3-win32.whl", hash = "sha256:88b4e43cab04c3c0f0d55df3b1eef62df2b629a1a369b5289a58f6fa8b07c4f4", size = 559297, upload-time = "2025-06-13T14:07:42.533Z" }, + { url = "https://files.pythonhosted.org/packages/9b/12/52da5509800f7ff2d287b2f2b4e636e7ea0f001181cba6964ff6c1537778/pyzmq-27.0.0-cp312-abi3-win_amd64.whl", hash = "sha256:dce4199bf5f648a902ce37e7b3afa286f305cd2ef7a8b6ec907470ccb6c8b371", size = 619203, upload-time = "2025-06-13T14:07:43.843Z" }, + { url = "https://files.pythonhosted.org/packages/93/6d/7f2e53b19d1edb1eb4f09ec7c3a1f945ca0aac272099eab757d15699202b/pyzmq-27.0.0-cp312-abi3-win_arm64.whl", hash = "sha256:56e46bbb85d52c1072b3f809cc1ce77251d560bc036d3a312b96db1afe76db2e", size = 551927, upload-time = "2025-06-13T14:07:45.51Z" }, + { url = "https://files.pythonhosted.org/packages/19/62/876b27c4ff777db4ceba1c69ea90d3c825bb4f8d5e7cd987ce5802e33c55/pyzmq-27.0.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:c36ad534c0c29b4afa088dc53543c525b23c0797e01b69fef59b1a9c0e38b688", size = 1340826, upload-time = "2025-06-13T14:07:46.881Z" }, + { url = "https://files.pythonhosted.org/packages/43/69/58ef8f4f59d3bcd505260c73bee87b008850f45edca40ddaba54273c35f4/pyzmq-27.0.0-cp313-cp313t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:67855c14173aec36395d7777aaba3cc527b393821f30143fd20b98e1ff31fd38", size = 897283, upload-time = "2025-06-13T14:07:49.562Z" }, + { url = "https://files.pythonhosted.org/packages/43/15/93a0d0396700a60475ad3c5d42c5f1c308d3570bc94626b86c71ef9953e0/pyzmq-27.0.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8617c7d43cd8ccdb62aebe984bfed77ca8f036e6c3e46dd3dddda64b10f0ab7a", size = 660567, upload-time = "2025-06-13T14:07:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/0e/b3/fe055513e498ca32f64509abae19b9c9eb4d7c829e02bd8997dd51b029eb/pyzmq-27.0.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:67bfbcbd0a04c575e8103a6061d03e393d9f80ffdb9beb3189261e9e9bc5d5e9", size = 847681, upload-time = "2025-06-13T14:07:52.77Z" }, + { url = "https://files.pythonhosted.org/packages/b6/4f/ff15300b00b5b602191f3df06bbc8dd4164e805fdd65bb77ffbb9c5facdc/pyzmq-27.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5cd11d46d7b7e5958121b3eaf4cd8638eff3a720ec527692132f05a57f14341d", size = 1650148, upload-time = "2025-06-13T14:07:54.178Z" }, + { url = "https://files.pythonhosted.org/packages/c4/6f/84bdfff2a224a6f26a24249a342e5906993c50b0761e311e81b39aef52a7/pyzmq-27.0.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:b801c2e40c5aa6072c2f4876de8dccd100af6d9918d4d0d7aa54a1d982fd4f44", size = 2023768, upload-time = "2025-06-13T14:07:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/64/39/dc2db178c26a42228c5ac94a9cc595030458aa64c8d796a7727947afbf55/pyzmq-27.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:20d5cb29e8c5f76a127c75b6e7a77e846bc4b655c373baa098c26a61b7ecd0ef", size = 1885199, upload-time = "2025-06-13T14:07:57.166Z" }, + { url = "https://files.pythonhosted.org/packages/c7/21/dae7b06a1f8cdee5d8e7a63d99c5d129c401acc40410bef2cbf42025e26f/pyzmq-27.0.0-cp313-cp313t-win32.whl", hash = "sha256:a20528da85c7ac7a19b7384e8c3f8fa707841fd85afc4ed56eda59d93e3d98ad", size = 575439, upload-time = "2025-06-13T14:07:58.959Z" }, + { url = "https://files.pythonhosted.org/packages/eb/bc/1709dc55f0970cf4cb8259e435e6773f9946f41a045c2cb90e870b7072da/pyzmq-27.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:d8229f2efece6a660ee211d74d91dbc2a76b95544d46c74c615e491900dc107f", size = 639933, upload-time = "2025-06-13T14:08:00.777Z" }, +] + +[[package]] +name = "referencing" +version = "0.36.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2f/db/98b5c277be99dd18bfd91dd04e1b759cad18d1a338188c936e92f921c7e2/referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", size = 74744, upload-time = "2025-01-25T08:48:16.138Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0", size = 26775, upload-time = "2025-01-25T08:48:14.241Z" }, +] + +[[package]] +name = "requests" +version = "2.32.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, +] + +[[package]] +name = "rfc3339-validator" +version = "0.1.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513, upload-time = "2021-05-12T16:37:54.178Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490, upload-time = "2021-05-12T16:37:52.536Z" }, +] + +[[package]] +name = "rfc3986-validator" +version = "0.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/da/88/f270de456dd7d11dcc808abfa291ecdd3f45ff44e3b549ffa01b126464d0/rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055", size = 6760, upload-time = "2019-10-28T16:00:19.144Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", size = 4242, upload-time = "2019-10-28T16:00:13.976Z" }, +] + +[[package]] +name = "rich" +version = "14.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078, upload-time = "2025-03-30T14:15:14.23Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229, upload-time = "2025-03-30T14:15:12.283Z" }, +] + +[[package]] +name = "roman-numerals-py" +version = "3.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/76/48fd56d17c5bdbdf65609abbc67288728a98ed4c02919428d4f52d23b24b/roman_numerals_py-3.1.0.tar.gz", hash = "sha256:be4bf804f083a4ce001b5eb7e3c0862479d10f94c936f6c4e5f250aa5ff5bd2d", size = 9017, upload-time = "2025-02-22T07:34:54.333Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/53/97/d2cbbaa10c9b826af0e10fdf836e1bf344d9f0abb873ebc34d1f49642d3f/roman_numerals_py-3.1.0-py3-none-any.whl", hash = "sha256:9da2ad2fb670bcf24e81070ceb3be72f6c11c440d73bd579fbeca1e9f330954c", size = 7742, upload-time = "2025-02-22T07:34:52.422Z" }, +] + +[[package]] +name = "rpds-py" +version = "0.26.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a5/aa/4456d84bbb54adc6a916fb10c9b374f78ac840337644e4a5eda229c81275/rpds_py-0.26.0.tar.gz", hash = "sha256:20dae58a859b0906f0685642e591056f1e787f3a8b39c8e8749a45dc7d26bdb0", size = 27385, upload-time = "2025-07-01T15:57:13.958Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/86/90eb87c6f87085868bd077c7a9938006eb1ce19ed4d06944a90d3560fce2/rpds_py-0.26.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:894514d47e012e794f1350f076c427d2347ebf82f9b958d554d12819849a369d", size = 363933, upload-time = "2025-07-01T15:54:15.734Z" }, + { url = "https://files.pythonhosted.org/packages/63/78/4469f24d34636242c924626082b9586f064ada0b5dbb1e9d096ee7a8e0c6/rpds_py-0.26.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc921b96fa95a097add244da36a1d9e4f3039160d1d30f1b35837bf108c21136", size = 350447, upload-time = "2025-07-01T15:54:16.922Z" }, + { url = "https://files.pythonhosted.org/packages/ad/91/c448ed45efdfdade82348d5e7995e15612754826ea640afc20915119734f/rpds_py-0.26.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e1157659470aa42a75448b6e943c895be8c70531c43cb78b9ba990778955582", size = 384711, upload-time = "2025-07-01T15:54:18.101Z" }, + { url = "https://files.pythonhosted.org/packages/ec/43/e5c86fef4be7f49828bdd4ecc8931f0287b1152c0bb0163049b3218740e7/rpds_py-0.26.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:521ccf56f45bb3a791182dc6b88ae5f8fa079dd705ee42138c76deb1238e554e", size = 400865, upload-time = "2025-07-01T15:54:19.295Z" }, + { url = "https://files.pythonhosted.org/packages/55/34/e00f726a4d44f22d5c5fe2e5ddd3ac3d7fd3f74a175607781fbdd06fe375/rpds_py-0.26.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9def736773fd56b305c0eef698be5192c77bfa30d55a0e5885f80126c4831a15", size = 517763, upload-time = "2025-07-01T15:54:20.858Z" }, + { url = "https://files.pythonhosted.org/packages/52/1c/52dc20c31b147af724b16104500fba13e60123ea0334beba7b40e33354b4/rpds_py-0.26.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cdad4ea3b4513b475e027be79e5a0ceac8ee1c113a1a11e5edc3c30c29f964d8", size = 406651, upload-time = "2025-07-01T15:54:22.508Z" }, + { url = "https://files.pythonhosted.org/packages/2e/77/87d7bfabfc4e821caa35481a2ff6ae0b73e6a391bb6b343db2c91c2b9844/rpds_py-0.26.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82b165b07f416bdccf5c84546a484cc8f15137ca38325403864bfdf2b5b72f6a", size = 386079, upload-time = "2025-07-01T15:54:23.987Z" }, + { url = "https://files.pythonhosted.org/packages/e3/d4/7f2200c2d3ee145b65b3cddc4310d51f7da6a26634f3ac87125fd789152a/rpds_py-0.26.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d04cab0a54b9dba4d278fe955a1390da3cf71f57feb78ddc7cb67cbe0bd30323", size = 421379, upload-time = "2025-07-01T15:54:25.073Z" }, + { url = "https://files.pythonhosted.org/packages/ae/13/9fdd428b9c820869924ab62236b8688b122baa22d23efdd1c566938a39ba/rpds_py-0.26.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:79061ba1a11b6a12743a2b0f72a46aa2758613d454aa6ba4f5a265cc48850158", size = 562033, upload-time = "2025-07-01T15:54:26.225Z" }, + { url = "https://files.pythonhosted.org/packages/f3/e1/b69686c3bcbe775abac3a4c1c30a164a2076d28df7926041f6c0eb5e8d28/rpds_py-0.26.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f405c93675d8d4c5ac87364bb38d06c988e11028a64b52a47158a355079661f3", size = 591639, upload-time = "2025-07-01T15:54:27.424Z" }, + { url = "https://files.pythonhosted.org/packages/5c/c9/1e3d8c8863c84a90197ac577bbc3d796a92502124c27092413426f670990/rpds_py-0.26.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dafd4c44b74aa4bed4b250f1aed165b8ef5de743bcca3b88fc9619b6087093d2", size = 557105, upload-time = "2025-07-01T15:54:29.93Z" }, + { url = "https://files.pythonhosted.org/packages/9f/c5/90c569649057622959f6dcc40f7b516539608a414dfd54b8d77e3b201ac0/rpds_py-0.26.0-cp312-cp312-win32.whl", hash = "sha256:3da5852aad63fa0c6f836f3359647870e21ea96cf433eb393ffa45263a170d44", size = 223272, upload-time = "2025-07-01T15:54:31.128Z" }, + { url = "https://files.pythonhosted.org/packages/7d/16/19f5d9f2a556cfed454eebe4d354c38d51c20f3db69e7b4ce6cff904905d/rpds_py-0.26.0-cp312-cp312-win_amd64.whl", hash = "sha256:cf47cfdabc2194a669dcf7a8dbba62e37a04c5041d2125fae0233b720da6f05c", size = 234995, upload-time = "2025-07-01T15:54:32.195Z" }, + { url = "https://files.pythonhosted.org/packages/83/f0/7935e40b529c0e752dfaa7880224771b51175fce08b41ab4a92eb2fbdc7f/rpds_py-0.26.0-cp312-cp312-win_arm64.whl", hash = "sha256:20ab1ae4fa534f73647aad289003f1104092890849e0266271351922ed5574f8", size = 223198, upload-time = "2025-07-01T15:54:33.271Z" }, + { url = "https://files.pythonhosted.org/packages/6a/67/bb62d0109493b12b1c6ab00de7a5566aa84c0e44217c2d94bee1bd370da9/rpds_py-0.26.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:696764a5be111b036256c0b18cd29783fab22154690fc698062fc1b0084b511d", size = 363917, upload-time = "2025-07-01T15:54:34.755Z" }, + { url = "https://files.pythonhosted.org/packages/4b/f3/34e6ae1925a5706c0f002a8d2d7f172373b855768149796af87bd65dcdb9/rpds_py-0.26.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1e6c15d2080a63aaed876e228efe4f814bc7889c63b1e112ad46fdc8b368b9e1", size = 350073, upload-time = "2025-07-01T15:54:36.292Z" }, + { url = "https://files.pythonhosted.org/packages/75/83/1953a9d4f4e4de7fd0533733e041c28135f3c21485faaef56a8aadbd96b5/rpds_py-0.26.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:390e3170babf42462739a93321e657444f0862c6d722a291accc46f9d21ed04e", size = 384214, upload-time = "2025-07-01T15:54:37.469Z" }, + { url = "https://files.pythonhosted.org/packages/48/0e/983ed1b792b3322ea1d065e67f4b230f3b96025f5ce3878cc40af09b7533/rpds_py-0.26.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7da84c2c74c0f5bc97d853d9e17bb83e2dcafcff0dc48286916001cc114379a1", size = 400113, upload-time = "2025-07-01T15:54:38.954Z" }, + { url = "https://files.pythonhosted.org/packages/69/7f/36c0925fff6f660a80be259c5b4f5e53a16851f946eb080351d057698528/rpds_py-0.26.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c5fe114a6dd480a510b6d3661d09d67d1622c4bf20660a474507aaee7eeeee9", size = 515189, upload-time = "2025-07-01T15:54:40.57Z" }, + { url = "https://files.pythonhosted.org/packages/13/45/cbf07fc03ba7a9b54662c9badb58294ecfb24f828b9732970bd1a431ed5c/rpds_py-0.26.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3100b3090269f3a7ea727b06a6080d4eb7439dca4c0e91a07c5d133bb1727ea7", size = 406998, upload-time = "2025-07-01T15:54:43.025Z" }, + { url = "https://files.pythonhosted.org/packages/6c/b0/8fa5e36e58657997873fd6a1cf621285ca822ca75b4b3434ead047daa307/rpds_py-0.26.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c03c9b0c64afd0320ae57de4c982801271c0c211aa2d37f3003ff5feb75bb04", size = 385903, upload-time = "2025-07-01T15:54:44.752Z" }, + { url = "https://files.pythonhosted.org/packages/4b/f7/b25437772f9f57d7a9fbd73ed86d0dcd76b4c7c6998348c070d90f23e315/rpds_py-0.26.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5963b72ccd199ade6ee493723d18a3f21ba7d5b957017607f815788cef50eaf1", size = 419785, upload-time = "2025-07-01T15:54:46.043Z" }, + { url = "https://files.pythonhosted.org/packages/a7/6b/63ffa55743dfcb4baf2e9e77a0b11f7f97ed96a54558fcb5717a4b2cd732/rpds_py-0.26.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9da4e873860ad5bab3291438525cae80169daecbfafe5657f7f5fb4d6b3f96b9", size = 561329, upload-time = "2025-07-01T15:54:47.64Z" }, + { url = "https://files.pythonhosted.org/packages/2f/07/1f4f5e2886c480a2346b1e6759c00278b8a69e697ae952d82ae2e6ee5db0/rpds_py-0.26.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5afaddaa8e8c7f1f7b4c5c725c0070b6eed0228f705b90a1732a48e84350f4e9", size = 590875, upload-time = "2025-07-01T15:54:48.9Z" }, + { url = "https://files.pythonhosted.org/packages/cc/bc/e6639f1b91c3a55f8c41b47d73e6307051b6e246254a827ede730624c0f8/rpds_py-0.26.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4916dc96489616a6f9667e7526af8fa693c0fdb4f3acb0e5d9f4400eb06a47ba", size = 556636, upload-time = "2025-07-01T15:54:50.619Z" }, + { url = "https://files.pythonhosted.org/packages/05/4c/b3917c45566f9f9a209d38d9b54a1833f2bb1032a3e04c66f75726f28876/rpds_py-0.26.0-cp313-cp313-win32.whl", hash = "sha256:2a343f91b17097c546b93f7999976fd6c9d5900617aa848c81d794e062ab302b", size = 222663, upload-time = "2025-07-01T15:54:52.023Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0b/0851bdd6025775aaa2365bb8de0697ee2558184c800bfef8d7aef5ccde58/rpds_py-0.26.0-cp313-cp313-win_amd64.whl", hash = "sha256:0a0b60701f2300c81b2ac88a5fb893ccfa408e1c4a555a77f908a2596eb875a5", size = 234428, upload-time = "2025-07-01T15:54:53.692Z" }, + { url = "https://files.pythonhosted.org/packages/ed/e8/a47c64ed53149c75fb581e14a237b7b7cd18217e969c30d474d335105622/rpds_py-0.26.0-cp313-cp313-win_arm64.whl", hash = "sha256:257d011919f133a4746958257f2c75238e3ff54255acd5e3e11f3ff41fd14256", size = 222571, upload-time = "2025-07-01T15:54:54.822Z" }, + { url = "https://files.pythonhosted.org/packages/89/bf/3d970ba2e2bcd17d2912cb42874107390f72873e38e79267224110de5e61/rpds_py-0.26.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:529c8156d7506fba5740e05da8795688f87119cce330c244519cf706a4a3d618", size = 360475, upload-time = "2025-07-01T15:54:56.228Z" }, + { url = "https://files.pythonhosted.org/packages/82/9f/283e7e2979fc4ec2d8ecee506d5a3675fce5ed9b4b7cb387ea5d37c2f18d/rpds_py-0.26.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f53ec51f9d24e9638a40cabb95078ade8c99251945dad8d57bf4aabe86ecee35", size = 346692, upload-time = "2025-07-01T15:54:58.561Z" }, + { url = "https://files.pythonhosted.org/packages/e3/03/7e50423c04d78daf391da3cc4330bdb97042fc192a58b186f2d5deb7befd/rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab504c4d654e4a29558eaa5bb8cea5fdc1703ea60a8099ffd9c758472cf913f", size = 379415, upload-time = "2025-07-01T15:54:59.751Z" }, + { url = "https://files.pythonhosted.org/packages/57/00/d11ee60d4d3b16808432417951c63df803afb0e0fc672b5e8d07e9edaaae/rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd0641abca296bc1a00183fe44f7fced8807ed49d501f188faa642d0e4975b83", size = 391783, upload-time = "2025-07-01T15:55:00.898Z" }, + { url = "https://files.pythonhosted.org/packages/08/b3/1069c394d9c0d6d23c5b522e1f6546b65793a22950f6e0210adcc6f97c3e/rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69b312fecc1d017b5327afa81d4da1480f51c68810963a7336d92203dbb3d4f1", size = 512844, upload-time = "2025-07-01T15:55:02.201Z" }, + { url = "https://files.pythonhosted.org/packages/08/3b/c4fbf0926800ed70b2c245ceca99c49f066456755f5d6eb8863c2c51e6d0/rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c741107203954f6fc34d3066d213d0a0c40f7bb5aafd698fb39888af277c70d8", size = 402105, upload-time = "2025-07-01T15:55:03.698Z" }, + { url = "https://files.pythonhosted.org/packages/1c/b0/db69b52ca07413e568dae9dc674627a22297abb144c4d6022c6d78f1e5cc/rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc3e55a7db08dc9a6ed5fb7103019d2c1a38a349ac41901f9f66d7f95750942f", size = 383440, upload-time = "2025-07-01T15:55:05.398Z" }, + { url = "https://files.pythonhosted.org/packages/4c/e1/c65255ad5b63903e56b3bb3ff9dcc3f4f5c3badde5d08c741ee03903e951/rpds_py-0.26.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9e851920caab2dbcae311fd28f4313c6953993893eb5c1bb367ec69d9a39e7ed", size = 412759, upload-time = "2025-07-01T15:55:08.316Z" }, + { url = "https://files.pythonhosted.org/packages/e4/22/bb731077872377a93c6e93b8a9487d0406c70208985831034ccdeed39c8e/rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:dfbf280da5f876d0b00c81f26bedce274e72a678c28845453885a9b3c22ae632", size = 556032, upload-time = "2025-07-01T15:55:09.52Z" }, + { url = "https://files.pythonhosted.org/packages/e0/8b/393322ce7bac5c4530fb96fc79cc9ea2f83e968ff5f6e873f905c493e1c4/rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1cc81d14ddfa53d7f3906694d35d54d9d3f850ef8e4e99ee68bc0d1e5fed9a9c", size = 585416, upload-time = "2025-07-01T15:55:11.216Z" }, + { url = "https://files.pythonhosted.org/packages/49/ae/769dc372211835bf759319a7aae70525c6eb523e3371842c65b7ef41c9c6/rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dca83c498b4650a91efcf7b88d669b170256bf8017a5db6f3e06c2bf031f57e0", size = 554049, upload-time = "2025-07-01T15:55:13.004Z" }, + { url = "https://files.pythonhosted.org/packages/6b/f9/4c43f9cc203d6ba44ce3146246cdc38619d92c7bd7bad4946a3491bd5b70/rpds_py-0.26.0-cp313-cp313t-win32.whl", hash = "sha256:4d11382bcaf12f80b51d790dee295c56a159633a8e81e6323b16e55d81ae37e9", size = 218428, upload-time = "2025-07-01T15:55:14.486Z" }, + { url = "https://files.pythonhosted.org/packages/7e/8b/9286b7e822036a4a977f2f1e851c7345c20528dbd56b687bb67ed68a8ede/rpds_py-0.26.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff110acded3c22c033e637dd8896e411c7d3a11289b2edf041f86663dbc791e9", size = 231524, upload-time = "2025-07-01T15:55:15.745Z" }, + { url = "https://files.pythonhosted.org/packages/55/07/029b7c45db910c74e182de626dfdae0ad489a949d84a468465cd0ca36355/rpds_py-0.26.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:da619979df60a940cd434084355c514c25cf8eb4cf9a508510682f6c851a4f7a", size = 364292, upload-time = "2025-07-01T15:55:17.001Z" }, + { url = "https://files.pythonhosted.org/packages/13/d1/9b3d3f986216b4d1f584878dca15ce4797aaf5d372d738974ba737bf68d6/rpds_py-0.26.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ea89a2458a1a75f87caabefe789c87539ea4e43b40f18cff526052e35bbb4fdf", size = 350334, upload-time = "2025-07-01T15:55:18.922Z" }, + { url = "https://files.pythonhosted.org/packages/18/98/16d5e7bc9ec715fa9668731d0cf97f6b032724e61696e2db3d47aeb89214/rpds_py-0.26.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feac1045b3327a45944e7dcbeb57530339f6b17baff154df51ef8b0da34c8c12", size = 384875, upload-time = "2025-07-01T15:55:20.399Z" }, + { url = "https://files.pythonhosted.org/packages/f9/13/aa5e2b1ec5ab0e86a5c464d53514c0467bec6ba2507027d35fc81818358e/rpds_py-0.26.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b818a592bd69bfe437ee8368603d4a2d928c34cffcdf77c2e761a759ffd17d20", size = 399993, upload-time = "2025-07-01T15:55:21.729Z" }, + { url = "https://files.pythonhosted.org/packages/17/03/8021810b0e97923abdbab6474c8b77c69bcb4b2c58330777df9ff69dc559/rpds_py-0.26.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a8b0dd8648709b62d9372fc00a57466f5fdeefed666afe3fea5a6c9539a0331", size = 516683, upload-time = "2025-07-01T15:55:22.918Z" }, + { url = "https://files.pythonhosted.org/packages/dc/b1/da8e61c87c2f3d836954239fdbbfb477bb7b54d74974d8f6fcb34342d166/rpds_py-0.26.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6d3498ad0df07d81112aa6ec6c95a7e7b1ae00929fb73e7ebee0f3faaeabad2f", size = 408825, upload-time = "2025-07-01T15:55:24.207Z" }, + { url = "https://files.pythonhosted.org/packages/38/bc/1fc173edaaa0e52c94b02a655db20697cb5fa954ad5a8e15a2c784c5cbdd/rpds_py-0.26.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24a4146ccb15be237fdef10f331c568e1b0e505f8c8c9ed5d67759dac58ac246", size = 387292, upload-time = "2025-07-01T15:55:25.554Z" }, + { url = "https://files.pythonhosted.org/packages/7c/eb/3a9bb4bd90867d21916f253caf4f0d0be7098671b6715ad1cead9fe7bab9/rpds_py-0.26.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a9a63785467b2d73635957d32a4f6e73d5e4df497a16a6392fa066b753e87387", size = 420435, upload-time = "2025-07-01T15:55:27.798Z" }, + { url = "https://files.pythonhosted.org/packages/cd/16/e066dcdb56f5632713445271a3f8d3d0b426d51ae9c0cca387799df58b02/rpds_py-0.26.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:de4ed93a8c91debfd5a047be327b7cc8b0cc6afe32a716bbbc4aedca9e2a83af", size = 562410, upload-time = "2025-07-01T15:55:29.057Z" }, + { url = "https://files.pythonhosted.org/packages/60/22/ddbdec7eb82a0dc2e455be44c97c71c232983e21349836ce9f272e8a3c29/rpds_py-0.26.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:caf51943715b12af827696ec395bfa68f090a4c1a1d2509eb4e2cb69abbbdb33", size = 590724, upload-time = "2025-07-01T15:55:30.719Z" }, + { url = "https://files.pythonhosted.org/packages/2c/b4/95744085e65b7187d83f2fcb0bef70716a1ea0a9e5d8f7f39a86e5d83424/rpds_py-0.26.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4a59e5bc386de021f56337f757301b337d7ab58baa40174fb150accd480bc953", size = 558285, upload-time = "2025-07-01T15:55:31.981Z" }, + { url = "https://files.pythonhosted.org/packages/37/37/6309a75e464d1da2559446f9c811aa4d16343cebe3dbb73701e63f760caa/rpds_py-0.26.0-cp314-cp314-win32.whl", hash = "sha256:92c8db839367ef16a662478f0a2fe13e15f2227da3c1430a782ad0f6ee009ec9", size = 223459, upload-time = "2025-07-01T15:55:33.312Z" }, + { url = "https://files.pythonhosted.org/packages/d9/6f/8e9c11214c46098b1d1391b7e02b70bb689ab963db3b19540cba17315291/rpds_py-0.26.0-cp314-cp314-win_amd64.whl", hash = "sha256:b0afb8cdd034150d4d9f53926226ed27ad15b7f465e93d7468caaf5eafae0d37", size = 236083, upload-time = "2025-07-01T15:55:34.933Z" }, + { url = "https://files.pythonhosted.org/packages/47/af/9c4638994dd623d51c39892edd9d08e8be8220a4b7e874fa02c2d6e91955/rpds_py-0.26.0-cp314-cp314-win_arm64.whl", hash = "sha256:ca3f059f4ba485d90c8dc75cb5ca897e15325e4e609812ce57f896607c1c0867", size = 223291, upload-time = "2025-07-01T15:55:36.202Z" }, + { url = "https://files.pythonhosted.org/packages/4d/db/669a241144460474aab03e254326b32c42def83eb23458a10d163cb9b5ce/rpds_py-0.26.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:5afea17ab3a126006dc2f293b14ffc7ef3c85336cf451564a0515ed7648033da", size = 361445, upload-time = "2025-07-01T15:55:37.483Z" }, + { url = "https://files.pythonhosted.org/packages/3b/2d/133f61cc5807c6c2fd086a46df0eb8f63a23f5df8306ff9f6d0fd168fecc/rpds_py-0.26.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:69f0c0a3df7fd3a7eec50a00396104bb9a843ea6d45fcc31c2d5243446ffd7a7", size = 347206, upload-time = "2025-07-01T15:55:38.828Z" }, + { url = "https://files.pythonhosted.org/packages/05/bf/0e8fb4c05f70273469eecf82f6ccf37248558526a45321644826555db31b/rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:801a71f70f9813e82d2513c9a96532551fce1e278ec0c64610992c49c04c2dad", size = 380330, upload-time = "2025-07-01T15:55:40.175Z" }, + { url = "https://files.pythonhosted.org/packages/d4/a8/060d24185d8b24d3923322f8d0ede16df4ade226a74e747b8c7c978e3dd3/rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:df52098cde6d5e02fa75c1f6244f07971773adb4a26625edd5c18fee906fa84d", size = 392254, upload-time = "2025-07-01T15:55:42.015Z" }, + { url = "https://files.pythonhosted.org/packages/b9/7b/7c2e8a9ee3e6bc0bae26bf29f5219955ca2fbb761dca996a83f5d2f773fe/rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bc596b30f86dc6f0929499c9e574601679d0341a0108c25b9b358a042f51bca", size = 516094, upload-time = "2025-07-01T15:55:43.603Z" }, + { url = "https://files.pythonhosted.org/packages/75/d6/f61cafbed8ba1499b9af9f1777a2a199cd888f74a96133d8833ce5eaa9c5/rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9dfbe56b299cf5875b68eb6f0ebaadc9cac520a1989cac0db0765abfb3709c19", size = 402889, upload-time = "2025-07-01T15:55:45.275Z" }, + { url = "https://files.pythonhosted.org/packages/92/19/c8ac0a8a8df2dd30cdec27f69298a5c13e9029500d6d76718130f5e5be10/rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac64f4b2bdb4ea622175c9ab7cf09444e412e22c0e02e906978b3b488af5fde8", size = 384301, upload-time = "2025-07-01T15:55:47.098Z" }, + { url = "https://files.pythonhosted.org/packages/41/e1/6b1859898bc292a9ce5776016c7312b672da00e25cec74d7beced1027286/rpds_py-0.26.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:181ef9b6bbf9845a264f9aa45c31836e9f3c1f13be565d0d010e964c661d1e2b", size = 412891, upload-time = "2025-07-01T15:55:48.412Z" }, + { url = "https://files.pythonhosted.org/packages/ef/b9/ceb39af29913c07966a61367b3c08b4f71fad841e32c6b59a129d5974698/rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:49028aa684c144ea502a8e847d23aed5e4c2ef7cadfa7d5eaafcb40864844b7a", size = 557044, upload-time = "2025-07-01T15:55:49.816Z" }, + { url = "https://files.pythonhosted.org/packages/2f/27/35637b98380731a521f8ec4f3fd94e477964f04f6b2f8f7af8a2d889a4af/rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e5d524d68a474a9688336045bbf76cb0def88549c1b2ad9dbfec1fb7cfbe9170", size = 585774, upload-time = "2025-07-01T15:55:51.192Z" }, + { url = "https://files.pythonhosted.org/packages/52/d9/3f0f105420fecd18551b678c9a6ce60bd23986098b252a56d35781b3e7e9/rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c1851f429b822831bd2edcbe0cfd12ee9ea77868f8d3daf267b189371671c80e", size = 554886, upload-time = "2025-07-01T15:55:52.541Z" }, + { url = "https://files.pythonhosted.org/packages/6b/c5/347c056a90dc8dd9bc240a08c527315008e1b5042e7a4cf4ac027be9d38a/rpds_py-0.26.0-cp314-cp314t-win32.whl", hash = "sha256:7bdb17009696214c3b66bb3590c6d62e14ac5935e53e929bcdbc5a495987a84f", size = 219027, upload-time = "2025-07-01T15:55:53.874Z" }, + { url = "https://files.pythonhosted.org/packages/75/04/5302cea1aa26d886d34cadbf2dc77d90d7737e576c0065f357b96dc7a1a6/rpds_py-0.26.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f14440b9573a6f76b4ee4770c13f0b5921f71dde3b6fcb8dabbefd13b7fe05d7", size = 232821, upload-time = "2025-07-01T15:55:55.167Z" }, +] + +[[package]] +name = "ruff" +version = "0.12.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/2a/43955b530c49684d3c38fcda18c43caf91e99204c2a065552528e0552d4f/ruff-0.12.3.tar.gz", hash = "sha256:f1b5a4b6668fd7b7ea3697d8d98857390b40c1320a63a178eee6be0899ea2d77", size = 4459341, upload-time = "2025-07-11T13:21:16.086Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e2/fd/b44c5115539de0d598d75232a1cc7201430b6891808df111b8b0506aae43/ruff-0.12.3-py3-none-linux_armv6l.whl", hash = "sha256:47552138f7206454eaf0c4fe827e546e9ddac62c2a3d2585ca54d29a890137a2", size = 10430499, upload-time = "2025-07-11T13:20:26.321Z" }, + { url = "https://files.pythonhosted.org/packages/43/c5/9eba4f337970d7f639a37077be067e4ec80a2ad359e4cc6c5b56805cbc66/ruff-0.12.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:0a9153b000c6fe169bb307f5bd1b691221c4286c133407b8827c406a55282041", size = 11213413, upload-time = "2025-07-11T13:20:30.017Z" }, + { url = "https://files.pythonhosted.org/packages/e2/2c/fac3016236cf1fe0bdc8e5de4f24c76ce53c6dd9b5f350d902549b7719b2/ruff-0.12.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fa6b24600cf3b750e48ddb6057e901dd5b9aa426e316addb2a1af185a7509882", size = 10586941, upload-time = "2025-07-11T13:20:33.046Z" }, + { url = "https://files.pythonhosted.org/packages/c5/0f/41fec224e9dfa49a139f0b402ad6f5d53696ba1800e0f77b279d55210ca9/ruff-0.12.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2506961bf6ead54887ba3562604d69cb430f59b42133d36976421bc8bd45901", size = 10783001, upload-time = "2025-07-11T13:20:35.534Z" }, + { url = "https://files.pythonhosted.org/packages/0d/ca/dd64a9ce56d9ed6cad109606ac014860b1c217c883e93bf61536400ba107/ruff-0.12.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c4faaff1f90cea9d3033cbbcdf1acf5d7fb11d8180758feb31337391691f3df0", size = 10269641, upload-time = "2025-07-11T13:20:38.459Z" }, + { url = "https://files.pythonhosted.org/packages/63/5c/2be545034c6bd5ce5bb740ced3e7014d7916f4c445974be11d2a406d5088/ruff-0.12.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40dced4a79d7c264389de1c59467d5d5cefd79e7e06d1dfa2c75497b5269a5a6", size = 11875059, upload-time = "2025-07-11T13:20:41.517Z" }, + { url = "https://files.pythonhosted.org/packages/8e/d4/a74ef1e801ceb5855e9527dae105eaff136afcb9cc4d2056d44feb0e4792/ruff-0.12.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:0262d50ba2767ed0fe212aa7e62112a1dcbfd46b858c5bf7bbd11f326998bafc", size = 12658890, upload-time = "2025-07-11T13:20:44.442Z" }, + { url = "https://files.pythonhosted.org/packages/13/c8/1057916416de02e6d7c9bcd550868a49b72df94e3cca0aeb77457dcd9644/ruff-0.12.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12371aec33e1a3758597c5c631bae9a5286f3c963bdfb4d17acdd2d395406687", size = 12232008, upload-time = "2025-07-11T13:20:47.374Z" }, + { url = "https://files.pythonhosted.org/packages/f5/59/4f7c130cc25220392051fadfe15f63ed70001487eca21d1796db46cbcc04/ruff-0.12.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:560f13b6baa49785665276c963edc363f8ad4b4fc910a883e2625bdb14a83a9e", size = 11499096, upload-time = "2025-07-11T13:20:50.348Z" }, + { url = "https://files.pythonhosted.org/packages/d4/01/a0ad24a5d2ed6be03a312e30d32d4e3904bfdbc1cdbe63c47be9d0e82c79/ruff-0.12.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:023040a3499f6f974ae9091bcdd0385dd9e9eb4942f231c23c57708147b06311", size = 11688307, upload-time = "2025-07-11T13:20:52.945Z" }, + { url = "https://files.pythonhosted.org/packages/93/72/08f9e826085b1f57c9a0226e48acb27643ff19b61516a34c6cab9d6ff3fa/ruff-0.12.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:883d844967bffff5ab28bba1a4d246c1a1b2933f48cb9840f3fdc5111c603b07", size = 10661020, upload-time = "2025-07-11T13:20:55.799Z" }, + { url = "https://files.pythonhosted.org/packages/80/a0/68da1250d12893466c78e54b4a0ff381370a33d848804bb51279367fc688/ruff-0.12.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:2120d3aa855ff385e0e562fdee14d564c9675edbe41625c87eeab744a7830d12", size = 10246300, upload-time = "2025-07-11T13:20:58.222Z" }, + { url = "https://files.pythonhosted.org/packages/6a/22/5f0093d556403e04b6fd0984fc0fb32fbb6f6ce116828fd54306a946f444/ruff-0.12.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6b16647cbb470eaf4750d27dddc6ebf7758b918887b56d39e9c22cce2049082b", size = 11263119, upload-time = "2025-07-11T13:21:01.503Z" }, + { url = "https://files.pythonhosted.org/packages/92/c9/f4c0b69bdaffb9968ba40dd5fa7df354ae0c73d01f988601d8fac0c639b1/ruff-0.12.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e1417051edb436230023575b149e8ff843a324557fe0a265863b7602df86722f", size = 11746990, upload-time = "2025-07-11T13:21:04.524Z" }, + { url = "https://files.pythonhosted.org/packages/fe/84/7cc7bd73924ee6be4724be0db5414a4a2ed82d06b30827342315a1be9e9c/ruff-0.12.3-py3-none-win32.whl", hash = "sha256:dfd45e6e926deb6409d0616078a666ebce93e55e07f0fb0228d4b2608b2c248d", size = 10589263, upload-time = "2025-07-11T13:21:07.148Z" }, + { url = "https://files.pythonhosted.org/packages/07/87/c070f5f027bd81f3efee7d14cb4d84067ecf67a3a8efb43aadfc72aa79a6/ruff-0.12.3-py3-none-win_amd64.whl", hash = "sha256:a946cf1e7ba3209bdef039eb97647f1c77f6f540e5845ec9c114d3af8df873e7", size = 11695072, upload-time = "2025-07-11T13:21:11.004Z" }, + { url = "https://files.pythonhosted.org/packages/e0/30/f3eaf6563c637b6e66238ed6535f6775480db973c836336e4122161986fc/ruff-0.12.3-py3-none-win_arm64.whl", hash = "sha256:5f9c7c9c8f84c2d7f27e93674d27136fbf489720251544c4da7fb3d742e011b1", size = 10805855, upload-time = "2025-07-11T13:21:13.547Z" }, +] + +[[package]] +name = "salib" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "matplotlib" }, + { name = "multiprocess" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/8c/3e09d6b40f90ccf04b1308a88b7bf496596704e01ca30782a524d025a0e1/salib-1.5.1.tar.gz", hash = "sha256:e4a9c319b8dd02995a8dc983f57c452cb7e5b6dbd43e7b7856c90cb6a332bb5f", size = 725018, upload-time = "2024-08-19T16:35:25.825Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/40/393b381779d379afbb0e281d9f69cb511022e41a726f7871a929faec2b11/salib-1.5.1-py3-none-any.whl", hash = "sha256:a978b619c5a93eb14dd8c527f12e22d354b02f1f7143aba3cb84c1c7bc1382e5", size = 778858, upload-time = "2024-08-19T16:35:23.951Z" }, +] + +[[package]] +name = "scipy" +version = "1.16.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/81/18/b06a83f0c5ee8cddbde5e3f3d0bb9b702abfa5136ef6d4620ff67df7eee5/scipy-1.16.0.tar.gz", hash = "sha256:b5ef54021e832869c8cfb03bc3bf20366cbcd426e02a58e8a58d7584dfbb8f62", size = 30581216, upload-time = "2025-06-22T16:27:55.782Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/01/c0/c943bc8d2bbd28123ad0f4f1eef62525fa1723e84d136b32965dcb6bad3a/scipy-1.16.0-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:7eb6bd33cef4afb9fa5f1fb25df8feeb1e52d94f21a44f1d17805b41b1da3180", size = 36459071, upload-time = "2025-06-22T16:19:06.605Z" }, + { url = "https://files.pythonhosted.org/packages/99/0d/270e2e9f1a4db6ffbf84c9a0b648499842046e4e0d9b2275d150711b3aba/scipy-1.16.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:1dbc8fdba23e4d80394ddfab7a56808e3e6489176d559c6c71935b11a2d59db1", size = 28490500, upload-time = "2025-06-22T16:19:11.775Z" }, + { url = "https://files.pythonhosted.org/packages/1c/22/01d7ddb07cff937d4326198ec8d10831367a708c3da72dfd9b7ceaf13028/scipy-1.16.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:7dcf42c380e1e3737b343dec21095c9a9ad3f9cbe06f9c05830b44b1786c9e90", size = 20762345, upload-time = "2025-06-22T16:19:15.813Z" }, + { url = "https://files.pythonhosted.org/packages/34/7f/87fd69856569ccdd2a5873fe5d7b5bbf2ad9289d7311d6a3605ebde3a94b/scipy-1.16.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:26ec28675f4a9d41587266084c626b02899db373717d9312fa96ab17ca1ae94d", size = 23418563, upload-time = "2025-06-22T16:19:20.746Z" }, + { url = "https://files.pythonhosted.org/packages/f6/f1/e4f4324fef7f54160ab749efbab6a4bf43678a9eb2e9817ed71a0a2fd8de/scipy-1.16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:952358b7e58bd3197cfbd2f2f2ba829f258404bdf5db59514b515a8fe7a36c52", size = 33203951, upload-time = "2025-06-22T16:19:25.813Z" }, + { url = "https://files.pythonhosted.org/packages/6d/f0/b6ac354a956384fd8abee2debbb624648125b298f2c4a7b4f0d6248048a5/scipy-1.16.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:03931b4e870c6fef5b5c0970d52c9f6ddd8c8d3e934a98f09308377eba6f3824", size = 35070225, upload-time = "2025-06-22T16:19:31.416Z" }, + { url = "https://files.pythonhosted.org/packages/e5/73/5cbe4a3fd4bc3e2d67ffad02c88b83edc88f381b73ab982f48f3df1a7790/scipy-1.16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:512c4f4f85912767c351a0306824ccca6fd91307a9f4318efe8fdbd9d30562ef", size = 35389070, upload-time = "2025-06-22T16:19:37.387Z" }, + { url = "https://files.pythonhosted.org/packages/86/e8/a60da80ab9ed68b31ea5a9c6dfd3c2f199347429f229bf7f939a90d96383/scipy-1.16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e69f798847e9add03d512eaf5081a9a5c9a98757d12e52e6186ed9681247a1ac", size = 37825287, upload-time = "2025-06-22T16:19:43.375Z" }, + { url = "https://files.pythonhosted.org/packages/ea/b5/29fece1a74c6a94247f8a6fb93f5b28b533338e9c34fdcc9cfe7a939a767/scipy-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:adf9b1999323ba335adc5d1dc7add4781cb5a4b0ef1e98b79768c05c796c4e49", size = 38431929, upload-time = "2025-06-22T16:19:49.385Z" }, + { url = "https://files.pythonhosted.org/packages/46/95/0746417bc24be0c2a7b7563946d61f670a3b491b76adede420e9d173841f/scipy-1.16.0-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:e9f414cbe9ca289a73e0cc92e33a6a791469b6619c240aa32ee18abdce8ab451", size = 36418162, upload-time = "2025-06-22T16:19:56.3Z" }, + { url = "https://files.pythonhosted.org/packages/19/5a/914355a74481b8e4bbccf67259bbde171348a3f160b67b4945fbc5f5c1e5/scipy-1.16.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:bbba55fb97ba3cdef9b1ee973f06b09d518c0c7c66a009c729c7d1592be1935e", size = 28465985, upload-time = "2025-06-22T16:20:01.238Z" }, + { url = "https://files.pythonhosted.org/packages/58/46/63477fc1246063855969cbefdcee8c648ba4b17f67370bd542ba56368d0b/scipy-1.16.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:58e0d4354eacb6004e7aa1cd350e5514bd0270acaa8d5b36c0627bb3bb486974", size = 20737961, upload-time = "2025-06-22T16:20:05.913Z" }, + { url = "https://files.pythonhosted.org/packages/93/86/0fbb5588b73555e40f9d3d6dde24ee6fac7d8e301a27f6f0cab9d8f66ff2/scipy-1.16.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:75b2094ec975c80efc273567436e16bb794660509c12c6a31eb5c195cbf4b6dc", size = 23377941, upload-time = "2025-06-22T16:20:10.668Z" }, + { url = "https://files.pythonhosted.org/packages/ca/80/a561f2bf4c2da89fa631b3cbf31d120e21ea95db71fd9ec00cb0247c7a93/scipy-1.16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6b65d232157a380fdd11a560e7e21cde34fdb69d65c09cb87f6cc024ee376351", size = 33196703, upload-time = "2025-06-22T16:20:16.097Z" }, + { url = "https://files.pythonhosted.org/packages/11/6b/3443abcd0707d52e48eb315e33cc669a95e29fc102229919646f5a501171/scipy-1.16.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d8747f7736accd39289943f7fe53a8333be7f15a82eea08e4afe47d79568c32", size = 35083410, upload-time = "2025-06-22T16:20:21.734Z" }, + { url = "https://files.pythonhosted.org/packages/20/ab/eb0fc00e1e48961f1bd69b7ad7e7266896fe5bad4ead91b5fc6b3561bba4/scipy-1.16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eb9f147a1b8529bb7fec2a85cf4cf42bdfadf9e83535c309a11fdae598c88e8b", size = 35387829, upload-time = "2025-06-22T16:20:27.548Z" }, + { url = "https://files.pythonhosted.org/packages/57/9e/d6fc64e41fad5d481c029ee5a49eefc17f0b8071d636a02ceee44d4a0de2/scipy-1.16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d2b83c37edbfa837a8923d19c749c1935ad3d41cf196006a24ed44dba2ec4358", size = 37841356, upload-time = "2025-06-22T16:20:35.112Z" }, + { url = "https://files.pythonhosted.org/packages/7c/a7/4c94bbe91f12126b8bf6709b2471900577b7373a4fd1f431f28ba6f81115/scipy-1.16.0-cp313-cp313-win_amd64.whl", hash = "sha256:79a3c13d43c95aa80b87328a46031cf52508cf5f4df2767602c984ed1d3c6bbe", size = 38403710, upload-time = "2025-06-22T16:21:54.473Z" }, + { url = "https://files.pythonhosted.org/packages/47/20/965da8497f6226e8fa90ad3447b82ed0e28d942532e92dd8b91b43f100d4/scipy-1.16.0-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:f91b87e1689f0370690e8470916fe1b2308e5b2061317ff76977c8f836452a47", size = 36813833, upload-time = "2025-06-22T16:20:43.925Z" }, + { url = "https://files.pythonhosted.org/packages/28/f4/197580c3dac2d234e948806e164601c2df6f0078ed9f5ad4a62685b7c331/scipy-1.16.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:88a6ca658fb94640079e7a50b2ad3b67e33ef0f40e70bdb7dc22017dae73ac08", size = 28974431, upload-time = "2025-06-22T16:20:51.302Z" }, + { url = "https://files.pythonhosted.org/packages/8a/fc/e18b8550048d9224426e76906694c60028dbdb65d28b1372b5503914b89d/scipy-1.16.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:ae902626972f1bd7e4e86f58fd72322d7f4ec7b0cfc17b15d4b7006efc385176", size = 21246454, upload-time = "2025-06-22T16:20:57.276Z" }, + { url = "https://files.pythonhosted.org/packages/8c/48/07b97d167e0d6a324bfd7484cd0c209cc27338b67e5deadae578cf48e809/scipy-1.16.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:8cb824c1fc75ef29893bc32b3ddd7b11cf9ab13c1127fe26413a05953b8c32ed", size = 23772979, upload-time = "2025-06-22T16:21:03.363Z" }, + { url = "https://files.pythonhosted.org/packages/4c/4f/9efbd3f70baf9582edf271db3002b7882c875ddd37dc97f0f675ad68679f/scipy-1.16.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:de2db7250ff6514366a9709c2cba35cb6d08498e961cba20d7cff98a7ee88938", size = 33341972, upload-time = "2025-06-22T16:21:11.14Z" }, + { url = "https://files.pythonhosted.org/packages/3f/dc/9e496a3c5dbe24e76ee24525155ab7f659c20180bab058ef2c5fa7d9119c/scipy-1.16.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e85800274edf4db8dd2e4e93034f92d1b05c9421220e7ded9988b16976f849c1", size = 35185476, upload-time = "2025-06-22T16:21:19.156Z" }, + { url = "https://files.pythonhosted.org/packages/ce/b3/21001cff985a122ba434c33f2c9d7d1dc3b669827e94f4fc4e1fe8b9dfd8/scipy-1.16.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4f720300a3024c237ace1cb11f9a84c38beb19616ba7c4cdcd771047a10a1706", size = 35570990, upload-time = "2025-06-22T16:21:27.797Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d3/7ba42647d6709251cdf97043d0c107e0317e152fa2f76873b656b509ff55/scipy-1.16.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:aad603e9339ddb676409b104c48a027e9916ce0d2838830691f39552b38a352e", size = 37950262, upload-time = "2025-06-22T16:21:36.976Z" }, + { url = "https://files.pythonhosted.org/packages/eb/c4/231cac7a8385394ebbbb4f1ca662203e9d8c332825ab4f36ffc3ead09a42/scipy-1.16.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f56296fefca67ba605fd74d12f7bd23636267731a72cb3947963e76b8c0a25db", size = 38515076, upload-time = "2025-06-22T16:21:45.694Z" }, +] + +[[package]] +name = "seaborn" +version = "0.13.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "matplotlib" }, + { name = "numpy" }, + { name = "pandas" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/86/59/a451d7420a77ab0b98f7affa3a1d78a313d2f7281a57afb1a34bae8ab412/seaborn-0.13.2.tar.gz", hash = "sha256:93e60a40988f4d65e9f4885df477e2fdaff6b73a9ded434c1ab356dd57eefff7", size = 1457696, upload-time = "2024-01-25T13:21:52.551Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987", size = 294914, upload-time = "2024-01-25T13:21:49.598Z" }, +] + +[[package]] +name = "send2trash" +version = "1.8.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/3a/aec9b02217bb79b87bbc1a21bc6abc51e3d5dcf65c30487ac96c0908c722/Send2Trash-1.8.3.tar.gz", hash = "sha256:b18e7a3966d99871aefeb00cfbcfdced55ce4871194810fc71f4aa484b953abf", size = 17394, upload-time = "2024-04-07T00:01:09.267Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/b0/4562db6223154aa4e22f939003cb92514c79f3d4dccca3444253fd17f902/Send2Trash-1.8.3-py3-none-any.whl", hash = "sha256:0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9", size = 18072, upload-time = "2024-04-07T00:01:07.438Z" }, +] + +[[package]] +name = "setuptools" +version = "80.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, +] + +[[package]] +name = "shellingham" +version = "1.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "snowballstemmer" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/75/a7/9810d872919697c9d01295633f5d574fb416d47e535f258272ca1f01f447/snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895", size = 105575, upload-time = "2025-05-09T16:34:51.843Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/78/3565d011c61f5a43488987ee32b6f3f656e7f107ac2782dd57bdd7d91d9a/snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064", size = 103274, upload-time = "2025-05-09T16:34:50.371Z" }, +] + +[[package]] +name = "soupsieve" +version = "2.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3f/f4/4a80cd6ef364b2e8b65b15816a843c0980f7a5a2b4dc701fc574952aa19f/soupsieve-2.7.tar.gz", hash = "sha256:ad282f9b6926286d2ead4750552c8a6142bc4c783fd66b0293547c8fe6ae126a", size = 103418, upload-time = "2025-04-20T18:50:08.518Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/9c/0e6afc12c269578be5c0c1c9f4b49a8d32770a080260c333ac04cc1c832d/soupsieve-2.7-py3-none-any.whl", hash = "sha256:6e60cc5c1ffaf1cebcc12e8188320b72071e922c2e897f737cadce79ad5d30c4", size = 36677, upload-time = "2025-04-20T18:50:07.196Z" }, +] + +[[package]] +name = "sphinx" +version = "8.2.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "alabaster" }, + { name = "babel" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "docutils" }, + { name = "imagesize" }, + { name = "jinja2" }, + { name = "packaging" }, + { name = "pygments" }, + { name = "requests" }, + { name = "roman-numerals-py" }, + { name = "snowballstemmer" }, + { name = "sphinxcontrib-applehelp" }, + { name = "sphinxcontrib-devhelp" }, + { name = "sphinxcontrib-htmlhelp" }, + { name = "sphinxcontrib-jsmath" }, + { name = "sphinxcontrib-qthelp" }, + { name = "sphinxcontrib-serializinghtml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/ad/4360e50ed56cb483667b8e6dadf2d3fda62359593faabbe749a27c4eaca6/sphinx-8.2.3.tar.gz", hash = "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348", size = 8321876, upload-time = "2025-03-02T22:31:59.658Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/53/136e9eca6e0b9dc0e1962e2c908fbea2e5ac000c2a2fbd9a35797958c48b/sphinx-8.2.3-py3-none-any.whl", hash = "sha256:4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3", size = 3589741, upload-time = "2025-03-02T22:31:56.836Z" }, +] + +[[package]] +name = "sphinx-rtd-theme" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docutils" }, + { name = "sphinx" }, + { name = "sphinxcontrib-jquery" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/91/44/c97faec644d29a5ceddd3020ae2edffa69e7d00054a8c7a6021e82f20335/sphinx_rtd_theme-3.0.2.tar.gz", hash = "sha256:b7457bc25dda723b20b086a670b9953c859eab60a2a03ee8eb2bb23e176e5f85", size = 7620463, upload-time = "2024-11-13T11:06:04.545Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/77/46e3bac77b82b4df5bb5b61f2de98637724f246b4966cfc34bc5895d852a/sphinx_rtd_theme-3.0.2-py2.py3-none-any.whl", hash = "sha256:422ccc750c3a3a311de4ae327e82affdaf59eb695ba4936538552f3b00f4ee13", size = 7655561, upload-time = "2024-11-13T11:06:02.094Z" }, +] + +[[package]] +name = "sphinxcontrib-applehelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053, upload-time = "2024-07-29T01:09:00.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300, upload-time = "2024-07-29T01:08:58.99Z" }, +] + +[[package]] +name = "sphinxcontrib-bibtex" +version = "2.6.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docutils" }, + { name = "pybtex" }, + { name = "pybtex-docutils" }, + { name = "sphinx" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/83/1488c9879f2fa3c2cbd6f666c7a3a42a1fa9e08462bec73281fa6c092cba/sphinxcontrib_bibtex-2.6.5.tar.gz", hash = "sha256:9b3224dd6fece9268ebd8c905dc0a83ff2f6c54148a9235fe70e9d1e9ff149c0", size = 118462, upload-time = "2025-06-27T10:40:14.061Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/a0/3a612da94f828f26cabb247817393e79472c32b12c49222bf85fb6d7b6c8/sphinxcontrib_bibtex-2.6.5-py3-none-any.whl", hash = "sha256:455ea4509642ea0b28ede3721550273626f85af65af01f161bfd8e19dc1edd7d", size = 40410, upload-time = "2025-06-27T10:40:12.274Z" }, +] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967, upload-time = "2024-07-29T01:09:23.417Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530, upload-time = "2024-07-29T01:09:21.945Z" }, +] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617, upload-time = "2024-07-29T01:09:37.889Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705, upload-time = "2024-07-29T01:09:36.407Z" }, +] + +[[package]] +name = "sphinxcontrib-jquery" +version = "4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sphinx" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/f3/aa67467e051df70a6330fe7770894b3e4f09436dea6881ae0b4f3d87cad8/sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a", size = 122331, upload-time = "2023-03-14T15:01:01.944Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/85/749bd22d1a68db7291c89e2ebca53f4306c3f205853cf31e9de279034c3c/sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae", size = 121104, upload-time = "2023-03-14T15:01:00.356Z" }, +] + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787, upload-time = "2019-01-21T16:10:16.347Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071, upload-time = "2019-01-21T16:10:14.333Z" }, +] + +[[package]] +name = "sphinxcontrib-qthelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165, upload-time = "2024-07-29T01:09:56.435Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743, upload-time = "2024-07-29T01:09:54.885Z" }, +] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080, upload-time = "2024-07-29T01:10:09.332Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072, upload-time = "2024-07-29T01:10:08.203Z" }, +] + +[[package]] +name = "sqlalchemy" +version = "2.0.41" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "greenlet", marker = "(python_full_version < '3.14' and platform_machine == 'AMD64') or (python_full_version < '3.14' and platform_machine == 'WIN32') or (python_full_version < '3.14' and platform_machine == 'aarch64') or (python_full_version < '3.14' and platform_machine == 'amd64') or (python_full_version < '3.14' and platform_machine == 'ppc64le') or (python_full_version < '3.14' and platform_machine == 'win32') or (python_full_version < '3.14' and platform_machine == 'x86_64')" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/63/66/45b165c595ec89aa7dcc2c1cd222ab269bc753f1fc7a1e68f8481bd957bf/sqlalchemy-2.0.41.tar.gz", hash = "sha256:edba70118c4be3c2b1f90754d308d0b79c6fe2c0fdc52d8ddf603916f83f4db9", size = 9689424, upload-time = "2025-05-14T17:10:32.339Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/2a/f1f4e068b371154740dd10fb81afb5240d5af4aa0087b88d8b308b5429c2/sqlalchemy-2.0.41-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:81f413674d85cfd0dfcd6512e10e0f33c19c21860342a4890c3a2b59479929f9", size = 2119645, upload-time = "2025-05-14T17:55:24.854Z" }, + { url = "https://files.pythonhosted.org/packages/9b/e8/c664a7e73d36fbfc4730f8cf2bf930444ea87270f2825efbe17bf808b998/sqlalchemy-2.0.41-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:598d9ebc1e796431bbd068e41e4de4dc34312b7aa3292571bb3674a0cb415dd1", size = 2107399, upload-time = "2025-05-14T17:55:28.097Z" }, + { url = "https://files.pythonhosted.org/packages/5c/78/8a9cf6c5e7135540cb682128d091d6afa1b9e48bd049b0d691bf54114f70/sqlalchemy-2.0.41-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a104c5694dfd2d864a6f91b0956eb5d5883234119cb40010115fd45a16da5e70", size = 3293269, upload-time = "2025-05-14T17:50:38.227Z" }, + { url = "https://files.pythonhosted.org/packages/3c/35/f74add3978c20de6323fb11cb5162702670cc7a9420033befb43d8d5b7a4/sqlalchemy-2.0.41-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6145afea51ff0af7f2564a05fa95eb46f542919e6523729663a5d285ecb3cf5e", size = 3303364, upload-time = "2025-05-14T17:51:49.829Z" }, + { url = "https://files.pythonhosted.org/packages/6a/d4/c990f37f52c3f7748ebe98883e2a0f7d038108c2c5a82468d1ff3eec50b7/sqlalchemy-2.0.41-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b46fa6eae1cd1c20e6e6f44e19984d438b6b2d8616d21d783d150df714f44078", size = 3229072, upload-time = "2025-05-14T17:50:39.774Z" }, + { url = "https://files.pythonhosted.org/packages/15/69/cab11fecc7eb64bc561011be2bd03d065b762d87add52a4ca0aca2e12904/sqlalchemy-2.0.41-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41836fe661cc98abfae476e14ba1906220f92c4e528771a8a3ae6a151242d2ae", size = 3268074, upload-time = "2025-05-14T17:51:51.736Z" }, + { url = "https://files.pythonhosted.org/packages/5c/ca/0c19ec16858585d37767b167fc9602593f98998a68a798450558239fb04a/sqlalchemy-2.0.41-cp312-cp312-win32.whl", hash = "sha256:a8808d5cf866c781150d36a3c8eb3adccfa41a8105d031bf27e92c251e3969d6", size = 2084514, upload-time = "2025-05-14T17:55:49.915Z" }, + { url = "https://files.pythonhosted.org/packages/7f/23/4c2833d78ff3010a4e17f984c734f52b531a8c9060a50429c9d4b0211be6/sqlalchemy-2.0.41-cp312-cp312-win_amd64.whl", hash = "sha256:5b14e97886199c1f52c14629c11d90c11fbb09e9334fa7bb5f6d068d9ced0ce0", size = 2111557, upload-time = "2025-05-14T17:55:51.349Z" }, + { url = "https://files.pythonhosted.org/packages/d3/ad/2e1c6d4f235a97eeef52d0200d8ddda16f6c4dd70ae5ad88c46963440480/sqlalchemy-2.0.41-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4eeb195cdedaf17aab6b247894ff2734dcead6c08f748e617bfe05bd5a218443", size = 2115491, upload-time = "2025-05-14T17:55:31.177Z" }, + { url = "https://files.pythonhosted.org/packages/cf/8d/be490e5db8400dacc89056f78a52d44b04fbf75e8439569d5b879623a53b/sqlalchemy-2.0.41-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d4ae769b9c1c7757e4ccce94b0641bc203bbdf43ba7a2413ab2523d8d047d8dc", size = 2102827, upload-time = "2025-05-14T17:55:34.921Z" }, + { url = "https://files.pythonhosted.org/packages/a0/72/c97ad430f0b0e78efaf2791342e13ffeafcbb3c06242f01a3bb8fe44f65d/sqlalchemy-2.0.41-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a62448526dd9ed3e3beedc93df9bb6b55a436ed1474db31a2af13b313a70a7e1", size = 3225224, upload-time = "2025-05-14T17:50:41.418Z" }, + { url = "https://files.pythonhosted.org/packages/5e/51/5ba9ea3246ea068630acf35a6ba0d181e99f1af1afd17e159eac7e8bc2b8/sqlalchemy-2.0.41-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc56c9788617b8964ad02e8fcfeed4001c1f8ba91a9e1f31483c0dffb207002a", size = 3230045, upload-time = "2025-05-14T17:51:54.722Z" }, + { url = "https://files.pythonhosted.org/packages/78/2f/8c14443b2acea700c62f9b4a8bad9e49fc1b65cfb260edead71fd38e9f19/sqlalchemy-2.0.41-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c153265408d18de4cc5ded1941dcd8315894572cddd3c58df5d5b5705b3fa28d", size = 3159357, upload-time = "2025-05-14T17:50:43.483Z" }, + { url = "https://files.pythonhosted.org/packages/fc/b2/43eacbf6ccc5276d76cea18cb7c3d73e294d6fb21f9ff8b4eef9b42bbfd5/sqlalchemy-2.0.41-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f67766965996e63bb46cfbf2ce5355fc32d9dd3b8ad7e536a920ff9ee422e23", size = 3197511, upload-time = "2025-05-14T17:51:57.308Z" }, + { url = "https://files.pythonhosted.org/packages/fa/2e/677c17c5d6a004c3c45334ab1dbe7b7deb834430b282b8a0f75ae220c8eb/sqlalchemy-2.0.41-cp313-cp313-win32.whl", hash = "sha256:bfc9064f6658a3d1cadeaa0ba07570b83ce6801a1314985bf98ec9b95d74e15f", size = 2082420, upload-time = "2025-05-14T17:55:52.69Z" }, + { url = "https://files.pythonhosted.org/packages/e9/61/e8c1b9b6307c57157d328dd8b8348ddc4c47ffdf1279365a13b2b98b8049/sqlalchemy-2.0.41-cp313-cp313-win_amd64.whl", hash = "sha256:82ca366a844eb551daff9d2e6e7a9e5e76d2612c8564f58db6c19a726869c1df", size = 2108329, upload-time = "2025-05-14T17:55:54.495Z" }, + { url = "https://files.pythonhosted.org/packages/1c/fc/9ba22f01b5cdacc8f5ed0d22304718d2c758fce3fd49a5372b886a86f37c/sqlalchemy-2.0.41-py3-none-any.whl", hash = "sha256:57df5dc6fdb5ed1a88a1ed2195fd31927e705cad62dedd86b46972752a80f576", size = 1911224, upload-time = "2025-05-14T17:39:42.154Z" }, +] + +[package.optional-dependencies] +mypy = [ + { name = "mypy" }, +] + +[[package]] +name = "sqlalchemy-continuum" +version = "1.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sqlalchemy" }, + { name = "sqlalchemy-utils" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/05/81/76e0b16ca8575463ba83e014afe8a89443bbc6a896dad3c48068ce571611/sqlalchemy_continuum-1.4.2.tar.gz", hash = "sha256:0fd2be79f718eda47c2206879d92ec4ebf1889364637b3caf3ee5d34bd19c8e3", size = 81713, upload-time = "2024-05-02T20:03:43.192Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/d4/c404ce46dc2d53e536f470e76d7f657de46cf091d5ba05d19040d420d825/SQLAlchemy_Continuum-1.4.2-py3-none-any.whl", hash = "sha256:154588d79deb8b1683b5f39c130e6f0ad793c0b2f27e8c210565c23fb6fe74de", size = 44789, upload-time = "2024-05-02T20:03:41.009Z" }, +] + +[[package]] +name = "sqlalchemy-utils" +version = "0.41.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sqlalchemy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4d/bf/abfd5474cdd89ddd36dbbde9c6efba16bfa7f5448913eba946fed14729da/SQLAlchemy-Utils-0.41.2.tar.gz", hash = "sha256:bc599c8c3b3319e53ce6c5c3c471120bd325d0071fb6f38a10e924e3d07b9990", size = 138017, upload-time = "2024-03-24T15:17:28.196Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/f0/dc4757b83ac1ab853cf222df8535ed73973e0c203d983982ba7b8bc60508/SQLAlchemy_Utils-0.41.2-py3-none-any.whl", hash = "sha256:85cf3842da2bf060760f955f8467b87983fb2e30f1764fd0e24a48307dc8ec6e", size = 93083, upload-time = "2024-03-24T15:17:24.533Z" }, +] + +[[package]] +name = "stack-data" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asttokens" }, + { name = "executing" }, + { name = "pure-eval" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, +] + +[[package]] +name = "starlette" +version = "0.47.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0a/69/662169fdb92fb96ec3eaee218cf540a629d629c86d7993d9651226a6789b/starlette-0.47.1.tar.gz", hash = "sha256:aef012dd2b6be325ffa16698f9dc533614fb1cebd593a906b90dc1025529a79b", size = 2583072, upload-time = "2025-06-21T04:03:17.337Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/95/38ef0cd7fa11eaba6a99b3c4f5ac948d8bc6ff199aabd327a29cc000840c/starlette-0.47.1-py3-none-any.whl", hash = "sha256:5e11c9f5c7c3f24959edbf2dffdc01bba860228acf657129467d8a7468591527", size = 72747, upload-time = "2025-06-21T04:03:15.705Z" }, +] + +[[package]] +name = "tabulate" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/fe/802052aecb21e3797b8f7902564ab6ea0d60ff8ca23952079064155d1ae1/tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c", size = 81090, upload-time = "2022-10-06T17:21:48.54Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f", size = 35252, upload-time = "2022-10-06T17:21:44.262Z" }, +] + +[[package]] +name = "temoa" +version = "3.0.0" +source = { editable = "." } +dependencies = [ + { name = "deprecated" }, + { name = "graphviz" }, + { name = "gravis" }, + { name = "gurobipy" }, + { name = "highspy" }, + { name = "ipykernel" }, + { name = "ipython" }, + { name = "joblib" }, + { name = "jupyter" }, + { name = "jupyter-contrib-nbextensions" }, + { name = "matplotlib" }, + { name = "networkx" }, + { name = "numpy" }, + { name = "nx-vis-visualizer" }, + { name = "openpyxl" }, + { name = "pandas" }, + { name = "pyam-iamc" }, + { name = "pydoe" }, + { name = "pyomo" }, + { name = "pytest" }, + { name = "pyutilib" }, + { name = "salib" }, + { name = "scipy" }, + { name = "seaborn" }, + { name = "tabulate" }, + { name = "xlsxwriter" }, +] + +[package.optional-dependencies] +dev = [ + { name = "pre-commit" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "ruff" }, +] +docs = [ + { name = "sphinx" }, + { name = "sphinx-rtd-theme" }, + { name = "sphinxcontrib-bibtex" }, + { name = "sphinxcontrib-htmlhelp" }, + { name = "sphinxcontrib-serializinghtml" }, +] +plotting = [ + { name = "matplotlib" }, + { name = "seaborn" }, +] + +[package.dev-dependencies] +dev = [ + { name = "gurobipy" }, +] + +[package.metadata] +requires-dist = [ + { name = "deprecated", specifier = ">=1.2.14" }, + { name = "graphviz", specifier = ">=0.20.3" }, + { name = "gravis", specifier = ">=0.1.0" }, + { name = "gurobipy", specifier = ">=11.0.3" }, + { name = "highspy", specifier = ">=1.7.2" }, + { name = "ipykernel" }, + { name = "ipython" }, + { name = "joblib" }, + { name = "jupyter" }, + { name = "jupyter-contrib-nbextensions" }, + { name = "matplotlib", specifier = "==3.9.2" }, + { name = "matplotlib", marker = "extra == 'plotting'", specifier = ">=3.9.2" }, + { name = "networkx", specifier = ">=3.3" }, + { name = "numpy", specifier = ">=2.1.0" }, + { name = "nx-vis-visualizer", specifier = ">=0.1.1" }, + { name = "openpyxl", specifier = ">=3.1.5" }, + { name = "pandas", specifier = ">=2.2.2" }, + { name = "pre-commit", marker = "extra == 'dev'" }, + { name = "pyam-iamc", specifier = ">=2.2.4" }, + { name = "pydoe", specifier = ">=0.3.8" }, + { name = "pyomo", specifier = ">=6.8.0" }, + { name = "pytest", specifier = ">=8.3.2" }, + { name = "pytest", marker = "extra == 'dev'" }, + { name = "pytest-cov", marker = "extra == 'dev'" }, + { name = "pyutilib", specifier = ">=6.0.0" }, + { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.2.0" }, + { name = "salib", specifier = ">=1.5.1" }, + { name = "scipy", specifier = ">=1.14.1" }, + { name = "seaborn", specifier = ">=0.13.2" }, + { name = "seaborn", marker = "extra == 'plotting'", specifier = ">=0.13.2" }, + { name = "sphinx", marker = "extra == 'docs'", specifier = ">=7.4.7" }, + { name = "sphinx-rtd-theme", marker = "extra == 'docs'", specifier = ">=2.0.0" }, + { name = "sphinxcontrib-bibtex", marker = "extra == 'docs'", specifier = ">=2.6.2" }, + { name = "sphinxcontrib-htmlhelp", marker = "extra == 'docs'", specifier = ">=2.1.0" }, + { name = "sphinxcontrib-serializinghtml", marker = "extra == 'docs'", specifier = ">=2.0.0" }, + { name = "tabulate", specifier = ">=0.9.0" }, + { name = "xlsxwriter", specifier = ">=3.2.0" }, +] +provides-extras = ["docs", "dev", "plotting"] + +[package.metadata.requires-dev] +dev = [{ name = "gurobipy", specifier = ">=12.0.3" }] + +[[package]] +name = "terminado" +version = "0.18.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ptyprocess", marker = "os_name != 'nt'" }, + { name = "pywinpty", marker = "os_name == 'nt'" }, + { name = "tornado" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8a/11/965c6fd8e5cc254f1fe142d547387da17a8ebfd75a3455f637c663fb38a0/terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e", size = 32701, upload-time = "2024-03-12T14:34:39.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154, upload-time = "2024-03-12T14:34:36.569Z" }, +] + +[[package]] +name = "tinycss2" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "webencodings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085, upload-time = "2024-10-24T14:58:29.895Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610, upload-time = "2024-10-24T14:58:28.029Z" }, +] + +[[package]] +name = "toml" +version = "0.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253, upload-time = "2020-11-01T01:40:22.204Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" }, +] + +[[package]] +name = "tornado" +version = "6.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/51/89/c72771c81d25d53fe33e3dca61c233b665b2780f21820ba6fd2c6793c12b/tornado-6.5.1.tar.gz", hash = "sha256:84ceece391e8eb9b2b95578db65e920d2a61070260594819589609ba9bc6308c", size = 509934, upload-time = "2025-05-22T18:15:38.788Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/89/f4532dee6843c9e0ebc4e28d4be04c67f54f60813e4bf73d595fe7567452/tornado-6.5.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d50065ba7fd11d3bd41bcad0825227cc9a95154bad83239357094c36708001f7", size = 441948, upload-time = "2025-05-22T18:15:20.862Z" }, + { url = "https://files.pythonhosted.org/packages/15/9a/557406b62cffa395d18772e0cdcf03bed2fff03b374677348eef9f6a3792/tornado-6.5.1-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9e9ca370f717997cb85606d074b0e5b247282cf5e2e1611568b8821afe0342d6", size = 440112, upload-time = "2025-05-22T18:15:22.591Z" }, + { url = "https://files.pythonhosted.org/packages/55/82/7721b7319013a3cf881f4dffa4f60ceff07b31b394e459984e7a36dc99ec/tornado-6.5.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b77e9dfa7ed69754a54c89d82ef746398be82f749df69c4d3abe75c4d1ff4888", size = 443672, upload-time = "2025-05-22T18:15:24.027Z" }, + { url = "https://files.pythonhosted.org/packages/7d/42/d11c4376e7d101171b94e03cef0cbce43e823ed6567ceda571f54cf6e3ce/tornado-6.5.1-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:253b76040ee3bab8bcf7ba9feb136436a3787208717a1fb9f2c16b744fba7331", size = 443019, upload-time = "2025-05-22T18:15:25.735Z" }, + { url = "https://files.pythonhosted.org/packages/7d/f7/0c48ba992d875521ac761e6e04b0a1750f8150ae42ea26df1852d6a98942/tornado-6.5.1-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:308473f4cc5a76227157cdf904de33ac268af770b2c5f05ca6c1161d82fdd95e", size = 443252, upload-time = "2025-05-22T18:15:27.499Z" }, + { url = "https://files.pythonhosted.org/packages/89/46/d8d7413d11987e316df4ad42e16023cd62666a3c0dfa1518ffa30b8df06c/tornado-6.5.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:caec6314ce8a81cf69bd89909f4b633b9f523834dc1a352021775d45e51d9401", size = 443930, upload-time = "2025-05-22T18:15:29.299Z" }, + { url = "https://files.pythonhosted.org/packages/78/b2/f8049221c96a06df89bed68260e8ca94beca5ea532ffc63b1175ad31f9cc/tornado-6.5.1-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:13ce6e3396c24e2808774741331638ee6c2f50b114b97a55c5b442df65fd9692", size = 443351, upload-time = "2025-05-22T18:15:31.038Z" }, + { url = "https://files.pythonhosted.org/packages/76/ff/6a0079e65b326cc222a54720a748e04a4db246870c4da54ece4577bfa702/tornado-6.5.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5cae6145f4cdf5ab24744526cc0f55a17d76f02c98f4cff9daa08ae9a217448a", size = 443328, upload-time = "2025-05-22T18:15:32.426Z" }, + { url = "https://files.pythonhosted.org/packages/49/18/e3f902a1d21f14035b5bc6246a8c0f51e0eef562ace3a2cea403c1fb7021/tornado-6.5.1-cp39-abi3-win32.whl", hash = "sha256:e0a36e1bc684dca10b1aa75a31df8bdfed656831489bc1e6a6ebed05dc1ec365", size = 444396, upload-time = "2025-05-22T18:15:34.205Z" }, + { url = "https://files.pythonhosted.org/packages/7b/09/6526e32bf1049ee7de3bebba81572673b19a2a8541f795d887e92af1a8bc/tornado-6.5.1-cp39-abi3-win_amd64.whl", hash = "sha256:908e7d64567cecd4c2b458075589a775063453aeb1d2a1853eedb806922f568b", size = 444840, upload-time = "2025-05-22T18:15:36.1Z" }, + { url = "https://files.pythonhosted.org/packages/55/a7/535c44c7bea4578e48281d83c615219f3ab19e6abc67625ef637c73987be/tornado-6.5.1-cp39-abi3-win_arm64.whl", hash = "sha256:02420a0eb7bf617257b9935e2b754d1b63897525d8a289c9d65690d580b4dcf7", size = 443596, upload-time = "2025-05-22T18:15:37.433Z" }, +] + +[[package]] +name = "traitlets" +version = "5.14.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, +] + +[[package]] +name = "typeguard" +version = "4.4.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c7/68/71c1a15b5f65f40e91b65da23b8224dad41349894535a97f63a52e462196/typeguard-4.4.4.tar.gz", hash = "sha256:3a7fd2dffb705d4d0efaed4306a704c89b9dee850b688f060a8b1615a79e5f74", size = 75203, upload-time = "2025-06-18T09:56:07.624Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/a9/e3aee762739c1d7528da1c3e06d518503f8b6c439c35549b53735ba52ead/typeguard-4.4.4-py3-none-any.whl", hash = "sha256:b5f562281b6bfa1f5492470464730ef001646128b180769880468bd84b68b09e", size = 34874, upload-time = "2025-06-18T09:56:05.999Z" }, +] + +[[package]] +name = "typer" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "rich" }, + { name = "shellingham" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c5/8c/7d682431efca5fd290017663ea4588bf6f2c6aad085c7f108c5dbc316e70/typer-0.16.0.tar.gz", hash = "sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b", size = 102625, upload-time = "2025-05-26T14:30:31.824Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/42/3efaf858001d2c2913de7f354563e3a3a2f0decae3efe98427125a8f441e/typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855", size = 46317, upload-time = "2025-05-26T14:30:30.523Z" }, +] + +[[package]] +name = "types-python-dateutil" +version = "2.9.0.20250708" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/95/6bdde7607da2e1e99ec1c1672a759d42f26644bbacf939916e086db34870/types_python_dateutil-2.9.0.20250708.tar.gz", hash = "sha256:ccdbd75dab2d6c9696c350579f34cffe2c281e4c5f27a585b2a2438dd1d5c8ab", size = 15834, upload-time = "2025-07-08T03:14:03.382Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/72/52/43e70a8e57fefb172c22a21000b03ebcc15e47e97f5cb8495b9c2832efb4/types_python_dateutil-2.9.0.20250708-py3-none-any.whl", hash = "sha256:4d6d0cc1cc4d24a2dc3816024e502564094497b713f7befda4d5bc7a8e3fd21f", size = 17724, upload-time = "2025-07-08T03:14:02.593Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.14.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/98/5a/da40306b885cc8c09109dc2e1abd358d5684b1425678151cdaed4731c822/typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36", size = 107673, upload-time = "2025-07-04T13:28:34.16Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b5/00/d631e67a838026495268c2f6884f3711a15a9a2a96cd244fdaea53b823fb/typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76", size = 43906, upload-time = "2025-07-04T13:28:32.743Z" }, +] + +[[package]] +name = "typing-inspect" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mypy-extensions" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dc/74/1789779d91f1961fa9438e9a8710cdae6bd138c80d7303996933d117264a/typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78", size = 13825, upload-time = "2023-05-24T20:25:47.612Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f", size = 8827, upload-time = "2023-05-24T20:25:45.287Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, +] + +[[package]] +name = "tzdata" +version = "2025.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" }, +] + +[[package]] +name = "uri-template" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/31/c7/0336f2bd0bcbada6ccef7aaa25e443c118a704f828a0620c6fa0207c1b64/uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7", size = 21678, upload-time = "2023-06-21T01:49:05.374Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363", size = 11140, upload-time = "2023-06-21T01:49:03.467Z" }, +] + +[[package]] +name = "urllib3" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, +] + +[[package]] +name = "virtualenv" +version = "20.31.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/56/2c/444f465fb2c65f40c3a104fd0c495184c4f2336d65baf398e3c75d72ea94/virtualenv-20.31.2.tar.gz", hash = "sha256:e10c0a9d02835e592521be48b332b6caee6887f332c111aa79a09b9e79efc2af", size = 6076316, upload-time = "2025-05-08T17:58:23.811Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/40/b1c265d4b2b62b58576588510fc4d1fe60a86319c8de99fd8e9fec617d2c/virtualenv-20.31.2-py3-none-any.whl", hash = "sha256:36efd0d9650ee985f0cad72065001e66d49a6f24eb44d98980f630686243cf11", size = 6057982, upload-time = "2025-05-08T17:58:21.15Z" }, +] + +[[package]] +name = "wcwidth" +version = "0.2.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301, upload-time = "2024-01-06T02:10:57.829Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166, upload-time = "2024-01-06T02:10:55.763Z" }, +] + +[[package]] +name = "webcolors" +version = "24.11.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7b/29/061ec845fb58521848f3739e466efd8250b4b7b98c1b6c5bf4d40b419b7e/webcolors-24.11.1.tar.gz", hash = "sha256:ecb3d768f32202af770477b8b65f318fa4f566c22948673a977b00d589dd80f6", size = 45064, upload-time = "2024-11-11T07:43:24.224Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/e8/c0e05e4684d13459f93d312077a9a2efbe04d59c393bc2b8802248c908d4/webcolors-24.11.1-py3-none-any.whl", hash = "sha256:515291393b4cdf0eb19c155749a096f779f7d909f7cceea072791cb9095b92e9", size = 14934, upload-time = "2024-11-11T07:43:22.529Z" }, +] + +[[package]] +name = "webencodings" +version = "0.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721, upload-time = "2017-04-05T20:21:34.189Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774, upload-time = "2017-04-05T20:21:32.581Z" }, +] + +[[package]] +name = "websocket-client" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e6/30/fba0d96b4b5fbf5948ed3f4681f7da2f9f64512e1d303f94b4cc174c24a5/websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da", size = 54648, upload-time = "2024-04-23T22:16:16.976Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", size = 58826, upload-time = "2024-04-23T22:16:14.422Z" }, +] + +[[package]] +name = "widgetsnbextension" +version = "4.0.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/41/53/2e0253c5efd69c9656b1843892052a31c36d37ad42812b5da45c62191f7e/widgetsnbextension-4.0.14.tar.gz", hash = "sha256:a3629b04e3edb893212df862038c7232f62973373869db5084aed739b437b5af", size = 1097428, upload-time = "2025-04-10T13:01:25.628Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/51/5447876806d1088a0f8f71e16542bf350918128d0a69437df26047c8e46f/widgetsnbextension-4.0.14-py3-none-any.whl", hash = "sha256:4875a9eaf72fbf5079dc372a51a9f268fc38d46f767cbf85c43a36da5cb9b575", size = 2196503, upload-time = "2025-04-10T13:01:23.086Z" }, +] + +[[package]] +name = "wquantiles" +version = "0.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/24/ae0216512052aee6cf68cba89f83ce011e06feff7a4cae5b03d78d078b24/wquantiles-0.6.tar.gz", hash = "sha256:a9e5b61277c8bf414394131bba4af0fc565de379ca73d6f7a336ba60184fa5c4", size = 2948, upload-time = "2021-05-26T10:38:08.815Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/75/3cce30508bf46121b7cabce57b9cacbf8d935fa555cb3c5fca43f8dd0414/wquantiles-0.6-py3-none-any.whl", hash = "sha256:1b90d68fa05251bb96f8806a346e8d7dec9a9bb99f381ad5094707b46ab85218", size = 3291, upload-time = "2021-05-26T10:38:07.38Z" }, +] + +[[package]] +name = "wrapt" +version = "1.17.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/fc/e91cc220803d7bc4db93fb02facd8461c37364151b8494762cc88b0fbcef/wrapt-1.17.2.tar.gz", hash = "sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3", size = 55531, upload-time = "2025-01-14T10:35:45.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a1/bd/ab55f849fd1f9a58ed7ea47f5559ff09741b25f00c191231f9f059c83949/wrapt-1.17.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d5e2439eecc762cd85e7bd37161d4714aa03a33c5ba884e26c81559817ca0925", size = 53799, upload-time = "2025-01-14T10:33:57.4Z" }, + { url = "https://files.pythonhosted.org/packages/53/18/75ddc64c3f63988f5a1d7e10fb204ffe5762bc663f8023f18ecaf31a332e/wrapt-1.17.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fc7cb4c1c744f8c05cd5f9438a3caa6ab94ce8344e952d7c45a8ed59dd88392", size = 38821, upload-time = "2025-01-14T10:33:59.334Z" }, + { url = "https://files.pythonhosted.org/packages/48/2a/97928387d6ed1c1ebbfd4efc4133a0633546bec8481a2dd5ec961313a1c7/wrapt-1.17.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8fdbdb757d5390f7c675e558fd3186d590973244fab0c5fe63d373ade3e99d40", size = 38919, upload-time = "2025-01-14T10:34:04.093Z" }, + { url = "https://files.pythonhosted.org/packages/73/54/3bfe5a1febbbccb7a2f77de47b989c0b85ed3a6a41614b104204a788c20e/wrapt-1.17.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bb1d0dbf99411f3d871deb6faa9aabb9d4e744d67dcaaa05399af89d847a91d", size = 88721, upload-time = "2025-01-14T10:34:07.163Z" }, + { url = "https://files.pythonhosted.org/packages/25/cb/7262bc1b0300b4b64af50c2720ef958c2c1917525238d661c3e9a2b71b7b/wrapt-1.17.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d18a4865f46b8579d44e4fe1e2bcbc6472ad83d98e22a26c963d46e4c125ef0b", size = 80899, upload-time = "2025-01-14T10:34:09.82Z" }, + { url = "https://files.pythonhosted.org/packages/2a/5a/04cde32b07a7431d4ed0553a76fdb7a61270e78c5fd5a603e190ac389f14/wrapt-1.17.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc570b5f14a79734437cb7b0500376b6b791153314986074486e0b0fa8d71d98", size = 89222, upload-time = "2025-01-14T10:34:11.258Z" }, + { url = "https://files.pythonhosted.org/packages/09/28/2e45a4f4771fcfb109e244d5dbe54259e970362a311b67a965555ba65026/wrapt-1.17.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6d9187b01bebc3875bac9b087948a2bccefe464a7d8f627cf6e48b1bbae30f82", size = 86707, upload-time = "2025-01-14T10:34:12.49Z" }, + { url = "https://files.pythonhosted.org/packages/c6/d2/dcb56bf5f32fcd4bd9aacc77b50a539abdd5b6536872413fd3f428b21bed/wrapt-1.17.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9e8659775f1adf02eb1e6f109751268e493c73716ca5761f8acb695e52a756ae", size = 79685, upload-time = "2025-01-14T10:34:15.043Z" }, + { url = "https://files.pythonhosted.org/packages/80/4e/eb8b353e36711347893f502ce91c770b0b0929f8f0bed2670a6856e667a9/wrapt-1.17.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e8b2816ebef96d83657b56306152a93909a83f23994f4b30ad4573b00bd11bb9", size = 87567, upload-time = "2025-01-14T10:34:16.563Z" }, + { url = "https://files.pythonhosted.org/packages/17/27/4fe749a54e7fae6e7146f1c7d914d28ef599dacd4416566c055564080fe2/wrapt-1.17.2-cp312-cp312-win32.whl", hash = "sha256:468090021f391fe0056ad3e807e3d9034e0fd01adcd3bdfba977b6fdf4213ea9", size = 36672, upload-time = "2025-01-14T10:34:17.727Z" }, + { url = "https://files.pythonhosted.org/packages/15/06/1dbf478ea45c03e78a6a8c4be4fdc3c3bddea5c8de8a93bc971415e47f0f/wrapt-1.17.2-cp312-cp312-win_amd64.whl", hash = "sha256:ec89ed91f2fa8e3f52ae53cd3cf640d6feff92ba90d62236a81e4e563ac0e991", size = 38865, upload-time = "2025-01-14T10:34:19.577Z" }, + { url = "https://files.pythonhosted.org/packages/ce/b9/0ffd557a92f3b11d4c5d5e0c5e4ad057bd9eb8586615cdaf901409920b14/wrapt-1.17.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6ed6ffac43aecfe6d86ec5b74b06a5be33d5bb9243d055141e8cabb12aa08125", size = 53800, upload-time = "2025-01-14T10:34:21.571Z" }, + { url = "https://files.pythonhosted.org/packages/c0/ef/8be90a0b7e73c32e550c73cfb2fa09db62234227ece47b0e80a05073b375/wrapt-1.17.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:35621ae4c00e056adb0009f8e86e28eb4a41a4bfa8f9bfa9fca7d343fe94f998", size = 38824, upload-time = "2025-01-14T10:34:22.999Z" }, + { url = "https://files.pythonhosted.org/packages/36/89/0aae34c10fe524cce30fe5fc433210376bce94cf74d05b0d68344c8ba46e/wrapt-1.17.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a604bf7a053f8362d27eb9fefd2097f82600b856d5abe996d623babd067b1ab5", size = 38920, upload-time = "2025-01-14T10:34:25.386Z" }, + { url = "https://files.pythonhosted.org/packages/3b/24/11c4510de906d77e0cfb5197f1b1445d4fec42c9a39ea853d482698ac681/wrapt-1.17.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cbabee4f083b6b4cd282f5b817a867cf0b1028c54d445b7ec7cfe6505057cf8", size = 88690, upload-time = "2025-01-14T10:34:28.058Z" }, + { url = "https://files.pythonhosted.org/packages/71/d7/cfcf842291267bf455b3e266c0c29dcb675b5540ee8b50ba1699abf3af45/wrapt-1.17.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49703ce2ddc220df165bd2962f8e03b84c89fee2d65e1c24a7defff6f988f4d6", size = 80861, upload-time = "2025-01-14T10:34:29.167Z" }, + { url = "https://files.pythonhosted.org/packages/d5/66/5d973e9f3e7370fd686fb47a9af3319418ed925c27d72ce16b791231576d/wrapt-1.17.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8112e52c5822fc4253f3901b676c55ddf288614dc7011634e2719718eaa187dc", size = 89174, upload-time = "2025-01-14T10:34:31.702Z" }, + { url = "https://files.pythonhosted.org/packages/a7/d3/8e17bb70f6ae25dabc1aaf990f86824e4fd98ee9cadf197054e068500d27/wrapt-1.17.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9fee687dce376205d9a494e9c121e27183b2a3df18037f89d69bd7b35bcf59e2", size = 86721, upload-time = "2025-01-14T10:34:32.91Z" }, + { url = "https://files.pythonhosted.org/packages/6f/54/f170dfb278fe1c30d0ff864513cff526d624ab8de3254b20abb9cffedc24/wrapt-1.17.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:18983c537e04d11cf027fbb60a1e8dfd5190e2b60cc27bc0808e653e7b218d1b", size = 79763, upload-time = "2025-01-14T10:34:34.903Z" }, + { url = "https://files.pythonhosted.org/packages/4a/98/de07243751f1c4a9b15c76019250210dd3486ce098c3d80d5f729cba029c/wrapt-1.17.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:703919b1633412ab54bcf920ab388735832fdcb9f9a00ae49387f0fe67dad504", size = 87585, upload-time = "2025-01-14T10:34:36.13Z" }, + { url = "https://files.pythonhosted.org/packages/f9/f0/13925f4bd6548013038cdeb11ee2cbd4e37c30f8bfd5db9e5a2a370d6e20/wrapt-1.17.2-cp313-cp313-win32.whl", hash = "sha256:abbb9e76177c35d4e8568e58650aa6926040d6a9f6f03435b7a522bf1c487f9a", size = 36676, upload-time = "2025-01-14T10:34:37.962Z" }, + { url = "https://files.pythonhosted.org/packages/bf/ae/743f16ef8c2e3628df3ddfd652b7d4c555d12c84b53f3d8218498f4ade9b/wrapt-1.17.2-cp313-cp313-win_amd64.whl", hash = "sha256:69606d7bb691b50a4240ce6b22ebb319c1cfb164e5f6569835058196e0f3a845", size = 38871, upload-time = "2025-01-14T10:34:39.13Z" }, + { url = "https://files.pythonhosted.org/packages/3d/bc/30f903f891a82d402ffb5fda27ec1d621cc97cb74c16fea0b6141f1d4e87/wrapt-1.17.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:4a721d3c943dae44f8e243b380cb645a709ba5bd35d3ad27bc2ed947e9c68192", size = 56312, upload-time = "2025-01-14T10:34:40.604Z" }, + { url = "https://files.pythonhosted.org/packages/8a/04/c97273eb491b5f1c918857cd26f314b74fc9b29224521f5b83f872253725/wrapt-1.17.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:766d8bbefcb9e00c3ac3b000d9acc51f1b399513f44d77dfe0eb026ad7c9a19b", size = 40062, upload-time = "2025-01-14T10:34:45.011Z" }, + { url = "https://files.pythonhosted.org/packages/4e/ca/3b7afa1eae3a9e7fefe499db9b96813f41828b9fdb016ee836c4c379dadb/wrapt-1.17.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e496a8ce2c256da1eb98bd15803a79bee00fc351f5dfb9ea82594a3f058309e0", size = 40155, upload-time = "2025-01-14T10:34:47.25Z" }, + { url = "https://files.pythonhosted.org/packages/89/be/7c1baed43290775cb9030c774bc53c860db140397047cc49aedaf0a15477/wrapt-1.17.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d615e4fe22f4ad3528448c193b218e077656ca9ccb22ce2cb20db730f8d306", size = 113471, upload-time = "2025-01-14T10:34:50.934Z" }, + { url = "https://files.pythonhosted.org/packages/32/98/4ed894cf012b6d6aae5f5cc974006bdeb92f0241775addad3f8cd6ab71c8/wrapt-1.17.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a5aaeff38654462bc4b09023918b7f21790efb807f54c000a39d41d69cf552cb", size = 101208, upload-time = "2025-01-14T10:34:52.297Z" }, + { url = "https://files.pythonhosted.org/packages/ea/fd/0c30f2301ca94e655e5e057012e83284ce8c545df7661a78d8bfca2fac7a/wrapt-1.17.2-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a7d15bbd2bc99e92e39f49a04653062ee6085c0e18b3b7512a4f2fe91f2d681", size = 109339, upload-time = "2025-01-14T10:34:53.489Z" }, + { url = "https://files.pythonhosted.org/packages/75/56/05d000de894c4cfcb84bcd6b1df6214297b8089a7bd324c21a4765e49b14/wrapt-1.17.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e3890b508a23299083e065f435a492b5435eba6e304a7114d2f919d400888cc6", size = 110232, upload-time = "2025-01-14T10:34:55.327Z" }, + { url = "https://files.pythonhosted.org/packages/53/f8/c3f6b2cf9b9277fb0813418e1503e68414cd036b3b099c823379c9575e6d/wrapt-1.17.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8c8b293cd65ad716d13d8dd3624e42e5a19cc2a2f1acc74b30c2c13f15cb61a6", size = 100476, upload-time = "2025-01-14T10:34:58.055Z" }, + { url = "https://files.pythonhosted.org/packages/a7/b1/0bb11e29aa5139d90b770ebbfa167267b1fc548d2302c30c8f7572851738/wrapt-1.17.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c82b8785d98cdd9fed4cac84d765d234ed3251bd6afe34cb7ac523cb93e8b4f", size = 106377, upload-time = "2025-01-14T10:34:59.3Z" }, + { url = "https://files.pythonhosted.org/packages/6a/e1/0122853035b40b3f333bbb25f1939fc1045e21dd518f7f0922b60c156f7c/wrapt-1.17.2-cp313-cp313t-win32.whl", hash = "sha256:13e6afb7fe71fe7485a4550a8844cc9ffbe263c0f1a1eea569bc7091d4898555", size = 37986, upload-time = "2025-01-14T10:35:00.498Z" }, + { url = "https://files.pythonhosted.org/packages/09/5e/1655cf481e079c1f22d0cabdd4e51733679932718dc23bf2db175f329b76/wrapt-1.17.2-cp313-cp313t-win_amd64.whl", hash = "sha256:eaf675418ed6b3b31c7a989fd007fa7c3be66ce14e5c3b27336383604c9da85c", size = 40750, upload-time = "2025-01-14T10:35:03.378Z" }, + { url = "https://files.pythonhosted.org/packages/2d/82/f56956041adef78f849db6b289b282e72b55ab8045a75abad81898c28d19/wrapt-1.17.2-py3-none-any.whl", hash = "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8", size = 23594, upload-time = "2025-01-14T10:35:44.018Z" }, +] + +[[package]] +name = "xlsxwriter" +version = "3.2.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/47/7704bac42ac6fe1710ae099b70e6a1e68ed173ef14792b647808c357da43/xlsxwriter-3.2.5.tar.gz", hash = "sha256:7e88469d607cdc920151c0ab3ce9cf1a83992d4b7bc730c5ffdd1a12115a7dbe", size = 213306, upload-time = "2025-06-17T08:59:14.619Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/34/a22e6664211f0c8879521328000bdcae9bf6dbafa94a923e531f6d5b3f73/xlsxwriter-3.2.5-py3-none-any.whl", hash = "sha256:4f4824234e1eaf9d95df9a8fe974585ff91d0f5e3d3f12ace5b71e443c1c6abd", size = 172347, upload-time = "2025-06-17T08:59:13.453Z" }, +] From 7c478864bfc4b7de1386c06eeb0dc382c18c4cce Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 18 Jul 2025 15:11:18 -0400 Subject: [PATCH 178/587] Add exception handling around ugly log file check --- temoa/temoa_model/run_actions.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/temoa/temoa_model/run_actions.py b/temoa/temoa_model/run_actions.py index 449b5b010..7894da6f5 100644 --- a/temoa/temoa_model/run_actions.py +++ b/temoa/temoa_model/run_actions.py @@ -156,15 +156,19 @@ def build_instance( logger.info('Started creating model instance from data') instance = model.create_instance(loaded_portal, name=model_name) if not silent: - # Check for warnings in log file to notify user. Ugly but it works - log_file = os.path.join(definitions.get_OUTPUT_PATH(), 'log.log') - with open(log_file, 'r') as f: - warnings_found = any("| WARNING |" in line or "| ERROR |" in line or "| CRITICAL |" in line for line in f) - if warnings_found: - SE.write('\r[%8.2f] Instance created with warnings. Check log file.\n' % (time() - hack)) - else: - SE.write('\r[%8.2f] Instance created. \n' % (time() - hack)) # needs spaces to clear previous line - SE.flush() + try: + # Check for warnings in log file to notify user. Ugly but it works + log_file = os.path.join(definitions.get_OUTPUT_PATH(), 'log.log') + with open(log_file, 'r') as f: + warnings_found = any("| WARNING |" in line or "| ERROR |" in line or "| CRITICAL |" in line for line in f) + if warnings_found: + SE.write('\r[%8.2f] Instance created with warnings. Check log file.\n' % (time() - hack)) + else: + SE.write('\r[%8.2f] Instance created. \n' % (time() - hack)) # needs spaces to clear previous line + SE.flush() + except: + SE.write('\r[%8.2f] Instance created. \n' % (time() - hack)) # needs spaces to clear previous line + SE.flush() logger.info('Finished creating model instance from data') # save LP if requested From a1a762bc53e577fbb48b589cd65f980f19b4dc8a Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 18 Jul 2025 15:11:49 -0400 Subject: [PATCH 179/587] Force log config in case some package logger precedes Temoa's logger --- main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/main.py b/main.py index 9ad4b4e85..6cb52ec8a 100644 --- a/main.py +++ b/main.py @@ -177,6 +177,7 @@ def setup_logging(output_path: Path, debug_level=False): format='%(asctime)s | %(module)s | %(levelname)s | %(message)s', datefmt='%d-%b-%y %H:%M:%S', level=level, + force=True, ) logger.info('*** STARTING TEMOA ***') From 338fae364686bc145862c5f644d5ba0e766c1cdf Mon Sep 17 00:00:00 2001 From: Anil Radhakrishnan Date: Mon, 21 Jul 2025 11:43:28 -0400 Subject: [PATCH 180/587] adds github actions based CI testing (#8) * re: changing gitignore to reject files by default * feat: uv based dependency management * adding pre-commit based dependency tracking and adding autogenerated requirement files * adding ci based testing --- .github/workflows/ci.yml | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..633ee7014 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,34 @@ +name: CI + +on: + push: + branches: ["main", "temoa_alpha", "ci_testing", "1.0.0-dev-operator"] + pull_request: + branches: ["main", "temoa_alpha", "ci_testing", "1.0.0-dev-operator"] + +jobs: + test: + name: setup and test + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.12"] + + steps: + - uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + enable-cache: true + + - name: Install the project + run: uv sync --all-extras --dev + + - name: Install CBC solver + run: | + sudo apt-get update + sudo apt-get install -y coinor-cbc + + - name: Run tests + run: uv run pytest tests From 3eb85f4324dc8f02b31e067dcc1fa3d468de28e2 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 21 Jul 2025 13:28:06 -0400 Subject: [PATCH 181/587] Add configs for materials and seasonal storage example models --- data_files/my_configs/materials.toml | 156 ++++++++++++++++++++ data_files/my_configs/seasonal_storage.toml | 156 ++++++++++++++++++++ 2 files changed, 312 insertions(+) create mode 100644 data_files/my_configs/materials.toml create mode 100644 data_files/my_configs/seasonal_storage.toml diff --git a/data_files/my_configs/materials.toml b/data_files/my_configs/materials.toml new file mode 100644 index 000000000..9889c7af9 --- /dev/null +++ b/data_files/my_configs/materials.toml @@ -0,0 +1,156 @@ +# ---------------------------------------------------------- +# Configuration file for a Temoa Run +# Allows specification of run type and associated parameters +# ---------------------------------------------------------- +# +# For toml format info see: https://toml.io/en/ +# - comments may be added with hash +# - do NOT comment out table names in brackets like: [] + +# Scenario Name (Mandatory) +# This scenario name is used to label results within the output .sqlite file +# (cannot contain "-" dash) +scenario = "zulu" + +# Scenaio Mode (Mandatory) +# See documentation for explanations. A standard single run is "perfect_foresight" +# mode must be one of (case-insensitive): +# [perfect_foresight, MGA, myopic, method_of_morris, build_only, check, monte_carlo] +scenario_mode = "perfect_foresight" + +# Input database (Mandatory) +input_database = "data_files/example_dbs/materials.sqlite" + +# Output file (Mandatory) +# The output file must be an existing .sqlite file +# For Pefrect Foresight, the user may target the same input file or a separate / +# copied sqlite file in a different location. Myopic, MGA require that input_database = output_database +output_database = "data_files/example_dbs/materials.sqlite" + +# ------------------------------------ +# DATA / MODEL CHECKS +# To check data / cost integrity +# ------------------------------------ + +# See the documentation section on Data Quality for notes on the features below + +# Check the pricing structure for common errors, which are reported in the log file +# Strongly recommended +price_check = true + +# Check the network connectivity for processes in the model. Strongly +# recommended to ensure proper performance. Results are reported in log file +# This requires that source commodities be marked with 's' in Commodity table +# This is required for Myopic runs +source_trace = true + +# Produce HTML files for Commodity Networks. Requires source_trace above +plot_commodity_network = true + +# ------------------------------------ +# SOLVER +# Solver Selection +# ------------------------------------ + +# use the NEOS server to solve. (Currently NOT supported) +neos = false + +# solver (Mandatory) +# Depending on what client machine has installed. +# [cbc, appsi_highs, gurobi, cplex, ...] +solver_name = "cbc" + +# ------------------------------------ +# OUTPUTS +# select desired output products/files +# ------------------------------------ + +# generate an Excel file in the output_files folder +save_excel = true + +# save the duals in the output Database (may slow execution slightly?) +save_duals = true + +# save storage levels by time slice (may be a large amount of data) +save_storage_levels = true + +# save a copy of the pyomo-generated lp file(s) to the outputs folder (maybe a large file(s)!) +save_lp_file = false + +# ------------------------------------ +# MODEL PARAMETERS +# these are specific to each model +# ------------------------------------ + +# What seasons represent in the model +# Options: +# 'consecutive_days' +# Seasons are a set of days in order, with each season representing only one day. Examples +# might be a model of a representative week with 7 days or a whole-year model with 365 days. +# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# 'representative_periods' +# Each season represents a number of days, though not necessarily in any particular order. +# If using inter-season constraints like seasonal storage or ramp rates, the true sequence +# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# the Technology table. +# 'seasonal_timeslices' +# Each season represents a sequential slice of the year, with one or many days represented per +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out +# in the schema). This is an advanced feature and not recommended for most users. Seasonal +# storage must be tagged and the TimeSeasonSequential table filled. +time_sequencing = 'seasonal_timeslices' + +# How contributions to the planning reserve margin are calculated +# Options: +# 'static' +# Traditional planning reserve formulation. Contributions are independent of hourly availability: +# capacity value = net capacity * capacity credit +# 'dynamic' +# Contributions are available output including a capacity derate factor (e.g., forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = net capacity * reserve capacity derate * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * reserve capacity derate +reserve_margin = 'static' + +# --------------------------------------------------- +# MODE OPTIONS +# options below are mode-specific and will be ignored +# if the run is not executed in that mode. +# --------------------------------------------------- +[MGA] +# see notes on these in the extensions/modeling_to_generate_alternatives folder readme.txt +cost_epsilon = 0.03 # propotional relaxation on optimal cost (ex: 0.05 = bound at 105% of original optimal cost) +iteration_limit = 55 # max iterations to perform +time_limit_hrs = 1 # max time +axis = "tech_category_activity" # use the tech activity Manager to control exploration based on categories in Tech +weighting = "hull_expansion" # use a convex hull expansion algorithm to weight exploration + +[myopic] +view_depth = 2 # number of periods seen/analyzed per iteration +step_size = 1 # number of periods to step by (must be <= view depth) + +[morris] +perturbation = 0.10 # amount to perturb marked parameters (ex: 0.10 -> +/- 10%) +levels = 8 # number of levels in param grid (must be even number) +trajectories = 10 # number of Morris trajectories to generate/explore +seed = false # random seed for use in generation/analysis for repeatable results. false=system derived +cores = 0 # number of CPU cores to use. 0 (default) = cpu count +# Note: Problem size (in general) is (Groups + 1) * trajectories see the SALib Dox +# Groups = number of unique labels used in MM analysis columns in DB + +[SVMGA] +cost_epsilon = 0.05 +# labels from appropriate tables in database. It is recommended to only use one of the lists below and leave +# the others blank +emission_labels = ['co2', 'nox'] +capacity_labels = ['TXD', 'TXG'] +activity_labels = [] + +[monte_carlo] +# a path from the PROJECT ROOT to the settings file that contains the run data. +run_settings = 'data_files/monte_carlo/run_settings_1.csv' + diff --git a/data_files/my_configs/seasonal_storage.toml b/data_files/my_configs/seasonal_storage.toml new file mode 100644 index 000000000..ed8eafa33 --- /dev/null +++ b/data_files/my_configs/seasonal_storage.toml @@ -0,0 +1,156 @@ +# ---------------------------------------------------------- +# Configuration file for a Temoa Run +# Allows specification of run type and associated parameters +# ---------------------------------------------------------- +# +# For toml format info see: https://toml.io/en/ +# - comments may be added with hash +# - do NOT comment out table names in brackets like: [
] + +# Scenario Name (Mandatory) +# This scenario name is used to label results within the output .sqlite file +# (cannot contain "-" dash) +scenario = "zulu" + +# Scenaio Mode (Mandatory) +# See documentation for explanations. A standard single run is "perfect_foresight" +# mode must be one of (case-insensitive): +# [perfect_foresight, MGA, myopic, method_of_morris, build_only, check, monte_carlo] +scenario_mode = "perfect_foresight" + +# Input database (Mandatory) +input_database = "data_files/example_dbs/seasonal_storage.sqlite" + +# Output file (Mandatory) +# The output file must be an existing .sqlite file +# For Pefrect Foresight, the user may target the same input file or a separate / +# copied sqlite file in a different location. Myopic, MGA require that input_database = output_database +output_database = "data_files/example_dbs/seasonal_storage.sqlite" + +# ------------------------------------ +# DATA / MODEL CHECKS +# To check data / cost integrity +# ------------------------------------ + +# See the documentation section on Data Quality for notes on the features below + +# Check the pricing structure for common errors, which are reported in the log file +# Strongly recommended +price_check = true + +# Check the network connectivity for processes in the model. Strongly +# recommended to ensure proper performance. Results are reported in log file +# This requires that source commodities be marked with 's' in Commodity table +# This is required for Myopic runs +source_trace = true + +# Produce HTML files for Commodity Networks. Requires source_trace above +plot_commodity_network = true + +# ------------------------------------ +# SOLVER +# Solver Selection +# ------------------------------------ + +# use the NEOS server to solve. (Currently NOT supported) +neos = false + +# solver (Mandatory) +# Depending on what client machine has installed. +# [cbc, appsi_highs, gurobi, cplex, ...] +solver_name = "cbc" + +# ------------------------------------ +# OUTPUTS +# select desired output products/files +# ------------------------------------ + +# generate an Excel file in the output_files folder +save_excel = true + +# save the duals in the output Database (may slow execution slightly?) +save_duals = true + +# save storage levels by time slice (may be a large amount of data) +save_storage_levels = true + +# save a copy of the pyomo-generated lp file(s) to the outputs folder (maybe a large file(s)!) +save_lp_file = false + +# ------------------------------------ +# MODEL PARAMETERS +# these are specific to each model +# ------------------------------------ + +# What seasons represent in the model +# Options: +# 'consecutive_days' +# Seasons are a set of days in order, with each season representing only one day. Examples +# might be a model of a representative week with 7 days or a whole-year model with 365 days. +# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# 'representative_periods' +# Each season represents a number of days, though not necessarily in any particular order. +# If using inter-season constraints like seasonal storage or ramp rates, the true sequence +# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# the Technology table. +# 'seasonal_timeslices' +# Each season represents a sequential slice of the year, with one or many days represented per +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out +# in the schema). This is an advanced feature and not recommended for most users. Seasonal +# storage must be tagged and the TimeSeasonSequential table filled. +time_sequencing = 'representative_periods' + +# How contributions to the planning reserve margin are calculated +# Options: +# 'static' +# Traditional planning reserve formulation. Contributions are independent of hourly availability: +# capacity value = net capacity * capacity credit +# 'dynamic' +# Contributions are available output including a capacity derate factor (e.g., forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = net capacity * reserve capacity derate * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * reserve capacity derate +reserve_margin = 'static' + +# --------------------------------------------------- +# MODE OPTIONS +# options below are mode-specific and will be ignored +# if the run is not executed in that mode. +# --------------------------------------------------- +[MGA] +# see notes on these in the extensions/modeling_to_generate_alternatives folder readme.txt +cost_epsilon = 0.03 # propotional relaxation on optimal cost (ex: 0.05 = bound at 105% of original optimal cost) +iteration_limit = 55 # max iterations to perform +time_limit_hrs = 1 # max time +axis = "tech_category_activity" # use the tech activity Manager to control exploration based on categories in Tech +weighting = "hull_expansion" # use a convex hull expansion algorithm to weight exploration + +[myopic] +view_depth = 2 # number of periods seen/analyzed per iteration +step_size = 1 # number of periods to step by (must be <= view depth) + +[morris] +perturbation = 0.10 # amount to perturb marked parameters (ex: 0.10 -> +/- 10%) +levels = 8 # number of levels in param grid (must be even number) +trajectories = 10 # number of Morris trajectories to generate/explore +seed = false # random seed for use in generation/analysis for repeatable results. false=system derived +cores = 0 # number of CPU cores to use. 0 (default) = cpu count +# Note: Problem size (in general) is (Groups + 1) * trajectories see the SALib Dox +# Groups = number of unique labels used in MM analysis columns in DB + +[SVMGA] +cost_epsilon = 0.05 +# labels from appropriate tables in database. It is recommended to only use one of the lists below and leave +# the others blank +emission_labels = ['co2', 'nox'] +capacity_labels = ['TXD', 'TXG'] +activity_labels = [] + +[monte_carlo] +# a path from the PROJECT ROOT to the settings file that contains the run data. +run_settings = 'data_files/monte_carlo/run_settings_1.csv' + From 46f0c90ad2774b8f770a212695d174a012c9e4f7 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 21 Jul 2025 13:36:18 -0400 Subject: [PATCH 182/587] Revert all default solvers to cbc --- tests/testing_configs/config_materials.toml | 2 +- tests/testing_configs/config_seasonal_storage.toml | 2 +- tests/testing_configs/config_survival_curve.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/testing_configs/config_materials.toml b/tests/testing_configs/config_materials.toml index 51a038bec..71f23bf7b 100644 --- a/tests/testing_configs/config_materials.toml +++ b/tests/testing_configs/config_materials.toml @@ -7,7 +7,7 @@ output_database = "tests/testing_outputs/materials.sqlite" neos = false # solver -solver_name = "gurobi" +solver_name = "cbc" # generate an excel file in the output_files folder save_excel = false diff --git a/tests/testing_configs/config_seasonal_storage.toml b/tests/testing_configs/config_seasonal_storage.toml index 3ba26b442..bbd82ede2 100644 --- a/tests/testing_configs/config_seasonal_storage.toml +++ b/tests/testing_configs/config_seasonal_storage.toml @@ -7,7 +7,7 @@ output_database = "tests/testing_outputs/seasonal_storage.sqlite" neos = false # solver -solver_name = "gurobi" +solver_name = "cbc" # generate an excel file in the output_files folder save_excel = false diff --git a/tests/testing_configs/config_survival_curve.toml b/tests/testing_configs/config_survival_curve.toml index b4e48f2f8..19cd465d3 100644 --- a/tests/testing_configs/config_survival_curve.toml +++ b/tests/testing_configs/config_survival_curve.toml @@ -7,7 +7,7 @@ output_database = "tests/testing_outputs/survival_curve.sqlite" neos = false # solver -solver_name = "gurobi" +solver_name = "cbc" # generate an excel file in the output_files folder save_excel = false From 3bcbf45335a6dd4706d6548887bb94549f6a31cd Mon Sep 17 00:00:00 2001 From: Anil Radhakrishnan Date: Mon, 21 Jul 2025 13:46:07 -0400 Subject: [PATCH 183/587] adding pre-commit based code consistency (#9) --- .pre-commit-config.yaml | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6eb1cd44b..f0d5889bd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ repos: - repo: https://github.com/astral-sh/uv-pre-commit # uv version. - rev: 0.7.21 + rev: 0.8.0 hooks: # Dependency management - id: uv-lock @@ -25,3 +25,31 @@ repos: - -o - requirements-dev.txt # Output file name files: ^pyproject\.toml$ + + # Code quality and formatting + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-toml + - id: check-json + - id: check-merge-conflict + - id: check-added-large-files + args: ["--maxkb=1024"] + - id: debug-statements + # Python Linting & Formatting with Ruff + - repo: https://github.com/astral-sh/ruff-pre-commit + # Ruff version. + rev: "v0.12.4" + hooks: + - id: ruff + name: ruff (linter) + args: [--fix, --exit-non-zero-on-fix] + # --fix: attempts to automatically fix linting issues. + # --exit-non-zero-on-fix: ensures that if fixes were made, + # the commit fails, prompting you to + # review and re-stage the changes. + - id: ruff-format + name: ruff-format (formatter) From f31d62f93a56359db1e33b3d6362c78139187dde Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 21 Jul 2025 16:42:10 -0400 Subject: [PATCH 184/587] Fix bug in warning output for seasonal storage --- temoa/temoa_model/temoa_initialize.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index e0be2c8b2..2d6e99120 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1202,9 +1202,9 @@ def CreateTimeSeasonSequential(M: 'TemoaModel'): ) if abs(count_total - value(M.DaysPerPeriod)) >= 0.001: logger.warning( - f'Sum of num_days in TimeSeasonSequential ({sum(sequential.values())}) ' - f'does not sum to days_per_period ({value(M.DaysPerPeriod)}) from the ' - 'MetaData table.' + f'Sum of num_days in TimeSeasonSequential ({count_total}) ' + f'for period {p} does not sum to days_per_period ({value(M.DaysPerPeriod)}) ' + 'from the MetaData table.' ) # Check that seasons using in storage seasons are actual seasons From bcbefc7f8352893cd40d262c9fac51c7d9dccbbe Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 21 Jul 2025 16:44:51 -0400 Subject: [PATCH 185/587] Remove pointless check in commodity balance constraints --- temoa/temoa_model/temoa_rules.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 263e72095..9398c58cf 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1122,8 +1122,6 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): \qquad \forall \{r, p, s, d, c\} \in \Theta_{\text{CommodityBalance}} """ - if c in M.commodity_demand: # Is this necessary? Demand comms have no downstream process no shouldnt be in indices - return Constraint.Skip produced = 0 consumed = 0 @@ -1255,9 +1253,6 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): at the period level, summing all flows over the period but allowing imbalances at the time slice or seasonal level. Applies only to commodities in the :code:`commodity_annual` set. """ - - if c in M.commodity_demand: # Is this necessary? Demand comms have no downstream process no shouldnt be in indices - return Constraint.Skip produced = 0 consumed = 0 From ffd8b01eb62ced5700064e2ca1851ea1756b9074 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 21 Jul 2025 18:55:40 -0400 Subject: [PATCH 186/587] Optimise and standardise usage of key sets --- .../model_checking/network_model_data.py | 6 +- .../model_checking/pricing_check.py | 10 +- .../temoa_model/model_checking/validators.py | 2 +- temoa/temoa_model/table_data_puller.py | 18 ++-- temoa/temoa_model/table_writer.py | 2 +- temoa/temoa_model/temoa_initialize.py | 96 ++++++++++--------- temoa/temoa_model/temoa_model.py | 6 +- temoa/temoa_model/temoa_rules.py | 28 +++--- tests/legacy_test_values.py | 9 +- tests/testing_data/test_system_sets.json | 20 ---- tests/testing_data/utopia_sets.json | 75 --------------- 11 files changed, 92 insertions(+), 180 deletions(-) diff --git a/temoa/temoa_model/model_checking/network_model_data.py b/temoa/temoa_model/model_checking/network_model_data.py index 2a93a625d..b2efebda6 100644 --- a/temoa/temoa_model/model_checking/network_model_data.py +++ b/temoa/temoa_model/model_checking/network_model_data.py @@ -91,7 +91,7 @@ def available_techs(self) -> dict[tuple[str, int | str], set[Tech]]: @available_techs.setter def available_techs(self, available_techs: dict[tuple[str, int], set[Tech]]) -> None: # check for region violations - for r, p in available_techs.keys(): + for r, p in available_techs: for tech in available_techs[r, p]: if tech.region != r: raise ValueError( @@ -152,7 +152,7 @@ def _build_from_model(M: TemoaModel, myopic_index=None) -> NetworkModelData: res.physical_commodities = set(M.commodity_all) source_com = defaultdict(set) dem_com = defaultdict(set) - for r, p, d in M.Demand: + for r, p, d in M.Demand.sparse_iterkeys(): dem_com[r, p].add(d) res.demand_commodities = dem_com techs = defaultdict(set) @@ -164,7 +164,7 @@ def _build_from_model(M: TemoaModel, myopic_index=None) -> NetworkModelData: techs[r, p].add(Tech(r, ic, tech, v, oc)) res.available_techs = techs linked_techs = set() - for r, driver, emission, driven in M.LinkedTechs: + for r, driver, emission, driven in M.LinkedTechs.sparse_iterkeys(): linked_techs.add(LinkedTech(r, driver, emission, driven)) res.available_linked_techs = linked_techs logger.debug('built network data: %s', res.__str__()) diff --git a/temoa/temoa_model/model_checking/pricing_check.py b/temoa/temoa_model/model_checking/pricing_check.py index b2a66fcf9..07f064113 100644 --- a/temoa/temoa_model/model_checking/pricing_check.py +++ b/temoa/temoa_model/model_checking/pricing_check.py @@ -78,11 +78,11 @@ def price_checker(M: 'TemoaModel') -> bool: # var costs for the period = vintage year base_year_variable_cost_rtv = set() - for r, p, t, v in M.CostFixed: + for r, p, t, v in M.CostFixed.sparse_iterkeys(): fixed_costs[r, t, v].add(p) if p == v: base_year_fixed_cost_rtv.add((r, t, v)) - for r, p, t, v in M.CostVariable: + for r, p, t, v in M.CostVariable.sparse_iterkeys(): var_costs[r, t, v].add(p) if p == v: base_year_variable_cost_rtv.add((r, t, v)) @@ -291,7 +291,7 @@ def check_tech_uncap(M: 'TemoaModel') -> bool: if tech in M.tech_uncap } - fixed_cost_periods = {(r, t, v): p for r, p, t, v in M.CostFixed} + fixed_cost_periods = {(r, t, v): p for r, p, t, v in M.CostFixed.sparse_iterkeys()} rtv_with_fixed_cost = efficiency_rtv & set(fixed_cost_periods.keys()) if rtv_with_fixed_cost: logger.error( @@ -300,7 +300,7 @@ def check_tech_uncap(M: 'TemoaModel') -> bool: for rtv in rtv_with_fixed_cost: logger.error('%s: %s', rtv, fixed_cost_periods[rtv]) - rtv_with_invest_cost = efficiency_rtv & set(M.CostInvest.keys()) + rtv_with_invest_cost = efficiency_rtv & set(M.CostInvest.sparse_iterkeys()) if rtv_with_invest_cost: logger.error( 'The following technologies are labeled as unlimited capacity, but have an INVEST cost' @@ -341,7 +341,7 @@ def check_tech_uncap(M: 'TemoaModel') -> bool: capacity_params = (M.ExistingCapacity,) bad_cap_entries = False for param in capacity_params: - bad_entries = {(r, t, v) for r, t, v in param.keys() if t in M.tech_uncap} + bad_entries = {(r, t, v) for r, t, v in param.sparse_iterkeys() if t in M.tech_uncap} if bad_entries: for entry in bad_entries: logger.error( diff --git a/temoa/temoa_model/model_checking/validators.py b/temoa/temoa_model/model_checking/validators.py index 5ed4371be..d3611b643 100644 --- a/temoa/temoa_model/model_checking/validators.py +++ b/temoa/temoa_model/model_checking/validators.py @@ -306,7 +306,7 @@ def validate_Efficiency(M: 'TemoaModel', val, r, si, t, v, so) -> bool: def validate_ReserveMargin(M: 'TemoaModel'): - for r in M.PlanningReserveMargin: + for r in M.PlanningReserveMargin.sparse_iterkeys(): if all((r, p) not in M.processReservePeriods for p in M.time_optimize): logger.warning( 'Planning reserve margin provided but there are no reserve ' diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index 7d3a2e2c5..e4e527c5c 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -96,7 +96,7 @@ def poll_capacity_results(M: TemoaModel, epsilon=1e-5) -> CapData: """ # Built Capacity built = [] - for r, t, v in M.V_NewCapacity: + for r, t, v in M.V_NewCapacity.keys(): if v in M.time_optimize: val = value(M.V_NewCapacity[r, t, v]) if abs(val) < epsilon: @@ -106,7 +106,7 @@ def poll_capacity_results(M: TemoaModel, epsilon=1e-5) -> CapData: # NetCapacity net = [] - for r, p, t, v in M.V_Capacity: + for r, p, t, v in M.V_Capacity.keys(): val = value(M.V_Capacity[r, p, t, v]) if abs(val) < epsilon: continue @@ -147,7 +147,7 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl # ---- NON-annual ---- # Storage, which has a unique v_flow_in (non-storage techs do not have this variable) - for key in M.V_FlowIn: + for key in M.V_FlowIn.keys(): fi = FI(*key) flow = value(M.V_FlowIn[fi]) if abs(flow) < epsilon: @@ -156,7 +156,7 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl res[fi][FlowType.LOST] = (1 - temoa_rules.get_variable_efficiency(M, *key)) * flow # regular flows - for key in M.V_FlowOut: + for key in M.V_FlowOut.keys(): fi = FI(*key) flow = value(M.V_FlowOut[fi]) if abs(flow) < epsilon: @@ -169,7 +169,7 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl res[fi][FlowType.LOST] = (1 - temoa_rules.get_variable_efficiency(M, *key)) * flow # curtailment flows - for key in M.V_Curtailment: + for key in M.V_Curtailment.keys(): fi = FI(*key) val = value(M.V_Curtailment[fi]) if abs(val) < epsilon: @@ -177,7 +177,7 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl res[fi][FlowType.CURTAIL] = val # flex techs. This will subtract the flex from their output flow IOT make OUT the "net" - for key in M.V_Flex: + for key in M.V_Flex.keys(): fi = FI(*key) flow = value(M.V_Flex[fi]) if abs(flow) < epsilon: @@ -188,7 +188,7 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl # ---- annual ---- # basic annual flows - for r, p, i, t, v, o in M.V_FlowOutAnnual: + for r, p, i, t, v, o in M.V_FlowOutAnnual.keys(): for s in M.TimeSeason[p]: for d in M.time_of_day: fi = FI(r, p, s, d, i, t, v, o) @@ -200,7 +200,7 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl res[fi][FlowType.LOST] = (1 - value(M.Efficiency[ritvo(fi)])) * res[fi][FlowType.IN] # flex annual - for r, p, i, t, v, o in M.V_FlexAnnual: + for r, p, i, t, v, o in M.V_FlexAnnual.keys(): for s in M.TimeSeason[p]: for d in M.time_of_day: fi = FI(r, p, s, d, i, t, v, o) @@ -570,7 +570,7 @@ def poll_emissions( base = [ (r, p, e, i, t, v, o) - for (r, e, i, t, v, o) in M.EmissionActivity + for (r, e, i, t, v, o) in M.EmissionActivity.sparse_iterkeys() for p in M.time_optimize if (r, p, t, v) in M.processInputs ] diff --git a/temoa/temoa_model/table_writer.py b/temoa/temoa_model/table_writer.py index d94fb330c..79ac82db0 100644 --- a/temoa/temoa_model/table_writer.py +++ b/temoa/temoa_model/table_writer.py @@ -510,7 +510,7 @@ def write_costs(self, M: TemoaModel, emission_entries=None, iteration=None): def _insert_cost_results(self, regular_entries, exchange_entries, emission_entries, iteration): # add the emission costs to the same row data, if provided if emission_entries: - for k in emission_entries.keys(): + for k in emission_entries: regular_entries[k].update(emission_entries[k]) self._write_cost_rows(regular_entries, iteration=iteration) self._write_cost_rows(exchange_entries, iteration=iteration) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 2d6e99120..6a180d0c4 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -262,10 +262,10 @@ def CheckEfficiencyIndices(M: 'TemoaModel'): # TODO: This could be upgraded to scan for finer resolution # by checking by REGION and PERIOD... Each region/period is unique. c_physical = set(i for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) - c_physical = c_physical | set(i for r, i, t, v in M.ConstructionInput) + c_physical = c_physical | set(i for r, i, t, v in M.ConstructionInput.sparse_iterkeys()) techs = set(t for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) c_outputs = set(o for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) - c_outputs = c_outputs | set(o for r, t, v, o in M.EndOfLifeOutput) + c_outputs = c_outputs | set(o for r, t, v, o in M.EndOfLifeOutput.sparse_iterkeys()) symdiff = c_physical.symmetric_difference(M.commodity_physical) if symdiff: @@ -938,11 +938,11 @@ def CreateSparseDicts(M: 'TemoaModel'): # raise ValueError(f_msg) # Need this here for the commodity balance rpc set - for r, i, t, v in M.ConstructionInput: + for r, i, t, v in M.ConstructionInput.sparse_iterkeys(): if (r, v, i) not in M.capacityConsumptionTechs: M.capacityConsumptionTechs[r, v, i] = set() M.capacityConsumptionTechs[r, v, i].add(t) - for r, t, v, o in M.EndOfLifeOutput: + for r, t, v, o in M.EndOfLifeOutput.sparse_iterkeys(): if (r, t, v) not in M.retirementPeriods: continue # might be running myopic for p in M.retirementPeriods[r, t, v]: @@ -961,8 +961,8 @@ def CreateSparseDicts(M: 'TemoaModel'): SE.write(msg.format(i)) # valid region-period-commodity sets for commodity balance constraints - commodityUpstream_rpi = set(M.commodityUStreamProcess.keys() | M.retirementProductionProcesses.keys() | M.importRegions.keys()) - commodityDownstream_rpo = set(M.commodityDStreamProcess.keys() | M.capacityConsumptionTechs.keys() | M.exportRegions.keys()) + commodityUpstream_rpi = set(M.commodityUStreamProcess | M.retirementProductionProcesses | M.importRegions) + commodityDownstream_rpo = set(M.commodityDStreamProcess | M.capacityConsumptionTechs | M.exportRegions) M.commodityBalance_rpc = commodityUpstream_rpi.intersection(commodityDownstream_rpo) # A dictionary of whether a storage tech is seasonal, just to speed things up @@ -973,7 +973,7 @@ def CreateSparseDicts(M: 'TemoaModel'): M.activeFlow_rpsditvo = set( (r, p, s, d, i, t, v, o) - for r, p, t in M.processVintages.keys() + for r, p, t in M.processVintages if t not in M.tech_annual for v in M.processVintages[r, p, t] for i in M.processInputs[r, p, t, v] @@ -984,7 +984,7 @@ def CreateSparseDicts(M: 'TemoaModel'): M.activeFlow_rpitvo = set( (r, p, i, t, v, o) - for r, p, t in M.processVintages.keys() + for r, p, t in M.processVintages if t in M.tech_annual for v in M.processVintages[r, p, t] for i in M.processInputs[r, p, t, v] @@ -993,7 +993,7 @@ def CreateSparseDicts(M: 'TemoaModel'): M.activeFlex_rpsditvo = set( (r, p, s, d, i, t, v, o) - for r, p, t in M.processVintages.keys() + for r, p, t in M.processVintages if (t not in M.tech_annual) and (t in M.tech_flex) for v in M.processVintages[r, p, t] for i in M.processInputs[r, p, t, v] @@ -1004,7 +1004,7 @@ def CreateSparseDicts(M: 'TemoaModel'): M.activeFlex_rpitvo = set( (r, p, i, t, v, o) - for r, p, t in M.processVintages.keys() + for r, p, t in M.processVintages if (t in M.tech_annual) and (t in M.tech_flex) for v in M.processVintages[r, p, t] for i in M.processInputs[r, p, t, v] @@ -1013,7 +1013,7 @@ def CreateSparseDicts(M: 'TemoaModel'): M.activeFlowInStorage_rpsditvo = set( (r, p, s, d, i, t, v, o) - for r, p, t in M.processVintages.keys() + for r, p, t in M.processVintages if t in M.tech_storage for v in M.processVintages[r, p, t] for i in M.processInputs[r, p, t, v] @@ -1024,7 +1024,7 @@ def CreateSparseDicts(M: 'TemoaModel'): M.activeCurtailment_rpsditvo = set( (r, p, s, d, i, t, v, o) - for r, p, t in M.curtailmentVintages.keys() + for r, p, t in M.curtailmentVintages for v in M.curtailmentVintages[r, p, t] for i in M.processInputs[r, p, t, v] for o in M.processOutputsByInput[r, p, t, v, i] @@ -1034,45 +1034,47 @@ def CreateSparseDicts(M: 'TemoaModel'): M.activeActivity_rptv = set( (r, p, t, v) - for r, p, t in M.processVintages.keys() + for r, p, t in M.processVintages for v in M.processVintages[r, p, t] ) - M.activeRegionsForTech = defaultdict(set) - for r, p, t, v in M.activeActivity_rptv: - M.activeRegionsForTech[p, t].add(r) + # devnote: currently unused + # M.activeRegionsForTech = defaultdict(set) + # for r, p, t, v in M.activeActivity_rptv: + # M.activeRegionsForTech[p, t].add(r) - M.activeCapacity_rtv = set( + M.newCapacity_rtv = set( (r, t, v) - for r, p, t in M.processVintages.keys() + for r, p, t in M.processVintages for v in M.processVintages[r, p, t] - if t not in M.tech_uncap + if t not in M.tech_uncap and v in M.time_optimize ) M.activeCapacityAvailable_rpt = set( (r, p, t) - for r, p, t in M.processVintages.keys() + for r, p, t in M.processVintages if M.processVintages[r, p, t] if t not in M.tech_uncap ) M.activeCapacityAvailable_rptv = set( (r, p, t, v) - for r, p, t in M.processVintages.keys() + for r, p, t in M.processVintages for v in M.processVintages[r, p, t] if t not in M.tech_uncap ) - M.groupRegionActiveFlow_rpt = set( - (gr, p, t) - for _r, p, t in M.processVintages.keys() - for gr in M.regionalGlobalIndices - if _r in gather_group_regions(M, gr) - ) + # devnote: currently unused + # M.groupRegionActiveFlow_rpt = set( + # (gr, p, t) + # for _r, p, t in M.processVintages + # for gr in M.regionalGlobalIndices + # if _r in gather_group_regions(M, gr) + # ) M.storageLevelIndices_rpsdtv = set( (r, p, s, d, t, v) - for r, p, t in M.storageVintages.keys() + for r, p, t in M.storageVintages for v in M.storageVintages[r, p, t] for s in M.TimeSeason[p] for d in M.time_of_day @@ -1080,7 +1082,7 @@ def CreateSparseDicts(M: 'TemoaModel'): M.seasonalStorageLevelIndices_rpstv = set( (r, p, s_stor, t, v) - for r, p, t in M.storageVintages.keys() + for r, p, t in M.storageVintages if t in M.tech_seasonal_storage for v in M.storageVintages[r, p, t] for _p, s_stor in M.sequential_to_season @@ -1179,7 +1181,7 @@ def CreateTimeSeasonSequential(M: 'TemoaModel'): raise ValueError(msg) sequential = dict() - for p, s_seq, s in M.TimeSeasonSequential: + for p, s_seq, s in M.TimeSeasonSequential.sparse_iterkeys(): num_days = value(M.TimeSeasonSequential[p, s_seq, s]) if M.TimeSequencing.first() == 'consecutive_days' and abs(num_days - 1.0) >= 0.01: msg = ( @@ -1217,7 +1219,7 @@ def CreateTimeSeasonSequential(M: 'TemoaModel'): logger.error(msg) raise ValueError(msg) - for (p, s) in M.SegFracPerSeason: + for (p, s) in M.SegFracPerSeason.sparse_iterkeys(): if s not in M.TimeSeason[p]: continue @@ -1244,11 +1246,11 @@ def CreateSurvivalCurve(M: 'TemoaModel'): rtv_interpolated = set() # so we only need one warning - for (r, _, t, v, _) in M.Efficiency: + for (r, _, t, v, _) in M.Efficiency.sparse_iterkeys(): M.isSurvivalCurveProcess[r, t, v] = False # by default # Collect rptv indices into (r, t, v): p dictionary - for r, p, t, v in M.LifetimeSurvivalCurve: + for r, p, t, v in M.LifetimeSurvivalCurve.sparse_iterkeys(): if (r, t, v) not in M.survivalCurvePeriods: M.survivalCurvePeriods[r, t, v] = list() M.survivalCurvePeriods[r, t, v].append(p) @@ -1478,13 +1480,13 @@ def LifetimeLoanProcessIndices(M: 'TemoaModel'): def CapacityVariableIndices(M: 'TemoaModel'): - return M.activeCapacity_rtv + return M.newCapacity_rtv def RetiredCapacityVariableIndices(M: 'TemoaModel'): return set( (r, p, t, v) - for r, p, t in M.processVintages.keys() + for r, p, t in M.processVintages if t in M.tech_retirement and t not in M.tech_uncap for v in M.processVintages[r, p, t] if v < p <= v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[p]) @@ -1494,7 +1496,7 @@ def RetiredCapacityVariableIndices(M: 'TemoaModel'): def AnnualRetirementVariableIndices(M: 'TemoaModel'): return set( (r, p, t, v) - for r, t, v in M.retirementPeriods.keys() + for r, t, v in M.retirementPeriods for p in M.retirementPeriods[r, t, v] ) @@ -1677,7 +1679,7 @@ def DemandConstraintIndices(M: 'TemoaModel'): def BaseloadDiurnalConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, s, d, t, v) - for r, p, t in M.baseloadVintages.keys() + for r, p, t in M.baseloadVintages for v in M.baseloadVintages[r, p, t] for s in M.TimeSeason[p] for d in M.time_of_day @@ -1689,7 +1691,7 @@ def BaseloadDiurnalConstraintIndices(M: 'TemoaModel'): def RegionalExchangeCapacityConstraintIndices(M: 'TemoaModel'): indices = set( (r_e, r_i, p, t, v) - for r_e, p, i in M.exportRegions.keys() + for r_e, p, i in M.exportRegions for r_i, t, v, o in M.exportRegions[r_e, p, i] ) @@ -1790,7 +1792,7 @@ def RampDownSeasonConstraintIndices(M: 'TemoaModel'): def ReserveMarginIndices(M: 'TemoaModel'): indices = set( (r, p, s, d) - for r in M.PlanningReserveMargin + for r in M.PlanningReserveMargin.sparse_iterkeys() for p in M.time_optimize if (r, p) in M.processReservePeriods for s in M.TimeSeason[p] @@ -1803,7 +1805,7 @@ def ReserveMarginIndices(M: 'TemoaModel'): def LimitTechInputSplitConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, s, d, i, t, v, op) - for r, p, i, t, op in M.inputSplitVintages.keys() + for r, p, i, t, op in M.inputSplitVintages if t not in M.tech_annual for v in M.inputSplitVintages[r, p, i, t, op] for s in M.TimeSeason[p] @@ -1811,7 +1813,7 @@ def LimitTechInputSplitConstraintIndices(M: 'TemoaModel'): ) ann_indices = set( (r, p, i, t, op) - for r, p, i, t, op in M.inputSplitVintages.keys() + for r, p, i, t, op in M.inputSplitVintages if t in M.tech_annual ) if len(ann_indices) > 0: @@ -1827,7 +1829,7 @@ def LimitTechInputSplitConstraintIndices(M: 'TemoaModel'): def LimitTechInputSplitAnnualConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, i, t, v, op) - for r, p, i, t, op in M.inputSplitAnnualVintages.keys() + for r, p, i, t, op in M.inputSplitAnnualVintages if t in M.tech_annual for v in M.inputSplitAnnualVintages[r, p, i, t, op] ) @@ -1838,7 +1840,7 @@ def LimitTechInputSplitAnnualConstraintIndices(M: 'TemoaModel'): def LimitTechInputSplitAverageConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, i, t, v, op) - for r, p, i, t, op in M.inputSplitAnnualVintages.keys() + for r, p, i, t, op in M.inputSplitAnnualVintages if t not in M.tech_annual for v in M.inputSplitAnnualVintages[r, p, i, t, op] ) @@ -1848,7 +1850,7 @@ def LimitTechInputSplitAverageConstraintIndices(M: 'TemoaModel'): def LimitTechOutputSplitConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, s, d, t, v, o, op) - for r, p, t, o, op in M.outputSplitVintages.keys() + for r, p, t, o, op in M.outputSplitVintages if t not in M.tech_annual for v in M.outputSplitVintages[r, p, t, o, op] for s in M.TimeSeason[p] @@ -1856,7 +1858,7 @@ def LimitTechOutputSplitConstraintIndices(M: 'TemoaModel'): ) ann_indices = set( (r, p, t, o, op) - for r, p, t, o, op in M.outputSplitVintages.keys() + for r, p, t, o, op in M.outputSplitVintages if t in M.tech_annual ) if len(ann_indices) > 0: @@ -1872,7 +1874,7 @@ def LimitTechOutputSplitConstraintIndices(M: 'TemoaModel'): def LimitTechOutputSplitAnnualConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, t, v, o, op) - for r, p, t, o, op in M.outputSplitAnnualVintages.keys() + for r, p, t, o, op in M.outputSplitAnnualVintages if t in M.tech_annual for v in M.outputSplitAnnualVintages[r, p, t, o, op] ) @@ -1882,7 +1884,7 @@ def LimitTechOutputSplitAnnualConstraintIndices(M: 'TemoaModel'): def LimitTechOutputSplitAverageConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, t, v, o, op) - for r, p, t, o, op in M.outputSplitAnnualVintages.keys() + for r, p, t, o, op in M.outputSplitAnnualVintages if t not in M.tech_annual for v in M.outputSplitAnnualVintages[r, p, t, o, op] ) diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 07917bb92..980ea1522 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -94,7 +94,7 @@ def __init__(M, *args, **kwargs): M.activeRegionsForTech = None """currently available regions by period and tech {(p, t) : r}""" - M.activeCapacity_rtv = None + M.newCapacity_rtv = None M.activeCapacityAvailable_rpt = None M.activeCapacityAvailable_rptv = None M.groupRegionActiveFlow_rpt = None # Set of valid group-region, period, tech indices @@ -139,7 +139,7 @@ def __init__(M, *args, **kwargs): M.isEfficiencyVariable: dict[tuple, bool] = dict() # {(r, p, i, t, v, o): bool} which efficiencies have variable indexing M.isCapacityFactorProcess: dict[tuple, bool] = dict() # {(r, p, t, v): bool} which capacity factors have have period-vintage indexing M.isSeasonalStorage: dict[tuple, bool] = dict() # {t: bool} whether a storage tech is seasonal storage - M.isSurvivalCurveProcess: dict[str, bool] = dict() # {(r, t, v): bool} whether a process uses survival curves. + M.isSurvivalCurveProcess: dict[tuple, bool] = dict() # {(r, t, v): bool} whether a process uses survival curves. ################################################ # Model Sets # @@ -628,9 +628,11 @@ def __init__(M, *args, **kwargs): # M.RetiredCapacityConstraint = Constraint( # M.RetiredCapacityVar_rptv, rule=RetiredCapacity_Constraint # ) + M.progress_marker_4a = BuildAction(['Starting AnnualRetirementConstraint'], rule=progress_check) M.AnnualRetirementConstraint = Constraint( M.AnnualRetirementVar_rptv, rule=AnnualRetirement_Constraint ) + M.progress_marker_4b = BuildAction(['Starting AdjustedCapacityConstraint'], rule=progress_check) M.AdjustedCapacityConstraint = Constraint( M.CostFixed_rptv, rule=AdjustedCapacity_Constraint ) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 9398c58cf..a9a51c7df 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -830,7 +830,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): # of indices that are valid which is basically the filter of: # EmissionActivty by CostEmission # and to ensure that the techology is active we need to filter that - # result with processInput.keys() + # result with processInput # ================= Emissions and Flex and Curtailment ================= # Flex flows are deducted from V_FlowOut, so it is NOT NEEDED to tax them again. (See commodity balance constr) @@ -839,7 +839,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): base = [ (r, p, e, i, t, v, o) - for (r, e, i, t, v, o) in M.EmissionActivity + for (r, e, i, t, v, o) in M.EmissionActivity.sparse_iterkeys() if (r, p, e) in M.CostEmission # tightest filter first and (r, p, t, v) in M.processInputs ] @@ -1414,14 +1414,14 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): # try: # collected = sum( # M.V_FlowOut[reg, p, S_s, S_d, S_i, S_t, S_v, r] # is r the input or the output!? -# for S_i, S_t, S_v in M.processByPeriodAndOutput.keys() +# for S_i, S_t, S_v in M.processByPeriodAndOutput # for S_s in M.TimeSeason[p] # for S_d in M.time_of_day # ) # except KeyError: # collected = sum( # M.V_FlowOutAnnual[reg, p, S_i, S_t, S_v, r] -# for S_i, S_t, S_v in M.processByPeriodAndOutput.keys() +# for S_i, S_t, S_v in M.processByPeriodAndOutput # ) # expr = collected <= value(M.ResourceBound[reg, p, r]) @@ -2589,7 +2589,7 @@ def LimitGrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): CapRPT = M.V_CapacityAvailableByPeriodAndTech # relevant r, p, t indices - cap_rpt = set((_r, _p, _t) for _r, _p, _t in CapRPT if _t in techs and _r in regions) + cap_rpt = set((_r, _p, _t) for _r, _p, _t in CapRPT.keys() if _t in techs and _r in regions) # periods the technology can have capacity in this region (sorted) periods = sorted(set(_p for _r, _p, _t in cap_rpt)) @@ -2629,7 +2629,7 @@ def LimitGrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): capacity_prev = sum( value(M.ExistingCapacity[_r, _t, _v]) \ * min( 1.0, (_v + value(M.LifetimeProcess[_r, _t, _v]) - p_prev)/(p - p_prev) ) - for _r, _t, _v in M.ExistingCapacity + for _r, _t, _v in M.ExistingCapacity.sparse_iterkeys() if _r in regions and _t in techs and _v + value(M.LifetimeProcess[_r, _t, _v]) > p_prev ) else: @@ -2700,9 +2700,9 @@ def LimitGrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False) NewCapRTV = M.V_NewCapacity # relevant r, t, v indices - cap_rtv = set((_r, _t, _v) for _r, _t, _v in NewCapRTV if _t in techs and _r in regions) + cap_rtv = set((_r, _t, _v) for _r, _t, _v in NewCapRTV.keys() if _t in techs and _r in regions) # periods the technology can be built in this region (sorted) - periods = sorted(set(_v for _r, _t, _v in NewCapRTV if _v in M.time_optimize)) + periods = sorted(set(_v for _r, _t, _v in cap_rtv)) if len(periods) == 0: if p == M.time_optimize.first(): @@ -2738,7 +2738,7 @@ def LimitGrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False) p_prev = M.time_exist.last() new_cap_prev = sum( value(M.ExistingCapacity[_r, _t, _v]) - for _r, _t, _v in M.ExistingCapacity + for _r, _t, _v in M.ExistingCapacity.sparse_iterkeys() if _r in regions and _t in techs and _v == p_prev ) else: @@ -2812,9 +2812,9 @@ def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = F NewCapRTV = M.V_NewCapacity # relevant r, t, v indices - cap_rtv = set((_r, _t, _v) for _r, _t, _v in NewCapRTV if _t in techs and _r in regions) + cap_rtv = set((_r, _t, _v) for _r, _t, _v in NewCapRTV.keys() if _t in techs and _r in regions) # periods the technology can be built in this region (sorted) - periods = sorted(set(_v for _r, _t, _v in cap_rtv if _v in M.time_optimize)) + periods = sorted(set(_v for _r, _t, _v in cap_rtv)) if len(periods) == 0: if p == M.time_optimize.first(): @@ -2851,13 +2851,13 @@ def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = F p_prev = M.time_exist.last() new_cap_prev = sum( value(M.ExistingCapacity[_r, _t, _v]) - for _r, _t, _v in M.ExistingCapacity + for _r, _t, _v in M.ExistingCapacity.sparse_iterkeys() if _r in regions and _t in techs and _v == p_prev ) p_prev2 = M.time_exist.prev(p_prev) new_cap_prev2 = sum( value(M.ExistingCapacity[_r, _t, _v]) - for _r, _t, _v in M.ExistingCapacity + for _r, _t, _v in M.ExistingCapacity.sparse_iterkeys() if _r in regions and _t in techs and _v == p_prev2 ) else: @@ -2873,7 +2873,7 @@ def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = F p_prev2 = M.time_exist.last() new_cap_prev2 = sum( value(M.ExistingCapacity[_r, _t, _v]) - for _r, _t, _v in M.ExistingCapacity + for _r, _t, _v in M.ExistingCapacity.sparse_iterkeys() if _r in regions and _t in techs and _v == p_prev2 ) else: diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index 2362b37c4..32f7efd44 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -50,7 +50,8 @@ class ExpectedVals(Enum): ExpectedVals.CONSTR_COUNT: 2834, # reduced by 6 when reworking storageinit. # increased after making annualretirement derived var - ExpectedVals.VAR_COUNT: 1904, + # reduced 2025/07/21 after removing existing vintage V_NewCapacity indices + ExpectedVals.VAR_COUNT: 1900, }, 'utopia': { # reduced after reworking storageinit -> storage was less constrained @@ -66,7 +67,8 @@ class ExpectedVals(Enum): # reduced 3/27: unlim_cap techs now employed. # reduced by 4 in storageinit rework. # increased after making annualretirement derived var - ExpectedVals.VAR_COUNT: 1070, + # reduced 2025/07/21 after removing existing vintage V_NewCapacity indices + ExpectedVals.VAR_COUNT: 1055, }, 'mediumville': { # added 2025/06/12 prior to addition of dynamic reserve margin @@ -94,6 +96,7 @@ class ExpectedVals(Enum): ExpectedVals.EFF_DOMAIN_SIZE: 64, ExpectedVals.EFF_INDEX_SIZE: 8, ExpectedVals.CONSTR_COUNT: 101, - ExpectedVals.VAR_COUNT: 103, + # reduced 2025/07/21 after removing existing vintage V_NewCapacity indices + ExpectedVals.VAR_COUNT: 101, }, } diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 45b6714ab..e629674b4 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -43730,11 +43730,6 @@ "R_EH", 2030 ], - [ - "R1-R2", - "E_TRANS", - 2015 - ], [ "R1", "T_DSL", @@ -43760,21 +43755,11 @@ "T_DSL", 2030 ], - [ - "R2", - "E_NUCLEAR", - 2015 - ], [ "R2", "S_OILREF", 2020 ], - [ - "R2-R1", - "E_TRANS", - 2015 - ], [ "R1", "T_EV", @@ -43925,11 +43910,6 @@ "R_EH", 2025 ], - [ - "R1", - "E_NUCLEAR", - 2015 - ], [ "R2", "T_EV", diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 9cefb9196..072aed77d 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -23780,41 +23780,11 @@ "E21", 2000 ], - [ - "utopia", - "TXG", - 1970 - ], - [ - "utopia", - "E51", - 1980 - ], - [ - "utopia", - "E70", - 1960 - ], - [ - "utopia", - "E31", - 1980 - ], - [ - "utopia", - "RHO", - 1970 - ], [ "utopia", "TXE", 1990 ], - [ - "utopia", - "E01", - 1980 - ], [ "utopia", "E51", @@ -23830,11 +23800,6 @@ "RL1", 1990 ], - [ - "utopia", - "TXD", - 1980 - ], [ "utopia", "TXG", @@ -23870,11 +23835,6 @@ "E01", 2010 ], - [ - "utopia", - "E01", - 1970 - ], [ "utopia", "TXD", @@ -23885,11 +23845,6 @@ "E51", 2000 ], - [ - "utopia", - "E70", - 1980 - ], [ "utopia", "SRE", @@ -23900,11 +23855,6 @@ "TXG", 1990 ], - [ - "utopia", - "RL1", - 1980 - ], [ "utopia", "E31", @@ -23915,11 +23865,6 @@ "RHO", 1990 ], - [ - "utopia", - "TXD", - 1970 - ], [ "utopia", "TXE", @@ -23945,11 +23890,6 @@ "RL1", 2010 ], - [ - "utopia", - "E01", - 1960 - ], [ "utopia", "TXD", @@ -23960,16 +23900,6 @@ "E21", 2010 ], - [ - "utopia", - "E70", - 1970 - ], - [ - "utopia", - "TXG", - 1980 - ], [ "utopia", "E51", @@ -23980,11 +23910,6 @@ "E31", 1990 ], - [ - "utopia", - "RHO", - 1980 - ], [ "utopia", "TXE", From caed9fb5da0392e5b5957ae1a2934c7d9aa1fd1e Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 22 Jul 2025 12:01:01 -0400 Subject: [PATCH 187/587] Test removal of demand activity constraint --- temoa/temoa_model/temoa_initialize.py | 4 ++++ temoa/temoa_model/temoa_model.py | 15 +++++++------ temoa/temoa_model/temoa_rules.py | 31 ++++++++++++++++++--------- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 6a180d0c4..1d03a46ec 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -814,6 +814,10 @@ def CreateSparseDicts(M: 'TemoaModel'): # if tech is no longer active, don't include it if v + l_lifetime <= p: continue + + # All demand technologies must be annual technologies + if o in M.commodity_demand and t not in M.tech_annual: + M.tech_annual.add(t) # Here we utilize the indices in a given iteration of the loop to # create the dictionary keys, and initialize the associated values diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 980ea1522..17555a053 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -281,7 +281,6 @@ def __init__(M, *args, **kwargs): ) M.Demand = Param(M.regions, M.time_optimize, M.commodity_demand) - M.initialize_Demands = BuildAction(rule=CreateDemands) # Dev Note: This parameter is currently NOT implemented. Preserved for later refactoring # LimitResource IS implemented but sums cumulatively for a technology rather than resource commodity @@ -380,6 +379,7 @@ def __init__(M, *args, **kwargs): # perform the sparse matrix of indexing for the parameters, variables, and # equations below. M.Create_SparseDicts = BuildAction(rule=CreateSparseDicts) + M.initialize_Demands = BuildAction(rule=CreateDemands) M.CapacityFactor_rpsdt = Set(dimen=5, initialize=CapacityFactorTechIndices) M.CapacityFactorTech = Param(M.CapacityFactor_rpsdt, default=1, validate=validate_0to1) @@ -644,12 +644,13 @@ def __init__(M, *args, **kwargs): M.DemandConstraint_rpsdc = Set(dimen=5, initialize=DemandConstraintIndices) M.DemandConstraint = Constraint(M.DemandConstraint_rpsdc, rule=Demand_Constraint) - M.DemandActivityConstraint_rpsdtv_dem_s0d0 = Set( - dimen=9, initialize=DemandActivityConstraintIndices - ) - M.DemandActivityConstraint = Constraint( - M.DemandActivityConstraint_rpsdtv_dem_s0d0, rule=DemandActivity_Constraint - ) + # devnote: testing a workaround + # M.DemandActivityConstraint_rpsdtv_dem_s0d0 = Set( + # dimen=9, initialize=DemandActivityConstraintIndices + # ) + # M.DemandActivityConstraint = Constraint( + # M.DemandActivityConstraint_rpsdtv_dem_s0d0, rule=DemandActivity_Constraint + # ) M.CommodityBalanceConstraint_rpsdc = Set( dimen=5, initialize=CommodityBalanceConstraintIndices diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index a9a51c7df..abdb65d5b 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -957,24 +957,24 @@ def Demand_Constraint(M: 'TemoaModel', r, p, s, d, dem): could satisfy both an end-use and internal system demand, then the output from :math:`\textbf{FO}` and :math:`\textbf{FOA}` would be double counted.""" - supply = sum( - M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, dem] - for S_t, S_v in M.commodityUStreamProcess[r, p, dem] - if S_t not in M.tech_annual - for S_i in M.processInputsByOutput[r, p, S_t, S_v, dem] - ) + # All demand techs are annual now + # supply = sum( + # M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, dem] + # for S_t, S_v in M.commodityUStreamProcess[r, p, dem] + # if S_t not in M.tech_annual + # for S_i in M.processInputsByOutput[r, p, S_t, S_v, dem] + # ) supply_annual = sum( M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, dem] for S_t, S_v in M.commodityUStreamProcess[r, p, dem] - if S_t in M.tech_annual for S_i in M.processInputsByOutput[r, p, S_t, S_v, dem] - ) * value(M.SegFrac[p, s, d]) + ) - DemandConstraintErrorCheck(supply + supply_annual, r, p, s, d, dem) + DemandConstraintErrorCheck(supply_annual, r, p, s, d, dem) expr = ( - supply + supply_annual == value(M.Demand[r, p, dem]) * value(M.DemandSpecificDistribution[r, p, s, d, dem]) + supply_annual == value(M.Demand[r, p, dem]) ) return expr @@ -1150,6 +1150,17 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): for S_t, S_v in M.commodityDStreamProcess[r, p, c] if S_t not in M.tech_storage and S_t in M.tech_annual for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] + if S_o not in M.commodity_demand + ) + + # Into demand technologies (always annual flows) + consumed += sum( + value(M.DemandSpecificDistribution[r, p, s, d, S_o]) + * M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] / get_variable_efficiency(M, r, p, s, d, c, S_t, S_v, S_o) + for S_t, S_v in M.commodityDStreamProcess[r, p, c] + if S_t not in M.tech_storage and S_t in M.tech_annual + for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] + if S_o in M.commodity_demand ) if (r, p, c) in M.capacityConsumptionTechs: From 36be10112f2894363d5890bdbf9c76fe7fbfc2f1 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 22 Jul 2025 12:23:26 -0400 Subject: [PATCH 188/587] Update Capacity Constraint to handle change to demand techs --- temoa/temoa_model/temoa_initialize.py | 7 ++++--- temoa/temoa_model/temoa_model.py | 1 + temoa/temoa_model/temoa_rules.py | 18 +++++++++++++----- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 1d03a46ec..d152d13e9 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -816,8 +816,9 @@ def CreateSparseDicts(M: 'TemoaModel'): continue # All demand technologies must be annual technologies - if o in M.commodity_demand and t not in M.tech_annual: + if o in M.commodity_demand and t not in M.tech_demand: M.tech_annual.add(t) + M.tech_demand.add(t) # Here we utilize the indices in a given iteration of the loop to # create the dictionary keys, and initialize the associated values @@ -1562,7 +1563,7 @@ def CapacityConstraintIndices(M: 'TemoaModel'): capacity_indices = set( (r, p, s, d, t, v) for r, p, t, v in M.activeActivity_rptv - if t not in M.tech_annual + if (t not in M.tech_annual or t in M.tech_demand) if t not in M.tech_uncap if t not in M.tech_storage for s in M.TimeSeason[p] @@ -1591,7 +1592,7 @@ def CapacityAnnualConstraintIndices(M: 'TemoaModel'): capacity_indices = set( (r, p, t, v) for r, p, t, v in M.activeActivity_rptv - if t in M.tech_annual + if t in M.tech_annual and t not in M.tech_demand if t not in M.tech_uncap ) diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 17555a053..9d605c3d2 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -183,6 +183,7 @@ def __init__(M, *args, **kwargs): M.tech_all = Set(initialize=M.tech_production, validate=no_slash_or_pipe) # was M.tech_resource | M.tech_production M.tech_baseload = Set(within=M.tech_all) M.tech_annual = Set(within=M.tech_all) + M.tech_demand = Set(within=M.tech_annual) # annual storage not supported in Storage constraint or TableWriter, so exclude from domain M.tech_storage = Set(within=M.tech_all) M.tech_reserve = Set(within=M.tech_all) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index abdb65d5b..db62ead1b 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -244,11 +244,19 @@ def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): # The expressions below are defined in-line to minimize the amount of # expression cloning taking place with Pyomo. - useful_activity = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) + if t in M.tech_demand: + useful_activity = sum( + M.DemandSpecificDistribution[r, p, s, d, S_o] + * M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + else: + useful_activity = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) if t in M.tech_curtailment: # If technologies are present in the curtailment set, then enough From 0b8fa5bbb5e9ac6dc146c244e76e941a564e9b33 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 23 Jul 2025 14:11:02 -0400 Subject: [PATCH 189/587] Update everything for annualisation of demands --- .../temoa_model/model_checking/validators.py | 23 + temoa/temoa_model/run_actions.py | 1 + temoa/temoa_model/table_data_puller.py | 6 +- temoa/temoa_model/temoa_initialize.py | 136 +- temoa/temoa_model/temoa_model.py | 6 +- temoa/temoa_model/temoa_rules.py | 156 +- tests/legacy_test_values.py | 24 +- tests/testing_data/mediumville_sets.json | 734 +- tests/testing_data/test_system_sets.json | 20260 ++++------------ tests/testing_data/utopia_sets.json | 10975 +++------ 10 files changed, 9039 insertions(+), 23282 deletions(-) diff --git a/temoa/temoa_model/model_checking/validators.py b/temoa/temoa_model/model_checking/validators.py index d3611b643..0098975c0 100644 --- a/temoa/temoa_model/model_checking/validators.py +++ b/temoa/temoa_model/model_checking/validators.py @@ -327,9 +327,32 @@ def validate_tech_sets(M: 'TemoaModel'): check_no_intersection(M.tech_annual, M.tech_curtailment), check_no_intersection(M.tech_curtailment, M.tech_flex), check_no_intersection(M.tech_all, M.tech_group_names), + check_no_intersection(M.tech_uncap, M.tech_reserve) ) ): raise ValueError("Technology sets failed to validate. Check log file for details.") + + +def validate_demand_tech_sets(M: 'TemoaModel'): + """ + Check tech sets for any forbidden intersections + """ + if not all( + ( + check_no_intersection(M.tech_demand, M.tech_baseload), + check_no_intersection(M.tech_demand, M.tech_storage), + check_no_intersection(M.tech_demand, M.tech_upramping), + check_no_intersection(M.tech_demand, M.tech_downramping), + check_no_intersection(M.tech_demand, M.tech_flex) + ) + ): + raise ValueError( + "Demand technologies were added to forbidden sets. Check log file for details. " + "If these technologies require these features, consider adding an intermediate " + "process between the technology's output commodity and the demand commodity. " + "Note this will break the enforcement that demand technologies meet " + "a consistent proportion of demands throughout the year." + ) def check_no_intersection(set_one, set_two): diff --git a/temoa/temoa_model/run_actions.py b/temoa/temoa_model/run_actions.py index 7894da6f5..111f5ad74 100644 --- a/temoa/temoa_model/run_actions.py +++ b/temoa/temoa_model/run_actions.py @@ -263,6 +263,7 @@ def solve_instance( optimizer.options["Crossover"] = 0 # non basic solution, ie no crossover optimizer.options["BarConvTol"] = 1.e-5 optimizer.options["FeasibilityTol"] = 1.e-6 + # optimizer.options["BarOrder"] = 0 # if solve times seem unusually long, try 0 or 1 elif solver_name == 'appsi_highs': pass diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index e4e527c5c..a5dbe4b32 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -191,8 +191,12 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl for r, p, i, t, v, o in M.V_FlowOutAnnual.keys(): for s in M.TimeSeason[p]: for d in M.time_of_day: + if t in M.tech_demand: + distribution = value(M.DemandSpecificDistribution[r, p, s, d, o]) + else: + distribution = value(M.SegFrac[p, s, d]) fi = FI(r, p, s, d, i, t, v, o) - flow = value(M.V_FlowOutAnnual[r, p, i, t, v, o]) * value(M.SegFrac[p, s, d]) + flow = value(M.V_FlowOutAnnual[r, p, i, t, v, o]) * distribution if abs(flow) < epsilon: continue res[fi][FlowType.OUT] = flow diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index d152d13e9..815303904 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -108,19 +108,19 @@ def AnnualCommodityBalanceConstraintErrorCheck(supplied, demanded, r, p, c): raise Exception(msg.format(c, r, p, expr)) -def DemandConstraintErrorCheck(supply, r, p, s, d, dem): +def DemandConstraintErrorCheck(supply, r, p, dem): # note: if a pyomo equation simplifies to an int, there are no variables in it, which # is an indicator of a problem if isinstance(supply, int): msg = ( - "Error: Demand '{}' for ({}, {}, {}, {}) unable to be met by any " + "Error: Demand '{}' for ({}, {}) unable to be met by any " 'technology.\n\tPossible reasons:\n' ' - Is the Efficiency parameter missing an entry for this demand?\n' ' - Does a tech that satisfies this demand need a longer ' 'Lifetime?\n' ) - logger.error(msg.format(dem, r, p, s, d)) - raise Exception(msg.format(dem, r, p, s, d)) + logger.error(msg.format(dem, r, p)) + raise Exception(msg.format(dem, r, p)) def validate_time(M: 'TemoaModel'): @@ -1606,76 +1606,74 @@ def CapacityAnnualConstraintIndices(M: 'TemoaModel'): # --------------------------------------------------------------- -def DemandActivityConstraintIndices(M: 'TemoaModel'): - """\ -This function returns a set of sparse indices that are used in the -DemandActivity constraint. It returns a tuple of the form: -(p,s,d,t,v,dem,first_s,first_d) where "dem" is a demand commodity, and "first_s" -and "first_d" are the reference season and time-of-day, respectively used to -ensure demand activity remains consistent across time slices. -""" - - # needed data structures... - # the count of techs that supply a commodity - suppliers = defaultdict(set) - # (region, demand): (season, tod) # the goal of the exercise! - anchor_season_tod = {} - # (region, demand): (period, tech, vintage) # the viable tech and vintage per region, demand - viable_tech_vintage = defaultdict(list) - - # start the loop over possible combos - for r, p, t, v, dem in M.processInputsByOutput: - # we aren't concerned with non-demand commodities or annual techs - if dem not in M.commodity_demand or t in M.tech_annual: - continue - # capture the (p, t, v) in case we need to act on it - viable_tech_vintage[r, p, dem].append((t, v)) - suppliers[dem].add(t) # one more recognized supplier - if len(suppliers[dem]) > 1: - # We need to act on (build) for this region-demand, put in a placeholder - anchor_season_tod[r, p, dem] = None - - # Find the first timestep of the year where the demand is appreciably sized: - # appreciable = not so small that we get into numerical instability when applying small multipliers - appreciable_size = 0.0001 - - for r, p, dem in anchor_season_tod: - found_flag = False - s0, d0 = None, None - for s0, d0 in ((ss, dd) for ss in M.TimeSeason[p] for dd in M.time_of_day): - if (r, p, s0, d0, dem) in M.DemandSpecificDistribution: - if value(M.DemandSpecificDistribution[r, p, s0, d0, dem]) >= appreciable_size: - found_flag = True - break # we have one with some value associated - found = 'found' if found_flag else 'not found' - # set it. If nothing was found the first indices should work just fine... - anchor_season_tod[r, p, dem] = (s0, d0) - logger.debug( - 'Using season/tod: %s, %s for commodity %s in region %s which was %s in DSD ' - 'to set DemandActivity baseline', - s0, - d0, - dem, - r, - found, - ) - - # Start yielding the constraint indices - for r, p, dem in anchor_season_tod: - s0, d0 = anchor_season_tod[r, p, dem] - for t, v in viable_tech_vintage[r, p, dem]: - for s in M.TimeSeason[p]: - for d in M.time_of_day: - if s != s0 or d != d0: - yield r, p, s, d, t, v, dem, s0, d0 +# def DemandActivityConstraintIndices(M: 'TemoaModel'): +# """\ +# This function returns a set of sparse indices that are used in the +# DemandActivity constraint. It returns a tuple of the form: +# (p,s,d,t,v,dem,first_s,first_d) where "dem" is a demand commodity, and "first_s" +# and "first_d" are the reference season and time-of-day, respectively used to +# ensure demand activity remains consistent across time slices. +# """ + +# # needed data structures... +# # the count of techs that supply a commodity +# suppliers = defaultdict(set) +# # (region, demand): (season, tod) # the goal of the exercise! +# anchor_season_tod = {} +# # (region, demand): (period, tech, vintage) # the viable tech and vintage per region, demand +# viable_tech_vintage = defaultdict(list) + +# # start the loop over possible combos +# for r, p, t, v, dem in M.processInputsByOutput: +# # we aren't concerned with non-demand commodities or annual techs +# if dem not in M.commodity_demand or t in M.tech_annual: +# continue +# # capture the (p, t, v) in case we need to act on it +# viable_tech_vintage[r, p, dem].append((t, v)) +# suppliers[dem].add(t) # one more recognized supplier +# if len(suppliers[dem]) > 1: +# # We need to act on (build) for this region-demand, put in a placeholder +# anchor_season_tod[r, p, dem] = None + +# # Find the first timestep of the year where the demand is appreciably sized: +# # appreciable = not so small that we get into numerical instability when applying small multipliers +# appreciable_size = 0.0001 + +# for r, p, dem in anchor_season_tod: +# found_flag = False +# s0, d0 = None, None +# for s0, d0 in ((ss, dd) for ss in M.TimeSeason[p] for dd in M.time_of_day): +# if (r, p, s0, d0, dem) in M.DemandSpecificDistribution: +# if value(M.DemandSpecificDistribution[r, p, s0, d0, dem]) >= appreciable_size: +# found_flag = True +# break # we have one with some value associated +# found = 'found' if found_flag else 'not found' +# # set it. If nothing was found the first indices should work just fine... +# anchor_season_tod[r, p, dem] = (s0, d0) +# logger.debug( +# 'Using season/tod: %s, %s for commodity %s in region %s which was %s in DSD ' +# 'to set DemandActivity baseline', +# s0, +# d0, +# dem, +# r, +# found, +# ) + +# # Start yielding the constraint indices +# for r, p, dem in anchor_season_tod: +# s0, d0 = anchor_season_tod[r, p, dem] +# for t, v in viable_tech_vintage[r, p, dem]: +# for s in M.TimeSeason[p]: +# for d in M.time_of_day: +# if s != s0 or d != d0: +# yield r, p, s, d, t, v, dem, s0, d0 def DemandConstraintIndices(M: 'TemoaModel'): indices = set( - (r, p, s, d, dem) + (r, p, dem) for r, p, dem in M.Demand.sparse_iterkeys() - for s in M.TimeSeason[p] - for d in M.time_of_day ) return indices diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 9d605c3d2..f35e47744 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -42,6 +42,7 @@ region_group_check, validate_Efficiency, validate_tech_sets, + validate_demand_tech_sets, no_slash_or_pipe, validate_ReserveMargin, ) @@ -380,6 +381,7 @@ def __init__(M, *args, **kwargs): # perform the sparse matrix of indexing for the parameters, variables, and # equations below. M.Create_SparseDicts = BuildAction(rule=CreateSparseDicts) + M.validate_demand_techs = BuildAction(rule=validate_demand_tech_sets) M.initialize_Demands = BuildAction(rule=CreateDemands) M.CapacityFactor_rpsdt = Set(dimen=5, initialize=CapacityFactorTechIndices) @@ -642,8 +644,8 @@ def __init__(M, *args, **kwargs): # Declare core model constraints that ensure proper system functioning # In driving order, starting with the need to meet end-use demands - M.DemandConstraint_rpsdc = Set(dimen=5, initialize=DemandConstraintIndices) - M.DemandConstraint = Constraint(M.DemandConstraint_rpsdc, rule=Demand_Constraint) + M.DemandConstraint_rpc = Set(dimen=3, initialize=DemandConstraintIndices) + M.DemandConstraint = Constraint(M.DemandConstraint_rpc, rule=Demand_Constraint) # devnote: testing a workaround # M.DemandActivityConstraint_rpsdtv_dem_s0d0 = Set( diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index db62ead1b..1a0bcefa3 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -941,7 +941,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): # --------------------------------------------------------------- -def Demand_Constraint(M: 'TemoaModel', r, p, s, d, dem): +def Demand_Constraint(M: 'TemoaModel', r, p, dem): r""" The Demand constraint drives the model. This constraint ensures that supply at @@ -979,7 +979,7 @@ def Demand_Constraint(M: 'TemoaModel', r, p, s, d, dem): for S_i in M.processInputsByOutput[r, p, S_t, S_v, dem] ) - DemandConstraintErrorCheck(supply_annual, r, p, s, d, dem) + DemandConstraintErrorCheck(supply_annual, r, p, dem) expr = ( supply_annual == value(M.Demand[r, p, dem]) @@ -988,49 +988,50 @@ def Demand_Constraint(M: 'TemoaModel', r, p, s, d, dem): return expr -def DemandActivity_Constraint(M: 'TemoaModel', r, p, s, d, t, v, dem, s_0, d_0): - r""" +# devnote: no longer needed +# def DemandActivity_Constraint(M: 'TemoaModel', r, p, s, d, t, v, dem, s_0, d_0): +# r""" - For end-use demands, it is unreasonable to let the model arbitrarily shift the - use of demand technologies across time slices. For instance, if household A buys - a natural gas furnace while household B buys an electric furnace, then both units - should be used throughout the year. Without this constraint, the model might choose - to only use the electric furnace during the day, and the natural gas furnace during the - night. +# For end-use demands, it is unreasonable to let the model arbitrarily shift the +# use of demand technologies across time slices. For instance, if household A buys +# a natural gas furnace while household B buys an electric furnace, then both units +# should be used throughout the year. Without this constraint, the model might choose +# to only use the electric furnace during the day, and the natural gas furnace during the +# night. - This constraint ensures that the ratio of a process activity to demand is - constant for all time slices. Note that if a demand is not specified in a given - time slice, or is zero, then this constraint will not be considered for that - slice and demand. This is transparently handled by the :math:`\Theta` superset. +# This constraint ensures that the ratio of a process activity to demand is +# constant for all time slices. Note that if a demand is not specified in a given +# time slice, or is zero, then this constraint will not be considered for that +# slice and demand. This is transparently handled by the :math:`\Theta` superset. - .. math:: - :label: DemandActivity +# .. math:: +# :label: DemandActivity - DEM_{r, p, s, d, dem} \cdot \sum_{I} \textbf{FO}_{r, p, s_0, d_0, i, t \not \in T^{a}, v, dem} - = - DEM_{r, p, s_0, d_0, dem} \cdot \sum_{I} \textbf{FO}_{r, p, s, d, i, t \not \in T^{a}, v, dem} +# DEM_{r, p, s, d, dem} \cdot \sum_{I} \textbf{FO}_{r, p, s_0, d_0, i, t \not \in T^{a}, v, dem} +# = +# DEM_{r, p, s_0, d_0, dem} \cdot \sum_{I} \textbf{FO}_{r, p, s, d, i, t \not \in T^{a}, v, dem} - \\ - \forall \{r, p, s, d, t, v, dem, s_0, d_0\} \in \Theta_{\text{DemandActivity}} +# \\ +# \forall \{r, p, s, d, t, v, dem, s_0, d_0\} \in \Theta_{\text{DemandActivity}} - Note that this constraint is only applied to the demand commodities with diurnal - variations, and therefore the equation above only includes :math:`\textbf{FO}` - and not :math:`\textbf{FOA}` - """ +# Note that this constraint is only applied to the demand commodities with diurnal +# variations, and therefore the equation above only includes :math:`\textbf{FO}` +# and not :math:`\textbf{FOA}` +# """ - act_a = sum( - M.V_FlowOut[r, p, s_0, d_0, S_i, t, v, dem] - for S_i in M.processInputsByOutput[r, p, t, v, dem] - ) - act_b = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, dem] for S_i in M.processInputsByOutput[r, p, t, v, dem] - ) +# act_a = sum( +# M.V_FlowOut[r, p, s_0, d_0, S_i, t, v, dem] +# for S_i in M.processInputsByOutput[r, p, t, v, dem] +# ) +# act_b = sum( +# M.V_FlowOut[r, p, s, d, S_i, t, v, dem] for S_i in M.processInputsByOutput[r, p, t, v, dem] +# ) - expr = ( - act_a * value(M.DemandSpecificDistribution[r, p, s, d, dem]) - == act_b * value(M.DemandSpecificDistribution[r, p, s_0, d_0, dem]) - ) - return expr +# expr = ( +# act_a * value(M.DemandSpecificDistribution[r, p, s, d, dem]) +# == act_b * value(M.DemandSpecificDistribution[r, p, s_0, d_0, dem]) +# ) +# return expr def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): @@ -1156,19 +1157,17 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): consumed += value(M.SegFrac[p, s, d]) * sum( M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] / get_variable_efficiency(M, r, p, s, d, c, S_t, S_v, S_o) for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t not in M.tech_storage and S_t in M.tech_annual + if S_t in M.tech_annual and S_t not in M.tech_demand for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] - if S_o not in M.commodity_demand ) - # Into demand technologies (always annual flows) + # Into demand technologies (annual flow fit to DSD profile) consumed += sum( value(M.DemandSpecificDistribution[r, p, s, d, S_o]) * M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] / get_variable_efficiency(M, r, p, s, d, c, S_t, S_v, S_o) for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t not in M.tech_storage and S_t in M.tech_annual + if S_t in M.tech_demand for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] - if S_o in M.commodity_demand ) if (r, p, c) in M.capacityConsumptionTechs: @@ -1300,7 +1299,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): consumed += sum( M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] / value(M.Efficiency[r, c, S_t, S_v, S_o]) for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t not in M.tech_storage and S_t in M.tech_annual + if S_t in M.tech_annual for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] ) @@ -2227,6 +2226,17 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): total_generation = sum( M.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] for (t, S_v) in M.processReservePeriods[r, p] + if t not in M.tech_demand + for S_i in M.processInputs[r, p, t, S_v] + for S_o in M.processOutputsByInput[r, p, t, S_v, S_i] + ) + + # Generators might serve demands directly + total_generation = sum( + value(M.DemandSpecificDistribution[r, p, s, d, S_o]) + * M.V_FlowOutAnnual[r, p, s, d, S_i, t, S_v, S_o] + for (t, S_v) in M.processReservePeriods[r, p] + if t in M.tech_demand for S_i in M.processInputs[r, p, t, S_v] for S_o in M.processOutputsByInput[r, p, t, S_v, S_i] ) @@ -3656,19 +3666,59 @@ def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): the primary region corresponds to the linked technology as well. The lifetimes of the primary and linked technologies should be specified and identical. """ + + if t in M.tech_demand: + primary_flow = sum( + M.DemandSpecificDistribution[r, p, s, d, S_o] + * M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] + * value(M.EmissionActivity[r, e, S_i, t, v, S_o]) + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + elif t in M.tech_annual: + primary_flow = sum( + M.SegFrac[p, s, d] + * M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] + * value(M.EmissionActivity[r, e, S_i, t, v, S_o]) + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + else: + primary_flow = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + * value(M.EmissionActivity[r, e, S_i, t, v, S_o]) + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + linked_t = M.LinkedTechs[r, t, e] - primary_flow = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] * value(M.EmissionActivity[r, e, S_i, t, v, S_o]) - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) + # linked_flow = sum( + # M.V_FlowOut[r, p, s, d, S_i, linked_t, v, S_o] + # for S_i in M.processInputs[r, p, linked_t, v] + # for S_o in M.processOutputsByInput[r, p, linked_t, v, S_i] + # ) - linked_flow = sum( - M.V_FlowOut[r, p, s, d, S_i, linked_t, v, S_o] - for S_i in M.processInputs[r, p, linked_t, v] - for S_o in M.processOutputsByInput[r, p, linked_t, v, S_i] - ) + if t in M.tech_demand: + linked_flow = sum( + M.DemandSpecificDistribution[r, p, s, d, S_o] + * M.V_FlowOutAnnual[r, p, S_i, linked_t, v, S_o] + for S_i in M.processInputs[r, p, linked_t, v] + for S_o in M.processOutputsByInput[r, p, linked_t, v, S_i] + ) + elif t in M.tech_annual: + linked_flow = sum( + M.SegFrac[p, s, d] + * M.V_FlowOutAnnual[r, p, S_i, linked_t, v, S_o] + for S_i in M.processInputs[r, p, linked_t, v] + for S_o in M.processOutputsByInput[r, p, linked_t, v, S_i] + ) + else: + linked_flow = sum( + M.V_FlowOut[r, p, s, d, S_i, linked_t, v, S_o] + for S_i in M.processInputs[r, p, linked_t, v] + for S_o in M.processOutputsByInput[r, p, linked_t, v, S_i] + ) return -primary_flow == linked_flow diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index 32f7efd44..a425b8cab 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -47,11 +47,13 @@ class ExpectedVals(Enum): ExpectedVals.EFF_INDEX_SIZE: 74, # increased by 2 when reworking storageinit. # increased after making annualretirement derived var - ExpectedVals.CONSTR_COUNT: 2834, + # reduced 2025/07/25 by 504 after annualising demands + ExpectedVals.CONSTR_COUNT: 2330, # reduced by 6 when reworking storageinit. # increased after making annualretirement derived var # reduced 2025/07/21 after removing existing vintage V_NewCapacity indices - ExpectedVals.VAR_COUNT: 1900, + # reduced 2025/07/25 by 420 after annualising demands + ExpectedVals.VAR_COUNT: 1480, }, 'utopia': { # reduced after reworking storageinit -> storage was less constrained @@ -63,12 +65,14 @@ class ExpectedVals(Enum): ExpectedVals.EFF_INDEX_SIZE: 64, # reduced 3/27: unlim_cap techs now employed. # increased after making annualretirement derived var - ExpectedVals.CONSTR_COUNT: 1471, + # reduced 2025/07/25 by 225 after annualising demands + ExpectedVals.CONSTR_COUNT: 1246, # reduced 3/27: unlim_cap techs now employed. # reduced by 4 in storageinit rework. # increased after making annualretirement derived var # reduced 2025/07/21 after removing existing vintage V_NewCapacity indices - ExpectedVals.VAR_COUNT: 1055, + # reduced 2025/07/25 by 200 after annualising demands + ExpectedVals.VAR_COUNT: 855, }, 'mediumville': { # added 2025/06/12 prior to addition of dynamic reserve margin @@ -77,16 +81,20 @@ class ExpectedVals(Enum): ExpectedVals.EFF_DOMAIN_SIZE: 2800, ExpectedVals.EFF_INDEX_SIZE: 18, # increased after reviving RampSeason constraints - ExpectedVals.CONSTR_COUNT: 240, - ExpectedVals.VAR_COUNT: 140, + # reduced 2025/07/25 by 24 after annualising demands + ExpectedVals.CONSTR_COUNT: 216, + # reduced 2025/07/25 by 18 after annualising demands + ExpectedVals.VAR_COUNT: 122, }, 'seasonal_storage': { # added 2025/06/16 after addition of seasonal storage ExpectedVals.OBJ_VALUE: 76661.0231, ExpectedVals.EFF_DOMAIN_SIZE: 24, ExpectedVals.EFF_INDEX_SIZE: 4, - ExpectedVals.CONSTR_COUNT: 182, - ExpectedVals.VAR_COUNT: 90, + # reduced 2025/07/25 by 7 after annualising demands + ExpectedVals.CONSTR_COUNT: 175, + # reduced 2025/07/25 by 7 after annualising demands + ExpectedVals.VAR_COUNT: 83, }, 'survival_curve': { # added 2025/06/19 after addition of survival curves diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 9742ba18d..a8282361c 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -1878,252 +1878,26 @@ "ELC" ] ], - "DemandActivityConstraint_rpsdtv_dem_s0d0": [ - [ - "A", - 2025, - "s2", - "d2", - "heater", - 2025, - "RH", - "s1", - "d1" - ], - [ - "A", - 2025, - "s1", - "d2", - "heater", - 2025, - "RH", - "s1", - "d1" - ], - [ - "A", - 2025, - "s2", - "d1", - "heater", - 2025, - "RH", - "s1", - "d1" - ], - [ - "B", - 2025, - "s2", - "d1", - "GeoHeater", - 2025, - "RH", - "s1", - "d1" - ], - [ - "B", - 2025, - "s2", - "d2", - "heater", - 2025, - "RH", - "s1", - "d1" - ], - [ - "B", - 2025, - "s2", - "d1", - "heater", - 2025, - "RH", - "s1", - "d1" - ], - [ - "A", - 2025, - "s2", - "d1", - "GeoHeater", - 2025, - "RH", - "s1", - "d1" - ], - [ - "B", - 2025, - "s1", - "d2", - "heater", - 2025, - "RH", - "s1", - "d1" - ], - [ - "A", - 2025, - "s1", - "d2", - "GeoHeater", - 2025, - "RH", - "s1", - "d1" - ], - [ - "A", - 2025, - "s2", - "d2", - "GeoHeater", - 2025, - "RH", - "s1", - "d1" - ], + "DemandConstraint_rpc": [ [ "B", 2025, - "s1", - "d2", - "GeoHeater", - 2025, - "RH", - "s1", - "d1" - ], - [ - "B", - 2025, - "s2", - "d2", - "GeoHeater", - 2025, - "RH", - "s1", - "d1" - ] - ], - "DemandConstraint_rpsdc": [ - [ - "A", - 2025, - "s1", - "d2", - "RL" - ], - [ - "B", - 2025, - "s2", - "d1", - "RL" - ], - [ - "A", - 2025, - "s1", - "d2", - "RH" - ], - [ - "B", - 2025, - "s2", - "d1", - "RH" - ], - [ - "A", - 2025, - "s1", - "d1", - "RL" - ], - [ - "A", - 2025, - "s1", - "d1", "RH" ], [ "A", 2025, - "s2", - "d2", "RH" ], [ "B", 2025, - "s1", - "d1", - "RL" - ], - [ - "B", - 2025, - "s2", - "d2", "RL" ], - [ - "B", - 2025, - "s1", - "d1", - "RH" - ], - [ - "B", - 2025, - "s2", - "d2", - "RH" - ], [ "A", 2025, - "s2", - "d2", "RL" - ], - [ - "B", - 2025, - "s1", - "d2", - "RL" - ], - [ - "B", - 2025, - "s1", - "d2", - "RH" - ], - [ - "A", - 2025, - "s2", - "d1", - "RL" - ], - [ - "A", - 2025, - "s2", - "d1", - "RH" ] ], "EmissionActivity_reitvo": [ @@ -2470,14 +2244,6 @@ ] ], "FlowVarAnnual_rpitvo": [ - [ - "A", - 2025, - "earth", - "GeoThermal", - 2025, - "GeoHyd" - ], [ "B", 2025, @@ -2485,54 +2251,18 @@ "GeoThermal", 2025, "GeoHyd" - ] - ], - "FlowVar_rpsditvo": [ - [ - "B", - 2025, - "s1", - "d1", - "GeoHyd", - "GeoHeater", - 2025, - "RH" ], [ - "A", + "B", 2025, - "s2", - "d1", "GeoHyd", "GeoHeater", 2025, "RH" ], - [ - "A-B", - 2025, - "s2", - "d1", - "FusionGasFuel", - "FGF_pipe", - 2025, - "FusionGasFuel" - ], [ "B", 2025, - "s1", - "d2", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "A", - 2025, - "s1", - "d1", "ELC", "bulbs", 2025, @@ -2541,118 +2271,22 @@ [ "A", 2025, - "s2", - "d1", "earth", - "EFL", - 2025, - "FusionGasFuel" - ], - [ - "A", - 2025, - "s2", - "d2", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "B", - 2025, - "s1", - "d1", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A-B", - 2025, - "s1", - "d2", - "FusionGasFuel", - "FGF_pipe", - 2025, - "FusionGasFuel" - ], - [ - "A", - 2025, - "s2", - "d1", - "earth", - "well", - 2025, - "HYD" - ], - [ - "A", - 2025, - "s2", - "d2", - "HYD", - "EH", + "GeoThermal", 2025, - "ELC" + "GeoHyd" ], [ "A", 2025, - "s1", - "d2", - "FusionGasFuel", - "heater", + "GeoHyd", + "GeoHeater", 2025, "RH" ], - [ - "B-A", - 2025, - "s2", - "d2", - "FusionGasFuel", - "FGF_pipe", - 2025, - "FusionGasFuel" - ], - [ - "A", - 2025, - "s2", - "d1", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s2", - "d2", - "earth", - "EFL", - 2025, - "FusionGasFuel" - ], [ "B", 2025, - "s2", - "d1", - "ELC", - "batt", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s1", - "d1", "FusionGasFuel", "heater", 2025, @@ -2661,128 +2295,46 @@ [ "A", 2025, - "s1", - "d2", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s2", - "d2", "ELC", "bulbs", 2025, "RL" ], [ - "B", + "A", 2025, - "s2", - "d1", "FusionGasFuel", "heater", 2025, "RH" - ], + ] + ], + "FlowVar_rpsditvo": [ [ - "B", + "A", 2025, - "s1", + "s2", "d2", "earth", - "well", - 2025, - "HYD" - ], - [ - "B", - 2025, - "s1", - "d1", - "earth", - "well", + "EFL", 2025, - "HYD" + "FusionGasFuel" ], [ "B", 2025, "s1", "d2", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s2", - "d1", - "earth", - "well", - 2025, - "HYD" - ], - [ - "A", - 2025, - "s2", - "d1", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "B", - 2025, - "s2", - "d1", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "A", - 2025, - "s2", - "d2", "HYD", "EF", 2025, "ELC" ], - [ - "A", - 2025, - "s1", - "d2", - "earth", - "well", - 2025, - "HYD" - ], [ "B", 2025, "s2", "d2", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s1", - "d2", "HYD", "EH", 2025, @@ -2792,7 +2344,7 @@ "A", 2025, "s2", - "d1", + "d2", "HYD", "EH", 2025, @@ -2802,66 +2354,56 @@ "B", 2025, "s2", - "d1", - "HYD", - "EF", + "d2", + "ELC", + "batt", 2025, "ELC" ], [ - "A", + "B", 2025, - "s1", - "d1", - "GeoHyd", - "GeoHeater", + "s2", + "d2", + "earth", + "well", 2025, - "RH" + "HYD" ], [ "B", 2025, - "s1", + "s2", "d1", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "A", - 2025, - "s1", - "d2", "HYD", "EF", 2025, "ELC" ], [ - "B", + "A", 2025, "s2", - "d2", - "GeoHyd", - "GeoHeater", + "d1", + "earth", + "EFL", 2025, - "RH" + "FusionGasFuel" ], [ - "B", + "A", 2025, "s1", - "d2", - "GeoHyd", - "GeoHeater", + "d1", + "HYD", + "EF", 2025, - "RH" + "ELC" ], [ "A-B", 2025, - "s2", + "s1", "d2", "FusionGasFuel", "FGF_pipe", @@ -2869,39 +2411,39 @@ "FusionGasFuel" ], [ - "A", + "B", 2025, "s2", "d2", - "FusionGasFuel", - "heater", + "HYD", + "EF", 2025, - "RH" + "ELC" ], [ "A", 2025, "s2", - "d2", - "GeoHyd", - "GeoHeater", + "d1", + "HYD", + "EF", 2025, - "RH" + "ELC" ], [ - "B", + "B-A", 2025, "s1", - "d2", - "ELC", - "batt", + "d1", + "FusionGasFuel", + "FGF_pipe", 2025, - "ELC" + "FusionGasFuel" ], [ "B", 2025, - "s2", + "s1", "d1", "HYD", "EH", @@ -2909,10 +2451,10 @@ "ELC" ], [ - "A-B", + "B-A", 2025, "s1", - "d1", + "d2", "FusionGasFuel", "FGF_pipe", 2025, @@ -2924,10 +2466,30 @@ "s1", "d1", "HYD", - "EF", + "EH", + 2025, + "ELC" + ], + [ + "B", + 2025, + "s2", + "d1", + "HYD", + "EH", 2025, "ELC" ], + [ + "B", + 2025, + "s1", + "d1", + "earth", + "well", + 2025, + "HYD" + ], [ "A", 2025, @@ -2942,7 +2504,7 @@ "B-A", 2025, "s2", - "d1", + "d2", "FusionGasFuel", "FGF_pipe", 2025, @@ -2953,6 +2515,16 @@ 2025, "s1", "d2", + "earth", + "EFL", + 2025, + "FusionGasFuel" + ], + [ + "A", + 2025, + "s2", + "d1", "HYD", "EH", 2025, @@ -2962,6 +2534,26 @@ "B", 2025, "s2", + "d1", + "ELC", + "batt", + 2025, + "ELC" + ], + [ + "B", + 2025, + "s2", + "d1", + "earth", + "well", + 2025, + "HYD" + ], + [ + "A", + 2025, + "s1", "d2", "HYD", "EF", @@ -2969,37 +2561,37 @@ "ELC" ], [ - "A", + "B-A", 2025, "s2", "d1", "FusionGasFuel", - "heater", + "FGF_pipe", 2025, - "RH" + "FusionGasFuel" ], [ - "A", + "A-B", 2025, "s1", "d1", - "earth", - "well", + "FusionGasFuel", + "FGF_pipe", 2025, - "HYD" + "FusionGasFuel" ], [ "A", 2025, - "s1", - "d2", - "ELC", - "bulbs", + "s2", + "d1", + "earth", + "well", 2025, - "RL" + "HYD" ], [ - "B", + "A", 2025, "s2", "d2", @@ -3012,56 +2604,66 @@ "B", 2025, "s1", - "d2", + "d1", "HYD", "EF", 2025, "ELC" ], [ - "B", + "A-B", 2025, "s2", - "d2", - "ELC", - "batt", + "d1", + "FusionGasFuel", + "FGF_pipe", 2025, - "ELC" + "FusionGasFuel" ], [ - "B-A", + "B", 2025, "s1", "d2", + "earth", + "well", + 2025, + "HYD" + ], + [ + "A-B", + 2025, + "s2", + "d2", "FusionGasFuel", "FGF_pipe", 2025, "FusionGasFuel" ], [ - "A", + "B", 2025, "s1", "d2", - "earth", - "EFL", + "HYD", + "EH", 2025, - "FusionGasFuel" + "ELC" ], [ - "B", + "A", 2025, - "s2", - "d1", - "ELC", - "bulbs", + "s1", + "d2", + "HYD", + "EH", 2025, - "RL" + "ELC" ], [ "A", 2025, - "s2", + "s1", "d2", "earth", "well", @@ -3069,10 +2671,10 @@ "HYD" ], [ - "B", + "A", 2025, - "s1", - "d1", + "s2", + "d2", "HYD", "EF", 2025, @@ -3082,39 +2684,19 @@ "B", 2025, "s1", - "d1", + "d2", "ELC", "batt", 2025, "ELC" ], - [ - "B-A", - 2025, - "s1", - "d1", - "FusionGasFuel", - "FGF_pipe", - 2025, - "FusionGasFuel" - ], [ "B", 2025, "s1", "d1", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s2", - "d2", - "HYD", - "EH", + "ELC", + "batt", 2025, "ELC" ], @@ -3123,10 +2705,10 @@ 2025, "s1", "d1", - "HYD", - "EH", + "earth", + "well", 2025, - "ELC" + "HYD" ] ], "LifetimeProcess_rtv": [ @@ -4276,8 +3858,16 @@ "batt" ], "tech_annual": [ + "bulbs", + "heater", + "GeoHeater", "GeoThermal" ], + "tech_demand": [ + "bulbs", + "heater", + "GeoHeater" + ], "tech_baseload": [ "EH" ], diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index e629674b4..ce3d11482 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -19722,9341 +19722,112 @@ "GSL" ] ], - "DemandActivityConstraint_rpsdtv_dem_s0d0": [ + "DemandConstraint_rpc": [ [ "R1", - 2020, - "fall", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "fall", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "spring", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "fall", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "winter", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "winter", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "winter", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "fall", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "summer", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "summer", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "winter", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "spring", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "fall", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "spring", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "winter", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "spring", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "summer", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "spring", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "spring", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "winter", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "summer", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "summer", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "summer", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "fall", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "summer", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "summer", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "winter", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "spring", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "summer", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "winter", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "winter", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "summer", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "spring", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "spring", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "summer", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "winter", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "fall", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "summer", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "fall", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "winter", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "winter", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "fall", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "spring", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "fall", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "fall", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "summer", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "spring", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "summer", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "winter", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "spring", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "spring", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "fall", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "winter", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "spring", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "spring", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "winter", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "fall", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "winter", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "fall", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "fall", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "summer", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "fall", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "summer", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "summer", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "winter", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "summer", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "winter", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "spring", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_EV", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_GSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "fall", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "spring", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "summer", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "fall", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "spring", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "night", - "R_EH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "summer", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_DSL", - 2030, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "night", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "summer", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2020, - "fall", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "day", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "winter", - "night", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2020, - "winter", - "night", - "R_EH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "fall", - "day", - "R_EH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2020, - "winter", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_GSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_EV", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_DSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2030, - "summer", - "day", - "R_NGH", - 2030, - "RH", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "summer", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_EV", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2030, - "winter", - "day", - "R_NGH", - 2025, - "RH", - "spring", - "day" - ], - [ - "R2", - 2030, - "winter", - "night", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "winter", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_GSL", - 2025, - "VMT", - "spring", - "day" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_DSL", - 2020, - "VMT", - "spring", - "day" - ], - [ - "R2", - 2020, - "fall", - "day", - "R_NGH", - 2020, - "RH", - "spring", - "day" - ] - ], - "DemandConstraint_rpsdc": [ - [ - "R1", - 2030, - "spring", - "day", - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "RH" - ], - [ - "R1", - 2025, - "winter", - "night", - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "RH" - ], - [ - "R1", - 2030, - "fall", - "day", - "RH" - ], - [ - "R2", - 2030, - "summer", - "night", - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "RH" - ], - [ - "R2", - 2025, - "summer", - "night", - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "RH" - ], - [ - "R1", - 2025, - "winter", - "day", - "VMT" - ], - [ - "R2", - 2025, - "spring", - "day", - "RH" - ], - [ - "R2", - 2030, - "summer", - "day", - "VMT" - ], - [ - "R2", - 2020, - "winter", - "day", - "RH" - ], - [ - "R1", - 2030, - "winter", - "night", - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "VMT" - ], - [ - "R1", - 2020, - "summer", - "night", - "RH" - ], - [ - "R1", - 2030, - "winter", - "day", - "VMT" - ], - [ - "R2", - 2025, - "summer", - "day", - "RH" - ], - [ - "R1", - 2020, - "spring", - "day", - "VMT" - ], - [ - "R2", - 2030, - "winter", - "night", - "RH" - ], - [ - "R1", - 2020, - "fall", - "day", - "RH" - ], - [ - "R1", - 2025, - "spring", - "night", - "RH" - ], - [ - "R2", - 2030, - "winter", - "day", - "RH" - ], - [ - "R2", - 2025, - "winter", - "day", - "RH" - ], - [ - "R1", - 2025, - "spring", - "day", - "RH" - ], - [ - "R1", - 2025, - "summer", - "night", - "RH" - ], - [ - "R1", - 2020, - "winter", - "night", - "RH" - ], - [ - "R1", - 2025, - "fall", - "night", - "VMT" - ], - [ - "R2", - 2020, - "spring", - "night", - "RH" - ], - [ - "R1", - 2020, - "winter", - "day", - "RH" - ], - [ - "R1", - 2025, - "fall", - "day", - "VMT" - ], - [ - "R2", - 2020, - "summer", - "day", - "VMT" - ], - [ - "R2", - 2020, - "spring", - "day", - "RH" - ], - [ - "R2", - 2020, - "fall", - "night", - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "RH" - ], - [ - "R2", - 2020, - "fall", - "day", - "VMT" - ], - [ - "R1", - 2025, - "winter", - "night", - "RH" - ], - [ - "R1", - 2030, - "fall", - "night", - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "RH" - ], - [ - "R2", - 2025, - "spring", - "night", - "VMT" - ], - [ - "R1", - 2025, - "winter", - "day", - "RH" - ], - [ - "R1", - 2030, - "fall", - "day", - "VMT" - ], - [ - "R2", - 2025, - "summer", - "night", - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "VMT" - ], - [ - "R2", - 2025, - "spring", - "day", - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "RH" - ], - [ - "R2", - 2020, - "winter", - "night", - "VMT" - ], - [ - "R2", - 2025, - "fall", - "day", - "RH" - ], - [ - "R2", - 2020, - "winter", - "day", - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "RH" - ], - [ - "R1", - 2020, - "spring", - "night", - "RH" - ], - [ - "R1", - 2020, - "summer", - "day", - "VMT" - ], - [ - "R1", - 2020, - "spring", - "day", - "RH" - ], - [ - "R2", - 2020, - "summer", - "night", - "VMT" - ], - [ - "R1", - 2020, - "fall", - "night", - "VMT" - ], - [ - "R2", - 2025, - "winter", - "night", - "VMT" - ], - [ - "R1", - 2020, - "fall", - "day", - "VMT" - ], - [ - "R1", - 2025, - "spring", - "night", - "VMT" - ], - [ - "R2", - 2030, - "winter", - "day", - "VMT" - ], - [ - "R2", - 2025, - "winter", - "day", - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "RH" - ], - [ - "R1", - 2025, - "fall", - "night", - "RH" - ], - [ - "R1", - 2020, - "winter", - "night", - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "VMT" - ], - [ - "R2", - 2020, - "spring", - "night", - "VMT" - ], - [ - "R2", - 2020, - "summer", - "day", - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "VMT" - ], - [ - "R2", - 2020, - "fall", - "night", - "RH" - ], - [ - "R2", - 2030, - "summer", - "day", - "RH" - ], - [ - "R1", - 2030, - "fall", - "night", - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "RH" - ], - [ - "R2", - 2025, - "spring", - "night", - "RH" - ], - [ - "R1", - 2020, - "summer", - "night", - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "RH" - ], - [ - "R2", - 2030, - "spring", - "day", - "RH" - ], - [ - "R2", - 2025, - "summer", - "day", - "VMT" - ], - [ - "R2", - 2020, - "winter", - "night", - "RH" - ], - [ - "R2", - 2025, - "fall", - "night", - "VMT" - ], - [ - "R2", - 2030, - "winter", - "night", - "VMT" - ], - [ - "R2", - 2025, - "fall", - "day", - "VMT" - ], - [ - "R1", - 2020, - "spring", - "night", - "VMT" - ], - [ - "R1", - 2025, - "spring", - "day", - "VMT" - ], - [ - "R1", - 2020, - "summer", - "day", - "RH" - ], - [ - "R1", - 2025, - "summer", - "night", - "VMT" - ], - [ - "R2", - 2020, - "summer", - "night", - "RH" - ], - [ - "R1", - 2020, - "fall", - "night", - "RH" - ], - [ - "R1", - 2025, - "fall", - "day", - "RH" - ], - [ - "R2", - 2025, - "winter", - "night", - "RH" - ], - [ - "R1", - 2020, - "winter", - "day", - "VMT" - ], - [ - "R2", - 2020, - "spring", - "day", - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "VMT" - ], - [ - "R2", - 2020, - "fall", - "day", - "RH" - ] - ], - "EmissionActivity_reitvo": [ - [ - "R1", - "CO2", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - "CO2", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - "CO2", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - "CO2", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - "CO2", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - "CO2", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - "CO2", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - "CO2", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - "CO2", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - "CO2", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - "CO2", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - "CO2", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - "CO2", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - "CO2", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - "CO2", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - "CO2", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - "CO2", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - "CO2", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - "CO2", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - "CO2", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - "CO2", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - "CO2", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - "CO2", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - "CO2", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - "CO2", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - "CO2", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - "CO2", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - "CO2", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - "CO2", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R2", - "CO2", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - "CO2", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - "CO2", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - "CO2", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - "CO2", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - "CO2", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - "CO2", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - "CO2", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R1", - "CO2", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - "CO2", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R2", - "CO2", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - "CO2", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - "CO2", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - "CO2", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - "CO2", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - "CO2", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - "CO2", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - "CO2", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - "CO2", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R2", - "CO2", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - "CO2", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - "CO2", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - "CO2", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - "CO2", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - "CO2", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - "CO2", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - "CO2", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - "CO2", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - "CO2", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - "CO2", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - "CO2", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - "CO2", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - "CO2", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - "CO2", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R2", - "CO2", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - "CO2", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - "CO2", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - "CO2", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - "CO2", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - "CO2", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - "CO2", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - "CO2", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - "CO2", - "ELC", - "R_EH", - 2020, - "RH" - ] - ], - "FlexVarAnnual_rpitvo": [], - "FlexVar_rpsditvo": [], - "FlowInStorage_rpsditvo": [ - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ] - ], - "FlowVarAnnual_rpitvo": [], - "FlowVar_rpsditvo": [ - [ - "R1", - 2030, - "winter", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2020, - "spring", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2025, - "fall", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "winter", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "fall", - "night", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2020, - "winter", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2020, - "winter", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2030, - "summer", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "fall", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "spring", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "spring", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "winter", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2-R1", - 2025, - "fall", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2030, - "summer", - "night", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2025, - "fall", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2025, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "spring", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "fall", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "winter", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2025, - "fall", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2025, - "winter", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2025, - "summer", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "spring", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "fall", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "winter", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "spring", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "summer", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "night", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "spring", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2025, - "spring", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "summer", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2030, - "fall", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2030, - "fall", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2025, - "fall", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "spring", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "winter", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2-R1", - 2030, - "summer", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "fall", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "winter", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2020, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2025, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2-R1", - 2020, - "summer", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R1", - 2025, - "spring", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2-R1", - 2025, - "summer", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "fall", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "winter", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2030, - "spring", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2025, - "summer", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "spring", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2020, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "winter", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "winter", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2030, - "spring", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "winter", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2-R1", - 2025, - "spring", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "spring", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2025, - "winter", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2030, - "spring", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2025, - "fall", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2025, - "winter", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "fall", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "summer", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "fall", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "fall", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "summer", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "summer", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "fall", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2025, - "spring", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2020, - "summer", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2025, - "winter", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2030, - "spring", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2030, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "winter", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "fall", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "summer", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2030, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "summer", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2030, - "winter", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2020, - "spring", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "spring", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2030, - "spring", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "spring", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "fall", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "winter", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "summer", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2025, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "fall", - "day", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2020, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "fall", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2025, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "NG", - "R_NGH", 2030, "RH" ], - [ - "R2", - 2020, - "summer", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "spring", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "winter", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], [ "R1", - 2030, - "winter", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2-R1", 2025, - "winter", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "NG", - "R_NGH", - 2030, "RH" ], [ "R1", - 2025, - "summer", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2030, - "summer", - "day", - "E10", - "T_GSL", 2030, "VMT" ], - [ - "R2", - 2030, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], [ "R1", - 2030, - "summer", - "night", - "URN", - "E_NUCLEAR", 2025, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "E10", - "T_GSL", - 2030, "VMT" ], - [ - "R1", - 2030, - "summer", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], [ "R2", - 2030, - "winter", - "day", - "ethos", - "S_IMPNG", 2020, - "NG" + "RH" ], [ - "R2-R1", + "R1", 2020, - "fall", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" + "VMT" ], [ "R2", - 2020, - "summer", - "night", - "ELC", - "R_EH", - 2020, + 2030, "RH" ], [ - "R2-R1", + "R2", + 2025, + "RH" + ], + [ + "R2", 2020, - "fall", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" + "VMT" ], [ "R2", 2025, - "fall", - "day", - "DSL", - "T_DSL", - 2020, "VMT" ], [ - "R1", + "R2", 2030, - "winter", - "night", + "VMT" + ], + [ + "R1", + 2020, + "RH" + ] + ], + "EmissionActivity_reitvo": [ + [ + "R1", + "CO2", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + "CO2", "SOL", "E_SOLPV", - 2030, + 2020, "ELC" ], + [ + "R2", + "CO2", + "NG", + "R_NGH", + 2030, + "RH" + ], [ "R1", + "CO2", + "ethos", + "S_IMPOIL", 2020, - "spring", - "day", + "OIL" + ], + [ + "R2", + "CO2", "NG", "E_NGCC", - 2020, + 2025, "ELC" ], [ - "R2", - 2020, - "winter", - "day", + "R1", + "CO2", "URN", "E_NUCLEAR", 2020, @@ -29064,59 +19835,63 @@ ], [ "R2", + "CO2", + "OIL", + "S_OILREF", 2020, - "fall", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" + "DSL" ], [ "R1", - 2030, - "fall", - "day", - "ELC", - "R_EH", + "CO2", + "ETH", + "T_BLND", 2020, - "RH" + "E10" ], [ "R2", - 2020, - "summer", - "day", - "NG", - "E_NGCC", - 2020, + "CO2", + "ELC", + "E_BATT", + 2030, "ELC" ], [ "R2", + "CO2", + "OIL", + "S_OILREF", 2020, - "spring", - "night", - "GSL", - "T_BLND", + "GSL" + ], + [ + "R2", + "CO2", + "NG", + "E_NGCC", 2020, - "E10" + "ELC" ], [ "R1", - 2030, - "spring", - "day", - "GSL", - "T_BLND", + "CO2", + "NG", + "E_NGCC", 2020, - "E10" + "ELC" ], [ "R2", + "CO2", + "ELC", + "T_EV", 2030, - "summer", - "day", + "VMT" + ], + [ + "R2", + "CO2", "ethos", "S_IMPURN", 2020, @@ -29124,99 +19899,87 @@ ], [ "R1", - 2025, - "summer", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" + "CO2", + "ELC", + "E_BATT", + 2030, + "ELC" ], [ - "R2", + "R1", + "CO2", + "NG", + "R_NGH", 2025, - "spring", - "night", - "GSL", - "T_BLND", - 2020, - "E10" + "RH" ], [ "R2", - 2030, - "summer", - "night", - "OIL", - "S_OILREF", + "CO2", + "DSL", + "T_DSL", 2020, - "GSL" + "VMT" ], [ "R1", + "CO2", + "ELC", + "T_EV", 2030, - "winter", - "day", - "E10", - "T_GSL", - 2020, "VMT" ], [ - "R2", - 2030, - "fall", - "night", + "R1", + "CO2", "DSL", "T_DSL", - 2020, + 2030, "VMT" ], [ "R2", - 2030, - "fall", - "night", + "CO2", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + "CO2", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", + "CO2", "NG", "R_NGH", 2025, "RH" ], - [ - "R1", - 2025, - "winter", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], [ "R2", - 2030, - "fall", - "day", + "CO2", "E10", "T_GSL", - 2020, + 2030, "VMT" ], [ - "R2", - 2020, - "spring", - "day", - "OIL", - "S_OILREF", + "R1", + "CO2", + "GSL", + "T_BLND", 2020, - "GSL" + "E10" ], [ - "R2", - 2030, - "fall", - "night", + "R1", + "CO2", "URN", "E_NUCLEAR", 2015, @@ -29224,209 +19987,143 @@ ], [ "R2", - 2020, - "summer", - "night", - "ELC", - "T_EV", - 2020, - "VMT" + "CO2", + "SOL", + "E_SOLPV", + 2030, + "ELC" ], [ "R1", + "CO2", + "E10", + "T_GSL", 2030, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" + "VMT" ], [ "R1", - 2025, - "spring", - "night", - "ELC", - "R_EH", - 2025, - "RH" + "CO2", + "URN", + "E_NUCLEAR", + 2030, + "ELC" ], [ "R1", - 2030, - "fall", - "day", + "CO2", "SOL", "E_SOLPV", - 2025, + 2030, "ELC" ], [ - "R1", - 2020, - "spring", - "day", + "R2", + "CO2", "ELC", - "R_EH", - 2020, - "RH" + "E_BATT", + 2025, + "ELC" ], [ "R2", + "CO2", + "NG", + "R_NGH", 2020, - "summer", - "night", - "GSL", - "T_BLND", - 2020, - "E10" + "RH" ], [ "R2", - 2020, - "fall", - "night", + "CO2", "ELC", "T_EV", - 2020, + 2025, "VMT" ], [ - "R2", - 2030, - "fall", - "night", - "SOL", - "E_SOLPV", + "R1", + "CO2", + "ELC", + "E_BATT", 2025, "ELC" ], [ "R1", - 2030, - "fall", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "fall", - "night", + "CO2", "E10", "T_GSL", - 2020, + 2025, "VMT" ], [ "R1", - 2030, - "fall", - "day", - "E10", - "T_GSL", + "CO2", + "NG", + "R_NGH", 2020, + "RH" + ], + [ + "R1", + "CO2", + "ELC", + "T_EV", + 2025, "VMT" ], [ "R1", - 2030, - "winter", - "day", + "CO2", "ELC", - "E_BATT", - 2020, - "ELC" + "R_EH", + 2030, + "RH" ], [ - "R2", + "R1", + "CO2", + "DSL", + "T_DSL", 2025, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" + "VMT" ], [ "R2", - 2020, - "winter", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2020, - "winter", - "day", + "CO2", "URN", "E_NUCLEAR", - 2020, + 2030, "ELC" ], [ - "R1", - 2030, - "winter", - "day", + "R2", + "CO2", "DSL", "T_DSL", 2030, "VMT" ], [ - "R1", - 2025, - "summer", - "night", - "ELC", - "E_BATT", + "R2", + "CO2", + "E10", + "T_GSL", 2025, - "ELC" + "VMT" ], [ - "R1", + "R2", + "CO2", + "ELC", + "R_EH", 2030, - "fall", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2025, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" + "RH" ], [ "R2", - 2025, - "fall", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "day", + "CO2", "SOL", "E_SOLPV", 2025, @@ -29434,89 +20131,55 @@ ], [ "R2", - 2030, - "spring", - "night", - "NG", - "R_NGH", - 2030, - "RH" + "CO2", + "ethos", + "S_IMPNG", + 2020, + "NG" ], [ "R1", - 2030, - "summer", - "night", + "CO2", "ELC", - "E_BATT", - 2025, - "ELC" + "T_EV", + 2020, + "VMT" ], [ "R1", - 2030, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "day", + "CO2", "URN", "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", 2025, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2015, "ELC" ], [ "R1", - 2025, - "spring", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" + "CO2", + "SOL", + "E_SOLPV", + 2025, + "ELC" ], [ "R1", - 2025, - "winter", - "day", + "CO2", "NG", - "R_NGH", - 2025, - "RH" + "E_NGCC", + 2030, + "ELC" ], [ - "R1", - 2020, - "winter", - "night", - "URN", - "E_NUCLEAR", + "R2", + "CO2", + "ELC", + "E_BATT", 2020, "ELC" ], [ "R2", - 2030, - "spring", - "night", + "CO2", "ethos", "S_IMPOIL", 2020, @@ -29524,129 +20187,111 @@ ], [ "R2", - 2025, - "spring", - "day", - "URN", - "E_NUCLEAR", + "CO2", + "ELC", + "T_EV", 2020, - "ELC" + "VMT" ], [ "R1", - 2030, - "summer", - "night", - "ethos", - "S_IMPOIL", + "CO2", + "OIL", + "S_OILREF", 2020, - "OIL" + "DSL" ], [ - "R2", + "R1", + "CO2", + "ELC", + "E_BATT", 2020, - "winter", - "day", + "ELC" + ], + [ + "R2", + "CO2", "ELC", "R_EH", - 2020, + 2025, "RH" ], [ - "R2", - 2030, - "winter", - "night", - "ETH", - "T_BLND", + "R1", + "CO2", + "E10", + "T_GSL", 2020, - "E10" + "VMT" ], [ "R1", - 2030, - "spring", - "night", - "ethos", - "S_IMPNG", + "CO2", + "OIL", + "S_OILREF", 2020, - "NG" + "GSL" ], [ - "R1-R2", - 2030, - "summer", - "day", - "ELC", - "E_TRANS", - 2015, + "R2", + "CO2", + "URN", + "E_NUCLEAR", + 2025, "ELC" ], [ "R1", - 2025, - "spring", - "night", + "CO2", "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", + "R_EH", 2025, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" + "RH" ], [ "R1", - 2020, - "spring", - "day", + "CO2", "DSL", "T_DSL", 2020, "VMT" ], [ - "R1-R2", + "R1", + "CO2", + "NG", + "R_NGH", 2030, - "winter", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" + "RH" ], [ - "R1", + "R2", + "CO2", + "DSL", + "T_DSL", 2025, - "spring", - "night", - "ETH", + "VMT" + ], + [ + "R2", + "CO2", + "GSL", "T_BLND", 2020, "E10" ], [ "R2", - 2025, - "summer", - "day", - "ELC", - "T_EV", - 2025, - "VMT" + "CO2", + "NG", + "E_NGCC", + 2030, + "ELC" ], [ - "R1", - 2030, - "winter", - "day", + "R2", + "CO2", "ethos", "S_IMPETH", 2020, @@ -29654,341 +20299,249 @@ ], [ "R2", - 2030, - "spring", - "day", - "ELC", - "R_EH", + "CO2", + "E10", + "T_GSL", 2020, - "RH" - ], - [ - "R2-R1", - 2025, - "spring", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" + "VMT" ], [ "R1", - 2030, - "spring", - "day", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "T_EV", - 2030, - "VMT" + "CO2", + "ethos", + "S_IMPETH", + 2020, + "ETH" ], [ - "R2", - 2030, - "winter", - "night", - "E10", - "T_GSL", - 2030, - "VMT" + "R1", + "CO2", + "ethos", + "S_IMPURN", + 2020, + "URN" ], [ - "R1-R2", + "R1", + "CO2", + "SOL", + "E_SOLPV", 2020, - "winter", - "night", - "ELC", - "E_TRANS", - 2015, "ELC" ], [ "R1", - 2030, - "summer", - "day", - "ELC", - "T_EV", + "CO2", + "NG", + "E_NGCC", 2025, - "VMT" + "ELC" ], [ - "R1", + "R2", + "CO2", + "ELC", + "R_EH", 2020, - "summer", - "day", - "GSL", - "T_BLND", + "RH" + ], + [ + "R2", + "CO2", + "URN", + "E_NUCLEAR", 2020, - "E10" + "ELC" ], [ "R1", - 2025, - "summer", - "night", + "CO2", "ELC", "R_EH", 2020, "RH" - ], - [ - "R2", - 2030, - "winter", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], + ] + ], + "FlexVarAnnual_rpitvo": [], + "FlexVar_rpsditvo": [], + "FlowInStorage_rpsditvo": [ [ "R2", 2030, - "spring", - "day", + "summer", + "night", "ELC", "E_BATT", 2025, "ELC" ], [ - "R2", - 2030, - "summer", + "R1", + 2025, + "fall", "day", - "E10", - "T_GSL", - 2030, - "VMT" + "ELC", + "E_BATT", + 2020, + "ELC" ], [ "R1", - 2030, - "spring", + 2025, + "summer", "night", - "OIL", - "S_OILREF", + "ELC", + "E_BATT", 2020, - "GSL" + "ELC" ], [ "R1", - 2020, - "summer", + 2030, + "spring", "day", - "ETH", - "T_BLND", + "ELC", + "E_BATT", 2020, - "E10" + "ELC" ], [ "R2", 2030, - "spring", + "summer", "day", - "NG", - "E_NGCC", - 2020, + "ELC", + "E_BATT", + 2025, "ELC" ], [ - "R1", + "R2", 2020, - "summer", + "winter", "night", "ELC", - "R_EH", + "E_BATT", 2020, - "RH" + "ELC" ], [ "R1", - 2030, - "fall", - "night", - "ELC", - "T_EV", 2025, - "VMT" - ], - [ - "R1", - 2030, "spring", - "day", + "night", "ELC", - "T_EV", - 2030, - "VMT" + "E_BATT", + 2020, + "ELC" ], [ - "R2", + "R1", 2030, - "fall", + "summer", "night", - "ethos", - "S_IMPOIL", + "ELC", + "E_BATT", 2020, - "OIL" + "ELC" ], [ "R2", 2025, - "summer", + "fall", "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "spring", - "day", - "URN", - "E_NUCLEAR", + "ELC", + "E_BATT", 2025, "ELC" ], [ - "R1", + "R2", 2025, "spring", "night", - "OIL", - "S_OILREF", - 2020, - "GSL" + "ELC", + "E_BATT", + 2025, + "ELC" ], [ "R2", 2030, - "summer", + "fall", "night", - "ethos", - "S_IMPETH", + "ELC", + "E_BATT", 2020, - "ETH" + "ELC" ], [ "R2", 2030, "fall", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "spring", - "night", - "NG", - "E_NGCC", - 2025, + "day", + "ELC", + "E_BATT", + 2030, "ELC" ], [ "R1", - 2030, + 2020, "winter", "day", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2025, - "spring", - "day", - "ethos", - "S_IMPNG", + "ELC", + "E_BATT", 2020, - "NG" + "ELC" ], [ - "R2", - 2030, - "fall", + "R1", + 2020, + "summer", "night", - "ethos", - "S_IMPETH", + "ELC", + "E_BATT", 2020, - "ETH" + "ELC" ], [ "R1", - 2025, - "summer", + 2020, + "winter", "night", - "E10", - "T_GSL", + "ELC", + "E_BATT", 2020, - "VMT" + "ELC" ], [ "R1", - 2030, + 2025, "spring", "day", - "URN", - "E_NUCLEAR", + "ELC", + "E_BATT", 2025, "ELC" ], [ "R1", 2025, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "fall", + "winter", "night", - "GSL", - "T_BLND", + "ELC", + "E_BATT", 2020, - "E10" + "ELC" ], [ "R2", - 2030, - "winter", - "night", - "OIL", - "S_OILREF", 2020, - "DSL" - ], - [ - "R1", - 2030, "fall", "day", - "SOL", - "E_SOLPV", + "ELC", + "E_BATT", 2020, "ELC" ], @@ -29996,36 +20549,46 @@ "R1", 2025, "fall", - "night", - "E10", - "T_GSL", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", 2020, - "VMT" + "summer", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" ], [ "R2", 2025, "spring", - "night", - "URN", - "E_NUCLEAR", - 2025, + "day", + "ELC", + "E_BATT", + 2020, "ELC" ], [ "R1", 2030, - "summer", + "fall", "night", - "E10", - "T_GSL", - 2020, - "VMT" + "ELC", + "E_BATT", + 2030, + "ELC" ], [ - "R1", - 2025, - "winter", + "R2", + 2020, + "spring", "night", "ELC", "E_BATT", @@ -30034,211 +20597,221 @@ ], [ "R2", - 2030, - "summer", - "night", - "ETH", - "T_BLND", + 2025, + "fall", + "day", + "ELC", + "E_BATT", 2020, - "E10" + "ELC" ], [ "R1", + 2030, + "fall", + "day", + "ELC", + "E_BATT", 2020, - "winter", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" + "ELC" ], [ "R2", - 2020, + 2025, "winter", "day", - "ethos", - "S_IMPNG", + "ELC", + "E_BATT", 2020, - "NG" + "ELC" ], [ "R2", - 2020, - "fall", + 2025, + "summer", "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" + "ELC", + "E_BATT", + 2025, + "ELC" ], [ - "R1-R2", - 2020, - "spring", + "R1", + 2030, + "winter", "day", "ELC", - "E_TRANS", - 2015, + "E_BATT", + 2030, "ELC" ], [ - "R1", - 2020, - "summer", + "R2", + 2030, + "spring", "night", - "E10", - "T_GSL", - 2020, - "VMT" + "ELC", + "E_BATT", + 2030, + "ELC" ], [ - "R1", + "R2", 2025, "summer", - "night", - "SOL", - "E_SOLPV", + "day", + "ELC", + "E_BATT", 2025, "ELC" ], [ "R1", 2030, - "summer", + "spring", "night", - "URN", - "E_NUCLEAR", - 2015, + "ELC", + "E_BATT", + 2020, "ELC" ], [ "R2", 2030, "spring", - "night", + "day", "ELC", - "T_EV", + "E_BATT", 2030, - "VMT" + "ELC" ], [ - "R1", - 2025, - "fall", + "R2", + 2030, + "winter", "day", "ELC", - "R_EH", - 2020, - "RH" + "E_BATT", + 2030, + "ELC" ], [ "R2", - 2025, - "spring", - "day", - "NG", - "R_NGH", - 2025, - "RH" + 2030, + "winter", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" ], [ "R1", 2030, "winter", "night", - "ethos", - "S_IMPNG", - 2020, - "NG" + "ELC", + "E_BATT", + 2030, + "ELC" ], [ "R1", - 2020, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" + 2025, + "summer", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" ], [ "R1", 2030, "summer", - "night", - "SOL", - "E_SOLPV", + "day", + "ELC", + "E_BATT", 2025, "ELC" ], [ "R2", - 2030, + 2020, "winter", - "night", - "SOL", - "E_SOLPV", + "day", + "ELC", + "E_BATT", 2020, "ELC" ], [ - "R1", - 2020, - "summer", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" + "R2", + 2030, + "spring", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" ], [ - "R1-R2", + "R1", 2030, - "fall", + "winter", "day", "ELC", - "E_TRANS", - 2015, + "E_BATT", + 2020, "ELC" ], [ - "R2", + "R1", 2030, - "winter", - "night", - "URN", - "E_NUCLEAR", + "fall", + "day", + "ELC", + "E_BATT", 2025, "ELC" ], [ "R1", - 2030, - "summer", + 2025, + "winter", "day", - "OIL", - "S_OILREF", + "ELC", + "E_BATT", 2020, - "GSL" + "ELC" ], [ - "R1", + "R2", 2025, - "summer", + "winter", "day", - "DSL", - "T_DSL", + "ELC", + "E_BATT", 2025, - "VMT" + "ELC" ], [ - "R1", + "R2", 2030, "summer", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "winter", "day", - "URN", - "E_NUCLEAR", + "ELC", + "E_BATT", 2020, "ELC" ], @@ -30247,153 +20820,133 @@ 2025, "spring", "day", - "DSL", - "T_DSL", - 2020, - "VMT" + "ELC", + "E_BATT", + 2025, + "ELC" ], [ "R1", - 2030, - "fall", + 2025, + "summer", "night", - "E10", - "T_GSL", + "ELC", + "E_BATT", 2025, - "VMT" + "ELC" ], [ - "R2", - 2020, - "winter", + "R1", + 2025, + "summer", "day", - "DSL", - "T_DSL", + "ELC", + "E_BATT", 2020, - "VMT" + "ELC" ], [ "R1", - 2025, - "fall", + 2030, + "spring", "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" + "ELC", + "E_BATT", + 2025, + "ELC" ], [ "R1", 2030, - "fall", + "winter", "night", "ELC", - "R_EH", + "E_BATT", 2020, - "RH" + "ELC" ], [ "R2", 2020, "summer", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2025, - "fall", - "day", - "NG", - "E_NGCC", + "night", + "ELC", + "E_BATT", 2020, "ELC" ], [ "R2", - 2030, - "summer", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "spring", + 2020, + "fall", "night", "ELC", - "R_EH", - 2025, - "RH" + "E_BATT", + 2020, + "ELC" ], [ "R1", - 2025, + 2020, "fall", - "night", - "NG", - "R_NGH", + "day", + "ELC", + "E_BATT", 2020, - "RH" + "ELC" ], [ "R1", - 2025, + 2020, "fall", - "day", - "ethos", - "S_IMPETH", + "night", + "ELC", + "E_BATT", 2020, - "ETH" + "ELC" ], [ "R2", 2030, - "winter", + "summer", "day", "ELC", - "R_EH", + "E_BATT", 2030, - "RH" + "ELC" ], [ "R1", 2025, - "winter", + "spring", "night", - "DSL", - "T_DSL", + "ELC", + "E_BATT", 2025, - "VMT" + "ELC" ], [ "R1", - 2025, - "winter", + 2030, + "summer", "night", - "GSL", - "T_BLND", - 2020, - "E10" + "ELC", + "E_BATT", + 2025, + "ELC" ], [ "R1", 2020, - "winter", - "night", - "OIL", - "S_OILREF", + "spring", + "day", + "ELC", + "E_BATT", 2020, - "GSL" + "ELC" ], [ - "R1", + "R2", 2030, "fall", "night", @@ -30403,289 +20956,299 @@ "ELC" ], [ - "R1", + "R2", 2030, - "winter", + "fall", "day", "ELC", - "T_EV", - 2030, - "VMT" + "E_BATT", + 2020, + "ELC" ], [ "R1", - 2030, - "summer", - "night", - "NG", - "R_NGH", 2025, - "RH" + "winter", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" ], [ "R2", - 2020, - "fall", + 2030, + "summer", "day", - "NG", - "E_NGCC", + "ELC", + "E_BATT", 2020, "ELC" ], [ "R1", - 2030, + 2025, + "winter", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2025, "fall", "night", "ELC", - "T_EV", + "E_BATT", 2020, - "VMT" + "ELC" ], [ "R1", - 2020, + 2030, "summer", "night", - "OIL", - "S_OILREF", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "night", + "ELC", + "E_BATT", 2020, - "DSL" + "ELC" ], [ "R2", 2025, - "fall", + "winter", "night", - "ETH", - "T_BLND", + "ELC", + "E_BATT", 2020, - "E10" + "ELC" ], [ "R2", - 2030, + 2025, "fall", "day", "ELC", - "T_EV", - 2030, - "VMT" + "E_BATT", + 2025, + "ELC" ], [ - "R2", + "R1", 2020, "spring", - "day", - "SOL", - "E_SOLPV", + "night", + "ELC", + "E_BATT", 2020, "ELC" ], [ "R1", 2030, - "fall", + "spring", "night", - "NG", - "E_NGCC", - 2020, + "ELC", + "E_BATT", + 2025, "ELC" ], [ "R2", 2030, - "fall", - "day", - "SOL", - "E_SOLPV", + "winter", + "night", + "ELC", + "E_BATT", 2020, "ELC" ], [ "R1", - 2030, - "winter", - "day", - "SOL", - "E_SOLPV", 2025, + "spring", + "day", + "ELC", + "E_BATT", + 2020, "ELC" ], [ "R2", - 2025, - "spring", + 2030, + "summer", "night", - "NG", - "E_NGCC", - 2025, + "ELC", + "E_BATT", + 2020, "ELC" ], [ - "R2", + "R1", 2025, "fall", - "day", - "ethos", - "S_IMPETH", + "night", + "ELC", + "E_BATT", 2020, - "ETH" + "ELC" ], [ "R1", 2030, - "winter", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "summer", - "day", + "fall", + "night", "ELC", - "R_EH", + "E_BATT", 2025, - "RH" + "ELC" ], [ - "R2", + "R1", 2030, - "winter", + "summer", "day", - "NG", - "E_NGCC", + "ELC", + "E_BATT", 2030, "ELC" ], [ "R2", 2020, - "fall", - "night", - "SOL", - "E_SOLPV", + "spring", + "day", + "ELC", + "E_BATT", 2020, "ELC" ], [ - "R1", + "R2", 2025, - "fall", + "summer", "night", - "ethos", - "S_IMPOIL", + "ELC", + "E_BATT", 2020, - "OIL" + "ELC" ], [ - "R2", - 2025, + "R1", + 2030, "winter", "day", - "URN", - "E_NUCLEAR", + "ELC", + "E_BATT", 2025, "ELC" ], [ "R1", 2030, - "summer", + "fall", "day", - "ethos", - "S_IMPNG", - 2020, - "NG" + "ELC", + "E_BATT", + 2030, + "ELC" ], [ - "R1", - 2020, + "R2", + 2025, "summer", - "night", - "SOL", - "E_SOLPV", + "day", + "ELC", + "E_BATT", 2020, "ELC" ], [ "R2", - 2025, + 2030, "spring", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" + "day", + "ELC", + "E_BATT", + 2025, + "ELC" ], [ "R2", - 2020, + 2030, "winter", - "night", - "URN", - "E_NUCLEAR", - 2020, + "day", + "ELC", + "E_BATT", + 2025, "ELC" ], [ "R1", - 2025, + 2030, "spring", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" + "night", + "ELC", + "E_BATT", + 2030, + "ELC" ], [ - "R1-R2", + "R2", 2025, - "fall", - "day", + "winter", + "night", "ELC", - "E_TRANS", - 2015, + "E_BATT", + 2025, "ELC" ], [ "R1", 2030, - "fall", + "spring", "day", - "DSL", - "T_DSL", - 2025, - "VMT" + "ELC", + "E_BATT", + 2030, + "ELC" ], [ "R2", 2030, - "summer", + "winter", "night", - "OIL", - "S_OILREF", - 2020, - "DSL" + "ELC", + "E_BATT", + 2025, + "ELC" ], [ "R1", 2030, - "fall", - "day", - "NG", - "E_NGCC", + "winter", + "night", + "ELC", + "E_BATT", 2025, "ELC" ], [ - "R2", + "R1", 2020, - "fall", + "summer", "day", "ELC", "E_BATT", @@ -30693,50 +21256,50 @@ "ELC" ], [ - "R2", - 2025, + "R1", + 2030, "fall", - "day", + "night", "ELC", - "R_EH", + "E_BATT", 2020, - "RH" + "ELC" + ], + [ + "R1", + 2025, + "fall", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" ], [ "R2", - 2020, + 2030, "spring", "day", - "NG", - "E_NGCC", + "ELC", + "E_BATT", 2020, "ELC" ], [ - "R2", - 2020, + "R1", + 2030, "summer", "day", - "NG", - "R_NGH", + "ELC", + "E_BATT", 2020, - "RH" + "ELC" ], [ - "R1", + "R2", 2030, "spring", "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2025, - "fall", - "day", "ELC", "E_BATT", 2020, @@ -30745,7 +21308,7 @@ [ "R2", 2030, - "spring", + "fall", "night", "ELC", "E_BATT", @@ -30754,349 +21317,387 @@ ], [ "R2", - 2025, - "summer", + 2030, + "fall", "day", - "NG", - "E_NGCC", + "ELC", + "E_BATT", 2025, "ELC" + ] + ], + "FlowVarAnnual_rpitvo": [ + [ + "R1", + 2030, + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2020, + "ELC", + "T_EV", + 2020, + "VMT" ], [ "R2", 2025, - "winter", - "day", - "ETH", - "T_BLND", + "E10", + "T_GSL", 2020, - "E10" + "VMT" + ], + [ + "R1", + 2025, + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "DSL", + "T_DSL", + 2025, + "VMT" ], [ "R2", 2025, - "summer", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" + "ELC", + "R_EH", + 2025, + "RH" ], [ "R2", + 2030, + "ELC", + "T_EV", 2020, - "summer", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" + "VMT" ], [ "R2", - 2020, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" + 2025, + "NG", + "R_NGH", + 2025, + "RH" ], [ "R1", 2030, - "spring", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" + "DSL", + "T_DSL", + 2030, + "VMT" ], [ "R1", 2030, - "summer", - "day", - "GSL", - "T_BLND", + "ELC", + "R_EH", 2020, - "E10" + "RH" ], [ "R1", 2030, - "spring", - "night", - "DSL", - "T_DSL", - 2030, + "ELC", + "T_EV", + 2025, "VMT" ], [ "R1", 2030, - "spring", - "night", - "ETH", - "T_BLND", - 2020, - "E10" + "E10", + "T_GSL", + 2025, + "VMT" ], [ "R2", + 2030, + "E10", + "T_GSL", 2025, - "summer", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" + "VMT" + ], + [ + "R2", + 2030, + "ELC", + "R_EH", + 2030, + "RH" ], [ "R2", 2025, - "winter", - "day", - "NG", - "R_NGH", + "ELC", + "R_EH", 2020, "RH" ], [ "R2", 2030, - "fall", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" + "DSL", + "T_DSL", + 2020, + "VMT" ], [ "R1", - 2025, - "fall", - "day", - "E10", - "T_GSL", - 2025, + 2020, + "ELC", + "T_EV", + 2020, "VMT" ], [ "R1", 2020, - "fall", - "day", - "DSL", - "T_DSL", + "E10", + "T_GSL", 2020, "VMT" ], [ "R2", 2030, - "summer", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" + "NG", + "R_NGH", + 2030, + "RH" ], [ "R2", - 2030, - "winter", - "night", - "DSL", - "T_DSL", + 2025, + "ELC", + "T_EV", 2025, "VMT" ], [ "R2", 2025, - "spring", - "night", - "E10", - "T_GSL", + "NG", + "R_NGH", 2020, + "RH" + ], + [ + "R1", + 2030, + "DSL", + "T_DSL", + 2025, "VMT" ], [ "R1", + 2030, + "NG", + "R_NGH", 2025, - "winter", - "night", - "ETH", - "T_BLND", - 2020, - "E10" + "RH" ], [ - "R2", + "R1", 2020, - "fall", - "day", - "OIL", - "S_OILREF", + "NG", + "R_NGH", 2020, - "GSL" + "RH" ], [ "R1", 2025, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "NG", + "R_NGH", + 2025, + "RH" ], [ "R1", 2030, - "winter", - "night", "ELC", - "E_BATT", + "T_EV", 2020, - "ELC" + "VMT" ], [ "R2", + 2030, + "E10", + "T_GSL", 2020, - "fall", - "day", - "ethos", - "S_IMPURN", + "VMT" + ], + [ + "R1", + 2030, + "DSL", + "T_DSL", 2020, - "URN" + "VMT" ], [ - "R2-R1", + "R2", + 2030, + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", 2025, - "summer", - "day", "ELC", - "E_TRANS", - 2015, - "ELC" + "R_EH", + 2025, + "RH" ], [ "R2", - 2020, - "fall", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" + 2030, + "ELC", + "T_EV", + 2030, + "VMT" ], [ "R1", - 2030, - "spring", - "night", + 2025, "ELC", "T_EV", - 2030, + 2025, + "VMT" + ], + [ + "R2", + 2025, + "DSL", + "T_DSL", + 2025, "VMT" ], [ "R2", - 2025, - "fall", - "day", + 2030, "NG", - "E_NGCC", + "R_NGH", 2025, - "ELC" + "RH" ], [ - "R1", - 2025, - "fall", - "night", - "SOL", - "E_SOLPV", + "R2", 2025, - "ELC" + "ELC", + "T_EV", + 2020, + "VMT" ], [ "R2", - 2025, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" + 2020, + "E10", + "T_GSL", + 2020, + "VMT" ], [ "R1", 2030, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" + "E10", + "T_GSL", + 2020, + "VMT" ], [ "R1", 2030, - "winter", - "day", - "ethos", - "S_IMPNG", + "NG", + "R_NGH", 2020, - "NG" + "RH" ], [ - "R2", - 2020, - "spring", - "night", - "URN", - "E_NUCLEAR", + "R1", + 2025, + "DSL", + "T_DSL", 2020, - "ELC" + "VMT" ], [ - "R2", + "R1", 2025, - "winter", - "night", - "GSL", - "T_BLND", + "NG", + "R_NGH", 2020, - "E10" + "RH" + ], + [ + "R1", + 2025, + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "ELC", + "R_EH", + 2030, + "RH" ], [ "R2", 2030, - "winter", - "day", "DSL", "T_DSL", 2030, "VMT" ], [ - "R2-R1", + "R2", 2030, - "spring", - "day", "ELC", - "E_TRANS", - 2015, - "ELC" + "R_EH", + 2020, + "RH" ], [ - "R2", - 2020, - "winter", - "night", + "R1", + 2025, "ELC", "R_EH", 2020, @@ -31105,178 +21706,124 @@ [ "R1", 2030, - "winter", - "day", - "URN", - "E_NUCLEAR", + "ELC", + "T_EV", 2030, - "ELC" + "VMT" ], [ "R2", 2030, - "spring", - "night", - "SOL", - "E_SOLPV", + "ELC", + "T_EV", 2025, - "ELC" + "VMT" ], [ "R2", - 2030, - "summer", - "night", + 2020, "ELC", "R_EH", - 2030, + 2020, "RH" ], [ - "R1", - 2025, - "spring", - "day", - "ELC", - "T_EV", + "R2", 2025, + "DSL", + "T_DSL", + 2020, "VMT" ], [ "R1", - 2025, - "spring", - "day", - "E10", - "T_GSL", - 2025, + 2020, + "DSL", + "T_DSL", + 2020, "VMT" ], [ - "R1", - 2025, - "winter", - "day", - "ELC", - "R_EH", + "R2", + 2030, + "NG", + "R_NGH", 2020, "RH" ], [ - "R1", + "R2", 2020, - "fall", - "night", - "ETH", - "T_BLND", + "DSL", + "T_DSL", 2020, - "E10" + "VMT" ], [ "R1", 2030, - "summer", - "night", "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", + "R_EH", 2025, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" + "RH" ], [ "R2", - 2025, - "summer", - "night", - "ELC", - "E_BATT", 2020, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "ethos", - "S_IMPOIL", + "NG", + "R_NGH", 2020, - "OIL" + "RH" ], [ - "R1", + "R2", 2025, - "fall", - "day", - "NG", - "R_NGH", + "E10", + "T_GSL", 2025, - "RH" + "VMT" ], [ "R1", 2025, - "fall", - "day", - "ethos", - "S_IMPURN", + "ELC", + "T_EV", 2020, - "URN" + "VMT" ], [ "R1", 2030, - "spring", - "night", - "ELC", - "E_BATT", + "E10", + "T_GSL", 2030, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" + "VMT" ], [ "R2", - 2025, - "winter", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], + 2030, + "E10", + "T_GSL", + 2030, + "VMT" + ] + ], + "FlowVar_rpsditvo": [ [ "R2", 2020, - "summer", - "day", - "URN", - "E_NUCLEAR", + "fall", + "night", + "OIL", + "S_OILREF", 2020, - "ELC" + "GSL" ], [ - "R1", + "R2", 2030, - "spring", - "night", + "fall", + "day", "OIL", "S_OILREF", 2020, @@ -31293,60 +21840,50 @@ "ELC" ], [ - "R2", + "R1", 2030, - "summer", + "winter", "night", "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "night", - "DSL", - "T_DSL", + "E_BATT", 2020, - "VMT" + "ELC" ], [ "R2", 2030, - "fall", + "summer", "night", - "E10", - "T_GSL", - 2030, - "VMT" + "ELC", + "E_BATT", + 2025, + "ELC" ], [ "R2", - 2030, - "summer", + 2025, + "spring", "night", - "SOL", - "E_SOLPV", + "OIL", + "S_OILREF", 2020, - "ELC" + "GSL" ], [ "R1", 2025, - "fall", + "summer", "day", - "ELC", - "E_BATT", + "OIL", + "S_OILREF", 2020, - "ELC" + "GSL" ], [ - "R2", + "R1", 2025, - "summer", - "night", + "winter", + "day", "URN", "E_NUCLEAR", 2025, @@ -31354,52 +21891,72 @@ ], [ "R2", - 2030, - "fall", + 2020, + "winter", "night", "ethos", - "S_IMPNG", + "S_IMPETH", 2020, - "NG" + "ETH" ], [ "R2", 2030, "spring", - "day", - "ELC", - "T_EV", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", 2025, - "VMT" + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" ], [ - "R1", + "R1-R2", + 2030, + "spring", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2", 2020, - "summer", + "winter", "day", - "ELC", - "T_EV", + "ethos", + "S_IMPNG", 2020, - "VMT" + "NG" ], [ "R2", - 2030, - "spring", + 2020, + "winter", "day", - "NG", - "R_NGH", + "ethos", + "S_IMPURN", 2020, - "RH" + "URN" ], [ "R1", - 2025, - "winter", + 2030, + "fall", "day", - "NG", - "E_NGCC", - 2020, + "SOL", + "E_SOLPV", + 2025, "ELC" ], [ @@ -31407,15 +21964,15 @@ 2025, "fall", "day", - "URN", - "E_NUCLEAR", + "ETH", + "T_BLND", 2020, - "ELC" + "E10" ], [ "R1", 2020, - "winter", + "fall", "day", "GSL", "T_BLND", @@ -31423,29 +21980,39 @@ "E10" ], [ - "R1", + "R2", 2025, - "spring", + "summer", "night", - "OIL", - "S_OILREF", - 2020, - "DSL" + "SOL", + "E_SOLPV", + 2025, + "ELC" ], [ "R2", 2030, - "winter", + "spring", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2025, + "fall", "day", "ELC", - "R_EH", + "E_BATT", 2020, - "RH" + "ELC" ], [ - "R1", - 2030, - "winter", + "R2", + 2020, + "fall", "night", "ETH", "T_BLND", @@ -31453,89 +22020,49 @@ "E10" ], [ - "R1", - 2020, - "summer", + "R2", + 2030, + "fall", "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", "SOL", "E_SOLPV", 2020, "ELC" ], [ - "R2", - 2030, - "winter", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", + "R1", 2025, "spring", "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2025, - "summer", - "day", - "ethos", - "S_IMPETH", + "URN", + "E_NUCLEAR", 2020, - "ETH" + "ELC" ], [ "R2", 2025, "spring", "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "fall", - "night", - "ethos", - "S_IMPOIL", + "SOL", + "E_SOLPV", 2020, - "OIL" + "ELC" ], [ "R2", 2030, "winter", "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" + "URN", + "E_NUCLEAR", + 2025, + "ELC" ], [ "R2", 2030, - "winter", + "spring", "day", "NG", "E_NGCC", @@ -31543,39 +22070,29 @@ "ELC" ], [ - "R1", - 2020, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "fall", + "R1", + 2030, + "spring", "night", - "ELC", - "T_EV", + "GSL", + "T_BLND", 2020, - "VMT" + "E10" ], [ "R1", - 2020, - "winter", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" + 2030, + "spring", + "night", + "URN", + "E_NUCLEAR", + 2030, + "ELC" ], [ "R1", 2030, - "fall", + "winter", "day", "ELC", "E_BATT", @@ -31584,281 +22101,251 @@ ], [ "R1", - 2020, + 2025, "winter", - "night", - "DSL", - "T_DSL", + "day", + "SOL", + "E_SOLPV", 2020, - "VMT" + "ELC" ], [ - "R2", - 2020, + "R1-R2", + 2030, "fall", "day", - "ETH", - "T_BLND", - 2020, - "E10" + "ELC", + "E_TRANS", + 2015, + "ELC" ], [ - "R1", - 2020, - "spring", - "day", - "ethos", - "S_IMPNG", + "R1-R2", 2020, - "NG" - ], - [ - "R2", - 2025, - "summer", + "winter", "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" + "ELC", + "E_TRANS", + 2015, + "ELC" ], [ - "R1", - 2020, + "R2", + 2030, "fall", "night", - "ELC", - "E_BATT", + "ethos", + "S_IMPNG", 2020, - "ELC" + "NG" ], [ "R2", - 2025, - "summer", - "night", - "ETH", - "T_BLND", + 2030, + "fall", + "day", + "OIL", + "S_OILREF", 2020, - "E10" + "GSL" ], [ - "R1", + "R2-R1", 2025, "winter", "night", - "ethos", - "S_IMPURN", - 2020, - "URN" + "ELC", + "E_TRANS", + 2015, + "ELC" ], [ "R2", 2020, - "spring", + "winter", "night", - "DSL", - "T_DSL", + "SOL", + "E_SOLPV", 2020, - "VMT" + "ELC" ], [ "R1", 2025, "fall", "day", - "DSL", - "T_DSL", - 2025, - "VMT" + "GSL", + "T_BLND", + 2020, + "E10" ], [ "R2", 2030, - "summer", + "spring", "night", - "DSL", - "T_DSL", + "SOL", + "E_SOLPV", 2030, - "VMT" + "ELC" ], [ "R1", - 2030, - "summer", - "night", - "DSL", - "T_DSL", - 2030, - "VMT" + 2025, + "winter", + "day", + "ETH", + "T_BLND", + 2020, + "E10" ], [ - "R2", + "R1", 2030, - "fall", + "spring", "day", - "DSL", - "T_DSL", - 2025, - "VMT" + "URN", + "E_NUCLEAR", + 2020, + "ELC" ], [ "R2", - 2030, + 2020, "spring", "night", "ELC", - "R_EH", + "E_BATT", 2020, - "RH" + "ELC" ], [ - "R2", + "R1", 2030, - "summer", + "winter", "night", - "E10", - "T_GSL", + "ethos", + "S_IMPNG", 2020, - "VMT" + "NG" ], [ "R2", - 2025, - "spring", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "day", + 2020, + "fall", + "night", "ELC", - "T_EV", + "E_BATT", 2020, - "VMT" + "ELC" ], [ "R2", - 2025, + 2030, "spring", - "day", - "E10", - "T_GSL", - 2025, - "VMT" + "night", + "NG", + "E_NGCC", + 2030, + "ELC" ], [ - "R1", - 2025, + "R2", + 2020, "fall", - "day", + "night", "ethos", "S_IMPNG", 2020, "NG" ], [ - "R1", + "R2", 2025, - "winter", - "day", - "DSL", - "T_DSL", + "spring", + "night", + "ELC", + "E_BATT", 2020, - "VMT" + "ELC" ], [ "R2", 2020, - "fall", - "day", - "SOL", - "E_SOLPV", + "winter", + "night", + "ETH", + "T_BLND", 2020, - "ELC" + "E10" ], [ "R2", 2030, - "fall", + "summer", "day", "URN", "E_NUCLEAR", - 2020, + 2030, "ELC" ], [ - "R2-R1", - 2030, + "R1", + 2025, "winter", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" ], [ "R1", 2020, - "winter", - "day", - "ELC", - "T_EV", + "fall", + "night", + "URN", + "E_NUCLEAR", 2020, - "VMT" + "ELC" ], [ "R2", 2025, "fall", - "night", - "DSL", - "T_DSL", + "day", + "NG", + "E_NGCC", 2025, - "VMT" + "ELC" ], [ - "R2", - 2025, - "fall", - "day", - "OIL", - "S_OILREF", + "R1", 2020, - "GSL" + "summer", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" ], [ "R1", - 2025, + 2030, "fall", "day", "ELC", - "T_EV", - 2025, - "VMT" + "E_BATT", + 2030, + "ELC" ], [ "R1", 2025, "summer", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "SOL", - "E_SOLPV", + "night", + "URN", + "E_NUCLEAR", 2025, "ELC" ], @@ -31867,10 +22354,20 @@ 2025, "spring", "night", - "E10", - "T_GSL", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", 2025, - "VMT" + "fall", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" ], [ "R2", @@ -31879,63 +22376,33 @@ "night", "NG", "E_NGCC", - 2025, + 2020, "ELC" ], [ - "R1", + "R2", 2030, "spring", "night", "ELC", "E_BATT", - 2025, - "ELC" - ], - [ - "R1", 2030, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2020, "ELC" ], [ "R2", - 2020, - "spring", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "spring", + 2025, + "fall", "night", - "E10", - "T_GSL", + "OIL", + "S_OILREF", 2020, - "VMT" + "GSL" ], [ "R1", 2030, - "winter", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "winter", + "summer", "night", "OIL", "S_OILREF", @@ -31946,26 +22413,36 @@ "R1", 2030, "summer", + "day", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R1", + 2020, + "winter", "night", - "ethos", - "S_IMPETH", + "GSL", + "T_BLND", 2020, - "ETH" + "E10" ], [ - "R1", - 2030, + "R1-R2", + 2020, "summer", "day", "ELC", - "E_BATT", - 2030, + "E_TRANS", + 2015, "ELC" ], [ "R2", - 2030, - "spring", + 2020, + "summer", "night", "NG", "E_NGCC", @@ -31973,60 +22450,70 @@ "ELC" ], [ - "R2-R1", + "R1", + 2030, + "winter", + "night", + "OIL", + "S_OILREF", 2020, - "summer", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" + "DSL" ], [ "R1", 2030, "spring", - "night", - "SOL", - "E_SOLPV", - 2025, + "day", + "URN", + "E_NUCLEAR", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "day", + "ELC", + "E_BATT", + 2030, "ELC" ], [ "R2", 2020, - "summer", + "fall", "day", - "DSL", - "T_DSL", + "ethos", + "S_IMPETH", 2020, - "VMT" + "ETH" ], [ "R1", 2025, - "summer", + "spring", "day", - "NG", - "E_NGCC", - 2025, + "URN", + "E_NUCLEAR", + 2020, "ELC" ], [ - "R2", + "R1", 2025, - "spring", - "day", - "NG", - "E_NGCC", + "winter", + "night", + "SOL", + "E_SOLPV", 2020, "ELC" ], [ - "R2", - 2030, - "spring", - "day", + "R1", + 2025, + "winter", + "night", "GSL", "T_BLND", 2020, @@ -32035,77 +22522,67 @@ [ "R1", 2030, - "winter", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, "summer", "day", - "ELC", - "R_EH", - 2020, - "RH" + "URN", + "E_NUCLEAR", + 2015, + "ELC" ], [ - "R2", - 2025, + "R1", + 2020, "summer", "day", - "DSL", - "T_DSL", + "ethos", + "S_IMPOIL", 2020, - "VMT" + "OIL" ], [ - "R2", + "R1", 2020, - "fall", + "spring", "day", - "NG", - "R_NGH", + "ethos", + "S_IMPURN", 2020, - "RH" + "URN" ], [ - "R1", - 2025, - "fall", + "R2", + 2030, + "summer", "day", - "URN", - "E_NUCLEAR", - 2015, + "NG", + "E_NGCC", + 2025, "ELC" ], [ - "R1", + "R2", + 2030, + "fall", + "day", + "NG", + "E_NGCC", 2025, - "summer", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" + "ELC" ], [ - "R1", + "R2", 2030, - "summer", + "winter", "day", "NG", "E_NGCC", - 2020, + 2030, "ELC" ], [ - "R1-R2", - 2020, - "spring", + "R2-R1", + 2025, + "summer", "night", "ELC", "E_TRANS", @@ -32115,76 +22592,66 @@ [ "R1", 2030, - "fall", + "summer", "night", - "SOL", - "E_SOLPV", - 2030, + "URN", + "E_NUCLEAR", + 2025, "ELC" ], [ "R1", - 2030, + 2025, "winter", - "night", - "URN", - "E_NUCLEAR", - 2015, + "day", + "ELC", + "E_BATT", + 2025, "ELC" ], [ - "R1", + "R2", 2025, - "spring", - "night", - "URN", - "E_NUCLEAR", + "fall", + "day", + "ETH", + "T_BLND", 2020, - "ELC" + "E10" ], [ "R2", 2030, - "winter", - "day", + "fall", + "night", "URN", "E_NUCLEAR", - 2015, + 2030, "ELC" ], [ "R1", - 2025, - "spring", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", 2030, - "summer", - "day", - "ELC", - "E_BATT", + "fall", + "night", + "SOL", + "E_SOLPV", 2025, "ELC" ], [ "R2", 2020, - "fall", + "winter", "night", - "NG", - "R_NGH", + "OIL", + "S_OILREF", 2020, - "RH" + "GSL" ], [ "R2", - 2030, + 2020, "summer", "day", "GSL", @@ -32193,119 +22660,169 @@ "E10" ], [ - "R2", + "R1", 2030, "summer", "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2020, + "spring", + "day", "URN", "E_NUCLEAR", 2015, "ELC" ], [ - "R2", + "R2-R1", 2030, - "winter", + "summer", "day", - "NG", - "R_NGH", - 2030, - "RH" + "ELC", + "E_TRANS", + 2015, + "ELC" ], [ - "R2", + "R1", 2025, - "fall", + "spring", "night", - "E10", - "T_GSL", + "SOL", + "E_SOLPV", 2025, - "VMT" + "ELC" + ], + [ + "R1-R2", + 2025, + "summer", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" ], [ "R2", + 2030, + "winter", + "night", + "GSL", + "T_BLND", 2020, - "spring", + "E10" + ], + [ + "R1", + 2030, + "winter", "day", - "ELC", - "R_EH", + "URN", + "E_NUCLEAR", 2020, - "RH" + "ELC" ], [ "R2", - 2030, - "fall", + 2025, + "summer", "night", "ELC", "E_BATT", - 2020, + 2025, "ELC" ], [ "R1", 2020, - "fall", + "summer", "day", - "NG", - "E_NGCC", + "GSL", + "T_BLND", 2020, - "ELC" + "E10" ], [ - "R1", - 2030, + "R2", + 2025, "spring", - "day", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2025, + "spring", + "night", "NG", "E_NGCC", - 2030, + 2025, "ELC" ], [ - "R2", - 2030, + "R1", + 2025, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2020, "summer", - "day", - "NG", - "E_NGCC", + "night", + "GSL", + "T_BLND", 2020, - "ELC" + "E10" ], [ "R2", - 2025, - "winter", + 2020, + "fall", "night", "URN", "E_NUCLEAR", - 2025, + 2020, "ELC" ], [ "R1", - 2025, - "summer", - "day", - "ELC", - "R_EH", - 2025, - "RH" + 2020, + "winter", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" ], [ - "R1", + "R2", 2030, - "spring", + "winter", "day", - "ethos", - "S_IMPURN", - 2020, - "URN" + "ELC", + "E_BATT", + 2025, + "ELC" ], [ "R1", - 2020, - "spring", + 2030, + "summer", "night", "OIL", "S_OILREF", @@ -32316,41 +22833,61 @@ "R1", 2030, "summer", + "night", + "SOL", + "E_SOLPV", + 2030, + "ELC" + ], + [ + "R1", + 2020, + "winter", "day", - "ELC", - "R_EH", - 2025, - "RH" + "ethos", + "S_IMPNG", + 2020, + "NG" ], [ - "R2", + "R1", 2025, - "spring", + "summer", "day", - "ELC", - "E_BATT", - 2020, + "URN", + "E_NUCLEAR", + 2015, "ELC" ], [ "R2", 2020, - "summer", + "fall", "night", - "SOL", - "E_SOLPV", + "ethos", + "S_IMPOIL", 2020, - "ELC" + "OIL" ], [ "R2", 2025, "summer", - "night", - "E10", - "T_GSL", + "day", + "NG", + "E_NGCC", 2020, - "VMT" + "ELC" + ], + [ + "R2-R1", + 2020, + "fall", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" ], [ "R2", @@ -32359,87 +22896,67 @@ "night", "URN", "E_NUCLEAR", - 2020, + 2015, "ELC" ], [ - "R1", - 2030, - "fall", - "day", - "ELC", - "E_BATT", + "R2-R1", 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "fall", + "summer", "night", - "OIL", - "S_OILREF", - 2020, - "GSL" + "ELC", + "E_TRANS", + 2015, + "ELC" ], [ "R1", 2030, "summer", "night", - "OIL", - "S_OILREF", + "ethos", + "S_IMPOIL", 2020, - "GSL" + "OIL" ], [ - "R1", + "R2", 2025, - "spring", - "day", - "NG", - "E_NGCC", + "fall", + "night", + "SOL", + "E_SOLPV", 2025, "ELC" ], [ "R1", 2025, - "winter", + "summer", "day", - "GSL", - "T_BLND", + "ethos", + "S_IMPNG", 2020, - "E10" + "NG" ], [ "R1", 2025, "summer", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" ], [ "R2", 2030, - "fall", + "summer", "night", - "NG", - "E_NGCC", - 2030, + "ELC", + "E_BATT", + 2020, "ELC" ], [ @@ -32447,106 +22964,66 @@ 2025, "winter", "day", - "ELC", - "T_EV", - 2025, - "VMT" + "GSL", + "T_BLND", + 2020, + "E10" ], [ "R2", - 2020, + 2030, "spring", "day", - "ELC", - "T_EV", + "ETH", + "T_BLND", 2020, - "VMT" + "E10" ], [ "R2", 2020, - "winter", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2025, "spring", "day", - "ELC", - "T_EV", + "SOL", + "E_SOLPV", 2020, - "VMT" + "ELC" ], [ - "R2", + "R1-R2", 2030, - "fall", + "winter", "day", - "NG", - "R_NGH", - 2025, - "RH" + "ELC", + "E_TRANS", + 2015, + "ELC" ], [ "R2", - 2020, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "spring", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", 2025, "winter", - "day", - "ETH", - "T_BLND", + "night", + "ethos", + "S_IMPURN", 2020, - "E10" + "URN" ], [ "R1", - 2030, + 2025, "winter", "day", - "NG", - "E_NGCC", + "URN", + "E_NUCLEAR", 2020, "ELC" ], [ "R1", 2025, - "summer", + "fall", "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2025, - "spring", - "night", "ELC", "E_BATT", 2025, @@ -32554,47 +23031,47 @@ ], [ "R1", - 2030, + 2025, "summer", - "day", - "DSL", - "T_DSL", + "night", + "SOL", + "E_SOLPV", 2025, - "VMT" + "ELC" ], [ "R1", 2025, "spring", - "night", - "SOL", - "E_SOLPV", + "day", + "NG", + "E_NGCC", 2025, "ELC" ], [ "R1", - 2030, + 2020, "summer", - "day", - "E10", - "T_GSL", - 2025, - "VMT" + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" ], [ - "R2", - 2020, - "winter", + "R1", + 2025, + "spring", "day", - "ELC", - "T_EV", + "ethos", + "S_IMPOIL", 2020, - "VMT" + "OIL" ], [ "R2", - 2030, + 2020, "summer", "night", "URN", @@ -32603,137 +23080,127 @@ "ELC" ], [ - "R1", - 2020, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, + "R2-R1", + 2020, "spring", "night", - "URN", - "E_NUCLEAR", - 2030, + "ELC", + "E_TRANS", + 2015, "ELC" ], [ "R1", - 2020, - "winter", + 2030, + "fall", "day", - "ethos", - "S_IMPOIL", + "SOL", + "E_SOLPV", 2020, - "OIL" + "ELC" ], [ - "R1", - 2030, + "R2", + 2020, "summer", "night", - "URN", - "E_NUCLEAR", + "ELC", + "E_BATT", 2020, "ELC" ], [ "R2", + 2030, + "summer", + "night", + "OIL", + "S_OILREF", 2020, - "winter", - "day", - "E10", - "T_GSL", - 2020, - "VMT" + "DSL" ], [ "R2", 2030, - "spring", - "night", - "E10", - "T_GSL", - 2025, - "VMT" + "fall", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" ], [ "R2", 2025, + "summer", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2030, "fall", "day", - "ELC", - "T_EV", - 2025, - "VMT" + "ethos", + "S_IMPNG", + 2020, + "NG" ], [ "R1", - 2025, - "winter", + 2030, + "fall", "day", "ethos", - "S_IMPETH", + "S_IMPURN", 2020, - "ETH" + "URN" ], [ - "R1", + "R2-R1", 2025, "spring", "night", - "E10", - "T_GSL", - 2020, - "VMT" + "ELC", + "E_TRANS", + 2015, + "ELC" ], [ - "R2", - 2025, + "R2-R1", + 2030, "fall", - "day", - "NG", - "R_NGH", - 2025, - "RH" + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" ], [ "R1", - 2030, - "winter", - "night", - "GSL", - "T_BLND", 2020, - "E10" - ], - [ - "R2", - 2025, - "winter", - "day", - "ethos", - "S_IMPOIL", + "spring", + "night", + "ELC", + "E_BATT", 2020, - "OIL" + "ELC" ], [ "R1", 2030, - "winter", + "fall", "night", - "SOL", - "E_SOLPV", - 2025, + "ELC", + "E_BATT", + 2030, "ELC" ], [ - "R2", + "R1", 2025, "fall", "night", @@ -32742,20 +23209,30 @@ 2020, "ETH" ], + [ + "R1", + 2020, + "winter", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], [ "R2", 2030, "winter", "day", - "GSL", - "T_BLND", + "URN", + "E_NUCLEAR", 2020, - "E10" + "ELC" ], [ "R2", - 2020, - "winter", + 2030, + "spring", "day", "URN", "E_NUCLEAR", @@ -32764,119 +23241,79 @@ ], [ "R1", - 2020, - "fall", + 2030, + "winter", "day", - "GSL", - "T_BLND", - 2020, - "E10" + "SOL", + "E_SOLPV", + 2030, + "ELC" ], [ "R1", 2020, "winter", "night", - "E10", - "T_GSL", + "ELC", + "E_BATT", 2020, - "VMT" + "ELC" ], [ - "R1", - 2030, + "R2", + 2025, "winter", - "night", - "ethos", - "S_IMPOIL", + "day", + "SOL", + "E_SOLPV", 2020, - "OIL" + "ELC" ], [ "R1", - 2030, - "spring", - "day", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "night", - "ethos", - "S_IMPETH", 2020, - "ETH" - ], - [ - "R2", - 2030, "fall", - "night", - "ETH", - "T_BLND", + "day", + "ELC", + "E_BATT", 2020, - "E10" + "ELC" ], [ - "R2", + "R1", 2030, "winter", - "day", - "URN", - "E_NUCLEAR", + "night", + "NG", + "E_NGCC", 2030, "ELC" ], - [ - "R2", - 2025, - "fall", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], [ "R1", - 2020, + 2025, "spring", "night", - "ethos", - "S_IMPURN", + "NG", + "E_NGCC", 2020, - "URN" + "ELC" ], [ "R2", 2030, "fall", "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "fall", - "day", - "OIL", - "S_OILREF", + "ethos", + "S_IMPURN", 2020, - "DSL" + "URN" ], [ "R1-R2", - 2030, - "spring", - "day", + 2025, + "fall", + "night", "ELC", "E_TRANS", 2015, @@ -32886,96 +23323,96 @@ "R1", 2025, "winter", - "day", - "SOL", - "E_SOLPV", + "night", + "ETH", + "T_BLND", 2020, - "ELC" + "E10" ], [ - "R1", - 2030, + "R2", + 2020, "spring", "day", - "ELC", - "E_BATT", - 2030, - "ELC" + "ethos", + "S_IMPETH", + 2020, + "ETH" ], [ - "R1", + "R2", 2025, "spring", "night", - "ELC", - "R_EH", + "ethos", + "S_IMPOIL", 2020, - "RH" + "OIL" ], [ "R2", 2030, - "fall", + "spring", "night", - "ELC", - "T_EV", - 2030, - "VMT" + "GSL", + "T_BLND", + 2020, + "E10" ], [ - "R1", - 2030, - "winter", + "R2", + 2020, + "summer", "day", "OIL", "S_OILREF", 2020, - "GSL" + "DSL" ], [ "R2", 2030, - "fall", + "spring", "night", "SOL", "E_SOLPV", - 2020, + 2025, "ELC" ], - [ - "R1", - 2030, - "winter", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], [ "R2", - 2020, + 2025, "summer", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" ], [ "R1", 2030, "spring", "day", - "NG", - "E_NGCC", - 2025, + "URN", + "E_NUCLEAR", + 2015, "ELC" ], [ "R1", - 2025, + 2030, "spring", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "fall", "day", "ethos", "S_IMPOIL", @@ -32983,219 +23420,129 @@ "OIL" ], [ - "R1", + "R2", 2030, - "winter", + "spring", "day", - "DSL", - "T_DSL", - 2025, - "VMT" + "OIL", + "S_OILREF", + 2020, + "DSL" ], [ - "R2", - 2025, + "R1", + 2030, "winter", "night", - "URN", - "E_NUCLEAR", + "ethos", + "S_IMPOIL", 2020, - "ELC" + "OIL" ], [ "R1", - 2025, - "summer", + 2030, + "winter", "night", - "ELC", - "E_BATT", + "NG", + "E_NGCC", 2020, "ELC" ], [ "R1", 2025, - "summer", + "fall", "day", - "ELC", - "R_EH", + "ethos", + "S_IMPNG", 2020, - "RH" + "NG" ], [ "R1", 2025, "fall", "day", - "SOL", - "E_SOLPV", + "ethos", + "S_IMPURN", 2020, - "ELC" + "URN" ], [ "R2", 2030, - "spring", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, "summer", - "night", - "ELC", - "E_BATT", - 2020, + "day", + "URN", + "E_NUCLEAR", + 2025, "ELC" ], [ "R2", 2020, - "spring", + "fall", "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", + "NG", + "E_NGCC", 2020, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2015, "ELC" ], - [ - "R1", - 2025, - "winter", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], [ "R2", - 2020, - "fall", + 2025, + "summer", "night", - "OIL", - "S_OILREF", + "ethos", + "S_IMPETH", 2020, - "GSL" + "ETH" ], [ - "R1", + "R2", 2030, - "fall", - "day", + "summer", + "night", "OIL", "S_OILREF", 2020, "GSL" ], - [ - "R1", - 2025, - "winter", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], [ "R1", 2020, - "winter", + "fall", "night", "URN", "E_NUCLEAR", 2015, "ELC" ], - [ - "R2", - 2030, - "spring", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], [ "R2", 2025, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, "fall", "day", - "ethos", - "S_IMPURN", + "NG", + "E_NGCC", 2020, - "URN" + "ELC" ], [ "R2", 2025, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "spring", "day", "ethos", - "S_IMPOIL", + "S_IMPNG", 2020, - "OIL" + "NG" ], [ - "R1", + "R2", 2020, "fall", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "spring", "day", "ETH", "T_BLND", @@ -33204,13 +23551,13 @@ ], [ "R1", - 2025, - "spring", - "night", + 2030, + "fall", + "day", "ELC", - "T_EV", - 2020, - "VMT" + "E_BATT", + 2025, + "ELC" ], [ "R1", @@ -33219,35 +23566,45 @@ "night", "URN", "E_NUCLEAR", - 2025, + 2020, + "ELC" + ], + [ + "R1-R2", + 2030, + "fall", + "night", + "ELC", + "E_TRANS", + 2015, "ELC" ], [ "R2", 2025, "fall", - "day", + "night", "ethos", - "S_IMPNG", + "S_IMPURN", 2020, - "NG" + "URN" ], [ "R1", - 2020, - "winter", - "night", + 2030, + "fall", + "day", "NG", "E_NGCC", - 2020, + 2030, "ELC" ], [ - "R2", - 2020, + "R1", + 2030, "summer", - "day", - "ETH", + "night", + "GSL", "T_BLND", 2020, "E10" @@ -33255,180 +23612,190 @@ [ "R1", 2030, - "fall", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" + "summer", + "day", + "NG", + "E_NGCC", + 2030, + "ELC" ], [ "R1", - 2030, - "spring", - "day", - "ELC", - "R_EH", 2025, - "RH" + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" ], [ "R2", 2030, - "winter", + "summer", "day", - "ELC", - "E_BATT", - 2030, - "ELC" + "ethos", + "S_IMPETH", + 2020, + "ETH" ], [ "R2", 2030, "winter", - "night", - "ELC", - "T_EV", - 2025, - "VMT" + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" ], [ "R2", 2030, - "spring", - "day", + "summer", + "night", "ethos", "S_IMPOIL", 2020, "OIL" ], [ - "R2", - 2030, + "R2-R1", + 2020, "winter", "night", - "E10", - "T_GSL", - 2025, - "VMT" + "ELC", + "E_TRANS", + 2015, + "ELC" ], [ "R2", 2025, - "winter", - "day", - "E10", - "T_GSL", + "summer", + "night", + "NG", + "E_NGCC", 2025, - "VMT" + "ELC" ], [ - "R2", + "R1", 2030, "winter", - "day", - "OIL", - "S_OILREF", + "night", + "URN", + "E_NUCLEAR", + 2030, + "ELC" + ], + [ + "R1", 2020, - "DSL" + "fall", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" ], [ "R1", 2030, - "summer", - "day", - "ELC", - "T_EV", + "spring", + "night", + "ethos", + "S_IMPETH", 2020, - "VMT" + "ETH" ], [ "R2", - 2025, - "spring", + 2020, + "summer", "night", - "SOL", - "E_SOLPV", - 2025, + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2030, + "summer", + "day", + "NG", + "E_NGCC", + 2020, "ELC" ], [ "R1", 2020, "spring", - "day", - "SOL", - "E_SOLPV", + "night", + "ethos", + "S_IMPETH", 2020, - "ELC" + "ETH" ], [ - "R2-R1", + "R2", 2025, "fall", "night", "ELC", - "E_TRANS", - 2015, + "E_BATT", + 2025, "ELC" ], [ "R1", - 2030, - "fall", + 2025, + "spring", "day", - "ELC", - "R_EH", - 2030, - "RH" + "OIL", + "S_OILREF", + 2020, + "DSL" ], [ "R2", 2030, - "winter", + "fall", "day", "NG", - "R_NGH", + "E_NGCC", 2020, - "RH" + "ELC" ], [ "R2", 2030, - "summer", + "winter", "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "fall", - "night", "NG", "E_NGCC", - 2020, + 2025, "ELC" ], [ - "R1", + "R2", 2030, - "winter", - "night", - "ELC", - "T_EV", + "summer", + "day", + "SOL", + "E_SOLPV", 2030, - "VMT" + "ELC" ], [ "R1", - 2020, - "winter", + 2030, + "summer", "night", - "SOL", - "E_SOLPV", + "URN", + "E_NUCLEAR", 2020, "ELC" ], @@ -33436,6 +23803,16 @@ "R1", 2025, "winter", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "fall", "night", "URN", "E_NUCLEAR", @@ -33443,9 +23820,9 @@ "ELC" ], [ - "R1", - 2030, - "spring", + "R2", + 2020, + "summer", "day", "OIL", "S_OILREF", @@ -33455,17 +23832,17 @@ [ "R2", 2030, - "winter", + "spring", "day", "ELC", - "T_EV", - 2030, - "VMT" + "E_BATT", + 2020, + "ELC" ], [ "R1", - 2020, - "spring", + 2030, + "fall", "night", "SOL", "E_SOLPV", @@ -33476,157 +23853,177 @@ "R2", 2025, "winter", - "night", - "SOL", - "E_SOLPV", + "day", + "NG", + "E_NGCC", 2025, "ELC" ], [ - "R1", + "R1-R2", 2030, - "fall", + "summer", "night", "ELC", - "R_EH", - 2030, - "RH" + "E_TRANS", + 2015, + "ELC" ], [ "R1", - 2030, - "spring", - "day", - "DSL", - "T_DSL", 2025, - "VMT" + "spring", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" ], [ - "R2", - 2025, - "summer", + "R1-R2", + 2030, + "winter", "night", - "SOL", - "E_SOLPV", - 2025, + "ELC", + "E_TRANS", + 2015, "ELC" ], + [ + "R2", + 2030, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], [ "R1", 2030, "spring", "day", - "ELC", - "T_EV", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1-R2", 2025, - "VMT" + "spring", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" ], [ "R1", 2025, "spring", - "day", - "URN", - "E_NUCLEAR", + "night", + "SOL", + "E_SOLPV", 2020, "ELC" ], [ "R2", - 2020, + 2030, "summer", "night", - "E10", - "T_GSL", - 2020, - "VMT" + "URN", + "E_NUCLEAR", + 2030, + "ELC" ], [ "R1", - 2025, - "summer", + 2030, + "spring", "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" + "URN", + "E_NUCLEAR", + 2025, + "ELC" ], [ - "R1", - 2025, - "summer", - "night", + "R2", + 2020, + "spring", + "day", "ETH", "T_BLND", 2020, "E10" ], [ - "R2", - 2025, + "R1", + 2030, "winter", "day", "ELC", - "R_EH", - 2025, - "RH" + "E_BATT", + 2020, + "ELC" ], [ "R1", - 2025, - "spring", - "night", - "NG", - "E_NGCC", + 2020, + "fall", + "day", + "SOL", + "E_SOLPV", 2020, "ELC" ], [ - "R2", - 2030, - "summer", + "R1", + 2020, + "fall", "day", - "ELC", - "T_EV", + "ethos", + "S_IMPOIL", 2020, - "VMT" + "OIL" ], [ - "R1", + "R2", 2030, - "summer", + "spring", "night", - "ETH", - "T_BLND", - 2020, - "E10" + "NG", + "E_NGCC", + 2025, + "ELC" ], [ "R1", 2030, - "spring", + "winter", "day", "URN", "E_NUCLEAR", - 2020, + 2015, "ELC" ], [ "R1", - 2025, - "summer", - "night", - "NG", - "R_NGH", 2020, - "RH" + "spring", + "day", + "GSL", + "T_BLND", + 2020, + "E10" ], [ "R1", - 2020, - "winter", - "night", + 2030, + "summer", + "day", "GSL", "T_BLND", 2020, @@ -33635,31 +24032,41 @@ [ "R2", 2025, - "spring", + "summer", "night", - "URN", - "E_NUCLEAR", + "ELC", + "E_BATT", 2020, "ELC" ], [ "R1", - 2020, + 2025, "summer", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "spring", "night", - "ethos", - "S_IMPNG", + "NG", + "E_NGCC", 2020, - "NG" + "ELC" ], [ - "R1-R2", - 2020, - "summer", + "R2", + 2030, + "winter", "night", "ELC", - "E_TRANS", - 2015, + "E_BATT", + 2030, "ELC" ], [ @@ -33667,176 +24074,146 @@ 2025, "winter", "night", - "NG", - "R_NGH", + "ELC", + "E_BATT", 2025, - "RH" - ], - [ - "R1", - 2030, - "fall", - "night", - "NG", - "E_NGCC", - 2030, "ELC" ], [ - "R1", + "R2", 2020, - "spring", + "fall", "night", - "NG", - "E_NGCC", - 2020, + "URN", + "E_NUCLEAR", + 2015, "ELC" ], [ - "R1", - 2020, - "spring", + "R2", + 2030, + "winter", "day", - "NG", - "R_NGH", + "ELC", + "E_BATT", 2020, - "RH" + "ELC" ], [ "R1", - 2025, - "summer", + 2020, + "fall", "night", - "SOL", - "E_SOLPV", + "NG", + "E_NGCC", 2020, "ELC" ], [ "R2", - 2030, - "spring", - "night", - "ELC", - "T_EV", 2025, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "SOL", - "E_SOLPV", - 2030, + "fall", + "day", + "URN", + "E_NUCLEAR", + 2020, "ELC" ], [ "R2", 2025, - "summer", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" + "winter", + "day", + "ETH", + "T_BLND", + 2020, + "E10" ], [ "R2", 2030, "fall", - "day", - "ethos", - "S_IMPETH", + "night", + "OIL", + "S_OILREF", 2020, - "ETH" + "DSL" ], [ "R2", - 2030, + 2025, "spring", "day", "URN", "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "NG", - "R_NGH", 2025, - "RH" + "ELC" ], [ "R2", 2025, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2015, + "fall", + "night", + "SOL", + "E_SOLPV", + 2020, "ELC" ], [ "R1", - 2030, - "summer", + 2025, + "fall", "night", - "NG", - "E_NGCC", - 2030, + "ELC", + "E_BATT", + 2025, "ELC" ], [ - "R2", + "R1", 2025, "spring", "day", - "NG", - "R_NGH", + "OIL", + "S_OILREF", 2020, - "RH" + "GSL" ], [ - "R1", - 2020, - "spring", + "R2", + 2030, + "winter", "day", - "E10", - "T_GSL", + "ETH", + "T_BLND", 2020, - "VMT" + "E10" ], [ - "R1", - 2030, - "summer", - "night", - "ethos", - "S_IMPURN", + "R2-R1", 2020, - "URN" + "winter", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" ], [ "R1", 2025, - "winter", + "spring", "day", - "ELC", - "T_EV", - 2020, - "VMT" + "URN", + "E_NUCLEAR", + 2015, + "ELC" ], [ - "R2", + "R1", 2025, - "fall", - "day", + "winter", + "night", "URN", "E_NUCLEAR", 2025, @@ -33845,87 +24222,127 @@ [ "R2", 2030, - "winter", - "day", - "E10", - "T_GSL", + "spring", + "night", + "ELC", + "E_BATT", 2025, - "VMT" + "ELC" ], [ - "R2", - 2030, + "R1", + 2025, "winter", - "night", + "day", "URN", "E_NUCLEAR", - 2020, + 2015, "ELC" ], [ "R1", 2025, - "summer", + "fall", "day", - "E10", - "T_GSL", - 2025, - "VMT" + "ELC", + "E_BATT", + 2020, + "ELC" ], [ "R1", + 2030, + "summer", + "day", + "OIL", + "S_OILREF", 2020, - "fall", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" + "GSL" ], [ "R1", - 2020, + 2025, "spring", "day", - "URN", - "E_NUCLEAR", - 2015, + "NG", + "E_NGCC", + 2020, "ELC" ], [ - "R2", - 2020, - "winter", + "R1", + 2025, + "summer", "night", - "NG", - "E_NGCC", + "SOL", + "E_SOLPV", 2020, "ELC" ], [ "R1", + 2025, + "fall", + "night", + "ETH", + "T_BLND", 2020, + "E10" + ], + [ + "R1", + 2030, "summer", "day", - "E10", - "T_GSL", + "SOL", + "E_SOLPV", 2020, - "VMT" + "ELC" ], [ "R1", 2025, - "summer", + "winter", "day", - "DSL", - "T_DSL", + "ethos", + "S_IMPURN", 2020, - "VMT" + "URN" ], [ - "R1", + "R2", 2030, "summer", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2030, + "spring", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "fall", + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2030, + "fall", "day", "URN", "E_NUCLEAR", @@ -33933,59 +24350,69 @@ "ELC" ], [ - "R2", - 2030, + "R1", + 2020, "spring", "day", - "ETH", - "T_BLND", + "ethos", + "S_IMPETH", 2020, - "E10" + "ETH" ], [ "R2", - 2020, + 2030, "fall", "day", - "DSL", - "T_DSL", - 2020, - "VMT" + "ELC", + "E_BATT", + 2025, + "ELC" ], [ "R2", 2020, - "winter", - "day", - "SOL", - "E_SOLPV", + "spring", + "night", + "NG", + "E_NGCC", 2020, "ELC" ], + [ + "R2", + 2030, + "fall", + "night", + "NG", + "E_NGCC", + 2030, + "ELC" + ], [ "R1", - 2020, - "spring", + 2030, + "fall", "night", - "OIL", - "S_OILREF", + "ethos", + "S_IMPETH", 2020, - "DSL" + "ETH" ], [ "R1", - 2020, - "fall", + 2030, + "spring", "day", - "NG", - "R_NGH", + "ethos", + "S_IMPURN", 2020, - "RH" + "URN" ], [ - "R1-R2", + "R2-R1", 2025, - "spring", + "fall", "night", "ELC", "E_TRANS", @@ -33994,89 +24421,69 @@ ], [ "R2", - 2030, - "summer", + 2025, + "spring", "day", - "SOL", - "E_SOLPV", - 2030, - "ELC" + "ethos", + "S_IMPETH", + 2020, + "ETH" ], [ - "R1", - 2025, + "R2", + 2020, "fall", "day", - "ELC", - "E_BATT", - 2025, + "URN", + "E_NUCLEAR", + 2020, "ELC" ], [ "R1", - 2030, - "summer", - "night", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "spring", + 2025, + "winter", "day", - "NG", - "R_NGH", - 2030, - "RH" + "ethos", + "S_IMPNG", + 2020, + "NG" ], [ "R2", - 2030, - "summer", + 2020, + "spring", "day", - "NG", - "R_NGH", + "GSL", + "T_BLND", 2020, - "RH" + "E10" ], [ - "R2", + "R1-R2", 2030, - "fall", - "night", + "summer", + "day", "ELC", - "R_EH", - 2030, - "RH" + "E_TRANS", + 2015, + "ELC" ], [ "R2", 2025, - "spring", + "summer", "night", - "ELC", - "R_EH", + "ethos", + "S_IMPURN", 2020, - "RH" + "URN" ], [ "R2", - 2030, - "fall", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", 2025, - "summer", - "night", + "spring", + "day", "OIL", "S_OILREF", 2020, @@ -34085,12 +24492,22 @@ [ "R1", 2030, - "spring", + "fall", "day", - "E10", - "T_GSL", + "URN", + "E_NUCLEAR", 2030, - "VMT" + "ELC" + ], + [ + "R1", + 2020, + "winter", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" ], [ "R1", @@ -34103,108 +24520,138 @@ "DSL" ], [ - "R2", - 2030, + "R2-R1", + 2020, "summer", "day", - "E10", - "T_GSL", - 2020, - "VMT" + "ELC", + "E_TRANS", + 2015, + "ELC" ], [ "R1", - 2030, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", 2020, - "winter", + "spring", "night", - "SOL", - "E_SOLPV", + "NG", + "E_NGCC", 2020, "ELC" ], [ "R1", 2030, - "summer", + "winter", "day", - "NG", - "E_NGCC", - 2030, + "SOL", + "E_SOLPV", + 2025, "ELC" ], + [ + "R2", + 2020, + "winter", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], [ "R2", 2030, - "fall", + "winter", "night", - "URN", - "E_NUCLEAR", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2-R1", 2030, + "spring", + "night", + "ELC", + "E_TRANS", + 2015, "ELC" ], [ - "R1", - 2030, - "winter", + "R2", + 2020, + "summer", "day", - "ELC", - "T_EV", - 2025, - "VMT" + "ethos", + "S_IMPURN", + 2020, + "URN" ], [ "R1", 2030, - "summer", + "winter", "night", "NG", - "R_NGH", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "night", + "ethos", + "S_IMPETH", 2020, - "RH" + "ETH" ], [ "R2", 2030, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2030, - "ELC" + "fall", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" ], [ - "R1", + "R2", 2025, - "spring", - "day", - "NG", - "R_NGH", + "winter", + "night", + "SOL", + "E_SOLPV", 2025, - "RH" + "ELC" ], [ "R2", - 2020, - "fall", + 2025, + "summer", "night", - "GSL", + "ETH", "T_BLND", 2020, "E10" ], [ - "R2-R1", + "R2", + 2030, + "spring", + "day", + "ethos", + "S_IMPNG", 2020, + "NG" + ], + [ + "R1-R2", + 2025, "winter", "day", "ELC", @@ -34213,32 +24660,42 @@ "ELC" ], [ - "R1", - 2025, - "winter", + "R2", + 2020, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2020, + "summer", "day", "ethos", - "S_IMPNG", + "S_IMPETH", 2020, - "NG" + "ETH" ], [ "R1", - 2030, + 2025, "spring", - "day", - "ELC", - "T_EV", + "night", + "ETH", + "T_BLND", 2020, - "VMT" + "E10" ], [ "R2", 2025, "winter", - "day", - "NG", - "E_NGCC", + "night", + "URN", + "E_NUCLEAR", 2025, "ELC" ], @@ -34246,116 +24703,96 @@ "R2", 2030, "fall", - "day", - "ELC", - "T_EV", - 2025, - "VMT" + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" ], [ "R2", 2030, - "summer", + "spring", "night", - "NG", - "E_NGCC", - 2030, + "SOL", + "E_SOLPV", + 2020, "ELC" ], [ "R2", - 2020, - "spring", + 2030, + "summer", "day", - "ethos", - "S_IMPURN", + "ETH", + "T_BLND", 2020, - "URN" + "E10" ], [ "R1", 2030, - "winter", - "day", - "SOL", - "E_SOLPV", - 2020, + "spring", + "night", + "ELC", + "E_BATT", + 2025, "ELC" ], [ "R2", - 2025, + 2030, "spring", "night", - "NG", - "E_NGCC", + "ethos", + "S_IMPURN", 2020, - "ELC" + "URN" ], [ - "R1", - 2030, - "winter", - "day", + "R2", + 2025, + "fall", + "night", "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1-R2", + "E_NGCC", 2025, - "summer", - "day", - "ELC", - "E_TRANS", - 2015, "ELC" ], [ - "R1", - 2020, - "winter", + "R2", + 2030, + "summer", "day", "URN", "E_NUCLEAR", - 2015, + 2020, "ELC" ], [ "R2", - 2025, - "summer", + 2020, + "winter", "day", - "ELC", - "R_EH", + "ethos", + "S_IMPOIL", 2020, - "RH" + "OIL" ], [ "R1", - 2025, + 2030, "winter", - "night", + "day", "ethos", "S_IMPETH", 2020, "ETH" ], [ - "R2", - 2020, - "winter", - "night", - "DSL", - "T_DSL", + "R1", 2020, - "VMT" - ], - [ - "R2", - 2025, - "winter", + "spring", "day", "URN", "E_NUCLEAR", @@ -34363,249 +24800,239 @@ "ELC" ], [ - "R2", + "R2-R1", 2030, - "winter", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "winter", + "fall", "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "night", - "URN", - "E_NUCLEAR", + "ELC", + "E_TRANS", 2015, "ELC" ], [ "R1", - 2020, + 2030, "summer", - "night", - "URN", - "E_NUCLEAR", - 2020, + "day", + "ELC", + "E_BATT", + 2030, "ELC" ], - [ - "R2", - 2025, - "summer", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], [ "R1", - 2030, - "fall", + 2020, + "spring", "day", - "DSL", - "T_DSL", + "ELC", + "E_BATT", 2020, - "VMT" + "ELC" ], [ "R2", - 2020, - "summer", + 2030, + "winter", "day", - "ELC", - "T_EV", + "ethos", + "S_IMPURN", 2020, - "VMT" + "URN" ], [ "R2", + 2025, + "winter", + "night", + "ethos", + "S_IMPETH", 2020, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" + "ETH" ], [ "R1", 2030, - "fall", + "summer", "day", "NG", "E_NGCC", - 2020, + 2025, "ELC" ], [ - "R2", - 2030, - "winter", + "R1-R2", + 2020, + "spring", "day", - "SOL", - "E_SOLPV", - 2030, + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1-R2", + 2020, + "summer", + "night", + "ELC", + "E_TRANS", + 2015, "ELC" ], [ "R2", 2025, - "summer", + "spring", "day", - "GSL", - "T_BLND", + "OIL", + "S_OILREF", 2020, - "E10" + "GSL" ], [ "R1", 2025, "fall", "night", - "ethos", - "S_IMPETH", + "OIL", + "S_OILREF", 2020, - "ETH" + "GSL" ], [ "R2", - 2025, - "summer", - "day", - "ELC", - "T_EV", 2020, - "VMT" + "summer", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" ], [ - "R2-R1", + "R1", 2030, "fall", "night", "ELC", - "E_TRANS", - 2015, + "E_BATT", + 2025, "ELC" ], [ "R1", - 2030, - "summer", + 2020, + "spring", "day", - "SOL", - "E_SOLPV", - 2030, - "ELC" + "ETH", + "T_BLND", + 2020, + "E10" ], [ "R2", 2030, "winter", - "day", - "ELC", - "T_EV", + "night", + "ETH", + "T_BLND", 2020, - "VMT" + "E10" ], [ - "R2", + "R1", 2025, "summer", "day", - "NG", - "E_NGCC", + "ETH", + "T_BLND", 2020, - "ELC" + "E10" ], [ "R2", - 2030, + 2020, "winter", - "day", - "E10", - "T_GSL", + "night", + "ethos", + "S_IMPURN", 2020, - "VMT" + "URN" ], [ - "R1", + "R2", 2020, + "summer", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2025, "fall", - "day", - "ELC", - "T_EV", + "night", + "ETH", + "T_BLND", 2020, - "VMT" + "E10" ], [ - "R1-R2", - 2030, - "spring", + "R2", + 2025, + "fall", "night", "ELC", - "E_TRANS", - 2015, + "E_BATT", + 2020, "ELC" ], [ "R1", - 2030, + 2020, "spring", "night", - "DSL", - "T_DSL", - 2025, - "VMT" + "OIL", + "S_OILREF", + 2020, + "DSL" ], [ "R1", - 2025, - "fall", + 2030, + "winter", "day", - "ETH", - "T_BLND", - 2020, - "E10" + "NG", + "E_NGCC", + 2025, + "ELC" ], [ "R1", 2020, - "fall", - "day", - "E10", - "T_GSL", + "winter", + "night", + "NG", + "E_NGCC", 2020, - "VMT" + "ELC" ], [ - "R1", - 2020, - "summer", + "R2", + 2025, + "winter", "day", "ELC", "E_BATT", - 2020, + 2025, "ELC" ], [ - "R1", + "R2", 2025, - "fall", + "winter", "night", "ETH", "T_BLND", @@ -34615,237 +25042,227 @@ [ "R2", 2030, - "winter", - "night", - "NG", - "E_NGCC", + "summer", + "day", + "SOL", + "E_SOLPV", 2025, "ELC" ], [ "R2", 2030, - "fall", - "day", - "NG", - "E_NGCC", + "spring", + "night", + "ethos", + "S_IMPETH", 2020, - "ELC" + "ETH" ], [ - "R1", - 2025, - "fall", + "R2", + 2030, + "spring", "day", - "E10", - "T_GSL", + "ethos", + "S_IMPURN", 2020, - "VMT" + "URN" ], [ - "R1", - 2030, + "R2", + 2025, "winter", "day", - "OIL", - "S_OILREF", + "NG", + "E_NGCC", 2020, - "DSL" + "ELC" ], [ - "R1", - 2020, - "fall", + "R2", + 2025, + "summer", "night", "ethos", - "S_IMPETH", + "S_IMPOIL", 2020, - "ETH" - ], - [ - "R1", - 2025, - "spring", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" + "OIL" ], [ - "R1", + "R2", 2025, - "spring", + "winter", "day", "ethos", - "S_IMPNG", + "S_IMPURN", 2020, - "NG" - ], - [ - "R1", - 2030, - "fall", - "night", - "DSL", - "T_DSL", - 2030, - "VMT" + "URN" ], [ - "R1", + "R2", 2030, - "spring", - "night", - "ELC", - "T_EV", - 2025, - "VMT" + "winter", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" ], [ - "R1", + "R2-R1", 2030, - "summer", - "night", + "spring", + "day", "ELC", - "R_EH", - 2025, - "RH" + "E_TRANS", + 2015, + "ELC" ], [ "R2", - 2025, + 2030, "fall", "day", - "NG", - "E_NGCC", + "ethos", + "S_IMPETH", 2020, - "ELC" + "ETH" ], [ - "R1", - 2030, - "winter", - "day", - "E10", - "T_GSL", + "R2", 2030, - "VMT" + "summer", + "night", + "URN", + "E_NUCLEAR", + 2025, + "ELC" ], [ - "R2", - 2020, - "fall", + "R1", + 2030, + "summer", "night", - "ETH", - "T_BLND", - 2020, - "E10" + "ELC", + "E_BATT", + 2030, + "ELC" ], [ "R1", - 2025, - "fall", + 2030, + "spring", "night", - "SOL", - "E_SOLPV", + "URN", + "E_NUCLEAR", 2020, "ELC" ], [ "R2", - 2020, - "fall", - "night", + 2030, + "summer", + "day", "OIL", "S_OILREF", 2020, "DSL" ], [ - "R1", + "R2", 2030, - "fall", + "summer", + "night", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "summer", "day", - "OIL", - "S_OILREF", - 2020, - "DSL" + "NG", + "E_NGCC", + 2025, + "ELC" ], [ "R2", - 2025, + 2030, "spring", "night", - "OIL", - "S_OILREF", + "NG", + "E_NGCC", 2020, - "GSL" + "ELC" ], [ - "R2", + "R1", 2030, - "summer", + "spring", "day", - "ethos", - "S_IMPOIL", + "GSL", + "T_BLND", 2020, - "OIL" + "E10" ], [ - "R2-R1", - 2020, - "spring", + "R1", + 2025, + "summer", "day", "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", + "E_BATT", 2020, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2015, "ELC" ], [ - "R2", + "R1", 2025, - "fall", + "spring", "night", - "OIL", - "S_OILREF", + "ethos", + "S_IMPURN", 2020, - "DSL" + "URN" ], [ "R2", 2030, "winter", - "day", - "DSL", - "T_DSL", + "night", + "ELC", + "E_BATT", 2025, - "VMT" + "ELC" ], [ "R1", 2025, + "summer", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", + 2025, "winter", "night", "ELC", - "T_EV", - 2025, - "VMT" + "E_BATT", + 2020, + "ELC" ], [ "R1", 2030, - "summer", + "fall", "day", "NG", "E_NGCC", @@ -34853,159 +25270,129 @@ "ELC" ], [ - "R1", + "R2", 2030, "fall", - "night", - "OIL", - "S_OILREF", + "day", + "ETH", + "T_BLND", 2020, - "GSL" + "E10" ], [ - "R1-R2", - 2025, + "R1", + 2030, "fall", "night", - "ELC", - "E_TRANS", - 2015, - "ELC" + "GSL", + "T_BLND", + 2020, + "E10" ], [ "R1", 2030, - "winter", - "day", + "fall", + "night", "URN", "E_NUCLEAR", - 2025, + 2030, "ELC" ], [ "R2", 2030, - "spring", + "fall", "night", - "ethos", - "S_IMPNG", + "GSL", + "T_BLND", 2020, - "NG" + "E10" ], [ - "R2", + "R1-R2", 2025, - "spring", + "winter", "night", - "DSL", - "T_DSL", - 2025, - "VMT" + "ELC", + "E_TRANS", + 2015, + "ELC" ], [ "R1", - 2030, + 2020, "winter", "day", - "ELC", - "T_EV", + "ethos", + "S_IMPOIL", 2020, - "VMT" + "OIL" ], [ "R2", - 2030, + 2025, "spring", - "night", - "SOL", - "E_SOLPV", + "day", + "URN", + "E_NUCLEAR", 2020, "ELC" ], [ "R2", - 2030, - "summer", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "winter", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", 2020, - "spring", + "winter", "day", - "ELC", - "T_EV", + "NG", + "E_NGCC", 2020, - "VMT" + "ELC" ], [ - "R1", - 2030, - "fall", - "day", - "E10", - "T_GSL", + "R2-R1", 2030, - "VMT" + "winter", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" ], [ "R1", 2030, "winter", - "day", - "ELC", - "E_BATT", - 2030, + "night", + "URN", + "E_NUCLEAR", + 2025, "ELC" ], [ "R1", - 2025, - "spring", + 2030, + "fall", "day", - "E10", - "T_GSL", + "ELC", + "E_BATT", 2020, - "VMT" + "ELC" ], [ "R1", 2025, - "summer", + "fall", "night", - "ethos", - "S_IMPURN", + "ELC", + "E_BATT", 2020, - "URN" + "ELC" ], [ - "R2", + "R1", 2020, - "summer", + "spring", "night", "OIL", "S_OILREF", @@ -35013,112 +25400,102 @@ "GSL" ], [ - "R1", - 2025, - "fall", + "R2", + 2020, + "spring", "night", - "ELC", - "T_EV", - 2025, - "VMT" + "ethos", + "S_IMPURN", + 2020, + "URN" ], [ "R1", 2030, "summer", "night", - "ELC", - "T_EV", - 2025, - "VMT" + "ethos", + "S_IMPETH", + 2020, + "ETH" ], [ "R2", 2025, "summer", - "night", - "OIL", - "S_OILREF", + "day", + "ethos", + "S_IMPURN", 2020, - "GSL" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" + "URN" ], [ - "R2", - 2025, + "R1", + 2020, "fall", - "night", + "day", "URN", "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1-R2", 2025, + "summer", + "day", + "ELC", + "E_TRANS", + 2015, "ELC" ], [ - "R2", - 2020, + "R1", + 2025, "winter", "night", - "ethos", - "S_IMPOIL", + "URN", + "E_NUCLEAR", 2020, - "OIL" + "ELC" ], [ "R2", - 2025, + 2030, "spring", - "day", + "night", "ELC", "E_BATT", - 2025, + 2020, "ELC" ], [ - "R2", - 2025, + "R1", + 2020, "winter", "night", "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", + "S_IMPNG", 2020, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" + "NG" ], [ "R1", 2030, - "spring", - "day", - "OIL", - "S_OILREF", + "winter", + "night", + "ethos", + "S_IMPETH", 2020, - "DSL" + "ETH" ], [ - "R1", + "R2", 2030, - "summer", + "fall", "night", - "SOL", - "E_SOLPV", + "URN", + "E_NUCLEAR", 2020, "ELC" ], @@ -35126,137 +25503,147 @@ "R2", 2025, "summer", - "day", - "URN", - "E_NUCLEAR", - 2015, + "night", + "NG", + "E_NGCC", + 2020, "ELC" ], [ "R1", 2030, - "spring", + "fall", "night", - "ELC", - "R_EH", - 2030, - "RH" + "ethos", + "S_IMPNG", + 2020, + "NG" ], [ "R1", - 2020, + 2030, "fall", "night", - "NG", - "R_NGH", + "ethos", + "S_IMPURN", 2020, - "RH" + "URN" ], [ "R2", - 2030, + 2020, "summer", "night", - "ELC", - "T_EV", - 2025, - "VMT" + "ETH", + "T_BLND", + 2020, + "E10" ], [ "R2", 2030, - "summer", + "fall", "day", - "ethos", - "S_IMPNG", + "ELC", + "E_BATT", 2020, - "NG" + "ELC" + ], + [ + "R1", + 2020, + "winter", + "day", + "GSL", + "T_BLND", + 2020, + "E10" ], [ "R2", 2030, "fall", "night", - "E10", - "T_GSL", - 2025, - "VMT" + "SOL", + "E_SOLPV", + 2030, + "ELC" ], [ "R2", - 2025, + 2030, "summer", "day", - "E10", - "T_GSL", - 2025, - "VMT" + "OIL", + "S_OILREF", + 2020, + "GSL" ], [ "R2", 2030, - "spring", - "day", - "ELC", - "R_EH", + "winter", + "night", + "NG", + "E_NGCC", 2030, - "RH" + "ELC" + ], + [ + "R1", + 2030, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2025, + "winter", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" ], [ "R2", 2025, - "summer", - "night", + "fall", + "day", "URN", "E_NUCLEAR", - 2020, + 2025, "ELC" ], [ "R2", 2030, - "winter", + "spring", "night", - "ethos", - "S_IMPOIL", + "ETH", + "T_BLND", 2020, - "OIL" + "E10" ], [ "R2", - 2030, - "spring", - "day", - "ELC", - "T_EV", 2020, - "VMT" - ], - [ - "R2", - 2025, "fall", "day", - "GSL", - "T_BLND", - 2020, - "E10" + "URN", + "E_NUCLEAR", + 2015, + "ELC" ], [ "R2", - 2025, - "fall", + 2030, + "winter", "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "night", "NG", "E_NGCC", 2020, @@ -35265,137 +25652,137 @@ [ "R1", 2030, - "winter", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "winter", + "summer", "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2020, - "spring", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" + "URN", + "E_NUCLEAR", + 2015, + "ELC" ], [ "R1", 2020, "summer", "day", - "OIL", - "S_OILREF", + "SOL", + "E_SOLPV", 2020, - "GSL" + "ELC" ], [ "R2", 2030, - "fall", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" + "winter", + "night", + "URN", + "E_NUCLEAR", + 2025, + "ELC" ], [ - "R2", - 2030, - "summer", - "day", - "ELC", - "R_EH", + "R1", 2030, - "RH" + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" ], [ "R1", - 2030, - "spring", + 2025, + "fall", "night", "NG", "E_NGCC", - 2030, + 2025, "ELC" ], [ - "R2", + "R1", 2030, - "summer", + "winter", "night", - "NG", - "E_NGCC", - 2020, + "SOL", + "E_SOLPV", + 2030, "ELC" ], [ "R1", - 2025, - "winter", + 2020, + "spring", "night", - "DSL", - "T_DSL", + "ETH", + "T_BLND", 2020, - "VMT" + "E10" ], [ - "R2", - 2025, - "spring", + "R1", + 2020, + "summer", "day", - "ELC", - "R_EH", + "URN", + "E_NUCLEAR", 2020, - "RH" + "ELC" ], [ "R2", 2030, - "spring", - "day", - "NG", - "E_NGCC", - 2030, - "ELC" + "winter", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" ], [ "R1", 2030, "fall", - "night", - "NG", - "R_NGH", + "day", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R1", 2030, - "RH" + "winter", + "day", + "SOL", + "E_SOLPV", + 2020, + "ELC" ], [ "R1", 2020, - "spring", - "night", - "NG", - "R_NGH", + "winter", + "day", + "SOL", + "E_SOLPV", 2020, - "RH" + "ELC" ], [ "R1", 2030, - "fall", + "spring", + "night", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R2", + 2020, + "winter", "night", "ELC", "E_BATT", @@ -35403,169 +25790,179 @@ "ELC" ], [ - "R2", - 2025, + "R1", + 2020, "winter", - "night", - "OIL", - "S_OILREF", + "day", + "URN", + "E_NUCLEAR", 2020, - "GSL" + "ELC" ], [ "R2", - 2025, - "winter", + 2020, + "spring", "night", - "DSL", - "T_DSL", - 2025, - "VMT" + "ethos", + "S_IMPETH", + 2020, + "ETH" ], [ "R2", 2025, "winter", "night", - "ELC", - "T_EV", - 2025, - "VMT" + "SOL", + "E_SOLPV", + 2020, + "ELC" ], [ "R2", 2025, "winter", "night", - "E10", - "T_GSL", - 2025, - "VMT" + "GSL", + "T_BLND", + 2020, + "E10" ], [ "R2", 2025, - "spring", - "night", + "winter", + "day", "ethos", "S_IMPETH", 2020, - "ETH" - ], - [ - "R2", - 2020, - "spring", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" + "ETH" ], [ - "R2-R1", + "R2", 2030, "winter", "night", - "ELC", - "E_TRANS", + "URN", + "E_NUCLEAR", 2015, "ELC" ], [ "R1", - 2030, + 2025, "summer", "night", - "E10", - "T_GSL", - 2030, - "VMT" + "NG", + "E_NGCC", + 2025, + "ELC" ], [ "R2", - 2030, - "summer", + 2025, + "fall", "day", - "ELC", - "T_EV", - 2030, - "VMT" + "SOL", + "E_SOLPV", + 2025, + "ELC" ], [ "R2", + 2025, + "winter", + "night", + "URN", + "E_NUCLEAR", 2020, - "spring", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" + "ELC" ], [ "R1", 2025, - "fall", + "summer", "day", - "DSL", - "T_DSL", + "ethos", + "S_IMPOIL", 2020, - "VMT" + "OIL" ], [ - "R2", - 2030, + "R1", + 2020, "summer", "night", - "DSL", - "T_DSL", - 2025, - "VMT" + "NG", + "E_NGCC", + 2020, + "ELC" ], [ "R2", 2030, - "winter", + "spring", "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2025, + "fall", + "night", "ethos", - "S_IMPETH", + "S_IMPNG", 2020, - "ETH" + "NG" ], [ - "R2", - 2030, + "R1", + 2025, "fall", - "day", - "DSL", - "T_DSL", + "night", + "ethos", + "S_IMPURN", 2020, - "VMT" + "URN" ], [ - "R2", + "R1", 2030, - "fall", - "day", + "spring", + "night", "ELC", "E_BATT", - 2030, + 2020, "ELC" ], [ "R2", 2025, + "fall", + "night", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + 2020, "spring", - "day", - "E10", - "T_GSL", + "night", + "ethos", + "S_IMPNG", 2020, - "VMT" + "NG" ], [ "R1", 2020, - "winter", + "summer", "night", "ethos", "S_IMPOIL", @@ -35573,19 +25970,19 @@ "OIL" ], [ - "R1", - 2025, - "spring", + "R2", + 2030, + "summer", "day", - "ELC", - "E_BATT", - 2025, + "URN", + "E_NUCLEAR", + 2015, "ELC" ], [ - "R2", + "R1", 2025, - "fall", + "winter", "night", "NG", "E_NGCC", @@ -35593,9 +25990,9 @@ "ELC" ], [ - "R2", - 2030, - "fall", + "R1", + 2020, + "spring", "day", "URN", "E_NUCLEAR", @@ -35604,18 +26001,8 @@ ], [ "R1", - 2020, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", 2025, - "summer", + "fall", "day", "ethos", "S_IMPOIL", @@ -35624,228 +26011,308 @@ ], [ "R1", - 2025, - "fall", + 2030, + "summer", "day", "ELC", - "T_EV", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "night", + "ETH", + "T_BLND", 2020, - "VMT" + "E10" + ], + [ + "R1", + 2030, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" ], [ "R2", 2030, "winter", "night", - "SOL", - "E_SOLPV", - 2030, - "ELC" + "ethos", + "S_IMPETH", + 2020, + "ETH" ], [ "R2", - 2030, + 2020, "spring", "day", - "URN", - "E_NUCLEAR", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2020, + "spring", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2020, + "summer", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2025, + "spring", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2020, + "spring", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2020, + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", 2030, + "summer", + "day", + "NG", + "E_NGCC", + 2020, "ELC" ], [ "R1", 2030, - "spring", + "summer", "day", - "SOL", - "E_SOLPV", + "ethos", + "S_IMPURN", 2020, - "ELC" + "URN" ], [ "R2", 2025, - "winter", + "spring", "night", - "NG", - "E_NGCC", - 2020, + "URN", + "E_NUCLEAR", + 2025, "ELC" ], [ "R2", - 2025, + 2030, "summer", "day", "ELC", "E_BATT", - 2025, + 2030, "ELC" ], [ - "R1", - 2030, - "spring", + "R2", + 2025, + "fall", "night", - "ELC", - "E_BATT", + "ethos", + "S_IMPOIL", 2020, - "ELC" + "OIL" ], [ - "R1", + "R2", 2025, - "summer", - "night", + "fall", + "day", "ethos", "S_IMPETH", 2020, "ETH" ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "R_EH", - 2030, - "RH" - ], [ "R2", 2030, - "summer", + "spring", "night", "ethos", - "S_IMPURN", + "S_IMPOIL", 2020, - "URN" + "OIL" ], [ - "R2", + "R1", 2030, - "winter", + "fall", "night", "ELC", "E_BATT", - 2030, + 2020, "ELC" ], [ "R1", - 2025, - "summer", + 2030, + "spring", "day", "ELC", "E_BATT", - 2025, + 2020, "ELC" ], [ - "R1", + "R1-R2", + 2020, + "fall", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R2", 2025, "summer", "day", - "GSL", - "T_BLND", + "OIL", + "S_OILREF", 2020, - "E10" + "DSL" ], [ - "R1", + "R2-R1", 2030, - "spring", + "summer", "night", "ELC", - "R_EH", - 2025, - "RH" + "E_TRANS", + 2015, + "ELC" ], [ "R2", - 2030, + 2025, "summer", "night", - "ELC", - "T_EV", + "ethos", + "S_IMPNG", 2020, - "VMT" + "NG" ], [ - "R1", + "R2", 2030, - "summer", - "day", - "ELC", - "E_BATT", + "fall", + "night", + "NG", + "E_NGCC", 2025, "ELC" ], [ - "R1", - 2030, + "R2", + 2025, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R2", + 2020, "summer", "day", - "NG", - "R_NGH", - 2030, - "RH" + "URN", + "E_NUCLEAR", + 2020, + "ELC" ], [ "R2", 2020, - "winter", + "fall", "day", - "ELC", - "E_BATT", + "SOL", + "E_SOLPV", 2020, "ELC" ], [ "R2", 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" + "fall", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" ], [ - "R1", + "R2", 2020, "winter", "day", - "OIL", - "S_OILREF", + "GSL", + "T_BLND", 2020, - "GSL" + "E10" ], [ - "R1", - 2030, - "spring", - "night", - "SOL", - "E_SOLPV", + "R2", 2020, + "winter", + "night", + "URN", + "E_NUCLEAR", + 2015, "ELC" ], [ "R1", 2030, - "spring", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2025, - "summer", + "winter", "day", "NG", "E_NGCC", @@ -35854,13 +26321,13 @@ ], [ "R2", - 2025, - "summer", - "day", - "E10", - "T_GSL", + 2030, + "winter", + "night", + "SOL", + "E_SOLPV", 2020, - "VMT" + "ELC" ], [ "R2", @@ -35868,102 +26335,132 @@ "fall", "day", "ethos", - "S_IMPOIL", + "S_IMPURN", 2020, - "OIL" + "URN" ], [ - "R2", + "R1", 2025, - "fall", - "day", - "SOL", - "E_SOLPV", + "spring", + "night", + "ELC", + "E_BATT", 2025, "ELC" ], [ "R1", 2025, - "spring", - "night", + "fall", + "day", "NG", - "R_NGH", + "E_NGCC", 2025, - "RH" + "ELC" + ], + [ + "R2", + 2025, + "summer", + "day", + "GSL", + "T_BLND", + 2020, + "E10" ], [ "R2", 2030, - "spring", + "winter", "day", - "E10", - "T_GSL", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", 2030, - "VMT" + "summer", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" ], [ "R1", 2030, - "fall", + "summer", "night", - "GSL", - "T_BLND", - 2020, - "E10" + "ELC", + "E_BATT", + 2025, + "ELC" ], [ - "R2", + "R1", 2030, - "winter", - "day", - "ETH", - "T_BLND", - 2020, - "E10" + "spring", + "night", + "URN", + "E_NUCLEAR", + 2015, + "ELC" ], [ "R1", 2025, - "winter", - "night", + "spring", + "day", "ELC", - "R_EH", + "E_BATT", 2025, - "RH" + "ELC" ], [ "R2", 2020, - "spring", + "winter", "night", - "OIL", - "S_OILREF", + "ethos", + "S_IMPOIL", 2020, - "GSL" + "OIL" ], [ - "R2", + "R1", 2025, - "fall", + "summer", "day", - "E10", - "T_GSL", + "NG", + "E_NGCC", 2020, - "VMT" + "ELC" ], [ "R1", 2030, - "fall", + "spring", "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" + "ethos", + "S_IMPURN", + 2020, + "URN" ], [ "R2", + 2025, + "winter", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R1", 2020, "spring", "night", @@ -35972,10 +26469,20 @@ 2020, "URN" ], + [ + "R1", + 2025, + "summer", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], [ "R1-R2", - 2030, - "winter", + 2025, + "fall", "day", "ELC", "E_TRANS", @@ -35983,60 +26490,40 @@ "ELC" ], [ - "R1", - 2025, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", + "R2", 2020, - "spring", + "summer", "night", - "ELC", - "R_EH", + "OIL", + "S_OILREF", 2020, - "RH" + "GSL" ], [ "R1", - 2020, - "winter", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", 2025, - "spring", + "fall", "night", - "ELC", - "T_EV", + "URN", + "E_NUCLEAR", 2025, - "VMT" + "ELC" ], [ - "R2", + "R1", 2030, - "summer", + "fall", "day", - "NG", - "R_NGH", - 2030, - "RH" + "ethos", + "S_IMPOIL", + 2020, + "OIL" ], [ "R1", 2030, "winter", - "night", + "day", "NG", "E_NGCC", 2030, @@ -36044,58 +26531,48 @@ ], [ "R1", - 2030, - "fall", + 2020, + "summer", "night", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "ELC", - "R_EH", + "OIL", + "S_OILREF", 2020, - "RH" + "DSL" ], [ - "R2", - 2030, - "summer", - "day", - "ELC", - "E_BATT", + "R1-R2", 2020, + "fall", + "night", + "ELC", + "E_TRANS", + 2015, "ELC" ], [ "R2", 2020, - "winter", + "spring", "day", - "ethos", - "S_IMPOIL", + "NG", + "E_NGCC", 2020, - "OIL" + "ELC" ], [ - "R2", + "R1", 2030, "fall", "night", - "OIL", - "S_OILREF", - 2020, - "GSL" + "URN", + "E_NUCLEAR", + 2025, + "ELC" ], [ "R2", - 2030, - "winter", + 2025, + "summer", "day", "OIL", "S_OILREF", @@ -36107,119 +26584,89 @@ 2025, "winter", "day", - "ethos", - "S_IMPURN", - 2020, - "URN" + "NG", + "E_NGCC", + 2025, + "ELC" ], [ - "R1-R2", + "R1", + 2025, + "summer", + "night", + "ethos", + "S_IMPNG", 2020, - "winter", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" + "NG" ], [ "R2", 2025, - "fall", - "night", - "E10", - "T_GSL", + "winter", + "day", + "OIL", + "S_OILREF", 2020, - "VMT" + "GSL" ], [ "R1", 2030, - "spring", + "winter", "night", - "NG", - "E_NGCC", - 2025, + "URN", + "E_NUCLEAR", + 2020, "ELC" ], [ "R2", - 2030, - "winter", - "day", - "ethos", - "S_IMPURN", 2020, - "URN" - ], - [ - "R2", - 2025, - "winter", + "fall", "night", - "ELC", - "E_BATT", + "GSL", + "T_BLND", 2020, - "ELC" + "E10" ], [ "R1", 2025, "summer", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1-R2", - 2030, - "summer", "night", "ELC", - "E_TRANS", - 2015, + "E_BATT", + 2025, "ELC" ], [ "R1", 2020, - "spring", - "night", - "GSL", + "summer", + "day", + "ETH", "T_BLND", 2020, "E10" ], [ "R1", - 2025, - "fall", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", 2020, - "winter", + "fall", "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" + "URN", + "E_NUCLEAR", + 2015, + "ELC" ], [ "R1", 2025, "winter", "night", - "NG", - "E_NGCC", - 2025, + "URN", + "E_NUCLEAR", + 2015, "ELC" ], [ @@ -36227,105 +26674,85 @@ 2030, "summer", "night", - "ELC", - "E_BATT", - 2020, + "NG", + "E_NGCC", + 2030, "ELC" ], [ - "R1", + "R2", 2030, "summer", "day", - "ELC", - "R_EH", + "SOL", + "E_SOLPV", 2020, - "RH" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC", - "T_EV", - 2025, - "VMT" + "ELC" ], [ "R1", - 2020, + 2025, "spring", "night", "ethos", - "S_IMPOIL", + "S_IMPNG", 2020, - "OIL" + "NG" ], [ "R2", - 2020, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2020, + 2030, + "spring", + "day", + "ELC", + "E_BATT", + 2030, "ELC" ], [ - "R1", - 2020, - "spring", - "night", - "ETH", - "T_BLND", - 2020, - "E10" + "R2", + 2030, + "winter", + "day", + "SOL", + "E_SOLPV", + 2030, + "ELC" ], [ "R1", 2030, - "fall", - "day", + "summer", + "night", "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "spring", - "day", - "ELC", - "E_BATT", - 2020, + "E_NGCC", + 2030, "ELC" ], [ "R2", - 2025, - "winter", + 2030, + "summer", "night", - "ELC", - "T_EV", + "ethos", + "S_IMPETH", 2020, - "VMT" + "ETH" ], [ - "R1", + "R2", 2030, - "winter", + "summer", "day", - "GSL", - "T_BLND", + "ethos", + "S_IMPURN", 2020, - "E10" + "URN" ], [ "R1", 2025, - "spring", + "fall", "day", "OIL", "S_OILREF", @@ -36333,173 +26760,153 @@ "GSL" ], [ - "R1", - 2025, - "spring", + "R2", + 2020, + "summer", "day", - "NG", - "E_NGCC", + "ELC", + "E_BATT", 2020, "ELC" ], [ "R1", - 2025, - "summer", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", 2030, - "fall", + "summer", "day", "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2020, - "summer", - "night", - "GSL", - "T_BLND", + "S_IMPETH", 2020, - "E10" + "ETH" ], [ "R2", 2030, - "spring", + "winter", "night", - "ETH", - "T_BLND", - 2020, - "E10" + "NG", + "E_NGCC", + 2025, + "ELC" ], [ "R1", 2025, - "summer", - "night", - "NG", - "R_NGH", + "fall", + "day", + "URN", + "E_NUCLEAR", 2025, - "RH" + "ELC" ], [ - "R1", + "R2", 2030, - "winter", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" + "spring", + "night", + "URN", + "E_NUCLEAR", + 2030, + "ELC" ], [ "R1", 2025, - "fall", - "day", - "NG", - "R_NGH", + "winter", + "night", + "ELC", + "E_BATT", 2020, - "RH" + "ELC" ], [ "R2", - 2030, - "fall", + 2025, + "winter", "day", "ELC", "E_BATT", - 2025, + 2020, "ELC" ], [ "R2", 2030, - "winter", + "summer", "night", "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "NG", - "R_NGH", + "E_NGCC", 2020, - "RH" + "ELC" ], [ "R2", - 2020, + 2030, "fall", - "day", - "GSL", - "T_BLND", - 2020, - "E10" + "night", + "ELC", + "E_BATT", + 2030, + "ELC" ], [ "R2", 2030, - "spring", - "day", - "DSL", - "T_DSL", - 2030, - "VMT" + "winter", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" ], [ - "R1", - 2020, - "spring", - "day", - "OIL", - "S_OILREF", + "R1", + 2025, + "fall", + "night", + "NG", + "E_NGCC", 2020, - "GSL" + "ELC" ], [ "R1", 2030, - "summer", + "fall", "day", - "ethos", - "S_IMPOIL", + "GSL", + "T_BLND", 2020, - "OIL" + "E10" ], [ "R1", 2025, - "spring", + "winter", "night", - "ethos", - "S_IMPNG", + "OIL", + "S_OILREF", 2020, - "NG" + "DSL" ], [ "R1", 2025, "spring", + "day", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "winter", "night", - "ELC", - "E_BATT", - 2020, + "SOL", + "E_SOLPV", + 2025, "ELC" ], [ @@ -36507,94 +26914,84 @@ 2030, "summer", "day", - "DSL", - "T_DSL", - 2020, - "VMT" + "URN", + "E_NUCLEAR", + 2030, + "ELC" ], [ - "R1", + "R2", 2030, - "summer", + "fall", "day", - "ETH", + "GSL", "T_BLND", 2020, "E10" ], [ - "R1", - 2020, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "spring", + "R2", + 2030, + "summer", "night", "SOL", "E_SOLPV", - 2020, + 2030, "ELC" ], [ "R1", - 2030, + 2020, "summer", - "day", - "E10", - "T_GSL", + "night", + "OIL", + "S_OILREF", 2020, - "VMT" + "GSL" ], [ - "R1", + "R1-R2", 2030, "spring", - "night", - "URN", - "E_NUCLEAR", - 2025, + "day", + "ELC", + "E_TRANS", + 2015, "ELC" ], [ - "R2", + "R1", 2030, - "summer", + "spring", "night", - "URN", - "E_NUCLEAR", - 2015, + "SOL", + "E_SOLPV", + 2020, "ELC" ], [ - "R2", + "R1", 2030, "spring", - "night", - "E10", - "T_GSL", - 2020, - "VMT" + "day", + "NG", + "E_NGCC", + 2030, + "ELC" ], [ - "R2", - 2025, - "fall", + "R1", + 2030, + "summer", "day", - "ELC", - "T_EV", + "ETH", + "T_BLND", 2020, - "VMT" + "E10" ], [ "R2", - 2025, + 2020, "spring", "night", "OIL", @@ -36602,179 +26999,149 @@ 2020, "DSL" ], - [ - "R2", - 2030, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], [ "R1", 2020, - "summer", + "spring", "day", "ethos", - "S_IMPOIL", + "S_IMPNG", 2020, - "OIL" + "NG" ], [ "R1", + 2030, + "spring", + "night", + "ethos", + "S_IMPNG", 2020, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" + "NG" ], [ "R2", 2025, - "fall", + "spring", "day", - "NG", - "R_NGH", + "ethos", + "S_IMPNG", 2020, - "RH" + "NG" ], [ "R1", 2020, - "summer", + "fall", "night", "ethos", - "S_IMPETH", + "S_IMPOIL", 2020, - "ETH" + "OIL" ], [ "R1", - 2020, - "winter", + 2025, + "summer", "night", - "ELC", - "E_BATT", + "NG", + "E_NGCC", 2020, "ELC" ], [ "R1", - 2030, + 2020, "fall", - "night", - "OIL", - "S_OILREF", + "day", + "ethos", + "S_IMPETH", 2020, - "DSL" - ], - [ - "R1", - 2030, - "winter", - "night", - "DSL", - "T_DSL", - 2030, - "VMT" + "ETH" ], [ "R2", 2025, - "winter", + "spring", "day", - "DSL", - "T_DSL", + "ELC", + "E_BATT", 2025, - "VMT" + "ELC" ], [ "R2", - 2030, - "summer", + 2025, + "spring", "night", - "ethos", - "S_IMPOIL", + "ETH", + "T_BLND", 2020, - "OIL" + "E10" ], [ - "R1", + "R2", 2030, "winter", "night", - "SOL", - "E_SOLPV", + "ELC", + "E_BATT", 2020, "ELC" ], [ "R2", - 2030, - "winter", - "day", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, + 2025, "fall", - "night", - "NG", - "R_NGH", + "day", + "SOL", + "E_SOLPV", 2020, - "RH" + "ELC" ], [ "R2", - 2020, - "spring", + 2025, + "winter", "night", - "ELC", - "E_BATT", - 2020, + "URN", + "E_NUCLEAR", + 2015, "ELC" ], [ - "R2", + "R1", 2020, - "winter", + "summer", "day", "OIL", "S_OILREF", 2020, - "GSL" + "DSL" ], [ - "R1", - 2020, - "spring", + "R2", + 2025, + "winter", "day", "URN", "E_NUCLEAR", - 2020, + 2025, "ELC" ], [ - "R2", + "R1", 2030, - "summer", + "fall", "day", - "DSL", - "T_DSL", - 2030, - "VMT" + "NG", + "E_NGCC", + 2020, + "ELC" ], [ "R2", - 2030, + 2020, "summer", "day", "ETH", @@ -36783,69 +27150,59 @@ "E10" ], [ - "R2", - 2020, + "R1", + 2030, "winter", "day", - "ethos", - "S_IMPURN", + "ETH", + "T_BLND", 2020, - "URN" + "E10" ], [ - "R2", - 2025, - "spring", - "night", - "NG", - "R_NGH", + "R1", 2025, - "RH" - ], - [ - "R2", - 2030, "spring", "day", - "E10", - "T_GSL", - 2025, - "VMT" + "ethos", + "S_IMPETH", + 2020, + "ETH" ], [ - "R2", + "R1", 2020, - "summer", - "night", - "OIL", - "S_OILREF", + "fall", + "day", + "NG", + "E_NGCC", 2020, - "DSL" + "ELC" ], [ - "R1", + "R2", 2025, - "spring", + "fall", "night", "ethos", - "S_IMPURN", + "S_IMPNG", 2020, - "URN" + "NG" ], [ "R1", - 2030, + 2025, "winter", "night", - "ELC", - "E_BATT", - 2030, + "NG", + "E_NGCC", + 2020, "ELC" ], [ "R2", - 2025, - "summer", + 2020, + "fall", "night", "OIL", "S_OILREF", @@ -36853,39 +27210,29 @@ "DSL" ], [ - "R1", - 2020, - "winter", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", + "R2", 2030, "fall", "night", "SOL", "E_SOLPV", - 2020, + 2025, "ELC" ], [ - "R2", + "R1", 2030, - "fall", + "spring", "day", - "ELC", - "R_EH", + "ethos", + "S_IMPOIL", 2020, - "RH" + "OIL" ], [ "R1-R2", - 2025, - "summer", + 2020, + "spring", "night", "ELC", "E_TRANS", @@ -36893,70 +27240,60 @@ "ELC" ], [ - "R2", - 2020, + "R1", + 2025, "winter", - "night", - "ethos", - "S_IMPNG", + "day", + "OIL", + "S_OILREF", 2020, - "NG" + "DSL" ], [ "R2", 2025, - "fall", + "spring", "night", - "SOL", - "E_SOLPV", - 2025, + "URN", + "E_NUCLEAR", + 2020, "ELC" ], [ "R1", - 2030, - "spring", - "day", - "ELC", - "E_BATT", 2025, - "ELC" - ], - [ - "R2", - 2020, - "summer", + "winter", "night", - "ELC", - "E_BATT", + "OIL", + "S_OILREF", 2020, - "ELC" + "GSL" ], [ "R1", - 2030, + 2025, "winter", "night", "ethos", - "S_IMPETH", + "S_IMPURN", 2020, - "ETH" + "URN" ], [ "R2", 2030, - "fall", - "night", + "summer", + "day", "ELC", - "T_EV", + "E_BATT", 2025, - "VMT" + "ELC" ], [ "R2", - 2020, - "spring", - "day", + 2030, + "summer", + "night", "ETH", "T_BLND", 2020, @@ -36964,109 +27301,69 @@ ], [ "R2", - 2020, - "spring", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2020, - "winter", + 2030, + "fall", "night", - "ELC", - "T_EV", - 2020, - "VMT" + "URN", + "E_NUCLEAR", + 2015, + "ELC" ], [ "R1", 2025, "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "spring", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2020, - "spring", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "winter", "day", - "ELC", - "E_BATT", + "SOL", + "E_SOLPV", 2025, "ELC" ], [ - "R1", + "R2", 2025, "fall", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", "day", - "NG", - "E_NGCC", + "GSL", + "T_BLND", 2020, - "ELC" + "E10" ], [ "R1", - 2030, + 2020, "winter", - "day", - "DSL", - "T_DSL", + "night", + "ethos", + "S_IMPOIL", 2020, - "VMT" + "OIL" ], [ "R1", - 2030, - "winter", - "day", - "ETH", - "T_BLND", + 2025, + "summer", + "night", + "ethos", + "S_IMPETH", 2020, - "E10" + "ETH" ], [ "R2", 2025, - "winter", + "spring", "night", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R2", + 2020, + "summer", + "day", "URN", "E_NUCLEAR", 2015, @@ -37074,99 +27371,99 @@ ], [ "R2", + 2020, + "spring", + "night", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", 2030, "winter", - "night", + "day", "ethos", "S_IMPNG", 2020, "NG" ], [ - "R2", - 2025, - "summer", + "R1", + 2030, + "winter", "day", - "NG", - "R_NGH", - 2025, - "RH" + "ethos", + "S_IMPURN", + 2020, + "URN" ], [ "R1", 2030, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2030, + "summer", + "night", + "SOL", + "E_SOLPV", + 2025, "ELC" ], [ - "R2", + "R1", 2020, - "spring", - "day", - "E10", - "T_GSL", + "fall", + "night", + "GSL", + "T_BLND", 2020, - "VMT" + "E10" ], [ - "R2", + "R1", 2030, "spring", "night", - "DSL", - "T_DSL", - 2020, - "VMT" + "NG", + "E_NGCC", + 2030, + "ELC" ], [ "R1", - 2020, - "summer", + 2025, + "spring", "night", - "NG", - "R_NGH", + "ELC", + "E_BATT", 2020, - "RH" + "ELC" ], [ "R1", - 2020, + 2025, "fall", "day", - "ELC", - "R_EH", + "NG", + "E_NGCC", 2020, - "RH" + "ELC" ], [ "R2", 2025, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "summer", + "winter", "night", "ethos", - "S_IMPETH", + "S_IMPNG", 2020, - "ETH" + "NG" ], [ - "R1", - 2025, - "summer", - "night", + "R2", + 2020, + "winter", + "day", "URN", "E_NUCLEAR", 2020, @@ -37177,176 +27474,136 @@ 2020, "summer", "day", - "OIL", - "S_OILREF", - 2020, - "DSL" + "URN", + "E_NUCLEAR", + 2015, + "ELC" ], [ - "R2", + "R1", 2020, - "fall", - "night", - "DSL", - "T_DSL", + "spring", + "day", + "NG", + "E_NGCC", 2020, - "VMT" + "ELC" ], [ "R1", - 2025, + 2020, "summer", "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "ethos", - "S_IMPURN", + "OIL", + "S_OILREF", 2020, - "URN" + "GSL" ], [ "R1", - 2020, + 2030, "fall", - "night", - "ethos", - "S_IMPOIL", + "day", + "URN", + "E_NUCLEAR", 2020, - "OIL" + "ELC" ], [ "R1", - 2025, - "summer", + 2030, + "fall", "night", - "NG", - "E_NGCC", - 2025, - "ELC" + "ETH", + "T_BLND", + 2020, + "E10" ], [ "R1", 2025, - "summer", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2020, - "spring", + "fall", "night", "SOL", "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", 2025, - "summer", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" + "ELC" ], [ "R2", 2030, "summer", "night", - "SOL", - "E_SOLPV", - 2030, + "URN", + "E_NUCLEAR", + 2015, "ELC" ], [ "R1", 2030, - "spring", - "day", + "summer", + "night", "ELC", - "R_EH", + "E_BATT", 2020, - "RH" + "ELC" ], [ - "R1", + "R2", 2030, - "summer", - "night", + "fall", + "day", "SOL", "E_SOLPV", 2030, "ELC" ], [ - "R2", - 2030, - "winter", + "R1", + 2025, + "spring", "day", "ELC", "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "NG", - "R_NGH", - 2030, - "RH" + 2020, + "ELC" ], [ "R2", - 2030, + 2025, "summer", "night", - "NG", - "R_NGH", - 2020, - "RH" + "URN", + "E_NUCLEAR", + 2025, + "ELC" ], [ - "R2", - 2030, - "winter", + "R1", + 2020, + "summer", "night", - "E10", - "T_GSL", + "ELC", + "E_BATT", 2020, - "VMT" + "ELC" ], [ "R2", - 2025, - "winter", + 2020, + "summer", "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + 2020, + "fall", + "day", "ETH", "T_BLND", 2020, @@ -37355,8 +27612,8 @@ [ "R2", 2025, - "winter", - "night", + "fall", + "day", "OIL", "S_OILREF", 2020, @@ -37365,87 +27622,87 @@ [ "R2", 2025, - "winter", + "spring", "day", - "E10", - "T_GSL", - 2020, - "VMT" + "URN", + "E_NUCLEAR", + 2015, + "ELC" ], [ "R2", - 2030, - "spring", + 2020, + "fall", "day", - "NG", - "R_NGH", - 2030, - "RH" + "GSL", + "T_BLND", + 2020, + "E10" ], [ "R2", - 2025, + 2030, "spring", "night", - "SOL", - "E_SOLPV", + "ethos", + "S_IMPNG", 2020, - "ELC" + "NG" ], [ - "R2", + "R1", + 2030, + "fall", + "night", + "NG", + "E_NGCC", 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2020, "ELC" ], [ "R1", 2025, - "summer", + "winter", "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" + "OIL", + "S_OILREF", + 2020, + "GSL" ], [ - "R1", - 2030, - "fall", - "day", - "ELC", - "R_EH", - 2025, - "RH" + "R2", + 2020, + "spring", + "night", + "GSL", + "T_BLND", + 2020, + "E10" ], [ - "R1", - 2020, + "R2", + 2030, "fall", - "day", - "ethos", - "S_IMPOIL", + "night", + "ETH", + "T_BLND", 2020, - "OIL" + "E10" ], [ - "R1", + "R2", 2030, "winter", "night", - "ELC", - "T_EV", - 2025, - "VMT" + "ethos", + "S_IMPOIL", + 2020, + "OIL" ], [ "R1", 2025, - "winter", + "fall", "night", "URN", "E_NUCLEAR", @@ -37453,178 +27710,138 @@ "ELC" ], [ - "R1-R2", - 2020, - "fall", + "R2", + 2025, + "spring", "day", - "ELC", - "E_TRANS", - 2015, + "NG", + "E_NGCC", + 2020, "ELC" ], [ "R2", - 2030, + 2020, "winter", "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "night", "SOL", "E_SOLPV", 2020, "ELC" ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], [ "R2", - 2030, - "winter", - "night", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R1", - 2030, + 2020, "spring", "day", - "DSL", - "T_DSL", + "OIL", + "S_OILREF", 2020, - "VMT" + "GSL" ], [ "R2", - 2025, - "summer", - "night", + 2030, + "spring", + "day", "SOL", "E_SOLPV", - 2020, + 2030, "ELC" ], [ "R1", - 2025, + 2020, "spring", - "day", - "GSL", - "T_BLND", + "night", + "URN", + "E_NUCLEAR", 2020, - "E10" + "ELC" ], [ - "R1", - 2025, + "R2", + 2030, "spring", "day", "URN", "E_NUCLEAR", - 2015, + 2030, "ELC" ], [ - "R2", + "R1", 2025, - "spring", - "night", + "winter", + "day", "ethos", - "S_IMPURN", + "S_IMPOIL", 2020, - "URN" + "OIL" ], [ "R1", 2025, "winter", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1-R2", + "day", + "NG", + "E_NGCC", 2020, - "fall", - "night", - "ELC", - "E_TRANS", - 2015, "ELC" ], [ "R1", - 2020, - "fall", + 2030, + "winter", "night", - "SOL", - "E_SOLPV", - 2020, + "URN", + "E_NUCLEAR", + 2015, "ELC" ], [ - "R2-R1", - 2030, - "spring", + "R1", + 2025, + "summer", "night", "ELC", - "E_TRANS", - 2015, + "E_BATT", + 2020, "ELC" ], [ - "R1-R2", + "R1", 2030, - "fall", - "night", + "summer", + "day", "ELC", - "E_TRANS", - 2015, + "E_BATT", + 2020, "ELC" ], [ - "R1", - 2025, - "fall", + "R2", + 2020, + "winter", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2020, + "winter", "night", - "URN", - "E_NUCLEAR", + "NG", + "E_NGCC", 2020, "ELC" ], [ "R2", - 2025, + 2020, "summer", "day", "ethos", @@ -37633,29 +27850,39 @@ "NG" ], [ - "R1", - 2020, + "R2", + 2030, "fall", - "day", - "URN", - "E_NUCLEAR", + "night", + "NG", + "E_NGCC", 2020, "ELC" ], [ "R2", - 2025, - "winter", + 2030, + "spring", "day", "ELC", - "R_EH", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "night", + "OIL", + "S_OILREF", 2020, - "RH" + "DSL" ], [ - "R1", + "R2", 2025, - "spring", + "summer", "day", "SOL", "E_SOLPV", @@ -37664,97 +27891,157 @@ ], [ "R2", - 2025, - "fall", - "night", + 2030, + "winter", + "day", "SOL", "E_SOLPV", - 2020, + 2025, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "night", + "NG", + "E_NGCC", + 2025, "ELC" ], [ "R2", 2020, - "winter", - "night", + "summer", + "day", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "day", "ethos", - "S_IMPURN", + "S_IMPOIL", 2020, - "URN" + "OIL" ], [ "R2", 2025, "winter", - "night", + "day", "ethos", "S_IMPOIL", 2020, "OIL" ], [ - "R2", - 2020, + "R1", + 2030, + "winter", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R1", + 2025, "summer", "night", - "ethos", - "S_IMPURN", + "ETH", + "T_BLND", 2020, - "URN" + "E10" ], [ - "R2", + "R1", + 2025, + "summer", + "day", + "URN", + "E_NUCLEAR", 2025, + "ELC" + ], + [ + "R2", + 2030, "winter", "night", "NG", - "R_NGH", + "E_NGCC", 2020, - "RH" + "ELC" ], [ "R1", - 2020, - "winter", + 2025, + "fall", "day", - "ETH", - "T_BLND", + "URN", + "E_NUCLEAR", 2020, - "E10" + "ELC" ], [ "R2", 2025, - "winter", + "spring", "day", - "GSL", + "ETH", "T_BLND", 2020, "E10" ], [ "R1", - 2020, + 2030, "winter", "day", - "OIL", - "S_OILREF", + "ethos", + "S_IMPOIL", 2020, - "DSL" + "OIL" ], [ - "R2", - 2025, + "R1", + 2020, "summer", - "night", + "day", "NG", "E_NGCC", - 2025, + 2020, "ELC" ], + [ + "R1", + 2020, + "spring", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], [ "R2", 2025, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2030, "summer", "night", "ethos", @@ -37764,9 +28051,9 @@ ], [ "R2", - 2025, - "winter", - "day", + 2030, + "fall", + "night", "ELC", "E_BATT", 2025, @@ -37774,108 +28061,88 @@ ], [ "R1", - 2025, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "fall", + 2030, + "spring", "day", - "ethos", - "S_IMPNG", + "OIL", + "S_OILREF", 2020, - "NG" + "DSL" ], [ "R1", - 2025, - "summer", - "day", - "ETH", - "T_BLND", 2020, - "E10" - ], - [ - "R2", - 2030, "summer", "night", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "T_EV", + "ethos", + "S_IMPURN", 2020, - "VMT" + "URN" ], [ - "R2", - 2030, - "fall", - "night", - "NG", - "E_NGCC", + "R1", 2025, + "spring", + "day", + "SOL", + "E_SOLPV", + 2020, "ELC" ], [ - "R2", + "R1", 2025, "spring", "day", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2030, + "summer", + "night", "SOL", "E_SOLPV", 2025, "ELC" ], [ - "R2", + "R1", 2030, - "spring", + "summer", "day", "URN", "E_NUCLEAR", - 2015, + 2025, "ELC" ], [ "R1", - 2025, - "summer", + 2020, + "winter", "day", "NG", - "R_NGH", + "E_NGCC", 2020, - "RH" + "ELC" ], [ "R1", - 2030, - "summer", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" + 2020, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" ], [ "R2", 2020, - "spring", + "winter", "night", "OIL", "S_OILREF", @@ -37884,38 +28151,28 @@ ], [ "R2", - 2025, + 2030, "fall", - "day", - "URN", - "E_NUCLEAR", + "night", + "ethos", + "S_IMPETH", 2020, - "ELC" + "ETH" ], [ - "R2", - 2020, + "R1", + 2030, "winter", "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1-R2", + "OIL", + "S_OILREF", 2020, - "summer", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" + "DSL" ], [ - "R2", - 2030, - "spring", + "R1", + 2025, + "fall", "day", "SOL", "E_SOLPV", @@ -37924,277 +28181,307 @@ ], [ "R1", + 2030, + "winter", + "night", + "ethos", + "S_IMPURN", 2020, - "summer", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" + "URN" ], [ "R1", 2025, "winter", "day", - "URN", - "E_NUCLEAR", - 2025, + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2020, + "summer", + "night", + "SOL", + "E_SOLPV", + 2020, "ELC" ], [ - "R1", + "R2-R1", 2025, "summer", "day", - "E10", - "T_GSL", - 2020, - "VMT" + "ELC", + "E_TRANS", + 2015, + "ELC" ], [ "R2", - 2030, + 2020, "winter", "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" + "GSL", + "T_BLND", + 2020, + "E10" ], [ - "R1", - 2025, - "summer", + "R2", + 2020, + "spring", "night", "URN", "E_NUCLEAR", - 2015, + 2020, "ELC" ], [ "R1", 2030, - "fall", + "winter", "day", - "URN", - "E_NUCLEAR", - 2030, - "ELC" + "GSL", + "T_BLND", + 2020, + "E10" ], [ - "R2", + "R1", 2020, "fall", - "day", + "night", "ELC", - "T_EV", + "E_BATT", 2020, - "VMT" + "ELC" ], [ "R2", - 2030, - "fall", - "night", - "OIL", - "S_OILREF", 2020, - "DSL" - ], - [ - "R1", - 2025, - "summer", + "spring", "day", - "SOL", - "E_SOLPV", + "ELC", + "E_BATT", 2020, "ELC" ], [ - "R1", - 2030, - "winter", - "night", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2030, + "R2", + 2020, "fall", "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", "ethos", - "S_IMPURN", + "S_IMPETH", 2020, - "URN" + "ETH" ], [ - "R1", + "R2", 2030, - "winter", - "night", - "E10", - "T_GSL", + "spring", + "day", + "NG", + "E_NGCC", 2030, - "VMT" + "ELC" ], [ "R2", - 2030, - "summer", - "day", - "SOL", - "E_SOLPV", 2025, + "spring", + "day", + "ELC", + "E_BATT", + 2020, "ELC" ], [ "R1", 2025, - "fall", + "winter", "night", - "ELC", - "R_EH", - 2025, - "RH" + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + 2020, + "spring", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" ], [ "R1", - 2030, + 2020, "spring", - "day", - "NG", - "R_NGH", - 2025, - "RH" + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" ], [ - "R2", - 2030, - "fall", - "night", - "ELC", - "R_EH", + "R1", 2025, - "RH" + "spring", + "day", + "ethos", + "S_IMPURN", + 2020, + "URN" ], [ "R1", - 2025, + 2020, "winter", "night", - "NG", - "R_NGH", - 2025, - "RH" + "SOL", + "E_SOLPV", + 2020, + "ELC" ], [ "R1", 2030, - "winter", + "fall", "night", "URN", "E_NUCLEAR", - 2025, + 2020, "ELC" ], [ - "R1", - 2030, + "R2", + 2020, "spring", + "night", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + 2025, + "summer", "day", - "E10", - "T_GSL", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2-R1", 2025, - "VMT" + "winter", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" ], [ "R1", - 2030, - "winter", + 2020, + "summer", "night", - "ELC", - "T_EV", + "ethos", + "S_IMPETH", 2020, - "VMT" + "ETH" + ], + [ + "R2", + 2020, + "winter", + "day", + "ETH", + "T_BLND", + 2020, + "E10" ], [ "R1", - 2025, + 2020, "spring", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + 2020, + "summer", "day", - "OIL", - "S_OILREF", + "ethos", + "S_IMPOIL", 2020, - "DSL" + "OIL" ], [ "R2", - 2030, + 2020, "fall", "day", - "E10", - "T_GSL", - 2030, - "VMT" + "ELC", + "E_BATT", + 2020, + "ELC" ], [ "R1", - 2020, - "winter", + 2030, + "spring", "day", - "ethos", - "S_IMPETH", + "OIL", + "S_OILREF", 2020, - "ETH" + "GSL" ], [ "R2", - 2030, + 2020, "fall", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" + "day", + "ethos", + "S_IMPNG", + 2020, + "NG" ], [ "R2", 2030, - "winter", + "summer", "day", - "URN", - "E_NUCLEAR", - 2025, + "ELC", + "E_BATT", + 2020, "ELC" ], [ "R1", - 2030, - "winter", + 2020, + "fall", "day", - "ELC", - "R_EH", - 2030, - "RH" + "OIL", + "S_OILREF", + 2020, + "GSL" ], [ "R2", - 2030, + 2025, "summer", "day", "URN", @@ -38204,88 +28491,118 @@ ], [ "R1", - 2025, - "spring", + 2030, + "winter", "day", - "NG", - "R_NGH", + "OIL", + "S_OILREF", 2020, - "RH" + "GSL" ], [ "R2", - 2025, - "winter", + 2030, + "summer", "night", - "ethos", - "S_IMPURN", - 2020, - "URN" + "ELC", + "E_BATT", + 2030, + "ELC" ], [ - "R2", - 2020, - "spring", + "R1", + 2025, + "summer", "day", - "GSL", - "T_BLND", + "SOL", + "E_SOLPV", 2020, - "E10" + "ELC" ], [ "R2", - 2030, + 2020, "fall", "night", - "ELC", - "E_BATT", - 2030, + "SOL", + "E_SOLPV", + 2020, "ELC" ], [ - "R1", + "R2", 2025, - "summer", + "fall", "night", - "ELC", - "T_EV", + "URN", + "E_NUCLEAR", 2025, - "VMT" + "ELC" ], [ "R2", 2025, "spring", - "day", - "GSL", - "T_BLND", + "night", + "SOL", + "E_SOLPV", 2020, - "E10" + "ELC" ], [ "R2", - 2030, + 2020, "fall", "day", - "ELC", - "T_EV", + "OIL", + "S_OILREF", 2020, - "VMT" + "DSL" ], [ - "R2", + "R1", 2030, "summer", + "night", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "fall", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2025, + "fall", "day", - "NG", - "E_NGCC", - 2030, + "URN", + "E_NUCLEAR", + 2015, "ELC" ], [ - "R2", + "R2", + 2025, + "spring", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", 2030, - "summer", + "spring", "night", "NG", "E_NGCC", @@ -38295,56 +28612,66 @@ [ "R1", 2020, - "spring", + "summer", "day", - "OIL", - "S_OILREF", + "ethos", + "S_IMPNG", 2020, - "DSL" + "NG" ], [ - "R2", - 2020, - "winter", + "R1", + 2030, + "summer", "night", - "GSL", - "T_BLND", + "ethos", + "S_IMPNG", 2020, - "E10" + "NG" ], [ "R1", 2020, - "fall", - "night", + "summer", + "day", "ethos", "S_IMPURN", 2020, "URN" ], + [ + "R2", + 2020, + "winter", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], [ "R1", 2030, - "summer", + "winter", "night", - "DSL", - "T_DSL", - 2025, - "VMT" + "SOL", + "E_SOLPV", + 2020, + "ELC" ], [ "R1", - 2025, + 2030, "fall", - "night", - "NG", - "E_NGCC", - 2025, + "day", + "URN", + "E_NUCLEAR", + 2015, "ELC" ], [ "R1", - 2025, + 2020, "fall", "night", "ethos", @@ -38354,278 +28681,228 @@ ], [ "R2", - 2020, - "spring", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", 2025, "spring", - "day", - "SOL", - "E_SOLPV", + "night", + "ethos", + "S_IMPETH", 2020, - "ELC" + "ETH" ], [ "R2", 2025, - "spring", - "night", + "summer", + "day", "ELC", "E_BATT", 2025, "ELC" ], - [ - "R2", - 2030, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], [ "R2", 2025, - "spring", + "fall", "day", - "ETH", - "T_BLND", + "ethos", + "S_IMPNG", 2020, - "E10" - ], - [ - "R2-R1", - 2025, - "winter", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" + "NG" ], [ "R2", - 2020, - "winter", + 2025, + "fall", "day", - "NG", - "E_NGCC", + "ethos", + "S_IMPURN", 2020, - "ELC" + "URN" ], [ - "R2", - 2030, - "spring", + "R1", + 2025, + "fall", "night", - "NG", - "R_NGH", + "SOL", + "E_SOLPV", 2020, - "RH" + "ELC" ], [ "R2", - 2030, + 2025, "summer", - "night", + "day", "ethos", - "S_IMPNG", + "S_IMPOIL", 2020, - "NG" + "OIL" ], [ "R2", 2030, "winter", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "spring", - "night", + "day", "ethos", - "S_IMPURN", + "S_IMPOIL", 2020, - "URN" + "OIL" ], [ "R1", - 2020, - "winter", + 2030, + "spring", "day", - "SOL", - "E_SOLPV", - 2020, + "NG", + "E_NGCC", + 2025, "ELC" ], [ "R2", - 2020, + 2025, "summer", - "day", - "ELC", - "E_BATT", + "night", + "URN", + "E_NUCLEAR", 2020, "ELC" ], [ - "R2", - 2020, + "R1", + 2030, "winter", - "day", + "night", "ETH", "T_BLND", 2020, "E10" ], [ - "R2", - 2020, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "fall", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", + "R2-R1", 2025, - "winter", + "spring", "day", - "SOL", - "E_SOLPV", - 2025, + "ELC", + "E_TRANS", + 2015, "ELC" ], [ "R2", - 2025, - "winter", + 2030, + "fall", "day", - "ELC", - "E_BATT", - 2020, + "URN", + "E_NUCLEAR", + 2030, "ELC" ], [ - "R2", + "R1", 2020, - "fall", - "night", + "winter", + "day", "ethos", "S_IMPETH", 2020, "ETH" ], [ - "R1", - 2025, - "winter", - "day", - "OIL", - "S_OILREF", + "R2", 2020, - "GSL" - ], - [ - "R1", + "spring", + "day", + "ethos", + "S_IMPOIL", 2020, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" + "OIL" ], [ "R1", 2030, "fall", - "day", - "ETH", - "T_BLND", + "night", + "ethos", + "S_IMPOIL", 2020, - "E10" + "OIL" ], [ "R1", + 2030, + "fall", + "night", + "NG", + "E_NGCC", 2025, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2015, "ELC" ], [ "R1", - 2030, - "spring", - "night", - "E10", - "T_GSL", - 2030, - "VMT" + 2020, + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" ], [ "R2", 2020, "winter", - "night", + "day", "OIL", "S_OILREF", 2020, - "GSL" + "DSL" ], [ - "R2", + "R1", + 2030, + "summer", + "day", + "ethos", + "S_IMPOIL", 2020, - "fall", + "OIL" + ], + [ + "R1", + 2030, + "winter", "day", "URN", "E_NUCLEAR", - 2015, + 2030, "ELC" ], [ "R1", - 2030, + 2025, + "summer", + "day", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + 2025, "winter", "day", - "NG", - "E_NGCC", - 2030, + "URN", + "E_NUCLEAR", + 2020, "ELC" ], [ "R2", 2030, - "winter", + "spring", "day", "SOL", "E_SOLPV", @@ -38633,39 +28910,49 @@ "ELC" ], [ - "R2-R1", + "R2", 2030, - "summer", + "winter", "day", - "ELC", - "E_TRANS", - 2015, - "ELC" + "GSL", + "T_BLND", + 2020, + "E10" ], [ - "R2-R1", + "R1", 2020, "spring", "night", - "ELC", - "E_TRANS", + "URN", + "E_NUCLEAR", 2015, "ELC" ], [ "R2", - 2025, - "fall", + 2030, + "spring", "day", "URN", "E_NUCLEAR", - 2015, + 2025, "ELC" ], [ "R1", - 2020, - "fall", + 2030, + "spring", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "summer", "day", "ethos", "S_IMPNG", @@ -38675,418 +28962,498 @@ [ "R1", 2030, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2030, + "spring", + "day", + "SOL", + "E_SOLPV", + 2025, "ELC" ], [ "R2", 2020, - "spring", + "summer", "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + 2020, + "fall", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + 2025, + "winter", + "day", "ethos", "S_IMPNG", 2020, "NG" ], [ - "R1", + "R2", 2030, - "summer", - "day", + "fall", + "night", "SOL", "E_SOLPV", - 2025, + 2020, "ELC" ], [ - "R1-R2", - 2025, + "R2", + 2030, "winter", "night", - "ELC", - "E_TRANS", - 2015, + "SOL", + "E_SOLPV", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "URN", + "E_NUCLEAR", + 2025, "ELC" ], [ "R1", 2030, - "summer", + "fall", "day", - "DSL", - "T_DSL", - 2030, - "VMT" + "ETH", + "T_BLND", + 2020, + "E10" ], [ "R1", - 2025, + 2020, "winter", "night", - "ethos", - "S_IMPNG", + "OIL", + "S_OILREF", 2020, - "NG" + "DSL" ], [ - "R1", - 2030, + "R2", + 2025, "spring", "night", - "DSL", - "T_DSL", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", 2020, - "VMT" + "fall", + "day", + "ethos", + "S_IMPOIL", + 2020, + "OIL" ], [ "R2", - 2030, - "winter", - "night", + 2020, + "fall", + "day", "NG", "E_NGCC", 2020, "ELC" ], [ - "R2", - 2025, + "R1", + 2030, "fall", "day", - "DSL", - "T_DSL", - 2025, - "VMT" + "ethos", + "S_IMPETH", + 2020, + "ETH" ], [ - "R1-R2", + "R2", 2025, - "winter", + "summer", "day", - "ELC", - "E_TRANS", - 2015, + "SOL", + "E_SOLPV", + 2020, "ELC" ], [ - "R1", + "R2", 2020, - "spring", + "summer", "day", - "ethos", - "S_IMPETH", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2030, + "summer", + "night", + "NG", + "E_NGCC", 2020, - "ETH" + "ELC" ], [ "R2", - 2025, + 2030, "winter", "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2025, - "spring", - "night", - "DSL", - "T_DSL", + "SOL", + "E_SOLPV", 2020, - "VMT" + "ELC" ], [ "R1", 2030, - "fall", + "winter", "night", - "DSL", - "T_DSL", + "ELC", + "E_BATT", 2025, - "VMT" + "ELC" ], [ "R1", - 2020, + 2025, "spring", "night", - "URN", - "E_NUCLEAR", + "ethos", + "S_IMPOIL", 2020, - "ELC" + "OIL" ], [ "R1", - 2030, - "spring", - "night", - "ELC", - "T_EV", + 2025, + "summer", + "day", + "URN", + "E_NUCLEAR", 2020, - "VMT" + "ELC" ], [ "R2", 2025, - "fall", - "night", - "ELC", - "R_EH", + "spring", + "day", + "NG", + "E_NGCC", 2025, - "RH" + "ELC" ], [ "R1", 2025, "fall", + "day", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", + 2025, + "summer", "night", - "ELC", - "R_EH", + "OIL", + "S_OILREF", 2020, - "RH" + "DSL" ], [ - "R1", + "R2", 2030, - "summer", - "night", - "ELC", - "R_EH", + "winter", + "day", + "OIL", + "S_OILREF", 2020, - "RH" + "DSL" ], [ "R1", 2030, "spring", "day", - "NG", - "R_NGH", + "ethos", + "S_IMPETH", 2020, - "RH" + "ETH" ], [ "R2", - 2025, - "spring", + 2030, + "winter", "night", - "ETH", - "T_BLND", + "ethos", + "S_IMPNG", 2020, - "E10" + "NG" ], [ "R1", - 2030, + 2020, "winter", "day", - "E10", - "T_GSL", - 2025, - "VMT" + "ELC", + "E_BATT", + 2020, + "ELC" ], [ - "R1", - 2020, + "R2", + 2030, "fall", - "day", - "ethos", - "S_IMPURN", + "night", + "ELC", + "E_BATT", 2020, - "URN" + "ELC" ], [ - "R2", - 2030, + "R1", + 2020, "fall", "night", - "DSL", - "T_DSL", - 2025, - "VMT" + "SOL", + "E_SOLPV", + 2020, + "ELC" ], [ - "R2", + "R1", 2030, "fall", - "night", - "NG", - "R_NGH", + "day", + "SOL", + "E_SOLPV", 2030, - "RH" + "ELC" ], [ "R2", 2030, - "winter", - "day", - "DSL", - "T_DSL", + "summer", + "night", + "SOL", + "E_SOLPV", 2020, - "VMT" + "ELC" ], [ "R1", - 2025, - "winter", - "night", - "ELC", - "T_EV", 2020, - "VMT" - ], - [ - "R2", - 2025, - "spring", + "winter", "day", "OIL", "S_OILREF", 2020, - "DSL" + "GSL" ], [ - "R2", - 2030, - "fall", - "day", - "E10", - "T_GSL", + "R1", 2025, - "VMT" + "winter", + "night", + "SOL", + "E_SOLPV", + 2025, + "ELC" ], [ "R2", 2020, - "summer", + "winter", "day", - "ethos", - "S_IMPNG", + "OIL", + "S_OILREF", 2020, - "NG" + "GSL" ], [ - "R1", - 2030, - "winter", - "day", - "URN", - "E_NUCLEAR", + "R2-R1", 2020, + "spring", + "day", + "ELC", + "E_TRANS", + 2015, "ELC" ], [ "R2", - 2030, - "fall", - "day", - "ethos", - "S_IMPURN", + 2025, + "summer", + "night", + "GSL", + "T_BLND", 2020, - "URN" + "E10" ], [ "R1", - 2030, + 2025, "fall", "day", "SOL", "E_SOLPV", - 2030, + 2020, "ELC" ], [ "R2", 2025, - "spring", + "winter", "night", - "DSL", - "T_DSL", - 2020, - "VMT" + "NG", + "E_NGCC", + 2025, + "ELC" ], [ - "R1", - 2020, - "fall", + "R2", + 2030, + "summer", "night", "ethos", "S_IMPNG", 2020, "NG" ], + [ + "R2", + 2030, + "summer", + "night", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R2", + 2025, + "fall", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], [ "R1", 2025, "spring", "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "R_EH", + "GSL", + "T_BLND", 2020, - "RH" + "E10" ], [ "R1", - 2025, + 2020, "winter", "day", - "E10", - "T_GSL", + "ETH", + "T_BLND", 2020, - "VMT" + "E10" ], [ "R2", 2030, "fall", - "night", + "day", "SOL", "E_SOLPV", - 2030, + 2025, "ELC" ], [ "R1", - 2030, - "fall", - "day", - "ELC", - "T_EV", 2025, - "VMT" + "summer", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" ], [ "R1", 2025, - "summer", + "spring", "night", - "ELC", - "T_EV", - 2020, - "VMT" + "URN", + "E_NUCLEAR", + 2025, + "ELC" ], [ - "R1", - 2030, + "R2", + 2025, "spring", "day", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "URN", + "E_NUCLEAR", + 2030, + "ELC" + ], + [ + "R2", + 2020, + "spring", + "night", "URN", "E_NUCLEAR", 2015, @@ -39094,48 +29461,68 @@ ], [ "R1", + 2025, + "fall", + "day", + "ethos", + "S_IMPETH", 2020, - "summer", + "ETH" + ], + [ + "R2", + 2030, + "spring", "day", "NG", "E_NGCC", - 2020, + 2025, "ELC" ], [ - "R1", - 2030, + "R2-R1", + 2020, "fall", "day", - "E10", - "T_GSL", - 2025, - "VMT" + "ELC", + "E_TRANS", + 2015, + "ELC" ], [ "R1", 2030, "winter", "day", - "SOL", - "E_SOLPV", + "ELC", + "E_BATT", 2030, "ELC" ], [ "R1", 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2025, + "summer", + "night", + "URN", + "E_NUCLEAR", + 2030, "ELC" ], + [ + "R1", + 2020, + "winter", + "night", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], [ "R2", - 2030, - "spring", + 2025, + "summer", "day", "ethos", "S_IMPETH", @@ -39143,59 +29530,49 @@ "ETH" ], [ - "R2-R1", - 2020, - "winter", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", + "R1", 2025, "winter", - "night", - "ELC", - "E_BATT", + "day", + "SOL", + "E_SOLPV", 2025, "ELC" ], [ - "R1", + "R2", 2025, - "fall", - "night", - "ELC", - "T_EV", + "spring", + "day", + "ethos", + "S_IMPOIL", 2020, - "VMT" + "OIL" ], [ "R1", 2025, "fall", "night", - "NG", - "E_NGCC", - 2020, + "URN", + "E_NUCLEAR", + 2015, "ELC" ], [ "R1", 2030, - "summer", + "winter", "night", - "ELC", - "T_EV", + "GSL", + "T_BLND", 2020, - "VMT" + "E10" ], [ "R1", - 2030, - "winter", + 2020, + "fall", "night", "OIL", "S_OILREF", @@ -39203,78 +29580,68 @@ "DSL" ], [ - "R1-R2", - 2025, - "spring", + "R1", + 2030, + "fall", "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "night", - "DSL", - "T_DSL", + "OIL", + "S_OILREF", 2020, - "VMT" + "DSL" ], [ - "R2", - 2020, - "summer", - "night", - "NG", - "E_NGCC", + "R1", 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "ethos", - "S_IMPURN", + "spring", + "day", + "OIL", + "S_OILREF", 2020, - "URN" + "DSL" ], [ - "R2", + "R1", 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2025, "fall", "night", "URN", "E_NUCLEAR", - 2020, + 2015, "ELC" ], [ "R1", + 2030, + "fall", + "night", + "OIL", + "S_OILREF", 2020, + "DSL" + ], + [ + "R2", + 2030, "summer", - "night", + "day", "ethos", "S_IMPOIL", 2020, "OIL" ], [ - "R2", - 2025, + "R1-R2", + 2020, + "winter", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" + ], + [ + "R1", + 2030, "spring", "day", "URN", @@ -39283,49 +29650,49 @@ "ELC" ], [ - "R2", - 2030, - "fall", - "day", - "DSL", - "T_DSL", - 2030, - "VMT" + "R1-R2", + 2025, + "spring", + "night", + "ELC", + "E_TRANS", + 2015, + "ELC" ], [ "R2", - 2020, - "winter", + 2025, + "summer", "night", - "ELC", - "E_BATT", + "OIL", + "S_OILREF", 2020, - "ELC" + "GSL" ], [ "R2", 2030, - "spring", - "night", - "DSL", - "T_DSL", - 2030, - "VMT" + "winter", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" ], [ "R1", 2020, "fall", "night", - "ELC", - "T_EV", + "ethos", + "S_IMPETH", 2020, - "VMT" + "ETH" ], [ "R2", 2025, - "fall", + "spring", "night", "ELC", "E_BATT", @@ -39333,90 +29700,110 @@ "ELC" ], [ - "R2", + "R1", 2020, - "summer", + "fall", "day", - "OIL", - "S_OILREF", + "ethos", + "S_IMPNG", 2020, - "GSL" + "NG" ], [ "R1", 2020, - "spring", - "night", - "DSL", - "T_DSL", + "fall", + "day", + "ethos", + "S_IMPURN", 2020, - "VMT" + "URN" ], [ - "R1", + "R2", 2030, - "summer", - "day", + "winter", + "night", "URN", "E_NUCLEAR", 2030, "ELC" ], + [ + "R1", + 2020, + "summer", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], [ "R2", 2025, + "fall", + "night", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + 2030, "summer", "day", "OIL", "S_OILREF", 2020, - "GSL" + "DSL" ], [ "R2", 2030, "fall", "night", - "E10", - "T_GSL", + "ethos", + "S_IMPURN", 2020, - "VMT" + "URN" ], [ - "R2", - 2030, - "spring", - "day", - "ELC", - "R_EH", - 2025, - "RH" + "R1", + 2020, + "winter", + "night", + "ETH", + "T_BLND", + 2020, + "E10" ], [ "R1", - 2020, - "summer", + 2025, + "winter", "day", - "ELC", - "R_EH", + "ethos", + "S_IMPETH", 2020, - "RH" + "ETH" ], [ - "R2", - 2025, - "summer", + "R1", + 2030, + "spring", "night", - "URN", - "E_NUCLEAR", - 2015, + "SOL", + "E_SOLPV", + 2030, "ELC" ], [ "R1", - 2020, + 2025, "spring", - "night", + "day", "ethos", "S_IMPNG", 2020, @@ -39424,159 +29811,139 @@ ], [ "R2", - 2030, - "spring", + 2025, + "fall", "night", - "OIL", - "S_OILREF", + "URN", + "E_NUCLEAR", 2020, - "GSL" + "ELC" ], [ "R2", 2030, "summer", - "night", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "winter", "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "fall", - "night", - "ETH", + "GSL", "T_BLND", 2020, "E10" ], [ - "R2", + "R1", 2025, - "winter", + "summer", "night", - "ELC", - "R_EH", + "OIL", + "S_OILREF", 2020, - "RH" + "GSL" ], [ "R1", 2025, - "summer", + "fall", "night", - "ELC", - "R_EH", - 2025, - "RH" + "ethos", + "S_IMPOIL", + 2020, + "OIL" ], [ - "R2", + "R1", 2030, - "spring", + "summer", "day", - "ELC", - "E_BATT", + "SOL", + "E_SOLPV", 2030, "ELC" ], [ "R1", 2020, - "summer", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, "spring", "day", - "NG", - "E_NGCC", - 2025, + "SOL", + "E_SOLPV", + 2020, "ELC" ], [ - "R1", - 2030, - "fall", + "R2", + 2020, + "summer", "night", - "DSL", - "T_DSL", + "ethos", + "S_IMPNG", 2020, - "VMT" + "NG" ], [ - "R2", - 2020, - "fall", - "night", + "R2-R1", + 2030, + "winter", + "day", "ELC", - "R_EH", - 2020, - "RH" + "E_TRANS", + 2015, + "ELC" ], [ "R1", - 2030, - "fall", + 2025, + "summer", "night", - "ELC", - "T_EV", - 2030, - "VMT" + "ethos", + "S_IMPOIL", + 2020, + "OIL" ], [ "R1", - 2020, + 2025, "spring", - "night", + "day", "URN", "E_NUCLEAR", - 2015, + 2025, "ELC" ], [ "R1", 2030, - "fall", - "night", - "NG", - "R_NGH", + "summer", + "day", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", 2025, - "RH" + "spring", + "night", + "ethos", + "S_IMPETH", + 2020, + "ETH" ], [ "R2", - 2025, + 2030, "summer", - "night", + "day", "NG", - "R_NGH", - 2025, - "RH" + "E_NGCC", + 2030, + "ELC" ], [ "R2", - 2020, - "fall", - "night", + 2025, + "summer", + "day", "ELC", "E_BATT", 2020, @@ -39585,199 +29952,259 @@ [ "R2", 2025, - "fall", + "spring", "night", - "ELC", - "R_EH", + "OIL", + "S_OILREF", 2020, - "RH" + "DSL" ], [ "R2", 2030, "fall", "day", + "NG", + "E_NGCC", + 2030, + "ELC" + ], + [ + "R1", + 2020, + "summer", + "night", "SOL", "E_SOLPV", - 2030, + 2020, "ELC" ], [ "R1", 2020, - "winter", + "fall", "night", - "NG", - "R_NGH", + "OIL", + "S_OILREF", 2020, - "RH" + "GSL" ], [ "R2", - 2020, - "spring", + 2030, + "winter", "night", - "ethos", - "S_IMPOIL", + "OIL", + "S_OILREF", 2020, - "OIL" + "DSL" ], [ - "R2-R1", + "R1", 2030, "fall", "day", - "ELC", - "E_TRANS", - 2015, + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", + 2030, + "spring", + "day", + "NG", + "E_NGCC", + 2020, "ELC" ], [ - "R2", + "R1", + 2020, + "spring", + "day", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R1", 2025, + "summer", + "day", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + 2020, "winter", - "night", - "DSL", - "T_DSL", + "day", + "ethos", + "S_IMPURN", 2020, - "VMT" + "URN" ], [ "R2", - 2025, + 2020, "winter", "day", - "NG", - "E_NGCC", + "ELC", + "E_BATT", 2020, "ELC" ], [ - "R2", - 2025, - "winter", + "R1", + 2030, + "fall", "night", - "E10", - "T_GSL", + "OIL", + "S_OILREF", 2020, - "VMT" + "GSL" ], [ - "R1", - 2025, - "summer", + "R2", + 2020, + "spring", "night", - "E10", - "T_GSL", - 2025, - "VMT" + "SOL", + "E_SOLPV", + 2020, + "ELC" ], [ "R1", - 2025, + 2030, "fall", "night", - "E10", - "T_GSL", - 2025, - "VMT" + "SOL", + "E_SOLPV", + 2030, + "ELC" ], [ "R1", 2030, - "summer", - "night", - "E10", - "T_GSL", - 2025, - "VMT" + "spring", + "day", + "SOL", + "E_SOLPV", + 2030, + "ELC" ], [ - "R1", + "R2", 2025, - "winter", + "summer", "night", - "ELC", - "E_BATT", - 2025, + "URN", + "E_NUCLEAR", + 2015, "ELC" ], [ "R2", 2030, - "summer", + "fall", "day", - "ELC", - "T_EV", + "URN", + "E_NUCLEAR", 2025, - "VMT" + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "OIL", + "S_OILREF", + 2020, + "DSL" ], [ "R1", - 2025, - "winter", + 2020, + "summer", "day", - "ethos", - "S_IMPOIL", + "ELC", + "E_BATT", 2020, - "OIL" + "ELC" ], [ "R2", - 2030, - "summer", + 2025, + "winter", "night", - "DSL", - "T_DSL", + "OIL", + "S_OILREF", 2020, - "VMT" + "DSL" ], [ "R1", 2020, - "fall", + "summer", "night", - "E10", - "T_GSL", + "ETH", + "T_BLND", 2020, - "VMT" + "E10" ], [ - "R1", - 2020, + "R2", + 2025, "spring", "night", - "ELC", - "E_BATT", + "GSL", + "T_BLND", 2020, + "E10" + ], + [ + "R2", + 2025, + "winter", + "day", + "SOL", + "E_SOLPV", + 2025, "ELC" ], [ "R2", 2020, - "fall", - "night", - "NG", - "E_NGCC", + "spring", + "day", + "URN", + "E_NUCLEAR", 2020, "ELC" ], [ "R2", 2025, - "fall", - "night", - "ethos", - "S_IMPOIL", + "summer", + "day", + "ETH", + "T_BLND", 2020, - "OIL" + "E10" ], [ - "R2", - 2025, - "summer", + "R1", + 2020, + "fall", "night", - "GSL", + "ETH", "T_BLND", 2020, "E10" @@ -39786,15 +30213,15 @@ "R1", 2025, "spring", - "day", - "ELC", - "E_BATT", - 2020, + "night", + "NG", + "E_NGCC", + 2025, "ELC" ], [ - "R2", - 2025, + "R1", + 2030, "fall", "night", "NG", @@ -39803,202 +30230,222 @@ "ELC" ], [ - "R1", + "R2", 2020, - "summer", + "spring", "night", - "ETH", - "T_BLND", + "OIL", + "S_OILREF", 2020, - "E10" + "GSL" ], [ "R1", 2020, "winter", - "day", - "ELC", - "R_EH", + "night", + "ethos", + "S_IMPURN", 2020, - "RH" + "URN" ], [ "R1", 2030, - "fall", + "winter", "day", - "GSL", - "T_BLND", - 2020, - "E10" + "URN", + "E_NUCLEAR", + 2025, + "ELC" ], [ "R1", 2025, - "fall", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "OIL", - "S_OILREF", + "winter", + "night", + "ethos", + "S_IMPOIL", 2020, - "GSL" + "OIL" ], [ "R2", 2025, - "fall", + "winter", "day", - "ETH", - "T_BLND", - 2020, - "E10" + "URN", + "E_NUCLEAR", + 2015, + "ELC" ], [ "R2", 2030, - "winter", - "night", + "spring", + "day", "SOL", "E_SOLPV", - 2025, + 2020, "ELC" ], [ "R2", - 2025, - "summer", + 2030, + "spring", "day", - "ELC", - "E_BATT", + "URN", + "E_NUCLEAR", 2020, "ELC" ], [ - "R1", - 2030, - "winter", - "night", - "ELC", - "R_EH", + "R2-R1", 2025, - "RH" + "fall", + "day", + "ELC", + "E_TRANS", + 2015, + "ELC" ], [ "R2", - 2030, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2030, - "ELC" + 2025, + "spring", + "day", + "GSL", + "T_BLND", + 2020, + "E10" ], [ - "R2", + "R1", 2030, - "winter", - "night", + "spring", + "day", "ELC", "E_BATT", 2025, "ELC" ], [ - "R2", + "R1", 2030, "spring", "day", - "OIL", - "S_OILREF", + "SOL", + "E_SOLPV", 2020, - "GSL" + "ELC" ], [ "R1", 2025, "fall", - "day", + "night", "GSL", "T_BLND", 2020, "E10" ], [ - "R1", + "R2", 2030, - "spring", - "night", + "winter", + "day", "ELC", - "R_EH", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", 2020, - "RH" + "winter", + "night", + "URN", + "E_NUCLEAR", + 2020, + "ELC" ], [ "R1", - 2030, - "summer", + 2020, + "winter", "day", "URN", "E_NUCLEAR", - 2025, + 2015, "ELC" ], [ "R2", 2025, - "spring", + "summer", "day", - "DSL", - "T_DSL", + "NG", + "E_NGCC", 2025, - "VMT" + "ELC" ], [ "R1", 2030, - "summer", + "spring", "day", - "ELC", - "E_BATT", + "ETH", + "T_BLND", 2020, + "E10" + ], + [ + "R2", + 2030, + "winter", + "night", + "SOL", + "E_SOLPV", + 2025, "ELC" ], [ "R1", + 2025, + "spring", + "day", + "ETH", + "T_BLND", 2020, - "winter", + "E10" + ], + [ + "R2", + 2030, + "spring", "night", - "ethos", - "S_IMPETH", + "URN", + "E_NUCLEAR", 2020, - "ETH" + "ELC" ], [ "R1", 2030, - "summer", - "day", - "NG", - "R_NGH", - 2025, - "RH" + "spring", + "night", + "ethos", + "S_IMPOIL", + 2020, + "OIL" ], [ - "R2", + "R1", 2030, "spring", "night", - "ELC", - "E_BATT", + "NG", + "E_NGCC", 2020, "ELC" ] @@ -46584,7 +37031,20 @@ "E_NUCLEAR", "T_DSL" ], - "tech_annual": [], + "tech_annual": [ + "T_EV", + "R_NGH", + "T_GSL", + "R_EH", + "T_DSL" + ], + "tech_demand": [ + "T_EV", + "R_NGH", + "T_GSL", + "R_EH", + "T_DSL" + ], "tech_baseload": [ "E_NUCLEAR" ], diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 072aed77d..3214a587a 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -10196,4205 +10196,73 @@ ] ], "CurtailmentVar_rpsditvo": [], - "DemandActivityConstraint_rpsdtv_dem_s0d0": [ + "DemandConstraint_rpc": [ [ "utopia", 2000, - "summer", - "day", - "RHE", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXG", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RHO", - 1980, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHO", - 1980, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHE", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHO", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXE", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHE", - 2010, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXD", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXG", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXD", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHE", - 2010, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXE", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXG", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXD", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHO", - 1980, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXG", - 1970, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXG", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXG", - 1970, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXD", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHO", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHO", - 1980, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHO", - 1970, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHO", - 1980, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHO", - 2010, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXD", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXD", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHE", - 2010, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXD", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXE", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXD", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXG", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXE", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXD", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXD", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXD", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXE", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXG", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHO", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXD", - 1970, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXD", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXE", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXG", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHE", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHO", - 2010, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXG", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXE", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXD", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXG", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXD", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXD", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXD", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RHO", - 1970, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXD", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHE", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHE", - 2010, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXG", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXD", - 1970, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHO", - 1980, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXG", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXG", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXG", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHE", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXE", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHO", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXE", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXG", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXG", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXD", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXG", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXG", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXE", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXD", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXG", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXG", - 1970, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHO", - 2010, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXD", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXG", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXG", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHO", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXG", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXE", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RHO", - 1980, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXG", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHO", - 1980, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHE", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXG", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHO", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHO", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXD", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXG", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXG", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXE", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXD", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXD", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHE", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXE", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHE", - 2010, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXG", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXD", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXD", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXD", - 1970, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXG", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXE", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXD", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXD", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHO", - 1970, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXG", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXD", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXE", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHE", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXG", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXE", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXE", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHO", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXG", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXG", - 1970, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXG", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXD", - 1970, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXE", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXG", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXE", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXD", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHO", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXD", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHO", - 1980, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RHO", - 1970, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHO", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXE", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHE", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXD", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXE", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXE", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHO", - 2010, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXG", - 1980, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXD", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHE", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXG", - 1970, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXG", - 2010, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHO", - 1970, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXD", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXD", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXD", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHO", - 2000, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHO", - 2010, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXD", - 1970, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHE", - 1990, - "RH", - "inter", - "day" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHO", - 1980, - "RH", - "inter", - "day" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXE", - 2000, - "TX", - "inter", - "day" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXE", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXE", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXG", - 1990, - "TX", - "inter", - "day" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHO", - 1990, - "RH", - "inter", - "day" - ] - ], - "DemandConstraint_rpsdc": [ - [ - "utopia", - 2010, - "inter", - "night", - "RH" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "RL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RH" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RL" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RH" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TX" - ], - [ - "utopia", - 2000, - "inter", - "day", - "RL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "RH" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RH" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RL" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TX" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TX" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RH" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RH" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TX" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "TX" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RH" - ], - [ - "utopia", - 2000, - "summer", - "day", - "RL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RH" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RH" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RH" - ], - [ - "utopia", - 2000, - "summer", - "day", - "RH" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RH" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TX" - ], - [ - "utopia", - 1990, - "inter", - "day", - "RL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "TX" - ], - [ - "utopia", - 1990, - "inter", - "day", - "RH" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RH" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RH" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TX" - ], - [ - "utopia", - 2000, - "inter", - "day", - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TX" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "RH" - ] - ], - "EmissionActivity_reitvo": [ - [ - "utopia", - "co2", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - "co2", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - "co2", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - "nox", - "HCO", - "E01", - 1960, - "ELC" - ], - [ - "utopia", - "co2", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - "nox", - "ELC", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - "co2", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - "co2", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - "nox", - "ELC", - "RL1", - 2010, - "RL" - ], - [ - "utopia", - "co2", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - "nox", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - "nox", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - "co2", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - "co2", - "OIL", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - "co2", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - "nox", - "URN", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - "co2", - "OIL", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - "co2", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - "co2", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - "nox", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - "nox", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - "co2", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - "nox", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - "co2", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - "co2", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - "nox", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - "nox", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - "co2", - "ELC", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - "nox", - "OIL", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - "nox", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - "nox", - "OIL", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - "nox", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - "co2", - "DSL", - "E70", - 2010, - "ELC" - ], - [ - "utopia", - "co2", - "GSL", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - "nox", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - "co2", - "ELC", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - "nox", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - "nox", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - "nox", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - "co2", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - "nox", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - "nox", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - "co2", - "ELC", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - "nox", - "HYD", - "E31", - 2010, - "ELC" - ], - [ - "utopia", - "co2", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - "nox", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - "nox", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - "nox", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - "co2", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - "nox", - "ELC", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - "nox", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - "nox", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - "co2", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - "nox", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - "nox", - "DSL", - "E70", - 2010, - "ELC" - ], - [ - "utopia", - "co2", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - "nox", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - "nox", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - "nox", - "ELC", - "RL1", - 2000, - "RL" - ], - [ - "utopia", - "co2", - "HCO", - "E01", - 1960, - "ELC" - ], - [ - "utopia", - "co2", - "ELC", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - "co2", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - "nox", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - "co2", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - "nox", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - "co2", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - "nox", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - "co2", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - "co2", - "DSL", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - "co2", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - "nox", - "HCO", - "E01", - 2010, - "ELC" - ], - [ - "utopia", - "co2", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - "co2", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - "co2", - "ELC", - "RL1", - 2010, - "RL" - ], - [ - "utopia", - "nox", - "DSL", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - "nox", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - "co2", - "URN", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - "nox", - "ELC", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - "nox", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - "co2", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - "co2", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - "co2", - "DSL", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - "co2", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - "co2", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - "nox", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - "co2", - "DSL", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - "co2", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - "co2", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - "co2", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - "nox", - "DSL", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - "nox", - "FEQ", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - "co2", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - "nox", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - "co2", - "DSL", - "E70", - 1960, - "ELC" - ], - [ - "utopia", - "co2", - "GSL", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - "co2", - "ELC", - "RL1", - 2000, - "RL" - ], - [ - "utopia", - "nox", - "GSL", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - "co2", - "DSL", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - "nox", - "GSL", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - "nox", - "ELC", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - "nox", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - "co2", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - "co2", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - "co2", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - "nox", - "DSL", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - "co2", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - "nox", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - "nox", - "DSL", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - "co2", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - "nox", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - "nox", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - "nox", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - "nox", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - "co2", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - "co2", - "HCO", - "E01", - 2010, - "ELC" - ], - [ - "utopia", - "nox", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - "nox", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - "nox", - "DSL", - "E70", - 1960, - "ELC" - ], - [ - "utopia", - "nox", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - "co2", - "HYD", - "E31", - 2010, - "ELC" - ], - [ - "utopia", - "nox", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - "co2", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - "co2", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - "nox", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - "nox", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - "co2", - "FEQ", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - "co2", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - "nox", - "DSL", - "E70", - 1990, - "ELC" - ] - ], - "FlexVarAnnual_rpitvo": [], - "FlexVar_rpsditvo": [], - "FlowInStorage_rpsditvo": [ - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ] - ], - "FlowVarAnnual_rpitvo": [], - "FlowVar_rpsditvo": [ - [ - "utopia", - 2000, - "inter", - "day", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "day", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "day", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "night", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "OIL", - "SRE", - 2000, - "DSL" + "TX" ], [ "utopia", - 2010, - "summer", - "day", - "OIL", - "SRE", 2000, - "GSL" + "RH" ], [ "utopia", 2010, - "winter", - "night", - "HYD", - "E31", - 2000, - "ELC" + "RL" ], [ "utopia", - 2000, - "inter", - "day", - "ethos", - "IMPURN1", 1990, - "URN" + "RL" ], [ "utopia", 2010, - "winter", - "day", - "ELC", - "RHE", - 1990, - "RH" + "TX" ], [ "utopia", 2010, - "inter", - "day", - "OIL", - "SRE", - 2000, - "DSL" + "RH" ], [ "utopia", - 2000, - "winter", - "night", - "ELC", - "TXE", - 2000, + 1990, "TX" ], [ "utopia", 2000, - "winter", - "day", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ethos", - "IMPHYD", - 1990, - "HYD" + "RL" ], [ "utopia", 1990, - "winter", - "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], + "RH" + ] + ], + "EmissionActivity_reitvo": [ [ "utopia", + "co2", + "DSL", + "RHO", 2000, - "winter", - "night", - "OIL", - "SRE", - 1990, - "GSL" + "RH" ], [ "utopia", - 2010, - "winter", - "night", - "GSL", - "TXG", - 2010, - "TX" + "co2", + "ethos", + "IMPHYD", + 1990, + "HYD" ], [ "utopia", - 2010, - "winter", - "night", + "co2", "HCO", "E01", 1980, @@ -14402,59 +10270,39 @@ ], [ "utopia", - 2000, - "summer", - "day", - "OIL", - "SRE", - 2000, - "DSL" + "nox", + "HCO", + "E01", + 1960, + "ELC" ], [ "utopia", + "co2", + "ELC", + "E51", 2010, - "summer", - "night", - "OIL", - "SRE", - 1990, - "GSL" + "ELC" ], [ "utopia", - 1990, - "summer", - "night", + "nox", "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "day", - "DSL", - "RHO", - 1990, - "RH" + "RL1", + 1980, + "RL" ], [ "utopia", - 2000, - "winter", - "night", - "HCO", - "E01", + "co2", + "URN", + "E21", 2000, "ELC" ], [ "utopia", - 2010, - "winter", - "day", + "co2", "ethos", "IMPDSL1", 1990, @@ -14462,19 +10310,15 @@ ], [ "utopia", - 1990, - "summer", - "day", - "HCO", - "E01", - 1970, - "ELC" + "nox", + "ELC", + "RL1", + 2010, + "RL" ], [ "utopia", - 1990, - "summer", - "night", + "co2", "ethos", "IMPHCO1", 1990, @@ -14482,319 +10326,191 @@ ], [ "utopia", + "nox", + "OIL", + "SRE", 1990, - "inter", - "day", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 1990, - "inter", - "day", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ELC", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "DSL", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ethos", - "IMPHYD", - 1990, - "HYD" + "GSL" ], [ "utopia", - 2000, - "summer", - "night", + "nox", "DSL", "E70", - 1970, + 1980, "ELC" ], [ "utopia", - 2010, - "winter", - "night", + "co2", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + "co2", "OIL", "SRE", - 2000, + 2010, "DSL" ], [ "utopia", - 1990, - "summer", - "day", - "ELC", - "RHE", - 1990, - "RH" + "co2", + "HCO", + "E01", + 1970, + "ELC" ], [ "utopia", - 2000, - "summer", - "night", - "HYD", - "E31", - 2000, + "nox", + "URN", + "E21", + 2010, "ELC" ], [ "utopia", + "co2", + "OIL", + "SRE", 2010, - "winter", - "day", - "DSL", - "E70", - 1980, - "ELC" + "GSL" ], [ "utopia", - 2000, - "winter", - "day", + "co2", "URN", "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "HYD", - "E31", 1990, "ELC" ], [ "utopia", - 2010, - "inter", - "night", - "HCO", - "E01", + "co2", + "GSL", + "TXG", 1980, - "ELC" + "TX" ], [ "utopia", - 2010, - "inter", - "day", - "ethos", - "IMPGSL1", + "nox", + "ELC", + "E51", 1990, - "GSL" + "ELC" ], [ "utopia", - 1990, - "summer", - "night", - "GSL", - "TXG", - 1990, + "nox", + "ELC", + "TXE", + 2000, "TX" ], [ "utopia", + "co2", + "DSL", + "TXD", 1990, - "winter", - "day", - "HCO", - "E01", - 1970, - "ELC" + "TX" ], [ "utopia", - 2010, - "winter", - "day", - "ELC", - "E51", - 2000, + "nox", + "DSL", + "E70", + 1970, "ELC" ], [ "utopia", - 1990, - "inter", - "day", - "ELC", - "RHE", - 1990, + "co2", + "DSL", + "RHO", + 1980, "RH" ], [ "utopia", + "co2", + "HYD", + "E31", 2000, - "winter", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" + "ELC" ], [ "utopia", - 2010, - "winter", - "night", + "nox", "ethos", - "IMPDSL1", + "IMPFEQ", 1990, - "DSL" + "FEQ" ], [ "utopia", - 2010, - "winter", - "night", - "ELC", - "RL1", - 2010, - "RL" + "nox", + "DSL", + "RHO", + 1990, + "RH" ], [ "utopia", - 2010, - "summer", - "night", + "co2", "ELC", - "TXE", + "RHE", 2010, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "TXE", - 1990, - "TX" + "RH" ], [ "utopia", + "nox", + "OIL", + "SRE", 2010, - "inter", - "day", - "DSL", - "TXD", - 2010, - "TX" + "DSL" ], [ "utopia", - 1990, - "summer", - "day", - "DSL", - "E70", - 1960, + "nox", + "URN", + "E21", + 2000, "ELC" ], [ "utopia", - 1990, - "inter", - "day", - "ethos", - "IMPGSL1", - 1990, + "nox", + "OIL", + "SRE", + 2010, "GSL" ], [ "utopia", - 1990, - "inter", - "night", - "ELC", - "TXE", + "nox", + "GSL", + "TXG", 1990, "TX" ], [ "utopia", + "co2", + "DSL", + "E70", 2010, - "summer", - "day", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "HYD", - "E31", - 1980, "ELC" ], [ "utopia", - 1990, - "winter", - "day", + "co2", "GSL", "TXG", 1970, @@ -14802,489 +10518,431 @@ ], [ "utopia", + "nox", + "FEQ", + "E21", 1990, - "winter", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" + "ELC" ], [ "utopia", + "co2", + "ELC", + "TXE", 2010, - "winter", - "night", - "DSL", - "E70", - 2000, - "ELC" + "TX" ], [ "utopia", - 2000, - "inter", - "day", + "nox", "ELC", "E51", - 1990, + 1980, "ELC" ], [ "utopia", - 1990, - "summer", - "night", + "nox", "ELC", - "RL1", - 1980, - "RL" + "TXE", + 1990, + "TX" ], [ "utopia", - 2000, - "summer", - "night", - "ELC", - "RHE", + "nox", + "ethos", + "IMPGSL1", 1990, - "RH" + "GSL" ], [ "utopia", - 2000, - "summer", - "night", + "co2", "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "HYD", - "E31", - 2010, - "ELC" + "TXD", + 1980, + "TX" ], [ "utopia", - 2010, - "summer", - "day", - "ELC", - "TXE", - 2010, + "nox", + "DSL", + "TXD", + 1990, "TX" ], [ "utopia", - 2010, - "winter", - "night", + "nox", "HCO", "E01", - 2000, + 1990, "ELC" ], [ "utopia", + "co2", + "ELC", + "RL1", 1990, - "winter", - "night", - "DSL", - "E70", - 1970, - "ELC" + "RL" ], [ "utopia", - 2010, - "winter", - "day", - "DSL", - "E70", + "nox", + "HYD", + "E31", 2010, "ELC" ], [ "utopia", + "co2", + "FEQ", + "E21", 2000, - "summer", - "night", + "ELC" + ], + [ + "utopia", + "nox", "DSL", "RHO", - 2000, + 1980, "RH" ], [ "utopia", - 2010, - "inter", - "night", + "nox", "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", + "IMPURN1", 1990, - "inter", - "night", - "DSL", - "E70", - 1980, - "ELC" + "URN" ], [ "utopia", + "nox", + "OIL", + "SRE", 2000, - "winter", - "day", - "ethos", - "IMPHYD", - 1990, - "HYD" + "DSL" ], [ "utopia", - 2000, - "winter", - "night", + "co2", "GSL", "TXG", - 1980, + 2000, "TX" ], [ "utopia", - 2010, - "winter", - "day", - "DSL", - "RHO", + "nox", + "ELC", + "RHE", 2010, "RH" ], [ "utopia", + "nox", + "OIL", + "SRE", 2000, - "winter", - "day", - "HCO", - "E01", + "GSL" + ], + [ + "utopia", + "nox", + "GSL", + "TXG", 1980, + "TX" + ], + [ + "utopia", + "co2", + "DSL", + "E70", + 2000, "ELC" ], [ "utopia", + "nox", + "ELC", + "E51", 2010, - "summer", - "night", - "HYD", - "E31", - 1980, "ELC" ], [ "utopia", + "nox", + "DSL", + "E70", 2010, - "inter", - "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" + "ELC" ], [ "utopia", - 2010, - "winter", - "night", - "ELC", - "E51", + "co2", + "HCO", + "E01", 2000, "ELC" ], [ "utopia", - 2010, - "inter", - "night", - "OIL", - "SRE", - 1990, - "DSL" + "nox", + "DSL", + "TXD", + 1980, + "TX" ], [ "utopia", - 1990, - "inter", - "night", - "OIL", - "SRE", - 1990, - "GSL" + "nox", + "HCO", + "E01", + 1980, + "ELC" ], [ "utopia", + "nox", + "ELC", + "RL1", 2000, - "winter", - "night", - "ethos", - "IMPOIL1", - 1990, - "OIL" + "RL" ], [ "utopia", - 2000, - "inter", - "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" + "co2", + "HCO", + "E01", + 1960, + "ELC" ], [ "utopia", + "co2", + "ELC", + "RL1", + 1980, + "RL" + ], + [ + "utopia", + "co2", + "ethos", + "IMPFEQ", 1990, - "summer", - "day", - "DSL", - "E70", - 1990, - "ELC" + "FEQ" ], [ "utopia", - 2010, - "summer", - "day", - "HCO", - "E01", - 2010, + "nox", + "ELC", + "E51", + 2000, "ELC" ], [ "utopia", - 2000, - "winter", - "day", - "DSL", - "TXD", - 2000, + "co2", + "GSL", + "TXG", + 1990, "TX" ], [ "utopia", - 1990, - "summer", - "day", - "DSL", - "RHO", - 1970, - "RH" + "nox", + "HYD", + "E31", + 1980, + "ELC" ], [ "utopia", + "co2", + "OIL", + "SRE", 2000, - "inter", - "night", - "ELC", - "RL1", - 2000, - "RL" + "DSL" ], [ "utopia", - 1990, - "summer", - "day", - "ELC", - "E51", - 1980, + "nox", + "DSL", + "E70", + 2000, "ELC" ], [ "utopia", + "co2", + "OIL", + "SRE", 2000, - "inter", - "night", - "ethos", - "IMPOIL1", - 1990, - "OIL" + "GSL" ], [ "utopia", - 1990, - "inter", - "day", - "ELC", - "E51", - 1990, - "ELC" + "co2", + "DSL", + "RHO", + 2010, + "RH" ], [ "utopia", - 2010, - "summer", - "night", + "co2", "ethos", - "IMPHYD", + "IMPGSL1", 1990, - "HYD" + "GSL" ], [ "utopia", - 2010, - "summer", - "night", + "nox", "HCO", "E01", - 1980, + 2010, "ELC" ], [ "utopia", - 2010, - "winter", - "day", - "HCO", - "E01", - 1990, + "co2", + "DSL", + "E70", + 1970, "ELC" ], [ "utopia", + "co2", + "HCO", + "E01", 1990, - "summer", - "night", - "HYD", - "E31", - 1980, "ELC" ], [ "utopia", - 2000, - "summer", - "day", + "co2", "ELC", - "RHE", - 1990, - "RH" + "RL1", + 2010, + "RL" ], [ "utopia", - 1990, - "summer", - "day", + "nox", "DSL", "TXD", - 1980, + 1970, "TX" ], [ "utopia", - 1990, - "winter", - "day", - "GSL", - "TXG", - 1990, - "TX" + "nox", + "HCO", + "E01", + 1970, + "ELC" ], [ "utopia", - 2000, - "inter", - "night", + "co2", + "URN", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + "nox", "ELC", - "E51", - 2000, + "RL1", + 1990, + "RL" + ], + [ + "utopia", + "nox", + "URN", + "E21", + 1990, "ELC" ], [ "utopia", - 2000, - "winter", - "night", - "DSL", - "TXD", - 2000, - "TX" + "co2", + "ethos", + "IMPURN1", + 1990, + "URN" ], [ "utopia", + "co2", + "ELC", + "TXE", 2000, - "winter", - "day", - "GSL", - "TXG", - 1980, "TX" ], [ "utopia", - 2000, - "summer", - "day", + "co2", "DSL", "RHO", - 1980, + 1970, "RH" ], [ "utopia", + "co2", + "ELC", + "E51", 2000, - "inter", - "day", - "DSL", - "E70", - 1980, "ELC" ], [ "utopia", - 2000, - "inter", - "night", - "HCO", - "E01", - 1980, + "co2", + "HYD", + "E31", + 1990, "ELC" ], [ "utopia", - 2010, - "inter", - "night", - "HCO", - "E01", - 2010, - "ELC" + "nox", + "ethos", + "IMPOIL1", + 1990, + "OIL" ], [ "utopia", - 2010, - "inter", - "day", + "co2", "DSL", - "E70", + "TXD", + 2010, + "TX" + ], + [ + "utopia", + "co2", + "OIL", + "SRE", 1990, - "ELC" + "DSL" ], [ "utopia", - 2010, - "inter", - "night", + "co2", "ELC", "RHE", 2000, @@ -15292,159 +10950,127 @@ ], [ "utopia", - 2010, - "inter", - "night", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ethos", - "IMPOIL1", + "co2", + "OIL", + "SRE", 1990, - "OIL" + "GSL" ], [ "utopia", - 1990, - "summer", - "day", - "ELC", - "TXE", - 1990, - "TX" + "nox", + "DSL", + "RHO", + 2010, + "RH" ], [ "utopia", - 1990, - "summer", - "night", - "DSL", - "E70", - 1980, + "nox", + "FEQ", + "E21", + 2010, "ELC" ], [ "utopia", + "co2", + "FEQ", + "E21", 1990, - "winter", - "night", - "HCO", - "E01", - 1980, "ELC" ], [ "utopia", - 2010, - "summer", - "night", + "nox", "HCO", "E01", - 2010, + 2000, "ELC" ], [ "utopia", - 2010, - "inter", - "day", - "ELC", - "RHE", - 2010, - "RH" + "co2", + "DSL", + "E70", + 1960, + "ELC" ], [ "utopia", + "co2", + "GSL", + "TXG", 2010, - "summer", - "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" + "TX" ], [ "utopia", - 2010, - "winter", - "day", - "FEQ", - "E21", - 1990, - "ELC" + "co2", + "ELC", + "RL1", + 2000, + "RL" ], [ "utopia", - 1990, - "winter", - "night", + "nox", "GSL", "TXG", - 1990, + 2010, "TX" ], [ "utopia", - 2000, - "inter", - "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" + "co2", + "DSL", + "TXD", + 1970, + "TX" ], [ "utopia", - 2000, - "summer", - "day", + "nox", + "GSL", + "TXG", + 1970, + "TX" + ], + [ + "utopia", + "nox", "ELC", - "E51", - 2000, - "ELC" + "TXE", + 2010, + "TX" ], [ "utopia", + "nox", + "HYD", + "E31", 2000, - "summer", - "day", - "ethos", - "IMPURN1", - 1990, - "URN" + "ELC" ], [ "utopia", - 2010, - "summer", - "day", - "ethos", - "IMPGSL1", + "co2", + "ELC", + "TXE", 1990, - "GSL" + "TX" ], [ "utopia", + "co2", + "ELC", + "E51", 1990, - "summer", - "day", - "ethos", - "IMPURN1", - 1990, - "URN" + "ELC" ], [ "utopia", - 2010, - "winter", - "day", + "co2", "HYD", "E31", 1980, @@ -15452,39 +11078,55 @@ ], [ "utopia", - 2000, - "inter", - "day", - "GSL", - "TXG", + "nox", + "DSL", + "RHO", + 1970, + "RH" + ], + [ + "utopia", + "co2", + "DSL", + "TXD", 2000, "TX" ], [ "utopia", - 2010, - "inter", - "night", - "DSL", - "E70", + "nox", + "ethos", + "IMPDSL1", 1990, - "ELC" + "DSL" ], [ "utopia", - 2000, - "summer", - "night", + "nox", + "DSL", + "TXD", + 2010, + "TX" + ], + [ + "utopia", + "co2", "ELC", - "TXE", + "RHE", 1990, - "TX" + "RH" ], [ "utopia", - 2000, - "winter", - "day", + "nox", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + "nox", "ELC", "RHE", 2000, @@ -15492,157 +11134,147 @@ ], [ "utopia", - 2010, - "inter", - "day", - "FEQ", - "E21", + "nox", + "ethos", + "IMPHCO1", 1990, - "ELC" + "HCO" ], [ "utopia", - 2010, - "winter", - "night", - "ethos", - "IMPURN1", + "nox", + "DSL", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + "co2", + "DSL", + "E70", 1990, - "URN" + "ELC" ], [ "utopia", - 2010, - "inter", - "night", - "ELC", - "E51", + "co2", + "HCO", + "E01", 2010, "ELC" ], [ "utopia", - 2010, - "inter", - "day", - "DSL", - "RHO", + "nox", + "FEQ", + "E21", 2000, - "RH" + "ELC" ], [ "utopia", + "nox", + "ethos", + "IMPHYD", 1990, - "inter", - "day", - "OIL", - "SRE", - 1990, - "GSL" + "HYD" ], [ "utopia", + "nox", + "DSL", + "E70", + 1960, + "ELC" + ], + [ + "utopia", + "nox", + "GSL", + "TXG", 2000, - "winter", - "night", - "OIL", - "SRE", - 2000, - "DSL" + "TX" ], [ "utopia", - 2010, - "summer", - "day", - "FEQ", - "E21", + "co2", + "HYD", + "E31", 2010, "ELC" ], [ "utopia", - 2000, - "inter", - "day", - "FEQ", - "E21", + "nox", + "HYD", + "E31", 1990, "ELC" ], [ "utopia", - 2010, - "summer", - "night", - "DSL", - "TXD", - 2000, - "TX" + "co2", + "ELC", + "E51", + 1980, + "ELC" ], [ "utopia", + "co2", + "ethos", + "IMPOIL1", 1990, - "inter", - "day", - "FEQ", - "E21", - 1990, - "ELC" + "OIL" ], [ "utopia", - 2010, - "inter", - "day", - "URN", - "E21", + "nox", + "DSL", + "TXD", 2000, - "ELC" + "TX" ], [ "utopia", + "nox", + "ELC", + "RHE", 1990, - "winter", - "day", - "OIL", - "SRE", - 1990, - "DSL" + "RH" ], [ "utopia", - 2000, - "winter", - "night", + "co2", "FEQ", "E21", - 2000, + 2010, "ELC" ], [ "utopia", - 1990, - "inter", - "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" + "co2", + "DSL", + "E70", + 1980, + "ELC" ], [ "utopia", - 1990, - "summer", - "night", - "FEQ", - "E21", + "nox", + "DSL", + "E70", 1990, "ELC" - ], + ] + ], + "FlexVarAnnual_rpitvo": [], + "FlexVar_rpsditvo": [], + "FlowInStorage_rpsditvo": [ [ "utopia", - 1990, + 2000, "winter", "day", "ELC", @@ -15652,93 +11284,83 @@ ], [ "utopia", - 2010, + 2000, "inter", "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", + "ELC", + "E51", 2000, - "summer", - "night", - "OIL", - "SRE", - 1990, - "DSL" + "ELC" ], [ "utopia", 2010, - "inter", + "winter", "day", - "OIL", - "SRE", - 1990, - "GSL" + "ELC", + "E51", + 2000, + "ELC" ], [ "utopia", - 1990, - "winter", + 2000, + "inter", "night", "ELC", - "RL1", - 1990, - "RL" + "E51", + 1980, + "ELC" ], [ "utopia", - 2010, - "inter", + 2000, + "winter", "night", - "FEQ", - "E21", - 1990, + "ELC", + "E51", + 2000, "ELC" ], [ "utopia", 2000, "winter", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" + "day", + "ELC", + "E51", + 2000, + "ELC" ], [ "utopia", - 1990, - "inter", + 2000, + "winter", "night", - "HCO", - "E01", - 1990, + "ELC", + "E51", + 1980, "ELC" ], [ "utopia", - 1990, + 2010, "inter", "day", - "HYD", - "E31", - 1980, + "ELC", + "E51", + 2000, "ELC" ], [ "utopia", 2010, - "summer", + "inter", "day", - "OIL", - "SRE", - 2000, - "DSL" + "ELC", + "E51", + 1980, + "ELC" ], [ "utopia", @@ -15746,27 +11368,17 @@ "summer", "night", "ELC", - "RL1", - 2000, - "RL" - ], - [ - "utopia", - 1990, - "winter", - "night", - "HYD", - "E31", + "E51", 1990, "ELC" ], [ "utopia", - 2000, - "summer", + 1990, + "winter", "day", - "HCO", - "E01", + "ELC", + "E51", 1980, "ELC" ], @@ -15776,84 +11388,84 @@ "summer", "day", "ELC", - "TXE", + "E51", 1990, - "TX" + "ELC" ], [ "utopia", 2010, - "summer", + "winter", "day", "ELC", - "RHE", - 2000, - "RH" + "E51", + 1980, + "ELC" ], [ "utopia", - 2000, + 1990, "winter", "night", "ELC", - "RHE", + "E51", 1990, - "RH" + "ELC" ], [ "utopia", - 2000, - "winter", - "night", - "URN", - "E21", - 1990, + 2010, + "summer", + "day", + "ELC", + "E51", + 2010, "ELC" ], [ "utopia", 2000, "inter", - "night", - "DSL", - "TXD", + "day", + "ELC", + "E51", 1990, - "TX" + "ELC" ], [ "utopia", - 2000, - "winter", + 1990, + "summer", "day", - "OIL", - "SRE", - 2000, - "DSL" + "ELC", + "E51", + 1990, + "ELC" ], [ "utopia", 2010, - "winter", + "summer", "day", - "ethos", - "IMPHYD", + "ELC", + "E51", 1990, - "HYD" + "ELC" ], [ "utopia", 2010, - "winter", - "day", - "URN", - "E21", + "summer", + "night", + "ELC", + "E51", 2000, "ELC" ], [ "utopia", 1990, - "winter", + "inter", "night", "ELC", "E51", @@ -15863,8 +11475,8 @@ [ "utopia", 2010, - "inter", - "day", + "summer", + "night", "ELC", "E51", 1990, @@ -15875,185 +11487,185 @@ 2010, "winter", "night", - "FEQ", - "E21", - 2010, + "ELC", + "E51", + 2000, "ELC" ], - [ - "utopia", - 2010, - "winter", - "day", - "OIL", - "SRE", - 2010, - "GSL" - ], [ "utopia", 1990, "summer", "night", - "OIL", - "SRE", - 1990, - "DSL" + "ELC", + "E51", + 1980, + "ELC" ], [ "utopia", 1990, - "summer", - "night", - "HCO", - "E01", - 1960, + "inter", + "day", + "ELC", + "E51", + 1980, "ELC" ], [ "utopia", - 2010, - "summer", + 2000, + "winter", "day", - "ethos", - "IMPDSL1", + "ELC", + "E51", 1990, - "DSL" + "ELC" ], [ "utopia", - 1990, - "inter", + 2010, + "winter", "day", - "ethos", - "IMPOIL1", - 1990, - "OIL" + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ELC", + "E51", + 1980, + "ELC" ], [ "utopia", 2000, - "inter", + "summer", "day", "ELC", - "RHE", + "E51", 2000, - "RH" + "ELC" ], [ "utopia", + 2000, + "inter", + "night", + "ELC", + "E51", 1990, - "winter", - "day", - "DSL", - "RHO", - 1980, - "RH" + "ELC" ], [ "utopia", - 1990, - "summer", - "day", - "OIL", - "SRE", - 1990, - "GSL" + 2010, + "inter", + "night", + "ELC", + "E51", + 2000, + "ELC" ], [ "utopia", 2000, "winter", "night", - "DSL", - "RHO", + "ELC", + "E51", 1990, - "RH" + "ELC" ], [ "utopia", - 2000, - "summer", - "night", - "HCO", - "E01", - 1980, + 2010, + "inter", + "day", + "ELC", + "E51", + 2010, "ELC" ], [ "utopia", 2010, - "summer", + "inter", "night", - "GSL", - "TXG", - 2010, - "TX" + "ELC", + "E51", + 1980, + "ELC" ], [ "utopia", - 2010, - "inter", - "day", - "HYD", - "E31", + 1990, + "winter", + "night", + "ELC", + "E51", 1980, "ELC" ], [ "utopia", 2010, - "summer", + "inter", "day", - "DSL", - "E70", + "ELC", + "E51", 1990, "ELC" ], [ "utopia", - 1990, - "inter", + 2010, + "winter", "night", - "HCO", - "E01", - 1960, + "ELC", + "E51", + 1980, "ELC" ], [ "utopia", - 2000, + 1990, "winter", "day", - "DSL", - "RHO", - 2000, - "RH" + "ELC", + "E51", + 1990, + "ELC" ], [ "utopia", - 2010, - "winter", - "day", - "HYD", - "E31", - 2010, + 2000, + "summer", + "night", + "ELC", + "E51", + 1980, "ELC" ], [ "utopia", - 1990, - "inter", + 2010, + "winter", "day", - "DSL", - "E70", - 1970, + "ELC", + "E51", + 1990, "ELC" ], [ "utopia", 2000, - "winter", + "summer", "day", "ELC", "E51", @@ -16062,33 +11674,33 @@ ], [ "utopia", - 1990, + 2000, "inter", - "night", - "HYD", - "E31", - 1980, + "day", + "ELC", + "E51", + 2000, "ELC" ], [ "utopia", 2010, "summer", - "night", - "OIL", - "SRE", + "day", + "ELC", + "E51", 2000, - "DSL" + "ELC" ], [ "utopia", - 2010, - "winter", - "day", - "ethos", - "IMPOIL1", 1990, - "OIL" + "summer", + "day", + "ELC", + "E51", + 1980, + "ELC" ], [ "utopia", @@ -16096,108 +11708,98 @@ "summer", "night", "ELC", - "RHE", - 2000, - "RH" + "E51", + 2010, + "ELC" ], [ "utopia", - 2000, - "inter", + 2010, + "summer", "day", - "URN", - "E21", - 2000, + "ELC", + "E51", + 1980, "ELC" ], [ "utopia", - 2010, - "inter", - "day", + 2000, + "summer", + "night", "ELC", - "TXE", + "E51", 2000, - "TX" + "ELC" ], [ "utopia", - 2000, + 1990, "inter", "day", - "ethos", - "IMPFEQ", + "ELC", + "E51", 1990, - "FEQ" + "ELC" ], [ "utopia", - 2000, - "winter", - "day", - "DSL", - "E70", - 1990, + 2010, + "inter", + "night", + "ELC", + "E51", + 2010, "ELC" ], [ "utopia", 1990, - "summer", + "inter", "night", - "HCO", - "E01", + "ELC", + "E51", 1990, "ELC" ], [ "utopia", + 2010, + "inter", + "night", + "ELC", + "E51", 1990, - "winter", - "day", - "DSL", - "TXD", - 1980, - "TX" + "ELC" ], [ "utopia", 2000, "inter", "day", - "HYD", - "E31", - 2000, + "ELC", + "E51", + 1980, "ELC" ], [ "utopia", - 1990, + 2010, "winter", "night", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "night", - "HYD", - "E31", - 2000, + "ELC", + "E51", + 2010, "ELC" ], [ "utopia", - 2010, - "inter", - "day", - "HYD", - "E31", - 2010, + 1990, + "summer", + "night", + "ELC", + "E51", + 1990, "ELC" ], [ @@ -16205,386 +11807,304 @@ 2010, "winter", "night", - "URN", - "E21", + "ELC", + "E51", 1990, "ELC" - ], + ] + ], + "FlowVarAnnual_rpitvo": [ [ "utopia", + 2000, + "DSL", + "TXD", 1990, - "summer", - "day", - "GSL", - "TXG", - 1970, "TX" ], [ "utopia", 1990, - "inter", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" + "GSL", + "TXG", + 1970, + "TX" ], [ "utopia", - 1990, - "inter", - "day", + 2000, "GSL", "TXG", - 1980, + 2000, "TX" ], [ "utopia", 2010, - "inter", - "day", - "ethos", - "IMPOIL1", - 1990, - "OIL" + "ELC", + "RHE", + 2000, + "RH" ], [ "utopia", 1990, - "inter", - "night", - "URN", - "E21", + "ELC", + "RL1", 1990, - "ELC" + "RL" ], [ "utopia", 2010, - "summer", - "night", "ELC", - "E51", - 1980, - "ELC" + "RL1", + 2010, + "RL" ], [ "utopia", 2000, - "winter", - "day", - "ethos", - "IMPOIL1", - 1990, - "OIL" + "GSL", + "TXG", + 1980, + "TX" ], [ "utopia", - 2010, - "summer", - "day", + 1990, "DSL", "RHO", - 2000, + 1980, "RH" ], [ "utopia", - 2000, - "inter", - "day", + 2010, "DSL", "RHO", - 1980, + 2010, "RH" ], [ "utopia", 2000, - "inter", - "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" + "ELC", + "RHE", + 2000, + "RH" ], [ "utopia", 1990, - "inter", - "day", - "DSL", - "RHO", - 1980, - "RH" + "ELC", + "TXE", + 1990, + "TX" ], [ "utopia", 2010, - "inter", - "night", "ELC", "TXE", - 2000, + 2010, "TX" ], [ "utopia", 1990, - "inter", - "night", - "DSL", - "RHO", + "GSL", + "TXG", 1980, - "RH" + "TX" ], [ "utopia", 2010, - "winter", - "day", - "OIL", - "SRE", + "DSL", + "RHO", 1990, - "DSL" + "RH" ], [ "utopia", + 2010, + "GSL", + "TXG", 2000, - "winter", - "night", - "DSL", - "E70", - 1990, - "ELC" + "TX" ], [ "utopia", - 1990, - "winter", - "night", + 2000, "DSL", - "TXD", - 1980, - "TX" + "RHO", + 2000, + "RH" ], [ "utopia", - 2010, - "summer", - "day", - "URN", - "E21", 2000, - "ELC" + "DSL", + "RHO", + 1980, + "RH" ], [ "utopia", - 2010, - "summer", - "night", - "DSL", - "E70", + 2000, + "GSL", + "TXG", 1990, - "ELC" + "TX" ], [ "utopia", 1990, - "summer", - "night", "DSL", - "RHO", + "TXD", 1980, - "RH" + "TX" ], [ "utopia", - 2000, - "inter", - "night", + 2010, "DSL", - "RHO", - 2000, + "TXD", + 2010, + "TX" + ], + [ + "utopia", + 1990, + "ELC", + "RHE", + 1990, "RH" ], [ "utopia", 2010, - "winter", - "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "night", "ELC", - "E51", - 2000, - "ELC" + "RHE", + 2010, + "RH" ], [ "utopia", 2000, - "winter", - "day", - "FEQ", - "E21", + "ELC", + "TXE", 1990, - "ELC" + "TX" ], [ "utopia", 2000, - "inter", - "day", - "OIL", - "SRE", - 1990, - "DSL" + "DSL", + "TXD", + 2000, + "TX" ], [ "utopia", 2010, - "summer", - "day", - "OIL", - "SRE", + "ELC", + "RHE", 1990, - "GSL" + "RH" ], [ "utopia", - 2010, - "inter", - "night", - "ethos", - "IMPOIL1", 1990, - "OIL" + "DSL", + "RHO", + 1990, + "RH" ], [ "utopia", 2000, - "inter", - "night", - "URN", - "E21", + "ELC", + "RL1", 2000, - "ELC" + "RL" ], [ "utopia", - 2010, - "summer", - "day", - "DSL", - "TXD", 2000, - "TX" + "ELC", + "RHE", + 1990, + "RH" ], [ "utopia", 2000, - "inter", - "day", "DSL", "TXD", 1980, "TX" ], - [ - "utopia", - 2010, - "inter", - "night", - "OIL", - "SRE", - 2000, - "GSL" - ], [ "utopia", 1990, - "inter", - "day", "DSL", "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "TXE", 1990, "TX" ], [ "utopia", 1990, - "winter", - "day", - "HYD", - "E31", - 1990, - "ELC" + "ELC", + "RL1", + 1980, + "RL" ], [ "utopia", - 2000, - "inter", - "night", - "DSL", - "E70", 1990, - "ELC" + "DSL", + "RHO", + 1970, + "RH" ], [ "utopia", 1990, - "winter", - "night", - "ELC", - "TXE", + "GSL", + "TXG", 1990, "TX" ], [ "utopia", 2010, - "inter", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" + "DSL", + "RHO", + 2000, + "RH" ], [ "utopia", 2010, - "winter", - "night", "GSL", "TXG", - 2000, + 2010, "TX" ], [ "utopia", 2000, - "winter", - "day", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2010, "ELC", "TXE", 2000, @@ -16593,76 +12113,62 @@ [ "utopia", 1990, - "summer", - "day", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "OIL", - "SRE", - 1990, - "DSL" + "DSL", + "TXD", + 1970, + "TX" ], [ "utopia", - 1990, - "summer", - "night", + 2010, "DSL", "TXD", - 1980, + 2000, "TX" ], [ "utopia", 2000, - "summer", - "night", "ELC", - "E51", - 1990, - "ELC" - ], + "TXE", + 2000, + "TX" + ] + ], + "FlowVar_rpsditvo": [ [ "utopia", 1990, - "summer", + "winter", "day", - "HCO", - "E01", - 1960, - "ELC" + "ethos", + "IMPURN1", + 1990, + "URN" ], [ "utopia", - 2010, - "winter", + 2000, + "inter", "day", - "GSL", - "TXG", - 2010, - "TX" + "ELC", + "E51", + 1980, + "ELC" ], [ "utopia", - 1990, + 2010, "inter", "day", - "HCO", - "E01", - 1970, - "ELC" + "ethos", + "IMPHCO1", + 1990, + "HCO" ], [ "utopia", - 2010, + 1990, "winter", "night", "ethos", @@ -16672,108 +12178,138 @@ ], [ "utopia", - 1990, + 2010, "inter", - "night", - "DSL", - "TXD", - 1970, - "TX" + "day", + "ethos", + "IMPURN1", + 1990, + "URN" ], [ "utopia", 2010, - "inter", + "summer", "day", - "HCO", - "E01", + "HYD", + "E31", + 2000, + "ELC" + ], + [ + "utopia", 2000, + "summer", + "night", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "URN", + "E21", + 1990, "ELC" ], [ "utopia", 2010, "summer", - "day", - "ELC", - "E51", - 1990, + "night", + "DSL", + "E70", + 1980, "ELC" ], [ "utopia", - 2010, + 2000, "winter", "night", - "OIL", - "SRE", + "HCO", + "E01", 1990, - "DSL" + "ELC" ], [ "utopia", 1990, - "winter", + "summer", "night", - "OIL", - "SRE", + "ethos", + "IMPHCO1", 1990, - "GSL" + "HCO" ], [ "utopia", - 2000, - "winter", + 2010, + "summer", "night", "HYD", "E31", 1980, "ELC" ], + [ + "utopia", + 2000, + "summer", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], [ "utopia", 2010, - "winter", + "inter", "night", "ethos", - "IMPFEQ", + "IMPHYD", 1990, - "FEQ" + "HYD" ], [ "utopia", 1990, "summer", "night", - "GSL", - "TXG", - 1980, - "TX" + "ethos", + "IMPURN1", + 1990, + "URN" ], [ "utopia", 2000, "winter", "day", - "HYD", - "E31", + "OIL", + "SRE", 2000, - "ELC" + "GSL" ], [ "utopia", + 2000, + "inter", + "night", + "ethos", + "IMPGSL1", 1990, - "winter", - "day", - "HCO", - "E01", - 1960, - "ELC" + "GSL" ], [ "utopia", - 1990, - "winter", + 2010, + "inter", "day", "ethos", "IMPFEQ", @@ -16783,60 +12319,70 @@ [ "utopia", 2010, - "inter", - "day", - "GSL", - "TXG", + "summer", + "night", + "OIL", + "SRE", 2010, - "TX" + "DSL" ], [ "utopia", - 2010, - "summer", + 1990, + "inter", "night", - "ELC", - "TXE", - 2000, - "TX" + "DSL", + "E70", + 1960, + "ELC" ], [ "utopia", - 2000, + 2010, "summer", "night", "OIL", "SRE", - 2000, + 1990, "GSL" ], [ "utopia", - 2000, - "summer", + 2010, + "winter", "night", "ethos", - "IMPFEQ", + "IMPDSL1", 1990, - "FEQ" + "DSL" ], [ "utopia", - 2010, - "inter", - "day", - "DSL", - "TXD", 2000, - "TX" + "summer", + "night", + "HYD", + "E31", + 1980, + "ELC" ], [ "utopia", 1990, - "summer", + "winter", "day", "HCO", "E01", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "HCO", + "E01", 1990, "ELC" ], @@ -16844,135 +12390,165 @@ "utopia", 2010, "summer", - "day", - "OIL", - "SRE", + "night", + "HYD", + "E31", 2010, - "GSL" + "ELC" ], [ "utopia", - 2000, - "winter", + 1990, + "summer", "night", - "ELC", - "RL1", - 2000, - "RL" + "HCO", + "E01", + 1990, + "ELC" ], [ "utopia", - 2000, - "summer", + 2010, + "winter", "day", - "GSL", - "TXG", - 2000, - "TX" + "ELC", + "E51", + 1980, + "ELC" ], [ "utopia", - 2000, - "winter", + 2010, + "inter", "night", - "ethos", - "IMPGSL1", + "FEQ", + "E21", 1990, - "GSL" + "ELC" ], [ "utopia", - 2000, + 2010, "summer", "day", - "HYD", - "E31", - 1990, + "FEQ", + "E21", + 2000, "ELC" ], [ "utopia", 2010, - "summer", + "inter", "night", - "ELC", - "E51", - 2010, + "URN", + "E21", + 1990, "ELC" ], [ "utopia", 1990, - "summer", + "inter", "day", - "ethos", - "IMPHYD", + "FEQ", + "E21", 1990, - "HYD" + "ELC" ], [ "utopia", 2010, - "winter", + "inter", "day", - "ethos", - "IMPURN1", + "HCO", + "E01", 1990, - "URN" + "ELC" ], [ "utopia", 2010, "summer", - "day", - "ELC", - "TXE", + "night", + "DSL", + "E70", 2000, - "TX" + "ELC" ], [ "utopia", - 2010, + 1990, "winter", "night", - "HCO", - "E01", + "OIL", + "SRE", 1990, + "DSL" + ], + [ + "utopia", + 2000, + "winter", + "day", + "HYD", + "E31", + 2000, "ELC" ], + [ + "utopia", + 2010, + "inter", + "night", + "OIL", + "SRE", + 2000, + "DSL" + ], [ "utopia", 1990, "winter", "night", - "DSL", - "E70", - 1960, + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 2010, + "inter", + "night", + "HCO", + "E01", + 1980, "ELC" ], [ "utopia", 2010, - "winter", - "day", - "DSL", - "E70", + "inter", + "night", + "OIL", + "SRE", 2000, - "ELC" + "GSL" ], [ "utopia", - 1990, - "inter", + 2000, + "winter", "night", - "ELC", - "E51", + "ethos", + "IMPDSL1", 1990, - "ELC" + "DSL" ], [ "utopia", - 2010, + 1990, "summer", "night", "ethos", @@ -16980,73 +12556,53 @@ 1990, "OIL" ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL", - "TXD", - 1990, - "TX" - ], [ "utopia", 2010, - "winter", + "inter", "day", "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "day", - "HCO", - "E01", - 1990, + "E70", + 2010, "ELC" ], [ "utopia", - 2000, + 2010, "winter", "day", - "HCO", - "E01", - 1970, - "ELC" + "OIL", + "SRE", + 2010, + "DSL" ], [ "utopia", 2010, "inter", - "night", - "GSL", - "TXG", - 2010, - "TX" + "day", + "ELC", + "E51", + 1980, + "ELC" ], [ "utopia", 2010, "winter", "night", - "ELC", - "E51", - 1990, + "FEQ", + "E21", + 2010, "ELC" ], [ "utopia", 2010, - "summer", + "winter", "day", - "HYD", - "E31", + "ELC", + "E51", 2010, "ELC" ], @@ -17056,125 +12612,105 @@ "summer", "day", "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL", - "TXD", + "IMPURN1", 1990, - "TX" + "URN" ], [ "utopia", - 1990, - "inter", + 2010, + "winter", "day", - "ELC", - "RL1", - 1980, - "RL" + "OIL", + "SRE", + 2010, + "GSL" ], [ "utopia", - 1990, - "inter", + 2010, + "summer", "night", - "FEQ", - "E21", + "HCO", + "E01", 1990, "ELC" ], [ "utopia", 2000, - "inter", - "day", - "ELC", - "RL1", - 2000, - "RL" - ], - [ - "utopia", - 2010, "summer", "night", "FEQ", "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "HYD", - "E31", 2000, "ELC" ], [ "utopia", - 2010, - "winter", - "night", - "ethos", - "IMPHCO1", + 2000, + "summer", + "day", + "OIL", + "SRE", 1990, - "HCO" + "DSL" ], [ "utopia", 1990, "winter", "day", - "HCO", - "E01", - 1980, + "DSL", + "E70", + 1990, "ELC" ], [ "utopia", - 2010, - "winter", + 2000, + "inter", "day", - "ELC", - "RHE", - 2010, - "RH" + "OIL", + "SRE", + 1990, + "GSL" ], [ "utopia", - 1990, + 2000, "winter", "night", - "DSL", - "E70", + "ELC", + "E51", 1990, "ELC" ], [ "utopia", - 1990, + 2010, "inter", "night", - "ethos", - "IMPFEQ", + "HYD", + "E31", 1990, - "FEQ" + "ELC" ], [ "utopia", 1990, "winter", "night", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", "ethos", "IMPOIL1", 1990, @@ -17185,25 +12721,15 @@ 2000, "summer", "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "winter", - "night", "DSL", - "RHO", - 2000, - "RH" + "E70", + 1990, + "ELC" ], [ "utopia", 2000, - "winter", + "summer", "day", "HCO", "E01", @@ -17212,71 +12738,81 @@ ], [ "utopia", - 2000, + 2010, "winter", - "night", - "HCO", - "E01", - 1970, - "ELC" + "day", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ethos", + "IMPDSL1", + 1990, + "DSL" ], [ "utopia", 2000, "inter", "day", - "ELC", - "TXE", + "ethos", + "IMPHYD", 1990, - "TX" + "HYD" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ELC", + "E51", + 2010, + "ELC" ], [ "utopia", 2010, "summer", - "night", + "day", "OIL", "SRE", - 2010, - "GSL" + 2000, + "DSL" ], [ "utopia", - 2010, + 2000, "inter", "night", - "ethos", - "IMPHYD", + "FEQ", + "E21", 1990, - "HYD" + "ELC" ], [ "utopia", - 2000, + 2010, "summer", "day", - "ELC", - "RL1", + "OIL", + "SRE", 2000, - "RL" + "GSL" ], [ "utopia", 1990, - "summer", - "day", - "DSL", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - 2000, "winter", - "day", - "URN", - "E21", + "night", + "HYD", + "E31", 1990, "ELC" ], @@ -17284,8 +12820,8 @@ "utopia", 2000, "summer", - "night", - "URN", + "day", + "FEQ", "E21", 2000, "ELC" @@ -17293,7 +12829,17 @@ [ "utopia", 2010, - "summer", + "inter", + "night", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "inter", "night", "ethos", "IMPGSL1", @@ -17307,47 +12853,47 @@ "day", "DSL", "E70", - 1970, + 1980, "ELC" ], [ "utopia", - 2010, - "winter", - "night", - "DSL", - "E70", - 1990, + 2000, + "inter", + "day", + "FEQ", + "E21", + 2000, "ELC" ], [ "utopia", - 2010, + 1990, "winter", "night", - "DSL", - "TXD", - 2010, - "TX" + "HCO", + "E01", + 1970, + "ELC" ], [ "utopia", - 1990, - "summer", - "day", - "DSL", - "RHO", - 1990, - "RH" + 2000, + "inter", + "night", + "HYD", + "E31", + 1980, + "ELC" ], [ "utopia", 2000, "inter", "day", - "DSL", - "E70", - 1970, + "URN", + "E21", + 2000, "ELC" ], [ @@ -17355,16 +12901,36 @@ 2010, "winter", "day", - "ELC", - "E51", + "HCO", + "E01", 1990, "ELC" ], [ "utopia", 2010, + "inter", + "day", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 2000, "summer", "day", + "HCO", + "E01", + 1970, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", "HYD", "E31", 1980, @@ -17375,315 +12941,295 @@ 2000, "winter", "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" + "HYD", + "E31", + 1980, + "ELC" ], [ "utopia", - 2000, - "inter", - "night", - "HCO", - "E01", - 1970, + 2010, + "summer", + "day", + "ELC", + "E51", + 1980, "ELC" ], [ "utopia", 2010, - "winter", - "night", - "ELC", - "RHE", - 2010, - "RH" + "inter", + "day", + "OIL", + "SRE", + 1990, + "GSL" ], [ "utopia", - 2010, + 2000, "inter", "night", - "HCO", - "E01", - 2000, - "ELC" + "ethos", + "IMPHYD", + 1990, + "HYD" ], [ "utopia", - 1990, + 2010, "inter", "night", - "DSL", - "E70", - 1970, + "HCO", + "E01", + 2010, "ELC" ], [ "utopia", - 2000, + 1990, "summer", "night", "ethos", - "IMPGSL1", + "IMPFEQ", 1990, - "GSL" + "FEQ" ], [ "utopia", - 2010, - "inter", - "day", - "DSL", - "E70", - 1980, + 1990, + "winter", + "night", + "FEQ", + "E21", + 1990, "ELC" ], [ "utopia", 2010, - "winter", + "summer", "day", "ELC", - "RL1", + "E51", 2010, - "RL" + "ELC" ], [ "utopia", - 1990, - "summer", + 2010, + "inter", "day", "URN", "E21", - 1990, + 2000, "ELC" ], [ "utopia", + 2010, + "winter", + "night", + "OIL", + "SRE", 1990, + "GSL" + ], + [ + "utopia", + 2010, "summer", - "night", - "DSL", - "E70", - 1970, + "day", + "HCO", + "E01", + 1980, "ELC" ], [ "utopia", 2010, - "inter", + "winter", "day", - "ELC", - "RHE", - 2000, - "RH" + "FEQ", + "E21", + 1990, + "ELC" ], [ "utopia", 2010, - "summer", - "night", + "inter", + "day", "HYD", "E31", - 2010, + 1990, "ELC" ], [ "utopia", - 2000, + 2010, "inter", "day", - "ELC", - "E51", - 1980, - "ELC" + "OIL", + "SRE", + 2010, + "DSL" ], [ "utopia", - 1990, + 2010, "summer", "day", "DSL", "E70", - 1980, + 2000, "ELC" ], [ "utopia", 2010, "summer", - "day", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", + "day", + "HCO", + "E01", 2010, - "inter", - "night", - "HYD", - "E31", - 2000, "ELC" ], [ "utopia", 2000, - "inter", - "night", - "OIL", - "SRE", + "winter", + "day", + "URN", + "E21", 2000, - "GSL" + "ELC" ], [ "utopia", 1990, - "summer", + "inter", "day", "DSL", - "RHO", - 1980, - "RH" + "E70", + 1970, + "ELC" ], [ "utopia", - 2000, + 2010, "summer", "day", "DSL", "E70", - 2000, + 1990, "ELC" ], [ "utopia", - 2000, + 2010, "winter", "night", - "ELC", - "E51", + "URN", + "E21", 2000, "ELC" ], [ "utopia", 2000, - "summer", + "winter", "day", "DSL", - "RHO", - 2000, - "RH" + "E70", + 1980, + "ELC" ], [ "utopia", 2000, - "inter", + "summer", "day", - "DSL", - "E70", - 2000, - "ELC" + "ethos", + "IMPHYD", + 1990, + "HYD" ], [ "utopia", - 2000, + 2010, "inter", "night", - "HCO", - "E01", - 2000, + "ELC", + "E51", + 1980, "ELC" ], [ "utopia", - 2010, + 2000, "inter", - "day", - "ELC", - "RL1", - 2010, - "RL" + "night", + "HCO", + "E01", + 1970, + "ELC" ], [ "utopia", - 2010, - "inter", - "day", + 2000, + "summer", + "night", "ethos", - "IMPDSL1", + "IMPHYD", 1990, - "DSL" + "HYD" ], [ "utopia", - 2010, - "inter", - "day", - "ELC", - "RHE", 1990, - "RH" + "summer", + "night", + "ethos", + "IMPHYD", + 1990, + "HYD" ], [ "utopia", - 2010, + 1990, "inter", "day", - "DSL", - "E70", - 2010, - "ELC" + "ethos", + "IMPFEQ", + 1990, + "FEQ" ], [ "utopia", - 2010, - "inter", + 2000, + "winter", "night", - "DSL", - "E70", - 1980, - "ELC" + "ethos", + "IMPHYD", + 1990, + "HYD" ], [ "utopia", 2010, - "summer", + "winter", "night", "HYD", "E31", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ethos", - "IMPOIL1", 1990, - "OIL" + "ELC" ], [ "utopia", 2010, - "inter", + "winter", "night", "OIL", "SRE", @@ -17693,8 +13239,8 @@ [ "utopia", 2000, - "summer", - "day", + "inter", + "night", "DSL", "E70", 1990, @@ -17703,31 +13249,31 @@ [ "utopia", 2010, - "inter", - "day", - "DSL", - "RHO", + "winter", + "night", + "HCO", + "E01", 1990, - "RH" + "ELC" ], [ "utopia", - 2000, + 2010, "winter", "night", - "DSL", - "TXD", - 1990, - "TX" + "OIL", + "SRE", + 2010, + "GSL" ], [ "utopia", 1990, "inter", "day", - "ELC", - "E51", - 1980, + "HCO", + "E01", + 1960, "ELC" ], [ @@ -17735,160 +13281,140 @@ 2000, "winter", "night", - "GSL", - "TXG", + "OIL", + "SRE", 2000, - "TX" + "DSL" ], [ "utopia", 2000, "winter", - "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" + "day", + "HCO", + "E01", + 1970, + "ELC" ], [ "utopia", 2010, "inter", "day", - "URN", + "FEQ", "E21", 1990, "ELC" ], [ "utopia", - 2010, - "inter", - "night", - "ELC", - "RL1", - 2010, - "RL" + 1990, + "summer", + "day", + "HCO", + "E01", + 1970, + "ELC" ], [ "utopia", - 2000, + 1990, "winter", - "night", - "FEQ", - "E21", + "day", + "ethos", + "IMPHYD", 1990, - "ELC" + "HYD" ], [ "utopia", 2010, - "inter", + "winter", "night", - "ELC", - "RHE", + "ethos", + "IMPHCO1", 1990, - "RH" + "HCO" ], [ "utopia", - 2010, + 2000, "inter", "night", - "DSL", - "E70", - 2010, + "URN", + "E21", + 1990, "ELC" ], [ "utopia", 2000, "inter", - "night", - "ethos", - "IMPHYD", + "day", + "DSL", + "E70", 1990, - "HYD" - ], - [ - "utopia", - 2010, - "summer", - "night", - "HCO", - "E01", - 2000, "ELC" ], [ "utopia", - 2000, + 2010, "summer", - "night", + "day", "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ELC", - "RL1", - 1980, - "RL" + "IMPHYD", + 1990, + "HYD" ], [ "utopia", 1990, "winter", "night", - "ELC", - "RHE", + "ethos", + "IMPFEQ", 1990, - "RH" + "FEQ" ], [ "utopia", - 2010, - "winter", + 1990, + "inter", "day", - "ELC", - "TXE", - 2010, - "TX" + "HCO", + "E01", + 1990, + "ELC" ], [ "utopia", - 2010, + 2000, "summer", "day", - "OIL", - "SRE", - 1990, - "DSL" + "HYD", + "E31", + 1980, + "ELC" ], [ "utopia", - 2000, - "summer", + 2010, + "winter", "night", - "DSL", - "E70", + "ELC", + "E51", 1990, "ELC" ], [ "utopia", - 2010, + 1990, "inter", - "night", - "DSL", - "RHO", + "day", + "ethos", + "IMPOIL1", 1990, - "RH" + "OIL" ], [ "utopia", @@ -17896,43 +13422,43 @@ "winter", "day", "ELC", - "RL1", + "E51", 1990, - "RL" + "ELC" ], [ "utopia", - 2000, - "winter", + 1990, + "summer", "day", - "ethos", - "IMPURN1", + "HYD", + "E31", 1990, - "URN" + "ELC" ], [ "utopia", - 2000, - "summer", + 1990, + "inter", "day", - "FEQ", - "E21", - 2000, - "ELC" + "OIL", + "SRE", + 1990, + "GSL" ], [ "utopia", - 2000, - "summer", - "night", - "DSL", - "RHO", 1990, - "RH" + "inter", + "day", + "ELC", + "E51", + 1980, + "ELC" ], [ "utopia", - 2010, + 2000, "summer", "day", "ethos", @@ -17942,39 +13468,19 @@ ], [ "utopia", - 2010, + 2000, "summer", - "night", - "URN", - "E21", + "day", + "ethos", + "IMPOIL1", 1990, - "ELC" + "OIL" ], [ "utopia", - 1990, + 2000, "winter", "night", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", "URN", "E21", 1990, @@ -17982,109 +13488,149 @@ ], [ "utopia", + 2000, + "winter", + "night", + "ethos", + "IMPHCO1", 1990, - "inter", - "day", - "ELC", - "TXE", - 1990, - "TX" + "HCO" ], [ "utopia", 2000, - "inter", + "summer", "night", "DSL", - "TXD", + "E70", 1980, - "TX" + "ELC" ], [ "utopia", 2000, "winter", "day", - "OIL", - "SRE", + "HCO", + "E01", 1990, - "DSL" + "ELC" ], [ "utopia", 2010, "inter", "day", - "ELC", - "E51", - 1980, + "FEQ", + "E21", + 2010, "ELC" ], [ "utopia", - 2000, + 2010, "winter", "day", - "DSL", - "TXD", - 1990, - "TX" + "URN", + "E21", + 2010, + "ELC" ], [ "utopia", - 2010, + 2000, "winter", "night", - "FEQ", - "E21", - 2000, + "HCO", + "E01", + 1980, "ELC" ], [ "utopia", 1990, "summer", - "day", - "HYD", - "E31", - 1990, + "night", + "DSL", + "E70", + 1960, "ELC" ], [ "utopia", - 2010, + 2000, + "inter", + "night", + "HCO", + "E01", + 2000, + "ELC" + ], + [ + "utopia", + 2000, "winter", "day", "OIL", "SRE", + 1990, + "GSL" + ], + [ + "utopia", 2000, + "winter", + "day", + "ethos", + "IMPGSL1", + 1990, "GSL" ], [ "utopia", 2000, - "summer", + "inter", "day", "ELC", "E51", - 1990, + 2000, "ELC" ], [ "utopia", 2010, "winter", + "day", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "inter", "night", - "ELC", - "TXE", - 2010, - "TX" + "ethos", + "IMPHCO1", + 1990, + "HCO" ], [ "utopia", 2010, - "winter", + "summer", "day", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 2010, + "summer", + "night", "FEQ", "E21", 2010, @@ -18093,97 +13639,97 @@ [ "utopia", 2010, - "summer", + "winter", "day", - "GSL", - "TXG", - 2010, - "TX" + "ethos", + "IMPFEQ", + 1990, + "FEQ" ], [ "utopia", 2000, "inter", "day", - "OIL", - "SRE", - 2000, + "ethos", + "IMPGSL1", + 1990, "GSL" ], [ "utopia", - 1990, - "winter", + 2010, + "summer", "night", "URN", "E21", - 1990, + 2010, "ELC" ], [ "utopia", - 2000, + 2010, "summer", "night", - "HCO", - "E01", - 1970, + "ELC", + "E51", + 1980, "ELC" ], [ "utopia", 2010, "summer", - "night", - "GSL", - "TXG", - 2000, - "TX" + "day", + "ethos", + "IMPHCO1", + 1990, + "HCO" ], [ "utopia", 2010, - "winter", + "summer", "day", - "HCO", - "E01", - 1980, - "ELC" + "ethos", + "IMPURN1", + 1990, + "URN" ], [ "utopia", 1990, - "inter", + "winter", "night", "ethos", - "IMPHCO1", + "IMPOIL1", 1990, - "HCO" + "OIL" ], [ "utopia", 2000, "winter", "day", - "DSL", - "RHO", + "ELC", + "E51", 1990, - "RH" + "ELC" ], [ "utopia", - 2010, + 1990, "winter", "day", - "HYD", - "E31", - 2000, + "DSL", + "E70", + 1960, "ELC" ], [ "utopia", - 2000, - "winter", + 1990, + "inter", "night", "OIL", "SRE", @@ -18192,169 +13738,159 @@ ], [ "utopia", - 1990, - "winter", + 2000, + "summer", "night", - "ethos", - "IMPHYD", - 1990, - "HYD" + "HCO", + "E01", + 1980, + "ELC" ], [ "utopia", 2010, - "winter", + "summer", "night", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", + "HYD", + "E31", 2000, - "inter", - "night", - "ELC", - "E51", - 1990, "ELC" ], [ "utopia", - 2000, - "inter", + 1990, + "summer", "night", - "FEQ", - "E21", - 2000, + "HCO", + "E01", + 1980, "ELC" ], [ "utopia", - 2010, - "winter", + 1990, + "inter", "night", "OIL", "SRE", - 2010, + 1990, "GSL" ], [ "utopia", - 2010, - "summer", + 1990, + "inter", "night", - "OIL", - "SRE", + "HCO", + "E01", + 1960, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ethos", + "IMPDSL1", 1990, "DSL" ], [ "utopia", - 2010, + 1990, "inter", - "day", - "ELC", - "E51", - 2010, + "night", + "DSL", + "E70", + 1980, "ELC" ], [ "utopia", - 2010, + 2000, "inter", - "night", - "ELC", - "E51", + "day", + "HYD", + "E31", 1980, "ELC" ], [ "utopia", 2010, - "summer", + "inter", "day", - "FEQ", - "E21", - 2000, + "HCO", + "E01", + 1980, "ELC" ], [ "utopia", - 2000, + 2010, "summer", - "day", + "night", "OIL", "SRE", - 2000, + 2010, "GSL" ], [ "utopia", - 1990, - "winter", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 1990, - "inter", + 2000, + "summer", "night", - "ELC", - "RL1", - 1990, - "RL" + "HYD", + "E31", + 2000, + "ELC" ], [ "utopia", - 2000, - "inter", + 1990, + "summer", "day", - "URN", + "FEQ", "E21", 1990, "ELC" ], [ "utopia", - 2000, + 2010, "inter", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" + "day", + "DSL", + "E70", + 2000, + "ELC" ], [ "utopia", - 1990, + 2010, "summer", "day", - "ethos", - "IMPFEQ", + "HYD", + "E31", 1990, - "FEQ" + "ELC" ], [ "utopia", 2010, - "summer", - "night", - "URN", - "E21", - 2010, - "ELC" + "winter", + "day", + "OIL", + "SRE", + 2000, + "DSL" ], [ "utopia", 2000, - "summer", - "night", + "winter", + "day", "ethos", "IMPDSL1", 1990, @@ -18362,78 +13898,78 @@ ], [ "utopia", + 2010, + "winter", + "night", + "FEQ", + "E21", 2000, - "inter", - "day", - "HYD", - "E31", - 1990, "ELC" ], [ "utopia", - 1990, - "winter", + 2010, + "inter", "night", - "DSL", - "RHO", - 1970, - "RH" + "FEQ", + "E21", + 2010, + "ELC" ], [ "utopia", - 2000, + 2010, "winter", - "night", - "URN", - "E21", + "day", + "OIL", + "SRE", 2000, - "ELC" + "GSL" ], [ "utopia", - 2000, - "inter", + 2010, + "summer", "night", - "DSL", - "TXD", + "OIL", + "SRE", 2000, - "TX" + "DSL" ], [ "utopia", - 2000, + 2010, "summer", "night", - "GSL", - "TXG", - 1980, - "TX" + "ELC", + "E51", + 2000, + "ELC" ], [ "utopia", - 2000, + 2010, "summer", "night", "HCO", "E01", - 2000, + 1980, "ELC" ], [ "utopia", 2010, - "winter", + "summer", "day", - "HCO", - "E01", - 2010, + "URN", + "E21", + 1990, "ELC" ], [ "utopia", 2010, - "winter", + "summer", "night", "OIL", "SRE", @@ -18442,32 +13978,32 @@ ], [ "utopia", - 1990, - "inter", + 2000, + "summer", "night", - "HCO", - "E01", - 1980, + "FEQ", + "E21", + 1990, "ELC" ], [ "utopia", 1990, - "inter", + "winter", "day", "DSL", "E70", - 1990, + 1980, "ELC" ], [ "utopia", 2000, "winter", - "day", + "night", "ELC", "E51", - 2000, + 1980, "ELC" ], [ @@ -18475,35 +14011,45 @@ 2010, "winter", "day", - "URN", - "E21", - 1990, + "HYD", + "E31", + 2000, "ELC" ], [ "utopia", - 2010, - "inter", - "day", - "OIL", - "SRE", - 2010, - "GSL" + 1990, + "summer", + "night", + "DSL", + "E70", + 1990, + "ELC" ], [ "utopia", - 2010, + 1990, "inter", "night", - "FEQ", - "E21", - 2010, - "ELC" + "ethos", + "IMPURN1", + 1990, + "URN" ], [ "utopia", 1990, "winter", + "day", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "inter", "night", "ethos", "IMPDSL1", @@ -18512,42 +14058,42 @@ ], [ "utopia", - 1990, - "winter", + 2000, + "summer", "day", - "URN", + "FEQ", "E21", 1990, "ELC" ], [ "utopia", - 2000, + 2010, "summer", - "day", + "night", "HCO", "E01", - 1970, + 2010, "ELC" ], [ "utopia", 1990, - "inter", + "winter", "day", - "DSL", - "RHO", + "HCO", + "E01", 1970, - "RH" + "ELC" ], [ "utopia", 2000, - "winter", - "night", + "summer", + "day", "DSL", "E70", - 1980, + 1970, "ELC" ], [ @@ -18555,150 +14101,90 @@ 1990, "winter", "night", - "DSL", - "TXD", - 1970, - "TX" + "HCO", + "E01", + 1960, + "ELC" ], [ "utopia", 2010, "summer", "day", - "URN", + "FEQ", "E21", 1990, "ELC" ], - [ - "utopia", - 2010, - "summer", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" - ], [ "utopia", 2000, - "inter", + "summer", "day", - "GSL", - "TXG", + "OIL", + "SRE", 1990, - "TX" + "GSL" ], [ "utopia", 2000, - "winter", + "inter", "night", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "day", "ELC", - "RHE", - 1990, - "RH" + "E51", + 2000, + "ELC" ], [ "utopia", - 2010, - "winter", - "night", + 1990, + "summer", + "day", "URN", "E21", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ethos", - "IMPURN1", 1990, - "URN" + "ELC" ], [ "utopia", 1990, "inter", "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "URN", - "E21", + "HCO", + "E01", 1990, "ELC" ], [ "utopia", - 1990, + 2010, "winter", "day", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", + "ELC", + "E51", 2000, - "summer", - "night", - "ethos", - "IMPOIL1", - 1990, - "OIL" + "ELC" ], [ "utopia", - 1990, + 2010, "inter", "night", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" + "URN", + "E21", + 2010, + "ELC" ], [ "utopia", - 1990, + 2000, "winter", "day", - "DSL", - "RHO", - 1970, - "RH" + "HYD", + "E31", + 1990, + "ELC" ], [ "utopia", @@ -18708,62 +14194,32 @@ "OIL", "SRE", 1990, - "GSL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL", - "TXD", - 1970, - "TX" + "DSL" ], [ "utopia", - 2000, + 2010, "inter", "night", - "GSL", - "TXG", - 1980, - "TX" + "OIL", + "SRE", + 1990, + "GSL" ], [ "utopia", - 2000, - "summer", + 2010, + "inter", "day", "HCO", "E01", - 2000, + 2010, "ELC" ], - [ - "utopia", - 1990, - "inter", - "night", - "GSL", - "TXG", - 1980, - "TX" - ], [ "utopia", 2000, - "inter", + "summer", "day", "ethos", "IMPGSL1", @@ -18772,42 +14228,52 @@ ], [ "utopia", - 2010, + 2000, "summer", "day", "DSL", "E70", - 1980, + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "HCO", + "E01", + 1990, "ELC" ], [ "utopia", 2000, "inter", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" + "night", + "HYD", + "E31", + 2000, + "ELC" ], [ "utopia", 1990, - "winter", + "summer", "day", - "ELC", - "TXE", + "ethos", + "IMPDSL1", 1990, - "TX" + "DSL" ], [ "utopia", - 2000, + 2010, "inter", "day", - "HCO", - "E01", - 1990, + "ELC", + "E51", + 2000, "ELC" ], [ @@ -18817,7 +14283,7 @@ "night", "ELC", "E51", - 1980, + 2000, "ELC" ], [ @@ -18825,79 +14291,99 @@ 2010, "winter", "day", - "GSL", - "TXG", - 2000, - "TX" + "HCO", + "E01", + 2010, + "ELC" ], [ "utopia", 1990, - "summer", - "night", - "URN", - "E21", + "inter", + "day", + "HYD", + "E31", 1990, "ELC" ], [ "utopia", - 2010, - "summer", + 1990, + "inter", "night", "ELC", - "RL1", - 2010, - "RL" + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "HYD", + "E31", + 1980, + "ELC" ], [ "utopia", 2010, "inter", - "day", - "FEQ", - "E21", - 2010, + "night", + "HYD", + "E31", + 1980, "ELC" ], [ "utopia", - 2010, + 1990, + "winter", + "night", + "DSL", + "E70", + 1970, + "ELC" + ], + [ + "utopia", + 2000, "summer", "night", - "ELC", - "RHE", + "ethos", + "IMPDSL1", 1990, - "RH" + "DSL" ], [ "utopia", 2010, "inter", - "day", - "HCO", - "E01", - 1990, + "night", + "DSL", + "E70", + 1980, "ELC" ], [ "utopia", - 2010, + 2000, "summer", "day", - "ELC", - "E51", - 1980, + "HCO", + "E01", + 1990, "ELC" ], [ "utopia", 2000, "winter", - "day", - "DSL", - "E70", - 1980, + "night", + "HYD", + "E31", + 2000, "ELC" ], [ @@ -18905,25 +14391,25 @@ 1990, "summer", "night", - "HCO", - "E01", - 1980, - "ELC" + "ethos", + "IMPDSL1", + 1990, + "DSL" ], [ "utopia", - 1990, - "winter", + 2010, + "summer", "day", - "DSL", - "TXD", - 1970, - "TX" + "ELC", + "E51", + 2000, + "ELC" ], [ "utopia", 2000, - "inter", + "summer", "night", "OIL", "SRE", @@ -18932,42 +14418,62 @@ ], [ "utopia", - 2000, - "inter", + 2010, + "summer", "day", - "DSL", - "TXD", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", 2000, - "TX" + "summer", + "night", + "OIL", + "SRE", + 2000, + "GSL" ], [ "utopia", 2000, - "inter", + "summer", "night", - "HYD", - "E31", + "ELC", + "E51", 1990, "ELC" ], [ "utopia", 2010, - "summer", - "day", + "winter", + "night", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 1990, + "winter", + "night", "ELC", - "RL1", - 2010, - "RL" + "E51", + 1990, + "ELC" ], [ "utopia", - 2010, - "inter", - "day", - "HYD", - "E31", 2000, + "winter", + "day", + "FEQ", + "E21", + 1990, "ELC" ], [ @@ -18975,16 +14481,36 @@ 2010, "summer", "day", - "ELC", - "RHE", + "ethos", + "IMPGSL1", 1990, - "RH" + "GSL" ], [ "utopia", 2010, - "summer", + "winter", + "day", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 2010, + "inter", "day", + "OIL", + "SRE", + 2000, + "DSL" + ], + [ + "utopia", + 2010, + "inter", + "night", "DSL", "E70", 2010, @@ -18992,119 +14518,109 @@ ], [ "utopia", - 2010, - "winter", - "day", - "ethos", - "IMPHCO1", 1990, - "HCO" - ], - [ - "utopia", - 2000, - "summer", - "day", - "GSL", - "TXG", + "inter", + "night", + "ethos", + "IMPDSL1", 1990, - "TX" + "DSL" ], [ "utopia", 2010, - "summer", + "winter", "day", - "DSL", - "RHO", - 1990, - "RH" + "HCO", + "E01", + 1980, + "ELC" ], [ "utopia", 1990, - "summer", - "day", - "GSL", - "TXG", + "winter", + "night", + "ethos", + "IMPDSL1", 1990, - "TX" + "DSL" ], [ "utopia", - 2010, + 1990, "summer", "day", - "ELC", - "E51", - 2010, + "DSL", + "E70", + 1980, "ELC" ], [ "utopia", 2000, "inter", - "night", - "GSL", - "TXG", + "day", + "OIL", + "SRE", 2000, - "TX" + "DSL" ], [ "utopia", - 1990, + 2000, "inter", - "night", - "DSL", - "RHO", - 1970, - "RH" + "day", + "ethos", + "IMPFEQ", + 1990, + "FEQ" ], [ "utopia", - 2000, + 2010, "winter", "day", "ethos", - "IMPGSL1", + "IMPURN1", 1990, - "GSL" + "URN" ], [ "utopia", - 1990, - "summer", + 2010, + "inter", "night", "ethos", - "IMPFEQ", + "IMPGSL1", 1990, - "FEQ" + "GSL" ], [ "utopia", 2010, "summer", "night", - "ELC", - "E51", - 2000, - "ELC" + "ethos", + "IMPDSL1", + 1990, + "DSL" ], [ "utopia", - 2010, + 1990, "inter", "day", - "ethos", - "IMPHYD", - 1990, - "HYD" + "DSL", + "E70", + 1960, + "ELC" ], [ "utopia", 2010, "summer", - "night", + "day", "DSL", "E70", 1980, @@ -19112,201 +14628,241 @@ ], [ "utopia", + 2010, + "winter", + "night", + "URN", + "E21", 1990, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "DSL", + "E70", + 1970, + "ELC" + ], + [ + "utopia", + 2010, "inter", "night", - "ELC", - "E51", - 1980, + "HCO", + "E01", + 2000, "ELC" ], [ "utopia", - 1990, + 2000, "winter", - "day", + "night", "FEQ", "E21", - 1990, + 2000, "ELC" ], [ "utopia", 1990, - "winter", + "summer", "day", - "ethos", - "IMPHYD", - 1990, - "HYD" + "DSL", + "E70", + 1970, + "ELC" ], [ "utopia", - 2000, - "summer", + 2010, + "inter", "day", - "DSL", - "TXD", - 1980, - "TX" + "OIL", + "SRE", + 2010, + "GSL" ], [ "utopia", - 2000, - "summer", + 1990, + "winter", + "day", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 2010, + "inter", "day", "URN", "E21", - 2000, + 1990, "ELC" ], [ "utopia", - 2010, + 1990, "inter", - "night", - "GSL", - "TXG", - 2000, - "TX" + "day", + "DSL", + "E70", + 1990, + "ELC" ], [ "utopia", - 2000, - "summer", + 1990, + "inter", "night", "ethos", - "IMPHYD", + "IMPFEQ", 1990, - "HYD" + "FEQ" ], [ "utopia", + 2010, + "inter", + "day", + "ethos", + "IMPDSL1", 1990, - "summer", - "night", - "DSL", - "TXD", - 1970, - "TX" + "DSL" ], [ "utopia", 2010, - "winter", + "summer", "day", "DSL", - "TXD", + "E70", 2010, - "TX" + "ELC" ], [ "utopia", - 1990, - "summer", + 2000, + "inter", "day", - "ethos", - "IMPGSL1", + "HCO", + "E01", 1990, - "GSL" + "ELC" ], [ "utopia", 1990, "inter", - "night", - "DSL", - "TXD", - 1980, - "TX" + "day", + "URN", + "E21", + 1990, + "ELC" ], [ "utopia", 2010, - "summer", + "inter", "day", - "ethos", - "IMPURN1", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "URN", + "E21", 1990, - "URN" + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "HYD", + "E31", + 2010, + "ELC" ], [ "utopia", - 1990, + 2000, "inter", "day", "ethos", - "IMPURN1", + "IMPOIL1", 1990, - "URN" + "OIL" ], [ "utopia", - 1990, - "winter", + 2000, + "inter", "day", - "HYD", - "E31", + "DSL", + "E70", 1980, "ELC" ], [ "utopia", - 2000, + 1990, "inter", - "night", - "DSL", - "E70", + "day", + "HCO", + "E01", 1980, "ELC" ], [ "utopia", 1990, - "summer", + "inter", "night", - "ELC", - "RL1", + "HYD", + "E31", 1990, - "RL" + "ELC" ], [ "utopia", 2000, - "winter", + "inter", "day", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" + "HCO", + "E01", + 1980, + "ELC" ], [ "utopia", 2010, - "winter", + "summer", "day", - "ELC", - "RHE", + "HCO", + "E01", 2000, - "RH" + "ELC" ], [ "utopia", - 1990, + 2010, "winter", "night", - "DSL", - "E70", + "ELC", + "E51", 1980, "ELC" ], @@ -19315,49 +14871,79 @@ 1990, "inter", "day", - "OIL", - "SRE", + "ethos", + "IMPURN1", 1990, - "DSL" + "URN" ], [ "utopia", - 1990, + 2000, "inter", "day", - "HCO", - "E01", - 1960, - "ELC" + "ethos", + "IMPHCO1", + 1990, + "HCO" ], [ "utopia", 2000, - "summer", - "night", - "DSL", - "TXD", - 1980, - "TX" + "inter", + "day", + "ethos", + "IMPURN1", + 1990, + "URN" ], [ "utopia", 2010, "winter", "night", - "DSL", - "RHO", + "ethos", + "IMPGSL1", 1990, - "RH" + "GSL" ], [ "utopia", 2000, "winter", "day", - "HCO", - "E01", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "FEQ", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "ethos", + "IMPOIL1", 1990, + "OIL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "HYD", + "E31", + 2010, "ELC" ], [ @@ -19372,129 +14958,99 @@ ], [ "utopia", - 1990, + 2000, "inter", - "day", - "GSL", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - 2010, - "summer", "night", - "DSL", - "RHO", - 1990, - "RH" + "OIL", + "SRE", + 2000, + "DSL" ], [ "utopia", - 1990, + 2000, "summer", "day", - "ELC", - "RL1", + "ethos", + "IMPFEQ", 1990, - "RL" + "FEQ" ], [ "utopia", 2000, "inter", "night", - "ELC", - "RHE", + "OIL", + "SRE", 2000, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "night", - "GSL", - "TXG", - 1970, - "TX" + "GSL" ], [ "utopia", 2000, - "winter", + "summer", "day", - "HYD", - "E31", + "URN", + "E21", 1990, "ELC" ], [ "utopia", - 2010, + 2000, "winter", - "night", - "HYD", - "E31", + "day", + "ethos", + "IMPFEQ", 1990, - "ELC" + "FEQ" ], [ "utopia", - 2010, + 2000, "winter", - "night", - "DSL", - "E70", + "day", + "HCO", + "E01", 1980, "ELC" ], - [ - "utopia", - 1990, - "winter", - "night", - "FEQ", - "E21", - 1990, - "ELC" - ], [ "utopia", 2010, - "summer", - "night", + "inter", + "day", "FEQ", "E21", - 2010, + 2000, "ELC" ], [ "utopia", - 1990, + 2000, "winter", "day", - "OIL", - "SRE", + "ethos", + "IMPHCO1", 1990, - "GSL" + "HCO" ], [ "utopia", 2000, - "summer", + "winter", "day", - "HYD", - "E31", - 1980, - "ELC" + "ethos", + "IMPURN1", + 1990, + "URN" ], [ "utopia", - 2010, - "inter", - "day", + 2000, + "winter", + "night", "OIL", "SRE", 1990, @@ -19504,17 +15060,17 @@ "utopia", 2010, "winter", - "day", + "night", "ELC", "E51", - 1980, + 2010, "ELC" ], [ "utopia", - 2000, + 2010, "summer", - "day", + "night", "ethos", "IMPHYD", 1990, @@ -19522,79 +15078,69 @@ ], [ "utopia", - 1990, - "inter", + 2000, + "winter", "night", - "ethos", - "IMPURN1", + "OIL", + "SRE", 1990, - "URN" + "GSL" ], [ "utopia", - 2010, + 2000, "winter", "day", "DSL", "E70", - 1990, + 2000, "ELC" ], [ "utopia", - 2000, - "summer", + 2010, + "winter", "night", "OIL", "SRE", - 1990, - "GSL" + 2000, + "DSL" ], [ "utopia", 2010, - "winter", + "inter", "night", "ELC", - "RHE", + "E51", 2000, - "RH" + "ELC" ], [ "utopia", - 1990, - "summer", + 2000, + "inter", "night", "DSL", - "RHO", - 1970, - "RH" + "E70", + 1980, + "ELC" ], [ "utopia", 2000, "inter", "night", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "day", "HCO", "E01", - 1980, + 1990, "ELC" ], [ "utopia", 2010, - "inter", - "day", + "winter", + "night", "ethos", "IMPURN1", 1990, @@ -19602,32 +15148,22 @@ ], [ "utopia", - 2000, + 2010, "winter", - "night", - "HCO", - "E01", - 1990, + "day", + "DSL", + "E70", + 1980, "ELC" ], [ "utopia", - 2000, - "winter", - "day", - "ethos", - "IMPFEQ", 1990, - "FEQ" - ], - [ - "utopia", - 2000, "summer", - "night", - "FEQ", - "E21", - 2000, + "day", + "ELC", + "E51", + 1990, "ELC" ], [ @@ -19635,59 +15171,59 @@ 1990, "summer", "night", - "HYD", - "E31", + "URN", + "E21", 1990, "ELC" ], [ "utopia", - 2000, + 2010, "inter", "night", - "ELC", - "TXE", - 2000, - "TX" + "ethos", + "IMPDSL1", + 1990, + "DSL" ], [ "utopia", - 1990, - "summer", - "day", + 2010, + "winter", + "night", "DSL", "E70", - 1970, + 2000, "ELC" ], [ "utopia", 2010, "summer", - "day", - "HCO", - "E01", - 1990, + "night", + "FEQ", + "E21", + 2000, "ELC" ], [ "utopia", - 2010, + 2000, "winter", "night", - "OIL", - "SRE", - 2010, - "DSL" + "ethos", + "IMPOIL1", + 1990, + "OIL" ], [ "utopia", - 2010, - "inter", - "night", - "HYD", - "E31", 1990, + "summer", + "day", + "HCO", + "E01", + 1960, "ELC" ], [ @@ -19695,150 +15231,130 @@ 2000, "inter", "night", - "OIL", - "SRE", + "ethos", + "IMPHCO1", 1990, - "GSL" + "HCO" ], [ "utopia", - 2010, - "winter", - "night", - "DSL", - "E70", - 2010, + 1990, + "inter", + "day", + "ELC", + "E51", + 1990, "ELC" ], [ "utopia", - 2000, - "winter", - "night", - "ELC", - "E51", + 2010, + "inter", + "day", + "ethos", + "IMPHYD", 1990, - "ELC" + "HYD" ], [ "utopia", - 2000, + 1990, "summer", "night", - "HYD", - "E31", + "ELC", + "E51", 1990, "ELC" ], - [ - "utopia", - 2000, - "winter", - "day", - "OIL", - "SRE", - 2000, - "GSL" - ], [ "utopia", 2010, "winter", - "day", - "OIL", - "SRE", - 2010, - "DSL" + "night", + "DSL", + "E70", + 1990, + "ELC" ], [ "utopia", 2000, - "inter", - "day", - "DSL", - "E70", + "winter", + "night", + "ethos", + "IMPURN1", 1990, - "ELC" + "URN" ], [ "utopia", 2000, "summer", "night", - "DSL", - "TXD", + "URN", + "E21", 2000, - "TX" + "ELC" ], [ "utopia", - 2010, - "winter", + 1990, + "inter", "night", - "ELC", - "E51", - 1980, + "DSL", + "E70", + 1970, "ELC" ], [ "utopia", - 1990, + 2010, "winter", - "day", - "ELC", - "RHE", + "night", + "ethos", + "IMPOIL1", 1990, - "RH" + "OIL" ], [ "utopia", 2000, - "winter", - "night", - "HCO", - "E01", - 1980, + "summer", + "day", + "HYD", + "E31", + 2000, "ELC" ], [ "utopia", - 2010, + 1990, "summer", "day", "HYD", "E31", - 2000, + 1980, "ELC" ], [ "utopia", 2010, - "summer", + "winter", "night", - "DSL", - "E70", - 2010, + "HYD", + "E31", + 1980, "ELC" ], [ "utopia", - 2000, - "inter", + 1990, + "summer", "day", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "HCO", - "E01", + "ethos", + "IMPOIL1", 1990, - "ELC" + "OIL" ], [ "utopia", @@ -19847,173 +15363,163 @@ "night", "HCO", "E01", - 2010, + 1980, "ELC" ], [ "utopia", - 1990, - "inter", + 2000, + "summer", "night", "DSL", "E70", - 1990, + 1970, "ELC" ], [ "utopia", - 2000, - "summer", - "day", + 1990, + "winter", + "night", "ethos", - "IMPDSL1", + "IMPHYD", 1990, - "DSL" + "HYD" + ], + [ + "utopia", + 2010, + "winter", + "day", + "URN", + "E21", + 2000, + "ELC" ], [ "utopia", 2010, "summer", "night", - "DSL", - "RHO", - 2010, - "RH" + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "HCO", + "E01", + 1970, + "ELC" ], [ "utopia", 2010, "summer", "night", - "HYD", - "E31", - 1990, + "URN", + "E21", + 2000, "ELC" ], [ "utopia", - 1990, + 2000, "summer", - "day", + "night", "ethos", - "IMPDSL1", + "IMPOIL1", 1990, - "DSL" + "OIL" ], [ "utopia", 1990, "summer", - "night", - "OIL", - "SRE", + "day", + "ethos", + "IMPHCO1", 1990, - "GSL" + "HCO" ], [ "utopia", 1990, "summer", "day", - "OIL", - "SRE", + "ethos", + "IMPURN1", 1990, - "DSL" + "URN" ], [ "utopia", - 2000, - "summer", + 1990, + "winter", "day", "DSL", "E70", - 1980, + 1970, "ELC" ], [ "utopia", 2010, "winter", - "night", + "day", "HYD", "E31", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "OIL", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ethos", - "IMPFEQ", 1990, - "FEQ" + "ELC" ], [ "utopia", - 2010, - "inter", - "day", - "GSL", - "TXG", 2000, - "TX" - ], - [ - "utopia", - 1990, "winter", - "day", - "ethos", - "IMPOIL1", + "night", + "DSL", + "E70", 1990, - "OIL" + "ELC" ], [ "utopia", - 2010, + 1990, "summer", "night", - "OIL", - "SRE", - 2000, - "GSL" + "DSL", + "E70", + 1980, + "ELC" ], [ "utopia", 2000, "winter", - "day", - "GSL", - "TXG", + "night", + "HCO", + "E01", 2000, - "TX" + "ELC" ], [ "utopia", - 2000, + 2010, "winter", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" + "night", + "HYD", + "E31", + 2010, + "ELC" ], [ "utopia", 2000, - "inter", + "summer", "night", "ethos", "IMPFEQ", @@ -20022,12 +15528,12 @@ ], [ "utopia", - 1990, - "inter", - "day", + 2010, + "winter", + "night", "HCO", "E01", - 1990, + 2010, "ELC" ], [ @@ -20035,180 +15541,190 @@ 2000, "summer", "night", - "URN", - "E21", + "ethos", + "IMPHCO1", 1990, - "ELC" + "HCO" ], [ "utopia", - 2010, + 2000, "summer", "night", - "HCO", - "E01", + "ethos", + "IMPURN1", 1990, - "ELC" + "URN" ], [ "utopia", 1990, - "summer", + "inter", "night", "DSL", "E70", - 1960, + 1990, "ELC" ], + [ + "utopia", + 1990, + "winter", + "day", + "OIL", + "SRE", + 1990, + "DSL" + ], [ "utopia", 2010, "winter", - "night", + "day", "DSL", - "TXD", - 2000, - "TX" + "E70", + 2010, + "ELC" ], [ "utopia", 2000, - "summer", + "winter", "day", "ELC", - "RHE", - 2000, - "RH" + "E51", + 1980, + "ELC" ], [ "utopia", - 2000, - "summer", - "night", - "DSL", - "E70", - 1980, - "ELC" + 1990, + "winter", + "day", + "OIL", + "SRE", + 1990, + "GSL" ], [ "utopia", - 2010, - "inter", + 1990, + "winter", "day", - "DSL", - "RHO", - 2010, - "RH" + "ELC", + "E51", + 1980, + "ELC" ], [ "utopia", - 2000, + 2010, "summer", "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" + "URN", + "E21", + 2010, + "ELC" ], [ "utopia", - 2000, - "summer", - "night", - "DSL", - "RHO", - 1980, - "RH" + 1990, + "winter", + "day", + "HCO", + "E01", + 1960, + "ELC" ], [ "utopia", - 2010, + 1990, "inter", "night", - "HCO", - "E01", + "URN", + "E21", 1990, "ELC" ], [ "utopia", - 1990, - "inter", + 2000, + "summer", "night", - "DSL", - "E70", - 1960, + "HCO", + "E01", + 1970, "ELC" ], [ "utopia", - 2000, + 1990, "winter", "day", - "GSL", - "TXG", + "ethos", + "IMPGSL1", 1990, - "TX" + "GSL" ], [ "utopia", 1990, - "summer", + "inter", "night", - "ELC", - "E51", - 1980, - "ELC" + "ethos", + "IMPOIL1", + 1990, + "OIL" ], [ "utopia", - 2000, - "summer", - "day", - "DSL", - "RHO", 1990, - "RH" + "summer", + "night", + "HCO", + "E01", + 1970, + "ELC" ], [ "utopia", - 2010, - "inter", + 1990, + "summer", "day", - "URN", - "E21", - 2010, + "HCO", + "E01", + 1990, "ELC" ], [ "utopia", - 2010, - "winter", + 2000, + "summer", "day", "ELC", "E51", - 2010, + 1980, "ELC" ], [ "utopia", - 1990, + 2010, "summer", - "night", + "day", "ethos", - "IMPDSL1", + "IMPOIL1", 1990, - "DSL" + "OIL" ], [ "utopia", - 1990, - "winter", + 2000, + "inter", "night", - "GSL", - "TXG", - 1970, - "TX" + "ELC", + "E51", + 1990, + "ELC" ], [ "utopia", @@ -20216,78 +15732,88 @@ "summer", "night", "ethos", - "IMPHCO1", + "IMPOIL1", 1990, - "HCO" + "OIL" ], [ "utopia", 2010, + "summer", + "day", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 1990, "inter", "night", - "ELC", - "RHE", - 2010, - "RH" + "HCO", + "E01", + 1980, + "ELC" ], [ "utopia", 2010, "winter", "day", - "OIL", - "SRE", + "ethos", + "IMPHYD", 1990, - "GSL" + "HYD" ], [ "utopia", 2000, "winter", - "day", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "winter", "night", - "FEQ", - "E21", + "ethos", + "IMPGSL1", 1990, - "ELC" + "GSL" ], [ "utopia", - 1990, - "summer", + 2000, + "winter", "day", "HYD", "E31", 1980, "ELC" ], + [ + "utopia", + 2000, + "winter", + "day", + "OIL", + "SRE", + 2000, + "DSL" + ], [ "utopia", 1990, - "summer", + "winter", "night", - "DSL", - "E70", + "ethos", + "IMPHCO1", 1990, - "ELC" + "HCO" ], [ "utopia", 2000, "summer", - "day", - "ELC", - "E51", - 1980, + "night", + "HYD", + "E31", + 1990, "ELC" ], [ @@ -20295,145 +15821,135 @@ 1990, "winter", "day", - "GSL", - "TXG", - 1980, - "TX" + "HCO", + "E01", + 1990, + "ELC" ], [ "utopia", 2000, "inter", "day", - "ELC", - "E51", + "HYD", + "E31", 2000, "ELC" ], [ "utopia", - 2000, - "summer", - "night", - "ELC", - "RHE", - 2000, - "RH" + 2010, + "inter", + "day", + "DSL", + "E70", + 1990, + "ELC" ], [ "utopia", 2010, - "winter", + "inter", "day", - "FEQ", - "E21", + "HCO", + "E01", 2000, "ELC" ], [ "utopia", 2010, - "inter", + "summer", "night", - "DSL", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "day", "ethos", - "IMPGSL1", + "IMPHCO1", 1990, - "GSL" + "HCO" ], [ "utopia", 2010, "summer", - "day", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "inter", "night", "ethos", - "IMPOIL1", + "IMPURN1", 1990, - "OIL" + "URN" ], [ "utopia", - 2000, + 2010, "winter", "night", - "GSL", - "TXG", + "FEQ", + "E21", 1990, - "TX" + "ELC" ], [ "utopia", 2000, "inter", - "day", - "OIL", - "SRE", + "night", + "HYD", + "E31", 1990, - "GSL" + "ELC" ], [ "utopia", - 2010, + 2000, "inter", - "night", - "URN", - "E21", - 2010, + "day", + "ELC", + "E51", + 1990, "ELC" ], [ "utopia", 2010, - "winter", + "inter", "night", - "ELC", - "E51", - 2010, + "FEQ", + "E21", + 2000, "ELC" ], [ "utopia", 2010, - "inter", + "summer", "night", "OIL", "SRE", - 2000, + 1990, "DSL" ], [ "utopia", 2010, "summer", - "night", - "ethos", - "IMPFEQ", + "day", + "HYD", + "E31", + 2010, + "ELC" + ], + [ + "utopia", 1990, - "FEQ" + "winter", + "day", + "HYD", + "E31", + 1990, + "ELC" ], [ "utopia", - 2010, - "inter", + 2000, + "summer", "night", "DSL", "E70", @@ -20442,11 +15958,11 @@ ], [ "utopia", - 2000, + 1990, "inter", - "night", - "ELC", - "E51", + "day", + "HYD", + "E31", 1980, "ELC" ], @@ -20454,60 +15970,80 @@ "utopia", 1990, "winter", + "day", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 2010, + "summer", "night", - "HCO", - "E01", - 1970, + "DSL", + "E70", + 1990, "ELC" ], [ "utopia", 2000, - "inter", + "summer", + "day", + "OIL", + "SRE", + 2000, + "DSL" + ], + [ + "utopia", + 1990, + "summer", "day", "ethos", - "IMPOIL1", + "IMPGSL1", 1990, - "OIL" + "GSL" ], [ "utopia", - 2010, - "inter", - "day", - "ELC", - "E51", - 2000, + 1990, + "winter", + "night", + "DSL", + "E70", + 1960, "ELC" ], [ "utopia", 2010, - "inter", + "summer", "night", - "DSL", - "RHO", - 2000, - "RH" + "HYD", + "E31", + 1990, + "ELC" ], [ "utopia", 2000, - "winter", - "night", - "DSL", - "TXD", - 1980, - "TX" + "summer", + "day", + "ELC", + "E51", + 2000, + "ELC" ], [ "utopia", - 2010, + 2000, "summer", "day", - "FEQ", - "E21", - 1990, + "HCO", + "E01", + 1980, "ELC" ], [ @@ -20517,43 +16053,33 @@ "day", "OIL", "SRE", - 1990, + 2000, "GSL" ], [ "utopia", - 2010, - "winter", - "day", - "ELC", - "TXE", 2000, - "TX" - ], - [ - "utopia", - 2010, - "inter", + "summer", "night", - "DSL", - "TXD", - 2010, - "TX" + "ELC", + "E51", + 1980, + "ELC" ], [ "utopia", - 2010, - "summer", + 1990, + "winter", "night", - "URN", - "E21", - 2000, + "ELC", + "E51", + 1980, "ELC" ], [ "utopia", - 1990, - "winter", + 2000, + "summer", "night", "ethos", "IMPGSL1", @@ -20562,118 +16088,158 @@ ], [ "utopia", - 2000, + 2010, "inter", - "day", - "HYD", - "E31", - 1980, - "ELC" + "night", + "ethos", + "IMPFEQ", + 1990, + "FEQ" ], [ "utopia", 1990, "summer", - "day", - "ELC", - "E51", + "night", + "ethos", + "IMPGSL1", 1990, - "ELC" + "GSL" ], [ "utopia", 1990, "winter", "night", - "OIL", - "SRE", + "URN", + "E21", 1990, - "DSL" + "ELC" ], [ "utopia", + 2010, + "inter", + "night", + "ethos", + "IMPURN1", 1990, - "winter", + "URN" + ], + [ + "utopia", + 2000, + "summer", "night", "HCO", "E01", - 1960, + 2000, "ELC" ], [ "utopia", 2010, - "winter", - "day", - "HCO", - "E01", + "inter", + "night", + "DSL", + "E70", 2000, "ELC" ], + [ + "utopia", + 2000, + "inter", + "night", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], [ "utopia", 2010, "winter", - "night", + "day", "OIL", "SRE", 1990, - "GSL" + "DSL" ], [ "utopia", - 1990, - "winter", - "night", + 2010, + "inter", + "day", "ethos", - "IMPFEQ", + "IMPGSL1", 1990, - "FEQ" + "GSL" ], [ "utopia", - 1990, - "summer", + 2010, + "winter", "day", - "DSL", - "TXD", + "ELC", + "E51", 1990, - "TX" + "ELC" ], [ "utopia", 1990, "winter", - "day", - "ELC", - "RL1", + "night", + "HCO", + "E01", 1980, - "RL" + "ELC" ], [ "utopia", 2010, "winter", "day", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 2010, + "summer", + "day", + "FEQ", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", "ethos", - "IMPFEQ", + "IMPDSL1", 1990, - "FEQ" + "DSL" ], [ "utopia", 2010, "inter", "night", - "DSL", - "TXD", + "URN", + "E21", 2000, - "TX" + "ELC" ], [ "utopia", - 2000, - "summer", + 1990, + "winter", "day", "FEQ", "E21", @@ -20682,39 +16248,59 @@ ], [ "utopia", - 2010, + 2000, "inter", + "day", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 1990, + "winter", "night", - "ELC", - "E51", - 2000, - "ELC" + "ethos", + "IMPURN1", + 1990, + "URN" ], [ "utopia", - 2000, + 2010, "summer", "night", - "OIL", - "SRE", + "DSL", + "E70", + 2010, + "ELC" + ], + [ + "utopia", 2000, - "DSL" + "winter", + "day", + "ethos", + "IMPHYD", + 1990, + "HYD" ], [ "utopia", 2010, - "inter", + "summer", "day", "OIL", "SRE", - 2000, + 1990, "GSL" ], [ "utopia", 2010, - "summer", - "day", + "inter", + "night", "OIL", "SRE", 2010, @@ -20722,109 +16308,109 @@ ], [ "utopia", - 2000, + 2010, "inter", - "day", + "night", "HCO", "E01", - 1970, + 1990, "ELC" ], [ "utopia", - 2000, + 2010, "inter", - "day", - "GSL", - "TXG", - 1980, - "TX" + "night", + "OIL", + "SRE", + 2010, + "GSL" ], [ "utopia", 2000, "winter", - "day", - "ELC", - "RL1", - 2000, - "RL" + "night", + "FEQ", + "E21", + 1990, + "ELC" ], [ "utopia", - 2010, - "inter", - "day", - "DSL", - "E70", 2000, - "ELC" + "winter", + "night", + "ethos", + "IMPFEQ", + 1990, + "FEQ" ], [ "utopia", - 2000, + 2010, "summer", - "day", - "ELC", - "TXE", - 2000, - "TX" + "night", + "ethos", + "IMPGSL1", + 1990, + "GSL" ], [ "utopia", - 2000, + 1990, "summer", - "night", - "GSL", - "TXG", - 2000, - "TX" + "day", + "DSL", + "E70", + 1960, + "ELC" ], [ "utopia", - 1990, - "winter", + 2000, + "inter", "day", - "ethos", - "IMPURN1", + "FEQ", + "E21", 1990, - "URN" + "ELC" ], [ "utopia", - 1990, + 2000, "winter", "night", - "HCO", - "E01", + "HYD", + "E31", 1990, "ELC" ], [ "utopia", - 2010, + 1990, "summer", "day", "ethos", - "IMPHYD", + "IMPFEQ", 1990, - "HYD" + "FEQ" ], [ "utopia", 2010, - "winter", - "night", - "URN", - "E21", + "inter", + "day", + "OIL", + "SRE", 2000, - "ELC" + "GSL" ], [ "utopia", 2010, "inter", - "night", + "day", "ELC", "E51", 1990, @@ -20832,123 +16418,113 @@ ], [ "utopia", - 1990, - "summer", - "night", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 1990, + 2010, "winter", "day", - "DSL", - "E70", - 1960, + "HCO", + "E01", + 2000, "ELC" ], [ "utopia", - 2010, + 2000, "winter", "day", - "URN", + "FEQ", "E21", - 2010, + 2000, "ELC" ], [ "utopia", 1990, - "winter", + "inter", "night", "ELC", "E51", - 1990, + 1980, "ELC" ], [ "utopia", - 2000, - "winter", + 2010, + "summer", "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" + "HCO", + "E01", + 2000, + "ELC" ], [ "utopia", 2000, - "summer", + "inter", "day", - "HCO", - "E01", - 1990, - "ELC" + "OIL", + "SRE", + 2000, + "GSL" ], [ "utopia", 1990, "inter", - "night", - "GSL", - "TXG", - 1970, - "TX" + "day", + "ethos", + "IMPHYD", + 1990, + "HYD" ], [ "utopia", - 1990, + 2010, "inter", - "day", + "night", "ethos", - "IMPFEQ", + "IMPHCO1", 1990, - "FEQ" + "HCO" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ELC", + "E51", + 2000, + "ELC" ], [ "utopia", 2000, "summer", "night", - "GSL", - "TXG", + "OIL", + "SRE", 1990, - "TX" + "DSL" ], [ "utopia", - 2000, - "winter", + 2010, + "inter", "night", - "DSL", - "E70", + "HYD", + "E31", 2000, "ELC" ], [ "utopia", 2000, - "winter", + "summer", "night", - "ELC", - "RHE", - 2000, - "RH" + "OIL", + "SRE", + 1990, + "GSL" ], [ "utopia", @@ -20956,37 +16532,47 @@ "winter", "night", "DSL", - "TXD", + "E70", 1990, - "TX" + "ELC" ], [ "utopia", - 2010, - "winter", + 1990, + "summer", "day", - "HYD", - "E31", + "DSL", + "E70", 1990, "ELC" ], [ "utopia", - 2000, - "inter", + 2010, + "summer", "day", - "ethos", - "IMPHYD", - 1990, - "HYD" + "OIL", + "SRE", + 2010, + "DSL" ], [ "utopia", - 2000, + 2010, "inter", "day", - "HCO", - "E01", + "URN", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "HYD", + "E31", 1980, "ELC" ], @@ -20997,113 +16583,113 @@ "night", "FEQ", "E21", - 1990, + 2000, "ELC" ], [ "utopia", - 1990, + 2000, "inter", "day", - "URN", - "E21", - 1990, + "HCO", + "E01", + 1970, "ELC" ], [ "utopia", - 2000, + 2010, "summer", - "night", - "ELC", - "TXE", - 2000, - "TX" + "day", + "HCO", + "E01", + 1990, + "ELC" ], [ "utopia", 2010, - "inter", + "summer", "day", - "FEQ", - "E21", - 2000, - "ELC" + "OIL", + "SRE", + 2010, + "GSL" ], [ "utopia", + 2010, + "summer", + "night", + "ethos", + "IMPFEQ", 1990, + "FEQ" + ], + [ + "utopia", + 2000, "inter", "night", - "HCO", - "E01", - 1970, + "URN", + "E21", + 2000, "ELC" ], [ "utopia", - 1990, - "inter", + 2010, + "winter", "night", - "ELC", - "RL1", - 1980, - "RL" + "ethos", + "IMPHYD", + 1990, + "HYD" ], [ "utopia", - 2010, + 2000, "inter", "day", "HCO", "E01", - 1980, + 2000, "ELC" ], [ "utopia", - 1990, + 2010, "winter", - "day", - "DSL", - "E70", - 1990, + "night", + "ELC", + "E51", + 2000, "ELC" ], [ "utopia", - 2000, - "winter", + 1990, + "summer", "day", - "DSL", - "E70", - 1970, - "ELC" + "ethos", + "IMPHYD", + 1990, + "HYD" ], [ "utopia", 1990, "summer", "night", - "HCO", - "E01", - 1970, + "HYD", + "E31", + 1990, "ELC" ], [ "utopia", 2010, - "summer", - "day", - "DSL", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - 2000, - "inter", + "winter", "night", "OIL", "SRE", @@ -21114,127 +16700,137 @@ "utopia", 2010, "summer", - "night", - "OIL", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - 2000, - "inter", "day", - "FEQ", - "E21", - 2000, + "ELC", + "E51", + 1990, "ELC" ], [ "utopia", + 2010, + "inter", + "night", + "ethos", + "IMPOIL1", 1990, - "winter", - "day", - "DSL", - "RHO", - 1990, - "RH" + "OIL" ], [ "utopia", - 2000, + 2010, "inter", "night", - "HYD", - "E31", - 1980, + "ELC", + "E51", + 1990, "ELC" ], [ "utopia", 1990, "inter", - "night", + "day", "ethos", - "IMPHYD", + "IMPHCO1", 1990, - "HYD" + "HCO" ], [ "utopia", 1990, - "inter", + "winter", "day", - "DSL", - "TXD", + "ethos", + "IMPFEQ", 1990, - "TX" + "FEQ" ], [ "utopia", - 2010, - "summer", - "night", - "DSL", - "TXD", - 2010, - "TX" + 2000, + "winter", + "day", + "HCO", + "E01", + 2000, + "ELC" ], [ "utopia", - 2000, - "summer", - "night", + 1990, + "inter", + "day", "HCO", "E01", - 1990, + 1970, "ELC" ], [ "utopia", - 2010, + 2000, "inter", "day", - "HYD", - "E31", - 1990, + "DSL", + "E70", + 1970, "ELC" ], [ "utopia", 2000, - "inter", + "summer", "day", - "ELC", - "RHE", - 1990, - "RH" + "URN", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "DSL", + "E70", + 1980, + "ELC" ], [ "utopia", - 1990, + 2010, "winter", - "day", - "ELC", - "E51", - 1990, - "ELC" + "night", + "OIL", + "SRE", + 2000, + "GSL" ], [ "utopia", - 1990, + 2000, "inter", "day", "DSL", "E70", - 1960, + 2000, "ELC" ], [ "utopia", - 2010, + 1990, "inter", "night", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 2010, + "winter", + "day", "FEQ", "E21", 2000, @@ -21242,21 +16838,31 @@ ], [ "utopia", - 1990, + 2010, "winter", "day", - "DSL", - "E70", - 1980, - "ELC" + "ethos", + "IMPGSL1", + 1990, + "GSL" ], [ "utopia", - 1990, + 2010, "inter", "day", "HYD", "E31", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "FEQ", + "E21", 1990, "ELC" ], @@ -21264,20 +16870,30 @@ "utopia", 2010, "inter", - "day", - "HCO", - "E01", + "night", + "ELC", + "E51", 2010, "ELC" ], [ "utopia", - 2010, + 2000, "summer", "day", - "ELC", - "E51", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", 2000, + "inter", + "night", + "DSL", + "E70", + 1970, "ELC" ], [ @@ -21285,19 +16901,19 @@ 2000, "inter", "night", - "GSL", - "TXG", + "ethos", + "IMPOIL1", 1990, - "TX" + "OIL" ], [ "utopia", - 2000, + 2010, "winter", - "day", + "night", "DSL", "E70", - 2000, + 2010, "ELC" ], [ @@ -21305,239 +16921,249 @@ 2000, "winter", "night", + "URN", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", "DSL", "E70", - 1970, + 1980, "ELC" ], [ "utopia", - 1990, + 2010, "winter", "day", - "DSL", - "TXD", + "URN", + "E21", 1990, - "TX" + "ELC" ], [ "utopia", - 1990, - "inter", + 2010, + "winter", "night", - "GSL", - "TXG", - 1990, - "TX" + "URN", + "E21", + 2010, + "ELC" ], [ "utopia", - 1990, + 2000, "winter", - "night", + "day", "DSL", - "RHO", + "E70", 1990, - "RH" + "ELC" ], [ "utopia", 2000, "inter", - "day", + "night", "HCO", "E01", - 2000, + 1980, "ELC" ], [ "utopia", - 2010, + 1990, "inter", "night", - "ELC", - "TXE", - 2010, - "TX" + "FEQ", + "E21", + 1990, + "ELC" ], [ "utopia", 2000, - "winter", - "day", - "DSL", - "RHO", - 1980, - "RH" + "inter", + "night", + "ethos", + "IMPURN1", + 1990, + "URN" ], [ "utopia", 2010, - "summer", + "winter", "day", - "ELC", - "RHE", - 2010, - "RH" + "HYD", + "E31", + 1980, + "ELC" ], [ "utopia", 2000, - "summer", - "day", - "URN", - "E21", - 1990, + "winter", + "night", + "DSL", + "E70", + 1980, "ELC" ], [ "utopia", - 2010, + 1990, "summer", - "day", + "night", "DSL", - "RHO", - 2010, - "RH" + "E70", + 1970, + "ELC" ], [ "utopia", - 2000, - "winter", + 1990, + "summer", "day", - "FEQ", - "E21", - 2000, - "ELC" + "OIL", + "SRE", + 1990, + "DSL" ], [ "utopia", - 2000, - "summer", + 2010, + "winter", "day", "ethos", - "IMPOIL1", + "IMPDSL1", 1990, - "OIL" + "DSL" ], [ "utopia", - 2000, - "inter", + 2010, + "winter", "night", - "DSL", - "E70", - 1970, + "HYD", + "E31", + 2000, "ELC" ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL", - "RHO", - 1990, - "RH" - ], [ "utopia", 1990, "summer", - "night", - "ethos", - "IMPHYD", + "day", + "OIL", + "SRE", 1990, - "HYD" + "GSL" ], [ "utopia", 1990, "summer", "day", - "ethos", - "IMPOIL1", - 1990, - "OIL" + "ELC", + "E51", + 1980, + "ELC" ], [ "utopia", - 1990, + 2000, "inter", "night", "DSL", - "RHO", - 1990, - "RH" + "E70", + 2000, + "ELC" ], [ "utopia", - 2000, - "inter", - "day", - "DSL", - "TXD", - 1990, - "TX" + 2010, + "winter", + "night", + "HCO", + "E01", + 2000, + "ELC" ], [ "utopia", 2010, "summer", - "day", - "URN", + "night", + "FEQ", "E21", - 2010, + 1990, "ELC" ], [ "utopia", 2010, + "winter", + "day", + "DSL", + "E70", + 2000, + "ELC" + ], + [ + "utopia", + 1990, "inter", - "night", + "day", "OIL", "SRE", - 2010, - "GSL" + 1990, + "DSL" ], [ "utopia", - 2000, - "winter", + 2010, + "summer", "night", - "DSL", - "RHO", - 2000, - "RH" + "ELC", + "E51", + 2010, + "ELC" ], [ "utopia", 2010, "summer", "day", - "DSL", - "E70", + "URN", + "E21", 2000, "ELC" ], [ "utopia", - 2010, - "winter", + 1990, + "summer", "night", - "ethos", - "IMPOIL1", + "OIL", + "SRE", 1990, - "OIL" + "DSL" ], [ "utopia", - 1990, - "inter", - "day", + 2000, + "winter", + "night", "DSL", "E70", - 1980, + 1970, "ELC" ], [ @@ -21545,209 +17171,189 @@ 1990, "summer", "night", - "DSL", - "TXD", + "OIL", + "SRE", 1990, - "TX" + "GSL" ], [ "utopia", - 2000, - "winter", - "day", + 1990, + "summer", + "night", "ELC", "E51", - 1990, + 1980, "ELC" ], [ "utopia", 1990, - "inter", + "summer", "night", - "HYD", - "E31", - 1990, + "HCO", + "E01", + 1960, "ELC" ], [ "utopia", 1990, - "summer", - "day", - "ELC", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - 2000, "inter", "day", "ethos", - "IMPHCO1", + "IMPGSL1", 1990, - "HCO" + "GSL" ], [ "utopia", - 2010, + 1990, "summer", - "night", - "ELC", - "RHE", - 2010, - "RH" + "day", + "HCO", + "E01", + 1980, + "ELC" ], [ "utopia", 2000, "inter", "night", - "ELC", - "RHE", + "OIL", + "SRE", 1990, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "night", - "DSL", - "E70", - 2000, - "ELC" + "DSL" ], [ "utopia", 2010, "winter", - "night", + "day", "HYD", "E31", - 1980, + 2010, "ELC" ], [ "utopia", - 1990, + 2000, "inter", "night", "ELC", - "RHE", - 1990, - "RH" + "E51", + 1980, + "ELC" ], [ "utopia", - 2010, + 2000, "inter", - "day", - "ELC", - "TXE", - 2010, - "TX" + "night", + "OIL", + "SRE", + 1990, + "GSL" ], [ "utopia", - 2010, - "summer", - "night", - "FEQ", + 1990, + "winter", + "day", + "URN", "E21", - 2000, + 1990, "ELC" ], [ "utopia", - 2010, - "winter", + 2000, + "summer", "night", - "ELC", - "RHE", + "URN", + "E21", 1990, - "RH" + "ELC" ], [ "utopia", - 2000, + 1990, "inter", "night", - "DSL", - "RHO", - 1980, - "RH" + "HCO", + "E01", + 1970, + "ELC" ], [ "utopia", 2000, "summer", "day", - "GSL", - "TXG", - 1980, - "TX" + "HYD", + "E31", + 1990, + "ELC" ], [ "utopia", 2000, - "summer", - "night", - "FEQ", - "E21", + "winter", + "day", + "OIL", + "SRE", 1990, - "ELC" + "DSL" ], [ "utopia", - 1990, - "summer", + 2010, + "inter", "day", "ethos", - "IMPHCO1", + "IMPOIL1", 1990, - "HCO" + "OIL" ], [ "utopia", - 1990, - "summer", + 2000, + "winter", "day", - "GSL", - "TXG", - 1980, - "TX" + "ELC", + "E51", + 2000, + "ELC" ], [ "utopia", - 2010, + 2000, "inter", "day", - "ethos", - "IMPFEQ", + "HYD", + "E31", 1990, - "FEQ" + "ELC" ], [ "utopia", - 1990, + 2010, "inter", "day", - "GSL", - "TXG", - 1990, - "TX" + "DSL", + "E70", + 1980, + "ELC" ], [ "utopia", - 2010, - "summer", + 2000, + "winter", "night", - "ELC", - "E51", - 1990, + "DSL", + "E70", + 2000, "ELC" ] ], @@ -25612,7 +21218,22 @@ "RHO", "TXG" ], - "tech_annual": [], + "tech_annual": [ + "RHO", + "TXE", + "RHE", + "TXG", + "TXD", + "RL1" + ], + "tech_demand": [ + "RHO", + "TXE", + "RHE", + "TXG", + "TXD", + "RL1" + ], "tech_baseload": [ "E31", "E01", From 8370fb1bb4721a5a04d2014fe588cb499061bb4b Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 23 Jul 2025 17:48:56 -0400 Subject: [PATCH 190/587] Fix a little bug in the ReserveMargin constraint for annualised demands --- temoa/temoa_model/temoa_rules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 1a0bcefa3..04f814a6f 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -2232,7 +2232,7 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): ) # Generators might serve demands directly - total_generation = sum( + total_generation += sum( value(M.DemandSpecificDistribution[r, p, s, d, S_o]) * M.V_FlowOutAnnual[r, p, s, d, S_i, t, S_v, S_o] for (t, S_v) in M.processReservePeriods[r, p] From f2d5b21bf2b513a490c5ebbd059bbba70f22cff5 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 24 Jul 2025 15:25:42 -0400 Subject: [PATCH 191/587] Comment out MPL as it is no longer used --- temoa/temoa_model/table_data_puller.py | 8 +- temoa/temoa_model/temoa_model.py | 5 +- temoa/temoa_model/temoa_rules.py | 11 +- tests/testing_data/mediumville_sets.json | 110 --- tests/testing_data/test_system_sets.json | 938 ----------------------- tests/testing_data/utopia_sets.json | 692 ----------------- 6 files changed, 13 insertions(+), 1751 deletions(-) diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index a5dbe4b32..59d1192ed 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -305,7 +305,7 @@ def poll_cost_results( # conveniences... GDR = value(M.GlobalDiscountRate) - MPL = M.ModelProcessLife + # MPL = M.ModelProcessLife LLN = M.LoanLifetimeProcess exchange_costs = ExchangeTechCostLedger(M) @@ -370,15 +370,15 @@ def poll_cost_results( ) for r, p, t, v in M.CostFixed.sparse_iterkeys(): - cap = value(M.V_Capacity[r, p, t, v]) / value(M.ProcessLifeFrac[r, p, t, v]) + cap = value(M.V_Capacity[r, p, t, v]) if abs(cap) < epsilon: continue fixed_cost = value(M.CostFixed[r, p, t, v]) - undiscounted_fixed_cost = cap * fixed_cost * value(MPL[r, p, t, v]) + undiscounted_fixed_cost = cap * fixed_cost * value(M.PeriodLength[p]) model_fixed_cost = temoa_rules.fixed_or_variable_cost( - cap, fixed_cost, value(MPL[r, p, t, v]), GDR=GDR, P_0=p_0, p=p + cap, fixed_cost, value(M.PeriodLength[p]), GDR=GDR, P_0=p_0, p=p ) if '-' in r: exchange_costs.add_cost_record( diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index f35e47744..79b83903d 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -426,8 +426,9 @@ def __init__(M, *args, **kwargs): ) M.CostEmission = Param(M.CostEmission_rpe) - M.ModelProcessLife_rptv = Set(dimen=4, initialize=ModelProcessLifeIndices) - M.ModelProcessLife = Param(M.ModelProcessLife_rptv, initialize=ParamModelProcessLife_rule) + # devnote: no longer used + # 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) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 04f814a6f..62844cf92 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -750,7 +750,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): P_0 = min(M.time_optimize) P_e = M.time_future.last() # End point of modeled horizon GDR = value(M.GlobalDiscountRate) - MPL = M.ModelProcessLife + # MPL = M.ModelProcessLife if value(M.MyopicDiscountingYear) != 0: P_0 = value(M.MyopicDiscountingYear) @@ -3564,11 +3564,12 @@ def RenewablePortfolioStandard_Constraint(M: 'TemoaModel', r, p, g): # --------------------------------------------------------------- # Define rule-based parameters # --------------------------------------------------------------- -def ParamModelProcessLife_rule(M: 'TemoaModel', r, p, t, v): - life_length = value(M.LifetimeProcess[r, t, v]) - mpl = min(v + life_length - p, value(M.PeriodLength[p])) +# devnote: MPL no longer used. Instead, use adjusted capacity * period length +# def ParamModelProcessLife_rule(M: 'TemoaModel', r, p, t, v): +# life_length = value(M.LifetimeProcess[r, t, v]) +# mpl = min(v + life_length - p, value(M.PeriodLength[p])) - return mpl +# return mpl def ParamPeriodLength(M: 'TemoaModel', p): diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index a8282361c..39ad2370d 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -3134,116 +3134,6 @@ 2025 ] ], - "ModelProcessLife_rptv": [ - [ - "A", - 2025, - "GeoThermal", - 2025 - ], - [ - "A", - 2025, - "EF", - 2025 - ], - [ - "A", - 2025, - "GeoHeater", - 2025 - ], - [ - "B", - 2025, - "well", - 2025 - ], - [ - "A-B", - 2025, - "FGF_pipe", - 2025 - ], - [ - "A", - 2025, - "heater", - 2025 - ], - [ - "B", - 2025, - "bulbs", - 2025 - ], - [ - "B", - 2025, - "GeoThermal", - 2025 - ], - [ - "B", - 2025, - "EF", - 2025 - ], - [ - "A", - 2025, - "EH", - 2025 - ], - [ - "B", - 2025, - "heater", - 2025 - ], - [ - "B", - 2025, - "GeoHeater", - 2025 - ], - [ - "A", - 2025, - "EFL", - 2025 - ], - [ - "A", - 2025, - "bulbs", - 2025 - ], - [ - "B", - 2025, - "batt", - 2025 - ], - [ - "B-A", - 2025, - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "EH", - 2025 - ], - [ - "A", - 2025, - "well", - 2025 - ] - ], "NewCapacityVar_rtv": [ [ "A", diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index ce3d11482..fc75245de 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -33173,944 +33173,6 @@ 2020 ] ], - "ModelProcessLife_rptv": [ - [ - "R2", - 2030, - "R_NGH", - 2030 - ], - [ - "R2", - 2020, - "S_IMPETH", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "S_IMPNG", - 2020 - ], - [ - "R2", - 2020, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "S_IMPURN", - 2020 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "S_IMPNG", - 2020 - ], - [ - "R1", - 2030, - "R_EH", - 2020 - ], - [ - "R2", - 2020, - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2020, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2030, - "T_EV", - 2030 - ], - [ - "R2", - 2030, - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "T_EV", - 2025 - ], - [ - "R1", - 2030, - "S_IMPNG", - 2020 - ], - [ - "R1", - 2020, - "S_IMPNG", - 2020 - ], - [ - "R1", - 2025, - "S_IMPETH", - 2020 - ], - [ - "R1", - 2025, - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "S_IMPURN", - 2020 - ], - [ - "R2", - 2030, - "R_NGH", - 2025 - ], - [ - "R1", - 2020, - "S_IMPURN", - 2020 - ], - [ - "R2", - 2020, - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "E_NGCC", - 2020 - ], - [ - "R2", - 2020, - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2025, - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "R_NGH", - 2020 - ], - [ - "R2", - 2020, - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2025 - ], - [ - "R2-R1", - 2020, - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "T_GSL", - 2030 - ], - [ - "R2-R1", - 2030, - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "E_NGCC", - 2030 - ], - [ - "R2", - 2025, - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "T_EV", - 2025 - ], - [ - "R1", - 2020, - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "T_EV", - 2025 - ], - [ - "R1", - 2030, - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "S_IMPOIL", - 2020 - ], - [ - "R1", - 2025, - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "R_NGH", - 2020 - ], - [ - "R1", - 2020, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2030 - ], - [ - "R2", - 2020, - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "S_IMPETH", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2030 - ], - [ - "R1", - 2030, - "T_GSL", - 2030 - ], - [ - "R2", - 2025, - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "T_GSL", - 2025 - ], - [ - "R2", - 2025, - "S_IMPETH", - 2020 - ], - [ - "R1", - 2030, - "E_NGCC", - 2025 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "T_EV", - 2020 - ], - [ - "R1-R2", - 2025, - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "T_GSL", - 2025 - ], - [ - "R2", - 2020, - "S_IMPNG", - 2020 - ], - [ - "R2", - 2025, - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "S_IMPOIL", - 2020 - ], - [ - "R1", - 2025, - "T_DSL", - 2025 - ], - [ - "R2", - 2025, - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "R_EH", - 2030 - ], - [ - "R1", - 2030, - "S_IMPETH", - 2020 - ], - [ - "R1", - 2025, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "S_IMPURN", - 2020 - ], - [ - "R2", - 2030, - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "E_NGCC", - 2020 - ], - [ - "R1", - 2020, - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "R_EH", - 2025 - ], - [ - "R2", - 2025, - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "T_EV", - 2020 - ], - [ - "R2-R1", - 2025, - "E_TRANS", - 2015 - ], - [ - "R1", - 2020, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2020, - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "R_EH", - 2030 - ], - [ - "R1", - 2030, - "T_DSL", - 2030 - ], - [ - "R1", - 2030, - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "T_GSL", - 2020 - ], - [ - "R2", - 2020, - "S_IMPURN", - 2020 - ], - [ - "R1", - 2020, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2030 - ], - [ - "R1", - 2025, - "R_NGH", - 2025 - ], - [ - "R2", - 2025, - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "E_SOLPV", - 2025 - ], - [ - "R1", - 2020, - "E_SOLPV", - 2020 - ], - [ - "R1-R2", - 2030, - "E_TRANS", - 2015 - ], - [ - "R2", - 2020, - "T_DSL", - 2020 - ], - [ - "R1-R2", - 2020, - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "T_EV", - 2025 - ], - [ - "R1", - 2025, - "S_IMPNG", - 2020 - ], - [ - "R2", - 2030, - "T_DSL", - 2030 - ], - [ - "R2", - 2030, - "R_EH", - 2025 - ], - [ - "R1", - 2020, - "S_IMPETH", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2025, - "R_EH", - 2025 - ], - [ - "R1", - 2030, - "T_DSL", - 2025 - ], - [ - "R1", - 2020, - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "R_NGH", - 2030 - ], - [ - "R2", - 2030, - "E_BATT", - 2030 - ], - [ - "R2", - 2025, - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "R_EH", - 2025 - ], - [ - "R1", - 2025, - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2030, - "R_EH", - 2020 - ], - [ - "R1", - 2020, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "T_DSL", - 2025 - ], - [ - "R2", - 2025, - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "T_EV", - 2030 - ], - [ - "R1", - 2030, - "T_DSL", - 2020 - ], - [ - "R1", - 2025, - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "S_IMPURN", - 2020 - ] - ], "NewCapacityVar_rtv": [ [ "R2", diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 3214a587a..218c3658e 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -18678,698 +18678,6 @@ 2000 ] ], - "ModelProcessLife_rptv": [ - [ - "utopia", - 2000, - "RL1", - 2000 - ], - [ - "utopia", - 2000, - "E21", - 2000 - ], - [ - "utopia", - 2000, - "TXE", - 1990 - ], - [ - "utopia", - 1990, - "RL1", - 1980 - ], - [ - "utopia", - 1990, - "RHO", - 1990 - ], - [ - "utopia", - 2000, - "IMPDSL1", - 1990 - ], - [ - "utopia", - 2010, - "IMPURN1", - 1990 - ], - [ - "utopia", - 1990, - "TXG", - 1980 - ], - [ - "utopia", - 2010, - "E01", - 1980 - ], - [ - "utopia", - 2010, - "E51", - 1980 - ], - [ - "utopia", - 2000, - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "TXG", - 2000 - ], - [ - "utopia", - 1990, - "E70", - 1960 - ], - [ - "utopia", - 2010, - "E21", - 1990 - ], - [ - "utopia", - 1990, - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "IMPHCO1", - 1990 - ], - [ - "utopia", - 2010, - "RHE", - 2010 - ], - [ - "utopia", - 2000, - "E31", - 2000 - ], - [ - "utopia", - 2010, - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "E01", - 1980 - ], - [ - "utopia", - 2000, - "E70", - 1970 - ], - [ - "utopia", - 1990, - "E51", - 1980 - ], - [ - "utopia", - 2010, - "E01", - 2000 - ], - [ - "utopia", - 2010, - "E51", - 2000 - ], - [ - "utopia", - 2010, - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "TXD", - 2000 - ], - [ - "utopia", - 2000, - "E70", - 2000 - ], - [ - "utopia", - 2000, - "IMPHYD", - 1990 - ], - [ - "utopia", - 2010, - "E31", - 1990 - ], - [ - "utopia", - 2000, - "SRE", - 2000 - ], - [ - "utopia", - 1990, - "TXD", - 1970 - ], - [ - "utopia", - 2010, - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "TXD", - 1980 - ], - [ - "utopia", - 1990, - "IMPFEQ", - 1990 - ], - [ - "utopia", - 2000, - "IMPOIL1", - 1990 - ], - [ - "utopia", - 2010, - "IMPGSL1", - 1990 - ], - [ - "utopia", - 2000, - "RHO", - 2000 - ], - [ - "utopia", - 2010, - "RHO", - 2010 - ], - [ - "utopia", - 1990, - "E31", - 1990 - ], - [ - "utopia", - 1990, - "RHO", - 1980 - ], - [ - "utopia", - 2010, - "E70", - 1990 - ], - [ - "utopia", - 2010, - "E31", - 2010 - ], - [ - "utopia", - 1990, - "IMPGSL1", - 1990 - ], - [ - "utopia", - 1990, - "TXG", - 1970 - ], - [ - "utopia", - 2000, - "TXG", - 1980 - ], - [ - "utopia", - 1990, - "IMPDSL1", - 1990 - ], - [ - "utopia", - 2010, - "RHE", - 2000 - ], - [ - "utopia", - 2000, - "E31", - 1990 - ], - [ - "utopia", - 2010, - "E70", - 2010 - ], - [ - "utopia", - 2000, - "IMPURN1", - 1990 - ], - [ - "utopia", - 1990, - "E21", - 1990 - ], - [ - "utopia", - 2010, - "IMPFEQ", - 1990 - ], - [ - "utopia", - 1990, - "E70", - 1980 - ], - [ - "utopia", - 2010, - "E21", - 2010 - ], - [ - "utopia", - 1990, - "E01", - 1970 - ], - [ - "utopia", - 2000, - "E01", - 1980 - ], - [ - "utopia", - 2010, - "E01", - 1990 - ], - [ - "utopia", - 2000, - "E51", - 1980 - ], - [ - "utopia", - 2010, - "E51", - 1990 - ], - [ - "utopia", - 2000, - "TXG", - 2000 - ], - [ - "utopia", - 1990, - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "SRE", - 2010 - ], - [ - "utopia", - 2000, - "E70", - 1990 - ], - [ - "utopia", - 2010, - "E31", - 1980 - ], - [ - "utopia", - 2000, - "E21", - 1990 - ], - [ - "utopia", - 2000, - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "IMPOIL1", - 1990 - ], - [ - "utopia", - 2000, - "E01", - 2000 - ], - [ - "utopia", - 2010, - "IMPDSL1", - 1990 - ], - [ - "utopia", - 2000, - "E51", - 2000 - ], - [ - "utopia", - 1990, - "TXD", - 1990 - ], - [ - "utopia", - 2000, - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "IMPHCO1", - 1990 - ], - [ - "utopia", - 2000, - "TXD", - 2000 - ], - [ - "utopia", - 2010, - "TXD", - 2010 - ], - [ - "utopia", - 1990, - "E31", - 1980 - ], - [ - "utopia", - 1990, - "RHO", - 1970 - ], - [ - "utopia", - 2010, - "E70", - 1980 - ], - [ - "utopia", - 2010, - "E31", - 2000 - ], - [ - "utopia", - 1990, - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "TXE", - 2000 - ], - [ - "utopia", - 2010, - "TXE", - 2010 - ], - [ - "utopia", - 1990, - "IMPOIL1", - 1990 - ], - [ - "utopia", - 1990, - "RL1", - 1990 - ], - [ - "utopia", - 2010, - "RL1", - 2010 - ], - [ - "utopia", - 2000, - "IMPGSL1", - 1990 - ], - [ - "utopia", - 1990, - "IMPHCO1", - 1990 - ], - [ - "utopia", - 2010, - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "E70", - 2000 - ], - [ - "utopia", - 2000, - "E31", - 1980 - ], - [ - "utopia", - 2010, - "TXG", - 2010 - ], - [ - "utopia", - 1990, - "E70", - 1970 - ], - [ - "utopia", - 2010, - "E21", - 2000 - ], - [ - "utopia", - 1990, - "E01", - 1960 - ], - [ - "utopia", - 2000, - "E01", - 1970 - ], - [ - "utopia", - 2010, - "IMPHYD", - 1990 - ], - [ - "utopia", - 2010, - "SRE", - 2000 - ], - [ - "utopia", - 1990, - "IMPURN1", - 1990 - ], - [ - "utopia", - 2000, - "RHE", - 2000 - ], - [ - "utopia", - 1990, - "E01", - 1990 - ], - [ - "utopia", - 2000, - "E70", - 1980 - ], - [ - "utopia", - 1990, - "E51", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 2010 - ], - [ - "utopia", - 2010, - "E51", - 2010 - ], - [ - "utopia", - 1990, - "E70", - 1990 - ], - [ - "utopia", - 2010, - "RHO", - 2000 - ], - [ - "utopia", - 1990, - "IMPHYD", - 1990 - ], - [ - "utopia", - 2000, - "E01", - 1990 - ], - [ - "utopia", - 2000, - "E51", - 1990 - ], - [ - "utopia", - 2000, - "IMPFEQ", - 1990 - ], - [ - "utopia", - 1990, - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "RHO", - 1980 - ], - [ - "utopia", - 2000, - "TXD", - 1990 - ] - ], "NewCapacityVar_rtv": [ [ "utopia", From 32464697b8f3c35958bfc5beba7916abcfc2a00c Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 24 Jul 2025 16:50:54 -0400 Subject: [PATCH 192/587] Make storage test tolerances absolute instead of relative --- tests/test_storage.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_storage.py b/tests/test_storage.py index 52d2c612c..4ab04f8b3 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -54,7 +54,7 @@ def test_storage_fraction(system_test_run): ) assert model.V_StorageLevel[r, p, s, d, t, v].value == pytest.approx( - energy, rel=1e-3 + energy, abs=1e-5 ), f'model fails to initialise storage state at start of season {r, p, s, d, t, v}' @@ -135,7 +135,7 @@ def test_storage_flow_balance(system_test_run): outflow = sum(model.V_FlowOut[idx].value for idx in outflow_indices) assert inflow == pytest.approx( - outflow, rel=1e-3 + outflow, abs=1e-5 ), (f'total inflow and outflow of storage tech {s_tech} do not match', ' - there is a discontinuity of storage states') From 216382f600bfb734a627c11774c42da4e43540d5 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 29 Jul 2025 11:48:43 -0400 Subject: [PATCH 193/587] Fix typo in exchange flows for commodity balance constraint --- temoa/temoa_model/temoa_rules.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 62844cf92..c9694ca97 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1228,7 +1228,7 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): if S_t not in M.tech_annual ) consumed += sum( - value(M.SegFrac[p, s, d]) * M.V_FlowOutAnnual[reg + '-' + r, p, c, S_t, S_v, S_o] + value(M.SegFrac[p, s, d]) * M.V_FlowOutAnnual[r + '-' + reg, p, c, S_t, S_v, S_o] / get_variable_efficiency(M, r + '-' + reg, p, s, d, c, S_t, S_v, S_o) for reg, S_t, S_v, S_o in M.exportRegions[r, p, c] if S_t in M.tech_annual @@ -1380,7 +1380,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): if S_t not in M.tech_annual ) produced += sum( - M.V_FlowOutAnnual[r + '-' + S_r, p, S_i, S_t, S_v, c] + M.V_FlowOutAnnual[S_r + '-' + r, p, S_i, S_t, S_v, c] for S_r, S_t, S_v, S_i in M.importRegions[r, p, c] if S_t in M.tech_annual ) From ff9892f28d6d4741622d56d9f776f0a25188bf1d Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 29 Jul 2025 12:20:15 -0400 Subject: [PATCH 194/587] Allow regions without any demand commodities (e.g., transmission nodes) --- temoa/temoa_model/model_checking/commodity_network.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/temoa/temoa_model/model_checking/commodity_network.py b/temoa/temoa_model/model_checking/commodity_network.py index 91d97c8cb..51863c326 100644 --- a/temoa/temoa_model/model_checking/commodity_network.py +++ b/temoa/temoa_model/model_checking/commodity_network.py @@ -78,11 +78,14 @@ def __init__(self, region, period: int, model_data: NetworkModelData): self.orig_connex: set[tuple] = set() + # devnote: changing this from error to info as a power sector model might have + # transmission-only nodes (exchange techs only, no demands) if not self.model_data.demand_commodities[self.region, self.period]: - raise ValueError( - f'No demand commodities discovered in region {self.region} period {self.period}. Check ' - f'Demand table data' + msg = ( + f'No demand commodities discovered in region {self.region} period {self.period}. Ignore this ' + 'if this was intentional.' ) + logger.info(msg) # dev note: This code was originally designed/tested to run on tuples of (ic, tech_name, oc) # since the implementation of Tech named tuple, we could switch over to that soon, # but it will be work to re-work the tests. The networks are smaller this way From b767650efa9ad9daa5c2f9ff413995d34ac9f49d Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 30 Jul 2025 16:22:15 -0400 Subject: [PATCH 195/587] Fix a bug in LinkedEmissionsTech_Constraint --- temoa/temoa_model/temoa_rules.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index c9694ca97..299612f0f 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -3700,14 +3700,14 @@ def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): # for S_o in M.processOutputsByInput[r, p, linked_t, v, S_i] # ) - if t in M.tech_demand: + if linked_t in M.tech_demand: linked_flow = sum( M.DemandSpecificDistribution[r, p, s, d, S_o] * M.V_FlowOutAnnual[r, p, S_i, linked_t, v, S_o] for S_i in M.processInputs[r, p, linked_t, v] for S_o in M.processOutputsByInput[r, p, linked_t, v, S_i] ) - elif t in M.tech_annual: + elif linked_t in M.tech_annual: linked_flow = sum( M.SegFrac[p, s, d] * M.V_FlowOutAnnual[r, p, S_i, linked_t, v, S_o] From e5e4b4b4959fb8bbc6a69f40a2cade6b1143cea7 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 30 Jul 2025 16:47:22 -0400 Subject: [PATCH 196/587] Clean up demand constraint indices --- temoa/temoa_model/hybrid_loader.py | 1 + temoa/temoa_model/temoa_initialize.py | 13 +++++++------ temoa/temoa_model/temoa_model.py | 6 ++++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 35fee7d5d..008d0917e 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -1116,6 +1116,7 @@ def load_param_idx_sets(self, data: dict) -> dict: param_idx_sets = { M.CostInvest.name: M.CostInvest_rtv.name, M.CostEmission.name: M.CostEmission_rpe.name, + M.Demand.name: M.DemandConstraint_rpc.name, M.LimitEmission.name: M.LimitEmissionConstraint_rpe.name, M.LimitActivity.name: M.LimitActivityConstraint_rpt.name, M.LimitSeasonalCapacityFactor.name: M.LimitSeasonalCapacityFactorConstraint_rpst.name, diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 815303904..d4c9e1013 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1670,13 +1670,14 @@ def CapacityAnnualConstraintIndices(M: 'TemoaModel'): # yield r, p, s, d, t, v, dem, s0, d0 -def DemandConstraintIndices(M: 'TemoaModel'): - indices = set( - (r, p, dem) - for r, p, dem in M.Demand.sparse_iterkeys() - ) +# devnote: no longer needed +# def DemandConstraintIndices(M: 'TemoaModel'): +# indices = set( +# (r, p, dem) +# for r, p, dem in M.Demand.sparse_iterkeys() +# ) - return indices +# return indices def BaseloadDiurnalConstraintIndices(M: 'TemoaModel'): diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 79b83903d..88fa090e1 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -282,7 +282,10 @@ def __init__(M, *args, **kwargs): default=0 ) - M.Demand = Param(M.regions, M.time_optimize, M.commodity_demand) + M.DemandConstraint_rpc = Set( + within=M.regions * M.time_optimize * M.commodity_demand + ) + M.Demand = Param(M.DemandConstraint_rpc) # Dev Note: This parameter is currently NOT implemented. Preserved for later refactoring # LimitResource IS implemented but sums cumulatively for a technology rather than resource commodity @@ -645,7 +648,6 @@ def __init__(M, *args, **kwargs): # Declare core model constraints that ensure proper system functioning # In driving order, starting with the need to meet end-use demands - M.DemandConstraint_rpc = Set(dimen=3, initialize=DemandConstraintIndices) M.DemandConstraint = Constraint(M.DemandConstraint_rpc, rule=Demand_Constraint) # devnote: testing a workaround From 8e207c3ff2abdf99e514bb23b51dec38b62224d3 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 30 Jul 2025 16:49:16 -0400 Subject: [PATCH 197/587] Move creation of tech_demand set out of period loop for efficiency --- temoa/temoa_model/temoa_initialize.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index d4c9e1013..6cf243eb6 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -785,6 +785,11 @@ def CreateSparseDicts(M: 'TemoaModel'): if t in M.tech_flex and o not in M.commodity_flex: M.commodity_flex.add(o) + # All demand technologies must be annual technologies + if o in M.commodity_demand and t not in M.tech_demand: + M.tech_annual.add(t) + M.tech_demand.add(t) + # Add in the period (p) index, since it's not included in the efficiency # table. for p in M.time_optimize: @@ -814,11 +819,6 @@ def CreateSparseDicts(M: 'TemoaModel'): # if tech is no longer active, don't include it if v + l_lifetime <= p: continue - - # All demand technologies must be annual technologies - if o in M.commodity_demand and t not in M.tech_demand: - M.tech_annual.add(t) - M.tech_demand.add(t) # Here we utilize the indices in a given iteration of the loop to # create the dictionary keys, and initialize the associated values From ba8d9544fcf9e4e9392da92900b9c395c9193317 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 19 Aug 2025 15:52:14 -0400 Subject: [PATCH 198/587] Make annualised demands an optional feature for flexibility and add a tricky demand test --- .../temoa_model/model_checking/validators.py | 22 - temoa/temoa_model/table_data_puller.py | 5 +- temoa/temoa_model/temoa_initialize.py | 15 +- temoa/temoa_model/temoa_model.py | 16 +- temoa/temoa_model/temoa_rules.py | 139 +- tests/conftest.py | 1 + tests/legacy_test_values.py | 39 +- tests/test_full_runs.py | 1 + .../config_annualised_demand.toml | 77 + tests/testing_data/annualised_demand.sql | 1054 ++ tests/testing_data/mediumville_sets.json | 461 +- tests/testing_data/test_system_sets.json | 11138 +++++++++++++-- tests/testing_data/utopia_sets.json | 11427 +++++++++++----- 13 files changed, 19832 insertions(+), 4563 deletions(-) create mode 100644 tests/testing_configs/config_annualised_demand.toml create mode 100644 tests/testing_data/annualised_demand.sql diff --git a/temoa/temoa_model/model_checking/validators.py b/temoa/temoa_model/model_checking/validators.py index 0098975c0..b5ab6a8a8 100644 --- a/temoa/temoa_model/model_checking/validators.py +++ b/temoa/temoa_model/model_checking/validators.py @@ -331,28 +331,6 @@ def validate_tech_sets(M: 'TemoaModel'): ) ): raise ValueError("Technology sets failed to validate. Check log file for details.") - - -def validate_demand_tech_sets(M: 'TemoaModel'): - """ - Check tech sets for any forbidden intersections - """ - if not all( - ( - check_no_intersection(M.tech_demand, M.tech_baseload), - check_no_intersection(M.tech_demand, M.tech_storage), - check_no_intersection(M.tech_demand, M.tech_upramping), - check_no_intersection(M.tech_demand, M.tech_downramping), - check_no_intersection(M.tech_demand, M.tech_flex) - ) - ): - raise ValueError( - "Demand technologies were added to forbidden sets. Check log file for details. " - "If these technologies require these features, consider adding an intermediate " - "process between the technology's output commodity and the demand commodity. " - "Note this will break the enforcement that demand technologies meet " - "a consistent proportion of demands throughout the year." - ) def check_no_intersection(set_one, set_two): diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/temoa_model/table_data_puller.py index 59d1192ed..9cd1889e6 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/temoa_model/table_data_puller.py @@ -189,9 +189,12 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl # basic annual flows for r, p, i, t, v, o in M.V_FlowOutAnnual.keys(): + # Make sure this isn't just a non-annual demand tech + if t not in M.tech_annual: + continue for s in M.TimeSeason[p]: for d in M.time_of_day: - if t in M.tech_demand: + if o in M.commodity_demand: distribution = value(M.DemandSpecificDistribution[r, p, s, d, o]) else: distribution = value(M.SegFrac[p, s, d]) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 6cf243eb6..49a93d5b6 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -787,7 +787,6 @@ def CreateSparseDicts(M: 'TemoaModel'): # All demand technologies must be annual technologies if o in M.commodity_demand and t not in M.tech_demand: - M.tech_annual.add(t) M.tech_demand.add(t) # Add in the period (p) index, since it's not included in the efficiency @@ -990,10 +989,10 @@ def CreateSparseDicts(M: 'TemoaModel'): M.activeFlow_rpitvo = set( (r, p, i, t, v, o) for r, p, t in M.processVintages - if t in M.tech_annual for v in M.processVintages[r, p, t] for i in M.processInputs[r, p, t, v] for o in M.processOutputsByInput[r, p, t, v, i] + if t in M.tech_annual or (t in M.tech_demand and o in M.commodity_demand) ) M.activeFlex_rpsditvo = set( @@ -1670,6 +1669,18 @@ def CapacityAnnualConstraintIndices(M: 'TemoaModel'): # yield r, p, s, d, t, v, dem, s0, d0 +def DemandActivityConstraintIndices(M: 'TemoaModel'): + indices = set( + (r, p, s, d, t, v, dem) + for r, p, dem in M.DemandConstraint_rpc + for t, v in M.commodityUStreamProcess[r, p, dem] + if t not in M.tech_annual + for s in M.TimeSeason[p] + for d in M.time_of_day + ) + return indices + + # devnote: no longer needed # def DemandConstraintIndices(M: 'TemoaModel'): # indices = set( diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 88fa090e1..81e554fb9 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -42,7 +42,6 @@ region_group_check, validate_Efficiency, validate_tech_sets, - validate_demand_tech_sets, no_slash_or_pipe, validate_ReserveMargin, ) @@ -184,7 +183,7 @@ def __init__(M, *args, **kwargs): M.tech_all = Set(initialize=M.tech_production, validate=no_slash_or_pipe) # was M.tech_resource | M.tech_production M.tech_baseload = Set(within=M.tech_all) M.tech_annual = Set(within=M.tech_all) - M.tech_demand = Set(within=M.tech_annual) + M.tech_demand = Set(within=M.tech_all) # annual storage not supported in Storage constraint or TableWriter, so exclude from domain M.tech_storage = Set(within=M.tech_all) M.tech_reserve = Set(within=M.tech_all) @@ -384,7 +383,6 @@ def __init__(M, *args, **kwargs): # perform the sparse matrix of indexing for the parameters, variables, and # equations below. M.Create_SparseDicts = BuildAction(rule=CreateSparseDicts) - M.validate_demand_techs = BuildAction(rule=validate_demand_tech_sets) M.initialize_Demands = BuildAction(rule=CreateDemands) M.CapacityFactor_rpsdt = Set(dimen=5, initialize=CapacityFactorTechIndices) @@ -651,12 +649,12 @@ def __init__(M, *args, **kwargs): M.DemandConstraint = Constraint(M.DemandConstraint_rpc, rule=Demand_Constraint) # devnote: testing a workaround - # M.DemandActivityConstraint_rpsdtv_dem_s0d0 = Set( - # dimen=9, initialize=DemandActivityConstraintIndices - # ) - # M.DemandActivityConstraint = Constraint( - # M.DemandActivityConstraint_rpsdtv_dem_s0d0, rule=DemandActivity_Constraint - # ) + M.DemandActivityConstraint_rpsdtv_dem = Set( + dimen=7, initialize=DemandActivityConstraintIndices + ) + M.DemandActivityConstraint = Constraint( + M.DemandActivityConstraint_rpsdtv_dem, rule=DemandActivity_Constraint + ) M.CommodityBalanceConstraint_rpsdc = Set( dimen=5, initialize=CommodityBalanceConstraintIndices diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 299612f0f..fb0d99ae4 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -244,9 +244,14 @@ def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): # The expressions below are defined in-line to minimize the amount of # expression cloning taking place with Pyomo. - if t in M.tech_demand: + if t in M.tech_annual: + # Annual demand technology useful_activity = sum( - M.DemandSpecificDistribution[r, p, s, d, S_o] + ( + value(M.DemandSpecificDistribution[r, p, s, d, S_o]) + if S_o in M.commodity_demand + else value(M.SegFrac[p, s, d]) + ) * M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] @@ -989,49 +994,50 @@ def Demand_Constraint(M: 'TemoaModel', r, p, dem): # devnote: no longer needed -# def DemandActivity_Constraint(M: 'TemoaModel', r, p, s, d, t, v, dem, s_0, d_0): -# r""" +def DemandActivity_Constraint(M: 'TemoaModel', r, p, s, d, t, v, dem): + r""" -# For end-use demands, it is unreasonable to let the model arbitrarily shift the -# use of demand technologies across time slices. For instance, if household A buys -# a natural gas furnace while household B buys an electric furnace, then both units -# should be used throughout the year. Without this constraint, the model might choose -# to only use the electric furnace during the day, and the natural gas furnace during the -# night. + For end-use demands, it is unreasonable to let the model arbitrarily shift the + use of demand technologies across time slices. For instance, if household A buys + a natural gas furnace while household B buys an electric furnace, then both units + should be used throughout the year. Without this constraint, the model might choose + to only use the electric furnace during the day, and the natural gas furnace during the + night. -# This constraint ensures that the ratio of a process activity to demand is -# constant for all time slices. Note that if a demand is not specified in a given -# time slice, or is zero, then this constraint will not be considered for that -# slice and demand. This is transparently handled by the :math:`\Theta` superset. + This constraint ensures that the ratio of a process activity to demand is + constant for all time slices. Note that if a demand is not specified in a given + time slice, or is zero, then this constraint will not be considered for that + slice and demand. This is transparently handled by the :math:`\Theta` superset. -# .. math:: -# :label: DemandActivity + .. math:: + :label: DemandActivity -# DEM_{r, p, s, d, dem} \cdot \sum_{I} \textbf{FO}_{r, p, s_0, d_0, i, t \not \in T^{a}, v, dem} -# = -# DEM_{r, p, s_0, d_0, dem} \cdot \sum_{I} \textbf{FO}_{r, p, s, d, i, t \not \in T^{a}, v, dem} + DEM_{r, p, s, d, dem} \cdot \sum_{I} \textbf{FO}_{r, p, s_0, d_0, i, t \not \in T^{a}, v, dem} + = + DEM_{r, p, s_0, d_0, dem} \cdot \sum_{I} \textbf{FO}_{r, p, s, d, i, t \not \in T^{a}, v, dem} -# \\ -# \forall \{r, p, s, d, t, v, dem, s_0, d_0\} \in \Theta_{\text{DemandActivity}} + \\ + \forall \{r, p, s, d, t, v, dem, s_0, d_0\} \in \Theta_{\text{DemandActivity}} -# Note that this constraint is only applied to the demand commodities with diurnal -# variations, and therefore the equation above only includes :math:`\textbf{FO}` -# and not :math:`\textbf{FOA}` -# """ + Note that this constraint is only applied to the demand commodities with diurnal + variations, and therefore the equation above only includes :math:`\textbf{FO}` + and not :math:`\textbf{FOA}` + """ -# act_a = sum( -# M.V_FlowOut[r, p, s_0, d_0, S_i, t, v, dem] -# for S_i in M.processInputsByOutput[r, p, t, v, dem] -# ) -# act_b = sum( -# M.V_FlowOut[r, p, s, d, S_i, t, v, dem] for S_i in M.processInputsByOutput[r, p, t, v, dem] -# ) + activity = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, dem] + for S_i in M.processInputsByOutput[r, p, t, v, dem] + ) -# expr = ( -# act_a * value(M.DemandSpecificDistribution[r, p, s, d, dem]) -# == act_b * value(M.DemandSpecificDistribution[r, p, s_0, d_0, dem]) -# ) -# return expr + annual_activity = sum( + M.V_FlowOutAnnual[r, p, S_i, t, v, dem] + for S_i in M.processInputsByOutput[r, p, t, v, dem] + ) + + expr = ( + annual_activity * value(M.DemandSpecificDistribution[r, p, s, d, dem]) == activity + ) + return expr def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): @@ -1154,19 +1160,15 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): ) # Into annual flows - consumed += value(M.SegFrac[p, s, d]) * sum( - M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] / get_variable_efficiency(M, r, p, s, d, c, S_t, S_v, S_o) - for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t in M.tech_annual and S_t not in M.tech_demand - for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] - ) - - # Into demand technologies (annual flow fit to DSD profile) consumed += sum( - value(M.DemandSpecificDistribution[r, p, s, d, S_o]) + ( + value(M.DemandSpecificDistribution[r, p, s, d, S_o]) + if S_o in M.commodity_demand + else value(M.SegFrac[p, s, d]) + ) * M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] / get_variable_efficiency(M, r, p, s, d, c, S_t, S_v, S_o) for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t in M.tech_demand + if S_t in M.tech_annual for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] ) @@ -2223,20 +2225,26 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): # In most Temoa input databases, demand is endogenous, so we use electricity # generation instead as a proxy for electricity demand. + # Non-annual generation total_generation = sum( M.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] for (t, S_v) in M.processReservePeriods[r, p] - if t not in M.tech_demand + if t not in M.tech_annual for S_i in M.processInputs[r, p, t, S_v] for S_o in M.processOutputsByInput[r, p, t, S_v, S_i] ) # Generators might serve demands directly + # Annual generation total_generation += sum( - value(M.DemandSpecificDistribution[r, p, s, d, S_o]) + ( + value(M.DemandSpecificDistribution[r, p, s, d, S_o]) + if S_o in M.commodity_demand + else value(M.SegFrac[p, s, d]) + ) * M.V_FlowOutAnnual[r, p, s, d, S_i, t, S_v, S_o] for (t, S_v) in M.processReservePeriods[r, p] - if t in M.tech_demand + if t in M.tech_annual for S_i in M.processInputs[r, p, t, S_v] for S_o in M.processOutputsByInput[r, p, t, S_v, S_i] ) @@ -3668,17 +3676,13 @@ def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): of the primary and linked technologies should be specified and identical. """ - if t in M.tech_demand: - primary_flow = sum( - M.DemandSpecificDistribution[r, p, s, d, S_o] - * M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] - * value(M.EmissionActivity[r, e, S_i, t, v, S_o]) - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - elif t in M.tech_annual: + if t in M.tech_annual: primary_flow = sum( - M.SegFrac[p, s, d] + ( + value(M.DemandSpecificDistribution[r, p, s, d, S_o]) + if S_o in M.commodity_demand + else value(M.SegFrac[p, s, d]) + ) * M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] * value(M.EmissionActivity[r, e, S_i, t, v, S_o]) for S_i in M.processInputs[r, p, t, v] @@ -3700,16 +3704,13 @@ def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): # for S_o in M.processOutputsByInput[r, p, linked_t, v, S_i] # ) - if linked_t in M.tech_demand: + if linked_t in M.tech_annual: linked_flow = sum( - M.DemandSpecificDistribution[r, p, s, d, S_o] - * M.V_FlowOutAnnual[r, p, S_i, linked_t, v, S_o] - for S_i in M.processInputs[r, p, linked_t, v] - for S_o in M.processOutputsByInput[r, p, linked_t, v, S_i] - ) - elif linked_t in M.tech_annual: - linked_flow = sum( - M.SegFrac[p, s, d] + ( + value(M.DemandSpecificDistribution[r, p, s, d, S_o]) + if S_o in M.commodity_demand + else value(M.SegFrac[p, s, d]) + ) * M.V_FlowOutAnnual[r, p, S_i, linked_t, v, S_o] for S_i in M.processInputs[r, p, linked_t, v] for S_o in M.processOutputsByInput[r, p, linked_t, v, S_i] diff --git a/tests/conftest.py b/tests/conftest.py index eefc25cd7..0a42bde20 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -78,6 +78,7 @@ def refresh_databases() -> None: ('simple_linked_tech.sql', 'simple_linked_tech.sqlite'), ('seasonal_storage.sql', 'seasonal_storage.sqlite'), ('survival_curve.sql', 'survival_curve.sqlite'), + ('annualised_demand.sql', 'annualised_demand.sqlite'), ) for src, db in databases: if Path.exists(data_output_path / db): diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index a425b8cab..f859e9703 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -48,12 +48,14 @@ class ExpectedVals(Enum): # increased by 2 when reworking storageinit. # increased after making annualretirement derived var # reduced 2025/07/25 by 504 after annualising demands - ExpectedVals.CONSTR_COUNT: 2330, + # increased 2025/08/19 after making annual demands optional + ExpectedVals.CONSTR_COUNT: 2810, # reduced by 6 when reworking storageinit. # increased after making annualretirement derived var # reduced 2025/07/21 after removing existing vintage V_NewCapacity indices # reduced 2025/07/25 by 420 after annualising demands - ExpectedVals.VAR_COUNT: 1480, + # increased 2025/08/19 after making annual demands optional + ExpectedVals.VAR_COUNT: 1960, }, 'utopia': { # reduced after reworking storageinit -> storage was less constrained @@ -66,13 +68,15 @@ class ExpectedVals(Enum): # reduced 3/27: unlim_cap techs now employed. # increased after making annualretirement derived var # reduced 2025/07/25 by 225 after annualising demands - ExpectedVals.CONSTR_COUNT: 1246, + # increased 2025/08/19 after making annual demands optional + ExpectedVals.CONSTR_COUNT: 1486, # reduced 3/27: unlim_cap techs now employed. # reduced by 4 in storageinit rework. # increased after making annualretirement derived var # reduced 2025/07/21 after removing existing vintage V_NewCapacity indices # reduced 2025/07/25 by 200 after annualising demands - ExpectedVals.VAR_COUNT: 855, + # increased 2025/08/19 after making annual demands optional + ExpectedVals.VAR_COUNT: 1095, }, 'mediumville': { # added 2025/06/12 prior to addition of dynamic reserve margin @@ -82,9 +86,11 @@ class ExpectedVals(Enum): ExpectedVals.EFF_INDEX_SIZE: 18, # increased after reviving RampSeason constraints # reduced 2025/07/25 by 24 after annualising demands - ExpectedVals.CONSTR_COUNT: 216, + # increased 2025/08/19 after making annual demands optional + ExpectedVals.CONSTR_COUNT: 240, # reduced 2025/07/25 by 18 after annualising demands - ExpectedVals.VAR_COUNT: 122, + # increased 2025/08/19 after making annual demands optional + ExpectedVals.VAR_COUNT: 146, }, 'seasonal_storage': { # added 2025/06/16 after addition of seasonal storage @@ -92,9 +98,11 @@ class ExpectedVals(Enum): ExpectedVals.EFF_DOMAIN_SIZE: 24, ExpectedVals.EFF_INDEX_SIZE: 4, # reduced 2025/07/25 by 7 after annualising demands - ExpectedVals.CONSTR_COUNT: 175, + # increased 2025/08/19 after making annual demands optional + ExpectedVals.CONSTR_COUNT: 183, # reduced 2025/07/25 by 7 after annualising demands - ExpectedVals.VAR_COUNT: 83, + # increased 2025/08/19 after making annual demands optional + ExpectedVals.VAR_COUNT: 91, }, 'survival_curve': { # added 2025/06/19 after addition of survival curves @@ -103,8 +111,19 @@ class ExpectedVals(Enum): ExpectedVals.OBJ_VALUE: 31.9423, ExpectedVals.EFF_DOMAIN_SIZE: 64, ExpectedVals.EFF_INDEX_SIZE: 8, - ExpectedVals.CONSTR_COUNT: 101, + ExpectedVals.CONSTR_COUNT: 127, # reduced 2025/07/21 after removing existing vintage V_NewCapacity indices - ExpectedVals.VAR_COUNT: 101, + ExpectedVals.VAR_COUNT: 127, + }, + 'annualised_demand': { + # added 2025/06/19 after addition of survival curves + # reduced after changing fixed costs from MLP to PL + # increased after adding PeriodSurvivalCurve + ExpectedVals.OBJ_VALUE: 1.9524, + ExpectedVals.EFF_DOMAIN_SIZE: 36, + ExpectedVals.EFF_INDEX_SIZE: 10, + ExpectedVals.CONSTR_COUNT: 15, + # reduced 2025/07/21 after removing existing vintage V_NewCapacity indices + ExpectedVals.VAR_COUNT: 21, }, } diff --git a/tests/test_full_runs.py b/tests/test_full_runs.py index 203a2b748..fff865449 100644 --- a/tests/test_full_runs.py +++ b/tests/test_full_runs.py @@ -44,6 +44,7 @@ {'name': 'mediumville', 'filename': 'config_mediumville.toml'}, {'name': 'seasonal_storage', 'filename': 'config_seasonal_storage.toml'}, {'name': 'survival_curve', 'filename': 'config_survival_curve.toml'}, + {'name': 'annualised_demand', 'filename': 'config_annualised_demand.toml'}, ] myopic_files = [{'name': 'myopic utopia', 'filename': 'config_utopia_myopic.toml'}] diff --git a/tests/testing_configs/config_annualised_demand.toml b/tests/testing_configs/config_annualised_demand.toml new file mode 100644 index 000000000..c280d1d58 --- /dev/null +++ b/tests/testing_configs/config_annualised_demand.toml @@ -0,0 +1,77 @@ +# this config is used for testing in test_full_runs.py +scenario = "test run" +scenario_mode = "perfect_foresight" + +input_database = "tests/testing_outputs/annualised_demand.sqlite" +output_database = "tests/testing_outputs/annualised_demand.sqlite" +neos = false + +# solver +solver_name = "cbc" + +# generate an excel file in the output_files folder +save_excel = false + +# save the duals in the output .sqlite database +save_duals = false + +# save a copy of the pyomo-generated lp file to the outputs folder (may be large file!) +save_lp_file = false + +# ------------------------------------ +# MODEL PARAMETERS +# these are specific to each model +# ------------------------------------ + +# What seasons represent in the model +# Options: +# 'consecutive_days' +# Seasons are a set of days in order, with each season representing only one day. Examples +# might be a model of a representative week with 7 days or a whole-year model with 365 days. +# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# 'representative_periods' +# Each season represents a number of days, though not necessarily in any particular order. +# If using inter-season constraints like seasonal storage or ramp rates, the true sequence +# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# the Technology table. +# 'seasonal_timeslices' +# Each season represents a sequential slice of the year, with one or many days represented per +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out +# in the schema). This is an advanced feature and not recommended for most users. Seasonal +# storage must be tagged and the TimeSeasonSequential table filled. +time_sequencing = 'representative_periods' + +# How contributions to the planning reserve margin are calculated +# Options: +# 'static' +# Traditional planning reserve formulation. Contributions are independent of hourly availability: +# capacity value = net capacity * capacity credit +# 'dynamic' +# Contributions are available output including a capacity derate factor (e.g., forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = net capacity * reserve capacity derate * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * reserve capacity derate +reserve_margin = 'static' + +# --------------------------------------------------- +# MODE OPTIONS +# options below are mode-specific and will be ignored +# if the run is not executed in that mode. +# --------------------------------------------------- +[MGA] +cost_epsilon = 0.03 # 3% relaxation on optimal cost +iteration_limit = 15 # max iterations to perform +time_limit_hrs = 1 # max time +axis = "tech_category_activity" # use the tech activity Manager to control exploration based on categories in Tech +weighting = "hull_expansion" # use a convex hull expansion algorithm to weight exploration + +[myopic] +myopic_view = 2 # number of periods seen at one iteration + + + + diff --git a/tests/testing_data/annualised_demand.sql b/tests/testing_data/annualised_demand.sql new file mode 100644 index 000000000..4740e32e8 --- /dev/null +++ b/tests/testing_data/annualised_demand.sql @@ -0,0 +1,1054 @@ +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE MetaData +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); +INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO MetaData VALUES('days_per_period',365,'count of days in each period'); +CREATE TABLE MetaDataReal +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); +CREATE TABLE OutputDualVariable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE OutputObjective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE SeasonLabel +( + season TEXT PRIMARY KEY, + notes TEXT +); +CREATE TABLE SectorLabel +( + sector TEXT PRIMARY KEY, + notes TEXT +); +CREATE TABLE CapacityCredit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + credit REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage), + CHECK (credit >= 0 AND credit <= 1) +); +CREATE TABLE CapacityFactorProcess +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE CapacityFactorTech +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE CapacityToActivity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + c2a REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE Commodity +( + name TEXT + PRIMARY KEY, + flag TEXT + REFERENCES CommodityType (label), + description TEXT +); +INSERT INTO Commodity VALUES('source','s',NULL); +INSERT INTO Commodity VALUES('annual','a',NULL); +INSERT INTO Commodity VALUES('physical','p',NULL); +INSERT INTO Commodity VALUES('demand','d',NULL); +CREATE TABLE CommodityType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO CommodityType VALUES('s','source commodity'); +INSERT INTO CommodityType VALUES('a','annual commodity'); +INSERT INTO CommodityType VALUES('p','physical commodity'); +INSERT INTO CommodityType VALUES('d','demand commodity'); +INSERT INTO CommodityType VALUES('e','emissions commodity'); +INSERT INTO CommodityType VALUES('w','waste commodity'); +INSERT INTO CommodityType VALUES('wa','waste annual commodity'); +INSERT INTO CommodityType VALUES('wp','waste physical commodity'); +CREATE TABLE ConstructionInput +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); +CREATE TABLE CostEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT NOT NULL + REFERENCES Commodity (name), + cost REAL NOT NULL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE CostFixed +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE CostInvest +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +INSERT INTO CostInvest VALUES('region','annual',2000,1.0,NULL,NULL); +INSERT INTO CostInvest VALUES('region','non_annual',2000,1.0,NULL,NULL); +CREATE TABLE CostVariable +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +INSERT INTO CostVariable VALUES('region',2000,'annual',2000,1.0,NULL,NULL); +INSERT INTO CostVariable VALUES('region',2000,'non_annual',2000,1.0,NULL,NULL); +CREATE TABLE Demand +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + commodity TEXT + REFERENCES Commodity (name), + demand REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, commodity) +); +INSERT INTO Demand VALUES('region',2000,'demand',1.0,NULL,NULL); +CREATE TABLE DemandSpecificDistribution +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tod TEXT + REFERENCES TimeOfDay (tod), + demand_name TEXT + REFERENCES Commodity (name), + dsd REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), + CHECK (dsd >= 0 AND dsd <= 1) +); +CREATE TABLE EndOfLifeOutput +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) +); +CREATE TABLE Efficiency +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +INSERT INTO Efficiency VALUES('region','annual','annual',2000,'physical',1.0,NULL); +INSERT INTO Efficiency VALUES('region','annual','annual',2000,'demand',1.0,NULL); +INSERT INTO Efficiency VALUES('region','physical','annual',2000,'demand',1.0,NULL); +INSERT INTO Efficiency VALUES('region','physical','annual',2000,'annual',1.0,NULL); +INSERT INTO Efficiency VALUES('region','source','import',2000,'physical',1.0,NULL); +INSERT INTO Efficiency VALUES('region','source','import',2000,'annual',1.0,NULL); +INSERT INTO Efficiency VALUES('region','annual','non_annual',2000,'physical',1.0,NULL); +INSERT INTO Efficiency VALUES('region','annual','non_annual',2000,'demand',1.0,NULL); +INSERT INTO Efficiency VALUES('region','physical','non_annual',2000,'demand',1.0,NULL); +INSERT INTO Efficiency VALUES('region','physical','non_annual',2000,'annual',1.0,NULL); +CREATE TABLE EfficiencyVariable +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE EmissionActivity +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) +); +CREATE TABLE EmissionEmbodied +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE EmissionEndOfLife +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE ExistingCapacity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE TechGroup +( + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE LoanLifetimeProcess +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +INSERT INTO LoanLifetimeProcess VALUES ('region','annual',2000,1,NULL); +INSERT INTO LoanLifetimeProcess VALUES ('region','non_annual',2000,1,NULL); +CREATE TABLE LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE LifetimeProcess +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE LifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +INSERT INTO LifetimeTech VALUES ('region', 'annual', 1, NULL); +INSERT INTO LifetimeTech VALUES ('region', 'non_annual', 1, NULL); +CREATE TABLE Operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO Operator VALUES('e','equal to'); +INSERT INTO Operator VALUES('le','less than or equal to'); +INSERT INTO Operator VALUES('ge','greater than or equal to'); +CREATE TABLE LimitGrowthCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitDegrowthCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitGrowthNewCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitDegrowthNewCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitGrowthNewCapacityDelta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitDegrowthNewCapacityDelta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitStorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) +); +CREATE TABLE LimitActivity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +INSERT INTO LimitActivity VALUES('region',2000,'annual','le',0.5,NULL,NULL); +INSERT INTO LimitActivity VALUES('region',2000,'non_annual','le',0.5,NULL,NULL); +CREATE TABLE LimitActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE LimitAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, operator), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE LimitCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE LimitCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE LimitNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE LimitNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE LimitResource +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE LimitSeasonalCapacityFactor +( + region TEXT + REFERENCES Region (region), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) +); +CREATE TABLE LimitTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE LimitTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE LimitEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputFlowOut +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); +CREATE TABLE PlanningReserveMargin +( + region TEXT + PRIMARY KEY + REFERENCES Region (region), + margin REAL, + notes TEXT +); +CREATE TABLE RampDownHourly +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE RampUpHourly +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE Region +( + region TEXT + PRIMARY KEY, + notes TEXT +); +INSERT INTO Region VALUES('region',NULL); +CREATE TABLE ReserveCapacityDerate +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE TimeSegmentFraction +( + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tod TEXT + REFERENCES TimeOfDay (tod), + segfrac REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segfrac >= 0 AND segfrac <= 1) +); +INSERT INTO TimeSegmentFraction VALUES(2000,'S1','D1',1.0,NULL); +CREATE TABLE StorageDuration +( + region TEXT, + tech TEXT, + duration REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE LifetimeSurvivalCurve +( + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE TechnologyType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO TechnologyType VALUES('p','production technology'); +INSERT INTO TechnologyType VALUES('pb','baseload production technology'); +INSERT INTO TechnologyType VALUES('ps','storage production technology'); +CREATE TABLE TimeOfDay +( + sequence INTEGER UNIQUE, + tod TEXT + PRIMARY KEY +); +INSERT INTO TimeOfDay VALUES(0,'D1'); +CREATE TABLE TimePeriod +( + sequence INTEGER UNIQUE, + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES TimePeriodType (label) +); +INSERT INTO TimePeriod VALUES(0,2000,'f'); +INSERT INTO TimePeriod VALUES(1,2001,'f'); +CREATE TABLE TimeSeason +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT + REFERENCES SeasonLabel (season), + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +INSERT INTO TimeSeason VALUES(2000,0,'S1',NULL); +CREATE TABLE TimeSeasonSequential +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + seas_seq TEXT, + season TEXT + REFERENCES SeasonLabel (season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) +); +CREATE TABLE TimePeriodType +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO TimePeriodType VALUES('e','existing vintages'); +INSERT INTO TimePeriodType VALUES('f','future'); +CREATE TABLE OutputEmission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE RPSRequirement +( + region TEXT NOT NULL + REFERENCES Region (region), + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech_group TEXT NOT NULL + REFERENCES TechGroup (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE TechGroupMember +( + group_name TEXT + REFERENCES TechGroup (group_name), + tech TEXT + REFERENCES Technology (tech), + PRIMARY KEY (group_name, tech) +); +CREATE TABLE Technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES TechnologyType (label) +); +INSERT INTO Technology VALUES('annual','p','energy',NULL,NULL,0,1,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('import','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO Technology VALUES('non_annual','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +CREATE TABLE OutputCost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES TimePeriod (period), + FOREIGN KEY (tech) REFERENCES Technology (tech) +); +COMMIT; diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 39ad2370d..aa5267582 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -1878,6 +1878,224 @@ "ELC" ] ], + "DemandActivityConstraint_rpsdtv_dem": [ + [ + "B", + 2025, + "s2", + "d2", + "GeoHeater", + 2025, + "RH" + ], + [ + "B", + 2025, + "s1", + "d2", + "heater", + 2025, + "RH" + ], + [ + "B", + 2025, + "s2", + "d1", + "bulbs", + 2025, + "RL" + ], + [ + "B", + 2025, + "s1", + "d1", + "heater", + 2025, + "RH" + ], + [ + "B", + 2025, + "s1", + "d1", + "bulbs", + 2025, + "RL" + ], + [ + "B", + 2025, + "s2", + "d1", + "GeoHeater", + 2025, + "RH" + ], + [ + "A", + 2025, + "s1", + "d2", + "heater", + 2025, + "RH" + ], + [ + "A", + 2025, + "s1", + "d2", + "bulbs", + 2025, + "RL" + ], + [ + "A", + 2025, + "s2", + "d1", + "GeoHeater", + 2025, + "RH" + ], + [ + "A", + 2025, + "s1", + "d1", + "bulbs", + 2025, + "RL" + ], + [ + "A", + 2025, + "s1", + "d2", + "GeoHeater", + 2025, + "RH" + ], + [ + "A", + 2025, + "s2", + "d2", + "heater", + 2025, + "RH" + ], + [ + "B", + 2025, + "s1", + "d2", + "bulbs", + 2025, + "RL" + ], + [ + "B", + 2025, + "s1", + "d2", + "GeoHeater", + 2025, + "RH" + ], + [ + "A", + 2025, + "s2", + "d2", + "bulbs", + 2025, + "RL" + ], + [ + "B", + 2025, + "s2", + "d2", + "heater", + 2025, + "RH" + ], + [ + "A", + 2025, + "s2", + "d2", + "GeoHeater", + 2025, + "RH" + ], + [ + "A", + 2025, + "s1", + "d1", + "GeoHeater", + 2025, + "RH" + ], + [ + "B", + 2025, + "s2", + "d2", + "bulbs", + 2025, + "RL" + ], + [ + "A", + 2025, + "s2", + "d1", + "bulbs", + 2025, + "RL" + ], + [ + "B", + 2025, + "s1", + "d1", + "GeoHeater", + 2025, + "RH" + ], + [ + "A", + 2025, + "s2", + "d1", + "heater", + 2025, + "RH" + ], + [ + "B", + 2025, + "s2", + "d1", + "heater", + 2025, + "RH" + ], + [ + "A", + 2025, + "s1", + "d1", + "heater", + 2025, + "RH" + ] + ], "DemandConstraint_rpc": [ [ "B", @@ -2310,6 +2528,246 @@ ] ], "FlowVar_rpsditvo": [ + [ + "B", + 2025, + "s2", + "d2", + "GeoHyd", + "GeoHeater", + 2025, + "RH" + ], + [ + "A", + 2025, + "s1", + "d2", + "ELC", + "bulbs", + 2025, + "RL" + ], + [ + "A", + 2025, + "s1", + "d1", + "GeoHyd", + "GeoHeater", + 2025, + "RH" + ], + [ + "B", + 2025, + "s2", + "d1", + "ELC", + "bulbs", + 2025, + "RL" + ], + [ + "B", + 2025, + "s2", + "d2", + "FusionGasFuel", + "heater", + 2025, + "RH" + ], + [ + "A", + 2025, + "s1", + "d1", + "FusionGasFuel", + "heater", + 2025, + "RH" + ], + [ + "B", + 2025, + "s1", + "d2", + "GeoHyd", + "GeoHeater", + 2025, + "RH" + ], + [ + "B", + 2025, + "s1", + "d2", + "ELC", + "bulbs", + 2025, + "RL" + ], + [ + "B", + 2025, + "s1", + "d1", + "GeoHyd", + "GeoHeater", + 2025, + "RH" + ], + [ + "B", + 2025, + "s2", + "d2", + "ELC", + "bulbs", + 2025, + "RL" + ], + [ + "A", + 2025, + "s1", + "d1", + "ELC", + "bulbs", + 2025, + "RL" + ], + [ + "A", + 2025, + "s2", + "d1", + "GeoHyd", + "GeoHeater", + 2025, + "RH" + ], + [ + "A", + 2025, + "s2", + "d2", + "GeoHyd", + "GeoHeater", + 2025, + "RH" + ], + [ + "A", + 2025, + "s2", + "d2", + "ELC", + "bulbs", + 2025, + "RL" + ], + [ + "A", + 2025, + "s1", + "d2", + "GeoHyd", + "GeoHeater", + 2025, + "RH" + ], + [ + "B", + 2025, + "s1", + "d2", + "FusionGasFuel", + "heater", + 2025, + "RH" + ], + [ + "A", + 2025, + "s2", + "d1", + "FusionGasFuel", + "heater", + 2025, + "RH" + ], + [ + "B", + 2025, + "s2", + "d1", + "FusionGasFuel", + "heater", + 2025, + "RH" + ], + [ + "A", + 2025, + "s2", + "d1", + "ELC", + "bulbs", + 2025, + "RL" + ], + [ + "B", + 2025, + "s2", + "d1", + "GeoHyd", + "GeoHeater", + 2025, + "RH" + ], + [ + "B", + 2025, + "s1", + "d1", + "FusionGasFuel", + "heater", + 2025, + "RH" + ], + [ + "A", + 2025, + "s1", + "d2", + "FusionGasFuel", + "heater", + 2025, + "RH" + ], + [ + "B", + 2025, + "s1", + "d1", + "ELC", + "bulbs", + 2025, + "RL" + ], + [ + "A", + 2025, + "s2", + "d2", + "FusionGasFuel", + "heater", + 2025, + "RH" + ], [ "A", 2025, @@ -3748,9 +4206,6 @@ "batt" ], "tech_annual": [ - "bulbs", - "heater", - "GeoHeater", "GeoThermal" ], "tech_demand": [ diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index fc75245de..4e03ab73a 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -19722,472 +19722,9370 @@ "GSL" ] ], - "DemandConstraint_rpc": [ + "DemandActivityConstraint_rpsdtv_dem": [ [ - "R1", + "R2", 2030, - "RH" - ], - [ - "R1", - 2025, - "RH" - ], - [ - "R1", + "summer", + "night", + "T_EV", 2030, "VMT" ], - [ - "R1", - 2025, - "VMT" - ], [ "R2", 2020, - "RH" + "winter", + "night", + "T_GSL", + 2020, + "VMT" ], [ "R1", + 2030, + "fall", + "day", + "T_GSL", 2020, "VMT" ], [ "R2", 2030, - "RH" + "winter", + "night", + "T_DSL", + 2030, + "VMT" ], [ - "R2", + "R1", 2025, + "spring", + "day", + "R_NGH", + 2020, "RH" ], [ - "R2", + "R1", + 2025, + "fall", + "night", + "T_GSL", 2020, "VMT" ], [ "R2", 2025, + "fall", + "day", + "T_EV", + 2025, "VMT" ], [ - "R2", - 2030, + "R1", + 2025, + "summer", + "day", + "T_GSL", + 2020, "VMT" ], [ - "R1", + "R2", + 2030, + "summer", + "day", + "R_NGH", 2020, "RH" - ] - ], - "EmissionActivity_reitvo": [ - [ - "R1", - "CO2", - "ethos", - "S_IMPNG", - 2020, - "NG" ], [ - "R2", - "CO2", - "SOL", - "E_SOLPV", - 2020, - "ELC" + "R1", + 2030, + "spring", + "night", + "T_GSL", + 2025, + "VMT" ], [ - "R2", - "CO2", - "NG", - "R_NGH", + "R1", 2030, + "summer", + "day", + "R_EH", + 2025, "RH" ], [ - "R1", - "CO2", - "ethos", - "S_IMPOIL", + "R2", 2020, - "OIL" + "fall", + "night", + "T_GSL", + 2020, + "VMT" ], [ - "R2", - "CO2", - "NG", - "E_NGCC", + "R1", 2025, - "ELC" + "winter", + "day", + "T_GSL", + 2025, + "VMT" ], [ "R1", - "CO2", - "URN", - "E_NUCLEAR", 2020, - "ELC" + "fall", + "night", + "R_EH", + 2020, + "RH" ], [ "R2", - "CO2", - "OIL", - "S_OILREF", - 2020, - "DSL" + 2030, + "winter", + "night", + "T_EV", + 2025, + "VMT" ], [ "R1", - "CO2", - "ETH", - "T_BLND", 2020, - "E10" + "spring", + "night", + "R_NGH", + 2020, + "RH" ], [ "R2", - "CO2", - "ELC", - "E_BATT", 2030, - "ELC" - ], - [ - "R2", - "CO2", - "OIL", - "S_OILREF", + "spring", + "night", + "T_EV", 2020, - "GSL" + "VMT" ], [ - "R2", - "CO2", - "NG", - "E_NGCC", - 2020, - "ELC" + "R1", + 2030, + "summer", + "day", + "T_GSL", + 2025, + "VMT" ], [ "R1", - "CO2", - "NG", - "E_NGCC", - 2020, - "ELC" + 2025, + "summer", + "night", + "R_EH", + 2025, + "RH" ], [ "R2", - "CO2", - "ELC", - "T_EV", - 2030, + 2025, + "summer", + "night", + "T_DSL", + 2020, "VMT" ], [ "R2", - "CO2", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - "CO2", - "ELC", - "E_BATT", 2030, - "ELC" + "fall", + "night", + "R_EH", + 2025, + "RH" ], [ "R1", - "CO2", - "NG", + 2030, + "summer", + "night", "R_NGH", 2025, "RH" ], [ "R2", - "CO2", - "DSL", + 2030, + "fall", + "day", "T_DSL", 2020, "VMT" ], [ - "R1", - "CO2", - "ELC", + "R2", + 2030, + "fall", + "night", "T_EV", 2030, "VMT" ], [ - "R1", - "CO2", - "DSL", - "T_DSL", - 2030, + "R2", + 2025, + "spring", + "night", + "T_EV", + 2020, "VMT" ], [ "R2", - "CO2", - "ETH", - "T_BLND", 2020, - "E10" + "summer", + "day", + "T_DSL", + 2020, + "VMT" ], [ - "R2", - "CO2", - "URN", - "E_NUCLEAR", - 2015, - "ELC" + "R1", + 2025, + "fall", + "day", + "T_GSL", + 2020, + "VMT" ], [ "R2", - "CO2", - "NG", + 2030, + "fall", + "day", "R_NGH", - 2025, + 2020, "RH" ], [ - "R2", - "CO2", - "E10", - "T_GSL", + "R1", 2030, + "spring", + "day", + "T_EV", + 2025, "VMT" ], [ - "R1", - "CO2", - "GSL", - "T_BLND", + "R2", 2020, - "E10" + "fall", + "day", + "T_EV", + 2020, + "VMT" ], [ "R1", - "CO2", - "URN", - "E_NUCLEAR", - 2015, - "ELC" + 2020, + "summer", + "day", + "T_DSL", + 2020, + "VMT" ], [ - "R2", - "CO2", - "SOL", - "E_SOLPV", - 2030, - "ELC" + "R1", + 2020, + "summer", + "night", + "T_GSL", + 2020, + "VMT" ], [ "R1", - "CO2", - "E10", + 2025, + "spring", + "night", "T_GSL", - 2030, + 2025, "VMT" ], [ "R1", - "CO2", - "URN", - "E_NUCLEAR", - 2030, - "ELC" + 2025, + "winter", + "night", + "T_GSL", + 2020, + "VMT" ], [ "R1", - "CO2", - "SOL", - "E_SOLPV", - 2030, - "ELC" + 2020, + "spring", + "day", + "T_GSL", + 2020, + "VMT" ], [ "R2", - "CO2", - "ELC", - "E_BATT", - 2025, - "ELC" + 2020, + "spring", + "night", + "R_EH", + 2020, + "RH" ], [ - "R2", - "CO2", - "NG", - "R_NGH", + "R1", + 2030, + "fall", + "day", + "R_EH", 2020, "RH" ], [ "R2", - "CO2", - "ELC", - "T_EV", - 2025, + 2030, + "spring", + "day", + "T_GSL", + 2020, "VMT" ], [ - "R1", - "CO2", - "ELC", - "E_BATT", - 2025, - "ELC" + "R2", + 2030, + "fall", + "night", + "R_NGH", + 2030, + "RH" ], [ "R1", - "CO2", - "E10", + 2030, + "winter", + "night", "T_GSL", - 2025, + 2030, "VMT" ], [ "R1", - "CO2", - "NG", - "R_NGH", - 2020, - "RH" + 2030, + "fall", + "day", + "T_EV", + 2025, + "VMT" ], [ - "R1", - "CO2", - "ELC", + "R2", + 2025, + "winter", + "night", "T_EV", 2025, "VMT" ], [ "R1", - "CO2", - "ELC", - "R_EH", 2030, - "RH" + "fall", + "night", + "T_DSL", + 2020, + "VMT" ], [ "R1", - "CO2", - "DSL", + 2025, + "summer", + "night", "T_DSL", 2025, "VMT" ], [ "R2", - "CO2", - "URN", - "E_NUCLEAR", 2030, - "ELC" - ], - [ - "R2", - "CO2", - "DSL", - "T_DSL", + "fall", + "day", + "T_GSL", 2030, "VMT" ], [ - "R2", - "CO2", - "E10", - "T_GSL", + "R1", + 2030, + "summer", + "day", + "T_EV", 2025, "VMT" ], [ "R2", - "CO2", - "ELC", + 2020, + "fall", + "night", "R_EH", - 2030, + 2020, "RH" ], [ - "R2", - "CO2", - "SOL", - "E_SOLPV", + "R1", 2025, - "ELC" + "winter", + "night", + "T_DSL", + 2020, + "VMT" ], [ "R2", - "CO2", - "ethos", - "S_IMPNG", + 2030, + "winter", + "day", + "R_NGH", 2020, - "NG" + "RH" ], [ "R1", - "CO2", - "ELC", + 2030, + "winter", + "day", "T_EV", - 2020, + 2030, "VMT" ], [ "R1", - "CO2", - "URN", - "E_NUCLEAR", - 2025, - "ELC" + 2020, + "winter", + "day", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "R_NGH", + 2030, + "RH" ], [ "R1", - "CO2", - "SOL", - "E_SOLPV", 2025, - "ELC" + "summer", + "night", + "T_EV", + 2020, + "VMT" ], [ "R1", - "CO2", - "NG", + 2030, + "fall", + "day", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "summer", + "day", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "winter", + "day", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "day", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "winter", + "day", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "spring", + "night", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "day", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "winter", + "night", + "R_NGH", + 2030, + "RH" + ], + [ + "R1", + 2025, + "spring", + "night", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "summer", + "night", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "day", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "spring", + "night", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "day", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "day", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "spring", + "night", + "T_EV", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "night", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "winter", + "night", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "spring", + "day", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2020, + "winter", + "day", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "day", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "night", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "spring", + "night", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "summer", + "day", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "spring", + "night", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "day", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "winter", + "day", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "winter", + "night", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "spring", + "day", + "R_NGH", + 2030, + "RH" + ], + [ + "R1", + 2030, + "winter", + "day", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2020, + "fall", + "night", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "night", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "night", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "winter", + "night", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "spring", + "day", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "fall", + "night", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "summer", + "night", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "spring", + "day", + "T_GSL", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "summer", + "night", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "night", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "summer", + "night", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "day", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "night", + "R_EH", + 2030, + "RH" + ], + [ + "R1", + 2020, + "winter", + "night", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "day", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "night", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "night", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_DSL", + 2030, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "night", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "winter", + "night", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "day", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "spring", + "night", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "winter", + "night", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "night", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "day", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "day", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "fall", + "day", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "day", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "day", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "day", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2020, + "winter", + "night", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "fall", + "night", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "day", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2020, + "summer", + "night", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "winter", + "night", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "night", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "winter", + "day", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "spring", + "night", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "fall", + "day", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "fall", + "night", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "day", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "summer", + "day", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2020, + "fall", + "night", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "winter", + "day", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "day", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "night", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "spring", + "night", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "day", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "day", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "spring", + "night", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2020, + "summer", + "day", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "winter", + "day", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "night", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_EV", + 2030, + "VMT" + ], + [ + "R2", + 2020, + "winter", + "day", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "night", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "day", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "fall", + "night", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "spring", + "day", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "winter", + "day", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2020, + "fall", + "day", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "night", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "winter", + "day", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "spring", + "day", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2020, + "winter", + "night", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "spring", + "day", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "winter", + "night", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "fall", + "day", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "day", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_DSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "night", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "winter", + "night", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "night", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "night", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "spring", + "day", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_GSL", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "summer", + "day", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "night", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_EV", + 2030, + "VMT" + ], + [ + "R2", + 2020, + "winter", + "day", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "day", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "winter", + "day", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "winter", + "day", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "fall", + "day", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "day", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "day", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "day", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "winter", + "night", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "night", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "spring", + "night", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2020, + "summer", + "night", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "winter", + "night", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + 2025, + "fall", + "day", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "day", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "fall", + "day", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "summer", + "day", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "night", + "T_GSL", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "night", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "fall", + "night", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "spring", + "day", + "T_DSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "night", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "night", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "day", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "spring", + "day", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "fall", + "day", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "day", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2020, + "spring", + "day", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "spring", + "day", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "spring", + "day", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "winter", + "day", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "day", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "fall", + "day", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "night", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "fall", + "day", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "fall", + "night", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "fall", + "day", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "spring", + "day", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "day", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "day", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "summer", + "day", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2020, + "winter", + "night", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "night", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2020, + "summer", + "night", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "winter", + "night", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "night", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2020, + "winter", + "day", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "fall", + "day", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "day", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "day", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "T_DSL", + 2030, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "day", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "summer", + "day", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "day", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + 2025, + "winter", + "day", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "day", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "summer", + "night", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "winter", + "night", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "winter", + "day", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "day", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "spring", + "day", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "night", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "spring", + "night", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "summer", + "night", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "night", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "winter", + "night", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2020, + "spring", + "night", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "summer", + "night", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "night", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2025, + "spring", + "night", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "summer", + "day", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "day", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "summer", + "day", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "summer", + "day", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "day", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "winter", + "night", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "night", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "night", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2020, + "spring", + "night", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "day", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "night", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2020, + "spring", + "day", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "spring", + "day", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "night", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "day", + "T_DSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "night", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "night", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "fall", + "day", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "night", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "spring", + "day", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "R_NGH", + 2030, + "RH" + ], + [ + "R1", + 2025, + "spring", + "day", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "winter", + "day", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "winter", + "night", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "summer", + "day", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "winter", + "day", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "night", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "night", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "winter", + "day", + "R_EH", + 2030, + "RH" + ], + [ + "R1", + 2025, + "spring", + "day", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "spring", + "night", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "spring", + "night", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "night", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "summer", + "night", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "spring", + "day", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "night", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "summer", + "night", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "T_DSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "day", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "summer", + "day", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "spring", + "night", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "day", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2025, + "fall", + "night", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "T_EV", + 2030, + "VMT" + ], + [ + "R2", + 2025, + "summer", + "night", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "summer", + "night", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "night", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "winter", + "day", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "day", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "summer", + "night", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "day", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "day", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "day", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "winter", + "night", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "night", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "winter", + "night", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "fall", + "night", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "spring", + "night", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "night", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "summer", + "day", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "day", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2020, + "spring", + "day", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "day", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "fall", + "day", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "night", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "night", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "spring", + "day", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "spring", + "day", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_GSL", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_EV", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2020, + "spring", + "night", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "day", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "fall", + "day", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "fall", + "day", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "summer", + "night", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "day", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "fall", + "night", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "night", + "T_DSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "night", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "night", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "fall", + "night", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "day", + "R_NGH", + 2030, + "RH" + ], + [ + "R1", + 2025, + "fall", + "day", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "night", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2020, + "fall", + "night", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2020, + "spring", + "day", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "winter", + "night", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "day", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "fall", + "day", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "night", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "summer", + "day", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "day", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "day", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "fall", + "night", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "winter", + "day", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + 2025, + "spring", + "night", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "spring", + "night", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2020, + "summer", + "night", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "fall", + "day", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "day", + "R_EH", + 2030, + "RH" + ], + [ + "R1", + 2030, + "summer", + "day", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + 2025, + "summer", + "day", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "summer", + "day", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + 2025, + "summer", + "night", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "summer", + "day", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "winter", + "day", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "fall", + "day", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "day", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "fall", + "night", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "summer", + "day", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "night", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "fall", + "night", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "winter", + "day", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2020, + "summer", + "day", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "spring", + "night", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "day", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "summer", + "night", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "summer", + "day", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "fall", + "day", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "night", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "day", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "night", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "night", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2020, + "winter", + "night", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "day", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "day", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "fall", + "day", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "day", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "fall", + "night", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "day", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "night", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "day", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "spring", + "night", + "T_GSL", + 2030, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "night", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "winter", + "night", + "T_EV", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "spring", + "night", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "summer", + "night", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "R_EH", + 2030, + "RH" + ], + [ + "R1", + 2030, + "summer", + "night", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "fall", + "day", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "night", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "fall", + "day", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "day", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "night", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "night", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "spring", + "day", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "fall", + "day", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2020, + "winter", + "night", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "day", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "night", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "R_EH", + 2030, + "RH" + ], + [ + "R1", + 2025, + "winter", + "night", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "day", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "day", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "summer", + "day", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "day", + "T_EV", + 2030, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "day", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "spring", + "day", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "summer", + "day", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "fall", + "night", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "summer", + "day", + "T_EV", + 2030, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "night", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "day", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "winter", + "day", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "R_NGH", + 2030, + "RH" + ], + [ + "R1", + 2030, + "fall", + "night", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "night", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "day", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "winter", + "day", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "summer", + "night", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "day", + "T_DSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "day", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "winter", + "day", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "spring", + "night", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "night", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "spring", + "night", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "fall", + "day", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "spring", + "night", + "R_EH", + 2030, + "RH" + ] + ], + "DemandConstraint_rpc": [ + [ + "R1", + 2030, + "RH" + ], + [ + "R1", + 2025, + "RH" + ], + [ + "R1", + 2030, + "VMT" + ], + [ + "R1", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "RH" + ], + [ + "R1", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "RH" + ], + [ + "R2", + 2025, + "RH" + ], + [ + "R2", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "VMT" + ], + [ + "R1", + 2020, + "RH" + ] + ], + "EmissionActivity_reitvo": [ + [ + "R1", + "CO2", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R2", + "CO2", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R2", + "CO2", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R1", + "CO2", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + "CO2", + "NG", + "E_NGCC", + 2025, + "ELC" + ], + [ + "R1", + "CO2", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R2", + "CO2", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + "CO2", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + "CO2", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + "CO2", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + "CO2", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R1", + "CO2", + "NG", + "E_NGCC", + 2020, + "ELC" + ], + [ + "R2", + "CO2", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R2", + "CO2", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + "CO2", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R1", + "CO2", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + "CO2", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + "CO2", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + "CO2", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + "CO2", + "ETH", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + "CO2", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", + "CO2", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + "CO2", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + "CO2", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R1", + "CO2", + "URN", + "E_NUCLEAR", + 2015, + "ELC" + ], + [ + "R2", + "CO2", + "SOL", + "E_SOLPV", + 2030, + "ELC" + ], + [ + "R1", + "CO2", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + "CO2", + "URN", + "E_NUCLEAR", + 2030, + "ELC" + ], + [ + "R1", + "CO2", + "SOL", + "E_SOLPV", + 2030, + "ELC" + ], + [ + "R2", + "CO2", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + "CO2", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + "CO2", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + "CO2", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + "CO2", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + "CO2", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + "CO2", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + "CO2", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R1", + "CO2", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + "CO2", + "URN", + "E_NUCLEAR", + 2030, + "ELC" + ], + [ + "R2", + "CO2", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + "CO2", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + "CO2", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + "CO2", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R2", + "CO2", + "ethos", + "S_IMPNG", + 2020, + "NG" + ], + [ + "R1", + "CO2", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + "CO2", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R1", + "CO2", + "SOL", + "E_SOLPV", + 2025, + "ELC" + ], + [ + "R1", + "CO2", + "NG", + "E_NGCC", + 2030, + "ELC" + ], + [ + "R2", + "CO2", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + "CO2", + "ethos", + "S_IMPOIL", + 2020, + "OIL" + ], + [ + "R2", + "CO2", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + "CO2", + "OIL", + "S_OILREF", + 2020, + "DSL" + ], + [ + "R1", + "CO2", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + "CO2", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + "CO2", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + "CO2", + "OIL", + "S_OILREF", + 2020, + "GSL" + ], + [ + "R2", + "CO2", + "URN", + "E_NUCLEAR", + 2025, + "ELC" + ], + [ + "R1", + "CO2", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + "CO2", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + "CO2", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + "CO2", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + "CO2", + "GSL", + "T_BLND", + 2020, + "E10" + ], + [ + "R2", + "CO2", + "NG", + "E_NGCC", + 2030, + "ELC" + ], + [ + "R2", + "CO2", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R2", + "CO2", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + "CO2", + "ethos", + "S_IMPETH", + 2020, + "ETH" + ], + [ + "R1", + "CO2", + "ethos", + "S_IMPURN", + 2020, + "URN" + ], + [ + "R1", + "CO2", + "SOL", + "E_SOLPV", + 2020, + "ELC" + ], + [ + "R1", + "CO2", + "NG", "E_NGCC", + 2025, + "ELC" + ], + [ + "R2", + "CO2", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + "CO2", + "URN", + "E_NUCLEAR", + 2020, + "ELC" + ], + [ + "R1", + "CO2", + "ELC", + "R_EH", + 2020, + "RH" + ] + ], + "FlexVarAnnual_rpitvo": [], + "FlexVar_rpsditvo": [], + "FlowInStorage_rpsditvo": [ + [ + "R2", + 2030, + "summer", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2020, + "winter", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R1", + 2020, + "winter", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "summer", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "winter", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "winter", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "fall", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2020, + "summer", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2020, + "spring", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2020, + "winter", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "winter", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2025, + "summer", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "summer", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2020, + "fall", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "fall", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2020, + "fall", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2020, + "spring", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "winter", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "winter", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "spring", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "fall", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2020, + "spring", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "spring", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "summer", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2020, + "spring", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "summer", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2025, + "winter", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "spring", + "day", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "winter", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2030, + "winter", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R1", + 2020, + "summer", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "fall", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2025, + "fall", + "night", + "ELC", + "E_BATT", + 2025, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R1", + 2030, + "summer", + "day", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "spring", + "night", + "ELC", + "E_BATT", + 2020, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "night", + "ELC", + "E_BATT", + 2030, + "ELC" + ], + [ + "R2", + 2030, + "fall", + "day", + "ELC", + "E_BATT", + 2025, + "ELC" + ] + ], + "FlowVarAnnual_rpitvo": [ + [ + "R1", + 2030, + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2020, + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + 2025, + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2025, + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2020, + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + 2025, + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2020, + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2020, + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "E10", + "T_GSL", + 2030, + "VMT" + ] + ], + "FlowVar_rpsditvo": [ + [ + "R1", + 2020, + "spring", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "summer", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "summer", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "winter", + "day", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R1", + 2030, + "spring", + "night", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2020, + "winter", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2020, + "spring", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "winter", + "day", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + 2020, + "spring", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "summer", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "summer", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "night", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "summer", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "fall", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "spring", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "winter", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "fall", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "spring", + "night", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "spring", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "winter", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2020, + "winter", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "summer", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "summer", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "fall", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "summer", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "winter", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R1", + 2025, + "winter", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "summer", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "fall", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "spring", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "summer", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "summer", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "summer", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2020, + "spring", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "spring", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "winter", + "night", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "night", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "day", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "fall", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "summer", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "winter", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "winter", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "fall", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "winter", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2020, + "winter", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "summer", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "day", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "fall", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "winter", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "day", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R1", + 2030, + "fall", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "spring", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "fall", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "spring", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "fall", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2020, + "summer", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "winter", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "fall", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "fall", + "night", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "winter", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "winter", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "summer", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "summer", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "winter", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "fall", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "spring", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2020, + "fall", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "winter", + "night", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R1", + 2025, + "winter", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "fall", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "spring", + "day", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "night", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "winter", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "summer", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "winter", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "summer", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "winter", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "summer", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "fall", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "winter", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "fall", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "day", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R1", + 2030, + "spring", + "day", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R1", + 2030, + "fall", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "winter", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "winter", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "spring", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "fall", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "summer", + "day", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "winter", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "fall", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "winter", + "day", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R1", + 2030, + "summer", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R1", + 2030, + "fall", + "day", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "spring", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2020, + "summer", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2020, + "fall", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "spring", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "winter", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "spring", + "day", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + 2020, + "fall", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "fall", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "winter", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "night", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "fall", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "summer", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "fall", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "day", + "ELC", + "T_EV", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "summer", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "spring", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "fall", + "night", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "night", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R1", + 2025, + "winter", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "winter", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "summer", + "night", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2020, + "spring", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "fall", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "night", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "winter", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "summer", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "summer", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "summer", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2025, + "spring", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2020, + "spring", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "summer", + "night", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "winter", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "day", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R1", + 2030, + "fall", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "day", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "spring", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "fall", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "winter", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2030, + "spring", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "day", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "fall", + "day", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R1", + 2030, + "summer", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2020, + "spring", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "night", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "fall", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "summer", + "night", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "spring", + "day", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2020, + "fall", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R1", + 2020, + "summer", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "fall", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "day", + "ELC", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "day", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "night", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "spring", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "summer", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", + 2020, + "winter", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "summer", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R2", 2030, - "ELC" + "spring", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "fall", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "day", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "night", + "ELC", + "R_EH", + 2025, + "RH" + ], + [ + "R2", + 2020, + "spring", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "winter", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "summer", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2020, + "spring", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "night", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "winter", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "winter", + "night", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R2", + 2025, + "winter", + "day", + "ELC", + "T_EV", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "summer", + "day", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2030, + "winter", + "night", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R2", + 2020, + "summer", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R2", + 2025, + "summer", + "day", + "E10", + "T_GSL", + 2020, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "spring", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2030, + "fall", + "day", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "winter", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" ], [ - "R2", - "CO2", + "R1", + 2030, + "spring", + "day", "ELC", - "E_BATT", + "T_EV", 2020, - "ELC" + "VMT" + ], + [ + "R1", + 2030, + "spring", + "day", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R1", + 2030, + "spring", + "night", + "NG", + "R_NGH", + 2030, + "RH" ], [ "R2", - "CO2", - "ethos", - "S_IMPOIL", 2020, - "OIL" + "winter", + "night", + "E10", + "T_GSL", + 2020, + "VMT" ], [ "R2", - "CO2", + 2025, + "spring", + "day", "ELC", "T_EV", 2020, @@ -20195,151 +29093,259 @@ ], [ "R1", - "CO2", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - "CO2", + 2030, + "summer", + "night", "ELC", - "E_BATT", - 2020, - "ELC" + "T_EV", + 2030, + "VMT" ], [ "R2", - "CO2", + 2025, + "summer", + "day", "ELC", "R_EH", - 2025, + 2020, "RH" ], [ - "R1", - "CO2", + "R2", + 2030, + "winter", + "day", "E10", "T_GSL", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "night", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "night", + "DSL", + "T_DSL", 2020, "VMT" ], [ "R1", - "CO2", - "OIL", - "S_OILREF", + 2030, + "winter", + "day", + "E10", + "T_GSL", 2020, - "GSL" + "VMT" ], [ "R2", - "CO2", - "URN", - "E_NUCLEAR", + 2030, + "summer", + "day", + "ELC", + "R_EH", 2025, - "ELC" + "RH" ], [ "R1", - "CO2", - "ELC", - "R_EH", 2025, - "RH" + "summer", + "day", + "E10", + "T_GSL", + 2025, + "VMT" ], [ "R1", - "CO2", + 2030, + "summer", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R2", + 2025, + "winter", + "night", "DSL", "T_DSL", 2020, "VMT" ], [ - "R1", - "CO2", + "R2", + 2030, + "winter", + "day", "NG", "R_NGH", 2030, "RH" ], [ - "R2", - "CO2", - "DSL", - "T_DSL", + "R1", 2025, + "spring", + "night", + "ELC", + "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2020, + "fall", + "day", + "ELC", + "T_EV", + 2020, "VMT" ], [ "R2", - "CO2", - "GSL", - "T_BLND", + 2030, + "spring", + "day", + "ELC", + "T_EV", 2020, - "E10" + "VMT" ], [ "R2", - "CO2", - "NG", - "E_NGCC", 2030, - "ELC" + "summer", + "day", + "E10", + "T_GSL", + 2030, + "VMT" ], [ - "R2", - "CO2", - "ethos", - "S_IMPETH", + "R1", 2020, - "ETH" + "fall", + "day", + "ELC", + "R_EH", + 2020, + "RH" ], [ "R2", - "CO2", + 2030, + "winter", + "night", + "E10", + "T_GSL", + 2030, + "VMT" + ], + [ + "R1", + 2030, + "spring", + "night", + "ELC", + "R_EH", + 2030, + "RH" + ], + [ + "R2", + 2030, + "spring", + "night", "E10", "T_GSL", 2020, "VMT" ], + [ + "R2", + 2020, + "summer", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], [ "R1", - "CO2", - "ethos", - "S_IMPETH", + 2030, + "winter", + "night", + "ELC", + "T_EV", 2020, - "ETH" + "VMT" + ], + [ + "R1", + 2030, + "summer", + "day", + "ELC", + "R_EH", + 2030, + "RH" ], [ - "R1", - "CO2", - "ethos", - "S_IMPURN", + "R2", + 2025, + "fall", + "night", + "NG", + "R_NGH", 2020, - "URN" + "RH" ], [ "R1", - "CO2", - "SOL", - "E_SOLPV", + 2030, + "summer", + "night", + "NG", + "R_NGH", 2020, - "ELC" + "RH" ], [ - "R1", - "CO2", - "NG", - "E_NGCC", + "R2", 2025, - "ELC" + "winter", + "day", + "E10", + "T_GSL", + 2025, + "VMT" ], [ - "R2", - "CO2", + "R1", + 2030, + "spring", + "day", "ELC", "R_EH", 2020, @@ -20347,183 +29353,213 @@ ], [ "R2", - "CO2", - "URN", - "E_NUCLEAR", 2020, - "ELC" - ], - [ - "R1", - "CO2", + "winter", + "night", "ELC", "R_EH", 2020, "RH" - ] - ], - "FlexVarAnnual_rpitvo": [], - "FlexVar_rpsditvo": [], - "FlowInStorage_rpsditvo": [ + ], [ - "R2", + "R1", 2030, "summer", "night", "ELC", - "E_BATT", - 2025, - "ELC" + "R_EH", + 2030, + "RH" ], [ - "R1", + "R2", 2025, - "fall", - "day", + "spring", + "night", "ELC", - "E_BATT", + "R_EH", 2020, - "ELC" + "RH" ], [ "R1", - 2025, - "summer", - "night", + 2020, + "spring", + "day", "ELC", - "E_BATT", + "R_EH", 2020, - "ELC" + "RH" ], [ - "R1", + "R2", 2030, - "spring", + "winter", "day", "ELC", - "E_BATT", + "T_EV", 2020, - "ELC" + "VMT" ], [ - "R2", + "R1", 2030, "summer", "day", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R1", + 2025, + "spring", + "day", "ELC", - "E_BATT", + "T_EV", 2025, - "ELC" + "VMT" ], [ "R2", + 2030, + "spring", + "day", + "NG", + "R_NGH", 2020, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" + "RH" ], [ "R1", 2025, - "spring", + "summer", + "day", + "NG", + "R_NGH", + 2025, + "RH" + ], + [ + "R1", + 2030, + "fall", "night", - "ELC", - "E_BATT", + "DSL", + "T_DSL", 2020, - "ELC" + "VMT" ], [ "R1", 2030, - "summer", - "night", + "winter", + "day", "ELC", - "E_BATT", + "R_EH", 2020, - "ELC" + "RH" ], [ - "R2", + "R1", 2025, "fall", "night", "ELC", - "E_BATT", + "T_EV", 2025, - "ELC" + "VMT" ], [ - "R2", + "R1", 2025, "spring", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" + "day", + "DSL", + "T_DSL", + 2020, + "VMT" ], [ - "R2", + "R1", 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" + "spring", + "day", + "E10", + "T_GSL", + 2025, + "VMT" ], [ "R2", 2030, - "fall", + "summer", "day", "ELC", - "E_BATT", + "T_EV", 2030, - "ELC" + "VMT" ], [ "R1", - 2020, + 2030, "winter", - "day", + "night", "ELC", - "E_BATT", + "R_EH", 2020, - "ELC" + "RH" ], [ - "R1", - 2020, - "summer", + "R2", + 2030, + "spring", "night", "ELC", - "E_BATT", + "R_EH", 2020, - "ELC" + "RH" ], [ "R1", + 2030, + "fall", + "day", + "NG", + "R_NGH", 2020, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" + "RH" ], [ "R1", - 2025, + 2030, "spring", "day", - "ELC", - "E_BATT", - 2025, - "ELC" + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "fall", + "day", + "DSL", + "T_DSL", + 2030, + "VMT" + ], + [ + "R2", + 2030, + "winter", + "day", + "DSL", + "T_DSL", + 2020, + "VMT" ], [ "R1", @@ -20531,269 +29567,259 @@ "winter", "night", "ELC", - "E_BATT", - 2020, - "ELC" + "T_EV", + 2025, + "VMT" ], [ - "R2", + "R1", 2020, - "fall", + "winter", "day", "ELC", - "E_BATT", + "T_EV", 2020, - "ELC" + "VMT" ], [ - "R1", + "R2", + 2025, + "spring", + "night", + "DSL", + "T_DSL", 2025, + "VMT" + ], + [ + "R2", + 2030, "fall", "day", - "ELC", - "E_BATT", + "NG", + "R_NGH", 2025, - "ELC" + "RH" ], [ "R2", - 2020, + 2030, "summer", - "day", + "night", "ELC", - "E_BATT", - 2020, - "ELC" + "T_EV", + 2030, + "VMT" ], [ "R2", - 2025, - "spring", + 2030, + "summer", "day", "ELC", - "E_BATT", + "T_EV", 2020, - "ELC" + "VMT" ], [ "R1", - 2030, - "fall", + 2020, + "summer", "night", - "ELC", - "E_BATT", - 2030, - "ELC" + "E10", + "T_GSL", + 2020, + "VMT" ], [ "R2", 2020, - "spring", + "fall", "night", "ELC", - "E_BATT", + "R_EH", 2020, - "ELC" + "RH" ], [ "R2", - 2025, + 2020, "fall", "day", - "ELC", - "E_BATT", + "NG", + "R_NGH", 2020, - "ELC" + "RH" ], [ "R1", 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" + "winter", + "night", + "NG", + "R_NGH", + 2025, + "RH" ], [ - "R2", - 2025, - "winter", + "R1", + 2020, + "spring", "day", "ELC", - "E_BATT", + "T_EV", 2020, - "ELC" + "VMT" ], [ "R2", - 2025, + 2030, "summer", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" + "day", + "NG", + "R_NGH", + 2030, + "RH" ], [ "R1", - 2030, - "winter", + 2020, + "summer", "day", "ELC", - "E_BATT", - 2030, - "ELC" + "T_EV", + 2020, + "VMT" ], [ "R2", - 2030, + 2025, "spring", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" + "day", + "DSL", + "T_DSL", + 2020, + "VMT" ], [ - "R2", + "R1", 2025, - "summer", + "fall", "day", - "ELC", - "E_BATT", - 2025, - "ELC" + "E10", + "T_GSL", + 2020, + "VMT" ], [ "R1", - 2030, - "spring", + 2025, + "winter", "night", - "ELC", - "E_BATT", - 2020, - "ELC" + "NG", + "R_NGH", + 2025, + "RH" ], [ "R2", 2030, "spring", "day", - "ELC", - "E_BATT", - 2030, - "ELC" + "E10", + "T_GSL", + 2025, + "VMT" ], [ - "R2", + "R1", 2030, - "winter", + "fall", "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" + "E10", + "T_GSL", + 2025, + "VMT" ], [ "R1", 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "summer", + "spring", "day", - "ELC", - "E_BATT", + "NG", + "R_NGH", 2025, - "ELC" + "RH" ], [ "R1", 2030, - "summer", - "day", - "ELC", - "E_BATT", + "spring", + "night", + "NG", + "R_NGH", 2025, - "ELC" + "RH" ], [ - "R2", + "R1", 2020, "winter", "day", - "ELC", - "E_BATT", + "NG", + "R_NGH", 2020, - "ELC" + "RH" ], [ - "R2", + "R1", 2030, - "spring", + "summer", "night", "ELC", - "E_BATT", + "T_EV", 2025, - "ELC" + "VMT" ], [ "R1", - 2030, - "winter", - "day", + 2020, + "summer", + "night", "ELC", - "E_BATT", + "T_EV", 2020, - "ELC" + "VMT" ], [ "R1", - 2030, - "fall", + 2020, + "winter", "day", "ELC", - "E_BATT", - 2025, - "ELC" + "R_EH", + 2020, + "RH" ], [ - "R1", - 2025, - "winter", - "day", - "ELC", - "E_BATT", + "R2", + 2030, + "summer", + "night", + "DSL", + "T_DSL", 2020, - "ELC" + "VMT" ], [ "R2", 2025, - "winter", - "day", - "ELC", - "E_BATT", + "fall", + "night", + "DSL", + "T_DSL", 2025, - "ELC" + "VMT" ], [ "R2", @@ -20801,339 +29827,299 @@ "summer", "night", "ELC", - "E_BATT", + "R_EH", 2030, - "ELC" + "RH" ], [ "R2", 2030, - "winter", + "summer", "day", "ELC", - "E_BATT", + "R_EH", 2020, - "ELC" + "RH" + ], + [ + "R2", + 2030, + "fall", + "night", + "E10", + "T_GSL", + 2030, + "VMT" ], [ "R2", 2025, "spring", "day", - "ELC", - "E_BATT", + "E10", + "T_GSL", 2025, - "ELC" + "VMT" ], [ "R1", - 2025, - "summer", + 2030, + "fall", "night", "ELC", - "E_BATT", - 2025, - "ELC" + "T_EV", + 2030, + "VMT" ], [ "R1", 2025, "summer", "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "E_BATT", + "E10", + "T_GSL", 2020, - "ELC" + "VMT" ], [ "R2", 2020, - "summer", + "fall", "night", - "ELC", - "E_BATT", + "DSL", + "T_DSL", 2020, - "ELC" + "VMT" ], [ "R2", - 2020, - "fall", + 2025, + "summer", "night", "ELC", - "E_BATT", - 2020, - "ELC" + "R_EH", + 2025, + "RH" ], [ "R1", - 2020, + 2030, "fall", "day", "ELC", - "E_BATT", - 2020, - "ELC" + "R_EH", + 2030, + "RH" ], [ "R1", - 2020, + 2025, "fall", "night", - "ELC", - "E_BATT", - 2020, - "ELC" + "NG", + "R_NGH", + 2025, + "RH" ], [ "R2", 2030, - "summer", + "winter", "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "ELC", - "E_BATT", + "NG", + "R_NGH", 2025, - "ELC" + "RH" ], [ "R1", 2030, "summer", "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "day", - "ELC", - "E_BATT", + "DSL", + "T_DSL", 2020, - "ELC" + "VMT" ], [ "R2", 2030, "fall", - "night", + "day", "ELC", - "E_BATT", - 2025, - "ELC" + "T_EV", + 2030, + "VMT" ], [ "R2", 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "winter", + "summer", "day", - "ELC", - "E_BATT", + "E10", + "T_GSL", 2025, - "ELC" + "VMT" ], [ "R2", 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" + "spring", + "night", + "NG", + "R_NGH", + 2030, + "RH" ], [ - "R1", - 2025, + "R2", + 2030, "winter", "night", - "ELC", - "E_BATT", + "E10", + "T_GSL", 2025, - "ELC" + "VMT" ], [ - "R2", + "R1", 2025, - "fall", + "summer", "night", "ELC", - "E_BATT", - 2020, - "ELC" + "T_EV", + 2025, + "VMT" ], [ "R1", 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2025, "spring", "night", "ELC", - "E_BATT", - 2020, - "ELC" + "R_EH", + 2025, + "RH" ], [ "R2", 2025, - "winter", + "summer", "night", - "ELC", - "E_BATT", - 2020, - "ELC" + "DSL", + "T_DSL", + 2025, + "VMT" ], [ - "R2", - 2025, - "fall", + "R1", + 2030, + "summer", "day", "ELC", - "E_BATT", + "R_EH", 2025, - "ELC" + "RH" ], [ "R1", 2020, - "spring", + "summer", "night", - "ELC", - "E_BATT", + "NG", + "R_NGH", 2020, - "ELC" + "RH" ], [ - "R1", - 2030, - "spring", - "night", - "ELC", - "E_BATT", + "R2", 2025, - "ELC" + "winter", + "day", + "E10", + "T_GSL", + 2020, + "VMT" ], [ - "R2", + "R1", 2030, - "winter", + "summer", "night", "ELC", - "E_BATT", - 2020, - "ELC" + "R_EH", + 2025, + "RH" ], [ - "R1", + "R2", 2025, - "spring", + "winter", "day", - "ELC", - "E_BATT", - 2020, - "ELC" + "NG", + "R_NGH", + 2025, + "RH" ], [ "R2", 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" + "spring", + "day", + "DSL", + "T_DSL", + 2030, + "VMT" ], [ "R1", - 2025, + 2030, "fall", "night", - "ELC", - "E_BATT", - 2020, - "ELC" + "NG", + "R_NGH", + 2030, + "RH" ], [ "R1", 2030, - "fall", + "winter", "night", - "ELC", - "E_BATT", + "E10", + "T_GSL", 2025, - "ELC" + "VMT" ], [ - "R1", + "R2", + 2025, + "fall", + "day", + "E10", + "T_GSL", + 2025, + "VMT" + ], + [ + "R2", 2030, "summer", "day", - "ELC", - "E_BATT", + "DSL", + "T_DSL", 2030, - "ELC" + "VMT" ], [ - "R2", + "R1", 2020, - "spring", + "winter", "day", - "ELC", - "E_BATT", + "E10", + "T_GSL", 2020, - "ELC" + "VMT" ], [ "R2", @@ -21141,243 +30127,305 @@ "summer", "night", "ELC", - "E_BATT", + "T_EV", + 2025, + "VMT" + ], + [ + "R1", 2020, - "ELC" + "fall", + "night", + "NG", + "R_NGH", + 2020, + "RH" ], [ "R1", 2030, - "winter", + "spring", "day", - "ELC", - "E_BATT", - 2025, - "ELC" + "E10", + "T_GSL", + 2020, + "VMT" ], [ - "R1", + "R2", 2030, - "fall", + "summer", "day", "ELC", - "E_BATT", - 2030, - "ELC" + "T_EV", + 2025, + "VMT" ], [ "R2", 2025, - "summer", + "winter", "day", "ELC", - "E_BATT", - 2020, - "ELC" + "R_EH", + 2025, + "RH" ], [ "R2", 2030, + "fall", + "night", + "NG", + "R_NGH", + 2030, + "RH" + ], + [ + "R1", + 2030, "spring", "day", - "ELC", - "E_BATT", + "DSL", + "T_DSL", 2025, - "ELC" + "VMT" ], [ "R2", 2030, - "winter", + "fall", "day", - "ELC", - "E_BATT", + "DSL", + "T_DSL", 2025, - "ELC" + "VMT" ], [ "R1", - 2030, + 2020, "spring", "night", - "ELC", - "E_BATT", - 2030, - "ELC" + "E10", + "T_GSL", + 2020, + "VMT" ], [ - "R2", + "R1", 2025, "winter", "night", "ELC", - "E_BATT", - 2025, - "ELC" + "T_EV", + 2020, + "VMT" ], [ - "R1", + "R2", 2030, - "spring", - "day", - "ELC", - "E_BATT", + "winter", + "night", + "DSL", + "T_DSL", 2030, - "ELC" + "VMT" ], [ "R2", - 2030, - "winter", + 2025, + "spring", + "night", + "DSL", + "T_DSL", + 2020, + "VMT" + ], + [ + "R2", + 2025, + "spring", "night", "ELC", - "E_BATT", + "T_EV", 2025, - "ELC" + "VMT" ], [ - "R1", + "R2", 2030, - "winter", + "fall", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "summer", "night", "ELC", - "E_BATT", + "T_EV", 2025, - "ELC" + "VMT" ], [ "R1", 2020, - "summer", - "day", + "spring", + "night", "ELC", - "E_BATT", + "T_EV", 2020, - "ELC" + "VMT" ], [ "R1", - 2030, - "fall", + 2020, + "winter", "night", "ELC", - "E_BATT", + "T_EV", 2020, - "ELC" + "VMT" ], [ "R1", 2025, - "fall", + "spring", "night", - "ELC", - "E_BATT", + "DSL", + "T_DSL", 2025, - "ELC" + "VMT" ], [ - "R2", + "R1", 2030, - "spring", - "day", - "ELC", - "E_BATT", + "winter", + "night", + "NG", + "R_NGH", 2020, - "ELC" + "RH" ], [ "R1", - 2030, + 2020, "summer", - "day", - "ELC", - "E_BATT", + "night", + "DSL", + "T_DSL", 2020, - "ELC" + "VMT" ], [ "R2", 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" + "summer", + "day", + "NG", + "R_NGH", + 2025, + "RH" ], [ "R2", 2030, - "fall", + "winter", "night", "ELC", - "E_BATT", + "T_EV", 2030, - "ELC" + "VMT" ], [ "R2", - 2030, - "fall", + 2020, + "winter", "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ] - ], - "FlowVarAnnual_rpitvo": [ + "DSL", + "T_DSL", + 2020, + "VMT" + ], [ - "R1", + "R2", 2030, + "summer", + "night", "NG", "R_NGH", 2030, "RH" ], [ - "R2", - 2020, - "ELC", - "T_EV", + "R1", + 2025, + "winter", + "night", + "NG", + "R_NGH", 2020, - "VMT" + "RH" ], [ - "R2", - 2025, - "E10", - "T_GSL", - 2020, + "R1", + 2030, + "winter", + "day", + "ELC", + "T_EV", + 2030, "VMT" ], [ "R1", - 2025, + 2030, + "fall", + "day", "E10", "T_GSL", 2020, "VMT" ], [ - "R1", + "R2", 2020, + "fall", + "day", "ELC", "R_EH", 2020, "RH" ], [ - "R2", - 2030, - "DSL", - "T_DSL", + "R1", 2025, + "spring", + "day", + "ELC", + "T_EV", + 2020, "VMT" ], [ - "R2", + "R1", + 2030, + "spring", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R1", 2025, + "summer", + "night", "ELC", "R_EH", 2025, @@ -21386,158 +30434,188 @@ [ "R2", 2030, - "ELC", - "T_EV", - 2020, + "summer", + "night", + "E10", + "T_GSL", + 2030, "VMT" ], [ - "R2", - 2025, + "R1", + 2030, + "summer", + "day", "NG", "R_NGH", - 2025, + 2020, "RH" ], [ "R1", - 2030, - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "ELC", - "R_EH", + 2025, + "summer", + "day", + "NG", + "R_NGH", 2020, "RH" ], [ "R1", 2030, + "fall", + "night", "ELC", - "T_EV", - 2025, - "VMT" + "R_EH", + 2030, + "RH" ], [ "R1", 2030, + "summer", + "day", "E10", "T_GSL", - 2025, + 2030, "VMT" ], [ "R2", - 2030, - "E10", - "T_GSL", 2025, + "fall", + "night", + "DSL", + "T_DSL", + 2020, "VMT" ], [ "R2", 2030, + "summer", + "night", "ELC", "R_EH", - 2030, + 2025, "RH" ], [ "R2", + 2030, + "fall", + "night", + "E10", + "T_GSL", 2025, - "ELC", - "R_EH", - 2020, - "RH" + "VMT" ], [ "R2", - 2030, - "DSL", - "T_DSL", + 2025, + "spring", + "day", + "E10", + "T_GSL", 2020, "VMT" ], [ "R1", - 2020, + 2030, + "fall", + "night", "ELC", "T_EV", - 2020, + 2025, "VMT" ], [ - "R1", + "R2", 2020, - "E10", - "T_GSL", + "winter", + "day", + "ELC", + "T_EV", 2020, "VMT" ], [ "R2", - 2030, - "NG", - "R_NGH", - 2030, + 2025, + "summer", + "night", + "ELC", + "R_EH", + 2020, "RH" ], [ - "R2", - 2025, + "R1", + 2030, + "fall", + "day", "ELC", - "T_EV", + "R_EH", 2025, - "VMT" + "RH" ], [ "R2", 2025, + "summer", + "day", "NG", "R_NGH", 2020, "RH" ], [ - "R1", + "R2", 2030, - "DSL", - "T_DSL", + "winter", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "fall", + "day", + "ELC", + "T_EV", 2025, "VMT" ], [ - "R1", + "R2", 2030, - "NG", - "R_NGH", - 2025, - "RH" + "summer", + "day", + "E10", + "T_GSL", + 2020, + "VMT" ], [ "R1", - 2020, + 2030, + "winter", + "day", "NG", "R_NGH", - 2020, + 2030, "RH" ], [ - "R1", - 2025, - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, + "R2", + 2030, + "spring", + "night", "NG", "R_NGH", 2025, @@ -21545,7 +30623,9 @@ ], [ "R1", - 2030, + 2025, + "summer", + "night", "ELC", "T_EV", 2020, @@ -21554,78 +30634,128 @@ [ "R2", 2030, + "winter", + "night", "E10", "T_GSL", 2020, "VMT" ], [ - "R1", - 2030, + "R2", + 2025, + "summer", + "night", "DSL", "T_DSL", 2020, "VMT" ], [ - "R2", + "R1", 2030, + "summer", + "day", "ELC", "R_EH", + 2020, + "RH" + ], + [ + "R1", + 2025, + "spring", + "day", + "NG", + "R_NGH", 2025, "RH" ], [ "R1", 2025, + "fall", + "day", "ELC", "R_EH", 2025, "RH" ], + [ + "R2", + 2020, + "spring", + "night", + "NG", + "R_NGH", + 2020, + "RH" + ], [ "R2", 2030, - "ELC", - "T_EV", - 2030, + "spring", + "day", + "E10", + "T_GSL", + 2020, "VMT" ], [ "R1", - 2025, - "ELC", - "T_EV", - 2025, + 2020, + "fall", + "day", + "E10", + "T_GSL", + 2020, "VMT" ], [ "R2", 2025, + "winter", + "day", + "NG", + "R_NGH", + 2020, + "RH" + ], + [ + "R2", + 2030, + "spring", + "day", "DSL", "T_DSL", 2025, "VMT" ], [ - "R2", + "R1", 2030, + "fall", + "night", "NG", "R_NGH", 2025, "RH" ], [ - "R2", - 2025, - "ELC", - "T_EV", + "R1", + 2030, + "winter", + "night", + "E10", + "T_GSL", 2020, "VMT" ], [ "R2", - 2020, + 2025, + "fall", + "day", "E10", "T_GSL", 2020, @@ -21633,31 +30763,69 @@ ], [ "R1", - 2030, + 2025, + "fall", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R2", + 2025, + "winter", + "night", "E10", "T_GSL", + 2025, + "VMT" + ], + [ + "R2", + 2030, + "summer", + "day", + "DSL", + "T_DSL", + 2025, + "VMT" + ], + [ + "R1", + 2025, + "fall", + "night", + "ELC", + "T_EV", 2020, "VMT" ], [ "R1", 2030, + "spring", + "day", "NG", "R_NGH", 2020, "RH" ], [ - "R1", + "R2", 2025, - "DSL", - "T_DSL", - 2020, - "VMT" + "spring", + "day", + "NG", + "R_NGH", + 2025, + "RH" ], [ "R1", - 2025, + 2020, + "spring", + "day", "NG", "R_NGH", 2020, @@ -21666,14 +30834,18 @@ [ "R1", 2025, + "spring", + "day", "E10", "T_GSL", 2025, "VMT" ], [ - "R1", + "R2", 2030, + "winter", + "day", "ELC", "R_EH", 2030, @@ -21682,94 +30854,58 @@ [ "R2", 2030, - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2030, + "winter", + "night", "ELC", "R_EH", - 2020, + 2030, "RH" ], [ - "R1", + "R2", 2025, + "winter", + "day", "ELC", "R_EH", 2020, "RH" ], - [ - "R1", - 2030, - "ELC", - "T_EV", - 2030, - "VMT" - ], [ "R2", 2030, - "ELC", - "T_EV", + "fall", + "night", + "NG", + "R_NGH", 2025, - "VMT" - ], - [ - "R2", - 2020, - "ELC", - "R_EH", - 2020, "RH" ], [ "R2", - 2025, - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, + 2030, + "fall", + "day", "DSL", "T_DSL", 2020, "VMT" ], - [ - "R2", - 2030, - "NG", - "R_NGH", - 2020, - "RH" - ], [ "R2", 2020, - "DSL", - "T_DSL", + "fall", + "day", + "E10", + "T_GSL", 2020, "VMT" ], [ "R1", - 2030, - "ELC", - "R_EH", 2025, - "RH" - ], - [ - "R2", - 2020, + "fall", + "night", "NG", "R_NGH", 2020, @@ -21777,38 +30913,24 @@ ], [ "R2", - 2025, - "E10", - "T_GSL", + 2030, + "winter", + "night", + "DSL", + "T_DSL", 2025, "VMT" ], [ "R1", - 2025, + 2020, + "fall", + "night", "ELC", - "T_EV", + "R_EH", 2020, - "VMT" - ], - [ - "R1", - 2030, - "E10", - "T_GSL", - 2030, - "VMT" + "RH" ], - [ - "R2", - 2030, - "E10", - "T_GSL", - 2030, - "VMT" - ] - ], - "FlowVar_rpsditvo": [ [ "R2", 2020, @@ -36093,13 +45215,7 @@ "E_NUCLEAR", "T_DSL" ], - "tech_annual": [ - "T_EV", - "R_NGH", - "T_GSL", - "R_EH", - "T_DSL" - ], + "tech_annual": [], "tech_demand": [ "T_EV", "R_NGH", diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 218c3658e..17fdf0a70 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -10243,898 +10243,5416 @@ "RH" ] ], - "EmissionActivity_reitvo": [ + "DemandActivityConstraint_rpsdtv_dem": [ [ "utopia", - "co2", - "DSL", - "RHO", 2000, - "RH" + "summer", + "night", + "TXG", + 1990, + "TX" ], [ "utopia", - "co2", - "ethos", - "IMPHYD", 1990, - "HYD" + "inter", + "night", + "RL1", + 1990, + "RL" ], [ "utopia", - "co2", - "HCO", - "E01", + 2000, + "summer", + "day", + "RHO", 1980, - "ELC" + "RH" ], [ "utopia", - "nox", - "HCO", - "E01", - 1960, - "ELC" + 2000, + "summer", + "day", + "TXD", + 2000, + "TX" ], [ "utopia", - "co2", - "ELC", - "E51", 2010, - "ELC" - ], - [ - "utopia", - "nox", - "ELC", - "RL1", - 1980, - "RL" + "summer", + "day", + "TXG", + 2000, + "TX" ], [ "utopia", - "co2", - "URN", - "E21", 2000, - "ELC" + "winter", + "day", + "RHE", + 2000, + "RH" ], [ "utopia", - "co2", - "ethos", - "IMPDSL1", 1990, - "DSL" + "winter", + "night", + "TXE", + 1990, + "TX" ], [ "utopia", - "nox", - "ELC", + 1990, + "summer", + "night", "RL1", - 2010, + 1980, "RL" ], [ "utopia", - "co2", - "ethos", - "IMPHCO1", + 2000, + "summer", + "night", + "TXE", 1990, - "HCO" + "TX" ], [ "utopia", - "nox", - "OIL", - "SRE", + 2000, + "summer", + "day", + "TXG", 1990, - "GSL" + "TX" ], [ "utopia", - "nox", - "DSL", - "E70", - 1980, - "ELC" + 2010, + "winter", + "night", + "TXG", + 2000, + "TX" ], [ "utopia", - "co2", - "DSL", + 2010, + "winter", + "day", + "TXE", + 2010, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "night", "RHO", 1990, "RH" ], [ "utopia", - "co2", - "OIL", - "SRE", - 2010, - "DSL" + 2000, + "inter", + "day", + "RHO", + 2000, + "RH" ], [ "utopia", - "co2", - "HCO", - "E01", + 1990, + "winter", + "day", + "TXG", 1970, - "ELC" + "TX" ], [ "utopia", - "nox", - "URN", - "E21", 2010, - "ELC" + "summer", + "night", + "TXG", + 2000, + "TX" ], [ "utopia", - "co2", - "OIL", - "SRE", 2010, - "GSL" + "inter", + "night", + "RHE", + 2000, + "RH" ], [ "utopia", - "co2", - "URN", - "E21", - 1990, - "ELC" + 2000, + "summer", + "night", + "TXD", + 1980, + "TX" ], [ "utopia", - "co2", - "GSL", - "TXG", - 1980, - "TX" + 2010, + "inter", + "day", + "RHO", + 2000, + "RH" ], [ "utopia", - "nox", - "ELC", - "E51", 1990, - "ELC" + "inter", + "night", + "TXD", + 1980, + "TX" ], [ "utopia", - "nox", - "ELC", - "TXE", 2000, + "winter", + "night", + "TXG", + 1990, "TX" ], [ "utopia", - "co2", - "DSL", + 2010, + "winter", + "night", "TXD", - 1990, + 2010, "TX" ], [ "utopia", - "nox", - "DSL", - "E70", - 1970, - "ELC" + 1990, + "summer", + "night", + "TXD", + 1980, + "TX" ], [ "utopia", - "co2", - "DSL", - "RHO", - 1980, - "RH" + 2010, + "summer", + "night", + "TXD", + 2010, + "TX" ], [ "utopia", - "co2", - "HYD", - "E31", + 2010, + "summer", + "night", + "TXE", 2000, - "ELC" + "TX" ], [ "utopia", - "nox", - "ethos", - "IMPFEQ", - 1990, - "FEQ" + 2000, + "inter", + "night", + "RHO", + 1980, + "RH" ], [ "utopia", - "nox", - "DSL", + 1990, + "winter", + "day", "RHO", 1990, "RH" ], [ "utopia", - "co2", - "ELC", - "RHE", - 2010, - "RH" + 1990, + "summer", + "day", + "RL1", + 1980, + "RL" ], [ "utopia", - "nox", - "OIL", - "SRE", - 2010, - "DSL" + 2000, + "winter", + "day", + "TXD", + 2000, + "TX" ], [ "utopia", - "nox", - "URN", - "E21", 2000, - "ELC" + "inter", + "day", + "RL1", + 2000, + "RL" ], [ "utopia", - "nox", - "OIL", - "SRE", - 2010, - "GSL" + 2000, + "summer", + "night", + "RHE", + 1990, + "RH" ], [ "utopia", - "nox", - "GSL", - "TXG", + 2000, + "winter", + "night", + "TXE", 1990, "TX" ], [ "utopia", - "co2", - "DSL", - "E70", - 2010, - "ELC" + 2000, + "winter", + "night", + "TXD", + 2000, + "TX" ], [ "utopia", - "co2", - "GSL", - "TXG", + 1990, + "winter", + "day", + "TXD", 1970, "TX" ], [ "utopia", - "nox", - "FEQ", - "E21", - 1990, - "ELC" + 2010, + "inter", + "day", + "RHE", + 2000, + "RH" ], [ "utopia", - "co2", - "ELC", - "TXE", - 2010, + 1990, + "inter", + "day", + "TXG", + 1980, "TX" ], [ "utopia", - "nox", - "ELC", - "E51", - 1980, - "ELC" + 2010, + "winter", + "day", + "RHE", + 2010, + "RH" ], [ "utopia", - "nox", - "ELC", - "TXE", - 1990, - "TX" + 2010, + "inter", + "night", + "RHO", + 2010, + "RH" ], [ "utopia", - "nox", - "ethos", - "IMPGSL1", 1990, - "GSL" + "inter", + "night", + "RL1", + 1980, + "RL" ], [ "utopia", - "co2", - "DSL", + 1990, + "winter", + "night", "TXD", 1980, "TX" ], [ "utopia", - "nox", - "DSL", - "TXD", 1990, - "TX" + "summer", + "night", + "RHE", + 1990, + "RH" ], [ "utopia", - "nox", - "HCO", - "E01", 1990, - "ELC" + "summer", + "night", + "RHO", + 1990, + "RH" ], [ "utopia", - "co2", - "ELC", - "RL1", - 1990, - "RL" + 2000, + "summer", + "day", + "TXG", + 1980, + "TX" ], [ "utopia", - "nox", - "HYD", - "E31", 2010, - "ELC" + "winter", + "night", + "RHO", + 2010, + "RH" ], [ "utopia", - "co2", - "FEQ", - "E21", + 2010, + "winter", + "day", + "TXE", 2000, - "ELC" + "TX" ], [ "utopia", - "nox", - "DSL", - "RHO", - 1980, + 2000, + "inter", + "day", + "RHE", + 2000, "RH" ], [ "utopia", - "nox", - "ethos", - "IMPURN1", - 1990, - "URN" + 2000, + "summer", + "night", + "RHO", + 2000, + "RH" ], [ "utopia", - "nox", - "OIL", - "SRE", - 2000, - "DSL" + 2010, + "inter", + "night", + "RL1", + 2010, + "RL" ], [ "utopia", - "co2", - "GSL", + 2000, + "inter", + "day", "TXG", 2000, "TX" ], [ "utopia", - "nox", - "ELC", - "RHE", - 2010, - "RH" + 1990, + "inter", + "day", + "TXD", + 1970, + "TX" ], [ "utopia", - "nox", - "OIL", - "SRE", 2000, - "GSL" + "winter", + "night", + "TXG", + 1980, + "TX" ], [ "utopia", - "nox", - "GSL", + 2010, + "inter", + "day", "TXG", - 1980, + 2000, "TX" ], [ "utopia", - "co2", - "DSL", - "E70", 2000, - "ELC" + "inter", + "night", + "TXE", + 1990, + "TX" ], [ "utopia", - "nox", - "ELC", - "E51", - 2010, - "ELC" + 1990, + "summer", + "night", + "TXD", + 1970, + "TX" ], [ "utopia", - "nox", - "DSL", - "E70", 2010, - "ELC" - ], + "inter", + "night", + "TXG", + 2000, + "TX" + ], [ "utopia", - "co2", - "HCO", - "E01", 2000, - "ELC" + "winter", + "day", + "TXD", + 1990, + "TX" ], [ "utopia", - "nox", - "DSL", + 2000, + "inter", + "night", "TXD", 1980, "TX" ], [ "utopia", - "nox", - "HCO", - "E01", - 1980, - "ELC" + 2010, + "inter", + "night", + "TXE", + 2010, + "TX" ], [ "utopia", - "nox", - "ELC", - "RL1", - 2000, - "RL" + 1990, + "winter", + "day", + "TXG", + 1990, + "TX" ], [ "utopia", - "co2", - "HCO", - "E01", - 1960, - "ELC" + 2010, + "inter", + "day", + "TXD", + 2010, + "TX" ], [ "utopia", - "co2", - "ELC", - "RL1", - 1980, - "RL" + 2010, + "inter", + "day", + "TXE", + 2000, + "TX" ], [ "utopia", - "co2", - "ethos", - "IMPFEQ", 1990, - "FEQ" + "inter", + "day", + "TXG", + 1970, + "TX" ], [ "utopia", - "nox", - "ELC", - "E51", + 2010, + "winter", + "day", + "RHE", 2000, - "ELC" + "RH" ], [ "utopia", - "co2", - "GSL", - "TXG", 1990, + "winter", + "night", + "TXD", + 1970, "TX" ], [ "utopia", - "nox", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - "co2", - "OIL", - "SRE", 2000, - "DSL" + "inter", + "day", + "TXD", + 2000, + "TX" ], [ "utopia", - "nox", - "DSL", - "E70", - 2000, - "ELC" + 1990, + "summer", + "day", + "TXD", + 1970, + "TX" ], [ "utopia", - "co2", - "OIL", - "SRE", - 2000, - "GSL" + 1990, + "winter", + "night", + "TXG", + 1980, + "TX" ], [ "utopia", - "co2", - "DSL", + 1990, + "inter", + "night", "RHO", - 2010, + 1990, "RH" ], [ "utopia", - "co2", - "ethos", - "IMPGSL1", 1990, - "GSL" + "summer", + "night", + "RHO", + 1980, + "RH" ], [ "utopia", - "nox", - "HCO", - "E01", 2010, - "ELC" + "summer", + "day", + "RHO", + 2000, + "RH" ], [ "utopia", - "co2", - "DSL", - "E70", - 1970, - "ELC" + 2010, + "summer", + "day", + "RHE", + 1990, + "RH" ], [ "utopia", - "co2", - "HCO", - "E01", - 1990, - "ELC" + 2010, + "winter", + "night", + "RHO", + 2000, + "RH" ], [ "utopia", - "co2", - "ELC", - "RL1", - 2010, - "RL" + 2000, + "winter", + "day", + "RHO", + 2000, + "RH" ], [ "utopia", - "nox", - "DSL", - "TXD", - 1970, + 1990, + "summer", + "night", + "TXG", + 1990, "TX" ], [ "utopia", - "nox", - "HCO", - "E01", - 1970, - "ELC" + 2000, + "summer", + "night", + "TXD", + 2000, + "TX" ], [ "utopia", - "co2", - "URN", - "E21", - 2010, - "ELC" + 1990, + "winter", + "day", + "TXD", + 1990, + "TX" ], [ "utopia", - "nox", - "ELC", - "RL1", + 2010, + "summer", + "night", + "RHE", 1990, - "RL" + "RH" ], [ "utopia", - "nox", - "URN", - "E21", 1990, - "ELC" + "winter", + "night", + "RHO", + 1980, + "RH" ], [ "utopia", - "co2", - "ethos", - "IMPURN1", + 2000, + "inter", + "day", + "TXG", 1990, - "URN" + "TX" ], [ "utopia", - "co2", - "ELC", - "TXE", 2000, - "TX" + "summer", + "day", + "RL1", + 2000, + "RL" ], [ "utopia", - "co2", - "DSL", - "RHO", - 1970, + 2000, + "winter", + "night", + "RHO", + 1980, "RH" ], [ "utopia", - "co2", - "ELC", - "E51", 2000, - "ELC" + "summer", + "day", + "TXG", + 2000, + "TX" ], [ "utopia", - "co2", - "HYD", - "E31", 1990, - "ELC" + "inter", + "day", + "RHE", + 1990, + "RH" ], [ "utopia", - "nox", - "ethos", - "IMPOIL1", - 1990, - "OIL" + 2000, + "winter", + "day", + "TXD", + 1980, + "TX" ], [ "utopia", - "co2", - "DSL", - "TXD", - 2010, + 1990, + "winter", + "day", + "TXG", + 1980, "TX" ], [ "utopia", - "co2", - "OIL", - "SRE", 1990, - "DSL" + "winter", + "night", + "RL1", + 1980, + "RL" ], [ "utopia", - "co2", - "ELC", - "RHE", 2000, - "RH" + "winter", + "night", + "RL1", + 2000, + "RL" ], [ "utopia", - "co2", - "OIL", - "SRE", - 1990, - "GSL" + 2000, + "summer", + "day", + "TXE", + 2000, + "TX" ], [ "utopia", - "nox", - "DSL", - "RHO", 2010, - "RH" + "winter", + "day", + "TXG", + 2010, + "TX" ], [ "utopia", - "nox", - "FEQ", - "E21", - 2010, - "ELC" + 1990, + "inter", + "day", + "RHO", + 1970, + "RH" ], [ "utopia", - "co2", - "FEQ", - "E21", 1990, - "ELC" + "winter", + "night", + "TXG", + 1970, + "TX" ], [ "utopia", - "nox", - "HCO", - "E01", 2000, - "ELC" + "summer", + "night", + "TXG", + 1980, + "TX" ], [ "utopia", - "co2", - "DSL", - "E70", - 1960, - "ELC" + 2010, + "summer", + "night", + "RL1", + 2010, + "RL" ], [ "utopia", - "co2", - "GSL", + 1990, + "inter", + "night", "TXG", - 2010, + 1980, "TX" ], [ "utopia", - "co2", - "ELC", + 2010, + "winter", + "night", + "RHE", + 2010, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "day", "RL1", 2000, "RL" ], [ "utopia", - "nox", - "GSL", - "TXG", - 2010, - "TX" + 2000, + "winter", + "day", + "RHO", + 1990, + "RH" ], [ "utopia", - "co2", - "DSL", - "TXD", - 1970, + 1990, + "summer", + "night", + "TXG", + 1980, "TX" ], [ "utopia", - "nox", - "GSL", + 2010, + "summer", + "night", "TXG", - 1970, + 2010, "TX" ], [ "utopia", - "nox", - "ELC", + 2000, + "winter", + "night", "TXE", - 2010, + 2000, "TX" ], [ "utopia", - "nox", - "HYD", - "E31", - 2000, - "ELC" + 1990, + "winter", + "day", + "TXD", + 1980, + "TX" ], [ "utopia", - "co2", - "ELC", + 1990, + "summer", + "day", "TXE", 1990, "TX" ], [ "utopia", - "co2", - "ELC", - "E51", 1990, - "ELC" + "inter", + "day", + "TXD", + 1990, + "TX" ], [ "utopia", - "co2", - "HYD", - "E31", - 1980, - "ELC" + 2000, + "winter", + "day", + "TXG", + 2000, + "TX" ], [ "utopia", - "nox", - "DSL", + 1990, + "summer", + "day", "RHO", 1970, "RH" ], [ "utopia", - "co2", - "DSL", + 1990, + "summer", + "day", "TXD", - 2000, + 1990, "TX" ], [ "utopia", - "nox", - "ethos", - "IMPDSL1", + 2000, + "inter", + "day", + "RHO", 1990, - "DSL" + "RH" ], [ "utopia", - "nox", - "DSL", - "TXD", + 2010, + "summer", + "night", + "TXE", 2010, "TX" ], [ "utopia", - "co2", - "ELC", + 2010, + "inter", + "day", "RHE", 1990, "RH" ], [ "utopia", - "nox", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - "nox", - "ELC", + 2000, + "summer", + "day", + "RHE", + 2000, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + 2010, + "inter", + "night", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + 2010, + "inter", + "day", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 1990, + "winter", + "day", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "winter", + "night", + "RL1", + 2010, + "RL" + ], + [ + "utopia", + 1990, + "inter", + "day", + "RL1", + 1990, + "RL" + ], + [ + "utopia", + 1990, + "winter", + "night", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXG", + 1970, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "night", + "RHE", + 2000, + "RH" + ], + [ + "utopia", + 2010, + "winter", + "night", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "night", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + 1990, + "summer", + "day", + "RL1", + 1990, + "RL" + ], + [ + "utopia", + 2000, + "summer", + "night", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "winter", + "day", + "RHO", + 2010, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "night", + "RL1", + 2000, + "RL" + ], + [ + "utopia", + 2010, + "inter", + "night", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + 2010, + "winter", + "night", + "TXE", + 2010, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "night", + "RHE", + 2010, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "night", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + 1990, + "summer", + "night", + "TXG", + 1970, + "TX" + ], + [ + "utopia", + 2010, + "inter", + "night", + "TXD", + 2010, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "night", + "RHO", + 2010, + "RH" + ], + [ + "utopia", + 1990, + "inter", + "day", + "TXD", + 1980, + "TX" + ], + [ + "utopia", + 2000, + "winter", + "night", "RHE", 2000, - "RH" + "RH" + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXD", + 1980, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + 2010, + "inter", + "day", + "TXG", + 2010, + "TX" + ], + [ + "utopia", + 2010, + "inter", + "night", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "day", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + 2010, + "inter", + "night", + "TXG", + 2010, + "TX" + ], + [ + "utopia", + 1990, + "inter", + "day", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXG", + 1970, + "TX" + ], + [ + "utopia", + 2000, + "summer", + "day", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "summer", + "day", + "RL1", + 2010, + "RL" + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + 1990, + "summer", + "night", + "RL1", + 1990, + "RL" + ], + [ + "utopia", + 2000, + "inter", + "day", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "inter", + "day", + "TXE", + 2010, + "TX" + ], + [ + "utopia", + 1990, + "winter", + "day", + "RL1", + 1990, + "RL" + ], + [ + "utopia", + 2010, + "winter", + "night", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 1990, + "summer", + "day", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 1990, + "inter", + "day", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 1990, + "winter", + "night", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + 1990, + "summer", + "day", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "summer", + "night", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "day", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "night", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "summer", + "day", + "TXE", + 2010, + "TX" + ], + [ + "utopia", + 2010, + "inter", + "day", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + 1990, + "summer", + "night", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + 1990, + "winter", + "night", + "RHO", + 1970, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "day", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "winter", + "day", + "TXD", + 2010, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "night", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "night", + "RHE", + 2000, + "RH" + ], + [ + "utopia", + 1990, + "winter", + "day", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "night", + "RHE", + 2000, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "night", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 1990, + "inter", + "night", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + 2010, + "inter", + "night", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + 1990, + "summer", + "night", + "RHO", + 1970, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "day", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "day", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "day", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "night", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "inter", + "day", + "RHE", + 2010, + "RH" + ], + [ + "utopia", + 1990, + "winter", + "night", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "inter", + "night", + "RHE", + 2010, + "RH" + ], + [ + "utopia", + 2010, + "inter", + "day", + "RHO", + 2010, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "day", + "TXD", + 1980, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "day", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + 1990, + "summer", + "night", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "day", + "RHE", + 2010, + "RH" + ], + [ + "utopia", + 2010, + "summer", + "day", + "TXD", + 2010, + "TX" + ], + [ + "utopia", + 2000, + "summer", + "day", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + 1990, + "inter", + "day", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + 1990, + "summer", + "day", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + 1990, + "winter", + "day", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + 1990, + "inter", + "day", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "day", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "summer", + "day", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "day", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "day", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "day", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "night", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "night", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + 1990, + "inter", + "night", + "RHO", + 1970, + "RH" + ], + [ + "utopia", + 2000, + "summer", + "day", + "TXD", + 1980, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + 2000, + "summer", + "night", + "RL1", + 2000, + "RL" + ], + [ + "utopia", + 1990, + "inter", + "day", + "RL1", + 1980, + "RL" + ], + [ + "utopia", + 2000, + "winter", + "day", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + 2000, + "inter", + "day", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + 2010, + "inter", + "day", + "RL1", + 2010, + "RL" + ], + [ + "utopia", + 2000, + "summer", + "night", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + 1990, + "inter", + "night", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "winter", + "night", + "TXD", + 1980, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "day", + "RHE", + 2000, + "RH" + ], + [ + "utopia", + 2010, + "summer", + "day", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "summer", + "day", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "inter", + "night", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "summer", + "night", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + 2010, + "summer", + "day", + "TXG", + 2010, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "night", + "TXG", + 2010, + "TX" + ], + [ + "utopia", + 1990, + "winter", + "night", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 1990, + "winter", + "day", + "RHO", + 1970, + "RH" + ], + [ + "utopia", + 2010, + "summer", + "night", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + 1990, + "summer", + "day", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + 2000, + "winter", + "night", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "summer", + "night", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + 2010, + "summer", + "day", + "RHO", + 2010, + "RH" + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXD", + 1970, + "TX" + ], + [ + "utopia", + 1990, + "inter", + "night", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + 2000, + "inter", + "night", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + 1990, + "winter", + "night", + "RL1", + 1990, + "RL" + ], + [ + "utopia", + 1990, + "winter", + "day", + "RL1", + 1980, + "RL" + ], + [ + "utopia", + 2000, + "inter", + "day", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "day", + "RL1", + 2010, + "RL" + ], + [ + "utopia", + 2000, + "summer", + "night", + "RHE", + 2000, + "RH" + ] + ], + "EmissionActivity_reitvo": [ + [ + "utopia", + "co2", + "DSL", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + "co2", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + "co2", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + "nox", + "HCO", + "E01", + 1960, + "ELC" + ], + [ + "utopia", + "co2", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + "nox", + "ELC", + "RL1", + 1980, + "RL" + ], + [ + "utopia", + "co2", + "URN", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + "co2", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + "nox", + "ELC", + "RL1", + 2010, + "RL" + ], + [ + "utopia", + "co2", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + "nox", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + "nox", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + "co2", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + "co2", + "OIL", + "SRE", + 2010, + "DSL" + ], + [ + "utopia", + "co2", + "HCO", + "E01", + 1970, + "ELC" + ], + [ + "utopia", + "nox", + "URN", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + "co2", + "OIL", + "SRE", + 2010, + "GSL" + ], + [ + "utopia", + "co2", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + "co2", + "GSL", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + "nox", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + "nox", + "ELC", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + "co2", + "DSL", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + "nox", + "DSL", + "E70", + 1970, + "ELC" + ], + [ + "utopia", + "co2", + "DSL", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + "co2", + "HYD", + "E31", + 2000, + "ELC" + ], + [ + "utopia", + "nox", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + "nox", + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + "co2", + "ELC", + "RHE", + 2010, + "RH" + ], + [ + "utopia", + "nox", + "OIL", + "SRE", + 2010, + "DSL" + ], + [ + "utopia", + "nox", + "URN", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + "nox", + "OIL", + "SRE", + 2010, + "GSL" + ], + [ + "utopia", + "nox", + "GSL", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + "co2", + "DSL", + "E70", + 2010, + "ELC" + ], + [ + "utopia", + "co2", + "GSL", + "TXG", + 1970, + "TX" + ], + [ + "utopia", + "nox", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + "co2", + "ELC", + "TXE", + 2010, + "TX" + ], + [ + "utopia", + "nox", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + "nox", + "ELC", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + "nox", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + "co2", + "DSL", + "TXD", + 1980, + "TX" + ], + [ + "utopia", + "nox", + "DSL", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + "nox", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + "co2", + "ELC", + "RL1", + 1990, + "RL" + ], + [ + "utopia", + "nox", + "HYD", + "E31", + 2010, + "ELC" + ], + [ + "utopia", + "co2", + "FEQ", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + "nox", + "DSL", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + "nox", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + "nox", + "OIL", + "SRE", + 2000, + "DSL" + ], + [ + "utopia", + "co2", + "GSL", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + "nox", + "ELC", + "RHE", + 2010, + "RH" + ], + [ + "utopia", + "nox", + "OIL", + "SRE", + 2000, + "GSL" + ], + [ + "utopia", + "nox", + "GSL", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + "co2", + "DSL", + "E70", + 2000, + "ELC" + ], + [ + "utopia", + "nox", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + "nox", + "DSL", + "E70", + 2010, + "ELC" + ], + [ + "utopia", + "co2", + "HCO", + "E01", + 2000, + "ELC" + ], + [ + "utopia", + "nox", + "DSL", + "TXD", + 1980, + "TX" + ], + [ + "utopia", + "nox", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + "nox", + "ELC", + "RL1", + 2000, + "RL" + ], + [ + "utopia", + "co2", + "HCO", + "E01", + 1960, + "ELC" + ], + [ + "utopia", + "co2", + "ELC", + "RL1", + 1980, + "RL" + ], + [ + "utopia", + "co2", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + "nox", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + "co2", + "GSL", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + "nox", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + "co2", + "OIL", + "SRE", + 2000, + "DSL" + ], + [ + "utopia", + "nox", + "DSL", + "E70", + 2000, + "ELC" + ], + [ + "utopia", + "co2", + "OIL", + "SRE", + 2000, + "GSL" + ], + [ + "utopia", + "co2", + "DSL", + "RHO", + 2010, + "RH" + ], + [ + "utopia", + "co2", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + "nox", + "HCO", + "E01", + 2010, + "ELC" + ], + [ + "utopia", + "co2", + "DSL", + "E70", + 1970, + "ELC" + ], + [ + "utopia", + "co2", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + "co2", + "ELC", + "RL1", + 2010, + "RL" + ], + [ + "utopia", + "nox", + "DSL", + "TXD", + 1970, + "TX" + ], + [ + "utopia", + "nox", + "HCO", + "E01", + 1970, + "ELC" + ], + [ + "utopia", + "co2", + "URN", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + "nox", + "ELC", + "RL1", + 1990, + "RL" + ], + [ + "utopia", + "nox", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + "co2", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + "co2", + "ELC", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + "co2", + "DSL", + "RHO", + 1970, + "RH" + ], + [ + "utopia", + "co2", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + "co2", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + "nox", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + "co2", + "DSL", + "TXD", + 2010, + "TX" + ], + [ + "utopia", + "co2", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + "co2", + "ELC", + "RHE", + 2000, + "RH" + ], + [ + "utopia", + "co2", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + "nox", + "DSL", + "RHO", + 2010, + "RH" + ], + [ + "utopia", + "nox", + "FEQ", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + "co2", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + "nox", + "HCO", + "E01", + 2000, + "ELC" + ], + [ + "utopia", + "co2", + "DSL", + "E70", + 1960, + "ELC" + ], + [ + "utopia", + "co2", + "GSL", + "TXG", + 2010, + "TX" + ], + [ + "utopia", + "co2", + "ELC", + "RL1", + 2000, + "RL" + ], + [ + "utopia", + "nox", + "GSL", + "TXG", + 2010, + "TX" + ], + [ + "utopia", + "co2", + "DSL", + "TXD", + 1970, + "TX" + ], + [ + "utopia", + "nox", + "GSL", + "TXG", + 1970, + "TX" + ], + [ + "utopia", + "nox", + "ELC", + "TXE", + 2010, + "TX" + ], + [ + "utopia", + "nox", + "HYD", + "E31", + 2000, + "ELC" + ], + [ + "utopia", + "co2", + "ELC", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + "co2", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + "co2", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + "nox", + "DSL", + "RHO", + 1970, + "RH" + ], + [ + "utopia", + "co2", + "DSL", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + "nox", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + "nox", + "DSL", + "TXD", + 2010, + "TX" + ], + [ + "utopia", + "co2", + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + "nox", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + "nox", + "ELC", + "RHE", + 2000, + "RH" + ], + [ + "utopia", + "nox", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + "nox", + "DSL", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + "co2", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + "co2", + "HCO", + "E01", + 2010, + "ELC" + ], + [ + "utopia", + "nox", + "FEQ", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + "nox", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + "nox", + "DSL", + "E70", + 1960, + "ELC" + ], + [ + "utopia", + "nox", + "GSL", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + "co2", + "HYD", + "E31", + 2010, + "ELC" + ], + [ + "utopia", + "nox", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + "co2", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + "co2", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + "nox", + "DSL", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + "nox", + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + "co2", + "FEQ", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + "co2", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + "nox", + "DSL", + "E70", + 1990, + "ELC" + ] + ], + "FlexVarAnnual_rpitvo": [], + "FlexVar_rpsditvo": [], + "FlowInStorage_rpsditvo": [ + [ + "utopia", + 2000, + "winter", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "ELC", + "E51", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ELC", + "E51", + 1990, + "ELC" + ] + ], + "FlowVarAnnual_rpitvo": [ + [ + "utopia", + 2000, + "DSL", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + 1990, + "GSL", + "TXG", + 1970, + "TX" + ], + [ + "utopia", + 2000, + "GSL", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + 2010, + "ELC", + "RHE", + 2000, + "RH" + ], + [ + "utopia", + 1990, + "ELC", + "RL1", + 1990, + "RL" + ], + [ + "utopia", + 2010, + "ELC", + "RL1", + 2010, + "RL" + ], + [ + "utopia", + 2000, + "GSL", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + 1990, + "DSL", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + 2010, + "DSL", + "RHO", + 2010, + "RH" + ], + [ + "utopia", + 2000, + "ELC", + "RHE", + 2000, + "RH" + ], + [ + "utopia", + 1990, + "ELC", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "ELC", + "TXE", + 2010, + "TX" + ], + [ + "utopia", + 1990, + "GSL", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + 2010, + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "GSL", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "DSL", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + 2000, + "DSL", + "RHO", + 1980, + "RH" + ], + [ + "utopia", + 2000, + "GSL", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + 1990, + "DSL", + "TXD", + 1980, + "TX" + ], + [ + "utopia", + 2010, + "DSL", + "TXD", + 2010, + "TX" + ], + [ + "utopia", + 1990, + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "ELC", + "RHE", + 2010, + "RH" + ], + [ + "utopia", + 2000, + "ELC", + "TXE", + 1990, + "TX" + ], + [ + "utopia", + 2000, + "DSL", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + 2010, + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 1990, + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "ELC", + "RL1", + 2000, + "RL" + ], + [ + "utopia", + 2000, + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2000, + "DSL", + "TXD", + 1980, + "TX" + ], + [ + "utopia", + 1990, + "DSL", + "TXD", + 1990, + "TX" + ], + [ + "utopia", + 1990, + "ELC", + "RL1", + 1980, + "RL" + ], + [ + "utopia", + 1990, + "DSL", + "RHO", + 1970, + "RH" + ], + [ + "utopia", + 1990, + "GSL", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + 2010, + "DSL", + "RHO", + 2000, + "RH" + ], + [ + "utopia", + 2010, + "GSL", + "TXG", + 2010, + "TX" + ], + [ + "utopia", + 2000, + "DSL", + "RHO", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "ELC", + "TXE", + 2000, + "TX" + ], + [ + "utopia", + 1990, + "DSL", + "TXD", + 1970, + "TX" + ], + [ + "utopia", + 2010, + "DSL", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + 2000, + "ELC", + "TXE", + 2000, + "TX" + ] + ], + "FlowVar_rpsditvo": [ + [ + "utopia", + 1990, + "winter", + "day", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 1990, + "winter", + "night", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 2010, + "summer", + "day", + "HYD", + "E31", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 2010, + "summer", + "night", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 1990, + "summer", + "night", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 2000, + "winter", + "day", + "OIL", + "SRE", + 2000, + "GSL" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 2010, + "summer", + "night", + "OIL", + "SRE", + 2010, + "DSL" + ], + [ + "utopia", + 1990, + "inter", + "night", + "DSL", + "E70", + 1960, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 2000, + "summer", + "night", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "HYD", + "E31", + 2010, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "FEQ", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "DSL", + "E70", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 2000, + "winter", + "day", + "HYD", + "E31", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "OIL", + "SRE", + 2000, + "DSL" + ], + [ + "utopia", + 1990, + "winter", + "night", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 2010, + "inter", + "night", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "OIL", + "SRE", + 2000, + "GSL" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 1990, + "summer", + "night", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "DSL", + "E70", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "OIL", + "SRE", + 2010, + "DSL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "FEQ", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 2010, + "winter", + "day", + "OIL", + "SRE", + 2010, + "GSL" + ], + [ + "utopia", + 2010, + "summer", + "night", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "FEQ", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 1990, + "winter", + "day", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 2000, + "summer", + "day", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "HCO", + "E01", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "OIL", + "SRE", + 2000, + "DSL" + ], + [ + "utopia", + 2000, + "inter", + "night", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "OIL", + "SRE", + 2000, + "GSL" + ], + [ + "utopia", + 1990, + "winter", + "night", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "FEQ", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "night", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + 2000, + "summer", + "day", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "FEQ", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "night", + "HCO", + "E01", + 1970, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "URN", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 2000, + "summer", + "day", + "HCO", + "E01", + 1970, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 2010, + "inter", + "night", + "HCO", + "E01", + 2010, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 1990, + "winter", + "night", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ELC", + "E51", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "URN", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 2010, + "summer", + "day", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "OIL", + "SRE", + 2010, + "DSL" + ], + [ + "utopia", + 2010, + "summer", + "day", + "DSL", + "E70", + 2000, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "HCO", + "E01", + 2010, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "URN", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "DSL", + "E70", + 1970, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "URN", + "E21", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 2010, + "inter", + "night", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "HCO", + "E01", + 1970, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "night", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 1990, + "summer", + "night", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 1990, + "inter", + "day", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 2010, + "winter", + "night", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "OIL", + "SRE", + 2010, + "DSL" + ], + [ + "utopia", + 2000, + "inter", + "night", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "OIL", + "SRE", + 2010, + "GSL" + ], + [ + "utopia", + 1990, + "inter", + "day", + "HCO", + "E01", + 1960, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "OIL", + "SRE", + 2000, + "DSL" + ], + [ + "utopia", + 2000, + "winter", + "day", + "HCO", + "E01", + 1970, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "FEQ", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "day", + "HCO", + "E01", + 1970, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 2000, + "inter", + "night", + "URN", + "E21", + 1990, + "ELC" ], [ "utopia", - "nox", + 2000, + "inter", + "day", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "day", + "ethos", + "IMPHYD", + 1990, + "HYD" + ], + [ + "utopia", + 1990, + "winter", + "night", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], + [ + "utopia", + 1990, + "inter", + "day", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "night", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 1990, + "winter", + "day", + "ELC", + "E51", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "day", + "HYD", + "E31", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 1990, + "inter", + "day", + "ELC", + "E51", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", + 2000, + "summer", + "day", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 2000, + "winter", + "night", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", "ethos", "IMPHCO1", 1990, @@ -11142,15 +15660,109 @@ ], [ "utopia", - "nox", - "DSL", - "RHO", 2000, - "RH" + "summer", + "night", + "DSL", + "E70", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "day", + "FEQ", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + 2010, + "winter", + "day", + "URN", + "E21", + 2010, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 1990, + "summer", + "night", + "DSL", + "E70", + 1960, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "HCO", + "E01", + 2000, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "day", + "OIL", + "SRE", + 1990, + "GSL" + ], + [ + "utopia", + 2000, + "winter", + "day", + "ethos", + "IMPGSL1", + 1990, + "GSL" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ELC", + "E51", + 2000, + "ELC" ], [ "utopia", - "co2", + 2010, + "winter", + "day", "DSL", "E70", 1990, @@ -11158,63 +15770,69 @@ ], [ "utopia", - "co2", - "HCO", - "E01", + 1990, + "inter", + "night", + "ethos", + "IMPHCO1", + 1990, + "HCO" + ], + [ + "utopia", 2010, - "ELC" + "summer", + "day", + "ethos", + "IMPFEQ", + 1990, + "FEQ" ], [ "utopia", - "nox", + 2010, + "summer", + "night", "FEQ", "E21", - 2000, + 2010, "ELC" ], [ "utopia", - "nox", + 2010, + "winter", + "day", "ethos", - "IMPHYD", + "IMPFEQ", 1990, - "HYD" - ], - [ - "utopia", - "nox", - "DSL", - "E70", - 1960, - "ELC" + "FEQ" ], [ "utopia", - "nox", - "GSL", - "TXG", 2000, - "TX" + "inter", + "day", + "ethos", + "IMPGSL1", + 1990, + "GSL" ], [ "utopia", - "co2", - "HYD", - "E31", + 2010, + "summer", + "night", + "URN", + "E21", 2010, "ELC" ], [ "utopia", - "nox", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - "co2", + 2010, + "summer", + "night", "ELC", "E51", 1980, @@ -11222,123 +15840,141 @@ ], [ "utopia", - "co2", + 2010, + "summer", + "day", "ethos", - "IMPOIL1", + "IMPHCO1", 1990, - "OIL" + "HCO" ], [ "utopia", - "nox", - "DSL", - "TXD", - 2000, - "TX" + 2010, + "summer", + "day", + "ethos", + "IMPURN1", + 1990, + "URN" ], [ "utopia", - "nox", - "ELC", - "RHE", 1990, - "RH" + "winter", + "night", + "ethos", + "IMPOIL1", + 1990, + "OIL" ], [ "utopia", - "co2", - "FEQ", - "E21", - 2010, + 2000, + "winter", + "day", + "ELC", + "E51", + 1990, "ELC" ], [ "utopia", - "co2", + 1990, + "winter", + "day", "DSL", "E70", - 1980, + 1960, "ELC" ], [ "utopia", - "nox", - "DSL", - "E70", 1990, - "ELC" - ] - ], - "FlexVarAnnual_rpitvo": [], - "FlexVar_rpsditvo": [], - "FlowInStorage_rpsditvo": [ + "inter", + "night", + "OIL", + "SRE", + 1990, + "DSL" + ], [ "utopia", 2000, - "winter", - "day", - "ELC", - "E51", + "summer", + "night", + "HCO", + "E01", 1980, "ELC" ], [ "utopia", - 2000, - "inter", + 2010, + "summer", "night", - "ELC", - "E51", + "HYD", + "E31", 2000, "ELC" ], [ "utopia", - 2010, - "winter", - "day", - "ELC", - "E51", - 2000, + 1990, + "summer", + "night", + "HCO", + "E01", + 1980, "ELC" ], [ "utopia", - 2000, + 1990, "inter", "night", - "ELC", - "E51", - 1980, - "ELC" + "OIL", + "SRE", + 1990, + "GSL" ], [ "utopia", - 2000, - "winter", + 1990, + "inter", "night", - "ELC", - "E51", - 2000, + "HCO", + "E01", + 1960, "ELC" ], [ "utopia", 2000, - "winter", + "inter", "day", - "ELC", - "E51", - 2000, + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 1990, + "inter", + "night", + "DSL", + "E70", + 1980, "ELC" ], [ "utopia", 2000, - "winter", - "night", - "ELC", - "E51", + "inter", + "day", + "HYD", + "E31", 1980, "ELC" ], @@ -11347,99 +15983,139 @@ 2010, "inter", "day", - "ELC", - "E51", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "summer", + "night", + "OIL", + "SRE", + 2010, + "GSL" + ], + [ + "utopia", + 2000, + "summer", + "night", + "HYD", + "E31", 2000, "ELC" ], + [ + "utopia", + 1990, + "summer", + "day", + "FEQ", + "E21", + 1990, + "ELC" + ], [ "utopia", 2010, "inter", "day", - "ELC", - "E51", - 1980, + "DSL", + "E70", + 2000, "ELC" ], [ "utopia", - 2000, + 2010, "summer", - "night", - "ELC", - "E51", + "day", + "HYD", + "E31", 1990, "ELC" ], [ "utopia", - 1990, + 2010, "winter", "day", - "ELC", - "E51", - 1980, - "ELC" + "OIL", + "SRE", + 2000, + "DSL" ], [ "utopia", 2000, - "summer", + "winter", "day", - "ELC", - "E51", + "ethos", + "IMPDSL1", 1990, - "ELC" + "DSL" ], [ "utopia", 2010, "winter", - "day", - "ELC", - "E51", - 1980, + "night", + "FEQ", + "E21", + 2000, "ELC" ], [ "utopia", - 1990, - "winter", + 2010, + "inter", "night", - "ELC", - "E51", - 1990, + "FEQ", + "E21", + 2010, "ELC" ], [ "utopia", 2010, - "summer", + "winter", "day", - "ELC", - "E51", - 2010, - "ELC" + "OIL", + "SRE", + 2000, + "GSL" ], [ "utopia", + 2010, + "summer", + "night", + "OIL", + "SRE", 2000, - "inter", - "day", + "DSL" + ], + [ + "utopia", + 2010, + "summer", + "night", "ELC", "E51", - 1990, + 2000, "ELC" ], [ "utopia", - 1990, + 2010, "summer", - "day", - "ELC", - "E51", - 1990, + "night", + "HCO", + "E01", + 1980, "ELC" ], [ @@ -11447,8 +16123,8 @@ 2010, "summer", "day", - "ELC", - "E51", + "URN", + "E21", 1990, "ELC" ], @@ -11457,38 +16133,48 @@ 2010, "summer", "night", - "ELC", - "E51", + "OIL", + "SRE", + 2000, + "GSL" + ], + [ + "utopia", 2000, + "summer", + "night", + "FEQ", + "E21", + 1990, "ELC" ], [ "utopia", 1990, - "inter", - "night", - "ELC", - "E51", + "winter", + "day", + "DSL", + "E70", 1980, "ELC" ], [ "utopia", - 2010, - "summer", + 2000, + "winter", "night", "ELC", "E51", - 1990, + 1980, "ELC" ], [ "utopia", 2010, "winter", - "night", - "ELC", - "E51", + "day", + "HYD", + "E31", 2000, "ELC" ], @@ -11497,39 +16183,49 @@ 1990, "summer", "night", - "ELC", - "E51", - 1980, + "DSL", + "E70", + 1990, "ELC" ], [ "utopia", 1990, "inter", + "night", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 1990, + "winter", "day", - "ELC", - "E51", + "HYD", + "E31", 1980, "ELC" ], [ "utopia", 2000, - "winter", - "day", - "ELC", - "E51", + "inter", + "night", + "ethos", + "IMPDSL1", 1990, - "ELC" + "DSL" ], [ "utopia", - 2010, - "winter", + 2000, + "summer", "day", - "ELC", - "E51", - 2010, + "FEQ", + "E21", + 1990, "ELC" ], [ @@ -11537,9 +16233,19 @@ 2010, "summer", "night", - "ELC", - "E51", - 1980, + "HCO", + "E01", + 2010, + "ELC" + ], + [ + "utopia", + 1990, + "winter", + "day", + "HCO", + "E01", + 1970, "ELC" ], [ @@ -11547,179 +16253,189 @@ 2000, "summer", "day", - "ELC", - "E51", - 2000, + "DSL", + "E70", + 1970, "ELC" ], [ "utopia", - 2000, - "inter", - "night", - "ELC", - "E51", 1990, + "winter", + "night", + "HCO", + "E01", + 1960, "ELC" ], [ "utopia", 2010, - "inter", - "night", - "ELC", - "E51", - 2000, + "summer", + "day", + "FEQ", + "E21", + 1990, "ELC" ], [ "utopia", 2000, - "winter", - "night", - "ELC", - "E51", + "summer", + "day", + "OIL", + "SRE", 1990, - "ELC" + "GSL" ], [ "utopia", - 2010, + 2000, "inter", - "day", + "night", "ELC", "E51", - 2010, + 2000, "ELC" ], [ "utopia", - 2010, - "inter", - "night", - "ELC", - "E51", - 1980, + 1990, + "summer", + "day", + "URN", + "E21", + 1990, "ELC" ], [ "utopia", 1990, - "winter", + "inter", "night", - "ELC", - "E51", - 1980, + "HCO", + "E01", + 1990, "ELC" ], [ "utopia", 2010, - "inter", + "winter", "day", "ELC", "E51", - 1990, + 2000, "ELC" ], [ "utopia", 2010, - "winter", + "inter", "night", - "ELC", - "E51", - 1980, + "URN", + "E21", + 2010, "ELC" ], [ "utopia", - 1990, + 2000, "winter", "day", - "ELC", - "E51", + "HYD", + "E31", 1990, "ELC" ], [ "utopia", - 2000, - "summer", + 2010, + "inter", "night", - "ELC", - "E51", - 1980, - "ELC" + "OIL", + "SRE", + 1990, + "DSL" ], [ "utopia", 2010, - "winter", - "day", - "ELC", - "E51", + "inter", + "night", + "OIL", + "SRE", 1990, - "ELC" + "GSL" ], [ "utopia", - 2000, - "summer", + 2010, + "inter", "day", - "ELC", - "E51", - 1980, + "HCO", + "E01", + 2010, "ELC" ], [ "utopia", 2000, - "inter", + "summer", "day", - "ELC", - "E51", - 2000, - "ELC" + "ethos", + "IMPGSL1", + 1990, + "GSL" ], [ "utopia", - 2010, + 2000, "summer", "day", - "ELC", - "E51", + "DSL", + "E70", 2000, "ELC" ], [ "utopia", 1990, - "summer", - "day", - "ELC", - "E51", - 1980, + "winter", + "night", + "HCO", + "E01", + 1990, "ELC" ], [ "utopia", - 2010, - "summer", + 2000, + "inter", "night", - "ELC", - "E51", - 2010, + "HYD", + "E31", + 2000, "ELC" ], [ "utopia", - 2010, + 1990, "summer", "day", + "ethos", + "IMPDSL1", + 1990, + "DSL" + ], + [ + "utopia", + 2010, + "inter", + "day", "ELC", "E51", - 1980, + 2000, "ELC" ], [ @@ -11734,22 +16450,22 @@ ], [ "utopia", - 1990, - "inter", + 2010, + "winter", "day", - "ELC", - "E51", - 1990, + "HCO", + "E01", + 2010, "ELC" ], [ "utopia", - 2010, + 1990, "inter", - "night", - "ELC", - "E51", - 2010, + "day", + "HYD", + "E31", + 1990, "ELC" ], [ @@ -11764,417 +16480,413 @@ ], [ "utopia", - 2010, - "inter", - "night", - "ELC", - "E51", 1990, + "winter", + "night", + "HYD", + "E31", + 1980, "ELC" ], [ "utopia", - 2000, + 2010, "inter", - "day", - "ELC", - "E51", + "night", + "HYD", + "E31", 1980, "ELC" ], [ "utopia", - 2010, + 1990, "winter", "night", - "ELC", - "E51", - 2010, + "DSL", + "E70", + 1970, "ELC" ], [ "utopia", - 1990, + 2000, "summer", "night", - "ELC", - "E51", + "ethos", + "IMPDSL1", 1990, - "ELC" + "DSL" ], [ "utopia", 2010, - "winter", + "inter", "night", - "ELC", - "E51", - 1990, - "ELC" - ] - ], - "FlowVarAnnual_rpitvo": [ - [ - "utopia", - 2000, "DSL", - "TXD", - 1990, - "TX" + "E70", + 1980, + "ELC" ], [ "utopia", + 2000, + "summer", + "day", + "HCO", + "E01", 1990, - "GSL", - "TXG", - 1970, - "TX" + "ELC" ], [ "utopia", 2000, - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "ELC", - "RHE", + "winter", + "night", + "HYD", + "E31", 2000, - "RH" + "ELC" ], [ "utopia", 1990, - "ELC", - "RL1", + "summer", + "night", + "ethos", + "IMPDSL1", 1990, - "RL" + "DSL" ], [ "utopia", 2010, + "summer", + "day", "ELC", - "RL1", - 2010, - "RL" - ], - [ - "utopia", + "E51", 2000, - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2010, - "DSL", - "RHO", - 2010, - "RH" + "ELC" ], [ "utopia", 2000, - "ELC", - "RHE", + "summer", + "night", + "OIL", + "SRE", 2000, - "RH" + "DSL" ], [ "utopia", + 2010, + "summer", + "day", + "OIL", + "SRE", 1990, - "ELC", - "TXE", - 1990, - "TX" + "DSL" ], [ "utopia", - 2010, - "ELC", - "TXE", - 2010, - "TX" + 2000, + "summer", + "night", + "OIL", + "SRE", + 2000, + "GSL" ], [ "utopia", + 2000, + "summer", + "night", + "ELC", + "E51", 1990, - "GSL", - "TXG", - 1980, - "TX" + "ELC" ], [ "utopia", 2010, - "DSL", - "RHO", + "winter", + "night", + "ethos", + "IMPFEQ", 1990, - "RH" + "FEQ" ], [ "utopia", - 2010, - "GSL", - "TXG", - 2000, - "TX" + 1990, + "winter", + "night", + "ELC", + "E51", + 1990, + "ELC" ], [ "utopia", 2000, - "DSL", - "RHO", - 2000, - "RH" + "winter", + "day", + "FEQ", + "E21", + 1990, + "ELC" ], [ "utopia", - 2000, - "DSL", - "RHO", - 1980, - "RH" + 2010, + "summer", + "day", + "ethos", + "IMPGSL1", + 1990, + "GSL" ], [ "utopia", - 2000, - "GSL", - "TXG", + 2010, + "winter", + "day", + "ethos", + "IMPOIL1", 1990, - "TX" + "OIL" ], [ "utopia", - 1990, - "DSL", - "TXD", - 1980, - "TX" + 2010, + "inter", + "day", + "OIL", + "SRE", + 2000, + "DSL" ], [ "utopia", 2010, + "inter", + "night", "DSL", - "TXD", + "E70", 2010, - "TX" + "ELC" ], [ "utopia", 1990, - "ELC", - "RHE", + "inter", + "night", + "ethos", + "IMPDSL1", 1990, - "RH" + "DSL" ], [ "utopia", 2010, - "ELC", - "RHE", - 2010, - "RH" + "winter", + "day", + "HCO", + "E01", + 1980, + "ELC" ], [ "utopia", - 2000, - "ELC", - "TXE", 1990, - "TX" - ], - [ - "utopia", - 2000, - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "ELC", - "RHE", + "winter", + "night", + "ethos", + "IMPDSL1", 1990, - "RH" + "DSL" ], [ "utopia", 1990, + "summer", + "day", "DSL", - "RHO", - 1990, - "RH" + "E70", + 1980, + "ELC" ], [ "utopia", 2000, - "ELC", - "RL1", + "inter", + "day", + "OIL", + "SRE", 2000, - "RL" + "DSL" ], [ "utopia", 2000, - "ELC", - "RHE", + "inter", + "day", + "ethos", + "IMPFEQ", 1990, - "RH" - ], - [ - "utopia", - 2000, - "DSL", - "TXD", - 1980, - "TX" + "FEQ" ], [ "utopia", + 2010, + "winter", + "day", + "ethos", + "IMPURN1", 1990, - "DSL", - "TXD", - 1990, - "TX" + "URN" ], [ "utopia", + 2010, + "inter", + "night", + "ethos", + "IMPGSL1", 1990, - "ELC", - "RL1", - 1980, - "RL" + "GSL" ], [ "utopia", + 2010, + "summer", + "night", + "ethos", + "IMPDSL1", 1990, - "DSL", - "RHO", - 1970, - "RH" + "DSL" ], [ "utopia", 1990, - "GSL", - "TXG", - 1990, - "TX" + "inter", + "day", + "DSL", + "E70", + 1960, + "ELC" ], [ "utopia", 2010, + "summer", + "day", "DSL", - "RHO", - 2000, - "RH" + "E70", + 1980, + "ELC" ], [ "utopia", 2010, - "GSL", - "TXG", - 2010, - "TX" + "winter", + "night", + "URN", + "E21", + 1990, + "ELC" ], [ "utopia", 2000, + "winter", + "day", "DSL", - "RHO", - 1990, - "RH" + "E70", + 1970, + "ELC" ], [ "utopia", 2010, - "ELC", - "TXE", + "inter", + "night", + "HCO", + "E01", 2000, - "TX" + "ELC" ], [ "utopia", - 1990, - "DSL", - "TXD", - 1970, - "TX" + 2000, + "winter", + "night", + "FEQ", + "E21", + 2000, + "ELC" ], [ "utopia", - 2010, + 1990, + "summer", + "day", "DSL", - "TXD", - 2000, - "TX" + "E70", + 1970, + "ELC" ], [ "utopia", - 2000, - "ELC", - "TXE", - 2000, - "TX" - ] - ], - "FlowVar_rpsditvo": [ + 2010, + "inter", + "day", + "OIL", + "SRE", + 2010, + "GSL" + ], [ "utopia", 1990, "winter", "day", "ethos", - "IMPURN1", + "IMPDSL1", 1990, - "URN" + "DSL" ], [ "utopia", - 2000, + 2010, "inter", "day", - "ELC", - "E51", - 1980, + "URN", + "E21", + 1990, "ELC" ], [ "utopia", - 2010, + 1990, "inter", "day", - "ethos", - "IMPHCO1", + "DSL", + "E70", 1990, - "HCO" + "ELC" ], [ "utopia", 1990, - "winter", + "inter", "night", "ethos", - "IMPGSL1", + "IMPFEQ", 1990, - "GSL" + "FEQ" ], [ "utopia", @@ -12182,35 +16894,55 @@ "inter", "day", "ethos", - "IMPURN1", + "IMPDSL1", 1990, - "URN" + "DSL" ], [ "utopia", 2010, "summer", "day", - "HYD", - "E31", - 2000, + "DSL", + "E70", + 2010, "ELC" ], [ "utopia", 2000, - "summer", - "night", - "DSL", - "E70", + "inter", + "day", + "HCO", + "E01", + 1990, + "ELC" + ], + [ + "utopia", + 1990, + "inter", + "day", + "URN", + "E21", 1990, "ELC" ], [ "utopia", 2010, - "summer", - "night", + "inter", + "day", + "HYD", + "E31", + 1980, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", "URN", "E21", 1990, @@ -12219,8 +16951,28 @@ [ "utopia", 2010, - "summer", + "inter", "night", + "HYD", + "E31", + 2010, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 2000, + "inter", + "day", "DSL", "E70", 1980, @@ -12228,59 +16980,59 @@ ], [ "utopia", - 2000, - "winter", - "night", + 1990, + "inter", + "day", "HCO", "E01", - 1990, + 1980, "ELC" ], [ "utopia", 1990, - "summer", + "inter", "night", - "ethos", - "IMPHCO1", + "HYD", + "E31", 1990, - "HCO" + "ELC" ], [ "utopia", - 2010, - "summer", - "night", - "HYD", - "E31", + 2000, + "inter", + "day", + "HCO", + "E01", 1980, "ELC" ], [ "utopia", - 2000, + 2010, "summer", "day", - "ELC", - "E51", - 1990, + "HCO", + "E01", + 2000, "ELC" ], [ "utopia", 2010, - "inter", + "winter", "night", - "ethos", - "IMPHYD", - 1990, - "HYD" + "ELC", + "E51", + 1980, + "ELC" ], [ "utopia", 1990, - "summer", - "night", + "inter", + "day", "ethos", "IMPURN1", 1990, @@ -12289,17 +17041,27 @@ [ "utopia", 2000, - "winter", + "inter", "day", - "OIL", - "SRE", - 2000, - "GSL" + "ethos", + "IMPHCO1", + 1990, + "HCO" ], [ "utopia", 2000, "inter", + "day", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 2010, + "winter", "night", "ethos", "IMPGSL1", @@ -12308,111 +17070,111 @@ ], [ "utopia", - 2010, - "inter", + 2000, + "winter", "day", - "ethos", - "IMPFEQ", + "URN", + "E21", 1990, - "FEQ" + "ELC" ], [ "utopia", 2010, - "summer", - "night", - "OIL", - "SRE", + "winter", + "day", + "FEQ", + "E21", 2010, - "DSL" + "ELC" ], [ "utopia", + 2000, + "winter", + "day", + "ethos", + "IMPOIL1", 1990, + "OIL" + ], + [ + "utopia", + 2010, "inter", - "night", - "DSL", - "E70", - 1960, + "day", + "HYD", + "E31", + 2010, "ELC" ], [ "utopia", - 2010, - "summer", + 2000, + "winter", "night", "OIL", "SRE", - 1990, + 2000, "GSL" ], [ "utopia", - 2010, - "winter", + 2000, + "inter", "night", - "ethos", - "IMPDSL1", - 1990, + "OIL", + "SRE", + 2000, "DSL" ], [ "utopia", 2000, "summer", - "night", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "winter", "day", - "HCO", - "E01", - 1980, - "ELC" + "ethos", + "IMPFEQ", + 1990, + "FEQ" ], [ "utopia", 2000, - "summer", + "inter", "night", - "HCO", - "E01", - 1990, - "ELC" + "OIL", + "SRE", + 2000, + "GSL" ], [ "utopia", - 2010, + 2000, "summer", - "night", - "HYD", - "E31", - 2010, + "day", + "URN", + "E21", + 1990, "ELC" ], [ "utopia", + 2000, + "winter", + "day", + "ethos", + "IMPFEQ", 1990, - "summer", - "night", - "HCO", - "E01", - 1990, - "ELC" + "FEQ" ], [ "utopia", - 2010, + 2000, "winter", "day", - "ELC", - "E51", + "HCO", + "E01", 1980, "ELC" ], @@ -12420,50 +17182,50 @@ "utopia", 2010, "inter", - "night", + "day", "FEQ", "E21", - 1990, + 2000, "ELC" ], [ "utopia", - 2010, - "summer", - "day", - "FEQ", - "E21", 2000, - "ELC" + "winter", + "day", + "ethos", + "IMPHCO1", + 1990, + "HCO" ], [ "utopia", - 2010, - "inter", - "night", - "URN", - "E21", + 2000, + "winter", + "day", + "ethos", + "IMPURN1", 1990, - "ELC" + "URN" ], [ "utopia", + 2000, + "winter", + "night", + "OIL", + "SRE", 1990, - "inter", - "day", - "FEQ", - "E21", - 1990, - "ELC" + "DSL" ], [ "utopia", 2010, - "inter", - "day", - "HCO", - "E01", - 1990, + "winter", + "night", + "ELC", + "E51", + 2010, "ELC" ], [ @@ -12471,174 +17233,134 @@ 2010, "summer", "night", - "DSL", - "E70", - 2000, - "ELC" + "ethos", + "IMPHYD", + 1990, + "HYD" ], [ "utopia", - 1990, + 2000, "winter", "night", "OIL", "SRE", 1990, - "DSL" + "GSL" ], [ "utopia", 2000, "winter", "day", - "HYD", - "E31", + "DSL", + "E70", 2000, "ELC" ], [ "utopia", 2010, - "inter", + "winter", "night", "OIL", "SRE", 2000, "DSL" ], - [ - "utopia", - 1990, - "winter", - "night", - "OIL", - "SRE", - 1990, - "GSL" - ], [ "utopia", 2010, "inter", "night", - "HCO", - "E01", - 1980, + "ELC", + "E51", + 2000, "ELC" ], [ "utopia", - 2010, + 2000, "inter", "night", - "OIL", - "SRE", - 2000, - "GSL" + "DSL", + "E70", + 1980, + "ELC" ], [ "utopia", 2000, - "winter", + "inter", "night", - "ethos", - "IMPDSL1", + "HCO", + "E01", 1990, - "DSL" + "ELC" ], [ "utopia", - 1990, - "summer", + 2010, + "winter", "night", "ethos", - "IMPOIL1", + "IMPURN1", 1990, - "OIL" + "URN" ], [ "utopia", 2010, - "inter", + "winter", "day", "DSL", "E70", - 2010, + 1980, "ELC" ], [ "utopia", - 2010, - "winter", - "day", - "OIL", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - 2010, - "inter", + 1990, + "summer", "day", "ELC", "E51", - 1980, + 1990, "ELC" ], [ "utopia", - 2010, - "winter", + 1990, + "summer", "night", - "FEQ", + "URN", "E21", - 2010, + 1990, "ELC" ], [ "utopia", 2010, - "winter", - "day", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", + "inter", + "night", "ethos", - "IMPURN1", + "IMPDSL1", 1990, - "URN" + "DSL" ], [ "utopia", 2010, "winter", - "day", - "OIL", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - 2010, - "summer", "night", - "HCO", - "E01", - 1990, + "DSL", + "E70", + 2000, "ELC" ], [ "utopia", - 2000, + 2010, "summer", "night", "FEQ", @@ -12649,37 +17371,57 @@ [ "utopia", 2000, + "winter", + "night", + "ethos", + "IMPOIL1", + 1990, + "OIL" + ], + [ + "utopia", + 1990, "summer", "day", - "OIL", - "SRE", + "HCO", + "E01", + 1960, + "ELC" + ], + [ + "utopia", + 2000, + "inter", + "night", + "ethos", + "IMPHCO1", 1990, - "DSL" + "HCO" ], [ "utopia", 1990, - "winter", + "inter", "day", - "DSL", - "E70", + "ELC", + "E51", 1990, "ELC" ], [ "utopia", - 2000, + 2010, "inter", "day", - "OIL", - "SRE", + "ethos", + "IMPHYD", 1990, - "GSL" + "HYD" ], [ "utopia", - 2000, - "winter", + 1990, + "summer", "night", "ELC", "E51", @@ -12688,29 +17430,49 @@ ], [ "utopia", - 2010, - "inter", + 2010, + "winter", + "night", + "DSL", + "E70", + 1990, + "ELC" + ], + [ + "utopia", + 2000, + "winter", + "night", + "ethos", + "IMPURN1", + 1990, + "URN" + ], + [ + "utopia", + 2000, + "summer", "night", - "HYD", - "E31", - 1990, + "URN", + "E21", + 2000, "ELC" ], [ "utopia", 1990, - "winter", + "inter", "night", "DSL", "E70", - 1980, + 1970, "ELC" ], [ "utopia", - 1990, + 2010, "winter", - "day", + "night", "ethos", "IMPOIL1", 1990, @@ -12721,316 +17483,286 @@ 2000, "summer", "day", - "DSL", - "E70", - 1990, + "HYD", + "E31", + 2000, "ELC" ], [ "utopia", - 2000, + 1990, "summer", "day", - "HCO", - "E01", - 2000, + "HYD", + "E31", + 1980, "ELC" ], [ "utopia", 2010, "winter", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" + "night", + "HYD", + "E31", + 1980, + "ELC" ], [ "utopia", - 2010, - "summer", - "day", - "ethos", - "IMPDSL1", 1990, - "DSL" - ], - [ - "utopia", - 2000, - "inter", + "summer", "day", "ethos", - "IMPHYD", + "IMPOIL1", 1990, - "HYD" + "OIL" ], [ "utopia", 2010, - "inter", - "day", - "ELC", - "E51", - 2010, + "winter", + "night", + "HCO", + "E01", + 1980, "ELC" ], [ "utopia", - 2010, - "summer", - "day", - "OIL", - "SRE", 2000, - "DSL" + "summer", + "night", + "DSL", + "E70", + 1970, + "ELC" ], [ "utopia", - 2000, - "inter", + 1990, + "winter", "night", - "FEQ", - "E21", + "ethos", + "IMPHYD", 1990, - "ELC" + "HYD" ], [ "utopia", 2010, - "summer", + "winter", "day", - "OIL", - "SRE", + "URN", + "E21", 2000, - "GSL" + "ELC" ], [ "utopia", - 1990, - "winter", + 2010, + "summer", "night", - "HYD", - "E31", + "ELC", + "E51", 1990, "ELC" ], [ "utopia", 2000, - "summer", - "day", - "FEQ", - "E21", - 2000, + "winter", + "night", + "HCO", + "E01", + 1970, "ELC" ], [ "utopia", 2010, - "inter", + "summer", "night", - "DSL", - "E70", - 1990, + "URN", + "E21", + 2000, "ELC" ], [ "utopia", - 1990, - "inter", + 2000, + "summer", "night", "ethos", - "IMPGSL1", + "IMPOIL1", 1990, - "GSL" + "OIL" ], [ "utopia", - 2000, + 1990, "summer", "day", - "DSL", - "E70", - 1980, - "ELC" + "ethos", + "IMPHCO1", + 1990, + "HCO" ], [ "utopia", - 2000, - "inter", + 1990, + "summer", "day", - "FEQ", - "E21", - 2000, - "ELC" + "ethos", + "IMPURN1", + 1990, + "URN" ], [ "utopia", 1990, "winter", - "night", - "HCO", - "E01", + "day", + "DSL", + "E70", 1970, "ELC" ], [ "utopia", - 2000, - "inter", - "night", + 2010, + "winter", + "day", "HYD", "E31", - 1980, + 1990, "ELC" ], [ "utopia", 2000, - "inter", - "day", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2010, "winter", - "day", - "HCO", - "E01", + "night", + "DSL", + "E70", 1990, "ELC" ], [ "utopia", - 2010, - "inter", - "day", - "OIL", - "SRE", 1990, - "DSL" + "summer", + "night", + "DSL", + "E70", + 1980, + "ELC" ], [ "utopia", 2000, - "summer", - "day", + "winter", + "night", "HCO", "E01", - 1970, + 2000, "ELC" ], [ "utopia", - 1990, - "summer", + 2010, + "winter", "night", "HYD", "E31", - 1980, + 2010, "ELC" ], [ "utopia", 2000, - "winter", + "summer", "night", - "HYD", - "E31", - 1980, - "ELC" + "ethos", + "IMPFEQ", + 1990, + "FEQ" ], [ "utopia", 2010, - "summer", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", + "winter", + "night", + "HCO", + "E01", 2010, - "inter", - "day", - "OIL", - "SRE", - 1990, - "GSL" + "ELC" ], [ "utopia", 2000, - "inter", + "summer", "night", "ethos", - "IMPHYD", + "IMPHCO1", 1990, - "HYD" + "HCO" ], [ "utopia", - 2010, - "inter", + 2000, + "summer", "night", - "HCO", - "E01", - 2010, - "ELC" + "ethos", + "IMPURN1", + 1990, + "URN" ], [ "utopia", 1990, - "summer", + "inter", "night", - "ethos", - "IMPFEQ", + "DSL", + "E70", 1990, - "FEQ" + "ELC" ], [ "utopia", 1990, "winter", - "night", - "FEQ", - "E21", + "day", + "OIL", + "SRE", 1990, - "ELC" + "DSL" ], [ "utopia", 2010, - "summer", + "winter", "day", - "ELC", - "E51", + "DSL", + "E70", 2010, "ELC" ], [ "utopia", - 2010, - "inter", - "day", - "URN", - "E21", 2000, + "winter", + "day", + "ELC", + "E51", + 1980, "ELC" ], [ "utopia", - 2010, + 1990, "winter", - "night", + "day", "OIL", "SRE", 1990, @@ -13038,173 +17770,163 @@ ], [ "utopia", - 2010, - "summer", + 1990, + "winter", "day", - "HCO", - "E01", + "ELC", + "E51", 1980, "ELC" ], [ "utopia", 2010, - "winter", + "summer", "day", - "FEQ", + "URN", "E21", - 1990, + 2010, "ELC" ], [ "utopia", - 2010, - "inter", - "day", - "HYD", - "E31", 1990, + "winter", + "day", + "HCO", + "E01", + 1960, "ELC" ], [ "utopia", - 2010, + 1990, "inter", - "day", - "OIL", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "DSL", - "E70", - 2000, + "night", + "URN", + "E21", + 1990, "ELC" ], [ "utopia", - 2010, + 2000, "summer", - "day", + "night", "HCO", "E01", - 2010, + 1970, "ELC" ], [ "utopia", - 2000, + 1990, "winter", "day", - "URN", - "E21", - 2000, - "ELC" + "ethos", + "IMPGSL1", + 1990, + "GSL" ], [ "utopia", 1990, "inter", - "day", - "DSL", - "E70", - 1970, - "ELC" + "night", + "ethos", + "IMPOIL1", + 1990, + "OIL" ], [ "utopia", - 2010, - "summer", - "day", - "DSL", - "E70", 1990, + "summer", + "night", + "HCO", + "E01", + 1970, "ELC" ], [ "utopia", - 2010, - "winter", - "night", - "URN", - "E21", - 2000, + 1990, + "summer", + "day", + "HCO", + "E01", + 1990, "ELC" ], [ "utopia", 2000, - "winter", + "summer", "day", - "DSL", - "E70", + "ELC", + "E51", 1980, "ELC" ], [ "utopia", - 2000, + 2010, "summer", "day", "ethos", - "IMPHYD", + "IMPOIL1", 1990, - "HYD" + "OIL" ], [ "utopia", - 2010, + 2000, "inter", "night", "ELC", "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "HCO", - "E01", - 1970, + 1990, "ELC" ], [ "utopia", - 2000, + 2010, "summer", "night", "ethos", - "IMPHYD", + "IMPOIL1", 1990, - "HYD" + "OIL" ], [ "utopia", - 1990, + 2010, "summer", - "night", - "ethos", - "IMPHYD", - 1990, - "HYD" + "day", + "HYD", + "E31", + 1980, + "ELC" ], [ "utopia", 1990, "inter", + "night", + "HCO", + "E01", + 1980, + "ELC" + ], + [ + "utopia", + 2010, + "winter", "day", "ethos", - "IMPFEQ", + "IMPHYD", 1990, - "FEQ" + "HYD" ], [ "utopia", @@ -13212,88 +17934,68 @@ "winter", "night", "ethos", - "IMPHYD", + "IMPGSL1", 1990, - "HYD" + "GSL" ], [ "utopia", - 2010, + 2000, "winter", - "night", + "day", "HYD", "E31", - 1990, + 1980, "ELC" ], [ "utopia", - 2010, + 2000, "winter", - "night", + "day", "OIL", "SRE", - 2010, + 2000, "DSL" ], [ "utopia", - 2000, - "inter", - "night", - "DSL", - "E70", 1990, - "ELC" - ], - [ - "utopia", - 2010, "winter", "night", - "HCO", - "E01", + "ethos", + "IMPHCO1", 1990, - "ELC" + "HCO" ], [ "utopia", - 2010, - "winter", + 2000, + "summer", "night", - "OIL", - "SRE", - 2010, - "GSL" + "HYD", + "E31", + 1990, + "ELC" ], [ "utopia", 1990, - "inter", + "winter", "day", "HCO", "E01", - 1960, + 1990, "ELC" ], [ "utopia", 2000, - "winter", - "night", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2000, - "winter", + "inter", "day", - "HCO", - "E01", - 1970, + "HYD", + "E31", + 2000, "ELC" ], [ @@ -13301,47 +18003,47 @@ 2010, "inter", "day", - "FEQ", - "E21", + "DSL", + "E70", 1990, "ELC" ], [ "utopia", - 1990, - "summer", + 2010, + "inter", "day", "HCO", "E01", - 1970, + 2000, "ELC" ], [ "utopia", - 1990, - "winter", - "day", + 2010, + "summer", + "night", "ethos", - "IMPHYD", + "IMPHCO1", 1990, - "HYD" + "HCO" ], [ "utopia", 2010, - "winter", + "summer", "night", "ethos", - "IMPHCO1", + "IMPURN1", 1990, - "HCO" + "URN" ], [ "utopia", - 2000, - "inter", + 2010, + "winter", "night", - "URN", + "FEQ", "E21", 1990, "ELC" @@ -13350,110 +18052,100 @@ "utopia", 2000, "inter", - "day", - "DSL", - "E70", + "night", + "HYD", + "E31", 1990, "ELC" ], [ "utopia", - 2010, - "summer", + 2000, + "inter", "day", - "ethos", - "IMPHYD", + "ELC", + "E51", 1990, - "HYD" + "ELC" ], [ "utopia", - 1990, - "winter", + 2010, + "inter", "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" + "FEQ", + "E21", + 2000, + "ELC" ], [ "utopia", + 2010, + "summer", + "night", + "OIL", + "SRE", 1990, - "inter", - "day", - "HCO", - "E01", - 1990, - "ELC" + "DSL" ], [ "utopia", - 2000, + 2010, "summer", "day", "HYD", "E31", - 1980, - "ELC" - ], - [ - "utopia", 2010, - "winter", - "night", - "ELC", - "E51", - 1990, "ELC" ], [ "utopia", 1990, - "inter", + "winter", "day", - "ethos", - "IMPOIL1", + "HYD", + "E31", 1990, - "OIL" + "ELC" ], [ "utopia", - 1990, - "winter", - "day", - "ELC", - "E51", - 1990, + 2000, + "summer", + "night", + "DSL", + "E70", + 2000, "ELC" ], [ "utopia", 1990, - "summer", + "inter", "day", "HYD", "E31", - 1990, + 1980, "ELC" ], [ "utopia", 1990, - "inter", + "winter", "day", - "OIL", - "SRE", + "ethos", + "IMPHCO1", 1990, - "GSL" + "HCO" ], [ "utopia", + 2010, + "summer", + "night", + "DSL", + "E70", 1990, - "inter", - "day", - "ELC", - "E51", - 1980, "ELC" ], [ @@ -13461,194 +18153,184 @@ 2000, "summer", "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" + "OIL", + "SRE", + 2000, + "DSL" ], [ "utopia", - 2000, + 1990, "summer", "day", "ethos", - "IMPOIL1", + "IMPGSL1", 1990, - "OIL" + "GSL" ], [ "utopia", - 2000, + 1990, "winter", "night", - "URN", - "E21", - 1990, + "DSL", + "E70", + 1960, "ELC" ], [ "utopia", - 2000, - "winter", + 2010, + "summer", "night", - "ethos", - "IMPHCO1", + "HYD", + "E31", 1990, - "HCO" + "ELC" ], [ "utopia", 2000, "summer", - "night", - "DSL", - "E70", - 1980, + "day", + "ELC", + "E51", + 2000, "ELC" ], [ "utopia", 2000, - "winter", + "summer", "day", "HCO", "E01", - 1990, + 1980, "ELC" ], [ "utopia", - 2010, - "inter", + 2000, + "summer", "day", - "FEQ", - "E21", - 2010, - "ELC" + "OIL", + "SRE", + 2000, + "GSL" ], [ "utopia", - 2010, - "winter", - "day", - "URN", - "E21", - 2010, + 2000, + "summer", + "night", + "ELC", + "E51", + 1980, "ELC" ], [ "utopia", - 2000, + 1990, "winter", "night", - "HCO", - "E01", + "ELC", + "E51", 1980, "ELC" ], [ "utopia", - 1990, + 2000, "summer", "night", - "DSL", - "E70", - 1960, - "ELC" + "ethos", + "IMPGSL1", + 1990, + "GSL" ], [ "utopia", - 2000, + 2010, "inter", "night", - "HCO", - "E01", - 2000, - "ELC" + "ethos", + "IMPFEQ", + 1990, + "FEQ" ], [ "utopia", - 2000, - "winter", - "day", - "OIL", - "SRE", + 1990, + "summer", + "night", + "ethos", + "IMPGSL1", 1990, "GSL" ], [ "utopia", - 2000, + 1990, "winter", - "day", + "night", + "URN", + "E21", + 1990, + "ELC" + ], + [ + "utopia", + 2010, + "inter", + "night", "ethos", - "IMPGSL1", + "IMPURN1", 1990, - "GSL" + "URN" ], [ "utopia", 2000, - "inter", - "day", - "ELC", - "E51", + "summer", + "night", + "HCO", + "E01", 2000, "ELC" ], [ "utopia", 2010, - "winter", - "day", + "inter", + "night", "DSL", "E70", - 1990, + 2000, "ELC" ], [ "utopia", - 1990, + 2000, "inter", "night", "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ethos", "IMPFEQ", 1990, "FEQ" ], - [ - "utopia", - 2010, - "summer", - "night", - "FEQ", - "E21", - 2010, - "ELC" - ], [ "utopia", 2010, "winter", "day", - "ethos", - "IMPFEQ", + "OIL", + "SRE", 1990, - "FEQ" + "DSL" ], [ "utopia", - 2000, + 2010, "inter", "day", "ethos", @@ -13659,61 +18341,61 @@ [ "utopia", 2010, - "summer", - "night", - "URN", - "E21", - 2010, + "winter", + "day", + "ELC", + "E51", + 1990, "ELC" ], [ "utopia", - 2010, - "summer", + 1990, + "winter", "night", - "ELC", - "E51", + "HCO", + "E01", 1980, "ELC" ], [ "utopia", 2010, - "summer", + "winter", "day", - "ethos", - "IMPHCO1", + "OIL", + "SRE", 1990, - "HCO" + "GSL" ], [ "utopia", 2010, "summer", "day", - "ethos", - "IMPURN1", - 1990, - "URN" + "FEQ", + "E21", + 2010, + "ELC" ], [ "utopia", 1990, - "winter", - "night", + "inter", + "day", "ethos", - "IMPOIL1", + "IMPDSL1", 1990, - "OIL" + "DSL" ], [ "utopia", + 2010, + "inter", + "night", + "URN", + "E21", 2000, - "winter", - "day", - "ELC", - "E51", - 1990, "ELC" ], [ @@ -13721,16 +18403,16 @@ 1990, "winter", "day", - "DSL", - "E70", - 1960, + "FEQ", + "E21", + 1990, "ELC" ], [ "utopia", - 1990, + 2000, "inter", - "night", + "day", "OIL", "SRE", 1990, @@ -13738,39 +18420,39 @@ ], [ "utopia", - 2000, - "summer", + 1990, + "winter", "night", - "HCO", - "E01", - 1980, - "ELC" + "ethos", + "IMPURN1", + 1990, + "URN" ], [ "utopia", 2010, "summer", "night", - "HYD", - "E31", - 2000, + "DSL", + "E70", + 2010, "ELC" ], [ "utopia", + 2000, + "winter", + "day", + "ethos", + "IMPHYD", 1990, - "summer", - "night", - "HCO", - "E01", - 1980, - "ELC" + "HYD" ], [ "utopia", - 1990, - "inter", - "night", + 2010, + "summer", + "day", "OIL", "SRE", 1990, @@ -13778,58 +18460,28 @@ ], [ "utopia", - 1990, + 2010, "inter", "night", - "HCO", - "E01", - 1960, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ethos", - "IMPDSL1", - 1990, + "OIL", + "SRE", + 2010, "DSL" ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "HYD", - "E31", - 1980, - "ELC" - ], [ "utopia", 2010, "inter", - "day", + "night", "HCO", "E01", - 1980, + 1990, "ELC" ], [ "utopia", 2010, - "summer", + "inter", "night", "OIL", "SRE", @@ -13839,81 +18491,91 @@ [ "utopia", 2000, - "summer", + "winter", "night", - "HYD", - "E31", - 2000, + "FEQ", + "E21", + 1990, "ELC" ], [ "utopia", + 2000, + "winter", + "night", + "ethos", + "IMPFEQ", 1990, + "FEQ" + ], + [ + "utopia", + 2010, "summer", - "day", - "FEQ", - "E21", + "night", + "ethos", + "IMPGSL1", 1990, - "ELC" + "GSL" ], [ "utopia", - 2010, - "inter", + 1990, + "summer", "day", "DSL", "E70", - 2000, + 1960, "ELC" ], [ "utopia", - 2010, - "summer", + 2000, + "inter", "day", - "HYD", - "E31", + "FEQ", + "E21", 1990, "ELC" ], [ "utopia", - 2010, - "winter", - "day", - "OIL", - "SRE", 2000, - "DSL" + "winter", + "night", + "HYD", + "E31", + 1990, + "ELC" ], [ "utopia", - 2000, - "winter", + 1990, + "summer", "day", "ethos", - "IMPDSL1", + "IMPFEQ", 1990, - "DSL" + "FEQ" ], [ "utopia", 2010, - "winter", - "night", - "FEQ", - "E21", + "inter", + "day", + "OIL", + "SRE", 2000, - "ELC" + "GSL" ], [ "utopia", 2010, "inter", - "night", - "FEQ", - "E21", - 2010, + "day", + "ELC", + "E51", + 1990, "ELC" ], [ @@ -13921,29 +18583,29 @@ 2010, "winter", "day", - "OIL", - "SRE", + "HCO", + "E01", 2000, - "GSL" + "ELC" ], [ "utopia", - 2010, - "summer", - "night", - "OIL", - "SRE", 2000, - "DSL" + "winter", + "day", + "FEQ", + "E21", + 2000, + "ELC" ], [ "utopia", - 2010, - "summer", + 1990, + "inter", "night", "ELC", "E51", - 2000, + 1980, "ELC" ], [ @@ -13953,24 +18615,14 @@ "night", "HCO", "E01", - 1980, + 2000, "ELC" ], [ "utopia", - 2010, - "summer", + 2000, + "inter", "day", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", "OIL", "SRE", 2000, @@ -13978,23 +18630,23 @@ ], [ "utopia", - 2000, - "summer", - "night", - "FEQ", - "E21", 1990, - "ELC" + "inter", + "day", + "ethos", + "IMPHYD", + 1990, + "HYD" ], [ "utopia", + 2010, + "inter", + "night", + "ethos", + "IMPHCO1", 1990, - "winter", - "day", - "DSL", - "E70", - 1980, - "ELC" + "HCO" ], [ "utopia", @@ -14003,14 +18655,24 @@ "night", "ELC", "E51", - 1980, + 2000, "ELC" ], + [ + "utopia", + 2000, + "summer", + "night", + "OIL", + "SRE", + 1990, + "DSL" + ], [ "utopia", 2010, - "winter", - "day", + "inter", + "night", "HYD", "E31", 2000, @@ -14018,92 +18680,82 @@ ], [ "utopia", - 1990, + 2000, "summer", "night", - "DSL", - "E70", + "OIL", + "SRE", 1990, - "ELC" + "GSL" ], [ "utopia", 1990, - "inter", + "winter", "night", - "ethos", - "IMPURN1", + "DSL", + "E70", 1990, - "URN" + "ELC" ], [ "utopia", 1990, - "winter", + "summer", "day", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ethos", - "IMPDSL1", + "DSL", + "E70", 1990, - "DSL" + "ELC" ], [ "utopia", - 2000, + 2010, "summer", "day", - "FEQ", - "E21", - 1990, - "ELC" + "OIL", + "SRE", + 2010, + "DSL" ], [ "utopia", 2010, - "summer", - "night", - "HCO", - "E01", + "inter", + "day", + "URN", + "E21", 2010, "ELC" ], [ "utopia", 1990, - "winter", - "day", - "HCO", - "E01", - 1970, + "inter", + "night", + "HYD", + "E31", + 1980, "ELC" ], [ "utopia", 2000, - "summer", - "day", - "DSL", - "E70", - 1970, + "inter", + "night", + "FEQ", + "E21", + 2000, "ELC" ], [ "utopia", - 1990, - "winter", - "night", + 2000, + "inter", + "day", "HCO", "E01", - 1960, + 1970, "ELC" ], [ @@ -14111,56 +18763,66 @@ 2010, "summer", "day", - "FEQ", - "E21", + "HCO", + "E01", 1990, "ELC" ], [ "utopia", - 2000, + 2010, "summer", "day", "OIL", "SRE", - 1990, + 2010, "GSL" ], + [ + "utopia", + 2010, + "summer", + "night", + "ethos", + "IMPFEQ", + 1990, + "FEQ" + ], [ "utopia", 2000, "inter", "night", - "ELC", - "E51", + "URN", + "E21", 2000, "ELC" ], [ "utopia", + 2010, + "winter", + "night", + "ethos", + "IMPHYD", 1990, - "summer", - "day", - "URN", - "E21", - 1990, - "ELC" + "HYD" ], [ "utopia", - 1990, + 2000, "inter", - "night", + "day", "HCO", "E01", - 1990, + 2000, "ELC" ], [ "utopia", 2010, "winter", - "day", + "night", "ELC", "E51", 2000, @@ -14168,19 +18830,19 @@ ], [ "utopia", - 2010, - "inter", - "night", - "URN", - "E21", - 2010, - "ELC" + 1990, + "summer", + "day", + "ethos", + "IMPHYD", + 1990, + "HYD" ], [ "utopia", - 2000, - "winter", - "day", + 1990, + "summer", + "night", "HYD", "E31", 1990, @@ -14189,7 +18851,7 @@ [ "utopia", 2010, - "inter", + "winter", "night", "OIL", "SRE", @@ -14199,188 +18861,158 @@ [ "utopia", 2010, - "inter", - "night", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "HCO", - "E01", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL", - "E70", - 2000, + "summer", + "day", + "ELC", + "E51", + 1990, "ELC" ], [ "utopia", - 1990, - "winter", + 2010, + "inter", "night", - "HCO", - "E01", + "ethos", + "IMPOIL1", 1990, - "ELC" + "OIL" ], [ "utopia", - 2000, + 2010, "inter", "night", - "HYD", - "E31", - 2000, + "ELC", + "E51", + 1990, "ELC" ], [ "utopia", 1990, - "summer", + "inter", "day", "ethos", - "IMPDSL1", + "IMPHCO1", 1990, - "DSL" + "HCO" ], [ "utopia", - 2010, - "inter", + 1990, + "winter", "day", - "ELC", - "E51", - 2000, - "ELC" + "ethos", + "IMPFEQ", + 1990, + "FEQ" ], [ "utopia", 2000, - "summer", - "night", - "ELC", - "E51", + "winter", + "day", + "HCO", + "E01", 2000, "ELC" ], [ "utopia", - 2010, - "winter", + 1990, + "inter", "day", "HCO", "E01", - 2010, + 1970, "ELC" ], [ "utopia", - 1990, + 2000, "inter", "day", - "HYD", - "E31", - 1990, + "DSL", + "E70", + 1970, "ELC" ], [ "utopia", - 1990, - "inter", - "night", - "ELC", - "E51", - 1990, + 2000, + "summer", + "day", + "URN", + "E21", + 2000, "ELC" ], [ "utopia", - 1990, + 2010, "winter", "night", - "HYD", - "E31", + "DSL", + "E70", 1980, "ELC" ], [ "utopia", 2010, - "inter", + "winter", "night", - "HYD", - "E31", - 1980, - "ELC" + "OIL", + "SRE", + 2000, + "GSL" ], [ "utopia", - 1990, - "winter", - "night", + 2000, + "inter", + "day", "DSL", "E70", - 1970, + 2000, "ELC" ], [ "utopia", - 2000, - "summer", + 1990, + "inter", "night", "ethos", - "IMPDSL1", + "IMPHYD", 1990, - "DSL" + "HYD" ], [ "utopia", 2010, - "inter", - "night", - "DSL", - "E70", - 1980, + "winter", + "day", + "FEQ", + "E21", + 2000, "ELC" ], [ "utopia", - 2000, - "summer", + 2010, + "winter", "day", - "HCO", - "E01", + "ethos", + "IMPGSL1", 1990, - "ELC" + "GSL" ], [ "utopia", - 2000, - "winter", - "night", + 2010, + "inter", + "day", "HYD", "E31", 2000, @@ -14391,87 +19023,87 @@ 1990, "summer", "night", - "ethos", - "IMPDSL1", + "FEQ", + "E21", 1990, - "DSL" + "ELC" ], [ "utopia", 2010, - "summer", - "day", + "inter", + "night", "ELC", "E51", - 2000, + 2010, "ELC" ], [ "utopia", 2000, "summer", - "night", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2010, - "summer", "day", - "OIL", - "SRE", + "ethos", + "IMPDSL1", 1990, "DSL" ], [ "utopia", 2000, - "summer", + "inter", "night", - "OIL", - "SRE", - 2000, - "GSL" + "DSL", + "E70", + 1970, + "ELC" ], [ "utopia", 2000, - "summer", + "inter", "night", - "ELC", - "E51", + "ethos", + "IMPOIL1", 1990, - "ELC" + "OIL" ], [ "utopia", 2010, "winter", "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" + "DSL", + "E70", + 2010, + "ELC" ], [ "utopia", - 1990, + 2000, "winter", "night", - "ELC", - "E51", + "URN", + "E21", + 2000, + "ELC" + ], + [ + "utopia", 1990, + "inter", + "day", + "DSL", + "E70", + 1980, "ELC" ], [ "utopia", - 2000, + 2010, "winter", "day", - "FEQ", + "URN", "E21", 1990, "ELC" @@ -14479,102 +19111,92 @@ [ "utopia", 2010, - "summer", - "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" + "winter", + "night", + "URN", + "E21", + 2010, + "ELC" ], [ "utopia", - 2010, + 2000, "winter", "day", - "ethos", - "IMPOIL1", + "DSL", + "E70", 1990, - "OIL" + "ELC" ], [ "utopia", - 2010, - "inter", - "day", - "OIL", - "SRE", 2000, - "DSL" + "inter", + "night", + "HCO", + "E01", + 1980, + "ELC" ], [ "utopia", - 2010, + 1990, "inter", "night", - "DSL", - "E70", - 2010, + "FEQ", + "E21", + 1990, "ELC" ], [ "utopia", - 1990, + 2000, "inter", "night", "ethos", - "IMPDSL1", + "IMPURN1", 1990, - "DSL" + "URN" ], [ "utopia", 2010, "winter", "day", - "HCO", - "E01", + "HYD", + "E31", 1980, "ELC" ], [ "utopia", - 1990, + 2000, "winter", "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" + "DSL", + "E70", + 1980, + "ELC" ], [ "utopia", 1990, "summer", - "day", + "night", "DSL", "E70", - 1980, + 1970, "ELC" ], [ "utopia", - 2000, - "inter", + 1990, + "summer", "day", "OIL", "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ethos", - "IMPFEQ", 1990, - "FEQ" + "DSL" ], [ "utopia", @@ -14582,74 +19204,54 @@ "winter", "day", "ethos", - "IMPURN1", + "IMPDSL1", 1990, - "URN" + "DSL" ], [ "utopia", 2010, - "inter", + "winter", "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" + "HYD", + "E31", + 2000, + "ELC" ], [ "utopia", - 2010, + 1990, "summer", - "night", - "ethos", - "IMPDSL1", + "day", + "OIL", + "SRE", 1990, - "DSL" + "GSL" ], [ "utopia", 1990, - "inter", - "day", - "DSL", - "E70", - 1960, - "ELC" - ], - [ - "utopia", - 2010, "summer", "day", - "DSL", - "E70", + "ELC", + "E51", 1980, "ELC" ], - [ - "utopia", - 2010, - "winter", - "night", - "URN", - "E21", - 1990, - "ELC" - ], [ "utopia", 2000, - "winter", - "day", + "inter", + "night", "DSL", "E70", - 1970, + 2000, "ELC" ], [ "utopia", 2010, - "inter", + "winter", "night", "HCO", "E01", @@ -14658,102 +19260,102 @@ ], [ "utopia", - 2000, - "winter", + 2010, + "summer", "night", "FEQ", "E21", - 2000, + 1990, "ELC" ], [ "utopia", - 1990, - "summer", + 2010, + "winter", "day", "DSL", "E70", - 1970, + 2000, "ELC" ], [ "utopia", - 2010, + 1990, "inter", "day", "OIL", "SRE", - 2010, - "GSL" + 1990, + "DSL" ], [ "utopia", - 1990, - "winter", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" + 2010, + "summer", + "night", + "ELC", + "E51", + 2010, + "ELC" ], [ "utopia", 2010, - "inter", + "summer", "day", "URN", "E21", - 1990, + 2000, "ELC" ], [ "utopia", 1990, - "inter", - "day", + "summer", + "night", + "OIL", + "SRE", + 1990, + "DSL" + ], + [ + "utopia", + 2000, + "winter", + "night", "DSL", "E70", - 1990, + 1970, "ELC" ], [ "utopia", 1990, - "inter", + "summer", "night", - "ethos", - "IMPFEQ", + "OIL", + "SRE", 1990, - "FEQ" + "GSL" ], [ "utopia", - 2010, - "inter", - "day", - "ethos", - "IMPDSL1", 1990, - "DSL" - ], - [ - "utopia", - 2010, "summer", - "day", - "DSL", - "E70", - 2010, + "night", + "ELC", + "E51", + 1980, "ELC" ], [ "utopia", - 2000, - "inter", - "day", + 1990, + "summer", + "night", "HCO", "E01", - 1990, + 1960, "ELC" ], [ @@ -14761,18 +19363,18 @@ 1990, "inter", "day", - "URN", - "E21", + "ethos", + "IMPGSL1", 1990, - "ELC" + "GSL" ], [ "utopia", - 2010, - "inter", + 1990, + "summer", "day", - "HYD", - "E31", + "HCO", + "E01", 1980, "ELC" ], @@ -14780,17 +19382,17 @@ "utopia", 2000, "inter", - "day", - "URN", - "E21", + "night", + "OIL", + "SRE", 1990, - "ELC" + "DSL" ], [ "utopia", 2010, - "inter", - "night", + "winter", + "day", "HYD", "E31", 2010, @@ -14800,150 +19402,110 @@ "utopia", 2000, "inter", - "day", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "HCO", - "E01", + "night", + "ELC", + "E51", 1980, "ELC" ], [ "utopia", - 1990, + 2000, "inter", "night", - "HYD", - "E31", + "OIL", + "SRE", 1990, - "ELC" + "GSL" ], [ "utopia", - 2000, - "inter", + 1990, + "winter", "day", - "HCO", - "E01", - 1980, + "URN", + "E21", + 1990, "ELC" ], [ "utopia", - 2010, - "summer", - "day", - "HCO", - "E01", 2000, - "ELC" - ], - [ - "utopia", - 2010, - "winter", + "summer", "night", - "ELC", - "E51", - 1980, + "URN", + "E21", + 1990, "ELC" ], [ "utopia", 1990, "inter", - "day", - "ethos", - "IMPURN1", - 1990, - "URN" + "night", + "HCO", + "E01", + 1970, + "ELC" ], [ "utopia", 2000, - "inter", + "summer", "day", - "ethos", - "IMPHCO1", + "HYD", + "E31", 1990, - "HCO" + "ELC" ], [ "utopia", 2000, - "inter", + "winter", "day", - "ethos", - "IMPURN1", + "OIL", + "SRE", 1990, - "URN" + "DSL" ], [ "utopia", 2010, - "winter", - "night", + "inter", + "day", "ethos", - "IMPGSL1", + "IMPOIL1", 1990, - "GSL" + "OIL" ], [ "utopia", 2000, "winter", "day", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "FEQ", - "E21", - 2010, + "ELC", + "E51", + 2000, "ELC" ], [ "utopia", 2000, - "winter", + "inter", "day", - "ethos", - "IMPOIL1", + "HYD", + "E31", 1990, - "OIL" + "ELC" ], [ "utopia", 2010, "inter", "day", - "HYD", - "E31", - 2010, + "DSL", + "E70", + 1980, "ELC" ], [ @@ -14951,140 +19513,150 @@ 2000, "winter", "night", - "OIL", - "SRE", + "DSL", + "E70", 2000, - "GSL" + "ELC" ], [ "utopia", - 2000, - "inter", + 2010, + "summer", "night", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", + "ELC", + "RHE", 2000, - "summer", - "day", - "ethos", - "IMPFEQ", - 1990, - "FEQ" + "RH" ], [ "utopia", 2000, - "inter", + "winter", "night", - "OIL", - "SRE", - 2000, - "GSL" + "DSL", + "RHO", + 1990, + "RH" ], [ "utopia", - 2000, + 2010, "summer", "day", - "URN", - "E21", - 1990, - "ELC" + "ELC", + "RHE", + 2010, + "RH" ], [ "utopia", - 2000, + 2010, "winter", "day", - "ethos", - "IMPFEQ", - 1990, - "FEQ" + "DSL", + "RHO", + 2000, + "RH" ], [ "utopia", 2000, - "winter", + "inter", "day", - "HCO", - "E01", - 1980, - "ELC" + "ELC", + "TXE", + 1990, + "TX" ], [ "utopia", 2010, - "inter", + "summer", "day", - "FEQ", - "E21", - 2000, - "ELC" + "DSL", + "RHO", + 2010, + "RH" ], [ "utopia", - 2000, + 2010, "winter", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" + "night", + "ELC", + "RL1", + 2010, + "RL" ], [ "utopia", 2000, - "winter", + "summer", "day", - "ethos", - "IMPURN1", + "ELC", + "TXE", 1990, - "URN" + "TX" ], [ "utopia", - 2000, + 1990, "winter", "night", - "OIL", - "SRE", + "ELC", + "RL1", 1990, - "DSL" + "RL" + ], + [ + "utopia", + 2010, + "inter", + "day", + "ELC", + "RHE", + 2010, + "RH" ], [ "utopia", 2010, "winter", + "day", + "DSL", + "TXD", + 2000, + "TX" + ], + [ + "utopia", + 2010, + "summer", "night", "ELC", - "E51", + "RL1", 2010, - "ELC" + "RL" ], [ "utopia", 2010, "summer", - "night", - "ethos", - "IMPHYD", - 1990, - "HYD" + "day", + "DSL", + "TXD", + 2010, + "TX" ], [ "utopia", 2000, - "winter", + "inter", "night", - "OIL", - "SRE", + "DSL", + "RHO", 1990, - "GSL" + "RH" ], [ "utopia", @@ -15092,1989 +19664,2009 @@ "winter", "day", "DSL", - "E70", - 2000, - "ELC" + "TXD", + 1980, + "TX" ], [ "utopia", - 2010, - "winter", - "night", - "OIL", - "SRE", - 2000, - "DSL" + 1990, + "summer", + "day", + "ELC", + "TXE", + 1990, + "TX" ], [ "utopia", 2010, - "inter", + "winter", "night", - "ELC", - "E51", + "DSL", + "RHO", 2000, - "ELC" + "RH" ], [ "utopia", - 2000, - "inter", + 1990, + "winter", "night", "DSL", - "E70", + "RHO", 1980, - "ELC" + "RH" ], [ "utopia", 2000, - "inter", - "night", - "HCO", - "E01", + "summer", + "day", + "DSL", + "RHO", 1990, - "ELC" + "RH" ], [ "utopia", - 2010, - "winter", - "night", - "ethos", - "IMPURN1", + 2000, + "summer", + "day", + "GSL", + "TXG", 1990, - "URN" + "TX" ], [ "utopia", 2010, - "winter", - "day", - "DSL", - "E70", - 1980, - "ELC" + "inter", + "night", + "GSL", + "TXG", + 2000, + "TX" ], [ "utopia", - 1990, - "summer", + 2000, + "winter", "day", "ELC", - "E51", + "RHE", 1990, - "ELC" + "RH" ], [ "utopia", 1990, - "summer", + "winter", "night", - "URN", - "E21", + "DSL", + "TXD", 1990, - "ELC" + "TX" ], [ "utopia", - 2010, - "inter", + 2000, + "winter", "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" + "DSL", + "RHO", + 1980, + "RH" ], [ "utopia", 2010, "winter", "night", - "DSL", - "E70", + "ELC", + "TXE", 2000, - "ELC" + "TX" ], [ "utopia", 2010, "summer", - "night", - "FEQ", - "E21", + "day", + "ELC", + "RHE", 2000, - "ELC" + "RH" ], [ "utopia", - 2000, - "winter", - "night", - "ethos", - "IMPOIL1", 1990, - "OIL" + "inter", + "day", + "ELC", + "RL1", + 1990, + "RL" ], [ "utopia", 1990, - "summer", + "winter", "day", - "HCO", - "E01", - 1960, - "ELC" + "GSL", + "TXG", + 1980, + "TX" ], [ "utopia", 2000, - "inter", - "night", - "ethos", - "IMPHCO1", + "winter", + "day", + "ELC", + "TXE", 1990, - "HCO" + "TX" ], [ "utopia", - 1990, - "inter", + 2000, + "winter", "day", - "ELC", - "E51", + "GSL", + "TXG", 1990, - "ELC" + "TX" ], [ "utopia", 2010, "inter", "day", - "ethos", - "IMPHYD", - 1990, - "HYD" + "ELC", + "RL1", + 2010, + "RL" ], [ "utopia", - 1990, + 2000, "summer", "night", - "ELC", - "E51", + "GSL", + "TXG", 1990, - "ELC" + "TX" ], [ "utopia", 2010, - "winter", - "night", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", + "inter", + "day", + "ELC", + "TXE", 2000, - "winter", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" + "TX" ], [ "utopia", 2000, - "summer", + "winter", "night", - "URN", - "E21", + "GSL", + "TXG", 2000, - "ELC" + "TX" ], [ "utopia", 1990, - "inter", - "night", + "winter", + "day", "DSL", - "E70", - 1970, - "ELC" + "RHO", + 1990, + "RH" ], [ "utopia", 2010, "winter", - "night", - "ethos", - "IMPOIL1", + "day", + "DSL", + "RHO", 1990, - "OIL" + "RH" ], [ "utopia", - 2000, + 2010, "summer", "day", - "HYD", - "E31", + "DSL", + "RHO", 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "HYD", - "E31", - 1980, - "ELC" + "RH" ], [ "utopia", 2010, "winter", - "night", - "HYD", - "E31", - 1980, - "ELC" + "day", + "ELC", + "RHE", + 2010, + "RH" ], [ "utopia", 1990, - "summer", + "winter", "day", - "ethos", - "IMPOIL1", + "DSL", + "TXD", 1990, - "OIL" + "TX" ], [ "utopia", 2010, - "winter", - "night", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", + "inter", + "day", + "ELC", + "RHE", 2000, - "summer", - "night", - "DSL", - "E70", - 1970, - "ELC" + "RH" ], [ "utopia", 1990, "winter", "night", - "ethos", - "IMPHYD", - 1990, - "HYD" + "DSL", + "TXD", + 1980, + "TX" ], [ "utopia", - 2010, - "winter", + 1990, + "inter", "day", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "E51", + "DSL", + "TXD", 1990, - "ELC" + "TX" ], [ "utopia", - 2000, + 2010, "winter", "night", - "HCO", - "E01", - 1970, - "ELC" + "DSL", + "RHO", + 1990, + "RH" ], [ "utopia", - 2010, + 2000, "summer", "night", - "URN", - "E21", + "ELC", + "TXE", 2000, - "ELC" + "TX" ], [ "utopia", - 2000, - "summer", + 2010, + "winter", "night", - "ethos", - "IMPOIL1", - 1990, - "OIL" + "DSL", + "TXD", + 2010, + "TX" ], [ "utopia", 1990, - "summer", + "inter", "day", - "ethos", - "IMPHCO1", + "ELC", + "RHE", 1990, - "HCO" + "RH" ], [ "utopia", - 1990, + 2010, "summer", "day", - "ethos", - "IMPURN1", + "ELC", + "RHE", 1990, - "URN" + "RH" ], [ "utopia", 1990, - "winter", + "inter", "day", - "DSL", - "E70", - 1970, - "ELC" + "ELC", + "TXE", + 1990, + "TX" ], [ "utopia", - 2010, + 2000, "winter", "day", - "HYD", - "E31", - 1990, - "ELC" + "DSL", + "RHO", + 1980, + "RH" ], [ "utopia", 2000, "winter", - "night", - "DSL", - "E70", - 1990, - "ELC" + "day", + "GSL", + "TXG", + 1980, + "TX" ], [ "utopia", - 1990, - "summer", + 2000, + "inter", "night", - "DSL", - "E70", - 1980, - "ELC" + "GSL", + "TXG", + 2000, + "TX" ], [ "utopia", 2000, "winter", - "night", - "HCO", - "E01", + "day", + "DSL", + "TXD", 2000, - "ELC" + "TX" ], [ "utopia", - 2010, + 2000, "winter", "night", - "HYD", - "E31", - 2010, - "ELC" + "DSL", + "TXD", + 1990, + "TX" ], [ "utopia", 2000, - "summer", - "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" + "inter", + "day", + "DSL", + "TXD", + 1980, + "TX" ], [ "utopia", - 2010, - "winter", + 1990, + "summer", "night", - "HCO", - "E01", - 2010, - "ELC" + "ELC", + "RL1", + 1990, + "RL" ], [ "utopia", - 2000, + 1990, "summer", "night", - "ethos", - "IMPHCO1", + "GSL", + "TXG", 1990, - "HCO" + "TX" ], [ "utopia", + 2010, + "winter", + "day", + "ELC", + "TXE", 2000, - "summer", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" + "TX" ], [ "utopia", 1990, - "inter", + "summer", "night", - "DSL", - "E70", + "ELC", + "TXE", 1990, - "ELC" + "TX" ], [ "utopia", 1990, "winter", - "day", - "OIL", - "SRE", + "night", + "ELC", + "RHE", 1990, - "DSL" + "RH" ], [ "utopia", - 2010, - "winter", - "day", - "DSL", - "E70", - 2010, - "ELC" + 2000, + "inter", + "night", + "ELC", + "RHE", + 2000, + "RH" ], [ "utopia", 2000, + "summer", + "night", + "GSL", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + 2010, "winter", - "day", + "night", "ELC", - "E51", - 1980, - "ELC" + "RHE", + 2000, + "RH" ], [ "utopia", - 1990, + 2000, "winter", - "day", - "OIL", - "SRE", + "night", + "GSL", + "TXG", 1990, - "GSL" + "TX" ], [ "utopia", 1990, "winter", "day", - "ELC", - "E51", + "DSL", + "RHO", 1980, - "ELC" + "RH" ], [ "utopia", - 2010, - "summer", - "day", - "URN", - "E21", - 2010, - "ELC" + 2000, + "inter", + "night", + "ELC", + "TXE", + 2000, + "TX" ], [ "utopia", - 1990, + 2000, "winter", - "day", - "HCO", - "E01", - 1960, - "ELC" + "night", + "ELC", + "RHE", + 1990, + "RH" ], [ "utopia", - 1990, + 2010, "inter", "night", - "URN", - "E21", + "DSL", + "RHO", 1990, - "ELC" + "RH" + ], + [ + "utopia", + 1990, + "inter", + "day", + "DSL", + "RHO", + 1980, + "RH" ], [ "utopia", 2000, "summer", "night", - "HCO", - "E01", - 1970, - "ELC" + "ELC", + "RL1", + 2000, + "RL" ], [ "utopia", - 1990, + 2010, "winter", - "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" + "night", + "DSL", + "TXD", + 2000, + "TX" ], [ "utopia", 1990, "inter", "night", - "ethos", - "IMPOIL1", + "GSL", + "TXG", 1990, - "OIL" + "TX" + ], + [ + "utopia", + 2000, + "inter", + "day", + "ELC", + "RL1", + 2000, + "RL" ], [ "utopia", 1990, - "summer", + "winter", "night", - "HCO", - "E01", + "DSL", + "TXD", 1970, - "ELC" + "TX" ], [ "utopia", - 1990, - "summer", + 2010, + "inter", "day", - "HCO", - "E01", - 1990, - "ELC" + "DSL", + "RHO", + 2010, + "RH" ], [ "utopia", - 2000, - "summer", + 1990, + "inter", "day", - "ELC", - "E51", + "DSL", + "TXD", 1980, - "ELC" + "TX" ], [ "utopia", - 2010, + 2000, "summer", "day", - "ethos", - "IMPOIL1", + "DSL", + "TXD", 1990, - "OIL" + "TX" ], [ "utopia", - 2000, + 2010, "inter", "night", "ELC", - "E51", - 1990, - "ELC" + "RL1", + 2010, + "RL" ], [ "utopia", 2010, + "inter", + "day", + "DSL", + "TXD", + 2010, + "TX" + ], + [ + "utopia", + 2000, "summer", "night", - "ethos", - "IMPOIL1", + "DSL", + "RHO", 1990, - "OIL" + "RH" ], [ "utopia", - 2010, - "summer", - "day", - "HYD", - "E31", - 1980, - "ELC" + 2000, + "winter", + "night", + "DSL", + "RHO", + 2000, + "RH" ], [ "utopia", - 1990, + 2000, "inter", + "day", + "ELC", + "RHE", + 1990, + "RH" + ], + [ + "utopia", + 2010, + "summer", "night", - "HCO", - "E01", - 1980, - "ELC" + "DSL", + "RHO", + 2000, + "RH" ], [ "utopia", 2010, - "winter", - "day", - "ethos", - "IMPHYD", - 1990, - "HYD" + "summer", + "night", + "ELC", + "TXE", + 2010, + "TX" ], [ "utopia", 2000, - "winter", + "inter", "night", - "ethos", - "IMPGSL1", + "DSL", + "TXD", 1990, - "GSL" + "TX" ], [ "utopia", - 2000, - "winter", + 1990, + "summer", "day", - "HYD", - "E31", - 1980, - "ELC" + "DSL", + "TXD", + 1970, + "TX" ], [ "utopia", - 2000, + 1990, "winter", - "day", - "OIL", - "SRE", - 2000, - "DSL" + "night", + "GSL", + "TXG", + 1980, + "TX" ], [ "utopia", - 1990, + 2000, "winter", "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" + "DSL", + "TXD", + 1980, + "TX" ], [ "utopia", 2000, - "summer", + "inter", "night", - "HYD", - "E31", + "GSL", + "TXG", 1990, - "ELC" + "TX" ], [ "utopia", 1990, "winter", "day", - "HCO", - "E01", + "ELC", + "TXE", 1990, - "ELC" + "TX" ], [ "utopia", - 2000, - "inter", - "day", - "HYD", - "E31", - 2000, - "ELC" + 1990, + "summer", + "night", + "GSL", + "TXG", + 1980, + "TX" ], [ "utopia", - 2010, - "inter", + 1990, + "summer", "day", - "DSL", - "E70", + "ELC", + "RL1", 1990, - "ELC" + "RL" ], [ "utopia", - 2010, - "inter", - "day", - "HCO", - "E01", 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", + "inter", "night", - "ethos", - "IMPHCO1", + "ELC", + "RHE", 1990, - "HCO" + "RH" ], [ "utopia", - 2010, - "summer", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" + 2000, + "inter", + "day", + "GSL", + "TXG", + 2000, + "TX" ], [ "utopia", 2010, "winter", "night", - "FEQ", - "E21", + "ELC", + "RHE", 1990, - "ELC" + "RH" ], [ "utopia", 2000, "inter", - "night", - "HYD", - "E31", - 1990, - "ELC" + "day", + "DSL", + "RHO", + 1980, + "RH" ], [ "utopia", - 2000, - "inter", - "day", - "ELC", - "E51", 1990, - "ELC" + "inter", + "night", + "DSL", + "RHO", + 1980, + "RH" ], [ "utopia", - 2010, + 1990, "inter", - "night", - "FEQ", - "E21", - 2000, - "ELC" + "day", + "DSL", + "RHO", + 1970, + "RH" ], [ "utopia", 2010, "summer", "night", - "OIL", - "SRE", + "ELC", + "RHE", 1990, - "DSL" + "RH" ], [ "utopia", - 2010, - "summer", - "day", - "HYD", - "E31", - 2010, - "ELC" + 1990, + "inter", + "night", + "GSL", + "TXG", + 1980, + "TX" ], [ "utopia", - 1990, - "winter", + 2000, + "summer", "day", - "HYD", - "E31", - 1990, - "ELC" + "DSL", + "RHO", + 1980, + "RH" ], [ "utopia", - 2000, + 1990, "summer", "night", "DSL", - "E70", - 2000, - "ELC" + "RHO", + 1990, + "RH" ], [ "utopia", - 1990, - "inter", + 2000, + "winter", "day", - "HYD", - "E31", - 1980, - "ELC" + "ELC", + "TXE", + 2000, + "TX" ], [ "utopia", - 1990, + 2010, "winter", "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" + "GSL", + "TXG", + 2010, + "TX" ], [ "utopia", - 2010, + 2000, "summer", - "night", + "day", "DSL", - "E70", - 1990, - "ELC" + "TXD", + 1980, + "TX" ], [ "utopia", 2000, "summer", - "day", - "OIL", - "SRE", + "night", + "DSL", + "TXD", 2000, - "DSL" + "TX" ], [ "utopia", - 1990, + 2010, "summer", "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" + "ELC", + "TXE", + 2010, + "TX" ], [ "utopia", 1990, "winter", "night", - "DSL", - "E70", - 1960, - "ELC" + "ELC", + "RL1", + 1980, + "RL" ], [ "utopia", - 2010, - "summer", - "night", - "HYD", - "E31", 1990, - "ELC" + "winter", + "day", + "GSL", + "TXG", + 1970, + "TX" ], [ "utopia", 2000, - "summer", + "winter", "day", - "ELC", - "E51", + "GSL", + "TXG", 2000, - "ELC" + "TX" ], [ "utopia", - 2000, + 2010, "summer", - "day", - "HCO", - "E01", - 1980, - "ELC" + "night", + "DSL", + "TXD", + 2010, + "TX" ], [ "utopia", - 2000, + 1990, "summer", - "day", - "OIL", - "SRE", - 2000, - "GSL" + "night", + "DSL", + "TXD", + 1990, + "TX" ], [ "utopia", 2000, - "summer", + "inter", "night", - "ELC", - "E51", + "DSL", + "RHO", 1980, - "ELC" + "RH" ], [ "utopia", 1990, "winter", - "night", + "day", "ELC", - "E51", - 1980, - "ELC" + "RL1", + 1990, + "RL" ], [ "utopia", 2000, "summer", - "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" + "day", + "ELC", + "RHE", + 2000, + "RH" ], [ "utopia", 2010, - "inter", + "winter", "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" + "GSL", + "TXG", + 2010, + "TX" ], [ "utopia", - 1990, + 2010, "summer", "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" + "GSL", + "TXG", + 2010, + "TX" ], [ "utopia", 1990, - "winter", - "night", - "URN", - "E21", - 1990, - "ELC" + "summer", + "day", + "GSL", + "TXG", + 1980, + "TX" ], [ "utopia", - 2010, - "inter", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" + 2000, + "summer", + "day", + "GSL", + "TXG", + 1980, + "TX" ], [ "utopia", 2000, - "summer", - "night", - "HCO", - "E01", + "inter", + "day", + "DSL", + "TXD", 2000, - "ELC" + "TX" ], [ "utopia", - 2010, - "inter", + 1990, + "winter", "night", - "DSL", - "E70", - 2000, - "ELC" + "GSL", + "TXG", + 1970, + "TX" ], [ "utopia", - 2000, - "inter", - "night", - "ethos", - "IMPFEQ", 1990, - "FEQ" + "winter", + "day", + "DSL", + "TXD", + 1980, + "TX" ], [ "utopia", - 2010, + 2000, "winter", "day", - "OIL", - "SRE", - 1990, - "DSL" + "ELC", + "RL1", + 2000, + "RL" ], [ "utopia", - 2010, + 1990, "inter", - "day", - "ethos", - "IMPGSL1", + "night", + "DSL", + "TXD", 1990, - "GSL" + "TX" ], [ "utopia", - 2010, - "winter", - "day", + 2000, + "summer", + "night", "ELC", - "E51", + "TXE", 1990, - "ELC" + "TX" ], [ "utopia", 1990, - "winter", + "inter", "night", - "HCO", - "E01", + "GSL", + "TXG", + 1970, + "TX" + ], + [ + "utopia", + 1990, + "summer", + "night", + "DSL", + "RHO", 1980, - "ELC" + "RH" ], [ "utopia", 2010, "winter", "day", - "OIL", - "SRE", - 1990, - "GSL" + "GSL", + "TXG", + 2000, + "TX" ], [ "utopia", - 2010, + 2000, "summer", - "day", - "FEQ", - "E21", - 2010, - "ELC" + "night", + "ELC", + "RHE", + 1990, + "RH" ], [ "utopia", - 1990, - "inter", + 2010, + "summer", "day", - "ethos", - "IMPDSL1", + "DSL", + "RHO", 1990, - "DSL" + "RH" ], [ "utopia", - 2010, - "inter", + 2000, + "winter", "night", - "URN", - "E21", + "DSL", + "TXD", 2000, - "ELC" + "TX" ], [ "utopia", 1990, - "winter", + "summer", "day", - "FEQ", - "E21", + "DSL", + "RHO", 1990, - "ELC" + "RH" ], [ "utopia", - 2000, - "inter", + 2010, + "winter", "day", - "OIL", - "SRE", - 1990, - "DSL" + "ELC", + "RHE", + 2000, + "RH" ], [ "utopia", 1990, - "winter", + "inter", "night", - "ethos", - "IMPURN1", + "ELC", + "RL1", 1990, - "URN" + "RL" ], [ "utopia", 2010, "summer", - "night", - "DSL", - "E70", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "winter", "day", - "ethos", - "IMPHYD", - 1990, - "HYD" + "ELC", + "TXE", + 2000, + "TX" ], [ "utopia", 2010, "summer", - "day", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "inter", "night", - "OIL", - "SRE", - 2010, - "DSL" + "DSL", + "TXD", + 2000, + "TX" ], [ "utopia", 2010, "inter", "night", - "HCO", - "E01", - 1990, - "ELC" + "ELC", + "RHE", + 2000, + "RH" ], [ "utopia", - 2010, - "inter", + 2000, + "summer", "night", - "OIL", - "SRE", - 2010, - "GSL" + "DSL", + "TXD", + 1990, + "TX" ], [ "utopia", 2000, - "winter", - "night", - "FEQ", - "E21", + "summer", + "day", + "ELC", + "RHE", 1990, - "ELC" + "RH" ], [ "utopia", - 2000, + 2010, "winter", "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" + "GSL", + "TXG", + 2000, + "TX" ], [ "utopia", 2010, "summer", "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" + "GSL", + "TXG", + 2000, + "TX" + ], + [ + "utopia", + 2010, + "winter", + "day", + "DSL", + "RHO", + 2010, + "RH" ], [ "utopia", 1990, "summer", "day", - "DSL", - "E70", - 1960, - "ELC" + "GSL", + "TXG", + 1970, + "TX" ], [ "utopia", - 2000, - "inter", + 2010, + "summer", "day", - "FEQ", - "E21", - 1990, - "ELC" + "GSL", + "TXG", + 2010, + "TX" ], [ "utopia", 2000, "winter", "night", - "HYD", - "E31", - 1990, - "ELC" + "ELC", + "TXE", + 2000, + "TX" ], [ "utopia", - 1990, - "summer", + 2000, + "inter", "day", - "ethos", - "IMPFEQ", + "DSL", + "TXD", 1990, - "FEQ" + "TX" ], [ "utopia", 2010, + "winter", + "day", + "DSL", + "TXD", + 2010, + "TX" + ], + [ + "utopia", + 1990, "inter", "day", - "OIL", - "SRE", - 2000, - "GSL" + "GSL", + "TXG", + 1970, + "TX" ], [ "utopia", 2010, "inter", "day", - "ELC", - "E51", - 1990, - "ELC" + "GSL", + "TXG", + 2010, + "TX" ], [ "utopia", 2010, "winter", - "day", - "HCO", - "E01", - 2000, - "ELC" + "night", + "ELC", + "RHE", + 2010, + "RH" ], [ "utopia", - 2000, + 2010, "winter", - "day", - "FEQ", - "E21", - 2000, - "ELC" + "night", + "DSL", + "RHO", + 2010, + "RH" ], [ "utopia", 1990, "inter", "night", - "ELC", - "E51", + "DSL", + "TXD", 1980, - "ELC" + "TX" ], [ "utopia", 2010, - "summer", + "inter", "night", - "HCO", - "E01", - 2000, - "ELC" + "ELC", + "TXE", + 2010, + "TX" ], [ "utopia", - 2000, - "inter", + 1990, + "summer", "day", - "OIL", - "SRE", - 2000, - "GSL" + "DSL", + "RHO", + 1980, + "RH" ], [ "utopia", 1990, "inter", "day", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" + "DSL", + "TXD", + 1970, + "TX" ], [ "utopia", 2000, - "winter", - "night", - "ELC", - "E51", + "summer", + "day", + "DSL", + "RHO", 2000, - "ELC" + "RH" ], [ "utopia", - 2000, + 1990, "summer", "night", - "OIL", - "SRE", - 1990, - "DSL" + "ELC", + "RL1", + 1980, + "RL" ], [ "utopia", 2010, - "inter", - "night", - "HYD", - "E31", + "summer", + "day", + "DSL", + "TXD", 2000, - "ELC" + "TX" ], [ "utopia", 2000, "summer", "night", - "OIL", - "SRE", - 1990, - "GSL" + "DSL", + "RHO", + 1980, + "RH" ], [ "utopia", - 1990, + 2010, "winter", "night", - "DSL", - "E70", - 1990, - "ELC" + "ELC", + "TXE", + 2010, + "TX" ], [ "utopia", 1990, - "summer", + "winter", "day", - "DSL", - "E70", + "GSL", + "TXG", 1990, - "ELC" + "TX" ], [ "utopia", - 2010, - "summer", - "day", - "OIL", - "SRE", - 2010, - "DSL" + 2000, + "inter", + "night", + "ELC", + "TXE", + 1990, + "TX" ], [ "utopia", - 2010, - "inter", + 2000, + "winter", + "night", + "GSL", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + 2000, + "winter", "day", - "URN", - "E21", - 2010, - "ELC" + "DSL", + "RHO", + 2000, + "RH" ], [ "utopia", 1990, - "inter", - "night", - "HYD", - "E31", - 1980, - "ELC" + "winter", + "day", + "DSL", + "RHO", + 1970, + "RH" ], [ "utopia", 2000, "inter", "night", - "FEQ", - "E21", - 2000, - "ELC" + "DSL", + "TXD", + 1980, + "TX" ], [ "utopia", 2000, - "inter", - "day", - "HCO", - "E01", - 1970, - "ELC" + "summer", + "night", + "DSL", + "TXD", + 1980, + "TX" ], [ "utopia", - 2010, - "summer", - "day", - "HCO", - "E01", 1990, - "ELC" + "inter", + "night", + "ELC", + "RHE", + 1990, + "RH" ], [ "utopia", 2010, - "summer", + "winter", "day", - "OIL", - "SRE", - 2010, - "GSL" + "ELC", + "RHE", + 1990, + "RH" ], [ "utopia", 2010, "summer", "night", - "ethos", - "IMPFEQ", + "DSL", + "RHO", 1990, - "FEQ" + "RH" + ], + [ + "utopia", + 1990, + "winter", + "day", + "ELC", + "RHE", + 1990, + "RH" ], [ "utopia", 2000, - "inter", + "winter", "night", - "URN", - "E21", + "ELC", + "RL1", 2000, - "ELC" + "RL" ], [ "utopia", 2010, - "winter", + "inter", "night", - "ethos", - "IMPHYD", + "ELC", + "RHE", 1990, - "HYD" + "RH" ], [ "utopia", - 2000, + 2010, "inter", "day", - "HCO", - "E01", + "DSL", + "RHO", 2000, - "ELC" + "RH" ], [ "utopia", - 2010, - "winter", + 2000, + "inter", "night", + "GSL", + "TXG", + 1980, + "TX" + ], + [ + "utopia", + 2010, + "inter", + "day", "ELC", - "E51", - 2000, - "ELC" + "TXE", + 2010, + "TX" ], [ "utopia", 1990, - "summer", + "inter", "day", - "ethos", - "IMPHYD", - 1990, - "HYD" + "ELC", + "RL1", + 1980, + "RL" ], [ "utopia", 1990, - "summer", + "winter", "night", - "HYD", - "E31", + "GSL", + "TXG", 1990, - "ELC" + "TX" ], [ "utopia", 2010, - "winter", - "night", - "OIL", - "SRE", - 1990, - "DSL" + "inter", + "day", + "DSL", + "TXD", + 2000, + "TX" ], [ "utopia", - 2010, + 1990, "summer", "day", "ELC", - "E51", - 1990, - "ELC" + "RL1", + 1980, + "RL" ], [ "utopia", - 2010, + 2000, "inter", "night", - "ethos", - "IMPOIL1", - 1990, - "OIL" + "ELC", + "RL1", + 2000, + "RL" ], [ "utopia", 2010, "inter", "night", - "ELC", - "E51", - 1990, - "ELC" + "DSL", + "RHO", + 2010, + "RH" ], [ "utopia", 1990, - "inter", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" + "winter", + "night", + "DSL", + "RHO", + 1970, + "RH" ], [ "utopia", 1990, - "winter", - "day", - "ethos", - "IMPFEQ", - 1990, - "FEQ" + "inter", + "night", + "DSL", + "RHO", + 1970, + "RH" ], [ "utopia", + 2010, + "summer", + "night", + "ELC", + "TXE", 2000, - "winter", - "day", - "HCO", - "E01", - 2000, - "ELC" + "TX" ], [ "utopia", - 1990, + 2010, "inter", - "day", - "HCO", - "E01", - 1970, - "ELC" + "night", + "DSL", + "TXD", + 2010, + "TX" ], [ "utopia", - 2000, + 2010, "inter", "day", - "DSL", - "E70", - 1970, - "ELC" + "GSL", + "TXG", + 2000, + "TX" ], [ "utopia", 2000, "summer", "day", - "URN", - "E21", + "ELC", + "RL1", 2000, - "ELC" + "RL" ], [ "utopia", - 2010, - "winter", + 1990, + "inter", "night", "DSL", - "E70", - 1980, - "ELC" + "TXD", + 1970, + "TX" ], [ "utopia", - 2010, - "winter", + 1990, + "summer", "night", - "OIL", - "SRE", - 2000, - "GSL" + "ELC", + "RHE", + 1990, + "RH" ], [ "utopia", - 2000, - "inter", + 1990, + "summer", "day", "DSL", - "E70", - 2000, - "ELC" + "RHO", + 1970, + "RH" ], [ "utopia", - 1990, + 2010, "inter", "night", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2010, - "winter", - "day", - "FEQ", - "E21", + "ELC", + "TXE", 2000, - "ELC" + "TX" ], [ "utopia", 2010, - "winter", + "inter", "day", - "ethos", - "IMPGSL1", + "ELC", + "RHE", 1990, - "GSL" + "RH" ], [ "utopia", - 2010, - "inter", - "day", - "HYD", - "E31", - 2000, - "ELC" + 1990, + "summer", + "night", + "GSL", + "TXG", + 1970, + "TX" ], [ "utopia", 1990, "summer", - "night", - "FEQ", - "E21", + "day", + "DSL", + "TXD", 1990, - "ELC" + "TX" ], [ "utopia", - 2010, + 2000, "inter", - "night", - "ELC", - "E51", - 2010, - "ELC" + "day", + "GSL", + "TXG", + 1990, + "TX" ], [ "utopia", 2000, "summer", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" + "night", + "GSL", + "TXG", + 1980, + "TX" ], [ "utopia", 2000, - "inter", - "night", + "winter", + "day", "DSL", - "E70", - 1970, - "ELC" + "RHO", + 1990, + "RH" ], [ "utopia", - 2000, + 1990, "inter", - "night", - "ethos", - "IMPOIL1", + "day", + "GSL", + "TXG", 1990, - "OIL" + "TX" ], [ "utopia", 2010, - "winter", - "night", - "DSL", - "E70", + "summer", + "day", + "ELC", + "RL1", 2010, - "ELC" + "RL" ], [ "utopia", - 2000, - "winter", - "night", - "URN", - "E21", - 2000, - "ELC" + 2010, + "inter", + "day", + "DSL", + "RHO", + 1990, + "RH" ], [ "utopia", 1990, + "summer", + "day", + "GSL", + "TXG", + 1990, + "TX" + ], + [ + "utopia", + 2000, "inter", "day", "DSL", - "E70", - 1980, - "ELC" + "RHO", + 2000, + "RH" ], [ "utopia", - 2010, - "winter", - "day", - "URN", - "E21", 1990, - "ELC" + "summer", + "night", + "DSL", + "TXD", + 1980, + "TX" ], [ "utopia", - 2010, + 2000, "winter", "night", - "URN", - "E21", - 2010, - "ELC" + "ELC", + "RHE", + 2000, + "RH" ], [ "utopia", 2000, - "winter", - "day", - "DSL", - "E70", - 1990, - "ELC" + "summer", + "night", + "ELC", + "RHE", + 2000, + "RH" ], [ "utopia", - 2000, + 2010, "inter", "night", - "HCO", - "E01", - 1980, - "ELC" + "DSL", + "RHO", + 2000, + "RH" ], [ "utopia", 1990, "inter", - "night", - "FEQ", - "E21", + "day", + "DSL", + "RHO", 1990, - "ELC" + "RH" ], [ "utopia", - 2000, - "inter", + 2010, + "summer", "night", - "ethos", - "IMPURN1", - 1990, - "URN" + "ELC", + "RHE", + 2010, + "RH" ], [ "utopia", - 2010, + 1990, "winter", "day", - "HYD", - "E31", + "ELC", + "RL1", 1980, - "ELC" + "RL" ], [ "utopia", 2000, - "winter", - "night", - "DSL", - "E70", - 1980, - "ELC" + "summer", + "day", + "ELC", + "TXE", + 2000, + "TX" ], [ "utopia", - 1990, - "summer", + 2010, + "inter", "night", "DSL", - "E70", - 1970, - "ELC" + "TXD", + 2000, + "TX" ], [ "utopia", - 1990, + 2000, "summer", "day", - "OIL", - "SRE", - 1990, - "DSL" + "DSL", + "TXD", + 2000, + "TX" ], [ "utopia", - 2010, - "winter", + 2000, + "inter", "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "HYD", - "E31", + "ELC", + "TXE", 2000, - "ELC" + "TX" ], [ "utopia", 1990, - "summer", - "day", - "OIL", - "SRE", + "inter", + "night", + "ELC", + "TXE", 1990, - "GSL" + "TX" ], [ "utopia", - 1990, - "summer", + 2010, + "winter", "day", "ELC", - "E51", - 1980, - "ELC" + "TXE", + 2010, + "TX" ], [ "utopia", @@ -17082,279 +21674,249 @@ "inter", "night", "DSL", - "E70", + "RHO", 2000, - "ELC" + "RH" ], [ "utopia", - 2010, - "winter", - "night", - "HCO", - "E01", 2000, - "ELC" + "inter", + "day", + "ELC", + "RHE", + 2000, + "RH" ], [ "utopia", - 2010, + 2000, "summer", "night", - "FEQ", - "E21", - 1990, - "ELC" + "DSL", + "RHO", + 2000, + "RH" ], [ "utopia", - 2010, + 1990, "winter", "day", "DSL", - "E70", - 2000, - "ELC" + "TXD", + 1970, + "TX" ], [ "utopia", - 1990, - "inter", + 2000, + "winter", "day", - "OIL", - "SRE", + "DSL", + "TXD", 1990, - "DSL" + "TX" ], [ "utopia", 2010, "summer", "night", - "ELC", - "E51", + "DSL", + "RHO", 2010, - "ELC" + "RH" ], [ "utopia", - 2010, + 1990, "summer", "day", - "URN", - "E21", - 2000, - "ELC" + "DSL", + "TXD", + 1980, + "TX" ], [ "utopia", - 1990, - "summer", + 2000, + "inter", "night", - "OIL", - "SRE", - 1990, - "DSL" + "DSL", + "TXD", + 2000, + "TX" ], [ "utopia", - 2000, - "winter", + 2010, + "inter", "night", - "DSL", - "E70", - 1970, - "ELC" + "ELC", + "RHE", + 2010, + "RH" ], [ "utopia", 1990, - "summer", + "winter", "night", - "OIL", - "SRE", + "ELC", + "TXE", 1990, - "GSL" + "TX" ], [ "utopia", 1990, - "summer", + "winter", "night", - "ELC", - "E51", - 1980, - "ELC" + "DSL", + "RHO", + 1990, + "RH" ], [ "utopia", - 1990, + 2000, "summer", - "night", - "HCO", - "E01", - 1960, - "ELC" + "day", + "GSL", + "TXG", + 2000, + "TX" ], [ "utopia", - 1990, + 2000, "inter", "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" + "GSL", + "TXG", + 1980, + "TX" ], [ "utopia", 1990, - "summer", + "inter", "day", - "HCO", - "E01", + "GSL", + "TXG", 1980, - "ELC" + "TX" ], [ "utopia", - 2000, + 2010, "inter", "night", - "OIL", - "SRE", - 1990, - "DSL" + "GSL", + "TXG", + 2010, + "TX" ], [ "utopia", - 2010, + 2000, "winter", "day", - "HYD", - "E31", - 2010, - "ELC" + "ELC", + "RHE", + 2000, + "RH" ], [ "utopia", + 2010, + "summer", + "day", + "GSL", + "TXG", 2000, - "inter", - "night", - "ELC", - "E51", - 1980, - "ELC" + "TX" ], [ "utopia", 2000, - "inter", + "winter", "night", - "OIL", - "SRE", + "ELC", + "TXE", 1990, - "GSL" + "TX" ], [ "utopia", 1990, - "winter", - "day", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, "summer", - "night", - "URN", - "E21", + "day", + "ELC", + "RHE", 1990, - "ELC" + "RH" ], [ "utopia", 1990, - "inter", + "summer", "night", - "HCO", - "E01", + "DSL", + "RHO", 1970, - "ELC" + "RH" ], [ "utopia", 2000, - "summer", + "inter", "day", - "HYD", - "E31", + "DSL", + "RHO", 1990, - "ELC" + "RH" ], [ "utopia", - 2000, - "winter", - "day", - "OIL", - "SRE", 1990, - "DSL" + "inter", + "night", + "ELC", + "RL1", + 1980, + "RL" ], [ "utopia", - 2010, - "inter", - "day", - "ethos", - "IMPOIL1", 1990, - "OIL" + "summer", + "night", + "DSL", + "TXD", + 1970, + "TX" ], [ "utopia", - 2000, + 2010, "winter", "day", "ELC", - "E51", - 2000, - "ELC" + "RL1", + 2010, + "RL" ], [ "utopia", - 2000, - "inter", - "day", - "HYD", - "E31", 1990, - "ELC" - ], - [ - "utopia", - 2010, "inter", - "day", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "winter", "night", "DSL", - "E70", - 2000, - "ELC" + "RHO", + 1990, + "RH" ] ], "LifetimeProcess_rtv": [ @@ -20526,14 +25088,7 @@ "RHO", "TXG" ], - "tech_annual": [ - "RHO", - "TXE", - "RHE", - "TXG", - "TXD", - "RL1" - ], + "tech_annual": [], "tech_demand": [ "RHO", "TXE", From d907b095a6911857e69ebdaef4bee82b91769b61 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 19 Aug 2025 15:51:43 -0400 Subject: [PATCH 199/587] Fix emissions test database --- tests/testing_data/emissions.sql | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 5ec4decea..3840a1bd6 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -230,6 +230,11 @@ INSERT INTO Demand VALUES('TestRegion',2000,'annual_flex_null',0.299999999999999 INSERT INTO Demand VALUES('TestRegion',2000,'embodied_out',0.5999999999999999778,NULL,NULL); INSERT INTO Demand VALUES('TestRegion',2000,'eol_out',0.5999999999999999778,NULL,NULL); INSERT INTO Demand VALUES('TestRegion',2005,'ordinary_out',0.2999999999999999889,NULL,NULL); +INSERT INTO Demand VALUES('TestRegion',2005,'annual_out',1.0,NULL,NULL); +INSERT INTO Demand VALUES('TestRegion',2005,'curtailment_out',0.2999999999999999889,NULL,NULL); +INSERT INTO Demand VALUES('TestRegion',2005,'flex_null',0.2999999999999999889,NULL,NULL); +INSERT INTO Demand VALUES('TestRegion',2005,'annual_flex_null',0.2999999999999999889,NULL,NULL); +INSERT INTO Demand VALUES('TestRegion',2005,'embodied_out',0.5999999999999999778,NULL,NULL); CREATE TABLE DemandSpecificDistribution ( region TEXT, From cd92671562865d5b0e59f8e54044d354ed84bcca Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 6 Aug 2025 13:19:55 -0400 Subject: [PATCH 200/587] Add a missing comma to the schema --- data_files/temoa_schema_v3_1.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index b53b48dfc..0f748cf85 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -848,7 +848,7 @@ CREATE TABLE IF NOT EXISTS RampUpHourly tech TEXT REFERENCES Technology (tech), rate REAL, - notes TEXT + notes TEXT, PRIMARY KEY (region, tech) ); CREATE TABLE IF NOT EXISTS Region From 0ec29c6f0f5d8d6f83ead61484d00131af897f9d Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 7 Aug 2025 17:16:16 -0400 Subject: [PATCH 201/587] Change the continuity guard rail for consecutive days databases --- temoa/temoa_model/temoa_initialize.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 49a93d5b6..66def0103 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1185,16 +1185,20 @@ def CreateTimeSeasonSequential(M: 'TemoaModel'): raise ValueError(msg) sequential = dict() + prev_n = 0 for p, s_seq, s in M.TimeSeasonSequential.sparse_iterkeys(): num_days = value(M.TimeSeasonSequential[p, s_seq, s]) - if M.TimeSequencing.first() == 'consecutive_days' and abs(num_days - 1.0) >= 0.01: + if M.TimeSequencing.first() == 'consecutive_days' and prev_n and abs(num_days - prev_n) >= 0.001: msg = ( - 'TimeSequencing set to consecutive_days but a season in the TimeSegmentFraction table does not ' - f'represent exactly one day. This would lead to bad model behaviour: {p, s}, days: {num_days}. ' - 'Check the config file.' + 'TimeSequencing set to consecutive_days but two consecutive seasons do not represent the same ' + f'number of days. This discontinuity will lead to bad model behaviour: {p, s}, days: {num_days}. ' + f'Previous number of days: {prev_n}. Check the config file for more information.' ) logger.error(msg) raise ValueError(msg) + prev_n = num_days # for validating next in sequence + + # Regardless of their order, make sure the total number of days adds up if (p, s) not in sequential: sequential[p, s] = 0 sequential[p, s] += num_days From 19e5228c4ec7642e09e796594deddc5245d7ad87 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 12 Aug 2025 10:44:19 -0400 Subject: [PATCH 202/587] Update SurvivalCurve to LifetimeSurvivalCurve in utopia sqls --- data_files/example_dbs/utopia.sql | 2 +- tests/testing_data/utopia.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index a7de4caf0..4fe2c58f6 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -1378,7 +1378,7 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE SurvivalCurve +CREATE TABLE LifetimeSurvivalCurve ( region TEXT NOT NULL, period INTEGER NOT NULL, diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index a7de4caf0..4fe2c58f6 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -1378,7 +1378,7 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE SurvivalCurve +CREATE TABLE LifetimeSurvivalCurve ( region TEXT NOT NULL, period INTEGER NOT NULL, From 8083a4243d677d0a7a2dbc069835d77f39bc07ca Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 19 Aug 2025 12:32:09 -0400 Subject: [PATCH 203/587] Fix a typo in db migrator TechInputSplit tables should be 'ge' not 'le' --- temoa/utilities/db_migration_v3_to_v3_1.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/temoa/utilities/db_migration_v3_to_v3_1.py b/temoa/utilities/db_migration_v3_to_v3_1.py index c2897fb12..bc1c0de02 100644 --- a/temoa/utilities/db_migration_v3_to_v3_1.py +++ b/temoa/utilities/db_migration_v3_to_v3_1.py @@ -141,8 +141,8 @@ def column_check(old_name: str, new_name: str) -> bool: operator_added_tables = { 'EmissionLimit': ('LimitEmission', 'le'), 'TechOutputSplit': ('LimitTechOutputSplit', 'ge'), - 'TechInputSplitAnnual': ('LimitTechInputSplitAnnual', 'le'), - 'TechInputSplitAverage': ('LimitTechInputSplitAnnual', 'le'), + 'TechInputSplitAnnual': ('LimitTechInputSplitAnnual', 'ge'), + 'TechInputSplitAverage': ('LimitTechInputSplitAnnual', 'ge'), 'TechInputSplit': ('LimitTechInputSplit', 'ge'), 'MinNewCapacityShare': ('LimitNewCapacityShare', 'ge'), 'MinNewCapacityGroupShare': ('LimitNewCapacityShare', 'ge'), From 1410be697dfbd89bb462f063552e3a901ce2859b Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 19 Aug 2025 15:55:16 -0400 Subject: [PATCH 204/587] Remove unnecessary flow variable index checks --- temoa/temoa_model/temoa_rules.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index fb0d99ae4..be03fb7ae 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -2974,7 +2974,6 @@ def LimitActivity_Constraint(M: 'TemoaModel', r, p, t, op): for S_o in M.processOutputsByInput[_r, p, _t, S_v, S_i] for s in M.TimeSeason[p] for d in M.time_of_day - if (_r, p, s, d, S_i, _t, S_v, S_o) in M.V_FlowOut ) activity += sum( M.V_FlowOutAnnual[_r, p, S_i, _t, S_v, S_o] @@ -2983,7 +2982,6 @@ def LimitActivity_Constraint(M: 'TemoaModel', r, p, t, op): for S_v in M.processVintages.get((_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] - if (_r, p, S_i, _t, S_v, S_o) in M.V_FlowOutAnnual ) act_lim = value(M.LimitActivity[r, p, t, op]) @@ -3125,7 +3123,6 @@ def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] for s in M.TimeSeason[p] for d in M.time_of_day - if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut ) sub_activity += sum( M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] @@ -3134,7 +3131,6 @@ def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): for S_v in M.processVintages.get((_r, p, S_t), []) for S_i in M.processInputs[_r, p, S_t, S_v] for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual ) super_group = gather_group_techs(M, g2) @@ -3147,7 +3143,6 @@ def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] for s in M.TimeSeason[p] for d in M.time_of_day - if (_r, p, s, d, S_i, S_t, S_v, S_o) in M.V_FlowOut ) super_activity += sum( M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] @@ -3156,7 +3151,6 @@ def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): for S_v in M.processVintages.get((_r, p, S_t), []) for S_i in M.processInputs[_r, p, S_t, S_v] for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - if (_r, p, S_i, S_t, S_v, S_o) in M.V_FlowOutAnnual ) share_lim = value(M.LimitActivityShare[r, p, g1, g2, op]) @@ -3271,7 +3265,6 @@ def LimitAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o, op): for S_i in M.processInputs[_r, p, t, S_v] for s in M.TimeSeason[p] for d in M.time_of_day - if (_r, p, s, d, S_i, t, S_v, o) in M.V_FlowOut ) else: activity_rpt = sum( @@ -3279,7 +3272,6 @@ def LimitAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o, op): for _r in regions for S_v in M.processVintages.get((_r, p, t), []) for S_i in M.processInputs[_r, p, t, S_v] - if (_r, p, S_i, t, S_v, o) in M.V_FlowOutAnnual ) possible_activity_rpt = sum( From 03ab1b53badd33666bb67558f88af2e18efec411 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 19 Aug 2025 17:42:17 -0400 Subject: [PATCH 205/587] Relax tolerance on material flow test --- tests/test_material_results.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_material_results.py b/tests/test_material_results.py index 0f6282ca0..f77d100ba 100644 --- a/tests/test_material_results.py +++ b/tests/test_material_results.py @@ -84,5 +84,6 @@ def test_flows(solved_connection): .fetchone()[0] ) assert flow == pytest.approx( - flow_target + flow_target, + rel=1E-5, ), f'{name} flows were incorrect. Should be {flow_target}, got {flow}' \ No newline at end of file From 27db62f128f6c5c8733c27f9deda7d259b0eb75a Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 8 Sep 2025 14:44:39 -0400 Subject: [PATCH 206/587] Fix loading of tech ramping sets to load distinct techs --- temoa/temoa_model/hybrid_loader.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/temoa_model/hybrid_loader.py index 008d0917e..032b362ce 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/temoa_model/hybrid_loader.py @@ -1036,13 +1036,15 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N if self.table_exists('RampUpHourly'): raw = cur.execute('SELECT region, tech, rate FROM main.RampUpHourly').fetchall() load_element(M.RampUpHourly, raw, self.viable_rt, (0, 1)) - load_element(M.tech_upramping, sorted((row[1],) for row in raw), self.viable_techs) # sort for deterministic behavior + raw = cur.execute('SELECT DISTINCT tech FROM main.RampUpHourly').fetchall() + load_element(M.tech_upramping, raw, self.viable_techs) # RampDownHourly if self.table_exists('RampDownHourly'): raw = cur.execute('SELECT region, tech, rate FROM main.RampDownHourly').fetchall() load_element(M.RampDownHourly, raw, self.viable_rt, (0, 1)) - load_element(M.tech_downramping, sorted((row[1],) for row in raw), self.viable_techs) # sort for deterministic behavior + raw = cur.execute('SELECT DISTINCT tech FROM main.RampDownHourly').fetchall() + load_element(M.tech_downramping, raw, self.viable_techs) # CapacityCredit if self.table_exists('CapacityCredit'): From 6d528a348f8fec3882c0daeef8c8c2d1a87486e1 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 8 Sep 2025 16:24:23 -0400 Subject: [PATCH 207/587] Minor change to time sequencing warning --- temoa/temoa_model/temoa_initialize.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/temoa_model/temoa_initialize.py index 66def0103..15f8237e6 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/temoa_model/temoa_initialize.py @@ -1204,15 +1204,16 @@ def CreateTimeSeasonSequential(M: 'TemoaModel'): sequential[p, s] += num_days # Check that TimeSeasonSequential num_days total to number of days in each period + count_total = dict() # {p: n} total days per period according to TimeSeasonSequential for p in M.time_optimize: - count_total = sum( + count_total[p] = sum( sequential[p, s] for _p, s in sequential if _p == p ) - if abs(count_total - value(M.DaysPerPeriod)) >= 0.001: + if abs(count_total[p] - value(M.DaysPerPeriod)) >= 0.001: logger.warning( - f'Sum of num_days in TimeSeasonSequential ({count_total}) ' + f'Sum of num_days in TimeSeasonSequential ({count_total[p]}) ' f'for period {p} does not sum to days_per_period ({value(M.DaysPerPeriod)}) ' 'from the MetaData table.' ) @@ -1238,7 +1239,7 @@ def CreateTimeSeasonSequential(M: 'TemoaModel'): # Check that the two tables agree on the total seasonal composition of each period segfrac = value(M.SegFracPerSeason[p, s]) - segfracseq = sequential[p, s] / value(M.DaysPerPeriod) + segfracseq = sequential[p, s] / count_total[p] if abs(segfrac - segfracseq) >= 0.001: msg = ( 'Discrepancy of total period-season composition between ' From 5aea2688b7de75434b0168abf23d4700fe3a91ed Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 8 Sep 2025 16:24:46 -0400 Subject: [PATCH 208/587] Add an exception for exchange technologies in network loop check --- .../model_checking/commodity_graph.py | 38 +++++++++++-------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/temoa/temoa_model/model_checking/commodity_graph.py b/temoa/temoa_model/model_checking/commodity_graph.py index 95dcdbe81..21a8541c0 100644 --- a/temoa/temoa_model/model_checking/commodity_graph.py +++ b/temoa/temoa_model/model_checking/commodity_graph.py @@ -129,21 +129,29 @@ def generate_graph( # loop finder... try: cycles = nx.simple_cycles(G=dg) - for cycle in cycles: - cycle = list(cycle) - if len(cycle) < 2: # a storage item--not reportable - continue - res = '' - first = cycle[0] - for node in cycle: - res += f'{node} --> ' - res += first - logger.info( - 'Found cycle in region %s, period %d. No action needed if this is correct: %s', - region, - period, - res, - ) + try: + for cycle in cycles: + cycle = list(cycle) + if len(cycle) < 2: # a storage item--not reportable + continue + res = '' + first = cycle[0] + last_node = first + for node in cycle: + if node.split(' ')[0] == last_node.split(' ')[0]: + # This is just an exchange tech loop. Ignore. + raise ValueError("Just an exchange tech") + res += f'{node} --> ' + last_node = node + res += first + logger.info( + 'Found cycle in region %s, period %d. No action needed if this is correct: %s', + region, + period, + res, + ) + except ValueError: + pass except nx.NetworkXError as e: logger.warning('NetworkX exception encountered: %s. Loop evaluation NOT performed.', e) if config.plot_commodity_network: From 1436b70d19a1d84e4de77ce8c14fd60c13eda5d2 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 22 Sep 2025 10:45:02 -0400 Subject: [PATCH 209/587] Fix exchange tech exception in loop detection --- .../model_checking/commodity_graph.py | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/temoa/temoa_model/model_checking/commodity_graph.py b/temoa/temoa_model/model_checking/commodity_graph.py index 21a8541c0..57de1de05 100644 --- a/temoa/temoa_model/model_checking/commodity_graph.py +++ b/temoa/temoa_model/model_checking/commodity_graph.py @@ -129,29 +129,34 @@ def generate_graph( # loop finder... try: cycles = nx.simple_cycles(G=dg) - try: - for cycle in cycles: - cycle = list(cycle) - if len(cycle) < 2: # a storage item--not reportable - continue - res = '' - first = cycle[0] - last_node = first + for cycle in cycles: + cycle = list(cycle) + if len(cycle) < 2: # a storage item--not reportable + continue + res = '' + first = cycle[0] + last_node = first + try: for node in cycle: - if node.split(' ')[0] == last_node.split(' ')[0]: + if node.split(' (')[0] == last_node.split(' (')[0]: # This is just an exchange tech loop. Ignore. + # These are labelled in the graph as {base_tech} ({other region}) + # so we split on ' (' to compare the base techs raise ValueError("Just an exchange tech") res += f'{node} --> ' last_node = node - res += first - logger.info( - 'Found cycle in region %s, period %d. No action needed if this is correct: %s', - region, - period, - res, - ) - except ValueError: - pass + except ValueError: + # This is just a trick to continue the outer loop instead of the inner loop + # this cycle wasn't really a cycle so just continue + continue + res += first + logger.info( + 'Found cycle in region %s, period %d. No action needed if this is correct: %s', + region, + period, + res, + ) + except nx.NetworkXError as e: logger.warning('NetworkX exception encountered: %s. Loop evaluation NOT performed.', e) if config.plot_commodity_network: From 25b53409a85c4eff4928bb3f3e36306c5a6afc76 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 22 Sep 2025 12:28:19 -0400 Subject: [PATCH 210/587] Small change to simplify SeasonalStorageEnergy constraint --- temoa/temoa_model/temoa_rules.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index be03fb7ae..1754e2b77 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -1600,9 +1600,9 @@ def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_seq, t, v): :label: Storage Energy (Sequential Seasons) \mathbf{SSL}_{r,p,s^{seq},t,v} - + DA_{r,p,s^{seq}} \cdot \left(\mathbf{SL}_{r,p,s^*,d_{first},t,v} + - \sum_{D,I,O} \mathbf{FI}_{r,p,s^*,d,i,t,v,o} \cdot EFF_{r,i,t,v,o} - - \sum_{D,I,O} \mathbf{FO}_{r,p,s^*,d,i,t,v,o} + + DA_{r,p,s^{seq}} \cdot \left(\mathbf{SL}_{r,p,s^*,d_{last},t,v} + + \sum_{I,O} \mathbf{FI}_{r,p,s^*,d_{last},i,t,v,o} \cdot EFF_{r,i,t,v,o} + - \sum_{I,O} \mathbf{FO}_{r,p,s^*,d_{last},i,t,v,o} \right) = DA_{r,p,s^{seq}_{next}} \cdot \mathbf{SL}_{r,p,s_{next}^*,d_{first},t,v} @@ -1632,19 +1632,18 @@ def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_seq, t, v): # This is the sum of all input=i sent TO storage tech t of vintage v with # output=o in p,s charge = sum( - M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] * get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) + M.V_FlowIn[r, p, s, M.time_of_day.last(), S_i, t, v, S_o] + * get_variable_efficiency(M, r, p, s, M.time_of_day.last(), S_i, t, v, S_o) for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] - for d in M.time_of_day ) # This is the sum of all output=o withdrawn FROM storage tech t of vintage v # with input=i in p,s discharge = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + M.V_FlowOut[r, p, s, M.time_of_day.last(), S_i, t, v, S_o] for S_o in M.processOutputs[r, p, t, v] for S_i in M.processInputsByOutput[r, p, t, v, S_o] - for d in M.time_of_day ) s_seq_next = M.time_next_sequential[p, s_seq] @@ -1657,7 +1656,7 @@ def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_seq, t, v): stored_energy = (charge - discharge) * days_adjust - start = M.V_SeasonalStorageLevel[r, p, s_seq, t, v] + M.V_StorageLevel[r, p, s, M.time_of_day.first(), t, v] * days_adjust + start = M.V_SeasonalStorageLevel[r, p, s_seq, t, v] + M.V_StorageLevel[r, p, s, M.time_of_day.last(), t, v] * days_adjust end = M.V_SeasonalStorageLevel[r, p, s_seq_next, t, v] + M.V_StorageLevel[r, p, s_next, M.time_of_day.first(), t, v] * days_adjust_next expr = start + stored_energy == end From b0dbeb3442c5d38e3dd269dfadae3bbbe914c8bc Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 23 Sep 2025 15:39:05 -0400 Subject: [PATCH 211/587] Fix handling of period index in migrator --- temoa/utilities/db_migration_v3_to_v3_1.py | 113 +++++++++++++-------- 1 file changed, 68 insertions(+), 45 deletions(-) diff --git a/temoa/utilities/db_migration_v3_to_v3_1.py b/temoa/utilities/db_migration_v3_to_v3_1.py index bc1c0de02..bee1ae464 100644 --- a/temoa/utilities/db_migration_v3_to_v3_1.py +++ b/temoa/utilities/db_migration_v3_to_v3_1.py @@ -29,6 +29,7 @@ import sys import argparse import sqlite3 +import pandas as pd from pathlib import Path # Just to get the default lifetime... @@ -178,11 +179,9 @@ def column_check(old_name: str, new_name: str) -> bool: all_good = True for old_name, new_name in direct_transfer_tables: - good = column_check(old_name, new_name) - all_good = all_good and good + all_good = all_good and column_check(old_name, new_name) for old_name, new_name in period_added_tables: - good = column_check(old_name, new_name) - all_good = all_good and good + all_good = all_good and column_check(old_name, new_name) if not all_good: sys.exit(-1) @@ -246,18 +245,25 @@ def column_check(old_name: str, new_name: str) -> bool: con_new.executemany(query, data) print(f'Transfered {len(data)} rows from {old_name} to {new_name}') +# Need these +time_future = cur.execute('SELECT period FROM TimePeriod WHERE flag == "f"').fetchall() +time_optimize = [p[0] for p in time_future[0:-1]] + # get lifetimes. Major headache but needs to be done +lifetime_process = dict() +data = cur.execute('SELECT region, tech, vintage FROM Efficiency').fetchall() +for rtv in data: + lifetime_process[rtv] = TemoaModel.default_lifetime_tech data = cur.execute('SELECT region, tech, lifetime FROM LifetimeTech').fetchall() -lifetime_tech = dict() -for rtl in data: lifetime_tech[rtl[0:2]] = rtl[2] +for rtl in data: + for v in time_optimize: + lifetime_process[*rtl[0:2], v] = rtl[2] data = cur.execute('SELECT region, tech, vintage, lifetime FROM LifetimeProcess').fetchall() -lifetime_process = dict() -for rtvl in data: lifetime_process[rtvl[0:3]] = rtvl[3] +for rtvl in data: + lifetime_process[rtvl[0:3]] = rtvl[3] # add period indexing to seasonal tables print('\n --- Adding period index to some tables ---') -time_future = cur.execute('SELECT period FROM TimePeriod WHERE flag == "f"').fetchall() -time_optimize = [p[0] for p in time_future[0:-1]] for old_name, new_name in period_added_tables: if old_name == '': old_name = new_name @@ -271,47 +277,51 @@ def column_check(old_name: str, new_name: str) -> bool: old_columns = [c[1] for c in con_old.execute(f'PRAGMA table_info({old_name});').fetchall()] new_columns = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] cols = [c for c in new_columns if c in old_columns] - data = con_old.execute(f'SELECT {str(cols)[1:-1].replace("'","")} FROM {old_name}').fetchall() + data = pd.read_sql_query(f'SELECT {str(cols)[1:-1].replace("'","")} FROM {old_name}', con_old) - if not data: + if len(data) == 0: print('No data for: ' + old_name) continue + # This insanity collects the viable periods for each table if 'vintage' in cols: - r = cols.index('region') - t = cols.index('tech') - v = cols.index('vintage') + data['periods'] = [ + ( + p for p in time_optimize + if v <= p < v+lifetime_process[r, t, v] + ) + for r, t, v in data[['region','tech','vintage']] + ] elif 'tech' in cols: - r = cols.index('region') - t = cols.index('tech') - + periods = dict() + for r, t in data[['region','tech']].drop_duplicates().values: + periods[r, t] = [ + p for p in time_optimize + if any(( + v <= p < v+lifetime_process[r, t, v] + for v in [ + t[0] for t in con_old.execute( + f'SELECT vintage FROM Efficiency WHERE region == "{r}" AND tech == "{t}"' + ).fetchall() + ] + )) + ] + data['periods'] = [ + periods[r, t] + for (r, t) in data[['region','tech']].values + ] + else: + data['periods'] = [time_optimize for i in data.index] + data_new = [] for p in time_optimize: - for row in data: - # Remove infeasible rows - if 'vintage' in cols: - if row[v] > p: continue # v <= p - if (row[r], row[t], row[v]) in lifetime_process: life = lifetime_process[row[r], row[t], row[v]] - elif (row[r], row[t]) in lifetime_tech: life = lifetime_tech[row[r], row[t]] - else: life = TemoaModel.default_lifetime_tech - if row[v] + life <= p: continue # v+l > p - elif 'tech' in cols: - vints = [v[0] for v in con_old.execute(f'SELECT vintage FROM Efficiency WHERE tech == "{row[t]}"').fetchall()] - good = False - for v in vints: - # Can any of these vintages make p good? - if v > p: continue # Nope, need v <= p - if (row[r], row[t], v) in lifetime_process: life = lifetime_process[row[r], row[t], v] - elif (row[r], row[t]) in lifetime_tech: life = lifetime_tech[row[r], row[t]] - else: life = TemoaModel.default_lifetime_tech - if v + life <= p: continue # Nope, need v+l > p - good = True - if not good: continue - + for _idx, row in data.iterrows(): + if p not in row['periods']: + continue if old_name[0:5] == 'TimeS': # horrible but covers TimeSeason and TimeSegmentFraction - data_new.append((p, *row)) + data_new.append((p, *row.iloc[0:-1])) else: - data_new.append((row[0], p, *row[1::])) + data_new.append((row.iloc[0], p, *row.iloc[1:-1])) if old_name[0:5] == 'TimeS': # horrible but covers TimeSeason and TimeSegmentFraction cols = ['period',*cols] @@ -327,18 +337,31 @@ def column_check(old_name: str, new_name: str) -> bool: f'VALUES ({placeholders})' ) con_new.executemany(query, data_new) - print(f'Transfered {len(data)} rows from {old_name} to {new_name}') - + print(f'Transfered {len(data_new)} rows from {old_name} to {new_name}') + + +print('\n --- Making some final changes ---') +n_del = len(con_new.execute(( + "SELECT * FROM DemandSpecificDistribution " + "WHERE (region, period, demand_name) " + "NOT IN (SELECT region, period, commodity FROM Demand)" +)).fetchall()) +if n_del > 0: + con_new.execute(( + "DELETE FROM DemandSpecificDistribution " + "WHERE (region, period, demand_name) " + "NOT IN (SELECT region, period, commodity FROM Demand)" + )) + print(f"{n_del} extraneous rows removed from DemandSpecificDistribution after adding period index") # TimeSeason unique seasons to SeasonLabel con_new.execute("INSERT OR REPLACE INTO SeasonLabel(season) SELECT DISTINCT season FROM TimeSeason") - +print('Filled SeasonLabel') # Removal of tech_resource con_new.execute("UPDATE Technology SET flag='p' WHERE flag=='r';") print('Converted all resource techs to production techs.') - # LoanLifetimeTech -> LoanLifetimeProcess try: data = con_old.execute('SELECT region, tech, lifetime, notes FROM LoanLifetimeTech').fetchall() From 7cfc8df6c04d7dff68b73e7fb4375806e521f602 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 29 Sep 2025 11:12:23 -0400 Subject: [PATCH 212/587] Fix to LimitActivityShare_Constraint summation --- temoa/temoa_model/temoa_rules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/temoa_model/temoa_rules.py index 1754e2b77..c9df18cb0 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/temoa_model/temoa_rules.py @@ -3145,7 +3145,7 @@ def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): ) super_activity += sum( M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] - for S_t in super_group if S_t not in M.tech_annual + for S_t in super_group if S_t in M.tech_annual for _r in regions for S_v in M.processVintages.get((_r, p, S_t), []) for S_i in M.processInputs[_r, p, S_t, S_v] From 1d92c02b221b4de31b55bdf9650c79fa1c82b9e8 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 3 Oct 2025 17:20:10 -0400 Subject: [PATCH 213/587] adding temoa_davey_code to ci --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 633ee7014..a1b0bc731 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,9 @@ name: CI on: push: - branches: ["main", "temoa_alpha", "ci_testing", "1.0.0-dev-operator"] + branches: ["main", "temoa_alpha", "ci_testing", "1.0.0-dev-operator", "temoa_davey_code"] pull_request: - branches: ["main", "temoa_alpha", "ci_testing", "1.0.0-dev-operator"] + branches: ["main", "temoa_alpha", "ci_testing", "1.0.0-dev-operator", "temoa_davey_code"] jobs: test: From a913f222511e76013c9769344e2f8cf1bbef8e54 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 3 Oct 2025 17:37:38 -0400 Subject: [PATCH 214/587] adding coderabbit_config --- .coderabbit.yaml | 728 +++++++++++++++++++++++++++++++++++++++++++++++ .gitignore | 4 +- 2 files changed, 730 insertions(+), 2 deletions(-) create mode 100644 .coderabbit.yaml diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 000000000..8f34c034f --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,728 @@ +# yaml-language-server: $schema=https://storage.googleapis.com/coderabbit_public_assets/schema.v2.json + +# CodeRabbit Configuration Template +# Complete reference: https://docs.coderabbit.ai/reference/configuration +# Copy this file to .coderabbit.yaml in your repository root + +# ============================================================================= +# GLOBAL SETTINGS +# These settings apply to your entire CodeRabbit configuration +# ============================================================================= + +# Set the language for reviews by using the corresponding ISO language code. +# Options: de, de-DE, de-AT, de-CH, en, en-US, en-AU, en-GB, en-CA, en-NZ, en-ZA, es, es-AR, fr, fr-CA, fr-CH, fr-BE, nl, nl-BE, pt-AO, pt, pt-BR, pt-MZ, pt-PT, ar, ast-ES, ast, be-BY, be, br-FR, br, ca-ES, ca, ca-ES-valencia, ca-ES-balear, da-DK, da, de-DE-x-simple-language, el-GR, el, eo, fa, ga-IE, ga, gl-ES, gl, it, ja-JP, ja, km-KH, km, ko-KR, ko, pl-PL, pl, ro-RO, ro, ru-RU, ru, sk-SK, sk, sl-SI, sl, sv, ta-IN, ta, tl-PH, tl, tr, uk-UA, uk, zh-CN, zh, crh-UA, crh, cs-CZ, cs, nb, no, nl-NL, de-DE-x-simple-language-DE, es-ES, it-IT, fa-IR, sv-SE, de-LU, fr-FR, bg-BG, bg, he-IL, he, hi-IN, hi, vi-VN, vi, th-TH, th, bn-BD, bn +# Default: "en-US" +language: "en-US" + +# Set the tone of reviews and chat. Example: 'You must use talk like Mr. T. I pity the fool who doesn't!' +# Default: "" +tone_instructions: "" + +# Enable early-access features. +# Default: false +early_access: false + +# Enable free tier features for users not on a paid plan. +# Default: true +enable_free_tier: true + +# ============================================================================= +# REVIEWS +# Settings related to reviews. +# ============================================================================= + +# Settings related to reviews. +# Default: {} +reviews: + # Set the profile for reviews. Assertive profile yields more feedback, that may be considered nitpicky. + # Options: chill, assertive + # Default: "chill" + profile: "assertive" + + # Approve the review once CodeRabbit’s comments are resolved and no pre-merge checks are in an error state. Note: In GitLab, all discussions must be resolved. + # Default: false + request_changes_workflow: false + + # Generate a high level summary of the changes in the PR/MR description. + # Default: true + high_level_summary: true + + # Placeholder in the PR/MR description that gets replaced with the high level summary. + # Default: "@coderabbitai summary" + high_level_summary_placeholder: "@coderabbitai summary" + + # Include the high level summary in the walkthrough comment. + # Default: false + high_level_summary_in_walkthrough: false + + # Add this keyword in the PR/MR title to auto-generate the title. + # Default: "@coderabbitai" + auto_title_placeholder: "@coderabbitai" + + # Auto Title Instructions - Custom instructions for auto-generating the PR/MR title. + # Default: "" + auto_title_instructions: "" + + # Post review details on each review. Additionally, post a review status when a review is skipped in certain cases. + # Default: true + review_status: true + + # Set the commit status to 'pending' when the review is in progress and 'success' when it is complete. + # Default: true + commit_status: true + + # Set the commit status to 'failure' when the PR cannot be reviewed by CodeRabbit for any reason. + # Default: false + fail_commit_status: false + + # Generate walkthrough in a markdown collapsible section. + # Default: false + collapse_walkthrough: false + + # Generate a summary of the changed files in the walkthrough. + # Default: true + changed_files_summary: true + + # Generate sequence diagrams in the walkthrough. + # Default: true + sequence_diagrams: true + + # Estimate the code review effort in the walkthrough. + # Default: true + estimate_code_review_effort: true + + # Generate an assessment of how well the changes address the linked issues in the walkthrough. + # Default: true + assess_linked_issues: true + + # Include possibly related issues in the walkthrough. + # Default: true + related_issues: true + + # Related PRs - Include possibly related pull requests in the walkthrough. + # Default: true + related_prs: true + + # Suggest labels based on the changes in the pull request in the walkthrough. + # Default: true + suggested_labels: true + + # Automatically apply the suggested labels to the PR/MR. + # Default: false + auto_apply_labels: false + + # Suggest reviewers based on the changes in the pull request in the walkthrough. + # Default: true + suggested_reviewers: true + + # Automatically assign suggested reviewers to the pull request + # Default: false + auto_assign_reviewers: false + + # Generate a poem in the walkthrough comment. + # Default: true + poem: false + + # Labeling Instructions - Provide guidelines for suggesting labels for the PR/MR. When specific labels or instructions are provided, only those labels are considered, though previous examples are still used to inform the suggestions. If no such labels are provided, suggestions are based solely on previous PR/MRs. + # Default: [] + labeling_instructions: [] + + # Specify file patterns to include or exclude in a review using glob patterns (e.g., !dist/**, src/**). These patterns also apply to 'git sparse-checkout', including specified patterns and ignoring excluded ones (starting with '!') when cloning the repository. + # Default: [] + path_filters: [] + + # Path Instructions - Provide specific additional guidelines for code review based on file paths. + # Default: [] + path_instructions: [] + + # Abort the in-progress review if the pull request is closed or merged. + # Default: true + abort_on_close: true + + # Disable caching of code and dependencies. This will force CodeRabbit to download the code and dependencies fresh from the repository each time. + # Default: false + disable_cache: false + + # Configuration for auto review + # Default: {} + auto_review: + # Automatic Review - Automatic code review + # Default: true + enabled: true + + # Automatic Incremental Review - Automatic incremental code review on each push + # Default: true + auto_incremental_review: true + + # Ignore reviewing if the title of the pull request contains any of these keywords (case-insensitive). + # Default: [] + ignore_title_keywords: [] + + # List of labels to control which PRs/MRs to review. Labels starting with '!' are negative matches. Examples: ['bug', 'feature'] - reviews PRs with 'bug' OR 'feature' label. ['!wip'] - reviews all PRs except those with 'wip' label. ['bug', '!wip'] - reviews PRs with 'bug' label but not if they have 'wip' label. + # Default: [] + labels: [] + + # Review draft PRs/MRs. + # Default: false + drafts: false + + # Base branches (other than the default branch) to review. Accepts regex patterns. Use '.*' to match all branches. + # Default: [] + base_branches: [.*] + + # Ignore reviewing pull requests by these usernames. These should match the Git platform usernames exactly, not the email addresses. + # Default: [] + ignore_usernames: [] + + # Configuration for finishing touches + # Default: {} + finishing_touches: + # Docstrings - Options for generating Docstrings for your PRs/MRs. + # Default: {} + docstrings: + # Docstrings - Allow CodeRabbit to generate docstrings for PRs/MRs. + # Default: true + enabled: true + + # Unit Tests - Options for generating unit tests for your PRs/MRs. + # Default: {} + unit_tests: + # Unit Tests - Allow CodeRabbit to generate unit tests for PRs/MRs. + # Default: true + enabled: true + + # Configuration for pre merge checks + # Default: {} + pre_merge_checks: + # Docstring Coverage - Checks if the code has sufficient docstrings. + # Default: {} + docstrings: + # Mode - Determines how strictly the docstring coverage check is enforced. Warning will only generate a warning and does not require the user to resolve the check. Error requires the user to resolve issues before merging the pull request. If set to error and the request changes workflow is enabled, the pull request will be blocked until the issues are resolved. + # Options: off, warning, error + # Default: "warning" + mode: "warning" + + # Percentage threshold for docstring coverage check. + # Default: 80 + threshold: 80 + + # Title Check - Checks if the pull request title is appropriate and follows best practices. + # Default: {} + title: + # Mode - Determines how strictly the title check is enforced. Warning will only generate a warning and does not require the user to resolve the check. Error requires the user to resolve issues before merging the pull request. If set to error and the request changes workflow is enabled, the pull request will be blocked until the issues are resolved. + # Options: off, warning, error + # Default: "warning" + mode: "warning" + + # Requirements - Requirements for the pull request title. Example: 'Title should be concise and descriptive, ideally under 50 characters.' + # Default: "" + requirements: "" + + # Description Check - Checks if the pull request description is appropriate and follows best practices. + # Default: {} + description: + # Mode - Determines how strictly the description check is enforced. Warning will only generate a warning and does not require the user to resolve the check. Error requires the user to resolve issues before merging the pull request. If set to error and the request changes workflow is enabled, the pull request will be blocked until the issues are resolved. + # Options: off, warning, error + # Default: "warning" + mode: "warning" + + # Linked Issue Assessment - Checks if the pull request addresses the linked issues. Generate an assessment of how well the changes address the linked issues. + # Default: {} + issue_assessment: + # Mode - Determines how strictly the issue assessment check is enforced. Warning will only generate a warning and does not require the user to resolve the check. Error requires the user to resolve issues before merging the pull request. If set to error and the request changes workflow is enabled, the pull request will be blocked until the issues are resolved. + # Options: off, warning, error + # Default: "warning" + mode: "warning" + + # Custom Pre-merge Checks - Add unique checks to enforce your team's standards before merging a pull request. Each check must have a unique name (up to 50 characters) and clear instructions (up to 10000 characters). Use these to automatically verify coding, security, documentation, or business rules and maintain code quality. + # Default: [] + custom_checks: [] + + # Tools that provide additional context to code reviews. + # Default: {} + tools: + # Enable ast-grep - ast-grep is a code analysis tool that helps you to find patterns in your codebase using abstract syntax trees patterns. - v0.38.6 + # Default: {} + ast-grep: + # List of rules directories. + # Default: [] + rule_dirs: [] + + # List of utils directories. + # Default: [] + util_dirs: [] + + # Use ast-grep essentials package. + # Default: true + essential_rules: true + + # Predefined packages to be used. + # Default: [] + packages: [] + + # ShellCheck is a static analysis tool that finds bugs in your shell scripts. + # Default: {} + shellcheck: + # Enable ShellCheck - ShellCheck is a static analysis tool that finds bugs in your shell. - Enable ShellCheck integration. - v0.10.0 + # Default: true + enabled: true + + # Ruff is a Python linter and code formatter. + # Default: {} + ruff: + # Enable Ruff - Ruff is a Python linter and code formatter. - Enable Ruff integration. - v0.12.2 + # Default: true + enabled: true + + # markdownlint-cli2 is a static analysis tool to enforce standards and consistency for Markdown files. + # Default: {} + markdownlint: + # Enable markdownlint - markdownlint-cli2 is a static analysis tool to enforce standards and consistency for Markdown files. - Enable markdownlint integration. - v0.17.2 + # Default: true + enabled: true + + # GitHub Checks integration configuration. + # Default: {} + github-checks: + # Enable GitHub Checks - Enable integration, defaults to true - Enable GitHub Checks integration. + # Default: true + enabled: true + + # Time in milliseconds to wait for all GitHub Checks to conclude. Default 90 seconds, max 15 minutes (900000ms). + # Default: 90000 + timeout_ms: 90000 + + # LanguageTool is a style and grammar checker for 30+ languages. + # Default: {} + languagetool: + # Enable LanguageTool - Enable LanguageTool integration. + # Default: true + enabled: true + + # IDs of rules to be enabled. The rule won't run unless 'level' is set to a level that activates the rule. + # Default: [] + enabled_rules: [] + + # IDs of rules to be disabled. Note: EN_UNPAIRED_BRACKETS, and EN_UNPAIRED_QUOTES are always disabled. + # Default: [] + disabled_rules: [] + + # IDs of categories to be enabled. + # Default: [] + enabled_categories: [] + + # IDs of categories to be disabled. Note: TYPOS, TYPOGRAPHY, and CASING are always disabled. + # Default: [] + disabled_categories: [] + + # Only the rules and categories whose IDs are specified with 'enabledRules' or 'enabledCategories' are enabled. + # Default: false + enabled_only: false + + # If set to 'picky', additional rules will be activated, i.e. rules that you might only find useful when checking formal text. + # Options: default, picky + # Default: "default" + level: "default" + + # Biome is a fast formatter, linter, and analyzer for web projects. + # Default: {} + biome: + # Enable Biome - Biome is a fast formatter, linter, and analyzer for web projects. - Enable Biome integration. - v2.1.2 + # Default: true + enabled: true + + # Hadolint is a Dockerfile linter. + # Default: {} + hadolint: + # Enable Hadolint - Hadolint is a Dockerfile linter. - Enable Hadolint integration. - v2.12.0 + # Default: true + enabled: true + + # SwiftLint integration configuration object. + # Default: {} + swiftlint: + # Enable SwiftLint - SwiftLint is a Swift linter. - Enable SwiftLint integration. - v0.57.0 + # Default: true + enabled: true + + # Optional path to the SwiftLint configuration file relative to the repository. This is useful when the configuration file is named differently than the default '.swiftlint.yml' or '.swiftlint.yaml'. + config_file: "example-value" + + # PHPStan is a tool to analyze PHP code. + # Default: {} + phpstan: + # Enable PHPStan - PHPStan requires [config file](https://phpstan.org/config-reference#config-file) in your repository root. Please ensure that this file contains the `paths:` parameter. - v2.1.17 + # Default: true + enabled: true + + # Level - Specify the [rule level](https://phpstan.org/user-guide/rule-levels) to run. This setting is ignored if your configuration file already has a `level:` parameter. + # Options: default, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, max + # Default: "default" + level: "default" + + # PHPMD is a tool to find potential problems in PHP code. + # Default: {} + phpmd: + # Enable PHPMD - PHPMD is a tool to find potential problems in PHP code. - v2.15.0 + # Default: true + enabled: true + + # PHP CodeSniffer is a PHP linter and coding standard checker. + # Default: {} + phpcs: + # Enable PHP CodeSniffer - PHP CodeSniffer is a PHP linter and coding standard checker. - v3.7.2 + # Default: true + enabled: true + + # golangci-lint is a fast linters runner for Go. + # Default: {} + golangci-lint: + # Enable golangci-lint - golangci-lint is a fast linters runner for Go. - Enable golangci-lint integration. - v2.2.2 + # Default: true + enabled: true + + # Optional path to the golangci-lint configuration file relative to the repository. Useful when the configuration file is named differently than the default '.golangci.yml', '.golangci.yaml', '.golangci.toml', '.golangci.json'. + config_file: "example-value" + + # YAMLlint is a linter for YAML files. + # Default: {} + yamllint: + # Enable YAMLlint - YAMLlint is a linter for YAML files. - Enable YAMLlint integration. - v1.37.1 + # Default: true + enabled: true + + # Gitleaks is a secret scanner. + # Default: {} + gitleaks: + # Enable Gitleaks - Gitleaks is a secret scanner. - Enable Gitleaks integration. - v8.27.2 + # Default: true + enabled: true + + # Checkov is a static code analysis tool for infrastructure-as-code files. + # Default: {} + checkov: + # Enable Checkov - Checkov is a static code analysis tool for infrastructure-as-code files. - v3.2.334 + # Default: true + enabled: true + + # Detekt is a static code analysis tool for Kotlin files. + # Default: {} + detekt: + # Enable detekt - detekt is a static code analysis tool for Kotlin files. - v1.23.8 + # Default: true + enabled: true + + # Optional path to the detekt configuration file relative to the repository. + config_file: "example-value" + + # ESLint is a static code analysis tool for JavaScript files. + # Default: {} + eslint: + # Enable ESLint - ESLint is a static code analysis tool for JavaScript files. + # Default: true + enabled: true + + # Flake8 is a Python linter that wraps PyFlakes, pycodestyle and Ned Batchelder's McCabe script. + # Default: {} + flake8: + # Enable Flake8 - Flake8 is a Python linter that wraps PyFlakes, pycodestyle and Ned Batchelder's McCabe script. - v7.2.0 + # Default: true + enabled: true + + # RuboCop is a Ruby static code analyzer (a.k.a. linter ) and code formatter. + # Default: {} + rubocop: + # Enable RuboCop - RuboCop is a Ruby static code analyzer (a.k.a. linter ) and code formatter. - v1.76.1 + # Default: true + enabled: true + + # Buf offers linting for Protobuf files. + # Default: {} + buf: + # Enable Buf - Buf offers linting for Protobuf files. - v1.55.1 + # Default: true + enabled: true + + # Regal is a linter and language server for Rego. + # Default: {} + regal: + # Enable Regal - Regal is a linter and language server for Rego. - v0.35.1 + # Default: true + enabled: true + + # actionlint is a static checker for GitHub Actions workflow files. + # Default: {} + actionlint: + # Enable actionlint - is a static checker for GitHub Actions workflow files. - v1.7.7 + # Default: true + enabled: true + + # PMD is an extensible multilanguage static code analyzer. It’s mainly concerned with Java. + # Default: {} + pmd: + # Enable PMD - PMD is an extensible multilanguage static code analyzer. It’s mainly concerned with Java. - v7.15.0 + # Default: true + enabled: true + + # Optional path to the PMD configuration file relative to the repository. + config_file: "example-value" + + # Cppcheck is a static code analysis tool for the C and C++ programming languages. + # Default: {} + cppcheck: + # Enable Cppcheck - Cppcheck is a static code analysis tool for the C and C++ programming languages. - v2.17.1 + # Default: true + enabled: true + + # Semgrep is a static analysis tool designed to scan code for security vulnerabilities and code quality issues. + # Default: {} + semgrep: + # Enable Semgrep - Semgrep is a static analysis tool designed to scan code for security vulnerabilities and code quality issues. - Enable Semgrep integration. - v1.128.1 + # Default: true + enabled: true + + # Optional path to the Semgrep configuration file relative to the repository. + config_file: "example-value" + + # CircleCI tool is a static checker for CircleCI config files. + # Default: {} + circleci: + # Enable CircleCI - CircleCI tool is a static checker for CircleCI config files. - v0.1.32638 + # Default: true + enabled: true + + # Clippy is a collection of lints to catch common mistakes and improve your Rust code. + # Default: {} + clippy: + # Enable Clippy - Clippy is a collection of lints to catch common mistakes and improve your Rust code. - Enable Clippy integration. + # Default: true + enabled: true + + # SQLFluff is an open source, dialect-flexible and configurable SQL linter. + # Default: {} + sqlfluff: + # Enable SQLFluff - SQLFluff is an open source, dialect-flexible and configurable SQL linter. - v3.4.1 + # Default: true + enabled: true + + # Configuration for Prisma Schema linting to ensure schema file quality + # Default: {} + prismaLint: + # Enable Prisma Schema linting - Prisma Schema linting helps maintain consistent and error-free schema files - v0.10.2 + # Default: true + enabled: true + + # Pylint is a Python static code analysis tool. + # Default: {} + pylint: + # Enable Pylint - Pylint is a Python static code analysis tool. - v3.3.7 + # Default: true + enabled: true + + # Oxlint is a JavaScript/TypeScript linter for OXC written in Rust. + # Default: {} + oxc: + # Enable Oxlint - Oxlint is a JavaScript/TypeScript linter for OXC written in Rust. - v0.16.10 + # Default: true + enabled: true + + # Configuration for Shopify Theme Check to ensure theme quality and best practices + # Default: {} + shopifyThemeCheck: + # Enable Shopify Theme Check - A linter for Shopify themes that helps you follow Shopify theme & Liquid best practices - cli 3.77.1 - theme 3.58.2 + # Default: true + enabled: true + + # Configuration for Lua code linting to ensure code quality + # Default: {} + luacheck: + # Enable Lua code linting - Luacheck helps maintain consistent and error-free Lua code - v1.2.0 + # Default: true + enabled: true + + # Brakeman is a static analysis security vulnerability scanner for Ruby on Rails applications. - v7.0.2 + # Default: {} + brakeman: + # Enable Brakeman - Brakeman is a static analysis security vulnerability scanner for Ruby on Rails applications. - v7.0.2 + # Default: true + enabled: true + + # dotenv-linter is a tool for checking and fixing .env files for problems and best practices + # Default: {} + dotenvLint: + # Enable dotenv-linter - dotenv-linter is a tool for checking and fixing .env files for problems and best practices - v3.3.0 + # Default: true + enabled: true + + # HTMLHint is a static code analysis tool for HTML files. + # Default: {} + htmlhint: + # Enable HTMLHint - HTMLHint is a static code analysis tool for HTML files. - Enable HTMLHint integration. - v1.5.0 + # Default: true + enabled: true + + # checkmake is a linter for Makefiles. + # Default: {} + checkmake: + # Enable checkmake - checkmake is a linter for Makefiles. - v0.2.2 + # Default: true + enabled: true + + # OSV Scanner is a tool for vulnerability package scanning. + # Default: {} + osvScanner: + # Enable OSV Scanner - OSV Scanner is a tool for vulnerability package scanning - v2.1.0 + # Default: true + enabled: true + +# ============================================================================= +# CHAT +# Configuration for chat +# ============================================================================= + +# Configuration for chat +# Default: {} +chat: + # Generate art in response to chat messages. CodeRabbit expresses emotions as either ASCII or Emoji art. + # Default: true + art: true + + # Enable the bot to reply automatically without requiring the user to tag it. + # Default: true + auto_reply: true + + # Configuration for integrations + # Default: {} + integrations: + # Configuration for jira + # Default: {} + jira: + # Jira - Enable the Jira integration for opening issues, etc. 'auto' disables the integration for public repositories. + # Options: auto, enabled, disabled + # Default: "auto" + usage: "auto" + + # Configuration for linear + # Default: {} + linear: + # Linear - Enable the Linear integration for opening issues, etc. 'auto' disables the integration for public repositories. + # Options: auto, enabled, disabled + # Default: "auto" + usage: "auto" + +# ============================================================================= +# KNOWLEDGE BASE +# Configuration for knowledge base +# ============================================================================= + +# Configuration for knowledge base +# Default: {} +knowledge_base: + # Opt Out - Disable all knowledge base features that require data retention. If you opt out after opting in, all of your existing knowledge base data will be removed from the system. + # Default: false + opt_out: false + + # Configuration for web search + # Default: {} + web_search: + # Web Search - Enable the web search integration. + # Default: true + enabled: true + + # CodeRabbit will analyse and learn from your organization's code guidelines, which you can mention in the file patterns section. These guidelines will then be used to conduct thorough code reviews. + # Default: {} + code_guidelines: + # Enabled - Enable CodeRabbit to enforce your organization's coding standards during reviews. + # Default: true + enabled: true + + # File Patterns - Specify files for your coding guideline documents in this section. CodeRabbit will scan these files to understand your team's standards and apply them during code reviews. Multiple files supported. File names are case-sensitive. Common files like: (**/.cursorrules, .github/copilot-instructions.md, .github/instructions/*.instructions.md, **/CLAUDE.md, **/GEMINI.md, **/.cursor/rules/*, **/.windsurfrules, **/.clinerules/*, **/.rules/*, **/AGENT.md, **/AGENTS.md) are included by default. + # Default: [] + filePatterns: [] + + # Configuration for learnings + # Default: {} + learnings: + # Learnings - Specify the scope of learnings to use for the knowledge base. 'local' uses the repository's learnings, 'global' uses the organization's learnings, and 'auto' uses repository's learnings for public repositories and organization's learnings for private repositories. + # Options: local, global, auto + # Default: "auto" + scope: "auto" + + # Configuration for issues + # Default: {} + issues: + # Issues - Specify the scope of git platform (GitHub/GitLab) issues to use for the knowledge base. 'local' uses the repository's issues, 'global' uses the organization's issues, and 'auto' uses repository's issues for public repositories and organization's issues for private repositories. + # Options: local, global, auto + # Default: "auto" + scope: "auto" + + # Configuration for jira + # Default: {} + jira: + # Jira - Enable the Jira knowledge base integration. 'auto' disables the integration for public repositories. + # Options: auto, enabled, disabled + # Default: "auto" + usage: "auto" + + # Jira Project Keys - Specify the Jira project keys to use for the knowledge base. + # Default: [] + project_keys: [] + + # Configuration for linear + # Default: {} + linear: + # Linear - Enable the Linear knowledge base integration. 'auto' disables the integration for public repositories. + # Options: auto, enabled, disabled + # Default: "auto" + usage: "auto" + + # Linear Team Keys - Specify the Linear team keys (identifiers) to use for the knowledge base. E.g. 'ENG' + # Default: [] + team_keys: [] + + # Configuration for pull requests + # Default: {} + pull_requests: + # Pull Requests - Specify the scope of pull requests to use for the knowledge base. 'local' uses the repository's pull requests, 'global' uses the organization's pull requests, and 'auto' uses repository's pull requests for public repositories and organization's pull requests for private repositories. + # Options: local, global, auto + # Default: "auto" + scope: "auto" + + # Configuration for mcp + # Default: {} + mcp: + # MCP - Enable the MCP knowledge base integration. 'auto' disables the integration for public repositories. + # Options: auto, enabled, disabled + # Default: "auto" + usage: "auto" + + # MCP Disabled Servers - Specify MCP server labels to disable (case-insensitive). These servers will be excluded from reviews and knowledge base queries. + # Default: [] + disabled_servers: [] + +# ============================================================================= +# CODE GENERATION +# Configuration for code generation +# ============================================================================= + +# Configuration for code generation +# Default: {} +code_generation: + # Settings related to the generation of docstrings. + # Default: {"path_instructions":[]} + docstrings: + # Set the language for docstrings by using the corresponding ISO language code. + # Options: de, de-DE, de-AT, de-CH, en, en-US, en-AU, en-GB, en-CA, en-NZ, en-ZA, es, es-AR, fr, fr-CA, fr-CH, fr-BE, nl, nl-BE, pt-AO, pt, pt-BR, pt-MZ, pt-PT, ar, ast-ES, ast, be-BY, be, br-FR, br, ca-ES, ca, ca-ES-valencia, ca-ES-balear, da-DK, da, de-DE-x-simple-language, el-GR, el, eo, fa, ga-IE, ga, gl-ES, gl, it, ja-JP, ja, km-KH, km, ko-KR, ko, pl-PL, pl, ro-RO, ro, ru-RU, ru, sk-SK, sk, sl-SI, sl, sv, ta-IN, ta, tl-PH, tl, tr, uk-UA, uk, zh-CN, zh, crh-UA, crh, cs-CZ, cs, nb, no, nl-NL, de-DE-x-simple-language-DE, es-ES, it-IT, fa-IR, sv-SE, de-LU, fr-FR, bg-BG, bg, he-IL, he, hi-IN, hi, vi-VN, vi, th-TH, th, bn-BD, bn + # Default: "en-US" + language: "en-US" + + # Path Instructions - Provide additional guidelines for docstring generation based on file paths. + # Default: [] + path_instructions: [] + + # Settings related to the generation of unit tests. + # Default: {"path_instructions":[]} + unit_tests: + # Unit Test Generation - Provide additional guidelines for unit test generation based on file paths. + # Default: [] + path_instructions: [] diff --git a/.gitignore b/.gitignore index b0093ecfb..fa6d85add 100644 --- a/.gitignore +++ b/.gitignore @@ -20,10 +20,10 @@ !CHANGELOG.md !CONTRIBUTING.md !.pre-commit-config.yaml - +!.coderabbit.yaml # recursively re-ignore __pycache__ # ignore built docs -docs/_build \ No newline at end of file +docs/_build From bf3346dddbd591755801792ecd5fc3b6e0906061 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 7 Oct 2025 17:01:51 -0400 Subject: [PATCH 215/587] setting up new directory structure for clear public vs intermal api separation --- .gitignore | 1 + FEATURE_BRANCH.md | 25 + README.md | 152 ++- main.py | 12 +- pyproject.toml | 2 +- temoa/__init__.py | 67 ++ temoa/_internal/__init__.py | 8 + .../{temoa_model => _internal}/data_brick.py | 8 +- .../exchange_tech_cost_ledger.py | 5 +- .../hybrid_loader.py | 337 ++++-- .../{temoa_model => _internal}/run_actions.py | 60 +- .../table_data_puller.py | 84 +- .../table_writer.py | 40 +- .../temoa_initialize.py | 306 +++-- .../{temoa_model => _internal}/temoa_rules.py | 809 +++++++------ .../temoa_sequencer.py | 26 +- temoa/core/__init__.py | 13 + .../temoa_config.py => core/config.py} | 2 +- temoa/core/model.py | 1034 +++++++++++++++++ .../temoa_mode.py => core/modes.py} | 0 temoa/extensions/method_of_morris/morris.py | 13 +- .../method_of_morris/morris_evaluate.py | 9 +- .../method_of_morris/morris_sequencer.py | 13 +- .../manager_factory.py | 3 +- .../mga_sequencer.py | 17 +- .../tech_activity_vector_manager.py | 11 +- .../vector_manager.py | 5 +- .../worker.py | 3 +- temoa/extensions/monte_carlo/mc_run.py | 15 +- temoa/extensions/monte_carlo/mc_sequencer.py | 9 +- temoa/extensions/monte_carlo/mc_worker.py | 5 +- temoa/extensions/myopic/myopic_sequencer.py | 22 +- .../single_vector_mga/output_summary.py | 3 +- .../single_vector_mga/sv_mga_sequencer.py | 21 +- .../model_checking/__init__.py | 0 .../model_checking/commodity_graph.py | 31 +- .../model_checking/commodity_network.py | 5 +- .../commodity_network_manager.py | 10 +- .../model_checking/element_checker.py | 1 + .../model_checking/network_model_data.py | 39 +- .../model_checking/pricing_check.py | 3 +- .../model_checking/validators.py | 10 +- temoa/temoa_model/temoa_model.py | 342 ++++-- temoa/utilities/db_migration_v3_to_v3_1.py | 27 +- temoa/utilities/unit_cost_explorer.py | 2 +- tests/conftest.py | 4 +- tests/test_element_checker.py | 3 +- tests/test_emission_results.py | 102 +- tests/test_exchange_cost_ledger.py | 14 +- tests/test_material_results.py | 19 +- tests/test_model.py | 4 +- tests/test_network_model_data.py | 34 +- tests/test_pricing_check.py | 2 +- tests/test_set_consistency.py | 9 +- tests/test_source_check.py | 2 +- tests/test_storage.py | 39 +- tests/test_table_writer.py | 4 +- tests/test_temoa_sequencer.py | 4 +- tests/test_validators.py | 4 +- .../utilities/capture_set_sizes_for_cache.py | 2 +- .../utilities/capture_set_values_for_cache.py | 2 +- uv.lock | 2 +- 62 files changed, 2762 insertions(+), 1098 deletions(-) create mode 100644 FEATURE_BRANCH.md create mode 100644 temoa/_internal/__init__.py rename temoa/{temoa_model => _internal}/data_brick.py (97%) rename temoa/{temoa_model => _internal}/exchange_tech_cost_ledger.py (98%) rename temoa/{temoa_model => _internal}/hybrid_loader.py (81%) rename temoa/{temoa_model => _internal}/run_actions.py (89%) rename temoa/{temoa_model => _internal}/table_data_puller.py (90%) rename temoa/{temoa_model => _internal}/table_writer.py (97%) rename temoa/{temoa_model => _internal}/temoa_initialize.py (92%) rename temoa/{temoa_model => _internal}/temoa_rules.py (89%) rename temoa/{temoa_model => _internal}/temoa_sequencer.py (97%) create mode 100644 temoa/core/__init__.py rename temoa/{temoa_model/temoa_config.py => core/config.py} (99%) create mode 100755 temoa/core/model.py rename temoa/{temoa_model/temoa_mode.py => core/modes.py} (100%) rename temoa/{temoa_model => }/model_checking/__init__.py (100%) rename temoa/{temoa_model => }/model_checking/commodity_graph.py (91%) rename temoa/{temoa_model => }/model_checking/commodity_network.py (99%) rename temoa/{temoa_model => }/model_checking/commodity_network_manager.py (96%) rename temoa/{temoa_model => }/model_checking/element_checker.py (99%) rename temoa/{temoa_model => }/model_checking/network_model_data.py (93%) rename temoa/{temoa_model => }/model_checking/pricing_check.py (99%) rename temoa/{temoa_model => }/model_checking/validators.py (97%) diff --git a/.gitignore b/.gitignore index fa6d85add..a4704d842 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ !CONTRIBUTING.md !.pre-commit-config.yaml !.coderabbit.yaml +!FEATURE_BRANCH.md # recursively re-ignore __pycache__ diff --git a/FEATURE_BRANCH.md b/FEATURE_BRANCH.md new file mode 100644 index 000000000..4cce535fc --- /dev/null +++ b/FEATURE_BRANCH.md @@ -0,0 +1,25 @@ +# Library Reorganization Feature Branch + +## Overview + +Major refactoring to make TEMOA pip-installable with clean library API. + +## Current Phase + +[ ] Phase 1: Foundation +[ ] Phase 2: CLI Separation +[ ] Phase 3: Data & Configuration +[ ] Phase 4: Extensions & Testing +[ ] Phase 5: Documentation & Release + +## Testing Status + +- [ ] Core model tests pass +- [ ] CLI tests pass +- [ ] Extension tests pass +- [ ] Integration tests pass + +## Known Issues + +- [ ] Import path changes may break existing code +- [ ] Need to update CI/CD configuration diff --git a/README.md b/README.md index 0713d6def..ca3c01f69 100644 --- a/README.md +++ b/README.md @@ -1,79 +1,115 @@ -# Getting Started with TEMOA and Version 3 +# Getting Started with TEMOA Version 4.0.0a1 ## Overview +TEMOA (Tools for Energy Model Optimization and Analysis) is a sophisticated energy systems optimization framework that supports various modeling approaches including perfect foresight, myopic planning, uncertainty analysis, and alternative generation. + +### Package Structure + The main subdirectories in the project are: -1. `temoa/` -Contains the core Temoa model -2. `temoa/temoa_model` -The core model code necessary to build and solve a Temoa instance -3. `temoa/data_processing` -Code for post-processing solved models and working with output -4. `temoa/extensions` -Model extensions to solve the model using differing techniques. Note: There is some legacy and non-working -code in these modules that is planned future work. - -5. `data_files/` -Intended to hold input data files and config files. Examples are included. -Note that the example file utopia.sql represents a simple system called 'Utopia', which -is packaged with the MARKAL model generator and has been used -extensively for benchmarking exercises. -6. `output_files/` -The target for run-generated output including log files and other requested products. Temoa will create -time-stamped folders to gather output for runs -4. `docs/` -Contains the source code for the Temoa project manual, in reStructuredText -(ReST) format. -5. `notebooks/` -jupyter notebooks associated with the project. Note: Not all of these are functional at this time, but are -retained to guide future development +1. **`temoa/`** - Main package directory + - **`temoa.core`** - Public API for end users (TemoaModel, TemoaConfig, TemoaMode) + - **`temoa._internal`** - Private implementation modules (not for public use) + - **`temoa.data_processing`** - Post-processing and output utilities + - **`temoa.extensions`** - Optional extensions for different modeling approaches + - **`temoa.utilities`** - Helper scripts and database utilities + - **`temoa.model_checking`** - Model validation and integrity checking + +2. **`data_files/`** - Input data files and configuration examples +3. **`tests/`** - Comprehensive test suite +4. **`docs/`** - Documentation source files +5. **`notebooks/`** - Jupyter notebooks for analysis and examples + +### Installation + +TEMOA can be installed as a pip package: + +```bash +pip install -e . +``` + +Or using the provided requirements file: + +```bash +pip install -r requirements.txt +``` ## Guide to Setup 1. Obtain a current copy of Python from the python.org website. The model has been tested with 3.11 and 3.12. It will fail (raise error) on earlier versions. 2. A `requirements.txt` file has been included to allow for use of `pip` to populate a virtual environment. In order to use that the steps are: + - Ensure you have a copy of python 3.11/3.12 installed on your machine ([python.org](https://www.python.org)) - Make and activate a virtual environment using the `venv` package: ``` -$ python3.11 -m venv venv -$ source venv/bin/activate # for linux/osx, windows activation command may differ +python3.11 -m venv venv +source venv/bin/activate # for linux/osx, windows activation command may differ ``` + - Verify that you have a prepended indicator on your cursor that you are in the virtual environment (see below) - After activating the venv, use `pip` *within* the venv to install everything. Most IDEs have automated tools to help set up and associate this venv with the project. It is also possible from the command line: + ``` (venv) $ pip install -r requirements.txt ``` -- For Conda users, an environment.yml file is provided that is not currently fully tested. Additional installs may + +- For Conda users, an environment.yml file is provided that is not currently fully tested. Additional installs may be required. -3. The entry point for regular execution is now at the top level of the project so a "sample" run should be initiated as: +3. **Usage as a Library**: Import and use TEMOA programmatically: + +```python +import temoa +from temoa import TemoaModel, TemoaConfig, TemoaMode + +# Create configuration +config = TemoaConfig( + scenario="my_scenario", + scenario_mode=TemoaMode.PERFECT_FORESIGHT, + input_database="path/to/input.db", + output_database="path/to/output.db", + output_path="path/to/output", + solver_name="gurobi" +) + +# Build and solve model +model = TemoaModel() +# ... (additional usage) ``` -(venv) temoa $ python main.py --config data_files/my_configs/config_sample.toml + +4. **Command Line Usage**: Use the main entry point: + +```bash +python -m temoa --config data_files/my_configs/config_sample.toml ``` ## Database Setup -- Several sample database files in Version 3 format are provided in SQL format for learning/testing. These are provided in the -`data_files/example_dbs` folder. In order to use them, they must be converted into sqlite database files. This can + +- Several sample database files in Version 3 format are provided in SQL format for learning/testing. These are provided in the +`data_files/example_dbs` folder. In order to use them, they must be converted into sqlite database files. This can be done from the command line using the sqlite3 engine to convert them. sqlite3 is packaged with Python and should be available. If not, most configuration managers should be able to install it. The command to make the `.sqlite` file is (for Utopia as an example): + ``` (venv) $ sqlite3 utopia.sqlite < utopia.sql ``` + - Converting legacy db's to Version 3 can be done with the included database migration tool. Users who use this -tool are advised to carefully review the console outputs during conversion to ensure accuracy and check the +tool are advised to carefully review the console outputs during conversion to ensure accuracy and check the converted database carefully. The migration tool will build an empty new Version 3 database and move data from -the old database, preserving the legacy database in place. The command can be run from the top level of the +the old database, preserving the legacy database in place. The command can be run from the top level of the project and needs pointers to the target database and the Version 3 schema file. A typical execution from top level should look like: +```bash +python -m temoa.utilities.db_migration_to_v3 --source data_files/.sqlite --schema data_files/temoa_schema_v3.sql ``` -(venv) $ python temoa/utilities/db_migration_to_v3.py --source data_files/.sqlite --schema data_files/temoa_schema_v3.sql -``` + - Users may also create a blank full or minimal version of the database from the two schema files in the `data_files` directory as described above using the `sqlite3` command. The "minimal" version excludes some of the group parameters and is recommended as a starting point for entry-level models. It can be upgraded to the full set of @@ -100,51 +136,69 @@ and has all parameters in it. It can be copied/renamed, etc. | Mode Specific Settings | See the README files within mode folders for up-to-date values | ## Currently Supported Modes + ### Check + Build the model and run the numerous checks on it. Results will be in the log file. No solve is attempted. Note: The LP file for the model can be saved with this option and solved later/independently by selecting the ``save_lp_file`` option in the config. + ### Perfect Foresight + All-in-one run that solves the entire model at once. It is possible to run this without source tracing, which will use raw data in the model without checking the integrity of the underlying network. It is highly advised to use source tracing for most accurate results. + ### Myopic + Solve the model sequentially through iterative solves based on Myopic settings. Source tracing is required to accommodate build/no-build decisions made per iteration to ensure follow-on models are well built. + ### MGA (Modeling to Generate Alternatives) + An iterative solving process to explore near cost-optimal solutions. See the documentation on this mode. + ### SVMGA (Single Vector MGA) + A sequence of 2 model solves that establishes a base optimal cost, then relaxes the cost then minimizes an alternate unweighted objective function comprised of variables associated with labels selected in lists in the config file. + ### Method of Morris + A limited sensitivity analysis of user-selected variables using a Method of Morris approach. See the documentation on this mode. + ### Build Only + Mostly for test/troubleshooting. This builds/returns an un-solved model. Several other options are possible to pass to the main execution command including changing the logging level to `debug` or running silent (no console feedback) which may be best for server runs. Also, redirecting the output products is possible. To see available options invoke the `main.py` file with the `-h` flag: -``` -(venv) $ python main.py -h +```bash +python -m temoa --help ``` ## Typical Run -1. Prepare a database (or copy of one) as described above. Runs will fill the output tables and overwrite any data with the + +1. Prepare a database (or copy of one) as described above. Runs will fill the output tables and overwrite any data with the same scenario name. 2. Perepare a config file with paths to the database(s) relative to the top of the project, as in the example -3. Run the model, using the `main.py` entry point from the top-level of the project: -``` -(venv) temoa $ python main.py --config data_files/my_configs/config_sample.toml +3. Run the model using the module entry point: + +```bash +python -m temoa --config data_files/my_configs/config_sample.toml ``` + 4. Review the config display and accept -5. Review the log file and output products which are automatically placed in a time-stamped folder in `output_files`, +5. Review the log file and output products which are automatically placed in a time-stamped folder in `output_files`, unless user has redirected output 6. Review the data in the Output tables ## Testing + Users who wish to exercise the `pytest` based test in the test folder can do so from the command line or any IDE. Note that many of the tests perform solves on small models using the freely available `cbc` solver, which is required to run the testing suite. @@ -153,9 +207,10 @@ The tests should all run and pass (several are currently skipped and reflect in- be run from the top level of the `tests folder`. If `pytest` is installed it will locate tests within the folder and run/report them. Note the dot '.' below indicating current folder: +```bash +python -m pytest tests/ ``` -(venv) temoa/tests pytest . -``` + Several of the packages used may currently generate warnings during this testing process, but the tests should all PASS with the exception of skipped tests. @@ -165,19 +220,18 @@ The full Temoa documentation can be built by following the build README file in ## Hot Fix for Network Plots on Windows Machines -Users wishing to utilize the feature to make the html network plots of the energy network using the +Users wishing to utilize the feature to make the html network plots of the energy network using the `plot_commodity_network` option in the config file who are working on Windows Operating System may need to make a -"hot fix" to the library code. See note here: https://github.com/robert-haas/gravis/issues/10 +"hot fix" to the library code. See note here: The `gravis` library which nicely makes these plots appears to currently be non-maintained and a 1-line fix is likely needed to avoid error on Windows machines: + 1. Within the `venv` that contains project dependencies, navigate to the `gravis` folder 2. Open the file `gravis/_internal/plotting/data_structures.py` and edit line 120 to include the encoding flag: - `with open(filepath, 'w', encoding='utf-8') as file_handle:` - ## Hot Fix for Graphviz Users wishing to utilize the `graphviz` package to visualize results as described in the `README.md` file diff --git a/main.py b/main.py index 6cb52ec8a..fe534043c 100644 --- a/main.py +++ b/main.py @@ -1,6 +1,7 @@ """ Entry point for running the model. """ + import argparse import logging import os @@ -12,8 +13,9 @@ import definitions from definitions import PROJECT_ROOT -from temoa.temoa_model.temoa_model import TemoaModel -from temoa.temoa_model.temoa_sequencer import TemoaMode, TemoaSequencer +from temoa._internal.temoa_sequencer import TemoaSequencer +from temoa.core.model import TemoaModel +from temoa.core.modes import TemoaMode from temoa.version_information import TEMOA_MAJOR, TEMOA_MINOR # Written by: J. F. Hyink @@ -116,8 +118,7 @@ def parse_args(arg_list: list[str] | None) -> argparse.Namespace: if options.output_path: if not Path(options.output_path).is_dir(): raise FileNotFoundError( - f'The selected output path directory {options.output_path} ' - f'could not be located.' + f'The selected output path directory {options.output_path} could not be located.' ) else: output_path = Path(options.output_path) @@ -133,8 +134,7 @@ def parse_args(arg_list: list[str] | None) -> argparse.Namespace: # check for config file existence if not options.config_file: logger.error( - 'No config file found in CLA. ' - 'Temoa needs a config file to operate, see documentation.' + 'No config file found in CLA. Temoa needs a config file to operate, see documentation.' ) raise AttributeError('no config file provided.') else: diff --git a/pyproject.toml b/pyproject.toml index f406b47f8..26a9354fe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "temoa" -version = "3.0.0" +version = "4.0.0a1" description = "Tools for Energy Model Optimization and Analysis" readme = "README.md" requires-python = ">=3.12" diff --git a/temoa/__init__.py b/temoa/__init__.py index e69de29bb..e6809f3e6 100644 --- a/temoa/__init__.py +++ b/temoa/__init__.py @@ -0,0 +1,67 @@ +""" +Tools for Energy Model Optimization and Analysis (Temoa): +An open source framework for energy systems optimization modeling + +This module provides backward compatibility imports for the refactored TEMOA structure. +New code should import directly from temoa.core and temoa._internal as appropriate. +""" + +# Core API - public interface +# Internal modules - for backward compatibility +from temoa._internal.data_brick import DataBrick, data_brick_factory +from temoa._internal.exchange_tech_cost_ledger import CostType, ExchangeTechCostLedger +from temoa._internal.hybrid_loader import HybridLoader +from temoa._internal.run_actions import ( + build_instance, + handle_results, + save_lp, + solve_instance, +) +from temoa._internal.table_data_puller import ( + loan_costs, + poll_capacity_results, + poll_cost_results, + poll_emissions, + poll_flow_results, +) +from temoa._internal.table_writer import TableWriter +from temoa._internal.temoa_initialize import * +from temoa._internal.temoa_rules import * +from temoa._internal.temoa_sequencer import TemoaSequencer +from temoa.core.config import TemoaConfig +from temoa.core.model import TemoaModel +from temoa.core.modes import TemoaMode + +# Version information +from temoa.version_information import TEMOA_MAJOR, TEMOA_MINOR + +__version__ = '4.0.0a1' + +# Maintain backward compatibility for common imports +__all__ = [ + # Core API + 'TemoaModel', + 'TemoaConfig', + 'TemoaMode', + # Internal modules (for backward compatibility) + 'DataBrick', + 'data_brick_factory', + 'CostType', + 'ExchangeTechCostLedger', + 'HybridLoader', + 'build_instance', + 'solve_instance', + 'handle_results', + 'save_lp', + 'loan_costs', + 'poll_capacity_results', + 'poll_emissions', + 'poll_flow_results', + 'poll_cost_results', + 'TableWriter', + 'TemoaSequencer', + # Version info + 'TEMOA_MAJOR', + 'TEMOA_MINOR', + '__version__', +] diff --git a/temoa/_internal/__init__.py b/temoa/_internal/__init__.py new file mode 100644 index 000000000..b70e096bb --- /dev/null +++ b/temoa/_internal/__init__.py @@ -0,0 +1,8 @@ +""" +TEMOA Internal API + +This module contains internal implementation details for the TEMOA energy systems modeling library. +These modules are not part of the public API and may change without notice. +""" + +__all__ = [] diff --git a/temoa/temoa_model/data_brick.py b/temoa/_internal/data_brick.py similarity index 97% rename from temoa/temoa_model/data_brick.py rename to temoa/_internal/data_brick.py index 0b026834d..a4fd9e80f 100644 --- a/temoa/temoa_model/data_brick.py +++ b/temoa/_internal/data_brick.py @@ -31,16 +31,16 @@ """ -from temoa.temoa_model.table_data_puller import ( +from temoa._internal.table_data_puller import ( EI, CapData, + poll_capacity_results, poll_cost_results, - poll_flow_results, poll_emissions, + poll_flow_results, poll_objective, - poll_capacity_results, ) -from temoa.temoa_model.temoa_model import TemoaModel +from temoa.core.model import TemoaModel class DataBrick: diff --git a/temoa/temoa_model/exchange_tech_cost_ledger.py b/temoa/_internal/exchange_tech_cost_ledger.py similarity index 98% rename from temoa/temoa_model/exchange_tech_cost_ledger.py rename to temoa/_internal/exchange_tech_cost_ledger.py index 1256ae9e9..60dd241e2 100644 --- a/temoa/temoa_model/exchange_tech_cost_ledger.py +++ b/temoa/_internal/exchange_tech_cost_ledger.py @@ -29,13 +29,14 @@ separately gather all of the costs and then use a usage ratio to generate entries when asked for """ + from collections import defaultdict -from enum import unique, Enum +from enum import Enum, unique from typing import Union from pyomo.common.numeric_types import value -from temoa.temoa_model.temoa_model import TemoaModel +from temoa.core.model import TemoaModel from tests.utilities.namespace_mock import Namespace diff --git a/temoa/temoa_model/hybrid_loader.py b/temoa/_internal/hybrid_loader.py similarity index 81% rename from temoa/temoa_model/hybrid_loader.py rename to temoa/_internal/hybrid_loader.py index 032b362ce..a95a50a0c 100644 --- a/temoa/temoa_model/hybrid_loader.py +++ b/temoa/_internal/hybrid_loader.py @@ -29,24 +29,23 @@ """ - import sys import time from collections import defaultdict from logging import getLogger -from sqlite3 import Connection, OperationalError, Cursor +from sqlite3 import Connection, Cursor, OperationalError from typing import Sequence from pyomo.core import Param, Set from pyomo.dataportal import DataPortal +from temoa.core.config import TemoaConfig +from temoa.core.model import TemoaModel +from temoa.core.modes import TemoaMode from temoa.extensions.myopic.myopic_index import MyopicIndex -from temoa.temoa_model.model_checking import network_model_data, element_checker -from temoa.temoa_model.model_checking.commodity_network_manager import CommodityNetworkManager -from temoa.temoa_model.model_checking.element_checker import ViableSet -from temoa.temoa_model.temoa_config import TemoaConfig -from temoa.temoa_model.temoa_mode import TemoaMode -from temoa.temoa_model.temoa_model import TemoaModel +from temoa.model_checking import element_checker, network_model_data +from temoa.model_checking.commodity_network_manager import CommodityNetworkManager +from temoa.model_checking.element_checker import ViableSet logger = getLogger(__name__) @@ -321,11 +320,10 @@ def load_element( ) except ValueError as e: raise ValueError( - 'Failed to validate members of %s. Coding error likely.' - '\n%s' % (c.name, e) + 'Failed to validate members of %s. Coding error likely.\n%s' % (c.name, e) ) if len(screened) < len(values): - msg = ('Some values for {} failed to validate and were ignored: {}') + msg = 'Some values for {} failed to validate and were ignored: {}' logger.warning(msg.format(c.name, [val for val in values if val not in screened])) match c: case Set(): @@ -386,11 +384,13 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N time_optimize = [p[0] for p in raw[0:-1]] # time_of_day - if self.table_exists("TimeOfDay"): + if self.table_exists('TimeOfDay'): raw = cur.execute('SELECT tod FROM main.TimeOfDay ORDER BY sequence').fetchall() load_element(M.time_of_day, raw) else: - logger.warning('No TimeOfDay table found. Loading a single filler time of day "D" (assume this is an annual model)') + logger.warning( + 'No TimeOfDay table found. Loading a single filler time of day "D" (assume this is an annual model)' + ) load_element(M.time_of_day, [('D',)]) # TimeSequencing @@ -400,8 +400,12 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N pass case 'manual': # This is a hidden feature allowing the user to manually specify the sequence of states using the TimeNext table - if self.table_exists("TimeNext"): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT period, season, tod, season_next, tod_next FROM main.TimeNext') + if self.table_exists('TimeNext'): + raw = self.raw_check_mi_period( + mi, + cur=cur, + qry='SELECT period, season, tod, season_next, tod_next FROM main.TimeNext', + ) load_element(M.TimeNext, raw) else: # Hidden feature unlocked but not setup! Give a nice long explanation @@ -416,7 +420,9 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N logger.error(msg) raise ValueError(msg) case _: - msg = f"Invalid time sequencing parameter '{time_sequencing}'. Check the config file." + msg = ( + f"Invalid time sequencing parameter '{time_sequencing}'. Check the config file." + ) logger.error(msg) raise ValueError(msg) load_element(M.TimeSequencing, [(time_sequencing,)]) @@ -427,16 +433,14 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # myopic_base_year if mi: # assume first future period by default - p0 = cur.execute( - "SELECT min(period) FROM TimePeriod WHERE flag == 'f'" - ).fetchone() + p0 = cur.execute("SELECT min(period) FROM TimePeriod WHERE flag == 'f'").fetchone() # load as a singleton... data[M.MyopicDiscountingYear.name] = {None: int(p0[0])} # days_per_season raw = cur.execute( - "SELECT value from MetaData WHERE element == 'days_per_period'" - ).fetchall() + "SELECT value from MetaData WHERE element == 'days_per_period'" + ).fetchall() if not raw: logger.info( 'No value found for days_per_period in the MetaData table. ' @@ -496,7 +500,9 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N load_element(M.tech_storage, raw, self.viable_techs) # tech_seasonal_storage - raw = cur.execute("SELECT tech FROM main.Technology WHERE flag = 'ps' AND seas_stor > 0").fetchall() + raw = cur.execute( + "SELECT tech FROM main.Technology WHERE flag = 'ps' AND seas_stor > 0" + ).fetchall() load_element(M.tech_seasonal_storage, raw, self.viable_techs) # tech_reserve @@ -573,8 +579,8 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # === OPERATORS === # operator - if self.table_exists("Operator"): - raw = cur.execute("SELECT operator FROM main.Operator").fetchall() + if self.table_exists('Operator'): + raw = cur.execute('SELECT operator FROM main.Operator').fetchall() load_element(M.operator, raw) # === PARAMS === @@ -585,12 +591,16 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N load_element(M.Efficiency, raw) # EfficiencyVariable - if self.table_exists("EfficiencyVariable"): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tod, input_comm, tech, vintage, output_comm, efficiency FROM main.EfficiencyVariable') + if self.table_exists('EfficiencyVariable'): + raw = self.raw_check_mi_period( + mi, + cur=cur, + qry='SELECT region, period, season, tod, input_comm, tech, vintage, output_comm, efficiency FROM main.EfficiencyVariable', + ) load_element(M.EfficiencyVariable, raw, self.viable_ritvo, (0, 4, 5, 6, 7)) # ExistingCapacity - if self.table_exists("ExistingCapacity"): + if self.table_exists('ExistingCapacity'): if mi: # In order to get accurate capacity at start of this interval, we want to # 1. Only look at the previous period in the net capacity table (things that had some capacity) @@ -618,10 +628,12 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # devnote: We want full existing capacity history for end of life flows and growth constraints # load_element(M.ExistingCapacity, raw, self.viable_rtv, (0, 1, 2)) load_element(M.ExistingCapacity, raw) - load_element(M.tech_exist, list({(row[1],) for row in raw})) # need to keep these for accounting purposes + load_element( + M.tech_exist, list({(row[1],) for row in raw}) + ) # need to keep these for accounting purposes # GlobalDiscountRate - if self.table_exists("MetaDataReal"): + if self.table_exists('MetaDataReal'): raw = cur.execute( "SELECT value FROM main.MetaDataReal WHERE element = 'global_discount_rate'" ).fetchall() @@ -629,8 +641,12 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N data[M.GlobalDiscountRate.name] = {None: raw[0][0]} # SegFrac - if self.table_exists("TimeSegmentFraction"): - raw = self.raw_check_mi_period(mi=mi, cur=cur, qry='SELECT period, season, tod, segfrac FROM main.TimeSegmentFraction') + if self.table_exists('TimeSegmentFraction'): + raw = self.raw_check_mi_period( + mi=mi, + cur=cur, + qry='SELECT period, season, tod, segfrac FROM main.TimeSegmentFraction', + ) else: logger.warning( 'No TimeSegmentFraction table found. Loading filler SegFrac ("S", "D") for one time segment per period' @@ -639,53 +655,48 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # if no segfrac table, assume this is a periodic model if mi: raw = [ - (p, "S", "D", 1) + (p, 'S', 'D', 1) for p in time_optimize if mi.base_year <= p <= mi.last_demand_year ] else: - raw = [ - (p, "S", "D", 1) - for p in time_optimize - ] + raw = [(p, 'S', 'D', 1) for p in time_optimize] load_element(M.SegFrac, raw) # TimeSeason - if self.table_exists("TimeSeason"): + if self.table_exists('TimeSeason'): if mi: raw = cur.execute( 'SELECT period, season FROM main.TimeSeason WHERE' ' period >= ? AND period <= ? ORDER BY period, sequence', - (mi.base_year, mi.last_demand_year) + (mi.base_year, mi.last_demand_year), ).fetchall() else: - raw = cur.execute('SELECT period, season FROM main.TimeSeason ORDER BY period, sequence').fetchall() + raw = cur.execute( + 'SELECT period, season FROM main.TimeSeason ORDER BY period, sequence' + ).fetchall() for row in raw: - load_indexed_set( - M.TimeSeason, - index_value=row[0], - element=row[1] - ) + load_indexed_set(M.TimeSeason, index_value=row[0], element=row[1]) load_element(M.time_season, list(set((row[1],) for row in raw))) else: for period in time_optimize: - load_indexed_set( - M.TimeSeason, - index_value=period, - element='S' - ) - logger.warning('No TimeSeason table found. Loading a single filler season "S" (assume this is an annual model)') + load_indexed_set(M.TimeSeason, index_value=period, element='S') + logger.warning( + 'No TimeSeason table found. Loading a single filler season "S" (assume this is an annual model)' + ) load_element(M.time_season, [('S',)]) - if self.table_exists("TimeSeasonSequential"): + if self.table_exists('TimeSeasonSequential'): if mi: raw = cur.execute( 'SELECT period, seas_seq, season, num_days FROM main.TimeSeasonSequential WHERE' ' period >= ? AND period <= ? ORDER BY period, sequence', - (mi.base_year, mi.last_demand_year) + (mi.base_year, mi.last_demand_year), ).fetchall() else: - raw = cur.execute('SELECT period, seas_seq, season, num_days FROM main.TimeSeasonSequential ORDER BY period, sequence').fetchall() + raw = cur.execute( + 'SELECT period, seas_seq, season, num_days FROM main.TimeSeasonSequential ORDER BY period, sequence' + ).fetchall() load_element(M.TimeSeasonSequential, raw) if raw: load_element(M.ordered_season_sequential, [(row[0:3]) for row in raw]) @@ -693,51 +704,75 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # DemandSpecificDistribution if self.table_exists('DemandSpecificDistribution'): - raw = self.raw_check_mi_period(mi=mi, cur=cur, qry='SELECT region, period, season, tod, demand_name, dsd FROM main.DemandSpecificDistribution') + raw = self.raw_check_mi_period( + mi=mi, + cur=cur, + qry='SELECT region, period, season, tod, demand_name, dsd FROM main.DemandSpecificDistribution', + ) load_element(M.DemandSpecificDistribution, raw) # Demand - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, commodity, demand FROM main.Demand') + raw = self.raw_check_mi_period( + mi, cur=cur, qry='SELECT region, period, commodity, demand FROM main.Demand' + ) load_element(M.Demand, raw) # CapacityToActivity - if self.table_exists("CapacityToActivity"): + if self.table_exists('CapacityToActivity'): raw = cur.execute('SELECT region, tech, c2a FROM main.CapacityToActivity').fetchall() load_element(M.CapacityToActivity, raw, self.viable_rt, (0, 1)) # CapacityFactorTech - if self.table_exists("CapacityFactorTech"): - raw = self.raw_check_mi_period(mi=mi, cur=cur, qry='SELECT region, period, season, tod, tech, factor FROM main.CapacityFactorTech') + if self.table_exists('CapacityFactorTech'): + raw = self.raw_check_mi_period( + mi=mi, + cur=cur, + qry='SELECT region, period, season, tod, tech, factor FROM main.CapacityFactorTech', + ) load_element(M.CapacityFactorTech, raw, self.viable_rt, (0, 4)) # CapacityFactorProcess - if self.table_exists("CapacityFactorProcess"): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tod, tech, vintage, factor FROM main.CapacityFactorProcess') + if self.table_exists('CapacityFactorProcess'): + raw = self.raw_check_mi_period( + mi, + cur=cur, + qry='SELECT region, period, season, tod, tech, vintage, factor FROM main.CapacityFactorProcess', + ) load_element(M.CapacityFactorProcess, raw, self.viable_rtv, (0, 4, 5)) # LifetimeTech - if self.table_exists("LifetimeTech"): + if self.table_exists('LifetimeTech'): raw = cur.execute('SELECT region, tech, lifetime FROM main.LifetimeTech').fetchall() load_element(M.LifetimeTech, raw, self.viable_rt, val_loc=(0, 1)) # LifetimeProcess - if self.table_exists("LifetimeProcess"): - raw = cur.execute('SELECT region, tech, vintage, lifetime FROM main.LifetimeProcess').fetchall() + if self.table_exists('LifetimeProcess'): + raw = cur.execute( + 'SELECT region, tech, vintage, lifetime FROM main.LifetimeProcess' + ).fetchall() load_element(M.LifetimeProcess, raw, self.viable_rtv, val_loc=(0, 1, 2)) # LifetimeSurvivalCurve - if self.table_exists("LifetimeSurvivalCurve"): - raw = cur.execute('SELECT region, period, tech, vintage, fraction FROM main.LifetimeSurvivalCurve').fetchall() + if self.table_exists('LifetimeSurvivalCurve'): + raw = cur.execute( + 'SELECT region, period, tech, vintage, fraction FROM main.LifetimeSurvivalCurve' + ).fetchall() load_element(M.LifetimeSurvivalCurve, raw, self.viable_rtv, val_loc=(0, 2, 3)) # LoanLifetimeProcess - if self.table_exists("LoanLifetimeProcess"): - raw = cur.execute('SELECT region, tech, vintage, lifetime FROM main.LoanLifetimeProcess').fetchall() + if self.table_exists('LoanLifetimeProcess'): + raw = cur.execute( + 'SELECT region, tech, vintage, lifetime FROM main.LoanLifetimeProcess' + ).fetchall() load_element(M.LoanLifetimeProcess, raw, self.viable_rtv, (0, 1, 2)) # LimitTechInputSplit if self.table_exists('LimitTechInputSplit'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, input_comm, tech, operator, proportion FROM main.LimitTechInputSplit') + raw = self.raw_check_mi_period( + mi, + cur=cur, + qry='SELECT region, period, input_comm, tech, operator, proportion FROM main.LimitTechInputSplit', + ) loaded = load_element(M.LimitTechInputSplit, raw, self.viable_rpit, (0, 1, 2, 3)) # we need to see if anything was filtered out here and raise warning if so as it may have invalidated # a blending process and any missing items should be reviewed @@ -755,11 +790,15 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N period, tech, ic, - ) + ) # LimitTechInputSplitAnnual if self.table_exists('LimitTechInputSplitAnnual'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, input_comm, tech, operator, proportion FROM main.LimitTechInputSplitAnnual') + raw = self.raw_check_mi_period( + mi, + cur=cur, + qry='SELECT region, period, input_comm, tech, operator, proportion FROM main.LimitTechInputSplitAnnual', + ) loaded = load_element(M.LimitTechInputSplitAnnual, raw, self.viable_rpit, (0, 1, 2, 3)) # we need to see if anything was filtered out here and raise warning if so as it may have invalidated # a blending process and any missing items should be reviewed @@ -781,7 +820,11 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # LimitTechOutputSplit if self.table_exists('LimitTechOutputSplit'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, output_comm, operator, proportion FROM main.LimitTechOutputSplit') + raw = self.raw_check_mi_period( + mi, + cur=cur, + qry='SELECT region, period, tech, output_comm, operator, proportion FROM main.LimitTechOutputSplit', + ) loaded = load_element(M.LimitTechOutputSplit, raw, self.viable_rpto, (0, 1, 2, 3)) # raise warning regarding any deletions here... similar to input split above if len(loaded) < len(raw): @@ -802,7 +845,11 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # LimitTechOutputSplitAnnual if self.table_exists('LimitTechOutputSplitAnnual'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, output_comm, operator, proportion FROM main.LimitTechOutputSplitAnnual') + raw = self.raw_check_mi_period( + mi, + cur=cur, + qry='SELECT region, period, tech, output_comm, operator, proportion FROM main.LimitTechOutputSplitAnnual', + ) loaded = load_element(M.LimitTechOutputSplitAnnual, raw, self.viable_rpto, (0, 1, 2, 3)) # we need to see if anything was filtered out here and raise warning if so as it may have invalidated # a blending process and any missing items should be reviewed @@ -824,7 +871,11 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # RenewablePortfolioStandard if self.table_exists('RPSRequirement'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech_group, requirement FROM main.RPSRequirement') + raw = self.raw_check_mi_period( + mi, + cur=cur, + qry='SELECT region, period, tech_group, requirement FROM main.RPSRequirement', + ) load_element(M.RenewablePortfolioStandard, raw) if len(raw) > 0: logger.warning( @@ -835,7 +886,9 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N ) # CostFixed - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, vintage, cost FROM main.CostFixed') + raw = self.raw_check_mi_period( + mi, cur=cur, qry='SELECT region, period, tech, vintage, cost FROM main.CostFixed' + ) load_element(M.CostFixed, raw, self.viable_rtv, val_loc=(0, 2, 3)) # CostInvest @@ -843,7 +896,7 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # the "viable_rtv" will filter anything beyond view if mi: raw = cur.execute( - 'SELECT region, tech, vintage, cost FROM main.CostInvest ' 'WHERE vintage >= ?', + 'SELECT region, tech, vintage, cost FROM main.CostInvest WHERE vintage >= ?', (mi.base_year,), ).fetchall() else: @@ -851,16 +904,20 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N load_element(M.CostInvest, raw, self.viable_rtv, (0, 1, 2)) # CostVariable - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, vintage, cost FROM main.CostVariable') + raw = self.raw_check_mi_period( + mi, cur=cur, qry='SELECT region, period, tech, vintage, cost FROM main.CostVariable' + ) load_element(M.CostVariable, raw, self.viable_rtv, (0, 2, 3)) # CostEmissions (and supporting index set) if self.table_exists('CostEmission'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, emis_comm, cost from main.CostEmission') + raw = self.raw_check_mi_period( + mi, cur=cur, qry='SELECT region, period, emis_comm, cost from main.CostEmission' + ) load_element(M.CostEmission, raw) # DefaultLoanRate - if self.table_exists("MetaDataReal"): + if self.table_exists('MetaDataReal'): raw = cur.execute( "SELECT value FROM main.MetaDataReal WHERE element = 'default_loan_rate'" ).fetchall() @@ -868,101 +925,153 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N data[M.DefaultLoanRate.name] = {None: raw[0][0]} # LoanRate - if self.table_exists("LoanRate"): + if self.table_exists('LoanRate'): if mi: raw = cur.execute( - 'SELECT region, tech, vintage, rate FROM main.LoanRate ' 'WHERE vintage >= ?', + 'SELECT region, tech, vintage, rate FROM main.LoanRate WHERE vintage >= ?', (mi.base_year,), ).fetchall() else: - raw = cur.execute('SELECT region, tech, vintage, rate FROM main.LoanRate ').fetchall() + raw = cur.execute( + 'SELECT region, tech, vintage, rate FROM main.LoanRate ' + ).fetchall() load_element(M.LoanRate, raw, self.viable_rtv, (0, 1, 2)) # LimitCapacity if self.table_exists('LimitCapacity'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech_or_group, operator, capacity FROM main.LimitCapacity') - load_element(M.LimitCapacity, raw)#, self.viable_rt, (0, 2)) + raw = self.raw_check_mi_period( + mi, + cur=cur, + qry='SELECT region, period, tech_or_group, operator, capacity FROM main.LimitCapacity', + ) + load_element(M.LimitCapacity, raw) # , self.viable_rt, (0, 2)) # LimitNewCapacity if self.table_exists('LimitNewCapacity'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech_or_group, operator, new_cap FROM main.LimitNewCapacity') + raw = self.raw_check_mi_period( + mi, + cur=cur, + qry='SELECT region, period, tech_or_group, operator, new_cap FROM main.LimitNewCapacity', + ) load_element(M.LimitNewCapacity, raw) # LimitCapacityShare if self.table_exists('LimitCapacityShare'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitCapacityShare') + raw = self.raw_check_mi_period( + mi, + cur=cur, + qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitCapacityShare', + ) load_element(M.LimitCapacityShare, raw) # LimitNewCapacityShare if self.table_exists('LimitNewCapacityShare'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitNewCapacityShare') + raw = self.raw_check_mi_period( + mi, + cur=cur, + qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitNewCapacityShare', + ) load_element(M.LimitNewCapacityShare, raw) # LimitActivityShare if self.table_exists('LimitActivityShare'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitActivityShare') + raw = self.raw_check_mi_period( + mi, + cur=cur, + qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitActivityShare', + ) load_element(M.LimitActivityShare, raw) # LimitResource if self.table_exists('LimitResource'): - raw = cur.execute('SELECT region, tech_or_group, operator, cum_act FROM main.LimitResource').fetchall() + raw = cur.execute( + 'SELECT region, tech_or_group, operator, cum_act FROM main.LimitResource' + ).fetchall() load_element(M.LimitResource, raw) # LimitActivity if self.table_exists('LimitActivity'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech_or_group, operator, activity FROM main.LimitActivity') + raw = self.raw_check_mi_period( + mi, + cur=cur, + qry='SELECT region, period, tech_or_group, operator, activity FROM main.LimitActivity', + ) load_element(M.LimitActivity, raw) # LimitSeasonalCapacityFactor if self.table_exists('LimitSeasonalCapacityFactor'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tech, operator, factor FROM main.LimitSeasonalCapacityFactor') + raw = self.raw_check_mi_period( + mi, + cur=cur, + qry='SELECT region, period, season, tech, operator, factor FROM main.LimitSeasonalCapacityFactor', + ) load_element(M.LimitSeasonalCapacityFactor, raw, self.viable_rt, (0, 3)) # LimitAnnualCapacityFactor if self.table_exists('LimitAnnualCapacityFactor'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, output_comm, operator, factor FROM main.LimitAnnualCapacityFactor') + raw = self.raw_check_mi_period( + mi, + cur=cur, + qry='SELECT region, period, tech, output_comm, operator, factor FROM main.LimitAnnualCapacityFactor', + ) load_element(M.LimitAnnualCapacityFactor, raw, self.viable_rpto, (0, 1, 2, 3)) # LimitGrowthCapacity if self.table_exists('LimitGrowthCapacity'): - raw = cur.execute('SELECT region, tech_or_group, operator, rate, seed FROM main.LimitGrowthCapacity').fetchall() + raw = cur.execute( + 'SELECT region, tech_or_group, operator, rate, seed FROM main.LimitGrowthCapacity' + ).fetchall() raw = self.tuple_values(raw, 3) load_element(M.LimitGrowthCapacity, raw) # LimitDegrowthCapacity if self.table_exists('LimitDegrowthCapacity'): - raw = cur.execute('SELECT region, tech_or_group, operator, rate, seed FROM main.LimitDegrowthCapacity').fetchall() + raw = cur.execute( + 'SELECT region, tech_or_group, operator, rate, seed FROM main.LimitDegrowthCapacity' + ).fetchall() raw = self.tuple_values(raw, 3) load_element(M.LimitDegrowthCapacity, raw) # LimitGrowthNewCapacity if self.table_exists('LimitGrowthNewCapacity'): - raw = cur.execute('SELECT region, tech_or_group, operator, rate, seed FROM main.LimitGrowthNewCapacity').fetchall() + raw = cur.execute( + 'SELECT region, tech_or_group, operator, rate, seed FROM main.LimitGrowthNewCapacity' + ).fetchall() raw = self.tuple_values(raw, 3) load_element(M.LimitGrowthNewCapacity, raw) # LimitDegrowthNewCapacity if self.table_exists('LimitDegrowthNewCapacity'): - raw = cur.execute('SELECT region, tech_or_group, operator, rate, seed FROM main.LimitDegrowthNewCapacity').fetchall() + raw = cur.execute( + 'SELECT region, tech_or_group, operator, rate, seed FROM main.LimitDegrowthNewCapacity' + ).fetchall() raw = self.tuple_values(raw, 3) load_element(M.LimitDegrowthNewCapacity, raw) # LimitGrowthNewCapacityDelta if self.table_exists('LimitGrowthNewCapacityDelta'): - raw = cur.execute('SELECT region, tech_or_group, operator, rate, seed FROM main.LimitGrowthNewCapacityDelta').fetchall() + raw = cur.execute( + 'SELECT region, tech_or_group, operator, rate, seed FROM main.LimitGrowthNewCapacityDelta' + ).fetchall() raw = self.tuple_values(raw, 3) load_element(M.LimitGrowthNewCapacityDelta, raw) # LimitDegrowthNewCapacityDelta if self.table_exists('LimitDegrowthNewCapacityDelta'): - raw = cur.execute('SELECT region, tech_or_group, operator, rate, seed FROM main.LimitDegrowthNewCapacityDelta').fetchall() + raw = cur.execute( + 'SELECT region, tech_or_group, operator, rate, seed FROM main.LimitDegrowthNewCapacityDelta' + ).fetchall() raw = self.tuple_values(raw, 3) load_element(M.LimitDegrowthNewCapacityDelta, raw) # LimitEmission if self.table_exists('LimitEmission'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, emis_comm, operator, value FROM main.LimitEmission') + raw = self.raw_check_mi_period( + mi, + cur=cur, + qry='SELECT region, period, emis_comm, operator, value FROM main.LimitEmission', + ) load_element(M.LimitEmission, raw) # EmissionActivity @@ -978,19 +1087,17 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # EmissionEmbodied if self.table_exists('EmissionEmbodied'): raw = cur.execute( - 'SELECT region, emis_comm, tech, vintage, value ' - 'FROM main.EmissionEmbodied' + 'SELECT region, emis_comm, tech, vintage, value FROM main.EmissionEmbodied' ).fetchall() load_element(M.EmissionEmbodied, raw, self.viable_rtv, (0, 2, 3)) # EmissionEndOfLife if self.table_exists('EmissionEndOfLife'): raw = cur.execute( - 'SELECT region, emis_comm, tech, vintage, value ' - 'FROM main.EmissionEndOfLife' + 'SELECT region, emis_comm, tech, vintage, value FROM main.EmissionEndOfLife' ).fetchall() load_element(M.EmissionEndOfLife, raw, self.viable_rtv, (0, 2, 3)) - + # ConstructionInput if self.table_exists('ConstructionInput'): raw = cur.execute( @@ -1048,12 +1155,20 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # CapacityCredit if self.table_exists('CapacityCredit'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, tech, vintage, credit FROM main.CapacityCredit') + raw = self.raw_check_mi_period( + mi, + cur=cur, + qry='SELECT region, period, tech, vintage, credit FROM main.CapacityCredit', + ) load_element(M.CapacityCredit, raw, self.viable_rtv, (0, 2, 3)) # ReserveCapacityDerate if self.table_exists('ReserveCapacityDerate'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tech, vintage, factor FROM main.ReserveCapacityDerate') + raw = self.raw_check_mi_period( + mi, + cur=cur, + qry='SELECT region, period, season, tech, vintage, factor FROM main.ReserveCapacityDerate', + ) load_element(M.ReserveCapacityDerate, raw, self.viable_rtv, (0, 3, 4)) # PlanningReserveMargin @@ -1068,8 +1183,12 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N # StorageFraction if self.table_exists('LimitStorageLevelFraction'): - raw = self.raw_check_mi_period(mi, cur=cur, qry='SELECT region, period, season, tod, tech, vintage, operator, fraction FROM main.LimitStorageLevelFraction') - load_element(M.LimitStorageFraction, raw, self.viable_rtv, (0,4,5)) + raw = self.raw_check_mi_period( + mi, + cur=cur, + qry='SELECT region, period, season, tod, tech, vintage, operator, fraction FROM main.LimitStorageLevelFraction', + ) + load_element(M.LimitStorageFraction, raw, self.viable_rtv, (0, 4, 5)) # For T/S: dump the size of all data elements into the log if self.debugging: @@ -1082,13 +1201,13 @@ def load_indexed_set(indexed_set: Set, index_value, element, element_validator=N self.data = data return data - + def tuple_values(self, raw, index_length): new_raw = [] for row in raw: new_raw.append((*row[0:index_length], row[index_length::])) return new_raw - + def raw_check_mi_period(self, mi: MyopicIndex | None, cur: Cursor, qry: str) -> list: if mi: return cur.execute( diff --git a/temoa/temoa_model/run_actions.py b/temoa/_internal/run_actions.py similarity index 89% rename from temoa/temoa_model/run_actions.py rename to temoa/_internal/run_actions.py index 111f5ad74..019e71fe8 100644 --- a/temoa/temoa_model/run_actions.py +++ b/temoa/_internal/run_actions.py @@ -27,31 +27,32 @@ """ import os -import definitions import sqlite3 import sys from logging import getLogger from pathlib import Path -from sys import stderr as SE, version_info +from sys import stderr as SE +from sys import version_info from time import time from typing import Tuple from pyomo.environ import ( + Constraint, DataPortal, + SolverFactory, Suffix, - Var, - Constraint, - value, UnknownSolver, - SolverFactory, + Var, check_optimal_termination, + value, ) from pyomo.opt import SolverResults +import definitions +from temoa._internal.table_writer import TableWriter +from temoa.core.config import TemoaConfig +from temoa.core.model import TemoaModel from temoa.data_processing.DB_to_Excel import make_excel -from temoa.temoa_model.table_writer import TableWriter -from temoa.temoa_model.temoa_config import TemoaConfig -from temoa.temoa_model.temoa_model import TemoaModel logger = getLogger(__name__) @@ -160,14 +161,24 @@ def build_instance( # Check for warnings in log file to notify user. Ugly but it works log_file = os.path.join(definitions.get_OUTPUT_PATH(), 'log.log') with open(log_file, 'r') as f: - warnings_found = any("| WARNING |" in line or "| ERROR |" in line or "| CRITICAL |" in line for line in f) + warnings_found = any( + '| WARNING |' in line or '| ERROR |' in line or '| CRITICAL |' in line + for line in f + ) if warnings_found: - SE.write('\r[%8.2f] Instance created with warnings. Check log file.\n' % (time() - hack)) + SE.write( + '\r[%8.2f] Instance created with warnings. Check log file.\n' + % (time() - hack) + ) else: - SE.write('\r[%8.2f] Instance created. \n' % (time() - hack)) # needs spaces to clear previous line + SE.write( + '\r[%8.2f] Instance created. \n' % (time() - hack) + ) # needs spaces to clear previous line SE.flush() except: - SE.write('\r[%8.2f] Instance created. \n' % (time() - hack)) # needs spaces to clear previous line + SE.write( + '\r[%8.2f] Instance created. \n' % (time() - hack) + ) # needs spaces to clear previous line SE.flush() logger.info('Finished creating model instance from data') @@ -259,10 +270,10 @@ def solve_instance( elif solver_name == 'gurobi': # Note: these parameter values are taken to be the same as those in PyPSA (see: https://pypsa-eur.readthedocs.io/en/latest/configuration.html) - optimizer.options["Method"] = 2 # barrier - optimizer.options["Crossover"] = 0 # non basic solution, ie no crossover - optimizer.options["BarConvTol"] = 1.e-5 - optimizer.options["FeasibilityTol"] = 1.e-6 + optimizer.options['Method'] = 2 # barrier + optimizer.options['Crossover'] = 0 # non basic solution, ie no crossover + optimizer.options['BarConvTol'] = 1.0e-5 + optimizer.options['FeasibilityTol'] = 1.0e-6 # optimizer.options["BarOrder"] = 0 # if solve times seem unusually long, try 0 or 1 elif solver_name == 'appsi_highs': @@ -351,9 +362,20 @@ def handle_results( table_writer = TableWriter(config=config) if config.save_duals: - table_writer.write_results(M=instance, results_with_duals=results, save_storage_levels=config.save_storage_levels, append=append, iteration=iteration) + table_writer.write_results( + M=instance, + results_with_duals=results, + save_storage_levels=config.save_storage_levels, + append=append, + iteration=iteration, + ) else: - table_writer.write_results(M=instance, append=append, save_storage_levels=config.save_storage_levels, iteration=iteration) + table_writer.write_results( + M=instance, + append=append, + save_storage_levels=config.save_storage_levels, + iteration=iteration, + ) if not config.silent: SE.write( diff --git a/temoa/temoa_model/table_data_puller.py b/temoa/_internal/table_data_puller.py similarity index 90% rename from temoa/temoa_model/table_data_puller.py rename to temoa/_internal/table_data_puller.py index 9cd1889e6..e5ac38fed 100644 --- a/temoa/temoa_model/table_data_puller.py +++ b/temoa/_internal/table_data_puller.py @@ -30,17 +30,18 @@ by Workers who shouldn't interact with DB). Dev Note: In future, if transition away from sqlite, this could all be refactored to perform tasks within workers, but concurrent access to sqlite is a no-go """ + import functools import logging -from collections import namedtuple, defaultdict -from enum import unique, Enum +from collections import defaultdict, namedtuple +from enum import Enum, unique from pyomo.common.numeric_types import value from pyomo.core import Objective -from temoa.temoa_model import temoa_rules -from temoa.temoa_model.exchange_tech_cost_ledger import ExchangeTechCostLedger, CostType -from temoa.temoa_model.temoa_model import TemoaModel +from temoa._internal import temoa_rules +from temoa._internal.exchange_tech_cost_ledger import CostType, ExchangeTechCostLedger +from temoa.core.model import TemoaModel logger = logging.getLogger(__name__) @@ -218,8 +219,12 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl res[fi][FlowType.OUT] -= flow # construction flows - for (r, i, t, v) in M.ConstructionInput.sparse_iterkeys(): - annual = value(M.ConstructionInput[r, i, t, v]) * value(M.V_NewCapacity[r, t, v]) / value(M.PeriodLength[v]) + for r, i, t, v in M.ConstructionInput.sparse_iterkeys(): + annual = ( + value(M.ConstructionInput[r, i, t, v]) + * value(M.V_NewCapacity[r, t, v]) + / value(M.PeriodLength[v]) + ) for s in M.TimeSeason[v]: for d in M.time_of_day: fi = FI(r, v, s, d, i, t, v, 'ConstructionInput') @@ -229,7 +234,7 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl res[fi][FlowType.IN] = flow # end of life flows - for (r, t, v, o) in M.EndOfLifeOutput.sparse_iterkeys(): + for r, t, v, o in M.EndOfLifeOutput.sparse_iterkeys(): if (r, t, v) not in M.retirementPeriods: continue for p in M.retirementPeriods[r, t, v]: @@ -258,9 +263,12 @@ def poll_storage_level_results(M: TemoaModel, epsilon=1e-5) -> dict[SLI, float]: for r, p, s, d, t, v in M.StorageLevel_rpsdtv: if t in M.tech_seasonal_storage: continue - state = value(M.V_StorageLevel[r, p, s, d, t, v]) / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) + state = value(M.V_StorageLevel[r, p, s, d, t, v]) / ( + value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod) + ) sli = SLI(r, p, s, d, t, v) - if abs(state) < epsilon: state = 0 # still want to know but decimals are ugly + if abs(state) < epsilon: + state = 0 # still want to know but decimals are ugly res[sli] = state for r, p, s_seq, t, v in M.SeasonalStorageLevel_rpstv: @@ -268,11 +276,17 @@ def poll_storage_level_results(M: TemoaModel, epsilon=1e-5) -> dict[SLI, float]: # Ratio of days in virtual storage season to days in actual season # Flows and StorageLevel are normalised to the number of days in the ACTUAL season, so must # be adjusted to the number of days in the virtual storage season - days_adjust = value(M.TimeSeasonSequential[p, s_seq, s]) / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) + days_adjust = value(M.TimeSeasonSequential[p, s_seq, s]) / ( + value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod) + ) for d in M.time_of_day: - state = value(M.V_SeasonalStorageLevel[r, p, s_seq, t, v]) + value(M.V_StorageLevel[r, p, s, d, t, v]) * days_adjust + state = ( + value(M.V_SeasonalStorageLevel[r, p, s_seq, t, v]) + + value(M.V_StorageLevel[r, p, s, d, t, v]) * days_adjust + ) sli = SLI(r, p, s_seq, d, t, v) - if abs(state) < epsilon: state = 0 # still want to know but decimals are ugly + if abs(state) < epsilon: + state = 0 # still want to know but decimals are ugly res[sli] = state return res @@ -320,9 +334,9 @@ def poll_cost_results( continue loan_life = value(LLN[r, t, v]) loan_rate = value(M.LoanRate[r, t, v]) - + if M.isSurvivalCurveProcess[r, t, v]: - model_loan_cost, undiscounted_cost = loan_costs_survival_curve( + model_loan_cost, undiscounted_cost = loan_costs_survival_curve( M=M, r=r, t=t, @@ -572,7 +586,7 @@ def poll_emissions( GDR = value(M.GlobalDiscountRate) ########################### - # Process Emissions + # Process Emissions ########################### base = [ @@ -631,14 +645,18 @@ def poll_emissions( d_costs[ei.r, ei.p, ei.t, ei.v] += discounted_emiss_cost ########################### - # Embodied Emissions + # Embodied Emissions ########################### # iterate through embodied flows embodied_flows: dict[EI, float] = defaultdict(float) for r, e, t, v in M.EmissionEmbodied.sparse_iterkeys(): - embodied_flows[EI(r, v, t, v, e)] += value(M.V_NewCapacity[r, t, v] * M.EmissionEmbodied[r, e, t, v] / M.PeriodLength[v]) # for embodied costs - flows[EI(r, v, t, v, e)] += value(M.V_NewCapacity[r, t, v] * M.EmissionEmbodied[r, e, t, v] / M.PeriodLength[v]) # add embodied to process emissions + embodied_flows[EI(r, v, t, v, e)] += value( + M.V_NewCapacity[r, t, v] * M.EmissionEmbodied[r, e, t, v] / M.PeriodLength[v] + ) # for embodied costs + flows[EI(r, v, t, v, e)] += value( + M.V_NewCapacity[r, t, v] * M.EmissionEmbodied[r, e, t, v] / M.PeriodLength[v] + ) # add embodied to process emissions # add embodied costs to process costs for ei in embodied_flows: @@ -651,12 +669,16 @@ def poll_emissions( if cost_index not in M.CostEmission: continue undiscounted_emiss_cost = ( - embodied_flows[ei] * M.CostEmission[ei.r, ei.v, ei.e] * M.PeriodLength[ei.v] # treat as fixed cost distributed over construction period + embodied_flows[ei] + * M.CostEmission[ei.r, ei.v, ei.e] + * M.PeriodLength[ei.v] # treat as fixed cost distributed over construction period ) discounted_emiss_cost = temoa_rules.fixed_or_variable_cost( cap_or_flow=embodied_flows[ei], cost_factor=M.CostEmission[ei.r, ei.v, ei.e], - cost_years=M.PeriodLength[ei.v], # treat as fixed cost distributed over construction period + cost_years=M.PeriodLength[ + ei.v + ], # treat as fixed cost distributed over construction period GDR=GDR, P_0=p_0, p=ei.v, @@ -674,8 +696,12 @@ def poll_emissions( if (r, t, v) not in M.retirementPeriods: continue for p in M.retirementPeriods[r, t, v]: - eol_flows[EI(r, p, t, v, e)] += value(M.V_AnnualRetirement[r, p, t, v] * M.EmissionEndOfLife[r, e, t, v]) # for eol costs - flows[EI(r, p, t, v, e)] += value(M.V_AnnualRetirement[r, p, t, v] * M.EmissionEndOfLife[r, e, t, v]) # add eol to process emissions + eol_flows[EI(r, p, t, v, e)] += value( + M.V_AnnualRetirement[r, p, t, v] * M.EmissionEndOfLife[r, e, t, v] + ) # for eol costs + flows[EI(r, p, t, v, e)] += value( + M.V_AnnualRetirement[r, p, t, v] * M.EmissionEndOfLife[r, e, t, v] + ) # add eol to process emissions # add embodied costs to process costs for ei in eol_flows: @@ -688,19 +714,23 @@ def poll_emissions( if cost_index not in M.CostEmission: continue undiscounted_emiss_cost = ( - eol_flows[ei] * M.CostEmission[ei.r, ei.p, ei.e] * M.PeriodLength[ei.p] # treat as fixed cost distributed over retirement period + eol_flows[ei] + * M.CostEmission[ei.r, ei.p, ei.e] + * M.PeriodLength[ei.p] # treat as fixed cost distributed over retirement period ) discounted_emiss_cost = temoa_rules.fixed_or_variable_cost( cap_or_flow=eol_flows[ei], cost_factor=M.CostEmission[ei.r, ei.p, ei.e], - cost_years=M.PeriodLength[ei.p], # treat as fixed cost distributed over retirement period + cost_years=M.PeriodLength[ + ei.p + ], # treat as fixed cost distributed over retirement period GDR=GDR, P_0=p_0, p=ei.p, ) ud_costs[ei.r, ei.p, ei.t, ei.v] += undiscounted_emiss_cost d_costs[ei.r, ei.p, ei.t, ei.v] += discounted_emiss_cost - + # finally, now that all costs are added up for each rptv, put in cost dict costs = defaultdict(dict) for rptv in ud_costs: @@ -709,4 +739,4 @@ def poll_emissions( costs[rptv][CostType.D_EMISS] = d_costs[rptv] # wow, that was like pulling teeth - return costs, flows \ No newline at end of file + return costs, flows diff --git a/temoa/temoa_model/table_writer.py b/temoa/_internal/table_writer.py similarity index 97% rename from temoa/temoa_model/table_writer.py rename to temoa/_internal/table_writer.py index 79ac82db0..776d6ca95 100644 --- a/temoa/temoa_model/table_writer.py +++ b/temoa/_internal/table_writer.py @@ -1,6 +1,7 @@ """ tool for writing outputs to database tables """ + import sqlite3 import sys from collections import defaultdict @@ -12,26 +13,25 @@ from pyomo.opt import SolverResults from definitions import PROJECT_ROOT -from temoa.extensions.monte_carlo.mc_run import ChangeRecord -from temoa.temoa_model.data_brick import DataBrick -from temoa.temoa_model.exchange_tech_cost_ledger import CostType -from temoa.temoa_model.table_data_puller import ( - poll_capacity_results, - poll_flow_results, +from temoa._internal.data_brick import DataBrick +from temoa._internal.exchange_tech_cost_ledger import CostType +from temoa._internal.table_data_puller import ( + EI, FI, + CapData, FlowType, - EI, - SLI, _marks, - CapData, - poll_objective, - poll_storage_level_results, + poll_capacity_results, poll_cost_results, poll_emissions, + poll_flow_results, + poll_objective, + poll_storage_level_results, ) -from temoa.temoa_model.temoa_config import TemoaConfig -from temoa.temoa_model.temoa_mode import TemoaMode -from temoa.temoa_model.temoa_model import TemoaModel +from temoa.core.config import TemoaConfig +from temoa.core.model import TemoaModel +from temoa.core.modes import TemoaMode +from temoa.extensions.monte_carlo.mc_run import ChangeRecord if TYPE_CHECKING: pass @@ -243,8 +243,10 @@ def write_storage_level(self, M: TemoaModel, iteration=None) -> None: data = [] for sli, storage_level in storage_levels.items(): sector = self.tech_sectors[sli.t] - data.append((scenario_name, sli.r, sector, sli.p, sli.s, sli.d, sli.t, sli.v, storage_level)) - + data.append( + (scenario_name, sli.r, sector, sli.p, sli.s, sli.d, sli.t, sli.v, storage_level) + ) + qry = f'INSERT INTO OutputStorageLevel VALUES {_marks(9)}' self.con.executemany(qry, data) self.con.commit() @@ -282,9 +284,9 @@ def write_emissions(self, iteration=None) -> None: val = self.emission_register[ei] if abs(val) < self.epsilon: continue - if hasattr(ei, 'p'): # emissions from flows + if hasattr(ei, 'p'): # emissions from flows entry = (scenario, ei.r, sector, ei.p, ei.e, ei.t, ei.v, val) - else: # embodied emissions + else: # embodied emissions entry = (scenario, ei.r, sector, ei.v, ei.e, ei.t, ei.v, val) data.append(entry) qry = f'INSERT INTO OutputEmission VALUES {_marks(8)}' @@ -358,7 +360,7 @@ def write_flow_tables(self, iteration=None) -> None: FlowType.OUT: 'OutputFlowOut', FlowType.IN: 'OutputFlowIn', FlowType.CURTAIL: 'OutputCurtailment', - FlowType.FLEX: 'OutputCurtailment', # devnote: should flex have its own table? + FlowType.FLEX: 'OutputCurtailment', # devnote: should flex have its own table? } for flow_type, table_name in table_associations.items(): diff --git a/temoa/temoa_model/temoa_initialize.py b/temoa/_internal/temoa_initialize.py similarity index 92% rename from temoa/temoa_model/temoa_initialize.py rename to temoa/_internal/temoa_initialize.py index 15f8237e6..066ad3a03 100644 --- a/temoa/temoa_model/temoa_initialize.py +++ b/temoa/_internal/temoa_initialize.py @@ -18,8 +18,9 @@ in LICENSE.txt. Users uncompressing this from an archive may not have received this license file. If not, see . """ -from collections import defaultdict -from itertools import product as cross_product, product + +from itertools import product as cross_product + from operator import itemgetter as iget from sys import stderr as SE from typing import TYPE_CHECKING, Iterable @@ -28,14 +29,13 @@ from pyomo.core import Set if TYPE_CHECKING: - from temoa.temoa_model.temoa_model import TemoaModel + from temoa.core.model import TemoaModel -from io import StringIO - -from pyomo.environ import value from logging import getLogger +from pyomo.environ import value + logger = getLogger(__name__) @@ -72,7 +72,7 @@ def CommodityBalanceConstraintErrorCheck(supplied, demanded, r, p, s, d, c): if isinstance(supplied, int) or isinstance(demanded, int): expr = str(supplied == demanded) msg = ( - "Unable to balance commodity {} in ({}, {}, {}, {}).\n" + 'Unable to balance commodity {} in ({}, {}, {}, {}).\n' 'No flows on one side of constraint expression:\n' ' {}\n' 'Possible reasons:\n' @@ -93,7 +93,7 @@ def AnnualCommodityBalanceConstraintErrorCheck(supplied, demanded, r, p, c): if isinstance(supplied, int) or isinstance(demanded, int): expr = str(supplied == demanded) msg = ( - "Unable to balance annual commodity {} in ({}, {}).\n" + 'Unable to balance annual commodity {} in ({}, {}).\n' 'No flows on one side of constraint expression:\n' ' {}\n' 'Possible reasons:\n' @@ -136,7 +136,7 @@ def validate_time(M: 'TemoaModel'): if isinstance(year, int): continue - msg = f'Set "time_exist" requires integer-only elements.\n\n ' f'Invalid element: "{year}"' + msg = f'Set "time_exist" requires integer-only elements.\n\n Invalid element: "{year}"' logger.error(msg) raise Exception(msg) @@ -144,7 +144,7 @@ def validate_time(M: 'TemoaModel'): if isinstance(year, int): continue - msg = f'Set "time_future" requires integer-only elements.\n\n ' f'invalid element: "{year}"' + msg = f'Set "time_future" requires integer-only elements.\n\n invalid element: "{year}"' logger.error(msg) raise Exception(msg) @@ -180,17 +180,8 @@ def validate_SegFrac(M: 'TemoaModel'): """Ensure that the segment fractions adds up to 1""" for p in M.time_optimize: - - expected_keys = set( - (p, s, d) - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - keys = set( - (_p, s, d) - for _p, s, d in M.SegFrac.sparse_iterkeys() - if _p == p - ) + expected_keys = set((p, s, d) for s in M.TimeSeason[p] for d in M.time_of_day) + keys = set((_p, s, d) for _p, s, d in M.SegFrac.sparse_iterkeys() if _p == p) if expected_keys != keys: extra = keys.difference(expected_keys) @@ -203,10 +194,7 @@ def validate_SegFrac(M: 'TemoaModel'): logger.error(msg) raise ValueError(msg) - total = sum( - M.SegFrac[k] - for k in keys - ) + total = sum(M.SegFrac[k] for k in keys) if abs(float(total) - 1.0) > 0.001: # We can't explicitly test for "!= 1.0" because of incremental rounding @@ -228,7 +216,7 @@ def validate_SegFrac(M: 'TemoaModel'): ).format(p, items, total) logger.error(msg) raise Exception(msg) - + def validate_TimeNext(M: 'TemoaModel'): """ @@ -238,7 +226,7 @@ def validate_TimeNext(M: 'TemoaModel'): # Only check TimeNext if it is actually being used if M.TimeSequencing.first() != 'manual': return - + segfrac_psd = set(M.SegFrac.sparse_iterkeys()) time_next_psd = set((p, s, d) for p, s, d, s_next, d_next in M.TimeNext) time_next_psd_next = set((p, s_next, d_next) for p, s, d, s_next, d_next in M.TimeNext) @@ -302,10 +290,9 @@ def CheckEfficiencyIndices(M: 'TemoaModel'): f_msg = msg.format(', '.join(diff)) logger.error(f_msg) raise ValueError(f_msg) - -def CheckEfficiencyVariable(M: 'TemoaModel'): +def CheckEfficiencyVariable(M: 'TemoaModel'): count_rpitvo = dict() # Pull non-variable efficiency by default for r, i, t, v, o in M.Efficiency.sparse_iterkeys(): @@ -314,29 +301,28 @@ def CheckEfficiencyVariable(M: 'TemoaModel'): # Still want it for end of life flows continue for p in M.processPeriods[r, t, v]: - M.isEfficiencyVariable[r, p, i, t, v, o] = False + M.isEfficiencyVariable[r, p, i, t, v, o] = False count_rpitvo[r, p, i, t, v, o] = 0 - + annual = set() # Check for bad values and count up the good ones for r, p, s, d, i, t, v, o in M.EfficiencyVariable.sparse_iterkeys(): - if p not in M.processPeriods[r, t, v]: - msg = f"Invalid period {p} for process {r, t, v} in EfficiencyVariable table" + msg = f'Invalid period {p} for process {r, t, v} in EfficiencyVariable table' logger.error(msg) raise ValueError(msg) - + if t in M.tech_annual: annual.add(t) - + # Good value, pull from EfficiencyVariable table count_rpitvo[r, p, i, t, v, o] += 1 for t in annual: msg = ( - f"Variable efficiencies were provided for the annual technology {t}, which has " - "no variable output. This will only be applied to flows on non-annual commodities. " - "This is ambiguous behaviour and not recommended." + f'Variable efficiencies were provided for the annual technology {t}, which has ' + 'no variable output. This will only be applied to flows on non-annual commodities. ' + 'This is ambiguous behaviour and not recommended.' ) logger.warning(msg) @@ -344,34 +330,33 @@ def CheckEfficiencyVariable(M: 'TemoaModel'): # log a warning if some are missing (allowed but maybe accidental) num_seg = len(M.TimeSeason[p]) * len(M.time_of_day) for (r, p, i, t, v, o), count in count_rpitvo.items(): - if count > 0: M.isEfficiencyVariable[r, p, i, t, v, o] = True if count < num_seg: logger.info( 'Some but not all EfficiencyVariable values were set (%i out of a possible %i) for: %s' - ' Missing values will default to value set in Efficiency table.' - , count, num_seg, (r, p, i, t, v, o) + ' Missing values will default to value set in Efficiency table.', + count, + num_seg, + (r, p, i, t, v, o), ) def CheckCapacityFactorProcess(M: 'TemoaModel'): - count_rptv = dict() # Pull CapacityFactorTech by default for r, p, s, d, t in M.CapacityFactor_rpsdt: for v in M.processVintages[r, p, t]: M.isCapacityFactorProcess[r, p, t, v] = False count_rptv[r, p, t, v] = 0 - + # Check for bad values and count up the good ones for r, p, s, d, t, v in M.CapacityFactorProcess.sparse_iterkeys(): - if v not in M.processVintages[r, p, t]: - msg = f"Invalid process {p, v} for {r, t} in CapacityFactorProcess table" + msg = f'Invalid process {p, v} for {r, t} in CapacityFactorProcess table' logger.error(msg) raise ValueError(msg) - + # Good value, pull from CapacityFactorProcess table count_rptv[r, p, t, v] += 1 @@ -384,8 +369,10 @@ def CheckCapacityFactorProcess(M: 'TemoaModel'): if count < num_seg: logger.info( 'Some but not all processes were set in CapacityFactorProcess (%i out of a possible %i) for: %s' - ' Missing values will default to CapacityFactorTech value or 1 if that is not set either.' - , count, num_seg, (r, p, t, v) + ' Missing values will default to CapacityFactorTech value or 1 if that is not set either.', + count, + num_seg, + (r, p, t, v), ) @@ -506,7 +493,7 @@ def CreateDemands(M: 'TemoaModel'): DSD_region = iget(0) DSD_period = iget(1) DSD_dem = iget(4) - + # Step 1: Check if any demand commodities are going unused used_dems = set(dem for r, p, dem in M.Demand.sparse_iterkeys()) unused_dems = sorted(M.commodity_demand.difference(used_dems)) @@ -523,13 +510,13 @@ def CreateDemands(M: 'TemoaModel'): # unset_defaults = set(M.SegFrac.sparse_iterkeys()) # unset_defaults.difference_update(DDD.sparse_iterkeys()) # if unset_defaults: - # Some hackery because Pyomo thinks that this Param is constructed. - # However, in our view, it is not yet, because we're specifically - # targeting values that have not yet been constructed, that we know are - # valid, and that we will need. - # DDD._constructed = False - # for tslice in unset_defaults: - # DDD[tslice] = M.SegFrac[tslice] # DDD._constructed = True + # Some hackery because Pyomo thinks that this Param is constructed. + # However, in our view, it is not yet, because we're specifically + # targeting values that have not yet been constructed, that we know are + # valid, and that we will need. + # DDD._constructed = False + # for tslice in unset_defaults: + # DDD[tslice] = M.SegFrac[tslice] # DDD._constructed = True # Step 3: Check that DDD sums to 1 # devnote: this seems redundant to the SegFrac sum to 1 check. @@ -568,7 +555,9 @@ def CreateDemands(M: 'TemoaModel'): if unset_demand_distributions: for p in M.time_optimize: unset_distributions = set( - cross_product(M.regions, (p,), M.TimeSeason[p], M.time_of_day, unset_demand_distributions) + cross_product( + M.regions, (p,), M.TimeSeason[p], M.time_of_day, unset_demand_distributions + ) ) for r, p, s, d, dem in unset_distributions: DSD[r, p, s, d, dem] = value(M.SegFrac[p, s, d]) # DSD._constructed = True @@ -583,7 +572,7 @@ def CreateDemands(M: 'TemoaModel'): keys = [ k for k in DSD.sparse_iterkeys() - if DSD_region(k) == r and DSD_period(k) == p and DSD_dem(k) == dem + if DSD_region(k) == r and DSD_period(k) == p and DSD_dem(k) == dem ] if len(keys) != expected_key_length: # this could be very slow but only calls when there's a problem @@ -595,7 +584,8 @@ def CreateDemands(M: 'TemoaModel'): ) logger.info( 'Missing some time slices for Demand Specific Distribution %s: %s', - (r, p, dem), missing, + (r, p, dem), + missing, ) total = sum(value(DSD[i]) for i in keys) if abs(value(total) - 1.0) > 0.001: @@ -620,7 +610,7 @@ def CreateDemands(M: 'TemoaModel'): ) logger.error(msg.format((r, p, dem), items, total)) raise ValueError(msg.format((r, p, dem), items, total)) - + logger.debug('Finished creating demand distributions') @@ -766,8 +756,8 @@ def CreateSparseDicts(M: 'TemoaModel'): logger.info(msg) # Devnote: these are now useful due to end of life flows and # Growth constraints growing from existing cap so do not skip - #SE.write(msg % (l_process, l_lifetime, l_first_period)) - #continue + # SE.write(msg % (l_process, l_lifetime, l_first_period)) + # continue eindex = (r, i, t, v, o) if M.Efficiency[eindex] == 0: @@ -804,13 +794,18 @@ def CreateSparseDicts(M: 'TemoaModel'): # l_loan_life = value(M.LoanLifetimeProcess[l_process]) # if v + l_loan_life >= p: # M.processLoans[pindex] = True - + # Get all periods where the process can retire - if t not in M.tech_uncap and any(( - p <= v+l_lifetime < p + value(M.PeriodLength[p]), # natural eol this period - t in M.tech_retirement and v < p <= v+l_lifetime - value(M.PeriodLength[p]), # allowed early retirement - M.isSurvivalCurveProcess[r, t, v] and v <= p <= v+l_lifetime - )): + if t not in M.tech_uncap and any( + ( + p <= v + l_lifetime < p + value(M.PeriodLength[p]), # natural eol this period + t in M.tech_retirement + and v + < p + <= v + l_lifetime - value(M.PeriodLength[p]), # allowed early retirement + M.isSurvivalCurveProcess[r, t, v] and v <= p <= v + l_lifetime, + ) + ): if (r, t, v) not in M.retirementPeriods: M.retirementPeriods[r, t, v] = set() M.retirementPeriods[r, t, v].add(p) @@ -948,7 +943,7 @@ def CreateSparseDicts(M: 'TemoaModel'): M.capacityConsumptionTechs[r, v, i].add(t) for r, t, v, o in M.EndOfLifeOutput.sparse_iterkeys(): if (r, t, v) not in M.retirementPeriods: - continue # might be running myopic + continue # might be running myopic for p in M.retirementPeriods[r, t, v]: # What periods can this process retire in, either naturally or economically? if (r, p, o) not in M.retirementProductionProcesses: @@ -965,8 +960,12 @@ def CreateSparseDicts(M: 'TemoaModel'): SE.write(msg.format(i)) # valid region-period-commodity sets for commodity balance constraints - commodityUpstream_rpi = set(M.commodityUStreamProcess | M.retirementProductionProcesses | M.importRegions) - commodityDownstream_rpo = set(M.commodityDStreamProcess | M.capacityConsumptionTechs | M.exportRegions) + commodityUpstream_rpi = set( + M.commodityUStreamProcess | M.retirementProductionProcesses | M.importRegions + ) + commodityDownstream_rpo = set( + M.commodityDStreamProcess | M.capacityConsumptionTechs | M.exportRegions + ) M.commodityBalance_rpc = commodityUpstream_rpi.intersection(commodityDownstream_rpo) # A dictionary of whether a storage tech is seasonal, just to speed things up @@ -1037,9 +1036,7 @@ def CreateSparseDicts(M: 'TemoaModel'): ) M.activeActivity_rptv = set( - (r, p, t, v) - for r, p, t in M.processVintages - for v in M.processVintages[r, p, t] + (r, p, t, v) for r, p, t in M.processVintages for v in M.processVintages[r, p, t] ) # devnote: currently unused @@ -1097,7 +1094,6 @@ def CreateSparseDicts(M: 'TemoaModel'): def CreateTimeSequence(M: 'TemoaModel'): - logger.debug('Creating sequence of time slices.') # Establishing sequence of states @@ -1127,37 +1123,33 @@ def CreateTimeSequence(M: 'TemoaModel'): msg = f"Invalid time sequencing parameter loaded '{M.TimeSequencing.first()}'. Likely code error." logger.error(msg) raise ValueError(msg) - - msg += (' This behaviour can be changed using the ' - 'time_sequencing parameter in the config file. ') + + msg += ' This behaviour can be changed using the time_sequencing parameter in the config file. ' logger.info(msg) logger.debug('Creating superimposed sequential seasons.') - + # Superimposed sequential seasons for p in M.time_optimize: - seasons = [ - (s_seq, s) - for _p, s_seq, s in M.ordered_season_sequential - if _p == p - ] + seasons = [(s_seq, s) for _p, s_seq, s in M.ordered_season_sequential if _p == p] for i, (s_seq, s) in enumerate(seasons): M.sequential_to_season[p, s_seq] = s if (s_seq, s) == seasons[-1]: M.time_next_sequential[p, s_seq] = seasons[0][0] else: - M.time_next_sequential[p, s_seq] = seasons[i+1][0] - + M.time_next_sequential[p, s_seq] = seasons[i + 1][0] + logger.debug('Created time sequence.') def CreateTimeSeasonSequential(M: 'TemoaModel'): - - if all(( - not M.tech_seasonal_storage, - not M.RampUpHourly, - not M.RampDownHourly, - )): + if all( + ( + not M.tech_seasonal_storage, + not M.RampUpHourly, + not M.RampDownHourly, + ) + ): # Don't need it anyway return @@ -1172,23 +1164,29 @@ def CreateTimeSeasonSequential(M: 'TemoaModel'): for p in M.TimeSeason: for s in M.TimeSeason[p]: M.ordered_season_sequential.add((p, s, s)) - M.TimeSeasonSequential[p, s, s] = value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod) + M.TimeSeasonSequential[p, s, s] = value(M.SegFracPerSeason[p, s]) * value( + M.DaysPerPeriod + ) else: msg = ( f'No data in TimeSeasonSequential but time_sequencing parameter set to {M.TimeSequencing.first()} ' - 'and inter-season features used. TimeSeasonSequential must be filled for this type of time ' + 'and inter-season features used. TimeSeasonSequential must be filled for this type of time ' 'sequencing if seasonal storage or inter-season constraints like RampUp/RampDown are used. Check ' 'the config file.' ) logger.error(msg) raise ValueError(msg) - + sequential = dict() prev_n = 0 for p, s_seq, s in M.TimeSeasonSequential.sparse_iterkeys(): num_days = value(M.TimeSeasonSequential[p, s_seq, s]) - if M.TimeSequencing.first() == 'consecutive_days' and prev_n and abs(num_days - prev_n) >= 0.001: + if ( + M.TimeSequencing.first() == 'consecutive_days' + and prev_n + and abs(num_days - prev_n) >= 0.001 + ): msg = ( 'TimeSequencing set to consecutive_days but two consecutive seasons do not represent the same ' f'number of days. This discontinuity will lead to bad model behaviour: {p, s}, days: {num_days}. ' @@ -1196,7 +1194,7 @@ def CreateTimeSeasonSequential(M: 'TemoaModel'): ) logger.error(msg) raise ValueError(msg) - prev_n = num_days # for validating next in sequence + prev_n = num_days # for validating next in sequence # Regardless of their order, make sure the total number of days adds up if (p, s) not in sequential: @@ -1204,13 +1202,9 @@ def CreateTimeSeasonSequential(M: 'TemoaModel'): sequential[p, s] += num_days # Check that TimeSeasonSequential num_days total to number of days in each period - count_total = dict() # {p: n} total days per period according to TimeSeasonSequential + count_total = dict() # {p: n} total days per period according to TimeSeasonSequential for p in M.time_optimize: - count_total[p] = sum( - sequential[p, s] - for _p, s in sequential - if _p == p - ) + count_total[p] = sum(sequential[p, s] for _p, s in sequential if _p == p) if abs(count_total[p] - value(M.DaysPerPeriod)) >= 0.001: logger.warning( f'Sum of num_days in TimeSeasonSequential ({count_total[p]}) ' @@ -1219,7 +1213,7 @@ def CreateTimeSeasonSequential(M: 'TemoaModel'): ) # Check that seasons using in storage seasons are actual seasons - for (p, s) in sequential: + for p, s in sequential: if (p, s) not in M.SegFracPerSeason: msg = ( f'Period-season index {(p, s)} that does not exist in ' @@ -1227,14 +1221,14 @@ def CreateTimeSeasonSequential(M: 'TemoaModel'): ) logger.error(msg) raise ValueError(msg) - - for (p, s) in M.SegFracPerSeason.sparse_iterkeys(): + + for p, s in M.SegFracPerSeason.sparse_iterkeys(): if s not in M.TimeSeason[p]: continue # Check that all seasons are used in sequential seasons if (p, s) not in sequential: - msg = (f'Period-season index {(p, s)} absent from TimeSeasonSequential') + msg = f'Period-season index {(p, s)} absent from TimeSeasonSequential' logger.warning(msg) # Check that the two tables agree on the total seasonal composition of each period @@ -1242,9 +1236,9 @@ def CreateTimeSeasonSequential(M: 'TemoaModel'): segfracseq = sequential[p, s] / count_total[p] if abs(segfrac - segfracseq) >= 0.001: msg = ( - 'Discrepancy of total period-season composition between ' + 'Discrepancy of total period-season composition between ' 'TimeSegmentFraction and TimeSeasonSequential. Total fraction of each ' - 'period assigned to each season should match: ' + 'period assigned to each season should match: ' f'TimeSegmentFraction: {(p, s, value(M.SegFracPerSeason[p, s]))}' f', TimeSeasonSequential: {(p, s, segfracseq)}' ) @@ -1252,11 +1246,10 @@ def CreateTimeSeasonSequential(M: 'TemoaModel'): def CreateSurvivalCurve(M: 'TemoaModel'): - - rtv_interpolated = set() # so we only need one warning + rtv_interpolated = set() # so we only need one warning - for (r, _, t, v, _) in M.Efficiency.sparse_iterkeys(): - M.isSurvivalCurveProcess[r, t, v] = False # by default + for r, _, t, v, _ in M.Efficiency.sparse_iterkeys(): + M.isSurvivalCurveProcess[r, t, v] = False # by default # Collect rptv indices into (r, t, v): p dictionary for r, p, t, v in M.LifetimeSurvivalCurve.sparse_iterkeys(): @@ -1279,27 +1272,26 @@ def CreateSurvivalCurve(M: 'TemoaModel'): ) logger.error(msg) raise ValueError(msg) - + if value(M.LifetimeSurvivalCurve[r, v, t, v]) != 1: msg = ( 'LifetimeSurvivalCurve must begin at 1 for calculating annual retirements. ', - f'Got {value(M.LifetimeSurvivalCurve[r, v, t, v])} for ({r}, {v}, {t}, {v})' + f'Got {value(M.LifetimeSurvivalCurve[r, v, t, v])} for ({r}, {v}, {t}, {v})', ) logger.error(msg) raise ValueError(msg) # Collect a list of processes that needed to be interpolated, for warning - if periods_rtv != list(range(p_first, p_last+1, 1)): + if periods_rtv != list(range(p_first, p_last + 1, 1)): rtv_interpolated.add((r, t, v)) between_periods = [] for i, p in enumerate(periods_rtv): - if i == 0: - continue # Cant look back from first period. Could be zero but hey why not - + continue # Cant look back from first period. Could be zero but hey why not + # Check that the survival curve monotonically decreases - p_prev = periods_rtv[i-1] + p_prev = periods_rtv[i - 1] lsc = value(M.LifetimeSurvivalCurve[r, p, t, v]) lsc_prev = value(M.LifetimeSurvivalCurve[r, p_prev, t, v]) if lsc - lsc_prev > 0.0001: @@ -1309,9 +1301,9 @@ def CreateSurvivalCurve(M: 'TemoaModel'): ).format((r, p_prev, t, v), (r, p, t, v)) logger.error(msg) raise ValueError(msg) - + if p - p_prev > 1: - _between_periods = list(range(p_prev+1, p, 1)) + _between_periods = list(range(p_prev + 1, p, 1)) for _p in _between_periods: x = (_p - p_prev) / (p - p_prev) lsc_x = lsc_prev + x * (lsc - lsc_prev) @@ -1331,7 +1323,7 @@ def CreateSurvivalCurve(M: 'TemoaModel'): msg = ( f'The LifetimeProcess parameter for process ({r, t, v}) with survival curve ' f'does not extend beyond the end of that survival curve in {p}. To agree with ' - f'the survival curve, set LifetimeProcess[{r, t, v}] >= {p-v}' + f'the survival curve, set LifetimeProcess[{r, t, v}] >= {p - v}' ) logger.error(msg) raise ValueError(msg) @@ -1340,12 +1332,12 @@ def CreateSurvivalCurve(M: 'TemoaModel'): f'The LifetimeProcess parameter for process ({r, t, v}) with survival curve ' f'does match the end of that survival curve in {p}. This will waste compute. ' 'To agree with the survival curve and suppress this warning, set ' - f'LifetimeProcess[{r, t, v}] = {p-v}' + f'LifetimeProcess[{r, t, v}] = {p - v}' ) logger.warning(msg) - + continue - + # Flag if the last period is not fraction = 0. This is important for investment costs if p == p_last and lsc > 0.0001: msg = ( @@ -1355,19 +1347,19 @@ def CreateSurvivalCurve(M: 'TemoaModel'): ) logger.error(msg) raise ValueError(msg) - + M.survivalCurvePeriods[r, t, v].extend(between_periods) M.survivalCurvePeriods[r, t, v] = set(M.survivalCurvePeriods[r, t, v]) if rtv_interpolated: msg = ( 'For the purposes of investment cost accounting, LifetimeSurvivalCurve must be defined ' - f'for each individual year. Gaps between defined years will be filled by linear interpolation. ' + 'for each individual year. Gaps between defined years will be filled by linear interpolation. ' 'Otherwise, these individual years can be defined manually. Interpolated processes: {}' ).format([rtv for rtv in rtv_interpolated]) logger.info(msg) - + # --------------------------------------------------------------- # Create sparse parameter indices. # These functions are called from temoa_model.py and use the sparse keys @@ -1504,9 +1496,7 @@ def RetiredCapacityVariableIndices(M: 'TemoaModel'): def AnnualRetirementVariableIndices(M: 'TemoaModel'): return set( - (r, p, t, v) - for r, t, v in M.retirementPeriods - for p in M.retirementPeriods[r, t, v] + (r, p, t, v) for r, t, v in M.retirementPeriods for p in M.retirementPeriods[r, t, v] ) @@ -1545,6 +1535,7 @@ def CurtailmentVariableIndices(M: 'TemoaModel'): def StorageLevelVariableIndices(M: 'TemoaModel'): return M.storageLevelIndices_rpsdtv + def SeasonalStorageLevelVariableIndices(M: 'TemoaModel'): return M.seasonalStorageLevelIndices_rpstv @@ -1555,7 +1546,7 @@ def SeasonalStorageConstraintIndices(M: 'TemoaModel'): for r, p, s, t, v in M.seasonalStorageLevelIndices_rpstv for d in M.time_of_day ) - + return indices @@ -1774,8 +1765,8 @@ def RampDownDayConstraintIndices(M: 'TemoaModel'): def RampUpSeasonConstraintIndices(M: 'TemoaModel'): if M.TimeSequencing.first() == 'consecutive_days': - return Set.Skip # dont need this constraint - + return Set.Skip # dont need this constraint + # s, s_next indexing ensures we dont build redundant constraints indices = set( (r, p, s, s_next, t, v) @@ -1783,9 +1774,12 @@ def RampUpSeasonConstraintIndices(M: 'TemoaModel'): for v in M.rampUpVintages[r, p, t] for _p, s_seq, s in M.ordered_season_sequential if _p == p - for s_seq_next in (M.time_next_sequential[p, s_seq],) # next sequential season - for s_next in (M.sequential_to_season[p, s_seq_next],) # next sequential season's matching season - if s_next != M.time_next[p, s, M.time_of_day.last()][0] # to avoid redundancy on RampDay constraint + for s_seq_next in (M.time_next_sequential[p, s_seq],) # next sequential season + for s_next in ( + M.sequential_to_season[p, s_seq_next], + ) # next sequential season's matching season + if s_next + != M.time_next[p, s, M.time_of_day.last()][0] # to avoid redundancy on RampDay constraint ) return indices @@ -1793,17 +1787,20 @@ def RampUpSeasonConstraintIndices(M: 'TemoaModel'): def RampDownSeasonConstraintIndices(M: 'TemoaModel'): if M.TimeSequencing.first() == 'consecutive_days': - return Set.Skip # dont need this constraint - + return Set.Skip # dont need this constraint + # s, s_next indexing ensures we dont build redundant constraints indices = set( (r, p, s, s_next, t, v) for r, p, t in M.rampDownVintages for v in M.rampDownVintages[r, p, t] for _p, s_seq, s in M.ordered_season_sequential - for s_seq_next in (M.time_next_sequential[p, s_seq],) # next sequential season - for s_next in (M.sequential_to_season[p, s_seq_next],) # next sequential season's matching season - if s_next != M.time_next[p, s, M.time_of_day.last()][0] # to avoid redundancy on RampDay constraint + for s_seq_next in (M.time_next_sequential[p, s_seq],) # next sequential season + for s_next in ( + M.sequential_to_season[p, s_seq_next], + ) # next sequential season's matching season + if s_next + != M.time_next[p, s, M.time_of_day.last()][0] # to avoid redundancy on RampDay constraint ) return indices @@ -1818,7 +1815,7 @@ def ReserveMarginIndices(M: 'TemoaModel'): for s in M.TimeSeason[p] for d in M.time_of_day ) - + return indices @@ -1832,14 +1829,12 @@ def LimitTechInputSplitConstraintIndices(M: 'TemoaModel'): for d in M.time_of_day ) ann_indices = set( - (r, p, i, t, op) - for r, p, i, t, op in M.inputSplitVintages - if t in M.tech_annual + (r, p, i, t, op) for r, p, i, t, op in M.inputSplitVintages if t in M.tech_annual ) if len(ann_indices) > 0: msg = ( - "Warning: Annual technologies included in LimitTechInputSplit table. " - "Use LimitTechInputSplitAnnual table instead or these constraints will be ignored: {}" + 'Warning: Annual technologies included in LimitTechInputSplit table. ' + 'Use LimitTechInputSplitAnnual table instead or these constraints will be ignored: {}' ) logger.warning(msg.format(ann_indices)) @@ -1877,14 +1872,12 @@ def LimitTechOutputSplitConstraintIndices(M: 'TemoaModel'): for d in M.time_of_day ) ann_indices = set( - (r, p, t, o, op) - for r, p, t, o, op in M.outputSplitVintages - if t in M.tech_annual + (r, p, t, o, op) for r, p, t, o, op in M.outputSplitVintages if t in M.tech_annual ) if len(ann_indices) > 0: msg = ( - "Warning: Annual technologies included in LimitTechOutputSplit table. " - "Use LimitTechOutputSplitAnnual table instead or these constraints will be ignored: {}" + 'Warning: Annual technologies included in LimitTechOutputSplit table. ' + 'Use LimitTechOutputSplitAnnual table instead or these constraints will be ignored: {}' ) logger.warning(msg.format(ann_indices)) @@ -1919,6 +1912,7 @@ def LimitGrowthCapacityIndices(M: 'TemoaModel'): ) return indices + def LimitDegrowthCapacityIndices(M: 'TemoaModel'): indices = set( (r, p, t, op) @@ -1936,6 +1930,7 @@ def LimitGrowthNewCapacityIndices(M: 'TemoaModel'): ) return indices + def LimitDegrowthNewCapacityIndices(M: 'TemoaModel'): indices = set( (r, p, t, op) @@ -1953,6 +1948,7 @@ def LimitGrowthNewCapacityDeltaIndices(M: 'TemoaModel'): ) return indices + def LimitDegrowthNewCapacityDeltaIndices(M: 'TemoaModel'): indices = set( (r, p, t, op) @@ -1963,7 +1959,6 @@ def LimitDegrowthNewCapacityDeltaIndices(M: 'TemoaModel'): def loop_period_next_timeslice(M: 'TemoaModel', p, s, d) -> tuple[str, str]: - # Final time slice of final season (end of period) # Loop state back to initial state of first season # Loop the period @@ -1989,7 +1984,6 @@ def loop_period_next_timeslice(M: 'TemoaModel', p, s, d) -> tuple[str, str]: def loop_season_next_timeslice(M: 'TemoaModel', p, s, d) -> tuple[str, str]: - # We loop each season so never carrying state between seasons s_next = s diff --git a/temoa/temoa_model/temoa_rules.py b/temoa/_internal/temoa_rules.py similarity index 89% rename from temoa/temoa_model/temoa_rules.py rename to temoa/_internal/temoa_rules.py index c9df18cb0..4de98a9f3 100644 --- a/temoa/temoa_model/temoa_rules.py +++ b/temoa/_internal/temoa_rules.py @@ -23,19 +23,19 @@ from sys import stderr as SE from typing import TYPE_CHECKING -from pyomo.core import Var, Expression +from pyomo.core import Expression, Var from pyomo.environ import Constraint, value -from temoa.temoa_model.temoa_initialize import ( - DemandConstraintErrorCheck, - CommodityBalanceConstraintErrorCheck, +from temoa._internal.temoa_initialize import ( AnnualCommodityBalanceConstraintErrorCheck, + CommodityBalanceConstraintErrorCheck, + DemandConstraintErrorCheck, gather_group_regions, gather_group_techs, ) if TYPE_CHECKING: - from temoa.temoa_model.temoa_model import TemoaModel + from temoa.core.model import TemoaModel logger = getLogger(__name__) # --------------------------------------------------------------- @@ -65,7 +65,7 @@ def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): For processes using survival curves, the yearly survival curve :math:`\text{LSC}_{r,p,t,v}` is averaged over the period to get the effective remaining capacity for that period Because this - implicitly handles mid-period end of life, :math:`\text{PLF}_{r,p,t,v}` is used to account for both + implicitly handles mid-period end of life, :math:`\text{PLF}_{r,p,t,v}` is used to account for both phenomena. .. figure:: images/adjusted_capacity_sc.* @@ -77,7 +77,7 @@ def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): For processes with a defined survival curve, the surviving capacity is averaged over each period to get the adjusted capacity. This implicitly handles mid-period end of life as a survival curve will always be zero after the end of life of a process. - + .. math:: :label: Adjusted Capacity @@ -97,8 +97,8 @@ def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): & \text{if } \ v \notin T^e \end{cases} - \\\text{where } - \text{PLF}_{r,p,t,v} = + \\\text{where } + \text{PLF}_{r,p,t,v} = \begin{cases} \frac{1}{\text{LEN}_p} \cdot \left( \sum\limits_{y = p}^{p+\text{LEN}_{p}-1}{\text{LSC}_{r,y,t,v}} @@ -124,16 +124,17 @@ def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): early_retirements = sum( M.V_RetiredCapacity[r, S_p, t, v] / value(M.LifetimeSurvivalCurve[r, S_p, t, v]) for S_p in M.time_optimize - if v < S_p <= p and S_p < v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[S_p]) + if v < S_p <= p + and S_p < v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[S_p]) ) remaining_capacity = (built_capacity - early_retirements) * value(M.ProcessLifeFrac[r, p, t, v]) return M.V_Capacity[r, p, t, v] == remaining_capacity - + def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): r""" - Get the annualised retirement rate for a process in a given period. + Get the annualised retirement rate for a process in a given period. Used to output retirement (including end of life, EOL) and to model end of life flows and emissions. Assumes that retirement from the beginning of each period is evenly distributed over that model period :math:`\frac{1}{\text{LEN}_p}` @@ -151,17 +152,17 @@ def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): \frac{1}{\text{LEN}_p} \cdot \frac{\text{LSC}_{r,p,t,v}}{\text{PLF}_{r,p,t,v}} \cdot \textbf{CAP}_{r,p,t,v} & \text{if EOL} \\ - \frac{1}{\text{LEN}_p} \cdot - \left( + \frac{1}{\text{LEN}_p} \cdot + \left( \frac{\text{LSC}_{r,p,t,v}}{\text{PLF}_{r,p,t,v}} \cdot \textbf{CAP}_{r,p,t,v} - \frac{\text{LSC}_{r,p_{next},t,v}}{\text{PLF}_{r,p_{next},t,v}} \cdot \textbf{CAP}_{r,p_{next},t,v} \right) & \text{otherwise} \\ \end{cases} - + \\\text{where EOL when } p \leq v + LTP_{r,t,v} < p + LEN_p """ - + ## Get the capacity at the start of this period if p == v + value(M.LifetimeProcess[r, t, v]): # Exact EOL. No V_Capacity or V_RetiredCapacity for this period. @@ -209,7 +210,7 @@ def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): annualised_retirement = (cap_begin - cap_end) / M.PeriodLength[p] return M.V_AnnualRetirement[r, p, t, v] == annualised_retirement - + def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): r""" @@ -262,19 +263,16 @@ def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - + if t in M.tech_curtailment: # If technologies are present in the curtailment set, then enough # capacity must be available to cover both activity and curtailment. - return ( - get_capacity_factor(M, r, p, s, d, t, v) - * value(M.CapacityToActivity[r, t]) - * value(M.SegFrac[p, s, d]) - * M.V_Capacity[r, p, t, v] == useful_activity + sum( - M.V_Curtailment[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) + return get_capacity_factor(M, r, p, s, d, t, v) * value(M.CapacityToActivity[r, t]) * value( + M.SegFrac[p, s, d] + ) * M.V_Capacity[r, p, t, v] == useful_activity + sum( + M.V_Curtailment[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) else: return ( @@ -294,7 +292,7 @@ def CapacityAnnual_Constraint(M: 'TemoaModel', r, p, t, v): that installed capacity is sufficient across all timeslices, thus saving some computational effort. Instead, annual output is sufficient to calculate capacity. Hourly capacity factors cannot be defined to annual technologies - but annual capacity factors can be set using LimitAnnualCapacityFactor, + but annual capacity factors can be set using LimitAnnualCapacityFactor, which will be implicitly accounted for here. .. math:: @@ -314,11 +312,7 @@ def CapacityAnnual_Constraint(M: 'TemoaModel', r, p, t, v): for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - return ( - value(M.CapacityToActivity[r, t]) - * M.V_Capacity[r, p, t, v] - >= activity_rptv - ) + return value(M.CapacityToActivity[r, t]) * M.V_Capacity[r, p, t, v] >= activity_rptv # devnote: long dead @@ -375,10 +369,7 @@ def CapacityAvailableByPeriodAndTech_Constraint(M: 'TemoaModel', r, p, t): \\ \forall p \in \text{P}^o, r \in R, t \in T """ - cap_avail = sum( - M.V_Capacity[r, p, t, S_v] - for S_v in M.processVintages[r, p, t] - ) + cap_avail = sum(M.V_Capacity[r, p, t, S_v] for S_v in M.processVintages[r, p, t]) expr = M.V_CapacityAvailableByPeriodAndTech[r, p, t] == cap_avail return expr @@ -443,7 +434,7 @@ def TotalCost_rule(M): \end{aligned} Note that capital costs (:math:`{CI}_{r,t,v}`) are handled in several steps. - + 1. Each capital cost is amortized using the loan rate (i.e., technology-specific discount rate) and loan period. 2. The annual stream of payments is converted into a lump sum using the global discount rate and loan period. @@ -453,7 +444,7 @@ def TotalCost_rule(M): 4. Loan payments beyond the model time horizon are removed and the lump sum recalculated. 5. Finally, the lump sum is discounted back to the beginning of the horizon (:math:`P_0`) using the global discount rate. - + Steps 3 and 4 serve to correctly balance the cost-benefit of technologies whose useful lives would extend beyond the planning horizon. While an explicit salvage term is not included, this approach properly captures the capital costs incurred within the model time horizon, accounting for process-specific loan rates @@ -553,7 +544,7 @@ def TotalCost_rule(M): def annuity_to_pv(rate: float, periods: int) -> float | Expression: r""" Multiplication factor to convert an annuity to net present value - + .. math:: :label: annuity_to_pv @@ -566,7 +557,8 @@ def annuity_to_pv(rate: float, periods: int) -> float | Expression: """ if rate == 0: return periods - return ((1 + rate)**periods - 1) / (rate * (1 + rate)**periods) + return ((1 + rate) ** periods - 1) / (rate * (1 + rate) ** periods) + def pv_to_annuity(rate: float, periods: int) -> float | Expression: r""" @@ -579,12 +571,13 @@ def pv_to_annuity(rate: float, periods: int) -> float | Expression: """ if rate == 0: return 1 / periods - return (rate * (1 + rate)**periods) / ((1 + rate)**periods - 1) - + return (rate * (1 + rate) ** periods) / ((1 + rate) ** periods - 1) + + def fv_to_pv(rate: float, periods: int) -> float | Expression: r""" Multiplication factor to convert a future value to net present value - + .. math:: :label: fv_to_pv @@ -592,7 +585,7 @@ def fv_to_pv(rate: float, periods: int) -> float | Expression: """ if rate == 0: return 1 - return 1 / (1 + rate)**periods + return 1 / (1 + rate) ** periods def loan_cost( @@ -622,26 +615,33 @@ def loan_cost( # calculate the amortised loan repayment (annuity) annuity = ( - capacity * invest_cost # lump investment cost is capacity times CostInvest - * loan_annualize # calculate loan annuities for investment cost, if used + capacity + * invest_cost # lump investment cost is capacity times CostInvest + * loan_annualize # calculate loan annuities for investment cost, if used ) - + if not GDR: # Undiscounted result res = ( annuity - * lifetime_loan_process # sum of loan payments over loan period - / lifetime_process # redistributed over lifetime of process - * min(lifetime_process, P_e - vintage) # sum of redistributed costs for life of process (within planning horizon) + * lifetime_loan_process # sum of loan payments over loan period + / lifetime_process # redistributed over lifetime of process + * min( + lifetime_process, P_e - vintage + ) # sum of redistributed costs for life of process (within planning horizon) ) else: # Discounted result res = ( annuity - * annuity_to_pv(GDR, lifetime_loan_process) # PV of all loan payments, discounted to vintage year using GDR - * pv_to_annuity(GDR, lifetime_process) # reamortised over lifetime of process using GDR - * annuity_to_pv(GDR, min(lifetime_process, P_e - vintage)) # PV of all reamortised costs (within planning horizon) - * fv_to_pv(GDR, vintage - P_0) # finally, discounted from vintage year to P_0 + * annuity_to_pv( + GDR, lifetime_loan_process + ) # PV of all loan payments, discounted to vintage year using GDR + * pv_to_annuity(GDR, lifetime_process) # reamortised over lifetime of process using GDR + * annuity_to_pv( + GDR, min(lifetime_process, P_e - vintage) + ) # PV of all reamortised costs (within planning horizon) + * fv_to_pv(GDR, vintage - P_0) # finally, discounted from vintage year to P_0 ) return res @@ -675,21 +675,22 @@ def loan_cost_survival_curve( # calculate the amortised loan repayment (annuity) annuity = ( - capacity * invest_cost # lump investment cost is capacity times CostInvest - * loan_annualize # calculate loan annuities for investment cost, if used + capacity + * invest_cost # lump investment cost is capacity times CostInvest + * loan_annualize # calculate loan annuities for investment cost, if used ) - + if not GDR: # Undiscounted result res = ( annuity - * lifetime_loan_process # sum of loan payments over loan period - / sum( # redistributed over survival curve within horizon + * lifetime_loan_process # sum of loan payments over loan period + / sum( # redistributed over survival curve within horizon value(M.LifetimeSurvivalCurve[r, p, t, v]) for p in M.survivalCurvePeriods[r, t, v] if v <= p ) - * sum( # summed over survival curve within horizon + * sum( # summed over survival curve within horizon value(M.LifetimeSurvivalCurve[r, p, t, v]) for p in M.survivalCurvePeriods[r, t, v] if v <= p < P_e @@ -699,20 +700,23 @@ def loan_cost_survival_curve( # Discounted result res = ( annuity - * annuity_to_pv(GDR, lifetime_loan_process) # PV of all loan payments, discounted to vintage year using GDR - / sum( # redistributed over survival curve within horizon - value(M.LifetimeSurvivalCurve[r, p, t, v]) # reamortised over survival curve of process using GDR - * fv_to_pv(GDR, p - v + 1) # +1 because LSC is indexed to start of p not end of p + * annuity_to_pv( + GDR, lifetime_loan_process + ) # PV of all loan payments, discounted to vintage year using GDR + / sum( # redistributed over survival curve within horizon + value( + M.LifetimeSurvivalCurve[r, p, t, v] + ) # reamortised over survival curve of process using GDR + * fv_to_pv(GDR, p - v + 1) # +1 because LSC is indexed to start of p not end of p for p in M.survivalCurvePeriods[r, t, v] - if v <= p # this shouldnt be possible but play it safe + if v <= p # this shouldnt be possible but play it safe ) - * sum( # PV of all reamortised costs (within planning horizon) - value(M.LifetimeSurvivalCurve[r, p, t, v]) - * fv_to_pv(GDR, p - v + 1) + * sum( # PV of all reamortised costs (within planning horizon) + value(M.LifetimeSurvivalCurve[r, p, t, v]) * fv_to_pv(GDR, p - v + 1) for p in M.survivalCurvePeriods[r, t, v] if v <= p < P_e ) - * fv_to_pv(GDR, v - P_0) # finally, discounted from vintage year to P_0 + * fv_to_pv(GDR, v - P_0) # finally, discounted from vintage year to P_0 ) return res @@ -737,17 +741,19 @@ def fixed_or_variable_cost( :return: """ - annual_cost = cap_or_flow * cost_factor # annual fixed, variable, or emission cost - + annual_cost = cap_or_flow * cost_factor # annual fixed, variable, or emission cost + if not GDR: # Undiscounted result - return annual_cost * cost_years # annual cost times years paying that cost + return annual_cost * cost_years # annual cost times years paying that cost else: # Discounted result return ( annual_cost - * annuity_to_pv(GDR, cost_years) # PV of annual costs over this period, discounted to period p - * fv_to_pv(GDR, p - P_0) # discounted from p to p_0 + * annuity_to_pv( + GDR, cost_years + ) # PV of annual costs over this period, discounted to period p + * fv_to_pv(GDR, p - P_0) # discounted from p to p_0 ) @@ -871,7 +877,8 @@ def PeriodCost_rule(M: 'TemoaModel', p): # 1. variable emissions var_emissions = sum( fixed_or_variable_cost( - cap_or_flow=M.V_FlowOut[r, p, s, d, i, t, v, o] * value(M.EmissionActivity[r, e, i, t, v, o]), + cap_or_flow=M.V_FlowOut[r, p, s, d, i, t, v, o] + * value(M.EmissionActivity[r, e, i, t, v, o]), cost_factor=value(M.CostEmission[r, p, e]), cost_years=value(M.PeriodLength[p]), GDR=GDR, @@ -888,7 +895,8 @@ def PeriodCost_rule(M: 'TemoaModel', p): # 4. annual emissions var_annual_emissions = sum( fixed_or_variable_cost( - cap_or_flow=M.V_FlowOutAnnual[r, p, i, t, v, o] * value(M.EmissionActivity[r, e, i, t, v, o]), + cap_or_flow=M.V_FlowOutAnnual[r, p, i, t, v, o] + * value(M.EmissionActivity[r, e, i, t, v, o]), cost_factor=value(M.CostEmission[r, p, e]), cost_years=value(M.PeriodLength[p]), GDR=GDR, @@ -904,9 +912,13 @@ def PeriodCost_rule(M: 'TemoaModel', p): # 6. embodied - treated as a fixed cost distributed over the deployment period (vintage) embodied_emissions = sum( fixed_or_variable_cost( - cap_or_flow=M.V_NewCapacity[r, t, v] * value(M.EmissionEmbodied[r, e, t, v]) / value(M.PeriodLength[p]), + cap_or_flow=M.V_NewCapacity[r, t, v] + * value(M.EmissionEmbodied[r, e, t, v]) + / value(M.PeriodLength[p]), cost_factor=value(M.CostEmission[r, p, e]), - cost_years=M.PeriodLength[v], # We assume the embodied emissions are emitted in the same year as the capacity is installed. + cost_years=M.PeriodLength[ + v + ], # We assume the embodied emissions are emitted in the same year as the capacity is installed. GDR=GDR, P_0=P_0, p=p, @@ -921,7 +933,9 @@ def PeriodCost_rule(M: 'TemoaModel', p): fixed_or_variable_cost( cap_or_flow=M.V_AnnualRetirement[r, p, t, v] * value(M.EmissionEndOfLife[r, e, t, v]), cost_factor=value(M.CostEmission[r, p, e]), - cost_years=M.PeriodLength[p], # We assume the embodied emissions are emitted in the same year as the capacity is installed. + cost_years=M.PeriodLength[ + p + ], # We assume the embodied emissions are emitted in the same year as the capacity is installed. GDR=GDR, P_0=P_0, p=p, @@ -931,7 +945,9 @@ def PeriodCost_rule(M: 'TemoaModel', p): if (r, t, v) in M.retirementPeriods and p in M.retirementPeriods[r, t, v] ) - period_emission_cost = var_emissions + var_annual_emissions + embodied_emissions + endoflife_emissions + period_emission_cost = ( + var_emissions + var_annual_emissions + embodied_emissions + endoflife_emissions + ) period_costs = ( loan_costs + fixed_costs + variable_costs + variable_costs_annual + period_emission_cost @@ -986,9 +1002,7 @@ def Demand_Constraint(M: 'TemoaModel', r, p, dem): DemandConstraintErrorCheck(supply_annual, r, p, dem) - expr = ( - supply_annual == value(M.Demand[r, p, dem]) - ) + expr = supply_annual == value(M.Demand[r, p, dem]) return expr @@ -1025,18 +1039,14 @@ def DemandActivity_Constraint(M: 'TemoaModel', r, p, s, d, t, v, dem): """ activity = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, dem] - for S_i in M.processInputsByOutput[r, p, t, v, dem] + M.V_FlowOut[r, p, s, d, S_i, t, v, dem] for S_i in M.processInputsByOutput[r, p, t, v, dem] ) annual_activity = sum( - M.V_FlowOutAnnual[r, p, S_i, t, v, dem] - for S_i in M.processInputsByOutput[r, p, t, v, dem] + M.V_FlowOutAnnual[r, p, S_i, t, v, dem] for S_i in M.processInputsByOutput[r, p, t, v, dem] ) - expr = ( - annual_activity * value(M.DemandSpecificDistribution[r, p, s, d, dem]) == activity - ) + expr = annual_activity * value(M.DemandSpecificDistribution[r, p, s, d, dem]) == activity return expr @@ -1153,7 +1163,8 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): # Into flows consumed += sum( - M.V_FlowOut[r, p, s, d, c, S_t, S_v, S_o] / get_variable_efficiency(M, r, p, s, d, c, S_t, S_v, S_o) + M.V_FlowOut[r, p, s, d, c, S_t, S_v, S_o] + / get_variable_efficiency(M, r, p, s, d, c, S_t, S_v, S_o) for S_t, S_v in M.commodityDStreamProcess[r, p, c] if S_t not in M.tech_storage and S_t not in M.tech_annual for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] @@ -1166,7 +1177,8 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): if S_o in M.commodity_demand else value(M.SegFrac[p, s, d]) ) - * M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] / get_variable_efficiency(M, r, p, s, d, c, S_t, S_v, S_o) + * M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] + / get_variable_efficiency(M, r, p, s, d, c, S_t, S_v, S_o) for S_t, S_v in M.commodityDStreamProcess[r, p, c] if S_t in M.tech_annual for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] @@ -1175,10 +1187,14 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): if (r, p, c) in M.capacityConsumptionTechs: # Consumed by building capacity # Assume evenly distributed over a year - consumed += value(M.SegFrac[p, s, d]) * sum( - value(M.ConstructionInput[r, c, S_t, p]) * M.V_NewCapacity[r, S_t, p] - for S_t in M.capacityConsumptionTechs[r, p, c] - ) / M.PeriodLength[p] + consumed += ( + value(M.SegFrac[p, s, d]) + * sum( + value(M.ConstructionInput[r, c, S_t, p]) * M.V_NewCapacity[r, S_t, p] + for S_t in M.capacityConsumptionTechs[r, p, c] + ) + / M.PeriodLength[p] + ) if (r, p, c) in M.commodityUStreamProcess: # From flows including output from storage @@ -1212,7 +1228,7 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): if S_t in M.tech_annual and S_t in M.tech_flex for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] ) - + if (r, p, c) in M.retirementProductionProcesses: # Produced by retiring capacity # Assume evenly distributed over a year @@ -1230,7 +1246,8 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): if S_t not in M.tech_annual ) consumed += sum( - value(M.SegFrac[p, s, d]) * M.V_FlowOutAnnual[r + '-' + reg, p, c, S_t, S_v, S_o] + value(M.SegFrac[p, s, d]) + * M.V_FlowOutAnnual[r + '-' + reg, p, c, S_t, S_v, S_o] / get_variable_efficiency(M, r + '-' + reg, p, s, d, c, S_t, S_v, S_o) for reg, S_t, S_v, S_o in M.exportRegions[r, p, c] if S_t in M.tech_annual @@ -1273,10 +1290,10 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): at the period level, summing all flows over the period but allowing imbalances at the time slice or seasonal level. Applies only to commodities in the :code:`commodity_annual` set. """ - + produced = 0 consumed = 0 - + if (r, p, c) in M.commodityDStreamProcess: # Only storage techs have a flow in variable # For other techs, it would be redundant as in = out / eff @@ -1290,7 +1307,8 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): ) consumed += sum( - M.V_FlowOut[r, p, S_s, S_d, c, S_t, S_v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, c, S_t, S_v, S_o) + M.V_FlowOut[r, p, S_s, S_d, c, S_t, S_v, S_o] + / get_variable_efficiency(M, r, p, S_s, S_d, c, S_t, S_v, S_o) for S_s in M.TimeSeason[p] for S_d in M.time_of_day for S_t, S_v in M.commodityDStreamProcess[r, p, c] @@ -1308,10 +1326,13 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): if (r, p, c) in M.capacityConsumptionTechs: # Consumed by building capacity # Assume evenly distributed over a year - consumed += sum( - value(M.ConstructionInput[r, c, S_t, p]) * M.V_NewCapacity[r, S_t, p] - for S_t in M.capacityConsumptionTechs[r, p, c] - ) / M.PeriodLength[p] + consumed += ( + sum( + value(M.ConstructionInput[r, c, S_t, p]) * M.V_NewCapacity[r, S_t, p] + for S_t in M.capacityConsumptionTechs[r, p, c] + ) + / M.PeriodLength[p] + ) if (r, p, c) in M.commodityUStreamProcess: # Includes output from storage @@ -1554,18 +1575,19 @@ def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): = {SL}_{r,p,s_{{next}},d_{{next}},t,v} Note that for all seasonal representations except consecutive_days, the last time slice - of each season will loop back to the first time slice of the same season, preventing + of each season will loop back to the first time slice of the same season, preventing seasonal deltas for non-seasonal storage (see SeasonalStorageEnergyUpperBound). """ # We allow a non-zero daily delta only in the case of seasonal storage if M.isSeasonalStorage[t] and d == M.time_of_day.last(): - return Constraint.Skip # handled by SeasonalStorageEnergy_Constraint + return Constraint.Skip # handled by SeasonalStorageEnergy_Constraint # This is the sum of all input=i sent TO storage tech t of vintage v with # output=o in p,s,d charge = sum( - M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] * get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) + M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] + * get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) @@ -1582,7 +1604,10 @@ def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): s_next, d_next = M.time_next[p, s, d] - expr = M.V_StorageLevel[r, p, s, d, t, v] + stored_energy == M.V_StorageLevel[r, p, s_next, d_next, t, v] + expr = ( + M.V_StorageLevel[r, p, s, d, t, v] + stored_energy + == M.V_StorageLevel[r, p, s_next, d_next, t, v] + ) return expr @@ -1617,13 +1642,13 @@ def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_seq, t, v): :figclass: align-center :figwidth: 60% - How sequential seasons chain together for seasonal storage. Hatched area is - SeasonalStorageLevel :math:`SSL_{r,p,s^{seq},t,v}`. Vertical lines are - StorageLevel :math:`SL_{r,p,s^*,d,t,v}`. Green line is net seasonal storage - level :math:`SSL_{r,p,s^{seq},t,v} + SL_{r,p,s^*,d,t,v}`. Background grey - lines show how storage levels from non-sequential seasons are combined - in sequential seasons. Dashed line is SeasonalStorageEnergyUpperBound. - Sequential seasons two and four here are each two days while one and three + How sequential seasons chain together for seasonal storage. Hatched area is + SeasonalStorageLevel :math:`SSL_{r,p,s^{seq},t,v}`. Vertical lines are + StorageLevel :math:`SL_{r,p,s^*,d,t,v}`. Green line is net seasonal storage + level :math:`SSL_{r,p,s^{seq},t,v} + SL_{r,p,s^*,d,t,v}`. Background grey + lines show how storage levels from non-sequential seasons are combined + in sequential seasons. Dashed line is SeasonalStorageEnergyUpperBound. + Sequential seasons two and four here are each two days while one and three are each one day. """ @@ -1651,13 +1676,23 @@ def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_seq, t, v): # Flows and StorageLevel are normalised to the number of days in the non-sequential season, so must # be adjusted to the number of days in the sequential season - days_adjust = value(M.TimeSeasonSequential[p, s_seq, s]) / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) - days_adjust_next = value(M.TimeSeasonSequential[p, s_seq_next, s_next]) / (value(M.SegFracPerSeason[p, s_next]) * value(M.DaysPerPeriod)) + days_adjust = value(M.TimeSeasonSequential[p, s_seq, s]) / ( + value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod) + ) + days_adjust_next = value(M.TimeSeasonSequential[p, s_seq_next, s_next]) / ( + value(M.SegFracPerSeason[p, s_next]) * value(M.DaysPerPeriod) + ) stored_energy = (charge - discharge) * days_adjust - start = M.V_SeasonalStorageLevel[r, p, s_seq, t, v] + M.V_StorageLevel[r, p, s, M.time_of_day.last(), t, v] * days_adjust - end = M.V_SeasonalStorageLevel[r, p, s_seq_next, t, v] + M.V_StorageLevel[r, p, s_next, M.time_of_day.first(), t, v] * days_adjust_next + start = ( + M.V_SeasonalStorageLevel[r, p, s_seq, t, v] + + M.V_StorageLevel[r, p, s, M.time_of_day.last(), t, v] * days_adjust + ) + end = ( + M.V_SeasonalStorageLevel[r, p, s_seq_next, t, v] + + M.V_StorageLevel[r, p, s_next, M.time_of_day.first(), t, v] * days_adjust_next + ) expr = start + stored_energy == end return expr @@ -1692,7 +1727,7 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): A season can represent many days. Within each season, flows are multiplied by the number of days each season represents and, so, the upper bound needs to be adjusted to allow day-scale flows (e.g., charge in the morning, discharge in the afternoon). - + .. figure:: images/daily_storage_representation.* :align: center :width: 100% @@ -1703,15 +1738,16 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): """ if M.isSeasonalStorage[t]: - return Constraint.Skip # redundant on SeasonalStorageEnergyUpperBound + return Constraint.Skip # redundant on SeasonalStorageEnergyUpperBound energy_capacity = ( M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * (value(M.StorageDuration[r, t]) / (24 * value(M.DaysPerPeriod))) - * value(M.SegFracPerSeason[p, s]) * M.DaysPerPeriod # adjust for days in season + * value(M.SegFracPerSeason[p, s]) + * M.DaysPerPeriod # adjust for days in season ) - + expr = M.V_StorageLevel[r, p, s, d, t, v] <= energy_capacity return expr @@ -1719,8 +1755,8 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_seq, d, t, v): r""" - Builds off of StorageEnergyUpperBound_Constraint. Enforces the max charge capacity - of seasonal storage, summing the real storage level with the superimposed sequential + Builds off of StorageEnergyUpperBound_Constraint. Enforces the max charge capacity + of seasonal storage, summing the real storage level with the superimposed sequential seasonal storage level. :math:`s^*` represents the matching non-sequential season for the sequential season :math:`s^{seq}`. @@ -1733,12 +1769,12 @@ def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_seq, d, \\ - \text{where } DA_{r,p,s^{seq}} = \frac{\#days_{s^{seq}}}{SEG_{r,p,s^*} \cdot DPP} + \text{where } DA_{r,p,s^{seq}} = \frac{\#days_{s^{seq}}}{SEG_{r,p,s^*} \cdot DPP} + + - - Unlike non-seasonal (daily) storage, seasonal storage is allowed to carry energy - between seasons. However, through seasons representing multiple days, many days' + between seasons. However, through seasons representing multiple days, many days' charge deltas have accumulated, multiplied by the number of days the season represents. If we allowed these stacked deltas to carry between seasons then we would be multiplying the effective energy capacity of the storage. We could just constrain @@ -1780,12 +1816,14 @@ def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_seq, d, # Flows and StorageLevel are normalised to the number of days in the non-sequential season, so must # be adjusted to the number of days in the sequential season - days_adjust = value(M.TimeSeasonSequential[p, s_seq, s]) / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) + days_adjust = value(M.TimeSeasonSequential[p, s_seq, s]) / ( + value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod) + ) # V_StorageLevel tracks the running cumulative delta in the non-sequential season, so must be adjusted # to the size of the sequential season running_day_delta = M.V_StorageLevel[r, p, s, d, t, v] * days_adjust - + expr = M.V_SeasonalStorageLevel[r, p, s_seq, t, v] + running_day_delta <= energy_capacity return expr @@ -1810,16 +1848,15 @@ def StorageChargeRate_Constraint(M: 'TemoaModel', r, p, s, d, t, v): """ # Calculate energy charge in each time slice slice_charge = sum( - M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] * get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) + M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] + * get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) # Maximum energy charge in each time slice max_charge = ( - M.V_Capacity[r, p, t, v] - * value(M.CapacityToActivity[r, t]) - * value(M.SegFrac[p, s, d]) + M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[p, s, d]) ) # Energy charge cannot exceed the power capacity of the storage unit @@ -1853,9 +1890,7 @@ def StorageDischargeRate_Constraint(M: 'TemoaModel', r, p, s, d, t, v): # Maximum energy discharge in each time slice max_discharge = ( - M.V_Capacity[r, p, t, v] - * value(M.CapacityToActivity[r, t]) - * value(M.SegFrac[p, s, d]) + M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[p, s, d]) ) # Energy discharge cannot exceed the capacity of the storage unit @@ -1890,16 +1925,15 @@ def StorageThroughput_Constraint(M: 'TemoaModel', r, p, s, d, t, v): ) charge = sum( - M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] * get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) + M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] + * get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) throughput = charge + discharge max_throughput = ( - M.V_Capacity[r, p, t, v] - * value(M.CapacityToActivity[r, t]) - * value(M.SegFrac[p, s, d]) + M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[p, s, d]) ) expr = throughput <= max_throughput return expr @@ -1940,15 +1974,19 @@ def LimitStorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v, op): ) if M.isSeasonalStorage[t]: - s_seq = s # sequential season - s = M.sequential_to_season[p, s_seq] # non-sequential season + s_seq = s # sequential season + s = M.sequential_to_season[p, s_seq] # non-sequential season # adjust the storage level to the individual-day level - energy_level = M.V_StorageLevel[r, p, s, d, t, v] / (value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod)) + energy_level = M.V_StorageLevel[r, p, s, d, t, v] / ( + value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod) + ) if M.isSeasonalStorage[t]: # seasonal storage upper energy limit is absolute - energy_level = M.V_SeasonalStorageLevel[r, p, s_seq, t, v] + energy_level * value(M.TimeSeasonSequential[p, s_seq, s]) + energy_level = M.V_SeasonalStorageLevel[r, p, s_seq, t, v] + energy_level * value( + M.TimeSeasonSequential[p, s_seq, s] + ) expr = operator_expression(energy_level, op, energy_limit) @@ -1965,13 +2003,13 @@ def RampUpDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): The ramp rate constraint is utilized to limit the rate of electricity generation increase and decrease between two adjacent time slices in order to account for - physical limits associated with thermal power plants. This constraint is only - applied to technologies in the set :code:`tech_upramping`. We assume for + physical limits associated with thermal power plants. This constraint is only + applied to technologies in the set :code:`tech_upramping`. We assume for simplicity the rate limits do not vary with technology vintage. The ramp rate limits for a technology should be expressed in percentage of its rated capacity per hour. - In a representative periods or seasonal time slices model, the next time slice, + In a representative periods or seasonal time slices model, the next time slice, :math:`(s_{next},d_{next})`, from the end of each season, :math:`(s,d_{last})` is the beginning of the same season, :math:`(s,d_{first})` @@ -2012,34 +2050,44 @@ def RampUpDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): # How many hours does this time slice represent hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 - hourly_activity_sd = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) / hours_adjust + hourly_activity_sd = ( + sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) - hourly_activity_sd_next = sum( - M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) / hours_adjust + hourly_activity_sd_next = ( + sum( + M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) # elapsed hours from middle of this time slice to middle of next time slice - hours_elapsed = 24 / 2 * ( - value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) - + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + hours_elapsed = ( + 24 + / 2 + * ( + value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) + + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + ) ) ramp_fraction = hours_elapsed * value(M.RampUpHourly[r, t]) if ramp_fraction >= 1: msg = ( - "Warning: Hourly ramp up rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). " - f"Should be less than {1/hours_elapsed:.4f}. Constraint skipped." + 'Warning: Hourly ramp up rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' + f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' ) logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) return Constraint.Skip - activity_increase = hourly_activity_sd_next - hourly_activity_sd # opposite sign from rampdown + activity_increase = hourly_activity_sd_next - hourly_activity_sd # opposite sign from rampdown rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) expr = activity_increase <= rampable_activity @@ -2077,34 +2125,44 @@ def RampDownDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): # How many hours does this time slice represent hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 - hourly_activity_sd = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) / hours_adjust + hourly_activity_sd = ( + sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) - hourly_activity_sd_next = sum( - M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) / hours_adjust + hourly_activity_sd_next = ( + sum( + M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) # elapsed hours from middle of this time slice to middle of next time slice - hours_elapsed = 24 / 2 * ( - value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) - + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + hours_elapsed = ( + 24 + / 2 + * ( + value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) + + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + ) ) ramp_fraction = hours_elapsed * value(M.RampDownHourly[r, t]) if ramp_fraction >= 1: msg = ( - "Warning: Hourly ramp down rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). " - f"Should be less than {1/hours_elapsed:.4f}. Constraint skipped." + 'Warning: Hourly ramp down rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' + f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' ) logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) return Constraint.Skip - activity_decrease = hourly_activity_sd - hourly_activity_sd_next # opposite sign from rampup + activity_decrease = hourly_activity_sd - hourly_activity_sd_next # opposite sign from rampup rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) expr = activity_decrease <= rampable_activity @@ -2113,10 +2171,10 @@ def RampDownDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): def RampUpSeason_Constraint(M: 'TemoaModel', r, p, s, s_next, t, v): r""" - Constrains the ramp up rate of activity between time slices at the boundary - of sequential seasons. Same as RampUpDay but only applies to the boundary + Constrains the ramp up rate of activity between time slices at the boundary + of sequential seasons. Same as RampUpDay but only applies to the boundary between sequential seasons, i.e., :math:`(s^{seq},d_{last})` to :math:`(s^{seq}_{next},d_{first})` - and :math:`s^{seq}_{next}` is based on the TimeSequential table rather than the + and :math:`s^{seq}_{next}` is based on the TimeSequential table rather than the TimeSeason table. """ @@ -2126,46 +2184,56 @@ def RampUpSeason_Constraint(M: 'TemoaModel', r, p, s, s_next, t, v): # How many hours does this time slice represent hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 - hourly_activity_sd = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) / hours_adjust + hourly_activity_sd = ( + sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) - hourly_activity_sd_next = sum( - M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) / hours_adjust + hourly_activity_sd_next = ( + sum( + M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) # elapsed hours from middle of this time slice to middle of next time slice - hours_elapsed = 24 / 2 * ( - value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) - + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + hours_elapsed = ( + 24 + / 2 + * ( + value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) + + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + ) ) ramp_fraction = hours_elapsed * value(M.RampUpHourly[r, t]) if ramp_fraction >= 1: msg = ( - "Warning: Hourly ramp up rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). " - f"Should be less than {1/hours_elapsed:.4f}. Constraint skipped." + 'Warning: Hourly ramp up rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' + f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' ) logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) return Constraint.Skip - activity_increase = hourly_activity_sd_next - hourly_activity_sd # opposite sign from rampdown + activity_increase = hourly_activity_sd_next - hourly_activity_sd # opposite sign from rampdown rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) expr = activity_increase <= rampable_activity - + return expr def RampDownSeason_Constraint(M: 'TemoaModel', r, p, s, s_next, t, v): r""" - Constrains the ramp down rate of activity between time slices at the boundary - of sequential seasons. Same as RampDownDay but only applies to the boundary + Constrains the ramp down rate of activity between time slices at the boundary + of sequential seasons. Same as RampDownDay but only applies to the boundary between sequential seasons, i.e., :math:`(s^{seq},d_{last})` to :math:`(s^{seq}_{next},d_{first})` - and :math:`s^{seq}_{next}` is based on the TimeSequential table rather than the + and :math:`s^{seq}_{next}` is based on the TimeSequential table rather than the TimeSeason table. """ @@ -2175,42 +2243,51 @@ def RampDownSeason_Constraint(M: 'TemoaModel', r, p, s, s_next, t, v): # How many hours does this time slice represent hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 - hourly_activity_sd = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) / hours_adjust + hourly_activity_sd = ( + sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) - hourly_activity_sd_next = sum( - M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) / hours_adjust + hourly_activity_sd_next = ( + sum( + M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) # elapsed hours from middle of this time slice to middle of next time slice - hours_elapsed = 24 / 2 * ( - value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) - + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + hours_elapsed = ( + 24 + / 2 + * ( + value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) + + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + ) ) ramp_fraction = hours_elapsed * value(M.RampDownHourly[r, t]) if ramp_fraction >= 1: msg = ( - "Warning: Hourly ramp down rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). " - f"Should be less than {1/hours_elapsed:.4f}. Constraint skipped." + 'Warning: Hourly ramp down rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' + f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' ) logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) return Constraint.Skip - activity_decrease = hourly_activity_sd - hourly_activity_sd_next # opposite sign from rampup + activity_decrease = hourly_activity_sd - hourly_activity_sd_next # opposite sign from rampup rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) expr = activity_decrease <= rampable_activity - + return expr def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): - # Get available generation in this time slice depending on method specified in config file match M.ReserveMarginMethod.first(): case 'static': @@ -2314,7 +2391,7 @@ def ReserveMarginStatic(M: 'TemoaModel', r, p, s, d): &+ \sum_{ t \in T^{res} \cap T^{x},V,I,O } \textbf{FO}_{r_i-r, p, s, d, i, t, v, o}\\ &- \sum_{ t \in T^{res} \cap T^{x},V,I,O } \textbf{FI}_{r-r_i, p, s, d, i, t, v, o}\\ &- \left.\sum_{ t \in T^{res} \cap T^{s},V,I,O } \textbf{FI}_{r, p, s, d, i, t, v, o} \right] \cdot (1 + PRM_r)\\ - + \\ &\qquad\qquad\forall \{r, p, s, d\} \in \Theta_{\text{ReserveMargin}} \text{and} \forall r_i \in R """ @@ -2367,7 +2444,7 @@ def ReserveMarginStatic(M: 'TemoaModel', r, p, s, d): def ReserveMarginDynamic(M: 'TemoaModel', r, p, s, d): r""" - A dynamic alternative to the traditional, static reserve margin constraint. Capacity values + A dynamic alternative to the traditional, static reserve margin constraint. Capacity values are calculated from availability of generation in each hour—like an operating reserve margin—\ accounting for a capacity derate factor subtracting, for example, forced outage due to icing. @@ -2426,16 +2503,14 @@ def ReserveMarginDynamic(M: 'TemoaModel', r, p, s, d): # Storage # Derated net output flow available += sum( - M.V_FlowOut[r, p, s, d, i, t, v, o] - * value(M.ReserveCapacityDerate[r, p, s, t, v]) + M.V_FlowOut[r, p, s, d, i, t, v, o] * value(M.ReserveCapacityDerate[r, p, s, t, v]) for (t, v) in M.processReservePeriods[r, p] if t in M.tech_storage for i in M.processInputs[r, p, t, v] for o in M.processOutputsByInput[r, p, t, v, i] ) available -= sum( - M.V_FlowIn[r, p, s, d, i, t, v, o] - * value(M.ReserveCapacityDerate[r, p, s, t, v]) + M.V_FlowIn[r, p, s, d, i, t, v, o] * value(M.ReserveCapacityDerate[r, p, s, t, v]) for (t, v) in M.processReservePeriods[r, p] if t in M.tech_storage for i in M.processInputs[r, p, t, v] @@ -2550,8 +2625,7 @@ def LimitEmission_Constraint(M: 'TemoaModel', r, p, e, op): ) retirement_emissions = sum( - M.V_AnnualRetirement[reg, p, t, v] - * value(M.EmissionEndOfLife[reg, e, t, v]) + M.V_AnnualRetirement[reg, p, t, v] * value(M.EmissionEndOfLife[reg, e, t, v]) for reg in regions for (S_r, S_e, t, v) in M.EmissionEndOfLife.sparse_iterkeys() if (r, t, v) in M.retirementPeriods and p in M.retirementPeriods[r, t, v] @@ -2568,13 +2642,11 @@ def LimitEmission_Constraint(M: 'TemoaModel', r, p, e, op): # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated - msg = ( - "Warning: No technology produces emission '%s', though limit was " 'specified as %s.\n' - ) + msg = "Warning: No technology produces emission '%s', though limit was specified as %s.\n" logger.warning(msg, (e, emission_limit)) SE.write(msg % (e, emission_limit)) return Constraint.Skip - + return expr @@ -2582,21 +2654,23 @@ def LimitGrowthCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): r"""Constrain ramp up rate of available capacity""" return LimitGrowthCapacity(M, r, p, t, op, False) + def LimitDegrowthCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): r"""Constrain ramp down rate of available capacity""" return LimitGrowthCapacity(M, r, p, t, op, True) + def LimitGrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): r""" - Constrain the change of capacity available between periods. - Forces the model to ramp up and down the availability of new technologies + Constrain the change of capacity available between periods. + Forces the model to ramp up and down the availability of new technologies more smoothly. Has constant (seed, :math:`S_{r,t}`) and proportional (rate, :math:`R_{r,t}`) terms. This can be defined for a technology group instead of one technology, in which case, capacity available is summed over all technologies in the group. In the first period, previous available - capacity :math:`\mathbf{CAPAVL}_{r,p,t}` is replaced by previous existing + capacity :math:`\mathbf{CAPAVL}_{r,p,t}` is replaced by previous existing capacity, if any can be found. - + .. math:: :label: Limit (De)Growth Capacity @@ -2606,7 +2680,7 @@ def LimitGrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): \end{aligned} \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitGrowthCapacity}} - + \begin{aligned}\text{Degrowth:}\\ &\mathbf{CAPAVL}_{r,p_{prev},t} @@ -2634,27 +2708,29 @@ def LimitGrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): msg = ( 'Tried to set {}rowthCapacity constraint {} but there are no periods where this ' 'technology is available in this region. Constraint skipped.' - ).format("Deg" if degrowth else "G", (r, t)) + ).format('Deg' if degrowth else 'G', (r, t)) logger.warning(msg) return Constraint.Skip - + # Only warn in p0 so we dont dump multiple warnings if p == periods[0]: if SEED == 0: msg = ( 'No constant term (seed) provided for {}rowthCapacity constraint {}. ' 'No capacity will be built in any period following one with zero capacity.' - ).format("Deg" if degrowth else "G", (r, t)) + ).format('Deg' if degrowth else 'G', (r, t)) logger.info(msg) - gaps = [_p for _p in M.time_optimize if _p not in periods and min(periods) < _p < max(periods)] + gaps = [ + _p for _p in M.time_optimize if _p not in periods and min(periods) < _p < max(periods) + ] if gaps: msg = ( 'Constructing {}rowthCapacity constraint {} and there are period gaps in which' 'capacity cannot exist in this region ({}). Capacity in these periods ' 'will be treated as zero which may cause infeasibility or other problems.' - ).format("Deg" if degrowth else "G", (r, t), gaps) + ).format('Deg' if degrowth else 'G', (r, t), gaps) logger.warning(msg) - + # sum available capacity in this period capacity = sum(CapRPT[_r, _p, _t] for _r, _p, _t in cap_rpt if _p == p) @@ -2663,25 +2739,21 @@ def LimitGrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): # Adjust in-line for past PLF because we are constraining available capacity p_prev = M.time_exist.last() capacity_prev = sum( - value(M.ExistingCapacity[_r, _t, _v]) \ - * min( 1.0, (_v + value(M.LifetimeProcess[_r, _t, _v]) - p_prev)/(p - p_prev) ) + value(M.ExistingCapacity[_r, _t, _v]) + * min(1.0, (_v + value(M.LifetimeProcess[_r, _t, _v]) - p_prev) / (p - p_prev)) for _r, _t, _v in M.ExistingCapacity.sparse_iterkeys() if _r in regions and _t in techs and _v + value(M.LifetimeProcess[_r, _t, _v]) > p_prev ) else: # Otherwise, grab previous future period p_prev = M.time_optimize.prev(p) - capacity_prev = sum( - CapRPT[_r, _p, _t] - for _r, _p, _t in cap_rpt - if _p == p_prev - ) + capacity_prev = sum(CapRPT[_r, _p, _t] for _r, _p, _t in cap_rpt if _p == p_prev) if degrowth: expr = operator_expression(capacity_prev, op, SEED + capacity * RATE) else: expr = operator_expression(capacity, op, SEED + capacity_prev * RATE) - + # Check if any variables are actually included before returning if isinstance(expr, bool): return Constraint.Skip @@ -2692,21 +2764,23 @@ def LimitGrowthNewCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): r"""Constrain ramp up rate of new capacity deployment""" return LimitGrowthNewCapacity(M, r, p, t, op, False) + def LimitDegrowthNewCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): r"""Constrain ramp down rate of new capacity deployment""" return LimitGrowthNewCapacity(M, r, p, t, op, True) + def LimitGrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): r""" - Constrain the change of new capacity deployed between periods. - Forces the model to ramp up and down the deployment of new technologies + Constrain the change of new capacity deployed between periods. + Forces the model to ramp up and down the deployment of new technologies more smoothly. Has constant (seed, :math:`S_{r,t}`) and proportional (rate, :math:`R_{r,t}`) terms. This can be defined for a technology group instead of one technology, in which case, new capacity is summed over all technologies in the group. In the first period, previous new capacity :math:`\mathbf{NCAP}_{r,t,v_prev}` is replaced by previous existing capacity, if any can be found. - + .. math:: :label: Limit (De)Growth New Capacity @@ -2715,7 +2789,7 @@ def LimitGrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False) \leq S_{r,t} + (1+R_{r,t}) \cdot \mathbf{NCAP}_{r,t,v_{prev}} \text{ where } v=p \end{aligned} - + \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitGrowthCapacity}} \begin{aligned}\text{Degrowth:}\\ @@ -2723,7 +2797,7 @@ def LimitGrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False) \leq S_{r,t} + (1+R_{r,t}) \cdot \mathbf{NCAP}_{r,t,v} \text{ where } v=p \end{aligned} - + \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitDegrowthCapacity}} """ @@ -2738,34 +2812,36 @@ def LimitGrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False) # relevant r, t, v indices cap_rtv = set((_r, _t, _v) for _r, _t, _v in NewCapRTV.keys() if _t in techs and _r in regions) # periods the technology can be built in this region (sorted) - periods = sorted(set(_v for _r, _t, _v in cap_rtv)) + periods = sorted(set(_v for _r, _t, _v in cap_rtv)) if len(periods) == 0: if p == M.time_optimize.first(): msg = ( 'Tried to set {}rowthNewCapacity constraint {} but there are no periods where this ' 'technology can be built in this region. Constraint skipped.' - ).format("Deg" if degrowth else "G", (r, t)) + ).format('Deg' if degrowth else 'G', (r, t)) logger.warning(msg) return Constraint.Skip - + # Only warn in p0 so we dont dump multiple warnings if p == periods[0]: if SEED == 0: msg = ( 'No constant term (seed) provided for {}rowthNewCapacity constraint {}. ' 'No capacity will be built in any period following one with zero new capacity.' - ).format("Deg" if degrowth else "G", (r, t)) + ).format('Deg' if degrowth else 'G', (r, t)) logger.info(msg) - gaps = [_p for _p in M.time_optimize if _p not in periods and min(periods) < _p < max(periods)] + gaps = [ + _p for _p in M.time_optimize if _p not in periods and min(periods) < _p < max(periods) + ] if gaps: msg = ( 'Constructing {}rowthNewCapacity constraint {} and there are period gaps in which' 'new capacity cannot be built in this region ({}). New capacity in these periods ' 'will be treated as zero which may cause infeasibility or other problems.' - ).format("Deg" if degrowth else "G", (r, t), gaps) + ).format('Deg' if degrowth else 'G', (r, t), gaps) logger.warning(msg) - + # sum new capacity in this period new_cap = sum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p) @@ -2780,11 +2856,7 @@ def LimitGrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False) else: # Otherwise, grab previous future vintage p_prev = M.time_optimize.prev(p) - new_cap_prev = sum( - NewCapRTV[_r, _t, _v] - for _r, _t, _v in cap_rtv - if _v == p_prev - ) + new_cap_prev = sum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p_prev) if degrowth: expr = operator_expression(new_cap_prev, op, SEED + new_cap * RATE) @@ -2795,28 +2867,30 @@ def LimitGrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False) if isinstance(expr, bool): return Constraint.Skip return expr - + def LimitGrowthNewCapacityDeltaConstraint_rule(M: 'TemoaModel', r, p, t, op): r"""Constrain ramp up rate of change in new capacity deployment""" return LimitGrowthNewCapacityDelta(M, r, p, t, op, False) + def LimitDegrowthNewCapacityDeltaConstraint_rule(M: 'TemoaModel', r, p, t, op): r"""Constrain ramp down rate of change in new capacity deployment""" return LimitGrowthNewCapacityDelta(M, r, p, t, op, True) + def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): r""" - Constrain the acceleration of new capacity deployed between periods. - Forces the model to ramp up and down the change in deployment of new technologies + Constrain the acceleration of new capacity deployed between periods. + Forces the model to ramp up and down the change in deployment of new technologies more smoothly. Has constant (seed, :math:`S_{r,t}`) and proportional - (rate, :math:`R_{r,t}`) terms. It is recommended to leave the rate term empty - as it would prevent the possibility of inflection in the rate of deployment. + (rate, :math:`R_{r,t}`) terms. It is recommended to leave the rate term empty + as it would prevent the possibility of inflection in the rate of deployment. This constraint can be defined for a technology group instead of one technology, in which case, new capacity is summed over all technologies in the group. In the first period, previous new capacities are replaced by previous existing capacities, if any can be found. - + .. math:: :label: Limit (De)Growth New Capacity Delta @@ -2824,18 +2898,18 @@ def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = F &\mathbf{NCAP}_{r,t,v_i} - \mathbf{NCAP}_{r,t,v_{i-1}} \leq S_{r,t} + (1+R_{r,t}) \cdot (\mathbf{NCAP}_{r,t,v_{i-1}} - \mathbf{NCAP}_{r,t,v_{i-2}}) \end{aligned} - + \text{ where } v_i=p - + \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitGrowthCapacityDelta}} \begin{aligned}\text{Degrowth:}\\ &\mathbf{NCAP}_{r,t,v_{i-1}} - \mathbf{NCAP}_{r,t,v_{i-2}} \leq S_{r,t} + (1+R_{r,t}) \cdot (\mathbf{NCAP}_{r,t,v_i} - \mathbf{NCAP}_{r,t,v_{i-1}}) \end{aligned} - + \text{ where } v_i=p - + \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitDegrowthCapacityDelta}} """ @@ -2850,14 +2924,14 @@ def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = F # relevant r, t, v indices cap_rtv = set((_r, _t, _v) for _r, _t, _v in NewCapRTV.keys() if _t in techs and _r in regions) # periods the technology can be built in this region (sorted) - periods = sorted(set(_v for _r, _t, _v in cap_rtv)) + periods = sorted(set(_v for _r, _t, _v in cap_rtv)) if len(periods) == 0: if p == M.time_optimize.first(): msg = ( 'Tried to set {}rowthNewCapacityDelta constraint {} but there are no periods where this ' 'technology can be built in this region. Constraint skipped.' - ).format("Deg" if degrowth else "G", (r, t)) + ).format('Deg' if degrowth else 'G', (r, t)) logger.warning(msg) return Constraint.Skip @@ -2868,15 +2942,17 @@ def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = F 'No constant term (seed) provided for {}rowthNewCapacityDelta constraint {}. ' 'This is not recommended as deployment rates cannot inflect (change from ' 'accelerating to decelerating or vice-versa).' - ).format("Deg" if degrowth else "G", (r, t)) + ).format('Deg' if degrowth else 'G', (r, t)) logger.warning(msg) - gaps = [_p for _p in M.time_optimize if _p not in periods and min(periods) < _p < max(periods)] + gaps = [ + _p for _p in M.time_optimize if _p not in periods and min(periods) < _p < max(periods) + ] if gaps: msg = ( 'Constructing {}rowthNewCapacityDelta constraint {} and there are period gaps in which' 'new capacity cannot be built in this region ({}). New capacity in these periods ' 'will be treated as zero which may cause infeasibility or other problems.' - ).format("Deg" if degrowth else "G", (r, t), gaps) + ).format('Deg' if degrowth else 'G', (r, t), gaps) logger.warning(msg) # sum new capacity in this period @@ -2899,12 +2975,8 @@ def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = F else: # Not the first future period. Grab previous future period p_prev = M.time_optimize.prev(p) - new_cap_prev = sum( - NewCapRTV[_r, _t, _v] - for _r, _t, _v in cap_rtv - if _v == p_prev - ) - if p == M.time_optimize.at(2): # apparently pyomo sets are indexed 1-based + new_cap_prev = sum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p_prev) + if p == M.time_optimize.at(2): # apparently pyomo sets are indexed 1-based # Second future period, grab last existing vintage p_prev2 = M.time_exist.last() new_cap_prev2 = sum( @@ -2915,11 +2987,7 @@ def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = F else: # At least the third future period. Grab last two future vintages p_prev2 = M.time_optimize.prev(p_prev) - new_cap_prev2 = sum( - NewCapRTV[_r, _t, _v] - for _r, _t, _v in cap_rtv - if _v == p_prev2 - ) + new_cap_prev2 = sum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p_prev2) nc_delta_prev = new_cap_prev - new_cap_prev2 nc_delta = new_cap - new_cap_prev @@ -2928,7 +2996,7 @@ def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = F expr = operator_expression(nc_delta_prev, op, SEED + nc_delta * RATE) else: expr = operator_expression(nc_delta, op, SEED + nc_delta_prev * RATE) - + # Check if any variables are actually included before returning if isinstance(expr, bool): return Constraint.Skip @@ -2966,7 +3034,8 @@ def LimitActivity_Constraint(M: 'TemoaModel', r, p, t, op): activity = sum( M.V_FlowOut[_r, p, s, d, S_i, _t, S_v, S_o] - for _t in techs if _t not in M.tech_annual + for _t in techs + if _t not in M.tech_annual for _r in regions for S_v in M.processVintages.get((_r, p, _t), []) for S_i in M.processInputs[_r, p, _t, S_v] @@ -2976,7 +3045,8 @@ def LimitActivity_Constraint(M: 'TemoaModel', r, p, t, op): ) activity += sum( M.V_FlowOutAnnual[_r, p, S_i, _t, S_v, S_o] - for _t in techs if _t in M.tech_annual + for _t in techs + if _t in M.tech_annual for _r in regions for S_v in M.processVintages.get((_r, p, _t), []) for S_i in M.processInputs[_r, p, _t, S_v] @@ -3001,17 +3071,13 @@ def LimitNewCapacity_Constraint(M: 'TemoaModel', r, p, t, op): :label: LimitNewCapacity \textbf{NCAP}_{r, t, v} \le LNC_{r, p, t} - + \text{where }v=p """ regions = gather_group_regions(M, r) techs = gather_group_techs(M, t) cap_lim = value(M.LimitNewCapacity[r, p, t, op]) - new_cap = sum( - M.V_NewCapacity[_r, _t, p] - for _t in techs - for _r in regions - ) + new_cap = sum(M.V_NewCapacity[_r, _t, p] for _t in techs for _r in regions) expr = operator_expression(new_cap, op, cap_lim) return expr @@ -3033,9 +3099,7 @@ def LimitCapacity_Constraint(M: 'TemoaModel', r, p, t, op): techs = gather_group_techs(M, t) cap_lim = value(M.LimitCapacity[r, p, t, op]) capacity = sum( - M.V_CapacityAvailableByPeriodAndTech[_r, p, _t] - for _t in techs - for _r in regions + M.V_CapacityAvailableByPeriodAndTech[_r, p, _t] for _t in techs for _r in regions ) expr = operator_expression(capacity, op, cap_lim) return expr @@ -3054,7 +3118,7 @@ def LimitResource_Constraint(M: 'TemoaModel', r, t, op): \sum_{P,S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t \notin T^a, v, o} +\sum_{P,I,V,O} \textbf{FO}_{r, p, i, t \in T^a, v, o} - + \le LR_{r, t} \forall \{r, t\} \in \Theta_{\text{LimitResource}}""" @@ -3068,7 +3132,8 @@ def LimitResource_Constraint(M: 'TemoaModel', r, t, op): activity = sum( M.V_FlowOutAnnual[_r, p, S_i, _t, S_v, S_o] - for _t in techs if _t in M.tech_annual + for _t in techs + if _t in M.tech_annual for p in M.time_optimize for _r in regions if (_r, p, _t) in M.processVintages @@ -3078,7 +3143,8 @@ def LimitResource_Constraint(M: 'TemoaModel', r, t, op): ) activity += sum( M.V_FlowOut[_r, p, s, d, S_i, _t, S_v, S_o] - for _t in techs if _t not in M.tech_annual + for _t in techs + if _t not in M.tech_annual for p in M.time_optimize for _r in regions if (_r, p, _t) in M.processVintages @@ -3088,7 +3154,7 @@ def LimitResource_Constraint(M: 'TemoaModel', r, t, op): for s in M.TimeSeason[p] for d in M.time_of_day ) - + resource_lim = value(M.LimitResource[r, t, op]) expr = operator_expression(activity, op, resource_lim) return expr @@ -3106,7 +3172,7 @@ def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): \sum_{R_g \subseteq R,\ S,\ D,\ I,\ T^{g_1} \subseteq T,\ V,\ O} \mathbf{FO}_{r,p,s,d,i,t,v,o} \leq LAS_{r,p,g_1,g_2} \cdot \sum_{R_g \subseteq R,\ S,\ D,\ I,\ T^{g_2} \subseteq T,\ V,\ O} \mathbf{FO}_{r,p,s,d,i,t,v,o} - + \qquad \forall \{r, p, g_1, g_2\} \in \Theta_{\text{LimitActivityShare}} """ @@ -3115,7 +3181,8 @@ def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): sub_group = gather_group_techs(M, g1) sub_activity = sum( M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] - for S_t in sub_group if S_t not in M.tech_annual + for S_t in sub_group + if S_t not in M.tech_annual for _r in regions for S_v in M.processVintages.get((_r, p, S_t), []) for S_i in M.processInputs[_r, p, S_t, S_v] @@ -3125,7 +3192,8 @@ def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): ) sub_activity += sum( M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] - for S_t in sub_group if S_t in M.tech_annual + for S_t in sub_group + if S_t in M.tech_annual for _r in regions for S_v in M.processVintages.get((_r, p, S_t), []) for S_i in M.processInputs[_r, p, S_t, S_v] @@ -3135,7 +3203,8 @@ def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): super_group = gather_group_techs(M, g2) super_activity = sum( M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] - for S_t in super_group if S_t not in M.tech_annual + for S_t in super_group + if S_t not in M.tech_annual for _r in regions for S_v in M.processVintages.get((_r, p, S_t), []) for S_i in M.processInputs[_r, p, S_t, S_v] @@ -3145,7 +3214,8 @@ def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): ) super_activity += sum( M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] - for S_t in super_group if S_t in M.tech_annual + for S_t in super_group + if S_t in M.tech_annual for _r in regions for S_v in M.processVintages.get((_r, p, S_t), []) for S_i in M.processInputs[_r, p, S_t, S_v] @@ -3159,7 +3229,11 @@ def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): return Constraint.Skip logger.debug( 'created limit activity share constraint for (%s, %d, %s, %s) of %0.2f', - r, p, g1, g2, share_lim, + r, + p, + g1, + g2, + share_lim, ) return expr @@ -3238,11 +3312,11 @@ def LimitAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o, op): :label: LimitAnnualCapacityFactor \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMACF_{r, p, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} - + \forall \{r, p, t \notin T^{a}, o\} \in \Theta_{\text{LimitAnnualCapacityFactor}} - + \\\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \ge LIMACF_{r, p, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} - + \forall \{r, p, t \in T^{a}, o\} \in \Theta_{\text{LimitAnnualCapacityFactor}} """ # r can be an individual region (r='US'), or a combination of regions separated by plus (r='Mexico+US+Canada'), or 'global'. @@ -3250,10 +3324,7 @@ def LimitAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o, op): regions = gather_group_regions(M, r) # we need to screen here because it is possible that the restriction extends beyond the # lifetime of any vintage of the tech... - if all( - (_r, p, t) not in M.V_CapacityAvailableByPeriodAndTech - for _r in regions - ): + if all((_r, p, t) not in M.V_CapacityAvailableByPeriodAndTech for _r in regions): return Constraint.Skip if t not in M.tech_annual: @@ -3297,11 +3368,11 @@ def LimitSeasonalCapacityFactor_Constraint(M: 'TemoaModel', r, p, s, t, op): :label: Limit Seasonal Capacity Factor \sum_{D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMSCF_{r, p, s, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} - + \forall \{r, p, t \notin T^{a}, o\} \in \Theta_{\text{LimitSeasonalCapacityFactor}} - + \\\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \cdot \sum_{D} SEG_{s,d} \le LIMSCF_{r, p, s, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} - + \forall \{r, p, t \in T^{a}, o\} \in \Theta_{\text{LimitSeasonalCapacityFactor}} """ # r can be an individual region (r='US'), or a combination of regions separated by plus (r='Mexico+US+Canada'), or 'global'. @@ -3309,10 +3380,7 @@ def LimitSeasonalCapacityFactor_Constraint(M: 'TemoaModel', r, p, s, t, op): regions = gather_group_regions(M, r) # we need to screen here because it is possible that the restriction extends beyond the # lifetime of any vintage of the tech... - if all( - (_r, p, t) not in M.V_CapacityAvailableByPeriodAndTech - for _r in regions - ): + if all((_r, p, t) not in M.V_CapacityAvailableByPeriodAndTech for _r in regions): return Constraint.Skip if t not in M.tech_annual: @@ -3360,7 +3428,8 @@ def LimitTechInputSplit_Constraint(M: 'TemoaModel', r, p, s, d, i, t, v, op): ) total_inp = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] / get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + / get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) @@ -3387,7 +3456,9 @@ def LimitTechInputSplitAnnual_Constraint(M: 'TemoaModel', r, p, i, t, v, op): for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - expr = operator_expression(inp, op, value(M.LimitTechInputSplitAnnual[r, p, i, t, op]) * total_inp) + expr = operator_expression( + inp, op, value(M.LimitTechInputSplitAnnual[r, p, i, t, op]) * total_inp + ) return expr @@ -3401,21 +3472,25 @@ def LimitTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v, op): the constraint only fixes the input shares over the course of a year.""" inp = sum( - M.V_FlowOut[r, p, S_s, S_d, i, t, v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) + M.V_FlowOut[r, p, S_s, S_d, i, t, v, S_o] + / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) for S_s in M.TimeSeason[p] for S_d in M.time_of_day for S_o in M.processOutputsByInput[r, p, t, v, i] ) total_inp = sum( - M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) + M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] + / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) for S_s in M.TimeSeason[p] for S_d in M.time_of_day for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, i] ) - expr = operator_expression(inp, op, value(M.LimitTechInputSplitAnnual[r, p, i, t, op]) * total_inp) + expr = operator_expression( + inp, op, value(M.LimitTechInputSplitAnnual[r, p, i, t, op]) * total_inp + ) return expr @@ -3455,8 +3530,7 @@ def LimitTechOutputSplit_Constraint(M: 'TemoaModel', r, p, s, d, t, v, o, op): \forall \{r, p, s, d, t, v, o\} \in \Theta_{\text{LimitTechOutputSplit}}""" out = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, o] - for S_i in M.processInputsByOutput[r, p, t, v, o] + M.V_FlowOut[r, p, s, d, S_i, t, v, o] for S_i in M.processInputsByOutput[r, p, t, v, o] ) total_out = sum( @@ -3484,8 +3558,7 @@ def LimitTechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o, op): \forall \{r, p, t \in T^{a}, v, o\} \in \Theta_{\text{LimitTechOutputSplitAnnual}}""" out = sum( - M.V_FlowOutAnnual[r, p, S_i, t, v, o] - for S_i in M.processInputsByOutput[r, p, t, v, o] + M.V_FlowOutAnnual[r, p, S_i, t, v, o] for S_i in M.processInputsByOutput[r, p, t, v, o] ) total_out = sum( @@ -3494,7 +3567,9 @@ def LimitTechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o, op): for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - expr = operator_expression(out, op, value(M.LimitTechOutputSplitAnnual[r, p, t, o, op]) * total_out) + expr = operator_expression( + out, op, value(M.LimitTechOutputSplitAnnual[r, p, t, o, op]) * total_out + ) return expr @@ -3522,11 +3597,13 @@ def LimitTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o, op): for S_d in M.time_of_day ) - expr = operator_expression(out, op, value(M.LimitTechOutputSplitAnnual[r, p, t, o, op]) * total_out) + expr = operator_expression( + out, op, value(M.LimitTechOutputSplitAnnual[r, p, t, o, op]) * total_out + ) return expr -#@deprecated('Deprecated. Use LimitActivityGroupShare instead') # doesn't play well with pyomo +# @deprecated('Deprecated. Use LimitActivityGroupShare instead') # doesn't play well with pyomo def RenewablePortfolioStandard_Constraint(M: 'TemoaModel', r, p, g): r""" Allows users to specify the share of electricity generation in a region @@ -3603,7 +3680,7 @@ def ParamProcessLifeFraction_rule(M: 'TemoaModel', r, p, t, v): else: # Remaining life years within the EOL period years_remaining = v + value(M.LifetimeProcess[r, t, v]) - p - + if years_remaining >= period_length: # try to avoid floating point round-off errors for the common case. return 1 @@ -3636,11 +3713,7 @@ def ParamLoanAnnualize_rule(M: 'TemoaModel', r, t, v): def SegFracPerSeason_rule(M: 'TemoaModel', p, s): - return sum( - value(M.SegFrac[p, s, S_d]) - for S_d in M.time_of_day - if (p, s, S_d) in M.SegFrac - ) + return sum(value(M.SegFrac[p, s, S_d]) for S_d in M.time_of_day if (p, s, S_d) in M.SegFrac) def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): @@ -3666,7 +3739,7 @@ def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): the primary region corresponds to the linked technology as well. The lifetimes of the primary and linked technologies should be specified and identical. """ - + if t in M.tech_annual: primary_flow = sum( ( @@ -3715,21 +3788,22 @@ def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): return -primary_flow == linked_flow + def operator_expression(lhs: Expression | None, operator: str | None, rhs: Expression | None): """Returns an expression, applying a configured operator""" if any((lhs is None, operator is None, rhs is None)): - msg = ( - 'Tried to build a constraint using a bad expression or operator: {} {} {}' - ).format(lhs, operator, rhs) + msg = ('Tried to build a constraint using a bad expression or operator: {} {} {}').format( + lhs, operator, rhs + ) logger.error(msg) raise ValueError(msg) try: match operator: - case "e": + case 'e': expr = lhs == rhs - case "le": + case 'le': expr = lhs <= rhs - case "ge": + case 'ge': expr = lhs >= rhs case _: msg = ( @@ -3739,12 +3813,12 @@ def operator_expression(lhs: Expression | None, operator: str | None, rhs: Expre raise ValueError(msg) except Exception as e: print(e) - msg = ( - 'Tried to build a constraint using a bad expression or operator: {} {} {}' - ).format(lhs, operator, rhs) + msg = ('Tried to build a constraint using a bad expression or operator: {} {} {}').format( + lhs, operator, rhs + ) logger.error(msg) raise ValueError(msg) - + return expr @@ -3753,12 +3827,15 @@ def operator_expression(lhs: Expression | None, operator: str | None, rhs: Expre # indices directly every time - saves build time def get_variable_efficiency(M: 'TemoaModel', r, p, s, d, i, t, v, o): if M.isEfficiencyVariable[r, p, i, t, v, o]: - return value(M.Efficiency[r, i, t, v, o]) * value(M.EfficiencyVariable[r, p, s, d, i, t, v, o]) + return value(M.Efficiency[r, i, t, v, o]) * value( + M.EfficiencyVariable[r, p, s, d, i, t, v, o] + ) else: return value(M.Efficiency[r, i, t, v, o]) - + + def get_capacity_factor(M: 'TemoaModel', r, p, s, d, t, v): if M.isCapacityFactorProcess[r, p, t, v]: return value(M.CapacityFactorProcess[r, p, s, d, t, v]) else: - return value(M.CapacityFactorTech[r, p, s, d, t]) \ No newline at end of file + return value(M.CapacityFactorTech[r, p, s, d, t]) diff --git a/temoa/temoa_model/temoa_sequencer.py b/temoa/_internal/temoa_sequencer.py similarity index 97% rename from temoa/temoa_model/temoa_sequencer.py rename to temoa/_internal/temoa_sequencer.py index 5057564c6..921b45aa1 100644 --- a/temoa/temoa_model/temoa_sequencer.py +++ b/temoa/_internal/temoa_sequencer.py @@ -36,24 +36,24 @@ import pyomo.opt +from temoa._internal.hybrid_loader import HybridLoader +from temoa._internal.run_actions import ( + build_instance, + check_database_version, + check_python_version, + check_solve_status, + handle_results, + solve_instance, +) +from temoa.core.config import TemoaConfig +from temoa.core.model import TemoaModel +from temoa.core.modes import TemoaMode from temoa.extensions.method_of_morris.morris_sequencer import MorrisSequencer from temoa.extensions.modeling_to_generate_alternatives.mga_sequencer import MgaSequencer from temoa.extensions.monte_carlo.mc_sequencer import MCSequencer from temoa.extensions.myopic.myopic_sequencer import MyopicSequencer from temoa.extensions.single_vector_mga.sv_mga_sequencer import SvMgaSequencer -from temoa.temoa_model.hybrid_loader import HybridLoader -from temoa.temoa_model.model_checking.pricing_check import price_checker -from temoa.temoa_model.run_actions import ( - build_instance, - solve_instance, - handle_results, - check_solve_status, - check_python_version, - check_database_version, -) -from temoa.temoa_model.temoa_config import TemoaConfig -from temoa.temoa_model.temoa_mode import TemoaMode -from temoa.temoa_model.temoa_model import TemoaModel +from temoa.model_checking.pricing_check import price_checker from temoa.version_information import ( DB_MAJOR_VERSION, MIN_DB_MINOR_VERSION, diff --git a/temoa/core/__init__.py b/temoa/core/__init__.py new file mode 100644 index 000000000..9322473d9 --- /dev/null +++ b/temoa/core/__init__.py @@ -0,0 +1,13 @@ +""" +TEMOA Core API + +This module provides the main public API for the TEMOA energy systems modeling library. +""" + +from .config import TemoaConfig +from .model import TemoaModel +from .modes import TemoaMode + +__version__ = '4.0.0a1' + +__all__ = ['TemoaModel', 'TemoaConfig', 'TemoaMode', '__version__'] diff --git a/temoa/temoa_model/temoa_config.py b/temoa/core/config.py similarity index 99% rename from temoa/temoa_model/temoa_config.py rename to temoa/core/config.py index 5940f391b..e7c30c43c 100644 --- a/temoa/temoa_model/temoa_config.py +++ b/temoa/core/config.py @@ -24,7 +24,7 @@ from pathlib import Path from sys import stderr as SE -from temoa.temoa_model.temoa_mode import TemoaMode +from temoa.core.modes import TemoaMode logger = getLogger(__name__) diff --git a/temoa/core/model.py b/temoa/core/model.py new file mode 100755 index 000000000..90c606092 --- /dev/null +++ b/temoa/core/model.py @@ -0,0 +1,1034 @@ +#!/usr/bin/env python + +""" +Tools for Energy Model Optimization and Analysis (Temoa): +An open source framework for energy systems optimization modeling + +SPDX-License-Identifier: MIT + +""" + +import logging + +from pyomo.core import BuildCheck +from pyomo.environ import ( + AbstractModel, + Any, + BuildAction, + Integers, + NonNegativeReals, + Objective, + Param, + minimize, +) + +from temoa._internal.temoa_initialize import * +from temoa._internal.temoa_rules import * +from temoa.model_checking.validators import ( + no_slash_or_pipe, + region_check, + region_group_check, + # validate_CapacityFactorProcess, + validate_0to1, + validate_Efficiency, + validate_linked_tech, + validate_ReserveMargin, + validate_tech_sets, +) + +logger = logging.getLogger(__name__) + +# disable linter rule that complains about star imports for this file +# ruff: noqa: F405 + + +class TemoaModel(AbstractModel): + """ + An instance of the abstract Temoa model + """ + + # this is used in several places outside this class, and this provides no-build access to it + default_lifetime_tech = 40 + + def __init__(M, *args, **kwargs): + AbstractModel.__init__(M, *args, **kwargs) + + ################################################ + # Internally used Data Containers # + # (not formal model elements) # + ################################################ + + # Dev Note: The triple-quotes UNDER the items below pop up as dox in most IDEs + M.processInputs = dict() + M.processOutputs = dict() + M.processLoans = dict() + M.activeFlow_rpsditvo = None + """a flow index for techs NOT in tech_annual""" + + M.activeFlow_rpitvo = None + """a flow index for techs in tech_annual only""" + + M.activeFlex_rpsditvo = None + M.activeFlex_rpitvo = None + M.activeFlowInStorage_rpsditvo = None + M.activeCurtailment_rpsditvo = None + M.activeActivity_rptv = None + M.storageLevelIndices_rpsdtv = None + M.seasonalStorageLevelIndices_rpstv = None + """currently available (within lifespan) (r, p, t, v) tuples (from M.processVintages)""" + + M.activeRegionsForTech = None + """currently available regions by period and tech {(p, t) : r}""" + + M.newCapacity_rtv = None + M.activeCapacityAvailable_rpt = None + M.activeCapacityAvailable_rptv = None + M.groupRegionActiveFlow_rpt = None # Set of valid group-region, period, tech indices + M.commodityBalance_rpc = None # Set of valid region-period-commodity indices to balance + M.commodityDStreamProcess = dict() # The downstream process of a commodity during a period + M.commodityUStreamProcess = dict() # The upstream process of a commodity during a period + M.capacityConsumptionTechs = ( + dict() + ) # New capacity consuming a commodity during a period [r,p,c] -> t + M.retirementProductionProcesses = ( + dict() + ) # Retired capacity producing a commodity during a period [r,p,c] -> t,v + M.processInputsByOutput = dict() + M.processOutputsByInput = dict() + M.processTechs = dict() + M.processReservePeriods = dict() + M.processPeriods = dict() # {(r, t, v): set(p)} + M.retirementPeriods = ( + dict() + ) # {(r, t, v): set(p)} periods in which a process can economically or naturally retire + M.processVintages = dict() + M.survivalCurvePeriods: dict[tuple, set] = ( + dict() + ) # {(r, t, v): set(p)} periods for which the process has a defined survival fraction + """current available (within lifespan) vintages {(r, p, t) : set(v)}""" + + M.baseloadVintages = dict() + M.curtailmentVintages = dict() + M.storageVintages = dict() + M.rampUpVintages = dict() + M.rampDownVintages = dict() + M.inputSplitVintages = dict() + M.inputSplitAnnualVintages = dict() + M.outputSplitVintages = dict() + M.outputSplitAnnualVintages = dict() + # M.processByPeriodAndOutput = dict() # not currently used + M.exportRegions = dict() + M.importRegions = dict() + + # These establish time sequencing + M.time_next = dict() # {(p, s, d): (s_next, d_next)} sequence of following time slices + M.time_next_sequential = dict() # {(p, s_seq): (s_seq_next)} next virtual storage season + M.sequential_to_season = ( + dict() + ) # {(p, s_seq): (s)} season matching this virtual storage season + + ################################################ + # Switching Sets # + # (to avoid slow searches in initialisation) # + ################################################ + + M.isEfficiencyVariable: dict[tuple, bool] = ( + dict() + ) # {(r, p, i, t, v, o): bool} which efficiencies have variable indexing + M.isCapacityFactorProcess: dict[tuple, bool] = ( + dict() + ) # {(r, p, t, v): bool} which capacity factors have have period-vintage indexing + M.isSeasonalStorage: dict[tuple, bool] = ( + dict() + ) # {t: bool} whether a storage tech is seasonal storage + M.isSurvivalCurveProcess: dict[tuple, bool] = ( + dict() + ) # {(r, t, v): bool} whether a process uses survival curves. + + ################################################ + # Model Sets # + # (used for indexing model elements) # + ################################################ + + M.progress_marker_1 = BuildAction(['Starting to build Sets'], rule=progress_check) + + M.operator = Set() + + # Define time periods + M.time_exist = Set(ordered=True) + M.time_future = Set(ordered=True) + M.time_optimize = Set(ordered=True, initialize=init_set_time_optimize, within=M.time_future) + # Define time period vintages to track capacity installation + M.vintage_exist = Set(ordered=True, initialize=init_set_vintage_exist) + M.vintage_optimize = Set(ordered=True, initialize=init_set_vintage_optimize) + M.vintage_all = Set(initialize=M.time_exist | M.time_optimize) + # Perform some basic validation on the specified time periods. + M.validate_time = BuildAction(rule=validate_time) + + # Define the model time slices + M.time_season = Set(ordered=True, validate=no_slash_or_pipe) + M.time_season_sequential = Set(ordered=True, validate=no_slash_or_pipe) + M.TimeSeason = Set(M.time_optimize, within=M.time_season, ordered=True) + M.time_of_day = Set(ordered=True, validate=no_slash_or_pipe) + + # This is just to get the TimeStorageSeason table sequentially. There must be a better way but this works for now + M.ordered_season_sequential = Set( + dimen=3, within=M.time_optimize * M.time_season_sequential * M.time_season, ordered=True + ) + + # Define regions + M.regions = Set(validate=region_check) + # RegionalIndices is the set of all the possible combinations of interregional exchanges + # plus original region indices. If tech_exchange is empty, RegionalIndices =regions. + M.regionalIndices = Set(initialize=CreateRegionalIndices) + M.regionalGlobalIndices = Set(validate=region_group_check) + + # Define technology-related sets + # M.tech_resource = Set() # not actually used by anything + M.tech_production = Set() + M.tech_all = Set( + initialize=M.tech_production, validate=no_slash_or_pipe + ) # was M.tech_resource | M.tech_production + M.tech_baseload = Set(within=M.tech_all) + M.tech_annual = Set(within=M.tech_all) + M.tech_demand = Set(within=M.tech_all) + # annual storage not supported in Storage constraint or TableWriter, so exclude from domain + M.tech_storage = Set(within=M.tech_all) + M.tech_reserve = Set(within=M.tech_all) + M.tech_upramping = Set(within=M.tech_all) + M.tech_downramping = Set(within=M.tech_all) + M.tech_curtailment = Set(within=M.tech_all) + M.tech_flex = Set(within=M.tech_all) + # ensure there is no overlap flex <=> curtailable technologies + M.tech_exchange = Set(within=M.tech_all) + + # Define groups for technologies + M.tech_group_names = Set() + M.tech_group_members = Set(M.tech_group_names, within=M.tech_all) + M.tech_or_group = Set(initialize=M.tech_group_names | M.tech_all) + + M.tech_seasonal_storage = Set(within=M.tech_storage) + """storage technologies using the interseasonal storage feature""" + + M.tech_uncap = Set(within=M.tech_all - M.tech_reserve) + """techs with unlimited capacity, ALWAYS available within lifespan""" + + M.tech_exist = Set() + """techs with existing capacity, want to keep these for accounting reasons""" + + # the below is a convenience for domain checking in params below that should not accept uncap techs... + M.tech_with_capacity = Set(initialize=M.tech_all - M.tech_uncap) + """techs eligible for capacitization""" + # Define techs for which economic retirement is an option + # Note: Storage techs cannot (currently) be retired due to linkage to initialization + # process, which is currently incapable of reducing initializations on retirements. + # Note2: I think this has been fixed but I can't tell what the problem was. Suspect + # it was the old StorageInit constraint + M.tech_retirement = Set(within=M.tech_with_capacity) # - M.tech_storage) + + M.validate_techs = BuildAction(rule=validate_tech_sets) + + # Define commodity-related sets + M.commodity_demand = Set() + M.commodity_emissions = Set() + M.commodity_physical = Set() + M.commodity_waste = Set() + M.commodity_flex = Set(within=M.commodity_physical) + M.commodity_source = Set(within=M.commodity_physical) + M.commodity_annual = Set(within=M.commodity_physical) + M.commodity_carrier = Set( + initialize=M.commodity_physical | M.commodity_demand | M.commodity_waste + ) + M.commodity_all = Set( + initialize=M.commodity_carrier | M.commodity_emissions, validate=no_slash_or_pipe + ) + + ################################################ + # Model Parameters # + # (data gathered/derived from source) # + ################################################ + + # --------------------------------------------------------------- + # Dev Note: + # In order to increase model efficiency, we use sparse + # indexing of parameters, variables, and equations to prevent the + # creation of indices for which no data exists. While basic model sets + # are defined above, sparse index sets are defined below adjacent to the + # appropriate parameter, variable, or constraint and all are initialized + # in temoa_initialize.py. + # Because the function calls that define the sparse index sets obscure the + # sets utilized, we use a suffix that includes a one character name for each + # set. Example: "_tv" indicates a set defined over "technology" and "vintage". + # The complete index set is: psditvo, where p=period, s=season, d=day, + # i=input commodity, t=technology, v=vintage, o=output commodity. + # --------------------------------------------------------------- + + # these "progress markers" report build progress in the log, if the level == debug + M.progress_marker_2 = BuildAction(['Starting to build Params'], rule=progress_check) + + M.GlobalDiscountRate = Param(default=0.05) + + # Define time-related parameters + M.PeriodLength = Param(M.time_optimize, initialize=ParamPeriodLength) + M.SegFrac = Param(M.time_optimize, M.time_season, M.time_of_day) + M.validate_SegFrac = BuildAction(rule=validate_SegFrac) + M.TimeSequencing = Set() # How do states carry between time segments? + M.TimeNext = Set( + ordered=True + ) # This is just to get data from the table. Hidden feature and usually not used + M.validate_TimeNext = BuildAction(rule=validate_TimeNext) + + # Define demand- and resource-related parameters + # Dev Note: There does not appear to be a DB table supporting DemandDefaultDistro. This does not + # cause any problems, so let it be for now. + # Doesn't seem to be much point in the table. Just clones SegFrac + # M.DemandDefaultDistribution = Param(M.time_optimize, M.time_season, M.time_of_day, mutable=True) + M.DemandSpecificDistribution = Param( + M.regions, + M.time_optimize, + M.time_season, + M.time_of_day, + M.commodity_demand, + mutable=True, + default=0, + ) + + M.DemandConstraint_rpc = Set(within=M.regions * M.time_optimize * M.commodity_demand) + M.Demand = Param(M.DemandConstraint_rpc) + + # Dev Note: This parameter is currently NOT implemented. Preserved for later refactoring + # LimitResource IS implemented but sums cumulatively for a technology rather than resource commodity + # M.ResourceConstraint_rpr = Set(within=M.regions * M.time_optimize * M.commodity_physical) + # M.ResourceBound = Param(M.ResourceConstraint_rpr) + + # Define technology performance parameters + M.CapacityToActivity = Param(M.regionalIndices, M.tech_all, default=1) + + M.ExistingCapacity = Param(M.regionalIndices, M.tech_exist, M.vintage_exist) + + # Dev Note: The below is temporarily useful for passing down to validator to find set violations + # Uncomment this assignment, and comment out the orig below it... + # M.Efficiency = Param( + # Any, Any, Any, Any, Any, + # within=NonNegativeReals, validate=validate_Efficiency + # ) + + # devnote: need these here or CheckEfficiencyIndices may flag these commodities as unused + M.ConstructionInput = Param( + M.regions, M.commodity_physical, M.tech_with_capacity, M.vintage_optimize + ) + M.EndOfLifeOutput = Param( + M.regions, M.tech_with_capacity, M.vintage_all, M.commodity_carrier + ) + + M.Efficiency = Param( + M.regionalIndices, + M.commodity_physical, + M.tech_all, + M.vintage_all, + M.commodity_carrier, + within=NonNegativeReals, + validate=validate_Efficiency, + ) + M.validate_UsedEfficiencyIndices = BuildAction(rule=CheckEfficiencyIndices) + + M.EfficiencyVariable = Param( + M.regionalIndices, + M.time_optimize, + M.time_season, + M.time_of_day, + M.commodity_physical, + M.tech_all, + M.vintage_all, + M.commodity_carrier, + within=NonNegativeReals, + default=1, + ) + + M.LifetimeTech = Param( + M.regionalIndices, M.tech_all, default=TemoaModel.default_lifetime_tech + ) + + M.LifetimeProcess_rtv = Set(dimen=3, initialize=LifetimeProcessIndices) + M.LifetimeProcess = Param(M.LifetimeProcess_rtv, default=get_default_process_lifetime) + + M.LifetimeSurvivalCurve = Param( + M.regionalIndices, + Integers, + M.tech_all, + M.vintage_all, + default=get_default_survival, + validate=validate_0to1, + mutable=True, + ) + M.Create_SurvivalCurve = BuildAction(rule=CreateSurvivalCurve) + + M.LoanLifetimeProcess_rtv = Set(dimen=3, initialize=LifetimeLoanProcessIndices) + + # Dev Note: The LoanLifetimeProcess table *could* be removed. There is no longer a supporting + # table in the database. It is just a "passthrough" now to the default LoanLifetimeTech. + # It is already stitched in to the model, so will leave it for now. Table may be revived. + + M.LoanLifetimeProcess = Param(M.LoanLifetimeProcess_rtv, default=get_loan_life) + + M.LimitTechInputSplit = Param( + M.regions, + M.time_optimize, + M.commodity_physical, + M.tech_all, + M.operator, + validate=validate_0to1, + ) + M.LimitTechInputSplitAnnual = Param( + M.regions, + M.time_optimize, + M.commodity_physical, + M.tech_all, + M.operator, + validate=validate_0to1, + ) + + M.LimitTechOutputSplit = Param( + M.regions, + M.time_optimize, + M.tech_all, + M.commodity_carrier, + M.operator, + validate=validate_0to1, + ) + M.LimitTechOutputSplitAnnual = Param( + M.regions, + M.time_optimize, + M.tech_all, + M.commodity_carrier, + M.operator, + validate=validate_0to1, + ) + + M.RenewablePortfolioStandardConstraint_rpg = Set( + within=M.regions * M.time_optimize * M.tech_group_names + ) + M.RenewablePortfolioStandard = Param( + M.RenewablePortfolioStandardConstraint_rpg, validate=validate_0to1 + ) + + # These need to come before validate_SeasonSequential + M.RampUpHourly = Param(M.regions, M.tech_upramping, validate=validate_0to1) + M.RampDownHourly = Param(M.regions, M.tech_downramping, validate=validate_0to1) + + # Set up representation of time + M.DaysPerPeriod = Param() + M.SegFracPerSeason = Param(M.time_optimize, M.time_season, initialize=SegFracPerSeason_rule) + M.TimeSeasonSequential = Param( + M.time_optimize, M.time_season_sequential, M.time_season, mutable=True + ) + M.validate_SeasonSequential = BuildAction(rule=CreateTimeSeasonSequential) + M.Create_TimeSequence = BuildAction(rule=CreateTimeSequence) + + # The method below creates a series of helper functions that are used to + # perform the sparse matrix of indexing for the parameters, variables, and + # equations below. + M.Create_SparseDicts = BuildAction(rule=CreateSparseDicts) + M.initialize_Demands = BuildAction(rule=CreateDemands) + + M.CapacityFactor_rpsdt = Set(dimen=5, initialize=CapacityFactorTechIndices) + M.CapacityFactorTech = Param(M.CapacityFactor_rpsdt, default=1, validate=validate_0to1) + + # Dev note: using a default function below alleviates need to make this set. + # M.CapacityFactor_rsdtv = Set(dimen=5, initialize=CapacityFactorProcessIndices) + M.CapacityFactorProcess = Param( + M.regionalIndices, + M.time_optimize, + M.time_season, + M.time_of_day, + M.tech_with_capacity, + M.vintage_all, + # validate=validate_CapacityFactorProcess, # opting for a quicker validation, just 0->1 + validate=validate_0to1, + default=get_default_capacity_factor, # surprisingly slow but only called if a value is missing + ) + + M.CapacityConstraint_rpsdtv = Set(dimen=6, initialize=CapacityConstraintIndices) + M.initialize_CapacityFactors = BuildAction(rule=CheckCapacityFactorProcess) + M.initialize_EfficiencyVariable = BuildAction(rule=CheckEfficiencyVariable) + + # Define technology cost parameters + # dev note: the CostFixed_rptv isn't truly needed, but it is included in a constraint, so + # let it go for now + M.CostFixed_rptv = Set(dimen=4, initialize=CostFixedIndices) + M.CostFixed = Param(M.CostFixed_rptv) + + M.CostInvest_rtv = Set(within=M.regionalIndices * M.tech_all * M.time_optimize) + M.CostInvest = Param(M.CostInvest_rtv) + + M.DefaultLoanRate = Param(domain=NonNegativeReals) + M.LoanRate = Param(M.CostInvest_rtv, domain=NonNegativeReals, default=get_default_loan_rate) + M.LoanAnnualize = Param(M.CostInvest_rtv, initialize=ParamLoanAnnualize_rule) + + M.CostVariable_rptv = Set(dimen=4, initialize=CostVariableIndices) + M.CostVariable = Param(M.CostVariable_rptv) + + M.CostEmission_rpe = Set(within=M.regions * M.time_optimize * M.commodity_emissions) + M.CostEmission = Param(M.CostEmission_rpe) + + # devnote: no longer used + # 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) + + M.LimitCapacityConstraint_rpt = Set( + within=M.regionalGlobalIndices * M.time_optimize * M.tech_or_group * M.operator + ) + M.LimitCapacity = Param(M.LimitCapacityConstraint_rpt) + + M.LimitNewCapacityConstraint_rpt = Set( + within=M.regionalGlobalIndices * M.time_optimize * M.tech_or_group * M.operator + ) + M.LimitNewCapacity = Param(M.LimitNewCapacityConstraint_rpt) + + M.LimitResourceConstraint_rt = Set( + within=M.regionalGlobalIndices * M.tech_or_group * M.operator + ) + M.LimitResource = Param(M.LimitResourceConstraint_rt) + + M.LimitActivityConstraint_rpt = Set( + within=M.regionalGlobalIndices * M.time_optimize * M.tech_or_group * M.operator + ) + M.LimitActivity = Param(M.LimitActivityConstraint_rpt) + + M.LimitSeasonalCapacityFactorConstraint_rpst = Set( + within=M.regionalGlobalIndices + * M.time_optimize + * M.time_season + * M.tech_all + * M.operator + ) + M.LimitSeasonalCapacityFactor = Param( + M.LimitSeasonalCapacityFactorConstraint_rpst, validate=validate_0to1 + ) + + M.LimitAnnualCapacityFactorConstraint_rpto = Set( + within=M.regionalGlobalIndices + * M.time_optimize + * M.tech_all + * M.commodity_carrier + * M.operator + ) + M.LimitAnnualCapacityFactor = Param( + M.LimitAnnualCapacityFactorConstraint_rpto, validate=validate_0to1 + ) + + M.LimitGrowthCapacity = Param( + M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any + ) + M.LimitDegrowthCapacity = Param( + M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any + ) + M.LimitGrowthNewCapacity = Param( + M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any + ) + M.LimitDegrowthNewCapacity = Param( + M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any + ) + M.LimitGrowthNewCapacityDelta = Param( + M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any + ) + M.LimitDegrowthNewCapacityDelta = Param( + M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any + ) + + M.LimitEmissionConstraint_rpe = Set( + within=M.regionalGlobalIndices * M.time_optimize * M.commodity_emissions * M.operator + ) + M.LimitEmission = Param(M.LimitEmissionConstraint_rpe) + M.EmissionActivity_reitvo = Set(dimen=6, initialize=EmissionActivityIndices) + M.EmissionActivity = Param(M.EmissionActivity_reitvo) + + # devnote: deprecated when generalising tech/group columns in Limit tables + # M.LimitActivityGroupConstraint_rpg = Set( + # within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names * M.operator + # ) + # M.LimitActivityGroup = Param(M.LimitActivityGroupConstraint_rpg) + + # M.LimitCapacityGroupConstraint_rpg = Set( + # within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names * M.operator + # ) + # M.LimitCapacityGroup = Param(M.LimitCapacityGroupConstraint_rpg) + + # M.LimitNewCapacityGroupConstraint_rpg = Set( + # within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names * M.operator + # ) + # M.LimitNewCapacityGroup = Param(M.LimitNewCapacityGroupConstraint_rpg) + # M.GroupShareIndices = Set(dimen=5, initialize=GroupShareIndices) # doesn't feel worth it + + M.LimitCapacityShareConstraint_rpgg = Set( + within=M.regionalGlobalIndices + * M.time_optimize + * M.tech_or_group + * M.tech_or_group + * M.operator + ) + M.LimitCapacityShare = Param(M.LimitCapacityShareConstraint_rpgg) + + M.LimitActivityShareConstraint_rpgg = Set( + within=M.regionalGlobalIndices + * M.time_optimize + * M.tech_or_group + * M.tech_or_group + * M.operator + ) + M.LimitActivityShare = Param(M.LimitActivityShareConstraint_rpgg) + + M.LimitNewCapacityShareConstraint_rpgg = Set( + within=M.regionalGlobalIndices + * M.time_optimize + * M.tech_or_group + * M.tech_or_group + * M.operator + ) + M.LimitNewCapacityShare = Param(M.LimitNewCapacityShareConstraint_rpgg) + + # devnote: deprecated when generalising tech/group columns in Limit tables + # M.TwoGroupShareIndices = Set(dimen=5, initialize=TwoGroupShareIndices) + + # M.LimitNewCapacityGroupShareConstraint_rpgg = Set(within=M.TwoGroupShareIndices) + # M.LimitNewCapacityGroupShare = Param(M.TwoGroupShareIndices) + + # M.LimitActivityGroupShareConstraint_rpgg = Set(within=M.TwoGroupShareIndices) + # M.LimitActivityGroupShare = Param(M.TwoGroupShareIndices) + + # This set works for all storage-related constraints + M.StorageConstraints_rpsdtv = Set(dimen=6, initialize=StorageConstraintIndices) + M.SeasonalStorageConstraints_rpsdtv = Set( + dimen=6, initialize=SeasonalStorageConstraintIndices + ) + M.LimitStorageFractionConstraint_rpsdtv = Set( + within=(M.StorageConstraints_rpsdtv | M.SeasonalStorageConstraints_rpsdtv) * M.operator + ) + M.LimitStorageFraction = Param( + M.LimitStorageFractionConstraint_rpsdtv, validate=validate_0to1 + ) + + # Storage duration is expressed in hours + M.StorageDuration = Param(M.regions, M.tech_storage, default=4) + + M.LinkedTechs = Param(M.regionalIndices, M.tech_all, M.commodity_emissions, within=Any) + + # Define parameters associated with electric sector operation + M.ReserveMarginMethod = Set() # How contributions to the reserve margin are calculated + M.CapacityCredit = Param( + M.regionalIndices, + M.time_optimize, + M.tech_reserve, + M.vintage_all, + default=0, + validate=validate_0to1, + ) + M.ReserveCapacityDerate = Param( + M.regionalIndices, + M.time_optimize, + M.time_season, + M.tech_reserve, + M.vintage_all, + default=1, + validate=validate_0to1, + ) + M.PlanningReserveMargin = Param(M.regions) + + M.EmissionEmbodied = Param( + M.regions, M.commodity_emissions, M.tech_with_capacity, M.vintage_optimize + ) + M.EmissionEndOfLife = Param( + M.regions, M.commodity_emissions, M.tech_with_capacity, M.vintage_all + ) + + M.MyopicDiscountingYear = Param(default=0) + + ################################################ + # Model Variables # + # (assigned by solver) # + ################################################ + + # --------------------------------------------------------------- + # Dev Note: + # Decision variables are optimized in order to minimize cost. + # Base decision variables represent the lowest-level variables + # in the model. Derived decision variables are calculated for + # convenience, where 1 or more indices in the base variables are + # summed over. + # --------------------------------------------------------------- + + M.progress_marker_3 = BuildAction(['Starting to build Variables'], rule=progress_check) + + # Define base decision variables + M.FlowVar_rpsditvo = Set(dimen=8, initialize=FlowVariableIndices) + M.V_FlowOut = Var(M.FlowVar_rpsditvo, domain=NonNegativeReals) + + M.FlowVarAnnual_rpitvo = Set(dimen=6, initialize=FlowVariableAnnualIndices) + M.V_FlowOutAnnual = Var(M.FlowVarAnnual_rpitvo, domain=NonNegativeReals) + + M.FlexVar_rpsditvo = Set(dimen=8, initialize=FlexVariablelIndices) + M.V_Flex = Var(M.FlexVar_rpsditvo, domain=NonNegativeReals) + + M.FlexVarAnnual_rpitvo = Set(dimen=6, initialize=FlexVariableAnnualIndices) + M.V_FlexAnnual = Var(M.FlexVarAnnual_rpitvo, domain=NonNegativeReals) + + M.CurtailmentVar_rpsditvo = Set(dimen=8, initialize=CurtailmentVariableIndices) + M.V_Curtailment = Var(M.CurtailmentVar_rpsditvo, domain=NonNegativeReals, initialize=0) + + M.FlowInStorage_rpsditvo = Set(dimen=8, initialize=FlowInStorageVariableIndices) + M.V_FlowIn = Var(M.FlowInStorage_rpsditvo, domain=NonNegativeReals) + + M.StorageLevel_rpsdtv = Set(dimen=6, initialize=StorageLevelVariableIndices) + M.V_StorageLevel = Var(M.StorageLevel_rpsdtv, domain=NonNegativeReals) + + M.SeasonalStorageLevel_rpstv = Set(dimen=5, initialize=SeasonalStorageLevelVariableIndices) + M.V_SeasonalStorageLevel = Var(M.SeasonalStorageLevel_rpstv, domain=NonNegativeReals) + + # Derived decision variables + 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.AnnualRetirementVar_rptv = Set(dimen=4, initialize=AnnualRetirementVariableIndices) + M.V_AnnualRetirement = Var( + M.AnnualRetirementVar_rptv, domain=NonNegativeReals, initialize=0 + ) + + M.CapacityAvailableVar_rpt = Set(dimen=3, initialize=CapacityAvailableVariableIndices) + M.V_CapacityAvailableByPeriodAndTech = Var( + M.CapacityAvailableVar_rpt, domain=NonNegativeReals, initialize=0 + ) + + ################################################ + # Objective Function # + # (minimize total cost) # + ################################################ + + M.TotalCost = Objective(rule=TotalCost_rule, sense=minimize) + + ################################################ + # Constraints # + # # + ################################################ + + # --------------------------------------------------------------- + # Dev Note: + # Constraints are specified to ensure proper system behavior, + # and also to calculate some derived quantities. Note that descriptions + # of these constraints are provided in the associated comment blocks + # in temoa_rules.py, where the constraints are defined. + # --------------------------------------------------------------- + M.progress_marker_4 = BuildAction(['Starting to build Constraints'], rule=progress_check) + + # Declare constraints to calculate derived decision variables + M.CapacityConstraint = Constraint(M.CapacityConstraint_rpsdtv, rule=Capacity_Constraint) + + M.CapacityAnnualConstraint_rptv = Set(dimen=4, initialize=CapacityAnnualConstraintIndices) + M.CapacityAnnualConstraint = Constraint( + M.CapacityAnnualConstraint_rptv, rule=CapacityAnnual_Constraint + ) + + M.CapacityAvailableByPeriodAndTechConstraint = Constraint( + M.CapacityAvailableVar_rpt, rule=CapacityAvailableByPeriodAndTech_Constraint + ) + + # devnote: I think this constraint is redundant + # M.RetiredCapacityConstraint = Constraint( + # M.RetiredCapacityVar_rptv, rule=RetiredCapacity_Constraint + # ) + M.progress_marker_4a = BuildAction( + ['Starting AnnualRetirementConstraint'], rule=progress_check + ) + M.AnnualRetirementConstraint = Constraint( + M.AnnualRetirementVar_rptv, rule=AnnualRetirement_Constraint + ) + M.progress_marker_4b = BuildAction( + ['Starting AdjustedCapacityConstraint'], rule=progress_check + ) + M.AdjustedCapacityConstraint = Constraint( + M.CostFixed_rptv, rule=AdjustedCapacity_Constraint + ) + M.progress_marker_5 = BuildAction(['Finished Capacity Constraints'], rule=progress_check) + + # Declare core model constraints that ensure proper system functioning + # In driving order, starting with the need to meet end-use demands + + M.DemandConstraint = Constraint(M.DemandConstraint_rpc, rule=Demand_Constraint) + + # devnote: testing a workaround + M.DemandActivityConstraint_rpsdtv_dem = Set( + dimen=7, initialize=DemandActivityConstraintIndices + ) + M.DemandActivityConstraint = Constraint( + M.DemandActivityConstraint_rpsdtv_dem, rule=DemandActivity_Constraint + ) + + M.CommodityBalanceConstraint_rpsdc = Set( + dimen=5, initialize=CommodityBalanceConstraintIndices + ) + M.CommodityBalanceConstraint = Constraint( + M.CommodityBalanceConstraint_rpsdc, rule=CommodityBalance_Constraint + ) + + M.AnnualCommodityBalanceConstraint_rpc = Set( + dimen=3, initialize=AnnualCommodityBalanceConstraintIndices + ) + M.AnnualCommodityBalanceConstraint = Constraint( + M.AnnualCommodityBalanceConstraint_rpc, rule=AnnualCommodityBalance_Constraint + ) + + # M.ResourceExtractionConstraint = Constraint( + # M.ResourceConstraint_rpr, rule=ResourceExtraction_Constraint + # ) + + M.BaseloadDiurnalConstraint_rpsdtv = Set( + dimen=6, initialize=BaseloadDiurnalConstraintIndices + ) + M.BaseloadDiurnalConstraint = Constraint( + M.BaseloadDiurnalConstraint_rpsdtv, rule=BaseloadDiurnal_Constraint + ) + + M.RegionalExchangeCapacityConstraint_rrptv = Set( + dimen=5, initialize=RegionalExchangeCapacityConstraintIndices + ) + M.RegionalExchangeCapacityConstraint = Constraint( + M.RegionalExchangeCapacityConstraint_rrptv, rule=RegionalExchangeCapacity_Constraint + ) + + M.progress_marker_6 = BuildAction(['Starting Storage Constraints'], rule=progress_check) + + M.StorageEnergyConstraint = Constraint( + M.StorageConstraints_rpsdtv, rule=StorageEnergy_Constraint + ) + + M.StorageEnergyUpperBoundConstraint = Constraint( + M.StorageConstraints_rpsdtv, rule=StorageEnergyUpperBound_Constraint + ) + + M.SeasonalStorageEnergyConstraint = Constraint( + M.SeasonalStorageLevel_rpstv, rule=SeasonalStorageEnergy_Constraint + ) + + M.SeasonalStorageEnergyUpperBoundConstraint = Constraint( + M.SeasonalStorageConstraints_rpsdtv, rule=SeasonalStorageEnergyUpperBound_Constraint + ) + + M.StorageChargeRateConstraint = Constraint( + M.StorageConstraints_rpsdtv, rule=StorageChargeRate_Constraint + ) + + M.StorageDischargeRateConstraint = Constraint( + M.StorageConstraints_rpsdtv, rule=StorageDischargeRate_Constraint + ) + + M.StorageThroughputConstraint = Constraint( + M.StorageConstraints_rpsdtv, rule=StorageThroughput_Constraint + ) + + M.LimitStorageFractionConstraint = Constraint( + M.LimitStorageFractionConstraint_rpsdtv, rule=LimitStorageFraction_Constraint + ) + + M.RampUpDayConstraint_rpsdtv = Set(dimen=6, initialize=RampUpDayConstraintIndices) + M.RampUpDayConstraint = Constraint(M.RampUpDayConstraint_rpsdtv, rule=RampUpDay_Constraint) + M.RampDownDayConstraint_rpsdtv = Set(dimen=6, initialize=RampDownDayConstraintIndices) + M.RampDownDayConstraint = Constraint( + M.RampDownDayConstraint_rpsdtv, rule=RampDownDay_Constraint + ) + + M.RampUpSeasonConstraint_rpsstv = Set(dimen=6, initialize=RampUpSeasonConstraintIndices) + M.RampUpSeasonConstraint = Constraint( + M.RampUpSeasonConstraint_rpsstv, rule=RampUpSeason_Constraint + ) + M.RampDownSeasonConstraint_rpsstv = Set(dimen=6, initialize=RampDownSeasonConstraintIndices) + M.RampDownSeasonConstraint = Constraint( + M.RampDownSeasonConstraint_rpsstv, rule=RampDownSeason_Constraint + ) + + M.ReserveMargin_rpsd = Set(dimen=4, initialize=ReserveMarginIndices) + M.validate_ReserveMargin = BuildAction(rule=validate_ReserveMargin) + M.ReserveMarginConstraint = Constraint(M.ReserveMargin_rpsd, rule=ReserveMargin_Constraint) + + M.LimitEmissionConstraint = Constraint( + M.LimitEmissionConstraint_rpe, rule=LimitEmission_Constraint + ) + M.progress_marker_7 = BuildAction( + ['Starting LimitGrowth and Activity Constraints'], rule=progress_check + ) + + M.LimitGrowthCapacityConstraint_rpt = Set(dimen=4, initialize=LimitGrowthCapacityIndices) + M.LimitGrowthCapacityConstraint = Constraint( + M.LimitGrowthCapacityConstraint_rpt, rule=LimitGrowthCapacityConstraint_rule + ) + M.LimitDegrowthCapacityConstraint_rpt = Set( + dimen=4, initialize=LimitDegrowthCapacityIndices + ) + M.LimitDegrowthCapacityConstraint = Constraint( + M.LimitDegrowthCapacityConstraint_rpt, rule=LimitDegrowthCapacityConstraint_rule + ) + + M.LimitGrowthNewCapacityConstraint_rpt = Set( + dimen=4, initialize=LimitGrowthNewCapacityIndices + ) + M.LimitGrowthNewCapacityConstraint = Constraint( + M.LimitGrowthNewCapacityConstraint_rpt, rule=LimitGrowthNewCapacityConstraint_rule + ) + M.LimitDegrowthNewCapacityConstraint_rpt = Set( + dimen=4, initialize=LimitDegrowthNewCapacityIndices + ) + M.LimitDegrowthNewCapacityConstraint = Constraint( + M.LimitDegrowthNewCapacityConstraint_rpt, rule=LimitDegrowthNewCapacityConstraint_rule + ) + + M.LimitGrowthNewCapacityDeltaConstraint_rpt = Set( + dimen=4, initialize=LimitGrowthNewCapacityDeltaIndices + ) + M.LimitGrowthNewCapacityDeltaConstraint = Constraint( + M.LimitGrowthNewCapacityDeltaConstraint_rpt, + rule=LimitGrowthNewCapacityDeltaConstraint_rule, + ) + M.LimitDegrowthNewCapacityDeltaConstraint_rpt = Set( + dimen=4, initialize=LimitDegrowthNewCapacityDeltaIndices + ) + M.LimitDegrowthNewCapacityDeltaConstraint = Constraint( + M.LimitDegrowthNewCapacityDeltaConstraint_rpt, + rule=LimitDegrowthNewCapacityDeltaConstraint_rule, + ) + + M.LimitActivityConstraint = Constraint( + M.LimitActivityConstraint_rpt, rule=LimitActivity_Constraint + ) + + M.LimitSeasonalCapacityFactorConstraint = Constraint( + M.LimitSeasonalCapacityFactorConstraint_rpst, + rule=LimitSeasonalCapacityFactor_Constraint, + ) + + # devnote: deprecated when generalising tech/group columns in Limit tables + # M.LimitActivityGroupConstraint = Constraint( + # M.LimitActivityGroupConstraint_rpg, rule=LimitActivityGroup_Constraint + # ) + + M.LimitCapacityConstraint = Constraint( + M.LimitCapacityConstraint_rpt, rule=LimitCapacity_Constraint + ) + + M.LimitNewCapacityConstraint = Constraint( + M.LimitNewCapacityConstraint_rpt, rule=LimitNewCapacity_Constraint + ) + + # devnote: deprecated when generalising tech/group columns in Limit tables + # M.LimitCapacityGroupConstraint = Constraint( + # M.LimitCapacityGroupConstraint_rpg, rule=LimitCapacityGroup_Constraint + # ) + + # M.LimitNewCapacityGroupConstraint = Constraint( + # M.LimitNewCapacityGroupConstraint_rpg, rule=LimitNewCapacityGroup_Constraint + # ) + + M.LimitCapacityShareConstraint = Constraint( + M.LimitCapacityShareConstraint_rpgg, rule=LimitCapacityShare_Constraint + ) + + M.LimitActivityShareConstraint = Constraint( + M.LimitActivityShareConstraint_rpgg, rule=LimitActivityShare_Constraint + ) + + M.LimitNewCapacityShareConstraint = Constraint( + M.LimitNewCapacityShareConstraint_rpgg, rule=LimitNewCapacityShare_Constraint + ) + + # devnote: deprecated when generalising tech/group columns in Limit tables + # M.LimitNewCapacityGroupShareConstraint = Constraint( + # M.LimitNewCapacityGroupShareConstraint_rpgg, rule=LimitNewCapacityGroupShare_Constraint + # ) + + # M.LimitActivityGroupShareConstraint = Constraint( + # M.LimitActivityGroupShareConstraint_rpgg, rule=LimitActivityGroupShare_Constraint + # ) + + M.progress_marker_8 = BuildAction( + ['Starting Limit Capacity and Tech Split Constraints'], rule=progress_check + ) + + M.LimitResourceConstraint = Constraint( + M.LimitResourceConstraint_rt, rule=LimitResource_Constraint + ) + + M.LimitAnnualCapacityFactorConstraint = Constraint( + M.LimitAnnualCapacityFactorConstraint_rpto, rule=LimitAnnualCapacityFactor_Constraint + ) + + ## Tech input splits + M.LimitTechInputSplitConstraint_rpsditv = Set( + dimen=8, initialize=LimitTechInputSplitConstraintIndices + ) + M.LimitTechInputSplitConstraint = Constraint( + M.LimitTechInputSplitConstraint_rpsditv, rule=LimitTechInputSplit_Constraint + ) + + M.LimitTechInputSplitAnnualConstraint_rpitv = Set( + dimen=6, initialize=LimitTechInputSplitAnnualConstraintIndices + ) + M.LimitTechInputSplitAnnualConstraint = Constraint( + M.LimitTechInputSplitAnnualConstraint_rpitv, rule=LimitTechInputSplitAnnual_Constraint + ) + + M.LimitTechInputSplitAverageConstraint_rpitv = Set( + dimen=6, initialize=LimitTechInputSplitAverageConstraintIndices + ) + M.LimitTechInputSplitAverageConstraint = Constraint( + M.LimitTechInputSplitAverageConstraint_rpitv, rule=LimitTechInputSplitAverage_Constraint + ) + + ## Tech output splits + M.LimitTechOutputSplitConstraint_rpsdtvo = Set( + dimen=8, initialize=LimitTechOutputSplitConstraintIndices + ) + M.LimitTechOutputSplitConstraint = Constraint( + M.LimitTechOutputSplitConstraint_rpsdtvo, rule=LimitTechOutputSplit_Constraint + ) + + M.LimitTechOutputSplitAnnualConstraint_rptvo = Set( + dimen=6, initialize=LimitTechOutputSplitAnnualConstraintIndices + ) + M.LimitTechOutputSplitAnnualConstraint = Constraint( + M.LimitTechOutputSplitAnnualConstraint_rptvo, rule=LimitTechOutputSplitAnnual_Constraint + ) + + M.LimitTechOutputSplitAverageConstraint_rptvo = Set( + dimen=6, initialize=LimitTechOutputSplitAverageConstraintIndices + ) + M.LimitTechOutputSplitAverageConstraint = Constraint( + M.LimitTechOutputSplitAverageConstraint_rptvo, + rule=LimitTechOutputSplitAverage_Constraint, + ) + + M.RenewablePortfolioStandardConstraint = Constraint( + M.RenewablePortfolioStandardConstraint_rpg, rule=RenewablePortfolioStandard_Constraint + ) + + M.LinkedEmissionsTechConstraint_rpsdtve = Set( + dimen=7, initialize=LinkedTechConstraintIndices + ) + # the validation requires that the set above be built first: + M.validate_LinkedTech_lifetimes = BuildCheck(rule=validate_linked_tech) + + M.LinkedEmissionsTechConstraint = Constraint( + M.LinkedEmissionsTechConstraint_rpsdtve, rule=LinkedEmissionsTech_Constraint + ) + + M.progress_marker_9 = BuildAction(['Finished Constraints'], rule=progress_check) + + +def progress_check(M, checkpoint: str): + """A quick widget which is called by BuildAction in order to log creation progress""" + logger.debug('Model build progress: %s', checkpoint) diff --git a/temoa/temoa_model/temoa_mode.py b/temoa/core/modes.py similarity index 100% rename from temoa/temoa_model/temoa_mode.py rename to temoa/core/modes.py diff --git a/temoa/extensions/method_of_morris/morris.py b/temoa/extensions/method_of_morris/morris.py index 3b6841343..7de980326 100644 --- a/temoa/extensions/method_of_morris/morris.py +++ b/temoa/extensions/method_of_morris/morris.py @@ -5,18 +5,19 @@ from pyomo.dataportal import DataPortal from definitions import PROJECT_ROOT -from temoa.temoa_model import run_actions -from temoa.temoa_model.hybrid_loader import HybridLoader -from temoa.temoa_model.table_writer import TableWriter -from temoa.temoa_model.temoa_config import TemoaConfig +from temoa._internal import run_actions +from temoa._internal.hybrid_loader import HybridLoader +from temoa._internal.table_writer import TableWriter +from temoa.core.config import TemoaConfig start_time = time.time() -from joblib import Parallel, delayed import sqlite3 + +from joblib import Parallel, delayed from numpy import array from SALib.analyze import morris from SALib.sample.morris import sample -from SALib.util import read_param_file, compute_groups_matrix +from SALib.util import compute_groups_matrix, read_param_file seed = 42 diff --git a/temoa/extensions/method_of_morris/morris_evaluate.py b/temoa/extensions/method_of_morris/morris_evaluate.py index af75bdb6c..c105ce1af 100644 --- a/temoa/extensions/method_of_morris/morris_evaluate.py +++ b/temoa/extensions/method_of_morris/morris_evaluate.py @@ -27,6 +27,7 @@ This module contains the core "evaluation" function for Method Of Morris. It needs to be isolated (outside of class) to enable parallelization. """ + import logging import sqlite3 import sys @@ -34,9 +35,9 @@ from pyomo.dataportal import DataPortal -from temoa.temoa_model import run_actions -from temoa.temoa_model.table_writer import TableWriter -from temoa.temoa_model.temoa_config import TemoaConfig +from temoa._internal import run_actions +from temoa._internal.table_writer import TableWriter +from temoa.core.config import TemoaConfig def configure_worker_logger(log_queue, log_level): @@ -128,6 +129,6 @@ def evaluate(param_info, mm_sample, data, i, config: TemoaConfig, log_queue, log morris_objectives = [float(Y_OF), float(Y_CumulativeCO2)] logger.info('Finished MM evaluation # %d with OBJ value: %0.2f ', i + 1, Y_OF) if not config.silent: - sys.stdout.write(f'Completed MM run {i+1}\n') + sys.stdout.write(f'Completed MM run {i + 1}\n') sys.stdout.flush() return morris_objectives diff --git a/temoa/extensions/method_of_morris/morris_sequencer.py b/temoa/extensions/method_of_morris/morris_sequencer.py index 670f10769..b4bde836f 100644 --- a/temoa/extensions/method_of_morris/morris_sequencer.py +++ b/temoa/extensions/method_of_morris/morris_sequencer.py @@ -31,6 +31,7 @@ the joblib library """ + import csv import logging import multiprocessing @@ -40,17 +41,17 @@ from logging.handlers import QueueListener from pathlib import Path -from SALib.analyze import morris -from SALib.sample.morris import sample -from SALib.util import read_param_file, compute_groups_matrix from joblib import Parallel, delayed from numpy import array +from SALib.analyze import morris +from SALib.sample.morris import sample +from SALib.util import compute_groups_matrix, read_param_file from definitions import PROJECT_ROOT, get_OUTPUT_PATH +from temoa._internal.hybrid_loader import HybridLoader +from temoa._internal.table_writer import TableWriter +from temoa.core.config import TemoaConfig from temoa.extensions.method_of_morris.morris_evaluate import evaluate -from temoa.temoa_model.hybrid_loader import HybridLoader -from temoa.temoa_model.table_writer import TableWriter -from temoa.temoa_model.temoa_config import TemoaConfig logger = logging.getLogger(__name__) diff --git a/temoa/extensions/modeling_to_generate_alternatives/manager_factory.py b/temoa/extensions/modeling_to_generate_alternatives/manager_factory.py index 8416f3903..2fe260bd7 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/manager_factory.py +++ b/temoa/extensions/modeling_to_generate_alternatives/manager_factory.py @@ -25,14 +25,15 @@ Created on: 4/16/24 """ + import sqlite3 +from temoa.core.model import TemoaModel from temoa.extensions.modeling_to_generate_alternatives.mga_constants import MgaAxis, MgaWeighting from temoa.extensions.modeling_to_generate_alternatives.tech_activity_vector_manager import ( TechActivityVectorManager, ) from temoa.extensions.modeling_to_generate_alternatives.vector_manager import VectorManager -from temoa.temoa_model.temoa_model import TemoaModel def get_manager( diff --git a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py index d7f1d4c90..da45e2b07 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py +++ b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py @@ -26,6 +26,7 @@ The purpose of this module is to perform top-level control over an MGA model run """ + import logging import queue import sqlite3 @@ -42,18 +43,18 @@ from pyomo.dataportal import DataPortal from pyomo.opt import check_optimal_termination -from definitions import get_OUTPUT_PATH, PROJECT_ROOT +from definitions import PROJECT_ROOT, get_OUTPUT_PATH +from temoa._internal.hybrid_loader import HybridLoader +from temoa._internal.run_actions import build_instance +from temoa._internal.table_writer import TableWriter +from temoa._internal.temoa_rules import TotalCost_rule +from temoa.core.config import TemoaConfig +from temoa.core.model import TemoaModel from temoa.extensions.modeling_to_generate_alternatives.manager_factory import get_manager from temoa.extensions.modeling_to_generate_alternatives.mga_constants import MgaAxis, MgaWeighting from temoa.extensions.modeling_to_generate_alternatives.vector_manager import VectorManager from temoa.extensions.modeling_to_generate_alternatives.worker import Worker -from temoa.temoa_model.hybrid_loader import HybridLoader -from temoa.temoa_model.model_checking.pricing_check import price_checker -from temoa.temoa_model.run_actions import build_instance -from temoa.temoa_model.table_writer import TableWriter -from temoa.temoa_model.temoa_config import TemoaConfig -from temoa.temoa_model.temoa_model import TemoaModel -from temoa.temoa_model.temoa_rules import TotalCost_rule +from temoa.model_checking.pricing_check import price_checker logger = getLogger(__name__) diff --git a/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py b/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py index 8c23d8441..ec9ac323c 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py +++ b/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py @@ -25,6 +25,7 @@ Created on: 4/16/24 """ + import queue import sqlite3 from collections import defaultdict @@ -36,13 +37,13 @@ import numpy as np from matplotlib import pyplot as plt -from pyomo.core import Expression, Var, value, Objective, quicksum +from pyomo.core import Expression, Objective, Var, quicksum, value from definitions import get_OUTPUT_PATH +from temoa.core.model import TemoaModel from temoa.extensions.modeling_to_generate_alternatives.hull import Hull from temoa.extensions.modeling_to_generate_alternatives.mga_constants import MgaWeighting from temoa.extensions.modeling_to_generate_alternatives.vector_manager import VectorManager -from temoa.temoa_model.temoa_model import TemoaModel logger = getLogger(__name__) @@ -156,7 +157,7 @@ def random_input_vector_model(self) -> TemoaModel: var_vec = self.var_vector(new_model) coeffs = np.random.random(len(var_vec)) coeffs /= sum(coeffs) - obj_expr = quicksum(c * v for c, v in zip(coeffs, var_vec)) + obj_expr = quicksum(c * v for c, v in zip(coeffs, var_vec, strict=False)) new_model.obj = Objective(expr=obj_expr) return new_model @@ -259,7 +260,7 @@ def _make_basis_objective_vector(self, M: TemoaModel) -> Iterable[Expression] | # verify a unit vector err = abs(abs(sum(coeffs)) - 1) assert err < 1e-6, 'unit vector size error' - expr = sum(c * v for v, c in zip(vars, coeffs) if c != 0) + expr = sum(c * v for v, c in zip(vars, coeffs, strict=False) if c != 0) return expr def _next_objective_vector(self, M: TemoaModel) -> Expression | None: @@ -285,7 +286,7 @@ def _next_objective_vector(self, M: TemoaModel) -> Expression | None: obj_vars = self.var_vector(M) assert len(obj_vars) == len(coeffs) - return quicksum(c * v for v, c in zip(obj_vars, coeffs)) + return quicksum(c * v for v, c in zip(obj_vars, coeffs, strict=False)) def var_vector(self, M: TemoaModel) -> list[Var]: """Produce a properly sequenced array of variables from the current model for use in obj vector""" diff --git a/temoa/extensions/modeling_to_generate_alternatives/vector_manager.py b/temoa/extensions/modeling_to_generate_alternatives/vector_manager.py index 9284e11fa..2a761e9f4 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/vector_manager.py +++ b/temoa/extensions/modeling_to_generate_alternatives/vector_manager.py @@ -26,11 +26,12 @@ An ABC to serve as a framework for future Vector Managers """ + import sqlite3 from abc import ABC, abstractmethod -from collections.abc import Iterator, Iterable +from collections.abc import Iterable, Iterator -from temoa.temoa_model.temoa_model import TemoaModel +from temoa.core.model import TemoaModel class VectorManager(ABC): diff --git a/temoa/extensions/modeling_to_generate_alternatives/worker.py b/temoa/extensions/modeling_to_generate_alternatives/worker.py index 6632032bf..1c1ba999c 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/worker.py +++ b/temoa/extensions/modeling_to_generate_alternatives/worker.py @@ -27,6 +27,7 @@ Class to contain Workers that execute solves in separate processes """ + import logging.handlers from datetime import datetime from logging import getLogger @@ -35,7 +36,7 @@ from pyomo.opt import SolverFactory, SolverResults, check_optimal_termination -from temoa.temoa_model.temoa_model import TemoaModel +from temoa.core.model import TemoaModel verbose = False # for T/S or monitoring... diff --git a/temoa/extensions/monte_carlo/mc_run.py b/temoa/extensions/monte_carlo/mc_run.py index 33b2b6bab..aef841a0c 100644 --- a/temoa/extensions/monte_carlo/mc_run.py +++ b/temoa/extensions/monte_carlo/mc_run.py @@ -25,7 +25,8 @@ Created on: 11/9/24 """ -from collections import namedtuple, defaultdict + +from collections import defaultdict, namedtuple from collections.abc import Generator from itertools import product from logging import getLogger @@ -34,9 +35,9 @@ from pyomo.dataportal import DataPortal from definitions import PROJECT_ROOT -from temoa.temoa_model.hybrid_loader import HybridLoader -from temoa.temoa_model.temoa_config import TemoaConfig -from temoa.temoa_model.temoa_model import TemoaModel +from temoa._internal.hybrid_loader import HybridLoader +from temoa.core.config import TemoaConfig +from temoa.core.model import TemoaModel logger = getLogger(__name__) @@ -230,9 +231,9 @@ def prescreen_input_file(self): """ with open(self.settings_file, 'r') as f: header = f.readline().strip() - assert ( - header == 'run,param,index,mod,value,notes' - ), 'header should be: run,param,index,mod,value,notes' + assert header == 'run,param,index,mod,value,notes', ( + 'header should be: run,param,index,mod,value,notes' + ) current_run = -1 for idx, row in enumerate(f.readlines(), start=2): rd = self.tweak_factory.row_parser(idx, row) diff --git a/temoa/extensions/monte_carlo/mc_sequencer.py b/temoa/extensions/monte_carlo/mc_sequencer.py index 80cffaef6..5823284a7 100644 --- a/temoa/extensions/monte_carlo/mc_sequencer.py +++ b/temoa/extensions/monte_carlo/mc_sequencer.py @@ -27,6 +27,7 @@ A sequencer for Monte Carlo Runs . """ + import logging import queue import sqlite3 @@ -40,12 +41,12 @@ from pyomo.dataportal import DataPortal from definitions import PROJECT_ROOT, get_OUTPUT_PATH +from temoa._internal.data_brick import DataBrick +from temoa._internal.hybrid_loader import HybridLoader +from temoa._internal.table_writer import TableWriter +from temoa.core.config import TemoaConfig from temoa.extensions.monte_carlo.mc_run import MCRunFactory from temoa.extensions.monte_carlo.mc_worker import MCWorker -from temoa.temoa_model.data_brick import DataBrick -from temoa.temoa_model.hybrid_loader import HybridLoader -from temoa.temoa_model.table_writer import TableWriter -from temoa.temoa_model.temoa_config import TemoaConfig logger = getLogger(__name__) diff --git a/temoa/extensions/monte_carlo/mc_worker.py b/temoa/extensions/monte_carlo/mc_worker.py index 73cbf2496..e4f6d458f 100644 --- a/temoa/extensions/monte_carlo/mc_worker.py +++ b/temoa/extensions/monte_carlo/mc_worker.py @@ -32,6 +32,7 @@ ingest DataPortal objects to make new models. The MGA will (in future) likely just take in new obj functions """ + import logging.handlers from datetime import datetime from logging import getLogger @@ -41,8 +42,8 @@ from pyomo.dataportal import DataPortal from pyomo.opt import SolverFactory, SolverResults, check_optimal_termination -from temoa.temoa_model.data_brick import DataBrick, data_brick_factory -from temoa.temoa_model.temoa_model import TemoaModel +from temoa._internal.data_brick import DataBrick, data_brick_factory +from temoa.core.model import TemoaModel verbose = False # for T/S or monitoring... diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index 65d8cdbee..faf467926 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -35,15 +35,15 @@ from sys import stderr as SE import definitions +from temoa._internal import run_actions +from temoa._internal.hybrid_loader import HybridLoader +from temoa._internal.table_writer import TableWriter +from temoa.core.config import TemoaConfig +from temoa.core.model import TemoaModel from temoa.data_processing.DB_to_Excel import make_excel from temoa.extensions.myopic.myopic_index import MyopicIndex from temoa.extensions.myopic.myopic_progress_mapper import MyopicProgressMapper -from temoa.temoa_model import run_actions -from temoa.temoa_model.hybrid_loader import HybridLoader -from temoa.temoa_model.model_checking.pricing_check import price_checker -from temoa.temoa_model.table_writer import TableWriter -from temoa.temoa_model.temoa_config import TemoaConfig -from temoa.temoa_model.temoa_model import TemoaModel +from temoa.model_checking.pricing_check import price_checker logger = logging.getLogger(__name__) @@ -281,7 +281,9 @@ def start(self): last_base_year = idx.base_year # update # delete anything in the OutputObjective table, it is nonsensical... - self.output_con.execute(f'DELETE FROM OutputObjective WHERE scenario == "{self.config.scenario}"') + self.output_con.execute( + f'DELETE FROM OutputObjective WHERE scenario == "{self.config.scenario}"' + ) self.output_con.commit() # 11. Compact the db... lots of writes/deletes leads to bloat @@ -475,9 +477,11 @@ def characterize_run(self, future_periods: list[int] | None = None) -> None: # check that we have enough periods to do myopic run # 2 iterations, excluding end year, will be via shortened depth, if reqd. - if len(future_periods) < self.view_depth+1: + if len(future_periods) < self.view_depth + 1: logger.error( - 'Not enough future years to run myopic mode. Need %d including end year. Got %d.', self.view_depth+1, len(future_periods) + 'Not enough future years to run myopic mode. Need %d including end year. Got %d.', + self.view_depth + 1, + len(future_periods), ) sys.exit(-1) self.optimization_periods = future_periods.copy() diff --git a/temoa/extensions/single_vector_mga/output_summary.py b/temoa/extensions/single_vector_mga/output_summary.py index 2caa33f9d..ef54e9172 100644 --- a/temoa/extensions/single_vector_mga/output_summary.py +++ b/temoa/extensions/single_vector_mga/output_summary.py @@ -26,12 +26,13 @@ A tabular summation of the results from an SVMGA run """ + import sqlite3 from sqlite3 import Connection import tabulate -from temoa.temoa_model.temoa_config import TemoaConfig +from temoa.core.config import TemoaConfig def summarize(config: TemoaConfig, orig_cost: float, option_cost: float) -> None: diff --git a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py index 611e46c1e..5fab60d10 100644 --- a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py +++ b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py @@ -28,23 +28,24 @@ The "single vector" distinguishes it from "regular" MGA in that this only uses 1 extra solve to look in one particular vector direction, characterized by keywords from an associated config file """ + import logging import sqlite3 import sys from collections.abc import Iterable -from pyomo.core import value, Constraint, Expression, Objective +from pyomo.core import Constraint, Expression, Objective, value from pyomo.dataportal import DataPortal from pyomo.opt import check_optimal_termination +from temoa._internal.hybrid_loader import HybridLoader +from temoa._internal.run_actions import build_instance, handle_results, save_lp, solve_instance +from temoa._internal.table_writer import TableWriter +from temoa._internal.temoa_rules import TotalCost_rule +from temoa.core.config import TemoaConfig +from temoa.core.model import TemoaModel from temoa.extensions.single_vector_mga.output_summary import summarize -from temoa.temoa_model.hybrid_loader import HybridLoader -from temoa.temoa_model.model_checking.pricing_check import price_checker -from temoa.temoa_model.run_actions import build_instance, solve_instance, handle_results, save_lp -from temoa.temoa_model.table_writer import TableWriter -from temoa.temoa_model.temoa_config import TemoaConfig -from temoa.temoa_model.temoa_model import TemoaModel -from temoa.temoa_model.temoa_rules import TotalCost_rule +from temoa.model_checking.pricing_check import price_checker logger = logging.getLogger(__name__) @@ -198,7 +199,9 @@ def flow_idxs_from_eac_idx(M: TemoaModel, reitvo: tuple) -> tuple[list[tuple], . for membership later """ r, _, i, t, v, o = reitvo - psd_set = [(p, s, d) for p in M.time_optimize for s in M.TimeSeason[p] for d in M.time_of_day] + psd_set = [ + (p, s, d) for p in M.time_optimize for s in M.TimeSeason[p] for d in M.time_of_day + ] flow_idxs = [(r, *psd, i, t, v, o) for psd in psd_set] annual_flow_idxs = [(r, p, i, t, v, o) for p in M.time_optimize] diff --git a/temoa/temoa_model/model_checking/__init__.py b/temoa/model_checking/__init__.py similarity index 100% rename from temoa/temoa_model/model_checking/__init__.py rename to temoa/model_checking/__init__.py diff --git a/temoa/temoa_model/model_checking/commodity_graph.py b/temoa/model_checking/commodity_graph.py similarity index 91% rename from temoa/temoa_model/model_checking/commodity_graph.py rename to temoa/model_checking/commodity_graph.py index 57de1de05..662cfb30b 100644 --- a/temoa/temoa_model/model_checking/commodity_graph.py +++ b/temoa/model_checking/commodity_graph.py @@ -2,6 +2,7 @@ A quick & dirty graph of the commodity network for troubleshooting purposes. Future development may enhance this quite a bit.... lots of opportunity! """ + import logging from pathlib import Path from typing import Iterable @@ -9,8 +10,8 @@ import gravis as gv import networkx as nx -from temoa.temoa_model.model_checking.network_model_data import NetworkModelData, Tech -from temoa.temoa_model.temoa_config import TemoaConfig +from temoa.core.config import TemoaConfig +from temoa.model_checking.network_model_data import NetworkModelData, Tech """ Tools for Energy Model Optimization and Analysis (Temoa): @@ -87,12 +88,15 @@ def generate_graph( (tech.ic, tech.name, tech.oc) for tech in network_data.available_techs[region, period] } cap_edges = { - (tech.ic, tech.name, tech.oc) for tech in network_data.available_techs[region, period] - if tech.name in ('Construction','EndOfLife') + (tech.ic, tech.name, tech.oc) + for tech in network_data.available_techs[region, period] + if tech.name in ('Construction', 'EndOfLife') } exc_edges = { - (tech.ic, tech.name, tech.oc) for tech in network_data.available_techs[region, period] - if tech.ic in network_data.exchange_commodities or tech.oc in network_data.exchange_commodities + (tech.ic, tech.name, tech.oc) + for tech in network_data.available_techs[region, period] + if tech.ic in network_data.exchange_commodities + or tech.oc in network_data.exchange_commodities } # troll through the tech_data and label things of low importance for edge in all_edges: @@ -142,7 +146,7 @@ def generate_graph( # This is just an exchange tech loop. Ignore. # These are labelled in the graph as {base_tech} ({other region}) # so we split on ' (' to compare the base techs - raise ValueError("Just an exchange tech") + raise ValueError('Just an exchange tech') res += f'{node} --> ' last_node = node except ValueError: @@ -156,7 +160,7 @@ def generate_graph( period, res, ) - + except nx.NetworkXError as e: logger.warning('NetworkX exception encountered: %s. Loop evaluation NOT performed.', e) if config.plot_commodity_network: @@ -221,8 +225,15 @@ def make_nx_graph(connections, edge_colors, edge_weights, layer_map) -> nx.Multi :return: a nx MultiDiGraph """ dg = nx.MultiDiGraph() # networkx multi(edge) directed graph - layer_colors = {1: 'limegreen', 2: 'violet', 3: 'darkorange', 4: 'darkgreen', 5: 'darkblue', 6: 'darkred'} - node_size = {1: 50, 2: 15, 3: 30, 4:20, 5:20, 6:30} + layer_colors = { + 1: 'limegreen', + 2: 'violet', + 3: 'darkorange', + 4: 'darkgreen', + 5: 'darkblue', + 6: 'darkred', + } + node_size = {1: 50, 2: 15, 3: 30, 4: 20, 5: 20, 6: 30} for ic, tech, oc in connections: dg.add_node( ic, diff --git a/temoa/temoa_model/model_checking/commodity_network.py b/temoa/model_checking/commodity_network.py similarity index 99% rename from temoa/temoa_model/model_checking/commodity_network.py rename to temoa/model_checking/commodity_network.py index 51863c326..67a8da368 100644 --- a/temoa/temoa_model/model_checking/commodity_network.py +++ b/temoa/model_checking/commodity_network.py @@ -30,7 +30,7 @@ from itertools import chain from logging import getLogger -from temoa.temoa_model.model_checking.network_model_data import NetworkModelData, Tech +from temoa.model_checking.network_model_data import NetworkModelData, Tech logger = getLogger(__name__) @@ -217,7 +217,8 @@ def analyze_network(self): # dev note: send a copy of connections... # it is consumed by the function. (easier than managing it in the recursion) discovered_sources, demand_side_connections = _visited_dfs( - self.model_data.demand_commodities[self.region, self.period] | self.model_data.waste_commodities[self.region, self.period], + self.model_data.demand_commodities[self.region, self.period] + | self.model_data.waste_commodities[self.region, self.period], self.model_data.source_commodities[self.region, self.period], self.connections.copy(), ) diff --git a/temoa/temoa_model/model_checking/commodity_network_manager.py b/temoa/model_checking/commodity_network_manager.py similarity index 96% rename from temoa/temoa_model/model_checking/commodity_network_manager.py rename to temoa/model_checking/commodity_network_manager.py index 2bfd2e392..094c4f617 100644 --- a/temoa/temoa_model/model_checking/commodity_network_manager.py +++ b/temoa/model_checking/commodity_network_manager.py @@ -34,11 +34,11 @@ from logging import getLogger from typing import Iterable -from temoa.temoa_model.model_checking.commodity_graph import generate_graph -from temoa.temoa_model.model_checking.commodity_network import CommodityNetwork -from temoa.temoa_model.model_checking.element_checker import ViableSet -from temoa.temoa_model.model_checking.network_model_data import NetworkModelData, Tech -from temoa.temoa_model.temoa_config import TemoaConfig +from temoa.core.config import TemoaConfig +from temoa.model_checking.commodity_graph import generate_graph +from temoa.model_checking.commodity_network import CommodityNetwork +from temoa.model_checking.element_checker import ViableSet +from temoa.model_checking.network_model_data import NetworkModelData, Tech logger = getLogger(__name__) diff --git a/temoa/temoa_model/model_checking/element_checker.py b/temoa/model_checking/element_checker.py similarity index 99% rename from temoa/temoa_model/model_checking/element_checker.py rename to temoa/model_checking/element_checker.py index 30f129b4b..d9a5865ee 100644 --- a/temoa/temoa_model/model_checking/element_checker.py +++ b/temoa/model_checking/element_checker.py @@ -29,6 +29,7 @@ class to hold members of "validation sets" used by loader to validate elements a any extra validation information in one instance. """ + import re from collections.abc import Iterable, Sequence from operator import itemgetter diff --git a/temoa/temoa_model/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py similarity index 93% rename from temoa/temoa_model/model_checking/network_model_data.py rename to temoa/model_checking/network_model_data.py index b2efebda6..3af5b9064 100644 --- a/temoa/temoa_model/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -34,13 +34,13 @@ import sqlite3 from collections import defaultdict, namedtuple from itertools import chain -from typing import Self, Any +from typing import Any, Self import deprecated from pyomo.core import ConcreteModel +from temoa.core.model import TemoaModel from temoa.extensions.myopic.myopic_index import MyopicIndex -from temoa.temoa_model.temoa_model import TemoaModel Tech = namedtuple('Tech', ['region', 'ic', 'name', 'vintage', 'oc']) LinkedTech = namedtuple('LinkedTech', ['region', 'driver', 'emission', 'driven']) @@ -58,7 +58,9 @@ def __init__(self, **kwargs): self.waste_commodities: set[str] = kwargs.get('waste_commodities') self.capacity_commodities: set[str] = kwargs.get('capacity_commodities') self.exchange_commodities: set[str] = kwargs.get('exchange_commodities') - self.source_commodities: dict[tuple[str, int | str], set[str]] = kwargs.get('source_commodities') + self.source_commodities: dict[tuple[str, int | str], set[str]] = kwargs.get( + 'source_commodities' + ) self.physical_commodities: set[str] = kwargs.get('all_commodities') # dict of (region, period): {Tech} self._available_techs: dict[tuple[str, int | str], set[Tech]] = kwargs.get( @@ -190,9 +192,11 @@ def _build_from_db( pass raw = cur.execute('SELECT period FROM TimePeriod').fetchall() periods = [p[0] for p in sorted(raw)] - period_length = {periods[i]: periods[i+1] - periods[i] for i in range(len(periods)-1)} + period_length = {periods[i]: periods[i + 1] - periods[i] for i in range(len(periods) - 1)} periods = periods[:-1] - raw = cur.execute("SELECT name FROM main.Commodity WHERE flag LIKE '%p%' OR flag = 's' OR flag LIKE '%a%'").fetchall() + raw = cur.execute( + "SELECT name FROM main.Commodity WHERE flag LIKE '%p%' OR flag = 's' OR flag LIKE '%a%'" + ).fetchall() res.physical_commodities = {c[0] for c in raw} res.capacity_commodities = set() res.exchange_commodities = set() @@ -243,7 +247,7 @@ def _build_from_db( raw = cur.execute(query).fetchall() # need to exclude the final year which is a non-demand year and should have no tech data # This ensures that the periods in this will match the periods in the hybrid loader. - + # filter further if myopic if myopic_index: periods = { @@ -258,8 +262,8 @@ def _build_from_db( if v <= p < v + lifetime: if '-' in r: r1, r2 = r.split('-') - source = f"{ic} ({r1})" - destination = f"{oc} ({r2})" + source = f'{ic} ({r1})' + destination = f'{oc} ({r2})' techs[r2, p].add(Tech(r2, source, tech, v, oc)) techs[r1, p].add(Tech(r1, ic, tech, v, destination)) techs[r, p].add(Tech(r, ic, tech, v, oc)) @@ -278,17 +282,20 @@ def _build_from_db( waste_dict[r, p].add(oc) # End of life output - if any(( - p <= v+lifetime < p + period_length[p], # natural eol this period - tech in tech_retire and v < p <= v+lifetime - period_length[p], # allowed early retirement - tech in tech_survival_curve and v <= p <= v+lifetime - )): + if any( + ( + p <= v + lifetime < p + period_length[p], # natural eol this period + tech in tech_retire + and v < p <= v + lifetime - period_length[p], # allowed early retirement + tech in tech_survival_curve and v <= p <= v + lifetime, + ) + ): try: raw_eol = cur.execute( 'SELECT region, tech, vintage, output_comm FROM EndOfLifeOutput ' f' WHERE region == "{r}" AND tech == "{tech}" AND vintage == {v}' ).fetchall() - + for _r, _tech, _v, _oc in raw_eol: techs[_r, p].add(Tech(_r, _tech, 'EndOfLife', _v, _oc)) source_dict[_r, p].add(_tech) @@ -302,7 +309,9 @@ def _build_from_db( # Construction input try: - raw = cur.execute('SELECT region, input_comm, tech, vintage FROM ConstructionInput').fetchall() + raw = cur.execute( + 'SELECT region, input_comm, tech, vintage FROM ConstructionInput' + ).fetchall() for r, ic, tech, v in raw: techs[r, v].add(Tech(r, ic, 'Construction', v, tech)) demand_dict[r, v].add(tech) diff --git a/temoa/temoa_model/model_checking/pricing_check.py b/temoa/model_checking/pricing_check.py similarity index 99% rename from temoa/temoa_model/model_checking/pricing_check.py rename to temoa/model_checking/pricing_check.py index 07f064113..dee54fd14 100644 --- a/temoa/temoa_model/model_checking/pricing_check.py +++ b/temoa/model_checking/pricing_check.py @@ -43,10 +43,11 @@ from collections import defaultdict from logging import getLogger from typing import TYPE_CHECKING + from pyomo.environ import value if TYPE_CHECKING: - from temoa.temoa_model.temoa_model import TemoaModel + from temoa.core.model import TemoaModel logger = getLogger(__name__) diff --git a/temoa/temoa_model/model_checking/validators.py b/temoa/model_checking/validators.py similarity index 97% rename from temoa/temoa_model/model_checking/validators.py rename to temoa/model_checking/validators.py index b5ab6a8a8..e05099505 100644 --- a/temoa/temoa_model/model_checking/validators.py +++ b/temoa/model_checking/validators.py @@ -31,10 +31,10 @@ from typing import TYPE_CHECKING import deprecated -from pyomo.environ import NonNegativeReals, value +from pyomo.environ import NonNegativeReals if TYPE_CHECKING: - from temoa.temoa_model.temoa_model import TemoaModel + from temoa.core.model import TemoaModel logger = getLogger(__name__) @@ -327,10 +327,10 @@ def validate_tech_sets(M: 'TemoaModel'): check_no_intersection(M.tech_annual, M.tech_curtailment), check_no_intersection(M.tech_curtailment, M.tech_flex), check_no_intersection(M.tech_all, M.tech_group_names), - check_no_intersection(M.tech_uncap, M.tech_reserve) + check_no_intersection(M.tech_uncap, M.tech_reserve), ) ): - raise ValueError("Technology sets failed to validate. Check log file for details.") + raise ValueError('Technology sets failed to validate. Check log file for details.') def check_no_intersection(set_one, set_two): @@ -361,4 +361,4 @@ def validate_tech_split(M: 'TemoaModel', val, r, p, c, t): def validate_0to1(M: 'TemoaModel', val, *args): - return 0.0 <= val <= 1.0 \ No newline at end of file + return 0.0 <= val <= 1.0 diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 81e554fb9..498e28baa 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -20,33 +20,34 @@ in LICENSE.txt. Users uncompressing this from an archive may not have received this license file. If not, see . """ + import logging from pyomo.core import BuildCheck from pyomo.environ import ( - Any, - NonNegativeReals, - Integers, AbstractModel, + Any, BuildAction, - Param, + Integers, + NonNegativeReals, Objective, + Param, minimize, ) -from temoa.temoa_model.model_checking.validators import ( - validate_linked_tech, +from temoa._internal.temoa_initialize import * +from temoa._internal.temoa_rules import * +from temoa.model_checking.validators import ( + no_slash_or_pipe, region_check, + region_group_check, # validate_CapacityFactorProcess, validate_0to1, - region_group_check, validate_Efficiency, - validate_tech_sets, - no_slash_or_pipe, + validate_linked_tech, validate_ReserveMargin, + validate_tech_sets, ) -from temoa.temoa_model.temoa_initialize import * -from temoa.temoa_model.temoa_rules import * logger = logging.getLogger(__name__) @@ -70,8 +71,6 @@ def __init__(M, *args, **kwargs): # (not formal model elements) # ################################################ - - # Dev Note: The triple-quotes UNDER the items below pop up as dox in most IDEs M.processInputs = dict() M.processOutputs = dict() @@ -97,20 +96,28 @@ def __init__(M, *args, **kwargs): M.newCapacity_rtv = None M.activeCapacityAvailable_rpt = None M.activeCapacityAvailable_rptv = None - M.groupRegionActiveFlow_rpt = None # Set of valid group-region, period, tech indices - M.commodityBalance_rpc = None # Set of valid region-period-commodity indices to balance + M.groupRegionActiveFlow_rpt = None # Set of valid group-region, period, tech indices + M.commodityBalance_rpc = None # Set of valid region-period-commodity indices to balance M.commodityDStreamProcess = dict() # The downstream process of a commodity during a period M.commodityUStreamProcess = dict() # The upstream process of a commodity during a period - M.capacityConsumptionTechs = dict() # New capacity consuming a commodity during a period [r,p,c] -> t - M.retirementProductionProcesses = dict() # Retired capacity producing a commodity during a period [r,p,c] -> t,v + M.capacityConsumptionTechs = ( + dict() + ) # New capacity consuming a commodity during a period [r,p,c] -> t + M.retirementProductionProcesses = ( + dict() + ) # Retired capacity producing a commodity during a period [r,p,c] -> t,v M.processInputsByOutput = dict() M.processOutputsByInput = dict() M.processTechs = dict() M.processReservePeriods = dict() - M.processPeriods = dict() # {(r, t, v): set(p)} - M.retirementPeriods = dict() # {(r, t, v): set(p)} periods in which a process can economically or naturally retire + M.processPeriods = dict() # {(r, t, v): set(p)} + M.retirementPeriods = ( + dict() + ) # {(r, t, v): set(p)} periods in which a process can economically or naturally retire M.processVintages = dict() - M.survivalCurvePeriods: dict[tuple, set] = dict() # {(r, t, v): set(p)} periods for which the process has a defined survival fraction + M.survivalCurvePeriods: dict[tuple, set] = ( + dict() + ) # {(r, t, v): set(p)} periods for which the process has a defined survival fraction """current available (within lifespan) vintages {(r, p, t) : set(v)}""" M.baseloadVintages = dict() @@ -127,19 +134,29 @@ def __init__(M, *args, **kwargs): M.importRegions = dict() # These establish time sequencing - M.time_next = dict() # {(p, s, d): (s_next, d_next)} sequence of following time slices - M.time_next_sequential = dict() # {(p, s_seq): (s_seq_next)} next virtual storage season - M.sequential_to_season = dict() # {(p, s_seq): (s)} season matching this virtual storage season + M.time_next = dict() # {(p, s, d): (s_next, d_next)} sequence of following time slices + M.time_next_sequential = dict() # {(p, s_seq): (s_seq_next)} next virtual storage season + M.sequential_to_season = ( + dict() + ) # {(p, s_seq): (s)} season matching this virtual storage season ################################################ # Switching Sets # # (to avoid slow searches in initialisation) # ################################################ - M.isEfficiencyVariable: dict[tuple, bool] = dict() # {(r, p, i, t, v, o): bool} which efficiencies have variable indexing - M.isCapacityFactorProcess: dict[tuple, bool] = dict() # {(r, p, t, v): bool} which capacity factors have have period-vintage indexing - M.isSeasonalStorage: dict[tuple, bool] = dict() # {t: bool} whether a storage tech is seasonal storage - M.isSurvivalCurveProcess: dict[tuple, bool] = dict() # {(r, t, v): bool} whether a process uses survival curves. + M.isEfficiencyVariable: dict[tuple, bool] = ( + dict() + ) # {(r, p, i, t, v, o): bool} which efficiencies have variable indexing + M.isCapacityFactorProcess: dict[tuple, bool] = ( + dict() + ) # {(r, p, t, v): bool} which capacity factors have have period-vintage indexing + M.isSeasonalStorage: dict[tuple, bool] = ( + dict() + ) # {t: bool} whether a storage tech is seasonal storage + M.isSurvivalCurveProcess: dict[tuple, bool] = ( + dict() + ) # {(r, t, v): bool} whether a process uses survival curves. ################################################ # Model Sets # @@ -168,7 +185,9 @@ def __init__(M, *args, **kwargs): M.time_of_day = Set(ordered=True, validate=no_slash_or_pipe) # This is just to get the TimeStorageSeason table sequentially. There must be a better way but this works for now - M.ordered_season_sequential = Set(dimen=3, within=M.time_optimize * M.time_season_sequential * M.time_season, ordered=True) + M.ordered_season_sequential = Set( + dimen=3, within=M.time_optimize * M.time_season_sequential * M.time_season, ordered=True + ) # Define regions M.regions = Set(validate=region_check) @@ -180,7 +199,9 @@ def __init__(M, *args, **kwargs): # Define technology-related sets # M.tech_resource = Set() # not actually used by anything M.tech_production = Set() - M.tech_all = Set(initialize=M.tech_production, validate=no_slash_or_pipe) # was M.tech_resource | M.tech_production + M.tech_all = Set( + initialize=M.tech_production, validate=no_slash_or_pipe + ) # was M.tech_resource | M.tech_production M.tech_baseload = Set(within=M.tech_all) M.tech_annual = Set(within=M.tech_all) M.tech_demand = Set(within=M.tech_all) @@ -216,7 +237,7 @@ def __init__(M, *args, **kwargs): # process, which is currently incapable of reducing initializations on retirements. # Note2: I think this has been fixed but I can't tell what the problem was. Suspect # it was the old StorageInit constraint - M.tech_retirement = Set(within=M.tech_with_capacity)# - M.tech_storage) + M.tech_retirement = Set(within=M.tech_with_capacity) # - M.tech_storage) M.validate_techs = BuildAction(rule=validate_tech_sets) @@ -228,7 +249,9 @@ def __init__(M, *args, **kwargs): M.commodity_flex = Set(within=M.commodity_physical) M.commodity_source = Set(within=M.commodity_physical) M.commodity_annual = Set(within=M.commodity_physical) - M.commodity_carrier = Set(initialize=M.commodity_physical | M.commodity_demand | M.commodity_waste) + M.commodity_carrier = Set( + initialize=M.commodity_physical | M.commodity_demand | M.commodity_waste + ) M.commodity_all = Set( initialize=M.commodity_carrier | M.commodity_emissions, validate=no_slash_or_pipe ) @@ -262,8 +285,10 @@ def __init__(M, *args, **kwargs): M.PeriodLength = Param(M.time_optimize, initialize=ParamPeriodLength) M.SegFrac = Param(M.time_optimize, M.time_season, M.time_of_day) M.validate_SegFrac = BuildAction(rule=validate_SegFrac) - M.TimeSequencing = Set() # How do states carry between time segments? - M.TimeNext = Set(ordered=True) # This is just to get data from the table. Hidden feature and usually not used + M.TimeSequencing = Set() # How do states carry between time segments? + M.TimeNext = Set( + ordered=True + ) # This is just to get data from the table. Hidden feature and usually not used M.validate_TimeNext = BuildAction(rule=validate_TimeNext) # Define demand- and resource-related parameters @@ -278,12 +303,10 @@ def __init__(M, *args, **kwargs): M.time_of_day, M.commodity_demand, mutable=True, - default=0 + default=0, ) - M.DemandConstraint_rpc = Set( - within=M.regions * M.time_optimize * M.commodity_demand - ) + M.DemandConstraint_rpc = Set(within=M.regions * M.time_optimize * M.commodity_demand) M.Demand = Param(M.DemandConstraint_rpc) # Dev Note: This parameter is currently NOT implemented. Preserved for later refactoring @@ -304,9 +327,13 @@ def __init__(M, *args, **kwargs): # ) # devnote: need these here or CheckEfficiencyIndices may flag these commodities as unused - M.ConstructionInput = Param(M.regions, M.commodity_physical, M.tech_with_capacity, M.vintage_optimize) - M.EndOfLifeOutput = Param(M.regions, M.tech_with_capacity, M.vintage_all, M.commodity_carrier) - + M.ConstructionInput = Param( + M.regions, M.commodity_physical, M.tech_with_capacity, M.vintage_optimize + ) + M.EndOfLifeOutput = Param( + M.regions, M.tech_with_capacity, M.vintage_all, M.commodity_carrier + ) + M.Efficiency = Param( M.regionalIndices, M.commodity_physical, @@ -345,7 +372,7 @@ def __init__(M, *args, **kwargs): M.vintage_all, default=get_default_survival, validate=validate_0to1, - mutable=True + mutable=True, ) M.Create_SurvivalCurve = BuildAction(rule=CreateSurvivalCurve) @@ -357,16 +384,46 @@ def __init__(M, *args, **kwargs): M.LoanLifetimeProcess = Param(M.LoanLifetimeProcess_rtv, default=get_loan_life) - M.LimitTechInputSplit = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all, M.operator, validate=validate_0to1) - M.LimitTechInputSplitAnnual = Param(M.regions, M.time_optimize, M.commodity_physical, M.tech_all, M.operator, validate=validate_0to1) - - M.LimitTechOutputSplit = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier, M.operator, validate=validate_0to1) - M.LimitTechOutputSplitAnnual = Param(M.regions, M.time_optimize, M.tech_all, M.commodity_carrier, M.operator, validate=validate_0to1) + M.LimitTechInputSplit = Param( + M.regions, + M.time_optimize, + M.commodity_physical, + M.tech_all, + M.operator, + validate=validate_0to1, + ) + M.LimitTechInputSplitAnnual = Param( + M.regions, + M.time_optimize, + M.commodity_physical, + M.tech_all, + M.operator, + validate=validate_0to1, + ) + + M.LimitTechOutputSplit = Param( + M.regions, + M.time_optimize, + M.tech_all, + M.commodity_carrier, + M.operator, + validate=validate_0to1, + ) + M.LimitTechOutputSplitAnnual = Param( + M.regions, + M.time_optimize, + M.tech_all, + M.commodity_carrier, + M.operator, + validate=validate_0to1, + ) M.RenewablePortfolioStandardConstraint_rpg = Set( within=M.regions * M.time_optimize * M.tech_group_names ) - M.RenewablePortfolioStandard = Param(M.RenewablePortfolioStandardConstraint_rpg, validate=validate_0to1) + M.RenewablePortfolioStandard = Param( + M.RenewablePortfolioStandardConstraint_rpg, validate=validate_0to1 + ) # These need to come before validate_SeasonSequential M.RampUpHourly = Param(M.regions, M.tech_upramping, validate=validate_0to1) @@ -375,7 +432,9 @@ def __init__(M, *args, **kwargs): # Set up representation of time M.DaysPerPeriod = Param() M.SegFracPerSeason = Param(M.time_optimize, M.time_season, initialize=SegFracPerSeason_rule) - M.TimeSeasonSequential = Param(M.time_optimize, M.time_season_sequential, M.time_season, mutable=True) + M.TimeSeasonSequential = Param( + M.time_optimize, M.time_season_sequential, M.time_season, mutable=True + ) M.validate_SeasonSequential = BuildAction(rule=CreateTimeSeasonSequential) M.Create_TimeSequence = BuildAction(rule=CreateTimeSequence) @@ -399,7 +458,7 @@ def __init__(M, *args, **kwargs): M.vintage_all, # validate=validate_CapacityFactorProcess, # opting for a quicker validation, just 0->1 validate=validate_0to1, - default=get_default_capacity_factor, # surprisingly slow but only called if a value is missing + default=get_default_capacity_factor, # surprisingly slow but only called if a value is missing ) M.CapacityConstraint_rpsdtv = Set(dimen=6, initialize=CapacityConstraintIndices) @@ -422,9 +481,7 @@ def __init__(M, *args, **kwargs): M.CostVariable_rptv = Set(dimen=4, initialize=CostVariableIndices) M.CostVariable = Param(M.CostVariable_rptv) - M.CostEmission_rpe = Set( - within=M.regions * M.time_optimize * M.commodity_emissions - ) + M.CostEmission_rpe = Set(within=M.regions * M.time_optimize * M.commodity_emissions) M.CostEmission = Param(M.CostEmission_rpe) # devnote: no longer used @@ -444,7 +501,9 @@ def __init__(M, *args, **kwargs): ) M.LimitNewCapacity = Param(M.LimitNewCapacityConstraint_rpt) - M.LimitResourceConstraint_rt = Set(within=M.regionalGlobalIndices * M.tech_or_group * M.operator) + M.LimitResourceConstraint_rt = Set( + within=M.regionalGlobalIndices * M.tech_or_group * M.operator + ) M.LimitResource = Param(M.LimitResourceConstraint_rt) M.LimitActivityConstraint_rpt = Set( @@ -453,21 +512,45 @@ def __init__(M, *args, **kwargs): M.LimitActivity = Param(M.LimitActivityConstraint_rpt) M.LimitSeasonalCapacityFactorConstraint_rpst = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.time_season * M.tech_all * M.operator + within=M.regionalGlobalIndices + * M.time_optimize + * M.time_season + * M.tech_all + * M.operator + ) + M.LimitSeasonalCapacityFactor = Param( + M.LimitSeasonalCapacityFactorConstraint_rpst, validate=validate_0to1 ) - M.LimitSeasonalCapacityFactor = Param(M.LimitSeasonalCapacityFactorConstraint_rpst, validate=validate_0to1) M.LimitAnnualCapacityFactorConstraint_rpto = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_all * M.commodity_carrier * M.operator + within=M.regionalGlobalIndices + * M.time_optimize + * M.tech_all + * M.commodity_carrier + * M.operator + ) + M.LimitAnnualCapacityFactor = Param( + M.LimitAnnualCapacityFactorConstraint_rpto, validate=validate_0to1 + ) + + M.LimitGrowthCapacity = Param( + M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any + ) + M.LimitDegrowthCapacity = Param( + M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any + ) + M.LimitGrowthNewCapacity = Param( + M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any + ) + M.LimitDegrowthNewCapacity = Param( + M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any + ) + M.LimitGrowthNewCapacityDelta = Param( + M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any + ) + M.LimitDegrowthNewCapacityDelta = Param( + M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any ) - M.LimitAnnualCapacityFactor = Param(M.LimitAnnualCapacityFactorConstraint_rpto, validate=validate_0to1) - - M.LimitGrowthCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any) - M.LimitDegrowthCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any) - M.LimitGrowthNewCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any) - M.LimitDegrowthNewCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any) - M.LimitGrowthNewCapacityDelta = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any) - M.LimitDegrowthNewCapacityDelta = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any) M.LimitEmissionConstraint_rpe = Set( within=M.regionalGlobalIndices * M.time_optimize * M.commodity_emissions * M.operator @@ -493,18 +576,36 @@ def __init__(M, *args, **kwargs): # M.LimitNewCapacityGroup = Param(M.LimitNewCapacityGroupConstraint_rpg) # M.GroupShareIndices = Set(dimen=5, initialize=GroupShareIndices) # doesn't feel worth it - M.LimitCapacityShareConstraint_rpgg = Set(within=M.regionalGlobalIndices * M.time_optimize * M.tech_or_group * M.tech_or_group * M.operator) + M.LimitCapacityShareConstraint_rpgg = Set( + within=M.regionalGlobalIndices + * M.time_optimize + * M.tech_or_group + * M.tech_or_group + * M.operator + ) M.LimitCapacityShare = Param(M.LimitCapacityShareConstraint_rpgg) - M.LimitActivityShareConstraint_rpgg = Set(within=M.regionalGlobalIndices * M.time_optimize * M.tech_or_group * M.tech_or_group * M.operator) + M.LimitActivityShareConstraint_rpgg = Set( + within=M.regionalGlobalIndices + * M.time_optimize + * M.tech_or_group + * M.tech_or_group + * M.operator + ) M.LimitActivityShare = Param(M.LimitActivityShareConstraint_rpgg) - M.LimitNewCapacityShareConstraint_rpgg = Set(within=M.regionalGlobalIndices * M.time_optimize * M.tech_or_group * M.tech_or_group * M.operator) + M.LimitNewCapacityShareConstraint_rpgg = Set( + within=M.regionalGlobalIndices + * M.time_optimize + * M.tech_or_group + * M.tech_or_group + * M.operator + ) M.LimitNewCapacityShare = Param(M.LimitNewCapacityShareConstraint_rpgg) # devnote: deprecated when generalising tech/group columns in Limit tables # M.TwoGroupShareIndices = Set(dimen=5, initialize=TwoGroupShareIndices) - + # M.LimitNewCapacityGroupShareConstraint_rpgg = Set(within=M.TwoGroupShareIndices) # M.LimitNewCapacityGroupShare = Param(M.TwoGroupShareIndices) @@ -513,9 +614,15 @@ def __init__(M, *args, **kwargs): # This set works for all storage-related constraints M.StorageConstraints_rpsdtv = Set(dimen=6, initialize=StorageConstraintIndices) - M.SeasonalStorageConstraints_rpsdtv = Set(dimen=6, initialize=SeasonalStorageConstraintIndices) - M.LimitStorageFractionConstraint_rpsdtv = Set(within=(M.StorageConstraints_rpsdtv | M.SeasonalStorageConstraints_rpsdtv) * M.operator) - M.LimitStorageFraction = Param(M.LimitStorageFractionConstraint_rpsdtv, validate=validate_0to1) + M.SeasonalStorageConstraints_rpsdtv = Set( + dimen=6, initialize=SeasonalStorageConstraintIndices + ) + M.LimitStorageFractionConstraint_rpsdtv = Set( + within=(M.StorageConstraints_rpsdtv | M.SeasonalStorageConstraints_rpsdtv) * M.operator + ) + M.LimitStorageFraction = Param( + M.LimitStorageFractionConstraint_rpsdtv, validate=validate_0to1 + ) # Storage duration is expressed in hours M.StorageDuration = Param(M.regions, M.tech_storage, default=4) @@ -523,17 +630,32 @@ def __init__(M, *args, **kwargs): M.LinkedTechs = Param(M.regionalIndices, M.tech_all, M.commodity_emissions, within=Any) # Define parameters associated with electric sector operation - M.ReserveMarginMethod = Set() # How contributions to the reserve margin are calculated + M.ReserveMarginMethod = Set() # How contributions to the reserve margin are calculated M.CapacityCredit = Param( - M.regionalIndices, M.time_optimize, M.tech_reserve, M.vintage_all, default=0, validate=validate_0to1 + M.regionalIndices, + M.time_optimize, + M.tech_reserve, + M.vintage_all, + default=0, + validate=validate_0to1, ) M.ReserveCapacityDerate = Param( - M.regionalIndices, M.time_optimize, M.time_season, M.tech_reserve, M.vintage_all, default=1, validate=validate_0to1 + M.regionalIndices, + M.time_optimize, + M.time_season, + M.tech_reserve, + M.vintage_all, + default=1, + validate=validate_0to1, ) M.PlanningReserveMargin = Param(M.regions) - - M.EmissionEmbodied = Param(M.regions, M.commodity_emissions, M.tech_with_capacity, M.vintage_optimize) - M.EmissionEndOfLife = Param(M.regions, M.commodity_emissions, M.tech_with_capacity, M.vintage_all) + + M.EmissionEmbodied = Param( + M.regions, M.commodity_emissions, M.tech_with_capacity, M.vintage_optimize + ) + M.EmissionEndOfLife = Param( + M.regions, M.commodity_emissions, M.tech_with_capacity, M.vintage_all + ) M.MyopicDiscountingYear = Param(default=0) @@ -589,7 +711,9 @@ def __init__(M, *args, **kwargs): M.V_RetiredCapacity = Var(M.RetiredCapacityVar_rptv, domain=NonNegativeReals, initialize=0) M.AnnualRetirementVar_rptv = Set(dimen=4, initialize=AnnualRetirementVariableIndices) - M.V_AnnualRetirement = Var(M.AnnualRetirementVar_rptv, domain=NonNegativeReals, initialize=0) + M.V_AnnualRetirement = Var( + M.AnnualRetirementVar_rptv, domain=NonNegativeReals, initialize=0 + ) M.CapacityAvailableVar_rpt = Set(dimen=3, initialize=CapacityAvailableVariableIndices) M.V_CapacityAvailableByPeriodAndTech = Var( @@ -633,11 +757,15 @@ def __init__(M, *args, **kwargs): # M.RetiredCapacityConstraint = Constraint( # M.RetiredCapacityVar_rptv, rule=RetiredCapacity_Constraint # ) - M.progress_marker_4a = BuildAction(['Starting AnnualRetirementConstraint'], rule=progress_check) + M.progress_marker_4a = BuildAction( + ['Starting AnnualRetirementConstraint'], rule=progress_check + ) M.AnnualRetirementConstraint = Constraint( M.AnnualRetirementVar_rptv, rule=AnnualRetirement_Constraint ) - M.progress_marker_4b = BuildAction(['Starting AdjustedCapacityConstraint'], rule=progress_check) + M.progress_marker_4b = BuildAction( + ['Starting AdjustedCapacityConstraint'], rule=progress_check + ) M.AdjustedCapacityConstraint = Constraint( M.CostFixed_rptv, rule=AdjustedCapacity_Constraint ) @@ -669,7 +797,7 @@ def __init__(M, *args, **kwargs): M.AnnualCommodityBalanceConstraint = Constraint( M.AnnualCommodityBalanceConstraint_rpc, rule=AnnualCommodityBalance_Constraint ) - + # M.ResourceExtractionConstraint = Constraint( # M.ResourceConstraint_rpr, rule=ResourceExtraction_Constraint # ) @@ -725,17 +853,23 @@ def __init__(M, *args, **kwargs): M.RampUpDayConstraint_rpsdtv = Set(dimen=6, initialize=RampUpDayConstraintIndices) M.RampUpDayConstraint = Constraint(M.RampUpDayConstraint_rpsdtv, rule=RampUpDay_Constraint) M.RampDownDayConstraint_rpsdtv = Set(dimen=6, initialize=RampDownDayConstraintIndices) - M.RampDownDayConstraint = Constraint(M.RampDownDayConstraint_rpsdtv, rule=RampDownDay_Constraint) - + M.RampDownDayConstraint = Constraint( + M.RampDownDayConstraint_rpsdtv, rule=RampDownDay_Constraint + ) + M.RampUpSeasonConstraint_rpsstv = Set(dimen=6, initialize=RampUpSeasonConstraintIndices) - M.RampUpSeasonConstraint = Constraint(M.RampUpSeasonConstraint_rpsstv, rule=RampUpSeason_Constraint) + M.RampUpSeasonConstraint = Constraint( + M.RampUpSeasonConstraint_rpsstv, rule=RampUpSeason_Constraint + ) M.RampDownSeasonConstraint_rpsstv = Set(dimen=6, initialize=RampDownSeasonConstraintIndices) - M.RampDownSeasonConstraint = Constraint(M.RampDownSeasonConstraint_rpsstv, rule=RampDownSeason_Constraint) + M.RampDownSeasonConstraint = Constraint( + M.RampDownSeasonConstraint_rpsstv, rule=RampDownSeason_Constraint + ) M.ReserveMargin_rpsd = Set(dimen=4, initialize=ReserveMarginIndices) M.validate_ReserveMargin = BuildAction(rule=validate_ReserveMargin) M.ReserveMarginConstraint = Constraint(M.ReserveMargin_rpsd, rule=ReserveMargin_Constraint) - + M.LimitEmissionConstraint = Constraint( M.LimitEmissionConstraint_rpe, rule=LimitEmission_Constraint ) @@ -747,27 +881,39 @@ def __init__(M, *args, **kwargs): M.LimitGrowthCapacityConstraint = Constraint( M.LimitGrowthCapacityConstraint_rpt, rule=LimitGrowthCapacityConstraint_rule ) - M.LimitDegrowthCapacityConstraint_rpt = Set(dimen=4, initialize=LimitDegrowthCapacityIndices) + M.LimitDegrowthCapacityConstraint_rpt = Set( + dimen=4, initialize=LimitDegrowthCapacityIndices + ) M.LimitDegrowthCapacityConstraint = Constraint( M.LimitDegrowthCapacityConstraint_rpt, rule=LimitDegrowthCapacityConstraint_rule ) - M.LimitGrowthNewCapacityConstraint_rpt = Set(dimen=4, initialize=LimitGrowthNewCapacityIndices) + M.LimitGrowthNewCapacityConstraint_rpt = Set( + dimen=4, initialize=LimitGrowthNewCapacityIndices + ) M.LimitGrowthNewCapacityConstraint = Constraint( M.LimitGrowthNewCapacityConstraint_rpt, rule=LimitGrowthNewCapacityConstraint_rule ) - M.LimitDegrowthNewCapacityConstraint_rpt = Set(dimen=4, initialize=LimitDegrowthNewCapacityIndices) + M.LimitDegrowthNewCapacityConstraint_rpt = Set( + dimen=4, initialize=LimitDegrowthNewCapacityIndices + ) M.LimitDegrowthNewCapacityConstraint = Constraint( M.LimitDegrowthNewCapacityConstraint_rpt, rule=LimitDegrowthNewCapacityConstraint_rule ) - M.LimitGrowthNewCapacityDeltaConstraint_rpt = Set(dimen=4, initialize=LimitGrowthNewCapacityDeltaIndices) + M.LimitGrowthNewCapacityDeltaConstraint_rpt = Set( + dimen=4, initialize=LimitGrowthNewCapacityDeltaIndices + ) M.LimitGrowthNewCapacityDeltaConstraint = Constraint( - M.LimitGrowthNewCapacityDeltaConstraint_rpt, rule=LimitGrowthNewCapacityDeltaConstraint_rule + M.LimitGrowthNewCapacityDeltaConstraint_rpt, + rule=LimitGrowthNewCapacityDeltaConstraint_rule, + ) + M.LimitDegrowthNewCapacityDeltaConstraint_rpt = Set( + dimen=4, initialize=LimitDegrowthNewCapacityDeltaIndices ) - M.LimitDegrowthNewCapacityDeltaConstraint_rpt = Set(dimen=4, initialize=LimitDegrowthNewCapacityDeltaIndices) M.LimitDegrowthNewCapacityDeltaConstraint = Constraint( - M.LimitDegrowthNewCapacityDeltaConstraint_rpt, rule=LimitDegrowthNewCapacityDeltaConstraint_rule + M.LimitDegrowthNewCapacityDeltaConstraint_rpt, + rule=LimitDegrowthNewCapacityDeltaConstraint_rule, ) M.LimitActivityConstraint = Constraint( @@ -775,7 +921,8 @@ def __init__(M, *args, **kwargs): ) M.LimitSeasonalCapacityFactorConstraint = Constraint( - M.LimitSeasonalCapacityFactorConstraint_rpst, rule=LimitSeasonalCapacityFactor_Constraint + M.LimitSeasonalCapacityFactorConstraint_rpst, + rule=LimitSeasonalCapacityFactor_Constraint, ) # devnote: deprecated when generalising tech/group columns in Limit tables @@ -811,7 +958,7 @@ def __init__(M, *args, **kwargs): M.LimitNewCapacityShareConstraint = Constraint( M.LimitNewCapacityShareConstraint_rpgg, rule=LimitNewCapacityShare_Constraint ) - + # devnote: deprecated when generalising tech/group columns in Limit tables # M.LimitNewCapacityGroupShareConstraint = Constraint( # M.LimitNewCapacityGroupShareConstraint_rpgg, rule=LimitNewCapacityGroupShare_Constraint @@ -822,7 +969,7 @@ def __init__(M, *args, **kwargs): # ) M.progress_marker_8 = BuildAction( - ['Starting Limit Capacity and Tech Split ' 'Constraints'], rule=progress_check + ['Starting Limit Capacity and Tech Split Constraints'], rule=progress_check ) M.LimitResourceConstraint = Constraint( @@ -874,7 +1021,8 @@ def __init__(M, *args, **kwargs): dimen=6, initialize=LimitTechOutputSplitAverageConstraintIndices ) M.LimitTechOutputSplitAverageConstraint = Constraint( - M.LimitTechOutputSplitAverageConstraint_rptvo, rule=LimitTechOutputSplitAverage_Constraint + M.LimitTechOutputSplitAverageConstraint_rptvo, + rule=LimitTechOutputSplitAverage_Constraint, ) M.RenewablePortfolioStandardConstraint = Constraint( diff --git a/temoa/utilities/db_migration_v3_to_v3_1.py b/temoa/utilities/db_migration_v3_to_v3_1.py index bee1ae464..cc55d96b9 100644 --- a/temoa/utilities/db_migration_v3_to_v3_1.py +++ b/temoa/utilities/db_migration_v3_to_v3_1.py @@ -25,18 +25,19 @@ Transition a v3.0 database to a v3.1 database. """ -import os -import sys import argparse +import os import sqlite3 -import pandas as pd +import sys from pathlib import Path +import pandas as pd + # Just to get the default lifetime... this_dir = os.path.dirname(__file__) root_dir = os.path.abspath(os.path.join(this_dir, '../..')) sys.path.append(root_dir) -from temoa.temoa_model.temoa_model import TemoaModel +from temoa.core.model import TemoaModel parser = argparse.ArgumentParser() parser.add_argument( @@ -72,6 +73,7 @@ # turn off FK verification while process executes con_new.execute('PRAGMA foreign_keys = 0;') + def column_check(old_name: str, new_name: str) -> bool: if old_name == '': old_name = new_name @@ -84,16 +86,17 @@ def column_check(old_name: str, new_name: str) -> bool: new_columns = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] old_columns = [c[1] for c in con_old.execute(f'PRAGMA table_info({old_name});').fetchall()] - missing = [c for c in new_columns if c not in old_columns and c not in ('period','notes')] + missing = [c for c in new_columns if c not in old_columns and c not in ('period', 'notes')] if len(missing) > 0: msg = ( f'Columns of {new_name} in the new database missing from {old_name} in old database. Try adding or renaming the column in the old database:' f'\n{missing}\n' - ) + ) print(msg) return False return True + # table mapping for DIRECT transfers # fmt: off direct_transfer_tables = [ @@ -273,7 +276,7 @@ def column_check(old_name: str, new_name: str) -> bool: except sqlite3.OperationalError: print('TABLE NOT FOUND: ' + old_name) continue - + old_columns = [c[1] for c in con_old.execute(f'PRAGMA table_info({old_name});').fetchall()] new_columns = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] cols = [c for c in new_columns if c in old_columns] @@ -282,7 +285,7 @@ def column_check(old_name: str, new_name: str) -> bool: if len(data) == 0: print('No data for: ' + old_name) continue - + # This insanity collects the viable periods for each table if 'vintage' in cols: data['periods'] = [ @@ -312,7 +315,7 @@ def column_check(old_name: str, new_name: str) -> bool: ] else: data['periods'] = [time_optimize for i in data.index] - + data_new = [] for p in time_optimize: for _idx, row in data.iterrows(): @@ -376,7 +379,7 @@ def column_check(old_name: str, new_name: str) -> bool: vints = [v[0] for v in con_old.execute(f'SELECT vintage FROM Efficiency WHERE region=="{row[0]}" AND tech="{row[1]}"').fetchall()] for v in vints: new_data.append((row[0], row[1], v, row[2], row[3])) - query = f'INSERT OR REPLACE INTO LoanLifetimeProcess VALUES (?,?,?,?,?)' + query = 'INSERT OR REPLACE INTO LoanLifetimeProcess VALUES (?,?,?,?,?)' con_new.executemany(query, new_data) print(f'Transfered {len(new_data)} rows from LifetimeLoanTech to LifetimeLoanProcess') @@ -385,7 +388,7 @@ def column_check(old_name: str, new_name: str) -> bool: print('\n --- The following transfers were impossible due to incompatible changes. Transfer manually. ---') for old_name, new_name in no_transfer.items(): print(f'{old_name} to {new_name}') - + print('\n --- Updating MetaData ---') cur.execute("DELETE FROM MetaData WHERE element == 'myopic_base_year'") @@ -419,4 +422,4 @@ def column_check(old_name: str, new_name: str) -> bool: ' If there was a mismatch of table names, something may have been lost.') con_new.close() -con_old.close() \ No newline at end of file +con_old.close() diff --git a/temoa/utilities/unit_cost_explorer.py b/temoa/utilities/unit_cost_explorer.py index 4cf40786a..31367dd89 100644 --- a/temoa/utilities/unit_cost_explorer.py +++ b/temoa/utilities/unit_cost_explorer.py @@ -3,7 +3,7 @@ of storage capacity """ -from temoa.temoa_model.temoa_rules import * +from temoa._internal.temoa_rules import * # Written by: J. F. Hyink # jeff@westernspark.us diff --git a/tests/conftest.py b/tests/conftest.py index 0a42bde20..53e37b4e7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -38,8 +38,8 @@ from pyomo.opt import SolverResults from definitions import PROJECT_ROOT -from temoa.temoa_model.temoa_model import TemoaModel -from temoa.temoa_model.temoa_sequencer import TemoaSequencer +from temoa._internal.temoa_sequencer import TemoaSequencer +from temoa.core.model import TemoaModel logger = logging.getLogger(__name__) diff --git a/tests/test_element_checker.py b/tests/test_element_checker.py index f04b935ef..a7b54e8ee 100644 --- a/tests/test_element_checker.py +++ b/tests/test_element_checker.py @@ -25,9 +25,10 @@ Created on: 4/25/24 """ + import pytest -from temoa.temoa_model.model_checking.element_checker import ViableSet, filter_elements +from temoa.model_checking.element_checker import ViableSet, filter_elements params = [ { diff --git a/tests/test_emission_results.py b/tests/test_emission_results.py index 52b9fbb56..2ab61d0b7 100644 --- a/tests/test_emission_results.py +++ b/tests/test_emission_results.py @@ -32,7 +32,7 @@ import pytest from definitions import PROJECT_ROOT -from temoa.temoa_model.temoa_sequencer import TemoaSequencer +from temoa._internal.temoa_sequencer import TemoaSequencer logger = logging.getLogger(__name__) @@ -92,12 +92,14 @@ def test_emissions(solved_connection): con, name, tech, emis_target = solved_connection emis = ( con.cursor() - .execute(f"SELECT SUM(emission) FROM main.OutputEmission WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied' AND period == 2000") + .execute( + f"SELECT SUM(emission) FROM main.OutputEmission WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied' AND period == 2000" + ) .fetchone()[0] ) - assert emis == pytest.approx( - emis_target - ), f'{name} emissions were incorrect. Should be {emis_target}, got {emis}' + assert emis == pytest.approx(emis_target), ( + f'{name} emissions were incorrect. Should be {emis_target}, got {emis}' + ) # Emission costs undiscounted @@ -114,13 +116,15 @@ def test_emissions_costs_undiscounted(solved_connection): con, name, tech, emis_target = solved_connection ec = ( con.cursor() - .execute(f"SELECT SUM(emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied' AND period == 2000") + .execute( + f"SELECT SUM(emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied' AND period == 2000" + ) .fetchone()[0] ) cost_target = 0.7 * emis_target * 5 # emission cost x emissions x 5y - assert ec == pytest.approx( - cost_target - ), f'{name} undiscounted emission costs were incorrect. Should be {cost_target}, got {ec}' + assert ec == pytest.approx(cost_target), ( + f'{name} undiscounted emission costs were incorrect. Should be {cost_target}, got {ec}' + ) # Emission costs discounted @@ -137,15 +141,15 @@ def test_emissions_costs_discounted(solved_connection): con, name, tech, emis_target = solved_connection ec = ( con.cursor() - .execute(f"SELECT SUM(d_emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied' AND period == 2000") + .execute( + f"SELECT SUM(d_emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied' AND period == 2000" + ) .fetchone()[0] ) - cost_target = ( - 0.7 * emis_target * 4.32947667063082 - ) # emission cost x emissions x P/A(5%, 5y, 1) - assert ec == pytest.approx( - cost_target - ), f'{name} discounted emission costs were incorrect. Should be {cost_target}, got {ec}' + cost_target = 0.7 * emis_target * 4.32947667063082 # emission cost x emissions x P/A(5%, 5y, 1) + assert ec == pytest.approx(cost_target), ( + f'{name} discounted emission costs were incorrect. Should be {cost_target}, got {ec}' + ) # Embodied emissions @@ -162,11 +166,13 @@ def test_embodied_emissions(solved_connection): con, name, tech, emis_target = solved_connection emis = ( con.cursor() - .execute(f"SELECT SUM(emission) FROM main.OutputEmission WHERE tech LIKE '{tech}' AND period == 2000") + .execute( + f"SELECT SUM(emission) FROM main.OutputEmission WHERE tech LIKE '{tech}' AND period == 2000" + ) .fetchone()[0] ) assert emis == pytest.approx( - emis_target/5 # embodied emissions are distributed over vintage period + emis_target / 5 # embodied emissions are distributed over vintage period ), f'{name} embodied emissions were incorrect. Should be {emis_target}, got {emis}' @@ -184,13 +190,15 @@ def test_embodied_emissions_costs_undiscounted(solved_connection): con, name, tech, emis_target = solved_connection ec = ( con.cursor() - .execute(f"SELECT SUM(emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND period == 2000") + .execute( + f"SELECT SUM(emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND period == 2000" + ) .fetchone()[0] ) cost_target = 0.7 * emis_target # emission cost x embodied emissions - assert ec == pytest.approx( - cost_target - ), f'{name} undiscounted embodied emission costs were incorrect. Should be {cost_target}, got {ec}' + assert ec == pytest.approx(cost_target), ( + f'{name} undiscounted embodied emission costs were incorrect. Should be {cost_target}, got {ec}' + ) # Embodied emission costs discounted @@ -207,15 +215,17 @@ def test_embodied_emissions_costs_discounted(solved_connection): con, name, tech, emis_target = solved_connection ec = ( con.cursor() - .execute(f"SELECT SUM(d_emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND period == 2000") + .execute( + f"SELECT SUM(d_emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND period == 2000" + ) .fetchone()[0] ) cost_target = ( - 0.7 * emis_target * 1/5 * (1.05**5-1)/(0.05*1.05**5) + 0.7 * emis_target * 1 / 5 * (1.05**5 - 1) / (0.05 * 1.05**5) ) # emission cost x embodied emissions x annual distribution x P/A(5%, 5y, 1) - assert ec == pytest.approx( - cost_target - ), f'{name} discounted emission costs were incorrect. Should be {cost_target}, got {ec}' + assert ec == pytest.approx(cost_target), ( + f'{name} discounted emission costs were incorrect. Should be {cost_target}, got {ec}' + ) # End of life emissions @@ -232,11 +242,13 @@ def test_endoflife_emissions(solved_connection): con, name, tech, emis_target = solved_connection emis = ( con.cursor() - .execute(f"SELECT SUM(emission) FROM main.OutputEmission WHERE tech LIKE '{tech}' AND period == 2005") + .execute( + f"SELECT SUM(emission) FROM main.OutputEmission WHERE tech LIKE '{tech}' AND period == 2005" + ) .fetchone()[0] ) assert emis == pytest.approx( - emis_target/5 # end of life emissions are distributed over vintage period + emis_target / 5 # end of life emissions are distributed over vintage period ), f'{name} end of life emissions were incorrect. Should be {emis_target}, got {emis}' @@ -254,13 +266,15 @@ def test_endoflife_emissions_costs_undiscounted(solved_connection): con, name, tech, emis_target = solved_connection ec = ( con.cursor() - .execute(f"SELECT SUM(emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND period == 2005") + .execute( + f"SELECT SUM(emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND period == 2005" + ) .fetchone()[0] ) cost_target = 0.7 * emis_target # emission cost x end of life emissions - assert ec == pytest.approx( - cost_target - ), f'{name} undiscounted end of life emission costs were incorrect. Should be {cost_target}, got {ec}' + assert ec == pytest.approx(cost_target), ( + f'{name} undiscounted end of life emission costs were incorrect. Should be {cost_target}, got {ec}' + ) # End of life emission costs discounted @@ -277,15 +291,17 @@ def test_endoflife_emissions_costs_discounted(solved_connection): con, name, tech, emis_target = solved_connection ec = ( con.cursor() - .execute(f"SELECT SUM(d_emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND period == 2005") + .execute( + f"SELECT SUM(d_emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND period == 2005" + ) .fetchone()[0] ) cost_target = ( - 0.7 * emis_target * 1/5 * (1.05**5-1)/(0.05*1.05**5) / 1.05**5 + 0.7 * emis_target * 1 / 5 * (1.05**5 - 1) / (0.05 * 1.05**5) / 1.05**5 ) # emission cost x end of life emissions x annual distribution x P/A(5%, 5y, 1) x P/F(5%, 1y) - assert ec == pytest.approx( - cost_target - ), f'{name} discounted emission costs were incorrect. Should be {cost_target}, got {ec}' + assert ec == pytest.approx(cost_target), ( + f'{name} discounted emission costs were incorrect. Should be {cost_target}, got {ec}' + ) # Curtailment @@ -309,9 +325,11 @@ def test_curtailment(solved_connection): print(name, tech, curt_target) curt = ( con.cursor() - .execute(f"SELECT SUM(curtailment) FROM main.OutputCurtailment WHERE tech LIKE '{tech}' AND period == 2000") + .execute( + f"SELECT SUM(curtailment) FROM main.OutputCurtailment WHERE tech LIKE '{tech}' AND period == 2000" + ) .fetchone()[0] ) - assert curt == pytest.approx( - curt_target - ), f'{name} curtailment was incorrect. Should be {curt_target}, got {curt}' + assert curt == pytest.approx(curt_target), ( + f'{name} curtailment was incorrect. Should be {curt_target}, got {curt}' + ) diff --git a/tests/test_exchange_cost_ledger.py b/tests/test_exchange_cost_ledger.py index 29a26d2e2..da7f0d3f0 100644 --- a/tests/test_exchange_cost_ledger.py +++ b/tests/test_exchange_cost_ledger.py @@ -28,7 +28,7 @@ import pytest -from temoa.temoa_model.exchange_tech_cost_ledger import CostType, ExchangeTechCostLedger +from temoa._internal.exchange_tech_cost_ledger import CostType, ExchangeTechCostLedger from tests.utilities.namespace_mock import Namespace # these are the necessary Temoa elements to make the ledger work @@ -100,13 +100,13 @@ def test_cost_allocation(fake_model, costs): # test for ratio... ratio = ledger.get_use_ratio('A', 'B', 2000, 't1', 2000) - assert ratio == pytest.approx( - costs['B_ratio'] - ), 'B should get 60% of cost as it receives 60% of flow' + assert ratio == pytest.approx(costs['B_ratio']), ( + 'B should get 60% of cost as it receives 60% of flow' + ) ratio = ledger.get_use_ratio('B', 'A', 2000, 't1', 2000) - assert ratio == pytest.approx( - costs['A_ratio'] - ), 'A should get 40% of cost as it receives 40% of flow' + assert ratio == pytest.approx(costs['A_ratio']), ( + 'A should get 40% of cost as it receives 40% of flow' + ) # test the outpt cost entries... entries = ledger.get_entries() diff --git a/tests/test_material_results.py b/tests/test_material_results.py index f77d100ba..b076bda9d 100644 --- a/tests/test_material_results.py +++ b/tests/test_material_results.py @@ -32,7 +32,7 @@ import pytest from definitions import PROJECT_ROOT -from temoa.temoa_model.temoa_sequencer import TemoaSequencer +from temoa._internal.temoa_sequencer import TemoaSequencer logger = logging.getLogger(__name__) @@ -57,7 +57,13 @@ def solved_connection(request, tmp_path_factory): sequencer.start() # make connection here as in your code... con = sqlite3.connect(sequencer.config.output_database) - yield con, request.param['name'], request.param['tech'], request.param['period'], request.param['target'] + yield ( + con, + request.param['name'], + request.param['tech'], + request.param['period'], + request.param['target'], + ) con.close() @@ -66,6 +72,7 @@ def solved_connection(request, tmp_path_factory): {'name': 'lithium import', 'tech': 'IMPORT_LI', 'period': 2000, 'target': 0.129291623}, ] + # Flows @pytest.mark.parametrize( 'solved_connection', @@ -80,10 +87,12 @@ def test_flows(solved_connection): con, name, tech, period, flow_target = solved_connection flow = ( con.cursor() - .execute(f"SELECT SUM(flow) FROM main.OutputFlowOut WHERE tech == '{tech}' AND period == {period}") + .execute( + f"SELECT SUM(flow) FROM main.OutputFlowOut WHERE tech == '{tech}' AND period == {period}" + ) .fetchone()[0] ) assert flow == pytest.approx( flow_target, - rel=1E-5, - ), f'{name} flows were incorrect. Should be {flow_target}, got {flow}' \ No newline at end of file + rel=1e-5, + ), f'{name} flows were incorrect. Should be {flow_target}, got {flow}' diff --git a/tests/test_model.py b/tests/test_model.py index 4710a69e9..9ef34567c 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -30,8 +30,8 @@ import pickle from definitions import PROJECT_ROOT -from temoa.temoa_model.temoa_mode import TemoaMode -from temoa.temoa_model.temoa_sequencer import TemoaSequencer +from temoa._internal.temoa_sequencer import TemoaSequencer +from temoa.core.modes import TemoaMode def test_serialization(): diff --git a/tests/test_network_model_data.py b/tests/test_network_model_data.py index e9b4e7a19..61dfa1811 100644 --- a/tests/test_network_model_data.py +++ b/tests/test_network_model_data.py @@ -31,8 +31,8 @@ import pytest -from temoa.temoa_model.model_checking import network_model_data -from temoa.temoa_model.model_checking.commodity_network import CommodityNetwork +from temoa.model_checking import network_model_data +from temoa.model_checking.commodity_network import CommodityNetwork # a couple of test cases with diagrams in the flow... params = [ @@ -51,14 +51,14 @@ { 'name': 'basic', 'data': [ - [], # retirement techs - [], # survival curve techs + [], # retirement techs + [], # survival curve techs [ (2020,), (2025,), ], # periods [(t,) for t in ['s1', 'p1', 'p2', 'p3', 'd1', 'd2']], # all commodities - [], # waste commodities + [], # waste commodities [ (t,) for t in [ @@ -100,14 +100,14 @@ { 'name': 'bad linked tech', 'data': [ - [], # retirement techs - [], # survival curve techs + [], # retirement techs + [], # survival curve techs [ (2020,), (2025,), ], # periods [(t,) for t in ['s1', 'p3', 'd1', 'd2']], # all commodities - [], # waste commodities + [], # waste commodities [ (t,) for t in [ @@ -148,14 +148,14 @@ # 'name': 'good linked tech', 'data': [ - [], # retirement techs - [], # survival curve techs + [], # retirement techs + [], # survival curve techs [ (2020,), (2025,), ], # periods [(t,) for t in ['s1', 'd1', 'd2', 's2']], # all commodities - [], # waste commodities + [], # waste commodities [(t,) for t in ['s1', 's2']], # sources [('R1', 2020, 'd1'), ('R1', 2020, 'd2')], # demands [ @@ -201,12 +201,12 @@ def test_build_from_db(mock_db_connection): """test a couple values in the load""" conn, expected = mock_db_connection network_data = network_model_data._build_from_db(conn) - assert ( - len(tuple(chain(*network_data.demand_commodities.values()))) == expected['demands'] - ), 'demand count failed' - assert ( - len(network_data.available_techs['R1', 2020]) == expected['techs'] - ), '6 techs are available' + assert len(tuple(chain(*network_data.demand_commodities.values()))) == expected['demands'], ( + 'demand count failed' + ) + assert len(network_data.available_techs['R1', 2020]) == expected['techs'], ( + '6 techs are available' + ) @pytest.mark.parametrize( diff --git a/tests/test_pricing_check.py b/tests/test_pricing_check.py index 40d6ee774..78b5bfba9 100644 --- a/tests/test_pricing_check.py +++ b/tests/test_pricing_check.py @@ -29,7 +29,7 @@ import pytest from pyomo.environ import Any, ConcreteModel, Param, Set -from temoa.temoa_model.model_checking.pricing_check import check_tech_uncap +from temoa.model_checking.pricing_check import check_tech_uncap @pytest.fixture diff --git a/tests/test_set_consistency.py b/tests/test_set_consistency.py index 6a0bfabc0..e211d30fa 100644 --- a/tests/test_set_consistency.py +++ b/tests/test_set_consistency.py @@ -37,7 +37,8 @@ from pyomo import environ as pyo from definitions import PROJECT_ROOT -from temoa.temoa_model.temoa_sequencer import TemoaMode, TemoaSequencer +from temoa._internal.temoa_sequencer import TemoaSequencer +from temoa.core.modes import TemoaMode params = [ ('utopia', 'config_utopia.toml', 'utopia_sets.json'), @@ -118,9 +119,9 @@ def test_set_consistency(data_name, config_file, set_file, tmp_path): print(f'{k}: {cached_sets[k]}') assert not missing_in_model, f'one or more cached set not in model: {missing_in_model}' - assert ( - not overage_in_model and not shortage_in_model - ), f'The {data_name} run-produced sets did not match cached values' + assert not overage_in_model and not shortage_in_model, ( + f'The {data_name} run-produced sets did not match cached values' + ) if cache_extra_sets: assert False, 'Cache has extra sets' if model_extra_sets: diff --git a/tests/test_source_check.py b/tests/test_source_check.py index 40c2cdd6e..702ae9a99 100644 --- a/tests/test_source_check.py +++ b/tests/test_source_check.py @@ -26,7 +26,7 @@ """ -from temoa.temoa_model.model_checking.commodity_network import _mark_good_connections, _visited_dfs +from temoa.model_checking.commodity_network import _mark_good_connections, _visited_dfs def test_network_analysis(): diff --git a/tests/test_storage.py b/tests/test_storage.py index 4ab04f8b3..7cdda1ed9 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -8,14 +8,10 @@ """ import logging -import pathlib import pytest -from definitions import PROJECT_ROOT -from temoa.temoa_model.temoa_mode import TemoaMode -from temoa.temoa_model.temoa_model import TemoaModel -from temoa.temoa_model.temoa_sequencer import TemoaSequencer +from temoa.core.model import TemoaModel logger = logging.getLogger(__name__) # suitable scenarios for storage testing....singleton for now. @@ -43,19 +39,19 @@ def test_storage_fraction(system_test_run): ) for r, p, s, d, t, v, op in model.LimitStorageFractionConstraint_rpsdtv: - energy = ( model.LimitStorageFraction[r, p, s, d, t, v, op] * model.V_Capacity[r, p, t, v].value * model.CapacityToActivity[r, t] * (model.StorageDuration[r, t] / 8760) - * model.SegFracPerSeason[p, s] * model.DaysPerPeriod + * model.SegFracPerSeason[p, s] + * model.DaysPerPeriod * model.ProcessLifeFrac[r, p, t, v] ) - assert model.V_StorageLevel[r, p, s, d, t, v].value == pytest.approx( - energy, abs=1e-5 - ), f'model fails to initialise storage state at start of season {r, p, s, d, t, v}' + assert model.V_StorageLevel[r, p, s, d, t, v].value == pytest.approx(energy, abs=1e-5), ( + f'model fails to initialise storage state at start of season {r, p, s, d, t, v}' + ) @pytest.mark.parametrize( @@ -74,9 +70,8 @@ def test_state_sequencing(system_test_run): assert len(model.StorageLevel_rpsdtv) > 0, ( 'This model does not appear to have any available storage components' ) - - for r, p, s, d, t, v in model.StorageLevel_rpsdtv: + for r, p, s, d, t, v in model.StorageLevel_rpsdtv: charge = sum( model.V_FlowIn[r, p, s, d, S_i, t, v, S_o].value * model.Efficiency[r, S_i, t, v, S_o] for S_i in model.processInputs[r, p, t, v] @@ -92,10 +87,10 @@ def test_state_sequencing(system_test_run): state = model.V_StorageLevel[r, p, s, d, t, v].value next_state = model.V_StorageLevel[r, p, s_next, d_next, t, v].value - - assert state + charge - discharge == pytest.approx( - next_state, abs=1e-5 - ), f'model fails to correctly sequence storage states {r, p, s, t, v} sequenced {s, d} to {s_next, d_next}' + + assert state + charge - discharge == pytest.approx(next_state, abs=1e-5), ( + f'model fails to correctly sequence storage states {r, p, s, t, v} sequenced {s, d} to {s_next, d_next}' + ) @pytest.mark.parametrize( @@ -112,7 +107,7 @@ def test_storage_flow_balance(system_test_run): model: TemoaModel # helps with typing for some reason... data_name, results, model, _ = system_test_run assert len(model.StorageLevel_rpsdtv) > 0, ( - 'This model does not appear to have' 'any available storage components' + 'This model does not appear to haveany available storage components' ) for s_tech in model.tech_storage: inflow_indices = { @@ -133,11 +128,11 @@ def test_storage_flow_balance(system_test_run): for (r, p, s, d, i, t, v, o) in inflow_indices ) outflow = sum(model.V_FlowOut[idx].value for idx in outflow_indices) - - assert inflow == pytest.approx( - outflow, abs=1e-5 - ), (f'total inflow and outflow of storage tech {s_tech} do not match', - ' - there is a discontinuity of storage states') + + assert inflow == pytest.approx(outflow, abs=1e-5), ( + f'total inflow and outflow of storage tech {s_tech} do not match', + ' - there is a discontinuity of storage states', + ) # devnote: the StorageInit constraint was reworked into LimitStorageLevelFraction diff --git a/tests/test_table_writer.py b/tests/test_table_writer.py index 22728d6d4..7f44996a9 100644 --- a/tests/test_table_writer.py +++ b/tests/test_table_writer.py @@ -28,7 +28,7 @@ import pytest -from temoa.temoa_model.table_data_puller import loan_costs +from temoa._internal.table_data_puller import loan_costs params = [ { @@ -56,7 +56,7 @@ 'p_0': 2020, 'vintage': 2030, 'p_e': 2035, - 'model_cost': 20950.20952, # reduced after fixing 1 year shift obj function bug + 'model_cost': 20950.20952, # reduced after fixing 1 year shift obj function bug 'undiscounted_cost': 33544.06, }, ] diff --git a/tests/test_temoa_sequencer.py b/tests/test_temoa_sequencer.py index 5f71a08a9..4adf3278e 100644 --- a/tests/test_temoa_sequencer.py +++ b/tests/test_temoa_sequencer.py @@ -31,8 +31,8 @@ import pytest from definitions import PROJECT_ROOT -from temoa.temoa_model.temoa_mode import TemoaMode -from temoa.temoa_model.temoa_sequencer import TemoaSequencer +from temoa._internal.temoa_sequencer import TemoaSequencer +from temoa.core.modes import TemoaMode params = [ {'name': 'build-only', 'mode': TemoaMode.BUILD_ONLY}, diff --git a/tests/test_validators.py b/tests/test_validators.py index 5c9b3a6e1..e8c17da42 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -30,11 +30,11 @@ import pyomo.environ as pyo import pytest -from temoa.temoa_model.model_checking.validators import ( +from temoa.model_checking.validators import ( linked_region_check, + no_slash_or_pipe, region_check, region_group_check, - no_slash_or_pipe, ) diff --git a/tests/utilities/capture_set_sizes_for_cache.py b/tests/utilities/capture_set_sizes_for_cache.py index 9394ec758..900d4536c 100644 --- a/tests/utilities/capture_set_sizes_for_cache.py +++ b/tests/utilities/capture_set_sizes_for_cache.py @@ -34,7 +34,7 @@ import pyomo.environ as pyo from definitions import PROJECT_ROOT -from temoa.temoa_model.temoa_sequencer import TemoaSequencer +from temoa._internal.temoa_sequencer import TemoaSequencer logger = logging.getLogger(__name__) diff --git a/tests/utilities/capture_set_values_for_cache.py b/tests/utilities/capture_set_values_for_cache.py index bef53dcb6..36926f080 100644 --- a/tests/utilities/capture_set_values_for_cache.py +++ b/tests/utilities/capture_set_values_for_cache.py @@ -35,7 +35,7 @@ import pyomo.environ as pyo from definitions import PROJECT_ROOT -from temoa.temoa_model.temoa_sequencer import TemoaSequencer +from temoa._internal.temoa_sequencer import TemoaSequencer from tests.conftest import refresh_databases print( diff --git a/uv.lock b/uv.lock index b9b838f28..6d43de06a 100644 --- a/uv.lock +++ b/uv.lock @@ -2924,7 +2924,7 @@ wheels = [ [[package]] name = "temoa" -version = "3.0.0" +version = "4.0.0a1" source = { editable = "." } dependencies = [ { name = "deprecated" }, From f3714206c05ee7fc68c1a9032f36fd766067ee76 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 7 Oct 2025 21:19:22 -0400 Subject: [PATCH 216/587] removing star imports from model.py, more work is needed to tame this file --- temoa/core/config.py | 12 ++-- temoa/core/model.py | 165 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 153 insertions(+), 24 deletions(-) diff --git a/temoa/core/config.py b/temoa/core/config.py index e7c30c43c..7cb890e28 100644 --- a/temoa/core/config.py +++ b/temoa/core/config.py @@ -47,8 +47,8 @@ def __init__( save_duals: bool = False, save_storage_levels: bool = False, save_lp_file: bool = False, - time_sequencing: str = None, - reserve_margin: str = None, + time_sequencing: str | None = None, + reserve_margin: str | None = None, MGA: dict | None = None, SVMGA: dict | None = None, myopic: dict | None = None, @@ -63,8 +63,8 @@ def __init__( ): if '-' in scenario: raise ValueError( - 'Scenario name must not contain "-". Dashes are used internally to indicate iterative ' - 'runs. Please rename scenario' + 'Scenario name must not contain "-". Dashes are used internally to indicate' + 'iterative runs. Please rename scenario' ) self.scenario = scenario # capture the operating mode @@ -75,13 +75,13 @@ def __init__( case str(): try: self.scenario_mode = TemoaMode[scenario_mode.upper()] - except KeyError: + except KeyError as err: raise AttributeError( f'The mode selection received by TemoaConfig: ' f'{scenario_mode} is invalid.\nPossible choices are ' f'{list(TemoaMode.__members__.keys())} (case ' f'insensitive).' - ) + ) from err case _: raise AttributeError( f'The mode selection received by TemoaConfig: ' diff --git a/temoa/core/model.py b/temoa/core/model.py index 90c606092..74ebbf9b8 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -10,11 +10,12 @@ import logging -from pyomo.core import BuildCheck +from pyomo.core import BuildCheck, Set, Var from pyomo.environ import ( AbstractModel, Any, BuildAction, + Constraint, Integers, NonNegativeReals, Objective, @@ -22,8 +23,131 @@ minimize, ) -from temoa._internal.temoa_initialize import * -from temoa._internal.temoa_rules import * +from temoa._internal.temoa_initialize import ( + AnnualCommodityBalanceConstraintIndices, + AnnualRetirementVariableIndices, + BaseloadDiurnalConstraintIndices, + CapacityAnnualConstraintIndices, + CapacityAvailableVariableIndices, + CapacityConstraintIndices, + CapacityFactorTechIndices, + CapacityVariableIndices, + CheckCapacityFactorProcess, + CheckEfficiencyIndices, + CheckEfficiencyVariable, + CommodityBalanceConstraintIndices, + CostFixedIndices, + CostVariableIndices, + CreateDemands, + CreateRegionalIndices, + CreateSparseDicts, + CreateSurvivalCurve, + CreateTimeSeasonSequential, + CreateTimeSequence, + CurtailmentVariableIndices, + DemandActivityConstraintIndices, + EmissionActivityIndices, + FlexVariableAnnualIndices, + FlexVariablelIndices, + FlowInStorageVariableIndices, + FlowVariableAnnualIndices, + FlowVariableIndices, + LifetimeLoanProcessIndices, + LifetimeProcessIndices, + LimitDegrowthCapacityIndices, + LimitDegrowthNewCapacityDeltaIndices, + LimitDegrowthNewCapacityIndices, + LimitGrowthCapacityIndices, + LimitGrowthNewCapacityDeltaIndices, + LimitGrowthNewCapacityIndices, + LimitTechInputSplitAnnualConstraintIndices, + LimitTechInputSplitAverageConstraintIndices, + LimitTechInputSplitConstraintIndices, + LimitTechOutputSplitAnnualConstraintIndices, + LimitTechOutputSplitAverageConstraintIndices, + LimitTechOutputSplitConstraintIndices, + LinkedTechConstraintIndices, + ModelProcessLifeIndices, + RampDownDayConstraintIndices, + RampDownSeasonConstraintIndices, + RampUpDayConstraintIndices, + RampUpSeasonConstraintIndices, + RegionalExchangeCapacityConstraintIndices, + ReserveMarginIndices, + RetiredCapacityVariableIndices, + SeasonalStorageConstraintIndices, + SeasonalStorageLevelVariableIndices, + StorageConstraintIndices, + StorageLevelVariableIndices, + get_default_capacity_factor, + get_default_loan_rate, + get_default_process_lifetime, + get_default_survival, + get_loan_life, + init_set_time_optimize, + init_set_vintage_exist, + init_set_vintage_optimize, + validate_SegFrac, + validate_time, + validate_TimeNext, +) + +# from temoa._internal.temoa_rules import * +from temoa._internal.temoa_rules import ( + AdjustedCapacity_Constraint, + AnnualCommodityBalance_Constraint, + AnnualRetirement_Constraint, + BaseloadDiurnal_Constraint, + Capacity_Constraint, + CapacityAnnual_Constraint, + CapacityAvailableByPeriodAndTech_Constraint, + CommodityBalance_Constraint, + Demand_Constraint, + DemandActivity_Constraint, + LimitActivity_Constraint, + LimitActivityShare_Constraint, + LimitAnnualCapacityFactor_Constraint, + LimitCapacity_Constraint, + LimitCapacityShare_Constraint, + LimitDegrowthCapacityConstraint_rule, + LimitDegrowthNewCapacityConstraint_rule, + LimitDegrowthNewCapacityDeltaConstraint_rule, + LimitEmission_Constraint, + LimitGrowthCapacityConstraint_rule, + LimitGrowthNewCapacityConstraint_rule, + LimitGrowthNewCapacityDeltaConstraint_rule, + LimitNewCapacity_Constraint, + LimitNewCapacityShare_Constraint, + LimitResource_Constraint, + LimitSeasonalCapacityFactor_Constraint, + LimitStorageFraction_Constraint, + LimitTechInputSplit_Constraint, + LimitTechInputSplitAnnual_Constraint, + LimitTechInputSplitAverage_Constraint, + LimitTechOutputSplit_Constraint, + LimitTechOutputSplitAnnual_Constraint, + LimitTechOutputSplitAverage_Constraint, + LinkedEmissionsTech_Constraint, + ParamLoanAnnualize_rule, + ParamPeriodLength, + ParamProcessLifeFraction_rule, + RampDownDay_Constraint, + RampDownSeason_Constraint, + RampUpDay_Constraint, + RampUpSeason_Constraint, + RegionalExchangeCapacity_Constraint, + RenewablePortfolioStandard_Constraint, + ReserveMargin_Constraint, + SeasonalStorageEnergy_Constraint, + SeasonalStorageEnergyUpperBound_Constraint, + SegFracPerSeason_rule, + StorageChargeRate_Constraint, + StorageDischargeRate_Constraint, + StorageEnergy_Constraint, + StorageEnergyUpperBound_Constraint, + StorageThroughput_Constraint, + TotalCost_rule, +) from temoa.model_checking.validators import ( no_slash_or_pipe, region_check, @@ -38,9 +162,6 @@ logger = logging.getLogger(__name__) -# disable linter rule that complains about star imports for this file -# ruff: noqa: F405 - class TemoaModel(AbstractModel): """ @@ -171,7 +292,8 @@ def __init__(M, *args, **kwargs): M.TimeSeason = Set(M.time_optimize, within=M.time_season, ordered=True) M.time_of_day = Set(ordered=True, validate=no_slash_or_pipe) - # This is just to get the TimeStorageSeason table sequentially. There must be a better way but this works for now + # This is just to get the TimeStorageSeason table sequentially. + # There must be a better way but this works for now M.ordered_season_sequential = Set( dimen=3, within=M.time_optimize * M.time_season_sequential * M.time_season, ordered=True ) @@ -216,7 +338,8 @@ def __init__(M, *args, **kwargs): M.tech_exist = Set() """techs with existing capacity, want to keep these for accounting reasons""" - # the below is a convenience for domain checking in params below that should not accept uncap techs... + # the below is a convenience for domain checking in params below that should not accept + # uncap techs... M.tech_with_capacity = Set(initialize=M.tech_all - M.tech_uncap) """techs eligible for capacitization""" # Define techs for which economic retirement is an option @@ -279,10 +402,12 @@ def __init__(M, *args, **kwargs): M.validate_TimeNext = BuildAction(rule=validate_TimeNext) # Define demand- and resource-related parameters - # Dev Note: There does not appear to be a DB table supporting DemandDefaultDistro. This does not - # cause any problems, so let it be for now. + # Dev Note: There does not appear to be a DB table supporting DemandDefaultDistro. + # This does not cause any problems, so let it be for now. # Doesn't seem to be much point in the table. Just clones SegFrac - # M.DemandDefaultDistribution = Param(M.time_optimize, M.time_season, M.time_of_day, mutable=True) + # M.DemandDefaultDistribution = Param( + # M.time_optimize, M.time_season, M.time_of_day, mutable=True + # ) M.DemandSpecificDistribution = Param( M.regions, M.time_optimize, @@ -297,7 +422,8 @@ def __init__(M, *args, **kwargs): M.Demand = Param(M.DemandConstraint_rpc) # Dev Note: This parameter is currently NOT implemented. Preserved for later refactoring - # LimitResource IS implemented but sums cumulatively for a technology rather than resource commodity + # LimitResource IS implemented but sums cumulatively for a technology rather than + # resource commodity # M.ResourceConstraint_rpr = Set(within=M.regions * M.time_optimize * M.commodity_physical) # M.ResourceBound = Param(M.ResourceConstraint_rpr) @@ -306,7 +432,8 @@ def __init__(M, *args, **kwargs): M.ExistingCapacity = Param(M.regionalIndices, M.tech_exist, M.vintage_exist) - # Dev Note: The below is temporarily useful for passing down to validator to find set violations + # Dev Note: The below is temporarily useful for passing down to validator to find + # set violations # Uncomment this assignment, and comment out the orig below it... # M.Efficiency = Param( # Any, Any, Any, Any, Any, @@ -365,9 +492,10 @@ def __init__(M, *args, **kwargs): M.LoanLifetimeProcess_rtv = Set(dimen=3, initialize=LifetimeLoanProcessIndices) - # Dev Note: The LoanLifetimeProcess table *could* be removed. There is no longer a supporting - # table in the database. It is just a "passthrough" now to the default LoanLifetimeTech. - # It is already stitched in to the model, so will leave it for now. Table may be revived. + # Dev Note: The LoanLifetimeProcess table *could* be removed. There is no longer a + # supporting table in the database. It is just a "passthrough" now to the + # default LoanLifetimeTech. It is already stitched in to the model, + # so will leave it for now. Table may be revived. M.LoanLifetimeProcess = Param(M.LoanLifetimeProcess_rtv, default=get_loan_life) @@ -445,7 +573,7 @@ def __init__(M, *args, **kwargs): M.vintage_all, # validate=validate_CapacityFactorProcess, # opting for a quicker validation, just 0->1 validate=validate_0to1, - default=get_default_capacity_factor, # surprisingly slow but only called if a value is missing + default=get_default_capacity_factor, # slow but only called if a value is missing ) M.CapacityConstraint_rpsdtv = Set(dimen=6, initialize=CapacityConstraintIndices) @@ -948,7 +1076,8 @@ def __init__(M, *args, **kwargs): # devnote: deprecated when generalising tech/group columns in Limit tables # M.LimitNewCapacityGroupShareConstraint = Constraint( - # M.LimitNewCapacityGroupShareConstraint_rpgg, rule=LimitNewCapacityGroupShare_Constraint + # M.LimitNewCapacityGroupShareConstraint_rpgg, + # rule=LimitNewCapacityGroupShare_Constraint # ) # M.LimitActivityGroupShareConstraint = Constraint( From c30d54470c79925f4c388209489480896f89db8e Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 7 Oct 2025 21:49:50 -0400 Subject: [PATCH 217/587] small taming of the model file, considering moving to a component formalism instead of the type structure used --- temoa/_internal/temoa_initialize.py | 79 ++++++++++++++++++++++++++++- temoa/_internal/temoa_rules.py | 73 ++++++++++++++++++++++++++ temoa/core/model.py | 28 +++++++++- temoa/model_checking/validators.py | 15 ++++++ 4 files changed, 192 insertions(+), 3 deletions(-) diff --git a/temoa/_internal/temoa_initialize.py b/temoa/_internal/temoa_initialize.py index 066ad3a03..3598fdaff 100644 --- a/temoa/_internal/temoa_initialize.py +++ b/temoa/_internal/temoa_initialize.py @@ -20,7 +20,6 @@ """ from itertools import product as cross_product - from operator import itemgetter as iget from sys import stderr as SE from typing import TYPE_CHECKING, Iterable @@ -47,6 +46,84 @@ # --------------------------------------------------------------- +# ============================================================================ +# Public API - Functions intended for external import +# ============================================================================ +__all__ = [ + # Index creation functions for constraints and variables + 'AnnualCommodityBalanceConstraintIndices', + 'AnnualRetirementVariableIndices', + 'BaseloadDiurnalConstraintIndices', + 'CapacityAnnualConstraintIndices', + 'CapacityAvailableVariableIndices', + 'CapacityConstraintIndices', + 'CapacityFactorTechIndices', + 'CapacityVariableIndices', + 'CommodityBalanceConstraintIndices', + 'CostFixedIndices', + 'CostVariableIndices', + 'CurtailmentVariableIndices', + 'DemandActivityConstraintIndices', + 'EmissionActivityIndices', + 'FlexVariableAnnualIndices', + 'FlexVariablelIndices', + 'FlowInStorageVariableIndices', + 'FlowVariableAnnualIndices', + 'FlowVariableIndices', + 'LifetimeLoanProcessIndices', + 'LifetimeProcessIndices', + 'LimitDegrowthCapacityIndices', + 'LimitDegrowthNewCapacityDeltaIndices', + 'LimitDegrowthNewCapacityIndices', + 'LimitGrowthCapacityIndices', + 'LimitGrowthNewCapacityDeltaIndices', + 'LimitGrowthNewCapacityIndices', + 'LimitTechInputSplitAnnualConstraintIndices', + 'LimitTechInputSplitAverageConstraintIndices', + 'LimitTechInputSplitConstraintIndices', + 'LimitTechOutputSplitAnnualConstraintIndices', + 'LimitTechOutputSplitAverageConstraintIndices', + 'LimitTechOutputSplitConstraintIndices', + 'LinkedTechConstraintIndices', + 'ModelProcessLifeIndices', + 'RampDownDayConstraintIndices', + 'RampDownSeasonConstraintIndices', + 'RampUpDayConstraintIndices', + 'RampUpSeasonConstraintIndices', + 'RegionalExchangeCapacityConstraintIndices', + 'ReserveMarginIndices', + 'RetiredCapacityVariableIndices', + 'SeasonalStorageConstraintIndices', + 'SeasonalStorageLevelVariableIndices', + 'StorageConstraintIndices', + 'StorageLevelVariableIndices', + # Validation and initialization functions + 'CheckCapacityFactorProcess', + 'CheckEfficiencyIndices', + 'CheckEfficiencyVariable', + 'CreateDemands', + 'CreateRegionalIndices', + 'CreateSparseDicts', + 'CreateSurvivalCurve', + 'CreateTimeSeasonSequential', + 'CreateTimeSequence', + # Default value functions + 'get_default_capacity_factor', + 'get_default_loan_rate', + 'get_default_process_lifetime', + 'get_default_survival', + 'get_loan_life', + # Set initialization functions + 'init_set_time_optimize', + 'init_set_vintage_exist', + 'init_set_vintage_optimize', + # Validation functions + 'validate_SegFrac', + 'validate_time', + 'validate_TimeNext', +] + + def isValidProcess(M: 'TemoaModel', r, p, i, t, v, o): """\ Returns a boolean (True or False) indicating whether, in any given period, a diff --git a/temoa/_internal/temoa_rules.py b/temoa/_internal/temoa_rules.py index 4de98a9f3..84ed1ca9d 100644 --- a/temoa/_internal/temoa_rules.py +++ b/temoa/_internal/temoa_rules.py @@ -38,6 +38,79 @@ from temoa.core.model import TemoaModel logger = getLogger(__name__) + + +# ============================================================================ +# Public API - Functions intended for external import +# ============================================================================ +__all__ = [ + # Core capacity constraints + 'AdjustedCapacity_Constraint', + 'Capacity_Constraint', + 'CapacityAnnual_Constraint', + 'CapacityAvailableByPeriodAndTech_Constraint', + # Activity and flow constraints + 'Demand_Constraint', + 'DemandActivity_Constraint', + 'CommodityBalance_Constraint', + 'AnnualCommodityBalance_Constraint', + # Retirement constraints + 'AnnualRetirement_Constraint', + # Storage constraints + 'StorageEnergy_Constraint', + 'StorageEnergyUpperBound_Constraint', + 'SeasonalStorageEnergy_Constraint', + 'SeasonalStorageEnergyUpperBound_Constraint', + 'StorageChargeRate_Constraint', + 'StorageDischargeRate_Constraint', + 'StorageThroughput_Constraint', + # Ramping constraints + 'BaseloadDiurnal_Constraint', + 'RampUpDay_Constraint', + 'RampDownDay_Constraint', + 'RampUpSeason_Constraint', + 'RampDownSeason_Constraint', + # Limit constraints (capacity, activity, emissions, etc.) + 'LimitActivity_Constraint', + 'LimitActivityShare_Constraint', + 'LimitAnnualCapacityFactor_Constraint', + 'LimitCapacity_Constraint', + 'LimitCapacityShare_Constraint', + 'LimitEmission_Constraint', + 'LimitNewCapacity_Constraint', + 'LimitNewCapacityShare_Constraint', + 'LimitResource_Constraint', + 'LimitSeasonalCapacityFactor_Constraint', + 'LimitStorageFraction_Constraint', + # Technology split constraints + 'LimitTechInputSplit_Constraint', + 'LimitTechInputSplitAnnual_Constraint', + 'LimitTechInputSplitAverage_Constraint', + 'LimitTechOutputSplit_Constraint', + 'LimitTechOutputSplitAnnual_Constraint', + 'LimitTechOutputSplitAverage_Constraint', + # Growth/degrowth constraints + 'LimitDegrowthCapacityConstraint_rule', + 'LimitDegrowthNewCapacityConstraint_rule', + 'LimitDegrowthNewCapacityDeltaConstraint_rule', + 'LimitGrowthCapacityConstraint_rule', + 'LimitGrowthNewCapacityConstraint_rule', + 'LimitGrowthNewCapacityDeltaConstraint_rule', + # Regional and special constraints + 'RegionalExchangeCapacity_Constraint', + 'RenewablePortfolioStandard_Constraint', + 'ReserveMargin_Constraint', + 'LinkedEmissionsTech_Constraint', + # Parameter calculation rules + 'ParamLoanAnnualize_rule', + 'ParamPeriodLength', + 'ParamProcessLifeFraction_rule', + 'SegFracPerSeason_rule', + # Objective function + 'TotalCost_rule', +] + + # --------------------------------------------------------------- # Define the derived variables used in the objective function # and constraints below. diff --git a/temoa/core/model.py b/temoa/core/model.py index 74ebbf9b8..c3f1d9e4b 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -24,6 +24,9 @@ ) from temoa._internal.temoa_initialize import ( + # ============================================================================ + # Index creation functions for constraints and variables + # ============================================================================ AnnualCommodityBalanceConstraintIndices, AnnualRetirementVariableIndices, BaseloadDiurnalConstraintIndices, @@ -79,36 +82,48 @@ SeasonalStorageLevelVariableIndices, StorageConstraintIndices, StorageLevelVariableIndices, + # Default value functions get_default_capacity_factor, get_default_loan_rate, get_default_process_lifetime, get_default_survival, get_loan_life, + # Set initialization functions init_set_time_optimize, init_set_vintage_exist, init_set_vintage_optimize, + # Validation functions validate_SegFrac, validate_time, validate_TimeNext, ) -# from temoa._internal.temoa_rules import * +# ============================================================================ +# Temoa Constraint Functions +# Core model constraints and business logic rules +# ============================================================================ from temoa._internal.temoa_rules import ( + # Core capacity constraints AdjustedCapacity_Constraint, AnnualCommodityBalance_Constraint, + # Retirement constraints AnnualRetirement_Constraint, + # Ramping constraints BaseloadDiurnal_Constraint, Capacity_Constraint, CapacityAnnual_Constraint, CapacityAvailableByPeriodAndTech_Constraint, CommodityBalance_Constraint, + # Activity and flow constraints Demand_Constraint, DemandActivity_Constraint, + # Limit constraints (capacity, activity, emissions, etc.) LimitActivity_Constraint, LimitActivityShare_Constraint, LimitAnnualCapacityFactor_Constraint, LimitCapacity_Constraint, LimitCapacityShare_Constraint, + # Growth/degrowth constraints LimitDegrowthCapacityConstraint_rule, LimitDegrowthNewCapacityConstraint_rule, LimitDegrowthNewCapacityDeltaConstraint_rule, @@ -121,6 +136,7 @@ LimitResource_Constraint, LimitSeasonalCapacityFactor_Constraint, LimitStorageFraction_Constraint, + # Technology split constraints LimitTechInputSplit_Constraint, LimitTechInputSplitAnnual_Constraint, LimitTechInputSplitAverage_Constraint, @@ -128,6 +144,7 @@ LimitTechOutputSplitAnnual_Constraint, LimitTechOutputSplitAverage_Constraint, LinkedEmissionsTech_Constraint, + # Parameter calculation rules ParamLoanAnnualize_rule, ParamPeriodLength, ParamProcessLifeFraction_rule, @@ -135,6 +152,7 @@ RampDownSeason_Constraint, RampUpDay_Constraint, RampUpSeason_Constraint, + # Regional and special constraints RegionalExchangeCapacity_Constraint, RenewablePortfolioStandard_Constraint, ReserveMargin_Constraint, @@ -143,16 +161,22 @@ SegFracPerSeason_rule, StorageChargeRate_Constraint, StorageDischargeRate_Constraint, + # Storage constraints StorageEnergy_Constraint, StorageEnergyUpperBound_Constraint, StorageThroughput_Constraint, + # Objective function TotalCost_rule, ) + +# ============================================================================ +# Validation Functions +# Input validation and data integrity checks +# ============================================================================ from temoa.model_checking.validators import ( no_slash_or_pipe, region_check, region_group_check, - # validate_CapacityFactorProcess, validate_0to1, validate_Efficiency, validate_linked_tech, diff --git a/temoa/model_checking/validators.py b/temoa/model_checking/validators.py index e05099505..4ab092c8b 100644 --- a/temoa/model_checking/validators.py +++ b/temoa/model_checking/validators.py @@ -39,6 +39,21 @@ logger = getLogger(__name__) +# ============================================================================ +# Public API - Functions intended for external import +# ============================================================================ +__all__ = [ + 'no_slash_or_pipe', + 'region_check', + 'region_group_check', + 'validate_0to1', + 'validate_Efficiency', + 'validate_linked_tech', + 'validate_ReserveMargin', + 'validate_tech_sets', +] + + def validate_linked_tech(M: 'TemoaModel') -> bool: """ A validation that for all the linked techs, they have the same lifetime in each possible vintage From 2dc439c04507bf4fd4d7efaa5eae54644d1bd575 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 8 Oct 2025 08:22:27 -0400 Subject: [PATCH 218/587] adding placeholder files for component structure --- temoa/components/capacity.py | 0 temoa/components/commodities.py | 0 temoa/components/costs.py | 0 temoa/components/emissions.py | 0 temoa/components/limits.py | 0 temoa/components/ramping.py | 0 temoa/components/reserves.py | 0 temoa/components/storage.py | 0 temoa/components/technology.py | 0 temoa/components/time.py | 0 10 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 temoa/components/capacity.py create mode 100644 temoa/components/commodities.py create mode 100644 temoa/components/costs.py create mode 100644 temoa/components/emissions.py create mode 100644 temoa/components/limits.py create mode 100644 temoa/components/ramping.py create mode 100644 temoa/components/reserves.py create mode 100644 temoa/components/storage.py create mode 100644 temoa/components/technology.py create mode 100644 temoa/components/time.py diff --git a/temoa/components/capacity.py b/temoa/components/capacity.py new file mode 100644 index 000000000..e69de29bb diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py new file mode 100644 index 000000000..e69de29bb diff --git a/temoa/components/costs.py b/temoa/components/costs.py new file mode 100644 index 000000000..e69de29bb diff --git a/temoa/components/emissions.py b/temoa/components/emissions.py new file mode 100644 index 000000000..e69de29bb diff --git a/temoa/components/limits.py b/temoa/components/limits.py new file mode 100644 index 000000000..e69de29bb diff --git a/temoa/components/ramping.py b/temoa/components/ramping.py new file mode 100644 index 000000000..e69de29bb diff --git a/temoa/components/reserves.py b/temoa/components/reserves.py new file mode 100644 index 000000000..e69de29bb diff --git a/temoa/components/storage.py b/temoa/components/storage.py new file mode 100644 index 000000000..e69de29bb diff --git a/temoa/components/technology.py b/temoa/components/technology.py new file mode 100644 index 000000000..e69de29bb diff --git a/temoa/components/time.py b/temoa/components/time.py new file mode 100644 index 000000000..e69de29bb From 1b42d776075093f21a45325ac8ef2bb56be76d90 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 8 Oct 2025 10:06:18 -0400 Subject: [PATCH 219/587] distributing temoa_initialize into components --- pyproject.toml | 3 + temoa/_internal/temoa_initialize.py | 1610 +-------------------------- temoa/_internal/temoa_rules.py | 70 +- temoa/components/capacity.py | 211 ++++ temoa/components/commodities.py | 258 +++++ temoa/components/costs.py | 95 ++ temoa/components/emissions.py | 30 + temoa/components/flows.py | 28 + temoa/components/geography.py | 50 + temoa/components/limits.py | 146 +++ temoa/components/operations.py | 16 + temoa/components/ramping.py | 73 ++ temoa/components/reserves.py | 17 + temoa/components/storage.py | 26 + temoa/components/technology.py | 284 +++++ temoa/components/time.py | 346 ++++++ temoa/core/model.py | 244 ++-- 17 files changed, 1723 insertions(+), 1784 deletions(-) create mode 100644 temoa/components/flows.py create mode 100644 temoa/components/geography.py create mode 100644 temoa/components/operations.py diff --git a/pyproject.toml b/pyproject.toml index 26a9354fe..29c182b65 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -77,6 +77,9 @@ select = [ "I", # isort "B", # flake8-bugbear ] +ignore = [ + "E501", # line too long temporarily ignored +] [tool.pytest.ini_options] minversion = "8.0" diff --git a/temoa/_internal/temoa_initialize.py b/temoa/_internal/temoa_initialize.py index 3598fdaff..c94ef158e 100644 --- a/temoa/_internal/temoa_initialize.py +++ b/temoa/_internal/temoa_initialize.py @@ -19,12 +19,9 @@ received this license file. If not, see . """ -from itertools import product as cross_product -from operator import itemgetter as iget from sys import stderr as SE -from typing import TYPE_CHECKING, Iterable +from typing import TYPE_CHECKING -from deprecated import deprecated from pyomo.core import Set if TYPE_CHECKING: @@ -35,7 +32,7 @@ from pyomo.environ import value -logger = getLogger(__name__) +logger = getLogger(name=__name__) # --------------------------------------------------------------- @@ -51,76 +48,7 @@ # ============================================================================ __all__ = [ # Index creation functions for constraints and variables - 'AnnualCommodityBalanceConstraintIndices', - 'AnnualRetirementVariableIndices', - 'BaseloadDiurnalConstraintIndices', - 'CapacityAnnualConstraintIndices', - 'CapacityAvailableVariableIndices', - 'CapacityConstraintIndices', - 'CapacityFactorTechIndices', - 'CapacityVariableIndices', - 'CommodityBalanceConstraintIndices', - 'CostFixedIndices', - 'CostVariableIndices', - 'CurtailmentVariableIndices', - 'DemandActivityConstraintIndices', - 'EmissionActivityIndices', - 'FlexVariableAnnualIndices', - 'FlexVariablelIndices', - 'FlowInStorageVariableIndices', - 'FlowVariableAnnualIndices', - 'FlowVariableIndices', - 'LifetimeLoanProcessIndices', - 'LifetimeProcessIndices', - 'LimitDegrowthCapacityIndices', - 'LimitDegrowthNewCapacityDeltaIndices', - 'LimitDegrowthNewCapacityIndices', - 'LimitGrowthCapacityIndices', - 'LimitGrowthNewCapacityDeltaIndices', - 'LimitGrowthNewCapacityIndices', - 'LimitTechInputSplitAnnualConstraintIndices', - 'LimitTechInputSplitAverageConstraintIndices', - 'LimitTechInputSplitConstraintIndices', - 'LimitTechOutputSplitAnnualConstraintIndices', - 'LimitTechOutputSplitAverageConstraintIndices', - 'LimitTechOutputSplitConstraintIndices', - 'LinkedTechConstraintIndices', - 'ModelProcessLifeIndices', - 'RampDownDayConstraintIndices', - 'RampDownSeasonConstraintIndices', - 'RampUpDayConstraintIndices', - 'RampUpSeasonConstraintIndices', - 'RegionalExchangeCapacityConstraintIndices', - 'ReserveMarginIndices', - 'RetiredCapacityVariableIndices', - 'SeasonalStorageConstraintIndices', - 'SeasonalStorageLevelVariableIndices', - 'StorageConstraintIndices', - 'StorageLevelVariableIndices', - # Validation and initialization functions - 'CheckCapacityFactorProcess', - 'CheckEfficiencyIndices', - 'CheckEfficiencyVariable', - 'CreateDemands', - 'CreateRegionalIndices', 'CreateSparseDicts', - 'CreateSurvivalCurve', - 'CreateTimeSeasonSequential', - 'CreateTimeSequence', - # Default value functions - 'get_default_capacity_factor', - 'get_default_loan_rate', - 'get_default_process_lifetime', - 'get_default_survival', - 'get_loan_life', - # Set initialization functions - 'init_set_time_optimize', - 'init_set_vintage_exist', - 'init_set_vintage_optimize', - # Validation functions - 'validate_SegFrac', - 'validate_time', - 'validate_TimeNext', ] @@ -139,631 +67,6 @@ def isValidProcess(M: 'TemoaModel', r, p, i, t, v, o): return False -def get_str_padding(obj): - return len(str(obj)) - - -def CommodityBalanceConstraintErrorCheck(supplied, demanded, r, p, s, d, c): - # note: if a pyomo equation simplifies to an int, there are no variables in it, which - # is an indicator of a problem. How this might come up I do not know - if isinstance(supplied, int) or isinstance(demanded, int): - expr = str(supplied == demanded) - msg = ( - 'Unable to balance commodity {} in ({}, {}, {}, {}).\n' - 'No flows on one side of constraint expression:\n' - ' {}\n' - 'Possible reasons:\n' - " - Is there a missing period in set 'time_future'?\n" - " - Is there a missing tech in set 'tech_resource'?\n" - " - Is there a missing tech in set 'tech_production'?\n" - " - Is there a missing commodity in set 'commodity_physical'?\n" - ' - Are there missing entries in the Efficiency table?\n' - ' - Does a process need a longer Lifetime?' - ) - logger.error(msg.format(c, r, p, s, d, expr)) - raise Exception(msg.format(c, r, p, s, d, expr)) - - -def AnnualCommodityBalanceConstraintErrorCheck(supplied, demanded, r, p, c): - # note: if a pyomo equation simplifies to an int, there are no variables in it, which - # is an indicator of a problem. How this might come up I do not know - if isinstance(supplied, int) or isinstance(demanded, int): - expr = str(supplied == demanded) - msg = ( - 'Unable to balance annual commodity {} in ({}, {}).\n' - 'No flows on one side of constraint expression:\n' - ' {}\n' - 'Possible reasons:\n' - " - Is there a missing period in set 'time_future'?\n" - " - Is there a missing tech in set 'tech_resource'?\n" - " - Is there a missing tech in set 'tech_production'?\n" - " - Is there a missing commodity in set 'commodity_physical'?\n" - ' - Are there missing entries in the Efficiency table?\n' - ' - Does a process need a longer Lifetime?' - ) - logger.error(msg.format(c, r, p, expr)) - raise Exception(msg.format(c, r, p, expr)) - - -def DemandConstraintErrorCheck(supply, r, p, dem): - # note: if a pyomo equation simplifies to an int, there are no variables in it, which - # is an indicator of a problem - if isinstance(supply, int): - msg = ( - "Error: Demand '{}' for ({}, {}) unable to be met by any " - 'technology.\n\tPossible reasons:\n' - ' - Is the Efficiency parameter missing an entry for this demand?\n' - ' - Does a tech that satisfies this demand need a longer ' - 'Lifetime?\n' - ) - logger.error(msg.format(dem, r, p)) - raise Exception(msg.format(dem, r, p)) - - -def validate_time(M: 'TemoaModel'): - """ - We check for integer status here, rather than asking Pyomo to do this via - a 'within=Integers' clause in the definition so that we can have a very - specific error message. If we instead use Pyomo's mechanism, the - python invocation of Temoa throws an error (including a traceback) - that has proven to be scary and/or impenetrable for the typical modeler. - """ - logger.debug('Started validating time index') - for year in M.time_exist: - if isinstance(year, int): - continue - - msg = f'Set "time_exist" requires integer-only elements.\n\n Invalid element: "{year}"' - logger.error(msg) - raise Exception(msg) - - for year in M.time_future: - if isinstance(year, int): - continue - - msg = f'Set "time_future" requires integer-only elements.\n\n invalid element: "{year}"' - logger.error(msg) - raise Exception(msg) - - if len(M.time_future) < 2: - msg = ( - 'Set "time_future" needs at least 2 specified years. \nTemoa ' - 'treats the integer numbers specified in this set as boundary years \n' - 'between periods, and uses them to automatically ascertain the length \n' - '(in years) of each period. Note that this means that there will be \n' - 'one less optimization period than the number of elements in this set.' - ) - - logger.error(msg) - raise RuntimeError(msg) - - # Ensure that the time_exist < time_future - if len(M.time_exist) > 0: - max_exist = max(M.time_exist) - min_horizon = min(M.time_future) - - if not (max_exist < min_horizon): - msg = ( - 'All items in time_future must be larger than in time_exist.' - '\ntime_exist max: {}' - '\ntime_future min: {}' - ) - logger.error(msg.format(max_exist, min_horizon)) - raise Exception(msg.format(max_exist, min_horizon)) - logger.debug('Finished validating time') - - -def validate_SegFrac(M: 'TemoaModel'): - """Ensure that the segment fractions adds up to 1""" - - for p in M.time_optimize: - expected_keys = set((p, s, d) for s in M.TimeSeason[p] for d in M.time_of_day) - keys = set((_p, s, d) for _p, s, d in M.SegFrac.sparse_iterkeys() if _p == p) - - if expected_keys != keys: - extra = keys.difference(expected_keys) - missing = expected_keys.difference(keys) - msg = ( - 'TimeSegmentFraction elements for period {} do not match TimeSeason and TimeOfDay.' - '\n\nIndices missing from TimeSegmentFraction:\n{}' - '\n\nIndices in TimeSegmentFraction missing from TimeSeason/TimeOfDay:\n{}' - ).format(p, missing, extra) - logger.error(msg) - raise ValueError(msg) - - total = sum(M.SegFrac[k] for k in keys) - - if abs(float(total) - 1.0) > 0.001: - # We can't explicitly test for "!= 1.0" because of incremental rounding - # errors associated with the specification of SegFrac by time slice, - # but we check to make sure it is within the specified tolerance. - - key_padding = max(map(get_str_padding, keys)) - - fmt = '%%-%ds = %%s' % key_padding - # Works out to something like "%-25s = %s" - - items = sorted([(k, M.SegFrac[k]) for k in keys]) - items = '\n '.join(fmt % (str(k), v) for k, v in items) - - msg = ( - 'The values of TimeSegmentFraction do not sum to 1 for period {}. ' - 'Each item in SegFrac represents a fraction of a year, so they must ' - 'total to 1. Current values:\n {}\n\tsum = {}' - ).format(p, items, total) - logger.error(msg) - raise Exception(msg) - - -def validate_TimeNext(M: 'TemoaModel'): - """ - If using this table, check that defined states are actually valid. - TimeSegmentFraction is already compared to other tables so just compare to SegFrac. - """ - # Only check TimeNext if it is actually being used - if M.TimeSequencing.first() != 'manual': - return - - segfrac_psd = set(M.SegFrac.sparse_iterkeys()) - time_next_psd = set((p, s, d) for p, s, d, s_next, d_next in M.TimeNext) - time_next_psd_next = set((p, s_next, d_next) for p, s, d, s_next, d_next in M.TimeNext) - - missing_psd = segfrac_psd.difference(time_next_psd) - missing_psd_next = segfrac_psd.difference(time_next_psd_next) - if missing_psd or missing_psd_next: - msg = ( - 'Failed to build state sequence. ' - '\nThese states from TimeSegmentFraction were not given a next state:\n{}\n' - '\nThese states from TimeSegmentFraction do not follow any state:\n{}' - ).format(missing_psd, missing_psd_next) - logger.error(msg) - raise ValueError(msg) - - -def CheckEfficiencyIndices(M: 'TemoaModel'): - """ - Ensure that there are no unused items in any of the Efficiency index sets. - """ - # TODO: This could be upgraded to scan for finer resolution - # by checking by REGION and PERIOD... Each region/period is unique. - c_physical = set(i for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) - c_physical = c_physical | set(i for r, i, t, v in M.ConstructionInput.sparse_iterkeys()) - techs = set(t for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) - c_outputs = set(o for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) - c_outputs = c_outputs | set(o for r, t, v, o in M.EndOfLifeOutput.sparse_iterkeys()) - - symdiff = c_physical.symmetric_difference(M.commodity_physical) - if symdiff: - msg = ( - 'Unused or unspecified physical carriers. Either add or remove ' - 'the following elements to the Set commodity_physical.' - '\n\n Element(s): {}' - ) - symdiff = (str(i) for i in symdiff) - f_msg = msg.format(', '.join(symdiff)) - logger.error(f_msg) - raise ValueError(f_msg) - - symdiff = techs.symmetric_difference(M.tech_all) - if symdiff: - msg = ( - 'Unused or unspecified technologies. Either add or remove ' - 'the following technology(ies) to the tech_resource or ' - 'tech_production Sets.\n\n Technology(ies): {}' - ) - symdiff = (str(i) for i in symdiff) - f_msg = msg.format(', '.join(symdiff)) - logger.error(f_msg) - raise ValueError(f_msg) - - diff = M.commodity_demand - c_outputs - if diff: - msg = ( - 'Unused or unspecified outputs. Either add or remove the ' - 'following elements to the commodity_demand Set.' - '\n\n Element(s): {}' - ) - diff = (str(i) for i in diff) - f_msg = msg.format(', '.join(diff)) - logger.error(f_msg) - raise ValueError(f_msg) - - -def CheckEfficiencyVariable(M: 'TemoaModel'): - count_rpitvo = dict() - # Pull non-variable efficiency by default - for r, i, t, v, o in M.Efficiency.sparse_iterkeys(): - if (r, t, v) not in M.processPeriods: - # Probably an existing vintage that retires in p0 - # Still want it for end of life flows - continue - for p in M.processPeriods[r, t, v]: - M.isEfficiencyVariable[r, p, i, t, v, o] = False - count_rpitvo[r, p, i, t, v, o] = 0 - - annual = set() - # Check for bad values and count up the good ones - for r, p, s, d, i, t, v, o in M.EfficiencyVariable.sparse_iterkeys(): - if p not in M.processPeriods[r, t, v]: - msg = f'Invalid period {p} for process {r, t, v} in EfficiencyVariable table' - logger.error(msg) - raise ValueError(msg) - - if t in M.tech_annual: - annual.add(t) - - # Good value, pull from EfficiencyVariable table - count_rpitvo[r, p, i, t, v, o] += 1 - - for t in annual: - msg = ( - f'Variable efficiencies were provided for the annual technology {t}, which has ' - 'no variable output. This will only be applied to flows on non-annual commodities. ' - 'This is ambiguous behaviour and not recommended.' - ) - logger.warning(msg) - - # Check if all possible values have been set as variable - # log a warning if some are missing (allowed but maybe accidental) - num_seg = len(M.TimeSeason[p]) * len(M.time_of_day) - for (r, p, i, t, v, o), count in count_rpitvo.items(): - if count > 0: - M.isEfficiencyVariable[r, p, i, t, v, o] = True - if count < num_seg: - logger.info( - 'Some but not all EfficiencyVariable values were set (%i out of a possible %i) for: %s' - ' Missing values will default to value set in Efficiency table.', - count, - num_seg, - (r, p, i, t, v, o), - ) - - -def CheckCapacityFactorProcess(M: 'TemoaModel'): - count_rptv = dict() - # Pull CapacityFactorTech by default - for r, p, s, d, t in M.CapacityFactor_rpsdt: - for v in M.processVintages[r, p, t]: - M.isCapacityFactorProcess[r, p, t, v] = False - count_rptv[r, p, t, v] = 0 - - # Check for bad values and count up the good ones - for r, p, s, d, t, v in M.CapacityFactorProcess.sparse_iterkeys(): - if v not in M.processVintages[r, p, t]: - msg = f'Invalid process {p, v} for {r, t} in CapacityFactorProcess table' - logger.error(msg) - raise ValueError(msg) - - # Good value, pull from CapacityFactorProcess table - count_rptv[r, p, t, v] += 1 - - # Check if all possible values have been set by process - # log a warning if some are missing (allowed but maybe accidental) - for (r, p, t, v), count in count_rptv.items(): - num_seg = len(M.TimeSeason[p]) * len(M.time_of_day) - if count > 0: - M.isCapacityFactorProcess[r, p, t, v] = True - if count < num_seg: - logger.info( - 'Some but not all processes were set in CapacityFactorProcess (%i out of a possible %i) for: %s' - ' Missing values will default to CapacityFactorTech value or 1 if that is not set either.', - count, - num_seg, - (r, p, t, v), - ) - - -@deprecated('should not be needed. We are pulling the default on-the-fly where used') -def CreateCapacityFactors(M: 'TemoaModel'): - """ - Steps to creating capacity factors: - 1. Collect all possible processes - 2. Find the ones _not_ specified in CapacityFactorProcess - 3. Set them, based on CapacityFactorTech. - """ - # Shorter names, for us lazy programmer types - CFP = M.CapacityFactorProcess - - # Step 1 - processes = set((r, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) - - all_cfs = set( - (r, p, s, d, t, v) - for (r, t, v) in processes - for p in M.processPeriods[r, t, v] - for s, d in cross_product(M.TimeSeason[p], M.time_of_day) - ) - - # Step 2 - unspecified_cfs = all_cfs.difference(CFP.sparse_iterkeys()) - - # Step 3 - - # Some hackery: We futz with _constructed because Pyomo thinks that this - # Param is already constructed. However, in our view, it is not yet, - # because we're specifically targeting values that have not yet been - # constructed, that we know are valid, and that we will need. - - if unspecified_cfs: - # CFP._constructed = False - for r, s, d, t, v in unspecified_cfs: - CFP[r, s, d, t, v] = M.CapacityFactorTech[r, s, d, t] - logger.debug( - 'Created Capacity Factors for %d processes without an explicit specification', - len(unspecified_cfs), - ) - # CFP._constructed = True - - -def get_default_survival(M: 'TemoaModel', r, p, t, v): - """ - Getting LifetimeSurvivalCurve where it is not defined - If this is a survival curve process, return 0 (likely beyond EOL) - Otherwise return 1 (no survival curve based EOL) - """ - if M.isSurvivalCurveProcess[r, t, v]: - return 0 - else: - return 1 - - -def get_default_process_lifetime(M: 'TemoaModel', r, t, v): - """ - This initializer used to initialize the LifetimeProcess parameter from LifetimeTech where needed - - Priority: - 1. Specified in LifetimeProcess data (provided as a fill and would not call this function) - 2. Specified in LifetimeTech data - 3. The default value from the LifetimeTech param (automatic) - :param M: generic model reference (not used) - :param r: region - :param t: tech - :param v: vintage - :return: the final lifetime value - """ - return M.LifetimeTech[r, t] - - -def get_default_capacity_factor(M: 'TemoaModel', r, p, s, d, t, v): - """ - This initializer is used to fill the CapacityFactorProcess from the CapacityFactorTech where needed. - - Priority: - 1. As specified in data input (this function not called) - 2. Here - 3. The default from CapacityFactorTech param - :param M: generic model reference - :param r: region - :param s: season - :param d: time-of-day slice - :param t: tech - :param v: vintage - :return: the capacity factor - """ - return M.CapacityFactorTech[r, p, s, d, t] - - -def get_default_loan_rate(M: 'TemoaModel', *_): - """get the default loan rate from the DefaultLoanRate param""" - return M.DefaultLoanRate() - - -def CreateDemands(M: 'TemoaModel'): - """ - Steps to create the demand distributions - 1. Use Demand keys to ensure that all demands in commodity_demand are used - 2. Find any slices not set in DemandDefaultDistribution, and set them based - on the associated SegFrac slice. - 3. Validate that the DemandDefaultDistribution sums to 1. - 4. Find any per-demand DemandSpecificDistribution values not set, and set - them from DemandDefaultDistribution. Note that this only sets a - distribution for an end-use demand if the user has *not* specified _any_ - anything for that end-use demand. Thus, it is up to the user to fully - specify the distribution, or not. No in-between. - 5. Validate that the per-demand distributions sum to 1. - """ - logger.debug('Started creating demand distributions in CreateDemands()') - - # Step 0: some setup for a couple of reusable items - # Get the nth element from the tuple (r, p, s, d, dem) - # So we only have to update these indices in one place if they change - DSD_region = iget(0) - DSD_period = iget(1) - DSD_dem = iget(4) - - # Step 1: Check if any demand commodities are going unused - used_dems = set(dem for r, p, dem in M.Demand.sparse_iterkeys()) - unused_dems = sorted(M.commodity_demand.difference(used_dems)) - if unused_dems: - for dem in unused_dems: - msg = "Warning: Demand '{}' is unused\n" - logger.warning(msg.format(dem)) - SE.write(msg.format(dem)) - - # devnote: DDD just clones SegFrac. Unless we want to specify it in the database, - # makes sense to just use SegFrac directly - # Step 2: Build the demand default distribution (= segfrac) - # DDD = M.DemandDefaultDistribution # Shorter, for us lazy programmer types - # unset_defaults = set(M.SegFrac.sparse_iterkeys()) - # unset_defaults.difference_update(DDD.sparse_iterkeys()) - # if unset_defaults: - # Some hackery because Pyomo thinks that this Param is constructed. - # However, in our view, it is not yet, because we're specifically - # targeting values that have not yet been constructed, that we know are - # valid, and that we will need. - # DDD._constructed = False - # for tslice in unset_defaults: - # DDD[tslice] = M.SegFrac[tslice] # DDD._constructed = True - - # Step 3: Check that DDD sums to 1 - # devnote: this seems redundant to the SegFrac sum to 1 check. - # total = sum(i for i in DDD.values()) - # if abs(value(total) - 1.0) > 0.001: - # # We can't explicitly test for "!= 1.0" because of incremental rounding - # # errors associated with the specification of demand shares by time slice, - # # but we check to make sure it is within the specified tolerance. - - # key_padding = max(map(get_str_padding, DDD.sparse_iterkeys())) - - # fmt = '%%-%ds = %%s' % key_padding - # # Works out to something like "%-25s = %s" - - # items = sorted(DDD.items()) - # items = '\n '.join(fmt % (str(k), v) for k, v in items) - - # msg = ( - # 'The values of the DemandDefaultDistribution parameter do not ' - # 'sum to 1. The DemandDefaultDistribution specifies how end-use ' - # 'demands are distributed among the time slices (i.e., time_season, ' - # 'time_of_day), so together, the data must total to 1. Current ' - # 'values:\n {}\n\tsum = {}' - # ) - # logger.error(msg.format(items, total)) - # raise ValueError(msg.format(items, total)) - - # Step 4: Fill out demand specific distribution table and check sums to 1 by region and demand - DSD = M.DemandSpecificDistribution - - demands_specified = set(map(DSD_dem, (i for i in DSD.sparse_iterkeys()))) - unset_demand_distributions = used_dems.difference( - demands_specified - ) # the demands not mentioned in DSD *at all* - - if unset_demand_distributions: - for p in M.time_optimize: - unset_distributions = set( - cross_product( - M.regions, (p,), M.TimeSeason[p], M.time_of_day, unset_demand_distributions - ) - ) - for r, p, s, d, dem in unset_distributions: - DSD[r, p, s, d, dem] = value(M.SegFrac[p, s, d]) # DSD._constructed = True - - # Step 5: A final "sum to 1" check for all DSD members (which now should be everything) - # Also check that all keys are made... The demand distro should be supported - # by the full set of (r, p, dem) keys because it is an equality constraint - # and we need to ensure even the zeros are passed in - used_rp_dems = set((r, p, dem) for r, p, dem in M.Demand.sparse_iterkeys()) - for r, p, dem in used_rp_dems: - expected_key_length = len(M.TimeSeason[p]) * len(M.time_of_day) - keys = [ - k - for k in DSD.sparse_iterkeys() - if DSD_region(k) == r and DSD_period(k) == p and DSD_dem(k) == dem - ] - if len(keys) != expected_key_length: - # this could be very slow but only calls when there's a problem - missing = set( - (s, d) - for s in M.TimeSeason[p] - for d in M.time_of_day - if (r, p, s, d, dem) not in keys - ) - logger.info( - 'Missing some time slices for Demand Specific Distribution %s: %s', - (r, p, dem), - missing, - ) - total = sum(value(DSD[i]) for i in keys) - if abs(value(total) - 1.0) > 0.001: - # We can't explicitly test for "!= 1.0" because of incremental rounding - # errors associated with the specification of demand shares by time slice, - # but we check to make sure it is within the specified tolerance. - key_padding = max(map(get_str_padding, keys)) - - fmt = '%%-%ds = %%s' % key_padding - # Works out to something like "%-25s = %s" - - items = sorted((k, value(DSD[k])) for k in keys) - items = '\n '.join(fmt % (str(k), v) for k, v in items) - - msg = ( - 'The values of the DemandSpecificDistribution parameter do not ' - 'sum to 1 for {}. The DemandSpecificDistribution specifies how end-use ' - 'demands are distributed per time-slice (i.e., time_season, ' - 'time_of_day). Within each region, period, end-use demand, then, the distribution ' - 'must total to 1.\n\n Demand-specific distribution in error: ' - ' \n {}\n\tsum = {}' - ) - logger.error(msg.format((r, p, dem), items, total)) - raise ValueError(msg.format((r, p, dem), items, total)) - - logger.debug('Finished creating demand distributions') - - -@deprecated(reason='vintage defaults are no longer available, so this should not be needed') -def CreateCosts(M: 'TemoaModel'): - """ - Steps to creating fixed and variable costs: - 1. Collect all possible cost indices (CostFixed, CostVariable) - 2. Find the ones _not_ specified in CostFixed and CostVariable - 3. Set them, based on Cost*VintageDefault - """ - logger.debug('Started Creating Fixed and Variable costs in CreateCosts()') - # Shorter names, for us lazy programmer types - CF = M.CostFixed - CV = M.CostVariable - - # Step 1 - fixed_indices = set(M.CostFixed_rptv) - var_indices = set(M.CostVariable_rptv) - - # Step 2 - unspecified_fixed_prices = fixed_indices.difference(CF.sparse_iterkeys()) - unspecified_var_prices = var_indices.difference(CV.sparse_iterkeys()) - - # Step 3 - - # Some hackery: We futz with _constructed because Pyomo thinks that this - # Param is already constructed. However, in our view, it is not yet, - # because we're specifically targeting values that have not yet been - # constructed, that we know are valid, and that we will need. - - if unspecified_fixed_prices: - # CF._constructed = False - for r, p, t, v in unspecified_fixed_prices: - if (r, t, v) in M.CostFixedVintageDefault: - CF[r, p, t, v] = M.CostFixedVintageDefault[r, t, v] # CF._constructed = True - - if unspecified_var_prices: - # CV._constructed = False - for r, p, t, v in unspecified_var_prices: - if (r, t, v) in M.CostVariableVintageDefault: - CV[r, p, t, v] = M.CostVariableVintageDefault[r, t, v] - # CV._constructed = True - logger.debug('Created M.CostFixed with size: %d', len(M.CostFixed)) - logger.debug('Created M.CostVariable with size: %d', len(M.CostVariable)) - logger.debug('Finished creating Fixed and Variable costs') - - -def init_set_time_optimize(M: 'TemoaModel'): - return sorted(M.time_future)[:-1] - - -def init_set_vintage_exist(M: 'TemoaModel'): - return sorted(M.time_exist) - - -def init_set_vintage_optimize(M: 'TemoaModel'): - return sorted(M.time_optimize) - - -def CreateRegionalIndices(M: 'TemoaModel'): - """Create the set of all regions and all region-region pairs""" - regional_indices = set() - for r_i in M.regions: - if '-' in r_i: - logger.error("Individual region names can not have '-' in their names: %s", str(r_i)) - raise ValueError("Individual region names can not have '-' in their names: " + str(r_i)) - for r_j in M.regions: - if r_i == r_j: - regional_indices.add(r_i) - else: - regional_indices.add(r_i + '-' + r_j) - # dev note: Sorting these passed them to pyomo in an ordered container and prevents warnings - return sorted(regional_indices) - - # --------------------------------------------------------------- # The functions below perform the sparse matrix indexing, allowing Pyomo to only # create the necessary parameter, variable, and constraint indices. This @@ -1170,273 +473,6 @@ def CreateSparseDicts(M: 'TemoaModel'): logger.debug('Completed creation of SparseDicts') -def CreateTimeSequence(M: 'TemoaModel'): - logger.debug('Creating sequence of time slices.') - - # Establishing sequence of states - match M.TimeSequencing.first(): - case 'consecutive_days': - msg = 'Running a consecutive days database.' - for p in M.time_optimize: - for s, d in M.TimeSeason[p] * M.time_of_day: - M.time_next[p, s, d] = loop_period_next_timeslice(M, p, s, d) - case 'seasonal_timeslices': - msg = 'Running a seasonal time slice database.' - for p in M.time_optimize: - for s, d in M.TimeSeason[p] * M.time_of_day: - M.time_next[p, s, d] = loop_season_next_timeslice(M, p, s, d) - case 'representative_periods': - msg = 'Running a representative periods database.' - for p in M.time_optimize: - for s, d in M.TimeSeason[p] * M.time_of_day: - M.time_next[p, s, d] = loop_season_next_timeslice(M, p, s, d) - case 'manual': - # Hidden feature. Define the sequence directly in the TimeNext table - msg = 'Pulling time sequence from TimeNext table.' - for p, s, d, s_next, d_next in M.TimeNext: - M.time_next[p, s, d] = s_next, d_next - case _: - # This should have been caught in hybrid_loader - msg = f"Invalid time sequencing parameter loaded '{M.TimeSequencing.first()}'. Likely code error." - logger.error(msg) - raise ValueError(msg) - - msg += ' This behaviour can be changed using the time_sequencing parameter in the config file. ' - logger.info(msg) - - logger.debug('Creating superimposed sequential seasons.') - - # Superimposed sequential seasons - for p in M.time_optimize: - seasons = [(s_seq, s) for _p, s_seq, s in M.ordered_season_sequential if _p == p] - for i, (s_seq, s) in enumerate(seasons): - M.sequential_to_season[p, s_seq] = s - if (s_seq, s) == seasons[-1]: - M.time_next_sequential[p, s_seq] = seasons[0][0] - else: - M.time_next_sequential[p, s_seq] = seasons[i + 1][0] - - logger.debug('Created time sequence.') - - -def CreateTimeSeasonSequential(M: 'TemoaModel'): - if all( - ( - not M.tech_seasonal_storage, - not M.RampUpHourly, - not M.RampDownHourly, - ) - ): - # Don't need it anyway - return - - if not M.TimeSeasonSequential: - if M.TimeSequencing.first() in ('consecutive_days', 'seasonal_timeslices'): - logger.info( - 'No data in TimeSeasonSequential. By default, assuming sequential seasons ' - 'match TimeSeason and TimeSegmentFraction.' - ) - for s in M.time_season: - M.time_season_sequential.add(s) - for p in M.TimeSeason: - for s in M.TimeSeason[p]: - M.ordered_season_sequential.add((p, s, s)) - M.TimeSeasonSequential[p, s, s] = value(M.SegFracPerSeason[p, s]) * value( - M.DaysPerPeriod - ) - - else: - msg = ( - f'No data in TimeSeasonSequential but time_sequencing parameter set to {M.TimeSequencing.first()} ' - 'and inter-season features used. TimeSeasonSequential must be filled for this type of time ' - 'sequencing if seasonal storage or inter-season constraints like RampUp/RampDown are used. Check ' - 'the config file.' - ) - logger.error(msg) - raise ValueError(msg) - - sequential = dict() - prev_n = 0 - for p, s_seq, s in M.TimeSeasonSequential.sparse_iterkeys(): - num_days = value(M.TimeSeasonSequential[p, s_seq, s]) - if ( - M.TimeSequencing.first() == 'consecutive_days' - and prev_n - and abs(num_days - prev_n) >= 0.001 - ): - msg = ( - 'TimeSequencing set to consecutive_days but two consecutive seasons do not represent the same ' - f'number of days. This discontinuity will lead to bad model behaviour: {p, s}, days: {num_days}. ' - f'Previous number of days: {prev_n}. Check the config file for more information.' - ) - logger.error(msg) - raise ValueError(msg) - prev_n = num_days # for validating next in sequence - - # Regardless of their order, make sure the total number of days adds up - if (p, s) not in sequential: - sequential[p, s] = 0 - sequential[p, s] += num_days - - # Check that TimeSeasonSequential num_days total to number of days in each period - count_total = dict() # {p: n} total days per period according to TimeSeasonSequential - for p in M.time_optimize: - count_total[p] = sum(sequential[p, s] for _p, s in sequential if _p == p) - if abs(count_total[p] - value(M.DaysPerPeriod)) >= 0.001: - logger.warning( - f'Sum of num_days in TimeSeasonSequential ({count_total[p]}) ' - f'for period {p} does not sum to days_per_period ({value(M.DaysPerPeriod)}) ' - 'from the MetaData table.' - ) - - # Check that seasons using in storage seasons are actual seasons - for p, s in sequential: - if (p, s) not in M.SegFracPerSeason: - msg = ( - f'Period-season index {(p, s)} that does not exist in ' - 'TimeSegmentFraction referenced in TimeSeasonSequential .' - ) - logger.error(msg) - raise ValueError(msg) - - for p, s in M.SegFracPerSeason.sparse_iterkeys(): - if s not in M.TimeSeason[p]: - continue - - # Check that all seasons are used in sequential seasons - if (p, s) not in sequential: - msg = f'Period-season index {(p, s)} absent from TimeSeasonSequential' - logger.warning(msg) - - # Check that the two tables agree on the total seasonal composition of each period - segfrac = value(M.SegFracPerSeason[p, s]) - segfracseq = sequential[p, s] / count_total[p] - if abs(segfrac - segfracseq) >= 0.001: - msg = ( - 'Discrepancy of total period-season composition between ' - 'TimeSegmentFraction and TimeSeasonSequential. Total fraction of each ' - 'period assigned to each season should match: ' - f'TimeSegmentFraction: {(p, s, value(M.SegFracPerSeason[p, s]))}' - f', TimeSeasonSequential: {(p, s, segfracseq)}' - ) - logger.warning(msg) - - -def CreateSurvivalCurve(M: 'TemoaModel'): - rtv_interpolated = set() # so we only need one warning - - for r, _, t, v, _ in M.Efficiency.sparse_iterkeys(): - M.isSurvivalCurveProcess[r, t, v] = False # by default - - # Collect rptv indices into (r, t, v): p dictionary - for r, p, t, v in M.LifetimeSurvivalCurve.sparse_iterkeys(): - if (r, t, v) not in M.survivalCurvePeriods: - M.survivalCurvePeriods[r, t, v] = list() - M.survivalCurvePeriods[r, t, v].append(p) - M.isSurvivalCurveProcess[r, t, v] = True - - # Go through all the periods for each (r, t, v) in order - for r, t, v in M.survivalCurvePeriods: - periods_rtv = sorted(M.survivalCurvePeriods[r, t, v]) - - p_first = periods_rtv[0] - p_last = periods_rtv[-1] - - if p_first != v: - msg = ( - 'LifetimeSurvivalCurve must be defined starting in the vintage period. Must ' - f'define ({r}, >{v}<, {t}, {v})' - ) - logger.error(msg) - raise ValueError(msg) - - if value(M.LifetimeSurvivalCurve[r, v, t, v]) != 1: - msg = ( - 'LifetimeSurvivalCurve must begin at 1 for calculating annual retirements. ', - f'Got {value(M.LifetimeSurvivalCurve[r, v, t, v])} for ({r}, {v}, {t}, {v})', - ) - logger.error(msg) - raise ValueError(msg) - - # Collect a list of processes that needed to be interpolated, for warning - if periods_rtv != list(range(p_first, p_last + 1, 1)): - rtv_interpolated.add((r, t, v)) - - between_periods = [] - for i, p in enumerate(periods_rtv): - if i == 0: - continue # Cant look back from first period. Could be zero but hey why not - - # Check that the survival curve monotonically decreases - p_prev = periods_rtv[i - 1] - lsc = value(M.LifetimeSurvivalCurve[r, p, t, v]) - lsc_prev = value(M.LifetimeSurvivalCurve[r, p_prev, t, v]) - if lsc - lsc_prev > 0.0001: - msg = ( - 'LifetimeSurvivalCurve fraction increases going forward in time from {} to {}. ' - 'This is not allowed.' - ).format((r, p_prev, t, v), (r, p, t, v)) - logger.error(msg) - raise ValueError(msg) - - if p - p_prev > 1: - _between_periods = list(range(p_prev + 1, p, 1)) - for _p in _between_periods: - x = (_p - p_prev) / (p - p_prev) - lsc_x = lsc_prev + x * (lsc - lsc_prev) - M.LifetimeSurvivalCurve[r, _p, t, v] = lsc_x - between_periods.extend(_between_periods) - - if lsc < 0.0001: - if p != p_last: - msg = ( - 'There is no need to continue a survival curve beyond fraction ~= 0. ' - f'ignoring periods beyond {p} for ({r, t, v})' - ) - logger.info(msg) - - # Make sure the lifetime for this process aligns with survival curve end - if value(M.LifetimeProcess[r, t, v]) < p - v: - msg = ( - f'The LifetimeProcess parameter for process ({r, t, v}) with survival curve ' - f'does not extend beyond the end of that survival curve in {p}. To agree with ' - f'the survival curve, set LifetimeProcess[{r, t, v}] >= {p - v}' - ) - logger.error(msg) - raise ValueError(msg) - elif value(M.LifetimeProcess[r, t, v]) != p - v: - msg = ( - f'The LifetimeProcess parameter for process ({r, t, v}) with survival curve ' - f'does match the end of that survival curve in {p}. This will waste compute. ' - 'To agree with the survival curve and suppress this warning, set ' - f'LifetimeProcess[{r, t, v}] = {p - v}' - ) - logger.warning(msg) - - continue - - # Flag if the last period is not fraction = 0. This is important for investment costs - if p == p_last and lsc > 0.0001: - msg = ( - 'Any defined survival curve must continue to zero for the purposes of ' - 'investment cost accounting, even if this period would extend beyond ' - f'defined future periods. Continue ({r, t, v}) to fraction == 0.' - ) - logger.error(msg) - raise ValueError(msg) - - M.survivalCurvePeriods[r, t, v].extend(between_periods) - M.survivalCurvePeriods[r, t, v] = set(M.survivalCurvePeriods[r, t, v]) - - if rtv_interpolated: - msg = ( - 'For the purposes of investment cost accounting, LifetimeSurvivalCurve must be defined ' - 'for each individual year. Gaps between defined years will be filled by linear interpolation. ' - 'Otherwise, these individual years can be defined manually. Interpolated processes: {}' - ).format([rtv for rtv in rtv_interpolated]) - logger.info(msg) - - # --------------------------------------------------------------- # Create sparse parameter indices. # These functions are called from temoa_model.py and use the sparse keys @@ -1444,70 +480,6 @@ def CreateSurvivalCurve(M: 'TemoaModel'): # --------------------------------------------------------------- -@deprecated('switched over to validator... this set is typically VERY empty') -def CapacityFactorProcessIndices(M: 'TemoaModel'): - indices = set( - (r, s, d, t, v) - for r, i, t, v, o in M.Efficiency.sparse_iterkeys() - for p in M.time_optimize - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - return indices - - -def CapacityFactorTechIndices(M: 'TemoaModel'): - all_cfs = set( - (r, p, s, d, t) - for r, p, t in M.activeCapacityAvailable_rpt - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - return all_cfs - - -def CostFixedIndices(M: 'TemoaModel'): - # we pull the unlimited capacity techs from this index. They cannot have fixed costs - return {(r, p, t, v) for r, p, t, v in M.activeActivity_rptv if t not in M.tech_uncap} - - -def CostVariableIndices(M: 'TemoaModel'): - return M.activeActivity_rptv - - -# dev note: appears superfluous... -# def CostInvestIndices(M: 'TemoaModel'): -# indices = set((r, t, v) for r, p, t, v in M.processLoans) -# -# return indices - - -@deprecated('No longer used. See the region_group_check in validators.py') -def RegionalGlobalInitializedIndices(M: 'TemoaModel'): - from itertools import permutations - - indices = set() - for n in range(1, len(M.regions) + 1): - regional_perms = permutations(M.regions, n) - for i in regional_perms: - indices.add('+'.join(i)) - indices.add('global') - indices = indices.union(M.regionalIndices) - - return indices - - -def EmissionActivityIndices(M: 'TemoaModel'): - indices = set( - (r, e, i, t, v, o) - for r, i, t, v, o in M.Efficiency.sparse_iterkeys() - for e in M.commodity_emissions - if r in M.regions # omit any exchange/groups - ) - - return indices - - # devnote: this does not appear to be used anywhere # given that it doesnt check if periods are valid, cant think what it would be for # def EmissionActivityByPeriodAndTechVariableIndices(M: 'TemoaModel'): @@ -1518,38 +490,6 @@ def EmissionActivityIndices(M: 'TemoaModel'): # return indices -def ModelProcessLifeIndices(M: 'TemoaModel'): - """\ -Returns the set of sensical (region, period, tech, vintage) tuples. The tuple indicates -the periods in which a process is active, distinct from TechLifeFracIndices that -returns indices only for processes that EOL mid-period. -""" - return M.activeActivity_rptv - - -def LifetimeProcessIndices(M: 'TemoaModel'): - """\ -Based on the Efficiency parameter's indices, this function returns the set of -process indices that may be specified in the LifetimeProcess parameter. -""" - indices = set((r, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) - - return indices - - -def LifetimeLoanProcessIndices(M: 'TemoaModel'): - """\ -Based on the Efficiency parameter's indices and time_future parameter, this -function returns the set of process indices that may be specified in the -CostInvest parameter. -""" - min_period = min(M.vintage_optimize) - - indices = set((r, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys() if v >= min_period) - - return indices - - # --------------------------------------------------------------- # Create sparse indices for decision variables. # These functions are called from temoa_model.py and use the dictionaries @@ -1557,552 +497,6 @@ def LifetimeLoanProcessIndices(M: 'TemoaModel'): # --------------------------------------------------------------- -def CapacityVariableIndices(M: 'TemoaModel'): - return M.newCapacity_rtv - - -def RetiredCapacityVariableIndices(M: 'TemoaModel'): - return set( - (r, p, t, v) - for r, p, t in M.processVintages - if t in M.tech_retirement and t not in M.tech_uncap - for v in M.processVintages[r, p, t] - if v < p <= v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[p]) - ) - - -def AnnualRetirementVariableIndices(M: 'TemoaModel'): - return set( - (r, p, t, v) for r, t, v in M.retirementPeriods for p in M.retirementPeriods[r, t, v] - ) - - -def CapacityAvailableVariableIndices(M: 'TemoaModel'): - return M.activeCapacityAvailable_rpt - - -def CapacityAvailableVariableIndicesVintage(M: 'TemoaModel'): - return M.activeCapacityAvailable_rptv - - -def FlowVariableIndices(M: 'TemoaModel'): - return M.activeFlow_rpsditvo - - -def FlowVariableAnnualIndices(M: 'TemoaModel'): - return M.activeFlow_rpitvo - - -def FlexVariablelIndices(M: 'TemoaModel'): - return M.activeFlex_rpsditvo - - -def FlexVariableAnnualIndices(M: 'TemoaModel'): - return M.activeFlex_rpitvo - - -def FlowInStorageVariableIndices(M: 'TemoaModel'): - return M.activeFlowInStorage_rpsditvo - - -def CurtailmentVariableIndices(M: 'TemoaModel'): - return M.activeCurtailment_rpsditvo - - -def StorageLevelVariableIndices(M: 'TemoaModel'): - return M.storageLevelIndices_rpsdtv - - -def SeasonalStorageLevelVariableIndices(M: 'TemoaModel'): - return M.seasonalStorageLevelIndices_rpstv - - -def SeasonalStorageConstraintIndices(M: 'TemoaModel'): - indices = set( - (r, p, s, d, t, v) - for r, p, s, t, v in M.seasonalStorageLevelIndices_rpstv - for d in M.time_of_day - ) - - return indices - - -def StorageConstraintIndices(M: 'TemoaModel'): - return M.storageLevelIndices_rpsdtv - - -def CapacityConstraintIndices(M: 'TemoaModel'): - capacity_indices = set( - (r, p, s, d, t, v) - for r, p, t, v in M.activeActivity_rptv - if (t not in M.tech_annual or t in M.tech_demand) - if t not in M.tech_uncap - if t not in M.tech_storage - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - - return capacity_indices - - -def LinkedTechConstraintIndices(M: 'TemoaModel'): - linkedtech_indices = set( - (r, p, s, d, t, v, e) - for r, t, e in M.LinkedTechs.sparse_iterkeys() - for p in M.time_optimize - if (r, p, t) in M.processVintages - for v in M.processVintages[r, p, t] - if (r, p, t, v) in M.activeActivity_rptv - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - - return linkedtech_indices - - -def CapacityAnnualConstraintIndices(M: 'TemoaModel'): - capacity_indices = set( - (r, p, t, v) - for r, p, t, v in M.activeActivity_rptv - if t in M.tech_annual and t not in M.tech_demand - if t not in M.tech_uncap - ) - - return capacity_indices - - -# --------------------------------------------------------------- -# Create sparse indices for constraints. -# These functions are called from temoa_model.py and use the dictionaries -# created above in CreateSparseDicts() -# --------------------------------------------------------------- - - -# def DemandActivityConstraintIndices(M: 'TemoaModel'): -# """\ -# This function returns a set of sparse indices that are used in the -# DemandActivity constraint. It returns a tuple of the form: -# (p,s,d,t,v,dem,first_s,first_d) where "dem" is a demand commodity, and "first_s" -# and "first_d" are the reference season and time-of-day, respectively used to -# ensure demand activity remains consistent across time slices. -# """ - -# # needed data structures... -# # the count of techs that supply a commodity -# suppliers = defaultdict(set) -# # (region, demand): (season, tod) # the goal of the exercise! -# anchor_season_tod = {} -# # (region, demand): (period, tech, vintage) # the viable tech and vintage per region, demand -# viable_tech_vintage = defaultdict(list) - -# # start the loop over possible combos -# for r, p, t, v, dem in M.processInputsByOutput: -# # we aren't concerned with non-demand commodities or annual techs -# if dem not in M.commodity_demand or t in M.tech_annual: -# continue -# # capture the (p, t, v) in case we need to act on it -# viable_tech_vintage[r, p, dem].append((t, v)) -# suppliers[dem].add(t) # one more recognized supplier -# if len(suppliers[dem]) > 1: -# # We need to act on (build) for this region-demand, put in a placeholder -# anchor_season_tod[r, p, dem] = None - -# # Find the first timestep of the year where the demand is appreciably sized: -# # appreciable = not so small that we get into numerical instability when applying small multipliers -# appreciable_size = 0.0001 - -# for r, p, dem in anchor_season_tod: -# found_flag = False -# s0, d0 = None, None -# for s0, d0 in ((ss, dd) for ss in M.TimeSeason[p] for dd in M.time_of_day): -# if (r, p, s0, d0, dem) in M.DemandSpecificDistribution: -# if value(M.DemandSpecificDistribution[r, p, s0, d0, dem]) >= appreciable_size: -# found_flag = True -# break # we have one with some value associated -# found = 'found' if found_flag else 'not found' -# # set it. If nothing was found the first indices should work just fine... -# anchor_season_tod[r, p, dem] = (s0, d0) -# logger.debug( -# 'Using season/tod: %s, %s for commodity %s in region %s which was %s in DSD ' -# 'to set DemandActivity baseline', -# s0, -# d0, -# dem, -# r, -# found, -# ) - -# # Start yielding the constraint indices -# for r, p, dem in anchor_season_tod: -# s0, d0 = anchor_season_tod[r, p, dem] -# for t, v in viable_tech_vintage[r, p, dem]: -# for s in M.TimeSeason[p]: -# for d in M.time_of_day: -# if s != s0 or d != d0: -# yield r, p, s, d, t, v, dem, s0, d0 - - -def DemandActivityConstraintIndices(M: 'TemoaModel'): - indices = set( - (r, p, s, d, t, v, dem) - for r, p, dem in M.DemandConstraint_rpc - for t, v in M.commodityUStreamProcess[r, p, dem] - if t not in M.tech_annual - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - return indices - - -# devnote: no longer needed -# def DemandConstraintIndices(M: 'TemoaModel'): -# indices = set( -# (r, p, dem) -# for r, p, dem in M.Demand.sparse_iterkeys() -# ) - -# return indices - - -def BaseloadDiurnalConstraintIndices(M: 'TemoaModel'): - indices = set( - (r, p, s, d, t, v) - for r, p, t in M.baseloadVintages - for v in M.baseloadVintages[r, p, t] - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - - return indices - - -def RegionalExchangeCapacityConstraintIndices(M: 'TemoaModel'): - indices = set( - (r_e, r_i, p, t, v) - for r_e, p, i in M.exportRegions - for r_i, t, v, o in M.exportRegions[r_e, p, i] - ) - - return indices - - -def CommodityBalanceConstraintIndices(M: 'TemoaModel'): - # Generate indices only for those commodities that are produced by - # technologies with varying output at the time slice level. - indices = set( - (r, p, s, d, c) - for r, p, c in M.commodityBalance_rpc - # r in this line includes interregional transfer combinations (not needed). - if r in M.regions # this line ensures only the regions are included. - and c not in M.commodity_annual - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - - return indices - - -def AnnualCommodityBalanceConstraintIndices(M: 'TemoaModel'): - # Generate indices only for those commodities that are produced by - # technologies with constant annual output. - indices = set( - (r, p, c) - for r, p, c in M.commodityBalance_rpc - # r in this line includes interregional transfer combinations (not needed). - if r in M.regions # this line ensures only the regions are included. - and c in M.commodity_annual - ) - - return indices - - -def RampUpDayConstraintIndices(M: 'TemoaModel'): - indices = set( - (r, p, s, d, t, v) - for r, p, t in M.rampUpVintages - for v in M.rampUpVintages[r, p, t] - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - - return indices - - -def RampDownDayConstraintIndices(M: 'TemoaModel'): - indices = set( - (r, p, s, d, t, v) - for r, p, t in M.rampDownVintages - for v in M.rampDownVintages[r, p, t] - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - - return indices - - -def RampUpSeasonConstraintIndices(M: 'TemoaModel'): - if M.TimeSequencing.first() == 'consecutive_days': - return Set.Skip # dont need this constraint - - # s, s_next indexing ensures we dont build redundant constraints - indices = set( - (r, p, s, s_next, t, v) - for r, p, t in M.rampUpVintages - for v in M.rampUpVintages[r, p, t] - for _p, s_seq, s in M.ordered_season_sequential - if _p == p - for s_seq_next in (M.time_next_sequential[p, s_seq],) # next sequential season - for s_next in ( - M.sequential_to_season[p, s_seq_next], - ) # next sequential season's matching season - if s_next - != M.time_next[p, s, M.time_of_day.last()][0] # to avoid redundancy on RampDay constraint - ) - - return indices - - -def RampDownSeasonConstraintIndices(M: 'TemoaModel'): - if M.TimeSequencing.first() == 'consecutive_days': - return Set.Skip # dont need this constraint - - # s, s_next indexing ensures we dont build redundant constraints - indices = set( - (r, p, s, s_next, t, v) - for r, p, t in M.rampDownVintages - for v in M.rampDownVintages[r, p, t] - for _p, s_seq, s in M.ordered_season_sequential - for s_seq_next in (M.time_next_sequential[p, s_seq],) # next sequential season - for s_next in ( - M.sequential_to_season[p, s_seq_next], - ) # next sequential season's matching season - if s_next - != M.time_next[p, s, M.time_of_day.last()][0] # to avoid redundancy on RampDay constraint - ) - - return indices - - -def ReserveMarginIndices(M: 'TemoaModel'): - indices = set( - (r, p, s, d) - for r in M.PlanningReserveMargin.sparse_iterkeys() - for p in M.time_optimize - if (r, p) in M.processReservePeriods - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - - return indices - - -def LimitTechInputSplitConstraintIndices(M: 'TemoaModel'): - indices = set( - (r, p, s, d, i, t, v, op) - for r, p, i, t, op in M.inputSplitVintages - if t not in M.tech_annual - for v in M.inputSplitVintages[r, p, i, t, op] - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - ann_indices = set( - (r, p, i, t, op) for r, p, i, t, op in M.inputSplitVintages if t in M.tech_annual - ) - if len(ann_indices) > 0: - msg = ( - 'Warning: Annual technologies included in LimitTechInputSplit table. ' - 'Use LimitTechInputSplitAnnual table instead or these constraints will be ignored: {}' - ) - logger.warning(msg.format(ann_indices)) - - return indices - - -def LimitTechInputSplitAnnualConstraintIndices(M: 'TemoaModel'): - indices = set( - (r, p, i, t, v, op) - for r, p, i, t, op in M.inputSplitAnnualVintages - if t in M.tech_annual - for v in M.inputSplitAnnualVintages[r, p, i, t, op] - ) - - return indices - - -def LimitTechInputSplitAverageConstraintIndices(M: 'TemoaModel'): - indices = set( - (r, p, i, t, v, op) - for r, p, i, t, op in M.inputSplitAnnualVintages - if t not in M.tech_annual - for v in M.inputSplitAnnualVintages[r, p, i, t, op] - ) - return indices - - -def LimitTechOutputSplitConstraintIndices(M: 'TemoaModel'): - indices = set( - (r, p, s, d, t, v, o, op) - for r, p, t, o, op in M.outputSplitVintages - if t not in M.tech_annual - for v in M.outputSplitVintages[r, p, t, o, op] - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - ann_indices = set( - (r, p, t, o, op) for r, p, t, o, op in M.outputSplitVintages if t in M.tech_annual - ) - if len(ann_indices) > 0: - msg = ( - 'Warning: Annual technologies included in LimitTechOutputSplit table. ' - 'Use LimitTechOutputSplitAnnual table instead or these constraints will be ignored: {}' - ) - logger.warning(msg.format(ann_indices)) - - return indices - - -def LimitTechOutputSplitAnnualConstraintIndices(M: 'TemoaModel'): - indices = set( - (r, p, t, v, o, op) - for r, p, t, o, op in M.outputSplitAnnualVintages - if t in M.tech_annual - for v in M.outputSplitAnnualVintages[r, p, t, o, op] - ) - return indices - - -def LimitTechOutputSplitAverageConstraintIndices(M: 'TemoaModel'): - indices = set( - (r, p, t, v, o, op) - for r, p, t, o, op in M.outputSplitAnnualVintages - if t not in M.tech_annual - for v in M.outputSplitAnnualVintages[r, p, t, o, op] - ) - return indices - - -def LimitGrowthCapacityIndices(M: 'TemoaModel'): - indices = set( - (r, p, t, op) - for r, t, op in M.LimitGrowthCapacity.sparse_iterkeys() - for p in M.time_optimize - ) - return indices - - -def LimitDegrowthCapacityIndices(M: 'TemoaModel'): - indices = set( - (r, p, t, op) - for r, t, op in M.LimitDegrowthCapacity.sparse_iterkeys() - for p in M.time_optimize - ) - return indices - - -def LimitGrowthNewCapacityIndices(M: 'TemoaModel'): - indices = set( - (r, p, t, op) - for r, t, op in M.LimitGrowthNewCapacity.sparse_iterkeys() - for p in M.time_optimize - ) - return indices - - -def LimitDegrowthNewCapacityIndices(M: 'TemoaModel'): - indices = set( - (r, p, t, op) - for r, t, op in M.LimitDegrowthNewCapacity.sparse_iterkeys() - for p in M.time_optimize - ) - return indices - - -def LimitGrowthNewCapacityDeltaIndices(M: 'TemoaModel'): - indices = set( - (r, p, t, op) - for r, t, op in M.LimitGrowthNewCapacityDelta.sparse_iterkeys() - for p in M.time_optimize - ) - return indices - - -def LimitDegrowthNewCapacityDeltaIndices(M: 'TemoaModel'): - indices = set( - (r, p, t, op) - for r, t, op in M.LimitDegrowthNewCapacityDelta.sparse_iterkeys() - for p in M.time_optimize - ) - return indices - - -def loop_period_next_timeslice(M: 'TemoaModel', p, s, d) -> tuple[str, str]: - # Final time slice of final season (end of period) - # Loop state back to initial state of first season - # Loop the period - if s == M.TimeSeason[p].last() and d == M.time_of_day.last(): - s_next = M.TimeSeason[p].first() - d_next = M.time_of_day.first() - - # Last time slice of any season that is NOT the last season - # Carry state to initial state of next season - # Carry state between seasons - elif d == M.time_of_day.last(): - s_next = M.TimeSeason[p].next(s) - d_next = M.time_of_day.first() - - # Any other time slice - # Carry state to next time slice in the same season - # Continuing through this season - else: - s_next = s - d_next = M.time_of_day.next(d) - - return s_next, d_next - - -def loop_season_next_timeslice(M: 'TemoaModel', p, s, d) -> tuple[str, str]: - # We loop each season so never carrying state between seasons - s_next = s - - # Final time slice of any season - # Loop state back to initial state of same season - # Loop each season - if d == M.time_of_day.last(): - d_next = M.time_of_day.first() - - # Any other time slice - # Carry state to next time slice in the same season - # Continuing through this season - else: - d_next = M.time_of_day.next(d) - - return s_next, d_next - - -def gather_group_regions(M: 'TemoaModel', region: str) -> Iterable[str]: - if region == 'global': - regions = M.regions - elif '+' in region: - regions = region.split('+') - else: - regions = (region,) - return regions - - -def gather_group_techs(M: 'TemoaModel', t_or_g: str) -> Iterable[str]: - if t_or_g in M.tech_group_names: - techs = M.tech_group_members[t_or_g] - elif '+' in t_or_g: - techs = t_or_g.split('+') - else: - techs = (t_or_g,) - return techs - - -def get_loan_life(M: 'TemoaModel', r, t, v): - return M.LifetimeProcess[r, t, v] - - def copy_from(other_set): """a cheap reference function to replace the lambdas in orig temoa_model""" return Set(other_set.sparse_iterkeys()) diff --git a/temoa/_internal/temoa_rules.py b/temoa/_internal/temoa_rules.py index 84ed1ca9d..b57bd7b1b 100644 --- a/temoa/_internal/temoa_rules.py +++ b/temoa/_internal/temoa_rules.py @@ -26,12 +26,10 @@ from pyomo.core import Expression, Var from pyomo.environ import Constraint, value -from temoa._internal.temoa_initialize import ( - AnnualCommodityBalanceConstraintErrorCheck, - CommodityBalanceConstraintErrorCheck, - DemandConstraintErrorCheck, - gather_group_regions, - gather_group_techs, +from temoa.components import ( + commodities, + geography, + technology, ) if TYPE_CHECKING: @@ -1073,7 +1071,7 @@ def Demand_Constraint(M: 'TemoaModel', r, p, dem): for S_i in M.processInputsByOutput[r, p, S_t, S_v, dem] ) - DemandConstraintErrorCheck(supply_annual, r, p, dem) + commodities.DemandConstraintErrorCheck(supply_annual, r, p, dem) expr = supply_annual == value(M.Demand[r, p, dem]) @@ -1339,7 +1337,7 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): if S_t in M.tech_annual ) - CommodityBalanceConstraintErrorCheck( + commodities.CommodityBalanceConstraintErrorCheck( produced, consumed, r, @@ -1481,7 +1479,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): if S_t in M.tech_annual ) - AnnualCommodityBalanceConstraintErrorCheck( + commodities.AnnualCommodityBalanceConstraintErrorCheck( produced, consumed, r, @@ -2660,7 +2658,7 @@ def LimitEmission_Constraint(M: 'TemoaModel', r, p, e, op): # if r == 'global', the constraint is system-wide - regions = gather_group_regions(M, r) + regions = geography.gather_group_regions(M, r) # ================= Emissions and Flex and Curtailment ================= # Flex flows are deducted from V_FlowOut, so it is NOT NEEDED to tax them again. (See commodity balance constr) @@ -2763,8 +2761,8 @@ def LimitGrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitDegrowthCapacity}} """ - regions = gather_group_regions(M, r) - techs = gather_group_techs(M, t) + regions = geography.gather_group_regions(M, r) + techs = technology.gather_group_techs(M, t) growth = M.LimitDegrowthCapacity if degrowth else M.LimitGrowthCapacity RATE = 1 + value(growth[r, t, op][0]) @@ -2874,8 +2872,8 @@ def LimitGrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False) \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitDegrowthCapacity}} """ - regions = gather_group_regions(M, r) - techs = gather_group_techs(M, t) + regions = geography.gather_group_regions(M, r) + techs = technology.gather_group_techs(M, t) growth = M.LimitDegrowthNewCapacity if degrowth else M.LimitGrowthNewCapacity RATE = 1 + value(growth[r, t, op][0]) @@ -2986,8 +2984,8 @@ def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = F \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitDegrowthCapacityDelta}} """ - regions = gather_group_regions(M, r) - techs = gather_group_techs(M, t) + regions = geography.gather_group_regions(M, r) + techs = technology.gather_group_techs(M, t) growth = M.LimitDegrowthNewCapacityDelta if degrowth else M.LimitGrowthNewCapacityDelta RATE = 1 + value(growth[r, t, op][0]) @@ -3102,8 +3100,8 @@ def LimitActivity_Constraint(M: 'TemoaModel', r, p, t, op): # r can be an individual region (r='US'), or a combination of regions separated by # a + (r='Mexico+US+Canada'), or 'global'. # if r == 'global', the constraint is system-wide - regions = gather_group_regions(M, r) - techs = gather_group_techs(M, t) + regions = geography.gather_group_regions(M, r) + techs = technology.gather_group_techs(M, t) activity = sum( M.V_FlowOut[_r, p, s, d, S_i, _t, S_v, S_o] @@ -3147,8 +3145,8 @@ def LimitNewCapacity_Constraint(M: 'TemoaModel', r, p, t, op): \text{where }v=p """ - regions = gather_group_regions(M, r) - techs = gather_group_techs(M, t) + regions = geography.gather_group_regions(M, r) + techs = technology.gather_group_techs(M, t) cap_lim = value(M.LimitNewCapacity[r, p, t, op]) new_cap = sum(M.V_NewCapacity[_r, _t, p] for _t in techs for _r in regions) expr = operator_expression(new_cap, op, cap_lim) @@ -3168,8 +3166,8 @@ def LimitCapacity_Constraint(M: 'TemoaModel', r, p, t, op): \textbf{CAPAVL}_{r, p, t} \le LC_{r, p, t} \forall \{r, p, t\} \in \Theta_{\text{LimitCapacity}}""" - regions = gather_group_regions(M, r) - techs = gather_group_techs(M, t) + regions = geography.gather_group_regions(M, r) + techs = technology.gather_group_techs(M, t) cap_lim = value(M.LimitCapacity[r, p, t, op]) capacity = sum( M.V_CapacityAvailableByPeriodAndTech[_r, p, _t] for _t in techs for _r in regions @@ -3200,8 +3198,8 @@ def LimitResource_Constraint(M: 'TemoaModel', r, t, op): # dev note: this would generally be applied to a "dummy import" technology to restrict something like # oil/mineral extraction across all model periods. Looks fine to me. - regions = gather_group_regions(M, r) - techs = gather_group_techs(M, t) + regions = geography.gather_group_regions(M, r) + techs = technology.gather_group_techs(M, t) activity = sum( M.V_FlowOutAnnual[_r, p, S_i, _t, S_v, S_o] @@ -3249,9 +3247,9 @@ def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): \qquad \forall \{r, p, g_1, g_2\} \in \Theta_{\text{LimitActivityShare}} """ - regions = gather_group_regions(M, r) + regions = geography.gather_group_regions(M, r) - sub_group = gather_group_techs(M, g1) + sub_group = technology.gather_group_techs(M, g1) sub_activity = sum( M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] for S_t in sub_group @@ -3273,7 +3271,7 @@ def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] ) - super_group = gather_group_techs(M, g2) + super_group = technology.gather_group_techs(M, g2) super_activity = sum( M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] for S_t in super_group @@ -3317,9 +3315,9 @@ def LimitCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): technology or technology group as a fraction of another technology or group. """ - regions = gather_group_regions(M, r) + regions = geography.gather_group_regions(M, r) - sub_group = gather_group_techs(M, g1) + sub_group = technology.gather_group_techs(M, g1) sub_capacity = sum( M.V_CapacityAvailableByPeriodAndTech[_r, p, _t] for _t in sub_group @@ -3327,7 +3325,7 @@ def LimitCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): if (_r, p, _t) in M.processVintages ) - super_group = gather_group_techs(M, g2) + super_group = technology.gather_group_techs(M, g2) super_capacity = sum( M.V_CapacityAvailableByPeriodAndTech[_r, p, _t] for _t in super_group @@ -3348,9 +3346,9 @@ def LimitNewCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): of a given technology or group as a fraction of another technology or group.""" - regions = gather_group_regions(M, r) + regions = geography.gather_group_regions(M, r) - sub_group = gather_group_techs(M, g1) + sub_group = technology.gather_group_techs(M, g1) sub_new_cap = sum( M.V_NewCapacity[_r, _t, p] for _t in sub_group @@ -3358,7 +3356,7 @@ def LimitNewCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): if (_r, _t, p) in M.processPeriods ) - super_group = gather_group_techs(M, g2) + super_group = technology.gather_group_techs(M, g2) super_new_cap = sum( M.V_NewCapacity[_r, _t, p] for _t in super_group @@ -3394,7 +3392,7 @@ def LimitAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o, op): """ # r can be an individual region (r='US'), or a combination of regions separated by plus (r='Mexico+US+Canada'), or 'global'. # if r == 'global', the constraint is system-wide - regions = gather_group_regions(M, r) + regions = geography.gather_group_regions(M, r) # we need to screen here because it is possible that the restriction extends beyond the # lifetime of any vintage of the tech... if all((_r, p, t) not in M.V_CapacityAvailableByPeriodAndTech for _r in regions): @@ -3450,7 +3448,7 @@ def LimitSeasonalCapacityFactor_Constraint(M: 'TemoaModel', r, p, s, t, op): """ # r can be an individual region (r='US'), or a combination of regions separated by plus (r='Mexico+US+Canada'), or 'global'. # if r == 'global', the constraint is system-wide - regions = gather_group_regions(M, r) + regions = geography.gather_group_regions(M, r) # we need to screen here because it is possible that the restriction extends beyond the # lifetime of any vintage of the tech... if all((_r, p, t) not in M.V_CapacityAvailableByPeriodAndTech for _r in regions): @@ -3890,7 +3888,7 @@ def operator_expression(lhs: Expression | None, operator: str | None, rhs: Expre lhs, operator, rhs ) logger.error(msg) - raise ValueError(msg) + raise ValueError(msg) from e return expr diff --git a/temoa/components/capacity.py b/temoa/components/capacity.py index e69de29bb..aa73e45b7 100644 --- a/temoa/components/capacity.py +++ b/temoa/components/capacity.py @@ -0,0 +1,211 @@ +# temoa/components/capacity.py +""" +Defines the capacity-related components of the Temoa model. + +This includes the core variables for new, retired, and available capacity, +as well as the constraints that govern their relationships and enforce +production limits. +""" + +from __future__ import annotations + +from itertools import product as cross_product +from logging import getLogger +from typing import TYPE_CHECKING + +from deprecated import deprecated +from pyomo.environ import ( + value, +) + +if TYPE_CHECKING: + from temoa.core.model import TemoaModel + + +logger = getLogger(name=__name__) +# ============================================================================ +# INDEX GENERATION FUNCTIONS +# (Formerly in temoa/_internal/temoa_initialize.py) +# ============================================================================ +# By convention, we can prefix these with an underscore to indicate they are +# internal helpers for this component's construction. + + +def CapacityVariableIndices(M: 'TemoaModel'): + return M.newCapacity_rtv + + +def RetiredCapacityVariableIndices(M: 'TemoaModel'): + return set( + (r, p, t, v) + for r, p, t in M.processVintages + if t in M.tech_retirement and t not in M.tech_uncap + for v in M.processVintages[r, p, t] + if v < p <= v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[p]) + ) + + +def AnnualRetirementVariableIndices(M: 'TemoaModel'): + return set( + (r, p, t, v) for r, t, v in M.retirementPeriods for p in M.retirementPeriods[r, t, v] + ) + + +def CapacityAvailableVariableIndices(M: 'TemoaModel'): + return M.activeCapacityAvailable_rpt + + +def CapacityAvailableVariableIndicesVintage(M: 'TemoaModel'): + return M.activeCapacityAvailable_rptv + + +def CheckCapacityFactorProcess(M: 'TemoaModel'): + count_rptv = dict() + # Pull CapacityFactorTech by default + for r, p, _s, _d, t in M.CapacityFactor_rpsdt: + for v in M.processVintages[r, p, t]: + M.isCapacityFactorProcess[r, p, t, v] = False + count_rptv[r, p, t, v] = 0 + + # Check for bad values and count up the good ones + for r, p, _s, _d, t, v in M.CapacityFactorProcess.sparse_iterkeys(): + if v not in M.processVintages[r, p, t]: + msg = f'Invalid process {p, v} for {r, t} in CapacityFactorProcess table' + logger.error(msg) + raise ValueError(msg) + + # Good value, pull from CapacityFactorProcess table + count_rptv[r, p, t, v] += 1 + + # Check if all possible values have been set by process + # log a warning if some are missing (allowed but maybe accidental) + for (r, p, t, v), count in count_rptv.items(): + num_seg = len(M.TimeSeason[p]) * len(M.time_of_day) + if count > 0: + M.isCapacityFactorProcess[r, p, t, v] = True + if count < num_seg: + logger.info( + 'Some but not all processes were set in CapacityFactorProcess (%i out of a possible %i) for: %s' + ' Missing values will default to CapacityFactorTech value or 1 if that is not set either.', + count, + num_seg, + (r, p, t, v), + ) + + +@deprecated('should not be needed. We are pulling the default on-the-fly where used') +def CreateCapacityFactors(M: 'TemoaModel'): + """ + Steps to creating capacity factors: + 1. Collect all possible processes + 2. Find the ones _not_ specified in CapacityFactorProcess + 3. Set them, based on CapacityFactorTech. + """ + # Shorter names, for us lazy programmer types + CFP = M.CapacityFactorProcess + + # Step 1 + processes = set((r, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) + + all_cfs = set( + (r, p, s, d, t, v) + for (r, t, v) in processes + for p in M.processPeriods[r, t, v] + for s, d in cross_product(M.TimeSeason[p], M.time_of_day) + ) + + # Step 2 + unspecified_cfs = all_cfs.difference(CFP.sparse_iterkeys()) + + # Step 3 + + # Some hackery: We futz with _constructed because Pyomo thinks that this + # Param is already constructed. However, in our view, it is not yet, + # because we're specifically targeting values that have not yet been + # constructed, that we know are valid, and that we will need. + + if unspecified_cfs: + # CFP._constructed = False + for r, s, d, t, v in unspecified_cfs: + CFP[r, s, d, t, v] = M.CapacityFactorTech[r, s, d, t] + logger.debug( + 'Created Capacity Factors for %d processes without an explicit specification', + len(unspecified_cfs), + ) + # CFP._constructed = True + + +def get_default_capacity_factor(M: 'TemoaModel', r, p, s, d, t, v): + """ + This initializer is used to fill the CapacityFactorProcess from the CapacityFactorTech where needed. + + Priority: + 1. As specified in data input (this function not called) + 2. Here + 3. The default from CapacityFactorTech param + :param M: generic model reference + :param r: region + :param s: season + :param d: time-of-day slice + :param t: tech + :param v: vintage + :return: the capacity factor + """ + return M.CapacityFactorTech[r, p, s, d, t] + + +@deprecated('switched over to validator... this set is typically VERY empty') +def CapacityFactorProcessIndices(M: 'TemoaModel'): + indices = set( + (r, s, d, t, v) + for r, i, t, v, o in M.Efficiency.sparse_iterkeys() + for p in M.time_optimize + for s in M.TimeSeason[p] + for d in M.time_of_day + ) + return indices + + +def CapacityFactorTechIndices(M: 'TemoaModel'): + all_cfs = set( + (r, p, s, d, t) + for r, p, t in M.activeCapacityAvailable_rpt + for s in M.TimeSeason[p] + for d in M.time_of_day + ) + return all_cfs + + +def CapacityConstraintIndices(M: 'TemoaModel'): + capacity_indices = set( + (r, p, s, d, t, v) + for r, p, t, v in M.activeActivity_rptv + if (t not in M.tech_annual or t in M.tech_demand) + if t not in M.tech_uncap + if t not in M.tech_storage + for s in M.TimeSeason[p] + for d in M.time_of_day + ) + + return capacity_indices + + +def CapacityAnnualConstraintIndices(M: 'TemoaModel'): + capacity_indices = set( + (r, p, t, v) + for r, p, t, v in M.activeActivity_rptv + if t in M.tech_annual and t not in M.tech_demand + if t not in M.tech_uncap + ) + + return capacity_indices + + +def RegionalExchangeCapacityConstraintIndices(M: 'TemoaModel'): + indices = set( + (r_e, r_i, p, t, v) + for r_e, p, i in M.exportRegions + for r_i, t, v, o in M.exportRegions[r_e, p, i] + ) + + return indices diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index e69de29bb..0fc8e2987 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -0,0 +1,258 @@ +import sys +from itertools import product as cross_product +from logging import getLogger +from operator import itemgetter as iget +from typing import TYPE_CHECKING + +from pyomo.environ import value + +if TYPE_CHECKING: + from temoa.core.model import TemoaModel + + +logger = getLogger(name=__name__) + + +def CommodityBalanceConstraintErrorCheck(supplied, demanded, r, p, s, d, c): + # note: if a pyomo equation simplifies to an int, there are no variables in it, which + # is an indicator of a problem. How this might come up I do not know + if isinstance(supplied, int) or isinstance(demanded, int): + expr = str(supplied == demanded) + msg = ( + 'Unable to balance commodity {} in ({}, {}, {}, {}).\n' + 'No flows on one side of constraint expression:\n' + ' {}\n' + 'Possible reasons:\n' + " - Is there a missing period in set 'time_future'?\n" + " - Is there a missing tech in set 'tech_resource'?\n" + " - Is there a missing tech in set 'tech_production'?\n" + " - Is there a missing commodity in set 'commodity_physical'?\n" + ' - Are there missing entries in the Efficiency table?\n' + ' - Does a process need a longer Lifetime?' + ) + logger.error(msg.format(c, r, p, s, d, expr)) + raise Exception(msg.format(c, r, p, s, d, expr)) + + +def AnnualCommodityBalanceConstraintErrorCheck(supplied, demanded, r, p, c): + # note: if a pyomo equation simplifies to an int, there are no variables in it, which + # is an indicator of a problem. How this might come up I do not know + if isinstance(supplied, int) or isinstance(demanded, int): + expr = str(supplied == demanded) + msg = ( + 'Unable to balance annual commodity {} in ({}, {}).\n' + 'No flows on one side of constraint expression:\n' + ' {}\n' + 'Possible reasons:\n' + " - Is there a missing period in set 'time_future'?\n" + " - Is there a missing tech in set 'tech_resource'?\n" + " - Is there a missing tech in set 'tech_production'?\n" + " - Is there a missing commodity in set 'commodity_physical'?\n" + ' - Are there missing entries in the Efficiency table?\n' + ' - Does a process need a longer Lifetime?' + ) + logger.error(msg.format(c, r, p, expr)) + raise Exception(msg.format(c, r, p, expr)) + + +def DemandConstraintErrorCheck(supply, r, p, dem): + # note: if a pyomo equation simplifies to an int, there are no variables in it, which + # is an indicator of a problem + if isinstance(supply, int): + msg = ( + "Error: Demand '{}' for ({}, {}) unable to be met by any " + 'technology.\n\tPossible reasons:\n' + ' - Is the Efficiency parameter missing an entry for this demand?\n' + ' - Does a tech that satisfies this demand need a longer ' + 'Lifetime?\n' + ) + logger.error(msg.format(dem, r, p)) + raise Exception(msg.format(dem, r, p)) + + +def DemandActivityConstraintIndices(M: 'TemoaModel'): + indices = set( + (r, p, s, d, t, v, dem) + for r, p, dem in M.DemandConstraint_rpc + for t, v in M.commodityUStreamProcess[r, p, dem] + if t not in M.tech_annual + for s in M.TimeSeason[p] + for d in M.time_of_day + ) + return indices + + +def CreateDemands(M: 'TemoaModel'): + """ + Steps to create the demand distributions + 1. Use Demand keys to ensure that all demands in commodity_demand are used + 2. Find any slices not set in DemandDefaultDistribution, and set them based + on the associated SegFrac slice. + 3. Validate that the DemandDefaultDistribution sums to 1. + 4. Find any per-demand DemandSpecificDistribution values not set, and set + them from DemandDefaultDistribution. Note that this only sets a + distribution for an end-use demand if the user has *not* specified _any_ + anything for that end-use demand. Thus, it is up to the user to fully + specify the distribution, or not. No in-between. + 5. Validate that the per-demand distributions sum to 1. + """ + logger.debug('Started creating demand distributions in CreateDemands()') + + # Step 0: some setup for a couple of reusable items + # Get the nth element from the tuple (r, p, s, d, dem) + # So we only have to update these indices in one place if they change + DSD_region = iget(0) + DSD_period = iget(1) + DSD_dem = iget(4) + + # Step 1: Check if any demand commodities are going unused + used_dems = set(dem for r, p, dem in M.Demand.sparse_iterkeys()) + unused_dems = sorted(M.commodity_demand.difference(used_dems)) + if unused_dems: + for dem in unused_dems: + msg = "Warning: Demand '{}' is unused\n" + logger.warning(msg.format(dem)) + sys.stderr.write(msg.format(dem)) + + # devnote: DDD just clones SegFrac. Unless we want to specify it in the database, + # makes sense to just use SegFrac directly + # Step 2: Build the demand default distribution (= segfrac) + # DDD = M.DemandDefaultDistribution # Shorter, for us lazy programmer types + # unset_defaults = set(M.SegFrac.sparse_iterkeys()) + # unset_defaults.difference_update(DDD.sparse_iterkeys()) + # if unset_defaults: + # Some hackery because Pyomo thinks that this Param is constructed. + # However, in our view, it is not yet, because we're specifically + # targeting values that have not yet been constructed, that we know are + # valid, and that we will need. + # DDD._constructed = False + # for tslice in unset_defaults: + # DDD[tslice] = M.SegFrac[tslice] # DDD._constructed = True + + # Step 3: Check that DDD sums to 1 + # devnote: this seems redundant to the SegFrac sum to 1 check. + # total = sum(i for i in DDD.values()) + # if abs(value(total) - 1.0) > 0.001: + # # We can't explicitly test for "!= 1.0" because of incremental rounding + # # errors associated with the specification of demand shares by time slice, + # # but we check to make sure it is within the specified tolerance. + + # key_padding = max(map(get_str_padding, DDD.sparse_iterkeys())) + + # fmt = '%%-%ds = %%s' % key_padding + # # Works out to something like "%-25s = %s" + + # items = sorted(DDD.items()) + # items = '\n '.join(fmt % (str(k), v) for k, v in items) + + # msg = ( + # 'The values of the DemandDefaultDistribution parameter do not ' + # 'sum to 1. The DemandDefaultDistribution specifies how end-use ' + # 'demands are distributed among the time slices (i.e., time_season, ' + # 'time_of_day), so together, the data must total to 1. Current ' + # 'values:\n {}\n\tsum = {}' + # ) + # logger.error(msg.format(items, total)) + # raise ValueError(msg.format(items, total)) + + # Step 4: Fill out demand specific distribution table and check sums to 1 by region and demand + DSD = M.DemandSpecificDistribution + + demands_specified = set(map(DSD_dem, (i for i in DSD.sparse_iterkeys()))) + unset_demand_distributions = used_dems.difference( + demands_specified + ) # the demands not mentioned in DSD *at all* + + if unset_demand_distributions: + for p in M.time_optimize: + unset_distributions = set( + cross_product( + M.regions, (p,), M.TimeSeason[p], M.time_of_day, unset_demand_distributions + ) + ) + for r, p, s, d, dem in unset_distributions: + DSD[r, p, s, d, dem] = value(M.SegFrac[p, s, d]) # DSD._constructed = True + + # Step 5: A final "sum to 1" check for all DSD members (which now should be everything) + # Also check that all keys are made... The demand distro should be supported + # by the full set of (r, p, dem) keys because it is an equality constraint + # and we need to ensure even the zeros are passed in + used_rp_dems = set((r, p, dem) for r, p, dem in M.Demand.sparse_iterkeys()) + for r, p, dem in used_rp_dems: + expected_key_length = len(M.TimeSeason[p]) * len(M.time_of_day) + keys = [ + k + for k in DSD.sparse_iterkeys() + if DSD_region(k) == r and DSD_period(k) == p and DSD_dem(k) == dem + ] + if len(keys) != expected_key_length: + # this could be very slow but only calls when there's a problem + missing = set( + (s, d) + for s in M.TimeSeason[p] + for d in M.time_of_day + if (r, p, s, d, dem) not in keys + ) + logger.info( + 'Missing some time slices for Demand Specific Distribution %s: %s', + (r, p, dem), + missing, + ) + total = sum(value(DSD[i]) for i in keys) + if abs(value(total) - 1.0) > 0.001: + # We can't explicitly test for "!= 1.0" because of incremental rounding + # errors associated with the specification of demand shares by time slice, + # but we check to make sure it is within the specified tolerance. + def get_str_padding(obj): + return len(str(obj)) + + key_padding = max(map(get_str_padding, keys)) + + fmt = '%%-%ds = %%s' % key_padding + # Works out to something like "%-25s = %s" + + items = sorted((k, value(DSD[k])) for k in keys) + items = '\n '.join(fmt % (str(k), v) for k, v in items) + + msg = ( + 'The values of the DemandSpecificDistribution parameter do not ' + 'sum to 1 for {}. The DemandSpecificDistribution specifies how end-use ' + 'demands are distributed per time-slice (i.e., time_season, ' + 'time_of_day). Within each region, period, end-use demand, then, the distribution ' + 'must total to 1.\n\n Demand-specific distribution in error: ' + ' \n {}\n\tsum = {}' + ) + logger.error(msg.format((r, p, dem), items, total)) + raise ValueError(msg.format((r, p, dem), items, total)) + + logger.debug('Finished creating demand distributions') + + +def CommodityBalanceConstraintIndices(M: 'TemoaModel'): + # Generate indices only for those commodities that are produced by + # technologies with varying output at the time slice level. + indices = set( + (r, p, s, d, c) + for r, p, c in M.commodityBalance_rpc + # r in this line includes interregional transfer combinations (not needed). + if r in M.regions # this line ensures only the regions are included. + and c not in M.commodity_annual + for s in M.TimeSeason[p] + for d in M.time_of_day + ) + + return indices + + +def AnnualCommodityBalanceConstraintIndices(M: 'TemoaModel'): + # Generate indices only for those commodities that are produced by + # technologies with constant annual output. + indices = set( + (r, p, c) + for r, p, c in M.commodityBalance_rpc + # r in this line includes interregional transfer combinations (not needed). + if r in M.regions # this line ensures only the regions are included. + and c in M.commodity_annual + ) + + return indices diff --git a/temoa/components/costs.py b/temoa/components/costs.py index e69de29bb..5c58a18ac 100644 --- a/temoa/components/costs.py +++ b/temoa/components/costs.py @@ -0,0 +1,95 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +from deprecated import deprecated + +if TYPE_CHECKING: + from temoa.core.model import TemoaModel + +from logging import getLogger + +logger = getLogger(name=__name__) + + +def get_default_loan_rate(M: 'TemoaModel', *_): + """get the default loan rate from the DefaultLoanRate param""" + return M.DefaultLoanRate() + + +@deprecated(reason='vintage defaults are no longer available, so this should not be needed') +def CreateCosts(M: 'TemoaModel'): + """ + Steps to creating fixed and variable costs: + 1. Collect all possible cost indices (CostFixed, CostVariable) + 2. Find the ones _not_ specified in CostFixed and CostVariable + 3. Set them, based on Cost*VintageDefault + """ + logger.debug('Started Creating Fixed and Variable costs in CreateCosts()') + # Shorter names, for us lazy programmer types + CF = M.CostFixed + CV = M.CostVariable + + # Step 1 + fixed_indices = set(M.CostFixed_rptv) + var_indices = set(M.CostVariable_rptv) + + # Step 2 + unspecified_fixed_prices = fixed_indices.difference(CF.sparse_iterkeys()) + unspecified_var_prices = var_indices.difference(CV.sparse_iterkeys()) + + # Step 3 + + # Some hackery: We futz with _constructed because Pyomo thinks that this + # Param is already constructed. However, in our view, it is not yet, + # because we're specifically targeting values that have not yet been + # constructed, that we know are valid, and that we will need. + + if unspecified_fixed_prices: + # CF._constructed = False + for r, p, t, v in unspecified_fixed_prices: + if (r, t, v) in M.CostFixedVintageDefault: + CF[r, p, t, v] = M.CostFixedVintageDefault[r, t, v] # CF._constructed = True + + if unspecified_var_prices: + # CV._constructed = False + for r, p, t, v in unspecified_var_prices: + if (r, t, v) in M.CostVariableVintageDefault: + CV[r, p, t, v] = M.CostVariableVintageDefault[r, t, v] + # CV._constructed = True + logger.debug('Created M.CostFixed with size: %d', len(M.CostFixed)) + logger.debug('Created M.CostVariable with size: %d', len(M.CostVariable)) + logger.debug('Finished creating Fixed and Variable costs') + + +def CostFixedIndices(M: 'TemoaModel'): + # we pull the unlimited capacity techs from this index. They cannot have fixed costs + return {(r, p, t, v) for r, p, t, v in M.activeActivity_rptv if t not in M.tech_uncap} + + +def CostVariableIndices(M: 'TemoaModel'): + return M.activeActivity_rptv + + +# dev note: appears superfluous... +# def CostInvestIndices(M: 'TemoaModel'): +# indices = set((r, t, v) for r, p, t, v in M.processLoans) +# +# return indices + + +def get_loan_life(M: 'TemoaModel', r, t, v): + return M.LifetimeProcess[r, t, v] + + +def LifetimeLoanProcessIndices(M: 'TemoaModel'): + """\ +Based on the Efficiency parameter's indices and time_future parameter, this +function returns the set of process indices that may be specified in the +CostInvest parameter. +""" + min_period = min(M.vintage_optimize) + + indices = set((r, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys() if v >= min_period) + + return indices diff --git a/temoa/components/emissions.py b/temoa/components/emissions.py index e69de29bb..6f961d190 100644 --- a/temoa/components/emissions.py +++ b/temoa/components/emissions.py @@ -0,0 +1,30 @@ +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from temoa.core.model import TemoaModel + + +def EmissionActivityIndices(M: 'TemoaModel'): + indices = set( + (r, e, i, t, v, o) + for r, i, t, v, o in M.Efficiency.sparse_iterkeys() + for e in M.commodity_emissions + if r in M.regions # omit any exchange/groups + ) + + return indices + + +def LinkedTechConstraintIndices(M: 'TemoaModel'): + linkedtech_indices = set( + (r, p, s, d, t, v, e) + for r, t, e in M.LinkedTechs.sparse_iterkeys() + for p in M.time_optimize + if (r, p, t) in M.processVintages + for v in M.processVintages[r, p, t] + if (r, p, t, v) in M.activeActivity_rptv + for s in M.TimeSeason[p] + for d in M.time_of_day + ) + + return linkedtech_indices diff --git a/temoa/components/flows.py b/temoa/components/flows.py new file mode 100644 index 000000000..b056af776 --- /dev/null +++ b/temoa/components/flows.py @@ -0,0 +1,28 @@ +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from temoa.core.model import TemoaModel + + +def FlowVariableIndices(M: 'TemoaModel'): + return M.activeFlow_rpsditvo + + +def FlowVariableAnnualIndices(M: 'TemoaModel'): + return M.activeFlow_rpitvo + + +def FlexVariablelIndices(M: 'TemoaModel'): + return M.activeFlex_rpsditvo + + +def FlexVariableAnnualIndices(M: 'TemoaModel'): + return M.activeFlex_rpitvo + + +def FlowInStorageVariableIndices(M: 'TemoaModel'): + return M.activeFlowInStorage_rpsditvo + + +def CurtailmentVariableIndices(M: 'TemoaModel'): + return M.activeCurtailment_rpsditvo diff --git a/temoa/components/geography.py b/temoa/components/geography.py new file mode 100644 index 000000000..474b7c577 --- /dev/null +++ b/temoa/components/geography.py @@ -0,0 +1,50 @@ +from logging import getLogger +from typing import TYPE_CHECKING, Iterable + +from deprecated import deprecated + +if TYPE_CHECKING: + from temoa.core.model import TemoaModel + +logger = getLogger(name=__name__) + + +def CreateRegionalIndices(M: 'TemoaModel'): + """Create the set of all regions and all region-region pairs""" + regional_indices = set() + for r_i in M.regions: + if '-' in r_i: + logger.error("Individual region names can not have '-' in their names: %s", str(r_i)) + raise ValueError("Individual region names can not have '-' in their names: " + str(r_i)) + for r_j in M.regions: + if r_i == r_j: + regional_indices.add(r_i) + else: + regional_indices.add(r_i + '-' + r_j) + # dev note: Sorting these passed them to pyomo in an ordered container and prevents warnings + return sorted(regional_indices) + + +@deprecated('No longer used. See the region_group_check in validators.py') +def RegionalGlobalInitializedIndices(M: 'TemoaModel'): + from itertools import permutations + + indices = set() + for n in range(1, len(M.regions) + 1): + regional_perms = permutations(M.regions, n) + for i in regional_perms: + indices.add('+'.join(i)) + indices.add('global') + indices = indices.union(M.regionalIndices) + + return indices + + +def gather_group_regions(M: 'TemoaModel', region: str) -> Iterable[str]: + if region == 'global': + regions = M.regions + elif '+' in region: + regions = region.split('+') + else: + regions = (region,) + return regions diff --git a/temoa/components/limits.py b/temoa/components/limits.py index e69de29bb..0c73bfed2 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -0,0 +1,146 @@ +from logging import getLogger +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from temoa.core.model import TemoaModel + +logger = getLogger(__name__) + + +def LimitTechInputSplitConstraintIndices(M: 'TemoaModel'): + indices = set( + (r, p, s, d, i, t, v, op) + for r, p, i, t, op in M.inputSplitVintages + if t not in M.tech_annual + for v in M.inputSplitVintages[r, p, i, t, op] + for s in M.TimeSeason[p] + for d in M.time_of_day + ) + ann_indices = set( + (r, p, i, t, op) for r, p, i, t, op in M.inputSplitVintages if t in M.tech_annual + ) + if len(ann_indices) > 0: + msg = ( + 'Warning: Annual technologies included in LimitTechInputSplit table. ' + 'Use LimitTechInputSplitAnnual table instead or these constraints will be ignored: {}' + ) + logger.warning(msg.format(ann_indices)) + + return indices + + +def LimitTechInputSplitAnnualConstraintIndices(M: 'TemoaModel'): + indices = set( + (r, p, i, t, v, op) + for r, p, i, t, op in M.inputSplitAnnualVintages + if t in M.tech_annual + for v in M.inputSplitAnnualVintages[r, p, i, t, op] + ) + + return indices + + +def LimitTechInputSplitAverageConstraintIndices(M: 'TemoaModel'): + indices = set( + (r, p, i, t, v, op) + for r, p, i, t, op in M.inputSplitAnnualVintages + if t not in M.tech_annual + for v in M.inputSplitAnnualVintages[r, p, i, t, op] + ) + return indices + + +def LimitTechOutputSplitConstraintIndices(M: 'TemoaModel'): + indices = set( + (r, p, s, d, t, v, o, op) + for r, p, t, o, op in M.outputSplitVintages + if t not in M.tech_annual + for v in M.outputSplitVintages[r, p, t, o, op] + for s in M.TimeSeason[p] + for d in M.time_of_day + ) + ann_indices = set( + (r, p, t, o, op) for r, p, t, o, op in M.outputSplitVintages if t in M.tech_annual + ) + if len(ann_indices) > 0: + msg = ( + 'Warning: Annual technologies included in LimitTechOutputSplit table. ' + 'Use LimitTechOutputSplitAnnual table instead or these constraints will be ignored: {}' + ) + logger.warning(msg.format(ann_indices)) + + return indices + + +def LimitTechOutputSplitAnnualConstraintIndices(M: 'TemoaModel'): + indices = set( + (r, p, t, v, o, op) + for r, p, t, o, op in M.outputSplitAnnualVintages + if t in M.tech_annual + for v in M.outputSplitAnnualVintages[r, p, t, o, op] + ) + return indices + + +def LimitTechOutputSplitAverageConstraintIndices(M: 'TemoaModel'): + indices = set( + (r, p, t, v, o, op) + for r, p, t, o, op in M.outputSplitAnnualVintages + if t not in M.tech_annual + for v in M.outputSplitAnnualVintages[r, p, t, o, op] + ) + return indices + + +def LimitGrowthCapacityIndices(M: 'TemoaModel'): + indices = set( + (r, p, t, op) + for r, t, op in M.LimitGrowthCapacity.sparse_iterkeys() + for p in M.time_optimize + ) + return indices + + +def LimitDegrowthCapacityIndices(M: 'TemoaModel'): + indices = set( + (r, p, t, op) + for r, t, op in M.LimitDegrowthCapacity.sparse_iterkeys() + for p in M.time_optimize + ) + return indices + + +def LimitGrowthNewCapacityIndices(M: 'TemoaModel'): + indices = set( + (r, p, t, op) + for r, t, op in M.LimitGrowthNewCapacity.sparse_iterkeys() + for p in M.time_optimize + ) + return indices + + +def LimitDegrowthNewCapacityIndices(M: 'TemoaModel'): + indices = set( + (r, p, t, op) + for r, t, op in M.LimitDegrowthNewCapacity.sparse_iterkeys() + for p in M.time_optimize + ) + return indices + + +def LimitGrowthNewCapacityDeltaIndices(M: 'TemoaModel'): + indices = set( + (r, p, t, op) + for r, t, op in M.LimitGrowthNewCapacityDelta.sparse_iterkeys() + for p in M.time_optimize + ) + return indices + + +def LimitDegrowthNewCapacityDeltaIndices(M: 'TemoaModel'): + indices = set( + (r, p, t, op) + for r, t, op in M.LimitDegrowthNewCapacityDelta.sparse_iterkeys() + for p in M.time_optimize + ) + return indices diff --git a/temoa/components/operations.py b/temoa/components/operations.py new file mode 100644 index 000000000..03088f69c --- /dev/null +++ b/temoa/components/operations.py @@ -0,0 +1,16 @@ +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from temoa.core.model import TemoaModel + + +def BaseloadDiurnalConstraintIndices(M: 'TemoaModel'): + indices = set( + (r, p, s, d, t, v) + for r, p, t in M.baseloadVintages + for v in M.baseloadVintages[r, p, t] + for s in M.TimeSeason[p] + for d in M.time_of_day + ) + + return indices diff --git a/temoa/components/ramping.py b/temoa/components/ramping.py index e69de29bb..5009e9fce 100644 --- a/temoa/components/ramping.py +++ b/temoa/components/ramping.py @@ -0,0 +1,73 @@ +from typing import TYPE_CHECKING + +from pyomo.core import Set + +if TYPE_CHECKING: + from temoa.core.model import TemoaModel + + +def RampUpDayConstraintIndices(M: 'TemoaModel'): + indices = set( + (r, p, s, d, t, v) + for r, p, t in M.rampUpVintages + for v in M.rampUpVintages[r, p, t] + for s in M.TimeSeason[p] + for d in M.time_of_day + ) + + return indices + + +def RampDownDayConstraintIndices(M: 'TemoaModel'): + indices = set( + (r, p, s, d, t, v) + for r, p, t in M.rampDownVintages + for v in M.rampDownVintages[r, p, t] + for s in M.TimeSeason[p] + for d in M.time_of_day + ) + + return indices + + +def RampUpSeasonConstraintIndices(M: 'TemoaModel'): + if M.TimeSequencing.first() == 'consecutive_days': + return Set.Skip # dont need this constraint + + # s, s_next indexing ensures we dont build redundant constraints + indices = set( + (r, p, s, s_next, t, v) + for r, p, t in M.rampUpVintages + for v in M.rampUpVintages[r, p, t] + for _p, s_seq, s in M.ordered_season_sequential + if _p == p + for s_seq_next in (M.time_next_sequential[p, s_seq],) # next sequential season + for s_next in ( + M.sequential_to_season[p, s_seq_next], + ) # next sequential season's matching season + if s_next + != M.time_next[p, s, M.time_of_day.last()][0] # to avoid redundancy on RampDay constraint + ) + + return indices + + +def RampDownSeasonConstraintIndices(M: 'TemoaModel'): + if M.TimeSequencing.first() == 'consecutive_days': + return Set.Skip # dont need this constraint + + # s, s_next indexing ensures we dont build redundant constraints + indices = set( + (r, p, s, s_next, t, v) + for r, p, t in M.rampDownVintages + for v in M.rampDownVintages[r, p, t] + for _p, s_seq, s in M.ordered_season_sequential + for s_seq_next in (M.time_next_sequential[p, s_seq],) # next sequential season + for s_next in ( + M.sequential_to_season[p, s_seq_next], + ) # next sequential season's matching season + if s_next + != M.time_next[p, s, M.time_of_day.last()][0] # to avoid redundancy on RampDay constraint + ) + + return indices diff --git a/temoa/components/reserves.py b/temoa/components/reserves.py index e69de29bb..296ea5a00 100644 --- a/temoa/components/reserves.py +++ b/temoa/components/reserves.py @@ -0,0 +1,17 @@ +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from temoa.core.model import TemoaModel + + +def ReserveMarginIndices(M: 'TemoaModel'): + indices = set( + (r, p, s, d) + for r in M.PlanningReserveMargin.sparse_iterkeys() + for p in M.time_optimize + if (r, p) in M.processReservePeriods + for s in M.TimeSeason[p] + for d in M.time_of_day + ) + + return indices diff --git a/temoa/components/storage.py b/temoa/components/storage.py index e69de29bb..207d83259 100644 --- a/temoa/components/storage.py +++ b/temoa/components/storage.py @@ -0,0 +1,26 @@ +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from temoa.core.model import TemoaModel + + +def StorageLevelVariableIndices(M: 'TemoaModel'): + return M.storageLevelIndices_rpsdtv + + +def SeasonalStorageLevelVariableIndices(M: 'TemoaModel'): + return M.seasonalStorageLevelIndices_rpstv + + +def SeasonalStorageConstraintIndices(M: 'TemoaModel'): + indices = set( + (r, p, s, d, t, v) + for r, p, s, t, v in M.seasonalStorageLevelIndices_rpstv + for d in M.time_of_day + ) + + return indices + + +def StorageConstraintIndices(M: 'TemoaModel'): + return M.storageLevelIndices_rpsdtv diff --git a/temoa/components/technology.py b/temoa/components/technology.py index e69de29bb..bc1c1b623 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -0,0 +1,284 @@ +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from temoa.core.model import TemoaModel + + +from logging import getLogger +from typing import Iterable + +from pyomo.environ import value + +logger = getLogger(__name__) + + +def CheckEfficiencyIndices(M: 'TemoaModel'): + """ + Ensure that there are no unused items in any of the Efficiency index sets. + """ + # TODO: This could be upgraded to scan for finer resolution + # by checking by REGION and PERIOD... Each region/period is unique. + c_physical = set(i for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) + c_physical = c_physical | set(i for r, i, t, v in M.ConstructionInput.sparse_iterkeys()) + techs = set(t for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) + c_outputs = set(o for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) + c_outputs = c_outputs | set(o for r, t, v, o in M.EndOfLifeOutput.sparse_iterkeys()) + + symdiff = c_physical.symmetric_difference(M.commodity_physical) + if symdiff: + msg = ( + 'Unused or unspecified physical carriers. Either add or remove ' + 'the following elements to the Set commodity_physical.' + '\n\n Element(s): {}' + ) + symdiff = (str(i) for i in symdiff) + f_msg = msg.format(', '.join(symdiff)) + logger.error(f_msg) + raise ValueError(f_msg) + + symdiff = techs.symmetric_difference(M.tech_all) + if symdiff: + msg = ( + 'Unused or unspecified technologies. Either add or remove ' + 'the following technology(ies) to the tech_resource or ' + 'tech_production Sets.\n\n Technology(ies): {}' + ) + symdiff = (str(i) for i in symdiff) + f_msg = msg.format(', '.join(symdiff)) + logger.error(f_msg) + raise ValueError(f_msg) + + diff = M.commodity_demand - c_outputs + if diff: + msg = ( + 'Unused or unspecified outputs. Either add or remove the ' + 'following elements to the commodity_demand Set.' + '\n\n Element(s): {}' + ) + diff = (str(i) for i in diff) + f_msg = msg.format(', '.join(diff)) + logger.error(f_msg) + raise ValueError(f_msg) + + +def CheckEfficiencyVariable(M: 'TemoaModel'): + count_rpitvo = dict() + # Pull non-variable efficiency by default + for r, i, t, v, o in M.Efficiency.sparse_iterkeys(): + if (r, t, v) not in M.processPeriods: + # Probably an existing vintage that retires in p0 + # Still want it for end of life flows + continue + for p in M.processPeriods[r, t, v]: + M.isEfficiencyVariable[r, p, i, t, v, o] = False + count_rpitvo[r, p, i, t, v, o] = 0 + + annual = set() + # Check for bad values and count up the good ones + for r, p, _s, _d, i, t, v, o in M.EfficiencyVariable.sparse_iterkeys(): + if p not in M.processPeriods[r, t, v]: + msg = f'Invalid period {p} for process {r, t, v} in EfficiencyVariable table' + logger.error(msg) + raise ValueError(msg) + + if t in M.tech_annual: + annual.add(t) + + # Good value, pull from EfficiencyVariable table + count_rpitvo[r, p, i, t, v, o] += 1 + + for t in annual: + msg = ( + f'Variable efficiencies were provided for the annual technology {t}, which has ' + 'no variable output. This will only be applied to flows on non-annual commodities. ' + 'This is ambiguous behaviour and not recommended.' + ) + logger.warning(msg) + + # Check if all possible values have been set as variable + # log a warning if some are missing (allowed but maybe accidental) + num_seg = len(M.TimeSeason[p]) * len(M.time_of_day) + for (r, p, i, t, v, o), count in count_rpitvo.items(): + if count > 0: + M.isEfficiencyVariable[r, p, i, t, v, o] = True + if count < num_seg: + logger.info( + 'Some but not all EfficiencyVariable values were set (%i out of a possible %i) for: %s' + ' Missing values will default to value set in Efficiency table.', + count, + num_seg, + (r, p, i, t, v, o), + ) + + +def ModelProcessLifeIndices(M: 'TemoaModel'): + """\ +Returns the set of sensical (region, period, tech, vintage) tuples. The tuple indicates +the periods in which a process is active, distinct from TechLifeFracIndices that +returns indices only for processes that EOL mid-period. +""" + return M.activeActivity_rptv + + +def LifetimeProcessIndices(M: 'TemoaModel'): + """\ +Based on the Efficiency parameter's indices, this function returns the set of +process indices that may be specified in the LifetimeProcess parameter. +""" + indices = set((r, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) + + return indices + + +def get_default_survival(M: 'TemoaModel', r, p, t, v): + """ + Getting LifetimeSurvivalCurve where it is not defined + If this is a survival curve process, return 0 (likely beyond EOL) + Otherwise return 1 (no survival curve based EOL) + """ + if M.isSurvivalCurveProcess[r, t, v]: + return 0 + else: + return 1 + + +def get_default_process_lifetime(M: 'TemoaModel', r, t, v): + """ + This initializer used to initialize the LifetimeProcess parameter from LifetimeTech where needed + + Priority: + 1. Specified in LifetimeProcess data (provided as a fill and would not call this function) + 2. Specified in LifetimeTech data + 3. The default value from the LifetimeTech param (automatic) + :param M: generic model reference (not used) + :param r: region + :param t: tech + :param v: vintage + :return: the final lifetime value + """ + return M.LifetimeTech[r, t] + + +def gather_group_techs(M: 'TemoaModel', t_or_g: str) -> Iterable[str]: + if t_or_g in M.tech_group_names: + techs = M.tech_group_members[t_or_g] + elif '+' in t_or_g: + techs = t_or_g.split('+') + else: + techs = (t_or_g,) + return techs + + +def CreateSurvivalCurve(M: 'TemoaModel'): + rtv_interpolated = set() # so we only need one warning + + for r, _, t, v, _ in M.Efficiency.sparse_iterkeys(): + M.isSurvivalCurveProcess[r, t, v] = False # by default + + # Collect rptv indices into (r, t, v): p dictionary + for r, p, t, v in M.LifetimeSurvivalCurve.sparse_iterkeys(): + if (r, t, v) not in M.survivalCurvePeriods: + M.survivalCurvePeriods[r, t, v] = list() + M.survivalCurvePeriods[r, t, v].append(p) + M.isSurvivalCurveProcess[r, t, v] = True + + # Go through all the periods for each (r, t, v) in order + for r, t, v in M.survivalCurvePeriods: + periods_rtv = sorted(M.survivalCurvePeriods[r, t, v]) + + p_first = periods_rtv[0] + p_last = periods_rtv[-1] + + if p_first != v: + msg = ( + 'LifetimeSurvivalCurve must be defined starting in the vintage period. Must ' + f'define ({r}, >{v}<, {t}, {v})' + ) + logger.error(msg) + raise ValueError(msg) + + if value(M.LifetimeSurvivalCurve[r, v, t, v]) != 1: + msg = ( + 'LifetimeSurvivalCurve must begin at 1 for calculating annual retirements. ', + f'Got {value(M.LifetimeSurvivalCurve[r, v, t, v])} for ({r}, {v}, {t}, {v})', + ) + logger.error(msg) + raise ValueError(msg) + + # Collect a list of processes that needed to be interpolated, for warning + if periods_rtv != list(range(p_first, p_last + 1, 1)): + rtv_interpolated.add((r, t, v)) + + between_periods = [] + for i, p in enumerate(periods_rtv): + if i == 0: + continue # Cant look back from first period. Could be zero but hey why not + + # Check that the survival curve monotonically decreases + p_prev = periods_rtv[i - 1] + lsc = value(M.LifetimeSurvivalCurve[r, p, t, v]) + lsc_prev = value(M.LifetimeSurvivalCurve[r, p_prev, t, v]) + if lsc - lsc_prev > 0.0001: + msg = ( + 'LifetimeSurvivalCurve fraction increases going forward in time from {} to {}. ' + 'This is not allowed.' + ).format((r, p_prev, t, v), (r, p, t, v)) + logger.error(msg) + raise ValueError(msg) + + if p - p_prev > 1: + _between_periods = list(range(p_prev + 1, p, 1)) + for _p in _between_periods: + x = (_p - p_prev) / (p - p_prev) + lsc_x = lsc_prev + x * (lsc - lsc_prev) + M.LifetimeSurvivalCurve[r, _p, t, v] = lsc_x + between_periods.extend(_between_periods) + + if lsc < 0.0001: + if p != p_last: + msg = ( + 'There is no need to continue a survival curve beyond fraction ~= 0. ' + f'ignoring periods beyond {p} for ({r, t, v})' + ) + logger.info(msg) + + # Make sure the lifetime for this process aligns with survival curve end + if value(M.LifetimeProcess[r, t, v]) < p - v: + msg = ( + f'The LifetimeProcess parameter for process ({r, t, v}) with survival curve ' + f'does not extend beyond the end of that survival curve in {p}. To agree with ' + f'the survival curve, set LifetimeProcess[{r, t, v}] >= {p - v}' + ) + logger.error(msg) + raise ValueError(msg) + elif value(M.LifetimeProcess[r, t, v]) != p - v: + msg = ( + f'The LifetimeProcess parameter for process ({r, t, v}) with survival curve ' + f'does match the end of that survival curve in {p}. This will waste compute. ' + 'To agree with the survival curve and suppress this warning, set ' + f'LifetimeProcess[{r, t, v}] = {p - v}' + ) + logger.warning(msg) + + continue + + # Flag if the last period is not fraction = 0. This is important for investment costs + if p == p_last and lsc > 0.0001: + msg = ( + 'Any defined survival curve must continue to zero for the purposes of ' + 'investment cost accounting, even if this period would extend beyond ' + f'defined future periods. Continue ({r, t, v}) to fraction == 0.' + ) + logger.error(msg) + raise ValueError(msg) + + M.survivalCurvePeriods[r, t, v].extend(between_periods) + M.survivalCurvePeriods[r, t, v] = set(M.survivalCurvePeriods[r, t, v]) + + if rtv_interpolated: + msg = ( + 'For the purposes of investment cost accounting, LifetimeSurvivalCurve must be defined ' + 'for each individual year. Gaps between defined years will be filled by linear interpolation. ' + 'Otherwise, these individual years can be defined manually. Interpolated processes: {}' + ).format([rtv for rtv in rtv_interpolated]) + logger.info(msg) diff --git a/temoa/components/time.py b/temoa/components/time.py index e69de29bb..a1c9850c4 100644 --- a/temoa/components/time.py +++ b/temoa/components/time.py @@ -0,0 +1,346 @@ +# temoa/components/time.py +""" +This module contains components related to time indexing in the Temoa model. +""" + +from logging import getLogger +from typing import TYPE_CHECKING + +from pyomo.environ import value + +if TYPE_CHECKING: + from temoa.core.model import TemoaModel + + +logger = getLogger(__name__) + + +def init_set_time_optimize(M: 'TemoaModel'): + return sorted(M.time_future)[:-1] + + +def validate_time(M: 'TemoaModel'): + """ + We check for integer status here, rather than asking Pyomo to do this via + a 'within=Integers' clause in the definition so that we can have a very + specific error message. If we instead use Pyomo's mechanism, the + python invocation of Temoa throws an error (including a traceback) + that has proven to be scary and/or impenetrable for the typical modeler. + """ + logger.debug('Started validating time index') + for year in M.time_exist: + if isinstance(year, int): + continue + + msg = f'Set "time_exist" requires integer-only elements.\n\n Invalid element: "{year}"' + logger.error(msg) + raise Exception(msg) + + for year in M.time_future: + if isinstance(year, int): + continue + + msg = f'Set "time_future" requires integer-only elements.\n\n invalid element: "{year}"' + logger.error(msg) + raise Exception(msg) + + if len(M.time_future) < 2: + msg = ( + 'Set "time_future" needs at least 2 specified years. \nTemoa ' + 'treats the integer numbers specified in this set as boundary years \n' + 'between periods, and uses them to automatically ascertain the length \n' + '(in years) of each period. Note that this means that there will be \n' + 'one less optimization period than the number of elements in this set.' + ) + + logger.error(msg) + raise RuntimeError(msg) + + # Ensure that the time_exist < time_future + if len(M.time_exist) > 0: + max_exist = max(M.time_exist) + min_horizon = min(M.time_future) + + if not (max_exist < min_horizon): + msg = ( + 'All items in time_future must be larger than in time_exist.' + '\ntime_exist max: {}' + '\ntime_future min: {}' + ) + logger.error(msg.format(max_exist, min_horizon)) + raise Exception(msg.format(max_exist, min_horizon)) + logger.debug('Finished validating time') + + +def validate_TimeNext(M: 'TemoaModel'): + """ + If using this table, check that defined states are actually valid. + TimeSegmentFraction is already compared to other tables so just compare to SegFrac. + """ + # Only check TimeNext if it is actually being used + if M.TimeSequencing.first() != 'manual': + return + + segfrac_psd = set(M.SegFrac.sparse_iterkeys()) + time_next_psd = set((p, s, d) for p, s, d, s_next, d_next in M.TimeNext) + time_next_psd_next = set((p, s_next, d_next) for p, s, d, s_next, d_next in M.TimeNext) + + missing_psd = segfrac_psd.difference(time_next_psd) + missing_psd_next = segfrac_psd.difference(time_next_psd_next) + if missing_psd or missing_psd_next: + msg = ( + 'Failed to build state sequence. ' + '\nThese states from TimeSegmentFraction were not given a next state:\n{}\n' + '\nThese states from TimeSegmentFraction do not follow any state:\n{}' + ).format(missing_psd, missing_psd_next) + logger.error(msg) + raise ValueError(msg) + + +def loop_period_next_timeslice(M: 'TemoaModel', p, s, d) -> tuple[str, str]: + # Final time slice of final season (end of period) + # Loop state back to initial state of first season + # Loop the period + if s == M.TimeSeason[p].last() and d == M.time_of_day.last(): + s_next = M.TimeSeason[p].first() + d_next = M.time_of_day.first() + + # Last time slice of any season that is NOT the last season + # Carry state to initial state of next season + # Carry state between seasons + elif d == M.time_of_day.last(): + s_next = M.TimeSeason[p].next(s) + d_next = M.time_of_day.first() + + # Any other time slice + # Carry state to next time slice in the same season + # Continuing through this season + else: + s_next = s + d_next = M.time_of_day.next(d) + + return s_next, d_next + + +def loop_season_next_timeslice(M: 'TemoaModel', p, s, d) -> tuple[str, str]: + # We loop each season so never carrying state between seasons + s_next = s + + # Final time slice of any season + # Loop state back to initial state of same season + # Loop each season + if d == M.time_of_day.last(): + d_next = M.time_of_day.first() + + # Any other time slice + # Carry state to next time slice in the same season + # Continuing through this season + else: + d_next = M.time_of_day.next(d) + + return s_next, d_next + + +def CreateTimeSequence(M: 'TemoaModel'): + logger.debug('Creating sequence of time slices.') + + # Establishing sequence of states + match M.TimeSequencing.first(): + case 'consecutive_days': + msg = 'Running a consecutive days database.' + for p in M.time_optimize: + for s, d in M.TimeSeason[p] * M.time_of_day: + M.time_next[p, s, d] = loop_period_next_timeslice(M, p, s, d) + case 'seasonal_timeslices': + msg = 'Running a seasonal time slice database.' + for p in M.time_optimize: + for s, d in M.TimeSeason[p] * M.time_of_day: + M.time_next[p, s, d] = loop_season_next_timeslice(M, p, s, d) + case 'representative_periods': + msg = 'Running a representative periods database.' + for p in M.time_optimize: + for s, d in M.TimeSeason[p] * M.time_of_day: + M.time_next[p, s, d] = loop_season_next_timeslice(M, p, s, d) + case 'manual': + # Hidden feature. Define the sequence directly in the TimeNext table + msg = 'Pulling time sequence from TimeNext table.' + for p, s, d, s_next, d_next in M.TimeNext: + M.time_next[p, s, d] = s_next, d_next + case _: + # This should have been caught in hybrid_loader + msg = f"Invalid time sequencing parameter loaded '{M.TimeSequencing.first()}'. Likely code error." + logger.error(msg) + raise ValueError(msg) + + msg += ' This behaviour can be changed using the time_sequencing parameter in the config file. ' + logger.info(msg) + + logger.debug('Creating superimposed sequential seasons.') + + # Superimposed sequential seasons + for p in M.time_optimize: + seasons = [(s_seq, s) for _p, s_seq, s in M.ordered_season_sequential if _p == p] + for i, (s_seq, s) in enumerate(seasons): + M.sequential_to_season[p, s_seq] = s + if (s_seq, s) == seasons[-1]: + M.time_next_sequential[p, s_seq] = seasons[0][0] + else: + M.time_next_sequential[p, s_seq] = seasons[i + 1][0] + + logger.debug('Created time sequence.') + + +def CreateTimeSeasonSequential(M: 'TemoaModel'): + if all( + ( + not M.tech_seasonal_storage, + not M.RampUpHourly, + not M.RampDownHourly, + ) + ): + # Don't need it anyway + return + + if not M.TimeSeasonSequential: + if M.TimeSequencing.first() in ('consecutive_days', 'seasonal_timeslices'): + logger.info( + 'No data in TimeSeasonSequential. By default, assuming sequential seasons ' + 'match TimeSeason and TimeSegmentFraction.' + ) + for s in M.time_season: + M.time_season_sequential.add(s) + for p in M.TimeSeason: + for s in M.TimeSeason[p]: + M.ordered_season_sequential.add((p, s, s)) + M.TimeSeasonSequential[p, s, s] = value(M.SegFracPerSeason[p, s]) * value( + M.DaysPerPeriod + ) + + else: + msg = ( + f'No data in TimeSeasonSequential but time_sequencing parameter set to {M.TimeSequencing.first()} ' + 'and inter-season features used. TimeSeasonSequential must be filled for this type of time ' + 'sequencing if seasonal storage or inter-season constraints like RampUp/RampDown are used. Check ' + 'the config file.' + ) + logger.error(msg) + raise ValueError(msg) + + sequential = dict() + prev_n = 0 + for p, s_seq, s in M.TimeSeasonSequential.sparse_iterkeys(): + num_days = value(M.TimeSeasonSequential[p, s_seq, s]) + if ( + M.TimeSequencing.first() == 'consecutive_days' + and prev_n + and abs(num_days - prev_n) >= 0.001 + ): + msg = ( + 'TimeSequencing set to consecutive_days but two consecutive seasons do not represent the same ' + f'number of days. This discontinuity will lead to bad model behaviour: {p, s}, days: {num_days}. ' + f'Previous number of days: {prev_n}. Check the config file for more information.' + ) + logger.error(msg) + raise ValueError(msg) + prev_n = num_days # for validating next in sequence + + # Regardless of their order, make sure the total number of days adds up + if (p, s) not in sequential: + sequential[p, s] = 0 + sequential[p, s] += num_days + + # Check that TimeSeasonSequential num_days total to number of days in each period + count_total = dict() # {p: n} total days per period according to TimeSeasonSequential + for p in M.time_optimize: + count_total[p] = sum(sequential[p, s] for _p, s in sequential if _p == p) + if abs(count_total[p] - value(M.DaysPerPeriod)) >= 0.001: + logger.warning( + f'Sum of num_days in TimeSeasonSequential ({count_total[p]}) ' + f'for period {p} does not sum to days_per_period ({value(M.DaysPerPeriod)}) ' + 'from the MetaData table.' + ) + + # Check that seasons using in storage seasons are actual seasons + for p, s in sequential: + if (p, s) not in M.SegFracPerSeason: + msg = ( + f'Period-season index {(p, s)} that does not exist in ' + 'TimeSegmentFraction referenced in TimeSeasonSequential .' + ) + logger.error(msg) + raise ValueError(msg) + + for p, s in M.SegFracPerSeason.sparse_iterkeys(): + if s not in M.TimeSeason[p]: + continue + + # Check that all seasons are used in sequential seasons + if (p, s) not in sequential: + msg = f'Period-season index {(p, s)} absent from TimeSeasonSequential' + logger.warning(msg) + + # Check that the two tables agree on the total seasonal composition of each period + segfrac = value(M.SegFracPerSeason[p, s]) + segfracseq = sequential[p, s] / count_total[p] + if abs(segfrac - segfracseq) >= 0.001: + msg = ( + 'Discrepancy of total period-season composition between ' + 'TimeSegmentFraction and TimeSeasonSequential. Total fraction of each ' + 'period assigned to each season should match: ' + f'TimeSegmentFraction: {(p, s, value(M.SegFracPerSeason[p, s]))}' + f', TimeSeasonSequential: {(p, s, segfracseq)}' + ) + logger.warning(msg) + + +def validate_SegFrac(M: 'TemoaModel'): + """Ensure that the segment fractions adds up to 1""" + + for p in M.time_optimize: + expected_keys = set((p, s, d) for s in M.TimeSeason[p] for d in M.time_of_day) + keys = set((_p, s, d) for _p, s, d in M.SegFrac.sparse_iterkeys() if _p == p) + + if expected_keys != keys: + extra = keys.difference(expected_keys) + missing = expected_keys.difference(keys) + msg = ( + 'TimeSegmentFraction elements for period {} do not match TimeSeason and TimeOfDay.' + '\n\nIndices missing from TimeSegmentFraction:\n{}' + '\n\nIndices in TimeSegmentFraction missing from TimeSeason/TimeOfDay:\n{}' + ).format(p, missing, extra) + logger.error(msg) + raise ValueError(msg) + + total = sum(M.SegFrac[k] for k in keys) + + if abs(float(total) - 1.0) > 0.001: + # We can't explicitly test for "!= 1.0" because of incremental rounding + # errors associated with the specification of SegFrac by time slice, + # but we check to make sure it is within the specified tolerance. + + def get_str_padding(obj): + return len(str(obj)) + + key_padding = max(map(get_str_padding, keys)) + + fmt = '%%-%ds = %%s' % key_padding + # Works out to something like "%-25s = %s" + + items = sorted([(k, M.SegFrac[k]) for k in keys]) + items = '\n '.join(fmt % (str(k), v) for k, v in items) + + msg = ( + 'The values of TimeSegmentFraction do not sum to 1 for period {}. ' + 'Each item in SegFrac represents a fraction of a year, so they must ' + 'total to 1. Current values:\n {}\n\tsum = {}' + ).format(p, items, total) + logger.error(msg) + raise Exception(msg) + + +def init_set_vintage_exist(M: 'TemoaModel'): + return sorted(M.time_exist) + + +def init_set_vintage_optimize(M: 'TemoaModel'): + return sorted(M.time_optimize) diff --git a/temoa/core/model.py b/temoa/core/model.py index c3f1d9e4b..23c27af29 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -23,80 +23,7 @@ minimize, ) -from temoa._internal.temoa_initialize import ( - # ============================================================================ - # Index creation functions for constraints and variables - # ============================================================================ - AnnualCommodityBalanceConstraintIndices, - AnnualRetirementVariableIndices, - BaseloadDiurnalConstraintIndices, - CapacityAnnualConstraintIndices, - CapacityAvailableVariableIndices, - CapacityConstraintIndices, - CapacityFactorTechIndices, - CapacityVariableIndices, - CheckCapacityFactorProcess, - CheckEfficiencyIndices, - CheckEfficiencyVariable, - CommodityBalanceConstraintIndices, - CostFixedIndices, - CostVariableIndices, - CreateDemands, - CreateRegionalIndices, - CreateSparseDicts, - CreateSurvivalCurve, - CreateTimeSeasonSequential, - CreateTimeSequence, - CurtailmentVariableIndices, - DemandActivityConstraintIndices, - EmissionActivityIndices, - FlexVariableAnnualIndices, - FlexVariablelIndices, - FlowInStorageVariableIndices, - FlowVariableAnnualIndices, - FlowVariableIndices, - LifetimeLoanProcessIndices, - LifetimeProcessIndices, - LimitDegrowthCapacityIndices, - LimitDegrowthNewCapacityDeltaIndices, - LimitDegrowthNewCapacityIndices, - LimitGrowthCapacityIndices, - LimitGrowthNewCapacityDeltaIndices, - LimitGrowthNewCapacityIndices, - LimitTechInputSplitAnnualConstraintIndices, - LimitTechInputSplitAverageConstraintIndices, - LimitTechInputSplitConstraintIndices, - LimitTechOutputSplitAnnualConstraintIndices, - LimitTechOutputSplitAverageConstraintIndices, - LimitTechOutputSplitConstraintIndices, - LinkedTechConstraintIndices, - ModelProcessLifeIndices, - RampDownDayConstraintIndices, - RampDownSeasonConstraintIndices, - RampUpDayConstraintIndices, - RampUpSeasonConstraintIndices, - RegionalExchangeCapacityConstraintIndices, - ReserveMarginIndices, - RetiredCapacityVariableIndices, - SeasonalStorageConstraintIndices, - SeasonalStorageLevelVariableIndices, - StorageConstraintIndices, - StorageLevelVariableIndices, - # Default value functions - get_default_capacity_factor, - get_default_loan_rate, - get_default_process_lifetime, - get_default_survival, - get_loan_life, - # Set initialization functions - init_set_time_optimize, - init_set_vintage_exist, - init_set_vintage_optimize, - # Validation functions - validate_SegFrac, - validate_time, - validate_TimeNext, -) +from temoa._internal.temoa_initialize import CreateSparseDicts # ============================================================================ # Temoa Constraint Functions @@ -168,6 +95,21 @@ # Objective function TotalCost_rule, ) +from temoa.components import ( + capacity, + commodities, + costs, + emissions, + flows, + geography, + limits, + operations, + ramping, + reserves, + storage, + technology, + time, +) # ============================================================================ # Validation Functions @@ -302,13 +244,15 @@ def __init__(M, *args, **kwargs): # Define time periods M.time_exist = Set(ordered=True) M.time_future = Set(ordered=True) - M.time_optimize = Set(ordered=True, initialize=init_set_time_optimize, within=M.time_future) + M.time_optimize = Set( + ordered=True, initialize=time.init_set_time_optimize, within=M.time_future + ) # Define time period vintages to track capacity installation - M.vintage_exist = Set(ordered=True, initialize=init_set_vintage_exist) - M.vintage_optimize = Set(ordered=True, initialize=init_set_vintage_optimize) + M.vintage_exist = Set(ordered=True, initialize=time.init_set_vintage_exist) + M.vintage_optimize = Set(ordered=True, initialize=time.init_set_vintage_optimize) M.vintage_all = Set(initialize=M.time_exist | M.time_optimize) # Perform some basic validation on the specified time periods. - M.validate_time = BuildAction(rule=validate_time) + M.validate_time = BuildAction(rule=time.validate_time) # Define the model time slices M.time_season = Set(ordered=True, validate=no_slash_or_pipe) @@ -326,7 +270,7 @@ def __init__(M, *args, **kwargs): M.regions = Set(validate=region_check) # RegionalIndices is the set of all the possible combinations of interregional exchanges # plus original region indices. If tech_exchange is empty, RegionalIndices =regions. - M.regionalIndices = Set(initialize=CreateRegionalIndices) + M.regionalIndices = Set(initialize=geography.CreateRegionalIndices) M.regionalGlobalIndices = Set(validate=region_group_check) # Define technology-related sets @@ -418,12 +362,12 @@ def __init__(M, *args, **kwargs): # Define time-related parameters M.PeriodLength = Param(M.time_optimize, initialize=ParamPeriodLength) M.SegFrac = Param(M.time_optimize, M.time_season, M.time_of_day) - M.validate_SegFrac = BuildAction(rule=validate_SegFrac) + M.validate_SegFrac = BuildAction(rule=time.validate_SegFrac) M.TimeSequencing = Set() # How do states carry between time segments? M.TimeNext = Set( ordered=True ) # This is just to get data from the table. Hidden feature and usually not used - M.validate_TimeNext = BuildAction(rule=validate_TimeNext) + M.validate_TimeNext = BuildAction(rule=time.validate_TimeNext) # Define demand- and resource-related parameters # Dev Note: There does not appear to be a DB table supporting DemandDefaultDistro. @@ -481,7 +425,7 @@ def __init__(M, *args, **kwargs): within=NonNegativeReals, validate=validate_Efficiency, ) - M.validate_UsedEfficiencyIndices = BuildAction(rule=CheckEfficiencyIndices) + M.validate_UsedEfficiencyIndices = BuildAction(rule=technology.CheckEfficiencyIndices) M.EfficiencyVariable = Param( M.regionalIndices, @@ -500,28 +444,30 @@ def __init__(M, *args, **kwargs): M.regionalIndices, M.tech_all, default=TemoaModel.default_lifetime_tech ) - M.LifetimeProcess_rtv = Set(dimen=3, initialize=LifetimeProcessIndices) - M.LifetimeProcess = Param(M.LifetimeProcess_rtv, default=get_default_process_lifetime) + M.LifetimeProcess_rtv = Set(dimen=3, initialize=technology.LifetimeProcessIndices) + M.LifetimeProcess = Param( + M.LifetimeProcess_rtv, default=technology.get_default_process_lifetime + ) M.LifetimeSurvivalCurve = Param( M.regionalIndices, Integers, M.tech_all, M.vintage_all, - default=get_default_survival, + default=technology.get_default_survival, validate=validate_0to1, mutable=True, ) - M.Create_SurvivalCurve = BuildAction(rule=CreateSurvivalCurve) + M.Create_SurvivalCurve = BuildAction(rule=technology.CreateSurvivalCurve) - M.LoanLifetimeProcess_rtv = Set(dimen=3, initialize=LifetimeLoanProcessIndices) + M.LoanLifetimeProcess_rtv = Set(dimen=3, initialize=costs.LifetimeLoanProcessIndices) # Dev Note: The LoanLifetimeProcess table *could* be removed. There is no longer a # supporting table in the database. It is just a "passthrough" now to the # default LoanLifetimeTech. It is already stitched in to the model, # so will leave it for now. Table may be revived. - M.LoanLifetimeProcess = Param(M.LoanLifetimeProcess_rtv, default=get_loan_life) + M.LoanLifetimeProcess = Param(M.LoanLifetimeProcess_rtv, default=costs.get_loan_life) M.LimitTechInputSplit = Param( M.regions, @@ -574,16 +520,16 @@ def __init__(M, *args, **kwargs): M.TimeSeasonSequential = Param( M.time_optimize, M.time_season_sequential, M.time_season, mutable=True ) - M.validate_SeasonSequential = BuildAction(rule=CreateTimeSeasonSequential) - M.Create_TimeSequence = BuildAction(rule=CreateTimeSequence) + M.validate_SeasonSequential = BuildAction(rule=time.CreateTimeSeasonSequential) + M.Create_TimeSequence = BuildAction(rule=time.CreateTimeSequence) # The method below creates a series of helper functions that are used to # perform the sparse matrix of indexing for the parameters, variables, and # equations below. M.Create_SparseDicts = BuildAction(rule=CreateSparseDicts) - M.initialize_Demands = BuildAction(rule=CreateDemands) + M.initialize_Demands = BuildAction(rule=commodities.CreateDemands) - M.CapacityFactor_rpsdt = Set(dimen=5, initialize=CapacityFactorTechIndices) + M.CapacityFactor_rpsdt = Set(dimen=5, initialize=capacity.CapacityFactorTechIndices) M.CapacityFactorTech = Param(M.CapacityFactor_rpsdt, default=1, validate=validate_0to1) # Dev note: using a default function below alleviates need to make this set. @@ -597,27 +543,29 @@ def __init__(M, *args, **kwargs): M.vintage_all, # validate=validate_CapacityFactorProcess, # opting for a quicker validation, just 0->1 validate=validate_0to1, - default=get_default_capacity_factor, # slow but only called if a value is missing + default=capacity.get_default_capacity_factor, # slow but only called if a value is missing ) - M.CapacityConstraint_rpsdtv = Set(dimen=6, initialize=CapacityConstraintIndices) - M.initialize_CapacityFactors = BuildAction(rule=CheckCapacityFactorProcess) - M.initialize_EfficiencyVariable = BuildAction(rule=CheckEfficiencyVariable) + M.CapacityConstraint_rpsdtv = Set(dimen=6, initialize=capacity.CapacityConstraintIndices) + M.initialize_CapacityFactors = BuildAction(rule=capacity.CheckCapacityFactorProcess) + M.initialize_EfficiencyVariable = BuildAction(rule=technology.CheckEfficiencyVariable) # Define technology cost parameters # dev note: the CostFixed_rptv isn't truly needed, but it is included in a constraint, so # let it go for now - M.CostFixed_rptv = Set(dimen=4, initialize=CostFixedIndices) + M.CostFixed_rptv = Set(dimen=4, initialize=costs.CostFixedIndices) M.CostFixed = Param(M.CostFixed_rptv) M.CostInvest_rtv = Set(within=M.regionalIndices * M.tech_all * M.time_optimize) M.CostInvest = Param(M.CostInvest_rtv) M.DefaultLoanRate = Param(domain=NonNegativeReals) - M.LoanRate = Param(M.CostInvest_rtv, domain=NonNegativeReals, default=get_default_loan_rate) + M.LoanRate = Param( + M.CostInvest_rtv, domain=NonNegativeReals, default=costs.get_default_loan_rate + ) M.LoanAnnualize = Param(M.CostInvest_rtv, initialize=ParamLoanAnnualize_rule) - M.CostVariable_rptv = Set(dimen=4, initialize=CostVariableIndices) + M.CostVariable_rptv = Set(dimen=4, initialize=costs.CostVariableIndices) M.CostVariable = Param(M.CostVariable_rptv) M.CostEmission_rpe = Set(within=M.regions * M.time_optimize * M.commodity_emissions) @@ -627,7 +575,7 @@ def __init__(M, *args, **kwargs): # 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_rptv = Set(dimen=4, initialize=technology.ModelProcessLifeIndices) M.ProcessLifeFrac = Param(M.ProcessLifeFrac_rptv, initialize=ParamProcessLifeFraction_rule) M.LimitCapacityConstraint_rpt = Set( @@ -695,7 +643,7 @@ def __init__(M, *args, **kwargs): within=M.regionalGlobalIndices * M.time_optimize * M.commodity_emissions * M.operator ) M.LimitEmission = Param(M.LimitEmissionConstraint_rpe) - M.EmissionActivity_reitvo = Set(dimen=6, initialize=EmissionActivityIndices) + M.EmissionActivity_reitvo = Set(dimen=6, initialize=emissions.EmissionActivityIndices) M.EmissionActivity = Param(M.EmissionActivity_reitvo) # devnote: deprecated when generalising tech/group columns in Limit tables @@ -752,9 +700,9 @@ def __init__(M, *args, **kwargs): # M.LimitActivityGroupShare = Param(M.TwoGroupShareIndices) # This set works for all storage-related constraints - M.StorageConstraints_rpsdtv = Set(dimen=6, initialize=StorageConstraintIndices) + M.StorageConstraints_rpsdtv = Set(dimen=6, initialize=storage.StorageConstraintIndices) M.SeasonalStorageConstraints_rpsdtv = Set( - dimen=6, initialize=SeasonalStorageConstraintIndices + dimen=6, initialize=storage.SeasonalStorageConstraintIndices ) M.LimitStorageFractionConstraint_rpsdtv = Set( within=(M.StorageConstraints_rpsdtv | M.SeasonalStorageConstraints_rpsdtv) * M.operator @@ -815,46 +763,52 @@ def __init__(M, *args, **kwargs): M.progress_marker_3 = BuildAction(['Starting to build Variables'], rule=progress_check) # Define base decision variables - M.FlowVar_rpsditvo = Set(dimen=8, initialize=FlowVariableIndices) + M.FlowVar_rpsditvo = Set(dimen=8, initialize=flows.FlowVariableIndices) M.V_FlowOut = Var(M.FlowVar_rpsditvo, domain=NonNegativeReals) - M.FlowVarAnnual_rpitvo = Set(dimen=6, initialize=FlowVariableAnnualIndices) + M.FlowVarAnnual_rpitvo = Set(dimen=6, initialize=flows.FlowVariableAnnualIndices) M.V_FlowOutAnnual = Var(M.FlowVarAnnual_rpitvo, domain=NonNegativeReals) - M.FlexVar_rpsditvo = Set(dimen=8, initialize=FlexVariablelIndices) + M.FlexVar_rpsditvo = Set(dimen=8, initialize=flows.FlexVariablelIndices) M.V_Flex = Var(M.FlexVar_rpsditvo, domain=NonNegativeReals) - M.FlexVarAnnual_rpitvo = Set(dimen=6, initialize=FlexVariableAnnualIndices) + M.FlexVarAnnual_rpitvo = Set(dimen=6, initialize=flows.FlexVariableAnnualIndices) M.V_FlexAnnual = Var(M.FlexVarAnnual_rpitvo, domain=NonNegativeReals) - M.CurtailmentVar_rpsditvo = Set(dimen=8, initialize=CurtailmentVariableIndices) + M.CurtailmentVar_rpsditvo = Set(dimen=8, initialize=flows.CurtailmentVariableIndices) M.V_Curtailment = Var(M.CurtailmentVar_rpsditvo, domain=NonNegativeReals, initialize=0) - M.FlowInStorage_rpsditvo = Set(dimen=8, initialize=FlowInStorageVariableIndices) + M.FlowInStorage_rpsditvo = Set(dimen=8, initialize=flows.FlowInStorageVariableIndices) M.V_FlowIn = Var(M.FlowInStorage_rpsditvo, domain=NonNegativeReals) - M.StorageLevel_rpsdtv = Set(dimen=6, initialize=StorageLevelVariableIndices) + M.StorageLevel_rpsdtv = Set(dimen=6, initialize=storage.StorageLevelVariableIndices) M.V_StorageLevel = Var(M.StorageLevel_rpsdtv, domain=NonNegativeReals) - M.SeasonalStorageLevel_rpstv = Set(dimen=5, initialize=SeasonalStorageLevelVariableIndices) + M.SeasonalStorageLevel_rpstv = Set( + dimen=5, initialize=storage.SeasonalStorageLevelVariableIndices + ) M.V_SeasonalStorageLevel = Var(M.SeasonalStorageLevel_rpstv, domain=NonNegativeReals) # Derived decision variables - M.CapacityVar_rptv = Set(dimen=4, initialize=CostFixedIndices) + M.CapacityVar_rptv = Set(dimen=4, initialize=costs.CostFixedIndices) M.V_Capacity = Var(M.CapacityVar_rptv, domain=NonNegativeReals) - M.NewCapacityVar_rtv = Set(dimen=3, initialize=CapacityVariableIndices) + M.NewCapacityVar_rtv = Set(dimen=3, initialize=capacity.CapacityVariableIndices) M.V_NewCapacity = Var(M.NewCapacityVar_rtv, domain=NonNegativeReals, initialize=0) - M.RetiredCapacityVar_rptv = Set(dimen=4, initialize=RetiredCapacityVariableIndices) + M.RetiredCapacityVar_rptv = Set(dimen=4, initialize=capacity.RetiredCapacityVariableIndices) M.V_RetiredCapacity = Var(M.RetiredCapacityVar_rptv, domain=NonNegativeReals, initialize=0) - M.AnnualRetirementVar_rptv = Set(dimen=4, initialize=AnnualRetirementVariableIndices) + M.AnnualRetirementVar_rptv = Set( + dimen=4, initialize=capacity.AnnualRetirementVariableIndices + ) M.V_AnnualRetirement = Var( M.AnnualRetirementVar_rptv, domain=NonNegativeReals, initialize=0 ) - M.CapacityAvailableVar_rpt = Set(dimen=3, initialize=CapacityAvailableVariableIndices) + M.CapacityAvailableVar_rpt = Set( + dimen=3, initialize=capacity.CapacityAvailableVariableIndices + ) M.V_CapacityAvailableByPeriodAndTech = Var( M.CapacityAvailableVar_rpt, domain=NonNegativeReals, initialize=0 ) @@ -883,7 +837,9 @@ def __init__(M, *args, **kwargs): # Declare constraints to calculate derived decision variables M.CapacityConstraint = Constraint(M.CapacityConstraint_rpsdtv, rule=Capacity_Constraint) - M.CapacityAnnualConstraint_rptv = Set(dimen=4, initialize=CapacityAnnualConstraintIndices) + M.CapacityAnnualConstraint_rptv = Set( + dimen=4, initialize=capacity.CapacityAnnualConstraintIndices + ) M.CapacityAnnualConstraint = Constraint( M.CapacityAnnualConstraint_rptv, rule=CapacityAnnual_Constraint ) @@ -917,21 +873,21 @@ def __init__(M, *args, **kwargs): # devnote: testing a workaround M.DemandActivityConstraint_rpsdtv_dem = Set( - dimen=7, initialize=DemandActivityConstraintIndices + dimen=7, initialize=commodities.DemandActivityConstraintIndices ) M.DemandActivityConstraint = Constraint( M.DemandActivityConstraint_rpsdtv_dem, rule=DemandActivity_Constraint ) M.CommodityBalanceConstraint_rpsdc = Set( - dimen=5, initialize=CommodityBalanceConstraintIndices + dimen=5, initialize=commodities.CommodityBalanceConstraintIndices ) M.CommodityBalanceConstraint = Constraint( M.CommodityBalanceConstraint_rpsdc, rule=CommodityBalance_Constraint ) M.AnnualCommodityBalanceConstraint_rpc = Set( - dimen=3, initialize=AnnualCommodityBalanceConstraintIndices + dimen=3, initialize=commodities.AnnualCommodityBalanceConstraintIndices ) M.AnnualCommodityBalanceConstraint = Constraint( M.AnnualCommodityBalanceConstraint_rpc, rule=AnnualCommodityBalance_Constraint @@ -942,14 +898,14 @@ def __init__(M, *args, **kwargs): # ) M.BaseloadDiurnalConstraint_rpsdtv = Set( - dimen=6, initialize=BaseloadDiurnalConstraintIndices + dimen=6, initialize=operations.BaseloadDiurnalConstraintIndices ) M.BaseloadDiurnalConstraint = Constraint( M.BaseloadDiurnalConstraint_rpsdtv, rule=BaseloadDiurnal_Constraint ) M.RegionalExchangeCapacityConstraint_rrptv = Set( - dimen=5, initialize=RegionalExchangeCapacityConstraintIndices + dimen=5, initialize=capacity.RegionalExchangeCapacityConstraintIndices ) M.RegionalExchangeCapacityConstraint = Constraint( M.RegionalExchangeCapacityConstraint_rrptv, rule=RegionalExchangeCapacity_Constraint @@ -989,23 +945,29 @@ def __init__(M, *args, **kwargs): M.LimitStorageFractionConstraint_rpsdtv, rule=LimitStorageFraction_Constraint ) - M.RampUpDayConstraint_rpsdtv = Set(dimen=6, initialize=RampUpDayConstraintIndices) + M.RampUpDayConstraint_rpsdtv = Set(dimen=6, initialize=ramping.RampUpDayConstraintIndices) M.RampUpDayConstraint = Constraint(M.RampUpDayConstraint_rpsdtv, rule=RampUpDay_Constraint) - M.RampDownDayConstraint_rpsdtv = Set(dimen=6, initialize=RampDownDayConstraintIndices) + M.RampDownDayConstraint_rpsdtv = Set( + dimen=6, initialize=ramping.RampDownDayConstraintIndices + ) M.RampDownDayConstraint = Constraint( M.RampDownDayConstraint_rpsdtv, rule=RampDownDay_Constraint ) - M.RampUpSeasonConstraint_rpsstv = Set(dimen=6, initialize=RampUpSeasonConstraintIndices) + M.RampUpSeasonConstraint_rpsstv = Set( + dimen=6, initialize=ramping.RampUpSeasonConstraintIndices + ) M.RampUpSeasonConstraint = Constraint( M.RampUpSeasonConstraint_rpsstv, rule=RampUpSeason_Constraint ) - M.RampDownSeasonConstraint_rpsstv = Set(dimen=6, initialize=RampDownSeasonConstraintIndices) + M.RampDownSeasonConstraint_rpsstv = Set( + dimen=6, initialize=ramping.RampDownSeasonConstraintIndices + ) M.RampDownSeasonConstraint = Constraint( M.RampDownSeasonConstraint_rpsstv, rule=RampDownSeason_Constraint ) - M.ReserveMargin_rpsd = Set(dimen=4, initialize=ReserveMarginIndices) + M.ReserveMargin_rpsd = Set(dimen=4, initialize=reserves.ReserveMarginIndices) M.validate_ReserveMargin = BuildAction(rule=validate_ReserveMargin) M.ReserveMarginConstraint = Constraint(M.ReserveMargin_rpsd, rule=ReserveMargin_Constraint) @@ -1016,39 +978,41 @@ def __init__(M, *args, **kwargs): ['Starting LimitGrowth and Activity Constraints'], rule=progress_check ) - M.LimitGrowthCapacityConstraint_rpt = Set(dimen=4, initialize=LimitGrowthCapacityIndices) + M.LimitGrowthCapacityConstraint_rpt = Set( + dimen=4, initialize=limits.LimitGrowthCapacityIndices + ) M.LimitGrowthCapacityConstraint = Constraint( M.LimitGrowthCapacityConstraint_rpt, rule=LimitGrowthCapacityConstraint_rule ) M.LimitDegrowthCapacityConstraint_rpt = Set( - dimen=4, initialize=LimitDegrowthCapacityIndices + dimen=4, initialize=limits.LimitDegrowthCapacityIndices ) M.LimitDegrowthCapacityConstraint = Constraint( M.LimitDegrowthCapacityConstraint_rpt, rule=LimitDegrowthCapacityConstraint_rule ) M.LimitGrowthNewCapacityConstraint_rpt = Set( - dimen=4, initialize=LimitGrowthNewCapacityIndices + dimen=4, initialize=limits.LimitGrowthNewCapacityIndices ) M.LimitGrowthNewCapacityConstraint = Constraint( M.LimitGrowthNewCapacityConstraint_rpt, rule=LimitGrowthNewCapacityConstraint_rule ) M.LimitDegrowthNewCapacityConstraint_rpt = Set( - dimen=4, initialize=LimitDegrowthNewCapacityIndices + dimen=4, initialize=limits.LimitDegrowthNewCapacityIndices ) M.LimitDegrowthNewCapacityConstraint = Constraint( M.LimitDegrowthNewCapacityConstraint_rpt, rule=LimitDegrowthNewCapacityConstraint_rule ) M.LimitGrowthNewCapacityDeltaConstraint_rpt = Set( - dimen=4, initialize=LimitGrowthNewCapacityDeltaIndices + dimen=4, initialize=limits.LimitGrowthNewCapacityDeltaIndices ) M.LimitGrowthNewCapacityDeltaConstraint = Constraint( M.LimitGrowthNewCapacityDeltaConstraint_rpt, rule=LimitGrowthNewCapacityDeltaConstraint_rule, ) M.LimitDegrowthNewCapacityDeltaConstraint_rpt = Set( - dimen=4, initialize=LimitDegrowthNewCapacityDeltaIndices + dimen=4, initialize=limits.LimitDegrowthNewCapacityDeltaIndices ) M.LimitDegrowthNewCapacityDeltaConstraint = Constraint( M.LimitDegrowthNewCapacityDeltaConstraint_rpt, @@ -1122,21 +1086,21 @@ def __init__(M, *args, **kwargs): ## Tech input splits M.LimitTechInputSplitConstraint_rpsditv = Set( - dimen=8, initialize=LimitTechInputSplitConstraintIndices + dimen=8, initialize=limits.LimitTechInputSplitConstraintIndices ) M.LimitTechInputSplitConstraint = Constraint( M.LimitTechInputSplitConstraint_rpsditv, rule=LimitTechInputSplit_Constraint ) M.LimitTechInputSplitAnnualConstraint_rpitv = Set( - dimen=6, initialize=LimitTechInputSplitAnnualConstraintIndices + dimen=6, initialize=limits.LimitTechInputSplitAnnualConstraintIndices ) M.LimitTechInputSplitAnnualConstraint = Constraint( M.LimitTechInputSplitAnnualConstraint_rpitv, rule=LimitTechInputSplitAnnual_Constraint ) M.LimitTechInputSplitAverageConstraint_rpitv = Set( - dimen=6, initialize=LimitTechInputSplitAverageConstraintIndices + dimen=6, initialize=limits.LimitTechInputSplitAverageConstraintIndices ) M.LimitTechInputSplitAverageConstraint = Constraint( M.LimitTechInputSplitAverageConstraint_rpitv, rule=LimitTechInputSplitAverage_Constraint @@ -1144,21 +1108,21 @@ def __init__(M, *args, **kwargs): ## Tech output splits M.LimitTechOutputSplitConstraint_rpsdtvo = Set( - dimen=8, initialize=LimitTechOutputSplitConstraintIndices + dimen=8, initialize=limits.LimitTechOutputSplitConstraintIndices ) M.LimitTechOutputSplitConstraint = Constraint( M.LimitTechOutputSplitConstraint_rpsdtvo, rule=LimitTechOutputSplit_Constraint ) M.LimitTechOutputSplitAnnualConstraint_rptvo = Set( - dimen=6, initialize=LimitTechOutputSplitAnnualConstraintIndices + dimen=6, initialize=limits.LimitTechOutputSplitAnnualConstraintIndices ) M.LimitTechOutputSplitAnnualConstraint = Constraint( M.LimitTechOutputSplitAnnualConstraint_rptvo, rule=LimitTechOutputSplitAnnual_Constraint ) M.LimitTechOutputSplitAverageConstraint_rptvo = Set( - dimen=6, initialize=LimitTechOutputSplitAverageConstraintIndices + dimen=6, initialize=limits.LimitTechOutputSplitAverageConstraintIndices ) M.LimitTechOutputSplitAverageConstraint = Constraint( M.LimitTechOutputSplitAverageConstraint_rptvo, @@ -1170,7 +1134,7 @@ def __init__(M, *args, **kwargs): ) M.LinkedEmissionsTechConstraint_rpsdtve = Set( - dimen=7, initialize=LinkedTechConstraintIndices + dimen=7, initialize=emissions.LinkedTechConstraintIndices ) # the validation requires that the set above be built first: M.validate_LinkedTech_lifetimes = BuildCheck(rule=validate_linked_tech) From 927e047788ff041c92102aeff156e1aaf3742636 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 8 Oct 2025 17:30:55 -0400 Subject: [PATCH 220/587] distributing temoa_rules into components --- temoa/__init__.py | 2 - temoa/_internal/table_data_puller.py | 39 +- temoa/_internal/temoa_rules.py | 3912 ----------------- temoa/components/capacity.py | 298 ++ temoa/components/commodities.py | 464 ++ temoa/components/costs.py | 567 ++- temoa/components/emissions.py | 75 + temoa/components/geography.py | 22 + temoa/components/limits.py | 1093 +++++ temoa/components/operations.py | 71 + temoa/components/ramping.py | 298 ++ temoa/components/reserves.py | 271 ++ temoa/components/storage.py | 438 ++ temoa/components/technology.py | 27 + temoa/components/time.py | 18 + temoa/components/utils.py | 56 + temoa/core/model.py | 192 +- .../mga_sequencer.py | 4 +- .../single_vector_mga/sv_mga_sequencer.py | 2 +- 19 files changed, 3789 insertions(+), 4060 deletions(-) delete mode 100644 temoa/_internal/temoa_rules.py create mode 100644 temoa/components/utils.py diff --git a/temoa/__init__.py b/temoa/__init__.py index e6809f3e6..3ff349b73 100644 --- a/temoa/__init__.py +++ b/temoa/__init__.py @@ -25,8 +25,6 @@ poll_flow_results, ) from temoa._internal.table_writer import TableWriter -from temoa._internal.temoa_initialize import * -from temoa._internal.temoa_rules import * from temoa._internal.temoa_sequencer import TemoaSequencer from temoa.core.config import TemoaConfig from temoa.core.model import TemoaModel diff --git a/temoa/_internal/table_data_puller.py b/temoa/_internal/table_data_puller.py index e5ac38fed..defffd9f5 100644 --- a/temoa/_internal/table_data_puller.py +++ b/temoa/_internal/table_data_puller.py @@ -39,8 +39,9 @@ from pyomo.common.numeric_types import value from pyomo.core import Objective -from temoa._internal import temoa_rules from temoa._internal.exchange_tech_cost_ledger import CostType, ExchangeTechCostLedger +from temoa.components import costs +from temoa.components.utils import get_variable_efficiency from temoa.core.model import TemoaModel logger = logging.getLogger(__name__) @@ -154,7 +155,7 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl if abs(flow) < epsilon: continue res[fi][FlowType.IN] = flow - res[fi][FlowType.LOST] = (1 - temoa_rules.get_variable_efficiency(M, *key)) * flow + res[fi][FlowType.LOST] = (1 - get_variable_efficiency(M, *key)) * flow # regular flows for key in M.V_FlowOut.keys(): @@ -165,9 +166,9 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl res[fi][FlowType.OUT] = flow if fi.t not in M.tech_storage: # we can get the flow in by out/eff... - flow = value(M.V_FlowOut[fi]) / temoa_rules.get_variable_efficiency(M, *key) + flow = value(M.V_FlowOut[fi]) / get_variable_efficiency(M, *key) res[fi][FlowType.IN] = flow - res[fi][FlowType.LOST] = (1 - temoa_rules.get_variable_efficiency(M, *key)) * flow + res[fi][FlowType.LOST] = (1 - get_variable_efficiency(M, *key)) * flow # curtailment flows for key in M.V_Curtailment.keys(): @@ -394,7 +395,7 @@ def poll_cost_results( fixed_cost = value(M.CostFixed[r, p, t, v]) undiscounted_fixed_cost = cap * fixed_cost * value(M.PeriodLength[p]) - model_fixed_cost = temoa_rules.fixed_or_variable_cost( + model_fixed_cost = costs.fixed_or_variable_cost( cap, fixed_cost, value(M.PeriodLength[p]), GDR=GDR, P_0=p_0, p=p ) if '-' in r: @@ -440,7 +441,7 @@ def poll_cost_results( var_cost = value(M.CostVariable[r, p, t, v]) undiscounted_var_cost = activity * var_cost * value(M.PeriodLength[p]) - model_var_cost = temoa_rules.fixed_or_variable_cost( + model_var_cost = costs.fixed_or_variable_cost( activity, var_cost, value(M.PeriodLength[p]), GDR=GDR, P_0=p_0, p=p ) if '-' in r: @@ -486,8 +487,8 @@ def loan_costs( """ # dev note: this is a passthrough function. Sole intent is to use the EXACT formula the # model uses for these costs - loan_ar = temoa_rules.pv_to_annuity(rate=loan_rate, periods=loan_life) - model_ic = temoa_rules.loan_cost( + loan_ar = costs.pv_to_annuity(rate=loan_rate, periods=loan_life) + model_ic = costs.loan_cost( capacity, invest_cost, loan_annualize=loan_ar, @@ -500,7 +501,7 @@ def loan_costs( ) # Override the GDR to get the undiscounted value global_discount_rate = 0 - undiscounted_cost = temoa_rules.loan_cost( + undiscounted_cost = costs.loan_cost( capacity, invest_cost, loan_annualize=loan_ar, @@ -535,8 +536,8 @@ def loan_costs_survival_curve( """ # dev note: this is a passthrough function. Sole intent is to use the EXACT formula the # model uses for these costs - loan_ar = temoa_rules.pv_to_annuity(rate=loan_rate, periods=loan_life) - model_ic = temoa_rules.loan_cost_survival_curve( + loan_ar = costs.pv_to_annuity(rate=loan_rate, periods=loan_life) + model_ic = costs.loan_cost_survival_curve( M, r, t, @@ -551,7 +552,7 @@ def loan_costs_survival_curve( ) # Override the GDR to get the undiscounted value global_discount_rate = 0 - undiscounted_cost = temoa_rules.loan_cost_survival_curve( + undiscounted_cost = costs.loan_cost_survival_curve( M, r, t, @@ -633,7 +634,7 @@ def poll_emissions( undiscounted_emiss_cost = ( flows[ei] * M.CostEmission[ei.r, ei.p, ei.e] * M.PeriodLength[ei.p] ) - discounted_emiss_cost = temoa_rules.fixed_or_variable_cost( + discounted_emiss_cost = costs.fixed_or_variable_cost( cap_or_flow=flows[ei], cost_factor=M.CostEmission[ei.r, ei.p, ei.e], cost_years=M.PeriodLength[ei.p], @@ -673,7 +674,7 @@ def poll_emissions( * M.CostEmission[ei.r, ei.v, ei.e] * M.PeriodLength[ei.v] # treat as fixed cost distributed over construction period ) - discounted_emiss_cost = temoa_rules.fixed_or_variable_cost( + discounted_emiss_cost = costs.fixed_or_variable_cost( cap_or_flow=embodied_flows[ei], cost_factor=M.CostEmission[ei.r, ei.v, ei.e], cost_years=M.PeriodLength[ @@ -718,7 +719,7 @@ def poll_emissions( * M.CostEmission[ei.r, ei.p, ei.e] * M.PeriodLength[ei.p] # treat as fixed cost distributed over retirement period ) - discounted_emiss_cost = temoa_rules.fixed_or_variable_cost( + discounted_emiss_cost = costs.fixed_or_variable_cost( cap_or_flow=eol_flows[ei], cost_factor=M.CostEmission[ei.r, ei.p, ei.e], cost_years=M.PeriodLength[ @@ -732,11 +733,11 @@ def poll_emissions( d_costs[ei.r, ei.p, ei.t, ei.v] += discounted_emiss_cost # finally, now that all costs are added up for each rptv, put in cost dict - costs = defaultdict(dict) + costs_dict = defaultdict(dict) for rptv in ud_costs: - costs[rptv][CostType.EMISS] = ud_costs[rptv] + costs_dict[rptv][CostType.EMISS] = ud_costs[rptv] for rptv in d_costs: - costs[rptv][CostType.D_EMISS] = d_costs[rptv] + costs_dict[rptv][CostType.D_EMISS] = d_costs[rptv] # wow, that was like pulling teeth - return costs, flows + return costs_dict, flows diff --git a/temoa/_internal/temoa_rules.py b/temoa/_internal/temoa_rules.py deleted file mode 100644 index b57bd7b1b..000000000 --- a/temoa/_internal/temoa_rules.py +++ /dev/null @@ -1,3912 +0,0 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . -""" - -from logging import getLogger -from sys import stderr as SE -from typing import TYPE_CHECKING - -from pyomo.core import Expression, Var -from pyomo.environ import Constraint, value - -from temoa.components import ( - commodities, - geography, - technology, -) - -if TYPE_CHECKING: - from temoa.core.model import TemoaModel - -logger = getLogger(__name__) - - -# ============================================================================ -# Public API - Functions intended for external import -# ============================================================================ -__all__ = [ - # Core capacity constraints - 'AdjustedCapacity_Constraint', - 'Capacity_Constraint', - 'CapacityAnnual_Constraint', - 'CapacityAvailableByPeriodAndTech_Constraint', - # Activity and flow constraints - 'Demand_Constraint', - 'DemandActivity_Constraint', - 'CommodityBalance_Constraint', - 'AnnualCommodityBalance_Constraint', - # Retirement constraints - 'AnnualRetirement_Constraint', - # Storage constraints - 'StorageEnergy_Constraint', - 'StorageEnergyUpperBound_Constraint', - 'SeasonalStorageEnergy_Constraint', - 'SeasonalStorageEnergyUpperBound_Constraint', - 'StorageChargeRate_Constraint', - 'StorageDischargeRate_Constraint', - 'StorageThroughput_Constraint', - # Ramping constraints - 'BaseloadDiurnal_Constraint', - 'RampUpDay_Constraint', - 'RampDownDay_Constraint', - 'RampUpSeason_Constraint', - 'RampDownSeason_Constraint', - # Limit constraints (capacity, activity, emissions, etc.) - 'LimitActivity_Constraint', - 'LimitActivityShare_Constraint', - 'LimitAnnualCapacityFactor_Constraint', - 'LimitCapacity_Constraint', - 'LimitCapacityShare_Constraint', - 'LimitEmission_Constraint', - 'LimitNewCapacity_Constraint', - 'LimitNewCapacityShare_Constraint', - 'LimitResource_Constraint', - 'LimitSeasonalCapacityFactor_Constraint', - 'LimitStorageFraction_Constraint', - # Technology split constraints - 'LimitTechInputSplit_Constraint', - 'LimitTechInputSplitAnnual_Constraint', - 'LimitTechInputSplitAverage_Constraint', - 'LimitTechOutputSplit_Constraint', - 'LimitTechOutputSplitAnnual_Constraint', - 'LimitTechOutputSplitAverage_Constraint', - # Growth/degrowth constraints - 'LimitDegrowthCapacityConstraint_rule', - 'LimitDegrowthNewCapacityConstraint_rule', - 'LimitDegrowthNewCapacityDeltaConstraint_rule', - 'LimitGrowthCapacityConstraint_rule', - 'LimitGrowthNewCapacityConstraint_rule', - 'LimitGrowthNewCapacityDeltaConstraint_rule', - # Regional and special constraints - 'RegionalExchangeCapacity_Constraint', - 'RenewablePortfolioStandard_Constraint', - 'ReserveMargin_Constraint', - 'LinkedEmissionsTech_Constraint', - # Parameter calculation rules - 'ParamLoanAnnualize_rule', - 'ParamPeriodLength', - 'ParamProcessLifeFraction_rule', - 'SegFracPerSeason_rule', - # Objective function - 'TotalCost_rule', -] - - -# --------------------------------------------------------------- -# Define the derived variables used in the objective function -# and constraints below. -# --------------------------------------------------------------- - - -def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): - r""" - This constraint updates the capacity of a process by taking into account retirements - and end of life. For a given :code:`(r,p,t,v)` index, this constraint sets the capacity - equal to the amount installed in period :code:`v` and subtracts from it any and all retirements - that occurred prior to the period in question, :code:`p`, and end of life from the - survival curve if defined. It finally adjusts for the process life fraction, which - accounts for a possible mid-period end of life where, for example, EOL 3 years into a 5-year - period would be treated as :math:`\frac{3}{5}` capacity for all 5 years. - - .. figure:: images/adjusted_capacity_plf.* - :align: center - :width: 100% - :figclass: align-center - :figwidth: 50% - - For processes reaching end of life mid-period, the process life fraction adjustment is applied, - distributing the effective capacity over the whole period. - - For processes using survival curves, the yearly survival curve :math:`\text{LSC}_{r,p,t,v}` is - averaged over the period to get the effective remaining capacity for that period Because this - implicitly handles mid-period end of life, :math:`\text{PLF}_{r,p,t,v}` is used to account for both - phenomena. - - .. figure:: images/adjusted_capacity_sc.* - :align: center - :width: 100% - :figclass: align-center - :figwidth: 50% - - For processes with a defined survival curve, the surviving capacity is averaged over each - period to get the adjusted capacity. This implicitly handles mid-period end of life as a - survival curve will always be zero after the end of life of a process. - - .. math:: - :label: Adjusted Capacity - - \textbf{CAP}_{r,p,t,v} = - \begin{cases} - \text{PLF}_{r,p,t,v} \cdot - \left( - \text{ECAP}_{r,t,v} - \sum\limits_{v < p' <= p} - \frac{\textbf{RCAP}_{r,p',t,v}}{\text{LSC}_{r,p',t,v}} - \right) - & \text{if } \ v \in T^e \\ - \text{PLF}_{r,p,t,v} \cdot - \left( - \textbf{NCAP}_{r,t,v} - \sum\limits_{v < p' <= p} - \frac{\textbf{RCAP}_{r,p',t,v}}{\text{LSC}_{r,p',t,v}} - \right) - & \text{if } \ v \notin T^e - \end{cases} - - \\\text{where } - \text{PLF}_{r,p,t,v} = - \begin{cases} - \frac{1}{\text{LEN}_p} \cdot \left( - \sum\limits_{y = p}^{p+\text{LEN}_{p}-1}{\text{LSC}_{r,y,t,v}} - \right) - & \text{if } t \in T^{sc} \\ - \frac{1}{\text{LEN}_p} \cdot \left( v + \text{LTP}_{r,t,v} - p \right) - & \text{if } t \notin T^{sc} \\ - \end{cases} - - We divide :math:`\frac{\textbf{RCAP}_{r,p',t,v}}{\text{LSC}_{r,p',t,v}}` - because the average survival factor in :math:`\text{PLF}_{r,p,t,v}` is indexed to the vintage - period (the beginning of the survival curve). So, we adjust for the relative survival from - the time when that retirement occurred (treated here as at the beginning of each period). - """ - - if v in M.time_exist: - built_capacity = value(M.ExistingCapacity[r, t, v]) - else: - built_capacity = M.V_NewCapacity[r, t, v] - - early_retirements = 0 - if t in M.tech_retirement: - early_retirements = sum( - M.V_RetiredCapacity[r, S_p, t, v] / value(M.LifetimeSurvivalCurve[r, S_p, t, v]) - for S_p in M.time_optimize - if v < S_p <= p - and S_p < v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[S_p]) - ) - - remaining_capacity = (built_capacity - early_retirements) * value(M.ProcessLifeFrac[r, p, t, v]) - return M.V_Capacity[r, p, t, v] == remaining_capacity - - -def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): - r""" - Get the annualised retirement rate for a process in a given period. - Used to output retirement (including end of life, EOL) and to model end of - life flows and emissions. Assumes that retirement from the beginning of each period - is evenly distributed over that model period :math:`\frac{1}{\text{LEN}_p}` - for the accounting of retirement flows (in the same way we assume capacity is - deployed evenly over the model period for construction inputs and embodied emissions). - The factor :math:`\frac{\text{LSC}_{r,p,t,v}}{\text{PLF}_{r,p,t,v}}` - adjusts the average survival during a period to the survival at the beginning - of that period. - - .. math:: - :label: Annual Retirement - - \textbf{ART}_{r,p,t,v} = - \begin{cases} - \frac{1}{\text{LEN}_p} \cdot - \frac{\text{LSC}_{r,p,t,v}}{\text{PLF}_{r,p,t,v}} \cdot \textbf{CAP}_{r,p,t,v} - & \text{if EOL} \\ - \frac{1}{\text{LEN}_p} \cdot - \left( - \frac{\text{LSC}_{r,p,t,v}}{\text{PLF}_{r,p,t,v}} \cdot \textbf{CAP}_{r,p,t,v} - - \frac{\text{LSC}_{r,p_{next},t,v}}{\text{PLF}_{r,p_{next},t,v}} \cdot \textbf{CAP}_{r,p_{next},t,v} - \right) - & \text{otherwise} \\ - \end{cases} - - \\\text{where EOL when } p \leq v + LTP_{r,t,v} < p + LEN_p - """ - - ## Get the capacity at the start of this period - if p == v + value(M.LifetimeProcess[r, t, v]): - # Exact EOL. No V_Capacity or V_RetiredCapacity for this period. - if p == M.time_optimize.first(): - # Must be existing capacity. Apply survival curve to existing cap - cap_begin = M.ExistingCapacity[r, t, v] * M.LifetimeSurvivalCurve[r, p, t, v] - else: - # Get previous capacity and continue survival curve - p_prev = M.time_optimize.prev(p) - cap_begin = ( - M.V_Capacity[r, p_prev, t, v] - * value(M.LifetimeSurvivalCurve[r, p, t, v]) - / value(M.ProcessLifeFrac[r, p_prev, t, v]) - ) - else: - # The capacity at the beginning of the period - cap_begin = ( - M.V_Capacity[r, p, t, v] - * value(M.LifetimeSurvivalCurve[r, p, t, v]) - / value(M.ProcessLifeFrac[r, p, t, v]) - ) - - ## Get the capacity at the end of this period - if p <= v + value(M.LifetimeProcess[r, t, v]) < p + value(M.PeriodLength[p]): - # EOL so capacity ends on zero - cap_end = 0 - else: - # Mid-life period, ending capacity is beginning capacity of next period - p_next = M.time_future.next(p) - - if p == M.time_optimize.last() or p_next == v + value(M.LifetimeProcess[r, t, v]): - # No V_Capacity or V_RetiredCapacity for next period so just continue down the survival curve - cap_end = ( - cap_begin - * value(M.LifetimeSurvivalCurve[r, p_next, t, v]) - / value(M.LifetimeSurvivalCurve[r, p, t, v]) - ) - else: - # Get the next period's beginning capacity - cap_end = ( - M.V_Capacity[r, p_next, t, v] - * value(M.LifetimeSurvivalCurve[r, p_next, t, v]) - / value(M.ProcessLifeFrac[r, p_next, t, v]) - ) - - annualised_retirement = (cap_begin - cap_end) / M.PeriodLength[p] - return M.V_AnnualRetirement[r, p, t, v] == annualised_retirement - - -def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): - r""" - This constraint ensures that the capacity of a given process is sufficient - to support its activity across all time periods and time slices. The calculation - on the left hand side of the equality is the maximum amount of energy a process - can produce in the timeslice :code:`(s,d)`. Note that the curtailment variable - shown below only applies to technologies that are members of the curtailment set. - Curtailment is necessary to track explicitly in scenarios that include a high - renewable target. Without it, the model can generate more activity than is used - to meet demand, and have all activity (including the portion curtailed) count - towards the target. Tracking activity and curtailment separately prevents this - possibility. - - .. math:: - :label: Capacity - - \left ( - \text{CFP}_{r, p, s, d, t, v} - \cdot \text{C2A}_{r, t} - \cdot \text{SEG}_{s, d} - \right ) - \cdot \textbf{CAP}_{r, t, v} - = - \sum_{I, O} \textbf{FO}_{r, p, s, d, i, t, v, o} - + - \sum_{I, O} \textbf{CUR}_{r, p, s, d, i, t, v, o} - - \\ - \forall \{r, p, s, d, t, v\} \in \Theta_{\text{FO}} - """ - # The expressions below are defined in-line to minimize the amount of - # expression cloning taking place with Pyomo. - - if t in M.tech_annual: - # Annual demand technology - useful_activity = sum( - ( - value(M.DemandSpecificDistribution[r, p, s, d, S_o]) - if S_o in M.commodity_demand - else value(M.SegFrac[p, s, d]) - ) - * M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - else: - useful_activity = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - - if t in M.tech_curtailment: - # If technologies are present in the curtailment set, then enough - # capacity must be available to cover both activity and curtailment. - return get_capacity_factor(M, r, p, s, d, t, v) * value(M.CapacityToActivity[r, t]) * value( - M.SegFrac[p, s, d] - ) * M.V_Capacity[r, p, t, v] == useful_activity + sum( - M.V_Curtailment[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - else: - return ( - get_capacity_factor(M, r, p, s, d, t, v) - * value(M.CapacityToActivity[r, t]) - * value(M.SegFrac[p, s, d]) - * M.V_Capacity[r, p, t, v] - >= useful_activity - ) - - -def CapacityAnnual_Constraint(M: 'TemoaModel', r, p, t, v): - r""" - Similar to Capacity_Constraint, but for technologies belonging to the - :code:`tech_annual` set. Technologies in the tech_annual set have constant output - across different timeslices within a year, so we do not need to ensure - that installed capacity is sufficient across all timeslices, thus saving - some computational effort. Instead, annual output is sufficient to calculate - capacity. Hourly capacity factors cannot be defined to annual technologies - but annual capacity factors can be set using LimitAnnualCapacityFactor, - which will be implicitly accounted for here. - - .. math:: - :label: CapacityAnnual - - \text{C2A}_{r, t} - \cdot \textbf{CAP}_{r, t, v} - = - \sum_{I, O} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} - - \\ - \forall \{r, p, t \in T^{a}, v\} \in \Theta_{\text{Activity}} - """ - activity_rptv = sum( - M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - - return value(M.CapacityToActivity[r, t]) * M.V_Capacity[r, p, t, v] >= activity_rptv - - -# devnote: long dead -# def ActivityByTech_Constraint(M: 'TemoaModel', t): -# r""" -# This constraint is utilized by the MGA objective function and defines -# the total activity of a technology over the planning horizon. The first version -# below applies to technologies with variable output at the timeslice level, -# and the second version applies to technologies with constant annual output -# in the :code:`tech_annual` set. - -# .. math:: -# :label: ActivityByTech - -# \textbf{ACT}_{t} = \sum_{R, P, S, D, I, V, O} \textbf{FO}_{r, p, s, d,i, t, v, o} -# \; -# \forall t \not\in T^{a} - -# \textbf{ACT}_{t} = \sum_{R, P, I, V, O} \textbf{FOA}_{r, p, i, t, v, o} -# \; -# \forall t \in T^{a} -# """ -# if t not in M.tech_annual: -# indices = [] -# for s_index in M.FlowVar_rpsditvo: -# if t in s_index: -# indices.append(s_index) -# activity = sum(M.V_FlowOut[s_index] for s_index in indices) -# else: -# indices = [] -# for s_index in M.FlowVarAnnual_rpitvo: -# if t in s_index: -# indices.append(s_index) -# activity = sum(M.V_FlowOutAnnual[s_index] for s_index in indices) - -# if int is type(activity): -# return Constraint.Skip - -# expr = M.V_ActivityByTech[t] == activity -# return expr - - -def CapacityAvailableByPeriodAndTech_Constraint(M: 'TemoaModel', r, p, t): - r""" - - The :math:`\textbf{CAPAVL}` variable is nominally for reporting solution values, - but is also used in the Limit constraint calculations. - - .. math:: - :label: CapacityAvailable - - \textbf{CAPAVL}_{r, p, t} = \sum_{v, p_i \leq p} \textbf{CAP}_{r, p, t, v} - - \\ - \forall p \in \text{P}^o, r \in R, t \in T - """ - cap_avail = sum(M.V_Capacity[r, p, t, S_v] for S_v in M.processVintages[r, p, t]) - - expr = M.V_CapacityAvailableByPeriodAndTech[r, p, t] == cap_avail - return expr - - -# devnote: I don't think this constraint is necessary as if this were violated -# then V_Capacity would be negative, which isn't allowed anyway -# def RetiredCapacity_Constraint(M: 'TemoaModel', r, p, t, v): -# r""" - -# Temoa allows for the economic retirement of technologies presented in the -# :code:`tech_retirement` set. This constraint sets the upper limit of retired -# capacity to the total installed capacity. -# In the equation below, we set the upper bound of the retired capacity to the -# previous period's total installed capacity (CAPAVL) - -# .. math:: -# :label: RetiredCapacity - -# \textbf{CAPRET}_{r, p, t, v} \leq \sum_{V} {PLF}_{r, p, t, v} \cdot \textbf{CAP}_{r, t, v} -# \\ -# \forall \{r, p, t, v\} \in \Theta_{\text{RetiredCapacity}} -# """ -# if p == M.time_optimize.first(): -# cap_avail = value(M.ExistingCapacity[r, t, v]) -# else: -# cap_avail = M.V_Capacity[r, M.time_optimize.prev(p), t, v] -# expr = M.V_RetiredCapacity[r, p, t, v] <= cap_avail -# return expr - - -# --------------------------------------------------------------- -# Define the Objective Function -# --------------------------------------------------------------- -def TotalCost_rule(M): - r""" - - Using the :code:`FlowOut` and :code:`Capacity` variables, the Temoa objective - function calculates the cost of energy supply, under the assumption that capital - costs are paid through loans. This implementation sums up all the costs incurred, - and is defined as :math:`C_{tot} = C_{loans} + C_{fixed} + C_{variable} + C_{emissions}`. - Each term on the right-hand side represents the cost incurred over the model - time horizon and discounted to the initial year in the horizon (:math:`{P}_0`). - The calculation of each term is given below. - - .. math:: - :label: obj_invest - - \begin{aligned} - C_{loans} =& \sum_{r, t, v \in \Theta_{CI}} CI_{r, t, v} \cdot \textbf{NCAP}_{r, t, v} - && \text{(overnight capital cost)} \\ - &\cdot \frac{A}{P}(i=\text{LR}_{r,t,v}, N=\text{LLP}_{r,t,v}) - && \text{(overnight cost amortised into annual loan payments)} \\ - &\cdot \frac{P}{A}(i=GDR, N=\text{LLP}_{r,t,v}) - && \text{(annual loan payments discounted to NPV in vintage year)} \\ - &\cdot \frac{A}{P}(i=GDR, N=\text{LTP}_{r,t,v}) - && \text{(NPV reamortised over lifetime of process using GDR)} \\ - &\cdot \frac{P}{A}(i=GDR, N=\min(\text{LTP}_{r,t,v}, P_e - v)) - && \text{(costs within planning horizon discounted to NPV in vintage year)} \\ - &\cdot \frac{P}{F}(i=GDR, N=v - P_0) - && \text{(NPV in vintage year discounted to base year } P_0\text{)} \\ - \end{aligned} - - Note that capital costs (:math:`{CI}_{r,t,v}`) are handled in several steps. - - 1. Each capital cost is amortized using the loan rate (i.e., technology-specific discount rate) and loan period. - - 2. The annual stream of payments is converted into a lump sum using the global discount rate and loan period. - - 3. The new lump sum is amortized at the global discount rate over the process lifetime. - - 4. Loan payments beyond the model time horizon are removed and the lump sum recalculated. - - 5. Finally, the lump sum is discounted back to the beginning of the horizon (:math:`P_0`) using the global discount rate. - - Steps 3 and 4 serve to correctly balance the cost-benefit of technologies whose useful lives - would extend beyond the planning horizon. While an explicit salvage term is not included, this approach properly - captures the capital costs incurred within the model time horizon, accounting for process-specific loan rates - and periods. - - In the case of processes using survival curves, steps 3 and 4 do not reamortise costs uniformly over the process lifetime. - Instead, costs are amortised over the life of the process in proportion to the survival fraction in each year. - Note that, for this calculation, a survival curve :math:`{LSC}_{r,y,t,v}` must be defined out to the year in which the - surviving fraction is zero, even if that extends beyond the planning horizon. It must also be defined for each integer - year between model periods and, if not, these gaps will be filled by linear interpolation ahead of this calculation. - - .. math:: - :label: obj_invest_survival_curve - - \begin{aligned} - C_{loans,LSC} =& \sum_{r, t, v \in \Theta_{CI}} CI_{r, t, v} \cdot \textbf{NCAP}_{r, t, v} - && \text{(overnight capital cost)} \\ - &\cdot \frac{A}{P}(i=\text{LR}_{r,t,v}, N=\text{LLP}_{r,t,v}) - && \text{(overnight cost amortised into annual loan payments)} \\ - &\cdot \frac{P}{A}(i=GDR, N=\text{LLP}_{r,t,v}) - && \text{(annual loan payments discounted to NPV in vintage year)} \\ - &\cdot \left( - \sum_{v < Y} LSC_{r,y,t,v} \cdot \frac{P}{F}(i=GDR, N=P - v + 1) - \right)^{-1} - && \text{(reamortised over survival curve (normalized)} \\ - &\cdot \sum_{v < Y < P_e} LSC_{r,y,t,v} \cdot \frac{P}{F}(i=GDR, N=P - v + 1) - && \text{(costs within planning horizon discounted to NPV in vintage year)} \\ - &\cdot \frac{P}{F}(i=GDR, N=v - P_0) - && \text{(NPV in vintage year discounted to base year } P_0 \text{)} - \end{aligned} - - Where :math:`Y` is the set of each integer year :math:`y` within the planning horizon. - - .. figure:: images/survival_curve_discounting.* - :align: center - :width: 100% - :figclass: align-center - :figwidth: 60% - - Steps 3 and 4 for processes with survival curves. - - Fixed, variable, and emissions annual cost factors are determined by: - - .. math:: - :label: annual_fixed_variable_emission - - \begin{aligned} - C_{fixed} =& \sum_{r, p, t, v \in \Theta_{CF}} CF_{r, p, t, v} \cdot \textbf{CAP}_{r, p, t, v} - && \text{(annual fixed cost)} \\ - \\ - C_{variable} =& \sum_{r, p, t \notin T^a, v \in \Theta_{CV}} - CV_{r, p, t, v} \cdot \sum_{S, D, I, O} \mathbf{FO}_{r, p, s, d, i, t, v, o} - && \text{(annual variable cost on flow)} \\ - & \text{where } t \notin T^a \\ - &+\\ - & \sum_{r, p, t \in T^a,\ v \in \Theta_{VC}} CV_{r, p, t, v} - \cdot \sum_{I, O} \mathbf{FOA}_{r, p, i, t, v, o} - && \text{(annual variable cost on annual flows)} \\ - & \text{where } t \in T^a \\ - &+\\ - C_{emissions} =& \sum_{r, p, e \in \Theta_{CE}} CE_{r, p, e} - \cdot EAC_{r, i, t, v, o, e} \cdot \sum_{S, D, I, O} \mathbf{FO}_{r, p, s, d, i, t, v, o} - && \text{(annual emission cost on flow)} \\ - & \text{where } t \notin T^a \\ - &+\\ - & \sum_{r, p, e \in \Theta_{CE}} CE_{r, p, e} - \cdot EAC_{r, i, t, v, o, e} \cdot \sum_{I, O} \mathbf{FOA}_{r, p, i, t, v, o} - && \text{(annual emission cost on annual flows)} \\ - & \text{where } t \in T^a \\ - &+\\ - & \sum_{r, p, e \in \Theta_{CE}} \frac{CE_{r, p, e} - \cdot EE_{r, e, t, v} \cdot \mathbf{NCAP}_{r, t, v=p}}{{LEN}_p} - && \text{(annual embodied emission cost)} \\ - &+\\ - & \sum_{r, p, e \in \Theta_{CE}, v} CE_{r, p, e} - \cdot EEOL_{r, e, t, v} \cdot \mathbf{ART}_{r, p, t, v} - && \text{(annual retirement/end of life emission cost)} \\ - \end{aligned} - - Each of these costs are then discounted within each period and then to the base year: - - .. math:: - :label: obj_fixed_variable_emission - - \begin{aligned} - C_{fix,var,emiss} =& C_{fixed} + C_{variable} + C_{emissions} \\ - &\cdot \frac{P}{A}(i=GDR,\ N=LEN_p) - && \text{(for each year in period } p \text{ discounted to NPV in } p \text{)}\\ - &\cdot \frac{P}{F}(i=GDR,\ N=p - P_0) - && \text{(discounted from period } p \text{ to NPV in base year } P_0 \text{)} - \end{aligned} - """ - - return sum(PeriodCost_rule(M, p) for p in M.time_optimize) - - -def annuity_to_pv(rate: float, periods: int) -> float | Expression: - r""" - Multiplication factor to convert an annuity to net present value - - .. math:: - :label: annuity_to_pv - - \frac{P}{A}(i, N) = \frac{(1 + i)^N - 1}{i (1 + i)^N} - - where: - - - :math:`i` is the interest/discount rate - - :math:`N` is the number of periods - """ - if rate == 0: - return periods - return ((1 + rate) ** periods - 1) / (rate * (1 + rate) ** periods) - - -def pv_to_annuity(rate: float, periods: int) -> float | Expression: - r""" - Multiplication factor to convert net present value to an annuity - - .. math:: - :label: pv_to_annuity - - \frac{A}{P}(i, N) = \frac{i + (1 + i)^N}{(1 + i)^N - 1} - """ - if rate == 0: - return 1 / periods - return (rate * (1 + rate) ** periods) / ((1 + rate) ** periods - 1) - - -def fv_to_pv(rate: float, periods: int) -> float | Expression: - r""" - Multiplication factor to convert a future value to net present value - - .. math:: - :label: fv_to_pv - - \frac{P}{F}(i, N) = \frac{1}{(1 + i)^N} - """ - if rate == 0: - return 1 - return 1 / (1 + rate) ** periods - - -def loan_cost( - capacity: float | Var, - invest_cost: float, - loan_annualize: float, - lifetime_loan_process: float | int, - lifetime_process: int, - P_0: int, - P_e: int, - GDR: float, - vintage: int, -) -> float | Expression: - """ - function to calculate the loan cost. It can be used with fixed values to produce a hard number or - pyomo variables/params to make a pyomo Expression - :param capacity: The capacity to use to calculate cost - :param invest_cost: the cost/capacity - :param loan_annualize: parameter - :param lifetime_loan_process: lifetime of the loan - :param P_0: the year to discount the costs back to - :param P_e: the 'end year' or cutoff year for loan payments - :param GDR: Global Discount Rate - :param vintage: the base year of the loan - :return: fixed number or pyomo expression based on input types - """ - - # calculate the amortised loan repayment (annuity) - annuity = ( - capacity - * invest_cost # lump investment cost is capacity times CostInvest - * loan_annualize # calculate loan annuities for investment cost, if used - ) - - if not GDR: - # Undiscounted result - res = ( - annuity - * lifetime_loan_process # sum of loan payments over loan period - / lifetime_process # redistributed over lifetime of process - * min( - lifetime_process, P_e - vintage - ) # sum of redistributed costs for life of process (within planning horizon) - ) - else: - # Discounted result - res = ( - annuity - * annuity_to_pv( - GDR, lifetime_loan_process - ) # PV of all loan payments, discounted to vintage year using GDR - * pv_to_annuity(GDR, lifetime_process) # reamortised over lifetime of process using GDR - * annuity_to_pv( - GDR, min(lifetime_process, P_e - vintage) - ) # PV of all reamortised costs (within planning horizon) - * fv_to_pv(GDR, vintage - P_0) # finally, discounted from vintage year to P_0 - ) - return res - - -def loan_cost_survival_curve( - M: 'TemoaModel', - r: str, - t: str, - v: str, - capacity: float | Var, - invest_cost: float, - loan_annualize: float, - lifetime_loan_process: float | int, - P_0: int, - P_e: int, - GDR: float, -) -> float | Expression: - """ - function to calculate the loan cost only in the case of processes :math:`(r, t, v)` using - survival curves. It can be used with fixed values to produce a hard number or pyomo - variables/params to make a pyomo Expression - :param capacity: The capacity to use to calculate cost - :param invest_cost: the cost/capacity - :param loan_annualize: parameter - :param lifetime_loan_process: lifetime of the loan - :param P_0: the year to discount the costs back to - :param P_e: the 'end year' or cutoff year for loan payments - :param GDR: Global Discount Rate - :return: fixed number or pyomo expression based on input types - """ - - # calculate the amortised loan repayment (annuity) - annuity = ( - capacity - * invest_cost # lump investment cost is capacity times CostInvest - * loan_annualize # calculate loan annuities for investment cost, if used - ) - - if not GDR: - # Undiscounted result - res = ( - annuity - * lifetime_loan_process # sum of loan payments over loan period - / sum( # redistributed over survival curve within horizon - value(M.LifetimeSurvivalCurve[r, p, t, v]) - for p in M.survivalCurvePeriods[r, t, v] - if v <= p - ) - * sum( # summed over survival curve within horizon - value(M.LifetimeSurvivalCurve[r, p, t, v]) - for p in M.survivalCurvePeriods[r, t, v] - if v <= p < P_e - ) - ) - else: - # Discounted result - res = ( - annuity - * annuity_to_pv( - GDR, lifetime_loan_process - ) # PV of all loan payments, discounted to vintage year using GDR - / sum( # redistributed over survival curve within horizon - value( - M.LifetimeSurvivalCurve[r, p, t, v] - ) # reamortised over survival curve of process using GDR - * fv_to_pv(GDR, p - v + 1) # +1 because LSC is indexed to start of p not end of p - for p in M.survivalCurvePeriods[r, t, v] - if v <= p # this shouldnt be possible but play it safe - ) - * sum( # PV of all reamortised costs (within planning horizon) - value(M.LifetimeSurvivalCurve[r, p, t, v]) * fv_to_pv(GDR, p - v + 1) - for p in M.survivalCurvePeriods[r, t, v] - if v <= p < P_e - ) - * fv_to_pv(GDR, v - P_0) # finally, discounted from vintage year to P_0 - ) - return res - - -def fixed_or_variable_cost( - cap_or_flow: float | Var, - cost_factor: float, - cost_years: float, - GDR: float | None, - P_0: float, - p: int, -) -> float | Expression: - """ - Extraction of the fixed and var cost formulation. (It is same for both with either capacity or - flow as the driving variable.) - :param cap_or_flow: Capacity if fixed cost / flow out if variable - :param cost_factor: the cost (either fixed or variable) of the cap/flow variable - :param cost_years: for how many years is this cost incurred - :param GDR: discount rate or None - :param P_0: the period to discount this back to - :param p: the period under evaluation - :return: - """ - - annual_cost = cap_or_flow * cost_factor # annual fixed, variable, or emission cost - - if not GDR: - # Undiscounted result - return annual_cost * cost_years # annual cost times years paying that cost - else: - # Discounted result - return ( - annual_cost - * annuity_to_pv( - GDR, cost_years - ) # PV of annual costs over this period, discounted to period p - * fv_to_pv(GDR, p - P_0) # discounted from p to p_0 - ) - - -def PeriodCost_rule(M: 'TemoaModel', p): - P_0 = min(M.time_optimize) - P_e = M.time_future.last() # End point of modeled horizon - GDR = value(M.GlobalDiscountRate) - # MPL = M.ModelProcessLife - - if value(M.MyopicDiscountingYear) != 0: - P_0 = value(M.MyopicDiscountingYear) - - loan_costs = sum( - loan_cost( - M.V_NewCapacity[r, S_t, S_v], - value(M.CostInvest[r, S_t, S_v]), - value(M.LoanAnnualize[r, S_t, S_v]), - value(M.LoanLifetimeProcess[r, S_t, S_v]), - value(M.LifetimeProcess[r, S_t, S_v]), - P_0, - P_e, - GDR, - vintage=S_v, - ) - for r, S_t, S_v in M.CostInvest.sparse_iterkeys() - if S_v == p and not M.isSurvivalCurveProcess[r, S_t, S_v] - ) - loan_costs += sum( - loan_cost_survival_curve( - M, - r, - S_t, - S_v, - M.V_NewCapacity[r, S_t, S_v], - value(M.CostInvest[r, S_t, S_v]), - value(M.LoanAnnualize[r, S_t, S_v]), - value(M.LoanLifetimeProcess[r, S_t, S_v]), - P_0, - P_e, - GDR, - ) - for r, S_t, S_v in M.CostInvest.sparse_iterkeys() - if S_v == p and M.isSurvivalCurveProcess[r, S_t, S_v] - ) - - fixed_costs = sum( - fixed_or_variable_cost( - M.V_Capacity[r, p, S_t, S_v], - value(M.CostFixed[r, p, S_t, S_v]), - value(M.PeriodLength[p]), - GDR, - P_0, - p=p, - ) - for r, S_p, S_t, S_v in M.CostFixed.sparse_iterkeys() - if S_p == p - ) - - variable_costs = sum( - fixed_or_variable_cost( - M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, S_o], - value(M.CostVariable[r, p, S_t, S_v]), - value(M.PeriodLength[p]), - GDR, - P_0, - p, - ) - for r, S_p, S_t, S_v in M.CostVariable.sparse_iterkeys() - if S_p == p and S_t not in M.tech_annual - for S_i in M.processInputs[r, S_p, S_t, S_v] - for S_o in M.processOutputsByInput[r, S_p, S_t, S_v, S_i] - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - - variable_costs_annual = sum( - fixed_or_variable_cost( - M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, S_o], - value(M.CostVariable[r, p, S_t, S_v]), - value(M.PeriodLength[p]), - GDR, - P_0, - p, - ) - for r, S_p, S_t, S_v in M.CostVariable.sparse_iterkeys() - if S_p == p and S_t in M.tech_annual - for S_i in M.processInputs[r, S_p, S_t, S_v] - for S_o in M.processOutputsByInput[r, S_p, S_t, S_v, S_i] - ) - - # The emissions costs occur over the five possible emission sources. - # to do any/all of them we need 2 baseline sets: The regular and annual sets - # of indices that are valid which is basically the filter of: - # EmissionActivty by CostEmission - # and to ensure that the techology is active we need to filter that - # result with processInput - - # ================= Emissions and Flex and Curtailment ================= - # Flex flows are deducted from V_FlowOut, so it is NOT NEEDED to tax them again. (See commodity balance constr) - # Curtailment does not draw any inputs, so it seems logical that curtailed flows not be taxed either - # Earlier versions of this code had accounting for flex & curtailment that have been removed. - - base = [ - (r, p, e, i, t, v, o) - for (r, e, i, t, v, o) in M.EmissionActivity.sparse_iterkeys() - if (r, p, e) in M.CostEmission # tightest filter first - and (r, p, t, v) in M.processInputs - ] - - # then expand the base for the normal (season/tod) set and annual separately: - normal = [ - (r, p, e, s, d, i, t, v, o) - for (r, p, e, i, t, v, o) in base - for s in M.TimeSeason[p] - for d in M.time_of_day - if t not in M.tech_annual - ] - - annual = [(r, p, e, i, t, v, o) for (r, p, e, i, t, v, o) in base if t in M.tech_annual] - - # 1. variable emissions - var_emissions = sum( - fixed_or_variable_cost( - cap_or_flow=M.V_FlowOut[r, p, s, d, i, t, v, o] - * value(M.EmissionActivity[r, e, i, t, v, o]), - cost_factor=value(M.CostEmission[r, p, e]), - cost_years=value(M.PeriodLength[p]), - GDR=GDR, - P_0=P_0, - p=p, - ) - for (r, p, e, s, d, i, t, v, o) in normal - ) - - # 2. flex emissions -- removed (double counting, flex wastes are SUBTRACTIVE from flowout) - - # 3. curtailment emissions -- removed (curtailment is no-flow, for accounting only, so no emissions) - - # 4. annual emissions - var_annual_emissions = sum( - fixed_or_variable_cost( - cap_or_flow=M.V_FlowOutAnnual[r, p, i, t, v, o] - * value(M.EmissionActivity[r, e, i, t, v, o]), - cost_factor=value(M.CostEmission[r, p, e]), - cost_years=value(M.PeriodLength[p]), - GDR=GDR, - P_0=P_0, - p=p, - ) - for (r, p, e, i, t, v, o) in annual - if t not in M.tech_flex - ) - - # 5. flex annual emissions -- removed (double counting, flex wastes are SUBTRACTIVE from flowout) - - # 6. embodied - treated as a fixed cost distributed over the deployment period (vintage) - embodied_emissions = sum( - fixed_or_variable_cost( - cap_or_flow=M.V_NewCapacity[r, t, v] - * value(M.EmissionEmbodied[r, e, t, v]) - / value(M.PeriodLength[p]), - cost_factor=value(M.CostEmission[r, p, e]), - cost_years=M.PeriodLength[ - v - ], # We assume the embodied emissions are emitted in the same year as the capacity is installed. - GDR=GDR, - P_0=P_0, - p=p, - ) - for (r, e, t, v) in M.EmissionEmbodied.sparse_iterkeys() - if (r, p, e) in M.CostEmission - if v == p - ) - - # 6. endoflife - treated as a fixed cost distributed over the retirement period - endoflife_emissions = sum( - fixed_or_variable_cost( - cap_or_flow=M.V_AnnualRetirement[r, p, t, v] * value(M.EmissionEndOfLife[r, e, t, v]), - cost_factor=value(M.CostEmission[r, p, e]), - cost_years=M.PeriodLength[ - p - ], # We assume the embodied emissions are emitted in the same year as the capacity is installed. - GDR=GDR, - P_0=P_0, - p=p, - ) - for (r, e, t, v) in M.EmissionEndOfLife.sparse_iterkeys() - if (r, p, e) in M.CostEmission - if (r, t, v) in M.retirementPeriods and p in M.retirementPeriods[r, t, v] - ) - - period_emission_cost = ( - var_emissions + var_annual_emissions + embodied_emissions + endoflife_emissions - ) - - period_costs = ( - loan_costs + fixed_costs + variable_costs + variable_costs_annual + period_emission_cost - ) - return period_costs - - -# --------------------------------------------------------------- -# Define the Model Constraints. -# The order of constraint definitions follows the same order as the -# declarations in temoa_model.py. -# --------------------------------------------------------------- - - -def Demand_Constraint(M: 'TemoaModel', r, p, dem): - r""" - - The Demand constraint drives the model. This constraint ensures that supply at - least meets the demand specified by the Demand parameter in all periods and - slices, by ensuring that the sum of all the demand output commodity (:math:`c`) - generated by both commodity flow at the time slice level (:math:`\textbf{FO}`) and - the annual level (:math:`\textbf{FOA}`) must meet the modeler-specified demand - in each time slice. - - .. math:: - :label: Demand - - \sum_{I, T-T^{a}, V} \textbf{FO}_{r, p, s, d, i, t \not \in T^{a}, v, dem} + - SEG_{s,d} \cdot \sum_{I, T^{a}, V} \textbf{FOA}_{r, p, i, t \in T^{a}, v, dem} - = - {DEM}_{r, p, dem} \cdot {DSD}_{r, s, d, dem} - - Note that the validity of this constraint relies on the fact that the - :math:`C^d` set is distinct from both :math:`C^e` and :math:`C^p`. In other - words, an end-use demand must only be an end-use demand. Note that if an output - could satisfy both an end-use and internal system demand, then the output from - :math:`\textbf{FO}` and :math:`\textbf{FOA}` would be double counted.""" - - # All demand techs are annual now - # supply = sum( - # M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, dem] - # for S_t, S_v in M.commodityUStreamProcess[r, p, dem] - # if S_t not in M.tech_annual - # for S_i in M.processInputsByOutput[r, p, S_t, S_v, dem] - # ) - - supply_annual = sum( - M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, dem] - for S_t, S_v in M.commodityUStreamProcess[r, p, dem] - for S_i in M.processInputsByOutput[r, p, S_t, S_v, dem] - ) - - commodities.DemandConstraintErrorCheck(supply_annual, r, p, dem) - - expr = supply_annual == value(M.Demand[r, p, dem]) - - return expr - - -# devnote: no longer needed -def DemandActivity_Constraint(M: 'TemoaModel', r, p, s, d, t, v, dem): - r""" - - For end-use demands, it is unreasonable to let the model arbitrarily shift the - use of demand technologies across time slices. For instance, if household A buys - a natural gas furnace while household B buys an electric furnace, then both units - should be used throughout the year. Without this constraint, the model might choose - to only use the electric furnace during the day, and the natural gas furnace during the - night. - - This constraint ensures that the ratio of a process activity to demand is - constant for all time slices. Note that if a demand is not specified in a given - time slice, or is zero, then this constraint will not be considered for that - slice and demand. This is transparently handled by the :math:`\Theta` superset. - - .. math:: - :label: DemandActivity - - DEM_{r, p, s, d, dem} \cdot \sum_{I} \textbf{FO}_{r, p, s_0, d_0, i, t \not \in T^{a}, v, dem} - = - DEM_{r, p, s_0, d_0, dem} \cdot \sum_{I} \textbf{FO}_{r, p, s, d, i, t \not \in T^{a}, v, dem} - - \\ - \forall \{r, p, s, d, t, v, dem, s_0, d_0\} \in \Theta_{\text{DemandActivity}} - - Note that this constraint is only applied to the demand commodities with diurnal - variations, and therefore the equation above only includes :math:`\textbf{FO}` - and not :math:`\textbf{FOA}` - """ - - activity = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, dem] for S_i in M.processInputsByOutput[r, p, t, v, dem] - ) - - annual_activity = sum( - M.V_FlowOutAnnual[r, p, S_i, t, v, dem] for S_i in M.processInputsByOutput[r, p, t, v, dem] - ) - - expr = annual_activity * value(M.DemandSpecificDistribution[r, p, s, d, dem]) == activity - return expr - - -def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): - r""" - Where the Demand constraint :eq:`Demand` ensures that end-use demands are met, - the CommodityBalance constraint ensures that the endogenous system demands are - met. This constraint requires the total production of a given commodity - to equal the amount consumed, thus ensuring an energy balance at the system - level. In this most general form of the constraint, the energy commodity being - balanced has variable production at the time slice level. The energy commodity - can then be consumed by three types of processes: storage technologies, non-storage - technologies with output that varies at the time slice level, and non-storage - technologies with constant annual output. - - Separate expressions are required in order to account for the consumption of - commodity :math:`c` by downstream processes. For the commodity flow into storage - technologies, we use :math:`\textbf{FI}_{r, p, s, d, i, t, v, c}`. Note that the FlowIn - variable is defined only for storage technologies, and is required because storage - technologies balance production and consumption across time slices rather than - within a single time slice. For commodity flows into non-storage processes with time - varying output, we use :math:`\textbf{FO}_{r, p, s, d, i, t, v, c}/EFF_{r, i,t,v,o}`. - The division by :math:`EFF_{r, c,t,v,o}` is applied to the output flows that consume - commodity :math:`c` to determine input flows. Finally, we need to account - for the consumption of commodity :math:`c` by the processes in - :code:`tech_annual`. Since the commodity flow of these processes is on an - annual basis, we use :math:`SEG_{s,d}` to calculate the consumption of - commodity :math:`c` in time-slice :math:`(s,d)` from the annual flows. - Formulating an expression for the production of commodity :math:`c` is - more straightforward, and is simply calculated by - :math:`\textbf{FO}_{r, p, s, d, i, t, v, c}`. - - In some cases, the overproduction of a commodity may be required, such - that the supply exceeds the endogenous demand. Refineries represent a - common example, where the share of different refined products are governed - by TechOutputSplit, but total production is driven by a particular commodity - like gasoline. Such a situation can result in the overproduction of other - refined products, such as diesel or kerosene. In such cases, we need to - track the excess production of these commodities. To do so, the technology - producing the excess commodity should be added to the :code:`tech_flex` set. - This flexible technology designation will activate a slack variable - (:math:`\textbf{FLX}_{r, p, s, d, i, t, v, c}`) representing - the excess production in the :code:`CommodityBalanceAnnual_Constraint`. Note - that the :code:`tech_flex` set is different from :code:`tech_curtailment` set; - the latter is technology- rather than commodity-focused and is used in the - :code:`Capacity_Constraint` to track output that is used to produce useful - output and the amount curtailed, and to ensure that the installed capacity - covers both. Alternatively, the commodity can be added to the - :code:`commodity_waste` set, for which this equality constraint becomes an - inequality constraint, allowing production to exceed consumption for a single - commodity. - - 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{FO}` variables over the appropriate import and export regions, - respectively, which are defined in :code:`temoa_initialize.py` by parsing the - :code:`tech_exchange` processes. - - Consumption of the commodity by construction inputs is annualised using the period - length. Production of the commodity by end-of-life outputs uses the AnnualRetirement - variable, which is already annualised. - - Finally, for annual commodities, AnnualCommodityBalance is used which balances - the sum of flows over each year. - - *process outputs + imports + end of life outputs = process inputs + construction inputs + exports + flex waste* - - .. math:: - :label: CommodityBalance - - \begin{aligned} - &\sum_{I, t \notin T^a, V} \mathbf{FO}_{r, p, s, d, i, t, v, c} - && \text{(processes outputting commodity)} \\ - &+ SEG_{s,d} \cdot \sum_{I, t \in T^a, V} \frac{\mathbf{FOA}_{r, p, i, t, v, c}}{EFF_{r, i, t, v, c}} - && \text{(annual processes outputting commodity)} \\ - &+ \sum_{\text{reg} \neq r, I, t \in T^x, V} \mathbf{FIM}_{r - \text{reg}, p, s, d, i, t, v, c} - && \text{(inter-regional imports of commodity)} \\ - &+ SEG_{s,d} \sum_{T, V} \left ( EOLO_{r, t, v, c} \cdot \textbf{ART}_{r, p, t, v} \right ) - && \text{(end-of-life outputs of commodity)} \\ - &\begin{cases} - &= \text{if } c \notin C^w \\ - &\geq \text{if } c \in C^w \end{cases} \\ - &\sum_{t \in T^s, V, O} \mathbf{FIS}_{r, p, s, d, c, t, v, o} - && \text{(commodity stored)} \\ - &+ \sum_{t \notin T^s, V, O} \frac{\mathbf{FO}_{r, p, s, d, c, t, v, o}}{EFF_{r, c, t, v, o}} - && \text{(commodity consumed by processes)} \\ - &+ SEG_{s,d} \cdot \sum_{t \in T^a, V, O} \frac{\mathbf{FOA}_{r, p, c, t, v, o}}{EFF_{r, c, t, v, o}} - && \text{(commodity consumed by annual processes)} \\ - &+ \sum_{\text{reg} \neq r, t \in T^x, V, O} \mathbf{FEX}_{r - \text{reg}, p, s, d, c, t, v, o} - && \text{(inter-regional exports of commodity)} \\ - &+ \sum_{I, t \in T^f, V} \mathbf{FLX}_{r, p, s, d, i, t, v, c} - && \text{(flex wastes of commodity)} \\ - &+ SEG_{s,d} \cdot \sum_{T, V} \left ( CON_{r, c, t, v} \cdot \frac{\textbf{NCAP}_{r, t, v}}{LEN_p} \right ) - && \text{(consumed annually by construction inputs)} - \end{aligned} - - \qquad \forall \{r, p, s, d, c\} \in \Theta_{\text{CommodityBalance}} - - """ - - produced = 0 - consumed = 0 - - if (r, p, c) in M.commodityDStreamProcess: - # Only storage techs have a flow in variable - # For other techs, it would be redundant as in = out / eff - consumed += sum( - M.V_FlowIn[r, p, s, d, c, S_t, S_v, S_o] - for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t in M.tech_storage - for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] - ) - - # Into flows - consumed += sum( - M.V_FlowOut[r, p, s, d, c, S_t, S_v, S_o] - / get_variable_efficiency(M, r, p, s, d, c, S_t, S_v, S_o) - for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t not in M.tech_storage and S_t not in M.tech_annual - for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] - ) - - # Into annual flows - consumed += sum( - ( - value(M.DemandSpecificDistribution[r, p, s, d, S_o]) - if S_o in M.commodity_demand - else value(M.SegFrac[p, s, d]) - ) - * M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] - / get_variable_efficiency(M, r, p, s, d, c, S_t, S_v, S_o) - for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t in M.tech_annual - for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] - ) - - if (r, p, c) in M.capacityConsumptionTechs: - # Consumed by building capacity - # Assume evenly distributed over a year - consumed += ( - value(M.SegFrac[p, s, d]) - * sum( - value(M.ConstructionInput[r, c, S_t, p]) * M.V_NewCapacity[r, S_t, p] - for S_t in M.capacityConsumptionTechs[r, p, c] - ) - / M.PeriodLength[p] - ) - - if (r, p, c) in M.commodityUStreamProcess: - # From flows including output from storage - produced += sum( - M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, c] - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t not in M.tech_annual - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] - ) - - # From annual flows - produced += value(M.SegFrac[p, s, d]) * sum( - M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, c] - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t in M.tech_annual - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] - ) - - if c in M.commodity_flex: - # Wasted by flex flows - consumed += sum( - M.V_Flex[r, p, s, d, S_i, S_t, S_v, c] - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t not in M.tech_annual and S_t in M.tech_flex - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] - ) - # Wasted by annual flex flows - consumed += value(M.SegFrac[p, s, d]) * sum( - M.V_FlexAnnual[r, p, S_i, S_t, S_v, c] - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t in M.tech_annual and S_t in M.tech_flex - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] - ) - - if (r, p, c) in M.retirementProductionProcesses: - # Produced by retiring capacity - # Assume evenly distributed over a year - produced += value(M.SegFrac[p, s, d]) * sum( - value(M.EndOfLifeOutput[r, S_t, S_v, c]) * M.V_AnnualRetirement[r, p, S_t, S_v] - for S_t, S_v in M.retirementProductionProcesses[r, p, c] - ) - - # export of commodity c from region r to other regions - if (r, p, c) in M.exportRegions: - consumed += sum( - M.V_FlowOut[r + '-' + reg, p, s, d, c, S_t, S_v, S_o] - / get_variable_efficiency(M, r + '-' + reg, p, s, d, c, S_t, S_v, S_o) - for reg, S_t, S_v, S_o in M.exportRegions[r, p, c] - if S_t not in M.tech_annual - ) - consumed += sum( - value(M.SegFrac[p, s, d]) - * M.V_FlowOutAnnual[r + '-' + reg, p, c, S_t, S_v, S_o] - / get_variable_efficiency(M, r + '-' + reg, p, s, d, c, S_t, S_v, S_o) - for reg, S_t, S_v, S_o in M.exportRegions[r, p, c] - if S_t in M.tech_annual - ) - - # import of commodity c from other regions into region r - if (r, p, c) in M.importRegions: - produced += sum( - M.V_FlowOut[reg + '-' + r, p, s, d, S_i, S_t, S_v, c] - for reg, S_t, S_v, S_i in M.importRegions[r, p, c] - if S_t not in M.tech_annual - ) - produced += sum( - value(M.SegFrac[p, s, d]) * M.V_FlowOutAnnual[reg + '-' + r, p, S_i, S_t, S_v, c] - for reg, S_t, S_v, S_i in M.importRegions[r, p, c] - if S_t in M.tech_annual - ) - - commodities.CommodityBalanceConstraintErrorCheck( - produced, - consumed, - r, - p, - s, - d, - c, - ) - - if c in M.commodity_waste: - expr = produced >= consumed - else: - expr = produced == consumed - - return expr - - -def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): - r""" - Similar to CommodityBalance_Constraint but only balances the supply and demand of the commodity - at the period level, summing all flows over the period but allowing imbalances at the time slice - or seasonal level. Applies only to commodities in the :code:`commodity_annual` set. - """ - - produced = 0 - consumed = 0 - - if (r, p, c) in M.commodityDStreamProcess: - # Only storage techs have a flow in variable - # For other techs, it would be redundant as in = out / eff - consumed += sum( - M.V_FlowIn[r, p, S_s, S_d, c, S_t, S_v, S_o] - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day - for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t in M.tech_storage - for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] - ) - - consumed += sum( - M.V_FlowOut[r, p, S_s, S_d, c, S_t, S_v, S_o] - / get_variable_efficiency(M, r, p, S_s, S_d, c, S_t, S_v, S_o) - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day - for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t not in M.tech_storage and S_t not in M.tech_annual - for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] - ) - - consumed += sum( - M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] / value(M.Efficiency[r, c, S_t, S_v, S_o]) - for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t in M.tech_annual - for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] - ) - - if (r, p, c) in M.capacityConsumptionTechs: - # Consumed by building capacity - # Assume evenly distributed over a year - consumed += ( - sum( - value(M.ConstructionInput[r, c, S_t, p]) * M.V_NewCapacity[r, S_t, p] - for S_t in M.capacityConsumptionTechs[r, p, c] - ) - / M.PeriodLength[p] - ) - - if (r, p, c) in M.commodityUStreamProcess: - # Includes output from storage - produced += sum( - M.V_FlowOut[r, p, S_s, S_d, S_i, S_t, S_v, c] - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t not in M.tech_annual - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] - ) - - produced += sum( - M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, c] - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t in M.tech_annual - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] - ) - - if c in M.commodity_flex: - consumed += sum( - M.V_Flex[r, p, S_s, S_d, S_i, S_t, S_v, c] - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t not in M.tech_annual and S_t in M.tech_flex - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] - ) - consumed += sum( - M.V_FlexAnnual[r, p, S_i, S_t, S_v, c] - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t in M.tech_flex and S_t in M.tech_annual - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] - ) - - if (r, p, c) in M.retirementProductionProcesses: - # Produced by retiring capacity - # Assume evenly distributed over a year - produced += sum( - value(M.EndOfLifeOutput[r, S_t, S_v, c]) * M.V_AnnualRetirement[r, p, S_t, S_v] - for S_t, S_v in M.retirementProductionProcesses[r, p, c] - ) - - # export of commodity c from region r to other regions - if (r, p, c) in M.exportRegions: - consumed += sum( - M.V_FlowOut[r + '-' + S_r, p, S_s, S_d, c, S_t, S_v, S_o] - / get_variable_efficiency(M, r + '-' + S_r, p, S_s, S_d, c, S_t, S_v, S_o) - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day - for S_r, S_t, S_v, S_o in M.exportRegions[r, p, c] - if S_t not in M.tech_annual - ) - consumed += sum( - M.V_FlowOutAnnual[r + '-' + S_r, p, c, S_t, S_v, S_o] - / M.Efficiency[r + '-' + S_r, c, S_t, S_v, S_o] - for S_r, S_t, S_v, S_o in M.exportRegions[r, p, c] - if S_t in M.tech_annual - ) - - # import of commodity c from other regions into region r - if (r, p, c) in M.importRegions: - produced += sum( - M.V_FlowOut[S_r + '-' + r, p, S_s, S_d, S_i, S_t, S_v, c] - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day - for S_r, S_t, S_v, S_i in M.importRegions[r, p, c] - if S_t not in M.tech_annual - ) - produced += sum( - M.V_FlowOutAnnual[S_r + '-' + r, p, S_i, S_t, S_v, c] - for S_r, S_t, S_v, S_i in M.importRegions[r, p, c] - if S_t in M.tech_annual - ) - - commodities.AnnualCommodityBalanceConstraintErrorCheck( - produced, - consumed, - r, - p, - c, - ) - - if c in M.commodity_waste: - expr = produced >= consumed - else: - expr = produced == consumed - - return expr - - -# Devnote: Not currently active -# def ResourceExtraction_Constraint(M: 'TemoaModel', reg, p, r): -# r""" -# The ResourceExtraction constraint allows a modeler to specify an annual limit on -# the amount of a particular resource Temoa may use in a period. The first version -# of the constraint pertains to technologies with variable output at the time slice -# level, and the second version pertains to technologies with constant annual output -# belonging to the :code:`tech_annual` set. - -# .. math:: -# :label: ResourceExtraction - -# \sum_{S, D, I, t \in T^r \& t \not \in T^{a}, V} \textbf{FO}_{r, p, s, d, i, t, v, c} \le RSC_{r, p, c} - -# \forall \{r, p, c\} \in \Theta_{\text{ResourceExtraction}} - -# \sum_{I, t \in T^r \& t \in T^{a}, V} \textbf{FOA}_{r, p, i, t, v, c} \le RSC_{r, p, c} - -# \forall \{r, p, c\} \in \Theta_{\text{ResourceExtraction}} -# """ -# logger.warning( -# 'The ResourceBound parameter / ResourceExtraction constraint is not currently supported. ' -# 'Recommend removing data from supporting table' -# ) -# # dev note: This constraint does not have a table in the current schema -# # Additionally, the below (incorrect) construct assumes that a resource cannot be used -# # by BOTH a non-annual and annual tech. It should be re-written to add these -# # dev note: Cant think of a case where this would be needed but cant use LimitActivityGroup -# try: -# collected = sum( -# M.V_FlowOut[reg, p, S_s, S_d, S_i, S_t, S_v, r] # is r the input or the output!? -# for S_i, S_t, S_v in M.processByPeriodAndOutput -# for S_s in M.TimeSeason[p] -# for S_d in M.time_of_day -# ) -# except KeyError: -# collected = sum( -# M.V_FlowOutAnnual[reg, p, S_i, S_t, S_v, r] -# for S_i, S_t, S_v in M.processByPeriodAndOutput -# ) - -# expr = collected <= value(M.ResourceBound[reg, p, r]) -# return expr - - -def BaseloadDiurnal_Constraint(M: 'TemoaModel', r, p, s, d, t, v): - r""" - - Some electric generators cannot ramp output over a short period of time (e.g., - hourly or daily). Temoa models this behavior by forcing technologies in the - :code:`tech_baseload` set to maintain a constant output across all times-of-day - within the same season. Note that the output of a baseload process can vary - between seasons. - - Ideally, this constraint would not be necessary, and baseload processes would - simply not have a :math:`d` index. However, implementing the more efficient - functionality is currently on the Temoa TODO list. - - .. math:: - :label: BaseloadDaily - - SEG_{s, D_0} - \cdot \sum_{I, O} \textbf{FO}_{r, p, s, d,i, t, v, o} - = - SEG_{s, d} - \cdot \sum_{I, O} \textbf{FO}_{r, p, s, D_0,i, t, v, o} - - \\ - \forall \{r, p, s, d, t, v\} \in \Theta_{\text{BaseloadDiurnal}} - """ - # Question: How to set the different times of day equal to each other? - - # Step 1: Acquire a "canonical" representation of the times of day - l_times = sorted(M.time_of_day) # i.e. a sorted Python list. - # This is the commonality between invocations of this method. - - index = l_times.index(d) - if 0 == index: - # When index is 0, it means that we've reached the beginning of the array - # For the algorithm, this is a terminating condition: do not create - # an effectively useless constraint - return Constraint.Skip - - # Step 2: Set the rest of the times of day equal in output to the first. - # i.e. create a set of constraints that look something like: - # tod[ 2 ] == tod[ 1 ] - # tod[ 3 ] == tod[ 1 ] - # tod[ 4 ] == tod[ 1 ] - # and so on ... - d_0 = l_times[0] - - # Step 3: the actual expression. For baseload, must compute the /average/ - # activity over the segment. By definition, average is - # (segment activity) / (segment length) - # So: (ActA / SegA) == (ActB / SegB) - # computationally, however, multiplication is cheaper than division, so: - # (ActA * SegB) == (ActB * SegA) - activity_sd = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - - activity_sd_0 = sum( - M.V_FlowOut[r, p, s, d_0, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - - expr = activity_sd * value(M.SegFrac[p, s, d_0]) == activity_sd_0 * value(M.SegFrac[p, s, d]) - - return expr - - -def RegionalExchangeCapacity_Constraint(M: 'TemoaModel', r_e, r_i, p, t, v): - r""" - - This constraint ensures that the process (t,v) connecting regions - r_e and r_i is handled by one capacity variables. - - .. math:: - :label: RegionalExchangeCapacity - - \textbf{CAP}_{r_e,t,v} - = - \textbf{CAP}_{r_i,t,v} - - \\ - \forall \{r_e, r_i, t, v\} \in \Theta_{\text{RegionalExchangeCapacity}} - """ - - expr = M.V_Capacity[r_e + '-' + r_i, p, t, v] == M.V_Capacity[r_i + '-' + r_e, p, t, v] - - return expr - - -def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): - r""" - This constraint enforces the continuity of storage level between time slices. - storage level in the next time slice (:math:`s_{next}, d_{next}`) is equal to - current storage level plus net charge in the current time slice. - - .. math:: - :label: Storage Energy - - {SL}_{r,p,s,d,t,v} - + \sum\limits_{I,O} \mathbf{FIS}_{r,p,s,d,i,t,v,o} \cdot {EFF}_{r,i,t,v,o} - - \sum\limits_{I,O} \mathbf{FO}_{r,p,s,d,i,t,v,o} - = {SL}_{r,p,s_{{next}},d_{{next}},t,v} - - Note that for all seasonal representations except consecutive_days, the last time slice - of each season will loop back to the first time slice of the same season, preventing - seasonal deltas for non-seasonal storage (see SeasonalStorageEnergyUpperBound). - """ - - # We allow a non-zero daily delta only in the case of seasonal storage - if M.isSeasonalStorage[t] and d == M.time_of_day.last(): - return Constraint.Skip # handled by SeasonalStorageEnergy_Constraint - - # This is the sum of all input=i sent TO storage tech t of vintage v with - # output=o in p,s,d - charge = sum( - M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] - * get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - - # This is the sum of all output=o withdrawn FROM storage tech t of vintage v - # with input=i in p,s,d - discharge = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_o in M.processOutputs[r, p, t, v] - for S_i in M.processInputsByOutput[r, p, t, v, S_o] - ) - - stored_energy = charge - discharge - - s_next, d_next = M.time_next[p, s, d] - - expr = ( - M.V_StorageLevel[r, p, s, d, t, v] + stored_energy - == M.V_StorageLevel[r, p, s_next, d_next, t, v] - ) - - return expr - - -def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_seq, t, v): - r""" - This constraint enforces the continuity of state of charge between seasons for seasonal - storage. Sequential season storage level increases by the matched season's net charge - over that entire day, adjusted for number of days represented by sequential vs non-sequential - seasons. Only applies to storage technologies in the :code:`tech_seasonal_storage` set. - :math:`s^*` represents the matching non-sequential season for the sequential season - :math:`s^{seq}`. - - .. math:: - :label: Storage Energy (Sequential Seasons) - - \mathbf{SSL}_{r,p,s^{seq},t,v} - + DA_{r,p,s^{seq}} \cdot \left(\mathbf{SL}_{r,p,s^*,d_{last},t,v} + - \sum_{I,O} \mathbf{FI}_{r,p,s^*,d_{last},i,t,v,o} \cdot EFF_{r,i,t,v,o} - - \sum_{I,O} \mathbf{FO}_{r,p,s^*,d_{last},i,t,v,o} - \right) - - = DA_{r,p,s^{seq}_{next}} \cdot \mathbf{SL}_{r,p,s_{next}^*,d_{first},t,v} - + \mathbf{SSL}_{r,p,s^{seq}_{next},t,v} - - \\ - \text{where } DA_{r,p,s^{seq}} = \frac{\#days_{s^{seq}}}{SEG_{r,p,s^*} \cdot DPP} - - .. figure:: images/ldes_chain.* - :align: center - :width: 100% - :figclass: align-center - :figwidth: 60% - - How sequential seasons chain together for seasonal storage. Hatched area is - SeasonalStorageLevel :math:`SSL_{r,p,s^{seq},t,v}`. Vertical lines are - StorageLevel :math:`SL_{r,p,s^*,d,t,v}`. Green line is net seasonal storage - level :math:`SSL_{r,p,s^{seq},t,v} + SL_{r,p,s^*,d,t,v}`. Background grey - lines show how storage levels from non-sequential seasons are combined - in sequential seasons. Dashed line is SeasonalStorageEnergyUpperBound. - Sequential seasons two and four here are each two days while one and three - are each one day. - """ - - s = M.sequential_to_season[p, s_seq] - - # This is the sum of all input=i sent TO storage tech t of vintage v with - # output=o in p,s - charge = sum( - M.V_FlowIn[r, p, s, M.time_of_day.last(), S_i, t, v, S_o] - * get_variable_efficiency(M, r, p, s, M.time_of_day.last(), S_i, t, v, S_o) - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - - # This is the sum of all output=o withdrawn FROM storage tech t of vintage v - # with input=i in p,s - discharge = sum( - M.V_FlowOut[r, p, s, M.time_of_day.last(), S_i, t, v, S_o] - for S_o in M.processOutputs[r, p, t, v] - for S_i in M.processInputsByOutput[r, p, t, v, S_o] - ) - - s_seq_next = M.time_next_sequential[p, s_seq] - s_next = M.sequential_to_season[p, s_seq_next] - - # Flows and StorageLevel are normalised to the number of days in the non-sequential season, so must - # be adjusted to the number of days in the sequential season - days_adjust = value(M.TimeSeasonSequential[p, s_seq, s]) / ( - value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod) - ) - days_adjust_next = value(M.TimeSeasonSequential[p, s_seq_next, s_next]) / ( - value(M.SegFracPerSeason[p, s_next]) * value(M.DaysPerPeriod) - ) - - stored_energy = (charge - discharge) * days_adjust - - start = ( - M.V_SeasonalStorageLevel[r, p, s_seq, t, v] - + M.V_StorageLevel[r, p, s, M.time_of_day.last(), t, v] * days_adjust - ) - end = ( - M.V_SeasonalStorageLevel[r, p, s_seq_next, t, v] - + M.V_StorageLevel[r, p, s_next, M.time_of_day.first(), t, v] * days_adjust_next - ) - - expr = start + stored_energy == end - return expr - - -def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): - r""" - This constraint ensures that the amount of energy stored does not exceed - the upper bound set by the energy capacity of the storage device, as calculated - on the right-hand side. - - Because the number and duration of time slices are user-defined, we need to adjust - the storage duration, which is specified in hours. First, the hourly duration is divided - by the number of hours in a year to obtain the duration as a fraction of the year. - Since the :math:`C2A` parameter assumes the conversion of capacity to annual activity, - we need to express the storage duration as fraction of a year. Then, :math:`SEG_{s,d}` - summed over the time-of-day slices (:math:`d`) multiplied by :math:`DPP` yields the - number of days per season. This step is necessary because conventional time sliced models - use a single day to represent many days within a given season. Thus, it is necessary to - scale the storage duration to account for the number of days in each season. - - .. math:: - :label: StorageEnergyUpperBound - - \textbf{SL}_{r, p, s, d, t, v} \le - \textbf{CAP}_{r,t,v} \cdot C2A_{r,t} \cdot \frac {SD_{r,t}}{24 \cdot DPP} - \cdot \sum_{d} SEG_{s,d} \cdot DPP - - \\ - \forall \{r, p, s, d, t, v\} \in \Theta_{\text{StorageEnergyUpperBound}} - - A season can represent many days. Within each season, flows are multiplied by the - number of days each season represents and, so, the upper bound needs to be adjusted - to allow day-scale flows (e.g., charge in the morning, discharge in the afternoon). - - .. figure:: images/daily_storage_representation.* - :align: center - :width: 100% - :figclass: center - :figwidth: 40% - - Representation of a 3-day season for non-seasonal (daily) storage. - """ - - if M.isSeasonalStorage[t]: - return Constraint.Skip # redundant on SeasonalStorageEnergyUpperBound - - energy_capacity = ( - M.V_Capacity[r, p, t, v] - * value(M.CapacityToActivity[r, t]) - * (value(M.StorageDuration[r, t]) / (24 * value(M.DaysPerPeriod))) - * value(M.SegFracPerSeason[p, s]) - * M.DaysPerPeriod # adjust for days in season - ) - - expr = M.V_StorageLevel[r, p, s, d, t, v] <= energy_capacity - - return expr - - -def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_seq, d, t, v): - r""" - Builds off of StorageEnergyUpperBound_Constraint. Enforces the max charge capacity - of seasonal storage, summing the real storage level with the superimposed sequential - seasonal storage level. :math:`s^*` represents the matching non-sequential season for - the sequential season :math:`s^{seq}`. - - .. math:: - :label: Seasonal Storage Energy Capacity - - \mathbf{SSL}_{r,p,s^{seq},t,v} - + \mathbf{SL}_{r,p,s^*,d,t,v} \cdot DA_{r,p,s^{seq}} - \leq \mathbf{CAP}_{r,p,t,v} \cdot C2A_{r,t} \cdot \frac{SD_{r,t}}{24 \cdot DPP} - - \\ - - \text{where } DA_{r,p,s^{seq}} = \frac{\#days_{s^{seq}}}{SEG_{r,p,s^*} \cdot DPP} - - - - Unlike non-seasonal (daily) storage, seasonal storage is allowed to carry energy - between seasons. However, through seasons representing multiple days, many days' - charge deltas have accumulated, multiplied by the number of days the season - represents. If we allowed these stacked deltas to carry between seasons then we would - be multiplying the effective energy capacity of the storage. We could just constrain - the seasonal delta to the unadjusted energy capacity, but then the final day in the - season would sit atop a season's worth of deltas, possibly exceeding our upper or - lower bound by a factor of :math:`\frac{N-1}{N}` where :math:`N` is the number of - days the sequential season represents. - - .. figure:: images/ldes_delta_problem.* - :align: center - :width: 100% - :figclass: center - :figwidth: 100% - - The energy upper bound or non-negative lower bound could be violated in a - season representing multiple days if we both adjusted the upper bound to - the number of days and allowed a seasonal delta. - - So, we do not adjust the upper energy bound for seasonal storage. This limits the - ability of seasonal storage to perform arbitrage within each season, but allows it to - carry energy between seasons realistically. - - .. figure:: images/ldes_delta_representation.* - :align: center - :width: 100% - :figclass: center - :figwidth: 40% - - Unadjusted energy upper bound constraint for seasonal storage. - """ - - s = M.sequential_to_season[p, s_seq] - - energy_capacity = ( - M.V_Capacity[r, p, t, v] - * value(M.CapacityToActivity[r, t]) - * (value(M.StorageDuration[r, t]) / (24 * value(M.DaysPerPeriod))) - ) - - # Flows and StorageLevel are normalised to the number of days in the non-sequential season, so must - # be adjusted to the number of days in the sequential season - days_adjust = value(M.TimeSeasonSequential[p, s_seq, s]) / ( - value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod) - ) - - # V_StorageLevel tracks the running cumulative delta in the non-sequential season, so must be adjusted - # to the size of the sequential season - running_day_delta = M.V_StorageLevel[r, p, s, d, t, v] * days_adjust - - expr = M.V_SeasonalStorageLevel[r, p, s_seq, t, v] + running_day_delta <= energy_capacity - - return expr - - -def StorageChargeRate_Constraint(M: 'TemoaModel', r, p, s, d, t, v): - r""" - - This constraint ensures that the charge rate of the storage unit is - limited by the power capacity (typically GW) of the storage unit. - - .. math:: - :label: StorageChargeRate - - \sum_{I, O} \textbf{FIS}_{r, p, s, d, i, t, v, o} \cdot EFF_{r,i,t,v,o} - \le - \textbf{CAP}_{r,t,v} \cdot C2A_{r,t} \cdot SEG_{s,d} - - \\ - \forall \{r, p, s, d, t, v\} \in \Theta_{\text{StorageChargeRate}} - - """ - # Calculate energy charge in each time slice - slice_charge = sum( - M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] - * get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - - # Maximum energy charge in each time slice - max_charge = ( - M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[p, s, d]) - ) - - # Energy charge cannot exceed the power capacity of the storage unit - expr = slice_charge <= max_charge - - return expr - - -def StorageDischargeRate_Constraint(M: 'TemoaModel', r, p, s, d, t, v): - r""" - - This constraint ensures that the discharge rate of the storage unit - is limited by the power capacity (typically GW) of the storage unit. - - .. math:: - :label: StorageDischargeRate - - \sum_{I, O} \textbf{FO}_{r, p, s, d, i, t, v, o} - \le - \textbf{CAP}_{r,t,v} \cdot C2A_{r,t} \cdot SEG_{s,d} - - \\ - \forall \{r,p, s, d, t, v\} \in \Theta_{\text{StorageDischargeRate}} - """ - # Calculate energy discharge in each time slice - slice_discharge = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_o in M.processOutputs[r, p, t, v] - for S_i in M.processInputsByOutput[r, p, t, v, S_o] - ) - - # Maximum energy discharge in each time slice - max_discharge = ( - M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[p, s, d]) - ) - - # Energy discharge cannot exceed the capacity of the storage unit - expr = slice_discharge <= max_discharge - - return expr - - -def StorageThroughput_Constraint(M: 'TemoaModel', r, p, s, d, t, v): - r""" - - It is not enough to only limit the charge and discharge rate separately. We also - need to ensure that the maximum throughput (charge + discharge) does not exceed - the capacity (typically GW) of the storage unit. - - .. math:: - :label: StorageThroughput - - \sum_{I, O} \textbf{FO}_{r, p, s, d, i, t, v, o} - + - \sum_{I, O} \textbf{FIS}_{r, p, s, d, i, t, v, o} \cdot EFF_{r,i,t,v,o} - \le - \textbf{CAP}_{r,t,v} \cdot C2A_{r,t} \cdot SEG_{s,d} - - \\ - \forall \{r, p, s, d, t, v\} \in \Theta_{\text{StorageThroughput}} - """ - discharge = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_o in M.processOutputs[r, p, t, v] - for S_i in M.processInputsByOutput[r, p, t, v, S_o] - ) - - charge = sum( - M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] - * get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - - throughput = charge + discharge - max_throughput = ( - M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[p, s, d]) - ) - expr = throughput <= max_throughput - return expr - - -def LimitStorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v, op): - r""" - - This constraint is used if the users wishes to force a specific storage charge level - for certain storage technologies and vintages at a certain time slice. - In this case, the value of the decision variable :math:`\textbf{SI}_{r,t,v}` is set by - this constraint rather than being optimized. User-specified storage charge levels that are - sufficiently different from the optimal :math:`\textbf{SI}_{r,t,v}` could impact the - cost-effectiveness of storage. For example, if the optimal charge level happens to be - 50% of the full energy capacity, forced charge levels (specified by parameter - :math:`SIF_{r,t,v}`) equal to 10% or 90% of the full energycapacity could lead to - more expensive solutions. - - - .. math:: - :label: LimitStorageFraction - - \textbf{SF}_{r,p,s,d,t,v} \le - \ SF_{r,p,s,d,t,v} - \cdot - \textbf{CAP}_{r,p,t,v} \cdot C2A_{r,t} \cdot \frac {SD_{r,t}}{(24 \cdot DPP hrs/yr} - \cdot \sum_{d} SEG_{s,d} \cdot M.DaysPerPeriod days/yr \cdot MPL_{r,p,t,v} - - \\ - \forall \{r, p, s, d, t, v\} \in \Theta_{\text{LimitStorageFraction}} - """ - - energy_limit = ( - M.V_Capacity[r, p, t, v] - * value(M.CapacityToActivity[r, t]) - * (value(M.StorageDuration[r, t]) / (24 * value(M.DaysPerPeriod))) - * value(M.LimitStorageFraction[r, p, s, d, t, v, op]) - ) - - if M.isSeasonalStorage[t]: - s_seq = s # sequential season - s = M.sequential_to_season[p, s_seq] # non-sequential season - - # adjust the storage level to the individual-day level - energy_level = M.V_StorageLevel[r, p, s, d, t, v] / ( - value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod) - ) - - if M.isSeasonalStorage[t]: - # seasonal storage upper energy limit is absolute - energy_level = M.V_SeasonalStorageLevel[r, p, s_seq, t, v] + energy_level * value( - M.TimeSeasonSequential[p, s_seq, s] - ) - - expr = operator_expression(energy_level, op, energy_limit) - - return expr - - -def RampUpDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): - r""" - One of two constraints built from the RampUpHourly table, along with the - RampUpSeason_Constraint. RampUpDay constrains ramp rates between time slices - within each season and RampUpSeason constrains ramp rates between sequential - seasons. If the :code:`time_sequencing` parameter is set to :code:`consecutive_days` - then the RampUpSeason constraint is skipped as seasons already connect together. - - The ramp rate constraint is utilized to limit the rate of electricity generation - increase and decrease between two adjacent time slices in order to account for - physical limits associated with thermal power plants. This constraint is only - applied to technologies in the set :code:`tech_upramping`. We assume for - simplicity the rate limits do not vary with technology vintage. The ramp rate - limits for a technology should be expressed in percentage of its rated capacity - per hour. - - In a representative periods or seasonal time slices model, the next time slice, - :math:`(s_{next},d_{next})`, from the end of each season, :math:`(s,d_{last})` - is the beginning of the same season, :math:`(s,d_{first})` - - .. math:: - :label: RampUpDay - - \frac{ - \sum_{I,O} \mathbf{FO}_{r,p,s_{next},d_{next},i,t,v,o} - }{ - SEG_{r,p,s_{next},d_{next}} \cdot 24 \cdot DPP - } - - - \frac{ - \sum_{I,O} \mathbf{FO}_{r,p,s,d,i,t,v,o} - }{ - SEG_{r,p,s,d} \cdot 24 \cdot DPP - } - \leq - R_{r,t} \cdot \Delta H_{r,p,s,d,s_{next},d_{next}} \cdot CAP_{r,p,t,v} \cdot C2A_{r,t} - \\ - \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampUpDay}} - \\ - \text{where: } \Delta H_{r,p,s,d,s_{next},d_{next}} = \frac{24}{2} - \left ( \frac{SEG_{r,p,s,d}}{\sum_{D} SEG_{r,p,s,d'}} + - \frac{SEG_{r,p,s_{next},d_{next}}}{\sum_{D} SEG_{r,p,s_{next},d'}} \right ) - - where: - - - :math:`SEG_{r,p,s,d}` is the fraction of the period in time slice :math:`(s,d)` - - :math:`DPP` is the number of days in each period - - :math:`R_{r,t}` is the ramp rate per hour - - :math:`\Delta H_{r,p,s,d,s_{next},d_{next}}` is the number of elapsed hours between midpoints of time slices - - :math:`CAP \cdot C2A` gives the maximum hourly change in activity - """ - - s_next, d_next = M.time_next[p, s, d] - - # How many hours does this time slice represent - hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 - - hourly_activity_sd = ( - sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - / hours_adjust - ) - - hourly_activity_sd_next = ( - sum( - M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - / hours_adjust - ) - - # elapsed hours from middle of this time slice to middle of next time slice - hours_elapsed = ( - 24 - / 2 - * ( - value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) - + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) - ) - ) - ramp_fraction = hours_elapsed * value(M.RampUpHourly[r, t]) - - if ramp_fraction >= 1: - msg = ( - 'Warning: Hourly ramp up rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' - f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' - ) - logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) - return Constraint.Skip - - activity_increase = hourly_activity_sd_next - hourly_activity_sd # opposite sign from rampdown - rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) - expr = activity_increase <= rampable_activity - - return expr - - -def RampDownDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): - r""" - - Similar to the :code`RampUpDay` constraint, we use the :code:`RampDownDay` - constraint to limit ramp down rates between any two adjacent time slices. - - .. math:: - :label: RampDownDay - - \frac{ - \sum_{I,O} \mathbf{FO}_{r,p,s,d,i,t,v,o} - }{ - SEG_{r,p,s,d} \cdot 24 \cdot DPP - } - - - \frac{ - \sum_{I,O} \mathbf{FO}_{r,p,s_{next},d_{next},i,t,v,o} - }{ - SEG_{r,p,s_{next},d_{next}} \cdot 24 \cdot DPP - } - \leq - R_{r,t} \cdot \Delta H_{r,p,s,d,s_{next},d_{next}} \cdot CAP_{r,p,t,v} \cdot C2A_{r,t} - \\ - \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampDownDay}} - """ - - s_next, d_next = M.time_next[p, s, d] - - # How many hours does this time slice represent - hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 - - hourly_activity_sd = ( - sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - / hours_adjust - ) - - hourly_activity_sd_next = ( - sum( - M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - / hours_adjust - ) - - # elapsed hours from middle of this time slice to middle of next time slice - hours_elapsed = ( - 24 - / 2 - * ( - value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) - + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) - ) - ) - ramp_fraction = hours_elapsed * value(M.RampDownHourly[r, t]) - - if ramp_fraction >= 1: - msg = ( - 'Warning: Hourly ramp down rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' - f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' - ) - logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) - return Constraint.Skip - - activity_decrease = hourly_activity_sd - hourly_activity_sd_next # opposite sign from rampup - rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) - expr = activity_decrease <= rampable_activity - - return expr - - -def RampUpSeason_Constraint(M: 'TemoaModel', r, p, s, s_next, t, v): - r""" - Constrains the ramp up rate of activity between time slices at the boundary - of sequential seasons. Same as RampUpDay but only applies to the boundary - between sequential seasons, i.e., :math:`(s^{seq},d_{last})` to :math:`(s^{seq}_{next},d_{first})` - and :math:`s^{seq}_{next}` is based on the TimeSequential table rather than the - TimeSeason table. - """ - - d = M.time_of_day.last() - d_next = M.time_of_day.first() - - # How many hours does this time slice represent - hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 - - hourly_activity_sd = ( - sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - / hours_adjust - ) - - hourly_activity_sd_next = ( - sum( - M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - / hours_adjust - ) - - # elapsed hours from middle of this time slice to middle of next time slice - hours_elapsed = ( - 24 - / 2 - * ( - value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) - + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) - ) - ) - ramp_fraction = hours_elapsed * value(M.RampUpHourly[r, t]) - - if ramp_fraction >= 1: - msg = ( - 'Warning: Hourly ramp up rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' - f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' - ) - logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) - return Constraint.Skip - - activity_increase = hourly_activity_sd_next - hourly_activity_sd # opposite sign from rampdown - rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) - expr = activity_increase <= rampable_activity - - return expr - - -def RampDownSeason_Constraint(M: 'TemoaModel', r, p, s, s_next, t, v): - r""" - Constrains the ramp down rate of activity between time slices at the boundary - of sequential seasons. Same as RampDownDay but only applies to the boundary - between sequential seasons, i.e., :math:`(s^{seq},d_{last})` to :math:`(s^{seq}_{next},d_{first})` - and :math:`s^{seq}_{next}` is based on the TimeSequential table rather than the - TimeSeason table. - """ - - d = M.time_of_day.last() - d_next = M.time_of_day.first() - - # How many hours does this time slice represent - hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 - - hourly_activity_sd = ( - sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - / hours_adjust - ) - - hourly_activity_sd_next = ( - sum( - M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - / hours_adjust - ) - - # elapsed hours from middle of this time slice to middle of next time slice - hours_elapsed = ( - 24 - / 2 - * ( - value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) - + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) - ) - ) - ramp_fraction = hours_elapsed * value(M.RampDownHourly[r, t]) - - if ramp_fraction >= 1: - msg = ( - 'Warning: Hourly ramp down rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' - f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' - ) - logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) - return Constraint.Skip - - activity_decrease = hourly_activity_sd - hourly_activity_sd_next # opposite sign from rampup - rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) - expr = activity_decrease <= rampable_activity - - return expr - - -def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): - # Get available generation in this time slice depending on method specified in config file - match M.ReserveMarginMethod.first(): - case 'static': - available = ReserveMarginStatic(M, r, p, s, d) - case 'dynamic': - available = ReserveMarginDynamic(M, r, p, s, d) - case _: - msg = f"Invalid reserve margin parameter '{M.ReserveMarginMethod.first()}'. Check the config file." - logger.error(msg) - raise ValueError(msg) - - # In most Temoa input databases, demand is endogenous, so we use electricity - # generation instead as a proxy for electricity demand. - # Non-annual generation - total_generation = sum( - M.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] - for (t, S_v) in M.processReservePeriods[r, p] - if t not in M.tech_annual - for S_i in M.processInputs[r, p, t, S_v] - for S_o in M.processOutputsByInput[r, p, t, S_v, S_i] - ) - - # Generators might serve demands directly - # Annual generation - total_generation += sum( - ( - value(M.DemandSpecificDistribution[r, p, s, d, S_o]) - if S_o in M.commodity_demand - else value(M.SegFrac[p, s, d]) - ) - * M.V_FlowOutAnnual[r, p, s, d, S_i, t, S_v, S_o] - for (t, S_v) in M.processReservePeriods[r, p] - if t in M.tech_annual - for S_i in M.processInputs[r, p, t, S_v] - for S_o in M.processOutputsByInput[r, p, t, S_v, S_i] - ) - - # We must take into account flows into storage technologies. - # Flows into storage technologies need to be subtracted from the - # load calculation. - total_generation -= sum( - M.V_FlowIn[r, p, s, d, S_i, t, S_v, S_o] - for (t, S_v) in M.processReservePeriods[r, p] - if t in M.tech_storage - for S_i in M.processInputs[r, p, t, S_v] - for S_o in M.processOutputsByInput[r, p, t, S_v, S_i] - ) - - # Electricity imports and exports via exchange techs are accounted - # for below: - for r1r2 in M.regionalIndices: # ensure the region is of the form r1-r2 - if '-' not in r1r2: - continue - if (r1r2, p) not in M.processReservePeriods: # ensure r1r2 is a valid reserve provider in p - continue - r1, r2 = r1r2.split('-') - # First, determine the exports, and subtract this value from the - # total generation. - if r1 == r: - total_generation -= sum( - M.V_FlowOut[r1r2, p, s, d, S_i, t, S_v, S_o] - / get_variable_efficiency(M, r1r2, p, s, d, S_i, t, S_v, S_o) - for (t, S_v) in M.processReservePeriods[r1r2, p] - for S_i in M.processInputs[r1r2, p, t, S_v] - for S_o in M.processOutputsByInput[r1r2, p, t, S_v, S_i] - ) - # Second, determine the imports, and add this value from the - # total generation. - elif r2 == r: - total_generation += sum( - M.V_FlowOut[r1r2, p, s, d, S_i, t, S_v, S_o] - for (t, S_v) in M.processReservePeriods[r1r2, p] - for S_i in M.processInputs[r1r2, p, t, S_v] - for S_o in M.processOutputsByInput[r1r2, p, t, S_v, S_i] - ) - - requirement = total_generation * (1 + value(M.PlanningReserveMargin[r])) - return available >= requirement - - -def ReserveMarginStatic(M: 'TemoaModel', r, p, s, d): - r""" - - During each period :math:`p`, the sum of capacity values of all reserve - technologies :math:`\sum_{t \in T^{res}} \textbf{CAPAVL}_{r,p,t}`, which are - defined in the set :math:`\textbf{T}^{res}`, should exceed the peak load by - :math:`PRM`, the regional reserve margin. Note that the reserve - margin is expressed in percentage of the peak load. Generally speaking, in - a database we may not know the peak demand before running the model, therefore, - we write this equation for all the time-slices defined in the database in each region. - Each generator is allowed to contribute its available capacity times a pre-defined - capacity credit, :math:`CC_{t,r}` - - .. math:: - :label: reserve_margin_static - - &\sum_{t \in T^{res} \setminus T^{x}} {CC_{t,r} \cdot \textbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*} \cdot C2A_{r,t} }\\ - &+ \sum_{t \in T^{res} \cap T^{x}} {CC_{t,r_i-r} \cdot \textbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*} \cdot C2A_{r_i-r,t} }\\ - &- \sum_{t \in T^{res} \cap T^{x}} {CC_{t,r-r_i} \cdot \textbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*} \cdot C2A_{r-r_i,t} }\\ - &\geq \left [ \sum_{ t \in T^{res} \setminus T^{x},V,I,O } \textbf{FO}_{r, p, s, d, i, t, v, o}\right.\\ - &+ \sum_{ t \in T^{res} \cap T^{x},V,I,O } \textbf{FO}_{r_i-r, p, s, d, i, t, v, o}\\ - &- \sum_{ t \in T^{res} \cap T^{x},V,I,O } \textbf{FI}_{r-r_i, p, s, d, i, t, v, o}\\ - &- \left.\sum_{ t \in T^{res} \cap T^{s},V,I,O } \textbf{FI}_{r, p, s, d, i, t, v, o} \right] \cdot (1 + PRM_r)\\ - - \\ - &\qquad\qquad\forall \{r, p, s, d\} \in \Theta_{\text{ReserveMargin}} \text{and} \forall r_i \in R - """ - if (not M.tech_reserve) or ( - (r, p) not in M.processReservePeriods - ): # If reserve set empty or if r,p not in M.processReservePeriod, skip the constraint - return Constraint.Skip - - available = sum( - value(M.CapacityCredit[r, p, t, v]) - * M.V_Capacity[r, p, t, v] - * value(M.CapacityToActivity[r, t]) - * value(M.SegFrac[p, s, d]) - for (t, v) in M.processReservePeriods[r, p] - if t not in M.tech_uncap - ) - - # The above code does not consider exchange techs, e.g. electricity - # transmission between two distinct regions. - # We take exchange takes into account below. - # Note that a single exchange tech linking regions Ri and Rj is twice - # defined: once for region "Ri-Rj" and once for region "Rj-Ri". - - # First, determine the amount of firm capacity each exchange tech - # contributes. - for r1r2 in M.regionalIndices: - if '-' not in r1r2: - continue - if (r1r2, p) not in M.processReservePeriods: # ensure r1r2 is a valid reserve provider in p - continue - r1, r2 = r1r2.split('-') - - # Only consider the capacity of technologies that import to - # the region in question -- i.e. for cases where r2 == r. - if r2 != r: - continue - - # add the available capacity of the exchange tech. - available += sum( - value(M.CapacityCredit[r1r2, p, t, v]) - * M.V_Capacity[r1r2, p, t, v] - * value(M.CapacityToActivity[r1r2, t]) - * value(M.SegFrac[p, s, d]) - for (t, v) in M.processReservePeriods[r1r2, p] - for t in M.tech_reserve - ) - - return available - - -def ReserveMarginDynamic(M: 'TemoaModel', r, p, s, d): - r""" - A dynamic alternative to the traditional, static reserve margin constraint. Capacity values - are calculated from availability of generation in each hour—like an operating reserve margin—\ - accounting for a capacity derate factor subtracting, for example, forced outage due to icing. - - .. math:: - :label: reserve_margin_dynamic - - &\sum_{t \in T^{res} \setminus T^{x} \setminus T^s,\ V} CFP_{r,p,s^*,d^*,t,v}\ - \cdot RCD_{r,p,s^*,t,v}\ - \cdot \mathbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*}\ - \cdot C2A_{r,t} \\ - &+ \sum_{t \in T^{res} \cap T^{x} \setminus T^s,\ V} CFP_{r_i - r, p, s^*, d^*, t, v}\ - \cdot RCD_{r_i - r, p, s^*, t, v}\ - \cdot \mathbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*}\ - \cdot C2A_{r_i - r, t} \\ - &- \sum_{t \in T^{res} \cap T^{x} \setminus T^s,\ V} CFP_{r - r_i, p, s^*, d^*, t, v}\ - \cdot RCD_{r - r_i, p, s^*, t, v}\ - \cdot \mathbf{CAPAVL}_{p,t}\ - \cdot SEG_{s^*,d^*} \cdot C2A_{r - r_i, t} \\ - &+ \sum_{t \in (T^s \cap T^{res}), V, I, O} \ - \left(\ - \mathbf{FO}_{r,p,s,d,i,t,v,o} - \mathbf{FI}_{r,p,s,d,i,t,v,o}\ - \right)\ - \cdot RCD_{r,p,s,t,v} \\ - &\geq\ - \left[\ - \sum_{t \in T^{res} \setminus T^{x}, V, I, O}\ - \mathbf{FO}_{r, p, s, d, i, t, v, o}\ - \right. \\ - &+ \sum_{t \in T^{res} \cap T^{x}, V, I, O} \ - \mathbf{FO}_{r_i - r, p, s, d, i, t, v, o} \\ - &- \sum_{t \in T^{res} \cap T^{x}, V, I, O} \ - \mathbf{FI}_{r - r_i, p, s, d, i, t, v, o} \\ - &- \left. \sum_{t \in T^{res} \cap T^{s}, V, I, O} \ - \mathbf{FI}_{r, p, s, d, i, t, v, o} \right] \cdot (1 + PRM_r) \\ - \\ - &\qquad \qquad \forall \{r, p, s, d\} \in \ - \Theta_{\text{ReserveMargin}} \text{ and } \forall r_i \in R - """ - if (not M.tech_reserve) or ( - (r, p) not in M.processReservePeriods - ): # If reserve set empty or if r,p not in M.processReservePeriod, skip the constraint - return Constraint.Skip - - # Everything but storage and exchange techs - # Derated available generation - available = sum( - M.V_Capacity[r, p, t, v] - * value(M.ReserveCapacityDerate[r, p, s, t, v]) - * value(M.CapacityFactorProcess[r, p, s, d, t, v]) - * value(M.CapacityToActivity[r, t]) - * value(M.SegFrac[p, s, d]) - for (t, v) in M.processReservePeriods[r, p] - if t not in M.tech_uncap and t not in M.tech_storage - ) - - # Storage - # Derated net output flow - available += sum( - M.V_FlowOut[r, p, s, d, i, t, v, o] * value(M.ReserveCapacityDerate[r, p, s, t, v]) - for (t, v) in M.processReservePeriods[r, p] - if t in M.tech_storage - for i in M.processInputs[r, p, t, v] - for o in M.processOutputsByInput[r, p, t, v, i] - ) - available -= sum( - M.V_FlowIn[r, p, s, d, i, t, v, o] * value(M.ReserveCapacityDerate[r, p, s, t, v]) - for (t, v) in M.processReservePeriods[r, p] - if t in M.tech_storage - for i in M.processInputs[r, p, t, v] - for o in M.processOutputsByInput[r, p, t, v, i] - ) - - # The above code does not consider exchange techs, e.g. electricity - # transmission between two distinct regions. - # We take exchange takes into account below. - # Note that a single exchange tech linking regions Ri and Rj is twice - # defined: once for region "Ri-Rj" and once for region "Rj-Ri". - - # First, determine the amount of firm capacity each exchange tech - # contributes. - for r1r2 in M.regionalIndices: - if '-' not in r1r2: - continue - if (r1r2, p) not in M.processReservePeriods: # ensure r1r2 is a valid reserve provider in p - continue - r1, r2 = r1r2.split('-') - - # Only consider the capacity of technologies that import to - # the region in question -- i.e. for cases where r2 == r. - if r2 != r: - continue - - # add the available output of the exchange tech. - available += sum( - M.V_Capacity[r1r2, p, t, v] - * value(M.ReserveCapacityDerate[r, p, s, t, v]) - * value(M.CapacityFactorProcess[r, p, s, d, t, v]) - * value(M.CapacityToActivity[r1r2, t]) - * value(M.SegFrac[p, s, d]) - for (t, v) in M.processReservePeriods[r1r2, p] - for t in M.tech_reserve - ) - - return available - - -def LimitEmission_Constraint(M: 'TemoaModel', r, p, e, op): - r""" - - A modeler can track emissions through use of the :code:`commodity_emissions` - set and :code:`EmissionActivity` parameter. The :math:`EAC` parameter is - analogous to the efficiency table, tying emissions to a unit of activity. The - LimitEmission constraint allows the modeler to assign an upper bound per period - to each emission commodity. Note that this constraint sums emissions from - technologies with output varying at the time slice and those with constant annual - output in separate terms. - - .. math:: - :label: LimitEmission - - \sum_{S,D,I,T,V,O|{r,e,i,t,v,o} \in EAC} \left ( - EAC_{r, e, i, t, v, o} \cdot \textbf{FO}_{r, p, s, d, i, t, v, o} - \right ) & \\ - + - \sum_{I,T,V,O|{r,e,i,t \in T^{a},v,o} \in EAC} ( - EAC_{r, e, i, t, v, o} \cdot & \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} - ) - \le - ELM_{r, p, e} - - \\ - & \forall \{r, p, e\} \in \Theta_{\text{LimitEmission}} - - """ - emission_limit = value(M.LimitEmission[r, p, e, op]) - - # 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 - - regions = geography.gather_group_regions(M, r) - - # ================= Emissions and Flex and Curtailment ================= - # Flex flows are deducted from V_FlowOut, so it is NOT NEEDED to tax them again. (See commodity balance constr) - # Curtailment does not draw any inputs, so it seems logical that curtailed flows not be taxed either - - process_emissions = sum( - M.V_FlowOut[reg, p, S_s, S_d, S_i, S_t, S_v, S_o] - * value(M.EmissionActivity[reg, e, S_i, S_t, S_v, S_o]) - for reg in regions - for tmp_r, tmp_e, S_i, S_t, S_v, S_o in M.EmissionActivity.sparse_iterkeys() - if tmp_e == e and tmp_r == reg and S_t not in M.tech_annual - # EmissionsActivity not indexed by p, so make sure (r,p,t,v) combos valid - if (reg, p, S_t, S_v) in M.processInputs - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day - ) - - process_emissions_annual = sum( - M.V_FlowOutAnnual[reg, p, S_i, S_t, S_v, S_o] - * value(M.EmissionActivity[reg, e, S_i, S_t, S_v, S_o]) - for reg in regions - for tmp_r, tmp_e, S_i, S_t, S_v, S_o in M.EmissionActivity.sparse_iterkeys() - if tmp_e == e and tmp_r == reg and S_t in M.tech_annual - # EmissionsActivity not indexed by p, so make sure (r,p,t,v) combos valid - if (reg, p, S_t, S_v) in M.processInputs - ) - - embodied_emissions = sum( - M.V_NewCapacity[reg, t, v] - * value(M.EmissionEmbodied[reg, e, t, v]) - / value(M.PeriodLength[v]) - for reg in regions - for (S_r, S_e, t, v) in M.EmissionEmbodied.sparse_iterkeys() - if v == p and S_r == reg and S_e == e - ) - - retirement_emissions = sum( - M.V_AnnualRetirement[reg, p, t, v] * value(M.EmissionEndOfLife[reg, e, t, v]) - for reg in regions - for (S_r, S_e, t, v) in M.EmissionEndOfLife.sparse_iterkeys() - if (r, t, v) in M.retirementPeriods and p in M.retirementPeriods[r, t, v] - if S_r == reg and S_e == e - ) - - lhs = ( - process_emissions + process_emissions_annual + embodied_emissions + retirement_emissions - # + emissions_flex # NO! flex is subtracted from flowout, already accounted by flowout - # + emissions_curtail # NO! curtailed flows are not actual flows, just an accounting tool - # + emissions_flex_annual # NO! flexannual is subtracted from flowoutannual, already accounted - ) - expr = operator_expression(lhs, op, emission_limit) - - # in the case that there is nothing to sum, skip - if isinstance(expr, bool): # an empty list was generated - msg = "Warning: No technology produces emission '%s', though limit was specified as %s.\n" - logger.warning(msg, (e, emission_limit)) - SE.write(msg % (e, emission_limit)) - return Constraint.Skip - - return expr - - -def LimitGrowthCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): - r"""Constrain ramp up rate of available capacity""" - return LimitGrowthCapacity(M, r, p, t, op, False) - - -def LimitDegrowthCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): - r"""Constrain ramp down rate of available capacity""" - return LimitGrowthCapacity(M, r, p, t, op, True) - - -def LimitGrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): - r""" - Constrain the change of capacity available between periods. - Forces the model to ramp up and down the availability of new technologies - more smoothly. Has constant (seed, :math:`S_{r,t}`) and proportional - (rate, :math:`R_{r,t}`) terms. This can be defined for a technology group - instead of one technology, in which case, capacity available is summed over - all technologies in the group. In the first period, previous available - capacity :math:`\mathbf{CAPAVL}_{r,p,t}` is replaced by previous existing - capacity, if any can be found. - - .. math:: - :label: Limit (De)Growth Capacity - - \begin{aligned}\text{Growth:}\\ - &\mathbf{CAPAVL}_{r,p,t} - \leq S_{r,t} + (1+R_{r,t}) \cdot \mathbf{CAPAVL}_{r,p_{prev},t} - \end{aligned} - - \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitGrowthCapacity}} - - - \begin{aligned}\text{Degrowth:}\\ - &\mathbf{CAPAVL}_{r,p_{prev},t} - \leq S_{r,t} + (1+R_{r,t}) \cdot \mathbf{CAPAVL}_{r,p,t} - \end{aligned} - - \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitDegrowthCapacity}} - """ - - regions = geography.gather_group_regions(M, r) - techs = technology.gather_group_techs(M, t) - - growth = M.LimitDegrowthCapacity if degrowth else M.LimitGrowthCapacity - RATE = 1 + value(growth[r, t, op][0]) - SEED = value(growth[r, t, op][1]) - CapRPT = M.V_CapacityAvailableByPeriodAndTech - - # relevant r, p, t indices - cap_rpt = set((_r, _p, _t) for _r, _p, _t in CapRPT.keys() if _t in techs and _r in regions) - # periods the technology can have capacity in this region (sorted) - periods = sorted(set(_p for _r, _p, _t in cap_rpt)) - - if len(periods) == 0: - if p == M.time_optimize.first(): - msg = ( - 'Tried to set {}rowthCapacity constraint {} but there are no periods where this ' - 'technology is available in this region. Constraint skipped.' - ).format('Deg' if degrowth else 'G', (r, t)) - logger.warning(msg) - return Constraint.Skip - - # Only warn in p0 so we dont dump multiple warnings - if p == periods[0]: - if SEED == 0: - msg = ( - 'No constant term (seed) provided for {}rowthCapacity constraint {}. ' - 'No capacity will be built in any period following one with zero capacity.' - ).format('Deg' if degrowth else 'G', (r, t)) - logger.info(msg) - gaps = [ - _p for _p in M.time_optimize if _p not in periods and min(periods) < _p < max(periods) - ] - if gaps: - msg = ( - 'Constructing {}rowthCapacity constraint {} and there are period gaps in which' - 'capacity cannot exist in this region ({}). Capacity in these periods ' - 'will be treated as zero which may cause infeasibility or other problems.' - ).format('Deg' if degrowth else 'G', (r, t), gaps) - logger.warning(msg) - - # sum available capacity in this period - capacity = sum(CapRPT[_r, _p, _t] for _r, _p, _t in cap_rpt if _p == p) - - if p == M.time_optimize.first(): - # First future period. Grab available capacity in last existing period - # Adjust in-line for past PLF because we are constraining available capacity - p_prev = M.time_exist.last() - capacity_prev = sum( - value(M.ExistingCapacity[_r, _t, _v]) - * min(1.0, (_v + value(M.LifetimeProcess[_r, _t, _v]) - p_prev) / (p - p_prev)) - for _r, _t, _v in M.ExistingCapacity.sparse_iterkeys() - if _r in regions and _t in techs and _v + value(M.LifetimeProcess[_r, _t, _v]) > p_prev - ) - else: - # Otherwise, grab previous future period - p_prev = M.time_optimize.prev(p) - capacity_prev = sum(CapRPT[_r, _p, _t] for _r, _p, _t in cap_rpt if _p == p_prev) - - if degrowth: - expr = operator_expression(capacity_prev, op, SEED + capacity * RATE) - else: - expr = operator_expression(capacity, op, SEED + capacity_prev * RATE) - - # Check if any variables are actually included before returning - if isinstance(expr, bool): - return Constraint.Skip - return expr - - -def LimitGrowthNewCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): - r"""Constrain ramp up rate of new capacity deployment""" - return LimitGrowthNewCapacity(M, r, p, t, op, False) - - -def LimitDegrowthNewCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): - r"""Constrain ramp down rate of new capacity deployment""" - return LimitGrowthNewCapacity(M, r, p, t, op, True) - - -def LimitGrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): - r""" - Constrain the change of new capacity deployed between periods. - Forces the model to ramp up and down the deployment of new technologies - more smoothly. Has constant (seed, :math:`S_{r,t}`) and proportional - (rate, :math:`R_{r,t}`) terms. This can be defined for a technology group - instead of one technology, in which case, new capacity is summed over - all technologies in the group. In the first period, previous new capacity - :math:`\mathbf{NCAP}_{r,t,v_prev}` is replaced by previous existing capacity, - if any can be found. - - .. math:: - :label: Limit (De)Growth New Capacity - - \begin{aligned}\text{Growth:}\\ - &\mathbf{NCAP}_{r,t,v} - \leq S_{r,t} + (1+R_{r,t}) \cdot \mathbf{NCAP}_{r,t,v_{prev}} - \text{ where } v=p - \end{aligned} - - \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitGrowthCapacity}} - - \begin{aligned}\text{Degrowth:}\\ - &\mathbf{NCAP}_{r,t,v_{prev}} - \leq S_{r,t} + (1+R_{r,t}) \cdot \mathbf{NCAP}_{r,t,v} - \text{ where } v=p - \end{aligned} - - \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitDegrowthCapacity}} - """ - - regions = geography.gather_group_regions(M, r) - techs = technology.gather_group_techs(M, t) - - growth = M.LimitDegrowthNewCapacity if degrowth else M.LimitGrowthNewCapacity - RATE = 1 + value(growth[r, t, op][0]) - SEED = value(growth[r, t, op][1]) - NewCapRTV = M.V_NewCapacity - - # relevant r, t, v indices - cap_rtv = set((_r, _t, _v) for _r, _t, _v in NewCapRTV.keys() if _t in techs and _r in regions) - # periods the technology can be built in this region (sorted) - periods = sorted(set(_v for _r, _t, _v in cap_rtv)) - - if len(periods) == 0: - if p == M.time_optimize.first(): - msg = ( - 'Tried to set {}rowthNewCapacity constraint {} but there are no periods where this ' - 'technology can be built in this region. Constraint skipped.' - ).format('Deg' if degrowth else 'G', (r, t)) - logger.warning(msg) - return Constraint.Skip - - # Only warn in p0 so we dont dump multiple warnings - if p == periods[0]: - if SEED == 0: - msg = ( - 'No constant term (seed) provided for {}rowthNewCapacity constraint {}. ' - 'No capacity will be built in any period following one with zero new capacity.' - ).format('Deg' if degrowth else 'G', (r, t)) - logger.info(msg) - gaps = [ - _p for _p in M.time_optimize if _p not in periods and min(periods) < _p < max(periods) - ] - if gaps: - msg = ( - 'Constructing {}rowthNewCapacity constraint {} and there are period gaps in which' - 'new capacity cannot be built in this region ({}). New capacity in these periods ' - 'will be treated as zero which may cause infeasibility or other problems.' - ).format('Deg' if degrowth else 'G', (r, t), gaps) - logger.warning(msg) - - # sum new capacity in this period - new_cap = sum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p) - - if p == M.time_optimize.first(): - # First future period. Grab last existing vintage - p_prev = M.time_exist.last() - new_cap_prev = sum( - value(M.ExistingCapacity[_r, _t, _v]) - for _r, _t, _v in M.ExistingCapacity.sparse_iterkeys() - if _r in regions and _t in techs and _v == p_prev - ) - else: - # Otherwise, grab previous future vintage - p_prev = M.time_optimize.prev(p) - new_cap_prev = sum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p_prev) - - if degrowth: - expr = operator_expression(new_cap_prev, op, SEED + new_cap * RATE) - else: - expr = operator_expression(new_cap, op, SEED + new_cap_prev * RATE) - - # Check if any variables are actually included before returning - if isinstance(expr, bool): - return Constraint.Skip - return expr - - -def LimitGrowthNewCapacityDeltaConstraint_rule(M: 'TemoaModel', r, p, t, op): - r"""Constrain ramp up rate of change in new capacity deployment""" - return LimitGrowthNewCapacityDelta(M, r, p, t, op, False) - - -def LimitDegrowthNewCapacityDeltaConstraint_rule(M: 'TemoaModel', r, p, t, op): - r"""Constrain ramp down rate of change in new capacity deployment""" - return LimitGrowthNewCapacityDelta(M, r, p, t, op, True) - - -def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): - r""" - Constrain the acceleration of new capacity deployed between periods. - Forces the model to ramp up and down the change in deployment of new technologies - more smoothly. Has constant (seed, :math:`S_{r,t}`) and proportional - (rate, :math:`R_{r,t}`) terms. It is recommended to leave the rate term empty - as it would prevent the possibility of inflection in the rate of deployment. - This constraint can be defined for a technology group instead of one technology, - in which case, new capacity is summed over all technologies in the group. In the - first period, previous new capacities are replaced by previous existing capacities, - if any can be found. - - .. math:: - :label: Limit (De)Growth New Capacity Delta - - \begin{aligned}\text{Growth:}\\ - &\mathbf{NCAP}_{r,t,v_i} - \mathbf{NCAP}_{r,t,v_{i-1}} - \leq S_{r,t} + (1+R_{r,t}) \cdot (\mathbf{NCAP}_{r,t,v_{i-1}} - \mathbf{NCAP}_{r,t,v_{i-2}}) - \end{aligned} - - \text{ where } v_i=p - - \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitGrowthCapacityDelta}} - - \begin{aligned}\text{Degrowth:}\\ - &\mathbf{NCAP}_{r,t,v_{i-1}} - \mathbf{NCAP}_{r,t,v_{i-2}} - \leq S_{r,t} + (1+R_{r,t}) \cdot (\mathbf{NCAP}_{r,t,v_i} - \mathbf{NCAP}_{r,t,v_{i-1}}) - \end{aligned} - - \text{ where } v_i=p - - \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitDegrowthCapacityDelta}} - """ - - regions = geography.gather_group_regions(M, r) - techs = technology.gather_group_techs(M, t) - - growth = M.LimitDegrowthNewCapacityDelta if degrowth else M.LimitGrowthNewCapacityDelta - RATE = 1 + value(growth[r, t, op][0]) - SEED = value(growth[r, t, op][1]) - NewCapRTV = M.V_NewCapacity - - # relevant r, t, v indices - cap_rtv = set((_r, _t, _v) for _r, _t, _v in NewCapRTV.keys() if _t in techs and _r in regions) - # periods the technology can be built in this region (sorted) - periods = sorted(set(_v for _r, _t, _v in cap_rtv)) - - if len(periods) == 0: - if p == M.time_optimize.first(): - msg = ( - 'Tried to set {}rowthNewCapacityDelta constraint {} but there are no periods where this ' - 'technology can be built in this region. Constraint skipped.' - ).format('Deg' if degrowth else 'G', (r, t)) - logger.warning(msg) - return Constraint.Skip - - # Only warn in p0 so we dont dump multiple warnings - if p == periods[0]: - if SEED == 0: - msg = ( - 'No constant term (seed) provided for {}rowthNewCapacityDelta constraint {}. ' - 'This is not recommended as deployment rates cannot inflect (change from ' - 'accelerating to decelerating or vice-versa).' - ).format('Deg' if degrowth else 'G', (r, t)) - logger.warning(msg) - gaps = [ - _p for _p in M.time_optimize if _p not in periods and min(periods) < _p < max(periods) - ] - if gaps: - msg = ( - 'Constructing {}rowthNewCapacityDelta constraint {} and there are period gaps in which' - 'new capacity cannot be built in this region ({}). New capacity in these periods ' - 'will be treated as zero which may cause infeasibility or other problems.' - ).format('Deg' if degrowth else 'G', (r, t), gaps) - logger.warning(msg) - - # sum new capacity in this period - new_cap = sum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p) - - if p == M.time_optimize.first(): - # First planning period, pull last two existing vintages - p_prev = M.time_exist.last() - new_cap_prev = sum( - value(M.ExistingCapacity[_r, _t, _v]) - for _r, _t, _v in M.ExistingCapacity.sparse_iterkeys() - if _r in regions and _t in techs and _v == p_prev - ) - p_prev2 = M.time_exist.prev(p_prev) - new_cap_prev2 = sum( - value(M.ExistingCapacity[_r, _t, _v]) - for _r, _t, _v in M.ExistingCapacity.sparse_iterkeys() - if _r in regions and _t in techs and _v == p_prev2 - ) - else: - # Not the first future period. Grab previous future period - p_prev = M.time_optimize.prev(p) - new_cap_prev = sum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p_prev) - if p == M.time_optimize.at(2): # apparently pyomo sets are indexed 1-based - # Second future period, grab last existing vintage - p_prev2 = M.time_exist.last() - new_cap_prev2 = sum( - value(M.ExistingCapacity[_r, _t, _v]) - for _r, _t, _v in M.ExistingCapacity.sparse_iterkeys() - if _r in regions and _t in techs and _v == p_prev2 - ) - else: - # At least the third future period. Grab last two future vintages - p_prev2 = M.time_optimize.prev(p_prev) - new_cap_prev2 = sum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p_prev2) - - nc_delta_prev = new_cap_prev - new_cap_prev2 - nc_delta = new_cap - new_cap_prev - - if degrowth: - expr = operator_expression(nc_delta_prev, op, SEED + nc_delta * RATE) - else: - expr = operator_expression(nc_delta, op, SEED + nc_delta_prev * RATE) - - # Check if any variables are actually included before returning - if isinstance(expr, bool): - return Constraint.Skip - return expr - - -def LimitActivity_Constraint(M: 'TemoaModel', r, p, t, op): - r""" - - Sets a limit on the activity from a specific technology. - Note that the indices for these constraints are region, period and tech, not tech - and vintage. The first version of the constraint pertains to technologies with - variable output at the time slice level, and the second version pertains to - technologies with constant annual output belonging to the :code:`tech_annual` - set. - - .. math:: - :label: LimitActivity - - \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} - - \forall \{r, p, t \notin T^{a}\} \in \Theta_{\text{LimitActivity}} - - +\sum_{I,V,O} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} - - \forall \{r, p, t \in T^{a}\} \in \Theta_{\text{LimitActivity}} - - \le LA_{r, p, t} - """ - # r can be an individual region (r='US'), or a combination of regions separated by - # a + (r='Mexico+US+Canada'), or 'global'. - # if r == 'global', the constraint is system-wide - regions = geography.gather_group_regions(M, r) - techs = technology.gather_group_techs(M, t) - - activity = sum( - M.V_FlowOut[_r, p, s, d, S_i, _t, S_v, S_o] - for _t in techs - if _t not in M.tech_annual - for _r in regions - for S_v in M.processVintages.get((_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.TimeSeason[p] - for d in M.time_of_day - ) - activity += sum( - M.V_FlowOutAnnual[_r, p, S_i, _t, S_v, S_o] - for _t in techs - if _t in M.tech_annual - for _r in regions - for S_v in M.processVintages.get((_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] - ) - - act_lim = value(M.LimitActivity[r, p, t, op]) - expr = operator_expression(activity, op, act_lim) - # in the case that there is nothing to sum, skip - if isinstance(expr, bool): # an empty list was generated - return Constraint.Skip - return expr - - -def LimitNewCapacity_Constraint(M: 'TemoaModel', r, p, t, op): - r""" - The LimitNewCapacity constraint sets a limit on the newly installed capacity of a - given technology or group in a given year. Note that the indices for these constraints are region, - period and tech. - - .. math:: - :label: LimitNewCapacity - - \textbf{NCAP}_{r, t, v} \le LNC_{r, p, t} - - \text{where }v=p - """ - regions = geography.gather_group_regions(M, r) - techs = technology.gather_group_techs(M, t) - cap_lim = value(M.LimitNewCapacity[r, p, t, op]) - new_cap = sum(M.V_NewCapacity[_r, _t, p] for _t in techs for _r in regions) - expr = operator_expression(new_cap, op, cap_lim) - return expr - - -def LimitCapacity_Constraint(M: 'TemoaModel', r, p, t, op): - r""" - - The LimitCapacity constraint sets a limit on the available capacity of a - given technology. Note that the indices for these constraints are region, period and - tech, not tech and vintage. - - .. math:: - :label: LimitCapacity - - \textbf{CAPAVL}_{r, p, t} \le LC_{r, p, t} - - \forall \{r, p, t\} \in \Theta_{\text{LimitCapacity}}""" - regions = geography.gather_group_regions(M, r) - techs = technology.gather_group_techs(M, t) - cap_lim = value(M.LimitCapacity[r, p, t, op]) - capacity = sum( - M.V_CapacityAvailableByPeriodAndTech[_r, p, _t] for _t in techs for _r in regions - ) - expr = operator_expression(capacity, op, cap_lim) - return expr - - -def LimitResource_Constraint(M: 'TemoaModel', r, t, op): - r""" - - The LimitResource constraint sets a limit on the available resource of a - given technology across all model time periods. Note that the indices for these - constraints are region and tech. - - .. math:: - :label: LimitResource - - \sum_{P,S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t \notin T^a, v, o} - - +\sum_{P,I,V,O} \textbf{FO}_{r, p, i, t \in T^a, v, o} - - \le LR_{r, t} - - \forall \{r, t\} \in \Theta_{\text{LimitResource}}""" - # dev note: this constraint is a misnomer. It is actually a "global activity constraint on a tech" - # regardless of whatever "resources" are consumed. - # dev note: this would generally be applied to a "dummy import" technology to restrict something like - # oil/mineral extraction across all model periods. Looks fine to me. - - regions = geography.gather_group_regions(M, r) - techs = technology.gather_group_techs(M, t) - - activity = sum( - M.V_FlowOutAnnual[_r, p, S_i, _t, S_v, S_o] - for _t in techs - if _t in M.tech_annual - for p in M.time_optimize - for _r in regions - if (_r, p, _t) in M.processVintages - 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] - ) - activity += sum( - M.V_FlowOut[_r, p, s, d, S_i, _t, S_v, S_o] - for _t in techs - if _t not in M.tech_annual - for p in M.time_optimize - for _r in regions - if (_r, p, _t) in M.processVintages - 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.TimeSeason[p] - for d in M.time_of_day - ) - - resource_lim = value(M.LimitResource[r, t, op]) - expr = operator_expression(activity, op, resource_lim) - return expr - - -def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): - r""" - Limits the activity of a given technology or group as a fraction of another - technology or group, summed over a period. This can be used to set, for example, - a renewable portfolio scheme constraint. - - .. math:: - :label: Limit Activity Share - - \sum_{R_g \subseteq R,\ S,\ D,\ I,\ T^{g_1} \subseteq T,\ V,\ O} \mathbf{FO}_{r,p,s,d,i,t,v,o} - \leq LAS_{r,p,g_1,g_2} \cdot - \sum_{R_g \subseteq R,\ S,\ D,\ I,\ T^{g_2} \subseteq T,\ V,\ O} \mathbf{FO}_{r,p,s,d,i,t,v,o} - - \qquad \forall \{r, p, g_1, g_2\} \in \Theta_{\text{LimitActivityShare}} - """ - - regions = geography.gather_group_regions(M, r) - - sub_group = technology.gather_group_techs(M, g1) - sub_activity = sum( - M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] - for S_t in sub_group - if S_t not in M.tech_annual - for _r in regions - for S_v in M.processVintages.get((_r, p, S_t), []) - for S_i in M.processInputs[_r, p, S_t, S_v] - for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - sub_activity += sum( - M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] - for S_t in sub_group - if S_t in M.tech_annual - for _r in regions - for S_v in M.processVintages.get((_r, p, S_t), []) - for S_i in M.processInputs[_r, p, S_t, S_v] - for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - ) - - super_group = technology.gather_group_techs(M, g2) - super_activity = sum( - M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] - for S_t in super_group - if S_t not in M.tech_annual - for _r in regions - for S_v in M.processVintages.get((_r, p, S_t), []) - for S_i in M.processInputs[_r, p, S_t, S_v] - for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - super_activity += sum( - M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] - for S_t in super_group - if S_t in M.tech_annual - for _r in regions - for S_v in M.processVintages.get((_r, p, S_t), []) - for S_i in M.processInputs[_r, p, S_t, S_v] - for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - ) - - share_lim = value(M.LimitActivityShare[r, p, g1, g2, op]) - expr = operator_expression(sub_activity, op, share_lim * super_activity) - # in the case that there is nothing to sum, skip - if isinstance(expr, bool): # an empty list was generated - return Constraint.Skip - logger.debug( - 'created limit activity share constraint for (%s, %d, %s, %s) of %0.2f', - r, - p, - g1, - g2, - share_lim, - ) - return expr - - -def LimitCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): - r""" - The LimitCapacityShare constraint limits the available capacity of a given - technology or technology group as a fraction of another technology or group. - """ - - regions = geography.gather_group_regions(M, r) - - sub_group = technology.gather_group_techs(M, g1) - sub_capacity = sum( - M.V_CapacityAvailableByPeriodAndTech[_r, p, _t] - for _t in sub_group - for _r in regions - if (_r, p, _t) in M.processVintages - ) - - super_group = technology.gather_group_techs(M, g2) - super_capacity = sum( - M.V_CapacityAvailableByPeriodAndTech[_r, p, _t] - for _t in super_group - for _r in regions - if (_r, p, _t) in M.processVintages - ) - share_lim = value(M.LimitCapacityShare[r, p, g1, g2, op]) - - expr = operator_expression(sub_capacity, op, share_lim * super_capacity) - if isinstance(expr, bool): - return Constraint.Skip - return expr - - -def LimitNewCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): - r""" - The LimitNewCapacityShare constraint limits the share of new capacity - of a given technology or group as a fraction of another technology or - group.""" - - regions = geography.gather_group_regions(M, r) - - sub_group = technology.gather_group_techs(M, g1) - sub_new_cap = sum( - M.V_NewCapacity[_r, _t, p] - for _t in sub_group - for _r in regions - if (_r, _t, p) in M.processPeriods - ) - - super_group = technology.gather_group_techs(M, g2) - super_new_cap = sum( - M.V_NewCapacity[_r, _t, p] - for _t in super_group - for _r in regions - if (_r, _t, p) in M.processPeriods - ) - - share_lim = value(M.LimitNewCapacityShare[r, p, g1, g2, op]) - expr = operator_expression(sub_new_cap, op, share_lim * super_new_cap) - if isinstance(expr, bool): - return Constraint.Skip - return expr - - -def LimitAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o, op): - r""" - The LimitAnnualCapacityFactor 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: LimitAnnualCapacityFactor - - \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMACF_{r, p, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} - - \forall \{r, p, t \notin T^{a}, o\} \in \Theta_{\text{LimitAnnualCapacityFactor}} - - \\\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \ge LIMACF_{r, p, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} - - \forall \{r, p, t \in T^{a}, o\} \in \Theta_{\text{LimitAnnualCapacityFactor}} - """ - # r can be an individual region (r='US'), or a combination of regions separated by plus (r='Mexico+US+Canada'), or 'global'. - # if r == 'global', the constraint is system-wide - regions = geography.gather_group_regions(M, r) - # we need to screen here because it is possible that the restriction extends beyond the - # lifetime of any vintage of the tech... - if all((_r, p, t) not in M.V_CapacityAvailableByPeriodAndTech for _r in regions): - return Constraint.Skip - - if t not in M.tech_annual: - activity_rpt = sum( - M.V_FlowOut[_r, p, s, d, S_i, t, S_v, o] - for _r in regions - for S_v in M.processVintages.get((_r, p, t), []) - for S_i in M.processInputs[_r, p, t, S_v] - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - else: - activity_rpt = sum( - M.V_FlowOutAnnual[_r, p, S_i, t, S_v, o] - for _r in regions - for S_v in M.processVintages.get((_r, p, t), []) - for S_i in M.processInputs[_r, p, t, S_v] - ) - - possible_activity_rpt = sum( - M.V_CapacityAvailableByPeriodAndTech[_r, p, t] * value(M.CapacityToActivity[_r, t]) - for _r in regions - ) - annual_cf = value(M.LimitAnnualCapacityFactor[r, p, t, o, op]) - expr = operator_expression(activity_rpt, op, annual_cf * possible_activity_rpt) - # in the case that there is nothing to sum, skip - if isinstance(expr, bool): # an empty list was generated - return Constraint.Skip - return expr - - -def LimitSeasonalCapacityFactor_Constraint(M: 'TemoaModel', r, p, s, t, op): - r""" - The LimitSeasonalCapacityFactor sets an upper bound on the seasonal 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: Limit Seasonal Capacity Factor - - \sum_{D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMSCF_{r, p, s, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} - - \forall \{r, p, t \notin T^{a}, o\} \in \Theta_{\text{LimitSeasonalCapacityFactor}} - - \\\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \cdot \sum_{D} SEG_{s,d} \le LIMSCF_{r, p, s, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} - - \forall \{r, p, t \in T^{a}, o\} \in \Theta_{\text{LimitSeasonalCapacityFactor}} - """ - # r can be an individual region (r='US'), or a combination of regions separated by plus (r='Mexico+US+Canada'), or 'global'. - # if r == 'global', the constraint is system-wide - regions = geography.gather_group_regions(M, r) - # we need to screen here because it is possible that the restriction extends beyond the - # lifetime of any vintage of the tech... - if all((_r, p, t) not in M.V_CapacityAvailableByPeriodAndTech for _r in regions): - return Constraint.Skip - - if t not in M.tech_annual: - activity_rpst = sum( - M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] - for _r in regions - 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 d in M.time_of_day - ) - else: - activity_rpst = sum( - M.V_FlowOutAnnual[_r, p, S_i, t, S_v, S_o] * M.SegFracPerSeason[p, s] - for _r in regions - 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] - ) - - possible_activity_rpst = sum( - M.V_CapacityAvailableByPeriodAndTech[_r, p, t] - * value(M.CapacityToActivity[_r, t]) - * value(M.SegFracPerSeason[p, s]) - for _r in regions - ) - seasonal_cf = value(M.LimitSeasonalCapacityFactor[r, p, s, t, op]) - expr = operator_expression(activity_rpst, op, seasonal_cf * possible_activity_rpst) - # in the case that there is nothing to sum, skip - if isinstance(expr, bool): # an empty list was generated - return Constraint.Skip - return expr - - -def LimitTechInputSplit_Constraint(M: 'TemoaModel', r, p, s, d, i, t, v, op): - r""" - Allows users to limit shares of commodity inputs to a process - producing a single output. These shares can vary by model time period. See - LimitTechOutputSplit_Constraint for an analogous explanation. Under this constraint, - only the technologies with variable output at the timeslice level (i.e., - NOT in the :code:`tech_annual` set) are considered.""" - inp = sum( - M.V_FlowOut[r, p, s, d, i, t, v, S_o] / get_variable_efficiency(M, r, p, s, d, i, t, v, S_o) - for S_o in M.processOutputsByInput[r, p, t, v, i] - ) - - total_inp = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - / get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - - expr = operator_expression(inp, op, value(M.LimitTechInputSplit[r, p, i, t, op]) * total_inp) - return expr - - -def LimitTechInputSplitAnnual_Constraint(M: 'TemoaModel', r, p, i, t, v, op): - r""" - Allows users to limit shares of commodity inputs to a process - producing a single output. These shares can vary by model time period. See - LimitTechOutputSplitAnnual_Constraint for an analogous explanation. Under this - function, only the technologies with constant annual output (i.e., members - of the :code:`tech_annual` set) are considered.""" - inp = sum( - M.V_FlowOutAnnual[r, p, i, t, v, S_o] / value(M.Efficiency[r, i, t, v, S_o]) - for S_o in M.processOutputsByInput[r, p, t, v, i] - ) - - total_inp = sum( - M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] / value(M.Efficiency[r, S_i, t, v, S_o]) - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - - expr = operator_expression( - inp, op, value(M.LimitTechInputSplitAnnual[r, p, i, t, op]) * total_inp - ) - return expr - - -def LimitTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v, op): - r""" - Allows users to limit shares of commodity inputs to a process - 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 LimitTechInputSplit 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.""" - - inp = sum( - M.V_FlowOut[r, p, S_s, S_d, i, t, v, S_o] - / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day - for S_o in M.processOutputsByInput[r, p, t, v, i] - ) - - total_inp = sum( - M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] - / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, i] - ) - - expr = operator_expression( - inp, op, value(M.LimitTechInputSplitAnnual[r, p, i, t, op]) * total_inp - ) - return expr - - -def LimitTechOutputSplit_Constraint(M: 'TemoaModel', r, p, s, d, t, v, o, op): - r""" - - Some processes take a single input and make multiple outputs, and the user would like to - specify either a constant or time-varying ratio of outputs per unit input. The most - canonical example is an oil refinery. Crude oil is used to produce many different refined - products. In many cases, the modeler would like to limit the share of each refined - product produced by the refinery. - - For example, a hypothetical (and highly simplified) refinery might have a crude oil input - that produces 4 parts diesel, 3 parts gasoline, and 2 parts kerosene. The relative - ratios to the output then are: - - .. math:: - - d = \tfrac{4}{9} \cdot \text{total output}, \qquad - g = \tfrac{3}{9} \cdot \text{total output}, \qquad - k = \tfrac{2}{9} \cdot \text{total output} - - Note that it is possible to specify output shares that sum to less than unity. In such - cases, the model optimizes the remaining share. In addition, it is possible to change the - specified shares by model time period. Under this constraint, only the - technologies with variable output at the timeslice level (i.e., NOT in the - :code:`tech_annual` set) are considered. - - The constraint is formulated as follows: - - .. math:: - :label: LimitTechOutputSplit - - \sum_{I, t \not \in T^{a}} \textbf{FO}_{r, p, s, d, i, t, v, o} - \geq - TOS_{r, p, t, o} \cdot \sum_{I, O, t \not \in T^{a}} \textbf{FO}_{r, p, s, d, i, t, v, o} - - \forall \{r, p, s, d, t, v, o\} \in \Theta_{\text{LimitTechOutputSplit}}""" - out = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, o] for S_i in M.processInputsByOutput[r, p, t, v, o] - ) - - total_out = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - - expr = operator_expression(out, op, value(M.LimitTechOutputSplit[r, p, t, o, op]) * total_out) - return expr - - -def LimitTechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o, op): - r""" - This constraint operates similarly to LimitTechOutputSplit_Constraint. - However, under this function, only the technologies with constant annual - output (i.e., members of the :code:`tech_annual` set) are considered. - - .. math:: - :label: LimitTechOutputSplitAnnual - - \sum_{I, T^{a}} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} - \geq - TOS_{r, p, t, o} \cdot \sum_{I, O, T^{a}} \textbf{FOA}_{r, p, s, d, i, t \in T^{a}, v, o} - - \forall \{r, p, t \in T^{a}, v, o\} \in \Theta_{\text{LimitTechOutputSplitAnnual}}""" - out = sum( - M.V_FlowOutAnnual[r, p, S_i, t, v, o] for S_i in M.processInputsByOutput[r, p, t, v, o] - ) - - total_out = sum( - M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - - expr = operator_expression( - out, op, value(M.LimitTechOutputSplitAnnual[r, p, t, o, op]) * total_out - ) - return expr - - -def LimitTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o, op): - r""" - Allows users to limit shares of commodity outputs from a process. - 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 LimitTechOutputSplit 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 output shares over the course of a year.""" - - out = sum( - M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, o] - for S_i in M.processInputsByOutput[r, p, t, v, o] - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day - ) - - total_out = sum( - M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day - ) - - expr = operator_expression( - out, op, value(M.LimitTechOutputSplitAnnual[r, p, t, o, op]) * total_out - ) - return expr - - -# @deprecated('Deprecated. Use LimitActivityGroupShare instead') # doesn't play well with pyomo -def RenewablePortfolioStandard_Constraint(M: 'TemoaModel', r, p, g): - r""" - Allows users to specify the share of electricity generation in a region - coming from RPS-eligible technologies. - """ - # devnote: this formulation leans on the reserve set, which is not necessarily - # the super set we want. We can also generalise this to all groups and so - # it has been deprecated in favour of the LimitActivityGroupShare constraint. - - inp = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for t in M.tech_group_members[g] - for (_t, v) in M.processReservePeriods[r, p] - if _t == t - for s in M.TimeSeason[p] - for d in M.time_of_day - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - - total_inp = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for (t, v) in M.processReservePeriods[r, p] - for s in M.TimeSeason[p] - for d in M.time_of_day - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - - expr = inp >= (value(M.RenewablePortfolioStandard[r, p, g]) * total_inp) - return expr - - -# --------------------------------------------------------------- -# Define rule-based parameters -# --------------------------------------------------------------- -# devnote: MPL no longer used. Instead, use adjusted capacity * period length -# def ParamModelProcessLife_rule(M: 'TemoaModel', r, p, t, v): -# life_length = value(M.LifetimeProcess[r, t, v]) -# mpl = min(v + life_length - p, value(M.PeriodLength[p])) - -# return mpl - - -def ParamPeriodLength(M: 'TemoaModel', p): - # This specifically does not use time_optimize because this function is - # called /over/ time_optimize. - periods = sorted(M.time_future) - - i = periods.index(p) - - # The +1 won't fail, because this rule is called over time_optimize, which - # lacks the last period in time_future. - length = periods[i + 1] - periods[i] - - return length - - -def ParamProcessLifeFraction_rule(M: 'TemoaModel', r, p, t, v): - r""" - Get the effective capacity of a process :math:`` in a period :math:`p`. - - Accounts for mid-period end of life or average survival over the period - for processes using survival curves. - """ - - period_length = value(M.PeriodLength[p]) - - if M.isSurvivalCurveProcess[r, t, v]: - # Sum survival fraction over the period - years_remaining = sum( - value(M.LifetimeSurvivalCurve[r, _p, t, v]) for _p in range(p, p + period_length, 1) - ) - else: - # Remaining life years within the EOL period - years_remaining = v + value(M.LifetimeProcess[r, t, v]) - p - - if years_remaining >= period_length: - # try to avoid floating point round-off errors for the common case. - return 1 - - frac = years_remaining / float(period_length) - return frac - - -# devnote: made redundant by time-value equations for objective function -# def loan_annualization_rate(loan_rate: float | None, loan_life: int | float) -> float: -# """ -# This calculation is broken out specifically so that it can be used for param creation -# and separately to calculate loan costs rather than rely on fully-built model parameters -# :param loan_rate: -# :param loan_life: - -# """ -# if not loan_rate: -# # dev note: this should not be needed as the LoanRate param has a default (see the definition) -# return 1.0 / loan_life -# annualized_rate = loan_rate / (1.0 - (1.0 + loan_rate) ** (-loan_life)) -# return annualized_rate - - -def ParamLoanAnnualize_rule(M: 'TemoaModel', r, t, v): - dr = value(M.LoanRate[r, t, v]) - lln = value(M.LoanLifetimeProcess[r, t, v]) - annualized_rate = pv_to_annuity(dr, lln) - return annualized_rate - - -def SegFracPerSeason_rule(M: 'TemoaModel', p, s): - return sum(value(M.SegFrac[p, s, S_d]) for S_d in M.time_of_day if (p, s, S_d) in M.SegFrac) - - -def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): - r""" - This constraint is necessary for carbon capture technologies that produce - CO2 as an emissions commodity, but the CO2 also serves as a physical - input commodity to a downstream process, such as synthetic fuel production. - To accomplish this, a dummy technology is linked to the CO2-producing - technology, converting the emissions activity into a physical commodity - amount as follows: - - .. math:: - :label: LinkedEmissionsTech - - - \sum_{I, O} \textbf{FO}_{r, p, s, d, i, t, v, o} \cdot EAC_{r, e, i, t, v, o} - = \sum_{I, O} \textbf{FO}_{r, p, s, d, i, t, v, o} - - \forall \{r, p, s, d, t, v, e\} \in \Theta_{\text{LinkedTechs}} - - The relationship between the primary and linked technologies is given - 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. - """ - - if t in M.tech_annual: - primary_flow = sum( - ( - value(M.DemandSpecificDistribution[r, p, s, d, S_o]) - if S_o in M.commodity_demand - else value(M.SegFrac[p, s, d]) - ) - * M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] - * value(M.EmissionActivity[r, e, S_i, t, v, S_o]) - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - else: - primary_flow = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - * value(M.EmissionActivity[r, e, S_i, t, v, S_o]) - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - - linked_t = M.LinkedTechs[r, t, e] - - # linked_flow = sum( - # M.V_FlowOut[r, p, s, d, S_i, linked_t, v, S_o] - # for S_i in M.processInputs[r, p, linked_t, v] - # for S_o in M.processOutputsByInput[r, p, linked_t, v, S_i] - # ) - - if linked_t in M.tech_annual: - linked_flow = sum( - ( - value(M.DemandSpecificDistribution[r, p, s, d, S_o]) - if S_o in M.commodity_demand - else value(M.SegFrac[p, s, d]) - ) - * M.V_FlowOutAnnual[r, p, S_i, linked_t, v, S_o] - for S_i in M.processInputs[r, p, linked_t, v] - for S_o in M.processOutputsByInput[r, p, linked_t, v, S_i] - ) - else: - linked_flow = sum( - M.V_FlowOut[r, p, s, d, S_i, linked_t, v, S_o] - for S_i in M.processInputs[r, p, linked_t, v] - for S_o in M.processOutputsByInput[r, p, linked_t, v, S_i] - ) - - return -primary_flow == linked_flow - - -def operator_expression(lhs: Expression | None, operator: str | None, rhs: Expression | None): - """Returns an expression, applying a configured operator""" - if any((lhs is None, operator is None, rhs is None)): - msg = ('Tried to build a constraint using a bad expression or operator: {} {} {}').format( - lhs, operator, rhs - ) - logger.error(msg) - raise ValueError(msg) - try: - match operator: - case 'e': - expr = lhs == rhs - case 'le': - expr = lhs <= rhs - case 'ge': - expr = lhs >= rhs - case _: - msg = ( - 'Tried to build a constraint using a bad operator. Allowed operators are "e","le", or "ge". Got "{}": {} {} {}' - ).format(operator, lhs, operator, rhs) - logger.error(msg) - raise ValueError(msg) - except Exception as e: - print(e) - msg = ('Tried to build a constraint using a bad expression or operator: {} {} {}').format( - lhs, operator, rhs - ) - logger.error(msg) - raise ValueError(msg) from e - - return expr - - -# To avoid building big many-indexed parameters when they aren't needed - saves memory -# Much faster to build a dictionary and check that than check the parameter -# indices directly every time - saves build time -def get_variable_efficiency(M: 'TemoaModel', r, p, s, d, i, t, v, o): - if M.isEfficiencyVariable[r, p, i, t, v, o]: - return value(M.Efficiency[r, i, t, v, o]) * value( - M.EfficiencyVariable[r, p, s, d, i, t, v, o] - ) - else: - return value(M.Efficiency[r, i, t, v, o]) - - -def get_capacity_factor(M: 'TemoaModel', r, p, s, d, t, v): - if M.isCapacityFactorProcess[r, p, t, v]: - return value(M.CapacityFactorProcess[r, p, s, d, t, v]) - else: - return value(M.CapacityFactorTech[r, p, s, d, t]) diff --git a/temoa/components/capacity.py b/temoa/components/capacity.py index aa73e45b7..0fd54c5f9 100644 --- a/temoa/components/capacity.py +++ b/temoa/components/capacity.py @@ -209,3 +209,301 @@ def RegionalExchangeCapacityConstraintIndices(M: 'TemoaModel'): ) return indices + + +def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): + r""" + This constraint updates the capacity of a process by taking into account retirements + and end of life. For a given :code:`(r,p,t,v)` index, this constraint sets the capacity + equal to the amount installed in period :code:`v` and subtracts from it any and all retirements + that occurred prior to the period in question, :code:`p`, and end of life from the + survival curve if defined. It finally adjusts for the process life fraction, which + accounts for a possible mid-period end of life where, for example, EOL 3 years into a 5-year + period would be treated as :math:`\frac{3}{5}` capacity for all 5 years. + + .. figure:: images/adjusted_capacity_plf.* + :align: center + :width: 100% + :figclass: align-center + :figwidth: 50% + + For processes reaching end of life mid-period, the process life fraction adjustment is applied, + distributing the effective capacity over the whole period. + + For processes using survival curves, the yearly survival curve :math:`\text{LSC}_{r,p,t,v}` is + averaged over the period to get the effective remaining capacity for that period Because this + implicitly handles mid-period end of life, :math:`\text{PLF}_{r,p,t,v}` is used to account for both + phenomena. + + .. figure:: images/adjusted_capacity_sc.* + :align: center + :width: 100% + :figclass: align-center + :figwidth: 50% + + For processes with a defined survival curve, the surviving capacity is averaged over each + period to get the adjusted capacity. This implicitly handles mid-period end of life as a + survival curve will always be zero after the end of life of a process. + + .. math:: + :label: Adjusted Capacity + + \textbf{CAP}_{r,p,t,v} = + \begin{cases} + \text{PLF}_{r,p,t,v} \cdot + \left( + \text{ECAP}_{r,t,v} - \sum\limits_{v < p' <= p} + \frac{\textbf{RCAP}_{r,p',t,v}}{\text{LSC}_{r,p',t,v}} + \right) + & \text{if } \ v \in T^e \\ + \text{PLF}_{r,p,t,v} \cdot + \left( + \textbf{NCAP}_{r,t,v} - \sum\limits_{v < p' <= p} + \frac{\textbf{RCAP}_{r,p',t,v}}{\text{LSC}_{r,p',t,v}} + \right) + & \text{if } \ v \notin T^e + \end{cases} + + \\\text{where } + \text{PLF}_{r,p,t,v} = + \begin{cases} + \frac{1}{\text{LEN}_p} \cdot \left( + \sum\limits_{y = p}^{p+\text{LEN}_{p}-1}{\text{LSC}_{r,y,t,v}} + \right) + & \text{if } t \in T^{sc} \\ + \frac{1}{\text{LEN}_p} \cdot \left( v + \text{LTP}_{r,t,v} - p \right) + & \text{if } t \notin T^{sc} \\ + \end{cases} + + We divide :math:`\frac{\textbf{RCAP}_{r,p',t,v}}{\text{LSC}_{r,p',t,v}}` + because the average survival factor in :math:`\text{PLF}_{r,p,t,v}` is indexed to the vintage + period (the beginning of the survival curve). So, we adjust for the relative survival from + the time when that retirement occurred (treated here as at the beginning of each period). + """ + + if v in M.time_exist: + built_capacity = value(M.ExistingCapacity[r, t, v]) + else: + built_capacity = M.V_NewCapacity[r, t, v] + + early_retirements = 0 + if t in M.tech_retirement: + early_retirements = sum( + M.V_RetiredCapacity[r, S_p, t, v] / value(M.LifetimeSurvivalCurve[r, S_p, t, v]) + for S_p in M.time_optimize + if v < S_p <= p + and S_p < v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[S_p]) + ) + + remaining_capacity = (built_capacity - early_retirements) * value(M.ProcessLifeFrac[r, p, t, v]) + return M.V_Capacity[r, p, t, v] == remaining_capacity + + +def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): + r""" + This constraint ensures that the capacity of a given process is sufficient + to support its activity across all time periods and time slices. The calculation + on the left hand side of the equality is the maximum amount of energy a process + can produce in the timeslice :code:`(s,d)`. Note that the curtailment variable + shown below only applies to technologies that are members of the curtailment set. + Curtailment is necessary to track explicitly in scenarios that include a high + renewable target. Without it, the model can generate more activity than is used + to meet demand, and have all activity (including the portion curtailed) count + towards the target. Tracking activity and curtailment separately prevents this + possibility. + + .. math:: + :label: Capacity + + \left ( + \text{CFP}_{r, p, s, d, t, v} + \cdot \text{C2A}_{r, t} + \cdot \text{SEG}_{s, d} + \right ) + \cdot \textbf{CAP}_{r, t, v} + = + \sum_{I, O} \textbf{FO}_{r, p, s, d, i, t, v, o} + + + \sum_{I, O} \textbf{CUR}_{r, p, s, d, i, t, v, o} + + \\ + \forall \{r, p, s, d, t, v\} \in \Theta_{\text{FO}} + """ + # The expressions below are defined in-line to minimize the amount of + # expression cloning taking place with Pyomo. + + if t in M.tech_annual: + # Annual demand technology + useful_activity = sum( + ( + value(M.DemandSpecificDistribution[r, p, s, d, S_o]) + if S_o in M.commodity_demand + else value(M.SegFrac[p, s, d]) + ) + * M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + else: + useful_activity = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + + if t in M.tech_curtailment: + # If technologies are present in the curtailment set, then enough + # capacity must be available to cover both activity and curtailment. + return get_capacity_factor(M, r, p, s, d, t, v) * value(M.CapacityToActivity[r, t]) * value( + M.SegFrac[p, s, d] + ) * M.V_Capacity[r, p, t, v] == useful_activity + sum( + M.V_Curtailment[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + else: + return ( + get_capacity_factor(M, r, p, s, d, t, v) + * value(M.CapacityToActivity[r, t]) + * value(M.SegFrac[p, s, d]) + * M.V_Capacity[r, p, t, v] + >= useful_activity + ) + + +def CapacityAnnual_Constraint(M: 'TemoaModel', r, p, t, v): + r""" + Similar to Capacity_Constraint, but for technologies belonging to the + :code:`tech_annual` set. Technologies in the tech_annual set have constant output + across different timeslices within a year, so we do not need to ensure + that installed capacity is sufficient across all timeslices, thus saving + some computational effort. Instead, annual output is sufficient to calculate + capacity. Hourly capacity factors cannot be defined to annual technologies + but annual capacity factors can be set using LimitAnnualCapacityFactor, + which will be implicitly accounted for here. + + .. math:: + :label: CapacityAnnual + + \text{C2A}_{r, t} + \cdot \textbf{CAP}_{r, t, v} + = + \sum_{I, O} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} + + \\ + \forall \{r, p, t \in T^{a}, v\} \in \Theta_{\text{Activity}} + """ + activity_rptv = sum( + M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + + return value(M.CapacityToActivity[r, t]) * M.V_Capacity[r, p, t, v] >= activity_rptv + + +def CapacityAvailableByPeriodAndTech_Constraint(M: 'TemoaModel', r, p, t): + r""" + + The :math:`\textbf{CAPAVL}` variable is nominally for reporting solution values, + but is also used in the Limit constraint calculations. + + .. math:: + :label: CapacityAvailable + + \textbf{CAPAVL}_{r, p, t} = \sum_{v, p_i \leq p} \textbf{CAP}_{r, p, t, v} + + \\ + \forall p \in \text{P}^o, r \in R, t \in T + """ + cap_avail = sum(M.V_Capacity[r, p, t, S_v] for S_v in M.processVintages[r, p, t]) + + expr = M.V_CapacityAvailableByPeriodAndTech[r, p, t] == cap_avail + return expr + + +def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): + r""" + Get the annualised retirement rate for a process in a given period. + Used to output retirement (including end of life, EOL) and to model end of + life flows and emissions. Assumes that retirement from the beginning of each period + is evenly distributed over that model period :math:`\frac{1}{\text{LEN}_p}` + for the accounting of retirement flows (in the same way we assume capacity is + deployed evenly over the model period for construction inputs and embodied emissions). + The factor :math:`\frac{\text{LSC}_{r,p,t,v}}{\text{PLF}_{r,p,t,v}}` + adjusts the average survival during a period to the survival at the beginning + of that period. + + .. math:: + :label: Annual Retirement + + \textbf{ART}_{r,p,t,v} = + \begin{cases} + \frac{1}{\text{LEN}_p} \cdot + \frac{\text{LSC}_{r,p,t,v}}{\text{PLF}_{r,p,t,v}} \cdot \textbf{CAP}_{r,p,t,v} + & \text{if EOL} \\ + \frac{1}{\text{LEN}_p} \cdot + \left( + \frac{\text{LSC}_{r,p,t,v}}{\text{PLF}_{r,p,t,v}} \cdot \textbf{CAP}_{r,p,t,v} + - \frac{\text{LSC}_{r,p_{next},t,v}}{\text{PLF}_{r,p_{next},t,v}} \cdot \textbf{CAP}_{r,p_{next},t,v} + \right) + & \text{otherwise} \\ + \end{cases} + + \\\text{where EOL when } p \leq v + LTP_{r,t,v} < p + LEN_p + """ + + ## Get the capacity at the start of this period + if p == v + value(M.LifetimeProcess[r, t, v]): + # Exact EOL. No V_Capacity or V_RetiredCapacity for this period. + if p == M.time_optimize.first(): + # Must be existing capacity. Apply survival curve to existing cap + cap_begin = M.ExistingCapacity[r, t, v] * M.LifetimeSurvivalCurve[r, p, t, v] + else: + # Get previous capacity and continue survival curve + p_prev = M.time_optimize.prev(p) + cap_begin = ( + M.V_Capacity[r, p_prev, t, v] + * value(M.LifetimeSurvivalCurve[r, p, t, v]) + / value(M.ProcessLifeFrac[r, p_prev, t, v]) + ) + else: + # The capacity at the beginning of the period + cap_begin = ( + M.V_Capacity[r, p, t, v] + * value(M.LifetimeSurvivalCurve[r, p, t, v]) + / value(M.ProcessLifeFrac[r, p, t, v]) + ) + + ## Get the capacity at the end of this period + if p <= v + value(M.LifetimeProcess[r, t, v]) < p + value(M.PeriodLength[p]): + # EOL so capacity ends on zero + cap_end = 0 + else: + # Mid-life period, ending capacity is beginning capacity of next period + p_next = M.time_future.next(p) + + if p == M.time_optimize.last() or p_next == v + value(M.LifetimeProcess[r, t, v]): + # No V_Capacity or V_RetiredCapacity for next period so just continue down the survival curve + cap_end = ( + cap_begin + * value(M.LifetimeSurvivalCurve[r, p_next, t, v]) + / value(M.LifetimeSurvivalCurve[r, p, t, v]) + ) + else: + # Get the next period's beginning capacity + cap_end = ( + M.V_Capacity[r, p_next, t, v] + * value(M.LifetimeSurvivalCurve[r, p_next, t, v]) + / value(M.ProcessLifeFrac[r, p_next, t, v]) + ) + + annualised_retirement = (cap_begin - cap_end) / M.PeriodLength[p] + return M.V_AnnualRetirement[r, p, t, v] == annualised_retirement + + +def get_capacity_factor(M: 'TemoaModel', r, p, s, d, t, v): + if M.isCapacityFactorProcess[r, p, t, v]: + return value(M.CapacityFactorProcess[r, p, s, d, t, v]) + else: + return value(M.CapacityFactorTech[r, p, s, d, t]) diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index 0fc8e2987..68ebcf951 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -3,12 +3,14 @@ from logging import getLogger from operator import itemgetter as iget from typing import TYPE_CHECKING +from pyomo.environ import Constraint, value from pyomo.environ import value if TYPE_CHECKING: from temoa.core.model import TemoaModel +from .utils import get_variable_efficiency logger = getLogger(name=__name__) @@ -256,3 +258,465 @@ def AnnualCommodityBalanceConstraintIndices(M: 'TemoaModel'): ) return indices + + +def Demand_Constraint(M: 'TemoaModel', r, p, dem): + r""" + + The Demand constraint drives the model. This constraint ensures that supply at + least meets the demand specified by the Demand parameter in all periods and + slices, by ensuring that the sum of all the demand output commodity (:math:`c`) + generated by both commodity flow at the time slice level (:math:`\textbf{FO}`) and + the annual level (:math:`\textbf{FOA}`) must meet the modeler-specified demand + in each time slice. + + .. math:: + :label: Demand + + \sum_{I, T-T^{a}, V} \textbf{FO}_{r, p, s, d, i, t \not \in T^{a}, v, dem} + + SEG_{s,d} \cdot \sum_{I, T^{a}, V} \textbf{FOA}_{r, p, i, t \in T^{a}, v, dem} + = + {DEM}_{r, p, dem} \cdot {DSD}_{r, s, d, dem} + + Note that the validity of this constraint relies on the fact that the + :math:`C^d` set is distinct from both :math:`C^e` and :math:`C^p`. In other + words, an end-use demand must only be an end-use demand. Note that if an output + could satisfy both an end-use and internal system demand, then the output from + :math:`\textbf{FO}` and :math:`\textbf{FOA}` would be double counted.""" + + # All demand techs are annual now + # supply = sum( + # M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, dem] + # for S_t, S_v in M.commodityUStreamProcess[r, p, dem] + # if S_t not in M.tech_annual + # for S_i in M.processInputsByOutput[r, p, S_t, S_v, dem] + # ) + + supply_annual = sum( + M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, dem] + for S_t, S_v in M.commodityUStreamProcess[r, p, dem] + for S_i in M.processInputsByOutput[r, p, S_t, S_v, dem] + ) + + DemandConstraintErrorCheck(supply_annual, r, p, dem) + + expr = supply_annual == value(M.Demand[r, p, dem]) + + return expr + + +# devnote: no longer needed +def DemandActivity_Constraint(M: 'TemoaModel', r, p, s, d, t, v, dem): + r""" + + For end-use demands, it is unreasonable to let the model arbitrarily shift the + use of demand technologies across time slices. For instance, if household A buys + a natural gas furnace while household B buys an electric furnace, then both units + should be used throughout the year. Without this constraint, the model might choose + to only use the electric furnace during the day, and the natural gas furnace during the + night. + + This constraint ensures that the ratio of a process activity to demand is + constant for all time slices. Note that if a demand is not specified in a given + time slice, or is zero, then this constraint will not be considered for that + slice and demand. This is transparently handled by the :math:`\Theta` superset. + + .. math:: + :label: DemandActivity + + DEM_{r, p, s, d, dem} \cdot \sum_{I} \textbf{FO}_{r, p, s_0, d_0, i, t \not \in T^{a}, v, dem} + = + DEM_{r, p, s_0, d_0, dem} \cdot \sum_{I} \textbf{FO}_{r, p, s, d, i, t \not \in T^{a}, v, dem} + + \\ + \forall \{r, p, s, d, t, v, dem, s_0, d_0\} \in \Theta_{\text{DemandActivity}} + + Note that this constraint is only applied to the demand commodities with diurnal + variations, and therefore the equation above only includes :math:`\textbf{FO}` + and not :math:`\textbf{FOA}` + """ + + activity = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, dem] for S_i in M.processInputsByOutput[r, p, t, v, dem] + ) + + annual_activity = sum( + M.V_FlowOutAnnual[r, p, S_i, t, v, dem] for S_i in M.processInputsByOutput[r, p, t, v, dem] + ) + + expr = annual_activity * value(M.DemandSpecificDistribution[r, p, s, d, dem]) == activity + return expr + + +def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): + r""" + Where the Demand constraint :eq:`Demand` ensures that end-use demands are met, + the CommodityBalance constraint ensures that the endogenous system demands are + met. This constraint requires the total production of a given commodity + to equal the amount consumed, thus ensuring an energy balance at the system + level. In this most general form of the constraint, the energy commodity being + balanced has variable production at the time slice level. The energy commodity + can then be consumed by three types of processes: storage technologies, non-storage + technologies with output that varies at the time slice level, and non-storage + technologies with constant annual output. + + Separate expressions are required in order to account for the consumption of + commodity :math:`c` by downstream processes. For the commodity flow into storage + technologies, we use :math:`\textbf{FI}_{r, p, s, d, i, t, v, c}`. Note that the FlowIn + variable is defined only for storage technologies, and is required because storage + technologies balance production and consumption across time slices rather than + within a single time slice. For commodity flows into non-storage processes with time + varying output, we use :math:`\textbf{FO}_{r, p, s, d, i, t, v, c}/EFF_{r, i,t,v,o}`. + The division by :math:`EFF_{r, c,t,v,o}` is applied to the output flows that consume + commodity :math:`c` to determine input flows. Finally, we need to account + for the consumption of commodity :math:`c` by the processes in + :code:`tech_annual`. Since the commodity flow of these processes is on an + annual basis, we use :math:`SEG_{s,d}` to calculate the consumption of + commodity :math:`c` in time-slice :math:`(s,d)` from the annual flows. + Formulating an expression for the production of commodity :math:`c` is + more straightforward, and is simply calculated by + :math:`\textbf{FO}_{r, p, s, d, i, t, v, c}`. + + In some cases, the overproduction of a commodity may be required, such + that the supply exceeds the endogenous demand. Refineries represent a + common example, where the share of different refined products are governed + by TechOutputSplit, but total production is driven by a particular commodity + like gasoline. Such a situation can result in the overproduction of other + refined products, such as diesel or kerosene. In such cases, we need to + track the excess production of these commodities. To do so, the technology + producing the excess commodity should be added to the :code:`tech_flex` set. + This flexible technology designation will activate a slack variable + (:math:`\textbf{FLX}_{r, p, s, d, i, t, v, c}`) representing + the excess production in the :code:`CommodityBalanceAnnual_Constraint`. Note + that the :code:`tech_flex` set is different from :code:`tech_curtailment` set; + the latter is technology- rather than commodity-focused and is used in the + :code:`Capacity_Constraint` to track output that is used to produce useful + output and the amount curtailed, and to ensure that the installed capacity + covers both. Alternatively, the commodity can be added to the + :code:`commodity_waste` set, for which this equality constraint becomes an + inequality constraint, allowing production to exceed consumption for a single + commodity. + + 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{FO}` variables over the appropriate import and export regions, + respectively, which are defined in :code:`temoa_initialize.py` by parsing the + :code:`tech_exchange` processes. + + Consumption of the commodity by construction inputs is annualised using the period + length. Production of the commodity by end-of-life outputs uses the AnnualRetirement + variable, which is already annualised. + + Finally, for annual commodities, AnnualCommodityBalance is used which balances + the sum of flows over each year. + + *process outputs + imports + end of life outputs = process inputs + construction inputs + exports + flex waste* + + .. math:: + :label: CommodityBalance + + \begin{aligned} + &\sum_{I, t \notin T^a, V} \mathbf{FO}_{r, p, s, d, i, t, v, c} + && \text{(processes outputting commodity)} \\ + &+ SEG_{s,d} \cdot \sum_{I, t \in T^a, V} \frac{\mathbf{FOA}_{r, p, i, t, v, c}}{EFF_{r, i, t, v, c}} + && \text{(annual processes outputting commodity)} \\ + &+ \sum_{\text{reg} \neq r, I, t \in T^x, V} \mathbf{FIM}_{r - \text{reg}, p, s, d, i, t, v, c} + && \text{(inter-regional imports of commodity)} \\ + &+ SEG_{s,d} \sum_{T, V} \left ( EOLO_{r, t, v, c} \cdot \textbf{ART}_{r, p, t, v} \right ) + && \text{(end-of-life outputs of commodity)} \\ + &\begin{cases} + &= \text{if } c \notin C^w \\ + &\geq \text{if } c \in C^w \end{cases} \\ + &\sum_{t \in T^s, V, O} \mathbf{FIS}_{r, p, s, d, c, t, v, o} + && \text{(commodity stored)} \\ + &+ \sum_{t \notin T^s, V, O} \frac{\mathbf{FO}_{r, p, s, d, c, t, v, o}}{EFF_{r, c, t, v, o}} + && \text{(commodity consumed by processes)} \\ + &+ SEG_{s,d} \cdot \sum_{t \in T^a, V, O} \frac{\mathbf{FOA}_{r, p, c, t, v, o}}{EFF_{r, c, t, v, o}} + && \text{(commodity consumed by annual processes)} \\ + &+ \sum_{\text{reg} \neq r, t \in T^x, V, O} \mathbf{FEX}_{r - \text{reg}, p, s, d, c, t, v, o} + && \text{(inter-regional exports of commodity)} \\ + &+ \sum_{I, t \in T^f, V} \mathbf{FLX}_{r, p, s, d, i, t, v, c} + && \text{(flex wastes of commodity)} \\ + &+ SEG_{s,d} \cdot \sum_{T, V} \left ( CON_{r, c, t, v} \cdot \frac{\textbf{NCAP}_{r, t, v}}{LEN_p} \right ) + && \text{(consumed annually by construction inputs)} + \end{aligned} + + \qquad \forall \{r, p, s, d, c\} \in \Theta_{\text{CommodityBalance}} + + """ + + produced = 0 + consumed = 0 + + if (r, p, c) in M.commodityDStreamProcess: + # Only storage techs have a flow in variable + # For other techs, it would be redundant as in = out / eff + consumed += sum( + M.V_FlowIn[r, p, s, d, c, S_t, S_v, S_o] + for S_t, S_v in M.commodityDStreamProcess[r, p, c] + if S_t in M.tech_storage + for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] + ) + + # Into flows + consumed += sum( + M.V_FlowOut[r, p, s, d, c, S_t, S_v, S_o] + / get_variable_efficiency(M, r, p, s, d, c, S_t, S_v, S_o) + for S_t, S_v in M.commodityDStreamProcess[r, p, c] + if S_t not in M.tech_storage and S_t not in M.tech_annual + for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] + ) + + # Into annual flows + consumed += sum( + ( + value(M.DemandSpecificDistribution[r, p, s, d, S_o]) + if S_o in M.commodity_demand + else value(M.SegFrac[p, s, d]) + ) + * M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] + / get_variable_efficiency(M, r, p, s, d, c, S_t, S_v, S_o) + for S_t, S_v in M.commodityDStreamProcess[r, p, c] + if S_t in M.tech_annual + for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] + ) + + if (r, p, c) in M.capacityConsumptionTechs: + # Consumed by building capacity + # Assume evenly distributed over a year + consumed += ( + value(M.SegFrac[p, s, d]) + * sum( + value(M.ConstructionInput[r, c, S_t, p]) * M.V_NewCapacity[r, S_t, p] + for S_t in M.capacityConsumptionTechs[r, p, c] + ) + / M.PeriodLength[p] + ) + + if (r, p, c) in M.commodityUStreamProcess: + # From flows including output from storage + produced += sum( + M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, c] + for S_t, S_v in M.commodityUStreamProcess[r, p, c] + if S_t not in M.tech_annual + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + ) + + # From annual flows + produced += value(M.SegFrac[p, s, d]) * sum( + M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, c] + for S_t, S_v in M.commodityUStreamProcess[r, p, c] + if S_t in M.tech_annual + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + ) + + if c in M.commodity_flex: + # Wasted by flex flows + consumed += sum( + M.V_Flex[r, p, s, d, S_i, S_t, S_v, c] + for S_t, S_v in M.commodityUStreamProcess[r, p, c] + if S_t not in M.tech_annual and S_t in M.tech_flex + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + ) + # Wasted by annual flex flows + consumed += value(M.SegFrac[p, s, d]) * sum( + M.V_FlexAnnual[r, p, S_i, S_t, S_v, c] + for S_t, S_v in M.commodityUStreamProcess[r, p, c] + if S_t in M.tech_annual and S_t in M.tech_flex + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + ) + + if (r, p, c) in M.retirementProductionProcesses: + # Produced by retiring capacity + # Assume evenly distributed over a year + produced += value(M.SegFrac[p, s, d]) * sum( + value(M.EndOfLifeOutput[r, S_t, S_v, c]) * M.V_AnnualRetirement[r, p, S_t, S_v] + for S_t, S_v in M.retirementProductionProcesses[r, p, c] + ) + + # export of commodity c from region r to other regions + if (r, p, c) in M.exportRegions: + consumed += sum( + M.V_FlowOut[r + '-' + reg, p, s, d, c, S_t, S_v, S_o] + / get_variable_efficiency(M, r + '-' + reg, p, s, d, c, S_t, S_v, S_o) + for reg, S_t, S_v, S_o in M.exportRegions[r, p, c] + if S_t not in M.tech_annual + ) + consumed += sum( + value(M.SegFrac[p, s, d]) + * M.V_FlowOutAnnual[r + '-' + reg, p, c, S_t, S_v, S_o] + / get_variable_efficiency(M, r + '-' + reg, p, s, d, c, S_t, S_v, S_o) + for reg, S_t, S_v, S_o in M.exportRegions[r, p, c] + if S_t in M.tech_annual + ) + + # import of commodity c from other regions into region r + if (r, p, c) in M.importRegions: + produced += sum( + M.V_FlowOut[reg + '-' + r, p, s, d, S_i, S_t, S_v, c] + for reg, S_t, S_v, S_i in M.importRegions[r, p, c] + if S_t not in M.tech_annual + ) + produced += sum( + value(M.SegFrac[p, s, d]) * M.V_FlowOutAnnual[reg + '-' + r, p, S_i, S_t, S_v, c] + for reg, S_t, S_v, S_i in M.importRegions[r, p, c] + if S_t in M.tech_annual + ) + + CommodityBalanceConstraintErrorCheck( + produced, + consumed, + r, + p, + s, + d, + c, + ) + + if c in M.commodity_waste: + expr = produced >= consumed + else: + expr = produced == consumed + + return expr + + +def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): + r""" + Similar to CommodityBalance_Constraint but only balances the supply and demand of the commodity + at the period level, summing all flows over the period but allowing imbalances at the time slice + or seasonal level. Applies only to commodities in the :code:`commodity_annual` set. + """ + + produced = 0 + consumed = 0 + + if (r, p, c) in M.commodityDStreamProcess: + # Only storage techs have a flow in variable + # For other techs, it would be redundant as in = out / eff + consumed += sum( + M.V_FlowIn[r, p, S_s, S_d, c, S_t, S_v, S_o] + for S_s in M.TimeSeason[p] + for S_d in M.time_of_day + for S_t, S_v in M.commodityDStreamProcess[r, p, c] + if S_t in M.tech_storage + for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] + ) + + consumed += sum( + M.V_FlowOut[r, p, S_s, S_d, c, S_t, S_v, S_o] + / get_variable_efficiency(M, r, p, S_s, S_d, c, S_t, S_v, S_o) + for S_s in M.TimeSeason[p] + for S_d in M.time_of_day + for S_t, S_v in M.commodityDStreamProcess[r, p, c] + if S_t not in M.tech_storage and S_t not in M.tech_annual + for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] + ) + + consumed += sum( + M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] / value(M.Efficiency[r, c, S_t, S_v, S_o]) + for S_t, S_v in M.commodityDStreamProcess[r, p, c] + if S_t in M.tech_annual + for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] + ) + + if (r, p, c) in M.capacityConsumptionTechs: + # Consumed by building capacity + # Assume evenly distributed over a year + consumed += ( + sum( + value(M.ConstructionInput[r, c, S_t, p]) * M.V_NewCapacity[r, S_t, p] + for S_t in M.capacityConsumptionTechs[r, p, c] + ) + / M.PeriodLength[p] + ) + + if (r, p, c) in M.commodityUStreamProcess: + # Includes output from storage + produced += sum( + M.V_FlowOut[r, p, S_s, S_d, S_i, S_t, S_v, c] + for S_s in M.TimeSeason[p] + for S_d in M.time_of_day + for S_t, S_v in M.commodityUStreamProcess[r, p, c] + if S_t not in M.tech_annual + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + ) + + produced += sum( + M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, c] + for S_t, S_v in M.commodityUStreamProcess[r, p, c] + if S_t in M.tech_annual + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + ) + + if c in M.commodity_flex: + consumed += sum( + M.V_Flex[r, p, S_s, S_d, S_i, S_t, S_v, c] + for S_s in M.TimeSeason[p] + for S_d in M.time_of_day + for S_t, S_v in M.commodityUStreamProcess[r, p, c] + if S_t not in M.tech_annual and S_t in M.tech_flex + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + ) + consumed += sum( + M.V_FlexAnnual[r, p, S_i, S_t, S_v, c] + for S_t, S_v in M.commodityUStreamProcess[r, p, c] + if S_t in M.tech_flex and S_t in M.tech_annual + for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + ) + + if (r, p, c) in M.retirementProductionProcesses: + # Produced by retiring capacity + # Assume evenly distributed over a year + produced += sum( + value(M.EndOfLifeOutput[r, S_t, S_v, c]) * M.V_AnnualRetirement[r, p, S_t, S_v] + for S_t, S_v in M.retirementProductionProcesses[r, p, c] + ) + + # export of commodity c from region r to other regions + if (r, p, c) in M.exportRegions: + consumed += sum( + M.V_FlowOut[r + '-' + S_r, p, S_s, S_d, c, S_t, S_v, S_o] + / get_variable_efficiency(M, r + '-' + S_r, p, S_s, S_d, c, S_t, S_v, S_o) + for S_s in M.TimeSeason[p] + for S_d in M.time_of_day + for S_r, S_t, S_v, S_o in M.exportRegions[r, p, c] + if S_t not in M.tech_annual + ) + consumed += sum( + M.V_FlowOutAnnual[r + '-' + S_r, p, c, S_t, S_v, S_o] + / M.Efficiency[r + '-' + S_r, c, S_t, S_v, S_o] + for S_r, S_t, S_v, S_o in M.exportRegions[r, p, c] + if S_t in M.tech_annual + ) + + # import of commodity c from other regions into region r + if (r, p, c) in M.importRegions: + produced += sum( + M.V_FlowOut[S_r + '-' + r, p, S_s, S_d, S_i, S_t, S_v, c] + for S_s in M.TimeSeason[p] + for S_d in M.time_of_day + for S_r, S_t, S_v, S_i in M.importRegions[r, p, c] + if S_t not in M.tech_annual + ) + produced += sum( + M.V_FlowOutAnnual[S_r + '-' + r, p, S_i, S_t, S_v, c] + for S_r, S_t, S_v, S_i in M.importRegions[r, p, c] + if S_t in M.tech_annual + ) + + AnnualCommodityBalanceConstraintErrorCheck( + produced, + consumed, + r, + p, + c, + ) + + if c in M.commodity_waste: + expr = produced >= consumed + else: + expr = produced == consumed + + return expr diff --git a/temoa/components/costs.py b/temoa/components/costs.py index 5c58a18ac..d4c7a8e71 100644 --- a/temoa/components/costs.py +++ b/temoa/components/costs.py @@ -4,6 +4,9 @@ from deprecated import deprecated +from pyomo.core import Expression, Var +from pyomo.environ import value + if TYPE_CHECKING: from temoa.core.model import TemoaModel @@ -71,11 +74,220 @@ def CostVariableIndices(M: 'TemoaModel'): return M.activeActivity_rptv -# dev note: appears superfluous... -# def CostInvestIndices(M: 'TemoaModel'): -# indices = set((r, t, v) for r, p, t, v in M.processLoans) -# -# return indices +def annuity_to_pv(rate: float, periods: int) -> float | Expression: + r""" + Multiplication factor to convert an annuity to net present value + + .. math:: + :label: annuity_to_pv + + \frac{P}{A}(i, N) = \frac{(1 + i)^N - 1}{i (1 + i)^N} + + where: + + - :math:`i` is the interest/discount rate + - :math:`N` is the number of periods + """ + if rate == 0: + return periods + return ((1 + rate) ** periods - 1) / (rate * (1 + rate) ** periods) + + +def pv_to_annuity(rate: float, periods: int) -> float | Expression: + r""" + Multiplication factor to convert net present value to an annuity + + .. math:: + :label: pv_to_annuity + + \frac{A}{P}(i, N) = \frac{i + (1 + i)^N}{(1 + i)^N - 1} + """ + if rate == 0: + return 1 / periods + return (rate * (1 + rate) ** periods) / ((1 + rate) ** periods - 1) + + +def fv_to_pv(rate: float, periods: int) -> float | Expression: + r""" + Multiplication factor to convert a future value to net present value + + .. math:: + :label: fv_to_pv + + \frac{P}{F}(i, N) = \frac{1}{(1 + i)^N} + """ + if rate == 0: + return 1 + return 1 / (1 + rate) ** periods + + +def loan_cost( + capacity: float | Var, + invest_cost: float, + loan_annualize: float, + lifetime_loan_process: float | int, + lifetime_process: int, + P_0: int, + P_e: int, + GDR: float, + vintage: int, +) -> float | Expression: + """ + function to calculate the loan cost. It can be used with fixed values to produce a hard number or + pyomo variables/params to make a pyomo Expression + :param capacity: The capacity to use to calculate cost + :param invest_cost: the cost/capacity + :param loan_annualize: parameter + :param lifetime_loan_process: lifetime of the loan + :param P_0: the year to discount the costs back to + :param P_e: the 'end year' or cutoff year for loan payments + :param GDR: Global Discount Rate + :param vintage: the base year of the loan + :return: fixed number or pyomo expression based on input types + """ + + # calculate the amortised loan repayment (annuity) + annuity = ( + capacity + * invest_cost # lump investment cost is capacity times CostInvest + * loan_annualize # calculate loan annuities for investment cost, if used + ) + + if not GDR: + # Undiscounted result + res = ( + annuity + * lifetime_loan_process # sum of loan payments over loan period + / lifetime_process # redistributed over lifetime of process + * min( + lifetime_process, P_e - vintage + ) # sum of redistributed costs for life of process (within planning horizon) + ) + else: + # Discounted result + res = ( + annuity + * annuity_to_pv( + GDR, lifetime_loan_process + ) # PV of all loan payments, discounted to vintage year using GDR + * pv_to_annuity(GDR, lifetime_process) # reamortised over lifetime of process using GDR + * annuity_to_pv( + GDR, min(lifetime_process, P_e - vintage) + ) # PV of all reamortised costs (within planning horizon) + * fv_to_pv(GDR, vintage - P_0) # finally, discounted from vintage year to P_0 + ) + return res + + +def loan_cost_survival_curve( + M: 'TemoaModel', + r: str, + t: str, + v: str, + capacity: float | Var, + invest_cost: float, + loan_annualize: float, + lifetime_loan_process: float | int, + P_0: int, + P_e: int, + GDR: float, +) -> float | Expression: + """ + function to calculate the loan cost only in the case of processes :math:`(r, t, v)` using + survival curves. It can be used with fixed values to produce a hard number or pyomo + variables/params to make a pyomo Expression + :param capacity: The capacity to use to calculate cost + :param invest_cost: the cost/capacity + :param loan_annualize: parameter + :param lifetime_loan_process: lifetime of the loan + :param P_0: the year to discount the costs back to + :param P_e: the 'end year' or cutoff year for loan payments + :param GDR: Global Discount Rate + :return: fixed number or pyomo expression based on input types + """ + + # calculate the amortised loan repayment (annuity) + annuity = ( + capacity + * invest_cost # lump investment cost is capacity times CostInvest + * loan_annualize # calculate loan annuities for investment cost, if used + ) + + if not GDR: + # Undiscounted result + res = ( + annuity + * lifetime_loan_process # sum of loan payments over loan period + / sum( # redistributed over survival curve within horizon + value(M.LifetimeSurvivalCurve[r, p, t, v]) + for p in M.survivalCurvePeriods[r, t, v] + if v <= p + ) + * sum( # summed over survival curve within horizon + value(M.LifetimeSurvivalCurve[r, p, t, v]) + for p in M.survivalCurvePeriods[r, t, v] + if v <= p < P_e + ) + ) + else: + # Discounted result + res = ( + annuity + * annuity_to_pv( + GDR, lifetime_loan_process + ) # PV of all loan payments, discounted to vintage year using GDR + / sum( # redistributed over survival curve within horizon + value( + M.LifetimeSurvivalCurve[r, p, t, v] + ) # reamortised over survival curve of process using GDR + * fv_to_pv(GDR, p - v + 1) # +1 because LSC is indexed to start of p not end of p + for p in M.survivalCurvePeriods[r, t, v] + if v <= p # this shouldnt be possible but play it safe + ) + * sum( # PV of all reamortised costs (within planning horizon) + value(M.LifetimeSurvivalCurve[r, p, t, v]) * fv_to_pv(GDR, p - v + 1) + for p in M.survivalCurvePeriods[r, t, v] + if v <= p < P_e + ) + * fv_to_pv(GDR, v - P_0) # finally, discounted from vintage year to P_0 + ) + return res + + +def fixed_or_variable_cost( + cap_or_flow: float | Var, + cost_factor: float, + cost_years: float, + GDR: float | None, + P_0: float, + p: int, +) -> float | Expression: + """ + Extraction of the fixed and var cost formulation. (It is same for both with either capacity or + flow as the driving variable.) + :param cap_or_flow: Capacity if fixed cost / flow out if variable + :param cost_factor: the cost (either fixed or variable) of the cap/flow variable + :param cost_years: for how many years is this cost incurred + :param GDR: discount rate or None + :param P_0: the period to discount this back to + :param p: the period under evaluation + :return: + """ + + annual_cost = cap_or_flow * cost_factor # annual fixed, variable, or emission cost + + if not GDR: + # Undiscounted result + return annual_cost * cost_years # annual cost times years paying that cost + else: + # Discounted result + return ( + annual_cost + * annuity_to_pv( + GDR, cost_years + ) # PV of annual costs over this period, discounted to period p + * fv_to_pv(GDR, p - P_0) # discounted from p to p_0 + ) def get_loan_life(M: 'TemoaModel', r, t, v): @@ -93,3 +305,348 @@ def LifetimeLoanProcessIndices(M: 'TemoaModel'): indices = set((r, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys() if v >= min_period) return indices + + +def PeriodCost_rule(M: 'TemoaModel', p): + P_0 = min(M.time_optimize) + P_e = M.time_future.last() # End point of modeled horizon + GDR = value(M.GlobalDiscountRate) + # MPL = M.ModelProcessLife + + if value(M.MyopicDiscountingYear) != 0: + P_0 = value(M.MyopicDiscountingYear) + + loan_costs = sum( + loan_cost( + M.V_NewCapacity[r, S_t, S_v], + value(M.CostInvest[r, S_t, S_v]), + value(M.LoanAnnualize[r, S_t, S_v]), + value(M.LoanLifetimeProcess[r, S_t, S_v]), + value(M.LifetimeProcess[r, S_t, S_v]), + P_0, + P_e, + GDR, + vintage=S_v, + ) + for r, S_t, S_v in M.CostInvest.sparse_iterkeys() + if S_v == p and not M.isSurvivalCurveProcess[r, S_t, S_v] + ) + loan_costs += sum( + loan_cost_survival_curve( + M, + r, + S_t, + S_v, + M.V_NewCapacity[r, S_t, S_v], + value(M.CostInvest[r, S_t, S_v]), + value(M.LoanAnnualize[r, S_t, S_v]), + value(M.LoanLifetimeProcess[r, S_t, S_v]), + P_0, + P_e, + GDR, + ) + for r, S_t, S_v in M.CostInvest.sparse_iterkeys() + if S_v == p and M.isSurvivalCurveProcess[r, S_t, S_v] + ) + + fixed_costs = sum( + fixed_or_variable_cost( + M.V_Capacity[r, p, S_t, S_v], + value(M.CostFixed[r, p, S_t, S_v]), + value(M.PeriodLength[p]), + GDR, + P_0, + p=p, + ) + for r, S_p, S_t, S_v in M.CostFixed.sparse_iterkeys() + if S_p == p + ) + + variable_costs = sum( + fixed_or_variable_cost( + M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, S_o], + value(M.CostVariable[r, p, S_t, S_v]), + value(M.PeriodLength[p]), + GDR, + P_0, + p, + ) + for r, S_p, S_t, S_v in M.CostVariable.sparse_iterkeys() + if S_p == p and S_t not in M.tech_annual + for S_i in M.processInputs[r, S_p, S_t, S_v] + for S_o in M.processOutputsByInput[r, S_p, S_t, S_v, S_i] + for s in M.TimeSeason[p] + for d in M.time_of_day + ) + + variable_costs_annual = sum( + fixed_or_variable_cost( + M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, S_o], + value(M.CostVariable[r, p, S_t, S_v]), + value(M.PeriodLength[p]), + GDR, + P_0, + p, + ) + for r, S_p, S_t, S_v in M.CostVariable.sparse_iterkeys() + if S_p == p and S_t in M.tech_annual + for S_i in M.processInputs[r, S_p, S_t, S_v] + for S_o in M.processOutputsByInput[r, S_p, S_t, S_v, S_i] + ) + + # The emissions costs occur over the five possible emission sources. + # to do any/all of them we need 2 baseline sets: The regular and annual sets + # of indices that are valid which is basically the filter of: + # EmissionActivty by CostEmission + # and to ensure that the techology is active we need to filter that + # result with processInput + + # ================= Emissions and Flex and Curtailment ================= + # Flex flows are deducted from V_FlowOut, so it is NOT NEEDED to tax them again. (See commodity balance constr) + # Curtailment does not draw any inputs, so it seems logical that curtailed flows not be taxed either + # Earlier versions of this code had accounting for flex & curtailment that have been removed. + + base = [ + (r, p, e, i, t, v, o) + for (r, e, i, t, v, o) in M.EmissionActivity.sparse_iterkeys() + if (r, p, e) in M.CostEmission # tightest filter first + and (r, p, t, v) in M.processInputs + ] + + # then expand the base for the normal (season/tod) set and annual separately: + normal = [ + (r, p, e, s, d, i, t, v, o) + for (r, p, e, i, t, v, o) in base + for s in M.TimeSeason[p] + for d in M.time_of_day + if t not in M.tech_annual + ] + + annual = [(r, p, e, i, t, v, o) for (r, p, e, i, t, v, o) in base if t in M.tech_annual] + + # 1. variable emissions + var_emissions = sum( + fixed_or_variable_cost( + cap_or_flow=M.V_FlowOut[r, p, s, d, i, t, v, o] + * value(M.EmissionActivity[r, e, i, t, v, o]), + cost_factor=value(M.CostEmission[r, p, e]), + cost_years=value(M.PeriodLength[p]), + GDR=GDR, + P_0=P_0, + p=p, + ) + for (r, p, e, s, d, i, t, v, o) in normal + ) + + # 2. flex emissions -- removed (double counting, flex wastes are SUBTRACTIVE from flowout) + + # 3. curtailment emissions -- removed (curtailment is no-flow, for accounting only, so no emissions) + + # 4. annual emissions + var_annual_emissions = sum( + fixed_or_variable_cost( + cap_or_flow=M.V_FlowOutAnnual[r, p, i, t, v, o] + * value(M.EmissionActivity[r, e, i, t, v, o]), + cost_factor=value(M.CostEmission[r, p, e]), + cost_years=value(M.PeriodLength[p]), + GDR=GDR, + P_0=P_0, + p=p, + ) + for (r, p, e, i, t, v, o) in annual + if t not in M.tech_flex + ) + + # 5. flex annual emissions -- removed (double counting, flex wastes are SUBTRACTIVE from flowout) + + # 6. embodied - treated as a fixed cost distributed over the deployment period (vintage) + embodied_emissions = sum( + fixed_or_variable_cost( + cap_or_flow=M.V_NewCapacity[r, t, v] + * value(M.EmissionEmbodied[r, e, t, v]) + / value(M.PeriodLength[p]), + cost_factor=value(M.CostEmission[r, p, e]), + cost_years=M.PeriodLength[ + v + ], # We assume the embodied emissions are emitted in the same year as the capacity is installed. + GDR=GDR, + P_0=P_0, + p=p, + ) + for (r, e, t, v) in M.EmissionEmbodied.sparse_iterkeys() + if (r, p, e) in M.CostEmission + if v == p + ) + + # 6. endoflife - treated as a fixed cost distributed over the retirement period + endoflife_emissions = sum( + fixed_or_variable_cost( + cap_or_flow=M.V_AnnualRetirement[r, p, t, v] * value(M.EmissionEndOfLife[r, e, t, v]), + cost_factor=value(M.CostEmission[r, p, e]), + cost_years=M.PeriodLength[ + p + ], # We assume the embodied emissions are emitted in the same year as the capacity is installed. + GDR=GDR, + P_0=P_0, + p=p, + ) + for (r, e, t, v) in M.EmissionEndOfLife.sparse_iterkeys() + if (r, p, e) in M.CostEmission + if (r, t, v) in M.retirementPeriods and p in M.retirementPeriods[r, t, v] + ) + + period_emission_cost = ( + var_emissions + var_annual_emissions + embodied_emissions + endoflife_emissions + ) + + period_costs = ( + loan_costs + fixed_costs + variable_costs + variable_costs_annual + period_emission_cost + ) + return period_costs + + +def ParamLoanAnnualize_rule(M: 'TemoaModel', r, t, v): + dr = value(M.LoanRate[r, t, v]) + lln = value(M.LoanLifetimeProcess[r, t, v]) + annualized_rate = pv_to_annuity(dr, lln) + return annualized_rate + + +# --------------------------------------------------------------- +# Define the Objective Function +# --------------------------------------------------------------- +def TotalCost_rule(M): + r""" + + Using the :code:`FlowOut` and :code:`Capacity` variables, the Temoa objective + function calculates the cost of energy supply, under the assumption that capital + costs are paid through loans. This implementation sums up all the costs incurred, + and is defined as :math:`C_{tot} = C_{loans} + C_{fixed} + C_{variable} + C_{emissions}`. + Each term on the right-hand side represents the cost incurred over the model + time horizon and discounted to the initial year in the horizon (:math:`{P}_0`). + The calculation of each term is given below. + + .. math:: + :label: obj_invest + + \begin{aligned} + C_{loans} =& \sum_{r, t, v \in \Theta_{CI}} CI_{r, t, v} \cdot \textbf{NCAP}_{r, t, v} + && \text{(overnight capital cost)} \\ + &\cdot \frac{A}{P}(i=\text{LR}_{r,t,v}, N=\text{LLP}_{r,t,v}) + && \text{(overnight cost amortised into annual loan payments)} \\ + &\cdot \frac{P}{A}(i=GDR, N=\text{LLP}_{r,t,v}) + && \text{(annual loan payments discounted to NPV in vintage year)} \\ + &\cdot \frac{A}{P}(i=GDR, N=\text{LTP}_{r,t,v}) + && \text{(NPV reamortised over lifetime of process using GDR)} \\ + &\cdot \frac{P}{A}(i=GDR, N=\min(\text{LTP}_{r,t,v}, P_e - v)) + && \text{(costs within planning horizon discounted to NPV in vintage year)} \\ + &\cdot \frac{P}{F}(i=GDR, N=v - P_0) + && \text{(NPV in vintage year discounted to base year } P_0\text{)} \\ + \end{aligned} + + Note that capital costs (:math:`{CI}_{r,t,v}`) are handled in several steps. + + 1. Each capital cost is amortized using the loan rate (i.e., technology-specific discount rate) and loan period. + + 2. The annual stream of payments is converted into a lump sum using the global discount rate and loan period. + + 3. The new lump sum is amortized at the global discount rate over the process lifetime. + + 4. Loan payments beyond the model time horizon are removed and the lump sum recalculated. + + 5. Finally, the lump sum is discounted back to the beginning of the horizon (:math:`P_0`) using the global discount rate. + + Steps 3 and 4 serve to correctly balance the cost-benefit of technologies whose useful lives + would extend beyond the planning horizon. While an explicit salvage term is not included, this approach properly + captures the capital costs incurred within the model time horizon, accounting for process-specific loan rates + and periods. + + In the case of processes using survival curves, steps 3 and 4 do not reamortise costs uniformly over the process lifetime. + Instead, costs are amortised over the life of the process in proportion to the survival fraction in each year. + Note that, for this calculation, a survival curve :math:`{LSC}_{r,y,t,v}` must be defined out to the year in which the + surviving fraction is zero, even if that extends beyond the planning horizon. It must also be defined for each integer + year between model periods and, if not, these gaps will be filled by linear interpolation ahead of this calculation. + + .. math:: + :label: obj_invest_survival_curve + + \begin{aligned} + C_{loans,LSC} =& \sum_{r, t, v \in \Theta_{CI}} CI_{r, t, v} \cdot \textbf{NCAP}_{r, t, v} + && \text{(overnight capital cost)} \\ + &\cdot \frac{A}{P}(i=\text{LR}_{r,t,v}, N=\text{LLP}_{r,t,v}) + && \text{(overnight cost amortised into annual loan payments)} \\ + &\cdot \frac{P}{A}(i=GDR, N=\text{LLP}_{r,t,v}) + && \text{(annual loan payments discounted to NPV in vintage year)} \\ + &\cdot \left( + \sum_{v < Y} LSC_{r,y,t,v} \cdot \frac{P}{F}(i=GDR, N=P - v + 1) + \right)^{-1} + && \text{(reamortised over survival curve (normalized)} \\ + &\cdot \sum_{v < Y < P_e} LSC_{r,y,t,v} \cdot \frac{P}{F}(i=GDR, N=P - v + 1) + && \text{(costs within planning horizon discounted to NPV in vintage year)} \\ + &\cdot \frac{P}{F}(i=GDR, N=v - P_0) + && \text{(NPV in vintage year discounted to base year } P_0 \text{)} + \end{aligned} + + Where :math:`Y` is the set of each integer year :math:`y` within the planning horizon. + + .. figure:: images/survival_curve_discounting.* + :align: center + :width: 100% + :figclass: align-center + :figwidth: 60% + + Steps 3 and 4 for processes with survival curves. + + Fixed, variable, and emissions annual cost factors are determined by: + + .. math:: + :label: annual_fixed_variable_emission + + \begin{aligned} + C_{fixed} =& \sum_{r, p, t, v \in \Theta_{CF}} CF_{r, p, t, v} \cdot \textbf{CAP}_{r, p, t, v} + && \text{(annual fixed cost)} \\ + \\ + C_{variable} =& \sum_{r, p, t \notin T^a, v \in \Theta_{CV}} + CV_{r, p, t, v} \cdot \sum_{S, D, I, O} \mathbf{FO}_{r, p, s, d, i, t, v, o} + && \text{(annual variable cost on flow)} \\ + & \text{where } t \notin T^a \\ + &+\\ + & \sum_{r, p, t \in T^a,\ v \in \Theta_{VC}} CV_{r, p, t, v} + \cdot \sum_{I, O} \mathbf{FOA}_{r, p, i, t, v, o} + && \text{(annual variable cost on annual flows)} \\ + & \text{where } t \in T^a \\ + &+\\ + C_{emissions} =& \sum_{r, p, e \in \Theta_{CE}} CE_{r, p, e} + \cdot EAC_{r, i, t, v, o, e} \cdot \sum_{S, D, I, O} \mathbf{FO}_{r, p, s, d, i, t, v, o} + && \text{(annual emission cost on flow)} \\ + & \text{where } t \notin T^a \\ + &+\\ + & \sum_{r, p, e \in \Theta_{CE}} CE_{r, p, e} + \cdot EAC_{r, i, t, v, o, e} \cdot \sum_{I, O} \mathbf{FOA}_{r, p, i, t, v, o} + && \text{(annual emission cost on annual flows)} \\ + & \text{where } t \in T^a \\ + &+\\ + & \sum_{r, p, e \in \Theta_{CE}} \frac{CE_{r, p, e} + \cdot EE_{r, e, t, v} \cdot \mathbf{NCAP}_{r, t, v=p}}{{LEN}_p} + && \text{(annual embodied emission cost)} \\ + &+\\ + & \sum_{r, p, e \in \Theta_{CE}, v} CE_{r, p, e} + \cdot EEOL_{r, e, t, v} \cdot \mathbf{ART}_{r, p, t, v} + && \text{(annual retirement/end of life emission cost)} \\ + \end{aligned} + + Each of these costs are then discounted within each period and then to the base year: + + .. math:: + :label: obj_fixed_variable_emission + + \begin{aligned} + C_{fix,var,emiss} =& C_{fixed} + C_{variable} + C_{emissions} \\ + &\cdot \frac{P}{A}(i=GDR,\ N=LEN_p) + && \text{(for each year in period } p \text{ discounted to NPV in } p \text{)}\\ + &\cdot \frac{P}{F}(i=GDR,\ N=p - P_0) + && \text{(discounted from period } p \text{ to NPV in base year } P_0 \text{)} + \end{aligned} + """ + + return sum(PeriodCost_rule(M, p) for p in M.time_optimize) diff --git a/temoa/components/emissions.py b/temoa/components/emissions.py index 6f961d190..a449102fa 100644 --- a/temoa/components/emissions.py +++ b/temoa/components/emissions.py @@ -1,5 +1,7 @@ from typing import TYPE_CHECKING +from pyomo.environ import value + if TYPE_CHECKING: from temoa.core.model import TemoaModel @@ -28,3 +30,76 @@ def LinkedTechConstraintIndices(M: 'TemoaModel'): ) return linkedtech_indices + + +def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): + r""" + This constraint is necessary for carbon capture technologies that produce + CO2 as an emissions commodity, but the CO2 also serves as a physical + input commodity to a downstream process, such as synthetic fuel production. + To accomplish this, a dummy technology is linked to the CO2-producing + technology, converting the emissions activity into a physical commodity + amount as follows: + + .. math:: + :label: LinkedEmissionsTech + + - \sum_{I, O} \textbf{FO}_{r, p, s, d, i, t, v, o} \cdot EAC_{r, e, i, t, v, o} + = \sum_{I, O} \textbf{FO}_{r, p, s, d, i, t, v, o} + + \forall \{r, p, s, d, t, v, e\} \in \Theta_{\text{LinkedTechs}} + + The relationship between the primary and linked technologies is given + 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. + """ + + if t in M.tech_annual: + primary_flow = sum( + ( + value(M.DemandSpecificDistribution[r, p, s, d, S_o]) + if S_o in M.commodity_demand + else value(M.SegFrac[p, s, d]) + ) + * M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] + * value(M.EmissionActivity[r, e, S_i, t, v, S_o]) + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + else: + primary_flow = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + * value(M.EmissionActivity[r, e, S_i, t, v, S_o]) + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + + linked_t = M.LinkedTechs[r, t, e] + + # linked_flow = sum( + # M.V_FlowOut[r, p, s, d, S_i, linked_t, v, S_o] + # for S_i in M.processInputs[r, p, linked_t, v] + # for S_o in M.processOutputsByInput[r, p, linked_t, v, S_i] + # ) + + if linked_t in M.tech_annual: + linked_flow = sum( + ( + value(M.DemandSpecificDistribution[r, p, s, d, S_o]) + if S_o in M.commodity_demand + else value(M.SegFrac[p, s, d]) + ) + * M.V_FlowOutAnnual[r, p, S_i, linked_t, v, S_o] + for S_i in M.processInputs[r, p, linked_t, v] + for S_o in M.processOutputsByInput[r, p, linked_t, v, S_i] + ) + else: + linked_flow = sum( + M.V_FlowOut[r, p, s, d, S_i, linked_t, v, S_o] + for S_i in M.processInputs[r, p, linked_t, v] + for S_o in M.processOutputsByInput[r, p, linked_t, v, S_i] + ) + + return -primary_flow == linked_flow diff --git a/temoa/components/geography.py b/temoa/components/geography.py index 474b7c577..0884ded2b 100644 --- a/temoa/components/geography.py +++ b/temoa/components/geography.py @@ -48,3 +48,25 @@ def gather_group_regions(M: 'TemoaModel', region: str) -> Iterable[str]: else: regions = (region,) return regions + + +def RegionalExchangeCapacity_Constraint(M: 'TemoaModel', r_e, r_i, p, t, v): + r""" + + This constraint ensures that the process (t,v) connecting regions + r_e and r_i is handled by one capacity variables. + + .. math:: + :label: RegionalExchangeCapacity + + \textbf{CAP}_{r_e,t,v} + = + \textbf{CAP}_{r_i,t,v} + + \\ + \forall \{r_e, r_i, t, v\} \in \Theta_{\text{RegionalExchangeCapacity}} + """ + + expr = M.V_Capacity[r_e + '-' + r_i, p, t, v] == M.V_Capacity[r_i + '-' + r_e, p, t, v] + + return expr diff --git a/temoa/components/limits.py b/temoa/components/limits.py index 0c73bfed2..e5df3d4e9 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -1,6 +1,13 @@ +import sys from logging import getLogger from typing import TYPE_CHECKING +from pyomo.environ import Constraint, value + +import temoa.components.geography as geography +import temoa.components.technology as technology +from temoa.components.utils import get_variable_efficiency, operator_expression + if TYPE_CHECKING: from temoa.core.model import TemoaModel @@ -144,3 +151,1089 @@ def LimitDegrowthNewCapacityDeltaIndices(M: 'TemoaModel'): for p in M.time_optimize ) return indices + + +# @deprecated('Deprecated. Use LimitActivityGroupShare instead') # doesn't play well with pyomo +def RenewablePortfolioStandard_Constraint(M: 'TemoaModel', r, p, g): + r""" + Allows users to specify the share of electricity generation in a region + coming from RPS-eligible technologies. + """ + # devnote: this formulation leans on the reserve set, which is not necessarily + # the super set we want. We can also generalise this to all groups and so + # it has been deprecated in favour of the LimitActivityGroupShare constraint. + + inp = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for t in M.tech_group_members[g] + for (_t, v) in M.processReservePeriods[r, p] + if _t == t + for s in M.TimeSeason[p] + for d in M.time_of_day + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + + total_inp = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for (t, v) in M.processReservePeriods[r, p] + for s in M.TimeSeason[p] + for d in M.time_of_day + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + + expr = inp >= (value(M.RenewablePortfolioStandard[r, p, g]) * total_inp) + return expr + + +def LimitResource_Constraint(M: 'TemoaModel', r, t, op): + r""" + + The LimitResource constraint sets a limit on the available resource of a + given technology across all model time periods. Note that the indices for these + constraints are region and tech. + + .. math:: + :label: LimitResource + + \sum_{P,S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t \notin T^a, v, o} + + +\sum_{P,I,V,O} \textbf{FO}_{r, p, i, t \in T^a, v, o} + + \le LR_{r, t} + + \forall \{r, t\} \in \Theta_{\text{LimitResource}}""" + # dev note: this constraint is a misnomer. It is actually a "global activity constraint on a tech" + # regardless of whatever "resources" are consumed. + # dev note: this would generally be applied to a "dummy import" technology to restrict something like + # oil/mineral extraction across all model periods. Looks fine to me. + + regions = geography.gather_group_regions(M, r) + techs = technology.gather_group_techs(M, t) + + activity = sum( + M.V_FlowOutAnnual[_r, p, S_i, _t, S_v, S_o] + for _t in techs + if _t in M.tech_annual + for p in M.time_optimize + for _r in regions + if (_r, p, _t) in M.processVintages + 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] + ) + activity += sum( + M.V_FlowOut[_r, p, s, d, S_i, _t, S_v, S_o] + for _t in techs + if _t not in M.tech_annual + for p in M.time_optimize + for _r in regions + if (_r, p, _t) in M.processVintages + 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.TimeSeason[p] + for d in M.time_of_day + ) + + resource_lim = value(M.LimitResource[r, t, op]) + expr = operator_expression(activity, op, resource_lim) + return expr + + +def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): + r""" + Limits the activity of a given technology or group as a fraction of another + technology or group, summed over a period. This can be used to set, for example, + a renewable portfolio scheme constraint. + + .. math:: + :label: Limit Activity Share + + \sum_{R_g \subseteq R,\ S,\ D,\ I,\ T^{g_1} \subseteq T,\ V,\ O} \mathbf{FO}_{r,p,s,d,i,t,v,o} + \leq LAS_{r,p,g_1,g_2} \cdot + \sum_{R_g \subseteq R,\ S,\ D,\ I,\ T^{g_2} \subseteq T,\ V,\ O} \mathbf{FO}_{r,p,s,d,i,t,v,o} + + \qquad \forall \{r, p, g_1, g_2\} \in \Theta_{\text{LimitActivityShare}} + """ + + regions = geography.gather_group_regions(M, r) + + sub_group = technology.gather_group_techs(M, g1) + sub_activity = sum( + M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] + for S_t in sub_group + if S_t not in M.tech_annual + for _r in regions + for S_v in M.processVintages.get((_r, p, S_t), []) + for S_i in M.processInputs[_r, p, S_t, S_v] + for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] + for s in M.TimeSeason[p] + for d in M.time_of_day + ) + sub_activity += sum( + M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] + for S_t in sub_group + if S_t in M.tech_annual + for _r in regions + for S_v in M.processVintages.get((_r, p, S_t), []) + for S_i in M.processInputs[_r, p, S_t, S_v] + for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] + ) + + super_group = technology.gather_group_techs(M, g2) + super_activity = sum( + M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] + for S_t in super_group + if S_t not in M.tech_annual + for _r in regions + for S_v in M.processVintages.get((_r, p, S_t), []) + for S_i in M.processInputs[_r, p, S_t, S_v] + for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] + for s in M.TimeSeason[p] + for d in M.time_of_day + ) + super_activity += sum( + M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] + for S_t in super_group + if S_t in M.tech_annual + for _r in regions + for S_v in M.processVintages.get((_r, p, S_t), []) + for S_i in M.processInputs[_r, p, S_t, S_v] + for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] + ) + + share_lim = value(M.LimitActivityShare[r, p, g1, g2, op]) + expr = operator_expression(sub_activity, op, share_lim * super_activity) + # in the case that there is nothing to sum, skip + if isinstance(expr, bool): # an empty list was generated + return Constraint.Skip + logger.debug( + 'created limit activity share constraint for (%s, %d, %s, %s) of %0.2f', + r, + p, + g1, + g2, + share_lim, + ) + return expr + + +def LimitCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): + r""" + The LimitCapacityShare constraint limits the available capacity of a given + technology or technology group as a fraction of another technology or group. + """ + + regions = geography.gather_group_regions(M, r) + + sub_group = technology.gather_group_techs(M, g1) + sub_capacity = sum( + M.V_CapacityAvailableByPeriodAndTech[_r, p, _t] + for _t in sub_group + for _r in regions + if (_r, p, _t) in M.processVintages + ) + + super_group = technology.gather_group_techs(M, g2) + super_capacity = sum( + M.V_CapacityAvailableByPeriodAndTech[_r, p, _t] + for _t in super_group + for _r in regions + if (_r, p, _t) in M.processVintages + ) + share_lim = value(M.LimitCapacityShare[r, p, g1, g2, op]) + + expr = operator_expression(sub_capacity, op, share_lim * super_capacity) + if isinstance(expr, bool): + return Constraint.Skip + return expr + + +def LimitNewCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): + r""" + The LimitNewCapacityShare constraint limits the share of new capacity + of a given technology or group as a fraction of another technology or + group.""" + + regions = geography.gather_group_regions(M, r) + + sub_group = technology.gather_group_techs(M, g1) + sub_new_cap = sum( + M.V_NewCapacity[_r, _t, p] + for _t in sub_group + for _r in regions + if (_r, _t, p) in M.processPeriods + ) + + super_group = technology.gather_group_techs(M, g2) + super_new_cap = sum( + M.V_NewCapacity[_r, _t, p] + for _t in super_group + for _r in regions + if (_r, _t, p) in M.processPeriods + ) + + share_lim = value(M.LimitNewCapacityShare[r, p, g1, g2, op]) + expr = operator_expression(sub_new_cap, op, share_lim * super_new_cap) + if isinstance(expr, bool): + return Constraint.Skip + return expr + + +def LimitAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o, op): + r""" + The LimitAnnualCapacityFactor 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: LimitAnnualCapacityFactor + + \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMACF_{r, p, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} + + \forall \{r, p, t \notin T^{a}, o\} \in \Theta_{\text{LimitAnnualCapacityFactor}} + + \\\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \ge LIMACF_{r, p, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} + + \forall \{r, p, t \in T^{a}, o\} \in \Theta_{\text{LimitAnnualCapacityFactor}} + """ + # r can be an individual region (r='US'), or a combination of regions separated by plus (r='Mexico+US+Canada'), or 'global'. + # if r == 'global', the constraint is system-wide + regions = geography.gather_group_regions(M, r) + # we need to screen here because it is possible that the restriction extends beyond the + # lifetime of any vintage of the tech... + if all((_r, p, t) not in M.V_CapacityAvailableByPeriodAndTech for _r in regions): + return Constraint.Skip + + if t not in M.tech_annual: + activity_rpt = sum( + M.V_FlowOut[_r, p, s, d, S_i, t, S_v, o] + for _r in regions + for S_v in M.processVintages.get((_r, p, t), []) + for S_i in M.processInputs[_r, p, t, S_v] + for s in M.TimeSeason[p] + for d in M.time_of_day + ) + else: + activity_rpt = sum( + M.V_FlowOutAnnual[_r, p, S_i, t, S_v, o] + for _r in regions + for S_v in M.processVintages.get((_r, p, t), []) + for S_i in M.processInputs[_r, p, t, S_v] + ) + + possible_activity_rpt = sum( + M.V_CapacityAvailableByPeriodAndTech[_r, p, t] * value(M.CapacityToActivity[_r, t]) + for _r in regions + ) + annual_cf = value(M.LimitAnnualCapacityFactor[r, p, t, o, op]) + expr = operator_expression(activity_rpt, op, annual_cf * possible_activity_rpt) + # in the case that there is nothing to sum, skip + if isinstance(expr, bool): # an empty list was generated + return Constraint.Skip + return expr + + +def LimitSeasonalCapacityFactor_Constraint(M: 'TemoaModel', r, p, s, t, op): + r""" + The LimitSeasonalCapacityFactor sets an upper bound on the seasonal 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: Limit Seasonal Capacity Factor + + \sum_{D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMSCF_{r, p, s, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} + + \forall \{r, p, t \notin T^{a}, o\} \in \Theta_{\text{LimitSeasonalCapacityFactor}} + + \\\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \cdot \sum_{D} SEG_{s,d} \le LIMSCF_{r, p, s, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} + + \forall \{r, p, t \in T^{a}, o\} \in \Theta_{\text{LimitSeasonalCapacityFactor}} + """ + # r can be an individual region (r='US'), or a combination of regions separated by plus (r='Mexico+US+Canada'), or 'global'. + # if r == 'global', the constraint is system-wide + regions = geography.gather_group_regions(M, r) + # we need to screen here because it is possible that the restriction extends beyond the + # lifetime of any vintage of the tech... + if all((_r, p, t) not in M.V_CapacityAvailableByPeriodAndTech for _r in regions): + return Constraint.Skip + + if t not in M.tech_annual: + activity_rpst = sum( + M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] + for _r in regions + 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 d in M.time_of_day + ) + else: + activity_rpst = sum( + M.V_FlowOutAnnual[_r, p, S_i, t, S_v, S_o] * M.SegFracPerSeason[p, s] + for _r in regions + 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] + ) + + possible_activity_rpst = sum( + M.V_CapacityAvailableByPeriodAndTech[_r, p, t] + * value(M.CapacityToActivity[_r, t]) + * value(M.SegFracPerSeason[p, s]) + for _r in regions + ) + seasonal_cf = value(M.LimitSeasonalCapacityFactor[r, p, s, t, op]) + expr = operator_expression(activity_rpst, op, seasonal_cf * possible_activity_rpst) + # in the case that there is nothing to sum, skip + if isinstance(expr, bool): # an empty list was generated + return Constraint.Skip + return expr + + +def LimitTechInputSplit_Constraint(M: 'TemoaModel', r, p, s, d, i, t, v, op): + r""" + Allows users to limit shares of commodity inputs to a process + producing a single output. These shares can vary by model time period. See + LimitTechOutputSplit_Constraint for an analogous explanation. Under this constraint, + only the technologies with variable output at the timeslice level (i.e., + NOT in the :code:`tech_annual` set) are considered.""" + inp = sum( + M.V_FlowOut[r, p, s, d, i, t, v, S_o] / get_variable_efficiency(M, r, p, s, d, i, t, v, S_o) + for S_o in M.processOutputsByInput[r, p, t, v, i] + ) + + total_inp = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + / get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + + expr = operator_expression(inp, op, value(M.LimitTechInputSplit[r, p, i, t, op]) * total_inp) + return expr + + +def LimitTechInputSplitAnnual_Constraint(M: 'TemoaModel', r, p, i, t, v, op): + r""" + Allows users to limit shares of commodity inputs to a process + producing a single output. These shares can vary by model time period. See + LimitTechOutputSplitAnnual_Constraint for an analogous explanation. Under this + function, only the technologies with constant annual output (i.e., members + of the :code:`tech_annual` set) are considered.""" + inp = sum( + M.V_FlowOutAnnual[r, p, i, t, v, S_o] / value(M.Efficiency[r, i, t, v, S_o]) + for S_o in M.processOutputsByInput[r, p, t, v, i] + ) + + total_inp = sum( + M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] / value(M.Efficiency[r, S_i, t, v, S_o]) + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + + expr = operator_expression( + inp, op, value(M.LimitTechInputSplitAnnual[r, p, i, t, op]) * total_inp + ) + return expr + + +def LimitTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v, op): + r""" + Allows users to limit shares of commodity inputs to a process + 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 LimitTechInputSplit 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.""" + + inp = sum( + M.V_FlowOut[r, p, S_s, S_d, i, t, v, S_o] + / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) + for S_s in M.TimeSeason[p] + for S_d in M.time_of_day + for S_o in M.processOutputsByInput[r, p, t, v, i] + ) + + total_inp = sum( + M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] + / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) + for S_s in M.TimeSeason[p] + for S_d in M.time_of_day + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, i] + ) + + expr = operator_expression( + inp, op, value(M.LimitTechInputSplitAnnual[r, p, i, t, op]) * total_inp + ) + return expr + + +def LimitTechOutputSplit_Constraint(M: 'TemoaModel', r, p, s, d, t, v, o, op): + r""" + + Some processes take a single input and make multiple outputs, and the user would like to + specify either a constant or time-varying ratio of outputs per unit input. The most + canonical example is an oil refinery. Crude oil is used to produce many different refined + products. In many cases, the modeler would like to limit the share of each refined + product produced by the refinery. + + For example, a hypothetical (and highly simplified) refinery might have a crude oil input + that produces 4 parts diesel, 3 parts gasoline, and 2 parts kerosene. The relative + ratios to the output then are: + + .. math:: + + d = \tfrac{4}{9} \cdot \text{total output}, \qquad + g = \tfrac{3}{9} \cdot \text{total output}, \qquad + k = \tfrac{2}{9} \cdot \text{total output} + + Note that it is possible to specify output shares that sum to less than unity. In such + cases, the model optimizes the remaining share. In addition, it is possible to change the + specified shares by model time period. Under this constraint, only the + technologies with variable output at the timeslice level (i.e., NOT in the + :code:`tech_annual` set) are considered. + + The constraint is formulated as follows: + + .. math:: + :label: LimitTechOutputSplit + + \sum_{I, t \not \in T^{a}} \textbf{FO}_{r, p, s, d, i, t, v, o} + \geq + TOS_{r, p, t, o} \cdot \sum_{I, O, t \not \in T^{a}} \textbf{FO}_{r, p, s, d, i, t, v, o} + + \forall \{r, p, s, d, t, v, o\} \in \Theta_{\text{LimitTechOutputSplit}}""" + out = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, o] for S_i in M.processInputsByOutput[r, p, t, v, o] + ) + + total_out = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + + expr = operator_expression(out, op, value(M.LimitTechOutputSplit[r, p, t, o, op]) * total_out) + return expr + + +def LimitTechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o, op): + r""" + This constraint operates similarly to LimitTechOutputSplit_Constraint. + However, under this function, only the technologies with constant annual + output (i.e., members of the :code:`tech_annual` set) are considered. + + .. math:: + :label: LimitTechOutputSplitAnnual + + \sum_{I, T^{a}} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} + \geq + TOS_{r, p, t, o} \cdot \sum_{I, O, T^{a}} \textbf{FOA}_{r, p, s, d, i, t \in T^{a}, v, o} + + \forall \{r, p, t \in T^{a}, v, o\} \in \Theta_{\text{LimitTechOutputSplitAnnual}}""" + out = sum( + M.V_FlowOutAnnual[r, p, S_i, t, v, o] for S_i in M.processInputsByOutput[r, p, t, v, o] + ) + + total_out = sum( + M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + + expr = operator_expression( + out, op, value(M.LimitTechOutputSplitAnnual[r, p, t, o, op]) * total_out + ) + return expr + + +def LimitTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o, op): + r""" + Allows users to limit shares of commodity outputs from a process. + 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 LimitTechOutputSplit 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 output shares over the course of a year.""" + + out = sum( + M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, o] + for S_i in M.processInputsByOutput[r, p, t, v, o] + for S_s in M.TimeSeason[p] + for S_d in M.time_of_day + ) + + total_out = sum( + M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + for S_s in M.TimeSeason[p] + for S_d in M.time_of_day + ) + + expr = operator_expression( + out, op, value(M.LimitTechOutputSplitAnnual[r, p, t, o, op]) * total_out + ) + return expr + + +def LimitEmission_Constraint(M: 'TemoaModel', r, p, e, op): + r""" + + A modeler can track emissions through use of the :code:`commodity_emissions` + set and :code:`EmissionActivity` parameter. The :math:`EAC` parameter is + analogous to the efficiency table, tying emissions to a unit of activity. The + LimitEmission constraint allows the modeler to assign an upper bound per period + to each emission commodity. Note that this constraint sums emissions from + technologies with output varying at the time slice and those with constant annual + output in separate terms. + + .. math:: + :label: LimitEmission + + \sum_{S,D,I,T,V,O|{r,e,i,t,v,o} \in EAC} \left ( + EAC_{r, e, i, t, v, o} \cdot \textbf{FO}_{r, p, s, d, i, t, v, o} + \right ) & \\ + + + \sum_{I,T,V,O|{r,e,i,t \in T^{a},v,o} \in EAC} ( + EAC_{r, e, i, t, v, o} \cdot & \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} + ) + \le + ELM_{r, p, e} + + \\ + & \forall \{r, p, e\} \in \Theta_{\text{LimitEmission}} + + """ + emission_limit = value(M.LimitEmission[r, p, e, op]) + + # 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 + + regions = geography.gather_group_regions(M, r) + + # ================= Emissions and Flex and Curtailment ================= + # Flex flows are deducted from V_FlowOut, so it is NOT NEEDED to tax them again. (See commodity balance constr) + # Curtailment does not draw any inputs, so it seems logical that curtailed flows not be taxed either + + process_emissions = sum( + M.V_FlowOut[reg, p, S_s, S_d, S_i, S_t, S_v, S_o] + * value(M.EmissionActivity[reg, e, S_i, S_t, S_v, S_o]) + for reg in regions + for tmp_r, tmp_e, S_i, S_t, S_v, S_o in M.EmissionActivity.sparse_iterkeys() + if tmp_e == e and tmp_r == reg and S_t not in M.tech_annual + # EmissionsActivity not indexed by p, so make sure (r,p,t,v) combos valid + if (reg, p, S_t, S_v) in M.processInputs + for S_s in M.TimeSeason[p] + for S_d in M.time_of_day + ) + + process_emissions_annual = sum( + M.V_FlowOutAnnual[reg, p, S_i, S_t, S_v, S_o] + * value(M.EmissionActivity[reg, e, S_i, S_t, S_v, S_o]) + for reg in regions + for tmp_r, tmp_e, S_i, S_t, S_v, S_o in M.EmissionActivity.sparse_iterkeys() + if tmp_e == e and tmp_r == reg and S_t in M.tech_annual + # EmissionsActivity not indexed by p, so make sure (r,p,t,v) combos valid + if (reg, p, S_t, S_v) in M.processInputs + ) + + embodied_emissions = sum( + M.V_NewCapacity[reg, t, v] + * value(M.EmissionEmbodied[reg, e, t, v]) + / value(M.PeriodLength[v]) + for reg in regions + for (S_r, S_e, t, v) in M.EmissionEmbodied.sparse_iterkeys() + if v == p and S_r == reg and S_e == e + ) + + retirement_emissions = sum( + M.V_AnnualRetirement[reg, p, t, v] * value(M.EmissionEndOfLife[reg, e, t, v]) + for reg in regions + for (S_r, S_e, t, v) in M.EmissionEndOfLife.sparse_iterkeys() + if (r, t, v) in M.retirementPeriods and p in M.retirementPeriods[r, t, v] + if S_r == reg and S_e == e + ) + + lhs = ( + process_emissions + process_emissions_annual + embodied_emissions + retirement_emissions + # + emissions_flex # NO! flex is subtracted from flowout, already accounted by flowout + # + emissions_curtail # NO! curtailed flows are not actual flows, just an accounting tool + # + emissions_flex_annual # NO! flexannual is subtracted from flowoutannual, already accounted + ) + expr = operator_expression(lhs, op, emission_limit) + + # in the case that there is nothing to sum, skip + if isinstance(expr, bool): # an empty list was generated + msg = "Warning: No technology produces emission '%s', though limit was specified as %s.\n" + logger.warning(msg, (e, emission_limit)) + sys.stderr.write(msg % (e, emission_limit)) + return Constraint.Skip + + return expr + + +def LimitGrowthCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): + r"""Constrain ramp up rate of available capacity""" + return LimitGrowthCapacity(M, r, p, t, op, False) + + +def LimitDegrowthCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): + r"""Constrain ramp down rate of available capacity""" + return LimitGrowthCapacity(M, r, p, t, op, True) + + +def LimitGrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): + r""" + Constrain the change of capacity available between periods. + Forces the model to ramp up and down the availability of new technologies + more smoothly. Has constant (seed, :math:`S_{r,t}`) and proportional + (rate, :math:`R_{r,t}`) terms. This can be defined for a technology group + instead of one technology, in which case, capacity available is summed over + all technologies in the group. In the first period, previous available + capacity :math:`\mathbf{CAPAVL}_{r,p,t}` is replaced by previous existing + capacity, if any can be found. + + .. math:: + :label: Limit (De)Growth Capacity + + \begin{aligned}\text{Growth:}\\ + &\mathbf{CAPAVL}_{r,p,t} + \leq S_{r,t} + (1+R_{r,t}) \cdot \mathbf{CAPAVL}_{r,p_{prev},t} + \end{aligned} + + \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitGrowthCapacity}} + + + \begin{aligned}\text{Degrowth:}\\ + &\mathbf{CAPAVL}_{r,p_{prev},t} + \leq S_{r,t} + (1+R_{r,t}) \cdot \mathbf{CAPAVL}_{r,p,t} + \end{aligned} + + \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitDegrowthCapacity}} + """ + + regions = geography.gather_group_regions(M, r) + techs = technology.gather_group_techs(M, t) + + growth = M.LimitDegrowthCapacity if degrowth else M.LimitGrowthCapacity + RATE = 1 + value(growth[r, t, op][0]) + SEED = value(growth[r, t, op][1]) + CapRPT = M.V_CapacityAvailableByPeriodAndTech + + # relevant r, p, t indices + cap_rpt = set((_r, _p, _t) for _r, _p, _t in CapRPT.keys() if _t in techs and _r in regions) + # periods the technology can have capacity in this region (sorted) + periods = sorted(set(_p for _r, _p, _t in cap_rpt)) + + if len(periods) == 0: + if p == M.time_optimize.first(): + msg = ( + 'Tried to set {}rowthCapacity constraint {} but there are no periods where this ' + 'technology is available in this region. Constraint skipped.' + ).format('Deg' if degrowth else 'G', (r, t)) + logger.warning(msg) + return Constraint.Skip + + # Only warn in p0 so we dont dump multiple warnings + if p == periods[0]: + if SEED == 0: + msg = ( + 'No constant term (seed) provided for {}rowthCapacity constraint {}. ' + 'No capacity will be built in any period following one with zero capacity.' + ).format('Deg' if degrowth else 'G', (r, t)) + logger.info(msg) + gaps = [ + _p for _p in M.time_optimize if _p not in periods and min(periods) < _p < max(periods) + ] + if gaps: + msg = ( + 'Constructing {}rowthCapacity constraint {} and there are period gaps in which' + 'capacity cannot exist in this region ({}). Capacity in these periods ' + 'will be treated as zero which may cause infeasibility or other problems.' + ).format('Deg' if degrowth else 'G', (r, t), gaps) + logger.warning(msg) + + # sum available capacity in this period + capacity = sum(CapRPT[_r, _p, _t] for _r, _p, _t in cap_rpt if _p == p) + + if p == M.time_optimize.first(): + # First future period. Grab available capacity in last existing period + # Adjust in-line for past PLF because we are constraining available capacity + p_prev = M.time_exist.last() + capacity_prev = sum( + value(M.ExistingCapacity[_r, _t, _v]) + * min(1.0, (_v + value(M.LifetimeProcess[_r, _t, _v]) - p_prev) / (p - p_prev)) + for _r, _t, _v in M.ExistingCapacity.sparse_iterkeys() + if _r in regions and _t in techs and _v + value(M.LifetimeProcess[_r, _t, _v]) > p_prev + ) + else: + # Otherwise, grab previous future period + p_prev = M.time_optimize.prev(p) + capacity_prev = sum(CapRPT[_r, _p, _t] for _r, _p, _t in cap_rpt if _p == p_prev) + + if degrowth: + expr = operator_expression(capacity_prev, op, SEED + capacity * RATE) + else: + expr = operator_expression(capacity, op, SEED + capacity_prev * RATE) + + # Check if any variables are actually included before returning + if isinstance(expr, bool): + return Constraint.Skip + return expr + + +def LimitGrowthNewCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): + r"""Constrain ramp up rate of new capacity deployment""" + return LimitGrowthNewCapacity(M, r, p, t, op, False) + + +def LimitDegrowthNewCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): + r"""Constrain ramp down rate of new capacity deployment""" + return LimitGrowthNewCapacity(M, r, p, t, op, True) + + +def LimitGrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): + r""" + Constrain the change of new capacity deployed between periods. + Forces the model to ramp up and down the deployment of new technologies + more smoothly. Has constant (seed, :math:`S_{r,t}`) and proportional + (rate, :math:`R_{r,t}`) terms. This can be defined for a technology group + instead of one technology, in which case, new capacity is summed over + all technologies in the group. In the first period, previous new capacity + :math:`\mathbf{NCAP}_{r,t,v_prev}` is replaced by previous existing capacity, + if any can be found. + + .. math:: + :label: Limit (De)Growth New Capacity + + \begin{aligned}\text{Growth:}\\ + &\mathbf{NCAP}_{r,t,v} + \leq S_{r,t} + (1+R_{r,t}) \cdot \mathbf{NCAP}_{r,t,v_{prev}} + \text{ where } v=p + \end{aligned} + + \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitGrowthCapacity}} + + \begin{aligned}\text{Degrowth:}\\ + &\mathbf{NCAP}_{r,t,v_{prev}} + \leq S_{r,t} + (1+R_{r,t}) \cdot \mathbf{NCAP}_{r,t,v} + \text{ where } v=p + \end{aligned} + + \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitDegrowthCapacity}} + """ + + regions = geography.gather_group_regions(M, r) + techs = technology.gather_group_techs(M, t) + + growth = M.LimitDegrowthNewCapacity if degrowth else M.LimitGrowthNewCapacity + RATE = 1 + value(growth[r, t, op][0]) + SEED = value(growth[r, t, op][1]) + NewCapRTV = M.V_NewCapacity + + # relevant r, t, v indices + cap_rtv = set((_r, _t, _v) for _r, _t, _v in NewCapRTV.keys() if _t in techs and _r in regions) + # periods the technology can be built in this region (sorted) + periods = sorted(set(_v for _r, _t, _v in cap_rtv)) + + if len(periods) == 0: + if p == M.time_optimize.first(): + msg = ( + 'Tried to set {}rowthNewCapacity constraint {} but there are no periods where this ' + 'technology can be built in this region. Constraint skipped.' + ).format('Deg' if degrowth else 'G', (r, t)) + logger.warning(msg) + return Constraint.Skip + + # Only warn in p0 so we dont dump multiple warnings + if p == periods[0]: + if SEED == 0: + msg = ( + 'No constant term (seed) provided for {}rowthNewCapacity constraint {}. ' + 'No capacity will be built in any period following one with zero new capacity.' + ).format('Deg' if degrowth else 'G', (r, t)) + logger.info(msg) + gaps = [ + _p for _p in M.time_optimize if _p not in periods and min(periods) < _p < max(periods) + ] + if gaps: + msg = ( + 'Constructing {}rowthNewCapacity constraint {} and there are period gaps in which' + 'new capacity cannot be built in this region ({}). New capacity in these periods ' + 'will be treated as zero which may cause infeasibility or other problems.' + ).format('Deg' if degrowth else 'G', (r, t), gaps) + logger.warning(msg) + + # sum new capacity in this period + new_cap = sum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p) + + if p == M.time_optimize.first(): + # First future period. Grab last existing vintage + p_prev = M.time_exist.last() + new_cap_prev = sum( + value(M.ExistingCapacity[_r, _t, _v]) + for _r, _t, _v in M.ExistingCapacity.sparse_iterkeys() + if _r in regions and _t in techs and _v == p_prev + ) + else: + # Otherwise, grab previous future vintage + p_prev = M.time_optimize.prev(p) + new_cap_prev = sum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p_prev) + + if degrowth: + expr = operator_expression(new_cap_prev, op, SEED + new_cap * RATE) + else: + expr = operator_expression(new_cap, op, SEED + new_cap_prev * RATE) + + # Check if any variables are actually included before returning + if isinstance(expr, bool): + return Constraint.Skip + return expr + + +def LimitGrowthNewCapacityDeltaConstraint_rule(M: 'TemoaModel', r, p, t, op): + r"""Constrain ramp up rate of change in new capacity deployment""" + return LimitGrowthNewCapacityDelta(M, r, p, t, op, False) + + +def LimitDegrowthNewCapacityDeltaConstraint_rule(M: 'TemoaModel', r, p, t, op): + r"""Constrain ramp down rate of change in new capacity deployment""" + return LimitGrowthNewCapacityDelta(M, r, p, t, op, True) + + +def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): + r""" + Constrain the acceleration of new capacity deployed between periods. + Forces the model to ramp up and down the change in deployment of new technologies + more smoothly. Has constant (seed, :math:`S_{r,t}`) and proportional + (rate, :math:`R_{r,t}`) terms. It is recommended to leave the rate term empty + as it would prevent the possibility of inflection in the rate of deployment. + This constraint can be defined for a technology group instead of one technology, + in which case, new capacity is summed over all technologies in the group. In the + first period, previous new capacities are replaced by previous existing capacities, + if any can be found. + + .. math:: + :label: Limit (De)Growth New Capacity Delta + + \begin{aligned}\text{Growth:}\\ + &\mathbf{NCAP}_{r,t,v_i} - \mathbf{NCAP}_{r,t,v_{i-1}} + \leq S_{r,t} + (1+R_{r,t}) \cdot (\mathbf{NCAP}_{r,t,v_{i-1}} - \mathbf{NCAP}_{r,t,v_{i-2}}) + \end{aligned} + + \text{ where } v_i=p + + \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitGrowthCapacityDelta}} + + \begin{aligned}\text{Degrowth:}\\ + &\mathbf{NCAP}_{r,t,v_{i-1}} - \mathbf{NCAP}_{r,t,v_{i-2}} + \leq S_{r,t} + (1+R_{r,t}) \cdot (\mathbf{NCAP}_{r,t,v_i} - \mathbf{NCAP}_{r,t,v_{i-1}}) + \end{aligned} + + \text{ where } v_i=p + + \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitDegrowthCapacityDelta}} + """ + + regions = geography.gather_group_regions(M, r) + techs = technology.gather_group_techs(M, t) + + growth = M.LimitDegrowthNewCapacityDelta if degrowth else M.LimitGrowthNewCapacityDelta + RATE = 1 + value(growth[r, t, op][0]) + SEED = value(growth[r, t, op][1]) + NewCapRTV = M.V_NewCapacity + + # relevant r, t, v indices + cap_rtv = set((_r, _t, _v) for _r, _t, _v in NewCapRTV.keys() if _t in techs and _r in regions) + # periods the technology can be built in this region (sorted) + periods = sorted(set(_v for _r, _t, _v in cap_rtv)) + + if len(periods) == 0: + if p == M.time_optimize.first(): + msg = ( + 'Tried to set {}rowthNewCapacityDelta constraint {} but there are no periods where this ' + 'technology can be built in this region. Constraint skipped.' + ).format('Deg' if degrowth else 'G', (r, t)) + logger.warning(msg) + return Constraint.Skip + + # Only warn in p0 so we dont dump multiple warnings + if p == periods[0]: + if SEED == 0: + msg = ( + 'No constant term (seed) provided for {}rowthNewCapacityDelta constraint {}. ' + 'This is not recommended as deployment rates cannot inflect (change from ' + 'accelerating to decelerating or vice-versa).' + ).format('Deg' if degrowth else 'G', (r, t)) + logger.warning(msg) + gaps = [ + _p for _p in M.time_optimize if _p not in periods and min(periods) < _p < max(periods) + ] + if gaps: + msg = ( + 'Constructing {}rowthNewCapacityDelta constraint {} and there are period gaps in which' + 'new capacity cannot be built in this region ({}). New capacity in these periods ' + 'will be treated as zero which may cause infeasibility or other problems.' + ).format('Deg' if degrowth else 'G', (r, t), gaps) + logger.warning(msg) + + # sum new capacity in this period + new_cap = sum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p) + + if p == M.time_optimize.first(): + # First planning period, pull last two existing vintages + p_prev = M.time_exist.last() + new_cap_prev = sum( + value(M.ExistingCapacity[_r, _t, _v]) + for _r, _t, _v in M.ExistingCapacity.sparse_iterkeys() + if _r in regions and _t in techs and _v == p_prev + ) + p_prev2 = M.time_exist.prev(p_prev) + new_cap_prev2 = sum( + value(M.ExistingCapacity[_r, _t, _v]) + for _r, _t, _v in M.ExistingCapacity.sparse_iterkeys() + if _r in regions and _t in techs and _v == p_prev2 + ) + else: + # Not the first future period. Grab previous future period + p_prev = M.time_optimize.prev(p) + new_cap_prev = sum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p_prev) + if p == M.time_optimize.at(2): # apparently pyomo sets are indexed 1-based + # Second future period, grab last existing vintage + p_prev2 = M.time_exist.last() + new_cap_prev2 = sum( + value(M.ExistingCapacity[_r, _t, _v]) + for _r, _t, _v in M.ExistingCapacity.sparse_iterkeys() + if _r in regions and _t in techs and _v == p_prev2 + ) + else: + # At least the third future period. Grab last two future vintages + p_prev2 = M.time_optimize.prev(p_prev) + new_cap_prev2 = sum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p_prev2) + + nc_delta_prev = new_cap_prev - new_cap_prev2 + nc_delta = new_cap - new_cap_prev + + if degrowth: + expr = operator_expression(nc_delta_prev, op, SEED + nc_delta * RATE) + else: + expr = operator_expression(nc_delta, op, SEED + nc_delta_prev * RATE) + + # Check if any variables are actually included before returning + if isinstance(expr, bool): + return Constraint.Skip + return expr + + +def LimitActivity_Constraint(M: 'TemoaModel', r, p, t, op): + r""" + + Sets a limit on the activity from a specific technology. + Note that the indices for these constraints are region, period and tech, not tech + and vintage. The first version of the constraint pertains to technologies with + variable output at the time slice level, and the second version pertains to + technologies with constant annual output belonging to the :code:`tech_annual` + set. + + .. math:: + :label: LimitActivity + + \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} + + \forall \{r, p, t \notin T^{a}\} \in \Theta_{\text{LimitActivity}} + + +\sum_{I,V,O} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} + + \forall \{r, p, t \in T^{a}\} \in \Theta_{\text{LimitActivity}} + + \le LA_{r, p, t} + """ + # r can be an individual region (r='US'), or a combination of regions separated by + # a + (r='Mexico+US+Canada'), or 'global'. + # if r == 'global', the constraint is system-wide + regions = geography.gather_group_regions(M, r) + techs = technology.gather_group_techs(M, t) + + activity = sum( + M.V_FlowOut[_r, p, s, d, S_i, _t, S_v, S_o] + for _t in techs + if _t not in M.tech_annual + for _r in regions + for S_v in M.processVintages.get((_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.TimeSeason[p] + for d in M.time_of_day + ) + activity += sum( + M.V_FlowOutAnnual[_r, p, S_i, _t, S_v, S_o] + for _t in techs + if _t in M.tech_annual + for _r in regions + for S_v in M.processVintages.get((_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] + ) + + act_lim = value(M.LimitActivity[r, p, t, op]) + expr = operator_expression(activity, op, act_lim) + # in the case that there is nothing to sum, skip + if isinstance(expr, bool): # an empty list was generated + return Constraint.Skip + return expr + + +def LimitNewCapacity_Constraint(M: 'TemoaModel', r, p, t, op): + r""" + The LimitNewCapacity constraint sets a limit on the newly installed capacity of a + given technology or group in a given year. Note that the indices for these constraints are region, + period and tech. + + .. math:: + :label: LimitNewCapacity + + \textbf{NCAP}_{r, t, v} \le LNC_{r, p, t} + + \text{where }v=p + """ + regions = geography.gather_group_regions(M, r) + techs = technology.gather_group_techs(M, t) + cap_lim = value(M.LimitNewCapacity[r, p, t, op]) + new_cap = sum(M.V_NewCapacity[_r, _t, p] for _t in techs for _r in regions) + expr = operator_expression(new_cap, op, cap_lim) + return expr + + +def LimitCapacity_Constraint(M: 'TemoaModel', r, p, t, op): + r""" + + The LimitCapacity constraint sets a limit on the available capacity of a + given technology. Note that the indices for these constraints are region, period and + tech, not tech and vintage. + + .. math:: + :label: LimitCapacity + + \textbf{CAPAVL}_{r, p, t} \le LC_{r, p, t} + + \forall \{r, p, t\} \in \Theta_{\text{LimitCapacity}}""" + regions = geography.gather_group_regions(M, r) + techs = technology.gather_group_techs(M, t) + cap_lim = value(M.LimitCapacity[r, p, t, op]) + capacity = sum( + M.V_CapacityAvailableByPeriodAndTech[_r, p, _t] for _t in techs for _r in regions + ) + expr = operator_expression(capacity, op, cap_lim) + return expr diff --git a/temoa/components/operations.py b/temoa/components/operations.py index 03088f69c..edc5ae831 100644 --- a/temoa/components/operations.py +++ b/temoa/components/operations.py @@ -1,5 +1,7 @@ from typing import TYPE_CHECKING +from pyomo.environ import Constraint, value + if TYPE_CHECKING: from temoa.core.model import TemoaModel @@ -14,3 +16,72 @@ def BaseloadDiurnalConstraintIndices(M: 'TemoaModel'): ) return indices + + +def BaseloadDiurnal_Constraint(M: 'TemoaModel', r, p, s, d, t, v): + r""" + + Some electric generators cannot ramp output over a short period of time (e.g., + hourly or daily). Temoa models this behavior by forcing technologies in the + :code:`tech_baseload` set to maintain a constant output across all times-of-day + within the same season. Note that the output of a baseload process can vary + between seasons. + + Ideally, this constraint would not be necessary, and baseload processes would + simply not have a :math:`d` index. However, implementing the more efficient + functionality is currently on the Temoa TODO list. + + .. math:: + :label: BaseloadDaily + + SEG_{s, D_0} + \cdot \sum_{I, O} \textbf{FO}_{r, p, s, d,i, t, v, o} + = + SEG_{s, d} + \cdot \sum_{I, O} \textbf{FO}_{r, p, s, D_0,i, t, v, o} + + \\ + \forall \{r, p, s, d, t, v\} \in \Theta_{\text{BaseloadDiurnal}} + """ + # Question: How to set the different times of day equal to each other? + + # Step 1: Acquire a "canonical" representation of the times of day + l_times = sorted(M.time_of_day) # i.e. a sorted Python list. + # This is the commonality between invocations of this method. + + index = l_times.index(d) + if 0 == index: + # When index is 0, it means that we've reached the beginning of the array + # For the algorithm, this is a terminating condition: do not create + # an effectively useless constraint + return Constraint.Skip + + # Step 2: Set the rest of the times of day equal in output to the first. + # i.e. create a set of constraints that look something like: + # tod[ 2 ] == tod[ 1 ] + # tod[ 3 ] == tod[ 1 ] + # tod[ 4 ] == tod[ 1 ] + # and so on ... + d_0 = l_times[0] + + # Step 3: the actual expression. For baseload, must compute the /average/ + # activity over the segment. By definition, average is + # (segment activity) / (segment length) + # So: (ActA / SegA) == (ActB / SegB) + # computationally, however, multiplication is cheaper than division, so: + # (ActA * SegB) == (ActB * SegA) + activity_sd = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + + activity_sd_0 = sum( + M.V_FlowOut[r, p, s, d_0, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + + expr = activity_sd * value(M.SegFrac[p, s, d_0]) == activity_sd_0 * value(M.SegFrac[p, s, d]) + + return expr diff --git a/temoa/components/ramping.py b/temoa/components/ramping.py index 5009e9fce..bc80f14cd 100644 --- a/temoa/components/ramping.py +++ b/temoa/components/ramping.py @@ -1,10 +1,14 @@ from typing import TYPE_CHECKING +from logging import getLogger +from pyomo.environ import Constraint, value from pyomo.core import Set if TYPE_CHECKING: from temoa.core.model import TemoaModel +logger = getLogger(__name__) + def RampUpDayConstraintIndices(M: 'TemoaModel'): indices = set( @@ -71,3 +75,297 @@ def RampDownSeasonConstraintIndices(M: 'TemoaModel'): ) return indices + + +def RampUpDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): + r""" + One of two constraints built from the RampUpHourly table, along with the + RampUpSeason_Constraint. RampUpDay constrains ramp rates between time slices + within each season and RampUpSeason constrains ramp rates between sequential + seasons. If the :code:`time_sequencing` parameter is set to :code:`consecutive_days` + then the RampUpSeason constraint is skipped as seasons already connect together. + + The ramp rate constraint is utilized to limit the rate of electricity generation + increase and decrease between two adjacent time slices in order to account for + physical limits associated with thermal power plants. This constraint is only + applied to technologies in the set :code:`tech_upramping`. We assume for + simplicity the rate limits do not vary with technology vintage. The ramp rate + limits for a technology should be expressed in percentage of its rated capacity + per hour. + + In a representative periods or seasonal time slices model, the next time slice, + :math:`(s_{next},d_{next})`, from the end of each season, :math:`(s,d_{last})` + is the beginning of the same season, :math:`(s,d_{first})` + + .. math:: + :label: RampUpDay + + \frac{ + \sum_{I,O} \mathbf{FO}_{r,p,s_{next},d_{next},i,t,v,o} + }{ + SEG_{r,p,s_{next},d_{next}} \cdot 24 \cdot DPP + } + - + \frac{ + \sum_{I,O} \mathbf{FO}_{r,p,s,d,i,t,v,o} + }{ + SEG_{r,p,s,d} \cdot 24 \cdot DPP + } + \leq + R_{r,t} \cdot \Delta H_{r,p,s,d,s_{next},d_{next}} \cdot CAP_{r,p,t,v} \cdot C2A_{r,t} + \\ + \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampUpDay}} + \\ + \text{where: } \Delta H_{r,p,s,d,s_{next},d_{next}} = \frac{24}{2} + \left ( \frac{SEG_{r,p,s,d}}{\sum_{D} SEG_{r,p,s,d'}} + + \frac{SEG_{r,p,s_{next},d_{next}}}{\sum_{D} SEG_{r,p,s_{next},d'}} \right ) + + where: + + - :math:`SEG_{r,p,s,d}` is the fraction of the period in time slice :math:`(s,d)` + - :math:`DPP` is the number of days in each period + - :math:`R_{r,t}` is the ramp rate per hour + - :math:`\Delta H_{r,p,s,d,s_{next},d_{next}}` is the number of elapsed hours between midpoints of time slices + - :math:`CAP \cdot C2A` gives the maximum hourly change in activity + """ + + s_next, d_next = M.time_next[p, s, d] + + # How many hours does this time slice represent + hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 + + hourly_activity_sd = ( + sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) + + hourly_activity_sd_next = ( + sum( + M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) + + # elapsed hours from middle of this time slice to middle of next time slice + hours_elapsed = ( + 24 + / 2 + * ( + value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) + + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + ) + ) + ramp_fraction = hours_elapsed * value(M.RampUpHourly[r, t]) + + if ramp_fraction >= 1: + msg = ( + 'Warning: Hourly ramp up rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' + f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' + ) + logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) + return Constraint.Skip + + activity_increase = hourly_activity_sd_next - hourly_activity_sd # opposite sign from rampdown + rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) + expr = activity_increase <= rampable_activity + + return expr + + +def RampDownDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): + r""" + + Similar to the :code`RampUpDay` constraint, we use the :code:`RampDownDay` + constraint to limit ramp down rates between any two adjacent time slices. + + .. math:: + :label: RampDownDay + + \frac{ + \sum_{I,O} \mathbf{FO}_{r,p,s,d,i,t,v,o} + }{ + SEG_{r,p,s,d} \cdot 24 \cdot DPP + } + - + \frac{ + \sum_{I,O} \mathbf{FO}_{r,p,s_{next},d_{next},i,t,v,o} + }{ + SEG_{r,p,s_{next},d_{next}} \cdot 24 \cdot DPP + } + \leq + R_{r,t} \cdot \Delta H_{r,p,s,d,s_{next},d_{next}} \cdot CAP_{r,p,t,v} \cdot C2A_{r,t} + \\ + \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampDownDay}} + """ + + s_next, d_next = M.time_next[p, s, d] + + # How many hours does this time slice represent + hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 + + hourly_activity_sd = ( + sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) + + hourly_activity_sd_next = ( + sum( + M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) + + # elapsed hours from middle of this time slice to middle of next time slice + hours_elapsed = ( + 24 + / 2 + * ( + value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) + + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + ) + ) + ramp_fraction = hours_elapsed * value(M.RampDownHourly[r, t]) + + if ramp_fraction >= 1: + msg = ( + 'Warning: Hourly ramp down rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' + f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' + ) + logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) + return Constraint.Skip + + activity_decrease = hourly_activity_sd - hourly_activity_sd_next # opposite sign from rampup + rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) + expr = activity_decrease <= rampable_activity + + return expr + + +def RampUpSeason_Constraint(M: 'TemoaModel', r, p, s, s_next, t, v): + r""" + Constrains the ramp up rate of activity between time slices at the boundary + of sequential seasons. Same as RampUpDay but only applies to the boundary + between sequential seasons, i.e., :math:`(s^{seq},d_{last})` to :math:`(s^{seq}_{next},d_{first})` + and :math:`s^{seq}_{next}` is based on the TimeSequential table rather than the + TimeSeason table. + """ + + d = M.time_of_day.last() + d_next = M.time_of_day.first() + + # How many hours does this time slice represent + hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 + + hourly_activity_sd = ( + sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) + + hourly_activity_sd_next = ( + sum( + M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) + + # elapsed hours from middle of this time slice to middle of next time slice + hours_elapsed = ( + 24 + / 2 + * ( + value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) + + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + ) + ) + ramp_fraction = hours_elapsed * value(M.RampUpHourly[r, t]) + + if ramp_fraction >= 1: + msg = ( + 'Warning: Hourly ramp up rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' + f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' + ) + logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) + return Constraint.Skip + + activity_increase = hourly_activity_sd_next - hourly_activity_sd # opposite sign from rampdown + rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) + expr = activity_increase <= rampable_activity + + return expr + + +def RampDownSeason_Constraint(M: 'TemoaModel', r, p, s, s_next, t, v): + r""" + Constrains the ramp down rate of activity between time slices at the boundary + of sequential seasons. Same as RampDownDay but only applies to the boundary + between sequential seasons, i.e., :math:`(s^{seq},d_{last})` to :math:`(s^{seq}_{next},d_{first})` + and :math:`s^{seq}_{next}` is based on the TimeSequential table rather than the + TimeSeason table. + """ + + d = M.time_of_day.last() + d_next = M.time_of_day.first() + + # How many hours does this time slice represent + hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 + + hourly_activity_sd = ( + sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) + + hourly_activity_sd_next = ( + sum( + M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) + + # elapsed hours from middle of this time slice to middle of next time slice + hours_elapsed = ( + 24 + / 2 + * ( + value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) + + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + ) + ) + ramp_fraction = hours_elapsed * value(M.RampDownHourly[r, t]) + + if ramp_fraction >= 1: + msg = ( + 'Warning: Hourly ramp down rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' + f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' + ) + logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) + return Constraint.Skip + + activity_decrease = hourly_activity_sd - hourly_activity_sd_next # opposite sign from rampup + rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) + expr = activity_decrease <= rampable_activity + + return expr diff --git a/temoa/components/reserves.py b/temoa/components/reserves.py index 296ea5a00..b5407d358 100644 --- a/temoa/components/reserves.py +++ b/temoa/components/reserves.py @@ -1,8 +1,15 @@ +from logging import getLogger from typing import TYPE_CHECKING +from pyomo.environ import Constraint, value + +from .utils import get_variable_efficiency + if TYPE_CHECKING: from temoa.core.model import TemoaModel +logger = getLogger(__name__) + def ReserveMarginIndices(M: 'TemoaModel'): indices = set( @@ -15,3 +22,267 @@ def ReserveMarginIndices(M: 'TemoaModel'): ) return indices + + +def ReserveMarginDynamic(M: 'TemoaModel', r, p, s, d): + r""" + A dynamic alternative to the traditional, static reserve margin constraint. Capacity values + are calculated from availability of generation in each hour—like an operating reserve margin—\ + accounting for a capacity derate factor subtracting, for example, forced outage due to icing. + + .. math:: + :label: reserve_margin_dynamic + + &\sum_{t \in T^{res} \setminus T^{x} \setminus T^s,\ V} CFP_{r,p,s^*,d^*,t,v}\ + \cdot RCD_{r,p,s^*,t,v}\ + \cdot \mathbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*}\ + \cdot C2A_{r,t} \\ + &+ \sum_{t \in T^{res} \cap T^{x} \setminus T^s,\ V} CFP_{r_i - r, p, s^*, d^*, t, v}\ + \cdot RCD_{r_i - r, p, s^*, t, v}\ + \cdot \mathbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*}\ + \cdot C2A_{r_i - r, t} \\ + &- \sum_{t \in T^{res} \cap T^{x} \setminus T^s,\ V} CFP_{r - r_i, p, s^*, d^*, t, v}\ + \cdot RCD_{r - r_i, p, s^*, t, v}\ + \cdot \mathbf{CAPAVL}_{p,t}\ + \cdot SEG_{s^*,d^*} \cdot C2A_{r - r_i, t} \\ + &+ \sum_{t \in (T^s \cap T^{res}), V, I, O} \ + \left(\ + \mathbf{FO}_{r,p,s,d,i,t,v,o} - \mathbf{FI}_{r,p,s,d,i,t,v,o}\ + \right)\ + \cdot RCD_{r,p,s,t,v} \\ + &\geq\ + \left[\ + \sum_{t \in T^{res} \setminus T^{x}, V, I, O}\ + \mathbf{FO}_{r, p, s, d, i, t, v, o}\ + \right. \\ + &+ \sum_{t \in T^{res} \cap T^{x}, V, I, O} \ + \mathbf{FO}_{r_i - r, p, s, d, i, t, v, o} \\ + &- \sum_{t \in T^{res} \cap T^{x}, V, I, O} \ + \mathbf{FI}_{r - r_i, p, s, d, i, t, v, o} \\ + &- \left. \sum_{t \in T^{res} \cap T^{s}, V, I, O} \ + \mathbf{FI}_{r, p, s, d, i, t, v, o} \right] \cdot (1 + PRM_r) \\ + \\ + &\qquad \qquad \forall \{r, p, s, d\} \in \ + \Theta_{\text{ReserveMargin}} \text{ and } \forall r_i \in R + """ + if (not M.tech_reserve) or ( + (r, p) not in M.processReservePeriods + ): # If reserve set empty or if r,p not in M.processReservePeriod, skip the constraint + return Constraint.Skip + + # Everything but storage and exchange techs + # Derated available generation + available = sum( + M.V_Capacity[r, p, t, v] + * value(M.ReserveCapacityDerate[r, p, s, t, v]) + * value(M.CapacityFactorProcess[r, p, s, d, t, v]) + * value(M.CapacityToActivity[r, t]) + * value(M.SegFrac[p, s, d]) + for (t, v) in M.processReservePeriods[r, p] + if t not in M.tech_uncap and t not in M.tech_storage + ) + + # Storage + # Derated net output flow + available += sum( + M.V_FlowOut[r, p, s, d, i, t, v, o] * value(M.ReserveCapacityDerate[r, p, s, t, v]) + for (t, v) in M.processReservePeriods[r, p] + if t in M.tech_storage + for i in M.processInputs[r, p, t, v] + for o in M.processOutputsByInput[r, p, t, v, i] + ) + available -= sum( + M.V_FlowIn[r, p, s, d, i, t, v, o] * value(M.ReserveCapacityDerate[r, p, s, t, v]) + for (t, v) in M.processReservePeriods[r, p] + if t in M.tech_storage + for i in M.processInputs[r, p, t, v] + for o in M.processOutputsByInput[r, p, t, v, i] + ) + + # The above code does not consider exchange techs, e.g. electricity + # transmission between two distinct regions. + # We take exchange takes into account below. + # Note that a single exchange tech linking regions Ri and Rj is twice + # defined: once for region "Ri-Rj" and once for region "Rj-Ri". + + # First, determine the amount of firm capacity each exchange tech + # contributes. + for r1r2 in M.regionalIndices: + if '-' not in r1r2: + continue + if (r1r2, p) not in M.processReservePeriods: # ensure r1r2 is a valid reserve provider in p + continue + r1, r2 = r1r2.split('-') + + # Only consider the capacity of technologies that import to + # the region in question -- i.e. for cases where r2 == r. + if r2 != r: + continue + + # add the available output of the exchange tech. + available += sum( + M.V_Capacity[r1r2, p, t, v] + * value(M.ReserveCapacityDerate[r, p, s, t, v]) + * value(M.CapacityFactorProcess[r, p, s, d, t, v]) + * value(M.CapacityToActivity[r1r2, t]) + * value(M.SegFrac[p, s, d]) + for (t, v) in M.processReservePeriods[r1r2, p] + for t in M.tech_reserve + ) + + return available + + +def ReserveMarginStatic(M: 'TemoaModel', r, p, s, d): + r""" + + During each period :math:`p`, the sum of capacity values of all reserve + technologies :math:`\sum_{t \in T^{res}} \textbf{CAPAVL}_{r,p,t}`, which are + defined in the set :math:`\textbf{T}^{res}`, should exceed the peak load by + :math:`PRM`, the regional reserve margin. Note that the reserve + margin is expressed in percentage of the peak load. Generally speaking, in + a database we may not know the peak demand before running the model, therefore, + we write this equation for all the time-slices defined in the database in each region. + Each generator is allowed to contribute its available capacity times a pre-defined + capacity credit, :math:`CC_{t,r}` + + .. math:: + :label: reserve_margin_static + + &\sum_{t \in T^{res} \setminus T^{x}} {CC_{t,r} \cdot \textbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*} \cdot C2A_{r,t} }\\ + &+ \sum_{t \in T^{res} \cap T^{x}} {CC_{t,r_i-r} \cdot \textbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*} \cdot C2A_{r_i-r,t} }\\ + &- \sum_{t \in T^{res} \cap T^{x}} {CC_{t,r-r_i} \cdot \textbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*} \cdot C2A_{r-r_i,t} }\\ + &\geq \left [ \sum_{ t \in T^{res} \setminus T^{x},V,I,O } \textbf{FO}_{r, p, s, d, i, t, v, o}\right.\\ + &+ \sum_{ t \in T^{res} \cap T^{x},V,I,O } \textbf{FO}_{r_i-r, p, s, d, i, t, v, o}\\ + &- \sum_{ t \in T^{res} \cap T^{x},V,I,O } \textbf{FI}_{r-r_i, p, s, d, i, t, v, o}\\ + &- \left.\sum_{ t \in T^{res} \cap T^{s},V,I,O } \textbf{FI}_{r, p, s, d, i, t, v, o} \right] \cdot (1 + PRM_r)\\ + + \\ + &\qquad\qquad\forall \{r, p, s, d\} \in \Theta_{\text{ReserveMargin}} \text{and} \forall r_i \in R + """ + if (not M.tech_reserve) or ( + (r, p) not in M.processReservePeriods + ): # If reserve set empty or if r,p not in M.processReservePeriod, skip the constraint + return Constraint.Skip + + available = sum( + value(M.CapacityCredit[r, p, t, v]) + * M.V_Capacity[r, p, t, v] + * value(M.CapacityToActivity[r, t]) + * value(M.SegFrac[p, s, d]) + for (t, v) in M.processReservePeriods[r, p] + if t not in M.tech_uncap + ) + + # The above code does not consider exchange techs, e.g. electricity + # transmission between two distinct regions. + # We take exchange takes into account below. + # Note that a single exchange tech linking regions Ri and Rj is twice + # defined: once for region "Ri-Rj" and once for region "Rj-Ri". + + # First, determine the amount of firm capacity each exchange tech + # contributes. + for r1r2 in M.regionalIndices: + if '-' not in r1r2: + continue + if (r1r2, p) not in M.processReservePeriods: # ensure r1r2 is a valid reserve provider in p + continue + r1, r2 = r1r2.split('-') + + # Only consider the capacity of technologies that import to + # the region in question -- i.e. for cases where r2 == r. + if r2 != r: + continue + + # add the available capacity of the exchange tech. + available += sum( + value(M.CapacityCredit[r1r2, p, t, v]) + * M.V_Capacity[r1r2, p, t, v] + * value(M.CapacityToActivity[r1r2, t]) + * value(M.SegFrac[p, s, d]) + for (t, v) in M.processReservePeriods[r1r2, p] + for t in M.tech_reserve + ) + + return available + + +def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): + # Get available generation in this time slice depending on method specified in config file + match M.ReserveMarginMethod.first(): + case 'static': + available = ReserveMarginStatic(M, r, p, s, d) + case 'dynamic': + available = ReserveMarginDynamic(M, r, p, s, d) + case _: + msg = f"Invalid reserve margin parameter '{M.ReserveMarginMethod.first()}'. Check the config file." + logger.error(msg) + raise ValueError(msg) + + # In most Temoa input databases, demand is endogenous, so we use electricity + # generation instead as a proxy for electricity demand. + # Non-annual generation + total_generation = sum( + M.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] + for (t, S_v) in M.processReservePeriods[r, p] + if t not in M.tech_annual + for S_i in M.processInputs[r, p, t, S_v] + for S_o in M.processOutputsByInput[r, p, t, S_v, S_i] + ) + + # Generators might serve demands directly + # Annual generation + total_generation += sum( + ( + value(M.DemandSpecificDistribution[r, p, s, d, S_o]) + if S_o in M.commodity_demand + else value(M.SegFrac[p, s, d]) + ) + * M.V_FlowOutAnnual[r, p, s, d, S_i, t, S_v, S_o] + for (t, S_v) in M.processReservePeriods[r, p] + if t in M.tech_annual + for S_i in M.processInputs[r, p, t, S_v] + for S_o in M.processOutputsByInput[r, p, t, S_v, S_i] + ) + + # We must take into account flows into storage technologies. + # Flows into storage technologies need to be subtracted from the + # load calculation. + total_generation -= sum( + M.V_FlowIn[r, p, s, d, S_i, t, S_v, S_o] + for (t, S_v) in M.processReservePeriods[r, p] + if t in M.tech_storage + for S_i in M.processInputs[r, p, t, S_v] + for S_o in M.processOutputsByInput[r, p, t, S_v, S_i] + ) + + # Electricity imports and exports via exchange techs are accounted + # for below: + for r1r2 in M.regionalIndices: # ensure the region is of the form r1-r2 + if '-' not in r1r2: + continue + if (r1r2, p) not in M.processReservePeriods: # ensure r1r2 is a valid reserve provider in p + continue + r1, r2 = r1r2.split('-') + # First, determine the exports, and subtract this value from the + # total generation. + if r1 == r: + total_generation -= sum( + M.V_FlowOut[r1r2, p, s, d, S_i, t, S_v, S_o] + / get_variable_efficiency(M, r1r2, p, s, d, S_i, t, S_v, S_o) + for (t, S_v) in M.processReservePeriods[r1r2, p] + for S_i in M.processInputs[r1r2, p, t, S_v] + for S_o in M.processOutputsByInput[r1r2, p, t, S_v, S_i] + ) + # Second, determine the imports, and add this value from the + # total generation. + elif r2 == r: + total_generation += sum( + M.V_FlowOut[r1r2, p, s, d, S_i, t, S_v, S_o] + for (t, S_v) in M.processReservePeriods[r1r2, p] + for S_i in M.processInputs[r1r2, p, t, S_v] + for S_o in M.processOutputsByInput[r1r2, p, t, S_v, S_i] + ) + + requirement = total_generation * (1 + value(M.PlanningReserveMargin[r])) + return available >= requirement diff --git a/temoa/components/storage.py b/temoa/components/storage.py index 207d83259..7a8167db5 100644 --- a/temoa/components/storage.py +++ b/temoa/components/storage.py @@ -1,5 +1,9 @@ from typing import TYPE_CHECKING +from pyomo.environ import Constraint, value + +from .utils import get_variable_efficiency, operator_expression + if TYPE_CHECKING: from temoa.core.model import TemoaModel @@ -24,3 +28,437 @@ def SeasonalStorageConstraintIndices(M: 'TemoaModel'): def StorageConstraintIndices(M: 'TemoaModel'): return M.storageLevelIndices_rpsdtv + + +def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): + r""" + This constraint enforces the continuity of storage level between time slices. + storage level in the next time slice (:math:`s_{next}, d_{next}`) is equal to + current storage level plus net charge in the current time slice. + + .. math:: + :label: Storage Energy + + {SL}_{r,p,s,d,t,v} + + \sum\limits_{I,O} \mathbf{FIS}_{r,p,s,d,i,t,v,o} \cdot {EFF}_{r,i,t,v,o} + - \sum\limits_{I,O} \mathbf{FO}_{r,p,s,d,i,t,v,o} + = {SL}_{r,p,s_{{next}},d_{{next}},t,v} + + Note that for all seasonal representations except consecutive_days, the last time slice + of each season will loop back to the first time slice of the same season, preventing + seasonal deltas for non-seasonal storage (see SeasonalStorageEnergyUpperBound). + """ + + # We allow a non-zero daily delta only in the case of seasonal storage + if M.isSeasonalStorage[t] and d == M.time_of_day.last(): + return Constraint.Skip # handled by SeasonalStorageEnergy_Constraint + + # This is the sum of all input=i sent TO storage tech t of vintage v with + # output=o in p,s,d + charge = sum( + M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] + * get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + + # This is the sum of all output=o withdrawn FROM storage tech t of vintage v + # with input=i in p,s,d + discharge = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_o in M.processOutputs[r, p, t, v] + for S_i in M.processInputsByOutput[r, p, t, v, S_o] + ) + + stored_energy = charge - discharge + + s_next, d_next = M.time_next[p, s, d] + + expr = ( + M.V_StorageLevel[r, p, s, d, t, v] + stored_energy + == M.V_StorageLevel[r, p, s_next, d_next, t, v] + ) + + return expr + + +def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_seq, t, v): + r""" + This constraint enforces the continuity of state of charge between seasons for seasonal + storage. Sequential season storage level increases by the matched season's net charge + over that entire day, adjusted for number of days represented by sequential vs non-sequential + seasons. Only applies to storage technologies in the :code:`tech_seasonal_storage` set. + :math:`s^*` represents the matching non-sequential season for the sequential season + :math:`s^{seq}`. + + .. math:: + :label: Storage Energy (Sequential Seasons) + + \mathbf{SSL}_{r,p,s^{seq},t,v} + + DA_{r,p,s^{seq}} \cdot \left(\mathbf{SL}_{r,p,s^*,d_{last},t,v} + + \sum_{I,O} \mathbf{FI}_{r,p,s^*,d_{last},i,t,v,o} \cdot EFF_{r,i,t,v,o} + - \sum_{I,O} \mathbf{FO}_{r,p,s^*,d_{last},i,t,v,o} + \right) + + = DA_{r,p,s^{seq}_{next}} \cdot \mathbf{SL}_{r,p,s_{next}^*,d_{first},t,v} + + \mathbf{SSL}_{r,p,s^{seq}_{next},t,v} + + \\ + \text{where } DA_{r,p,s^{seq}} = \frac{\#days_{s^{seq}}}{SEG_{r,p,s^*} \cdot DPP} + + .. figure:: images/ldes_chain.* + :align: center + :width: 100% + :figclass: align-center + :figwidth: 60% + + How sequential seasons chain together for seasonal storage. Hatched area is + SeasonalStorageLevel :math:`SSL_{r,p,s^{seq},t,v}`. Vertical lines are + StorageLevel :math:`SL_{r,p,s^*,d,t,v}`. Green line is net seasonal storage + level :math:`SSL_{r,p,s^{seq},t,v} + SL_{r,p,s^*,d,t,v}`. Background grey + lines show how storage levels from non-sequential seasons are combined + in sequential seasons. Dashed line is SeasonalStorageEnergyUpperBound. + Sequential seasons two and four here are each two days while one and three + are each one day. + """ + + s = M.sequential_to_season[p, s_seq] + + # This is the sum of all input=i sent TO storage tech t of vintage v with + # output=o in p,s + charge = sum( + M.V_FlowIn[r, p, s, M.time_of_day.last(), S_i, t, v, S_o] + * get_variable_efficiency(M, r, p, s, M.time_of_day.last(), S_i, t, v, S_o) + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + + # This is the sum of all output=o withdrawn FROM storage tech t of vintage v + # with input=i in p,s + discharge = sum( + M.V_FlowOut[r, p, s, M.time_of_day.last(), S_i, t, v, S_o] + for S_o in M.processOutputs[r, p, t, v] + for S_i in M.processInputsByOutput[r, p, t, v, S_o] + ) + + s_seq_next = M.time_next_sequential[p, s_seq] + s_next = M.sequential_to_season[p, s_seq_next] + + # Flows and StorageLevel are normalised to the number of days in the non-sequential season, so must + # be adjusted to the number of days in the sequential season + days_adjust = value(M.TimeSeasonSequential[p, s_seq, s]) / ( + value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod) + ) + days_adjust_next = value(M.TimeSeasonSequential[p, s_seq_next, s_next]) / ( + value(M.SegFracPerSeason[p, s_next]) * value(M.DaysPerPeriod) + ) + + stored_energy = (charge - discharge) * days_adjust + + start = ( + M.V_SeasonalStorageLevel[r, p, s_seq, t, v] + + M.V_StorageLevel[r, p, s, M.time_of_day.last(), t, v] * days_adjust + ) + end = ( + M.V_SeasonalStorageLevel[r, p, s_seq_next, t, v] + + M.V_StorageLevel[r, p, s_next, M.time_of_day.first(), t, v] * days_adjust_next + ) + + expr = start + stored_energy == end + return expr + + +def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): + r""" + This constraint ensures that the amount of energy stored does not exceed + the upper bound set by the energy capacity of the storage device, as calculated + on the right-hand side. + + Because the number and duration of time slices are user-defined, we need to adjust + the storage duration, which is specified in hours. First, the hourly duration is divided + by the number of hours in a year to obtain the duration as a fraction of the year. + Since the :math:`C2A` parameter assumes the conversion of capacity to annual activity, + we need to express the storage duration as fraction of a year. Then, :math:`SEG_{s,d}` + summed over the time-of-day slices (:math:`d`) multiplied by :math:`DPP` yields the + number of days per season. This step is necessary because conventional time sliced models + use a single day to represent many days within a given season. Thus, it is necessary to + scale the storage duration to account for the number of days in each season. + + .. math:: + :label: StorageEnergyUpperBound + + \textbf{SL}_{r, p, s, d, t, v} \le + \textbf{CAP}_{r,t,v} \cdot C2A_{r,t} \cdot \frac {SD_{r,t}}{24 \cdot DPP} + \cdot \sum_{d} SEG_{s,d} \cdot DPP + + \\ + \forall \{r, p, s, d, t, v\} \in \Theta_{\text{StorageEnergyUpperBound}} + + A season can represent many days. Within each season, flows are multiplied by the + number of days each season represents and, so, the upper bound needs to be adjusted + to allow day-scale flows (e.g., charge in the morning, discharge in the afternoon). + + .. figure:: images/daily_storage_representation.* + :align: center + :width: 100% + :figclass: center + :figwidth: 40% + + Representation of a 3-day season for non-seasonal (daily) storage. + """ + + if M.isSeasonalStorage[t]: + return Constraint.Skip # redundant on SeasonalStorageEnergyUpperBound + + energy_capacity = ( + M.V_Capacity[r, p, t, v] + * value(M.CapacityToActivity[r, t]) + * (value(M.StorageDuration[r, t]) / (24 * value(M.DaysPerPeriod))) + * value(M.SegFracPerSeason[p, s]) + * M.DaysPerPeriod # adjust for days in season + ) + + expr = M.V_StorageLevel[r, p, s, d, t, v] <= energy_capacity + + return expr + + +def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_seq, d, t, v): + r""" + Builds off of StorageEnergyUpperBound_Constraint. Enforces the max charge capacity + of seasonal storage, summing the real storage level with the superimposed sequential + seasonal storage level. :math:`s^*` represents the matching non-sequential season for + the sequential season :math:`s^{seq}`. + + .. math:: + :label: Seasonal Storage Energy Capacity + + \mathbf{SSL}_{r,p,s^{seq},t,v} + + \mathbf{SL}_{r,p,s^*,d,t,v} \cdot DA_{r,p,s^{seq}} + \leq \mathbf{CAP}_{r,p,t,v} \cdot C2A_{r,t} \cdot \frac{SD_{r,t}}{24 \cdot DPP} + + \\ + + \text{where } DA_{r,p,s^{seq}} = \frac{\#days_{s^{seq}}}{SEG_{r,p,s^*} \cdot DPP} + + + + Unlike non-seasonal (daily) storage, seasonal storage is allowed to carry energy + between seasons. However, through seasons representing multiple days, many days' + charge deltas have accumulated, multiplied by the number of days the season + represents. If we allowed these stacked deltas to carry between seasons then we would + be multiplying the effective energy capacity of the storage. We could just constrain + the seasonal delta to the unadjusted energy capacity, but then the final day in the + season would sit atop a season's worth of deltas, possibly exceeding our upper or + lower bound by a factor of :math:`\frac{N-1}{N}` where :math:`N` is the number of + days the sequential season represents. + + .. figure:: images/ldes_delta_problem.* + :align: center + :width: 100% + :figclass: center + :figwidth: 100% + + The energy upper bound or non-negative lower bound could be violated in a + season representing multiple days if we both adjusted the upper bound to + the number of days and allowed a seasonal delta. + + So, we do not adjust the upper energy bound for seasonal storage. This limits the + ability of seasonal storage to perform arbitrage within each season, but allows it to + carry energy between seasons realistically. + + .. figure:: images/ldes_delta_representation.* + :align: center + :width: 100% + :figclass: center + :figwidth: 40% + + Unadjusted energy upper bound constraint for seasonal storage. + """ + + s = M.sequential_to_season[p, s_seq] + + energy_capacity = ( + M.V_Capacity[r, p, t, v] + * value(M.CapacityToActivity[r, t]) + * (value(M.StorageDuration[r, t]) / (24 * value(M.DaysPerPeriod))) + ) + + # Flows and StorageLevel are normalised to the number of days in the non-sequential season, so must + # be adjusted to the number of days in the sequential season + days_adjust = value(M.TimeSeasonSequential[p, s_seq, s]) / ( + value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod) + ) + + # V_StorageLevel tracks the running cumulative delta in the non-sequential season, so must be adjusted + # to the size of the sequential season + running_day_delta = M.V_StorageLevel[r, p, s, d, t, v] * days_adjust + + expr = M.V_SeasonalStorageLevel[r, p, s_seq, t, v] + running_day_delta <= energy_capacity + + return expr + + +def StorageChargeRate_Constraint(M: 'TemoaModel', r, p, s, d, t, v): + r""" + + This constraint ensures that the charge rate of the storage unit is + limited by the power capacity (typically GW) of the storage unit. + + .. math:: + :label: StorageChargeRate + + \sum_{I, O} \textbf{FIS}_{r, p, s, d, i, t, v, o} \cdot EFF_{r,i,t,v,o} + \le + \textbf{CAP}_{r,t,v} \cdot C2A_{r,t} \cdot SEG_{s,d} + + \\ + \forall \{r, p, s, d, t, v\} \in \Theta_{\text{StorageChargeRate}} + + """ + # Calculate energy charge in each time slice + slice_charge = sum( + M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] + * get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + + # Maximum energy charge in each time slice + max_charge = ( + M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[p, s, d]) + ) + + # Energy charge cannot exceed the power capacity of the storage unit + expr = slice_charge <= max_charge + + return expr + + +def StorageDischargeRate_Constraint(M: 'TemoaModel', r, p, s, d, t, v): + r""" + + This constraint ensures that the discharge rate of the storage unit + is limited by the power capacity (typically GW) of the storage unit. + + .. math:: + :label: StorageDischargeRate + + \sum_{I, O} \textbf{FO}_{r, p, s, d, i, t, v, o} + \le + \textbf{CAP}_{r,t,v} \cdot C2A_{r,t} \cdot SEG_{s,d} + + \\ + \forall \{r,p, s, d, t, v\} \in \Theta_{\text{StorageDischargeRate}} + """ + # Calculate energy discharge in each time slice + slice_discharge = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_o in M.processOutputs[r, p, t, v] + for S_i in M.processInputsByOutput[r, p, t, v, S_o] + ) + + # Maximum energy discharge in each time slice + max_discharge = ( + M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[p, s, d]) + ) + + # Energy discharge cannot exceed the capacity of the storage unit + expr = slice_discharge <= max_discharge + + return expr + + +def StorageThroughput_Constraint(M: 'TemoaModel', r, p, s, d, t, v): + r""" + + It is not enough to only limit the charge and discharge rate separately. We also + need to ensure that the maximum throughput (charge + discharge) does not exceed + the capacity (typically GW) of the storage unit. + + .. math:: + :label: StorageThroughput + + \sum_{I, O} \textbf{FO}_{r, p, s, d, i, t, v, o} + + + \sum_{I, O} \textbf{FIS}_{r, p, s, d, i, t, v, o} \cdot EFF_{r,i,t,v,o} + \le + \textbf{CAP}_{r,t,v} \cdot C2A_{r,t} \cdot SEG_{s,d} + + \\ + \forall \{r, p, s, d, t, v\} \in \Theta_{\text{StorageThroughput}} + """ + discharge = sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_o in M.processOutputs[r, p, t, v] + for S_i in M.processInputsByOutput[r, p, t, v, S_o] + ) + + charge = sum( + M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] + * get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + + throughput = charge + discharge + max_throughput = ( + M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[p, s, d]) + ) + expr = throughput <= max_throughput + return expr + + +# A limit but more cohesive here than in limits.py +def LimitStorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v, op): + r""" + + This constraint is used if the users wishes to force a specific storage charge level + for certain storage technologies and vintages at a certain time slice. + In this case, the value of the decision variable :math:`\textbf{SI}_{r,t,v}` is set by + this constraint rather than being optimized. User-specified storage charge levels that are + sufficiently different from the optimal :math:`\textbf{SI}_{r,t,v}` could impact the + cost-effectiveness of storage. For example, if the optimal charge level happens to be + 50% of the full energy capacity, forced charge levels (specified by parameter + :math:`SIF_{r,t,v}`) equal to 10% or 90% of the full energycapacity could lead to + more expensive solutions. + + + .. math:: + :label: LimitStorageFraction + + \textbf{SF}_{r,p,s,d,t,v} \le + \ SF_{r,p,s,d,t,v} + \cdot + \textbf{CAP}_{r,p,t,v} \cdot C2A_{r,t} \cdot \frac {SD_{r,t}}{(24 \cdot DPP hrs/yr} + \cdot \sum_{d} SEG_{s,d} \cdot M.DaysPerPeriod days/yr \cdot MPL_{r,p,t,v} + + \\ + \forall \{r, p, s, d, t, v\} \in \Theta_{\text{LimitStorageFraction}} + """ + + energy_limit = ( + M.V_Capacity[r, p, t, v] + * value(M.CapacityToActivity[r, t]) + * (value(M.StorageDuration[r, t]) / (24 * value(M.DaysPerPeriod))) + * value(M.LimitStorageFraction[r, p, s, d, t, v, op]) + ) + + if M.isSeasonalStorage[t]: + s_seq = s # sequential season + s = M.sequential_to_season[p, s_seq] # non-sequential season + + # adjust the storage level to the individual-day level + energy_level = M.V_StorageLevel[r, p, s, d, t, v] / ( + value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod) + ) + + if M.isSeasonalStorage[t]: + # seasonal storage upper energy limit is absolute + energy_level = M.V_SeasonalStorageLevel[r, p, s_seq, t, v] + energy_level * value( + M.TimeSeasonSequential[p, s_seq, s] + ) + + expr = operator_expression(energy_level, op, energy_limit) + + return expr diff --git a/temoa/components/technology.py b/temoa/components/technology.py index bc1c1b623..d493c92ae 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -282,3 +282,30 @@ def CreateSurvivalCurve(M: 'TemoaModel'): 'Otherwise, these individual years can be defined manually. Interpolated processes: {}' ).format([rtv for rtv in rtv_interpolated]) logger.info(msg) + + +def ParamProcessLifeFraction_rule(M: 'TemoaModel', r, p, t, v): + r""" + Get the effective capacity of a process :math:`` in a period :math:`p`. + + Accounts for mid-period end of life or average survival over the period + for processes using survival curves. + """ + + period_length = value(M.PeriodLength[p]) + + if M.isSurvivalCurveProcess[r, t, v]: + # Sum survival fraction over the period + years_remaining = sum( + value(M.LifetimeSurvivalCurve[r, _p, t, v]) for _p in range(p, p + period_length, 1) + ) + else: + # Remaining life years within the EOL period + years_remaining = v + value(M.LifetimeProcess[r, t, v]) - p + + if years_remaining >= period_length: + # try to avoid floating point round-off errors for the common case. + return 1 + + frac = years_remaining / float(period_length) + return frac diff --git a/temoa/components/time.py b/temoa/components/time.py index a1c9850c4..309465f21 100644 --- a/temoa/components/time.py +++ b/temoa/components/time.py @@ -344,3 +344,21 @@ def init_set_vintage_exist(M: 'TemoaModel'): def init_set_vintage_optimize(M: 'TemoaModel'): return sorted(M.time_optimize) + + +def SegFracPerSeason_rule(M: 'TemoaModel', p, s): + return sum(value(M.SegFrac[p, s, S_d]) for S_d in M.time_of_day if (p, s, S_d) in M.SegFrac) + + +def ParamPeriodLength(M: 'TemoaModel', p): + # This specifically does not use time_optimize because this function is + # called /over/ time_optimize. + periods = sorted(M.time_future) + + i = periods.index(p) + + # The +1 won't fail, because this rule is called over time_optimize, which + # lacks the last period in time_future. + length = periods[i + 1] - periods[i] + + return length diff --git a/temoa/components/utils.py b/temoa/components/utils.py new file mode 100644 index 000000000..727c38a46 --- /dev/null +++ b/temoa/components/utils.py @@ -0,0 +1,56 @@ +from logging import getLogger +from typing import TYPE_CHECKING + +from pyomo.core import Expression +from pyomo.environ import value + +if TYPE_CHECKING: + from temoa.core.model import TemoaModel + + +logger = getLogger(__name__) + + +def operator_expression(lhs: Expression | None, operator: str | None, rhs: Expression | None): + """Returns an expression, applying a configured operator""" + if any((lhs is None, operator is None, rhs is None)): + msg = ('Tried to build a constraint using a bad expression or operator: {} {} {}').format( + lhs, operator, rhs + ) + logger.error(msg) + raise ValueError(msg) + try: + match operator: + case 'e': + expr = lhs == rhs + case 'le': + expr = lhs <= rhs + case 'ge': + expr = lhs >= rhs + case _: + msg = ( + 'Tried to build a constraint using a bad operator. Allowed operators are "e","le", or "ge". Got "{}": {} {} {}' + ).format(operator, lhs, operator, rhs) + logger.error(msg) + raise ValueError(msg) + except Exception as e: + print(e) + msg = ('Tried to build a constraint using a bad expression or operator: {} {} {}').format( + lhs, operator, rhs + ) + logger.error(msg) + raise ValueError(msg) from e + + return expr + + +# To avoid building big many-indexed parameters when they aren't needed - saves memory +# Much faster to build a dictionary and check that than check the parameter +# indices directly every time - saves build time +def get_variable_efficiency(M: 'TemoaModel', r, p, s, d, i, t, v, o): + if M.isEfficiencyVariable[r, p, i, t, v, o]: + return value(M.Efficiency[r, i, t, v, o]) * value( + M.EfficiencyVariable[r, p, s, d, i, t, v, o] + ) + else: + return value(M.Efficiency[r, i, t, v, o]) diff --git a/temoa/core/model.py b/temoa/core/model.py index 23c27af29..96e913526 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -29,72 +29,6 @@ # Temoa Constraint Functions # Core model constraints and business logic rules # ============================================================================ -from temoa._internal.temoa_rules import ( - # Core capacity constraints - AdjustedCapacity_Constraint, - AnnualCommodityBalance_Constraint, - # Retirement constraints - AnnualRetirement_Constraint, - # Ramping constraints - BaseloadDiurnal_Constraint, - Capacity_Constraint, - CapacityAnnual_Constraint, - CapacityAvailableByPeriodAndTech_Constraint, - CommodityBalance_Constraint, - # Activity and flow constraints - Demand_Constraint, - DemandActivity_Constraint, - # Limit constraints (capacity, activity, emissions, etc.) - LimitActivity_Constraint, - LimitActivityShare_Constraint, - LimitAnnualCapacityFactor_Constraint, - LimitCapacity_Constraint, - LimitCapacityShare_Constraint, - # Growth/degrowth constraints - LimitDegrowthCapacityConstraint_rule, - LimitDegrowthNewCapacityConstraint_rule, - LimitDegrowthNewCapacityDeltaConstraint_rule, - LimitEmission_Constraint, - LimitGrowthCapacityConstraint_rule, - LimitGrowthNewCapacityConstraint_rule, - LimitGrowthNewCapacityDeltaConstraint_rule, - LimitNewCapacity_Constraint, - LimitNewCapacityShare_Constraint, - LimitResource_Constraint, - LimitSeasonalCapacityFactor_Constraint, - LimitStorageFraction_Constraint, - # Technology split constraints - LimitTechInputSplit_Constraint, - LimitTechInputSplitAnnual_Constraint, - LimitTechInputSplitAverage_Constraint, - LimitTechOutputSplit_Constraint, - LimitTechOutputSplitAnnual_Constraint, - LimitTechOutputSplitAverage_Constraint, - LinkedEmissionsTech_Constraint, - # Parameter calculation rules - ParamLoanAnnualize_rule, - ParamPeriodLength, - ParamProcessLifeFraction_rule, - RampDownDay_Constraint, - RampDownSeason_Constraint, - RampUpDay_Constraint, - RampUpSeason_Constraint, - # Regional and special constraints - RegionalExchangeCapacity_Constraint, - RenewablePortfolioStandard_Constraint, - ReserveMargin_Constraint, - SeasonalStorageEnergy_Constraint, - SeasonalStorageEnergyUpperBound_Constraint, - SegFracPerSeason_rule, - StorageChargeRate_Constraint, - StorageDischargeRate_Constraint, - # Storage constraints - StorageEnergy_Constraint, - StorageEnergyUpperBound_Constraint, - StorageThroughput_Constraint, - # Objective function - TotalCost_rule, -) from temoa.components import ( capacity, commodities, @@ -360,7 +294,7 @@ def __init__(M, *args, **kwargs): M.GlobalDiscountRate = Param(default=0.05) # Define time-related parameters - M.PeriodLength = Param(M.time_optimize, initialize=ParamPeriodLength) + M.PeriodLength = Param(M.time_optimize, initialize=time.ParamPeriodLength) M.SegFrac = Param(M.time_optimize, M.time_season, M.time_of_day) M.validate_SegFrac = BuildAction(rule=time.validate_SegFrac) M.TimeSequencing = Set() # How do states carry between time segments? @@ -516,7 +450,9 @@ def __init__(M, *args, **kwargs): # Set up representation of time M.DaysPerPeriod = Param() - M.SegFracPerSeason = Param(M.time_optimize, M.time_season, initialize=SegFracPerSeason_rule) + M.SegFracPerSeason = Param( + M.time_optimize, M.time_season, initialize=time.SegFracPerSeason_rule + ) M.TimeSeasonSequential = Param( M.time_optimize, M.time_season_sequential, M.time_season, mutable=True ) @@ -563,7 +499,7 @@ def __init__(M, *args, **kwargs): M.LoanRate = Param( M.CostInvest_rtv, domain=NonNegativeReals, default=costs.get_default_loan_rate ) - M.LoanAnnualize = Param(M.CostInvest_rtv, initialize=ParamLoanAnnualize_rule) + M.LoanAnnualize = Param(M.CostInvest_rtv, initialize=costs.ParamLoanAnnualize_rule) M.CostVariable_rptv = Set(dimen=4, initialize=costs.CostVariableIndices) M.CostVariable = Param(M.CostVariable_rptv) @@ -576,7 +512,9 @@ def __init__(M, *args, **kwargs): # M.ModelProcessLife = Param(M.ModelProcessLife_rptv, initialize=ParamModelProcessLife_rule) M.ProcessLifeFrac_rptv = Set(dimen=4, initialize=technology.ModelProcessLifeIndices) - M.ProcessLifeFrac = Param(M.ProcessLifeFrac_rptv, initialize=ParamProcessLifeFraction_rule) + M.ProcessLifeFrac = Param( + M.ProcessLifeFrac_rptv, initialize=technology.ParamProcessLifeFraction_rule + ) M.LimitCapacityConstraint_rpt = Set( within=M.regionalGlobalIndices * M.time_optimize * M.tech_or_group * M.operator @@ -818,7 +756,7 @@ def __init__(M, *args, **kwargs): # (minimize total cost) # ################################################ - M.TotalCost = Objective(rule=TotalCost_rule, sense=minimize) + M.TotalCost = Objective(rule=costs.TotalCost_rule, sense=minimize) ################################################ # Constraints # @@ -835,17 +773,19 @@ def __init__(M, *args, **kwargs): M.progress_marker_4 = BuildAction(['Starting to build Constraints'], rule=progress_check) # Declare constraints to calculate derived decision variables - M.CapacityConstraint = Constraint(M.CapacityConstraint_rpsdtv, rule=Capacity_Constraint) + M.CapacityConstraint = Constraint( + M.CapacityConstraint_rpsdtv, rule=capacity.Capacity_Constraint + ) M.CapacityAnnualConstraint_rptv = Set( dimen=4, initialize=capacity.CapacityAnnualConstraintIndices ) M.CapacityAnnualConstraint = Constraint( - M.CapacityAnnualConstraint_rptv, rule=CapacityAnnual_Constraint + M.CapacityAnnualConstraint_rptv, rule=capacity.CapacityAnnual_Constraint ) M.CapacityAvailableByPeriodAndTechConstraint = Constraint( - M.CapacityAvailableVar_rpt, rule=CapacityAvailableByPeriodAndTech_Constraint + M.CapacityAvailableVar_rpt, rule=capacity.CapacityAvailableByPeriodAndTech_Constraint ) # devnote: I think this constraint is redundant @@ -856,41 +796,42 @@ def __init__(M, *args, **kwargs): ['Starting AnnualRetirementConstraint'], rule=progress_check ) M.AnnualRetirementConstraint = Constraint( - M.AnnualRetirementVar_rptv, rule=AnnualRetirement_Constraint + M.AnnualRetirementVar_rptv, rule=capacity.AnnualRetirement_Constraint ) M.progress_marker_4b = BuildAction( ['Starting AdjustedCapacityConstraint'], rule=progress_check ) M.AdjustedCapacityConstraint = Constraint( - M.CostFixed_rptv, rule=AdjustedCapacity_Constraint + M.CostFixed_rptv, rule=capacity.AdjustedCapacity_Constraint ) M.progress_marker_5 = BuildAction(['Finished Capacity Constraints'], rule=progress_check) # Declare core model constraints that ensure proper system functioning # In driving order, starting with the need to meet end-use demands - M.DemandConstraint = Constraint(M.DemandConstraint_rpc, rule=Demand_Constraint) + M.DemandConstraint = Constraint(M.DemandConstraint_rpc, rule=commodities.Demand_Constraint) # devnote: testing a workaround M.DemandActivityConstraint_rpsdtv_dem = Set( dimen=7, initialize=commodities.DemandActivityConstraintIndices ) M.DemandActivityConstraint = Constraint( - M.DemandActivityConstraint_rpsdtv_dem, rule=DemandActivity_Constraint + M.DemandActivityConstraint_rpsdtv_dem, rule=commodities.DemandActivity_Constraint ) M.CommodityBalanceConstraint_rpsdc = Set( dimen=5, initialize=commodities.CommodityBalanceConstraintIndices ) M.CommodityBalanceConstraint = Constraint( - M.CommodityBalanceConstraint_rpsdc, rule=CommodityBalance_Constraint + M.CommodityBalanceConstraint_rpsdc, rule=commodities.CommodityBalance_Constraint ) M.AnnualCommodityBalanceConstraint_rpc = Set( dimen=3, initialize=commodities.AnnualCommodityBalanceConstraintIndices ) M.AnnualCommodityBalanceConstraint = Constraint( - M.AnnualCommodityBalanceConstraint_rpc, rule=AnnualCommodityBalance_Constraint + M.AnnualCommodityBalanceConstraint_rpc, + rule=commodities.AnnualCommodityBalance_Constraint, ) # M.ResourceExtractionConstraint = Constraint( @@ -901,78 +842,84 @@ def __init__(M, *args, **kwargs): dimen=6, initialize=operations.BaseloadDiurnalConstraintIndices ) M.BaseloadDiurnalConstraint = Constraint( - M.BaseloadDiurnalConstraint_rpsdtv, rule=BaseloadDiurnal_Constraint + M.BaseloadDiurnalConstraint_rpsdtv, rule=operations.BaseloadDiurnal_Constraint ) M.RegionalExchangeCapacityConstraint_rrptv = Set( dimen=5, initialize=capacity.RegionalExchangeCapacityConstraintIndices ) M.RegionalExchangeCapacityConstraint = Constraint( - M.RegionalExchangeCapacityConstraint_rrptv, rule=RegionalExchangeCapacity_Constraint + M.RegionalExchangeCapacityConstraint_rrptv, + rule=geography.RegionalExchangeCapacity_Constraint, ) M.progress_marker_6 = BuildAction(['Starting Storage Constraints'], rule=progress_check) M.StorageEnergyConstraint = Constraint( - M.StorageConstraints_rpsdtv, rule=StorageEnergy_Constraint + M.StorageConstraints_rpsdtv, rule=storage.StorageEnergy_Constraint ) M.StorageEnergyUpperBoundConstraint = Constraint( - M.StorageConstraints_rpsdtv, rule=StorageEnergyUpperBound_Constraint + M.StorageConstraints_rpsdtv, rule=storage.StorageEnergyUpperBound_Constraint ) M.SeasonalStorageEnergyConstraint = Constraint( - M.SeasonalStorageLevel_rpstv, rule=SeasonalStorageEnergy_Constraint + M.SeasonalStorageLevel_rpstv, rule=storage.SeasonalStorageEnergy_Constraint ) M.SeasonalStorageEnergyUpperBoundConstraint = Constraint( - M.SeasonalStorageConstraints_rpsdtv, rule=SeasonalStorageEnergyUpperBound_Constraint + M.SeasonalStorageConstraints_rpsdtv, + rule=storage.SeasonalStorageEnergyUpperBound_Constraint, ) M.StorageChargeRateConstraint = Constraint( - M.StorageConstraints_rpsdtv, rule=StorageChargeRate_Constraint + M.StorageConstraints_rpsdtv, rule=storage.StorageChargeRate_Constraint ) M.StorageDischargeRateConstraint = Constraint( - M.StorageConstraints_rpsdtv, rule=StorageDischargeRate_Constraint + M.StorageConstraints_rpsdtv, rule=storage.StorageDischargeRate_Constraint ) M.StorageThroughputConstraint = Constraint( - M.StorageConstraints_rpsdtv, rule=StorageThroughput_Constraint + M.StorageConstraints_rpsdtv, rule=storage.StorageThroughput_Constraint ) M.LimitStorageFractionConstraint = Constraint( - M.LimitStorageFractionConstraint_rpsdtv, rule=LimitStorageFraction_Constraint + M.LimitStorageFractionConstraint_rpsdtv, rule=storage.LimitStorageFraction_Constraint ) M.RampUpDayConstraint_rpsdtv = Set(dimen=6, initialize=ramping.RampUpDayConstraintIndices) - M.RampUpDayConstraint = Constraint(M.RampUpDayConstraint_rpsdtv, rule=RampUpDay_Constraint) + M.RampUpDayConstraint = Constraint( + M.RampUpDayConstraint_rpsdtv, rule=ramping.RampUpDay_Constraint + ) M.RampDownDayConstraint_rpsdtv = Set( dimen=6, initialize=ramping.RampDownDayConstraintIndices ) M.RampDownDayConstraint = Constraint( - M.RampDownDayConstraint_rpsdtv, rule=RampDownDay_Constraint + M.RampDownDayConstraint_rpsdtv, rule=ramping.RampDownDay_Constraint ) M.RampUpSeasonConstraint_rpsstv = Set( dimen=6, initialize=ramping.RampUpSeasonConstraintIndices ) M.RampUpSeasonConstraint = Constraint( - M.RampUpSeasonConstraint_rpsstv, rule=RampUpSeason_Constraint + M.RampUpSeasonConstraint_rpsstv, rule=ramping.RampUpSeason_Constraint ) M.RampDownSeasonConstraint_rpsstv = Set( dimen=6, initialize=ramping.RampDownSeasonConstraintIndices ) M.RampDownSeasonConstraint = Constraint( - M.RampDownSeasonConstraint_rpsstv, rule=RampDownSeason_Constraint + M.RampDownSeasonConstraint_rpsstv, rule=ramping.RampDownSeason_Constraint ) M.ReserveMargin_rpsd = Set(dimen=4, initialize=reserves.ReserveMarginIndices) M.validate_ReserveMargin = BuildAction(rule=validate_ReserveMargin) - M.ReserveMarginConstraint = Constraint(M.ReserveMargin_rpsd, rule=ReserveMargin_Constraint) + M.ReserveMarginConstraint = Constraint( + M.ReserveMargin_rpsd, rule=reserves.ReserveMargin_Constraint + ) M.LimitEmissionConstraint = Constraint( - M.LimitEmissionConstraint_rpe, rule=LimitEmission_Constraint + M.LimitEmissionConstraint_rpe, rule=limits.LimitEmission_Constraint ) M.progress_marker_7 = BuildAction( ['Starting LimitGrowth and Activity Constraints'], rule=progress_check @@ -982,26 +929,28 @@ def __init__(M, *args, **kwargs): dimen=4, initialize=limits.LimitGrowthCapacityIndices ) M.LimitGrowthCapacityConstraint = Constraint( - M.LimitGrowthCapacityConstraint_rpt, rule=LimitGrowthCapacityConstraint_rule + M.LimitGrowthCapacityConstraint_rpt, rule=limits.LimitGrowthCapacityConstraint_rule ) M.LimitDegrowthCapacityConstraint_rpt = Set( dimen=4, initialize=limits.LimitDegrowthCapacityIndices ) M.LimitDegrowthCapacityConstraint = Constraint( - M.LimitDegrowthCapacityConstraint_rpt, rule=LimitDegrowthCapacityConstraint_rule + M.LimitDegrowthCapacityConstraint_rpt, rule=limits.LimitDegrowthCapacityConstraint_rule ) M.LimitGrowthNewCapacityConstraint_rpt = Set( dimen=4, initialize=limits.LimitGrowthNewCapacityIndices ) M.LimitGrowthNewCapacityConstraint = Constraint( - M.LimitGrowthNewCapacityConstraint_rpt, rule=LimitGrowthNewCapacityConstraint_rule + M.LimitGrowthNewCapacityConstraint_rpt, + rule=limits.LimitGrowthNewCapacityConstraint_rule, ) M.LimitDegrowthNewCapacityConstraint_rpt = Set( dimen=4, initialize=limits.LimitDegrowthNewCapacityIndices ) M.LimitDegrowthNewCapacityConstraint = Constraint( - M.LimitDegrowthNewCapacityConstraint_rpt, rule=LimitDegrowthNewCapacityConstraint_rule + M.LimitDegrowthNewCapacityConstraint_rpt, + rule=limits.LimitDegrowthNewCapacityConstraint_rule, ) M.LimitGrowthNewCapacityDeltaConstraint_rpt = Set( @@ -1009,23 +958,23 @@ def __init__(M, *args, **kwargs): ) M.LimitGrowthNewCapacityDeltaConstraint = Constraint( M.LimitGrowthNewCapacityDeltaConstraint_rpt, - rule=LimitGrowthNewCapacityDeltaConstraint_rule, + rule=limits.LimitGrowthNewCapacityDeltaConstraint_rule, ) M.LimitDegrowthNewCapacityDeltaConstraint_rpt = Set( dimen=4, initialize=limits.LimitDegrowthNewCapacityDeltaIndices ) M.LimitDegrowthNewCapacityDeltaConstraint = Constraint( M.LimitDegrowthNewCapacityDeltaConstraint_rpt, - rule=LimitDegrowthNewCapacityDeltaConstraint_rule, + rule=limits.LimitDegrowthNewCapacityDeltaConstraint_rule, ) M.LimitActivityConstraint = Constraint( - M.LimitActivityConstraint_rpt, rule=LimitActivity_Constraint + M.LimitActivityConstraint_rpt, rule=limits.LimitActivity_Constraint ) M.LimitSeasonalCapacityFactorConstraint = Constraint( M.LimitSeasonalCapacityFactorConstraint_rpst, - rule=LimitSeasonalCapacityFactor_Constraint, + rule=limits.LimitSeasonalCapacityFactor_Constraint, ) # devnote: deprecated when generalising tech/group columns in Limit tables @@ -1034,11 +983,11 @@ def __init__(M, *args, **kwargs): # ) M.LimitCapacityConstraint = Constraint( - M.LimitCapacityConstraint_rpt, rule=LimitCapacity_Constraint + M.LimitCapacityConstraint_rpt, rule=limits.LimitCapacity_Constraint ) M.LimitNewCapacityConstraint = Constraint( - M.LimitNewCapacityConstraint_rpt, rule=LimitNewCapacity_Constraint + M.LimitNewCapacityConstraint_rpt, rule=limits.LimitNewCapacity_Constraint ) # devnote: deprecated when generalising tech/group columns in Limit tables @@ -1051,15 +1000,15 @@ def __init__(M, *args, **kwargs): # ) M.LimitCapacityShareConstraint = Constraint( - M.LimitCapacityShareConstraint_rpgg, rule=LimitCapacityShare_Constraint + M.LimitCapacityShareConstraint_rpgg, rule=limits.LimitCapacityShare_Constraint ) M.LimitActivityShareConstraint = Constraint( - M.LimitActivityShareConstraint_rpgg, rule=LimitActivityShare_Constraint + M.LimitActivityShareConstraint_rpgg, rule=limits.LimitActivityShare_Constraint ) M.LimitNewCapacityShareConstraint = Constraint( - M.LimitNewCapacityShareConstraint_rpgg, rule=LimitNewCapacityShare_Constraint + M.LimitNewCapacityShareConstraint_rpgg, rule=limits.LimitNewCapacityShare_Constraint ) # devnote: deprecated when generalising tech/group columns in Limit tables @@ -1077,11 +1026,12 @@ def __init__(M, *args, **kwargs): ) M.LimitResourceConstraint = Constraint( - M.LimitResourceConstraint_rt, rule=LimitResource_Constraint + M.LimitResourceConstraint_rt, rule=limits.LimitResource_Constraint ) M.LimitAnnualCapacityFactorConstraint = Constraint( - M.LimitAnnualCapacityFactorConstraint_rpto, rule=LimitAnnualCapacityFactor_Constraint + M.LimitAnnualCapacityFactorConstraint_rpto, + rule=limits.LimitAnnualCapacityFactor_Constraint, ) ## Tech input splits @@ -1089,21 +1039,23 @@ def __init__(M, *args, **kwargs): dimen=8, initialize=limits.LimitTechInputSplitConstraintIndices ) M.LimitTechInputSplitConstraint = Constraint( - M.LimitTechInputSplitConstraint_rpsditv, rule=LimitTechInputSplit_Constraint + M.LimitTechInputSplitConstraint_rpsditv, rule=limits.LimitTechInputSplit_Constraint ) M.LimitTechInputSplitAnnualConstraint_rpitv = Set( dimen=6, initialize=limits.LimitTechInputSplitAnnualConstraintIndices ) M.LimitTechInputSplitAnnualConstraint = Constraint( - M.LimitTechInputSplitAnnualConstraint_rpitv, rule=LimitTechInputSplitAnnual_Constraint + M.LimitTechInputSplitAnnualConstraint_rpitv, + rule=limits.LimitTechInputSplitAnnual_Constraint, ) M.LimitTechInputSplitAverageConstraint_rpitv = Set( dimen=6, initialize=limits.LimitTechInputSplitAverageConstraintIndices ) M.LimitTechInputSplitAverageConstraint = Constraint( - M.LimitTechInputSplitAverageConstraint_rpitv, rule=LimitTechInputSplitAverage_Constraint + M.LimitTechInputSplitAverageConstraint_rpitv, + rule=limits.LimitTechInputSplitAverage_Constraint, ) ## Tech output splits @@ -1111,14 +1063,15 @@ def __init__(M, *args, **kwargs): dimen=8, initialize=limits.LimitTechOutputSplitConstraintIndices ) M.LimitTechOutputSplitConstraint = Constraint( - M.LimitTechOutputSplitConstraint_rpsdtvo, rule=LimitTechOutputSplit_Constraint + M.LimitTechOutputSplitConstraint_rpsdtvo, rule=limits.LimitTechOutputSplit_Constraint ) M.LimitTechOutputSplitAnnualConstraint_rptvo = Set( dimen=6, initialize=limits.LimitTechOutputSplitAnnualConstraintIndices ) M.LimitTechOutputSplitAnnualConstraint = Constraint( - M.LimitTechOutputSplitAnnualConstraint_rptvo, rule=LimitTechOutputSplitAnnual_Constraint + M.LimitTechOutputSplitAnnualConstraint_rptvo, + rule=limits.LimitTechOutputSplitAnnual_Constraint, ) M.LimitTechOutputSplitAverageConstraint_rptvo = Set( @@ -1126,11 +1079,12 @@ def __init__(M, *args, **kwargs): ) M.LimitTechOutputSplitAverageConstraint = Constraint( M.LimitTechOutputSplitAverageConstraint_rptvo, - rule=LimitTechOutputSplitAverage_Constraint, + rule=limits.LimitTechOutputSplitAverage_Constraint, ) M.RenewablePortfolioStandardConstraint = Constraint( - M.RenewablePortfolioStandardConstraint_rpg, rule=RenewablePortfolioStandard_Constraint + M.RenewablePortfolioStandardConstraint_rpg, + rule=limits.RenewablePortfolioStandard_Constraint, ) M.LinkedEmissionsTechConstraint_rpsdtve = Set( @@ -1140,7 +1094,7 @@ def __init__(M, *args, **kwargs): M.validate_LinkedTech_lifetimes = BuildCheck(rule=validate_linked_tech) M.LinkedEmissionsTechConstraint = Constraint( - M.LinkedEmissionsTechConstraint_rpsdtve, rule=LinkedEmissionsTech_Constraint + M.LinkedEmissionsTechConstraint_rpsdtve, rule=emissions.LinkedEmissionsTech_Constraint ) M.progress_marker_9 = BuildAction(['Finished Constraints'], rule=progress_check) diff --git a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py index da45e2b07..92d8eefed 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py +++ b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py @@ -47,7 +47,7 @@ from temoa._internal.hybrid_loader import HybridLoader from temoa._internal.run_actions import build_instance from temoa._internal.table_writer import TableWriter -from temoa._internal.temoa_rules import TotalCost_rule +from temoa.components.costs import TotalCost_rule from temoa.core.config import TemoaConfig from temoa.core.model import TemoaModel from temoa.extensions.modeling_to_generate_alternatives.manager_factory import get_manager @@ -227,7 +227,7 @@ def start(self): s_path = Path(get_OUTPUT_PATH(), 'solver_logs') if not s_path.exists(): s_path.mkdir() - for i in range(num_workers): + for _ in range(num_workers): w = Worker( model_queue=work_queue, results_queue=result_queue, diff --git a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py index 5fab60d10..a0e1cc6b9 100644 --- a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py +++ b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py @@ -41,7 +41,7 @@ from temoa._internal.hybrid_loader import HybridLoader from temoa._internal.run_actions import build_instance, handle_results, save_lp, solve_instance from temoa._internal.table_writer import TableWriter -from temoa._internal.temoa_rules import TotalCost_rule +from temoa.components.costs import TotalCost_rule from temoa.core.config import TemoaConfig from temoa.core.model import TemoaModel from temoa.extensions.single_vector_mga.output_summary import summarize From ff6e71f0f123238b5083f06c28dcff271883818d Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 8 Oct 2025 17:58:31 -0400 Subject: [PATCH 221/587] fixing linting errors in _internal --- temoa/_internal/hybrid_loader.py | 2 +- temoa/_internal/run_actions.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/temoa/_internal/hybrid_loader.py b/temoa/_internal/hybrid_loader.py index a95a50a0c..effce1368 100644 --- a/temoa/_internal/hybrid_loader.py +++ b/temoa/_internal/hybrid_loader.py @@ -321,7 +321,7 @@ def load_element( except ValueError as e: raise ValueError( 'Failed to validate members of %s. Coding error likely.\n%s' % (c.name, e) - ) + ) from e if len(screened) < len(values): msg = 'Some values for {} failed to validate and were ignored: {}' logger.warning(msg.format(c.name, [val for val in values if val not in screened])) diff --git a/temoa/_internal/run_actions.py b/temoa/_internal/run_actions.py index 019e71fe8..64242d73f 100644 --- a/temoa/_internal/run_actions.py +++ b/temoa/_internal/run_actions.py @@ -175,7 +175,7 @@ def build_instance( '\r[%8.2f] Instance created. \n' % (time() - hack) ) # needs spaces to clear previous line SE.flush() - except: + except Exception: SE.write( '\r[%8.2f] Instance created. \n' % (time() - hack) ) # needs spaces to clear previous line @@ -342,7 +342,6 @@ def check_solve_status(result: SolverResults) -> tuple[bool, str]: """ soln = result['Solution'] - lesser_responses = ('feasible', 'globallyOptimal', 'locallyOptimal') logger.info('The solver reported status as: %s', soln.Status) if check_optimal_termination(results=result): return True, '' From 08448e896a733adda0701ec341dad49bba2e9d1e Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 8 Oct 2025 17:59:35 -0400 Subject: [PATCH 222/587] fixing linting errors in components --- temoa/components/commodities.py | 1 - temoa/components/costs.py | 1 - temoa/components/ramping.py | 4 ++-- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index 68ebcf951..c2b8d1dee 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -3,7 +3,6 @@ from logging import getLogger from operator import itemgetter as iget from typing import TYPE_CHECKING -from pyomo.environ import Constraint, value from pyomo.environ import value diff --git a/temoa/components/costs.py b/temoa/components/costs.py index d4c7a8e71..21abc5db4 100644 --- a/temoa/components/costs.py +++ b/temoa/components/costs.py @@ -3,7 +3,6 @@ from typing import TYPE_CHECKING from deprecated import deprecated - from pyomo.core import Expression, Var from pyomo.environ import value diff --git a/temoa/components/ramping.py b/temoa/components/ramping.py index bc80f14cd..71e11d21a 100644 --- a/temoa/components/ramping.py +++ b/temoa/components/ramping.py @@ -1,8 +1,8 @@ +from logging import getLogger from typing import TYPE_CHECKING -from logging import getLogger -from pyomo.environ import Constraint, value from pyomo.core import Set +from pyomo.environ import Constraint, value if TYPE_CHECKING: from temoa.core.model import TemoaModel From 5eb0b3d3056386537a015b09fc7000f20f96f31b Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 9 Oct 2025 15:22:22 -0400 Subject: [PATCH 223/587] splitting up CreateSparseDicts, storing the chunks in precompute for now --- temoa/_internal/precompute.py | 340 +++++++++++++++++++ temoa/_internal/temoa_initialize.py | 502 ---------------------------- temoa/components/limits.py | 2 +- temoa/core/model.py | 56 +++- 4 files changed, 386 insertions(+), 514 deletions(-) create mode 100644 temoa/_internal/precompute.py delete mode 100644 temoa/_internal/temoa_initialize.py diff --git a/temoa/_internal/precompute.py b/temoa/_internal/precompute.py new file mode 100644 index 000000000..51d572cc6 --- /dev/null +++ b/temoa/_internal/precompute.py @@ -0,0 +1,340 @@ +# temoa/_internal/precompute.py +from logging import getLogger +from typing import TYPE_CHECKING + +from pyomo.environ import value + +if TYPE_CHECKING: + from temoa.core.model import TemoaModel + +logger = getLogger(__name__) + + +def _populate_core_dictionaries(M: 'TemoaModel'): + """ + Loops through the Efficiency parameter to populate the core sparse dictionaries + that define process relationships, inputs, outputs, and active periods. + + This function is foundational for creating the sparse indices used throughout the model. + """ + logger.debug('Populating core sparse dictionaries from Efficiency parameter.') + first_period = min(M.time_future) + exist_indices = M.ExistingCapacity.sparse_keys() + + for r, i, t, v, o in M.Efficiency.sparse_iterkeys(): + # A. Basic data validation and warnings + process = (r, t, v) + lifetime = value(M.LifetimeProcess[process]) + if v in M.vintage_exist: + if process not in exist_indices and t not in M.tech_uncap: + logger.warning( + f'Warning: {process} has a specified Efficiency, but does not ' + f'have any existing install base (ExistingCapacity).' + ) + continue + if t not in M.tech_uncap and M.ExistingCapacity[process] == 0: + logger.warning( + f'Notice: Unnecessary specification of ExistingCapacity for {process}. ' + f'Declaring a capacity of zero may be omitted.' + ) + continue + if v + lifetime <= first_period: + logger.info( + f'{process} specified as ExistingCapacity, but its ' + f'lifetime ({lifetime} years) does not extend past the ' + f'beginning of time_future ({first_period}).' + ) + + if M.Efficiency[r, i, t, v, o] == 0: + logger.info( + f'Notice: Unnecessary specification of Efficiency for {(r, i, t, v, o)}. ' + f'Specifying an efficiency of zero may be omitted.' + ) + continue + + M.used_techs.add(t) + + # B. Loop through time periods to build time-dependent relationships + for p in M.time_optimize: + # Skip if tech is not invented or is already retired + if p < v or v + lifetime <= p: + continue + + pindex = (r, p, t, v) + + # C. Initialize dictionary keys if not present + if pindex not in M.processInputs: + M.processInputs[pindex] = set() + M.processOutputs[pindex] = set() + if (r, p, i) not in M.commodityDStreamProcess: + M.commodityDStreamProcess[r, p, i] = set() + if (r, p, o) not in M.commodityUStreamProcess: + M.commodityUStreamProcess[r, p, o] = set() + if (r, p, t, v, i) not in M.processOutputsByInput: + M.processOutputsByInput[r, p, t, v, i] = set() + if (r, p, t, v, o) not in M.processInputsByOutput: + M.processInputsByOutput[r, p, t, v, o] = set() + if (r, p, t) not in M.processVintages: + M.processVintages[r, p, t] = set() + if (r, t, v) not in M.processPeriods: + M.processPeriods[r, t, v] = set() + + # D. Populate the dictionaries + M.processInputs[pindex].add(i) + M.processOutputs[pindex].add(o) + M.commodityDStreamProcess[r, p, i].add((t, v)) + M.commodityUStreamProcess[r, p, o].add((t, v)) + M.processOutputsByInput[r, p, t, v, i].add(o) + M.processInputsByOutput[r, p, t, v, o].add(i) + M.processVintages[r, p, t].add(v) + M.processPeriods[r, t, v].add(p) + + +def _create_technology_and_commodity_sets(M: 'TemoaModel'): + """ + Populates technology and commodity subset definitions based on their roles + (e.g., demand, flexible) identified from the Efficiency parameter. + """ + logger.debug('Creating technology and commodity subsets.') + for _r, _i, t, _v, o in M.Efficiency.sparse_iterkeys(): + if t in M.tech_flex and o not in M.commodity_flex: + M.commodity_flex.add(o) + + if o in M.commodity_demand and t not in M.tech_demand: + M.tech_demand.add(t) + + +def _create_operational_vintage_sets(M: 'TemoaModel'): + """ + Populates vintage-based dictionaries for technologies with special + operational characteristics like curtailment, baseload, storage, ramping, and reserves. + """ + logger.debug('Creating vintage sets for operational constraints.') + + # Initialize the dictionaries to prevent KeyErrors later + M.curtailmentVintages = {} + M.baseloadVintages = {} + M.storageVintages = {} + M.rampUpVintages = {} + M.rampDownVintages = {} + M.isSeasonalStorage = {} + M.processReservePeriods = {} # Initialize the missing dictionary + + # Now populate them + for r, p, t in M.processVintages: + for v in M.processVintages[r, p, t]: + key_rpt = (r, p, t) + key_rp = (r, p) + if t in M.tech_curtailment: + M.curtailmentVintages.setdefault(key_rpt, set()).add(v) + if t in M.tech_baseload: + M.baseloadVintages.setdefault(key_rpt, set()).add(v) + if t in M.tech_storage: + M.storageVintages.setdefault(key_rpt, set()).add(v) + if t in M.tech_upramping: + M.rampUpVintages.setdefault(key_rpt, set()).add(v) + if t in M.tech_downramping: + M.rampDownVintages.setdefault(key_rpt, set()).add(v) + if t in M.tech_reserve: + M.processReservePeriods.setdefault(key_rp, set()).add((t, v)) + + # A dictionary of whether a storage tech is seasonal, just to speed things up + for t in M.tech_storage: + M.isSeasonalStorage[t] = t in M.tech_seasonal_storage + + +def _create_limit_vintage_sets(M: 'TemoaModel'): + """ + Populates vintage sets for technologies constrained by input/output split limits. + """ + logger.debug('Creating vintage sets for split limits.') + # Assuming M.processVintages is already populated + for r, p, t in M.processVintages: + for v in M.processVintages[r, p, t]: + for i in M.processInputs.get((r, p, t, v), []): + for op in M.operator: + if (r, p, i, t, op) in M.LimitTechInputSplit: + M.inputSplitVintages.setdefault((r, p, i, t, op), set()).add(v) + if (r, p, i, t, op) in M.LimitTechInputSplitAnnual: + M.inputSplitAnnualVintages.setdefault((r, p, i, t, op), set()).add(v) + + for o in M.processOutputs.get((r, p, t, v), []): + for op in M.operator: + if (r, p, t, o, op) in M.LimitTechOutputSplit: + M.outputSplitVintages.setdefault((r, p, t, o, op), set()).add(v) + if (r, p, t, o, op) in M.LimitTechOutputSplitAnnual: + M.outputSplitAnnualVintages.setdefault((r, p, t, o, op), set()).add(v) + + +# In temoa/_internal/precompute.py +def _create_geography_sets(M: 'TemoaModel'): + """Populates dictionaries related to inter-regional commodity exchange.""" + logger.debug('Creating geography-related sets for exchange technologies.') + for r, i, t, v, o in M.Efficiency.sparse_iterkeys(): + if t not in M.tech_exchange: + continue + + if '-' not in r: + msg = f"Exchange technology {t} has an invalid region '{r}'. Must be 'region_from-region_to'." + logger.error(msg) + raise ValueError(msg) + + region_from, region_to = r.split('-', 1) + + lifetime = value(M.LifetimeProcess[r, t, v]) + for p in M.time_optimize: + if p >= v and v + lifetime > p: + M.exportRegions.setdefault((region_from, p, i), set()).add((region_to, t, v, o)) + M.importRegions.setdefault((region_to, p, o), set()).add((region_from, t, v, i)) + + +# In temoa/_internal/precompute.py +def _create_capacity_and_retirement_sets(M: 'TemoaModel'): + """ + Creates sets and dictionaries related to technology capacity, retirement, + and end-of-life material flows. + """ + logger.debug('Creating capacity, retirement, and construction/EOL sets.') + # Retirement periods + for r, _i, t, v, _o in M.Efficiency.sparse_iterkeys(): + lifetime = value(M.LifetimeProcess[r, t, v]) + for p in M.time_optimize: + is_natural_eol = p <= v + lifetime < p + value(M.PeriodLength[p]) + is_early_retire = t in M.tech_retirement and v < p <= v + lifetime - value( + M.PeriodLength[p] + ) + is_survival_curve = M.isSurvivalCurveProcess[r, t, v] and v <= p <= v + lifetime + + if t not in M.tech_uncap and any((is_natural_eol, is_early_retire, is_survival_curve)): + M.retirementPeriods.setdefault((r, t, v), set()).add(p) + + # Construction and End-of-life flows + for r, i, t, v in M.ConstructionInput.sparse_iterkeys(): + M.capacityConsumptionTechs.setdefault((r, v, i), set()).add(t) + + for r, t, v, o in M.EndOfLifeOutput.sparse_iterkeys(): + if (r, t, v) in M.retirementPeriods: + for p in M.retirementPeriods[r, t, v]: + M.retirementProductionProcesses.setdefault((r, p, o), set()).add((t, v)) + + # Active capacity sets + M.newCapacity_rtv = set( + (r, t, v) + for r, p, t in M.processVintages + for v in M.processVintages[r, p, t] + if t not in M.tech_uncap and v in M.time_optimize + ) + M.activeCapacityAvailable_rpt = set( + (r, p, t) + for r, p, t in M.processVintages + if M.processVintages[r, p, t] and t not in M.tech_uncap + ) + M.activeCapacityAvailable_rptv = set( + (r, p, t, v) + for r, p, t in M.processVintages + for v in M.processVintages[r, p, t] + if t not in M.tech_uncap + ) + + +def _create_commodity_balance_and_flow_sets(M: 'TemoaModel'): + """ + Creates the aggregated sets required for commodity balance constraints + and the indexed sets for active technology flows, capacities, and storage levels. + """ + logger.debug('Creating commodity balance and active flow index sets.') + # 1. Commodity Balance + commodity_upstream = set( + M.commodityUStreamProcess | M.retirementProductionProcesses | M.importRegions + ) + commodity_downstream = set( + M.commodityDStreamProcess | M.capacityConsumptionTechs | M.exportRegions + ) + M.commodityBalance_rpc = commodity_upstream.intersection(commodity_downstream) + + # 2. Active Flow Indices (Time-Sliced) + M.activeFlow_rpsditvo = set( + (r, p, s, d, i, t, v, o) + for r, p, t in M.processVintages + if t not in M.tech_annual + for v in M.processVintages[r, p, t] + for i in M.processInputs.get((r, p, t, v), set()) + for o in M.processOutputsByInput.get((r, p, t, v, i), set()) + for s in M.TimeSeason[p] # REVERTED THIS LINE + for d in M.time_of_day + ) + + # 3. Active Flow Indices (Annual) + M.activeFlow_rpitvo = set( + (r, p, i, t, v, o) + for r, p, t in M.processVintages + for v in M.processVintages[r, p, t] + for i in M.processInputs.get((r, p, t, v), set()) + for o in M.processOutputsByInput.get((r, p, t, v, i), set()) + if t in M.tech_annual or (t in M.tech_demand and o in M.commodity_demand) + ) + + # 4. Active Flexible Technology Flow Indices + M.activeFlex_rpsditvo = set( + (r, p, s, d, i, t, v, o) + for r, p, t in M.processVintages + if (t not in M.tech_annual) and (t in M.tech_flex) + for v in M.processVintages[r, p, t] + for i in M.processInputs.get((r, p, t, v), set()) + for o in M.processOutputsByInput.get((r, p, t, v, i), set()) + for s in M.TimeSeason[p] # REVERTED THIS LINE + for d in M.time_of_day + ) + + M.activeFlex_rpitvo = set( + (r, p, i, t, v, o) + for r, p, t in M.processVintages + if (t in M.tech_annual) and (t in M.tech_flex) + for v in M.processVintages[r, p, t] + for i in M.processInputs.get((r, p, t, v), set()) + for o in M.processOutputsByInput.get((r, p, t, v, i), set()) + ) + + # 5. Active Storage and Curtailment Indices + M.activeFlowInStorage_rpsditvo = set( + (r, p, s, d, i, t, v, o) + for r, p, t in M.storageVintages + for v in M.storageVintages[r, p, t] + for i in M.processInputs.get((r, p, t, v), set()) + for o in M.processOutputsByInput.get((r, p, t, v, i), set()) + for s in M.TimeSeason[p] # REVERTED THIS LINE + for d in M.time_of_day + ) + + M.activeCurtailment_rpsditvo = set( + (r, p, s, d, i, t, v, o) + for r, p, t in M.curtailmentVintages + for v in M.curtailmentVintages[r, p, t] + for i in M.processInputs.get((r, p, t, v), set()) + for o in M.processOutputsByInput.get((r, p, t, v, i), set()) + for s in M.TimeSeason[p] # REVERTED THIS LINE + for d in M.time_of_day + ) + + # 6. Active Technology and Capacity Indices + M.activeActivity_rptv = set( + (r, p, t, v) for r, p, t in M.processVintages for v in M.processVintages[r, p, t] + ) + + # 7. Storage Level Indices + M.storageLevelIndices_rpsdtv = set( + (r, p, s, d, t, v) + for r, p, t in M.storageVintages + for v in M.storageVintages[r, p, t] + for s in M.TimeSeason[p] # REVERTED THIS LINE + for d in M.time_of_day + ) + + M.seasonalStorageLevelIndices_rpstv = set( + (r, p, s_stor, t, v) + for r, p, t in M.storageVintages + if t in M.tech_seasonal_storage + for v in M.storageVintages[r, p, t] + for _p, s_stor in M.sequential_to_season + if _p == p + ) diff --git a/temoa/_internal/temoa_initialize.py b/temoa/_internal/temoa_initialize.py deleted file mode 100644 index c94ef158e..000000000 --- a/temoa/_internal/temoa_initialize.py +++ /dev/null @@ -1,502 +0,0 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . -""" - -from sys import stderr as SE -from typing import TYPE_CHECKING - -from pyomo.core import Set - -if TYPE_CHECKING: - from temoa.core.model import TemoaModel - - -from logging import getLogger - -from pyomo.environ import value - -logger = getLogger(name=__name__) - - -# --------------------------------------------------------------- -# Validation and initialization routines. -# There are a variety of functions in this section that do the following: -# Check valid indices, validate parameter specifications, and set default -# parameter values. -# --------------------------------------------------------------- - - -# ============================================================================ -# Public API - Functions intended for external import -# ============================================================================ -__all__ = [ - # Index creation functions for constraints and variables - 'CreateSparseDicts', -] - - -def isValidProcess(M: 'TemoaModel', r, p, i, t, v, o): - """\ -Returns a boolean (True or False) indicating whether, in any given period, a -technology can take a specified input carrier and convert it to and specified -output carrier. Not currently used. -""" - index = (r, p, t, v) - if index in M.processInputs and index in M.processOutputs: - if i in M.processInputs[index]: - if o in M.processOutputs[index]: - return True - - return False - - -# --------------------------------------------------------------- -# The functions below perform the sparse matrix indexing, allowing Pyomo to only -# create the necessary parameter, variable, and constraint indices. This -# cuts down *tremendously* on memory usage, which decreases time and increases -# the maximum specifiable problem size. -# -# It begins below in CreateSparseDicts, which creates a set of -# dictionaries that serve as the basis of the sparse indices. -# --------------------------------------------------------------- - - -def CreateSparseDicts(M: 'TemoaModel'): - """ - This function creates customized dictionaries with only the key / value pairs - defined in the associated datafile. The dictionaries defined here are used to - do the sparse matrix indexing for all parameters, variables, and constraints - in the model. The function works by looping over the sparse indices in the - Efficiency table. For each iteration of the loop, the appropriate key / value - pairs are defined as appropriate for each dictionary. - """ - l_first_period = min(M.time_future) - l_exist_indices = M.ExistingCapacity.sparse_keys() - l_used_techs = set() - - # The basis for the dictionaries are the sparse keys defined in the - # Efficiency table. - logger.debug( - 'Starting creation of SparseDicts with Efficiency table size: %d', len(M.Efficiency) - ) - for r, i, t, v, o in M.Efficiency.sparse_iterkeys(): - if '-' in r and t not in M.tech_exchange: - msg = ( - f'Technology {t} seems to be an exchange technology ' - f'but it is not specified in tech_exchange set' - ) - logger.error(msg) - raise ValueError(msg) - l_process = (r, t, v) - l_lifetime = value(M.LifetimeProcess[l_process]) - # Do some error checking for the user. - if v in M.vintage_exist: - if l_process not in l_exist_indices and t not in M.tech_uncap: - msg = ( - 'Warning: %s has a specified Efficiency, but does not ' - 'have any existing install base (ExistingCapacity).\n' - ) - logger.warning(msg, str(l_process)) - # SE.write(msg % str(l_process)) - continue - if t not in M.tech_uncap and M.ExistingCapacity[l_process] == 0: - msg = ( - 'Notice: Unnecessary specification of ExistingCapacity ' - '%s. If specifying a capacity of zero, you may simply ' - 'omit the declaration.\n' - ) - logger.warning(msg, str(l_process)) - # SE.write(msg % str(l_process)) - continue - if v + l_lifetime <= l_first_period: - msg = ( - '{} specified as ExistingCapacity, but its ' - 'lifetime ({} years) does not extend past the ' - 'beginning of time_future ({}) so it is never active. This ' - 'may be intentional for use in Growth constraints ' - 'or end of life flows.' - ).format(l_process, l_lifetime, l_first_period) - logger.info(msg) - # Devnote: these are now useful due to end of life flows and - # Growth constraints growing from existing cap so do not skip - # SE.write(msg % (l_process, l_lifetime, l_first_period)) - # continue - - eindex = (r, i, t, v, o) - if M.Efficiency[eindex] == 0: - msg = ( - '\nNotice: Unnecessary specification of Efficiency %s. If ' - 'specifying an efficiency of zero, you may simply omit the ' - 'declaration.\n' - ) - logger.info(msg, str(eindex)) - SE.write(msg % str(eindex)) - continue - - l_used_techs.add(t) - - if t in M.tech_flex and o not in M.commodity_flex: - M.commodity_flex.add(o) - - # All demand technologies must be annual technologies - if o in M.commodity_demand and t not in M.tech_demand: - M.tech_demand.add(t) - - # Add in the period (p) index, since it's not included in the efficiency - # table. - for p in M.time_optimize: - # Can't build a vintage before it's been invented - if p < v: - continue - - pindex = (r, p, t, v) - - # dev note: this gathering of processLoans appears to be unused in any meaningful way - # it is just plucked later for (r, t, v) combos which aren't needed anyhow. - # if v in M.time_optimize: - # l_loan_life = value(M.LoanLifetimeProcess[l_process]) - # if v + l_loan_life >= p: - # M.processLoans[pindex] = True - - # Get all periods where the process can retire - if t not in M.tech_uncap and any( - ( - p <= v + l_lifetime < p + value(M.PeriodLength[p]), # natural eol this period - t in M.tech_retirement - and v - < p - <= v + l_lifetime - value(M.PeriodLength[p]), # allowed early retirement - M.isSurvivalCurveProcess[r, t, v] and v <= p <= v + l_lifetime, - ) - ): - if (r, t, v) not in M.retirementPeriods: - M.retirementPeriods[r, t, v] = set() - M.retirementPeriods[r, t, v].add(p) - - # if tech is no longer active, don't include it - if v + l_lifetime <= p: - continue - - # Here we utilize the indices in a given iteration of the loop to - # create the dictionary keys, and initialize the associated values - # to an empty set. - if pindex not in M.processInputs: - M.processInputs[pindex] = set() - M.processOutputs[pindex] = set() - if (r, p, i) not in M.commodityDStreamProcess: - M.commodityDStreamProcess[r, p, i] = set() - if (r, p, o) not in M.commodityUStreamProcess: - M.commodityUStreamProcess[r, p, o] = set() - if (r, p, t, v, i) not in M.processOutputsByInput: - M.processOutputsByInput[r, p, t, v, i] = set() - if (r, p, t, v, o) not in M.processInputsByOutput: - M.processInputsByOutput[r, p, t, v, o] = set() - if (r, t) not in M.processTechs: - M.processTechs[r, t] = set() - # While the dictionary just above identifies the vintage (v) - # associated with each (r,p,t) we need to do the same below for various - # technology subsets. - if (r, p, t) not in M.processVintages: - M.processVintages[r, p, t] = set() - if (r, t, v) not in M.processPeriods: - M.processPeriods[r, t, v] = set() - if t in M.tech_curtailment and (r, p, t) not in M.curtailmentVintages: - M.curtailmentVintages[r, p, t] = set() - if t in M.tech_baseload and (r, p, t) not in M.baseloadVintages: - M.baseloadVintages[r, p, t] = set() - if t in M.tech_storage and (r, p, t) not in M.storageVintages: - M.storageVintages[r, p, t] = set() - if t in M.tech_upramping and (r, p, t) not in M.rampUpVintages: - M.rampUpVintages[r, p, t] = set() - if t in M.tech_downramping and (r, p, t) not in M.rampDownVintages: - M.rampDownVintages[r, p, t] = set() - - # tech split - for op in M.operator: - if (r, p, i, t, op) in M.LimitTechInputSplit: - if (r, p, i, t, op) not in M.inputSplitVintages: - M.inputSplitVintages[r, p, i, t, op] = set() - M.inputSplitVintages[r, p, i, t, op].add(v) - if (r, p, i, t, op) in M.LimitTechInputSplitAnnual: - if (r, p, i, t, op) not in M.inputSplitAnnualVintages: - M.inputSplitAnnualVintages[r, p, i, t, op] = set() - M.inputSplitAnnualVintages[r, p, i, t, op].add(v) - if (r, p, t, o, op) in M.LimitTechOutputSplit: - if (r, p, t, o, op) not in M.outputSplitVintages: - M.outputSplitVintages[r, p, t, o, op] = set() - M.outputSplitVintages[r, p, t, o, op].add(v) - if (r, p, t, o, op) in M.LimitTechOutputSplitAnnual: - if (r, p, t, o, op) not in M.outputSplitAnnualVintages: - M.outputSplitAnnualVintages[r, p, t, o, op] = set() - M.outputSplitAnnualVintages[r, p, t, o, op].add(v) - - # if t in M.tech_resource and (r, p, o) not in M.processByPeriodAndOutput: # not currently used - # M.processByPeriodAndOutput[r, p, o] = set() - if t in M.tech_reserve and (r, p) not in M.processReservePeriods: - M.processReservePeriods[r, p] = set() - - # since t is in M.tech_exchange, r here has *-* format (e.g. 'US-Mexico'). # r[ - # :r.find("-")] extracts the region index before the "-". - if t in M.tech_exchange and (r[: r.find('-')], p, i) not in M.exportRegions: - M.exportRegions[r[: r.find('-')], p, i] = set() - if t in M.tech_exchange and (r[r.find('-') + 1 :], p, o) not in M.importRegions: - M.importRegions[r[r.find('-') + 1 :], p, o] = set() - - # Now that all of the keys have been defined, and values initialized - # to empty sets, we fill in the appropriate values for each - # dictionary. - M.processInputs[pindex].add(i) - M.processOutputs[pindex].add(o) - M.commodityDStreamProcess[r, p, i].add((t, v)) - M.commodityUStreamProcess[r, p, o].add((t, v)) - M.processOutputsByInput[r, p, t, v, i].add(o) - M.processInputsByOutput[r, p, t, v, o].add(i) - M.processTechs[r, t].add((p, v)) - M.processVintages[r, p, t].add(v) - M.processPeriods[r, t, v].add(p) - if t in M.tech_curtailment: - M.curtailmentVintages[r, p, t].add(v) - if t in M.tech_baseload: - M.baseloadVintages[r, p, t].add(v) - if t in M.tech_storage: - M.storageVintages[r, p, t].add(v) - if t in M.tech_upramping: - M.rampUpVintages[r, p, t].add(v) - if t in M.tech_downramping: - M.rampDownVintages[r, p, t].add(v) - - # if t in M.tech_resource: - # M.processByPeriodAndOutput[r, p, o].add((i, t, v)) # not currently used - if t in M.tech_reserve: - M.processReservePeriods[r, p].add((t, v)) - if t in M.tech_exchange: - M.exportRegions[r[: r.find('-')], p, i].add((r[r.find('-') + 1 :], t, v, o)) - if t in M.tech_exchange: - M.importRegions[r[r.find('-') + 1 :], p, o].add((r[: r.find('-')], t, v, i)) - - # devnote: I think this was only necessary because the commodity balance constraint rpc indices - # weren't accounting for imports/exports. I added them to the set below so this should be fixed - # for r, i, t, v, o in M.Efficiency.sparse_iterkeys(): - # if t in M.tech_exchange: - # reg = r.split('-')[0] - # for r1, i1, t1, v1, o1 in M.Efficiency.sparse_iterkeys(): - # if (r1 == reg) & (o1 == i): - # for p in M.time_optimize: - # if p >= v and (r1, p, o1) not in M.commodityDStreamProcess: - # msg = ( - # 'The {} process in region {} has no downstream process other ' - # 'than a transport ({}) process. This will cause the commodity ' - # 'balance constraint to fail. Add a dummy technology downstream ' - # 'of the {} process to the Efficiency table to avoid this ' - # 'issue. The dummy technology should have the same region and ' - # 'vintage as the {} process, an efficiency of 100%, with the {} ' - # 'commodity as the input and output.' - # 'The dummy technology may also need a corresponding row in the ' - # 'ExistingCapacity table with capacity values that equal the {} ' - # 'technology.' - # ) - # f_msg = msg.format(t1, r1, t, t1, t1, o1, t1) - # logger.error(f_msg) - # raise ValueError(f_msg) - - # Need this here for the commodity balance rpc set - for r, i, t, v in M.ConstructionInput.sparse_iterkeys(): - if (r, v, i) not in M.capacityConsumptionTechs: - M.capacityConsumptionTechs[r, v, i] = set() - M.capacityConsumptionTechs[r, v, i].add(t) - for r, t, v, o in M.EndOfLifeOutput.sparse_iterkeys(): - if (r, t, v) not in M.retirementPeriods: - continue # might be running myopic - for p in M.retirementPeriods[r, t, v]: - # What periods can this process retire in, either naturally or economically? - if (r, p, o) not in M.retirementProductionProcesses: - M.retirementProductionProcesses[r, p, o] = set() - M.retirementProductionProcesses[r, p, o].add((t, v)) - - l_unused_techs = M.tech_all - l_used_techs - if l_unused_techs: - msg = ( - "Notice: '{}' specified as technology, but it is not utilized in " - 'the Efficiency parameter.\n' - ) - for i in sorted(l_unused_techs): - SE.write(msg.format(i)) - - # valid region-period-commodity sets for commodity balance constraints - commodityUpstream_rpi = set( - M.commodityUStreamProcess | M.retirementProductionProcesses | M.importRegions - ) - commodityDownstream_rpo = set( - M.commodityDStreamProcess | M.capacityConsumptionTechs | M.exportRegions - ) - M.commodityBalance_rpc = commodityUpstream_rpi.intersection(commodityDownstream_rpo) - - # A dictionary of whether a storage tech is seasonal, just to speed things up - for t in M.tech_storage: - M.isSeasonalStorage[t] = False - for t in M.tech_seasonal_storage: - M.isSeasonalStorage[t] = True - - M.activeFlow_rpsditvo = set( - (r, p, s, d, i, t, v, o) - for r, p, t in M.processVintages - if t not in M.tech_annual - for v in M.processVintages[r, p, t] - for i in M.processInputs[r, p, t, v] - for o in M.processOutputsByInput[r, p, t, v, i] - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - - M.activeFlow_rpitvo = set( - (r, p, i, t, v, o) - for r, p, t in M.processVintages - for v in M.processVintages[r, p, t] - for i in M.processInputs[r, p, t, v] - for o in M.processOutputsByInput[r, p, t, v, i] - if t in M.tech_annual or (t in M.tech_demand and o in M.commodity_demand) - ) - - M.activeFlex_rpsditvo = set( - (r, p, s, d, i, t, v, o) - for r, p, t in M.processVintages - if (t not in M.tech_annual) and (t in M.tech_flex) - for v in M.processVintages[r, p, t] - for i in M.processInputs[r, p, t, v] - for o in M.processOutputsByInput[r, p, t, v, i] - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - - M.activeFlex_rpitvo = set( - (r, p, i, t, v, o) - for r, p, t in M.processVintages - if (t in M.tech_annual) and (t in M.tech_flex) - for v in M.processVintages[r, p, t] - for i in M.processInputs[r, p, t, v] - for o in M.processOutputsByInput[r, p, t, v, i] - ) - - M.activeFlowInStorage_rpsditvo = set( - (r, p, s, d, i, t, v, o) - for r, p, t in M.processVintages - if t in M.tech_storage - for v in M.processVintages[r, p, t] - for i in M.processInputs[r, p, t, v] - for o in M.processOutputsByInput[r, p, t, v, i] - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - - M.activeCurtailment_rpsditvo = set( - (r, p, s, d, i, t, v, o) - for r, p, t in M.curtailmentVintages - for v in M.curtailmentVintages[r, p, t] - for i in M.processInputs[r, p, t, v] - for o in M.processOutputsByInput[r, p, t, v, i] - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - - M.activeActivity_rptv = set( - (r, p, t, v) for r, p, t in M.processVintages for v in M.processVintages[r, p, t] - ) - - # devnote: currently unused - # M.activeRegionsForTech = defaultdict(set) - # for r, p, t, v in M.activeActivity_rptv: - # M.activeRegionsForTech[p, t].add(r) - - M.newCapacity_rtv = set( - (r, t, v) - for r, p, t in M.processVintages - for v in M.processVintages[r, p, t] - if t not in M.tech_uncap and v in M.time_optimize - ) - - M.activeCapacityAvailable_rpt = set( - (r, p, t) - for r, p, t in M.processVintages - if M.processVintages[r, p, t] - if t not in M.tech_uncap - ) - - M.activeCapacityAvailable_rptv = set( - (r, p, t, v) - for r, p, t in M.processVintages - for v in M.processVintages[r, p, t] - if t not in M.tech_uncap - ) - - # devnote: currently unused - # M.groupRegionActiveFlow_rpt = set( - # (gr, p, t) - # for _r, p, t in M.processVintages - # for gr in M.regionalGlobalIndices - # if _r in gather_group_regions(M, gr) - # ) - - M.storageLevelIndices_rpsdtv = set( - (r, p, s, d, t, v) - for r, p, t in M.storageVintages - for v in M.storageVintages[r, p, t] - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - - M.seasonalStorageLevelIndices_rpstv = set( - (r, p, s_stor, t, v) - for r, p, t in M.storageVintages - if t in M.tech_seasonal_storage - for v in M.storageVintages[r, p, t] - for _p, s_stor in M.sequential_to_season - if _p == p - ) - - logger.debug('Completed creation of SparseDicts') - - -# --------------------------------------------------------------- -# Create sparse parameter indices. -# These functions are called from temoa_model.py and use the sparse keys -# associated with specific parameters. -# --------------------------------------------------------------- - - -# devnote: this does not appear to be used anywhere -# given that it doesnt check if periods are valid, cant think what it would be for -# def EmissionActivityByPeriodAndTechVariableIndices(M: 'TemoaModel'): -# indices = set( -# (e, p, t) for e, i, t, v, o in M.EmissionActivity.sparse_iterkeys() for p in M.time_optimize -# ) - -# return indices - - -# --------------------------------------------------------------- -# Create sparse indices for decision variables. -# These functions are called from temoa_model.py and use the dictionaries -# created above in CreateSparseDicts() -# --------------------------------------------------------------- - - -def copy_from(other_set): - """a cheap reference function to replace the lambdas in orig temoa_model""" - return Set(other_set.sparse_iterkeys()) diff --git a/temoa/components/limits.py b/temoa/components/limits.py index e5df3d4e9..b22023cd1 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -166,7 +166,7 @@ def RenewablePortfolioStandard_Constraint(M: 'TemoaModel', r, p, g): inp = sum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] for t in M.tech_group_members[g] - for (_t, v) in M.processReservePeriods[r, p] + for (_t, v) in M.processReservePeriods.get((r, p), []) if _t == t for s in M.TimeSeason[p] for d in M.time_of_day diff --git a/temoa/core/model.py b/temoa/core/model.py index 96e913526..0a7d9cb3d 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -23,12 +23,15 @@ minimize, ) -from temoa._internal.temoa_initialize import CreateSparseDicts - -# ============================================================================ -# Temoa Constraint Functions -# Core model constraints and business logic rules -# ============================================================================ +from temoa._internal.precompute import ( + _create_capacity_and_retirement_sets, + _create_commodity_balance_and_flow_sets, + _create_geography_sets, + _create_limit_vintage_sets, + _create_operational_vintage_sets, + _create_technology_and_commodity_sets, + _populate_core_dictionaries, +) from temoa.components import ( capacity, commodities, @@ -44,11 +47,6 @@ technology, time, ) - -# ============================================================================ -# Validation Functions -# Input validation and data integrity checks -# ============================================================================ from temoa.model_checking.validators import ( no_slash_or_pipe, region_check, @@ -63,6 +61,42 @@ logger = logging.getLogger(__name__) +def CreateSparseDicts(M: 'TemoaModel'): + """ + Creates and populates all sparse dictionaries and sets required for the model + by calling component-specific precomputation functions. + """ + # Initialize a set to track technologies used in the Efficiency table + M.used_techs = set() + + # Call the decomposed functions in logical order + # 1. Populate core relationships from Efficiency table + _populate_core_dictionaries(M) + + # 2. Classify technologies and commodities + _create_technology_and_commodity_sets(M) + + # 3. Create sets for specific components + _create_operational_vintage_sets(M) # For operations, storage, ramping + _create_limit_vintage_sets(M) # For limits + _create_geography_sets(M) # For geography/exchange + _create_capacity_and_retirement_sets(M) # For capacity + + # 4. Create final aggregated sets for constraints + _create_commodity_balance_and_flow_sets(M) # For flows and commodities + + # Final check for unused technologies + unused_techs = M.tech_all - M.used_techs + if unused_techs: + for tech in sorted(unused_techs): + logger.warning( + f"Notice: '{tech}' is specified as a technology but is not " + 'utilized in the Efficiency parameter.' + ) + + logger.debug('Completed creation of SparseDicts') + + class TemoaModel(AbstractModel): """ An instance of the abstract Temoa model From eea827162fd084eb6f94a5d2c7d4cf8801e2d950 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 9 Oct 2025 15:44:06 -0400 Subject: [PATCH 224/587] moving the chunked from precompute to the component files --- temoa/_internal/precompute.py | 340 -------------------------------- temoa/components/capacity.py | 48 +++++ temoa/components/commodities.py | 14 ++ temoa/components/flows.py | 106 ++++++++++ temoa/components/geography.py | 22 +++ temoa/components/limits.py | 23 +++ temoa/components/operations.py | 42 ++++ temoa/components/technology.py | 80 ++++++++ temoa/core/model.py | 23 +-- 9 files changed, 342 insertions(+), 356 deletions(-) delete mode 100644 temoa/_internal/precompute.py diff --git a/temoa/_internal/precompute.py b/temoa/_internal/precompute.py deleted file mode 100644 index 51d572cc6..000000000 --- a/temoa/_internal/precompute.py +++ /dev/null @@ -1,340 +0,0 @@ -# temoa/_internal/precompute.py -from logging import getLogger -from typing import TYPE_CHECKING - -from pyomo.environ import value - -if TYPE_CHECKING: - from temoa.core.model import TemoaModel - -logger = getLogger(__name__) - - -def _populate_core_dictionaries(M: 'TemoaModel'): - """ - Loops through the Efficiency parameter to populate the core sparse dictionaries - that define process relationships, inputs, outputs, and active periods. - - This function is foundational for creating the sparse indices used throughout the model. - """ - logger.debug('Populating core sparse dictionaries from Efficiency parameter.') - first_period = min(M.time_future) - exist_indices = M.ExistingCapacity.sparse_keys() - - for r, i, t, v, o in M.Efficiency.sparse_iterkeys(): - # A. Basic data validation and warnings - process = (r, t, v) - lifetime = value(M.LifetimeProcess[process]) - if v in M.vintage_exist: - if process not in exist_indices and t not in M.tech_uncap: - logger.warning( - f'Warning: {process} has a specified Efficiency, but does not ' - f'have any existing install base (ExistingCapacity).' - ) - continue - if t not in M.tech_uncap and M.ExistingCapacity[process] == 0: - logger.warning( - f'Notice: Unnecessary specification of ExistingCapacity for {process}. ' - f'Declaring a capacity of zero may be omitted.' - ) - continue - if v + lifetime <= first_period: - logger.info( - f'{process} specified as ExistingCapacity, but its ' - f'lifetime ({lifetime} years) does not extend past the ' - f'beginning of time_future ({first_period}).' - ) - - if M.Efficiency[r, i, t, v, o] == 0: - logger.info( - f'Notice: Unnecessary specification of Efficiency for {(r, i, t, v, o)}. ' - f'Specifying an efficiency of zero may be omitted.' - ) - continue - - M.used_techs.add(t) - - # B. Loop through time periods to build time-dependent relationships - for p in M.time_optimize: - # Skip if tech is not invented or is already retired - if p < v or v + lifetime <= p: - continue - - pindex = (r, p, t, v) - - # C. Initialize dictionary keys if not present - if pindex not in M.processInputs: - M.processInputs[pindex] = set() - M.processOutputs[pindex] = set() - if (r, p, i) not in M.commodityDStreamProcess: - M.commodityDStreamProcess[r, p, i] = set() - if (r, p, o) not in M.commodityUStreamProcess: - M.commodityUStreamProcess[r, p, o] = set() - if (r, p, t, v, i) not in M.processOutputsByInput: - M.processOutputsByInput[r, p, t, v, i] = set() - if (r, p, t, v, o) not in M.processInputsByOutput: - M.processInputsByOutput[r, p, t, v, o] = set() - if (r, p, t) not in M.processVintages: - M.processVintages[r, p, t] = set() - if (r, t, v) not in M.processPeriods: - M.processPeriods[r, t, v] = set() - - # D. Populate the dictionaries - M.processInputs[pindex].add(i) - M.processOutputs[pindex].add(o) - M.commodityDStreamProcess[r, p, i].add((t, v)) - M.commodityUStreamProcess[r, p, o].add((t, v)) - M.processOutputsByInput[r, p, t, v, i].add(o) - M.processInputsByOutput[r, p, t, v, o].add(i) - M.processVintages[r, p, t].add(v) - M.processPeriods[r, t, v].add(p) - - -def _create_technology_and_commodity_sets(M: 'TemoaModel'): - """ - Populates technology and commodity subset definitions based on their roles - (e.g., demand, flexible) identified from the Efficiency parameter. - """ - logger.debug('Creating technology and commodity subsets.') - for _r, _i, t, _v, o in M.Efficiency.sparse_iterkeys(): - if t in M.tech_flex and o not in M.commodity_flex: - M.commodity_flex.add(o) - - if o in M.commodity_demand and t not in M.tech_demand: - M.tech_demand.add(t) - - -def _create_operational_vintage_sets(M: 'TemoaModel'): - """ - Populates vintage-based dictionaries for technologies with special - operational characteristics like curtailment, baseload, storage, ramping, and reserves. - """ - logger.debug('Creating vintage sets for operational constraints.') - - # Initialize the dictionaries to prevent KeyErrors later - M.curtailmentVintages = {} - M.baseloadVintages = {} - M.storageVintages = {} - M.rampUpVintages = {} - M.rampDownVintages = {} - M.isSeasonalStorage = {} - M.processReservePeriods = {} # Initialize the missing dictionary - - # Now populate them - for r, p, t in M.processVintages: - for v in M.processVintages[r, p, t]: - key_rpt = (r, p, t) - key_rp = (r, p) - if t in M.tech_curtailment: - M.curtailmentVintages.setdefault(key_rpt, set()).add(v) - if t in M.tech_baseload: - M.baseloadVintages.setdefault(key_rpt, set()).add(v) - if t in M.tech_storage: - M.storageVintages.setdefault(key_rpt, set()).add(v) - if t in M.tech_upramping: - M.rampUpVintages.setdefault(key_rpt, set()).add(v) - if t in M.tech_downramping: - M.rampDownVintages.setdefault(key_rpt, set()).add(v) - if t in M.tech_reserve: - M.processReservePeriods.setdefault(key_rp, set()).add((t, v)) - - # A dictionary of whether a storage tech is seasonal, just to speed things up - for t in M.tech_storage: - M.isSeasonalStorage[t] = t in M.tech_seasonal_storage - - -def _create_limit_vintage_sets(M: 'TemoaModel'): - """ - Populates vintage sets for technologies constrained by input/output split limits. - """ - logger.debug('Creating vintage sets for split limits.') - # Assuming M.processVintages is already populated - for r, p, t in M.processVintages: - for v in M.processVintages[r, p, t]: - for i in M.processInputs.get((r, p, t, v), []): - for op in M.operator: - if (r, p, i, t, op) in M.LimitTechInputSplit: - M.inputSplitVintages.setdefault((r, p, i, t, op), set()).add(v) - if (r, p, i, t, op) in M.LimitTechInputSplitAnnual: - M.inputSplitAnnualVintages.setdefault((r, p, i, t, op), set()).add(v) - - for o in M.processOutputs.get((r, p, t, v), []): - for op in M.operator: - if (r, p, t, o, op) in M.LimitTechOutputSplit: - M.outputSplitVintages.setdefault((r, p, t, o, op), set()).add(v) - if (r, p, t, o, op) in M.LimitTechOutputSplitAnnual: - M.outputSplitAnnualVintages.setdefault((r, p, t, o, op), set()).add(v) - - -# In temoa/_internal/precompute.py -def _create_geography_sets(M: 'TemoaModel'): - """Populates dictionaries related to inter-regional commodity exchange.""" - logger.debug('Creating geography-related sets for exchange technologies.') - for r, i, t, v, o in M.Efficiency.sparse_iterkeys(): - if t not in M.tech_exchange: - continue - - if '-' not in r: - msg = f"Exchange technology {t} has an invalid region '{r}'. Must be 'region_from-region_to'." - logger.error(msg) - raise ValueError(msg) - - region_from, region_to = r.split('-', 1) - - lifetime = value(M.LifetimeProcess[r, t, v]) - for p in M.time_optimize: - if p >= v and v + lifetime > p: - M.exportRegions.setdefault((region_from, p, i), set()).add((region_to, t, v, o)) - M.importRegions.setdefault((region_to, p, o), set()).add((region_from, t, v, i)) - - -# In temoa/_internal/precompute.py -def _create_capacity_and_retirement_sets(M: 'TemoaModel'): - """ - Creates sets and dictionaries related to technology capacity, retirement, - and end-of-life material flows. - """ - logger.debug('Creating capacity, retirement, and construction/EOL sets.') - # Retirement periods - for r, _i, t, v, _o in M.Efficiency.sparse_iterkeys(): - lifetime = value(M.LifetimeProcess[r, t, v]) - for p in M.time_optimize: - is_natural_eol = p <= v + lifetime < p + value(M.PeriodLength[p]) - is_early_retire = t in M.tech_retirement and v < p <= v + lifetime - value( - M.PeriodLength[p] - ) - is_survival_curve = M.isSurvivalCurveProcess[r, t, v] and v <= p <= v + lifetime - - if t not in M.tech_uncap and any((is_natural_eol, is_early_retire, is_survival_curve)): - M.retirementPeriods.setdefault((r, t, v), set()).add(p) - - # Construction and End-of-life flows - for r, i, t, v in M.ConstructionInput.sparse_iterkeys(): - M.capacityConsumptionTechs.setdefault((r, v, i), set()).add(t) - - for r, t, v, o in M.EndOfLifeOutput.sparse_iterkeys(): - if (r, t, v) in M.retirementPeriods: - for p in M.retirementPeriods[r, t, v]: - M.retirementProductionProcesses.setdefault((r, p, o), set()).add((t, v)) - - # Active capacity sets - M.newCapacity_rtv = set( - (r, t, v) - for r, p, t in M.processVintages - for v in M.processVintages[r, p, t] - if t not in M.tech_uncap and v in M.time_optimize - ) - M.activeCapacityAvailable_rpt = set( - (r, p, t) - for r, p, t in M.processVintages - if M.processVintages[r, p, t] and t not in M.tech_uncap - ) - M.activeCapacityAvailable_rptv = set( - (r, p, t, v) - for r, p, t in M.processVintages - for v in M.processVintages[r, p, t] - if t not in M.tech_uncap - ) - - -def _create_commodity_balance_and_flow_sets(M: 'TemoaModel'): - """ - Creates the aggregated sets required for commodity balance constraints - and the indexed sets for active technology flows, capacities, and storage levels. - """ - logger.debug('Creating commodity balance and active flow index sets.') - # 1. Commodity Balance - commodity_upstream = set( - M.commodityUStreamProcess | M.retirementProductionProcesses | M.importRegions - ) - commodity_downstream = set( - M.commodityDStreamProcess | M.capacityConsumptionTechs | M.exportRegions - ) - M.commodityBalance_rpc = commodity_upstream.intersection(commodity_downstream) - - # 2. Active Flow Indices (Time-Sliced) - M.activeFlow_rpsditvo = set( - (r, p, s, d, i, t, v, o) - for r, p, t in M.processVintages - if t not in M.tech_annual - for v in M.processVintages[r, p, t] - for i in M.processInputs.get((r, p, t, v), set()) - for o in M.processOutputsByInput.get((r, p, t, v, i), set()) - for s in M.TimeSeason[p] # REVERTED THIS LINE - for d in M.time_of_day - ) - - # 3. Active Flow Indices (Annual) - M.activeFlow_rpitvo = set( - (r, p, i, t, v, o) - for r, p, t in M.processVintages - for v in M.processVintages[r, p, t] - for i in M.processInputs.get((r, p, t, v), set()) - for o in M.processOutputsByInput.get((r, p, t, v, i), set()) - if t in M.tech_annual or (t in M.tech_demand and o in M.commodity_demand) - ) - - # 4. Active Flexible Technology Flow Indices - M.activeFlex_rpsditvo = set( - (r, p, s, d, i, t, v, o) - for r, p, t in M.processVintages - if (t not in M.tech_annual) and (t in M.tech_flex) - for v in M.processVintages[r, p, t] - for i in M.processInputs.get((r, p, t, v), set()) - for o in M.processOutputsByInput.get((r, p, t, v, i), set()) - for s in M.TimeSeason[p] # REVERTED THIS LINE - for d in M.time_of_day - ) - - M.activeFlex_rpitvo = set( - (r, p, i, t, v, o) - for r, p, t in M.processVintages - if (t in M.tech_annual) and (t in M.tech_flex) - for v in M.processVintages[r, p, t] - for i in M.processInputs.get((r, p, t, v), set()) - for o in M.processOutputsByInput.get((r, p, t, v, i), set()) - ) - - # 5. Active Storage and Curtailment Indices - M.activeFlowInStorage_rpsditvo = set( - (r, p, s, d, i, t, v, o) - for r, p, t in M.storageVintages - for v in M.storageVintages[r, p, t] - for i in M.processInputs.get((r, p, t, v), set()) - for o in M.processOutputsByInput.get((r, p, t, v, i), set()) - for s in M.TimeSeason[p] # REVERTED THIS LINE - for d in M.time_of_day - ) - - M.activeCurtailment_rpsditvo = set( - (r, p, s, d, i, t, v, o) - for r, p, t in M.curtailmentVintages - for v in M.curtailmentVintages[r, p, t] - for i in M.processInputs.get((r, p, t, v), set()) - for o in M.processOutputsByInput.get((r, p, t, v, i), set()) - for s in M.TimeSeason[p] # REVERTED THIS LINE - for d in M.time_of_day - ) - - # 6. Active Technology and Capacity Indices - M.activeActivity_rptv = set( - (r, p, t, v) for r, p, t in M.processVintages for v in M.processVintages[r, p, t] - ) - - # 7. Storage Level Indices - M.storageLevelIndices_rpsdtv = set( - (r, p, s, d, t, v) - for r, p, t in M.storageVintages - for v in M.storageVintages[r, p, t] - for s in M.TimeSeason[p] # REVERTED THIS LINE - for d in M.time_of_day - ) - - M.seasonalStorageLevelIndices_rpstv = set( - (r, p, s_stor, t, v) - for r, p, t in M.storageVintages - if t in M.tech_seasonal_storage - for v in M.storageVintages[r, p, t] - for _p, s_stor in M.sequential_to_season - if _p == p - ) diff --git a/temoa/components/capacity.py b/temoa/components/capacity.py index 0fd54c5f9..153568bc7 100644 --- a/temoa/components/capacity.py +++ b/temoa/components/capacity.py @@ -507,3 +507,51 @@ def get_capacity_factor(M: 'TemoaModel', r, p, s, d, t, v): return value(M.CapacityFactorProcess[r, p, s, d, t, v]) else: return value(M.CapacityFactorTech[r, p, s, d, t]) + + +def create_capacity_and_retirement_sets(M: 'TemoaModel'): + """ + Creates sets and dictionaries related to technology capacity, retirement, + and end-of-life material flows. + """ + logger.debug('Creating capacity, retirement, and construction/EOL sets.') + # Retirement periods + for r, _i, t, v, _o in M.Efficiency.sparse_iterkeys(): + lifetime = value(M.LifetimeProcess[r, t, v]) + for p in M.time_optimize: + is_natural_eol = p <= v + lifetime < p + value(M.PeriodLength[p]) + is_early_retire = t in M.tech_retirement and v < p <= v + lifetime - value( + M.PeriodLength[p] + ) + is_survival_curve = M.isSurvivalCurveProcess[r, t, v] and v <= p <= v + lifetime + + if t not in M.tech_uncap and any((is_natural_eol, is_early_retire, is_survival_curve)): + M.retirementPeriods.setdefault((r, t, v), set()).add(p) + + # Construction and End-of-life flows + for r, i, t, v in M.ConstructionInput.sparse_iterkeys(): + M.capacityConsumptionTechs.setdefault((r, v, i), set()).add(t) + + for r, t, v, o in M.EndOfLifeOutput.sparse_iterkeys(): + if (r, t, v) in M.retirementPeriods: + for p in M.retirementPeriods[r, t, v]: + M.retirementProductionProcesses.setdefault((r, p, o), set()).add((t, v)) + + # Active capacity sets + M.newCapacity_rtv = set( + (r, t, v) + for r, p, t in M.processVintages + for v in M.processVintages[r, p, t] + if t not in M.tech_uncap and v in M.time_optimize + ) + M.activeCapacityAvailable_rpt = set( + (r, p, t) + for r, p, t in M.processVintages + if M.processVintages[r, p, t] and t not in M.tech_uncap + ) + M.activeCapacityAvailable_rptv = set( + (r, p, t, v) + for r, p, t in M.processVintages + for v in M.processVintages[r, p, t] + if t not in M.tech_uncap + ) diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index c2b8d1dee..dfbf38f2d 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -719,3 +719,17 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): expr = produced == consumed return expr + + +def create_technology_and_commodity_sets(M: 'TemoaModel'): + """ + Populates technology and commodity subset definitions based on their roles + (e.g., demand, flexible) identified from the Efficiency parameter. + """ + logger.debug('Creating technology and commodity subsets.') + for _r, _i, t, _v, o in M.Efficiency.sparse_iterkeys(): + if t in M.tech_flex and o not in M.commodity_flex: + M.commodity_flex.add(o) + + if o in M.commodity_demand and t not in M.tech_demand: + M.tech_demand.add(t) diff --git a/temoa/components/flows.py b/temoa/components/flows.py index b056af776..0a13be0ca 100644 --- a/temoa/components/flows.py +++ b/temoa/components/flows.py @@ -1,8 +1,11 @@ +from logging import getLogger from typing import TYPE_CHECKING if TYPE_CHECKING: from temoa.core.model import TemoaModel +logger = getLogger(__name__) + def FlowVariableIndices(M: 'TemoaModel'): return M.activeFlow_rpsditvo @@ -26,3 +29,106 @@ def FlowInStorageVariableIndices(M: 'TemoaModel'): def CurtailmentVariableIndices(M: 'TemoaModel'): return M.activeCurtailment_rpsditvo + + +def create_commodity_balance_and_flow_sets(M: 'TemoaModel'): + """ + Creates the aggregated sets required for commodity balance constraints + and the indexed sets for active technology flows, capacities, and storage levels. + """ + logger.debug('Creating commodity balance and active flow index sets.') + # 1. Commodity Balance + commodity_upstream = set( + M.commodityUStreamProcess | M.retirementProductionProcesses | M.importRegions + ) + commodity_downstream = set( + M.commodityDStreamProcess | M.capacityConsumptionTechs | M.exportRegions + ) + M.commodityBalance_rpc = commodity_upstream.intersection(commodity_downstream) + + # 2. Active Flow Indices (Time-Sliced) + M.activeFlow_rpsditvo = set( + (r, p, s, d, i, t, v, o) + for r, p, t in M.processVintages + if t not in M.tech_annual + for v in M.processVintages[r, p, t] + for i in M.processInputs.get((r, p, t, v), set()) + for o in M.processOutputsByInput.get((r, p, t, v, i), set()) + for s in M.TimeSeason[p] # REVERTED THIS LINE + for d in M.time_of_day + ) + + # 3. Active Flow Indices (Annual) + M.activeFlow_rpitvo = set( + (r, p, i, t, v, o) + for r, p, t in M.processVintages + for v in M.processVintages[r, p, t] + for i in M.processInputs.get((r, p, t, v), set()) + for o in M.processOutputsByInput.get((r, p, t, v, i), set()) + if t in M.tech_annual or (t in M.tech_demand and o in M.commodity_demand) + ) + + # 4. Active Flexible Technology Flow Indices + M.activeFlex_rpsditvo = set( + (r, p, s, d, i, t, v, o) + for r, p, t in M.processVintages + if (t not in M.tech_annual) and (t in M.tech_flex) + for v in M.processVintages[r, p, t] + for i in M.processInputs.get((r, p, t, v), set()) + for o in M.processOutputsByInput.get((r, p, t, v, i), set()) + for s in M.TimeSeason[p] # REVERTED THIS LINE + for d in M.time_of_day + ) + + M.activeFlex_rpitvo = set( + (r, p, i, t, v, o) + for r, p, t in M.processVintages + if (t in M.tech_annual) and (t in M.tech_flex) + for v in M.processVintages[r, p, t] + for i in M.processInputs.get((r, p, t, v), set()) + for o in M.processOutputsByInput.get((r, p, t, v, i), set()) + ) + + # 5. Active Storage and Curtailment Indices + M.activeFlowInStorage_rpsditvo = set( + (r, p, s, d, i, t, v, o) + for r, p, t in M.storageVintages + for v in M.storageVintages[r, p, t] + for i in M.processInputs.get((r, p, t, v), set()) + for o in M.processOutputsByInput.get((r, p, t, v, i), set()) + for s in M.TimeSeason[p] # REVERTED THIS LINE + for d in M.time_of_day + ) + + M.activeCurtailment_rpsditvo = set( + (r, p, s, d, i, t, v, o) + for r, p, t in M.curtailmentVintages + for v in M.curtailmentVintages[r, p, t] + for i in M.processInputs.get((r, p, t, v), set()) + for o in M.processOutputsByInput.get((r, p, t, v, i), set()) + for s in M.TimeSeason[p] # REVERTED THIS LINE + for d in M.time_of_day + ) + + # 6. Active Technology and Capacity Indices + M.activeActivity_rptv = set( + (r, p, t, v) for r, p, t in M.processVintages for v in M.processVintages[r, p, t] + ) + + # 7. Storage Level Indices + M.storageLevelIndices_rpsdtv = set( + (r, p, s, d, t, v) + for r, p, t in M.storageVintages + for v in M.storageVintages[r, p, t] + for s in M.TimeSeason[p] # REVERTED THIS LINE + for d in M.time_of_day + ) + + M.seasonalStorageLevelIndices_rpstv = set( + (r, p, s_stor, t, v) + for r, p, t in M.storageVintages + if t in M.tech_seasonal_storage + for v in M.storageVintages[r, p, t] + for _p, s_stor in M.sequential_to_season + if _p == p + ) diff --git a/temoa/components/geography.py b/temoa/components/geography.py index 0884ded2b..0f748f88b 100644 --- a/temoa/components/geography.py +++ b/temoa/components/geography.py @@ -2,6 +2,7 @@ from typing import TYPE_CHECKING, Iterable from deprecated import deprecated +from pyomo.environ import value if TYPE_CHECKING: from temoa.core.model import TemoaModel @@ -70,3 +71,24 @@ def RegionalExchangeCapacity_Constraint(M: 'TemoaModel', r_e, r_i, p, t, v): expr = M.V_Capacity[r_e + '-' + r_i, p, t, v] == M.V_Capacity[r_i + '-' + r_e, p, t, v] return expr + + +def create_geography_sets(M: 'TemoaModel'): + """Populates dictionaries related to inter-regional commodity exchange.""" + logger.debug('Creating geography-related sets for exchange technologies.') + for r, i, t, v, o in M.Efficiency.sparse_iterkeys(): + if t not in M.tech_exchange: + continue + + if '-' not in r: + msg = f"Exchange technology {t} has an invalid region '{r}'. Must be 'region_from-region_to'." + logger.error(msg) + raise ValueError(msg) + + region_from, region_to = r.split('-', 1) + + lifetime = value(M.LifetimeProcess[r, t, v]) + for p in M.time_optimize: + if p >= v and v + lifetime > p: + M.exportRegions.setdefault((region_from, p, i), set()).add((region_to, t, v, o)) + M.importRegions.setdefault((region_to, p, o), set()).add((region_from, t, v, i)) diff --git a/temoa/components/limits.py b/temoa/components/limits.py index b22023cd1..e1a842752 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -1237,3 +1237,26 @@ def LimitCapacity_Constraint(M: 'TemoaModel', r, p, t, op): ) expr = operator_expression(capacity, op, cap_lim) return expr + + +def create_limit_vintage_sets(M: 'TemoaModel'): + """ + Populates vintage sets for technologies constrained by input/output split limits. + """ + logger.debug('Creating vintage sets for split limits.') + # Assuming M.processVintages is already populated + for r, p, t in M.processVintages: + for v in M.processVintages[r, p, t]: + for i in M.processInputs.get((r, p, t, v), []): + for op in M.operator: + if (r, p, i, t, op) in M.LimitTechInputSplit: + M.inputSplitVintages.setdefault((r, p, i, t, op), set()).add(v) + if (r, p, i, t, op) in M.LimitTechInputSplitAnnual: + M.inputSplitAnnualVintages.setdefault((r, p, i, t, op), set()).add(v) + + for o in M.processOutputs.get((r, p, t, v), []): + for op in M.operator: + if (r, p, t, o, op) in M.LimitTechOutputSplit: + M.outputSplitVintages.setdefault((r, p, t, o, op), set()).add(v) + if (r, p, t, o, op) in M.LimitTechOutputSplitAnnual: + M.outputSplitAnnualVintages.setdefault((r, p, t, o, op), set()).add(v) diff --git a/temoa/components/operations.py b/temoa/components/operations.py index edc5ae831..a22944da5 100644 --- a/temoa/components/operations.py +++ b/temoa/components/operations.py @@ -1,3 +1,4 @@ +from logging import getLogger from typing import TYPE_CHECKING from pyomo.environ import Constraint, value @@ -5,6 +6,8 @@ if TYPE_CHECKING: from temoa.core.model import TemoaModel +logger = getLogger(__name__) + def BaseloadDiurnalConstraintIndices(M: 'TemoaModel'): indices = set( @@ -85,3 +88,42 @@ def BaseloadDiurnal_Constraint(M: 'TemoaModel', r, p, s, d, t, v): expr = activity_sd * value(M.SegFrac[p, s, d_0]) == activity_sd_0 * value(M.SegFrac[p, s, d]) return expr + + +def create_operational_vintage_sets(M: 'TemoaModel'): + """ + Populates vintage-based dictionaries for technologies with special + operational characteristics like curtailment, baseload, storage, ramping, and reserves. + """ + logger.debug('Creating vintage sets for operational constraints.') + + # Initialize the dictionaries to prevent KeyErrors later + M.curtailmentVintages = {} + M.baseloadVintages = {} + M.storageVintages = {} + M.rampUpVintages = {} + M.rampDownVintages = {} + M.isSeasonalStorage = {} + M.processReservePeriods = {} # Initialize the missing dictionary + + # Now populate them + for r, p, t in M.processVintages: + for v in M.processVintages[r, p, t]: + key_rpt = (r, p, t) + key_rp = (r, p) + if t in M.tech_curtailment: + M.curtailmentVintages.setdefault(key_rpt, set()).add(v) + if t in M.tech_baseload: + M.baseloadVintages.setdefault(key_rpt, set()).add(v) + if t in M.tech_storage: + M.storageVintages.setdefault(key_rpt, set()).add(v) + if t in M.tech_upramping: + M.rampUpVintages.setdefault(key_rpt, set()).add(v) + if t in M.tech_downramping: + M.rampDownVintages.setdefault(key_rpt, set()).add(v) + if t in M.tech_reserve: + M.processReservePeriods.setdefault(key_rp, set()).add((t, v)) + + # A dictionary of whether a storage tech is seasonal, just to speed things up + for t in M.tech_storage: + M.isSeasonalStorage[t] = t in M.tech_seasonal_storage diff --git a/temoa/components/technology.py b/temoa/components/technology.py index d493c92ae..829bee5ca 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -309,3 +309,83 @@ def ParamProcessLifeFraction_rule(M: 'TemoaModel', r, p, t, v): frac = years_remaining / float(period_length) return frac + + +def populate_core_dictionaries(M: 'TemoaModel'): + """ + Loops through the Efficiency parameter to populate the core sparse dictionaries + that define process relationships, inputs, outputs, and active periods. + + This function is foundational for creating the sparse indices used throughout the model. + """ + logger.debug('Populating core sparse dictionaries from Efficiency parameter.') + first_period = min(M.time_future) + exist_indices = M.ExistingCapacity.sparse_keys() + + for r, i, t, v, o in M.Efficiency.sparse_iterkeys(): + # A. Basic data validation and warnings + process = (r, t, v) + lifetime = value(M.LifetimeProcess[process]) + if v in M.vintage_exist: + if process not in exist_indices and t not in M.tech_uncap: + logger.warning( + f'Warning: {process} has a specified Efficiency, but does not ' + f'have any existing install base (ExistingCapacity).' + ) + continue + if t not in M.tech_uncap and M.ExistingCapacity[process] == 0: + logger.warning( + f'Notice: Unnecessary specification of ExistingCapacity for {process}. ' + f'Declaring a capacity of zero may be omitted.' + ) + continue + if v + lifetime <= first_period: + logger.info( + f'{process} specified as ExistingCapacity, but its ' + f'lifetime ({lifetime} years) does not extend past the ' + f'beginning of time_future ({first_period}).' + ) + + if M.Efficiency[r, i, t, v, o] == 0: + logger.info( + f'Notice: Unnecessary specification of Efficiency for {(r, i, t, v, o)}. ' + f'Specifying an efficiency of zero may be omitted.' + ) + continue + + M.used_techs.add(t) + + # B. Loop through time periods to build time-dependent relationships + for p in M.time_optimize: + # Skip if tech is not invented or is already retired + if p < v or v + lifetime <= p: + continue + + pindex = (r, p, t, v) + + # C. Initialize dictionary keys if not present + if pindex not in M.processInputs: + M.processInputs[pindex] = set() + M.processOutputs[pindex] = set() + if (r, p, i) not in M.commodityDStreamProcess: + M.commodityDStreamProcess[r, p, i] = set() + if (r, p, o) not in M.commodityUStreamProcess: + M.commodityUStreamProcess[r, p, o] = set() + if (r, p, t, v, i) not in M.processOutputsByInput: + M.processOutputsByInput[r, p, t, v, i] = set() + if (r, p, t, v, o) not in M.processInputsByOutput: + M.processInputsByOutput[r, p, t, v, o] = set() + if (r, p, t) not in M.processVintages: + M.processVintages[r, p, t] = set() + if (r, t, v) not in M.processPeriods: + M.processPeriods[r, t, v] = set() + + # D. Populate the dictionaries + M.processInputs[pindex].add(i) + M.processOutputs[pindex].add(o) + M.commodityDStreamProcess[r, p, i].add((t, v)) + M.commodityUStreamProcess[r, p, o].add((t, v)) + M.processOutputsByInput[r, p, t, v, i].add(o) + M.processInputsByOutput[r, p, t, v, o].add(i) + M.processVintages[r, p, t].add(v) + M.processPeriods[r, t, v].add(p) diff --git a/temoa/core/model.py b/temoa/core/model.py index 0a7d9cb3d..e3d217862 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -23,15 +23,6 @@ minimize, ) -from temoa._internal.precompute import ( - _create_capacity_and_retirement_sets, - _create_commodity_balance_and_flow_sets, - _create_geography_sets, - _create_limit_vintage_sets, - _create_operational_vintage_sets, - _create_technology_and_commodity_sets, - _populate_core_dictionaries, -) from temoa.components import ( capacity, commodities, @@ -71,19 +62,19 @@ def CreateSparseDicts(M: 'TemoaModel'): # Call the decomposed functions in logical order # 1. Populate core relationships from Efficiency table - _populate_core_dictionaries(M) + technology.populate_core_dictionaries(M) # 2. Classify technologies and commodities - _create_technology_and_commodity_sets(M) + commodities.create_technology_and_commodity_sets(M) # 3. Create sets for specific components - _create_operational_vintage_sets(M) # For operations, storage, ramping - _create_limit_vintage_sets(M) # For limits - _create_geography_sets(M) # For geography/exchange - _create_capacity_and_retirement_sets(M) # For capacity + operations.create_operational_vintage_sets(M) # For operations, storage, ramping + limits.create_limit_vintage_sets(M) # For limits + geography.create_geography_sets(M) # For geography/exchange + capacity.create_capacity_and_retirement_sets(M) # For capacity # 4. Create final aggregated sets for constraints - _create_commodity_balance_and_flow_sets(M) # For flows and commodities + flows.create_commodity_balance_and_flow_sets(M) # For flows and commodities # Final check for unused technologies unused_techs = M.tech_all - M.used_techs From e3ab9bb3b2abc6f30e21cb849de40952b3df9cd0 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 9 Oct 2025 16:12:16 -0400 Subject: [PATCH 225/587] cleaning up capacity.py --- temoa/components/capacity.py | 539 +++++++++++++++++++---------------- 1 file changed, 286 insertions(+), 253 deletions(-) diff --git a/temoa/components/capacity.py b/temoa/components/capacity.py index 153568bc7..0c6486367 100644 --- a/temoa/components/capacity.py +++ b/temoa/components/capacity.py @@ -2,9 +2,11 @@ """ Defines the capacity-related components of the Temoa model. -This includes the core variables for new, retired, and available capacity, -as well as the constraints that govern their relationships and enforce -production limits. +This module is responsible for: +- Defining Pyomo index sets for variables. +- Defining the rules for all capacity-related constraints, such as capacity + production limits, retirement accounting, and available capacity aggregation. +- Pre-calculating sparse index sets for capacity, retirement, and material flows. """ from __future__ import annotations @@ -23,40 +25,11 @@ logger = getLogger(name=__name__) -# ============================================================================ -# INDEX GENERATION FUNCTIONS -# (Formerly in temoa/_internal/temoa_initialize.py) -# ============================================================================ -# By convention, we can prefix these with an underscore to indicate they are -# internal helpers for this component's construction. - - -def CapacityVariableIndices(M: 'TemoaModel'): - return M.newCapacity_rtv - - -def RetiredCapacityVariableIndices(M: 'TemoaModel'): - return set( - (r, p, t, v) - for r, p, t in M.processVintages - if t in M.tech_retirement and t not in M.tech_uncap - for v in M.processVintages[r, p, t] - if v < p <= v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[p]) - ) -def AnnualRetirementVariableIndices(M: 'TemoaModel'): - return set( - (r, p, t, v) for r, t, v in M.retirementPeriods for p in M.retirementPeriods[r, t, v] - ) - - -def CapacityAvailableVariableIndices(M: 'TemoaModel'): - return M.activeCapacityAvailable_rpt - - -def CapacityAvailableVariableIndicesVintage(M: 'TemoaModel'): - return M.activeCapacityAvailable_rptv +# ============================================================================ +# HELPER FUNCTIONS AND VALIDATORS +# ============================================================================ def CheckCapacityFactorProcess(M: 'TemoaModel'): @@ -154,149 +127,237 @@ def get_default_capacity_factor(M: 'TemoaModel', r, p, s, d, t, v): return M.CapacityFactorTech[r, p, s, d, t] -@deprecated('switched over to validator... this set is typically VERY empty') -def CapacityFactorProcessIndices(M: 'TemoaModel'): - indices = set( - (r, s, d, t, v) - for r, i, t, v, o in M.Efficiency.sparse_iterkeys() - for p in M.time_optimize - for s in M.TimeSeason[p] - for d in M.time_of_day +def get_capacity_factor(M: 'TemoaModel', r, p, s, d, t, v): + if M.isCapacityFactorProcess[r, p, t, v]: + return value(M.CapacityFactorProcess[r, p, s, d, t, v]) + else: + return value(M.CapacityFactorTech[r, p, s, d, t]) + + +# ============================================================================ +# PYOMO INDEX SETS +# ============================================================================ + + +def CapacityVariableIndices(M: 'TemoaModel'): + return M.newCapacity_rtv + + +def RetiredCapacityVariableIndices(M: 'TemoaModel'): + return set( + (r, p, t, v) + for r, p, t in M.processVintages + if t in M.tech_retirement and t not in M.tech_uncap + for v in M.processVintages[r, p, t] + if v < p <= v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[p]) ) - return indices -def CapacityFactorTechIndices(M: 'TemoaModel'): - all_cfs = set( - (r, p, s, d, t) - for r, p, t in M.activeCapacityAvailable_rpt - for s in M.TimeSeason[p] - for d in M.time_of_day +def AnnualRetirementVariableIndices(M: 'TemoaModel'): + return set( + (r, p, t, v) for r, t, v in M.retirementPeriods for p in M.retirementPeriods[r, t, v] ) - return all_cfs -def CapacityConstraintIndices(M: 'TemoaModel'): +def CapacityAvailableVariableIndices(M: 'TemoaModel'): + return M.activeCapacityAvailable_rpt + + +def RegionalExchangeCapacityConstraintIndices(M: 'TemoaModel'): + indices = set( + (r_e, r_i, p, t, v) + for r_e, p, i in M.exportRegions + for r_i, t, v, o in M.exportRegions[r_e, p, i] + ) + + return indices + + +def CapacityAnnualConstraintIndices(M: 'TemoaModel'): capacity_indices = set( - (r, p, s, d, t, v) + (r, p, t, v) for r, p, t, v in M.activeActivity_rptv - if (t not in M.tech_annual or t in M.tech_demand) + if t in M.tech_annual and t not in M.tech_demand if t not in M.tech_uncap - if t not in M.tech_storage - for s in M.TimeSeason[p] - for d in M.time_of_day ) return capacity_indices -def CapacityAnnualConstraintIndices(M: 'TemoaModel'): +def CapacityConstraintIndices(M: 'TemoaModel'): capacity_indices = set( - (r, p, t, v) + (r, p, s, d, t, v) for r, p, t, v in M.activeActivity_rptv - if t in M.tech_annual and t not in M.tech_demand + if (t not in M.tech_annual or t in M.tech_demand) if t not in M.tech_uncap + if t not in M.tech_storage + for s in M.TimeSeason[p] + for d in M.time_of_day ) return capacity_indices -def RegionalExchangeCapacityConstraintIndices(M: 'TemoaModel'): +@deprecated('switched over to validator... this set is typically VERY empty') +def CapacityFactorProcessIndices(M: 'TemoaModel'): indices = set( - (r_e, r_i, p, t, v) - for r_e, p, i in M.exportRegions - for r_i, t, v, o in M.exportRegions[r_e, p, i] + (r, s, d, t, v) + for r, i, t, v, o in M.Efficiency.sparse_iterkeys() + for p in M.time_optimize + for s in M.TimeSeason[p] + for d in M.time_of_day ) - return indices -def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): - r""" - This constraint updates the capacity of a process by taking into account retirements - and end of life. For a given :code:`(r,p,t,v)` index, this constraint sets the capacity - equal to the amount installed in period :code:`v` and subtracts from it any and all retirements - that occurred prior to the period in question, :code:`p`, and end of life from the - survival curve if defined. It finally adjusts for the process life fraction, which - accounts for a possible mid-period end of life where, for example, EOL 3 years into a 5-year - period would be treated as :math:`\frac{3}{5}` capacity for all 5 years. +def CapacityFactorTechIndices(M: 'TemoaModel'): + all_cfs = set( + (r, p, s, d, t) + for r, p, t in M.activeCapacityAvailable_rpt + for s in M.TimeSeason[p] + for d in M.time_of_day + ) + return all_cfs - .. figure:: images/adjusted_capacity_plf.* - :align: center - :width: 100% - :figclass: align-center - :figwidth: 50% - For processes reaching end of life mid-period, the process life fraction adjustment is applied, - distributing the effective capacity over the whole period. +def CapacityAvailableVariableIndicesVintage(M: 'TemoaModel'): + return M.activeCapacityAvailable_rptv - For processes using survival curves, the yearly survival curve :math:`\text{LSC}_{r,p,t,v}` is - averaged over the period to get the effective remaining capacity for that period Because this - implicitly handles mid-period end of life, :math:`\text{PLF}_{r,p,t,v}` is used to account for both - phenomena. - .. figure:: images/adjusted_capacity_sc.* - :align: center - :width: 100% - :figclass: align-center - :figwidth: 50% +# ============================================================================ +# PYOMO CONSTRAINT RULES +# ============================================================================ - For processes with a defined survival curve, the surviving capacity is averaged over each - period to get the adjusted capacity. This implicitly handles mid-period end of life as a - survival curve will always be zero after the end of life of a process. + +def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): + r""" + Get the annualised retirement rate for a process in a given period. + Used to output retirement (including end of life, EOL) and to model end of + life flows and emissions. Assumes that retirement from the beginning of each period + is evenly distributed over that model period :math:`\frac{1}{\text{LEN}_p}` + for the accounting of retirement flows (in the same way we assume capacity is + deployed evenly over the model period for construction inputs and embodied emissions). + The factor :math:`\frac{\text{LSC}_{r,p,t,v}}{\text{PLF}_{r,p,t,v}}` + adjusts the average survival during a period to the survival at the beginning + of that period. .. math:: - :label: Adjusted Capacity + :label: Annual Retirement - \textbf{CAP}_{r,p,t,v} = + \textbf{ART}_{r,p,t,v} = \begin{cases} - \text{PLF}_{r,p,t,v} \cdot - \left( - \text{ECAP}_{r,t,v} - \sum\limits_{v < p' <= p} - \frac{\textbf{RCAP}_{r,p',t,v}}{\text{LSC}_{r,p',t,v}} - \right) - & \text{if } \ v \in T^e \\ - \text{PLF}_{r,p,t,v} \cdot + \frac{1}{\text{LEN}_p} \cdot + \frac{\text{LSC}_{r,p,t,v}}{\text{PLF}_{r,p,t,v}} \cdot \textbf{CAP}_{r,p,t,v} + & \text{if EOL} \\ + \frac{1}{\text{LEN}_p} \cdot \left( - \textbf{NCAP}_{r,t,v} - \sum\limits_{v < p' <= p} - \frac{\textbf{RCAP}_{r,p',t,v}}{\text{LSC}_{r,p',t,v}} - \right) - & \text{if } \ v \notin T^e - \end{cases} - - \\\text{where } - \text{PLF}_{r,p,t,v} = - \begin{cases} - \frac{1}{\text{LEN}_p} \cdot \left( - \sum\limits_{y = p}^{p+\text{LEN}_{p}-1}{\text{LSC}_{r,y,t,v}} + \frac{\text{LSC}_{r,p,t,v}}{\text{PLF}_{r,p,t,v}} \cdot \textbf{CAP}_{r,p,t,v} + - \frac{\text{LSC}_{r,p_{next},t,v}}{\text{PLF}_{r,p_{next},t,v}} \cdot \textbf{CAP}_{r,p_{next},t,v} \right) - & \text{if } t \in T^{sc} \\ - \frac{1}{\text{LEN}_p} \cdot \left( v + \text{LTP}_{r,t,v} - p \right) - & \text{if } t \notin T^{sc} \\ + & \text{otherwise} \\ \end{cases} - We divide :math:`\frac{\textbf{RCAP}_{r,p',t,v}}{\text{LSC}_{r,p',t,v}}` - because the average survival factor in :math:`\text{PLF}_{r,p,t,v}` is indexed to the vintage - period (the beginning of the survival curve). So, we adjust for the relative survival from - the time when that retirement occurred (treated here as at the beginning of each period). + \\\text{where EOL when } p \leq v + LTP_{r,t,v} < p + LEN_p """ - if v in M.time_exist: - built_capacity = value(M.ExistingCapacity[r, t, v]) + ## Get the capacity at the start of this period + if p == v + value(M.LifetimeProcess[r, t, v]): + # Exact EOL. No V_Capacity or V_RetiredCapacity for this period. + if p == M.time_optimize.first(): + # Must be existing capacity. Apply survival curve to existing cap + cap_begin = M.ExistingCapacity[r, t, v] * M.LifetimeSurvivalCurve[r, p, t, v] + else: + # Get previous capacity and continue survival curve + p_prev = M.time_optimize.prev(p) + cap_begin = ( + M.V_Capacity[r, p_prev, t, v] + * value(M.LifetimeSurvivalCurve[r, p, t, v]) + / value(M.ProcessLifeFrac[r, p_prev, t, v]) + ) else: - built_capacity = M.V_NewCapacity[r, t, v] - - early_retirements = 0 - if t in M.tech_retirement: - early_retirements = sum( - M.V_RetiredCapacity[r, S_p, t, v] / value(M.LifetimeSurvivalCurve[r, S_p, t, v]) - for S_p in M.time_optimize - if v < S_p <= p - and S_p < v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[S_p]) + # The capacity at the beginning of the period + cap_begin = ( + M.V_Capacity[r, p, t, v] + * value(M.LifetimeSurvivalCurve[r, p, t, v]) + / value(M.ProcessLifeFrac[r, p, t, v]) ) - remaining_capacity = (built_capacity - early_retirements) * value(M.ProcessLifeFrac[r, p, t, v]) - return M.V_Capacity[r, p, t, v] == remaining_capacity + ## Get the capacity at the end of this period + if p <= v + value(M.LifetimeProcess[r, t, v]) < p + value(M.PeriodLength[p]): + # EOL so capacity ends on zero + cap_end = 0 + else: + # Mid-life period, ending capacity is beginning capacity of next period + p_next = M.time_future.next(p) + + if p == M.time_optimize.last() or p_next == v + value(M.LifetimeProcess[r, t, v]): + # No V_Capacity or V_RetiredCapacity for next period so just continue down the survival curve + cap_end = ( + cap_begin + * value(M.LifetimeSurvivalCurve[r, p_next, t, v]) + / value(M.LifetimeSurvivalCurve[r, p, t, v]) + ) + else: + # Get the next period's beginning capacity + cap_end = ( + M.V_Capacity[r, p_next, t, v] + * value(M.LifetimeSurvivalCurve[r, p_next, t, v]) + / value(M.ProcessLifeFrac[r, p_next, t, v]) + ) + + annualised_retirement = (cap_begin - cap_end) / M.PeriodLength[p] + return M.V_AnnualRetirement[r, p, t, v] == annualised_retirement + + +def CapacityAvailableByPeriodAndTech_Constraint(M: 'TemoaModel', r, p, t): + r""" + + The :math:`\textbf{CAPAVL}` variable is nominally for reporting solution values, + but is also used in the Limit constraint calculations. + + .. math:: + :label: CapacityAvailable + + \textbf{CAPAVL}_{r, p, t} = \sum_{v, p_i \leq p} \textbf{CAP}_{r, p, t, v} + + \\ + \forall p \in \text{P}^o, r \in R, t \in T + """ + cap_avail = sum(M.V_Capacity[r, p, t, S_v] for S_v in M.processVintages[r, p, t]) + + expr = M.V_CapacityAvailableByPeriodAndTech[r, p, t] == cap_avail + return expr + + +def CapacityAnnual_Constraint(M: 'TemoaModel', r, p, t, v): + r""" + Similar to Capacity_Constraint, but for technologies belonging to the + :code:`tech_annual` set. Technologies in the tech_annual set have constant output + across different timeslices within a year, so we do not need to ensure + that installed capacity is sufficient across all timeslices, thus saving + some computational effort. Instead, annual output is sufficient to calculate + capacity. Hourly capacity factors cannot be defined to annual technologies + but annual capacity factors can be set using LimitAnnualCapacityFactor, + which will be implicitly accounted for here. + + .. math:: + :label: CapacityAnnual + + \text{C2A}_{r, t} + \cdot \textbf{CAP}_{r, t, v} + = + \sum_{I, O} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} + + \\ + \forall \{r, p, t \in T^{a}, v\} \in \Theta_{\text{Activity}} + """ + activity_rptv = sum( + M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + + return value(M.CapacityToActivity[r, t]) * M.V_Capacity[r, p, t, v] >= activity_rptv def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): @@ -371,151 +432,122 @@ def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): ) -def CapacityAnnual_Constraint(M: 'TemoaModel', r, p, t, v): - r""" - Similar to Capacity_Constraint, but for technologies belonging to the - :code:`tech_annual` set. Technologies in the tech_annual set have constant output - across different timeslices within a year, so we do not need to ensure - that installed capacity is sufficient across all timeslices, thus saving - some computational effort. Instead, annual output is sufficient to calculate - capacity. Hourly capacity factors cannot be defined to annual technologies - but annual capacity factors can be set using LimitAnnualCapacityFactor, - which will be implicitly accounted for here. - - .. math:: - :label: CapacityAnnual - - \text{C2A}_{r, t} - \cdot \textbf{CAP}_{r, t, v} - = - \sum_{I, O} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} - - \\ - \forall \{r, p, t \in T^{a}, v\} \in \Theta_{\text{Activity}} - """ - activity_rptv = sum( - M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - - return value(M.CapacityToActivity[r, t]) * M.V_Capacity[r, p, t, v] >= activity_rptv - - -def CapacityAvailableByPeriodAndTech_Constraint(M: 'TemoaModel', r, p, t): +def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): r""" + This constraint updates the capacity of a process by taking into account retirements + and end of life. For a given :code:`(r,p,t,v)` index, this constraint sets the capacity + equal to the amount installed in period :code:`v` and subtracts from it any and all retirements + that occurred prior to the period in question, :code:`p`, and end of life from the + survival curve if defined. It finally adjusts for the process life fraction, which + accounts for a possible mid-period end of life where, for example, EOL 3 years into a 5-year + period would be treated as :math:`\frac{3}{5}` capacity for all 5 years. - The :math:`\textbf{CAPAVL}` variable is nominally for reporting solution values, - but is also used in the Limit constraint calculations. - - .. math:: - :label: CapacityAvailable - - \textbf{CAPAVL}_{r, p, t} = \sum_{v, p_i \leq p} \textbf{CAP}_{r, p, t, v} + .. figure:: images/adjusted_capacity_plf.* + :align: center + :width: 100% + :figclass: align-center + :figwidth: 50% - \\ - \forall p \in \text{P}^o, r \in R, t \in T - """ - cap_avail = sum(M.V_Capacity[r, p, t, S_v] for S_v in M.processVintages[r, p, t]) + For processes reaching end of life mid-period, the process life fraction adjustment is applied, + distributing the effective capacity over the whole period. - expr = M.V_CapacityAvailableByPeriodAndTech[r, p, t] == cap_avail - return expr + For processes using survival curves, the yearly survival curve :math:`\text{LSC}_{r,p,t,v}` is + averaged over the period to get the effective remaining capacity for that period Because this + implicitly handles mid-period end of life, :math:`\text{PLF}_{r,p,t,v}` is used to account for both + phenomena. + .. figure:: images/adjusted_capacity_sc.* + :align: center + :width: 100% + :figclass: align-center + :figwidth: 50% -def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): - r""" - Get the annualised retirement rate for a process in a given period. - Used to output retirement (including end of life, EOL) and to model end of - life flows and emissions. Assumes that retirement from the beginning of each period - is evenly distributed over that model period :math:`\frac{1}{\text{LEN}_p}` - for the accounting of retirement flows (in the same way we assume capacity is - deployed evenly over the model period for construction inputs and embodied emissions). - The factor :math:`\frac{\text{LSC}_{r,p,t,v}}{\text{PLF}_{r,p,t,v}}` - adjusts the average survival during a period to the survival at the beginning - of that period. + For processes with a defined survival curve, the surviving capacity is averaged over each + period to get the adjusted capacity. This implicitly handles mid-period end of life as a + survival curve will always be zero after the end of life of a process. .. math:: - :label: Annual Retirement + :label: Adjusted Capacity - \textbf{ART}_{r,p,t,v} = + \textbf{CAP}_{r,p,t,v} = \begin{cases} - \frac{1}{\text{LEN}_p} \cdot - \frac{\text{LSC}_{r,p,t,v}}{\text{PLF}_{r,p,t,v}} \cdot \textbf{CAP}_{r,p,t,v} - & \text{if EOL} \\ - \frac{1}{\text{LEN}_p} \cdot + \text{PLF}_{r,p,t,v} \cdot \left( - \frac{\text{LSC}_{r,p,t,v}}{\text{PLF}_{r,p,t,v}} \cdot \textbf{CAP}_{r,p,t,v} - - \frac{\text{LSC}_{r,p_{next},t,v}}{\text{PLF}_{r,p_{next},t,v}} \cdot \textbf{CAP}_{r,p_{next},t,v} + \text{ECAP}_{r,t,v} - \sum\limits_{v < p' <= p} + \frac{\textbf{RCAP}_{r,p',t,v}}{\text{LSC}_{r,p',t,v}} \right) - & \text{otherwise} \\ + & \text{if } \ v \in T^e \\ + \text{PLF}_{r,p,t,v} \cdot + \left( + \textbf{NCAP}_{r,t,v} - \sum\limits_{v < p' <= p} + \frac{\textbf{RCAP}_{r,p',t,v}}{\text{LSC}_{r,p',t,v}} + \right) + & \text{if } \ v \notin T^e \end{cases} - \\\text{where EOL when } p \leq v + LTP_{r,t,v} < p + LEN_p - """ + \\\text{where } + \text{PLF}_{r,p,t,v} = + \begin{cases} + \frac{1}{\text{LEN}_p} \cdot \left( + \sum\limits_{y = p}^{p+\text{LEN}_{p}-1}{\text{LSC}_{r,y,t,v}} + \right) + & \text{if } t \in T^{sc} \\ + \frac{1}{\text{LEN}_p} \cdot \left( v + \text{LTP}_{r,t,v} - p \right) + & \text{if } t \notin T^{sc} \\ + \end{cases} - ## Get the capacity at the start of this period - if p == v + value(M.LifetimeProcess[r, t, v]): - # Exact EOL. No V_Capacity or V_RetiredCapacity for this period. - if p == M.time_optimize.first(): - # Must be existing capacity. Apply survival curve to existing cap - cap_begin = M.ExistingCapacity[r, t, v] * M.LifetimeSurvivalCurve[r, p, t, v] - else: - # Get previous capacity and continue survival curve - p_prev = M.time_optimize.prev(p) - cap_begin = ( - M.V_Capacity[r, p_prev, t, v] - * value(M.LifetimeSurvivalCurve[r, p, t, v]) - / value(M.ProcessLifeFrac[r, p_prev, t, v]) - ) - else: - # The capacity at the beginning of the period - cap_begin = ( - M.V_Capacity[r, p, t, v] - * value(M.LifetimeSurvivalCurve[r, p, t, v]) - / value(M.ProcessLifeFrac[r, p, t, v]) - ) + We divide :math:`\frac{\textbf{RCAP}_{r,p',t,v}}{\text{LSC}_{r,p',t,v}}` + because the average survival factor in :math:`\text{PLF}_{r,p,t,v}` is indexed to the vintage + period (the beginning of the survival curve). So, we adjust for the relative survival from + the time when that retirement occurred (treated here as at the beginning of each period). + """ - ## Get the capacity at the end of this period - if p <= v + value(M.LifetimeProcess[r, t, v]) < p + value(M.PeriodLength[p]): - # EOL so capacity ends on zero - cap_end = 0 + if v in M.time_exist: + built_capacity = value(M.ExistingCapacity[r, t, v]) else: - # Mid-life period, ending capacity is beginning capacity of next period - p_next = M.time_future.next(p) + built_capacity = M.V_NewCapacity[r, t, v] - if p == M.time_optimize.last() or p_next == v + value(M.LifetimeProcess[r, t, v]): - # No V_Capacity or V_RetiredCapacity for next period so just continue down the survival curve - cap_end = ( - cap_begin - * value(M.LifetimeSurvivalCurve[r, p_next, t, v]) - / value(M.LifetimeSurvivalCurve[r, p, t, v]) - ) - else: - # Get the next period's beginning capacity - cap_end = ( - M.V_Capacity[r, p_next, t, v] - * value(M.LifetimeSurvivalCurve[r, p_next, t, v]) - / value(M.ProcessLifeFrac[r, p_next, t, v]) - ) + early_retirements = 0 + if t in M.tech_retirement: + early_retirements = sum( + M.V_RetiredCapacity[r, S_p, t, v] / value(M.LifetimeSurvivalCurve[r, S_p, t, v]) + for S_p in M.time_optimize + if v < S_p <= p + and S_p < v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[S_p]) + ) - annualised_retirement = (cap_begin - cap_end) / M.PeriodLength[p] - return M.V_AnnualRetirement[r, p, t, v] == annualised_retirement + remaining_capacity = (built_capacity - early_retirements) * value(M.ProcessLifeFrac[r, p, t, v]) + return M.V_Capacity[r, p, t, v] == remaining_capacity -def get_capacity_factor(M: 'TemoaModel', r, p, s, d, t, v): - if M.isCapacityFactorProcess[r, p, t, v]: - return value(M.CapacityFactorProcess[r, p, s, d, t, v]) - else: - return value(M.CapacityFactorTech[r, p, s, d, t]) +# ============================================================================ +# PRE-COMPUTATION FUNCTIONS +# ============================================================================ def create_capacity_and_retirement_sets(M: 'TemoaModel'): """ - Creates sets and dictionaries related to technology capacity, retirement, - and end-of-life material flows. + Creates and populates component-specific Python sets and dictionaries on the model object. + + This function is called once during model initialization and is responsible for + creating the sparse indices related to technology capacity, retirement, and + construction/end-of-life material flows. These data structures are then + used by other functions in this module to build Pyomo components. + + Populates: + - M.retirementPeriods: dict mapping (r, t, v) to a set of periods `p` + where retirement can occur. + - M.capacityConsumptionTechs: dict mapping (r, v, i) to a set of techs `t` + that consume commodity `i` for construction. + - M.retirementProductionProcesses: dict mapping (r, p, o) to a set of `(t, v)` + processes that produce commodity `o` at end-of-life. + - M.newCapacity_rtv: set of (r, t, v) for new capacity investments. + - M.activeCapacityAvailable_rpt: set of (r, p, t) where capacity is active. + - M.activeCapacityAvailable_rptv: set of (r, p, t, v) where vintage capacity is active. """ + logger.debug('Creating capacity, retirement, and construction/EOL sets.') - # Retirement periods + # Calculate retirement periods based on lifetime and survival curves for r, _i, t, v, _o in M.Efficiency.sparse_iterkeys(): lifetime = value(M.LifetimeProcess[r, t, v]) for p in M.time_optimize: @@ -528,16 +560,17 @@ def create_capacity_and_retirement_sets(M: 'TemoaModel'): if t not in M.tech_uncap and any((is_natural_eol, is_early_retire, is_survival_curve)): M.retirementPeriods.setdefault((r, t, v), set()).add(p) - # Construction and End-of-life flows + # Link construction materials to technologies for r, i, t, v in M.ConstructionInput.sparse_iterkeys(): M.capacityConsumptionTechs.setdefault((r, v, i), set()).add(t) + # Link end-of-life materials to retiring technologies for r, t, v, o in M.EndOfLifeOutput.sparse_iterkeys(): if (r, t, v) in M.retirementPeriods: for p in M.retirementPeriods[r, t, v]: M.retirementProductionProcesses.setdefault((r, p, o), set()).add((t, v)) - # Active capacity sets + # Create active capacity index sets from the now-populated processVintages M.newCapacity_rtv = set( (r, t, v) for r, p, t in M.processVintages From eb71312e928844cca3a16bb50846becd211c749c Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 9 Oct 2025 16:19:27 -0400 Subject: [PATCH 226/587] cleaning up commodities.py --- temoa/components/commodities.py | 328 ++++++++++++++++++-------------- 1 file changed, 182 insertions(+), 146 deletions(-) diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index dfbf38f2d..c5808667c 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -1,3 +1,13 @@ +""" +Defines the commodity and demand-related components of the Temoa model. + +This module is responsible for: +- Pre-computing technology and commodity subsets (e.g., demand techs, flex techs). +- Calculating and validating demand distributions across time slices. +- Defining the core commodity balance and demand satisfaction constraints that + drive the model's energy system solution. +""" + import sys from itertools import product as cross_product from logging import getLogger @@ -13,6 +23,10 @@ logger = getLogger(name=__name__) +# ============================================================================ +# HELPER FUNCTIONS AND VALIDATORS +# ============================================================================ + def CommodityBalanceConstraintErrorCheck(supplied, demanded, r, p, s, d, c): # note: if a pyomo equation simplifies to an int, there are no variables in it, which @@ -71,6 +85,11 @@ def DemandConstraintErrorCheck(supply, r, p, dem): raise Exception(msg.format(dem, r, p)) +# ============================================================================ +# PYOMO INDEX SET FUNCTIONS +# ============================================================================ + + def DemandActivityConstraintIndices(M: 'TemoaModel'): indices = set( (r, p, s, d, t, v, dem) @@ -83,152 +102,6 @@ def DemandActivityConstraintIndices(M: 'TemoaModel'): return indices -def CreateDemands(M: 'TemoaModel'): - """ - Steps to create the demand distributions - 1. Use Demand keys to ensure that all demands in commodity_demand are used - 2. Find any slices not set in DemandDefaultDistribution, and set them based - on the associated SegFrac slice. - 3. Validate that the DemandDefaultDistribution sums to 1. - 4. Find any per-demand DemandSpecificDistribution values not set, and set - them from DemandDefaultDistribution. Note that this only sets a - distribution for an end-use demand if the user has *not* specified _any_ - anything for that end-use demand. Thus, it is up to the user to fully - specify the distribution, or not. No in-between. - 5. Validate that the per-demand distributions sum to 1. - """ - logger.debug('Started creating demand distributions in CreateDemands()') - - # Step 0: some setup for a couple of reusable items - # Get the nth element from the tuple (r, p, s, d, dem) - # So we only have to update these indices in one place if they change - DSD_region = iget(0) - DSD_period = iget(1) - DSD_dem = iget(4) - - # Step 1: Check if any demand commodities are going unused - used_dems = set(dem for r, p, dem in M.Demand.sparse_iterkeys()) - unused_dems = sorted(M.commodity_demand.difference(used_dems)) - if unused_dems: - for dem in unused_dems: - msg = "Warning: Demand '{}' is unused\n" - logger.warning(msg.format(dem)) - sys.stderr.write(msg.format(dem)) - - # devnote: DDD just clones SegFrac. Unless we want to specify it in the database, - # makes sense to just use SegFrac directly - # Step 2: Build the demand default distribution (= segfrac) - # DDD = M.DemandDefaultDistribution # Shorter, for us lazy programmer types - # unset_defaults = set(M.SegFrac.sparse_iterkeys()) - # unset_defaults.difference_update(DDD.sparse_iterkeys()) - # if unset_defaults: - # Some hackery because Pyomo thinks that this Param is constructed. - # However, in our view, it is not yet, because we're specifically - # targeting values that have not yet been constructed, that we know are - # valid, and that we will need. - # DDD._constructed = False - # for tslice in unset_defaults: - # DDD[tslice] = M.SegFrac[tslice] # DDD._constructed = True - - # Step 3: Check that DDD sums to 1 - # devnote: this seems redundant to the SegFrac sum to 1 check. - # total = sum(i for i in DDD.values()) - # if abs(value(total) - 1.0) > 0.001: - # # We can't explicitly test for "!= 1.0" because of incremental rounding - # # errors associated with the specification of demand shares by time slice, - # # but we check to make sure it is within the specified tolerance. - - # key_padding = max(map(get_str_padding, DDD.sparse_iterkeys())) - - # fmt = '%%-%ds = %%s' % key_padding - # # Works out to something like "%-25s = %s" - - # items = sorted(DDD.items()) - # items = '\n '.join(fmt % (str(k), v) for k, v in items) - - # msg = ( - # 'The values of the DemandDefaultDistribution parameter do not ' - # 'sum to 1. The DemandDefaultDistribution specifies how end-use ' - # 'demands are distributed among the time slices (i.e., time_season, ' - # 'time_of_day), so together, the data must total to 1. Current ' - # 'values:\n {}\n\tsum = {}' - # ) - # logger.error(msg.format(items, total)) - # raise ValueError(msg.format(items, total)) - - # Step 4: Fill out demand specific distribution table and check sums to 1 by region and demand - DSD = M.DemandSpecificDistribution - - demands_specified = set(map(DSD_dem, (i for i in DSD.sparse_iterkeys()))) - unset_demand_distributions = used_dems.difference( - demands_specified - ) # the demands not mentioned in DSD *at all* - - if unset_demand_distributions: - for p in M.time_optimize: - unset_distributions = set( - cross_product( - M.regions, (p,), M.TimeSeason[p], M.time_of_day, unset_demand_distributions - ) - ) - for r, p, s, d, dem in unset_distributions: - DSD[r, p, s, d, dem] = value(M.SegFrac[p, s, d]) # DSD._constructed = True - - # Step 5: A final "sum to 1" check for all DSD members (which now should be everything) - # Also check that all keys are made... The demand distro should be supported - # by the full set of (r, p, dem) keys because it is an equality constraint - # and we need to ensure even the zeros are passed in - used_rp_dems = set((r, p, dem) for r, p, dem in M.Demand.sparse_iterkeys()) - for r, p, dem in used_rp_dems: - expected_key_length = len(M.TimeSeason[p]) * len(M.time_of_day) - keys = [ - k - for k in DSD.sparse_iterkeys() - if DSD_region(k) == r and DSD_period(k) == p and DSD_dem(k) == dem - ] - if len(keys) != expected_key_length: - # this could be very slow but only calls when there's a problem - missing = set( - (s, d) - for s in M.TimeSeason[p] - for d in M.time_of_day - if (r, p, s, d, dem) not in keys - ) - logger.info( - 'Missing some time slices for Demand Specific Distribution %s: %s', - (r, p, dem), - missing, - ) - total = sum(value(DSD[i]) for i in keys) - if abs(value(total) - 1.0) > 0.001: - # We can't explicitly test for "!= 1.0" because of incremental rounding - # errors associated with the specification of demand shares by time slice, - # but we check to make sure it is within the specified tolerance. - def get_str_padding(obj): - return len(str(obj)) - - key_padding = max(map(get_str_padding, keys)) - - fmt = '%%-%ds = %%s' % key_padding - # Works out to something like "%-25s = %s" - - items = sorted((k, value(DSD[k])) for k in keys) - items = '\n '.join(fmt % (str(k), v) for k, v in items) - - msg = ( - 'The values of the DemandSpecificDistribution parameter do not ' - 'sum to 1 for {}. The DemandSpecificDistribution specifies how end-use ' - 'demands are distributed per time-slice (i.e., time_season, ' - 'time_of_day). Within each region, period, end-use demand, then, the distribution ' - 'must total to 1.\n\n Demand-specific distribution in error: ' - ' \n {}\n\tsum = {}' - ) - logger.error(msg.format((r, p, dem), items, total)) - raise ValueError(msg.format((r, p, dem), items, total)) - - logger.debug('Finished creating demand distributions') - - def CommodityBalanceConstraintIndices(M: 'TemoaModel'): # Generate indices only for those commodities that are produced by # technologies with varying output at the time slice level. @@ -259,6 +132,11 @@ def AnnualCommodityBalanceConstraintIndices(M: 'TemoaModel'): return indices +# ============================================================================ +# PYOMO CONSTRAINT RULES +# ============================================================================ + + def Demand_Constraint(M: 'TemoaModel', r, p, dem): r""" @@ -721,10 +599,22 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): return expr +# ============================================================================ +# PRE-COMPUTATION FUNCTIONS +# ============================================================================ + + def create_technology_and_commodity_sets(M: 'TemoaModel'): """ Populates technology and commodity subset definitions based on their roles (e.g., demand, flexible) identified from the Efficiency parameter. + + This function iterates through the `Efficiency` parameter to identify and + add technologies and commodities to special `Pyomo.Set` objects on the model. + + Populates: + - M.commodity_flex: Commodities that can be over-produced. + - M.tech_demand: Technologies that directly satisfy an end-use demand. """ logger.debug('Creating technology and commodity subsets.') for _r, _i, t, _v, o in M.Efficiency.sparse_iterkeys(): @@ -733,3 +623,149 @@ def create_technology_and_commodity_sets(M: 'TemoaModel'): if o in M.commodity_demand and t not in M.tech_demand: M.tech_demand.add(t) + + +def CreateDemands(M: 'TemoaModel'): + """ + Steps to create the demand distributions + 1. Use Demand keys to ensure that all demands in commodity_demand are used + 2. Find any slices not set in DemandDefaultDistribution, and set them based + on the associated SegFrac slice. + 3. Validate that the DemandDefaultDistribution sums to 1. + 4. Find any per-demand DemandSpecificDistribution values not set, and set + them from DemandDefaultDistribution. Note that this only sets a + distribution for an end-use demand if the user has *not* specified _any_ + anything for that end-use demand. Thus, it is up to the user to fully + specify the distribution, or not. No in-between. + 5. Validate that the per-demand distributions sum to 1. + """ + logger.debug('Started creating demand distributions in CreateDemands()') + + # Step 0: some setup for a couple of reusable items + # Get the nth element from the tuple (r, p, s, d, dem) + # So we only have to update these indices in one place if they change + DSD_region = iget(0) + DSD_period = iget(1) + DSD_dem = iget(4) + + # Step 1: Check if any demand commodities are going unused + used_dems = set(dem for r, p, dem in M.Demand.sparse_iterkeys()) + unused_dems = sorted(M.commodity_demand.difference(used_dems)) + if unused_dems: + for dem in unused_dems: + msg = "Warning: Demand '{}' is unused\n" + logger.warning(msg.format(dem)) + sys.stderr.write(msg.format(dem)) + + # devnote: DDD just clones SegFrac. Unless we want to specify it in the database, + # makes sense to just use SegFrac directly + # Step 2: Build the demand default distribution (= segfrac) + # DDD = M.DemandDefaultDistribution # Shorter, for us lazy programmer types + # unset_defaults = set(M.SegFrac.sparse_iterkeys()) + # unset_defaults.difference_update(DDD.sparse_iterkeys()) + # if unset_defaults: + # Some hackery because Pyomo thinks that this Param is constructed. + # However, in our view, it is not yet, because we're specifically + # targeting values that have not yet been constructed, that we know are + # valid, and that we will need. + # DDD._constructed = False + # for tslice in unset_defaults: + # DDD[tslice] = M.SegFrac[tslice] # DDD._constructed = True + + # Step 3: Check that DDD sums to 1 + # devnote: this seems redundant to the SegFrac sum to 1 check. + # total = sum(i for i in DDD.values()) + # if abs(value(total) - 1.0) > 0.001: + # # We can't explicitly test for "!= 1.0" because of incremental rounding + # # errors associated with the specification of demand shares by time slice, + # # but we check to make sure it is within the specified tolerance. + + # key_padding = max(map(get_str_padding, DDD.sparse_iterkeys())) + + # fmt = '%%-%ds = %%s' % key_padding + # # Works out to something like "%-25s = %s" + + # items = sorted(DDD.items()) + # items = '\n '.join(fmt % (str(k), v) for k, v in items) + + # msg = ( + # 'The values of the DemandDefaultDistribution parameter do not ' + # 'sum to 1. The DemandDefaultDistribution specifies how end-use ' + # 'demands are distributed among the time slices (i.e., time_season, ' + # 'time_of_day), so together, the data must total to 1. Current ' + # 'values:\n {}\n\tsum = {}' + # ) + # logger.error(msg.format(items, total)) + # raise ValueError(msg.format(items, total)) + + # Step 4: Fill out demand specific distribution table and check sums to 1 by region and demand + DSD = M.DemandSpecificDistribution + + demands_specified = set(map(DSD_dem, (i for i in DSD.sparse_iterkeys()))) + unset_demand_distributions = used_dems.difference( + demands_specified + ) # the demands not mentioned in DSD *at all* + + if unset_demand_distributions: + for p in M.time_optimize: + unset_distributions = set( + cross_product( + M.regions, (p,), M.TimeSeason[p], M.time_of_day, unset_demand_distributions + ) + ) + for r, p, s, d, dem in unset_distributions: + DSD[r, p, s, d, dem] = value(M.SegFrac[p, s, d]) # DSD._constructed = True + + # Step 5: A final "sum to 1" check for all DSD members (which now should be everything) + # Also check that all keys are made... The demand distro should be supported + # by the full set of (r, p, dem) keys because it is an equality constraint + # and we need to ensure even the zeros are passed in + used_rp_dems = set((r, p, dem) for r, p, dem in M.Demand.sparse_iterkeys()) + for r, p, dem in used_rp_dems: + expected_key_length = len(M.TimeSeason[p]) * len(M.time_of_day) + keys = [ + k + for k in DSD.sparse_iterkeys() + if DSD_region(k) == r and DSD_period(k) == p and DSD_dem(k) == dem + ] + if len(keys) != expected_key_length: + # this could be very slow but only calls when there's a problem + missing = set( + (s, d) + for s in M.TimeSeason[p] + for d in M.time_of_day + if (r, p, s, d, dem) not in keys + ) + logger.info( + 'Missing some time slices for Demand Specific Distribution %s: %s', + (r, p, dem), + missing, + ) + total = sum(value(DSD[i]) for i in keys) + if abs(value(total) - 1.0) > 0.001: + # We can't explicitly test for "!= 1.0" because of incremental rounding + # errors associated with the specification of demand shares by time slice, + # but we check to make sure it is within the specified tolerance. + def get_str_padding(obj): + return len(str(obj)) + + key_padding = max(map(get_str_padding, keys)) + + fmt = '%%-%ds = %%s' % key_padding + # Works out to something like "%-25s = %s" + + items = sorted((k, value(DSD[k])) for k in keys) + items = '\n '.join(fmt % (str(k), v) for k, v in items) + + msg = ( + 'The values of the DemandSpecificDistribution parameter do not ' + 'sum to 1 for {}. The DemandSpecificDistribution specifies how end-use ' + 'demands are distributed per time-slice (i.e., time_season, ' + 'time_of_day). Within each region, period, end-use demand, then, the distribution ' + 'must total to 1.\n\n Demand-specific distribution in error: ' + ' \n {}\n\tsum = {}' + ) + logger.error(msg.format((r, p, dem), items, total)) + raise ValueError(msg.format((r, p, dem), items, total)) + + logger.debug('Finished creating demand distributions') From 6ade40411f2c2dc36fca39357caa8dec9ea1fa1a Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 9 Oct 2025 16:27:42 -0400 Subject: [PATCH 227/587] cleaning up costs.py --- temoa/components/costs.py | 192 +++++++++++++++++++++++--------------- 1 file changed, 116 insertions(+), 76 deletions(-) diff --git a/temoa/components/costs.py b/temoa/components/costs.py index 21abc5db4..03d178644 100644 --- a/temoa/components/costs.py +++ b/temoa/components/costs.py @@ -1,3 +1,16 @@ +# temoa/components/costs.py +""" +Defines the cost-related components and the objective function of the Temoa model. + +This module is responsible for: +- Defining financial helper functions for Present Value, Future Value, and Annuity calculations. +- Pre-computing and populating cost parameters. +- Defining the rules for calculating all investment, fixed, variable, and emission-related + costs incurred over the model horizon. +- Defining the model's objective function (TotalCost_rule) to minimize the + net present value of the total system cost. +""" + from __future__ import annotations from typing import TYPE_CHECKING @@ -14,65 +27,16 @@ logger = getLogger(name=__name__) +# ============================================================================ +# FINANCIAL HELPER FUNCTIONS +# ============================================================================ + + def get_default_loan_rate(M: 'TemoaModel', *_): """get the default loan rate from the DefaultLoanRate param""" return M.DefaultLoanRate() -@deprecated(reason='vintage defaults are no longer available, so this should not be needed') -def CreateCosts(M: 'TemoaModel'): - """ - Steps to creating fixed and variable costs: - 1. Collect all possible cost indices (CostFixed, CostVariable) - 2. Find the ones _not_ specified in CostFixed and CostVariable - 3. Set them, based on Cost*VintageDefault - """ - logger.debug('Started Creating Fixed and Variable costs in CreateCosts()') - # Shorter names, for us lazy programmer types - CF = M.CostFixed - CV = M.CostVariable - - # Step 1 - fixed_indices = set(M.CostFixed_rptv) - var_indices = set(M.CostVariable_rptv) - - # Step 2 - unspecified_fixed_prices = fixed_indices.difference(CF.sparse_iterkeys()) - unspecified_var_prices = var_indices.difference(CV.sparse_iterkeys()) - - # Step 3 - - # Some hackery: We futz with _constructed because Pyomo thinks that this - # Param is already constructed. However, in our view, it is not yet, - # because we're specifically targeting values that have not yet been - # constructed, that we know are valid, and that we will need. - - if unspecified_fixed_prices: - # CF._constructed = False - for r, p, t, v in unspecified_fixed_prices: - if (r, t, v) in M.CostFixedVintageDefault: - CF[r, p, t, v] = M.CostFixedVintageDefault[r, t, v] # CF._constructed = True - - if unspecified_var_prices: - # CV._constructed = False - for r, p, t, v in unspecified_var_prices: - if (r, t, v) in M.CostVariableVintageDefault: - CV[r, p, t, v] = M.CostVariableVintageDefault[r, t, v] - # CV._constructed = True - logger.debug('Created M.CostFixed with size: %d', len(M.CostFixed)) - logger.debug('Created M.CostVariable with size: %d', len(M.CostVariable)) - logger.debug('Finished creating Fixed and Variable costs') - - -def CostFixedIndices(M: 'TemoaModel'): - # we pull the unlimited capacity techs from this index. They cannot have fixed costs - return {(r, p, t, v) for r, p, t, v in M.activeActivity_rptv if t not in M.tech_uncap} - - -def CostVariableIndices(M: 'TemoaModel'): - return M.activeActivity_rptv - - def annuity_to_pv(rate: float, periods: int) -> float | Expression: r""" Multiplication factor to convert an annuity to net present value @@ -120,6 +84,43 @@ def fv_to_pv(rate: float, periods: int) -> float | Expression: return 1 / (1 + rate) ** periods +def get_loan_life(M: 'TemoaModel', r, t, v): + return M.LifetimeProcess[r, t, v] + + +# ============================================================================ +# PYOMO INDEX SET FUNCTIONS +# ============================================================================ + + +def CostFixedIndices(M: 'TemoaModel'): + # we pull the unlimited capacity techs from this index. They cannot have fixed costs + return {(r, p, t, v) for r, p, t, v in M.activeActivity_rptv if t not in M.tech_uncap} + + +def CostVariableIndices(M: 'TemoaModel'): + return M.activeActivity_rptv + + +def LifetimeLoanProcessIndices(M: 'TemoaModel'): + """ + Based on the Efficiency parameter's indices and time_future parameter, this + function returns the set of process indices that may be specified in the + CostInvest parameter. + """ + min_period = min(M.vintage_optimize) + + indices = set((r, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys() if v >= min_period) + + return indices + + +# ============================================================================ +# COST CALCULATION FUNCTIONS +# These functions are the building blocks for the objective function. +# ============================================================================ + + def loan_cost( capacity: float | Var, invest_cost: float, @@ -289,21 +290,9 @@ def fixed_or_variable_cost( ) -def get_loan_life(M: 'TemoaModel', r, t, v): - return M.LifetimeProcess[r, t, v] - - -def LifetimeLoanProcessIndices(M: 'TemoaModel'): - """\ -Based on the Efficiency parameter's indices and time_future parameter, this -function returns the set of process indices that may be specified in the -CostInvest parameter. -""" - min_period = min(M.vintage_optimize) - - indices = set((r, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys() if v >= min_period) - - return indices +# ============================================================================ +# PYOMO EXPRESSION AND OBJECTIVE FUNCTION RULES +# ============================================================================ def PeriodCost_rule(M: 'TemoaModel', p): @@ -504,13 +493,6 @@ def PeriodCost_rule(M: 'TemoaModel', p): return period_costs -def ParamLoanAnnualize_rule(M: 'TemoaModel', r, t, v): - dr = value(M.LoanRate[r, t, v]) - lln = value(M.LoanLifetimeProcess[r, t, v]) - annualized_rate = pv_to_annuity(dr, lln) - return annualized_rate - - # --------------------------------------------------------------- # Define the Objective Function # --------------------------------------------------------------- @@ -649,3 +631,61 @@ def TotalCost_rule(M): """ return sum(PeriodCost_rule(M, p) for p in M.time_optimize) + + +# ============================================================================ +# PRE-COMPUTATION AND PARAMETER INITIALIZATION +# ============================================================================ + + +@deprecated(reason='vintage defaults are no longer available, so this should not be needed') +def CreateCosts(M: 'TemoaModel'): + """ + Steps to creating fixed and variable costs: + 1. Collect all possible cost indices (CostFixed, CostVariable) + 2. Find the ones _not_ specified in CostFixed and CostVariable + 3. Set them, based on Cost*VintageDefault + """ + logger.debug('Started Creating Fixed and Variable costs in CreateCosts()') + # Shorter names, for us lazy programmer types + CF = M.CostFixed + CV = M.CostVariable + + # Step 1 + fixed_indices = set(M.CostFixed_rptv) + var_indices = set(M.CostVariable_rptv) + + # Step 2 + unspecified_fixed_prices = fixed_indices.difference(CF.sparse_iterkeys()) + unspecified_var_prices = var_indices.difference(CV.sparse_iterkeys()) + + # Step 3 + + # Some hackery: We futz with _constructed because Pyomo thinks that this + # Param is already constructed. However, in our view, it is not yet, + # because we're specifically targeting values that have not yet been + # constructed, that we know are valid, and that we will need. + + if unspecified_fixed_prices: + # CF._constructed = False + for r, p, t, v in unspecified_fixed_prices: + if (r, t, v) in M.CostFixedVintageDefault: + CF[r, p, t, v] = M.CostFixedVintageDefault[r, t, v] # CF._constructed = True + + if unspecified_var_prices: + # CV._constructed = False + for r, p, t, v in unspecified_var_prices: + if (r, t, v) in M.CostVariableVintageDefault: + CV[r, p, t, v] = M.CostVariableVintageDefault[r, t, v] + # CV._constructed = True + logger.debug('Created M.CostFixed with size: %d', len(M.CostFixed)) + logger.debug('Created M.CostVariable with size: %d', len(M.CostVariable)) + logger.debug('Finished creating Fixed and Variable costs') + + +def ParamLoanAnnualize_rule(M: 'TemoaModel', r, t, v): + """Rule to calculate the annualized loan rate from the loan rate and lifetime.""" + dr = value(M.LoanRate[r, t, v]) + lln = value(M.LoanLifetimeProcess[r, t, v]) + annualized_rate = pv_to_annuity(dr, lln) + return annualized_rate From d7f69b4680ef30236a4eb8bf9d403c029c21b391 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 9 Oct 2025 16:30:56 -0400 Subject: [PATCH 228/587] cleaning up emissions.py --- temoa/components/emissions.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/temoa/components/emissions.py b/temoa/components/emissions.py index a449102fa..33409d5c4 100644 --- a/temoa/components/emissions.py +++ b/temoa/components/emissions.py @@ -1,3 +1,14 @@ +# temoa/components/emissions.py +""" +Defines the components of the Temoa model related to emissions accounting. + +This module is responsible for: +- Defining index sets for emission-related parameters and constraints. +- Defining the constraint rule for 'linked technologies', a special case where + an emission commodity (e.g., captured CO2) is also treated as a physical + input to a downstream process (e.g., synthetic fuel production). +""" + from typing import TYPE_CHECKING from pyomo.environ import value @@ -6,6 +17,11 @@ from temoa.core.model import TemoaModel +# ============================================================================ +# PYOMO INDEX SET FUNCTIONS +# ============================================================================ + + def EmissionActivityIndices(M: 'TemoaModel'): indices = set( (r, e, i, t, v, o) @@ -32,6 +48,11 @@ def LinkedTechConstraintIndices(M: 'TemoaModel'): return linkedtech_indices +# ============================================================================ +# PYOMO CONSTRAINT RULES +# ============================================================================ + + def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): r""" This constraint is necessary for carbon capture technologies that produce From 6c0185b537b0daf52b97fc8914b527a9144b81e8 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 9 Oct 2025 16:33:51 -0400 Subject: [PATCH 229/587] cleaning up flows.py --- temoa/components/flows.py | 40 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/temoa/components/flows.py b/temoa/components/flows.py index 0a13be0ca..b1d4ddb3f 100644 --- a/temoa/components/flows.py +++ b/temoa/components/flows.py @@ -1,3 +1,14 @@ +# temoa/components/flows.py +""" +Defines the flow-related components of the Temoa model. + +This module is responsible for: +- Pre-computing the sparse index sets for all types of commodity flows + (standard, annual, flexible, storage, curtailment). +- Defining the Pyomo index set functions used to construct the flow-related + decision variables (V_FlowOut, V_FlowIn, V_Flex, etc.). +""" + from logging import getLogger from typing import TYPE_CHECKING @@ -7,6 +18,11 @@ logger = getLogger(__name__) +# ============================================================================ +# PYOMO INDEX SET FUNCTIONS +# ============================================================================ + + def FlowVariableIndices(M: 'TemoaModel'): return M.activeFlow_rpsditvo @@ -31,10 +47,30 @@ def CurtailmentVariableIndices(M: 'TemoaModel'): return M.activeCurtailment_rpsditvo +# ============================================================================ +# PRE-COMPUTATION FUNCTION +# ============================================================================ + + def create_commodity_balance_and_flow_sets(M: 'TemoaModel'): """ - Creates the aggregated sets required for commodity balance constraints - and the indexed sets for active technology flows, capacities, and storage levels. + Creates aggregated sets for commodity balances and detailed index sets for active flows. + + This function is a critical part of the model setup, responsible for + creating the large, sparse index sets that define where decision variables + for flows, capacity, and storage levels will be created. + + Populates: + - M.commodityBalance_rpc: The master set of (r, p, c) for balance constraints. + - M.activeFlow_rpsditvo: Indices for time-sliced flows (V_FlowOut). + - M.activeFlow_rpitvo: Indices for annual flows (V_FlowOutAnnual). + - M.activeFlex_rpsditvo: Indices for flexible time-sliced flows (V_Flex). + - M.activeFlex_rpitvo: Indices for flexible annual flows (V_FlexAnnual). + - M.activeFlowInStorage_rpsditvo: Indices for flows into storage (V_FlowIn). + - M.activeCurtailment_rpsditvo: Indices for curtailed generation (V_Curtailment). + - M.activeActivity_rptv: Master set of active (r, p, t, v) processes. + - M.storageLevelIndices_rpsdtv: Indices for storage state variables (V_StorageLevel). + - M.seasonalStorageLevelIndices_rpstv: Indices for seasonal storage levels. """ logger.debug('Creating commodity balance and active flow index sets.') # 1. Commodity Balance From 53462dd1b0a6e6ffa445b0fc73ea35254850cc09 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 9 Oct 2025 16:36:59 -0400 Subject: [PATCH 230/587] cleaning up geography.py --- temoa/components/geography.py | 61 +++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 9 deletions(-) diff --git a/temoa/components/geography.py b/temoa/components/geography.py index 0f748f88b..b74d6c81c 100644 --- a/temoa/components/geography.py +++ b/temoa/components/geography.py @@ -1,3 +1,15 @@ +# temoa/components/geography.py +""" +Defines the geography-related components of the Temoa model. + +This module is responsible for handling all logic related to multi-region models, +including: +- Pre-computing the data structures for inter-regional commodity transfers + (imports and exports). +- Defining the sets of valid regions and regional groupings. +- Defining constraints that govern inter-regional capacity and flows. +""" + from logging import getLogger from typing import TYPE_CHECKING, Iterable @@ -9,6 +21,25 @@ logger = getLogger(name=__name__) +# ============================================================================ +# HELPER FUNCTIONS +# ============================================================================ + + +def gather_group_regions(M: 'TemoaModel', region: str) -> Iterable[str]: + if region == 'global': + regions = M.regions + elif '+' in region: + regions = region.split('+') + else: + regions = (region,) + return regions + + +# ============================================================================ +# PYOMO INDEX SET FUNCTIONS +# ============================================================================ + def CreateRegionalIndices(M: 'TemoaModel'): """Create the set of all regions and all region-region pairs""" @@ -41,14 +72,9 @@ def RegionalGlobalInitializedIndices(M: 'TemoaModel'): return indices -def gather_group_regions(M: 'TemoaModel', region: str) -> Iterable[str]: - if region == 'global': - regions = M.regions - elif '+' in region: - regions = region.split('+') - else: - regions = (region,) - return regions +# ============================================================================ +# PYOMO CONSTRAINT RULES +# ============================================================================ def RegionalExchangeCapacity_Constraint(M: 'TemoaModel', r_e, r_i, p, t, v): @@ -73,8 +99,25 @@ def RegionalExchangeCapacity_Constraint(M: 'TemoaModel', r_e, r_i, p, t, v): return expr +# ============================================================================ +# PRE-COMPUTATION FUNCTION +# ============================================================================ + + def create_geography_sets(M: 'TemoaModel'): - """Populates dictionaries related to inter-regional commodity exchange.""" + """ + Populates dictionaries related to inter-regional commodity exchange. + + This function iterates through exchange technologies (identified by a '-' in + their region name) and populates the `M.exportRegions` and `M.importRegions` + dictionaries. These are used later in the commodity balance constraints. + + Populates: + - M.exportRegions: dict mapping (region_from, p, commodity) to a set + of (region_to, t, v, o) tuples. + - M.importRegions: dict mapping (region_to, p, commodity) to a set + of (region_from, t, v, i) tuples. + """ logger.debug('Creating geography-related sets for exchange technologies.') for r, i, t, v, o in M.Efficiency.sparse_iterkeys(): if t not in M.tech_exchange: From f4c1125c7b89d207f5be80edfb698f0bee7d473c Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 9 Oct 2025 16:42:30 -0400 Subject: [PATCH 231/587] cleaning up limits.py --- temoa/components/limits.py | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/temoa/components/limits.py b/temoa/components/limits.py index e1a842752..860a188ca 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -1,3 +1,15 @@ +# temoa/components/limits.py +""" +Defines the various limit-related components of the Temoa model. + +This module contains a wide variety of constraints that enforce +limits on the energy system. These include, but are not limited to: +- Input/Output splits for technologies like refineries. +- Growth and degrowth rates for capacity deployment. +- Shares of capacity or activity for technology groups (e.g., for RPS policies). +- Absolute limits on capacity, new investment, or emissions. +""" + import sys from logging import getLogger from typing import TYPE_CHECKING @@ -13,6 +25,10 @@ logger = getLogger(__name__) +# ============================================================================ +# PYOMO INDEX SET FUNCTIONS +# ============================================================================ + def LimitTechInputSplitConstraintIndices(M: 'TemoaModel'): indices = set( @@ -153,6 +169,11 @@ def LimitDegrowthNewCapacityDeltaIndices(M: 'TemoaModel'): return indices +# ============================================================================ +# PYOMO CONSTRAINT RULES +# ============================================================================ + + # @deprecated('Deprecated. Use LimitActivityGroupShare instead') # doesn't play well with pyomo def RenewablePortfolioStandard_Constraint(M: 'TemoaModel', r, p, g): r""" @@ -1239,9 +1260,24 @@ def LimitCapacity_Constraint(M: 'TemoaModel', r, p, t, op): return expr +# ============================================================================ +# PRE-COMPUTATION FUNCTION +# ============================================================================ + + def create_limit_vintage_sets(M: 'TemoaModel'): """ - Populates vintage sets for technologies constrained by input/output split limits. + Populates vintage-specific dictionaries for input/output split limit constraints. + + This function iterates through active processes and identifies which vintages are + subject to split constraints, populating dictionaries that are then used by + the index set functions below. + + Populates: + - M.inputSplitVintages: dict mapping (r, p, i, t, op) to a set of vintages `v`. + - M.inputSplitAnnualVintages: dict for annual-specific input splits. + - M.outputSplitVintages: dict mapping (r, p, t, o, op) to a set of vintages `v`. + - M.outputSplitAnnualVintages: dict for annual-specific output splits. """ logger.debug('Creating vintage sets for split limits.') # Assuming M.processVintages is already populated From 53353a2e6fc7a6b4a7e6c51893a6901f037f9620 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 9 Oct 2025 16:52:06 -0400 Subject: [PATCH 232/587] cleaning up operations and merging ramping into it --- temoa/components/operations.py | 405 ++++++++++++++++++++++++++++++++- temoa/components/ramping.py | 371 ------------------------------ temoa/core/model.py | 19 +- 3 files changed, 405 insertions(+), 390 deletions(-) delete mode 100644 temoa/components/ramping.py diff --git a/temoa/components/operations.py b/temoa/components/operations.py index a22944da5..7b9a9a84a 100644 --- a/temoa/components/operations.py +++ b/temoa/components/operations.py @@ -1,6 +1,19 @@ +# temoa/components/operations.py +""" +Defines operational constraints for technologies in the Temoa model. + +This module is responsible for constraints that govern the dispatch behavior +of technologies across time slices, including: +- Pre-computing sets for technologies with special operational characteristics. +- Baseload constraints, which force constant output within a season. +- Ramping constraints, which limit the rate of change in output between + adjacent time slices. +""" + from logging import getLogger from typing import TYPE_CHECKING +from pyomo.core import Set from pyomo.environ import Constraint, value if TYPE_CHECKING: @@ -8,6 +21,10 @@ logger = getLogger(__name__) +# ============================================================================ +# PYOMO INDEX SET FUNCTIONS +# ============================================================================ + def BaseloadDiurnalConstraintIndices(M: 'TemoaModel'): indices = set( @@ -21,6 +38,78 @@ def BaseloadDiurnalConstraintIndices(M: 'TemoaModel'): return indices +def RampUpDayConstraintIndices(M: 'TemoaModel'): + indices = set( + (r, p, s, d, t, v) + for r, p, t in M.rampUpVintages + for v in M.rampUpVintages[r, p, t] + for s in M.TimeSeason[p] + for d in M.time_of_day + ) + + return indices + + +def RampDownDayConstraintIndices(M: 'TemoaModel'): + indices = set( + (r, p, s, d, t, v) + for r, p, t in M.rampDownVintages + for v in M.rampDownVintages[r, p, t] + for s in M.TimeSeason[p] + for d in M.time_of_day + ) + + return indices + + +def RampUpSeasonConstraintIndices(M: 'TemoaModel'): + if M.TimeSequencing.first() == 'consecutive_days': + return Set.Skip # dont need this constraint + + # s, s_next indexing ensures we dont build redundant constraints + indices = set( + (r, p, s, s_next, t, v) + for r, p, t in M.rampUpVintages + for v in M.rampUpVintages[r, p, t] + for _p, s_seq, s in M.ordered_season_sequential + if _p == p + for s_seq_next in (M.time_next_sequential[p, s_seq],) # next sequential season + for s_next in ( + M.sequential_to_season[p, s_seq_next], + ) # next sequential season's matching season + if s_next + != M.time_next[p, s, M.time_of_day.last()][0] # to avoid redundancy on RampDay constraint + ) + + return indices + + +def RampDownSeasonConstraintIndices(M: 'TemoaModel'): + if M.TimeSequencing.first() == 'consecutive_days': + return Set.Skip # dont need this constraint + + # s, s_next indexing ensures we dont build redundant constraints + indices = set( + (r, p, s, s_next, t, v) + for r, p, t in M.rampDownVintages + for v in M.rampDownVintages[r, p, t] + for _p, s_seq, s in M.ordered_season_sequential + for s_seq_next in (M.time_next_sequential[p, s_seq],) # next sequential season + for s_next in ( + M.sequential_to_season[p, s_seq_next], + ) # next sequential season's matching season + if s_next + != M.time_next[p, s, M.time_of_day.last()][0] # to avoid redundancy on RampDay constraint + ) + + return indices + + +# ============================================================================ +# PYOMO CONSTRAINT RULES +# ============================================================================ + + def BaseloadDiurnal_Constraint(M: 'TemoaModel', r, p, s, d, t, v): r""" @@ -90,23 +179,25 @@ def BaseloadDiurnal_Constraint(M: 'TemoaModel', r, p, s, d, t, v): return expr +# ============================================================================ +# PRE-COMPUTATION FUNCTION +# ============================================================================ + + def create_operational_vintage_sets(M: 'TemoaModel'): """ Populates vintage-based dictionaries for technologies with special operational characteristics like curtailment, baseload, storage, ramping, and reserves. + + Populates: + - M.curtailmentVintages, M.baseloadVintages, M.storageVintages, + M.rampUpVintages, M.rampDownVintages: Dictionaries mapping (r, p, t) + to a set of vintages `v`. + - M.processReservePeriods: Dictionary mapping (r, p) to a set of (t, v) tuples. + - M.isSeasonalStorage: A boolean lookup for seasonal storage technologies. """ logger.debug('Creating vintage sets for operational constraints.') - # Initialize the dictionaries to prevent KeyErrors later - M.curtailmentVintages = {} - M.baseloadVintages = {} - M.storageVintages = {} - M.rampUpVintages = {} - M.rampDownVintages = {} - M.isSeasonalStorage = {} - M.processReservePeriods = {} # Initialize the missing dictionary - - # Now populate them for r, p, t in M.processVintages: for v in M.processVintages[r, p, t]: key_rpt = (r, p, t) @@ -127,3 +218,297 @@ def create_operational_vintage_sets(M: 'TemoaModel'): # A dictionary of whether a storage tech is seasonal, just to speed things up for t in M.tech_storage: M.isSeasonalStorage[t] = t in M.tech_seasonal_storage + + +def RampUpDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): + r""" + One of two constraints built from the RampUpHourly table, along with the + RampUpSeason_Constraint. RampUpDay constrains ramp rates between time slices + within each season and RampUpSeason constrains ramp rates between sequential + seasons. If the :code:`time_sequencing` parameter is set to :code:`consecutive_days` + then the RampUpSeason constraint is skipped as seasons already connect together. + + The ramp rate constraint is utilized to limit the rate of electricity generation + increase and decrease between two adjacent time slices in order to account for + physical limits associated with thermal power plants. This constraint is only + applied to technologies in the set :code:`tech_upramping`. We assume for + simplicity the rate limits do not vary with technology vintage. The ramp rate + limits for a technology should be expressed in percentage of its rated capacity + per hour. + + In a representative periods or seasonal time slices model, the next time slice, + :math:`(s_{next},d_{next})`, from the end of each season, :math:`(s,d_{last})` + is the beginning of the same season, :math:`(s,d_{first})` + + .. math:: + :label: RampUpDay + + \frac{ + \sum_{I,O} \mathbf{FO}_{r,p,s_{next},d_{next},i,t,v,o} + }{ + SEG_{r,p,s_{next},d_{next}} \cdot 24 \cdot DPP + } + - + \frac{ + \sum_{I,O} \mathbf{FO}_{r,p,s,d,i,t,v,o} + }{ + SEG_{r,p,s,d} \cdot 24 \cdot DPP + } + \leq + R_{r,t} \cdot \Delta H_{r,p,s,d,s_{next},d_{next}} \cdot CAP_{r,p,t,v} \cdot C2A_{r,t} + \\ + \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampUpDay}} + \\ + \text{where: } \Delta H_{r,p,s,d,s_{next},d_{next}} = \frac{24}{2} + \left ( \frac{SEG_{r,p,s,d}}{\sum_{D} SEG_{r,p,s,d'}} + + \frac{SEG_{r,p,s_{next},d_{next}}}{\sum_{D} SEG_{r,p,s_{next},d'}} \right ) + + where: + + - :math:`SEG_{r,p,s,d}` is the fraction of the period in time slice :math:`(s,d)` + - :math:`DPP` is the number of days in each period + - :math:`R_{r,t}` is the ramp rate per hour + - :math:`\Delta H_{r,p,s,d,s_{next},d_{next}}` is the number of elapsed hours between midpoints of time slices + - :math:`CAP \cdot C2A` gives the maximum hourly change in activity + """ + + s_next, d_next = M.time_next[p, s, d] + + # How many hours does this time slice represent + hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 + + hourly_activity_sd = ( + sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) + + hourly_activity_sd_next = ( + sum( + M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) + + # elapsed hours from middle of this time slice to middle of next time slice + hours_elapsed = ( + 24 + / 2 + * ( + value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) + + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + ) + ) + ramp_fraction = hours_elapsed * value(M.RampUpHourly[r, t]) + + if ramp_fraction >= 1: + msg = ( + 'Warning: Hourly ramp up rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' + f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' + ) + logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) + return Constraint.Skip + + activity_increase = hourly_activity_sd_next - hourly_activity_sd # opposite sign from rampdown + rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) + expr = activity_increase <= rampable_activity + + return expr + + +def RampDownDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): + r""" + + Similar to the :code`RampUpDay` constraint, we use the :code:`RampDownDay` + constraint to limit ramp down rates between any two adjacent time slices. + + .. math:: + :label: RampDownDay + + \frac{ + \sum_{I,O} \mathbf{FO}_{r,p,s,d,i,t,v,o} + }{ + SEG_{r,p,s,d} \cdot 24 \cdot DPP + } + - + \frac{ + \sum_{I,O} \mathbf{FO}_{r,p,s_{next},d_{next},i,t,v,o} + }{ + SEG_{r,p,s_{next},d_{next}} \cdot 24 \cdot DPP + } + \leq + R_{r,t} \cdot \Delta H_{r,p,s,d,s_{next},d_{next}} \cdot CAP_{r,p,t,v} \cdot C2A_{r,t} + \\ + \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampDownDay}} + """ + + s_next, d_next = M.time_next[p, s, d] + + # How many hours does this time slice represent + hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 + + hourly_activity_sd = ( + sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) + + hourly_activity_sd_next = ( + sum( + M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) + + # elapsed hours from middle of this time slice to middle of next time slice + hours_elapsed = ( + 24 + / 2 + * ( + value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) + + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + ) + ) + ramp_fraction = hours_elapsed * value(M.RampDownHourly[r, t]) + + if ramp_fraction >= 1: + msg = ( + 'Warning: Hourly ramp down rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' + f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' + ) + logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) + return Constraint.Skip + + activity_decrease = hourly_activity_sd - hourly_activity_sd_next # opposite sign from rampup + rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) + expr = activity_decrease <= rampable_activity + + return expr + + +def RampUpSeason_Constraint(M: 'TemoaModel', r, p, s, s_next, t, v): + r""" + Constrains the ramp up rate of activity between time slices at the boundary + of sequential seasons. Same as RampUpDay but only applies to the boundary + between sequential seasons, i.e., :math:`(s^{seq},d_{last})` to :math:`(s^{seq}_{next},d_{first})` + and :math:`s^{seq}_{next}` is based on the TimeSequential table rather than the + TimeSeason table. + """ + + d = M.time_of_day.last() + d_next = M.time_of_day.first() + + # How many hours does this time slice represent + hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 + + hourly_activity_sd = ( + sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) + + hourly_activity_sd_next = ( + sum( + M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) + + # elapsed hours from middle of this time slice to middle of next time slice + hours_elapsed = ( + 24 + / 2 + * ( + value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) + + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + ) + ) + ramp_fraction = hours_elapsed * value(M.RampUpHourly[r, t]) + + if ramp_fraction >= 1: + msg = ( + 'Warning: Hourly ramp up rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' + f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' + ) + logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) + return Constraint.Skip + + activity_increase = hourly_activity_sd_next - hourly_activity_sd # opposite sign from rampdown + rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) + expr = activity_increase <= rampable_activity + + return expr + + +def RampDownSeason_Constraint(M: 'TemoaModel', r, p, s, s_next, t, v): + r""" + Constrains the ramp down rate of activity between time slices at the boundary + of sequential seasons. Same as RampDownDay but only applies to the boundary + between sequential seasons, i.e., :math:`(s^{seq},d_{last})` to :math:`(s^{seq}_{next},d_{first})` + and :math:`s^{seq}_{next}` is based on the TimeSequential table rather than the + TimeSeason table. + """ + + d = M.time_of_day.last() + d_next = M.time_of_day.first() + + # How many hours does this time slice represent + hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 + + hourly_activity_sd = ( + sum( + M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) + + hourly_activity_sd_next = ( + sum( + M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in M.processInputs[r, p, t, v] + for S_o in M.processOutputsByInput[r, p, t, v, S_i] + ) + / hours_adjust + ) + + # elapsed hours from middle of this time slice to middle of next time slice + hours_elapsed = ( + 24 + / 2 + * ( + value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) + + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + ) + ) + ramp_fraction = hours_elapsed * value(M.RampDownHourly[r, t]) + + if ramp_fraction >= 1: + msg = ( + 'Warning: Hourly ramp down rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' + f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' + ) + logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) + return Constraint.Skip + + activity_decrease = hourly_activity_sd - hourly_activity_sd_next # opposite sign from rampup + rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) + expr = activity_decrease <= rampable_activity + + return expr diff --git a/temoa/components/ramping.py b/temoa/components/ramping.py deleted file mode 100644 index 71e11d21a..000000000 --- a/temoa/components/ramping.py +++ /dev/null @@ -1,371 +0,0 @@ -from logging import getLogger -from typing import TYPE_CHECKING - -from pyomo.core import Set -from pyomo.environ import Constraint, value - -if TYPE_CHECKING: - from temoa.core.model import TemoaModel - -logger = getLogger(__name__) - - -def RampUpDayConstraintIndices(M: 'TemoaModel'): - indices = set( - (r, p, s, d, t, v) - for r, p, t in M.rampUpVintages - for v in M.rampUpVintages[r, p, t] - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - - return indices - - -def RampDownDayConstraintIndices(M: 'TemoaModel'): - indices = set( - (r, p, s, d, t, v) - for r, p, t in M.rampDownVintages - for v in M.rampDownVintages[r, p, t] - for s in M.TimeSeason[p] - for d in M.time_of_day - ) - - return indices - - -def RampUpSeasonConstraintIndices(M: 'TemoaModel'): - if M.TimeSequencing.first() == 'consecutive_days': - return Set.Skip # dont need this constraint - - # s, s_next indexing ensures we dont build redundant constraints - indices = set( - (r, p, s, s_next, t, v) - for r, p, t in M.rampUpVintages - for v in M.rampUpVintages[r, p, t] - for _p, s_seq, s in M.ordered_season_sequential - if _p == p - for s_seq_next in (M.time_next_sequential[p, s_seq],) # next sequential season - for s_next in ( - M.sequential_to_season[p, s_seq_next], - ) # next sequential season's matching season - if s_next - != M.time_next[p, s, M.time_of_day.last()][0] # to avoid redundancy on RampDay constraint - ) - - return indices - - -def RampDownSeasonConstraintIndices(M: 'TemoaModel'): - if M.TimeSequencing.first() == 'consecutive_days': - return Set.Skip # dont need this constraint - - # s, s_next indexing ensures we dont build redundant constraints - indices = set( - (r, p, s, s_next, t, v) - for r, p, t in M.rampDownVintages - for v in M.rampDownVintages[r, p, t] - for _p, s_seq, s in M.ordered_season_sequential - for s_seq_next in (M.time_next_sequential[p, s_seq],) # next sequential season - for s_next in ( - M.sequential_to_season[p, s_seq_next], - ) # next sequential season's matching season - if s_next - != M.time_next[p, s, M.time_of_day.last()][0] # to avoid redundancy on RampDay constraint - ) - - return indices - - -def RampUpDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): - r""" - One of two constraints built from the RampUpHourly table, along with the - RampUpSeason_Constraint. RampUpDay constrains ramp rates between time slices - within each season and RampUpSeason constrains ramp rates between sequential - seasons. If the :code:`time_sequencing` parameter is set to :code:`consecutive_days` - then the RampUpSeason constraint is skipped as seasons already connect together. - - The ramp rate constraint is utilized to limit the rate of electricity generation - increase and decrease between two adjacent time slices in order to account for - physical limits associated with thermal power plants. This constraint is only - applied to technologies in the set :code:`tech_upramping`. We assume for - simplicity the rate limits do not vary with technology vintage. The ramp rate - limits for a technology should be expressed in percentage of its rated capacity - per hour. - - In a representative periods or seasonal time slices model, the next time slice, - :math:`(s_{next},d_{next})`, from the end of each season, :math:`(s,d_{last})` - is the beginning of the same season, :math:`(s,d_{first})` - - .. math:: - :label: RampUpDay - - \frac{ - \sum_{I,O} \mathbf{FO}_{r,p,s_{next},d_{next},i,t,v,o} - }{ - SEG_{r,p,s_{next},d_{next}} \cdot 24 \cdot DPP - } - - - \frac{ - \sum_{I,O} \mathbf{FO}_{r,p,s,d,i,t,v,o} - }{ - SEG_{r,p,s,d} \cdot 24 \cdot DPP - } - \leq - R_{r,t} \cdot \Delta H_{r,p,s,d,s_{next},d_{next}} \cdot CAP_{r,p,t,v} \cdot C2A_{r,t} - \\ - \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampUpDay}} - \\ - \text{where: } \Delta H_{r,p,s,d,s_{next},d_{next}} = \frac{24}{2} - \left ( \frac{SEG_{r,p,s,d}}{\sum_{D} SEG_{r,p,s,d'}} + - \frac{SEG_{r,p,s_{next},d_{next}}}{\sum_{D} SEG_{r,p,s_{next},d'}} \right ) - - where: - - - :math:`SEG_{r,p,s,d}` is the fraction of the period in time slice :math:`(s,d)` - - :math:`DPP` is the number of days in each period - - :math:`R_{r,t}` is the ramp rate per hour - - :math:`\Delta H_{r,p,s,d,s_{next},d_{next}}` is the number of elapsed hours between midpoints of time slices - - :math:`CAP \cdot C2A` gives the maximum hourly change in activity - """ - - s_next, d_next = M.time_next[p, s, d] - - # How many hours does this time slice represent - hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 - - hourly_activity_sd = ( - sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - / hours_adjust - ) - - hourly_activity_sd_next = ( - sum( - M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - / hours_adjust - ) - - # elapsed hours from middle of this time slice to middle of next time slice - hours_elapsed = ( - 24 - / 2 - * ( - value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) - + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) - ) - ) - ramp_fraction = hours_elapsed * value(M.RampUpHourly[r, t]) - - if ramp_fraction >= 1: - msg = ( - 'Warning: Hourly ramp up rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' - f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' - ) - logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) - return Constraint.Skip - - activity_increase = hourly_activity_sd_next - hourly_activity_sd # opposite sign from rampdown - rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) - expr = activity_increase <= rampable_activity - - return expr - - -def RampDownDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): - r""" - - Similar to the :code`RampUpDay` constraint, we use the :code:`RampDownDay` - constraint to limit ramp down rates between any two adjacent time slices. - - .. math:: - :label: RampDownDay - - \frac{ - \sum_{I,O} \mathbf{FO}_{r,p,s,d,i,t,v,o} - }{ - SEG_{r,p,s,d} \cdot 24 \cdot DPP - } - - - \frac{ - \sum_{I,O} \mathbf{FO}_{r,p,s_{next},d_{next},i,t,v,o} - }{ - SEG_{r,p,s_{next},d_{next}} \cdot 24 \cdot DPP - } - \leq - R_{r,t} \cdot \Delta H_{r,p,s,d,s_{next},d_{next}} \cdot CAP_{r,p,t,v} \cdot C2A_{r,t} - \\ - \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampDownDay}} - """ - - s_next, d_next = M.time_next[p, s, d] - - # How many hours does this time slice represent - hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 - - hourly_activity_sd = ( - sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - / hours_adjust - ) - - hourly_activity_sd_next = ( - sum( - M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - / hours_adjust - ) - - # elapsed hours from middle of this time slice to middle of next time slice - hours_elapsed = ( - 24 - / 2 - * ( - value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) - + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) - ) - ) - ramp_fraction = hours_elapsed * value(M.RampDownHourly[r, t]) - - if ramp_fraction >= 1: - msg = ( - 'Warning: Hourly ramp down rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' - f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' - ) - logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) - return Constraint.Skip - - activity_decrease = hourly_activity_sd - hourly_activity_sd_next # opposite sign from rampup - rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) - expr = activity_decrease <= rampable_activity - - return expr - - -def RampUpSeason_Constraint(M: 'TemoaModel', r, p, s, s_next, t, v): - r""" - Constrains the ramp up rate of activity between time slices at the boundary - of sequential seasons. Same as RampUpDay but only applies to the boundary - between sequential seasons, i.e., :math:`(s^{seq},d_{last})` to :math:`(s^{seq}_{next},d_{first})` - and :math:`s^{seq}_{next}` is based on the TimeSequential table rather than the - TimeSeason table. - """ - - d = M.time_of_day.last() - d_next = M.time_of_day.first() - - # How many hours does this time slice represent - hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 - - hourly_activity_sd = ( - sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - / hours_adjust - ) - - hourly_activity_sd_next = ( - sum( - M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - / hours_adjust - ) - - # elapsed hours from middle of this time slice to middle of next time slice - hours_elapsed = ( - 24 - / 2 - * ( - value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) - + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) - ) - ) - ramp_fraction = hours_elapsed * value(M.RampUpHourly[r, t]) - - if ramp_fraction >= 1: - msg = ( - 'Warning: Hourly ramp up rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' - f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' - ) - logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) - return Constraint.Skip - - activity_increase = hourly_activity_sd_next - hourly_activity_sd # opposite sign from rampdown - rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) - expr = activity_increase <= rampable_activity - - return expr - - -def RampDownSeason_Constraint(M: 'TemoaModel', r, p, s, s_next, t, v): - r""" - Constrains the ramp down rate of activity between time slices at the boundary - of sequential seasons. Same as RampDownDay but only applies to the boundary - between sequential seasons, i.e., :math:`(s^{seq},d_{last})` to :math:`(s^{seq}_{next},d_{first})` - and :math:`s^{seq}_{next}` is based on the TimeSequential table rather than the - TimeSeason table. - """ - - d = M.time_of_day.last() - d_next = M.time_of_day.first() - - # How many hours does this time slice represent - hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 - - hourly_activity_sd = ( - sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - / hours_adjust - ) - - hourly_activity_sd_next = ( - sum( - M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - ) - / hours_adjust - ) - - # elapsed hours from middle of this time slice to middle of next time slice - hours_elapsed = ( - 24 - / 2 - * ( - value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) - + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) - ) - ) - ramp_fraction = hours_elapsed * value(M.RampDownHourly[r, t]) - - if ramp_fraction >= 1: - msg = ( - 'Warning: Hourly ramp down rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' - f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' - ) - logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) - return Constraint.Skip - - activity_decrease = hourly_activity_sd - hourly_activity_sd_next # opposite sign from rampup - rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) - expr = activity_decrease <= rampable_activity - - return expr diff --git a/temoa/core/model.py b/temoa/core/model.py index e3d217862..0799aaca7 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -32,7 +32,6 @@ geography, limits, operations, - ramping, reserves, storage, technology, @@ -913,28 +912,30 @@ def __init__(M, *args, **kwargs): M.LimitStorageFractionConstraint_rpsdtv, rule=storage.LimitStorageFraction_Constraint ) - M.RampUpDayConstraint_rpsdtv = Set(dimen=6, initialize=ramping.RampUpDayConstraintIndices) + M.RampUpDayConstraint_rpsdtv = Set( + dimen=6, initialize=operations.RampUpDayConstraintIndices + ) M.RampUpDayConstraint = Constraint( - M.RampUpDayConstraint_rpsdtv, rule=ramping.RampUpDay_Constraint + M.RampUpDayConstraint_rpsdtv, rule=operations.RampUpDay_Constraint ) M.RampDownDayConstraint_rpsdtv = Set( - dimen=6, initialize=ramping.RampDownDayConstraintIndices + dimen=6, initialize=operations.RampDownDayConstraintIndices ) M.RampDownDayConstraint = Constraint( - M.RampDownDayConstraint_rpsdtv, rule=ramping.RampDownDay_Constraint + M.RampDownDayConstraint_rpsdtv, rule=operations.RampDownDay_Constraint ) M.RampUpSeasonConstraint_rpsstv = Set( - dimen=6, initialize=ramping.RampUpSeasonConstraintIndices + dimen=6, initialize=operations.RampUpSeasonConstraintIndices ) M.RampUpSeasonConstraint = Constraint( - M.RampUpSeasonConstraint_rpsstv, rule=ramping.RampUpSeason_Constraint + M.RampUpSeasonConstraint_rpsstv, rule=operations.RampUpSeason_Constraint ) M.RampDownSeasonConstraint_rpsstv = Set( - dimen=6, initialize=ramping.RampDownSeasonConstraintIndices + dimen=6, initialize=operations.RampDownSeasonConstraintIndices ) M.RampDownSeasonConstraint = Constraint( - M.RampDownSeasonConstraint_rpsstv, rule=ramping.RampDownSeason_Constraint + M.RampDownSeasonConstraint_rpsstv, rule=operations.RampDownSeason_Constraint ) M.ReserveMargin_rpsd = Set(dimen=4, initialize=reserves.ReserveMarginIndices) From 1a7d3bf776d53db204916968cafbdffbca91715b Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 9 Oct 2025 16:54:43 -0400 Subject: [PATCH 233/587] cleaning up reserves.py --- temoa/components/reserves.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/temoa/components/reserves.py b/temoa/components/reserves.py index b5407d358..a0d69cfcb 100644 --- a/temoa/components/reserves.py +++ b/temoa/components/reserves.py @@ -1,3 +1,13 @@ +# temoa/components/reserves.py +""" +Defines the reserve margin components of the Temoa model. + +This module is responsible for ensuring the energy system maintains a sufficient +planning reserve margin to ensure reliability. It supports both a 'static' +(based on installed capacity) and a 'dynamic' (based on available generation +in a time slice) formulation for calculating available reserves. +""" + from logging import getLogger from typing import TYPE_CHECKING @@ -10,6 +20,10 @@ logger = getLogger(__name__) +# ============================================================================ +# PYOMO INDEX SET FUNCTIONS +# ============================================================================ + def ReserveMarginIndices(M: 'TemoaModel'): indices = set( @@ -24,6 +38,11 @@ def ReserveMarginIndices(M: 'TemoaModel'): return indices +# ============================================================================ +# HELPER FUNCTIONS FOR CONSTRAINT LOGIC +# ============================================================================ + + def ReserveMarginDynamic(M: 'TemoaModel', r, p, s, d): r""" A dynamic alternative to the traditional, static reserve margin constraint. Capacity values @@ -207,6 +226,11 @@ def ReserveMarginStatic(M: 'TemoaModel', r, p, s, d): return available +# ============================================================================ +# PYOMO CONSTRAINT RULE +# ============================================================================ + + def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): # Get available generation in this time slice depending on method specified in config file match M.ReserveMarginMethod.first(): From 3babdbe3d3e4163831b17a418a3a0920c5a45607 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 9 Oct 2025 16:58:36 -0400 Subject: [PATCH 234/587] cleaning up storage.py --- temoa/components/storage.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/temoa/components/storage.py b/temoa/components/storage.py index 7a8167db5..9e9591d69 100644 --- a/temoa/components/storage.py +++ b/temoa/components/storage.py @@ -1,3 +1,16 @@ +# temoa/components/storage.py +""" +Defines the energy storage-related components of the Temoa model. + +This module is responsible for modeling the behavior of storage technologies, +including: +- Defining the state variables for storage levels (both daily and seasonal). +- Enforcing the conservation of energy from one time slice to the next. +- Constraining the storage level to be within the device's energy capacity. +- Constraining the charge, discharge, and throughput rates to be within the + device's power capacity. +""" + from typing import TYPE_CHECKING from pyomo.environ import Constraint, value @@ -8,6 +21,11 @@ from temoa.core.model import TemoaModel +# ============================================================================ +# PYOMO INDEX SET FUNCTIONS +# ============================================================================ + + def StorageLevelVariableIndices(M: 'TemoaModel'): return M.storageLevelIndices_rpsdtv @@ -30,6 +48,13 @@ def StorageConstraintIndices(M: 'TemoaModel'): return M.storageLevelIndices_rpsdtv +# ============================================================================ +# PYOMO CONSTRAINT RULES +# ============================================================================ + +# --- Core Energy Balance Constraints --- + + def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): r""" This constraint enforces the continuity of storage level between time slices. @@ -168,6 +193,9 @@ def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_seq, t, v): return expr +# --- Capacity and Rate Limit Constraints --- + + def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): r""" This constraint ensures that the amount of energy stored does not exceed From 93ed9248d93ebda4c56394b2eed125eab94ba6b2 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 9 Oct 2025 17:06:53 -0400 Subject: [PATCH 235/587] cleaning up technology.py --- temoa/components/technology.py | 440 ++++++++++++++++++--------------- 1 file changed, 235 insertions(+), 205 deletions(-) diff --git a/temoa/components/technology.py b/temoa/components/technology.py index 829bee5ca..a6ce9881f 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -1,3 +1,15 @@ +# temoa/components/technology.py +""" +Defines the core technology-related components of the Temoa model. + +This module is the foundation of the model, responsible for: +- Pre-computing the core data structures that link technologies to commodities, + time periods, and vintages based on the `Efficiency` parameter. +- Handling technology lifetimes, including survival curve validation and interpolation. +- Defining Pyomo index sets for core technology parameters. +- Validating model inputs related to technologies, efficiencies, and commodities. +""" + from typing import TYPE_CHECKING if TYPE_CHECKING: @@ -11,120 +23,40 @@ logger = getLogger(__name__) +# ============================================================================ +# HELPER FUNCTIONS +# ============================================================================ -def CheckEfficiencyIndices(M: 'TemoaModel'): - """ - Ensure that there are no unused items in any of the Efficiency index sets. - """ - # TODO: This could be upgraded to scan for finer resolution - # by checking by REGION and PERIOD... Each region/period is unique. - c_physical = set(i for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) - c_physical = c_physical | set(i for r, i, t, v in M.ConstructionInput.sparse_iterkeys()) - techs = set(t for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) - c_outputs = set(o for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) - c_outputs = c_outputs | set(o for r, t, v, o in M.EndOfLifeOutput.sparse_iterkeys()) - - symdiff = c_physical.symmetric_difference(M.commodity_physical) - if symdiff: - msg = ( - 'Unused or unspecified physical carriers. Either add or remove ' - 'the following elements to the Set commodity_physical.' - '\n\n Element(s): {}' - ) - symdiff = (str(i) for i in symdiff) - f_msg = msg.format(', '.join(symdiff)) - logger.error(f_msg) - raise ValueError(f_msg) - - symdiff = techs.symmetric_difference(M.tech_all) - if symdiff: - msg = ( - 'Unused or unspecified technologies. Either add or remove ' - 'the following technology(ies) to the tech_resource or ' - 'tech_production Sets.\n\n Technology(ies): {}' - ) - symdiff = (str(i) for i in symdiff) - f_msg = msg.format(', '.join(symdiff)) - logger.error(f_msg) - raise ValueError(f_msg) - - diff = M.commodity_demand - c_outputs - if diff: - msg = ( - 'Unused or unspecified outputs. Either add or remove the ' - 'following elements to the commodity_demand Set.' - '\n\n Element(s): {}' - ) - diff = (str(i) for i in diff) - f_msg = msg.format(', '.join(diff)) - logger.error(f_msg) - raise ValueError(f_msg) +def gather_group_techs(M: 'TemoaModel', t_or_g: str) -> Iterable[str]: + if t_or_g in M.tech_group_names: + techs = M.tech_group_members[t_or_g] + elif '+' in t_or_g: + techs = t_or_g.split('+') + else: + techs = (t_or_g,) + return techs -def CheckEfficiencyVariable(M: 'TemoaModel'): - count_rpitvo = dict() - # Pull non-variable efficiency by default - for r, i, t, v, o in M.Efficiency.sparse_iterkeys(): - if (r, t, v) not in M.processPeriods: - # Probably an existing vintage that retires in p0 - # Still want it for end of life flows - continue - for p in M.processPeriods[r, t, v]: - M.isEfficiencyVariable[r, p, i, t, v, o] = False - count_rpitvo[r, p, i, t, v, o] = 0 - - annual = set() - # Check for bad values and count up the good ones - for r, p, _s, _d, i, t, v, o in M.EfficiencyVariable.sparse_iterkeys(): - if p not in M.processPeriods[r, t, v]: - msg = f'Invalid period {p} for process {r, t, v} in EfficiencyVariable table' - logger.error(msg) - raise ValueError(msg) - - if t in M.tech_annual: - annual.add(t) - - # Good value, pull from EfficiencyVariable table - count_rpitvo[r, p, i, t, v, o] += 1 - - for t in annual: - msg = ( - f'Variable efficiencies were provided for the annual technology {t}, which has ' - 'no variable output. This will only be applied to flows on non-annual commodities. ' - 'This is ambiguous behaviour and not recommended.' - ) - logger.warning(msg) - # Check if all possible values have been set as variable - # log a warning if some are missing (allowed but maybe accidental) - num_seg = len(M.TimeSeason[p]) * len(M.time_of_day) - for (r, p, i, t, v, o), count in count_rpitvo.items(): - if count > 0: - M.isEfficiencyVariable[r, p, i, t, v, o] = True - if count < num_seg: - logger.info( - 'Some but not all EfficiencyVariable values were set (%i out of a possible %i) for: %s' - ' Missing values will default to value set in Efficiency table.', - count, - num_seg, - (r, p, i, t, v, o), - ) +# ============================================================================ +# PYOMO INDEX SETS AND PARAMETER RULES +# ============================================================================ def ModelProcessLifeIndices(M: 'TemoaModel'): - """\ -Returns the set of sensical (region, period, tech, vintage) tuples. The tuple indicates -the periods in which a process is active, distinct from TechLifeFracIndices that -returns indices only for processes that EOL mid-period. -""" + """ + Returns the set of sensical (region, period, tech, vintage) tuples. The tuple indicates + the periods in which a process is active, distinct from TechLifeFracIndices that + returns indices only for processes that EOL mid-period. + """ return M.activeActivity_rptv def LifetimeProcessIndices(M: 'TemoaModel'): - """\ -Based on the Efficiency parameter's indices, this function returns the set of -process indices that may be specified in the LifetimeProcess parameter. -""" + """ + Based on the Efficiency parameter's indices, this function returns the set of + process indices that may be specified in the LifetimeProcess parameter. + """ indices = set((r, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) return indices @@ -136,10 +68,7 @@ def get_default_survival(M: 'TemoaModel', r, p, t, v): If this is a survival curve process, return 0 (likely beyond EOL) Otherwise return 1 (no survival curve based EOL) """ - if M.isSurvivalCurveProcess[r, t, v]: - return 0 - else: - return 1 + return 0.0 if M.isSurvivalCurveProcess[r, t, v] else 1.0 def get_default_process_lifetime(M: 'TemoaModel', r, t, v): @@ -159,14 +88,123 @@ def get_default_process_lifetime(M: 'TemoaModel', r, t, v): return M.LifetimeTech[r, t] -def gather_group_techs(M: 'TemoaModel', t_or_g: str) -> Iterable[str]: - if t_or_g in M.tech_group_names: - techs = M.tech_group_members[t_or_g] - elif '+' in t_or_g: - techs = t_or_g.split('+') +def ParamProcessLifeFraction_rule(M: 'TemoaModel', r, p, t, v): + r""" + Get the effective capacity of a process :math:`` in a period :math:`p`. + + Accounts for mid-period end of life or average survival over the period + for processes using survival curves. + """ + + period_length = value(M.PeriodLength[p]) + + if M.isSurvivalCurveProcess[r, t, v]: + # Sum survival fraction over the period + years_remaining = sum( + value(M.LifetimeSurvivalCurve[r, _p, t, v]) for _p in range(p, p + period_length, 1) + ) else: - techs = (t_or_g,) - return techs + # Remaining life years within the EOL period + years_remaining = v + value(M.LifetimeProcess[r, t, v]) - p + + if years_remaining >= period_length: + # try to avoid floating point round-off errors for the common case. + return 1 + + frac = years_remaining / float(period_length) + return frac + + +# ============================================================================ +# PRE-COMPUTATION AND VALIDATION FUNCTIONS +# ============================================================================ + + +def populate_core_dictionaries(M: 'TemoaModel'): + """ + Populates the core sparse dictionaries from the `Efficiency` parameter. + + This function is foundational for creating the sparse indices used throughout + the model, defining process relationships, inputs, outputs, and active periods. + + Populates: + - M.processInputs, M.processOutputs + - M.commodityDStreamProcess, M.commodityUStreamProcess + - M.processOutputsByInput, M.processInputsByOutput + - M.processVintages, M.processPeriods + - M.used_techs + """ + logger.debug('Populating core sparse dictionaries from Efficiency parameter.') + first_period = min(M.time_future) + exist_indices = M.ExistingCapacity.sparse_keys() + + for r, i, t, v, o in M.Efficiency.sparse_iterkeys(): + # A. Basic data validation and warnings + process = (r, t, v) + lifetime = value(M.LifetimeProcess[process]) + if v in M.vintage_exist: + if process not in exist_indices and t not in M.tech_uncap: + logger.warning( + f'Warning: {process} has a specified Efficiency, but does not ' + f'have any existing install base (ExistingCapacity).' + ) + continue + if t not in M.tech_uncap and M.ExistingCapacity[process] == 0: + logger.warning( + f'Notice: Unnecessary specification of ExistingCapacity for {process}. ' + f'Declaring a capacity of zero may be omitted.' + ) + continue + if v + lifetime <= first_period: + logger.info( + f'{process} specified as ExistingCapacity, but its ' + f'lifetime ({lifetime} years) does not extend past the ' + f'beginning of time_future ({first_period}).' + ) + + if M.Efficiency[r, i, t, v, o] == 0: + logger.info( + f'Notice: Unnecessary specification of Efficiency for {(r, i, t, v, o)}. ' + f'Specifying an efficiency of zero may be omitted.' + ) + continue + + M.used_techs.add(t) + + # B. Loop through time periods to build time-dependent relationships + for p in M.time_optimize: + # Skip if tech is not invented or is already retired + if p < v or v + lifetime <= p: + continue + + pindex = (r, p, t, v) + + # C. Initialize dictionary keys if not present + if pindex not in M.processInputs: + M.processInputs[pindex] = set() + M.processOutputs[pindex] = set() + if (r, p, i) not in M.commodityDStreamProcess: + M.commodityDStreamProcess[r, p, i] = set() + if (r, p, o) not in M.commodityUStreamProcess: + M.commodityUStreamProcess[r, p, o] = set() + if (r, p, t, v, i) not in M.processOutputsByInput: + M.processOutputsByInput[r, p, t, v, i] = set() + if (r, p, t, v, o) not in M.processInputsByOutput: + M.processInputsByOutput[r, p, t, v, o] = set() + if (r, p, t) not in M.processVintages: + M.processVintages[r, p, t] = set() + if (r, t, v) not in M.processPeriods: + M.processPeriods[r, t, v] = set() + + # D. Populate the dictionaries + M.processInputs[pindex].add(i) + M.processOutputs[pindex].add(o) + M.commodityDStreamProcess[r, p, i].add((t, v)) + M.commodityUStreamProcess[r, p, o].add((t, v)) + M.processOutputsByInput[r, p, t, v, i].add(o) + M.processInputsByOutput[r, p, t, v, o].add(i) + M.processVintages[r, p, t].add(v) + M.processPeriods[r, t, v].add(p) def CreateSurvivalCurve(M: 'TemoaModel'): @@ -284,108 +322,100 @@ def CreateSurvivalCurve(M: 'TemoaModel'): logger.info(msg) -def ParamProcessLifeFraction_rule(M: 'TemoaModel', r, p, t, v): - r""" - Get the effective capacity of a process :math:`` in a period :math:`p`. - - Accounts for mid-period end of life or average survival over the period - for processes using survival curves. +def CheckEfficiencyIndices(M: 'TemoaModel'): """ + Ensure that there are no unused items in any of the Efficiency index sets. + """ + # TODO: This could be upgraded to scan for finer resolution + # by checking by REGION and PERIOD... Each region/period is unique. + c_physical = set(i for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) + c_physical = c_physical | set(i for r, i, t, v in M.ConstructionInput.sparse_iterkeys()) + techs = set(t for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) + c_outputs = set(o for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) + c_outputs = c_outputs | set(o for r, t, v, o in M.EndOfLifeOutput.sparse_iterkeys()) - period_length = value(M.PeriodLength[p]) - - if M.isSurvivalCurveProcess[r, t, v]: - # Sum survival fraction over the period - years_remaining = sum( - value(M.LifetimeSurvivalCurve[r, _p, t, v]) for _p in range(p, p + period_length, 1) + symdiff = c_physical.symmetric_difference(M.commodity_physical) + if symdiff: + msg = ( + 'Unused or unspecified physical carriers. Either add or remove ' + 'the following elements to the Set commodity_physical.' + '\n\n Element(s): {}' ) - else: - # Remaining life years within the EOL period - years_remaining = v + value(M.LifetimeProcess[r, t, v]) - p - - if years_remaining >= period_length: - # try to avoid floating point round-off errors for the common case. - return 1 - - frac = years_remaining / float(period_length) - return frac + symdiff = (str(i) for i in symdiff) + f_msg = msg.format(', '.join(symdiff)) + logger.error(f_msg) + raise ValueError(f_msg) + symdiff = techs.symmetric_difference(M.tech_all) + if symdiff: + msg = ( + 'Unused or unspecified technologies. Either add or remove ' + 'the following technology(ies) to the tech_resource or ' + 'tech_production Sets.\n\n Technology(ies): {}' + ) + symdiff = (str(i) for i in symdiff) + f_msg = msg.format(', '.join(symdiff)) + logger.error(f_msg) + raise ValueError(f_msg) -def populate_core_dictionaries(M: 'TemoaModel'): - """ - Loops through the Efficiency parameter to populate the core sparse dictionaries - that define process relationships, inputs, outputs, and active periods. + diff = M.commodity_demand - c_outputs + if diff: + msg = ( + 'Unused or unspecified outputs. Either add or remove the ' + 'following elements to the commodity_demand Set.' + '\n\n Element(s): {}' + ) + diff = (str(i) for i in diff) + f_msg = msg.format(', '.join(diff)) + logger.error(f_msg) + raise ValueError(f_msg) - This function is foundational for creating the sparse indices used throughout the model. - """ - logger.debug('Populating core sparse dictionaries from Efficiency parameter.') - first_period = min(M.time_future) - exist_indices = M.ExistingCapacity.sparse_keys() +def CheckEfficiencyVariable(M: 'TemoaModel'): + count_rpitvo = dict() + # Pull non-variable efficiency by default for r, i, t, v, o in M.Efficiency.sparse_iterkeys(): - # A. Basic data validation and warnings - process = (r, t, v) - lifetime = value(M.LifetimeProcess[process]) - if v in M.vintage_exist: - if process not in exist_indices and t not in M.tech_uncap: - logger.warning( - f'Warning: {process} has a specified Efficiency, but does not ' - f'have any existing install base (ExistingCapacity).' - ) - continue - if t not in M.tech_uncap and M.ExistingCapacity[process] == 0: - logger.warning( - f'Notice: Unnecessary specification of ExistingCapacity for {process}. ' - f'Declaring a capacity of zero may be omitted.' - ) - continue - if v + lifetime <= first_period: - logger.info( - f'{process} specified as ExistingCapacity, but its ' - f'lifetime ({lifetime} years) does not extend past the ' - f'beginning of time_future ({first_period}).' - ) - - if M.Efficiency[r, i, t, v, o] == 0: - logger.info( - f'Notice: Unnecessary specification of Efficiency for {(r, i, t, v, o)}. ' - f'Specifying an efficiency of zero may be omitted.' - ) + if (r, t, v) not in M.processPeriods: + # Probably an existing vintage that retires in p0 + # Still want it for end of life flows continue + for p in M.processPeriods[r, t, v]: + M.isEfficiencyVariable[r, p, i, t, v, o] = False + count_rpitvo[r, p, i, t, v, o] = 0 - M.used_techs.add(t) + annual = set() + # Check for bad values and count up the good ones + for r, p, _s, _d, i, t, v, o in M.EfficiencyVariable.sparse_iterkeys(): + if p not in M.processPeriods[r, t, v]: + msg = f'Invalid period {p} for process {r, t, v} in EfficiencyVariable table' + logger.error(msg) + raise ValueError(msg) - # B. Loop through time periods to build time-dependent relationships - for p in M.time_optimize: - # Skip if tech is not invented or is already retired - if p < v or v + lifetime <= p: - continue + if t in M.tech_annual: + annual.add(t) - pindex = (r, p, t, v) + # Good value, pull from EfficiencyVariable table + count_rpitvo[r, p, i, t, v, o] += 1 - # C. Initialize dictionary keys if not present - if pindex not in M.processInputs: - M.processInputs[pindex] = set() - M.processOutputs[pindex] = set() - if (r, p, i) not in M.commodityDStreamProcess: - M.commodityDStreamProcess[r, p, i] = set() - if (r, p, o) not in M.commodityUStreamProcess: - M.commodityUStreamProcess[r, p, o] = set() - if (r, p, t, v, i) not in M.processOutputsByInput: - M.processOutputsByInput[r, p, t, v, i] = set() - if (r, p, t, v, o) not in M.processInputsByOutput: - M.processInputsByOutput[r, p, t, v, o] = set() - if (r, p, t) not in M.processVintages: - M.processVintages[r, p, t] = set() - if (r, t, v) not in M.processPeriods: - M.processPeriods[r, t, v] = set() + for t in annual: + msg = ( + f'Variable efficiencies were provided for the annual technology {t}, which has ' + 'no variable output. This will only be applied to flows on non-annual commodities. ' + 'This is ambiguous behaviour and not recommended.' + ) + logger.warning(msg) - # D. Populate the dictionaries - M.processInputs[pindex].add(i) - M.processOutputs[pindex].add(o) - M.commodityDStreamProcess[r, p, i].add((t, v)) - M.commodityUStreamProcess[r, p, o].add((t, v)) - M.processOutputsByInput[r, p, t, v, i].add(o) - M.processInputsByOutput[r, p, t, v, o].add(i) - M.processVintages[r, p, t].add(v) - M.processPeriods[r, t, v].add(p) + # Check if all possible values have been set as variable + # log a warning if some are missing (allowed but maybe accidental) + num_seg = len(M.TimeSeason[p]) * len(M.time_of_day) + for (r, p, i, t, v, o), count in count_rpitvo.items(): + if count > 0: + M.isEfficiencyVariable[r, p, i, t, v, o] = True + if count < num_seg: + logger.info( + 'Some but not all EfficiencyVariable values were set (%i out of a possible %i) for: %s' + ' Missing values will default to value set in Efficiency table.', + count, + num_seg, + (r, p, i, t, v, o), + ) From ec5aac507035be2ac9dbafc64e01ce7ca777f00b Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 9 Oct 2025 17:13:41 -0400 Subject: [PATCH 236/587] cleaning up time.py --- temoa/components/time.py | 172 ++++++++++++++++++++++----------------- 1 file changed, 99 insertions(+), 73 deletions(-) diff --git a/temoa/components/time.py b/temoa/components/time.py index 309465f21..dab6b5345 100644 --- a/temoa/components/time.py +++ b/temoa/components/time.py @@ -1,6 +1,14 @@ # temoa/components/time.py """ This module contains components related to time indexing in the Temoa model. + +It is responsible for: +- Validating the core time sets (`time_exist`, `time_future`). +- Validating the user-defined time-slice fractions (`TimeSegmentFraction`). +- Creating the sequence of time slices (`time_next`) based on the chosen + sequencing method (e.g., `seasonal_timeslices`, `consecutive_days`). +- Creating and validating the superimposed sequential seasons used for + seasonal storage and inter-season ramping constraints. """ from logging import getLogger @@ -15,8 +23,10 @@ logger = getLogger(__name__) -def init_set_time_optimize(M: 'TemoaModel'): - return sorted(M.time_future)[:-1] +# ============================================================================ +# INITIAL VALIDATION FUNCTIONS +# These are called early in the model build to ensure time data is coherent. +# ============================================================================ def validate_time(M: 'TemoaModel'): @@ -72,6 +82,51 @@ def validate_time(M: 'TemoaModel'): logger.debug('Finished validating time') +def validate_SegFrac(M: 'TemoaModel'): + """Ensure that the segment fractions adds up to 1""" + + for p in M.time_optimize: + expected_keys = set((p, s, d) for s in M.TimeSeason[p] for d in M.time_of_day) + keys = set((_p, s, d) for _p, s, d in M.SegFrac.sparse_iterkeys() if _p == p) + + if expected_keys != keys: + extra = keys.difference(expected_keys) + missing = expected_keys.difference(keys) + msg = ( + 'TimeSegmentFraction elements for period {} do not match TimeSeason and TimeOfDay.' + '\n\nIndices missing from TimeSegmentFraction:\n{}' + '\n\nIndices in TimeSegmentFraction missing from TimeSeason/TimeOfDay:\n{}' + ).format(p, missing, extra) + logger.error(msg) + raise ValueError(msg) + + total = sum(M.SegFrac[k] for k in keys) + + if abs(float(total) - 1.0) > 0.001: + # We can't explicitly test for "!= 1.0" because of incremental rounding + # errors associated with the specification of SegFrac by time slice, + # but we check to make sure it is within the specified tolerance. + + def get_str_padding(obj): + return len(str(obj)) + + key_padding = max(map(get_str_padding, keys)) + + fmt = '%%-%ds = %%s' % key_padding + # Works out to something like "%-25s = %s" + + items = sorted([(k, M.SegFrac[k]) for k in keys]) + items = '\n '.join(fmt % (str(k), v) for k, v in items) + + msg = ( + 'The values of TimeSegmentFraction do not sum to 1 for period {}. ' + 'Each item in SegFrac represents a fraction of a year, so they must ' + 'total to 1. Current values:\n {}\n\tsum = {}' + ).format(p, items, total) + logger.error(msg) + raise Exception(msg) + + def validate_TimeNext(M: 'TemoaModel'): """ If using this table, check that defined states are actually valid. @@ -97,6 +152,43 @@ def validate_TimeNext(M: 'TemoaModel'): raise ValueError(msg) +# ============================================================================ +# PYOMO SET INITIALIZERS AND PARAMETER RULES +# ============================================================================ + + +def init_set_time_optimize(M: 'TemoaModel'): + """Initializes the `time_optimize` set (all future years except the last).""" + return sorted(M.time_future)[:-1] + + +def init_set_vintage_exist(M: 'TemoaModel'): + """Initializes the `vintage_exist` set.""" + return sorted(M.time_exist) + + +def init_set_vintage_optimize(M: 'TemoaModel'): + """Initializes the `vintage_optimize` set.""" + return sorted(M.time_optimize) + + +def SegFracPerSeason_rule(M: 'TemoaModel', p, s): + """Rule to calculate the total fraction of a period represented by a season.""" + return sum(value(M.SegFrac[p, s, d]) for d in M.time_of_day if (p, s, d) in M.SegFrac) + + +def ParamPeriodLength(M: 'TemoaModel', p): + """Rule to calculate the length of each optimization period in years.""" + periods = sorted(M.time_future) + i = periods.index(p) + return periods[i + 1] - periods[i] + + +# ============================================================================ +# HELPER FUNCTIONS FOR TIME SEQUENCING +# ============================================================================ + + def loop_period_next_timeslice(M: 'TemoaModel', p, s, d) -> tuple[str, str]: # Final time slice of final season (end of period) # Loop state back to initial state of first season @@ -141,6 +233,11 @@ def loop_season_next_timeslice(M: 'TemoaModel', p, s, d) -> tuple[str, str]: return s_next, d_next +# ============================================================================ +# PRE-COMPUTATION & SEQUENCE CREATION +# ============================================================================ + + def CreateTimeSequence(M: 'TemoaModel'): logger.debug('Creating sequence of time slices.') @@ -291,74 +388,3 @@ def CreateTimeSeasonSequential(M: 'TemoaModel'): f', TimeSeasonSequential: {(p, s, segfracseq)}' ) logger.warning(msg) - - -def validate_SegFrac(M: 'TemoaModel'): - """Ensure that the segment fractions adds up to 1""" - - for p in M.time_optimize: - expected_keys = set((p, s, d) for s in M.TimeSeason[p] for d in M.time_of_day) - keys = set((_p, s, d) for _p, s, d in M.SegFrac.sparse_iterkeys() if _p == p) - - if expected_keys != keys: - extra = keys.difference(expected_keys) - missing = expected_keys.difference(keys) - msg = ( - 'TimeSegmentFraction elements for period {} do not match TimeSeason and TimeOfDay.' - '\n\nIndices missing from TimeSegmentFraction:\n{}' - '\n\nIndices in TimeSegmentFraction missing from TimeSeason/TimeOfDay:\n{}' - ).format(p, missing, extra) - logger.error(msg) - raise ValueError(msg) - - total = sum(M.SegFrac[k] for k in keys) - - if abs(float(total) - 1.0) > 0.001: - # We can't explicitly test for "!= 1.0" because of incremental rounding - # errors associated with the specification of SegFrac by time slice, - # but we check to make sure it is within the specified tolerance. - - def get_str_padding(obj): - return len(str(obj)) - - key_padding = max(map(get_str_padding, keys)) - - fmt = '%%-%ds = %%s' % key_padding - # Works out to something like "%-25s = %s" - - items = sorted([(k, M.SegFrac[k]) for k in keys]) - items = '\n '.join(fmt % (str(k), v) for k, v in items) - - msg = ( - 'The values of TimeSegmentFraction do not sum to 1 for period {}. ' - 'Each item in SegFrac represents a fraction of a year, so they must ' - 'total to 1. Current values:\n {}\n\tsum = {}' - ).format(p, items, total) - logger.error(msg) - raise Exception(msg) - - -def init_set_vintage_exist(M: 'TemoaModel'): - return sorted(M.time_exist) - - -def init_set_vintage_optimize(M: 'TemoaModel'): - return sorted(M.time_optimize) - - -def SegFracPerSeason_rule(M: 'TemoaModel', p, s): - return sum(value(M.SegFrac[p, s, S_d]) for S_d in M.time_of_day if (p, s, S_d) in M.SegFrac) - - -def ParamPeriodLength(M: 'TemoaModel', p): - # This specifically does not use time_optimize because this function is - # called /over/ time_optimize. - periods = sorted(M.time_future) - - i = periods.index(p) - - # The +1 won't fail, because this rule is called over time_optimize, which - # lacks the last period in time_future. - length = periods[i + 1] - periods[i] - - return length From 084077ee1fc5a5f7de2487bb163e88f75df1b92b Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 9 Oct 2025 17:16:40 -0400 Subject: [PATCH 237/587] cleaning up utils.py --- temoa/components/utils.py | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/temoa/components/utils.py b/temoa/components/utils.py index 727c38a46..205ed8d5b 100644 --- a/temoa/components/utils.py +++ b/temoa/components/utils.py @@ -1,3 +1,11 @@ +# temoa/components/utils.py +""" +This module contains generic, reusable utility functions for the Temoa model. + +These helpers are used by various components to perform common tasks like +building Pyomo expressions from strings or calculating time-variable efficiencies. +""" + from logging import getLogger from typing import TYPE_CHECKING @@ -44,11 +52,21 @@ def operator_expression(lhs: Expression | None, operator: str | None, rhs: Expre return expr -# To avoid building big many-indexed parameters when they aren't needed - saves memory -# Much faster to build a dictionary and check that than check the parameter -# indices directly every time - saves build time -def get_variable_efficiency(M: 'TemoaModel', r, p, s, d, i, t, v, o): - if M.isEfficiencyVariable[r, p, i, t, v, o]: +def get_variable_efficiency(M: 'TemoaModel', r, p, s, d, i, t, v, o) -> float: + """ + Calculates the effective efficiency for a process in a specific time slice. + + This function handles time-varying efficiencies. It checks a pre-computed boolean, + `M.isEfficiencyVariable`, to determine if a variable efficiency is defined for + the given process. + + - If True, it returns `Efficiency * EfficiencyVariable`. + - If False, it returns the base `Efficiency`. + + This dictionary-lookup approach is used for performance, as it is much faster + than repeatedly checking the indices of a large Pyomo parameter during model build. + """ + if M.isEfficiencyVariable.get((r, p, i, t, v, o), False): return value(M.Efficiency[r, i, t, v, o]) * value( M.EfficiencyVariable[r, p, s, d, i, t, v, o] ) From 8b8f663411b3a9d81512aa1eef767eea499a5773 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 10 Oct 2025 11:00:19 -0400 Subject: [PATCH 238/587] updated backwards compat temoa_model to not used temoa_rules or initialize --- temoa/temoa_model/temoa_model.py | 384 +++++++++++++++++++------------ 1 file changed, 234 insertions(+), 150 deletions(-) diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 498e28baa..0799aaca7 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -4,30 +4,18 @@ Tools for Energy Model Optimization and Analysis (Temoa): An open source framework for energy systems optimization modeling -Copyright (C) 2015, NC State University +SPDX-License-Identifier: MIT -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . """ import logging -from pyomo.core import BuildCheck +from pyomo.core import BuildCheck, Set, Var from pyomo.environ import ( AbstractModel, Any, BuildAction, + Constraint, Integers, NonNegativeReals, Objective, @@ -35,13 +23,24 @@ minimize, ) -from temoa._internal.temoa_initialize import * -from temoa._internal.temoa_rules import * +from temoa.components import ( + capacity, + commodities, + costs, + emissions, + flows, + geography, + limits, + operations, + reserves, + storage, + technology, + time, +) from temoa.model_checking.validators import ( no_slash_or_pipe, region_check, region_group_check, - # validate_CapacityFactorProcess, validate_0to1, validate_Efficiency, validate_linked_tech, @@ -51,8 +50,41 @@ logger = logging.getLogger(__name__) -# disable linter rule that complains about star imports for this file -# ruff: noqa: F405 + +def CreateSparseDicts(M: 'TemoaModel'): + """ + Creates and populates all sparse dictionaries and sets required for the model + by calling component-specific precomputation functions. + """ + # Initialize a set to track technologies used in the Efficiency table + M.used_techs = set() + + # Call the decomposed functions in logical order + # 1. Populate core relationships from Efficiency table + technology.populate_core_dictionaries(M) + + # 2. Classify technologies and commodities + commodities.create_technology_and_commodity_sets(M) + + # 3. Create sets for specific components + operations.create_operational_vintage_sets(M) # For operations, storage, ramping + limits.create_limit_vintage_sets(M) # For limits + geography.create_geography_sets(M) # For geography/exchange + capacity.create_capacity_and_retirement_sets(M) # For capacity + + # 4. Create final aggregated sets for constraints + flows.create_commodity_balance_and_flow_sets(M) # For flows and commodities + + # Final check for unused technologies + unused_techs = M.tech_all - M.used_techs + if unused_techs: + for tech in sorted(unused_techs): + logger.warning( + f"Notice: '{tech}' is specified as a technology but is not " + 'utilized in the Efficiency parameter.' + ) + + logger.debug('Completed creation of SparseDicts') class TemoaModel(AbstractModel): @@ -170,13 +202,15 @@ def __init__(M, *args, **kwargs): # Define time periods M.time_exist = Set(ordered=True) M.time_future = Set(ordered=True) - M.time_optimize = Set(ordered=True, initialize=init_set_time_optimize, within=M.time_future) + M.time_optimize = Set( + ordered=True, initialize=time.init_set_time_optimize, within=M.time_future + ) # Define time period vintages to track capacity installation - M.vintage_exist = Set(ordered=True, initialize=init_set_vintage_exist) - M.vintage_optimize = Set(ordered=True, initialize=init_set_vintage_optimize) + M.vintage_exist = Set(ordered=True, initialize=time.init_set_vintage_exist) + M.vintage_optimize = Set(ordered=True, initialize=time.init_set_vintage_optimize) M.vintage_all = Set(initialize=M.time_exist | M.time_optimize) # Perform some basic validation on the specified time periods. - M.validate_time = BuildAction(rule=validate_time) + M.validate_time = BuildAction(rule=time.validate_time) # Define the model time slices M.time_season = Set(ordered=True, validate=no_slash_or_pipe) @@ -184,7 +218,8 @@ def __init__(M, *args, **kwargs): M.TimeSeason = Set(M.time_optimize, within=M.time_season, ordered=True) M.time_of_day = Set(ordered=True, validate=no_slash_or_pipe) - # This is just to get the TimeStorageSeason table sequentially. There must be a better way but this works for now + # This is just to get the TimeStorageSeason table sequentially. + # There must be a better way but this works for now M.ordered_season_sequential = Set( dimen=3, within=M.time_optimize * M.time_season_sequential * M.time_season, ordered=True ) @@ -193,7 +228,7 @@ def __init__(M, *args, **kwargs): M.regions = Set(validate=region_check) # RegionalIndices is the set of all the possible combinations of interregional exchanges # plus original region indices. If tech_exchange is empty, RegionalIndices =regions. - M.regionalIndices = Set(initialize=CreateRegionalIndices) + M.regionalIndices = Set(initialize=geography.CreateRegionalIndices) M.regionalGlobalIndices = Set(validate=region_group_check) # Define technology-related sets @@ -229,7 +264,8 @@ def __init__(M, *args, **kwargs): M.tech_exist = Set() """techs with existing capacity, want to keep these for accounting reasons""" - # the below is a convenience for domain checking in params below that should not accept uncap techs... + # the below is a convenience for domain checking in params below that should not accept + # uncap techs... M.tech_with_capacity = Set(initialize=M.tech_all - M.tech_uncap) """techs eligible for capacitization""" # Define techs for which economic retirement is an option @@ -282,20 +318,22 @@ def __init__(M, *args, **kwargs): M.GlobalDiscountRate = Param(default=0.05) # Define time-related parameters - M.PeriodLength = Param(M.time_optimize, initialize=ParamPeriodLength) + M.PeriodLength = Param(M.time_optimize, initialize=time.ParamPeriodLength) M.SegFrac = Param(M.time_optimize, M.time_season, M.time_of_day) - M.validate_SegFrac = BuildAction(rule=validate_SegFrac) + M.validate_SegFrac = BuildAction(rule=time.validate_SegFrac) M.TimeSequencing = Set() # How do states carry between time segments? M.TimeNext = Set( ordered=True ) # This is just to get data from the table. Hidden feature and usually not used - M.validate_TimeNext = BuildAction(rule=validate_TimeNext) + M.validate_TimeNext = BuildAction(rule=time.validate_TimeNext) # Define demand- and resource-related parameters - # Dev Note: There does not appear to be a DB table supporting DemandDefaultDistro. This does not - # cause any problems, so let it be for now. + # Dev Note: There does not appear to be a DB table supporting DemandDefaultDistro. + # This does not cause any problems, so let it be for now. # Doesn't seem to be much point in the table. Just clones SegFrac - # M.DemandDefaultDistribution = Param(M.time_optimize, M.time_season, M.time_of_day, mutable=True) + # M.DemandDefaultDistribution = Param( + # M.time_optimize, M.time_season, M.time_of_day, mutable=True + # ) M.DemandSpecificDistribution = Param( M.regions, M.time_optimize, @@ -310,7 +348,8 @@ def __init__(M, *args, **kwargs): M.Demand = Param(M.DemandConstraint_rpc) # Dev Note: This parameter is currently NOT implemented. Preserved for later refactoring - # LimitResource IS implemented but sums cumulatively for a technology rather than resource commodity + # LimitResource IS implemented but sums cumulatively for a technology rather than + # resource commodity # M.ResourceConstraint_rpr = Set(within=M.regions * M.time_optimize * M.commodity_physical) # M.ResourceBound = Param(M.ResourceConstraint_rpr) @@ -319,7 +358,8 @@ def __init__(M, *args, **kwargs): M.ExistingCapacity = Param(M.regionalIndices, M.tech_exist, M.vintage_exist) - # Dev Note: The below is temporarily useful for passing down to validator to find set violations + # Dev Note: The below is temporarily useful for passing down to validator to find + # set violations # Uncomment this assignment, and comment out the orig below it... # M.Efficiency = Param( # Any, Any, Any, Any, Any, @@ -343,7 +383,7 @@ def __init__(M, *args, **kwargs): within=NonNegativeReals, validate=validate_Efficiency, ) - M.validate_UsedEfficiencyIndices = BuildAction(rule=CheckEfficiencyIndices) + M.validate_UsedEfficiencyIndices = BuildAction(rule=technology.CheckEfficiencyIndices) M.EfficiencyVariable = Param( M.regionalIndices, @@ -362,27 +402,30 @@ def __init__(M, *args, **kwargs): M.regionalIndices, M.tech_all, default=TemoaModel.default_lifetime_tech ) - M.LifetimeProcess_rtv = Set(dimen=3, initialize=LifetimeProcessIndices) - M.LifetimeProcess = Param(M.LifetimeProcess_rtv, default=get_default_process_lifetime) + M.LifetimeProcess_rtv = Set(dimen=3, initialize=technology.LifetimeProcessIndices) + M.LifetimeProcess = Param( + M.LifetimeProcess_rtv, default=technology.get_default_process_lifetime + ) M.LifetimeSurvivalCurve = Param( M.regionalIndices, Integers, M.tech_all, M.vintage_all, - default=get_default_survival, + default=technology.get_default_survival, validate=validate_0to1, mutable=True, ) - M.Create_SurvivalCurve = BuildAction(rule=CreateSurvivalCurve) + M.Create_SurvivalCurve = BuildAction(rule=technology.CreateSurvivalCurve) - M.LoanLifetimeProcess_rtv = Set(dimen=3, initialize=LifetimeLoanProcessIndices) + M.LoanLifetimeProcess_rtv = Set(dimen=3, initialize=costs.LifetimeLoanProcessIndices) - # Dev Note: The LoanLifetimeProcess table *could* be removed. There is no longer a supporting - # table in the database. It is just a "passthrough" now to the default LoanLifetimeTech. - # It is already stitched in to the model, so will leave it for now. Table may be revived. + # Dev Note: The LoanLifetimeProcess table *could* be removed. There is no longer a + # supporting table in the database. It is just a "passthrough" now to the + # default LoanLifetimeTech. It is already stitched in to the model, + # so will leave it for now. Table may be revived. - M.LoanLifetimeProcess = Param(M.LoanLifetimeProcess_rtv, default=get_loan_life) + M.LoanLifetimeProcess = Param(M.LoanLifetimeProcess_rtv, default=costs.get_loan_life) M.LimitTechInputSplit = Param( M.regions, @@ -431,20 +474,22 @@ def __init__(M, *args, **kwargs): # Set up representation of time M.DaysPerPeriod = Param() - M.SegFracPerSeason = Param(M.time_optimize, M.time_season, initialize=SegFracPerSeason_rule) + M.SegFracPerSeason = Param( + M.time_optimize, M.time_season, initialize=time.SegFracPerSeason_rule + ) M.TimeSeasonSequential = Param( M.time_optimize, M.time_season_sequential, M.time_season, mutable=True ) - M.validate_SeasonSequential = BuildAction(rule=CreateTimeSeasonSequential) - M.Create_TimeSequence = BuildAction(rule=CreateTimeSequence) + M.validate_SeasonSequential = BuildAction(rule=time.CreateTimeSeasonSequential) + M.Create_TimeSequence = BuildAction(rule=time.CreateTimeSequence) # The method below creates a series of helper functions that are used to # perform the sparse matrix of indexing for the parameters, variables, and # equations below. M.Create_SparseDicts = BuildAction(rule=CreateSparseDicts) - M.initialize_Demands = BuildAction(rule=CreateDemands) + M.initialize_Demands = BuildAction(rule=commodities.CreateDemands) - M.CapacityFactor_rpsdt = Set(dimen=5, initialize=CapacityFactorTechIndices) + M.CapacityFactor_rpsdt = Set(dimen=5, initialize=capacity.CapacityFactorTechIndices) M.CapacityFactorTech = Param(M.CapacityFactor_rpsdt, default=1, validate=validate_0to1) # Dev note: using a default function below alleviates need to make this set. @@ -458,27 +503,29 @@ def __init__(M, *args, **kwargs): M.vintage_all, # validate=validate_CapacityFactorProcess, # opting for a quicker validation, just 0->1 validate=validate_0to1, - default=get_default_capacity_factor, # surprisingly slow but only called if a value is missing + default=capacity.get_default_capacity_factor, # slow but only called if a value is missing ) - M.CapacityConstraint_rpsdtv = Set(dimen=6, initialize=CapacityConstraintIndices) - M.initialize_CapacityFactors = BuildAction(rule=CheckCapacityFactorProcess) - M.initialize_EfficiencyVariable = BuildAction(rule=CheckEfficiencyVariable) + M.CapacityConstraint_rpsdtv = Set(dimen=6, initialize=capacity.CapacityConstraintIndices) + M.initialize_CapacityFactors = BuildAction(rule=capacity.CheckCapacityFactorProcess) + M.initialize_EfficiencyVariable = BuildAction(rule=technology.CheckEfficiencyVariable) # Define technology cost parameters # dev note: the CostFixed_rptv isn't truly needed, but it is included in a constraint, so # let it go for now - M.CostFixed_rptv = Set(dimen=4, initialize=CostFixedIndices) + M.CostFixed_rptv = Set(dimen=4, initialize=costs.CostFixedIndices) M.CostFixed = Param(M.CostFixed_rptv) M.CostInvest_rtv = Set(within=M.regionalIndices * M.tech_all * M.time_optimize) M.CostInvest = Param(M.CostInvest_rtv) M.DefaultLoanRate = Param(domain=NonNegativeReals) - M.LoanRate = Param(M.CostInvest_rtv, domain=NonNegativeReals, default=get_default_loan_rate) - M.LoanAnnualize = Param(M.CostInvest_rtv, initialize=ParamLoanAnnualize_rule) + M.LoanRate = Param( + M.CostInvest_rtv, domain=NonNegativeReals, default=costs.get_default_loan_rate + ) + M.LoanAnnualize = Param(M.CostInvest_rtv, initialize=costs.ParamLoanAnnualize_rule) - M.CostVariable_rptv = Set(dimen=4, initialize=CostVariableIndices) + M.CostVariable_rptv = Set(dimen=4, initialize=costs.CostVariableIndices) M.CostVariable = Param(M.CostVariable_rptv) M.CostEmission_rpe = Set(within=M.regions * M.time_optimize * M.commodity_emissions) @@ -488,8 +535,10 @@ def __init__(M, *args, **kwargs): # 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) + M.ProcessLifeFrac_rptv = Set(dimen=4, initialize=technology.ModelProcessLifeIndices) + M.ProcessLifeFrac = Param( + M.ProcessLifeFrac_rptv, initialize=technology.ParamProcessLifeFraction_rule + ) M.LimitCapacityConstraint_rpt = Set( within=M.regionalGlobalIndices * M.time_optimize * M.tech_or_group * M.operator @@ -556,7 +605,7 @@ def __init__(M, *args, **kwargs): within=M.regionalGlobalIndices * M.time_optimize * M.commodity_emissions * M.operator ) M.LimitEmission = Param(M.LimitEmissionConstraint_rpe) - M.EmissionActivity_reitvo = Set(dimen=6, initialize=EmissionActivityIndices) + M.EmissionActivity_reitvo = Set(dimen=6, initialize=emissions.EmissionActivityIndices) M.EmissionActivity = Param(M.EmissionActivity_reitvo) # devnote: deprecated when generalising tech/group columns in Limit tables @@ -613,9 +662,9 @@ def __init__(M, *args, **kwargs): # M.LimitActivityGroupShare = Param(M.TwoGroupShareIndices) # This set works for all storage-related constraints - M.StorageConstraints_rpsdtv = Set(dimen=6, initialize=StorageConstraintIndices) + M.StorageConstraints_rpsdtv = Set(dimen=6, initialize=storage.StorageConstraintIndices) M.SeasonalStorageConstraints_rpsdtv = Set( - dimen=6, initialize=SeasonalStorageConstraintIndices + dimen=6, initialize=storage.SeasonalStorageConstraintIndices ) M.LimitStorageFractionConstraint_rpsdtv = Set( within=(M.StorageConstraints_rpsdtv | M.SeasonalStorageConstraints_rpsdtv) * M.operator @@ -676,46 +725,52 @@ def __init__(M, *args, **kwargs): M.progress_marker_3 = BuildAction(['Starting to build Variables'], rule=progress_check) # Define base decision variables - M.FlowVar_rpsditvo = Set(dimen=8, initialize=FlowVariableIndices) + M.FlowVar_rpsditvo = Set(dimen=8, initialize=flows.FlowVariableIndices) M.V_FlowOut = Var(M.FlowVar_rpsditvo, domain=NonNegativeReals) - M.FlowVarAnnual_rpitvo = Set(dimen=6, initialize=FlowVariableAnnualIndices) + M.FlowVarAnnual_rpitvo = Set(dimen=6, initialize=flows.FlowVariableAnnualIndices) M.V_FlowOutAnnual = Var(M.FlowVarAnnual_rpitvo, domain=NonNegativeReals) - M.FlexVar_rpsditvo = Set(dimen=8, initialize=FlexVariablelIndices) + M.FlexVar_rpsditvo = Set(dimen=8, initialize=flows.FlexVariablelIndices) M.V_Flex = Var(M.FlexVar_rpsditvo, domain=NonNegativeReals) - M.FlexVarAnnual_rpitvo = Set(dimen=6, initialize=FlexVariableAnnualIndices) + M.FlexVarAnnual_rpitvo = Set(dimen=6, initialize=flows.FlexVariableAnnualIndices) M.V_FlexAnnual = Var(M.FlexVarAnnual_rpitvo, domain=NonNegativeReals) - M.CurtailmentVar_rpsditvo = Set(dimen=8, initialize=CurtailmentVariableIndices) + M.CurtailmentVar_rpsditvo = Set(dimen=8, initialize=flows.CurtailmentVariableIndices) M.V_Curtailment = Var(M.CurtailmentVar_rpsditvo, domain=NonNegativeReals, initialize=0) - M.FlowInStorage_rpsditvo = Set(dimen=8, initialize=FlowInStorageVariableIndices) + M.FlowInStorage_rpsditvo = Set(dimen=8, initialize=flows.FlowInStorageVariableIndices) M.V_FlowIn = Var(M.FlowInStorage_rpsditvo, domain=NonNegativeReals) - M.StorageLevel_rpsdtv = Set(dimen=6, initialize=StorageLevelVariableIndices) + M.StorageLevel_rpsdtv = Set(dimen=6, initialize=storage.StorageLevelVariableIndices) M.V_StorageLevel = Var(M.StorageLevel_rpsdtv, domain=NonNegativeReals) - M.SeasonalStorageLevel_rpstv = Set(dimen=5, initialize=SeasonalStorageLevelVariableIndices) + M.SeasonalStorageLevel_rpstv = Set( + dimen=5, initialize=storage.SeasonalStorageLevelVariableIndices + ) M.V_SeasonalStorageLevel = Var(M.SeasonalStorageLevel_rpstv, domain=NonNegativeReals) # Derived decision variables - M.CapacityVar_rptv = Set(dimen=4, initialize=CostFixedIndices) + M.CapacityVar_rptv = Set(dimen=4, initialize=costs.CostFixedIndices) M.V_Capacity = Var(M.CapacityVar_rptv, domain=NonNegativeReals) - M.NewCapacityVar_rtv = Set(dimen=3, initialize=CapacityVariableIndices) + M.NewCapacityVar_rtv = Set(dimen=3, initialize=capacity.CapacityVariableIndices) M.V_NewCapacity = Var(M.NewCapacityVar_rtv, domain=NonNegativeReals, initialize=0) - M.RetiredCapacityVar_rptv = Set(dimen=4, initialize=RetiredCapacityVariableIndices) + M.RetiredCapacityVar_rptv = Set(dimen=4, initialize=capacity.RetiredCapacityVariableIndices) M.V_RetiredCapacity = Var(M.RetiredCapacityVar_rptv, domain=NonNegativeReals, initialize=0) - M.AnnualRetirementVar_rptv = Set(dimen=4, initialize=AnnualRetirementVariableIndices) + M.AnnualRetirementVar_rptv = Set( + dimen=4, initialize=capacity.AnnualRetirementVariableIndices + ) M.V_AnnualRetirement = Var( M.AnnualRetirementVar_rptv, domain=NonNegativeReals, initialize=0 ) - M.CapacityAvailableVar_rpt = Set(dimen=3, initialize=CapacityAvailableVariableIndices) + M.CapacityAvailableVar_rpt = Set( + dimen=3, initialize=capacity.CapacityAvailableVariableIndices + ) M.V_CapacityAvailableByPeriodAndTech = Var( M.CapacityAvailableVar_rpt, domain=NonNegativeReals, initialize=0 ) @@ -725,7 +780,7 @@ def __init__(M, *args, **kwargs): # (minimize total cost) # ################################################ - M.TotalCost = Objective(rule=TotalCost_rule, sense=minimize) + M.TotalCost = Objective(rule=costs.TotalCost_rule, sense=minimize) ################################################ # Constraints # @@ -742,15 +797,19 @@ def __init__(M, *args, **kwargs): M.progress_marker_4 = BuildAction(['Starting to build Constraints'], rule=progress_check) # Declare constraints to calculate derived decision variables - M.CapacityConstraint = Constraint(M.CapacityConstraint_rpsdtv, rule=Capacity_Constraint) + M.CapacityConstraint = Constraint( + M.CapacityConstraint_rpsdtv, rule=capacity.Capacity_Constraint + ) - M.CapacityAnnualConstraint_rptv = Set(dimen=4, initialize=CapacityAnnualConstraintIndices) + M.CapacityAnnualConstraint_rptv = Set( + dimen=4, initialize=capacity.CapacityAnnualConstraintIndices + ) M.CapacityAnnualConstraint = Constraint( - M.CapacityAnnualConstraint_rptv, rule=CapacityAnnual_Constraint + M.CapacityAnnualConstraint_rptv, rule=capacity.CapacityAnnual_Constraint ) M.CapacityAvailableByPeriodAndTechConstraint = Constraint( - M.CapacityAvailableVar_rpt, rule=CapacityAvailableByPeriodAndTech_Constraint + M.CapacityAvailableVar_rpt, rule=capacity.CapacityAvailableByPeriodAndTech_Constraint ) # devnote: I think this constraint is redundant @@ -761,41 +820,42 @@ def __init__(M, *args, **kwargs): ['Starting AnnualRetirementConstraint'], rule=progress_check ) M.AnnualRetirementConstraint = Constraint( - M.AnnualRetirementVar_rptv, rule=AnnualRetirement_Constraint + M.AnnualRetirementVar_rptv, rule=capacity.AnnualRetirement_Constraint ) M.progress_marker_4b = BuildAction( ['Starting AdjustedCapacityConstraint'], rule=progress_check ) M.AdjustedCapacityConstraint = Constraint( - M.CostFixed_rptv, rule=AdjustedCapacity_Constraint + M.CostFixed_rptv, rule=capacity.AdjustedCapacity_Constraint ) M.progress_marker_5 = BuildAction(['Finished Capacity Constraints'], rule=progress_check) # Declare core model constraints that ensure proper system functioning # In driving order, starting with the need to meet end-use demands - M.DemandConstraint = Constraint(M.DemandConstraint_rpc, rule=Demand_Constraint) + M.DemandConstraint = Constraint(M.DemandConstraint_rpc, rule=commodities.Demand_Constraint) # devnote: testing a workaround M.DemandActivityConstraint_rpsdtv_dem = Set( - dimen=7, initialize=DemandActivityConstraintIndices + dimen=7, initialize=commodities.DemandActivityConstraintIndices ) M.DemandActivityConstraint = Constraint( - M.DemandActivityConstraint_rpsdtv_dem, rule=DemandActivity_Constraint + M.DemandActivityConstraint_rpsdtv_dem, rule=commodities.DemandActivity_Constraint ) M.CommodityBalanceConstraint_rpsdc = Set( - dimen=5, initialize=CommodityBalanceConstraintIndices + dimen=5, initialize=commodities.CommodityBalanceConstraintIndices ) M.CommodityBalanceConstraint = Constraint( - M.CommodityBalanceConstraint_rpsdc, rule=CommodityBalance_Constraint + M.CommodityBalanceConstraint_rpsdc, rule=commodities.CommodityBalance_Constraint ) M.AnnualCommodityBalanceConstraint_rpc = Set( - dimen=3, initialize=AnnualCommodityBalanceConstraintIndices + dimen=3, initialize=commodities.AnnualCommodityBalanceConstraintIndices ) M.AnnualCommodityBalanceConstraint = Constraint( - M.AnnualCommodityBalanceConstraint_rpc, rule=AnnualCommodityBalance_Constraint + M.AnnualCommodityBalanceConstraint_rpc, + rule=commodities.AnnualCommodityBalance_Constraint, ) # M.ResourceExtractionConstraint = Constraint( @@ -803,126 +863,144 @@ def __init__(M, *args, **kwargs): # ) M.BaseloadDiurnalConstraint_rpsdtv = Set( - dimen=6, initialize=BaseloadDiurnalConstraintIndices + dimen=6, initialize=operations.BaseloadDiurnalConstraintIndices ) M.BaseloadDiurnalConstraint = Constraint( - M.BaseloadDiurnalConstraint_rpsdtv, rule=BaseloadDiurnal_Constraint + M.BaseloadDiurnalConstraint_rpsdtv, rule=operations.BaseloadDiurnal_Constraint ) M.RegionalExchangeCapacityConstraint_rrptv = Set( - dimen=5, initialize=RegionalExchangeCapacityConstraintIndices + dimen=5, initialize=capacity.RegionalExchangeCapacityConstraintIndices ) M.RegionalExchangeCapacityConstraint = Constraint( - M.RegionalExchangeCapacityConstraint_rrptv, rule=RegionalExchangeCapacity_Constraint + M.RegionalExchangeCapacityConstraint_rrptv, + rule=geography.RegionalExchangeCapacity_Constraint, ) M.progress_marker_6 = BuildAction(['Starting Storage Constraints'], rule=progress_check) M.StorageEnergyConstraint = Constraint( - M.StorageConstraints_rpsdtv, rule=StorageEnergy_Constraint + M.StorageConstraints_rpsdtv, rule=storage.StorageEnergy_Constraint ) M.StorageEnergyUpperBoundConstraint = Constraint( - M.StorageConstraints_rpsdtv, rule=StorageEnergyUpperBound_Constraint + M.StorageConstraints_rpsdtv, rule=storage.StorageEnergyUpperBound_Constraint ) M.SeasonalStorageEnergyConstraint = Constraint( - M.SeasonalStorageLevel_rpstv, rule=SeasonalStorageEnergy_Constraint + M.SeasonalStorageLevel_rpstv, rule=storage.SeasonalStorageEnergy_Constraint ) M.SeasonalStorageEnergyUpperBoundConstraint = Constraint( - M.SeasonalStorageConstraints_rpsdtv, rule=SeasonalStorageEnergyUpperBound_Constraint + M.SeasonalStorageConstraints_rpsdtv, + rule=storage.SeasonalStorageEnergyUpperBound_Constraint, ) M.StorageChargeRateConstraint = Constraint( - M.StorageConstraints_rpsdtv, rule=StorageChargeRate_Constraint + M.StorageConstraints_rpsdtv, rule=storage.StorageChargeRate_Constraint ) M.StorageDischargeRateConstraint = Constraint( - M.StorageConstraints_rpsdtv, rule=StorageDischargeRate_Constraint + M.StorageConstraints_rpsdtv, rule=storage.StorageDischargeRate_Constraint ) M.StorageThroughputConstraint = Constraint( - M.StorageConstraints_rpsdtv, rule=StorageThroughput_Constraint + M.StorageConstraints_rpsdtv, rule=storage.StorageThroughput_Constraint ) M.LimitStorageFractionConstraint = Constraint( - M.LimitStorageFractionConstraint_rpsdtv, rule=LimitStorageFraction_Constraint + M.LimitStorageFractionConstraint_rpsdtv, rule=storage.LimitStorageFraction_Constraint ) - M.RampUpDayConstraint_rpsdtv = Set(dimen=6, initialize=RampUpDayConstraintIndices) - M.RampUpDayConstraint = Constraint(M.RampUpDayConstraint_rpsdtv, rule=RampUpDay_Constraint) - M.RampDownDayConstraint_rpsdtv = Set(dimen=6, initialize=RampDownDayConstraintIndices) + M.RampUpDayConstraint_rpsdtv = Set( + dimen=6, initialize=operations.RampUpDayConstraintIndices + ) + M.RampUpDayConstraint = Constraint( + M.RampUpDayConstraint_rpsdtv, rule=operations.RampUpDay_Constraint + ) + M.RampDownDayConstraint_rpsdtv = Set( + dimen=6, initialize=operations.RampDownDayConstraintIndices + ) M.RampDownDayConstraint = Constraint( - M.RampDownDayConstraint_rpsdtv, rule=RampDownDay_Constraint + M.RampDownDayConstraint_rpsdtv, rule=operations.RampDownDay_Constraint ) - M.RampUpSeasonConstraint_rpsstv = Set(dimen=6, initialize=RampUpSeasonConstraintIndices) + M.RampUpSeasonConstraint_rpsstv = Set( + dimen=6, initialize=operations.RampUpSeasonConstraintIndices + ) M.RampUpSeasonConstraint = Constraint( - M.RampUpSeasonConstraint_rpsstv, rule=RampUpSeason_Constraint + M.RampUpSeasonConstraint_rpsstv, rule=operations.RampUpSeason_Constraint + ) + M.RampDownSeasonConstraint_rpsstv = Set( + dimen=6, initialize=operations.RampDownSeasonConstraintIndices ) - M.RampDownSeasonConstraint_rpsstv = Set(dimen=6, initialize=RampDownSeasonConstraintIndices) M.RampDownSeasonConstraint = Constraint( - M.RampDownSeasonConstraint_rpsstv, rule=RampDownSeason_Constraint + M.RampDownSeasonConstraint_rpsstv, rule=operations.RampDownSeason_Constraint ) - M.ReserveMargin_rpsd = Set(dimen=4, initialize=ReserveMarginIndices) + M.ReserveMargin_rpsd = Set(dimen=4, initialize=reserves.ReserveMarginIndices) M.validate_ReserveMargin = BuildAction(rule=validate_ReserveMargin) - M.ReserveMarginConstraint = Constraint(M.ReserveMargin_rpsd, rule=ReserveMargin_Constraint) + M.ReserveMarginConstraint = Constraint( + M.ReserveMargin_rpsd, rule=reserves.ReserveMargin_Constraint + ) M.LimitEmissionConstraint = Constraint( - M.LimitEmissionConstraint_rpe, rule=LimitEmission_Constraint + M.LimitEmissionConstraint_rpe, rule=limits.LimitEmission_Constraint ) M.progress_marker_7 = BuildAction( ['Starting LimitGrowth and Activity Constraints'], rule=progress_check ) - M.LimitGrowthCapacityConstraint_rpt = Set(dimen=4, initialize=LimitGrowthCapacityIndices) + M.LimitGrowthCapacityConstraint_rpt = Set( + dimen=4, initialize=limits.LimitGrowthCapacityIndices + ) M.LimitGrowthCapacityConstraint = Constraint( - M.LimitGrowthCapacityConstraint_rpt, rule=LimitGrowthCapacityConstraint_rule + M.LimitGrowthCapacityConstraint_rpt, rule=limits.LimitGrowthCapacityConstraint_rule ) M.LimitDegrowthCapacityConstraint_rpt = Set( - dimen=4, initialize=LimitDegrowthCapacityIndices + dimen=4, initialize=limits.LimitDegrowthCapacityIndices ) M.LimitDegrowthCapacityConstraint = Constraint( - M.LimitDegrowthCapacityConstraint_rpt, rule=LimitDegrowthCapacityConstraint_rule + M.LimitDegrowthCapacityConstraint_rpt, rule=limits.LimitDegrowthCapacityConstraint_rule ) M.LimitGrowthNewCapacityConstraint_rpt = Set( - dimen=4, initialize=LimitGrowthNewCapacityIndices + dimen=4, initialize=limits.LimitGrowthNewCapacityIndices ) M.LimitGrowthNewCapacityConstraint = Constraint( - M.LimitGrowthNewCapacityConstraint_rpt, rule=LimitGrowthNewCapacityConstraint_rule + M.LimitGrowthNewCapacityConstraint_rpt, + rule=limits.LimitGrowthNewCapacityConstraint_rule, ) M.LimitDegrowthNewCapacityConstraint_rpt = Set( - dimen=4, initialize=LimitDegrowthNewCapacityIndices + dimen=4, initialize=limits.LimitDegrowthNewCapacityIndices ) M.LimitDegrowthNewCapacityConstraint = Constraint( - M.LimitDegrowthNewCapacityConstraint_rpt, rule=LimitDegrowthNewCapacityConstraint_rule + M.LimitDegrowthNewCapacityConstraint_rpt, + rule=limits.LimitDegrowthNewCapacityConstraint_rule, ) M.LimitGrowthNewCapacityDeltaConstraint_rpt = Set( - dimen=4, initialize=LimitGrowthNewCapacityDeltaIndices + dimen=4, initialize=limits.LimitGrowthNewCapacityDeltaIndices ) M.LimitGrowthNewCapacityDeltaConstraint = Constraint( M.LimitGrowthNewCapacityDeltaConstraint_rpt, - rule=LimitGrowthNewCapacityDeltaConstraint_rule, + rule=limits.LimitGrowthNewCapacityDeltaConstraint_rule, ) M.LimitDegrowthNewCapacityDeltaConstraint_rpt = Set( - dimen=4, initialize=LimitDegrowthNewCapacityDeltaIndices + dimen=4, initialize=limits.LimitDegrowthNewCapacityDeltaIndices ) M.LimitDegrowthNewCapacityDeltaConstraint = Constraint( M.LimitDegrowthNewCapacityDeltaConstraint_rpt, - rule=LimitDegrowthNewCapacityDeltaConstraint_rule, + rule=limits.LimitDegrowthNewCapacityDeltaConstraint_rule, ) M.LimitActivityConstraint = Constraint( - M.LimitActivityConstraint_rpt, rule=LimitActivity_Constraint + M.LimitActivityConstraint_rpt, rule=limits.LimitActivity_Constraint ) M.LimitSeasonalCapacityFactorConstraint = Constraint( M.LimitSeasonalCapacityFactorConstraint_rpst, - rule=LimitSeasonalCapacityFactor_Constraint, + rule=limits.LimitSeasonalCapacityFactor_Constraint, ) # devnote: deprecated when generalising tech/group columns in Limit tables @@ -931,11 +1009,11 @@ def __init__(M, *args, **kwargs): # ) M.LimitCapacityConstraint = Constraint( - M.LimitCapacityConstraint_rpt, rule=LimitCapacity_Constraint + M.LimitCapacityConstraint_rpt, rule=limits.LimitCapacity_Constraint ) M.LimitNewCapacityConstraint = Constraint( - M.LimitNewCapacityConstraint_rpt, rule=LimitNewCapacity_Constraint + M.LimitNewCapacityConstraint_rpt, rule=limits.LimitNewCapacity_Constraint ) # devnote: deprecated when generalising tech/group columns in Limit tables @@ -948,20 +1026,21 @@ def __init__(M, *args, **kwargs): # ) M.LimitCapacityShareConstraint = Constraint( - M.LimitCapacityShareConstraint_rpgg, rule=LimitCapacityShare_Constraint + M.LimitCapacityShareConstraint_rpgg, rule=limits.LimitCapacityShare_Constraint ) M.LimitActivityShareConstraint = Constraint( - M.LimitActivityShareConstraint_rpgg, rule=LimitActivityShare_Constraint + M.LimitActivityShareConstraint_rpgg, rule=limits.LimitActivityShare_Constraint ) M.LimitNewCapacityShareConstraint = Constraint( - M.LimitNewCapacityShareConstraint_rpgg, rule=LimitNewCapacityShare_Constraint + M.LimitNewCapacityShareConstraint_rpgg, rule=limits.LimitNewCapacityShare_Constraint ) # devnote: deprecated when generalising tech/group columns in Limit tables # M.LimitNewCapacityGroupShareConstraint = Constraint( - # M.LimitNewCapacityGroupShareConstraint_rpgg, rule=LimitNewCapacityGroupShare_Constraint + # M.LimitNewCapacityGroupShareConstraint_rpgg, + # rule=LimitNewCapacityGroupShare_Constraint # ) # M.LimitActivityGroupShareConstraint = Constraint( @@ -973,70 +1052,75 @@ def __init__(M, *args, **kwargs): ) M.LimitResourceConstraint = Constraint( - M.LimitResourceConstraint_rt, rule=LimitResource_Constraint + M.LimitResourceConstraint_rt, rule=limits.LimitResource_Constraint ) M.LimitAnnualCapacityFactorConstraint = Constraint( - M.LimitAnnualCapacityFactorConstraint_rpto, rule=LimitAnnualCapacityFactor_Constraint + M.LimitAnnualCapacityFactorConstraint_rpto, + rule=limits.LimitAnnualCapacityFactor_Constraint, ) ## Tech input splits M.LimitTechInputSplitConstraint_rpsditv = Set( - dimen=8, initialize=LimitTechInputSplitConstraintIndices + dimen=8, initialize=limits.LimitTechInputSplitConstraintIndices ) M.LimitTechInputSplitConstraint = Constraint( - M.LimitTechInputSplitConstraint_rpsditv, rule=LimitTechInputSplit_Constraint + M.LimitTechInputSplitConstraint_rpsditv, rule=limits.LimitTechInputSplit_Constraint ) M.LimitTechInputSplitAnnualConstraint_rpitv = Set( - dimen=6, initialize=LimitTechInputSplitAnnualConstraintIndices + dimen=6, initialize=limits.LimitTechInputSplitAnnualConstraintIndices ) M.LimitTechInputSplitAnnualConstraint = Constraint( - M.LimitTechInputSplitAnnualConstraint_rpitv, rule=LimitTechInputSplitAnnual_Constraint + M.LimitTechInputSplitAnnualConstraint_rpitv, + rule=limits.LimitTechInputSplitAnnual_Constraint, ) M.LimitTechInputSplitAverageConstraint_rpitv = Set( - dimen=6, initialize=LimitTechInputSplitAverageConstraintIndices + dimen=6, initialize=limits.LimitTechInputSplitAverageConstraintIndices ) M.LimitTechInputSplitAverageConstraint = Constraint( - M.LimitTechInputSplitAverageConstraint_rpitv, rule=LimitTechInputSplitAverage_Constraint + M.LimitTechInputSplitAverageConstraint_rpitv, + rule=limits.LimitTechInputSplitAverage_Constraint, ) ## Tech output splits M.LimitTechOutputSplitConstraint_rpsdtvo = Set( - dimen=8, initialize=LimitTechOutputSplitConstraintIndices + dimen=8, initialize=limits.LimitTechOutputSplitConstraintIndices ) M.LimitTechOutputSplitConstraint = Constraint( - M.LimitTechOutputSplitConstraint_rpsdtvo, rule=LimitTechOutputSplit_Constraint + M.LimitTechOutputSplitConstraint_rpsdtvo, rule=limits.LimitTechOutputSplit_Constraint ) M.LimitTechOutputSplitAnnualConstraint_rptvo = Set( - dimen=6, initialize=LimitTechOutputSplitAnnualConstraintIndices + dimen=6, initialize=limits.LimitTechOutputSplitAnnualConstraintIndices ) M.LimitTechOutputSplitAnnualConstraint = Constraint( - M.LimitTechOutputSplitAnnualConstraint_rptvo, rule=LimitTechOutputSplitAnnual_Constraint + M.LimitTechOutputSplitAnnualConstraint_rptvo, + rule=limits.LimitTechOutputSplitAnnual_Constraint, ) M.LimitTechOutputSplitAverageConstraint_rptvo = Set( - dimen=6, initialize=LimitTechOutputSplitAverageConstraintIndices + dimen=6, initialize=limits.LimitTechOutputSplitAverageConstraintIndices ) M.LimitTechOutputSplitAverageConstraint = Constraint( M.LimitTechOutputSplitAverageConstraint_rptvo, - rule=LimitTechOutputSplitAverage_Constraint, + rule=limits.LimitTechOutputSplitAverage_Constraint, ) M.RenewablePortfolioStandardConstraint = Constraint( - M.RenewablePortfolioStandardConstraint_rpg, rule=RenewablePortfolioStandard_Constraint + M.RenewablePortfolioStandardConstraint_rpg, + rule=limits.RenewablePortfolioStandard_Constraint, ) M.LinkedEmissionsTechConstraint_rpsdtve = Set( - dimen=7, initialize=LinkedTechConstraintIndices + dimen=7, initialize=emissions.LinkedTechConstraintIndices ) # the validation requires that the set above be built first: M.validate_LinkedTech_lifetimes = BuildCheck(rule=validate_linked_tech) M.LinkedEmissionsTechConstraint = Constraint( - M.LinkedEmissionsTechConstraint_rpsdtve, rule=LinkedEmissionsTech_Constraint + M.LinkedEmissionsTechConstraint_rpsdtve, rule=emissions.LinkedEmissionsTech_Constraint ) M.progress_marker_9 = BuildAction(['Finished Constraints'], rule=progress_check) From ce637133acc568c3d7f240528da9354a1d251143 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 10 Oct 2025 11:58:46 -0400 Subject: [PATCH 239/587] fixed tuple missing period index bug in deprecated CreateCapacityFactors --- temoa/components/capacity.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/temoa/components/capacity.py b/temoa/components/capacity.py index 0c6486367..3258eb14b 100644 --- a/temoa/components/capacity.py +++ b/temoa/components/capacity.py @@ -99,8 +99,8 @@ def CreateCapacityFactors(M: 'TemoaModel'): if unspecified_cfs: # CFP._constructed = False - for r, s, d, t, v in unspecified_cfs: - CFP[r, s, d, t, v] = M.CapacityFactorTech[r, s, d, t] + for r, p, s, d, t, v in unspecified_cfs: + CFP[r, p, s, d, t, v] = M.CapacityFactorTech[r, p, s, d, t] logger.debug( 'Created Capacity Factors for %d processes without an explicit specification', len(unspecified_cfs), From 71933dbf419686ec73871be09afb2a1004f4e370 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 10 Oct 2025 12:42:25 -0400 Subject: [PATCH 240/587] using enums for operator expression for simpler and more robust function --- temoa/components/limits.py | 52 ++++++++++++++++++++----------------- temoa/components/storage.py | 4 +-- temoa/components/utils.py | 45 +++++++++++--------------------- 3 files changed, 45 insertions(+), 56 deletions(-) diff --git a/temoa/components/limits.py b/temoa/components/limits.py index 860a188ca..24730bef5 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -18,7 +18,7 @@ import temoa.components.geography as geography import temoa.components.technology as technology -from temoa.components.utils import get_variable_efficiency, operator_expression +from temoa.components.utils import Operator, get_variable_efficiency, operator_expression if TYPE_CHECKING: from temoa.core.model import TemoaModel @@ -259,7 +259,7 @@ def LimitResource_Constraint(M: 'TemoaModel', r, t, op): ) resource_lim = value(M.LimitResource[r, t, op]) - expr = operator_expression(activity, op, resource_lim) + expr = operator_expression(activity, Operator(op), resource_lim) return expr @@ -326,7 +326,7 @@ def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): ) share_lim = value(M.LimitActivityShare[r, p, g1, g2, op]) - expr = operator_expression(sub_activity, op, share_lim * super_activity) + expr = operator_expression(sub_activity, Operator(op), share_lim * super_activity) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated return Constraint.Skip @@ -366,7 +366,7 @@ def LimitCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): ) share_lim = value(M.LimitCapacityShare[r, p, g1, g2, op]) - expr = operator_expression(sub_capacity, op, share_lim * super_capacity) + expr = operator_expression(sub_capacity, Operator(op), share_lim * super_capacity) if isinstance(expr, bool): return Constraint.Skip return expr @@ -397,7 +397,7 @@ def LimitNewCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): ) share_lim = value(M.LimitNewCapacityShare[r, p, g1, g2, op]) - expr = operator_expression(sub_new_cap, op, share_lim * super_new_cap) + expr = operator_expression(sub_new_cap, Operator(op), share_lim * super_new_cap) if isinstance(expr, bool): return Constraint.Skip return expr @@ -452,7 +452,7 @@ def LimitAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o, op): for _r in regions ) annual_cf = value(M.LimitAnnualCapacityFactor[r, p, t, o, op]) - expr = operator_expression(activity_rpt, op, annual_cf * possible_activity_rpt) + expr = operator_expression(activity_rpt, Operator(op), annual_cf * possible_activity_rpt) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated return Constraint.Skip @@ -511,7 +511,7 @@ def LimitSeasonalCapacityFactor_Constraint(M: 'TemoaModel', r, p, s, t, op): for _r in regions ) seasonal_cf = value(M.LimitSeasonalCapacityFactor[r, p, s, t, op]) - expr = operator_expression(activity_rpst, op, seasonal_cf * possible_activity_rpst) + expr = operator_expression(activity_rpst, Operator(op), seasonal_cf * possible_activity_rpst) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated return Constraint.Skip @@ -537,7 +537,9 @@ def LimitTechInputSplit_Constraint(M: 'TemoaModel', r, p, s, d, i, t, v, op): for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - expr = operator_expression(inp, op, value(M.LimitTechInputSplit[r, p, i, t, op]) * total_inp) + expr = operator_expression( + inp, Operator(op), value(M.LimitTechInputSplit[r, p, i, t, op]) * total_inp + ) return expr @@ -560,12 +562,12 @@ def LimitTechInputSplitAnnual_Constraint(M: 'TemoaModel', r, p, i, t, v, op): ) expr = operator_expression( - inp, op, value(M.LimitTechInputSplitAnnual[r, p, i, t, op]) * total_inp + inp, Operator(op), value(M.LimitTechInputSplitAnnual[r, p, i, t, op]) * total_inp ) return expr -def LimitTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v, op): +def LimitTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v, op: str): r""" Allows users to limit shares of commodity inputs to a process producing a single output. Under this constraint, only the technologies with variable @@ -592,7 +594,7 @@ def LimitTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v, op): ) expr = operator_expression( - inp, op, value(M.LimitTechInputSplitAnnual[r, p, i, t, op]) * total_inp + inp, Operator(op), value(M.LimitTechInputSplitAnnual[r, p, i, t, op]) * total_inp ) return expr @@ -642,7 +644,9 @@ def LimitTechOutputSplit_Constraint(M: 'TemoaModel', r, p, s, d, t, v, o, op): for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - expr = operator_expression(out, op, value(M.LimitTechOutputSplit[r, p, t, o, op]) * total_out) + expr = operator_expression( + out, Operator(op), value(M.LimitTechOutputSplit[r, p, t, o, op]) * total_out + ) return expr @@ -671,7 +675,7 @@ def LimitTechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o, op): ) expr = operator_expression( - out, op, value(M.LimitTechOutputSplitAnnual[r, p, t, o, op]) * total_out + out, Operator(op), value(M.LimitTechOutputSplitAnnual[r, p, t, o, op]) * total_out ) return expr @@ -701,7 +705,7 @@ def LimitTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o, op): ) expr = operator_expression( - out, op, value(M.LimitTechOutputSplitAnnual[r, p, t, o, op]) * total_out + out, Operator(op), value(M.LimitTechOutputSplitAnnual[r, p, t, o, op]) * total_out ) return expr @@ -793,7 +797,7 @@ def LimitEmission_Constraint(M: 'TemoaModel', r, p, e, op): # + emissions_curtail # NO! curtailed flows are not actual flows, just an accounting tool # + emissions_flex_annual # NO! flexannual is subtracted from flowoutannual, already accounted ) - expr = operator_expression(lhs, op, emission_limit) + expr = operator_expression(lhs, Operator(op), emission_limit) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated @@ -905,9 +909,9 @@ def LimitGrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): capacity_prev = sum(CapRPT[_r, _p, _t] for _r, _p, _t in cap_rpt if _p == p_prev) if degrowth: - expr = operator_expression(capacity_prev, op, SEED + capacity * RATE) + expr = operator_expression(capacity_prev, Operator(op), SEED + capacity * RATE) else: - expr = operator_expression(capacity, op, SEED + capacity_prev * RATE) + expr = operator_expression(capacity, Operator(op), SEED + capacity_prev * RATE) # Check if any variables are actually included before returning if isinstance(expr, bool): @@ -1014,9 +1018,9 @@ def LimitGrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False) new_cap_prev = sum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p_prev) if degrowth: - expr = operator_expression(new_cap_prev, op, SEED + new_cap * RATE) + expr = operator_expression(new_cap_prev, Operator(op), SEED + new_cap * RATE) else: - expr = operator_expression(new_cap, op, SEED + new_cap_prev * RATE) + expr = operator_expression(new_cap, Operator(op), SEED + new_cap_prev * RATE) # Check if any variables are actually included before returning if isinstance(expr, bool): @@ -1148,9 +1152,9 @@ def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = F nc_delta = new_cap - new_cap_prev if degrowth: - expr = operator_expression(nc_delta_prev, op, SEED + nc_delta * RATE) + expr = operator_expression(nc_delta_prev, Operator(op), SEED + nc_delta * RATE) else: - expr = operator_expression(nc_delta, op, SEED + nc_delta_prev * RATE) + expr = operator_expression(nc_delta, Operator(op), SEED + nc_delta_prev * RATE) # Check if any variables are actually included before returning if isinstance(expr, bool): @@ -1209,7 +1213,7 @@ def LimitActivity_Constraint(M: 'TemoaModel', r, p, t, op): ) act_lim = value(M.LimitActivity[r, p, t, op]) - expr = operator_expression(activity, op, act_lim) + expr = operator_expression(activity, Operator(op), act_lim) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated return Constraint.Skip @@ -1233,7 +1237,7 @@ def LimitNewCapacity_Constraint(M: 'TemoaModel', r, p, t, op): techs = technology.gather_group_techs(M, t) cap_lim = value(M.LimitNewCapacity[r, p, t, op]) new_cap = sum(M.V_NewCapacity[_r, _t, p] for _t in techs for _r in regions) - expr = operator_expression(new_cap, op, cap_lim) + expr = operator_expression(new_cap, Operator(op), cap_lim) return expr @@ -1256,7 +1260,7 @@ def LimitCapacity_Constraint(M: 'TemoaModel', r, p, t, op): capacity = sum( M.V_CapacityAvailableByPeriodAndTech[_r, p, _t] for _t in techs for _r in regions ) - expr = operator_expression(capacity, op, cap_lim) + expr = operator_expression(capacity, Operator(op), cap_lim) return expr diff --git a/temoa/components/storage.py b/temoa/components/storage.py index 9e9591d69..4efff8174 100644 --- a/temoa/components/storage.py +++ b/temoa/components/storage.py @@ -15,7 +15,7 @@ from pyomo.environ import Constraint, value -from .utils import get_variable_efficiency, operator_expression +from .utils import Operator, get_variable_efficiency, operator_expression if TYPE_CHECKING: from temoa.core.model import TemoaModel @@ -487,6 +487,6 @@ def LimitStorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v, op): M.TimeSeasonSequential[p, s_seq, s] ) - expr = operator_expression(energy_level, op, energy_limit) + expr = operator_expression(energy_level, Operator(op), energy_limit) return expr diff --git a/temoa/components/utils.py b/temoa/components/utils.py index 205ed8d5b..161f07004 100644 --- a/temoa/components/utils.py +++ b/temoa/components/utils.py @@ -6,6 +6,7 @@ building Pyomo expressions from strings or calculating time-variable efficiencies. """ +from enum import Enum from logging import getLogger from typing import TYPE_CHECKING @@ -19,37 +20,21 @@ logger = getLogger(__name__) -def operator_expression(lhs: Expression | None, operator: str | None, rhs: Expression | None): - """Returns an expression, applying a configured operator""" - if any((lhs is None, operator is None, rhs is None)): - msg = ('Tried to build a constraint using a bad expression or operator: {} {} {}').format( - lhs, operator, rhs - ) - logger.error(msg) - raise ValueError(msg) - try: - match operator: - case 'e': - expr = lhs == rhs - case 'le': - expr = lhs <= rhs - case 'ge': - expr = lhs >= rhs - case _: - msg = ( - 'Tried to build a constraint using a bad operator. Allowed operators are "e","le", or "ge". Got "{}": {} {} {}' - ).format(operator, lhs, operator, rhs) - logger.error(msg) - raise ValueError(msg) - except Exception as e: - print(e) - msg = ('Tried to build a constraint using a bad expression or operator: {} {} {}').format( - lhs, operator, rhs - ) - logger.error(msg) - raise ValueError(msg) from e +class Operator(str, Enum): + EQUAL = 'e' + LESS_EQUAL = 'le' + GREATER_EQUAL = 'ge' + - return expr +def operator_expression(lhs: Expression, operator: Operator, rhs: Expression): + match operator: + case Operator.EQUAL: + return lhs == rhs + case Operator.LESS_EQUAL: + return lhs <= rhs + case Operator.GREATER_EQUAL: + return lhs >= rhs + raise ValueError(f'Invalid operator: {operator!r}') def get_variable_efficiency(M: 'TemoaModel', r, p, s, d, i, t, v, o) -> float: From a655e1e3b3e0c28d97d5b6d3ba25ebc5f4fcaf2a Mon Sep 17 00:00:00 2001 From: Anil Radhakrishnan Date: Tue, 14 Oct 2025 11:23:59 -0400 Subject: [PATCH 241/587] Refactoring hybrid loader to use declarative manifest (#164) --- temoa/__init__.py | 2 +- temoa/_internal/hybrid_loader.py | 1264 ----------------- temoa/_internal/temoa_sequencer.py | 2 +- temoa/data_io/README.md | 115 ++ temoa/data_io/component_manifest.py | 702 +++++++++ temoa/data_io/hybrid_loader.py | 827 +++++++++++ temoa/data_io/loader_manifest.py | 52 + temoa/extensions/method_of_morris/morris.py | 2 +- .../method_of_morris/morris_sequencer.py | 2 +- .../mga_sequencer.py | 2 +- temoa/extensions/monte_carlo/mc_run.py | 2 +- temoa/extensions/monte_carlo/mc_sequencer.py | 2 +- temoa/extensions/myopic/myopic_sequencer.py | 2 +- .../single_vector_mga/sv_mga_sequencer.py | 2 +- 14 files changed, 1705 insertions(+), 1273 deletions(-) delete mode 100644 temoa/_internal/hybrid_loader.py create mode 100644 temoa/data_io/README.md create mode 100644 temoa/data_io/component_manifest.py create mode 100644 temoa/data_io/hybrid_loader.py create mode 100644 temoa/data_io/loader_manifest.py diff --git a/temoa/__init__.py b/temoa/__init__.py index 3ff349b73..1c54ccc0b 100644 --- a/temoa/__init__.py +++ b/temoa/__init__.py @@ -10,7 +10,6 @@ # Internal modules - for backward compatibility from temoa._internal.data_brick import DataBrick, data_brick_factory from temoa._internal.exchange_tech_cost_ledger import CostType, ExchangeTechCostLedger -from temoa._internal.hybrid_loader import HybridLoader from temoa._internal.run_actions import ( build_instance, handle_results, @@ -29,6 +28,7 @@ from temoa.core.config import TemoaConfig from temoa.core.model import TemoaModel from temoa.core.modes import TemoaMode +from temoa.data_io.hybrid_loader import HybridLoader # Version information from temoa.version_information import TEMOA_MAJOR, TEMOA_MINOR diff --git a/temoa/_internal/hybrid_loader.py b/temoa/_internal/hybrid_loader.py deleted file mode 100644 index effce1368..000000000 --- a/temoa/_internal/hybrid_loader.py +++ /dev/null @@ -1,1264 +0,0 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 1/21/24 - -A module to build/load a Data Portal for myopic run using both SQL to pull data -and python to filter results - -""" - -import sys -import time -from collections import defaultdict -from logging import getLogger -from sqlite3 import Connection, Cursor, OperationalError -from typing import Sequence - -from pyomo.core import Param, Set -from pyomo.dataportal import DataPortal - -from temoa.core.config import TemoaConfig -from temoa.core.model import TemoaModel -from temoa.core.modes import TemoaMode -from temoa.extensions.myopic.myopic_index import MyopicIndex -from temoa.model_checking import element_checker, network_model_data -from temoa.model_checking.commodity_network_manager import CommodityNetworkManager -from temoa.model_checking.element_checker import ViableSet - -logger = getLogger(__name__) - -# the tables below are ones in which we might find regional groups which should be captured -# to make the members of the RegionalGlobalIndices Set in the model. They need to aggregated -tables_with_regional_groups = { - 'LimitAnnualCapacityFactor': 'region', - 'LimitEmission': 'region', - 'LimitSeasonalCapacityFactor': 'region', - 'LimitCapacity': 'region', - 'LimitActivity': 'region', - 'LimitNewCapacity': 'region', - 'LimitActivityShare': 'region', - 'LimitCapacityShare': 'region', - 'LimitNewCapacityShare': 'region', - 'LimitResource': 'region', - 'LimitGrowthCapacity': 'region', - 'LimitDegrowthCapacity': 'region', - 'LimitGrowthNewCapacity': 'region', - 'LimitDegrowthNewCapacity': 'region', - 'LimitGrowthNewCapacityDelta': 'region', - 'LimitDegrowthNewCapacityDelta': 'region', -} - - -class HybridLoader: - """ - An instance of the HybridLoader - """ - - def __init__(self, db_connection: Connection, config: TemoaConfig): - """ - build a loader for an instance. - :param db_connection: a Connection to the database - :param config: the config, which controls some options during execution - """ - self.debugging = False # for T/S, will print to screen the data load values - self.con = db_connection - self.config = config - - self.manager: CommodityNetworkManager | None = None - - # filters for myopic ops - self.viable_techs: ViableSet | None = None - self.viable_comms: ViableSet | None = None - self.viable_input_comms: ViableSet | None = None - self.viable_output_comms: ViableSet | None = None - self.viable_vintages: ViableSet | None = None - self.viable_ritvo: ViableSet | None = None - self.viable_rpto: ViableSet | None = None - self.viable_rtv: ViableSet | None = None - self.viable_rt: ViableSet | None = None - self.viable_rpit: ViableSet | None = None - self.viable_rtt: ViableSet | None = None # to support scanning LinkedTech - self.efficiency_values: list[tuple] = [] - - # container for loaded data - self.data: dict | None = None - - def source_trace_only(self, make_plots: bool = False, myopic_index: MyopicIndex | None = None): - if myopic_index and not isinstance(myopic_index, MyopicIndex): - raise ValueError('myopic_index must be an instance of MyopicIndex') - self._source_trace(myopic_index) - self.manager = None # to prevent possible out-of-synch build from stale data - - def _source_trace(self, myopic_index: MyopicIndex = None): - network_data = network_model_data.build(self.con, myopic_index=myopic_index) - cur = self.con.cursor() - # need periods to execute the source check by [r, p]. At this point, we can only pull from DB - periods = { - period for (period, *_) in cur.execute("SELECT period FROM TimePeriod WHERE flag = 'f'") - } - # we need to exclude the last period, it is a non-demand year - periods = sorted(periods)[:-1] - - if myopic_index: - periods = { - p for p in periods if myopic_index.base_year <= p <= myopic_index.last_demand_year - } - self.manager = CommodityNetworkManager(periods=periods, network_data=network_data) - all_regions_clean = self.manager.analyze_network() - if not all_regions_clean and not self.config.silent: - print('\nWarning: Orphaned processes detected. See log file for details.') - self.manager.analyze_graphs(self.config) - - def _build_efficiency_dataset( - self, use_raw_data=False, myopic_index: MyopicIndex | None = None - ): - """ - Build the efficiency dataset. For myopic mode, this means pull from MyopicEfficiency table - and we cannot use raw data. For other modes, we can either use raw data or the filtered data - provided by the manager (normal) - :param use_raw_data: if True, use raw data (without source-trace filtering) for build - :param myopic_index: the myopic index to use (or None for other modes) - :return: - """ - if myopic_index and use_raw_data: - raise RuntimeError('Cannot build from raw data in myopic mode... Likely coding error.') - cur = self.con.cursor() - # pull the data based on whether myopic/not - if myopic_index: - # pull from MyopicEfficiency, and filter by myopic index years - contents = cur.execute( - 'SELECT region, input_comm, tech, vintage, output_comm, efficiency, lifetime ' - 'FROM MyopicEfficiency ' - 'WHERE vintage + lifetime > ?', - (myopic_index.base_year,), - ).fetchall() - else: - # pull from regular Efficiency table - contents = cur.execute( - 'SELECT region, input_comm, tech, vintage, output_comm, efficiency, NULL FROM main.Efficiency' - ).fetchall() - - # set up filters, if requested... - if use_raw_data: - efficiency_entries = [row[:-1] for row in contents] - - else: # (always must when myopic) - if self.manager: - filts = self.manager.build_filters() - else: - raise RuntimeError('trying to filter, but manager has not analyzed network yet.') - self.viable_ritvo = filts['ritvo'] - self.viable_rtv = filts['rtv'] - self.viable_rt = filts['rt'] - self.viable_rpit = filts['rpit'] - self.viable_rpto = filts['rpto'] - self.viable_techs = filts['t'] - self.viable_input_comms = filts['ic'] - self.viable_vintages = filts['v'] - self.viable_output_comms = filts['oc'] - self.viable_comms = ViableSet( - elements=self.viable_input_comms.members | self.viable_output_comms.members - ) - rtt = { - (r, t1, t2) for r, t1 in self.viable_rt.members for t2 in self.viable_techs.members - } - self.viable_rtt = ViableSet( - elements=rtt, exception_loc=0, exception_vals=ViableSet.REGION_REGEXES - ) - efficiency_entries = { - (r, i, t, v, o, eff) - for r, i, t, v, o, eff, lifetime in contents - if (r, i, t, v, o) in self.viable_ritvo.members - } - logger.debug('polled %d elements from MyopicEfficiency table', len(efficiency_entries)) - - # book the EfficiencyTable - # we should sort here for deterministic results after pulling from set - self.efficiency_values = sorted(efficiency_entries) - - def table_exists(self, table_name: str) -> bool: - """ - Check if a table exists in the schema... for use with "optional" tables - :param table_name: the table name to check - :return: True if it exists in the schema - """ - table_name_check = ( - self.con.cursor() - .execute("SELECT name FROM sqlite_master WHERE type='table' AND name= ?", (table_name,)) - .fetchone() - ) - if table_name_check: - return True - logger.info('Did not find existing table for (optional) table: %s', table_name) - return False - - pass - - def load_data_portal(self, myopic_index: MyopicIndex | None = None) -> DataPortal: - # time the creation of the data portal - tic = time.time() - data_dict = self.create_data_dict(myopic_index=myopic_index) - - # pyomo namespace format has data[namespace][idx]=value - # the default namespace is None, thus... - namespace = {None: data_dict} - if self.debugging: - for item in namespace[None].items(): - print(item[0], item[1]) - dp = DataPortal(data_dict=namespace) - toc = time.time() - logger.debug('Data Portal Load time: %0.5f seconds', (toc - tic)) - return dp - - @staticmethod - def data_portal_from_data(data_source: dict) -> DataPortal: - """ - Create a DataPortal object from a data dictionary. Useful when the data has been modified - :param data_source: the dataset to use - :return: a new DataPortal object - """ - namespace = {None: data_source} - dp = DataPortal(data_dict=namespace) - return dp - - def create_data_dict(self, myopic_index: MyopicIndex | None = None) -> dict: - """ - Create and Load a Data Portal. If source tracing is enabled in the config, the source trace will - be executed and filtered data will be used. Without source-trace, raw (unfiltered) data will be loaded. - :param myopic_index: the MyopicIndex for myopic run. None for other modes - :return: - """ - # the general plan: - # 0. determine if source trace needs to be done, and do it - # 1. build the efficiency table - # 2. iterate through the model elements that are directly read from data - # 3. use SQL query to get the full table - # 4. (OPTIONALLY) filter it, as needed for myopic - # 5. load it into the data dictionary - logger.info('Loading data dictionary') - - # some logic checking... - if myopic_index is not None: - if not isinstance(myopic_index, MyopicIndex): - raise ValueError(f'received an illegal entry for the myopic index: {myopic_index}') - if self.config.scenario_mode != TemoaMode.MYOPIC: - raise RuntimeError( - 'Myopic Index passed to data dictionary build, but mode is not Myopic.... ' - 'Likely code error.' - ) - elif myopic_index is None and self.config.scenario_mode == TemoaMode.MYOPIC: - raise RuntimeError( - 'Mode is myopic, but no MyopicIndex specified in data portal build.... Likely code ' - 'error.' - ) - - if self.config.source_trace or self.config.scenario_mode == TemoaMode.MYOPIC: - use_raw_data = False - self._source_trace(myopic_index=myopic_index) - else: - use_raw_data = True - - # build the Efficiency Dataset - self._build_efficiency_dataset(use_raw_data=use_raw_data, myopic_index=myopic_index) - - mi = myopic_index # convenience - - # housekeeping - data: dict[str, list | dict] = dict() - - def load_element( - c: Set | Param, - values: Sequence[tuple], - validation: ViableSet | None = None, - val_loc: tuple = (0,), - ) -> Sequence[tuple]: - """ - Helper to alleviate some typing! - Expects that the values passed in are an iterable of tuples, like a standard - query result. Note that any filtering is disregarded if there is no myopic index in use - :param c: the model component to load - :param values: the keys for param or the item values for set as tuples (should be Sequence to help - get deterministic results) - :param validation: the set to validate the keys/set value against - :param val_loc: tuple of the positions of r, t, v in the key for validation - :return: a sequence of the values loaded - """ - if len(values) == 0: - logger.info('table, but no (usable) values for param or set: %s', c.name) - return [] - if not isinstance(values[0], tuple): - raise ValueError('values must be an iterable of tuples') - - if use_raw_data or validation is None: - screened = list(values) - else: - try: - screened = element_checker.filter_elements( - values=values, validation=validation, value_locations=val_loc - ) - except ValueError as e: - raise ValueError( - 'Failed to validate members of %s. Coding error likely.\n%s' % (c.name, e) - ) from e - if len(screened) < len(values): - msg = 'Some values for {} failed to validate and were ignored: {}' - logger.warning(msg.format(c.name, [val for val in values if val not in screened])) - match c: - case Set(): - if not screened: # no available values - data[c.name] = [] - elif len(screened[0]) == 1: # set of individual values - data[c.name] = [t[0] for t in screened] - else: # set of tuples, pass directly... - data[c.name] = screened - case Param(): - data[c.name] = {t[:-1]: t[-1] for t in screened} - return screened - - def load_indexed_set(indexed_set: Set, index_value, element, element_validator=None): - """ - load an element into an indexed set in the data store - :param indexed_set: the name of the pyomo Set - :param index_value: the index value to load into - :param element: the value to add to the indexed set - :param element_validator: a set of legal elements for the element to be added, or None for all elements - :return: None - """ - if element_validator and element not in element_validator: - return - data_store = data.get(indexed_set.name, defaultdict(list)) - data_store[index_value].append(element) - data[indexed_set.name] = data_store - - M: TemoaModel = TemoaModel() # for typing purposes only - cur = self.con.cursor() - - # === TIME SETS === - - # time_exist - if mi: - raw = cur.execute( - 'SELECT period FROM main.TimePeriod WHERE period < ? ORDER BY sequence', - (mi.base_year,), - ).fetchall() - else: - raw = cur.execute( - "SELECT period FROM main.TimePeriod WHERE flag = 'e' ORDER BY sequence" - ).fetchall() - load_element(M.time_exist, raw) - - # time_future - if mi: - raw = cur.execute( - 'SELECT period FROM main.TimePeriod WHERE ' - 'flag = "f" AND period >= ? AND period <= ? ORDER BY sequence', - (mi.base_year, mi.last_year), - ).fetchall() - else: - raw = cur.execute( - "SELECT period FROM main.TimePeriod WHERE flag = 'f' ORDER BY sequence" - ).fetchall() - load_element(M.time_future, raw) - time_optimize = [p[0] for p in raw[0:-1]] - - # time_of_day - if self.table_exists('TimeOfDay'): - raw = cur.execute('SELECT tod FROM main.TimeOfDay ORDER BY sequence').fetchall() - load_element(M.time_of_day, raw) - else: - logger.warning( - 'No TimeOfDay table found. Loading a single filler time of day "D" (assume this is an annual model)' - ) - load_element(M.time_of_day, [('D',)]) - - # TimeSequencing - time_sequencing = self.config.time_sequencing - match time_sequencing: - case 'seasonal_timeslices' | 'representative_periods' | 'consecutive_days': - pass - case 'manual': - # This is a hidden feature allowing the user to manually specify the sequence of states using the TimeNext table - if self.table_exists('TimeNext'): - raw = self.raw_check_mi_period( - mi, - cur=cur, - qry='SELECT period, season, tod, season_next, tod_next FROM main.TimeNext', - ) - load_element(M.TimeNext, raw) - else: - # Hidden feature unlocked but not setup! Give a nice long explanation - msg = ( - 'Tried to manually sequence time slices using TimeNext but the table did not exist. ' - "With time_sequencing set to 'manual' in the config file, the sequence of time slices will be pulled " - 'directly from the TimeNext table, where each row defines the next time slice in the order. ' - 'This is an advanced feature and not recommended for most users. If you do NOT want to ' - 'manually define the sequence of time slices, change the time_sequencing parameter. Otherwise ' - 'the TimeNext table can be found commented out in the v3.1 schema.' - ) - logger.error(msg) - raise ValueError(msg) - case _: - msg = ( - f"Invalid time sequencing parameter '{time_sequencing}'. Check the config file." - ) - logger.error(msg) - raise ValueError(msg) - load_element(M.TimeSequencing, [(time_sequencing,)]) - - # ReserveMarginMethod - load_element(M.ReserveMarginMethod, [(self.config.reserve_margin,)]) - - # myopic_base_year - if mi: - # assume first future period by default - p0 = cur.execute("SELECT min(period) FROM TimePeriod WHERE flag == 'f'").fetchone() - # load as a singleton... - data[M.MyopicDiscountingYear.name] = {None: int(p0[0])} - - # days_per_season - raw = cur.execute( - "SELECT value from MetaData WHERE element == 'days_per_period'" - ).fetchall() - if not raw: - logger.info( - 'No value found for days_per_period in the MetaData table. ' - 'Assuming this is an annual database (365 days per period)' - ) - raw = [(365,)] - data[M.DaysPerPeriod.name] = {None: int(raw[0][0])} - - # === REGION SETS === - - # regions - raw = cur.execute('SELECT region FROM main.Region').fetchall() - load_element(M.regions, raw) - - # region-groups (these are the R1+R2, R1+R4+R6 type region labels) AND regular region names - # currently, we just load all the indices from the tables that could employ them. - # the validator is used to ensure they are legit. (see temoa_model) - regions_and_groups = set() - for table, field_name in tables_with_regional_groups.items(): - if self.table_exists(table): - raw = cur.execute(f'SELECT {field_name} from main.{table}').fetchall() - regions_and_groups.update({t[0] for t in raw}) - if None in regions_and_groups: - raise ValueError('Table %s appears to have an empty entry for region.' % table) - # sort (for deterministic pyomo behavior) - list_of_groups = sorted((t,) for t in regions_and_groups) - load_element(M.regionalGlobalIndices, list_of_groups) - - # region-exchanges - # auto-generated - - # === TECH SETS === - - # tech_resource # devnote: not used anywhere - # raw = cur.execute("SELECT tech FROM main.Technology WHERE flag = 'r'").fetchall() - # load_element(M.tech_resource, raw, self.viable_techs) - - # tech_production - raw = cur.execute("SELECT tech FROM main.Technology WHERE flag LIKE 'p%'").fetchall() - load_element(M.tech_production, raw, self.viable_techs) - - # tech_uncap - try: - raw = cur.execute('SELECT tech FROM main.Technology WHERE unlim_cap > 0').fetchall() - load_element(M.tech_uncap, raw, self.viable_techs) - except OperationalError: - logger.info( - 'The current database does not support non-capacity techs and should be upgraded.' - ) - - # tech_baseload - raw = cur.execute("SELECT tech FROM main.Technology WHERE flag = 'pb'").fetchall() - load_element(M.tech_baseload, raw, self.viable_techs) - - # tech_storage - raw = cur.execute("SELECT tech FROM main.Technology WHERE flag = 'ps'").fetchall() - load_element(M.tech_storage, raw, self.viable_techs) - - # tech_seasonal_storage - raw = cur.execute( - "SELECT tech FROM main.Technology WHERE flag = 'ps' AND seas_stor > 0" - ).fetchall() - load_element(M.tech_seasonal_storage, raw, self.viable_techs) - - # tech_reserve - raw = cur.execute('SELECT tech FROM Technology WHERE reserve > 0').fetchall() - load_element(M.tech_reserve, raw, self.viable_techs) - - # tech_curtailment - raw = cur.execute('SELECT tech FROM Technology WHERE curtail > 0').fetchall() - load_element(M.tech_curtailment, raw, self.viable_techs) - - # tech_flex - raw = cur.execute('SELECT tech FROM Technology WHERE flex > 0').fetchall() - load_element(M.tech_flex, raw, self.viable_techs) - - # tech_exchange - raw = cur.execute('SELECT tech FROM Technology WHERE exchange > 0').fetchall() - load_element(M.tech_exchange, raw, self.viable_techs) - - # groups & tech_groups (supports RPS and general tech grouping) - if self.table_exists('TechGroup'): - raw = cur.execute('SELECT group_name FROM main.TechGroup').fetchall() - load_element(M.tech_group_names, raw) - - if self.table_exists('TechGroupMember'): - raw = cur.execute('SELECT group_name, tech FROM main.TechGroupMember').fetchall() - validator = self.viable_techs.members if self.viable_techs else None - for row in raw: - load_indexed_set( - M.tech_group_members, - index_value=row[0], - element=row[1], - element_validator=validator, - ) - - # tech_annual - raw = cur.execute('SELECT tech FROM Technology WHERE annual > 0').fetchall() - load_element(M.tech_annual, raw, self.viable_techs) - - # tech_retirement - raw = cur.execute('SELECT tech FROM Technology WHERE retire > 0').fetchall() - load_element(M.tech_retirement, raw, self.viable_techs) - - # === COMMODITIES === - - # commodity_demand - raw = cur.execute("SELECT name FROM main.Commodity WHERE flag = 'd'").fetchall() - load_element(M.commodity_demand, raw, self.viable_comms) - - # commodity_emissions - # currently NOT validated against anything... shouldn't be a problem ? - raw = cur.execute("SELECT name FROM main.Commodity WHERE flag = 'e'").fetchall() - load_element(M.commodity_emissions, raw) - - # commodity_physical - raw = cur.execute( - "SELECT name FROM main.Commodity WHERE flag LIKE '%p%' OR flag = 's' OR flag LIKE '%a%'" - ).fetchall() - # The model enforces 0 symmetric difference between the physical commodities - # and the input commodities, so we need to include only the viable INPUTS - load_element(M.commodity_physical, raw, self.viable_input_comms) - - # commodity_source - raw = cur.execute("SELECT name FROM main.Commodity WHERE flag = 's'").fetchall() - load_element(M.commodity_source, raw, self.viable_input_comms) - - # commodity_annual - raw = cur.execute("SELECT name FROM main.Commodity WHERE flag LIKE '%a%'").fetchall() - load_element(M.commodity_annual, raw, self.viable_input_comms) - - # commodity_waste - raw = cur.execute("SELECT name FROM main.Commodity WHERE flag LIKE '%w%'").fetchall() - load_element(M.commodity_waste, raw, self.viable_output_comms) - - # === OPERATORS === - - # operator - if self.table_exists('Operator'): - raw = cur.execute('SELECT operator FROM main.Operator').fetchall() - load_element(M.operator, raw) - - # === PARAMS === - - # Efficiency - # we have already computed/filtered this... no need for another data pull - raw = self.efficiency_values - load_element(M.Efficiency, raw) - - # EfficiencyVariable - if self.table_exists('EfficiencyVariable'): - raw = self.raw_check_mi_period( - mi, - cur=cur, - qry='SELECT region, period, season, tod, input_comm, tech, vintage, output_comm, efficiency FROM main.EfficiencyVariable', - ) - load_element(M.EfficiencyVariable, raw, self.viable_ritvo, (0, 4, 5, 6, 7)) - - # ExistingCapacity - if self.table_exists('ExistingCapacity'): - if mi: - # In order to get accurate capacity at start of this interval, we want to - # 1. Only look at the previous period in the net capacity table (things that had some capacity) - # 2. Omit any techs that are "unlimited capacity" to keep them out of capacity variables - # 3. add in everything from the original ExistingCapacity table - - # get previous period - raw = cur.execute( - 'SELECT MAX(period) FROM main.TimePeriod WHERE period < ?', (mi.base_year,) - ).fetchone() - previous_period = raw[0] - # noinspection SqlUnused - raw = cur.execute( - 'SELECT region, tech, vintage, capacity FROM main.OutputBuiltCapacity ' - ' WHERE vintage <= ? ' - ' AND scenario = ? ' - 'UNION ' - ' SELECT region, tech, vintage, capacity FROM main.ExistingCapacity ', - (previous_period, self.config.scenario), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, tech, vintage, capacity FROM main.ExistingCapacity' - ).fetchall() - # devnote: We want full existing capacity history for end of life flows and growth constraints - # load_element(M.ExistingCapacity, raw, self.viable_rtv, (0, 1, 2)) - load_element(M.ExistingCapacity, raw) - load_element( - M.tech_exist, list({(row[1],) for row in raw}) - ) # need to keep these for accounting purposes - - # GlobalDiscountRate - if self.table_exists('MetaDataReal'): - raw = cur.execute( - "SELECT value FROM main.MetaDataReal WHERE element = 'global_discount_rate'" - ).fetchall() - # do this separately as it is non-indexed, so we need to make a mapping with None - data[M.GlobalDiscountRate.name] = {None: raw[0][0]} - - # SegFrac - if self.table_exists('TimeSegmentFraction'): - raw = self.raw_check_mi_period( - mi=mi, - cur=cur, - qry='SELECT period, season, tod, segfrac FROM main.TimeSegmentFraction', - ) - else: - logger.warning( - 'No TimeSegmentFraction table found. Loading filler SegFrac ("S", "D") for one time segment per period' - ' (assume this is a periodic model)' - ) - # if no segfrac table, assume this is a periodic model - if mi: - raw = [ - (p, 'S', 'D', 1) - for p in time_optimize - if mi.base_year <= p <= mi.last_demand_year - ] - else: - raw = [(p, 'S', 'D', 1) for p in time_optimize] - load_element(M.SegFrac, raw) - - # TimeSeason - if self.table_exists('TimeSeason'): - if mi: - raw = cur.execute( - 'SELECT period, season FROM main.TimeSeason WHERE' - ' period >= ? AND period <= ? ORDER BY period, sequence', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT period, season FROM main.TimeSeason ORDER BY period, sequence' - ).fetchall() - for row in raw: - load_indexed_set(M.TimeSeason, index_value=row[0], element=row[1]) - load_element(M.time_season, list(set((row[1],) for row in raw))) - else: - for period in time_optimize: - load_indexed_set(M.TimeSeason, index_value=period, element='S') - logger.warning( - 'No TimeSeason table found. Loading a single filler season "S" (assume this is an annual model)' - ) - load_element(M.time_season, [('S',)]) - - if self.table_exists('TimeSeasonSequential'): - if mi: - raw = cur.execute( - 'SELECT period, seas_seq, season, num_days FROM main.TimeSeasonSequential WHERE' - ' period >= ? AND period <= ? ORDER BY period, sequence', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - raw = cur.execute( - 'SELECT period, seas_seq, season, num_days FROM main.TimeSeasonSequential ORDER BY period, sequence' - ).fetchall() - load_element(M.TimeSeasonSequential, raw) - if raw: - load_element(M.ordered_season_sequential, [(row[0:3]) for row in raw]) - load_element(M.time_season_sequential, list(set((row[1],) for row in raw))) - - # DemandSpecificDistribution - if self.table_exists('DemandSpecificDistribution'): - raw = self.raw_check_mi_period( - mi=mi, - cur=cur, - qry='SELECT region, period, season, tod, demand_name, dsd FROM main.DemandSpecificDistribution', - ) - load_element(M.DemandSpecificDistribution, raw) - - # Demand - raw = self.raw_check_mi_period( - mi, cur=cur, qry='SELECT region, period, commodity, demand FROM main.Demand' - ) - load_element(M.Demand, raw) - - # CapacityToActivity - if self.table_exists('CapacityToActivity'): - raw = cur.execute('SELECT region, tech, c2a FROM main.CapacityToActivity').fetchall() - load_element(M.CapacityToActivity, raw, self.viable_rt, (0, 1)) - - # CapacityFactorTech - if self.table_exists('CapacityFactorTech'): - raw = self.raw_check_mi_period( - mi=mi, - cur=cur, - qry='SELECT region, period, season, tod, tech, factor FROM main.CapacityFactorTech', - ) - load_element(M.CapacityFactorTech, raw, self.viable_rt, (0, 4)) - - # CapacityFactorProcess - if self.table_exists('CapacityFactorProcess'): - raw = self.raw_check_mi_period( - mi, - cur=cur, - qry='SELECT region, period, season, tod, tech, vintage, factor FROM main.CapacityFactorProcess', - ) - load_element(M.CapacityFactorProcess, raw, self.viable_rtv, (0, 4, 5)) - - # LifetimeTech - if self.table_exists('LifetimeTech'): - raw = cur.execute('SELECT region, tech, lifetime FROM main.LifetimeTech').fetchall() - load_element(M.LifetimeTech, raw, self.viable_rt, val_loc=(0, 1)) - - # LifetimeProcess - if self.table_exists('LifetimeProcess'): - raw = cur.execute( - 'SELECT region, tech, vintage, lifetime FROM main.LifetimeProcess' - ).fetchall() - load_element(M.LifetimeProcess, raw, self.viable_rtv, val_loc=(0, 1, 2)) - - # LifetimeSurvivalCurve - if self.table_exists('LifetimeSurvivalCurve'): - raw = cur.execute( - 'SELECT region, period, tech, vintage, fraction FROM main.LifetimeSurvivalCurve' - ).fetchall() - load_element(M.LifetimeSurvivalCurve, raw, self.viable_rtv, val_loc=(0, 2, 3)) - - # LoanLifetimeProcess - if self.table_exists('LoanLifetimeProcess'): - raw = cur.execute( - 'SELECT region, tech, vintage, lifetime FROM main.LoanLifetimeProcess' - ).fetchall() - load_element(M.LoanLifetimeProcess, raw, self.viable_rtv, (0, 1, 2)) - - # LimitTechInputSplit - if self.table_exists('LimitTechInputSplit'): - raw = self.raw_check_mi_period( - mi, - cur=cur, - qry='SELECT region, period, input_comm, tech, operator, proportion FROM main.LimitTechInputSplit', - ) - loaded = load_element(M.LimitTechInputSplit, raw, self.viable_rpit, (0, 1, 2, 3)) - # we need to see if anything was filtered out here and raise warning if so as it may have invalidated - # a blending process and any missing items should be reviewed - if len(loaded) < len(raw): - missing = set(raw) - set(loaded) - for item in sorted(missing, key=lambda x: (x[0], x[1], x[3], x[2])): - region, period, ic, tech, _, _ = item - logger.warning( - 'Technology Input Split requirement in region %s, period %d for tech %s with input' - 'commodity %s has ' - 'been removed because the tech path with that input is ' - 'invalid/not available/orphan. See the other warnings for this TECH in ' - 'this region-period, and check for availability of all components in data.', - region, - period, - tech, - ic, - ) - - # LimitTechInputSplitAnnual - if self.table_exists('LimitTechInputSplitAnnual'): - raw = self.raw_check_mi_period( - mi, - cur=cur, - qry='SELECT region, period, input_comm, tech, operator, proportion FROM main.LimitTechInputSplitAnnual', - ) - loaded = load_element(M.LimitTechInputSplitAnnual, raw, self.viable_rpit, (0, 1, 2, 3)) - # we need to see if anything was filtered out here and raise warning if so as it may have invalidated - # a blending process and any missing items should be reviewed - if len(loaded) < len(raw): - missing = set(raw) - set(loaded) - for item in sorted(missing, key=lambda x: (x[0], x[1], x[3], x[2])): - region, period, ic, tech, _, _ = item - logger.warning( - 'Technology Input Split Annual requirement in region %s, period %d for tech %s with input' - 'commodity %s has ' - 'been removed because the tech path with that input is ' - 'invalid/not available/orphan. See the other warnings for this TECH in ' - 'this region-period, and check for availability of all components in data.', - region, - period, - tech, - ic, - ) - - # LimitTechOutputSplit - if self.table_exists('LimitTechOutputSplit'): - raw = self.raw_check_mi_period( - mi, - cur=cur, - qry='SELECT region, period, tech, output_comm, operator, proportion FROM main.LimitTechOutputSplit', - ) - loaded = load_element(M.LimitTechOutputSplit, raw, self.viable_rpto, (0, 1, 2, 3)) - # raise warning regarding any deletions here... similar to input split above - if len(loaded) < len(raw): - missing = set(raw) - set(loaded) - for item in sorted(missing): - region, period, tech, oc, _, _ = item - logger.warning( - 'Technology Output Split requirement in region %s, period %d for tech %s with output' - 'commodity %s has ' - 'been removed because the tech path with that output is ' - 'invalid/not available/orphan. See the other warnings for this TECH in ' - 'this region-period, and check for availability of all components in data.', - region, - period, - tech, - oc, - ) - - # LimitTechOutputSplitAnnual - if self.table_exists('LimitTechOutputSplitAnnual'): - raw = self.raw_check_mi_period( - mi, - cur=cur, - qry='SELECT region, period, tech, output_comm, operator, proportion FROM main.LimitTechOutputSplitAnnual', - ) - loaded = load_element(M.LimitTechOutputSplitAnnual, raw, self.viable_rpto, (0, 1, 2, 3)) - # we need to see if anything was filtered out here and raise warning if so as it may have invalidated - # a blending process and any missing items should be reviewed - if len(loaded) < len(raw): - missing = set(raw) - set(loaded) - for item in sorted(missing): - region, period, tech, oc, _, _ = item - logger.warning( - 'Technology Output Split Annual requirement in region %s, period %d for tech %s with output' - 'commodity %s has ' - 'been removed because the tech path with that output is ' - 'invalid/not available/orphan. See the other warnings for this TECH in ' - 'this region-period, and check for availability of all components in data.', - region, - period, - tech, - oc, - ) - - # RenewablePortfolioStandard - if self.table_exists('RPSRequirement'): - raw = self.raw_check_mi_period( - mi, - cur=cur, - qry='SELECT region, period, tech_group, requirement FROM main.RPSRequirement', - ) - load_element(M.RenewablePortfolioStandard, raw) - if len(raw) > 0: - logger.warning( - 'The RenewablePortfolioStandard constraint has been deprecated. Use the ' - 'LimitActivityShare constraint instead, using the same sub group and ' - 'constructing a new super group for all relevant generators. The constraint ' - 'has been applied for now but this feature will be removed in the future.' - ) - - # CostFixed - raw = self.raw_check_mi_period( - mi, cur=cur, qry='SELECT region, period, tech, vintage, cost FROM main.CostFixed' - ) - load_element(M.CostFixed, raw, self.viable_rtv, val_loc=(0, 2, 3)) - - # CostInvest - # exclude "existing" vintages by screening for base year and beyond. - # the "viable_rtv" will filter anything beyond view - if mi: - raw = cur.execute( - 'SELECT region, tech, vintage, cost FROM main.CostInvest WHERE vintage >= ?', - (mi.base_year,), - ).fetchall() - else: - raw = cur.execute('SELECT region, tech, vintage, cost FROM main.CostInvest ').fetchall() - load_element(M.CostInvest, raw, self.viable_rtv, (0, 1, 2)) - - # CostVariable - raw = self.raw_check_mi_period( - mi, cur=cur, qry='SELECT region, period, tech, vintage, cost FROM main.CostVariable' - ) - load_element(M.CostVariable, raw, self.viable_rtv, (0, 2, 3)) - - # CostEmissions (and supporting index set) - if self.table_exists('CostEmission'): - raw = self.raw_check_mi_period( - mi, cur=cur, qry='SELECT region, period, emis_comm, cost from main.CostEmission' - ) - load_element(M.CostEmission, raw) - - # DefaultLoanRate - if self.table_exists('MetaDataReal'): - raw = cur.execute( - "SELECT value FROM main.MetaDataReal WHERE element = 'default_loan_rate'" - ).fetchall() - # do this separately as it is non-indexed, so we need to make a mapping with None - data[M.DefaultLoanRate.name] = {None: raw[0][0]} - - # LoanRate - if self.table_exists('LoanRate'): - if mi: - raw = cur.execute( - 'SELECT region, tech, vintage, rate FROM main.LoanRate WHERE vintage >= ?', - (mi.base_year,), - ).fetchall() - else: - raw = cur.execute( - 'SELECT region, tech, vintage, rate FROM main.LoanRate ' - ).fetchall() - - load_element(M.LoanRate, raw, self.viable_rtv, (0, 1, 2)) - - # LimitCapacity - if self.table_exists('LimitCapacity'): - raw = self.raw_check_mi_period( - mi, - cur=cur, - qry='SELECT region, period, tech_or_group, operator, capacity FROM main.LimitCapacity', - ) - load_element(M.LimitCapacity, raw) # , self.viable_rt, (0, 2)) - - # LimitNewCapacity - if self.table_exists('LimitNewCapacity'): - raw = self.raw_check_mi_period( - mi, - cur=cur, - qry='SELECT region, period, tech_or_group, operator, new_cap FROM main.LimitNewCapacity', - ) - load_element(M.LimitNewCapacity, raw) - - # LimitCapacityShare - if self.table_exists('LimitCapacityShare'): - raw = self.raw_check_mi_period( - mi, - cur=cur, - qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitCapacityShare', - ) - load_element(M.LimitCapacityShare, raw) - - # LimitNewCapacityShare - if self.table_exists('LimitNewCapacityShare'): - raw = self.raw_check_mi_period( - mi, - cur=cur, - qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitNewCapacityShare', - ) - load_element(M.LimitNewCapacityShare, raw) - - # LimitActivityShare - if self.table_exists('LimitActivityShare'): - raw = self.raw_check_mi_period( - mi, - cur=cur, - qry='SELECT region, period, sub_group, super_group, operator, share FROM main.LimitActivityShare', - ) - load_element(M.LimitActivityShare, raw) - - # LimitResource - if self.table_exists('LimitResource'): - raw = cur.execute( - 'SELECT region, tech_or_group, operator, cum_act FROM main.LimitResource' - ).fetchall() - load_element(M.LimitResource, raw) - - # LimitActivity - if self.table_exists('LimitActivity'): - raw = self.raw_check_mi_period( - mi, - cur=cur, - qry='SELECT region, period, tech_or_group, operator, activity FROM main.LimitActivity', - ) - load_element(M.LimitActivity, raw) - - # LimitSeasonalCapacityFactor - if self.table_exists('LimitSeasonalCapacityFactor'): - raw = self.raw_check_mi_period( - mi, - cur=cur, - qry='SELECT region, period, season, tech, operator, factor FROM main.LimitSeasonalCapacityFactor', - ) - load_element(M.LimitSeasonalCapacityFactor, raw, self.viable_rt, (0, 3)) - - # LimitAnnualCapacityFactor - if self.table_exists('LimitAnnualCapacityFactor'): - raw = self.raw_check_mi_period( - mi, - cur=cur, - qry='SELECT region, period, tech, output_comm, operator, factor FROM main.LimitAnnualCapacityFactor', - ) - load_element(M.LimitAnnualCapacityFactor, raw, self.viable_rpto, (0, 1, 2, 3)) - - # LimitGrowthCapacity - if self.table_exists('LimitGrowthCapacity'): - raw = cur.execute( - 'SELECT region, tech_or_group, operator, rate, seed FROM main.LimitGrowthCapacity' - ).fetchall() - raw = self.tuple_values(raw, 3) - load_element(M.LimitGrowthCapacity, raw) - - # LimitDegrowthCapacity - if self.table_exists('LimitDegrowthCapacity'): - raw = cur.execute( - 'SELECT region, tech_or_group, operator, rate, seed FROM main.LimitDegrowthCapacity' - ).fetchall() - raw = self.tuple_values(raw, 3) - load_element(M.LimitDegrowthCapacity, raw) - - # LimitGrowthNewCapacity - if self.table_exists('LimitGrowthNewCapacity'): - raw = cur.execute( - 'SELECT region, tech_or_group, operator, rate, seed FROM main.LimitGrowthNewCapacity' - ).fetchall() - raw = self.tuple_values(raw, 3) - load_element(M.LimitGrowthNewCapacity, raw) - - # LimitDegrowthNewCapacity - if self.table_exists('LimitDegrowthNewCapacity'): - raw = cur.execute( - 'SELECT region, tech_or_group, operator, rate, seed FROM main.LimitDegrowthNewCapacity' - ).fetchall() - raw = self.tuple_values(raw, 3) - load_element(M.LimitDegrowthNewCapacity, raw) - - # LimitGrowthNewCapacityDelta - if self.table_exists('LimitGrowthNewCapacityDelta'): - raw = cur.execute( - 'SELECT region, tech_or_group, operator, rate, seed FROM main.LimitGrowthNewCapacityDelta' - ).fetchall() - raw = self.tuple_values(raw, 3) - load_element(M.LimitGrowthNewCapacityDelta, raw) - - # LimitDegrowthNewCapacityDelta - if self.table_exists('LimitDegrowthNewCapacityDelta'): - raw = cur.execute( - 'SELECT region, tech_or_group, operator, rate, seed FROM main.LimitDegrowthNewCapacityDelta' - ).fetchall() - raw = self.tuple_values(raw, 3) - load_element(M.LimitDegrowthNewCapacityDelta, raw) - - # LimitEmission - if self.table_exists('LimitEmission'): - raw = self.raw_check_mi_period( - mi, - cur=cur, - qry='SELECT region, period, emis_comm, operator, value FROM main.LimitEmission', - ) - load_element(M.LimitEmission, raw) - - # EmissionActivity - # The current emission constraint screens by valid inputs, so if it is NOT - # built in a particular region, this should still be OK - if self.table_exists('EmissionActivity'): - raw = cur.execute( - 'SELECT region, emis_comm, input_comm, tech, vintage, output_comm, activity ' - 'FROM main.EmissionActivity ' - ).fetchall() - load_element(M.EmissionActivity, raw, self.viable_ritvo, (0, 2, 3, 4, 5)) - - # EmissionEmbodied - if self.table_exists('EmissionEmbodied'): - raw = cur.execute( - 'SELECT region, emis_comm, tech, vintage, value FROM main.EmissionEmbodied' - ).fetchall() - load_element(M.EmissionEmbodied, raw, self.viable_rtv, (0, 2, 3)) - - # EmissionEndOfLife - if self.table_exists('EmissionEndOfLife'): - raw = cur.execute( - 'SELECT region, emis_comm, tech, vintage, value FROM main.EmissionEndOfLife' - ).fetchall() - load_element(M.EmissionEndOfLife, raw, self.viable_rtv, (0, 2, 3)) - - # ConstructionInput - if self.table_exists('ConstructionInput'): - raw = cur.execute( - 'SELECT region, input_comm, tech, vintage, value FROM main.ConstructionInput' - ).fetchall() - load_element(M.ConstructionInput, raw, self.viable_rtv, (0, 2, 3)) - - # EndOfLifeOutput - if self.table_exists('EndOfLifeOutput'): - raw = cur.execute( - 'SELECT region, tech, vintage, output_comm, value FROM main.EndOfLifeOutput' - ).fetchall() - load_element(M.EndOfLifeOutput, raw, self.viable_rtv, (0, 1, 2)) - - # LinkedTechs - # Note: Both of the linked techs must be viable. As this is non period/vintage - # specific, it should be true that if one is built, the other is also - if self.table_exists('LinkedTech'): - raw = cur.execute( - 'SELECT primary_region, primary_tech, emis_comm, driven_tech FROM main.LinkedTech' - ).fetchall() - loaded = load_element(M.LinkedTechs, raw, self.viable_rtt, (0, 1, 3)) - # The below is a second check (belt and suspenders) and shouldn't really be needed, but it is - # preserved for now. - # we are checking that for each of the rejected LinkedTechs that each of the individual - # techs are also to be rejected (not members of valid_tech) ... if not ODD behavior - # could occur if the linkage is NOT established and the techs operate independently! - if len(loaded) < len(raw): - missing = set(raw) - set(loaded) - valid_techs = self.viable_techs.members - for item in missing: - t1 = item[1] - t2 = item[3] - if t1 in valid_techs or t2 in valid_techs: - # this is a PROBLEM. The commodity network should have removed both the - # driver and driven techs from the valid tech set, and they should not be in - # the valid tech set lest they be allowed in the model independently. - logger.error('Linked Tech item %s is not valid. Check data', item) - print('problem loading linked tech. See log file') - sys.exit(-1) - - # RampUpHourly - if self.table_exists('RampUpHourly'): - raw = cur.execute('SELECT region, tech, rate FROM main.RampUpHourly').fetchall() - load_element(M.RampUpHourly, raw, self.viable_rt, (0, 1)) - raw = cur.execute('SELECT DISTINCT tech FROM main.RampUpHourly').fetchall() - load_element(M.tech_upramping, raw, self.viable_techs) - - # RampDownHourly - if self.table_exists('RampDownHourly'): - raw = cur.execute('SELECT region, tech, rate FROM main.RampDownHourly').fetchall() - load_element(M.RampDownHourly, raw, self.viable_rt, (0, 1)) - raw = cur.execute('SELECT DISTINCT tech FROM main.RampDownHourly').fetchall() - load_element(M.tech_downramping, raw, self.viable_techs) - - # CapacityCredit - if self.table_exists('CapacityCredit'): - raw = self.raw_check_mi_period( - mi, - cur=cur, - qry='SELECT region, period, tech, vintage, credit FROM main.CapacityCredit', - ) - load_element(M.CapacityCredit, raw, self.viable_rtv, (0, 2, 3)) - - # ReserveCapacityDerate - if self.table_exists('ReserveCapacityDerate'): - raw = self.raw_check_mi_period( - mi, - cur=cur, - qry='SELECT region, period, season, tech, vintage, factor FROM main.ReserveCapacityDerate', - ) - load_element(M.ReserveCapacityDerate, raw, self.viable_rtv, (0, 3, 4)) - - # PlanningReserveMargin - if self.table_exists('PlanningReserveMargin'): - raw = cur.execute('SELECT region, margin FROM main.PlanningReserveMargin').fetchall() - load_element(M.PlanningReserveMargin, raw) - - # StorageDuration - if self.table_exists('StorageDuration'): - raw = cur.execute('SELECT region, tech, duration FROM main.StorageDuration').fetchall() - load_element(M.StorageDuration, raw, self.viable_rt, (0, 1)) - - # StorageFraction - if self.table_exists('LimitStorageLevelFraction'): - raw = self.raw_check_mi_period( - mi, - cur=cur, - qry='SELECT region, period, season, tod, tech, vintage, operator, fraction FROM main.LimitStorageLevelFraction', - ) - load_element(M.LimitStorageFraction, raw, self.viable_rtv, (0, 4, 5)) - - # For T/S: dump the size of all data elements into the log - if self.debugging: - temp = '\n'.join((f'{k} : {len(v)}' for k, v in data.items())) - logger.info(temp) - - # capture the parameter indexing sets - set_data = self.load_param_idx_sets(data=data) - data.update(set_data) - self.data = data - - return data - - def tuple_values(self, raw, index_length): - new_raw = [] - for row in raw: - new_raw.append((*row[0:index_length], row[index_length::])) - return new_raw - - def raw_check_mi_period(self, mi: MyopicIndex | None, cur: Cursor, qry: str) -> list: - if mi: - return cur.execute( - qry + ' WHERE period >= ? AND period <= ?', - (mi.base_year, mi.last_demand_year), - ).fetchall() - else: - return cur.execute(qry).fetchall() - - def load_param_idx_sets(self, data: dict) -> dict: - """ - Build a dictionary of sparse sets that can be used for indexing the parameters. - :param data: The parameters to peel out index values from - :return: a dictionary of the set name: values - - The purpose of this function is to use the data we have already captured for the parameters - to make indexing sets in the model. This replaces all of the "lambda" functions which were - previously used to reverse engineer the built parameters. - - Having these sets allows quicker constraint builds because they are the basis of many constraints - - It also enables the model to be serialized by python's pickle by removing functions from the model - definitions - """ - - M: TemoaModel = TemoaModel() # for typing - param_idx_sets = { - M.CostInvest.name: M.CostInvest_rtv.name, - M.CostEmission.name: M.CostEmission_rpe.name, - M.Demand.name: M.DemandConstraint_rpc.name, - M.LimitEmission.name: M.LimitEmissionConstraint_rpe.name, - M.LimitActivity.name: M.LimitActivityConstraint_rpt.name, - M.LimitSeasonalCapacityFactor.name: M.LimitSeasonalCapacityFactorConstraint_rpst.name, - M.LimitActivityShare.name: M.LimitActivityShareConstraint_rpgg.name, - M.LimitAnnualCapacityFactor.name: M.LimitAnnualCapacityFactorConstraint_rpto.name, - M.LimitCapacity.name: M.LimitCapacityConstraint_rpt.name, - M.LimitCapacityShare.name: M.LimitCapacityShareConstraint_rpgg.name, - M.LimitNewCapacity.name: M.LimitNewCapacityConstraint_rpt.name, - M.LimitNewCapacityShare.name: M.LimitNewCapacityShareConstraint_rpgg.name, - M.LimitResource.name: M.LimitResourceConstraint_rt.name, - M.LimitStorageFraction.name: M.LimitStorageFractionConstraint_rpsdtv.name, - M.RenewablePortfolioStandard.name: M.RenewablePortfolioStandardConstraint_rpg.name, - # M.ResourceBound.name: M.ResourceConstraint_rpr.name, - } - - res = {} - for p, s in param_idx_sets.items(): - param_data = data.get(p) - if param_data is None: - # no data for this param... nothing to capture for idx set - continue - idxs = list(param_data.keys()) - res[s] = idxs - return res diff --git a/temoa/_internal/temoa_sequencer.py b/temoa/_internal/temoa_sequencer.py index 921b45aa1..481feea51 100644 --- a/temoa/_internal/temoa_sequencer.py +++ b/temoa/_internal/temoa_sequencer.py @@ -36,7 +36,6 @@ import pyomo.opt -from temoa._internal.hybrid_loader import HybridLoader from temoa._internal.run_actions import ( build_instance, check_database_version, @@ -48,6 +47,7 @@ from temoa.core.config import TemoaConfig from temoa.core.model import TemoaModel from temoa.core.modes import TemoaMode +from temoa.data_io.hybrid_loader import HybridLoader from temoa.extensions.method_of_morris.morris_sequencer import MorrisSequencer from temoa.extensions.modeling_to_generate_alternatives.mga_sequencer import MgaSequencer from temoa.extensions.monte_carlo.mc_sequencer import MCSequencer diff --git a/temoa/data_io/README.md b/temoa/data_io/README.md new file mode 100644 index 000000000..0e85cf30c --- /dev/null +++ b/temoa/data_io/README.md @@ -0,0 +1,115 @@ +# Temoa Data I/O Subsystem + +This directory contains the core data loading engine for the Temoa model. It is responsible for reading data from a SQLite database, validating it, and preparing it for instantiation in a Pyomo model. + +## Architecture: Manifest-Driven Loading + +The data loading process follows a declarative, **manifest-driven architecture**. This design separates the *configuration* of what to load from the *procedural logic* of how to load it. This makes the system easier to understand, maintain, and extend. + +The key files are: + +- `hybrid_loader.py`: The main engine. Its `HybridLoader` class orchestrates the entire process. It iterates through the manifest, fetches data, applies validation, and calls specialized "custom loaders" for components that require complex logic. +- `component_manifest.py`: **This is the primary file for developers to modify.** It contains the `build_manifest` function, which returns a declarative list of all data components to be loaded into the model. Each entry in this list is a `LoadItem`. +- `loader_manifest.py`: Defines the `LoadItem` dataclass, which is the schema for each entry in the manifest. It tells the `HybridLoader` everything it needs to know about a component: its source table, columns, validation rules, etc. + +## How to Add a New Model Component + +Adding new data components to the model is now a straightforward process that primarily involves editing the `component_manifest.py` file. + +### Case 1: Adding a Simple Set or Parameter + +This is the most common case, for a component that maps directly to a database table. + +**Goal:** Add a new parameter `MyNewParam(region, tech, value)`. + +**Steps:** + +1. **Define the component** in `temoa/core/model.py` (e.g., `M.MyNewParam = Param(M.regions, M.tech_production)`). +2. **Open `temoa/data_io/component_manifest.py`**. +3. **Add a `LoadItem`** to the manifest list in the appropriate logical section (e.g., under `Operational Constraints`). + + ```python + # temoa/data_io/component_manifest.py + + # ... inside the manifest list + LoadItem( + component=M.MyNewParam, + table='MyNewParamTableName', + columns=['region', 'tech', 'value'], + # Optional: Add validation if this component should be filtered + # by the source-trace analysis. + validator_name='viable_rt', + validation_map=(0, 1), # Corresponds to 'region' and 'tech' columns + ), + # ... + ``` + +4. **You're done.** The `HybridLoader` engine will automatically handle fetching, validating, and loading this component. + +### Case 2: Adding a Component with a Simple Fallback + +If a component is optional and should have a default value if its table is missing, use the `fallback_data` attribute. + +**Goal:** Add an optional set `MyOptionalSet(some_value)` that defaults to `[('A',), ('B',)]`. + +**Steps:** + +1. **Define the component** in `temoa/core/model.py`. +2. **Add a `LoadItem`** to `component_manifest.py`. + + ```python + # temoa/data_io/component_manifest.py + + LoadItem( + component=M.MyOptionalSet, + table='MyOptionalSetTable', + columns=['some_value'], + is_table_required=False, # Mark the table as optional + fallback_data=[('A',), ('B',)] # Provide default data + ), + ``` + +### Case 3: Adding a Component with Complex Logic + +If a component requires logic that doesn't fit the standard pattern (e.g., aggregating from multiple tables, complex myopic queries, dynamic fallbacks), use a custom loader. + +**Goal:** Add a parameter `MyComplexParam` that requires special handling. + +**Steps:** + +1. **Define the component** in `temoa/core/model.py`. +2. **Open `temoa/data_io/hybrid_loader.py`**. +3. **Create a new custom loader method** inside the `HybridLoader` class. The method must accept `self, data, raw_data, filtered_data` as arguments. + + ```python + # temoa/data_io/hybrid_loader.py + + # ... inside the HybridLoader class, in the custom loaders section + def _load_my_complex_param(self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple]): + """Custom loader for MyComplexParam.""" + M = TemoaModel() + # --- Add your custom logic here --- + # For example, perform a special query or transform the data. + final_data_to_load = [(r, t, v * 2) for r, t, v in filtered_data] # Example transformation + + # Use the standard helper to load the final data + self._load_component_data(data, M.MyComplexParam, final_data_to_load) + ``` + +4. **Open `temoa/data_io/component_manifest.py`**. +5. **Add a `LoadItem`** that points to your new custom loader. + + ```python + # temoa/data_io/component_manifest.py + + LoadItem( + component=M.MyComplexParam, + table='MyComplexParamTable', # Can be a real table or a placeholder + columns=['region', 'tech', 'value'], + # Point to your new method + custom_loader_name='_load_my_complex_param', + is_table_required=False # Usually False if the loader has complex logic + ), + ``` + +This pattern keeps the main engine clean while providing unlimited flexibility to handle any data loading scenario. diff --git a/temoa/data_io/component_manifest.py b/temoa/data_io/component_manifest.py new file mode 100644 index 000000000..330738884 --- /dev/null +++ b/temoa/data_io/component_manifest.py @@ -0,0 +1,702 @@ +# temoa/data_io/component_manifest.py +""" +Defines the data loading manifest for the Temoa model. + +This module contains a single function, `build_manifest`, which constructs a +list of `LoadItem` objects. This list serves as the declarative configuration +for the `HybridLoader`, specifying every data component to be loaded from the +database into the Pyomo model. + +The manifest is organized into logical groups that mirror the structure of the +Temoa model itself (e.g., Time, Regions, Technologies, Costs, Constraints). +This cohesive grouping makes it easier for developers to find and understand +how specific parts of the model are populated with data. + +To add a new standard component to the model, a developer typically only needs +to add a new `LoadItem` to this manifest. +""" + +from temoa.core.model import TemoaModel +from temoa.data_io.loader_manifest import LoadItem + + +def build_manifest(M: TemoaModel) -> list[LoadItem]: + """ + Builds the manifest of all data components to be loaded into the Pyomo model. + + This declarative approach separates the configuration of what to load from the + procedural logic of how to load it. The manifest is ordered logically to + enhance readability and maintainability. + + Args: + M: An instance of TemoaModel to link components. + + Returns: + A list of LoadItem objects describing all data to be loaded. + """ + manifest = [ + # ========================================================================= + # Core Model Structure (Regions, Techs, Commodities, Groups) + # ========================================================================= + LoadItem( + component=M.regions, + table='Region', + columns=['region'], + is_period_filtered=False, + ), + LoadItem( + component=M.regionalGlobalIndices, + table='meta_regional_groups', # Placeholder, custom loader does the work + columns=['region_or_group'], + custom_loader_name='_load_regional_global_indices', + is_period_filtered=False, + is_table_required=False, + ), + LoadItem( + component=M.tech_production, + table='Technology', + columns=['tech'], + where_clause="flag LIKE 'p%'", + validator_name='viable_techs', + validation_map=(0,), + is_period_filtered=False, + ), + LoadItem( + component=M.tech_uncap, + table='Technology', + columns=['tech'], + where_clause='unlim_cap > 0', + validator_name='viable_techs', + validation_map=(0,), + is_period_filtered=False, + is_table_required=False, + ), + LoadItem( + component=M.tech_baseload, + table='Technology', + columns=['tech'], + where_clause="flag = 'pb'", + validator_name='viable_techs', + validation_map=(0,), + is_period_filtered=False, + ), + LoadItem( + component=M.tech_storage, + table='Technology', + columns=['tech'], + where_clause="flag = 'ps'", + validator_name='viable_techs', + validation_map=(0,), + is_period_filtered=False, + ), + LoadItem( + component=M.tech_seasonal_storage, + table='Technology', + columns=['tech'], + where_clause="flag = 'ps' AND seas_stor > 0", + validator_name='viable_techs', + validation_map=(0,), + is_period_filtered=False, + ), + LoadItem( + component=M.tech_reserve, + table='Technology', + columns=['tech'], + where_clause='reserve > 0', + validator_name='viable_techs', + validation_map=(0,), + is_period_filtered=False, + ), + LoadItem( + component=M.tech_curtailment, + table='Technology', + columns=['tech'], + where_clause='curtail > 0', + validator_name='viable_techs', + validation_map=(0,), + is_period_filtered=False, + ), + LoadItem( + component=M.tech_flex, + table='Technology', + columns=['tech'], + where_clause='flex > 0', + validator_name='viable_techs', + validation_map=(0,), + is_period_filtered=False, + ), + LoadItem( + component=M.tech_exchange, + table='Technology', + columns=['tech'], + where_clause='exchange > 0', + validator_name='viable_techs', + validation_map=(0,), + is_period_filtered=False, + ), + LoadItem( + component=M.tech_annual, + table='Technology', + columns=['tech'], + where_clause='annual > 0', + validator_name='viable_techs', + validation_map=(0,), + is_period_filtered=False, + ), + LoadItem( + component=M.tech_retirement, + table='Technology', + columns=['tech'], + where_clause='retire > 0', + validator_name='viable_techs', + validation_map=(0,), + is_period_filtered=False, + ), + LoadItem( + component=M.tech_group_names, + table='TechGroup', + columns=['group_name'], + is_period_filtered=False, + is_table_required=False, + ), + LoadItem( + component=M.tech_group_members, + table='TechGroupMember', + columns=['group_name', 'tech'], + custom_loader_name='_load_tech_group_members', + is_period_filtered=False, + is_table_required=False, + ), + LoadItem( + component=M.commodity_demand, + table='Commodity', + columns=['name'], + where_clause="flag = 'd'", + validator_name='viable_comms', + validation_map=(0,), + is_period_filtered=False, + ), + LoadItem( + component=M.commodity_emissions, + table='Commodity', + columns=['name'], + where_clause="flag = 'e'", + is_period_filtered=False, + ), + LoadItem( + component=M.commodity_physical, + table='Commodity', + columns=['name'], + where_clause="flag LIKE '%p%' OR flag = 's' OR flag LIKE '%a%'", + validator_name='viable_input_comms', + validation_map=(0,), + is_period_filtered=False, + ), + LoadItem( + component=M.commodity_source, + table='Commodity', + columns=['name'], + where_clause="flag = 's'", + validator_name='viable_input_comms', + validation_map=(0,), + is_period_filtered=False, + ), + LoadItem( + component=M.commodity_annual, + table='Commodity', + columns=['name'], + where_clause="flag LIKE '%a%'", + validator_name='viable_input_comms', + validation_map=(0,), + is_period_filtered=False, + ), + LoadItem( + component=M.commodity_waste, + table='Commodity', + columns=['name'], + where_clause="flag LIKE '%w%'", + validator_name='viable_output_comms', + validation_map=(0,), + is_period_filtered=False, + ), + LoadItem( + component=M.operator, + table='Operator', + columns=['operator'], + is_period_filtered=False, + is_table_required=False, + ), + # ========================================================================= + # Time-Related Components + # ========================================================================= + LoadItem( + component=M.time_of_day, + table='TimeOfDay', + columns=['tod'], + is_period_filtered=False, + is_table_required=False, + fallback_data=[('D',)], + ), + LoadItem( + component=M.TimeSeason, + table='TimeSeason', + columns=['period', 'season'], + custom_loader_name='_load_time_season', + is_period_filtered=False, # Custom loader handles myopic filtering + is_table_required=False, + ), + LoadItem( + component=M.TimeSeasonSequential, + table='TimeSeasonSequential', + columns=['period', 'seas_seq', 'season', 'num_days'], + custom_loader_name='_load_time_season_sequential', + is_table_required=False, + ), + LoadItem( + component=M.SegFrac, + table='TimeSegmentFraction', + columns=['period', 'season', 'tod', 'segfrac'], + custom_loader_name='_load_seg_frac', + is_table_required=False, + ), + # ========================================================================= + # Capacity and Cost Components + # ========================================================================= + LoadItem( + component=M.ExistingCapacity, + table='ExistingCapacity', + columns=['region', 'tech', 'vintage', 'capacity'], + custom_loader_name='_load_existing_capacity', + is_period_filtered=False, # Custom loader handles all logic + is_table_required=False, + ), + LoadItem( + component=M.CostInvest, + table='CostInvest', + columns=['region', 'tech', 'vintage', 'cost'], + validator_name='viable_rtv', + validation_map=(0, 1, 2), + custom_loader_name='_load_cost_invest', + is_period_filtered=False, # Custom loader handles this + is_table_required=False, + ), + LoadItem( + component=M.CostFixed, + table='CostFixed', + columns=['region', 'period', 'tech', 'vintage', 'cost'], + validator_name='viable_rtv', + validation_map=(0, 2, 3), + ), + LoadItem( + component=M.CostVariable, + table='CostVariable', + columns=['region', 'period', 'tech', 'vintage', 'cost'], + validator_name='viable_rtv', + validation_map=(0, 2, 3), + ), + LoadItem( + component=M.CostEmission, + table='CostEmission', + columns=['region', 'period', 'emis_comm', 'cost'], + is_table_required=False, + ), + LoadItem( + component=M.LoanRate, + table='LoanRate', + columns=['region', 'tech', 'vintage', 'rate'], + validator_name='viable_rtv', + validation_map=(0, 1, 2), + custom_loader_name='_load_loan_rate', + is_period_filtered=False, # Custom loader handles this + is_table_required=False, + ), + # ========================================================================= + # Singleton and Configuration-based Components + # ========================================================================= + LoadItem( + component=M.DaysPerPeriod, + table='MetaData', + columns=['value'], + where_clause="element == 'days_per_period'", + custom_loader_name='_load_days_per_period', + is_period_filtered=False, + is_table_required=False, + ), + LoadItem( + component=M.GlobalDiscountRate, + table='MetaDataReal', + columns=['value'], + where_clause="element = 'global_discount_rate'", + custom_loader_name='_load_global_discount_rate', + is_period_filtered=False, + is_table_required=False, + ), + LoadItem( + component=M.DefaultLoanRate, + table='MetaDataReal', + columns=['value'], + where_clause="element = 'default_loan_rate'", + custom_loader_name='_load_default_loan_rate', + is_period_filtered=False, + is_table_required=False, + ), + # ========================================================================= + # Operational Constraints and Parameters + # ========================================================================= + LoadItem( + component=M.Efficiency, + table='meta_efficiency', # Placeholder, custom loader does the work + columns=[], + custom_loader_name='_load_efficiency', + is_period_filtered=False, + is_table_required=False, + ), + LoadItem( + component=M.EfficiencyVariable, + table='EfficiencyVariable', + columns=[ + 'region', + 'period', + 'season', + 'tod', + 'input_comm', + 'tech', + 'vintage', + 'output_comm', + 'efficiency', + ], + validator_name='viable_ritvo', + validation_map=(0, 4, 5, 6, 7), + is_table_required=False, + ), + LoadItem( + component=M.Demand, table='Demand', columns=['region', 'period', 'commodity', 'demand'] + ), + LoadItem( + component=M.DemandSpecificDistribution, + table='DemandSpecificDistribution', + columns=['region', 'period', 'season', 'tod', 'demand_name', 'dsd'], + is_table_required=False, + ), + LoadItem( + component=M.CapacityToActivity, + table='CapacityToActivity', + columns=['region', 'tech', 'c2a'], + validator_name='viable_rt', + validation_map=(0, 1), + is_period_filtered=False, + is_table_required=False, + ), + LoadItem( + component=M.CapacityFactorTech, + table='CapacityFactorTech', + columns=['region', 'period', 'season', 'tod', 'tech', 'factor'], + validator_name='viable_rt', + validation_map=(0, 4), + is_table_required=False, + ), + LoadItem( + component=M.CapacityFactorProcess, + table='CapacityFactorProcess', + columns=['region', 'period', 'season', 'tod', 'tech', 'vintage', 'factor'], + validator_name='viable_rtv', + validation_map=(0, 4, 5), + is_table_required=False, + ), + LoadItem( + component=M.LifetimeTech, + table='LifetimeTech', + columns=['region', 'tech', 'lifetime'], + validator_name='viable_rt', + validation_map=(0, 1), + is_period_filtered=False, + is_table_required=False, + ), + LoadItem( + component=M.LifetimeProcess, + table='LifetimeProcess', + columns=['region', 'tech', 'vintage', 'lifetime'], + validator_name='viable_rtv', + validation_map=(0, 1, 2), + is_period_filtered=False, + is_table_required=False, + ), + LoadItem( + component=M.LifetimeSurvivalCurve, + table='LifetimeSurvivalCurve', + columns=['region', 'period', 'tech', 'vintage', 'fraction'], + validator_name='viable_rtv', + validation_map=(0, 2, 3), + is_period_filtered=False, + is_table_required=False, + ), + LoadItem( + component=M.LoanLifetimeProcess, + table='LoanLifetimeProcess', + columns=['region', 'tech', 'vintage', 'lifetime'], + validator_name='viable_rtv', + validation_map=(0, 1, 2), + is_period_filtered=False, + is_table_required=False, + ), + LoadItem( + component=M.RampUpHourly, + table='RampUpHourly', + columns=['region', 'tech', 'rate'], + custom_loader_name='_load_ramping_up', + validator_name='viable_rt', + validation_map=(0, 1), + is_period_filtered=False, + is_table_required=False, + ), + LoadItem( + component=M.tech_upramping, + table='RampUpHourly', + columns=['tech'], + validator_name='viable_techs', + validation_map=(0,), + is_period_filtered=False, + ), + LoadItem( + component=M.RampDownHourly, + table='RampDownHourly', + columns=['region', 'tech', 'rate'], + custom_loader_name='_load_ramping_down', + validator_name='viable_rt', + validation_map=(0, 1), + is_period_filtered=False, + is_table_required=False, + ), + LoadItem( + component=M.tech_downramping, + table='RampDownHourly', + columns=['tech'], + validator_name='viable_techs', + validation_map=(0,), + is_period_filtered=False, + ), + LoadItem( + component=M.RenewablePortfolioStandard, + table='RPSRequirement', + columns=['region', 'period', 'tech_group', 'requirement'], + custom_loader_name='_load_rps_requirement', + is_table_required=False, + ), + LoadItem( + component=M.CapacityCredit, + table='CapacityCredit', + columns=['region', 'period', 'tech', 'vintage', 'credit'], + validator_name='viable_rtv', + validation_map=(0, 2, 3), + is_table_required=False, + ), + LoadItem( + component=M.ReserveCapacityDerate, + table='ReserveCapacityDerate', + columns=['region', 'period', 'season', 'tech', 'vintage', 'factor'], + validator_name='viable_rtv', + validation_map=(0, 3, 4), + is_table_required=False, + ), + LoadItem( + component=M.PlanningReserveMargin, + table='PlanningReserveMargin', + columns=['region', 'margin'], + is_period_filtered=False, + is_table_required=False, + ), + LoadItem( + component=M.StorageDuration, + table='StorageDuration', + columns=['region', 'tech', 'duration'], + validator_name='viable_rt', + validation_map=(0, 1), + is_period_filtered=False, + is_table_required=False, + ), + LoadItem( + component=M.LimitStorageFraction, + table='LimitStorageLevelFraction', + columns=[ + 'region', + 'period', + 'season', + 'tod', + 'tech', + 'vintage', + 'operator', + 'fraction', + ], + validator_name='viable_rtv', + validation_map=(0, 4, 5), + is_table_required=False, + ), + LoadItem( + component=M.EmissionActivity, + table='EmissionActivity', + columns=[ + 'region', + 'emis_comm', + 'input_comm', + 'tech', + 'vintage', + 'output_comm', + 'activity', + ], + validator_name='viable_ritvo', + validation_map=(0, 2, 3, 4, 5), + is_period_filtered=False, + is_table_required=False, + ), + LoadItem( + component=M.EmissionEmbodied, + table='EmissionEmbodied', + columns=['region', 'emis_comm', 'tech', 'vintage', 'value'], + validator_name='viable_rtv', + validation_map=(0, 2, 3), + is_period_filtered=False, + is_table_required=False, + ), + LoadItem( + component=M.EmissionEndOfLife, + table='EmissionEndOfLife', + columns=['region', 'emis_comm', 'tech', 'vintage', 'value'], + validator_name='viable_rtv', + validation_map=(0, 2, 3), + is_period_filtered=False, + is_table_required=False, + ), + LoadItem( + component=M.ConstructionInput, + table='ConstructionInput', + columns=['region', 'input_comm', 'tech', 'vintage', 'value'], + validator_name='viable_rtv', + validation_map=(0, 2, 3), + is_period_filtered=False, + is_table_required=False, + ), + LoadItem( + component=M.EndOfLifeOutput, + table='EndOfLifeOutput', + columns=['region', 'tech', 'vintage', 'output_comm', 'value'], + validator_name='viable_rtv', + validation_map=(0, 1, 2), + is_period_filtered=False, + is_table_required=False, + ), + # ========================================================================= + # Limit Constraints + # ========================================================================= + LoadItem( + component=M.LimitCapacity, + table='LimitCapacity', + columns=['region', 'period', 'tech_or_group', 'operator', 'capacity'], + is_table_required=False, + ), + LoadItem( + component=M.LimitNewCapacity, + table='LimitNewCapacity', + columns=['region', 'period', 'tech_or_group', 'operator', 'new_cap'], + is_table_required=False, + ), + LoadItem( + component=M.LimitCapacityShare, + table='LimitCapacityShare', + columns=['region', 'period', 'sub_group', 'super_group', 'operator', 'share'], + is_table_required=False, + ), + LoadItem( + component=M.LimitNewCapacityShare, + table='LimitNewCapacityShare', + columns=['region', 'period', 'sub_group', 'super_group', 'operator', 'share'], + is_table_required=False, + ), + LoadItem( + component=M.LimitActivity, + table='LimitActivity', + columns=['region', 'period', 'tech_or_group', 'operator', 'activity'], + is_table_required=False, + ), + LoadItem( + component=M.LimitActivityShare, + table='LimitActivityShare', + columns=['region', 'period', 'sub_group', 'super_group', 'operator', 'share'], + is_table_required=False, + ), + LoadItem( + component=M.LimitResource, + table='LimitResource', + columns=['region', 'tech_or_group', 'operator', 'cum_act'], + is_period_filtered=False, + is_table_required=False, + ), + LoadItem( + component=M.LimitSeasonalCapacityFactor, + table='LimitSeasonalCapacityFactor', + columns=['region', 'period', 'season', 'tech', 'operator', 'factor'], + validator_name='viable_rt', + validation_map=(0, 3), + is_table_required=False, + ), + LoadItem( + component=M.LimitAnnualCapacityFactor, + table='LimitAnnualCapacityFactor', + columns=['region', 'period', 'tech', 'output_comm', 'operator', 'factor'], + validator_name='viable_rpto', + validation_map=(0, 1, 2, 3), + is_table_required=False, + ), + LoadItem( + component=M.LimitEmission, + table='LimitEmission', + columns=['region', 'period', 'emis_comm', 'operator', 'value'], + is_table_required=False, + ), + LoadItem( + component=M.LimitTechInputSplit, + table='LimitTechInputSplit', + columns=['region', 'period', 'input_comm', 'tech', 'operator', 'proportion'], + validator_name='viable_rpit', + validation_map=(0, 1, 2, 3), + custom_loader_name='_load_limit_tech_input_split', + is_table_required=False, + ), + LoadItem( + component=M.LimitTechInputSplitAnnual, + table='LimitTechInputSplitAnnual', + columns=['region', 'period', 'input_comm', 'tech', 'operator', 'proportion'], + validator_name='viable_rpit', + validation_map=(0, 1, 2, 3), + custom_loader_name='_load_limit_tech_input_split_annual', + is_table_required=False, + ), + LoadItem( + component=M.LimitTechOutputSplit, + table='LimitTechOutputSplit', + columns=['region', 'period', 'tech', 'output_comm', 'operator', 'proportion'], + validator_name='viable_rpto', + validation_map=(0, 1, 2, 3), + custom_loader_name='_load_limit_tech_output_split', + is_table_required=False, + ), + LoadItem( + component=M.LimitTechOutputSplitAnnual, + table='LimitTechOutputSplitAnnual', + columns=['region', 'period', 'tech', 'output_comm', 'operator', 'proportion'], + validator_name='viable_rpto', + validation_map=(0, 1, 2, 3), + custom_loader_name='_load_limit_tech_output_split_annual', + is_table_required=False, + ), + LoadItem( + component=M.LinkedTechs, + table='LinkedTech', + columns=['primary_region', 'primary_tech', 'emis_comm', 'driven_tech'], + validator_name='viable_rtt', + validation_map=(0, 1, 3), + custom_loader_name='_load_linked_techs', + is_period_filtered=False, + is_table_required=False, + ), + ] + return manifest diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py new file mode 100644 index 000000000..8d15f63cb --- /dev/null +++ b/temoa/data_io/hybrid_loader.py @@ -0,0 +1,827 @@ +# temoa/data_io/hybrid_loader.py +""" +Defines the main data loading engine for the Temoa model. + +The primary component of this module is the `HybridLoader` class, which is +responsible for reading, validating, and formatting data from a Temoa SQLite +database for use in a Pyomo model. + +Architecture: + The loader operates on a declarative, manifest-driven architecture. The + configuration for what data to load is defined externally in + `temoa.data_io.component_manifest.py`. This separation of concerns means + that adding new, standard model components often only requires a change to + the manifest, not this procedural code. + + For components that require complex logic (e.g., conditional queries for + myopic mode, data aggregation, or dynamic fallbacks), the manifest directs + the engine to use specialized 'custom loader' methods within the + `HybridLoader` class. +""" + +import time +from collections import defaultdict +from collections.abc import Sequence +from logging import getLogger +from sqlite3 import Connection, Cursor, OperationalError +from typing import Any + +from pyomo.core import Param, Set +from pyomo.dataportal import DataPortal + +from temoa.core.config import TemoaConfig +from temoa.core.model import TemoaModel +from temoa.core.modes import TemoaMode +from temoa.data_io.component_manifest import build_manifest +from temoa.data_io.loader_manifest import LoadItem +from temoa.extensions.myopic.myopic_index import MyopicIndex +from temoa.model_checking import element_checker, network_model_data +from temoa.model_checking.commodity_network_manager import CommodityNetworkManager +from temoa.model_checking.element_checker import ViableSet + +logger = getLogger(__name__) + +# A manifest of tables that may contain region groups, used by a custom loader. +tables_with_regional_groups = { + 'LimitAnnualCapacityFactor': 'region', + 'LimitEmission': 'region', + 'LimitSeasonalCapacityFactor': 'region', + 'LimitCapacity': 'region', + 'LimitActivity': 'region', + 'LimitNewCapacity': 'region', + 'LimitActivityShare': 'region', + 'LimitCapacityShare': 'region', + 'LimitNewCapacityShare': 'region', + 'LimitResource': 'region', + 'LimitGrowthCapacity': 'region', + 'LimitDegrowthCapacity': 'region', + 'LimitGrowthNewCapacity': 'region', + 'LimitDegrowthNewCapacity': 'region', + 'LimitGrowthNewCapacityDelta': 'region', + 'LimitDegrowthNewCapacityDelta': 'region', +} + + +class HybridLoader: + """ + Drives the loading of model data from a SQLite database into a format + suitable for Pyomo's DataPortal. + + This loader is manifest-driven. The `component_manifest.py` file provides a + declarative list of all components to be loaded, separating the configuration + of what to load from the procedural logic of how to load it. + """ + + def __init__(self, db_connection: Connection, config: TemoaConfig) -> None: + """ + Initializes the loader. + + :param db_connection: An active SQLite database connection. + :param config: The Temoa configuration object. + """ + self.debugging = False + self.con = db_connection + self.config = config + self.myopic_index: MyopicIndex | None = None + + # Build the data loading manifest and a name-based map for quick lookup + M = TemoaModel() + self.manifest = build_manifest(M) + self.manifest_map = {item.component.name: item for item in self.manifest} + + # --- Data containers and filters populated during loading --- + self.manager: CommodityNetworkManager | None = None + self.efficiency_values: list[tuple] = [] + self.data: dict[str, Any] | None = None + + # --- Viable sets for source-trace filtering --- + self.viable_techs: ViableSet | None = None + self.viable_comms: ViableSet | None = None + self.viable_input_comms: ViableSet | None = None + self.viable_output_comms: ViableSet | None = None + self.viable_vintages: ViableSet | None = None + self.viable_ritvo: ViableSet | None = None + self.viable_rpto: ViableSet | None = None + self.viable_rtv: ViableSet | None = None + self.viable_rt: ViableSet | None = None + self.viable_rpit: ViableSet | None = None + self.viable_rtt: ViableSet | None = None + + def source_trace_only(self, myopic_index: MyopicIndex | None = None) -> None: + """ + Runs only the source-trace analysis without a full data load. + This is primarily for the 'check' mode. + + :param myopic_index: The MyopicIndex for the run, if applicable. + """ + if myopic_index and not isinstance(myopic_index, MyopicIndex): + raise ValueError('myopic_index must be an instance of MyopicIndex') + self._source_trace(myopic_index) + self.manager = None # Prevent use of stale data + + def load_data_portal(self, myopic_index: MyopicIndex | None = None) -> DataPortal: + """ + Main entry point to create and load a DataPortal object. + + :param myopic_index: The MyopicIndex for the run, if applicable. + :return: A populated Pyomo DataPortal object. + """ + tic = time.time() + data_dict = self.create_data_dict(myopic_index=myopic_index) + + namespace = {None: data_dict} + dp = DataPortal(data_dict=namespace) + + toc = time.time() + logger.debug('Data Portal Load time: %0.5f seconds', (toc - tic)) + return dp + + @staticmethod + def data_portal_from_data(data_source: dict) -> DataPortal: + """ + Creates a DataPortal object from an existing data dictionary. + Useful for model runs where the data has been modified in memory. + + :param data_source: The data dictionary to use. + :return: A new DataPortal object. + """ + namespace = {None: data_source} + dp = DataPortal(data_dict=namespace) + return dp + + # ================================================================================= + # Main Data Loading Engine + # ================================================================================= + + def create_data_dict(self, myopic_index: MyopicIndex | None = None) -> dict[str, Any]: + """ + The main manifest-driven engine for loading model data. + + This method orchestrates the loading process: + 1. Performs setup (source tracing, critical time sets). + 2. Iterates through the manifest from `component_manifest.py`. + 3. For each component, it fetches, filters, and loads the data. + 4. Delegates to custom loader methods for special cases. + 5. Finalizes the data dictionary with derived index sets. + + :param myopic_index: The MyopicIndex for myopic runs. None for other modes. + :return: A dictionary of model data suitable for a DataPortal. + """ + logger.info('Loading data dictionary') + + # --------------------------------------------------------------------- + # Preamble: Setup, source tracing, and loading critical index sets + # --------------------------------------------------------------------- + if myopic_index: + if not isinstance(myopic_index, MyopicIndex): + raise ValueError(f'Received illegal entry for myopic index: {myopic_index}') + if self.config.scenario_mode != TemoaMode.MYOPIC: + raise RuntimeError('Myopic Index passed, but mode is not Myopic.') + elif not myopic_index and self.config.scenario_mode == TemoaMode.MYOPIC: + raise RuntimeError('Mode is myopic, but no MyopicIndex specified.') + + self.myopic_index = myopic_index + + use_raw_data = not ( + self.config.source_trace or self.config.scenario_mode == TemoaMode.MYOPIC + ) + if not use_raw_data: + self._source_trace(myopic_index=myopic_index) + + self._build_efficiency_dataset(use_raw_data=use_raw_data, myopic_index=myopic_index) + + data: dict[str, Any] = {} + cur = self.con.cursor() + M = TemoaModel() + + # Load critical time sets first, as they index other components + if myopic_index: + raw_exist = cur.execute( + 'SELECT period FROM TimePeriod WHERE period < ? ORDER BY sequence', + (myopic_index.base_year,), + ).fetchall() + raw_future = cur.execute( + 'SELECT period FROM TimePeriod WHERE flag = "f" AND period >= ? AND period <= ? ORDER BY sequence', + (myopic_index.base_year, myopic_index.last_year), + ).fetchall() + else: + raw_exist = cur.execute( + "SELECT period FROM TimePeriod WHERE flag = 'e' ORDER BY sequence" + ).fetchall() + raw_future = cur.execute( + "SELECT period FROM TimePeriod WHERE flag = 'f' ORDER BY sequence" + ).fetchall() + self._load_component_data(data, M.time_exist, raw_exist) + self._load_component_data(data, M.time_future, raw_future) + data['time_optimize'] = [p[0] for p in raw_future[:-1]] + + # --------------------------------------------------------------------- + # Manifest-driven loading loop + # --------------------------------------------------------------------- + for item in self.manifest: + # 1. Fetch data from the database + raw_data = self._fetch_data(cur, item, myopic_index) + + # 2. Validate/filter data + filtered_data = self._filter_data(raw_data, item, use_raw_data) + + # 3. Load data using either a custom loader or the standard path + if item.custom_loader_name: + loader_func = getattr(self, item.custom_loader_name) + loader_func(data, raw_data, filtered_data) + else: + # Standard loading path for non-custom components + if not raw_data and not item.is_table_required and item.fallback_data: + logger.warning( + "Table '%s' not found or is empty. Using default values for %s.", + item.table, + item.component.name, + ) + raw_data = item.fallback_data + filtered_data = self._filter_data(raw_data, item, use_raw_data) + + if not filtered_data: + continue + + if len(filtered_data) < len(raw_data): + ignored_count = len(raw_data) - len(filtered_data) + logger.warning( + '%d values for %s failed to validate and were ignored.', + ignored_count, + item.component.name, + ) + self._load_component_data(data, item.component, filtered_data) + + # --------------------------------------------------------------------- + # Finalization + # --------------------------------------------------------------------- + # Load simple config-based or myopic-specific values + self._load_component_data(data, M.TimeSequencing, [(self.config.time_sequencing,)]) + self._load_component_data(data, M.ReserveMarginMethod, [(self.config.reserve_margin,)]) + if myopic_index: + p0_result = cur.execute( + "SELECT min(period) FROM TimePeriod WHERE flag == 'f'" + ).fetchone() + if p0_result: + data[M.MyopicDiscountingYear.name] = {None: int(p0_result[0])} + + # Create derived index sets for parameters now that all base data is loaded + set_data = self.load_param_idx_sets(data=data) + data.update(set_data) + self.data = data + + return data + + # ================================================================================= + # Core Engine Helpers + def _fetch_data(self, cur: Cursor, item: LoadItem, mi: MyopicIndex | None) -> list[tuple]: + """ + Fetches data for a component based on its manifest item. + + :param cur: The database cursor. + :param item: The LoadItem describing what to fetch. + :param mi: The MyopicIndex for period filtering, if applicable. + :return: A list of tuples containing the raw data. + """ + # If this is a custom loader and no columns are specified, no fetch is needed. + if item.custom_loader_name and not item.columns: + return [] + + if not self.table_exists(item.table): + if item.is_table_required: + raise FileNotFoundError(f"Required table '{item.table}' not found in the database.") + return [] + + query = f'SELECT {", ".join(item.columns)} FROM main.{item.table}' + params = [] + + where_clauses = [] + if item.where_clause: + where_clauses.append(f'({item.where_clause})') + if item.is_period_filtered and mi: + where_clauses.append('period >= ? AND period <= ?') + params.extend([mi.base_year, mi.last_demand_year]) + + if where_clauses: + query += ' WHERE ' + ' AND '.join(where_clauses) + + try: + return cur.execute(query, params).fetchall() + except OperationalError as e: + if not item.is_table_required: + logger.info( + 'Could not load optional component %s, likely due to older schema. Skipping. Error: %s', + item.component.name, + e, + ) + return [] + else: + raise + + def _filter_data( + self, values: Sequence[tuple], item: LoadItem, use_raw_data: bool + ) -> Sequence[tuple]: + """ + Applies validation filters to a list of data tuples. + + :param values: The raw data tuples from the database. + :param item: The LoadItem describing the component. + :param use_raw_data: If True, skips filtering. + :return: A filtered sequence of data tuples. + """ + if use_raw_data or not item.validator_name: + return values + + validator = getattr(self, item.validator_name, None) + if validator is None: + return values + + return element_checker.filter_elements( + values=values, validation=validator, value_locations=item.validation_map + ) + + def _load_component_data( + self, data: dict, component: Set | Param, values: Sequence[tuple] + ) -> None: + """ + Loads a sequence of values into the data dictionary for a given Pyomo component. + + :param data: The main data dictionary being built. + :param component: The Pyomo Set or Param to load. + :param values: The sequence of data tuples to load. + """ + if not values: + return + if isinstance(component, Set): + if len(values[0]) == 1: + data[component.name] = [t[0] for t in values] + else: + data[component.name] = list(values) + elif isinstance(component, Param): + # A singleton/scalar Param is represented by a single tuple with one + # element, e.g., [(value,)]. The data dictionary needs to map this + # to {None: value}. An indexed Param has tuples with len > 1, + # e.g., [(key1, key2, value)], which map to {(key1, key2): value}. + if len(values[0]) == 1: + if len(values) > 1: + logger.warning( + "Component '%s' appears to be a scalar Param but has multiple values. Using only the first value.", + component.name, + ) + data[component.name] = {None: values[0][0]} + else: # Indexed Param + data[component.name] = {t[:-1]: t[-1] for t in values} + + def table_exists(self, table_name: str) -> bool: + """ + Checks if a table exists in the database schema. + + :param table_name: The name of the table to check. + :return: True if the table exists, False otherwise. + """ + table_name_check = ( + self.con.cursor() + .execute("SELECT name FROM sqlite_master WHERE type='table' AND name= ?", (table_name,)) + .fetchone() + ) + return bool(table_name_check) + + # ================================================================================= + # Internal Setup Methods + # ================================================================================= + + def _source_trace(self, myopic_index: MyopicIndex | None = None) -> None: + """ + Performs the source-trace analysis to identify viable components. + """ + network_data = network_model_data.build(self.con, myopic_index=myopic_index) + cur = self.con.cursor() + periods = set( + [ + p + for (p,) in cur.execute( + "SELECT period FROM TimePeriod WHERE flag = 'f' ORDER BY period" + ) + ][:-1] # drop last period + ) + + if myopic_index: + periods = { + p for p in periods if myopic_index.base_year <= p <= myopic_index.last_demand_year + } + + self.manager = CommodityNetworkManager(periods=periods, network_data=network_data) + if not self.manager.analyze_network() and not self.config.silent: + print('\nWarning: Orphaned processes detected. See log file for details.') + self.manager.analyze_graphs(self.config) + + def _build_efficiency_dataset( + self, use_raw_data: bool, myopic_index: MyopicIndex | None = None + ) -> None: + """ + Builds the efficiency dataset, applying source-trace filters if necessary. + """ + cur = self.con.cursor() + if myopic_index: + contents = cur.execute( + 'SELECT region, input_comm, tech, vintage, output_comm, efficiency, lifetime ' + 'FROM MyopicEfficiency WHERE vintage + lifetime > ?', + (myopic_index.base_year,), + ).fetchall() + else: + contents = cur.execute( + 'SELECT region, input_comm, tech, vintage, output_comm, efficiency, NULL FROM main.Efficiency' + ).fetchall() + + if use_raw_data: + self.efficiency_values = sorted([row[:-1] for row in contents]) + return + + if not self.manager: + raise RuntimeError('Source trace manager not initialized for filtering.') + + filts = self.manager.build_filters() + self.viable_ritvo = filts['ritvo'] + self.viable_rtv = filts['rtv'] + self.viable_rt = filts['rt'] + self.viable_rpit = filts['rpit'] + self.viable_rpto = filts['rpto'] + self.viable_techs = filts['t'] + self.viable_input_comms = filts['ic'] + self.viable_output_comms = filts['oc'] + self.viable_comms = ViableSet(elements=filts['ic'].members | filts['oc'].members) + rtt = {(r, t1, t2) for r, t1 in filts['rt'].members for t2 in filts['t'].members} + self.viable_rtt = ViableSet( + elements=rtt, exception_loc=0, exception_vals=ViableSet.REGION_REGEXES + ) + + efficiency_entries = { + row[:-1] + for row in contents + if (row[0], row[1], row[2], row[3], row[4]) in self.viable_ritvo.members + } + logger.debug('Polled %d elements from Efficiency tables', len(efficiency_entries)) + self.efficiency_values = sorted(efficiency_entries) + + # ================================================================================= + # Custom Loaders (Grouped by Cohesion) + # ================================================================================= + + # --- Core Model Structure --- + def _load_regional_global_indices( + self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] + ): + """ + Aggregates region and group names from the Region table and all Limit tables. + """ + M = TemoaModel() + cur = self.con.cursor() + regions_and_groups: set[str] = set() + + if self.table_exists('Region'): + regions_and_groups.update( + t[0] for t in cur.execute('SELECT region FROM main.Region').fetchall() + ) + + for table, field_name in tables_with_regional_groups.items(): + if self.table_exists(table): + regions_and_groups.update( + t[0] for t in cur.execute(f'SELECT {field_name} FROM main.{table}').fetchall() + ) + + if None in regions_and_groups: + raise ValueError('A table has an empty entry for its region column.') + + list_of_groups = sorted((t,) for t in regions_and_groups) + self._load_component_data(data, M.regionalGlobalIndices, list_of_groups) + + def _load_tech_group_members( + self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] + ): + """Loads members into the indexed set `tech_group_members`.""" + M = TemoaModel() + validator = self.viable_techs.members if self.viable_techs else None + for group_name, tech in filtered_data: + if validator is None or tech in validator: + store = data.get(M.tech_group_members.name, defaultdict(list)) + store[group_name].append(tech) + data[M.tech_group_members.name] = store + + # --- Time-Related Components --- + def _load_time_season( + self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] + ): + """ + Loads the indexed TimeSeason set and the simple time_season set, + with a dynamic fallback if the table is missing. + """ + M = TemoaModel() + mi = self.myopic_index + time_optimize = data.get('time_optimize', []) + + rows_to_load = [] + if not raw_data: + logger.warning('No TimeSeason table found. Loading a single filler season "S".') + rows_to_load = [(p, 'S') for p in time_optimize] + elif mi: + valid_periods = set(time_optimize) + rows_to_load = [row for row in raw_data if row[0] in valid_periods] + else: + rows_to_load = list(raw_data) + + if not rows_to_load: + data.setdefault(M.time_season.name, []) + return + + unique_seasons = sorted(list(set((row[1],) for row in rows_to_load))) + self._load_component_data(data, M.time_season, unique_seasons) + + for period, season in rows_to_load: + store = data.get(M.TimeSeason.name, defaultdict(list)) + store[period].append(season) + data[M.TimeSeason.name] = store + + def _load_time_season_sequential( + self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] + ): + """ + Composite loader for TimeSeasonSequential and its associated index sets. + """ + M = TemoaModel() + self._load_component_data(data, M.TimeSeasonSequential, filtered_data) + if filtered_data: + ordered_data = [row[0:3] for row in filtered_data] + self._load_component_data(data, M.ordered_season_sequential, ordered_data) + seq_data = sorted(list(set((row[1],) for row in filtered_data))) + self._load_component_data(data, M.time_season_sequential, seq_data) + + def _load_seg_frac(self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple]): + """Handles dynamic fallbacks for SegFrac if its table is missing.""" + M = TemoaModel() + if filtered_data: + self._load_component_data(data, M.SegFrac, filtered_data) + else: + logger.warning('No TimeSegmentFraction table found. Generating default SegFrac values.') + time_optimize = data.get('time_optimize', []) + fallback = [(p, 'S', 'D', 1.0) for p in time_optimize] + self._load_component_data(data, M.SegFrac, fallback) + + # --- Capacity and Cost Components --- + def _load_existing_capacity( + self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] + ): + """ + Handles different queries for myopic vs. standard runs and also + populates the `tech_exist` set. + """ + M = TemoaModel() + cur = self.con.cursor() + mi = self.myopic_index + + rows_to_load = [] + if mi: + prev_period_res = cur.execute( + 'SELECT MAX(period) FROM TimePeriod WHERE period < ?', (mi.base_year,) + ).fetchone() + prev_period = prev_period_res[0] if prev_period_res else -1 + rows_to_load = cur.execute( + 'SELECT region, tech, vintage, capacity FROM OutputBuiltCapacity WHERE vintage <= ? AND scenario = ? ' + 'UNION SELECT region, tech, vintage, capacity FROM ExistingCapacity', + (prev_period, self.config.scenario), + ).fetchall() + elif self.table_exists('ExistingCapacity'): + rows_to_load = cur.execute( + 'SELECT region, tech, vintage, capacity FROM ExistingCapacity' + ).fetchall() + + self._load_component_data(data, M.ExistingCapacity, rows_to_load) + if rows_to_load: + tech_exist_data = sorted(list({(row[1],) for row in rows_to_load})) + self._load_component_data(data, M.tech_exist, tech_exist_data) + + def _load_cost_invest( + self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] + ): + """Handles myopic period filtering for CostInvest.""" + M = TemoaModel() + mi = self.myopic_index + data_to_load = [row for row in filtered_data if not mi or row[2] >= mi.base_year] + self._load_component_data(data, M.CostInvest, data_to_load) + + def _load_loan_rate( + self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] + ): + """Handles myopic period filtering for LoanRate.""" + M = TemoaModel() + mi = self.myopic_index + data_to_load = [row for row in filtered_data if not mi or row[2] >= mi.base_year] + self._load_component_data(data, M.LoanRate, data_to_load) + + # --- Singleton and Configuration-based Components --- + def _load_days_per_period( + self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] + ): + """Loads the singleton DaysPerPeriod, with a fallback.""" + M = TemoaModel() + value = 365 + if filtered_data: + value = int(filtered_data[0][0]) + else: + logger.info('No value for days_per_period found. Assuming 365 days per period.') + data[M.DaysPerPeriod.name] = {None: value} + + def _load_global_discount_rate( + self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] + ): + """Loads the required singleton GlobalDiscountRate.""" + M = TemoaModel() + if filtered_data: + data[M.GlobalDiscountRate.name] = {None: float(filtered_data[0][0])} + else: + raise ValueError( + "Missing required parameter: 'global_discount_rate' not found in MetaDataReal table." + ) + + def _load_default_loan_rate( + self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] + ): + """Loads the optional singleton DefaultLoanRate.""" + M = TemoaModel() + if filtered_data: + data[M.DefaultLoanRate.name] = {None: float(filtered_data[0][0])} + + # --- Operational Constraints and Parameters --- + def _load_efficiency( + self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] + ): + """Loads the main Efficiency parameter, which is pre-calculated.""" + M = TemoaModel() + self._load_component_data(data, M.Efficiency, self.efficiency_values) + + def _load_linked_techs( + self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] + ): + """Provides critical error checking for LinkedTechs.""" + item = self.manifest_map['LinkedTechs'] + self._load_component_data(data, item.component, filtered_data) + if len(filtered_data) < len(raw_data): + missing = set(raw_data) - set(filtered_data) + valid_techs = self.viable_techs.members if self.viable_techs else set() + for entry in missing: + p_tech, d_tech = entry[1], entry[3] + if p_tech in valid_techs or d_tech in valid_techs: + msg = ( + 'A LinkedTech entry %s was invalidated, but one of its component technologies ' + 'remains viable. This could lead to incorrect model behavior.' + ) + logger.error(msg, entry) + raise RuntimeError(msg % (entry,)) + + def _load_ramping_down( + self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] + ): + """Composite loader for RampDownHourly and its index set `tech_downramping`.""" + M = TemoaModel() + self._load_component_data(data, M.RampDownHourly, filtered_data) + if filtered_data: + tech_data = sorted(list({(row[1],) for row in filtered_data})) + tech_filtered = self._filter_data( + tech_data, self.manifest_map[M.tech_downramping.name], use_raw_data=False + ) + self._load_component_data(data, M.tech_downramping, tech_filtered) + + def _load_ramping_up( + self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] + ): + """Composite loader for RampUpHourly and its index set `tech_upramping`.""" + M = TemoaModel() + self._load_component_data(data, M.RampUpHourly, filtered_data) + if filtered_data: + tech_data = sorted(list({(row[1],) for row in filtered_data})) + tech_filtered = self._filter_data( + tech_data, self.manifest_map[M.tech_upramping.name], use_raw_data=False + ) + self._load_component_data(data, M.tech_upramping, tech_filtered) + + def _load_rps_requirement( + self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] + ): + """Handles deprecation warning for RenewablePortfolioStandard.""" + M = TemoaModel() + self._load_component_data(data, M.RenewablePortfolioStandard, filtered_data) + if filtered_data: + logger.warning( + 'The RenewablePortfolioStandard constraint is deprecated. Use LimitActivityShare instead. ' + 'The constraint has been applied but this feature may be removed in the future.' + ) + + def _load_limit_tech_input_split( + self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] + ): + """Provides detailed warnings for filtered LimitTechInputSplit data.""" + item = self.manifest_map['LimitTechInputSplit'] + self._load_component_data(data, item.component, filtered_data) + if len(filtered_data) < len(raw_data): + missing = set(raw_data) - set(filtered_data) + for r, p, i, t, _, _ in sorted(missing, key=lambda x: (x[0], x[1], x[3], x[2])): + logger.warning( + 'Tech Input Split in region %s, period %d for tech %s with input %s ' + 'was removed because the path is invalid/orphaned. Review other warnings.', + r, + p, + t, + i, + ) + + def _load_limit_tech_input_split_annual( + self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] + ): + """Provides detailed warnings for filtered LimitTechInputSplitAnnual data.""" + item = self.manifest_map['LimitTechInputSplitAnnual'] + self._load_component_data(data, item.component, filtered_data) + if len(filtered_data) < len(raw_data): + missing = set(raw_data) - set(filtered_data) + for r, p, i, t, _, _ in sorted(missing, key=lambda x: (x[0], x[1], x[3], x[2])): + logger.warning( + 'Tech Input Split Annual in region %s, period %d for tech %s with input %s ' + 'was removed because the path is invalid/orphaned. Review other warnings.', + r, + p, + t, + i, + ) + + def _load_limit_tech_output_split( + self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] + ): + """Provides detailed warnings for filtered LimitTechOutputSplit data.""" + item = self.manifest_map['LimitTechOutputSplit'] + self._load_component_data(data, item.component, filtered_data) + if len(filtered_data) < len(raw_data): + missing = set(raw_data) - set(filtered_data) + for r, p, t, o, _, _ in sorted(missing, key=lambda x: (x[0], x[1], x[2], x[3])): + logger.warning( + 'Tech Output Split in region %s, period %d for tech %s with output %s ' + 'was removed because the path is invalid/orphaned. Review other warnings.', + r, + p, + t, + o, + ) + + def _load_limit_tech_output_split_annual( + self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] + ): + """Provides detailed warnings for filtered LimitTechOutputSplitAnnual data.""" + item = self.manifest_map['LimitTechOutputSplitAnnual'] + self._load_component_data(data, item.component, filtered_data) + if len(filtered_data) < len(raw_data): + missing = set(raw_data) - set(filtered_data) + for r, p, t, o, _, _ in sorted(missing, key=lambda x: (x[0], x[1], x[2], x[3])): + logger.warning( + 'Tech Output Split Annual in region %s, period %d for tech %s with output %s ' + 'was removed because the path is invalid/orphaned. Review other warnings.', + r, + p, + t, + o, + ) + + # ================================================================================= + # Finalizer Method + # ================================================================================= + + def load_param_idx_sets(self, data: dict) -> dict: + """ + Builds a dictionary of sparse sets used for indexing parameters. + This is a final data enhancement step that runs after all primary data + has been loaded. + + :param data: The main data dictionary. + :return: A dictionary of the new index sets to be added. + """ + M = TemoaModel() + param_idx_sets = { + M.CostInvest.name: M.CostInvest_rtv.name, + M.CostEmission.name: M.CostEmission_rpe.name, + M.Demand.name: M.DemandConstraint_rpc.name, + M.LimitEmission.name: M.LimitEmissionConstraint_rpe.name, + M.LimitActivity.name: M.LimitActivityConstraint_rpt.name, + M.LimitSeasonalCapacityFactor.name: M.LimitSeasonalCapacityFactorConstraint_rpst.name, + M.LimitActivityShare.name: M.LimitActivityShareConstraint_rpgg.name, + M.LimitAnnualCapacityFactor.name: M.LimitAnnualCapacityFactorConstraint_rpto.name, + M.LimitCapacity.name: M.LimitCapacityConstraint_rpt.name, + M.LimitCapacityShare.name: M.LimitCapacityShareConstraint_rpgg.name, + M.LimitNewCapacity.name: M.LimitNewCapacityConstraint_rpt.name, + M.LimitNewCapacityShare.name: M.LimitNewCapacityShareConstraint_rpgg.name, + M.LimitResource.name: M.LimitResourceConstraint_rt.name, + M.LimitStorageFraction.name: M.LimitStorageFractionConstraint_rpsdtv.name, + M.RenewablePortfolioStandard.name: M.RenewablePortfolioStandardConstraint_rpg.name, + } + + res = {} + for p_name, s_name in param_idx_sets.items(): + param_data = data.get(p_name) + if param_data: + res[s_name] = list(param_data.keys()) + return res diff --git a/temoa/data_io/loader_manifest.py b/temoa/data_io/loader_manifest.py new file mode 100644 index 000000000..552cc3d52 --- /dev/null +++ b/temoa/data_io/loader_manifest.py @@ -0,0 +1,52 @@ +# temoa/data_io/loader_manifest.py +""" +Defines the data structure for the data loading manifest. + +This module contains the `LoadItem` dataclass, which serves as the schema for +the declarative manifest used by the `HybridLoader`. Each `LoadItem` instance +provides the loader with all the necessary metadata to fetch, validate, and +load a single Pyomo component (a `Set` or `Param`) from the database. + +""" + +from dataclasses import dataclass, field +from typing import Any, Optional + +from pyomo.core import Param, Set + + +@dataclass +class LoadItem: + """ + Describes a single data component to load from the database. + + Attributes: + component: The target Pyomo `Set` or `Param` object to be loaded. + table: The name of the source table in the SQLite database. + columns: A list of column names to select from the table. The last + column is assumed to be the value for a `Param`. + validator_name: Optional. The name of a `ViableSet` attribute on the + `HybridLoader` instance, used for source-trace filtering. + validation_map: A tuple indicating which column indices in the data + correspond to the elements needing validation (e.g., region, tech). + where_clause: Optional. An SQL `WHERE` clause to apply when querying. + is_period_filtered: If True, the loader automatically adds a `WHERE` + clause to filter by the active periods in a myopic run. + is_table_required: If True, the loader will raise an error if the + table does not exist. + custom_loader_name: Optional. The name of a specialized method in + `HybridLoader` to handle non-standard loading logic for this component. + fallback_data: Optional. A list of default data tuples to use if the + table is missing or returns no data. + """ + + component: Set | Param + table: str + columns: list[str] + validator_name: Optional[str] = None + validation_map: tuple[int, ...] = field(default_factory=tuple) + where_clause: Optional[str] = None + is_period_filtered: bool = True + is_table_required: bool = True + custom_loader_name: Optional[str] = None + fallback_data: Optional[list[tuple[Any, ...]]] = None diff --git a/temoa/extensions/method_of_morris/morris.py b/temoa/extensions/method_of_morris/morris.py index 7de980326..50d952be4 100644 --- a/temoa/extensions/method_of_morris/morris.py +++ b/temoa/extensions/method_of_morris/morris.py @@ -6,9 +6,9 @@ from definitions import PROJECT_ROOT from temoa._internal import run_actions -from temoa._internal.hybrid_loader import HybridLoader from temoa._internal.table_writer import TableWriter from temoa.core.config import TemoaConfig +from temoa.data_io.hybrid_loader import HybridLoader start_time = time.time() import sqlite3 diff --git a/temoa/extensions/method_of_morris/morris_sequencer.py b/temoa/extensions/method_of_morris/morris_sequencer.py index b4bde836f..9e7267d8e 100644 --- a/temoa/extensions/method_of_morris/morris_sequencer.py +++ b/temoa/extensions/method_of_morris/morris_sequencer.py @@ -48,9 +48,9 @@ from SALib.util import compute_groups_matrix, read_param_file from definitions import PROJECT_ROOT, get_OUTPUT_PATH -from temoa._internal.hybrid_loader import HybridLoader from temoa._internal.table_writer import TableWriter from temoa.core.config import TemoaConfig +from temoa.data_io.hybrid_loader import HybridLoader from temoa.extensions.method_of_morris.morris_evaluate import evaluate logger = logging.getLogger(__name__) diff --git a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py index 92d8eefed..66e92e567 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py +++ b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py @@ -44,12 +44,12 @@ from pyomo.opt import check_optimal_termination from definitions import PROJECT_ROOT, get_OUTPUT_PATH -from temoa._internal.hybrid_loader import HybridLoader from temoa._internal.run_actions import build_instance from temoa._internal.table_writer import TableWriter from temoa.components.costs import TotalCost_rule from temoa.core.config import TemoaConfig from temoa.core.model import TemoaModel +from temoa.data_io.hybrid_loader import HybridLoader from temoa.extensions.modeling_to_generate_alternatives.manager_factory import get_manager from temoa.extensions.modeling_to_generate_alternatives.mga_constants import MgaAxis, MgaWeighting from temoa.extensions.modeling_to_generate_alternatives.vector_manager import VectorManager diff --git a/temoa/extensions/monte_carlo/mc_run.py b/temoa/extensions/monte_carlo/mc_run.py index aef841a0c..537bea1fd 100644 --- a/temoa/extensions/monte_carlo/mc_run.py +++ b/temoa/extensions/monte_carlo/mc_run.py @@ -35,9 +35,9 @@ from pyomo.dataportal import DataPortal from definitions import PROJECT_ROOT -from temoa._internal.hybrid_loader import HybridLoader from temoa.core.config import TemoaConfig from temoa.core.model import TemoaModel +from temoa.data_io.hybrid_loader import HybridLoader logger = getLogger(__name__) diff --git a/temoa/extensions/monte_carlo/mc_sequencer.py b/temoa/extensions/monte_carlo/mc_sequencer.py index 5823284a7..44945f68d 100644 --- a/temoa/extensions/monte_carlo/mc_sequencer.py +++ b/temoa/extensions/monte_carlo/mc_sequencer.py @@ -42,9 +42,9 @@ from definitions import PROJECT_ROOT, get_OUTPUT_PATH from temoa._internal.data_brick import DataBrick -from temoa._internal.hybrid_loader import HybridLoader from temoa._internal.table_writer import TableWriter from temoa.core.config import TemoaConfig +from temoa.data_io.hybrid_loader import HybridLoader from temoa.extensions.monte_carlo.mc_run import MCRunFactory from temoa.extensions.monte_carlo.mc_worker import MCWorker diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index faf467926..9a073127e 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -36,10 +36,10 @@ import definitions from temoa._internal import run_actions -from temoa._internal.hybrid_loader import HybridLoader from temoa._internal.table_writer import TableWriter from temoa.core.config import TemoaConfig from temoa.core.model import TemoaModel +from temoa.data_io.hybrid_loader import HybridLoader from temoa.data_processing.DB_to_Excel import make_excel from temoa.extensions.myopic.myopic_index import MyopicIndex from temoa.extensions.myopic.myopic_progress_mapper import MyopicProgressMapper diff --git a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py index a0e1cc6b9..6b4b92725 100644 --- a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py +++ b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py @@ -38,12 +38,12 @@ from pyomo.dataportal import DataPortal from pyomo.opt import check_optimal_termination -from temoa._internal.hybrid_loader import HybridLoader from temoa._internal.run_actions import build_instance, handle_results, save_lp, solve_instance from temoa._internal.table_writer import TableWriter from temoa.components.costs import TotalCost_rule from temoa.core.config import TemoaConfig from temoa.core.model import TemoaModel +from temoa.data_io.hybrid_loader import HybridLoader from temoa.extensions.single_vector_mga.output_summary import summarize from temoa.model_checking.pricing_check import price_checker From be24fff5558d00b8b088c0c3032067ebe06571bf Mon Sep 17 00:00:00 2001 From: idelder <35704891+idelder@users.noreply.github.com> Date: Tue, 14 Oct 2025 11:30:59 -0400 Subject: [PATCH 242/587] Fix database schema to include output_comm in primary key of LimitAnnualCapacityFactor table (#163) --- data_files/example_dbs/materials.sql | 2 +- data_files/example_dbs/morris_utopia.sql | 2 +- data_files/example_dbs/seasonal_storage.sql | 2 +- data_files/example_dbs/stepped_demand.sql | 2 +- data_files/example_dbs/survival_curve.sql | 2 +- data_files/example_dbs/test_system.sql | 2 +- data_files/example_dbs/utopia.sql | 2 +- data_files/temoa_basics_2.sql | 2 +- data_files/temoa_schema_v3_1.sql | 2 +- tests/testing_data/annualised_demand.sql | 2 +- tests/testing_data/emissions.sql | 2 +- tests/testing_data/materials.sql | 2 +- tests/testing_data/mediumville.sql | 2 +- tests/testing_data/seasonal_storage.sql | 2 +- tests/testing_data/simple_linked_tech.sql | 2 +- tests/testing_data/storageville.sql | 2 +- tests/testing_data/survival_curve.sql | 2 +- tests/testing_data/test_system.sql | 2 +- tests/testing_data/utopia.sql | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index b0242fd4a..d77376460 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -943,7 +943,7 @@ CREATE TABLE LimitAnnualCapacityFactor REFERENCES Operator (operator), factor REAL, notes TEXT, - PRIMARY KEY (region, period, tech, operator), + PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE LimitCapacity diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index e9c503a47..eba96479a 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -981,7 +981,7 @@ CREATE TABLE LimitAnnualCapacityFactor REFERENCES Operator (operator), factor REAL, notes TEXT, - PRIMARY KEY (region, period, tech, operator), + PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE LimitCapacity diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql index 370e84415..2c368a71a 100644 --- a/data_files/example_dbs/seasonal_storage.sql +++ b/data_files/example_dbs/seasonal_storage.sql @@ -561,7 +561,7 @@ CREATE TABLE LimitAnnualCapacityFactor REFERENCES Operator (operator), factor REAL, notes TEXT, - PRIMARY KEY (region, period, tech, operator), + PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE LimitCapacity diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index 3f146a143..a399d02cd 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -718,7 +718,7 @@ CREATE TABLE LimitAnnualCapacityFactor REFERENCES Operator (operator), factor REAL, notes TEXT, - PRIMARY KEY (region, period, tech, operator), + PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE LimitCapacity diff --git a/data_files/example_dbs/survival_curve.sql b/data_files/example_dbs/survival_curve.sql index d0b689103..df443dd87 100644 --- a/data_files/example_dbs/survival_curve.sql +++ b/data_files/example_dbs/survival_curve.sql @@ -591,7 +591,7 @@ CREATE TABLE LimitAnnualCapacityFactor REFERENCES Operator (operator), factor REAL, notes TEXT, - PRIMARY KEY (region, period, tech, operator), + PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE LimitCapacity diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index 8a09f21a5..8933934ea 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -953,7 +953,7 @@ CREATE TABLE LimitAnnualCapacityFactor REFERENCES Operator (operator), factor REAL, notes TEXT, - PRIMARY KEY (region, period, tech, operator), + PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE LimitCapacity diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 4fe2c58f6..f32cc2236 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -975,7 +975,7 @@ CREATE TABLE LimitAnnualCapacityFactor REFERENCES Operator (operator), factor REAL, notes TEXT, - PRIMARY KEY (region, period, tech, operator), + PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE LimitCapacity diff --git a/data_files/temoa_basics_2.sql b/data_files/temoa_basics_2.sql index 3606512d7..24a4797b5 100644 --- a/data_files/temoa_basics_2.sql +++ b/data_files/temoa_basics_2.sql @@ -261,7 +261,7 @@ CREATE TABLE IF NOT EXISTS LimitAnnualCapacityFactor REFERENCES Operator (operator), factor REAL, notes TEXT, - PRIMARY KEY (region, period, tech, operator), + PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE IF NOT EXISTS LimitCapacity diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index 0f748cf85..7626b3791 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -526,7 +526,7 @@ CREATE TABLE IF NOT EXISTS LimitAnnualCapacityFactor REFERENCES Operator (operator), factor REAL, notes TEXT, - PRIMARY KEY (region, period, tech, operator), + PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE IF NOT EXISTS LimitCapacity diff --git a/tests/testing_data/annualised_demand.sql b/tests/testing_data/annualised_demand.sql index 4740e32e8..5a263ae28 100644 --- a/tests/testing_data/annualised_demand.sql +++ b/tests/testing_data/annualised_demand.sql @@ -535,7 +535,7 @@ CREATE TABLE LimitAnnualCapacityFactor REFERENCES Operator (operator), factor REAL, notes TEXT, - PRIMARY KEY (region, period, tech, operator), + PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE LimitCapacity diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 3840a1bd6..2757828a8 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -568,7 +568,7 @@ CREATE TABLE LimitAnnualCapacityFactor REFERENCES Operator (operator), factor REAL, notes TEXT, - PRIMARY KEY (region, period, tech, operator), + PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE LimitCapacity diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index b0242fd4a..d77376460 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -943,7 +943,7 @@ CREATE TABLE LimitAnnualCapacityFactor REFERENCES Operator (operator), factor REAL, notes TEXT, - PRIMARY KEY (region, period, tech, operator), + PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE LimitCapacity diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 6739e0d03..9fff3b221 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -641,7 +641,7 @@ CREATE TABLE LimitAnnualCapacityFactor REFERENCES Operator (operator), factor REAL, notes TEXT, - PRIMARY KEY (region, period, tech, operator), + PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE LimitCapacity diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index 370e84415..2c368a71a 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -561,7 +561,7 @@ CREATE TABLE LimitAnnualCapacityFactor REFERENCES Operator (operator), factor REAL, notes TEXT, - PRIMARY KEY (region, period, tech, operator), + PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE LimitCapacity diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index fc762787c..607f9e249 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -540,7 +540,7 @@ CREATE TABLE LimitAnnualCapacityFactor REFERENCES Operator (operator), factor REAL, notes TEXT, - PRIMARY KEY (region, period, tech, operator), + PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE LimitCapacity diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index ae3f2979d..c9e7288f8 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -549,7 +549,7 @@ CREATE TABLE LimitAnnualCapacityFactor REFERENCES Operator (operator), factor REAL, notes TEXT, - PRIMARY KEY (region, period, tech, operator), + PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE LimitCapacity diff --git a/tests/testing_data/survival_curve.sql b/tests/testing_data/survival_curve.sql index d0b689103..df443dd87 100644 --- a/tests/testing_data/survival_curve.sql +++ b/tests/testing_data/survival_curve.sql @@ -591,7 +591,7 @@ CREATE TABLE LimitAnnualCapacityFactor REFERENCES Operator (operator), factor REAL, notes TEXT, - PRIMARY KEY (region, period, tech, operator), + PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE LimitCapacity diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 8a09f21a5..8933934ea 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -953,7 +953,7 @@ CREATE TABLE LimitAnnualCapacityFactor REFERENCES Operator (operator), factor REAL, notes TEXT, - PRIMARY KEY (region, period, tech, operator), + PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE LimitCapacity diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 4fe2c58f6..f32cc2236 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -975,7 +975,7 @@ CREATE TABLE LimitAnnualCapacityFactor REFERENCES Operator (operator), factor REAL, notes TEXT, - PRIMARY KEY (region, period, tech, operator), + PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE LimitCapacity From eff7cbad27df4b61f7a223ca1ad092223a6e8fca Mon Sep 17 00:00:00 2001 From: idelder <35704891+idelder@users.noreply.github.com> Date: Wed, 15 Oct 2025 10:42:52 -0400 Subject: [PATCH 243/587] Fix lifetime check in db migrator to include existing vintages (#162) --- temoa/utilities/db_migration_v3_to_v3_1.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/temoa/utilities/db_migration_v3_to_v3_1.py b/temoa/utilities/db_migration_v3_to_v3_1.py index cc55d96b9..893fed2b6 100644 --- a/temoa/utilities/db_migration_v3_to_v3_1.py +++ b/temoa/utilities/db_migration_v3_to_v3_1.py @@ -248,9 +248,10 @@ def column_check(old_name: str, new_name: str) -> bool: con_new.executemany(query, data) print(f'Transfered {len(data)} rows from {old_name} to {new_name}') -# Need these -time_future = cur.execute('SELECT period FROM TimePeriod WHERE flag == "f"').fetchall() -time_optimize = [p[0] for p in time_future[0:-1]] +time_all = [ + p[0] for p in cur.execute('SELECT period FROM TimePeriod').fetchall() +] +time_all = sorted(time_all)[0:-1] # Exclude horizon end # get lifetimes. Major headache but needs to be done lifetime_process = dict() @@ -259,12 +260,18 @@ def column_check(old_name: str, new_name: str) -> bool: lifetime_process[rtv] = TemoaModel.default_lifetime_tech data = cur.execute('SELECT region, tech, lifetime FROM LifetimeTech').fetchall() for rtl in data: - for v in time_optimize: + for v in time_all: lifetime_process[*rtl[0:2], v] = rtl[2] data = cur.execute('SELECT region, tech, vintage, lifetime FROM LifetimeProcess').fetchall() for rtvl in data: lifetime_process[rtvl[0:3]] = rtvl[3] +# Planning periods to add to period indices +time_optimize = [ + p[0] for p in cur.execute('SELECT period FROM TimePeriod WHERE flag == "f"').fetchall() +] +time_optimize = sorted(time_optimize)[0:-1] # Exclude horizon end + # add period indexing to seasonal tables print('\n --- Adding period index to some tables ---') for old_name, new_name in period_added_tables: From e5f6bc737197e06cb24ccb89a0f6d19f08deb23c Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 18 Oct 2025 18:59:59 -0400 Subject: [PATCH 244/587] adding stubs for pyomo created with stubgen, updating coderabbit config to ignore the large stubs dir, adding mypy config to pyproject along with typing libs --- .coderabbit.yaml | 2 +- .gitignore | 1 + .pre-commit-config.yaml | 11 +- pyproject.toml | 100 ++- requirements-dev.txt | 28 +- stubs/pyomo/__init__.pyi | 4 + stubs/pyomo/_archive/__init__.pyi | 1 + stubs/pyomo/_archive/chull.pyi | 0 stubs/pyomo/_archive/component_map.pyi | 1 + stubs/pyomo/_archive/component_set.pyi | 1 + stubs/pyomo/_archive/current.pyi | 127 ++++ stubs/pyomo/_archive/plugin.pyi | 30 + stubs/pyomo/_archive/rangeset.pyi | 1 + stubs/pyomo/_archive/register_numpy_types.pyi | 18 + stubs/pyomo/_archive/sets.pyi | 7 + stubs/pyomo/_archive/template_expr.pyi | 2 + stubs/pyomo/common/__init__.pyi | 17 + stubs/pyomo/common/_command.pyi | 7 + stubs/pyomo/common/_common.pyi | 6 + stubs/pyomo/common/autoslots.pyi | 30 + stubs/pyomo/common/backports.pyi | 1 + stubs/pyomo/common/cmake_builder.pyi | 7 + stubs/pyomo/common/collections/__init__.pyi | 13 + stubs/pyomo/common/collections/bunch.pyi | 10 + .../common/collections/component_map.pyi | 31 + .../common/collections/component_set.pyi | 19 + stubs/pyomo/common/collections/orderedset.pyi | 18 + stubs/pyomo/common/config.pyi | 238 +++++++ stubs/pyomo/common/dependencies.pyi | 128 ++++ stubs/pyomo/common/deprecation.pyi | 45 ++ stubs/pyomo/common/download.pyi | 41 ++ stubs/pyomo/common/enums.pyi | 28 + stubs/pyomo/common/env.pyi | 58 ++ stubs/pyomo/common/envvar.pyi | 3 + stubs/pyomo/common/errors.pyi | 19 + stubs/pyomo/common/extensions.pyi | 3 + stubs/pyomo/common/factory.pyi | 9 + stubs/pyomo/common/fileutils.pyi | 65 ++ stubs/pyomo/common/flags.pyi | 8 + stubs/pyomo/common/formatting.pyi | 17 + stubs/pyomo/common/gc_manager.pyi | 22 + stubs/pyomo/common/gsl.pyi | 8 + stubs/pyomo/common/log.pyi | 96 +++ stubs/pyomo/common/modeling.pyi | 8 + stubs/pyomo/common/multithread.pyi | 22 + stubs/pyomo/common/numeric_types.pyi | 22 + stubs/pyomo/common/plugin_base.pyi | 66 ++ stubs/pyomo/common/plugins.pyi | 1 + stubs/pyomo/common/pyomo_typing.pyi | 4 + stubs/pyomo/common/shutdown.pyi | 1 + stubs/pyomo/common/sorting.pyi | 5 + stubs/pyomo/common/tee.pyi | 89 +++ stubs/pyomo/common/tempfiles.pyi | 65 ++ stubs/pyomo/common/timing.pyi | 97 +++ stubs/pyomo/common/unittest.pyi | 86 +++ stubs/pyomo/contrib/__init__.pyi | 1 + .../alternative_solutions/__init__.pyi | 15 + .../alternative_solutions/aos_utils.pyi | 24 + .../contrib/alternative_solutions/balas.pyi | 19 + .../contrib/alternative_solutions/lp_enum.pyi | 22 + .../lp_enum_solnpool.pyi | 42 ++ .../contrib/alternative_solutions/obbt.pyi | 31 + .../alternative_solutions/shifted_lp.pyi | 8 + .../alternative_solutions/solnpool.pyi | 17 + .../alternative_solutions/solution.pyi | 22 + .../contrib/ampl_function_demo/__init__.pyi | 0 .../contrib/ampl_function_demo/build.pyi | 6 + .../contrib/ampl_function_demo/plugins.pyi | 6 + stubs/pyomo/contrib/appsi/__init__.pyi | 4 + stubs/pyomo/contrib/appsi/base.pyi | 290 +++++++++ stubs/pyomo/contrib/appsi/build.pyi | 5 + stubs/pyomo/contrib/appsi/cmodel/__init__.pyi | 4 + .../contrib/appsi/cmodel/appsi_cmodel.pyi | 258 ++++++++ .../pyomo/contrib/appsi/examples/__init__.pyi | 0 .../appsi/examples/getting_started.pyi | 4 + stubs/pyomo/contrib/appsi/fbbt.pyi | 48 ++ stubs/pyomo/contrib/appsi/plugins.pyi | 12 + .../pyomo/contrib/appsi/solvers/__init__.pyi | 9 + stubs/pyomo/contrib/appsi/solvers/cbc.pyi | 86 +++ stubs/pyomo/contrib/appsi/solvers/cplex.pyi | 87 +++ stubs/pyomo/contrib/appsi/solvers/gurobi.pyi | 177 +++++ stubs/pyomo/contrib/appsi/solvers/highs.pyi | 121 ++++ stubs/pyomo/contrib/appsi/solvers/ipopt.pyi | 90 +++ stubs/pyomo/contrib/appsi/solvers/maingo.pyi | 96 +++ .../appsi/solvers/maingo_solvermodel.pyi | 42 ++ stubs/pyomo/contrib/appsi/solvers/wntr.pyi | 85 +++ stubs/pyomo/contrib/appsi/utils/__init__.pyi | 4 + .../utils/collect_vars_and_named_exprs.pyi | 13 + .../contrib/appsi/utils/get_objective.pyi | 3 + .../pyomo/contrib/appsi/writers/__init__.pyi | 2 + stubs/pyomo/contrib/appsi/writers/config.pyi | 3 + .../pyomo/contrib/appsi/writers/lp_writer.pyi | 36 ++ .../pyomo/contrib/appsi/writers/nl_writer.pyi | 38 ++ stubs/pyomo/contrib/benders/__init__.pyi | 0 stubs/pyomo/contrib/benders/benders_cuts.pyi | 40 ++ .../contrib/benders/examples/__init__.pyi | 0 .../pyomo/contrib/benders/examples/farmer.pyi | 21 + .../contrib/benders/examples/grothey_ex.pyi | 5 + .../contrib/community_detection/__init__.pyi | 0 .../community_detection/community_graph.pyi | 14 + .../contrib/community_detection/detection.pyi | 64 ++ .../contrib/community_detection/event_log.pyi | 6 + .../contrib/community_detection/plugins.pyi | 1 + stubs/pyomo/contrib/cp/__init__.pyi | 25 + stubs/pyomo/contrib/cp/interval_var.pyi | 63 ++ stubs/pyomo/contrib/cp/plugins.pyi | 1 + stubs/pyomo/contrib/cp/repn/__init__.pyi | 0 .../pyomo/contrib/cp/repn/docplex_writer.pyi | 151 +++++ .../contrib/cp/scheduling_expr/__init__.pyi | 0 .../precedence_expressions.pyi | 11 + .../cp/scheduling_expr/scheduling_logic.pyi | 9 + .../scheduling_expr/sequence_expressions.pyi | 22 + .../step_function_expressions.pyi | 48 ++ stubs/pyomo/contrib/cp/sequence_var.pyi | 26 + stubs/pyomo/contrib/cp/transform/__init__.pyi | 0 .../logical_to_disjunctive_program.pyi | 23 + .../logical_to_disjunctive_walker.pyi | 33 + .../contrib/cspline_external/__init__.pyi | 0 .../pyomo/contrib/cspline_external/build.pyi | 6 + .../cspline_external/cspline_parameters.pyi | 30 + .../contrib/cspline_external/plugins.pyi | 6 + stubs/pyomo/contrib/doe/__init__.pyi | 17 + stubs/pyomo/contrib/doe/doe.pyi | 103 +++ stubs/pyomo/contrib/doe/examples/__init__.pyi | 0 .../reactor_compute_factorial_FIM.pyi | 5 + .../contrib/doe/examples/reactor_example.pyi | 5 + .../doe/examples/reactor_experiment.pyi | 16 + stubs/pyomo/contrib/doe/utils.pyi | 5 + stubs/pyomo/contrib/example/__init__.pyi | 3 + stubs/pyomo/contrib/example/bar.pyi | 1 + stubs/pyomo/contrib/example/foo.pyi | 1 + .../contrib/example/plugins/__init__.pyi | 1 + .../contrib/example/plugins/ex_plugin.pyi | 6 + stubs/pyomo/contrib/fbbt/__init__.pyi | 0 .../contrib/fbbt/expression_bounds_walker.pyi | 68 ++ stubs/pyomo/contrib/fbbt/fbbt.pyi | 76 +++ stubs/pyomo/contrib/fbbt/interval.pyi | 46 ++ stubs/pyomo/contrib/fme/__init__.pyi | 0 .../fme/fourier_motzkin_elimination.pyi | 37 ++ stubs/pyomo/contrib/fme/plugins.pyi | 1 + stubs/pyomo/contrib/gdp_bounds/__init__.pyi | 0 .../contrib/gdp_bounds/compute_bounds.pyi | 28 + stubs/pyomo/contrib/gdp_bounds/info.pyi | 10 + stubs/pyomo/contrib/gdp_bounds/plugins.pyi | 1 + stubs/pyomo/contrib/gdpopt/GDPopt.pyi | 21 + stubs/pyomo/contrib/gdpopt/__init__.pyi | 3 + .../contrib/gdpopt/algorithm_base_class.pyi | 62 ++ .../pyomo/contrib/gdpopt/branch_and_bound.pyi | 47 ++ stubs/pyomo/contrib/gdpopt/config_options.pyi | 18 + .../contrib/gdpopt/create_oa_subproblems.pyi | 38 ++ stubs/pyomo/contrib/gdpopt/cut_generation.pyi | 7 + .../gdpopt/discrete_problem_initialize.pyi | 42 ++ stubs/pyomo/contrib/gdpopt/enumerate.pyi | 25 + stubs/pyomo/contrib/gdpopt/gloa.pyi | 32 + stubs/pyomo/contrib/gdpopt/ldsda.pyi | 53 ++ stubs/pyomo/contrib/gdpopt/loa.pyi | 40 ++ .../contrib/gdpopt/nlp_initialization.pyi | 4 + .../contrib/gdpopt/oa_algorithm_utils.pyi | 7 + stubs/pyomo/contrib/gdpopt/plugins.pyi | 1 + stubs/pyomo/contrib/gdpopt/ric.pyi | 16 + .../contrib/gdpopt/solve_discrete_problem.pyi | 13 + .../pyomo/contrib/gdpopt/solve_subproblem.pyi | 49 ++ stubs/pyomo/contrib/gdpopt/util.pyi | 94 +++ stubs/pyomo/contrib/gjh/GJH.pyi | 10 + stubs/pyomo/contrib/gjh/__init__.pyi | 0 stubs/pyomo/contrib/gjh/getGJH.pyi | 9 + stubs/pyomo/contrib/gjh/plugins.pyi | 6 + stubs/pyomo/contrib/iis/__init__.pyi | 4 + stubs/pyomo/contrib/iis/iis.pyi | 29 + stubs/pyomo/contrib/iis/mis.pyi | 17 + .../contrib/incidence_analysis/__init__.pyi | 12 + .../incidence_analysis/common/__init__.pyi | 0 .../common/dulmage_mendelsohn.pyi | 4 + .../contrib/incidence_analysis/config.pyi | 24 + .../contrib/incidence_analysis/connected.pyi | 1 + .../incidence_analysis/dulmage_mendelsohn.pyi | 17 + .../contrib/incidence_analysis/incidence.pyi | 7 + .../contrib/incidence_analysis/interface.pyi | 82 +++ .../contrib/incidence_analysis/matching.pyi | 1 + .../contrib/incidence_analysis/scc_solver.pyi | 20 + .../incidence_analysis/triangularize.pyi | 8 + .../contrib/incidence_analysis/visualize.pyi | 21 + .../pyomo/contrib/interior_point/__init__.pyi | 0 .../interior_point/examples/__init__.pyi | 0 .../contrib/interior_point/examples/ex1.pyi | 5 + .../contrib/interior_point/interface.pyi | 187 ++++++ .../contrib/interior_point/interior_point.pyi | 89 +++ .../inverse_reduced_hessian.pyi | 17 + .../interior_point/linalg/__init__.pyi | 0 .../linalg/base_linear_solver_interface.pyi | 14 + .../interior_point/linalg/ma27_interface.pyi | 24 + .../interior_point/linalg/mumps_interface.pyi | 29 + .../interior_point/linalg/scipy_interface.pyi | 18 + .../pyomo/contrib/latex_printer/__init__.pyi | 1 + .../contrib/latex_printer/latex_printer.pyi | 111 ++++ stubs/pyomo/contrib/mcpp/__init__.pyi | 0 stubs/pyomo/contrib/mcpp/build.pyi | 9 + stubs/pyomo/contrib/mcpp/getMCPP.pyi | 7 + stubs/pyomo/contrib/mcpp/plugins.pyi | 7 + stubs/pyomo/contrib/mcpp/pyomo_mcpp.pyi | 72 +++ stubs/pyomo/contrib/mindtpy/MindtPy.pyi | 20 + stubs/pyomo/contrib/mindtpy/__init__.pyi | 3 + .../contrib/mindtpy/algorithm_base_class.pyi | 208 ++++++ .../pyomo/contrib/mindtpy/config_options.pyi | 8 + .../pyomo/contrib/mindtpy/cut_generation.pyi | 33 + .../mindtpy/extended_cutting_plane.pyi | 21 + .../contrib/mindtpy/feasibility_pump.pyi | 21 + .../mindtpy/global_outer_approximation.pyi | 22 + .../contrib/mindtpy/outer_approximation.pyi | 27 + stubs/pyomo/contrib/mindtpy/plugins.pyi | 1 + stubs/pyomo/contrib/mindtpy/single_tree.pyi | 47 ++ stubs/pyomo/contrib/mindtpy/tabu_list.pyi | 9 + stubs/pyomo/contrib/mindtpy/util.pyi | 71 ++ stubs/pyomo/contrib/mpc/__init__.pyi | 5 + stubs/pyomo/contrib/mpc/data/__init__.pyi | 7 + stubs/pyomo/contrib/mpc/data/convert.pyi | 15 + .../contrib/mpc/data/dynamic_data_base.pyi | 13 + .../contrib/mpc/data/find_nearest_index.pyi | 4 + stubs/pyomo/contrib/mpc/data/get_cuid.pyi | 6 + .../pyomo/contrib/mpc/data/interval_data.pyi | 27 + stubs/pyomo/contrib/mpc/data/scalar_data.pyi | 6 + stubs/pyomo/contrib/mpc/data/series_data.pyi | 22 + stubs/pyomo/contrib/mpc/examples/__init__.pyi | 0 .../contrib/mpc/examples/cstr/__init__.pyi | 0 .../pyomo/contrib/mpc/examples/cstr/model.pyi | 6 + .../contrib/mpc/examples/cstr/run_mpc.pyi | 14 + .../mpc/examples/cstr/run_openloop.pyi | 11 + .../pyomo/contrib/mpc/interfaces/__init__.pyi | 1 + .../contrib/mpc/interfaces/copy_values.pyi | 7 + .../contrib/mpc/interfaces/load_data.pyi | 16 + .../mpc/interfaces/model_interface.pyi | 63 ++ .../contrib/mpc/interfaces/var_linker.pyi | 7 + stubs/pyomo/contrib/mpc/modeling/__init__.pyi | 1 + .../contrib/mpc/modeling/constraints.pyi | 4 + .../contrib/mpc/modeling/cost_expressions.pyi | 35 + stubs/pyomo/contrib/mpc/modeling/terminal.pyi | 10 + stubs/pyomo/contrib/multistart/__init__.pyi | 0 .../contrib/multistart/high_conf_stop.pyi | 2 + stubs/pyomo/contrib/multistart/multi.pyi | 32 + stubs/pyomo/contrib/multistart/plugins.pyi | 1 + stubs/pyomo/contrib/multistart/reinit.pyi | 15 + stubs/pyomo/contrib/parmest/__init__.pyi | 2 + .../contrib/parmest/examples/__init__.pyi | 0 .../examples/reaction_kinetics/__init__.pyi | 0 .../simple_reaction_parmest_example.pyi | 31 + .../examples/reactor_design/__init__.pyi | 0 .../reactor_design/bootstrap_example.pyi | 5 + .../confidence_region_example.pyi | 5 + .../reactor_design/datarec_example.pyi | 22 + .../reactor_design/leaveNout_example.pyi | 5 + .../likelihood_ratio_example.pyi | 5 + .../multisensor_data_example.pyi | 9 + .../parameter_estimation_example.pyi | 5 + .../reactor_design/reactor_design.pyi | 17 + .../timeseries_data_example.pyi | 14 + .../examples/rooney_biegler/__init__.pyi | 0 .../rooney_biegler/bootstrap_example.pyi | 5 + .../likelihood_ratio_example.pyi | 5 + .../parameter_estimation_example.pyi | 5 + .../rooney_biegler/rooney_biegler.pyi | 15 + .../rooney_biegler_with_constraint.pyi | 15 + .../parmest/examples/semibatch/__init__.pyi | 0 .../examples/semibatch/parallel_example.pyi | 3 + .../parameter_estimation_example.pyi | 5 + .../examples/semibatch/scenario_example.pyi | 5 + .../parmest/examples/semibatch/semibatch.pyi | 31 + stubs/pyomo/contrib/parmest/experiment.pyi | 6 + stubs/pyomo/contrib/parmest/graphics.pyi | 35 + stubs/pyomo/contrib/parmest/parmest.pyi | 119 ++++ .../pyomo/contrib/parmest/scenariocreator.pyi | 25 + .../pyomo/contrib/parmest/utils/__init__.pyi | 12 + .../pyomo/contrib/parmest/utils/create_ef.pyi | 17 + .../parmest/utils/ipopt_solver_wrapper.pyi | 4 + .../contrib/parmest/utils/model_utils.pyi | 11 + .../pyomo/contrib/parmest/utils/mpi_utils.pyi | 20 + .../contrib/parmest/utils/scenario_tree.pyi | 26 + stubs/pyomo/contrib/piecewise/__init__.pyi | 38 ++ .../ordered_3d_j1_triangulation_data.pyi | 1 + .../piecewise/piecewise_linear_expression.pyi | 12 + .../piecewise/piecewise_linear_function.pyi | 61 ++ .../contrib/piecewise/transform/__init__.pyi | 0 .../transform/convex_combination.pyi | 4 + .../disaggregated_convex_combination.pyi | 4 + .../transform/disaggregated_logarithmic.pyi | 14 + .../piecewise/transform/incremental.pyi | 14 + .../transform/inner_representation_gdp.pyi | 15 + .../piecewise/transform/multiple_choice.pyi | 4 + .../piecewise/transform/nested_inner_repn.pyi | 15 + .../piecewise/transform/nonlinear_to_pwl.pyi | 69 ++ .../transform/outer_representation_gdp.pyi | 16 + .../piecewise_linear_transformation_base.pyi | 36 ++ .../transform/piecewise_to_mip_visitor.pyi | 15 + .../reduced_inner_representation_gdp.pyi | 14 + .../contrib/piecewise/triangulations.pyi | 29 + .../pyomo/contrib/preprocessing/__init__.pyi | 0 .../preprocessing/plugins/__init__.pyi | 1 + .../preprocessing/plugins/bounds_to_vars.pyi | 15 + .../plugins/constraint_tightener.pyi | 14 + .../deactivate_trivial_constraints.pyi | 20 + .../plugins/detect_fixed_vars.pyi | 18 + .../plugins/equality_propagate.pyi | 23 + .../plugins/induced_linearity.pyi | 37 ++ .../preprocessing/plugins/init_vars.pyi | 9 + .../preprocessing/plugins/int_to_binary.pyi | 25 + .../plugins/remove_zero_terms.pyi | 13 + .../preprocessing/plugins/strip_bounds.pyi | 15 + .../preprocessing/plugins/var_aggregator.pyi | 23 + .../plugins/zero_sum_propagator.pyi | 9 + stubs/pyomo/contrib/preprocessing/util.pyi | 4 + stubs/pyomo/contrib/pynumero/__init__.pyi | 6 + .../contrib/pynumero/algorithms/__init__.pyi | 0 .../pynumero/algorithms/solvers/__init__.pyi | 0 .../algorithms/solvers/cyipopt_solver.pyi | 45 ++ .../algorithms/solvers/implicit_functions.pyi | 82 +++ .../algorithms/solvers/pyomo_ext_cyipopt.pyi | 46 ++ .../algorithms/solvers/scipy_solvers.pyi | 77 +++ .../algorithms/solvers/square_solver_base.pyi | 20 + stubs/pyomo/contrib/pynumero/asl.pyi | 37 ++ stubs/pyomo/contrib/pynumero/build.pyi | 6 + stubs/pyomo/contrib/pynumero/dependencies.pyi | 7 + .../contrib/pynumero/examples/__init__.pyi | 0 .../pynumero/examples/callback/__init__.pyi | 0 .../examples/callback/cyipopt_callback.pyi | 15 + .../callback/cyipopt_callback_halt.pyi | 15 + .../callback/cyipopt_functor_callback.pyi | 20 + .../examples/callback/reactor_design.pyi | 8 + .../examples/external_grey_box/__init__.pyi | 0 .../external_with_objective.pyi | 32 + .../external_grey_box/param_est/__init__.pyi | 0 .../param_est/generate_data.pyi | 2 + .../external_grey_box/param_est/models.pyi | 24 + .../param_est/perform_estimation.pyi | 2 + .../react_example/__init__.pyi | 0 .../react_example/maximize_cb_outputs.pyi | 8 + .../maximize_cb_ratio_residuals.pyi | 35 + .../react_example/reactor_model_outputs.pyi | 13 + .../react_example/reactor_model_residuals.pyi | 48 ++ .../contrib/pynumero/examples/feasibility.pyi | 9 + .../pynumero/examples/mumps_example.pyi | 5 + .../pynumero/examples/nlp_interface.pyi | 4 + .../pynumero/examples/nlp_interface_2.pyi | 5 + .../pynumero/examples/parallel_matvec.pyi | 5 + .../pynumero/examples/parallel_vector_ops.pyi | 4 + .../contrib/pynumero/examples/sensitivity.pyi | 7 + stubs/pyomo/contrib/pynumero/examples/sqp.pyi | 21 + stubs/pyomo/contrib/pynumero/exceptions.pyi | 1 + .../contrib/pynumero/interfaces/__init__.pyi | 0 .../contrib/pynumero/interfaces/ampl_nlp.pyi | 62 ++ .../pynumero/interfaces/cyipopt_interface.pyi | 84 +++ .../pynumero/interfaces/external_grey_box.pyi | 62 ++ .../interfaces/external_pyomo_model.pyi | 52 ++ .../pyomo/contrib/pynumero/interfaces/nlp.pyi | 99 +++ .../pynumero/interfaces/nlp_projections.pyi | 69 ++ .../interfaces/pyomo_grey_box_nlp.pyi | 82 +++ .../contrib/pynumero/interfaces/pyomo_nlp.pyi | 94 +++ .../contrib/pynumero/interfaces/utils.pyi | 18 + stubs/pyomo/contrib/pynumero/intrinsic.pyi | 12 + .../contrib/pynumero/linalg/__init__.pyi | 2 + stubs/pyomo/contrib/pynumero/linalg/base.pyi | 51 ++ stubs/pyomo/contrib/pynumero/linalg/ma27.pyi | 25 + .../pynumero/linalg/ma27_interface.pyi | 29 + stubs/pyomo/contrib/pynumero/linalg/ma57.pyi | 30 + .../pynumero/linalg/ma57_interface.pyi | 35 + .../pynumero/linalg/mumps_interface.pyi | 38 ++ .../pynumero/linalg/scipy_interface.pyi | 40 ++ stubs/pyomo/contrib/pynumero/linalg/utils.pyi | 4 + stubs/pyomo/contrib/pynumero/plugins.pyi | 11 + .../contrib/pynumero/sparse/__init__.pyi | 6 + .../contrib/pynumero/sparse/base_block.pyi | 50 ++ .../contrib/pynumero/sparse/block_matrix.pyi | 86 +++ .../contrib/pynumero/sparse/block_vector.pyi | 105 +++ .../pynumero/sparse/mpi_block_matrix.pyi | 99 +++ .../pynumero/sparse/mpi_block_vector.pyi | 113 ++++ stubs/pyomo/contrib/pyros/__init__.pyi | 15 + stubs/pyomo/contrib/pyros/config.pyi | 71 ++ .../contrib/pyros/master_problem_methods.pyi | 56 ++ stubs/pyomo/contrib/pyros/pyros.pyi | 48 ++ .../contrib/pyros/pyros_algorithm_methods.pyi | 29 + .../pyros/separation_problem_methods.pyi | 62 ++ stubs/pyomo/contrib/pyros/solve_data.pyi | 130 ++++ .../pyomo/contrib/pyros/uncertainty_sets.pyi | 296 +++++++++ stubs/pyomo/contrib/pyros/util.pyi | 223 +++++++ stubs/pyomo/contrib/satsolver/__init__.pyi | 0 stubs/pyomo/contrib/satsolver/satsolver.pyi | 49 ++ .../contrib/sensitivity_toolbox/__init__.pyi | 0 .../examples/HIV_Transmission.pyi | 20 + .../sensitivity_toolbox/examples/__init__.pyi | 0 .../examples/feedbackController.pyi | 19 + .../examples/parameter.pyi | 13 + .../examples/parameter_kaug.pyi | 7 + .../examples/rangeInequality.pyi | 10 + .../examples/rooney_biegler.pyi | 2 + .../contrib/sensitivity_toolbox/k_aug.pyi | 27 + .../contrib/sensitivity_toolbox/sens.pyi | 72 +++ .../pyomo/contrib/simplification/__init__.pyi | 1 + stubs/pyomo/contrib/simplification/build.pyi | 15 + .../contrib/simplification/ginac/__init__.pyi | 4 + .../pyomo/contrib/simplification/plugins.pyi | 5 + .../pyomo/contrib/simplification/simplify.pyi | 20 + stubs/pyomo/contrib/solver/__init__.pyi | 1 + .../pyomo/contrib/solver/common/__init__.pyi | 0 stubs/pyomo/contrib/solver/common/base.pyi | 112 ++++ stubs/pyomo/contrib/solver/common/config.pyi | 84 +++ stubs/pyomo/contrib/solver/common/factory.pyi | 9 + .../contrib/solver/common/persistent.pyi | 42 ++ stubs/pyomo/contrib/solver/common/results.pyi | 63 ++ .../contrib/solver/common/solution_loader.pyi | 28 + stubs/pyomo/contrib/solver/common/util.pyi | 35 + stubs/pyomo/contrib/solver/plugins.pyi | 7 + .../pyomo/contrib/solver/solvers/__init__.pyi | 0 .../contrib/solver/solvers/gurobi_direct.pyi | 66 ++ .../solver/solvers/gurobi_persistent.pyi | 163 +++++ stubs/pyomo/contrib/solver/solvers/highs.pyi | 91 +++ stubs/pyomo/contrib/solver/solvers/ipopt.pyi | 62 ++ .../contrib/solver/solvers/sol_reader.pyi | 40 ++ stubs/pyomo/contrib/trustregion/TRF.pyi | 39 ++ stubs/pyomo/contrib/trustregion/__init__.pyi | 0 .../contrib/trustregion/examples/__init__.pyi | 0 .../contrib/trustregion/examples/example1.pyi | 15 + .../contrib/trustregion/examples/example2.pyi | 11 + stubs/pyomo/contrib/trustregion/filter.pyi | 13 + stubs/pyomo/contrib/trustregion/interface.pyi | 57 ++ stubs/pyomo/contrib/trustregion/plugins.pyi | 5 + stubs/pyomo/contrib/trustregion/util.pyi | 31 + stubs/pyomo/contrib/viewer/__init__.pyi | 0 stubs/pyomo/contrib/viewer/model_browser.pyi | 64 ++ stubs/pyomo/contrib/viewer/model_select.pyi | 15 + stubs/pyomo/contrib/viewer/pyomo_viewer.pyi | 21 + stubs/pyomo/contrib/viewer/qt.pyi | 53 ++ stubs/pyomo/contrib/viewer/report.pyi | 18 + stubs/pyomo/contrib/viewer/residual_table.pyi | 31 + stubs/pyomo/contrib/viewer/ui.pyi | 41 ++ stubs/pyomo/contrib/viewer/ui_data.pyi | 29 + stubs/pyomo/core/__init__.pyi | 162 +++++ stubs/pyomo/core/base/PyomoModel.pyi | 111 ++++ stubs/pyomo/core/base/__init__.pyi | 122 ++++ stubs/pyomo/core/base/action.pyi | 12 + stubs/pyomo/core/base/block.pyi | 184 ++++++ stubs/pyomo/core/base/blockutil.pyi | 4 + stubs/pyomo/core/base/boolean_var.pyi | 103 +++ stubs/pyomo/core/base/check.pyi | 12 + stubs/pyomo/core/base/component.pyi | 170 +++++ stubs/pyomo/core/base/component_namer.pyi | 10 + stubs/pyomo/core/base/component_order.pyi | 14 + stubs/pyomo/core/base/componentuid.pyi | 41 ++ stubs/pyomo/core/base/config.pyi | 37 ++ stubs/pyomo/core/base/connector.pyi | 49 ++ stubs/pyomo/core/base/constraint.pyi | 136 ++++ stubs/pyomo/core/base/disable_methods.pyi | 3 + stubs/pyomo/core/base/enums.pyi | 41 ++ stubs/pyomo/core/base/expression.pyi | 128 ++++ stubs/pyomo/core/base/external.pyi | 63 ++ stubs/pyomo/core/base/global_set.pyi | 51 ++ stubs/pyomo/core/base/indexed_component.pyi | 65 ++ .../core/base/indexed_component_slice.pyi | 67 ++ stubs/pyomo/core/base/initializer.pyi | 92 +++ stubs/pyomo/core/base/instance2dat.pyi | 5 + stubs/pyomo/core/base/label.pyi | 63 ++ stubs/pyomo/core/base/logical_constraint.pyi | 69 ++ stubs/pyomo/core/base/matrix_constraint.pyi | 49 ++ stubs/pyomo/core/base/misc.pyi | 9 + stubs/pyomo/core/base/numvalue.pyi | 43 ++ stubs/pyomo/core/base/objective.pyi | 92 +++ stubs/pyomo/core/base/param.pyi | 90 +++ stubs/pyomo/core/base/piecewise.pyi | 95 +++ stubs/pyomo/core/base/range.pyi | 60 ++ stubs/pyomo/core/base/reference.pyi | 64 ++ stubs/pyomo/core/base/set.pyi | 609 ++++++++++++++++++ stubs/pyomo/core/base/set_types.pyi | 19 + stubs/pyomo/core/base/sos.pyi | 51 ++ stubs/pyomo/core/base/suffix.pyi | 74 +++ stubs/pyomo/core/base/symbol_map.pyi | 4 + stubs/pyomo/core/base/symbolic.pyi | 7 + stubs/pyomo/core/base/transformation.pyi | 40 ++ stubs/pyomo/core/base/units_container.pyi | 84 +++ stubs/pyomo/core/base/util.pyi | 5 + stubs/pyomo/core/base/var.pyi | 199 ++++++ stubs/pyomo/core/beta/__init__.pyi | 2 + stubs/pyomo/core/beta/dict_objects.pyi | 38 ++ stubs/pyomo/core/beta/list_objects.pyi | 46 ++ stubs/pyomo/core/expr/__init__.pyi | 154 +++++ stubs/pyomo/core/expr/base.pyi | 62 ++ stubs/pyomo/core/expr/boolean_value.pyi | 52 ++ stubs/pyomo/core/expr/calculus/__init__.pyi | 0 .../pyomo/core/expr/calculus/derivatives.pyi | 11 + .../core/expr/calculus/diff_with_pyomo.pyi | 26 + .../core/expr/calculus/diff_with_sympy.pyi | 7 + stubs/pyomo/core/expr/cnf_walker.pyi | 19 + stubs/pyomo/core/expr/compare.pyi | 57 ++ stubs/pyomo/core/expr/expr_common.pyi | 48 ++ stubs/pyomo/core/expr/expr_errors.pyi | 1 + stubs/pyomo/core/expr/logical_expr.pyi | 103 +++ stubs/pyomo/core/expr/ndarray.pyi | 4 + stubs/pyomo/core/expr/numeric_expr.pyi | 240 +++++++ stubs/pyomo/core/expr/numvalue.pyi | 43 ++ stubs/pyomo/core/expr/relational_expr.pyi | 58 ++ stubs/pyomo/core/expr/symbol_map.pyi | 18 + stubs/pyomo/core/expr/sympy_tools.pyi | 39 ++ stubs/pyomo/core/expr/taylor_series.pyi | 8 + stubs/pyomo/core/expr/template_expr.pyi | 206 ++++++ stubs/pyomo/core/expr/visitor.pyi | 146 +++++ stubs/pyomo/core/kernel/__init__.pyi | 64 ++ stubs/pyomo/core/kernel/base.pyi | 35 + stubs/pyomo/core/kernel/block.pyi | 35 + stubs/pyomo/core/kernel/conic.pyi | 132 ++++ stubs/pyomo/core/kernel/constraint.pyi | 96 +++ stubs/pyomo/core/kernel/container_utils.pyi | 8 + stubs/pyomo/core/kernel/dict_container.pyi | 19 + stubs/pyomo/core/kernel/expression.pyi | 56 ++ .../core/kernel/heterogeneous_container.pyi | 15 + .../core/kernel/homogeneous_container.pyi | 7 + stubs/pyomo/core/kernel/list_container.pyi | 13 + stubs/pyomo/core/kernel/matrix_constraint.pyi | 83 +++ stubs/pyomo/core/kernel/objective.pyi | 22 + stubs/pyomo/core/kernel/parameter.pyi | 30 + .../kernel/piecewise_library/__init__.pyi | 3 + .../kernel/piecewise_library/transforms.pyi | 124 ++++ .../piecewise_library/transforms_nd.pyi | 43 ++ .../core/kernel/piecewise_library/util.pyi | 15 + stubs/pyomo/core/kernel/set_types.pyi | 35 + stubs/pyomo/core/kernel/sos.pyi | 24 + stubs/pyomo/core/kernel/suffix.pyi | 55 ++ stubs/pyomo/core/kernel/tuple_container.pyi | 16 + stubs/pyomo/core/kernel/variable.pyi | 85 +++ stubs/pyomo/core/plugins/__init__.pyi | 1 + .../pyomo/core/plugins/transform/__init__.pyi | 9 + .../core/plugins/transform/add_slack_vars.pyi | 24 + .../core/plugins/transform/discrete_vars.pyi | 21 + .../transform/eliminate_fixed_vars.pyi | 14 + .../plugins/transform/equality_transform.pyi | 11 + .../plugins/transform/expand_connectors.pyi | 17 + .../core/plugins/transform/hierarchy.pyi | 19 + .../plugins/transform/logical_to_linear.pyi | 49 ++ .../pyomo/core/plugins/transform/lp_dual.pyi | 36 ++ stubs/pyomo/core/plugins/transform/model.pyi | 5 + .../transform/nonnegative_transform.pyi | 51 ++ .../plugins/transform/radix_linearization.pyi | 18 + .../plugins/transform/relax_integrality.pyi | 6 + .../pyomo/core/plugins/transform/scaling.pyi | 19 + .../core/plugins/transform/standard_form.pyi | 11 + stubs/pyomo/core/plugins/transform/util.pyi | 9 + stubs/pyomo/core/pyomoobject.pyi | 11 + stubs/pyomo/core/staleflag.pyi | 9 + stubs/pyomo/core/util.pyi | 20 + stubs/pyomo/dae/__init__.pyi | 5 + stubs/pyomo/dae/contset.pyi | 18 + stubs/pyomo/dae/diffvar.pyi | 17 + stubs/pyomo/dae/flatten.pyi | 26 + stubs/pyomo/dae/initialization.pyi | 21 + stubs/pyomo/dae/integral.pyi | 28 + stubs/pyomo/dae/misc.pyi | 29 + stubs/pyomo/dae/plugins/__init__.pyi | 1 + stubs/pyomo/dae/plugins/colloc.pyi | 39 ++ stubs/pyomo/dae/plugins/finitedifference.pyi | 27 + stubs/pyomo/dae/set_utils.pyi | 11 + stubs/pyomo/dae/simulator.pyi | 55 ++ stubs/pyomo/dae/utilities.pyi | 9 + stubs/pyomo/dataportal/DataPortal.pyi | 22 + stubs/pyomo/dataportal/TableData.pyi | 16 + stubs/pyomo/dataportal/__init__.pyi | 5 + stubs/pyomo/dataportal/factory.pyi | 15 + stubs/pyomo/dataportal/parse_datacmds.pyi | 48 ++ stubs/pyomo/dataportal/plugins/__init__.pyi | 1 + stubs/pyomo/dataportal/plugins/csv_table.pyi | 11 + .../pyomo/dataportal/plugins/datacommands.pyi | 17 + stubs/pyomo/dataportal/plugins/db_table.pyi | 74 +++ stubs/pyomo/dataportal/plugins/json_dict.pyi | 38 ++ stubs/pyomo/dataportal/plugins/sheet.pyi | 33 + stubs/pyomo/dataportal/plugins/text.pyi | 11 + stubs/pyomo/dataportal/plugins/xml_table.pyi | 14 + stubs/pyomo/dataportal/process_data.pyi | 13 + stubs/pyomo/duality/__init__.pyi | 1 + stubs/pyomo/duality/collect.pyi | 9 + stubs/pyomo/duality/lagrangian_dual.pyi | 22 + stubs/pyomo/duality/plugins.pyi | 22 + stubs/pyomo/environ/__init__.pyi | 173 +++++ stubs/pyomo/future.pyi | 4 + stubs/pyomo/gdp/__init__.pyi | 5 + stubs/pyomo/gdp/basic_step.pyi | 13 + stubs/pyomo/gdp/disjunct.pyi | 171 +++++ stubs/pyomo/gdp/plugins/__init__.pyi | 3 + stubs/pyomo/gdp/plugins/between_steps.pyi | 5 + stubs/pyomo/gdp/plugins/bigm.pyi | 59 ++ stubs/pyomo/gdp/plugins/bigm_mixin.pyi | 8 + stubs/pyomo/gdp/plugins/bilinear.pyi | 17 + .../gdp/plugins/binary_multiplication.pyi | 15 + .../gdp/plugins/bound_pretransformation.pyi | 32 + stubs/pyomo/gdp/plugins/cuttingplane.pyi | 77 +++ stubs/pyomo/gdp/plugins/fix_disjuncts.pyi | 23 + .../gdp/plugins/gdp_to_mip_transformation.pyi | 46 ++ stubs/pyomo/gdp/plugins/gdp_var_mover.pyi | 15 + stubs/pyomo/gdp/plugins/hull.pyi | 64 ++ stubs/pyomo/gdp/plugins/multiple_bigm.pyi | 52 ++ .../pyomo/gdp/plugins/partition_disjuncts.pyi | 61 ++ .../transform_current_disjunctive_state.pyi | 19 + stubs/pyomo/gdp/transformed_disjunct.pyi | 14 + stubs/pyomo/gdp/util.pyi | 58 ++ stubs/pyomo/kernel/__init__.pyi | 137 ++++ stubs/pyomo/kernel/util.pyi | 12 + stubs/pyomo/mpec/__init__.pyi | 3 + stubs/pyomo/mpec/complementarity.pyi | 65 ++ stubs/pyomo/mpec/plugins/__init__.pyi | 1 + stubs/pyomo/mpec/plugins/mpec1.pyi | 15 + stubs/pyomo/mpec/plugins/mpec2.pyi | 16 + stubs/pyomo/mpec/plugins/mpec3.pyi | 12 + stubs/pyomo/mpec/plugins/mpec4.pyi | 18 + stubs/pyomo/mpec/plugins/pathampl.pyi | 11 + stubs/pyomo/mpec/plugins/solver1.pyi | 7 + stubs/pyomo/mpec/plugins/solver2.pyi | 7 + stubs/pyomo/neos/__init__.pyi | 3 + stubs/pyomo/neos/kestrel.pyi | 31 + stubs/pyomo/neos/plugins/NEOS.pyi | 13 + stubs/pyomo/neos/plugins/__init__.pyi | 1 + stubs/pyomo/neos/plugins/kestrel_plugin.pyi | 24 + stubs/pyomo/network/__init__.pyi | 3 + stubs/pyomo/network/arc.pyi | 54 ++ stubs/pyomo/network/decomposition.pyi | 60 ++ stubs/pyomo/network/foqus_graph.pyi | 34 + stubs/pyomo/network/plugins/__init__.pyi | 1 + stubs/pyomo/network/plugins/expand_arcs.pyi | 18 + stubs/pyomo/network/port.pyi | 81 +++ stubs/pyomo/network/util.pyi | 6 + stubs/pyomo/opt/__init__.pyi | 44 ++ stubs/pyomo/opt/base/__init__.pyi | 14 + stubs/pyomo/opt/base/convert.pyi | 8 + stubs/pyomo/opt/base/error.pyi | 2 + stubs/pyomo/opt/base/formats.pyi | 22 + stubs/pyomo/opt/base/opt_config.pyi | 0 stubs/pyomo/opt/base/problem.pyi | 24 + stubs/pyomo/opt/base/results.pyi | 18 + stubs/pyomo/opt/base/solvers.pyi | 99 +++ stubs/pyomo/opt/parallel/__init__.pyi | 6 + stubs/pyomo/opt/parallel/async_solver.pyi | 19 + stubs/pyomo/opt/parallel/local.pyi | 11 + stubs/pyomo/opt/parallel/manager.pyi | 44 ++ stubs/pyomo/opt/plugins/__init__.pyi | 1 + stubs/pyomo/opt/plugins/driver.pyi | 6 + stubs/pyomo/opt/plugins/res.pyi | 11 + stubs/pyomo/opt/plugins/sol.pyi | 12 + stubs/pyomo/opt/problem/__init__.pyi | 4 + stubs/pyomo/opt/problem/ampl.pyi | 11 + stubs/pyomo/opt/results.pyi | 44 ++ stubs/pyomo/opt/results/__init__.pyi | 14 + stubs/pyomo/opt/results/container.pyi | 73 +++ stubs/pyomo/opt/results/problem.pyi | 11 + stubs/pyomo/opt/results/results_.pyi | 21 + stubs/pyomo/opt/results/solution.pyi | 43 ++ stubs/pyomo/opt/results/solver.pyi | 53 ++ stubs/pyomo/opt/solver/__init__.pyi | 6 + stubs/pyomo/opt/solver/ilmcmd.pyi | 6 + stubs/pyomo/opt/solver/shellcmd.pyi | 25 + stubs/pyomo/repn/__init__.pyi | 3 + stubs/pyomo/repn/ampl.pyi | 136 ++++ stubs/pyomo/repn/beta/__init__.pyi | 1 + stubs/pyomo/repn/beta/matrix.pyi | 86 +++ stubs/pyomo/repn/linear.pyi | 76 +++ stubs/pyomo/repn/linear_template.pyi | 48 ++ stubs/pyomo/repn/parameterized_linear.pyi | 49 ++ stubs/pyomo/repn/parameterized_quadratic.pyi | 34 + stubs/pyomo/repn/plugins/__init__.pyi | 3 + stubs/pyomo/repn/plugins/ampl/__init__.pyi | 1 + stubs/pyomo/repn/plugins/ampl/ampl_.pyi | 69 ++ stubs/pyomo/repn/plugins/baron_writer.pyi | 35 + stubs/pyomo/repn/plugins/cpxlp.pyi | 33 + stubs/pyomo/repn/plugins/gams_writer.pyi | 67 ++ stubs/pyomo/repn/plugins/lp_writer.pyi | 64 ++ stubs/pyomo/repn/plugins/mps.pyi | 23 + stubs/pyomo/repn/plugins/nl_writer.pyi | 134 ++++ .../plugins/parameterized_standard_form.pyi | 43 ++ stubs/pyomo/repn/plugins/standard_form.pyi | 70 ++ stubs/pyomo/repn/quadratic.pyi | 38 ++ stubs/pyomo/repn/standard_aux.pyi | 4 + stubs/pyomo/repn/standard_repn.pyi | 76 +++ stubs/pyomo/repn/util.pyi | 121 ++++ stubs/pyomo/scripting/__init__.pyi | 2 + stubs/pyomo/scripting/commands.pyi | 4 + stubs/pyomo/scripting/convert.pyi | 14 + stubs/pyomo/scripting/driver_help.pyi | 19 + stubs/pyomo/scripting/interface.pyi | 53 ++ stubs/pyomo/scripting/plugins/__init__.pyi | 1 + stubs/pyomo/scripting/plugins/build_ext.pyi | 6 + stubs/pyomo/scripting/plugins/convert.pyi | 14 + stubs/pyomo/scripting/plugins/download.pyi | 10 + stubs/pyomo/scripting/plugins/extras.pyi | 7 + stubs/pyomo/scripting/plugins/solve.pyi | 11 + stubs/pyomo/scripting/pyomo_command.pyi | 5 + stubs/pyomo/scripting/pyomo_main.pyi | 12 + stubs/pyomo/scripting/pyomo_parser.pyi | 14 + stubs/pyomo/scripting/solve_config.pyi | 9 + stubs/pyomo/scripting/util.pyi | 72 +++ stubs/pyomo/solvers/__init__.pyi | 0 stubs/pyomo/solvers/amplfunc_merge.pyi | 4 + stubs/pyomo/solvers/mockmip.pyi | 8 + stubs/pyomo/solvers/plugins/__init__.pyi | 1 + .../solvers/plugins/converter/__init__.pyi | 3 + .../pyomo/solvers/plugins/converter/ampl.pyi | 9 + .../solvers/plugins/converter/glpsol.pyi | 9 + .../pyomo/solvers/plugins/converter/model.pyi | 11 + .../pyomo/solvers/plugins/converter/pico.pyi | 9 + stubs/pyomo/solvers/plugins/solvers/ASL.pyi | 26 + stubs/pyomo/solvers/plugins/solvers/BARON.pyi | 24 + .../solvers/plugins/solvers/CBCplugin.pyi | 39 ++ .../pyomo/solvers/plugins/solvers/CONOPT.pyi | 15 + stubs/pyomo/solvers/plugins/solvers/CPLEX.pyi | 51 ++ stubs/pyomo/solvers/plugins/solvers/GAMS.pyi | 67 ++ stubs/pyomo/solvers/plugins/solvers/GLPK.pyi | 44 ++ .../pyomo/solvers/plugins/solvers/GUROBI.pyi | 50 ++ .../solvers/plugins/solvers/GUROBI_RUN.pyi | 6 + stubs/pyomo/solvers/plugins/solvers/IPOPT.pyi | 22 + .../solvers/plugins/solvers/KNITROAMPL.pyi | 14 + stubs/pyomo/solvers/plugins/solvers/SAS.pyi | 48 ++ .../solvers/plugins/solvers/SCIPAMPL.pyi | 19 + .../pyomo/solvers/plugins/solvers/XPRESS.pyi | 8 + .../solvers/plugins/solvers/__init__.pyi | 22 + .../solvers/plugins/solvers/cplex_direct.pyi | 73 +++ .../plugins/solvers/cplex_persistent.pyi | 9 + .../solvers/direct_or_persistent_solver.pyi | 23 + .../solvers/plugins/solvers/direct_solver.pyi | 16 + .../solvers/plugins/solvers/gurobi_direct.pyi | 50 ++ .../plugins/solvers/gurobi_persistent.pyi | 31 + .../solvers/plugins/solvers/mosek_direct.pyi | 52 ++ .../plugins/solvers/mosek_persistent.pyi | 25 + .../plugins/solvers/persistent_solver.pyi | 35 + .../solvers/plugins/solvers/pywrapper.pyi | 8 + .../solvers/plugins/solvers/xpress_direct.pyi | 46 ++ .../plugins/solvers/xpress_persistent.pyi | 14 + stubs/pyomo/solvers/wrappers.pyi | 2 + stubs/pyomo/util/__init__.pyi | 0 stubs/pyomo/util/blockutil.pyi | 9 + stubs/pyomo/util/calc_var_value.pyi | 19 + stubs/pyomo/util/check_units.pyi | 36 ++ stubs/pyomo/util/components.pyi | 6 + stubs/pyomo/util/config_domains.pyi | 6 + stubs/pyomo/util/diagnostics.pyi | 8 + stubs/pyomo/util/infeasible.pyi | 21 + stubs/pyomo/util/model_size.pyi | 15 + stubs/pyomo/util/report_scaling.pyi | 10 + stubs/pyomo/util/slices.pyi | 9 + stubs/pyomo/util/subsystems.pyi | 66 ++ stubs/pyomo/util/vars_from_expressions.pyi | 15 + stubs/pyomo/version/__init__.pyi | 3 + stubs/pyomo/version/info.pyi | 10 + uv.lock | 59 +- 743 files changed, 23893 insertions(+), 52 deletions(-) create mode 100644 stubs/pyomo/__init__.pyi create mode 100644 stubs/pyomo/_archive/__init__.pyi create mode 100644 stubs/pyomo/_archive/chull.pyi create mode 100644 stubs/pyomo/_archive/component_map.pyi create mode 100644 stubs/pyomo/_archive/component_set.pyi create mode 100644 stubs/pyomo/_archive/current.pyi create mode 100644 stubs/pyomo/_archive/plugin.pyi create mode 100644 stubs/pyomo/_archive/rangeset.pyi create mode 100644 stubs/pyomo/_archive/register_numpy_types.pyi create mode 100644 stubs/pyomo/_archive/sets.pyi create mode 100644 stubs/pyomo/_archive/template_expr.pyi create mode 100644 stubs/pyomo/common/__init__.pyi create mode 100644 stubs/pyomo/common/_command.pyi create mode 100644 stubs/pyomo/common/_common.pyi create mode 100644 stubs/pyomo/common/autoslots.pyi create mode 100644 stubs/pyomo/common/backports.pyi create mode 100644 stubs/pyomo/common/cmake_builder.pyi create mode 100644 stubs/pyomo/common/collections/__init__.pyi create mode 100644 stubs/pyomo/common/collections/bunch.pyi create mode 100644 stubs/pyomo/common/collections/component_map.pyi create mode 100644 stubs/pyomo/common/collections/component_set.pyi create mode 100644 stubs/pyomo/common/collections/orderedset.pyi create mode 100644 stubs/pyomo/common/config.pyi create mode 100644 stubs/pyomo/common/dependencies.pyi create mode 100644 stubs/pyomo/common/deprecation.pyi create mode 100644 stubs/pyomo/common/download.pyi create mode 100644 stubs/pyomo/common/enums.pyi create mode 100644 stubs/pyomo/common/env.pyi create mode 100644 stubs/pyomo/common/envvar.pyi create mode 100644 stubs/pyomo/common/errors.pyi create mode 100644 stubs/pyomo/common/extensions.pyi create mode 100644 stubs/pyomo/common/factory.pyi create mode 100644 stubs/pyomo/common/fileutils.pyi create mode 100644 stubs/pyomo/common/flags.pyi create mode 100644 stubs/pyomo/common/formatting.pyi create mode 100644 stubs/pyomo/common/gc_manager.pyi create mode 100644 stubs/pyomo/common/gsl.pyi create mode 100644 stubs/pyomo/common/log.pyi create mode 100644 stubs/pyomo/common/modeling.pyi create mode 100644 stubs/pyomo/common/multithread.pyi create mode 100644 stubs/pyomo/common/numeric_types.pyi create mode 100644 stubs/pyomo/common/plugin_base.pyi create mode 100644 stubs/pyomo/common/plugins.pyi create mode 100644 stubs/pyomo/common/pyomo_typing.pyi create mode 100644 stubs/pyomo/common/shutdown.pyi create mode 100644 stubs/pyomo/common/sorting.pyi create mode 100644 stubs/pyomo/common/tee.pyi create mode 100644 stubs/pyomo/common/tempfiles.pyi create mode 100644 stubs/pyomo/common/timing.pyi create mode 100644 stubs/pyomo/common/unittest.pyi create mode 100644 stubs/pyomo/contrib/__init__.pyi create mode 100644 stubs/pyomo/contrib/alternative_solutions/__init__.pyi create mode 100644 stubs/pyomo/contrib/alternative_solutions/aos_utils.pyi create mode 100644 stubs/pyomo/contrib/alternative_solutions/balas.pyi create mode 100644 stubs/pyomo/contrib/alternative_solutions/lp_enum.pyi create mode 100644 stubs/pyomo/contrib/alternative_solutions/lp_enum_solnpool.pyi create mode 100644 stubs/pyomo/contrib/alternative_solutions/obbt.pyi create mode 100644 stubs/pyomo/contrib/alternative_solutions/shifted_lp.pyi create mode 100644 stubs/pyomo/contrib/alternative_solutions/solnpool.pyi create mode 100644 stubs/pyomo/contrib/alternative_solutions/solution.pyi create mode 100644 stubs/pyomo/contrib/ampl_function_demo/__init__.pyi create mode 100644 stubs/pyomo/contrib/ampl_function_demo/build.pyi create mode 100644 stubs/pyomo/contrib/ampl_function_demo/plugins.pyi create mode 100644 stubs/pyomo/contrib/appsi/__init__.pyi create mode 100644 stubs/pyomo/contrib/appsi/base.pyi create mode 100644 stubs/pyomo/contrib/appsi/build.pyi create mode 100644 stubs/pyomo/contrib/appsi/cmodel/__init__.pyi create mode 100644 stubs/pyomo/contrib/appsi/cmodel/appsi_cmodel.pyi create mode 100644 stubs/pyomo/contrib/appsi/examples/__init__.pyi create mode 100644 stubs/pyomo/contrib/appsi/examples/getting_started.pyi create mode 100644 stubs/pyomo/contrib/appsi/fbbt.pyi create mode 100644 stubs/pyomo/contrib/appsi/plugins.pyi create mode 100644 stubs/pyomo/contrib/appsi/solvers/__init__.pyi create mode 100644 stubs/pyomo/contrib/appsi/solvers/cbc.pyi create mode 100644 stubs/pyomo/contrib/appsi/solvers/cplex.pyi create mode 100644 stubs/pyomo/contrib/appsi/solvers/gurobi.pyi create mode 100644 stubs/pyomo/contrib/appsi/solvers/highs.pyi create mode 100644 stubs/pyomo/contrib/appsi/solvers/ipopt.pyi create mode 100644 stubs/pyomo/contrib/appsi/solvers/maingo.pyi create mode 100644 stubs/pyomo/contrib/appsi/solvers/maingo_solvermodel.pyi create mode 100644 stubs/pyomo/contrib/appsi/solvers/wntr.pyi create mode 100644 stubs/pyomo/contrib/appsi/utils/__init__.pyi create mode 100644 stubs/pyomo/contrib/appsi/utils/collect_vars_and_named_exprs.pyi create mode 100644 stubs/pyomo/contrib/appsi/utils/get_objective.pyi create mode 100644 stubs/pyomo/contrib/appsi/writers/__init__.pyi create mode 100644 stubs/pyomo/contrib/appsi/writers/config.pyi create mode 100644 stubs/pyomo/contrib/appsi/writers/lp_writer.pyi create mode 100644 stubs/pyomo/contrib/appsi/writers/nl_writer.pyi create mode 100644 stubs/pyomo/contrib/benders/__init__.pyi create mode 100644 stubs/pyomo/contrib/benders/benders_cuts.pyi create mode 100644 stubs/pyomo/contrib/benders/examples/__init__.pyi create mode 100644 stubs/pyomo/contrib/benders/examples/farmer.pyi create mode 100644 stubs/pyomo/contrib/benders/examples/grothey_ex.pyi create mode 100644 stubs/pyomo/contrib/community_detection/__init__.pyi create mode 100644 stubs/pyomo/contrib/community_detection/community_graph.pyi create mode 100644 stubs/pyomo/contrib/community_detection/detection.pyi create mode 100644 stubs/pyomo/contrib/community_detection/event_log.pyi create mode 100644 stubs/pyomo/contrib/community_detection/plugins.pyi create mode 100644 stubs/pyomo/contrib/cp/__init__.pyi create mode 100644 stubs/pyomo/contrib/cp/interval_var.pyi create mode 100644 stubs/pyomo/contrib/cp/plugins.pyi create mode 100644 stubs/pyomo/contrib/cp/repn/__init__.pyi create mode 100644 stubs/pyomo/contrib/cp/repn/docplex_writer.pyi create mode 100644 stubs/pyomo/contrib/cp/scheduling_expr/__init__.pyi create mode 100644 stubs/pyomo/contrib/cp/scheduling_expr/precedence_expressions.pyi create mode 100644 stubs/pyomo/contrib/cp/scheduling_expr/scheduling_logic.pyi create mode 100644 stubs/pyomo/contrib/cp/scheduling_expr/sequence_expressions.pyi create mode 100644 stubs/pyomo/contrib/cp/scheduling_expr/step_function_expressions.pyi create mode 100644 stubs/pyomo/contrib/cp/sequence_var.pyi create mode 100644 stubs/pyomo/contrib/cp/transform/__init__.pyi create mode 100644 stubs/pyomo/contrib/cp/transform/logical_to_disjunctive_program.pyi create mode 100644 stubs/pyomo/contrib/cp/transform/logical_to_disjunctive_walker.pyi create mode 100644 stubs/pyomo/contrib/cspline_external/__init__.pyi create mode 100644 stubs/pyomo/contrib/cspline_external/build.pyi create mode 100644 stubs/pyomo/contrib/cspline_external/cspline_parameters.pyi create mode 100644 stubs/pyomo/contrib/cspline_external/plugins.pyi create mode 100644 stubs/pyomo/contrib/doe/__init__.pyi create mode 100644 stubs/pyomo/contrib/doe/doe.pyi create mode 100644 stubs/pyomo/contrib/doe/examples/__init__.pyi create mode 100644 stubs/pyomo/contrib/doe/examples/reactor_compute_factorial_FIM.pyi create mode 100644 stubs/pyomo/contrib/doe/examples/reactor_example.pyi create mode 100644 stubs/pyomo/contrib/doe/examples/reactor_experiment.pyi create mode 100644 stubs/pyomo/contrib/doe/utils.pyi create mode 100644 stubs/pyomo/contrib/example/__init__.pyi create mode 100644 stubs/pyomo/contrib/example/bar.pyi create mode 100644 stubs/pyomo/contrib/example/foo.pyi create mode 100644 stubs/pyomo/contrib/example/plugins/__init__.pyi create mode 100644 stubs/pyomo/contrib/example/plugins/ex_plugin.pyi create mode 100644 stubs/pyomo/contrib/fbbt/__init__.pyi create mode 100644 stubs/pyomo/contrib/fbbt/expression_bounds_walker.pyi create mode 100644 stubs/pyomo/contrib/fbbt/fbbt.pyi create mode 100644 stubs/pyomo/contrib/fbbt/interval.pyi create mode 100644 stubs/pyomo/contrib/fme/__init__.pyi create mode 100644 stubs/pyomo/contrib/fme/fourier_motzkin_elimination.pyi create mode 100644 stubs/pyomo/contrib/fme/plugins.pyi create mode 100644 stubs/pyomo/contrib/gdp_bounds/__init__.pyi create mode 100644 stubs/pyomo/contrib/gdp_bounds/compute_bounds.pyi create mode 100644 stubs/pyomo/contrib/gdp_bounds/info.pyi create mode 100644 stubs/pyomo/contrib/gdp_bounds/plugins.pyi create mode 100644 stubs/pyomo/contrib/gdpopt/GDPopt.pyi create mode 100644 stubs/pyomo/contrib/gdpopt/__init__.pyi create mode 100644 stubs/pyomo/contrib/gdpopt/algorithm_base_class.pyi create mode 100644 stubs/pyomo/contrib/gdpopt/branch_and_bound.pyi create mode 100644 stubs/pyomo/contrib/gdpopt/config_options.pyi create mode 100644 stubs/pyomo/contrib/gdpopt/create_oa_subproblems.pyi create mode 100644 stubs/pyomo/contrib/gdpopt/cut_generation.pyi create mode 100644 stubs/pyomo/contrib/gdpopt/discrete_problem_initialize.pyi create mode 100644 stubs/pyomo/contrib/gdpopt/enumerate.pyi create mode 100644 stubs/pyomo/contrib/gdpopt/gloa.pyi create mode 100644 stubs/pyomo/contrib/gdpopt/ldsda.pyi create mode 100644 stubs/pyomo/contrib/gdpopt/loa.pyi create mode 100644 stubs/pyomo/contrib/gdpopt/nlp_initialization.pyi create mode 100644 stubs/pyomo/contrib/gdpopt/oa_algorithm_utils.pyi create mode 100644 stubs/pyomo/contrib/gdpopt/plugins.pyi create mode 100644 stubs/pyomo/contrib/gdpopt/ric.pyi create mode 100644 stubs/pyomo/contrib/gdpopt/solve_discrete_problem.pyi create mode 100644 stubs/pyomo/contrib/gdpopt/solve_subproblem.pyi create mode 100644 stubs/pyomo/contrib/gdpopt/util.pyi create mode 100644 stubs/pyomo/contrib/gjh/GJH.pyi create mode 100644 stubs/pyomo/contrib/gjh/__init__.pyi create mode 100644 stubs/pyomo/contrib/gjh/getGJH.pyi create mode 100644 stubs/pyomo/contrib/gjh/plugins.pyi create mode 100644 stubs/pyomo/contrib/iis/__init__.pyi create mode 100644 stubs/pyomo/contrib/iis/iis.pyi create mode 100644 stubs/pyomo/contrib/iis/mis.pyi create mode 100644 stubs/pyomo/contrib/incidence_analysis/__init__.pyi create mode 100644 stubs/pyomo/contrib/incidence_analysis/common/__init__.pyi create mode 100644 stubs/pyomo/contrib/incidence_analysis/common/dulmage_mendelsohn.pyi create mode 100644 stubs/pyomo/contrib/incidence_analysis/config.pyi create mode 100644 stubs/pyomo/contrib/incidence_analysis/connected.pyi create mode 100644 stubs/pyomo/contrib/incidence_analysis/dulmage_mendelsohn.pyi create mode 100644 stubs/pyomo/contrib/incidence_analysis/incidence.pyi create mode 100644 stubs/pyomo/contrib/incidence_analysis/interface.pyi create mode 100644 stubs/pyomo/contrib/incidence_analysis/matching.pyi create mode 100644 stubs/pyomo/contrib/incidence_analysis/scc_solver.pyi create mode 100644 stubs/pyomo/contrib/incidence_analysis/triangularize.pyi create mode 100644 stubs/pyomo/contrib/incidence_analysis/visualize.pyi create mode 100644 stubs/pyomo/contrib/interior_point/__init__.pyi create mode 100644 stubs/pyomo/contrib/interior_point/examples/__init__.pyi create mode 100644 stubs/pyomo/contrib/interior_point/examples/ex1.pyi create mode 100644 stubs/pyomo/contrib/interior_point/interface.pyi create mode 100644 stubs/pyomo/contrib/interior_point/interior_point.pyi create mode 100644 stubs/pyomo/contrib/interior_point/inverse_reduced_hessian.pyi create mode 100644 stubs/pyomo/contrib/interior_point/linalg/__init__.pyi create mode 100644 stubs/pyomo/contrib/interior_point/linalg/base_linear_solver_interface.pyi create mode 100644 stubs/pyomo/contrib/interior_point/linalg/ma27_interface.pyi create mode 100644 stubs/pyomo/contrib/interior_point/linalg/mumps_interface.pyi create mode 100644 stubs/pyomo/contrib/interior_point/linalg/scipy_interface.pyi create mode 100644 stubs/pyomo/contrib/latex_printer/__init__.pyi create mode 100644 stubs/pyomo/contrib/latex_printer/latex_printer.pyi create mode 100644 stubs/pyomo/contrib/mcpp/__init__.pyi create mode 100644 stubs/pyomo/contrib/mcpp/build.pyi create mode 100644 stubs/pyomo/contrib/mcpp/getMCPP.pyi create mode 100644 stubs/pyomo/contrib/mcpp/plugins.pyi create mode 100644 stubs/pyomo/contrib/mcpp/pyomo_mcpp.pyi create mode 100644 stubs/pyomo/contrib/mindtpy/MindtPy.pyi create mode 100644 stubs/pyomo/contrib/mindtpy/__init__.pyi create mode 100644 stubs/pyomo/contrib/mindtpy/algorithm_base_class.pyi create mode 100644 stubs/pyomo/contrib/mindtpy/config_options.pyi create mode 100644 stubs/pyomo/contrib/mindtpy/cut_generation.pyi create mode 100644 stubs/pyomo/contrib/mindtpy/extended_cutting_plane.pyi create mode 100644 stubs/pyomo/contrib/mindtpy/feasibility_pump.pyi create mode 100644 stubs/pyomo/contrib/mindtpy/global_outer_approximation.pyi create mode 100644 stubs/pyomo/contrib/mindtpy/outer_approximation.pyi create mode 100644 stubs/pyomo/contrib/mindtpy/plugins.pyi create mode 100644 stubs/pyomo/contrib/mindtpy/single_tree.pyi create mode 100644 stubs/pyomo/contrib/mindtpy/tabu_list.pyi create mode 100644 stubs/pyomo/contrib/mindtpy/util.pyi create mode 100644 stubs/pyomo/contrib/mpc/__init__.pyi create mode 100644 stubs/pyomo/contrib/mpc/data/__init__.pyi create mode 100644 stubs/pyomo/contrib/mpc/data/convert.pyi create mode 100644 stubs/pyomo/contrib/mpc/data/dynamic_data_base.pyi create mode 100644 stubs/pyomo/contrib/mpc/data/find_nearest_index.pyi create mode 100644 stubs/pyomo/contrib/mpc/data/get_cuid.pyi create mode 100644 stubs/pyomo/contrib/mpc/data/interval_data.pyi create mode 100644 stubs/pyomo/contrib/mpc/data/scalar_data.pyi create mode 100644 stubs/pyomo/contrib/mpc/data/series_data.pyi create mode 100644 stubs/pyomo/contrib/mpc/examples/__init__.pyi create mode 100644 stubs/pyomo/contrib/mpc/examples/cstr/__init__.pyi create mode 100644 stubs/pyomo/contrib/mpc/examples/cstr/model.pyi create mode 100644 stubs/pyomo/contrib/mpc/examples/cstr/run_mpc.pyi create mode 100644 stubs/pyomo/contrib/mpc/examples/cstr/run_openloop.pyi create mode 100644 stubs/pyomo/contrib/mpc/interfaces/__init__.pyi create mode 100644 stubs/pyomo/contrib/mpc/interfaces/copy_values.pyi create mode 100644 stubs/pyomo/contrib/mpc/interfaces/load_data.pyi create mode 100644 stubs/pyomo/contrib/mpc/interfaces/model_interface.pyi create mode 100644 stubs/pyomo/contrib/mpc/interfaces/var_linker.pyi create mode 100644 stubs/pyomo/contrib/mpc/modeling/__init__.pyi create mode 100644 stubs/pyomo/contrib/mpc/modeling/constraints.pyi create mode 100644 stubs/pyomo/contrib/mpc/modeling/cost_expressions.pyi create mode 100644 stubs/pyomo/contrib/mpc/modeling/terminal.pyi create mode 100644 stubs/pyomo/contrib/multistart/__init__.pyi create mode 100644 stubs/pyomo/contrib/multistart/high_conf_stop.pyi create mode 100644 stubs/pyomo/contrib/multistart/multi.pyi create mode 100644 stubs/pyomo/contrib/multistart/plugins.pyi create mode 100644 stubs/pyomo/contrib/multistart/reinit.pyi create mode 100644 stubs/pyomo/contrib/parmest/__init__.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/__init__.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/reaction_kinetics/__init__.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/reaction_kinetics/simple_reaction_parmest_example.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/reactor_design/__init__.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/reactor_design/bootstrap_example.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/reactor_design/confidence_region_example.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/reactor_design/datarec_example.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/reactor_design/leaveNout_example.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/reactor_design/likelihood_ratio_example.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/reactor_design/multisensor_data_example.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/reactor_design/parameter_estimation_example.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/reactor_design/reactor_design.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/reactor_design/timeseries_data_example.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/rooney_biegler/__init__.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/rooney_biegler/bootstrap_example.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/rooney_biegler/likelihood_ratio_example.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/rooney_biegler/parameter_estimation_example.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/rooney_biegler/rooney_biegler.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/rooney_biegler/rooney_biegler_with_constraint.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/semibatch/__init__.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/semibatch/parallel_example.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/semibatch/parameter_estimation_example.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/semibatch/scenario_example.pyi create mode 100644 stubs/pyomo/contrib/parmest/examples/semibatch/semibatch.pyi create mode 100644 stubs/pyomo/contrib/parmest/experiment.pyi create mode 100644 stubs/pyomo/contrib/parmest/graphics.pyi create mode 100644 stubs/pyomo/contrib/parmest/parmest.pyi create mode 100644 stubs/pyomo/contrib/parmest/scenariocreator.pyi create mode 100644 stubs/pyomo/contrib/parmest/utils/__init__.pyi create mode 100644 stubs/pyomo/contrib/parmest/utils/create_ef.pyi create mode 100644 stubs/pyomo/contrib/parmest/utils/ipopt_solver_wrapper.pyi create mode 100644 stubs/pyomo/contrib/parmest/utils/model_utils.pyi create mode 100644 stubs/pyomo/contrib/parmest/utils/mpi_utils.pyi create mode 100644 stubs/pyomo/contrib/parmest/utils/scenario_tree.pyi create mode 100644 stubs/pyomo/contrib/piecewise/__init__.pyi create mode 100644 stubs/pyomo/contrib/piecewise/ordered_3d_j1_triangulation_data.pyi create mode 100644 stubs/pyomo/contrib/piecewise/piecewise_linear_expression.pyi create mode 100644 stubs/pyomo/contrib/piecewise/piecewise_linear_function.pyi create mode 100644 stubs/pyomo/contrib/piecewise/transform/__init__.pyi create mode 100644 stubs/pyomo/contrib/piecewise/transform/convex_combination.pyi create mode 100644 stubs/pyomo/contrib/piecewise/transform/disaggregated_convex_combination.pyi create mode 100644 stubs/pyomo/contrib/piecewise/transform/disaggregated_logarithmic.pyi create mode 100644 stubs/pyomo/contrib/piecewise/transform/incremental.pyi create mode 100644 stubs/pyomo/contrib/piecewise/transform/inner_representation_gdp.pyi create mode 100644 stubs/pyomo/contrib/piecewise/transform/multiple_choice.pyi create mode 100644 stubs/pyomo/contrib/piecewise/transform/nested_inner_repn.pyi create mode 100644 stubs/pyomo/contrib/piecewise/transform/nonlinear_to_pwl.pyi create mode 100644 stubs/pyomo/contrib/piecewise/transform/outer_representation_gdp.pyi create mode 100644 stubs/pyomo/contrib/piecewise/transform/piecewise_linear_transformation_base.pyi create mode 100644 stubs/pyomo/contrib/piecewise/transform/piecewise_to_mip_visitor.pyi create mode 100644 stubs/pyomo/contrib/piecewise/transform/reduced_inner_representation_gdp.pyi create mode 100644 stubs/pyomo/contrib/piecewise/triangulations.pyi create mode 100644 stubs/pyomo/contrib/preprocessing/__init__.pyi create mode 100644 stubs/pyomo/contrib/preprocessing/plugins/__init__.pyi create mode 100644 stubs/pyomo/contrib/preprocessing/plugins/bounds_to_vars.pyi create mode 100644 stubs/pyomo/contrib/preprocessing/plugins/constraint_tightener.pyi create mode 100644 stubs/pyomo/contrib/preprocessing/plugins/deactivate_trivial_constraints.pyi create mode 100644 stubs/pyomo/contrib/preprocessing/plugins/detect_fixed_vars.pyi create mode 100644 stubs/pyomo/contrib/preprocessing/plugins/equality_propagate.pyi create mode 100644 stubs/pyomo/contrib/preprocessing/plugins/induced_linearity.pyi create mode 100644 stubs/pyomo/contrib/preprocessing/plugins/init_vars.pyi create mode 100644 stubs/pyomo/contrib/preprocessing/plugins/int_to_binary.pyi create mode 100644 stubs/pyomo/contrib/preprocessing/plugins/remove_zero_terms.pyi create mode 100644 stubs/pyomo/contrib/preprocessing/plugins/strip_bounds.pyi create mode 100644 stubs/pyomo/contrib/preprocessing/plugins/var_aggregator.pyi create mode 100644 stubs/pyomo/contrib/preprocessing/plugins/zero_sum_propagator.pyi create mode 100644 stubs/pyomo/contrib/preprocessing/util.pyi create mode 100644 stubs/pyomo/contrib/pynumero/__init__.pyi create mode 100644 stubs/pyomo/contrib/pynumero/algorithms/__init__.pyi create mode 100644 stubs/pyomo/contrib/pynumero/algorithms/solvers/__init__.pyi create mode 100644 stubs/pyomo/contrib/pynumero/algorithms/solvers/cyipopt_solver.pyi create mode 100644 stubs/pyomo/contrib/pynumero/algorithms/solvers/implicit_functions.pyi create mode 100644 stubs/pyomo/contrib/pynumero/algorithms/solvers/pyomo_ext_cyipopt.pyi create mode 100644 stubs/pyomo/contrib/pynumero/algorithms/solvers/scipy_solvers.pyi create mode 100644 stubs/pyomo/contrib/pynumero/algorithms/solvers/square_solver_base.pyi create mode 100644 stubs/pyomo/contrib/pynumero/asl.pyi create mode 100644 stubs/pyomo/contrib/pynumero/build.pyi create mode 100644 stubs/pyomo/contrib/pynumero/dependencies.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/__init__.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/callback/__init__.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/callback/cyipopt_callback.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/callback/cyipopt_callback_halt.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/callback/cyipopt_functor_callback.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/callback/reactor_design.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/external_grey_box/__init__.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/external_grey_box/external_with_objective.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/external_grey_box/param_est/__init__.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/external_grey_box/param_est/generate_data.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/external_grey_box/param_est/models.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/external_grey_box/param_est/perform_estimation.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/external_grey_box/react_example/__init__.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/external_grey_box/react_example/maximize_cb_outputs.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/external_grey_box/react_example/maximize_cb_ratio_residuals.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/external_grey_box/react_example/reactor_model_outputs.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/external_grey_box/react_example/reactor_model_residuals.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/feasibility.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/mumps_example.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/nlp_interface.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/nlp_interface_2.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/parallel_matvec.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/parallel_vector_ops.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/sensitivity.pyi create mode 100644 stubs/pyomo/contrib/pynumero/examples/sqp.pyi create mode 100644 stubs/pyomo/contrib/pynumero/exceptions.pyi create mode 100644 stubs/pyomo/contrib/pynumero/interfaces/__init__.pyi create mode 100644 stubs/pyomo/contrib/pynumero/interfaces/ampl_nlp.pyi create mode 100644 stubs/pyomo/contrib/pynumero/interfaces/cyipopt_interface.pyi create mode 100644 stubs/pyomo/contrib/pynumero/interfaces/external_grey_box.pyi create mode 100644 stubs/pyomo/contrib/pynumero/interfaces/external_pyomo_model.pyi create mode 100644 stubs/pyomo/contrib/pynumero/interfaces/nlp.pyi create mode 100644 stubs/pyomo/contrib/pynumero/interfaces/nlp_projections.pyi create mode 100644 stubs/pyomo/contrib/pynumero/interfaces/pyomo_grey_box_nlp.pyi create mode 100644 stubs/pyomo/contrib/pynumero/interfaces/pyomo_nlp.pyi create mode 100644 stubs/pyomo/contrib/pynumero/interfaces/utils.pyi create mode 100644 stubs/pyomo/contrib/pynumero/intrinsic.pyi create mode 100644 stubs/pyomo/contrib/pynumero/linalg/__init__.pyi create mode 100644 stubs/pyomo/contrib/pynumero/linalg/base.pyi create mode 100644 stubs/pyomo/contrib/pynumero/linalg/ma27.pyi create mode 100644 stubs/pyomo/contrib/pynumero/linalg/ma27_interface.pyi create mode 100644 stubs/pyomo/contrib/pynumero/linalg/ma57.pyi create mode 100644 stubs/pyomo/contrib/pynumero/linalg/ma57_interface.pyi create mode 100644 stubs/pyomo/contrib/pynumero/linalg/mumps_interface.pyi create mode 100644 stubs/pyomo/contrib/pynumero/linalg/scipy_interface.pyi create mode 100644 stubs/pyomo/contrib/pynumero/linalg/utils.pyi create mode 100644 stubs/pyomo/contrib/pynumero/plugins.pyi create mode 100644 stubs/pyomo/contrib/pynumero/sparse/__init__.pyi create mode 100644 stubs/pyomo/contrib/pynumero/sparse/base_block.pyi create mode 100644 stubs/pyomo/contrib/pynumero/sparse/block_matrix.pyi create mode 100644 stubs/pyomo/contrib/pynumero/sparse/block_vector.pyi create mode 100644 stubs/pyomo/contrib/pynumero/sparse/mpi_block_matrix.pyi create mode 100644 stubs/pyomo/contrib/pynumero/sparse/mpi_block_vector.pyi create mode 100644 stubs/pyomo/contrib/pyros/__init__.pyi create mode 100644 stubs/pyomo/contrib/pyros/config.pyi create mode 100644 stubs/pyomo/contrib/pyros/master_problem_methods.pyi create mode 100644 stubs/pyomo/contrib/pyros/pyros.pyi create mode 100644 stubs/pyomo/contrib/pyros/pyros_algorithm_methods.pyi create mode 100644 stubs/pyomo/contrib/pyros/separation_problem_methods.pyi create mode 100644 stubs/pyomo/contrib/pyros/solve_data.pyi create mode 100644 stubs/pyomo/contrib/pyros/uncertainty_sets.pyi create mode 100644 stubs/pyomo/contrib/pyros/util.pyi create mode 100644 stubs/pyomo/contrib/satsolver/__init__.pyi create mode 100644 stubs/pyomo/contrib/satsolver/satsolver.pyi create mode 100644 stubs/pyomo/contrib/sensitivity_toolbox/__init__.pyi create mode 100644 stubs/pyomo/contrib/sensitivity_toolbox/examples/HIV_Transmission.pyi create mode 100644 stubs/pyomo/contrib/sensitivity_toolbox/examples/__init__.pyi create mode 100644 stubs/pyomo/contrib/sensitivity_toolbox/examples/feedbackController.pyi create mode 100644 stubs/pyomo/contrib/sensitivity_toolbox/examples/parameter.pyi create mode 100644 stubs/pyomo/contrib/sensitivity_toolbox/examples/parameter_kaug.pyi create mode 100644 stubs/pyomo/contrib/sensitivity_toolbox/examples/rangeInequality.pyi create mode 100644 stubs/pyomo/contrib/sensitivity_toolbox/examples/rooney_biegler.pyi create mode 100644 stubs/pyomo/contrib/sensitivity_toolbox/k_aug.pyi create mode 100644 stubs/pyomo/contrib/sensitivity_toolbox/sens.pyi create mode 100644 stubs/pyomo/contrib/simplification/__init__.pyi create mode 100644 stubs/pyomo/contrib/simplification/build.pyi create mode 100644 stubs/pyomo/contrib/simplification/ginac/__init__.pyi create mode 100644 stubs/pyomo/contrib/simplification/plugins.pyi create mode 100644 stubs/pyomo/contrib/simplification/simplify.pyi create mode 100644 stubs/pyomo/contrib/solver/__init__.pyi create mode 100644 stubs/pyomo/contrib/solver/common/__init__.pyi create mode 100644 stubs/pyomo/contrib/solver/common/base.pyi create mode 100644 stubs/pyomo/contrib/solver/common/config.pyi create mode 100644 stubs/pyomo/contrib/solver/common/factory.pyi create mode 100644 stubs/pyomo/contrib/solver/common/persistent.pyi create mode 100644 stubs/pyomo/contrib/solver/common/results.pyi create mode 100644 stubs/pyomo/contrib/solver/common/solution_loader.pyi create mode 100644 stubs/pyomo/contrib/solver/common/util.pyi create mode 100644 stubs/pyomo/contrib/solver/plugins.pyi create mode 100644 stubs/pyomo/contrib/solver/solvers/__init__.pyi create mode 100644 stubs/pyomo/contrib/solver/solvers/gurobi_direct.pyi create mode 100644 stubs/pyomo/contrib/solver/solvers/gurobi_persistent.pyi create mode 100644 stubs/pyomo/contrib/solver/solvers/highs.pyi create mode 100644 stubs/pyomo/contrib/solver/solvers/ipopt.pyi create mode 100644 stubs/pyomo/contrib/solver/solvers/sol_reader.pyi create mode 100644 stubs/pyomo/contrib/trustregion/TRF.pyi create mode 100644 stubs/pyomo/contrib/trustregion/__init__.pyi create mode 100644 stubs/pyomo/contrib/trustregion/examples/__init__.pyi create mode 100644 stubs/pyomo/contrib/trustregion/examples/example1.pyi create mode 100644 stubs/pyomo/contrib/trustregion/examples/example2.pyi create mode 100644 stubs/pyomo/contrib/trustregion/filter.pyi create mode 100644 stubs/pyomo/contrib/trustregion/interface.pyi create mode 100644 stubs/pyomo/contrib/trustregion/plugins.pyi create mode 100644 stubs/pyomo/contrib/trustregion/util.pyi create mode 100644 stubs/pyomo/contrib/viewer/__init__.pyi create mode 100644 stubs/pyomo/contrib/viewer/model_browser.pyi create mode 100644 stubs/pyomo/contrib/viewer/model_select.pyi create mode 100644 stubs/pyomo/contrib/viewer/pyomo_viewer.pyi create mode 100644 stubs/pyomo/contrib/viewer/qt.pyi create mode 100644 stubs/pyomo/contrib/viewer/report.pyi create mode 100644 stubs/pyomo/contrib/viewer/residual_table.pyi create mode 100644 stubs/pyomo/contrib/viewer/ui.pyi create mode 100644 stubs/pyomo/contrib/viewer/ui_data.pyi create mode 100644 stubs/pyomo/core/__init__.pyi create mode 100644 stubs/pyomo/core/base/PyomoModel.pyi create mode 100644 stubs/pyomo/core/base/__init__.pyi create mode 100644 stubs/pyomo/core/base/action.pyi create mode 100644 stubs/pyomo/core/base/block.pyi create mode 100644 stubs/pyomo/core/base/blockutil.pyi create mode 100644 stubs/pyomo/core/base/boolean_var.pyi create mode 100644 stubs/pyomo/core/base/check.pyi create mode 100644 stubs/pyomo/core/base/component.pyi create mode 100644 stubs/pyomo/core/base/component_namer.pyi create mode 100644 stubs/pyomo/core/base/component_order.pyi create mode 100644 stubs/pyomo/core/base/componentuid.pyi create mode 100644 stubs/pyomo/core/base/config.pyi create mode 100644 stubs/pyomo/core/base/connector.pyi create mode 100644 stubs/pyomo/core/base/constraint.pyi create mode 100644 stubs/pyomo/core/base/disable_methods.pyi create mode 100644 stubs/pyomo/core/base/enums.pyi create mode 100644 stubs/pyomo/core/base/expression.pyi create mode 100644 stubs/pyomo/core/base/external.pyi create mode 100644 stubs/pyomo/core/base/global_set.pyi create mode 100644 stubs/pyomo/core/base/indexed_component.pyi create mode 100644 stubs/pyomo/core/base/indexed_component_slice.pyi create mode 100644 stubs/pyomo/core/base/initializer.pyi create mode 100644 stubs/pyomo/core/base/instance2dat.pyi create mode 100644 stubs/pyomo/core/base/label.pyi create mode 100644 stubs/pyomo/core/base/logical_constraint.pyi create mode 100644 stubs/pyomo/core/base/matrix_constraint.pyi create mode 100644 stubs/pyomo/core/base/misc.pyi create mode 100644 stubs/pyomo/core/base/numvalue.pyi create mode 100644 stubs/pyomo/core/base/objective.pyi create mode 100644 stubs/pyomo/core/base/param.pyi create mode 100644 stubs/pyomo/core/base/piecewise.pyi create mode 100644 stubs/pyomo/core/base/range.pyi create mode 100644 stubs/pyomo/core/base/reference.pyi create mode 100644 stubs/pyomo/core/base/set.pyi create mode 100644 stubs/pyomo/core/base/set_types.pyi create mode 100644 stubs/pyomo/core/base/sos.pyi create mode 100644 stubs/pyomo/core/base/suffix.pyi create mode 100644 stubs/pyomo/core/base/symbol_map.pyi create mode 100644 stubs/pyomo/core/base/symbolic.pyi create mode 100644 stubs/pyomo/core/base/transformation.pyi create mode 100644 stubs/pyomo/core/base/units_container.pyi create mode 100644 stubs/pyomo/core/base/util.pyi create mode 100644 stubs/pyomo/core/base/var.pyi create mode 100644 stubs/pyomo/core/beta/__init__.pyi create mode 100644 stubs/pyomo/core/beta/dict_objects.pyi create mode 100644 stubs/pyomo/core/beta/list_objects.pyi create mode 100644 stubs/pyomo/core/expr/__init__.pyi create mode 100644 stubs/pyomo/core/expr/base.pyi create mode 100644 stubs/pyomo/core/expr/boolean_value.pyi create mode 100644 stubs/pyomo/core/expr/calculus/__init__.pyi create mode 100644 stubs/pyomo/core/expr/calculus/derivatives.pyi create mode 100644 stubs/pyomo/core/expr/calculus/diff_with_pyomo.pyi create mode 100644 stubs/pyomo/core/expr/calculus/diff_with_sympy.pyi create mode 100644 stubs/pyomo/core/expr/cnf_walker.pyi create mode 100644 stubs/pyomo/core/expr/compare.pyi create mode 100644 stubs/pyomo/core/expr/expr_common.pyi create mode 100644 stubs/pyomo/core/expr/expr_errors.pyi create mode 100644 stubs/pyomo/core/expr/logical_expr.pyi create mode 100644 stubs/pyomo/core/expr/ndarray.pyi create mode 100644 stubs/pyomo/core/expr/numeric_expr.pyi create mode 100644 stubs/pyomo/core/expr/numvalue.pyi create mode 100644 stubs/pyomo/core/expr/relational_expr.pyi create mode 100644 stubs/pyomo/core/expr/symbol_map.pyi create mode 100644 stubs/pyomo/core/expr/sympy_tools.pyi create mode 100644 stubs/pyomo/core/expr/taylor_series.pyi create mode 100644 stubs/pyomo/core/expr/template_expr.pyi create mode 100644 stubs/pyomo/core/expr/visitor.pyi create mode 100644 stubs/pyomo/core/kernel/__init__.pyi create mode 100644 stubs/pyomo/core/kernel/base.pyi create mode 100644 stubs/pyomo/core/kernel/block.pyi create mode 100644 stubs/pyomo/core/kernel/conic.pyi create mode 100644 stubs/pyomo/core/kernel/constraint.pyi create mode 100644 stubs/pyomo/core/kernel/container_utils.pyi create mode 100644 stubs/pyomo/core/kernel/dict_container.pyi create mode 100644 stubs/pyomo/core/kernel/expression.pyi create mode 100644 stubs/pyomo/core/kernel/heterogeneous_container.pyi create mode 100644 stubs/pyomo/core/kernel/homogeneous_container.pyi create mode 100644 stubs/pyomo/core/kernel/list_container.pyi create mode 100644 stubs/pyomo/core/kernel/matrix_constraint.pyi create mode 100644 stubs/pyomo/core/kernel/objective.pyi create mode 100644 stubs/pyomo/core/kernel/parameter.pyi create mode 100644 stubs/pyomo/core/kernel/piecewise_library/__init__.pyi create mode 100644 stubs/pyomo/core/kernel/piecewise_library/transforms.pyi create mode 100644 stubs/pyomo/core/kernel/piecewise_library/transforms_nd.pyi create mode 100644 stubs/pyomo/core/kernel/piecewise_library/util.pyi create mode 100644 stubs/pyomo/core/kernel/set_types.pyi create mode 100644 stubs/pyomo/core/kernel/sos.pyi create mode 100644 stubs/pyomo/core/kernel/suffix.pyi create mode 100644 stubs/pyomo/core/kernel/tuple_container.pyi create mode 100644 stubs/pyomo/core/kernel/variable.pyi create mode 100644 stubs/pyomo/core/plugins/__init__.pyi create mode 100644 stubs/pyomo/core/plugins/transform/__init__.pyi create mode 100644 stubs/pyomo/core/plugins/transform/add_slack_vars.pyi create mode 100644 stubs/pyomo/core/plugins/transform/discrete_vars.pyi create mode 100644 stubs/pyomo/core/plugins/transform/eliminate_fixed_vars.pyi create mode 100644 stubs/pyomo/core/plugins/transform/equality_transform.pyi create mode 100644 stubs/pyomo/core/plugins/transform/expand_connectors.pyi create mode 100644 stubs/pyomo/core/plugins/transform/hierarchy.pyi create mode 100644 stubs/pyomo/core/plugins/transform/logical_to_linear.pyi create mode 100644 stubs/pyomo/core/plugins/transform/lp_dual.pyi create mode 100644 stubs/pyomo/core/plugins/transform/model.pyi create mode 100644 stubs/pyomo/core/plugins/transform/nonnegative_transform.pyi create mode 100644 stubs/pyomo/core/plugins/transform/radix_linearization.pyi create mode 100644 stubs/pyomo/core/plugins/transform/relax_integrality.pyi create mode 100644 stubs/pyomo/core/plugins/transform/scaling.pyi create mode 100644 stubs/pyomo/core/plugins/transform/standard_form.pyi create mode 100644 stubs/pyomo/core/plugins/transform/util.pyi create mode 100644 stubs/pyomo/core/pyomoobject.pyi create mode 100644 stubs/pyomo/core/staleflag.pyi create mode 100644 stubs/pyomo/core/util.pyi create mode 100644 stubs/pyomo/dae/__init__.pyi create mode 100644 stubs/pyomo/dae/contset.pyi create mode 100644 stubs/pyomo/dae/diffvar.pyi create mode 100644 stubs/pyomo/dae/flatten.pyi create mode 100644 stubs/pyomo/dae/initialization.pyi create mode 100644 stubs/pyomo/dae/integral.pyi create mode 100644 stubs/pyomo/dae/misc.pyi create mode 100644 stubs/pyomo/dae/plugins/__init__.pyi create mode 100644 stubs/pyomo/dae/plugins/colloc.pyi create mode 100644 stubs/pyomo/dae/plugins/finitedifference.pyi create mode 100644 stubs/pyomo/dae/set_utils.pyi create mode 100644 stubs/pyomo/dae/simulator.pyi create mode 100644 stubs/pyomo/dae/utilities.pyi create mode 100644 stubs/pyomo/dataportal/DataPortal.pyi create mode 100644 stubs/pyomo/dataportal/TableData.pyi create mode 100644 stubs/pyomo/dataportal/__init__.pyi create mode 100644 stubs/pyomo/dataportal/factory.pyi create mode 100644 stubs/pyomo/dataportal/parse_datacmds.pyi create mode 100644 stubs/pyomo/dataportal/plugins/__init__.pyi create mode 100644 stubs/pyomo/dataportal/plugins/csv_table.pyi create mode 100644 stubs/pyomo/dataportal/plugins/datacommands.pyi create mode 100644 stubs/pyomo/dataportal/plugins/db_table.pyi create mode 100644 stubs/pyomo/dataportal/plugins/json_dict.pyi create mode 100644 stubs/pyomo/dataportal/plugins/sheet.pyi create mode 100644 stubs/pyomo/dataportal/plugins/text.pyi create mode 100644 stubs/pyomo/dataportal/plugins/xml_table.pyi create mode 100644 stubs/pyomo/dataportal/process_data.pyi create mode 100644 stubs/pyomo/duality/__init__.pyi create mode 100644 stubs/pyomo/duality/collect.pyi create mode 100644 stubs/pyomo/duality/lagrangian_dual.pyi create mode 100644 stubs/pyomo/duality/plugins.pyi create mode 100644 stubs/pyomo/environ/__init__.pyi create mode 100644 stubs/pyomo/future.pyi create mode 100644 stubs/pyomo/gdp/__init__.pyi create mode 100644 stubs/pyomo/gdp/basic_step.pyi create mode 100644 stubs/pyomo/gdp/disjunct.pyi create mode 100644 stubs/pyomo/gdp/plugins/__init__.pyi create mode 100644 stubs/pyomo/gdp/plugins/between_steps.pyi create mode 100644 stubs/pyomo/gdp/plugins/bigm.pyi create mode 100644 stubs/pyomo/gdp/plugins/bigm_mixin.pyi create mode 100644 stubs/pyomo/gdp/plugins/bilinear.pyi create mode 100644 stubs/pyomo/gdp/plugins/binary_multiplication.pyi create mode 100644 stubs/pyomo/gdp/plugins/bound_pretransformation.pyi create mode 100644 stubs/pyomo/gdp/plugins/cuttingplane.pyi create mode 100644 stubs/pyomo/gdp/plugins/fix_disjuncts.pyi create mode 100644 stubs/pyomo/gdp/plugins/gdp_to_mip_transformation.pyi create mode 100644 stubs/pyomo/gdp/plugins/gdp_var_mover.pyi create mode 100644 stubs/pyomo/gdp/plugins/hull.pyi create mode 100644 stubs/pyomo/gdp/plugins/multiple_bigm.pyi create mode 100644 stubs/pyomo/gdp/plugins/partition_disjuncts.pyi create mode 100644 stubs/pyomo/gdp/plugins/transform_current_disjunctive_state.pyi create mode 100644 stubs/pyomo/gdp/transformed_disjunct.pyi create mode 100644 stubs/pyomo/gdp/util.pyi create mode 100644 stubs/pyomo/kernel/__init__.pyi create mode 100644 stubs/pyomo/kernel/util.pyi create mode 100644 stubs/pyomo/mpec/__init__.pyi create mode 100644 stubs/pyomo/mpec/complementarity.pyi create mode 100644 stubs/pyomo/mpec/plugins/__init__.pyi create mode 100644 stubs/pyomo/mpec/plugins/mpec1.pyi create mode 100644 stubs/pyomo/mpec/plugins/mpec2.pyi create mode 100644 stubs/pyomo/mpec/plugins/mpec3.pyi create mode 100644 stubs/pyomo/mpec/plugins/mpec4.pyi create mode 100644 stubs/pyomo/mpec/plugins/pathampl.pyi create mode 100644 stubs/pyomo/mpec/plugins/solver1.pyi create mode 100644 stubs/pyomo/mpec/plugins/solver2.pyi create mode 100644 stubs/pyomo/neos/__init__.pyi create mode 100644 stubs/pyomo/neos/kestrel.pyi create mode 100644 stubs/pyomo/neos/plugins/NEOS.pyi create mode 100644 stubs/pyomo/neos/plugins/__init__.pyi create mode 100644 stubs/pyomo/neos/plugins/kestrel_plugin.pyi create mode 100644 stubs/pyomo/network/__init__.pyi create mode 100644 stubs/pyomo/network/arc.pyi create mode 100644 stubs/pyomo/network/decomposition.pyi create mode 100644 stubs/pyomo/network/foqus_graph.pyi create mode 100644 stubs/pyomo/network/plugins/__init__.pyi create mode 100644 stubs/pyomo/network/plugins/expand_arcs.pyi create mode 100644 stubs/pyomo/network/port.pyi create mode 100644 stubs/pyomo/network/util.pyi create mode 100644 stubs/pyomo/opt/__init__.pyi create mode 100644 stubs/pyomo/opt/base/__init__.pyi create mode 100644 stubs/pyomo/opt/base/convert.pyi create mode 100644 stubs/pyomo/opt/base/error.pyi create mode 100644 stubs/pyomo/opt/base/formats.pyi create mode 100644 stubs/pyomo/opt/base/opt_config.pyi create mode 100644 stubs/pyomo/opt/base/problem.pyi create mode 100644 stubs/pyomo/opt/base/results.pyi create mode 100644 stubs/pyomo/opt/base/solvers.pyi create mode 100644 stubs/pyomo/opt/parallel/__init__.pyi create mode 100644 stubs/pyomo/opt/parallel/async_solver.pyi create mode 100644 stubs/pyomo/opt/parallel/local.pyi create mode 100644 stubs/pyomo/opt/parallel/manager.pyi create mode 100644 stubs/pyomo/opt/plugins/__init__.pyi create mode 100644 stubs/pyomo/opt/plugins/driver.pyi create mode 100644 stubs/pyomo/opt/plugins/res.pyi create mode 100644 stubs/pyomo/opt/plugins/sol.pyi create mode 100644 stubs/pyomo/opt/problem/__init__.pyi create mode 100644 stubs/pyomo/opt/problem/ampl.pyi create mode 100644 stubs/pyomo/opt/results.pyi create mode 100644 stubs/pyomo/opt/results/__init__.pyi create mode 100644 stubs/pyomo/opt/results/container.pyi create mode 100644 stubs/pyomo/opt/results/problem.pyi create mode 100644 stubs/pyomo/opt/results/results_.pyi create mode 100644 stubs/pyomo/opt/results/solution.pyi create mode 100644 stubs/pyomo/opt/results/solver.pyi create mode 100644 stubs/pyomo/opt/solver/__init__.pyi create mode 100644 stubs/pyomo/opt/solver/ilmcmd.pyi create mode 100644 stubs/pyomo/opt/solver/shellcmd.pyi create mode 100644 stubs/pyomo/repn/__init__.pyi create mode 100644 stubs/pyomo/repn/ampl.pyi create mode 100644 stubs/pyomo/repn/beta/__init__.pyi create mode 100644 stubs/pyomo/repn/beta/matrix.pyi create mode 100644 stubs/pyomo/repn/linear.pyi create mode 100644 stubs/pyomo/repn/linear_template.pyi create mode 100644 stubs/pyomo/repn/parameterized_linear.pyi create mode 100644 stubs/pyomo/repn/parameterized_quadratic.pyi create mode 100644 stubs/pyomo/repn/plugins/__init__.pyi create mode 100644 stubs/pyomo/repn/plugins/ampl/__init__.pyi create mode 100644 stubs/pyomo/repn/plugins/ampl/ampl_.pyi create mode 100644 stubs/pyomo/repn/plugins/baron_writer.pyi create mode 100644 stubs/pyomo/repn/plugins/cpxlp.pyi create mode 100644 stubs/pyomo/repn/plugins/gams_writer.pyi create mode 100644 stubs/pyomo/repn/plugins/lp_writer.pyi create mode 100644 stubs/pyomo/repn/plugins/mps.pyi create mode 100644 stubs/pyomo/repn/plugins/nl_writer.pyi create mode 100644 stubs/pyomo/repn/plugins/parameterized_standard_form.pyi create mode 100644 stubs/pyomo/repn/plugins/standard_form.pyi create mode 100644 stubs/pyomo/repn/quadratic.pyi create mode 100644 stubs/pyomo/repn/standard_aux.pyi create mode 100644 stubs/pyomo/repn/standard_repn.pyi create mode 100644 stubs/pyomo/repn/util.pyi create mode 100644 stubs/pyomo/scripting/__init__.pyi create mode 100644 stubs/pyomo/scripting/commands.pyi create mode 100644 stubs/pyomo/scripting/convert.pyi create mode 100644 stubs/pyomo/scripting/driver_help.pyi create mode 100644 stubs/pyomo/scripting/interface.pyi create mode 100644 stubs/pyomo/scripting/plugins/__init__.pyi create mode 100644 stubs/pyomo/scripting/plugins/build_ext.pyi create mode 100644 stubs/pyomo/scripting/plugins/convert.pyi create mode 100644 stubs/pyomo/scripting/plugins/download.pyi create mode 100644 stubs/pyomo/scripting/plugins/extras.pyi create mode 100644 stubs/pyomo/scripting/plugins/solve.pyi create mode 100644 stubs/pyomo/scripting/pyomo_command.pyi create mode 100644 stubs/pyomo/scripting/pyomo_main.pyi create mode 100644 stubs/pyomo/scripting/pyomo_parser.pyi create mode 100644 stubs/pyomo/scripting/solve_config.pyi create mode 100644 stubs/pyomo/scripting/util.pyi create mode 100644 stubs/pyomo/solvers/__init__.pyi create mode 100644 stubs/pyomo/solvers/amplfunc_merge.pyi create mode 100644 stubs/pyomo/solvers/mockmip.pyi create mode 100644 stubs/pyomo/solvers/plugins/__init__.pyi create mode 100644 stubs/pyomo/solvers/plugins/converter/__init__.pyi create mode 100644 stubs/pyomo/solvers/plugins/converter/ampl.pyi create mode 100644 stubs/pyomo/solvers/plugins/converter/glpsol.pyi create mode 100644 stubs/pyomo/solvers/plugins/converter/model.pyi create mode 100644 stubs/pyomo/solvers/plugins/converter/pico.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/ASL.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/BARON.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/CBCplugin.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/CONOPT.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/CPLEX.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/GAMS.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/GLPK.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/GUROBI.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/GUROBI_RUN.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/IPOPT.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/KNITROAMPL.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/SAS.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/SCIPAMPL.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/XPRESS.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/__init__.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/cplex_direct.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/cplex_persistent.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/direct_or_persistent_solver.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/direct_solver.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/gurobi_direct.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/gurobi_persistent.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/mosek_direct.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/mosek_persistent.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/persistent_solver.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/pywrapper.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/xpress_direct.pyi create mode 100644 stubs/pyomo/solvers/plugins/solvers/xpress_persistent.pyi create mode 100644 stubs/pyomo/solvers/wrappers.pyi create mode 100644 stubs/pyomo/util/__init__.pyi create mode 100644 stubs/pyomo/util/blockutil.pyi create mode 100644 stubs/pyomo/util/calc_var_value.pyi create mode 100644 stubs/pyomo/util/check_units.pyi create mode 100644 stubs/pyomo/util/components.pyi create mode 100644 stubs/pyomo/util/config_domains.pyi create mode 100644 stubs/pyomo/util/diagnostics.pyi create mode 100644 stubs/pyomo/util/infeasible.pyi create mode 100644 stubs/pyomo/util/model_size.pyi create mode 100644 stubs/pyomo/util/report_scaling.pyi create mode 100644 stubs/pyomo/util/slices.pyi create mode 100644 stubs/pyomo/util/subsystems.pyi create mode 100644 stubs/pyomo/util/vars_from_expressions.pyi create mode 100644 stubs/pyomo/version/__init__.pyi create mode 100644 stubs/pyomo/version/info.pyi diff --git a/.coderabbit.yaml b/.coderabbit.yaml index 8f34c034f..4329ecbd2 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -129,7 +129,7 @@ reviews: # Specify file patterns to include or exclude in a review using glob patterns (e.g., !dist/**, src/**). These patterns also apply to 'git sparse-checkout', including specified patterns and ignoring excluded ones (starting with '!') when cloning the repository. # Default: [] - path_filters: [] + path_filters: ["!stubs/**"] # Path Instructions - Provide specific additional guidelines for code review based on file paths. # Default: [] diff --git a/.gitignore b/.gitignore index a4704d842..221ddf110 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ !notebooks/ !output_files/ !.github/ +!stubs/ # unignore files !.gitignore diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f0d5889bd..78d1311f3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ repos: - repo: https://github.com/astral-sh/uv-pre-commit # uv version. - rev: 0.8.0 + rev: 0.9.3 hooks: # Dependency management - id: uv-lock @@ -28,7 +28,7 @@ repos: # Code quality and formatting - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: v6.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -39,10 +39,15 @@ repos: - id: check-added-large-files args: ["--maxkb=1024"] - id: debug-statements + - repo: https://github.com/asottile/pyupgrade + rev: v3.21.0 + hooks: + - id: pyupgrade + args: ["--py312-plus"] # Python Linting & Formatting with Ruff - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: "v0.12.4" + rev: "v0.14.1" hooks: - id: ruff name: ruff (linter) diff --git a/pyproject.toml b/pyproject.toml index 29c182b65..bc753ba55 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,6 +38,18 @@ dependencies = [ "gravis>=0.1.0", ] + +[dependency-groups] +dev = [ + "gurobipy>=12.0.3", + "types-deprecated>=1.2.15.20250304", + "ruff>=0.2.0", + "pre-commit", + "pytest", + "pytest-cov", + "pandas-stubs>=2.3.2.250926", +] + [project.optional-dependencies] docs = [ "sphinx>=7.4.7", @@ -47,12 +59,6 @@ docs = [ "sphinxcontrib-bibtex>=2.6.2", ] -dev = [ - "ruff>=0.2.0", - "pre-commit", - "pytest", - "pytest-cov", -] plotting = [ "matplotlib>=3.9.2", "seaborn>=0.13.2", @@ -65,6 +71,7 @@ build-backend = "hatchling.build" [tool.ruff] line-length = 100 indent-width = 4 +exclude = ["stubs"] [tool.ruff.format] quote-style = "single" @@ -88,10 +95,85 @@ testpaths = [ "tests", ] -[dependency-groups] -dev = [ - "gurobipy>=12.0.3", +[tool.mypy] +# Python version targeting +python_version = "3.12" + +# Tell mypy to also look for stubs in this directory +mypy_path = "stubs" + +# Exclude specific directories from type checking will try to add them back gradually +exclude = "(?x)(^tests/|^temoa/model_checking/|^temoa/data_processing/|^temoa/extensions/|^temoa/utilities/|^docs/)" + +# Strict typing for our own code +disallow_untyped_defs = true +disallow_incomplete_defs = true +check_untyped_defs = true +disallow_untyped_decorators = true +no_implicit_optional = true +warn_redundant_casts = true +warn_unused_ignores = true +warn_no_return = true +warn_unreachable = true +strict_equality = true + +# Handle external dependencies gracefully +ignore_missing_imports = false + +# Be explicit about Any usage +disallow_any_generics = true +disallow_any_unimported = true +disallow_any_expr = false # temporarily false to ease transition +disallow_any_decorated = true +disallow_any_explicit = true + +# Module-specific overrides for external dependencies +[[tool.mypy.overrides]] +module = [ + "pyomo.*", ] +ignore_missing_imports = true + +# Less strict for test files initially +[[tool.mypy.overrides]] +module = "tests.*" +disallow_untyped_defs = false + +disallow_incomplete_defs = false + +# Silence errors from excluded modules (follow imports but don't report errors) +[[tool.mypy.overrides]] +module = [ + "temoa.data_processing.*", + "temoa.extensions.*", + "temoa.model_checking.*", +] +follow_imports = "silent" + +# Enable strict checking for core modules +[[tool.mypy.overrides]] +module = [ + "temoa.core.*", + "temoa.components.*", + "temoa._internal.*", + "temoa.data_io.*", + "temoa.model_checking.*", +] +disallow_untyped_defs = true +disallow_incomplete_defs = true +check_untyped_defs = true + +# Less strict for type definitions (allow Any for stubs) +[[tool.mypy.overrides]] +module = "temoa.types.*" +disallow_any_explicit = false + +# Relax Any restrictions for Pyomo-related code +[[tool.mypy.overrides]] +module = ["temoa.components.*", "temoa._internal.*"] +disallow_any_explicit = false +disallow_any_unimported = false + [project.urls] Homepage = "https://temoaproject.org" diff --git a/requirements-dev.txt b/requirements-dev.txt index 00db4ec30..51527dabd 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -40,8 +40,6 @@ certifi==2025.7.14 # requests cffi==1.17.1 # via argon2-cffi-bindings -cfgv==3.4.0 - # via pre-commit charset-normalizer==3.4.2 # via requests click==8.2.1 @@ -52,8 +50,6 @@ comm==0.2.2 # ipywidgets contourpy==1.3.2 # via matplotlib -coverage==7.9.2 - # via pytest-cov cycler==0.12.1 # via matplotlib debugpy==1.8.15 @@ -66,8 +62,6 @@ deprecated==1.2.18 # via temoa (pyproject.toml) dill==0.4.0 # via multiprocess -distlib==0.3.9 - # via virtualenv docutils==0.21.2 # via # pybtex-docutils @@ -82,8 +76,6 @@ fastapi==0.116.1 # via ixmp4 fastjsonschema==2.21.1 # via nbformat -filelock==3.18.0 - # via virtualenv flexcache==0.3 # via pint flexparser==0.4 @@ -118,8 +110,6 @@ hyperframe==6.1.0 # via h2 iam-units==2023.9.12 # via pyam-iamc -identify==2.6.12 - # via pre-commit idna==3.10 # via # anyio @@ -288,8 +278,6 @@ networkx==3.5 # via # temoa (pyproject.toml) # nx-vis-visualizer -nodeenv==1.9.1 - # via pre-commit nose==1.3.7 # via pyutilib notebook==7.4.4 @@ -363,15 +351,10 @@ platformdirs==4.3.8 # via # jupyter-core # pint - # virtualenv pluggy==1.6.0 - # via - # pytest - # pytest-cov + # via pytest ply==3.11 # via pyomo -pre-commit==4.2.0 - # via temoa (pyproject.toml) prometheus-client==0.22.1 # via jupyter-server prompt-toolkit==3.0.51 @@ -428,10 +411,6 @@ pyomo==6.9.2 pyparsing==3.2.3 # via matplotlib pytest==8.4.1 - # via - # temoa (pyproject.toml) - # pytest-cov -pytest-cov==6.2.1 # via temoa (pyproject.toml) python-dateutil==2.9.0.post0 # via @@ -453,7 +432,6 @@ pyyaml==6.0.2 # via # jupyter-events # jupyter-nbextensions-configurator - # pre-commit # pyam-iamc # pybtex pyzmq==27.0.0 @@ -490,8 +468,6 @@ rpds-py==0.26.0 # via # jsonschema # referencing -ruff==0.12.3 - # via temoa (pyproject.toml) salib==1.5.1 # via temoa (pyproject.toml) scipy==1.16.0 @@ -647,8 +623,6 @@ uri-template==1.3.0 # via jsonschema urllib3==2.5.0 # via requests -virtualenv==20.31.2 - # via pre-commit wcwidth==0.2.13 # via prompt-toolkit webcolors==24.11.1 diff --git a/stubs/pyomo/__init__.pyi b/stubs/pyomo/__init__.pyi new file mode 100644 index 000000000..34bfef24c --- /dev/null +++ b/stubs/pyomo/__init__.pyi @@ -0,0 +1,4 @@ +from pyomo.common.deprecation import moved_module as moved_module + +from . import common as common +from .version import __version__ as __version__ diff --git a/stubs/pyomo/_archive/__init__.pyi b/stubs/pyomo/_archive/__init__.pyi new file mode 100644 index 000000000..3a03abe59 --- /dev/null +++ b/stubs/pyomo/_archive/__init__.pyi @@ -0,0 +1 @@ +__doc__: str diff --git a/stubs/pyomo/_archive/chull.pyi b/stubs/pyomo/_archive/chull.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/_archive/component_map.pyi b/stubs/pyomo/_archive/component_map.pyi new file mode 100644 index 000000000..9ca2b6f68 --- /dev/null +++ b/stubs/pyomo/_archive/component_map.pyi @@ -0,0 +1 @@ +from pyomo.common.collections import ComponentMap as ComponentMap diff --git a/stubs/pyomo/_archive/component_set.pyi b/stubs/pyomo/_archive/component_set.pyi new file mode 100644 index 000000000..2094a8416 --- /dev/null +++ b/stubs/pyomo/_archive/component_set.pyi @@ -0,0 +1 @@ +from pyomo.common.collections import ComponentSet as ComponentSet diff --git a/stubs/pyomo/_archive/current.pyi b/stubs/pyomo/_archive/current.pyi new file mode 100644 index 000000000..ecc3a5386 --- /dev/null +++ b/stubs/pyomo/_archive/current.pyi @@ -0,0 +1,127 @@ +from pyomo.core.expr import AbsExpression as AbsExpression +from pyomo.core.expr import AndExpression as AndExpression +from pyomo.core.expr import AtLeastExpression as AtLeastExpression +from pyomo.core.expr import AtMostExpression as AtMostExpression +from pyomo.core.expr import BinaryBooleanExpression as BinaryBooleanExpression +from pyomo.core.expr import Boolean_GetAttrExpression as Boolean_GetAttrExpression +from pyomo.core.expr import Boolean_GetItemExpression as Boolean_GetItemExpression +from pyomo.core.expr import BooleanConstant as BooleanConstant +from pyomo.core.expr import BooleanExpressionBase as BooleanExpressionBase +from pyomo.core.expr import BooleanValue as BooleanValue +from pyomo.core.expr import CallExpression as CallExpression +from pyomo.core.expr import DivisionExpression as DivisionExpression +from pyomo.core.expr import EqualityExpression as EqualityExpression +from pyomo.core.expr import EquivalenceExpression as EquivalenceExpression +from pyomo.core.expr import ExactlyExpression as ExactlyExpression +from pyomo.core.expr import Expr_if as Expr_if +from pyomo.core.expr import Expr_ifExpression as Expr_ifExpression +from pyomo.core.expr import ExpressionBase as ExpressionBase +from pyomo.core.expr import ExpressionReplacementVisitor as ExpressionReplacementVisitor +from pyomo.core.expr import ExpressionValueVisitor as ExpressionValueVisitor +from pyomo.core.expr import ExternalFunctionExpression as ExternalFunctionExpression +from pyomo.core.expr import FixedExpressionError as FixedExpressionError +from pyomo.core.expr import GetAttrExpression as GetAttrExpression +from pyomo.core.expr import GetItemExpression as GetItemExpression +from pyomo.core.expr import ImplicationExpression as ImplicationExpression +from pyomo.core.expr import IndexTemplate as IndexTemplate +from pyomo.core.expr import InequalityExpression as InequalityExpression +from pyomo.core.expr import LinearDecompositionError as LinearDecompositionError +from pyomo.core.expr import LinearExpression as LinearExpression +from pyomo.core.expr import Mode as Mode +from pyomo.core.expr import MonomialTermExpression as MonomialTermExpression +from pyomo.core.expr import NaryBooleanExpression as NaryBooleanExpression +from pyomo.core.expr import NegationExpression as NegationExpression +from pyomo.core.expr import NonConstantExpressionError as NonConstantExpressionError +from pyomo.core.expr import NotExpression as NotExpression +from pyomo.core.expr import NPV_AbsExpression as NPV_AbsExpression +from pyomo.core.expr import NPV_Boolean_GetAttrExpression as NPV_Boolean_GetAttrExpression +from pyomo.core.expr import NPV_Boolean_GetItemExpression as NPV_Boolean_GetItemExpression +from pyomo.core.expr import NPV_DivisionExpression as NPV_DivisionExpression +from pyomo.core.expr import NPV_Expr_ifExpression as NPV_Expr_ifExpression +from pyomo.core.expr import NPV_expression_types as NPV_expression_types +from pyomo.core.expr import NPV_ExternalFunctionExpression as NPV_ExternalFunctionExpression +from pyomo.core.expr import NPV_NegationExpression as NPV_NegationExpression +from pyomo.core.expr import NPV_Numeric_GetAttrExpression as NPV_Numeric_GetAttrExpression +from pyomo.core.expr import NPV_Numeric_GetItemExpression as NPV_Numeric_GetItemExpression +from pyomo.core.expr import NPV_PowExpression as NPV_PowExpression +from pyomo.core.expr import NPV_ProductExpression as NPV_ProductExpression +from pyomo.core.expr import NPV_Structural_GetAttrExpression as NPV_Structural_GetAttrExpression +from pyomo.core.expr import NPV_Structural_GetItemExpression as NPV_Structural_GetItemExpression +from pyomo.core.expr import NPV_SumExpression as NPV_SumExpression +from pyomo.core.expr import NPV_UnaryFunctionExpression as NPV_UnaryFunctionExpression +from pyomo.core.expr import Numeric_GetAttrExpression as Numeric_GetAttrExpression +from pyomo.core.expr import Numeric_GetItemExpression as Numeric_GetItemExpression +from pyomo.core.expr import NumericExpression as NumericExpression +from pyomo.core.expr import NumericValue as NumericValue +from pyomo.core.expr import OrExpression as OrExpression +from pyomo.core.expr import PowExpression as PowExpression +from pyomo.core.expr import ProductExpression as ProductExpression +from pyomo.core.expr import RangedExpression as RangedExpression +from pyomo.core.expr import RelationalExpression as RelationalExpression +from pyomo.core.expr import ReplaceTemplateExpression as ReplaceTemplateExpression +from pyomo.core.expr import SimpleExpressionVisitor as SimpleExpressionVisitor +from pyomo.core.expr import StreamBasedExpressionVisitor as StreamBasedExpressionVisitor +from pyomo.core.expr import Structural_GetAttrExpression as Structural_GetAttrExpression +from pyomo.core.expr import Structural_GetItemExpression as Structural_GetItemExpression +from pyomo.core.expr import SumExpression as SumExpression +from pyomo.core.expr import SumExpressionBase as SumExpressionBase +from pyomo.core.expr import SymbolMap as SymbolMap +from pyomo.core.expr import TemplateExpressionError as TemplateExpressionError +from pyomo.core.expr import TemplateSumExpression as TemplateSumExpression +from pyomo.core.expr import UnaryBooleanExpression as UnaryBooleanExpression +from pyomo.core.expr import UnaryFunctionExpression as UnaryFunctionExpression +from pyomo.core.expr import XorExpression as XorExpression +from pyomo.core.expr import acos as acos +from pyomo.core.expr import acosh as acosh +from pyomo.core.expr import as_numeric as as_numeric +from pyomo.core.expr import asin as asin +from pyomo.core.expr import asinh as asinh +from pyomo.core.expr import atan as atan +from pyomo.core.expr import atanh as atanh +from pyomo.core.expr import atleast as atleast +from pyomo.core.expr import atmost as atmost +from pyomo.core.expr import ceil as ceil +from pyomo.core.expr import clone_expression as clone_expression +from pyomo.core.expr import cos as cos +from pyomo.core.expr import cosh as cosh +from pyomo.core.expr import decompose_term as decompose_term +from pyomo.core.expr import equivalent as equivalent +from pyomo.core.expr import evaluate_expression as evaluate_expression +from pyomo.core.expr import exactly as exactly +from pyomo.core.expr import exp as exp +from pyomo.core.expr import expression_to_string as expression_to_string +from pyomo.core.expr import floor as floor +from pyomo.core.expr import identify_components as identify_components +from pyomo.core.expr import identify_mutable_parameters as identify_mutable_parameters +from pyomo.core.expr import identify_variables as identify_variables +from pyomo.core.expr import implies as implies +from pyomo.core.expr import inequality as inequality +from pyomo.core.expr import land as land +from pyomo.core.expr import linear_expression as linear_expression +from pyomo.core.expr import lnot as lnot +from pyomo.core.expr import log as log +from pyomo.core.expr import log10 as log10 +from pyomo.core.expr import lor as lor +from pyomo.core.expr import native_logical_types as native_logical_types +from pyomo.core.expr import native_numeric_types as native_numeric_types +from pyomo.core.expr import native_types as native_types +from pyomo.core.expr import nonlinear_expression as nonlinear_expression +from pyomo.core.expr import nonpyomo_leaf_types as nonpyomo_leaf_types +from pyomo.core.expr import polynomial_degree as polynomial_degree +from pyomo.core.expr import replace_expressions as replace_expressions +from pyomo.core.expr import resolve_template as resolve_template +from pyomo.core.expr import sin as sin +from pyomo.core.expr import sinh as sinh +from pyomo.core.expr import sizeof_expression as sizeof_expression +from pyomo.core.expr import special_boolean_atom_types as special_boolean_atom_types +from pyomo.core.expr import sqrt as sqrt +from pyomo.core.expr import substitute_getitem_with_param as substitute_getitem_with_param +from pyomo.core.expr import substitute_template_expression as substitute_template_expression +from pyomo.core.expr import substitute_template_with_value as substitute_template_with_value +from pyomo.core.expr import tan as tan +from pyomo.core.expr import tanh as tanh +from pyomo.core.expr import templatize_constraint as templatize_constraint +from pyomo.core.expr import templatize_rule as templatize_rule +from pyomo.core.expr import value as value +from pyomo.core.expr import xor as xor +from pyomo.core.expr.expr_common import clone_counter as clone_counter diff --git a/stubs/pyomo/_archive/plugin.pyi b/stubs/pyomo/_archive/plugin.pyi new file mode 100644 index 000000000..e6deb9430 --- /dev/null +++ b/stubs/pyomo/_archive/plugin.pyi @@ -0,0 +1,30 @@ +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.transformation import Transformation as Transformation +from pyomo.core.base.transformation import TransformationData as TransformationData +from pyomo.core.base.transformation import TransformationFactory as TransformationFactory +from pyomo.core.base.transformation import TransformationInfo as TransformationInfo +from pyomo.core.base.transformation import TransformationTimer as TransformationTimer +from pyomo.scripting.interface import DeprecatedInterface as DeprecatedInterface +from pyomo.scripting.interface import ExtensionPoint as ExtensionPoint +from pyomo.scripting.interface import Interface as Interface +from pyomo.scripting.interface import IPyomoPresolveAction as IPyomoPresolveAction +from pyomo.scripting.interface import IPyomoPresolver as IPyomoPresolver +from pyomo.scripting.interface import IPyomoScriptCreateDataPortal as IPyomoScriptCreateDataPortal +from pyomo.scripting.interface import IPyomoScriptCreateModel as IPyomoScriptCreateModel +from pyomo.scripting.interface import IPyomoScriptModifyInstance as IPyomoScriptModifyInstance +from pyomo.scripting.interface import IPyomoScriptPostprocess as IPyomoScriptPostprocess +from pyomo.scripting.interface import IPyomoScriptPreprocess as IPyomoScriptPreprocess +from pyomo.scripting.interface import IPyomoScriptPrintInstance as IPyomoScriptPrintInstance +from pyomo.scripting.interface import IPyomoScriptPrintModel as IPyomoScriptPrintModel +from pyomo.scripting.interface import IPyomoScriptPrintResults as IPyomoScriptPrintResults +from pyomo.scripting.interface import IPyomoScriptSaveInstance as IPyomoScriptSaveInstance +from pyomo.scripting.interface import IPyomoScriptSaveResults as IPyomoScriptSaveResults +from pyomo.scripting.interface import Plugin as Plugin +from pyomo.scripting.interface import implements as implements +from pyomo.scripting.interface import pyomo_callback as pyomo_callback + +class IPyomoExpression(DeprecatedInterface): + def type(self) -> None: ... + def create(self, args) -> None: ... + +class IParamRepresentation(DeprecatedInterface): ... diff --git a/stubs/pyomo/_archive/rangeset.pyi b/stubs/pyomo/_archive/rangeset.pyi new file mode 100644 index 000000000..b13d84222 --- /dev/null +++ b/stubs/pyomo/_archive/rangeset.pyi @@ -0,0 +1 @@ +from pyomo.core.base.set import RangeSet as RangeSet diff --git a/stubs/pyomo/_archive/register_numpy_types.pyi b/stubs/pyomo/_archive/register_numpy_types.pyi new file mode 100644 index 000000000..e519b8933 --- /dev/null +++ b/stubs/pyomo/_archive/register_numpy_types.pyi @@ -0,0 +1,18 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies import numpy as numpy +from pyomo.common.numeric_types import RegisterBooleanType as RegisterBooleanType +from pyomo.common.numeric_types import RegisterIntegerType as RegisterIntegerType +from pyomo.common.numeric_types import RegisterNumericType as RegisterNumericType +from pyomo.common.numeric_types import native_boolean_types as native_boolean_types +from pyomo.common.numeric_types import native_complex_types as native_complex_types +from pyomo.common.numeric_types import native_integer_types as native_integer_types +from pyomo.common.numeric_types import native_numeric_types as native_numeric_types + +numpy_int_names: Incomplete +numpy_int: Incomplete +numpy_float_names: Incomplete +numpy_float: Incomplete +numpy_bool_names: Incomplete +numpy_bool: Incomplete +numpy_complex_names: Incomplete +numpy_complex: Incomplete diff --git a/stubs/pyomo/_archive/sets.pyi b/stubs/pyomo/_archive/sets.pyi new file mode 100644 index 000000000..29c397ed4 --- /dev/null +++ b/stubs/pyomo/_archive/sets.pyi @@ -0,0 +1,7 @@ +from pyomo.core.base.set import IndexedSet as IndexedSet +from pyomo.core.base.set import Set as Set +from pyomo.core.base.set import SetData as SetData +from pyomo.core.base.set import SetOf as SetOf +from pyomo.core.base.set import process_setarg as process_setarg +from pyomo.core.base.set import set_options as set_options +from pyomo.core.base.set import simple_set_rule as simple_set_rule diff --git a/stubs/pyomo/_archive/template_expr.pyi b/stubs/pyomo/_archive/template_expr.pyi new file mode 100644 index 000000000..1c6801e76 --- /dev/null +++ b/stubs/pyomo/_archive/template_expr.pyi @@ -0,0 +1,2 @@ +from pyomo.core.expr.template_expr import IndexTemplate as IndexTemplate +from pyomo.core.expr.template_expr import TemplateExpressionError as TemplateExpressionError diff --git a/stubs/pyomo/common/__init__.pyi b/stubs/pyomo/common/__init__.pyi new file mode 100644 index 000000000..1eb009460 --- /dev/null +++ b/stubs/pyomo/common/__init__.pyi @@ -0,0 +1,17 @@ +from . import config as config +from . import dependencies as dependencies +from . import envvar as envvar +from . import log as log +from . import shutdown as shutdown +from . import timing as timing +from ._command import get_pyomo_commands as get_pyomo_commands +from ._command import pyomo_command as pyomo_command +from .deprecation import deprecated as deprecated +from .deprecation import moved_module as moved_module +from .errors import DeveloperError as DeveloperError +from .factory import Factory as Factory +from .fileutils import Executable as Executable +from .fileutils import Library as Library +from .fileutils import register_executable as register_executable +from .fileutils import registered_executable as registered_executable +from .fileutils import unregister_executable as unregister_executable diff --git a/stubs/pyomo/common/_command.pyi b/stubs/pyomo/common/_command.pyi new file mode 100644 index 000000000..7b4ad01b5 --- /dev/null +++ b/stubs/pyomo/common/_command.pyi @@ -0,0 +1,7 @@ +from _typeshed import Incomplete + +logger: Incomplete +registry: Incomplete + +def pyomo_command(name=None, doc=None): ... +def get_pyomo_commands(): ... diff --git a/stubs/pyomo/common/_common.pyi b/stubs/pyomo/common/_common.pyi new file mode 100644 index 000000000..95613821b --- /dev/null +++ b/stubs/pyomo/common/_common.pyi @@ -0,0 +1,6 @@ +from _typeshed import Incomplete + +old_help: Incomplete +old_help = help + +def help(thing=None) -> None: ... diff --git a/stubs/pyomo/common/autoslots.pyi b/stubs/pyomo/common/autoslots.pyi new file mode 100644 index 000000000..45a27800d --- /dev/null +++ b/stubs/pyomo/common/autoslots.pyi @@ -0,0 +1,30 @@ +import collections +from typing import NamedTuple + +from _typeshed import Incomplete + +class _autoslot_info(NamedTuple): + has_dict: Incomplete + slots: Incomplete + slot_mappers: Incomplete + field_mappers: Incomplete + +class _DeepcopyDispatcher(collections.defaultdict): + def __missing__(self, key): ... + +def fast_deepcopy(obj, memo): ... + +class AutoSlots(type): + def __init__(cls, name, bases, classdict) -> None: ... + @staticmethod + def collect_autoslots(cls) -> None: ... + @staticmethod + def weakref_mapper(encode, val): ... + @staticmethod + def weakref_sequence_mapper(encode, val): ... + @staticmethod + def encode_as_none(encode, val): ... + class Mixin: + def __init_subclass__(cls, **kwds) -> None: ... + def __deepcopy__(self, memo): ... + def __deepcopy_state__(self, memo, new_object) -> None: ... diff --git a/stubs/pyomo/common/backports.pyi b/stubs/pyomo/common/backports.pyi new file mode 100644 index 000000000..21f55e254 --- /dev/null +++ b/stubs/pyomo/common/backports.pyi @@ -0,0 +1 @@ +from pyomo.common.deprecation import relocated_module_attribute as relocated_module_attribute diff --git a/stubs/pyomo/common/cmake_builder.pyi b/stubs/pyomo/common/cmake_builder.pyi new file mode 100644 index 000000000..5b323868d --- /dev/null +++ b/stubs/pyomo/common/cmake_builder.pyi @@ -0,0 +1,7 @@ +from pyomo.common.fileutils import find_executable as find_executable +from pyomo.common.fileutils import this_file_dir as this_file_dir + +def handleReadonly(function, path, excinfo) -> None: ... +def build_cmake_project( + targets, package_name=None, description=None, user_args=[], parallel=None +) -> None: ... diff --git a/stubs/pyomo/common/collections/__init__.pyi b/stubs/pyomo/common/collections/__init__.pyi new file mode 100644 index 000000000..355d79497 --- /dev/null +++ b/stubs/pyomo/common/collections/__init__.pyi @@ -0,0 +1,13 @@ +from collections import UserDict as UserDict +from collections.abc import Mapping as Mapping +from collections.abc import MutableMapping as MutableMapping +from collections.abc import MutableSet as MutableSet +from collections.abc import Sequence as Sequence +from collections.abc import Set as Set + +from .bunch import Bunch as Bunch +from .component_map import ComponentMap as ComponentMap +from .component_map import DefaultComponentMap as DefaultComponentMap +from .component_set import ComponentSet as ComponentSet +from .orderedset import OrderedDict as OrderedDict +from .orderedset import OrderedSet as OrderedSet diff --git a/stubs/pyomo/common/collections/bunch.pyi b/stubs/pyomo/common/collections/bunch.pyi new file mode 100644 index 000000000..ecd3d90d3 --- /dev/null +++ b/stubs/pyomo/common/collections/bunch.pyi @@ -0,0 +1,10 @@ +class Bunch(dict): + def __init__(self, *args, **kw) -> None: ... + def update(self, d): ... + def set_name(self, name) -> None: ... + def __getitem__(self, name): ... + def __setitem__(self, name, val) -> None: ... + def __delitem__(self, name) -> None: ... + def __getattr__(self, name): ... + def __setattr__(self, name, val) -> None: ... + def __delattr__(self, name) -> None: ... diff --git a/stubs/pyomo/common/collections/component_map.pyi b/stubs/pyomo/common/collections/component_map.pyi new file mode 100644 index 000000000..0f82b50d7 --- /dev/null +++ b/stubs/pyomo/common/collections/component_map.pyi @@ -0,0 +1,31 @@ +import collections + +from _typeshed import Incomplete +from pyomo.common.autoslots import AutoSlots as AutoSlots + +class _Hasher(collections.defaultdict): + def __init__(self, *args, **kwargs) -> None: ... + def hashable(self, obj, hashable=None): ... + +class ComponentMap(AutoSlots.Mixin, collections.abc.MutableMapping): + __autoslot_mappers__: Incomplete + hasher: Incomplete + def __init__(self, *args, **kwds) -> None: ... + def __getitem__(self, obj): ... + def __setitem__(self, obj, val) -> None: ... + def __delitem__(self, obj) -> None: ... + def __iter__(self): ... + def __len__(self) -> int: ... + def update(self, *args, **kwargs): ... + def __eq__(self, other): ... + def __ne__(self, other): ... + def __contains__(self, obj) -> bool: ... + def clear(self) -> None: ... + def get(self, key, default=None): ... + def setdefault(self, key, default=None): ... + +class DefaultComponentMap(ComponentMap): + default_factory: Incomplete + def __init__(self, default_factory=None, *args, **kwargs) -> None: ... + def __missing__(self, key): ... + def __getitem__(self, obj): ... diff --git a/stubs/pyomo/common/collections/component_set.pyi b/stubs/pyomo/common/collections/component_set.pyi new file mode 100644 index 000000000..4ff0b9ea1 --- /dev/null +++ b/stubs/pyomo/common/collections/component_set.pyi @@ -0,0 +1,19 @@ +from collections.abc import MutableSet as collections_MutableSet + +from _typeshed import Incomplete +from pyomo.common.autoslots import AutoSlots as AutoSlots + +class ComponentSet(AutoSlots.Mixin, collections_MutableSet): + __autoslot_mappers__: Incomplete + hasher: Incomplete + def __init__(self, iterable=None) -> None: ... + def update(self, iterable) -> None: ... + def __contains__(self, val) -> bool: ... + def __iter__(self): ... + def __len__(self) -> int: ... + def add(self, val) -> None: ... + def discard(self, val) -> None: ... + def __eq__(self, other): ... + def __ne__(self, other): ... + def clear(self) -> None: ... + def remove(self, val) -> None: ... diff --git a/stubs/pyomo/common/collections/orderedset.pyi b/stubs/pyomo/common/collections/orderedset.pyi new file mode 100644 index 000000000..abed5a8e0 --- /dev/null +++ b/stubs/pyomo/common/collections/orderedset.pyi @@ -0,0 +1,18 @@ +from collections import OrderedDict as OrderedDict +from collections.abc import MutableSet + +from pyomo.common.autoslots import AutoSlots as AutoSlots + +class OrderedSet(AutoSlots.Mixin, MutableSet): + def __init__(self, iterable=None) -> None: ... + def update(self, iterable) -> None: ... + def __contains__(self, val) -> bool: ... + def __iter__(self): ... + def __len__(self) -> int: ... + def add(self, val) -> None: ... + def discard(self, val) -> None: ... + def clear(self) -> None: ... + def remove(self, val) -> None: ... + def intersection(self, other): ... + def union(self, other): ... + def __reversed__(self): ... diff --git a/stubs/pyomo/common/config.pyi b/stubs/pyomo/common/config.pyi new file mode 100644 index 000000000..e0fff8278 --- /dev/null +++ b/stubs/pyomo/common/config.pyi @@ -0,0 +1,238 @@ +import enum +import types +from collections.abc import Generator + +from _typeshed import Incomplete +from pyomo.common.collections import Mapping as Mapping +from pyomo.common.collections import Sequence as Sequence +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.common.deprecation import relocated_module_attribute as relocated_module_attribute +from pyomo.common.fileutils import import_file as import_file +from pyomo.common.flags import NOTSET as NOTSET +from pyomo.common.flags import building_documentation as building_documentation +from pyomo.common.formatting import wrap_reStructuredText as wrap_reStructuredText + +logger: Incomplete +USER_OPTION: int +ADVANCED_OPTION: int +DEVELOPER_OPTION: int + +def Bool(val): ... +def Integer(val): ... +def PositiveInt(val): ... +def NegativeInt(val): ... +def NonPositiveInt(val): ... +def NonNegativeInt(val): ... +def PositiveFloat(val): ... +def NegativeFloat(val): ... +def NonPositiveFloat(val): ... +def NonNegativeFloat(val): ... + +class In: + def __new__(cls, domain=None, cast=None): ... + def __init__(self, domain, cast=None) -> None: ... + def __call__(self, value): ... + def domain_name(self): ... + +class InEnum: + def __init__(self, domain) -> None: ... + def __call__(self, value): ... + def domain_name(self): ... + +class IsInstance: + baseClasses: Incomplete + document_full_base_names: Incomplete + def __init__(self, *bases, document_full_base_names: bool = False) -> None: ... + def __call__(self, obj): ... + def domain_name(self): ... + +class ListOf: + itemtype: Incomplete + domain: Incomplete + string_lexer: Incomplete + def __init__(self, itemtype, domain=None, string_lexer=...) -> None: ... + def __call__(self, value): ... + def domain_name(self): ... + +class Module: + basePath: Incomplete + expandPath: Incomplete + def __init__(self, basePath=None, expandPath=None) -> None: ... + def __call__(self, module_id): ... + +class Path: + BasePath: Incomplete + SuppressPathExpansion: bool + basePath: Incomplete + expandPath: Incomplete + def __init__(self, basePath=None, expandPath=None) -> None: ... + def __call__(self, path): ... + def domain_name(self): ... + +class PathList(Path): + def __call__(self, data): ... + +class DynamicImplicitDomain: + callback: Incomplete + def __init__(self, callback) -> None: ... + def __call__(self, key, value): ... + +class ConfigEnum(enum.Enum): + def __new__(cls, value, *args): ... + @classmethod + def from_enum_or_string(cls, arg): ... + +__doc__: str + +class _UnpickleableDomain: + def __init__(self, obj) -> None: ... + def __call__(self, arg): ... + +class ConfigFormatter: + def generate(self, config, indent_spacing: int = 2, width: int = 78, visibility=None): ... + +class String_ConfigFormatter(ConfigFormatter): + def __init__(self, block_start, block_end, item_start, item_body, item_end) -> None: ... + +class LaTeX_ConfigFormatter(String_ConfigFormatter): + def __init__(self) -> None: ... + +class numpydoc_ConfigFormatter(ConfigFormatter): ... + +def add_docstring_list(docstring, configdict, indent_by: int = 4): ... + +class document_kwargs_from_configdict: + config: Incomplete + section: Incomplete + indent_spacing: Incomplete + width: Incomplete + visibility: Incomplete + doc: Incomplete + def __init__( + self, + config, + section: str = 'Keyword Arguments', + indent_spacing: int = 4, + width: int = 78, + visibility=None, + doc=None, + ) -> None: ... + def __call__(self, fcn): ... + +class UninitializedMixin: ... + +class ConfigBase: + class NoArgument: ... + __class__: Incomplete + def __init__( + self, default=None, domain=None, description=None, doc=None, visibility: int = 0 + ) -> None: ... + def __call__( + self, + value=..., + default=..., + domain=..., + description=..., + doc=..., + visibility=..., + implicit=..., + implicit_domain=..., + preserve_implicit: bool = False, + ): ... + def name(self, fully_qualified: bool = False): ... + def domain_name(self): ... + def set_default_value(self, default) -> None: ... + def set_domain(self, domain) -> None: ... + def reset(self) -> None: ... + def declare_as_argument(self, *args, **kwds): ... + def initialize_argparse(self, parser): ... + def import_argparse(self, parsed_args): ... + def display( + self, content_filter=None, indent_spacing: int = 2, ostream=None, visibility=None + ) -> None: ... + def generate_yaml_template( + self, indent_spacing: int = 2, width: int = 78, visibility: int = 0 + ): ... + def generate_documentation( + self, + block_start=None, + block_end=None, + item_start=None, + item_body=None, + item_end=None, + indent_spacing: int = 2, + width: int = 78, + visibility=None, + format: str = 'latex', + ): ... + def user_values(self) -> Generator[Incomplete]: ... + def unused_user_values(self) -> Generator[Incomplete]: ... + +class ConfigValue(ConfigBase): + def value(self, accessValue: bool = True): ... + def set_value(self, value) -> None: ... + +class ImmutableConfigValue(ConfigValue): + def __new__(self, *args, **kwds): ... + +class MarkImmutable: + def __init__(self, *args) -> None: ... + def lock(self) -> None: ... + def release_lock(self) -> None: ... + def __enter__(self): ... + def __exit__( + self, t: type[BaseException] | None, v: BaseException | None, tb: types.TracebackType | None + ) -> None: ... + +class ConfigList(ConfigBase, Sequence): + def __init__( + self, default=None, domain=None, description=None, doc=None, visibility: int = 0 + ) -> None: ... + def __getitem__(self, key): ... + def get(self, key, default=...): ... + def __setitem__(self, key, val) -> None: ... + def __len__(self) -> int: ... + def __iter__(self): ... + def value(self, accessValue: bool = True): ... + def set_value(self, value) -> None: ... + def append(self, value=...) -> None: ... + def add(self, value=...): ... + +class ConfigDict(ConfigBase, Mapping): + content_filters: Incomplete + def __init__( + self, + description=None, + doc=None, + implicit: bool = False, + implicit_domain=None, + visibility: int = 0, + ) -> None: ... + def domain_name(self): ... + def __dir__(self): ... + def __getitem__(self, key): ... + def get(self, key, default=...): ... + def setdefault(self, key, default=...): ... + def __setitem__(self, key, val) -> None: ... + def __delitem__(self, key) -> None: ... + def __contains__(self, key) -> bool: ... + def __len__(self) -> int: ... + def __iter__(self): ... + def __getattr__(self, attr): ... + def __setattr__(self, name, value) -> None: ... + def __delattr__(self, name) -> None: ... + def keys(self): ... + def values(self): ... + def items(self) -> Generator[Incomplete]: ... + def iterkeys(self): ... + def itervalues(self): ... + def iteritems(self): ... + def declare(self, name, config): ... + def declare_from(self, other, skip=None) -> None: ... + def add(self, name, config): ... + def value(self, accessValue: bool = True): ... + def set_value(self, value, skip_implicit: bool = False): ... + def reset(self) -> None: ... + +ConfigBlock = ConfigDict diff --git a/stubs/pyomo/common/dependencies.pyi b/stubs/pyomo/common/dependencies.pyi new file mode 100644 index 000000000..cfc7be4a9 --- /dev/null +++ b/stubs/pyomo/common/dependencies.pyi @@ -0,0 +1,128 @@ +import types +from types import ModuleType + +from _typeshed import Incomplete +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.common.errors import DeferredImportError as DeferredImportError +from pyomo.common.flags import building_documentation as building_documentation +from pyomo.common.flags import in_testing_environment as in_testing_environment +from pyomo.common.flags import serializing as serializing + +SUPPRESS_DEPENDENCY_WARNINGS: bool + +class ModuleUnavailable: + def __init__(self, name, message, version_error, import_error, package) -> None: ... + def __getattr__(self, attr) -> None: ... + def mro(self): ... + def log_import_warning(self, logger: str = 'pyomo', msg=None) -> None: ... + def generate_import_warning(self, logger: str = 'pyomo.common') -> None: ... + +class DeferredImportModule: + def __init__(self, indicator, deferred_submodules, submodule_name) -> None: ... + def __getattr__(self, attr): ... + def mro(self): ... + +def UnavailableClass(unavailable_module): ... + +class _DeferredImportIndicatorBase: + def __and__(self, other): ... + def __or__(self, other): ... + def __rand__(self, other): ... + def __ror__(self, other): ... + +class DeferredImportIndicator(_DeferredImportIndicatorBase): + def __init__( + self, + name, + error_message, + catch_exceptions, + minimum_version, + original_globals, + callback, + importer, + deferred_submodules, + ) -> None: ... + def __bool__(self) -> bool: ... + def resolve(self) -> None: ... + def replace_self_in_globals(self, _globals) -> None: ... + +class _DeferredAnd(_DeferredImportIndicatorBase): + def __init__(self, a, b) -> None: ... + def __bool__(self) -> bool: ... + +class _DeferredOr(_DeferredImportIndicatorBase): + def __init__(self, a, b) -> None: ... + def __bool__(self) -> bool: ... + +def check_min_version(module, min_version): ... + +class DeferredImportCallbackLoader: + def __init__(self, loader, deferred_indicators: list[DeferredImportIndicator]) -> None: ... + def module_repr(self, module: ModuleType) -> str: ... + def create_module(self, spec) -> ModuleType: ... + def exec_module(self, module: ModuleType) -> None: ... + def load_module(self, fullname) -> ModuleType: ... + +class DeferredImportCallbackFinder: + def find_spec(self, fullname, path, target=None): ... + def invalidate_caches(self) -> None: ... + +def attempt_import( + name, + error_message=None, + only_catch_importerror=None, + minimum_version=None, + alt_names=None, + callback=None, + importer=None, + defer_check=None, + defer_import=None, + deferred_submodules=None, + catch_exceptions=None, +): ... +def declare_deferred_modules_as_importable(globals_dict): ... + +class declare_modules_as_importable: + globals_dict: Incomplete + init_dict: Incomplete + init_modules: Incomplete + def __init__(self, globals_dict) -> None: ... + def __enter__(self) -> None: ... + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: ... + +yaml_load_args: Incomplete +ctypes: Incomplete +_: Incomplete +random: Incomplete +dill: Incomplete +dill_available: Incomplete +mpi4py: Incomplete +mpi4py_available: Incomplete +networkx: Incomplete +networkx_available: Incomplete +numpy: Incomplete +numpy_available: Incomplete +pandas: Incomplete +pandas_available: Incomplete +pathlib: Incomplete +pathlib_available: Incomplete +pint: Incomplete +pint_available: Incomplete +plotly: Incomplete +plotly_available: Incomplete +pympler: Incomplete +pympler_available: Incomplete +pyutilib: Incomplete +pyutilib_available: Incomplete +scipy: Incomplete +scipy_available: Incomplete +yaml: Incomplete +yaml_available: Incomplete +matplotlib: Incomplete +matplotlib_available: Incomplete diff --git a/stubs/pyomo/common/deprecation.pyi b/stubs/pyomo/common/deprecation.pyi new file mode 100644 index 000000000..86bcdb14a --- /dev/null +++ b/stubs/pyomo/common/deprecation.pyi @@ -0,0 +1,45 @@ +import types +from typing import NamedTuple + +from _typeshed import Incomplete +from pyomo.common.errors import DeveloperError as DeveloperError +from pyomo.common.flags import NOTSET as NOTSET +from pyomo.common.flags import building_documentation as building_documentation +from pyomo.common.flags import in_testing_environment as in_testing_environment + +def default_deprecation_msg(obj, user_msg, version, remove_in): ... +def deprecation_warning( + msg, logger=None, version=None, remove_in=None, calling_frame=None +) -> None: ... +def deprecated(msg=None, logger=None, version=None, remove_in=None): ... +def relocated_module(new_name, msg=None, logger=None, version=None, remove_in=None) -> None: ... +def relocated_module_attribute( + local, target, version, remove_in=None, msg=None, f_globals=None +): ... + +class RenamedClass(type): + def __new__(cls, name, bases, classdict, *args, **kwargs): ... + def __instancecheck__(cls, instance): ... + def __subclasscheck__(cls, subclass): ... + +class MovedModuleLoader: + def __init__(self, info) -> None: ... + def create_module(self, spec) -> types.ModuleType: ... + def exec_module(self, module: types.ModuleType) -> None: ... + +class MovedModuleFinder: + mapping: Incomplete + def find_spec(self, fullname, path, target=None): ... + def invalidate_caches(self) -> None: ... + +class MovedModuleInfo(NamedTuple): + old_name: str + new_name: str + msg: str + logger: str + version: str + remove_in: str + +def moved_module( + old_name, new_name, msg=..., logger=None, version=None, remove_in=None +) -> None: ... diff --git a/stubs/pyomo/common/download.pyi b/stubs/pyomo/common/download.pyi new file mode 100644 index 000000000..c90097c36 --- /dev/null +++ b/stubs/pyomo/common/download.pyi @@ -0,0 +1,41 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import + +from . import envvar as envvar +from .deprecation import deprecated as deprecated +from .errors import DeveloperError as DeveloperError + +request: Incomplete +urllib_error: Incomplete +ssl: Incomplete +zipfile: Incomplete +tarfile: Incomplete +gzip: Incomplete +distro: Incomplete +distro_available: Incomplete +logger: Incomplete +DownloadFactory: Incomplete + +class FileDownloader: + target: Incomplete + insecure: Incomplete + cacert: Incomplete + def __init__(self, insecure: bool = False, cacert=None) -> None: ... + @classmethod + def get_sysinfo(cls): ... + @classmethod + def get_os_version(cls, normalize: bool = True): ... + def get_url(self, urlmap): ... + def get_platform_url(self, urlmap): ... + def create_parser(self, parser=None): ... + def parse_args(self, argv) -> None: ... + def set_destination_filename(self, default) -> None: ... + def destination(self): ... + def retrieve_url(self, url): ... + def get_file(self, url, binary) -> None: ... + def get_binary_file(self, url): ... + def get_text_file(self, url): ... + def get_binary_file_from_zip_archive(self, url, srcname) -> None: ... + def get_zip_archive(self, url, dirOffset: int = 0) -> None: ... + def get_tar_archive(self, url, dirOffset: int = 0): ... + def get_gzipped_binary_file(self, url) -> None: ... diff --git a/stubs/pyomo/common/enums.pyi b/stubs/pyomo/common/enums.pyi new file mode 100644 index 000000000..02f42777e --- /dev/null +++ b/stubs/pyomo/common/enums.pyi @@ -0,0 +1,28 @@ +import enum + +from _typeshed import Incomplete + +Enum = enum.Enum + +class IntEnum(enum.IntEnum): + __doc__ = ... + def to_bytes(self, /, length: int = 1, byteorder: str = 'big', *, signed: bool = False): ... + @classmethod + def from_bytes(cls, bytes, byteorder: str = 'big', *, signed: bool = False): ... + +class ExtendedEnumType(_EnumType): + def __getattr__(cls, attr): ... + def __iter__(cls): ... + def __contains__(cls, member) -> bool: ... + def __dir__(self): ... + def __instancecheck__(cls, instance): ... + def __new__(metacls, cls, bases, classdict, **kwds): ... + +class NamedIntEnum(IntEnum): ... + +class ObjectiveSense(NamedIntEnum): + minimize = 1 + maximize = -1 + +minimize: Incomplete +maximize: Incomplete diff --git a/stubs/pyomo/common/env.pyi b/stubs/pyomo/common/env.pyi new file mode 100644 index 000000000..e7fdc1608 --- /dev/null +++ b/stubs/pyomo/common/env.pyi @@ -0,0 +1,58 @@ +import types + +from _typeshed import Incomplete + +from .dependencies import ctypes as ctypes + +class _RestorableEnvironInterface: + dll: Incomplete + def __init__(self, dll) -> None: ... + def restore(self) -> None: ... + def __getitem__(self, key): ... + def __setitem__(self, key, val) -> None: ... + def __delitem__(self, key) -> None: ... + +class _OSEnviron: + def available(self): ... + def get_env_dict(self): ... + def getenv(self, key): ... + def wgetenv(self, key): ... + def putenv_s(self, key, val) -> None: ... + def wputenv_s(self, key, val) -> None: ... + +class _MsvcrtDLL: + dll: Incomplete + def __init__(self, name) -> None: ... + putenv_s: Incomplete + wputenv_s: Incomplete + getenv: Incomplete + wgetenv: Incomplete + def available(self): ... + def get_env_dict(self): ... + +class _Win32DLL: + dll: Incomplete + def __init__(self, name) -> None: ... + putenv_s: Incomplete + wputenv_s: Incomplete + def available(self): ... + def getenv(self, key): ... + def wgetenv(self, key): ... + def get_env_dict(self): ... + +class CtypesEnviron: + DLLs: Incomplete + interfaces: Incomplete + def __init__(self, **kwds) -> None: ... + def __enter__(self): ... + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + exc_traceback: types.TracebackType | None, + ) -> None: ... + def restore(self) -> None: ... + def __getitem__(self, key): ... + def __contains__(self, key) -> bool: ... + def __setitem__(self, key, val) -> None: ... + def __delitem__(self, key) -> None: ... diff --git a/stubs/pyomo/common/envvar.pyi b/stubs/pyomo/common/envvar.pyi new file mode 100644 index 000000000..c9f7bfc5f --- /dev/null +++ b/stubs/pyomo/common/envvar.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +PYOMO_CONFIG_DIR: Incomplete diff --git a/stubs/pyomo/common/errors.pyi b/stubs/pyomo/common/errors.pyi new file mode 100644 index 000000000..fde7c3021 --- /dev/null +++ b/stubs/pyomo/common/errors.pyi @@ -0,0 +1,19 @@ +from _typeshed import Incomplete + +def format_exception(msg, prolog=None, epilog=None, exception=None, width: int = 76): ... + +class ApplicationError(Exception): ... +class PyomoException(Exception): ... +class DeferredImportError(ImportError): ... +class DeveloperError(PyomoException, NotImplementedError): ... +class InfeasibleConstraintException(PyomoException): ... +class IterationLimitError(PyomoException, RuntimeError): ... +class IntervalException(PyomoException, ValueError): ... +class InvalidValueError(PyomoException, ValueError): ... +class MouseTrap(PyomoException, NotImplementedError): ... +class NondifferentiableError(PyomoException, ValueError): ... +class TempfileContextError(PyomoException, IndexError): ... + +class TemplateExpressionError(ValueError): + template: Incomplete + def __init__(self, template, *args, **kwds) -> None: ... diff --git a/stubs/pyomo/common/extensions.pyi b/stubs/pyomo/common/extensions.pyi new file mode 100644 index 000000000..a89dd55eb --- /dev/null +++ b/stubs/pyomo/common/extensions.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +ExtensionBuilderFactory: Incomplete diff --git a/stubs/pyomo/common/factory.pyi b/stubs/pyomo/common/factory.pyi new file mode 100644 index 000000000..8210142cc --- /dev/null +++ b/stubs/pyomo/common/factory.pyi @@ -0,0 +1,9 @@ +class Factory: + def __init__(self, description=None) -> None: ... + def __call__(self, name, **kwds): ... + def __iter__(self): ... + def __contains__(self, name) -> bool: ... + def get_class(self, name): ... + def doc(self, name): ... + def unregister(self, name) -> None: ... + def register(self, name, doc=None): ... diff --git a/stubs/pyomo/common/fileutils.pyi b/stubs/pyomo/common/fileutils.pyi new file mode 100644 index 000000000..b959c4679 --- /dev/null +++ b/stubs/pyomo/common/fileutils.pyi @@ -0,0 +1,65 @@ +from _typeshed import Incomplete + +from . import envvar as envvar +from .dependencies import ctypes as ctypes +from .deprecation import deprecated as deprecated +from .deprecation import relocated_module_attribute as relocated_module_attribute + +def this_file(stack_offset: int = 1): ... +def this_file_dir(stack_offset: int = 1): ... + +PYOMO_ROOT_DIR: Incomplete + +def find_path( + name, + validate, + cwd: bool = True, + mode=..., + ext=None, + pathlist=[], + allow_pathlist_deep_references: bool = True, +): ... +def find_file( + filename, + cwd: bool = True, + mode=..., + ext=None, + pathlist=[], + allow_pathlist_deep_references: bool = True, +): ... +def find_dir( + dirname, cwd: bool = True, mode=..., pathlist=[], allow_pathlist_deep_references: bool = True +): ... +def find_library(libname, cwd: bool = True, include_PATH: bool = True, pathlist=None): ... +def find_executable(exename, cwd: bool = True, include_PATH: bool = True, pathlist=None): ... +def import_file(path, clear_cache: bool = False, infer_package: bool = True, module_name=None): ... + +class PathData: + def __init__(self, manager, name) -> None: ... + def path(self): ... + def set_path(self, value) -> None: ... + def get_path(self): ... + def disable(self) -> None: ... + def available(self): ... + def rehash(self) -> None: ... + def __nonzero__(self): ... + __bool__ = __nonzero__ + +class ExecutableData(PathData): + @property + def executable(self): ... + @executable.setter + def executable(self, value) -> None: ... + +class PathManager: + pathlist: Incomplete + def __init__(self, finder, dataClass) -> None: ... + def __call__(self, path): ... + def rehash(self) -> None: ... + +Executable: Incomplete +Library: Incomplete + +def register_executable(name, validate=None): ... +def registered_executable(name): ... +def unregister_executable(name) -> None: ... diff --git a/stubs/pyomo/common/flags.pyi b/stubs/pyomo/common/flags.pyi new file mode 100644 index 000000000..1575dd598 --- /dev/null +++ b/stubs/pyomo/common/flags.pyi @@ -0,0 +1,8 @@ +class FlagType(type): + def __new__(mcs, name, bases, dct): ... + +class NOTSET(metaclass=FlagType): ... + +def in_testing_environment(state=...): ... +def building_documentation(state=...): ... +def serializing(): ... diff --git a/stubs/pyomo/common/formatting.pyi b/stubs/pyomo/common/formatting.pyi new file mode 100644 index 000000000..b1e2bf17e --- /dev/null +++ b/stubs/pyomo/common/formatting.pyi @@ -0,0 +1,17 @@ +from _typeshed import Incomplete +from pyomo.common.sorting import sorted_robust as sorted_robust + +def tostr(value, quote_str: bool = False): ... +def tabular_writer(ostream, prefix, data, header, row_generator) -> None: ... + +class StreamIndenter: + os: Incomplete + indent: Incomplete + stripped_indent: Incomplete + newline: bool + def __init__(self, ostream, indent=...) -> None: ... + def __getattr__(self, name): ... + def write(self, data) -> None: ... + def writelines(self, sequence) -> None: ... + +def wrap_reStructuredText(docstr, wrapper): ... diff --git a/stubs/pyomo/common/gc_manager.pyi b/stubs/pyomo/common/gc_manager.pyi new file mode 100644 index 000000000..8a32ecc86 --- /dev/null +++ b/stubs/pyomo/common/gc_manager.pyi @@ -0,0 +1,22 @@ +import types + +from _typeshed import Incomplete +from pyomo.common.multithread import MultiThreadWrapper as MultiThreadWrapper + +class __PauseGCCompanion: + def __init__(self) -> None: ... + +PauseGCCompanion: __PauseGCCompanion + +class PauseGC: + stack_pointer: Incomplete + reenable_gc: Incomplete + def __init__(self) -> None: ... + def __enter__(self): ... + def __exit__( + self, + type: type[BaseException] | None, + value: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: ... + def close(self) -> None: ... diff --git a/stubs/pyomo/common/gsl.pyi b/stubs/pyomo/common/gsl.pyi new file mode 100644 index 000000000..dd5490eba --- /dev/null +++ b/stubs/pyomo/common/gsl.pyi @@ -0,0 +1,8 @@ +from _typeshed import Incomplete +from pyomo.common import Library as Library +from pyomo.common.deprecation import deprecated as deprecated + +logger: Incomplete + +def get_gsl(downloader) -> None: ... +def find_GSL(): ... diff --git a/stubs/pyomo/common/log.pyi b/stubs/pyomo/common/log.pyi new file mode 100644 index 000000000..416fa4e94 --- /dev/null +++ b/stubs/pyomo/common/log.pyi @@ -0,0 +1,96 @@ +import io +import logging +import types +from collections.abc import Generator + +from _typeshed import Incomplete +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.fileutils import PYOMO_ROOT_DIR as PYOMO_ROOT_DIR +from pyomo.common.flags import building_documentation as building_documentation +from pyomo.common.flags import in_testing_environment as in_testing_environment +from pyomo.common.formatting import wrap_reStructuredText as wrap_reStructuredText +from pyomo.version.info import releaselevel as releaselevel + +def RTD(_id): ... +def is_debug_set(logger): ... + +class WrappingFormatter(logging.Formatter): + basepath: Incomplete + def __init__(self, **kwds) -> None: ... + def format(self, record): ... + +class LegacyPyomoFormatter(logging.Formatter): + verbosity: Incomplete + standard_formatter: Incomplete + verbose_formatter: Incomplete + def __init__(self, **kwds) -> None: ... + def format(self, record): ... + +class StdoutHandler(logging.StreamHandler): + stream: Incomplete + def flush(self) -> None: ... + def emit(self, record) -> None: ... + +class Preformatted: + msg: Incomplete + def __init__(self, msg) -> None: ... + +class _GlobalLogFilter: + logger: Incomplete + def __init__(self) -> None: ... + def filter(self, record): ... + +pyomo_logger: Incomplete +pyomo_handler: Incomplete +pyomo_formatter: Incomplete + +class LogHandler(logging.StreamHandler): + def __init__(self, base: str = '', stream=None, level=..., verbosity=None) -> None: ... + +class LoggingIntercept: + handler: Incomplete + output: Incomplete + def __init__( + self, output=None, module=None, level=..., formatter=None, logger=None + ) -> None: ... + def __enter__(self): ... + def __exit__( + self, + et: type[BaseException] | None, + ev: BaseException | None, + tb: types.TracebackType | None, + ) -> None: ... + @property + def module(self): ... + +class LogStream(io.TextIOBase): + def __init__(self, level, logger) -> None: ... + def write(self, s: str) -> int: ... + def flush(self) -> None: ... + def redirect_streams(self, redirects) -> Generator[Incomplete]: ... + +class _StreamRedirector: + handler: Incomplete + fd: Incomplete + orig_stream: Incomplete + def __init__(self, handler, fd) -> None: ... + def __enter__(self) -> None: ... + def __exit__( + self, + et: type[BaseException] | None, + ev: BaseException | None, + tb: types.TracebackType | None, + ) -> None: ... + +class _LastResortRedirector: + fd: Incomplete + orig_stream: Incomplete + def __init__(self, fd) -> None: ... + orig: Incomplete + def __enter__(self) -> None: ... + def __exit__( + self, + et: type[BaseException] | None, + ev: BaseException | None, + tb: types.TracebackType | None, + ) -> None: ... diff --git a/stubs/pyomo/common/modeling.pyi b/stubs/pyomo/common/modeling.pyi new file mode 100644 index 000000000..70c94e066 --- /dev/null +++ b/stubs/pyomo/common/modeling.pyi @@ -0,0 +1,8 @@ +from .dependencies import random as random +from .flags import NOTSET as NOTSET +from .flags import FlagType as FlagType + +NoArgumentGiven = NOTSET + +def randint(a, b): ... +def unique_component_name(instance, name): ... diff --git a/stubs/pyomo/common/multithread.pyi b/stubs/pyomo/common/multithread.pyi new file mode 100644 index 000000000..2208f79cd --- /dev/null +++ b/stubs/pyomo/common/multithread.pyi @@ -0,0 +1,22 @@ +import types + +class MultiThreadWrapper: + def __init__(self, base) -> None: ... + def __getattr__(self, attr): ... + def __setattr__(self, attr, value) -> None: ... + def __delattr__(self, attr) -> None: ... + def __enter__(self): ... + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: types.TracebackType | None, + ): ... + def __dir__(self): ... + def __new__(cls, wrapped): ... + +class MultiThreadWrapperWithMain(MultiThreadWrapper): + def __init__(self, base) -> None: ... + def __getattr__(self, attr): ... + def __setattr__(self, attr, value) -> None: ... + def __dir__(self): ... diff --git a/stubs/pyomo/common/numeric_types.pyi b/stubs/pyomo/common/numeric_types.pyi new file mode 100644 index 000000000..d17a82fe2 --- /dev/null +++ b/stubs/pyomo/common/numeric_types.pyi @@ -0,0 +1,22 @@ +from _typeshed import Incomplete +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.deprecation import relocated_module_attribute as relocated_module_attribute +from pyomo.common.errors import TemplateExpressionError as TemplateExpressionError + +logger: Incomplete +nonpyomo_leaf_types: Incomplete +native_numeric_types: Incomplete +native_integer_types: Incomplete +native_logical_types: Incomplete +native_complex_types: Incomplete +native_types: Incomplete + +def RegisterNumericType(new_type: type): ... +def RegisterIntegerType(new_type: type): ... +def RegisterBooleanType(new_type: type): ... +def RegisterComplexType(new_type: type): ... +def RegisterLogicalType(new_type: type): ... +def check_if_native_type(obj): ... +def check_if_logical_type(obj): ... +def check_if_numeric_type(obj): ... +def value(obj, exception: bool = True): ... diff --git a/stubs/pyomo/common/plugin_base.pyi b/stubs/pyomo/common/plugin_base.pyi new file mode 100644 index 000000000..71ba1225f --- /dev/null +++ b/stubs/pyomo/common/plugin_base.pyi @@ -0,0 +1,66 @@ +from _typeshed import Incomplete +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.common.errors import PyomoException as PyomoException + +class PluginGlobals: + @staticmethod + def add_env(name) -> None: ... + @staticmethod + def pop_env() -> None: ... + @staticmethod + def clear() -> None: ... + +class PluginError(PyomoException): ... + +def alias(name, doc=None, subclass=None) -> None: ... +def implements(interface, inherit=None, namespace=None, service: bool = False) -> None: ... + +class InterfaceMeta(type): + def __new__(cls, name, bases, classdict, *args, **kwargs): ... + +class Interface(metaclass=InterfaceMeta): ... + +class _deprecated_plugin_dict(dict): + def __init__(self, name, classdict) -> None: ... + def __setitem__(self, key, val) -> None: ... + def items(self): ... + +class DeprecatedInterfaceMeta(InterfaceMeta): + def __new__(cls, name, bases, classdict, *args, **kwargs): ... + +class DeprecatedInterface(Interface, metaclass=DeprecatedInterfaceMeta): ... + +class PluginMeta(type): + def __new__(cls, name, bases, classdict, *args, **kwargs): ... + +class Plugin(metaclass=PluginMeta): + def __new__(cls): ... + def activate(self) -> None: ... + enable = activate + def deactivate(self) -> None: ... + disable = deactivate + def enabled(self): ... + +class SingletonPlugin(Plugin): + __singleton__: bool + +class ExtensionPoint: + def __init__(self, interface) -> None: ... + def __iter__(self, key=None, all: bool = False): ... + def __len__(self) -> int: ... + def extensions(self, all: bool = False, key=None): ... + def __call__(self, key=None, all: bool = False): ... + def service(self, key=None, all: bool = False): ... + +class PluginFactory: + interface: Incomplete + def __init__(self, interface) -> None: ... + def __call__(self, name, *args, **kwds): ... + def services(self): ... + def get_class(self, name): ... + def doc(self, name): ... + def deactivate(self, name) -> None: ... + def activate(self, name) -> None: ... + +CreatePluginFactory = PluginFactory diff --git a/stubs/pyomo/common/plugins.pyi b/stubs/pyomo/common/plugins.pyi new file mode 100644 index 000000000..08b671c7f --- /dev/null +++ b/stubs/pyomo/common/plugins.pyi @@ -0,0 +1 @@ +def load() -> None: ... diff --git a/stubs/pyomo/common/pyomo_typing.pyi b/stubs/pyomo/common/pyomo_typing.pyi new file mode 100644 index 000000000..ce0957a02 --- /dev/null +++ b/stubs/pyomo/common/pyomo_typing.pyi @@ -0,0 +1,4 @@ +import typing + +def overload(func: typing.Callable): ... +def get_overloads_for(func: typing.Callable): ... diff --git a/stubs/pyomo/common/shutdown.pyi b/stubs/pyomo/common/shutdown.pyi new file mode 100644 index 000000000..285b1a905 --- /dev/null +++ b/stubs/pyomo/common/shutdown.pyi @@ -0,0 +1 @@ +def python_is_shutting_down(): ... diff --git a/stubs/pyomo/common/sorting.pyi b/stubs/pyomo/common/sorting.pyi new file mode 100644 index 000000000..180827d48 --- /dev/null +++ b/stubs/pyomo/common/sorting.pyi @@ -0,0 +1,5 @@ +class _robust_sort_keyfcn: + def __init__(self, key=None) -> None: ... + def __call__(self, val): ... + +def sorted_robust(iterable, key=None, reverse: bool = False): ... diff --git a/stubs/pyomo/common/tee.pyi b/stubs/pyomo/common/tee.pyi new file mode 100644 index 000000000..a9f847fe9 --- /dev/null +++ b/stubs/pyomo/common/tee.pyi @@ -0,0 +1,89 @@ +import types + +from _typeshed import Incomplete +from pyomo.common.log import LoggingIntercept as LoggingIntercept +from pyomo.common.log import LogStream as LogStream + +logger: Incomplete + +class _SignalFlush: + def __init__(self, ostream, handle) -> None: ... + def flush(self) -> None: ... + def __getattr__(self, attr): ... + def __setattr__(self, attr, val): ... + +class _AutoFlush(_SignalFlush): + def write(self, data) -> None: ... + def writelines(self, data) -> None: ... + +class redirect_fd: + fd: Incomplete + std: Incomplete + target: Incomplete + target_file: Incomplete + synchronize: Incomplete + original_file: Incomplete + original_fd: Incomplete + def __init__(self, fd: int = 1, output=None, synchronize: bool = True) -> None: ... + def __enter__(self): ... + def __exit__( + self, + et: type[BaseException] | None, + ev: BaseException | None, + tb: types.TracebackType | None, + ) -> None: ... + +class capture_output: + output: Incomplete + old: Incomplete + tee: Incomplete + capture_fd: Incomplete + context_stack: Incomplete + def __init__(self, output=None, capture_fd: bool = False) -> None: ... + output_stream: Incomplete + def __enter__(self): ... + def __exit__( + self, + et: type[BaseException] | None, + ev: BaseException | None, + tb: types.TracebackType | None, + ) -> None: ... + def __del__(self) -> None: ... + def setup(self): ... + def reset(self): ... + +class _StreamHandle: + buffering: Incomplete + newlines: Incomplete + flush: bool + write_file: Incomplete + decoder_buffer: bytes + encoding: Incomplete + output_buffer: str + def __init__(self, mode, buffering, encoding, newline) -> None: ... + def fileno(self): ... + write_pipe: Incomplete + def close(self) -> None: ... + def finalize(self, ostreams) -> None: ... + def decodeIncomingBuffer(self) -> None: ... + def writeOutputBuffer(self, ostreams, flush) -> None: ... + +class TeeStream: + ostreams: Incomplete + encoding: Incomplete + buffering: Incomplete + def __init__(self, *ostreams, encoding=None, buffering: int = -1) -> None: ... + @property + def STDOUT(self): ... + @property + def STDERR(self): ... + def open(self, mode: str = 'w', buffering: int = -1, encoding=None, newline=None): ... + def close(self, in_exception: bool = False) -> None: ... + def __enter__(self): ... + def __exit__( + self, + et: type[BaseException] | None, + ev: BaseException | None, + tb: types.TracebackType | None, + ) -> None: ... + def __del__(self) -> None: ... diff --git a/stubs/pyomo/common/tempfiles.pyi b/stubs/pyomo/common/tempfiles.pyi new file mode 100644 index 000000000..954b22d17 --- /dev/null +++ b/stubs/pyomo/common/tempfiles.pyi @@ -0,0 +1,65 @@ +import types + +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.dependencies import pyutilib_available as pyutilib_available +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.common.errors import TempfileContextError as TempfileContextError +from pyomo.common.multithread import MultiThreadWrapperWithMain as MultiThreadWrapperWithMain + +deletion_errors_are_fatal: bool +logger: Incomplete +pyutilib_tempfiles: Incomplete +_: Incomplete + +class TempfileManagerClass: + tempdir: Incomplete + def __init__(self) -> None: ... + def __del__(self) -> None: ... + def shutdown(self, remove: bool = True) -> None: ... + def context(self): ... + def create_tempfile(self, suffix=None, prefix=None, text: bool = False, dir=None): ... + def create_tempdir(self, suffix=None, prefix=None, dir=None): ... + def add_tempfile(self, filename, exists: bool = True): ... + def clear_tempfiles(self, remove: bool = True) -> None: ... + def sequential_files(self, ctr: int = 0) -> None: ... + def unique_files(self) -> None: ... + def new_context(self): ... + def push(self): ... + def pop(self, remove: bool = True): ... + def __enter__(self): ... + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: types.TracebackType | None, + ) -> None: ... + +class TempfileContext: + manager: Incomplete + tempfiles: Incomplete + tempdir: Incomplete + os: Incomplete + shutil: Incomplete + def __init__(self, manager) -> None: ... + def __del__(self) -> None: ... + def __enter__(self): ... + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: types.TracebackType | None, + ) -> None: ... + def mkstemp(self, suffix=None, prefix=None, dir=None, text: bool = False): ... + def mkdtemp(self, suffix=None, prefix=None, dir=None): ... + def gettempdir(self): ... + def gettempdirb(self): ... + def gettempprefix(self): ... + def gettempprefixb(self): ... + def create_tempfile(self, suffix=None, prefix=None, text: bool = False, dir=None): ... + def create_tempdir(self, suffix=None, prefix=None, dir=None): ... + def add_tempfile(self, filename, exists: bool = True) -> None: ... + def release(self, remove: bool = True) -> None: ... + +TempfileManager: TempfileManagerClass diff --git a/stubs/pyomo/common/timing.pyi b/stubs/pyomo/common/timing.pyi new file mode 100644 index 000000000..a856d94d5 --- /dev/null +++ b/stubs/pyomo/common/timing.pyi @@ -0,0 +1,97 @@ +import time +import types + +from _typeshed import Incomplete +from pyomo.common.deprecation import deprecation_warning as deprecation_warning + +class report_timing: + def __init__(self, stream: bool = True, level=...) -> None: ... + def reset(self) -> None: ... + def __enter__(self): ... + def __exit__( + self, + et: type[BaseException] | None, + ev: BaseException | None, + tb: types.TracebackType | None, + ) -> None: ... + +class GeneralTimer: + fmt: Incomplete + data: Incomplete + def __init__(self, fmt, data) -> None: ... + def report(self) -> None: ... + @property + def obj(self): ... + @property + def timer(self): ... + +class ConstructionTimer: + msg: str + in_progress: str + obj: Incomplete + timer: Incomplete + def __init__(self, obj) -> None: ... + def report(self) -> None: ... + @property + def name(self): ... + +class TransformationTimer: + msg: str + in_progress: str + obj: Incomplete + mode: str + timer: Incomplete + def __init__(self, obj, mode=None) -> None: ... + def report(self) -> None: ... + @property + def name(self): ... + +default_timer = time.perf_counter + +class TicTocTimer: + ostream: Incomplete + logger: Incomplete + level: Incomplete + def __init__(self, ostream=..., logger=None) -> None: ... + def tic(self, msg=..., *args, ostream=..., logger=..., level=...) -> None: ... + def toc(self, msg=..., *args, delta: bool = True, ostream=..., logger=..., level=...): ... + def stop(self): ... + def start(self) -> None: ... + def __enter__(self): ... + def __exit__( + self, + et: type[BaseException] | None, + ev: BaseException | None, + tb: types.TracebackType | None, + ) -> None: ... + +tic: Incomplete +toc: Incomplete + +class _HierarchicalHelper: + tic_toc: Incomplete + timers: Incomplete + total_time: int + n_calls: int + def __init__(self) -> None: ... + def start(self) -> None: ... + def stop(self) -> None: ... + def to_str(self, indent, stage_identifier_lengths): ... + def get_timers(self, res, prefix) -> None: ... + def flatten(self) -> None: ... + def clear_except(self, *args) -> None: ... + +class HierarchicalTimer: + stack: Incomplete + timers: Incomplete + def __init__(self) -> None: ... + def start(self, identifier) -> None: ... + def stop(self, identifier) -> None: ... + def reset(self) -> None: ... + def get_total_time(self, identifier): ... + def get_num_calls(self, identifier): ... + def get_relative_percent_time(self, identifier): ... + def get_total_percent_time(self, identifier): ... + def get_timers(self): ... + def flatten(self) -> None: ... + def clear_except(self, *args) -> None: ... diff --git a/stubs/pyomo/common/unittest.pyi b/stubs/pyomo/common/unittest.pyi new file mode 100644 index 000000000..9d765cc70 --- /dev/null +++ b/stubs/pyomo/common/unittest.pyi @@ -0,0 +1,86 @@ +import enum +import types +import unittest as _unittest +from io import StringIO as StringIO +from unittest import * +from unittest import mock as mock + +from _typeshed import Incomplete +from pyomo.common.collections import Mapping as Mapping +from pyomo.common.collections import Sequence as Sequence +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.dependencies import check_min_version as check_min_version +from pyomo.common.errors import InvalidValueError as InvalidValueError +from pyomo.common.fileutils import import_file as import_file +from pyomo.common.log import LoggingIntercept as LoggingIntercept +from pyomo.common.log import pyomo_formatter as pyomo_formatter +from pyomo.common.tee import capture_output as capture_output + +pytest: Incomplete +pytest_available: Incomplete + +def assertStructuredAlmostEqual( + first, + second, + places=None, + msg=None, + delta=None, + reltol=None, + abstol=None, + allow_second_superset: bool = False, + item_callback=..., + exception=..., + formatter=..., +) -> None: ... + +class _RunnerResult(enum.Enum): + exception = 0 + call = 1 + unittest = 2 + +def timeout(seconds, require_fork: bool = False, timeout_raises=...): ... + +class _AssertRaisesContext_NormalizeWhitespace(_unittest.case._AssertRaisesContext): + expected_regex: Incomplete + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: types.TracebackType | None, + ): ... + +class TestCase(_unittest.TestCase): + maxDiff: Incomplete + def assertStructuredAlmostEqual( + self, + first, + second, + places=None, + msg=None, + delta=None, + reltol=None, + abstol=None, + allow_second_superset: bool = False, + item_callback=..., + ) -> None: ... + def assertRaisesRegex(self, expected_exception, expected_regex, *args, **kwargs): ... + def assertExpressionsEqual(self, a, b, include_named_exprs: bool = True, places=None): ... + def assertExpressionsStructurallyEqual( + self, a, b, include_named_exprs: bool = True, places=None + ): ... + +class BaselineTestDriver: + @staticmethod + def custom_name_func(test_func, test_num, test_params): ... + def __init__(self, test) -> None: ... + def initialize_dependencies(self) -> None: ... + @classmethod + def gather_tests(cls, test_dirs): ... + def check_skip(self, name): ... + def filter_fcn(self, line): ... + def filter_file_contents(self, lines, abstol=None): ... + def compare_baseline( + self, test_output, baseline, abstol: float = 1e-06, reltol: float = 1e-08 + ): ... + def python_test_driver(self, tname, test_file, base_file) -> None: ... + def shell_test_driver(self, tname, test_file, base_file) -> None: ... diff --git a/stubs/pyomo/contrib/__init__.pyi b/stubs/pyomo/contrib/__init__.pyi new file mode 100644 index 000000000..460fc3dc3 --- /dev/null +++ b/stubs/pyomo/contrib/__init__.pyi @@ -0,0 +1 @@ +from pyomo.common.deprecation import moved_module as moved_module diff --git a/stubs/pyomo/contrib/alternative_solutions/__init__.pyi b/stubs/pyomo/contrib/alternative_solutions/__init__.pyi new file mode 100644 index 000000000..fa3439d27 --- /dev/null +++ b/stubs/pyomo/contrib/alternative_solutions/__init__.pyi @@ -0,0 +1,15 @@ +from pyomo.contrib.alternative_solutions.aos_utils import logcontext as logcontext +from pyomo.contrib.alternative_solutions.balas import ( + enumerate_binary_solutions as enumerate_binary_solutions, +) +from pyomo.contrib.alternative_solutions.lp_enum import ( + enumerate_linear_solutions as enumerate_linear_solutions, +) +from pyomo.contrib.alternative_solutions.obbt import obbt_analysis as obbt_analysis +from pyomo.contrib.alternative_solutions.obbt import ( + obbt_analysis_bounds_and_solutions as obbt_analysis_bounds_and_solutions, +) +from pyomo.contrib.alternative_solutions.solnpool import ( + gurobi_generate_solutions as gurobi_generate_solutions, +) +from pyomo.contrib.alternative_solutions.solution import Solution as Solution diff --git a/stubs/pyomo/contrib/alternative_solutions/aos_utils.pyi b/stubs/pyomo/contrib/alternative_solutions/aos_utils.pyi new file mode 100644 index 000000000..6876212cc --- /dev/null +++ b/stubs/pyomo/contrib/alternative_solutions/aos_utils.pyi @@ -0,0 +1,24 @@ +from collections.abc import Generator +from contextlib import contextmanager + +from _typeshed import Incomplete +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.dependencies import numpy_available as numpy_available +from pyomo.common.modeling import unique_component_name as unique_component_name + +logger: Incomplete + +@contextmanager +def logcontext(level) -> Generator[None]: ... +def get_active_objective(model): ... + +rng: Incomplete + +def get_model_variables( + model, + components=None, + include_continuous: bool = True, + include_binary: bool = True, + include_integer: bool = True, + include_fixed: bool = False, +): ... diff --git a/stubs/pyomo/contrib/alternative_solutions/balas.pyi b/stubs/pyomo/contrib/alternative_solutions/balas.pyi new file mode 100644 index 000000000..c3c722540 --- /dev/null +++ b/stubs/pyomo/contrib/alternative_solutions/balas.pyi @@ -0,0 +1,19 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.contrib.alternative_solutions import Solution as Solution + +logger: Incomplete + +def enumerate_binary_solutions( + model, + *, + num_solutions: int = 10, + variables=None, + rel_opt_gap=None, + abs_opt_gap=None, + search_mode: str = 'optimal', + solver: str = 'gurobi', + solver_options={}, + tee: bool = False, + seed=None, +): ... diff --git a/stubs/pyomo/contrib/alternative_solutions/lp_enum.pyi b/stubs/pyomo/contrib/alternative_solutions/lp_enum.pyi new file mode 100644 index 000000000..7e82e6f6e --- /dev/null +++ b/stubs/pyomo/contrib/alternative_solutions/lp_enum.pyi @@ -0,0 +1,22 @@ +from _typeshed import Incomplete +from pyomo.contrib import appsi as appsi +from pyomo.contrib.alternative_solutions import aos_utils as aos_utils +from pyomo.contrib.alternative_solutions import shifted_lp as shifted_lp +from pyomo.contrib.alternative_solutions import solnpool as solnpool +from pyomo.contrib.alternative_solutions import solution as solution + +logger: Incomplete + +def enumerate_linear_solutions( + model, + *, + num_solutions: int = 10, + rel_opt_gap=None, + abs_opt_gap=None, + zero_threshold: float = 1e-05, + search_mode: str = 'optimal', + solver: str = 'gurobi', + solver_options={}, + tee: bool = False, + seed=None, +): ... diff --git a/stubs/pyomo/contrib/alternative_solutions/lp_enum_solnpool.pyi b/stubs/pyomo/contrib/alternative_solutions/lp_enum_solnpool.pyi new file mode 100644 index 000000000..0ba7bd178 --- /dev/null +++ b/stubs/pyomo/contrib/alternative_solutions/lp_enum_solnpool.pyi @@ -0,0 +1,42 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.contrib import appsi as appsi +from pyomo.contrib.alternative_solutions import aos_utils as aos_utils +from pyomo.contrib.alternative_solutions import shifted_lp as shifted_lp +from pyomo.contrib.alternative_solutions import solution as solution + +logger: Incomplete +gurobipy: Incomplete +gurobi_available: Incomplete + +class NoGoodCutGenerator: + model: Incomplete + zero_threshold: Incomplete + variable_groups: Incomplete + variables: Incomplete + orig_model: Incomplete + all_variables: Incomplete + orig_objective: Incomplete + solutions: Incomplete + num_solutions: Incomplete + def __init__( + self, + model, + variable_groups, + zero_threshold, + orig_model, + all_variables, + orig_objective, + num_solutions, + ) -> None: ... + def cut_generator_callback(self, cb_m, cb_opt, cb_where) -> None: ... + +def enumerate_linear_solutions_soln_pool( + model, + num_solutions: int = 10, + rel_opt_gap=None, + abs_opt_gap=None, + zero_threshold: float = 1e-05, + solver_options={}, + tee: bool = False, +): ... diff --git a/stubs/pyomo/contrib/alternative_solutions/obbt.pyi b/stubs/pyomo/contrib/alternative_solutions/obbt.pyi new file mode 100644 index 000000000..65b26d28b --- /dev/null +++ b/stubs/pyomo/contrib/alternative_solutions/obbt.pyi @@ -0,0 +1,31 @@ +from _typeshed import Incomplete +from pyomo.contrib import appsi as appsi +from pyomo.contrib.alternative_solutions import Solution as Solution +from pyomo.contrib.alternative_solutions import aos_utils as aos_utils + +logger: Incomplete + +def obbt_analysis( + model, + *, + variables=None, + rel_opt_gap=None, + abs_opt_gap=None, + refine_discrete_bounds: bool = False, + warmstart: bool = True, + solver: str = 'gurobi', + solver_options={}, + tee: bool = False, +): ... +def obbt_analysis_bounds_and_solutions( + model, + *, + variables=None, + rel_opt_gap=None, + abs_opt_gap=None, + refine_discrete_bounds: bool = False, + warmstart: bool = True, + solver: str = 'gurobi', + solver_options={}, + tee: bool = False, +): ... diff --git a/stubs/pyomo/contrib/alternative_solutions/shifted_lp.pyi b/stubs/pyomo/contrib/alternative_solutions/shifted_lp.pyi new file mode 100644 index 000000000..ecebe649a --- /dev/null +++ b/stubs/pyomo/contrib/alternative_solutions/shifted_lp.pyi @@ -0,0 +1,8 @@ +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.contrib.alternative_solutions import aos_utils as aos_utils +from pyomo.contrib.fbbt.fbbt import compute_bounds_on_expr as compute_bounds_on_expr +from pyomo.gdp.util import ( + clone_without_expression_components as clone_without_expression_components, +) + +def get_shifted_linear_model(model, block=None): ... diff --git a/stubs/pyomo/contrib/alternative_solutions/solnpool.pyi b/stubs/pyomo/contrib/alternative_solutions/solnpool.pyi new file mode 100644 index 000000000..c9abb3556 --- /dev/null +++ b/stubs/pyomo/contrib/alternative_solutions/solnpool.pyi @@ -0,0 +1,17 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.contrib import appsi as appsi +from pyomo.contrib.alternative_solutions import Solution as Solution + +logger: Incomplete + +def gurobi_generate_solutions( + model, + *, + num_solutions: int = 10, + rel_opt_gap=None, + abs_opt_gap=None, + solver_options={}, + tee: bool = False, +): ... diff --git a/stubs/pyomo/contrib/alternative_solutions/solution.pyi b/stubs/pyomo/contrib/alternative_solutions/solution.pyi new file mode 100644 index 000000000..0fe2241c0 --- /dev/null +++ b/stubs/pyomo/contrib/alternative_solutions/solution.pyi @@ -0,0 +1,22 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.contrib.alternative_solutions import aos_utils as aos_utils + +class Solution: + variables: Incomplete + fixed_vars: Incomplete + objective: Incomplete + def __init__( + self, model, variable_list, include_fixed: bool = True, objective=None + ) -> None: ... + @property + def objective_value(self): ... + def pprint( + self, round_discrete: bool = True, sort_keys: bool = True, indent: int = 4 + ) -> None: ... + def to_string(self, round_discrete: bool = True, sort_keys: bool = True, indent: int = 4): ... + def to_dict(self, round_discrete: bool = True): ... + __repn__: Incomplete + def get_variable_name_values(self, include_fixed: bool = True, round_discrete: bool = True): ... + def get_fixed_variable_names(self): ... diff --git a/stubs/pyomo/contrib/ampl_function_demo/__init__.pyi b/stubs/pyomo/contrib/ampl_function_demo/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/ampl_function_demo/build.pyi b/stubs/pyomo/contrib/ampl_function_demo/build.pyi new file mode 100644 index 000000000..29a3b23d7 --- /dev/null +++ b/stubs/pyomo/contrib/ampl_function_demo/build.pyi @@ -0,0 +1,6 @@ +from pyomo.common.cmake_builder import build_cmake_project as build_cmake_project + +def build_ampl_function_demo(user_args=[], parallel=None): ... + +class AMPLFunctionDemoBuilder: + def __call__(self, parallel): ... diff --git a/stubs/pyomo/contrib/ampl_function_demo/plugins.pyi b/stubs/pyomo/contrib/ampl_function_demo/plugins.pyi new file mode 100644 index 000000000..4e29bceb5 --- /dev/null +++ b/stubs/pyomo/contrib/ampl_function_demo/plugins.pyi @@ -0,0 +1,6 @@ +from pyomo.common.extensions import ExtensionBuilderFactory as ExtensionBuilderFactory +from pyomo.contrib.ampl_function_demo.build import ( + AMPLFunctionDemoBuilder as AMPLFunctionDemoBuilder, +) + +def load() -> None: ... diff --git a/stubs/pyomo/contrib/appsi/__init__.pyi b/stubs/pyomo/contrib/appsi/__init__.pyi new file mode 100644 index 000000000..b4ad4cc20 --- /dev/null +++ b/stubs/pyomo/contrib/appsi/__init__.pyi @@ -0,0 +1,4 @@ +from . import base as base +from . import fbbt as fbbt +from . import solvers as solvers +from . import writers as writers diff --git a/stubs/pyomo/contrib/appsi/base.pyi b/stubs/pyomo/contrib/appsi/base.pyi new file mode 100644 index 000000000..fb74a440a --- /dev/null +++ b/stubs/pyomo/contrib/appsi/base.pyi @@ -0,0 +1,290 @@ +import abc +import enum +import types +from typing import Mapping, MutableMapping, NoReturn, Sequence + +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import NonNegativeFloat as NonNegativeFloat +from pyomo.common.enums import IntEnum as IntEnum +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.common.factory import Factory as Factory +from pyomo.common.timing import HierarchicalTimer as HierarchicalTimer +from pyomo.core.base import SymbolMap as SymbolMap +from pyomo.core.base.block import Block as Block +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.constraint import Constraint as Constraint +from pyomo.core.base.constraint import ConstraintData as ConstraintData +from pyomo.core.base.objective import ObjectiveData as ObjectiveData +from pyomo.core.base.param import Param as Param +from pyomo.core.base.param import ParamData as ParamData +from pyomo.core.base.sos import SOSConstraint as SOSConstraint +from pyomo.core.base.sos import SOSConstraintData as SOSConstraintData +from pyomo.core.base.var import Var as Var +from pyomo.core.base.var import VarData as VarData +from pyomo.core.expr.numvalue import NumericConstant as NumericConstant +from pyomo.core.kernel.objective import minimize as minimize +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager + +from .cmodel import cmodel as cmodel +from .cmodel import cmodel_available as cmodel_available +from .utils.collect_vars_and_named_exprs import ( + collect_vars_and_named_exprs as collect_vars_and_named_exprs, +) +from .utils.get_objective import get_objective as get_objective + +class TerminationCondition(enum.Enum): + unknown = 0 + maxTimeLimit = 1 + maxIterations = 2 + objectiveLimit = 3 + minStepLength = 4 + optimal = 5 + unbounded = 8 + infeasible = 9 + infeasibleOrUnbounded = 10 + error = 11 + interrupted = 12 + licensingProblems = 13 + +class SolverConfig(ConfigDict): + time_limit: float | None + warmstart: bool + stream_solver: bool + load_solution: bool + symbolic_solver_labels: bool + report_timing: bool + def __init__( + self, + description=None, + doc=None, + implicit: bool = False, + implicit_domain=None, + visibility: int = 0, + ) -> None: ... + +class MIPSolverConfig(SolverConfig): + mip_gap: float | None + relax_integrality: bool + def __init__( + self, + description=None, + doc=None, + implicit: bool = False, + implicit_domain=None, + visibility: int = 0, + ) -> None: ... + +class SolutionLoaderBase(abc.ABC, metaclass=abc.ABCMeta): + def load_vars(self, vars_to_load: Sequence[VarData] | None = None) -> NoReturn: ... + @abc.abstractmethod + def get_primals( + self, vars_to_load: Sequence[VarData] | None = None + ) -> Mapping[VarData, float]: ... + def get_duals( + self, cons_to_load: Sequence[ConstraintData] | None = None + ) -> dict[ConstraintData, float]: ... + def get_slacks( + self, cons_to_load: Sequence[ConstraintData] | None = None + ) -> dict[ConstraintData, float]: ... + def get_reduced_costs( + self, vars_to_load: Sequence[VarData] | None = None + ) -> Mapping[VarData, float]: ... + +class SolutionLoader(SolutionLoaderBase): + def __init__( + self, + primals: MutableMapping | None, + duals: MutableMapping | None, + slacks: MutableMapping | None, + reduced_costs: MutableMapping | None, + ) -> None: ... + def get_primals( + self, vars_to_load: Sequence[VarData] | None = None + ) -> Mapping[VarData, float]: ... + def get_duals( + self, cons_to_load: Sequence[ConstraintData] | None = None + ) -> dict[ConstraintData, float]: ... + def get_slacks( + self, cons_to_load: Sequence[ConstraintData] | None = None + ) -> dict[ConstraintData, float]: ... + def get_reduced_costs( + self, vars_to_load: Sequence[VarData] | None = None + ) -> Mapping[VarData, float]: ... + +class Results: + solution_loader: SolutionLoaderBase + termination_condition: TerminationCondition + best_feasible_objective: float | None + best_objective_bound: float | None + def __init__(self) -> None: ... + +class UpdateConfig(ConfigDict): + check_for_new_or_removed_constraints: bool + check_for_new_or_removed_vars: bool + check_for_new_or_removed_params: bool + check_for_new_objective: bool + update_constraints: bool + update_vars: bool + update_params: bool + update_named_expressions: bool + update_objective: bool + treat_fixed_vars_as_params: bool + def __init__( + self, + description=None, + doc=None, + implicit: bool = False, + implicit_domain=None, + visibility: int = 0, + ) -> None: ... + +class Solver(abc.ABC, metaclass=abc.ABCMeta): + class Availability(IntEnum): + NotFound = 0 + BadVersion = -1 + BadLicense = -2 + FullLicense = 1 + LimitedLicense = 2 + NeedsCompiledExtension = -3 + def __bool__(self) -> bool: ... + def __format__(self, format_spec) -> str: ... + + @abc.abstractmethod + def solve(self, model: BlockData, timer: HierarchicalTimer = None) -> Results: ... + @abc.abstractmethod + def available(self): ... + @abc.abstractmethod + def version(self) -> tuple: ... + @property + @abc.abstractmethod + def config(self): ... + @property + @abc.abstractmethod + def symbol_map(self): ... + def is_persistent(self): ... + +class PersistentSolver(Solver, metaclass=abc.ABCMeta): + def is_persistent(self): ... + def load_vars(self, vars_to_load: Sequence[VarData] | None = None) -> NoReturn: ... + @abc.abstractmethod + def get_primals( + self, vars_to_load: Sequence[VarData] | None = None + ) -> Mapping[VarData, float]: ... + def get_duals( + self, cons_to_load: Sequence[ConstraintData] | None = None + ) -> dict[ConstraintData, float]: ... + def get_slacks( + self, cons_to_load: Sequence[ConstraintData] | None = None + ) -> dict[ConstraintData, float]: ... + def get_reduced_costs( + self, vars_to_load: Sequence[VarData] | None = None + ) -> Mapping[VarData, float]: ... + @property + @abc.abstractmethod + def update_config(self) -> UpdateConfig: ... + @abc.abstractmethod + def set_instance(self, model): ... + @abc.abstractmethod + def add_variables(self, variables: list[VarData]): ... + @abc.abstractmethod + def add_params(self, params: list[ParamData]): ... + @abc.abstractmethod + def add_constraints(self, cons: list[ConstraintData]): ... + @abc.abstractmethod + def add_block(self, block: BlockData): ... + @abc.abstractmethod + def remove_variables(self, variables: list[VarData]): ... + @abc.abstractmethod + def remove_params(self, params: list[ParamData]): ... + @abc.abstractmethod + def remove_constraints(self, cons: list[ConstraintData]): ... + @abc.abstractmethod + def remove_block(self, block: BlockData): ... + @abc.abstractmethod + def set_objective(self, obj: ObjectiveData): ... + @abc.abstractmethod + def update_variables(self, variables: list[VarData]): ... + @abc.abstractmethod + def update_params(self): ... + +class PersistentSolutionLoader(SolutionLoaderBase): + def __init__(self, solver: PersistentSolver) -> None: ... + def get_primals(self, vars_to_load=None): ... + def get_duals( + self, cons_to_load: Sequence[ConstraintData] | None = None + ) -> dict[ConstraintData, float]: ... + def get_slacks( + self, cons_to_load: Sequence[ConstraintData] | None = None + ) -> dict[ConstraintData, float]: ... + def get_reduced_costs( + self, vars_to_load: Sequence[VarData] | None = None + ) -> Mapping[VarData, float]: ... + def invalidate(self) -> None: ... + +class PersistentBase(abc.ABC, metaclass=abc.ABCMeta): + use_extensions: bool + def __init__(self, only_child_vars: bool = False) -> None: ... + @property + def update_config(self): ... + @update_config.setter + def update_config(self, val: UpdateConfig): ... + def set_instance(self, model) -> None: ... + def add_variables(self, variables: list[VarData]): ... + def add_params(self, params: list[ParamData]): ... + def add_constraints(self, cons: list[ConstraintData]): ... + def add_sos_constraints(self, cons: list[SOSConstraintData]): ... + def set_objective(self, obj: ObjectiveData): ... + def add_block(self, block) -> None: ... + def remove_constraints(self, cons: list[ConstraintData]): ... + def remove_sos_constraints(self, cons: list[SOSConstraintData]): ... + def remove_variables(self, variables: list[VarData]): ... + def remove_params(self, params: list[ParamData]): ... + def remove_block(self, block) -> None: ... + def update_variables(self, variables: list[VarData]): ... + @abc.abstractmethod + def update_params(self): ... + def update(self, timer: HierarchicalTimer = None): ... + +legacy_termination_condition_map: Incomplete +legacy_solver_status_map: Incomplete +legacy_solution_status_map: Incomplete + +class LegacySolverInterface: + config: Incomplete + def solve( + self, + model: BlockData, + tee: bool = False, + load_solutions: bool = True, + logfile: str | None = None, + solnfile: str | None = None, + timelimit: float | None = None, + report_timing: bool = False, + solver_io: str | None = None, + suffixes: Sequence | None = None, + options: dict | None = None, + keepfiles: bool = False, + symbolic_solver_labels: bool = False, + warmstart: bool = False, + ): ... + def available(self, exception_flag: bool = True): ... + def license_is_valid(self) -> bool: ... + @property + def options(self): ... + @options.setter + def options(self, val) -> None: ... + def __enter__(self): ... + def __exit__( + self, + t: type[BaseException] | None, + v: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: ... + +class SolverFactoryClass(Factory): + def register(self, name, doc=None): ... + +SolverFactory: Incomplete diff --git a/stubs/pyomo/contrib/appsi/build.pyi b/stubs/pyomo/contrib/appsi/build.pyi new file mode 100644 index 000000000..b80861cc2 --- /dev/null +++ b/stubs/pyomo/contrib/appsi/build.pyi @@ -0,0 +1,5 @@ +def get_appsi_extension(in_setup: bool = False, appsi_root=None): ... +def build_appsi(args=[]) -> None: ... + +class AppsiBuilder: + def __call__(self, parallel): ... diff --git a/stubs/pyomo/contrib/appsi/cmodel/__init__.pyi b/stubs/pyomo/contrib/appsi/cmodel/__init__.pyi new file mode 100644 index 000000000..8474f39f5 --- /dev/null +++ b/stubs/pyomo/contrib/appsi/cmodel/__init__.pyi @@ -0,0 +1,4 @@ +from _typeshed import Incomplete + +cmodel: Incomplete +cmodel_available: Incomplete diff --git a/stubs/pyomo/contrib/appsi/cmodel/appsi_cmodel.pyi b/stubs/pyomo/contrib/appsi/cmodel/appsi_cmodel.pyi new file mode 100644 index 000000000..914a6fecc --- /dev/null +++ b/stubs/pyomo/contrib/appsi/cmodel/appsi_cmodel.pyi @@ -0,0 +1,258 @@ +from typing import ClassVar, overload + +import pyomo.common.errors + +division: ExprType +external_func: ExprType +inf: float +linear: ExprType +named_expr: ExprType +negation: ExprType +numeric_constant: ExprType +param: ExprType +power: ExprType +product: ExprType +py_float: ExprType +sum: ExprType +unary_func: ExprType +var: ExprType + +class Constant(ExpressionBase): + value: float + @overload + def __init__(self) -> None: ... + @overload + def __init__(self, arg0: float) -> None: ... + +class Constraint: + active: bool + lb: ExpressionBase + name: str + ub: ExpressionBase + def __init__(self) -> None: ... + +class ExprType: + __members__: ClassVar[dict] = ... # read-only + __entries: ClassVar[dict] = ... + division: ClassVar[ExprType] = ... + external_func: ClassVar[ExprType] = ... + linear: ClassVar[ExprType] = ... + named_expr: ClassVar[ExprType] = ... + negation: ClassVar[ExprType] = ... + numeric_constant: ClassVar[ExprType] = ... + param: ClassVar[ExprType] = ... + power: ClassVar[ExprType] = ... + product: ClassVar[ExprType] = ... + py_float: ClassVar[ExprType] = ... + sum: ClassVar[ExprType] = ... + unary_func: ClassVar[ExprType] = ... + var: ClassVar[ExprType] = ... + def __init__(self, value: int) -> None: ... + def __eq__(self, other: object) -> bool: ... + def __hash__(self) -> int: ... + def __index__(self) -> int: ... + def __int__(self) -> int: ... + def __ne__(self, other: object) -> bool: ... + @property + def name(self) -> str: ... + @property + def value(self) -> int: ... + +class Expression(ExpressionBase): + def __init__(self, arg0: int) -> None: ... + def get_operators(self) -> list[Operator]: ... + +class ExpressionBase(Node): + def __init__(self, *args, **kwargs) -> None: ... + def evaluate(self) -> float: ... + +class FBBTConstraint(Constraint): + body: ExpressionBase + def __init__( + self, arg0: ExpressionBase, arg1: ExpressionBase, arg2: ExpressionBase + ) -> None: ... + def perform_fbbt( + self, arg0: float, arg1: float, arg2: float, arg3: set[Var], arg4: bool + ) -> None: ... + +class FBBTModel(Model): + def __init__(self) -> None: ... + def perform_fbbt(self, arg0: float, arg1: float, arg2: float, arg3: int, arg4: bool) -> int: ... + def perform_fbbt_with_seed( + self, arg0: Var, arg1: float, arg2: float, arg3: float, arg4: int, arg5: bool + ) -> int: ... + +class FBBTObjective(Objective): + expr: ExpressionBase + def __init__(self, arg0: ExpressionBase) -> None: ... + +class InfeasibleConstraintException(pyomo.common.errors.InfeasibleConstraintException): ... +class IntervalException(pyomo.common.errors.IntervalException): ... + +class LPBase: + def __init__(self, *args, **kwargs) -> None: ... + +class LPConstraint(LPBase, Constraint): + def __init__(self) -> None: ... + +class LPObjective(LPBase, Objective): + def __init__(self) -> None: ... + +class LPWriter(Model): + def __init__(self) -> None: ... + def get_solve_cons(self) -> list[LPConstraint]: ... + def write(self, arg0: str) -> None: ... + +class Model: + constraints: set[Constraint] + objective: Objective + def __init__(self) -> None: ... + def add_constraint(self, arg0: Constraint) -> None: ... + def remove_constraint(self, arg0: Constraint) -> None: ... + +class NLBase: + def __init__(self, *args, **kwargs) -> None: ... + +class NLConstraint(NLBase, Constraint): + def __init__( + self, + arg0: ExpressionBase, + arg1: list[ExpressionBase], + arg2: list[Var], + arg3: ExpressionBase, + ) -> None: ... + +class NLObjective(NLBase, Objective): + def __init__( + self, + arg0: ExpressionBase, + arg1: list[ExpressionBase], + arg2: list[Var], + arg3: ExpressionBase, + ) -> None: ... + +class NLWriter(Model): + def __init__(self) -> None: ... + def get_solve_cons(self) -> list[NLConstraint]: ... + def get_solve_vars(self) -> list[Var]: ... + def write(self, arg0: str) -> None: ... + +class Node: + def __init__(self, *args, **kwargs) -> None: ... + def is_constant_type(self) -> bool: ... + def is_expression_type(self) -> bool: ... + def is_leaf(self) -> bool: ... + def is_operator_type(self) -> bool: ... + def is_param_type(self) -> bool: ... + def is_variable_type(self) -> bool: ... + +class Objective: + name: str + sense: int + def __init__(self) -> None: ... + +class Operator(Node): + def __init__(self, *args, **kwargs) -> None: ... + +class Param(ExpressionBase): + name: str + value: float + @overload + def __init__(self) -> None: ... + @overload + def __init__(self, arg0: float) -> None: ... + @overload + def __init__(self, arg0: str, arg1: float) -> None: ... + @overload + def __init__(self, arg0: str) -> None: ... + +class PyomoExprTypes: + def __init__(self) -> None: ... + +class Var(ExpressionBase): + domain: Domain + fixed: bool + lb: ExpressionBase + name: str + ub: ExpressionBase + value: float + @overload + def __init__(self) -> None: ... + @overload + def __init__(self, arg0: float) -> None: ... + @overload + def __init__(self, arg0: str, arg1: float) -> None: ... + @overload + def __init__(self, arg0: str) -> None: ... + def get_domain(self) -> Domain: ... + def get_lb(self) -> float: ... + def get_ub(self) -> float: ... + +def appsi_expr_from_pyomo_expr( + arg0: object, arg1: object, arg2: object, arg3: PyomoExprTypes +) -> ExpressionBase: ... +def appsi_exprs_from_pyomo_exprs(arg0: list, arg1: dict, arg2: dict) -> list[ExpressionBase]: ... +def create_constants(arg0: int) -> list[Constant]: ... +def create_params(arg0: int) -> list[Param]: ... +def create_vars(arg0: int) -> list[Var]: ... +def prep_for_repn(arg0: object, arg1: PyomoExprTypes) -> tuple: ... +def process_fbbt_constraints( + arg0: FBBTModel, + arg1: PyomoExprTypes, + arg2: list, + arg3: dict, + arg4: dict, + arg5: dict, + arg6: dict, + arg7: dict, +) -> None: ... +def process_lp_constraints(arg0: list, arg1: object) -> None: ... +def process_lp_objective( + arg0: PyomoExprTypes, arg1: object, arg2: dict, arg3: dict +) -> LPObjective: ... +def process_nl_constraints( + arg0: NLWriter, + arg1: PyomoExprTypes, + arg2: list, + arg3: dict, + arg4: dict, + arg5: dict, + arg6: dict, + arg7: dict, +) -> None: ... +def process_pyomo_vars( + arg0: PyomoExprTypes, + arg1: list, + arg2: dict, + arg3: dict, + arg4: dict, + arg5: dict, + arg6: bool, + arg7: object, + arg8: object, + arg9: bool, +) -> None: ... +def py_interval_abs(arg0: float, arg1: float) -> tuple[float, float]: ... +def py_interval_acos( + arg0: float, arg1: float, arg2: float, arg3: float, arg4: float +) -> tuple[float, float]: ... +def py_interval_add(arg0: float, arg1: float, arg2: float, arg3: float) -> tuple[float, float]: ... +def py_interval_asin( + arg0: float, arg1: float, arg2: float, arg3: float, arg4: float +) -> tuple[float, float]: ... +def py_interval_atan(arg0: float, arg1: float, arg2: float, arg3: float) -> tuple[float, float]: ... +def py_interval_cos(arg0: float, arg1: float) -> tuple[float, float]: ... +def py_interval_div( + arg0: float, arg1: float, arg2: float, arg3: float, arg4: float +) -> tuple[float, float]: ... +def py_interval_exp(arg0: float, arg1: float) -> tuple[float, float]: ... +def py_interval_inv(arg0: float, arg1: float, arg2: float) -> tuple[float, float]: ... +def py_interval_log(arg0: float, arg1: float) -> tuple[float, float]: ... +def py_interval_log10(arg0: float, arg1: float) -> tuple[float, float]: ... +def py_interval_mul(arg0: float, arg1: float, arg2: float, arg3: float) -> tuple[float, float]: ... +def py_interval_power( + arg0: float, arg1: float, arg2: float, arg3: float, arg4: float +) -> tuple[float, float]: ... +def py_interval_sin(arg0: float, arg1: float) -> tuple[float, float]: ... +def py_interval_sub(arg0: float, arg1: float, arg2: float, arg3: float) -> tuple[float, float]: ... +def py_interval_tan(arg0: float, arg1: float) -> tuple[float, float]: ... diff --git a/stubs/pyomo/contrib/appsi/examples/__init__.pyi b/stubs/pyomo/contrib/appsi/examples/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/appsi/examples/getting_started.pyi b/stubs/pyomo/contrib/appsi/examples/getting_started.pyi new file mode 100644 index 000000000..273861b0d --- /dev/null +++ b/stubs/pyomo/contrib/appsi/examples/getting_started.pyi @@ -0,0 +1,4 @@ +from pyomo.common.timing import HierarchicalTimer as HierarchicalTimer +from pyomo.contrib import appsi as appsi + +def main(plot: bool = True, n_points: int = 200) -> None: ... diff --git a/stubs/pyomo/contrib/appsi/fbbt.pyi b/stubs/pyomo/contrib/appsi/fbbt.pyi new file mode 100644 index 000000000..491c65bb4 --- /dev/null +++ b/stubs/pyomo/contrib/appsi/fbbt.pyi @@ -0,0 +1,48 @@ +from _typeshed import Incomplete +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import NonNegativeFloat as NonNegativeFloat +from pyomo.common.config import NonNegativeInt as NonNegativeInt +from pyomo.common.errors import InfeasibleConstraintException as InfeasibleConstraintException +from pyomo.contrib.appsi.base import PersistentBase as PersistentBase +from pyomo.core.base import SymbolMap as SymbolMap +from pyomo.core.base import TextLabeler as TextLabeler +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.constraint import ConstraintData as ConstraintData +from pyomo.core.base.objective import ObjectiveData as ObjectiveData +from pyomo.core.base.objective import maximize as maximize +from pyomo.core.base.objective import minimize as minimize +from pyomo.core.base.param import ParamData as ParamData +from pyomo.core.base.sos import SOSConstraintData as SOSConstraintData +from pyomo.core.base.var import VarData as VarData + +from .cmodel import cmodel as cmodel +from .cmodel import cmodel_available as cmodel_available + +class IntervalConfig(ConfigDict): + feasibility_tol: float + integer_tol: float + improvement_tol: float + max_iter: int + deactivate_satisfied_constraints: bool + def __init__( + self, + description=None, + doc=None, + implicit: bool = False, + implicit_domain=None, + visibility: int = 0, + ) -> None: ... + +class IntervalTightener(PersistentBase): + def __init__(self) -> None: ... + @property + def config(self): ... + @config.setter + def config(self, val: IntervalConfig): ... + update_config: Incomplete + def set_instance(self, model, symbolic_solver_labels: bool | None = None): ... + def update_params(self) -> None: ... + def set_objective(self, obj: ObjectiveData): ... + def perform_fbbt(self, model: BlockData, symbolic_solver_labels: bool | None = None): ... + def perform_fbbt_with_seed(self, model: BlockData, seed_var: VarData): ... diff --git a/stubs/pyomo/contrib/appsi/plugins.pyi b/stubs/pyomo/contrib/appsi/plugins.pyi new file mode 100644 index 000000000..2e79db83a --- /dev/null +++ b/stubs/pyomo/contrib/appsi/plugins.pyi @@ -0,0 +1,12 @@ +from pyomo.common.extensions import ExtensionBuilderFactory as ExtensionBuilderFactory + +from .base import SolverFactory as SolverFactory +from .build import AppsiBuilder as AppsiBuilder +from .solvers import Cbc as Cbc +from .solvers import Cplex as Cplex +from .solvers import Gurobi as Gurobi +from .solvers import Highs as Highs +from .solvers import Ipopt as Ipopt +from .solvers import MAiNGO as MAiNGO + +def load() -> None: ... diff --git a/stubs/pyomo/contrib/appsi/solvers/__init__.pyi b/stubs/pyomo/contrib/appsi/solvers/__init__.pyi new file mode 100644 index 000000000..325f3d11e --- /dev/null +++ b/stubs/pyomo/contrib/appsi/solvers/__init__.pyi @@ -0,0 +1,9 @@ +from .cbc import Cbc as Cbc +from .cplex import Cplex as Cplex +from .gurobi import Gurobi as Gurobi +from .gurobi import GurobiResults as GurobiResults +from .highs import Highs as Highs +from .ipopt import Ipopt as Ipopt +from .maingo import MAiNGO as MAiNGO +from .wntr import Wntr as Wntr +from .wntr import WntrResults as WntrResults diff --git a/stubs/pyomo/contrib/appsi/solvers/cbc.pyi b/stubs/pyomo/contrib/appsi/solvers/cbc.pyi new file mode 100644 index 000000000..344239bab --- /dev/null +++ b/stubs/pyomo/contrib/appsi/solvers/cbc.pyi @@ -0,0 +1,86 @@ +from typing import Mapping, Sequence + +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import NonNegativeInt as NonNegativeInt +from pyomo.common.errors import PyomoException as PyomoException +from pyomo.common.fileutils import Executable as Executable +from pyomo.common.log import LogStream as LogStream +from pyomo.common.tee import TeeStream as TeeStream +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.common.timing import HierarchicalTimer as HierarchicalTimer +from pyomo.contrib.appsi.base import PersistentSolutionLoader as PersistentSolutionLoader +from pyomo.contrib.appsi.base import PersistentSolver as PersistentSolver +from pyomo.contrib.appsi.base import Results as Results +from pyomo.contrib.appsi.base import SolverConfig as SolverConfig +from pyomo.contrib.appsi.base import TerminationCondition as TerminationCondition +from pyomo.contrib.appsi.cmodel import cmodel_available as cmodel_available +from pyomo.contrib.appsi.writers import LPWriter as LPWriter +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.constraint import ConstraintData as ConstraintData +from pyomo.core.base.objective import ObjectiveData as ObjectiveData +from pyomo.core.base.param import ParamData as ParamData +from pyomo.core.base.var import VarData as VarData +from pyomo.core.kernel.objective import maximize as maximize +from pyomo.core.kernel.objective import minimize as minimize +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager + +logger: Incomplete + +class CbcConfig(SolverConfig): + executable: Incomplete + filename: Incomplete + keepfiles: bool + solver_output_logger: Incomplete + log_level: Incomplete + def __init__( + self, + description=None, + doc=None, + implicit: bool = False, + implicit_domain=None, + visibility: int = 0, + ) -> None: ... + +class Cbc(PersistentSolver): + def __init__(self, only_child_vars: bool = False) -> None: ... + def available(self): ... + def version(self): ... + def lp_filename(self): ... + def log_filename(self): ... + def soln_filename(self): ... + @property + def config(self): ... + @config.setter + def config(self, val) -> None: ... + @property + def cbc_options(self): ... + @cbc_options.setter + def cbc_options(self, val: dict): ... + @property + def update_config(self): ... + @property + def writer(self): ... + @property + def symbol_map(self): ... + def set_instance(self, model) -> None: ... + def add_variables(self, variables: list[VarData]): ... + def add_params(self, params: list[ParamData]): ... + def add_constraints(self, cons: list[ConstraintData]): ... + def add_block(self, block: BlockData): ... + def remove_variables(self, variables: list[VarData]): ... + def remove_params(self, params: list[ParamData]): ... + def remove_constraints(self, cons: list[ConstraintData]): ... + def remove_block(self, block: BlockData): ... + def set_objective(self, obj: ObjectiveData): ... + def update_variables(self, variables: list[VarData]): ... + def update_params(self) -> None: ... + def solve(self, model, timer: HierarchicalTimer = None): ... + def get_primals( + self, vars_to_load: Sequence[VarData] | None = None + ) -> Mapping[VarData, float]: ... + def get_duals(self, cons_to_load=None): ... + def get_reduced_costs( + self, vars_to_load: Sequence[VarData] | None = None + ) -> Mapping[VarData, float]: ... diff --git a/stubs/pyomo/contrib/appsi/solvers/cplex.pyi b/stubs/pyomo/contrib/appsi/solvers/cplex.pyi new file mode 100644 index 000000000..81b8eb9ff --- /dev/null +++ b/stubs/pyomo/contrib/appsi/solvers/cplex.pyi @@ -0,0 +1,87 @@ +from typing import Mapping, Sequence + +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import NonNegativeInt as NonNegativeInt +from pyomo.common.errors import PyomoException as PyomoException +from pyomo.common.log import LogStream as LogStream +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.common.timing import HierarchicalTimer as HierarchicalTimer +from pyomo.contrib.appsi.base import MIPSolverConfig as MIPSolverConfig +from pyomo.contrib.appsi.base import PersistentSolutionLoader as PersistentSolutionLoader +from pyomo.contrib.appsi.base import PersistentSolver as PersistentSolver +from pyomo.contrib.appsi.base import Results as Results +from pyomo.contrib.appsi.base import TerminationCondition as TerminationCondition +from pyomo.contrib.appsi.cmodel import cmodel_available as cmodel_available +from pyomo.contrib.appsi.writers import LPWriter as LPWriter +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.constraint import ConstraintData as ConstraintData +from pyomo.core.base.objective import ObjectiveData as ObjectiveData +from pyomo.core.base.param import ParamData as ParamData +from pyomo.core.base.var import VarData as VarData +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager + +logger: Incomplete + +class CplexConfig(MIPSolverConfig): + filename: Incomplete + keepfiles: bool + solver_output_logger: Incomplete + log_level: Incomplete + def __init__( + self, + description=None, + doc=None, + implicit: bool = False, + implicit_domain=None, + visibility: int = 0, + ) -> None: ... + +class CplexResults(Results): + wallclock_time: Incomplete + solution_loader: Incomplete + def __init__(self, solver) -> None: ... + +class Cplex(PersistentSolver): + def __init__(self, only_child_vars: bool = False) -> None: ... + @property + def writer(self): ... + @property + def symbol_map(self): ... + def available(self): ... + def version(self): ... + def lp_filename(self): ... + def log_filename(self): ... + @property + def config(self): ... + @config.setter + def config(self, val) -> None: ... + @property + def cplex_options(self): ... + @cplex_options.setter + def cplex_options(self, val: dict): ... + @property + def update_config(self): ... + def set_instance(self, model) -> None: ... + def add_variables(self, variables: list[VarData]): ... + def add_params(self, params: list[ParamData]): ... + def add_constraints(self, cons: list[ConstraintData]): ... + def add_block(self, block: BlockData): ... + def remove_variables(self, variables: list[VarData]): ... + def remove_params(self, params: list[ParamData]): ... + def remove_constraints(self, cons: list[ConstraintData]): ... + def remove_block(self, block: BlockData): ... + def set_objective(self, obj: ObjectiveData): ... + def update_variables(self, variables: list[VarData]): ... + def update_params(self) -> None: ... + def solve(self, model, timer: HierarchicalTimer = None): ... + def get_primals( + self, vars_to_load: Sequence[VarData] | None = None + ) -> Mapping[VarData, float]: ... + def get_duals( + self, cons_to_load: Sequence[ConstraintData] | None = None + ) -> dict[ConstraintData, float]: ... + def get_reduced_costs( + self, vars_to_load: Sequence[VarData] | None = None + ) -> Mapping[VarData, float]: ... diff --git a/stubs/pyomo/contrib/appsi/solvers/gurobi.pyi b/stubs/pyomo/contrib/appsi/solvers/gurobi.pyi new file mode 100644 index 000000000..c0a8a9558 --- /dev/null +++ b/stubs/pyomo/contrib/appsi/solvers/gurobi.pyi @@ -0,0 +1,177 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.collections import OrderedSet as OrderedSet +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import NonNegativeInt as NonNegativeInt +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.errors import PyomoException as PyomoException +from pyomo.common.log import LogStream as LogStream +from pyomo.common.shutdown import python_is_shutting_down as python_is_shutting_down +from pyomo.common.tee import TeeStream as TeeStream +from pyomo.common.tee import capture_output as capture_output +from pyomo.common.timing import HierarchicalTimer as HierarchicalTimer +from pyomo.contrib.appsi.base import MIPSolverConfig as MIPSolverConfig +from pyomo.contrib.appsi.base import PersistentBase as PersistentBase +from pyomo.contrib.appsi.base import PersistentSolutionLoader as PersistentSolutionLoader +from pyomo.contrib.appsi.base import PersistentSolver as PersistentSolver +from pyomo.contrib.appsi.base import Results as Results +from pyomo.contrib.appsi.base import TerminationCondition as TerminationCondition +from pyomo.contrib.appsi.cmodel import cmodel as cmodel +from pyomo.contrib.appsi.cmodel import cmodel_available as cmodel_available +from pyomo.core.base import NumericLabeler as NumericLabeler +from pyomo.core.base import SymbolMap as SymbolMap +from pyomo.core.base import TextLabeler as TextLabeler +from pyomo.core.base.constraint import ConstraintData as ConstraintData +from pyomo.core.base.param import ParamData as ParamData +from pyomo.core.base.sos import SOSConstraintData as SOSConstraintData +from pyomo.core.base.var import Var as Var +from pyomo.core.base.var import VarData as VarData +from pyomo.core.expr.numeric_expr import NPV_MaxExpression as NPV_MaxExpression +from pyomo.core.expr.numeric_expr import NPV_MinExpression as NPV_MinExpression +from pyomo.core.expr.numvalue import is_constant as is_constant +from pyomo.core.expr.numvalue import is_fixed as is_fixed +from pyomo.core.expr.numvalue import native_numeric_types as native_numeric_types +from pyomo.core.expr.numvalue import value as value +from pyomo.core.kernel.objective import maximize as maximize +from pyomo.core.kernel.objective import minimize as minimize +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager +from pyomo.repn import generate_standard_repn as generate_standard_repn + +logger: Incomplete +gurobipy: Incomplete +gurobipy_available: Incomplete + +class DegreeError(PyomoException): ... + +class GurobiConfig(MIPSolverConfig): + logfile: str + solver_output_logger: Incomplete + log_level: Incomplete + def __init__( + self, + description=None, + doc=None, + implicit: bool = False, + implicit_domain=None, + visibility: int = 0, + ) -> None: ... + +class GurobiSolutionLoader(PersistentSolutionLoader): + def load_vars(self, vars_to_load=None, solution_number: int = 0) -> None: ... + def get_primals(self, vars_to_load=None, solution_number: int = 0): ... + +class GurobiResults(Results): + wallclock_time: Incomplete + solution_loader: Incomplete + def __init__(self, solver) -> None: ... + +class _MutableLowerBound: + var: Incomplete + expr: Incomplete + def __init__(self, expr) -> None: ... + def update(self) -> None: ... + +class _MutableUpperBound: + var: Incomplete + expr: Incomplete + def __init__(self, expr) -> None: ... + def update(self) -> None: ... + +class _MutableLinearCoefficient: + expr: Incomplete + var: Incomplete + con: Incomplete + gurobi_model: Incomplete + def __init__(self) -> None: ... + def update(self) -> None: ... + +class _MutableRangeConstant: + lhs_expr: Incomplete + rhs_expr: Incomplete + con: Incomplete + slack_name: Incomplete + gurobi_model: Incomplete + def __init__(self) -> None: ... + def update(self) -> None: ... + +class _MutableConstant: + expr: Incomplete + con: Incomplete + def __init__(self) -> None: ... + def update(self) -> None: ... + +class _MutableQuadraticConstraint: + con: Incomplete + gurobi_model: Incomplete + constant: Incomplete + last_constant_value: Incomplete + linear_coefs: Incomplete + last_linear_coef_values: Incomplete + quadratic_coefs: Incomplete + last_quadratic_coef_values: Incomplete + def __init__( + self, gurobi_model, gurobi_con, constant, linear_coefs, quadratic_coefs + ) -> None: ... + def get_updated_expression(self): ... + def get_updated_rhs(self): ... + +class _MutableObjective: + gurobi_model: Incomplete + constant: Incomplete + linear_coefs: Incomplete + quadratic_coefs: Incomplete + last_quadratic_coef_values: Incomplete + def __init__(self, gurobi_model, constant, linear_coefs, quadratic_coefs) -> None: ... + def get_updated_expression(self): ... + +class _MutableQuadraticCoefficient: + expr: Incomplete + var1: Incomplete + var2: Incomplete + def __init__(self) -> None: ... + +class Gurobi(PersistentBase, PersistentSolver): + def __init__(self, only_child_vars: bool = False) -> None: ... + def available(self): ... + def release_license(self) -> None: ... + def __del__(self) -> None: ... + def version(self): ... + @property + def config(self) -> GurobiConfig: ... + @config.setter + def config(self, val: GurobiConfig): ... + @property + def gurobi_options(self): ... + @gurobi_options.setter + def gurobi_options(self, val: dict): ... + @property + def symbol_map(self): ... + def solve(self, model, timer: HierarchicalTimer = None) -> Results: ... + def set_instance(self, model) -> None: ... + def update_params(self) -> None: ... + def load_vars(self, vars_to_load=None, solution_number: int = 0) -> None: ... + def get_primals(self, vars_to_load=None, solution_number: int = 0): ... + def get_reduced_costs(self, vars_to_load=None): ... + def get_duals(self, cons_to_load=None): ... + def get_slacks(self, cons_to_load=None): ... + def update(self, timer: HierarchicalTimer = None): ... + def get_model_attr(self, attr): ... + def write(self, filename) -> None: ... + def set_linear_constraint_attr(self, con, attr, val) -> None: ... + def set_var_attr(self, var, attr, val) -> None: ... + def get_var_attr(self, var, attr): ... + def get_linear_constraint_attr(self, con, attr): ... + def get_sos_attr(self, con, attr): ... + def get_quadratic_constraint_attr(self, con, attr): ... + def set_gurobi_param(self, param, val) -> None: ... + def get_gurobi_param_info(self, param): ... + def set_callback(self, func=None) -> None: ... + def cbCut(self, con) -> None: ... + def cbGet(self, what): ... + def cbGetNodeRel(self, vars) -> None: ... + def cbGetSolution(self, vars) -> None: ... + def cbLazy(self, con) -> None: ... + def cbSetSolution(self, vars, solution) -> None: ... + def cbUseSolution(self): ... + def reset(self) -> None: ... diff --git a/stubs/pyomo/contrib/appsi/solvers/highs.pyi b/stubs/pyomo/contrib/appsi/solvers/highs.pyi new file mode 100644 index 000000000..cb7c07710 --- /dev/null +++ b/stubs/pyomo/contrib/appsi/solvers/highs.pyi @@ -0,0 +1,121 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import NonNegativeInt as NonNegativeInt +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.errors import PyomoException as PyomoException +from pyomo.common.log import LogStream as LogStream +from pyomo.common.tee import TeeStream as TeeStream +from pyomo.common.tee import capture_output as capture_output +from pyomo.common.timing import HierarchicalTimer as HierarchicalTimer +from pyomo.contrib.appsi.base import MIPSolverConfig as MIPSolverConfig +from pyomo.contrib.appsi.base import PersistentBase as PersistentBase +from pyomo.contrib.appsi.base import PersistentSolutionLoader as PersistentSolutionLoader +from pyomo.contrib.appsi.base import PersistentSolver as PersistentSolver +from pyomo.contrib.appsi.base import Results as Results +from pyomo.contrib.appsi.base import TerminationCondition as TerminationCondition +from pyomo.contrib.appsi.cmodel import cmodel as cmodel +from pyomo.contrib.appsi.cmodel import cmodel_available as cmodel_available +from pyomo.core.base import SymbolMap as SymbolMap +from pyomo.core.base.constraint import ConstraintData as ConstraintData +from pyomo.core.base.param import ParamData as ParamData +from pyomo.core.base.sos import SOSConstraintData as SOSConstraintData +from pyomo.core.base.var import VarData as VarData +from pyomo.core.expr.numeric_expr import NPV_MaxExpression as NPV_MaxExpression +from pyomo.core.expr.numeric_expr import NPV_MinExpression as NPV_MinExpression +from pyomo.core.expr.numvalue import is_constant as is_constant +from pyomo.core.expr.numvalue import value as value +from pyomo.core.kernel.objective import maximize as maximize +from pyomo.core.kernel.objective import minimize as minimize +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager +from pyomo.repn import generate_standard_repn as generate_standard_repn + +logger: Incomplete +highspy: Incomplete +highspy_available: Incomplete + +class DegreeError(PyomoException): ... + +class HighsConfig(MIPSolverConfig): + logfile: str + solver_output_logger: Incomplete + log_level: Incomplete + def __init__( + self, + description=None, + doc=None, + implicit: bool = False, + implicit_domain=None, + visibility: int = 0, + ) -> None: ... + +class HighsResults(Results): + wallclock_time: Incomplete + solution_loader: Incomplete + def __init__(self, solver) -> None: ... + +class _MutableVarBounds: + pyomo_var_id: Incomplete + lower_expr: Incomplete + upper_expr: Incomplete + var_map: Incomplete + highs: Incomplete + def __init__(self, lower_expr, upper_expr, pyomo_var_id, var_map, highs) -> None: ... + def update(self) -> None: ... + +class _MutableLinearCoefficient: + expr: Incomplete + highs: Incomplete + pyomo_var_id: Incomplete + pyomo_con: Incomplete + con_map: Incomplete + var_map: Incomplete + def __init__(self, pyomo_con, pyomo_var_id, con_map, var_map, expr, highs) -> None: ... + def update(self) -> None: ... + +class _MutableObjectiveCoefficient: + expr: Incomplete + highs: Incomplete + pyomo_var_id: Incomplete + var_map: Incomplete + def __init__(self, pyomo_var_id, var_map, expr, highs) -> None: ... + def update(self) -> None: ... + +class _MutableObjectiveOffset: + expr: Incomplete + highs: Incomplete + def __init__(self, expr, highs) -> None: ... + def update(self) -> None: ... + +class _MutableConstraintBounds: + lower_expr: Incomplete + upper_expr: Incomplete + con: Incomplete + con_map: Incomplete + highs: Incomplete + def __init__(self, lower_expr, upper_expr, pyomo_con, con_map, highs) -> None: ... + def update(self) -> None: ... + +class Highs(PersistentBase, PersistentSolver): + def __init__(self, only_child_vars: bool = False) -> None: ... + def available(self): ... + def version(self): ... + @property + def config(self) -> HighsConfig: ... + @config.setter + def config(self, val: HighsConfig): ... + @property + def highs_options(self): ... + @highs_options.setter + def highs_options(self, val: dict): ... + @property + def symbol_map(self): ... + def warm_start_capable(self): ... + def solve(self, model, timer: HierarchicalTimer = None) -> Results: ... + def set_instance(self, model) -> None: ... + def update_params(self) -> None: ... + def load_vars(self, vars_to_load=None) -> None: ... + def get_primals(self, vars_to_load=None, solution_number: int = 0): ... + def get_reduced_costs(self, vars_to_load=None): ... + def get_duals(self, cons_to_load=None): ... + def get_slacks(self, cons_to_load=None): ... diff --git a/stubs/pyomo/contrib/appsi/solvers/ipopt.pyi b/stubs/pyomo/contrib/appsi/solvers/ipopt.pyi new file mode 100644 index 000000000..06dc3f480 --- /dev/null +++ b/stubs/pyomo/contrib/appsi/solvers/ipopt.pyi @@ -0,0 +1,90 @@ +from typing import Mapping, Sequence + +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import NonNegativeInt as NonNegativeInt +from pyomo.common.errors import PyomoException as PyomoException +from pyomo.common.fileutils import Executable as Executable +from pyomo.common.log import LogStream as LogStream +from pyomo.common.tee import TeeStream as TeeStream +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.common.timing import HierarchicalTimer as HierarchicalTimer +from pyomo.contrib.appsi.base import PersistentSolutionLoader as PersistentSolutionLoader +from pyomo.contrib.appsi.base import PersistentSolver as PersistentSolver +from pyomo.contrib.appsi.base import Results as Results +from pyomo.contrib.appsi.base import SolverConfig as SolverConfig +from pyomo.contrib.appsi.base import TerminationCondition as TerminationCondition +from pyomo.contrib.appsi.cmodel import cmodel_available as cmodel_available +from pyomo.contrib.appsi.writers import NLWriter as NLWriter +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.constraint import ConstraintData as ConstraintData +from pyomo.core.base.objective import ObjectiveData as ObjectiveData +from pyomo.core.base.param import ParamData as ParamData +from pyomo.core.base.var import VarData as VarData +from pyomo.core.expr.numvalue import value as value +from pyomo.core.expr.visitor import replace_expressions as replace_expressions +from pyomo.core.kernel.objective import minimize as minimize +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager + +logger: Incomplete + +class IpoptConfig(SolverConfig): + executable: Incomplete + filename: Incomplete + keepfiles: bool + solver_output_logger: Incomplete + log_level: Incomplete + def __init__( + self, + description=None, + doc=None, + implicit: bool = False, + implicit_domain=None, + visibility: int = 0, + ) -> None: ... + +ipopt_command_line_options: Incomplete + +class Ipopt(PersistentSolver): + def __init__(self, only_child_vars: bool = False) -> None: ... + def available(self): ... + def version(self): ... + def nl_filename(self): ... + def sol_filename(self): ... + def options_filename(self): ... + @property + def config(self): ... + @config.setter + def config(self, val) -> None: ... + @property + def ipopt_options(self): ... + @ipopt_options.setter + def ipopt_options(self, val: dict): ... + @property + def update_config(self): ... + @property + def writer(self): ... + @property + def symbol_map(self): ... + def set_instance(self, model) -> None: ... + def add_variables(self, variables: list[VarData]): ... + def add_params(self, params: list[ParamData]): ... + def add_constraints(self, cons: list[ConstraintData]): ... + def add_block(self, block: BlockData): ... + def remove_variables(self, variables: list[VarData]): ... + def remove_params(self, params: list[ParamData]): ... + def remove_constraints(self, cons: list[ConstraintData]): ... + def remove_block(self, block: BlockData): ... + def set_objective(self, obj: ObjectiveData): ... + def update_variables(self, variables: list[VarData]): ... + def update_params(self) -> None: ... + def solve(self, model, timer: HierarchicalTimer = None): ... + def get_primals( + self, vars_to_load: Sequence[VarData] | None = None + ) -> Mapping[VarData, float]: ... + def get_duals(self, cons_to_load: Sequence[ConstraintData] | None = None): ... + def get_reduced_costs( + self, vars_to_load: Sequence[VarData] | None = None + ) -> Mapping[VarData, float]: ... + def has_linear_solver(self, linear_solver): ... diff --git a/stubs/pyomo/contrib/appsi/solvers/maingo.pyi b/stubs/pyomo/contrib/appsi/solvers/maingo.pyi new file mode 100644 index 000000000..69a604576 --- /dev/null +++ b/stubs/pyomo/contrib/appsi/solvers/maingo.pyi @@ -0,0 +1,96 @@ +from typing import NamedTuple + +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import NonNegativeFloat as NonNegativeFloat +from pyomo.common.config import NonNegativeInt as NonNegativeInt +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.errors import PyomoException as PyomoException +from pyomo.common.log import LogStream as LogStream +from pyomo.common.tee import TeeStream as TeeStream +from pyomo.common.tee import capture_output as capture_output +from pyomo.common.timing import HierarchicalTimer as HierarchicalTimer +from pyomo.contrib.appsi.base import MIPSolverConfig as MIPSolverConfig +from pyomo.contrib.appsi.base import PersistentBase as PersistentBase +from pyomo.contrib.appsi.base import PersistentSolutionLoader as PersistentSolutionLoader +from pyomo.contrib.appsi.base import PersistentSolver as PersistentSolver +from pyomo.contrib.appsi.base import Results as Results +from pyomo.contrib.appsi.base import TerminationCondition as TerminationCondition +from pyomo.contrib.appsi.cmodel import cmodel as cmodel +from pyomo.contrib.appsi.cmodel import cmodel_available as cmodel_available +from pyomo.core.base import NumericLabeler as NumericLabeler +from pyomo.core.base import SymbolMap as SymbolMap +from pyomo.core.base import TextLabeler as TextLabeler +from pyomo.core.base.expression import ScalarExpression as ScalarExpression +from pyomo.core.base.var import ScalarVar as ScalarVar +from pyomo.core.base.var import Var as Var +from pyomo.core.expr.numvalue import is_constant as is_constant +from pyomo.core.expr.numvalue import is_fixed as is_fixed +from pyomo.core.expr.numvalue import native_numeric_types as native_numeric_types +from pyomo.core.expr.numvalue import native_types as native_types +from pyomo.core.expr.numvalue import nonpyomo_leaf_types as nonpyomo_leaf_types +from pyomo.core.expr.numvalue import value as value +from pyomo.core.kernel.objective import maximize as maximize +from pyomo.core.kernel.objective import minimize as minimize +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager +from pyomo.repn.util import valid_expr_ctypes_minlp as valid_expr_ctypes_minlp + +logger: Incomplete + +class MaingoVar(NamedTuple): + type: Incomplete + name: Incomplete + lb: Incomplete + ub: Incomplete + init: Incomplete + +maingopy: Incomplete +maingopy_available: Incomplete +maingo_solvermodel: Incomplete + +class MAiNGOConfig(MIPSolverConfig): + tolerances: ConfigDict + def __init__( + self, + description=None, + doc=None, + implicit: bool = False, + implicit_domain=None, + visibility: int = 0, + ) -> None: ... + +class MAiNGOSolutionLoader(PersistentSolutionLoader): + def load_vars(self, vars_to_load=None) -> None: ... + def get_primals(self, vars_to_load=None): ... + +class MAiNGOResults(Results): + wallclock_time: Incomplete + cpu_time: Incomplete + globally_optimal: Incomplete + solution_loader: Incomplete + def __init__(self, solver) -> None: ... + +class MAiNGO(PersistentBase, PersistentSolver): + def __init__(self, only_child_vars: bool = False) -> None: ... + def available(self): ... + def version(self): ... + @property + def config(self) -> MAiNGOConfig: ... + @config.setter + def config(self, val: MAiNGOConfig): ... + @property + def maingo_options(self): ... + @maingo_options.setter + def maingo_options(self, val: dict): ... + @property + def symbol_map(self): ... + def solve(self, model, timer: HierarchicalTimer = None): ... + def set_instance(self, model) -> None: ... + def update_params(self) -> None: ... + def load_vars(self, vars_to_load=None) -> None: ... + def get_primals(self, vars_to_load=None): ... + def get_reduced_costs(self, vars_to_load=None) -> None: ... + def get_duals(self, cons_to_load=None) -> None: ... + def update(self, timer: HierarchicalTimer = None): ... diff --git a/stubs/pyomo/contrib/appsi/solvers/maingo_solvermodel.pyi b/stubs/pyomo/contrib/appsi/solvers/maingo_solvermodel.pyi new file mode 100644 index 000000000..c313906fe --- /dev/null +++ b/stubs/pyomo/contrib/appsi/solvers/maingo_solvermodel.pyi @@ -0,0 +1,42 @@ +import pyomo.core.expr as EXPR +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.core.base.expression import ScalarExpression as ScalarExpression +from pyomo.core.base.var import ScalarVar as ScalarVar +from pyomo.core.expr.numvalue import is_constant as is_constant +from pyomo.core.expr.numvalue import is_fixed as is_fixed +from pyomo.core.expr.numvalue import native_numeric_types as native_numeric_types +from pyomo.core.expr.numvalue import native_types as native_types +from pyomo.core.expr.numvalue import nonpyomo_leaf_types as nonpyomo_leaf_types +from pyomo.core.expr.numvalue import value as value +from pyomo.core.kernel.objective import maximize as maximize +from pyomo.core.kernel.objective import minimize as minimize +from pyomo.repn.util import valid_expr_ctypes_minlp as valid_expr_ctypes_minlp + +maingopy: Incomplete +maingopy_available: Incomplete +LEFT_TO_RIGHT: Incomplete +RIGHT_TO_LEFT: Incomplete + +class ToMAiNGOVisitor(EXPR.ExpressionValueVisitor): + variables: Incomplete + idmap: Incomplete + def __init__(self, variables, idmap) -> None: ... + @classmethod + def maingo_log10(cls, x): ... + @classmethod + def maingo_asinh(cls, x): ... + @classmethod + def maingo_acosh(cls, x): ... + @classmethod + def maingo_atanh(cls, x): ... + def visit(self, node, values): ... + def visiting_potential_leaf(self, node): ... + +class SolverModel: + def __init__(self, var_list, objective, con_list, idmap, logger) -> None: ... + def build_maingo_objective(self, obj, visitor): ... + def build_maingo_constraints(self, cons, visitor): ... + def get_variables(self): ... + def get_initial_point(self): ... + def evaluate(self, maingo_vars): ... diff --git a/stubs/pyomo/contrib/appsi/solvers/wntr.pyi b/stubs/pyomo/contrib/appsi/solvers/wntr.pyi new file mode 100644 index 000000000..1345139b1 --- /dev/null +++ b/stubs/pyomo/contrib/appsi/solvers/wntr.pyi @@ -0,0 +1,85 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.errors import PyomoException as PyomoException +from pyomo.common.timing import HierarchicalTimer as HierarchicalTimer +from pyomo.contrib.appsi.base import PersistentBase as PersistentBase +from pyomo.contrib.appsi.base import PersistentSolutionLoader as PersistentSolutionLoader +from pyomo.contrib.appsi.base import PersistentSolver as PersistentSolver +from pyomo.contrib.appsi.base import Results as Results +from pyomo.contrib.appsi.base import SolverConfig as SolverConfig +from pyomo.contrib.appsi.base import TerminationCondition as TerminationCondition +from pyomo.contrib.appsi.cmodel import cmodel as cmodel +from pyomo.contrib.appsi.cmodel import cmodel_available as cmodel_available +from pyomo.core.base import NumericLabeler as NumericLabeler +from pyomo.core.base import SymbolMap as SymbolMap +from pyomo.core.base import TextLabeler as TextLabeler +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.constraint import ConstraintData as ConstraintData +from pyomo.core.base.param import ParamData as ParamData +from pyomo.core.base.var import VarData as VarData +from pyomo.core.expr.numeric_expr import AbsExpression as AbsExpression +from pyomo.core.expr.numeric_expr import DivisionExpression as DivisionExpression +from pyomo.core.expr.numeric_expr import LinearExpression as LinearExpression +from pyomo.core.expr.numeric_expr import MonomialTermExpression as MonomialTermExpression +from pyomo.core.expr.numeric_expr import NegationExpression as NegationExpression +from pyomo.core.expr.numeric_expr import NPV_AbsExpression as NPV_AbsExpression +from pyomo.core.expr.numeric_expr import NPV_DivisionExpression as NPV_DivisionExpression +from pyomo.core.expr.numeric_expr import NPV_NegationExpression as NPV_NegationExpression +from pyomo.core.expr.numeric_expr import NPV_PowExpression as NPV_PowExpression +from pyomo.core.expr.numeric_expr import NPV_ProductExpression as NPV_ProductExpression +from pyomo.core.expr.numeric_expr import NPV_SumExpression as NPV_SumExpression +from pyomo.core.expr.numeric_expr import NPV_UnaryFunctionExpression as NPV_UnaryFunctionExpression +from pyomo.core.expr.numeric_expr import PowExpression as PowExpression +from pyomo.core.expr.numeric_expr import ProductExpression as ProductExpression +from pyomo.core.expr.numeric_expr import SumExpression as SumExpression +from pyomo.core.expr.numeric_expr import UnaryFunctionExpression as UnaryFunctionExpression +from pyomo.core.expr.numvalue import native_numeric_types as native_numeric_types +from pyomo.core.expr.visitor import ExpressionValueVisitor as ExpressionValueVisitor +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager + +wntr: Incomplete +wntr_available: Incomplete +logger: Incomplete + +class WntrConfig(SolverConfig): + def __init__( + self, + description=None, + doc=None, + implicit: bool = False, + implicit_domain=None, + visibility: int = 0, + ) -> None: ... + +class WntrResults(Results): + wallclock_time: Incomplete + solution_loader: Incomplete + def __init__(self, solver) -> None: ... + +class Wntr(PersistentBase, PersistentSolver): + def __init__(self, only_child_vars: bool = True) -> None: ... + def available(self): ... + def version(self): ... + @property + def config(self) -> WntrConfig: ... + @config.setter + def config(self, val: WntrConfig): ... + @property + def wntr_options(self): ... + @wntr_options.setter + def wntr_options(self, val: dict): ... + @property + def symbol_map(self): ... + def solve(self, model: BlockData, timer: HierarchicalTimer = None) -> Results: ... + def set_instance(self, model) -> None: ... + def update_params(self) -> None: ... + def load_vars(self, vars_to_load=None) -> None: ... + def get_primals(self, vars_to_load=None): ... + +class PyomoToWntrVisitor(ExpressionValueVisitor): + var_map: Incomplete + param_map: Incomplete + def __init__(self, var_map, param_map) -> None: ... + def visit(self, node, values): ... + def visiting_potential_leaf(self, node): ... diff --git a/stubs/pyomo/contrib/appsi/utils/__init__.pyi b/stubs/pyomo/contrib/appsi/utils/__init__.pyi new file mode 100644 index 000000000..6e4add2f5 --- /dev/null +++ b/stubs/pyomo/contrib/appsi/utils/__init__.pyi @@ -0,0 +1,4 @@ +from .collect_vars_and_named_exprs import ( + collect_vars_and_named_exprs as collect_vars_and_named_exprs, +) +from .get_objective import get_objective as get_objective diff --git a/stubs/pyomo/contrib/appsi/utils/collect_vars_and_named_exprs.pyi b/stubs/pyomo/contrib/appsi/utils/collect_vars_and_named_exprs.pyi new file mode 100644 index 000000000..e425994df --- /dev/null +++ b/stubs/pyomo/contrib/appsi/utils/collect_vars_and_named_exprs.pyi @@ -0,0 +1,13 @@ +from _typeshed import Incomplete +from pyomo.core.expr.visitor import ExpressionValueVisitor as ExpressionValueVisitor +from pyomo.core.expr.visitor import nonpyomo_leaf_types as nonpyomo_leaf_types + +class _VarAndNamedExprCollector(ExpressionValueVisitor): + named_expressions: Incomplete + variables: Incomplete + fixed_vars: Incomplete + def __init__(self) -> None: ... + def visit(self, node, values) -> None: ... + def visiting_potential_leaf(self, node): ... + +def collect_vars_and_named_exprs(expr): ... diff --git a/stubs/pyomo/contrib/appsi/utils/get_objective.pyi b/stubs/pyomo/contrib/appsi/utils/get_objective.pyi new file mode 100644 index 000000000..9ab99f407 --- /dev/null +++ b/stubs/pyomo/contrib/appsi/utils/get_objective.pyi @@ -0,0 +1,3 @@ +from pyomo.core.base.objective import Objective as Objective + +def get_objective(block): ... diff --git a/stubs/pyomo/contrib/appsi/writers/__init__.pyi b/stubs/pyomo/contrib/appsi/writers/__init__.pyi new file mode 100644 index 000000000..d3dd86111 --- /dev/null +++ b/stubs/pyomo/contrib/appsi/writers/__init__.pyi @@ -0,0 +1,2 @@ +from .lp_writer import LPWriter as LPWriter +from .nl_writer import NLWriter as NLWriter diff --git a/stubs/pyomo/contrib/appsi/writers/config.pyi b/stubs/pyomo/contrib/appsi/writers/config.pyi new file mode 100644 index 000000000..6e7af44a9 --- /dev/null +++ b/stubs/pyomo/contrib/appsi/writers/config.pyi @@ -0,0 +1,3 @@ +class WriterConfig: + symbolic_solver_labels: bool + def __init__(self) -> None: ... diff --git a/stubs/pyomo/contrib/appsi/writers/lp_writer.pyi b/stubs/pyomo/contrib/appsi/writers/lp_writer.pyi new file mode 100644 index 000000000..4156bd61b --- /dev/null +++ b/stubs/pyomo/contrib/appsi/writers/lp_writer.pyi @@ -0,0 +1,36 @@ +from _typeshed import Incomplete +from pyomo.common.timing import HierarchicalTimer as HierarchicalTimer +from pyomo.contrib.appsi.base import PersistentBase as PersistentBase +from pyomo.core.base import NumericLabeler as NumericLabeler +from pyomo.core.base import SymbolMap as SymbolMap +from pyomo.core.base import TextLabeler as TextLabeler +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.constraint import ConstraintData as ConstraintData +from pyomo.core.base.objective import ObjectiveData as ObjectiveData +from pyomo.core.base.param import ParamData as ParamData +from pyomo.core.base.sos import SOSConstraintData as SOSConstraintData +from pyomo.core.base.var import VarData as VarData +from pyomo.core.expr.numvalue import value as value +from pyomo.core.kernel.objective import maximize as maximize +from pyomo.core.kernel.objective import minimize as minimize +from pyomo.repn.standard_repn import generate_standard_repn as generate_standard_repn + +from ..cmodel import cmodel as cmodel +from ..cmodel import cmodel_available as cmodel_available +from .config import WriterConfig as WriterConfig + +class LPWriter(PersistentBase): + def __init__(self, only_child_vars: bool = False) -> None: ... + @property + def config(self): ... + @config.setter + def config(self, val: WriterConfig): ... + update_config: Incomplete + def set_instance(self, model) -> None: ... + def update_params(self) -> None: ... + def write(self, model: BlockData, filename: str, timer: HierarchicalTimer = None): ... + def get_vars(self): ... + def get_ordered_cons(self): ... + def get_active_objective(self): ... + @property + def symbol_map(self): ... diff --git a/stubs/pyomo/contrib/appsi/writers/nl_writer.pyi b/stubs/pyomo/contrib/appsi/writers/nl_writer.pyi new file mode 100644 index 000000000..ef26c73aa --- /dev/null +++ b/stubs/pyomo/contrib/appsi/writers/nl_writer.pyi @@ -0,0 +1,38 @@ +from _typeshed import Incomplete +from pyomo.common.collections import OrderedSet as OrderedSet +from pyomo.common.timing import HierarchicalTimer as HierarchicalTimer +from pyomo.contrib.appsi.base import PersistentBase as PersistentBase +from pyomo.core.base import NumericLabeler as NumericLabeler +from pyomo.core.base import SymbolMap as SymbolMap +from pyomo.core.base import TextLabeler as TextLabeler +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.constraint import ConstraintData as ConstraintData +from pyomo.core.base.objective import ObjectiveData as ObjectiveData +from pyomo.core.base.param import ParamData as ParamData +from pyomo.core.base.sos import SOSConstraintData as SOSConstraintData +from pyomo.core.base.var import VarData as VarData +from pyomo.core.expr.numvalue import value as value +from pyomo.core.kernel.objective import minimize as minimize +from pyomo.repn.plugins.ampl.ampl_ import set_pyomo_amplfunc_env as set_pyomo_amplfunc_env +from pyomo.repn.standard_repn import generate_standard_repn as generate_standard_repn + +from ..cmodel import cmodel as cmodel +from ..cmodel import cmodel_available as cmodel_available +from .config import WriterConfig as WriterConfig + +class NLWriter(PersistentBase): + def __init__(self, only_child_vars: bool = False) -> None: ... + @property + def config(self): ... + @config.setter + def config(self, val: WriterConfig): ... + @property + def symbol_map(self): ... + update_config: Incomplete + def set_instance(self, model) -> None: ... + def update_params(self) -> None: ... + def write(self, model: BlockData, filename: str, timer: HierarchicalTimer = None): ... + def update(self, timer: HierarchicalTimer = None): ... + def get_ordered_vars(self): ... + def get_ordered_cons(self): ... + def get_active_objective(self): ... diff --git a/stubs/pyomo/contrib/benders/__init__.pyi b/stubs/pyomo/contrib/benders/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/benders/benders_cuts.pyi b/stubs/pyomo/contrib/benders/benders_cuts.pyi new file mode 100644 index 000000000..bb676132d --- /dev/null +++ b/stubs/pyomo/contrib/benders/benders_cuts.pyi @@ -0,0 +1,40 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.dependencies import mpi4py as mpi4py +from pyomo.common.dependencies import mpi4py_available as mpi4py_available +from pyomo.common.dependencies import numpy_available as numpy_available +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.block import declare_custom_block as declare_custom_block +from pyomo.core.expr.visitor import identify_variables as identify_variables +from pyomo.solvers.plugins.solvers.persistent_solver import PersistentSolver as PersistentSolver + +MPI: Incomplete +logger: Incomplete +__doc__: str +solver_dual_sign_convention: Incomplete + +class BendersCutGeneratorData(BlockData): + num_subproblems_by_rank: int + subproblems: Incomplete + complicating_vars_maps: Incomplete + root_vars: Incomplete + root_vars_indices: Incomplete + root_etas: Incomplete + cuts: Incomplete + subproblem_solvers: Incomplete + tol: Incomplete + all_root_etas: Incomplete + def __init__(self, component) -> None: ... + def global_num_subproblems(self): ... + def local_num_subproblems(self): ... + comm: Incomplete + def set_input(self, root_vars, tol: float = 1e-06, comm=None) -> None: ... + def add_subproblem( + self, + subproblem_fn, + subproblem_fn_kwargs, + root_eta, + subproblem_solver: str = 'gurobi_persistent', + relax_subproblem_cons: bool = False, + ) -> None: ... + def generate_cut(self): ... diff --git a/stubs/pyomo/contrib/benders/examples/__init__.pyi b/stubs/pyomo/contrib/benders/examples/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/benders/examples/farmer.pyi b/stubs/pyomo/contrib/benders/examples/farmer.pyi new file mode 100644 index 000000000..d70db5499 --- /dev/null +++ b/stubs/pyomo/contrib/benders/examples/farmer.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies import mpi4py as mpi4py +from pyomo.contrib.benders.benders_cuts import BendersCutGenerator as BendersCutGenerator + +class Farmer: + crops: Incomplete + total_acreage: int + PriceQuota: Incomplete + SubQuotaSellingPrice: Incomplete + SuperQuotaSellingPrice: Incomplete + CattleFeedRequirement: Incomplete + PurchasePrice: Incomplete + PlantingCostPerAcre: Incomplete + scenarios: Incomplete + crop_yield: Incomplete + scenario_probabilities: Incomplete + def __init__(self) -> None: ... + +def create_root(farmer): ... +def create_subproblem(root, farmer, scenario): ... +def main() -> None: ... diff --git a/stubs/pyomo/contrib/benders/examples/grothey_ex.pyi b/stubs/pyomo/contrib/benders/examples/grothey_ex.pyi new file mode 100644 index 000000000..7dfc88ef3 --- /dev/null +++ b/stubs/pyomo/contrib/benders/examples/grothey_ex.pyi @@ -0,0 +1,5 @@ +from pyomo.contrib.benders.benders_cuts import BendersCutGenerator as BendersCutGenerator + +def create_root(): ... +def create_subproblem(root): ... +def main() -> None: ... diff --git a/stubs/pyomo/contrib/community_detection/__init__.pyi b/stubs/pyomo/contrib/community_detection/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/community_detection/community_graph.pyi b/stubs/pyomo/contrib/community_detection/community_graph.pyi new file mode 100644 index 000000000..026a1a832 --- /dev/null +++ b/stubs/pyomo/contrib/community_detection/community_graph.pyi @@ -0,0 +1,14 @@ +from pyomo.core import ComponentMap as ComponentMap +from pyomo.core import Constraint as Constraint +from pyomo.core import Objective as Objective +from pyomo.core import SortComponents as SortComponents +from pyomo.core import Var as Var +from pyomo.core.expr import identify_variables as identify_variables + +def generate_model_graph( + model, + type_of_graph, + with_objective: bool = True, + weighted_graph: bool = True, + use_only_active_components: bool = True, +): ... diff --git a/stubs/pyomo/contrib/community_detection/detection.pyi b/stubs/pyomo/contrib/community_detection/detection.pyi new file mode 100644 index 000000000..0de67aee7 --- /dev/null +++ b/stubs/pyomo/contrib/community_detection/detection.pyi @@ -0,0 +1,64 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.contrib.community_detection.community_graph import ( + generate_model_graph as generate_model_graph, +) +from pyomo.core import Block as Block +from pyomo.core import ComponentMap as ComponentMap +from pyomo.core import ConcreteModel as ConcreteModel +from pyomo.core import Constraint as Constraint +from pyomo.core import ConstraintList as ConstraintList +from pyomo.core import Objective as Objective +from pyomo.core import Var as Var +from pyomo.core.base.objective import ObjectiveData as ObjectiveData +from pyomo.core.expr.visitor import identify_variables as identify_variables +from pyomo.core.expr.visitor import replace_expressions as replace_expressions + +logger: Incomplete +community_louvain: Incomplete +community_louvain_available: Incomplete + +def detect_communities( + model, + type_of_community_map: str = 'constraint', + with_objective: bool = True, + weighted_graph: bool = True, + random_seed=None, + use_only_active_components: bool = True, +): ... + +class CommunityMap: + community_map: Incomplete + type_of_community_map: Incomplete + with_objective: Incomplete + weighted_graph: Incomplete + random_seed: Incomplete + use_only_active_components: Incomplete + model: Incomplete + graph: Incomplete + graph_node_mapping: Incomplete + constraint_variable_map: Incomplete + graph_partition: Incomplete + def __init__( + self, + community_map, + type_of_community_map, + with_objective, + weighted_graph, + random_seed, + use_only_active_components, + model, + graph, + graph_node_mapping, + constraint_variable_map, + graph_partition, + ) -> None: ... + def __eq__(self, other): ... + def __iter__(self): ... + def __getitem__(self, item): ... + def __len__(self) -> int: ... + def keys(self): ... + def values(self): ... + def items(self): ... + def visualize_model_graph(self, type_of_graph: str = 'constraint', filename=None, pos=None): ... + def generate_structured_model(self): ... diff --git a/stubs/pyomo/contrib/community_detection/event_log.pyi b/stubs/pyomo/contrib/community_detection/event_log.pyi new file mode 100644 index 000000000..299cc45ab --- /dev/null +++ b/stubs/pyomo/contrib/community_detection/event_log.pyi @@ -0,0 +1,6 @@ +from _typeshed import Incomplete +from pyomo.core import Constraint as Constraint +from pyomo.core import Objective as Objective +from pyomo.core import Var as Var + +logger: Incomplete diff --git a/stubs/pyomo/contrib/community_detection/plugins.pyi b/stubs/pyomo/contrib/community_detection/plugins.pyi new file mode 100644 index 000000000..08b671c7f --- /dev/null +++ b/stubs/pyomo/contrib/community_detection/plugins.pyi @@ -0,0 +1 @@ +def load() -> None: ... diff --git a/stubs/pyomo/contrib/cp/__init__.pyi b/stubs/pyomo/contrib/cp/__init__.pyi new file mode 100644 index 000000000..e98e2b538 --- /dev/null +++ b/stubs/pyomo/contrib/cp/__init__.pyi @@ -0,0 +1,25 @@ +from pyomo.contrib.cp.interval_var import IntervalVar as IntervalVar +from pyomo.contrib.cp.interval_var import IntervalVarEndTime as IntervalVarEndTime +from pyomo.contrib.cp.interval_var import IntervalVarLength as IntervalVarLength +from pyomo.contrib.cp.interval_var import IntervalVarPresence as IntervalVarPresence +from pyomo.contrib.cp.interval_var import IntervalVarStartTime as IntervalVarStartTime +from pyomo.contrib.cp.repn.docplex_writer import CPOptimizerSolver as CPOptimizerSolver +from pyomo.contrib.cp.repn.docplex_writer import DocplexWriter as DocplexWriter +from pyomo.contrib.cp.scheduling_expr.scheduling_logic import alternative as alternative +from pyomo.contrib.cp.scheduling_expr.scheduling_logic import spans as spans +from pyomo.contrib.cp.scheduling_expr.scheduling_logic import synchronize as synchronize +from pyomo.contrib.cp.scheduling_expr.sequence_expressions import ( + before_in_sequence as before_in_sequence, +) +from pyomo.contrib.cp.scheduling_expr.sequence_expressions import ( + first_in_sequence as first_in_sequence, +) +from pyomo.contrib.cp.scheduling_expr.sequence_expressions import ( + last_in_sequence as last_in_sequence, +) +from pyomo.contrib.cp.scheduling_expr.sequence_expressions import no_overlap as no_overlap +from pyomo.contrib.cp.scheduling_expr.sequence_expressions import predecessor_to as predecessor_to +from pyomo.contrib.cp.scheduling_expr.step_function_expressions import AlwaysIn as AlwaysIn +from pyomo.contrib.cp.scheduling_expr.step_function_expressions import Pulse as Pulse +from pyomo.contrib.cp.scheduling_expr.step_function_expressions import Step as Step +from pyomo.contrib.cp.sequence_var import SequenceVar as SequenceVar diff --git a/stubs/pyomo/contrib/cp/interval_var.pyi b/stubs/pyomo/contrib/cp/interval_var.pyi new file mode 100644 index 000000000..cc9abbf7d --- /dev/null +++ b/stubs/pyomo/contrib/cp/interval_var.pyi @@ -0,0 +1,63 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.pyomo_typing import overload as overload +from pyomo.contrib.cp.scheduling_expr.precedence_expressions import AtExpression as AtExpression +from pyomo.contrib.cp.scheduling_expr.precedence_expressions import ( + BeforeExpression as BeforeExpression, +) +from pyomo.contrib.cp.scheduling_expr.scheduling_logic import SpanExpression as SpanExpression +from pyomo.core import Integers as Integers +from pyomo.core import value as value +from pyomo.core.base import Any as Any +from pyomo.core.base import ScalarBooleanVar as ScalarBooleanVar +from pyomo.core.base import ScalarVar as ScalarVar +from pyomo.core.base.block import Block as Block +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.global_set import UnindexedComponent_index as UnindexedComponent_index +from pyomo.core.base.indexed_component import IndexedComponent as IndexedComponent +from pyomo.core.base.indexed_component import UnindexedComponent_set as UnindexedComponent_set +from pyomo.core.base.initializer import BoundInitializer as BoundInitializer +from pyomo.core.base.initializer import Initializer as Initializer +from pyomo.core.expr import GetItemExpression as GetItemExpression + +class IntervalVarTimePoint(ScalarVar): + def get_associated_interval_var(self): ... + def before(self, time, delay: int = 0): ... + def after(self, time, delay: int = 0): ... + def at(self, time, delay: int = 0): ... + +class IntervalVarStartTime(IntervalVarTimePoint): + def __init__(self, *args, **kwd) -> None: ... + +class IntervalVarEndTime(IntervalVarTimePoint): + def __init__(self, *args, **kwd) -> None: ... + +class IntervalVarLength(ScalarVar): + def __init__(self, *args, **kwd) -> None: ... + def get_associated_interval_var(self): ... + +class IntervalVarPresence(ScalarBooleanVar): + def __init__(self, *args, **kwd) -> None: ... + def get_associated_interval_var(self): ... + +class IntervalVarData(BlockData): + is_present: Incomplete + start_time: Incomplete + end_time: Incomplete + length: Incomplete + def __init__(self, component=None) -> None: ... + @property + def optional(self): ... + @optional.setter + def optional(self, val) -> None: ... + def spans(self, *args): ... + +class IntervalVar(Block): + def __new__(cls, *args, **kwds): ... + +class ScalarIntervalVar(IntervalVarData, IntervalVar): + def __init__(self, *args, **kwds) -> None: ... + +class IndexedIntervalVar(IntervalVar): + def __getitem__(self, args): ... diff --git a/stubs/pyomo/contrib/cp/plugins.pyi b/stubs/pyomo/contrib/cp/plugins.pyi new file mode 100644 index 000000000..08b671c7f --- /dev/null +++ b/stubs/pyomo/contrib/cp/plugins.pyi @@ -0,0 +1 @@ +def load() -> None: ... diff --git a/stubs/pyomo/contrib/cp/repn/__init__.pyi b/stubs/pyomo/contrib/cp/repn/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/cp/repn/docplex_writer.pyi b/stubs/pyomo/contrib/cp/repn/docplex_writer.pyi new file mode 100644 index 000000000..0aeb358b5 --- /dev/null +++ b/stubs/pyomo/contrib/cp/repn/docplex_writer.pyi @@ -0,0 +1,151 @@ +import types + +from _typeshed import Incomplete +from pyomo.common import DeveloperError as DeveloperError +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.fileutils import Executable as Executable +from pyomo.contrib.cp import IntervalVar as IntervalVar +from pyomo.contrib.cp.interval_var import IndexedIntervalVar as IndexedIntervalVar +from pyomo.contrib.cp.interval_var import IntervalVarData as IntervalVarData +from pyomo.contrib.cp.interval_var import IntervalVarEndTime as IntervalVarEndTime +from pyomo.contrib.cp.interval_var import IntervalVarLength as IntervalVarLength +from pyomo.contrib.cp.interval_var import IntervalVarPresence as IntervalVarPresence +from pyomo.contrib.cp.interval_var import IntervalVarStartTime as IntervalVarStartTime +from pyomo.contrib.cp.interval_var import ScalarIntervalVar as ScalarIntervalVar +from pyomo.contrib.cp.scheduling_expr.precedence_expressions import AtExpression as AtExpression +from pyomo.contrib.cp.scheduling_expr.precedence_expressions import ( + BeforeExpression as BeforeExpression, +) +from pyomo.contrib.cp.scheduling_expr.scheduling_logic import ( + AlternativeExpression as AlternativeExpression, +) +from pyomo.contrib.cp.scheduling_expr.scheduling_logic import SpanExpression as SpanExpression +from pyomo.contrib.cp.scheduling_expr.scheduling_logic import ( + SynchronizeExpression as SynchronizeExpression, +) +from pyomo.contrib.cp.scheduling_expr.sequence_expressions import ( + BeforeInSequenceExpression as BeforeInSequenceExpression, +) +from pyomo.contrib.cp.scheduling_expr.sequence_expressions import ( + FirstInSequenceExpression as FirstInSequenceExpression, +) +from pyomo.contrib.cp.scheduling_expr.sequence_expressions import ( + LastInSequenceExpression as LastInSequenceExpression, +) +from pyomo.contrib.cp.scheduling_expr.sequence_expressions import ( + NoOverlapExpression as NoOverlapExpression, +) +from pyomo.contrib.cp.scheduling_expr.sequence_expressions import ( + PredecessorToExpression as PredecessorToExpression, +) +from pyomo.contrib.cp.scheduling_expr.step_function_expressions import AlwaysIn as AlwaysIn +from pyomo.contrib.cp.scheduling_expr.step_function_expressions import ( + CumulativeFunction as CumulativeFunction, +) +from pyomo.contrib.cp.scheduling_expr.step_function_expressions import ( + NegatedStepFunction as NegatedStepFunction, +) +from pyomo.contrib.cp.scheduling_expr.step_function_expressions import Pulse as Pulse +from pyomo.contrib.cp.scheduling_expr.step_function_expressions import StepAt as StepAt +from pyomo.contrib.cp.scheduling_expr.step_function_expressions import StepAtEnd as StepAtEnd +from pyomo.contrib.cp.scheduling_expr.step_function_expressions import StepAtStart as StepAtStart +from pyomo.contrib.cp.sequence_var import ScalarSequenceVar as ScalarSequenceVar +from pyomo.contrib.cp.sequence_var import SequenceVar as SequenceVar +from pyomo.contrib.cp.sequence_var import SequenceVarData as SequenceVarData +from pyomo.core.base import Block as Block +from pyomo.core.base import BooleanVar as BooleanVar +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import LogicalConstraint as LogicalConstraint +from pyomo.core.base import Objective as Objective +from pyomo.core.base import Param as Param +from pyomo.core.base import RangeSet as RangeSet +from pyomo.core.base import Set as Set +from pyomo.core.base import SortComponents as SortComponents +from pyomo.core.base import Suffix as Suffix +from pyomo.core.base import Var as Var +from pyomo.core.base import maximize as maximize +from pyomo.core.base import minimize as minimize +from pyomo.core.base import value as value +from pyomo.core.base.boolean_var import BooleanVarData as BooleanVarData +from pyomo.core.base.boolean_var import IndexedBooleanVar as IndexedBooleanVar +from pyomo.core.base.boolean_var import ScalarBooleanVar as ScalarBooleanVar +from pyomo.core.base.expression import ExpressionData as ExpressionData +from pyomo.core.base.expression import ScalarExpression as ScalarExpression +from pyomo.core.base.param import IndexedParam as IndexedParam +from pyomo.core.base.param import ParamData as ParamData +from pyomo.core.base.param import ScalarParam as ScalarParam +from pyomo.core.base.set import SetProduct as SetProduct +from pyomo.core.base.var import IndexedVar as IndexedVar +from pyomo.core.base.var import ScalarVar as ScalarVar +from pyomo.core.base.var import VarData as VarData +from pyomo.core.expr.visitor import StreamBasedExpressionVisitor as StreamBasedExpressionVisitor +from pyomo.core.expr.visitor import identify_variables as identify_variables +from pyomo.network import Port as Port +from pyomo.opt import SolverFactory as SolverFactory +from pyomo.opt import SolverResults as SolverResults +from pyomo.opt import TerminationCondition as TerminationCondition +from pyomo.opt import WriterFactory as WriterFactory +from pyomo.repn.util import ExitNodeDispatcher as ExitNodeDispatcher + +cp: Incomplete +docplex_available: Incomplete +cp_solver: Incomplete +logger: Incomplete + +class _GENERAL: ... +class _START_TIME: ... +class _END_TIME: ... +class _DEFERRED_ELEMENT_CONSTRAINT: ... +class _ELEMENT_CONSTRAINT: ... +class _DEFERRED_BEFORE: ... +class _DEFERRED_AFTER: ... +class _DEFERRED_AT: ... +class _BEFORE: ... +class _AT: ... +class _IMPLIES: ... +class _LAND: ... +class _LOR: ... +class _XOR: ... +class _EQUIVALENT_TO: ... + +step_func_expression_types: Incomplete + +class LogicalToDoCplex(StreamBasedExpressionVisitor): + exit_node_dispatcher: Incomplete + cpx: Incomplete + symbolic_solver_labels: Incomplete + var_map: Incomplete + pyomo_to_docplex: Incomplete + def __init__(self, cpx_model, symbolic_solver_labels: bool = False) -> None: ... + def initializeWalker(self, expr): ... + def beforeChild(self, node, child, child_idx): ... + def exitNode(self, node, data): ... + finalizeResult: Incomplete + +def collect_valid_components(model, active: bool = True, sort=None, valid=..., targets=...): ... + +class DocplexWriter: + CONFIG: Incomplete + config: Incomplete + def __init__(self) -> None: ... + def write(self, model, **options): ... + +class CPOptimizerSolver: + CONFIG: Incomplete + config: Incomplete + def __init__(self, **kwds) -> None: ... + @property + def options(self): ... + def __enter__(self): ... + def __exit__( + self, + t: type[BaseException] | None, + v: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: ... + def available(self, exception_flag: bool = True): ... + def license_is_valid(self): ... + def solve(self, model, **kwds): ... diff --git a/stubs/pyomo/contrib/cp/scheduling_expr/__init__.pyi b/stubs/pyomo/contrib/cp/scheduling_expr/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/cp/scheduling_expr/precedence_expressions.pyi b/stubs/pyomo/contrib/cp/scheduling_expr/precedence_expressions.pyi new file mode 100644 index 000000000..88f38b956 --- /dev/null +++ b/stubs/pyomo/contrib/cp/scheduling_expr/precedence_expressions.pyi @@ -0,0 +1,11 @@ +from _typeshed import Incomplete +from pyomo.core.expr.logical_expr import BooleanExpression as BooleanExpression + +class PrecedenceExpression(BooleanExpression): + PRECEDENCE: Incomplete + def nargs(self): ... + @property + def delay(self): ... + +class BeforeExpression(PrecedenceExpression): ... +class AtExpression(PrecedenceExpression): ... diff --git a/stubs/pyomo/contrib/cp/scheduling_expr/scheduling_logic.pyi b/stubs/pyomo/contrib/cp/scheduling_expr/scheduling_logic.pyi new file mode 100644 index 000000000..c626350c2 --- /dev/null +++ b/stubs/pyomo/contrib/cp/scheduling_expr/scheduling_logic.pyi @@ -0,0 +1,9 @@ +from pyomo.core.expr.logical_expr import NaryBooleanExpression as NaryBooleanExpression + +class SpanExpression(NaryBooleanExpression): ... +class AlternativeExpression(NaryBooleanExpression): ... +class SynchronizeExpression(NaryBooleanExpression): ... + +def spans(*args): ... +def alternative(*args): ... +def synchronize(*args): ... diff --git a/stubs/pyomo/contrib/cp/scheduling_expr/sequence_expressions.pyi b/stubs/pyomo/contrib/cp/scheduling_expr/sequence_expressions.pyi new file mode 100644 index 000000000..141dde7cc --- /dev/null +++ b/stubs/pyomo/contrib/cp/scheduling_expr/sequence_expressions.pyi @@ -0,0 +1,22 @@ +from pyomo.core.expr.logical_expr import BooleanExpression as BooleanExpression + +class NoOverlapExpression(BooleanExpression): + def nargs(self): ... + +class FirstInSequenceExpression(BooleanExpression): + def nargs(self): ... + +class LastInSequenceExpression(BooleanExpression): + def nargs(self): ... + +class BeforeInSequenceExpression(BooleanExpression): + def nargs(self): ... + +class PredecessorToExpression(BooleanExpression): + def nargs(self): ... + +def no_overlap(sequence_var): ... +def first_in_sequence(interval_var, sequence_var): ... +def last_in_sequence(interval_var, sequence_var): ... +def before_in_sequence(before_var, after_var, sequence_var): ... +def predecessor_to(before_var, after_var, sequence_var): ... diff --git a/stubs/pyomo/contrib/cp/scheduling_expr/step_function_expressions.pyi b/stubs/pyomo/contrib/cp/scheduling_expr/step_function_expressions.pyi new file mode 100644 index 000000000..c00e8d2c5 --- /dev/null +++ b/stubs/pyomo/contrib/cp/scheduling_expr/step_function_expressions.pyi @@ -0,0 +1,48 @@ +from _typeshed import Incomplete +from pyomo.contrib.cp.interval_var import IntervalVar as IntervalVar +from pyomo.contrib.cp.interval_var import IntervalVarData as IntervalVarData +from pyomo.contrib.cp.interval_var import IntervalVarEndTime as IntervalVarEndTime +from pyomo.contrib.cp.interval_var import IntervalVarStartTime as IntervalVarStartTime +from pyomo.core.expr.base import ExpressionBase as ExpressionBase +from pyomo.core.expr.logical_expr import BooleanExpression as BooleanExpression +from pyomo.core.expr.numeric_expr import SumExpression as SumExpression + +class StepFunction(ExpressionBase): + PRECEDENCE: Incomplete + def __add__(self, other): ... + def __radd__(self, other): ... + def __iadd__(self, other): ... + def __sub__(self, other): ... + def __rsub__(self, other): ... + def __isub__(self, other): ... + def within(self, bounds, times): ... + @property + def args(self): ... + +class Pulse(StepFunction): + def __init__(self, args=None, interval_var=None, height=None) -> None: ... + def nargs(self): ... + +class Step(StepFunction): + def __new__(cls, time, height): ... + +class StepBase(StepFunction): + def __init__(self, args) -> None: ... + def nargs(self): ... + +class StepAt(StepBase): ... +class StepAtStart(StepBase): ... +class StepAtEnd(StepBase): ... + +class CumulativeFunction(StepFunction): + PRECEDENCE: Incomplete + def __init__(self, args, nargs=None) -> None: ... + def nargs(self): ... + +class NegatedStepFunction(StepFunction): + def __init__(self, args) -> None: ... + def nargs(self): ... + +class AlwaysIn(BooleanExpression): + def __init__(self, args=None, cumul_func=None, bounds=None, times=None) -> None: ... + def nargs(self): ... diff --git a/stubs/pyomo/contrib/cp/sequence_var.pyi b/stubs/pyomo/contrib/cp/sequence_var.pyi new file mode 100644 index 000000000..a99bae4d2 --- /dev/null +++ b/stubs/pyomo/contrib/cp/sequence_var.pyi @@ -0,0 +1,26 @@ +from _typeshed import Incomplete +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.contrib.cp import IntervalVar as IntervalVar +from pyomo.core import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.component import ActiveComponentData as ActiveComponentData +from pyomo.core.base.global_set import UnindexedComponent_index as UnindexedComponent_index +from pyomo.core.base.indexed_component import ActiveIndexedComponent as ActiveIndexedComponent +from pyomo.core.base.initializer import Initializer as Initializer + +logger: Incomplete + +class SequenceVarData(ActiveComponentData): + interval_vars: Incomplete + def __init__(self, component=None) -> None: ... + def set_value(self, expr) -> None: ... + +class SequenceVar(ActiveIndexedComponent): + def __new__(cls, *args, **kwds): ... + def __init__(self, *args, **kwargs) -> None: ... + def construct(self, data=None) -> None: ... + +class ScalarSequenceVar(SequenceVarData, SequenceVar): + def __init__(self, *args, **kwds) -> None: ... + +class IndexedSequenceVar(SequenceVar): ... diff --git a/stubs/pyomo/contrib/cp/transform/__init__.pyi b/stubs/pyomo/contrib/cp/transform/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/cp/transform/logical_to_disjunctive_program.pyi b/stubs/pyomo/contrib/cp/transform/logical_to_disjunctive_program.pyi new file mode 100644 index 000000000..4480e8c19 --- /dev/null +++ b/stubs/pyomo/contrib/cp/transform/logical_to_disjunctive_program.pyi @@ -0,0 +1,23 @@ +from _typeshed import Incomplete +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.contrib.cp.transform.logical_to_disjunctive_walker import ( + LogicalToDisjunctiveVisitor as LogicalToDisjunctiveVisitor, +) +from pyomo.core import Binary as Binary +from pyomo.core import Block as Block +from pyomo.core import ConstraintList as ConstraintList +from pyomo.core import LogicalConstraint as LogicalConstraint +from pyomo.core import NonNegativeIntegers as NonNegativeIntegers +from pyomo.core import Transformation as Transformation +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core import VarList as VarList +from pyomo.core.base import SortComponents as SortComponents +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.util import target_list as target_list +from pyomo.gdp import Disjunct as Disjunct +from pyomo.gdp import Disjunction as Disjunction + +class LogicalToDisjunctive(Transformation): + CONFIG: Incomplete diff --git a/stubs/pyomo/contrib/cp/transform/logical_to_disjunctive_walker.pyi b/stubs/pyomo/contrib/cp/transform/logical_to_disjunctive_walker.pyi new file mode 100644 index 000000000..35181fe70 --- /dev/null +++ b/stubs/pyomo/contrib/cp/transform/logical_to_disjunctive_walker.pyi @@ -0,0 +1,33 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.errors import MouseTrap as MouseTrap +from pyomo.core.base import Binary as Binary +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import ConstraintList as ConstraintList +from pyomo.core.base import NonNegativeIntegers as NonNegativeIntegers +from pyomo.core.base import VarList as VarList +from pyomo.core.base import value as value +from pyomo.core.base.expression import ExpressionData as ExpressionData +from pyomo.core.base.expression import ScalarExpression as ScalarExpression +from pyomo.core.base.param import ParamData as ParamData +from pyomo.core.base.param import ScalarParam as ScalarParam +from pyomo.core.base.var import ScalarVar as ScalarVar +from pyomo.core.base.var import VarData as VarData +from pyomo.core.expr.expr_common import ExpressionType as ExpressionType +from pyomo.core.expr.visitor import StreamBasedExpressionVisitor as StreamBasedExpressionVisitor +from pyomo.gdp.disjunct import AutoLinkedBooleanVar as AutoLinkedBooleanVar +from pyomo.gdp.disjunct import Disjunct as Disjunct +from pyomo.gdp.disjunct import Disjunction as Disjunction + +class LogicalToDisjunctiveVisitor(StreamBasedExpressionVisitor): + z_vars: Incomplete + constraints: Incomplete + disjuncts: Incomplete + disjunctions: Incomplete + expansions: Incomplete + boolean_to_binary_map: Incomplete + def __init__(self) -> None: ... + def initializeWalker(self, expr): ... + def beforeChild(self, node, child, child_idx): ... + def exitNode(self, node, data): ... + def finalizeResult(self, result): ... diff --git a/stubs/pyomo/contrib/cspline_external/__init__.pyi b/stubs/pyomo/contrib/cspline_external/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/cspline_external/build.pyi b/stubs/pyomo/contrib/cspline_external/build.pyi new file mode 100644 index 000000000..d9a172e03 --- /dev/null +++ b/stubs/pyomo/contrib/cspline_external/build.pyi @@ -0,0 +1,6 @@ +from pyomo.common.cmake_builder import build_cmake_project as build_cmake_project + +def build_cspline_external(user_args=[], parallel=None): ... + +class ASLCsplineExternalBuilder: + def __call__(self, parallel): ... diff --git a/stubs/pyomo/contrib/cspline_external/cspline_parameters.pyi b/stubs/pyomo/contrib/cspline_external/cspline_parameters.pyi new file mode 100644 index 000000000..cafbf0717 --- /dev/null +++ b/stubs/pyomo/contrib/cspline_external/cspline_parameters.pyi @@ -0,0 +1,30 @@ +from _typeshed import Incomplete + +class CsplineParameters: + knots: Incomplete + a1: Incomplete + a2: Incomplete + a3: Incomplete + a4: Incomplete + def __init__(self, model=None, fptr=None) -> None: ... + @property + def n_knots(self): ... + @property + def n_segments(self): ... + @property + def valid(self): ... + def get_parameters_from_model(self, m) -> None: ... + def get_parameters_from_file(self, fptr) -> None: ... + def write_parameters(self, fptr) -> None: ... + def segment(self, x): ... + def f(self, x): ... + +def cubic_parameters_model( + x_data, + y_data, + x_knots=None, + end_point_constraint: bool = True, + objective_form: bool = False, + name: str = 'cubic spline parameters model', +): ... +def add_endpoint_second_derivative_constraints(m): ... diff --git a/stubs/pyomo/contrib/cspline_external/plugins.pyi b/stubs/pyomo/contrib/cspline_external/plugins.pyi new file mode 100644 index 000000000..fdff5a59e --- /dev/null +++ b/stubs/pyomo/contrib/cspline_external/plugins.pyi @@ -0,0 +1,6 @@ +from pyomo.common.extensions import ExtensionBuilderFactory as ExtensionBuilderFactory +from pyomo.contrib.cspline_external.build import ( + ASLCsplineExternalBuilder as ASLCsplineExternalBuilder, +) + +def load() -> None: ... diff --git a/stubs/pyomo/contrib/doe/__init__.pyi b/stubs/pyomo/contrib/doe/__init__.pyi new file mode 100644 index 000000000..dcf0ad3c5 --- /dev/null +++ b/stubs/pyomo/contrib/doe/__init__.pyi @@ -0,0 +1,17 @@ +from pyomo.common.deprecation import deprecated as deprecated + +from .doe import DesignOfExperiments as DesignOfExperiments +from .doe import FiniteDifferenceStep as FiniteDifferenceStep +from .doe import ObjectiveLib as ObjectiveLib +from .utils import rescale_FIM as rescale_FIM + +deprecation_message: str + +class MeasurementVariables: + def __init__(self, *args) -> None: ... + +class DesignVariables: + def __init__(self, *args) -> None: ... + +class ModelOptionLib: + def __init__(self, *args) -> None: ... diff --git a/stubs/pyomo/contrib/doe/doe.pyi b/stubs/pyomo/contrib/doe/doe.pyi new file mode 100644 index 000000000..717b66108 --- /dev/null +++ b/stubs/pyomo/contrib/doe/doe.pyi @@ -0,0 +1,103 @@ +from enum import Enum + +from _typeshed import Incomplete +from pyomo.common.dependencies import numpy_available as numpy_available +from pyomo.common.dependencies import pathlib as pathlib +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.common.timing import TicTocTimer as TicTocTimer +from pyomo.contrib.sensitivity_toolbox.sens import get_dsdp as get_dsdp +from pyomo.opt import SolverStatus as SolverStatus + +class ObjectiveLib(Enum): + determinant = 'determinant' + trace = 'trace' + minimum_eigenvalue = 'minimum_eigenvalue' + zero = 'zero' + +class FiniteDifferenceStep(Enum): + forward = 'forward' + central = 'central' + backward = 'backward' + +class DesignOfExperiments: + experiment: Incomplete + fd_formula: Incomplete + step: Incomplete + objective_option: Incomplete + scale_constant_value: Incomplete + scale_nominal_param_value: Incomplete + prior_FIM: Incomplete + jac_initial: Incomplete + fim_initial: Incomplete + L_diagonal_lower_bound: Incomplete + solver: Incomplete + tee: Incomplete + get_labeled_model_args: Incomplete + logger: Incomplete + Cholesky_option: Incomplete + only_compute_fim_lower: Incomplete + model: Incomplete + results: Incomplete + def __init__( + self, + experiment=None, + fd_formula: str = 'central', + step: float = 0.001, + objective_option: str = 'determinant', + scale_constant_value: float = 1.0, + scale_nominal_param_value: bool = False, + prior_FIM=None, + jac_initial=None, + fim_initial=None, + L_diagonal_lower_bound: float = 1e-07, + solver=None, + tee: bool = False, + get_labeled_model_args=None, + logger_level=..., + _Cholesky_option: bool = True, + _only_compute_fim_lower: bool = True, + ) -> None: ... + def run_doe(self, model=None, results_file=None) -> None: ... + def run_multi_doe_sequential(self, N_exp: int = 1) -> None: ... + def run_multi_doe_simultaneous(self, N_exp: int = 1) -> None: ... + compute_FIM_model: Incomplete + n_parameters: Incomplete + n_measurement_error: Incomplete + n_experiment_inputs: Incomplete + n_experiment_outputs: Incomplete + def compute_FIM(self, model=None, method: str = 'sequential'): ... + def create_doe_model(self, model=None): ... + def create_objective_function(self, model=None): ... + def check_model_labels(self, model=None) -> None: ... + def check_model_FIM(self, model=None, FIM=None) -> None: ... + def check_model_jac(self, jac=None) -> None: ... + def update_FIM_prior(self, model=None, FIM=None) -> None: ... + def update_unknown_parameter_values(self, model=None, param_vals=None) -> None: ... + factorial_model: Incomplete + fim_factorial_results: Incomplete + def compute_FIM_full_factorial( + self, model=None, design_ranges=None, method: str = 'sequential' + ): ... + figure_result_data: Incomplete + figure_sens_des_vars: Incomplete + figure_fixed_des_vars: Incomplete + def draw_factorial_figure( + self, + results=None, + sensitivity_design_variables=None, + fixed_design_variables=None, + full_design_variable_names=None, + title_text: str = '', + xlabel_text: str = '', + ylabel_text: str = '', + figure_file_name=None, + font_axes: int = 16, + font_tick: int = 14, + log_scale: bool = True, + ) -> None: ... + def get_FIM(self, model=None): ... + def get_sensitivity_matrix(self, model=None): ... + def get_experiment_input_values(self, model=None): ... + def get_unknown_parameter_values(self, model=None): ... + def get_experiment_output_values(self, model=None): ... + def get_measurement_error_values(self, model=None): ... diff --git a/stubs/pyomo/contrib/doe/examples/__init__.pyi b/stubs/pyomo/contrib/doe/examples/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/doe/examples/reactor_compute_factorial_FIM.pyi b/stubs/pyomo/contrib/doe/examples/reactor_compute_factorial_FIM.pyi new file mode 100644 index 000000000..1f78ac636 --- /dev/null +++ b/stubs/pyomo/contrib/doe/examples/reactor_compute_factorial_FIM.pyi @@ -0,0 +1,5 @@ +from pyomo.common.dependencies import pathlib as pathlib +from pyomo.contrib.doe import DesignOfExperiments as DesignOfExperiments +from pyomo.contrib.doe.examples.reactor_experiment import ReactorExperiment as ReactorExperiment + +def run_reactor_doe() -> None: ... diff --git a/stubs/pyomo/contrib/doe/examples/reactor_example.pyi b/stubs/pyomo/contrib/doe/examples/reactor_example.pyi new file mode 100644 index 000000000..1f78ac636 --- /dev/null +++ b/stubs/pyomo/contrib/doe/examples/reactor_example.pyi @@ -0,0 +1,5 @@ +from pyomo.common.dependencies import pathlib as pathlib +from pyomo.contrib.doe import DesignOfExperiments as DesignOfExperiments +from pyomo.contrib.doe.examples.reactor_experiment import ReactorExperiment as ReactorExperiment + +def run_reactor_doe() -> None: ... diff --git a/stubs/pyomo/contrib/doe/examples/reactor_experiment.pyi b/stubs/pyomo/contrib/doe/examples/reactor_experiment.pyi new file mode 100644 index 000000000..2e7bba235 --- /dev/null +++ b/stubs/pyomo/contrib/doe/examples/reactor_experiment.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from pyomo.contrib.parmest.experiment import Experiment as Experiment +from pyomo.dae import ContinuousSet as ContinuousSet +from pyomo.dae import DerivativeVar as DerivativeVar +from pyomo.dae import Simulator as Simulator + +class ReactorExperiment(Experiment): + data: Incomplete + nfe: Incomplete + ncp: Incomplete + model: Incomplete + def __init__(self, data, nfe, ncp) -> None: ... + def get_labeled_model(self): ... + def create_model(self): ... + def finalize_model(self): ... + def label_experiment(self) -> None: ... diff --git a/stubs/pyomo/contrib/doe/utils.pyi b/stubs/pyomo/contrib/doe/utils.pyi new file mode 100644 index 000000000..1337e67f3 --- /dev/null +++ b/stubs/pyomo/contrib/doe/utils.pyi @@ -0,0 +1,5 @@ +from pyomo.common.dependencies import numpy_available as numpy_available +from pyomo.core.base.param import ParamData as ParamData +from pyomo.core.base.var import VarData as VarData + +def rescale_FIM(FIM, param_vals): ... diff --git a/stubs/pyomo/contrib/example/__init__.pyi b/stubs/pyomo/contrib/example/__init__.pyi new file mode 100644 index 000000000..3e4a1ae19 --- /dev/null +++ b/stubs/pyomo/contrib/example/__init__.pyi @@ -0,0 +1,3 @@ +from pyomo.contrib.example import bar as bar +from pyomo.contrib.example.foo import * +from pyomo.contrib.example.plugins import load as load diff --git a/stubs/pyomo/contrib/example/bar.pyi b/stubs/pyomo/contrib/example/bar.pyi new file mode 100644 index 000000000..6ad95b422 --- /dev/null +++ b/stubs/pyomo/contrib/example/bar.pyi @@ -0,0 +1 @@ +b: str diff --git a/stubs/pyomo/contrib/example/foo.pyi b/stubs/pyomo/contrib/example/foo.pyi new file mode 100644 index 000000000..a13145cf8 --- /dev/null +++ b/stubs/pyomo/contrib/example/foo.pyi @@ -0,0 +1 @@ +a: int diff --git a/stubs/pyomo/contrib/example/plugins/__init__.pyi b/stubs/pyomo/contrib/example/plugins/__init__.pyi new file mode 100644 index 000000000..08b671c7f --- /dev/null +++ b/stubs/pyomo/contrib/example/plugins/__init__.pyi @@ -0,0 +1 @@ +def load() -> None: ... diff --git a/stubs/pyomo/contrib/example/plugins/ex_plugin.pyi b/stubs/pyomo/contrib/example/plugins/ex_plugin.pyi new file mode 100644 index 000000000..9e8bafbdd --- /dev/null +++ b/stubs/pyomo/contrib/example/plugins/ex_plugin.pyi @@ -0,0 +1,6 @@ +from pyomo.core.base import Transformation as Transformation +from pyomo.core.base import TransformationFactory as TransformationFactory + +class Xfrm_PyomoTransformation(Transformation): + def __init__(self) -> None: ... + def create_using(self, instance, **kwds): ... diff --git a/stubs/pyomo/contrib/fbbt/__init__.pyi b/stubs/pyomo/contrib/fbbt/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/fbbt/expression_bounds_walker.pyi b/stubs/pyomo/contrib/fbbt/expression_bounds_walker.pyi new file mode 100644 index 000000000..753d126cc --- /dev/null +++ b/stubs/pyomo/contrib/fbbt/expression_bounds_walker.pyi @@ -0,0 +1,68 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.contrib.fbbt.interval import BoolFlag as BoolFlag +from pyomo.contrib.fbbt.interval import acos as acos +from pyomo.contrib.fbbt.interval import add as add +from pyomo.contrib.fbbt.interval import asin as asin +from pyomo.contrib.fbbt.interval import atan as atan +from pyomo.contrib.fbbt.interval import cos as cos +from pyomo.contrib.fbbt.interval import div as div +from pyomo.contrib.fbbt.interval import eq as eq +from pyomo.contrib.fbbt.interval import exp as exp +from pyomo.contrib.fbbt.interval import if_ as if_ +from pyomo.contrib.fbbt.interval import ineq as ineq +from pyomo.contrib.fbbt.interval import interval_abs as interval_abs +from pyomo.contrib.fbbt.interval import log as log +from pyomo.contrib.fbbt.interval import log10 as log10 +from pyomo.contrib.fbbt.interval import mul as mul +from pyomo.contrib.fbbt.interval import power as power +from pyomo.contrib.fbbt.interval import ranged as ranged +from pyomo.contrib.fbbt.interval import sin as sin +from pyomo.contrib.fbbt.interval import sub as sub +from pyomo.contrib.fbbt.interval import tan as tan +from pyomo.core.base.expression import Expression as Expression +from pyomo.core.expr.logical_expr import BooleanExpression as BooleanExpression +from pyomo.core.expr.numeric_expr import AbsExpression as AbsExpression +from pyomo.core.expr.numeric_expr import DivisionExpression as DivisionExpression +from pyomo.core.expr.numeric_expr import Expr_ifExpression as Expr_ifExpression +from pyomo.core.expr.numeric_expr import ExternalFunctionExpression as ExternalFunctionExpression +from pyomo.core.expr.numeric_expr import LinearExpression as LinearExpression +from pyomo.core.expr.numeric_expr import MonomialTermExpression as MonomialTermExpression +from pyomo.core.expr.numeric_expr import NegationExpression as NegationExpression +from pyomo.core.expr.numeric_expr import NumericExpression as NumericExpression +from pyomo.core.expr.numeric_expr import PowExpression as PowExpression +from pyomo.core.expr.numeric_expr import ProductExpression as ProductExpression +from pyomo.core.expr.numeric_expr import SumExpression as SumExpression +from pyomo.core.expr.numeric_expr import UnaryFunctionExpression as UnaryFunctionExpression +from pyomo.core.expr.numvalue import native_numeric_types as native_numeric_types +from pyomo.core.expr.numvalue import native_types as native_types +from pyomo.core.expr.numvalue import value as value +from pyomo.core.expr.relational_expr import EqualityExpression as EqualityExpression +from pyomo.core.expr.relational_expr import InequalityExpression as InequalityExpression +from pyomo.core.expr.relational_expr import RangedExpression as RangedExpression +from pyomo.core.expr.visitor import StreamBasedExpressionVisitor as StreamBasedExpressionVisitor +from pyomo.repn.util import BeforeChildDispatcher as BeforeChildDispatcher +from pyomo.repn.util import ExitNodeDispatcher as ExitNodeDispatcher + +inf: Incomplete +logger: Incomplete + +class ExpressionBoundsBeforeChildDispatcher(BeforeChildDispatcher): + def __init__(self) -> None: ... + +class ExpressionBoundsExitNodeDispatcher(ExitNodeDispatcher): + def unexpected_expression_type(self, visitor, node, *args): ... + +class ExpressionBoundsVisitor(StreamBasedExpressionVisitor): + leaf_bounds: Incomplete + feasibility_tol: Incomplete + use_fixed_var_values_as_bounds: Incomplete + def __init__( + self, + leaf_bounds=None, + feasibility_tol: float = 1e-08, + use_fixed_var_values_as_bounds: bool = False, + ) -> None: ... + def initializeWalker(self, expr): ... + def beforeChild(self, node, child, child_idx): ... + def exitNode(self, node, data): ... diff --git a/stubs/pyomo/contrib/fbbt/fbbt.pyi b/stubs/pyomo/contrib/fbbt/fbbt.pyi new file mode 100644 index 000000000..ed980c59c --- /dev/null +++ b/stubs/pyomo/contrib/fbbt/fbbt.pyi @@ -0,0 +1,76 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import In as In +from pyomo.common.config import NonNegativeFloat as NonNegativeFloat +from pyomo.common.config import NonNegativeInt as NonNegativeInt +from pyomo.common.errors import InfeasibleConstraintException as InfeasibleConstraintException +from pyomo.common.errors import PyomoException as PyomoException +from pyomo.common.numeric_types import native_types as native_types +from pyomo.contrib.fbbt.expression_bounds_walker import ( + ExpressionBoundsVisitor as ExpressionBoundsVisitor, +) +from pyomo.core.base.block import Block as Block +from pyomo.core.base.constraint import Constraint as Constraint +from pyomo.core.base.expression import ExpressionData as ExpressionData +from pyomo.core.base.expression import ScalarExpression as ScalarExpression +from pyomo.core.base.objective import ObjectiveData as ObjectiveData +from pyomo.core.base.objective import ScalarObjective as ScalarObjective +from pyomo.core.base.var import Var as Var +from pyomo.core.expr.numvalue import is_fixed as is_fixed +from pyomo.core.expr.numvalue import nonpyomo_leaf_types as nonpyomo_leaf_types +from pyomo.core.expr.numvalue import value as value +from pyomo.core.expr.visitor import ExpressionValueVisitor as ExpressionValueVisitor +from pyomo.core.expr.visitor import StreamBasedExpressionVisitor as StreamBasedExpressionVisitor +from pyomo.core.expr.visitor import identify_variables as identify_variables +from pyomo.gdp import Disjunct as Disjunct + +logger: Incomplete +__doc__: str + +class FBBTException(PyomoException): ... + +class _FBBTVisitorLeafToRoot(StreamBasedExpressionVisitor): + bnds_dict: Incomplete + integer_tol: Incomplete + feasibility_tol: Incomplete + ignore_fixed: Incomplete + def __init__( + self, + bnds_dict, + integer_tol: float = 0.0001, + feasibility_tol: float = 1e-08, + ignore_fixed: bool = False, + ) -> None: ... + def initializeWalker(self, expr): ... + def beforeChild(self, node, child, child_idx): ... + def exitNode(self, node, data) -> None: ... + +class _FBBTVisitorRootToLeaf(ExpressionValueVisitor): + bnds_dict: Incomplete + integer_tol: Incomplete + feasibility_tol: Incomplete + def __init__( + self, bnds_dict, integer_tol: float = 0.0001, feasibility_tol: float = 1e-08 + ) -> None: ... + def visit(self, node, values) -> None: ... + def visiting_potential_leaf(self, node): ... + +def fbbt( + comp, + deactivate_satisfied_constraints: bool = False, + integer_tol: float = 1e-05, + feasibility_tol: float = 1e-08, + max_iter: int = 10, + improvement_tol: float = 0.0001, + descend_into: bool = True, +): ... +def compute_bounds_on_expr(expr, ignore_fixed: bool = False): ... + +class BoundsManager: + def __init__(self, comp) -> None: ... + def save_bounds(self) -> None: ... + def pop_bounds(self, ndx: int = -1) -> None: ... + def load_bounds(self, bnds, save_current_bounds: bool = True) -> None: ... diff --git a/stubs/pyomo/contrib/fbbt/interval.pyi b/stubs/pyomo/contrib/fbbt/interval.pyi new file mode 100644 index 000000000..8d74c3d5f --- /dev/null +++ b/stubs/pyomo/contrib/fbbt/interval.pyi @@ -0,0 +1,46 @@ +from _typeshed import Incomplete +from pyomo.common.errors import InfeasibleConstraintException as InfeasibleConstraintException +from pyomo.common.errors import IntervalException as IntervalException + +logger: Incomplete +inf: Incomplete + +class _bool_flag: + def __init__(self, val) -> None: ... + def __bool__(self) -> bool: ... + __float__: Incomplete + __int__: Incomplete + __abs__: Incomplete + __neg__: Incomplete + __add__: Incomplete + __sub__: Incomplete + __mul__: Incomplete + __div__: Incomplete + __pow__: Incomplete + __radd__: Incomplete + __rsub__: Incomplete + __rmul__: Incomplete + __rdiv__: Incomplete + __rpow__: Incomplete + +def BoolFlag(val): ... +def ineq(xl, xu, yl, yu, feasibility_tol): ... +def eq(xl, xu, yl, yu, feasibility_tol): ... +def ranged(xl, xu, yl, yu, zl, zu, feasibility_tol): ... +def if_(il, iu, tl, tu, fl, fu): ... +def add(xl, xu, yl, yu): ... +def sub(xl, xu, yl, yu): ... +def mul(xl, xu, yl, yu): ... +def inv(xl, xu, feasibility_tol): ... +def div(xl, xu, yl, yu, feasibility_tol): ... +def power(xl, xu, yl, yu, feasibility_tol): ... +def interval_abs(xl, xu): ... +def exp(xl, xu): ... +def log(xl, xu): ... +def log10(xl, xu): ... +def sin(xl, xu): ... +def cos(xl, xu): ... +def tan(xl, xu): ... +def asin(xl, xu, yl, yu, feasibility_tol): ... +def acos(xl, xu, yl, yu, feasibility_tol): ... +def atan(xl, xu, yl, yu): ... diff --git a/stubs/pyomo/contrib/fme/__init__.pyi b/stubs/pyomo/contrib/fme/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/fme/fourier_motzkin_elimination.pyi b/stubs/pyomo/contrib/fme/fourier_motzkin_elimination.pyi new file mode 100644 index 000000000..b1c1ecd66 --- /dev/null +++ b/stubs/pyomo/contrib/fme/fourier_motzkin_elimination.pyi @@ -0,0 +1,37 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import NonNegativeFloat as NonNegativeFloat +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.core import Block as Block +from pyomo.core import Constraint as Constraint +from pyomo.core import ConstraintList as ConstraintList +from pyomo.core import Expression as Expression +from pyomo.core import Objective as Objective +from pyomo.core import Param as Param +from pyomo.core import Set as Set +from pyomo.core import SetOf as SetOf +from pyomo.core import SortComponents as SortComponents +from pyomo.core import Suffix as Suffix +from pyomo.core import Var as Var +from pyomo.core import value as value +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.core.base import VarData as VarData +from pyomo.core.plugins.transform.hierarchy import Transformation as Transformation +from pyomo.opt import TerminationCondition as TerminationCondition +from pyomo.repn.standard_repn import generate_standard_repn as generate_standard_repn +from pyomo.util.config_domains import ComponentDataSet as ComponentDataSet + +logger: Incomplete + +def gcd(a, b): ... +def lcm(ints): ... + +class Fourier_Motzkin_Elimination_Transformation(Transformation): + CONFIG: Incomplete + def __init__(self) -> None: ... + def post_process_fme_constraints( + self, m, solver_factory, projected_constraints=None, tolerance: int = 0 + ) -> None: ... diff --git a/stubs/pyomo/contrib/fme/plugins.pyi b/stubs/pyomo/contrib/fme/plugins.pyi new file mode 100644 index 000000000..08b671c7f --- /dev/null +++ b/stubs/pyomo/contrib/fme/plugins.pyi @@ -0,0 +1 @@ +def load() -> None: ... diff --git a/stubs/pyomo/contrib/gdp_bounds/__init__.pyi b/stubs/pyomo/contrib/gdp_bounds/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/gdp_bounds/compute_bounds.pyi b/stubs/pyomo/contrib/gdp_bounds/compute_bounds.pyi new file mode 100644 index 000000000..ae292e6c1 --- /dev/null +++ b/stubs/pyomo/contrib/gdp_bounds/compute_bounds.pyi @@ -0,0 +1,28 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.errors import InfeasibleConstraintException as InfeasibleConstraintException +from pyomo.contrib.fbbt.fbbt import BoundsManager as BoundsManager +from pyomo.contrib.fbbt.fbbt import fbbt as fbbt +from pyomo.core import Constraint as Constraint +from pyomo.core import Objective as Objective +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core import minimize as minimize +from pyomo.core import value as value +from pyomo.core.base.block import Block as Block +from pyomo.core.base.block import TraversalStrategy as TraversalStrategy +from pyomo.core.expr import identify_variables as identify_variables +from pyomo.core.plugins.transform.hierarchy import Transformation as Transformation +from pyomo.gdp.disjunct import Disjunct as Disjunct +from pyomo.opt import SolverFactory as SolverFactory + +linear_degrees: Incomplete +inf: Incomplete + +def disjunctive_obbt(model, solver) -> None: ... +def obbt_disjunct(orig_model, idx, solver): ... +def solve_bounding_problem(model, solver): ... +def disjunctive_fbbt(model) -> None: ... +def fbbt_disjunct(disj, parent_bounds) -> None: ... + +class ComputeDisjunctiveVarBounds(Transformation): ... diff --git a/stubs/pyomo/contrib/gdp_bounds/info.pyi b/stubs/pyomo/contrib/gdp_bounds/info.pyi new file mode 100644 index 000000000..d30f008b2 --- /dev/null +++ b/stubs/pyomo/contrib/gdp_bounds/info.pyi @@ -0,0 +1,10 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.core import value as value + +inf: Incomplete + +def disjunctive_bounds(scope): ... +def disjunctive_bound(var, scope): ... +def disjunctive_lb(var, scope): ... +def disjunctive_ub(var, scope): ... diff --git a/stubs/pyomo/contrib/gdp_bounds/plugins.pyi b/stubs/pyomo/contrib/gdp_bounds/plugins.pyi new file mode 100644 index 000000000..08b671c7f --- /dev/null +++ b/stubs/pyomo/contrib/gdp_bounds/plugins.pyi @@ -0,0 +1 @@ +def load() -> None: ... diff --git a/stubs/pyomo/contrib/gdpopt/GDPopt.pyi b/stubs/pyomo/contrib/gdpopt/GDPopt.pyi new file mode 100644 index 000000000..fddf6253b --- /dev/null +++ b/stubs/pyomo/contrib/gdpopt/GDPopt.pyi @@ -0,0 +1,21 @@ +import types + +from _typeshed import Incomplete +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.contrib.gdpopt import __version__ as __version__ +from pyomo.opt.base import SolverFactory as SolverFactory + +class GDPoptSolver: + CONFIG: Incomplete + def solve(self, model, **kwds): ... + def __enter__(self): ... + def __exit__( + self, + t: type[BaseException] | None, + v: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: ... + def available(self, exception_flag: bool = True): ... + def license_is_valid(self): ... + def version(self): ... diff --git a/stubs/pyomo/contrib/gdpopt/__init__.pyi b/stubs/pyomo/contrib/gdpopt/__init__.pyi new file mode 100644 index 000000000..f27f712b6 --- /dev/null +++ b/stubs/pyomo/contrib/gdpopt/__init__.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +__version__: Incomplete diff --git a/stubs/pyomo/contrib/gdpopt/algorithm_base_class.pyi b/stubs/pyomo/contrib/gdpopt/algorithm_base_class.pyi new file mode 100644 index 000000000..9f4b92574 --- /dev/null +++ b/stubs/pyomo/contrib/gdpopt/algorithm_base_class.pyi @@ -0,0 +1,62 @@ +import types + +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.errors import DeveloperError as DeveloperError +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.contrib.gdpopt import __version__ as __version__ +from pyomo.contrib.gdpopt.create_oa_subproblems import ( + add_algebraic_variable_list as add_algebraic_variable_list, +) +from pyomo.contrib.gdpopt.create_oa_subproblems import ( + add_boolean_variable_lists as add_boolean_variable_lists, +) +from pyomo.contrib.gdpopt.create_oa_subproblems import add_disjunct_list as add_disjunct_list +from pyomo.contrib.gdpopt.create_oa_subproblems import add_util_block as add_util_block +from pyomo.contrib.gdpopt.util import get_main_elapsed_time as get_main_elapsed_time +from pyomo.contrib.gdpopt.util import lower_logger_level_to as lower_logger_level_to +from pyomo.contrib.gdpopt.util import solve_continuous_problem as solve_continuous_problem +from pyomo.contrib.gdpopt.util import time_code as time_code +from pyomo.core.base import Objective as Objective +from pyomo.core.base import maximize as maximize +from pyomo.core.base import minimize as minimize +from pyomo.core.base import value as value +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager +from pyomo.opt import SolverResults as SolverResults +from pyomo.util.model_size import build_model_size_report as build_model_size_report + +class _GDPoptAlgorithm: + CONFIG: Incomplete + config: Incomplete + LB: Incomplete + UB: Incomplete + timing: Incomplete + initialization_iteration: int + iteration: int + incumbent_boolean_soln: Incomplete + incumbent_continuous_soln: Incomplete + original_obj: Incomplete + original_util_block: Incomplete + log_formatter: str + def __init__(self, **kwds) -> None: ... + def __enter__(self): ... + def __exit__( + self, + t: type[BaseException] | None, + v: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: ... + def available(self, exception_flag: bool = True): ... + def license_is_valid(self): ... + def version(self): ... + def solve(self, model, **kwds): ... + @property + def objective_sense(self): ... + def relative_gap(self): ... + def primal_bound(self): ... + def update_incumbent(self, util_block) -> None: ... + def bounds_converged(self, config): ... + def reached_iteration_limit(self, config): ... + def reached_time_limit(self, config): ... + def any_termination_criterion_met(self, config): ... diff --git a/stubs/pyomo/contrib/gdpopt/branch_and_bound.pyi b/stubs/pyomo/contrib/gdpopt/branch_and_bound.pyi new file mode 100644 index 000000000..c28d7f304 --- /dev/null +++ b/stubs/pyomo/contrib/gdpopt/branch_and_bound.pyi @@ -0,0 +1,47 @@ +from typing import NamedTuple + +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.common.errors import InfeasibleConstraintException as InfeasibleConstraintException +from pyomo.contrib.fbbt.fbbt import fbbt as fbbt +from pyomo.contrib.gdpopt.algorithm_base_class import _GDPoptAlgorithm +from pyomo.contrib.gdpopt.create_oa_subproblems import ( + add_algebraic_variable_list as add_algebraic_variable_list, +) +from pyomo.contrib.gdpopt.create_oa_subproblems import ( + add_boolean_variable_lists as add_boolean_variable_lists, +) +from pyomo.contrib.gdpopt.create_oa_subproblems import add_disjunct_list as add_disjunct_list +from pyomo.contrib.gdpopt.create_oa_subproblems import add_disjunction_list as add_disjunction_list +from pyomo.contrib.gdpopt.create_oa_subproblems import ( + add_transformed_boolean_variable_list as add_transformed_boolean_variable_list, +) +from pyomo.contrib.gdpopt.create_oa_subproblems import add_util_block as add_util_block +from pyomo.contrib.gdpopt.nlp_initialization import ( + restore_vars_to_original_values as restore_vars_to_original_values, +) +from pyomo.contrib.gdpopt.util import SuppressInfeasibleWarning as SuppressInfeasibleWarning +from pyomo.contrib.gdpopt.util import copy_var_list_values as copy_var_list_values +from pyomo.contrib.gdpopt.util import get_main_elapsed_time as get_main_elapsed_time +from pyomo.contrib.satsolver.satsolver import satisfiable as satisfiable +from pyomo.core import Constraint as Constraint +from pyomo.core import Suffix as Suffix +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core import minimize as minimize +from pyomo.opt import SolverFactory as SolverFactory +from pyomo.opt import SolverStatus as SolverStatus + +class BBNodeData(NamedTuple): + obj_lb: Incomplete + obj_ub: Incomplete + is_screened: Incomplete + is_evaluated: Incomplete + num_unbranched_disjunctions: Incomplete + node_count: Incomplete + unbranched_disjunction_indices: Incomplete + +class GDP_LBB_Solver(_GDPoptAlgorithm): + CONFIG: Incomplete + algorithm: str + def solve(self, model, **kwds): ... diff --git a/stubs/pyomo/contrib/gdpopt/config_options.pyi b/stubs/pyomo/contrib/gdpopt/config_options.pyi new file mode 100644 index 000000000..1ac657af1 --- /dev/null +++ b/stubs/pyomo/contrib/gdpopt/config_options.pyi @@ -0,0 +1,18 @@ +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.config import ConfigList as ConfigList +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import In as In +from pyomo.common.config import NonNegativeFloat as NonNegativeFloat +from pyomo.common.config import NonNegativeInt as NonNegativeInt +from pyomo.common.config import PositiveInt as PositiveInt +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.contrib.gdpopt.discrete_problem_initialize import ( + valid_init_strategies as valid_init_strategies, +) +from pyomo.contrib.gdpopt.nlp_initialization import ( + restore_vars_to_original_values as restore_vars_to_original_values, +) +from pyomo.contrib.gdpopt.util import a_logger as a_logger +from pyomo.core.base import LogicalConstraint as LogicalConstraint +from pyomo.gdp.disjunct import Disjunction as Disjunction +from pyomo.util.config_domains import ComponentDataSet as ComponentDataSet diff --git a/stubs/pyomo/contrib/gdpopt/create_oa_subproblems.pyi b/stubs/pyomo/contrib/gdpopt/create_oa_subproblems.pyi new file mode 100644 index 000000000..b4f9cd235 --- /dev/null +++ b/stubs/pyomo/contrib/gdpopt/create_oa_subproblems.pyi @@ -0,0 +1,38 @@ +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.contrib.gdpopt.discrete_problem_initialize import ( + valid_init_strategies as valid_init_strategies, +) +from pyomo.contrib.gdpopt.util import get_main_elapsed_time as get_main_elapsed_time +from pyomo.contrib.gdpopt.util import ( + move_nonlinear_objective_to_constraints as move_nonlinear_objective_to_constraints, +) +from pyomo.core import Constraint as Constraint +from pyomo.core import Expression as Expression +from pyomo.core import LogicalConstraint as LogicalConstraint +from pyomo.core import Objective as Objective +from pyomo.core import SortComponents as SortComponents +from pyomo.core.base import ConstraintList as ConstraintList +from pyomo.core.base import Integers as Integers +from pyomo.core.base import Suffix as Suffix +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.core.base.block import Block as Block +from pyomo.core.base.block import TraversalStrategy as TraversalStrategy +from pyomo.gdp.disjunct import Disjunct as Disjunct +from pyomo.gdp.disjunct import Disjunction as Disjunction +from pyomo.util.vars_from_expressions import get_vars_from_components as get_vars_from_components + +def initialize_discrete_problem(util_block, subprob_util_block, config, solver): ... +def add_util_block(discrete): ... +def add_disjunct_list(util_block) -> None: ... +def add_disjunction_list(util_block) -> None: ... +def add_constraint_list(util_block) -> None: ... +def add_global_constraint_list(util_block) -> None: ... +def add_constraints_by_disjunct(util_block) -> None: ... +def add_algebraic_variable_list(util_block, name=None) -> None: ... +def add_discrete_variable_list(util_block) -> None: ... +def add_boolean_variable_lists(util_block) -> None: ... +def add_transformed_boolean_variable_list(util_block) -> None: ... +def get_subproblem(original_model, util_block): ... +def save_initial_values(subproblem_util_block) -> None: ... diff --git a/stubs/pyomo/contrib/gdpopt/cut_generation.pyi b/stubs/pyomo/contrib/gdpopt/cut_generation.pyi new file mode 100644 index 000000000..66c4a7e2c --- /dev/null +++ b/stubs/pyomo/contrib/gdpopt/cut_generation.pyi @@ -0,0 +1,7 @@ +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.core import Block as Block +from pyomo.core import Constraint as Constraint +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core import value as value + +def add_no_good_cut(target_model_util_block, config) -> None: ... diff --git a/stubs/pyomo/contrib/gdpopt/discrete_problem_initialize.pyi b/stubs/pyomo/contrib/gdpopt/discrete_problem_initialize.pyi new file mode 100644 index 000000000..28c95de52 --- /dev/null +++ b/stubs/pyomo/contrib/gdpopt/discrete_problem_initialize.pyi @@ -0,0 +1,42 @@ +from collections.abc import Generator +from contextlib import contextmanager + +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.contrib.gdpopt.cut_generation import add_no_good_cut as add_no_good_cut +from pyomo.contrib.gdpopt.solve_discrete_problem import ( + solve_MILP_discrete_problem as solve_MILP_discrete_problem, +) +from pyomo.core import Block as Block +from pyomo.core import Constraint as Constraint +from pyomo.core import Objective as Objective +from pyomo.core import Var as Var +from pyomo.core import maximize as maximize +from pyomo.core import value as value +from pyomo.gdp import Disjunct as Disjunct + +@contextmanager +def preserve_discrete_problem_feasible_region( + discrete_problem_util_block, config, original_bounds=None +) -> Generator[None]: ... +def init_custom_disjuncts( + util_block, discrete_problem_util_block, subprob_util_block, config, solver +) -> None: ... +def init_fixed_disjuncts( + util_block, discrete_problem_util_block, subprob_util_block, config, solver +) -> None: ... +@contextmanager +def use_discrete_problem_for_max_binary_initialization( + discrete_problem_util_block, +) -> Generator[None]: ... +def init_max_binaries( + util_block, discrete_problem_util_block, subprob_util_block, config, solver +): ... +@contextmanager +def use_discrete_problem_for_set_covering(discrete_problem_util_block) -> Generator[None]: ... +def update_set_covering_objective(discrete_problem_util_block, disj_needs_cover) -> None: ... +def init_set_covering( + util_block, discrete_problem_util_block, subprob_util_block, config, solver +): ... + +valid_init_strategies: Incomplete diff --git a/stubs/pyomo/contrib/gdpopt/enumerate.pyi b/stubs/pyomo/contrib/gdpopt/enumerate.pyi new file mode 100644 index 000000000..3feed0792 --- /dev/null +++ b/stubs/pyomo/contrib/gdpopt/enumerate.pyi @@ -0,0 +1,25 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.contrib.gdpopt.algorithm_base_class import _GDPoptAlgorithm +from pyomo.contrib.gdpopt.create_oa_subproblems import ( + add_discrete_variable_list as add_discrete_variable_list, +) +from pyomo.contrib.gdpopt.create_oa_subproblems import add_disjunction_list as add_disjunction_list +from pyomo.contrib.gdpopt.create_oa_subproblems import get_subproblem as get_subproblem +from pyomo.contrib.gdpopt.nlp_initialization import ( + restore_vars_to_original_values_enumerate as restore_vars_to_original_values_enumerate, +) +from pyomo.contrib.gdpopt.solve_subproblem import solve_subproblem as solve_subproblem +from pyomo.contrib.gdpopt.util import ( + fix_discrete_solution_in_subproblem as fix_discrete_solution_in_subproblem, +) +from pyomo.contrib.gdpopt.util import get_main_elapsed_time as get_main_elapsed_time +from pyomo.contrib.gdpopt.util import time_code as time_code +from pyomo.core import value as value +from pyomo.opt.base import SolverFactory as SolverFactory + +class GDP_Enumeration_Solver(_GDPoptAlgorithm): + CONFIG: Incomplete + algorithm: str + def solve(self, model, **kwds): ... diff --git a/stubs/pyomo/contrib/gdpopt/gloa.pyi b/stubs/pyomo/contrib/gdpopt/gloa.pyi new file mode 100644 index 000000000..b1dc28d8c --- /dev/null +++ b/stubs/pyomo/contrib/gdpopt/gloa.pyi @@ -0,0 +1,32 @@ +from _typeshed import Incomplete +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.common.errors import DeveloperError as DeveloperError +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.contrib.gdp_bounds.info import disjunctive_bounds as disjunctive_bounds +from pyomo.contrib.gdpopt.algorithm_base_class import _GDPoptAlgorithm +from pyomo.contrib.gdpopt.create_oa_subproblems import ( + add_constraints_by_disjunct as add_constraints_by_disjunct, +) +from pyomo.contrib.gdpopt.create_oa_subproblems import ( + add_global_constraint_list as add_global_constraint_list, +) +from pyomo.contrib.gdpopt.cut_generation import add_no_good_cut as add_no_good_cut +from pyomo.contrib.gdpopt.oa_algorithm_utils import _OAAlgorithmMixIn +from pyomo.contrib.gdpopt.solve_discrete_problem import ( + solve_MILP_discrete_problem as solve_MILP_discrete_problem, +) +from pyomo.contrib.gdpopt.util import time_code as time_code +from pyomo.contrib.mcpp.pyomo_mcpp import MCPP_Error as MCPP_Error +from pyomo.core import Block as Block +from pyomo.core import Constraint as Constraint +from pyomo.core import NonNegativeIntegers as NonNegativeIntegers +from pyomo.core import Objective as Objective +from pyomo.core import value as value +from pyomo.core.expr.numvalue import is_potentially_variable as is_potentially_variable +from pyomo.core.expr.visitor import identify_variables as identify_variables +from pyomo.opt.base import SolverFactory as SolverFactory + +class GDP_GLOA_Solver(_GDPoptAlgorithm, _OAAlgorithmMixIn): + CONFIG: Incomplete + algorithm: str + def solve(self, model, **kwds): ... diff --git a/stubs/pyomo/contrib/gdpopt/ldsda.pyi b/stubs/pyomo/contrib/gdpopt/ldsda.pyi new file mode 100644 index 000000000..aa6bec733 --- /dev/null +++ b/stubs/pyomo/contrib/gdpopt/ldsda.pyi @@ -0,0 +1,53 @@ +from typing import NamedTuple + +from _typeshed import Incomplete +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.errors import InfeasibleConstraintException as InfeasibleConstraintException +from pyomo.contrib.fbbt.fbbt import fbbt as fbbt +from pyomo.contrib.gdpopt.algorithm_base_class import _GDPoptAlgorithm +from pyomo.contrib.gdpopt.create_oa_subproblems import ( + add_algebraic_variable_list as add_algebraic_variable_list, +) +from pyomo.contrib.gdpopt.create_oa_subproblems import ( + add_boolean_variable_lists as add_boolean_variable_lists, +) +from pyomo.contrib.gdpopt.create_oa_subproblems import add_disjunct_list as add_disjunct_list +from pyomo.contrib.gdpopt.create_oa_subproblems import add_disjunction_list as add_disjunction_list +from pyomo.contrib.gdpopt.create_oa_subproblems import ( + add_transformed_boolean_variable_list as add_transformed_boolean_variable_list, +) +from pyomo.contrib.gdpopt.create_oa_subproblems import add_util_block as add_util_block +from pyomo.contrib.gdpopt.nlp_initialization import ( + restore_vars_to_original_values as restore_vars_to_original_values, +) +from pyomo.contrib.gdpopt.util import SuppressInfeasibleWarning as SuppressInfeasibleWarning +from pyomo.contrib.gdpopt.util import get_main_elapsed_time as get_main_elapsed_time +from pyomo.contrib.satsolver.satsolver import satisfiable as satisfiable +from pyomo.core import Objective as Objective +from pyomo.core import Suffix as Suffix +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core import minimize as minimize +from pyomo.core import value as value +from pyomo.core.expr.logical_expr import ExactlyExpression as ExactlyExpression +from pyomo.opt import SolverFactory as SolverFactory + +tabulate: Incomplete +tabulate_available: Incomplete + +class ExternalVarInfo(NamedTuple): + exactly_number: Incomplete + Boolean_vars: Incomplete + UB: Incomplete + LB: Incomplete + +class GDP_LDSDA_Solver(_GDPoptAlgorithm): + CONFIG: Incomplete + algorithm: str + def solve(self, model, **kwds): ... + def any_termination_criterion_met(self, config): ... + def fix_disjunctions_with_external_var(self, external_var_values_list) -> None: ... + best_direction: Incomplete + current_point: Incomplete + def neighbor_search(self, config): ... + def line_search(self, config) -> None: ... diff --git a/stubs/pyomo/contrib/gdpopt/loa.pyi b/stubs/pyomo/contrib/gdpopt/loa.pyi new file mode 100644 index 000000000..410028e4b --- /dev/null +++ b/stubs/pyomo/contrib/gdpopt/loa.pyi @@ -0,0 +1,40 @@ +from typing import NamedTuple + +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.contrib.gdpopt.algorithm_base_class import _GDPoptAlgorithm +from pyomo.contrib.gdpopt.create_oa_subproblems import add_constraint_list as add_constraint_list +from pyomo.contrib.gdpopt.cut_generation import add_no_good_cut as add_no_good_cut +from pyomo.contrib.gdpopt.oa_algorithm_utils import _OAAlgorithmMixIn +from pyomo.contrib.gdpopt.solve_discrete_problem import ( + solve_MILP_discrete_problem as solve_MILP_discrete_problem, +) +from pyomo.contrib.gdpopt.util import time_code as time_code +from pyomo.core import Block as Block +from pyomo.core import Constraint as Constraint +from pyomo.core import NonNegativeIntegers as NonNegativeIntegers +from pyomo.core import NonNegativeReals as NonNegativeReals +from pyomo.core import Objective as Objective +from pyomo.core import Var as Var +from pyomo.core import VarList as VarList +from pyomo.core import minimize as minimize +from pyomo.core import value as value +from pyomo.core.expr import differentiate as differentiate +from pyomo.core.expr.visitor import identify_variables as identify_variables +from pyomo.gdp import Disjunct as Disjunct +from pyomo.opt.base import SolverFactory as SolverFactory +from pyomo.repn import generate_standard_repn as generate_standard_repn + +MAX_SYMBOLIC_DERIV_SIZE: int + +class JacInfo(NamedTuple): + mode: Incomplete + vars: Incomplete + jac: Incomplete + +class GDP_LOA_Solver(_GDPoptAlgorithm, _OAAlgorithmMixIn): + CONFIG: Incomplete + algorithm: str + def solve(self, model, **kwds): ... diff --git a/stubs/pyomo/contrib/gdpopt/nlp_initialization.pyi b/stubs/pyomo/contrib/gdpopt/nlp_initialization.pyi new file mode 100644 index 000000000..ef631163d --- /dev/null +++ b/stubs/pyomo/contrib/gdpopt/nlp_initialization.pyi @@ -0,0 +1,4 @@ +def restore_vars_to_original_values(solver, nlp_util_block, mip_util_block) -> None: ... +def restore_vars_to_original_values_enumerate( + true_disjuncts, boolean_var_values, discrete_var_values, nlp_util_block +) -> None: ... diff --git a/stubs/pyomo/contrib/gdpopt/oa_algorithm_utils.pyi b/stubs/pyomo/contrib/gdpopt/oa_algorithm_utils.pyi new file mode 100644 index 000000000..2030ec482 --- /dev/null +++ b/stubs/pyomo/contrib/gdpopt/oa_algorithm_utils.pyi @@ -0,0 +1,7 @@ +from pyomo.contrib.gdpopt.solve_subproblem import solve_subproblem as solve_subproblem +from pyomo.contrib.gdpopt.util import ( + fix_discrete_problem_solution_in_subproblem as fix_discrete_problem_solution_in_subproblem, +) +from pyomo.core import value as value + +class _OAAlgorithmMixIn: ... diff --git a/stubs/pyomo/contrib/gdpopt/plugins.pyi b/stubs/pyomo/contrib/gdpopt/plugins.pyi new file mode 100644 index 000000000..08b671c7f --- /dev/null +++ b/stubs/pyomo/contrib/gdpopt/plugins.pyi @@ -0,0 +1 @@ +def load() -> None: ... diff --git a/stubs/pyomo/contrib/gdpopt/ric.pyi b/stubs/pyomo/contrib/gdpopt/ric.pyi new file mode 100644 index 000000000..d8c20d403 --- /dev/null +++ b/stubs/pyomo/contrib/gdpopt/ric.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.contrib.gdpopt.algorithm_base_class import _GDPoptAlgorithm +from pyomo.contrib.gdpopt.cut_generation import add_no_good_cut as add_no_good_cut +from pyomo.contrib.gdpopt.oa_algorithm_utils import _OAAlgorithmMixIn +from pyomo.contrib.gdpopt.solve_discrete_problem import ( + solve_MILP_discrete_problem as solve_MILP_discrete_problem, +) +from pyomo.contrib.gdpopt.util import time_code as time_code +from pyomo.core import Objective as Objective +from pyomo.opt.base import SolverFactory as SolverFactory + +class GDP_RIC_Solver(_GDPoptAlgorithm, _OAAlgorithmMixIn): + CONFIG: Incomplete + algorithm: str + def solve(self, model, **kwds): ... diff --git a/stubs/pyomo/contrib/gdpopt/solve_discrete_problem.pyi b/stubs/pyomo/contrib/gdpopt/solve_discrete_problem.pyi new file mode 100644 index 000000000..8750ca409 --- /dev/null +++ b/stubs/pyomo/contrib/gdpopt/solve_discrete_problem.pyi @@ -0,0 +1,13 @@ +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.common.errors import InfeasibleConstraintException as InfeasibleConstraintException +from pyomo.contrib.fbbt.fbbt import fbbt as fbbt +from pyomo.contrib.gdpopt.util import SuppressInfeasibleWarning as SuppressInfeasibleWarning +from pyomo.contrib.gdpopt.util import get_main_elapsed_time as get_main_elapsed_time +from pyomo.core import Constraint as Constraint +from pyomo.core import Objective as Objective +from pyomo.opt import SolutionStatus as SolutionStatus +from pyomo.opt import SolverFactory as SolverFactory +from pyomo.solvers.plugins.solvers.persistent_solver import PersistentSolver as PersistentSolver + +def solve_MILP_discrete_problem(util_block, solver, config): ... +def distinguish_mip_infeasible_or_unbounded(m, config): ... diff --git a/stubs/pyomo/contrib/gdpopt/solve_subproblem.pyi b/stubs/pyomo/contrib/gdpopt/solve_subproblem.pyi new file mode 100644 index 000000000..c0b64a891 --- /dev/null +++ b/stubs/pyomo/contrib/gdpopt/solve_subproblem.pyi @@ -0,0 +1,49 @@ +import types + +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.errors import DeveloperError as DeveloperError +from pyomo.common.errors import InfeasibleConstraintException as InfeasibleConstraintException +from pyomo.contrib import appsi as appsi +from pyomo.contrib.appsi.cmodel import cmodel_available as cmodel_available +from pyomo.contrib.fbbt.fbbt import fbbt as fbbt +from pyomo.contrib.gdpopt.solve_discrete_problem import ( + distinguish_mip_infeasible_or_unbounded as distinguish_mip_infeasible_or_unbounded, +) +from pyomo.contrib.gdpopt.util import SuppressInfeasibleWarning as SuppressInfeasibleWarning +from pyomo.contrib.gdpopt.util import get_main_elapsed_time as get_main_elapsed_time +from pyomo.contrib.gdpopt.util import is_feasible as is_feasible +from pyomo.core import Block as Block +from pyomo.core import Constraint as Constraint +from pyomo.core import Objective as Objective +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.opt import SolverFactory as SolverFactory +from pyomo.opt import SolverResults as SolverResults + +def configure_and_call_solver(model, solver, args, problem_type, timing, time_limit): ... +def process_nonlinear_problem_results(results, model, problem_type, config): ... +def solve_linear_subproblem(subproblem, config, timing): ... +def solve_NLP(nlp_model, config, timing): ... +def solve_MINLP(util_block, config, timing): ... +def detect_unfixed_discrete_vars(model): ... + +class preprocess_subproblem: + util_block: Incomplete + config: Incomplete + not_infeas: bool + unfixed_vars: Incomplete + original_bounds: Incomplete + constraints_deactivated: Incomplete + constraints_modified: Incomplete + def __init__(self, util_block, config) -> None: ... + def __enter__(self): ... + def __exit__( + self, + type: type[BaseException] | None, + value: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: ... + +def call_appropriate_subproblem_solver(subprob_util_block, solver, config): ... +def solve_subproblem(subprob_util_block, solver, config): ... diff --git a/stubs/pyomo/contrib/gdpopt/util.pyi b/stubs/pyomo/contrib/gdpopt/util.pyi new file mode 100644 index 000000000..e0447c3ab --- /dev/null +++ b/stubs/pyomo/contrib/gdpopt/util.pyi @@ -0,0 +1,94 @@ +import logging +import types +from collections.abc import Generator +from contextlib import contextmanager + +from _typeshed import Incomplete +from pyomo.common import timing as timing +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.contrib.fbbt.fbbt import compute_bounds_on_expr as compute_bounds_on_expr +from pyomo.contrib.mcpp.pyomo_mcpp import McCormick as McCormick +from pyomo.contrib.mcpp.pyomo_mcpp import mcpp_available as mcpp_available +from pyomo.core import Block as Block +from pyomo.core import Constraint as Constraint +from pyomo.core import Objective as Objective +from pyomo.core import Reals as Reals +from pyomo.core import Reference as Reference +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core import Var as Var +from pyomo.core import minimize as minimize +from pyomo.core import value as value +from pyomo.core.expr.numvalue import native_types as native_types +from pyomo.gdp import Disjunct as Disjunct +from pyomo.gdp import Disjunction as Disjunction +from pyomo.opt import SolverFactory as SolverFactory + +class _DoNothing: + def __init__(self, *args, **kwargs) -> None: ... + def __call__(self, *args, **kwargs) -> None: ... + def __getattr__(self, attr): ... + +class SuppressInfeasibleWarning: + class InfeasibleWarningFilter(logging.Filter): + def filter(self, record): ... + + warning_filter: Incomplete + def __enter__(self): ... + def __exit__( + self, + exception_type: type[BaseException] | None, + exception_value: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: ... + +def solve_continuous_problem(m, config): ... +def move_nonlinear_objective_to_constraints(util_block, logger): ... +def a_logger(str_or_logger): ... +def copy_var_list_values( + from_list, + to_list, + config, + skip_stale: bool = False, + skip_fixed: bool = True, + ignore_integrality: bool = False, +) -> None: ... +def fix_discrete_var(var, val, config) -> None: ... + +class fix_discrete_solution_in_subproblem: + True_disjuncts: Incomplete + boolean_var_values: Incomplete + discrete_var_values: Incomplete + subprob_util_block: Incomplete + config: Incomplete + def __init__( + self, + true_disjuncts, + boolean_var_values, + integer_var_values, + subprob_util_block, + config, + solver, + ) -> None: ... + def __enter__(self): ... + def __exit__( + self, + type: type[BaseException] | None, + value: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: ... + +class fix_discrete_problem_solution_in_subproblem(fix_discrete_solution_in_subproblem): + discrete_prob_util_block: Incomplete + subprob_util_block: Incomplete + solver: Incomplete + config: Incomplete + def __init__(self, discrete_prob_util_block, subproblem_util_block, solver, config) -> None: ... + def __enter__(self): ... + +def is_feasible(model, config): ... +@contextmanager +def time_code(timing_data_obj, code_block_name, is_main_timer: bool = False) -> Generator[None]: ... +def get_main_elapsed_time(timing_data_obj): ... +@contextmanager +def lower_logger_level_to(logger, level=None, tee: bool = False) -> Generator[None]: ... diff --git a/stubs/pyomo/contrib/gjh/GJH.pyi b/stubs/pyomo/contrib/gjh/GJH.pyi new file mode 100644 index 000000000..074fedb0e --- /dev/null +++ b/stubs/pyomo/contrib/gjh/GJH.pyi @@ -0,0 +1,10 @@ +from _typeshed import Incomplete +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.solvers.plugins.solvers.ASL import ASL as ASL + +logger: Incomplete + +def readgjh(fname=None): ... + +class GJHSolver(ASL): + def __init__(self, **kwds) -> None: ... diff --git a/stubs/pyomo/contrib/gjh/__init__.pyi b/stubs/pyomo/contrib/gjh/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/gjh/getGJH.pyi b/stubs/pyomo/contrib/gjh/getGJH.pyi new file mode 100644 index 000000000..4bcd06f03 --- /dev/null +++ b/stubs/pyomo/contrib/gjh/getGJH.pyi @@ -0,0 +1,9 @@ +from _typeshed import Incomplete +from pyomo.common.download import FileDownloader as FileDownloader + +logger: Incomplete +urlmap: Incomplete +exemap: Incomplete + +def get_gjh(downloader) -> None: ... +def main(argv) -> None: ... diff --git a/stubs/pyomo/contrib/gjh/plugins.pyi b/stubs/pyomo/contrib/gjh/plugins.pyi new file mode 100644 index 000000000..5eac6f1e5 --- /dev/null +++ b/stubs/pyomo/contrib/gjh/plugins.pyi @@ -0,0 +1,6 @@ +from pyomo.common.download import DownloadFactory as DownloadFactory +from pyomo.contrib.gjh.getGJH import get_gjh as get_gjh +from pyomo.contrib.gjh.GJH import GJHSolver as GJHSolver +from pyomo.opt.base import SolverFactory as SolverFactory + +def load() -> None: ... diff --git a/stubs/pyomo/contrib/iis/__init__.pyi b/stubs/pyomo/contrib/iis/__init__.pyi new file mode 100644 index 000000000..e8c8838e2 --- /dev/null +++ b/stubs/pyomo/contrib/iis/__init__.pyi @@ -0,0 +1,4 @@ +from pyomo.contrib.iis.iis import write_iis as write_iis +from pyomo.contrib.iis.mis import ( + compute_infeasibility_explanation as compute_infeasibility_explanation, +) diff --git a/stubs/pyomo/contrib/iis/iis.pyi b/stubs/pyomo/contrib/iis/iis.pyi new file mode 100644 index 000000000..562a7a2ed --- /dev/null +++ b/stubs/pyomo/contrib/iis/iis.pyi @@ -0,0 +1,29 @@ +import abc + +from _typeshed import Incomplete +from pyomo.environ import SolverFactory as SolverFactory + +logger: Incomplete + +def write_iis(pyomo_model, iis_file_name, solver=None, logger=...): ... + +class _IISBase(abc.ABC, metaclass=abc.ABCMeta): + def __init__(self, solver) -> None: ... + @abc.abstractmethod + def compute(self): ... + @abc.abstractmethod + def write(self, file_name): ... + +class CplexConflict(_IISBase): + def compute(self) -> None: ... + def write(self, file_name): ... + +class GurobiIIS(_IISBase): + def compute(self) -> None: ... + def write(self, file_name): ... + +class XpressIIS(_IISBase): + def compute(self) -> None: ... + def write(self, file_name): ... + +def IISFactory(solver): ... diff --git a/stubs/pyomo/contrib/iis/mis.pyi b/stubs/pyomo/contrib/iis/mis.pyi new file mode 100644 index 000000000..71e394513 --- /dev/null +++ b/stubs/pyomo/contrib/iis/mis.pyi @@ -0,0 +1,17 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.core.plugins.transform.add_slack_vars import AddSlackVariables as AddSlackVariables +from pyomo.core.plugins.transform.hierarchy import ( + IsomorphicTransformation as IsomorphicTransformation, +) +from pyomo.opt import WriterFactory as WriterFactory + +logger: Incomplete + +class _VariableBoundsAsConstraints(IsomorphicTransformation): ... + +def compute_infeasibility_explanation( + model, solver, tee: bool = False, tolerance: float = 1e-08, logger=... +): ... diff --git a/stubs/pyomo/contrib/incidence_analysis/__init__.pyi b/stubs/pyomo/contrib/incidence_analysis/__init__.pyi new file mode 100644 index 000000000..91f5447f7 --- /dev/null +++ b/stubs/pyomo/contrib/incidence_analysis/__init__.pyi @@ -0,0 +1,12 @@ +from pyomo.common.deprecation import moved_module as moved_module + +from .config import IncidenceMethod as IncidenceMethod +from .incidence import get_incident_variables as get_incident_variables +from .interface import IncidenceGraphInterface as IncidenceGraphInterface +from .interface import get_bipartite_incidence_graph as get_bipartite_incidence_graph +from .matching import maximum_matching as maximum_matching +from .scc_solver import ( + generate_strongly_connected_components as generate_strongly_connected_components, +) +from .scc_solver import solve_strongly_connected_components as solve_strongly_connected_components +from .triangularize import block_triangularize as block_triangularize diff --git a/stubs/pyomo/contrib/incidence_analysis/common/__init__.pyi b/stubs/pyomo/contrib/incidence_analysis/common/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/incidence_analysis/common/dulmage_mendelsohn.pyi b/stubs/pyomo/contrib/incidence_analysis/common/dulmage_mendelsohn.pyi new file mode 100644 index 000000000..93c82bee6 --- /dev/null +++ b/stubs/pyomo/contrib/incidence_analysis/common/dulmage_mendelsohn.pyi @@ -0,0 +1,4 @@ +from networkx.algorithms.components import connected_components as connected_components +from pyomo.common.dependencies import networkx_available as networkx_available + +def dulmage_mendelsohn(bg, top_nodes=None, matching=None): ... diff --git a/stubs/pyomo/contrib/incidence_analysis/config.pyi b/stubs/pyomo/contrib/incidence_analysis/config.pyi new file mode 100644 index 000000000..5d38819a0 --- /dev/null +++ b/stubs/pyomo/contrib/incidence_analysis/config.pyi @@ -0,0 +1,24 @@ +import enum + +from _typeshed import Incomplete +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import InEnum as InEnum +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.repn.ampl import AMPLRepnVisitor as AMPLRepnVisitor +from pyomo.repn.util import FileDeterminism as FileDeterminism +from pyomo.repn.util import FileDeterminism_to_SortComponents as FileDeterminism_to_SortComponents + +class IncidenceMethod(enum.Enum): + identify_variables = 0 + standard_repn = 1 + standard_repn_compute_values = 2 + ampl_repn = 3 + +class IncidenceOrder(enum.Enum): + dulmage_mendelsohn_upper = 0 + dulmage_mendelsohn_lower = 1 + +IncidenceConfig: Incomplete + +def get_config_from_kwds(**kwds): ... diff --git a/stubs/pyomo/contrib/incidence_analysis/connected.pyi b/stubs/pyomo/contrib/incidence_analysis/connected.pyi new file mode 100644 index 000000000..bbc09e619 --- /dev/null +++ b/stubs/pyomo/contrib/incidence_analysis/connected.pyi @@ -0,0 +1 @@ +def get_independent_submatrices(matrix): ... diff --git a/stubs/pyomo/contrib/incidence_analysis/dulmage_mendelsohn.pyi b/stubs/pyomo/contrib/incidence_analysis/dulmage_mendelsohn.pyi new file mode 100644 index 000000000..90a6c003a --- /dev/null +++ b/stubs/pyomo/contrib/incidence_analysis/dulmage_mendelsohn.pyi @@ -0,0 +1,17 @@ +from typing import NamedTuple + +from _typeshed import Incomplete + +class RowPartition(NamedTuple): + unmatched: Incomplete + overconstrained: Incomplete + underconstrained: Incomplete + square: Incomplete + +class ColPartition(NamedTuple): + unmatched: Incomplete + underconstrained: Incomplete + overconstrained: Incomplete + square: Incomplete + +def dulmage_mendelsohn(matrix_or_graph, top_nodes=None, matching=None): ... diff --git a/stubs/pyomo/contrib/incidence_analysis/incidence.pyi b/stubs/pyomo/contrib/incidence_analysis/incidence.pyi new file mode 100644 index 000000000..994cbce3d --- /dev/null +++ b/stubs/pyomo/contrib/incidence_analysis/incidence.pyi @@ -0,0 +1,7 @@ +from pyomo.contrib.incidence_analysis.config import IncidenceMethod as IncidenceMethod +from pyomo.contrib.incidence_analysis.config import get_config_from_kwds as get_config_from_kwds +from pyomo.core.expr.visitor import identify_variables as identify_variables +from pyomo.repn import generate_standard_repn as generate_standard_repn +from pyomo.util.subsystems import TemporarySubsystemManager as TemporarySubsystemManager + +def get_incident_variables(expr, **kwds): ... diff --git a/stubs/pyomo/contrib/incidence_analysis/interface.pyi b/stubs/pyomo/contrib/incidence_analysis/interface.pyi new file mode 100644 index 000000000..7bfe49c68 --- /dev/null +++ b/stubs/pyomo/contrib/incidence_analysis/interface.pyi @@ -0,0 +1,82 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.dependencies import plotly as plotly +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.contrib.incidence_analysis.config import get_config_from_kwds as get_config_from_kwds +from pyomo.contrib.incidence_analysis.connected import ( + get_independent_submatrices as get_independent_submatrices, +) +from pyomo.contrib.incidence_analysis.dulmage_mendelsohn import ColPartition as ColPartition +from pyomo.contrib.incidence_analysis.dulmage_mendelsohn import RowPartition as RowPartition +from pyomo.contrib.incidence_analysis.dulmage_mendelsohn import ( + dulmage_mendelsohn as dulmage_mendelsohn, +) +from pyomo.contrib.incidence_analysis.incidence import ( + get_incident_variables as get_incident_variables, +) +from pyomo.contrib.incidence_analysis.matching import maximum_matching as maximum_matching +from pyomo.contrib.incidence_analysis.triangularize import ( + block_triangularize as block_triangularize, +) +from pyomo.contrib.incidence_analysis.triangularize import ( + get_blocks_from_maps as get_blocks_from_maps, +) +from pyomo.contrib.incidence_analysis.triangularize import ( + get_diagonal_blocks as get_diagonal_blocks, +) +from pyomo.contrib.incidence_analysis.triangularize import ( + get_scc_of_projection as get_scc_of_projection, +) +from pyomo.contrib.pynumero.asl import AmplInterface as AmplInterface +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.constraint import Constraint as Constraint +from pyomo.core.base.objective import Objective as Objective +from pyomo.core.base.var import Var as Var +from pyomo.core.expr import EqualityExpression as EqualityExpression +from pyomo.util.subsystems import create_subsystem_block as create_subsystem_block + +pyomo_nlp: Incomplete +pyomo_nlp_available: Incomplete +asl_available: Incomplete + +def get_incidence_graph(variables, constraints, **kwds): ... +def get_bipartite_incidence_graph(variables, constraints, **kwds): ... +def extract_bipartite_subgraph(graph, nodes0, nodes1): ... +def get_structural_incidence_matrix(variables, constraints, **kwds): ... +def get_numeric_incidence_matrix(variables, constraints): ... + +class IncidenceGraphInterface: + def __init__( + self, model=None, active: bool = True, include_inequality: bool = True, **kwds + ) -> None: ... + @property + def variables(self): ... + @property + def constraints(self): ... + @property + def n_edges(self): ... + @property + def var_index_map(self): ... + @property + def con_index_map(self): ... + @property + def row_block_map(self) -> None: ... + @property + def col_block_map(self) -> None: ... + def get_matrix_coord(self, component): ... + def subgraph(self, variables, constraints): ... + @property + def incidence_matrix(self): ... + def get_adjacent_to(self, component): ... + def maximum_matching(self, variables=None, constraints=None): ... + def get_connected_components(self, variables=None, constraints=None): ... + def map_nodes_to_block_triangular_indices(self, variables=None, constraints=None): ... + def block_triangularize(self, variables=None, constraints=None): ... + def get_diagonal_blocks(self, variables=None, constraints=None): ... + def dulmage_mendelsohn(self, variables=None, constraints=None): ... + def remove_nodes(self, variables=None, constraints=None) -> None: ... + def plot(self, variables=None, constraints=None, title=None, show: bool = True) -> None: ... + def add_edge(self, variable, constraint) -> None: ... diff --git a/stubs/pyomo/contrib/incidence_analysis/matching.pyi b/stubs/pyomo/contrib/incidence_analysis/matching.pyi new file mode 100644 index 000000000..710346d58 --- /dev/null +++ b/stubs/pyomo/contrib/incidence_analysis/matching.pyi @@ -0,0 +1 @@ +def maximum_matching(matrix_or_graph, top_nodes=None): ... diff --git a/stubs/pyomo/contrib/incidence_analysis/scc_solver.pyi b/stubs/pyomo/contrib/incidence_analysis/scc_solver.pyi new file mode 100644 index 000000000..aaab51438 --- /dev/null +++ b/stubs/pyomo/contrib/incidence_analysis/scc_solver.pyi @@ -0,0 +1,20 @@ +from collections.abc import Generator + +from _typeshed import Incomplete +from pyomo.contrib.incidence_analysis.config import IncidenceMethod as IncidenceMethod +from pyomo.contrib.incidence_analysis.interface import ( + IncidenceGraphInterface as IncidenceGraphInterface, +) +from pyomo.core.base.constraint import Constraint as Constraint +from pyomo.util.calc_var_value import ( + calculate_variable_from_constraint as calculate_variable_from_constraint, +) +from pyomo.util.subsystems import TemporarySubsystemManager as TemporarySubsystemManager +from pyomo.util.subsystems import generate_subsystem_blocks as generate_subsystem_blocks + +def generate_strongly_connected_components( + constraints, variables=None, include_fixed: bool = False, igraph=None +) -> Generator[Incomplete]: ... +def solve_strongly_connected_components( + block, *, solver=None, solve_kwds=None, use_calc_var: bool = True, calc_var_kwds=None +): ... diff --git a/stubs/pyomo/contrib/incidence_analysis/triangularize.pyi b/stubs/pyomo/contrib/incidence_analysis/triangularize.pyi new file mode 100644 index 000000000..93286b9c5 --- /dev/null +++ b/stubs/pyomo/contrib/incidence_analysis/triangularize.pyi @@ -0,0 +1,8 @@ +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.contrib.incidence_analysis.matching import maximum_matching as maximum_matching + +def get_scc_of_projection(graph, top_nodes, matching=None): ... +def block_triangularize(matrix, matching=None): ... +def map_coords_to_block_triangular_indices(matrix, matching=None): ... +def get_blocks_from_maps(row_block_map, col_block_map): ... +def get_diagonal_blocks(matrix, matching=None): ... diff --git a/stubs/pyomo/contrib/incidence_analysis/visualize.pyi b/stubs/pyomo/contrib/incidence_analysis/visualize.pyi new file mode 100644 index 000000000..f0f295bca --- /dev/null +++ b/stubs/pyomo/contrib/incidence_analysis/visualize.pyi @@ -0,0 +1,21 @@ +from pyomo.common.dependencies import matplotlib as matplotlib +from pyomo.contrib.incidence_analysis.config import IncidenceOrder as IncidenceOrder +from pyomo.contrib.incidence_analysis.interface import ( + IncidenceGraphInterface as IncidenceGraphInterface, +) +from pyomo.contrib.incidence_analysis.interface import ( + get_structural_incidence_matrix as get_structural_incidence_matrix, +) + +def spy_dulmage_mendelsohn( + model, + *, + incidence_kwds=None, + order=..., + highlight_coarse: bool = True, + highlight_fine: bool = True, + skip_wellconstrained: bool = False, + ax=None, + linewidth: int = 2, + spy_kwds=None, +): ... diff --git a/stubs/pyomo/contrib/interior_point/__init__.pyi b/stubs/pyomo/contrib/interior_point/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/interior_point/examples/__init__.pyi b/stubs/pyomo/contrib/interior_point/examples/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/interior_point/examples/ex1.pyi b/stubs/pyomo/contrib/interior_point/examples/ex1.pyi new file mode 100644 index 000000000..78e999cb9 --- /dev/null +++ b/stubs/pyomo/contrib/interior_point/examples/ex1.pyi @@ -0,0 +1,5 @@ +from pyomo.contrib.interior_point.interface import InteriorPointInterface as InteriorPointInterface +from pyomo.contrib.interior_point.interior_point import InteriorPointSolver as InteriorPointSolver +from pyomo.contrib.interior_point.linalg.mumps_interface import MumpsInterface as MumpsInterface + +def solve_qcqp_example() -> None: ... diff --git a/stubs/pyomo/contrib/interior_point/interface.pyi b/stubs/pyomo/contrib/interior_point/interface.pyi new file mode 100644 index 000000000..79624d59c --- /dev/null +++ b/stubs/pyomo/contrib/interior_point/interface.pyi @@ -0,0 +1,187 @@ +from abc import ABCMeta, abstractmethod + +from pyomo.common.timing import HierarchicalTimer as HierarchicalTimer +from pyomo.contrib.pynumero.interfaces import ampl_nlp as ampl_nlp +from pyomo.contrib.pynumero.interfaces import pyomo_nlp as pyomo_nlp +from pyomo.contrib.pynumero.sparse import BlockMatrix as BlockMatrix +from pyomo.contrib.pynumero.sparse import BlockVector as BlockVector + +class BaseInteriorPointInterface(metaclass=ABCMeta): + @abstractmethod + def n_primals(self): ... + @abstractmethod + def nnz_hessian_lag(self): ... + @abstractmethod + def primals_lb(self): ... + @abstractmethod + def primals_ub(self): ... + @abstractmethod + def init_primals(self): ... + @abstractmethod + def set_primals(self, primals): ... + @abstractmethod + def get_primals(self): ... + @abstractmethod + def get_obj_factor(self): ... + @abstractmethod + def set_obj_factor(self, obj_factor): ... + @abstractmethod + def evaluate_objective(self): ... + @abstractmethod + def evaluate_grad_objective(self): ... + @abstractmethod + def n_eq_constraints(self): ... + @abstractmethod + def n_ineq_constraints(self): ... + @abstractmethod + def nnz_jacobian_eq(self): ... + @abstractmethod + def nnz_jacobian_ineq(self): ... + @abstractmethod + def ineq_lb(self): ... + @abstractmethod + def ineq_ub(self): ... + @abstractmethod + def init_duals_eq(self): ... + @abstractmethod + def init_duals_ineq(self): ... + @abstractmethod + def set_duals_eq(self, duals_eq): ... + @abstractmethod + def set_duals_ineq(self, duals_ineq): ... + @abstractmethod + def get_duals_eq(self): ... + @abstractmethod + def get_duals_ineq(self): ... + @abstractmethod + def evaluate_eq_constraints(self): ... + @abstractmethod + def evaluate_ineq_constraints(self): ... + @abstractmethod + def evaluate_jacobian_eq(self): ... + @abstractmethod + def evaluate_jacobian_ineq(self): ... + @abstractmethod + def init_slacks(self): ... + @abstractmethod + def init_duals_primals_lb(self): ... + @abstractmethod + def init_duals_primals_ub(self): ... + @abstractmethod + def init_duals_slacks_lb(self): ... + @abstractmethod + def init_duals_slacks_ub(self): ... + @abstractmethod + def set_slacks(self, slacks): ... + @abstractmethod + def set_duals_primals_lb(self, duals): ... + @abstractmethod + def set_duals_primals_ub(self, duals): ... + @abstractmethod + def set_duals_slacks_lb(self, duals): ... + @abstractmethod + def set_duals_slacks_ub(self, duals): ... + @abstractmethod + def get_slacks(self): ... + @abstractmethod + def get_duals_primals_lb(self): ... + @abstractmethod + def get_duals_primals_ub(self): ... + @abstractmethod + def get_duals_slacks_lb(self): ... + @abstractmethod + def get_duals_slacks_ub(self): ... + @abstractmethod + def set_barrier_parameter(self, barrier): ... + @abstractmethod + def evaluate_primal_dual_kkt_matrix(self, timer=None): ... + @abstractmethod + def evaluate_primal_dual_kkt_rhs(self, timer=None): ... + @abstractmethod + def set_primal_dual_kkt_solution(self, sol): ... + @abstractmethod + def get_delta_primals(self): ... + @abstractmethod + def get_delta_slacks(self): ... + @abstractmethod + def get_delta_duals_eq(self): ... + @abstractmethod + def get_delta_duals_ineq(self): ... + @abstractmethod + def get_delta_duals_primals_lb(self): ... + @abstractmethod + def get_delta_duals_primals_ub(self): ... + @abstractmethod + def get_delta_duals_slacks_lb(self): ... + @abstractmethod + def get_delta_duals_slacks_ub(self): ... + def regularize_equality_gradient(self, kkt, coef, copy_kkt: bool = True) -> None: ... + def regularize_hessian(self, kkt, coef, copy_kkt: bool = True) -> None: ... + +class InteriorPointInterface(BaseInteriorPointInterface): + def __init__(self, pyomo_model) -> None: ... + def n_primals(self): ... + def nnz_hessian_lag(self): ... + def set_obj_factor(self, obj_factor) -> None: ... + def get_obj_factor(self): ... + def n_eq_constraints(self): ... + def n_ineq_constraints(self): ... + def nnz_jacobian_eq(self): ... + def nnz_jacobian_ineq(self): ... + def init_primals(self): ... + def init_slacks(self): ... + def init_duals_eq(self): ... + def init_duals_ineq(self): ... + def init_duals_primals_lb(self): ... + def init_duals_primals_ub(self): ... + def init_duals_slacks_lb(self): ... + def init_duals_slacks_ub(self): ... + def set_primals(self, primals) -> None: ... + def set_slacks(self, slacks) -> None: ... + def set_duals_eq(self, duals) -> None: ... + def set_duals_ineq(self, duals) -> None: ... + def set_duals_primals_lb(self, duals) -> None: ... + def set_duals_primals_ub(self, duals) -> None: ... + def set_duals_slacks_lb(self, duals) -> None: ... + def set_duals_slacks_ub(self, duals) -> None: ... + def get_primals(self): ... + def get_slacks(self): ... + def get_duals_eq(self): ... + def get_duals_ineq(self): ... + def get_duals_primals_lb(self): ... + def get_duals_primals_ub(self): ... + def get_duals_slacks_lb(self): ... + def get_duals_slacks_ub(self): ... + def primals_lb(self): ... + def primals_ub(self): ... + def ineq_lb(self): ... + def ineq_ub(self): ... + def set_barrier_parameter(self, barrier) -> None: ... + def pyomo_nlp(self): ... + def evaluate_primal_dual_kkt_matrix(self, timer=None): ... + def evaluate_primal_dual_kkt_rhs(self, timer=None): ... + def set_primal_dual_kkt_solution(self, sol) -> None: ... + def get_delta_primals(self): ... + def get_delta_slacks(self): ... + def get_delta_duals_eq(self): ... + def get_delta_duals_ineq(self): ... + def get_delta_duals_primals_lb(self): ... + def get_delta_duals_primals_ub(self): ... + def get_delta_duals_slacks_lb(self): ... + def get_delta_duals_slacks_ub(self): ... + def evaluate_objective(self): ... + def evaluate_eq_constraints(self): ... + def evaluate_ineq_constraints(self): ... + def evaluate_grad_objective(self): ... + def evaluate_jacobian_eq(self): ... + def evaluate_jacobian_ineq(self): ... + def regularize_equality_gradient(self, kkt, coef, copy_kkt: bool = True): ... + def regularize_hessian(self, kkt, coef, copy_kkt: bool = True): ... + def load_primals_into_pyomo_model(self) -> None: ... + def pyomo_model(self): ... + def get_pyomo_variables(self): ... + def get_pyomo_constraints(self): ... + def variable_names(self): ... + def constraint_names(self): ... + def get_primal_indices(self, pyomo_variables): ... + def get_constraint_indices(self, pyomo_constraints): ... diff --git a/stubs/pyomo/contrib/interior_point/interior_point.pyi b/stubs/pyomo/contrib/interior_point/interior_point.pyi new file mode 100644 index 000000000..8a95790a4 --- /dev/null +++ b/stubs/pyomo/contrib/interior_point/interior_point.pyi @@ -0,0 +1,89 @@ +import enum +import types + +from _typeshed import Incomplete +from pyomo.common.timing import HierarchicalTimer as HierarchicalTimer +from pyomo.contrib.pynumero.interfaces.utils import build_bounds_mask as build_bounds_mask +from pyomo.contrib.pynumero.interfaces.utils import ( + build_compression_matrix as build_compression_matrix, +) +from pyomo.contrib.pynumero.linalg.base import LinearSolverStatus as LinearSolverStatus + +ip_logger: Incomplete + +class InteriorPointStatus(enum.Enum): + optimal = 0 + error = 1 + +class LinearSolveContext: + interior_point_logger: Incomplete + linear_solver_logger: Incomplete + filename: Incomplete + handler: Incomplete + def __init__( + self, interior_point_logger, linear_solver_logger, filename=None, level=... + ) -> None: ... + def __enter__(self) -> None: ... + def __exit__( + self, + et: type[BaseException] | None, + ev: BaseException | None, + tb: types.TracebackType | None, + ) -> None: ... + +class FactorizationContext: + logger: Incomplete + def __init__(self, logger) -> None: ... + def __enter__(self): ... + def __exit__( + self, + et: type[BaseException] | None, + ev: BaseException | None, + tb: types.TracebackType | None, + ) -> None: ... + def log_header(self) -> None: ... + def log_info(self, _iter, reg_iter, num_realloc, coef, neg_eig, status) -> None: ... + +class InteriorPointSolver: + linear_solver: Incomplete + max_iter: Incomplete + tol: Incomplete + linear_solver_log_filename: Incomplete + max_reallocation_iterations: Incomplete + reallocation_factor: Incomplete + base_eq_reg_coef: float + hess_reg_coef: float + max_reg_iter: int + reg_factor_increase: int + logger: Incomplete + factorization_context: Incomplete + linear_solver_logger: Incomplete + linear_solve_context: Incomplete + def __init__( + self, + linear_solver, + max_iter: int = 100, + tol: float = 1e-08, + linear_solver_log_filename=None, + max_reallocation_iterations: int = 5, + reallocation_factor: int = 2, + ) -> None: ... + def update_barrier_parameter(self) -> None: ... + def set_linear_solver(self, linear_solver) -> None: ... + interface: Incomplete + def set_interface(self, interface) -> None: ... + def solve(self, interface, timer=None, report_timing: bool = False): ... + def factorize(self, kkt, timer=None): ... + def process_init(self, x, lb, ub) -> None: ... + def process_init_duals_lb(self, x, lb) -> None: ... + def process_init_duals_ub(self, x, ub) -> None: ... + def check_convergence(self, barrier, timer=None): ... + def fraction_to_the_boundary(self): ... + +def try_factorization_and_reallocation( + kkt, linear_solver, reallocation_factor, max_iter, timer=None +): ... +def fraction_to_the_boundary(interface, tau): ... +def process_init(x, lb, ub) -> None: ... +def process_init_duals_lb(x, lb) -> None: ... +def process_init_duals_ub(x, ub) -> None: ... diff --git a/stubs/pyomo/contrib/interior_point/inverse_reduced_hessian.pyi b/stubs/pyomo/contrib/interior_point/inverse_reduced_hessian.pyi new file mode 100644 index 000000000..acca9fa74 --- /dev/null +++ b/stubs/pyomo/contrib/interior_point/inverse_reduced_hessian.pyi @@ -0,0 +1,17 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.opt import check_optimal_termination as check_optimal_termination + +from .interface import InteriorPointInterface as InteriorPointInterface +from .linalg.scipy_interface import ScipyInterface as ScipyInterface + +np: Incomplete +numpy_available: Incomplete + +def inv_reduced_hessian_barrier( + model, + independent_variables, + bound_tolerance: float = 1e-06, + solver_options=None, + tee: bool = False, +): ... diff --git a/stubs/pyomo/contrib/interior_point/linalg/__init__.pyi b/stubs/pyomo/contrib/interior_point/linalg/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/interior_point/linalg/base_linear_solver_interface.pyi b/stubs/pyomo/contrib/interior_point/linalg/base_linear_solver_interface.pyi new file mode 100644 index 000000000..d7fc6197f --- /dev/null +++ b/stubs/pyomo/contrib/interior_point/linalg/base_linear_solver_interface.pyi @@ -0,0 +1,14 @@ +from abc import ABCMeta, abstractmethod + +from pyomo.contrib.pynumero.linalg.base import ( + DirectLinearSolverInterface as DirectLinearSolverInterface, +) + +class IPLinearSolverInterface(DirectLinearSolverInterface, metaclass=ABCMeta): + @classmethod + def getLoggerName(cls): ... + @classmethod + def getLogger(cls): ... + def increase_memory_allocation(self, factor) -> None: ... + @abstractmethod + def get_inertia(self): ... diff --git a/stubs/pyomo/contrib/interior_point/linalg/ma27_interface.pyi b/stubs/pyomo/contrib/interior_point/linalg/ma27_interface.pyi new file mode 100644 index 000000000..c5e2b8c5d --- /dev/null +++ b/stubs/pyomo/contrib/interior_point/linalg/ma27_interface.pyi @@ -0,0 +1,24 @@ +from pyomo.contrib.pynumero.linalg.base import LinearSolverResults as LinearSolverResults +from pyomo.contrib.pynumero.linalg.base import LinearSolverStatus as LinearSolverStatus +from pyomo.contrib.pynumero.linalg.ma27_interface import MA27 as MA27 +from pyomo.contrib.pynumero.sparse import BlockMatrix as BlockMatrix +from pyomo.contrib.pynumero.sparse import BlockVector as BlockVector +from scipy.sparse import isspmatrix_coo as isspmatrix_coo +from scipy.sparse import spmatrix as spmatrix +from scipy.sparse import tril as tril + +from .base_linear_solver_interface import IPLinearSolverInterface as IPLinearSolverInterface + +class InteriorPointMA27Interface(MA27, IPLinearSolverInterface): + @classmethod + def getLoggerName(cls): ... + def __init__( + self, cntl_options=None, icntl_options=None, iw_factor: float = 1.2, a_factor: int = 2 + ) -> None: ... + def do_symbolic_factorization( + self, matrix: spmatrix | BlockMatrix, raise_on_error: bool = True + ) -> LinearSolverResults: ... + def do_numeric_factorization( + self, matrix: spmatrix | BlockMatrix, raise_on_error: bool = True + ) -> LinearSolverResults: ... + def get_inertia(self): ... diff --git a/stubs/pyomo/contrib/interior_point/linalg/mumps_interface.pyi b/stubs/pyomo/contrib/interior_point/linalg/mumps_interface.pyi new file mode 100644 index 000000000..283d404bb --- /dev/null +++ b/stubs/pyomo/contrib/interior_point/linalg/mumps_interface.pyi @@ -0,0 +1,29 @@ +import numpy as np +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.contrib.pynumero.linalg.base import LinearSolverResults as LinearSolverResults +from pyomo.contrib.pynumero.linalg.base import LinearSolverStatus as LinearSolverStatus +from pyomo.contrib.pynumero.linalg.mumps_interface import ( + MumpsCentralizedAssembledLinearSolver as MumpsCentralizedAssembledLinearSolver, +) +from pyomo.contrib.pynumero.sparse import BlockVector as BlockVector + +from .base_linear_solver_interface import IPLinearSolverInterface as IPLinearSolverInterface + +mumps: Incomplete +mumps_available: Incomplete + +class MumpsInterface(MumpsCentralizedAssembledLinearSolver, IPLinearSolverInterface): + @classmethod + def getLoggerName(cls): ... + error_level: Incomplete + log_error: Incomplete + logger: Incomplete + def __init__(self, par: int = 1, comm=None, cntl_options=None, icntl_options=None) -> None: ... + def do_back_solve( + self, rhs: np.ndarray | BlockVector, raise_on_error: bool = True + ) -> tuple[np.ndarray | BlockVector | None, LinearSolverResults]: ... + def get_inertia(self): ... + def get_error_info(self): ... + def log_header(self, include_error: bool = True, extra_fields=None) -> None: ... + def log_info(self) -> None: ... diff --git a/stubs/pyomo/contrib/interior_point/linalg/scipy_interface.pyi b/stubs/pyomo/contrib/interior_point/linalg/scipy_interface.pyi new file mode 100644 index 000000000..f5ce6fde5 --- /dev/null +++ b/stubs/pyomo/contrib/interior_point/linalg/scipy_interface.pyi @@ -0,0 +1,18 @@ +from _typeshed import Incomplete +from pyomo.contrib.pynumero.linalg.base import LinearSolverResults as LinearSolverResults +from pyomo.contrib.pynumero.linalg.scipy_interface import ScipyLU as ScipyLU +from pyomo.contrib.pynumero.sparse import BlockMatrix as BlockMatrix +from scipy.sparse import spmatrix as spmatrix + +from .base_linear_solver_interface import IPLinearSolverInterface as IPLinearSolverInterface + +class ScipyInterface(ScipyLU, IPLinearSolverInterface): + @classmethod + def getLoggerName(cls): ... + compute_inertia: Incomplete + logger: Incomplete + def __init__(self, compute_inertia: bool = False) -> None: ... + def do_numeric_factorization( + self, matrix: spmatrix | BlockMatrix, raise_on_error: bool = True + ) -> LinearSolverResults: ... + def get_inertia(self): ... diff --git a/stubs/pyomo/contrib/latex_printer/__init__.pyi b/stubs/pyomo/contrib/latex_printer/__init__.pyi new file mode 100644 index 000000000..8459e5007 --- /dev/null +++ b/stubs/pyomo/contrib/latex_printer/__init__.pyi @@ -0,0 +1 @@ +from pyomo.contrib.latex_printer.latex_printer import latex_printer as latex_printer diff --git a/stubs/pyomo/contrib/latex_printer/latex_printer.pyi b/stubs/pyomo/contrib/latex_printer/latex_printer.pyi new file mode 100644 index 000000000..9f6eaf311 --- /dev/null +++ b/stubs/pyomo/contrib/latex_printer/latex_printer.pyi @@ -0,0 +1,111 @@ +from _typeshed import Incomplete +from pyomo.common import DeveloperError as DeveloperError +from pyomo.common.collections.component_map import ComponentMap as ComponentMap +from pyomo.common.collections.component_set import ComponentSet as ComponentSet +from pyomo.common.dependencies import numpy_available as numpy_available +from pyomo.common.errors import InfeasibleConstraintException as InfeasibleConstraintException +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.block import IndexedBlock as IndexedBlock +from pyomo.core.base.constraint import IndexedConstraint as IndexedConstraint +from pyomo.core.base.constraint import ScalarConstraint as ScalarConstraint +from pyomo.core.base.enums import SortComponents as SortComponents +from pyomo.core.base.expression import ExpressionData as ExpressionData +from pyomo.core.base.expression import ScalarExpression as ScalarExpression +from pyomo.core.base.objective import ObjectiveData as ObjectiveData +from pyomo.core.base.objective import ScalarObjective as ScalarObjective +from pyomo.core.base.param import IndexedParam as IndexedParam +from pyomo.core.base.param import ParamData as ParamData +from pyomo.core.base.param import ScalarParam as ScalarParam +from pyomo.core.base.set import SetData as SetData +from pyomo.core.base.set import SetOperator as SetOperator +from pyomo.core.base.var import IndexedVar as IndexedVar +from pyomo.core.base.var import ScalarVar as ScalarVar +from pyomo.core.base.var import VarData as VarData +from pyomo.core.expr import AbsExpression as AbsExpression +from pyomo.core.expr import DivisionExpression as DivisionExpression +from pyomo.core.expr import EqualityExpression as EqualityExpression +from pyomo.core.expr import Expr_ifExpression as Expr_ifExpression +from pyomo.core.expr import ExternalFunctionExpression as ExternalFunctionExpression +from pyomo.core.expr import InequalityExpression as InequalityExpression +from pyomo.core.expr import LinearExpression as LinearExpression +from pyomo.core.expr import MonomialTermExpression as MonomialTermExpression +from pyomo.core.expr import NegationExpression as NegationExpression +from pyomo.core.expr import PowExpression as PowExpression +from pyomo.core.expr import ProductExpression as ProductExpression +from pyomo.core.expr import RangedExpression as RangedExpression +from pyomo.core.expr import SumExpression as SumExpression +from pyomo.core.expr import UnaryFunctionExpression as UnaryFunctionExpression +from pyomo.core.expr.base import ExpressionBase as ExpressionBase +from pyomo.core.expr.numeric_expr import NPV_DivisionExpression as NPV_DivisionExpression +from pyomo.core.expr.numeric_expr import NPV_SumExpression as NPV_SumExpression +from pyomo.core.expr.template_expr import GetAttrExpression as GetAttrExpression +from pyomo.core.expr.template_expr import GetItemExpression as GetItemExpression +from pyomo.core.expr.template_expr import IndexTemplate as IndexTemplate +from pyomo.core.expr.template_expr import ( + NPV_Numeric_GetItemExpression as NPV_Numeric_GetItemExpression, +) +from pyomo.core.expr.template_expr import ( + NPV_Structural_GetItemExpression as NPV_Structural_GetItemExpression, +) +from pyomo.core.expr.template_expr import Numeric_GetAttrExpression as Numeric_GetAttrExpression +from pyomo.core.expr.template_expr import Numeric_GetItemExpression as Numeric_GetItemExpression +from pyomo.core.expr.template_expr import TemplateSumExpression as TemplateSumExpression +from pyomo.core.expr.template_expr import resolve_template as resolve_template +from pyomo.core.expr.template_expr import templatize_constraint as templatize_constraint +from pyomo.core.expr.template_expr import templatize_rule as templatize_rule +from pyomo.core.expr.visitor import StreamBasedExpressionVisitor as StreamBasedExpressionVisitor +from pyomo.core.expr.visitor import identify_components as identify_components +from pyomo.repn.util import ExprType as ExprType + +set_operator_map: Incomplete +latex_reals: str +latex_integers: str +domainMap: Incomplete + +def decoder(num, base): ... +def indexCorrector(ixs, base): ... +def alphabetStringGenerator(num): ... +def templatize_expression(expr): ... +def templatize_passthrough(con): ... +def precedenceChecker(node, arg1, arg2=None): ... +def handle_negation_node(visitor, node, arg1): ... +def handle_product_node(visitor, node, arg1, arg2): ... +def handle_pow_node(visitor, node, arg1, arg2): ... +def handle_division_node(visitor, node, arg1, arg2): ... +def handle_abs_node(visitor, node, arg1): ... +def handle_unary_node(visitor, node, arg1): ... +def handle_equality_node(visitor, node, arg1, arg2): ... +def handle_inequality_node(visitor, node, arg1, arg2): ... +def handle_var_node(visitor, node): ... +def handle_num_node(visitor, node): ... +def handle_sumExpression_node(visitor, node, *args): ... +def handle_monomialTermExpression_node(visitor, node, arg1, arg2): ... +def handle_named_expression_node(visitor, node, arg1): ... +def handle_ranged_inequality_node(visitor, node, arg1, arg2, arg3): ... +def handle_exprif_node(visitor, node, arg1, arg2, arg3): ... +def handle_external_function_node(visitor, node, *args): ... +def handle_functionID_node(visitor, node, *args): ... +def handle_indexTemplate_node(visitor, node, *args): ... +def handle_numericGetItemExpression_node(visitor, node, *args): ... +def handle_templateSumExpression_node(visitor, node, *args): ... +def handle_param_node(visitor, node): ... +def handle_str_node(visitor, node): ... +def handle_npv_structuralGetItemExpression_node(visitor, node, *args): ... +def handle_indexedBlock_node(visitor, node, *args): ... +def handle_numericGetAttrExpression_node(visitor, node, *args): ... + +class _LatexVisitor(StreamBasedExpressionVisitor): + externalFunctionCounter: int + def __init__(self) -> None: ... + def exitNode(self, node, data): ... + +def analyze_variable(vr): ... +def multiple_replace(pstr, rep_dict): ... +def latex_printer( + pyomo_component, + latex_component_map=None, + ostream=None, + use_equation_environment: bool = False, + explicit_set_summation: bool = False, + throw_templatization_error: bool = False, +): ... diff --git a/stubs/pyomo/contrib/mcpp/__init__.pyi b/stubs/pyomo/contrib/mcpp/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/mcpp/build.pyi b/stubs/pyomo/contrib/mcpp/build.pyi new file mode 100644 index 000000000..76c0eeb99 --- /dev/null +++ b/stubs/pyomo/contrib/mcpp/build.pyi @@ -0,0 +1,9 @@ +from pyomo.common.download import FileDownloader as FileDownloader +from pyomo.common.fileutils import find_dir as find_dir +from pyomo.common.fileutils import this_file_dir as this_file_dir + +def build_mcpp(): ... + +class MCPPBuilder: + def __call__(self, parallel): ... + def skip(self): ... diff --git a/stubs/pyomo/contrib/mcpp/getMCPP.pyi b/stubs/pyomo/contrib/mcpp/getMCPP.pyi new file mode 100644 index 000000000..04baabe2b --- /dev/null +++ b/stubs/pyomo/contrib/mcpp/getMCPP.pyi @@ -0,0 +1,7 @@ +from _typeshed import Incomplete +from pyomo.common.download import FileDownloader as FileDownloader + +logger: Incomplete + +def get_mcpp(downloader) -> None: ... +def main(argv) -> None: ... diff --git a/stubs/pyomo/contrib/mcpp/plugins.pyi b/stubs/pyomo/contrib/mcpp/plugins.pyi new file mode 100644 index 000000000..1314f1887 --- /dev/null +++ b/stubs/pyomo/contrib/mcpp/plugins.pyi @@ -0,0 +1,7 @@ +from pyomo.common.download import DownloadFactory as DownloadFactory +from pyomo.common.extensions import ExtensionBuilderFactory as ExtensionBuilderFactory + +from .build import MCPPBuilder as MCPPBuilder +from .getMCPP import get_mcpp as get_mcpp + +def load() -> None: ... diff --git a/stubs/pyomo/contrib/mcpp/pyomo_mcpp.pyi b/stubs/pyomo/contrib/mcpp/pyomo_mcpp.pyi new file mode 100644 index 000000000..5c11e674a --- /dev/null +++ b/stubs/pyomo/contrib/mcpp/pyomo_mcpp.pyi @@ -0,0 +1,72 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.fileutils import Library as Library +from pyomo.core import Expression as Expression +from pyomo.core import value as value +from pyomo.core.base.block import SubclassOf as SubclassOf +from pyomo.core.base.expression import NamedExpressionData as NamedExpressionData +from pyomo.core.expr.numeric_expr import AbsExpression as AbsExpression +from pyomo.core.expr.numeric_expr import DivisionExpression as DivisionExpression +from pyomo.core.expr.numeric_expr import LinearExpression as LinearExpression +from pyomo.core.expr.numeric_expr import NegationExpression as NegationExpression +from pyomo.core.expr.numeric_expr import NPV_AbsExpression as NPV_AbsExpression +from pyomo.core.expr.numeric_expr import NPV_DivisionExpression as NPV_DivisionExpression +from pyomo.core.expr.numeric_expr import ( + NPV_ExternalFunctionExpression as NPV_ExternalFunctionExpression, +) +from pyomo.core.expr.numeric_expr import NPV_NegationExpression as NPV_NegationExpression +from pyomo.core.expr.numeric_expr import NPV_PowExpression as NPV_PowExpression +from pyomo.core.expr.numeric_expr import NPV_ProductExpression as NPV_ProductExpression +from pyomo.core.expr.numeric_expr import NPV_SumExpression as NPV_SumExpression +from pyomo.core.expr.numeric_expr import NPV_UnaryFunctionExpression as NPV_UnaryFunctionExpression +from pyomo.core.expr.numeric_expr import PowExpression as PowExpression +from pyomo.core.expr.numeric_expr import ProductExpression as ProductExpression +from pyomo.core.expr.numeric_expr import SumExpression as SumExpression +from pyomo.core.expr.numeric_expr import UnaryFunctionExpression as UnaryFunctionExpression +from pyomo.core.expr.numvalue import nonpyomo_leaf_types as nonpyomo_leaf_types +from pyomo.core.expr.visitor import StreamBasedExpressionVisitor as StreamBasedExpressionVisitor +from pyomo.core.expr.visitor import identify_variables as identify_variables + +logger: Incomplete +path: Incomplete +__version__: str + +def mcpp_available(): ... + +NPV_expressions: Incomplete + +class MCPP_Error(Exception): ... + +class MCPP_visitor(StreamBasedExpressionVisitor): + mcpp: Incomplete + missing_value_warnings: Incomplete + expr: Incomplete + num_vars: Incomplete + known_vars: Incomplete + var_to_idx: Incomplete + refs: Incomplete + def __init__(self, expression, improved_var_bounds=None) -> None: ... + def walk_expression(self): ... + def exitNode(self, node, data): ... + def beforeChild(self, node, child, child_idx): ... + def acceptChildResult(self, node, data, child_result, child_idx): ... + def register_num(self, num): ... + def register_var(self, var, lb, ub): ... + def finalizeResult(self, node_result): ... + +class McCormick: + mc_expr: Incomplete + mcpp: Incomplete + pyomo_expr: Incomplete + visitor: Incomplete + def __init__(self, expression, improved_var_bounds=None) -> None: ... + def __del__(self) -> None: ... + def __repn__(self): ... + def lower(self): ... + def upper(self): ... + def concave(self): ... + def convex(self): ... + def subcc(self): ... + def subcv(self): ... + def changePoint(self, var, point) -> None: ... + def warn_if_var_missing_value(self) -> None: ... diff --git a/stubs/pyomo/contrib/mindtpy/MindtPy.pyi b/stubs/pyomo/contrib/mindtpy/MindtPy.pyi new file mode 100644 index 000000000..02bc9aa35 --- /dev/null +++ b/stubs/pyomo/contrib/mindtpy/MindtPy.pyi @@ -0,0 +1,20 @@ +import types + +from _typeshed import Incomplete +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.contrib.mindtpy import __version__ as __version__ +from pyomo.opt import SolverFactory as SolverFactory + +class MindtPySolver: + CONFIG: Incomplete + def available(self, exception_flag: bool = True): ... + def license_is_valid(self): ... + def version(self): ... + def solve(self, model, **kwds): ... + def __enter__(self): ... + def __exit__( + self, + t: type[BaseException] | None, + v: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: ... diff --git a/stubs/pyomo/contrib/mindtpy/__init__.pyi b/stubs/pyomo/contrib/mindtpy/__init__.pyi new file mode 100644 index 000000000..f27f712b6 --- /dev/null +++ b/stubs/pyomo/contrib/mindtpy/__init__.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +__version__: Incomplete diff --git a/stubs/pyomo/contrib/mindtpy/algorithm_base_class.pyi b/stubs/pyomo/contrib/mindtpy/algorithm_base_class.pyi new file mode 100644 index 000000000..8e47bf20f --- /dev/null +++ b/stubs/pyomo/contrib/mindtpy/algorithm_base_class.pyi @@ -0,0 +1,208 @@ +import types + +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.errors import DeveloperError as DeveloperError +from pyomo.common.errors import InfeasibleConstraintException as InfeasibleConstraintException +from pyomo.contrib.fbbt.fbbt import fbbt as fbbt +from pyomo.contrib.gdpopt.solve_discrete_problem import ( + distinguish_mip_infeasible_or_unbounded as distinguish_mip_infeasible_or_unbounded, +) +from pyomo.contrib.gdpopt.util import SuppressInfeasibleWarning as SuppressInfeasibleWarning +from pyomo.contrib.gdpopt.util import get_main_elapsed_time as get_main_elapsed_time +from pyomo.contrib.gdpopt.util import lower_logger_level_to as lower_logger_level_to +from pyomo.contrib.gdpopt.util import time_code as time_code +from pyomo.contrib.mindtpy import __version__ as __version__ +from pyomo.contrib.mindtpy.cut_generation import add_no_good_cuts as add_no_good_cuts +from pyomo.contrib.mindtpy.util import GurobiPersistent4MindtPy as GurobiPersistent4MindtPy +from pyomo.contrib.mindtpy.util import add_orthogonality_cuts as add_orthogonality_cuts +from pyomo.contrib.mindtpy.util import add_var_bound as add_var_bound +from pyomo.contrib.mindtpy.util import copy_var_list_values as copy_var_list_values +from pyomo.contrib.mindtpy.util import ( + copy_var_list_values_from_solution_pool as copy_var_list_values_from_solution_pool, +) +from pyomo.contrib.mindtpy.util import epigraph_reformulation as epigraph_reformulation +from pyomo.contrib.mindtpy.util import fp_converged as fp_converged +from pyomo.contrib.mindtpy.util import ( + generate_lag_objective_function as generate_lag_objective_function, +) +from pyomo.contrib.mindtpy.util import ( + generate_norm1_objective_function as generate_norm1_objective_function, +) +from pyomo.contrib.mindtpy.util import ( + generate_norm2sq_objective_function as generate_norm2sq_objective_function, +) +from pyomo.contrib.mindtpy.util import generate_norm_constraint as generate_norm_constraint +from pyomo.contrib.mindtpy.util import ( + generate_norm_inf_objective_function as generate_norm_inf_objective_function, +) +from pyomo.contrib.mindtpy.util import get_integer_solution as get_integer_solution +from pyomo.contrib.mindtpy.util import initialize_feas_subproblem as initialize_feas_subproblem +from pyomo.contrib.mindtpy.util import ( + set_solver_constraint_violation_tolerance as set_solver_constraint_violation_tolerance, +) +from pyomo.contrib.mindtpy.util import set_solver_mipgap as set_solver_mipgap +from pyomo.contrib.mindtpy.util import setup_results_object as setup_results_object +from pyomo.contrib.mindtpy.util import update_solver_timelimit as update_solver_timelimit +from pyomo.core import Block as Block +from pyomo.core import Constraint as Constraint +from pyomo.core import ConstraintList as ConstraintList +from pyomo.core import Expression as Expression +from pyomo.core import NonNegativeReals as NonNegativeReals +from pyomo.core import Objective as Objective +from pyomo.core import RangeSet as RangeSet +from pyomo.core import Reals as Reals +from pyomo.core import Suffix as Suffix +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core import Var as Var +from pyomo.core import VarList as VarList +from pyomo.core import maximize as maximize +from pyomo.core import minimize as minimize +from pyomo.core import value as value +from pyomo.opt import SolutionStatus as SolutionStatus +from pyomo.opt import SolverFactory as SolverFactory +from pyomo.opt import SolverResults as SolverResults +from pyomo.opt import SolverStatus as SolverStatus +from pyomo.repn import generate_standard_repn as generate_standard_repn +from pyomo.solvers.plugins.solvers.gurobi_direct import gurobipy as gurobipy +from pyomo.solvers.plugins.solvers.persistent_solver import PersistentSolver as PersistentSolver +from pyomo.util.vars_from_expressions import get_vars_from_components as get_vars_from_components + +single_tree: Incomplete +single_tree_available: Incomplete +tabu_list: Incomplete +tabu_list_available: Incomplete +egb: Incomplete +egb_available: Incomplete + +class _MindtPyAlgorithm: + working_model: Incomplete + mip: Incomplete + fixed_nlp: Incomplete + results: Incomplete + timing: Incomplete + curr_int_sol: Incomplete + should_terminate: bool + integer_list: Incomplete + integer_solution_to_cuts_index: Incomplete + nlp_iter: int + mip_iter: int + mip_subiter: int + nlp_infeasible_counter: int + fp_iter: int + primal_bound_progress_time: Incomplete + dual_bound_progress_time: Incomplete + abs_gap: Incomplete + rel_gap: Incomplete + log_formatter: str + termination_condition_log_formatter: str + fixed_nlp_log_formatter: str + infeasible_fixed_nlp_log_formatter: str + log_note_formatter: str + primal_bound_improved: bool + dual_bound_improved: bool + best_solution_found: Incomplete + best_solution_found_time: Incomplete + stored_bound: Incomplete + num_no_good_cuts_added: Incomplete + last_iter_cuts: bool + mip_start_lazy_oa_cuts: Incomplete + mip_load_solutions: bool + nlp_load_solutions: bool + regularization_mip_load_solutions: bool + def __init__(self, **kwds) -> None: ... + def __enter__(self): ... + def __exit__( + self, + t: type[BaseException] | None, + v: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: ... + def available(self, exception_flag: bool = True): ... + def license_is_valid(self): ... + def version(self): ... + def set_up_logger(self) -> None: ... + util_block_name: Incomplete + def create_utility_block(self, model, name) -> None: ... + def model_is_valid(self): ... + def build_ordered_component_lists(self, model) -> None: ... + def add_cuts_components(self, model) -> None: ... + def get_dual_integral(self): ... + def get_primal_integral(self): ... + primal_integral: Incomplete + dual_integral: Incomplete + primal_dual_gap_integral: Incomplete + def get_integral_info(self) -> None: ... + def update_gap(self) -> None: ... + dual_bound: Incomplete + def update_dual_bound(self, bound_value) -> None: ... + def update_suboptimal_dual_bound(self, results) -> None: ... + primal_bound: Incomplete + def update_primal_bound(self, bound_value) -> None: ... + objective_sense: Incomplete + def process_objective(self, update_var_con_list: bool = True) -> None: ... + original_model: Incomplete + primal_bound_progress: Incomplete + dual_bound_progress: Incomplete + mip_objective_polynomial_degree: Incomplete + mip_constraint_polynomial_degree: Incomplete + def set_up_solve_data(self, model) -> None: ... + def MindtPy_initialization(self) -> None: ... + rnlp: Incomplete + def init_rNLP(self, add_oa_cuts: bool = True) -> None: ... + def init_max_binaries(self) -> None: ... + def solve_subproblem(self): ... + def handle_nlp_subproblem_tc(self, fixed_nlp, result, cb_opt=None) -> None: ... + def handle_subproblem_optimal(self, fixed_nlp, cb_opt=None, fp: bool = False) -> None: ... + def handle_subproblem_infeasible(self, fixed_nlp, cb_opt=None) -> None: ... + def handle_subproblem_other_termination( + self, fixed_nlp, termination_condition, cb_opt=None + ) -> None: ... + def solve_feasibility_subproblem(self): ... + def handle_feasibility_subproblem_tc(self, subprob_terminate_cond, MindtPy) -> None: ... + def algorithm_should_terminate(self, check_cycling): ... + def fix_dual_bound(self, last_iter_cuts) -> None: ... + def set_up_tabulist_callback(self) -> None: ... + def set_up_lazy_OA_callback(self) -> None: ... + def solve_main(self): ... + def solve_fp_main(self): ... + def solve_regularization_main(self): ... + def set_up_mip_solver(self): ... + def handle_main_optimal(self, main_mip, update_bound: bool = True) -> None: ... + def handle_main_infeasible(self) -> None: ... + def handle_main_max_timelimit(self, main_mip, main_mip_results) -> None: ... + def handle_main_unbounded(self, main_mip): ... + def handle_regularization_main_tc(self, main_mip, main_mip_results) -> None: ... + def setup_main(self) -> None: ... + def setup_fp_main(self) -> None: ... + def setup_regularization_main(self) -> None: ... + def update_result(self) -> None: ... + def load_solution(self) -> None: ... + def check_subsolver_validity(self) -> None: ... + def check_config(self) -> None: ... + def solve_fp_subproblem(self): ... + def handle_fp_subproblem_optimal(self, fp_nlp) -> None: ... + def handle_fp_main_tc(self, fp_main_results): ... + def fp_loop(self) -> None: ... + def initialize_mip_problem(self) -> None: ... + mip_opt: Incomplete + nlp_opt: Incomplete + feasibility_nlp_opt: Incomplete + regularization_mip_opt: Incomplete + def initialize_subsolvers(self) -> None: ... + def set_appsi_solver_update_config(self) -> None: ... + initial_var_values: Incomplete + def solve(self, model, **kwds): ... + def objective_reformulation(self) -> None: ... + def handle_main_mip_termination(self, main_mip, main_mip_results): ... + def MindtPy_iteration_loop(self) -> None: ... + def get_solution_name_obj(self, main_mip_results): ... + def add_regularization(self) -> None: ... + def bounds_converged(self): ... + def reached_iteration_limit(self): ... + def reached_time_limit(self): ... + def reached_stalling_limit(self): ... + def iteration_cycling(self): ... diff --git a/stubs/pyomo/contrib/mindtpy/config_options.pyi b/stubs/pyomo/contrib/mindtpy/config_options.pyi new file mode 100644 index 000000000..0641c3dce --- /dev/null +++ b/stubs/pyomo/contrib/mindtpy/config_options.pyi @@ -0,0 +1,8 @@ +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import In as In +from pyomo.common.config import NonNegativeInt as NonNegativeInt +from pyomo.common.config import PositiveFloat as PositiveFloat +from pyomo.common.config import PositiveInt as PositiveInt +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.contrib.gdpopt.util import a_logger as a_logger diff --git a/stubs/pyomo/contrib/mindtpy/cut_generation.pyi b/stubs/pyomo/contrib/mindtpy/cut_generation.pyi new file mode 100644 index 000000000..61d76be0d --- /dev/null +++ b/stubs/pyomo/contrib/mindtpy/cut_generation.pyi @@ -0,0 +1,33 @@ +from pyomo.contrib.gdpopt.util import time_code as time_code +from pyomo.contrib.mcpp.pyomo_mcpp import MCPP_Error as MCPP_Error +from pyomo.core import minimize as minimize +from pyomo.core import value as value + +def add_oa_cuts( + target_model, + dual_values, + jacobians, + objective_sense, + mip_constraint_polynomial_degree, + mip_iter, + config, + timing, + cb_opt=None, + linearize_active: bool = True, + linearize_violated: bool = True, +) -> None: ... +def add_oa_cuts_for_grey_box( + target_model, jacobians_model, config, objective_sense, mip_iter, cb_opt=None +) -> None: ... +def add_ecp_cuts( + target_model, + jacobians, + config, + timing, + linearize_active: bool = True, + linearize_violated: bool = True, +) -> None: ... +def add_no_good_cuts( + target_model, var_values, config, timing, mip_iter: int = 0, cb_opt=None +) -> None: ... +def add_affine_cuts(target_model, config, timing) -> None: ... diff --git a/stubs/pyomo/contrib/mindtpy/extended_cutting_plane.pyi b/stubs/pyomo/contrib/mindtpy/extended_cutting_plane.pyi new file mode 100644 index 000000000..bf3b10434 --- /dev/null +++ b/stubs/pyomo/contrib/mindtpy/extended_cutting_plane.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete +from pyomo.contrib.gdpopt.util import get_main_elapsed_time as get_main_elapsed_time +from pyomo.contrib.gdpopt.util import time_code as time_code +from pyomo.contrib.mindtpy.algorithm_base_class import _MindtPyAlgorithm +from pyomo.contrib.mindtpy.cut_generation import add_ecp_cuts as add_ecp_cuts +from pyomo.contrib.mindtpy.util import calc_jacobians as calc_jacobians +from pyomo.core import ConstraintList as ConstraintList +from pyomo.opt import SolverFactory as SolverFactory + +class MindtPy_ECP_Solver(_MindtPyAlgorithm): + CONFIG: Incomplete + last_iter_cuts: bool + def MindtPy_iteration_loop(self) -> None: ... + def check_config(self) -> None: ... + jacobians: Incomplete + def initialize_mip_problem(self) -> None: ... + def init_rNLP(self) -> None: ... + def algorithm_should_terminate(self): ... + primal_bound: Incomplete + best_solution_found: Incomplete + def all_nonlinear_constraint_satisfied(self): ... diff --git a/stubs/pyomo/contrib/mindtpy/feasibility_pump.pyi b/stubs/pyomo/contrib/mindtpy/feasibility_pump.pyi new file mode 100644 index 000000000..a542b0281 --- /dev/null +++ b/stubs/pyomo/contrib/mindtpy/feasibility_pump.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete +from pyomo.contrib.mindtpy.algorithm_base_class import _MindtPyAlgorithm +from pyomo.contrib.mindtpy.cut_generation import add_oa_cuts as add_oa_cuts +from pyomo.contrib.mindtpy.util import calc_jacobians as calc_jacobians +from pyomo.core import ConstraintList as ConstraintList +from pyomo.opt import SolverFactory as SolverFactory + +class MindtPy_FP_Solver(_MindtPyAlgorithm): + CONFIG: Incomplete + def check_config(self) -> None: ... + jacobians: Incomplete + def initialize_mip_problem(self) -> None: ... + def add_cuts( + self, + dual_values, + linearize_active: bool = True, + linearize_violated: bool = True, + cb_opt=None, + nlp=None, + ) -> None: ... + def MindtPy_iteration_loop(self) -> None: ... diff --git a/stubs/pyomo/contrib/mindtpy/global_outer_approximation.pyi b/stubs/pyomo/contrib/mindtpy/global_outer_approximation.pyi new file mode 100644 index 000000000..e3a06f470 --- /dev/null +++ b/stubs/pyomo/contrib/mindtpy/global_outer_approximation.pyi @@ -0,0 +1,22 @@ +from _typeshed import Incomplete +from pyomo.contrib.gdpopt.util import get_main_elapsed_time as get_main_elapsed_time +from pyomo.contrib.mindtpy.algorithm_base_class import _MindtPyAlgorithm +from pyomo.contrib.mindtpy.cut_generation import add_affine_cuts as add_affine_cuts +from pyomo.core import ConstraintList as ConstraintList +from pyomo.opt import SolverFactory as SolverFactory + +class MindtPy_GOA_Solver(_MindtPyAlgorithm): + CONFIG: Incomplete + def check_config(self) -> None: ... + def initialize_mip_problem(self) -> None: ... + def update_primal_bound(self, bound_value) -> None: ... + def add_cuts( + self, + dual_values=None, + linearize_active: bool = True, + linearize_violated: bool = True, + cb_opt=None, + nlp=None, + ) -> None: ... + integer_list: Incomplete + def deactivate_no_good_cuts_when_fixing_bound(self, no_good_cuts) -> None: ... diff --git a/stubs/pyomo/contrib/mindtpy/outer_approximation.pyi b/stubs/pyomo/contrib/mindtpy/outer_approximation.pyi new file mode 100644 index 000000000..683a48a77 --- /dev/null +++ b/stubs/pyomo/contrib/mindtpy/outer_approximation.pyi @@ -0,0 +1,27 @@ +from _typeshed import Incomplete +from pyomo.contrib.mindtpy.algorithm_base_class import _MindtPyAlgorithm +from pyomo.contrib.mindtpy.cut_generation import add_oa_cuts as add_oa_cuts +from pyomo.contrib.mindtpy.cut_generation import ( + add_oa_cuts_for_grey_box as add_oa_cuts_for_grey_box, +) +from pyomo.contrib.mindtpy.util import calc_jacobians as calc_jacobians +from pyomo.core import ConstraintList as ConstraintList +from pyomo.opt import SolverFactory as SolverFactory + +class MindtPy_OA_Solver(_MindtPyAlgorithm): + CONFIG: Incomplete + regularization_mip_type: str + def check_config(self) -> None: ... + jacobians: Incomplete + def initialize_mip_problem(self) -> None: ... + def add_cuts( + self, + dual_values, + linearize_active: bool = True, + linearize_violated: bool = True, + cb_opt=None, + nlp=None, + ) -> None: ... + integer_list: Incomplete + def deactivate_no_good_cuts_when_fixing_bound(self, no_good_cuts) -> None: ... + def objective_reformulation(self) -> None: ... diff --git a/stubs/pyomo/contrib/mindtpy/plugins.pyi b/stubs/pyomo/contrib/mindtpy/plugins.pyi new file mode 100644 index 000000000..08b671c7f --- /dev/null +++ b/stubs/pyomo/contrib/mindtpy/plugins.pyi @@ -0,0 +1 @@ +def load() -> None: ... diff --git a/stubs/pyomo/contrib/mindtpy/single_tree.pyi b/stubs/pyomo/contrib/mindtpy/single_tree.pyi new file mode 100644 index 000000000..c075d012e --- /dev/null +++ b/stubs/pyomo/contrib/mindtpy/single_tree.pyi @@ -0,0 +1,47 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.contrib.gdpopt.util import get_main_elapsed_time as get_main_elapsed_time +from pyomo.contrib.gdpopt.util import time_code as time_code +from pyomo.contrib.mcpp.pyomo_mcpp import MCPP_Error as MCPP_Error +from pyomo.contrib.mindtpy.cut_generation import add_no_good_cuts as add_no_good_cuts +from pyomo.contrib.mindtpy.cut_generation import add_oa_cuts as add_oa_cuts +from pyomo.contrib.mindtpy.util import copy_var_list_values as copy_var_list_values +from pyomo.contrib.mindtpy.util import get_integer_solution as get_integer_solution +from pyomo.contrib.mindtpy.util import set_var_valid_value as set_var_valid_value +from pyomo.core import minimize as minimize +from pyomo.core import value as value +from pyomo.core.expr import identify_variables as identify_variables +from pyomo.repn import generate_standard_repn as generate_standard_repn +from pyomo.solvers.plugins.solvers.gurobi_direct import gurobipy as gurobipy + +cplex: Incomplete +cplex_available: Incomplete + +class LazyOACallback_cplex: + def copy_lazy_var_list_values( + self, opt, from_list, to_list, config, skip_stale: bool = False, skip_fixed: bool = True + ) -> None: ... + def add_lazy_oa_cuts( + self, + target_model, + dual_values, + mindtpy_solver, + config, + opt, + linearize_active: bool = True, + linearize_violated: bool = True, + ) -> None: ... + def add_lazy_affine_cuts(self, mindtpy_solver, config, opt) -> None: ... + def add_lazy_no_good_cuts( + self, var_values, mindtpy_solver, config, opt, feasible: bool = False + ) -> None: ... + def handle_lazy_main_feasible_solution(self, main_mip, mindtpy_solver, config, opt) -> None: ... + def handle_lazy_subproblem_optimal(self, fixed_nlp, mindtpy_solver, config, opt) -> None: ... + def handle_lazy_subproblem_infeasible(self, fixed_nlp, mindtpy_solver, config, opt) -> None: ... + def handle_lazy_subproblem_other_termination( + self, fixed_nlp, termination_condition, mindtpy_solver, config + ) -> None: ... + def __call__(self) -> None: ... + +def LazyOACallback_gurobi(cb_m, cb_opt, cb_where, mindtpy_solver, config) -> None: ... +def handle_lazy_main_feasible_solution_gurobi(cb_m, cb_opt, mindtpy_solver, config) -> None: ... diff --git a/stubs/pyomo/contrib/mindtpy/tabu_list.pyi b/stubs/pyomo/contrib/mindtpy/tabu_list.pyi new file mode 100644 index 000000000..78cd16f50 --- /dev/null +++ b/stubs/pyomo/contrib/mindtpy/tabu_list.pyi @@ -0,0 +1,9 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies import UnavailableClass as UnavailableClass +from pyomo.common.dependencies import attempt_import as attempt_import + +cplex: Incomplete +cplex_available: Incomplete + +class IncumbentCallback_cplex: + def __call__(self) -> None: ... diff --git a/stubs/pyomo/contrib/mindtpy/util.pyi b/stubs/pyomo/contrib/mindtpy/util.pyi new file mode 100644 index 000000000..1303f91ce --- /dev/null +++ b/stubs/pyomo/contrib/mindtpy/util.pyi @@ -0,0 +1,71 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.contrib.fbbt.fbbt import compute_bounds_on_expr as compute_bounds_on_expr +from pyomo.contrib.gdpopt.util import get_main_elapsed_time as get_main_elapsed_time +from pyomo.contrib.gdpopt.util import time_code as time_code +from pyomo.contrib.mcpp.pyomo_mcpp import McCormick as McCormick +from pyomo.contrib.mcpp.pyomo_mcpp import mcpp_available as mcpp_available +from pyomo.core import Block as Block +from pyomo.core import Constraint as Constraint +from pyomo.core import ConstraintList as ConstraintList +from pyomo.core import Objective as Objective +from pyomo.core import RangeSet as RangeSet +from pyomo.core import Reals as Reals +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core import Var as Var +from pyomo.core import VarList as VarList +from pyomo.core import minimize as minimize +from pyomo.core import value as value +from pyomo.repn import generate_standard_repn as generate_standard_repn +from pyomo.solvers.plugins.solvers.gurobi_direct import gurobipy as gurobipy +from pyomo.solvers.plugins.solvers.gurobi_persistent import GurobiPersistent as GurobiPersistent +from pyomo.util.model_size import build_model_size_report as build_model_size_report + +pyomo_nlp: Incomplete +numpy: Incomplete + +def calc_jacobians(constraint_list, differentiate_mode): ... +def initialize_feas_subproblem(m, feasibility_norm) -> None: ... +def add_var_bound(model, config) -> None: ... +def generate_norm2sq_objective_function(model, setpoint_model, discrete_only: bool = False): ... +def generate_norm1_objective_function(model, setpoint_model, discrete_only: bool = False): ... +def generate_norm_inf_objective_function(model, setpoint_model, discrete_only: bool = False): ... +def generate_lag_objective_function( + model, setpoint_model, config, timing, discrete_only: bool = False +): ... +def generate_norm1_norm_constraint(model, setpoint_model, config, discrete_only: bool = True): ... +def update_solver_timelimit(opt, solver_name, timing, config) -> None: ... +def set_solver_mipgap(opt, solver_name, config) -> None: ... +def set_solver_constraint_violation_tolerance( + opt, solver_name, config, warm_start: bool = True +) -> None: ... +def get_integer_solution(model, string_zero: bool = False): ... +def copy_var_list_values_from_solution_pool( + from_list, + to_list, + config, + solver_model, + var_map, + solution_name, + ignore_integrality: bool = False, +) -> None: ... + +class GurobiPersistent4MindtPy(GurobiPersistent): ... + +def epigraph_reformulation(exp, slack_var_list, constraint_list, use_mcpp, sense) -> None: ... +def setup_results_object(results, model, config) -> None: ... +def fp_converged(working_model, mip_model, proj_zero_tolerance, discrete_only: bool = True): ... +def add_orthogonality_cuts(working_model, mip_model, config) -> None: ... +def generate_norm_constraint(fp_nlp_model, mip_model, config) -> None: ... +def copy_var_list_values( + from_list, + to_list, + config, + skip_stale: bool = False, + skip_fixed: bool = True, + ignore_integrality: bool = False, +) -> None: ... +def set_var_valid_value( + var, var_val, integer_tolerance, zero_tolerance, ignore_integrality +) -> None: ... diff --git a/stubs/pyomo/contrib/mpc/__init__.pyi b/stubs/pyomo/contrib/mpc/__init__.pyi new file mode 100644 index 000000000..aea682982 --- /dev/null +++ b/stubs/pyomo/contrib/mpc/__init__.pyi @@ -0,0 +1,5 @@ +from .data.get_cuid import get_indexed_cuid as get_indexed_cuid +from .data.interval_data import IntervalData as IntervalData +from .data.scalar_data import ScalarData as ScalarData +from .data.series_data import TimeSeriesData as TimeSeriesData +from .interfaces.model_interface import DynamicModelInterface as DynamicModelInterface diff --git a/stubs/pyomo/contrib/mpc/data/__init__.pyi b/stubs/pyomo/contrib/mpc/data/__init__.pyi new file mode 100644 index 000000000..ee5934aed --- /dev/null +++ b/stubs/pyomo/contrib/mpc/data/__init__.pyi @@ -0,0 +1,7 @@ +from .convert import interval_to_series as interval_to_series +from .convert import series_to_interval as series_to_interval +from .interval_data import IntervalData as IntervalData +from .scalar_data import ScalarData as ScalarData +from .series_data import TimeSeriesData as TimeSeriesData + +__doc__: str diff --git a/stubs/pyomo/contrib/mpc/data/convert.pyi b/stubs/pyomo/contrib/mpc/data/convert.pyi new file mode 100644 index 000000000..4808d6044 --- /dev/null +++ b/stubs/pyomo/contrib/mpc/data/convert.pyi @@ -0,0 +1,15 @@ +from pyomo.contrib.mpc.data.find_nearest_index import ( + find_nearest_interval_index as find_nearest_interval_index, +) +from pyomo.contrib.mpc.data.interval_data import IntervalData as IntervalData +from pyomo.contrib.mpc.data.scalar_data import ScalarData as ScalarData +from pyomo.contrib.mpc.data.series_data import TimeSeriesData as TimeSeriesData + +def interval_to_series( + data, + time_points=None, + tolerance: float = 0.0, + use_left_endpoints: bool = False, + prefer_left: bool = True, +): ... +def series_to_interval(data, use_left_endpoints: bool = False): ... diff --git a/stubs/pyomo/contrib/mpc/data/dynamic_data_base.pyi b/stubs/pyomo/contrib/mpc/data/dynamic_data_base.pyi new file mode 100644 index 000000000..1e708bb36 --- /dev/null +++ b/stubs/pyomo/contrib/mpc/data/dynamic_data_base.pyi @@ -0,0 +1,13 @@ +from pyomo.contrib.mpc.data.get_cuid import get_indexed_cuid as get_indexed_cuid +from pyomo.core.base.set import Set as Set + +class _DynamicDataBase: + def __init__(self, data, time_set=None, context=None) -> None: ... + def __eq__(self, other): ... + def get_data(self): ... + def get_cuid(self, key, context=None): ... + def get_data_from_key(self, key, context=None): ... + def contains_key(self, key, context=None): ... + def update_data(self, other, context=None) -> None: ... + def to_serializable(self) -> None: ... + def extract_variables(self, variables, context=None, copy_values: bool = False): ... diff --git a/stubs/pyomo/contrib/mpc/data/find_nearest_index.pyi b/stubs/pyomo/contrib/mpc/data/find_nearest_index.pyi new file mode 100644 index 000000000..794591b85 --- /dev/null +++ b/stubs/pyomo/contrib/mpc/data/find_nearest_index.pyi @@ -0,0 +1,4 @@ +def find_nearest_index(array, target, tolerance=None): ... +def find_nearest_interval_index( + interval_array, target, tolerance=None, prefer_left: bool = True +): ... diff --git a/stubs/pyomo/contrib/mpc/data/get_cuid.pyi b/stubs/pyomo/contrib/mpc/data/get_cuid.pyi new file mode 100644 index 000000000..27f65d39e --- /dev/null +++ b/stubs/pyomo/contrib/mpc/data/get_cuid.pyi @@ -0,0 +1,6 @@ +from pyomo.core.base.componentuid import ComponentUID as ComponentUID +from pyomo.core.base.indexed_component_slice import IndexedComponent_slice as IndexedComponent_slice +from pyomo.dae.flatten import get_slice_for_set as get_slice_for_set +from pyomo.util.slices import slice_component_along_sets as slice_component_along_sets + +def get_indexed_cuid(var, sets=None, dereference=None, context=None): ... diff --git a/stubs/pyomo/contrib/mpc/data/interval_data.pyi b/stubs/pyomo/contrib/mpc/data/interval_data.pyi new file mode 100644 index 000000000..c5383000b --- /dev/null +++ b/stubs/pyomo/contrib/mpc/data/interval_data.pyi @@ -0,0 +1,27 @@ +from typing import NamedTuple + +from _typeshed import Incomplete +from pyomo.contrib.mpc.data.dynamic_data_base import _DynamicDataBase +from pyomo.contrib.mpc.data.find_nearest_index import find_nearest_index as find_nearest_index +from pyomo.contrib.mpc.data.find_nearest_index import ( + find_nearest_interval_index as find_nearest_interval_index, +) +from pyomo.contrib.mpc.data.get_cuid import get_indexed_cuid as get_indexed_cuid +from pyomo.contrib.mpc.data.scalar_data import ScalarData as ScalarData + +class IntervalDataTuple(NamedTuple): + data: Incomplete + intervals: Incomplete + +def assert_disjoint_intervals(intervals) -> None: ... + +class IntervalData(_DynamicDataBase): + def __init__(self, data, intervals, time_set=None, context=None) -> None: ... + def __eq__(self, other): ... + def get_intervals(self): ... + def get_data_at_interval_indices(self, indices): ... + def get_data_at_time(self, time, tolerance=None, prefer_left: bool = True): ... + def to_serializable(self): ... + def concatenate(self, other, tolerance: float = 0.0) -> None: ... + def shift_time_points(self, offset) -> None: ... + def extract_variables(self, variables, context=None, copy_values: bool = False): ... diff --git a/stubs/pyomo/contrib/mpc/data/scalar_data.pyi b/stubs/pyomo/contrib/mpc/data/scalar_data.pyi new file mode 100644 index 000000000..db9e1cd4c --- /dev/null +++ b/stubs/pyomo/contrib/mpc/data/scalar_data.pyi @@ -0,0 +1,6 @@ +from pyomo.contrib.mpc.data.dynamic_data_base import _DynamicDataBase +from pyomo.contrib.mpc.data.get_cuid import get_indexed_cuid as get_indexed_cuid + +class ScalarData(_DynamicDataBase): + def __init__(self, data, time_set=None, context=None) -> None: ... + def to_serializable(self): ... diff --git a/stubs/pyomo/contrib/mpc/data/series_data.pyi b/stubs/pyomo/contrib/mpc/data/series_data.pyi new file mode 100644 index 000000000..2e23d1c80 --- /dev/null +++ b/stubs/pyomo/contrib/mpc/data/series_data.pyi @@ -0,0 +1,22 @@ +from typing import NamedTuple + +from _typeshed import Incomplete +from pyomo.contrib.mpc.data.dynamic_data_base import _DynamicDataBase +from pyomo.contrib.mpc.data.find_nearest_index import find_nearest_index as find_nearest_index +from pyomo.contrib.mpc.data.get_cuid import get_indexed_cuid as get_indexed_cuid +from pyomo.contrib.mpc.data.scalar_data import ScalarData as ScalarData + +class TimeSeriesTuple(NamedTuple): + data: Incomplete + time: Incomplete + +class TimeSeriesData(_DynamicDataBase): + def __init__(self, data, time, time_set=None, context=None) -> None: ... + def __eq__(self, other): ... + def get_time_points(self): ... + def get_data_at_time_indices(self, indices): ... + def get_data_at_time(self, time=None, tolerance: float = 0.0): ... + def to_serializable(self): ... + def concatenate(self, other, tolerance: float = 0.0) -> None: ... + def shift_time_points(self, offset) -> None: ... + def extract_variables(self, variables, context=None, copy_values: bool = False): ... diff --git a/stubs/pyomo/contrib/mpc/examples/__init__.pyi b/stubs/pyomo/contrib/mpc/examples/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/mpc/examples/cstr/__init__.pyi b/stubs/pyomo/contrib/mpc/examples/cstr/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/mpc/examples/cstr/model.pyi b/stubs/pyomo/contrib/mpc/examples/cstr/model.pyi new file mode 100644 index 000000000..2a956d041 --- /dev/null +++ b/stubs/pyomo/contrib/mpc/examples/cstr/model.pyi @@ -0,0 +1,6 @@ +from pyomo.contrib.incidence_analysis import IncidenceGraphInterface as IncidenceGraphInterface + +def make_model(dynamic: bool = True, horizon: float = 10.0): ... +def initialize_model(m, dynamic: bool = True, ntfe=None) -> None: ... +def create_instance(dynamic: bool = True, horizon=None, ntfe=None): ... +def main() -> None: ... diff --git a/stubs/pyomo/contrib/mpc/examples/cstr/run_mpc.pyi b/stubs/pyomo/contrib/mpc/examples/cstr/run_mpc.pyi new file mode 100644 index 000000000..12030ac7d --- /dev/null +++ b/stubs/pyomo/contrib/mpc/examples/cstr/run_mpc.pyi @@ -0,0 +1,14 @@ +from pyomo.contrib.mpc.examples.cstr.model import create_instance as create_instance + +def get_steady_state_data(target, tee: bool = False): ... +def run_cstr_mpc( + initial_data, + setpoint_data, + samples_per_controller_horizon: int = 5, + sample_time: float = 2.0, + ntfe_per_sample_controller: int = 2, + ntfe_plant: int = 5, + simulation_steps: int = 5, + tee: bool = False, +): ... +def main() -> None: ... diff --git a/stubs/pyomo/contrib/mpc/examples/cstr/run_openloop.pyi b/stubs/pyomo/contrib/mpc/examples/cstr/run_openloop.pyi new file mode 100644 index 000000000..3d2212468 --- /dev/null +++ b/stubs/pyomo/contrib/mpc/examples/cstr/run_openloop.pyi @@ -0,0 +1,11 @@ +from pyomo.contrib.mpc.examples.cstr.model import create_instance as create_instance + +def get_input_sequence(): ... +def run_cstr_openloop( + inputs, + model_horizon: float = 1.0, + ntfe: int = 10, + simulation_steps: int = 15, + tee: bool = False, +): ... +def main() -> None: ... diff --git a/stubs/pyomo/contrib/mpc/interfaces/__init__.pyi b/stubs/pyomo/contrib/mpc/interfaces/__init__.pyi new file mode 100644 index 000000000..3a03abe59 --- /dev/null +++ b/stubs/pyomo/contrib/mpc/interfaces/__init__.pyi @@ -0,0 +1 @@ +__doc__: str diff --git a/stubs/pyomo/contrib/mpc/interfaces/copy_values.pyi b/stubs/pyomo/contrib/mpc/interfaces/copy_values.pyi new file mode 100644 index 000000000..5b4de98c1 --- /dev/null +++ b/stubs/pyomo/contrib/mpc/interfaces/copy_values.pyi @@ -0,0 +1,7 @@ +from _typeshed import Incomplete + +iterable_scalars: Incomplete + +def copy_values_at_time( + source_vars, target_vars, source_time_points, target_time_points +) -> None: ... diff --git a/stubs/pyomo/contrib/mpc/interfaces/load_data.pyi b/stubs/pyomo/contrib/mpc/interfaces/load_data.pyi new file mode 100644 index 000000000..a6913b70f --- /dev/null +++ b/stubs/pyomo/contrib/mpc/interfaces/load_data.pyi @@ -0,0 +1,16 @@ +from pyomo.contrib.mpc.data.find_nearest_index import find_nearest_index as find_nearest_index +from pyomo.contrib.mpc.data.find_nearest_index import ( + find_nearest_interval_index as find_nearest_interval_index, +) + +def load_data_from_scalar(data, model, time) -> None: ... +def load_data_from_series(data, model, time, tolerance: float = 0.0) -> None: ... +def load_data_from_interval( + data, + model, + time, + tolerance: float = 0.0, + prefer_left: bool = True, + exclude_left_endpoint: bool = True, + exclude_right_endpoint: bool = False, +) -> None: ... diff --git a/stubs/pyomo/contrib/mpc/interfaces/model_interface.pyi b/stubs/pyomo/contrib/mpc/interfaces/model_interface.pyi new file mode 100644 index 000000000..4e2ac9d1a --- /dev/null +++ b/stubs/pyomo/contrib/mpc/interfaces/model_interface.pyi @@ -0,0 +1,63 @@ +from _typeshed import Incomplete +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.contrib.mpc.data.find_nearest_index import find_nearest_index as find_nearest_index +from pyomo.contrib.mpc.data.get_cuid import get_indexed_cuid as get_indexed_cuid +from pyomo.contrib.mpc.data.interval_data import IntervalData as IntervalData +from pyomo.contrib.mpc.data.scalar_data import ScalarData as ScalarData +from pyomo.contrib.mpc.data.series_data import TimeSeriesData as TimeSeriesData +from pyomo.contrib.mpc.interfaces.copy_values import copy_values_at_time as copy_values_at_time +from pyomo.contrib.mpc.interfaces.load_data import ( + load_data_from_interval as load_data_from_interval, +) +from pyomo.contrib.mpc.interfaces.load_data import load_data_from_scalar as load_data_from_scalar +from pyomo.contrib.mpc.interfaces.load_data import load_data_from_series as load_data_from_series +from pyomo.contrib.mpc.modeling.constraints import ( + get_piecewise_constant_constraints as get_piecewise_constant_constraints, +) +from pyomo.contrib.mpc.modeling.cost_expressions import ( + get_penalty_from_constant_target as get_penalty_from_constant_target, +) +from pyomo.contrib.mpc.modeling.cost_expressions import ( + get_penalty_from_target as get_penalty_from_target, +) +from pyomo.core.base.componentuid import ComponentUID as ComponentUID +from pyomo.core.base.expression import Expression as Expression +from pyomo.core.base.var import Var as Var +from pyomo.dae.flatten import flatten_dae_components as flatten_dae_components + +iterable_scalars: Incomplete + +class DynamicModelInterface: + model: Incomplete + time: Incomplete + def __init__(self, model, time, context=...) -> None: ... + def get_scalar_variables(self): ... + def get_indexed_variables(self): ... + def get_scalar_expressions(self): ... + def get_indexed_expressions(self): ... + def get_scalar_variable_data(self): ... + def get_data_at_time(self, time=None, include_expr: bool = False): ... + def load_data( + self, + data, + time_points=None, + tolerance: float = 0.0, + prefer_left=None, + exclude_left_endpoint=None, + exclude_right_endpoint=None, + ) -> None: ... + def copy_values_at_time(self, source_time=None, target_time=None) -> None: ... + def shift_values_by_time(self, dt) -> None: ... + def get_penalty_from_target( + self, + target_data, + time=None, + variables=None, + weight_data=None, + variable_set=None, + tolerance=None, + prefer_left=None, + ): ... + def get_piecewise_constant_constraints( + self, variables, sample_points, use_next: bool = True, tolerance: float = 0.0 + ): ... diff --git a/stubs/pyomo/contrib/mpc/interfaces/var_linker.pyi b/stubs/pyomo/contrib/mpc/interfaces/var_linker.pyi new file mode 100644 index 000000000..3f2b75fd4 --- /dev/null +++ b/stubs/pyomo/contrib/mpc/interfaces/var_linker.pyi @@ -0,0 +1,7 @@ +from pyomo.contrib.mpc.interfaces.copy_values import copy_values_at_time as copy_values_at_time + +class DynamicVarLinker: + def __init__( + self, source_variables, target_variables, source_time=None, target_time=None + ) -> None: ... + def transfer(self, t_source=None, t_target=None) -> None: ... diff --git a/stubs/pyomo/contrib/mpc/modeling/__init__.pyi b/stubs/pyomo/contrib/mpc/modeling/__init__.pyi new file mode 100644 index 000000000..3a03abe59 --- /dev/null +++ b/stubs/pyomo/contrib/mpc/modeling/__init__.pyi @@ -0,0 +1 @@ +__doc__: str diff --git a/stubs/pyomo/contrib/mpc/modeling/constraints.pyi b/stubs/pyomo/contrib/mpc/modeling/constraints.pyi new file mode 100644 index 000000000..8608f756b --- /dev/null +++ b/stubs/pyomo/contrib/mpc/modeling/constraints.pyi @@ -0,0 +1,4 @@ +from pyomo.core.base.constraint import Constraint as Constraint +from pyomo.core.base.set import Set as Set + +def get_piecewise_constant_constraints(inputs, time, sample_points, use_next: bool = True): ... diff --git a/stubs/pyomo/contrib/mpc/modeling/cost_expressions.pyi b/stubs/pyomo/contrib/mpc/modeling/cost_expressions.pyi new file mode 100644 index 000000000..b2f425080 --- /dev/null +++ b/stubs/pyomo/contrib/mpc/modeling/cost_expressions.pyi @@ -0,0 +1,35 @@ +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.contrib.mpc.data.convert import interval_to_series as interval_to_series +from pyomo.contrib.mpc.data.interval_data import IntervalData as IntervalData +from pyomo.contrib.mpc.data.scalar_data import ScalarData as ScalarData +from pyomo.contrib.mpc.data.series_data import TimeSeriesData as TimeSeriesData +from pyomo.contrib.mpc.data.series_data import get_indexed_cuid as get_indexed_cuid +from pyomo.core.base.componentuid import ComponentUID as ComponentUID +from pyomo.core.base.expression import Expression as Expression +from pyomo.core.base.set import Set as Set + +def get_penalty_from_constant_target( + variables, time, setpoint_data, weight_data=None, variable_set=None +): ... +def get_penalty_from_piecewise_constant_target( + variables, + time, + setpoint_data, + weight_data=None, + variable_set=None, + tolerance: float = 0.0, + prefer_left: bool = True, +): ... +def get_quadratic_penalty_at_time(var, t, setpoint, weight=None): ... +def get_penalty_from_time_varying_target( + variables, time, setpoint_data, weight_data=None, variable_set=None +): ... +def get_penalty_from_target( + variables, + time, + setpoint_data, + weight_data=None, + variable_set=None, + tolerance=None, + prefer_left=None, +): ... diff --git a/stubs/pyomo/contrib/mpc/modeling/terminal.pyi b/stubs/pyomo/contrib/mpc/modeling/terminal.pyi new file mode 100644 index 000000000..e42d249b3 --- /dev/null +++ b/stubs/pyomo/contrib/mpc/modeling/terminal.pyi @@ -0,0 +1,10 @@ +from pyomo.contrib.mpc.data.scalar_data import ScalarData as ScalarData +from pyomo.contrib.mpc.data.series_data import get_indexed_cuid as get_indexed_cuid +from pyomo.core.base.componentuid import ComponentUID as ComponentUID +from pyomo.core.base.expression import Expression as Expression +from pyomo.core.base.set import Set as Set + +def get_penalty_at_time( + variables, t, target_data, weight_data=None, time_set=None, variable_set=None +): ... +def get_terminal_penalty(variables, time_set, target_data, weight_data=None, variable_set=None): ... diff --git a/stubs/pyomo/contrib/multistart/__init__.pyi b/stubs/pyomo/contrib/multistart/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/multistart/high_conf_stop.pyi b/stubs/pyomo/contrib/multistart/high_conf_stop.pyi new file mode 100644 index 000000000..2b627e515 --- /dev/null +++ b/stubs/pyomo/contrib/multistart/high_conf_stop.pyi @@ -0,0 +1,2 @@ +def num_one_occurrences(observed_obj_vals, tolerance): ... +def should_stop(solutions, stopping_mass, stopping_delta, tolerance): ... diff --git a/stubs/pyomo/contrib/multistart/multi.pyi b/stubs/pyomo/contrib/multistart/multi.pyi new file mode 100644 index 000000000..64d41dc13 --- /dev/null +++ b/stubs/pyomo/contrib/multistart/multi.pyi @@ -0,0 +1,32 @@ +import types + +from _typeshed import Incomplete +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import In as In +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.contrib.multistart.high_conf_stop import should_stop as should_stop +from pyomo.contrib.multistart.reinit import reinitialize_variables as reinitialize_variables +from pyomo.contrib.multistart.reinit import strategies as strategies +from pyomo.core import Objective as Objective +from pyomo.core import Var as Var +from pyomo.core import minimize as minimize +from pyomo.core import value as value +from pyomo.opt import SolverFactory as SolverFactory +from pyomo.opt import SolverStatus as SolverStatus + +logger: Incomplete + +class MultiStart: + CONFIG: Incomplete + def available(self, exception_flag: bool = True): ... + def license_is_valid(self): ... + def solve(self, model, **kwds): ... + def __enter__(self): ... + def __exit__( + self, + t: type[BaseException] | None, + v: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: ... diff --git a/stubs/pyomo/contrib/multistart/plugins.pyi b/stubs/pyomo/contrib/multistart/plugins.pyi new file mode 100644 index 000000000..08b671c7f --- /dev/null +++ b/stubs/pyomo/contrib/multistart/plugins.pyi @@ -0,0 +1 @@ +def load() -> None: ... diff --git a/stubs/pyomo/contrib/multistart/reinit.pyi b/stubs/pyomo/contrib/multistart/reinit.pyi new file mode 100644 index 000000000..ade0dd169 --- /dev/null +++ b/stubs/pyomo/contrib/multistart/reinit.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from pyomo.core import Var as Var + +logger: Incomplete + +def rand(val, lb, ub): ... +def midpoint_guess_and_bound(val, lb, ub): ... +def rand_guess_and_bound(val, lb, ub): ... +def rand_distributed(val, lb, ub, divisions: int = 9): ... +def simple_midpoint(val, lb, ub): ... +def linspace(lower, upper, n): ... + +strategies: Incomplete + +def reinitialize_variables(model, config) -> None: ... diff --git a/stubs/pyomo/contrib/parmest/__init__.pyi b/stubs/pyomo/contrib/parmest/__init__.pyi new file mode 100644 index 000000000..f7a3bea97 --- /dev/null +++ b/stubs/pyomo/contrib/parmest/__init__.pyi @@ -0,0 +1,2 @@ +from pyomo.common.deprecation import moved_module as moved_module +from pyomo.common.deprecation import relocated_module_attribute as relocated_module_attribute diff --git a/stubs/pyomo/contrib/parmest/examples/__init__.pyi b/stubs/pyomo/contrib/parmest/examples/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/parmest/examples/reaction_kinetics/__init__.pyi b/stubs/pyomo/contrib/parmest/examples/reaction_kinetics/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/parmest/examples/reaction_kinetics/simple_reaction_parmest_example.pyi b/stubs/pyomo/contrib/parmest/examples/reaction_kinetics/simple_reaction_parmest_example.pyi new file mode 100644 index 000000000..803b704c5 --- /dev/null +++ b/stubs/pyomo/contrib/parmest/examples/reaction_kinetics/simple_reaction_parmest_example.pyi @@ -0,0 +1,31 @@ +from _typeshed import Incomplete +from pyomo.contrib.parmest.experiment import Experiment as Experiment +from pyomo.environ import ConcreteModel as ConcreteModel +from pyomo.environ import Constraint as Constraint +from pyomo.environ import Expression as Expression +from pyomo.environ import Objective as Objective +from pyomo.environ import Param as Param +from pyomo.environ import PositiveReals as PositiveReals +from pyomo.environ import RangeSet as RangeSet +from pyomo.environ import Var as Var +from pyomo.environ import exp as exp +from pyomo.environ import minimize as minimize +from pyomo.environ import value as value + +def simple_reaction_model(data): ... + +class SimpleReactionExperiment(Experiment): + data: Incomplete + model: Incomplete + def __init__(self, data) -> None: ... + def create_model(self) -> None: ... + def label_model(self): ... + def get_labeled_model(self): ... + +class SimpleReactionExperimentK2Fixed(SimpleReactionExperiment): + def label_model(self): ... + +class SimpleReactionExperimentK2Variable(SimpleReactionExperiment): + def label_model(self): ... + +def main() -> None: ... diff --git a/stubs/pyomo/contrib/parmest/examples/reactor_design/__init__.pyi b/stubs/pyomo/contrib/parmest/examples/reactor_design/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/parmest/examples/reactor_design/bootstrap_example.pyi b/stubs/pyomo/contrib/parmest/examples/reactor_design/bootstrap_example.pyi new file mode 100644 index 000000000..d60e13593 --- /dev/null +++ b/stubs/pyomo/contrib/parmest/examples/reactor_design/bootstrap_example.pyi @@ -0,0 +1,5 @@ +from pyomo.contrib.parmest.examples.reactor_design.reactor_design import ( + ReactorDesignExperiment as ReactorDesignExperiment, +) + +def main() -> None: ... diff --git a/stubs/pyomo/contrib/parmest/examples/reactor_design/confidence_region_example.pyi b/stubs/pyomo/contrib/parmest/examples/reactor_design/confidence_region_example.pyi new file mode 100644 index 000000000..d60e13593 --- /dev/null +++ b/stubs/pyomo/contrib/parmest/examples/reactor_design/confidence_region_example.pyi @@ -0,0 +1,5 @@ +from pyomo.contrib.parmest.examples.reactor_design.reactor_design import ( + ReactorDesignExperiment as ReactorDesignExperiment, +) + +def main() -> None: ... diff --git a/stubs/pyomo/contrib/parmest/examples/reactor_design/datarec_example.pyi b/stubs/pyomo/contrib/parmest/examples/reactor_design/datarec_example.pyi new file mode 100644 index 000000000..3599adb52 --- /dev/null +++ b/stubs/pyomo/contrib/parmest/examples/reactor_design/datarec_example.pyi @@ -0,0 +1,22 @@ +from _typeshed import Incomplete +from pyomo.contrib.parmest.examples.reactor_design.reactor_design import ( + ReactorDesignExperiment as ReactorDesignExperiment, +) +from pyomo.contrib.parmest.examples.reactor_design.reactor_design import ( + reactor_design_model as reactor_design_model, +) + +class ReactorDesignExperimentDataRec(ReactorDesignExperiment): + data_std: Incomplete + def __init__(self, data, data_std, experiment_number) -> None: ... + model: Incomplete + def create_model(self): ... + def label_model(self): ... + +class ReactorDesignExperimentPostDataRec(ReactorDesignExperiment): + data_std: Incomplete + def __init__(self, data, data_std, experiment_number) -> None: ... + def label_model(self): ... + +def generate_data(): ... +def main(): ... diff --git a/stubs/pyomo/contrib/parmest/examples/reactor_design/leaveNout_example.pyi b/stubs/pyomo/contrib/parmest/examples/reactor_design/leaveNout_example.pyi new file mode 100644 index 000000000..d60e13593 --- /dev/null +++ b/stubs/pyomo/contrib/parmest/examples/reactor_design/leaveNout_example.pyi @@ -0,0 +1,5 @@ +from pyomo.contrib.parmest.examples.reactor_design.reactor_design import ( + ReactorDesignExperiment as ReactorDesignExperiment, +) + +def main() -> None: ... diff --git a/stubs/pyomo/contrib/parmest/examples/reactor_design/likelihood_ratio_example.pyi b/stubs/pyomo/contrib/parmest/examples/reactor_design/likelihood_ratio_example.pyi new file mode 100644 index 000000000..d60e13593 --- /dev/null +++ b/stubs/pyomo/contrib/parmest/examples/reactor_design/likelihood_ratio_example.pyi @@ -0,0 +1,5 @@ +from pyomo.contrib.parmest.examples.reactor_design.reactor_design import ( + ReactorDesignExperiment as ReactorDesignExperiment, +) + +def main() -> None: ... diff --git a/stubs/pyomo/contrib/parmest/examples/reactor_design/multisensor_data_example.pyi b/stubs/pyomo/contrib/parmest/examples/reactor_design/multisensor_data_example.pyi new file mode 100644 index 000000000..098246b2c --- /dev/null +++ b/stubs/pyomo/contrib/parmest/examples/reactor_design/multisensor_data_example.pyi @@ -0,0 +1,9 @@ +from pyomo.contrib.parmest.examples.reactor_design.reactor_design import ( + ReactorDesignExperiment as ReactorDesignExperiment, +) + +class MultisensorReactorDesignExperiment(ReactorDesignExperiment): + def finalize_model(self): ... + def label_model(self): ... + +def main(): ... diff --git a/stubs/pyomo/contrib/parmest/examples/reactor_design/parameter_estimation_example.pyi b/stubs/pyomo/contrib/parmest/examples/reactor_design/parameter_estimation_example.pyi new file mode 100644 index 000000000..d60e13593 --- /dev/null +++ b/stubs/pyomo/contrib/parmest/examples/reactor_design/parameter_estimation_example.pyi @@ -0,0 +1,5 @@ +from pyomo.contrib.parmest.examples.reactor_design.reactor_design import ( + ReactorDesignExperiment as ReactorDesignExperiment, +) + +def main() -> None: ... diff --git a/stubs/pyomo/contrib/parmest/examples/reactor_design/reactor_design.pyi b/stubs/pyomo/contrib/parmest/examples/reactor_design/reactor_design.pyi new file mode 100644 index 000000000..43cd8ad11 --- /dev/null +++ b/stubs/pyomo/contrib/parmest/examples/reactor_design/reactor_design.pyi @@ -0,0 +1,17 @@ +from _typeshed import Incomplete +from pyomo.contrib.parmest.experiment import Experiment as Experiment + +def reactor_design_model(): ... + +class ReactorDesignExperiment(Experiment): + data: Incomplete + experiment_number: Incomplete + data_i: Incomplete + model: Incomplete + def __init__(self, data, experiment_number) -> None: ... + def create_model(self): ... + def finalize_model(self): ... + def label_model(self): ... + def get_labeled_model(self): ... + +def main() -> None: ... diff --git a/stubs/pyomo/contrib/parmest/examples/reactor_design/timeseries_data_example.pyi b/stubs/pyomo/contrib/parmest/examples/reactor_design/timeseries_data_example.pyi new file mode 100644 index 000000000..a37d732e8 --- /dev/null +++ b/stubs/pyomo/contrib/parmest/examples/reactor_design/timeseries_data_example.pyi @@ -0,0 +1,14 @@ +from _typeshed import Incomplete +from pyomo.contrib.parmest.examples.reactor_design.reactor_design import ( + ReactorDesignExperiment as ReactorDesignExperiment, +) + +class TimeSeriesReactorDesignExperiment(ReactorDesignExperiment): + data: Incomplete + experiment_number: Incomplete + data_i: Incomplete + model: Incomplete + def __init__(self, data, experiment_number) -> None: ... + def finalize_model(self): ... + +def main(): ... diff --git a/stubs/pyomo/contrib/parmest/examples/rooney_biegler/__init__.pyi b/stubs/pyomo/contrib/parmest/examples/rooney_biegler/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/parmest/examples/rooney_biegler/bootstrap_example.pyi b/stubs/pyomo/contrib/parmest/examples/rooney_biegler/bootstrap_example.pyi new file mode 100644 index 000000000..0296d5acc --- /dev/null +++ b/stubs/pyomo/contrib/parmest/examples/rooney_biegler/bootstrap_example.pyi @@ -0,0 +1,5 @@ +from pyomo.contrib.parmest.examples.rooney_biegler.rooney_biegler import ( + RooneyBieglerExperiment as RooneyBieglerExperiment, +) + +def main(): ... diff --git a/stubs/pyomo/contrib/parmest/examples/rooney_biegler/likelihood_ratio_example.pyi b/stubs/pyomo/contrib/parmest/examples/rooney_biegler/likelihood_ratio_example.pyi new file mode 100644 index 000000000..0296d5acc --- /dev/null +++ b/stubs/pyomo/contrib/parmest/examples/rooney_biegler/likelihood_ratio_example.pyi @@ -0,0 +1,5 @@ +from pyomo.contrib.parmest.examples.rooney_biegler.rooney_biegler import ( + RooneyBieglerExperiment as RooneyBieglerExperiment, +) + +def main(): ... diff --git a/stubs/pyomo/contrib/parmest/examples/rooney_biegler/parameter_estimation_example.pyi b/stubs/pyomo/contrib/parmest/examples/rooney_biegler/parameter_estimation_example.pyi new file mode 100644 index 000000000..0296d5acc --- /dev/null +++ b/stubs/pyomo/contrib/parmest/examples/rooney_biegler/parameter_estimation_example.pyi @@ -0,0 +1,5 @@ +from pyomo.contrib.parmest.examples.rooney_biegler.rooney_biegler import ( + RooneyBieglerExperiment as RooneyBieglerExperiment, +) + +def main(): ... diff --git a/stubs/pyomo/contrib/parmest/examples/rooney_biegler/rooney_biegler.pyi b/stubs/pyomo/contrib/parmest/examples/rooney_biegler/rooney_biegler.pyi new file mode 100644 index 000000000..28642a3db --- /dev/null +++ b/stubs/pyomo/contrib/parmest/examples/rooney_biegler/rooney_biegler.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from pyomo.contrib.parmest.experiment import Experiment as Experiment + +def rooney_biegler_model(data): ... + +class RooneyBieglerExperiment(Experiment): + data: Incomplete + model: Incomplete + def __init__(self, data) -> None: ... + def create_model(self) -> None: ... + def label_model(self) -> None: ... + def finalize_model(self) -> None: ... + def get_labeled_model(self): ... + +def main() -> None: ... diff --git a/stubs/pyomo/contrib/parmest/examples/rooney_biegler/rooney_biegler_with_constraint.pyi b/stubs/pyomo/contrib/parmest/examples/rooney_biegler/rooney_biegler_with_constraint.pyi new file mode 100644 index 000000000..906d2c485 --- /dev/null +++ b/stubs/pyomo/contrib/parmest/examples/rooney_biegler/rooney_biegler_with_constraint.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from pyomo.contrib.parmest.experiment import Experiment as Experiment + +def rooney_biegler_model_with_constraint(data): ... + +class RooneyBieglerExperiment(Experiment): + data: Incomplete + model: Incomplete + def __init__(self, data) -> None: ... + def create_model(self) -> None: ... + def label_model(self) -> None: ... + def finalize_model(self) -> None: ... + def get_labeled_model(self): ... + +def main() -> None: ... diff --git a/stubs/pyomo/contrib/parmest/examples/semibatch/__init__.pyi b/stubs/pyomo/contrib/parmest/examples/semibatch/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/parmest/examples/semibatch/parallel_example.pyi b/stubs/pyomo/contrib/parmest/examples/semibatch/parallel_example.pyi new file mode 100644 index 000000000..04cb2771b --- /dev/null +++ b/stubs/pyomo/contrib/parmest/examples/semibatch/parallel_example.pyi @@ -0,0 +1,3 @@ +from pyomo.contrib.parmest.examples.semibatch.semibatch import generate_model as generate_model + +def main() -> None: ... diff --git a/stubs/pyomo/contrib/parmest/examples/semibatch/parameter_estimation_example.pyi b/stubs/pyomo/contrib/parmest/examples/semibatch/parameter_estimation_example.pyi new file mode 100644 index 000000000..88271cd6c --- /dev/null +++ b/stubs/pyomo/contrib/parmest/examples/semibatch/parameter_estimation_example.pyi @@ -0,0 +1,5 @@ +from pyomo.contrib.parmest.examples.semibatch.semibatch import ( + SemiBatchExperiment as SemiBatchExperiment, +) + +def main() -> None: ... diff --git a/stubs/pyomo/contrib/parmest/examples/semibatch/scenario_example.pyi b/stubs/pyomo/contrib/parmest/examples/semibatch/scenario_example.pyi new file mode 100644 index 000000000..88271cd6c --- /dev/null +++ b/stubs/pyomo/contrib/parmest/examples/semibatch/scenario_example.pyi @@ -0,0 +1,5 @@ +from pyomo.contrib.parmest.examples.semibatch.semibatch import ( + SemiBatchExperiment as SemiBatchExperiment, +) + +def main() -> None: ... diff --git a/stubs/pyomo/contrib/parmest/examples/semibatch/semibatch.pyi b/stubs/pyomo/contrib/parmest/examples/semibatch/semibatch.pyi new file mode 100644 index 000000000..e6c071d53 --- /dev/null +++ b/stubs/pyomo/contrib/parmest/examples/semibatch/semibatch.pyi @@ -0,0 +1,31 @@ +from _typeshed import Incomplete +from pyomo.contrib.parmest.experiment import Experiment as Experiment +from pyomo.dae import ContinuousSet as ContinuousSet +from pyomo.dae import DerivativeVar as DerivativeVar +from pyomo.environ import ComponentUID as ComponentUID +from pyomo.environ import ConcreteModel as ConcreteModel +from pyomo.environ import Constraint as Constraint +from pyomo.environ import ConstraintList as ConstraintList +from pyomo.environ import Expression as Expression +from pyomo.environ import Objective as Objective +from pyomo.environ import Param as Param +from pyomo.environ import Set as Set +from pyomo.environ import SolverFactory as SolverFactory +from pyomo.environ import Suffix as Suffix +from pyomo.environ import TransformationFactory as TransformationFactory +from pyomo.environ import Var as Var +from pyomo.environ import exp as exp +from pyomo.environ import minimize as minimize + +def generate_model(data): ... + +class SemiBatchExperiment(Experiment): + data: Incomplete + model: Incomplete + def __init__(self, data) -> None: ... + def create_model(self) -> None: ... + def label_model(self) -> None: ... + def finalize_model(self) -> None: ... + def get_labeled_model(self): ... + +def main() -> None: ... diff --git a/stubs/pyomo/contrib/parmest/experiment.pyi b/stubs/pyomo/contrib/parmest/experiment.pyi new file mode 100644 index 000000000..bc5ec6cba --- /dev/null +++ b/stubs/pyomo/contrib/parmest/experiment.pyi @@ -0,0 +1,6 @@ +from _typeshed import Incomplete + +class Experiment: + model: Incomplete + def __init__(self, model=None) -> None: ... + def get_labeled_model(self): ... diff --git a/stubs/pyomo/contrib/parmest/graphics.pyi b/stubs/pyomo/contrib/parmest/graphics.pyi new file mode 100644 index 000000000..c93151e33 --- /dev/null +++ b/stubs/pyomo/contrib/parmest/graphics.pyi @@ -0,0 +1,35 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.dependencies import check_min_version as check_min_version +from pyomo.common.dependencies import matplotlib as matplotlib +from pyomo.common.dependencies import matplotlib_available as matplotlib_available +from pyomo.common.dependencies import numpy_available as numpy_available +from pyomo.common.dependencies import pandas_available as pandas_available +from pyomo.common.dependencies import scipy as scipy +from pyomo.common.dependencies import scipy_available as scipy_available +from pyomo.common.dependencies.scipy import stats as stats + +sns: Incomplete +seaborn_available: Incomplete +imports_available: Incomplete + +def pairwise_plot( + theta_values, + theta_star=None, + alpha=None, + distributions=[], + axis_limits=None, + title=None, + add_obj_contour: bool = True, + add_legend: bool = True, + filename=None, +) -> None: ... +def fit_rect_dist(theta_values, alpha): ... +def fit_mvn_dist(theta_values): ... +def fit_kde_dist(theta_values): ... +def grouped_boxplot( + data1, data2, normalize: bool = False, group_names=['data1', 'data2'], filename=None +) -> None: ... +def grouped_violinplot( + data1, data2, normalize: bool = False, group_names=['data1', 'data2'], filename=None +) -> None: ... diff --git a/stubs/pyomo/contrib/parmest/parmest.pyi b/stubs/pyomo/contrib/parmest/parmest.pyi new file mode 100644 index 000000000..8f3164dbd --- /dev/null +++ b/stubs/pyomo/contrib/parmest/parmest.pyi @@ -0,0 +1,119 @@ +from functools import singledispatchmethod + +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.dependencies import numpy_available as numpy_available +from pyomo.common.dependencies import pandas_available as pandas_available +from pyomo.common.dependencies import scipy as scipy +from pyomo.common.dependencies import scipy_available as scipy_available +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.common.tee import capture_output as capture_output +from pyomo.dae import ContinuousSet as ContinuousSet +from pyomo.environ import Block as Block +from pyomo.environ import ComponentUID as ComponentUID +from pyomo.opt import SolverFactory as SolverFactory + +use_mpisppy: bool +parmest_available: Incomplete +inverse_reduced_hessian: Incomplete +inverse_reduced_hessian_available: Incomplete +logger: Incomplete + +def ef_nonants(ef): ... +def SSE(model): ... + +class Estimator: + exp_list: Incomplete + obj_function: Incomplete + tee: Incomplete + diagnostic_mode: Incomplete + solver_options: Incomplete + pest_deprecated: Incomplete + estimator_theta_names: Incomplete + model_initialized: bool + @singledispatchmethod + def __init__( + self, + experiment_list, + obj_function=None, + tee: bool = False, + diagnostic_mode: bool = False, + solver_options=None, + ) -> None: ... + def theta_est( + self, solver: str = 'ef_ipopt', return_values=[], calc_cov: bool = False, cov_n=None + ): ... + def theta_est_bootstrap( + self, + bootstrap_samples, + samplesize=None, + replacement: bool = True, + seed=None, + return_samples: bool = False, + ): ... + def theta_est_leaveNout( + self, lNo, lNo_samples=None, seed=None, return_samples: bool = False + ): ... + def leaveNout_bootstrap_test( + self, lNo, lNo_samples, bootstrap_samples, distribution, alphas, seed=None + ): ... + theta_names_updated: Incomplete + def objective_at_theta(self, theta_values=None, initialize_parmest_model: bool = False): ... + def likelihood_ratio_test( + self, obj_at_theta, obj_value, alphas, return_thresholds: bool = False + ): ... + def confidence_region_test( + self, theta_values, distribution, alphas, test_theta_values=None + ): ... + +def group_data(data, groupby_column_name, use_mean=None): ... + +class _DeprecatedSecondStageCostExpr: + def __init__(self, ssc_function, data) -> None: ... + def __call__(self, model): ... + +class _DeprecatedEstimator: + model_function: Incomplete + callback_data: Incomplete + theta_names: Incomplete + obj_function: Incomplete + tee: Incomplete + diagnostic_mode: Incomplete + solver_options: Incomplete + model_initialized: bool + def __init__( + self, + model_function, + data, + theta_names, + obj_function=None, + tee: bool = False, + diagnostic_mode: bool = False, + solver_options=None, + ) -> None: ... + def theta_est( + self, solver: str = 'ef_ipopt', return_values=[], calc_cov: bool = False, cov_n=None + ): ... + def theta_est_bootstrap( + self, + bootstrap_samples, + samplesize=None, + replacement: bool = True, + seed=None, + return_samples: bool = False, + ): ... + def theta_est_leaveNout( + self, lNo, lNo_samples=None, seed=None, return_samples: bool = False + ): ... + def leaveNout_bootstrap_test( + self, lNo, lNo_samples, bootstrap_samples, distribution, alphas, seed=None + ): ... + theta_names_updated: Incomplete + def objective_at_theta(self, theta_values=None, initialize_parmest_model: bool = False): ... + def likelihood_ratio_test( + self, obj_at_theta, obj_value, alphas, return_thresholds: bool = False + ): ... + def confidence_region_test( + self, theta_values, distribution, alphas, test_theta_values=None + ): ... diff --git a/stubs/pyomo/contrib/parmest/scenariocreator.pyi b/stubs/pyomo/contrib/parmest/scenariocreator.pyi new file mode 100644 index 000000000..281cb160e --- /dev/null +++ b/stubs/pyomo/contrib/parmest/scenariocreator.pyi @@ -0,0 +1,25 @@ +from _typeshed import Incomplete + +logger: Incomplete + +class ScenarioSet: + name: Incomplete + def __init__(self, name) -> None: ... + def ScensIterator(self): ... + def ScenarioNumber(self, scennum): ... + def addone(self, scen) -> None: ... + def append_bootstrap(self, bootstrap_theta) -> None: ... + def write_csv(self, filename) -> None: ... + +class ParmestScen: + name: Incomplete + ThetaVals: Incomplete + probability: Incomplete + def __init__(self, name, ThetaVals, probability) -> None: ... + +class ScenarioCreator: + pest: Incomplete + solvername: Incomplete + def __init__(self, pest, solvername) -> None: ... + def ScenariosFromExperiments(self, addtoSet) -> None: ... + def ScenariosFromBootstrap(self, addtoSet, numtomake, seed=None) -> None: ... diff --git a/stubs/pyomo/contrib/parmest/utils/__init__.pyi b/stubs/pyomo/contrib/parmest/utils/__init__.pyi new file mode 100644 index 000000000..0872316c7 --- /dev/null +++ b/stubs/pyomo/contrib/parmest/utils/__init__.pyi @@ -0,0 +1,12 @@ +from pyomo.contrib.parmest.utils.create_ef import create_EF as create_EF +from pyomo.contrib.parmest.utils.create_ef import ef_nonants as ef_nonants +from pyomo.contrib.parmest.utils.create_ef import find_active_objective as find_active_objective +from pyomo.contrib.parmest.utils.create_ef import get_objs as get_objs +from pyomo.contrib.parmest.utils.ipopt_solver_wrapper import ( + ipopt_solve_with_stats as ipopt_solve_with_stats, +) +from pyomo.contrib.parmest.utils.model_utils import convert_params_to_vars as convert_params_to_vars +from pyomo.contrib.parmest.utils.mpi_utils import MPIInterface as MPIInterface +from pyomo.contrib.parmest.utils.mpi_utils import ParallelTaskManager as ParallelTaskManager +from pyomo.contrib.parmest.utils.scenario_tree import ScenarioNode as ScenarioNode +from pyomo.contrib.parmest.utils.scenario_tree import build_vardatalist as build_vardatalist diff --git a/stubs/pyomo/contrib/parmest/utils/create_ef.pyi b/stubs/pyomo/contrib/parmest/utils/create_ef.pyi new file mode 100644 index 000000000..2172d6dc3 --- /dev/null +++ b/stubs/pyomo/contrib/parmest/utils/create_ef.pyi @@ -0,0 +1,17 @@ +from collections.abc import Generator + +from _typeshed import Incomplete +from pyomo.core import Objective as Objective +from pyomo.core.expr.numeric_expr import LinearExpression as LinearExpression + +def get_objs(scenario_instance): ... +def create_EF( + scenario_names, + scenario_creator, + scenario_creator_kwargs=None, + EF_name=None, + suppress_warnings: bool = False, + nonant_for_fixed_vars: bool = True, +): ... +def find_active_objective(pyomomodel): ... +def ef_nonants(ef) -> Generator[Incomplete]: ... diff --git a/stubs/pyomo/contrib/parmest/utils/ipopt_solver_wrapper.pyi b/stubs/pyomo/contrib/parmest/utils/ipopt_solver_wrapper.pyi new file mode 100644 index 000000000..41c7081bb --- /dev/null +++ b/stubs/pyomo/contrib/parmest/utils/ipopt_solver_wrapper.pyi @@ -0,0 +1,4 @@ +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.opt import TerminationCondition as TerminationCondition + +def ipopt_solve_with_stats(model, solver, max_iter: int = 500, max_cpu_time: int = 120): ... diff --git a/stubs/pyomo/contrib/parmest/utils/model_utils.pyi b/stubs/pyomo/contrib/parmest/utils/model_utils.pyi new file mode 100644 index 000000000..fc7ca5e28 --- /dev/null +++ b/stubs/pyomo/contrib/parmest/utils/model_utils.pyi @@ -0,0 +1,11 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.core.base.param import IndexedParam as IndexedParam +from pyomo.core.base.var import IndexedVar as IndexedVar +from pyomo.core.expr import identify_mutable_parameters as identify_mutable_parameters +from pyomo.core.expr import replace_expressions as replace_expressions +from pyomo.environ import ComponentUID as ComponentUID + +logger: Incomplete + +def convert_params_to_vars(model, param_names=None, fix_vars: bool = False): ... diff --git a/stubs/pyomo/contrib/parmest/utils/mpi_utils.pyi b/stubs/pyomo/contrib/parmest/utils/mpi_utils.pyi new file mode 100644 index 000000000..305567ea2 --- /dev/null +++ b/stubs/pyomo/contrib/parmest/utils/mpi_utils.pyi @@ -0,0 +1,20 @@ +from _typeshed import Incomplete + +class MPIInterface: + __have_mpi__: Incomplete + def __init__(self) -> None: ... + @property + def have_mpi(self): ... + @property + def comm(self): ... + @property + def rank(self): ... + @property + def size(self): ... + +class ParallelTaskManager: + def __init__(self, n_total_tasks, mpi_interface=None) -> None: ... + def is_root(self): ... + def global_to_local_data(self, global_data): ... + def allgather_global_data(self, local_data): ... + def gather_global_data(self, local_data): ... diff --git a/stubs/pyomo/contrib/parmest/utils/scenario_tree.pyi b/stubs/pyomo/contrib/parmest/utils/scenario_tree.pyi new file mode 100644 index 000000000..7fe07f09c --- /dev/null +++ b/stubs/pyomo/contrib/parmest/utils/scenario_tree.pyi @@ -0,0 +1,26 @@ +from _typeshed import Incomplete + +def build_vardatalist(self, model, varlist=None): ... + +class ScenarioNode: + name: Incomplete + cond_prob: Incomplete + stage: Incomplete + cost_expression: Incomplete + nonant_list: Incomplete + nonant_ef_suppl_list: Incomplete + parent_name: Incomplete + nonant_vardata_list: Incomplete + nonant_ef_suppl_vardata_list: Incomplete + def __init__( + self, + name, + cond_prob, + stage, + cost_expression, + scen_name_list, + nonant_list, + scen_model, + nonant_ef_suppl_list=None, + parent_name=None, + ) -> None: ... diff --git a/stubs/pyomo/contrib/piecewise/__init__.pyi b/stubs/pyomo/contrib/piecewise/__init__.pyi new file mode 100644 index 000000000..f210e5b9d --- /dev/null +++ b/stubs/pyomo/contrib/piecewise/__init__.pyi @@ -0,0 +1,38 @@ +from pyomo.contrib.piecewise.piecewise_linear_expression import ( + PiecewiseLinearExpression as PiecewiseLinearExpression, +) +from pyomo.contrib.piecewise.piecewise_linear_function import ( + PiecewiseLinearFunction as PiecewiseLinearFunction, +) +from pyomo.contrib.piecewise.transform.convex_combination import ( + ConvexCombinationTransformation as ConvexCombinationTransformation, +) +from pyomo.contrib.piecewise.transform.disaggregated_convex_combination import ( + DisaggregatedConvexCombinationTransformation as DisaggregatedConvexCombinationTransformation, +) +from pyomo.contrib.piecewise.transform.disaggregated_logarithmic import ( + DisaggregatedLogarithmicMIPTransformation as DisaggregatedLogarithmicMIPTransformation, +) +from pyomo.contrib.piecewise.transform.incremental import ( + IncrementalMIPTransformation as IncrementalMIPTransformation, +) +from pyomo.contrib.piecewise.transform.inner_representation_gdp import ( + InnerRepresentationGDPTransformation as InnerRepresentationGDPTransformation, +) +from pyomo.contrib.piecewise.transform.multiple_choice import ( + MultipleChoiceTransformation as MultipleChoiceTransformation, +) +from pyomo.contrib.piecewise.transform.nested_inner_repn import ( + NestedInnerRepresentationGDPTransformation as NestedInnerRepresentationGDPTransformation, +) +from pyomo.contrib.piecewise.transform.nonlinear_to_pwl import ( + DomainPartitioningMethod as DomainPartitioningMethod, +) +from pyomo.contrib.piecewise.transform.nonlinear_to_pwl import NonlinearToPWL as NonlinearToPWL +from pyomo.contrib.piecewise.transform.outer_representation_gdp import ( + OuterRepresentationGDPTransformation as OuterRepresentationGDPTransformation, +) +from pyomo.contrib.piecewise.transform.reduced_inner_representation_gdp import ( + ReducedInnerRepresentationGDPTransformation as ReducedInnerRepresentationGDPTransformation, +) +from pyomo.contrib.piecewise.triangulations import Triangulation as Triangulation diff --git a/stubs/pyomo/contrib/piecewise/ordered_3d_j1_triangulation_data.pyi b/stubs/pyomo/contrib/piecewise/ordered_3d_j1_triangulation_data.pyi new file mode 100644 index 000000000..469c7d987 --- /dev/null +++ b/stubs/pyomo/contrib/piecewise/ordered_3d_j1_triangulation_data.pyi @@ -0,0 +1 @@ +def get_hamiltonian_paths(): ... diff --git a/stubs/pyomo/contrib/piecewise/piecewise_linear_expression.pyi b/stubs/pyomo/contrib/piecewise/piecewise_linear_expression.pyi new file mode 100644 index 000000000..c8c7b9b79 --- /dev/null +++ b/stubs/pyomo/contrib/piecewise/piecewise_linear_expression.pyi @@ -0,0 +1,12 @@ +from _typeshed import Incomplete +from pyomo.common.autoslots import AutoSlots as AutoSlots +from pyomo.core.expr.numeric_expr import NumericExpression as NumericExpression + +class PiecewiseLinearExpression(NumericExpression): + __autoslot_mappers__: Incomplete + def __init__(self, args, pw_linear_function) -> None: ... + def nargs(self): ... + @property + def pw_linear_function(self): ... + def create_node_with_local_data(self, args): ... + def polynomial_degree(self) -> None: ... diff --git a/stubs/pyomo/contrib/piecewise/piecewise_linear_function.pyi b/stubs/pyomo/contrib/piecewise/piecewise_linear_function.pyi new file mode 100644 index 000000000..ce59dcc5f --- /dev/null +++ b/stubs/pyomo/contrib/piecewise/piecewise_linear_function.pyi @@ -0,0 +1,61 @@ +from _typeshed import Incomplete +from pyomo.common import DeveloperError as DeveloperError +from pyomo.common.autoslots import AutoSlots as AutoSlots +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.dependencies.scipy import spatial as spatial +from pyomo.contrib.piecewise.piecewise_linear_expression import ( + PiecewiseLinearExpression as PiecewiseLinearExpression, +) +from pyomo.contrib.piecewise.triangulations import Triangulation as Triangulation +from pyomo.contrib.piecewise.triangulations import ( + get_ordered_j1_triangulation as get_ordered_j1_triangulation, +) +from pyomo.contrib.piecewise.triangulations import ( + get_unordered_j1_triangulation as get_unordered_j1_triangulation, +) +from pyomo.core import Any as Any +from pyomo.core import NonNegativeIntegers as NonNegativeIntegers +from pyomo.core import value as value +from pyomo.core.base.block import Block as Block +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.expression import Expression as Expression +from pyomo.core.base.global_set import UnindexedComponent_index as UnindexedComponent_index +from pyomo.core.base.indexed_component import UnindexedComponent_set as UnindexedComponent_set +from pyomo.core.base.initializer import Initializer as Initializer + +ZERO_TOLERANCE: float +logger: Incomplete + +class PiecewiseLinearFunctionData(BlockData): + def __init__(self, component=None) -> None: ... + @property + def triangulation(self): ... + def __call__(self, *args): ... + def map_transformation_var(self, pw_expr, v) -> None: ... + def get_transformation_var(self, pw_expr): ... + +class _univariate_linear_functor(AutoSlots.Mixin): + slope: Incomplete + intercept: Incomplete + def __init__(self, slope, intercept) -> None: ... + def __call__(self, x): ... + +class _multivariate_linear_functor(AutoSlots.Mixin): + normal: Incomplete + def __init__(self, normal) -> None: ... + def __call__(self, *args): ... + +class _tabular_data_functor(AutoSlots.Mixin): + tabular_data: Incomplete + def __init__(self, tabular_data, tupleize: bool = False) -> None: ... + def __call__(self, *args): ... + +class PiecewiseLinearFunction(Block): + def __new__(cls, *args, **kwds): ... + def __init__(self, *args, **kwargs) -> None: ... + +class ScalarPiecewiseLinearFunction(PiecewiseLinearFunctionData, PiecewiseLinearFunction): + def __init__(self, *args, **kwds) -> None: ... + +class IndexedPiecewiseLinearFunction(PiecewiseLinearFunction): ... diff --git a/stubs/pyomo/contrib/piecewise/transform/__init__.pyi b/stubs/pyomo/contrib/piecewise/transform/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/piecewise/transform/convex_combination.pyi b/stubs/pyomo/contrib/piecewise/transform/convex_combination.pyi new file mode 100644 index 000000000..d6ff86416 --- /dev/null +++ b/stubs/pyomo/contrib/piecewise/transform/convex_combination.pyi @@ -0,0 +1,4 @@ +from pyomo.core.base import Transformation as Transformation +from pyomo.core.base import TransformationFactory as TransformationFactory + +class ConvexCombinationTransformation(Transformation): ... diff --git a/stubs/pyomo/contrib/piecewise/transform/disaggregated_convex_combination.pyi b/stubs/pyomo/contrib/piecewise/transform/disaggregated_convex_combination.pyi new file mode 100644 index 000000000..bb0996a1a --- /dev/null +++ b/stubs/pyomo/contrib/piecewise/transform/disaggregated_convex_combination.pyi @@ -0,0 +1,4 @@ +from pyomo.core.base import Transformation as Transformation +from pyomo.core.base import TransformationFactory as TransformationFactory + +class DisaggregatedConvexCombinationTransformation(Transformation): ... diff --git a/stubs/pyomo/contrib/piecewise/transform/disaggregated_logarithmic.pyi b/stubs/pyomo/contrib/piecewise/transform/disaggregated_logarithmic.pyi new file mode 100644 index 000000000..a019b87f6 --- /dev/null +++ b/stubs/pyomo/contrib/piecewise/transform/disaggregated_logarithmic.pyi @@ -0,0 +1,14 @@ +from _typeshed import Incomplete +from pyomo.common.errors import DeveloperError as DeveloperError +from pyomo.contrib.piecewise.transform.piecewise_linear_transformation_base import ( + PiecewiseLinearTransformationBase as PiecewiseLinearTransformationBase, +) +from pyomo.core import Binary as Binary +from pyomo.core import Constraint as Constraint +from pyomo.core import RangeSet as RangeSet +from pyomo.core import Set as Set +from pyomo.core import Var as Var +from pyomo.core.base import TransformationFactory as TransformationFactory + +class DisaggregatedLogarithmicMIPTransformation(PiecewiseLinearTransformationBase): + CONFIG: Incomplete diff --git a/stubs/pyomo/contrib/piecewise/transform/incremental.pyi b/stubs/pyomo/contrib/piecewise/transform/incremental.pyi new file mode 100644 index 000000000..e7efa18ca --- /dev/null +++ b/stubs/pyomo/contrib/piecewise/transform/incremental.pyi @@ -0,0 +1,14 @@ +from _typeshed import Incomplete +from pyomo.contrib.piecewise.transform.piecewise_linear_transformation_base import ( + PiecewiseLinearTransformationBase as PiecewiseLinearTransformationBase, +) +from pyomo.contrib.piecewise.triangulations import Triangulation as Triangulation +from pyomo.core import Binary as Binary +from pyomo.core import Constraint as Constraint +from pyomo.core import Param as Param +from pyomo.core import RangeSet as RangeSet +from pyomo.core import Var as Var +from pyomo.core.base import TransformationFactory as TransformationFactory + +class IncrementalMIPTransformation(PiecewiseLinearTransformationBase): + CONFIG: Incomplete diff --git a/stubs/pyomo/contrib/piecewise/transform/inner_representation_gdp.pyi b/stubs/pyomo/contrib/piecewise/transform/inner_representation_gdp.pyi new file mode 100644 index 000000000..9ac834797 --- /dev/null +++ b/stubs/pyomo/contrib/piecewise/transform/inner_representation_gdp.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from pyomo.contrib.fbbt.fbbt import compute_bounds_on_expr as compute_bounds_on_expr +from pyomo.contrib.piecewise.transform.piecewise_linear_transformation_base import ( + PiecewiseLinearTransformationBase as PiecewiseLinearTransformationBase, +) +from pyomo.core import Constraint as Constraint +from pyomo.core import NonNegativeIntegers as NonNegativeIntegers +from pyomo.core import Suffix as Suffix +from pyomo.core import Var as Var +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.gdp import Disjunct as Disjunct +from pyomo.gdp import Disjunction as Disjunction + +class InnerRepresentationGDPTransformation(PiecewiseLinearTransformationBase): + CONFIG: Incomplete diff --git a/stubs/pyomo/contrib/piecewise/transform/multiple_choice.pyi b/stubs/pyomo/contrib/piecewise/transform/multiple_choice.pyi new file mode 100644 index 000000000..865e75ae8 --- /dev/null +++ b/stubs/pyomo/contrib/piecewise/transform/multiple_choice.pyi @@ -0,0 +1,4 @@ +from pyomo.core.base import Transformation as Transformation +from pyomo.core.base import TransformationFactory as TransformationFactory + +class MultipleChoiceTransformation(Transformation): ... diff --git a/stubs/pyomo/contrib/piecewise/transform/nested_inner_repn.pyi b/stubs/pyomo/contrib/piecewise/transform/nested_inner_repn.pyi new file mode 100644 index 000000000..37d0e9107 --- /dev/null +++ b/stubs/pyomo/contrib/piecewise/transform/nested_inner_repn.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from pyomo.common.errors import DeveloperError as DeveloperError +from pyomo.contrib.fbbt.fbbt import compute_bounds_on_expr as compute_bounds_on_expr +from pyomo.contrib.piecewise.transform.piecewise_linear_transformation_base import ( + PiecewiseLinearTransformationBase as PiecewiseLinearTransformationBase, +) +from pyomo.core import Constraint as Constraint +from pyomo.core import NonNegativeIntegers as NonNegativeIntegers +from pyomo.core import Suffix as Suffix +from pyomo.core import Var as Var +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.gdp import Disjunction as Disjunction + +class NestedInnerRepresentationGDPTransformation(PiecewiseLinearTransformationBase): + CONFIG: Incomplete diff --git a/stubs/pyomo/contrib/piecewise/transform/nonlinear_to_pwl.pyi b/stubs/pyomo/contrib/piecewise/transform/nonlinear_to_pwl.pyi new file mode 100644 index 000000000..d09f46411 --- /dev/null +++ b/stubs/pyomo/contrib/piecewise/transform/nonlinear_to_pwl.pyi @@ -0,0 +1,69 @@ +from _typeshed import Incomplete +from pyomo.common.autoslots import AutoSlots as AutoSlots +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import InEnum as InEnum +from pyomo.common.config import PositiveInt as PositiveInt +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.enums import IntEnum as IntEnum +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.contrib.piecewise import PiecewiseLinearExpression as PiecewiseLinearExpression +from pyomo.contrib.piecewise import PiecewiseLinearFunction as PiecewiseLinearFunction +from pyomo.core.expr import SumExpression as SumExpression +from pyomo.core.expr import identify_variables as identify_variables +from pyomo.core.util import target_list as target_list +from pyomo.environ import Any as Any +from pyomo.environ import Block as Block +from pyomo.environ import BooleanVar as BooleanVar +from pyomo.environ import Connector as Connector +from pyomo.environ import Constraint as Constraint +from pyomo.environ import Expression as Expression +from pyomo.environ import ExternalFunction as ExternalFunction +from pyomo.environ import LogicalConstraint as LogicalConstraint +from pyomo.environ import Objective as Objective +from pyomo.environ import Param as Param +from pyomo.environ import RangeSet as RangeSet +from pyomo.environ import Set as Set +from pyomo.environ import SetOf as SetOf +from pyomo.environ import SortComponents as SortComponents +from pyomo.environ import Suffix as Suffix +from pyomo.environ import Transformation as Transformation +from pyomo.environ import TransformationFactory as TransformationFactory +from pyomo.environ import Var as Var +from pyomo.environ import value as value +from pyomo.gdp import Disjunct as Disjunct +from pyomo.gdp import Disjunction as Disjunction +from pyomo.network import Port as Port +from pyomo.repn.quadratic import QuadraticRepnVisitor as QuadraticRepnVisitor +from pyomo.repn.util import ExprType as ExprType + +lineartree: Incomplete +lineartree_available: Incomplete +sklearn_lm: Incomplete +sklearn_available: Incomplete +logger: Incomplete + +class DomainPartitioningMethod(IntEnum): + RANDOM_GRID = 1 + UNIFORM_GRID = 2 + LINEAR_MODEL_TREE_UNIFORM = 3 + LINEAR_MODEL_TREE_RANDOM = 4 + +class _NonlinearToPWLTransformationData(AutoSlots.Mixin): + transformed_component: Incomplete + src_component: Incomplete + transformed_constraints: Incomplete + transformed_objectives: Incomplete + def __init__(self) -> None: ... + +class NonlinearToPWL(Transformation): + CONFIG: Incomplete + def __init__(self) -> None: ... + def get_src_component(self, cons): ... + def get_transformed_component(self, cons): ... + def get_transformed_nonlinear_constraints(self, model): ... + def get_transformed_quadratic_constraints(self, model): ... + def get_transformed_nonlinear_objectives(self, model): ... + def get_transformed_quadratic_objectives(self, model): ... diff --git a/stubs/pyomo/contrib/piecewise/transform/outer_representation_gdp.pyi b/stubs/pyomo/contrib/piecewise/transform/outer_representation_gdp.pyi new file mode 100644 index 000000000..7809f17ed --- /dev/null +++ b/stubs/pyomo/contrib/piecewise/transform/outer_representation_gdp.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies.scipy import spatial as spatial +from pyomo.contrib.fbbt.fbbt import compute_bounds_on_expr as compute_bounds_on_expr +from pyomo.contrib.piecewise.transform.piecewise_linear_transformation_base import ( + PiecewiseLinearTransformationBase as PiecewiseLinearTransformationBase, +) +from pyomo.core import Constraint as Constraint +from pyomo.core import NonNegativeIntegers as NonNegativeIntegers +from pyomo.core import Suffix as Suffix +from pyomo.core import Var as Var +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.gdp import Disjunct as Disjunct +from pyomo.gdp import Disjunction as Disjunction + +class OuterRepresentationGDPTransformation(PiecewiseLinearTransformationBase): + CONFIG: Incomplete diff --git a/stubs/pyomo/contrib/piecewise/transform/piecewise_linear_transformation_base.pyi b/stubs/pyomo/contrib/piecewise/transform/piecewise_linear_transformation_base.pyi new file mode 100644 index 000000000..7e605ea6a --- /dev/null +++ b/stubs/pyomo/contrib/piecewise/transform/piecewise_linear_transformation_base.pyi @@ -0,0 +1,36 @@ +from _typeshed import Incomplete +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.errors import DeveloperError as DeveloperError +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.contrib.piecewise import PiecewiseLinearFunction as PiecewiseLinearFunction +from pyomo.contrib.piecewise.transform.piecewise_to_mip_visitor import ( + PiecewiseLinearToMIP as PiecewiseLinearToMIP, +) +from pyomo.core import Any as Any +from pyomo.core import BooleanVar as BooleanVar +from pyomo.core import Connector as Connector +from pyomo.core import Constraint as Constraint +from pyomo.core import Expression as Expression +from pyomo.core import ExternalFunction as ExternalFunction +from pyomo.core import LogicalConstraint as LogicalConstraint +from pyomo.core import Objective as Objective +from pyomo.core import Param as Param +from pyomo.core import RangeSet as RangeSet +from pyomo.core import Set as Set +from pyomo.core import SetOf as SetOf +from pyomo.core import SortComponents as SortComponents +from pyomo.core import Suffix as Suffix +from pyomo.core import Var as Var +from pyomo.core.base import Transformation as Transformation +from pyomo.core.base.block import Block as Block +from pyomo.core.util import target_list as target_list +from pyomo.gdp import Disjunct as Disjunct +from pyomo.gdp import Disjunction as Disjunction +from pyomo.gdp.util import is_child_of as is_child_of +from pyomo.network import Port as Port + +class PiecewiseLinearTransformationBase(Transformation): + CONFIG: Incomplete + handlers: Incomplete + def __init__(self) -> None: ... diff --git a/stubs/pyomo/contrib/piecewise/transform/piecewise_to_mip_visitor.pyi b/stubs/pyomo/contrib/piecewise/transform/piecewise_to_mip_visitor.pyi new file mode 100644 index 000000000..fd64ceed8 --- /dev/null +++ b/stubs/pyomo/contrib/piecewise/transform/piecewise_to_mip_visitor.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from pyomo.contrib.piecewise.piecewise_linear_expression import ( + PiecewiseLinearExpression as PiecewiseLinearExpression, +) +from pyomo.core import Expression as Expression +from pyomo.core.expr.visitor import StreamBasedExpressionVisitor as StreamBasedExpressionVisitor + +class PiecewiseLinearToMIP(StreamBasedExpressionVisitor): + transform_pw_linear_expression: Incomplete + transBlock: Incomplete + def __init__(self, transform_pw_linear_expression, transBlock) -> None: ... + def initializeWalker(self, expr): ... + def beforeChild(self, node, child, child_idx): ... + def exitNode(self, node, data): ... + finalizeResult: Incomplete diff --git a/stubs/pyomo/contrib/piecewise/transform/reduced_inner_representation_gdp.pyi b/stubs/pyomo/contrib/piecewise/transform/reduced_inner_representation_gdp.pyi new file mode 100644 index 000000000..24a7fc96f --- /dev/null +++ b/stubs/pyomo/contrib/piecewise/transform/reduced_inner_representation_gdp.pyi @@ -0,0 +1,14 @@ +from _typeshed import Incomplete +from pyomo.contrib.fbbt.fbbt import compute_bounds_on_expr as compute_bounds_on_expr +from pyomo.contrib.piecewise.transform.piecewise_linear_transformation_base import ( + PiecewiseLinearTransformationBase as PiecewiseLinearTransformationBase, +) +from pyomo.core import Constraint as Constraint +from pyomo.core import NonNegativeIntegers as NonNegativeIntegers +from pyomo.core import Var as Var +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.gdp import Disjunct as Disjunct +from pyomo.gdp import Disjunction as Disjunction + +class ReducedInnerRepresentationGDPTransformation(PiecewiseLinearTransformationBase): + CONFIG: Incomplete diff --git a/stubs/pyomo/contrib/piecewise/triangulations.pyi b/stubs/pyomo/contrib/piecewise/triangulations.pyi new file mode 100644 index 000000000..5688445ce --- /dev/null +++ b/stubs/pyomo/contrib/piecewise/triangulations.pyi @@ -0,0 +1,29 @@ +from enum import Enum + +from _typeshed import Incomplete +from pyomo.common.errors import DeveloperError as DeveloperError +from pyomo.contrib.piecewise.ordered_3d_j1_triangulation_data import ( + get_hamiltonian_paths as get_hamiltonian_paths, +) + +class Triangulation(Enum): + Unknown = 0 + AssumeValid = 1 + Delaunay = 2 + J1 = 3 + OrderedJ1 = 4 + +class _Triangulation: + points: Incomplete + simplices: Incomplete + coplanar: Incomplete + def __init__(self, points, simplices, coplanar) -> None: ... + +def get_unordered_j1_triangulation(points, dimension): ... +def get_ordered_j1_triangulation(points, dimension): ... + +class Direction(Enum): + left = 0 + down = 1 + up = 2 + right = 3 diff --git a/stubs/pyomo/contrib/preprocessing/__init__.pyi b/stubs/pyomo/contrib/preprocessing/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/preprocessing/plugins/__init__.pyi b/stubs/pyomo/contrib/preprocessing/plugins/__init__.pyi new file mode 100644 index 000000000..08b671c7f --- /dev/null +++ b/stubs/pyomo/contrib/preprocessing/plugins/__init__.pyi @@ -0,0 +1 @@ +def load() -> None: ... diff --git a/stubs/pyomo/contrib/preprocessing/plugins/bounds_to_vars.pyi b/stubs/pyomo/contrib/preprocessing/plugins/bounds_to_vars.pyi new file mode 100644 index 000000000..0dce56ceb --- /dev/null +++ b/stubs/pyomo/contrib/preprocessing/plugins/bounds_to_vars.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import NonNegativeFloat as NonNegativeFloat +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.core.base.constraint import Constraint as Constraint +from pyomo.core.base.transformation import TransformationFactory as TransformationFactory +from pyomo.core.expr.numvalue import value as value +from pyomo.core.plugins.transform.hierarchy import ( + IsomorphicTransformation as IsomorphicTransformation, +) +from pyomo.repn import generate_standard_repn as generate_standard_repn + +class ConstraintToVarBoundTransform(IsomorphicTransformation): + CONFIG: Incomplete diff --git a/stubs/pyomo/contrib/preprocessing/plugins/constraint_tightener.pyi b/stubs/pyomo/contrib/preprocessing/plugins/constraint_tightener.pyi new file mode 100644 index 000000000..c39704ff7 --- /dev/null +++ b/stubs/pyomo/contrib/preprocessing/plugins/constraint_tightener.pyi @@ -0,0 +1,14 @@ +from _typeshed import Incomplete +from pyomo.common import deprecated as deprecated +from pyomo.core import Constraint as Constraint +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core import value as value +from pyomo.core.plugins.transform.hierarchy import ( + IsomorphicTransformation as IsomorphicTransformation, +) +from pyomo.repn.standard_repn import generate_standard_repn as generate_standard_repn + +logger: Incomplete + +class TightenConstraintFromVars(IsomorphicTransformation): + def __init__(self) -> None: ... diff --git a/stubs/pyomo/contrib/preprocessing/plugins/deactivate_trivial_constraints.pyi b/stubs/pyomo/contrib/preprocessing/plugins/deactivate_trivial_constraints.pyi new file mode 100644 index 000000000..04e7e168e --- /dev/null +++ b/stubs/pyomo/contrib/preprocessing/plugins/deactivate_trivial_constraints.pyi @@ -0,0 +1,20 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import NonNegativeFloat as NonNegativeFloat +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.common.errors import InfeasibleConstraintException as InfeasibleConstraintException +from pyomo.core.base.constraint import Constraint as Constraint +from pyomo.core.base.transformation import TransformationFactory as TransformationFactory +from pyomo.core.expr.numvalue import value as value +from pyomo.core.plugins.transform.hierarchy import ( + IsomorphicTransformation as IsomorphicTransformation, +) +from pyomo.repn import generate_standard_repn as generate_standard_repn + +logger: Incomplete + +class TrivialConstraintDeactivator(IsomorphicTransformation): + CONFIG: Incomplete + def revert(self, instance) -> None: ... diff --git a/stubs/pyomo/contrib/preprocessing/plugins/detect_fixed_vars.pyi b/stubs/pyomo/contrib/preprocessing/plugins/detect_fixed_vars.pyi new file mode 100644 index 000000000..81d31576b --- /dev/null +++ b/stubs/pyomo/contrib/preprocessing/plugins/detect_fixed_vars.pyi @@ -0,0 +1,18 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import NonNegativeFloat as NonNegativeFloat +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.core.base.block import Block as Block +from pyomo.core.base.transformation import TransformationFactory as TransformationFactory +from pyomo.core.base.var import Var as Var +from pyomo.core.expr.numvalue import value as value +from pyomo.core.plugins.transform.hierarchy import ( + IsomorphicTransformation as IsomorphicTransformation, +) +from pyomo.gdp import Disjunct as Disjunct + +class FixedVarDetector(IsomorphicTransformation): + CONFIG: Incomplete + def revert(self, instance) -> None: ... diff --git a/stubs/pyomo/contrib/preprocessing/plugins/equality_propagate.pyi b/stubs/pyomo/contrib/preprocessing/plugins/equality_propagate.pyi new file mode 100644 index 000000000..cc04699a5 --- /dev/null +++ b/stubs/pyomo/contrib/preprocessing/plugins/equality_propagate.pyi @@ -0,0 +1,23 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.common.errors import InfeasibleConstraintException as InfeasibleConstraintException +from pyomo.core.base.constraint import Constraint as Constraint +from pyomo.core.base.suffix import Suffix as Suffix +from pyomo.core.base.transformation import TransformationFactory as TransformationFactory +from pyomo.core.expr.numvalue import value as value +from pyomo.core.plugins.transform.hierarchy import ( + IsomorphicTransformation as IsomorphicTransformation, +) +from pyomo.repn.standard_repn import generate_standard_repn as generate_standard_repn + +class FixedVarPropagator(IsomorphicTransformation): + CONFIG: Incomplete + def revert(self, instance) -> None: ... + +class VarBoundPropagator(IsomorphicTransformation): + CONFIG: Incomplete + def revert(self, instance) -> None: ... diff --git a/stubs/pyomo/contrib/preprocessing/plugins/induced_linearity.pyi b/stubs/pyomo/contrib/preprocessing/plugins/induced_linearity.pyi new file mode 100644 index 000000000..70bd7fcd7 --- /dev/null +++ b/stubs/pyomo/contrib/preprocessing/plugins/induced_linearity.pyi @@ -0,0 +1,37 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import NonNegativeFloat as NonNegativeFloat +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.contrib.preprocessing.util import ( + SuppressConstantObjectiveWarning as SuppressConstantObjectiveWarning, +) +from pyomo.core import Binary as Binary +from pyomo.core import Block as Block +from pyomo.core import Constraint as Constraint +from pyomo.core import Objective as Objective +from pyomo.core import Set as Set +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core import Var as Var +from pyomo.core import summation as summation +from pyomo.core import value as value +from pyomo.core.plugins.transform.hierarchy import ( + IsomorphicTransformation as IsomorphicTransformation, +) +from pyomo.gdp import Disjunct as Disjunct +from pyomo.gdp import Disjunction as Disjunction +from pyomo.opt import SolverFactory as SolverFactory +from pyomo.repn import generate_standard_repn as generate_standard_repn + +logger: Incomplete + +class InducedLinearity(IsomorphicTransformation): + CONFIG: Incomplete + +def determine_valid_values(block, discr_var_to_constrs_map, config): ... +def prune_possible_values(block_scope, possible_values, config): ... +def zero_if_None(val): ... +def detect_effectively_discrete_vars(block, equality_tolerance): ... diff --git a/stubs/pyomo/contrib/preprocessing/plugins/init_vars.pyi b/stubs/pyomo/contrib/preprocessing/plugins/init_vars.pyi new file mode 100644 index 000000000..31494cbce --- /dev/null +++ b/stubs/pyomo/contrib/preprocessing/plugins/init_vars.pyi @@ -0,0 +1,9 @@ +from pyomo.core.base.transformation import TransformationFactory as TransformationFactory +from pyomo.core.base.var import Var as Var +from pyomo.core.expr.numvalue import value as value +from pyomo.core.plugins.transform.hierarchy import ( + IsomorphicTransformation as IsomorphicTransformation, +) + +class InitMidpoint(IsomorphicTransformation): ... +class InitZero(IsomorphicTransformation): ... diff --git a/stubs/pyomo/contrib/preprocessing/plugins/int_to_binary.pyi b/stubs/pyomo/contrib/preprocessing/plugins/int_to_binary.pyi new file mode 100644 index 000000000..1525c6948 --- /dev/null +++ b/stubs/pyomo/contrib/preprocessing/plugins/int_to_binary.pyi @@ -0,0 +1,25 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import In as In +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.core import Any as Any +from pyomo.core import Binary as Binary +from pyomo.core import Block as Block +from pyomo.core import Constraint as Constraint +from pyomo.core import RangeSet as RangeSet +from pyomo.core import Reals as Reals +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core import Var as Var +from pyomo.core import value as value +from pyomo.core.expr import identify_variables as identify_variables +from pyomo.core.plugins.transform.hierarchy import ( + IsomorphicTransformation as IsomorphicTransformation, +) +from pyomo.gdp import Disjunct as Disjunct + +logger: Incomplete + +class IntegerToBinary(IsomorphicTransformation): + CONFIG: Incomplete diff --git a/stubs/pyomo/contrib/preprocessing/plugins/remove_zero_terms.pyi b/stubs/pyomo/contrib/preprocessing/plugins/remove_zero_terms.pyi new file mode 100644 index 000000000..7ea4ba762 --- /dev/null +++ b/stubs/pyomo/contrib/preprocessing/plugins/remove_zero_terms.pyi @@ -0,0 +1,13 @@ +from _typeshed import Incomplete +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.core import quicksum as quicksum +from pyomo.core.base.constraint import Constraint as Constraint +from pyomo.core.base.transformation import TransformationFactory as TransformationFactory +from pyomo.core.plugins.transform.hierarchy import ( + IsomorphicTransformation as IsomorphicTransformation, +) +from pyomo.repn import generate_standard_repn as generate_standard_repn + +class RemoveZeroTerms(IsomorphicTransformation): + CONFIG: Incomplete diff --git a/stubs/pyomo/contrib/preprocessing/plugins/strip_bounds.pyi b/stubs/pyomo/contrib/preprocessing/plugins/strip_bounds.pyi new file mode 100644 index 000000000..38575caa8 --- /dev/null +++ b/stubs/pyomo/contrib/preprocessing/plugins/strip_bounds.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.core.base.set_types import Reals as Reals +from pyomo.core.base.transformation import TransformationFactory as TransformationFactory +from pyomo.core.base.var import Var as Var +from pyomo.core.plugins.transform.hierarchy import ( + NonIsomorphicTransformation as NonIsomorphicTransformation, +) + +class VariableBoundStripper(NonIsomorphicTransformation): + CONFIG: Incomplete + def revert(self, instance) -> None: ... diff --git a/stubs/pyomo/contrib/preprocessing/plugins/var_aggregator.pyi b/stubs/pyomo/contrib/preprocessing/plugins/var_aggregator.pyi new file mode 100644 index 000000000..340fdfd48 --- /dev/null +++ b/stubs/pyomo/contrib/preprocessing/plugins/var_aggregator.pyi @@ -0,0 +1,23 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.core.base import Block as Block +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import Objective as Objective +from pyomo.core.base import Reals as Reals +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.core.base import VarList as VarList +from pyomo.core.expr import ExpressionReplacementVisitor as ExpressionReplacementVisitor +from pyomo.core.expr.numvalue import value as value +from pyomo.core.plugins.transform.hierarchy import ( + IsomorphicTransformation as IsomorphicTransformation, +) +from pyomo.repn import generate_standard_repn as generate_standard_repn + +logger: Incomplete + +def min_if_not_None(iterable): ... +def max_if_not_None(iterable): ... + +class VariableAggregator(IsomorphicTransformation): + def update_variables(self, model) -> None: ... diff --git a/stubs/pyomo/contrib/preprocessing/plugins/zero_sum_propagator.pyi b/stubs/pyomo/contrib/preprocessing/plugins/zero_sum_propagator.pyi new file mode 100644 index 000000000..7c8340652 --- /dev/null +++ b/stubs/pyomo/contrib/preprocessing/plugins/zero_sum_propagator.pyi @@ -0,0 +1,9 @@ +from pyomo.core.base.constraint import Constraint as Constraint +from pyomo.core.base.transformation import TransformationFactory as TransformationFactory +from pyomo.core.expr.numvalue import value as value +from pyomo.core.plugins.transform.hierarchy import ( + IsomorphicTransformation as IsomorphicTransformation, +) +from pyomo.repn.standard_repn import generate_standard_repn as generate_standard_repn + +class ZeroSumPropagator(IsomorphicTransformation): ... diff --git a/stubs/pyomo/contrib/preprocessing/util.pyi b/stubs/pyomo/contrib/preprocessing/util.pyi new file mode 100644 index 000000000..6d6b50d1e --- /dev/null +++ b/stubs/pyomo/contrib/preprocessing/util.pyi @@ -0,0 +1,4 @@ +from pyomo.common.log import LoggingIntercept as LoggingIntercept + +class SuppressConstantObjectiveWarning(LoggingIntercept): + def __init__(self) -> None: ... diff --git a/stubs/pyomo/contrib/pynumero/__init__.pyi b/stubs/pyomo/contrib/pynumero/__init__.pyi new file mode 100644 index 000000000..6688e2ba5 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/__init__.pyi @@ -0,0 +1,6 @@ +from .intrinsic import allclose as allclose +from .intrinsic import intersect1d as intersect1d +from .intrinsic import isin as isin +from .intrinsic import norm as norm +from .intrinsic import setdiff1d as setdiff1d +from .intrinsic import where as where diff --git a/stubs/pyomo/contrib/pynumero/algorithms/__init__.pyi b/stubs/pyomo/contrib/pynumero/algorithms/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/pynumero/algorithms/solvers/__init__.pyi b/stubs/pyomo/contrib/pynumero/algorithms/solvers/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/pynumero/algorithms/solvers/cyipopt_solver.pyi b/stubs/pyomo/contrib/pynumero/algorithms/solvers/cyipopt_solver.pyi new file mode 100644 index 000000000..9a979b674 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/algorithms/solvers/cyipopt_solver.pyi @@ -0,0 +1,45 @@ +import types + +from _typeshed import Incomplete +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.dependencies import numpy_available as numpy_available +from pyomo.common.deprecation import relocated_module_attribute as relocated_module_attribute +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.common.tee import capture_output as capture_output +from pyomo.common.timing import TicTocTimer as TicTocTimer +from pyomo.core.base import Block as Block +from pyomo.core.base import Objective as Objective +from pyomo.core.base import minimize as minimize +from pyomo.opt import SolverResults as SolverResults +from pyomo.opt import SolverStatus as SolverStatus +from pyomo.opt import TerminationCondition as TerminationCondition +from pyomo.opt.results.solution import Solution as Solution + +pyomo_nlp: Incomplete +pyomo_grey_box: Incomplete +egb: Incomplete +cyipopt_interface: Incomplete +_: Incomplete +logger: Incomplete + +class CyIpoptSolver: + def __init__(self, problem_interface, options=None) -> None: ... + def solve(self, x0=None, tee: bool = False): ... + +class PyomoCyIpoptSolver: + CONFIG: Incomplete + config: Incomplete + def __init__(self, **kwds) -> None: ... + def available(self, exception_flag: bool = False): ... + def license_is_valid(self): ... + def version(self): ... + def solve(self, model, **kwds): ... + def __enter__(self): ... + def __exit__( + self, + t: type[BaseException] | None, + v: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: ... diff --git a/stubs/pyomo/contrib/pynumero/algorithms/solvers/implicit_functions.pyi b/stubs/pyomo/contrib/pynumero/algorithms/solvers/implicit_functions.pyi new file mode 100644 index 000000000..eb7243955 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/algorithms/solvers/implicit_functions.pyi @@ -0,0 +1,82 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.timing import HierarchicalTimer as HierarchicalTimer +from pyomo.contrib.incidence_analysis import IncidenceGraphInterface as IncidenceGraphInterface +from pyomo.contrib.incidence_analysis.scc_solver import ( + generate_strongly_connected_components as generate_strongly_connected_components, +) +from pyomo.contrib.pynumero.algorithms.solvers.cyipopt_solver import CyIpoptSolver as CyIpoptSolver +from pyomo.contrib.pynumero.algorithms.solvers.scipy_solvers import ( + FsolveNlpSolver as FsolveNlpSolver, +) +from pyomo.contrib.pynumero.algorithms.solvers.scipy_solvers import ( + NewtonNlpSolver as NewtonNlpSolver, +) +from pyomo.contrib.pynumero.algorithms.solvers.scipy_solvers import ( + SecantNewtonNlpSolver as SecantNewtonNlpSolver, +) +from pyomo.contrib.pynumero.interfaces.cyipopt_interface import CyIpoptNLP as CyIpoptNLP +from pyomo.core.base.objective import Objective as Objective +from pyomo.core.base.suffix import Suffix as Suffix +from pyomo.core.expr.visitor import identify_variables as identify_variables +from pyomo.util.calc_var_value import ( + calculate_variable_from_constraint as calculate_variable_from_constraint, +) +from pyomo.util.subsystems import TemporarySubsystemManager as TemporarySubsystemManager +from pyomo.util.subsystems import create_subsystem_block as create_subsystem_block +from pyomo.util.subsystems import generate_subsystem_blocks as generate_subsystem_blocks + +pyomo_nlp: Incomplete +nlp_proj: Incomplete + +class NlpSolverBase: + def __init__(self, nlp, options=None, timer=None) -> None: ... + def solve(self, **kwds) -> None: ... + +class CyIpoptSolverWrapper(NlpSolverBase): + def __init__(self, nlp, options=None, timer=None) -> None: ... + def solve(self, **kwds): ... + +class ScipySolverWrapper(NlpSolverBase): + def __init__(self, nlp, timer=None, options=None) -> None: ... + def solve(self, x0=None): ... + +class PyomoImplicitFunctionBase: + def __init__(self, variables, constraints, parameters) -> None: ... + def get_variables(self): ... + def get_constraints(self): ... + def get_parameters(self): ... + def get_block(self): ... + def set_parameters(self, values) -> None: ... + def evaluate_outputs(self) -> None: ... + def update_pyomo_model(self) -> None: ... + +class ImplicitFunctionSolver(PyomoImplicitFunctionBase): + def __init__( + self, variables, constraints, parameters, solver_class=None, solver_options=None, timer=None + ) -> None: ... + def set_parameters(self, values, **kwds): ... + def evaluate_outputs(self): ... + def update_pyomo_model(self) -> None: ... + +class DecomposedImplicitFunctionBase(PyomoImplicitFunctionBase): + def __init__( + self, + variables, + constraints, + parameters, + solver_class=None, + solver_options=None, + timer=None, + use_calc_var: bool = True, + ) -> None: ... + def n_subsystems(self): ... + def partition_system(self, variables, constraints) -> None: ... + def set_parameters(self, values) -> None: ... + def evaluate_outputs(self): ... + def update_pyomo_model(self) -> None: ... + +class SccImplicitFunctionSolver(DecomposedImplicitFunctionBase): + def partition_system(self, variables, constraints): ... diff --git a/stubs/pyomo/contrib/pynumero/algorithms/solvers/pyomo_ext_cyipopt.pyi b/stubs/pyomo/contrib/pynumero/algorithms/solvers/pyomo_ext_cyipopt.pyi new file mode 100644 index 000000000..c4b0aa496 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/algorithms/solvers/pyomo_ext_cyipopt.pyi @@ -0,0 +1,46 @@ +import abc + +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.contrib.pynumero.interfaces.cyipopt_interface import ( + CyIpoptProblemInterface as CyIpoptProblemInterface, +) +from pyomo.contrib.pynumero.interfaces.pyomo_nlp import PyomoNLP as PyomoNLP +from pyomo.contrib.pynumero.sparse.block_vector import BlockVector as BlockVector +from pyomo.core.base.var import VarData as VarData +from pyomo.environ import Constraint as Constraint +from pyomo.environ import Var as Var +from pyomo.environ import value as value + +class ExternalInputOutputModel(metaclass=abc.ABCMeta): + def __init__(self) -> None: ... + @abc.abstractmethod + def set_inputs(self, input_values): ... + @abc.abstractmethod + def evaluate_outputs(self): ... + @abc.abstractmethod + def evaluate_derivatives(self): ... + +class PyomoExternalCyIpoptProblem(CyIpoptProblemInterface): + def __init__( + self, + pyomo_model, + ex_input_output_model, + inputs, + outputs, + outputs_eqn_scaling=None, + nl_file_options=None, + ) -> None: ... + def load_x_into_pyomo(self, primals) -> None: ... + def x_init(self): ... + def x_lb(self): ... + def x_ub(self): ... + def g_lb(self): ... + def g_ub(self): ... + def scaling_factors(self): ... + def objective(self, primals): ... + def gradient(self, primals): ... + def constraints(self, primals): ... + def jacobianstructure(self): ... + def jacobian(self, primals): ... + def hessianstructure(self): ... + def hessian(self, x, y, obj_factor) -> None: ... diff --git a/stubs/pyomo/contrib/pynumero/algorithms/solvers/scipy_solvers.pyi b/stubs/pyomo/contrib/pynumero/algorithms/solvers/scipy_solvers.pyi new file mode 100644 index 000000000..f836b5ab6 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/algorithms/solvers/scipy_solvers.pyi @@ -0,0 +1,77 @@ +import types +from collections import namedtuple as namedtuple + +from _typeshed import Incomplete +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import In as In +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.dependencies import numpy_available as numpy_available +from pyomo.common.dependencies import scipy_available as scipy_available +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.common.timing import HierarchicalTimer as HierarchicalTimer +from pyomo.contrib.pynumero.algorithms.solvers.square_solver_base import ( + DenseSquareNlpSolver as DenseSquareNlpSolver, +) +from pyomo.contrib.pynumero.algorithms.solvers.square_solver_base import ( + ScalarDenseSquareNlpSolver as ScalarDenseSquareNlpSolver, +) +from pyomo.core.base.objective import Objective as Objective +from pyomo.opt import SolverResults as SolverResults +from pyomo.opt import TerminationCondition as TerminationCondition + +pyomo_nlp: Incomplete +_: Incomplete + +class FsolveNlpSolver(DenseSquareNlpSolver): + OPTIONS: Incomplete + def solve(self, x0=None): ... + +class RootNlpSolver(DenseSquareNlpSolver): + OPTIONS: Incomplete + def solve(self, x0=None): ... + +class NewtonNlpSolver(ScalarDenseSquareNlpSolver): + OPTIONS: Incomplete + def solve(self, x0=None): ... + +class SecantNewtonNlpSolver(NewtonNlpSolver): + OPTIONS: Incomplete + converged_with_secant: Incomplete + def __init__(self, nlp, timer=None, options=None) -> None: ... + def solve(self, x0=None): ... + +class PyomoScipySolver: + options: Incomplete + def __init__(self, options=None) -> None: ... + def available(self, exception_flag: bool = False): ... + def license_is_valid(self): ... + def version(self): ... + def set_options(self, options) -> None: ... + def solve(self, model, timer=None, tee: bool = False): ... + def get_nlp(self): ... + def create_nlp_solver(self, **kwds) -> None: ... + def get_pyomo_results(self, model, scipy_results) -> None: ... + def __enter__(self): ... + def __exit__( + self, + t: type[BaseException] | None, + v: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: ... + +class PyomoFsolveSolver(PyomoScipySolver): + def create_nlp_solver(self, **kwds): ... + def get_pyomo_results(self, model, scipy_results): ... + +class PyomoRootSolver(PyomoScipySolver): + def create_nlp_solver(self, **kwds): ... + def get_pyomo_results(self, model, scipy_results): ... + +class PyomoNewtonSolver(PyomoScipySolver): + def create_nlp_solver(self, **kwds): ... + def get_pyomo_results(self, model, scipy_results): ... + +class PyomoSecantNewtonSolver(PyomoNewtonSolver): + def converged_with_secant(self): ... + def create_nlp_solver(self, **kwds): ... diff --git a/stubs/pyomo/contrib/pynumero/algorithms/solvers/square_solver_base.pyi b/stubs/pyomo/contrib/pynumero/algorithms/solvers/square_solver_base.pyi new file mode 100644 index 000000000..500ee2ee9 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/algorithms/solvers/square_solver_base.pyi @@ -0,0 +1,20 @@ +from collections import namedtuple as namedtuple + +from _typeshed import Incomplete +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.timing import HierarchicalTimer as HierarchicalTimer +from pyomo.util.subsystems import create_subsystem_block as create_subsystem_block + +class SquareNlpSolverBase: + OPTIONS: Incomplete + options: Incomplete + def __init__(self, nlp, timer=None, options=None) -> None: ... + def solve(self, x0=None) -> None: ... + def evaluate_function(self, x0): ... + def evaluate_jacobian(self, x0): ... + +class DenseSquareNlpSolver(SquareNlpSolverBase): + def evaluate_jacobian(self, x0): ... + +class ScalarDenseSquareNlpSolver(DenseSquareNlpSolver): + def __init__(self, nlp, timer=None, options=None) -> None: ... diff --git a/stubs/pyomo/contrib/pynumero/asl.pyi b/stubs/pyomo/contrib/pynumero/asl.pyi new file mode 100644 index 000000000..53c7281a0 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/asl.pyi @@ -0,0 +1,37 @@ +from _typeshed import Incomplete +from pyomo.common.fileutils import find_library as find_library +from pyomo.contrib.pynumero.exceptions import PyNumeroEvaluationError as PyNumeroEvaluationError + +logger: Incomplete +CURRENT_INTERFACE_VERSION: int + +class _NotSet: ... + +class AmplInterface: + libname: Incomplete + ASLib: Incomplete + interface_version: Incomplete + asl_date: Incomplete + @classmethod + def available(cls): ... + def __init__(self, filename=None, nl_buffer=None) -> None: ... + def __del__(self) -> None: ... + def get_n_vars(self): ... + def get_n_constraints(self): ... + def get_nnz_jac_g(self): ... + def get_nnz_hessian_lag(self): ... + def get_bounds_info(self, xl, xu, gl, gu) -> None: ... + def get_x_lower_bounds(self, invec) -> None: ... + def get_x_upper_bounds(self, invec) -> None: ... + def get_g_lower_bounds(self, invec) -> None: ... + def get_g_upper_bounds(self, invec) -> None: ... + def get_init_x(self, invec) -> None: ... + def get_init_multipliers(self, invec) -> None: ... + def eval_f(self, x): ... + def eval_deriv_f(self, x, df) -> None: ... + def struct_jac_g(self, irow, jcol) -> None: ... + def struct_hes_lag(self, irow, jcol) -> None: ... + def eval_jac_g(self, x, jac_g_values) -> None: ... + def eval_g(self, x, g) -> None: ... + def eval_hes_lag(self, x, lam, hes_lag, obj_factor: float = 1.0) -> None: ... + def finalize_solution(self, ampl_solve_status_num, msg, x, lam) -> None: ... diff --git a/stubs/pyomo/contrib/pynumero/build.pyi b/stubs/pyomo/contrib/pynumero/build.pyi new file mode 100644 index 000000000..b703e6e5c --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/build.pyi @@ -0,0 +1,6 @@ +from pyomo.common.cmake_builder import build_cmake_project as build_cmake_project + +def build_pynumero(user_args=[], parallel=None): ... + +class PyNumeroBuilder: + def __call__(self, parallel): ... diff --git a/stubs/pyomo/contrib/pynumero/dependencies.pyi b/stubs/pyomo/contrib/pynumero/dependencies.pyi new file mode 100644 index 000000000..3dc179abb --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/dependencies.pyi @@ -0,0 +1,7 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.dependencies import scipy as scipy +from pyomo.common.dependencies import scipy_available as scipy_available + +numpy: Incomplete +numpy_available: Incomplete diff --git a/stubs/pyomo/contrib/pynumero/examples/__init__.pyi b/stubs/pyomo/contrib/pynumero/examples/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/pynumero/examples/callback/__init__.pyi b/stubs/pyomo/contrib/pynumero/examples/callback/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/pynumero/examples/callback/cyipopt_callback.pyi b/stubs/pyomo/contrib/pynumero/examples/callback/cyipopt_callback.pyi new file mode 100644 index 000000000..d4c67f1ab --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/examples/callback/cyipopt_callback.pyi @@ -0,0 +1,15 @@ +def iteration_callback( + nlp, + alg_mod, + iter_count, + obj_value, + inf_pr, + inf_du, + mu, + d_norm, + regularization_size, + alpha_du, + alpha_pr, + ls_trials, +) -> None: ... +def main() -> None: ... diff --git a/stubs/pyomo/contrib/pynumero/examples/callback/cyipopt_callback_halt.pyi b/stubs/pyomo/contrib/pynumero/examples/callback/cyipopt_callback_halt.pyi new file mode 100644 index 000000000..469113051 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/examples/callback/cyipopt_callback_halt.pyi @@ -0,0 +1,15 @@ +def iteration_callback( + nlp, + alg_mod, + iter_count, + obj_value, + inf_pr, + inf_du, + mu, + d_norm, + regularization_size, + alpha_du, + alpha_pr, + ls_trials, +): ... +def main(): ... diff --git a/stubs/pyomo/contrib/pynumero/examples/callback/cyipopt_functor_callback.pyi b/stubs/pyomo/contrib/pynumero/examples/callback/cyipopt_functor_callback.pyi new file mode 100644 index 000000000..410d9baa3 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/examples/callback/cyipopt_functor_callback.pyi @@ -0,0 +1,20 @@ +class ResidualsTableCallback: + def __init__(self) -> None: ... + def __call__( + self, + nlp, + alg_mod, + iter_count, + obj_value, + inf_pr, + inf_du, + mu, + d_norm, + regularization_size, + alpha_du, + alpha_pr, + ls_trials, + ) -> None: ... + def get_residual_dataframe(self): ... + +def main(): ... diff --git a/stubs/pyomo/contrib/pynumero/examples/callback/reactor_design.pyi b/stubs/pyomo/contrib/pynumero/examples/callback/reactor_design.pyi new file mode 100644 index 000000000..69e59b2e0 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/examples/callback/reactor_design.pyi @@ -0,0 +1,8 @@ +from _typeshed import Incomplete +from pyomo.core import * + +model: Incomplete +k1: Incomplete +k2: Incomplete +k3: Incomplete +caf: float diff --git a/stubs/pyomo/contrib/pynumero/examples/external_grey_box/__init__.pyi b/stubs/pyomo/contrib/pynumero/examples/external_grey_box/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/pynumero/examples/external_grey_box/external_with_objective.pyi b/stubs/pyomo/contrib/pynumero/examples/external_grey_box/external_with_objective.pyi new file mode 100644 index 000000000..13ca053d3 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/examples/external_grey_box/external_with_objective.pyi @@ -0,0 +1,32 @@ +from pyomo.contrib.pynumero.interfaces.external_grey_box import ( + ExternalGreyBoxBlock as ExternalGreyBoxBlock, +) +from pyomo.contrib.pynumero.interfaces.external_grey_box import ( + ExternalGreyBoxModel as ExternalGreyBoxModel, +) + +class Unconstrained(ExternalGreyBoxModel): + def input_names(self): ... + def set_input_values(self, input_values) -> None: ... + def has_objective(self): ... + def evaluate_objective(self): ... + def evaluate_grad_objective(self): ... + +class Constrained(ExternalGreyBoxModel): + def input_names(self): ... + def set_input_values(self, input_values) -> None: ... + def has_objective(self): ... + def evaluate_objective(self): ... + def evaluate_grad_objective(self): ... + def equality_constraint_names(self): ... + def evaluate_equality_constraints(self): ... + def evaluate_jacobian_equality_constraints(self): ... + +class ConstrainedWithHessian(Constrained): + def evaluate_hessian_objective(self): ... + def set_equality_constraint_multipliers(self, eq_con_multiplier_values) -> None: ... + def evaluate_hessian_equality_constraints(self): ... + +def solve_unconstrained(): ... +def solve_constrained(): ... +def solve_constrained_with_hessian(): ... diff --git a/stubs/pyomo/contrib/pynumero/examples/external_grey_box/param_est/__init__.pyi b/stubs/pyomo/contrib/pynumero/examples/external_grey_box/param_est/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/pynumero/examples/external_grey_box/param_est/generate_data.pyi b/stubs/pyomo/contrib/pynumero/examples/external_grey_box/param_est/generate_data.pyi new file mode 100644 index 000000000..0c68ad346 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/examples/external_grey_box/param_est/generate_data.pyi @@ -0,0 +1,2 @@ +def generate_data(N, UA_mean, UA_std, seed: int = 42): ... +def generate_data_external(N, UA_mean, UA_std, seed: int = 42): ... diff --git a/stubs/pyomo/contrib/pynumero/examples/external_grey_box/param_est/models.pyi b/stubs/pyomo/contrib/pynumero/examples/external_grey_box/param_est/models.pyi new file mode 100644 index 000000000..41c54915f --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/examples/external_grey_box/param_est/models.pyi @@ -0,0 +1,24 @@ +from pyomo.contrib.pynumero.interfaces.external_grey_box import ( + ExternalGreyBoxBlock as ExternalGreyBoxBlock, +) +from pyomo.contrib.pynumero.interfaces.external_grey_box import ( + ExternalGreyBoxModel as ExternalGreyBoxModel, +) + +def build_single_point_model_pyomo_only(m) -> None: ... +def build_single_point_model_external(m) -> None: ... + +class UAModelExternal(ExternalGreyBoxModel): + def __init__(self) -> None: ... + def n_inputs(self): ... + def n_equality_constraints(self): ... + def n_outputs(self): ... + def input_names(self): ... + def equality_constraint_names(self): ... + def output_names(self): ... + def finalize_block_construction(self, pyomo_block) -> None: ... + def set_input_values(self, input_values) -> None: ... + def set_equality_constraint_multipliers(self, eq_con_multiplier_values) -> None: ... + def evaluate_equality_constraints(self): ... + def evaluate_jacobian_equality_constraints(self): ... + def evaluate_hessian_equality_constraints(self): ... diff --git a/stubs/pyomo/contrib/pynumero/examples/external_grey_box/param_est/perform_estimation.pyi b/stubs/pyomo/contrib/pynumero/examples/external_grey_box/param_est/perform_estimation.pyi new file mode 100644 index 000000000..7699f2d5d --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/examples/external_grey_box/param_est/perform_estimation.pyi @@ -0,0 +1,2 @@ +def perform_estimation_pyomo_only(data_fname, solver_trace: bool = False): ... +def perform_estimation_external(data_fname, solver_trace: bool = False): ... diff --git a/stubs/pyomo/contrib/pynumero/examples/external_grey_box/react_example/__init__.pyi b/stubs/pyomo/contrib/pynumero/examples/external_grey_box/react_example/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/pynumero/examples/external_grey_box/react_example/maximize_cb_outputs.pyi b/stubs/pyomo/contrib/pynumero/examples/external_grey_box/react_example/maximize_cb_outputs.pyi new file mode 100644 index 000000000..efd309eae --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/examples/external_grey_box/react_example/maximize_cb_outputs.pyi @@ -0,0 +1,8 @@ +from pyomo.contrib.pynumero.examples.external_grey_box.react_example.reactor_model_outputs import ( + ReactorConcentrationsOutputModel as ReactorConcentrationsOutputModel, +) +from pyomo.contrib.pynumero.interfaces.external_grey_box import ( + ExternalGreyBoxBlock as ExternalGreyBoxBlock, +) + +def maximize_cb_outputs(show_solver_log: bool = False): ... diff --git a/stubs/pyomo/contrib/pynumero/examples/external_grey_box/react_example/maximize_cb_ratio_residuals.pyi b/stubs/pyomo/contrib/pynumero/examples/external_grey_box/react_example/maximize_cb_ratio_residuals.pyi new file mode 100644 index 000000000..88d772ca0 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/examples/external_grey_box/react_example/maximize_cb_ratio_residuals.pyi @@ -0,0 +1,35 @@ +from pyomo.contrib.pynumero.examples.external_grey_box.react_example.reactor_model_residuals import ( + ReactorModel as ReactorModel, +) +from pyomo.contrib.pynumero.examples.external_grey_box.react_example.reactor_model_residuals import ( + ReactorModelNoOutputs as ReactorModelNoOutputs, +) +from pyomo.contrib.pynumero.examples.external_grey_box.react_example.reactor_model_residuals import ( + ReactorModelScaled as ReactorModelScaled, +) +from pyomo.contrib.pynumero.examples.external_grey_box.react_example.reactor_model_residuals import ( + ReactorModelWithHessian as ReactorModelWithHessian, +) +from pyomo.contrib.pynumero.examples.external_grey_box.react_example.reactor_model_residuals import ( + create_pyomo_reactor_model as create_pyomo_reactor_model, +) +from pyomo.contrib.pynumero.interfaces.external_grey_box import ( + ExternalGreyBoxBlock as ExternalGreyBoxBlock, +) + +def maximize_cb_ratio_residuals_with_output( + show_solver_log: bool = False, additional_options={} +): ... +def maximize_cb_ratio_residuals_with_hessian_with_output( + show_solver_log: bool = False, additional_options={} +): ... +def maximize_cb_ratio_residuals_with_hessian_with_output_pyomo( + show_solver_log: bool = False, additional_options={} +): ... +def maximize_cb_ratio_residuals_with_output_scaling( + show_solver_log: bool = False, additional_options={} +): ... +def maximize_cb_ratio_residuals_with_obj(show_solver_log: bool = False, additional_options={}): ... +def maximize_cb_ratio_residuals_with_pyomo_variables( + show_solver_log: bool = False, additional_options={} +): ... diff --git a/stubs/pyomo/contrib/pynumero/examples/external_grey_box/react_example/reactor_model_outputs.pyi b/stubs/pyomo/contrib/pynumero/examples/external_grey_box/react_example/reactor_model_outputs.pyi new file mode 100644 index 000000000..81223e517 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/examples/external_grey_box/react_example/reactor_model_outputs.pyi @@ -0,0 +1,13 @@ +from pyomo.contrib.pynumero.interfaces.external_grey_box import ( + ExternalGreyBoxModel as ExternalGreyBoxModel, +) + +def reactor_outlet_concentrations(sv, caf, k1, k2, k3): ... + +class ReactorConcentrationsOutputModel(ExternalGreyBoxModel): + def input_names(self): ... + def output_names(self): ... + def set_input_values(self, input_values) -> None: ... + def finalize_block_construction(self, pyomo_block) -> None: ... + def evaluate_outputs(self): ... + def evaluate_jacobian_outputs(self): ... diff --git a/stubs/pyomo/contrib/pynumero/examples/external_grey_box/react_example/reactor_model_residuals.pyi b/stubs/pyomo/contrib/pynumero/examples/external_grey_box/react_example/reactor_model_residuals.pyi new file mode 100644 index 000000000..b69c97920 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/examples/external_grey_box/react_example/reactor_model_residuals.pyi @@ -0,0 +1,48 @@ +from pyomo.contrib.pynumero.interfaces.external_grey_box import ( + ExternalGreyBoxModel as ExternalGreyBoxModel, +) + +def create_pyomo_reactor_model(): ... + +class ReactorModel(ExternalGreyBoxModel): + def __init__(self, use_exact_derivatives: bool = True) -> None: ... + def input_names(self): ... + def equality_constraint_names(self): ... + def output_names(self): ... + def finalize_block_construction(self, pyomo_block) -> None: ... + def set_input_values(self, input_values) -> None: ... + def evaluate_equality_constraints(self): ... + def evaluate_outputs(self): ... + def evaluate_jacobian_equality_constraints(self): ... + def evaluate_jacobian_outputs(self): ... + +class ReactorModelWithHessian(ReactorModel): + def __init__(self) -> None: ... + def set_equality_constraint_multipliers(self, eq_con_multiplier_values) -> None: ... + def set_output_constraint_multipliers(self, output_con_multiplier_values) -> None: ... + def evaluate_hessian_equality_constraints(self): ... + def evaluate_hessian_outputs(self): ... + +class ReactorModelNoOutputs(ExternalGreyBoxModel): + def input_names(self): ... + def equality_constraint_names(self): ... + def output_names(self): ... + def finalize_block_construction(self, pyomo_block) -> None: ... + def set_input_values(self, input_values) -> None: ... + def evaluate_equality_constraints(self): ... + def evaluate_outputs(self) -> None: ... + def evaluate_jacobian_equality_constraints(self): ... + def evaluate_jacobian_outputs(self) -> None: ... + +class ReactorModelScaled(ExternalGreyBoxModel): + def input_names(self): ... + def equality_constraint_names(self): ... + def output_names(self): ... + def finalize_block_construction(self, pyomo_block) -> None: ... + def get_equality_constraint_scaling_factors(self): ... + def get_output_constraint_scaling_factors(self): ... + def set_input_values(self, input_values) -> None: ... + def evaluate_equality_constraints(self): ... + def evaluate_outputs(self): ... + def evaluate_jacobian_equality_constraints(self): ... + def evaluate_jacobian_outputs(self): ... diff --git a/stubs/pyomo/contrib/pynumero/examples/feasibility.pyi b/stubs/pyomo/contrib/pynumero/examples/feasibility.pyi new file mode 100644 index 000000000..fee0341c7 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/examples/feasibility.pyi @@ -0,0 +1,9 @@ +from pyomo.contrib.pynumero.interfaces.pyomo_nlp import PyomoNLP as PyomoNLP +from pyomo.contrib.pynumero.interfaces.utils import build_bounds_mask as build_bounds_mask +from pyomo.contrib.pynumero.interfaces.utils import ( + build_compression_matrix as build_compression_matrix, +) +from pyomo.contrib.pynumero.interfaces.utils import full_to_compressed as full_to_compressed + +def create_basic_model(): ... +def main(): ... diff --git a/stubs/pyomo/contrib/pynumero/examples/mumps_example.pyi b/stubs/pyomo/contrib/pynumero/examples/mumps_example.pyi new file mode 100644 index 000000000..ba0207876 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/examples/mumps_example.pyi @@ -0,0 +1,5 @@ +from pyomo.contrib.pynumero.linalg.mumps_interface import ( + MumpsCentralizedAssembledLinearSolver as MumpsCentralizedAssembledLinearSolver, +) + +def main() -> None: ... diff --git a/stubs/pyomo/contrib/pynumero/examples/nlp_interface.pyi b/stubs/pyomo/contrib/pynumero/examples/nlp_interface.pyi new file mode 100644 index 000000000..8a5693886 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/examples/nlp_interface.pyi @@ -0,0 +1,4 @@ +from pyomo.contrib.pynumero.interfaces.pyomo_nlp import PyomoNLP as PyomoNLP + +def create_model(): ... +def main() -> None: ... diff --git a/stubs/pyomo/contrib/pynumero/examples/nlp_interface_2.pyi b/stubs/pyomo/contrib/pynumero/examples/nlp_interface_2.pyi new file mode 100644 index 000000000..50d0be32d --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/examples/nlp_interface_2.pyi @@ -0,0 +1,5 @@ +from pyomo.contrib.pynumero.interfaces.pyomo_nlp import PyomoNLP as PyomoNLP +from pyomo.contrib.pynumero.sparse import BlockMatrix as BlockMatrix + +def create_problem(begin, end): ... +def main(show_plot: bool = True) -> None: ... diff --git a/stubs/pyomo/contrib/pynumero/examples/parallel_matvec.pyi b/stubs/pyomo/contrib/pynumero/examples/parallel_matvec.pyi new file mode 100644 index 000000000..2c7f22cb6 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/examples/parallel_matvec.pyi @@ -0,0 +1,5 @@ +from pyomo.common.dependencies import mpi4py as mpi4py +from pyomo.contrib.pynumero.sparse.mpi_block_matrix import MPIBlockMatrix as MPIBlockMatrix +from pyomo.contrib.pynumero.sparse.mpi_block_vector import MPIBlockVector as MPIBlockVector + +def main(): ... diff --git a/stubs/pyomo/contrib/pynumero/examples/parallel_vector_ops.pyi b/stubs/pyomo/contrib/pynumero/examples/parallel_vector_ops.pyi new file mode 100644 index 000000000..31422e5da --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/examples/parallel_vector_ops.pyi @@ -0,0 +1,4 @@ +from pyomo.common.dependencies import mpi4py as mpi4py +from pyomo.contrib.pynumero.sparse.mpi_block_vector import MPIBlockVector as MPIBlockVector + +def main(): ... diff --git a/stubs/pyomo/contrib/pynumero/examples/sensitivity.pyi b/stubs/pyomo/contrib/pynumero/examples/sensitivity.pyi new file mode 100644 index 000000000..d132e08ad --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/examples/sensitivity.pyi @@ -0,0 +1,7 @@ +from pyomo.contrib.pynumero.interfaces.pyomo_nlp import PyomoNLP as PyomoNLP +from pyomo.contrib.pynumero.sparse import BlockMatrix as BlockMatrix +from pyomo.contrib.pynumero.sparse import BlockVector as BlockVector + +def create_model(eta1, eta2): ... +def compute_init_lam(nlp, x=None, lam_max: float = 1000.0): ... +def main(): ... diff --git a/stubs/pyomo/contrib/pynumero/examples/sqp.pyi b/stubs/pyomo/contrib/pynumero/examples/sqp.pyi new file mode 100644 index 000000000..d2567dcff --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/examples/sqp.pyi @@ -0,0 +1,21 @@ +from pyomo import dae as dae +from pyomo.common.timing import TicTocTimer as TicTocTimer +from pyomo.contrib.pynumero.interfaces.nlp import NLP as NLP +from pyomo.contrib.pynumero.interfaces.pyomo_nlp import PyomoNLP as PyomoNLP +from pyomo.contrib.pynumero.linalg.base import LinearSolverInterface as LinearSolverInterface +from pyomo.contrib.pynumero.linalg.base import LinearSolverStatus as LinearSolverStatus +from pyomo.contrib.pynumero.linalg.ma27_interface import MA27 as MA27 +from pyomo.contrib.pynumero.sparse import BlockMatrix as BlockMatrix +from pyomo.contrib.pynumero.sparse import BlockVector as BlockVector +from scipy.sparse import tril as tril + +def build_burgers_model(nfe_x: int = 100, nfe_t: int = 200, start_t: int = 0, end_t: int = 1): ... +def sqp( + nlp: NLP, + linear_solver: LinearSolverInterface, + max_iter: int = 100, + tol: float = 1e-08, + output: bool = True, +): ... +def load_solution(m: None, nlp: PyomoNLP): ... +def main(linear_solver, nfe_x: int = 100, nfe_t: int = 200): ... diff --git a/stubs/pyomo/contrib/pynumero/exceptions.pyi b/stubs/pyomo/contrib/pynumero/exceptions.pyi new file mode 100644 index 000000000..2ac2d0aad --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/exceptions.pyi @@ -0,0 +1 @@ +class PyNumeroEvaluationError(ArithmeticError): ... diff --git a/stubs/pyomo/contrib/pynumero/interfaces/__init__.pyi b/stubs/pyomo/contrib/pynumero/interfaces/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/pynumero/interfaces/ampl_nlp.pyi b/stubs/pyomo/contrib/pynumero/interfaces/ampl_nlp.pyi new file mode 100644 index 000000000..a33b782d3 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/interfaces/ampl_nlp.pyi @@ -0,0 +1,62 @@ +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.contrib.pynumero.interfaces.nlp import ExtendedNLP as ExtendedNLP + +class AslNLP(ExtendedNLP): + def __init__(self, nl_file) -> None: ... + def n_primals(self): ... + def n_constraints(self): ... + def n_eq_constraints(self): ... + def n_ineq_constraints(self): ... + def nnz_jacobian(self): ... + def nnz_jacobian_eq(self): ... + def nnz_jacobian_ineq(self): ... + def nnz_hessian_lag(self): ... + def primals_lb(self): ... + def primals_ub(self): ... + def constraints_lb(self): ... + def constraints_ub(self): ... + def ineq_lb(self): ... + def ineq_ub(self): ... + def init_primals(self): ... + def init_duals(self): ... + def init_duals_eq(self): ... + def init_duals_ineq(self): ... + def create_new_vector(self, vector_type): ... + def set_primals(self, primals) -> None: ... + def get_primals(self): ... + def set_duals(self, duals) -> None: ... + def get_duals(self): ... + def set_obj_factor(self, obj_factor) -> None: ... + def get_obj_factor(self): ... + def set_duals_eq(self, duals_eq) -> None: ... + def get_duals_eq(self): ... + def set_duals_ineq(self, duals_ineq) -> None: ... + def get_duals_ineq(self): ... + def get_obj_scaling(self) -> None: ... + def get_primals_scaling(self) -> None: ... + def get_constraints_scaling(self) -> None: ... + def get_eq_constraints_scaling(self): ... + def get_ineq_constraints_scaling(self): ... + def evaluate_objective(self): ... + def evaluate_grad_objective(self, out=None): ... + def evaluate_constraints(self, out=None): ... + def evaluate_eq_constraints(self, out=None): ... + def evaluate_ineq_constraints(self, out=None): ... + def evaluate_jacobian(self, out=None): ... + def evaluate_jacobian_eq(self, out=None): ... + def evaluate_jacobian_ineq(self, out=None): ... + def evaluate_hessian_lag(self, out=None): ... + def report_solver_status(self, status_code, status_message) -> None: ... + +class AmplNLP(AslNLP): + def __init__(self, nl_file, row_filename=None, col_filename=None) -> None: ... + def primals_names(self): ... + def variable_names(self): ... + def constraint_names(self): ... + def eq_constraint_names(self): ... + def ineq_constraint_names(self): ... + def variable_idx(self, var_name): ... + def primal_idx(self, var_name): ... + def constraint_idx(self, con_name): ... + def eq_constraint_idx(self, con_name): ... + def ineq_constraint_idx(self, con_name): ... diff --git a/stubs/pyomo/contrib/pynumero/interfaces/cyipopt_interface.pyi b/stubs/pyomo/contrib/pynumero/interfaces/cyipopt_interface.pyi new file mode 100644 index 000000000..d0760d228 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/interfaces/cyipopt_interface.pyi @@ -0,0 +1,84 @@ +import abc + +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.dependencies import numpy_available as numpy_available +from pyomo.contrib.pynumero.exceptions import PyNumeroEvaluationError as PyNumeroEvaluationError + +cyipopt: Incomplete +cyipopt_available: Incomplete +cyipopt_Problem: Incomplete + +class CyIpoptProblemInterface(cyipopt_Problem, metaclass=abc.ABCMeta): + def __init__(self) -> None: ... + def solve(self, x, lagrange=None, zl=None, zu=None): ... + @abc.abstractmethod + def x_init(self): ... + @abc.abstractmethod + def x_lb(self): ... + @abc.abstractmethod + def x_ub(self): ... + @abc.abstractmethod + def g_lb(self): ... + @abc.abstractmethod + def g_ub(self): ... + @abc.abstractmethod + def scaling_factors(self): ... + @abc.abstractmethod + def objective(self, x): ... + @abc.abstractmethod + def gradient(self, x): ... + @abc.abstractmethod + def constraints(self, x): ... + @abc.abstractmethod + def jacobianstructure(self): ... + @abc.abstractmethod + def jacobian(self, x): ... + @abc.abstractmethod + def hessianstructure(self): ... + @abc.abstractmethod + def hessian(self, x, y, obj_factor): ... + def intermediate( + self, + alg_mod, + iter_count, + obj_value, + inf_pr, + inf_du, + mu, + d_norm, + regularization_size, + alpha_du, + alpha_pr, + ls_trials, + ) -> None: ... + +class CyIpoptNLP(CyIpoptProblemInterface): + def __init__(self, nlp, intermediate_callback=None, halt_on_evaluation_error=None) -> None: ... + def x_init(self): ... + def x_lb(self): ... + def x_ub(self): ... + def g_lb(self): ... + def g_ub(self): ... + def scaling_factors(self): ... + def objective(self, x): ... + def gradient(self, x): ... + def constraints(self, x): ... + def jacobianstructure(self): ... + def jacobian(self, x): ... + def hessianstructure(self): ... + def hessian(self, x, y, obj_factor): ... + def intermediate( + self, + alg_mod, + iter_count, + obj_value, + inf_pr, + inf_du, + mu, + d_norm, + regularization_size, + alpha_du, + alpha_pr, + ls_trials, + ): ... diff --git a/stubs/pyomo/contrib/pynumero/interfaces/external_grey_box.pyi b/stubs/pyomo/contrib/pynumero/interfaces/external_grey_box.pyi new file mode 100644 index 000000000..22d3bb9a5 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/interfaces/external_grey_box.pyi @@ -0,0 +1,62 @@ +from _typeshed import Incomplete +from pyomo.common.deprecation import RenamedClass as RenamedClass +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.timing import ConstructionTimer as ConstructionTimer +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import Set as Set +from pyomo.core.base import Var as Var +from pyomo.core.base import value as value +from pyomo.core.base.block import Block as Block +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.block import declare_custom_block as declare_custom_block +from pyomo.core.base.global_set import UnindexedComponent_index as UnindexedComponent_index +from pyomo.core.base.initializer import Initializer as Initializer +from pyomo.core.base.reference import Reference as Reference +from pyomo.core.base.set import UnindexedComponent_set as UnindexedComponent_set +from scipy.sparse import coo_matrix as coo_matrix + +from ..sparse.block_matrix import BlockMatrix as BlockMatrix + +logger: Incomplete + +class ExternalGreyBoxModel: + def n_inputs(self): ... + def n_equality_constraints(self): ... + def n_outputs(self): ... + def input_names(self) -> None: ... + def equality_constraint_names(self): ... + def output_names(self): ... + def finalize_block_construction(self, pyomo_block) -> None: ... + def set_input_values(self, input_values) -> None: ... + def set_equality_constraint_multipliers(self, eq_con_multiplier_values) -> None: ... + def set_output_constraint_multipliers(self, output_con_multiplier_values) -> None: ... + def get_equality_constraint_scaling_factors(self) -> None: ... + def get_output_constraint_scaling_factors(self) -> None: ... + def evaluate_equality_constraints(self) -> None: ... + def evaluate_outputs(self) -> None: ... + def evaluate_jacobian_equality_constraints(self) -> None: ... + def evaluate_jacobian_outputs(self) -> None: ... + def has_objective(self): ... + def evaluate_objective(self) -> float: ... + def evaluate_grad_objective(self, out=None) -> None: ... + +class ExternalGreyBoxBlockData(BlockData): + inputs: Incomplete + outputs: Incomplete + def set_external_model(self, external_grey_box_model, inputs=None, outputs=None) -> None: ... + def get_external_model(self): ... + +class ExternalGreyBoxBlock(Block): + def __new__(cls, *args, **kwds): ... + def __init__(self, *args, **kwds) -> None: ... + def construct(self, data=None) -> None: ... + +class ScalarExternalGreyBoxBlock(ExternalGreyBoxBlockData, ExternalGreyBoxBlock): + def __init__(self, *args, **kwds) -> None: ... + display: Incomplete + +class SimpleExternalGreyBoxBlock(metaclass=RenamedClass): + __renamed__new_class__ = ScalarExternalGreyBoxBlock + __renamed__version__: str + +class IndexedExternalGreyBoxBlock(ExternalGreyBoxBlock): ... diff --git a/stubs/pyomo/contrib/pynumero/interfaces/external_pyomo_model.pyi b/stubs/pyomo/contrib/pynumero/interfaces/external_pyomo_model.pyi new file mode 100644 index 000000000..02cb6e213 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/interfaces/external_pyomo_model.pyi @@ -0,0 +1,52 @@ +from _typeshed import Incomplete +from pyomo.common.timing import HierarchicalTimer as HierarchicalTimer +from pyomo.contrib.pynumero.algorithms.solvers.implicit_functions import ( + SccImplicitFunctionSolver as SccImplicitFunctionSolver, +) +from pyomo.contrib.pynumero.interfaces.external_grey_box import ( + ExternalGreyBoxModel as ExternalGreyBoxModel, +) +from pyomo.contrib.pynumero.interfaces.pyomo_nlp import PyomoNLP as PyomoNLP +from pyomo.core.base.constraint import Constraint as Constraint +from pyomo.core.base.objective import Objective as Objective +from pyomo.core.base.var import Var as Var +from pyomo.core.expr.visitor import identify_variables as identify_variables +from pyomo.util.subsystems import create_subsystem_block as create_subsystem_block + +def get_hessian_of_constraint(constraint, wrt1=None, wrt2=None, nlp=None): ... + +class ExternalPyomoModel(ExternalGreyBoxModel): + input_vars: Incomplete + external_vars: Incomplete + residual_cons: Incomplete + external_cons: Incomplete + residual_con_multipliers: Incomplete + residual_scaling_factors: Incomplete + def __init__( + self, + input_vars, + external_vars, + residual_cons, + external_cons, + solver_class=None, + solver_options=None, + timer=None, + ) -> None: ... + def n_inputs(self): ... + def n_equality_constraints(self): ... + def input_names(self): ... + def equality_constraint_names(self): ... + def set_input_values(self, input_values) -> None: ... + def set_equality_constraint_multipliers(self, eq_con_multipliers) -> None: ... + def set_external_constraint_multipliers(self, eq_con_multipliers) -> None: ... + def calculate_external_constraint_multipliers(self, resid_multipliers): ... + def get_full_space_lagrangian_hessians(self): ... + def calculate_reduced_hessian_lagrangian(self, hlxx, hlxy, hlyy): ... + def evaluate_equality_constraints(self): ... + def evaluate_jacobian_equality_constraints(self): ... + def evaluate_jacobian_external_variables(self): ... + def evaluate_hessian_external_variables(self): ... + def evaluate_hessians_of_residuals(self): ... + def evaluate_hessian_equality_constraints(self): ... + def set_equality_constraint_scaling_factors(self, scaling_factors) -> None: ... + def get_equality_constraint_scaling_factors(self): ... diff --git a/stubs/pyomo/contrib/pynumero/interfaces/nlp.pyi b/stubs/pyomo/contrib/pynumero/interfaces/nlp.pyi new file mode 100644 index 000000000..a43d228c1 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/interfaces/nlp.pyi @@ -0,0 +1,99 @@ +import abc + +class NLP(metaclass=abc.ABCMeta): + def __init__(self) -> None: ... + @abc.abstractmethod + def n_primals(self): ... + def primals_names(self): ... + @abc.abstractmethod + def n_constraints(self): ... + def constraint_names(self): ... + @abc.abstractmethod + def nnz_jacobian(self): ... + @abc.abstractmethod + def nnz_hessian_lag(self): ... + @abc.abstractmethod + def primals_lb(self): ... + @abc.abstractmethod + def primals_ub(self): ... + @abc.abstractmethod + def constraints_lb(self): ... + @abc.abstractmethod + def constraints_ub(self): ... + @abc.abstractmethod + def init_primals(self): ... + @abc.abstractmethod + def init_duals(self): ... + @abc.abstractmethod + def create_new_vector(self, vector_type): ... + @abc.abstractmethod + def set_primals(self, primals): ... + @abc.abstractmethod + def get_primals(self): ... + @abc.abstractmethod + def set_duals(self, duals): ... + @abc.abstractmethod + def get_duals(self): ... + @abc.abstractmethod + def set_obj_factor(self, obj_factor): ... + @abc.abstractmethod + def get_obj_factor(self): ... + @abc.abstractmethod + def get_obj_scaling(self): ... + @abc.abstractmethod + def get_primals_scaling(self): ... + @abc.abstractmethod + def get_constraints_scaling(self): ... + @abc.abstractmethod + def evaluate_objective(self): ... + @abc.abstractmethod + def evaluate_grad_objective(self, out=None): ... + @abc.abstractmethod + def evaluate_constraints(self, out=None): ... + @abc.abstractmethod + def evaluate_jacobian(self, out=None): ... + @abc.abstractmethod + def evaluate_hessian_lag(self, out=None): ... + @abc.abstractmethod + def report_solver_status(self, status_code, status_message): ... + +class ExtendedNLP(NLP, metaclass=abc.ABCMeta): + def __init__(self) -> None: ... + @abc.abstractmethod + def n_eq_constraints(self): ... + @abc.abstractmethod + def n_ineq_constraints(self): ... + @abc.abstractmethod + def nnz_jacobian_eq(self): ... + @abc.abstractmethod + def nnz_jacobian_ineq(self): ... + @abc.abstractmethod + def ineq_lb(self): ... + @abc.abstractmethod + def ineq_ub(self): ... + @abc.abstractmethod + def init_duals_eq(self): ... + @abc.abstractmethod + def init_duals_ineq(self): ... + @abc.abstractmethod + def create_new_vector(self, vector_type): ... + @abc.abstractmethod + def set_duals_eq(self, duals_eq): ... + @abc.abstractmethod + def get_duals_eq(self): ... + @abc.abstractmethod + def set_duals_ineq(self, duals_ineq): ... + @abc.abstractmethod + def get_duals_ineq(self): ... + @abc.abstractmethod + def get_eq_constraints_scaling(self): ... + @abc.abstractmethod + def get_ineq_constraints_scaling(self): ... + @abc.abstractmethod + def evaluate_eq_constraints(self, out=None): ... + @abc.abstractmethod + def evaluate_ineq_constraints(self, out=None): ... + @abc.abstractmethod + def evaluate_jacobian_eq(self, out=None): ... + @abc.abstractmethod + def evaluate_jacobian_ineq(self, out=None): ... diff --git a/stubs/pyomo/contrib/pynumero/interfaces/nlp_projections.pyi b/stubs/pyomo/contrib/pynumero/interfaces/nlp_projections.pyi new file mode 100644 index 000000000..79d33b381 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/interfaces/nlp_projections.pyi @@ -0,0 +1,69 @@ +from pyomo.contrib.pynumero.interfaces.nlp import NLP as NLP +from pyomo.contrib.pynumero.interfaces.nlp import ExtendedNLP as ExtendedNLP + +class _BaseNLPDelegator(NLP): + def __init__(self, original_nlp) -> None: ... + def n_primals(self): ... + def primals_names(self): ... + def n_constraints(self): ... + def constraint_names(self): ... + def nnz_jacobian(self): ... + def nnz_hessian_lag(self): ... + def primals_lb(self): ... + def primals_ub(self): ... + def constraints_lb(self): ... + def constraints_ub(self): ... + def init_primals(self): ... + def init_duals(self): ... + def create_new_vector(self, vector_type): ... + def set_primals(self, primals) -> None: ... + def get_primals(self): ... + def set_duals(self, duals) -> None: ... + def get_duals(self): ... + def set_obj_factor(self, obj_factor) -> None: ... + def get_obj_factor(self): ... + def get_obj_scaling(self): ... + def get_primals_scaling(self): ... + def get_constraints_scaling(self): ... + def evaluate_objective(self): ... + def evaluate_grad_objective(self, out=None): ... + def evaluate_constraints(self, out=None): ... + def evaluate_jacobian(self, out=None): ... + def evaluate_hessian_lag(self, out=None): ... + def report_solver_status(self, status_code, status_message) -> None: ... + +class _ExtendedNLPDelegator(_BaseNLPDelegator): + def __init__(self, original_nlp) -> None: ... + def n_eq_constraints(self): ... + def n_ineq_constraints(self): ... + def evaluate_eq_constraints(self): ... + def evaluate_jacobian_eq(self): ... + def evaluate_ineq_constraints(self): ... + def evaluate_jacobian_ineq(self): ... + +class RenamedNLP(_BaseNLPDelegator): + def __init__(self, original_nlp, primals_name_map) -> None: ... + def primals_names(self): ... + +class ProjectedNLP(_BaseNLPDelegator): + def __init__(self, original_nlp, primals_ordering) -> None: ... + def n_primals(self): ... + def primals_names(self): ... + def nnz_jacobian(self): ... + def nnz_hessian_lag(self): ... + def primals_lb(self): ... + def primals_ub(self): ... + def init_primals(self): ... + def create_new_vector(self, vector_type): ... + def set_primals(self, primals) -> None: ... + def get_primals(self): ... + def get_primals_scaling(self): ... + def evaluate_grad_objective(self, out=None): ... + def evaluate_jacobian(self, out=None): ... + def evaluate_hessian_lag(self, out=None): ... + def report_solver_status(self, status_code, status_message) -> None: ... + +class ProjectedExtendedNLP(ProjectedNLP, _ExtendedNLPDelegator): + def __init__(self, original_nlp, primals_ordering) -> None: ... + def evaluate_jacobian_eq(self, out=None): ... + def evaluate_jacobian_ineq(self, out=None): ... diff --git a/stubs/pyomo/contrib/pynumero/interfaces/pyomo_grey_box_nlp.pyi b/stubs/pyomo/contrib/pynumero/interfaces/pyomo_grey_box_nlp.pyi new file mode 100644 index 000000000..58b3a46ee --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/interfaces/pyomo_grey_box_nlp.pyi @@ -0,0 +1,82 @@ +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.contrib.pynumero.interfaces.external_grey_box import ( + ExternalGreyBoxBlock as ExternalGreyBoxBlock, +) +from pyomo.contrib.pynumero.interfaces.nlp import NLP as NLP +from pyomo.contrib.pynumero.interfaces.nlp_projections import ProjectedNLP as ProjectedNLP +from pyomo.contrib.pynumero.interfaces.pyomo_nlp import PyomoNLP as PyomoNLP +from pyomo.contrib.pynumero.interfaces.utils import ( + CondensedSparseSummation as CondensedSparseSummation, +) +from pyomo.contrib.pynumero.interfaces.utils import ( + make_lower_triangular_full as make_lower_triangular_full, +) +from pyomo.contrib.pynumero.sparse.block_matrix import BlockMatrix as BlockMatrix +from pyomo.contrib.pynumero.sparse.block_vector import BlockVector as BlockVector +from pyomo.core.base.suffix import SuffixFinder as SuffixFinder + +class PyomoNLPWithGreyBoxBlocks(NLP): + def __init__(self, pyomo_model) -> None: ... + def n_primals(self): ... + def primals_names(self): ... + def n_constraints(self): ... + def constraint_names(self): ... + def nnz_jacobian(self): ... + def nnz_hessian_lag(self): ... + def primals_lb(self): ... + def primals_ub(self): ... + def constraints_lb(self): ... + def constraints_ub(self): ... + def init_primals(self): ... + def init_duals(self): ... + def create_new_vector(self, vector_type): ... + def set_primals(self, primals) -> None: ... + def get_primals(self): ... + def set_duals(self, duals) -> None: ... + def get_duals(self): ... + def set_obj_factor(self, obj_factor) -> None: ... + def get_obj_factor(self): ... + def get_obj_scaling(self): ... + def get_primals_scaling(self): ... + def get_constraints_scaling(self): ... + def evaluate_objective(self): ... + def evaluate_grad_objective(self, out=None): ... + def evaluate_constraints(self, out=None): ... + def evaluate_jacobian(self, out=None): ... + def evaluate_hessian_lag(self, out=None): ... + def report_solver_status(self, status_code, status_message) -> None: ... + def load_state_into_pyomo(self, bound_multipliers=None) -> None: ... + +class _ExternalGreyBoxAsNLP(NLP): + def __init__(self, external_grey_box_block) -> None: ... + def n_primals(self): ... + def primals_names(self): ... + def n_constraints(self): ... + def constraint_names(self): ... + def nnz_jacobian(self): ... + def nnz_hessian_lag(self): ... + def primals_lb(self): ... + def primals_ub(self): ... + def constraints_lb(self): ... + def constraints_ub(self): ... + def init_primals(self): ... + def init_duals(self): ... + def create_new_vector(self, vector_type): ... + def set_primals(self, primals) -> None: ... + def get_primals(self): ... + def set_duals(self, duals) -> None: ... + def get_duals(self): ... + def set_obj_factor(self, obj_factor) -> None: ... + def get_obj_factor(self): ... + def get_obj_scaling(self) -> None: ... + def get_primals_scaling(self) -> None: ... + def get_constraints_scaling(self): ... + def evaluate_objective(self): ... + def evaluate_grad_objective(self, out=None): ... + def evaluate_constraints(self, out=None): ... + def evaluate_jacobian(self, out=None): ... + def has_hessian_support(self): ... + def evaluate_hessian_lag(self, out=None): ... + def report_solver_status(self, status_code, status_message) -> None: ... diff --git a/stubs/pyomo/contrib/pynumero/interfaces/pyomo_nlp.pyi b/stubs/pyomo/contrib/pynumero/interfaces/pyomo_nlp.pyi new file mode 100644 index 000000000..86b33e1f6 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/interfaces/pyomo_nlp.pyi @@ -0,0 +1,94 @@ +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.env import CtypesEnviron as CtypesEnviron +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.contrib.pynumero.interfaces.ampl_nlp import AslNLP as AslNLP +from pyomo.contrib.pynumero.interfaces.nlp import NLP as NLP +from pyomo.core.base.suffix import SuffixFinder as SuffixFinder +from pyomo.opt import WriterFactory as WriterFactory +from pyomo.solvers.amplfunc_merge import amplfunc_merge as amplfunc_merge + +from ..sparse.block_matrix import BlockMatrix as BlockMatrix +from .external_grey_box import ExternalGreyBoxBlock as ExternalGreyBoxBlock + +class PyomoNLP(AslNLP): + def __init__(self, pyomo_model, nl_file_options=None) -> None: ... + @property + def symbol_map(self): ... + def pyomo_model(self): ... + def get_pyomo_objective(self): ... + def get_pyomo_variables(self): ... + def get_pyomo_constraints(self): ... + def get_pyomo_equality_constraints(self): ... + def get_pyomo_inequality_constraints(self): ... + def variable_names(self): ... + def primals_names(self): ... + def constraint_names(self): ... + def equality_constraint_names(self): ... + def inequality_constraint_names(self): ... + def get_primal_indices(self, pyomo_variables): ... + def get_constraint_indices(self, pyomo_constraints): ... + def get_equality_constraint_indices(self, constraints): ... + def get_inequality_constraint_indices(self, constraints): ... + def get_obj_scaling(self): ... + def get_primals_scaling(self): ... + def get_constraints_scaling(self): ... + def extract_subvector_grad_objective(self, pyomo_variables): ... + def extract_subvector_constraints(self, pyomo_constraints): ... + def extract_submatrix_jacobian(self, pyomo_variables, pyomo_constraints): ... + def extract_submatrix_hessian_lag(self, pyomo_variables_rows, pyomo_variables_cols): ... + def load_state_into_pyomo(self, bound_multipliers=None) -> None: ... + +class PyomoGreyBoxNLP(NLP): + def __init__(self, pyomo_model) -> None: ... + def n_primals(self): ... + def n_constraints(self): ... + def n_eq_constraints(self): ... + def n_ineq_constraints(self): ... + def nnz_jacobian(self): ... + def nnz_jacobian_eq(self): ... + def nnz_hessian_lag(self): ... + def primals_lb(self): ... + def primals_ub(self): ... + def constraints_lb(self): ... + def constraints_ub(self): ... + def init_primals(self): ... + def init_duals(self): ... + def init_duals_eq(self): ... + def create_new_vector(self, vector_type): ... + def set_primals(self, primals) -> None: ... + def get_primals(self): ... + def set_duals(self, duals) -> None: ... + def get_duals(self): ... + def set_duals_eq(self, duals) -> None: ... + def get_duals_eq(self) -> None: ... + def set_obj_factor(self, obj_factor) -> None: ... + def get_obj_factor(self): ... + def get_obj_scaling(self): ... + def get_primals_scaling(self): ... + def get_constraints_scaling(self): ... + def evaluate_objective(self): ... + def evaluate_grad_objective(self, out=None): ... + def evaluate_constraints(self, out=None): ... + def evaluate_eq_constraints(self, out=None) -> None: ... + def evaluate_jacobian(self, out=None): ... + def evaluate_hessian_lag(self, out=None): ... + def report_solver_status(self, status_code, status_message) -> None: ... + def variable_names(self): ... + def primals_names(self): ... + def constraint_names(self): ... + def pyomo_model(self): ... + def get_pyomo_objective(self): ... + def get_pyomo_variables(self): ... + def get_pyomo_constraints(self) -> None: ... + def load_state_into_pyomo(self, bound_multipliers=None) -> None: ... + +class _ExternalGreyBoxModelHelper: + def __init__(self, ex_grey_box_block, vardata_to_idx, con_offset) -> None: ... + def set_primals(self, primals) -> None: ... + def set_duals(self, duals) -> None: ... + def n_residuals(self): ... + def get_residual_scaling(self): ... + def evaluate_residuals(self): ... + def evaluate_jacobian(self): ... + def evaluate_hessian(self): ... diff --git a/stubs/pyomo/contrib/pynumero/interfaces/utils.pyi b/stubs/pyomo/contrib/pynumero/interfaces/utils.pyi new file mode 100644 index 000000000..6a4587681 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/interfaces/utils.pyi @@ -0,0 +1,18 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.contrib.pynumero.sparse import BlockMatrix as BlockMatrix +from pyomo.contrib.pynumero.sparse import BlockVector as BlockVector + +mpi_block_vector: Incomplete +mpi_block_vector_available: Incomplete + +def build_bounds_mask(vector): ... +def build_compression_matrix(compression_mask): ... +def build_compression_mask_for_finite_values(vector): ... +def full_to_compressed(full_array, compression_mask, out=None): ... +def compressed_to_full(compressed_array, compression_mask, out=None, default=None): ... +def make_lower_triangular_full(lower_triangular_matrix): ... + +class CondensedSparseSummation: + def __init__(self, list_of_matrices) -> None: ... + def sum(self, list_of_matrices): ... diff --git a/stubs/pyomo/contrib/pynumero/intrinsic.pyi b/stubs/pyomo/contrib/pynumero/intrinsic.pyi new file mode 100644 index 000000000..7943ddef3 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/intrinsic.pyi @@ -0,0 +1,12 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import + +block_vector: Incomplete + +def norm(x, ord=None): ... +def allclose(x1, x2, rtol, atol): ... +def concatenate(arrays): ... +def where(*args): ... +def isin(element, test_elements, assume_unique: bool = False, invert: bool = False): ... +def intersect1d(ar1, ar2, assume_unique: bool = False, return_indices: bool = False): ... +def setdiff1d(ar1, ar2, assume_unique: bool = False): ... diff --git a/stubs/pyomo/contrib/pynumero/linalg/__init__.pyi b/stubs/pyomo/contrib/pynumero/linalg/__init__.pyi new file mode 100644 index 000000000..527ce7db7 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/linalg/__init__.pyi @@ -0,0 +1,2 @@ +from ..dependencies import numpy_available as numpy_available +from ..dependencies import scipy_available as scipy_available diff --git a/stubs/pyomo/contrib/pynumero/linalg/base.pyi b/stubs/pyomo/contrib/pynumero/linalg/base.pyi new file mode 100644 index 000000000..3fe20ab6d --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/linalg/base.pyi @@ -0,0 +1,51 @@ +import enum +from abc import ABCMeta, abstractmethod + +import numpy as np +from _typeshed import Incomplete +from pyomo.contrib.pynumero.sparse import BlockMatrix as BlockMatrix +from pyomo.contrib.pynumero.sparse import BlockVector as BlockVector +from pyomo.contrib.pynumero.sparse.base_block import BaseBlockMatrix as BaseBlockMatrix +from pyomo.contrib.pynumero.sparse.base_block import BaseBlockVector as BaseBlockVector +from scipy.sparse import spmatrix as spmatrix + +class LinearSolverStatus(enum.Enum): + successful = 0 + not_enough_memory = 1 + singular = 2 + error = 3 + warning = 4 + max_iter = 5 + +class LinearSolverResults: + status: Incomplete + def __init__(self, status: LinearSolverStatus | None = None) -> None: ... + +class LinearSolverInterface(metaclass=ABCMeta): + @abstractmethod + def solve( + self, + matrix: spmatrix | BlockMatrix, + rhs: np.ndarray | BlockVector, + raise_on_error: bool = True, + ) -> tuple[np.ndarray | BlockVector | None, LinearSolverResults]: ... + +class DirectLinearSolverInterface(LinearSolverInterface, metaclass=ABCMeta): + @abstractmethod + def do_symbolic_factorization( + self, matrix: spmatrix | BlockMatrix, raise_on_error: bool = True + ) -> LinearSolverResults: ... + @abstractmethod + def do_numeric_factorization( + self, matrix: spmatrix | BlockMatrix, raise_on_error: bool = True + ) -> LinearSolverResults: ... + @abstractmethod + def do_back_solve( + self, rhs: np.ndarray | BlockVector, raise_on_error: bool = True + ) -> tuple[np.ndarray | BlockVector | None, LinearSolverResults]: ... + def solve( + self, + matrix: spmatrix | BlockMatrix, + rhs: np.ndarray | BlockVector, + raise_on_error: bool = True, + ) -> tuple[np.ndarray | BlockVector | None, LinearSolverResults]: ... diff --git a/stubs/pyomo/contrib/pynumero/linalg/ma27.pyi b/stubs/pyomo/contrib/pynumero/linalg/ma27.pyi new file mode 100644 index 000000000..d44bf19a3 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/linalg/ma27.pyi @@ -0,0 +1,25 @@ +from _typeshed import Incomplete +from pyomo.common.fileutils import find_library as find_library +from pyomo.contrib.pynumero.linalg.utils import validate_index as validate_index +from pyomo.contrib.pynumero.linalg.utils import validate_value as validate_value + +class MA27Interface: + libname: Incomplete + @classmethod + def available(cls): ... + iw_factor: Incomplete + a_factor: Incomplete + lib: Incomplete + icntl_len: int + cntl_len: int + info_len: int + def __init__(self, iw_factor=None, a_factor=None) -> None: ... + def __del__(self) -> None: ... + def set_icntl(self, i, val) -> None: ... + def get_icntl(self, i): ... + def set_cntl(self, i, val) -> None: ... + def get_cntl(self, i): ... + def get_info(self, i): ... + def do_symbolic_factorization(self, dim, irn, icn): ... + def do_numeric_factorization(self, irn, icn, dim, entries): ... + def do_backsolve(self, rhs, copy: bool = True): ... diff --git a/stubs/pyomo/contrib/pynumero/linalg/ma27_interface.pyi b/stubs/pyomo/contrib/pynumero/linalg/ma27_interface.pyi new file mode 100644 index 000000000..c9486d15b --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/linalg/ma27_interface.pyi @@ -0,0 +1,29 @@ +import numpy as np +from pyomo.contrib.pynumero.sparse import BlockMatrix as BlockMatrix +from pyomo.contrib.pynumero.sparse import BlockVector as BlockVector +from scipy.sparse import spmatrix as spmatrix + +from .base import DirectLinearSolverInterface as DirectLinearSolverInterface +from .base import LinearSolverResults as LinearSolverResults +from .base import LinearSolverStatus as LinearSolverStatus +from .ma27 import MA27Interface as MA27Interface + +class MA27(DirectLinearSolverInterface): + def __init__( + self, cntl_options=None, icntl_options=None, iw_factor: float = 1.2, a_factor: int = 2 + ) -> None: ... + def do_symbolic_factorization( + self, matrix: spmatrix | BlockMatrix, raise_on_error: bool = True + ) -> LinearSolverResults: ... + def do_numeric_factorization( + self, matrix: spmatrix | BlockMatrix, raise_on_error: bool = True + ) -> LinearSolverResults: ... + def do_back_solve( + self, rhs: np.ndarray | BlockVector, raise_on_error: bool = True + ) -> tuple[np.ndarray | BlockVector | None, LinearSolverResults]: ... + def increase_memory_allocation(self, factor) -> None: ... + def set_icntl(self, key, value) -> None: ... + def set_cntl(self, key, value) -> None: ... + def get_icntl(self, key): ... + def get_cntl(self, key): ... + def get_info(self, key): ... diff --git a/stubs/pyomo/contrib/pynumero/linalg/ma57.pyi b/stubs/pyomo/contrib/pynumero/linalg/ma57.pyi new file mode 100644 index 000000000..ad5a28de8 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/linalg/ma57.pyi @@ -0,0 +1,30 @@ +from _typeshed import Incomplete +from pyomo.common.fileutils import find_library as find_library +from pyomo.contrib.pynumero.linalg.utils import validate_index as validate_index +from pyomo.contrib.pynumero.linalg.utils import validate_value as validate_value + +class MA57Interface: + libname: Incomplete + @classmethod + def available(cls): ... + work_factor: Incomplete + fact_factor: Incomplete + ifact_factor: Incomplete + lib: Incomplete + icntl_len: int + cntl_len: int + info_len: int + rinfo_len: int + def __init__(self, work_factor=None, fact_factor=None, ifact_factor=None) -> None: ... + def __del__(self) -> None: ... + def set_icntl(self, i, val) -> None: ... + def get_icntl(self, i): ... + def set_cntl(self, i, val) -> None: ... + def get_cntl(self, i): ... + def get_info(self, i): ... + def get_rinfo(self, i): ... + ne_cached: Incomplete + dim_cached: Incomplete + def do_symbolic_factorization(self, dim, irn, jcn): ... + def do_numeric_factorization(self, dim, entries): ... + def do_backsolve(self, rhs, copy: bool = True): ... diff --git a/stubs/pyomo/contrib/pynumero/linalg/ma57_interface.pyi b/stubs/pyomo/contrib/pynumero/linalg/ma57_interface.pyi new file mode 100644 index 000000000..cbe2c2855 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/linalg/ma57_interface.pyi @@ -0,0 +1,35 @@ +import numpy as np +from pyomo.contrib.pynumero.sparse import BlockMatrix as BlockMatrix +from pyomo.contrib.pynumero.sparse import BlockVector as BlockVector +from scipy.sparse import spmatrix as spmatrix + +from .base import DirectLinearSolverInterface as DirectLinearSolverInterface +from .base import LinearSolverResults as LinearSolverResults +from .base import LinearSolverStatus as LinearSolverStatus +from .ma57 import MA57Interface as MA57Interface + +class MA57(DirectLinearSolverInterface): + def __init__( + self, + cntl_options=None, + icntl_options=None, + work_factor: float = 1.2, + fact_factor: int = 2, + ifact_factor: int = 2, + ) -> None: ... + def do_symbolic_factorization( + self, matrix: spmatrix | BlockMatrix, raise_on_error: bool = True + ) -> LinearSolverResults: ... + def do_numeric_factorization( + self, matrix: spmatrix | BlockMatrix, raise_on_error: bool = True + ) -> LinearSolverResults: ... + def do_back_solve( + self, rhs: np.ndarray | BlockVector, raise_on_error: bool = True + ) -> tuple[np.ndarray | BlockVector | None, LinearSolverResults]: ... + def increase_memory_allocation(self, factor) -> None: ... + def set_icntl(self, key, value) -> None: ... + def set_cntl(self, key, value) -> None: ... + def get_icntl(self, key): ... + def get_cntl(self, key): ... + def get_info(self, key): ... + def get_rinfo(self, key): ... diff --git a/stubs/pyomo/contrib/pynumero/linalg/mumps_interface.pyi b/stubs/pyomo/contrib/pynumero/linalg/mumps_interface.pyi new file mode 100644 index 000000000..1d5a49ac3 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/linalg/mumps_interface.pyi @@ -0,0 +1,38 @@ +import numpy as np +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.contrib.pynumero.sparse import BlockMatrix as BlockMatrix +from pyomo.contrib.pynumero.sparse import BlockVector as BlockVector +from scipy.sparse import coo_matrix as coo_matrix +from scipy.sparse import spmatrix as spmatrix + +from .base import DirectLinearSolverInterface as DirectLinearSolverInterface +from .base import LinearSolverResults as LinearSolverResults +from .base import LinearSolverStatus as LinearSolverStatus + +mumps: Incomplete +mumps_available: Incomplete + +class MumpsCentralizedAssembledLinearSolver(DirectLinearSolverInterface): + def __init__( + self, sym: int = 0, par: int = 1, comm=None, cntl_options=None, icntl_options=None + ) -> None: ... + def do_symbolic_factorization( + self, matrix: spmatrix | BlockMatrix, raise_on_error: bool = True + ) -> LinearSolverResults: ... + def do_numeric_factorization( + self, matrix: spmatrix | BlockMatrix, raise_on_error: bool = True + ) -> LinearSolverResults: ... + def do_back_solve( + self, rhs: np.ndarray | BlockVector, raise_on_error: bool = True + ) -> tuple[np.ndarray | BlockVector | None, LinearSolverResults]: ... + def increase_memory_allocation(self, factor): ... + def __del__(self) -> None: ... + def set_icntl(self, key, value) -> None: ... + def set_cntl(self, key, value) -> None: ... + def get_icntl(self, key): ... + def get_cntl(self, key): ... + def get_info(self, key): ... + def get_infog(self, key): ... + def get_rinfo(self, key): ... + def get_rinfog(self, key): ... diff --git a/stubs/pyomo/contrib/pynumero/linalg/scipy_interface.pyi b/stubs/pyomo/contrib/pynumero/linalg/scipy_interface.pyi new file mode 100644 index 000000000..d442000f5 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/linalg/scipy_interface.pyi @@ -0,0 +1,40 @@ +from typing import Callable + +import numpy as np +from _typeshed import Incomplete +from pyomo.contrib.pynumero.sparse import BlockMatrix as BlockMatrix +from pyomo.contrib.pynumero.sparse import BlockVector as BlockVector +from scipy.linalg import eigvals as eigvals +from scipy.sparse import spmatrix as spmatrix +from scipy.sparse.linalg import LinearOperator + +from .base import DirectLinearSolverInterface as DirectLinearSolverInterface +from .base import LinearSolverInterface as LinearSolverInterface +from .base import LinearSolverResults as LinearSolverResults +from .base import LinearSolverStatus as LinearSolverStatus + +class ScipyLU(DirectLinearSolverInterface): + def __init__(self) -> None: ... + def do_symbolic_factorization( + self, matrix: spmatrix | BlockMatrix, raise_on_error: bool = True + ) -> LinearSolverResults: ... + def do_numeric_factorization( + self, matrix: spmatrix | BlockMatrix, raise_on_error: bool = True + ) -> LinearSolverResults: ... + def do_back_solve( + self, rhs: np.ndarray | BlockVector, raise_on_error: bool = True + ) -> tuple[np.ndarray | BlockVector | None, LinearSolverResults]: ... + +class _LinearOperator(LinearOperator): + def __init__(self, matrix: spmatrix | BlockMatrix) -> None: ... + +class ScipyIterative(LinearSolverInterface): + method: Incomplete + options: Incomplete + def __init__(self, method: Callable, options=None) -> None: ... + def solve( + self, + matrix: spmatrix | BlockMatrix, + rhs: np.ndarray | BlockVector, + raise_on_error: bool = True, + ) -> tuple[np.ndarray | BlockVector | None, LinearSolverResults]: ... diff --git a/stubs/pyomo/contrib/pynumero/linalg/utils.pyi b/stubs/pyomo/contrib/pynumero/linalg/utils.pyi new file mode 100644 index 000000000..3161e1fa9 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/linalg/utils.pyi @@ -0,0 +1,4 @@ +def validate_index(i, array_len, array_name: str = '') -> None: ... +def validate_value(val, dtype, array_name: str = '') -> None: ... + +class _NotSet: ... diff --git a/stubs/pyomo/contrib/pynumero/plugins.pyi b/stubs/pyomo/contrib/pynumero/plugins.pyi new file mode 100644 index 000000000..7619d749b --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/plugins.pyi @@ -0,0 +1,11 @@ +from pyomo.common.extensions import ExtensionBuilderFactory as ExtensionBuilderFactory +from pyomo.opt import SolverFactory as SolverFactory + +from .algorithms.solvers.cyipopt_solver import PyomoCyIpoptSolver as PyomoCyIpoptSolver +from .algorithms.solvers.scipy_solvers import PyomoFsolveSolver as PyomoFsolveSolver +from .algorithms.solvers.scipy_solvers import PyomoNewtonSolver as PyomoNewtonSolver +from .algorithms.solvers.scipy_solvers import PyomoRootSolver as PyomoRootSolver +from .algorithms.solvers.scipy_solvers import PyomoSecantNewtonSolver as PyomoSecantNewtonSolver +from .build import PyNumeroBuilder as PyNumeroBuilder + +def load() -> None: ... diff --git a/stubs/pyomo/contrib/pynumero/sparse/__init__.pyi b/stubs/pyomo/contrib/pynumero/sparse/__init__.pyi new file mode 100644 index 000000000..ccaeb5fd8 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/sparse/__init__.pyi @@ -0,0 +1,6 @@ +from ..dependencies import numpy_available as numpy_available +from ..dependencies import scipy_available as scipy_available +from .block_matrix import BlockMatrix as BlockMatrix +from .block_matrix import NotFullyDefinedBlockMatrixError as NotFullyDefinedBlockMatrixError +from .block_vector import BlockVector as BlockVector +from .block_vector import NotFullyDefinedBlockVectorError as NotFullyDefinedBlockVectorError diff --git a/stubs/pyomo/contrib/pynumero/sparse/base_block.pyi b/stubs/pyomo/contrib/pynumero/sparse/base_block.pyi new file mode 100644 index 000000000..02ae40917 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/sparse/base_block.pyi @@ -0,0 +1,50 @@ +from _typeshed import Incomplete + +class BaseBlockVector: + def __init__(self) -> None: ... + def argpartition(self, kth, axis: int = -1, kind: str = 'introselect', order=None) -> None: ... + def argsort(self, axis: int = -1, kind: str = 'quicksort', order=None) -> None: ... + def byteswap(self, inplace: bool = False) -> None: ... + def choose(self, choices, out=None, mode: str = 'raise') -> None: ... + def diagonal(self, offset: int = 0, axis1: int = 0, axis2: int = 1) -> None: ... + def getfield(self, dtype, offset: int = 0) -> None: ... + def item(self, *args) -> None: ... + def itemset(self, *args) -> None: ... + def newbyteorder(self, new_order: str = 'S') -> None: ... + def put(self, indices, values, mode: str = 'raise') -> None: ... + def partition(self, kth, axis: int = -1, kind: str = 'introselect', order=None) -> None: ... + def repeat(self, repeats, axis=None) -> None: ... + def reshape(self, shape, order: str = 'C') -> None: ... + def resize(self, new_shape, refcheck: bool = True) -> None: ... + def searchsorted(self, v, side: str = 'left', sorter=None) -> None: ... + def setfield(self, val, dtype, offset: int = 0) -> None: ... + def setflags(self, write=None, align=None, uic=None) -> None: ... + def sort(self, axis: int = -1, kind: str = 'quicksort', order=None) -> None: ... + def squeeze(self, axis=None) -> None: ... + def swapaxes(self, axis1, axis2) -> None: ... + def trace( + self, offset: int = 0, axis1: int = 0, axis2: int = 1, dtype=None, out=None + ) -> None: ... + def argmax(self, axis=None, out=None) -> None: ... + def argmin(self, axis=None, out=None) -> None: ... + def take(self, indices, axis=None, out=None, mode: str = 'raise') -> None: ... + def dump(self, file) -> None: ... + def dumps(self) -> None: ... + def tobytes(self, order: str = 'C') -> None: ... + +class BaseBlockMatrix: + def __init__(self) -> None: ... + def tolil(self, copy: bool = False) -> None: ... + def todia(self, copy: bool = False) -> None: ... + def tobsr(self, blocksize=None, copy: bool = False) -> None: ... + def sum(self, axis=None, dtype=None, out=None) -> None: ... + def mean(self, axis=None, dtype=None, out=None) -> None: ... + def diagonal(self, k: int = 0) -> None: ... + def nonzero(self) -> None: ... + def setdiag(self, values, k: int = 0) -> None: ... + def transpose(self, *axes) -> None: ... + def tostring(self, order: str = 'C') -> None: ... + +vec_unary_ufuncs: Incomplete +vec_binary_ufuncs: Incomplete +vec_associative_reductions: Incomplete diff --git a/stubs/pyomo/contrib/pynumero/sparse/block_matrix.pyi b/stubs/pyomo/contrib/pynumero/sparse/block_matrix.pyi new file mode 100644 index 000000000..841676de0 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/sparse/block_matrix.pyi @@ -0,0 +1,86 @@ +from _typeshed import Incomplete +from pyomo.contrib.pynumero.sparse.block_vector import BlockVector as BlockVector + +from .base_block import BaseBlockMatrix as BaseBlockMatrix + +logger: Incomplete + +class NotFullyDefinedBlockMatrixError(Exception): ... + +def assert_block_structure(mat) -> None: ... + +class BlockMatrix(BaseBlockMatrix): + format: str + def __init__(self, nbrows, nbcols) -> None: ... + @property + def bshape(self): ... + @property + def shape(self): ... + @property + def nnz(self): ... + @property + def dtype(self): ... + @property + def T(self): ... + def row_block_sizes(self, copy: bool = True): ... + def col_block_sizes(self, copy: bool = True): ... + def get_row_size(self, row): ... + def get_col_size(self, col): ... + def set_row_size(self, row, size) -> None: ... + def set_col_size(self, col, size) -> None: ... + def is_row_size_defined(self, row): ... + def is_col_size_defined(self, col): ... + def block_shapes(self): ... + def get_block_mask(self, copy: bool = True): ... + def dot(self, other): ... + def reset_brow(self, idx) -> None: ... + def reset_bcol(self, jdx) -> None: ... + def coo_data(self): ... + def tocoo(self, copy: bool = True): ... + def tocsr(self, copy: bool = True): ... + def tocsc(self, copy: bool = True): ... + def toarray(self, order=None, out=None): ... + def transpose(self, axes=None, copy: bool = True): ... + def is_empty_block(self, idx, jdx): ... + def has_undefined_row_sizes(self): ... + def has_undefined_col_sizes(self): ... + def copyfrom(self, other, deep: bool = True) -> None: ... + def copyto(self, other, deep: bool = True) -> None: ... + def copy(self, deep: bool = True): ... + def copy_structure(self): ... + def get_block(self, row, col): ... + def set_block(self, row, col, value) -> None: ... + def __getitem__(self, item) -> None: ... + def __setitem__(self, item, val) -> None: ... + def __add__(self, other): ... + def __radd__(self, other): ... + def __sub__(self, other): ... + def __rsub__(self, other): ... + def __mul__(self, other): ... + def __truediv__(self, other): ... + def __rtruediv__(self, other) -> None: ... + def __rmul__(self, other): ... + def __pow__(self, other) -> None: ... + def __abs__(self): ... + def __iadd__(self, other): ... + def __isub__(self, other): ... + def __imul__(self, other): ... + def __itruediv__(self, other): ... + def __div__(self, other): ... + def __rdiv__(self, other): ... + def __idiv__(self, other): ... + def __ifloordiv__(self, other) -> None: ... + def __neg__(self): ... + def __eq__(self, other): ... + def __ne__(self, other): ... + def __le__(self, other): ... + def __lt__(self, other): ... + def __ge__(self, other): ... + def __gt__(self, other): ... + def __len__(self) -> int: ... + def __matmul__(self, other): ... + def __rmatmul__(self, other): ... + def get_block_column_index(self, index): ... + def get_block_row_index(self, index): ... + def getcol(self, j): ... + def getrow(self, i): ... diff --git a/stubs/pyomo/contrib/pynumero/sparse/block_vector.pyi b/stubs/pyomo/contrib/pynumero/sparse/block_vector.pyi new file mode 100644 index 000000000..7cbc2e319 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/sparse/block_vector.pyi @@ -0,0 +1,105 @@ +from ..dependencies import numpy as np +from .base_block import BaseBlockVector as BaseBlockVector +from .base_block import vec_associative_reductions as vec_associative_reductions +from .base_block import vec_binary_ufuncs as vec_binary_ufuncs +from .base_block import vec_unary_ufuncs as vec_unary_ufuncs + +class NotFullyDefinedBlockVectorError(Exception): ... + +def assert_block_structure(vec) -> None: ... + +class BlockVector(BaseBlockVector, np.ndarray): + def __new__(cls, nblocks): ... + def __init__(self, nblocks) -> None: ... + def __array_finalize__(self, obj) -> None: ... + def __array_prepare__(self, out_arr, context=None): ... + def __array_wrap__(self, out_arr, context=None): ... + def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): ... + @property + def nblocks(self): ... + @property + def bshape(self): ... + @property + def shape(self): ... + @property + def size(self): ... + @property + def ndim(self): ... + @property + def has_none(self): ... + def block_sizes(self, copy: bool = True): ... + def get_block_size(self, ndx): ... + def is_block_defined(self, ndx): ... + def dot(self, other, out=None): ... + def sum(self, axis=None, dtype=None, out=None, keepdims: bool = False): ... + def all(self, axis=None, out=None, keepdims: bool = False): ... + def any(self, axis=None, out=None, keepdims: bool = False): ... + def max(self, axis=None, out=None, keepdims: bool = False): ... + def astype( + self, + dtype, + order: str = 'K', + casting: str = 'unsafe', + subok: bool = True, + copy: bool = True, + ): ... + def clip(self, min=None, max=None, out=None): ... + def compress(self, condition, axis=None, out=None): ... + def conj(self): ... + def conjugate(self): ... + def nonzero(self): ... + def ptp(self, axis=None, out=None, keepdims: bool = False): ... + def round(self, decimals: int = 0, out=None): ... + def std(self, axis=None, dtype=None, out=None, ddof: int = 0, keepdims: bool = False): ... + def var(self, axis=None, dtype=None, out=None, ddof: int = 0, keepdims: bool = False): ... + def tofile(self, fid, sep: str = '', format: str = '%s') -> None: ... + def min(self, axis=None, out=None, keepdims: bool = False): ... + def mean(self, axis=None, dtype=None, out=None, keepdims: bool = False): ... + def prod(self, axis=None, dtype=None, out=None, keepdims: bool = False): ... + def fill(self, value) -> None: ... + def tolist(self): ... + def flatten(self, order: str = 'C'): ... + def ravel(self, order: str = 'C'): ... + def argmax(self, axis=None, out=None): ... + def argmin(self, axis=None, out=None): ... + def cumprod(self, axis=None, dtype=None, out=None): ... + def cumsum(self, axis=None, dtype=None, out=None): ... + def clone(self, value=None, copy: bool = True): ... + def copyfrom(self, other) -> None: ... + def copyto(self, other) -> None: ... + def copy(self, order: str = 'C'): ... + def copy_structure(self): ... + def set_blocks(self, blocks) -> None: ... + def __iter__(self): ... + def __add__(self, other): ... + def __radd__(self, other): ... + def __sub__(self, other): ... + def __rsub__(self, other): ... + def __mul__(self, other): ... + def __rmul__(self, other): ... + def __truediv__(self, other): ... + def __rtruediv__(self, other): ... + def __floordiv__(self, other): ... + def __rfloordiv__(self, other): ... + def __iadd__(self, other): ... + def __isub__(self, other): ... + def __imul__(self, other): ... + def __itruediv__(self, other): ... + def __div__(self, other): ... + def __rdiv__(self, other): ... + def __idiv__(self, other): ... + def get_block(self, key): ... + def set_block(self, key, value) -> None: ... + def __getitem__(self, item) -> None: ... + def __setitem__(self, key, value) -> None: ... + def __le__(self, other): ... + def __lt__(self, other): ... + def __ge__(self, other): ... + def __gt__(self, other): ... + def __eq__(self, other): ... + def __ne__(self, other): ... + def __neg__(self): ... + def __contains__(self, item) -> bool: ... + def __len__(self) -> int: ... + def pprint(self) -> None: ... + def toMPIBlockVector(self, rank_ownership, mpi_comm, assert_correct_owners: bool = False): ... diff --git a/stubs/pyomo/contrib/pynumero/sparse/mpi_block_matrix.pyi b/stubs/pyomo/contrib/pynumero/sparse/mpi_block_matrix.pyi new file mode 100644 index 000000000..e50116a1b --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/sparse/mpi_block_matrix.pyi @@ -0,0 +1,99 @@ +from pyomo.common.dependencies import mpi4py as mpi4py + +from .base_block import BaseBlockMatrix as BaseBlockMatrix +from .block_matrix import BlockMatrix as BlockMatrix +from .block_matrix import NotFullyDefinedBlockMatrixError as NotFullyDefinedBlockMatrixError +from .block_vector import BlockVector as BlockVector +from .mpi_block_vector import MPIBlockVector as MPIBlockVector + +def assert_block_structure(mat: MPIBlockMatrix): ... + +class MPIBlockMatrix(BaseBlockMatrix): + def __init__( + self, nbrows, nbcols, rank_ownership, mpi_comm, assert_correct_owners: bool = False + ) -> None: ... + @property + def bshape(self): ... + @property + def shape(self): ... + @property + def nnz(self): ... + @property + def owned_blocks(self): ... + @property + def shared_blocks(self): ... + @property + def rank_ownership(self): ... + @property + def ownership_mask(self): ... + @property + def mpi_comm(self): ... + def get_row_size(self, row): ... + def get_col_size(self, col): ... + def set_row_size(self, row, size) -> None: ... + def set_col_size(self, col, size) -> None: ... + def is_row_size_defined(self, row, this_process_only: bool = True): ... + def is_col_size_defined(self, col, this_process_only: bool = True): ... + def get_block_mask(self, copy: bool = True): ... + @property + def T(self): ... + def dot(self, other): ... + def transpose(self, axes=None, copy: bool = True): ... + def tocoo(self) -> None: ... + def tocsr(self) -> None: ... + def tocsc(self) -> None: ... + def tolil(self, copy: bool = False) -> None: ... + def todia(self, copy: bool = False) -> None: ... + def tobsr(self, blocksize=None, copy: bool = False) -> None: ... + def coo_data(self) -> None: ... + def toarray(self) -> None: ... + def to_local_array(self): ... + def is_empty_block(self, idx, jdx, this_process_only: bool = True): ... + def broadcast_block_sizes(self) -> None: ... + def row_block_sizes(self, copy: bool = True): ... + def col_block_sizes(self, copy: bool = True): ... + def block_shapes(self): ... + def has_undefined_row_sizes(self): ... + def has_undefined_col_sizes(self): ... + def reset_bcol(self, jdx) -> None: ... + def reset_brow(self, idx) -> None: ... + def copy(self): ... + def copy_structure(self): ... + def get_block(self, row, col): ... + def set_block(self, row, col, value) -> None: ... + def __getitem__(self, item) -> None: ... + def __setitem__(self, item, val) -> None: ... + def __add__(self, other): ... + def __radd__(self, other): ... + def __sub__(self, other): ... + def __rsub__(self, other): ... + def __mul__(self, other): ... + def __rmul__(self, other): ... + def __pow__(self, other) -> None: ... + def __truediv__(self, other): ... + def __rtruediv__(self, other) -> None: ... + def __floordiv__(self, other): ... + def __rfloordiv__(self, other) -> None: ... + def __iadd__(self, other): ... + def __isub__(self, other): ... + def __imul__(self, other): ... + def __itruediv__(self, other): ... + def __div__(self, other): ... + def __rdiv__(self, other): ... + def __idiv__(self, other): ... + def __neg__(self): ... + def __abs__(self): ... + def __eq__(self, other): ... + def __ne__(self, other): ... + def __le__(self, other): ... + def __lt__(self, other): ... + def __ge__(self, other): ... + def __gt__(self, other): ... + def get_block_column_index(self, index): ... + def get_block_row_index(self, index): ... + def getcol(self, j): ... + def getrow(self, i): ... + @staticmethod + def fromBlockMatrix( + block_matrix, rank_ownership, mpi_comm, assert_correct_owners: bool = False + ): ... diff --git a/stubs/pyomo/contrib/pynumero/sparse/mpi_block_vector.pyi b/stubs/pyomo/contrib/pynumero/sparse/mpi_block_vector.pyi new file mode 100644 index 000000000..d89083c51 --- /dev/null +++ b/stubs/pyomo/contrib/pynumero/sparse/mpi_block_vector.pyi @@ -0,0 +1,113 @@ +import numpy as np +from pyomo.common.dependencies import mpi4py as mpi4py +from pyomo.contrib.pynumero.sparse import BlockVector as BlockVector + +from .base_block import BaseBlockVector as BaseBlockVector +from .base_block import vec_associative_reductions as vec_associative_reductions +from .base_block import vec_binary_ufuncs as vec_binary_ufuncs +from .base_block import vec_unary_ufuncs as vec_unary_ufuncs +from .block_vector import NotFullyDefinedBlockVectorError as NotFullyDefinedBlockVectorError + +def assert_block_structure(vec) -> None: ... + +class MPIBlockVector(BaseBlockVector, np.ndarray): + def __new__(cls, nblocks, rank_owner, mpi_comm, assert_correct_owners: bool = False): ... + def __init__( + self, nblocks, rank_owner, mpi_comm, assert_correct_owners: bool = False + ) -> None: ... + def __array_prepare__(self, out_arr, context=None): ... + def __array_wrap__(self, out_arr, context=None): ... + def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): ... + @property + def nblocks(self): ... + @property + def bshape(self): ... + @property + def shape(self): ... + @property + def size(self): ... + @property + def ndim(self): ... + @property + def has_none(self): ... + @property + def owned_blocks(self): ... + @property + def shared_blocks(self): ... + @property + def rank_ownership(self): ... + @property + def ownership_mask(self): ... + @property + def mpi_comm(self): ... + def is_broadcasted(self): ... + def block_sizes(self, copy: bool = True): ... + def get_block_size(self, ndx): ... + def broadcast_block_sizes(self) -> None: ... + def finalize_block_sizes(self, broadcast: bool = True, block_sizes=None) -> None: ... + def all(self, axis=None, out=None, keepdims: bool = False): ... + def any(self, axis=None, out=None, keepdims: bool = False): ... + def min(self, axis=None, out=None, keepdims: bool = False): ... + def max(self, axis=None, out=None, keepdims: bool = False): ... + def sum(self, axis=None, dtype=None, out=None, keepdims: bool = False): ... + def prod(self, axis=None, dtype=None, out=None, keepdims: bool = False): ... + def mean(self, axis=None, dtype=None, out=None, keepdims: bool = False): ... + def conj(self): ... + def conjugate(self): ... + def nonzero(self): ... + def round(self, decimals: int = 0, out=None): ... + def clip(self, min=None, max=None, out=None): ... + def compress(self, condition, axis=None, out=None): ... + def copyfrom(self, other) -> None: ... + def copyto(self, other) -> None: ... + def set_blocks(self, blocks) -> None: ... + def clone(self, value=None, copy: bool = True): ... + def copy(self, order: str = 'C'): ... + def copy_structure(self): ... + def fill(self, value) -> None: ... + def dot(self, other, out=None): ... + def make_local_structure_copy(self): ... + def make_local_copy(self): ... + def __add__(self, other): ... + def __radd__(self, other): ... + def __sub__(self, other): ... + def __rsub__(self, other): ... + def __mul__(self, other): ... + def __rmul__(self, other): ... + def __truediv__(self, other): ... + def __rtruediv__(self, other): ... + def __floordiv__(self, other): ... + def __rfloordiv__(self, other): ... + def __neg__(self): ... + def __iadd__(self, other): ... + def __isub__(self, other): ... + def __imul__(self, other): ... + def __itruediv__(self, other): ... + def __div__(self, other): ... + def __rdiv__(self, other): ... + def __idiv__(self, other): ... + def __le__(self, other): ... + def __lt__(self, other): ... + def __ge__(self, other): ... + def __gt__(self, other): ... + def __eq__(self, other): ... + def __ne__(self, other): ... + def __contains__(self, item) -> bool: ... + def get_block(self, key): ... + def set_block(self, key, value) -> None: ... + def __getitem__(self, item) -> None: ... + def __setitem__(self, key, value) -> None: ... + def pprint(self, root: int = 0) -> None: ... + def __len__(self) -> int: ... + def __iter__(self): ... + def std( + self, axis=None, dtype=None, out=None, ddof: int = 0, keepdims: bool = False + ) -> None: ... + def var( + self, axis=None, dtype=None, out=None, ddof: int = 0, keepdims: bool = False + ) -> None: ... + def cumprod(self, axis=None, dtype=None, out=None) -> None: ... + def cumsum(self, axis=None, dtype=None, out=None) -> None: ... + def tolist(self) -> None: ... + def flatten(self, order: str = 'C') -> None: ... + def ravel(self, order: str = 'C') -> None: ... diff --git a/stubs/pyomo/contrib/pyros/__init__.pyi b/stubs/pyomo/contrib/pyros/__init__.pyi new file mode 100644 index 000000000..c76a4a64a --- /dev/null +++ b/stubs/pyomo/contrib/pyros/__init__.pyi @@ -0,0 +1,15 @@ +from pyomo.contrib.pyros.pyros import PyROS as PyROS +from pyomo.contrib.pyros.uncertainty_sets import ( + AxisAlignedEllipsoidalSet as AxisAlignedEllipsoidalSet, +) +from pyomo.contrib.pyros.uncertainty_sets import BoxSet as BoxSet +from pyomo.contrib.pyros.uncertainty_sets import BudgetSet as BudgetSet +from pyomo.contrib.pyros.uncertainty_sets import CardinalitySet as CardinalitySet +from pyomo.contrib.pyros.uncertainty_sets import DiscreteScenarioSet as DiscreteScenarioSet +from pyomo.contrib.pyros.uncertainty_sets import EllipsoidalSet as EllipsoidalSet +from pyomo.contrib.pyros.uncertainty_sets import FactorModelSet as FactorModelSet +from pyomo.contrib.pyros.uncertainty_sets import IntersectionSet as IntersectionSet +from pyomo.contrib.pyros.uncertainty_sets import PolyhedralSet as PolyhedralSet +from pyomo.contrib.pyros.uncertainty_sets import UncertaintySet as UncertaintySet +from pyomo.contrib.pyros.util import ObjectiveType as ObjectiveType +from pyomo.contrib.pyros.util import pyrosTerminationCondition as pyrosTerminationCondition diff --git a/stubs/pyomo/contrib/pyros/config.pyi b/stubs/pyomo/contrib/pyros/config.pyi new file mode 100644 index 000000000..5e7c248ac --- /dev/null +++ b/stubs/pyomo/contrib/pyros/config.pyi @@ -0,0 +1,71 @@ +from _typeshed import Incomplete +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import In as In +from pyomo.common.config import InEnum as InEnum +from pyomo.common.config import IsInstance as IsInstance +from pyomo.common.config import NonNegativeFloat as NonNegativeFloat +from pyomo.common.config import Path as Path +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.common.errors import PyomoException as PyomoException +from pyomo.contrib.pyros.uncertainty_sets import UncertaintySet as UncertaintySet +from pyomo.contrib.pyros.util import ObjectiveType as ObjectiveType +from pyomo.contrib.pyros.util import setup_pyros_logger as setup_pyros_logger +from pyomo.contrib.pyros.util import standardize_component_data as standardize_component_data +from pyomo.core.base import Var as Var +from pyomo.core.base import VarData as VarData +from pyomo.core.base.param import Param as Param +from pyomo.core.base.param import ParamData as ParamData +from pyomo.opt import SolverFactory as SolverFactory + +default_pyros_solver_logger: Incomplete + +def logger_domain(obj): ... +def positive_int_or_minus_one(obj): ... +def uncertain_param_validator(uncertain_obj) -> None: ... +def uncertain_param_data_validator(uncertain_obj) -> None: ... + +class InputDataStandardizer: + ctype: Incomplete + cdatatype: Incomplete + ctype_validator: Incomplete + cdatatype_validator: Incomplete + allow_repeats: Incomplete + def __init__( + self, + ctype, + cdatatype, + ctype_validator=None, + cdatatype_validator=None, + allow_repeats: bool = False, + ) -> None: ... + def __call__(self, obj, from_iterable=None, allow_repeats=None): ... + def domain_name(self): ... + +class SolverNotResolvable(PyomoException): ... + +class SolverResolvable: + require_available: Incomplete + solver_desc: Incomplete + def __init__(self, require_available: bool = True, solver_desc: str = 'solver') -> None: ... + @staticmethod + def is_solver_type(obj): ... + def __call__(self, obj, require_available=None, solver_desc=None): ... + def domain_name(self): ... + +class SolverIterable: + require_available: Incomplete + filter_by_availability: Incomplete + solver_desc: Incomplete + def __init__( + self, + require_available: bool = True, + filter_by_availability: bool = True, + solver_desc: str = 'solver', + ) -> None: ... + def __call__( + self, obj, require_available=None, filter_by_availability=None, solver_desc=None + ): ... + def domain_name(self): ... + +def pyros_config(): ... diff --git a/stubs/pyomo/contrib/pyros/master_problem_methods.pyi b/stubs/pyomo/contrib/pyros/master_problem_methods.pyi new file mode 100644 index 000000000..a70cb47a5 --- /dev/null +++ b/stubs/pyomo/contrib/pyros/master_problem_methods.pyi @@ -0,0 +1,56 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.contrib.pyros.solve_data import MasterResults as MasterResults +from pyomo.contrib.pyros.util import ( + DR_POLISHING_PARAM_PRODUCT_ZERO_TOL as DR_POLISHING_PARAM_PRODUCT_ZERO_TOL, +) +from pyomo.contrib.pyros.util import TIC_TOC_SOLVE_TIME_ATTR as TIC_TOC_SOLVE_TIME_ATTR +from pyomo.contrib.pyros.util import ObjectiveType as ObjectiveType +from pyomo.contrib.pyros.util import call_solver as call_solver +from pyomo.contrib.pyros.util import check_time_limit_reached as check_time_limit_reached +from pyomo.contrib.pyros.util import enforce_dr_degree as enforce_dr_degree +from pyomo.contrib.pyros.util import ( + generate_all_decision_rule_var_data_objects as generate_all_decision_rule_var_data_objects, +) +from pyomo.contrib.pyros.util import get_all_first_stage_eq_cons as get_all_first_stage_eq_cons +from pyomo.contrib.pyros.util import get_dr_expression as get_dr_expression +from pyomo.contrib.pyros.util import pyrosTerminationCondition as pyrosTerminationCondition +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core.base import Block as Block +from pyomo.core.base import ConcreteModel as ConcreteModel +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import Objective as Objective +from pyomo.core.base import Var as Var +from pyomo.core.base.set_types import NonNegativeIntegers as NonNegativeIntegers +from pyomo.core.base.set_types import NonNegativeReals as NonNegativeReals +from pyomo.core.expr import identify_variables as identify_variables +from pyomo.core.expr import value as value +from pyomo.core.util import prod as prod +from pyomo.repn.standard_repn import generate_standard_repn as generate_standard_repn + +def construct_initial_master_problem(model_data): ... +def add_scenario_block_to_master_problem( + master_model, scenario_idx, param_realization, from_block, clone_first_stage_components +) -> None: ... +def construct_master_feasibility_problem(master_data): ... +def solve_master_feasibility_problem(master_data): ... +def construct_dr_polishing_problem(master_data): ... +def minimize_dr_vars(master_data): ... +def get_master_dr_degree(master_data): ... +def higher_order_decision_rule_efficiency(master_data) -> None: ... +def log_master_solve_results(master_model, config, results, desc: str = 'Optimized'): ... +def process_termination_condition_master_problem(config, results): ... +def solver_call_master(master_data): ... +def solve_master(master_data): ... + +class MasterProblemData: + master_model: Incomplete + original_model_name: Incomplete + iteration: int + timing: Incomplete + config: Incomplete + def __init__(self, model_data) -> None: ... + def solve_master(self): ... + def solve_dr_polishing(self): ... diff --git a/stubs/pyomo/contrib/pyros/pyros.pyi b/stubs/pyomo/contrib/pyros/pyros.pyi new file mode 100644 index 000000000..3d52148e5 --- /dev/null +++ b/stubs/pyomo/contrib/pyros/pyros.pyi @@ -0,0 +1,48 @@ +import types + +from _typeshed import Incomplete +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.contrib.pyros.config import logger_domain as logger_domain +from pyomo.contrib.pyros.config import pyros_config as pyros_config +from pyomo.contrib.pyros.pyros_algorithm_methods import ( + ROSolver_iterative_solve as ROSolver_iterative_solve, +) +from pyomo.contrib.pyros.solve_data import ROSolveResults as ROSolveResults +from pyomo.contrib.pyros.util import IterationLogRecord as IterationLogRecord +from pyomo.contrib.pyros.util import ModelData as ModelData +from pyomo.contrib.pyros.util import TimingData as TimingData +from pyomo.contrib.pyros.util import load_final_solution as load_final_solution +from pyomo.contrib.pyros.util import log_model_statistics as log_model_statistics +from pyomo.contrib.pyros.util import pyrosTerminationCondition as pyrosTerminationCondition +from pyomo.contrib.pyros.util import setup_pyros_logger as setup_pyros_logger +from pyomo.contrib.pyros.util import time_code as time_code +from pyomo.contrib.pyros.util import validate_pyros_inputs as validate_pyros_inputs +from pyomo.core.expr import value as value +from pyomo.opt import SolverFactory as SolverFactory + +__version__: str +default_pyros_solver_logger: Incomplete + +class PyROS: + CONFIG: Incomplete + def available(self, exception_flag: bool = True): ... + def version(self): ... + def license_is_valid(self): ... + def __enter__(self): ... + def __exit__( + self, + et: type[BaseException] | None, + ev: BaseException | None, + tb: types.TracebackType | None, + ) -> None: ... + def solve( + self, + model, + first_stage_variables, + second_stage_variables, + uncertain_params, + uncertainty_set, + local_solver, + global_solver, + **kwds, + ): ... diff --git a/stubs/pyomo/contrib/pyros/pyros_algorithm_methods.pyi b/stubs/pyomo/contrib/pyros/pyros_algorithm_methods.pyi new file mode 100644 index 000000000..686e9c02b --- /dev/null +++ b/stubs/pyomo/contrib/pyros/pyros_algorithm_methods.pyi @@ -0,0 +1,29 @@ +from typing import NamedTuple + +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.contrib.pyros.util import IterationLogRecord as IterationLogRecord +from pyomo.contrib.pyros.util import ObjectiveType as ObjectiveType +from pyomo.contrib.pyros.util import check_time_limit_reached as check_time_limit_reached +from pyomo.contrib.pyros.util import get_dr_var_to_monomial_map as get_dr_var_to_monomial_map +from pyomo.contrib.pyros.util import get_main_elapsed_time as get_main_elapsed_time +from pyomo.contrib.pyros.util import pyrosTerminationCondition as pyrosTerminationCondition +from pyomo.core.base import value as value + +class GRCSResults: + master_results: Incomplete + separation_results: Incomplete + pyros_termination_condition: Incomplete + iterations: Incomplete + def __init__( + self, master_results, separation_results, pyros_termination_condition, iterations + ) -> None: ... + +class VariableValueData(NamedTuple): + first_stage_variables: Incomplete + second_stage_variables: Incomplete + decision_rule_monomials: Incomplete + +def get_variable_value_data(working_blk, dr_var_to_monomial_map): ... +def evaluate_variable_shifts(current_var_data, previous_var_data, initial_var_data): ... +def ROSolver_iterative_solve(model_data): ... diff --git a/stubs/pyomo/contrib/pyros/separation_problem_methods.pyi b/stubs/pyomo/contrib/pyros/separation_problem_methods.pyi new file mode 100644 index 000000000..8cd3fae34 --- /dev/null +++ b/stubs/pyomo/contrib/pyros/separation_problem_methods.pyi @@ -0,0 +1,62 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.contrib.pyros.solve_data import ( + DiscreteSeparationSolveCallResults as DiscreteSeparationSolveCallResults, +) +from pyomo.contrib.pyros.solve_data import SeparationLoopResults as SeparationLoopResults +from pyomo.contrib.pyros.solve_data import SeparationResults as SeparationResults +from pyomo.contrib.pyros.solve_data import SeparationSolveCallResults as SeparationSolveCallResults +from pyomo.contrib.pyros.uncertainty_sets import Geometry as Geometry +from pyomo.contrib.pyros.util import ABS_CON_CHECK_FEAS_TOL as ABS_CON_CHECK_FEAS_TOL +from pyomo.contrib.pyros.util import call_solver as call_solver +from pyomo.contrib.pyros.util import check_time_limit_reached as check_time_limit_reached +from pyomo.contrib.pyros.util import get_all_first_stage_eq_cons as get_all_first_stage_eq_cons +from pyomo.core.base import Block as Block +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import Objective as Objective +from pyomo.core.base import Var as Var +from pyomo.core.base import maximize as maximize +from pyomo.core.base import value as value +from pyomo.core.expr import identify_mutable_parameters as identify_mutable_parameters +from pyomo.core.expr import identify_variables as identify_variables +from pyomo.core.expr import replace_expressions as replace_expressions + +def add_uncertainty_set_constraints(separation_model, config) -> None: ... +def construct_separation_problem(model_data): ... +def get_sep_objective_values(separation_data, ss_ineq_cons): ... +def get_argmax_sum_violations(solver_call_results_map, ss_ineq_cons_to_evaluate): ... +def solve_separation_problem(separation_data, master_data): ... +def evaluate_violations_by_nominal_master(separation_data, master_data, ss_ineq_cons): ... +def group_ss_ineq_constraints_by_priority(separation_data): ... +def get_worst_discrete_separation_solution( + ss_ineq_con, config, ss_ineq_cons_to_evaluate, discrete_solve_results +): ... +def get_con_name_repr(separation_model, con, with_obj_name: bool = True): ... +def perform_separation_loop(separation_data, master_data, solve_globally): ... +def evaluate_ss_ineq_con_violations( + separation_data, ss_ineq_con_to_maximize, ss_ineq_cons_to_evaluate +): ... +def initialize_separation(ss_ineq_con_to_maximize, separation_data, master_data): ... + +locally_acceptable: Incomplete +globally_acceptable: Incomplete + +def solver_call_separation( + separation_data, master_data, solve_globally, ss_ineq_con_to_maximize, ss_ineq_cons_to_evaluate +): ... +def discrete_solve( + separation_data, master_data, solve_globally, ss_ineq_con_to_maximize, ss_ineq_cons_to_evaluate +): ... + +class SeparationProblemData: + separation_model: Incomplete + timing: Incomplete + separation_priority_order: Incomplete + iteration: int + config: Incomplete + points_added_to_master: Incomplete + auxiliary_values_for_master_points: Incomplete + idxs_of_master_scenarios: Incomplete + def __init__(self, model_data) -> None: ... + def solve_separation(self, master_data): ... diff --git a/stubs/pyomo/contrib/pyros/solve_data.pyi b/stubs/pyomo/contrib/pyros/solve_data.pyi new file mode 100644 index 000000000..816206500 --- /dev/null +++ b/stubs/pyomo/contrib/pyros/solve_data.pyi @@ -0,0 +1,130 @@ +from _typeshed import Incomplete + +class ROSolveResults: + config: Incomplete + iterations: Incomplete + time: Incomplete + final_objective_value: Incomplete + pyros_termination_condition: Incomplete + def __init__( + self, + config=None, + iterations=None, + time=None, + final_objective_value=None, + pyros_termination_condition=None, + ) -> None: ... + +class MasterResults: + master_model: Incomplete + feasibility_problem_results: Incomplete + master_results_list: Incomplete + pyros_termination_condition: Incomplete + def __init__( + self, + master_model=None, + feasibility_problem_results=None, + master_results_list=None, + pyros_termination_condition=None, + ) -> None: ... + +class SeparationSolveCallResults: + results_list: Incomplete + solved_globally: Incomplete + scaled_violations: Incomplete + violating_param_realization: Incomplete + auxiliary_param_values: Incomplete + variable_values: Incomplete + found_violation: Incomplete + time_out: Incomplete + subsolver_error: Incomplete + discrete_set_scenario_index: Incomplete + def __init__( + self, + solved_globally, + results_list=None, + scaled_violations=None, + violating_param_realization=None, + auxiliary_param_values=None, + variable_values=None, + found_violation=None, + time_out=None, + subsolver_error=None, + discrete_set_scenario_index=None, + ) -> None: ... + def termination_acceptable(self, acceptable_terminations): ... + +class DiscreteSeparationSolveCallResults: + solved_globally: Incomplete + solver_call_results: Incomplete + second_stage_ineq_con: Incomplete + def __init__( + self, solved_globally, solver_call_results=None, second_stage_ineq_con=None + ) -> None: ... + @property + def time_out(self): ... + @property + def subsolver_error(self): ... + +class SeparationLoopResults: + solver_call_results: Incomplete + solved_globally: Incomplete + worst_case_ss_ineq_con: Incomplete + all_discrete_scenarios_exhausted: Incomplete + def __init__( + self, + solved_globally, + solver_call_results, + worst_case_ss_ineq_con, + all_discrete_scenarios_exhausted: bool = False, + ) -> None: ... + @property + def found_violation(self): ... + @property + def violating_param_realization(self): ... + @property + def auxiliary_param_values(self): ... + @property + def scaled_violations(self): ... + @property + def violating_separation_variable_values(self): ... + @property + def violated_second_stage_ineq_cons(self): ... + @property + def subsolver_error(self): ... + @property + def time_out(self): ... + +class SeparationResults: + local_separation_loop_results: Incomplete + global_separation_loop_results: Incomplete + def __init__(self, local_separation_loop_results, global_separation_loop_results) -> None: ... + @property + def time_out(self): ... + @property + def subsolver_error(self): ... + @property + def solved_locally(self): ... + @property + def solved_globally(self): ... + def get_violating_attr(self, attr_name): ... + @property + def all_discrete_scenarios_exhausted(self): ... + @property + def worst_case_ss_ineq_con(self): ... + @property + def main_loop_results(self): ... + @property + def found_violation(self): ... + @property + def violating_param_realization(self): ... + @property + def auxiliary_param_values(self): ... + @property + def scaled_violations(self): ... + @property + def violating_separation_variable_values(self): ... + @property + def violated_second_stage_ineq_cons(self): ... + @property + def robustness_certified(self): ... diff --git a/stubs/pyomo/contrib/pyros/uncertainty_sets.pyi b/stubs/pyomo/contrib/pyros/uncertainty_sets.pyi new file mode 100644 index 000000000..7cb030f5e --- /dev/null +++ b/stubs/pyomo/contrib/pyros/uncertainty_sets.pyi @@ -0,0 +1,296 @@ +import abc +from collections.abc import MutableSequence +from enum import Enum +from typing import NamedTuple + +from _typeshed import Incomplete +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.contrib.pyros.util import PARAM_IS_CERTAIN_ABS_TOL as PARAM_IS_CERTAIN_ABS_TOL +from pyomo.contrib.pyros.util import PARAM_IS_CERTAIN_REL_TOL as PARAM_IS_CERTAIN_REL_TOL +from pyomo.contrib.pyros.util import POINT_IN_UNCERTAINTY_SET_TOL as POINT_IN_UNCERTAINTY_SET_TOL +from pyomo.contrib.pyros.util import copy_docstring as copy_docstring +from pyomo.contrib.pyros.util import standardize_component_data as standardize_component_data +from pyomo.core.base import Block as Block +from pyomo.core.base import ConcreteModel as ConcreteModel +from pyomo.core.base import ConstraintList as ConstraintList +from pyomo.core.base import Var as Var +from pyomo.core.base import VarData as VarData +from pyomo.core.base import maximize as maximize +from pyomo.core.base import minimize as minimize +from pyomo.core.expr import mutable_expression as mutable_expression +from pyomo.core.expr import native_numeric_types as native_numeric_types +from pyomo.core.expr import value as value +from pyomo.core.util import dot_product as dot_product +from pyomo.core.util import quicksum as quicksum +from pyomo.opt.results import check_optimal_termination as check_optimal_termination + +valid_num_types: Incomplete + +def standardize_uncertain_param_vars(obj, dim): ... + +class UncertaintyQuantification(NamedTuple): + block: Incomplete + uncertainty_cons: Incomplete + uncertain_param_vars: Incomplete + auxiliary_vars: Incomplete + +def validate_arg_type( + arg_name, + arg_val, + valid_types, + valid_type_desc=None, + is_entry_of_arg: bool = False, + check_numeric_type_finite: bool = True, +) -> None: ... +def is_ragged(arr, arr_types=None): ... +def validate_dimensions(arr_name, arr, dim, display_value: bool = False) -> None: ... +def validate_array( + arr, + arr_name, + dim, + valid_types, + valid_type_desc=None, + required_shape=None, + required_shape_qual: str = '', +): ... + +class Geometry(Enum): + LINEAR = 1 + CONVEX_NONLINEAR = 2 + GENERAL_NONLINEAR = 3 + DISCRETE_SCENARIOS = 4 + +class UncertaintySet(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def dim(self): ... + @property + @abc.abstractmethod + def geometry(self): ... + @property + @abc.abstractmethod + def parameter_bounds(self): ... + def is_bounded(self, config): ... + def is_nonempty(self, config): ... + def is_valid(self, config): ... + @abc.abstractmethod + def set_as_constraint(self, uncertain_params=None, block=None): ... + def point_in_set(self, point): ... + def compute_auxiliary_uncertain_param_vals(self, point, solver=None) -> None: ... + +class UncertaintySetList(MutableSequence): + def __init__(self, uncertainty_sets=[], name=None, min_length=None) -> None: ... + def __len__(self) -> int: ... + def __getitem__(self, idx): ... + def __setitem__(self, idx, value) -> None: ... + def __delitem__(self, idx) -> None: ... + def clear(self) -> None: ... + def insert(self, idx, value) -> None: ... + @property + def dim(self): ... + +class BoxSet(UncertaintySet): + def __init__(self, bounds) -> None: ... + @property + def type(self): ... + @property + def bounds(self): ... + @bounds.setter + def bounds(self, val) -> None: ... + @property + def dim(self): ... + @property + def geometry(self): ... + @property + def parameter_bounds(self): ... + def set_as_constraint(self, uncertain_params=None, block=None): ... + +class CardinalitySet(UncertaintySet): + def __init__(self, origin, positive_deviation, gamma) -> None: ... + @property + def type(self): ... + @property + def origin(self): ... + @origin.setter + def origin(self, val) -> None: ... + @property + def positive_deviation(self): ... + @positive_deviation.setter + def positive_deviation(self, val) -> None: ... + @property + def gamma(self): ... + @gamma.setter + def gamma(self, val) -> None: ... + @property + def dim(self): ... + @property + def geometry(self): ... + @property + def parameter_bounds(self): ... + def set_as_constraint(self, uncertain_params=None, block=None): ... + def compute_auxiliary_uncertain_param_vals(self, point, solver=None): ... + def point_in_set(self, point): ... + +class PolyhedralSet(UncertaintySet): + def __init__(self, lhs_coefficients_mat, rhs_vec) -> None: ... + @property + def type(self): ... + @property + def coefficients_mat(self): ... + @coefficients_mat.setter + def coefficients_mat(self, val) -> None: ... + @property + def rhs_vec(self): ... + @rhs_vec.setter + def rhs_vec(self, val) -> None: ... + @property + def dim(self): ... + @property + def geometry(self): ... + @property + def parameter_bounds(self): ... + def set_as_constraint(self, uncertain_params=None, block=None): ... + +class BudgetSet(UncertaintySet): + def __init__(self, budget_membership_mat, rhs_vec, origin=None) -> None: ... + @property + def type(self): ... + @property + def coefficients_mat(self): ... + @property + def rhs_vec(self): ... + @property + def budget_membership_mat(self): ... + @budget_membership_mat.setter + def budget_membership_mat(self, val) -> None: ... + @property + def budget_rhs_vec(self): ... + @budget_rhs_vec.setter + def budget_rhs_vec(self, val) -> None: ... + @property + def origin(self): ... + @origin.setter + def origin(self, val) -> None: ... + @property + def dim(self): ... + @property + def geometry(self): ... + @property + def parameter_bounds(self): ... + def set_as_constraint(self, **kwargs): ... + +class FactorModelSet(UncertaintySet): + def __init__(self, origin, number_of_factors, psi_mat, beta) -> None: ... + @property + def type(self): ... + @property + def origin(self): ... + @origin.setter + def origin(self, val) -> None: ... + @property + def number_of_factors(self): ... + @number_of_factors.setter + def number_of_factors(self, val) -> None: ... + @property + def psi_mat(self): ... + @psi_mat.setter + def psi_mat(self, val) -> None: ... + @property + def beta(self): ... + @beta.setter + def beta(self, val) -> None: ... + @property + def dim(self): ... + @property + def geometry(self): ... + @property + def parameter_bounds(self): ... + def set_as_constraint(self, uncertain_params=None, block=None): ... + def compute_auxiliary_uncertain_param_vals(self, point, solver=None): ... + def point_in_set(self, point): ... + +class AxisAlignedEllipsoidalSet(UncertaintySet): + def __init__(self, center, half_lengths) -> None: ... + @property + def type(self): ... + @property + def center(self): ... + @center.setter + def center(self, val) -> None: ... + @property + def half_lengths(self): ... + @half_lengths.setter + def half_lengths(self, val) -> None: ... + @property + def dim(self): ... + @property + def geometry(self): ... + @property + def parameter_bounds(self): ... + def set_as_constraint(self, uncertain_params=None, block=None): ... + +class EllipsoidalSet(UncertaintySet): + def __init__(self, center, shape_matrix, scale: int = 1, gaussian_conf_lvl=None) -> None: ... + @property + def type(self): ... + @property + def center(self): ... + @center.setter + def center(self, val) -> None: ... + @property + def shape_matrix(self): ... + @shape_matrix.setter + def shape_matrix(self, val) -> None: ... + @property + def scale(self): ... + @scale.setter + def scale(self, val) -> None: ... + @property + def gaussian_conf_lvl(self): ... + @gaussian_conf_lvl.setter + def gaussian_conf_lvl(self, val) -> None: ... + @property + def dim(self): ... + @property + def geometry(self): ... + @property + def parameter_bounds(self): ... + def point_in_set(self, point): ... + def set_as_constraint(self, uncertain_params=None, block=None): ... + +class DiscreteScenarioSet(UncertaintySet): + def __init__(self, scenarios) -> None: ... + @property + def type(self): ... + @property + def scenarios(self): ... + @scenarios.setter + def scenarios(self, val) -> None: ... + @property + def dim(self): ... + @property + def geometry(self): ... + @property + def parameter_bounds(self): ... + def is_bounded(self, config): ... + def set_as_constraint(self, uncertain_params=None, block=None): ... + def point_in_set(self, point): ... + +class IntersectionSet(UncertaintySet): + def __init__(self, **unc_sets) -> None: ... + @property + def type(self): ... + @property + def all_sets(self): ... + @all_sets.setter + def all_sets(self, val) -> None: ... + @property + def dim(self): ... + @property + def geometry(self): ... + @property + def parameter_bounds(self): ... + def point_in_set(self, point): ... + @staticmethod + def intersect(Q1, Q2): ... + def set_as_constraint(self, uncertain_params=None, block=None): ... diff --git a/stubs/pyomo/contrib/pyros/util.pyi b/stubs/pyomo/contrib/pyros/util.pyi new file mode 100644 index 000000000..52cfd84e4 --- /dev/null +++ b/stubs/pyomo/contrib/pyros/util.pyi @@ -0,0 +1,223 @@ +import logging +from collections.abc import Generator +from contextlib import contextmanager +from enum import Enum +from typing import NamedTuple + +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.common.errors import InvalidValueError as InvalidValueError +from pyomo.common.log import Preformatted as Preformatted +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.common.timing import HierarchicalTimer as HierarchicalTimer +from pyomo.common.timing import TicTocTimer as TicTocTimer +from pyomo.core.base import Any as Any +from pyomo.core.base import Block as Block +from pyomo.core.base import Component as Component +from pyomo.core.base import ConcreteModel as ConcreteModel +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import Expression as Expression +from pyomo.core.base import Objective as Objective +from pyomo.core.base import Param as Param +from pyomo.core.base import ParamData as ParamData +from pyomo.core.base import Reals as Reals +from pyomo.core.base import Var as Var +from pyomo.core.base import VarData as VarData +from pyomo.core.base import maximize as maximize +from pyomo.core.base import minimize as minimize +from pyomo.core.base import value as value +from pyomo.core.expr.numeric_expr import SumExpression as SumExpression +from pyomo.core.expr.numvalue import native_types as native_types +from pyomo.core.expr.visitor import identify_mutable_parameters as identify_mutable_parameters +from pyomo.core.expr.visitor import identify_variables as identify_variables +from pyomo.core.expr.visitor import replace_expressions as replace_expressions +from pyomo.core.util import prod as prod +from pyomo.opt import SolverFactory as SolverFactory +from pyomo.repn.parameterized_quadratic import ( + ParameterizedQuadraticRepnVisitor as ParameterizedQuadraticRepnVisitor, +) +from pyomo.repn.util import OrderedVarRecorder as OrderedVarRecorder +from pyomo.util.vars_from_expressions import get_vars_from_components as get_vars_from_components + +PARAM_IS_CERTAIN_REL_TOL: float +PARAM_IS_CERTAIN_ABS_TOL: int +COEFF_MATCH_REL_TOL: float +COEFF_MATCH_ABS_TOL: int +ABS_CON_CHECK_FEAS_TOL: float +PRETRIANGULAR_VAR_COEFF_TOL: float +POINT_IN_UNCERTAINTY_SET_TOL: float +DR_POLISHING_PARAM_PRODUCT_ZERO_TOL: float +TIC_TOC_SOLVE_TIME_ATTR: str +DEFAULT_LOGGER_NAME: str +DEFAULT_SEPARATION_PRIORITY: int + +class TimingData: + hierarchical_timer_full_ids: Incomplete + def __init__(self) -> None: ... + def start_timer(self, full_identifier): ... + def stop_timer(self, full_identifier): ... + def get_total_time(self, full_identifier): ... + def get_main_elapsed_time(self): ... + +@contextmanager +def time_code(timing_data_obj, code_block_name, is_main_timer: bool = False) -> Generator[None]: ... +def get_main_elapsed_time(timing_data_obj): ... +def adjust_solver_time_settings(timing_data_obj, solver, config): ... +def revert_solver_max_time_adjustment( + solver, original_max_time_setting, custom_setting_present, config +) -> None: ... + +class PreformattedLogger(logging.Logger): + def critical(self, msg, *args, **kwargs): ... + def error(self, msg, *args, **kwargs): ... + def warning(self, msg, *args, **kwargs): ... + def info(self, msg, *args, **kwargs): ... + def debug(self, msg, *args, **kwargs): ... + def log(self, level, msg, *args, **kwargs): ... + +def setup_pyros_logger(name=...): ... + +class pyrosTerminationCondition(Enum): + robust_feasible = 0 + robust_optimal = 1 + robust_infeasible = 2 + max_iter = 3 + subsolver_error = 4 + time_out = 5 + @property + def message(self): ... + +class SeparationStrategy(Enum): + all_violations = ... + max_violation = ... + +class SolveMethod(Enum): + local_solve = ... + global_solve = ... + +class ObjectiveType(Enum): + worst_case = ... + nominal = ... + +def standardize_component_data( + obj, + valid_ctype, + valid_cdatatype, + ctype_validator=None, + cdatatype_validator=None, + allow_repeats: bool = False, + from_iterable=None, +): ... +def check_components_descended_from_model(model, components, components_name, config) -> None: ... +def check_variables_continuous(model, vars, config) -> None: ... +def validate_model(model, config) -> None: ... + +class VariablePartitioning(NamedTuple): + first_stage_variables: Incomplete + second_stage_variables: Incomplete + state_variables: Incomplete + +def validate_variable_partitioning(model, config): ... +def validate_uncertainty_specification(model, config) -> None: ... +def validate_separation_problem_options(model, config) -> None: ... +def validate_pyros_inputs(model, config): ... + +class ModelData: + original_model: Incomplete + timing: Incomplete + config: Incomplete + separation_priority_order: Incomplete + working_model: Incomplete + def __init__(self, original_model, config, timing) -> None: ... + def preprocess(self, user_var_partitioning): ... + +def setup_quadratic_expression_visitor( + wrt, subexpression_cache=None, var_map=None, var_order=None, sorter=None +): ... + +class BoundType: + LOWER: str + EQ: str + UPPER: str + +def get_var_bound_pairs(var): ... +def determine_certain_and_uncertain_bound( + domain_bound, declared_bound, uncertain_params, bound_type +): ... + +BoundTriple: Incomplete + +def rearrange_bound_pair_to_triple(lower_bound, upper_bound): ... +def get_var_certain_uncertain_bounds(var, uncertain_params): ... +def get_effective_var_partitioning(model_data): ... +def add_effective_var_partitioning(model_data) -> None: ... +def create_bound_constraint_expr(expr, bound, bound_type, standardize: bool = True): ... +def remove_var_declared_bound(var, bound_type) -> None: ... +def remove_all_var_bounds(var) -> None: ... +def turn_nonadjustable_var_bounds_to_constraints(model_data) -> None: ... +def turn_adjustable_var_bounds_to_constraints(model_data) -> None: ... +def replace_vars_with_params(block, var_to_param_map) -> None: ... +def setup_working_model(model_data, user_var_partitioning) -> None: ... +def standardize_inequality_constraints(model_data) -> None: ... +def standardize_equality_constraints(model_data) -> None: ... +def get_summands(expr): ... +def declare_objective_expressions(working_model, objective, sense=...) -> None: ... +def standardize_active_objective(model_data) -> None: ... +def get_all_nonadjustable_variables(working_model): ... +def get_all_first_stage_eq_cons(working_model): ... +def get_all_adjustable_variables(working_model): ... +def generate_all_decision_rule_var_data_objects( + working_blk, +) -> Generator[Incomplete, Incomplete]: ... +def generate_all_decision_rule_eqns(working_blk) -> Generator[Incomplete, Incomplete]: ... +def get_dr_expression(working_blk, second_stage_var): ... +def get_dr_var_to_monomial_map(working_blk): ... +def check_time_limit_reached(timing_data, config): ... +def reformulate_state_var_independent_eq_cons(model_data): ... +def get_effective_uncertain_dimensions(model_data): ... +def preprocess_model_data(model_data, user_var_partitioning): ... +def log_model_statistics(model_data) -> None: ... +def add_decision_rule_variables(model_data) -> None: ... +def add_decision_rule_constraints(model_data) -> None: ... +def enforce_dr_degree(working_blk, config, degree) -> None: ... +def load_final_solution(model_data, master_soln, original_user_var_partitioning): ... +def call_solver(model, solver, config, timing_obj, timer_name, err_msg): ... + +class IterationLogRecord: + iteration: Incomplete + objective: Incomplete + first_stage_var_shift: Incomplete + second_stage_var_shift: Incomplete + dr_var_shift: Incomplete + dr_polishing_success: Incomplete + num_violated_cons: Incomplete + all_sep_problems_solved: Incomplete + global_separation: Incomplete + max_violation: Incomplete + elapsed_time: Incomplete + def __init__( + self, + iteration, + objective, + first_stage_var_shift, + second_stage_var_shift, + dr_var_shift, + dr_polishing_success, + num_violated_cons, + all_sep_problems_solved, + global_separation, + max_violation, + elapsed_time, + ) -> None: ... + def get_log_str(self): ... + def log(self, log_func, **log_func_kwargs) -> None: ... + @staticmethod + def get_log_header_str(): ... + @staticmethod + def log_header(log_func, with_rules: bool = True, **log_func_kwargs) -> None: ... + @staticmethod + def log_header_rule(log_func, fillchar: str = '-', **log_func_kwargs) -> None: ... + +def copy_docstring(source_func): ... diff --git a/stubs/pyomo/contrib/satsolver/__init__.pyi b/stubs/pyomo/contrib/satsolver/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/satsolver/satsolver.pyi b/stubs/pyomo/contrib/satsolver/satsolver.pyi new file mode 100644 index 000000000..a6b050fd1 --- /dev/null +++ b/stubs/pyomo/contrib/satsolver/satsolver.pyi @@ -0,0 +1,49 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.core import Constraint as Constraint +from pyomo.core import NumericLabeler as NumericLabeler +from pyomo.core import SymbolMap as SymbolMap +from pyomo.core import Var as Var +from pyomo.core import value as value +from pyomo.core.expr import AbsExpression as AbsExpression +from pyomo.core.expr import DivisionExpression as DivisionExpression +from pyomo.core.expr import EqualityExpression as EqualityExpression +from pyomo.core.expr import InequalityExpression as InequalityExpression +from pyomo.core.expr import MonomialTermExpression as MonomialTermExpression +from pyomo.core.expr import NegationExpression as NegationExpression +from pyomo.core.expr import PowExpression as PowExpression +from pyomo.core.expr import ProductExpression as ProductExpression +from pyomo.core.expr import SumExpression as SumExpression +from pyomo.core.expr import UnaryFunctionExpression as UnaryFunctionExpression +from pyomo.core.expr.numvalue import nonpyomo_leaf_types as nonpyomo_leaf_types +from pyomo.core.expr.visitor import StreamBasedExpressionVisitor as StreamBasedExpressionVisitor +from pyomo.gdp import Disjunction as Disjunction + +z3: Incomplete +z3_available: Incomplete + +def satisfiable(model, logger=None): ... + +class SMTSatSolver: + variable_label_map: Incomplete + prefix_expr_list: Incomplete + variable_list: Incomplete + bounds_list: Incomplete + expression_list: Incomplete + disjunctions_list: Incomplete + walker: Incomplete + solver: Incomplete + logger: Incomplete + def __init__(self, model=None, logger=None) -> None: ... + def add_var(self, var): ... + def add_expr(self, expression) -> None: ... + def get_SMT_string(self): ... + def get_var_dict(self): ... + def check(self): ... + +class SMT_visitor(StreamBasedExpressionVisitor): + variable_label_map: Incomplete + def __init__(self, varmap) -> None: ... + def exitNode(self, node, data): ... + def beforeChild(self, node, child, child_idx): ... + def finalizeResult(self, node_result): ... diff --git a/stubs/pyomo/contrib/sensitivity_toolbox/__init__.pyi b/stubs/pyomo/contrib/sensitivity_toolbox/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/sensitivity_toolbox/examples/HIV_Transmission.pyi b/stubs/pyomo/contrib/sensitivity_toolbox/examples/HIV_Transmission.pyi new file mode 100644 index 000000000..fb14a8811 --- /dev/null +++ b/stubs/pyomo/contrib/sensitivity_toolbox/examples/HIV_Transmission.pyi @@ -0,0 +1,20 @@ +from pyomo.contrib.sensitivity_toolbox.sens import ( + sensitivity_calculation as sensitivity_calculation, +) +from pyomo.dae import ContinuousSet as ContinuousSet +from pyomo.dae import DerivativeVar as DerivativeVar +from pyomo.dae.simulator import Simulator as Simulator +from pyomo.environ import ConcreteModel as ConcreteModel +from pyomo.environ import Constraint as Constraint +from pyomo.environ import Expression as Expression +from pyomo.environ import Objective as Objective +from pyomo.environ import Param as Param +from pyomo.environ import Set as Set +from pyomo.environ import Suffix as Suffix +from pyomo.environ import TransformationFactory as TransformationFactory +from pyomo.environ import Var as Var +from pyomo.environ import exp as exp +from pyomo.environ import value as value + +def create_model(): ... +def initialize_model(m, n_sim, n_nfe, n_ncp) -> None: ... diff --git a/stubs/pyomo/contrib/sensitivity_toolbox/examples/__init__.pyi b/stubs/pyomo/contrib/sensitivity_toolbox/examples/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/sensitivity_toolbox/examples/feedbackController.pyi b/stubs/pyomo/contrib/sensitivity_toolbox/examples/feedbackController.pyi new file mode 100644 index 000000000..540249ded --- /dev/null +++ b/stubs/pyomo/contrib/sensitivity_toolbox/examples/feedbackController.pyi @@ -0,0 +1,19 @@ +from pyomo.contrib.sensitivity_toolbox.sens import ( + sensitivity_calculation as sensitivity_calculation, +) +from pyomo.dae import ContinuousSet as ContinuousSet +from pyomo.dae import DerivativeVar as DerivativeVar +from pyomo.dae.simulator import Simulator as Simulator +from pyomo.environ import ConcreteModel as ConcreteModel +from pyomo.environ import Constraint as Constraint +from pyomo.environ import Objective as Objective +from pyomo.environ import Param as Param +from pyomo.environ import SolverFactory as SolverFactory +from pyomo.environ import Suffix as Suffix +from pyomo.environ import TransformationFactory as TransformationFactory +from pyomo.environ import Var as Var +from pyomo.environ import value as value + +def create_model(): ... +def initialize_model(m, nfe) -> None: ... +def plot_optimal_solution(m): ... diff --git a/stubs/pyomo/contrib/sensitivity_toolbox/examples/parameter.pyi b/stubs/pyomo/contrib/sensitivity_toolbox/examples/parameter.pyi new file mode 100644 index 000000000..fe139402f --- /dev/null +++ b/stubs/pyomo/contrib/sensitivity_toolbox/examples/parameter.pyi @@ -0,0 +1,13 @@ +from pyomo.contrib.sensitivity_toolbox.sens import ( + sensitivity_calculation as sensitivity_calculation, +) +from pyomo.environ import ConcreteModel as ConcreteModel +from pyomo.environ import Constraint as Constraint +from pyomo.environ import NonNegativeReals as NonNegativeReals +from pyomo.environ import Objective as Objective +from pyomo.environ import Param as Param +from pyomo.environ import Var as Var +from pyomo.environ import value as value + +def create_model(): ... +def run_example(print_flag: bool = True): ... diff --git a/stubs/pyomo/contrib/sensitivity_toolbox/examples/parameter_kaug.pyi b/stubs/pyomo/contrib/sensitivity_toolbox/examples/parameter_kaug.pyi new file mode 100644 index 000000000..77fc9bfc8 --- /dev/null +++ b/stubs/pyomo/contrib/sensitivity_toolbox/examples/parameter_kaug.pyi @@ -0,0 +1,7 @@ +from pyomo.contrib.sensitivity_toolbox.sens import ( + sensitivity_calculation as sensitivity_calculation, +) +from pyomo.environ import * + +def create_model(): ... +def run_example(print_flag: bool = True): ... diff --git a/stubs/pyomo/contrib/sensitivity_toolbox/examples/rangeInequality.pyi b/stubs/pyomo/contrib/sensitivity_toolbox/examples/rangeInequality.pyi new file mode 100644 index 000000000..cf3141188 --- /dev/null +++ b/stubs/pyomo/contrib/sensitivity_toolbox/examples/rangeInequality.pyi @@ -0,0 +1,10 @@ +from pyomo.contrib.sensitivity_toolbox.sens import ( + sensitivity_calculation as sensitivity_calculation, +) +from pyomo.environ import ConcreteModel as ConcreteModel +from pyomo.environ import Constraint as Constraint +from pyomo.environ import Param as Param +from pyomo.environ import Var as Var +from pyomo.environ import inequality as inequality + +def create_model(): ... diff --git a/stubs/pyomo/contrib/sensitivity_toolbox/examples/rooney_biegler.pyi b/stubs/pyomo/contrib/sensitivity_toolbox/examples/rooney_biegler.pyi new file mode 100644 index 000000000..f100efac7 --- /dev/null +++ b/stubs/pyomo/contrib/sensitivity_toolbox/examples/rooney_biegler.pyi @@ -0,0 +1,2 @@ +def rooney_biegler_model(data): ... +def rooney_biegler_model_opt(): ... diff --git a/stubs/pyomo/contrib/sensitivity_toolbox/k_aug.pyi b/stubs/pyomo/contrib/sensitivity_toolbox/k_aug.pyi new file mode 100644 index 000000000..004c223ea --- /dev/null +++ b/stubs/pyomo/contrib/sensitivity_toolbox/k_aug.pyi @@ -0,0 +1,27 @@ +import types + +from _typeshed import Incomplete +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.environ import SolverFactory as SolverFactory + +debug_dir: str +gjh_dir: str +known_files: Incomplete + +class InTempDir: + def __init__(self, suffix=None, prefix=None, dir=None) -> None: ... + def __enter__(self) -> None: ... + def __exit__( + self, + ex_type: type[BaseException] | None, + ex_val: BaseException | None, + ex_bt: types.TracebackType | None, + ) -> None: ... + +class K_augInterface: + data: Incomplete + def __init__(self, k_aug=None, dot_sens=None) -> None: ... + def k_aug(self, model, **kwargs): ... + def dot_sens(self, model, **kwargs): ... + def set_k_aug_options(self, **options) -> None: ... + def set_dot_sens_options(self, **options) -> None: ... diff --git a/stubs/pyomo/contrib/sensitivity_toolbox/sens.pyi b/stubs/pyomo/contrib/sensitivity_toolbox/sens.pyi new file mode 100644 index 000000000..6694fbe84 --- /dev/null +++ b/stubs/pyomo/contrib/sensitivity_toolbox/sens.pyi @@ -0,0 +1,72 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies import scipy as scipy +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.common.sorting import sorted_robust as sorted_robust +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.contrib.sensitivity_toolbox.k_aug import InTempDir as InTempDir +from pyomo.contrib.sensitivity_toolbox.k_aug import K_augInterface as K_augInterface +from pyomo.core.expr import ExpressionReplacementVisitor as ExpressionReplacementVisitor +from pyomo.core.expr.numvalue import is_potentially_variable as is_potentially_variable +from pyomo.environ import Block as Block +from pyomo.environ import ComponentMap as ComponentMap +from pyomo.environ import ComponentUID as ComponentUID +from pyomo.environ import Constraint as Constraint +from pyomo.environ import ConstraintList as ConstraintList +from pyomo.environ import Objective as Objective +from pyomo.environ import Param as Param +from pyomo.environ import Suffix as Suffix +from pyomo.environ import Var as Var +from pyomo.environ import value as value +from pyomo.opt import SolverFactory as SolverFactory +from pyomo.opt import SolverStatus as SolverStatus + +logger: Incomplete + +def sipopt( + instance, + paramSubList, + perturbList, + cloneModel: bool = True, + tee: bool = False, + keepfiles: bool = False, + streamSoln: bool = False, +): ... +def kaug( + instance, + paramSubList, + perturbList, + cloneModel: bool = True, + tee: bool = False, + keepfiles: bool = False, + solver_options=None, + streamSoln: bool = False, +): ... + +class _NotAnIndex: ... + +def sensitivity_calculation( + method, + instance, + paramList, + perturbList, + cloneModel: bool = True, + tee: bool = False, + keepfiles: bool = False, + solver_options=None, +): ... +def get_dsdp(model, theta_names, theta, tee: bool = False): ... +def get_dfds_dcds(model, theta_names, tee: bool = False, solver_options=None): ... +def line_num(file_name, target): ... + +class SensitivityInterface: + model_instance: Incomplete + def __init__(self, instance, clone_model: bool = True) -> None: ... + @classmethod + def get_default_block_name(self): ... + @staticmethod + def get_default_var_name(name): ... + @staticmethod + def get_default_param_name(name): ... + def setup_sensitivity(self, paramList) -> None: ... + def perturb_parameters(self, perturbList) -> None: ... diff --git a/stubs/pyomo/contrib/simplification/__init__.pyi b/stubs/pyomo/contrib/simplification/__init__.pyi new file mode 100644 index 000000000..f07c4d223 --- /dev/null +++ b/stubs/pyomo/contrib/simplification/__init__.pyi @@ -0,0 +1 @@ +from .simplify import Simplifier as Simplifier diff --git a/stubs/pyomo/contrib/simplification/build.pyi b/stubs/pyomo/contrib/simplification/build.pyi new file mode 100644 index 000000000..3b39a912b --- /dev/null +++ b/stubs/pyomo/contrib/simplification/build.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from pyomo.common.download import FileDownloader as FileDownloader +from pyomo.common.envvar import PYOMO_CONFIG_DIR as PYOMO_CONFIG_DIR +from pyomo.common.fileutils import find_library as find_library +from pyomo.common.fileutils import this_file_dir as this_file_dir +from pyomo.common.tempfiles import TempfileManager as TempfileManager + +logger: Incomplete + +def build_ginac_library(parallel=None, argv=None, env=None) -> None: ... +def build_ginac_interface(parallel=None, args=None) -> None: ... + +class GiNaCInterfaceBuilder: + def __call__(self, parallel): ... + def skip(self): ... diff --git a/stubs/pyomo/contrib/simplification/ginac/__init__.pyi b/stubs/pyomo/contrib/simplification/ginac/__init__.pyi new file mode 100644 index 000000000..ab638b87f --- /dev/null +++ b/stubs/pyomo/contrib/simplification/ginac/__init__.pyi @@ -0,0 +1,4 @@ +from _typeshed import Incomplete + +interface: Incomplete +interface_available: Incomplete diff --git a/stubs/pyomo/contrib/simplification/plugins.pyi b/stubs/pyomo/contrib/simplification/plugins.pyi new file mode 100644 index 000000000..09727cccc --- /dev/null +++ b/stubs/pyomo/contrib/simplification/plugins.pyi @@ -0,0 +1,5 @@ +from pyomo.common.extensions import ExtensionBuilderFactory as ExtensionBuilderFactory + +from .build import GiNaCInterfaceBuilder as GiNaCInterfaceBuilder + +def load() -> None: ... diff --git a/stubs/pyomo/contrib/simplification/simplify.pyi b/stubs/pyomo/contrib/simplification/simplify.pyi new file mode 100644 index 000000000..23ac2239f --- /dev/null +++ b/stubs/pyomo/contrib/simplification/simplify.pyi @@ -0,0 +1,20 @@ +from _typeshed import Incomplete +from pyomo.common.enums import NamedIntEnum as NamedIntEnum +from pyomo.core.expr.numeric_expr import NumericExpression as NumericExpression +from pyomo.core.expr.numvalue import is_constant as is_constant +from pyomo.core.expr.numvalue import value as value +from pyomo.core.expr.sympy_tools import sympy2pyomo_expression as sympy2pyomo_expression +from pyomo.core.expr.sympy_tools import sympyify_expression as sympyify_expression + +def simplify_with_sympy(expr: NumericExpression): ... +def simplify_with_ginac(expr: NumericExpression, ginac_interface): ... + +class Simplifier: + class Mode(NamedIntEnum): + auto = 0 + sympy = 1 + ginac = 2 + + gi: Incomplete + simplify: Incomplete + def __init__(self, suppress_no_ginac_warnings: bool = False, mode: Mode = ...) -> None: ... diff --git a/stubs/pyomo/contrib/solver/__init__.pyi b/stubs/pyomo/contrib/solver/__init__.pyi new file mode 100644 index 000000000..460fc3dc3 --- /dev/null +++ b/stubs/pyomo/contrib/solver/__init__.pyi @@ -0,0 +1 @@ +from pyomo.common.deprecation import moved_module as moved_module diff --git a/stubs/pyomo/contrib/solver/common/__init__.pyi b/stubs/pyomo/contrib/solver/common/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/solver/common/base.pyi b/stubs/pyomo/contrib/solver/common/base.pyi new file mode 100644 index 000000000..c85bc53ed --- /dev/null +++ b/stubs/pyomo/contrib/solver/common/base.pyi @@ -0,0 +1,112 @@ +import types +from typing import Sequence + +from _typeshed import Incomplete +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.common.enums import IntEnum as IntEnum +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.contrib.solver.common.config import PersistentSolverConfig as PersistentSolverConfig +from pyomo.contrib.solver.common.config import SolverConfig as SolverConfig +from pyomo.contrib.solver.common.results import Results as Results +from pyomo.contrib.solver.common.results import ( + legacy_solution_status_map as legacy_solution_status_map, +) +from pyomo.contrib.solver.common.results import legacy_solver_status_map as legacy_solver_status_map +from pyomo.contrib.solver.common.results import ( + legacy_termination_condition_map as legacy_termination_condition_map, +) +from pyomo.contrib.solver.common.util import get_objective as get_objective +from pyomo.core.base import SymbolMap as SymbolMap +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.constraint import ConstraintData as ConstraintData +from pyomo.core.base.label import NumericLabeler as NumericLabeler +from pyomo.core.base.objective import Objective as Objective +from pyomo.core.base.objective import ObjectiveData as ObjectiveData +from pyomo.core.base.param import ParamData as ParamData +from pyomo.core.base.var import VarData as VarData +from pyomo.core.kernel.objective import minimize as minimize +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager +from pyomo.scripting.solve_config import default_config_block as default_config_block + +class Availability(IntEnum): + FullLicense = 2 + LimitedLicense = 1 + NotFound = 0 + BadVersion = -1 + BadLicense = -2 + NeedsCompiledExtension = -3 + def __bool__(self) -> bool: ... + def __format__(self, format_spec) -> str: ... + +class SolverBase: + CONFIG: Incomplete + name: Incomplete + config: Incomplete + def __init__(self, **kwds) -> None: ... + def __enter__(self): ... + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + exc_traceback: types.TracebackType | None, + ) -> None: ... + def solve(self, model: BlockData, **kwargs) -> Results: ... + def available(self) -> Availability: ... + def version(self) -> tuple: ... + def is_persistent(self) -> bool: ... + +class PersistentSolverBase(SolverBase): + CONFIG: Incomplete + def __init__(self, **kwds) -> None: ... + def solve(self, model: BlockData, **kwargs) -> Results: ... + def is_persistent(self) -> bool: ... + def set_instance(self, model: BlockData): ... + def set_objective(self, obj: ObjectiveData): ... + def add_variables(self, variables: list[VarData]): ... + def add_parameters(self, params: list[ParamData]): ... + def add_constraints(self, cons: list[ConstraintData]): ... + def add_block(self, block: BlockData): ... + def remove_variables(self, variables: list[VarData]): ... + def remove_parameters(self, params: list[ParamData]): ... + def remove_constraints(self, cons: list[ConstraintData]): ... + def remove_block(self, block: BlockData): ... + def update_variables(self, variables: list[VarData]): ... + def update_parameters(self) -> None: ... + +class LegacySolverWrapper: + options: Incomplete + def __init__(self, **kwargs) -> None: ... + def __enter__(self): ... + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + exc_traceback: types.TracebackType | None, + ) -> None: ... + def __setattr__(self, attr, value) -> None: ... + config: Incomplete + def solve( + self, + model: BlockData, + tee: bool = False, + load_solutions: bool = True, + logfile: str | None = None, + solnfile: str | None = None, + timelimit: float | None = None, + report_timing: bool = False, + solver_io: str | None = None, + suffixes: Sequence | None = None, + options: dict | None = None, + keepfiles: bool = False, + symbolic_solver_labels: bool = False, + raise_exception_on_nonoptimal_result: bool = False, + solver_options: dict | None = None, + writer_config: dict | None = None, + ): ... + def available(self, exception_flag: bool = True): ... + def license_is_valid(self) -> bool: ... + def config_block(self, init: bool = False): ... + def set_options(self, options) -> None: ... diff --git a/stubs/pyomo/contrib/solver/common/config.pyi b/stubs/pyomo/contrib/solver/common/config.pyi new file mode 100644 index 000000000..700eface9 --- /dev/null +++ b/stubs/pyomo/contrib/solver/common/config.pyi @@ -0,0 +1,84 @@ +from typing import TextIO + +from pyomo.common.config import Bool as Bool +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import NonNegativeFloat as NonNegativeFloat +from pyomo.common.config import NonNegativeInt as NonNegativeInt +from pyomo.common.config import Path as Path +from pyomo.common.log import LogStream as LogStream +from pyomo.common.numeric_types import native_logical_types as native_logical_types +from pyomo.common.timing import HierarchicalTimer as HierarchicalTimer + +def TextIO_or_Logger(val): ... + +class SolverConfig(ConfigDict): + tee: list[TextIO] + working_dir: Path | None + load_solutions: bool + raise_exception_on_nonoptimal_result: bool + symbolic_solver_labels: bool + timer: HierarchicalTimer | None + threads: int | None + time_limit: float | None + solver_options: ConfigDict + def __init__( + self, + description=None, + doc=None, + implicit: bool = False, + implicit_domain=None, + visibility: int = 0, + ) -> None: ... + +class BranchAndBoundConfig(SolverConfig): + rel_gap: float | None + abs_gap: float | None + def __init__( + self, + description=None, + doc=None, + implicit: bool = False, + implicit_domain=None, + visibility: int = 0, + ) -> None: ... + +class AutoUpdateConfig(ConfigDict): + check_for_new_or_removed_constraints: bool + check_for_new_or_removed_vars: bool + check_for_new_or_removed_params: bool + check_for_new_objective: bool + update_constraints: bool + update_vars: bool + update_parameters: bool + update_named_expressions: bool + update_objective: bool + def __init__( + self, + description=None, + doc=None, + implicit: bool = False, + implicit_domain=None, + visibility: int = 0, + ) -> None: ... + +class PersistentSolverConfig(SolverConfig): + auto_updates: AutoUpdateConfig + def __init__( + self, + description=None, + doc=None, + implicit: bool = False, + implicit_domain=None, + visibility: int = 0, + ) -> None: ... + +class PersistentBranchAndBoundConfig(PersistentSolverConfig, BranchAndBoundConfig): + def __init__( + self, + description=None, + doc=None, + implicit: bool = False, + implicit_domain=None, + visibility: int = 0, + ) -> None: ... diff --git a/stubs/pyomo/contrib/solver/common/factory.pyi b/stubs/pyomo/contrib/solver/common/factory.pyi new file mode 100644 index 000000000..b46112b8e --- /dev/null +++ b/stubs/pyomo/contrib/solver/common/factory.pyi @@ -0,0 +1,9 @@ +from _typeshed import Incomplete +from pyomo.common.factory import Factory as Factory +from pyomo.contrib.solver.common.base import LegacySolverWrapper as LegacySolverWrapper +from pyomo.opt.base.solvers import LegacySolverFactory as LegacySolverFactory + +class SolverFactoryClass(Factory): + def register(self, name, legacy_name=None, doc=None): ... + +SolverFactory: Incomplete diff --git a/stubs/pyomo/contrib/solver/common/persistent.pyi b/stubs/pyomo/contrib/solver/common/persistent.pyi new file mode 100644 index 000000000..ecebdf69c --- /dev/null +++ b/stubs/pyomo/contrib/solver/common/persistent.pyi @@ -0,0 +1,42 @@ +import abc + +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.timing import HierarchicalTimer as HierarchicalTimer +from pyomo.contrib.solver.common.results import Results as Results +from pyomo.contrib.solver.common.util import ( + collect_vars_and_named_exprs as collect_vars_and_named_exprs, +) +from pyomo.contrib.solver.common.util import get_objective as get_objective +from pyomo.core.base.constraint import Constraint as Constraint +from pyomo.core.base.constraint import ConstraintData as ConstraintData +from pyomo.core.base.objective import ObjectiveData as ObjectiveData +from pyomo.core.base.param import Param as Param +from pyomo.core.base.param import ParamData as ParamData +from pyomo.core.base.sos import SOSConstraint as SOSConstraint +from pyomo.core.base.sos import SOSConstraintData as SOSConstraintData +from pyomo.core.base.var import VarData as VarData +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager + +class PersistentSolverUtils(abc.ABC, metaclass=abc.ABCMeta): + def __init__(self, treat_fixed_vars_as_params: bool = True) -> None: ... + config: Incomplete + def set_instance(self, model) -> None: ... + def add_variables(self, variables: list[VarData]): ... + def add_parameters(self, params: list[ParamData]): ... + def add_constraints(self, cons: list[ConstraintData]): ... + def add_sos_constraints(self, cons: list[SOSConstraintData]): ... + def set_objective(self, obj: ObjectiveData): ... + def add_block(self, block) -> None: ... + def remove_constraints(self, cons: list[ConstraintData]): ... + def remove_sos_constraints(self, cons: list[SOSConstraintData]): ... + def remove_variables(self, variables: list[VarData]): ... + def remove_parameters(self, params: list[ParamData]): ... + def remove_block(self, block) -> None: ... + def update_variables(self, variables: list[VarData]): ... + @abc.abstractmethod + def update_parameters(self): ... + def update(self, timer: HierarchicalTimer = None): ... + +class PersistentSolverMixin: + def solve(self, model, **kwds) -> Results: ... diff --git a/stubs/pyomo/contrib/solver/common/results.pyi b/stubs/pyomo/contrib/solver/common/results.pyi new file mode 100644 index 000000000..be554b8f6 --- /dev/null +++ b/stubs/pyomo/contrib/solver/common/results.pyi @@ -0,0 +1,63 @@ +import enum + +from _typeshed import Incomplete +from pyomo.common.config import ADVANCED_OPTION as ADVANCED_OPTION +from pyomo.common.config import DEVELOPER_OPTION as DEVELOPER_OPTION +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import In as In +from pyomo.common.config import IsInstance as IsInstance +from pyomo.common.config import NonNegativeFloat as NonNegativeFloat +from pyomo.common.config import NonNegativeInt as NonNegativeInt + +class TerminationCondition(enum.Enum): + convergenceCriteriaSatisfied = 0 + maxTimeLimit = 1 + iterationLimit = 2 + objectiveLimit = 3 + minStepLength = 4 + unbounded = 5 + provenInfeasible = 6 + locallyInfeasible = 7 + infeasibleOrUnbounded = 8 + error = 9 + interrupted = 10 + licensingProblems = 11 + emptyModel = 12 + unknown = 42 + +class SolutionStatus(enum.Enum): + noSolution = 0 + infeasible = 10 + feasible = 20 + optimal = 30 + +class Results(ConfigDict): + solution_loader: Incomplete + termination_condition: TerminationCondition + solution_status: SolutionStatus + incumbent_objective: float | None + objective_bound: float | None + solver_name: str | None + solver_version: tuple[int, ...] | None + iteration_count: int | None + timing_info: ConfigDict + extra_info: ConfigDict + solver_config: ConfigDict + solver_log: str + def __init__( + self, + description=None, + doc=None, + implicit: bool = False, + implicit_domain=None, + visibility: int = 0, + ) -> None: ... + def display( + self, content_filter=None, indent_spacing: int = 2, ostream=None, visibility: int = 0 + ): ... + +legacy_termination_condition_map: Incomplete +legacy_solver_status_map: Incomplete + +def legacy_solution_status_map(results): ... diff --git a/stubs/pyomo/contrib/solver/common/solution_loader.pyi b/stubs/pyomo/contrib/solver/common/solution_loader.pyi new file mode 100644 index 000000000..983480434 --- /dev/null +++ b/stubs/pyomo/contrib/solver/common/solution_loader.pyi @@ -0,0 +1,28 @@ +from typing import Mapping, NoReturn, Sequence + +from pyomo.core.base.constraint import ConstraintData as ConstraintData +from pyomo.core.base.var import VarData as VarData +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager + +class SolutionLoaderBase: + def load_vars(self, vars_to_load: Sequence[VarData] | None = None) -> NoReturn: ... + def get_primals( + self, vars_to_load: Sequence[VarData] | None = None + ) -> Mapping[VarData, float]: ... + def get_duals( + self, cons_to_load: Sequence[ConstraintData] | None = None + ) -> dict[ConstraintData, float]: ... + def get_reduced_costs( + self, vars_to_load: Sequence[VarData] | None = None + ) -> Mapping[VarData, float]: ... + +class PersistentSolutionLoader(SolutionLoaderBase): + def __init__(self, solver) -> None: ... + def get_primals(self, vars_to_load=None): ... + def get_duals( + self, cons_to_load: Sequence[ConstraintData] | None = None + ) -> dict[ConstraintData, float]: ... + def get_reduced_costs( + self, vars_to_load: Sequence[VarData] | None = None + ) -> Mapping[VarData, float]: ... + def invalidate(self) -> None: ... diff --git a/stubs/pyomo/contrib/solver/common/util.pyi b/stubs/pyomo/contrib/solver/common/util.pyi new file mode 100644 index 000000000..eb509a81c --- /dev/null +++ b/stubs/pyomo/contrib/solver/common/util.pyi @@ -0,0 +1,35 @@ +from _typeshed import Incomplete +from pyomo.common.errors import PyomoException as PyomoException +from pyomo.core.base.objective import Objective as Objective +from pyomo.core.expr.visitor import ExpressionValueVisitor as ExpressionValueVisitor +from pyomo.core.expr.visitor import nonpyomo_leaf_types as nonpyomo_leaf_types + +class NoFeasibleSolutionError(PyomoException): + def __init__(self) -> None: ... + +class NoOptimalSolutionError(PyomoException): + def __init__(self) -> None: ... + +class NoSolutionError(PyomoException): + def __init__(self) -> None: ... + +class NoDualsError(PyomoException): + def __init__(self) -> None: ... + +class NoReducedCostsError(PyomoException): + def __init__(self) -> None: ... + +class IncompatibleModelError(PyomoException): + def __init__(self) -> None: ... + +def get_objective(block): ... + +class _VarAndNamedExprCollector(ExpressionValueVisitor): + named_expressions: Incomplete + variables: Incomplete + fixed_vars: Incomplete + def __init__(self) -> None: ... + def visit(self, node, values) -> None: ... + def visiting_potential_leaf(self, node): ... + +def collect_vars_and_named_exprs(expr): ... diff --git a/stubs/pyomo/contrib/solver/plugins.pyi b/stubs/pyomo/contrib/solver/plugins.pyi new file mode 100644 index 000000000..8ce770db2 --- /dev/null +++ b/stubs/pyomo/contrib/solver/plugins.pyi @@ -0,0 +1,7 @@ +from .common.factory import SolverFactory as SolverFactory +from .solvers.gurobi_direct import GurobiDirect as GurobiDirect +from .solvers.gurobi_persistent import GurobiPersistent as GurobiPersistent +from .solvers.highs import Highs as Highs +from .solvers.ipopt import Ipopt as Ipopt + +def load() -> None: ... diff --git a/stubs/pyomo/contrib/solver/solvers/__init__.pyi b/stubs/pyomo/contrib/solver/solvers/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/solver/solvers/gurobi_direct.pyi b/stubs/pyomo/contrib/solver/solvers/gurobi_direct.pyi new file mode 100644 index 000000000..6fad352e8 --- /dev/null +++ b/stubs/pyomo/contrib/solver/solvers/gurobi_direct.pyi @@ -0,0 +1,66 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.enums import ObjectiveSense as ObjectiveSense +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.common.errors import MouseTrap as MouseTrap +from pyomo.common.shutdown import python_is_shutting_down as python_is_shutting_down +from pyomo.common.tee import TeeStream as TeeStream +from pyomo.common.tee import capture_output as capture_output +from pyomo.common.timing import HierarchicalTimer as HierarchicalTimer +from pyomo.contrib.solver.common.base import Availability as Availability +from pyomo.contrib.solver.common.base import SolverBase as SolverBase +from pyomo.contrib.solver.common.config import BranchAndBoundConfig as BranchAndBoundConfig +from pyomo.contrib.solver.common.results import Results as Results +from pyomo.contrib.solver.common.results import SolutionStatus as SolutionStatus +from pyomo.contrib.solver.common.results import TerminationCondition as TerminationCondition +from pyomo.contrib.solver.common.solution_loader import SolutionLoaderBase as SolutionLoaderBase +from pyomo.contrib.solver.common.util import IncompatibleModelError as IncompatibleModelError +from pyomo.contrib.solver.common.util import NoDualsError as NoDualsError +from pyomo.contrib.solver.common.util import NoFeasibleSolutionError as NoFeasibleSolutionError +from pyomo.contrib.solver.common.util import NoOptimalSolutionError as NoOptimalSolutionError +from pyomo.contrib.solver.common.util import NoReducedCostsError as NoReducedCostsError +from pyomo.contrib.solver.common.util import NoSolutionError as NoSolutionError +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager +from pyomo.repn.plugins.standard_form import ( + LinearStandardFormCompiler as LinearStandardFormCompiler, +) + +gurobipy: Incomplete +gurobipy_available: Incomplete + +class GurobiConfigMixin: + use_mipstart: bool + def __init__(self) -> None: ... + +class GurobiConfig(BranchAndBoundConfig, GurobiConfigMixin): + def __init__( + self, + description=None, + doc=None, + implicit: bool = False, + implicit_domain=None, + visibility: int = 0, + ) -> None: ... + +class GurobiDirectSolutionLoader(SolutionLoaderBase): + def __init__(self, grb_model, grb_cons, grb_vars, pyo_cons, pyo_vars, pyo_obj) -> None: ... + def __del__(self) -> None: ... + def load_vars(self, vars_to_load=None, solution_number: int = 0): ... + def get_primals(self, vars_to_load=None, solution_number: int = 0): ... + def get_duals(self, cons_to_load=None): ... + def get_reduced_costs(self, vars_to_load=None): ... + +class GurobiSolverMixin: + def available(self): ... + def version(self): ... + +class GurobiDirect(GurobiSolverMixin, SolverBase): + CONFIG: Incomplete + def __init__(self, **kwds) -> None: ... + @staticmethod + def release_license() -> None: ... + def __del__(self) -> None: ... + def solve(self, model, **kwds) -> Results: ... diff --git a/stubs/pyomo/contrib/solver/solvers/gurobi_persistent.pyi b/stubs/pyomo/contrib/solver/solvers/gurobi_persistent.pyi new file mode 100644 index 000000000..0e8cb2d78 --- /dev/null +++ b/stubs/pyomo/contrib/solver/solvers/gurobi_persistent.pyi @@ -0,0 +1,163 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.collections import OrderedSet as OrderedSet +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.common.shutdown import python_is_shutting_down as python_is_shutting_down +from pyomo.common.tee import TeeStream as TeeStream +from pyomo.common.tee import capture_output as capture_output +from pyomo.common.timing import HierarchicalTimer as HierarchicalTimer +from pyomo.contrib.solver.common.base import Availability as Availability +from pyomo.contrib.solver.common.base import PersistentSolverBase as PersistentSolverBase +from pyomo.contrib.solver.common.config import ( + PersistentBranchAndBoundConfig as PersistentBranchAndBoundConfig, +) +from pyomo.contrib.solver.common.persistent import PersistentSolverMixin as PersistentSolverMixin +from pyomo.contrib.solver.common.persistent import PersistentSolverUtils as PersistentSolverUtils +from pyomo.contrib.solver.common.results import Results as Results +from pyomo.contrib.solver.common.results import SolutionStatus as SolutionStatus +from pyomo.contrib.solver.common.results import TerminationCondition as TerminationCondition +from pyomo.contrib.solver.common.solution_loader import ( + PersistentSolutionLoader as PersistentSolutionLoader, +) +from pyomo.contrib.solver.common.util import IncompatibleModelError as IncompatibleModelError +from pyomo.contrib.solver.common.util import NoDualsError as NoDualsError +from pyomo.contrib.solver.common.util import NoFeasibleSolutionError as NoFeasibleSolutionError +from pyomo.contrib.solver.common.util import NoOptimalSolutionError as NoOptimalSolutionError +from pyomo.contrib.solver.common.util import NoReducedCostsError as NoReducedCostsError +from pyomo.contrib.solver.common.util import NoSolutionError as NoSolutionError +from pyomo.contrib.solver.solvers.gurobi_direct import GurobiConfigMixin as GurobiConfigMixin +from pyomo.contrib.solver.solvers.gurobi_direct import GurobiSolverMixin as GurobiSolverMixin +from pyomo.core.base import NumericLabeler as NumericLabeler +from pyomo.core.base import SymbolMap as SymbolMap +from pyomo.core.base import TextLabeler as TextLabeler +from pyomo.core.base.constraint import ConstraintData as ConstraintData +from pyomo.core.base.param import ParamData as ParamData +from pyomo.core.base.sos import SOSConstraintData as SOSConstraintData +from pyomo.core.base.var import VarData as VarData +from pyomo.core.expr.numeric_expr import NPV_MaxExpression as NPV_MaxExpression +from pyomo.core.expr.numeric_expr import NPV_MinExpression as NPV_MinExpression +from pyomo.core.expr.numvalue import is_constant as is_constant +from pyomo.core.expr.numvalue import is_fixed as is_fixed +from pyomo.core.expr.numvalue import native_numeric_types as native_numeric_types +from pyomo.core.expr.numvalue import value as value +from pyomo.core.kernel.objective import maximize as maximize +from pyomo.core.kernel.objective import minimize as minimize +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager +from pyomo.repn import generate_standard_repn as generate_standard_repn + +logger: Incomplete +gurobipy: Incomplete +gurobipy_available: Incomplete + +class GurobiConfig(PersistentBranchAndBoundConfig, GurobiConfigMixin): + def __init__( + self, + description=None, + doc=None, + implicit: bool = False, + implicit_domain=None, + visibility: int = 0, + ) -> None: ... + +class GurobiSolutionLoader(PersistentSolutionLoader): + def load_vars(self, vars_to_load=None, solution_number: int = 0) -> None: ... + def get_primals(self, vars_to_load=None, solution_number: int = 0): ... + +class _MutableLowerBound: + var: Incomplete + expr: Incomplete + def __init__(self, expr) -> None: ... + def update(self) -> None: ... + +class _MutableUpperBound: + var: Incomplete + expr: Incomplete + def __init__(self, expr) -> None: ... + def update(self) -> None: ... + +class _MutableLinearCoefficient: + expr: Incomplete + var: Incomplete + con: Incomplete + gurobi_model: Incomplete + def __init__(self) -> None: ... + def update(self) -> None: ... + +class _MutableRangeConstant: + lhs_expr: Incomplete + rhs_expr: Incomplete + con: Incomplete + slack_name: Incomplete + gurobi_model: Incomplete + def __init__(self) -> None: ... + def update(self) -> None: ... + +class _MutableConstant: + expr: Incomplete + con: Incomplete + def __init__(self) -> None: ... + def update(self) -> None: ... + +class _MutableQuadraticConstraint: + con: Incomplete + gurobi_model: Incomplete + constant: Incomplete + last_constant_value: Incomplete + linear_coefs: Incomplete + last_linear_coef_values: Incomplete + quadratic_coefs: Incomplete + last_quadratic_coef_values: Incomplete + def __init__( + self, gurobi_model, gurobi_con, constant, linear_coefs, quadratic_coefs + ) -> None: ... + def get_updated_expression(self): ... + def get_updated_rhs(self): ... + +class _MutableObjective: + gurobi_model: Incomplete + constant: Incomplete + linear_coefs: Incomplete + quadratic_coefs: Incomplete + last_quadratic_coef_values: Incomplete + def __init__(self, gurobi_model, constant, linear_coefs, quadratic_coefs) -> None: ... + def get_updated_expression(self): ... + +class _MutableQuadraticCoefficient: + expr: Incomplete + var1: Incomplete + var2: Incomplete + def __init__(self) -> None: ... + +class GurobiPersistent( + GurobiSolverMixin, PersistentSolverMixin, PersistentSolverUtils, PersistentSolverBase +): + CONFIG: Incomplete + def __init__(self, **kwds) -> None: ... + def release_license(self) -> None: ... + def __del__(self) -> None: ... + @property + def symbol_map(self): ... + def set_instance(self, model) -> None: ... + def update_parameters(self) -> None: ... + def update(self, timer: HierarchicalTimer = None): ... + def get_model_attr(self, attr): ... + def write(self, filename) -> None: ... + def set_linear_constraint_attr(self, con, attr, val) -> None: ... + def set_var_attr(self, var, attr, val) -> None: ... + def get_var_attr(self, var, attr): ... + def get_linear_constraint_attr(self, con, attr): ... + def get_sos_attr(self, con, attr): ... + def get_quadratic_constraint_attr(self, con, attr): ... + def set_gurobi_param(self, param, val) -> None: ... + def get_gurobi_param_info(self, param): ... + def set_callback(self, func=None) -> None: ... + def cbCut(self, con) -> None: ... + def cbGet(self, what): ... + def cbGetNodeRel(self, variables) -> None: ... + def cbGetSolution(self, variables) -> None: ... + def cbLazy(self, con) -> None: ... + def cbSetSolution(self, variables, solution) -> None: ... + def cbUseSolution(self): ... + def reset(self) -> None: ... diff --git a/stubs/pyomo/contrib/solver/solvers/highs.pyi b/stubs/pyomo/contrib/solver/solvers/highs.pyi new file mode 100644 index 000000000..1c9c9dcbc --- /dev/null +++ b/stubs/pyomo/contrib/solver/solvers/highs.pyi @@ -0,0 +1,91 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.common.tee import TeeStream as TeeStream +from pyomo.common.tee import capture_output as capture_output +from pyomo.contrib.solver.common.base import Availability as Availability +from pyomo.contrib.solver.common.base import PersistentSolverBase as PersistentSolverBase +from pyomo.contrib.solver.common.config import ( + PersistentBranchAndBoundConfig as PersistentBranchAndBoundConfig, +) +from pyomo.contrib.solver.common.persistent import PersistentSolverMixin as PersistentSolverMixin +from pyomo.contrib.solver.common.persistent import PersistentSolverUtils as PersistentSolverUtils +from pyomo.contrib.solver.common.results import Results as Results +from pyomo.contrib.solver.common.results import SolutionStatus as SolutionStatus +from pyomo.contrib.solver.common.results import TerminationCondition as TerminationCondition +from pyomo.contrib.solver.common.solution_loader import ( + PersistentSolutionLoader as PersistentSolutionLoader, +) +from pyomo.contrib.solver.common.util import IncompatibleModelError as IncompatibleModelError +from pyomo.contrib.solver.common.util import NoDualsError as NoDualsError +from pyomo.contrib.solver.common.util import NoFeasibleSolutionError as NoFeasibleSolutionError +from pyomo.contrib.solver.common.util import NoOptimalSolutionError as NoOptimalSolutionError +from pyomo.contrib.solver.common.util import NoReducedCostsError as NoReducedCostsError +from pyomo.contrib.solver.common.util import NoSolutionError as NoSolutionError +from pyomo.core.base.constraint import ConstraintData as ConstraintData +from pyomo.core.base.param import ParamData as ParamData +from pyomo.core.base.sos import SOSConstraintData as SOSConstraintData +from pyomo.core.base.var import VarData as VarData +from pyomo.core.expr.numeric_expr import NPV_MaxExpression as NPV_MaxExpression +from pyomo.core.expr.numeric_expr import NPV_MinExpression as NPV_MinExpression +from pyomo.core.expr.numvalue import is_constant as is_constant +from pyomo.core.expr.numvalue import value as value +from pyomo.core.kernel.objective import maximize as maximize +from pyomo.core.kernel.objective import minimize as minimize +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager +from pyomo.repn import generate_standard_repn as generate_standard_repn + +logger: Incomplete +highspy: Incomplete +highspy_available: Incomplete + +class _MutableVarBounds: + pyomo_var_id: Incomplete + lower_expr: Incomplete + upper_expr: Incomplete + var_map: Incomplete + highs: Incomplete + def __init__(self, lower_expr, upper_expr, pyomo_var_id, var_map, highs) -> None: ... + def update(self) -> None: ... + +class _MutableLinearCoefficient: + expr: Incomplete + highs: Incomplete + pyomo_var_id: Incomplete + pyomo_con: Incomplete + con_map: Incomplete + var_map: Incomplete + def __init__(self, pyomo_con, pyomo_var_id, con_map, var_map, expr, highs) -> None: ... + def update(self) -> None: ... + +class _MutableObjectiveCoefficient: + expr: Incomplete + highs: Incomplete + pyomo_var_id: Incomplete + var_map: Incomplete + def __init__(self, pyomo_var_id, var_map, expr, highs) -> None: ... + def update(self) -> None: ... + +class _MutableObjectiveOffset: + expr: Incomplete + highs: Incomplete + def __init__(self, expr, highs) -> None: ... + def update(self) -> None: ... + +class _MutableConstraintBounds: + lower_expr: Incomplete + upper_expr: Incomplete + con: Incomplete + con_map: Incomplete + highs: Incomplete + def __init__(self, lower_expr, upper_expr, pyomo_con, con_map, highs) -> None: ... + def update(self) -> None: ... + +class Highs(PersistentSolverMixin, PersistentSolverUtils, PersistentSolverBase): + CONFIG: Incomplete + def __init__(self, **kwds) -> None: ... + def available(self): ... + def version(self): ... + def set_instance(self, model) -> None: ... + def update_parameters(self) -> None: ... diff --git a/stubs/pyomo/contrib/solver/solvers/ipopt.pyi b/stubs/pyomo/contrib/solver/solvers/ipopt.pyi new file mode 100644 index 000000000..838c9c456 --- /dev/null +++ b/stubs/pyomo/contrib/solver/solvers/ipopt.pyi @@ -0,0 +1,62 @@ +from typing import Mapping, Sequence + +from _typeshed import Incomplete +from pyomo.common import Executable as Executable +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.common.errors import DeveloperError as DeveloperError +from pyomo.common.errors import InfeasibleConstraintException as InfeasibleConstraintException +from pyomo.common.tee import TeeStream as TeeStream +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.common.timing import HierarchicalTimer as HierarchicalTimer +from pyomo.contrib.solver.common.base import Availability as Availability +from pyomo.contrib.solver.common.base import SolverBase as SolverBase +from pyomo.contrib.solver.common.config import SolverConfig as SolverConfig +from pyomo.contrib.solver.common.results import Results as Results +from pyomo.contrib.solver.common.results import SolutionStatus as SolutionStatus +from pyomo.contrib.solver.common.results import TerminationCondition as TerminationCondition +from pyomo.contrib.solver.common.util import NoFeasibleSolutionError as NoFeasibleSolutionError +from pyomo.contrib.solver.common.util import NoOptimalSolutionError as NoOptimalSolutionError +from pyomo.contrib.solver.common.util import NoSolutionError as NoSolutionError +from pyomo.contrib.solver.solvers.sol_reader import SolSolutionLoader as SolSolutionLoader +from pyomo.contrib.solver.solvers.sol_reader import parse_sol_file as parse_sol_file +from pyomo.core.base.suffix import Suffix as Suffix +from pyomo.core.base.var import VarData as VarData +from pyomo.core.expr.numvalue import value as value +from pyomo.core.expr.visitor import replace_expressions as replace_expressions +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager +from pyomo.repn.plugins.nl_writer import NLWriter as NLWriter +from pyomo.repn.plugins.nl_writer import NLWriterInfo as NLWriterInfo +from pyomo.solvers.amplfunc_merge import amplfunc_merge as amplfunc_merge + +logger: Incomplete + +class IpoptConfig(SolverConfig): + executable: Executable + writer_config: ConfigDict + def __init__( + self, + description=None, + doc=None, + implicit: bool = False, + implicit_domain=None, + visibility: int = 0, + ) -> None: ... + +class IpoptSolutionLoader(SolSolutionLoader): + def get_reduced_costs( + self, vars_to_load: Sequence[VarData] | None = None + ) -> Mapping[VarData, float]: ... + +ipopt_command_line_options: Incomplete + +class Ipopt(SolverBase): + CONFIG: Incomplete + def __init__(self, **kwds) -> None: ... + def available(self, config=None): ... + def version(self, config=None): ... + def has_linear_solver(self, linear_solver): ... + def solve(self, model, **kwds): ... diff --git a/stubs/pyomo/contrib/solver/solvers/sol_reader.pyi b/stubs/pyomo/contrib/solver/solvers/sol_reader.pyi new file mode 100644 index 000000000..d86b5edbd --- /dev/null +++ b/stubs/pyomo/contrib/solver/solvers/sol_reader.pyi @@ -0,0 +1,40 @@ +import io +from typing import Any, Mapping, NoReturn, Sequence + +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.errors import DeveloperError as DeveloperError +from pyomo.common.errors import PyomoException as PyomoException +from pyomo.contrib.solver.common.results import Results as Results +from pyomo.contrib.solver.common.results import SolutionStatus as SolutionStatus +from pyomo.contrib.solver.common.results import TerminationCondition as TerminationCondition +from pyomo.contrib.solver.common.solution_loader import SolutionLoaderBase as SolutionLoaderBase +from pyomo.core.base.constraint import ConstraintData as ConstraintData +from pyomo.core.base.var import VarData as VarData +from pyomo.core.expr import value as value +from pyomo.core.expr.visitor import replace_expressions as replace_expressions +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager +from pyomo.repn.plugins.nl_writer import NLWriterInfo as NLWriterInfo + +class SolFileData: + primals: list[float] + duals: list[float] + var_suffixes: dict[str, dict[int, Any]] + con_suffixes: dict[str, dict[Any]] + obj_suffixes: dict[str, dict[int, Any]] + problem_suffixes: dict[str, list[Any]] + other: None + def __init__(self) -> None: ... + +class SolSolutionLoader(SolutionLoaderBase): + def __init__(self, sol_data: SolFileData, nl_info: NLWriterInfo) -> None: ... + def load_vars(self, vars_to_load: Sequence[VarData] | None = None) -> NoReturn: ... + def get_primals( + self, vars_to_load: Sequence[VarData] | None = None + ) -> Mapping[VarData, float]: ... + def get_duals( + self, cons_to_load: Sequence[ConstraintData] | None = None + ) -> dict[ConstraintData, float]: ... + +def parse_sol_file( + sol_file: io.TextIOBase, nl_info: NLWriterInfo, result: Results +) -> tuple[Results, SolFileData]: ... diff --git a/stubs/pyomo/contrib/trustregion/TRF.pyi b/stubs/pyomo/contrib/trustregion/TRF.pyi new file mode 100644 index 000000000..812a56f60 --- /dev/null +++ b/stubs/pyomo/contrib/trustregion/TRF.pyi @@ -0,0 +1,39 @@ +import types + +from _typeshed import Incomplete +from pyomo.common.config import Bool as Bool +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import In as In +from pyomo.common.config import PositiveFloat as PositiveFloat +from pyomo.common.config import PositiveInt as PositiveInt +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.contrib.trustregion.filter import Filter as Filter +from pyomo.contrib.trustregion.filter import FilterElement as FilterElement +from pyomo.contrib.trustregion.interface import TRFInterface as TRFInterface +from pyomo.contrib.trustregion.util import IterationLogger as IterationLogger +from pyomo.core.base.range import NumericRange as NumericRange +from pyomo.opt import SolverFactory as SolverFactory + +logger: Incomplete +__version__: Incomplete + +def trust_region_method(model, decision_variables, ext_fcn_surrogate_map_rule, config): ... + +class TrustRegionSolver: + CONFIG: Incomplete + config: Incomplete + def __init__(self, **kwds) -> None: ... + def available(self, exception_flag: bool = True): ... + def version(self): ... + def license_is_valid(self): ... + def __enter__(self): ... + def __exit__( + self, + et: type[BaseException] | None, + ev: BaseException | None, + tb: types.TracebackType | None, + ) -> None: ... + def solve( + self, model, degrees_of_freedom_variables, ext_fcn_surrogate_map_rule=None, **kwds + ): ... diff --git a/stubs/pyomo/contrib/trustregion/__init__.pyi b/stubs/pyomo/contrib/trustregion/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/trustregion/examples/__init__.pyi b/stubs/pyomo/contrib/trustregion/examples/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/trustregion/examples/example1.pyi b/stubs/pyomo/contrib/trustregion/examples/example1.pyi new file mode 100644 index 000000000..6705516eb --- /dev/null +++ b/stubs/pyomo/contrib/trustregion/examples/example1.pyi @@ -0,0 +1,15 @@ +from pyomo.environ import ConcreteModel as ConcreteModel +from pyomo.environ import Constraint as Constraint +from pyomo.environ import ExternalFunction as ExternalFunction +from pyomo.environ import Objective as Objective +from pyomo.environ import Reals as Reals +from pyomo.environ import Var as Var +from pyomo.environ import cos as cos +from pyomo.environ import sin as sin +from pyomo.environ import sqrt as sqrt +from pyomo.opt import SolverFactory as SolverFactory + +def ext_fcn(a, b): ... +def grad_ext_fcn(args, fixed): ... +def create_model(): ... +def main() -> None: ... diff --git a/stubs/pyomo/contrib/trustregion/examples/example2.pyi b/stubs/pyomo/contrib/trustregion/examples/example2.pyi new file mode 100644 index 000000000..9c229c397 --- /dev/null +++ b/stubs/pyomo/contrib/trustregion/examples/example2.pyi @@ -0,0 +1,11 @@ +from pyomo.environ import ConcreteModel as ConcreteModel +from pyomo.environ import ExternalFunction as ExternalFunction +from pyomo.environ import Objective as Objective +from pyomo.environ import Var as Var +from pyomo.opt import SolverFactory as SolverFactory + +def ext_fcn(a, b): ... +def grad_ext_fcn(args, fixed): ... +def create_model(): ... +def basis_rule(component, ef_expr): ... +def main() -> None: ... diff --git a/stubs/pyomo/contrib/trustregion/filter.pyi b/stubs/pyomo/contrib/trustregion/filter.pyi new file mode 100644 index 000000000..ba36ff06d --- /dev/null +++ b/stubs/pyomo/contrib/trustregion/filter.pyi @@ -0,0 +1,13 @@ +from _typeshed import Incomplete + +class FilterElement: + objective: Incomplete + feasible: Incomplete + def __init__(self, objective, feasible) -> None: ... + def compare(self, filterElement): ... + +class Filter: + TrustRegionFilter: Incomplete + def __init__(self) -> None: ... + def addToFilter(self, filterElement) -> None: ... + def isAcceptable(self, filterElement, maximum_feasibility): ... diff --git a/stubs/pyomo/contrib/trustregion/interface.pyi b/stubs/pyomo/contrib/trustregion/interface.pyi new file mode 100644 index 000000000..d281fcff7 --- /dev/null +++ b/stubs/pyomo/contrib/trustregion/interface.pyi @@ -0,0 +1,57 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.contrib.trustregion.util import maxIgnoreNone as maxIgnoreNone +from pyomo.contrib.trustregion.util import minIgnoreNone as minIgnoreNone +from pyomo.core import Block as Block +from pyomo.core import Constraint as Constraint +from pyomo.core import ExternalFunction as ExternalFunction +from pyomo.core import Objective as Objective +from pyomo.core import Param as Param +from pyomo.core import Set as Set +from pyomo.core import VarList as VarList +from pyomo.core import maximize as maximize +from pyomo.core import minimize as minimize +from pyomo.core import value as value +from pyomo.core.expr.calculus.derivatives import differentiate as differentiate +from pyomo.core.expr.numeric_expr import ExternalFunctionExpression as ExternalFunctionExpression +from pyomo.core.expr.numvalue import native_types as native_types +from pyomo.core.expr.visitor import ExpressionReplacementVisitor as ExpressionReplacementVisitor +from pyomo.core.expr.visitor import identify_variables as identify_variables +from pyomo.opt import SolverFactory as SolverFactory +from pyomo.opt import check_optimal_termination as check_optimal_termination + +logger: Incomplete + +class EFReplacement(ExpressionReplacementVisitor): + trfData: Incomplete + efSet: Incomplete + def __init__(self, trfData, efSet) -> None: ... + def beforeChild(self, node, child, child_idx): ... + def exitNode(self, node, data): ... + +class TRFInterface: + original_model: Incomplete + config: Incomplete + model: Incomplete + decision_variables: Incomplete + data: Incomplete + basis_expression_rule: Incomplete + efSet: Incomplete + solver: Incomplete + def __init__(self, model, decision_variables, ext_fcn_surrogate_map_rule, config) -> None: ... + def replaceEF(self, expr): ... + degrees_of_freedom: Incomplete + def replaceExternalFunctionsWithVariables(self) -> None: ... + def createConstraints(self): ... + def getCurrentDecisionVariableValues(self): ... + def updateDecisionVariableBounds(self, radius) -> None: ... + def updateSurrogateModel(self) -> None: ... + def getCurrentModelState(self): ... + def calculateFeasibility(self): ... + def calculateStepSizeInfNorm(self, original_values, new_values): ... + initial_decision_bounds: Incomplete + def initializeProblem(self): ... + def solveModel(self): ... + def rejectStep(self) -> None: ... diff --git a/stubs/pyomo/contrib/trustregion/plugins.pyi b/stubs/pyomo/contrib/trustregion/plugins.pyi new file mode 100644 index 000000000..3fa961402 --- /dev/null +++ b/stubs/pyomo/contrib/trustregion/plugins.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete + +logger: Incomplete + +def load() -> None: ... diff --git a/stubs/pyomo/contrib/trustregion/util.pyi b/stubs/pyomo/contrib/trustregion/util.pyi new file mode 100644 index 000000000..e2b2d04f1 --- /dev/null +++ b/stubs/pyomo/contrib/trustregion/util.pyi @@ -0,0 +1,31 @@ +from _typeshed import Incomplete + +logger: Incomplete + +def minIgnoreNone(a, b): ... +def maxIgnoreNone(a, b): ... + +class IterationRecord: + iteration: Incomplete + feasibility: Incomplete + objectiveValue: Incomplete + trustRadius: Incomplete + stepNorm: Incomplete + def __init__( + self, iteration, feasibility=None, objectiveValue=None, trustRadius=None, stepNorm=None + ) -> None: ... + def detailLogger(self) -> None: ... + def verboseLogger(self) -> None: ... + +class IterationLogger: + iterations: Incomplete + def __init__(self) -> None: ... + iterrecord: Incomplete + def newIteration( + self, iteration, feasibility, objectiveValue, trustRadius, stepNorm + ) -> None: ... + def updateIteration( + self, feasibility=None, objectiveValue=None, trustRadius=None, stepNorm=None + ) -> None: ... + def logIteration(self) -> None: ... + def printIteration(self) -> None: ... diff --git a/stubs/pyomo/contrib/viewer/__init__.pyi b/stubs/pyomo/contrib/viewer/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/contrib/viewer/model_browser.pyi b/stubs/pyomo/contrib/viewer/model_browser.pyi new file mode 100644 index 000000000..af069f4e6 --- /dev/null +++ b/stubs/pyomo/contrib/viewer/model_browser.pyi @@ -0,0 +1,64 @@ +import pyomo.contrib.viewer.qt as myqt +from _typeshed import Incomplete +from pyomo.common.fileutils import this_file_dir as this_file_dir +from pyomo.common.flags import building_documentation as building_documentation +from pyomo.contrib.viewer.report import get_residual as get_residual +from pyomo.contrib.viewer.report import value_no_exception as value_no_exception +from pyomo.core.base.param import ParamData as ParamData +from pyomo.environ import Block as Block +from pyomo.environ import BooleanVar as BooleanVar +from pyomo.environ import Constraint as Constraint +from pyomo.environ import Expression as Expression +from pyomo.environ import Param as Param +from pyomo.environ import Var as Var +from pyomo.environ import units as units +from pyomo.environ import value as value + +class _ModelBrowserUI: ... +class _ModelBrowser: ... + +mypath: Incomplete + +class LineEditCreator(myqt.QItemEditorCreatorBase): + def createWidget(self, parent): ... + +class NumberDelegate(myqt.QItemDelegate): + def __init__(self, parent) -> None: ... + def setModelData(self, editor, model, index) -> None: ... + +class ModelBrowser(_ModelBrowser, _ModelBrowserUI): + ui_data: Incomplete + datmodel: Incomplete + def __init__(self, ui_data, standard: str = 'Var') -> None: ... + def refresh(self) -> None: ... + def update_model(self) -> None: ... + +class ComponentDataItem: + ui_data: Incomplete + data: Incomplete + parent: Incomplete + children: Incomplete + ids: Incomplete + get_callback: Incomplete + set_callback: Incomplete + def __init__(self, parent, o, ui_data) -> None: ... + def add_child(self, o): ... + def get(self, a): ... + def set(self, a, val): ... + +class ComponentDataModel(myqt.QAbstractItemModel): + column: Incomplete + ui_data: Incomplete + components: Incomplete + def __init__( + self, parent, ui_data, columns=['name', 'value'], components=..., editable=[] + ) -> None: ... + rootItems: Incomplete + def update_model(self) -> None: ... + def parent(self, index): ... + def index(self, row, column, parent=...): ... + def columnCount(self, parent=...): ... + def rowCount(self, parent=...): ... + def data(self, index=..., role=...): ... + def headerData(self, i, orientation, role=...): ... + def flags(self, index=...): ... diff --git a/stubs/pyomo/contrib/viewer/model_select.pyi b/stubs/pyomo/contrib/viewer/model_select.pyi new file mode 100644 index 000000000..23c5c66c3 --- /dev/null +++ b/stubs/pyomo/contrib/viewer/model_select.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from pyomo.common.fileutils import this_file_dir as this_file_dir +from pyomo.common.flags import building_documentation as building_documentation + +class _ModelSelectUI: ... +class _ModelSelect: ... + +mypath: Incomplete + +class ModelSelect(_ModelSelect, _ModelSelectUI): + ui_data: Incomplete + def __init__(self, parent, ui_data) -> None: ... + def select_model(self) -> None: ... + models: Incomplete + def update_models(self) -> None: ... diff --git a/stubs/pyomo/contrib/viewer/pyomo_viewer.pyi b/stubs/pyomo/contrib/viewer/pyomo_viewer.pyi new file mode 100644 index 000000000..7f2897e1d --- /dev/null +++ b/stubs/pyomo/contrib/viewer/pyomo_viewer.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies import UnavailableClass as UnavailableClass +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.scripting.pyomo_parser import add_subparser as add_subparser + +qtconsole_app: Incomplete +qtconsole_available: Incomplete + +class QtApp: + def active_widget_name(self): ... + def show_ui(self) -> None: ... + def hide_ui(self) -> None: ... + def run_script(self, checked: bool = False, filename=None) -> None: ... + def kernel_pyomo_init(self, kc) -> None: ... + run_script_act: Incomplete + show_ui_act: Incomplete + hide_ui_act: Incomplete + def init_qt_elements(self) -> None: ... + def new_frontend_master(self): ... + +def main(*args) -> None: ... diff --git a/stubs/pyomo/contrib/viewer/qt.pyi b/stubs/pyomo/contrib/viewer/qt.pyi new file mode 100644 index 000000000..d2ea133da --- /dev/null +++ b/stubs/pyomo/contrib/viewer/qt.pyi @@ -0,0 +1,53 @@ +import enum + +from _typeshed import Incomplete +from pyomo.common.flags import building_documentation as building_documentation +from PyQt5 import uic as uic +from PyQt5.QtWidgets import QAction as QAction + +supported: Incomplete +import_errors: Incomplete +available: bool +qt_package: Incomplete +QtWidgets: Incomplete +QtCore: Incomplete +QtGui: Incomplete +available = module_str + +class Qt: + class ItemDataRole(enum.Enum): + EditRole = 1 + DisplayRole = 2 + ToolTipRole = 3 + ForegroundRole = 4 + +class QtCore: + class QModelIndex: ... + Qt = Qt + +class QAbstractItemModel: + def __init__(*args, **kwargs) -> None: ... + +class QAbstractTableModel: + def __init__(*args, **kwargs) -> None: ... + +class QItemEditorCreatorBase: ... +class QItemDelegate: ... + +QAbstractItemView: Incomplete +QFileDialog: Incomplete +QMainWindow: Incomplete +QMdiArea: Incomplete +QApplication: Incomplete +QTableWidgetItem: Incomplete +QStatusBar: Incomplete +QLineEdit: Incomplete +QItemEditorFactory: Incomplete +QStyledItemDelegate: Incomplete +QComboBox: Incomplete +QMessageBox: Incomplete +QColor: Incomplete +QMetaType: Incomplete + +class QAbstractItemModel: ... +class QAbstractTableModel: ... diff --git a/stubs/pyomo/contrib/viewer/report.pyi b/stubs/pyomo/contrib/viewer/report.pyi new file mode 100644 index 000000000..53531ecdc --- /dev/null +++ b/stubs/pyomo/contrib/viewer/report.pyi @@ -0,0 +1,18 @@ +from collections.abc import Generator + +from _typeshed import Incomplete +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.core.expr import identify_variables as identify_variables +from pyomo.environ import Constraint as Constraint +from pyomo.environ import value as value + +def value_no_exception(c, div0=None): ... +def get_residual(ui_data, c): ... +def active_equalities(blk) -> Generator[Incomplete]: ... +def active_constraint_set(blk): ... +def active_equality_set(blk): ... +def count_free_variables(blk): ... +def count_equality_constraints(blk): ... +def count_constraints(blk): ... +def degrees_of_freedom(blk): ... +def free_variables_in_active_equalities_set(blk): ... diff --git a/stubs/pyomo/contrib/viewer/residual_table.pyi b/stubs/pyomo/contrib/viewer/residual_table.pyi new file mode 100644 index 000000000..e876e9823 --- /dev/null +++ b/stubs/pyomo/contrib/viewer/residual_table.pyi @@ -0,0 +1,31 @@ +import pyomo.contrib.viewer.qt as myqt +from _typeshed import Incomplete +from pyomo.common.fileutils import this_file_dir as this_file_dir +from pyomo.common.flags import building_documentation as building_documentation +from pyomo.contrib.viewer.report import get_residual as get_residual +from pyomo.contrib.viewer.report import value_no_exception as value_no_exception + +class _ResidualTableUI: ... +class _ResidualTable: ... + +mypath: Incomplete + +class ResidualTable(_ResidualTable, _ResidualTableUI): + ui_data: Incomplete + datmodel: Incomplete + def __init__(self, ui_data) -> None: ... + def sort(self) -> None: ... + def refresh(self) -> None: ... + def calculate(self) -> None: ... + +class ResidualDataModel(myqt.QAbstractTableModel): + column: Incomplete + ui_data: Incomplete + include_inactive: bool + def __init__(self, parent, ui_data) -> None: ... + def update_model(self) -> None: ... + def sort(self): ... + def rowCount(self, parent=...): ... + def columnCount(self, parent=...): ... + def data(self, index=..., role=...): ... + def headerData(self, i, orientation, role=...): ... diff --git a/stubs/pyomo/contrib/viewer/ui.pyi b/stubs/pyomo/contrib/viewer/ui.pyi new file mode 100644 index 000000000..88a97f4c3 --- /dev/null +++ b/stubs/pyomo/contrib/viewer/ui.pyi @@ -0,0 +1,41 @@ +from _typeshed import Incomplete +from pyomo.common.fileutils import this_file_dir as this_file_dir +from pyomo.common.flags import building_documentation as building_documentation +from pyomo.contrib.viewer.model_browser import ModelBrowser as ModelBrowser +from pyomo.contrib.viewer.model_select import ModelSelect as ModelSelect +from pyomo.contrib.viewer.residual_table import ResidualTable as ResidualTable +from pyomo.contrib.viewer.ui_data import UIData as UIData + +class _MainWindowUI: ... +class _MainWindow: ... + +def get_mainwindow( + model=None, + show: bool = True, + ask_close: bool = True, + model_var_name_in_main=None, + testing: bool = False, +): ... + +class MainWindow(_MainWindow, _MainWindowUI): + testing: Incomplete + ui_data: Incomplete + variables: Incomplete + constraints: Incomplete + expressions: Incomplete + parameters: Incomplete + residuals: Incomplete + def __init__(self, *args, **kwargs) -> None: ... + def toggle_tabs(self) -> None: ... + def variables_restart(self) -> None: ... + def expressions_restart(self) -> None: ... + def parameters_restart(self) -> None: ... + def constraints_restart(self) -> None: ... + def residuals_restart(self) -> None: ... + def set_model(self, model) -> None: ... + def update_model(self) -> None: ... + def model_information(self) -> None: ... + def refresh_on_execute(self) -> None: ... + def show_model_select(self): ... + def exit_action(self) -> None: ... + def closeEvent(self, event) -> None: ... diff --git a/stubs/pyomo/contrib/viewer/ui_data.pyi b/stubs/pyomo/contrib/viewer/ui_data.pyi new file mode 100644 index 000000000..fe2289a04 --- /dev/null +++ b/stubs/pyomo/contrib/viewer/ui_data.pyi @@ -0,0 +1,29 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.contrib.viewer.qt import * + +class UIDataNoUi: + model_var_name_in_main: Incomplete + value_cache: Incomplete + value_cache_units: Incomplete + def __init__(self, model=None, model_var_name_in_main=None) -> None: ... + def begin_update(self) -> None: ... + def end_update(self, emit: bool = True) -> None: ... + def emit_update(self) -> None: ... + def emit_exec_refresh(self) -> None: ... + @property + def model(self): ... + @model.setter + def model(self, value) -> None: ... + def calculate_constraints(self) -> None: ... + def calculate_expressions(self) -> None: ... + +class UIData(UIDataNoUi): ... + +class UIData(UIDataNoUi, QtCore.QObject): + updated: Incomplete + exec_refresh: Incomplete + def __init__(self, *args, **kwargs) -> None: ... + def end_update(self, emit: bool = True) -> None: ... + def emit_update(self) -> None: ... + def emit_exec_refresh(self) -> None: ... diff --git a/stubs/pyomo/core/__init__.pyi b/stubs/pyomo/core/__init__.pyi new file mode 100644 index 000000000..ec599f8d9 --- /dev/null +++ b/stubs/pyomo/core/__init__.pyi @@ -0,0 +1,162 @@ +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.deprecation import relocated_module_attribute as relocated_module_attribute +from pyomo.core import expr as expr +from pyomo.core import kernel as kernel +from pyomo.core import util as util +from pyomo.core.base import maximize as maximize +from pyomo.core.base import minimize as minimize +from pyomo.core.base.action import BuildAction as BuildAction +from pyomo.core.base.block import Block as Block +from pyomo.core.base.block import ScalarBlock as ScalarBlock +from pyomo.core.base.block import SortComponents as SortComponents +from pyomo.core.base.block import TraversalStrategy as TraversalStrategy +from pyomo.core.base.block import active_components as active_components +from pyomo.core.base.block import active_components_data as active_components_data +from pyomo.core.base.block import components as components +from pyomo.core.base.block import components_data as components_data +from pyomo.core.base.boolean_var import BooleanVar as BooleanVar +from pyomo.core.base.boolean_var import BooleanVarList as BooleanVarList +from pyomo.core.base.boolean_var import ScalarBooleanVar as ScalarBooleanVar +from pyomo.core.base.check import BuildCheck as BuildCheck +from pyomo.core.base.component import Component as Component +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.component import name as name +from pyomo.core.base.componentuid import ComponentUID as ComponentUID +from pyomo.core.base.config import PyomoOptions as PyomoOptions +from pyomo.core.base.connector import Connector as Connector +from pyomo.core.base.constraint import Constraint as Constraint +from pyomo.core.base.constraint import ConstraintList as ConstraintList +from pyomo.core.base.constraint import simple_constraint_rule as simple_constraint_rule +from pyomo.core.base.constraint import simple_constraintlist_rule as simple_constraintlist_rule +from pyomo.core.base.expression import Expression as Expression +from pyomo.core.base.external import ExternalFunction as ExternalFunction +from pyomo.core.base.instance2dat import instance2dat as instance2dat +from pyomo.core.base.label import AlphaNumericTextLabeler as AlphaNumericTextLabeler +from pyomo.core.base.label import CNameLabeler as CNameLabeler +from pyomo.core.base.label import CounterLabeler as CounterLabeler +from pyomo.core.base.label import CuidLabeler as CuidLabeler +from pyomo.core.base.label import NameLabeler as NameLabeler +from pyomo.core.base.label import NumericLabeler as NumericLabeler +from pyomo.core.base.label import ShortNameLabeler as ShortNameLabeler +from pyomo.core.base.label import TextLabeler as TextLabeler +from pyomo.core.base.logical_constraint import LogicalConstraint as LogicalConstraint +from pyomo.core.base.logical_constraint import LogicalConstraintList as LogicalConstraintList +from pyomo.core.base.misc import display as display +from pyomo.core.base.objective import Objective as Objective +from pyomo.core.base.objective import ObjectiveList as ObjectiveList +from pyomo.core.base.objective import simple_objective_rule as simple_objective_rule +from pyomo.core.base.objective import simple_objectivelist_rule as simple_objectivelist_rule +from pyomo.core.base.param import Param as Param +from pyomo.core.base.piecewise import Piecewise as Piecewise +from pyomo.core.base.PyomoModel import AbstractModel as AbstractModel +from pyomo.core.base.PyomoModel import ConcreteModel as ConcreteModel +from pyomo.core.base.PyomoModel import Model as Model +from pyomo.core.base.PyomoModel import global_option as global_option +from pyomo.core.base.reference import Reference as Reference +from pyomo.core.base.set import Any as Any +from pyomo.core.base.set import AnyWithNone as AnyWithNone +from pyomo.core.base.set import Binary as Binary +from pyomo.core.base.set import Boolean as Boolean +from pyomo.core.base.set import BooleanSet as BooleanSet +from pyomo.core.base.set import EmptySet as EmptySet +from pyomo.core.base.set import IntegerInterval as IntegerInterval +from pyomo.core.base.set import Integers as Integers +from pyomo.core.base.set import IntegerSet as IntegerSet +from pyomo.core.base.set import NegativeIntegers as NegativeIntegers +from pyomo.core.base.set import NegativeReals as NegativeReals +from pyomo.core.base.set import NonNegativeIntegers as NonNegativeIntegers +from pyomo.core.base.set import NonNegativeReals as NonNegativeReals +from pyomo.core.base.set import NonPositiveIntegers as NonPositiveIntegers +from pyomo.core.base.set import NonPositiveReals as NonPositiveReals +from pyomo.core.base.set import PercentFraction as PercentFraction +from pyomo.core.base.set import PositiveIntegers as PositiveIntegers +from pyomo.core.base.set import PositiveReals as PositiveReals +from pyomo.core.base.set import RangeSet as RangeSet +from pyomo.core.base.set import RealInterval as RealInterval +from pyomo.core.base.set import Reals as Reals +from pyomo.core.base.set import RealSet as RealSet +from pyomo.core.base.set import Set as Set +from pyomo.core.base.set import SetOf as SetOf +from pyomo.core.base.set import UnitInterval as UnitInterval +from pyomo.core.base.set import set_options as set_options +from pyomo.core.base.set import simple_set_rule as simple_set_rule +from pyomo.core.base.sos import SOSConstraint as SOSConstraint +from pyomo.core.base.suffix import Suffix as Suffix +from pyomo.core.base.suffix import active_export_suffix_generator as active_export_suffix_generator +from pyomo.core.base.suffix import active_import_suffix_generator as active_import_suffix_generator +from pyomo.core.base.symbol_map import symbol_map_from_instance as symbol_map_from_instance +from pyomo.core.base.transformation import ReverseTransformationToken as ReverseTransformationToken +from pyomo.core.base.transformation import Transformation as Transformation +from pyomo.core.base.transformation import TransformationFactory as TransformationFactory +from pyomo.core.base.var import ScalarVar as ScalarVar +from pyomo.core.base.var import Var as Var +from pyomo.core.base.var import VarList as VarList +from pyomo.core.expr import Expr_if as Expr_if +from pyomo.core.expr import acos as acos +from pyomo.core.expr import acosh as acosh +from pyomo.core.expr import all_different as all_different +from pyomo.core.expr import asin as asin +from pyomo.core.expr import asinh as asinh +from pyomo.core.expr import atan as atan +from pyomo.core.expr import atanh as atanh +from pyomo.core.expr import atleast as atleast +from pyomo.core.expr import atmost as atmost +from pyomo.core.expr import boolean_value as boolean_value +from pyomo.core.expr import calculus as calculus +from pyomo.core.expr import ceil as ceil +from pyomo.core.expr import cos as cos +from pyomo.core.expr import cosh as cosh +from pyomo.core.expr import count_if as count_if +from pyomo.core.expr import equivalent as equivalent +from pyomo.core.expr import exactly as exactly +from pyomo.core.expr import exp as exp +from pyomo.core.expr import expr_common as expr_common +from pyomo.core.expr import expr_errors as expr_errors +from pyomo.core.expr import floor as floor +from pyomo.core.expr import implies as implies +from pyomo.core.expr import inequality as inequality +from pyomo.core.expr import land as land +from pyomo.core.expr import linear_expression as linear_expression +from pyomo.core.expr import lnot as lnot +from pyomo.core.expr import log as log +from pyomo.core.expr import log10 as log10 +from pyomo.core.expr import logical_expr as logical_expr +from pyomo.core.expr import lor as lor +from pyomo.core.expr import nonlinear_expression as nonlinear_expression +from pyomo.core.expr import numeric_expr as numeric_expr +from pyomo.core.expr import numvalue as numvalue +from pyomo.core.expr import sin as sin +from pyomo.core.expr import sinh as sinh +from pyomo.core.expr import sqrt as sqrt +from pyomo.core.expr import symbol_map as symbol_map +from pyomo.core.expr import sympy_tools as sympy_tools +from pyomo.core.expr import tan as tan +from pyomo.core.expr import tanh as tanh +from pyomo.core.expr import taylor_series as taylor_series +from pyomo.core.expr import visitor as visitor +from pyomo.core.expr import xor as xor +from pyomo.core.expr.boolean_value import BooleanConstant as BooleanConstant +from pyomo.core.expr.boolean_value import BooleanValue as BooleanValue +from pyomo.core.expr.boolean_value import as_boolean as as_boolean +from pyomo.core.expr.boolean_value import native_logical_values as native_logical_values +from pyomo.core.expr.calculus.derivatives import differentiate as differentiate +from pyomo.core.expr.numvalue import NumericValue as NumericValue +from pyomo.core.expr.numvalue import PyomoObject as PyomoObject +from pyomo.core.expr.numvalue import ZeroConstant as ZeroConstant +from pyomo.core.expr.numvalue import is_constant as is_constant +from pyomo.core.expr.numvalue import is_fixed as is_fixed +from pyomo.core.expr.numvalue import is_potentially_variable as is_potentially_variable +from pyomo.core.expr.numvalue import is_variable_type as is_variable_type +from pyomo.core.expr.numvalue import native_numeric_types as native_numeric_types +from pyomo.core.expr.numvalue import native_types as native_types +from pyomo.core.expr.numvalue import nonpyomo_leaf_types as nonpyomo_leaf_types +from pyomo.core.expr.numvalue import polynomial_degree as polynomial_degree +from pyomo.core.expr.numvalue import value as value +from pyomo.core.expr.symbol_map import SymbolMap as SymbolMap +from pyomo.core.expr.taylor_series import taylor_series_expansion as taylor_series_expansion +from pyomo.core.util import dot_product as dot_product +from pyomo.core.util import prod as prod +from pyomo.core.util import quicksum as quicksum +from pyomo.core.util import sequence as sequence +from pyomo.core.util import sum_product as sum_product +from pyomo.core.util import summation as summation diff --git a/stubs/pyomo/core/base/PyomoModel.pyi b/stubs/pyomo/core/base/PyomoModel.pyi new file mode 100644 index 000000000..94a118cb7 --- /dev/null +++ b/stubs/pyomo/core/base/PyomoModel.pyi @@ -0,0 +1,111 @@ +from _typeshed import Incomplete +from pyomo.common import timing as timing +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.dependencies import pympler as pympler +from pyomo.common.dependencies import pympler_available as pympler_available +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.gc_manager import PauseGC as PauseGC +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.numeric_types import value as value +from pyomo.core.base.block import ScalarBlock as ScalarBlock +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.componentuid import ComponentUID as ComponentUID +from pyomo.core.base.constraint import Constraint as Constraint +from pyomo.core.base.label import CNameLabeler as CNameLabeler +from pyomo.core.base.label import CuidLabeler as CuidLabeler +from pyomo.core.base.objective import Objective as Objective +from pyomo.core.base.set import Set as Set +from pyomo.core.base.suffix import active_import_suffix_generator as active_import_suffix_generator +from pyomo.core.base.var import Var as Var +from pyomo.core.expr.symbol_map import SymbolMap as SymbolMap +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager +from pyomo.dataportal.DataPortal import DataPortal as DataPortal +from pyomo.opt.results import Solution as Solution +from pyomo.opt.results import SolverStatus as SolverStatus +from pyomo.opt.results import UndefinedData as UndefinedData + +logger: Incomplete +id_func = id + +def global_option(function, name, value): ... + +class PyomoConfig(Bunch): + def __init__(self, *args, **kw) -> None: ... + +class ModelSolution: + def __init__(self) -> None: ... + def __getattr__(self, name): ... + def __setattr__(self, name, val) -> None: ... + +class ModelSolutions: + def __init__(self, instance) -> None: ... + symbol_map: Incomplete + solutions: Incomplete + index: Incomplete + def clear(self, clear_symbol_maps: bool = True) -> None: ... + def __len__(self) -> int: ... + def __getitem__(self, index): ... + def add_symbol_map(self, symbol_map) -> None: ... + def delete_symbol_map(self, smap_id) -> None: ... + def load_from( + self, + results, + allow_consistent_values_for_fixed_vars: bool = False, + comparison_tolerance_for_fixed_vars: float = 1e-05, + ignore_invalid_labels: bool = False, + id=None, + delete_symbol_map: bool = True, + clear: bool = True, + default_variable_value=None, + select: int = 0, + ignore_fixed_vars: bool = True, + ) -> None: ... + def store_to(self, results, cuid: bool = False, skip_stale_vars: bool = False) -> None: ... + def add_solution( + self, + solution, + smap_id, + delete_symbol_map: bool = True, + cache=None, + ignore_invalid_labels: bool = False, + ignore_missing_symbols: bool = True, + default_variable_value=None, + ): ... + def select( + self, + index: int = 0, + allow_consistent_values_for_fixed_vars: bool = False, + comparison_tolerance_for_fixed_vars: float = 1e-05, + ignore_invalid_labels: bool = False, + ignore_fixed_vars: bool = True, + ) -> None: ... + +class Model(ScalarBlock): + def __new__(cls, *args, **kwds): ... + statistics: Incomplete + config: Incomplete + solutions: Incomplete + def __init__(self, name: str = 'unknown', **kwargs) -> None: ... + def compute_statistics(self, active: bool = True) -> None: ... + def nvariables(self): ... + def nconstraints(self): ... + def nobjectives(self): ... + def create_instance( + self, + filename=None, + data=None, + name=None, + namespace=None, + namespaces=None, + profile_memory: int = 0, + report_timing: bool = False, + **kwds, + ): ... + def preprocess(self, preprocessor=None) -> None: ... + def load(self, arg, namespaces=[None], profile_memory: int = 0) -> None: ... + +class ConcreteModel(Model): + def __init__(self, *args, **kwds) -> None: ... + +class AbstractModel(Model): + def __init__(self, *args, **kwds) -> None: ... diff --git a/stubs/pyomo/core/base/__init__.pyi b/stubs/pyomo/core/base/__init__.pyi new file mode 100644 index 000000000..faaeb745e --- /dev/null +++ b/stubs/pyomo/core/base/__init__.pyi @@ -0,0 +1,122 @@ +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.deprecation import moved_module as moved_module +from pyomo.common.deprecation import relocated_module_attribute as relocated_module_attribute +from pyomo.common.enums import maximize as maximize +from pyomo.common.enums import minimize as minimize +from pyomo.core.base.action import BuildAction as BuildAction +from pyomo.core.base.block import Block as Block +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.block import ScalarBlock as ScalarBlock +from pyomo.core.base.block import active_components as active_components +from pyomo.core.base.block import active_components_data as active_components_data +from pyomo.core.base.block import components as components +from pyomo.core.base.block import components_data as components_data +from pyomo.core.base.boolean_var import BooleanVar as BooleanVar +from pyomo.core.base.boolean_var import BooleanVarData as BooleanVarData +from pyomo.core.base.boolean_var import BooleanVarList as BooleanVarList +from pyomo.core.base.boolean_var import ScalarBooleanVar as ScalarBooleanVar +from pyomo.core.base.check import BuildCheck as BuildCheck +from pyomo.core.base.component import Component as Component +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.component import name as name +from pyomo.core.base.componentuid import ComponentUID as ComponentUID +from pyomo.core.base.config import PyomoOptions as PyomoOptions +from pyomo.core.base.connector import Connector as Connector +from pyomo.core.base.connector import ConnectorData as ConnectorData +from pyomo.core.base.constraint import Constraint as Constraint +from pyomo.core.base.constraint import ConstraintData as ConstraintData +from pyomo.core.base.constraint import ConstraintList as ConstraintList +from pyomo.core.base.constraint import simple_constraint_rule as simple_constraint_rule +from pyomo.core.base.constraint import simple_constraintlist_rule as simple_constraintlist_rule +from pyomo.core.base.enums import SortComponents as SortComponents +from pyomo.core.base.enums import TraversalStrategy as TraversalStrategy +from pyomo.core.base.expression import Expression as Expression +from pyomo.core.base.expression import ExpressionData as ExpressionData +from pyomo.core.base.expression import NamedExpressionData as NamedExpressionData +from pyomo.core.base.external import ExternalFunction as ExternalFunction +from pyomo.core.base.instance2dat import instance2dat as instance2dat +from pyomo.core.base.label import AlphaNumericTextLabeler as AlphaNumericTextLabeler +from pyomo.core.base.label import CNameLabeler as CNameLabeler +from pyomo.core.base.label import CounterLabeler as CounterLabeler +from pyomo.core.base.label import CuidLabeler as CuidLabeler +from pyomo.core.base.label import NameLabeler as NameLabeler +from pyomo.core.base.label import NumericLabeler as NumericLabeler +from pyomo.core.base.label import ShortNameLabeler as ShortNameLabeler +from pyomo.core.base.label import TextLabeler as TextLabeler +from pyomo.core.base.logical_constraint import LogicalConstraint as LogicalConstraint +from pyomo.core.base.logical_constraint import LogicalConstraintData as LogicalConstraintData +from pyomo.core.base.logical_constraint import LogicalConstraintList as LogicalConstraintList +from pyomo.core.base.misc import display as display +from pyomo.core.base.objective import Objective as Objective +from pyomo.core.base.objective import ObjectiveData as ObjectiveData +from pyomo.core.base.objective import ObjectiveList as ObjectiveList +from pyomo.core.base.objective import simple_objective_rule as simple_objective_rule +from pyomo.core.base.objective import simple_objectivelist_rule as simple_objectivelist_rule +from pyomo.core.base.param import Param as Param +from pyomo.core.base.param import ParamData as ParamData +from pyomo.core.base.piecewise import Piecewise as Piecewise +from pyomo.core.base.piecewise import PiecewiseData as PiecewiseData +from pyomo.core.base.PyomoModel import AbstractModel as AbstractModel +from pyomo.core.base.PyomoModel import ConcreteModel as ConcreteModel +from pyomo.core.base.PyomoModel import Model as Model +from pyomo.core.base.PyomoModel import ModelSolution as ModelSolution +from pyomo.core.base.PyomoModel import ModelSolutions as ModelSolutions +from pyomo.core.base.PyomoModel import global_option as global_option +from pyomo.core.base.reference import Reference as Reference +from pyomo.core.base.set import Any as Any +from pyomo.core.base.set import AnyWithNone as AnyWithNone +from pyomo.core.base.set import Binary as Binary +from pyomo.core.base.set import Boolean as Boolean +from pyomo.core.base.set import BooleanSet as BooleanSet +from pyomo.core.base.set import EmptySet as EmptySet +from pyomo.core.base.set import IntegerInterval as IntegerInterval +from pyomo.core.base.set import Integers as Integers +from pyomo.core.base.set import IntegerSet as IntegerSet +from pyomo.core.base.set import NegativeIntegers as NegativeIntegers +from pyomo.core.base.set import NegativeReals as NegativeReals +from pyomo.core.base.set import NonNegativeIntegers as NonNegativeIntegers +from pyomo.core.base.set import NonNegativeReals as NonNegativeReals +from pyomo.core.base.set import NonPositiveIntegers as NonPositiveIntegers +from pyomo.core.base.set import NonPositiveReals as NonPositiveReals +from pyomo.core.base.set import PercentFraction as PercentFraction +from pyomo.core.base.set import PositiveIntegers as PositiveIntegers +from pyomo.core.base.set import PositiveReals as PositiveReals +from pyomo.core.base.set import RangeSet as RangeSet +from pyomo.core.base.set import RealInterval as RealInterval +from pyomo.core.base.set import Reals as Reals +from pyomo.core.base.set import RealSet as RealSet +from pyomo.core.base.set import Set as Set +from pyomo.core.base.set import SetData as SetData +from pyomo.core.base.set import SetOf as SetOf +from pyomo.core.base.set import UnitInterval as UnitInterval +from pyomo.core.base.set import set_options as set_options +from pyomo.core.base.set import simple_set_rule as simple_set_rule +from pyomo.core.base.sos import SOSConstraint as SOSConstraint +from pyomo.core.base.sos import SOSConstraintData as SOSConstraintData +from pyomo.core.base.suffix import Suffix as Suffix +from pyomo.core.base.suffix import active_export_suffix_generator as active_export_suffix_generator +from pyomo.core.base.suffix import active_import_suffix_generator as active_import_suffix_generator +from pyomo.core.base.symbol_map import symbol_map_from_instance as symbol_map_from_instance +from pyomo.core.base.transformation import ReverseTransformationToken as ReverseTransformationToken +from pyomo.core.base.transformation import Transformation as Transformation +from pyomo.core.base.transformation import TransformationFactory as TransformationFactory +from pyomo.core.base.var import ScalarVar as ScalarVar +from pyomo.core.base.var import Var as Var +from pyomo.core.base.var import VarData as VarData +from pyomo.core.base.var import VarList as VarList +from pyomo.core.expr.boolean_value import BooleanConstant as BooleanConstant +from pyomo.core.expr.boolean_value import BooleanValue as BooleanValue +from pyomo.core.expr.boolean_value import as_boolean as as_boolean +from pyomo.core.expr.boolean_value import native_logical_values as native_logical_values +from pyomo.core.expr.numvalue import NumericValue as NumericValue +from pyomo.core.expr.numvalue import ZeroConstant as ZeroConstant +from pyomo.core.expr.numvalue import is_constant as is_constant +from pyomo.core.expr.numvalue import is_fixed as is_fixed +from pyomo.core.expr.numvalue import is_potentially_variable as is_potentially_variable +from pyomo.core.expr.numvalue import is_variable_type as is_variable_type +from pyomo.core.expr.numvalue import native_numeric_types as native_numeric_types +from pyomo.core.expr.numvalue import native_types as native_types +from pyomo.core.expr.numvalue import nonpyomo_leaf_types as nonpyomo_leaf_types +from pyomo.core.expr.numvalue import polynomial_degree as polynomial_degree +from pyomo.core.expr.numvalue import value as value +from pyomo.core.expr.symbol_map import SymbolMap as SymbolMap diff --git a/stubs/pyomo/core/base/action.pyi b/stubs/pyomo/core/base/action.pyi new file mode 100644 index 000000000..a2afbf4b4 --- /dev/null +++ b/stubs/pyomo/core/base/action.pyi @@ -0,0 +1,12 @@ +from _typeshed import Incomplete +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.timing import ConstructionTimer as ConstructionTimer +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.indexed_component import IndexedComponent as IndexedComponent +from pyomo.core.base.misc import apply_indexed_rule as apply_indexed_rule + +logger: Incomplete + +class BuildAction(IndexedComponent): + def __init__(self, *args, **kwd) -> None: ... + def construct(self, data=None) -> None: ... diff --git a/stubs/pyomo/core/base/block.pyi b/stubs/pyomo/core/base/block.pyi new file mode 100644 index 000000000..3c2539ee3 --- /dev/null +++ b/stubs/pyomo/core/base/block.pyi @@ -0,0 +1,184 @@ +from collections.abc import Generator + +from _typeshed import Incomplete +from pyomo.common.autoslots import AutoSlots as AutoSlots +from pyomo.common.collections import Mapping as Mapping +from pyomo.common.deprecation import RenamedClass as RenamedClass +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.common.formatting import StreamIndenter as StreamIndenter +from pyomo.common.gc_manager import PauseGC as PauseGC +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.pyomo_typing import overload as overload +from pyomo.common.timing import ConstructionTimer as ConstructionTimer +from pyomo.core.base.component import ActiveComponentData as ActiveComponentData +from pyomo.core.base.component import Component as Component +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.componentuid import ComponentUID as ComponentUID +from pyomo.core.base.enums import SortComponents as SortComponents +from pyomo.core.base.enums import TraversalStrategy as TraversalStrategy +from pyomo.core.base.global_set import UnindexedComponent_index as UnindexedComponent_index +from pyomo.core.base.indexed_component import ActiveIndexedComponent as ActiveIndexedComponent +from pyomo.core.base.indexed_component import IndexedComponent as IndexedComponent +from pyomo.core.base.indexed_component import UnindexedComponent_set as UnindexedComponent_set +from pyomo.core.base.initializer import Initializer as Initializer +from pyomo.core.base.set import Any as Any +from pyomo.core.base.var import Var as Var +from pyomo.opt import WriterFactory as WriterFactory +from pyomo.opt.base import ProblemFormat as ProblemFormat +from pyomo.opt.base import guess_format as guess_format + +logger: Incomplete + +class _generic_component_decorator: + def __init__(self, component, block, *args, **kwds) -> None: ... + def __call__(self, rule): ... + +class _component_decorator: + def __init__(self, block, component) -> None: ... + def __call__(self, *args, **kwds): ... + +class SubclassOf: + ctype: Incomplete + def __init__(self, *ctype) -> None: ... + def __contains__(self, item) -> bool: ... + def __len__(self) -> int: ... + def __getitem__(self, item): ... + def __iter__(self): ... + +class _DeduplicateInfo: + seen_components: Incomplete + seen_comp_thru_reference: Incomplete + seen_data: Incomplete + def __init__(self) -> None: ... + def unique(self, comp, items, are_values): ... + +class _BlockConstruction: + data: Incomplete + +class PseudoMap(AutoSlots.Mixin): + def __init__(self, block, ctype, active=None, sort: bool = False) -> None: ... + def __iter__(self): ... + def __getitem__(self, key): ... + def __nonzero__(self): ... + __bool__ = __nonzero__ + def __len__(self) -> int: ... + def __contains__(self, key) -> bool: ... + def keys(self): ... + def values(self): ... + def items(self) -> Generator[Incomplete]: ... + def iterkeys(self): ... + def itervalues(self): ... + def iteritems(self): ... + +class BlockData(ActiveComponentData): + def __init__(self, component) -> None: ... + def __getattr__(self, val) -> Component | IndexedComponent | Any: ... + def __setattr__(self, name: str, val: Component | IndexedComponent | Any): ... + def __delattr__(self, name) -> None: ... + def set_value(self, val) -> None: ... + def clear(self) -> None: ... + def transfer_attributes_from(self, src) -> None: ... + def collect_ctypes(self, active=None, descend_into: bool = True): ... + def model(self): ... + def find_component(self, label_or_component): ... + def add_component(self, name, val) -> None: ... + def del_component(self, name_or_object) -> None: ... + def reclassify_component_type( + self, name_or_object, new_ctype, preserve_declaration_order: bool = True + ) -> None: ... + def clone(self, memo=None): ... + def contains_component(self, ctype): ... + def component(self, name_or_object): ... + def component_map(self, ctype=None, active=None, sort: bool = False): ... + def all_components(self, *args, **kwargs): ... + def active_components(self, *args, **kwargs): ... + def all_component_data(self, *args, **kwargs): ... + def active_component_data(self, *args, **kwargs): ... + def component_objects( + self, + ctype=None, + active=None, + sort: bool = False, + descend_into: bool = True, + descent_order=None, + ) -> Generator[Incomplete, Incomplete]: ... + def component_data_objects( + self, + ctype=None, + active=None, + sort: bool = False, + descend_into: bool = True, + descent_order=None, + ) -> Generator[Incomplete, Incomplete]: ... + def component_data_iterindex( + self, + ctype=None, + active=None, + sort: bool = False, + descend_into: bool = True, + descent_order=None, + ) -> Generator[Incomplete, Incomplete]: ... + def all_blocks(self, *args, **kwargs): ... + def active_blocks(self, *args, **kwargs): ... + def block_data_objects( + self, active=None, sort: bool = False, descend_into: bool = True, descent_order=None + ): ... + def fix_all_vars(self) -> None: ... + def unfix_all_vars(self) -> None: ... + def is_constructed(self): ... + def display(self, filename=None, ostream=None, prefix: str = '') -> None: ... + def valid_problem_types(self): ... + solutions: Incomplete + def write( + self, + filename=None, + format=None, + solver_capability=None, + io_options={}, + int_marker: bool = False, + ): ... + def private_data(self, scope=None): ... + +class _BlockData(metaclass=RenamedClass): + __renamed__new_class__ = BlockData + __renamed__version__: str + +class Block(ActiveIndexedComponent): + def construct(self, data=None) -> None: ... + def display(self, filename=None, ostream=None, prefix: str = '') -> None: ... + @staticmethod + def register_private_data_initializer(initializer, scope=None) -> None: ... + +class ScalarBlock(BlockData, Block): + def __init__(self, *args, **kwds) -> None: ... + display: Incomplete + +class SimpleBlock(metaclass=RenamedClass): + __renamed__new_class__ = ScalarBlock + __renamed__version__: str + +class IndexedBlock(Block): + def __init__(self, *args, **kwds) -> None: ... + @overload + def __getitem__(self, index) -> BlockData: ... + __getitem__: Incomplete + +def generate_cuid_names(block, ctype=None, descend_into: bool = True): ... +def active_components(block, ctype, sort_by_names: bool = False, sort_by_keys: bool = False): ... +def components(block, ctype, sort_by_names: bool = False, sort_by_keys: bool = False): ... +def active_components_data( + block, ctype, sort=None, sort_by_keys: bool = False, sort_by_names: bool = False +): ... +def components_data( + block, ctype, sort=None, sort_by_keys: bool = False, sort_by_names: bool = False +): ... + +class ScalarCustomBlockMixin: + def __init__(self, *args, **kwargs) -> None: ... + +class CustomBlock(Block): + def __init__(self, *args, **kwargs) -> None: ... + def __new__(cls, *args, **kwargs): ... + +def declare_custom_block(name, new_ctype=None): ... diff --git a/stubs/pyomo/core/base/blockutil.pyi b/stubs/pyomo/core/base/blockutil.pyi new file mode 100644 index 000000000..bfe1d2e18 --- /dev/null +++ b/stubs/pyomo/core/base/blockutil.pyi @@ -0,0 +1,4 @@ +from pyomo.common import deprecated as deprecated +from pyomo.core.base import Var as Var + +def has_discrete_variables(block): ... diff --git a/stubs/pyomo/core/base/boolean_var.pyi b/stubs/pyomo/core/base/boolean_var.pyi new file mode 100644 index 000000000..d1bc187d6 --- /dev/null +++ b/stubs/pyomo/core/base/boolean_var.pyi @@ -0,0 +1,103 @@ +from weakref import ReferenceType as ReferenceType + +from _typeshed import Incomplete +from pyomo.common.deprecation import RenamedClass as RenamedClass +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.common.timing import ConstructionTimer as ConstructionTimer +from pyomo.core.base.component import ComponentData as ComponentData +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.global_set import UnindexedComponent_index as UnindexedComponent_index +from pyomo.core.base.indexed_component import IndexedComponent as IndexedComponent +from pyomo.core.base.indexed_component import UnindexedComponent_set as UnindexedComponent_set +from pyomo.core.base.misc import apply_indexed_rule as apply_indexed_rule +from pyomo.core.base.set import Binary as Binary +from pyomo.core.base.set import BooleanSet as BooleanSet +from pyomo.core.base.set import Set as Set +from pyomo.core.base.util import is_functor as is_functor +from pyomo.core.base.var import Var as Var +from pyomo.core.expr import GetItemExpression as GetItemExpression +from pyomo.core.expr.boolean_value import BooleanValue as BooleanValue +from pyomo.core.expr.numvalue import value as value +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager + +logger: Incomplete + +class _DeprecatedImplicitAssociatedBinaryVariable: + def __init__(self, boolvar) -> None: ... + def __call__(self): ... + +class BooleanVarData(ComponentData, BooleanValue): + __autoslot_mappers__: Incomplete + fixed: bool + def __init__(self, component=None) -> None: ... + def is_fixed(self): ... + def is_constant(self): ... + def is_variable_type(self): ... + def is_potentially_variable(self): ... + def set_value(self, val, skip_validation: bool = False) -> None: ... + def clear(self) -> None: ... + def __call__(self, exception=...): ... + @property + def value(self): ... + @value.setter + def value(self, val) -> None: ... + @property + def domain(self): ... + @property + def stale(self): ... + @stale.setter + def stale(self, val) -> None: ... + def get_associated_binary(self): ... + def associate_binary_var(self, binary_var) -> None: ... + def fix(self, value=..., skip_validation: bool = False) -> None: ... + def unfix(self) -> None: ... + def free(self): ... + +class _BooleanVarData(metaclass=RenamedClass): + __renamed__new_class__ = BooleanVarData + __renamed__version__: str + +class _GeneralBooleanVarData(metaclass=RenamedClass): + __renamed__new_class__ = BooleanVarData + __renamed__version__: str + +class BooleanVar(IndexedComponent): + def __new__(cls, *args, **kwds): ... + def __init__(self, *args, **kwd) -> None: ... + def flag_as_stale(self) -> None: ... + def get_values(self, include_fixed_values: bool = True): ... + extract_values = get_values + def set_values(self, new_values, skip_validation: bool = False) -> None: ... + def construct(self, data=None) -> None: ... + def add(self, index): ... + +class ScalarBooleanVar(BooleanVarData, BooleanVar): + def __init__(self, *args, **kwd) -> None: ... + @property + def value(self): ... + @value.setter + def value(self, val): ... + @property + def domain(self): ... + def fix(self, value=..., skip_validation: bool = False): ... + def unfix(self): ... + +class SimpleBooleanVar(metaclass=RenamedClass): + __renamed__new_class__ = ScalarBooleanVar + __renamed__version__: str + +class IndexedBooleanVar(BooleanVar): + def fix(self, value=..., skip_validation: bool = False) -> None: ... + def unfix(self) -> None: ... + def free(self): ... + @property + def domain(self): ... + def __getitem__(self, args): ... + +class BooleanVarList(IndexedBooleanVar): + def __init__(self, **kwargs) -> None: ... + def construct(self, data=None) -> None: ... + def add(self): ... diff --git a/stubs/pyomo/core/base/check.pyi b/stubs/pyomo/core/base/check.pyi new file mode 100644 index 000000000..7f1ba2744 --- /dev/null +++ b/stubs/pyomo/core/base/check.pyi @@ -0,0 +1,12 @@ +from _typeshed import Incomplete +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.timing import ConstructionTimer as ConstructionTimer +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.indexed_component import IndexedComponent as IndexedComponent +from pyomo.core.base.misc import apply_indexed_rule as apply_indexed_rule + +logger: Incomplete + +class BuildCheck(IndexedComponent): + def __init__(self, *args, **kwd) -> None: ... + def construct(self, data=None) -> None: ... diff --git a/stubs/pyomo/core/base/component.pyi b/stubs/pyomo/core/base/component.pyi new file mode 100644 index 000000000..dcf415e88 --- /dev/null +++ b/stubs/pyomo/core/base/component.pyi @@ -0,0 +1,170 @@ +from copy import deepcopy as deepcopy +from pickle import PickleError as PickleError + +import pyomo.common +from _typeshed import Incomplete +from pyomo.common import DeveloperError as DeveloperError +from pyomo.common.autoslots import AutoSlots as AutoSlots +from pyomo.common.autoslots import fast_deepcopy as fast_deepcopy +from pyomo.common.collections import OrderedDict as OrderedDict +from pyomo.common.deprecation import ( + RenamedClass as RenamedClass, +) +from pyomo.common.deprecation import ( + deprecated as deprecated, +) +from pyomo.common.deprecation import ( + deprecation_warning as deprecation_warning, +) +from pyomo.common.deprecation import ( + relocated_module_attribute as relocated_module_attribute, +) +from pyomo.common.factory import Factory as Factory +from pyomo.common.formatting import ( + StreamIndenter as StreamIndenter, +) +from pyomo.common.formatting import ( + tabular_writer as tabular_writer, +) +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.common.sorting import sorted_robust as sorted_robust +from pyomo.core.base.component_namer import index_repr as index_repr +from pyomo.core.base.component_namer import name_repr as name_repr +from pyomo.core.base.global_set import UnindexedComponent_index as UnindexedComponent_index +from pyomo.core.pyomoobject import PyomoObject as PyomoObject + +logger: Incomplete + +class ModelComponentFactoryClass(Factory): + def register(self, doc=None): ... + +ModelComponentFactory: Incomplete + +def name(component, index=..., fully_qualified: bool = False, relative_to=None): ... +def cname(*args, **kwds): ... + +class CloneError(pyomo.common.errors.PyomoException): ... + +class ComponentBase(PyomoObject): + def is_component_type(self): ... + def __deepcopy__(self, memo): ... + def __deepcopy_field__(self, value, memo, slot_name): ... + def cname(self, *args, **kwds): ... + def pprint(self, ostream=None, verbose: bool = False, prefix: str = '') -> None: ... + @property + def name(self): ... + @name.setter + def name(self, val) -> None: ... + @property + def local_name(self): ... + @property + def active(self): ... + @active.setter + def active(self, value) -> None: ... + def __iter__(self): ... + def at(self, index: int) -> typingAny: ... + def ord(self, item: typingAny) -> int: ... + def first(self) -> typingAny: ... + def last(self) -> typingAny: ... + def next(self, item: typingAny, step: int = 1) -> typingAny: ... + def nextw(self, item: typingAny, step: int = 1) -> typingAny: ... + def prev(self, item: typingAny, step: int = 1) -> typingAny: ... + def prevw(self, item: typingAny, step: int = 1) -> typingAny: ... + +class _ComponentBase(metaclass=RenamedClass): + __renamed__new_class__ = ComponentBase + __renamed__version__: str + +class Component(ComponentBase): + __autoslot_mappers__: Incomplete + doc: Incomplete + def __init__(self, **kwds) -> None: ... + @property + def ctype(self): ... + def type(self): ... + def construct(self, data=None) -> None: ... + def is_constructed(self): ... + def reconstruct(self, data=None) -> None: ... + def valid_model_component(self): ... + def pprint(self, ostream=None, verbose: bool = False, prefix: str = '') -> None: ... + def display(self, ostream=None, verbose: bool = False, prefix: str = '') -> None: ... + def parent_component(self): ... + def parent_block(self): ... + def model(self): ... + def root_block(self): ... + def getname(self, fully_qualified: bool = False, name_buffer=None, relative_to=None): ... + @property + def name(self): ... + @name.setter + def name(self, val) -> None: ... + def is_indexed(self): ... + def clear_suffix_value(self, suffix_or_name, expand: bool = True) -> None: ... + def set_suffix_value(self, suffix_or_name, value, expand: bool = True) -> None: ... + def get_suffix_value(self, suffix_or_name, default=None): ... + def __getitem__(self, key: typingAny) -> typingAny: ... + +class ActiveComponent(Component): + def __init__(self, **kwds) -> None: ... + @property + def active(self): ... + @active.setter + def active(self, value) -> None: ... + def activate(self) -> None: ... + def deactivate(self) -> None: ... + +class ComponentData(ComponentBase): + __autoslot_mappers__: Incomplete + def __init__(self, component) -> None: ... + @property + def ctype(self): ... + def type(self): ... + def parent_component(self): ... + def parent_block(self): ... + def model(self): ... + def index(self): ... + def getname(self, fully_qualified: bool = False, name_buffer=None, relative_to=None): ... + def is_indexed(self): ... + def clear_suffix_value(self, suffix_or_name, expand: bool = True) -> None: ... + def set_suffix_value(self, suffix_or_name, value, expand: bool = True) -> None: ... + def get_suffix_value(self, suffix_or_name, default=None): ... + def __len__(self) -> int: ... + def __getitem__(self, key: typingAny) -> typingAny: ... + def __bool__(self) -> bool: ... + def __int__(self) -> int: ... + def __float__(self) -> float: ... + def __lt__(self, other: typingAny) -> typingAny: ... + def __le__(self, other: typingAny) -> typingAny: ... + def __eq__(self, other: typingAny) -> typingAny: ... + def __ne__(self, other: typingAny) -> typingAny: ... + def __gt__(self, other: typingAny) -> typingAny: ... + def __ge__(self, other: typingAny) -> typingAny: ... + def __neg__(self) -> typingAny: ... + def __pos__(self) -> typingAny: ... + def __abs__(self) -> typingAny: ... + def __add__(self, other: typingAny) -> typingAny: ... + def __sub__(self, other: typingAny) -> typingAny: ... + def __mul__(self, other: typingAny) -> typingAny: ... + def __div__(self, other: typingAny) -> typingAny: ... + def __truediv__(self, other: typingAny) -> typingAny: ... + def __pow__(self, other: typingAny) -> typingAny: ... + def __radd__(self, other: typingAny) -> typingAny: ... + def __rsub__(self, other: typingAny) -> typingAny: ... + def __rmul__(self, other: typingAny) -> typingAny: ... + def __rdiv__(self, other: typingAny) -> typingAny: ... + def __rtruediv__(self, other: typingAny) -> typingAny: ... + def __rpow__(self, other: typingAny) -> typingAny: ... + def __iadd__(self, other: typingAny) -> typingAny: ... + def __isub__(self, other: typingAny) -> typingAny: ... + def __imul__(self, other: typingAny) -> typingAny: ... + def __idiv__(self, other: typingAny) -> typingAny: ... + def __itruediv__(self, other: typingAny) -> typingAny: ... + def __ipow__(self, other: typingAny) -> typingAny: ... + +class ActiveComponentData(ComponentData): + def __init__(self, component) -> None: ... + @property + def active(self): ... + @active.setter + def active(self, value) -> None: ... + def activate(self) -> None: ... + def deactivate(self) -> None: ... diff --git a/stubs/pyomo/core/base/component_namer.pyi b/stubs/pyomo/core/base/component_namer.pyi new file mode 100644 index 000000000..7bb59c3f4 --- /dev/null +++ b/stubs/pyomo/core/base/component_namer.pyi @@ -0,0 +1,10 @@ +from _typeshed import Incomplete + +literals: str +special_chars: Incomplete +re_number: Incomplete +re_special_char: Incomplete + +def name_repr(x, unknown_handler=...): ... +def tuple_repr(x, unknown_handler=...): ... +def index_repr(idx, unknown_handler=...): ... diff --git a/stubs/pyomo/core/base/component_order.pyi b/stubs/pyomo/core/base/component_order.pyi new file mode 100644 index 000000000..e29fdb10a --- /dev/null +++ b/stubs/pyomo/core/base/component_order.pyi @@ -0,0 +1,14 @@ +from _typeshed import Incomplete +from pyomo.core.base.block import Block as Block +from pyomo.core.base.constraint import Constraint as Constraint +from pyomo.core.base.expression import Expression as Expression +from pyomo.core.base.objective import Objective as Objective +from pyomo.core.base.param import Param as Param +from pyomo.core.base.set import RangeSet as RangeSet +from pyomo.core.base.set import Set as Set +from pyomo.core.base.sos import SOSConstraint as SOSConstraint +from pyomo.core.base.var import Var as Var + +items: Incomplete +display_items: Incomplete +display_name: Incomplete diff --git a/stubs/pyomo/core/base/componentuid.pyi b/stubs/pyomo/core/base/componentuid.pyi new file mode 100644 index 000000000..369a813e3 --- /dev/null +++ b/stubs/pyomo/core/base/componentuid.pyi @@ -0,0 +1,41 @@ +from collections.abc import Generator + +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.dependencies import pickle as pickle +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.core.base.component_namer import literals as literals +from pyomo.core.base.component_namer import special_chars as special_chars +from pyomo.core.base.indexed_component_slice import IndexedComponent_slice as IndexedComponent_slice +from pyomo.core.base.reference import Reference as Reference + +class _NotSpecified: ... + +class ComponentUID: + def __init__(self, component, cuid_buffer=None, context=None) -> None: ... + def get_repr(self, version: int = 2): ... + def __hash__(self): ... + def __lt__(self, other): ... + def __le__(self, other): ... + def __gt__(self, other): ... + def __ge__(self, other): ... + def __eq__(self, other): ... + def __ne__(self, other): ... + @staticmethod + def generate_cuid_string_map( + block, ctype=None, descend_into: bool = True, repr_version: int = 2 + ): ... + def find_component(self, block): ... + def find_component_on(self, block): ... + def list_components(self, block) -> Generator[Incomplete]: ... + def matches(self, component, context=None): ... + +t_ignore: str +tokens: Incomplete + +def t_NUMBER(t): ... +def t_WORD(t): ... +def t_STRING(t): ... +def t_STAR(t): ... +def t_PICKLE(t): ... +def t_error(t) -> None: ... diff --git a/stubs/pyomo/core/base/config.pyi b/stubs/pyomo/core/base/config.pyi new file mode 100644 index 000000000..9e654f0b9 --- /dev/null +++ b/stubs/pyomo/core/base/config.pyi @@ -0,0 +1,37 @@ +from _typeshed import Incomplete +from pyomo.common.config import ADVANCED_OPTION as ADVANCED_OPTION +from pyomo.common.config import ConfigBase as ConfigBase +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.dependencies import yaml as yaml +from pyomo.common.dependencies import yaml_available as yaml_available +from pyomo.common.dependencies import yaml_load_args as yaml_load_args + +logger: Incomplete + +class _PyomoOptions: + def __init__(self) -> None: ... + def active_config(self): ... + def __getitem__(self, key): ... + def get(self, key, default=...): ... + def __setitem__(self, key, val) -> None: ... + def __contains__(self, key) -> bool: ... + def __len__(self) -> int: ... + def __iter__(self): ... + def __getattr__(self, name): ... + def __setattr__(self, name, value): ... + def iterkeys(self): ... + def itervalues(self): ... + def iteritems(self): ... + def keys(self): ... + def values(self): ... + def items(self): ... + def declare(self, name, config): ... + def add(self, name, config): ... + def value(self, accessValue: bool = True): ... + def set_value(self, value): ... + def reset(self): ... + +def default_pyomo_config(): ... + +PyomoOptions: Incomplete diff --git a/stubs/pyomo/core/base/connector.pyi b/stubs/pyomo/core/base/connector.pyi new file mode 100644 index 000000000..9fb4a6013 --- /dev/null +++ b/stubs/pyomo/core/base/connector.pyi @@ -0,0 +1,49 @@ +from _typeshed import Incomplete +from pyomo.common.deprecation import RenamedClass as RenamedClass +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.formatting import tabular_writer as tabular_writer +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.common.numeric_types import value as value +from pyomo.common.timing import ConstructionTimer as ConstructionTimer +from pyomo.core.base.component import ComponentData as ComponentData +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.global_set import UnindexedComponent_index as UnindexedComponent_index +from pyomo.core.base.indexed_component import IndexedComponent as IndexedComponent +from pyomo.core.base.misc import apply_indexed_rule as apply_indexed_rule +from pyomo.core.expr.numvalue import NumericValue as NumericValue + +logger: Incomplete + +class ConnectorData(ComponentData, NumericValue): + vars: Incomplete + aggregators: Incomplete + def __init__(self, component=None) -> None: ... + def set_value(self, value) -> None: ... + def is_fixed(self): ... + def is_constant(self): ... + def is_potentially_variable(self): ... + def polynomial_degree(self): ... + def is_binary(self): ... + def is_integer(self): ... + def is_continuous(self): ... + def add(self, var, name=None, aggregate=None) -> None: ... + +class _ConnectorData(metaclass=RenamedClass): + __renamed__new_class__ = ConnectorData + __renamed__version__: str + +class Connector(IndexedComponent): + def __new__(cls, *args, **kwds): ... + def __init__(self, *args, **kwd) -> None: ... + def construct(self, data=None) -> None: ... + def display(self, prefix: str = '', ostream=None) -> None: ... + +class ScalarConnector(Connector, ConnectorData): + def __init__(self, *args, **kwd) -> None: ... + +class SimpleConnector(metaclass=RenamedClass): + __renamed__new_class__ = ScalarConnector + __renamed__version__: str + +class IndexedConnector(Connector): ... diff --git a/stubs/pyomo/core/base/constraint.pyi b/stubs/pyomo/core/base/constraint.pyi new file mode 100644 index 000000000..8211d0da5 --- /dev/null +++ b/stubs/pyomo/core/base/constraint.pyi @@ -0,0 +1,136 @@ +from _typeshed import Incomplete +from pyomo.common.deprecation import RenamedClass as RenamedClass +from pyomo.common.errors import DeveloperError as DeveloperError +from pyomo.common.errors import TemplateExpressionError as TemplateExpressionError +from pyomo.common.formatting import tabular_writer as tabular_writer +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.common.pyomo_typing import overload as overload +from pyomo.common.timing import ConstructionTimer as ConstructionTimer +from pyomo.core.base.component import ActiveComponentData as ActiveComponentData +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.disable_methods import disable_methods as disable_methods +from pyomo.core.base.global_set import UnindexedComponent_index as UnindexedComponent_index +from pyomo.core.base.indexed_component import ActiveIndexedComponent as ActiveIndexedComponent +from pyomo.core.base.indexed_component import IndexedComponent as IndexedComponent +from pyomo.core.base.indexed_component import UnindexedComponent_set as UnindexedComponent_set +from pyomo.core.base.indexed_component import rule_wrapper as rule_wrapper +from pyomo.core.base.initializer import CountedCallInitializer as CountedCallInitializer +from pyomo.core.base.initializer import IndexedCallInitializer as IndexedCallInitializer +from pyomo.core.base.initializer import Initializer as Initializer +from pyomo.core.base.set import Set as Set +from pyomo.core.expr import EqualityExpression as EqualityExpression +from pyomo.core.expr import ExpressionType as ExpressionType +from pyomo.core.expr import InequalityExpression as InequalityExpression +from pyomo.core.expr import RangedExpression as RangedExpression +from pyomo.core.expr.numvalue import NumericValue as NumericValue +from pyomo.core.expr.numvalue import as_numeric as as_numeric +from pyomo.core.expr.numvalue import is_fixed as is_fixed +from pyomo.core.expr.numvalue import native_logical_types as native_logical_types +from pyomo.core.expr.numvalue import native_numeric_types as native_numeric_types +from pyomo.core.expr.numvalue import native_types as native_types +from pyomo.core.expr.numvalue import value as value +from pyomo.core.expr.template_expr import templatize_constraint as templatize_constraint + +logger: Incomplete +TEMPLATIZE_CONSTRAINTS: bool + +def simple_constraint_rule(rule): ... +def simple_constraintlist_rule(rule): ... + +class ConstraintData(ActiveComponentData): + def __init__(self, expr=None, component=None) -> None: ... + def __call__(self, exception=...): ... + def to_bounded_expression(self, evaluate_bounds: bool = False): ... + @property + def body(self): ... + @property + def lower(self): ... + @property + def upper(self): ... + @property + def lb(self): ... + @property + def ub(self): ... + @property + def equality(self): ... + @property + def strict_lower(self): ... + @property + def strict_upper(self): ... + def has_lb(self): ... + def has_ub(self): ... + @property + def expr(self): ... + def get_value(self): ... + def set_value(self, expr) -> None: ... + def lslack(self): ... + def uslack(self): ... + def slack(self): ... + +class _ConstraintData(metaclass=RenamedClass): + __renamed__new_class__ = ConstraintData + __renamed__version__: str + +class _GeneralConstraintData(metaclass=RenamedClass): + __renamed__new_class__ = ConstraintData + __renamed__version__: str + +class TemplateConstraintData(ConstraintData): + def __init__(self, template_info, component, index) -> None: ... + @property + def expr(self): ... + def template_expr(self): ... + __class__: Incomplete + def set_value(self, expr): ... + def to_bounded_expression(self): ... + +class Constraint(ActiveIndexedComponent): + class Infeasible: ... + Feasible: Incomplete + NoConstraint: Incomplete + Violated = Infeasible + Satisfied = Feasible + def construct(self, data=None) -> None: ... + def display(self, prefix: str = '', ostream=None): ... + +class ScalarConstraint(ConstraintData, Constraint): + def __init__(self, *args, **kwds) -> None: ... + @property + def body(self): ... + @property + def lower(self): ... + @property + def upper(self): ... + @property + def equality(self): ... + @property + def strict_lower(self): ... + @property + def strict_upper(self): ... + def clear(self) -> None: ... + def set_value(self, expr): ... + def add(self, index, expr): ... + +class SimpleConstraint(metaclass=RenamedClass): + __renamed__new_class__ = ScalarConstraint + __renamed__version__: str + +class AbstractScalarConstraint(ScalarConstraint): ... + +class AbstractSimpleConstraint(metaclass=RenamedClass): + __renamed__new_class__ = AbstractScalarConstraint + __renamed__version__: str + +class IndexedConstraint(Constraint): + def add(self, index, expr): ... + @overload + def __getitem__(self, index) -> ConstraintData: ... + __getitem__: Incomplete + +class ConstraintList(IndexedConstraint): + class End: ... + rule: Incomplete + def __init__(self, **kwargs) -> None: ... + def construct(self, data=None) -> None: ... + def add(self, expr): ... diff --git a/stubs/pyomo/core/base/disable_methods.pyi b/stubs/pyomo/core/base/disable_methods.pyi new file mode 100644 index 000000000..740876010 --- /dev/null +++ b/stubs/pyomo/core/base/disable_methods.pyi @@ -0,0 +1,3 @@ +from pyomo.common import DeveloperError as DeveloperError + +def disable_methods(methods): ... diff --git a/stubs/pyomo/core/base/enums.pyi b/stubs/pyomo/core/base/enums.pyi new file mode 100644 index 000000000..876037ce6 --- /dev/null +++ b/stubs/pyomo/core/base/enums.pyi @@ -0,0 +1,41 @@ +import enum + +from _typeshed import Incomplete + +strictEnum: Incomplete + +class TraversalStrategy(enum.Enum): + BreadthFirstSearch = 1 + PrefixDepthFirstSearch = 2 + PostfixDepthFirstSearch = 3 + BFS = BreadthFirstSearch + ParentLastDepthFirstSearch = PostfixDepthFirstSearch + PostfixDFS = PostfixDepthFirstSearch + ParentFirstDepthFirstSearch = PrefixDepthFirstSearch + PrefixDFS = PrefixDepthFirstSearch + DepthFirstSearch = PrefixDepthFirstSearch + DFS = DepthFirstSearch + +class SortComponents(enum.Flag): + UNSORTED = 0 + ORDERED_INDICES = 2 + SORTED_INDICES = 4 + ALPHABETICAL = 8 + unsorted = UNSORTED + indices = SORTED_INDICES + declOrder = UNSORTED + declarationOrder = declOrder + alphaOrder = ALPHABETICAL + alphabeticalOrder = alphaOrder + alphabetical = alphaOrder + deterministic = ORDERED_INDICES + sortBoth = indices | alphabeticalOrder + alphabetizeComponentAndIndex = sortBoth + @staticmethod + def default(): ... + @staticmethod + def sorter(sort_by_names: bool = False, sort_by_keys: bool = False): ... + @staticmethod + def sort_names(flag): ... + @staticmethod + def sort_indices(flag): ... diff --git a/stubs/pyomo/core/base/expression.pyi b/stubs/pyomo/core/base/expression.pyi new file mode 100644 index 000000000..cde0a8129 --- /dev/null +++ b/stubs/pyomo/core/base/expression.pyi @@ -0,0 +1,128 @@ +from typing import Any as typingAny + +import pyomo.core.expr.numeric_expr as numeric_expr +from _typeshed import Incomplete +from pyomo.common.deprecation import RenamedClass as RenamedClass +from pyomo.common.formatting import tabular_writer as tabular_writer +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.common.numeric_types import ( + check_if_numeric_type as check_if_numeric_type, +) +from pyomo.common.numeric_types import ( + native_numeric_types as native_numeric_types, +) +from pyomo.common.numeric_types import ( + native_types as native_types, +) +from pyomo.common.pyomo_typing import overload as overload +from pyomo.common.timing import ConstructionTimer as ConstructionTimer +from pyomo.core.base.component import ( + ComponentData as ComponentData, +) +from pyomo.core.base.component import ( + ModelComponentFactory as ModelComponentFactory, +) +from pyomo.core.base.global_set import UnindexedComponent_index as UnindexedComponent_index +from pyomo.core.base.indexed_component import ( + IndexedComponent as IndexedComponent, +) +from pyomo.core.base.indexed_component import ( + UnindexedComponent_set as UnindexedComponent_set, +) +from pyomo.core.base.initializer import Initializer as Initializer +from pyomo.core.expr.numvalue import as_numeric as as_numeric + +logger: Incomplete + +class NamedExpressionData(numeric_expr.NumericValue): + EXPRESSION_SYSTEM: Incomplete + PRECEDENCE: int + ASSOCIATIVITY: Incomplete + def __call__(self, exception=...): ... + def create_node_with_local_data(self, values, classtype=None): ... + def is_named_expression_type(self): ... + def is_expression_type(self, expression_system=None): ... + def arg(self, index): ... + @property + def args(self): ... + def nargs(self): ... + def clone(self): ... + def polynomial_degree(self): ... + def is_potentially_variable(self): ... + @property + def expr(self): ... + @expr.setter + def expr(self, value) -> None: ... + def set_value(self, expr) -> None: ... + def is_constant(self): ... + def is_fixed(self): ... + def __iadd__(self, other): ... + def __imul__(self, other): ... + def __idiv__(self, other): ... + def __itruediv__(self, other): ... + def __ipow__(self, other): ... + +class _ExpressionData(metaclass=RenamedClass): + __renamed__new_class__ = NamedExpressionData + __renamed__version__: str + +class _GeneralExpressionDataImpl(metaclass=RenamedClass): + __renamed__new_class__ = NamedExpressionData + __renamed__version__: str + +class ExpressionData(NamedExpressionData, ComponentData): + def __init__(self, expr=None, component=None) -> None: ... + +class _GeneralExpressionData(metaclass=RenamedClass): + __renamed__new_class__ = ExpressionData + __renamed__version__: str + +class Expression(IndexedComponent): + NoConstraint = IndexedComponent.Skip + def __new__(cls, *args, **kwds): ... + def display(self, prefix: str = '', ostream=None): ... + def extract_values(self): ... + def store_values(self, new_values) -> None: ... + def construct(self, data=None) -> None: ... + def __lt__(self, other: typingAny) -> typingAny: ... + def __le__(self, other: typingAny) -> typingAny: ... + def __eq__(self, other: typingAny) -> typingAny: ... + def __ne__(self, other: typingAny) -> typingAny: ... + def __gt__(self, other: typingAny) -> typingAny: ... + def __ge__(self, other: typingAny) -> typingAny: ... + def __neg__(self) -> typingAny: ... + def __pos__(self) -> typingAny: ... + def __abs__(self) -> typingAny: ... + def __add__(self, other: typingAny) -> typingAny: ... + def __sub__(self, other: typingAny) -> typingAny: ... + def __mul__(self, other: typingAny) -> typingAny: ... + def __div__(self, other: typingAny) -> typingAny: ... + def __truediv__(self, other: typingAny) -> typingAny: ... + def __pow__(self, other: typingAny) -> typingAny: ... + def __radd__(self, other: typingAny) -> typingAny: ... + def __rsub__(self, other: typingAny) -> typingAny: ... + def __rmul__(self, other: typingAny) -> typingAny: ... + def __rdiv__(self, other: typingAny) -> typingAny: ... + def __rtruediv__(self, other: typingAny) -> typingAny: ... + def __rpow__(self, other: typingAny) -> typingAny: ... + +class ScalarExpression(ExpressionData, Expression): + def __init__(self, *args, **kwds) -> None: ... + def __call__(self, exception=...): ... + @property + def expr(self): ... + @expr.setter + def expr(self, expr) -> None: ... + def clear(self) -> None: ... + def set_value(self, expr): ... + def is_constant(self): ... + def is_fixed(self): ... + def add(self, index, expr): ... + +class SimpleExpression(metaclass=RenamedClass): + __renamed__new_class__ = ScalarExpression + __renamed__version__: str + +class IndexedExpression(Expression): + def add(self, index, expr): ... diff --git a/stubs/pyomo/core/base/external.pyi b/stubs/pyomo/core/base/external.pyi new file mode 100644 index 000000000..4f917079b --- /dev/null +++ b/stubs/pyomo/core/base/external.pyi @@ -0,0 +1,63 @@ +from ctypes import Structure + +from _typeshed import Incomplete +from pyomo.common.autoslots import AutoSlots as AutoSlots +from pyomo.common.fileutils import find_library as find_library +from pyomo.common.numeric_types import check_if_native_type as check_if_native_type +from pyomo.common.numeric_types import native_numeric_types as native_numeric_types +from pyomo.common.numeric_types import native_types as native_types +from pyomo.common.numeric_types import value as value +from pyomo.common.pyomo_typing import overload as overload +from pyomo.core.base.component import Component as Component +from pyomo.core.base.units_container import units as units +from pyomo.core.expr.numvalue import NonNumericValue as NonNumericValue +from pyomo.core.expr.numvalue import NumericConstant as NumericConstant + +logger: Incomplete +nan: Incomplete + +class ExternalFunction(Component): + def __new__(cls, *args, **kwargs): ... + def get_units(self): ... + def get_arg_units(self): ... + def __call__(self, *args): ... + def evaluate(self, args): ... + def evaluate_fgh(self, args, fixed=None, fgh: int = 2): ... + +class AMPLExternalFunction(ExternalFunction): + __autoslot_mappers__: Incomplete + def __init__(self, *args, **kwargs) -> None: ... + def load_library(self) -> None: ... + +class _PythonCallbackFunctionID(NumericConstant): + __autoslot_mappers__: Incomplete + def is_constant(self): ... + +class PythonCallbackFunction(ExternalFunction): + __autoslot_mappers__: Incomplete + global_registry: Incomplete + global_id_to_fid: Incomplete + @classmethod + def register_instance(cls, instance): ... + def __init__(self, *args, **kwargs) -> None: ... + def __call__(self, *args): ... + +class _ARGLIST(Structure): + n: Incomplete + at: Incomplete + nr: Incomplete + ra: Incomplete + sa: Incomplete + derivs: Incomplete + hes: Incomplete + dig: Incomplete + def __init__(self, args, fgh: int = 0, fixed=None) -> None: ... + +class _AMPLEXPORTS(Structure): ... + +class _AMPLEXPORTS(Structure): + AMPLFUNC: Incomplete + ADDFUNC: Incomplete + RANDSEEDSETTER: Incomplete + ADDRANDINIT: Incomplete + ATRESET: Incomplete diff --git a/stubs/pyomo/core/base/global_set.pyi b/stubs/pyomo/core/base/global_set.pyi new file mode 100644 index 000000000..e495ae697 --- /dev/null +++ b/stubs/pyomo/core/base/global_set.pyi @@ -0,0 +1,51 @@ +from collections.abc import Generator + +from _typeshed import Incomplete +from pyomo.core.base.range import NonNumericRange as NonNumericRange +from pyomo.core.pyomoobject import PyomoObject as PyomoObject + +GlobalSets: Incomplete + +class GlobalSetBase(PyomoObject): + def __reduce__(self): ... + def __deepcopy__(self, memo): ... + +class _UnindexedComponent_set(GlobalSetBase): + local_name: str + name: Incomplete + def __init__(self, name) -> None: ... + def __contains__(self, val) -> bool: ... + def get(self, value, default): ... + def __iter__(self): ... + def __reversed__(self): ... + def ordered_iter(self): ... + def sorted_iter(self): ... + def data(self): ... + def ordered_data(self): ... + def sorted_data(self): ... + def subsets(self, expand_all_set_operators=None): ... + def construct(self) -> None: ... + def ranges(self) -> Generator[Incomplete]: ... + def bounds(self): ... + def get_interval(self): ... + def __len__(self) -> int: ... + def __eq__(self, other): ... + def __ne__(self, other): ... + @property + def dimen(self): ... + def isdiscrete(self): ... + def isfinite(self): ... + def isordered(self): ... + def at(self, index) -> None: ... + def ord(self, item): ... + def first(self) -> None: ... + def last(self) -> None: ... + def next(self, item, step: int = 1) -> None: ... + def nextw(self, item, step: int = 1) -> None: ... + def prev(self, item, step: int = 1): ... + def prevw(self, item, step: int = 1): ... + def parent_block(self) -> None: ... + def parent_component(self): ... + +UnindexedComponent_set: Incomplete +UnindexedComponent_index: Incomplete diff --git a/stubs/pyomo/core/base/indexed_component.pyi b/stubs/pyomo/core/base/indexed_component.pyi new file mode 100644 index 000000000..99cca95e2 --- /dev/null +++ b/stubs/pyomo/core/base/indexed_component.pyi @@ -0,0 +1,65 @@ +from _typeshed import Incomplete +from pyomo.common import DeveloperError as DeveloperError +from pyomo.common.autoslots import fast_deepcopy as fast_deepcopy +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.common.errors import TemplateExpressionError as TemplateExpressionError +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.common.numeric_types import native_types as native_types +from pyomo.common.sorting import sorted_robust as sorted_robust +from pyomo.core.base.component import ActiveComponent as ActiveComponent +from pyomo.core.base.component import Component as Component +from pyomo.core.base.component import ComponentData as ComponentData +from pyomo.core.base.config import PyomoOptions as PyomoOptions +from pyomo.core.base.enums import SortComponents as SortComponents +from pyomo.core.base.global_set import UnindexedComponent_set as UnindexedComponent_set +from pyomo.core.base.indexed_component_slice import IndexedComponent_slice as IndexedComponent_slice +from pyomo.core.base.initializer import Initializer as Initializer +from pyomo.core.pyomoobject import PyomoObject as PyomoObject + +logger: Incomplete +sequence_types: Incomplete +slicer_types: Incomplete + +def normalize_index(x): ... + +class _NotFound: ... +class _NotSpecified: ... + +def rule_result_substituter(result_map, map_types): ... +def rule_wrapper(rule, wrapping_fcn, positional_arg_map=None, map_types=None): ... + +class IndexedComponent(Component): + class Skip: ... + + def __init__(self, *args, **kwds) -> None: ... + def to_dense_data(self) -> None: ... + def clear(self) -> None: ... + def index_set(self): ... + def is_indexed(self): ... + def is_reference(self): ... + def dim(self): ... + def __len__(self) -> int: ... + def __contains__(self, idx) -> bool: ... + def __iter__(self): ... + def keys(self, sort=..., ordered=...): ... + def values(self, sort=..., ordered=...): ... + def items(self, sort=..., ordered=...): ... + def iterkeys(self): ... + def itervalues(self): ... + def iteritems(self): ... + def __getitem__(self, index) -> ComponentData: ... + def __setitem__(self, index, val) -> None: ... + def __delitem__(self, index) -> None: ... + def set_value(self, value) -> None: ... + def id_index_map(self): ... + +class ActiveIndexedComponent(IndexedComponent, ActiveComponent): + def __init__(self, *args, **kwds) -> None: ... + def activate(self) -> None: ... + def deactivate(self) -> None: ... + +class IndexedComponent_NDArrayMixin: + def __array__(self, dtype=None): ... + def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): ... diff --git a/stubs/pyomo/core/base/indexed_component_slice.pyi b/stubs/pyomo/core/base/indexed_component_slice.pyi new file mode 100644 index 000000000..d0141fcac --- /dev/null +++ b/stubs/pyomo/core/base/indexed_component_slice.pyi @@ -0,0 +1,67 @@ +from _typeshed import Incomplete +from pyomo.common import DeveloperError as DeveloperError +from pyomo.common.collections import Sequence as Sequence +from pyomo.core.base.enums import SortComponents as SortComponents +from pyomo.core.base.global_set import UnindexedComponent_index as UnindexedComponent_index + +class IndexedComponent_slice: + ATTR_MASK: int + ITEM_MASK: int + CALL_MASK: int + GET_MASK: int + SET_MASK: int + DEL_MASK: int + slice_info: int + get_attribute = ATTR_MASK | GET_MASK + set_attribute = ATTR_MASK | SET_MASK + del_attribute = ATTR_MASK | DEL_MASK + get_item = ITEM_MASK | GET_MASK + set_item = ITEM_MASK | SET_MASK + del_item = ITEM_MASK | DEL_MASK + call = CALL_MASK + def __init__(self, component, fixed=None, sliced=None, ellipsis=None) -> None: ... + def __deepcopy__(self, memo): ... + def __iter__(self): ... + def __getattr__(self, name): ... + def __setattr__(self, name, value): ... + def __getitem__(self, idx): ... + def __setitem__(self, idx, val) -> None: ... + def __delitem__(self, idx) -> None: ... + def __call__(self, *args, **kwds): ... + def __hash__(self): ... + def __eq__(self, other): ... + def __ne__(self, other): ... + def duplicate(self): ... + def index_wildcard_keys(self, sort): ... + def wildcard_keys(self, sort=...): ... + def wildcard_values(self, sort=...): ... + def wildcard_items(self, sort=...): ... + def expanded_keys(self): ... + def expanded_items(self): ... + +class _slice_generator: + component: Incomplete + fixed: Incomplete + sliced: Incomplete + ellipsis: Incomplete + iter_over_index: Incomplete + last_index: Incomplete + tuplize_unflattened_index: Incomplete + explicit_index_count: int + component_iter: Incomplete + def __init__(self, component, fixed, sliced, ellipsis, iter_over_index, sort) -> None: ... + def next(self): ... + def __next__(self): ... + +class _NotIterable: ... + +class _IndexedComponent_slice_iter: + advance_iter: Incomplete + def __init__( + self, component_slice, advance_iter=..., iter_over_index: bool = False, sort: bool = False + ) -> None: ... + def __iter__(self): ... + def next(self): ... + def __next__(self): ... + def get_last_index(self): ... + def get_last_index_wildcards(self): ... diff --git a/stubs/pyomo/core/base/initializer.pyi b/stubs/pyomo/core/base/initializer.pyi new file mode 100644 index 000000000..a5712dd64 --- /dev/null +++ b/stubs/pyomo/core/base/initializer.pyi @@ -0,0 +1,92 @@ +from _typeshed import Incomplete +from pyomo.common.autoslots import AutoSlots as AutoSlots +from pyomo.common.dependencies import numpy as numpy +from pyomo.common.dependencies import numpy_available as numpy_available +from pyomo.common.dependencies import pandas as pandas +from pyomo.common.dependencies import pandas_available as pandas_available +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.core.pyomoobject import PyomoObject as PyomoObject + +initializer_map: Incomplete +sequence_types: Incomplete +function_types: Incomplete + +def Initializer( + arg, + allow_generators: bool = False, + treat_sequences_as_mappings: bool = True, + arg_not_specified=None, + additional_args: int = 0, +): ... + +class InitializerBase(AutoSlots.Mixin): + verified: bool + def constant(self): ... + def contains_indices(self): ... + def indices(self) -> None: ... + +class ConstantInitializer(InitializerBase): + val: Incomplete + verified: bool + def __init__(self, val) -> None: ... + def __call__(self, parent, idx): ... + def constant(self): ... + +class ItemInitializer(InitializerBase): + def __init__(self, _dict) -> None: ... + def __call__(self, parent, idx): ... + def contains_indices(self): ... + def indices(self): ... + +class DataFrameInitializer(InitializerBase): + def __init__(self, dataframe, column=None) -> None: ... + def __call__(self, parent, idx): ... + def contains_indices(self): ... + def indices(self): ... + +class IndexedCallInitializer(InitializerBase): + def __init__(self, _fcn) -> None: ... + def __call__(self, parent, idx): ... + +class ParameterizedIndexedCallInitializer(IndexedCallInitializer): + def __call__(self, parent, idx, *args): ... + +class CountedCallGenerator: + def __init__(self, ctype, fcn, scalar, parent, idx, start_at) -> None: ... + def __iter__(self): ... + def __next__(self): ... + next = __next__ + +class CountedCallInitializer(InitializerBase): + def __init__(self, obj, _indexed_init, starting_index: int = 1) -> None: ... + def __call__(self, parent, idx): ... + +class ScalarCallInitializer(InitializerBase): + def __init__(self, _fcn, constant: bool = True) -> None: ... + def __call__(self, parent, idx): ... + def constant(self): ... + +class ParameterizedScalarCallInitializer(ScalarCallInitializer): + def __call__(self, parent, idx, *args): ... + +class DefaultInitializer(InitializerBase): + def __init__(self, initializer, default, exceptions) -> None: ... + def __call__(self, parent, index): ... + def constant(self): ... + def contains_indices(self): ... + def indices(self): ... + +class ParameterizedInitializer(InitializerBase): + def __init__(self, base) -> None: ... + def constant(self): ... + def contains_indices(self): ... + def indices(self): ... + def __call__(self, parent, idx, *args): ... + +class BoundInitializer(InitializerBase): + def __new__(cls, arg=None, obj=...): ... + def __init__(self, arg, obj=...) -> None: ... + def __call__(self, parent, index): ... + def constant(self): ... + def contains_indices(self): ... + def indices(self): ... diff --git a/stubs/pyomo/core/base/instance2dat.pyi b/stubs/pyomo/core/base/instance2dat.pyi new file mode 100644 index 000000000..cfb5fa593 --- /dev/null +++ b/stubs/pyomo/core/base/instance2dat.pyi @@ -0,0 +1,5 @@ +from pyomo.core.base import Param as Param +from pyomo.core.base import Set as Set +from pyomo.core.base import value as value + +def instance2dat(instance, output_filename) -> None: ... diff --git a/stubs/pyomo/core/base/label.pyi b/stubs/pyomo/core/base/label.pyi new file mode 100644 index 000000000..51ec93d0e --- /dev/null +++ b/stubs/pyomo/core/base/label.pyi @@ -0,0 +1,63 @@ +from _typeshed import Incomplete +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.core.base.componentuid import ComponentUID as ComponentUID + +class _CharMapper: + table: Incomplete + other: Incomplete + def __init__(self, preserve, translate, other) -> None: ... + def __getitem__(self, c): ... + def make_table(self): ... + +def cpxlp_label_from_name(name): ... +def alphanum_label_from_name(name): ... + +class CuidLabeler: + def __call__(self, obj=None): ... + +class CounterLabeler: + def __init__(self, start: int = 0) -> None: ... + def __call__(self, obj=None): ... + +class NumericLabeler: + id: Incomplete + prefix: Incomplete + def __init__(self, prefix, start: int = 0) -> None: ... + def __call__(self, obj=None): ... + def remove_obj(self, obj) -> None: ... + +class CNameLabeler: + def __call__(self, obj): ... + +class LPFileLabeler: + def __call__(self, obj): ... + def remove_obj(self, obj) -> None: ... + +TextLabeler = LPFileLabeler + +class AlphaNumericTextLabeler: + def __call__(self, obj): ... + +class NameLabeler: + def __call__(self, obj): ... + +class ShortNameLabeler: + id: Incomplete + prefix: Incomplete + suffix: Incomplete + limit: Incomplete + labeler: Incomplete + known_labels: Incomplete + caseInsensitive: Incomplete + legalRegex: Incomplete + def __init__( + self, + limit, + suffix, + start: int = 0, + labeler=None, + prefix: str = '', + caseInsensitive: bool = False, + legalRegex=None, + ) -> None: ... + def __call__(self, obj=None): ... diff --git a/stubs/pyomo/core/base/logical_constraint.pyi b/stubs/pyomo/core/base/logical_constraint.pyi new file mode 100644 index 000000000..7d5793758 --- /dev/null +++ b/stubs/pyomo/core/base/logical_constraint.pyi @@ -0,0 +1,69 @@ +from _typeshed import Incomplete +from pyomo.common.deprecation import RenamedClass as RenamedClass +from pyomo.common.formatting import tabular_writer as tabular_writer +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.common.timing import ConstructionTimer as ConstructionTimer +from pyomo.core.base.component import ActiveComponentData as ActiveComponentData +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.global_set import UnindexedComponent_index as UnindexedComponent_index +from pyomo.core.base.indexed_component import ActiveIndexedComponent as ActiveIndexedComponent +from pyomo.core.base.indexed_component import UnindexedComponent_set as UnindexedComponent_set +from pyomo.core.base.misc import apply_indexed_rule as apply_indexed_rule +from pyomo.core.base.set import Set as Set +from pyomo.core.expr.boolean_value import BooleanConstant as BooleanConstant +from pyomo.core.expr.boolean_value import as_boolean as as_boolean +from pyomo.core.expr.numvalue import native_logical_types as native_logical_types +from pyomo.core.expr.numvalue import native_types as native_types + +logger: Incomplete + +class LogicalConstraintData(ActiveComponentData): + def __init__(self, expr=None, component=None) -> None: ... + def __call__(self, exception=...): ... + @property + def body(self): ... + @property + def expr(self): ... + def set_value(self, expr) -> None: ... + def get_value(self): ... + +class _LogicalConstraintData(metaclass=RenamedClass): + __renamed__new_class__ = LogicalConstraintData + __renamed__version__: str + +class _GeneralLogicalConstraintData(metaclass=RenamedClass): + __renamed__new_class__ = LogicalConstraintData + __renamed__version__: str + +class LogicalConstraint(ActiveIndexedComponent): + class Infeasible: ... + Feasible: Incomplete + NoConstraint: Incomplete + Violated = Infeasible + Satisfied = Feasible + def __new__(cls, *args, **kwds): ... + rule: Incomplete + def __init__(self, *args, **kwargs) -> None: ... + def construct(self, data=None) -> None: ... + def display(self, prefix: str = '', ostream=None): ... + +class ScalarLogicalConstraint(LogicalConstraintData, LogicalConstraint): + def __init__(self, *args, **kwds) -> None: ... + @property + def body(self): ... + def set_value(self, expr): ... + def add(self, index, expr): ... + +class SimpleLogicalConstraint(metaclass=RenamedClass): + __renamed__new_class__ = ScalarLogicalConstraint + __renamed__version__: str + +class IndexedLogicalConstraint(LogicalConstraint): + def add(self, index, expr): ... + +class LogicalConstraintList(IndexedLogicalConstraint): + End: Incomplete + def __init__(self, **kwargs) -> None: ... + def construct(self, data=None) -> None: ... + def add(self, expr): ... diff --git a/stubs/pyomo/core/base/matrix_constraint.pyi b/stubs/pyomo/core/base/matrix_constraint.pyi new file mode 100644 index 000000000..08cafabe1 --- /dev/null +++ b/stubs/pyomo/core/base/matrix_constraint.pyi @@ -0,0 +1,49 @@ +from collections.abc import Mapping + +from _typeshed import Incomplete +from pyomo.common.gc_manager import PauseGC as PauseGC +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.constraint import ConstraintData as ConstraintData +from pyomo.core.base.constraint import IndexedConstraint as IndexedConstraint +from pyomo.core.base.set_types import Any as Any +from pyomo.core.expr.numeric_expr import LinearExpression as LinearExpression +from pyomo.core.expr.numvalue import value as value +from pyomo.repn.standard_repn import StandardRepn as StandardRepn + +logger: Incomplete + +class _MatrixConstraintData(ConstraintData): + def canonical_form(self, compute_values: bool = True): ... + def __init__(self, index, component_ref) -> None: ... + def __call__(self, exception=...): ... + def has_lb(self): ... + def has_ub(self): ... + def lslack(self): ... + def uslack(self): ... + def slack(self): ... + def index(self): ... + @property + def body(self): ... + @property + def lower(self): ... + @property + def upper(self): ... + @property + def equality(self): ... + @property + def strict_lower(self): ... + @property + def strict_upper(self): ... + def set_value(self, expr) -> None: ... + +class MatrixConstraint(Mapping, IndexedConstraint): + def __init__(self, A_data, A_indices, A_indptr, lb, ub, x) -> None: ... + def construct(self, data=None) -> None: ... + def __getitem__(self, key): ... + def __len__(self) -> int: ... + def __iter__(self): ... + def add(self, index, expr) -> None: ... + def __delitem__(self) -> None: ... + def __setitem__(self, key, value) -> None: ... diff --git a/stubs/pyomo/core/base/misc.pyi b/stubs/pyomo/core/base/misc.pyi new file mode 100644 index 000000000..64e9b18e3 --- /dev/null +++ b/stubs/pyomo/core/base/misc.pyi @@ -0,0 +1,9 @@ +from _typeshed import Incomplete +from pyomo.common.deprecation import relocated_module_attribute as relocated_module_attribute + +logger: Incomplete + +def display(obj, ostream=None) -> None: ... +def create_name(name, ndx): ... +def apply_indexed_rule(obj, rule, model, index, options=None): ... +def apply_parameterized_indexed_rule(obj, rule, model, param, index): ... diff --git a/stubs/pyomo/core/base/numvalue.pyi b/stubs/pyomo/core/base/numvalue.pyi new file mode 100644 index 000000000..22e2f61a8 --- /dev/null +++ b/stubs/pyomo/core/base/numvalue.pyi @@ -0,0 +1,43 @@ +from _typeshed import Incomplete +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.common.deprecation import relocated_module_attribute as relocated_module_attribute +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.common.numeric_types import check_if_numeric_type as check_if_numeric_type +from pyomo.common.numeric_types import native_integer_types as native_integer_types +from pyomo.common.numeric_types import native_logical_types as native_logical_types +from pyomo.common.numeric_types import native_numeric_types as native_numeric_types +from pyomo.common.numeric_types import native_types as native_types +from pyomo.common.numeric_types import nonpyomo_leaf_types as nonpyomo_leaf_types +from pyomo.common.numeric_types import value as value +from pyomo.core.expr.expr_common import ExpressionType as ExpressionType +from pyomo.core.expr.numeric_expr import NumericValue as NumericValue +from pyomo.core.pyomoobject import PyomoObject as PyomoObject + +logger: Incomplete + +class NonNumericValue(PyomoObject): + value: Incomplete + def __init__(self, value) -> None: ... + def __call__(self, exception=...): ... + def is_constant(self): ... + def is_fixed(self): ... + +def is_constant(obj): ... +def is_fixed(obj): ... +def is_variable_type(obj): ... +def is_potentially_variable(obj): ... +def is_numeric_data(obj): ... +def polynomial_degree(obj): ... +def as_numeric(obj): ... +def check_if_numeric_type_and_cache(obj): ... + +class NumericConstant(NumericValue): + value: Incomplete + def __init__(self, value) -> None: ... + def is_constant(self): ... + def is_fixed(self): ... + def __call__(self, exception=...): ... + def pprint(self, ostream=None, verbose: bool = False) -> None: ... + +ZeroConstant: Incomplete diff --git a/stubs/pyomo/core/base/objective.pyi b/stubs/pyomo/core/base/objective.pyi new file mode 100644 index 000000000..c2454742e --- /dev/null +++ b/stubs/pyomo/core/base/objective.pyi @@ -0,0 +1,92 @@ +from _typeshed import Incomplete +from pyomo.common.deprecation import RenamedClass as RenamedClass +from pyomo.common.enums import ObjectiveSense as ObjectiveSense +from pyomo.common.enums import maximize as maximize +from pyomo.common.enums import minimize as minimize +from pyomo.common.errors import TemplateExpressionError as TemplateExpressionError +from pyomo.common.formatting import tabular_writer as tabular_writer +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.common.pyomo_typing import overload as overload +from pyomo.common.timing import ConstructionTimer as ConstructionTimer +from pyomo.core.base.component import ActiveComponentData as ActiveComponentData +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.expression import NamedExpressionData as NamedExpressionData +from pyomo.core.base.global_set import UnindexedComponent_index as UnindexedComponent_index +from pyomo.core.base.indexed_component import ActiveIndexedComponent as ActiveIndexedComponent +from pyomo.core.base.indexed_component import UnindexedComponent_set as UnindexedComponent_set +from pyomo.core.base.indexed_component import rule_wrapper as rule_wrapper +from pyomo.core.base.initializer import CountedCallInitializer as CountedCallInitializer +from pyomo.core.base.initializer import IndexedCallInitializer as IndexedCallInitializer +from pyomo.core.base.initializer import Initializer as Initializer +from pyomo.core.base.set import Set as Set +from pyomo.core.expr.numvalue import value as value +from pyomo.core.expr.template_expr import templatize_rule as templatize_rule + +logger: Incomplete +TEMPLATIZE_OBJECTIVES: bool + +def simple_objective_rule(rule): ... +def simple_objectivelist_rule(rule): ... + +class ObjectiveData(NamedExpressionData, ActiveComponentData): + def __init__(self, expr=None, sense=..., component=None) -> None: ... + def is_minimizing(self): ... + def set_value(self, expr): ... + @property + def sense(self): ... + @sense.setter + def sense(self, sense) -> None: ... + def set_sense(self, sense) -> None: ... + +class _ObjectiveData(metaclass=RenamedClass): + __renamed__new_class__ = ObjectiveData + __renamed__version__: str + +class _GeneralObjectiveData(metaclass=RenamedClass): + __renamed__new_class__ = ObjectiveData + __renamed__version__: str + +class TemplateObjectiveData(ObjectiveData): + def __init__(self, template_info, component, index, sense) -> None: ... + @property + def args(self): ... + def template_expr(self): ... + __class__: Incomplete + def set_value(self, expr): ... + +class Objective(ActiveIndexedComponent): + NoObjective: Incomplete + def __new__(cls, *args, **kwds): ... + def construct(self, data=None) -> None: ... + def display(self, prefix: str = '', ostream=None): ... + +class ScalarObjective(ObjectiveData, Objective): + def __init__(self, *args, **kwd) -> None: ... + def __call__(self, exception=...): ... + @property + def expr(self): ... + @expr.setter + def expr(self, expr) -> None: ... + @property + def sense(self): ... + @sense.setter + def sense(self, sense) -> None: ... + def clear(self) -> None: ... + def set_value(self, expr): ... + def set_sense(self, sense): ... + def add(self, index, expr): ... + +class SimpleObjective(metaclass=RenamedClass): + __renamed__new_class__ = ScalarObjective + __renamed__version__: str + +class IndexedObjective(Objective): + def add(self, index, expr): ... + +class ObjectiveList(IndexedObjective): + class End: ... + rule: Incomplete + def __init__(self, **kwargs) -> None: ... + def construct(self, data=None) -> None: ... + def add(self, expr, sense=...): ... diff --git a/stubs/pyomo/core/base/param.pyi b/stubs/pyomo/core/base/param.pyi new file mode 100644 index 000000000..8f60ebf1a --- /dev/null +++ b/stubs/pyomo/core/base/param.pyi @@ -0,0 +1,90 @@ +from _typeshed import Incomplete +from pyomo.common.autoslots import AutoSlots as AutoSlots +from pyomo.common.deprecation import RenamedClass as RenamedClass +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.common.numeric_types import native_types as native_types +from pyomo.common.pyomo_typing import overload as overload +from pyomo.common.timing import ConstructionTimer as ConstructionTimer +from pyomo.core.base.component import ComponentData as ComponentData +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.global_set import UnindexedComponent_index as UnindexedComponent_index +from pyomo.core.base.indexed_component import IndexedComponent as IndexedComponent +from pyomo.core.base.indexed_component import ( + IndexedComponent_NDArrayMixin as IndexedComponent_NDArrayMixin, +) +from pyomo.core.base.indexed_component import UnindexedComponent_set as UnindexedComponent_set +from pyomo.core.base.initializer import Initializer as Initializer +from pyomo.core.base.misc import apply_indexed_rule as apply_indexed_rule +from pyomo.core.base.misc import ( + apply_parameterized_indexed_rule as apply_parameterized_indexed_rule, +) +from pyomo.core.base.set import Reals as Reals +from pyomo.core.base.set import SetInitializer as SetInitializer +from pyomo.core.base.set import _AnySet +from pyomo.core.base.units_container import units as units +from pyomo.core.expr import GetItemExpression as GetItemExpression +from pyomo.core.expr.numvalue import NumericValue as NumericValue + +logger: Incomplete + +class _ImplicitAny(_AnySet): + __autoslot_mappers__: Incomplete + def __new__(cls, **kwargs): ... + def __init__(self, owner, **kwargs) -> None: ... + def __contains__(self, val) -> bool: ... + def getname(self, fully_qualified: bool = False, name_buffer=None, relative_to=None): ... + +class ParamData(ComponentData, NumericValue): + def __init__(self, component) -> None: ... + def clear(self) -> None: ... + def set_value(self, value, idx=...) -> None: ... + def __call__(self, exception=...): ... + @property + def value(self): ... + @value.setter + def value(self, val) -> None: ... + def get_units(self): ... + def is_fixed(self): ... + def is_constant(self): ... + def is_parameter_type(self): ... + +class _ParamData(metaclass=RenamedClass): + __renamed__new_class__ = ParamData + __renamed__version__: str + +class Param(IndexedComponent, IndexedComponent_NDArrayMixin): + DefaultMutable: bool + class NoValue: ... + + def __len__(self) -> int: ... + def __contains__(self, idx) -> bool: ... + @property + def mutable(self): ... + def get_units(self): ... + def sparse_keys(self): ... + def sparse_values(self): ... + def sparse_items(self): ... + def sparse_iterkeys(self): ... + def sparse_itervalues(self): ... + def sparse_iteritems(self): ... + def extract_values(self): ... + def extract_values_sparse(self): ... + def store_values(self, new_values, check: bool = True) -> None: ... + def set_default(self, val) -> None: ... + def default(self): ... + def construct(self, data=None) -> None: ... + +class ScalarParam(ParamData, Param): + def __init__(self, *args, **kwds) -> None: ... + def __call__(self, exception=...): ... + def set_value(self, value, index=...) -> None: ... + def is_constant(self): ... + +class SimpleParam(metaclass=RenamedClass): + __renamed__new_class__ = ScalarParam + __renamed__version__: str + +class IndexedParam(Param): + def __getitem__(self, args) -> ParamData: ... diff --git a/stubs/pyomo/core/base/piecewise.pyi b/stubs/pyomo/core/base/piecewise.pyi new file mode 100644 index 000000000..0f8c426ef --- /dev/null +++ b/stubs/pyomo/core/base/piecewise.pyi @@ -0,0 +1,95 @@ +import enum + +from _typeshed import Incomplete +from pyomo.common.deprecation import RenamedClass as RenamedClass +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.numeric_types import value as value +from pyomo.common.timing import ConstructionTimer as ConstructionTimer +from pyomo.core.base.block import Block as Block +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.constraint import Constraint as Constraint +from pyomo.core.base.constraint import ConstraintList as ConstraintList +from pyomo.core.base.set_types import Binary as Binary +from pyomo.core.base.set_types import NonNegativeReals as NonNegativeReals +from pyomo.core.base.set_types import PositiveReals as PositiveReals +from pyomo.core.base.sos import SOSConstraint as SOSConstraint +from pyomo.core.base.util import flatten_tuple as flatten_tuple +from pyomo.core.base.var import IndexedVar as IndexedVar +from pyomo.core.base.var import Var as Var +from pyomo.core.base.var import VarData as VarData + +logger: Incomplete + +class PWRepn(str, enum.Enum): + SOS2 = 'SOS2' + BIGM_BIN = 'BIGM_BIN' + BIGM_SOS1 = 'BIGM_SOS1' + CC = 'CC' + DCC = 'DCC' + DLOG = 'DLOG' + LOG = 'LOG' + MC = 'MC' + INC = 'INC' + +class Bound(str, enum.Enum): + Lower = 'Lower' + Upper = 'Upper' + Equal = 'Equal' + +class PiecewiseData(BlockData): + def __init__(self, parent) -> None: ... + def updateBoundType(self, bound_type) -> None: ... + def updatePoints(self, domain_pts, range_pts) -> None: ... + def build_constraints(self, functor, x_var, y_var) -> None: ... + def referenced_variables(self): ... + def __call__(self, x): ... + +class _PiecewiseData(metaclass=RenamedClass): + __renamed__new_class__ = PiecewiseData + __renamed__version__: str + +class _SimpleSinglePiecewise: + def construct(self, pblock, x_var, y_var) -> None: ... + +class _SimplifiedPiecewise: + def construct(self, pblock, x_var, y_var) -> None: ... + +class _SOS2Piecewise: + def construct(self, pblock, x_var, y_var): ... + +class _DCCPiecewise: + def construct(self, pblock, x_var, y_var): ... + +class _DLOGPiecewise: + def construct(self, pblock, x_var, y_var): ... + +class _CCPiecewise: + def construct(self, pblock, x_var, y_var): ... + +class _LOGPiecewise: + def construct(self, pblock, x_var, y_var): ... + +class _MCPiecewise: + def construct(self, pblock, x_var, y_var): ... + +class _INCPiecewise: + def construct(self, pblock, x_var, y_var): ... + +class _BIGMPiecewise: + binary: Incomplete + def __init__(self, binary: bool = True) -> None: ... + def construct(self, pblock, x_var, y_var): ... + +class Piecewise(Block): + def __new__(cls, *args, **kwds): ... + def __init__(self, *args, **kwds) -> None: ... + def construct(self, *args, **kwds) -> None: ... + def add(self, index, _is_indexed=None) -> None: ... + +class SimplePiecewise(PiecewiseData, Piecewise): + def __init__(self, *args, **kwds) -> None: ... + +class IndexedPiecewise(Piecewise): + def __init__(self, *args, **kwds) -> None: ... diff --git a/stubs/pyomo/core/base/range.pyi b/stubs/pyomo/core/base/range.pyi new file mode 100644 index 000000000..3f77df4d4 --- /dev/null +++ b/stubs/pyomo/core/base/range.pyi @@ -0,0 +1,60 @@ +from _typeshed import Incomplete +from pyomo.common.autoslots import AutoSlots as AutoSlots +from pyomo.common.numeric_types import check_if_numeric_type as check_if_numeric_type + +class RangeDifferenceError(ValueError): ... + +class NumericRange(AutoSlots.Mixin): + start: Incomplete + end: Incomplete + step: Incomplete + closed: Incomplete + def __init__(self, start, end, step, closed=(True, True)) -> None: ... + def __eq__(self, other): ... + def __ne__(self, other): ... + def __contains__(self, value) -> bool: ... + def isdiscrete(self): ... + def isfinite(self): ... + def isdisjoint(self, other): ... + def issubset(self, other): ... + def normalize_bounds(self): ... + def range_difference(self, other_ranges): ... + def range_intersection(self, other_ranges): ... + +class NonNumericRange: + value: Incomplete + def __init__(self, val) -> None: ... + def __eq__(self, other): ... + def __ne__(self, other): ... + def __contains__(self, value) -> bool: ... + def isdiscrete(self): ... + def isfinite(self): ... + def isdisjoint(self, other): ... + def issubset(self, other): ... + def range_difference(self, other_ranges): ... + def range_intersection(self, other_ranges): ... + +class AnyRange: + def __init__(self) -> None: ... + def __eq__(self, other): ... + def __ne__(self, other): ... + def __contains__(self, value) -> bool: ... + def isdiscrete(self): ... + def isfinite(self): ... + def isdisjoint(self, other): ... + def issubset(self, other): ... + def range_difference(self, other_ranges): ... + def range_intersection(self, other_ranges): ... + +class RangeProduct: + range_lists: Incomplete + def __init__(self, range_lists) -> None: ... + def __eq__(self, other): ... + def __ne__(self, other): ... + def __contains__(self, value) -> bool: ... + def isdiscrete(self): ... + def isfinite(self): ... + def isdisjoint(self, other): ... + def issubset(self, other): ... + def range_difference(self, other_ranges): ... + def range_intersection(self, other_ranges): ... diff --git a/stubs/pyomo/core/base/reference.pyi b/stubs/pyomo/core/base/reference.pyi new file mode 100644 index 000000000..32d9aea34 --- /dev/null +++ b/stubs/pyomo/core/base/reference.pyi @@ -0,0 +1,64 @@ +from _typeshed import Incomplete +from pyomo.common import DeveloperError as DeveloperError +from pyomo.common.collections import Mapping as Mapping +from pyomo.common.collections import MutableMapping as MutableMapping +from pyomo.common.collections import Sequence as Sequence +from pyomo.common.collections import Set as collections_Set +from pyomo.common.collections import UserDict as UserDict +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.core.base.component import Component as Component +from pyomo.core.base.component import ComponentData as ComponentData +from pyomo.core.base.enums import SortComponents as SortComponents +from pyomo.core.base.global_set import UnindexedComponent_set as UnindexedComponent_set +from pyomo.core.base.indexed_component import IndexedComponent as IndexedComponent +from pyomo.core.base.indexed_component import normalize_index as normalize_index +from pyomo.core.base.indexed_component_slice import IndexedComponent_slice as IndexedComponent_slice +from pyomo.core.base.set import DeclareGlobalSet as DeclareGlobalSet +from pyomo.core.base.set import OrderedSetOf as OrderedSetOf +from pyomo.core.base.set import Set as Set +from pyomo.core.base.set import SetData as SetData +from pyomo.core.base.set import SetOf as SetOf +from pyomo.core.base.util import flatten_tuple as flatten_tuple + +class _fill_in_known_wildcards: + base_key: Incomplete + key: Incomplete + known_slices: Incomplete + look_in_index: Incomplete + get_if_not_present: Incomplete + def __init__( + self, wildcard_values, look_in_index: bool = False, get_if_not_present: bool = False + ) -> None: ... + def __call__(self, _slice): ... + def check_complete(self) -> None: ... + +class SliceEllipsisLookupError(LookupError): ... + +class _ReferenceDict(MutableMapping): + def __init__(self, component_slice) -> None: ... + def __contains__(self, key) -> bool: ... + def __getitem__(self, key): ... + def __setitem__(self, key, val) -> None: ... + def __delitem__(self, key) -> None: ... + def __iter__(self): ... + def __len__(self) -> int: ... + def keys(self, sort=...): ... + def items(self, sort=...): ... + def values(self, sort=...): ... + def iteritems(self): ... + def itervalues(self): ... + +class _ReferenceDict_mapping(UserDict): + data: Incomplete + def __init__(self, data) -> None: ... + +class _ReferenceSet(collections_Set): + def __init__(self, component_slice) -> None: ... + def __contains__(self, key) -> bool: ... + def __iter__(self): ... + def __len__(self) -> int: ... + def ordered_iter(self): ... + def sorted_iter(self): ... + +def Reference(reference, ctype=...): ... diff --git a/stubs/pyomo/core/base/set.pyi b/stubs/pyomo/core/base/set.pyi new file mode 100644 index 000000000..98978b8fb --- /dev/null +++ b/stubs/pyomo/core/base/set.pyi @@ -0,0 +1,609 @@ +from collections.abc import Generator, Iterator +from functools import partial as partial +from typing import Any as typingAny + +from _typeshed import Incomplete +from pyomo.common.autoslots import AutoSlots as AutoSlots +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.deprecation import ( + RenamedClass as RenamedClass, +) +from pyomo.common.deprecation import ( + deprecated as deprecated, +) +from pyomo.common.deprecation import ( + deprecation_warning as deprecation_warning, +) +from pyomo.common.errors import DeveloperError as DeveloperError +from pyomo.common.errors import PyomoException as PyomoException +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.common.pyomo_typing import overload as overload +from pyomo.common.sorting import sorted_robust as sorted_robust +from pyomo.common.timing import ConstructionTimer as ConstructionTimer +from pyomo.core.base.component import ( + Component as Component, +) +from pyomo.core.base.component import ( + ComponentBase as ComponentBase, +) +from pyomo.core.base.component import ( + ComponentData as ComponentData, +) +from pyomo.core.base.component import ( + ModelComponentFactory as ModelComponentFactory, +) +from pyomo.core.base.disable_methods import disable_methods as disable_methods +from pyomo.core.base.global_set import ( + GlobalSetBase as GlobalSetBase, +) +from pyomo.core.base.global_set import ( + GlobalSets as GlobalSets, +) +from pyomo.core.base.global_set import ( + UnindexedComponent_index as UnindexedComponent_index, +) +from pyomo.core.base.indexed_component import ( + IndexedComponent as IndexedComponent, +) +from pyomo.core.base.indexed_component import ( + UnindexedComponent_set as UnindexedComponent_set, +) +from pyomo.core.base.indexed_component import ( + normalize_index as normalize_index, +) +from pyomo.core.base.indexed_component import ( + rule_wrapper as rule_wrapper, +) +from pyomo.core.base.initializer import ( + CountedCallInitializer as CountedCallInitializer, +) +from pyomo.core.base.initializer import ( + IndexedCallInitializer as IndexedCallInitializer, +) +from pyomo.core.base.initializer import ( + Initializer as Initializer, +) +from pyomo.core.base.initializer import ( + InitializerBase as InitializerBase, +) +from pyomo.core.base.initializer import ( + ParameterizedIndexedCallInitializer as ParameterizedIndexedCallInitializer, +) +from pyomo.core.base.initializer import ( + ParameterizedInitializer as ParameterizedInitializer, +) +from pyomo.core.base.initializer import ( + ParameterizedScalarCallInitializer as ParameterizedScalarCallInitializer, +) +from pyomo.core.base.range import ( + AnyRange as AnyRange, +) +from pyomo.core.base.range import ( + NonNumericRange as NonNumericRange, +) +from pyomo.core.base.range import ( + NumericRange as NumericRange, +) +from pyomo.core.base.range import ( + RangeDifferenceError as RangeDifferenceError, +) +from pyomo.core.base.range import ( + RangeProduct as RangeProduct, +) +from pyomo.core.expr.numvalue import ( + as_numeric as as_numeric, +) +from pyomo.core.expr.numvalue import ( + is_constant as is_constant, +) +from pyomo.core.expr.numvalue import ( + native_numeric_types as native_numeric_types, +) +from pyomo.core.expr.numvalue import ( + native_types as native_types, +) +from pyomo.core.expr.numvalue import ( + value as value, +) + +logger: Incomplete +FLATTEN_CROSS_PRODUCT: bool + +def process_setarg(arg): ... +def set_options(**kwds): ... +def simple_set_rule(rule): ... + +class UnknownSetDimen: ... + +class SetInitializer(InitializerBase): + verified: bool + def __init__(self, init, allow_generators: bool = True) -> None: ... + def intersect(self, other) -> None: ... + def __call__(self, parent, idx, obj): ... + def constant(self): ... + def contains_indices(self): ... + def indices(self): ... + def setdefault(self, val) -> None: ... + +class SetIntersectInitializer(InitializerBase): + def __init__(self, setA, setB) -> None: ... + def __call__(self, parent, idx): ... + def constant(self): ... + def contains_indices(self): ... + def indices(self): ... + +class BoundsInitializer(InitializerBase): + default_step: Incomplete + def __init__(self, init, default_step: int = 0) -> None: ... + def __call__(self, parent, idx): ... + def constant(self): ... + def setdefault(self, val) -> None: ... + +class TuplizeError(PyomoException): ... + +class TuplizeValuesInitializer(InitializerBase): + def __new__(cls, *args): ... + def __init__(self, _init) -> None: ... + def __call__(self, parent, index): ... + def constant(self): ... + def contains_indices(self): ... + def indices(self): ... + +class _NotFound: ... + +class SetData(ComponentData): + def __contains__(self, value) -> bool: ... + def get(self, value, default=None) -> None: ... + def isdiscrete(self): ... + def isfinite(self): ... + def isordered(self): ... + def subsets(self, expand_all_set_operators=None): ... + def __iter__(self) -> Iterator[typingAny]: ... + def __eq__(self, other): ... + def __ne__(self, other): ... + @property + def dimen(self) -> None: ... + @property + def domain(self) -> None: ... + def ranges(self) -> None: ... + def bounds(self): ... + def get_interval(self): ... + @property + def virtual(self): ... + @virtual.setter + def virtual(self, value) -> None: ... + @property + def concrete(self): ... + @concrete.setter + def concrete(self, value) -> None: ... + @property + def ordered(self): ... + @property + def filter(self) -> None: ... + def check_values(self): ... + def isdisjoint(self, other): ... + def issubset(self, other): ... + def issuperset(self, other): ... + def union(self, *args): ... + def intersection(self, *args): ... + def difference(self, *args): ... + def symmetric_difference(self, other): ... + def cross(self, *args): ... + __le__ = issubset + __ge__ = issuperset + __or__ = union + __and__ = intersection + __sub__ = difference + __xor__ = symmetric_difference + __mul__ = cross + def __ror__(self, other): ... + def __rand__(self, other): ... + def __rsub__(self, other): ... + def __rxor__(self, other): ... + def __rmul__(self, other): ... + def __lt__(self, other): ... + def __gt__(self, other): ... + +class _SetData(metaclass=RenamedClass): + __renamed__new_class__ = SetData + __renamed__version__: str + +class _SetDataBase(metaclass=RenamedClass): + __renamed__new_class__ = SetData + __renamed__version__: str + +class _FiniteSetMixin: + def __len__(self) -> int: ... + def __iter__(self): ... + def __reversed__(self): ... + def sorted_iter(self): ... + def ordered_iter(self): ... + def isdiscrete(self): ... + def isfinite(self): ... + def data(self): ... + @property + def value(self): ... + @property + def value_list(self): ... + def sorted_data(self): ... + def ordered_data(self): ... + def bounds(self): ... + def ranges(self) -> Generator[Incomplete]: ... + +class FiniteSetData(_FiniteSetMixin, SetData): + def __init__(self, component) -> None: ... + def get(self, value, default=None): ... + def __reversed__(self): ... + def __len__(self) -> int: ... + @property + def dimen(self): ... + @property + def domain(self): ... + @property + def filter(self): ... + def add(self, *values): ... + def remove(self, val) -> None: ... + def discard(self, val) -> None: ... + def clear(self) -> None: ... + def set_value(self, val) -> None: ... + def update(self, values) -> None: ... + def pop(self): ... + +class _FiniteSetData(metaclass=RenamedClass): + __renamed__new_class__ = FiniteSetData + __renamed__version__: str + +class _ScalarOrderedSetMixin: + def values(self) -> Generator[Incomplete]: ... + def items(self) -> Generator[Incomplete]: ... + +class _OrderedSetMixin: + def at(self, index) -> None: ... + def ord(self, val) -> None: ... + def __getitem__(self, key): ... + def card(self, index): ... + def isordered(self): ... + def ordered_data(self): ... + def ordered_iter(self): ... + def first(self): ... + def last(self): ... + def next(self, item, step: int = 1): ... + def nextw(self, item, step: int = 1): ... + def prev(self, item, step: int = 1): ... + def prevw(self, item, step: int = 1): ... + +class OrderedSetData(_OrderedSetMixin, FiniteSetData): + def __init__(self, component) -> None: ... + def __reversed__(self): ... + def remove(self, val) -> None: ... + def discard(self, val) -> None: ... + def clear(self) -> None: ... + def pop(self): ... + def at(self, index): ... + def ord(self, item): ... + +class _OrderedSetData(metaclass=RenamedClass): + __renamed__new_class__ = OrderedSetData + __renamed__version__: str + +class InsertionOrderSetData(OrderedSetData): + def set_value(self, val) -> None: ... + def update(self, values) -> None: ... + +class _InsertionOrderSetData(metaclass=RenamedClass): + __renamed__new_class__ = InsertionOrderSetData + __renamed__version__: str + +class _SortedSetMixin: + def ordered_iter(self): ... + def sorted_iter(self): ... + +class SortedSetData(_SortedSetMixin, OrderedSetData): + def __reversed__(self): ... + def sorted_data(self): ... + +class _SortedSetData(metaclass=RenamedClass): + __renamed__new_class__ = SortedSetData + __renamed__version__: str + +class Set(IndexedComponent): + class _SetEndException(Exception): ... + + class _SetEndType(type): + def __hash__(self): ... + + class End(metaclass=_SetEndType): ... + class InsertionOrder: ... + class SortedOrder: ... + + def check_values(self): ... + def construct(self, data=None) -> None: ... + def add(self, *values: typingAny) -> None: ... + def remove(self, val: typingAny) -> None: ... + def discard(self, val: typingAny) -> None: ... + def clear(self) -> None: ... + def update(self, values: typingAny) -> None: ... + def pop(self) -> typingAny: ... + def difference(self, *args: typingAny) -> 'SetDifference': ... + def at(self, index: int) -> typingAny: ... + def ord(self, item: typingAny) -> int: ... + def first(self) -> typingAny: ... + def last(self) -> typingAny: ... + def next(self, item: typingAny, step: int = 1) -> typingAny: ... + def nextw(self, item: typingAny, step: int = 1) -> typingAny: ... + def prev(self, item: typingAny, step: int = 1) -> typingAny: ... + def prevw(self, item: typingAny, step: int = 1) -> typingAny: ... + def difference(self, *args: Any) -> 'SetDifference': ... + def __or__(self, other: Any) -> 'SetUnion': ... + def __and__(self, other: Any) -> 'SetIntersection': ... + def __sub__(self, other: Any) -> 'SetDifference': ... + def __xor__(self, other: Any) -> 'SetSymmetricDifference': ... + def __mul__(self, other: Any) -> 'SetProduct': ... + +class IndexedSet(Set): + def data(self): ... + @overload + def __getitem__(self, index) -> SetData: ... + __getitem__: Incomplete + +class FiniteScalarSet(FiniteSetData, Set): + def __init__(self, **kwds) -> None: ... + +class FiniteSimpleSet(metaclass=RenamedClass): + __renamed__new_class__ = FiniteScalarSet + __renamed__version__: str + +class OrderedScalarSet(_ScalarOrderedSetMixin, InsertionOrderSetData, Set): + def __init__(self, **kwds) -> None: ... + +class OrderedSimpleSet(metaclass=RenamedClass): + __renamed__new_class__ = OrderedScalarSet + __renamed__version__: str + +class SortedScalarSet(_ScalarOrderedSetMixin, SortedSetData, Set): + def __init__(self, **kwds) -> None: ... + +class SortedSimpleSet(metaclass=RenamedClass): + __renamed__new_class__ = SortedScalarSet + __renamed__version__: str + +class AbstractFiniteScalarSet(FiniteScalarSet): ... + +class AbstractFiniteSimpleSet(metaclass=RenamedClass): + __renamed__new_class__ = AbstractFiniteScalarSet + __renamed__version__: str + +class AbstractOrderedScalarSet(OrderedScalarSet): ... + +class AbstractOrderedSimpleSet(metaclass=RenamedClass): + __renamed__new_class__ = AbstractOrderedScalarSet + __renamed__version__: str + +class AbstractSortedScalarSet(SortedScalarSet): ... + +class AbstractSortedSimpleSet(metaclass=RenamedClass): + __renamed__new_class__ = AbstractSortedScalarSet + __renamed__version__: str + +class SetOf(SetData, Component): + def __new__(cls, *args, **kwds): ... + def __init__(self, reference, **kwds) -> None: ... + def construct(self, data=None) -> None: ... + @property + def dimen(self): ... + @property + def domain(self): ... + +class InfiniteSetOf(SetOf): + def ranges(self): ... + +class FiniteSetOf(_FiniteSetMixin, SetOf): + def get(self, value, default=None): ... + def __len__(self) -> int: ... + def __reversed__(self): ... + +class UnorderedSetOf(metaclass=RenamedClass): + __renamed__new_class__ = FiniteSetOf + __renamed__version__: str + +class OrderedSetOf(_ScalarOrderedSetMixin, _OrderedSetMixin, FiniteSetOf): + def at(self, index): ... + def ord(self, item): ... + +class InfiniteRangeSetData(SetData): + def __init__(self, component) -> None: ... + def get(self, value, default=None): ... + def isdiscrete(self): ... + @property + def dimen(self): ... + @property + def domain(self): ... + def clear(self) -> None: ... + def ranges(self): ... + +class _InfiniteRangeSetData(metaclass=RenamedClass): + __renamed__new_class__ = InfiniteRangeSetData + __renamed__version__: str + +class FiniteRangeSetData(_SortedSetMixin, _OrderedSetMixin, _FiniteSetMixin, InfiniteRangeSetData): + def __len__(self) -> int: ... + def at(self, index): ... + def ord(self, item): ... + bounds: Incomplete + ranges: Incomplete + domain: Incomplete + +class _FiniteRangeSetData(metaclass=RenamedClass): + __renamed__new_class__ = FiniteRangeSetData + __renamed__version__: str + +class RangeSet(Component): + def __new__(cls, *args, **kwds): ... + def construct(self, data=None) -> None: ... + def dim(self): ... + def index_set(self): ... + +class InfiniteScalarRangeSet(InfiniteRangeSetData, RangeSet): + def __init__(self, *args, **kwds) -> None: ... + +class InfiniteSimpleRangeSet(metaclass=RenamedClass): + __renamed__new_class__ = InfiniteScalarRangeSet + __renamed__version__: str + +class FiniteScalarRangeSet(_ScalarOrderedSetMixin, FiniteRangeSetData, RangeSet): + def __init__(self, *args, **kwds) -> None: ... + +class FiniteSimpleRangeSet(metaclass=RenamedClass): + __renamed__new_class__ = FiniteScalarRangeSet + __renamed__version__: str + +class AbstractInfiniteScalarRangeSet(InfiniteScalarRangeSet): ... + +class AbstractInfiniteSimpleRangeSet(metaclass=RenamedClass): + __renamed__new_class__ = AbstractInfiniteScalarRangeSet + __renamed__version__: str + +class AbstractFiniteScalarRangeSet(FiniteScalarRangeSet): ... + +class AbstractFiniteSimpleRangeSet(metaclass=RenamedClass): + __renamed__new_class__ = AbstractFiniteScalarRangeSet + __renamed__version__: str + +class SetOperator(SetData, Set): + def __init__(self, *args, **kwds) -> None: ... + def construct(self, data=None) -> None: ... + def __len__(self) -> int: ... + def isdiscrete(self): ... + def subsets(self, expand_all_set_operators=None) -> Generator[Incomplete, Incomplete]: ... + @property + def set_tuple(self): ... + @property + def domain(self): ... + +class SetUnion(SetOperator): + def __new__(cls, *args): ... + def ranges(self): ... + @property + def dimen(self): ... + +class SetUnion_InfiniteSet(SetUnion): + def get(self, val, default=None): ... + +class SetUnion_FiniteSet(_FiniteSetMixin, SetUnion_InfiniteSet): + def __len__(self) -> int: ... + +class SetUnion_OrderedSet(_ScalarOrderedSetMixin, _OrderedSetMixin, SetUnion_FiniteSet): + def at(self, index): ... + def ord(self, item): ... + +class SetIntersection(SetOperator): + def __new__(cls, *args): ... + __class__: Incomplete + def construct(self, data=None) -> None: ... + def ranges(self) -> Generator[Incomplete, Incomplete]: ... + @property + def dimen(self): ... + +class SetIntersection_InfiniteSet(SetIntersection): + def get(self, val, default=None): ... + +class SetIntersection_FiniteSet(_FiniteSetMixin, SetIntersection_InfiniteSet): + def __len__(self) -> int: ... + +class SetIntersection_OrderedSet( + _ScalarOrderedSetMixin, _OrderedSetMixin, SetIntersection_FiniteSet +): + def at(self, index): ... + def ord(self, item): ... + +class SetDifference(SetOperator): + def __new__(cls, *args): ... + def ranges(self) -> Generator[Incomplete, Incomplete]: ... + @property + def dimen(self): ... + +class SetDifference_InfiniteSet(SetDifference): + def get(self, val, default=None): ... + +class SetDifference_FiniteSet(_FiniteSetMixin, SetDifference_InfiniteSet): + def __len__(self) -> int: ... + +class SetDifference_OrderedSet(_ScalarOrderedSetMixin, _OrderedSetMixin, SetDifference_FiniteSet): + def at(self, index): ... + def ord(self, item): ... + +class SetSymmetricDifference(SetOperator): + def __new__(cls, *args): ... + def ranges(self) -> Generator[Incomplete, Incomplete]: ... + @property + def dimen(self): ... + +class SetSymmetricDifference_InfiniteSet(SetSymmetricDifference): + def get(self, val, default=None): ... + +class SetSymmetricDifference_FiniteSet(_FiniteSetMixin, SetSymmetricDifference_InfiniteSet): + def __len__(self) -> int: ... + +class SetSymmetricDifference_OrderedSet( + _ScalarOrderedSetMixin, _OrderedSetMixin, SetSymmetricDifference_FiniteSet +): + def at(self, index): ... + def ord(self, item): ... + +class SetProduct(SetOperator): + def __new__(cls, *args): ... + def ranges(self) -> Generator[Incomplete]: ... + def bounds(self): ... + @property + def dimen(self): ... + +class SetProduct_InfiniteSet(SetProduct): + def get(self, val, default=None): ... + +class SetProduct_FiniteSet(_FiniteSetMixin, SetProduct_InfiniteSet): + def __len__(self) -> int: ... + +class SetProduct_OrderedSet(_ScalarOrderedSetMixin, _OrderedSetMixin, SetProduct_FiniteSet): + def at(self, index): ... + def ord(self, item): ... + +class _AnySet(SetData, Set): + def __init__(self, **kwds) -> None: ... + def get(self, val, default=None): ... + def ranges(self) -> Generator[Incomplete]: ... + def bounds(self): ... + def clear(self) -> None: ... + def __len__(self) -> int: ... + @property + def dimen(self) -> None: ... + @property + def domain(self): ... + +class _AnyWithNoneSet(_AnySet): + def get(self, val, default=None): ... + +class _EmptySet(_FiniteSetMixin, SetData, Set): + def __init__(self, **kwds) -> None: ... + def get(self, val, default=None): ... + def clear(self) -> None: ... + def __len__(self) -> int: ... + @property + def dimen(self): ... + @property + def domain(self): ... + +def DeclareGlobalSet(obj, caller_globals=None): ... + +real_global_set_ids: Incomplete +integer_global_set_ids: Incomplete +RealSet: Incomplete +IntegerSet: Incomplete +BinarySet: Incomplete +BooleanSet: Incomplete + +class RealInterval(RealSet): + def __new__(cls, **kwds): ... + +class IntegerInterval(IntegerSet): + def __new__(cls, **kwds): ... diff --git a/stubs/pyomo/core/base/set_types.pyi b/stubs/pyomo/core/base/set_types.pyi new file mode 100644 index 000000000..92ea6dba7 --- /dev/null +++ b/stubs/pyomo/core/base/set_types.pyi @@ -0,0 +1,19 @@ +from pyomo.core.base.set import Any as Any +from pyomo.core.base.set import AnyWithNone as AnyWithNone +from pyomo.core.base.set import Binary as Binary +from pyomo.core.base.set import Boolean as Boolean +from pyomo.core.base.set import EmptySet as EmptySet +from pyomo.core.base.set import IntegerInterval as IntegerInterval +from pyomo.core.base.set import Integers as Integers +from pyomo.core.base.set import NegativeIntegers as NegativeIntegers +from pyomo.core.base.set import NegativeReals as NegativeReals +from pyomo.core.base.set import NonNegativeIntegers as NonNegativeIntegers +from pyomo.core.base.set import NonNegativeReals as NonNegativeReals +from pyomo.core.base.set import NonPositiveIntegers as NonPositiveIntegers +from pyomo.core.base.set import NonPositiveReals as NonPositiveReals +from pyomo.core.base.set import PercentFraction as PercentFraction +from pyomo.core.base.set import PositiveIntegers as PositiveIntegers +from pyomo.core.base.set import PositiveReals as PositiveReals +from pyomo.core.base.set import RealInterval as RealInterval +from pyomo.core.base.set import Reals as Reals +from pyomo.core.base.set import UnitInterval as UnitInterval diff --git a/stubs/pyomo/core/base/sos.pyi b/stubs/pyomo/core/base/sos.pyi new file mode 100644 index 000000000..d2bf5e4a1 --- /dev/null +++ b/stubs/pyomo/core/base/sos.pyi @@ -0,0 +1,51 @@ +from collections.abc import Generator + +from _typeshed import Incomplete +from pyomo.common.deprecation import RenamedClass as RenamedClass +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.timing import ConstructionTimer as ConstructionTimer +from pyomo.core.base.component import ActiveComponentData as ActiveComponentData +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.global_set import UnindexedComponent_index as UnindexedComponent_index +from pyomo.core.base.indexed_component import ActiveIndexedComponent as ActiveIndexedComponent +from pyomo.core.base.indexed_component import UnindexedComponent_set as UnindexedComponent_set +from pyomo.core.base.misc import apply_indexed_rule as apply_indexed_rule +from pyomo.core.base.set_types import PositiveIntegers as PositiveIntegers + +logger: Incomplete + +class SOSConstraintData(ActiveComponentData): + def __init__(self, owner) -> None: ... + def num_variables(self): ... + def items(self): ... + @property + def level(self): ... + @level.setter + def level(self, level) -> None: ... + @property + def variables(self): ... + def get_variables(self) -> Generator[Incomplete]: ... + def get_items(self) -> Generator[Incomplete]: ... + def set_items(self, variables, weights) -> None: ... + +class _SOSConstraintData(metaclass=RenamedClass): + __renamed__new_class__ = SOSConstraintData + __renamed__version__: str + +class SOSConstraint(ActiveIndexedComponent): + Skip: Incomplete + def __new__(cls, *args, **kwds): ... + def __init__(self, *args, **kwargs) -> None: ... + def construct(self, data=None): ... + def add(self, index, variables, weights=None) -> None: ... + def pprint(self, ostream=None, verbose: bool = False, prefix: str = '') -> None: ... + +class ScalarSOSConstraint(SOSConstraint, SOSConstraintData): + def __init__(self, *args, **kwd) -> None: ... + +class SimpleSOSConstraint(metaclass=RenamedClass): + __renamed__new_class__ = ScalarSOSConstraint + __renamed__version__: str + +class IndexedSOSConstraint(SOSConstraint): + def __init__(self, *args, **kwds) -> None: ... diff --git a/stubs/pyomo/core/base/suffix.pyi b/stubs/pyomo/core/base/suffix.pyi new file mode 100644 index 000000000..779cd84d3 --- /dev/null +++ b/stubs/pyomo/core/base/suffix.pyi @@ -0,0 +1,74 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.config import In as In +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.enums import IntEnum as IntEnum +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.common.pyomo_typing import overload as overload +from pyomo.common.timing import ConstructionTimer as ConstructionTimer +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.component import ActiveComponent as ActiveComponent +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.disable_methods import disable_methods as disable_methods +from pyomo.core.base.initializer import Initializer as Initializer + +logger: Incomplete + +def suffix_generator(a_block, datatype=..., direction=..., active=None): ... +def active_export_suffix_generator(a_block, datatype=...): ... +def export_suffix_generator(a_block, datatype=...): ... +def active_import_suffix_generator(a_block, datatype=...): ... +def import_suffix_generator(a_block, datatype=...): ... +def active_local_suffix_generator(a_block, datatype=...): ... +def local_suffix_generator(a_block, datatype=...): ... +def active_suffix_generator(a_block, datatype=...): ... + +class SuffixDataType(IntEnum): + INT = 0 + FLOAT = 4 + +class SuffixDirection(IntEnum): + LOCAL = 0 + EXPORT = 1 + IMPORT = 2 + IMPORT_EXPORT = 3 + +class Suffix(ComponentMap, ActiveComponent): + LOCAL: Incomplete + EXPORT: Incomplete + IMPORT: Incomplete + IMPORT_EXPORT: Incomplete + FLOAT: Incomplete + INT: Incomplete + def __new__(cls, *args, **kwargs): ... + def construct(self, data=None) -> None: ... + @property + def datatype(self): ... + @datatype.setter + def datatype(self, datatype) -> None: ... + @property + def direction(self): ... + @direction.setter + def direction(self, direction) -> None: ... + def export_enabled(self): ... + def import_enabled(self): ... + def update_values(self, data, expand: bool = True) -> None: ... + def set_value(self, component, value, expand: bool = True) -> None: ... + def set_all_values(self, value) -> None: ... + def clear_value(self, component, expand: bool = True) -> None: ... + def clear_all_values(self) -> None: ... + def set_datatype(self, datatype) -> None: ... + def get_datatype(self): ... + def set_direction(self, direction) -> None: ... + def get_direction(self): ... + def pprint(self, *args, **kwds): ... + +class AbstractSuffix(Suffix): ... + +class SuffixFinder: + name: Incomplete + default: Incomplete + all_suffixes: Incomplete + def __init__(self, name, default=None, context=None) -> None: ... + def find(self, component_data): ... diff --git a/stubs/pyomo/core/base/symbol_map.pyi b/stubs/pyomo/core/base/symbol_map.pyi new file mode 100644 index 000000000..3e0d5c381 --- /dev/null +++ b/stubs/pyomo/core/base/symbol_map.pyi @@ -0,0 +1,4 @@ +from pyomo.core.base.label import TextLabeler as TextLabeler +from pyomo.core.expr.symbol_map import SymbolMap as SymbolMap + +def symbol_map_from_instance(instance): ... diff --git a/stubs/pyomo/core/base/symbolic.pyi b/stubs/pyomo/core/base/symbolic.pyi new file mode 100644 index 000000000..54d5c93d0 --- /dev/null +++ b/stubs/pyomo/core/base/symbolic.pyi @@ -0,0 +1,7 @@ +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.errors import NondifferentiableError as NondifferentiableError +from pyomo.core.expr.calculus.diff_with_sympy import ( + differentiate_available as differentiate_available, +) + +def differentiate(expr, wrt=None, wrt_list=None): ... diff --git a/stubs/pyomo/core/base/transformation.pyi b/stubs/pyomo/core/base/transformation.pyi new file mode 100644 index 000000000..f60ad1b2e --- /dev/null +++ b/stubs/pyomo/core/base/transformation.pyi @@ -0,0 +1,40 @@ +import types + +from _typeshed import Incomplete +from pyomo.common import Factory as Factory +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.errors import MouseTrap as MouseTrap +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.common.timing import TransformationTimer as TransformationTimer + +class TransformationInfo: ... + +class TransformationData: + def __init__(self) -> None: ... + def __getitem__(self, name): ... + +class Transformation: + def __init__(self, **kwds) -> None: ... + def __enter__(self): ... + def __exit__( + self, + t: type[BaseException] | None, + v: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: ... + def apply(self, model, **kwds): ... + def apply_to(self, model, **kwds): ... + def create_using(self, model, **kwds): ... + +class ReverseTransformationToken: + def __init__(self, transformation, model, targets, reverse_dict) -> None: ... + @property + def transformation(self): ... + @property + def reverse_dict(self): ... + def check_token_valid(self, cls, model, targets) -> None: ... + +TransformationFactory: Incomplete + +def apply_transformation(*args, **kwds): ... diff --git a/stubs/pyomo/core/base/units_container.pyi b/stubs/pyomo/core/base/units_container.pyi new file mode 100644 index 000000000..849c2b64b --- /dev/null +++ b/stubs/pyomo/core/base/units_container.pyi @@ -0,0 +1,84 @@ +import pyomo.core.expr as EXPR +from _typeshed import Incomplete +from pyomo.common.dependencies import pint_available as pint_available +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.core.expr.numvalue import NumericValue as NumericValue +from pyomo.core.expr.numvalue import native_numeric_types as native_numeric_types +from pyomo.core.expr.numvalue import native_types as native_types +from pyomo.core.expr.numvalue import nonpyomo_leaf_types as nonpyomo_leaf_types +from pyomo.core.expr.numvalue import value as value +from pyomo.core.expr.template_expr import IndexTemplate as IndexTemplate +from pyomo.core.expr.visitor import ExpressionValueVisitor as ExpressionValueVisitor + +logger: Incomplete + +class UnitsError(Exception): + msg: Incomplete + def __init__(self, msg) -> None: ... + +class InconsistentUnitsError(UnitsError): + def __init__(self, exp1, exp2, msg) -> None: ... + +class _PyomoUnit(NumericValue): + __autoslot_mappers__: Incomplete + def __init__(self, pint_unit, pint_registry) -> None: ... + def getname(self, fully_qualified: bool = False, name_buffer=None): ... + def is_constant(self): ... + def is_fixed(self): ... + def is_parameter_type(self): ... + def is_variable_type(self): ... + def is_potentially_variable(self): ... + def is_named_expression_type(self): ... + def is_expression_type(self, expression_system=None): ... + def is_component_type(self): ... + def is_indexed(self): ... + def __deepcopy__(self, memo): ... + def __eq__(self, other): ... + def to_string(self, verbose=None, labeler=None, smap=None, compute_values: bool = False): ... + def __call__(self, exception=...): ... + @property + def value(self): ... + def pprint(self, ostream=None, verbose: bool = False) -> None: ... + +class PintUnitExtractionVisitor(EXPR.StreamBasedExpressionVisitor): + def __init__( + self, pyomo_units_container, units_equivalence_tolerance: float = 1e-12 + ) -> None: ... + node_type_method_map: Incomplete + unary_function_method_map: Incomplete + def initializeWalker(self, expr): ... + def beforeChild(self, node, child, child_idx): ... + def exitNode(self, node, data): ... + def finalizeResult(self, result): ... + +class PyomoUnitsContainer: + def __init__(self, pint_registry=...) -> None: ... + def load_definitions_from_file(self, definition_file) -> None: ... + def load_definitions_from_strings(self, definition_string_list) -> None: ... + def __getattr__(self, item): ... + def get_units(self, expr): ... + def convert_temp_K_to_C(self, value_in_K): ... + def convert_temp_C_to_K(self, value_in_C): ... + def convert_temp_R_to_F(self, value_in_R): ... + def convert_temp_F_to_R(self, value_in_F): ... + def convert(self, src, to_units=None): ... + def convert_value(self, num_value, from_units=None, to_units=None): ... + def set_pint_registry(self, pint_registry) -> None: ... + @property + def pint_registry(self): ... + +class _QuantityVisitor(ExpressionValueVisitor): + native_types: Incomplete + def __init__(self) -> None: ... + def visit(self, node, values): ... + def visiting_potential_leaf(self, node): ... + def finalize(self, val): ... + +def as_quantity(expr): ... + +class _DeferredUnitsSingleton(PyomoUnitsContainer): + def __init__(self) -> None: ... + __class__: Incomplete + def __getattribute__(self, attr): ... + +units: Incomplete diff --git a/stubs/pyomo/core/base/util.pyi b/stubs/pyomo/core/base/util.pyi new file mode 100644 index 000000000..640e0c03d --- /dev/null +++ b/stubs/pyomo/core/base/util.pyi @@ -0,0 +1,5 @@ +from pyomo.common.deprecation import relocated_module_attribute as relocated_module_attribute +from pyomo.core.base.indexed_component import normalize_index as normalize_index + +def is_functor(obj): ... +def flatten_tuple(x): ... diff --git a/stubs/pyomo/core/base/var.pyi b/stubs/pyomo/core/base/var.pyi new file mode 100644 index 000000000..1f98d41ef --- /dev/null +++ b/stubs/pyomo/core/base/var.pyi @@ -0,0 +1,199 @@ +from typing import Any as typingAny + +from _typeshed import Incomplete +from pyomo.common.deprecation import RenamedClass as RenamedClass +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.common.pyomo_typing import overload as overload +from pyomo.common.timing import ConstructionTimer as ConstructionTimer +from pyomo.core.base.component import ( + ComponentData as ComponentData, +) +from pyomo.core.base.component import ( + ModelComponentFactory as ModelComponentFactory, +) +from pyomo.core.base.disable_methods import disable_methods as disable_methods +from pyomo.core.base.global_set import UnindexedComponent_index as UnindexedComponent_index +from pyomo.core.base.indexed_component import ( + IndexedComponent as IndexedComponent, +) +from pyomo.core.base.indexed_component import ( + IndexedComponent_NDArrayMixin as IndexedComponent_NDArrayMixin, +) +from pyomo.core.base.indexed_component import ( + UnindexedComponent_set as UnindexedComponent_set, +) +from pyomo.core.base.initializer import ( + BoundInitializer as BoundInitializer, +) +from pyomo.core.base.initializer import ( + DefaultInitializer as DefaultInitializer, +) +from pyomo.core.base.initializer import ( + Initializer as Initializer, +) +from pyomo.core.base.set import ( + Binary as Binary, +) +from pyomo.core.base.set import ( + Reals as Reals, +) +from pyomo.core.base.set import ( + Set as Set, +) +from pyomo.core.base.set import ( + SetInitializer as SetInitializer, +) +from pyomo.core.base.set import ( + integer_global_set_ids as integer_global_set_ids, +) +from pyomo.core.base.set import ( + real_global_set_ids as real_global_set_ids, +) +from pyomo.core.base.units_container import units as units +from pyomo.core.expr import GetItemExpression as GetItemExpression +from pyomo.core.expr.numeric_expr import ( + NPV_MaxExpression as NPV_MaxExpression, +) +from pyomo.core.expr.numeric_expr import ( + NPV_MinExpression as NPV_MinExpression, +) +from pyomo.core.expr.numvalue import ( + NumericValue as NumericValue, +) +from pyomo.core.expr.numvalue import ( + is_potentially_variable as is_potentially_variable, +) +from pyomo.core.expr.numvalue import ( + native_numeric_types as native_numeric_types, +) +from pyomo.core.expr.numvalue import ( + value as value, +) +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager + +logger: Incomplete + +class VarData(ComponentData, NumericValue): + __autoslot_mappers__: Incomplete + def __init__(self, component=None) -> None: ... + @classmethod + def copy(cls, src): ... + def set_value(self, val, skip_validation: bool = False) -> None: ... + @property + def value(self): ... + @value.setter + def value(self, val) -> None: ... + def __call__(self, exception=...): ... + @property + def domain(self): ... + @domain.setter + def domain(self, domain) -> None: ... + def has_lb(self): ... + def has_ub(self): ... + def setlb(self, val) -> None: ... + def setub(self, val) -> None: ... + @property + def bounds(self): ... + @bounds.setter + def bounds(self, val) -> None: ... + @property + def lb(self): ... + @lb.setter + def lb(self, val) -> None: ... + @property + def ub(self): ... + @ub.setter + def ub(self, val) -> None: ... + @property + def lower(self): ... + @lower.setter + def lower(self, val) -> None: ... + @property + def upper(self): ... + @upper.setter + def upper(self, val) -> None: ... + def get_units(self): ... + def fix(self, value=..., skip_validation: bool = False) -> None: ... + def unfix(self) -> None: ... + def free(self): ... + @property + def fixed(self): ... + @fixed.setter + def fixed(self, val) -> None: ... + @property + def stale(self): ... + @stale.setter + def stale(self, val) -> None: ... + def is_integer(self): ... + def is_binary(self): ... + def is_continuous(self): ... + def is_fixed(self): ... + def is_constant(self): ... + def is_variable_type(self): ... + def is_potentially_variable(self): ... + def clear(self) -> None: ... + +class _VarData(metaclass=RenamedClass): + __renamed__new_class__ = VarData + __renamed__version__: str + +class _GeneralVarData(metaclass=RenamedClass): + __renamed__new_class__ = VarData + __renamed__version__: str + +class Var(IndexedComponent, IndexedComponent_NDArrayMixin): + def flag_as_stale(self) -> None: ... + def get_values(self, include_fixed_values: bool = True): ... + extract_values = get_values + def set_values(self, new_values, skip_validation: bool = False) -> None: ... + def get_units(self): ... + def add(self, index): ... + def construct(self, data=None) -> None: ... + def __lt__(self, other: typingAny) -> typingAny: ... + def __le__(self, other: typingAny) -> typingAny: ... + def __eq__(self, other: typingAny) -> typingAny: ... + def __ne__(self, other: typingAny) -> typingAny: ... + def __gt__(self, other: typingAny) -> typingAny: ... + def __ge__(self, other: typingAny) -> typingAny: ... + def __neg__(self) -> typingAny: ... + def __pos__(self) -> typingAny: ... + def __abs__(self) -> typingAny: ... + def __add__(self, other: typingAny) -> typingAny: ... + def __sub__(self, other: typingAny) -> typingAny: ... + def __mul__(self, other: typingAny) -> typingAny: ... + def __div__(self, other: typingAny) -> typingAny: ... + def __truediv__(self, other: typingAny) -> typingAny: ... + def __pow__(self, other: typingAny) -> typingAny: ... + def __radd__(self, other: typingAny) -> typingAny: ... + def __rsub__(self, other: typingAny) -> typingAny: ... + def __rmul__(self, other: typingAny) -> typingAny: ... + def __rdiv__(self, other: typingAny) -> typingAny: ... + def __rtruediv__(self, other: typingAny) -> typingAny: ... + def __rpow__(self, other: typingAny) -> typingAny: ... + +class ScalarVar(VarData, Var): + def __init__(self, *args, **kwd) -> None: ... + +class AbstractScalarVar(ScalarVar): ... + +class SimpleVar(metaclass=RenamedClass): + __renamed__new_class__ = ScalarVar + __renamed__version__: str + +class IndexedVar(Var): + def setlb(self, val) -> None: ... + def setub(self, val) -> None: ... + def fix(self, value=..., skip_validation: bool = False) -> None: ... + def unfix(self) -> None: ... + def free(self): ... + @property + def domain(self) -> None: ... + @domain.setter + def domain(self, domain) -> None: ... + def __getitem__(self, args) -> VarData: ... + +class VarList(IndexedVar): + def __init__(self, **kwargs) -> None: ... + def construct(self, data=None) -> None: ... + def add(self): ... diff --git a/stubs/pyomo/core/beta/__init__.pyi b/stubs/pyomo/core/beta/__init__.pyi new file mode 100644 index 000000000..70bf92629 --- /dev/null +++ b/stubs/pyomo/core/beta/__init__.pyi @@ -0,0 +1,2 @@ +from pyomo.core.beta import dict_objects as dict_objects +from pyomo.core.beta import list_objects as list_objects diff --git a/stubs/pyomo/core/beta/dict_objects.pyi b/stubs/pyomo/core/beta/dict_objects.pyi new file mode 100644 index 000000000..f06736f4c --- /dev/null +++ b/stubs/pyomo/core/beta/dict_objects.pyi @@ -0,0 +1,38 @@ +from collections.abc import MutableMapping + +from _typeshed import Incomplete +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.core.base.constraint import ConstraintData as ConstraintData +from pyomo.core.base.constraint import IndexedConstraint as IndexedConstraint +from pyomo.core.base.expression import ExpressionData as ExpressionData +from pyomo.core.base.expression import IndexedExpression as IndexedExpression +from pyomo.core.base.objective import IndexedObjective as IndexedObjective +from pyomo.core.base.objective import ObjectiveData as ObjectiveData +from pyomo.core.base.set_types import Any as Any +from pyomo.core.base.var import IndexedVar as IndexedVar +from pyomo.core.base.var import VarData as VarData + +logger: Incomplete + +class ComponentDict(MutableMapping): + def __init__(self, interface_datatype, *args) -> None: ... + def construct(self, data=None) -> None: ... + def __setitem__(self, key, val) -> None: ... + def __delitem__(self, key) -> None: ... + def __getitem__(self, key): ... + def __iter__(self): ... + def __len__(self) -> int: ... + def __eq__(self, other): ... + def __ne__(self, other): ... + +class VarDict(ComponentDict, IndexedVar): + def __init__(self, *args, **kwds) -> None: ... + +class ConstraintDict(ComponentDict, IndexedConstraint): + def __init__(self, *args, **kwds) -> None: ... + +class ObjectiveDict(ComponentDict, IndexedObjective): + def __init__(self, *args, **kwds) -> None: ... + +class ExpressionDict(ComponentDict, IndexedExpression): + def __init__(self, *args, **kwds) -> None: ... diff --git a/stubs/pyomo/core/beta/list_objects.pyi b/stubs/pyomo/core/beta/list_objects.pyi new file mode 100644 index 000000000..484ee6730 --- /dev/null +++ b/stubs/pyomo/core/beta/list_objects.pyi @@ -0,0 +1,46 @@ +from collections.abc import MutableSequence + +from _typeshed import Incomplete +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.core.base.constraint import ConstraintData as ConstraintData +from pyomo.core.base.constraint import IndexedConstraint as IndexedConstraint +from pyomo.core.base.expression import ExpressionData as ExpressionData +from pyomo.core.base.expression import IndexedExpression as IndexedExpression +from pyomo.core.base.objective import IndexedObjective as IndexedObjective +from pyomo.core.base.objective import ObjectiveData as ObjectiveData +from pyomo.core.base.set_types import Any as Any +from pyomo.core.base.var import IndexedVar as IndexedVar +from pyomo.core.base.var import VarData as VarData + +logger: Incomplete + +class ComponentList(MutableSequence): + def __init__(self, interface_datatype, *args) -> None: ... + def construct(self, data=None) -> None: ... + def keys(self): ... + iterkeys = keys + def values(self): ... + itervalues = values + def items(self): ... + iteritems = items + def __setitem__(self, i, item) -> None: ... + def insert(self, i, item) -> None: ... + def __delitem__(self, i) -> None: ... + def __getitem__(self, i): ... + def __len__(self) -> int: ... + def __contains__(self, item) -> bool: ... + def index(self, item, start: int = 0, stop=None): ... + def count(self, item): ... + def reverse(self) -> None: ... + +class XVarList(ComponentList, IndexedVar): + def __init__(self, *args, **kwds) -> None: ... + +class XConstraintList(ComponentList, IndexedConstraint): + def __init__(self, *args, **kwds) -> None: ... + +class XObjectiveList(ComponentList, IndexedObjective): + def __init__(self, *args, **kwds) -> None: ... + +class XExpressionList(ComponentList, IndexedExpression): + def __init__(self, *args, **kwds) -> None: ... diff --git a/stubs/pyomo/core/expr/__init__.pyi b/stubs/pyomo/core/expr/__init__.pyi new file mode 100644 index 000000000..8d04ec0a2 --- /dev/null +++ b/stubs/pyomo/core/expr/__init__.pyi @@ -0,0 +1,154 @@ +from pyomo.common.deprecation import moved_module as moved_module +from pyomo.common.errors import TemplateExpressionError as TemplateExpressionError +from pyomo.common.numeric_types import native_numeric_types as native_numeric_types +from pyomo.common.numeric_types import native_types as native_types +from pyomo.common.numeric_types import nonpyomo_leaf_types as nonpyomo_leaf_types +from pyomo.common.numeric_types import value as value + +from . import boolean_value as boolean_value +from . import logical_expr as logical_expr +from . import numeric_expr as numeric_expr +from . import numvalue as numvalue +from . import relational_expr as relational_expr +from . import visitor as visitor +from .base import ExpressionBase as ExpressionBase +from .calculus.derivatives import differentiate as differentiate +from .expr_common import ExpressionType as ExpressionType +from .expr_common import Mode as Mode +from .expr_common import OperatorAssociativity as OperatorAssociativity +from .logical_expr import AllDifferentExpression as AllDifferentExpression +from .logical_expr import AndExpression as AndExpression +from .logical_expr import AtLeastExpression as AtLeastExpression +from .logical_expr import AtMostExpression as AtMostExpression +from .logical_expr import BinaryBooleanExpression as BinaryBooleanExpression +from .logical_expr import BooleanConstant as BooleanConstant +from .logical_expr import BooleanExpression as BooleanExpression +from .logical_expr import BooleanExpressionBase as BooleanExpressionBase +from .logical_expr import BooleanValue as BooleanValue +from .logical_expr import CountIfExpression as CountIfExpression +from .logical_expr import EquivalenceExpression as EquivalenceExpression +from .logical_expr import ExactlyExpression as ExactlyExpression +from .logical_expr import ImplicationExpression as ImplicationExpression +from .logical_expr import NaryBooleanExpression as NaryBooleanExpression +from .logical_expr import NotExpression as NotExpression +from .logical_expr import OrExpression as OrExpression +from .logical_expr import UnaryBooleanExpression as UnaryBooleanExpression +from .logical_expr import XorExpression as XorExpression +from .logical_expr import all_different as all_different +from .logical_expr import atleast as atleast +from .logical_expr import atmost as atmost +from .logical_expr import count_if as count_if +from .logical_expr import equivalent as equivalent +from .logical_expr import exactly as exactly +from .logical_expr import implies as implies +from .logical_expr import land as land +from .logical_expr import lnot as lnot +from .logical_expr import lor as lor +from .logical_expr import native_logical_types as native_logical_types +from .logical_expr import special_boolean_atom_types as special_boolean_atom_types +from .logical_expr import xor as xor +from .numeric_expr import AbsExpression as AbsExpression +from .numeric_expr import DivisionExpression as DivisionExpression +from .numeric_expr import Expr_if as Expr_if +from .numeric_expr import Expr_ifExpression as Expr_ifExpression +from .numeric_expr import ExternalFunctionExpression as ExternalFunctionExpression +from .numeric_expr import LinearDecompositionError as LinearDecompositionError +from .numeric_expr import LinearExpression as LinearExpression +from .numeric_expr import MaxExpression as MaxExpression +from .numeric_expr import MinExpression as MinExpression +from .numeric_expr import MonomialTermExpression as MonomialTermExpression +from .numeric_expr import NegationExpression as NegationExpression +from .numeric_expr import NPV_AbsExpression as NPV_AbsExpression +from .numeric_expr import NPV_DivisionExpression as NPV_DivisionExpression +from .numeric_expr import NPV_Expr_ifExpression as NPV_Expr_ifExpression +from .numeric_expr import NPV_expression_types as NPV_expression_types +from .numeric_expr import NPV_ExternalFunctionExpression as NPV_ExternalFunctionExpression +from .numeric_expr import NPV_MaxExpression as NPV_MaxExpression +from .numeric_expr import NPV_MinExpression as NPV_MinExpression +from .numeric_expr import NPV_NegationExpression as NPV_NegationExpression +from .numeric_expr import NPV_PowExpression as NPV_PowExpression +from .numeric_expr import NPV_ProductExpression as NPV_ProductExpression +from .numeric_expr import NPV_SumExpression as NPV_SumExpression +from .numeric_expr import NPV_UnaryFunctionExpression as NPV_UnaryFunctionExpression +from .numeric_expr import NumericExpression as NumericExpression +from .numeric_expr import NumericValue as NumericValue +from .numeric_expr import PowExpression as PowExpression +from .numeric_expr import ProductExpression as ProductExpression +from .numeric_expr import SumExpression as SumExpression +from .numeric_expr import SumExpressionBase as SumExpressionBase +from .numeric_expr import UnaryFunctionExpression as UnaryFunctionExpression +from .numeric_expr import acos as acos +from .numeric_expr import acosh as acosh +from .numeric_expr import asin as asin +from .numeric_expr import asinh as asinh +from .numeric_expr import atan as atan +from .numeric_expr import atanh as atanh +from .numeric_expr import ceil as ceil +from .numeric_expr import cos as cos +from .numeric_expr import cosh as cosh +from .numeric_expr import decompose_term as decompose_term +from .numeric_expr import exp as exp +from .numeric_expr import floor as floor +from .numeric_expr import linear_expression as linear_expression +from .numeric_expr import log as log +from .numeric_expr import log10 as log10 +from .numeric_expr import mutable_expression as mutable_expression +from .numeric_expr import nonlinear_expression as nonlinear_expression +from .numeric_expr import sin as sin +from .numeric_expr import sinh as sinh +from .numeric_expr import sqrt as sqrt +from .numeric_expr import tan as tan +from .numeric_expr import tanh as tanh +from .numvalue import ZeroConstant as ZeroConstant +from .numvalue import as_numeric as as_numeric +from .numvalue import is_constant as is_constant +from .numvalue import is_fixed as is_fixed +from .numvalue import is_potentially_variable as is_potentially_variable +from .numvalue import is_variable_type as is_variable_type +from .relational_expr import EqualityExpression as EqualityExpression +from .relational_expr import InequalityExpression as InequalityExpression +from .relational_expr import NotEqualExpression as NotEqualExpression +from .relational_expr import RangedExpression as RangedExpression +from .relational_expr import RelationalExpression as RelationalExpression +from .relational_expr import inequality as inequality +from .symbol_map import SymbolMap as SymbolMap +from .taylor_series import taylor_series_expansion as taylor_series_expansion +from .template_expr import Boolean_GetAttrExpression as Boolean_GetAttrExpression +from .template_expr import Boolean_GetItemExpression as Boolean_GetItemExpression +from .template_expr import CallExpression as CallExpression +from .template_expr import GetAttrExpression as GetAttrExpression +from .template_expr import GetItemExpression as GetItemExpression +from .template_expr import IndexTemplate as IndexTemplate +from .template_expr import NPV_Boolean_GetAttrExpression as NPV_Boolean_GetAttrExpression +from .template_expr import NPV_Boolean_GetItemExpression as NPV_Boolean_GetItemExpression +from .template_expr import NPV_Numeric_GetAttrExpression as NPV_Numeric_GetAttrExpression +from .template_expr import NPV_Numeric_GetItemExpression as NPV_Numeric_GetItemExpression +from .template_expr import NPV_Structural_GetAttrExpression as NPV_Structural_GetAttrExpression +from .template_expr import NPV_Structural_GetItemExpression as NPV_Structural_GetItemExpression +from .template_expr import Numeric_GetAttrExpression as Numeric_GetAttrExpression +from .template_expr import Numeric_GetItemExpression as Numeric_GetItemExpression +from .template_expr import ReplaceTemplateExpression as ReplaceTemplateExpression +from .template_expr import Structural_GetAttrExpression as Structural_GetAttrExpression +from .template_expr import Structural_GetItemExpression as Structural_GetItemExpression +from .template_expr import TemplateSumExpression as TemplateSumExpression +from .template_expr import resolve_template as resolve_template +from .template_expr import substitute_getitem_with_param as substitute_getitem_with_param +from .template_expr import substitute_template_expression as substitute_template_expression +from .template_expr import substitute_template_with_value as substitute_template_with_value +from .template_expr import templatize_constraint as templatize_constraint +from .template_expr import templatize_rule as templatize_rule +from .visitor import ExpressionReplacementVisitor as ExpressionReplacementVisitor +from .visitor import ExpressionValueVisitor as ExpressionValueVisitor +from .visitor import FixedExpressionError as FixedExpressionError +from .visitor import NonConstantExpressionError as NonConstantExpressionError +from .visitor import SimpleExpressionVisitor as SimpleExpressionVisitor +from .visitor import StreamBasedExpressionVisitor as StreamBasedExpressionVisitor +from .visitor import clone_expression as clone_expression +from .visitor import evaluate_expression as evaluate_expression +from .visitor import expression_to_string as expression_to_string +from .visitor import identify_components as identify_components +from .visitor import identify_mutable_parameters as identify_mutable_parameters +from .visitor import identify_variables as identify_variables +from .visitor import polynomial_degree as polynomial_degree +from .visitor import replace_expressions as replace_expressions +from .visitor import sizeof_expression as sizeof_expression diff --git a/stubs/pyomo/core/expr/base.pyi b/stubs/pyomo/core/expr/base.pyi new file mode 100644 index 000000000..a6900ee7b --- /dev/null +++ b/stubs/pyomo/core/expr/base.pyi @@ -0,0 +1,62 @@ +from typing import Any + +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.common.numeric_types import native_types as native_types +from pyomo.core.expr.expr_common import OperatorAssociativity as OperatorAssociativity +from pyomo.core.pyomoobject import PyomoObject as PyomoObject + +visitor: Incomplete +_: Incomplete + +class ExpressionBase(PyomoObject): + PRECEDENCE: int + ASSOCIATIVITY: Incomplete + def nargs(self) -> None: ... + def arg(self, i): ... + @property + def args(self) -> None: ... + def __call__(self, exception=...): ... + def to_string(self, verbose=None, labeler=None, smap=None, compute_values: bool = False): ... + def getname(self, *args, **kwds) -> None: ... + def clone(self, substitute=None): ... + def create_node_with_local_data(self, args, classtype=None): ... + def is_constant(self): ... + def is_fixed(self): ... + def is_potentially_variable(self): ... + def is_named_expression_type(self): ... + def is_expression_type(self, expression_system=None): ... + def size(self): ... + def __lt__(self, other: Any) -> Any: ... + def __le__(self, other: Any) -> Any: ... + def __eq__(self, other: Any) -> Any: ... + def __ne__(self, other: Any) -> Any: ... + def __gt__(self, other: Any) -> Any: ... + def __ge__(self, other: Any) -> Any: ... + def __neg__(self) -> Any: ... + def __pos__(self) -> Any: ... + def __abs__(self) -> Any: ... + def __add__(self, other: Any) -> Any: ... + def __sub__(self, other: Any) -> Any: ... + def __mul__(self, other: Any) -> Any: ... + def __div__(self, other: Any) -> Any: ... + def __truediv__(self, other: Any) -> Any: ... + def __pow__(self, other: Any) -> Any: ... + def __radd__(self, other: Any) -> Any: ... + def __rsub__(self, other: Any) -> Any: ... + def __rmul__(self, other: Any) -> Any: ... + def __rdiv__(self, other: Any) -> Any: ... + def __rtruediv__(self, other: Any) -> Any: ... + def __rpow__(self, other: Any) -> Any: ... + +class NPV_Mixin: + def is_potentially_variable(self): ... + def create_node_with_local_data(self, args, classtype=None): ... + def potentially_variable_base_class(self): ... + +class ExpressionArgs_Mixin: + def __init__(self, args) -> None: ... + def nargs(self): ... + @property + def args(self): ... diff --git a/stubs/pyomo/core/expr/boolean_value.pyi b/stubs/pyomo/core/expr/boolean_value.pyi new file mode 100644 index 000000000..338e7cf5a --- /dev/null +++ b/stubs/pyomo/core/expr/boolean_value.pyi @@ -0,0 +1,52 @@ +from _typeshed import Incomplete +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.common.numeric_types import native_logical_types as native_logical_types +from pyomo.common.numeric_types import native_types as native_types +from pyomo.core.pyomoobject import PyomoObject as PyomoObject + +logger: Incomplete +native_logical_values: Incomplete + +def as_boolean(obj): ... + +class BooleanValue(PyomoObject): + __hash__: Incomplete + def getname(self, fully_qualified: bool = False, name_buffer=None): ... + @property + def name(self): ... + @property + def local_name(self): ... + def is_constant(self): ... + def is_fixed(self): ... + def is_relational(self): ... + def is_indexed(self): ... + def is_numeric_type(self): ... + def is_logical_type(self): ... + def __invert__(self): ... + def equivalent_to(self, other): ... + def land(self, other): ... + def __and__(self, other): ... + def __rand__(self, other): ... + def __iand__(self, other): ... + def lor(self, other): ... + def __or__(self, other): ... + def __ror__(self, other): ... + def __ior__(self, other): ... + def xor(self, other): ... + def __xor__(self, other): ... + def __rxor__(self, other): ... + def __ixor__(self, other): ... + def implies(self, other): ... + def to_string(self, verbose=None, labeler=None, smap=None, compute_values: bool = False): ... + +class BooleanConstant(BooleanValue): + value: Incomplete + def __init__(self, value) -> None: ... + def is_constant(self): ... + def is_fixed(self): ... + def is_potentially_variable(self): ... + def __nonzero__(self): ... + def __bool__(self) -> bool: ... + def __call__(self, exception=...): ... + def pprint(self, ostream=None, verbose: bool = False) -> None: ... diff --git a/stubs/pyomo/core/expr/calculus/__init__.pyi b/stubs/pyomo/core/expr/calculus/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/core/expr/calculus/derivatives.pyi b/stubs/pyomo/core/expr/calculus/derivatives.pyi new file mode 100644 index 000000000..d9decd230 --- /dev/null +++ b/stubs/pyomo/core/expr/calculus/derivatives.pyi @@ -0,0 +1,11 @@ +import enum + +from .diff_with_pyomo import reverse_ad as reverse_ad +from .diff_with_pyomo import reverse_sd as reverse_sd + +class Modes(str, enum.Enum): + sympy = 'sympy' + reverse_symbolic = 'reverse_symbolic' + reverse_numeric = 'reverse_numeric' + +def differentiate(expr, wrt=None, wrt_list=None, mode=...): ... diff --git a/stubs/pyomo/core/expr/calculus/diff_with_pyomo.pyi b/stubs/pyomo/core/expr/calculus/diff_with_pyomo.pyi new file mode 100644 index 000000000..8f4018ee0 --- /dev/null +++ b/stubs/pyomo/core/expr/calculus/diff_with_pyomo.pyi @@ -0,0 +1,26 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.core.expr import cos as cos +from pyomo.core.expr import exp as exp +from pyomo.core.expr import log as log +from pyomo.core.expr import sin as sin +from pyomo.core.expr.numvalue import is_constant as is_constant +from pyomo.core.expr.numvalue import value as value +from pyomo.core.expr.visitor import ExpressionValueVisitor as ExpressionValueVisitor +from pyomo.core.expr.visitor import nonpyomo_leaf_types as nonpyomo_leaf_types + +class DifferentiationException(Exception): ... + +class _LeafToRootVisitor(ExpressionValueVisitor): + val_dict: Incomplete + der_dict: Incomplete + expr_list: Incomplete + value_func: Incomplete + operation_func: Incomplete + def __init__(self, val_dict, der_dict, expr_list, numeric: bool = True) -> None: ... + def visit(self, node, values): ... + def visiting_potential_leaf(self, node): ... + +def reverse_ad(expr): ... +def reverse_sd(expr): ... diff --git a/stubs/pyomo/core/expr/calculus/diff_with_sympy.pyi b/stubs/pyomo/core/expr/calculus/diff_with_sympy.pyi new file mode 100644 index 000000000..d641451a1 --- /dev/null +++ b/stubs/pyomo/core/expr/calculus/diff_with_sympy.pyi @@ -0,0 +1,7 @@ +from pyomo.core.expr.sympy_tools import sympy2pyomo_expression as sympy2pyomo_expression +from pyomo.core.expr.sympy_tools import sympy_available as sympy_available +from pyomo.core.expr.sympy_tools import sympyify_expression as sympyify_expression + +differentiate_available = sympy_available + +def differentiate(expr, wrt=None, wrt_list=None): ... diff --git a/stubs/pyomo/core/expr/cnf_walker.pyi b/stubs/pyomo/core/expr/cnf_walker.pyi new file mode 100644 index 000000000..c3361c0d3 --- /dev/null +++ b/stubs/pyomo/core/expr/cnf_walker.pyi @@ -0,0 +1,19 @@ +from _typeshed import Incomplete +from pyomo.common import DeveloperError as DeveloperError +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.core.expr.logical_expr import special_boolean_atom_types as special_boolean_atom_types +from pyomo.core.expr.numvalue import native_types as native_types +from pyomo.core.expr.numvalue import value as value +from pyomo.core.expr.sympy_tools import Pyomo2SympyVisitor as Pyomo2SympyVisitor +from pyomo.core.expr.sympy_tools import PyomoSympyBimap as PyomoSympyBimap +from pyomo.core.expr.sympy_tools import sympy as sympy +from pyomo.core.expr.sympy_tools import sympy2pyomo_expression as sympy2pyomo_expression + +class CNF_Pyomo2SympyVisitor(Pyomo2SympyVisitor): + boolean_variable_list: Incomplete + special_atom_map: Incomplete + def __init__(self, object_map, bool_varlist) -> None: ... + def beforeChild(self, node, child, child_idx): ... + +def to_cnf(expr, bool_varlist=None, bool_var_to_special_atoms=None): ... diff --git a/stubs/pyomo/core/expr/compare.pyi b/stubs/pyomo/core/expr/compare.pyi new file mode 100644 index 000000000..86c9da94d --- /dev/null +++ b/stubs/pyomo/core/expr/compare.pyi @@ -0,0 +1,57 @@ +import collections + +from _typeshed import Incomplete +from pyomo.common.collections import Sequence as Sequence +from pyomo.common.errors import PyomoException as PyomoException +from pyomo.common.formatting import tostr as tostr +from pyomo.common.numeric_types import native_types as native_types +from pyomo.core.expr import AbsExpression as AbsExpression +from pyomo.core.expr import DivisionExpression as DivisionExpression +from pyomo.core.expr import EqualityExpression as EqualityExpression +from pyomo.core.expr import Expr_ifExpression as Expr_ifExpression +from pyomo.core.expr import ExpressionBase as ExpressionBase +from pyomo.core.expr import ExternalFunctionExpression as ExternalFunctionExpression +from pyomo.core.expr import GetItemExpression as GetItemExpression +from pyomo.core.expr import InequalityExpression as InequalityExpression +from pyomo.core.expr import LinearExpression as LinearExpression +from pyomo.core.expr import MonomialTermExpression as MonomialTermExpression +from pyomo.core.expr import NegationExpression as NegationExpression +from pyomo.core.expr import NPV_AbsExpression as NPV_AbsExpression +from pyomo.core.expr import NPV_DivisionExpression as NPV_DivisionExpression +from pyomo.core.expr import NPV_ExternalFunctionExpression as NPV_ExternalFunctionExpression +from pyomo.core.expr import NPV_NegationExpression as NPV_NegationExpression +from pyomo.core.expr import NPV_PowExpression as NPV_PowExpression +from pyomo.core.expr import NPV_ProductExpression as NPV_ProductExpression +from pyomo.core.expr import NPV_SumExpression as NPV_SumExpression +from pyomo.core.expr import NPV_UnaryFunctionExpression as NPV_UnaryFunctionExpression +from pyomo.core.expr import NumericValue as NumericValue +from pyomo.core.expr import PowExpression as PowExpression +from pyomo.core.expr import ProductExpression as ProductExpression +from pyomo.core.expr import RangedExpression as RangedExpression +from pyomo.core.expr import SumExpression as SumExpression +from pyomo.core.expr import UnaryFunctionExpression as UnaryFunctionExpression + +from .numvalue import nonpyomo_leaf_types as nonpyomo_leaf_types +from .visitor import StreamBasedExpressionVisitor as StreamBasedExpressionVisitor + +def handle_expression(node: ExpressionBase, pn: list): ... +def handle_named_expression(node, pn: list, include_named_exprs: bool = True): ... +def handle_unary_expression(node: UnaryFunctionExpression, pn: list): ... +def handle_external_function_expression(node: ExternalFunctionExpression, pn: list): ... +def handle_sequence(node: collections.abc.Sequence, pn: list): ... +def handle_inequality(node: collections.abc.Sequence, pn: list): ... + +handler: Incomplete + +class PrefixVisitor(StreamBasedExpressionVisitor): + def __init__(self, include_named_exprs: bool = True) -> None: ... + def initializeWalker(self, expr): ... + def enterNode(self, node): ... + def finalizeResult(self, result): ... + +def convert_expression_to_prefix_notation(expr, include_named_exprs: bool = True): ... +def compare_expressions(expr1, expr2, include_named_exprs: bool = True): ... +def assertExpressionsEqual(test, a, b, include_named_exprs: bool = True, places=None) -> None: ... +def assertExpressionsStructurallyEqual( + test, a, b, include_named_exprs: bool = True, places=None +) -> None: ... diff --git a/stubs/pyomo/core/expr/expr_common.pyi b/stubs/pyomo/core/expr/expr_common.pyi new file mode 100644 index 000000000..4fc59dbf7 --- /dev/null +++ b/stubs/pyomo/core/expr/expr_common.pyi @@ -0,0 +1,48 @@ +from contextlib import nullcontext + +from pyomo.common import enums as enums +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.modeling import NOTSET as NOTSET + +TO_STRING_VERBOSE: bool + +class Mode(enums.IntEnum): + coopr_trees = 1 + coopr3_trees = 3 + pyomo4_trees = 4 + pyomo5_trees = 5 + pyomo6_trees = 6 + CURRENT = pyomo6_trees + +class OperatorAssociativity(enums.IntEnum): + RIGHT_TO_LEFT = -1 + NON_ASSOCIATIVE = 0 + LEFT_TO_RIGHT = 1 + +class ExpressionType(enums.Enum): + NUMERIC = 0 + RELATIONAL = 1 + LOGICAL = 2 + +class NUMERIC_ARG_TYPE(enums.IntEnum): + MUTABLE = -2 + ASNUMERIC = -1 + INVALID = 0 + NATIVE = 1 + NPV = 2 + PARAM = 3 + VAR = 4 + MONOMIAL = 5 + LINEAR = 6 + SUM = 7 + OTHER = 8 + +class RELATIONAL_ARG_TYPE(enums.IntEnum, metaclass=enums.ExtendedEnumType): + __base_enum__ = NUMERIC_ARG_TYPE + INEQUALITY = 100 + INVALID_RELATIONAL = 101 + +class clone_counter(nullcontext): + def __init__(self) -> None: ... + @property + def count(self): ... diff --git a/stubs/pyomo/core/expr/expr_errors.pyi b/stubs/pyomo/core/expr/expr_errors.pyi new file mode 100644 index 000000000..21f55e254 --- /dev/null +++ b/stubs/pyomo/core/expr/expr_errors.pyi @@ -0,0 +1 @@ +from pyomo.common.deprecation import relocated_module_attribute as relocated_module_attribute diff --git a/stubs/pyomo/core/expr/logical_expr.pyi b/stubs/pyomo/core/expr/logical_expr.pyi new file mode 100644 index 000000000..ce6a055b8 --- /dev/null +++ b/stubs/pyomo/core/expr/logical_expr.pyi @@ -0,0 +1,103 @@ +from _typeshed import Incomplete +from pyomo.common.deprecation import RenamedClass as RenamedClass +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.common.deprecation import relocated_module_attribute as relocated_module_attribute +from pyomo.common.errors import DeveloperError as DeveloperError +from pyomo.common.errors import PyomoException as PyomoException + +from .base import ExpressionBase as ExpressionBase +from .boolean_value import BooleanConstant as BooleanConstant +from .boolean_value import BooleanValue as BooleanValue +from .expr_common import ExpressionType as ExpressionType +from .numeric_expr import NumericExpression as NumericExpression +from .numvalue import as_numeric as as_numeric +from .numvalue import is_potentially_variable as is_potentially_variable +from .numvalue import native_logical_types as native_logical_types +from .numvalue import native_numeric_types as native_numeric_types +from .numvalue import native_types as native_types +from .numvalue import value as value + +logger: Incomplete + +class BooleanExpression(ExpressionBase, BooleanValue): + EXPRESSION_SYSTEM: Incomplete + PRECEDENCE: int + def __init__(self, args) -> None: ... + @property + def args(self): ... + +class BooleanExpressionBase(metaclass=RenamedClass): + __renamed__new_class__ = BooleanExpression + __renamed__version__: str + +def lnot(Y): ... +def equivalent(Y1, Y2): ... +def xor(Y1, Y2): ... +def implies(Y1, Y2): ... +def land(*args): ... +def lor(*args): ... +def exactly(n, *args): ... +def atmost(n, *args): ... +def atleast(n, *args): ... +def all_different(*args): ... +def count_if(*args): ... + +class UnaryBooleanExpression(BooleanExpression): + def nargs(self): ... + +class NotExpression(UnaryBooleanExpression): + PRECEDENCE: int + def getname(self, *arg, **kwd): ... + +class BinaryBooleanExpression(BooleanExpression): + def nargs(self): ... + +class EquivalenceExpression(BinaryBooleanExpression): + PRECEDENCE: int + def getname(self, *arg, **kwd): ... + +class XorExpression(BinaryBooleanExpression): + PRECEDENCE: int + def getname(self, *arg, **kwd): ... + +class ImplicationExpression(BinaryBooleanExpression): + PRECEDENCE: int + def getname(self, *arg, **kwd): ... + +class NaryBooleanExpression(BooleanExpression): + def __init__(self, args) -> None: ... + def nargs(self): ... + def getname(self, *arg, **kwd): ... + +class AndExpression(NaryBooleanExpression): + PRECEDENCE: int + def getname(self, *arg, **kwd): ... + def add(self, new_arg): ... + +class OrExpression(NaryBooleanExpression): + PRECEDENCE: int + def getname(self, *arg, **kwd): ... + def add(self, new_arg): ... + +class ExactlyExpression(NaryBooleanExpression): + PRECEDENCE: int + def getname(self, *arg, **kwd): ... + +class AtMostExpression(NaryBooleanExpression): + PRECEDENCE: int + def getname(self, *arg, **kwd): ... + +class AtLeastExpression(NaryBooleanExpression): + PRECEDENCE: int + def getname(self, *arg, **kwd): ... + +class AllDifferentExpression(NaryBooleanExpression): + PRECEDENCE: Incomplete + def getname(self, *arg, **kwd): ... + +class CountIfExpression(NumericExpression): + PRECEDENCE: Incomplete + def nargs(self): ... + def getname(self, *arg, **kwd): ... + +special_boolean_atom_types: Incomplete diff --git a/stubs/pyomo/core/expr/ndarray.pyi b/stubs/pyomo/core/expr/ndarray.pyi new file mode 100644 index 000000000..e3cb0f9a3 --- /dev/null +++ b/stubs/pyomo/core/expr/ndarray.pyi @@ -0,0 +1,4 @@ +from pyomo.common.dependencies import numpy_available as numpy_available + +class NumericNDArray: + def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): ... diff --git a/stubs/pyomo/core/expr/numeric_expr.pyi b/stubs/pyomo/core/expr/numeric_expr.pyi new file mode 100644 index 000000000..a1d607bea --- /dev/null +++ b/stubs/pyomo/core/expr/numeric_expr.pyi @@ -0,0 +1,240 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.deprecation import relocated_module_attribute as relocated_module_attribute +from pyomo.common.errors import DeveloperError as DeveloperError +from pyomo.common.errors import PyomoException as PyomoException +from pyomo.common.formatting import tostr as tostr +from pyomo.common.numeric_types import check_if_numeric_type as check_if_numeric_type +from pyomo.common.numeric_types import native_numeric_types as native_numeric_types +from pyomo.common.numeric_types import native_types as native_types +from pyomo.common.numeric_types import nonpyomo_leaf_types as nonpyomo_leaf_types +from pyomo.common.numeric_types import value as value +from pyomo.core.expr.base import ExpressionBase as ExpressionBase +from pyomo.core.expr.base import NPV_Mixin as NPV_Mixin +from pyomo.core.expr.base import visitor as visitor +from pyomo.core.expr.expr_common import ExpressionType as ExpressionType +from pyomo.core.expr.expr_common import OperatorAssociativity as OperatorAssociativity +from pyomo.core.pyomoobject import PyomoObject as PyomoObject + +logger: Incomplete +_: Incomplete + +def enable_expression_optimizations(zero=None, one=None) -> None: ... + +class mutable_expression: + e: Incomplete + def __enter__(self): ... + def __exit__(self, *args) -> None: ... + +class nonlinear_expression(mutable_expression): + e: Incomplete + def __enter__(self): ... + +class linear_expression(mutable_expression): ... + +class NumericValue(PyomoObject): + __hash__: Incomplete + def getname(self, *args, **kwargs): ... + @property + def name(self): ... + @property + def local_name(self): ... + def is_numeric_type(self): ... + def is_constant(self): ... + def is_fixed(self): ... + def is_potentially_variable(self): ... + def is_relational(self): ... + def is_indexed(self): ... + def polynomial_degree(self): ... + def __bool__(self) -> bool: ... + def __float__(self) -> float: ... + def __int__(self) -> int: ... + def __lt__(self, other): ... + def __gt__(self, other): ... + def __le__(self, other): ... + def __ge__(self, other): ... + def __eq__(self, other): ... + def __add__(self, other): ... + def __sub__(self, other): ... + def __mul__(self, other): ... + def __div__(self, other): ... + def __truediv__(self, other): ... + def __pow__(self, other): ... + def __radd__(self, other): ... + def __rsub__(self, other): ... + def __rmul__(self, other): ... + def __rdiv__(self, other): ... + def __rtruediv__(self, other): ... + def __rpow__(self, other): ... + def __iadd__(self, other): ... + def __isub__(self, other): ... + def __imul__(self, other): ... + def __idiv__(self, other): ... + def __itruediv__(self, other): ... + def __ipow__(self, other): ... + def __neg__(self): ... + def __pos__(self): ... + def __abs__(self): ... + def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): ... + def to_string(self, verbose=None, labeler=None, smap=None, compute_values: bool = False): ... + +class NumericExpression(ExpressionBase, NumericValue): + EXPRESSION_SYSTEM: Incomplete + PRECEDENCE: int + def __init__(self, args) -> None: ... + def nargs(self): ... + @property + def args(self): ... + __class__: Incomplete + def create_potentially_variable_object(self): ... + def polynomial_degree(self): ... + +class Numeric_NPV_Mixin(NPV_Mixin): + def potentially_variable_base_class(self): ... + def __neg__(self): ... + def __abs__(self): ... + +class NegationExpression(NumericExpression): + PRECEDENCE: int + def nargs(self): ... + def getname(self, *args, **kwds): ... + def __neg__(self): ... + +class NPV_NegationExpression(Numeric_NPV_Mixin, NegationExpression): + def __neg__(self): ... + +class ExternalFunctionExpression(NumericExpression): + PRECEDENCE: Incomplete + def __init__(self, args, fcn=None) -> None: ... + def nargs(self): ... + def create_node_with_local_data(self, args, classtype=None): ... + def getname(self, *args, **kwds): ... + def get_arg_units(self): ... + def get_units(self): ... + +class NPV_ExternalFunctionExpression(Numeric_NPV_Mixin, ExternalFunctionExpression): ... + +class PowExpression(NumericExpression): + PRECEDENCE: int + ASSOCIATIVITY: Incomplete + def getname(self, *args, **kwds): ... + +class NPV_PowExpression(Numeric_NPV_Mixin, PowExpression): ... + +class MaxExpression(NumericExpression): + PRECEDENCE: Incomplete + def nargs(self): ... + def getname(self, *args, **kwds): ... + +class NPV_MaxExpression(Numeric_NPV_Mixin, MaxExpression): ... + +class MinExpression(NumericExpression): + PRECEDENCE: Incomplete + def nargs(self): ... + def getname(self, *args, **kwds): ... + +class NPV_MinExpression(Numeric_NPV_Mixin, MinExpression): ... + +class ProductExpression(NumericExpression): + PRECEDENCE: int + def getname(self, *args, **kwds): ... + +class NPV_ProductExpression(Numeric_NPV_Mixin, ProductExpression): ... + +class MonomialTermExpression(ProductExpression): + def getname(self, *args, **kwds): ... + def create_node_with_local_data(self, args, classtype=None): ... + +class DivisionExpression(NumericExpression): + PRECEDENCE: int + def getname(self, *args, **kwds): ... + +class NPV_DivisionExpression(Numeric_NPV_Mixin, DivisionExpression): ... + +class SumExpression(NumericExpression): + PRECEDENCE: int + def __init__(self, args) -> None: ... + def nargs(self): ... + @property + def args(self): ... + def getname(self, *args, **kwds): ... + def add(self, new_arg): ... + +SumExpressionBase = SumExpression + +class LinearExpression(SumExpression): + def __init__(self, args=None, constant=None, linear_coefs=None, linear_vars=None) -> None: ... + @property + def constant(self): ... + @property + def linear_coefs(self): ... + @property + def linear_vars(self): ... + def create_node_with_local_data(self, args, classtype=None): ... + +class NPV_SumExpression(Numeric_NPV_Mixin, LinearExpression): ... + +class _MutableSumExpression(SumExpression): + __class__: Incomplete + def make_immutable(self) -> None: ... + def __iadd__(self, other): ... + +class _MutableLinearExpression(_MutableSumExpression): + __class__: Incomplete + def make_immutable(self) -> None: ... + def __iadd__(self, other): ... + +class _MutableNPVSumExpression(_MutableLinearExpression): + __class__: Incomplete + def make_immutable(self) -> None: ... + def __iadd__(self, other): ... + +class Expr_ifExpression(NumericExpression): + PRECEDENCE: Incomplete + def nargs(self): ... + def getname(self, *args, **kwds): ... + +class NPV_Expr_ifExpression(Numeric_NPV_Mixin, Expr_ifExpression): ... + +class UnaryFunctionExpression(NumericExpression): + PRECEDENCE: Incomplete + def __init__(self, args, name=None, fcn=None) -> None: ... + def nargs(self): ... + def create_node_with_local_data(self, args, classtype=None): ... + def getname(self, *args, **kwds): ... + +class NPV_UnaryFunctionExpression(Numeric_NPV_Mixin, UnaryFunctionExpression): ... + +class AbsExpression(UnaryFunctionExpression): + def __init__(self, arg) -> None: ... + def create_node_with_local_data(self, args, classtype=None): ... + +class NPV_AbsExpression(Numeric_NPV_Mixin, AbsExpression): ... + +def decompose_term(expr): ... + +class LinearDecompositionError(Exception): ... + +def register_arg_type(arg_class, etype) -> None: ... +def ceil(arg): ... +def floor(arg): ... +def exp(arg): ... +def log(arg): ... +def log10(arg): ... +def sqrt(arg): ... +def sin(arg): ... +def cos(arg): ... +def tan(arg): ... +def sinh(arg): ... +def cosh(arg): ... +def tanh(arg): ... +def asin(arg): ... +def acos(arg): ... +def atan(arg): ... +def asinh(arg): ... +def acosh(arg): ... +def atanh(arg): ... +def Expr_if(IF_=None, THEN_=None, ELSE_=None, **kwargs): ... + +NPV_expression_types: Incomplete diff --git a/stubs/pyomo/core/expr/numvalue.pyi b/stubs/pyomo/core/expr/numvalue.pyi new file mode 100644 index 000000000..22e2f61a8 --- /dev/null +++ b/stubs/pyomo/core/expr/numvalue.pyi @@ -0,0 +1,43 @@ +from _typeshed import Incomplete +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.common.deprecation import relocated_module_attribute as relocated_module_attribute +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.common.numeric_types import check_if_numeric_type as check_if_numeric_type +from pyomo.common.numeric_types import native_integer_types as native_integer_types +from pyomo.common.numeric_types import native_logical_types as native_logical_types +from pyomo.common.numeric_types import native_numeric_types as native_numeric_types +from pyomo.common.numeric_types import native_types as native_types +from pyomo.common.numeric_types import nonpyomo_leaf_types as nonpyomo_leaf_types +from pyomo.common.numeric_types import value as value +from pyomo.core.expr.expr_common import ExpressionType as ExpressionType +from pyomo.core.expr.numeric_expr import NumericValue as NumericValue +from pyomo.core.pyomoobject import PyomoObject as PyomoObject + +logger: Incomplete + +class NonNumericValue(PyomoObject): + value: Incomplete + def __init__(self, value) -> None: ... + def __call__(self, exception=...): ... + def is_constant(self): ... + def is_fixed(self): ... + +def is_constant(obj): ... +def is_fixed(obj): ... +def is_variable_type(obj): ... +def is_potentially_variable(obj): ... +def is_numeric_data(obj): ... +def polynomial_degree(obj): ... +def as_numeric(obj): ... +def check_if_numeric_type_and_cache(obj): ... + +class NumericConstant(NumericValue): + value: Incomplete + def __init__(self, value) -> None: ... + def is_constant(self): ... + def is_fixed(self): ... + def __call__(self, exception=...): ... + def pprint(self, ostream=None, verbose: bool = False) -> None: ... + +ZeroConstant: Incomplete diff --git a/stubs/pyomo/core/expr/relational_expr.pyi b/stubs/pyomo/core/expr/relational_expr.pyi new file mode 100644 index 000000000..913761010 --- /dev/null +++ b/stubs/pyomo/core/expr/relational_expr.pyi @@ -0,0 +1,58 @@ +from _typeshed import Incomplete +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.deprecation import relocated_module_attribute as relocated_module_attribute +from pyomo.common.errors import DeveloperError as DeveloperError +from pyomo.common.errors import PyomoException as PyomoException +from pyomo.common.numeric_types import check_if_numeric_type as check_if_numeric_type +from pyomo.common.numeric_types import native_numeric_types as native_numeric_types +from pyomo.common.numeric_types import value as value +from pyomo.core.expr.base import ExpressionBase as ExpressionBase +from pyomo.core.expr.boolean_value import BooleanValue as BooleanValue +from pyomo.core.expr.expr_common import ExpressionType as ExpressionType +from pyomo.core.expr.visitor import polynomial_degree as polynomial_degree +from pyomo.core.pyomoobject import PyomoObject as PyomoObject + +class RelationalExpression(ExpressionBase, BooleanValue): + EXPRESSION_SYSTEM: Incomplete + def __init__(self, args) -> None: ... + def __bool__(self) -> bool: ... + @property + def args(self): ... + def is_relational(self): ... + def is_potentially_variable(self): ... + def polynomial_degree(self): ... + def __eq__(self, other): ... + def __lt__(self, other): ... + def __gt__(self, other): ... + def __le__(self, other): ... + def __ge__(self, other): ... + +class RangedExpression(RelationalExpression): + PRECEDENCE: int + STRICT: Incomplete + def __init__(self, args, strict) -> None: ... + def nargs(self): ... + def create_node_with_local_data(self, args): ... + @property + def strict(self): ... + +class InequalityExpression(RelationalExpression): + PRECEDENCE: int + def __init__(self, args, strict) -> None: ... + def nargs(self): ... + def create_node_with_local_data(self, args): ... + @property + def strict(self): ... + +def inequality(lower=None, body=None, upper=None, strict: bool = False): ... + +class EqualityExpression(RelationalExpression): + PRECEDENCE: int + def nargs(self): ... + def __bool__(self) -> bool: ... + +class NotEqualExpression(RelationalExpression): + def nargs(self): ... + def __bool__(self) -> bool: ... + +def tuple_to_relational_expr(args): ... diff --git a/stubs/pyomo/core/expr/symbol_map.pyi b/stubs/pyomo/core/expr/symbol_map.pyi new file mode 100644 index 000000000..5162a03df --- /dev/null +++ b/stubs/pyomo/core/expr/symbol_map.pyi @@ -0,0 +1,18 @@ +from _typeshed import Incomplete + +class SymbolMap: + byObject: Incomplete + bySymbol: Incomplete + aliases: Incomplete + default_labeler: Incomplete + def __init__(self, labeler=None) -> None: ... + class UnknownSymbol: ... + + def addSymbol(self, obj, symb) -> None: ... + def addSymbols(self, obj_symbol_tuples) -> None: ... + def createSymbol(self, obj, labeler=None, *args): ... + def createSymbols(self, objs, labeler=None, *args) -> None: ... + def getSymbol(self, obj, labeler=None, *args): ... + def alias(self, obj, name) -> None: ... + def getObject(self, symbol): ... + def removeSymbol(self, obj) -> None: ... diff --git a/stubs/pyomo/core/expr/sympy_tools.pyi b/stubs/pyomo/core/expr/sympy_tools.pyi new file mode 100644 index 000000000..6ef946ebb --- /dev/null +++ b/stubs/pyomo/core/expr/sympy_tools.pyi @@ -0,0 +1,39 @@ +import pyomo.core.expr as EXPR +from _typeshed import Incomplete +from pyomo.common import DeveloperError as DeveloperError +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.errors import NondifferentiableError as NondifferentiableError +from pyomo.core.expr.numvalue import native_types as native_types +from pyomo.core.expr.numvalue import value as value + +sympy: Incomplete +sympy_available: Incomplete + +class PyomoSympyBimap: + pyomo2sympy: Incomplete + sympy2pyomo: Incomplete + i: int + def __init__(self) -> None: ... + def getPyomoSymbol(self, sympy_object, default=None): ... + def getSympySymbol(self, pyomo_object): ... + def sympyVars(self): ... + +class Pyomo2SympyVisitor(EXPR.StreamBasedExpressionVisitor): + object_map: Incomplete + keep_mutable_parameters: Incomplete + def __init__(self, object_map, keep_mutable_parameters: bool = False) -> None: ... + def initializeWalker(self, expr): ... + def exitNode(self, node, values): ... + def beforeChild(self, node, child, child_idx): ... + +class Sympy2PyomoVisitor(EXPR.StreamBasedExpressionVisitor): + object_map: Incomplete + def __init__(self, object_map) -> None: ... + def initializeWalker(self, expr): ... + def enterNode(self, node): ... + def exitNode(self, node, values): ... + def beforeChild(self, node, child, child_idx): ... + +def sympyify_expression(expr, keep_mutable_parameters: bool = False): ... +def sympy2pyomo_expression(expr, object_map): ... diff --git a/stubs/pyomo/core/expr/taylor_series.pyi b/stubs/pyomo/core/expr/taylor_series.pyi new file mode 100644 index 000000000..ba1b5fb97 --- /dev/null +++ b/stubs/pyomo/core/expr/taylor_series.pyi @@ -0,0 +1,8 @@ +from _typeshed import Incomplete +from pyomo.core.expr import differentiate as differentiate +from pyomo.core.expr import identify_variables as identify_variables +from pyomo.core.expr import value as value + +logger: Incomplete + +def taylor_series_expansion(expr, diff_mode=..., order: int = 1): ... diff --git a/stubs/pyomo/core/expr/template_expr.pyi b/stubs/pyomo/core/expr/template_expr.pyi new file mode 100644 index 000000000..47abd5178 --- /dev/null +++ b/stubs/pyomo/core/expr/template_expr.pyi @@ -0,0 +1,206 @@ +import types + +from _typeshed import Incomplete +from pyomo.common.collections import MutableMapping as MutableMapping +from pyomo.common.errors import TemplateExpressionError as TemplateExpressionError +from pyomo.common.gc_manager import PauseGC as PauseGC +from pyomo.core.expr.base import ExpressionArgs_Mixin as ExpressionArgs_Mixin +from pyomo.core.expr.base import ExpressionBase as ExpressionBase +from pyomo.core.expr.base import NPV_Mixin as NPV_Mixin +from pyomo.core.expr.logical_expr import BooleanExpression as BooleanExpression +from pyomo.core.expr.numeric_expr import ARG_TYPE as ARG_TYPE +from pyomo.core.expr.numeric_expr import Numeric_NPV_Mixin as Numeric_NPV_Mixin +from pyomo.core.expr.numeric_expr import NumericExpression as NumericExpression +from pyomo.core.expr.numeric_expr import SumExpression as SumExpression +from pyomo.core.expr.numeric_expr import mutable_expression as mutable_expression +from pyomo.core.expr.numeric_expr import register_arg_type as register_arg_type +from pyomo.core.expr.numvalue import NumericValue as NumericValue +from pyomo.core.expr.numvalue import as_numeric as as_numeric +from pyomo.core.expr.numvalue import is_constant as is_constant +from pyomo.core.expr.numvalue import native_types as native_types +from pyomo.core.expr.numvalue import nonpyomo_leaf_types as nonpyomo_leaf_types +from pyomo.core.expr.numvalue import value as value +from pyomo.core.expr.relational_expr import tuple_to_relational_expr as tuple_to_relational_expr +from pyomo.core.expr.visitor import ExpressionReplacementVisitor as ExpressionReplacementVisitor +from pyomo.core.expr.visitor import StreamBasedExpressionVisitor as StreamBasedExpressionVisitor +from pyomo.core.expr.visitor import expression_to_string as expression_to_string + +logger: Incomplete + +class _NotSpecified: ... + +class GetItemExpression(ExpressionBase): + PRECEDENCE: int + def __new__(cls, args=()): ... + def __getattr__(self, attr): ... + def __iter__(self): ... + def __len__(self) -> int: ... + def getname(self, *args, **kwds): ... + def nargs(self): ... + +class Numeric_GetItemExpression(GetItemExpression, NumericExpression): + def nargs(self): ... + +class NPV_Numeric_GetItemExpression(Numeric_NPV_Mixin, Numeric_GetItemExpression): ... +class Boolean_GetItemExpression(GetItemExpression, BooleanExpression): ... +class NPV_Boolean_GetItemExpression(NPV_Mixin, Boolean_GetItemExpression): ... +class Structural_GetItemExpression(ExpressionArgs_Mixin, GetItemExpression): ... +class NPV_Structural_GetItemExpression(NPV_Mixin, Structural_GetItemExpression): ... + +class GetAttrExpression(ExpressionBase): + PRECEDENCE: int + def __new__(cls, args=()): ... + def __getattr__(self, attr): ... + def __getitem__(self, *idx): ... + def __iter__(self): ... + def __len__(self) -> int: ... + def __call__(self, *args, **kwargs): ... + def getname(self, *args, **kwds): ... + def nargs(self): ... + +class Numeric_GetAttrExpression(GetAttrExpression, NumericExpression): ... +class NPV_Numeric_GetAttrExpression(Numeric_NPV_Mixin, Numeric_GetAttrExpression): ... +class Boolean_GetAttrExpression(GetAttrExpression, BooleanExpression): ... +class NPV_Boolean_GetAttrExpression(NPV_Mixin, Boolean_GetAttrExpression): ... +class Structural_GetAttrExpression(ExpressionArgs_Mixin, GetAttrExpression): ... +class NPV_Structural_GetAttrExpression(NPV_Mixin, Structural_GetAttrExpression): ... + +class CallExpression(NumericExpression): + PRECEDENCE: Incomplete + def __init__(self, args, kwargs) -> None: ... + def nargs(self): ... + def __getattr__(self, attr): ... + def __getitem__(self, *idx): ... + def __iter__(self): ... + def __len__(self) -> int: ... + def getname(self, *args, **kwds): ... + +class _TemplateSumExpression_argList: + def __init__(self, TSE) -> None: ... + def __len__(self) -> int: ... + def __getitem__(self, i): ... + def __enter__(self) -> None: ... + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: types.TracebackType | None, + ) -> None: ... + +class TemplateSumExpression(NumericExpression): + PRECEDENCE: int + def __init__(self, args, _iters) -> None: ... + def nargs(self): ... + @property + def args(self): ... + def template_args(self): ... + def template_iters(self): ... + def create_node_with_local_data(self, args): ... + def getname(self, *args, **kwds): ... + def is_potentially_variable(self): ... + def to_string(self, verbose=None, smap=None): ... + +class IndexTemplate(NumericValue): + def __init__(self, _set, index: int = 0, _id=None, _group=None) -> None: ... + def __deepcopy__(self, memo): ... + def __call__(self, exception: bool = True): ... + def is_fixed(self): ... + def is_potentially_variable(self): ... + def getname(self, fully_qualified: bool = False, name_buffer=None, relative_to=None): ... + def set_value(self, values=..., lock=None) -> None: ... + def lock(self, lock): ... + def unlock(self, lock) -> None: ... + +class _TemplateResolver(StreamBasedExpressionVisitor): + def beforeChild(self, node, child, child_idx): ... + def exitNode(self, node, args): ... + def initializeWalker(self, expr): ... + +def resolve_template(expr): ... + +class _wildcard_info: + source: Incomplete + original_value: Incomplete + objects: Incomplete + def __init__(self, src, obj) -> None: ... + value: Incomplete + def advance(self) -> None: ... + iter: Incomplete + def reset(self) -> None: ... + def restore(self) -> None: ... + +class ReplaceTemplateExpression(ExpressionReplacementVisitor): + template_types: Incomplete + substituter: Incomplete + substituter_args: Incomplete + def __init__(self, substituter, *args, **kwargs) -> None: ... + def beforeChild(self, node, child, child_idx): ... + +def substitute_template_expression(expr, substituter, *args, **kwargs): ... + +class _GetItemIndexer: + def __init__(self, expr) -> None: ... + def nargs(self): ... + def arg(self, i): ... + @property + def base(self): ... + @property + def args(self): ... + def __hash__(self): ... + def __eq__(self, other): ... + +def substitute_getitem_with_param(expr, _map): ... +def substitute_template_with_value(expr): ... + +class _set_iterator_template_generator: + context: Incomplete + def __init__(self, _set, context) -> None: ... + def __iter__(self): ... + def __next__(self): ... + next = __next__ + +class _template_iter_context: + cache: Incomplete + def __init__(self) -> None: ... + def get_iter(self, _set): ... + def npop_cache(self, n): ... + def next_id(self): ... + def next_group(self): ... + def sum_template(self, generator): ... + +class _template_iter_manager: + class _iter_wrapper: + def __init__(self, cls, context) -> None: ... + def acquire(self) -> None: ... + def release(self) -> None: ... + + class _pause_template_iter_manager: + iter_manager: Incomplete + def __init__(self, iter_manager) -> None: ... + def __enter__(self): ... + def __exit__( + self, + et: type[BaseException] | None, + ev: BaseException | None, + tb: types.TracebackType | None, + ) -> None: ... + + paused: bool + context: Incomplete + iters: Incomplete + builtin_sum: Incomplete + def __init__(self) -> None: ... + def init(self, context, *iter_fcns): ... + def acquire(self) -> None: ... + def release(self) -> None: ... + def __enter__(self): ... + def __exit__( + self, + et: type[BaseException] | None, + ev: BaseException | None, + tb: types.TracebackType | None, + ) -> None: ... + def pause(self): ... + +def templatize_rule(block, rule, index_set): ... +def templatize_constraint(con): ... diff --git a/stubs/pyomo/core/expr/visitor.pyi b/stubs/pyomo/core/expr/visitor.pyi new file mode 100644 index 000000000..c06bfdf89 --- /dev/null +++ b/stubs/pyomo/core/expr/visitor.pyi @@ -0,0 +1,146 @@ +import inspect +from collections.abc import Generator + +from _typeshed import Incomplete +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.common.errors import DeveloperError as DeveloperError +from pyomo.common.errors import TemplateExpressionError as TemplateExpressionError +from pyomo.common.numeric_types import native_numeric_types as native_numeric_types +from pyomo.common.numeric_types import native_types as native_types +from pyomo.common.numeric_types import nonpyomo_leaf_types as nonpyomo_leaf_types +from pyomo.common.numeric_types import value as value +from pyomo.core.expr.symbol_map import SymbolMap as SymbolMap + +logger: Incomplete +currentframe: Incomplete +currentframe = inspect.currentframe + +def get_stack_depth(): ... + +RECURSION_LIMIT: int + +class RevertToNonrecursive(Exception): ... + +class StreamBasedExpressionVisitor: + client_methods: Incomplete + recursion_stack: Incomplete + def __init__(self, **kwds) -> None: ... + def walk_expression(self, expr): ... + def walk_expression_nonrecursive(self, expr): ... + +class SimpleExpressionVisitor: + def visit(self, node) -> None: ... + def finalize(self) -> None: ... + def xbfs(self, node): ... + def xbfs_yield_leaves(self, node) -> Generator[Incomplete]: ... + +class ExpressionValueVisitor: + def visit(self, node, values) -> None: ... + def visiting_potential_leaf(self, node) -> None: ... + def finalize(self, ans): ... + def dfs_postorder_stack(self, node): ... + +def replace_expressions( + expr, + substitution_map, + descend_into_named_expressions: bool = True, + remove_named_expressions: bool = True, +): ... + +class ExpressionReplacementVisitor(StreamBasedExpressionVisitor): + substitute: Incomplete + enter_named_expr: Incomplete + rm_named_expr: Incomplete + def __init__( + self, + substitute=None, + descend_into_named_expressions: bool = True, + remove_named_expressions: bool = True, + ) -> None: ... + def initializeWalker(self, expr): ... + def beforeChild(self, node, child, child_idx): ... + def enterNode(self, node): ... + def acceptChildResult(self, node, data, child_result, child_idx): ... + def exitNode(self, node, data): ... + def dfs_postorder_stack(self, expr): ... + +def evaluate_fixed_subexpressions( + expr, descend_into_named_expressions: bool = True, remove_named_expressions: bool = True +): ... + +class EvaluateFixedSubexpressionVisitor(ExpressionReplacementVisitor): + def __init__( + self, descend_into_named_expressions: bool = False, remove_named_expressions: bool = False + ) -> None: ... + def beforeChild(self, node, child, child_idx): ... + +def clone_expression(expr, substitute=None): ... +def sizeof_expression(expr): ... + +class _EvaluationVisitor(ExpressionValueVisitor): + exception: Incomplete + def __init__(self, exception) -> None: ... + def visit(self, node, values): ... + def visiting_potential_leaf(self, node): ... + +class FixedExpressionError(Exception): + def __init__(self, *args, **kwds) -> None: ... + +class NonConstantExpressionError(Exception): + def __init__(self, *args, **kwds) -> None: ... + +class _EvaluateConstantExpressionVisitor(ExpressionValueVisitor): + def visit(self, node, values): ... + def visiting_potential_leaf(self, node): ... + +def evaluate_expression(exp, exception: bool = True, constant: bool = False): ... + +class _ComponentVisitor(StreamBasedExpressionVisitor): + def __init__(self, types) -> None: ... + def initializeWalker(self, expr): ... + def finalizeResult(self, result): ... + def exitNode(self, node, data) -> None: ... + +def identify_components(expr, component_types) -> Generator[Incomplete, Incomplete]: ... + +class IdentifyVariableVisitor(StreamBasedExpressionVisitor): + def __init__(self, include_fixed: bool = False, named_expression_cache=None) -> None: ... + def initializeWalker(self, expr): ... + def beforeChild(self, parent, child, index): ... + def exitNode(self, node, data) -> None: ... + def finalizeResult(self, result): ... + +def identify_variables( + expr, include_fixed: bool = True, named_expression_cache=None +) -> Generator[Incomplete, Incomplete]: ... + +class IdentifyMutableParamVisitor(IdentifyVariableVisitor): + def __init__(self) -> None: ... + def beforeChild(self, parent, child, index): ... + +def identify_mutable_parameters(expr) -> Generator[Incomplete, Incomplete]: ... + +class _PolynomialDegreeVisitor(ExpressionValueVisitor): + def visit(self, node, values): ... + def visiting_potential_leaf(self, node): ... + +def polynomial_degree(node): ... + +class _IsFixedVisitor(ExpressionValueVisitor): + def visit(self, node, values): ... + def visiting_potential_leaf(self, node): ... + +LEFT_TO_RIGHT: Incomplete +RIGHT_TO_LEFT: Incomplete + +class _ToStringVisitor(ExpressionValueVisitor): + verbose: Incomplete + smap: Incomplete + def __init__(self, verbose, smap) -> None: ... + def visit(self, node, values): ... + def visiting_potential_leaf(self, node): ... + +def expression_to_string( + expr, verbose=None, labeler=None, smap=None, compute_values: bool = False +): ... diff --git a/stubs/pyomo/core/kernel/__init__.pyi b/stubs/pyomo/core/kernel/__init__.pyi new file mode 100644 index 000000000..499c58296 --- /dev/null +++ b/stubs/pyomo/core/kernel/__init__.pyi @@ -0,0 +1,64 @@ +from pyomo.common.deprecation import moved_module as moved_module +from pyomo.common.deprecation import relocated_module_attribute as relocated_module_attribute +from pyomo.core.expr import Expr_if as Expr_if +from pyomo.core.expr import acos as acos +from pyomo.core.expr import acosh as acosh +from pyomo.core.expr import asin as asin +from pyomo.core.expr import asinh as asinh +from pyomo.core.expr import atan as atan +from pyomo.core.expr import atanh as atanh +from pyomo.core.expr import atleast as atleast +from pyomo.core.expr import atmost as atmost +from pyomo.core.expr import boolean_value as boolean_value +from pyomo.core.expr import ceil as ceil +from pyomo.core.expr import cos as cos +from pyomo.core.expr import cosh as cosh +from pyomo.core.expr import equivalent as equivalent +from pyomo.core.expr import exactly as exactly +from pyomo.core.expr import exp as exp +from pyomo.core.expr import floor as floor +from pyomo.core.expr import implies as implies +from pyomo.core.expr import inequality as inequality +from pyomo.core.expr import land as land +from pyomo.core.expr import linear_expression as linear_expression +from pyomo.core.expr import lnot as lnot +from pyomo.core.expr import log as log +from pyomo.core.expr import log10 as log10 +from pyomo.core.expr import logical_expr as logical_expr +from pyomo.core.expr import lor as lor +from pyomo.core.expr import nonlinear_expression as nonlinear_expression +from pyomo.core.expr import numeric_expr as numeric_expr +from pyomo.core.expr import numvalue as numvalue +from pyomo.core.expr import sin as sin +from pyomo.core.expr import sinh as sinh +from pyomo.core.expr import sqrt as sqrt +from pyomo.core.expr import tan as tan +from pyomo.core.expr import tanh as tanh +from pyomo.core.expr import xor as xor +from pyomo.core.expr.boolean_value import BooleanValue as BooleanValue +from pyomo.core.expr.calculus.derivatives import differentiate as differentiate +from pyomo.core.expr.numvalue import NumericValue as NumericValue +from pyomo.core.expr.numvalue import ZeroConstant as ZeroConstant +from pyomo.core.expr.numvalue import is_constant as is_constant +from pyomo.core.expr.numvalue import is_fixed as is_fixed +from pyomo.core.expr.numvalue import is_potentially_variable as is_potentially_variable +from pyomo.core.expr.numvalue import is_variable_type as is_variable_type +from pyomo.core.expr.numvalue import native_numeric_types as native_numeric_types +from pyomo.core.expr.numvalue import native_types as native_types +from pyomo.core.expr.numvalue import polynomial_degree as polynomial_degree +from pyomo.core.expr.numvalue import value as value +from pyomo.core.expr.taylor_series import taylor_series_expansion as taylor_series_expansion +from pyomo.core.kernel import base as base +from pyomo.core.kernel import block as block +from pyomo.core.kernel import constraint as constraint +from pyomo.core.kernel import expression as expression +from pyomo.core.kernel import heterogeneous_container as heterogeneous_container +from pyomo.core.kernel import homogeneous_container as homogeneous_container +from pyomo.core.kernel import matrix_constraint as matrix_constraint +from pyomo.core.kernel import objective as objective +from pyomo.core.kernel import parameter as parameter +from pyomo.core.kernel import piecewise_library as piecewise_library +from pyomo.core.kernel import set_types as set_types +from pyomo.core.kernel import sos as sos +from pyomo.core.kernel import suffix as suffix +from pyomo.core.kernel import variable as variable diff --git a/stubs/pyomo/core/kernel/base.pyi b/stubs/pyomo/core/kernel/base.pyi new file mode 100644 index 000000000..cf93e8520 --- /dev/null +++ b/stubs/pyomo/core/kernel/base.pyi @@ -0,0 +1,35 @@ +from _typeshed import Incomplete +from pyomo.common.autoslots import AutoSlots as AutoSlots + +class _no_ctype: ... + +class ICategorizedObject(AutoSlots.Mixin): + __autoslot_mappers__: Incomplete + @property + def ctype(self): ... + @property + def parent(self): ... + @property + def storage_key(self): ... + @property + def active(self): ... + @active.setter + def active(self, value) -> None: ... + def activate(self) -> None: ... + def deactivate(self) -> None: ... + def getname( + self, fully_qualified: bool = False, name_buffer={}, convert=..., relative_to=None + ): ... + @property + def name(self): ... + @property + def local_name(self): ... + def clone(self): ... + def __deepcopy__(self, memo): ... + +class ICategorizedObjectContainer(ICategorizedObject): + def activate(self, shallow: bool = True) -> None: ... + def deactivate(self, shallow: bool = True) -> None: ... + def child(self, *args, **kwds) -> None: ... + def children(self, *args, **kwds) -> None: ... + def components(self, *args, **kwds) -> None: ... diff --git a/stubs/pyomo/core/kernel/block.pyi b/stubs/pyomo/core/kernel/block.pyi new file mode 100644 index 000000000..0a2814ac5 --- /dev/null +++ b/stubs/pyomo/core/kernel/block.pyi @@ -0,0 +1,35 @@ +from collections.abc import Generator + +from _typeshed import Incomplete +from pyomo.core.expr.symbol_map import SymbolMap as SymbolMap +from pyomo.core.kernel.container_utils import define_simple_containers as define_simple_containers +from pyomo.core.kernel.heterogeneous_container import ( + IHeterogeneousContainer as IHeterogeneousContainer, +) +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager + +logger: Incomplete + +class IBlock(IHeterogeneousContainer): + def child(self, key): ... + +class block(IBlock): + def __init__(self) -> None: ... + def child_ctypes(self): ... + def children(self, ctype=...) -> Generator[Incomplete, Incomplete]: ... + def __setattr__(self, name, obj) -> None: ... + def __delattr__(self, name) -> None: ... + def write( + self, + filename, + format=None, + _solver_capability=None, + _called_by_solver: bool = False, + **kwds, + ): ... + def load_solution( + self, + solution, + allow_consistent_values_for_fixed_vars: bool = False, + comparison_tolerance_for_fixed_vars: float = 1e-05, + ) -> None: ... diff --git a/stubs/pyomo/core/kernel/conic.pyi b/stubs/pyomo/core/kernel/conic.pyi new file mode 100644 index 000000000..333fdd3e8 --- /dev/null +++ b/stubs/pyomo/core/kernel/conic.pyi @@ -0,0 +1,132 @@ +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.core.expr import exp as exp +from pyomo.core.expr import value as value +from pyomo.core.expr.numvalue import is_numeric_data as is_numeric_data +from pyomo.core.kernel.block import block as block +from pyomo.core.kernel.constraint import IConstraint as IConstraint +from pyomo.core.kernel.constraint import constraint as constraint +from pyomo.core.kernel.constraint import constraint_tuple as constraint_tuple +from pyomo.core.kernel.constraint import linear_constraint as linear_constraint +from pyomo.core.kernel.variable import IVariable as IVariable +from pyomo.core.kernel.variable import variable as variable +from pyomo.core.kernel.variable import variable_tuple as variable_tuple + +class _ConicBase(IConstraint): + def __init__(self) -> None: ... + @classmethod + def as_domain(cls, *args, **kwds) -> None: ... + def check_convexity_conditions(self, relax: bool = False) -> None: ... + @property + def body(self): ... + @property + def lower(self) -> None: ... + @property + def upper(self): ... + @property + def lb(self) -> None: ... + @property + def ub(self): ... + @property + def rhs(self) -> None: ... + @property + def equality(self): ... + def __call__(self, exception=...): ... + +class quadratic(_ConicBase): + def __init__(self, r, x) -> None: ... + @classmethod + def as_domain(cls, r, x): ... + @property + def r(self): ... + @property + def x(self): ... + def check_convexity_conditions(self, relax: bool = False): ... + +class rotated_quadratic(_ConicBase): + def __init__(self, r1, r2, x) -> None: ... + @classmethod + def as_domain(cls, r1, r2, x): ... + @property + def r1(self): ... + @property + def r2(self): ... + @property + def x(self): ... + def check_convexity_conditions(self, relax: bool = False): ... + +class primal_exponential(_ConicBase): + def __init__(self, r, x1, x2) -> None: ... + @classmethod + def as_domain(cls, r, x1, x2): ... + @property + def r(self): ... + @property + def x1(self): ... + @property + def x2(self): ... + def check_convexity_conditions(self, relax: bool = False): ... + +class primal_power(_ConicBase): + def __init__(self, r1, r2, x, alpha) -> None: ... + @classmethod + def as_domain(cls, r1, r2, x, alpha): ... + @property + def r1(self): ... + @property + def r2(self): ... + @property + def x(self): ... + @property + def alpha(self): ... + def check_convexity_conditions(self, relax: bool = False): ... + +class primal_geomean(_ConicBase): + def __init__(self, r, x) -> None: ... + @classmethod + def as_domain(cls, r, x): ... + @property + def r(self): ... + @property + def x(self): ... + +class dual_exponential(_ConicBase): + def __init__(self, r, x1, x2) -> None: ... + @classmethod + def as_domain(cls, r, x1, x2): ... + @property + def r(self): ... + @property + def x1(self): ... + @property + def x2(self): ... + def check_convexity_conditions(self, relax: bool = False): ... + +class dual_power(_ConicBase): + def __init__(self, r1, r2, x, alpha) -> None: ... + @classmethod + def as_domain(cls, r1, r2, x, alpha): ... + @property + def r1(self): ... + @property + def r2(self): ... + @property + def x(self): ... + @property + def alpha(self): ... + def check_convexity_conditions(self, relax: bool = False): ... + +class dual_geomean(_ConicBase): + def __init__(self, r, x) -> None: ... + @classmethod + def as_domain(cls, r, x): ... + @property + def r(self): ... + @property + def x(self): ... + +class svec_psdcone(_ConicBase): + def __init__(self, x) -> None: ... + @classmethod + def as_domain(cls, x): ... + @property + def x(self): ... diff --git a/stubs/pyomo/core/kernel/constraint.pyi b/stubs/pyomo/core/kernel/constraint.pyi new file mode 100644 index 000000000..f0a1a5089 --- /dev/null +++ b/stubs/pyomo/core/kernel/constraint.pyi @@ -0,0 +1,96 @@ +from _typeshed import Incomplete +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.core.expr.expr_common import ExpressionType as ExpressionType +from pyomo.core.expr.numvalue import ZeroConstant as ZeroConstant +from pyomo.core.expr.numvalue import as_numeric as as_numeric +from pyomo.core.expr.numvalue import is_numeric_data as is_numeric_data +from pyomo.core.expr.numvalue import is_potentially_variable as is_potentially_variable +from pyomo.core.expr.numvalue import value as value +from pyomo.core.expr.relational_expr import EqualityExpression as EqualityExpression +from pyomo.core.expr.relational_expr import InequalityExpression as InequalityExpression +from pyomo.core.expr.relational_expr import RangedExpression as RangedExpression +from pyomo.core.kernel.base import ICategorizedObject as ICategorizedObject +from pyomo.core.kernel.container_utils import define_simple_containers as define_simple_containers + +class IConstraint(ICategorizedObject): + body: Incomplete + lower: Incomplete + upper: Incomplete + lb: Incomplete + ub: Incomplete + rhs: Incomplete + equality: Incomplete + def __call__(self, exception=...): ... + @property + def lslack(self): ... + @property + def uslack(self): ... + @property + def slack(self): ... + @property + def expr(self): ... + @property + def bounds(self): ... + def has_lb(self): ... + def has_ub(self): ... + def to_bounded_expression(self, evaluate_bounds: bool = False): ... + +class _MutableBoundsConstraintMixin: + @property + def lower(self): ... + @lower.setter + def lower(self, lb) -> None: ... + @property + def upper(self): ... + @upper.setter + def upper(self, ub) -> None: ... + @property + def lb(self): ... + @lb.setter + def lb(self, lb) -> None: ... + @property + def ub(self): ... + @ub.setter + def ub(self, ub) -> None: ... + @property + def rhs(self): ... + @rhs.setter + def rhs(self, rhs) -> None: ... + @property + def bounds(self): ... + @bounds.setter + def bounds(self, bounds_tuple) -> None: ... + @property + def equality(self): ... + @equality.setter + def equality(self, equality) -> None: ... + +class constraint(_MutableBoundsConstraintMixin, IConstraint): + lb: Incomplete + ub: Incomplete + rhs: Incomplete + def __init__(self, expr=None, body=None, lb=None, ub=None, rhs=None) -> None: ... + @property + def body(self): ... + @body.setter + def body(self, body) -> None: ... + @property + def expr(self): ... + @expr.setter + def expr(self, expr) -> None: ... + +class linear_constraint(_MutableBoundsConstraintMixin, IConstraint): + lb: Incomplete + ub: Incomplete + rhs: Incomplete + def __init__( + self, variables=None, coefficients=None, terms=None, lb=None, ub=None, rhs=None + ) -> None: ... + @property + def terms(self): ... + @terms.setter + def terms(self, terms) -> None: ... + def __call__(self, exception=...): ... + @property + def body(self): ... + def canonical_form(self, compute_values: bool = True): ... diff --git a/stubs/pyomo/core/kernel/container_utils.pyi b/stubs/pyomo/core/kernel/container_utils.pyi new file mode 100644 index 000000000..b0c60515d --- /dev/null +++ b/stubs/pyomo/core/kernel/container_utils.pyi @@ -0,0 +1,8 @@ +from pyomo.core.kernel.dict_container import DictContainer as DictContainer +from pyomo.core.kernel.list_container import ListContainer as ListContainer +from pyomo.core.kernel.tuple_container import TupleContainer as TupleContainer + +def define_homogeneous_container_type( + namespace, name, container_class, ctype, doc=None, use_slots: bool = True +) -> None: ... +def define_simple_containers(namespace, prefix, ctype, use_slots: bool = True) -> None: ... diff --git a/stubs/pyomo/core/kernel/dict_container.pyi b/stubs/pyomo/core/kernel/dict_container.pyi new file mode 100644 index 000000000..b5e047cdb --- /dev/null +++ b/stubs/pyomo/core/kernel/dict_container.pyi @@ -0,0 +1,19 @@ +import collections.abc + +from _typeshed import Incomplete +from pyomo.core.kernel.homogeneous_container import IHomogeneousContainer as IHomogeneousContainer + +logger: Incomplete + +class DictContainer(IHomogeneousContainer, collections.abc.MutableMapping): + def __init__(self, *args, **kwds) -> None: ... + def child(self, key): ... + def children(self): ... + def __setitem__(self, key, item) -> None: ... + def __delitem__(self, key) -> None: ... + def __getitem__(self, key): ... + def __iter__(self): ... + def __len__(self) -> int: ... + def __contains__(self, key) -> bool: ... + def __eq__(self, other): ... + def __ne__(self, other): ... diff --git a/stubs/pyomo/core/kernel/expression.pyi b/stubs/pyomo/core/kernel/expression.pyi new file mode 100644 index 000000000..6550f6488 --- /dev/null +++ b/stubs/pyomo/core/kernel/expression.pyi @@ -0,0 +1,56 @@ +from _typeshed import Incomplete +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.core.expr.numvalue import NumericValue as NumericValue +from pyomo.core.expr.numvalue import is_constant as is_constant +from pyomo.core.expr.numvalue import is_fixed as is_fixed +from pyomo.core.expr.numvalue import is_numeric_data as is_numeric_data +from pyomo.core.expr.numvalue import is_potentially_variable as is_potentially_variable +from pyomo.core.expr.numvalue import value as value +from pyomo.core.kernel.base import ICategorizedObject as ICategorizedObject +from pyomo.core.kernel.container_utils import define_simple_containers as define_simple_containers + +class IIdentityExpression(NumericValue): + PRECEDENCE: int + ASSOCIATIVITY: Incomplete + @property + def expr(self): ... + def __call__(self, exception=...): ... + def is_fixed(self): ... + def is_parameter_type(self): ... + def is_variable_type(self): ... + def is_named_expression_type(self): ... + def is_expression_type(self, expression_system=None): ... + @property + def args(self): ... + def nargs(self): ... + def arg(self, i): ... + def polynomial_degree(self): ... + def to_string(self, verbose=None, labeler=None, smap=None, compute_values: bool = False): ... + def create_node_with_local_data(self, values): ... + def is_constant(self) -> None: ... + def is_potentially_variable(self) -> None: ... + def clone(self) -> None: ... + +def noclone(expr): ... + +class IExpression(ICategorizedObject, IIdentityExpression): + expr: Incomplete + def is_constant(self): ... + def is_potentially_variable(self): ... + def clone(self): ... + +class expression(IExpression): + def __init__(self, expr=None) -> None: ... + @property + def expr(self): ... + @expr.setter + def expr(self, expr) -> None: ... + +class data_expression(expression): + def is_potentially_variable(self): ... + def polynomial_degree(self): ... + @property + def expr(self): ... + @expr.setter + def expr(self, expr) -> None: ... diff --git a/stubs/pyomo/core/kernel/heterogeneous_container.pyi b/stubs/pyomo/core/kernel/heterogeneous_container.pyi new file mode 100644 index 000000000..507094d23 --- /dev/null +++ b/stubs/pyomo/core/kernel/heterogeneous_container.pyi @@ -0,0 +1,15 @@ +from collections.abc import Generator + +from _typeshed import Incomplete +from pyomo.core.kernel.base import ICategorizedObjectContainer as ICategorizedObjectContainer + +def heterogeneous_containers( + node, ctype=..., active: bool = True, descend_into: bool = True +) -> Generator[Incomplete, Incomplete]: ... + +class IHeterogeneousContainer(ICategorizedObjectContainer): + def collect_ctypes(self, active: bool = True, descend_into: bool = True): ... + def child_ctypes(self, *args, **kwds) -> None: ... + def components( + self, ctype=..., active: bool = True, descend_into: bool = True + ) -> Generator[Incomplete, Incomplete]: ... diff --git a/stubs/pyomo/core/kernel/homogeneous_container.pyi b/stubs/pyomo/core/kernel/homogeneous_container.pyi new file mode 100644 index 000000000..099922625 --- /dev/null +++ b/stubs/pyomo/core/kernel/homogeneous_container.pyi @@ -0,0 +1,7 @@ +from collections.abc import Generator + +from _typeshed import Incomplete +from pyomo.core.kernel.base import ICategorizedObjectContainer as ICategorizedObjectContainer + +class IHomogeneousContainer(ICategorizedObjectContainer): + def components(self, active: bool = True) -> Generator[Incomplete]: ... diff --git a/stubs/pyomo/core/kernel/list_container.pyi b/stubs/pyomo/core/kernel/list_container.pyi new file mode 100644 index 000000000..7601a3c5b --- /dev/null +++ b/stubs/pyomo/core/kernel/list_container.pyi @@ -0,0 +1,13 @@ +import collections.abc + +from _typeshed import Incomplete +from pyomo.core.kernel.tuple_container import TupleContainer as TupleContainer + +logger: Incomplete + +class ListContainer(TupleContainer, collections.abc.MutableSequence): + def __init__(self, *args) -> None: ... + def __setitem__(self, i, item) -> None: ... + def insert(self, i, item) -> None: ... + def __delitem__(self, i) -> None: ... + def reverse(self) -> None: ... diff --git a/stubs/pyomo/core/kernel/matrix_constraint.pyi b/stubs/pyomo/core/kernel/matrix_constraint.pyi new file mode 100644 index 000000000..68968efe8 --- /dev/null +++ b/stubs/pyomo/core/kernel/matrix_constraint.pyi @@ -0,0 +1,83 @@ +from collections.abc import Generator + +from _typeshed import Incomplete +from pyomo.common.dependencies import numpy as numpy +from pyomo.common.dependencies import scipy as scipy +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.core.expr.numvalue import NumericValue as NumericValue +from pyomo.core.expr.numvalue import value as value +from pyomo.core.kernel.constraint import IConstraint as IConstraint +from pyomo.core.kernel.constraint import constraint_tuple as constraint_tuple + +class _MatrixConstraintData(IConstraint): + def __init__(self, index) -> None: ... + @property + def index(self): ... + @property + def terms(self) -> Generator[Incomplete]: ... + def __call__(self, exception=...): ... + @property + def body(self): ... + @property + def lower(self): ... + @lower.setter + def lower(self, lb) -> None: ... + @property + def upper(self): ... + @upper.setter + def upper(self, ub) -> None: ... + @property + def lb(self): ... + @lb.setter + def lb(self, lb) -> None: ... + @property + def ub(self): ... + @ub.setter + def ub(self, ub) -> None: ... + @property + def rhs(self): ... + @rhs.setter + def rhs(self, rhs) -> None: ... + @property + def bounds(self): ... + @bounds.setter + def bounds(self, bounds_tuple) -> None: ... + @property + def equality(self): ... + @equality.setter + def equality(self, equality) -> None: ... + def canonical_form(self, compute_values: bool = True): ... + +class matrix_constraint(constraint_tuple): + def __init__(self, A, lb=None, ub=None, rhs=None, x=None, sparse: bool = True) -> None: ... + @property + def sparse(self): ... + @property + def A(self): ... + @property + def x(self): ... + @x.setter + def x(self, x) -> None: ... + @property + def lb(self): ... + @lb.setter + def lb(self, lb) -> None: ... + @property + def ub(self): ... + @ub.setter + def ub(self, ub) -> None: ... + @property + def rhs(self): ... + @rhs.setter + def rhs(self, rhs) -> None: ... + @property + def equality(self): ... + @equality.setter + def equality(self, equality) -> None: ... + def __call__(self, exception=...): ... + @property + def lslack(self, body=...): ... + @property + def uslack(self, body=...): ... + @property + def slack(self): ... diff --git a/stubs/pyomo/core/kernel/objective.pyi b/stubs/pyomo/core/kernel/objective.pyi new file mode 100644 index 000000000..771d987b3 --- /dev/null +++ b/stubs/pyomo/core/kernel/objective.pyi @@ -0,0 +1,22 @@ +from _typeshed import Incomplete +from pyomo.common.enums import ObjectiveSense as ObjectiveSense +from pyomo.common.enums import maximize as maximize +from pyomo.common.enums import minimize as minimize +from pyomo.core.expr.numvalue import as_numeric as as_numeric +from pyomo.core.kernel.container_utils import define_simple_containers as define_simple_containers +from pyomo.core.kernel.expression import IExpression as IExpression + +class IObjective(IExpression): + sense: Incomplete + def is_minimizing(self): ... + +class objective(IObjective): + def __init__(self, expr=None, sense=...) -> None: ... + @property + def expr(self): ... + @expr.setter + def expr(self, expr) -> None: ... + @property + def sense(self): ... + @sense.setter + def sense(self, sense) -> None: ... diff --git a/stubs/pyomo/core/kernel/parameter.pyi b/stubs/pyomo/core/kernel/parameter.pyi new file mode 100644 index 000000000..0faac7572 --- /dev/null +++ b/stubs/pyomo/core/kernel/parameter.pyi @@ -0,0 +1,30 @@ +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.core.expr.numvalue import NumericValue as NumericValue +from pyomo.core.expr.numvalue import is_numeric_data as is_numeric_data +from pyomo.core.kernel.base import ICategorizedObject as ICategorizedObject +from pyomo.core.kernel.container_utils import define_simple_containers as define_simple_containers + +class IParameter(ICategorizedObject, NumericValue): + def __call__(self, exception=...) -> None: ... + def is_constant(self): ... + def is_parameter_type(self): ... + def is_variable_type(self): ... + def is_fixed(self): ... + def is_potentially_variable(self): ... + def polynomial_degree(self): ... + +class parameter(IParameter): + def __init__(self, value=None) -> None: ... + def __call__(self, exception=...): ... + @property + def value(self): ... + @value.setter + def value(self, value) -> None: ... + +class functional_value(IParameter): + def __init__(self, fn=None) -> None: ... + def __call__(self, exception=...): ... + @property + def fn(self): ... + @fn.setter + def fn(self, fn) -> None: ... diff --git a/stubs/pyomo/core/kernel/piecewise_library/__init__.pyi b/stubs/pyomo/core/kernel/piecewise_library/__init__.pyi new file mode 100644 index 000000000..0bc382934 --- /dev/null +++ b/stubs/pyomo/core/kernel/piecewise_library/__init__.pyi @@ -0,0 +1,3 @@ +from pyomo.core.kernel.piecewise_library import transforms as transforms +from pyomo.core.kernel.piecewise_library import transforms_nd as transforms_nd +from pyomo.core.kernel.piecewise_library import util as util diff --git a/stubs/pyomo/core/kernel/piecewise_library/transforms.pyi b/stubs/pyomo/core/kernel/piecewise_library/transforms.pyi new file mode 100644 index 000000000..7439e0b6e --- /dev/null +++ b/stubs/pyomo/core/kernel/piecewise_library/transforms.pyi @@ -0,0 +1,124 @@ +from _typeshed import Incomplete +from pyomo.core.kernel.block import block as block +from pyomo.core.kernel.constraint import constraint_list as constraint_list +from pyomo.core.kernel.constraint import constraint_tuple as constraint_tuple +from pyomo.core.kernel.constraint import linear_constraint as linear_constraint +from pyomo.core.kernel.expression import expression as expression +from pyomo.core.kernel.expression import expression_tuple as expression_tuple +from pyomo.core.kernel.piecewise_library.util import ( + PiecewiseValidationError as PiecewiseValidationError, +) +from pyomo.core.kernel.piecewise_library.util import characterize_function as characterize_function +from pyomo.core.kernel.piecewise_library.util import generate_gray_code as generate_gray_code +from pyomo.core.kernel.piecewise_library.util import is_nondecreasing as is_nondecreasing +from pyomo.core.kernel.piecewise_library.util import ( + is_positive_power_of_two as is_positive_power_of_two, +) +from pyomo.core.kernel.piecewise_library.util import log2floor as log2floor +from pyomo.core.kernel.set_types import IntegerSet as IntegerSet +from pyomo.core.kernel.sos import sos2 as sos2 +from pyomo.core.kernel.variable import IVariable as IVariable +from pyomo.core.kernel.variable import variable as variable +from pyomo.core.kernel.variable import variable_dict as variable_dict +from pyomo.core.kernel.variable import variable_list as variable_list +from pyomo.core.kernel.variable import variable_tuple as variable_tuple + +logger: Incomplete +registered_transforms: Incomplete + +class _shadow_list: + def __init__(self, x) -> None: ... + def __len__(self) -> int: ... + def __getitem__(self, i): ... + +def piecewise( + breakpoints, + values, + input=None, + output=None, + bound: str = 'eq', + repn: str = 'sos2', + validate: bool = True, + simplify: bool = True, + equal_slopes_tolerance: float = 1e-06, + require_bounded_input_variable: bool = True, + require_variable_domain_coverage: bool = True, +): ... + +class PiecewiseLinearFunction: + def __init__(self, breakpoints, values, validate: bool = True, **kwds) -> None: ... + def validate(self, equal_slopes_tolerance: float = 1e-06): ... + @property + def breakpoints(self): ... + @property + def values(self): ... + def __call__(self, x): ... + +class TransformedPiecewiseLinearFunction(block): + def __init__( + self, f, input=None, output=None, bound: str = 'eq', validate: bool = True, **kwds + ) -> None: ... + @property + def input(self): ... + @property + def output(self): ... + @property + def bound(self): ... + def validate( + self, + equal_slopes_tolerance: float = 1e-06, + require_bounded_input_variable: bool = True, + require_variable_domain_coverage: bool = True, + ): ... + @property + def breakpoints(self): ... + @property + def values(self): ... + def __call__(self, x): ... + +class piecewise_convex(TransformedPiecewiseLinearFunction): + c: Incomplete + def __init__(self, *args, **kwds) -> None: ... + def validate(self, **kwds): ... + +class piecewise_sos2(TransformedPiecewiseLinearFunction): + c: Incomplete + s: Incomplete + def __init__(self, *args, **kwds) -> None: ... + def validate(self, **kwds): ... + +class piecewise_dcc(TransformedPiecewiseLinearFunction): + v: Incomplete + c: Incomplete + def __init__(self, *args, **kwds) -> None: ... + def validate(self, **kwds): ... + +class piecewise_cc(TransformedPiecewiseLinearFunction): + v: Incomplete + c: Incomplete + def __init__(self, *args, **kwds) -> None: ... + def validate(self, **kwds): ... + +class piecewise_mc(TransformedPiecewiseLinearFunction): + v: Incomplete + c: Incomplete + def __init__(self, *args, **kwds) -> None: ... + def validate(self, **kwds): ... + +class piecewise_inc(TransformedPiecewiseLinearFunction): + v: Incomplete + c: Incomplete + def __init__(self, *args, **kwds) -> None: ... + def validate(self, **kwds): ... + +class piecewise_dlog(TransformedPiecewiseLinearFunction): + v: Incomplete + c: Incomplete + def __init__(self, *args, **kwds) -> None: ... + def validate(self, **kwds): ... + +class piecewise_log(TransformedPiecewiseLinearFunction): + v: Incomplete + c: Incomplete + def __init__(self, *args, **kwds) -> None: ... + def validate(self, **kwds): ... diff --git a/stubs/pyomo/core/kernel/piecewise_library/transforms_nd.pyi b/stubs/pyomo/core/kernel/piecewise_library/transforms_nd.pyi new file mode 100644 index 000000000..49d2a5421 --- /dev/null +++ b/stubs/pyomo/core/kernel/piecewise_library/transforms_nd.pyi @@ -0,0 +1,43 @@ +from _typeshed import Incomplete +from pyomo.core.kernel.block import block as block +from pyomo.core.kernel.constraint import constraint_list as constraint_list +from pyomo.core.kernel.constraint import constraint_tuple as constraint_tuple +from pyomo.core.kernel.constraint import linear_constraint as linear_constraint +from pyomo.core.kernel.expression import expression as expression +from pyomo.core.kernel.expression import expression_tuple as expression_tuple +from pyomo.core.kernel.set_types import IntegerSet as IntegerSet +from pyomo.core.kernel.variable import variable as variable +from pyomo.core.kernel.variable import variable_dict as variable_dict +from pyomo.core.kernel.variable import variable_tuple as variable_tuple + +logger: Incomplete +registered_transforms: Incomplete + +def piecewise_nd(tri, values, input=None, output=None, bound: str = 'eq', repn: str = 'cc'): ... + +class PiecewiseLinearFunctionND: + def __init__(self, tri, values, validate: bool = True, **kwds) -> None: ... + @property + def triangulation(self): ... + @property + def values(self): ... + def __call__(self, x): ... + +class TransformedPiecewiseLinearFunctionND(block): + def __init__(self, f, input=None, output=None, bound: str = 'eq') -> None: ... + @property + def input(self): ... + @property + def output(self): ... + @property + def bound(self): ... + @property + def triangulation(self): ... + @property + def values(self): ... + def __call__(self, x): ... + +class piecewise_nd_cc(TransformedPiecewiseLinearFunctionND): + v: Incomplete + c: Incomplete + def __init__(self, *args, **kwds) -> None: ... diff --git a/stubs/pyomo/core/kernel/piecewise_library/util.pyi b/stubs/pyomo/core/kernel/piecewise_library/util.pyi new file mode 100644 index 000000000..0c38f323c --- /dev/null +++ b/stubs/pyomo/core/kernel/piecewise_library/util.pyi @@ -0,0 +1,15 @@ +from pyomo.common.dependencies import numpy as numpy +from pyomo.common.dependencies import numpy_available as numpy_available +from pyomo.common.dependencies import scipy as scipy +from pyomo.common.dependencies import scipy_available as scipy_available + +class PiecewiseValidationError(Exception): ... + +def is_constant(vals): ... +def is_nondecreasing(vals): ... +def is_nonincreasing(vals): ... +def is_positive_power_of_two(x): ... +def log2floor(n): ... +def generate_gray_code(nbits): ... +def characterize_function(breakpoints, values): ... +def generate_delaunay(variables, num: int = 10, **kwds): ... diff --git a/stubs/pyomo/core/kernel/set_types.pyi b/stubs/pyomo/core/kernel/set_types.pyi new file mode 100644 index 000000000..88fcf147d --- /dev/null +++ b/stubs/pyomo/core/kernel/set_types.pyi @@ -0,0 +1,35 @@ +from _typeshed import Incomplete + +logger: Incomplete + +class RealSet: + @staticmethod + def get_interval(): ... + @staticmethod + def is_continuous(): ... + @staticmethod + def is_integer(): ... + @staticmethod + def is_binary(): ... + +class IntegerSet: + @staticmethod + def get_interval(): ... + @staticmethod + def is_continuous(): ... + @staticmethod + def is_integer(): ... + @staticmethod + def is_binary(): ... + +class BinarySet: + @staticmethod + def get_interval(): ... + @staticmethod + def is_continuous(): ... + @staticmethod + def is_integer(): ... + @staticmethod + def is_binary(): ... + +BooleanSet = BinarySet diff --git a/stubs/pyomo/core/kernel/sos.pyi b/stubs/pyomo/core/kernel/sos.pyi new file mode 100644 index 000000000..25fd49b7d --- /dev/null +++ b/stubs/pyomo/core/kernel/sos.pyi @@ -0,0 +1,24 @@ +from _typeshed import Incomplete +from pyomo.core.expr.numvalue import is_numeric_data as is_numeric_data +from pyomo.core.kernel.base import ICategorizedObject as ICategorizedObject +from pyomo.core.kernel.container_utils import define_simple_containers as define_simple_containers + +class ISOS(ICategorizedObject): + variables: Incomplete + weights: Incomplete + level: Incomplete + def items(self): ... + def __contains__(self, v) -> bool: ... + def __len__(self) -> int: ... + +class sos(ISOS): + def __init__(self, variables, weights=None, level: int = 1) -> None: ... + @property + def variables(self): ... + @property + def weights(self): ... + @property + def level(self): ... + +def sos1(variables, weights=None): ... +def sos2(variables, weights=None): ... diff --git a/stubs/pyomo/core/kernel/suffix.pyi b/stubs/pyomo/core/kernel/suffix.pyi new file mode 100644 index 000000000..84fc60020 --- /dev/null +++ b/stubs/pyomo/core/kernel/suffix.pyi @@ -0,0 +1,55 @@ +from collections.abc import Generator + +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.core.kernel.base import ICategorizedObject as ICategorizedObject +from pyomo.core.kernel.container_utils import ( + define_homogeneous_container_type as define_homogeneous_container_type, +) +from pyomo.core.kernel.dict_container import DictContainer as DictContainer + +logger: Incomplete + +class ISuffix(ComponentMap, ICategorizedObject): + direction: Incomplete + datatype: Incomplete + +class suffix(ISuffix): + LOCAL: int + EXPORT: int + IMPORT: int + IMPORT_EXPORT: int + FLOAT: int + INT: int + def __init__(self, *args, **kwds) -> None: ... + def export_enabled(self): ... + def import_enabled(self): ... + @property + def datatype(self): ... + @datatype.setter + def datatype(self, datatype) -> None: ... + @property + def direction(self): ... + @direction.setter + def direction(self, direction) -> None: ... + def set_all_values(self, value) -> None: ... + def clear_value(self, component) -> None: ... + def clear_all_values(self) -> None: ... + def get_datatype(self): ... + def set_datatype(self, datatype) -> None: ... + def get_direction(self): ... + def set_direction(self, direction) -> None: ... + +def export_suffix_generator( + blk, datatype=..., active: bool = True, descend_into: bool = True +) -> Generator[Incomplete, None, Incomplete]: ... +def import_suffix_generator( + blk, datatype=..., active: bool = True, descend_into: bool = True +) -> Generator[Incomplete, None, Incomplete]: ... +def local_suffix_generator( + blk, datatype=..., active: bool = True, descend_into: bool = True +) -> Generator[Incomplete, None, Incomplete]: ... +def suffix_generator( + blk, datatype=..., active: bool = True, descend_into: bool = True +) -> Generator[Incomplete, None, Incomplete]: ... diff --git a/stubs/pyomo/core/kernel/tuple_container.pyi b/stubs/pyomo/core/kernel/tuple_container.pyi new file mode 100644 index 000000000..d869f5a68 --- /dev/null +++ b/stubs/pyomo/core/kernel/tuple_container.pyi @@ -0,0 +1,16 @@ +import collections.abc + +from pyomo.core.kernel.homogeneous_container import IHomogeneousContainer as IHomogeneousContainer + +class TupleContainer(IHomogeneousContainer, collections.abc.Sequence): + def __init__(self, *args) -> None: ... + def child(self, key): ... + def children(self): ... + def __getitem__(self, i): ... + def __len__(self) -> int: ... + def __eq__(self, other): ... + def __ne__(self, other): ... + def __iter__(self): ... + def __contains__(self, item) -> bool: ... + def index(self, item, start: int = 0, stop=None): ... + def count(self, item): ... diff --git a/stubs/pyomo/core/kernel/variable.pyi b/stubs/pyomo/core/kernel/variable.pyi new file mode 100644 index 000000000..9ed0cd830 --- /dev/null +++ b/stubs/pyomo/core/kernel/variable.pyi @@ -0,0 +1,85 @@ +from _typeshed import Incomplete +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.core.expr.numvalue import NumericValue as NumericValue +from pyomo.core.expr.numvalue import is_numeric_data as is_numeric_data +from pyomo.core.expr.numvalue import value as value +from pyomo.core.kernel.base import ICategorizedObject as ICategorizedObject +from pyomo.core.kernel.container_utils import define_simple_containers as define_simple_containers +from pyomo.core.kernel.set_types import IntegerSet as IntegerSet +from pyomo.core.kernel.set_types import RealSet as RealSet +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager + +class IVariable(ICategorizedObject, NumericValue): + domain_type: Incomplete + lb: Incomplete + ub: Incomplete + value: Incomplete + fixed: Incomplete + stale: Incomplete + @property + def bounds(self): ... + @bounds.setter + def bounds(self, bounds_tuple) -> None: ... + @property + def lb(self): ... + lower: Incomplete + @lb.setter + def lb(self, val) -> None: ... + @property + def ub(self): ... + upper: Incomplete + @ub.setter + def ub(self, val) -> None: ... + def fix(self, value=...) -> None: ... + def unfix(self) -> None: ... + free = unfix + def has_lb(self): ... + def has_ub(self): ... + @property + def lslack(self): ... + @property + def uslack(self): ... + @property + def slack(self): ... + def is_continuous(self): ... + def is_discrete(self): ... + def is_integer(self): ... + def is_binary(self): ... + def is_fixed(self): ... + def is_constant(self): ... + def is_parameter_type(self): ... + def is_variable_type(self): ... + def is_potentially_variable(self): ... + def polynomial_degree(self): ... + def __call__(self, exception=...): ... + +class variable(IVariable): + def __init__( + self, domain_type=None, domain=None, lb=None, ub=None, value=None, fixed: bool = False + ) -> None: ... + @property + def lower(self): ... + @lower.setter + def lower(self, lb) -> None: ... + @property + def upper(self): ... + @upper.setter + def upper(self, ub) -> None: ... + @property + def value(self): ... + @value.setter + def value(self, value) -> None: ... + def set_value(self, value, skip_validation: bool = True) -> None: ... + @property + def fixed(self): ... + @fixed.setter + def fixed(self, fixed) -> None: ... + @property + def stale(self): ... + @stale.setter + def stale(self, stale) -> None: ... + @property + def domain_type(self): ... + @domain_type.setter + def domain_type(self, domain_type) -> None: ... + domain: Incomplete diff --git a/stubs/pyomo/core/plugins/__init__.pyi b/stubs/pyomo/core/plugins/__init__.pyi new file mode 100644 index 000000000..08b671c7f --- /dev/null +++ b/stubs/pyomo/core/plugins/__init__.pyi @@ -0,0 +1 @@ +def load() -> None: ... diff --git a/stubs/pyomo/core/plugins/transform/__init__.pyi b/stubs/pyomo/core/plugins/transform/__init__.pyi new file mode 100644 index 000000000..e6b24df05 --- /dev/null +++ b/stubs/pyomo/core/plugins/transform/__init__.pyi @@ -0,0 +1,9 @@ +from pyomo.core.plugins.transform import add_slack_vars as add_slack_vars +from pyomo.core.plugins.transform import discrete_vars as discrete_vars +from pyomo.core.plugins.transform import expand_connectors as expand_connectors +from pyomo.core.plugins.transform import logical_to_linear as logical_to_linear +from pyomo.core.plugins.transform import lp_dual as lp_dual +from pyomo.core.plugins.transform import nonnegative_transform as nonnegative_transform +from pyomo.core.plugins.transform import radix_linearization as radix_linearization +from pyomo.core.plugins.transform import relax_integrality as relax_integrality +from pyomo.core.plugins.transform import scaling as scaling diff --git a/stubs/pyomo/core/plugins/transform/add_slack_vars.pyi b/stubs/pyomo/core/plugins/transform/add_slack_vars.pyi new file mode 100644 index 000000000..62e24558a --- /dev/null +++ b/stubs/pyomo/core/plugins/transform/add_slack_vars.pyi @@ -0,0 +1,24 @@ +from _typeshed import Incomplete +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.core import Block as Block +from pyomo.core import Constraint as Constraint +from pyomo.core import NonNegativeReals as NonNegativeReals +from pyomo.core import Objective as Objective +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core import Var as Var +from pyomo.core import value as value +from pyomo.core.base import ComponentUID as ComponentUID +from pyomo.core.plugins.transform.hierarchy import ( + NonIsomorphicTransformation as NonIsomorphicTransformation, +) + +def target_list(x): ... + +logger: Incomplete + +class AddSlackVariables(NonIsomorphicTransformation): + CONFIG: Incomplete + def __init__(self, **kwds) -> None: ... diff --git a/stubs/pyomo/core/plugins/transform/discrete_vars.pyi b/stubs/pyomo/core/plugins/transform/discrete_vars.pyi new file mode 100644 index 000000000..3deec7f55 --- /dev/null +++ b/stubs/pyomo/core/plugins/transform/discrete_vars.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete +from pyomo.common import deprecated as deprecated +from pyomo.core.base import Reals as Reals +from pyomo.core.base import Suffix as Suffix +from pyomo.core.base import Transformation as Transformation +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.core.base import Var as Var + +logger: Incomplete + +class RelaxIntegerVars(Transformation): + def __init__(self) -> None: ... + +class RelaxDiscreteVars(RelaxIntegerVars): + def __init__(self, **kwds) -> None: ... + +class FixIntegerVars(Transformation): + def __init__(self) -> None: ... + +class FixDiscreteVars(FixIntegerVars): + def __init__(self, **kwds) -> None: ... diff --git a/stubs/pyomo/core/plugins/transform/eliminate_fixed_vars.pyi b/stubs/pyomo/core/plugins/transform/eliminate_fixed_vars.pyi new file mode 100644 index 000000000..e0c2ce979 --- /dev/null +++ b/stubs/pyomo/core/plugins/transform/eliminate_fixed_vars.pyi @@ -0,0 +1,14 @@ +from pyomo.core import Constraint as Constraint +from pyomo.core import Objective as Objective +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core.base.var import Var as Var +from pyomo.core.base.var import VarData as VarData +from pyomo.core.expr import ExpressionBase as ExpressionBase +from pyomo.core.expr import as_numeric as as_numeric +from pyomo.core.plugins.transform.hierarchy import ( + IsomorphicTransformation as IsomorphicTransformation, +) +from pyomo.core.util import sequence as sequence + +class EliminateFixedVars(IsomorphicTransformation): + def __init__(self, **kwds) -> None: ... diff --git a/stubs/pyomo/core/plugins/transform/equality_transform.pyi b/stubs/pyomo/core/plugins/transform/equality_transform.pyi new file mode 100644 index 000000000..797ebabf6 --- /dev/null +++ b/stubs/pyomo/core/plugins/transform/equality_transform.pyi @@ -0,0 +1,11 @@ +from pyomo.core import NonNegativeReals as NonNegativeReals +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core import Var as Var +from pyomo.core.base.misc import create_name as create_name +from pyomo.core.plugins.transform.hierarchy import ( + IsomorphicTransformation as IsomorphicTransformation, +) +from pyomo.core.plugins.transform.util import collectAbstractComponents as collectAbstractComponents + +class EqualityTransform(IsomorphicTransformation): + def __init__(self, **kwds) -> None: ... diff --git a/stubs/pyomo/core/plugins/transform/expand_connectors.pyi b/stubs/pyomo/core/plugins/transform/expand_connectors.pyi new file mode 100644 index 000000000..92dc64dc1 --- /dev/null +++ b/stubs/pyomo/core/plugins/transform/expand_connectors.pyi @@ -0,0 +1,17 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.core.base import Connector as Connector +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import ConstraintList as ConstraintList +from pyomo.core.base import SortComponents as SortComponents +from pyomo.core.base import Transformation as Transformation +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.core.base import Var as Var +from pyomo.core.base.connector import ConnectorData as ConnectorData +from pyomo.core.base.connector import ScalarConnector as ScalarConnector + +logger: Incomplete + +class ExpandConnectors(Transformation): ... diff --git a/stubs/pyomo/core/plugins/transform/hierarchy.pyi b/stubs/pyomo/core/plugins/transform/hierarchy.pyi new file mode 100644 index 000000000..8a3ca5a84 --- /dev/null +++ b/stubs/pyomo/core/plugins/transform/hierarchy.pyi @@ -0,0 +1,19 @@ +from pyomo.core.base import Transformation as Transformation + +class AbstractTransformation(Transformation): + def __init__(self, **kwds) -> None: ... + +class ConcreteTransformation(Transformation): + def __init__(self, **kwds) -> None: ... + +class IsomorphicTransformation(Transformation): + def __init__(self, **kwds) -> None: ... + +class LinearTransformation(Transformation): + def __init__(self, **kwds) -> None: ... + +class NonIsomorphicTransformation(Transformation): + def __init__(self, **kwds) -> None: ... + +class NonlinearTransformation(Transformation): + def __init__(self, **kwds) -> None: ... diff --git a/stubs/pyomo/core/plugins/transform/logical_to_linear.pyi b/stubs/pyomo/core/plugins/transform/logical_to_linear.pyi new file mode 100644 index 000000000..e982fd3a8 --- /dev/null +++ b/stubs/pyomo/core/plugins/transform/logical_to_linear.pyi @@ -0,0 +1,49 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.errors import DeveloperError as DeveloperError +from pyomo.common.errors import MouseTrap as MouseTrap +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.contrib.fbbt.fbbt import compute_bounds_on_expr as compute_bounds_on_expr +from pyomo.core import Binary as Binary +from pyomo.core import Block as Block +from pyomo.core import BooleanVar as BooleanVar +from pyomo.core import BooleanVarList as BooleanVarList +from pyomo.core import ConstraintList as ConstraintList +from pyomo.core import LogicalConstraint as LogicalConstraint +from pyomo.core import SortComponents as SortComponents +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core import VarList as VarList +from pyomo.core import native_types as native_types +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.expr import AndExpression as AndExpression +from pyomo.core.expr import AtLeastExpression as AtLeastExpression +from pyomo.core.expr import AtMostExpression as AtMostExpression +from pyomo.core.expr import EqualityExpression as EqualityExpression +from pyomo.core.expr import ExactlyExpression as ExactlyExpression +from pyomo.core.expr import InequalityExpression as InequalityExpression +from pyomo.core.expr import NotExpression as NotExpression +from pyomo.core.expr import OrExpression as OrExpression +from pyomo.core.expr import RangedExpression as RangedExpression +from pyomo.core.expr import identify_variables as identify_variables +from pyomo.core.expr import special_boolean_atom_types as special_boolean_atom_types +from pyomo.core.expr.cnf_walker import to_cnf as to_cnf +from pyomo.core.expr.numvalue import native_logical_types as native_logical_types +from pyomo.core.expr.numvalue import value as value +from pyomo.core.expr.visitor import StreamBasedExpressionVisitor as StreamBasedExpressionVisitor +from pyomo.core.plugins.transform.hierarchy import ( + IsomorphicTransformation as IsomorphicTransformation, +) +from pyomo.core.util import target_list as target_list + +class LogicalToLinear(IsomorphicTransformation): + CONFIG: Incomplete + +def update_boolean_vars_from_binary(model, integer_tolerance: float = 1e-05) -> None: ... + +class CnfToLinearVisitor(StreamBasedExpressionVisitor): + def __init__(self, indicator_var, binary_varlist) -> None: ... + def exitNode(self, node, values): ... + def beforeChild(self, node, child, child_idx): ... + def finalizeResult(self, result): ... diff --git a/stubs/pyomo/core/plugins/transform/lp_dual.pyi b/stubs/pyomo/core/plugins/transform/lp_dual.pyi new file mode 100644 index 000000000..879862f6c --- /dev/null +++ b/stubs/pyomo/core/plugins/transform/lp_dual.pyi @@ -0,0 +1,36 @@ +from _typeshed import Incomplete +from pyomo.common.autoslots import AutoSlots as AutoSlots +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.dependencies import scipy as scipy +from pyomo.core import Block as Block +from pyomo.core import ConcreteModel as ConcreteModel +from pyomo.core import Constraint as Constraint +from pyomo.core import NonNegativeReals as NonNegativeReals +from pyomo.core import NonPositiveReals as NonPositiveReals +from pyomo.core import Objective as Objective +from pyomo.core import Reals as Reals +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core import Var as Var +from pyomo.core import maximize as maximize +from pyomo.core import minimize as minimize +from pyomo.opt import WriterFactory as WriterFactory +from pyomo.repn.standard_repn import isclose_const as isclose_const +from pyomo.util.config_domains import ComponentDataSet as ComponentDataSet + +class _LPDualData(AutoSlots.Mixin): + primal_var: Incomplete + dual_var: Incomplete + primal_constraint: Incomplete + dual_constraint: Incomplete + def __init__(self) -> None: ... + +class LinearProgrammingDual: + CONFIG: Incomplete + def apply_to(self, model, **options) -> None: ... + def create_using(self, model, ostream=None, **kwds): ... + def get_primal_constraint(self, model, dual_var): ... + def get_dual_constraint(self, model, primal_var): ... + def get_primal_var(self, model, dual_constraint): ... + def get_dual_var(self, model, primal_constraint): ... diff --git a/stubs/pyomo/core/plugins/transform/model.pyi b/stubs/pyomo/core/plugins/transform/model.pyi new file mode 100644 index 000000000..1c26b512f --- /dev/null +++ b/stubs/pyomo/core/plugins/transform/model.pyi @@ -0,0 +1,5 @@ +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import Objective as Objective + +def to_standard_form(self): ... diff --git a/stubs/pyomo/core/plugins/transform/nonnegative_transform.pyi b/stubs/pyomo/core/plugins/transform/nonnegative_transform.pyi new file mode 100644 index 000000000..72c7dc80d --- /dev/null +++ b/stubs/pyomo/core/plugins/transform/nonnegative_transform.pyi @@ -0,0 +1,51 @@ +import pyomo.core.expr as EXPR +from _typeshed import Incomplete +from pyomo.core import Binary as Binary +from pyomo.core import Constraint as Constraint +from pyomo.core import Integers as Integers +from pyomo.core import IntegerSet as IntegerSet +from pyomo.core import NegativeIntegers as NegativeIntegers +from pyomo.core import NegativeReals as NegativeReals +from pyomo.core import NonNegativeIntegers as NonNegativeIntegers +from pyomo.core import NonNegativeReals as NonNegativeReals +from pyomo.core import NonPositiveIntegers as NonPositiveIntegers +from pyomo.core import NonPositiveReals as NonPositiveReals +from pyomo.core import Objective as Objective +from pyomo.core import PercentFraction as PercentFraction +from pyomo.core import PositiveIntegers as PositiveIntegers +from pyomo.core import PositiveReals as PositiveReals +from pyomo.core import Reals as Reals +from pyomo.core import RealSet as RealSet +from pyomo.core import Set as Set +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core import Var as Var +from pyomo.core import nonpyomo_leaf_types as nonpyomo_leaf_types +from pyomo.core import value as value +from pyomo.core.base.misc import create_name as create_name +from pyomo.core.plugins.transform.hierarchy import ( + IsomorphicTransformation as IsomorphicTransformation, +) +from pyomo.core.plugins.transform.util import collectAbstractComponents as collectAbstractComponents +from pyomo.core.plugins.transform.util import partial as partial + +logger: Incomplete + +class VarmapVisitor(EXPR.ExpressionReplacementVisitor): + varmap: Incomplete + def __init__(self, varmap) -> None: ... + def visiting_potential_leaf(self, node): ... + +class NonNegativeTransformation(IsomorphicTransformation): + realSets: Incomplete + discreteSets: Incomplete + def __init__(self, **kwds) -> None: ... + @staticmethod + def boundsConstraintRule(lb, ub, attr, vars, model): ... + @staticmethod + def noConstraint(*args) -> None: ... + @staticmethod + def sumRule(attr, vars, model): ... + @staticmethod + def exprMapRule(ruleMap, model, ndx=None): ... + @staticmethod + def delayedExprMapRule(ruleMap, model, ndx=None): ... diff --git a/stubs/pyomo/core/plugins/transform/radix_linearization.pyi b/stubs/pyomo/core/plugins/transform/radix_linearization.pyi new file mode 100644 index 000000000..7f17aee97 --- /dev/null +++ b/stubs/pyomo/core/plugins/transform/radix_linearization.pyi @@ -0,0 +1,18 @@ +from _typeshed import Incomplete +from pyomo.core import Binary as Binary +from pyomo.core import value as value +from pyomo.core.base import Block as Block +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import ConstraintList as ConstraintList +from pyomo.core.base import RangeSet as RangeSet +from pyomo.core.base import Transformation as Transformation +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.core.base import Var as Var +from pyomo.core.base.var import VarData as VarData +from pyomo.core.expr import PowExpression as PowExpression +from pyomo.core.expr import ProductExpression as ProductExpression +from pyomo.core.expr.numvalue import as_numeric as as_numeric + +logger: Incomplete + +class RadixLinearization(Transformation): ... diff --git a/stubs/pyomo/core/plugins/transform/relax_integrality.pyi b/stubs/pyomo/core/plugins/transform/relax_integrality.pyi new file mode 100644 index 000000000..19ba2f9b6 --- /dev/null +++ b/stubs/pyomo/core/plugins/transform/relax_integrality.pyi @@ -0,0 +1,6 @@ +from pyomo.common import deprecated as deprecated +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.core.plugins.transform.discrete_vars import RelaxIntegerVars as RelaxIntegerVars + +class RelaxIntegrality(RelaxIntegerVars): + def __init__(self, **kwds) -> None: ... diff --git a/stubs/pyomo/core/plugins/transform/scaling.pyi b/stubs/pyomo/core/plugins/transform/scaling.pyi new file mode 100644 index 000000000..1efe9e8ed --- /dev/null +++ b/stubs/pyomo/core/plugins/transform/scaling.pyi @@ -0,0 +1,19 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.core.base import Block as Block +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import Objective as Objective +from pyomo.core.base import Suffix as Suffix +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.core.base import Var as Var +from pyomo.core.base import value as value +from pyomo.core.base.suffix import SuffixFinder as SuffixFinder +from pyomo.core.expr import replace_expressions as replace_expressions +from pyomo.core.plugins.transform.hierarchy import Transformation as Transformation +from pyomo.util.components import rename_components as rename_components + +logger: Incomplete + +class ScaleModel(Transformation): + def __init__(self, **kwds) -> None: ... + def propagate_solution(self, scaled_model, original_model) -> None: ... diff --git a/stubs/pyomo/core/plugins/transform/standard_form.pyi b/stubs/pyomo/core/plugins/transform/standard_form.pyi new file mode 100644 index 000000000..ae989f922 --- /dev/null +++ b/stubs/pyomo/core/plugins/transform/standard_form.pyi @@ -0,0 +1,11 @@ +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core.plugins.transform.equality_transform import EqualityTransform as EqualityTransform +from pyomo.core.plugins.transform.hierarchy import ( + IsomorphicTransformation as IsomorphicTransformation, +) +from pyomo.core.plugins.transform.nonnegative_transform import ( + NonNegativeTransformation as NonNegativeTransformation, +) + +class StandardForm(IsomorphicTransformation): + def __init__(self, **kwds) -> None: ... diff --git a/stubs/pyomo/core/plugins/transform/util.pyi b/stubs/pyomo/core/plugins/transform/util.pyi new file mode 100644 index 000000000..f8b5eec34 --- /dev/null +++ b/stubs/pyomo/core/plugins/transform/util.pyi @@ -0,0 +1,9 @@ +from pyomo.core import Constraint as Constraint +from pyomo.core import Objective as Objective +from pyomo.core import Param as Param +from pyomo.core import Set as Set +from pyomo.core import Var as Var + +def collectAbstractComponents(model): ... +def partial(*args, **kwargs): ... +def process_canonical_repn(expr): ... diff --git a/stubs/pyomo/core/pyomoobject.pyi b/stubs/pyomo/core/pyomoobject.pyi new file mode 100644 index 000000000..37f02cb45 --- /dev/null +++ b/stubs/pyomo/core/pyomoobject.pyi @@ -0,0 +1,11 @@ +from pyomo.common.autoslots import AutoSlots as AutoSlots + +class PyomoObject(AutoSlots.Mixin): + def is_component_type(self): ... + def is_numeric_type(self): ... + def is_parameter_type(self): ... + def is_variable_type(self): ... + def is_expression_type(self, expression_system=None): ... + def is_named_expression_type(self): ... + def is_logical_type(self): ... + def is_reference(self): ... diff --git a/stubs/pyomo/core/staleflag.pyi b/stubs/pyomo/core/staleflag.pyi new file mode 100644 index 000000000..46b9f1a11 --- /dev/null +++ b/stubs/pyomo/core/staleflag.pyi @@ -0,0 +1,9 @@ +from _typeshed import Incomplete + +class _StaleFlagManager: + def __init__(self) -> None: ... + def stale_mapper(self, encode, value): ... + def is_stale(self, val): ... + def mark_all_as_stale(self, delayed: bool = False) -> None: ... + +StaleFlagManager: Incomplete diff --git a/stubs/pyomo/core/util.pyi b/stubs/pyomo/core/util.pyi new file mode 100644 index 000000000..07e7ec711 --- /dev/null +++ b/stubs/pyomo/core/util.pyi @@ -0,0 +1,20 @@ +from _typeshed import Incomplete +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.core.base.component import ComponentBase as ComponentBase +from pyomo.core.base.expression import Expression as Expression +from pyomo.core.base.var import Var as Var +from pyomo.core.expr.numeric_expr import NPV_SumExpression as NPV_SumExpression +from pyomo.core.expr.numeric_expr import mutable_expression as mutable_expression +from pyomo.core.expr.numvalue import native_numeric_types as native_numeric_types + +logger: Incomplete + +def prod(terms): ... +def quicksum(args, start: int = 0, linear=None): ... +def sum_product(*args, **kwds): ... + +dot_product = sum_product +summation = sum_product + +def sequence(*args): ... +def target_list(x): ... diff --git a/stubs/pyomo/dae/__init__.pyi b/stubs/pyomo/dae/__init__.pyi new file mode 100644 index 000000000..acfc869e1 --- /dev/null +++ b/stubs/pyomo/dae/__init__.pyi @@ -0,0 +1,5 @@ +from pyomo.dae.contset import ContinuousSet as ContinuousSet +from pyomo.dae.diffvar import DAE_Error as DAE_Error +from pyomo.dae.diffvar import DerivativeVar as DerivativeVar +from pyomo.dae.integral import Integral as Integral +from pyomo.dae.simulator import Simulator as Simulator diff --git a/stubs/pyomo/dae/contset.pyi b/stubs/pyomo/dae/contset.pyi new file mode 100644 index 000000000..04cf49b83 --- /dev/null +++ b/stubs/pyomo/dae/contset.pyi @@ -0,0 +1,18 @@ +from _typeshed import Incomplete +from pyomo.common.numeric_types import native_numeric_types as native_numeric_types +from pyomo.common.timing import ConstructionTimer as ConstructionTimer +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.set import SortedScalarSet as SortedScalarSet + +logger: Incomplete + +class ContinuousSet(SortedScalarSet): + def __init__(self, *args, **kwds) -> None: ... + def get_finite_elements(self): ... + def get_discretization_info(self): ... + def get_changed(self): ... + def set_changed(self, newvalue) -> None: ... + def get_upper_element_boundary(self, point): ... + def get_lower_element_boundary(self, point): ... + def construct(self, values=None) -> None: ... + def find_nearest_index(self, target, tolerance=None): ... diff --git a/stubs/pyomo/dae/diffvar.pyi b/stubs/pyomo/dae/diffvar.pyi new file mode 100644 index 000000000..68aaefcff --- /dev/null +++ b/stubs/pyomo/dae/diffvar.pyi @@ -0,0 +1,17 @@ +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.set import UnknownSetDimen as UnknownSetDimen +from pyomo.core.base.var import Var as Var +from pyomo.dae.contset import ContinuousSet as ContinuousSet + +def create_access_function(var): ... + +class DAE_Error(Exception): ... + +class DerivativeVar(Var): + def __init__(self, sVar, **kwds) -> None: ... + def get_continuousset_list(self): ... + def is_fully_discretized(self): ... + def get_state_var(self): ... + def get_derivative_expression(self): ... + def set_derivative_expression(self, expr) -> None: ... diff --git a/stubs/pyomo/dae/flatten.pyi b/stubs/pyomo/dae/flatten.pyi new file mode 100644 index 000000000..26c3f60a8 --- /dev/null +++ b/stubs/pyomo/dae/flatten.pyi @@ -0,0 +1,26 @@ +from collections.abc import Generator + +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.core.base import Block as Block +from pyomo.core.base import Reference as Reference +from pyomo.core.base.block import SubclassOf as SubclassOf +from pyomo.core.base.component import ActiveComponent as ActiveComponent +from pyomo.core.base.indexed_component import UnindexedComponent_set as UnindexedComponent_set +from pyomo.core.base.indexed_component import normalize_index as normalize_index +from pyomo.core.base.indexed_component_slice import IndexedComponent_slice as IndexedComponent_slice +from pyomo.core.base.set import SetProduct as SetProduct + +def get_slice_for_set(s): ... + +class _NotAnIndex: ... + +def slice_component_along_sets( + component, sets, context_slice=None, normalize=None +) -> Generator[Incomplete]: ... +def generate_sliced_components( + b, index_stack, slice_, sets, ctype, index_map, active=None +) -> Generator[Incomplete]: ... +def flatten_components_along_sets(m, sets, ctype, indices=None, active=None): ... +def flatten_dae_components(model, time, ctype, indices=None, active=None): ... diff --git a/stubs/pyomo/dae/initialization.pyi b/stubs/pyomo/dae/initialization.pyi new file mode 100644 index 000000000..c7d833250 --- /dev/null +++ b/stubs/pyomo/dae/initialization.pyi @@ -0,0 +1,21 @@ +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.core.base import Block as Block +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import value as value +from pyomo.dae.set_utils import deactivate_model_at as deactivate_model_at +from pyomo.dae.set_utils import get_index_set_except as get_index_set_except +from pyomo.dae.set_utils import index_warning as index_warning +from pyomo.dae.set_utils import is_explicitly_indexed_by as is_explicitly_indexed_by +from pyomo.dae.set_utils import is_in_block_indexed_by as is_in_block_indexed_by + +def get_inconsistent_initial_conditions( + model, + time, + tol: float = 1e-08, + t0=None, + allow_skip: bool = True, + suppress_warnings: bool = False, +): ... +def solve_consistent_initial_conditions( + model, time, solver, tee: bool = False, allow_skip: bool = True, suppress_warnings: bool = False +): ... diff --git a/stubs/pyomo/dae/integral.pyi b/stubs/pyomo/dae/integral.pyi new file mode 100644 index 000000000..fe4b13a4c --- /dev/null +++ b/stubs/pyomo/dae/integral.pyi @@ -0,0 +1,28 @@ +from _typeshed import Incomplete +from pyomo.common.deprecation import RenamedClass as RenamedClass +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.expression import Expression as Expression +from pyomo.core.base.expression import ExpressionData as ExpressionData +from pyomo.core.base.expression import IndexedExpression as IndexedExpression +from pyomo.core.base.expression import ScalarExpression as ScalarExpression +from pyomo.core.base.indexed_component import rule_wrapper as rule_wrapper +from pyomo.dae.contset import ContinuousSet as ContinuousSet +from pyomo.dae.diffvar import DAE_Error as DAE_Error + +class Integral(Expression): + def __new__(cls, *args, **kwds): ... + loc: Incomplete + def __init__(self, *args, **kwds) -> None: ... + def get_continuousset(self): ... + +class ScalarIntegral(ScalarExpression, Integral): + def __init__(self, *args, **kwds) -> None: ... + def clear(self) -> None: ... + def is_fully_discretized(self): ... + +class SimpleIntegral(metaclass=RenamedClass): + __renamed__new_class__ = ScalarIntegral + __renamed__version__: str + +class IndexedIntegral(IndexedExpression, Integral): + def is_fully_discretized(self): ... diff --git a/stubs/pyomo/dae/misc.pyi b/stubs/pyomo/dae/misc.pyi new file mode 100644 index 000000000..f072da91b --- /dev/null +++ b/stubs/pyomo/dae/misc.pyi @@ -0,0 +1,29 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.formatting import tostr as tostr +from pyomo.common.log import LoggingIntercept as LoggingIntercept +from pyomo.core import Block as Block +from pyomo.core import Constraint as Constraint +from pyomo.core import Expression as Expression +from pyomo.core import Param as Param +from pyomo.core import Piecewise as Piecewise +from pyomo.core import Suffix as Suffix +from pyomo.core import Var as Var +from pyomo.core.base.block import IndexedBlock as IndexedBlock +from pyomo.core.base.block import SortComponents as SortComponents +from pyomo.core.base.misc import apply_indexed_rule as apply_indexed_rule +from pyomo.dae import ContinuousSet as ContinuousSet +from pyomo.dae import DAE_Error as DAE_Error + +logger: Incomplete + +def generate_finite_elements(ds, nfe) -> None: ... +def generate_colloc_points(ds, tau) -> None: ... +def expand_components(block) -> None: ... +def update_contset_indexed_component(comp, expansion_map) -> None: ... +def create_access_function(var): ... +def create_partial_expression(scheme, expr, ind, loc): ... +def add_discretization_equations(block, d): ... +def add_continuity_equations(block, d, i, loc): ... +def block_fully_discretized(b): ... +def get_index_information(var, ds): ... diff --git a/stubs/pyomo/dae/plugins/__init__.pyi b/stubs/pyomo/dae/plugins/__init__.pyi new file mode 100644 index 000000000..08b671c7f --- /dev/null +++ b/stubs/pyomo/dae/plugins/__init__.pyi @@ -0,0 +1 @@ +def load() -> None: ... diff --git a/stubs/pyomo/dae/plugins/colloc.pyi b/stubs/pyomo/dae/plugins/colloc.pyi new file mode 100644 index 000000000..ba5cffa55 --- /dev/null +++ b/stubs/pyomo/dae/plugins/colloc.pyi @@ -0,0 +1,39 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import In as In +from pyomo.common.config import PositiveInt as PositiveInt +from pyomo.common.dependencies import numpy as numpy +from pyomo.common.dependencies import numpy_available as numpy_available +from pyomo.core import ConstraintList as ConstraintList +from pyomo.core import Expression as Expression +from pyomo.core import Objective as Objective +from pyomo.core import Var as Var +from pyomo.core.base import Transformation as Transformation +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.dae import ContinuousSet as ContinuousSet +from pyomo.dae import DerivativeVar as DerivativeVar +from pyomo.dae import Integral as Integral +from pyomo.dae.diffvar import DAE_Error as DAE_Error +from pyomo.dae.misc import add_continuity_equations as add_continuity_equations +from pyomo.dae.misc import add_discretization_equations as add_discretization_equations +from pyomo.dae.misc import block_fully_discretized as block_fully_discretized +from pyomo.dae.misc import create_partial_expression as create_partial_expression +from pyomo.dae.misc import expand_components as expand_components +from pyomo.dae.misc import generate_colloc_points as generate_colloc_points +from pyomo.dae.misc import generate_finite_elements as generate_finite_elements +from pyomo.dae.misc import get_index_information as get_index_information + +logger: Incomplete + +def conv(a, b): ... +def calc_cp(alpha, beta, k): ... +def calc_adot(cp, order: int = 1): ... +def calc_afinal(cp): ... + +class Collocation_Discretization_Transformation(Transformation): + CONFIG: Incomplete + all_schemes: Incomplete + def __init__(self) -> None: ... + def reduce_collocation_points(self, instance, var=None, ncp=None, contset=None): ... diff --git a/stubs/pyomo/dae/plugins/finitedifference.pyi b/stubs/pyomo/dae/plugins/finitedifference.pyi new file mode 100644 index 000000000..7e1190ee3 --- /dev/null +++ b/stubs/pyomo/dae/plugins/finitedifference.pyi @@ -0,0 +1,27 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import In as In +from pyomo.common.config import PositiveInt as PositiveInt +from pyomo.core import Expression as Expression +from pyomo.core import Objective as Objective +from pyomo.core import Var as Var +from pyomo.core.base import Transformation as Transformation +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.dae import ContinuousSet as ContinuousSet +from pyomo.dae import DerivativeVar as DerivativeVar +from pyomo.dae import Integral as Integral +from pyomo.dae.diffvar import DAE_Error as DAE_Error +from pyomo.dae.misc import add_discretization_equations as add_discretization_equations +from pyomo.dae.misc import block_fully_discretized as block_fully_discretized +from pyomo.dae.misc import create_partial_expression as create_partial_expression +from pyomo.dae.misc import expand_components as expand_components +from pyomo.dae.misc import generate_finite_elements as generate_finite_elements + +logger: Incomplete + +class Finite_Difference_Transformation(Transformation): + CONFIG: Incomplete + all_schemes: Incomplete + def __init__(self) -> None: ... diff --git a/stubs/pyomo/dae/set_utils.pyi b/stubs/pyomo/dae/set_utils.pyi new file mode 100644 index 000000000..99d70fa53 --- /dev/null +++ b/stubs/pyomo/dae/set_utils.pyi @@ -0,0 +1,11 @@ +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.core.base import Block as Block +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base.set import SetProduct as SetProduct + +def index_warning(name, index): ... +def is_explicitly_indexed_by(comp, *sets, **kwargs): ... +def is_in_block_indexed_by(comp, s, stop_at=None): ... +def get_indices_of_projection(index_set, *sets): ... +def get_index_set_except(comp, *sets): ... +def deactivate_model_at(b, cset, pts, allow_skip: bool = True, suppress_warnings: bool = False): ... diff --git a/stubs/pyomo/dae/simulator.pyi b/stubs/pyomo/dae/simulator.pyi new file mode 100644 index 000000000..8b6b06a3e --- /dev/null +++ b/stubs/pyomo/dae/simulator.pyi @@ -0,0 +1,55 @@ +import pyomo.core.expr as EXPR +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.dependencies import numpy_available as numpy_available +from pyomo.common.dependencies import scipy as scipy +from pyomo.common.dependencies import scipy_available as scipy_available +from pyomo.core.base import Block as Block +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import Param as Param +from pyomo.core.base import Suffix as Suffix +from pyomo.core.base import value as value +from pyomo.core.expr.numvalue import native_numeric_types as native_numeric_types +from pyomo.core.expr.template_expr import IndexTemplate as IndexTemplate +from pyomo.dae import ContinuousSet as ContinuousSet +from pyomo.dae import DerivativeVar as DerivativeVar +from pyomo.dae.diffvar import DAE_Error as DAE_Error + +logger: Incomplete +casadi_intrinsic: Incomplete +casadi: Incomplete +casadi_available: Incomplete + +class Pyomo2Scipy_Visitor(EXPR.ExpressionReplacementVisitor): + templatemap: Incomplete + def __init__(self, templatemap) -> None: ... + def beforeChild(self, node, child, child_idx): ... + +def convert_pyomo2scipy(expr, templatemap): ... + +class Substitute_Pyomo2Casadi_Visitor(EXPR.ExpressionReplacementVisitor): + templatemap: Incomplete + def __init__(self, templatemap) -> None: ... + def exitNode(self, node, data): ... + def beforeChild(self, node, child, child_idx): ... + +class Convert_Pyomo2Casadi_Visitor(EXPR.ExpressionValueVisitor): + def visit(self, node, values): ... + def visiting_potential_leaf(self, node): ... + +def substitute_pyomo2casadi(expr, templatemap): ... +def convert_pyomo2casadi(expr): ... + +class Simulator: + def __init__(self, m, package: str = 'scipy') -> None: ... + def get_variable_order(self, vartype=None): ... + def simulate( + self, + numpoints=None, + tstep=None, + integrator=None, + varying_inputs=None, + initcon=None, + integrator_options=None, + ): ... + def initialize_model(self) -> None: ... diff --git a/stubs/pyomo/dae/utilities.pyi b/stubs/pyomo/dae/utilities.pyi new file mode 100644 index 000000000..4d6031d03 --- /dev/null +++ b/stubs/pyomo/dae/utilities.pyi @@ -0,0 +1,9 @@ +from _typeshed import Incomplete + +radau_tau_dict: Incomplete +radau_adot_dict: Incomplete +radau_adotdot_dict: Incomplete +legendre_tau_dict: Incomplete +legendre_adot_dict: Incomplete +legendre_adotdot_dict: Incomplete +legendre_afinal_dict: Incomplete diff --git a/stubs/pyomo/dataportal/DataPortal.pyi b/stubs/pyomo/dataportal/DataPortal.pyi new file mode 100644 index 000000000..ffa71dba2 --- /dev/null +++ b/stubs/pyomo/dataportal/DataPortal.pyi @@ -0,0 +1,22 @@ +from collections.abc import Generator + +from _typeshed import Incomplete +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.dataportal.factory import DataManagerFactory as DataManagerFactory +from pyomo.dataportal.factory import UnknownDataManager as UnknownDataManager + +logger: Incomplete + +class DataPortal: + def __init__(self, *args, **kwds) -> None: ... + def connect(self, **kwds) -> None: ... + def disconnect(self) -> None: ... + def load(self, **kwds) -> None: ... + def store(self, **kwds) -> None: ... + def data(self, name=None, namespace=None): ... + def __getitem__(self, *args): ... + def __setitem__(self, name, value) -> None: ... + def namespaces(self) -> Generator[Incomplete]: ... + def keys(self, namespace=None) -> Generator[Incomplete]: ... + def values(self, namespace=None) -> Generator[Incomplete]: ... + def items(self, namespace=None) -> Generator[Incomplete]: ... diff --git a/stubs/pyomo/dataportal/TableData.pyi b/stubs/pyomo/dataportal/TableData.pyi new file mode 100644 index 000000000..2145522ca --- /dev/null +++ b/stubs/pyomo/dataportal/TableData.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch + +class TableData: + options: Incomplete + def __init__(self) -> None: ... + def available(self): ... + filename: Incomplete + def initialize(self, **kwds) -> None: ... + def add_options(self, **kwds) -> None: ... + def open(self) -> None: ... + def read(self): ... + def write(self, data): ... + def close(self) -> None: ... + def process(self, model, data, default): ... + def clear(self) -> None: ... diff --git a/stubs/pyomo/dataportal/__init__.pyi b/stubs/pyomo/dataportal/__init__.pyi new file mode 100644 index 000000000..2cbbb1be9 --- /dev/null +++ b/stubs/pyomo/dataportal/__init__.pyi @@ -0,0 +1,5 @@ +from pyomo.dataportal import parse_datacmds as parse_datacmds +from pyomo.dataportal.DataPortal import DataPortal as DataPortal +from pyomo.dataportal.factory import DataManagerFactory as DataManagerFactory +from pyomo.dataportal.factory import UnknownDataManager as UnknownDataManager +from pyomo.dataportal.TableData import TableData as TableData diff --git a/stubs/pyomo/dataportal/factory.pyi b/stubs/pyomo/dataportal/factory.pyi new file mode 100644 index 000000000..468ce3bc3 --- /dev/null +++ b/stubs/pyomo/dataportal/factory.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from pyomo.common import Factory as Factory +from pyomo.common.plugin_base import PluginError as PluginError + +logger: Incomplete + +class UnknownDataManager: + type: Incomplete + def __init__(self, *args, **kwds) -> None: ... + def available(self): ... + +class DataManagerFactoryClass(Factory): + def __call__(self, _name=None, args=[], **kwds): ... + +DataManagerFactory: Incomplete diff --git a/stubs/pyomo/dataportal/parse_datacmds.pyi b/stubs/pyomo/dataportal/parse_datacmds.pyi new file mode 100644 index 000000000..da3b8287d --- /dev/null +++ b/stubs/pyomo/dataportal/parse_datacmds.pyi @@ -0,0 +1,48 @@ +from _typeshed import Incomplete +from pyomo.common.fileutils import this_file as this_file +from pyomo.core.base.util import flatten_tuple as flatten_tuple + +states: Incomplete +reserved: Incomplete +tokens: Incomplete +t_ignore: str +t_COMMA: str +t_LBRACKET: str +t_RBRACKET: str +t_LBRACE: str +t_RBRACE: str +t_COLON: str +t_EQ: str +t_TR: str +t_LPAREN: str +t_RPAREN: str +t_ASTERISK: str + +def t_newline(t) -> None: ... +def t_COMMENT(t) -> None: ... +def t_COLONEQ(t): ... +def t_SEMICOLON(t): ... +def t_NUM_VAL(t): ... +def t_WORDWITHLBRACKET(t): ... +def t_WORD(t): ... +def t_STRING(t): ... +def t_data_BRACKETEDSTRING(t): ... +def t_QUOTEDSTRING(t): ... +def t_error(t) -> None: ... +def p_expr(p) -> None: ... +def p_statements(p) -> None: ... +def p_statement(p) -> None: ... +def p_datastar(p) -> None: ... +def p_data(p) -> None: ... +def p_args(p) -> None: ... +def p_arg(p) -> None: ... +def p_itemstar(p) -> None: ... +def p_items(p) -> None: ... +def p_error(p) -> None: ... + +tabmodule: str +dat_lexer: Incomplete +dat_yaccer: Incomplete +dat_yaccer_tabfile: Incomplete + +def parse_data_commands(data=None, filename=None, debug: int = 0, outputdir=None): ... diff --git a/stubs/pyomo/dataportal/plugins/__init__.pyi b/stubs/pyomo/dataportal/plugins/__init__.pyi new file mode 100644 index 000000000..08b671c7f --- /dev/null +++ b/stubs/pyomo/dataportal/plugins/__init__.pyi @@ -0,0 +1 @@ +def load() -> None: ... diff --git a/stubs/pyomo/dataportal/plugins/csv_table.pyi b/stubs/pyomo/dataportal/plugins/csv_table.pyi new file mode 100644 index 000000000..2060dfc46 --- /dev/null +++ b/stubs/pyomo/dataportal/plugins/csv_table.pyi @@ -0,0 +1,11 @@ +from _typeshed import Incomplete +from pyomo.dataportal import TableData as TableData +from pyomo.dataportal.factory import DataManagerFactory as DataManagerFactory + +class CSVTable(TableData): + def __init__(self) -> None: ... + def open(self) -> None: ... + def close(self) -> None: ... + FILE: Incomplete + def read(self) -> None: ... + def write(self, data) -> None: ... diff --git a/stubs/pyomo/dataportal/plugins/datacommands.pyi b/stubs/pyomo/dataportal/plugins/datacommands.pyi new file mode 100644 index 000000000..b89db26d2 --- /dev/null +++ b/stubs/pyomo/dataportal/plugins/datacommands.pyi @@ -0,0 +1,17 @@ +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch +from pyomo.dataportal.factory import DataManagerFactory as DataManagerFactory + +class PyomoDataCommands: + options: Incomplete + def __init__(self) -> None: ... + def available(self): ... + filename: Incomplete + def initialize(self, **kwds) -> None: ... + def add_options(self, **kwds) -> None: ... + def open(self) -> None: ... + def close(self) -> None: ... + def read(self) -> None: ... + def write(self, data) -> None: ... + def process(self, model, data, default) -> None: ... + def clear(self) -> None: ... diff --git a/stubs/pyomo/dataportal/plugins/db_table.pyi b/stubs/pyomo/dataportal/plugins/db_table.pyi new file mode 100644 index 000000000..71a070615 --- /dev/null +++ b/stubs/pyomo/dataportal/plugins/db_table.pyi @@ -0,0 +1,74 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.dataportal import TableData as TableData +from pyomo.dataportal.factory import DataManagerFactory as DataManagerFactory + +pyodbc: Incomplete +pyodbc_available: Incomplete +pypyodbc: Incomplete +pypyodbc_available: Incomplete +sqlite3: Incomplete +sqlite3_available: Incomplete +pymysql: Incomplete +pymysql_available: Incomplete + +class db_Table(TableData): + using: Incomplete + def __init__(self) -> None: ... + filename: Incomplete + db: Incomplete + def open(self) -> None: ... + def read(self) -> None: ... + def close(self) -> None: ... + def connect(self, connection, options, kwds={}): ... + +class pyodbc_db_Table(db_Table): + using: str + def __init__(self) -> None: ... + def available(self): ... + def requirements(self): ... + def connect(self, connection, options): ... + def create_dsn_dict(self, argstr, existing_config): ... + def create_connection_string(self, ctype, connection, options): ... + +class ODBCError(Exception): + parameter: Incomplete + def __init__(self, value) -> None: ... + +class ODBCConfig: + ODBC_DS_KEY: str + ODBC_INFO_KEY: str + file: Incomplete + sources: Incomplete + source_specs: Incomplete + odbc_info: Incomplete + def __init__(self, filename=None, data=None) -> None: ... + def load(self, filename=None, data=None) -> None: ... + def __eq__(self, other): ... + def odbc_repr(self): ... + def write(self, filename) -> None: ... + def add_source(self, name, driver) -> None: ... + def del_source(self, name) -> None: ... + def add_source_spec(self, name, spec) -> None: ... + def del_source_spec(self, name) -> None: ... + def set_odbc_info(self, key, value) -> None: ... + +class pypyodbc_db_Table(pyodbc_db_Table): + using: str + def __init__(self) -> None: ... + def available(self): ... + def requirements(self): ... + def connect(self, connection, options): ... + +class sqlite3_db_Table(db_Table): + using: str + def __init__(self) -> None: ... + def available(self): ... + def requirements(self): ... + def connect(self, connection, options): ... + +class pymysql_db_Table(db_Table): + using: str + def __init__(self) -> None: ... + def available(self): ... + def requirements(self): ... diff --git a/stubs/pyomo/dataportal/plugins/json_dict.pyi b/stubs/pyomo/dataportal/plugins/json_dict.pyi new file mode 100644 index 000000000..40a38124b --- /dev/null +++ b/stubs/pyomo/dataportal/plugins/json_dict.pyi @@ -0,0 +1,38 @@ +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.dependencies import yaml as yaml +from pyomo.common.dependencies import yaml_available as yaml_available +from pyomo.common.dependencies import yaml_load_args as yaml_load_args +from pyomo.dataportal.factory import DataManagerFactory as DataManagerFactory + +def detuplize(d, sort: bool = False): ... +def tuplize(d): ... + +class JSONDictionary: + options: Incomplete + def __init__(self) -> None: ... + def available(self): ... + filename: Incomplete + def initialize(self, **kwds) -> None: ... + def add_options(self, **kwds) -> None: ... + def open(self) -> None: ... + def close(self) -> None: ... + def read(self) -> None: ... + def write(self, data) -> None: ... + def process(self, model, data, default) -> None: ... + def clear(self) -> None: ... + +class YamlDictionary: + options: Incomplete + def __init__(self) -> None: ... + def available(self): ... + def requirements(self): ... + filename: Incomplete + def initialize(self, **kwds) -> None: ... + def add_options(self, **kwds) -> None: ... + def open(self) -> None: ... + def close(self) -> None: ... + def read(self) -> None: ... + def write(self, data) -> None: ... + def process(self, model, data, default) -> None: ... + def clear(self) -> None: ... diff --git a/stubs/pyomo/dataportal/plugins/sheet.pyi b/stubs/pyomo/dataportal/plugins/sheet.pyi new file mode 100644 index 000000000..21ec488fa --- /dev/null +++ b/stubs/pyomo/dataportal/plugins/sheet.pyi @@ -0,0 +1,33 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.dependencies import importlib as importlib +from pyomo.common.dependencies import pyutilib as pyutilib +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.dataportal import TableData as TableData +from pyomo.dataportal.factory import DataManagerFactory as DataManagerFactory + +spreadsheet: Incomplete +spreadsheet_available: Incomplete + +class SheetTable(TableData): + ctype: Incomplete + def __init__(self, ctype=None) -> None: ... + sheet: Incomplete + def open(self) -> None: ... + def read(self) -> None: ... + def close(self) -> None: ... + +class SheetTable_xls(SheetTable): + def __init__(self) -> None: ... + def available(self): ... + def requirements(self): ... + +class SheetTable_xlsx(SheetTable): + def __init__(self) -> None: ... + def available(self): ... + def requirements(self): ... + +class SheetTable_xlsm(SheetTable): + def __init__(self) -> None: ... + def available(self): ... + def requirements(self): ... diff --git a/stubs/pyomo/dataportal/plugins/text.pyi b/stubs/pyomo/dataportal/plugins/text.pyi new file mode 100644 index 000000000..260c94d8e --- /dev/null +++ b/stubs/pyomo/dataportal/plugins/text.pyi @@ -0,0 +1,11 @@ +from _typeshed import Incomplete +from pyomo.dataportal import TableData as TableData +from pyomo.dataportal.factory import DataManagerFactory as DataManagerFactory + +class TextTable(TableData): + FILE: Incomplete + def __init__(self) -> None: ... + def open(self) -> None: ... + def close(self) -> None: ... + def read(self) -> None: ... + def write(self, data) -> None: ... diff --git a/stubs/pyomo/dataportal/plugins/xml_table.pyi b/stubs/pyomo/dataportal/plugins/xml_table.pyi new file mode 100644 index 000000000..785f62e27 --- /dev/null +++ b/stubs/pyomo/dataportal/plugins/xml_table.pyi @@ -0,0 +1,14 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.dataportal import TableData as TableData +from pyomo.dataportal.factory import DataManagerFactory as DataManagerFactory + +ET: Incomplete +ET_available: Incomplete + +class XMLTable(TableData): + def __init__(self) -> None: ... + def open(self) -> None: ... + def close(self) -> None: ... + def read(self) -> None: ... + def write(self, data) -> None: ... diff --git a/stubs/pyomo/dataportal/process_data.pyi b/stubs/pyomo/dataportal/process_data.pyi new file mode 100644 index 000000000..06187fddc --- /dev/null +++ b/stubs/pyomo/dataportal/process_data.pyi @@ -0,0 +1,13 @@ +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.collections import OrderedDict as OrderedDict +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.core.base.set import UnknownSetDimen as UnknownSetDimen +from pyomo.core.base.util import flatten_tuple as flatten_tuple +from pyomo.dataportal.factory import DataManagerFactory as DataManagerFactory +from pyomo.dataportal.factory import UnknownDataManager as UnknownDataManager +from pyomo.dataportal.parse_datacmds import parse_data_commands as parse_data_commands + +numlist: Incomplete +logger: Incomplete diff --git a/stubs/pyomo/duality/__init__.pyi b/stubs/pyomo/duality/__init__.pyi new file mode 100644 index 000000000..1346defbb --- /dev/null +++ b/stubs/pyomo/duality/__init__.pyi @@ -0,0 +1 @@ +from pyomo.duality import collect as collect diff --git a/stubs/pyomo/duality/collect.pyi b/stubs/pyomo/duality/collect.pyi new file mode 100644 index 000000000..ac4bc5ac9 --- /dev/null +++ b/stubs/pyomo/duality/collect.pyi @@ -0,0 +1,9 @@ +from pyomo.common.collections import Bunch as Bunch +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import Objective as Objective +from pyomo.core.base import Var as Var +from pyomo.core.base import maximize as maximize +from pyomo.core.base import minimize as minimize +from pyomo.repn.standard_repn import generate_standard_repn as generate_standard_repn + +def collect_linear_terms(block, unfixed): ... diff --git a/stubs/pyomo/duality/lagrangian_dual.pyi b/stubs/pyomo/duality/lagrangian_dual.pyi new file mode 100644 index 000000000..45207df32 --- /dev/null +++ b/stubs/pyomo/duality/lagrangian_dual.pyi @@ -0,0 +1,22 @@ +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.core import AbstractModel as AbstractModel +from pyomo.core import Constraint as Constraint +from pyomo.core import Objective as Objective +from pyomo.core import Set as Set +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core import Var as Var +from pyomo.core import maximize as maximize +from pyomo.core.plugins.transform.hierarchy import ( + IsomorphicTransformation as IsomorphicTransformation, +) +from pyomo.core.plugins.transform.standard_form import StandardForm as StandardForm +from pyomo.core.plugins.transform.util import partial as partial +from pyomo.core.plugins.transform.util import process_canonical_repn as process_canonical_repn +from pyomo.repn import generate_standard_repn as generate_standard_repn + +class DualTransformation(IsomorphicTransformation): + def __init__(self, **kwds) -> None: ... + +class _sparse(dict): + def __init__(self, default, *args, **kwds) -> None: ... + def __getitem__(self, ndx): ... diff --git a/stubs/pyomo/duality/plugins.pyi b/stubs/pyomo/duality/plugins.pyi new file mode 100644 index 000000000..4d9888bbc --- /dev/null +++ b/stubs/pyomo/duality/plugins.pyi @@ -0,0 +1,22 @@ +from _typeshed import Incomplete +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.core.base import Block as Block +from pyomo.core.base import ConcreteModel as ConcreteModel +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import Model as Model +from pyomo.core.base import NonNegativeReals as NonNegativeReals +from pyomo.core.base import NonPositiveReals as NonPositiveReals +from pyomo.core.base import Objective as Objective +from pyomo.core.base import Reals as Reals +from pyomo.core.base import Transformation as Transformation +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.core.base import Var as Var +from pyomo.core.base import minimize as minimize +from pyomo.duality.collect import collect_linear_terms as collect_linear_terms + +def load() -> None: ... + +logger: Incomplete + +class LinearDual_PyomoTransformation(Transformation): + def __init__(self) -> None: ... diff --git a/stubs/pyomo/environ/__init__.pyi b/stubs/pyomo/environ/__init__.pyi new file mode 100644 index 000000000..4eebab6b7 --- /dev/null +++ b/stubs/pyomo/environ/__init__.pyi @@ -0,0 +1,173 @@ +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.deprecation import relocated_module_attribute as relocated_module_attribute +from pyomo.core import AbstractModel as AbstractModel +from pyomo.core import AlphaNumericTextLabeler as AlphaNumericTextLabeler +from pyomo.core import Any as Any +from pyomo.core import AnyWithNone as AnyWithNone +from pyomo.core import Binary as Binary +from pyomo.core import Block as Block +from pyomo.core import Boolean as Boolean +from pyomo.core import BooleanConstant as BooleanConstant +from pyomo.core import BooleanSet as BooleanSet +from pyomo.core import BooleanValue as BooleanValue +from pyomo.core import BooleanVar as BooleanVar +from pyomo.core import BooleanVarList as BooleanVarList +from pyomo.core import BuildAction as BuildAction +from pyomo.core import BuildCheck as BuildCheck +from pyomo.core import CNameLabeler as CNameLabeler +from pyomo.core import Component as Component +from pyomo.core import ComponentUID as ComponentUID +from pyomo.core import ConcreteModel as ConcreteModel +from pyomo.core import Connector as Connector +from pyomo.core import Constraint as Constraint +from pyomo.core import ConstraintList as ConstraintList +from pyomo.core import CounterLabeler as CounterLabeler +from pyomo.core import CuidLabeler as CuidLabeler +from pyomo.core import EmptySet as EmptySet +from pyomo.core import Expr_if as Expr_if +from pyomo.core import Expression as Expression +from pyomo.core import ExternalFunction as ExternalFunction +from pyomo.core import IntegerInterval as IntegerInterval +from pyomo.core import Integers as Integers +from pyomo.core import IntegerSet as IntegerSet +from pyomo.core import LogicalConstraint as LogicalConstraint +from pyomo.core import LogicalConstraintList as LogicalConstraintList +from pyomo.core import Model as Model +from pyomo.core import ModelComponentFactory as ModelComponentFactory +from pyomo.core import NameLabeler as NameLabeler +from pyomo.core import NegativeIntegers as NegativeIntegers +from pyomo.core import NegativeReals as NegativeReals +from pyomo.core import NonNegativeIntegers as NonNegativeIntegers +from pyomo.core import NonNegativeReals as NonNegativeReals +from pyomo.core import NonPositiveIntegers as NonPositiveIntegers +from pyomo.core import NonPositiveReals as NonPositiveReals +from pyomo.core import NumericLabeler as NumericLabeler +from pyomo.core import NumericValue as NumericValue +from pyomo.core import Objective as Objective +from pyomo.core import ObjectiveList as ObjectiveList +from pyomo.core import Param as Param +from pyomo.core import PercentFraction as PercentFraction +from pyomo.core import Piecewise as Piecewise +from pyomo.core import PositiveIntegers as PositiveIntegers +from pyomo.core import PositiveReals as PositiveReals +from pyomo.core import PyomoObject as PyomoObject +from pyomo.core import PyomoOptions as PyomoOptions +from pyomo.core import RangeSet as RangeSet +from pyomo.core import RealInterval as RealInterval +from pyomo.core import Reals as Reals +from pyomo.core import RealSet as RealSet +from pyomo.core import Reference as Reference +from pyomo.core import ScalarBlock as ScalarBlock +from pyomo.core import ScalarBooleanVar as ScalarBooleanVar +from pyomo.core import ScalarVar as ScalarVar +from pyomo.core import Set as Set +from pyomo.core import SetOf as SetOf +from pyomo.core import ShortNameLabeler as ShortNameLabeler +from pyomo.core import SortComponents as SortComponents +from pyomo.core import SOSConstraint as SOSConstraint +from pyomo.core import Suffix as Suffix +from pyomo.core import SymbolMap as SymbolMap +from pyomo.core import TextLabeler as TextLabeler +from pyomo.core import Transformation as Transformation +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core import TraversalStrategy as TraversalStrategy +from pyomo.core import UnitInterval as UnitInterval +from pyomo.core import Var as Var +from pyomo.core import VarList as VarList +from pyomo.core import ZeroConstant as ZeroConstant +from pyomo.core import acos as acos +from pyomo.core import acosh as acosh +from pyomo.core import active_components as active_components +from pyomo.core import active_components_data as active_components_data +from pyomo.core import active_export_suffix_generator as active_export_suffix_generator +from pyomo.core import active_import_suffix_generator as active_import_suffix_generator +from pyomo.core import all_different as all_different +from pyomo.core import as_boolean as as_boolean +from pyomo.core import asin as asin +from pyomo.core import asinh as asinh +from pyomo.core import atan as atan +from pyomo.core import atanh as atanh +from pyomo.core import atleast as atleast +from pyomo.core import atmost as atmost +from pyomo.core import base as base +from pyomo.core import boolean_value as boolean_value +from pyomo.core import calculus as calculus +from pyomo.core import ceil as ceil +from pyomo.core import components as components +from pyomo.core import components_data as components_data +from pyomo.core import cos as cos +from pyomo.core import cosh as cosh +from pyomo.core import count_if as count_if +from pyomo.core import differentiate as differentiate +from pyomo.core import display as display +from pyomo.core import dot_product as dot_product +from pyomo.core import equivalent as equivalent +from pyomo.core import exactly as exactly +from pyomo.core import exp as exp +from pyomo.core import expr as expr +from pyomo.core import expr_common as expr_common +from pyomo.core import expr_errors as expr_errors +from pyomo.core import floor as floor +from pyomo.core import global_option as global_option +from pyomo.core import implies as implies +from pyomo.core import inequality as inequality +from pyomo.core import instance2dat as instance2dat +from pyomo.core import is_constant as is_constant +from pyomo.core import is_fixed as is_fixed +from pyomo.core import is_potentially_variable as is_potentially_variable +from pyomo.core import is_variable_type as is_variable_type +from pyomo.core import kernel as kernel +from pyomo.core import land as land +from pyomo.core import linear_expression as linear_expression +from pyomo.core import lnot as lnot +from pyomo.core import log as log +from pyomo.core import log10 as log10 +from pyomo.core import logical_expr as logical_expr +from pyomo.core import lor as lor +from pyomo.core import maximize as maximize +from pyomo.core import minimize as minimize +from pyomo.core import name as name +from pyomo.core import native_logical_values as native_logical_values +from pyomo.core import native_numeric_types as native_numeric_types +from pyomo.core import native_types as native_types +from pyomo.core import nonlinear_expression as nonlinear_expression +from pyomo.core import nonpyomo_leaf_types as nonpyomo_leaf_types +from pyomo.core import numeric_expr as numeric_expr +from pyomo.core import numvalue as numvalue +from pyomo.core import plugins as plugins +from pyomo.core import polynomial_degree as polynomial_degree +from pyomo.core import prod as prod +from pyomo.core import quicksum as quicksum +from pyomo.core import sequence as sequence +from pyomo.core import set_options as set_options +from pyomo.core import simple_constraint_rule as simple_constraint_rule +from pyomo.core import simple_constraintlist_rule as simple_constraintlist_rule +from pyomo.core import simple_objective_rule as simple_objective_rule +from pyomo.core import simple_objectivelist_rule as simple_objectivelist_rule +from pyomo.core import simple_set_rule as simple_set_rule +from pyomo.core import sin as sin +from pyomo.core import sinh as sinh +from pyomo.core import sqrt as sqrt +from pyomo.core import sum_product as sum_product +from pyomo.core import summation as summation +from pyomo.core import symbol_map as symbol_map +from pyomo.core import symbol_map_from_instance as symbol_map_from_instance +from pyomo.core import sympy_tools as sympy_tools +from pyomo.core import tan as tan +from pyomo.core import tanh as tanh +from pyomo.core import taylor_series as taylor_series +from pyomo.core import taylor_series_expansion as taylor_series_expansion +from pyomo.core import value as value +from pyomo.core import visitor as visitor +from pyomo.core import xor as xor +from pyomo.core.base import util as util +from pyomo.core.base.units_container import as_quantity as as_quantity +from pyomo.core.base.units_container import units as units +from pyomo.dataportal import DataPortal as DataPortal +from pyomo.opt import SolverFactory as SolverFactory +from pyomo.opt import SolverManagerFactory as SolverManagerFactory +from pyomo.opt import SolverStatus as SolverStatus +from pyomo.opt import TerminationCondition as TerminationCondition +from pyomo.opt import UnknownSolver as UnknownSolver +from pyomo.opt import assert_optimal_termination as assert_optimal_termination +from pyomo.opt import check_optimal_termination as check_optimal_termination diff --git a/stubs/pyomo/future.pyi b/stubs/pyomo/future.pyi new file mode 100644 index 000000000..99cb12eef --- /dev/null +++ b/stubs/pyomo/future.pyi @@ -0,0 +1,4 @@ +__doc__: str + +def __getattr__(name): ... +def solver_factory(version=None): ... diff --git a/stubs/pyomo/gdp/__init__.pyi b/stubs/pyomo/gdp/__init__.pyi new file mode 100644 index 000000000..57ecaa0a6 --- /dev/null +++ b/stubs/pyomo/gdp/__init__.pyi @@ -0,0 +1,5 @@ +from pyomo.gdp.disjunct import Disjunct as Disjunct +from pyomo.gdp.disjunct import DisjunctData as DisjunctData +from pyomo.gdp.disjunct import Disjunction as Disjunction +from pyomo.gdp.disjunct import DisjunctionData as DisjunctionData +from pyomo.gdp.disjunct import GDP_Error as GDP_Error diff --git a/stubs/pyomo/gdp/basic_step.pyi b/stubs/pyomo/gdp/basic_step.pyi new file mode 100644 index 000000000..a1363e6ca --- /dev/null +++ b/stubs/pyomo/gdp/basic_step.pyi @@ -0,0 +1,13 @@ +from _typeshed import Incomplete +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.core import Block as Block +from pyomo.core import Constraint as Constraint +from pyomo.core import ConstraintList as ConstraintList +from pyomo.core import Set as Set +from pyomo.core.base import Reference as Reference +from pyomo.gdp.disjunct import Disjunct as Disjunct +from pyomo.gdp.disjunct import Disjunction as Disjunction + +logger: Incomplete + +def apply_basic_step(disjunctions_or_constraints): ... diff --git a/stubs/pyomo/gdp/disjunct.pyi b/stubs/pyomo/gdp/disjunct.pyi new file mode 100644 index 000000000..e2613e235 --- /dev/null +++ b/stubs/pyomo/gdp/disjunct.pyi @@ -0,0 +1,171 @@ +from _typeshed import Incomplete +from pyomo.common.autoslots import AutoSlots as AutoSlots +from pyomo.common.deprecation import RenamedClass as RenamedClass +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.common.errors import PyomoException as PyomoException +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.common.numeric_types import native_logical_types as native_logical_types +from pyomo.common.numeric_types import native_types as native_types +from pyomo.common.timing import ConstructionTimer as ConstructionTimer +from pyomo.core import Any as Any +from pyomo.core import Binary as Binary +from pyomo.core import Block as Block +from pyomo.core import BooleanValue as BooleanValue +from pyomo.core import ConstraintList as ConstraintList +from pyomo.core import LogicalConstraintList as LogicalConstraintList +from pyomo.core import ModelComponentFactory as ModelComponentFactory +from pyomo.core import ScalarBooleanVar as ScalarBooleanVar +from pyomo.core import ScalarVar as ScalarVar +from pyomo.core import value as value +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.component import ActiveComponent as ActiveComponent +from pyomo.core.base.component import ActiveComponentData as ActiveComponentData +from pyomo.core.base.component import ComponentData as ComponentData +from pyomo.core.base.global_set import UnindexedComponent_index as UnindexedComponent_index +from pyomo.core.base.indexed_component import ActiveIndexedComponent as ActiveIndexedComponent +from pyomo.core.base.misc import apply_indexed_rule as apply_indexed_rule +from pyomo.core.expr.expr_common import ExpressionType as ExpressionType + +logger: Incomplete + +class GDP_Error(PyomoException): ... + +class AutoLinkedBinaryVar(ScalarVar): + INTEGER_TOLERANCE: float + __autoslot_mappers__: Incomplete + def __init__(self, boolean_var=None) -> None: ... + def get_associated_boolean(self): ... + def set_value( + self, val, skip_validation: bool = False, _propagate_value: bool = True + ) -> None: ... + def fix(self, value=..., skip_validation: bool = False) -> None: ... + def unfix(self) -> None: ... + +class AutoLinkedBooleanVar(ScalarBooleanVar): + def as_numeric(self): ... + def as_binary(self): ... + def set_value( + self, val, skip_validation: bool = False, _propagate_value: bool = True + ) -> None: ... + def fix(self, value=..., skip_validation: bool = False) -> None: ... + def unfix(self) -> None: ... + @property + def bounds(self): ... + @bounds.setter + def bounds(self, value) -> None: ... + @property + def lb(self): ... + @lb.setter + def lb(self, value) -> None: ... + @property + def ub(self): ... + @ub.setter + def ub(self, value) -> None: ... + def __abs__(self): ... + def __float__(self) -> float: ... + def __int__(self) -> int: ... + def __neg__(self): ... + def __bool__(self) -> bool: ... + def __pos__(self): ... + def get_units(self): ... + def has_lb(self): ... + def has_ub(self): ... + def is_binary(self): ... + def is_continuous(self): ... + def is_integer(self): ... + def polynomial_degree(self): ... + def __le__(self, arg): ... + def __lt__(self, arg): ... + def __ge__(self, arg): ... + def __gt__(self, arg): ... + def __eq__(self, arg): ... + def __ne__(self, arg): ... + def __add__(self, arg): ... + def __div__(self, arg): ... + def __mul__(self, arg): ... + def __pow__(self, arg): ... + def __sub__(self, arg): ... + def __truediv__(self, arg): ... + def __iadd__(self, arg): ... + def __idiv__(self, arg): ... + def __imul__(self, arg): ... + def __ipow__(self, arg): ... + def __isub__(self, arg): ... + def __itruediv__(self, arg): ... + def __radd__(self, arg): ... + def __rdiv__(self, arg): ... + def __rmul__(self, arg): ... + def __rpow__(self, arg): ... + def __rsub__(self, arg): ... + def __rtruediv__(self, arg): ... + def setlb(self, arg): ... + def setub(self, arg): ... + +class _Initializer: + value: int + deferred_value: int + function: int + dict_like: int + @staticmethod + def process(arg): ... + +class DisjunctData(BlockData): + __autoslot_mappers__: Incomplete + @property + def transformation_block(self): ... + indicator_var: Incomplete + binary_indicator_var: Incomplete + def __init__(self, component) -> None: ... + def activate(self) -> None: ... + def deactivate(self) -> None: ... + +class _DisjunctData(metaclass=RenamedClass): + __renamed__new_class__ = DisjunctData + __renamed__version__: str + +class Disjunct(Block): + def __new__(cls, *args, **kwds): ... + def __init__(self, *args, **kwargs) -> None: ... + +class ScalarDisjunct(DisjunctData, Disjunct): + def __init__(self, *args, **kwds) -> None: ... + +class SimpleDisjunct(metaclass=RenamedClass): + __renamed__new_class__ = ScalarDisjunct + __renamed__version__: str + +class IndexedDisjunct(Disjunct): + @property + def active(self): ... + +class DisjunctionData(ActiveComponentData): + __autoslot_mappers__: Incomplete + @property + def algebraic_constraint(self): ... + disjuncts: Incomplete + xor: bool + def __init__(self, component=None) -> None: ... + def set_value(self, expr) -> None: ... + +class _DisjunctionData(metaclass=RenamedClass): + __renamed__new_class__ = DisjunctionData + __renamed__version__: str + +class Disjunction(ActiveIndexedComponent): + def __new__(cls, *args, **kwds): ... + def __init__(self, *args, **kwargs) -> None: ... + def construct(self, data=None) -> None: ... + +class ScalarDisjunction(DisjunctionData, Disjunction): + def __init__(self, *args, **kwds) -> None: ... + def set_value(self, expr): ... + +class SimpleDisjunction(metaclass=RenamedClass): + __renamed__new_class__ = ScalarDisjunction + __renamed__version__: str + +class IndexedDisjunction(Disjunction): + @property + def active(self): ... diff --git a/stubs/pyomo/gdp/plugins/__init__.pyi b/stubs/pyomo/gdp/plugins/__init__.pyi new file mode 100644 index 000000000..8f6326a14 --- /dev/null +++ b/stubs/pyomo/gdp/plugins/__init__.pyi @@ -0,0 +1,3 @@ +from pyomo.common.deprecation import moved_module as moved_module + +def load() -> None: ... diff --git a/stubs/pyomo/gdp/plugins/between_steps.pyi b/stubs/pyomo/gdp/plugins/between_steps.pyi new file mode 100644 index 000000000..e19f6d2fb --- /dev/null +++ b/stubs/pyomo/gdp/plugins/between_steps.pyi @@ -0,0 +1,5 @@ +from pyomo.core import Transformation as Transformation +from pyomo.core import TransformationFactory as TransformationFactory + +class BetweenSteps_Transformation(Transformation): + def __init__(self) -> None: ... diff --git a/stubs/pyomo/gdp/plugins/bigm.pyi b/stubs/pyomo/gdp/plugins/bigm.pyi new file mode 100644 index 000000000..b5dd46f2e --- /dev/null +++ b/stubs/pyomo/gdp/plugins/bigm.pyi @@ -0,0 +1,59 @@ +from weakref import ReferenceType as ReferenceType + +from _typeshed import Incomplete +from pyomo.common.autoslots import AutoSlots as AutoSlots +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.common.gc_manager import PauseGC as PauseGC +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.contrib.cp.transform.logical_to_disjunctive_program import ( + LogicalToDisjunctive as LogicalToDisjunctive, +) +from pyomo.core import Any as Any +from pyomo.core import Binary as Binary +from pyomo.core import Block as Block +from pyomo.core import BooleanVar as BooleanVar +from pyomo.core import Connector as Connector +from pyomo.core import Constraint as Constraint +from pyomo.core import Expression as Expression +from pyomo.core import NonNegativeIntegers as NonNegativeIntegers +from pyomo.core import Param as Param +from pyomo.core import RangeSet as RangeSet +from pyomo.core import Set as Set +from pyomo.core import SetOf as SetOf +from pyomo.core import SortComponents as SortComponents +from pyomo.core import TraversalStrategy as TraversalStrategy +from pyomo.core import Var as Var +from pyomo.core import value as value +from pyomo.core.base import Reference as Reference +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.core.util import target_list as target_list +from pyomo.gdp import Disjunct as Disjunct +from pyomo.gdp import Disjunction as Disjunction +from pyomo.gdp import GDP_Error as GDP_Error +from pyomo.gdp.plugins.bigm_mixin import _BigM_MixIn +from pyomo.gdp.plugins.gdp_to_mip_transformation import ( + GDP_to_MIP_Transformation as GDP_to_MIP_Transformation, +) +from pyomo.gdp.util import is_child_of as is_child_of +from pyomo.network import Port as Port +from pyomo.repn import generate_standard_repn as generate_standard_repn + +logger: Incomplete + +class _BigMData(AutoSlots.Mixin): + bigm_src: Incomplete + def __init__(self) -> None: ... + +class BigM_Transformation(GDP_to_MIP_Transformation, _BigM_MixIn): + CONFIG: Incomplete + transformation_name: str + def __init__(self) -> None: ... + def get_m_value_src(self, constraint): ... + def get_M_value_src(self, constraint): ... + def get_M_value(self, constraint): ... + def get_all_M_values_by_constraint(self, model): ... + def get_largest_M_value(self, model): ... diff --git a/stubs/pyomo/gdp/plugins/bigm_mixin.pyi b/stubs/pyomo/gdp/plugins/bigm_mixin.pyi new file mode 100644 index 000000000..5b7fa7cab --- /dev/null +++ b/stubs/pyomo/gdp/plugins/bigm_mixin.pyi @@ -0,0 +1,8 @@ +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.contrib.fbbt.expression_bounds_walker import ( + ExpressionBoundsVisitor as ExpressionBoundsVisitor, +) +from pyomo.core import Suffix as Suffix +from pyomo.gdp import GDP_Error as GDP_Error + +class _BigM_MixIn: ... diff --git a/stubs/pyomo/gdp/plugins/bilinear.pyi b/stubs/pyomo/gdp/plugins/bilinear.pyi new file mode 100644 index 000000000..480525f2d --- /dev/null +++ b/stubs/pyomo/gdp/plugins/bilinear.pyi @@ -0,0 +1,17 @@ +from _typeshed import Incomplete +from pyomo.core import Block as Block +from pyomo.core import Constraint as Constraint +from pyomo.core import Objective as Objective +from pyomo.core import Set as Set +from pyomo.core import SortComponents as SortComponents +from pyomo.core import Transformation as Transformation +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core import VarList as VarList +from pyomo.gdp import Disjunct as Disjunct +from pyomo.gdp import Disjunction as Disjunction +from pyomo.repn import generate_standard_repn as generate_standard_repn + +logger: Incomplete + +class Bilinear_Transformation(Transformation): + def __init__(self) -> None: ... diff --git a/stubs/pyomo/gdp/plugins/binary_multiplication.pyi b/stubs/pyomo/gdp/plugins/binary_multiplication.pyi new file mode 100644 index 000000000..0c7858cb8 --- /dev/null +++ b/stubs/pyomo/gdp/plugins/binary_multiplication.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.core.util import target_list as target_list +from pyomo.gdp import Disjunction as Disjunction + +from .gdp_to_mip_transformation import GDP_to_MIP_Transformation as GDP_to_MIP_Transformation + +logger: Incomplete + +class GDPBinaryMultiplicationTransformation(GDP_to_MIP_Transformation): + CONFIG: Incomplete + transformation_name: str + def __init__(self) -> None: ... diff --git a/stubs/pyomo/gdp/plugins/bound_pretransformation.pyi b/stubs/pyomo/gdp/plugins/bound_pretransformation.pyi new file mode 100644 index 000000000..742d34535 --- /dev/null +++ b/stubs/pyomo/gdp/plugins/bound_pretransformation.pyi @@ -0,0 +1,32 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.core import Any as Any +from pyomo.core import Block as Block +from pyomo.core import Constraint as Constraint +from pyomo.core import NonNegativeIntegers as NonNegativeIntegers +from pyomo.core import SortComponents as SortComponents +from pyomo.core import Var as Var +from pyomo.core import value as value +from pyomo.core.base import Transformation as Transformation +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.core.expr import identify_variables as identify_variables +from pyomo.core.util import target_list as target_list +from pyomo.gdp import Disjunct as Disjunct +from pyomo.gdp import Disjunction as Disjunction +from pyomo.gdp import GDP_Error as GDP_Error +from pyomo.gdp.util import get_gdp_tree as get_gdp_tree +from pyomo.gdp.util import is_child_of as is_child_of +from pyomo.repn.standard_repn import generate_standard_repn as generate_standard_repn + +logger: Incomplete + +class BoundPretransformation(Transformation): + CONFIG: Incomplete + transformation_name: str + logger: Incomplete + def __init__(self) -> None: ... + def get_transformed_constraints(self, v, disjunction): ... diff --git a/stubs/pyomo/gdp/plugins/cuttingplane.pyi b/stubs/pyomo/gdp/plugins/cuttingplane.pyi new file mode 100644 index 000000000..7deeeed6b --- /dev/null +++ b/stubs/pyomo/gdp/plugins/cuttingplane.pyi @@ -0,0 +1,77 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import In as In +from pyomo.common.config import NonNegativeFloat as NonNegativeFloat +from pyomo.common.config import PositiveInt as PositiveInt +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.contrib.fme.fourier_motzkin_elimination import ( + Fourier_Motzkin_Elimination_Transformation as Fourier_Motzkin_Elimination_Transformation, +) +from pyomo.core import Any as Any +from pyomo.core import Block as Block +from pyomo.core import ComponentMap as ComponentMap +from pyomo.core import Constraint as Constraint +from pyomo.core import NonNegativeIntegers as NonNegativeIntegers +from pyomo.core import NonNegativeReals as NonNegativeReals +from pyomo.core import Objective as Objective +from pyomo.core import Param as Param +from pyomo.core import Reals as Reals +from pyomo.core import SortComponents as SortComponents +from pyomo.core import Suffix as Suffix +from pyomo.core import Transformation as Transformation +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core import Var as Var +from pyomo.core import value as value +from pyomo.core.expr import differentiate as differentiate +from pyomo.gdp import Disjunct as Disjunct +from pyomo.gdp import Disjunction as Disjunction +from pyomo.gdp import GDP_Error as GDP_Error +from pyomo.gdp.util import NORMAL as NORMAL +from pyomo.gdp.util import ( + clone_without_expression_components as clone_without_expression_components, +) +from pyomo.gdp.util import verify_successful_solve as verify_successful_solve +from pyomo.opt import SolverFactory as SolverFactory +from pyomo.repn import generate_standard_repn as generate_standard_repn + +logger: Incomplete + +def do_not_tighten(m): ... +def create_cuts_fme( + transBlock_rHull, + var_info, + hull_to_bigm_map, + rBigM_linear_constraints, + rHull_vars, + disaggregated_vars, + norm, + cut_threshold, + zero_tolerance, + integer_arithmetic, + constraint_tolerance, +): ... +def create_cuts_normal_vector( + transBlock_rHull, + var_info, + hull_to_bigm_map, + rBigM_linear_constraints, + rHull_vars, + disaggregated_vars, + norm, + cut_threshold, + zero_tolerance, + integer_arithmetic, + constraint_tolerance, +): ... +def back_off_constraint_with_calculated_cut_violation( + cut, transBlock_rHull, bigm_to_hull_map, opt, stream_solver, TOL +) -> None: ... +def back_off_constraint_by_fixed_tolerance( + cut, transBlock_rHull, bigm_to_hull_map, opt, stream_solver, TOL +) -> None: ... + +class CuttingPlane_Transformation(Transformation): + CONFIG: Incomplete + def __init__(self) -> None: ... diff --git a/stubs/pyomo/gdp/plugins/fix_disjuncts.pyi b/stubs/pyomo/gdp/plugins/fix_disjuncts.pyi new file mode 100644 index 000000000..636631a8f --- /dev/null +++ b/stubs/pyomo/gdp/plugins/fix_disjuncts.pyi @@ -0,0 +1,23 @@ +from math import fabs as fabs + +from _typeshed import Incomplete +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import NonNegativeFloat as NonNegativeFloat +from pyomo.contrib.cp.transform.logical_to_disjunctive_program import ( + LogicalToDisjunctive as LogicalToDisjunctive, +) +from pyomo.core.base import Transformation as Transformation +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.core.base.block import Block as Block +from pyomo.core.expr.numvalue import value as value +from pyomo.gdp import GDP_Error as GDP_Error +from pyomo.gdp.disjunct import Disjunct as Disjunct +from pyomo.gdp.disjunct import Disjunction as Disjunction +from pyomo.gdp.plugins.bigm import BigM_Transformation as BigM_Transformation + +logger: Incomplete + +class GDP_Disjunct_Fixer(Transformation): + def __init__(self, **kwargs) -> None: ... + CONFIG: Incomplete diff --git a/stubs/pyomo/gdp/plugins/gdp_to_mip_transformation.pyi b/stubs/pyomo/gdp/plugins/gdp_to_mip_transformation.pyi new file mode 100644 index 000000000..389efb19e --- /dev/null +++ b/stubs/pyomo/gdp/plugins/gdp_to_mip_transformation.pyi @@ -0,0 +1,46 @@ +from _typeshed import Incomplete +from pyomo.common.autoslots import AutoSlots as AutoSlots +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import DefaultComponentMap as DefaultComponentMap +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.core import Any as Any +from pyomo.core import Block as Block +from pyomo.core import BooleanVar as BooleanVar +from pyomo.core import Connector as Connector +from pyomo.core import Constraint as Constraint +from pyomo.core import Expression as Expression +from pyomo.core import NonNegativeIntegers as NonNegativeIntegers +from pyomo.core import Param as Param +from pyomo.core import RangeSet as RangeSet +from pyomo.core import Reference as Reference +from pyomo.core import Set as Set +from pyomo.core import SetOf as SetOf +from pyomo.core import Suffix as Suffix +from pyomo.core import Var as Var +from pyomo.core.base import Transformation as Transformation +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.core.base.external import ExternalFunction as ExternalFunction +from pyomo.gdp import Disjunct as Disjunct +from pyomo.gdp import Disjunction as Disjunction +from pyomo.gdp import GDP_Error as GDP_Error +from pyomo.gdp.util import get_gdp_tree as get_gdp_tree +from pyomo.gdp.util import get_src_constraint as get_src_constraint +from pyomo.gdp.util import get_src_disjunct as get_src_disjunct +from pyomo.gdp.util import get_src_disjunction as get_src_disjunction +from pyomo.gdp.util import get_transformed_constraints as get_transformed_constraints +from pyomo.network import Port as Port + +class _GDPTransformationData(AutoSlots.Mixin): + src_constraint: Incomplete + transformed_constraints: Incomplete + def __init__(self) -> None: ... + +class GDP_to_MIP_Transformation(Transformation): + logger: Incomplete + handlers: Incomplete + def __init__(self, logger) -> None: ... + def get_src_disjunct(self, transBlock): ... + def get_src_disjunction(self, xor_constraint): ... + def get_src_constraint(self, transformedConstraint): ... + def get_transformed_constraints(self, srcConstraint): ... diff --git a/stubs/pyomo/gdp/plugins/gdp_var_mover.pyi b/stubs/pyomo/gdp/plugins/gdp_var_mover.pyi new file mode 100644 index 000000000..1df0733e9 --- /dev/null +++ b/stubs/pyomo/gdp/plugins/gdp_var_mover.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core import TraversalStrategy as TraversalStrategy +from pyomo.core.base import Block as Block +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import Transformation as Transformation +from pyomo.core.base.indexed_component import ActiveIndexedComponent as ActiveIndexedComponent +from pyomo.gdp import Disjunct as Disjunct +from pyomo.gdp import Disjunction as Disjunction +from pyomo.gdp import GDP_Error as GDP_Error + +logger: Incomplete + +class HACK_GDP_Disjunct_Reclassifier(Transformation): ... diff --git a/stubs/pyomo/gdp/plugins/hull.pyi b/stubs/pyomo/gdp/plugins/hull.pyi new file mode 100644 index 000000000..b05f2e87c --- /dev/null +++ b/stubs/pyomo/gdp/plugins/hull.pyi @@ -0,0 +1,64 @@ +from _typeshed import Incomplete +from pyomo.common import deprecated as deprecated +from pyomo.common.autoslots import AutoSlots as AutoSlots +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.collections import DefaultComponentMap as DefaultComponentMap +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.core import Any as Any +from pyomo.core import Binary as Binary +from pyomo.core import Block as Block +from pyomo.core import BooleanVar as BooleanVar +from pyomo.core import Connector as Connector +from pyomo.core import Constraint as Constraint +from pyomo.core import Expression as Expression +from pyomo.core import NonNegativeIntegers as NonNegativeIntegers +from pyomo.core import Param as Param +from pyomo.core import RangeSet as RangeSet +from pyomo.core import Reals as Reals +from pyomo.core import Set as Set +from pyomo.core import SetOf as SetOf +from pyomo.core import SortComponents as SortComponents +from pyomo.core import Suffix as Suffix +from pyomo.core import TraversalStrategy as TraversalStrategy +from pyomo.core import Var as Var +from pyomo.core import value as value +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.core.expr.numvalue import ZeroConstant as ZeroConstant +from pyomo.core.util import target_list as target_list +from pyomo.gdp import Disjunct as Disjunct +from pyomo.gdp import Disjunction as Disjunction +from pyomo.gdp import GDP_Error as GDP_Error +from pyomo.gdp.disjunct import DisjunctData as DisjunctData +from pyomo.gdp.plugins.gdp_to_mip_transformation import ( + GDP_to_MIP_Transformation as GDP_to_MIP_Transformation, +) +from pyomo.gdp.util import ( + clone_without_expression_components as clone_without_expression_components, +) +from pyomo.gdp.util import is_child_of as is_child_of +from pyomo.util.vars_from_expressions import get_vars_from_components as get_vars_from_components + +logger: Incomplete + +class _HullTransformationData(AutoSlots.Mixin): + disaggregated_var_map: Incomplete + original_var_map: Incomplete + bigm_constraint_map: Incomplete + disaggregation_constraint_map: Incomplete + def __init__(self) -> None: ... + +class Hull_Reformulation(GDP_to_MIP_Transformation): + CONFIG: Incomplete + transformation_name: str + def __init__(self) -> None: ... + def get_disaggregated_var(self, v, disjunct, raise_exception: bool = True): ... + def get_src_var(self, disaggregated_var): ... + def get_disaggregation_constraint( + self, original_var, disjunction, raise_exception: bool = True + ): ... + def get_var_bounds_constraint(self, v, disjunct=None): ... + def get_transformed_constraints(self, cons): ... + +class _Deprecated_Name_Hull(Hull_Reformulation): + def __init__(self) -> None: ... diff --git a/stubs/pyomo/gdp/plugins/multiple_bigm.pyi b/stubs/pyomo/gdp/plugins/multiple_bigm.pyi new file mode 100644 index 000000000..67ebebda2 --- /dev/null +++ b/stubs/pyomo/gdp/plugins/multiple_bigm.pyi @@ -0,0 +1,52 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.gc_manager import PauseGC as PauseGC +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.core import Any as Any +from pyomo.core import Binary as Binary +from pyomo.core import Block as Block +from pyomo.core import BooleanVar as BooleanVar +from pyomo.core import Connector as Connector +from pyomo.core import Constraint as Constraint +from pyomo.core import Expression as Expression +from pyomo.core import ExternalFunction as ExternalFunction +from pyomo.core import NonNegativeIntegers as NonNegativeIntegers +from pyomo.core import Objective as Objective +from pyomo.core import Param as Param +from pyomo.core import Set as Set +from pyomo.core import SetOf as SetOf +from pyomo.core import SortComponents as SortComponents +from pyomo.core import Suffix as Suffix +from pyomo.core import Var as Var +from pyomo.core import maximize as maximize +from pyomo.core import minimize as minimize +from pyomo.core import value as value +from pyomo.core.base import Reference as Reference +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.core.util import target_list as target_list +from pyomo.gdp import Disjunct as Disjunct +from pyomo.gdp import Disjunction as Disjunction +from pyomo.gdp import GDP_Error as GDP_Error +from pyomo.gdp.plugins.bigm_mixin import _BigM_MixIn +from pyomo.gdp.plugins.gdp_to_mip_transformation import ( + GDP_to_MIP_Transformation as GDP_to_MIP_Transformation, +) +from pyomo.gdp.util import get_gdp_tree as get_gdp_tree +from pyomo.network import Port as Port +from pyomo.opt import SolverFactory as SolverFactory +from pyomo.opt import TerminationCondition as TerminationCondition +from pyomo.repn import generate_standard_repn as generate_standard_repn + +logger: Incomplete + +def Solver(val): ... + +class MultipleBigMTransformation(GDP_to_MIP_Transformation, _BigM_MixIn): + CONFIG: Incomplete + transformation_name: str + def __init__(self) -> None: ... + def get_src_constraints(self, transformedConstraint): ... + def get_all_M_values(self, model): ... diff --git a/stubs/pyomo/gdp/plugins/partition_disjuncts.pyi b/stubs/pyomo/gdp/plugins/partition_disjuncts.pyi new file mode 100644 index 000000000..bc84d3929 --- /dev/null +++ b/stubs/pyomo/gdp/plugins/partition_disjuncts.pyi @@ -0,0 +1,61 @@ +from math import floor as floor + +from _typeshed import Incomplete +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.contrib.fbbt.fbbt import compute_bounds_on_expr as compute_bounds_on_expr +from pyomo.core import Binary as Binary +from pyomo.core import Block as Block +from pyomo.core import BooleanVar as BooleanVar +from pyomo.core import ComponentMap as ComponentMap +from pyomo.core import ConcreteModel as ConcreteModel +from pyomo.core import Connector as Connector +from pyomo.core import Constraint as Constraint +from pyomo.core import Expression as Expression +from pyomo.core import LogicalConstraint as LogicalConstraint +from pyomo.core import LogicalConstraintList as LogicalConstraintList +from pyomo.core import NonNegativeIntegers as NonNegativeIntegers +from pyomo.core import Objective as Objective +from pyomo.core import Param as Param +from pyomo.core import RangeSet as RangeSet +from pyomo.core import Reference as Reference +from pyomo.core import Set as Set +from pyomo.core import SetOf as SetOf +from pyomo.core import SortComponents as SortComponents +from pyomo.core import Suffix as Suffix +from pyomo.core import Transformation as Transformation +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core import TraversalStrategy as TraversalStrategy +from pyomo.core import Var as Var +from pyomo.core import maximize as maximize +from pyomo.core import value as value +from pyomo.core.base.external import ExternalFunction as ExternalFunction +from pyomo.core.util import target_list as target_list +from pyomo.gdp import Disjunct as Disjunct +from pyomo.gdp import Disjunction as Disjunction +from pyomo.gdp import GDP_Error as GDP_Error +from pyomo.gdp.util import NORMAL as NORMAL +from pyomo.gdp.util import ( + clone_without_expression_components as clone_without_expression_components, +) +from pyomo.gdp.util import get_gdp_tree as get_gdp_tree +from pyomo.gdp.util import is_child_of as is_child_of +from pyomo.gdp.util import verify_successful_solve as verify_successful_solve +from pyomo.network import Port as Port +from pyomo.opt import SolverFactory as SolverFactory +from pyomo.repn import generate_standard_repn as generate_standard_repn +from pyomo.util.vars_from_expressions import get_vars_from_components as get_vars_from_components + +logger: Incomplete + +def arbitrary_partition(disjunction, P): ... +def compute_optimal_bounds(expr, global_constraints, opt): ... +def compute_fbbt_bounds(expr, global_constraints, opt): ... + +class PartitionDisjuncts_Transformation(Transformation): + CONFIG: Incomplete + handlers: Incomplete + def __init__(self) -> None: ... diff --git a/stubs/pyomo/gdp/plugins/transform_current_disjunctive_state.pyi b/stubs/pyomo/gdp/plugins/transform_current_disjunctive_state.pyi new file mode 100644 index 000000000..70b875c86 --- /dev/null +++ b/stubs/pyomo/gdp/plugins/transform_current_disjunctive_state.pyi @@ -0,0 +1,19 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.errors import InfeasibleConstraintException as InfeasibleConstraintException +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.core.base import Any as Any +from pyomo.core.base import Block as Block +from pyomo.core.base import ReverseTransformationToken as ReverseTransformationToken +from pyomo.core.base import SortComponents as SortComponents +from pyomo.core.base import Transformation as Transformation +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.core.util import target_list as target_list +from pyomo.gdp import Disjunct as Disjunct +from pyomo.gdp import Disjunction as Disjunction +from pyomo.gdp.util import GDP_Error as GDP_Error + +class TransformCurrentDisjunctiveState(Transformation): + CONFIG: Incomplete diff --git a/stubs/pyomo/gdp/transformed_disjunct.pyi b/stubs/pyomo/gdp/transformed_disjunct.pyi new file mode 100644 index 000000000..80d5f32b5 --- /dev/null +++ b/stubs/pyomo/gdp/transformed_disjunct.pyi @@ -0,0 +1,14 @@ +from _typeshed import Incomplete +from pyomo.common.autoslots import AutoSlots as AutoSlots +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.block import IndexedBlock as IndexedBlock +from pyomo.core.base.global_set import UnindexedComponent_index as UnindexedComponent_index +from pyomo.core.base.global_set import UnindexedComponent_set as UnindexedComponent_set + +class _TransformedDisjunctData(BlockData): + __autoslot_mappers__: Incomplete + @property + def src_disjunct(self): ... + def __init__(self, component) -> None: ... + +class _TransformedDisjunct(IndexedBlock): ... diff --git a/stubs/pyomo/gdp/util.pyi b/stubs/pyomo/gdp/util.pyi new file mode 100644 index 000000000..a386dad20 --- /dev/null +++ b/stubs/pyomo/gdp/util.pyi @@ -0,0 +1,58 @@ +from collections import defaultdict as defaultdict +from collections.abc import Generator + +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.collections import OrderedSet as OrderedSet +from pyomo.core import Block as Block +from pyomo.core import LogicalConstraint as LogicalConstraint +from pyomo.core import SortComponents as SortComponents +from pyomo.core import Suffix as Suffix +from pyomo.core import TraversalStrategy as TraversalStrategy +from pyomo.core import value as value +from pyomo.core.base.block import BlockData as BlockData +from pyomo.gdp import Disjunction as Disjunction +from pyomo.gdp import GDP_Error as GDP_Error +from pyomo.gdp.disjunct import Disjunct as Disjunct +from pyomo.gdp.disjunct import DisjunctData as DisjunctData +from pyomo.opt import SolverStatus as SolverStatus +from pyomo.opt import TerminationCondition as TerminationCondition + +logger: Incomplete + +class NORMAL: ... +class INFEASIBLE: ... +class NONOPTIMAL: ... + +def verify_successful_solve(results): ... +def clone_without_expression_components(expr, substitute=None): ... + +class GDPTree: + def __init__(self) -> None: ... + @property + def vertices(self): ... + def add_node(self, u) -> None: ... + def parent(self, u): ... + def children(self, u): ... + def parent_disjunct(self, u): ... + def root_disjunct(self, u): ... + def add_node(self, u) -> None: ... + def add_edge(self, u, v) -> None: ... + def topological_sort(self): ... + def reverse_topological_sort(self): ... + def in_degree(self, u): ... + def is_leaf(self, u): ... + @property + def leaves(self) -> Generator[Incomplete]: ... + @property + def disjunct_nodes(self) -> Generator[Incomplete]: ... + +def get_gdp_tree(targets, instance, knownBlocks=None): ... +def preprocess_targets(targets, instance, knownBlocks, gdp_tree=None): ... +def is_child_of(parent, child, knownBlocks=None): ... +def get_src_disjunction(xor_constraint): ... +def get_src_disjunct(transBlock): ... +def get_src_constraint(transformedConstraint): ... +def get_transformed_constraints(srcConstraint): ... +def check_model_algebraic(instance): ... diff --git a/stubs/pyomo/kernel/__init__.pyi b/stubs/pyomo/kernel/__init__.pyi new file mode 100644 index 000000000..8874f6d18 --- /dev/null +++ b/stubs/pyomo/kernel/__init__.pyi @@ -0,0 +1,137 @@ +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.core.expr import Expr_if as Expr_if +from pyomo.core.expr import acos as acos +from pyomo.core.expr import acosh as acosh +from pyomo.core.expr import asin as asin +from pyomo.core.expr import asinh as asinh +from pyomo.core.expr import atan as atan +from pyomo.core.expr import atanh as atanh +from pyomo.core.expr import atleast as atleast +from pyomo.core.expr import atmost as atmost +from pyomo.core.expr import boolean_value as boolean_value +from pyomo.core.expr import calculus as calculus +from pyomo.core.expr import ceil as ceil +from pyomo.core.expr import cnf_walker as cnf_walker +from pyomo.core.expr import cos as cos +from pyomo.core.expr import cosh as cosh +from pyomo.core.expr import equivalent as equivalent +from pyomo.core.expr import exactly as exactly +from pyomo.core.expr import exp as exp +from pyomo.core.expr import expr_common as expr_common +from pyomo.core.expr import expr_errors as expr_errors +from pyomo.core.expr import floor as floor +from pyomo.core.expr import implies as implies +from pyomo.core.expr import inequality as inequality +from pyomo.core.expr import land as land +from pyomo.core.expr import linear_expression as linear_expression +from pyomo.core.expr import lnot as lnot +from pyomo.core.expr import log as log +from pyomo.core.expr import log10 as log10 +from pyomo.core.expr import logical_expr as logical_expr +from pyomo.core.expr import lor as lor +from pyomo.core.expr import nonlinear_expression as nonlinear_expression +from pyomo.core.expr import numeric_expr as numeric_expr +from pyomo.core.expr import numvalue as numvalue +from pyomo.core.expr import sin as sin +from pyomo.core.expr import sinh as sinh +from pyomo.core.expr import sqrt as sqrt +from pyomo.core.expr import symbol_map as symbol_map +from pyomo.core.expr import sympy_tools as sympy_tools +from pyomo.core.expr import tan as tan +from pyomo.core.expr import tanh as tanh +from pyomo.core.expr import taylor_series as taylor_series +from pyomo.core.expr import template_expr as template_expr +from pyomo.core.expr import visitor as visitor +from pyomo.core.expr import xor as xor +from pyomo.core.expr.boolean_value import BooleanValue as BooleanValue +from pyomo.core.expr.calculus.derivatives import differentiate as differentiate +from pyomo.core.expr.numvalue import NumericValue as NumericValue +from pyomo.core.expr.numvalue import ZeroConstant as ZeroConstant +from pyomo.core.expr.numvalue import is_constant as is_constant +from pyomo.core.expr.numvalue import is_fixed as is_fixed +from pyomo.core.expr.numvalue import is_potentially_variable as is_potentially_variable +from pyomo.core.expr.numvalue import is_variable_type as is_variable_type +from pyomo.core.expr.numvalue import native_numeric_types as native_numeric_types +from pyomo.core.expr.numvalue import native_types as native_types +from pyomo.core.expr.numvalue import polynomial_degree as polynomial_degree +from pyomo.core.expr.numvalue import value as value +from pyomo.core.expr.taylor_series import taylor_series_expansion as taylor_series_expansion +from pyomo.core.kernel.block import block as block +from pyomo.core.kernel.block import block_dict as block_dict +from pyomo.core.kernel.block import block_list as block_list +from pyomo.core.kernel.block import block_tuple as block_tuple +from pyomo.core.kernel.constraint import constraint as constraint +from pyomo.core.kernel.constraint import constraint_dict as constraint_dict +from pyomo.core.kernel.constraint import constraint_list as constraint_list +from pyomo.core.kernel.constraint import constraint_tuple as constraint_tuple +from pyomo.core.kernel.constraint import linear_constraint as linear_constraint +from pyomo.core.kernel.expression import data_expression as data_expression +from pyomo.core.kernel.expression import expression as expression +from pyomo.core.kernel.expression import expression_dict as expression_dict +from pyomo.core.kernel.expression import expression_list as expression_list +from pyomo.core.kernel.expression import expression_tuple as expression_tuple +from pyomo.core.kernel.expression import noclone as noclone +from pyomo.core.kernel.heterogeneous_container import ( + IHeterogeneousContainer as IHeterogeneousContainer, +) +from pyomo.core.kernel.heterogeneous_container import ( + heterogeneous_containers as heterogeneous_containers, +) +from pyomo.core.kernel.matrix_constraint import matrix_constraint as matrix_constraint +from pyomo.core.kernel.objective import maximize as maximize +from pyomo.core.kernel.objective import minimize as minimize +from pyomo.core.kernel.objective import objective as objective +from pyomo.core.kernel.objective import objective_dict as objective_dict +from pyomo.core.kernel.objective import objective_list as objective_list +from pyomo.core.kernel.objective import objective_tuple as objective_tuple +from pyomo.core.kernel.parameter import functional_value as functional_value +from pyomo.core.kernel.parameter import parameter as parameter +from pyomo.core.kernel.parameter import parameter_dict as parameter_dict +from pyomo.core.kernel.parameter import parameter_list as parameter_list +from pyomo.core.kernel.parameter import parameter_tuple as parameter_tuple +from pyomo.core.kernel.piecewise_library.transforms import piecewise as piecewise +from pyomo.core.kernel.piecewise_library.transforms_nd import piecewise_nd as piecewise_nd +from pyomo.core.kernel.set_types import BooleanSet as BooleanSet +from pyomo.core.kernel.set_types import IntegerSet as IntegerSet +from pyomo.core.kernel.set_types import RealSet as RealSet +from pyomo.core.kernel.sos import sos as sos +from pyomo.core.kernel.sos import sos1 as sos1 +from pyomo.core.kernel.sos import sos2 as sos2 +from pyomo.core.kernel.sos import sos_dict as sos_dict +from pyomo.core.kernel.sos import sos_list as sos_list +from pyomo.core.kernel.sos import sos_tuple as sos_tuple +from pyomo.core.kernel.suffix import export_suffix_generator as export_suffix_generator +from pyomo.core.kernel.suffix import import_suffix_generator as import_suffix_generator +from pyomo.core.kernel.suffix import local_suffix_generator as local_suffix_generator +from pyomo.core.kernel.suffix import suffix as suffix +from pyomo.core.kernel.suffix import suffix_dict as suffix_dict +from pyomo.core.kernel.suffix import suffix_generator as suffix_generator +from pyomo.core.kernel.variable import variable as variable +from pyomo.core.kernel.variable import variable_dict as variable_dict +from pyomo.core.kernel.variable import variable_list as variable_list +from pyomo.core.kernel.variable import variable_tuple as variable_tuple +from pyomo.environ import Binary as Binary +from pyomo.environ import Boolean as Boolean +from pyomo.environ import IntegerInterval as IntegerInterval +from pyomo.environ import Integers as Integers +from pyomo.environ import NegativeIntegers as NegativeIntegers +from pyomo.environ import NegativeReals as NegativeReals +from pyomo.environ import NonNegativeIntegers as NonNegativeIntegers +from pyomo.environ import NonNegativeReals as NonNegativeReals +from pyomo.environ import NonPositiveIntegers as NonPositiveIntegers +from pyomo.environ import NonPositiveReals as NonPositiveReals +from pyomo.environ import PercentFraction as PercentFraction +from pyomo.environ import PositiveIntegers as PositiveIntegers +from pyomo.environ import PositiveReals as PositiveReals +from pyomo.environ import RealInterval as RealInterval +from pyomo.environ import Reals as Reals +from pyomo.environ import UnitInterval as UnitInterval +from pyomo.kernel.util import generate_names as generate_names +from pyomo.kernel.util import pprint as pprint +from pyomo.kernel.util import preorder_traversal as preorder_traversal +from pyomo.opt import SolverFactory as SolverFactory +from pyomo.opt import SolverStatus as SolverStatus +from pyomo.opt import TerminationCondition as TerminationCondition +from pyomo.version import __version__ as __version__ +from pyomo.version import version_info as version_info diff --git a/stubs/pyomo/kernel/util.pyi b/stubs/pyomo/kernel/util.pyi new file mode 100644 index 000000000..ae0c78ee9 --- /dev/null +++ b/stubs/pyomo/kernel/util.pyi @@ -0,0 +1,12 @@ +from collections.abc import Generator + +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.core.expr.numvalue import NumericValue as NumericValue +from pyomo.core.kernel.base import ICategorizedObject as ICategorizedObject + +def preorder_traversal( + node, ctype=..., active: bool = True, descend: bool = True +) -> Generator[Incomplete, None, Incomplete]: ... +def generate_names(node, convert=..., prefix: str = '', **kwds): ... +def pprint(obj, indent: int = 0, stream=...) -> None: ... diff --git a/stubs/pyomo/mpec/__init__.pyi b/stubs/pyomo/mpec/__init__.pyi new file mode 100644 index 000000000..5527fd29f --- /dev/null +++ b/stubs/pyomo/mpec/__init__.pyi @@ -0,0 +1,3 @@ +from pyomo.mpec.complementarity import Complementarity as Complementarity +from pyomo.mpec.complementarity import ComplementarityList as ComplementarityList +from pyomo.mpec.complementarity import complements as complements diff --git a/stubs/pyomo/mpec/complementarity.pyi b/stubs/pyomo/mpec/complementarity.pyi new file mode 100644 index 000000000..7dafec668 --- /dev/null +++ b/stubs/pyomo/mpec/complementarity.pyi @@ -0,0 +1,65 @@ +from typing import NamedTuple + +from _typeshed import Incomplete +from pyomo.common.deprecation import RenamedClass as RenamedClass +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.timing import ConstructionTimer as ConstructionTimer +from pyomo.core import Block as Block +from pyomo.core import Constraint as Constraint +from pyomo.core import Set as Set +from pyomo.core import Var as Var +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.disable_methods import disable_methods as disable_methods +from pyomo.core.base.global_set import UnindexedComponent_index as UnindexedComponent_index +from pyomo.core.base.initializer import CountedCallInitializer as CountedCallInitializer +from pyomo.core.base.initializer import IndexedCallInitializer as IndexedCallInitializer +from pyomo.core.base.initializer import Initializer as Initializer +from pyomo.core.expr.numvalue import ZeroConstant as ZeroConstant +from pyomo.core.expr.numvalue import as_numeric as as_numeric +from pyomo.core.expr.numvalue import native_numeric_types as native_numeric_types + +logger: Incomplete + +class ComplementarityTuple(NamedTuple): + arg0: Incomplete + arg1: Incomplete + +def complements(a, b): ... + +class ComplementarityData(BlockData): + c: Incomplete + v: Incomplete + ve: Incomplete + def to_standard_form(self) -> None: ... + def set_value(self, cc): ... + +class _ComplementarityData(metaclass=RenamedClass): + __renamed__new_class__ = ComplementarityData + __renamed__version__: str + +class Complementarity(Block): + def __new__(cls, *args, **kwds): ... + def __init__(self, *args, **kwargs) -> None: ... + def add(self, index, cc): ... + +class ScalarComplementarity(ComplementarityData, Complementarity): + def __init__(self, *args, **kwds) -> None: ... + +class SimpleComplementarity(metaclass=RenamedClass): + __renamed__new_class__ = ScalarComplementarity + __renamed__version__: str + +class AbstractScalarComplementarity(ScalarComplementarity): ... + +class AbstractSimpleComplementarity(metaclass=RenamedClass): + __renamed__new_class__ = AbstractScalarComplementarity + __renamed__version__: str + +class IndexedComplementarity(Complementarity): ... + +class ComplementarityList(IndexedComplementarity): + End: Incomplete + def __init__(self, **kwargs) -> None: ... + def add(self, expr): ... + def construct(self, data=None) -> None: ... diff --git a/stubs/pyomo/mpec/plugins/__init__.pyi b/stubs/pyomo/mpec/plugins/__init__.pyi new file mode 100644 index 000000000..08b671c7f --- /dev/null +++ b/stubs/pyomo/mpec/plugins/__init__.pyi @@ -0,0 +1 @@ +def load() -> None: ... diff --git a/stubs/pyomo/mpec/plugins/mpec1.pyi b/stubs/pyomo/mpec/plugins/mpec1.pyi new file mode 100644 index 000000000..796ad5a88 --- /dev/null +++ b/stubs/pyomo/mpec/plugins/mpec1.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from pyomo.core.base import Block as Block +from pyomo.core.base import ComponentUID as ComponentUID +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import Param as Param +from pyomo.core.base import SortComponents as SortComponents +from pyomo.core.base import Transformation as Transformation +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.gdp import Disjunct as Disjunct +from pyomo.mpec.complementarity import Complementarity as Complementarity + +logger: Incomplete + +class MPEC1_Transformation(Transformation): + def __init__(self) -> None: ... diff --git a/stubs/pyomo/mpec/plugins/mpec2.pyi b/stubs/pyomo/mpec/plugins/mpec2.pyi new file mode 100644 index 000000000..227cb2f85 --- /dev/null +++ b/stubs/pyomo/mpec/plugins/mpec2.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from pyomo.core.base import Block as Block +from pyomo.core.base import ComponentUID as ComponentUID +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import SortComponents as SortComponents +from pyomo.core.base import Transformation as Transformation +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.core.expr import inequality as inequality +from pyomo.gdp.disjunct import Disjunct as Disjunct +from pyomo.gdp.disjunct import Disjunction as Disjunction +from pyomo.mpec.complementarity import Complementarity as Complementarity + +logger: Incomplete + +class MPEC2_Transformation(Transformation): + def __init__(self) -> None: ... diff --git a/stubs/pyomo/mpec/plugins/mpec3.pyi b/stubs/pyomo/mpec/plugins/mpec3.pyi new file mode 100644 index 000000000..b962802fd --- /dev/null +++ b/stubs/pyomo/mpec/plugins/mpec3.pyi @@ -0,0 +1,12 @@ +from _typeshed import Incomplete +from pyomo.core.base import Block as Block +from pyomo.core.base import SortComponents as SortComponents +from pyomo.core.base import Transformation as Transformation +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.gdp import Disjunct as Disjunct +from pyomo.mpec.complementarity import Complementarity as Complementarity + +logger: Incomplete + +class MPEC3_Transformation(Transformation): + def __init__(self) -> None: ... diff --git a/stubs/pyomo/mpec/plugins/mpec4.pyi b/stubs/pyomo/mpec/plugins/mpec4.pyi new file mode 100644 index 000000000..89728c615 --- /dev/null +++ b/stubs/pyomo/mpec/plugins/mpec4.pyi @@ -0,0 +1,18 @@ +from _typeshed import Incomplete +from pyomo.core.base import Block as Block +from pyomo.core.base import ComponentUID as ComponentUID +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import SortComponents as SortComponents +from pyomo.core.base import Transformation as Transformation +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.core.base import Var as Var +from pyomo.core.base import value as value +from pyomo.gdp import Disjunct as Disjunct +from pyomo.mpec.complementarity import Complementarity as Complementarity + +logger: Incomplete + +class MPEC4_Transformation(Transformation): + def __init__(self) -> None: ... + def print_nl_form(self, instance) -> None: ... + def to_common_form(self, cdata, free_vars) -> None: ... diff --git a/stubs/pyomo/mpec/plugins/pathampl.pyi b/stubs/pyomo/mpec/plugins/pathampl.pyi new file mode 100644 index 000000000..a90673cec --- /dev/null +++ b/stubs/pyomo/mpec/plugins/pathampl.pyi @@ -0,0 +1,11 @@ +from _typeshed import Incomplete +from pyomo.common import Executable as Executable +from pyomo.common.collections import Bunch as Bunch +from pyomo.opt.base.solvers import SolverFactory as SolverFactory +from pyomo.solvers.plugins.solvers.ASL import ASL as ASL + +logger: Incomplete + +class PATHAMPL(ASL): + def __init__(self, **kwds) -> None: ... + def create_command_line(self, executable, problem_files): ... diff --git a/stubs/pyomo/mpec/plugins/solver1.pyi b/stubs/pyomo/mpec/plugins/solver1.pyi new file mode 100644 index 000000000..d9e486756 --- /dev/null +++ b/stubs/pyomo/mpec/plugins/solver1.pyi @@ -0,0 +1,7 @@ +import pyomo.opt +from pyomo.common.collections import Bunch as Bunch +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.opt import SolverFactory as SolverFactory + +class MPEC_Solver1(pyomo.opt.OptSolver): + def __init__(self, **kwds) -> None: ... diff --git a/stubs/pyomo/mpec/plugins/solver2.pyi b/stubs/pyomo/mpec/plugins/solver2.pyi new file mode 100644 index 000000000..d32a96874 --- /dev/null +++ b/stubs/pyomo/mpec/plugins/solver2.pyi @@ -0,0 +1,7 @@ +import pyomo.opt +from pyomo.common.collections import Bunch as Bunch +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.opt import SolverFactory as SolverFactory + +class MPEC_Solver2(pyomo.opt.OptSolver): + def __init__(self, **kwds) -> None: ... diff --git a/stubs/pyomo/neos/__init__.pyi b/stubs/pyomo/neos/__init__.pyi new file mode 100644 index 000000000..dbe6feb74 --- /dev/null +++ b/stubs/pyomo/neos/__init__.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +doc: Incomplete diff --git a/stubs/pyomo/neos/kestrel.pyi b/stubs/pyomo/neos/kestrel.pyi new file mode 100644 index 000000000..a9ffc0b5b --- /dev/null +++ b/stubs/pyomo/neos/kestrel.pyi @@ -0,0 +1,31 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import + +xmlrpclib: Incomplete +gzip: Incomplete +logger: Incomplete + +class NEOS: + scheme: str + host: str + port: str + +def ProxiedTransport(): ... + +class kestrelAMPL: + def __init__(self) -> None: ... + def __del__(self) -> None: ... + transport: Incomplete + neos: Incomplete + def setup_connection(self) -> None: ... + def tempfile(self): ... + def kill(self, jobNumber, password) -> None: ... + def solvers(self): ... + def retrieve(self, stub, jobNumber, password) -> None: ... + def submit(self, xml): ... + def getEmailAddress(self): ... + def getJobAndPassword(self): ... + def getAvailableSolvers(self): ... + options: Incomplete + def getSolverName(self): ... + def formXML(self, stub): ... diff --git a/stubs/pyomo/neos/plugins/NEOS.pyi b/stubs/pyomo/neos/plugins/NEOS.pyi new file mode 100644 index 000000000..6e76f783c --- /dev/null +++ b/stubs/pyomo/neos/plugins/NEOS.pyi @@ -0,0 +1,13 @@ +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.opt.base import ProblemFormat as ProblemFormat +from pyomo.opt.base import ResultsFormat as ResultsFormat +from pyomo.opt.base import SolverFactory as SolverFactory +from pyomo.opt.solver import SystemCallSolver as SystemCallSolver + +logger: Incomplete + +class NEOSRemoteSolver(SystemCallSolver): + def __init__(self, **kwds) -> None: ... + def create_command_line(self, executable, problem_files): ... diff --git a/stubs/pyomo/neos/plugins/__init__.pyi b/stubs/pyomo/neos/plugins/__init__.pyi new file mode 100644 index 000000000..08b671c7f --- /dev/null +++ b/stubs/pyomo/neos/plugins/__init__.pyi @@ -0,0 +1 @@ +def load() -> None: ... diff --git a/stubs/pyomo/neos/plugins/kestrel_plugin.pyi b/stubs/pyomo/neos/plugins/kestrel_plugin.pyi new file mode 100644 index 000000000..339ab29f2 --- /dev/null +++ b/stubs/pyomo/neos/plugins/kestrel_plugin.pyi @@ -0,0 +1,24 @@ +import types + +from _typeshed import Incomplete +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.core.base import Block as Block +from pyomo.opt import OptSolver as OptSolver +from pyomo.opt import SolverFactory as SolverFactory +from pyomo.opt import SolverManagerFactory as SolverManagerFactory +from pyomo.opt.parallel.async_solver import AsynchronousSolverManager as AsynchronousSolverManager +from pyomo.opt.parallel.manager import ActionManagerError as ActionManagerError +from pyomo.opt.parallel.manager import ActionStatus as ActionStatus + +xmlrpc_client: Incomplete +logger: Incomplete + +class SolverManager_NEOS(AsynchronousSolverManager): + kestrel: Incomplete + def clear(self) -> None: ... + def __exit__( + self, + t: type[BaseException] | None, + v: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: ... diff --git a/stubs/pyomo/network/__init__.pyi b/stubs/pyomo/network/__init__.pyi new file mode 100644 index 000000000..a5fd92fb0 --- /dev/null +++ b/stubs/pyomo/network/__init__.pyi @@ -0,0 +1,3 @@ +from pyomo.network.arc import Arc as Arc +from pyomo.network.decomposition import SequentialDecomposition as SequentialDecomposition +from pyomo.network.port import Port as Port diff --git a/stubs/pyomo/network/arc.pyi b/stubs/pyomo/network/arc.pyi new file mode 100644 index 000000000..9b6464b26 --- /dev/null +++ b/stubs/pyomo/network/arc.pyi @@ -0,0 +1,54 @@ +from _typeshed import Incomplete +from pyomo.common.deprecation import RenamedClass as RenamedClass +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.common.timing import ConstructionTimer as ConstructionTimer +from pyomo.core.base.component import ActiveComponentData as ActiveComponentData +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.global_set import UnindexedComponent_index as UnindexedComponent_index +from pyomo.core.base.indexed_component import ActiveIndexedComponent as ActiveIndexedComponent +from pyomo.core.base.indexed_component import UnindexedComponent_set as UnindexedComponent_set +from pyomo.core.base.misc import apply_indexed_rule as apply_indexed_rule +from pyomo.network.port import Port as Port + +logger: Incomplete + +class ArcData(ActiveComponentData): + def __init__(self, component=None, **kwds) -> None: ... + def __getattr__(self, name): ... + @property + def source(self): ... + src = source + @property + def destination(self): ... + dest = destination + @property + def ports(self): ... + @property + def directed(self): ... + @property + def expanded_block(self): ... + def set_value(self, vals) -> None: ... + +class _ArcData(metaclass=RenamedClass): + __renamed__new_class__ = ArcData + __renamed__version__: str + +class Arc(ActiveIndexedComponent): + def __new__(cls, *args, **kwds): ... + def __init__(self, *args, **kwds) -> None: ... + def construct(self, data=None) -> None: ... + +class ScalarArc(ArcData, Arc): + index: Incomplete + def __init__(self, *args, **kwds) -> None: ... + def set_value(self, vals) -> None: ... + +class SimpleArc(metaclass=RenamedClass): + __renamed__new_class__ = ScalarArc + __renamed__version__: str + +class IndexedArc(Arc): + def __init__(self, *args, **kwds) -> None: ... + @property + def expanded_block(self): ... diff --git a/stubs/pyomo/network/decomposition.pyi b/stubs/pyomo/network/decomposition.pyi new file mode 100644 index 000000000..da66166ed --- /dev/null +++ b/stubs/pyomo/network/decomposition.pyi @@ -0,0 +1,60 @@ +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.dependencies import networkx_available as networkx_available +from pyomo.common.dependencies import numpy as numpy +from pyomo.common.dependencies import numpy_available as numpy_available +from pyomo.core import Binary as Binary +from pyomo.core import ConcreteModel as ConcreteModel +from pyomo.core import Constraint as Constraint +from pyomo.core import Expression as Expression +from pyomo.core import Objective as Objective +from pyomo.core import Var as Var +from pyomo.core import minimize as minimize +from pyomo.core import value as value +from pyomo.core.expr import identify_variables as identify_variables +from pyomo.network import Arc as Arc +from pyomo.network import Port as Port +from pyomo.network.foqus_graph import FOQUSGraph as FOQUSGraph +from pyomo.repn import generate_standard_repn as generate_standard_repn + +imports_available: Incomplete +logger: Incomplete + +class SequentialDecomposition(FOQUSGraph): + cache: Incomplete + def __init__(self, **kwds) -> None: ... + def set_guesses_for(self, port, guesses) -> None: ... + def set_tear_set(self, tset) -> None: ... + def tear_set_arcs(self, G, method: str = 'mip', **kwds): ... + def indexes_to_arcs(self, G, lst): ... + def run(self, model, function): ... + def run_order(self, G, order, function, ignore=None, use_guesses: bool = False) -> None: ... + def pass_values(self, arc, fixed_inputs) -> None: ... + def pass_single_value(self, port, name, member, val, fixed) -> None: ... + def load_guesses(self, guesses, port, fixed) -> None: ... + def load_values(self, port, default, fixed, use_guesses) -> None: ... + def check_value_fix( + self, port, var, default, fixed, use_guesses, extensive: bool = False + ) -> None: ... + def combine_and_fix(self, port, name, obj, evars, fixed) -> None: ... + def source_dest_peer(self, arc, name, index=None): ... + def create_graph(self, model): ... + def select_tear_mip_model(self, G): ... + def select_tear_mip(self, G, solver, solver_io=None, solver_options={}): ... + def compute_err(self, svals, dvals, tol_type): ... + def tear_diff_direct(self, G, tears): ... + def pass_edges(self, G, edges) -> None: ... + def pass_tear_direct(self, G, tears) -> None: ... + def pass_tear_wegstein(self, G, tears, x) -> None: ... + def generate_gofx(self, G, tears): ... + def generate_first_x(self, G, tears): ... + def cacher(self, key, fcn, *args): ... + def tear_set(self, G): ... + def arc_to_edge(self, G): ... + def fixed_inputs(self): ... + def idx_to_node(self, G): ... + def node_to_idx(self, G): ... + def idx_to_edge(self, G): ... + def edge_to_idx(self, G): ... diff --git a/stubs/pyomo/network/foqus_graph.pyi b/stubs/pyomo/network/foqus_graph.pyi new file mode 100644 index 000000000..87edb1ec8 --- /dev/null +++ b/stubs/pyomo/network/foqus_graph.pyi @@ -0,0 +1,34 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies import numpy as numpy + +logger: Incomplete + +class FOQUSGraph: + def solve_tear_direct( + self, G, order, function, tears, outEdges, iterLim, tol, tol_type, report_diffs + ): ... + def solve_tear_wegstein( + self, + G, + order, + function, + tears, + outEdges, + iterLim, + tol, + tol_type, + report_diffs, + accel_min, + accel_max, + ): ... + def scc_collect(self, G, excludeEdges=None): ... + def scc_calculation_order(self, sccNodes, ie, oe): ... + def calculation_order(self, G, roots=None, nodes=None): ... + def tree_order(self, adj, adjR, roots=None): ... + def check_tear_set(self, G, tset): ... + def select_tear_heuristic(self, G): ... + def tear_upper_bound(self, G): ... + def sub_graph_edges(self, G, nodes): ... + def cycle_edge_matrix(self, G): ... + def all_cycles(self, G): ... + def adj_lists(self, G, excludeEdges=None, nodes=None, multi: bool = False): ... diff --git a/stubs/pyomo/network/plugins/__init__.pyi b/stubs/pyomo/network/plugins/__init__.pyi new file mode 100644 index 000000000..08b671c7f --- /dev/null +++ b/stubs/pyomo/network/plugins/__init__.pyi @@ -0,0 +1 @@ +def load() -> None: ... diff --git a/stubs/pyomo/network/plugins/expand_arcs.pyi b/stubs/pyomo/network/plugins/expand_arcs.pyi new file mode 100644 index 000000000..4604a9714 --- /dev/null +++ b/stubs/pyomo/network/plugins/expand_arcs.pyi @@ -0,0 +1,18 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.core.base import Block as Block +from pyomo.core.base import SortComponents as SortComponents +from pyomo.core.base import Transformation as Transformation +from pyomo.core.base import TransformationFactory as TransformationFactory +from pyomo.core.base.indexed_component import UnindexedComponent_set as UnindexedComponent_set +from pyomo.gdp import Disjunct as Disjunct +from pyomo.network import Arc as Arc +from pyomo.network.util import replicate_var as replicate_var + +logger: Incomplete +obj_iter_kwds: Incomplete + +class ExpandArcs(Transformation): ... diff --git a/stubs/pyomo/network/port.pyi b/stubs/pyomo/network/port.pyi new file mode 100644 index 000000000..dbf3a6c80 --- /dev/null +++ b/stubs/pyomo/network/port.pyi @@ -0,0 +1,81 @@ +from collections.abc import Generator + +from _typeshed import Incomplete +from pyomo.common.autoslots import AutoSlots as AutoSlots +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.deprecation import RenamedClass as RenamedClass +from pyomo.common.formatting import tabular_writer as tabular_writer +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.common.numeric_types import value as value +from pyomo.common.timing import ConstructionTimer as ConstructionTimer +from pyomo.core.base.component import ComponentData as ComponentData +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.constraint import Constraint as Constraint +from pyomo.core.base.global_set import UnindexedComponent_index as UnindexedComponent_index +from pyomo.core.base.indexed_component import IndexedComponent as IndexedComponent +from pyomo.core.base.indexed_component import UnindexedComponent_set as UnindexedComponent_set +from pyomo.core.base.label import alphanum_label_from_name as alphanum_label_from_name +from pyomo.core.base.misc import apply_indexed_rule as apply_indexed_rule +from pyomo.core.base.var import Var as Var +from pyomo.core.expr import identify_variables as identify_variables +from pyomo.core.expr.numvalue import as_numeric as as_numeric +from pyomo.network.util import create_var as create_var +from pyomo.network.util import tighten_var_domain as tighten_var_domain + +logger: Incomplete + +class PortData(ComponentData): + __autoslot_mappers__: Incomplete + vars: Incomplete + def __init__(self, component=None) -> None: ... + def __getattr__(self, name): ... + def arcs(self, active=None): ... + def sources(self, active=None): ... + def dests(self, active=None): ... + def set_value(self, value) -> None: ... + def polynomial_degree(self): ... + def is_fixed(self): ... + def is_potentially_variable(self): ... + def is_binary(self): ... + def is_integer(self): ... + def is_continuous(self): ... + def add(self, var, name=None, rule=None, **kwds) -> None: ... + def remove(self, name) -> None: ... + def rule_for(self, name): ... + def is_equality(self, name): ... + def is_extensive(self, name): ... + def fix(self) -> None: ... + def unfix(self) -> None: ... + free = unfix + def iter_vars( + self, expr_vars: bool = False, fixed=None, names: bool = False + ) -> Generator[Incomplete]: ... + def set_split_fraction(self, arc, val, fix: bool = True) -> None: ... + def get_split_fraction(self, arc): ... + +class _PortData(metaclass=RenamedClass): + __renamed__new_class__ = PortData + __renamed__version__: str + +class Port(IndexedComponent): + def __new__(cls, *args, **kwds): ... + def __init__(self, *args, **kwd) -> None: ... + def construct(self, data=None) -> None: ... + def display(self, prefix: str = '', ostream=None) -> None: ... + @staticmethod + def Equality(port, name, index_set) -> None: ... + @staticmethod + def Extensive( + port, name, index_set, include_splitfrac=None, write_var_sum: bool = True + ) -> None: ... + +class ScalarPort(Port, PortData): + def __init__(self, *args, **kwd) -> None: ... + +class SimplePort(metaclass=RenamedClass): + __renamed__new_class__ = ScalarPort + __renamed__version__: str + +class IndexedPort(Port): ... diff --git a/stubs/pyomo/network/util.pyi b/stubs/pyomo/network/util.pyi new file mode 100644 index 000000000..61774e05a --- /dev/null +++ b/stubs/pyomo/network/util.pyi @@ -0,0 +1,6 @@ +from pyomo.core import Var as Var +from pyomo.core.base.indexed_component import UnindexedComponent_set as UnindexedComponent_set + +def create_var(comp, name, block, index_set=None): ... +def tighten_var_domain(comp, new_var, index_set=None): ... +def replicate_var(comp, name, block, index_set=None): ... diff --git a/stubs/pyomo/opt/__init__.pyi b/stubs/pyomo/opt/__init__.pyi new file mode 100644 index 000000000..833ed3f05 --- /dev/null +++ b/stubs/pyomo/opt/__init__.pyi @@ -0,0 +1,44 @@ +from pyomo.common.deprecation import relocated_module_attribute as relocated_module_attribute +from pyomo.opt.base import AbstractProblemWriter as AbstractProblemWriter +from pyomo.opt.base import AbstractResultsReader as AbstractResultsReader +from pyomo.opt.base import BranchDirection as BranchDirection +from pyomo.opt.base import ConverterError as ConverterError +from pyomo.opt.base import OptSolver as OptSolver +from pyomo.opt.base import ProblemFormat as ProblemFormat +from pyomo.opt.base import ReaderFactory as ReaderFactory +from pyomo.opt.base import ResultsFormat as ResultsFormat +from pyomo.opt.base import SolverFactory as SolverFactory +from pyomo.opt.base import UnknownSolver as UnknownSolver +from pyomo.opt.base import WriterFactory as WriterFactory +from pyomo.opt.base import check_available_solvers as check_available_solvers +from pyomo.opt.base import convert as convert +from pyomo.opt.base import convert_problem as convert_problem +from pyomo.opt.base import error as error +from pyomo.opt.base import formats as formats +from pyomo.opt.base import guess_format as guess_format +from pyomo.opt.base import opt_config as opt_config +from pyomo.opt.base import solvers as solvers +from pyomo.opt.parallel import AsynchronousSolverManager as AsynchronousSolverManager +from pyomo.opt.parallel import SolverManagerFactory as SolverManagerFactory +from pyomo.opt.parallel import async_solver as async_solver +from pyomo.opt.parallel import local as local +from pyomo.opt.parallel import manager as manager +from pyomo.opt.problem import AmplModel as AmplModel +from pyomo.opt.problem import ampl as ampl +from pyomo.opt.results import ListContainer as ListContainer +from pyomo.opt.results import MapContainer as MapContainer +from pyomo.opt.results import ProblemSense as ProblemSense +from pyomo.opt.results import Solution as Solution +from pyomo.opt.results import SolutionStatus as SolutionStatus +from pyomo.opt.results import SolverResults as SolverResults +from pyomo.opt.results import SolverStatus as SolverStatus +from pyomo.opt.results import TerminationCondition as TerminationCondition +from pyomo.opt.results import UndefinedData as UndefinedData +from pyomo.opt.results import assert_optimal_termination as assert_optimal_termination +from pyomo.opt.results import check_optimal_termination as check_optimal_termination +from pyomo.opt.results import container as container +from pyomo.opt.results import ignore as ignore +from pyomo.opt.results import problem as problem +from pyomo.opt.results import results_ as results_ +from pyomo.opt.results import solution as solution +from pyomo.opt.results import undefined as undefined diff --git a/stubs/pyomo/opt/base/__init__.pyi b/stubs/pyomo/opt/base/__init__.pyi new file mode 100644 index 000000000..6ea26a9ce --- /dev/null +++ b/stubs/pyomo/opt/base/__init__.pyi @@ -0,0 +1,14 @@ +from pyomo.opt.base.convert import convert_problem as convert_problem +from pyomo.opt.base.error import ConverterError as ConverterError +from pyomo.opt.base.formats import ProblemFormat as ProblemFormat +from pyomo.opt.base.formats import ResultsFormat as ResultsFormat +from pyomo.opt.base.formats import guess_format as guess_format +from pyomo.opt.base.problem import AbstractProblemWriter as AbstractProblemWriter +from pyomo.opt.base.problem import BranchDirection as BranchDirection +from pyomo.opt.base.problem import WriterFactory as WriterFactory +from pyomo.opt.base.results import AbstractResultsReader as AbstractResultsReader +from pyomo.opt.base.results import ReaderFactory as ReaderFactory +from pyomo.opt.base.solvers import OptSolver as OptSolver +from pyomo.opt.base.solvers import SolverFactory as SolverFactory +from pyomo.opt.base.solvers import UnknownSolver as UnknownSolver +from pyomo.opt.base.solvers import check_available_solvers as check_available_solvers diff --git a/stubs/pyomo/opt/base/convert.pyi b/stubs/pyomo/opt/base/convert.pyi new file mode 100644 index 000000000..47924e2d9 --- /dev/null +++ b/stubs/pyomo/opt/base/convert.pyi @@ -0,0 +1,8 @@ +from _typeshed import Incomplete +from pyomo.common import Factory as Factory +from pyomo.opt.base.error import ConverterError as ConverterError +from pyomo.opt.base.formats import guess_format as guess_format + +ProblemConverterFactory: Incomplete + +def convert_problem(args, target_problem_type, valid_problem_types, has_capability=..., **kwds): ... diff --git a/stubs/pyomo/opt/base/error.pyi b/stubs/pyomo/opt/base/error.pyi new file mode 100644 index 000000000..b61d9fdc0 --- /dev/null +++ b/stubs/pyomo/opt/base/error.pyi @@ -0,0 +1,2 @@ +class ConverterError(Exception): + def __init__(self, *args, **kargs) -> None: ... diff --git a/stubs/pyomo/opt/base/formats.pyi b/stubs/pyomo/opt/base/formats.pyi new file mode 100644 index 000000000..e5c9194e7 --- /dev/null +++ b/stubs/pyomo/opt/base/formats.pyi @@ -0,0 +1,22 @@ +import enum + +class ProblemFormat(str, enum.Enum): + pyomo = 'pyomo' + cpxlp = 'cpxlp' + nl = 'nl' + mps = 'mps' + mod = 'mod' + lpxlp = 'lpxlp' + osil = 'osil' + bar = 'bar' + gams = 'gams' + +class ResultsFormat(str, enum.Enum): + osrl = 'osrl' + results = 'results' + sol = 'sol' + soln = 'soln' + yaml = 'yaml' + json = 'json' + +def guess_format(filename): ... diff --git a/stubs/pyomo/opt/base/opt_config.pyi b/stubs/pyomo/opt/base/opt_config.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/opt/base/problem.pyi b/stubs/pyomo/opt/base/problem.pyi new file mode 100644 index 000000000..e45c7014d --- /dev/null +++ b/stubs/pyomo/opt/base/problem.pyi @@ -0,0 +1,24 @@ +import types + +from _typeshed import Incomplete +from pyomo.common import Factory as Factory + +WriterFactory: Incomplete + +class AbstractProblemWriter: + format: Incomplete + def __init__(self, problem_format) -> None: ... + def __call__(self, model, filename, solver_capability, **kwds) -> None: ... + def __enter__(self): ... + def __exit__( + self, + t: type[BaseException] | None, + v: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: ... + +class BranchDirection: + default: int + down: int + up: int + ALL: Incomplete diff --git a/stubs/pyomo/opt/base/results.pyi b/stubs/pyomo/opt/base/results.pyi new file mode 100644 index 000000000..87cc9b852 --- /dev/null +++ b/stubs/pyomo/opt/base/results.pyi @@ -0,0 +1,18 @@ +import types + +from _typeshed import Incomplete +from pyomo.common import Factory as Factory + +ReaderFactory: Incomplete + +class AbstractResultsReader: + format: Incomplete + def __init__(self, results_format) -> None: ... + def __call__(self, filename, res=None, suffixes=[]) -> None: ... + def __enter__(self): ... + def __exit__( + self, + t: type[BaseException] | None, + v: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: ... diff --git a/stubs/pyomo/opt/base/solvers.pyi b/stubs/pyomo/opt/base/solvers.pyi new file mode 100644 index 000000000..b581377a7 --- /dev/null +++ b/stubs/pyomo/opt/base/solvers.pyi @@ -0,0 +1,99 @@ +import types + +from _typeshed import Incomplete +from pyomo.common import Factory as Factory +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.opt.base.convert import convert_problem as convert_problem +from pyomo.opt.base.formats import ResultsFormat as ResultsFormat + +logger: Incomplete + +class UnknownSolver: + type: Incomplete + options: Incomplete + def __init__(self, *args, **kwds) -> None: ... + def __enter__(self): ... + def __exit__( + self, + t: type[BaseException] | None, + v: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: ... + def available(self, exception_flag: bool = True): ... + def license_is_valid(self): ... + def warm_start_capable(self): ... + def solve(self, *args, **kwds) -> None: ... + def reset(self) -> None: ... + def set_options(self, istr) -> None: ... + def __bool__(self) -> bool: ... + def __getattr__(self, attr) -> None: ... + +class SolverFactoryClass(Factory): + def __call__(self, _name=None, **kwds): ... + +LegacySolverFactory: Incomplete +SolverFactory: Incomplete + +def check_available_solvers(*args): ... + +class OptSolver: + def __enter__(self): ... + def __exit__( + self, + t: type[BaseException] | None, + v: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: ... + @property + def tee(self) -> None: ... + @tee.setter + def tee(self, val) -> None: ... + @property + def suffixes(self) -> None: ... + @suffixes.setter + def suffixes(self, val) -> None: ... + @property + def keepfiles(self) -> None: ... + @keepfiles.setter + def keepfiles(self, val) -> None: ... + @property + def soln_file(self) -> None: ... + @soln_file.setter + def soln_file(self, val) -> None: ... + @property + def log_file(self) -> None: ... + @log_file.setter + def log_file(self, val) -> None: ... + @property + def symbolic_solver_labels(self) -> None: ... + @symbolic_solver_labels.setter + def symbolic_solver_labels(self, val) -> None: ... + @property + def warm_start_solve(self) -> None: ... + @warm_start_solve.setter + def warm_start_solve(self, val) -> None: ... + @property + def warm_start_file_name(self) -> None: ... + @warm_start_file_name.setter + def warm_start_file_name(self, val) -> None: ... + type: Incomplete + name: Incomplete + options: Incomplete + def __init__(self, **kwds) -> None: ... + def default_variable_value(self): ... + def __bool__(self) -> bool: ... + def version(self): ... + def problem_format(self): ... + def set_problem_format(self, format) -> None: ... + def results_format(self): ... + def set_results_format(self, format) -> None: ... + def has_capability(self, cap): ... + def available(self, exception_flag: bool = True): ... + def license_is_valid(self): ... + def warm_start_capable(self): ... + def solve(self, *args, **kwds): ... + def reset(self) -> None: ... + def set_options(self, istr) -> None: ... + def set_callback(self, name, callback_fn=None) -> None: ... + def config_block(self, init: bool = False): ... diff --git a/stubs/pyomo/opt/parallel/__init__.pyi b/stubs/pyomo/opt/parallel/__init__.pyi new file mode 100644 index 000000000..9131c3aa5 --- /dev/null +++ b/stubs/pyomo/opt/parallel/__init__.pyi @@ -0,0 +1,6 @@ +from pyomo.opt.parallel import local as local +from pyomo.opt.parallel import manager as manager +from pyomo.opt.parallel.async_solver import AsynchronousActionManager as AsynchronousActionManager +from pyomo.opt.parallel.async_solver import AsynchronousSolverManager as AsynchronousSolverManager +from pyomo.opt.parallel.async_solver import Factory as Factory +from pyomo.opt.parallel.async_solver import SolverManagerFactory as SolverManagerFactory diff --git a/stubs/pyomo/opt/parallel/async_solver.pyi b/stubs/pyomo/opt/parallel/async_solver.pyi new file mode 100644 index 000000000..99857d690 --- /dev/null +++ b/stubs/pyomo/opt/parallel/async_solver.pyi @@ -0,0 +1,19 @@ +import types + +from _typeshed import Incomplete +from pyomo.common import Factory as Factory +from pyomo.opt.parallel.manager import AsynchronousActionManager as AsynchronousActionManager + +SolverManagerFactory: Incomplete + +class AsynchronousSolverManager(AsynchronousActionManager): + def __init__(self, **kwds) -> None: ... + def solve(self, *args, **kwds): ... + def solve_all(self, solver, instances, **kwds) -> None: ... + def __enter__(self): ... + def __exit__( + self, + t: type[BaseException] | None, + v: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: ... diff --git a/stubs/pyomo/opt/parallel/local.pyi b/stubs/pyomo/opt/parallel/local.pyi new file mode 100644 index 000000000..28cd4c95b --- /dev/null +++ b/stubs/pyomo/opt/parallel/local.pyi @@ -0,0 +1,11 @@ +from _typeshed import Incomplete +from pyomo.common.collections import OrderedDict as OrderedDict +from pyomo.opt.parallel.async_solver import AsynchronousSolverManager as AsynchronousSolverManager +from pyomo.opt.parallel.async_solver import SolverManagerFactory as SolverManagerFactory +from pyomo.opt.parallel.manager import ActionHandle as ActionHandle +from pyomo.opt.parallel.manager import ActionManagerError as ActionManagerError +from pyomo.opt.parallel.manager import ActionStatus as ActionStatus + +class SolverManager_Serial(AsynchronousSolverManager): + results: Incomplete + def clear(self) -> None: ... diff --git a/stubs/pyomo/opt/parallel/manager.pyi b/stubs/pyomo/opt/parallel/manager.pyi new file mode 100644 index 000000000..ba3f1663b --- /dev/null +++ b/stubs/pyomo/opt/parallel/manager.pyi @@ -0,0 +1,44 @@ +import enum + +from _typeshed import Incomplete + +class ActionStatus(str, enum.Enum): + done = 'done' + error = 'error' + queued = 'queued' + executing = 'executing' + unknown = 'unknown' + +def solve_all_instances(solver_manager, solver, instances, **kwds) -> None: ... + +class ActionManagerError(Exception): + def __init__(self, *args, **kargs) -> None: ... + +class ActionHandle: + id_counter: int + id: int + status: Incomplete + explanation: Incomplete + def __init__(self, error: bool = False, explanation: str = '') -> None: ... + def update(self, ah) -> None: ... + def __lt__(self, other): ... + def __hash__(self): ... + def __eq__(self, other): ... + def __ne__(self, other): ... + +FailedActionHandle: Incomplete + +class AsynchronousActionManager: + def __init__(self) -> None: ... + event_handle: Incomplete + results: Incomplete + queued_action_counter: int + def clear(self) -> None: ... + def execute(self, *args, **kwds): ... + def queue(self, *args, **kwds): ... + def wait_all(self, *args) -> None: ... + def wait_any(self, *args): ... + def wait_for(self, ah): ... + def num_queued(self): ... + def get_status(self, ah): ... + def get_results(self, ah): ... diff --git a/stubs/pyomo/opt/plugins/__init__.pyi b/stubs/pyomo/opt/plugins/__init__.pyi new file mode 100644 index 000000000..08b671c7f --- /dev/null +++ b/stubs/pyomo/opt/plugins/__init__.pyi @@ -0,0 +1 @@ +def load() -> None: ... diff --git a/stubs/pyomo/opt/plugins/driver.pyi b/stubs/pyomo/opt/plugins/driver.pyi new file mode 100644 index 000000000..a2ddb884e --- /dev/null +++ b/stubs/pyomo/opt/plugins/driver.pyi @@ -0,0 +1,6 @@ +from _typeshed import Incomplete + +logger: Incomplete + +def setup_test_parser(parser) -> None: ... +def test_exec(options) -> None: ... diff --git a/stubs/pyomo/opt/plugins/res.pyi b/stubs/pyomo/opt/plugins/res.pyi new file mode 100644 index 000000000..4c1307fcb --- /dev/null +++ b/stubs/pyomo/opt/plugins/res.pyi @@ -0,0 +1,11 @@ +from pyomo.opt import SolverResults as SolverResults +from pyomo.opt.base import results as results +from pyomo.opt.base.formats import ResultsFormat as ResultsFormat + +class ResultsReader_yaml(results.AbstractResultsReader): + def __init__(self) -> None: ... + def __call__(self, filename, res=None, soln=None, suffixes=[]): ... + +class ResultsReader_json(results.AbstractResultsReader): + def __init__(self) -> None: ... + def __call__(self, filename, res=None, soln=None, suffixes=[]): ... diff --git a/stubs/pyomo/opt/plugins/sol.pyi b/stubs/pyomo/opt/plugins/sol.pyi new file mode 100644 index 000000000..9fda05639 --- /dev/null +++ b/stubs/pyomo/opt/plugins/sol.pyi @@ -0,0 +1,12 @@ +from _typeshed import Incomplete +from pyomo.opt import SolutionStatus as SolutionStatus +from pyomo.opt import SolverResults as SolverResults +from pyomo.opt import SolverStatus as SolverStatus +from pyomo.opt import TerminationCondition as TerminationCondition +from pyomo.opt.base import results as results +from pyomo.opt.base.formats import ResultsFormat as ResultsFormat + +class ResultsReader_sol(results.AbstractResultsReader): + name: Incomplete + def __init__(self, name=None) -> None: ... + def __call__(self, filename, res=None, soln=None, suffixes=[]): ... diff --git a/stubs/pyomo/opt/problem/__init__.pyi b/stubs/pyomo/opt/problem/__init__.pyi new file mode 100644 index 000000000..c6b1a9980 --- /dev/null +++ b/stubs/pyomo/opt/problem/__init__.pyi @@ -0,0 +1,4 @@ +from pyomo.opt.problem.ampl import AmplModel as AmplModel +from pyomo.opt.problem.ampl import ProblemFormat as ProblemFormat +from pyomo.opt.problem.ampl import convert_problem as convert_problem +from pyomo.opt.problem.ampl import guess_format as guess_format diff --git a/stubs/pyomo/opt/problem/ampl.pyi b/stubs/pyomo/opt/problem/ampl.pyi new file mode 100644 index 000000000..ad2c7ef76 --- /dev/null +++ b/stubs/pyomo/opt/problem/ampl.pyi @@ -0,0 +1,11 @@ +from _typeshed import Incomplete +from pyomo.opt.base import ProblemFormat as ProblemFormat +from pyomo.opt.base import convert_problem as convert_problem +from pyomo.opt.base import guess_format as guess_format + +class AmplModel: + modfile: Incomplete + datfile: Incomplete + def __init__(self, modfile, datfile=None) -> None: ... + def valid_problem_types(self): ... + def write(self, filename, format=None, solver_capability=None): ... diff --git a/stubs/pyomo/opt/results.pyi b/stubs/pyomo/opt/results.pyi new file mode 100644 index 000000000..69adf6db9 --- /dev/null +++ b/stubs/pyomo/opt/results.pyi @@ -0,0 +1,44 @@ +""" +Type stubs for Pyomo optimization module. + +This module provides minimal type definitions for Pyomo solver-related classes +to avoid requiring Pyomo as a dependency during type checking. +""" + +from enum import Enum +from typing import Any + +class SolverResults: + """Stub for Pyomo SolverResults class.""" + + def __init__(self, solver: Any = None) -> None: ... + def __getitem__(self, key: str) -> Any: ... + @property + def solver(self) -> Any: ... + +class SolverStatus(Enum): + """Stub for Pyomo SolverStatus enum.""" + + OK = 'ok' + WARNING = 'warning' + ERROR = 'error' + ABORTED = 'aborted' + UNKNOWN = 'unknown' + +class TerminationCondition(Enum): + """Stub for Pyomo TerminationCondition enum.""" + + convergenceCriteriaSatisfied = 0 + maxTimeLimit = 1 + iterationLimit = 2 + objectiveLimit = 3 + minStepLength = 4 + unbounded = 5 + provenInfeasible = 6 + locallyInfeasible = 7 + infeasibleOrUnbounded = 8 + error = 9 + interrupted = 10 + licensingProblems = 11 + emptyModel = 12 + unknown = 42 diff --git a/stubs/pyomo/opt/results/__init__.pyi b/stubs/pyomo/opt/results/__init__.pyi new file mode 100644 index 000000000..b42450891 --- /dev/null +++ b/stubs/pyomo/opt/results/__init__.pyi @@ -0,0 +1,14 @@ +from pyomo.common.deprecation import relocated_module_attribute as relocated_module_attribute +from pyomo.opt.results.container import ListContainer as ListContainer +from pyomo.opt.results.container import MapContainer as MapContainer +from pyomo.opt.results.container import UndefinedData as UndefinedData +from pyomo.opt.results.container import ignore as ignore +from pyomo.opt.results.container import undefined as undefined +from pyomo.opt.results.problem import ProblemSense as ProblemSense +from pyomo.opt.results.results_ import SolverResults as SolverResults +from pyomo.opt.results.solution import Solution as Solution +from pyomo.opt.results.solution import SolutionStatus as SolutionStatus +from pyomo.opt.results.solver import SolverStatus as SolverStatus +from pyomo.opt.results.solver import TerminationCondition as TerminationCondition +from pyomo.opt.results.solver import assert_optimal_termination as assert_optimal_termination +from pyomo.opt.results.solver import check_optimal_termination as check_optimal_termination diff --git a/stubs/pyomo/opt/results/container.pyi b/stubs/pyomo/opt/results/container.pyi new file mode 100644 index 000000000..3d897760b --- /dev/null +++ b/stubs/pyomo/opt/results/container.pyi @@ -0,0 +1,73 @@ +import enum + +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch + +class ScalarType(str, enum.Enum): + int = 'int' + time = 'time' + string = 'string' + float = 'float' + enum = 'enum' + undefined = 'undefined' + +default_print_options: Incomplete +strict: bool + +class UndefinedData: ... + +undefined: Incomplete +ignore: Incomplete + +class ScalarData: + value: Incomplete + description: Incomplete + units: Incomplete + scalar_description: Incomplete + scalar_type: Incomplete + def __init__( + self, + value=..., + description=None, + units=None, + scalar_description=None, + type=..., + required: bool = False, + ) -> None: ... + def get_value(self): ... + def pprint(self, ostream, option, prefix: str = '', repn=None): ... + def yaml_fix(self, val): ... + def load(self, repn) -> None: ... + +class ListContainer: + def __init__(self, cls) -> None: ... + def __len__(self) -> int: ... + def __getitem__(self, i): ... + def clear(self) -> None: ... + def delete(self, i) -> None: ... + def __call__(self, i: int = 0): ... + def __getattr__(self, name): ... + __class__: Incomplete + def __setattr__(self, name, val) -> None: ... + def insert(self, obj) -> None: ... + def add(self): ... + def pprint(self, ostream, option, prefix: str = '', repn=None): ... + def load(self, repn) -> None: ... + +class MapContainer(dict): + def __getnewargs_ex__(self): ... + def __getnewargs__(self): ... + def __new__(cls, *args, **kwargs): ... + def __init__(self, ordered: bool = False) -> None: ... + def keys(self): ... + def __getattr__(self, name): ... + __class__: Incomplete + def __setattr__(self, name, val) -> None: ... + def __setitem__(self, name, val) -> None: ... + def __getitem__(self, name): ... + def declare(self, name, **kwds) -> None: ... + def pprint( + self, ostream, option, from_list: bool = False, prefix: str = '', repn=None + ) -> None: ... + def load(self, repn) -> None: ... + def __getnewargs__(self): ... diff --git a/stubs/pyomo/opt/results/problem.pyi b/stubs/pyomo/opt/results/problem.pyi new file mode 100644 index 000000000..3028288f6 --- /dev/null +++ b/stubs/pyomo/opt/results/problem.pyi @@ -0,0 +1,11 @@ +from pyomo.common.enums import ExtendedEnumType as ExtendedEnumType +from pyomo.common.enums import IntEnum as IntEnum +from pyomo.common.enums import ObjectiveSense as ObjectiveSense +from pyomo.opt.results.container import MapContainer as MapContainer + +class ProblemSense(IntEnum, metaclass=ExtendedEnumType): + __base_enum__ = ObjectiveSense + unknown = 0 + +class ProblemInformation(MapContainer): + def __init__(self) -> None: ... diff --git a/stubs/pyomo/opt/results/results_.pyi b/stubs/pyomo/opt/results/results_.pyi new file mode 100644 index 000000000..50a9f92ba --- /dev/null +++ b/stubs/pyomo/opt/results/results_.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete +from pyomo.common.dependencies import yaml as yaml +from pyomo.common.dependencies import yaml_load_args as yaml_load_args +from pyomo.opt.results.container import ListContainer as ListContainer +from pyomo.opt.results.container import MapContainer as MapContainer +from pyomo.opt.results.container import ignore as ignore +from pyomo.opt.results.container import undefined as undefined +from pyomo.opt.results.solution import default_print_options as dpo + +logger: Incomplete + +class SolverResults(MapContainer): + undefined = undefined + default_print_options = dpo + def __init__(self) -> None: ... + def add(self, name, value, active, description) -> None: ... + def json_repn(self, options=None): ... + def write(self, **kwds) -> None: ... + def write_json(self, **kwds) -> None: ... + def write_yaml(self, **kwds) -> None: ... + def read(self, **kwds) -> None: ... diff --git a/stubs/pyomo/opt/results/solution.pyi b/stubs/pyomo/opt/results/solution.pyi new file mode 100644 index 000000000..628dc165d --- /dev/null +++ b/stubs/pyomo/opt/results/solution.pyi @@ -0,0 +1,43 @@ +import enum + +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.collections import OrderedDict as OrderedDict +from pyomo.opt.results.container import ListContainer as ListContainer +from pyomo.opt.results.container import MapContainer as MapContainer +from pyomo.opt.results.container import ignore as ignore + +default_print_options: Incomplete + +class SolutionStatus(str, enum.Enum): + bestSoFar = 'bestSoFar' + error = 'error' + feasible = 'feasible' + globallyOptimal = 'globallyOptimal' + infeasible = 'infeasible' + locallyOptimal = 'locallyOptimal' + optimal = 'optimal' + other = 'other' + stoppedByLimit = 'stoppedByLimit' + unbounded = 'unbounded' + unknown = 'unknown' + unsure = 'unsure' + +intlist: Incomplete +numlist: Incomplete + +class Solution(MapContainer): + def __init__(self) -> None: ... + variable: Incomplete + constraint: Incomplete + problem: Incomplete + objective: Incomplete + def load(self, repn) -> None: ... + def pprint(self, ostream, option, from_list: bool = False, prefix: str = '', repn=None): ... + +class SolutionSet(ListContainer): + def __init__(self) -> None: ... + def __len__(self) -> int: ... + def __call__(self, i: int = 1): ... + def pprint(self, ostream, option, prefix: str = '', repn=None): ... + def load(self, repn) -> None: ... diff --git a/stubs/pyomo/opt/results/solver.pyi b/stubs/pyomo/opt/results/solver.pyi new file mode 100644 index 000000000..eb8c38b9b --- /dev/null +++ b/stubs/pyomo/opt/results/solver.pyi @@ -0,0 +1,53 @@ +import enum + +from pyomo.opt.results.container import MapContainer as MapContainer +from pyomo.opt.results.container import ScalarType as ScalarType + +class SolverStatus(str, enum.Enum): + ok = 'ok' + warning = 'warning' + error = 'error' + aborted = 'aborted' + unknown = 'unknown' + +class TerminationCondition(str, enum.Enum): + unknown = 'unknown' + maxTimeLimit = 'maxTimeLimit' + maxIterations = 'maxIterations' + minFunctionValue = 'minFunctionValue' + minStepLength = 'minStepLength' + globallyOptimal = 'globallyOptimal' + locallyOptimal = 'locallyOptimal' + feasible = 'feasible' + optimal = 'optimal' + maxEvaluations = 'maxEvaluations' + other = 'other' + unbounded = 'unbounded' + infeasible = 'infeasible' + infeasibleOrUnbounded = 'infeasibleOrUnbounded' + invalidProblem = 'invalidProblem' + intermediateNonInteger = 'intermediateNonInteger' + noSolution = 'noSolution' + solverFailure = 'solverFailure' + internalSolverError = 'internalSolverError' + error = 'error' + userInterrupt = 'userInterrupt' + resourceInterrupt = 'resourceInterrupt' + licensingProblems = 'licensingProblems' + @staticmethod + def to_solver_status(tc): ... + +def check_optimal_termination(results): ... +def assert_optimal_termination(results) -> None: ... + +class BranchAndBoundStats(MapContainer): + def __init__(self) -> None: ... + +class BlackBoxStats(MapContainer): + def __init__(self) -> None: ... + +class SolverStatistics(MapContainer): + def __init__(self) -> None: ... + +class SolverInformation(MapContainer): + def __init__(self) -> None: ... diff --git a/stubs/pyomo/opt/solver/__init__.pyi b/stubs/pyomo/opt/solver/__init__.pyi new file mode 100644 index 000000000..d8ef6d90e --- /dev/null +++ b/stubs/pyomo/opt/solver/__init__.pyi @@ -0,0 +1,6 @@ +from pyomo.opt.solver.ilmcmd import ILMLicensedSystemCallSolver as ILMLicensedSystemCallSolver +from pyomo.opt.solver.shellcmd import OptSolver as OptSolver +from pyomo.opt.solver.shellcmd import ResultsFormat as ResultsFormat +from pyomo.opt.solver.shellcmd import SolverResults as SolverResults +from pyomo.opt.solver.shellcmd import SolverStatus as SolverStatus +from pyomo.opt.solver.shellcmd import SystemCallSolver as SystemCallSolver diff --git a/stubs/pyomo/opt/solver/ilmcmd.pyi b/stubs/pyomo/opt/solver/ilmcmd.pyi new file mode 100644 index 000000000..2bd45407e --- /dev/null +++ b/stubs/pyomo/opt/solver/ilmcmd.pyi @@ -0,0 +1,6 @@ +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.opt.solver.shellcmd import SystemCallSolver as SystemCallSolver + +class ILMLicensedSystemCallSolver(SystemCallSolver): + def __init__(self, **kwds) -> None: ... + def available(self, exception_flag: bool = False): ... diff --git a/stubs/pyomo/opt/solver/shellcmd.pyi b/stubs/pyomo/opt/solver/shellcmd.pyi new file mode 100644 index 000000000..3f57e9f57 --- /dev/null +++ b/stubs/pyomo/opt/solver/shellcmd.pyi @@ -0,0 +1,25 @@ +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.common.log import LoggingIntercept as LoggingIntercept +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.tee import TeeStream as TeeStream +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.opt.base import ResultsFormat as ResultsFormat +from pyomo.opt.base.solvers import OptSolver as OptSolver +from pyomo.opt.results import SolverResults as SolverResults +from pyomo.opt.results import SolverStatus as SolverStatus + +logger: Incomplete +SUBPROCESS_TIMEOUT_ABS_ADJUST: int +SUBPROCESS_TIMEOUT_REL_ADJUST: float + +class SystemCallSolver(OptSolver): + def __init__(self, **kwargs) -> None: ... + def set_executable(self, name=None, validate: bool = True) -> None: ... + def available(self, exception_flag: bool = False): ... + def create_command_line(self, executable, problem_files) -> None: ... + def process_logfile(self): ... + def process_soln_file(self, results): ... + def executable(self): ... + def process_output(self, rc): ... diff --git a/stubs/pyomo/repn/__init__.pyi b/stubs/pyomo/repn/__init__.pyi new file mode 100644 index 000000000..b14113122 --- /dev/null +++ b/stubs/pyomo/repn/__init__.pyi @@ -0,0 +1,3 @@ +from pyomo.repn.standard_aux import compute_standard_repn as compute_standard_repn +from pyomo.repn.standard_repn import StandardRepn as StandardRepn +from pyomo.repn.standard_repn import generate_standard_repn as generate_standard_repn diff --git a/stubs/pyomo/repn/ampl.pyi b/stubs/pyomo/repn/ampl.pyi new file mode 100644 index 000000000..5b717ae93 --- /dev/null +++ b/stubs/pyomo/repn/ampl.pyi @@ -0,0 +1,136 @@ +from _typeshed import Incomplete +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.common.errors import DeveloperError as DeveloperError +from pyomo.common.errors import InfeasibleConstraintException as InfeasibleConstraintException +from pyomo.common.errors import MouseTrap as MouseTrap +from pyomo.common.numeric_types import native_complex_types as native_complex_types +from pyomo.common.numeric_types import native_numeric_types as native_numeric_types +from pyomo.common.numeric_types import native_types as native_types +from pyomo.common.numeric_types import value as value +from pyomo.core.base import Expression as Expression +from pyomo.core.expr import AbsExpression as AbsExpression +from pyomo.core.expr import DivisionExpression as DivisionExpression +from pyomo.core.expr import EqualityExpression as EqualityExpression +from pyomo.core.expr import Expr_ifExpression as Expr_ifExpression +from pyomo.core.expr import ExternalFunctionExpression as ExternalFunctionExpression +from pyomo.core.expr import InequalityExpression as InequalityExpression +from pyomo.core.expr import LinearExpression as LinearExpression +from pyomo.core.expr import MonomialTermExpression as MonomialTermExpression +from pyomo.core.expr import NegationExpression as NegationExpression +from pyomo.core.expr import PowExpression as PowExpression +from pyomo.core.expr import ProductExpression as ProductExpression +from pyomo.core.expr import RangedExpression as RangedExpression +from pyomo.core.expr import SumExpression as SumExpression +from pyomo.core.expr import UnaryFunctionExpression as UnaryFunctionExpression +from pyomo.core.expr.visitor import StreamBasedExpressionVisitor as StreamBasedExpressionVisitor +from pyomo.repn.util import BeforeChildDispatcher as BeforeChildDispatcher +from pyomo.repn.util import ExitNodeDispatcher as ExitNodeDispatcher +from pyomo.repn.util import ExprType as ExprType +from pyomo.repn.util import InvalidNumber as InvalidNumber +from pyomo.repn.util import apply_node_operation as apply_node_operation +from pyomo.repn.util import complex_number_error as complex_number_error +from pyomo.repn.util import nan as nan +from pyomo.repn.util import sum_like_expression_types as sum_like_expression_types + +TOL: float + +class TextNLDebugTemplate: + unary: Incomplete + binary_sum: str + product: str + division: str + pow: str + abs: str + negation: str + nary_sum: str + exprif: str + and_expr: str + less_than: str + less_equal: str + equality: str + external_fcn: str + var: str + const: str + string: str + monomial: Incomplete + multiplier: Incomplete + +nl_operators: Incomplete + +class TextNLTemplate(TextNLDebugTemplate): ... + +class NLFragment: + def __init__(self, repn, node) -> None: ... + @property + def name(self): ... + +class AMPLRepn: + template = TextNLTemplate + nl: Incomplete + mult: int + const: Incomplete + linear: Incomplete + nonlinear: Incomplete + def __init__(self, const, linear, nonlinear) -> None: ... + def __eq__(self, other): ... + def __hash__(self): ... + def duplicate(self): ... + def compile_repn(self, prefix: str = '', args=None, named_exprs=None): ... + def compile_nonlinear_fragment(self) -> None: ... + named_exprs: Incomplete + def append(self, other) -> None: ... + def to_expr(self, var_map): ... + +class DebugAMPLRepn(AMPLRepn): + template = TextNLDebugTemplate + +def handle_negation_node(visitor, node, arg1): ... +def handle_product_node(visitor, node, arg1, arg2): ... +def handle_division_node(visitor, node, arg1, arg2): ... +def handle_pow_node(visitor, node, arg1, arg2): ... +def handle_abs_node(visitor, node, arg1): ... +def handle_unary_node(visitor, node, arg1): ... +def handle_exprif_node(visitor, node, arg1, arg2, arg3): ... +def handle_equality_node(visitor, node, arg1, arg2): ... +def handle_inequality_node(visitor, node, arg1, arg2): ... +def handle_ranged_inequality_node(visitor, node, arg1, arg2, arg3): ... +def handle_named_expression_node(visitor, node, arg1): ... +def handle_external_function_node(visitor, node, *args): ... + +class AMPLBeforeChildDispatcher(BeforeChildDispatcher): + def __init__(self) -> None: ... + +class AMPLRepnVisitor(StreamBasedExpressionVisitor): + subexpression_cache: Incomplete + external_functions: Incomplete + active_expression_source: Incomplete + var_map: Incomplete + used_named_expressions: Incomplete + symbolic_solver_labels: Incomplete + use_named_exprs: Incomplete + encountered_string_arguments: bool + fixed_vars: Incomplete + evaluate: Incomplete + sorter: Incomplete + Result: Incomplete + template: Incomplete + def __init__( + self, + subexpression_cache, + external_functions, + var_map, + used_named_expressions, + symbolic_solver_labels, + use_named_exprs, + sorter, + ) -> None: ... + def check_constant(self, ans, obj): ... + def cache_fixed_var(self, _id, child) -> None: ... + def node_result_to_amplrepn(self, data): ... + def initializeWalker(self, expr): ... + def beforeChild(self, node, child, child_idx): ... + def enterNode(self, node): ... + def exitNode(self, node, data): ... + def finalizeResult(self, result): ... + +def evaluate_ampl_nl_expression(nl, external_functions): ... diff --git a/stubs/pyomo/repn/beta/__init__.pyi b/stubs/pyomo/repn/beta/__init__.pyi new file mode 100644 index 000000000..257feb782 --- /dev/null +++ b/stubs/pyomo/repn/beta/__init__.pyi @@ -0,0 +1 @@ +from pyomo.repn.beta import matrix as matrix diff --git a/stubs/pyomo/repn/beta/matrix.pyi b/stubs/pyomo/repn/beta/matrix.pyi new file mode 100644 index 000000000..0823d0dd9 --- /dev/null +++ b/stubs/pyomo/repn/beta/matrix.pyi @@ -0,0 +1,86 @@ +from collections.abc import Mapping + +from _typeshed import Incomplete +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.modeling import NOTSET as NOTSET +from pyomo.common.numeric_types import value as value +from pyomo.core.base import SortComponents as SortComponents +from pyomo.core.base import Var as Var +from pyomo.core.base.component import ModelComponentFactory as ModelComponentFactory +from pyomo.core.base.constraint import Constraint as Constraint +from pyomo.core.base.constraint import ConstraintData as ConstraintData +from pyomo.core.base.constraint import IndexedConstraint as IndexedConstraint +from pyomo.core.base.constraint import ScalarConstraint as ScalarConstraint +from pyomo.core.base.set_types import Any as Any +from pyomo.core.expr.numvalue import ZeroConstant as ZeroConstant +from pyomo.core.expr.numvalue import is_fixed as is_fixed +from pyomo.core.expr.numvalue import native_numeric_types as native_numeric_types +from pyomo.repn import generate_standard_repn as generate_standard_repn + +logger: Incomplete + +def compile_block_linear_constraints( + parent_block, + constraint_name, + skip_trivial_constraints: bool = False, + single_precision_storage: bool = False, + verbose: bool = False, + descend_into: bool = True, +): ... + +class _LinearConstraintData(ConstraintData): + def __init__(self, index, component=None) -> None: ... + +class _LinearMatrixConstraintData(_LinearConstraintData): + def __init__(self, index, component=None) -> None: ... + def __call__(self, exception=...): ... + def has_lb(self): ... + def has_ub(self): ... + def lslack(self) -> None: ... + def uslack(self) -> None: ... + def index(self): ... + @property + def variables(self): ... + @property + def coefficients(self): ... + linear = coefficients + @property + def constant(self): ... + def to_bounded_expression(self, evaluate_bounds: bool = False): ... + @property + def body(self): ... + @property + def lower(self): ... + @property + def upper(self): ... + @property + def lb(self): ... + @property + def ub(self): ... + @property + def equality(self): ... + @property + def strict_lower(self): ... + @property + def strict_upper(self): ... + def set_value(self, expr) -> None: ... + +class MatrixConstraint(Mapping, IndexedConstraint): + StrictUpperBound: int + UpperBound: int + Equality: int + LowerBound: int + StrictLowerBound: int + NoBound: int + def __init__( + self, nrows, ncols, nnz, prows, jcols, vals, ranges, range_types, varmap + ) -> None: ... + def construct(self, data=None) -> None: ... + def __getitem__(self, key): ... + def __len__(self) -> int: ... + def __iter__(self): ... + def add(self, index, expr) -> None: ... + def __delitem__(self) -> None: ... + def keys(self, sort=None): ... + def values(self, sort=None): ... + def items(self, sort=None): ... diff --git a/stubs/pyomo/repn/linear.pyi b/stubs/pyomo/repn/linear.pyi new file mode 100644 index 000000000..979bf4da5 --- /dev/null +++ b/stubs/pyomo/repn/linear.pyi @@ -0,0 +1,76 @@ +from _typeshed import Incomplete +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.common.numeric_types import native_complex_types as native_complex_types +from pyomo.common.numeric_types import native_numeric_types as native_numeric_types +from pyomo.common.numeric_types import native_types as native_types +from pyomo.core.base.expression import Expression as Expression +from pyomo.core.expr import is_fixed as is_fixed +from pyomo.core.expr import value as value +from pyomo.core.expr.numeric_expr import AbsExpression as AbsExpression +from pyomo.core.expr.numeric_expr import DivisionExpression as DivisionExpression +from pyomo.core.expr.numeric_expr import Expr_ifExpression as Expr_ifExpression +from pyomo.core.expr.numeric_expr import ExternalFunctionExpression as ExternalFunctionExpression +from pyomo.core.expr.numeric_expr import LinearExpression as LinearExpression +from pyomo.core.expr.numeric_expr import MonomialTermExpression as MonomialTermExpression +from pyomo.core.expr.numeric_expr import NegationExpression as NegationExpression +from pyomo.core.expr.numeric_expr import PowExpression as PowExpression +from pyomo.core.expr.numeric_expr import ProductExpression as ProductExpression +from pyomo.core.expr.numeric_expr import SumExpression as SumExpression +from pyomo.core.expr.numeric_expr import UnaryFunctionExpression as UnaryFunctionExpression +from pyomo.core.expr.numeric_expr import mutable_expression as mutable_expression +from pyomo.core.expr.relational_expr import EqualityExpression as EqualityExpression +from pyomo.core.expr.relational_expr import InequalityExpression as InequalityExpression +from pyomo.core.expr.relational_expr import RangedExpression as RangedExpression +from pyomo.core.expr.visitor import StreamBasedExpressionVisitor as StreamBasedExpressionVisitor +from pyomo.repn.util import BeforeChildDispatcher as BeforeChildDispatcher +from pyomo.repn.util import ExitNodeDispatcher as ExitNodeDispatcher +from pyomo.repn.util import ExprType as ExprType +from pyomo.repn.util import FileDeterminism as FileDeterminism +from pyomo.repn.util import FileDeterminism_to_SortComponents as FileDeterminism_to_SortComponents +from pyomo.repn.util import InvalidNumber as InvalidNumber +from pyomo.repn.util import OrderedVarRecorder as OrderedVarRecorder +from pyomo.repn.util import VarRecorder as VarRecorder +from pyomo.repn.util import apply_node_operation as apply_node_operation +from pyomo.repn.util import complex_number_error as complex_number_error +from pyomo.repn.util import initialize_exit_node_dispatcher as initialize_exit_node_dispatcher +from pyomo.repn.util import nan as nan +from pyomo.repn.util import sum_like_expression_types as sum_like_expression_types + +logger: Incomplete + +class LinearRepn: + multiplier: int + constant: int + linear: Incomplete + nonlinear: Incomplete + def __init__(self) -> None: ... + def walker_exitNode(self): ... + def duplicate(self): ... + def to_expression(self, visitor): ... + def append(self, other) -> None: ... + +def to_expression(visitor, arg): ... +def define_exit_node_handlers(_exit_node_handlers=None): ... + +class LinearBeforeChildDispatcher(BeforeChildDispatcher): + def __init__(self) -> None: ... + +class LinearRepnVisitor(StreamBasedExpressionVisitor): + Result = LinearRepn + before_child_dispatcher: Incomplete + exit_node_dispatcher: Incomplete + expand_nonlinear_products: bool + max_exponential_expansion: int + subexpression_cache: Incomplete + var_recorder: Incomplete + var_map: Incomplete + evaluate: Incomplete + def __init__( + self, subexpression_cache, var_map=None, var_order=None, sorter=None, var_recorder=None + ) -> None: ... + def check_constant(self, ans, obj): ... + def initializeWalker(self, expr): ... + def beforeChild(self, node, child, child_idx): ... + def enterNode(self, node): ... + def exitNode(self, node, data): ... + def finalizeResult(self, result): ... diff --git a/stubs/pyomo/repn/linear_template.pyi b/stubs/pyomo/repn/linear_template.pyi new file mode 100644 index 000000000..896be8ba8 --- /dev/null +++ b/stubs/pyomo/repn/linear_template.pyi @@ -0,0 +1,48 @@ +from itertools import chain as chain + +import pyomo.repn.linear as linear +from _typeshed import Incomplete +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.errors import MouseTrap as MouseTrap +from pyomo.common.numeric_types import native_types as native_types +from pyomo.core.expr import ExpressionType as ExpressionType +from pyomo.repn.linear import LinearRepn as LinearRepn + +code_type: Incomplete + +class LinearTemplateRepn(LinearRepn): + linear_sum: Incomplete + def __init__(self) -> None: ... + def walker_exitNode(self): ... + def duplicate(self): ... + def append(self, other) -> None: ... + def compile( + self, + env, + smap, + expr_cache, + args, + remove_fixed_vars: bool = False, + check_duplicates: bool = False, + ): ... + +class LinearTemplateBeforeChildDispatcher(linear.LinearBeforeChildDispatcher): ... + +def define_exit_node_handlers(_exit_node_handlers=None): ... + +class LinearTemplateRepnVisitor(linear.LinearRepnVisitor): + Result = LinearTemplateRepn + before_child_dispatcher: Incomplete + exit_node_dispatcher: Incomplete + indexed_vars: Incomplete + indexed_params: Incomplete + expr_cache: Incomplete + env: Incomplete + symbolmap: Incomplete + expanded_templates: Incomplete + remove_fixed_vars: Incomplete + def __init__( + self, subexpression_cache, var_recorder, remove_fixed_vars: bool = False + ) -> None: ... + def enterNode(self, node): ... + def expand_expression(self, obj, template_info): ... diff --git a/stubs/pyomo/repn/parameterized_linear.pyi b/stubs/pyomo/repn/parameterized_linear.pyi new file mode 100644 index 000000000..18357b977 --- /dev/null +++ b/stubs/pyomo/repn/parameterized_linear.pyi @@ -0,0 +1,49 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.numeric_types import native_numeric_types as native_numeric_types +from pyomo.core import Var as Var +from pyomo.core.expr.numeric_expr import AbsExpression as AbsExpression +from pyomo.core.expr.numeric_expr import DivisionExpression as DivisionExpression +from pyomo.core.expr.numeric_expr import LinearExpression as LinearExpression +from pyomo.core.expr.numeric_expr import MonomialTermExpression as MonomialTermExpression +from pyomo.core.expr.numeric_expr import NegationExpression as NegationExpression +from pyomo.core.expr.numeric_expr import PowExpression as PowExpression +from pyomo.core.expr.numeric_expr import ProductExpression as ProductExpression +from pyomo.core.expr.numeric_expr import SumExpression as SumExpression +from pyomo.core.expr.numeric_expr import UnaryFunctionExpression as UnaryFunctionExpression +from pyomo.core.expr.numeric_expr import mutable_expression as mutable_expression +from pyomo.repn.linear import ExitNodeDispatcher as ExitNodeDispatcher +from pyomo.repn.linear import LinearBeforeChildDispatcher as LinearBeforeChildDispatcher +from pyomo.repn.linear import LinearRepn as LinearRepn +from pyomo.repn.linear import LinearRepnVisitor as LinearRepnVisitor +from pyomo.repn.linear import initialize_exit_node_dispatcher as initialize_exit_node_dispatcher +from pyomo.repn.util import ExprType as ExprType + +def to_expression(visitor, arg): ... + +class ParameterizedLinearRepn(LinearRepn): + def walker_exitNode(self): ... + def to_expression(self, visitor): ... + nonlinear: Incomplete + def append(self, other) -> None: ... + +class ParameterizedLinearBeforeChildDispatcher(LinearBeforeChildDispatcher): + def __init__(self) -> None: ... + +def define_exit_node_handlers(exit_node_handlers=None): ... + +class ParameterizedLinearRepnVisitor(LinearRepnVisitor): + Result = ParameterizedLinearRepn + exit_node_dispatcher: Incomplete + wrt: Incomplete + def __init__( + self, + subexpression_cache, + var_map=None, + var_order=None, + sorter=None, + wrt=None, + var_recorder=None, + ) -> None: ... + def beforeChild(self, node, child, child_idx): ... + def finalizeResult(self, result): ... diff --git a/stubs/pyomo/repn/parameterized_quadratic.pyi b/stubs/pyomo/repn/parameterized_quadratic.pyi new file mode 100644 index 000000000..21e54ca49 --- /dev/null +++ b/stubs/pyomo/repn/parameterized_quadratic.pyi @@ -0,0 +1,34 @@ +from _typeshed import Incomplete +from pyomo.common.numeric_types import native_numeric_types as native_numeric_types +from pyomo.core.expr.numeric_expr import DivisionExpression as DivisionExpression +from pyomo.core.expr.numeric_expr import Expr_ifExpression as Expr_ifExpression +from pyomo.core.expr.numeric_expr import PowExpression as PowExpression +from pyomo.core.expr.numeric_expr import ProductExpression as ProductExpression +from pyomo.core.expr.numeric_expr import mutable_expression as mutable_expression +from pyomo.repn.linear import ExitNodeDispatcher as ExitNodeDispatcher +from pyomo.repn.linear import initialize_exit_node_dispatcher as initialize_exit_node_dispatcher +from pyomo.repn.parameterized_linear import ( + ParameterizedLinearRepnVisitor as ParameterizedLinearRepnVisitor, +) +from pyomo.repn.parameterized_linear import to_expression as to_expression +from pyomo.repn.quadratic import QuadraticRepn as QuadraticRepn +from pyomo.repn.util import ExprType as ExprType + +class ParameterizedQuadraticRepn(QuadraticRepn): + def walker_exitNode(self): ... + def to_expression(self, visitor): ... + quadratic: Incomplete + nonlinear: Incomplete + def append(self, other) -> None: ... + +def is_zero(obj): ... +def is_zero_product(e1, e2): ... +def is_equal_to(obj, val): ... +def define_exit_node_handlers(exit_node_handlers=None): ... + +class ParameterizedQuadraticRepnVisitor(ParameterizedLinearRepnVisitor): + Result = ParameterizedQuadraticRepn + exit_node_dispatcher: Incomplete + max_exponential_expansion: int + expand_nonlinear_products: bool + def finalizeResult(self, result): ... diff --git a/stubs/pyomo/repn/plugins/__init__.pyi b/stubs/pyomo/repn/plugins/__init__.pyi new file mode 100644 index 000000000..e586f1817 --- /dev/null +++ b/stubs/pyomo/repn/plugins/__init__.pyi @@ -0,0 +1,3 @@ +def load() -> None: ... +def activate_writer_version(name, ver) -> None: ... +def active_writer_version(name): ... diff --git a/stubs/pyomo/repn/plugins/ampl/__init__.pyi b/stubs/pyomo/repn/plugins/ampl/__init__.pyi new file mode 100644 index 000000000..1afdf3b6f --- /dev/null +++ b/stubs/pyomo/repn/plugins/ampl/__init__.pyi @@ -0,0 +1 @@ +from pyomo.repn.plugins.ampl.ampl_ import ProblemWriter_nl as ProblemWriter_nl diff --git a/stubs/pyomo/repn/plugins/ampl/ampl_.pyi b/stubs/pyomo/repn/plugins/ampl/ampl_.pyi new file mode 100644 index 000000000..133c2037f --- /dev/null +++ b/stubs/pyomo/repn/plugins/ampl/ampl_.pyi @@ -0,0 +1,69 @@ +from _typeshed import Incomplete +from pyomo.common.fileutils import find_library as find_library +from pyomo.common.gc_manager import PauseGC as PauseGC +from pyomo.core.base import ComponentMap as ComponentMap +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import ExternalFunction as ExternalFunction +from pyomo.core.base import NamedExpressionData as NamedExpressionData +from pyomo.core.base import NameLabeler as NameLabeler +from pyomo.core.base import Objective as Objective +from pyomo.core.base import SortComponents as SortComponents +from pyomo.core.base import SOSConstraint as SOSConstraint +from pyomo.core.base import Suffix as Suffix +from pyomo.core.base import SymbolMap as SymbolMap +from pyomo.core.base import Var as Var +from pyomo.core.base import param as param +from pyomo.core.base import var as var +from pyomo.core.expr.numvalue import NumericConstant as NumericConstant +from pyomo.core.expr.numvalue import is_fixed as is_fixed +from pyomo.core.expr.numvalue import native_numeric_types as native_numeric_types +from pyomo.core.expr.numvalue import value as value +from pyomo.core.kernel.block import IBlock as IBlock +from pyomo.core.kernel.expression import IIdentityExpression as IIdentityExpression +from pyomo.core.kernel.variable import IVariable as IVariable +from pyomo.opt import AbstractProblemWriter as AbstractProblemWriter +from pyomo.opt import ProblemFormat as ProblemFormat +from pyomo.opt import WriterFactory as WriterFactory +from pyomo.repn.standard_repn import generate_standard_repn as generate_standard_repn + +logger: Incomplete + +def set_pyomo_amplfunc_env(external_libs) -> None: ... + +class StopWatch: + start: Incomplete + def __init__(self) -> None: ... + def report(self, msg) -> None: ... + def reset(self) -> None: ... + +class _Counter: + def __init__(self, start) -> None: ... + def __call__(self, obj): ... + +class ModelSOS: + class AmplSuffix: + name: Incomplete + ids: Incomplete + vals: Incomplete + def __init__(self, name) -> None: ... + def add(self, idx, val) -> None: ... + def genfilelines(self): ... + def is_empty(self): ... + + ampl_var_id: Incomplete + sosno: Incomplete + ref: Incomplete + block_cntr: int + varID_map: Incomplete + def __init__(self, ampl_var_id, varID_map) -> None: ... + def count_constraint(self, soscondata) -> None: ... + +class RepnWrapper: + repn: Incomplete + linear_vars: Incomplete + nonlinear_vars: Incomplete + def __init__(self, repn, linear, nonlinear) -> None: ... + +class ProblemWriter_nl(AbstractProblemWriter): + def __init__(self) -> None: ... + def __call__(self, model, filename, solver_capability, io_options): ... diff --git a/stubs/pyomo/repn/plugins/baron_writer.pyi b/stubs/pyomo/repn/plugins/baron_writer.pyi new file mode 100644 index 000000000..988952a4d --- /dev/null +++ b/stubs/pyomo/repn/plugins/baron_writer.pyi @@ -0,0 +1,35 @@ +from _typeshed import Incomplete +from pyomo.common.collections import OrderedSet as OrderedSet +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import NumericLabeler as NumericLabeler +from pyomo.core.base import Objective as Objective +from pyomo.core.base import Param as Param +from pyomo.core.base import ShortNameLabeler as ShortNameLabeler +from pyomo.core.base import SortComponents as SortComponents +from pyomo.core.base import SymbolMap as SymbolMap +from pyomo.core.base.component import ActiveComponent as ActiveComponent +from pyomo.core.expr.numvalue import native_numeric_types as native_numeric_types +from pyomo.core.expr.numvalue import native_types as native_types +from pyomo.core.expr.numvalue import nonpyomo_leaf_types as nonpyomo_leaf_types +from pyomo.core.expr.numvalue import value as value +from pyomo.core.expr.visitor import _ToStringVisitor +from pyomo.core.kernel.block import IBlock as IBlock +from pyomo.opt import ProblemFormat as ProblemFormat +from pyomo.opt.base import AbstractProblemWriter as AbstractProblemWriter +from pyomo.opt.base import WriterFactory as WriterFactory +from pyomo.repn.util import ftoa as ftoa +from pyomo.repn.util import valid_active_ctypes_minlp as valid_active_ctypes_minlp +from pyomo.repn.util import valid_expr_ctypes_minlp as valid_expr_ctypes_minlp + +logger: Incomplete + +class ToBaronVisitor(_ToStringVisitor): + variables: Incomplete + def __init__(self, variables, smap) -> None: ... + def visiting_potential_leaf(self, node): ... + +def expression_to_string(expr, variables, smap): ... + +class ProblemWriter_bar(AbstractProblemWriter): + def __init__(self) -> None: ... + def __call__(self, model, output_filename, solver_capability, io_options): ... diff --git a/stubs/pyomo/repn/plugins/cpxlp.pyi b/stubs/pyomo/repn/plugins/cpxlp.pyi new file mode 100644 index 000000000..5fbe6e894 --- /dev/null +++ b/stubs/pyomo/repn/plugins/cpxlp.pyi @@ -0,0 +1,33 @@ +from _typeshed import Incomplete +from pyomo.common.gc_manager import PauseGC as PauseGC +from pyomo.core.base import ComponentMap as ComponentMap +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import NumericLabeler as NumericLabeler +from pyomo.core.base import Objective as Objective +from pyomo.core.base import SortComponents as SortComponents +from pyomo.core.base import SOSConstraint as SOSConstraint +from pyomo.core.base import SymbolMap as SymbolMap +from pyomo.core.base import TextLabeler as TextLabeler +from pyomo.core.base import Var as Var +from pyomo.core.base import is_fixed as is_fixed +from pyomo.core.base import value as value +from pyomo.opt import ProblemFormat as ProblemFormat +from pyomo.opt.base import AbstractProblemWriter as AbstractProblemWriter +from pyomo.opt.base import WriterFactory as WriterFactory +from pyomo.repn import generate_standard_repn as generate_standard_repn + +logger: Incomplete + +class ProblemWriter_cpxlp(AbstractProblemWriter): + linear_coef_string_template: Incomplete + quad_coef_string_template: Incomplete + obj_string_template: Incomplete + sos_template_string: Incomplete + eq_string_template: Incomplete + geq_string_template: Incomplete + leq_string_template: Incomplete + lb_string_template: Incomplete + ub_string_template: Incomplete + def __init__(self) -> None: ... + def __call__(self, model, output_filename, solver_capability, io_options): ... + def printSOS(self, symbol_map, labeler, variable_symbol_map, soscondata, output) -> None: ... diff --git a/stubs/pyomo/repn/plugins/gams_writer.pyi b/stubs/pyomo/repn/plugins/gams_writer.pyi new file mode 100644 index 000000000..cbf7033fa --- /dev/null +++ b/stubs/pyomo/repn/plugins/gams_writer.pyi @@ -0,0 +1,67 @@ +from _typeshed import Incomplete +from pyomo.common.gc_manager import PauseGC as PauseGC +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import NumericLabeler as NumericLabeler +from pyomo.core.base import Objective as Objective +from pyomo.core.base import ShortNameLabeler as ShortNameLabeler +from pyomo.core.base import SortComponents as SortComponents +from pyomo.core.base import SymbolMap as SymbolMap +from pyomo.core.base import Var as Var +from pyomo.core.base import minimize as minimize +from pyomo.core.base.component import ActiveComponent as ActiveComponent +from pyomo.core.expr.numvalue import as_numeric as as_numeric +from pyomo.core.expr.numvalue import native_numeric_types as native_numeric_types +from pyomo.core.expr.numvalue import native_types as native_types +from pyomo.core.expr.numvalue import nonpyomo_leaf_types as nonpyomo_leaf_types +from pyomo.core.expr.numvalue import value as value +from pyomo.core.expr.visitor import _ToStringVisitor +from pyomo.core.kernel.base import ICategorizedObject as ICategorizedObject +from pyomo.opt import ProblemFormat as ProblemFormat +from pyomo.opt.base import AbstractProblemWriter as AbstractProblemWriter +from pyomo.opt.base import WriterFactory as WriterFactory +from pyomo.repn.util import ftoa as ftoa +from pyomo.repn.util import valid_active_ctypes_minlp as valid_active_ctypes_minlp +from pyomo.repn.util import valid_expr_ctypes_minlp as valid_expr_ctypes_minlp + +logger: Incomplete + +class ToGamsVisitor(_ToStringVisitor): + treechecker: Incomplete + is_discontinuous: bool + output_fixed_variables: Incomplete + def __init__(self, smap, treechecker, output_fixed_variables: bool = False) -> None: ... + def visiting_potential_leaf(self, node): ... + +def expression_to_string(expr, treechecker, smap=None, output_fixed_variables: bool = False): ... + +class Categorizer: + binary: Incomplete + ints: Incomplete + positive: Incomplete + reals: Incomplete + fixed: Incomplete + def __init__(self, var_list, symbol_map) -> None: ... + def __iter__(self): ... + +class StorageTreeChecker: + tree: Incomplete + model: Incomplete + def __init__(self, model) -> None: ... + def __call__(self, comp, exception_flag: bool = True): ... + def parent_block(self, comp): ... + def raise_error(self, comp) -> None: ... + +def split_long_line(line): ... + +class GAMSSymbolMap(SymbolMap): + var_labeler: Incomplete + var_list: Incomplete + def __init__(self, var_labeler, var_list) -> None: ... + def var_label(self, obj): ... + def var_recorder(self, obj): ... + +class ProblemWriter_gams(AbstractProblemWriter): + def __init__(self) -> None: ... + def __call__(self, model, output_filename, solver_capability, io_options): ... + +valid_solvers: Incomplete diff --git a/stubs/pyomo/repn/plugins/lp_writer.pyi b/stubs/pyomo/repn/plugins/lp_writer.pyi new file mode 100644 index 000000000..0497aebda --- /dev/null +++ b/stubs/pyomo/repn/plugins/lp_writer.pyi @@ -0,0 +1,64 @@ +from _typeshed import Incomplete +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import InEnum as InEnum +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.common.gc_manager import PauseGC as PauseGC +from pyomo.common.timing import TicTocTimer as TicTocTimer +from pyomo.core.base import Block as Block +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import Expression as Expression +from pyomo.core.base import ExternalFunction as ExternalFunction +from pyomo.core.base import Objective as Objective +from pyomo.core.base import Param as Param +from pyomo.core.base import RangeSet as RangeSet +from pyomo.core.base import Set as Set +from pyomo.core.base import SortComponents as SortComponents +from pyomo.core.base import SOSConstraint as SOSConstraint +from pyomo.core.base import Suffix as Suffix +from pyomo.core.base import SymbolMap as SymbolMap +from pyomo.core.base import Var as Var +from pyomo.core.base import minimize as minimize +from pyomo.core.base.component import ActiveComponent as ActiveComponent +from pyomo.core.base.label import LPFileLabeler as LPFileLabeler +from pyomo.core.base.label import NumericLabeler as NumericLabeler +from pyomo.network import Port as Port +from pyomo.opt import WriterFactory as WriterFactory +from pyomo.repn.linear import LinearRepnVisitor as LinearRepnVisitor +from pyomo.repn.quadratic import QuadraticRepnVisitor as QuadraticRepnVisitor +from pyomo.repn.util import FileDeterminism as FileDeterminism +from pyomo.repn.util import FileDeterminism_to_SortComponents as FileDeterminism_to_SortComponents +from pyomo.repn.util import OrderedVarRecorder as OrderedVarRecorder +from pyomo.repn.util import categorize_valid_components as categorize_valid_components +from pyomo.repn.util import ( + initialize_var_map_from_column_order as initialize_var_map_from_column_order, +) +from pyomo.repn.util import int_float as int_float +from pyomo.repn.util import ordered_active_constraints as ordered_active_constraints + +logger: Incomplete +inf: Incomplete +neg_inf: Incomplete + +class LPWriterInfo: + symbol_map: Incomplete + def __init__(self, symbol_map) -> None: ... + +class LPWriter: + CONFIG: Incomplete + config: Incomplete + def __init__(self) -> None: ... + def __call__(self, model, filename, solver_capability, io_options): ... + def write(self, model, ostream, **options): ... + +class _LPWriter_impl: + ostream: Incomplete + config: Incomplete + symbol_map: Incomplete + def __init__(self, ostream, config) -> None: ... + sorter: Incomplete + var_map: Incomplete + var_order: Incomplete + var_recorder: Incomplete + def write(self, model): ... + def write_expression(self, ostream, expr, is_objective): ... diff --git a/stubs/pyomo/repn/plugins/mps.pyi b/stubs/pyomo/repn/plugins/mps.pyi new file mode 100644 index 000000000..31db44451 --- /dev/null +++ b/stubs/pyomo/repn/plugins/mps.pyi @@ -0,0 +1,23 @@ +from _typeshed import Incomplete +from pyomo.common.gc_manager import PauseGC as PauseGC +from pyomo.core.base import ComponentMap as ComponentMap +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import NumericLabeler as NumericLabeler +from pyomo.core.base import Objective as Objective +from pyomo.core.base import SortComponents as SortComponents +from pyomo.core.base import SOSConstraint as SOSConstraint +from pyomo.core.base import SymbolMap as SymbolMap +from pyomo.core.base import TextLabeler as TextLabeler +from pyomo.core.base import Var as Var +from pyomo.core.base import is_fixed as is_fixed +from pyomo.core.base import value as value +from pyomo.opt import ProblemFormat as ProblemFormat +from pyomo.opt.base import AbstractProblemWriter as AbstractProblemWriter +from pyomo.opt.base import WriterFactory as WriterFactory +from pyomo.repn import generate_standard_repn as generate_standard_repn + +logger: Incomplete + +class ProblemWriter_mps(AbstractProblemWriter): + def __init__(self, int_marker: bool = False) -> None: ... + def __call__(self, model, output_filename, solver_capability, io_options): ... diff --git a/stubs/pyomo/repn/plugins/nl_writer.pyi b/stubs/pyomo/repn/plugins/nl_writer.pyi new file mode 100644 index 000000000..3ccecba3b --- /dev/null +++ b/stubs/pyomo/repn/plugins/nl_writer.pyi @@ -0,0 +1,134 @@ +import types +from typing import NamedTuple + +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.config import ConfigDict as ConfigDict +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import InEnum as InEnum +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.common.deprecation import relocated_module_attribute as relocated_module_attribute +from pyomo.common.errors import DeveloperError as DeveloperError +from pyomo.common.errors import InfeasibleConstraintException as InfeasibleConstraintException +from pyomo.common.gc_manager import PauseGC as PauseGC +from pyomo.common.timing import TicTocTimer as TicTocTimer +from pyomo.core.base import Block as Block +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import Expression as Expression +from pyomo.core.base import ExternalFunction as ExternalFunction +from pyomo.core.base import NameLabeler as NameLabeler +from pyomo.core.base import Objective as Objective +from pyomo.core.base import Param as Param +from pyomo.core.base import RangeSet as RangeSet +from pyomo.core.base import Set as Set +from pyomo.core.base import SortComponents as SortComponents +from pyomo.core.base import SOSConstraint as SOSConstraint +from pyomo.core.base import Suffix as Suffix +from pyomo.core.base import SymbolMap as SymbolMap +from pyomo.core.base import Var as Var +from pyomo.core.base import minimize as minimize +from pyomo.core.base.component import ActiveComponent as ActiveComponent +from pyomo.core.base.constraint import ConstraintData as ConstraintData +from pyomo.core.base.expression import ExpressionData as ExpressionData +from pyomo.core.base.expression import ScalarExpression as ScalarExpression +from pyomo.core.base.objective import ObjectiveData as ObjectiveData +from pyomo.core.base.objective import ScalarObjective as ScalarObjective +from pyomo.core.base.suffix import SuffixFinder as SuffixFinder +from pyomo.core.base.var import VarData as VarData +from pyomo.core.pyomoobject import PyomoObject as PyomoObject +from pyomo.network import Port as Port +from pyomo.opt import WriterFactory as WriterFactory +from pyomo.repn.ampl import TOL as TOL +from pyomo.repn.ampl import AMPLRepnVisitor as AMPLRepnVisitor +from pyomo.repn.ampl import evaluate_ampl_nl_expression as evaluate_ampl_nl_expression +from pyomo.repn.plugins.ampl.ampl_ import set_pyomo_amplfunc_env as set_pyomo_amplfunc_env +from pyomo.repn.util import FileDeterminism as FileDeterminism +from pyomo.repn.util import FileDeterminism_to_SortComponents as FileDeterminism_to_SortComponents +from pyomo.repn.util import categorize_valid_components as categorize_valid_components +from pyomo.repn.util import ( + initialize_var_map_from_column_order as initialize_var_map_from_column_order, +) +from pyomo.repn.util import int_float as int_float +from pyomo.repn.util import ordered_active_constraints as ordered_active_constraints + +logger: Incomplete +inf: Incomplete +minus_inf: Incomplete +allowable_binary_var_bounds: Incomplete + +class ScalingFactors(NamedTuple): + variables: Incomplete + constraints: Incomplete + objectives: Incomplete + +class NLWriterInfo: + variables: Incomplete + constraints: Incomplete + objectives: Incomplete + external_function_libraries: Incomplete + row_labels: Incomplete + column_labels: Incomplete + eliminated_vars: Incomplete + scaling: Incomplete + def __init__( + self, var, con, obj, external_libs, row_labels, col_labels, eliminated_vars, scaling + ) -> None: ... + +class NLWriter: + CONFIG: Incomplete + config: Incomplete + def __init__(self) -> None: ... + def __call__(self, model, filename, solver_capability, io_options): ... + def write(self, model, ostream, rowstream=None, colstream=None, **options) -> NLWriterInfo: ... + +class _SuffixData: + name: Incomplete + obj: Incomplete + con: Incomplete + var: Incomplete + prob: Incomplete + datatype: Incomplete + values: Incomplete + def __init__(self, name) -> None: ... + def update(self, suffix) -> None: ... + def store(self, obj, val) -> None: ... + def compile(self, column_order, row_order, obj_order, model_id) -> None: ... + +class CachingNumericSuffixFinder(SuffixFinder): + scale: bool + suffix_cache: Incomplete + def __init__(self, name, default=None, context=None) -> None: ... + def __call__(self, obj): ... + +class _NoScalingFactor: + scale: bool + def __call__(self, obj): ... + +class _NLWriter_impl: + ostream: Incomplete + rowstream: Incomplete + colstream: Incomplete + config: Incomplete + symbolic_solver_labels: Incomplete + subexpression_cache: Incomplete + subexpression_order: Incomplete + external_functions: Incomplete + used_named_expressions: Incomplete + var_map: Incomplete + var_id_to_nl_map: Incomplete + sorter: Incomplete + visitor: Incomplete + next_V_line_id: int + pause_gc: Incomplete + template: Incomplete + def __init__(self, ostream, rowstream, colstream, config) -> None: ... + def __enter__(self): ... + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: types.TracebackType | None, + ) -> None: ... + column_order: Incomplete + def write(self, model): ... diff --git a/stubs/pyomo/repn/plugins/parameterized_standard_form.pyi b/stubs/pyomo/repn/plugins/parameterized_standard_form.pyi new file mode 100644 index 000000000..67b12c9cd --- /dev/null +++ b/stubs/pyomo/repn/plugins/parameterized_standard_form.pyi @@ -0,0 +1,43 @@ +from _typeshed import Incomplete +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.common.gc_manager import PauseGC as PauseGC +from pyomo.common.numeric_types import native_numeric_types as native_numeric_types +from pyomo.core import Var as Var +from pyomo.opt import WriterFactory as WriterFactory +from pyomo.repn.parameterized_linear import ( + ParameterizedLinearRepnVisitor as ParameterizedLinearRepnVisitor, +) +from pyomo.repn.plugins.standard_form import ( + LinearStandardFormCompiler as LinearStandardFormCompiler, +) +from pyomo.repn.plugins.standard_form import LinearStandardFormInfo as LinearStandardFormInfo +from pyomo.repn.plugins.standard_form import _LinearStandardFormCompiler_impl +from pyomo.util.config_domains import ComponentDataSet as ComponentDataSet + +class ParameterizedLinearStandardFormCompiler(LinearStandardFormCompiler): + CONFIG: Incomplete + def write(self, model, ostream=None, **options): ... + +class _SparseMatrixBase: + data: Incomplete + indices: Incomplete + indptr: Incomplete + shape: Incomplete + def __init__(self, matrix_data, shape) -> None: ... + def __eq__(self, other): ... + +class _CSRMatrix(_SparseMatrixBase): + def __init__(self, matrix_data, shape) -> None: ... + def tocsc(self): ... + def todense(self): ... + +class _CSCMatrix(_SparseMatrixBase): + def __init__(self, matrix_data, shape) -> None: ... + def todense(self): ... + data: Incomplete + row_index: Incomplete + def sum_duplicates(self) -> None: ... + def eliminate_zeros(self) -> None: ... + +class _ParameterizedLinearStandardFormCompiler_impl(_LinearStandardFormCompiler_impl): ... diff --git a/stubs/pyomo/repn/plugins/standard_form.pyi b/stubs/pyomo/repn/plugins/standard_form.pyi new file mode 100644 index 000000000..1aedbfc77 --- /dev/null +++ b/stubs/pyomo/repn/plugins/standard_form.pyi @@ -0,0 +1,70 @@ +from typing import NamedTuple + +from _typeshed import Incomplete +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.config import ConfigValue as ConfigValue +from pyomo.common.config import InEnum as InEnum +from pyomo.common.config import document_kwargs_from_configdict as document_kwargs_from_configdict +from pyomo.common.dependencies import scipy as scipy +from pyomo.common.enums import ObjectiveSense as ObjectiveSense +from pyomo.common.gc_manager import PauseGC as PauseGC +from pyomo.common.numeric_types import native_types as native_types +from pyomo.common.numeric_types import value as value +from pyomo.common.timing import TicTocTimer as TicTocTimer +from pyomo.core.base import Block as Block +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import Expression as Expression +from pyomo.core.base import ExternalFunction as ExternalFunction +from pyomo.core.base import Objective as Objective +from pyomo.core.base import Param as Param +from pyomo.core.base import RangeSet as RangeSet +from pyomo.core.base import Set as Set +from pyomo.core.base import SortComponents as SortComponents +from pyomo.core.base import Suffix as Suffix +from pyomo.core.base import SymbolMap as SymbolMap +from pyomo.core.base import Var as Var +from pyomo.network import Port as Port +from pyomo.opt import WriterFactory as WriterFactory +from pyomo.repn.linear import LinearRepnVisitor as LinearRepnVisitor +from pyomo.repn.linear_template import LinearTemplateRepnVisitor as LinearTemplateRepnVisitor +from pyomo.repn.util import FileDeterminism as FileDeterminism +from pyomo.repn.util import FileDeterminism_to_SortComponents as FileDeterminism_to_SortComponents +from pyomo.repn.util import TemplateVarRecorder as TemplateVarRecorder +from pyomo.repn.util import categorize_valid_components as categorize_valid_components +from pyomo.repn.util import ( + initialize_var_map_from_column_order as initialize_var_map_from_column_order, +) +from pyomo.repn.util import ordered_active_constraints as ordered_active_constraints + +logger: Incomplete + +class RowEntry(NamedTuple): + constraint: Incomplete + bound_type: Incomplete + +class LinearStandardFormInfo: + c: Incomplete + c_offset: Incomplete + A: Incomplete + rhs: Incomplete + rows: Incomplete + columns: Incomplete + objectives: Incomplete + eliminated_vars: Incomplete + def __init__(self, c, c_offset, A, rhs, rows, columns, objectives, eliminated_vars) -> None: ... + @property + def x(self): ... + @property + def b(self): ... + +class LinearStandardFormCompiler: + CONFIG: Incomplete + config: Incomplete + def __init__(self) -> None: ... + def write(self, model, ostream=None, **options): ... + +class _LinearStandardFormCompiler_impl: + config: Incomplete + def __init__(self, config) -> None: ... + var_map: Incomplete + def write(self, model): ... diff --git a/stubs/pyomo/repn/quadratic.pyi b/stubs/pyomo/repn/quadratic.pyi new file mode 100644 index 000000000..d5e1d9363 --- /dev/null +++ b/stubs/pyomo/repn/quadratic.pyi @@ -0,0 +1,38 @@ +from _typeshed import Incomplete +from pyomo.core.base.expression import Expression as Expression +from pyomo.core.expr.numeric_expr import AbsExpression as AbsExpression +from pyomo.core.expr.numeric_expr import DivisionExpression as DivisionExpression +from pyomo.core.expr.numeric_expr import Expr_ifExpression as Expr_ifExpression +from pyomo.core.expr.numeric_expr import LinearExpression as LinearExpression +from pyomo.core.expr.numeric_expr import MonomialTermExpression as MonomialTermExpression +from pyomo.core.expr.numeric_expr import NegationExpression as NegationExpression +from pyomo.core.expr.numeric_expr import PowExpression as PowExpression +from pyomo.core.expr.numeric_expr import ProductExpression as ProductExpression +from pyomo.core.expr.numeric_expr import UnaryFunctionExpression as UnaryFunctionExpression +from pyomo.core.expr.numeric_expr import mutable_expression as mutable_expression +from pyomo.core.expr.relational_expr import EqualityExpression as EqualityExpression +from pyomo.core.expr.relational_expr import InequalityExpression as InequalityExpression +from pyomo.core.expr.relational_expr import RangedExpression as RangedExpression + +from . import linear as linear +from . import util as util +from .linear import to_expression as to_expression + +class QuadraticRepn: + multiplier: int + constant: int + linear: Incomplete + quadratic: Incomplete + nonlinear: Incomplete + def __init__(self) -> None: ... + def walker_exitNode(self): ... + def duplicate(self): ... + def to_expression(self, visitor): ... + def append(self, other) -> None: ... + +def define_exit_node_handlers(_exit_node_handlers=None): ... + +class QuadraticRepnVisitor(linear.LinearRepnVisitor): + Result = QuadraticRepn + exit_node_dispatcher: Incomplete + max_exponential_expansion: int diff --git a/stubs/pyomo/repn/standard_aux.pyi b/stubs/pyomo/repn/standard_aux.pyi new file mode 100644 index 000000000..65afea0d1 --- /dev/null +++ b/stubs/pyomo/repn/standard_aux.pyi @@ -0,0 +1,4 @@ +from pyomo.repn.standard_repn import preprocess_block_constraints as preprocess_block_constraints +from pyomo.repn.standard_repn import preprocess_block_objectives as preprocess_block_objectives + +def compute_standard_repn(data, model=None) -> None: ... diff --git a/stubs/pyomo/repn/standard_repn.pyi b/stubs/pyomo/repn/standard_repn.pyi new file mode 100644 index 000000000..0959fb4cb --- /dev/null +++ b/stubs/pyomo/repn/standard_repn.pyi @@ -0,0 +1,76 @@ +from _typeshed import Incomplete +from pyomo.common.numeric_types import native_numeric_types as native_numeric_types +from pyomo.common.numeric_types import native_types as native_types +from pyomo.core.base import ComponentMap as ComponentMap +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import Expression as Expression +from pyomo.core.base import Objective as Objective +from pyomo.core.base.expression import ExpressionData as ExpressionData +from pyomo.core.base.expression import NamedExpressionData as NamedExpressionData +from pyomo.core.base.expression import ScalarExpression as ScalarExpression +from pyomo.core.base.objective import ObjectiveData as ObjectiveData +from pyomo.core.base.objective import ScalarObjective as ScalarObjective +from pyomo.core.base.param import ParamData as ParamData +from pyomo.core.base.param import ScalarParam as ScalarParam +from pyomo.core.base.var import ScalarVar as ScalarVar +from pyomo.core.base.var import Var as Var +from pyomo.core.base.var import VarData as VarData +from pyomo.core.base.var import value as value +from pyomo.core.expr.numvalue import NumericConstant as NumericConstant +from pyomo.core.kernel.expression import expression as expression +from pyomo.core.kernel.expression import noclone as noclone +from pyomo.core.kernel.objective import objective as objective +from pyomo.core.kernel.variable import IVariable as IVariable +from pyomo.core.kernel.variable import variable as variable + +logger: Incomplete + +def isclose_const(a, b, rel_tol: float = 1e-09, abs_tol: float = 0.0): ... + +class StandardRepn: + constant: int + linear_vars: Incomplete + linear_coefs: Incomplete + quadratic_vars: Incomplete + quadratic_coefs: Incomplete + nonlinear_expr: Incomplete + nonlinear_vars: Incomplete + def __init__(self) -> None: ... + def is_fixed(self): ... + def polynomial_degree(self): ... + def is_constant(self): ... + def is_linear(self): ... + def is_quadratic(self): ... + def is_nonlinear(self): ... + def to_expression(self, sort: bool = True): ... + +def generate_standard_repn( + expr, + idMap=None, + compute_values: bool = True, + verbose: bool = False, + quadratic: bool = True, + repn=None, +): ... + +class ResultsWithQuadratics: + __slot__: Incomplete + constant: Incomplete + nonl: Incomplete + linear: Incomplete + quadratic: Incomplete + def __init__(self, constant: int = 0, nonl: int = 0, linear=None, quadratic=None) -> None: ... + +class ResultsWithoutQuadratics: + __slot__: Incomplete + constant: Incomplete + nonl: Incomplete + linear: Incomplete + def __init__(self, constant: int = 0, nonl: int = 0, linear=None) -> None: ... + +Results = ResultsWithQuadratics + +def preprocess_block_objectives(block, idMap=None) -> None: ... +def preprocess_block_constraints(block, idMap=None) -> None: ... +def preprocess_constraint(block, constraint, idMap=None, block_repn=None) -> None: ... +def preprocess_constraint_data(block, constraint_data, idMap=None, block_repn=None) -> None: ... diff --git a/stubs/pyomo/repn/util.pyi b/stubs/pyomo/repn/util.pyi new file mode 100644 index 000000000..3789dbc39 --- /dev/null +++ b/stubs/pyomo/repn/util.pyi @@ -0,0 +1,121 @@ +import collections + +from _typeshed import Incomplete +from pyomo.common import enums as enums +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.collections import Sequence as Sequence +from pyomo.common.deprecation import deprecation_warning as deprecation_warning +from pyomo.common.errors import DeveloperError as DeveloperError +from pyomo.common.errors import InvalidValueError as InvalidValueError +from pyomo.common.numeric_types import check_if_numeric_type as check_if_numeric_type +from pyomo.common.numeric_types import native_complex_types as native_complex_types +from pyomo.common.numeric_types import native_logical_types as native_logical_types +from pyomo.common.numeric_types import native_numeric_types as native_numeric_types +from pyomo.common.numeric_types import native_types as native_types +from pyomo.core.base import Block as Block +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import Expression as Expression +from pyomo.core.base import NumericLabeler as NumericLabeler +from pyomo.core.base import Objective as Objective +from pyomo.core.base import Param as Param +from pyomo.core.base import SortComponents as SortComponents +from pyomo.core.base import Suffix as Suffix +from pyomo.core.base import Var as Var +from pyomo.core.base.component import ActiveComponent as ActiveComponent +from pyomo.core.base.expression import NamedExpressionData as NamedExpressionData +from pyomo.core.expr.numvalue import is_fixed as is_fixed +from pyomo.core.expr.numvalue import value as value +from pyomo.core.pyomoobject import PyomoObject as PyomoObject + +logger: Incomplete +valid_expr_ctypes_minlp: Incomplete +valid_active_ctypes_minlp: Incomplete +sum_like_expression_types: Incomplete +HALT_ON_EVALUATION_ERROR: bool +nan: Incomplete +int_float: Incomplete + +class ExprType(enums.IntEnum): + CONSTANT = 0 + FIXED = 3 + VARIABLE = 5 + MONOMIAL = 10 + LINEAR = 20 + QUADRATIC = 30 + GENERAL = 40 + +class FileDeterminism(enums.IntEnum): + NONE = 0 + ORDERED = 10 + SORT_INDICES = 20 + SORT_SYMBOLS = 30 + def __format__(self, spec) -> str: ... + +class InvalidNumber(PyomoObject): + value: Incomplete + causes: Incomplete + def __init__(self, value, cause: str = '') -> None: ... + @staticmethod + def parse_args(*args): ... + def __eq__(self, other): ... + def __lt__(self, other): ... + def __gt__(self, other): ... + def __le__(self, other): ... + def __ge__(self, other): ... + def __format__(self, format_spec) -> str: ... + def __float__(self) -> float: ... + def __neg__(self): ... + def __abs__(self): ... + def __add__(self, other): ... + def __sub__(self, other): ... + def __mul__(self, other): ... + def __truediv__(self, other): ... + def __pow__(self, other): ... + def __radd__(self, other): ... + def __rsub__(self, other): ... + def __rmul__(self, other): ... + def __rtruediv__(self, other): ... + def __rpow__(self, other): ... + +class BeforeChildDispatcher(collections.defaultdict): + def __missing__(self, key): ... + def register_dispatcher(self, visitor, child): ... + +class ExitNodeDispatcher(collections.defaultdict): + def __init__(self, *args, **kwargs) -> None: ... + def __missing__(self, key): ... + def unexpected_expression_type(self, visitor, node, *args) -> None: ... + +def initialize_exit_node_dispatcher(exit_handlers): ... +def apply_node_operation(node, args): ... +def complex_number_error(value, visitor, expr, node: str = ''): ... +def categorize_valid_components(model, active: bool = True, sort=None, valid=..., targets=...): ... +def FileDeterminism_to_SortComponents(file_determinism): ... +def initialize_var_map_from_column_order(model, config, var_map): ... +def ordered_active_constraints(model, config): ... + +class VarRecorder: + var_map: Incomplete + sorter: Incomplete + def __init__(self, var_map, sorter) -> None: ... + def add(self, var) -> None: ... + +class OrderedVarRecorder: + var_map: Incomplete + var_order: Incomplete + sorter: Incomplete + def __init__(self, var_map, var_order, sorter) -> None: ... + def add(self, var) -> None: ... + +class TemplateVarRecorder: + var_map: Incomplete + sorter: Incomplete + env: Incomplete + symbolmap: Incomplete + def __init__(self, var_map, var_order, sorter) -> None: ... + @property + def var_order(self): ... + def add(self, var) -> None: ... + +def ftoa(val, parenthesize_negative_values: bool = False): ... diff --git a/stubs/pyomo/scripting/__init__.pyi b/stubs/pyomo/scripting/__init__.pyi new file mode 100644 index 000000000..e91cc075c --- /dev/null +++ b/stubs/pyomo/scripting/__init__.pyi @@ -0,0 +1,2 @@ +from pyomo.scripting import pyomo_command as pyomo_command +from pyomo.scripting import util as util diff --git a/stubs/pyomo/scripting/commands.pyi b/stubs/pyomo/scripting/commands.pyi new file mode 100644 index 000000000..023b0dd50 --- /dev/null +++ b/stubs/pyomo/scripting/commands.pyi @@ -0,0 +1,4 @@ +from pyomo.common._command import pyomo_command as pyomo_command +from pyomo.common.deprecation import deprecated as deprecated + +def pyomo_python(args=None) -> None: ... diff --git a/stubs/pyomo/scripting/convert.pyi b/stubs/pyomo/scripting/convert.pyi new file mode 100644 index 000000000..f000c782b --- /dev/null +++ b/stubs/pyomo/scripting/convert.pyi @@ -0,0 +1,14 @@ +from pyomo.common.collections import Bunch as Bunch +from pyomo.core.base import ConcreteModel as ConcreteModel +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import Objective as Objective +from pyomo.core.base import Var as Var +from pyomo.core.base import value as value +from pyomo.opt import ProblemFormat as ProblemFormat + +def convert(options=..., parser=None, model_format=None): ... +def convert_dakota(options=..., parser=None): ... +def pyomo2lp(args=None): ... +def pyomo2nl(args=None): ... +def pyomo2bar(args=None): ... +def pyomo2dakota(args=None): ... diff --git a/stubs/pyomo/scripting/driver_help.pyi b/stubs/pyomo/scripting/driver_help.pyi new file mode 100644 index 000000000..778fcbd35 --- /dev/null +++ b/stubs/pyomo/scripting/driver_help.pyi @@ -0,0 +1,19 @@ +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.tee import capture_output as capture_output + +logger: Incomplete + +def setup_command_parser(parser) -> None: ... +def command_exec(options): ... +def help_commands(): ... +def help_writers() -> None: ... +def help_datamanagers(options) -> None: ... +def help_environment() -> None: ... +def help_transformations() -> None: ... +def help_solvers(): ... +def print_components(data) -> None: ... +def help_exec(options) -> None: ... +def setup_help_parser(parser): ... + +help_parser: Incomplete diff --git a/stubs/pyomo/scripting/interface.pyi b/stubs/pyomo/scripting/interface.pyi new file mode 100644 index 000000000..c65fd1e48 --- /dev/null +++ b/stubs/pyomo/scripting/interface.pyi @@ -0,0 +1,53 @@ +from _typeshed import Incomplete +from pyomo.common.plugin_base import DeprecatedInterface as DeprecatedInterface +from pyomo.common.plugin_base import ExtensionPoint as ExtensionPoint +from pyomo.common.plugin_base import Interface as Interface +from pyomo.common.plugin_base import Plugin as Plugin +from pyomo.common.plugin_base import SingletonPlugin as SingletonPlugin +from pyomo.common.plugin_base import alias as alias +from pyomo.common.plugin_base import implements as implements + +registered_callback: Incomplete + +def pyomo_callback(name): ... + +class IPyomoScriptPreprocess(Interface): + def apply(self, **kwds) -> None: ... + +class IPyomoScriptCreateModel(Interface): + def apply(self, **kwds) -> None: ... + +class IPyomoScriptModifyInstance(Interface): + def apply(self, **kwds) -> None: ... + +class IPyomoScriptCreateDataPortal(Interface): + def apply(self, **kwds) -> None: ... + +class IPyomoScriptPrintModel(Interface): + def apply(self, **kwds) -> None: ... + +class IPyomoScriptPrintInstance(Interface): + def apply(self, **kwds) -> None: ... + +class IPyomoScriptSaveInstance(Interface): + def apply(self, **kwds) -> None: ... + +class IPyomoScriptPrintResults(Interface): + def apply(self, **kwds) -> None: ... + +class IPyomoScriptSaveResults(Interface): + def apply(self, **kwds) -> None: ... + +class IPyomoScriptPostprocess(Interface): + def apply(self, **kwds) -> None: ... + +class IPyomoPresolver(Interface): + def get_actions(self) -> None: ... + def activate_action(self, action) -> None: ... + def deactivate_action(self, action) -> None: ... + def set_actions(self, actions) -> None: ... + def presolve(self, instance) -> None: ... + +class IPyomoPresolveAction(Interface): + def presolve(self, instance) -> None: ... + def rank(self) -> None: ... diff --git a/stubs/pyomo/scripting/plugins/__init__.pyi b/stubs/pyomo/scripting/plugins/__init__.pyi new file mode 100644 index 000000000..08b671c7f --- /dev/null +++ b/stubs/pyomo/scripting/plugins/__init__.pyi @@ -0,0 +1 @@ +def load() -> None: ... diff --git a/stubs/pyomo/scripting/plugins/build_ext.pyi b/stubs/pyomo/scripting/plugins/build_ext.pyi new file mode 100644 index 000000000..afb26bbd5 --- /dev/null +++ b/stubs/pyomo/scripting/plugins/build_ext.pyi @@ -0,0 +1,6 @@ +from pyomo.common.extensions import ExtensionBuilderFactory as ExtensionBuilderFactory +from pyomo.scripting.pyomo_parser import add_subparser as add_subparser + +class ExtensionBuilder: + def create_parser(self, parser): ... + def call(self, args, unparsed): ... diff --git a/stubs/pyomo/scripting/plugins/convert.pyi b/stubs/pyomo/scripting/plugins/convert.pyi new file mode 100644 index 000000000..704222c31 --- /dev/null +++ b/stubs/pyomo/scripting/plugins/convert.pyi @@ -0,0 +1,14 @@ +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch +from pyomo.opt import guess_format as guess_format +from pyomo.scripting.pyomo_parser import CustomHelpFormatter as CustomHelpFormatter +from pyomo.scripting.pyomo_parser import add_subparser as add_subparser +from pyomo.scripting.solve_config import Default_Config as Default_Config + +def create_parser(parser=None): ... +def run_convert(options=..., parser=None): ... +def convert_exec(args, unparsed): ... + +convert_parser: Incomplete + +def create_temporary_parser(output: bool = False, generate: bool = False): ... diff --git a/stubs/pyomo/scripting/plugins/download.pyi b/stubs/pyomo/scripting/plugins/download.pyi new file mode 100644 index 000000000..a569d2760 --- /dev/null +++ b/stubs/pyomo/scripting/plugins/download.pyi @@ -0,0 +1,10 @@ +from _typeshed import Incomplete +from pyomo.common.download import DownloadFactory as DownloadFactory +from pyomo.common.download import FileDownloader as FileDownloader +from pyomo.scripting.pyomo_parser import add_subparser as add_subparser + +class GroupDownloader: + downloader: Incomplete + def __init__(self) -> None: ... + def create_parser(self, parser): ... + def call(self, args, unparsed): ... diff --git a/stubs/pyomo/scripting/plugins/extras.pyi b/stubs/pyomo/scripting/plugins/extras.pyi new file mode 100644 index 000000000..c1fb98a6a --- /dev/null +++ b/stubs/pyomo/scripting/plugins/extras.pyi @@ -0,0 +1,7 @@ +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.scripting.pyomo_parser import CustomHelpFormatter as CustomHelpFormatter +from pyomo.scripting.pyomo_parser import add_subparser as add_subparser + +def get_packages(): ... +def install_extras(args=[], quiet: bool = False) -> None: ... +def pyomo_subcommand(options): ... diff --git a/stubs/pyomo/scripting/plugins/solve.pyi b/stubs/pyomo/scripting/plugins/solve.pyi new file mode 100644 index 000000000..8a81343e6 --- /dev/null +++ b/stubs/pyomo/scripting/plugins/solve.pyi @@ -0,0 +1,11 @@ +from _typeshed import Incomplete +from pyomo.opt import SolverFactory as SolverFactory +from pyomo.opt import UnknownSolver as UnknownSolver +from pyomo.scripting.pyomo_parser import CustomHelpFormatter as CustomHelpFormatter +from pyomo.scripting.pyomo_parser import add_subparser as add_subparser + +def create_parser(parser=None): ... +def create_temporary_parser(solver: bool = False, generate: bool = False): ... +def solve_exec(args, unparsed): ... + +solve_parser: Incomplete diff --git a/stubs/pyomo/scripting/pyomo_command.pyi b/stubs/pyomo/scripting/pyomo_command.pyi new file mode 100644 index 000000000..c4acd442f --- /dev/null +++ b/stubs/pyomo/scripting/pyomo_command.pyi @@ -0,0 +1,5 @@ +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.dependencies import pympler_available as pympler_available +from pyomo.core import ConcreteModel as ConcreteModel + +def run_pyomo(options=..., parser=None): ... diff --git a/stubs/pyomo/scripting/pyomo_main.pyi b/stubs/pyomo/scripting/pyomo_main.pyi new file mode 100644 index 000000000..f62aeb1e9 --- /dev/null +++ b/stubs/pyomo/scripting/pyomo_main.pyi @@ -0,0 +1,12 @@ +from _typeshed import Incomplete +from pyomo.common.deprecation import deprecation_warning as deprecation_warning + +pyomo_commands: Incomplete +plugin_class: Incomplete +exctype: Incomplete +err: Incomplete +tb: Incomplete +msg: Incomplete + +def main(args=None): ... +def main_console_script(): ... diff --git a/stubs/pyomo/scripting/pyomo_parser.pyi b/stubs/pyomo/scripting/pyomo_parser.pyi new file mode 100644 index 000000000..1e3a67217 --- /dev/null +++ b/stubs/pyomo/scripting/pyomo_parser.pyi @@ -0,0 +1,14 @@ +import argparse + +from _typeshed import Incomplete + +class CustomHelpFormatter(argparse.RawDescriptionHelpFormatter): ... + +def get_version(): ... + +doc: str +epilog: str +subparsers: Incomplete + +def add_subparser(name, **args): ... +def get_parser(): ... diff --git a/stubs/pyomo/scripting/solve_config.pyi b/stubs/pyomo/scripting/solve_config.pyi new file mode 100644 index 000000000..6e789191b --- /dev/null +++ b/stubs/pyomo/scripting/solve_config.pyi @@ -0,0 +1,9 @@ +from pyomo.common.config import ConfigBlock as ConfigBlock +from pyomo.common.config import ConfigList as ConfigList +from pyomo.common.config import ConfigValue as ConfigValue + +class Default_Config: + def config_block(self, init: bool = False): ... + +def minlp_config_block(init: bool = False): ... +def default_config_block(solver, init: bool = False): ... diff --git a/stubs/pyomo/scripting/util.pyi b/stubs/pyomo/scripting/util.pyi new file mode 100644 index 000000000..2f35dc7fa --- /dev/null +++ b/stubs/pyomo/scripting/util.pyi @@ -0,0 +1,72 @@ +import types + +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.dependencies import pympler as pympler +from pyomo.common.dependencies import pympler_available as pympler_available +from pyomo.common.dependencies import yaml as yaml +from pyomo.common.dependencies import yaml_available as yaml_available +from pyomo.common.dependencies import yaml_load_args as yaml_load_args +from pyomo.common.deprecation import deprecated as deprecated +from pyomo.common.fileutils import import_file as import_file +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.tee import capture_output as capture_output +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.core import Model as Model +from pyomo.core import Suffix as Suffix +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core import display as display +from pyomo.dataportal import DataPortal as DataPortal +from pyomo.opt import ProblemFormat as ProblemFormat +from pyomo.opt.base import SolverFactory as SolverFactory +from pyomo.opt.parallel import SolverManagerFactory as SolverManagerFactory +from pyomo.scripting.interface import ExtensionPoint as ExtensionPoint +from pyomo.scripting.interface import IPyomoScriptCreateDataPortal as IPyomoScriptCreateDataPortal +from pyomo.scripting.interface import IPyomoScriptCreateModel as IPyomoScriptCreateModel +from pyomo.scripting.interface import IPyomoScriptModifyInstance as IPyomoScriptModifyInstance +from pyomo.scripting.interface import IPyomoScriptPostprocess as IPyomoScriptPostprocess +from pyomo.scripting.interface import IPyomoScriptPreprocess as IPyomoScriptPreprocess +from pyomo.scripting.interface import IPyomoScriptPrintInstance as IPyomoScriptPrintInstance +from pyomo.scripting.interface import IPyomoScriptPrintModel as IPyomoScriptPrintModel +from pyomo.scripting.interface import IPyomoScriptPrintResults as IPyomoScriptPrintResults +from pyomo.scripting.interface import IPyomoScriptSaveInstance as IPyomoScriptSaveInstance +from pyomo.scripting.interface import IPyomoScriptSaveResults as IPyomoScriptSaveResults +from pyomo.scripting.interface import Plugin as Plugin +from pyomo.scripting.interface import implements as implements +from pyomo.scripting.interface import registered_callback as registered_callback + +memory_data: Incomplete +IPython_available: Incomplete +filter_excepthook: bool +modelapi: Incomplete +logger: Incomplete +start_time: float + +def setup_environment(data) -> None: ... +def apply_preprocessing(data, parser=None): ... +def create_model(data): ... +def apply_optimizer(data, instance=None): ... +def process_results(data, instance=None, results=None, opt=None) -> None: ... +def apply_postprocessing(data, instance=None, results=None) -> None: ... +def finalize(data, model=None, instance=None, results=None) -> None: ... +def configure_loggers(options=None, shutdown: bool = False) -> None: ... + +class PyomoCommandLogContext: + options: Incomplete + fileLogger: Incomplete + original: Incomplete + def __init__(self, options) -> None: ... + capture: Incomplete + def __enter__(self): ... + def __exit__( + self, + et: type[BaseException] | None, + ev: BaseException | None, + tb: types.TracebackType | None, + ) -> None: ... + +def run_command( + command=None, parser=None, args=None, name: str = 'unknown', data=None, options=None +): ... +def cleanup() -> None: ... +def get_config_values(filename): ... diff --git a/stubs/pyomo/solvers/__init__.pyi b/stubs/pyomo/solvers/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/solvers/amplfunc_merge.pyi b/stubs/pyomo/solvers/amplfunc_merge.pyi new file mode 100644 index 000000000..a597f0e01 --- /dev/null +++ b/stubs/pyomo/solvers/amplfunc_merge.pyi @@ -0,0 +1,4 @@ +from pyomo.common.deprecation import relocated_module_attribute as relocated_module_attribute + +def unique_paths(*paths): ... +def amplfunc_merge(env, *funcs): ... diff --git a/stubs/pyomo/solvers/mockmip.pyi b/stubs/pyomo/solvers/mockmip.pyi new file mode 100644 index 000000000..719cdac03 --- /dev/null +++ b/stubs/pyomo/solvers/mockmip.pyi @@ -0,0 +1,8 @@ +from _typeshed import Incomplete + +class MockMIP: + mock_subdir: Incomplete + def __init__(self, mockdir) -> None: ... + def create_command_line(self, executable, problem_files) -> None: ... + executable: Incomplete + def version(self): ... diff --git a/stubs/pyomo/solvers/plugins/__init__.pyi b/stubs/pyomo/solvers/plugins/__init__.pyi new file mode 100644 index 000000000..08b671c7f --- /dev/null +++ b/stubs/pyomo/solvers/plugins/__init__.pyi @@ -0,0 +1 @@ +def load() -> None: ... diff --git a/stubs/pyomo/solvers/plugins/converter/__init__.pyi b/stubs/pyomo/solvers/plugins/converter/__init__.pyi new file mode 100644 index 000000000..e0ebeace6 --- /dev/null +++ b/stubs/pyomo/solvers/plugins/converter/__init__.pyi @@ -0,0 +1,3 @@ +from pyomo.solvers.plugins.converter import ampl as ampl +from pyomo.solvers.plugins.converter import glpsol as glpsol +from pyomo.solvers.plugins.converter import model as model diff --git a/stubs/pyomo/solvers/plugins/converter/ampl.pyi b/stubs/pyomo/solvers/plugins/converter/ampl.pyi new file mode 100644 index 000000000..671404a16 --- /dev/null +++ b/stubs/pyomo/solvers/plugins/converter/ampl.pyi @@ -0,0 +1,9 @@ +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.opt.base import ConverterError as ConverterError +from pyomo.opt.base import ProblemFormat as ProblemFormat +from pyomo.opt.base.convert import ProblemConverterFactory as ProblemConverterFactory + +class AmplMIPConverter: + def can_convert(self, from_type, to_type): ... + def apply(self, *args, **kwargs): ... diff --git a/stubs/pyomo/solvers/plugins/converter/glpsol.pyi b/stubs/pyomo/solvers/plugins/converter/glpsol.pyi new file mode 100644 index 000000000..b4551abd6 --- /dev/null +++ b/stubs/pyomo/solvers/plugins/converter/glpsol.pyi @@ -0,0 +1,9 @@ +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.opt.base import ConverterError as ConverterError +from pyomo.opt.base import ProblemFormat as ProblemFormat +from pyomo.opt.base.convert import ProblemConverterFactory as ProblemConverterFactory + +class GlpsolMIPConverter: + def can_convert(self, from_type, to_type): ... + def apply(self, *args, **kwargs): ... diff --git a/stubs/pyomo/solvers/plugins/converter/model.pyi b/stubs/pyomo/solvers/plugins/converter/model.pyi new file mode 100644 index 000000000..adaca063d --- /dev/null +++ b/stubs/pyomo/solvers/plugins/converter/model.pyi @@ -0,0 +1,11 @@ +from _typeshed import Incomplete +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.core.kernel.block import IBlock as IBlock +from pyomo.opt.base import ProblemFormat as ProblemFormat +from pyomo.opt.base.convert import ProblemConverterFactory as ProblemConverterFactory +from pyomo.solvers.plugins.converter.pico import PicoMIPConverter as PicoMIPConverter + +class PyomoMIPConverter: + pico_converter: Incomplete + def can_convert(self, from_type, to_type): ... + def apply(self, *args, **kwds): ... diff --git a/stubs/pyomo/solvers/plugins/converter/pico.pyi b/stubs/pyomo/solvers/plugins/converter/pico.pyi new file mode 100644 index 000000000..0ee576c5f --- /dev/null +++ b/stubs/pyomo/solvers/plugins/converter/pico.pyi @@ -0,0 +1,9 @@ +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.opt.base import ConverterError as ConverterError +from pyomo.opt.base import ProblemFormat as ProblemFormat + +class PicoMIPConverter: + def can_convert(self, from_type, to_type): ... + def available(self): ... + def apply(self, *args, **kwargs): ... diff --git a/stubs/pyomo/solvers/plugins/solvers/ASL.pyi b/stubs/pyomo/solvers/plugins/solvers/ASL.pyi new file mode 100644 index 000000000..0cb13af4b --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/ASL.pyi @@ -0,0 +1,26 @@ +from _typeshed import Incomplete +from pyomo.common import Executable as Executable +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.core import TransformationFactory as TransformationFactory +from pyomo.core.kernel.block import IBlock as IBlock +from pyomo.opt.base import ProblemFormat as ProblemFormat +from pyomo.opt.base import ResultsFormat as ResultsFormat +from pyomo.opt.base.solvers import SolverFactory as SolverFactory +from pyomo.opt.solver import SystemCallSolver as SystemCallSolver +from pyomo.solvers.amplfunc_merge import amplfunc_merge as amplfunc_merge +from pyomo.solvers.mockmip import MockMIP as MockMIP + +logger: Incomplete + +class ASL(SystemCallSolver): + def __init__(self, **kwds) -> None: ... + def available(self, exception_flag: bool = True): ... + def create_command_line(self, executable, problem_files): ... + +class MockASL(ASL, MockMIP): + def __init__(self, **kwds) -> None: ... + def available(self, exception_flag: bool = True): ... + def create_command_line(self, executable, problem_files): ... + def executable(self): ... diff --git a/stubs/pyomo/solvers/plugins/solvers/BARON.pyi b/stubs/pyomo/solvers/plugins/solvers/BARON.pyi new file mode 100644 index 000000000..30fb8a5c0 --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/BARON.pyi @@ -0,0 +1,24 @@ +from _typeshed import Incomplete +from pyomo.common import Executable as Executable +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.opt.base import OptSolver as OptSolver +from pyomo.opt.base import ProblemFormat as ProblemFormat +from pyomo.opt.base import ResultsFormat as ResultsFormat +from pyomo.opt.base.solvers import SolverFactory as SolverFactory +from pyomo.opt.results import Solution as Solution +from pyomo.opt.results import SolutionStatus as SolutionStatus +from pyomo.opt.results import SolverResults as SolverResults +from pyomo.opt.results import SolverStatus as SolverStatus +from pyomo.opt.results import TerminationCondition as TerminationCondition +from pyomo.opt.solver import SystemCallSolver as SystemCallSolver + +logger: Incomplete + +class BARONSHELL(SystemCallSolver): + def __init__(self, **kwds) -> None: ... + def license_is_valid(self): ... + def create_command_line(self, executable, problem_files): ... + def warm_start_capable(self): ... + def process_logfile(self): ... + def process_soln_file(self, results) -> None: ... diff --git a/stubs/pyomo/solvers/plugins/solvers/CBCplugin.pyi b/stubs/pyomo/solvers/plugins/solvers/CBCplugin.pyi new file mode 100644 index 000000000..49d55b974 --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/CBCplugin.pyi @@ -0,0 +1,39 @@ +from _typeshed import Incomplete +from pyomo.common import Executable as Executable +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.enums import maximize as maximize +from pyomo.common.enums import minimize as minimize +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.core import Var as Var +from pyomo.core.kernel.block import IBlock as IBlock +from pyomo.opt.base import OptSolver as OptSolver +from pyomo.opt.base import ProblemFormat as ProblemFormat +from pyomo.opt.base import ResultsFormat as ResultsFormat +from pyomo.opt.base.solvers import SolverFactory as SolverFactory +from pyomo.opt.results import Solution as Solution +from pyomo.opt.results import SolutionStatus as SolutionStatus +from pyomo.opt.results import SolverResults as SolverResults +from pyomo.opt.results import SolverStatus as SolverStatus +from pyomo.opt.results import TerminationCondition as TerminationCondition +from pyomo.opt.solver import SystemCallSolver as SystemCallSolver +from pyomo.solvers.mockmip import MockMIP as MockMIP + +logger: Incomplete + +class CBC(OptSolver): + def __new__(cls, *args, **kwds): ... + +class CBCSHELL(SystemCallSolver): + def __init__(self, **kwds) -> None: ... + def set_problem_format(self, format) -> None: ... + def warm_start_capable(self): ... + def create_command_line(self, executable, problem_files): ... + def process_logfile(self): ... + def process_soln_file(self, results) -> None: ... + +class MockCBC(CBCSHELL, MockMIP): + def __init__(self, **kwds) -> None: ... + def available(self, exception_flag: bool = True): ... + def create_command_line(self, executable, problem_files): ... + def executable(self): ... diff --git a/stubs/pyomo/solvers/plugins/solvers/CONOPT.pyi b/stubs/pyomo/solvers/plugins/solvers/CONOPT.pyi new file mode 100644 index 000000000..7521d22ee --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/CONOPT.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from pyomo.common import Executable as Executable +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.opt.base import ProblemFormat as ProblemFormat +from pyomo.opt.base import ResultsFormat as ResultsFormat +from pyomo.opt.base.solvers import SolverFactory as SolverFactory +from pyomo.opt.results import SolverStatus as SolverStatus +from pyomo.opt.solver import SystemCallSolver as SystemCallSolver + +logger: Incomplete + +class CONOPT(SystemCallSolver): + def __init__(self, **kwds) -> None: ... + def create_command_line(self, executable, problem_files): ... diff --git a/stubs/pyomo/solvers/plugins/solvers/CPLEX.pyi b/stubs/pyomo/solvers/plugins/solvers/CPLEX.pyi new file mode 100644 index 000000000..394619c77 --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/CPLEX.pyi @@ -0,0 +1,51 @@ +from _typeshed import Incomplete +from pyomo.common import Executable as Executable +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.enums import maximize as maximize +from pyomo.common.enums import minimize as minimize +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.core.base import Suffix as Suffix +from pyomo.core.base import Var as Var +from pyomo.core.base import active_export_suffix_generator as active_export_suffix_generator +from pyomo.core.kernel.block import IBlock as IBlock +from pyomo.core.kernel.suffix import export_suffix_generator as export_suffix_generator +from pyomo.opt.base import BranchDirection as BranchDirection +from pyomo.opt.base import OptSolver as OptSolver +from pyomo.opt.base import ProblemFormat as ProblemFormat +from pyomo.opt.base import ResultsFormat as ResultsFormat +from pyomo.opt.base.solvers import SolverFactory as SolverFactory +from pyomo.opt.results import Solution as Solution +from pyomo.opt.results import SolutionStatus as SolutionStatus +from pyomo.opt.results import SolverResults as SolverResults +from pyomo.opt.results import SolverStatus as SolverStatus +from pyomo.opt.results import TerminationCondition as TerminationCondition +from pyomo.opt.solver import ILMLicensedSystemCallSolver as ILMLicensedSystemCallSolver +from pyomo.solvers.mockmip import MockMIP as MockMIP +from pyomo.util.components import iter_component as iter_component + +logger: Incomplete + +class CPLEX(OptSolver): + def __new__(cls, *args, **kwds): ... + +class ORDFileSchema: + HEADER: str + FOOTER: str + @classmethod + def ROW(cls, name, priority, branch_direction=None): ... + +class CPLEXSHELL(ILMLicensedSystemCallSolver): + def __init__(self, **kwds) -> None: ... + def warm_start_capable(self): ... + SUFFIX_PRIORITY_NAME: str + SUFFIX_DIRECTION_NAME: str + def create_command_line(self, executable, problem_files): ... + def process_logfile(self): ... + def process_soln_file(self, results) -> None: ... + +class MockCPLEX(CPLEXSHELL, MockMIP): + def __init__(self, **kwds) -> None: ... + def available(self, exception_flag: bool = True): ... + def create_command_line(self, executable, problem_files): ... diff --git a/stubs/pyomo/solvers/plugins/solvers/GAMS.pyi b/stubs/pyomo/solvers/plugins/solvers/GAMS.pyi new file mode 100644 index 000000000..adf5b2ca8 --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/GAMS.pyi @@ -0,0 +1,67 @@ +import types + +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.tee import TeeStream as TeeStream +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import Objective as Objective +from pyomo.core.base import Var as Var +from pyomo.core.base import value as value +from pyomo.core.kernel.block import IBlock as IBlock +from pyomo.core.kernel.objective import IObjective as IObjective +from pyomo.core.kernel.variable import IVariable as IVariable +from pyomo.opt import ProblemFormat as ProblemFormat +from pyomo.opt import SolverFactory as SolverFactory +from pyomo.opt.results import Solution as Solution +from pyomo.opt.results import SolutionStatus as SolutionStatus +from pyomo.opt.results import SolverResults as SolverResults +from pyomo.opt.results import SolverStatus as SolverStatus +from pyomo.opt.results import TerminationCondition as TerminationCondition + +gdxcc: Incomplete +gdxcc_available: Incomplete +logger: Incomplete + +class _GAMSSolver: + options: Incomplete + def __init__(self, **kwds) -> None: ... + def version(self): ... + def warm_start_capable(self): ... + def default_variable_value(self): ... + def set_options(self, istr) -> None: ... + def __enter__(self): ... + def __exit__( + self, + t: type[BaseException] | None, + v: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: ... + +class GAMSSolver(_GAMSSolver): + def __new__(cls, *args, **kwds): ... + +class GAMSDirect(_GAMSSolver): + def available(self, exception_flag: bool = True): ... + def license_is_valid(self): ... + def solve(self, *args, **kwds): ... + +class GAMSShell(_GAMSSolver): + def available(self, exception_flag: bool = True): ... + def license_is_valid(self): ... + def executable(self): ... + def solve(self, *args, **kwds): ... + +class OutputStream: + tee: Incomplete + logfile: Incomplete + logfile_buffer: Incomplete + def __init__(self, tee: bool = False, logfile=None) -> None: ... + def __enter__(self): ... + def __exit__(self, *args, **kwargs) -> None: ... + def write(self, message) -> None: ... + def flush(self) -> None: ... + +def check_expr_evaluation(model, symbolMap, solver_io) -> None: ... +def check_expr(expr, name, solver_io) -> None: ... +def file_removal_gams_direct(tmpdir, newdir) -> None: ... diff --git a/stubs/pyomo/solvers/plugins/solvers/GLPK.pyi b/stubs/pyomo/solvers/plugins/solvers/GLPK.pyi new file mode 100644 index 000000000..03726f0a6 --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/GLPK.pyi @@ -0,0 +1,44 @@ +from _typeshed import Incomplete +from pyomo.common import Executable as Executable +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.enums import maximize as maximize +from pyomo.common.enums import minimize as minimize +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.opt import OptSolver as OptSolver +from pyomo.opt import ProblemFormat as ProblemFormat +from pyomo.opt import ResultsFormat as ResultsFormat +from pyomo.opt import SolutionStatus as SolutionStatus +from pyomo.opt import SolverFactory as SolverFactory +from pyomo.opt import SolverResults as SolverResults +from pyomo.opt import TerminationCondition as TerminationCondition +from pyomo.opt.solver import SystemCallSolver as SystemCallSolver +from pyomo.solvers.mockmip import MockMIP as MockMIP + +logger: Incomplete +GLP_BS: int +GLP_NL: int +GLP_NU: int +GLP_NF: int +GLP_NS: int +GLP_UNDEF: str +GLP_FEAS: str +GLP_INFEAS: str +GLP_NOFEAS: str +GLP_OPT: str + +class GLPK(OptSolver): + def __new__(cls, *args, **kwds): ... + +class GLPKSHELL(SystemCallSolver): + def __init__(self, **kwargs) -> None: ... + def create_command_line(self, executable, problem_files): ... + def process_logfile(self): ... + is_integer: Incomplete + def process_soln_file(self, results) -> None: ... + +class MockGLPK(GLPKSHELL, MockMIP): + def __init__(self, **kwds) -> None: ... + def available(self, exception_flag: bool = True): ... + def create_command_line(self, executable, problem_files): ... + def executable(self): ... diff --git a/stubs/pyomo/solvers/plugins/solvers/GUROBI.pyi b/stubs/pyomo/solvers/plugins/solvers/GUROBI.pyi new file mode 100644 index 000000000..2725f941d --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/GUROBI.pyi @@ -0,0 +1,50 @@ +from _typeshed import Incomplete +from pyomo.common import Executable as Executable +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.enums import maximize as maximize +from pyomo.common.enums import minimize as minimize +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.common.fileutils import this_file_dir as this_file_dir +from pyomo.common.log import is_debug_set as is_debug_set +from pyomo.common.tee import TeeStream as TeeStream +from pyomo.common.tee import capture_output as capture_output +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.core import ConcreteModel as ConcreteModel +from pyomo.core import Objective as Objective +from pyomo.core import Var as Var +from pyomo.core.kernel.block import IBlock as IBlock +from pyomo.opt.base import OptSolver as OptSolver +from pyomo.opt.base import ProblemFormat as ProblemFormat +from pyomo.opt.base import ResultsFormat as ResultsFormat +from pyomo.opt.base.solvers import SolverFactory as SolverFactory +from pyomo.opt.results import Solution as Solution +from pyomo.opt.results import SolutionStatus as SolutionStatus +from pyomo.opt.results import SolverStatus as SolverStatus +from pyomo.opt.results import TerminationCondition as TerminationCondition +from pyomo.opt.solver import ILMLicensedSystemCallSolver as ILMLicensedSystemCallSolver +from pyomo.solvers.plugins.solvers.ASL import ASL as ASL +from pyomo.solvers.plugins.solvers.gurobi_direct import gurobipy as gurobipy +from pyomo.solvers.plugins.solvers.gurobi_direct import gurobipy_available as gurobipy_available + +logger: Incomplete +GUROBI_RUN: Incomplete + +class GUROBI(OptSolver): + def __new__(cls, *args, **kwds): ... + +class GUROBINL(ASL): + def license_is_valid(self): ... + +class GUROBISHELL(ILMLicensedSystemCallSolver): + def __init__(self, **kwds) -> None: ... + def license_is_valid(self): ... + def warm_start_capable(self): ... + def create_command_line(self, executable, problem_files): ... + def process_soln_file(self, results) -> None: ... + +class GUROBIFILE(GUROBISHELL): + def available(self, exception_flag: bool = False): ... + def license_is_valid(self): ... + def create_command_line(self, executable, problem_files): ... + def process_soln_file(self, results) -> None: ... diff --git a/stubs/pyomo/solvers/plugins/solvers/GUROBI_RUN.pyi b/stubs/pyomo/solvers/plugins/solvers/GUROBI_RUN.pyi new file mode 100644 index 000000000..91698fb7c --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/GUROBI_RUN.pyi @@ -0,0 +1,6 @@ +from _typeshed import Incomplete + +GUROBI_VERSION: Incomplete + +def gurobi_run(model_file, warmstart_file, mipgap, options, suffixes): ... +def write_result(result, soln_file) -> None: ... diff --git a/stubs/pyomo/solvers/plugins/solvers/IPOPT.pyi b/stubs/pyomo/solvers/plugins/solvers/IPOPT.pyi new file mode 100644 index 000000000..996c485d3 --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/IPOPT.pyi @@ -0,0 +1,22 @@ +from _typeshed import Incomplete +from pyomo.common import Executable as Executable +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.common.tee import capture_output as capture_output +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.opt.base import ProblemFormat as ProblemFormat +from pyomo.opt.base import ResultsFormat as ResultsFormat +from pyomo.opt.base.solvers import SolverFactory as SolverFactory +from pyomo.opt.results import SolverResults as SolverResults +from pyomo.opt.results import SolverStatus as SolverStatus +from pyomo.opt.results import TerminationCondition as TerminationCondition +from pyomo.opt.solver import SystemCallSolver as SystemCallSolver +from pyomo.solvers.amplfunc_merge import amplfunc_merge as amplfunc_merge + +logger: Incomplete + +class IPOPT(SystemCallSolver): + def __init__(self, **kwds) -> None: ... + def create_command_line(self, executable, problem_files): ... + def process_output(self, rc): ... + def has_linear_solver(self, linear_solver): ... diff --git a/stubs/pyomo/solvers/plugins/solvers/KNITROAMPL.pyi b/stubs/pyomo/solvers/plugins/solvers/KNITROAMPL.pyi new file mode 100644 index 000000000..566068c44 --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/KNITROAMPL.pyi @@ -0,0 +1,14 @@ +from _typeshed import Incomplete +from pyomo.common import Executable as Executable +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.dependencies import pathlib as pathlib +from pyomo.opt.base.formats import ProblemFormat as ProblemFormat +from pyomo.opt.base.formats import ResultsFormat as ResultsFormat +from pyomo.opt.base.solvers import OptSolver as OptSolver +from pyomo.opt.base.solvers import SolverFactory as SolverFactory +from pyomo.solvers.plugins.solvers.ASL import ASL as ASL + +logger: Incomplete + +class KNITROAMPL(ASL): + def __init__(self, **kwds) -> None: ... diff --git a/stubs/pyomo/solvers/plugins/solvers/SAS.pyi b/stubs/pyomo/solvers/plugins/solvers/SAS.pyi new file mode 100644 index 000000000..a5f72ca85 --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/SAS.pyi @@ -0,0 +1,48 @@ +import abc +from abc import ABC + +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.log import LogStream as LogStream +from pyomo.common.tee import TeeStream as TeeStream +from pyomo.common.tee import capture_output as capture_output +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.core.base import Var as Var +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.kernel.block import IBlock as IBlock +from pyomo.opt.base import OptSolver as OptSolver +from pyomo.opt.base import ProblemFormat as ProblemFormat +from pyomo.opt.base import ResultsFormat as ResultsFormat +from pyomo.opt.base.solvers import SolverFactory as SolverFactory +from pyomo.opt.results import ProblemSense as ProblemSense +from pyomo.opt.results import SolutionStatus as SolutionStatus +from pyomo.opt.results import SolverResults as SolverResults +from pyomo.opt.results import SolverStatus as SolverStatus +from pyomo.opt.results import TerminationCondition as TerminationCondition + +uuid: Incomplete +uuid_available: Incomplete +logger: Incomplete +STATUS_TO_SOLVERSTATUS: Incomplete +SOLSTATUS_TO_TERMINATIONCOND: Incomplete +SOLSTATUS_TO_MESSAGE: Incomplete + +class SAS(OptSolver): + def __new__(cls, *args, **kwds): ... + +class SASAbc(ABC, OptSolver, metaclass=abc.ABCMeta): + def __init__(self, **kwds) -> None: ... + def available(self, exception_flag: bool = False): ... + def warm_start_capable(self): ... + +class SAS94(SASAbc): + def __init__(self, **kwds) -> None: ... + def __del__(self) -> None: ... + def sas_version(self): ... + def start_sas_session(self): ... + +class SASCAS(SASAbc): + def __init__(self, **kwds) -> None: ... + def __del__(self) -> None: ... + def start_sas_session(self): ... diff --git a/stubs/pyomo/solvers/plugins/solvers/SCIPAMPL.pyi b/stubs/pyomo/solvers/plugins/solvers/SCIPAMPL.pyi new file mode 100644 index 000000000..501d089fc --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/SCIPAMPL.pyi @@ -0,0 +1,19 @@ +from _typeshed import Incomplete +from pyomo.common import Executable as Executable +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.opt.base import ProblemFormat as ProblemFormat +from pyomo.opt.base import ResultsFormat as ResultsFormat +from pyomo.opt.base.solvers import SolverFactory as SolverFactory +from pyomo.opt.results import SolutionStatus as SolutionStatus +from pyomo.opt.results import SolverStatus as SolverStatus +from pyomo.opt.results import TerminationCondition as TerminationCondition +from pyomo.opt.solver import SystemCallSolver as SystemCallSolver + +logger: Incomplete + +class SCIPAMPL(SystemCallSolver): + def __init__(self, **kwds) -> None: ... + def create_command_line(self, executable, problem_files): ... + @staticmethod + def read_scip_log(filename: str): ... diff --git a/stubs/pyomo/solvers/plugins/solvers/XPRESS.pyi b/stubs/pyomo/solvers/plugins/solvers/XPRESS.pyi new file mode 100644 index 000000000..775c53d9d --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/XPRESS.pyi @@ -0,0 +1,8 @@ +from _typeshed import Incomplete +from pyomo.opt.base import OptSolver as OptSolver +from pyomo.opt.base.solvers import SolverFactory as SolverFactory + +logger: Incomplete + +class XPRESS(OptSolver): + def __new__(cls, *args, **kwds): ... diff --git a/stubs/pyomo/solvers/plugins/solvers/__init__.pyi b/stubs/pyomo/solvers/plugins/solvers/__init__.pyi new file mode 100644 index 000000000..8c00cadfc --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/__init__.pyi @@ -0,0 +1,22 @@ +from pyomo.solvers.plugins.solvers import ASL as ASL +from pyomo.solvers.plugins.solvers import BARON as BARON +from pyomo.solvers.plugins.solvers import CONOPT as CONOPT +from pyomo.solvers.plugins.solvers import CPLEX as CPLEX +from pyomo.solvers.plugins.solvers import GAMS as GAMS +from pyomo.solvers.plugins.solvers import GLPK as GLPK +from pyomo.solvers.plugins.solvers import GUROBI as GUROBI +from pyomo.solvers.plugins.solvers import IPOPT as IPOPT +from pyomo.solvers.plugins.solvers import KNITROAMPL as KNITROAMPL +from pyomo.solvers.plugins.solvers import SAS as SAS +from pyomo.solvers.plugins.solvers import SCIPAMPL as SCIPAMPL +from pyomo.solvers.plugins.solvers import XPRESS as XPRESS +from pyomo.solvers.plugins.solvers import CBCplugin as CBCplugin +from pyomo.solvers.plugins.solvers import cplex_direct as cplex_direct +from pyomo.solvers.plugins.solvers import cplex_persistent as cplex_persistent +from pyomo.solvers.plugins.solvers import gurobi_direct as gurobi_direct +from pyomo.solvers.plugins.solvers import gurobi_persistent as gurobi_persistent +from pyomo.solvers.plugins.solvers import mosek_direct as mosek_direct +from pyomo.solvers.plugins.solvers import mosek_persistent as mosek_persistent +from pyomo.solvers.plugins.solvers import pywrapper as pywrapper +from pyomo.solvers.plugins.solvers import xpress_direct as xpress_direct +from pyomo.solvers.plugins.solvers import xpress_persistent as xpress_persistent diff --git a/stubs/pyomo/solvers/plugins/solvers/cplex_direct.pyi b/stubs/pyomo/solvers/plugins/solvers/cplex_direct.pyi new file mode 100644 index 000000000..74f4879f0 --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/cplex_direct.pyi @@ -0,0 +1,73 @@ +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import Objective as Objective +from pyomo.core.base import SOSConstraint as SOSConstraint +from pyomo.core.base import Suffix as Suffix +from pyomo.core.base import Var as Var +from pyomo.core.expr.numvalue import is_fixed as is_fixed +from pyomo.core.expr.numvalue import value as value +from pyomo.core.kernel.objective import maximize as maximize +from pyomo.core.kernel.objective import minimize as minimize +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager +from pyomo.opt.base import SolverFactory as SolverFactory +from pyomo.opt.results.results_ import SolverResults as SolverResults +from pyomo.opt.results.solution import Solution as Solution +from pyomo.opt.results.solution import SolutionStatus as SolutionStatus +from pyomo.opt.results.solver import SolverStatus as SolverStatus +from pyomo.opt.results.solver import TerminationCondition as TerminationCondition +from pyomo.repn import generate_standard_repn as generate_standard_repn +from pyomo.solvers.plugins.solvers.direct_or_persistent_solver import ( + DirectOrPersistentSolver as DirectOrPersistentSolver, +) +from pyomo.solvers.plugins.solvers.direct_solver import DirectSolver as DirectSolver + +logger: Incomplete + +class DegreeError(ValueError): ... + +class _CplexExpr: + variables: Incomplete + coefficients: Incomplete + offset: Incomplete + q_variables1: Incomplete + q_variables2: Incomplete + q_coefficients: Incomplete + def __init__( + self, + variables, + coefficients, + offset=None, + q_variables1=None, + q_variables2=None, + q_coefficients=None, + ) -> None: ... + +class _VariableData: + lb: Incomplete + ub: Incomplete + types: Incomplete + names: Incomplete + def __init__(self, solver_model) -> None: ... + def add(self, lb, ub, type_, name) -> None: ... + def store_in_cplex(self) -> None: ... + +class _LinearConstraintData: + lin_expr: Incomplete + senses: Incomplete + rhs: Incomplete + range_values: Incomplete + names: Incomplete + def __init__(self, solver_model) -> None: ... + def add(self, cplex_expr, sense, rhs, range_values, name) -> None: ... + def store_in_cplex(self) -> None: ... + +class CPLEXDirect(DirectSolver): + def __init__(self, **kwds) -> None: ... + def warm_start_capable(self): ... + def load_duals(self, cons_to_load=None) -> None: ... + def load_rc(self, vars_to_load) -> None: ... + def load_slacks(self, cons_to_load=None) -> None: ... diff --git a/stubs/pyomo/solvers/plugins/solvers/cplex_persistent.pyi b/stubs/pyomo/solvers/plugins/solvers/cplex_persistent.pyi new file mode 100644 index 000000000..59ffdae45 --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/cplex_persistent.pyi @@ -0,0 +1,9 @@ +from pyomo.core.expr.numvalue import value as value +from pyomo.opt.base import SolverFactory as SolverFactory +from pyomo.solvers.plugins.solvers.cplex_direct import CPLEXDirect as CPLEXDirect +from pyomo.solvers.plugins.solvers.persistent_solver import PersistentSolver as PersistentSolver + +class CPLEXPersistent(PersistentSolver, CPLEXDirect): + def __init__(self, **kwds) -> None: ... + def update_var(self, var) -> None: ... + def write(self, filename, filetype: str = '') -> None: ... diff --git a/stubs/pyomo/solvers/plugins/solvers/direct_or_persistent_solver.pyi b/stubs/pyomo/solvers/plugins/solvers/direct_or_persistent_solver.pyi new file mode 100644 index 000000000..89d2196b6 --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/direct_or_persistent_solver.pyi @@ -0,0 +1,23 @@ +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.core.base import NumericLabeler as NumericLabeler +from pyomo.core.base import SymbolMap as SymbolMap +from pyomo.core.base import TextLabeler as TextLabeler +from pyomo.core.base.block import Block as Block +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.PyomoModel import Model as Model +from pyomo.core.kernel.block import IBlock as IBlock +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager +from pyomo.opt.base.formats import ResultsFormat as ResultsFormat +from pyomo.opt.base.solvers import OptSolver as OptSolver + +class DirectOrPersistentSolver(OptSolver): + results: Incomplete + def __init__(self, **kwds) -> None: ... + def load_vars(self, vars_to_load=None) -> None: ... + def warm_start_capable(self) -> None: ... + def available(self, exception_flag: bool = True): ... diff --git a/stubs/pyomo/solvers/plugins/solvers/direct_solver.pyi b/stubs/pyomo/solvers/plugins/solvers/direct_solver.pyi new file mode 100644 index 000000000..5ed6c02e2 --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/direct_solver.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.suffix import active_import_suffix_generator as active_import_suffix_generator +from pyomo.core.kernel.block import IBlock as IBlock +from pyomo.core.kernel.suffix import import_suffix_generator as import_suffix_generator +from pyomo.solvers.plugins.solvers.direct_or_persistent_solver import ( + DirectOrPersistentSolver as DirectOrPersistentSolver, +) + +logger: Incomplete + +class DirectSolver(DirectOrPersistentSolver): + options: Incomplete + def solve(self, *args, **kwds): ... diff --git a/stubs/pyomo/solvers/plugins/solvers/gurobi_direct.pyi b/stubs/pyomo/solvers/plugins/solvers/gurobi_direct.pyi new file mode 100644 index 000000000..d6e38832d --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/gurobi_direct.pyi @@ -0,0 +1,50 @@ +import types + +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.common.tee import capture_output as capture_output +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.core.base.suffix import Suffix as Suffix +from pyomo.core.expr.numvalue import is_fixed as is_fixed +from pyomo.core.expr.numvalue import value as value +from pyomo.core.kernel.objective import maximize as maximize +from pyomo.core.kernel.objective import minimize as minimize +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager +from pyomo.opt.base import SolverFactory as SolverFactory +from pyomo.opt.results.results_ import SolverResults as SolverResults +from pyomo.opt.results.solution import Solution as Solution +from pyomo.opt.results.solution import SolutionStatus as SolutionStatus +from pyomo.opt.results.solver import SolverStatus as SolverStatus +from pyomo.opt.results.solver import TerminationCondition as TerminationCondition +from pyomo.repn import generate_standard_repn as generate_standard_repn +from pyomo.solvers.plugins.solvers.direct_or_persistent_solver import ( + DirectOrPersistentSolver as DirectOrPersistentSolver, +) +from pyomo.solvers.plugins.solvers.direct_solver import DirectSolver as DirectSolver + +logger: Incomplete + +class DegreeError(ValueError): ... + +gurobipy: Incomplete +gurobipy_available: Incomplete + +class GurobiDirect(DirectSolver): + def __init__(self, manage_env: bool = False, **kwds) -> None: ... + def available(self, exception_flag: bool = True): ... + def close_global(self) -> None: ... + def close(self) -> None: ... + def __exit__( + self, + t: type[BaseException] | None, + v: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: ... + def warm_start_capable(self): ... + def load_duals(self, cons_to_load=None) -> None: ... + def load_rc(self, vars_to_load) -> None: ... + def load_slacks(self, cons_to_load=None) -> None: ... diff --git a/stubs/pyomo/solvers/plugins/solvers/gurobi_persistent.pyi b/stubs/pyomo/solvers/plugins/solvers/gurobi_persistent.pyi new file mode 100644 index 000000000..78e201b1e --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/gurobi_persistent.pyi @@ -0,0 +1,31 @@ +from pyomo.core.expr.numvalue import is_fixed as is_fixed +from pyomo.core.expr.numvalue import value as value +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager +from pyomo.opt.base import SolverFactory as SolverFactory +from pyomo.solvers.plugins.solvers.gurobi_direct import GurobiDirect as GurobiDirect +from pyomo.solvers.plugins.solvers.gurobi_direct import gurobipy as gurobipy +from pyomo.solvers.plugins.solvers.persistent_solver import PersistentSolver as PersistentSolver + +class GurobiPersistent(PersistentSolver, GurobiDirect): + def __init__(self, **kwds) -> None: ... + def update_var(self, var) -> None: ... + def write(self, filename) -> None: ... + def update(self) -> None: ... + def set_linear_constraint_attr(self, con, attr, val) -> None: ... + def set_var_attr(self, var, attr, val) -> None: ... + def get_model_attr(self, attr): ... + def get_var_attr(self, var, attr): ... + def get_linear_constraint_attr(self, con, attr): ... + def get_sos_attr(self, con, attr): ... + def get_quadratic_constraint_attr(self, con, attr): ... + def set_gurobi_param(self, param, val) -> None: ... + def get_gurobi_param_info(self, param): ... + def set_callback(self, func=None) -> None: ... + def cbCut(self, con) -> None: ... + def cbGet(self, what): ... + def cbGetNodeRel(self, vars) -> None: ... + def cbGetSolution(self, vars) -> None: ... + def cbLazy(self, con) -> None: ... + def cbSetSolution(self, vars, solution) -> None: ... + def cbUseSolution(self): ... + def reset(self) -> None: ... diff --git a/stubs/pyomo/solvers/plugins/solvers/mosek_direct.pyi b/stubs/pyomo/solvers/plugins/solvers/mosek_direct.pyi new file mode 100644 index 000000000..26364ab73 --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/mosek_direct.pyi @@ -0,0 +1,52 @@ +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.core import is_fixed as is_fixed +from pyomo.core import maximize as maximize +from pyomo.core import minimize as minimize +from pyomo.core import value as value +from pyomo.core.base.suffix import Suffix as Suffix +from pyomo.core.kernel.conic import dual_exponential as dual_exponential +from pyomo.core.kernel.conic import dual_geomean as dual_geomean +from pyomo.core.kernel.conic import dual_power as dual_power +from pyomo.core.kernel.conic import primal_exponential as primal_exponential +from pyomo.core.kernel.conic import primal_geomean as primal_geomean +from pyomo.core.kernel.conic import primal_power as primal_power +from pyomo.core.kernel.conic import quadratic as quadratic +from pyomo.core.kernel.conic import rotated_quadratic as rotated_quadratic +from pyomo.core.kernel.conic import svec_psdcone as svec_psdcone +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager +from pyomo.opt import SolverFactory as SolverFactory +from pyomo.opt.base.solvers import OptSolver as OptSolver +from pyomo.opt.results.results_ import SolverResults as SolverResults +from pyomo.opt.results.solution import Solution as Solution +from pyomo.opt.results.solution import SolutionStatus as SolutionStatus +from pyomo.opt.results.solver import SolverStatus as SolverStatus +from pyomo.opt.results.solver import TerminationCondition as TerminationCondition +from pyomo.repn import generate_standard_repn as generate_standard_repn +from pyomo.solvers.plugins.solvers.direct_or_persistent_solver import ( + DirectOrPersistentSolver as DirectOrPersistentSolver, +) +from pyomo.solvers.plugins.solvers.direct_solver import DirectSolver as DirectSolver + +logger: Incomplete +inf: Incomplete +mosek: Incomplete +mosek_available: Incomplete + +class DegreeError(ValueError): ... +class UnsupportedDomainError(TypeError): ... + +class MOSEK(OptSolver): + def __new__(cls, *args, **kwds): ... + +class MOSEKDirect(DirectSolver): + def __init__(self, **kwds) -> None: ... + def license_is_valid(self): ... + def warm_start_capable(self): ... + def load_duals(self, cons_to_load=None) -> None: ... + def load_rc(self, vars_to_load) -> None: ... + def load_slacks(self, cons_to_load=None) -> None: ... diff --git a/stubs/pyomo/solvers/plugins/solvers/mosek_persistent.pyi b/stubs/pyomo/solvers/plugins/solvers/mosek_persistent.pyi new file mode 100644 index 000000000..9f47bcca0 --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/mosek_persistent.pyi @@ -0,0 +1,25 @@ +from pyomo.core import is_fixed as is_fixed +from pyomo.core import value as value +from pyomo.core.base.constraint import Constraint as Constraint +from pyomo.core.base.PyomoModel import ConcreteModel as ConcreteModel +from pyomo.core.base.var import Var as Var +from pyomo.core.kernel.block import block as block +from pyomo.opt.base import SolverFactory as SolverFactory +from pyomo.solvers.plugins.solvers.direct_or_persistent_solver import ( + DirectOrPersistentSolver as DirectOrPersistentSolver, +) +from pyomo.solvers.plugins.solvers.direct_solver import DirectSolver as DirectSolver +from pyomo.solvers.plugins.solvers.mosek_direct import MOSEKDirect as MOSEKDirect +from pyomo.solvers.plugins.solvers.persistent_solver import PersistentSolver as PersistentSolver + +class MOSEKPersistent(PersistentSolver, MOSEKDirect): + def __init__(self, **kwds) -> None: ... + def add_vars(self, var_seq) -> None: ... + def add_constraints(self, con_seq) -> None: ... + def remove_var(self, solver_var) -> None: ... + def remove_vars(self, *solver_vars) -> None: ... + def remove_constraint(self, solver_con) -> None: ... + def remove_constraints(self, *solver_cons): ... + def update_var(self, solver_var) -> None: ... + def update_vars(self, *solver_vars) -> None: ... + def write(self, filename) -> None: ... diff --git a/stubs/pyomo/solvers/plugins/solvers/persistent_solver.pyi b/stubs/pyomo/solvers/plugins/solvers/persistent_solver.pyi new file mode 100644 index 000000000..cf419a75a --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/persistent_solver.pyi @@ -0,0 +1,35 @@ +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.constraint import Constraint as Constraint +from pyomo.core.base.sos import SOSConstraint as SOSConstraint +from pyomo.core.base.suffix import active_import_suffix_generator as active_import_suffix_generator +from pyomo.core.base.var import Var as Var +from pyomo.core.expr.numvalue import native_numeric_types as native_numeric_types +from pyomo.core.expr.numvalue import value as value +from pyomo.core.expr.visitor import evaluate_expression as evaluate_expression +from pyomo.core.kernel.block import IBlock as IBlock +from pyomo.core.kernel.suffix import import_suffix_generator as import_suffix_generator +from pyomo.solvers.plugins.solvers.direct_or_persistent_solver import ( + DirectOrPersistentSolver as DirectOrPersistentSolver, +) + +logger: Incomplete + +class PersistentSolver(DirectOrPersistentSolver): + def set_instance(self, model, **kwds): ... + def add_block(self, block) -> None: ... + def set_objective(self, obj): ... + def add_constraint(self, con) -> None: ... + def add_var(self, var) -> None: ... + def add_sos_constraint(self, con) -> None: ... + def add_column(self, model, var, obj_coef, constraints, coefficients) -> None: ... + def remove_block(self, block) -> None: ... + def remove_constraint(self, con) -> None: ... + def remove_sos_constraint(self, con) -> None: ... + def remove_var(self, var) -> None: ... + def update_var(self, var) -> None: ... + options: Incomplete + def solve(self, *args, **kwds): ... + def has_instance(self): ... diff --git a/stubs/pyomo/solvers/plugins/solvers/pywrapper.pyi b/stubs/pyomo/solvers/plugins/solvers/pywrapper.pyi new file mode 100644 index 000000000..7023b2922 --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/pywrapper.pyi @@ -0,0 +1,8 @@ +from _typeshed import Incomplete +from pyomo.opt import OptSolver as OptSolver +from pyomo.opt import SolverFactory as SolverFactory + +logger: Incomplete + +class pywrapper(OptSolver): + def __new__(cls, *args, **kwds): ... diff --git a/stubs/pyomo/solvers/plugins/solvers/xpress_direct.pyi b/stubs/pyomo/solvers/plugins/solvers/xpress_direct.pyi new file mode 100644 index 000000000..a0b583ce2 --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/xpress_direct.pyi @@ -0,0 +1,46 @@ +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.dependencies import attempt_import as attempt_import +from pyomo.common.errors import ApplicationError as ApplicationError +from pyomo.common.tee import capture_output as capture_output +from pyomo.common.tempfiles import TempfileManager as TempfileManager +from pyomo.core.base.suffix import Suffix as Suffix +from pyomo.core.expr.numvalue import is_fixed as is_fixed +from pyomo.core.expr.numvalue import value as value +from pyomo.core.kernel.objective import maximize as maximize +from pyomo.core.kernel.objective import minimize as minimize +from pyomo.core.staleflag import StaleFlagManager as StaleFlagManager +from pyomo.opt.base import SolverFactory as SolverFactory +from pyomo.opt.results.results_ import SolverResults as SolverResults +from pyomo.opt.results.solution import Solution as Solution +from pyomo.opt.results.solution import SolutionStatus as SolutionStatus +from pyomo.opt.results.solver import SolverStatus as SolverStatus +from pyomo.opt.results.solver import TerminationCondition as TerminationCondition +from pyomo.repn import generate_standard_repn as generate_standard_repn +from pyomo.solvers.plugins.solvers.direct_or_persistent_solver import ( + DirectOrPersistentSolver as DirectOrPersistentSolver, +) +from pyomo.solvers.plugins.solvers.direct_solver import DirectSolver as DirectSolver + +logger: Incomplete + +class DegreeError(ValueError): ... + +class _xpress_importer_class: + import_message: str + def __init__(self) -> None: ... + def __call__(self): ... + +class XpressDirect(DirectSolver): + XpressException = RuntimeError + def __init__(self, **kwds) -> None: ... + def available(self, exception_flag: bool = True): ... + def warm_start_capable(self): ... + def load_duals(self, cons_to_load=None) -> None: ... + def load_rc(self, vars_to_load=None) -> None: ... + def load_slacks(self, cons_to_load=None) -> None: ... + +xpress: Incomplete +xpress_available: Incomplete diff --git a/stubs/pyomo/solvers/plugins/solvers/xpress_persistent.pyi b/stubs/pyomo/solvers/plugins/solvers/xpress_persistent.pyi new file mode 100644 index 000000000..70e77f0c6 --- /dev/null +++ b/stubs/pyomo/solvers/plugins/solvers/xpress_persistent.pyi @@ -0,0 +1,14 @@ +from pyomo.core.base.PyomoModel import ConcreteModel as ConcreteModel +from pyomo.core.expr.numvalue import is_fixed as is_fixed +from pyomo.core.expr.numvalue import value as value +from pyomo.opt.base import SolverFactory as SolverFactory +from pyomo.solvers.plugins.solvers.persistent_solver import PersistentSolver as PersistentSolver +from pyomo.solvers.plugins.solvers.xpress_direct import XpressDirect as XpressDirect + +class XpressPersistent(PersistentSolver, XpressDirect): + def __init__(self, **kwds) -> None: ... + def update_var(self, var) -> None: ... + def get_xpress_attribute(self, *args): ... + def set_xpress_control(self, *args) -> None: ... + def get_xpress_control(self, *args): ... + def write(self, filename, flags: str = '') -> None: ... diff --git a/stubs/pyomo/solvers/wrappers.pyi b/stubs/pyomo/solvers/wrappers.pyi new file mode 100644 index 000000000..3122a872d --- /dev/null +++ b/stubs/pyomo/solvers/wrappers.pyi @@ -0,0 +1,2 @@ +class MIPSolverWrapper: + def add(self, constraint) -> None: ... diff --git a/stubs/pyomo/util/__init__.pyi b/stubs/pyomo/util/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/pyomo/util/blockutil.pyi b/stubs/pyomo/util/blockutil.pyi new file mode 100644 index 000000000..502fbbb24 --- /dev/null +++ b/stubs/pyomo/util/blockutil.pyi @@ -0,0 +1,9 @@ +from _typeshed import Incomplete +from pyomo.core import Constraint as Constraint +from pyomo.core import TraversalStrategy as TraversalStrategy +from pyomo.core import Var as Var + +logger: Incomplete + +def has_discrete_variables(block): ... +def log_model_constraints(m, logger=..., active: bool = True) -> None: ... diff --git a/stubs/pyomo/util/calc_var_value.pyi b/stubs/pyomo/util/calc_var_value.pyi new file mode 100644 index 000000000..effe9b5e1 --- /dev/null +++ b/stubs/pyomo/util/calc_var_value.pyi @@ -0,0 +1,19 @@ +from _typeshed import Incomplete +from pyomo.common.errors import IterationLimitError as IterationLimitError +from pyomo.common.numeric_types import native_complex_types as native_complex_types +from pyomo.common.numeric_types import native_numeric_types as native_numeric_types +from pyomo.common.numeric_types import value as value +from pyomo.core.base.constraint import Constraint as Constraint +from pyomo.core.expr.calculus.derivatives import differentiate as differentiate + +logger: Incomplete + +def calculate_variable_from_constraint( + variable, + constraint, + eps: float = 1e-08, + iterlim: int = 1000, + linesearch: bool = True, + alpha_min: float = 1e-08, + diff_mode=None, +) -> None: ... diff --git a/stubs/pyomo/util/check_units.pyi b/stubs/pyomo/util/check_units.pyi new file mode 100644 index 000000000..75ae61d2f --- /dev/null +++ b/stubs/pyomo/util/check_units.pyi @@ -0,0 +1,36 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.core.base import Block as Block +from pyomo.core.base import BooleanVar as BooleanVar +from pyomo.core.base import BuildAction as BuildAction +from pyomo.core.base import BuildCheck as BuildCheck +from pyomo.core.base import Constraint as Constraint +from pyomo.core.base import Expression as Expression +from pyomo.core.base import ExternalFunction as ExternalFunction +from pyomo.core.base import Objective as Objective +from pyomo.core.base import Param as Param +from pyomo.core.base import RangeSet as RangeSet +from pyomo.core.base import Set as Set +from pyomo.core.base import SetOf as SetOf +from pyomo.core.base import Suffix as Suffix +from pyomo.core.base import Var as Var +from pyomo.core.base import value as value +from pyomo.core.base.units_container import UnitsError as UnitsError +from pyomo.core.base.units_container import units as units +from pyomo.core.expr.numvalue import native_types as native_types +from pyomo.core.expr.template_expr import IndexTemplate as IndexTemplate +from pyomo.dae import ContinuousSet as ContinuousSet +from pyomo.dae import DerivativeVar as DerivativeVar +from pyomo.gdp import Disjunct as Disjunct +from pyomo.gdp import Disjunction as Disjunction +from pyomo.mpec import Complementarity as Complementarity +from pyomo.network import Arc as Arc +from pyomo.network import Port as Port +from pyomo.util.components import iter_component as iter_component + +logger: Incomplete + +def check_units_equivalent(*args): ... +def assert_units_equivalent(*args) -> None: ... +def assert_units_consistent(obj) -> None: ... +def identify_inconsistent_units(block): ... diff --git a/stubs/pyomo/util/components.pyi b/stubs/pyomo/util/components.pyi new file mode 100644 index 000000000..a8315ffad --- /dev/null +++ b/stubs/pyomo/util/components.pyi @@ -0,0 +1,6 @@ +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.core.base.reference import Reference as Reference + +def rename_components(model, component_list, prefix): ... +def iter_component(obj): ... diff --git a/stubs/pyomo/util/config_domains.pyi b/stubs/pyomo/util/config_domains.pyi new file mode 100644 index 000000000..e2498664d --- /dev/null +++ b/stubs/pyomo/util/config_domains.pyi @@ -0,0 +1,6 @@ +from pyomo.common.collections import ComponentSet as ComponentSet + +class ComponentDataSet: + def __init__(self, ctype) -> None: ... + def __call__(self, x): ... + def domain_name(self): ... diff --git a/stubs/pyomo/util/diagnostics.pyi b/stubs/pyomo/util/diagnostics.pyi new file mode 100644 index 000000000..de8e4a196 --- /dev/null +++ b/stubs/pyomo/util/diagnostics.pyi @@ -0,0 +1,8 @@ +from _typeshed import Incomplete +from pyomo.core.base.block import Block as Block +from pyomo.core.base.block import TraversalStrategy as TraversalStrategy +from pyomo.gdp import Disjunct as Disjunct + +logger: Incomplete + +def log_disjunct_values(m) -> None: ... diff --git a/stubs/pyomo/util/infeasible.pyi b/stubs/pyomo/util/infeasible.pyi new file mode 100644 index 000000000..1f17500a6 --- /dev/null +++ b/stubs/pyomo/util/infeasible.pyi @@ -0,0 +1,21 @@ +from collections.abc import Generator + +from _typeshed import Incomplete +from pyomo.common import deprecated as deprecated +from pyomo.core import Constraint as Constraint +from pyomo.core import Var as Var +from pyomo.core import value as value +from pyomo.core.expr.visitor import identify_variables as identify_variables +from pyomo.util.blockutil import log_model_constraints as log_model_constraints + +logger: Incomplete + +def find_infeasible_constraints(m, tol: float = 1e-06) -> Generator[Incomplete]: ... +def log_infeasible_constraints( + m, tol: float = 1e-06, logger=..., log_expression: bool = False, log_variables: bool = False +) -> None: ... +def find_infeasible_bounds(m, tol: float = 1e-06) -> Generator[Incomplete]: ... +def log_infeasible_bounds(m, tol: float = 1e-06, logger=...) -> None: ... +def find_close_to_bounds(m, tol: float = 1e-06) -> Generator[Incomplete]: ... +def log_close_to_bounds(m, tol: float = 1e-06, logger=...) -> None: ... +def log_active_constraints(m, logger=...) -> None: ... diff --git a/stubs/pyomo/util/model_size.pyi b/stubs/pyomo/util/model_size.pyi new file mode 100644 index 000000000..74b2ed9e2 --- /dev/null +++ b/stubs/pyomo/util/model_size.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from pyomo.common.collections import Bunch as Bunch +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.core import Block as Block +from pyomo.core import Constraint as Constraint +from pyomo.core import Var as Var +from pyomo.gdp import Disjunct as Disjunct +from pyomo.gdp import Disjunction as Disjunction + +default_logger: Incomplete + +class ModelSizeReport(Bunch): ... + +def build_model_size_report(model): ... +def log_model_size_report(model, logger=...) -> None: ... diff --git a/stubs/pyomo/util/report_scaling.pyi b/stubs/pyomo/util/report_scaling.pyi new file mode 100644 index 000000000..8c9379829 --- /dev/null +++ b/stubs/pyomo/util/report_scaling.pyi @@ -0,0 +1,10 @@ +from _typeshed import Incomplete +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.contrib.fbbt.fbbt import compute_bounds_on_expr as compute_bounds_on_expr +from pyomo.core.base.block import BlockData as BlockData +from pyomo.core.base.var import Var as Var +from pyomo.core.expr.calculus.diff_with_pyomo import reverse_sd as reverse_sd + +logger: Incomplete + +def report_scaling(m: BlockData, too_large: float = 50000.0, too_small: float = 1e-06) -> bool: ... diff --git a/stubs/pyomo/util/slices.pyi b/stubs/pyomo/util/slices.pyi new file mode 100644 index 000000000..f988f9724 --- /dev/null +++ b/stubs/pyomo/util/slices.pyi @@ -0,0 +1,9 @@ +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.core.base.global_set import UnindexedComponent_set as UnindexedComponent_set +from pyomo.core.base.indexed_component import normalize_index as normalize_index +from pyomo.core.base.indexed_component_slice import IndexedComponent_slice as IndexedComponent_slice + +def get_component_call_stack(comp, context=None): ... +def slice_component_along_sets(comp, sets, context=None): ... +def replace_indices(index, location_set_map, sets): ... +def get_location_set_map(index, index_set): ... diff --git a/stubs/pyomo/util/subsystems.pyi b/stubs/pyomo/util/subsystems.pyi new file mode 100644 index 000000000..c3ab68d29 --- /dev/null +++ b/stubs/pyomo/util/subsystems.pyi @@ -0,0 +1,66 @@ +import types +from collections.abc import Generator + +from _typeshed import Incomplete +from pyomo.common.collections import ComponentMap as ComponentMap +from pyomo.common.collections import ComponentSet as ComponentSet +from pyomo.common.modeling import unique_component_name as unique_component_name +from pyomo.core.base.block import Block as Block +from pyomo.core.base.constraint import Constraint as Constraint +from pyomo.core.base.expression import Expression as Expression +from pyomo.core.base.external import ExternalFunction as ExternalFunction +from pyomo.core.base.objective import Objective as Objective +from pyomo.core.base.reference import Reference as Reference +from pyomo.core.expr.numeric_expr import ExternalFunctionExpression as ExternalFunctionExpression +from pyomo.core.expr.numvalue import NumericValue as NumericValue +from pyomo.core.expr.numvalue import native_types as native_types +from pyomo.core.expr.visitor import StreamBasedExpressionVisitor as StreamBasedExpressionVisitor +from pyomo.core.expr.visitor import identify_variables as identify_variables +from pyomo.util.vars_from_expressions import get_vars_from_components as get_vars_from_components + +class _ExternalFunctionVisitor(StreamBasedExpressionVisitor): + named_expressions: Incomplete + def __init__(self, descend_into_named_expressions: bool = True) -> None: ... + def initializeWalker(self, expr): ... + def beforeChild(self, parent, child, index): ... + def exitNode(self, node, data) -> None: ... + def finalizeResult(self, result): ... + +def identify_external_functions(expr) -> Generator[Incomplete, Incomplete]: ... +def add_local_external_functions(block): ... +def create_subsystem_block(constraints, variables=None, include_fixed: bool = False): ... +def generate_subsystem_blocks(subsystems, include_fixed: bool = False) -> Generator[Incomplete]: ... + +class TemporarySubsystemManager: + def __init__( + self, + to_fix=None, + to_deactivate=None, + to_reset=None, + to_unfix=None, + remove_bounds_on_fix: bool = False, + ) -> None: ... + def __enter__(self): ... + def __exit__( + self, + ex_type: type[BaseException] | None, + ex_val: BaseException | None, + ex_bt: types.TracebackType | None, + ) -> None: ... + +class ParamSweeper(TemporarySubsystemManager): + input_values: Incomplete + output_values: Incomplete + n_scenario: Incomplete + initial_state_values: Incomplete + def __init__( + self, + n_scenario, + input_values, + output_values=None, + to_fix=None, + to_deactivate=None, + to_reset=None, + ) -> None: ... + def __iter__(self): ... + def __next__(self): ... diff --git a/stubs/pyomo/util/vars_from_expressions.pyi b/stubs/pyomo/util/vars_from_expressions.pyi new file mode 100644 index 000000000..c5b99746d --- /dev/null +++ b/stubs/pyomo/util/vars_from_expressions.pyi @@ -0,0 +1,15 @@ +from collections.abc import Generator + +from _typeshed import Incomplete +from pyomo.core import Block as Block +from pyomo.core.expr.visitor import IdentifyVariableVisitor as IdentifyVariableVisitor + +def get_vars_from_components( + block, + ctype, + include_fixed: bool = True, + active=None, + sort: bool = False, + descend_into=..., + descent_order=None, +) -> Generator[Incomplete]: ... diff --git a/stubs/pyomo/version/__init__.pyi b/stubs/pyomo/version/__init__.pyi new file mode 100644 index 000000000..fc61a17ad --- /dev/null +++ b/stubs/pyomo/version/__init__.pyi @@ -0,0 +1,3 @@ +from pyomo.version.info import __version__ as __version__ +from pyomo.version.info import version as version +from pyomo.version.info import version_info as version_info diff --git a/stubs/pyomo/version/info.pyi b/stubs/pyomo/version/info.pyi new file mode 100644 index 000000000..d70384d20 --- /dev/null +++ b/stubs/pyomo/version/info.pyi @@ -0,0 +1,10 @@ +from _typeshed import Incomplete + +major: int +minor: int +micro: int +releaselevel: str +serial: int +version_info: Incomplete +__version__: Incomplete +version = __version__ diff --git a/uv.lock b/uv.lock index 6d43de06a..3a26122be 100644 --- a/uv.lock +++ b/uv.lock @@ -1768,6 +1768,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d5/f9/07086f5b0f2a19872554abeea7658200824f5835c58a106fa8f2ae96a46c/pandas-2.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5db9637dbc24b631ff3707269ae4559bce4b7fd75c1c4d7e13f40edc42df4444", size = 13189044, upload-time = "2025-07-07T19:19:39.999Z" }, ] +[[package]] +name = "pandas-stubs" +version = "2.3.2.250926" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "types-pytz" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1b/3b/32be58a125db39d0b5f62cc93795f32b5bb2915bd5c4a46f0e35171985e2/pandas_stubs-2.3.2.250926.tar.gz", hash = "sha256:c64b9932760ceefb96a3222b953e6a251321a9832a28548be6506df473a66406", size = 102147, upload-time = "2025-09-26T19:50:39.522Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/96/1e4a035eaf4dce9610aac6e43026d0c6baa05773daf6d21e635a4fe19e21/pandas_stubs-2.3.2.250926-py3-none-any.whl", hash = "sha256:81121818453dcfe00f45c852f4dceee043640b813830f6e7bd084a4ef7ff7270", size = 159995, upload-time = "2025-09-26T19:50:38.241Z" }, +] + [[package]] name = "pandera" version = "0.25.0" @@ -2956,12 +2969,6 @@ dependencies = [ ] [package.optional-dependencies] -dev = [ - { name = "pre-commit" }, - { name = "pytest" }, - { name = "pytest-cov" }, - { name = "ruff" }, -] docs = [ { name = "sphinx" }, { name = "sphinx-rtd-theme" }, @@ -2977,6 +2984,12 @@ plotting = [ [package.dev-dependencies] dev = [ { name = "gurobipy" }, + { name = "pandas-stubs" }, + { name = "pre-commit" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "ruff" }, + { name = "types-deprecated" }, ] [package.metadata] @@ -2998,15 +3011,11 @@ requires-dist = [ { name = "nx-vis-visualizer", specifier = ">=0.1.1" }, { name = "openpyxl", specifier = ">=3.1.5" }, { name = "pandas", specifier = ">=2.2.2" }, - { name = "pre-commit", marker = "extra == 'dev'" }, { name = "pyam-iamc", specifier = ">=2.2.4" }, { name = "pydoe", specifier = ">=0.3.8" }, { name = "pyomo", specifier = ">=6.8.0" }, { name = "pytest", specifier = ">=8.3.2" }, - { name = "pytest", marker = "extra == 'dev'" }, - { name = "pytest-cov", marker = "extra == 'dev'" }, { name = "pyutilib", specifier = ">=6.0.0" }, - { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.2.0" }, { name = "salib", specifier = ">=1.5.1" }, { name = "scipy", specifier = ">=1.14.1" }, { name = "seaborn", specifier = ">=0.13.2" }, @@ -3019,10 +3028,18 @@ requires-dist = [ { name = "tabulate", specifier = ">=0.9.0" }, { name = "xlsxwriter", specifier = ">=3.2.0" }, ] -provides-extras = ["docs", "dev", "plotting"] +provides-extras = ["docs", "plotting"] [package.metadata.requires-dev] -dev = [{ name = "gurobipy", specifier = ">=12.0.3" }] +dev = [ + { name = "gurobipy", specifier = ">=12.0.3" }, + { name = "pandas-stubs", specifier = ">=2.3.2.250926" }, + { name = "pre-commit" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "ruff", specifier = ">=0.2.0" }, + { name = "types-deprecated", specifier = ">=1.2.15.20250304" }, +] [[package]] name = "terminado" @@ -3114,6 +3131,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/76/42/3efaf858001d2c2913de7f354563e3a3a2f0decae3efe98427125a8f441e/typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855", size = 46317, upload-time = "2025-05-26T14:30:30.523Z" }, ] +[[package]] +name = "types-deprecated" +version = "1.2.15.20250304" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0e/67/eeefaaabb03b288aad85483d410452c8bbcbf8b2bd876b0e467ebd97415b/types_deprecated-1.2.15.20250304.tar.gz", hash = "sha256:c329030553029de5cc6cb30f269c11f4e00e598c4241290179f63cda7d33f719", size = 8015, upload-time = "2025-03-04T02:48:17.894Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/e3/c18aa72ab84e0bc127a3a94e93be1a6ac2cb281371d3a45376ab7cfdd31c/types_deprecated-1.2.15.20250304-py3-none-any.whl", hash = "sha256:86a65aa550ea8acf49f27e226b8953288cd851de887970fbbdf2239c116c3107", size = 8553, upload-time = "2025-03-04T02:48:16.666Z" }, +] + [[package]] name = "types-python-dateutil" version = "2.9.0.20250708" @@ -3123,6 +3149,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/72/52/43e70a8e57fefb172c22a21000b03ebcc15e47e97f5cb8495b9c2832efb4/types_python_dateutil-2.9.0.20250708-py3-none-any.whl", hash = "sha256:4d6d0cc1cc4d24a2dc3816024e502564094497b713f7befda4d5bc7a8e3fd21f", size = 17724, upload-time = "2025-07-08T03:14:02.593Z" }, ] +[[package]] +name = "types-pytz" +version = "2025.2.0.20250809" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/07/e2/c774f754de26848f53f05defff5bb21dd9375a059d1ba5b5ea943cf8206e/types_pytz-2025.2.0.20250809.tar.gz", hash = "sha256:222e32e6a29bb28871f8834e8785e3801f2dc4441c715cd2082b271eecbe21e5", size = 10876, upload-time = "2025-08-09T03:14:17.453Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/d0/91c24fe54e565f2344d7a6821e6c6bb099841ef09007ea6321a0bac0f808/types_pytz-2025.2.0.20250809-py3-none-any.whl", hash = "sha256:4f55ed1b43e925cf851a756fe1707e0f5deeb1976e15bf844bcaa025e8fbd0db", size = 10095, upload-time = "2025-08-09T03:14:16.674Z" }, +] + [[package]] name = "typing-extensions" version = "4.14.1" From 2c522ae720305fdef1bbf42ade1f6a2d7c554faf Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 18 Oct 2025 19:01:25 -0400 Subject: [PATCH 245/587] adding temoa/types module for giving type aliases to temoa code --- temoa/types/__init__.py | 157 +++++++++++++++ temoa/types/core_types.py | 143 +++++++++++++ temoa/types/database_types.py | 166 +++++++++++++++ temoa/types/dict_types.py | 113 +++++++++++ temoa/types/index_types.py | 35 ++++ temoa/types/model_types.py | 345 ++++++++++++++++++++++++++++++++ temoa/types/set_types.py | 57 ++++++ temoa/types/solver_types.py | 99 +++++++++ temoa/types/validation_types.py | 237 ++++++++++++++++++++++ 9 files changed, 1352 insertions(+) create mode 100644 temoa/types/__init__.py create mode 100644 temoa/types/core_types.py create mode 100644 temoa/types/database_types.py create mode 100644 temoa/types/dict_types.py create mode 100644 temoa/types/index_types.py create mode 100644 temoa/types/model_types.py create mode 100644 temoa/types/set_types.py create mode 100644 temoa/types/solver_types.py create mode 100644 temoa/types/validation_types.py diff --git a/temoa/types/__init__.py b/temoa/types/__init__.py new file mode 100644 index 000000000..8ecfc80c5 --- /dev/null +++ b/temoa/types/__init__.py @@ -0,0 +1,157 @@ +# Types module for TEMOA + + +# Define public API for this module +# ruff: noqa: RUF022 +__all__ = [ + # Core types + 'Commodity', + 'CommoditySet', + 'Period', + 'Region', + 'RegionSet', + 'Season', + 'SparseIndex', + 'Technology', + 'TechSet', + 'TimeOfDay', + 'Vintage', + # Dictionary types + 'ActiveRegionsForTechDict', + 'BaseloadVintagesDict', + 'CapacityConsumptionTechsDict', + 'CapacityFactorProcessDict', + 'CommodityStreamProcessDict', + 'CurtailmentVintagesDict', + 'EfficiencyVariableDict', + 'ExportRegionsDict', + 'ImportRegionsDict', + 'InputSplitAnnualVintagesDict', + 'InputSplitVintagesDict', + 'OutputSplitAnnualVintagesDict', + 'OutputSplitVintagesDict', + 'ProcessInputsByOutputDict', + 'ProcessInputsDict', + 'ProcessLoansDict', + 'ProcessOutputsByInputDict', + 'ProcessOutputsDict', + 'ProcessPeriodsDict', + 'ProcessReservePeriodsDict', + 'ProcessTechsDict', + 'ProcessVintagesDict', + 'RampDownVintagesDict', + 'RampUpVintagesDict', + 'RetirementPeriodsDict', + 'RetirementProductionProcessesDict', + 'SeasonalStorageDict', + 'SequentialToSeasonDict', + 'StorageVintagesDict', + 'SurvivalCurvePeriodsDict', + 'SurvivalCurveProcessDict', + 'TimeNextDict', + 'TimeNextSequentialDict', + # Index types + 'RegionPeriodSeasonTimeInputTechVintageOutput', + 'RegionPeriodTechVintage', + # Set types + 'CommodityBalancedSet', + 'ActiveActivitySet', + 'ActiveCapacityAvailableSet', + 'ActiveCapacityAvailableVintageSet', + 'ActiveCurtailmentSet', + 'ActiveFlexAnnualSet', + 'ActiveFlexSet', + 'ActiveFlowAnnualSet', + 'ActiveFlowInStorageSet', + 'ActiveFlowSet', + 'GroupRegionActiveFlowSet', + 'NewCapacitySet', + 'SeasonalStorageLevelIndicesSet', + 'StorageLevelIndicesSet', + # Type aliases + 'ExprLike', +] + +# Core type aliases for commonly used dimensions +# ruff: noqa: RUF022 +from .core_types import ( + Commodity, + CommoditySet, + Period, + Region, + RegionSet, + Season, + SparseIndex, + Technology, + TechSet, + TimeOfDay, + Vintage, +) + +# Dictionary types used by the model +# ruff: noqa: RUF022 +from .dict_types import ( + ActiveRegionsForTechDict, + BaseloadVintagesDict, + CapacityConsumptionTechsDict, + CapacityFactorProcessDict, + CommodityStreamProcessDict, + CurtailmentVintagesDict, + EfficiencyVariableDict, + ExportRegionsDict, + ImportRegionsDict, + InputSplitAnnualVintagesDict, + InputSplitVintagesDict, + OutputSplitAnnualVintagesDict, + OutputSplitVintagesDict, + ProcessInputsByOutputDict, + ProcessInputsDict, + ProcessLoansDict, + ProcessOutputsByInputDict, + ProcessOutputsDict, + ProcessPeriodsDict, + ProcessReservePeriodsDict, + ProcessTechsDict, + ProcessVintagesDict, + RampDownVintagesDict, + RampUpVintagesDict, + RetirementPeriodsDict, + RetirementProductionProcessesDict, + SeasonalStorageDict, + SequentialToSeasonDict, + StorageVintagesDict, + SurvivalCurvePeriodsDict, + SurvivalCurveProcessDict, + TimeNextDict, + TimeNextSequentialDict, +) + +# Index tuple types +# ruff: noqa: RUF022 +from .index_types import ( + RegionPeriodSeasonTimeInputTechVintageOutput, + RegionPeriodTechVintage, +) + +# Set types for sparse indexing +# ruff: noqa: RUF022 +from .set_types import ( + ActiveActivitySet, + ActiveCapacityAvailableSet, + ActiveCapacityAvailableVintageSet, + ActiveCurtailmentSet, + ActiveFlexAnnualSet, + ActiveFlexSet, + ActiveFlowAnnualSet, + ActiveFlowInStorageSet, + ActiveFlowSet, + CommodityBalancedSet, + GroupRegionActiveFlowSet, + NewCapacitySet, + SeasonalStorageLevelIndicesSet, + StorageLevelIndicesSet, +) + +# Type alias for expressions that can be returned from reserve margin functions +# This covers Pyomo expressions, boolean expressions, and Constraint.Skip +ExprLike = float | bool | object # covers Pyomo expressions and Constraint.Skip diff --git a/temoa/types/core_types.py b/temoa/types/core_types.py new file mode 100644 index 000000000..7d572bf01 --- /dev/null +++ b/temoa/types/core_types.py @@ -0,0 +1,143 @@ +""" +Core type aliases for Temoa energy model. + +This module contains basic type aliases for commonly used dimensions +and fundamental data structures. +""" + +from collections.abc import Callable +from dataclasses import dataclass, field +from typing import Any + +# Core type aliases for commonly used dimensions +Region = str +Period = int +Technology = str +Vintage = int +Season = str +TimeOfDay = str +Commodity = str +InputCommodity = str +OutputCommodity = str +Process = str + +# Type aliases for common data structures +SparseIndex = ( + tuple[Region, Period] + | tuple[Region, Period, Technology] + | tuple[Region, Period, Technology, Vintage] + | tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity] + | tuple[Any, ...] +) + +# Database-related types +DatabaseConnection = Any # sqlite3.Connection or similar +DatabaseCursor = Any # sqlite3.Cursor or similar +QueryResult = list[tuple[Any, ...]] + +# Model parameter types +ParameterValue = int | float | str | bool +Parameterdict = dict[SparseIndex, ParameterValue] + +# Basic set types +StringSet = set[str] +TechSet = set[Technology] +CommoditySet = set[Commodity] +RegionSet = set[Region] +PeriodSet = set[Period] +VintageSet = set[Vintage] + +# Pyomo domain types +PyomoDomain = Any # Pyomo domain objects (NonNegativeReals, Integers, etc.) +PyomoIndexSet = Any # Pyomo set objects used for indexing + +# Configuration types +ScenarioName = str +Configdict = dict[str, Any] + +# Enhanced Configuration Types +SolverName = str +"""Type alias for solver names (e.g., 'gurobi', 'cplex', 'glpk', 'cbc').""" + + +@dataclass(slots=True) +class ScenarioConfig: + """ + Structured configuration for scenario-specific settings. + + This type represents configuration options that are specific to a particular + scenario run, including solver settings, output options, and analysis modes. + """ + + scenario: str + """Name of the scenario.""" + + input_database: str + """Path to the input database file.""" + + output_database: str + """Path to the output database file.""" + + solver_name: SolverName + """Name of the solver to use.""" + + save_excel: bool + """Whether to save results to Excel format.""" + + save_duals: bool + """Whether to save dual variables.""" + + save_storage_levels: bool + """Whether to save storage level information.""" + + +@dataclass(slots=True) +class SolverConfig: + """ + Configuration for solver-specific settings. + + This type represents solver options and parameters that control + the optimization process. + """ + + solver_name: SolverName + """Name of the solver.""" + + options: dict[str, Any] = field(default_factory=dict) + """Solver-specific options dictionary.""" + + time_limit: float | None = None + """Maximum time limit for solving (in seconds).""" + + mip_gap: float | None = None + """MIP gap tolerance for mixed-integer problems.""" + + +@dataclass(slots=True) +class OutputConfig: + """ + Configuration for output format and content settings. + + This type represents options that control what results are saved + and in what format. + """ + + save_excel: bool + """Whether to save results to Excel format.""" + + save_duals: bool + """Whether to save dual variables.""" + + save_storage_levels: bool + """Whether to save storage level information.""" + + save_lp_file: bool + """Whether to save the LP file.""" + + output_path: str + """Path where output files should be saved.""" + + +# Constraint rule types +ConstraintRule = Callable[..., object] +IndexsetRule = Callable[..., set[object]] diff --git a/temoa/types/database_types.py b/temoa/types/database_types.py new file mode 100644 index 000000000..3374ab225 --- /dev/null +++ b/temoa/types/database_types.py @@ -0,0 +1,166 @@ +""" +Database schema type definitions for Temoa energy model. + +This module provides type definitions for database tables, columns, and schema +versioning used throughout the Temoa codebase. +""" + +from collections.abc import Mapping, Sequence +from typing import Protocol + +# Type aliases for database schema elements +TableName = str +"""Type alias for database table names.""" + +ColumnName = str +"""Type alias for database column names.""" + +SchemaVersion = tuple[int, int] +"""Type alias for schema version (major, minor).""" + + +class DatabaseSchema(Protocol): + """ + Protocol defining the interface for database schema objects. + + This protocol describes the expected structure of database schema + information, allowing for type-safe access to schema metadata. + """ + + version: SchemaVersion + """Schema version as (major, minor) tuple.""" + + tables: Mapping[TableName, Sequence[ColumnName]] + """Mapping of table names to their column names.""" + + def get_table_columns(self, table: TableName) -> Sequence[ColumnName]: + """ + Get the list of columns for a given table. + + Args: + table: Name of the table + + Returns: + Sequence of column names for the table + """ + ... + + def validate_table(self, table: TableName) -> bool: + """ + Validate that a table exists in the schema. + + Args: + table: Name of the table to validate + + Returns: + True if table exists, False otherwise + """ + ... + + +# Common table row types for major Temoa tables +class TechnologyRow(Protocol): + """Protocol for Technology table rows.""" + + region: str + tech: str + flag: str + sector: str + tech_desc: str | None + + +class CommodityRow(Protocol): + """Protocol for Commodity table rows.""" + + region: str + comm_name: str + flag: str + comm_desc: str | None + + +class TimePeriodsRow(Protocol): + """Protocol for TimePeriods table rows.""" + + t_periods: int + flag: str + + +class EfficiencyRow(Protocol): + """Protocol for Efficiency table rows.""" + + region: str + input_comm: str + tech: str + vintage: int + output_comm: str + efficiency: float + eff_notes: str | None + + +class CapacityFactorRow(Protocol): + """Protocol for CapacityFactor table rows.""" + + region: str + season: str + time_of_day: str + tech: str + vintage: int + cf_process: float + cf_process_notes: str | None + + +class DemandRow(Protocol): + """Protocol for Demand table rows.""" + + region: str + periods: int + demand_comm: str + demand: float + demand_units: str + demand_notes: str | None + + +class EmissionActivityRow(Protocol): + """Protocol for EmissionActivity table rows.""" + + region: str + emis_comm: str + input_comm: str + tech: str + vintage: int + output_comm: str + emis_act: float + emis_act_units: str + emis_act_notes: str | None + + +# Query result types +TechnologyQueryResult = Sequence[Mapping[str, object]] +"""Type alias for technology query results.""" +CommodityQueryResult = Sequence[Mapping[str, object]] +"""Type alias for commodity query results.""" +EfficiencyQueryResult = Sequence[Mapping[str, object]] +"""Type alias for efficiency query results.""" +GenericQueryResult = Sequence[Mapping[str, object]] +"""Type alias for generic query results.""" + + +# Export all types +# ruff: noqa: RUF022 +__all__ = [ + 'TableName', + 'ColumnName', + 'SchemaVersion', + 'DatabaseSchema', + 'TechnologyRow', + 'CommodityRow', + 'TimePeriodsRow', + 'EfficiencyRow', + 'CapacityFactorRow', + 'DemandRow', + 'EmissionActivityRow', + 'TechnologyQueryResult', + 'CommodityQueryResult', + 'EfficiencyQueryResult', + 'GenericQueryResult', +] diff --git a/temoa/types/dict_types.py b/temoa/types/dict_types.py new file mode 100644 index 000000000..d725e14d0 --- /dev/null +++ b/temoa/types/dict_types.py @@ -0,0 +1,113 @@ +""" +Dictionary types for Temoa energy model. + +This module contains dictionary type definitions used throughout +the Temoa model for various data structures and mappings. +""" + +from .core_types import Commodity, Period, Region, Season, Technology, TimeOfDay, Vintage + +# Process-related dictionary types +ProcessInputsdict = dict[tuple[Region, Period, Technology, Vintage], set[Commodity]] +ProcessOutputsdict = dict[tuple[Region, Period, Technology, Vintage], set[Commodity]] +ProcessLoansdict = dict[tuple[Region, Technology, Vintage], float] +ProcessInputsByOutputdict = dict[ + tuple[Region, Period, Technology, Vintage, Commodity], set[Commodity] +] +ProcessOutputsByInputdict = dict[ + tuple[Region, Period, Technology, Vintage, Commodity], set[Commodity] +] +ProcessTechsdict = dict[tuple[Region, Period, Commodity], set[Technology]] +ProcessReservePeriodsdict = dict[tuple[Region, Period], set[tuple[Technology, Vintage]]] +ProcessPeriodsdict = dict[tuple[Region, Technology, Vintage], set[Period]] +RetirementPeriodsdict = dict[tuple[Region, Technology, Vintage], set[Period]] +ProcessVintagesdict = dict[tuple[Region, Period, Technology], set[Vintage]] +SurvivalCurvePeriodsdict = dict[tuple[Region, Technology, Vintage], set[Period]] +CapacityConsumptionTechsdict = dict[tuple[Region, Period, Commodity], set[Technology]] +RetirementProductionProcessesdict = dict[ + tuple[Region, Period, Commodity], set[tuple[Technology, Vintage]] +] + +# Capitalized aliases for compatibility +ProcessInputsDict = ProcessInputsdict +ProcessOutputsDict = ProcessOutputsdict +ProcessLoansDict = ProcessLoansdict +ProcessInputsByOutputDict = ProcessInputsByOutputdict +ProcessOutputsByInputDict = ProcessOutputsByInputdict +ProcessTechsDict = ProcessTechsdict +ProcessReservePeriodsDict = ProcessReservePeriodsdict +ProcessPeriodsDict = ProcessPeriodsdict +RetirementPeriodsDict = RetirementPeriodsdict +ProcessVintagesDict = ProcessVintagesdict +SurvivalCurvePeriodsDict = SurvivalCurvePeriodsdict +CapacityConsumptionTechsDict = CapacityConsumptionTechsdict +RetirementProductionProcessesDict = RetirementProductionProcessesdict + +# Commodity flow dictionary types +CommodityStreamProcessdict = dict[tuple[Region, Period, Commodity], set[tuple[Technology, Vintage]]] + + +# Capitalized aliases for compatibility +CommodityStreamProcessDict = CommodityStreamProcessdict + +# Technology classification dictionary types +BaseloadVintagesdict = dict[tuple[Region, Period, Technology], set[Vintage]] +CurtailmentVintagesdict = dict[tuple[Region, Period, Technology], set[Vintage]] +StorageVintagesdict = dict[tuple[Region, Period, Technology], set[Vintage]] +RampUpVintagesdict = dict[tuple[Region, Period, Technology], set[Vintage]] +RampDownVintagesdict = dict[tuple[Region, Period, Technology], set[Vintage]] +InputSplitVintagesdict = dict[tuple[Region, Period, Commodity, Technology, str], set[Vintage]] +InputSplitAnnualVintagesdict = dict[tuple[Region, Period, Commodity, Technology, str], set[Vintage]] +OutputSplitVintagesdict = dict[tuple[Region, Period, Technology, Commodity, str], set[Vintage]] +OutputSplitAnnualVintagesdict = dict[ + tuple[Region, Period, Technology, Commodity, str], set[Vintage] +] + +# Capitalized aliases for compatibility +BaseloadVintagesDict = BaseloadVintagesdict +CurtailmentVintagesDict = CurtailmentVintagesdict +StorageVintagesDict = StorageVintagesdict +RampUpVintagesDict = RampUpVintagesdict +RampDownVintagesDict = RampDownVintagesdict +InputSplitVintagesDict = InputSplitVintagesdict +InputSplitAnnualVintagesDict = InputSplitAnnualVintagesdict +OutputSplitVintagesDict = OutputSplitVintagesdict +OutputSplitAnnualVintagesDict = OutputSplitAnnualVintagesdict + +# Time sequencing dictionary types +TimeNextdict = dict[tuple[Period, Season, TimeOfDay], tuple[Season, TimeOfDay]] +TimeNextSequentialdict = dict[tuple[Period, Season], Season] +SequentialToSeasondict = dict[tuple[Period, Season], Season] + +# Capitalized aliases for compatibility +TimeNextDict = TimeNextdict +TimeNextSequentialDict = TimeNextSequentialdict +SequentialToSeasonDict = SequentialToSeasondict + +# Geography/exchange dictionary types +ExportRegionsdict = dict[ + tuple[Region, Period, Commodity], set[tuple[Region, Technology, Vintage, Commodity]] +] +ImportRegionsdict = dict[ + tuple[Region, Period, Commodity], set[tuple[Region, Technology, Vintage, Commodity]] +] +ActiveRegionsForTechdict = dict[tuple[Period, Technology], set[Region]] + +# Capitalized aliases for compatibility +ExportRegionsDict = ExportRegionsdict +ImportRegionsDict = ImportRegionsdict +ActiveRegionsForTechDict = ActiveRegionsForTechdict + +# Switching/boolean flag dictionary types +EfficiencyVariabledict = dict[ + tuple[Region, Period, Commodity, Technology, Vintage, Commodity], bool +] +CapacityFactorProcessdict = dict[tuple[Region, Period, Technology, Vintage], bool] +SeasonalStoragedict = dict[Technology, bool] +SurvivalCurveProcessdict = dict[tuple[Region, Technology, Vintage], bool] + +# Capitalized aliases for compatibility +EfficiencyVariableDict = EfficiencyVariabledict +CapacityFactorProcessDict = CapacityFactorProcessdict +SeasonalStorageDict = SeasonalStoragedict +SurvivalCurveProcessDict = SurvivalCurveProcessdict diff --git a/temoa/types/index_types.py b/temoa/types/index_types.py new file mode 100644 index 000000000..74fb0666e --- /dev/null +++ b/temoa/types/index_types.py @@ -0,0 +1,35 @@ +""" +Index tuple types for Temoa energy model. + +This module contains tuple type definitions used for indexing +various data structures in the Temoa model. +""" + +from .core_types import Commodity, Period, Region, Season, Technology, TimeOfDay, Vintage + +# Basic index tuples +RegionPeriod = tuple[Region, Period] +RegionPeriodTech = tuple[Region, Period, Technology] +RegionPeriodTechVintage = tuple[Region, Period, Technology, Vintage] +RegionPeriodSeasonTimeInputTechVintageOutput = tuple[ + Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity +] + +# Extended index types +RegionTech = tuple[Region, Technology] +RegionTechVintage = tuple[Region, Technology, Vintage] +RegionPeriodCommodity = tuple[Region, Period, Commodity] +PeriodSeasonTimeOfDay = tuple[Period, Season, TimeOfDay] +RegionPeriodSeasonTimeOfDay = tuple[Region, Period, Season, TimeOfDay] +RegionPeriodSeasonTimeOfDayTech = tuple[Region, Period, Season, TimeOfDay, Technology] +RegionPeriodSeasonTimeOfDayTechVintage = tuple[ + Region, Period, Season, TimeOfDay, Technology, Vintage +] +RegionPeriodSeasonTimeOfDayCommodity = tuple[Region, Period, Season, TimeOfDay, Commodity] +RegionPeriodCommodityInputTechVintageOutput = tuple[ + Region, Period, Commodity, Technology, Vintage, Commodity +] +RegionPeriodSeasonTimeOfDayCommodityTechVintageOutput = tuple[ + Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity +] +PeriodSeasonSequential = tuple[Period, Season] diff --git a/temoa/types/model_types.py b/temoa/types/model_types.py new file mode 100644 index 000000000..ed6dbea1b --- /dev/null +++ b/temoa/types/model_types.py @@ -0,0 +1,345 @@ +""" +Type definitions for TemoaModel and related core classes. + +This module provides comprehensive type annotations for the core Temoa model, +including the main TemoaModel class and its associated data structures. +""" + +from enum import Enum, unique +from typing import ( + TYPE_CHECKING, + Any, + NamedTuple, + Protocol, + runtime_checkable, +) + +from . import ( + Commodity, + CommoditySet, + Period, + Region, + RegionPeriodSeasonTimeInputTechVintageOutput, + RegionPeriodTechVintage, + RegionSet, + Season, + SparseIndex, + Technology, + TechSet, + TimeOfDay, + Vintage, +) + +# Import Pyomo stub types +if TYPE_CHECKING: + from pyomo.core import ( + AbstractModel, + BuildAction, + Constraint, + Objective, + Param, + Set, + Var, + ) +else: + # Runtime fallback for non-TYPE_CHECKING contexts + Set = Any # AbstractModel.set + Param = Any # AbstractModel.Param + Var = Any # AbstractModel.Var + Constraint = Any # AbstractModel.Constraint + BuildAction = Any # AbstractModel.BuildAction + Objective = Any # AbstractModel.Objective + +# Type aliases for model data structures +ProcessInputs = dict[tuple[Region, Period, Commodity, Technology, Vintage, Commodity], float] +ProcessOutputs = dict[tuple[Region, Period, Commodity, Technology, Vintage, Commodity], float] +TechClassification = dict[Technology, str] +SparseDict = dict[SparseIndex, set[SparseIndex]] +# Model sets type definitions (avoiding naming conflicts with set import) +TimesetTyped = set[Period] +RegionsetTyped = set[Region] +TechsetTyped = set[Technology] +CommoditysetTyped = set[Commodity] +VintagesetTyped = set[Vintage] + +# Model parameters type definitions +EfficiencyParam = Param # Multi-dimensional efficiency parameter +CostParam = Param # Cost parameters (investment, fixed, variable) +CapacityParam = Param # Capacity-related parameters +EmissionParam = Param # Emission parameters + +# Model variables type definitions +if TYPE_CHECKING: + FlowVar = Var # Flow variables + CapacityVar = Var # Capacity variables + CostVar = Var # Cost variables + + # Model constraints type definitions + FlowConstraint = Constraint # Flow balance constraints + CapacityConstraint = Constraint # Capacity constraints + CostConstraint = Constraint # Cost accounting constraints +else: + # Runtime fallback + FlowVar = Any # Flow variables + CapacityVar = Any # Capacity variables + CostVar = Any # Cost variables + FlowConstraint = Any # Flow balance constraints + CapacityConstraint = Any # Capacity constraints + CostConstraint = Any # Cost accounting constraints + + +@runtime_checkable +class TemoaModelProtocol(Protocol): + """Protocol defining the interface for TemoaModel instances.""" + + # Core identification + name: str + + # Time-related sets + time_exist: Set + time_future: Set + time_optimize: Set + vintage_exist: Set + vintage_optimize: Set + time_season: Set + time_of_day: Set + + # Geography sets + regions: Set + regionalIndices: Set + + # Technology sets + tech_all: Set + tech_production: Set + tech_storage: Set + tech_reserve: Set + tech_exchange: Set + + # Commodity sets + commodity_all: Set + commodity_demand: Set + commodity_physical: Set + commodity_emissions: Set + + # Model parameters + GlobalDiscountRate: Param + Demand: Param + Efficiency: Param + ExistingCapacity: Param + CapacityToActivity: Param + + # Model variables + V_FlowOut: Var + V_Capacity: Var + V_NewCapacity: Var + + # Model constraints + DemandConstraint: Constraint + CommodityBalanceConstraint: Constraint + CapacityConstraint: Constraint + + # Internal data structures + processInputs: ProcessInputs + processOutputs: ProcessOutputs + activeFlow_rpsditvo: set[RegionPeriodSeasonTimeInputTechVintageOutput] | None + activeActivity_rptv: set[RegionPeriodTechVintage] | None + + def __init__(self, *args: object, **kwargs: object) -> None: ... + + +if TYPE_CHECKING: + + class TemoaModel(AbstractModel): + """ + Type stub for the main TemoaModel class. + + This provides type information for the core Temoa energy model. + """ + + # Class attributes + default_lifetime_tech: int + + # Time-related sets + time_exist: Set + time_future: Set + time_optimize: Set + vintage_exist: Set + vintage_optimize: Set + vintage_all: Set + time_season: Set + time_of_day: Set + + # Geography sets + regions: Set + regionalIndices: Set + regionalGlobalIndices: Set + + # Technology sets + tech_all: Set + tech_production: Set + tech_baseload: Set + tech_annual: Set + tech_storage: Set + tech_reserve: Set + tech_exchange: Set + tech_uncap: Set + tech_with_capacity: Set + tech_retirement: Set + + # Commodity sets + commodity_all: Set + commodity_demand: Set + commodity_physical: Set + commodity_emissions: Set + commodity_carrier: Set + + # Model parameters + GlobalDiscountRate: Param + PeriodLength: Param + SegFrac: Param + Demand: Param + Efficiency: Param + ExistingCapacity: Param + CapacityToActivity: Param + CostInvest: Param + CostFixed: Param + CostVariable: Param + + # Model variables + V_FlowOut: Var + V_Capacity: Var + V_NewCapacity: Var + V_RetiredCapacity: Var + + # Model constraints + DemandConstraint: Constraint + CommodityBalanceConstraint: Constraint + CapacityConstraint: Constraint + + # Internal tracking dictionaries + processInputs: ProcessInputs + processOutputs: ProcessOutputs + used_techs: TechSet + activeFlow_rpsditvo: set[RegionPeriodSeasonTimeInputTechVintageOutput] + activeActivity_rptv: set[RegionPeriodTechVintage] + + def __init__(self, *args: object, **kwargs: object) -> None: ... + + +else: + # Runtime alias for TemoaModel when not TYPE_CHECKING + TemoaModel = Any + + +class EI(NamedTuple): + """Emission Index""" + + r: Region + p: Period + t: Technology + v: Vintage + e: Commodity + + +class FI(NamedTuple): + """Flow Index""" + + r: Region + p: Period + s: Season + d: TimeOfDay + i: Commodity + t: Technology + v: Vintage + o: Commodity + + +class SLI(NamedTuple): + """Storage Level Index""" + + r: Region + p: Period + s: Season + d: TimeOfDay + t: Technology + v: Vintage + + +class CapData(NamedTuple): + """Capacity Data Container""" + + built: Any + net: Any + retired: Any + + +@unique +class FlowType(Enum): + """Types of flow tracked""" + + IN = 1 + OUT = 2 + CURTAIL = 3 + FLEX = 4 + LOST = 5 + + +# Data structure types for model processing +class ModelData: + """Container for model data and metadata.""" + + def __init__( + self, + regions: RegionSet, + periods: set[Period], + technologies: TechSet, + commodities: CommoditySet, + **kwargs: object, + ) -> None: ... + + +# Export types for easy importing +# ruff: noqa: RUF022 +__all__ = [ + # Protocols + 'TemoaModelProtocol', + # Core classes + 'TemoaModel', + # Data structures + 'ModelData', + 'ProcessInputs', + 'ProcessOutputs', + 'TechClassification', + 'SparseDict', + # Named tuples for indexing + 'EI', + 'FI', + 'SLI', + 'CapData', + # Enums + 'FlowType', + # Typed set aliases + 'TimesetTyped', + 'RegionsetTyped', + 'TechsetTyped', + 'CommoditysetTyped', + 'VintagesetTyped', + # Pyomo type aliases + 'Set', + 'Param', + 'Var', + 'Constraint', + # Parameter types + 'EfficiencyParam', + 'CostParam', + 'CapacityParam', + 'EmissionParam', + # Variable types + 'FlowVar', + 'CapacityVar', + 'CostVar', + # Constraint types + 'FlowConstraint', + 'CapacityConstraint', + 'CostConstraint', +] diff --git a/temoa/types/set_types.py b/temoa/types/set_types.py new file mode 100644 index 000000000..b83eebb92 --- /dev/null +++ b/temoa/types/set_types.py @@ -0,0 +1,57 @@ +""" +Set types for Temoa energy model. + +This module contains set type definitions used for sparse indexing +and various collections in the Temoa model. +""" + +from typing import Optional + +from .core_types import Commodity, Period, Region, Season, Technology, TimeOfDay, Vintage + +# Set types for sparse indexing +ActiveFlowset = Optional[ + set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] +] +ActiveFlowAnnualset = Optional[ + set[tuple[Region, Period, Commodity, Technology, Vintage, Commodity]] +] +ActiveFlexset = Optional[ + set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] +] +ActiveFlexAnnualset = Optional[ + set[tuple[Region, Period, Commodity, Technology, Vintage, Commodity]] +] +ActiveFlowInStorageset = Optional[ + set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] +] +ActiveCurtailmentset = Optional[ + set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] +] +ActiveActivityset = Optional[set[tuple[Region, Period, Technology, Vintage]]] +StorageLevelIndicesset = Optional[ + set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]] +] +SeasonalStorageLevelIndicesset = Optional[set[tuple[Region, Period, Season, Technology, Vintage]]] +NewCapacityset = Optional[set[tuple[Region, Technology, Vintage]]] +ActiveCapacityAvailableset = Optional[set[tuple[Region, Period, Technology]]] +ActiveCapacityAvailableVintageset = Optional[set[tuple[Region, Period, Technology, Vintage]]] +GroupRegionActiveFlowset = Optional[set[tuple[Region, Period, Technology]]] + +CommodityBalancedSet = set[tuple[Region, Period, Commodity]] + + +# Capitalized aliases for compatibility +ActiveFlowSet = ActiveFlowset +ActiveFlowAnnualSet = ActiveFlowAnnualset +ActiveFlexSet = ActiveFlexset +ActiveFlexAnnualSet = ActiveFlexAnnualset +ActiveFlowInStorageSet = ActiveFlowInStorageset +ActiveCurtailmentSet = ActiveCurtailmentset +ActiveActivitySet = ActiveActivityset +StorageLevelIndicesSet = StorageLevelIndicesset +SeasonalStorageLevelIndicesSet = SeasonalStorageLevelIndicesset +NewCapacitySet = NewCapacityset +ActiveCapacityAvailableSet = ActiveCapacityAvailableset +ActiveCapacityAvailableVintageSet = ActiveCapacityAvailableVintageset +GroupRegionActiveFlowSet = GroupRegionActiveFlowset diff --git a/temoa/types/solver_types.py b/temoa/types/solver_types.py new file mode 100644 index 000000000..0b6e968d3 --- /dev/null +++ b/temoa/types/solver_types.py @@ -0,0 +1,99 @@ +""" +Solver-related type definitions for Temoa energy model. + +This module provides type definitions for solver results, status, and termination +conditions used throughout the Temoa codebase. +""" + +from collections.abc import Mapping +from enum import Enum +from typing import TYPE_CHECKING, Any, Protocol + +if TYPE_CHECKING: + from pyomo.opt.results import SolverResults, SolverStatus, TerminationCondition +else: + # Runtime fallbacks + PyomoSolverResults = Any + PyomoSolverStatus = Any + PyomoTerminationCondition = Any + + +class SolverStatusEnum(str, Enum): + """ + Enumeration of possible solver status values. + + These represent the high-level status of the solver after attempting to solve. + """ + + OK = 'ok' + WARNING = 'warning' + ERROR = 'error' + ABORTED = 'aborted' + UNKNOWN = 'unknown' + + +class TerminationConditionEnum(int, Enum): + """ + Enumeration of possible solver termination conditions. + + These represent the specific reason why the solver terminated. + Updated to match Pyomo 6.9.2 integer-based enum values. + """ + + convergenceCriteriaSatisfied = 0 + maxTimeLimit = 1 + iterationLimit = 2 + objectiveLimit = 3 + minStepLength = 4 + unbounded = 5 + provenInfeasible = 6 + locallyInfeasible = 7 + infeasibleOrUnbounded = 8 + error = 9 + interrupted = 10 + licensingProblems = 11 + emptyModel = 12 + unknown = 42 + + +class SolverResultsProtocol(Protocol): + """ + Protocol defining the interface for solver results objects. + + This protocol describes the expected structure of solver results returned + by Pyomo solvers, allowing for type-safe access to solver information. + """ + + solver: object + """Solver information and statistics.""" + + def __getitem__(self, key: str) -> object: + """Access result components by key (e.g., 'Solution', 'Problem').""" + ... + + +# Type aliases for solver-related types +SolverResults = SolverResults +"""Type alias for Pyomo SolverResults objects.""" + +SolverStatus = SolverStatus +"""Type alias for Pyomo SolverStatus enum.""" + +TerminationCondition = TerminationCondition +"""Type alias for Pyomo TerminationCondition enum.""" + +SolverOptions = Mapping[str, object] +"""Type alias for solver option dictionaries.""" + + +# Export all types +# ruff: noqa: RUF022 +__all__ = [ + 'SolverStatusEnum', + 'TerminationConditionEnum', + 'SolverResultsProtocol', + 'SolverResults', + 'SolverStatus', + 'TerminationCondition', + 'SolverOptions', +] diff --git a/temoa/types/validation_types.py b/temoa/types/validation_types.py new file mode 100644 index 000000000..3db057dc0 --- /dev/null +++ b/temoa/types/validation_types.py @@ -0,0 +1,237 @@ +""" +Validation result type definitions for Temoa energy model. + +This module provides type definitions for validation results, errors, and warnings +used in model checking and data validation throughout the Temoa codebase. +""" + +from dataclasses import dataclass +from enum import Enum +from typing import Any + + +class ValidationSeverity(str, Enum): + """ + Enumeration of validation message severity levels. + + These represent the severity of validation issues found during + model checking and data validation. + """ + + ERROR = 'error' + """Critical error that prevents model execution.""" + + WARNING = 'warning' + """Non-critical issue that may affect results.""" + + INFO = 'info' + """Informational message about model structure.""" + + +@dataclass(slots=True) +class ValidationError: + """ + Represents a validation error or warning. + + This dataclass encapsulates information about a validation issue, + including its severity, message, and location in the model. + + Attributes: + severity: The severity level of the validation issue + message: Human-readable description of the issue + location: Optional location information (e.g., file, line, component) + context: Optional additional context about the issue (e.g., {'variable': 'x', 'expected': 10, 'actual': 5}) + """ + + severity: ValidationSeverity + message: str + location: str | None = None + context: dict[str, Any] | None = None + + def __str__(self) -> str: + """Return a formatted string representation of the validation error.""" + parts = [f'[{self.severity.value.upper()}]', self.message] + if self.location: + parts.append(f'at {self.location}') + return ' '.join(parts) + + +@dataclass(slots=True) +class ValidationWarning: + """ + Represents a validation warning. + + This is a convenience type for warnings, which are non-critical validation + issues that don't prevent model execution but may affect results. + + Attributes: + message: Human-readable description of the warning + location: Optional location information + context: Optional additional context + """ + + message: str + location: str | None = None + context: dict[str, Any] | None = None + + def to_validation_error(self) -> ValidationError: + """Convert this warning to a ValidationError with WARNING severity.""" + return ValidationError( + severity=ValidationSeverity.WARNING, + message=self.message, + location=self.location, + context=self.context, + ) + + def __str__(self) -> str: + """Return a formatted string representation of the validation warning.""" + parts = ['[WARNING]', self.message] + if self.location: + parts.append(f'at {self.location}') + return ' '.join(parts) + + +@dataclass(slots=True) +class ValidationResult: + """ + Represents the complete result of a validation operation. + + This dataclass aggregates all validation errors and warnings found + during a validation operation, along with summary information. + + Attributes: + errors: List of validation errors found + warnings: List of validation warnings found + is_valid: Whether the validation passed (no errors) + summary: Optional summary message + """ + + errors: list[ValidationError] + warnings: list[ValidationWarning] + is_valid: bool + summary: str | None = None + + @classmethod + def create_success(cls, summary: str | None = None) -> 'ValidationResult': + """ + Create a successful validation result with no errors or warnings. + + Args: + summary: Optional summary message + + Returns: + ValidationResult indicating success + """ + return cls(errors=[], warnings=[], is_valid=True, summary=summary) + + @classmethod + def create_failure( + cls, + errors: list[ValidationError], + warnings: list[ValidationWarning] | None = None, + summary: str | None = None, + ) -> 'ValidationResult': + """ + Create a failed validation result with errors. + + Args: + errors: List of validation errors + warnings: Optional list of validation warnings + summary: Optional summary message + + Returns: + ValidationResult indicating failure + """ + if not errors: + raise ValueError('Failure result must contain at least one error') + return cls( + errors=errors, + warnings=warnings or [], + is_valid=False, + summary=summary, + ) + + def add_error( + self, + message: str, + location: str | None = None, + context: dict[str, Any] | None = None, + ) -> None: + """ + Add an error to this validation result. + + Args: + message: Error message + location: Optional location information + context: Optional additional context + """ + self.errors.append( + ValidationError( + severity=ValidationSeverity.ERROR, + message=message, + location=location, + context=context, + ) + ) + self.is_valid = False + + def add_warning( + self, + message: str, + location: str | None = None, + context: dict[str, Any] | None = None, + ) -> None: + """ + Add a warning to this validation result. + + Args: + message: Warning message + location: Optional location information + context: Optional additional context + """ + self.warnings.append(ValidationWarning(message=message, location=location, context=context)) + + def has_errors(self) -> bool: + """Check if this result contains any errors.""" + return bool(self.errors) + + def has_warnings(self) -> bool: + """Check if this result contains any warnings.""" + return bool(self.warnings) + + def error_count(self) -> int: + """Get the number of errors in this result.""" + return len(self.errors) + + def warning_count(self) -> int: + """Get the number of warnings in this result.""" + return len(self.warnings) + + def __str__(self) -> str: + """Return a formatted string representation of the validation result.""" + lines = [] + if self.summary: + lines.append(self.summary) + lines.append( + f'Validation {"PASSED" if self.is_valid else "FAILED"}: ' + f'{self.error_count()} errors, {self.warning_count()} warnings' + ) + if self.errors: + lines.append('\nErrors:') + for error in self.errors: + lines.append(f' {error}') + if self.warnings: + lines.append('\nWarnings:') + for warning in self.warnings: + lines.append(f' {warning}') + return '\n'.join(lines) + + +# Export all types +# ruff: noqa: RUF022 +__all__ = [ + 'ValidationSeverity', + 'ValidationError', + 'ValidationWarning', + 'ValidationResult', +] From d899da8af20e456f2c7942c49fca21fd5b0bf18e Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 18 Oct 2025 19:02:43 -0400 Subject: [PATCH 246/587] adding typing to temoa/_internal files --- temoa/_internal/__init__.py | 2 +- temoa/_internal/data_brick.py | 55 ++---- temoa/_internal/exchange_tech_cost_ledger.py | 50 ++--- temoa/_internal/run_actions.py | 42 ++-- temoa/_internal/table_data_puller.py | 198 +++++++++---------- temoa/_internal/table_writer.py | 138 +++++++++---- temoa/_internal/temoa_sequencer.py | 16 +- 7 files changed, 265 insertions(+), 236 deletions(-) diff --git a/temoa/_internal/__init__.py b/temoa/_internal/__init__.py index b70e096bb..eb59f677d 100644 --- a/temoa/_internal/__init__.py +++ b/temoa/_internal/__init__.py @@ -5,4 +5,4 @@ These modules are not part of the public API and may change without notice. """ -__all__ = [] +__all__: list[str] = [] diff --git a/temoa/_internal/data_brick.py b/temoa/_internal/data_brick.py index a4fd9e80f..312521a8a 100644 --- a/temoa/_internal/data_brick.py +++ b/temoa/_internal/data_brick.py @@ -1,29 +1,4 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 12/5/24 - Objective of this module is to build a lightweight container to hold a selection of model results from a Worker process with the intent to send this back via multiprocessing queue in lieu of sending the entire model back (which is giant and slow). It will probably be a "superset" of data elements required to report @@ -31,9 +6,8 @@ """ +from temoa._internal.exchange_tech_cost_ledger import CostType from temoa._internal.table_data_puller import ( - EI, - CapData, poll_capacity_results, poll_cost_results, poll_emissions, @@ -41,6 +15,7 @@ poll_objective, ) from temoa.core.model import TemoaModel +from temoa.types.model_types import EI, FI, CapData, FlowType class DataBrick: @@ -50,14 +25,14 @@ class DataBrick: def __init__( self, - name, - emission_costs, - emission_flows, - capacity_data, - flow_data, - obj_data, - regular_costs, - exchange_costs, + name: str, + emission_costs: dict[tuple[str, int, str, int], dict[CostType, float]], + emission_flows: dict[EI, float], + capacity_data: CapData, + flow_data: dict[FI, dict[FlowType, float]], + obj_data: list[tuple[str, float]], + regular_costs: dict[tuple[str, int, str, int], dict[CostType, float]], + exchange_costs: dict[tuple[str, int, str, int], dict[CostType, float]], ): self._name = name self._emission_costs = emission_costs @@ -81,23 +56,23 @@ def capacity_data(self) -> CapData: return self._capacity_data @property - def flow_data(self) -> dict: + def flow_data(self) -> dict[FI, dict[FlowType, float]]: return self._flow_data @property - def obj_data(self) -> list: + def obj_data(self) -> list[tuple[str, float]]: return self._obj_data @property - def cost_data(self): + def cost_data(self) -> dict[tuple[str, int, str, int], dict[CostType, float]]: return self._regular_costs @property - def exchange_cost_data(self): + def exchange_cost_data(self) -> dict[tuple[str, int, str, int], dict[CostType, float]]: return self._exchange_costs @property - def emission_cost_data(self): + def emission_cost_data(self) -> dict[tuple[str, int, str, int], dict[CostType, float]]: return self._emission_costs diff --git a/temoa/_internal/exchange_tech_cost_ledger.py b/temoa/_internal/exchange_tech_cost_ledger.py index 60dd241e2..5277e3d24 100644 --- a/temoa/_internal/exchange_tech_cost_ledger.py +++ b/temoa/_internal/exchange_tech_cost_ledger.py @@ -1,28 +1,4 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 4/1/24 The purpose of this module is to provide a ledger for all costs for exchange techs. The main reason for the need is that in many cases, the costs need to be apportioned by use ratio so it is helpful to @@ -32,12 +8,14 @@ from collections import defaultdict from enum import Enum, unique -from typing import Union +from typing import TYPE_CHECKING, Union, cast from pyomo.common.numeric_types import value from temoa.core.model import TemoaModel -from tests.utilities.namespace_mock import Namespace + +if TYPE_CHECKING: + from tests.utilities.namespace_mock import Namespace @unique @@ -54,11 +32,15 @@ class CostType(Enum): class ExchangeTechCostLedger: def __init__(self, M: Union[TemoaModel, 'Namespace']) -> None: - self.cost_records: dict[CostType, dict] = defaultdict(dict) + self.cost_records: dict[CostType, dict[tuple[str, str, str, int, int], float]] = ( + defaultdict(dict) + ) # could be a Namespace for testing purposes... See the related test self.M = M - def add_cost_record(self, link: str, period, tech, vintage, cost: float, cost_type: CostType): + def add_cost_record( + self, link: str, period: int, tech: str, vintage: int, cost: float, cost_type: CostType + ) -> None: """ add a cost associated with an exchange tech :return: @@ -69,7 +51,9 @@ def add_cost_record(self, link: str, period, tech, vintage, cost: float, cost_ty # add to the "seen" records for appropriate cost type self.cost_records[cost_type][r1, r2, tech, vintage, period] = cost - def get_use_ratio(self, exporter, importer, period, tech, vintage) -> float: + def get_use_ratio( + self, exporter: str, importer: str, period: int, tech: str, vintage: int + ) -> float: """ use flow to calculate the use ratio for these 2 entities for cost apportioning purposes :param exporter: @@ -79,7 +63,9 @@ def get_use_ratio(self, exporter, importer, period, tech, vintage) -> float: :param vintage: :return: the proportion to assign to the IMPORTER, or 0.5 if no usage """ - M = self.M + # Cast to TemoaModel for type checking - at runtime this will be either TemoaModel or Namespace + # Both have the same attributes, but mypy doesn't know about Namespace's dynamic attributes + M = cast(TemoaModel, self.M) # need to temporarily reconstitute the names rr1 = '-'.join([exporter, importer]) rr2 = '-'.join([importer, exporter]) @@ -130,8 +116,8 @@ def get_use_ratio(self, exporter, importer, period, tech, vintage) -> float: return act_dir1 / (act_dir1 + act_dir2) return 0.5 - def get_entries(self) -> dict: - region_costs = defaultdict(dict) + def get_entries(self) -> dict[tuple[str, int, str, int], dict[CostType, float]]: + region_costs: dict[tuple[str, int, str, int], dict[CostType, float]] = defaultdict(dict) # iterate through each region pairing, pull the cost records and decide if/how to split each one for cost_type in self.cost_records: # make a copy, this will be destructive operation diff --git a/temoa/_internal/run_actions.py b/temoa/_internal/run_actions.py index 64242d73f..188ee9651 100644 --- a/temoa/_internal/run_actions.py +++ b/temoa/_internal/run_actions.py @@ -34,7 +34,6 @@ from sys import stderr as SE from sys import version_info from time import time -from typing import Tuple from pyomo.environ import ( Constraint, @@ -57,7 +56,7 @@ logger = getLogger(__name__) -def check_python_version(min_major, min_minor) -> bool: +def check_python_version(min_major: int, min_minor: int) -> bool: if (min_major, min_minor) >= version_info: logger.error( 'Model is being run with python %d.%d. Expecting version %d.%d or later. ', @@ -70,7 +69,7 @@ def check_python_version(min_major, min_minor) -> bool: return True -def check_database_version(config: TemoaConfig, db_major_reqd: int, min_db_minor) -> bool: +def check_database_version(config: TemoaConfig, db_major_reqd: int, min_db_minor: int) -> bool: """ check the db version :param config: TemoaConfig instance @@ -130,10 +129,10 @@ def check_database_version(config: TemoaConfig, db_major_reqd: int, min_db_minor def build_instance( loaded_portal: DataPortal, - model_name=None, - silent=False, - keep_lp_file=False, - lp_path: Path = None, + model_name: str | None = None, + silent: bool = False, + keep_lp_file: bool = False, + lp_path: Path | None = None, ) -> TemoaModel: """ Build a Temoa Instance from data @@ -160,7 +159,7 @@ def build_instance( try: # Check for warnings in log file to notify user. Ugly but it works log_file = os.path.join(definitions.get_OUTPUT_PATH(), 'log.log') - with open(log_file, 'r') as f: + with open(log_file) as f: warnings_found = any( '| WARNING |' in line or '| ERROR |' in line or '| CRITICAL |' in line for line in f @@ -183,7 +182,7 @@ def build_instance( logger.info('Finished creating model instance from data') # save LP if requested - if keep_lp_file: + if keep_lp_file and lp_path is not None: save_lp(instance, lp_path) # gather some stats... @@ -212,8 +211,11 @@ def save_lp(instance: TemoaModel, lp_path: Path) -> None: def solve_instance( - instance: TemoaModel, solver_name, silent: bool = False, solver_suffixes=None -) -> Tuple[TemoaModel, SolverResults]: + instance: TemoaModel, + solver_name: str, + silent: bool = False, + solver_suffixes: list[str] | None = None, +) -> tuple[TemoaModel, SolverResults]: """ Solve the instance and return a loaded instance :param solver_suffixes: iterable of string names for suffixes. See pyomo dox. right now, only @@ -284,17 +286,17 @@ def solve_instance( # supports some. Perhaps in the future, this will be easier. For now, we need a different # solve command for highspy and no suffixes because it works so well. if solver_suffixes: - solver_suffixes = set(solver_suffixes) + solver_suffixes_set = set(solver_suffixes) legit_suffixes = {'dual', 'slack', 'rc'} - bad_apples = solver_suffixes - legit_suffixes - solver_suffixes &= legit_suffixes + bad_apples = solver_suffixes_set - legit_suffixes + solver_suffixes_set &= legit_suffixes if bad_apples: logger.warning( 'Solver suffix %s is not in pyomo standards (see pyomo dox). Removed', bad_apples, ) # convert back to list... - solver_suffixes = list(solver_suffixes) + solver_suffixes = list(solver_suffixes_set) else: solver_suffixes = [] result: SolverResults | None = None @@ -343,15 +345,19 @@ def check_solve_status(result: SolverResults) -> tuple[bool, str]: soln = result['Solution'] logger.info('The solver reported status as: %s', soln.Status) - if check_optimal_termination(results=result): + if check_optimal_termination(result): return True, '' else: return False, f'{soln.Status} was returned from solve' def handle_results( - instance: TemoaModel, results, config: TemoaConfig, append=False, iteration=None -): + instance: TemoaModel, + results: SolverResults, + config: TemoaConfig, + append: bool = False, + iteration: int | None = None, +) -> None: hack = time() if not config.silent: msg = '[ ] Calculating reporting variables and formatting results.' diff --git a/temoa/_internal/table_data_puller.py b/temoa/_internal/table_data_puller.py index defffd9f5..8e83b5d94 100644 --- a/temoa/_internal/table_data_puller.py +++ b/temoa/_internal/table_data_puller.py @@ -33,8 +33,7 @@ import functools import logging -from collections import defaultdict, namedtuple -from enum import Enum, unique +from collections import defaultdict from pyomo.common.numeric_types import value from pyomo.core import Objective @@ -43,6 +42,7 @@ from temoa.components import costs from temoa.components.utils import get_variable_efficiency from temoa.core.model import TemoaModel +from temoa.types.model_types import EI, FI, SLI, CapData, FlowType logger = logging.getLogger(__name__) @@ -54,42 +54,17 @@ def _marks(num: int) -> str: return marks -EI = namedtuple('EI', ['r', 'p', 't', 'v', 'e']) -"""Emission Index""" - - -@unique -class FlowType(Enum): - """Types of flow tracked""" - - IN = 1 - OUT = 2 - CURTAIL = 3 - FLEX = 4 - LOST = 5 - - -FI = namedtuple('FI', ['r', 'p', 's', 'd', 'i', 't', 'v', 'o']) -"""Flow Index""" - -SLI = namedtuple('SLI', ['r', 'p', 's', 'd', 't', 'v']) -"""Storage Level Index""" - -CapData = namedtuple('CapData', ['built', 'net', 'retired']) -"""Small container to hold named dictionaries of capacity data for processing""" - - -def ritvo(fi: FI) -> tuple: +def ritvo(fi: FI) -> tuple[str, str, str, int, str]: """convert FI to ritvo index""" return fi.r, fi.i, fi.t, fi.v, fi.o -def rpetv(fi: FI, e: str) -> tuple: +def rpetv(fi: FI, e: str) -> tuple[str, int, str, str, int]: """convert FI and emission to rpetv index""" return fi.r, fi.p, e, fi.t, fi.v -def poll_capacity_results(M: TemoaModel, epsilon=1e-5) -> CapData: +def poll_capacity_results(M: TemoaModel, epsilon: float = 1e-5) -> CapData: """ Poll a solved model for capacity results. :param M: Solved Model @@ -136,14 +111,14 @@ def poll_capacity_results(M: TemoaModel, epsilon=1e-5) -> CapData: return CapData(built=built, net=net, retired=ret) -def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, float]]: +def poll_flow_results(M: TemoaModel, epsilon: float = 1e-5) -> dict[FI, dict[FlowType, float]]: """ Poll a solved model for flow results. :param M: A solved Model :param epsilon: epsilon (default 1e-5) :return: nested dictionary of FlowIndex, FlowType : value """ - dd = functools.partial(defaultdict, float) + dd: functools.partial[dict[FlowType, float]] = functools.partial(defaultdict, float) res: dict[FI, dict[FlowType, float]] = defaultdict(dd) # ---- NON-annual ---- @@ -251,7 +226,7 @@ def poll_flow_results(M: TemoaModel, epsilon=1e-5) -> dict[FI, dict[FlowType, fl return res -def poll_storage_level_results(M: TemoaModel, epsilon=1e-5) -> dict[SLI, float]: +def poll_storage_level_results(M: TemoaModel, epsilon: float = 1e-5) -> dict[SLI, float]: """ Poll a solved model for flow results. :param M: A solved Model @@ -301,14 +276,17 @@ def poll_objective(M: TemoaModel) -> list[tuple[str, float]]: logger.warning('Multiple active objectives found. All will be logged in db') res = [] for obj in active_objs: - obj_name, obj_value = obj.getname(fully_qualified=True), value(obj) + obj_name, obj_value = obj.getname(fully_qualified=True), float(value(obj)) res.append((obj_name, obj_value)) return res def poll_cost_results( - M: TemoaModel, p_0: int | None, epsilon=1e-5 -) -> tuple[dict[tuple, dict], ...]: + M: TemoaModel, p_0: int | None, epsilon: float = 1e-5 +) -> tuple[ + dict[tuple[str, int, str, int], dict[CostType, float]], + dict[tuple[str, int, str, int], dict[CostType, float]], +]: """ Poll a solved model for all cost results :param M: Solved Model @@ -316,8 +294,11 @@ def poll_cost_results( :param epsilon: epsilon (default 1e-5) :return: tuple of cost_dict, exchange_cost_dict (for exchange techs) """ - if not p_0: - p_0 = min(M.time_optimize) + p_0_true: int + if p_0 is None: + p_0_true = min(M.time_optimize) + else: + p_0_true = p_0 p_e = M.time_future.last() @@ -327,7 +308,7 @@ def poll_cost_results( LLN = M.LoanLifetimeProcess exchange_costs = ExchangeTechCostLedger(M) - entries = defaultdict(dict) + entries: dict[tuple[str, int, str, int], dict[CostType, float]] = defaultdict(dict) for r, t, v in M.CostInvest.sparse_iterkeys(): # Returns only non-zero values # gather details... cap = value(M.V_NewCapacity[r, t, v]) @@ -346,7 +327,7 @@ def poll_cost_results( loan_life=loan_life, capacity=cap, invest_cost=value(M.CostInvest[r, t, v]), - p_0=p_0, + p_0=p_0_true, p_e=p_e, global_discount_rate=GDR, vintage=v, @@ -358,7 +339,7 @@ def poll_cost_results( capacity=cap, invest_cost=value(M.CostInvest[r, t, v]), process_life=value(M.LifetimeProcess[r, t, v]), - p_0=p_0, + p_0=p_0_true, p_e=p_e, global_discount_rate=GDR, vintage=v, @@ -396,7 +377,12 @@ def poll_cost_results( undiscounted_fixed_cost = cap * fixed_cost * value(M.PeriodLength[p]) model_fixed_cost = costs.fixed_or_variable_cost( - cap, fixed_cost, value(M.PeriodLength[p]), GDR=GDR, P_0=p_0, p=p + cap, + value(fixed_cost), + value(M.PeriodLength[p]), + GDR=GDR, + P_0=float(p_0) if p_0 is not None else 0.0, + p=p, ) if '-' in r: exchange_costs.add_cost_record( @@ -404,7 +390,7 @@ def poll_cost_results( period=p, tech=t, vintage=v, - cost=model_fixed_cost, + cost=float(value(model_fixed_cost)), cost_type=CostType.D_FIXED, ) exchange_costs.add_cost_record( @@ -412,12 +398,15 @@ def poll_cost_results( period=p, tech=t, vintage=v, - cost=undiscounted_fixed_cost, + cost=float(value(undiscounted_fixed_cost)), cost_type=CostType.FIXED, ) else: entries[r, p, t, v].update( - {CostType.D_FIXED: model_fixed_cost, CostType.FIXED: undiscounted_fixed_cost} + { + CostType.D_FIXED: float(value(model_fixed_cost)), + CostType.FIXED: float(value(undiscounted_fixed_cost)), + } ) for r, p, t, v in M.CostVariable.sparse_iterkeys(): @@ -442,7 +431,12 @@ def poll_cost_results( undiscounted_var_cost = activity * var_cost * value(M.PeriodLength[p]) model_var_cost = costs.fixed_or_variable_cost( - activity, var_cost, value(M.PeriodLength[p]), GDR=GDR, P_0=p_0, p=p + activity, + var_cost, + value(M.PeriodLength[p]), + GDR=GDR, + P_0=float(p_0) if p_0 is not None else 0.0, + p=p, ) if '-' in r: exchange_costs.add_cost_record( @@ -450,7 +444,7 @@ def poll_cost_results( period=p, tech=t, vintage=v, - cost=model_var_cost, + cost=float(value(model_var_cost)), cost_type=CostType.D_VARIABLE, ) exchange_costs.add_cost_record( @@ -458,28 +452,31 @@ def poll_cost_results( period=p, tech=t, vintage=v, - cost=undiscounted_var_cost, + cost=float(value(undiscounted_var_cost)), cost_type=CostType.VARIABLE, ) else: entries[r, p, t, v].update( - {CostType.D_VARIABLE: model_var_cost, CostType.VARIABLE: undiscounted_var_cost} + { + CostType.D_VARIABLE: float(value(model_var_cost)), + CostType.VARIABLE: float(value(undiscounted_var_cost)), + } ) exchange_entries = exchange_costs.get_entries() return entries, exchange_entries def loan_costs( - loan_rate, # this is referred to as LoanRate in parameters - loan_life, - capacity, - invest_cost, - process_life, - p_0, - p_e, - global_discount_rate, - vintage, - **kwargs, + loan_rate: float, # this is referred to as LoanRate in parameters + loan_life: float, + capacity: float, + invest_cost: float, + process_life: int, + p_0: int, + p_e: int, + global_discount_rate: float, + vintage: int, + **kwargs: object, ) -> tuple[float, float]: """ Calculate Loan costs by calling the loan annualize and loan cost functions in temoa_rules @@ -487,11 +484,11 @@ def loan_costs( """ # dev note: this is a passthrough function. Sole intent is to use the EXACT formula the # model uses for these costs - loan_ar = costs.pv_to_annuity(rate=loan_rate, periods=loan_life) + loan_ar = costs.pv_to_annuity(rate=loan_rate, periods=int(loan_life)) model_ic = costs.loan_cost( capacity, invest_cost, - loan_annualize=loan_ar, + loan_annualize=float(value(loan_ar)), lifetime_loan_process=loan_life, lifetime_process=process_life, P_0=p_0, @@ -504,7 +501,7 @@ def loan_costs( undiscounted_cost = costs.loan_cost( capacity, invest_cost, - loan_annualize=loan_ar, + loan_annualize=float(value(loan_ar)), lifetime_loan_process=loan_life, lifetime_process=process_life, P_0=p_0, @@ -512,23 +509,23 @@ def loan_costs( GDR=global_discount_rate, vintage=vintage, ) - return model_ic, undiscounted_cost + return float(value(model_ic)), float(value(undiscounted_cost)) def loan_costs_survival_curve( - M, - r, - t, - v, - loan_rate, # this is referred to as LoanRate in parameters - loan_life, - capacity, - invest_cost, - p_0, - p_e, - global_discount_rate, - vintage, - **kwargs, + M: TemoaModel, + r: str, + t: str, + v: int, + loan_rate: float, # this is referred to as LoanRate in parameters + loan_life: float, + capacity: float, + invest_cost: float, + p_0: int, + p_e: int, + global_discount_rate: float, + vintage: int, + **kwargs: object, ) -> tuple[float, float]: """ Calculate Loan costs by calling the loan annualize and loan cost functions in temoa_rules @@ -536,7 +533,7 @@ def loan_costs_survival_curve( """ # dev note: this is a passthrough function. Sole intent is to use the EXACT formula the # model uses for these costs - loan_ar = costs.pv_to_annuity(rate=loan_rate, periods=loan_life) + loan_ar = costs.pv_to_annuity(rate=loan_rate, periods=int(loan_life)) model_ic = costs.loan_cost_survival_curve( M, r, @@ -544,7 +541,7 @@ def loan_costs_survival_curve( v, capacity, invest_cost, - loan_annualize=loan_ar, + loan_annualize=float(value(loan_ar)), lifetime_loan_process=loan_life, P_0=p_0, P_e=p_e, @@ -559,18 +556,18 @@ def loan_costs_survival_curve( v, capacity, invest_cost, - loan_annualize=loan_ar, + loan_annualize=float(value(loan_ar)), lifetime_loan_process=loan_life, P_0=p_0, P_e=p_e, GDR=global_discount_rate, ) - return model_ic, undiscounted_cost + return float(value(model_ic)), float(value(undiscounted_cost)) def poll_emissions( - M: 'TemoaModel', p_0=None, epsilon=1e-5 -) -> tuple[dict[tuple, dict], dict[EI, float]]: + M: TemoaModel, p_0: int | None = None, epsilon: float = 1e-5 +) -> tuple[dict[tuple[str, int, str, int], dict[CostType, float]], dict[EI, float]]: """ Gather all emission flows, cost them and provide a tuple of costs and flows :param M: the model @@ -581,8 +578,11 @@ def poll_emissions( # UPDATE: older versions brought forward had some accounting errors here for flex/curtailed emissions # see the note on emissions in the Cost function in temoa_rules - if not p_0: - p_0 = min(M.time_optimize) + p_0_true: int + if p_0 is None: + p_0_true = min(M.time_optimize) + else: + p_0_true = p_0 GDR = value(M.GlobalDiscountRate) @@ -620,8 +620,8 @@ def poll_emissions( ) # gather costs - ud_costs = defaultdict(float) - d_costs = defaultdict(float) + ud_costs: dict[tuple[str, int, str, int], float] = defaultdict(float) + d_costs: dict[tuple[str, int, str, int], float] = defaultdict(float) for ei in flows: # zero out tiny flows if abs(flows[ei]) < epsilon: @@ -636,14 +636,14 @@ def poll_emissions( ) discounted_emiss_cost = costs.fixed_or_variable_cost( cap_or_flow=flows[ei], - cost_factor=M.CostEmission[ei.r, ei.p, ei.e], + cost_factor=value(M.CostEmission[ei.r, ei.p, ei.e]), cost_years=M.PeriodLength[ei.p], GDR=GDR, - P_0=p_0, + P_0=p_0_true, p=ei.p, ) - ud_costs[ei.r, ei.p, ei.t, ei.v] += undiscounted_emiss_cost - d_costs[ei.r, ei.p, ei.t, ei.v] += discounted_emiss_cost + ud_costs[ei.r, ei.p, ei.t, ei.v] += float(value(undiscounted_emiss_cost)) + d_costs[ei.r, ei.p, ei.t, ei.v] += float(value(discounted_emiss_cost)) ########################### # Embodied Emissions @@ -676,16 +676,16 @@ def poll_emissions( ) discounted_emiss_cost = costs.fixed_or_variable_cost( cap_or_flow=embodied_flows[ei], - cost_factor=M.CostEmission[ei.r, ei.v, ei.e], + cost_factor=value(M.CostEmission[ei.r, ei.v, ei.e]), cost_years=M.PeriodLength[ ei.v ], # treat as fixed cost distributed over construction period GDR=GDR, - P_0=p_0, + P_0=p_0_true, p=ei.v, ) - ud_costs[ei.r, ei.v, ei.t, ei.v] += undiscounted_emiss_cost - d_costs[ei.r, ei.v, ei.t, ei.v] += discounted_emiss_cost + ud_costs[ei.r, ei.v, ei.t, ei.v] += float(value(undiscounted_emiss_cost)) + d_costs[ei.r, ei.v, ei.t, ei.v] += float(value(discounted_emiss_cost)) ########################### # End of life Emissions @@ -721,19 +721,19 @@ def poll_emissions( ) discounted_emiss_cost = costs.fixed_or_variable_cost( cap_or_flow=eol_flows[ei], - cost_factor=M.CostEmission[ei.r, ei.p, ei.e], + cost_factor=value(M.CostEmission[ei.r, ei.p, ei.e]), cost_years=M.PeriodLength[ ei.p ], # treat as fixed cost distributed over retirement period GDR=GDR, - P_0=p_0, + P_0=p_0_true, p=ei.p, ) - ud_costs[ei.r, ei.p, ei.t, ei.v] += undiscounted_emiss_cost - d_costs[ei.r, ei.p, ei.t, ei.v] += discounted_emiss_cost + ud_costs[ei.r, ei.p, ei.t, ei.v] += float(value(undiscounted_emiss_cost)) + d_costs[ei.r, ei.p, ei.t, ei.v] += float(value(discounted_emiss_cost)) # finally, now that all costs are added up for each rptv, put in cost dict - costs_dict = defaultdict(dict) + costs_dict: dict[tuple[str, int, str, int], dict[CostType, float]] = defaultdict(dict) for rptv in ud_costs: costs_dict[rptv][CostType.EMISS] = ud_costs[rptv] for rptv in d_costs: diff --git a/temoa/_internal/table_writer.py b/temoa/_internal/table_writer.py index 776d6ca95..129802036 100644 --- a/temoa/_internal/table_writer.py +++ b/temoa/_internal/table_writer.py @@ -10,6 +10,7 @@ from pathlib import Path from typing import TYPE_CHECKING +from pyomo.core import value from pyomo.opt import SolverResults from definitions import PROJECT_ROOT @@ -90,7 +91,7 @@ class TableWriter: - def __init__(self, config: TemoaConfig, epsilon=1e-5): + def __init__(self, config: TemoaConfig, epsilon: float = 1e-5) -> None: self.config = config self.epsilon = epsilon self.tech_sectors: dict[str, str] | None = None @@ -108,7 +109,7 @@ def write_results( M: TemoaModel, results_with_duals: SolverResults | None = None, save_storage_levels: bool = False, - append=False, + append: bool = False, iteration: int | None = None, ) -> None: """ @@ -130,7 +131,7 @@ def write_results( p_0 = M.MyopicDiscountingYear else: p_0 = None # min year will be used in poll - e_costs, e_flows = poll_emissions(M=M, p_0=p_0) + e_costs, e_flows = poll_emissions(M=M, p_0=value(p_0)) self.emission_register = e_flows self.write_emissions(iteration=iteration) @@ -146,7 +147,7 @@ def write_results( self.con.commit() self.con.execute('VACUUM') - def write_mm_results(self, M: TemoaModel, iteration: int): + def write_mm_results(self, M: TemoaModel, iteration: int) -> None: """ tailored writer function for Method of Morris which: (a) appends data (so scenario needs to be cleared elsewhere @@ -166,7 +167,7 @@ def write_mm_results(self, M: TemoaModel, iteration: int): self.con.commit() self.con.execute('VACUUM') - def write_mc_results(self, brick: DataBrick, iteration: int): + def write_mc_results(self, brick: DataBrick, iteration: int) -> None: """ tailored write function to capture appropriate monte carlo results :param M: solve model @@ -193,13 +194,13 @@ def write_mc_results(self, brick: DataBrick, iteration: int): self.con.commit() self.con.execute('VACUUM') - def _set_tech_sectors(self): + def _set_tech_sectors(self) -> None: """pull the sector info and fill the mapping""" qry = 'SELECT tech, sector FROM Technology' data = self.con.execute(qry).fetchall() self.tech_sectors = dict(data) - def clear_scenario(self): + def clear_scenario(self) -> None: cur = self.con.cursor() for table in basic_output_tables: cur.execute(f'DELETE FROM {table} WHERE scenario == ?', (self.config.scenario,)) @@ -211,7 +212,7 @@ def clear_scenario(self): self.con.commit() self.clear_iterative_runs() - def clear_iterative_runs(self): + def clear_iterative_runs(self) -> None: """ clear runs that are iterative extensions to the scenario name Ex: scenario = 'Red Monkey" ... will clear "Red Monkey-1, Red Monkey-2, Red Monkey-3, Red Monkey-4' @@ -229,7 +230,7 @@ def clear_iterative_runs(self): pass self.con.commit() - def write_storage_level(self, M: TemoaModel, iteration=None) -> None: + def write_storage_level(self, M: TemoaModel, iteration: int | None = None) -> None: """Write the storage level table to the DB""" storage_levels = poll_storage_level_results(M=M) @@ -242,6 +243,8 @@ def write_storage_level(self, M: TemoaModel, iteration=None) -> None: data = [] for sli, storage_level in storage_levels.items(): + if self.tech_sectors is None: + raise RuntimeError('tech sectors not available... code error') sector = self.tech_sectors[sli.t] data.append( (scenario_name, sli.r, sector, sli.p, sli.s, sli.d, sli.t, sli.v, storage_level) @@ -251,12 +254,14 @@ def write_storage_level(self, M: TemoaModel, iteration=None) -> None: self.con.executemany(qry, data) self.con.commit() - def write_objective(self, M: TemoaModel, iteration=None) -> None: + def write_objective(self, M: TemoaModel, iteration: int | None = None) -> None: """Write the value of all ACTIVE objectives to the DB""" obj_vals = poll_objective(M=M) self._insert_objective_results(obj_vals, iteration=iteration) - def _insert_objective_results(self, obj_vals: list, iteration: int) -> None: + def _insert_objective_results( + self, obj_vals: list[tuple[str, float]], iteration: int | None + ) -> None: scenario_name = ( self.config.scenario + f'-{iteration}' if iteration is not None @@ -268,10 +273,12 @@ def _insert_objective_results(self, obj_vals: list, iteration: int) -> None: self.con.execute(qry, data) self.con.commit() - def write_emissions(self, iteration=None) -> None: + def write_emissions(self, iteration: int | None = None) -> None: """Write the emission table to the DB""" - if not self.tech_sectors: + if self.tech_sectors is None: raise RuntimeError('tech sectors not available... code error') + if self.emission_register is None: + raise RuntimeError('emission register not available... code error') data = [] scenario = ( @@ -301,7 +308,7 @@ def _insert_capacity_results(self, cap_data: CapData, iteration: int | None) -> scenario = scenario + f'-{iteration}' # Built Capacity - data = [] + data: list[tuple[str, str, str | None, str, int, float]] = [] for r, t, v, val in cap_data.built: s = self.tech_sectors.get(t) new_cap = (scenario, r, s, t, v, val) @@ -310,22 +317,39 @@ def _insert_capacity_results(self, cap_data: CapData, iteration: int | None) -> self.con.executemany(qry, data) # NetCapacity - data = [] + data_net: list[tuple[str, str, str | None, int, str, int, float]] = [] for r, p, t, v, val in cap_data.net: s = self.tech_sectors.get(t) - new_net_cap = (scenario, r, s, p, t, v, val) - data.append(new_net_cap) + new_net_cap: tuple[str, str, str | None, int, str, int, float] = ( + scenario, + r, + s, + p, + t, + v, + val, + ) + data_net.append(new_net_cap) qry = 'INSERT INTO OutputNetCapacity VALUES (?, ?, ?, ?, ?, ?, ?)' - self.con.executemany(qry, data) + self.con.executemany(qry, data_net) # Retired Capacity - data = [] + data_ret: list[tuple[str, str, str | None, int, str, int, float, float]] = [] for r, p, t, v, eol, early in cap_data.retired: s = self.tech_sectors.get(t) - new_retired_cap = (scenario, r, s, p, t, v, eol, early) - data.append(new_retired_cap) + new_retired_cap: tuple[str, str, str | None, int, str, int, float, float] = ( + scenario, + r, + s, + p, + t, + v, + eol, + early, + ) + data_ret.append(new_retired_cap) qry = 'INSERT INTO OutputRetiredCapacity VALUES (?, ?, ?, ?, ?, ?, ?, ?)' - self.con.executemany(qry, data) + self.con.executemany(qry, data_ret) self.con.commit() def write_capacity_tables(self, M: TemoaModel, iteration: int | None = None) -> None: @@ -333,14 +357,16 @@ def write_capacity_tables(self, M: TemoaModel, iteration: int | None = None) -> cap_data = poll_capacity_results(M=M) self._insert_capacity_results(cap_data=cap_data, iteration=iteration) - def write_flow_tables(self, iteration=None) -> None: + def write_flow_tables(self, iteration: int | None = None) -> None: """Write the flow tables""" if not self.tech_sectors: raise RuntimeError('tech sectors not available... code error') if not self.flow_register: raise RuntimeError('flow_register not available... code error') # sort the flows - flows_by_type: dict[FlowType, list[tuple]] = defaultdict(list) + flows_by_type: dict[ + FlowType, list[tuple[str, str, str | None, int, str, str, str, str, int, str, float]] + ] = defaultdict(list) scenario = ( self.config.scenario + f'-{iteration}' if iteration is not None @@ -369,7 +395,7 @@ def write_flow_tables(self, iteration=None) -> None: self.con.commit() - def write_summary_flow(self, M: TemoaModel, iteration: int | None = None): + def write_summary_flow(self, M: TemoaModel, iteration: int | None = None) -> None: """ This is normally called from MGA (other?) iterative solves where capturing the annual summary of flow out is desired vs. flows by season, tod for @@ -381,7 +407,9 @@ def write_summary_flow(self, M: TemoaModel, iteration: int | None = None): flow_data = self.calculate_flows(M=M) self._insert_summary_flow_results(flow_data=flow_data, iteration=iteration) - def _insert_summary_flow_results(self, flow_data: dict, iteration: int | None) -> None: + def _insert_summary_flow_results( + self, flow_data: dict[FI, dict[FlowType, float]], iteration: int | None + ) -> None: if not self.tech_sectors: raise RuntimeError('tech sectors not available... code error') @@ -396,21 +424,32 @@ def _insert_summary_flow_results(self, flow_data: dict, iteration: int | None) - # iterate through all elements of the flow register, look for output flows only, # and gather the total by index (region, period, input_comm, tech, vintage, output_comm) # this is summing across season, tod - output_flows = defaultdict(float) + output_flows: dict[tuple[str, str, str | None, int, str, str, int, str], float] = ( + defaultdict(float) + ) for fi in self.flow_register: sector = self.tech_sectors.get(fi.t) # get the output flow for this index, if it exists... flow_out_value = self.flow_register[fi].get(FlowType.OUT, None) if flow_out_value: - idx = (scenario, fi.r, sector, fi.p, fi.i, fi.t, fi.v, fi.o) + idx: tuple[str, str, str | None, int, str, str, int, str] = ( + scenario, + fi.r, + sector, + fi.p, + fi.i, + fi.t, + fi.v, + fi.o, + ) output_flows[idx] += flow_out_value # convert to entries, if the sum is non-negligible - entries = [] + entries: list[tuple[str, str, str | None, int, str, str, int, str, float]] = [] for idx, flow in output_flows.items(): if abs(flow) < self.epsilon: continue - entry = (*idx, flow) + entry: tuple[str, str, str | None, int, str, str, int, str, float] = (*idx, flow) entries.append(entry) qry = f'INSERT INTO OutputFlowOutSummary VALUES {_marks(9)}' @@ -488,7 +527,12 @@ def calculate_flows(self, M: TemoaModel) -> dict[FI, dict[FlowType, float]]: """Gather all flows by Flow Index and Type""" return poll_flow_results(M, self.epsilon) - def write_costs(self, M: TemoaModel, emission_entries=None, iteration=None): + def write_costs( + self, + M: TemoaModel, + emission_entries: dict[tuple[str, int, str, int], dict[CostType, float]] | None = None, + iteration: int | None = None, + ) -> None: """ Gather the cost data vars :param iteration: tag for iteration in scenario name @@ -504,12 +548,18 @@ def write_costs(self, M: TemoaModel, emission_entries=None, iteration=None): else: p_0 = min(M.time_optimize) - entries, exchange_entries = poll_cost_results(M, p_0, self.epsilon) + entries, exchange_entries = poll_cost_results(M, value(p_0), self.epsilon) # write to table self._insert_cost_results(entries, exchange_entries, emission_entries, iteration) - def _insert_cost_results(self, regular_entries, exchange_entries, emission_entries, iteration): + def _insert_cost_results( + self, + regular_entries: dict[tuple[str, int, str, int], dict[CostType, float]], + exchange_entries: dict[tuple[str, int, str, int], dict[CostType, float]], + emission_entries: dict[tuple[str, int, str, int], dict[CostType, float]] | None, + iteration: int | None, + ) -> None: # add the emission costs to the same row data, if provided if emission_entries: for k in emission_entries: @@ -517,8 +567,14 @@ def _insert_cost_results(self, regular_entries, exchange_entries, emission_entri self._write_cost_rows(regular_entries, iteration=iteration) self._write_cost_rows(exchange_entries, iteration=iteration) - def _write_cost_rows(self, entries, iteration=None): + def _write_cost_rows( + self, + entries: dict[tuple[str, int, str, int], dict[CostType, float]], + iteration: int | None = None, + ) -> None: """Write the entries to the OutputCost table""" + if self.tech_sectors is None: + raise RuntimeError('tech sectors not available... code error') cur = self.con.cursor() scenario_name = ( self.config.scenario + f'-{iteration}' @@ -549,7 +605,7 @@ def _write_cost_rows(self, entries, iteration=None): cur.executemany(qry, rows) self.con.commit() - def write_dual_variables(self, results: SolverResults, iteration=None): + def write_dual_variables(self, results: SolverResults, iteration: int | None = None) -> None: """Write the dual variables to the OutputDualVariable table""" scenario_name = ( self.config.scenario + f'-{iteration}' @@ -564,7 +620,7 @@ def write_dual_variables(self, results: SolverResults, iteration=None): # MONTE CARLO stuff - def write_tweaks(self, iteration: int, change_records: Iterable[ChangeRecord]): + def write_tweaks(self, iteration: int, change_records: Iterable[ChangeRecord]) -> None: scenario = f'{self.config.scenario}-{iteration}' records = [] for change_record in change_records: @@ -581,24 +637,24 @@ def write_tweaks(self, iteration: int, change_records: Iterable[ChangeRecord]): self.con.executemany(qry, records) self.con.commit() - def __del__(self): + def __del__(self) -> None: if self.con: self.con.close() - def make_summary_flow_table(self): + def make_summary_flow_table(self) -> None: # make the additional output table, if needed... self.execute_script(flow_summary_file_loc) - def make_mc_tweaks_table(self): + def make_mc_tweaks_table(self) -> None: # make the table for monte carlo tweaks, if needed... self.execute_script(mc_tweaks_file_loc) - def execute_script(self, script_file: str | Path): + def execute_script(self, script_file: str | Path) -> None: """ A utility to execute a sql script on the current db connection :return: """ - with open(script_file, 'r') as table_script: + with open(script_file) as table_script: sql_commands = table_script.read() logger.debug('Executing sql from file: %s ', script_file) diff --git a/temoa/_internal/temoa_sequencer.py b/temoa/_internal/temoa_sequencer.py index 481feea51..6b020f557 100644 --- a/temoa/_internal/temoa_sequencer.py +++ b/temoa/_internal/temoa_sequencer.py @@ -73,8 +73,8 @@ def __init__( output_path: str | Path, mode_override: TemoaMode | None = None, silent: bool = False, - **kwargs, - ): + **kwargs: object, + ) -> None: """ Create a new Sequencer :param config_file: Optional path to config file. If not provided, it will be read @@ -100,8 +100,7 @@ def __init__( logger.error('Output directory does not exist: %s', self.output_path) raise FileNotFoundError(f'Invalid output directory: {self.output_path}') - self.temoa_mode: TemoaMode = TemoaMode.BUILD_ONLY # placeholder, over-written in start() - self.mode_override: TemoaMode = mode_override + self.mode_override: TemoaMode | None = mode_override # for feedback to user self.silent = silent @@ -140,7 +139,7 @@ def start(self) -> TemoaModel | None: self.temoa_mode = self.config.scenario_mode # check it... if not isinstance(self.temoa_mode, TemoaMode): - logger.error( + logger.error( # type: ignore[unreachable] 'Temoa Mode not set properly. Override: %s, Config File: %s', self.mode_override, self.config.scenario_mode, @@ -197,6 +196,7 @@ def start(self) -> TemoaModel | None: if not good_prices and not self.config.silent: print('Warning: Cost anomalies discovered. Check log file for details.') con.close() + return None case TemoaMode.PERFECT_FORESIGHT: con = sqlite3.connect(self.config.input_database) @@ -236,11 +236,13 @@ def start(self) -> TemoaModel | None: sys.exit(-1) handle_results(self.pf_solved_instance, self.pf_results, self.config) con.close() + return None case TemoaMode.MYOPIC: # create a myopic sequencer and shift control to it myopic_sequencer = MyopicSequencer(config=self.config) myopic_sequencer.start() + return None case TemoaMode.MGA: if self.config.solver_name == 'appsi_highs': @@ -250,14 +252,17 @@ def start(self) -> TemoaModel | None: ) mga_sequencer = MgaSequencer(config=self.config) mga_sequencer.start() + return None case TemoaMode.SVMGA: sv_mga_sequencer = SvMgaSequencer(config=self.config) sv_mga_sequencer.start() + return None case TemoaMode.METHOD_OF_MORRIS: mm_sequencer = MorrisSequencer(config=self.config) mm_sequencer.start() + return None case TemoaMode.MONTE_CARLO: if self.config.solver_name == 'appsi_highs': @@ -282,6 +287,7 @@ def start(self) -> TemoaModel | None: logger.warning('Save duals disabled for MONTE_CARLO') mc_sequencer = MCSequencer(config=self.config) mc_sequencer.start() + return None case _: raise NotImplementedError('not yet built') From c7345986dc5d874974dfd0b4b3f01b6084f7fb69 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 18 Oct 2025 19:03:13 -0400 Subject: [PATCH 247/587] adding typing to temoa/core files --- temoa/core/config.py | 22 +++--- temoa/core/model.py | 172 ++++++++++++++++++++----------------------- 2 files changed, 90 insertions(+), 104 deletions(-) diff --git a/temoa/core/config.py b/temoa/core/config.py index 7cb890e28..1f769b9c7 100644 --- a/temoa/core/config.py +++ b/temoa/core/config.py @@ -49,11 +49,11 @@ def __init__( save_lp_file: bool = False, time_sequencing: str | None = None, reserve_margin: str | None = None, - MGA: dict | None = None, - SVMGA: dict | None = None, - myopic: dict | None = None, - morris: dict | None = None, - monte_carlo: dict | None = None, + MGA: dict[str, object] | None = None, + SVMGA: dict[str, object] | None = None, + myopic: dict[str, object] | None = None, + morris: dict[str, object] | None = None, + monte_carlo: dict[str, object] | None = None, config_file: Path | None = None, silent: bool = False, stream_output: bool = False, @@ -153,7 +153,7 @@ def __init__( SE.write('Warning: ' + msg) @staticmethod - def build_config(config_file: Path, output_path: Path, silent=False) -> 'TemoaConfig': + def build_config(config_file: Path, output_path: Path, silent: bool = False) -> 'TemoaConfig': """ build a Temoa Config from a config file :param silent: suppress warnings and confirmations @@ -171,7 +171,7 @@ def build_config(config_file: Path, output_path: Path, silent=False) -> 'TemoaCo logger.info('Mode: %s', tc.scenario_mode.name) return tc - def __repr__(self): + def __repr__(self) -> str: width = 25 spacer = '\n' + '-' * width + '\n' msg = spacer @@ -202,7 +202,7 @@ def __repr__(self): msg += '{:>{}s}: {}\n'.format('Time sequencing', width, self.time_sequencing) msg += '{:>{}s}: {}\n'.format('Planning reserve margin', width, self.reserve_margin) - if self.scenario_mode == TemoaMode.MYOPIC: + if self.scenario_mode == TemoaMode.MYOPIC and self.myopic_inputs is not None: msg += spacer msg += '{:>{}s}: {}\n'.format( 'Myopic view depth', width, self.myopic_inputs.get('view_depth') @@ -211,7 +211,7 @@ def __repr__(self): 'Myopic step size', width, self.myopic_inputs.get('step_size') ) - if self.scenario_mode == TemoaMode.MGA: + if self.scenario_mode == TemoaMode.MGA and self.mga_inputs is not None: msg += spacer msg += '{:>{}s}: {}\n'.format( 'MGA Cost Epsilon', width, self.mga_inputs.get('cost_epsilon') @@ -225,7 +225,7 @@ def __repr__(self): msg += '{:>{}s}: {}\n'.format('MGA Axis:', width, self.mga_inputs.get('axis')) msg += '{:>{}s}: {}\n'.format('MGA Weighting', width, self.mga_inputs.get('weighting')) - if self.scenario_mode == TemoaMode.METHOD_OF_MORRIS: + if self.scenario_mode == TemoaMode.METHOD_OF_MORRIS and self.morris_inputs is not None: msg += spacer msg += '{:>{}s}: {}\n'.format( 'Morris Perturbation', width, self.morris_inputs.get('perturbation') @@ -243,7 +243,7 @@ def __repr__(self): 'Morris CPU Cores Requested', width, self.morris_inputs.get('cores') ) - if self.scenario_mode == TemoaMode.SVMGA: + if self.scenario_mode == TemoaMode.SVMGA and self.svmga_inputs is not None: msg += spacer msg += '{:>{}s}: {}\n'.format( 'SVMGA Cost Epsilon', width, self.svmga_inputs.get('cost_epsilon') diff --git a/temoa/core/model.py b/temoa/core/model.py index 0799aaca7..d52f31f3b 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -9,11 +9,11 @@ """ import logging +from typing import TYPE_CHECKING from pyomo.core import BuildCheck, Set, Var from pyomo.environ import ( AbstractModel, - Any, BuildAction, Constraint, Integers, @@ -23,6 +23,15 @@ minimize, ) +from temoa.types.core_types import Technology + +if TYPE_CHECKING: + from pyomo.environ import AbstractModel as PyomoAbstractModel + +else: + PyomoAbstractModel = AbstractModel # type: ignore[misc,assignment] + +from temoa import types as t from temoa.components import ( capacity, commodities, @@ -51,13 +60,11 @@ logger = logging.getLogger(__name__) -def CreateSparseDicts(M: 'TemoaModel'): +def CreateSparseDicts(M: 'TemoaModel') -> None: """ Creates and populates all sparse dictionaries and sets required for the model by calling component-specific precomputation functions. """ - # Initialize a set to track technologies used in the Efficiency table - M.used_techs = set() # Call the decomposed functions in logical order # 1. Populate core relationships from Efficiency table @@ -87,7 +94,7 @@ def CreateSparseDicts(M: 'TemoaModel'): logger.debug('Completed creation of SparseDicts') -class TemoaModel(AbstractModel): +class TemoaModel(PyomoAbstractModel): """ An instance of the abstract Temoa model """ @@ -95,8 +102,8 @@ class TemoaModel(AbstractModel): # this is used in several places outside this class, and this provides no-build access to it default_lifetime_tech = 40 - def __init__(M, *args, **kwargs): - AbstractModel.__init__(M, *args, **kwargs) + def __init__(M, *args: object, **kwargs: object) -> None: + PyomoAbstractModel.__init__(M, *args, **kwargs) ################################################ # Internally used Data Containers # @@ -104,91 +111,77 @@ def __init__(M, *args, **kwargs): ################################################ # Dev Note: The triple-quotes UNDER the items below pop up as dox in most IDEs - M.processInputs = dict() - M.processOutputs = dict() - M.processLoans = dict() - M.activeFlow_rpsditvo = None + M.processInputs: t.ProcessInputsDict = {} + M.processOutputs: t.ProcessOutputsDict = {} + M.processLoans: t.ProcessLoansDict = {} + M.activeFlow_rpsditvo: t.ActiveFlowSet = set() """a flow index for techs NOT in tech_annual""" - M.activeFlow_rpitvo = None + M.activeFlow_rpitvo: t.ActiveFlowAnnualSet = set() """a flow index for techs in tech_annual only""" - M.activeFlex_rpsditvo = None - M.activeFlex_rpitvo = None - M.activeFlowInStorage_rpsditvo = None - M.activeCurtailment_rpsditvo = None - M.activeActivity_rptv = None - M.storageLevelIndices_rpsdtv = None - M.seasonalStorageLevelIndices_rpstv = None + M.activeFlex_rpsditvo: t.ActiveFlexSet = set() + M.activeFlex_rpitvo: t.ActiveFlexAnnualSet = set() + M.activeFlowInStorage_rpsditvo: t.ActiveFlowInStorageSet = set() + M.activeCurtailment_rpsditvo: t.ActiveCurtailmentSet = set() + M.activeActivity_rptv: t.ActiveActivitySet = set() + M.storageLevelIndices_rpsdtv: t.StorageLevelIndicesSet = set() + M.seasonalStorageLevelIndices_rpstv: t.SeasonalStorageLevelIndicesSet = set() """currently available (within lifespan) (r, p, t, v) tuples (from M.processVintages)""" - M.activeRegionsForTech = None + M.activeRegionsForTech: t.ActiveRegionsForTechDict = {} """currently available regions by period and tech {(p, t) : r}""" - M.newCapacity_rtv = None - M.activeCapacityAvailable_rpt = None - M.activeCapacityAvailable_rptv = None - M.groupRegionActiveFlow_rpt = None # Set of valid group-region, period, tech indices - M.commodityBalance_rpc = None # Set of valid region-period-commodity indices to balance - M.commodityDStreamProcess = dict() # The downstream process of a commodity during a period - M.commodityUStreamProcess = dict() # The upstream process of a commodity during a period - M.capacityConsumptionTechs = ( - dict() - ) # New capacity consuming a commodity during a period [r,p,c] -> t - M.retirementProductionProcesses = ( - dict() - ) # Retired capacity producing a commodity during a period [r,p,c] -> t,v - M.processInputsByOutput = dict() - M.processOutputsByInput = dict() - M.processTechs = dict() - M.processReservePeriods = dict() - M.processPeriods = dict() # {(r, t, v): set(p)} - M.retirementPeriods = ( - dict() - ) # {(r, t, v): set(p)} periods in which a process can economically or naturally retire - M.processVintages = dict() - M.survivalCurvePeriods: dict[tuple, set] = ( - dict() - ) # {(r, t, v): set(p)} periods for which the process has a defined survival fraction + M.newCapacity_rtv: t.NewCapacitySet = set() + M.activeCapacityAvailable_rpt: t.ActiveCapacityAvailableSet = set() + M.activeCapacityAvailable_rptv: t.ActiveCapacityAvailableVintageSet = set() + M.groupRegionActiveFlow_rpt: t.GroupRegionActiveFlowSet = ( + set() # Set of valid group-region, period, tech indices + ) + M.commodityBalance_rpc: t.CommodityBalancedSet = ( + set() + ) # Set of valid region-period-commodity indices to balance + M.commodityDStreamProcess: t.CommodityStreamProcessDict = {} # The downstream process of a commodity during a period + M.commodityUStreamProcess: t.CommodityStreamProcessDict = {} # The upstream process of a commodity during a period + M.capacityConsumptionTechs: t.CapacityConsumptionTechsDict = {} # New capacity consuming a commodity during a period [r,p,c] -> t + M.retirementProductionProcesses: t.RetirementProductionProcessesDict = {} # Retired capacity producing a commodity during a period [r,p,c] -> t,v + M.processInputsByOutput: t.ProcessInputsByOutputDict = {} + M.processOutputsByInput: t.ProcessOutputsByInputDict = {} + M.processTechs: t.ProcessTechsDict = {} + M.processReservePeriods: t.ProcessReservePeriodsDict = {} + M.processPeriods: t.ProcessPeriodsDict = {} # {(r, t, v): set(p)} + M.retirementPeriods: t.RetirementPeriodsDict = {} # {(r, t, v): set(p)} periods in which a process can economically or naturally retire + M.processVintages: t.ProcessVintagesDict = {} + M.survivalCurvePeriods: t.SurvivalCurvePeriodsDict = {} # {(r, t, v): set(p)} periods for which the process has a defined survival fraction """current available (within lifespan) vintages {(r, p, t) : set(v)}""" - M.baseloadVintages = dict() - M.curtailmentVintages = dict() - M.storageVintages = dict() - M.rampUpVintages = dict() - M.rampDownVintages = dict() - M.inputSplitVintages = dict() - M.inputSplitAnnualVintages = dict() - M.outputSplitVintages = dict() - M.outputSplitAnnualVintages = dict() - # M.processByPeriodAndOutput = dict() # not currently used - M.exportRegions = dict() - M.importRegions = dict() + M.baseloadVintages: t.BaseloadVintagesDict = {} + M.curtailmentVintages: t.CurtailmentVintagesDict = {} + M.storageVintages: t.StorageVintagesDict = {} + M.rampUpVintages: t.RampUpVintagesDict = {} + M.rampDownVintages: t.RampDownVintagesDict = {} + M.inputSplitVintages: t.InputSplitVintagesDict = {} + M.inputSplitAnnualVintages: t.InputSplitAnnualVintagesDict = {} + M.outputSplitVintages: t.OutputSplitVintagesDict = {} + M.outputSplitAnnualVintages: t.OutputSplitAnnualVintagesDict = {} + # M.processByPeriodAndOutput = {} # not currently used + M.exportRegions: t.ExportRegionsDict = {} + M.importRegions: t.ImportRegionsDict = {} # These establish time sequencing - M.time_next = dict() # {(p, s, d): (s_next, d_next)} sequence of following time slices - M.time_next_sequential = dict() # {(p, s_seq): (s_seq_next)} next virtual storage season - M.sequential_to_season = ( - dict() - ) # {(p, s_seq): (s)} season matching this virtual storage season + M.time_next: t.TimeNextDict = {} # {(p, s, d): (s_next, d_next)} sequence of following time slices + M.time_next_sequential: t.TimeNextSequentialDict = {} # {(p, s_seq): (s_seq_next)} next virtual storage season + M.sequential_to_season: t.SequentialToSeasonDict = {} # {(p, s_seq): (s)} season matching this virtual storage season ################################################ # Switching Sets # # (to avoid slow searches in initialisation) # ################################################ - M.isEfficiencyVariable: dict[tuple, bool] = ( - dict() - ) # {(r, p, i, t, v, o): bool} which efficiencies have variable indexing - M.isCapacityFactorProcess: dict[tuple, bool] = ( - dict() - ) # {(r, p, t, v): bool} which capacity factors have have period-vintage indexing - M.isSeasonalStorage: dict[tuple, bool] = ( - dict() - ) # {t: bool} whether a storage tech is seasonal storage - M.isSurvivalCurveProcess: dict[tuple, bool] = ( - dict() - ) # {(r, t, v): bool} whether a process uses survival curves. + M.isEfficiencyVariable: t.EfficiencyVariableDict = {} # {(r, p, i, t, v, o): bool} which efficiencies have variable indexing + M.isCapacityFactorProcess: t.CapacityFactorProcessDict = {} # {(r, p, t, v): bool} which capacity factors have have period-vintage indexing + M.isSeasonalStorage: t.SeasonalStorageDict = {} # {t: bool} whether a storage tech is seasonal storage + M.isSurvivalCurveProcess: t.SurvivalCurveProcessDict = {} # {(r, t, v): bool} whether a process uses survival curves. ################################################ # Model Sets # @@ -232,7 +225,7 @@ def __init__(M, *args, **kwargs): M.regionalGlobalIndices = Set(validate=region_group_check) # Define technology-related sets - # M.tech_resource = Set() # not actually used by anything + # M.tech_resource = Set() # not actually used by M.tech_production = Set() M.tech_all = Set( initialize=M.tech_production, validate=no_slash_or_pipe @@ -264,6 +257,9 @@ def __init__(M, *args, **kwargs): M.tech_exist = Set() """techs with existing capacity, want to keep these for accounting reasons""" + M.used_techs: set[Technology] = set() + """ track techs used in Efficiency table used in CreateSparseDicts """ + # the below is a convenience for domain checking in params below that should not accept # uncap techs... M.tech_with_capacity = Set(initialize=M.tech_all - M.tech_uncap) @@ -582,23 +578,13 @@ def __init__(M, *args, **kwargs): M.LimitAnnualCapacityFactorConstraint_rpto, validate=validate_0to1 ) - M.LimitGrowthCapacity = Param( - M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any - ) - M.LimitDegrowthCapacity = Param( - M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any - ) - M.LimitGrowthNewCapacity = Param( - M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any - ) - M.LimitDegrowthNewCapacity = Param( - M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any - ) - M.LimitGrowthNewCapacityDelta = Param( - M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any - ) + M.LimitGrowthCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator) + M.LimitDegrowthCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator) + M.LimitGrowthNewCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator) + M.LimitDegrowthNewCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator) + M.LimitGrowthNewCapacityDelta = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator) M.LimitDegrowthNewCapacityDelta = Param( - M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any + M.regionalGlobalIndices, M.tech_or_group, M.operator ) M.LimitEmissionConstraint_rpe = Set( @@ -676,7 +662,7 @@ def __init__(M, *args, **kwargs): # Storage duration is expressed in hours M.StorageDuration = Param(M.regions, M.tech_storage, default=4) - M.LinkedTechs = Param(M.regionalIndices, M.tech_all, M.commodity_emissions, within=Any) + M.LinkedTechs = Param(M.regionalIndices, M.tech_all, M.commodity_emissions) # Define parameters associated with electric sector operation M.ReserveMarginMethod = Set() # How contributions to the reserve margin are calculated @@ -1126,6 +1112,6 @@ def __init__(M, *args, **kwargs): M.progress_marker_9 = BuildAction(['Finished Constraints'], rule=progress_check) -def progress_check(M, checkpoint: str): +def progress_check(M: TemoaModel, checkpoint: str) -> None: """A quick widget which is called by BuildAction in order to log creation progress""" logger.debug('Model build progress: %s', checkpoint) From 607528aacebb59bf484fd28e7dcb2701cab6bbcb Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 18 Oct 2025 19:03:39 -0400 Subject: [PATCH 248/587] adding typing to temoa/component files --- temoa/components/capacity.py | 188 ++++++++++++-------- temoa/components/commodities.py | 68 ++++--- temoa/components/costs.py | 93 +++++----- temoa/components/emissions.py | 31 ++-- temoa/components/flows.py | 68 ++++--- temoa/components/geography.py | 29 +-- temoa/components/limits.py | 305 ++++++++++++++++++++------------ temoa/components/operations.py | 107 ++++++++--- temoa/components/reserves.py | 15 +- temoa/components/storage.py | 83 ++++++--- temoa/components/technology.py | 91 +++++----- temoa/components/time.py | 104 ++++++----- temoa/components/utils.py | 25 ++- 13 files changed, 752 insertions(+), 455 deletions(-) diff --git a/temoa/components/capacity.py b/temoa/components/capacity.py index 3258eb14b..6349e76ab 100644 --- a/temoa/components/capacity.py +++ b/temoa/components/capacity.py @@ -13,15 +13,21 @@ from itertools import product as cross_product from logging import getLogger -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any from deprecated import deprecated -from pyomo.environ import ( - value, -) +from pyomo.environ import value if TYPE_CHECKING: from temoa.core.model import TemoaModel + from temoa.types import ( + Period, + Region, + Season, + Technology, + TimeOfDay, + Vintage, + ) logger = getLogger(name=__name__) @@ -32,8 +38,8 @@ # ============================================================================ -def CheckCapacityFactorProcess(M: 'TemoaModel'): - count_rptv = dict() +def CheckCapacityFactorProcess(M: TemoaModel) -> None: + count_rptv: dict[tuple[Any, Any, Any, Any], int] = {} # Pull CapacityFactorTech by default for r, p, _s, _d, t in M.CapacityFactor_rpsdt: for v in M.processVintages[r, p, t]: @@ -67,7 +73,7 @@ def CheckCapacityFactorProcess(M: 'TemoaModel'): @deprecated('should not be needed. We are pulling the default on-the-fly where used') -def CreateCapacityFactors(M: 'TemoaModel'): +def CreateCapacityFactors(M: TemoaModel) -> None: """ Steps to creating capacity factors: 1. Collect all possible processes @@ -78,14 +84,14 @@ def CreateCapacityFactors(M: 'TemoaModel'): CFP = M.CapacityFactorProcess # Step 1 - processes = set((r, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) + processes = {(r, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys()} - all_cfs = set( + all_cfs = { (r, p, s, d, t, v) for (r, t, v) in processes for p in M.processPeriods[r, t, v] for s, d in cross_product(M.TimeSeason[p], M.time_of_day) - ) + } # Step 2 unspecified_cfs = all_cfs.difference(CFP.sparse_iterkeys()) @@ -108,7 +114,9 @@ def CreateCapacityFactors(M: 'TemoaModel'): # CFP._constructed = True -def get_default_capacity_factor(M: 'TemoaModel', r, p, s, d, t, v): +def get_default_capacity_factor( + M: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage +) -> float: """ This initializer is used to fill the CapacityFactorProcess from the CapacityFactorTech where needed. @@ -124,10 +132,12 @@ def get_default_capacity_factor(M: 'TemoaModel', r, p, s, d, t, v): :param v: vintage :return: the capacity factor """ - return M.CapacityFactorTech[r, p, s, d, t] + return value(M.CapacityFactorTech[r, p, s, d, t]) -def get_capacity_factor(M: 'TemoaModel', r, p, s, d, t, v): +def get_capacity_factor( + M: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage +) -> float: if M.isCapacityFactorProcess[r, p, t, v]: return value(M.CapacityFactorProcess[r, p, s, d, t, v]) else: @@ -139,88 +149,110 @@ def get_capacity_factor(M: 'TemoaModel', r, p, s, d, t, v): # ============================================================================ -def CapacityVariableIndices(M: 'TemoaModel'): +def CapacityVariableIndices( + M: TemoaModel, +) -> set[tuple[Region, Technology, Vintage]] | None: return M.newCapacity_rtv -def RetiredCapacityVariableIndices(M: 'TemoaModel'): - return set( +def RetiredCapacityVariableIndices( + M: TemoaModel, +) -> set[tuple[Region, Period, Technology, Vintage]]: + return { (r, p, t, v) for r, p, t in M.processVintages if t in M.tech_retirement and t not in M.tech_uncap for v in M.processVintages[r, p, t] if v < p <= v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[p]) - ) + } -def AnnualRetirementVariableIndices(M: 'TemoaModel'): - return set( - (r, p, t, v) for r, t, v in M.retirementPeriods for p in M.retirementPeriods[r, t, v] - ) +def AnnualRetirementVariableIndices( + M: TemoaModel, +) -> set[tuple[Region, Period, Technology, Vintage]]: + return {(r, p, t, v) for r, t, v in M.retirementPeriods for p in M.retirementPeriods[r, t, v]} -def CapacityAvailableVariableIndices(M: 'TemoaModel'): +def CapacityAvailableVariableIndices( + M: TemoaModel, +) -> set[tuple[Region, Period, Technology]] | None: return M.activeCapacityAvailable_rpt -def RegionalExchangeCapacityConstraintIndices(M: 'TemoaModel'): - indices = set( - (r_e, r_i, p, t, v) - for r_e, p, i in M.exportRegions - for r_i, t, v, o in M.exportRegions[r_e, p, i] - ) +def RegionalExchangeCapacityConstraintIndices( + M: TemoaModel, +) -> set[tuple[Region, Region, Period, Technology, Vintage]]: + indices: set[tuple[Region, Region, Period, Technology, Vintage]] = set() + for r_e, p, i in M.exportRegions: + for r_i, t, v, _o in M.exportRegions[r_e, p, i]: + indices.add((r_e, r_i, p, t, v)) return indices -def CapacityAnnualConstraintIndices(M: 'TemoaModel'): - capacity_indices = set( - (r, p, t, v) - for r, p, t, v in M.activeActivity_rptv - if t in M.tech_annual and t not in M.tech_demand - if t not in M.tech_uncap - ) +def CapacityAnnualConstraintIndices( + M: TemoaModel, +) -> set[tuple[Region, Period, Technology, Vintage]]: + capacity_indices: set[tuple[Region, Period, Technology, Vintage]] = set() + if M.activeActivity_rptv: + for r, p, t, v in M.activeActivity_rptv: + if t in M.tech_annual and t not in M.tech_demand: + if t not in M.tech_uncap: + capacity_indices.add((r, p, t, v)) + else: + return set() return capacity_indices -def CapacityConstraintIndices(M: 'TemoaModel'): - capacity_indices = set( - (r, p, s, d, t, v) - for r, p, t, v in M.activeActivity_rptv - if (t not in M.tech_annual or t in M.tech_demand) - if t not in M.tech_uncap - if t not in M.tech_storage - for s in M.TimeSeason[p] - for d in M.time_of_day - ) +def CapacityConstraintIndices( + M: TemoaModel, +) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]]: + capacity_indices: set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]] = set() + if M.activeActivity_rptv: + for r, p, t, v in M.activeActivity_rptv: + if t not in M.tech_annual or t in M.tech_demand: + if t not in M.tech_uncap: + if t not in M.tech_storage: + for s in M.TimeSeason[p]: + for d in M.time_of_day: + capacity_indices.add((r, p, s, d, t, v)) + else: + return set() return capacity_indices @deprecated('switched over to validator... this set is typically VERY empty') -def CapacityFactorProcessIndices(M: 'TemoaModel'): - indices = set( - (r, s, d, t, v) - for r, i, t, v, o in M.Efficiency.sparse_iterkeys() - for p in M.time_optimize - for s in M.TimeSeason[p] - for d in M.time_of_day - ) +def CapacityFactorProcessIndices( + M: TemoaModel, +) -> set[tuple[str, str, str, str, int]]: + indices: set[tuple[Region, Season, TimeOfDay, Technology, Vintage]] = set() + for r, _i, t, v, _o in M.Efficiency.sparse_iterkeys(): + for p in M.time_optimize: + for s in M.TimeSeason[p]: + for d in M.time_of_day: + indices.add((r, s, d, t, v)) return indices -def CapacityFactorTechIndices(M: 'TemoaModel'): - all_cfs = set( - (r, p, s, d, t) - for r, p, t in M.activeCapacityAvailable_rpt - for s in M.TimeSeason[p] - for d in M.time_of_day - ) +def CapacityFactorTechIndices( + M: TemoaModel, +) -> set[tuple[Region, Period, Season, TimeOfDay, Technology]]: + all_cfs: set[tuple[Region, Period, Season, TimeOfDay, Technology]] = set() + if M.activeCapacityAvailable_rpt: + for r, p, t in M.activeCapacityAvailable_rpt: + for s in M.TimeSeason[p]: + for d in M.time_of_day: + all_cfs.add((r, p, s, d, t)) + else: + return set() return all_cfs -def CapacityAvailableVariableIndicesVintage(M: 'TemoaModel'): +def CapacityAvailableVariableIndicesVintage( + M: TemoaModel, +) -> set[tuple[Region, Period, Technology, Vintage]] | None: return M.activeCapacityAvailable_rptv @@ -229,7 +261,9 @@ def CapacityAvailableVariableIndicesVintage(M: 'TemoaModel'): # ============================================================================ -def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): +def AnnualRetirement_Constraint( + M: TemoaModel, r: Region, p: Period, t: Technology, v: Vintage +) -> Any: r""" Get the annualised retirement rate for a process in a given period. Used to output retirement (including end of life, EOL) and to model end of @@ -309,7 +343,9 @@ def AnnualRetirement_Constraint(M: 'TemoaModel', r, p, t, v): return M.V_AnnualRetirement[r, p, t, v] == annualised_retirement -def CapacityAvailableByPeriodAndTech_Constraint(M: 'TemoaModel', r, p, t): +def CapacityAvailableByPeriodAndTech_Constraint( + M: TemoaModel, r: Region, p: Period, t: Technology +) -> Any: r""" The :math:`\textbf{CAPAVL}` variable is nominally for reporting solution values, @@ -329,7 +365,9 @@ def CapacityAvailableByPeriodAndTech_Constraint(M: 'TemoaModel', r, p, t): return expr -def CapacityAnnual_Constraint(M: 'TemoaModel', r, p, t, v): +def CapacityAnnual_Constraint( + M: TemoaModel, r: Region, p: Period, t: Technology, v: Vintage +) -> Any: r""" Similar to Capacity_Constraint, but for technologies belonging to the :code:`tech_annual` set. Technologies in the tech_annual set have constant output @@ -360,7 +398,9 @@ def CapacityAnnual_Constraint(M: 'TemoaModel', r, p, t, v): return value(M.CapacityToActivity[r, t]) * M.V_Capacity[r, p, t, v] >= activity_rptv -def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): +def Capacity_Constraint( + M: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage +) -> Any: r""" This constraint ensures that the capacity of a given process is sufficient to support its activity across all time periods and time slices. The calculation @@ -432,7 +472,9 @@ def Capacity_Constraint(M: 'TemoaModel', r, p, s, d, t, v): ) -def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): +def AdjustedCapacity_Constraint( + M: TemoaModel, r: Region, p: Period, t: Technology, v: Vintage +) -> Any: r""" This constraint updates the capacity of a process by taking into account retirements and end of life. For a given :code:`(r,p,t,v)` index, this constraint sets the capacity @@ -525,7 +567,7 @@ def AdjustedCapacity_Constraint(M: 'TemoaModel', r, p, t, v): # ============================================================================ -def create_capacity_and_retirement_sets(M: 'TemoaModel'): +def create_capacity_and_retirement_sets(M: TemoaModel) -> None: """ Creates and populates component-specific Python sets and dictionaries on the model object. @@ -571,20 +613,20 @@ def create_capacity_and_retirement_sets(M: 'TemoaModel'): M.retirementProductionProcesses.setdefault((r, p, o), set()).add((t, v)) # Create active capacity index sets from the now-populated processVintages - M.newCapacity_rtv = set( + M.newCapacity_rtv = { (r, t, v) for r, p, t in M.processVintages for v in M.processVintages[r, p, t] if t not in M.tech_uncap and v in M.time_optimize - ) - M.activeCapacityAvailable_rpt = set( + } + M.activeCapacityAvailable_rpt = { (r, p, t) for r, p, t in M.processVintages if M.processVintages[r, p, t] and t not in M.tech_uncap - ) - M.activeCapacityAvailable_rptv = set( + } + M.activeCapacityAvailable_rptv = { (r, p, t, v) for r, p, t in M.processVintages for v in M.processVintages[r, p, t] if t not in M.tech_uncap - ) + } diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index c5808667c..5336dcf43 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -12,13 +12,14 @@ from itertools import product as cross_product from logging import getLogger from operator import itemgetter as iget -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any from pyomo.environ import value if TYPE_CHECKING: from temoa.core.model import TemoaModel +from ..types import Commodity, Period, Region from .utils import get_variable_efficiency logger = getLogger(name=__name__) @@ -28,7 +29,9 @@ # ============================================================================ -def CommodityBalanceConstraintErrorCheck(supplied, demanded, r, p, s, d, c): +def CommodityBalanceConstraintErrorCheck( + supplied: Any, demanded: Any, r: Region, p: Period, s: str, d: str, c: Commodity +) -> None: # note: if a pyomo equation simplifies to an int, there are no variables in it, which # is an indicator of a problem. How this might come up I do not know if isinstance(supplied, int) or isinstance(demanded, int): @@ -49,7 +52,9 @@ def CommodityBalanceConstraintErrorCheck(supplied, demanded, r, p, s, d, c): raise Exception(msg.format(c, r, p, s, d, expr)) -def AnnualCommodityBalanceConstraintErrorCheck(supplied, demanded, r, p, c): +def AnnualCommodityBalanceConstraintErrorCheck( + supplied: Any, demanded: Any, r: Region, p: Period, c: Commodity +) -> None: # note: if a pyomo equation simplifies to an int, there are no variables in it, which # is an indicator of a problem. How this might come up I do not know if isinstance(supplied, int) or isinstance(demanded, int): @@ -70,7 +75,7 @@ def AnnualCommodityBalanceConstraintErrorCheck(supplied, demanded, r, p, c): raise Exception(msg.format(c, r, p, expr)) -def DemandConstraintErrorCheck(supply, r, p, dem): +def DemandConstraintErrorCheck(supply: Any, r: Region, p: Period, dem: Commodity) -> None: # note: if a pyomo equation simplifies to an int, there are no variables in it, which # is an indicator of a problem if isinstance(supply, int): @@ -90,22 +95,26 @@ def DemandConstraintErrorCheck(supply, r, p, dem): # ============================================================================ -def DemandActivityConstraintIndices(M: 'TemoaModel'): - indices = set( +def DemandActivityConstraintIndices( + M: 'TemoaModel', +) -> set[tuple[Region, Period, str, str, str, int, Commodity]]: + indices = { (r, p, s, d, t, v, dem) for r, p, dem in M.DemandConstraint_rpc for t, v in M.commodityUStreamProcess[r, p, dem] if t not in M.tech_annual for s in M.TimeSeason[p] for d in M.time_of_day - ) + } return indices -def CommodityBalanceConstraintIndices(M: 'TemoaModel'): +def CommodityBalanceConstraintIndices( + M: 'TemoaModel', +) -> set[tuple[Region, Period, str, str, Commodity]]: # Generate indices only for those commodities that are produced by # technologies with varying output at the time slice level. - indices = set( + indices = { (r, p, s, d, c) for r, p, c in M.commodityBalance_rpc # r in this line includes interregional transfer combinations (not needed). @@ -113,21 +122,23 @@ def CommodityBalanceConstraintIndices(M: 'TemoaModel'): and c not in M.commodity_annual for s in M.TimeSeason[p] for d in M.time_of_day - ) + } return indices -def AnnualCommodityBalanceConstraintIndices(M: 'TemoaModel'): +def AnnualCommodityBalanceConstraintIndices( + M: 'TemoaModel', +) -> set[tuple[Region, Period, Commodity]]: # Generate indices only for those commodities that are produced by # technologies with constant annual output. - indices = set( + indices = { (r, p, c) for r, p, c in M.commodityBalance_rpc # r in this line includes interregional transfer combinations (not needed). if r in M.regions # this line ensures only the regions are included. and c in M.commodity_annual - ) + } return indices @@ -137,7 +148,7 @@ def AnnualCommodityBalanceConstraintIndices(M: 'TemoaModel'): # ============================================================================ -def Demand_Constraint(M: 'TemoaModel', r, p, dem): +def Demand_Constraint(M: 'TemoaModel', r: Region, p: Period, dem: Commodity) -> Any: r""" The Demand constraint drives the model. This constraint ensures that supply at @@ -183,7 +194,9 @@ def Demand_Constraint(M: 'TemoaModel', r, p, dem): # devnote: no longer needed -def DemandActivity_Constraint(M: 'TemoaModel', r, p, s, d, t, v, dem): +def DemandActivity_Constraint( + M: 'TemoaModel', r: Region, p: Period, s: str, d: str, t: str, v: int, dem: Commodity +) -> Any: r""" For end-use demands, it is unreasonable to let the model arbitrarily shift the @@ -225,7 +238,9 @@ def DemandActivity_Constraint(M: 'TemoaModel', r, p, s, d, t, v, dem): return expr -def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): +def CommodityBalance_Constraint( + M: 'TemoaModel', r: Region, p: Period, s: str, d: str, c: Commodity +) -> Any: r""" Where the Demand constraint :eq:`Demand` ensures that end-use demands are met, the CommodityBalance constraint ensures that the endogenous system demands are @@ -459,7 +474,7 @@ def CommodityBalance_Constraint(M: 'TemoaModel', r, p, s, d, c): return expr -def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): +def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r: Region, p: Period, c: Commodity) -> Any: r""" Similar to CommodityBalance_Constraint but only balances the supply and demand of the commodity at the period level, summing all flows over the period but allowing imbalances at the time slice @@ -604,7 +619,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r, p, c): # ============================================================================ -def create_technology_and_commodity_sets(M: 'TemoaModel'): +def create_technology_and_commodity_sets(M: 'TemoaModel') -> None: """ Populates technology and commodity subset definitions based on their roles (e.g., demand, flexible) identified from the Efficiency parameter. @@ -625,7 +640,7 @@ def create_technology_and_commodity_sets(M: 'TemoaModel'): M.tech_demand.add(t) -def CreateDemands(M: 'TemoaModel'): +def CreateDemands(M: 'TemoaModel') -> None: """ Steps to create the demand distributions 1. Use Demand keys to ensure that all demands in commodity_demand are used @@ -649,7 +664,7 @@ def CreateDemands(M: 'TemoaModel'): DSD_dem = iget(4) # Step 1: Check if any demand commodities are going unused - used_dems = set(dem for r, p, dem in M.Demand.sparse_iterkeys()) + used_dems = {dem for r, p, dem in M.Demand.sparse_iterkeys()} unused_dems = sorted(M.commodity_demand.difference(used_dems)) if unused_dems: for dem in unused_dems: @@ -720,7 +735,7 @@ def CreateDemands(M: 'TemoaModel'): # Also check that all keys are made... The demand distro should be supported # by the full set of (r, p, dem) keys because it is an equality constraint # and we need to ensure even the zeros are passed in - used_rp_dems = set((r, p, dem) for r, p, dem in M.Demand.sparse_iterkeys()) + used_rp_dems = {(r, p, dem) for r, p, dem in M.Demand.sparse_iterkeys()} for r, p, dem in used_rp_dems: expected_key_length = len(M.TimeSeason[p]) * len(M.time_of_day) keys = [ @@ -730,12 +745,12 @@ def CreateDemands(M: 'TemoaModel'): ] if len(keys) != expected_key_length: # this could be very slow but only calls when there's a problem - missing = set( + missing = { (s, d) for s in M.TimeSeason[p] for d in M.time_of_day if (r, p, s, d, dem) not in keys - ) + } logger.info( 'Missing some time slices for Demand Specific Distribution %s: %s', (r, p, dem), @@ -746,7 +761,7 @@ def CreateDemands(M: 'TemoaModel'): # We can't explicitly test for "!= 1.0" because of incremental rounding # errors associated with the specification of demand shares by time slice, # but we check to make sure it is within the specified tolerance. - def get_str_padding(obj): + def get_str_padding(obj: Any) -> int: return len(str(obj)) key_padding = max(map(get_str_padding, keys)) @@ -754,9 +769,8 @@ def get_str_padding(obj): fmt = '%%-%ds = %%s' % key_padding # Works out to something like "%-25s = %s" - items = sorted((k, value(DSD[k])) for k in keys) - items = '\n '.join(fmt % (str(k), v) for k, v in items) - + items_list: list[tuple[Any, Any]] = sorted([(k, value(DSD[k])) for k in keys]) + items = '\n '.join(fmt % (str(k), v) for k, v in items_list) msg = ( 'The values of the DemandSpecificDistribution parameter do not ' 'sum to 1 for {}. The DemandSpecificDistribution specifies how end-use ' diff --git a/temoa/components/costs.py b/temoa/components/costs.py index 03d178644..caeb96db7 100644 --- a/temoa/components/costs.py +++ b/temoa/components/costs.py @@ -13,11 +13,12 @@ from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any from deprecated import deprecated from pyomo.core import Expression, Var -from pyomo.environ import value +from pyomo.core.base.component import ComponentData +from pyomo.environ import quicksum, value if TYPE_CHECKING: from temoa.core.model import TemoaModel @@ -32,9 +33,9 @@ # ============================================================================ -def get_default_loan_rate(M: 'TemoaModel', *_): +def get_default_loan_rate(M: TemoaModel, *_: Any) -> float: """get the default loan rate from the DefaultLoanRate param""" - return M.DefaultLoanRate() + return value(M.DefaultLoanRate) def annuity_to_pv(rate: float, periods: int) -> float | Expression: @@ -84,8 +85,8 @@ def fv_to_pv(rate: float, periods: int) -> float | Expression: return 1 / (1 + rate) ** periods -def get_loan_life(M: 'TemoaModel', r, t, v): - return M.LifetimeProcess[r, t, v] +def get_loan_life(M: TemoaModel, r: str, t: str, v: int) -> int: + return value(M.LifetimeProcess[r, t, v]) # ============================================================================ @@ -93,16 +94,20 @@ def get_loan_life(M: 'TemoaModel', r, t, v): # ============================================================================ -def CostFixedIndices(M: 'TemoaModel'): +def CostFixedIndices(M: TemoaModel) -> set[tuple[str, int, str, int]]: # we pull the unlimited capacity techs from this index. They cannot have fixed costs - return {(r, p, t, v) for r, p, t, v in M.activeActivity_rptv if t not in M.tech_uncap} + if M.activeActivity_rptv: + return {(r, p, t, v) for r, p, t, v in M.activeActivity_rptv if t not in M.tech_uncap} + return set() -def CostVariableIndices(M: 'TemoaModel'): - return M.activeActivity_rptv +def CostVariableIndices(M: TemoaModel) -> set[tuple[str, int, str, int]]: + if M.activeActivity_rptv: + return M.activeActivity_rptv + return set() -def LifetimeLoanProcessIndices(M: 'TemoaModel'): +def LifetimeLoanProcessIndices(M: TemoaModel) -> set[tuple[str, str, int]]: """ Based on the Efficiency parameter's indices and time_future parameter, this function returns the set of process indices that may be specified in the @@ -110,7 +115,7 @@ def LifetimeLoanProcessIndices(M: 'TemoaModel'): """ min_period = min(M.vintage_optimize) - indices = set((r, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys() if v >= min_period) + indices = {(r, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys() if v >= min_period} return indices @@ -122,7 +127,7 @@ def LifetimeLoanProcessIndices(M: 'TemoaModel'): def loan_cost( - capacity: float | Var, + capacity: float | Var | ComponentData, invest_cost: float, loan_annualize: float, lifetime_loan_process: float | int, @@ -168,7 +173,7 @@ def loan_cost( res = ( annuity * annuity_to_pv( - GDR, lifetime_loan_process + GDR, int(lifetime_loan_process) ) # PV of all loan payments, discounted to vintage year using GDR * pv_to_annuity(GDR, lifetime_process) # reamortised over lifetime of process using GDR * annuity_to_pv( @@ -180,11 +185,11 @@ def loan_cost( def loan_cost_survival_curve( - M: 'TemoaModel', + M: TemoaModel, r: str, t: str, - v: str, - capacity: float | Var, + v: int, + capacity: float | Var | ComponentData, invest_cost: float, loan_annualize: float, lifetime_loan_process: float | int, @@ -234,7 +239,7 @@ def loan_cost_survival_curve( res = ( annuity * annuity_to_pv( - GDR, lifetime_loan_process + GDR, int(lifetime_loan_process) ) # PV of all loan payments, discounted to vintage year using GDR / sum( # redistributed over survival curve within horizon value( @@ -255,9 +260,9 @@ def loan_cost_survival_curve( def fixed_or_variable_cost( - cap_or_flow: float | Var, + cap_or_flow: float | Var | ComponentData, cost_factor: float, - cost_years: float, + cost_years: float | ComponentData, GDR: float | None, P_0: float, p: int, @@ -284,9 +289,9 @@ def fixed_or_variable_cost( return ( annual_cost * annuity_to_pv( - GDR, cost_years + GDR, int(cost_years) ) # PV of annual costs over this period, discounted to period p - * fv_to_pv(GDR, p - P_0) # discounted from p to p_0 + * fv_to_pv(GDR, int(p - P_0)) # discounted from p to p_0 ) @@ -295,7 +300,7 @@ def fixed_or_variable_cost( # ============================================================================ -def PeriodCost_rule(M: 'TemoaModel', p): +def PeriodCost_rule(M: TemoaModel, p: int) -> float | Expression: P_0 = min(M.time_optimize) P_e = M.time_future.last() # End point of modeled horizon GDR = value(M.GlobalDiscountRate) @@ -304,7 +309,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): if value(M.MyopicDiscountingYear) != 0: P_0 = value(M.MyopicDiscountingYear) - loan_costs = sum( + loan_costs = quicksum( loan_cost( M.V_NewCapacity[r, S_t, S_v], value(M.CostInvest[r, S_t, S_v]), @@ -319,7 +324,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): for r, S_t, S_v in M.CostInvest.sparse_iterkeys() if S_v == p and not M.isSurvivalCurveProcess[r, S_t, S_v] ) - loan_costs += sum( + loan_costs += quicksum( loan_cost_survival_curve( M, r, @@ -337,7 +342,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): if S_v == p and M.isSurvivalCurveProcess[r, S_t, S_v] ) - fixed_costs = sum( + fixed_costs = quicksum( fixed_or_variable_cost( M.V_Capacity[r, p, S_t, S_v], value(M.CostFixed[r, p, S_t, S_v]), @@ -350,7 +355,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): if S_p == p ) - variable_costs = sum( + variable_costs = quicksum( fixed_or_variable_cost( M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, S_o], value(M.CostVariable[r, p, S_t, S_v]), @@ -367,7 +372,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): for d in M.time_of_day ) - variable_costs_annual = sum( + variable_costs_annual = quicksum( fixed_or_variable_cost( M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, S_o], value(M.CostVariable[r, p, S_t, S_v]), @@ -413,7 +418,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): annual = [(r, p, e, i, t, v, o) for (r, p, e, i, t, v, o) in base if t in M.tech_annual] # 1. variable emissions - var_emissions = sum( + var_emissions = quicksum( fixed_or_variable_cost( cap_or_flow=M.V_FlowOut[r, p, s, d, i, t, v, o] * value(M.EmissionActivity[r, e, i, t, v, o]), @@ -431,7 +436,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): # 3. curtailment emissions -- removed (curtailment is no-flow, for accounting only, so no emissions) # 4. annual emissions - var_annual_emissions = sum( + var_annual_emissions = quicksum( fixed_or_variable_cost( cap_or_flow=M.V_FlowOutAnnual[r, p, i, t, v, o] * value(M.EmissionActivity[r, e, i, t, v, o]), @@ -448,15 +453,15 @@ def PeriodCost_rule(M: 'TemoaModel', p): # 5. flex annual emissions -- removed (double counting, flex wastes are SUBTRACTIVE from flowout) # 6. embodied - treated as a fixed cost distributed over the deployment period (vintage) - embodied_emissions = sum( + embodied_emissions = quicksum( fixed_or_variable_cost( cap_or_flow=M.V_NewCapacity[r, t, v] * value(M.EmissionEmbodied[r, e, t, v]) / value(M.PeriodLength[p]), cost_factor=value(M.CostEmission[r, p, e]), - cost_years=M.PeriodLength[ - v - ], # We assume the embodied emissions are emitted in the same year as the capacity is installed. + cost_years=value( + M.PeriodLength[v] + ), # We assume the embodied emissions are emitted in the same year as the capacity is installed. GDR=GDR, P_0=P_0, p=p, @@ -467,13 +472,13 @@ def PeriodCost_rule(M: 'TemoaModel', p): ) # 6. endoflife - treated as a fixed cost distributed over the retirement period - endoflife_emissions = sum( + endoflife_emissions = quicksum( fixed_or_variable_cost( cap_or_flow=M.V_AnnualRetirement[r, p, t, v] * value(M.EmissionEndOfLife[r, e, t, v]), cost_factor=value(M.CostEmission[r, p, e]), - cost_years=M.PeriodLength[ - p - ], # We assume the embodied emissions are emitted in the same year as the capacity is installed. + cost_years=value( + M.PeriodLength[p] + ), # We assume the embodied emissions are emitted in the same year as the capacity is installed. GDR=GDR, P_0=P_0, p=p, @@ -496,7 +501,7 @@ def PeriodCost_rule(M: 'TemoaModel', p): # --------------------------------------------------------------- # Define the Objective Function # --------------------------------------------------------------- -def TotalCost_rule(M): +def TotalCost_rule(M: TemoaModel) -> Expression: r""" Using the :code:`FlowOut` and :code:`Capacity` variables, the Temoa objective @@ -630,7 +635,7 @@ def TotalCost_rule(M): \end{aligned} """ - return sum(PeriodCost_rule(M, p) for p in M.time_optimize) + return quicksum(PeriodCost_rule(M, p) for p in M.time_optimize) # ============================================================================ @@ -639,7 +644,7 @@ def TotalCost_rule(M): @deprecated(reason='vintage defaults are no longer available, so this should not be needed') -def CreateCosts(M: 'TemoaModel'): +def CreateCosts(M: TemoaModel) -> None: """ Steps to creating fixed and variable costs: 1. Collect all possible cost indices (CostFixed, CostVariable) @@ -678,12 +683,12 @@ def CreateCosts(M: 'TemoaModel'): if (r, t, v) in M.CostVariableVintageDefault: CV[r, p, t, v] = M.CostVariableVintageDefault[r, t, v] # CV._constructed = True - logger.debug('Created M.CostFixed with size: %d', len(M.CostFixed)) - logger.debug('Created M.CostVariable with size: %d', len(M.CostVariable)) + logger.debug('Created M.CostFixed with size: %d', len(value(M.CostFixed))) + logger.debug('Created M.CostVariable with size: %d', len(value(M.CostVariable))) logger.debug('Finished creating Fixed and Variable costs') -def ParamLoanAnnualize_rule(M: 'TemoaModel', r, t, v): +def ParamLoanAnnualize_rule(M: TemoaModel, r: str, t: str, v: int) -> float | Expression: """Rule to calculate the annualized loan rate from the loan rate and lifetime.""" dr = value(M.LoanRate[r, t, v]) lln = value(M.LoanLifetimeProcess[r, t, v]) diff --git a/temoa/components/emissions.py b/temoa/components/emissions.py index 33409d5c4..19997aa0f 100644 --- a/temoa/components/emissions.py +++ b/temoa/components/emissions.py @@ -11,8 +11,11 @@ from typing import TYPE_CHECKING +from pyomo.core import quicksum from pyomo.environ import value +from temoa.types import ExprLike + if TYPE_CHECKING: from temoa.core.model import TemoaModel @@ -22,28 +25,28 @@ # ============================================================================ -def EmissionActivityIndices(M: 'TemoaModel'): - indices = set( +def EmissionActivityIndices(M: 'TemoaModel') -> set[tuple[str, str, str, str, int, str]]: + indices = { (r, e, i, t, v, o) for r, i, t, v, o in M.Efficiency.sparse_iterkeys() for e in M.commodity_emissions if r in M.regions # omit any exchange/groups - ) + } return indices -def LinkedTechConstraintIndices(M: 'TemoaModel'): - linkedtech_indices = set( +def LinkedTechConstraintIndices(M: 'TemoaModel') -> set[tuple[str, int, str, str, str, int, str]]: + linkedtech_indices = { (r, p, s, d, t, v, e) for r, t, e in M.LinkedTechs.sparse_iterkeys() for p in M.time_optimize if (r, p, t) in M.processVintages for v in M.processVintages[r, p, t] - if (r, p, t, v) in M.activeActivity_rptv + if M.activeActivity_rptv and (r, p, t, v) in M.activeActivity_rptv for s in M.TimeSeason[p] for d in M.time_of_day - ) + } return linkedtech_indices @@ -53,7 +56,9 @@ def LinkedTechConstraintIndices(M: 'TemoaModel'): # ============================================================================ -def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): +def LinkedEmissionsTech_Constraint( + M: 'TemoaModel', r: str, p: int, s: str, d: str, t: str, v: int, e: str +) -> ExprLike: r""" This constraint is necessary for carbon capture technologies that produce CO2 as an emissions commodity, but the CO2 also serves as a physical @@ -78,7 +83,7 @@ def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): """ if t in M.tech_annual: - primary_flow = sum( + primary_flow = quicksum( ( value(M.DemandSpecificDistribution[r, p, s, d, S_o]) if S_o in M.commodity_demand @@ -90,14 +95,14 @@ def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) else: - primary_flow = sum( + primary_flow = quicksum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] * value(M.EmissionActivity[r, e, S_i, t, v, S_o]) for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - linked_t = M.LinkedTechs[r, t, e] + linked_t = value(M.LinkedTechs[r, t, e]) # linked_flow = sum( # M.V_FlowOut[r, p, s, d, S_i, linked_t, v, S_o] @@ -106,7 +111,7 @@ def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): # ) if linked_t in M.tech_annual: - linked_flow = sum( + linked_flow = quicksum( ( value(M.DemandSpecificDistribution[r, p, s, d, S_o]) if S_o in M.commodity_demand @@ -117,7 +122,7 @@ def LinkedEmissionsTech_Constraint(M: 'TemoaModel', r, p, s, d, t, v, e): for S_o in M.processOutputsByInput[r, p, linked_t, v, S_i] ) else: - linked_flow = sum( + linked_flow = quicksum( M.V_FlowOut[r, p, s, d, S_i, linked_t, v, S_o] for S_i in M.processInputs[r, p, linked_t, v] for S_o in M.processOutputsByInput[r, p, linked_t, v, S_i] diff --git a/temoa/components/flows.py b/temoa/components/flows.py index b1d4ddb3f..7cfec112a 100644 --- a/temoa/components/flows.py +++ b/temoa/components/flows.py @@ -15,6 +15,12 @@ if TYPE_CHECKING: from temoa.core.model import TemoaModel +from temoa.types import ( + ActiveFlexAnnualSet, + ActiveFlowAnnualSet, + RegionPeriodSeasonTimeInputTechVintageOutput, +) + logger = getLogger(__name__) @@ -23,27 +29,39 @@ # ============================================================================ -def FlowVariableIndices(M: 'TemoaModel'): +def FlowVariableIndices( + M: 'TemoaModel', +) -> set[RegionPeriodSeasonTimeInputTechVintageOutput] | None: return M.activeFlow_rpsditvo -def FlowVariableAnnualIndices(M: 'TemoaModel'): +def FlowVariableAnnualIndices( + M: 'TemoaModel', +) -> ActiveFlowAnnualSet: return M.activeFlow_rpitvo -def FlexVariablelIndices(M: 'TemoaModel'): +def FlexVariablelIndices( + M: 'TemoaModel', +) -> set[RegionPeriodSeasonTimeInputTechVintageOutput] | None: return M.activeFlex_rpsditvo -def FlexVariableAnnualIndices(M: 'TemoaModel'): +def FlexVariableAnnualIndices( + M: 'TemoaModel', +) -> ActiveFlexAnnualSet: return M.activeFlex_rpitvo -def FlowInStorageVariableIndices(M: 'TemoaModel'): +def FlowInStorageVariableIndices( + M: 'TemoaModel', +) -> set[RegionPeriodSeasonTimeInputTechVintageOutput] | None: return M.activeFlowInStorage_rpsditvo -def CurtailmentVariableIndices(M: 'TemoaModel'): +def CurtailmentVariableIndices( + M: 'TemoaModel', +) -> set[RegionPeriodSeasonTimeInputTechVintageOutput] | None: return M.activeCurtailment_rpsditvo @@ -52,7 +70,7 @@ def CurtailmentVariableIndices(M: 'TemoaModel'): # ============================================================================ -def create_commodity_balance_and_flow_sets(M: 'TemoaModel'): +def create_commodity_balance_and_flow_sets(M: 'TemoaModel') -> None: """ Creates aggregated sets for commodity balances and detailed index sets for active flows. @@ -83,7 +101,7 @@ def create_commodity_balance_and_flow_sets(M: 'TemoaModel'): M.commodityBalance_rpc = commodity_upstream.intersection(commodity_downstream) # 2. Active Flow Indices (Time-Sliced) - M.activeFlow_rpsditvo = set( + M.activeFlow_rpsditvo = { (r, p, s, d, i, t, v, o) for r, p, t in M.processVintages if t not in M.tech_annual @@ -92,20 +110,20 @@ def create_commodity_balance_and_flow_sets(M: 'TemoaModel'): for o in M.processOutputsByInput.get((r, p, t, v, i), set()) for s in M.TimeSeason[p] # REVERTED THIS LINE for d in M.time_of_day - ) + } # 3. Active Flow Indices (Annual) - M.activeFlow_rpitvo = set( + M.activeFlow_rpitvo = { (r, p, i, t, v, o) for r, p, t in M.processVintages for v in M.processVintages[r, p, t] for i in M.processInputs.get((r, p, t, v), set()) for o in M.processOutputsByInput.get((r, p, t, v, i), set()) if t in M.tech_annual or (t in M.tech_demand and o in M.commodity_demand) - ) + } # 4. Active Flexible Technology Flow Indices - M.activeFlex_rpsditvo = set( + M.activeFlex_rpsditvo = { (r, p, s, d, i, t, v, o) for r, p, t in M.processVintages if (t not in M.tech_annual) and (t in M.tech_flex) @@ -114,19 +132,19 @@ def create_commodity_balance_and_flow_sets(M: 'TemoaModel'): for o in M.processOutputsByInput.get((r, p, t, v, i), set()) for s in M.TimeSeason[p] # REVERTED THIS LINE for d in M.time_of_day - ) + } - M.activeFlex_rpitvo = set( + M.activeFlex_rpitvo = { (r, p, i, t, v, o) for r, p, t in M.processVintages if (t in M.tech_annual) and (t in M.tech_flex) for v in M.processVintages[r, p, t] for i in M.processInputs.get((r, p, t, v), set()) for o in M.processOutputsByInput.get((r, p, t, v, i), set()) - ) + } # 5. Active Storage and Curtailment Indices - M.activeFlowInStorage_rpsditvo = set( + M.activeFlowInStorage_rpsditvo = { (r, p, s, d, i, t, v, o) for r, p, t in M.storageVintages for v in M.storageVintages[r, p, t] @@ -134,9 +152,9 @@ def create_commodity_balance_and_flow_sets(M: 'TemoaModel'): for o in M.processOutputsByInput.get((r, p, t, v, i), set()) for s in M.TimeSeason[p] # REVERTED THIS LINE for d in M.time_of_day - ) + } - M.activeCurtailment_rpsditvo = set( + M.activeCurtailment_rpsditvo = { (r, p, s, d, i, t, v, o) for r, p, t in M.curtailmentVintages for v in M.curtailmentVintages[r, p, t] @@ -144,27 +162,27 @@ def create_commodity_balance_and_flow_sets(M: 'TemoaModel'): for o in M.processOutputsByInput.get((r, p, t, v, i), set()) for s in M.TimeSeason[p] # REVERTED THIS LINE for d in M.time_of_day - ) + } # 6. Active Technology and Capacity Indices - M.activeActivity_rptv = set( + M.activeActivity_rptv = { (r, p, t, v) for r, p, t in M.processVintages for v in M.processVintages[r, p, t] - ) + } # 7. Storage Level Indices - M.storageLevelIndices_rpsdtv = set( + M.storageLevelIndices_rpsdtv = { (r, p, s, d, t, v) for r, p, t in M.storageVintages for v in M.storageVintages[r, p, t] for s in M.TimeSeason[p] # REVERTED THIS LINE for d in M.time_of_day - ) + } - M.seasonalStorageLevelIndices_rpstv = set( + M.seasonalStorageLevelIndices_rpstv = { (r, p, s_stor, t, v) for r, p, t in M.storageVintages if t in M.tech_seasonal_storage for v in M.storageVintages[r, p, t] for _p, s_stor in M.sequential_to_season if _p == p - ) + } diff --git a/temoa/components/geography.py b/temoa/components/geography.py index b74d6c81c..f92b4d5e0 100644 --- a/temoa/components/geography.py +++ b/temoa/components/geography.py @@ -10,8 +10,9 @@ - Defining constraints that govern inter-regional capacity and flows. """ +from collections.abc import Iterable from logging import getLogger -from typing import TYPE_CHECKING, Iterable +from typing import TYPE_CHECKING from deprecated import deprecated from pyomo.environ import value @@ -19,6 +20,9 @@ if TYPE_CHECKING: from temoa.core.model import TemoaModel +# Import type annotations +from temoa.types import Period, Region, Technology, Vintage + logger = getLogger(name=__name__) # ============================================================================ @@ -26,13 +30,14 @@ # ============================================================================ -def gather_group_regions(M: 'TemoaModel', region: str) -> Iterable[str]: +def gather_group_regions(M: 'TemoaModel', region: Region) -> Iterable[Region]: + regions: list[Region] if region == 'global': - regions = M.regions + regions = list(M.regions) elif '+' in region: regions = region.split('+') else: - regions = (region,) + regions = [region] return regions @@ -41,9 +46,9 @@ def gather_group_regions(M: 'TemoaModel', region: str) -> Iterable[str]: # ============================================================================ -def CreateRegionalIndices(M: 'TemoaModel'): +def CreateRegionalIndices(M: 'TemoaModel') -> list[Region]: """Create the set of all regions and all region-region pairs""" - regional_indices = set() + regional_indices: set[Region] = set() for r_i in M.regions: if '-' in r_i: logger.error("Individual region names can not have '-' in their names: %s", str(r_i)) @@ -58,10 +63,10 @@ def CreateRegionalIndices(M: 'TemoaModel'): @deprecated('No longer used. See the region_group_check in validators.py') -def RegionalGlobalInitializedIndices(M: 'TemoaModel'): +def RegionalGlobalInitializedIndices(M: 'TemoaModel') -> set[Region]: from itertools import permutations - indices = set() + indices: set[Region] = set() for n in range(1, len(M.regions) + 1): regional_perms = permutations(M.regions, n) for i in regional_perms: @@ -77,7 +82,9 @@ def RegionalGlobalInitializedIndices(M: 'TemoaModel'): # ============================================================================ -def RegionalExchangeCapacity_Constraint(M: 'TemoaModel', r_e, r_i, p, t, v): +def RegionalExchangeCapacity_Constraint( + M: 'TemoaModel', r_e: Region, r_i: Region, p: Period, t: Technology, v: Vintage +) -> object: r""" This constraint ensures that the process (t,v) connecting regions @@ -104,7 +111,7 @@ def RegionalExchangeCapacity_Constraint(M: 'TemoaModel', r_e, r_i, p, t, v): # ============================================================================ -def create_geography_sets(M: 'TemoaModel'): +def create_geography_sets(M: 'TemoaModel') -> None: """ Populates dictionaries related to inter-regional commodity exchange. @@ -130,7 +137,7 @@ def create_geography_sets(M: 'TemoaModel'): region_from, region_to = r.split('-', 1) - lifetime = value(M.LifetimeProcess[r, t, v]) + lifetime: float = value(M.LifetimeProcess[r, t, v]) for p in M.time_optimize: if p >= v and v + lifetime > p: M.exportRegions.setdefault((region_from, p, i), set()).add((region_to, t, v, o)) diff --git a/temoa/components/limits.py b/temoa/components/limits.py index 24730bef5..4e8d310f9 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -12,13 +12,14 @@ import sys from logging import getLogger -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any -from pyomo.environ import Constraint, value +from pyomo.environ import Constraint, quicksum, value import temoa.components.geography as geography import temoa.components.technology as technology from temoa.components.utils import Operator, get_variable_efficiency, operator_expression +from temoa.types import Period, Region, Technology, Vintage if TYPE_CHECKING: from temoa.core.model import TemoaModel @@ -30,18 +31,20 @@ # ============================================================================ -def LimitTechInputSplitConstraintIndices(M: 'TemoaModel'): - indices = set( +def LimitTechInputSplitConstraintIndices( + M: 'TemoaModel', +) -> set[tuple[Region, Period, str, str, str, str, Vintage, str]]: + indices = { (r, p, s, d, i, t, v, op) for r, p, i, t, op in M.inputSplitVintages if t not in M.tech_annual for v in M.inputSplitVintages[r, p, i, t, op] for s in M.TimeSeason[p] for d in M.time_of_day - ) - ann_indices = set( + } + ann_indices = { (r, p, i, t, op) for r, p, i, t, op in M.inputSplitVintages if t in M.tech_annual - ) + } if len(ann_indices) > 0: msg = ( 'Warning: Annual technologies included in LimitTechInputSplit table. ' @@ -52,39 +55,45 @@ def LimitTechInputSplitConstraintIndices(M: 'TemoaModel'): return indices -def LimitTechInputSplitAnnualConstraintIndices(M: 'TemoaModel'): - indices = set( +def LimitTechInputSplitAnnualConstraintIndices( + M: 'TemoaModel', +) -> set[tuple[Region, Period, str, str, Vintage, str]]: + indices = { (r, p, i, t, v, op) for r, p, i, t, op in M.inputSplitAnnualVintages if t in M.tech_annual for v in M.inputSplitAnnualVintages[r, p, i, t, op] - ) + } return indices -def LimitTechInputSplitAverageConstraintIndices(M: 'TemoaModel'): - indices = set( +def LimitTechInputSplitAverageConstraintIndices( + M: 'TemoaModel', +) -> set[tuple[Region, Period, str, str, Vintage, str]]: + indices = { (r, p, i, t, v, op) for r, p, i, t, op in M.inputSplitAnnualVintages if t not in M.tech_annual for v in M.inputSplitAnnualVintages[r, p, i, t, op] - ) + } return indices -def LimitTechOutputSplitConstraintIndices(M: 'TemoaModel'): - indices = set( +def LimitTechOutputSplitConstraintIndices( + M: 'TemoaModel', +) -> set[tuple[Region, Period, str, str, str, Vintage, str, str]]: + indices = { (r, p, s, d, t, v, o, op) for r, p, t, o, op in M.outputSplitVintages if t not in M.tech_annual for v in M.outputSplitVintages[r, p, t, o, op] for s in M.TimeSeason[p] for d in M.time_of_day - ) - ann_indices = set( + } + ann_indices = { (r, p, t, o, op) for r, p, t, o, op in M.outputSplitVintages if t in M.tech_annual - ) + } if len(ann_indices) > 0: msg = ( 'Warning: Annual technologies included in LimitTechOutputSplit table. ' @@ -95,77 +104,85 @@ def LimitTechOutputSplitConstraintIndices(M: 'TemoaModel'): return indices -def LimitTechOutputSplitAnnualConstraintIndices(M: 'TemoaModel'): - indices = set( +def LimitTechOutputSplitAnnualConstraintIndices( + M: 'TemoaModel', +) -> set[tuple[Region, Period, str, Vintage, str, str]]: + indices = { (r, p, t, v, o, op) for r, p, t, o, op in M.outputSplitAnnualVintages if t in M.tech_annual for v in M.outputSplitAnnualVintages[r, p, t, o, op] - ) + } return indices -def LimitTechOutputSplitAverageConstraintIndices(M: 'TemoaModel'): - indices = set( +def LimitTechOutputSplitAverageConstraintIndices( + M: 'TemoaModel', +) -> set[tuple[Region, Period, str, Vintage, str, str]]: + indices = { (r, p, t, v, o, op) for r, p, t, o, op in M.outputSplitAnnualVintages if t not in M.tech_annual for v in M.outputSplitAnnualVintages[r, p, t, o, op] - ) + } return indices -def LimitGrowthCapacityIndices(M: 'TemoaModel'): - indices = set( +def LimitGrowthCapacityIndices(M: 'TemoaModel') -> set[tuple[Region, Period, Technology, str]]: + indices = { (r, p, t, op) for r, t, op in M.LimitGrowthCapacity.sparse_iterkeys() for p in M.time_optimize - ) + } return indices -def LimitDegrowthCapacityIndices(M: 'TemoaModel'): - indices = set( +def LimitDegrowthCapacityIndices(M: 'TemoaModel') -> set[tuple[Region, Period, Technology, str]]: + indices = { (r, p, t, op) for r, t, op in M.LimitDegrowthCapacity.sparse_iterkeys() for p in M.time_optimize - ) + } return indices -def LimitGrowthNewCapacityIndices(M: 'TemoaModel'): - indices = set( +def LimitGrowthNewCapacityIndices(M: 'TemoaModel') -> set[tuple[Region, Period, Technology, str]]: + indices = { (r, p, t, op) for r, t, op in M.LimitGrowthNewCapacity.sparse_iterkeys() for p in M.time_optimize - ) + } return indices -def LimitDegrowthNewCapacityIndices(M: 'TemoaModel'): - indices = set( +def LimitDegrowthNewCapacityIndices(M: 'TemoaModel') -> set[tuple[Region, Period, Technology, str]]: + indices = { (r, p, t, op) for r, t, op in M.LimitDegrowthNewCapacity.sparse_iterkeys() for p in M.time_optimize - ) + } return indices -def LimitGrowthNewCapacityDeltaIndices(M: 'TemoaModel'): - indices = set( +def LimitGrowthNewCapacityDeltaIndices( + M: 'TemoaModel', +) -> set[tuple[Region, Period, Technology, str]]: + indices = { (r, p, t, op) for r, t, op in M.LimitGrowthNewCapacityDelta.sparse_iterkeys() for p in M.time_optimize - ) + } return indices -def LimitDegrowthNewCapacityDeltaIndices(M: 'TemoaModel'): - indices = set( +def LimitDegrowthNewCapacityDeltaIndices( + M: 'TemoaModel', +) -> set[tuple[Region, Period, Technology, str]]: + indices = { (r, p, t, op) for r, t, op in M.LimitDegrowthNewCapacityDelta.sparse_iterkeys() for p in M.time_optimize - ) + } return indices @@ -175,7 +192,7 @@ def LimitDegrowthNewCapacityDeltaIndices(M: 'TemoaModel'): # @deprecated('Deprecated. Use LimitActivityGroupShare instead') # doesn't play well with pyomo -def RenewablePortfolioStandard_Constraint(M: 'TemoaModel', r, p, g): +def RenewablePortfolioStandard_Constraint(M: 'TemoaModel', r: Region, p: Period, g: str) -> Any: r""" Allows users to specify the share of electricity generation in a region coming from RPS-eligible technologies. @@ -184,7 +201,7 @@ def RenewablePortfolioStandard_Constraint(M: 'TemoaModel', r, p, g): # the super set we want. We can also generalise this to all groups and so # it has been deprecated in favour of the LimitActivityGroupShare constraint. - inp = sum( + inp = quicksum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] for t in M.tech_group_members[g] for (_t, v) in M.processReservePeriods.get((r, p), []) @@ -195,7 +212,7 @@ def RenewablePortfolioStandard_Constraint(M: 'TemoaModel', r, p, g): for S_o in M.processOutputsByInput[r, p, t, v, S_i] ) - total_inp = sum( + total_inp = quicksum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] for (t, v) in M.processReservePeriods[r, p] for s in M.TimeSeason[p] @@ -208,7 +225,7 @@ def RenewablePortfolioStandard_Constraint(M: 'TemoaModel', r, p, g): return expr -def LimitResource_Constraint(M: 'TemoaModel', r, t, op): +def LimitResource_Constraint(M: 'TemoaModel', r: Region, t: Technology, op: str) -> Any: r""" The LimitResource constraint sets a limit on the available resource of a @@ -233,7 +250,7 @@ def LimitResource_Constraint(M: 'TemoaModel', r, t, op): regions = geography.gather_group_regions(M, r) techs = technology.gather_group_techs(M, t) - activity = sum( + activity = quicksum( M.V_FlowOutAnnual[_r, p, S_i, _t, S_v, S_o] for _t in techs if _t in M.tech_annual @@ -244,7 +261,7 @@ def LimitResource_Constraint(M: 'TemoaModel', r, t, op): for S_i in M.processInputs[_r, p, _t, S_v] for S_o in M.processOutputsByInput[_r, p, _t, S_v, S_i] ) - activity += sum( + activity += quicksum( M.V_FlowOut[_r, p, s, d, S_i, _t, S_v, S_o] for _t in techs if _t not in M.tech_annual @@ -263,7 +280,9 @@ def LimitResource_Constraint(M: 'TemoaModel', r, t, op): return expr -def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): +def LimitActivityShare_Constraint( + M: 'TemoaModel', r: Region, p: Period, g1: str, g2: str, op: str +) -> Any: r""" Limits the activity of a given technology or group as a fraction of another technology or group, summed over a period. This can be used to set, for example, @@ -282,7 +301,7 @@ def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): regions = geography.gather_group_regions(M, r) sub_group = technology.gather_group_techs(M, g1) - sub_activity = sum( + sub_activity = quicksum( M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] for S_t in sub_group if S_t not in M.tech_annual @@ -293,7 +312,7 @@ def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): for s in M.TimeSeason[p] for d in M.time_of_day ) - sub_activity += sum( + sub_activity += quicksum( M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] for S_t in sub_group if S_t in M.tech_annual @@ -304,7 +323,7 @@ def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): ) super_group = technology.gather_group_techs(M, g2) - super_activity = sum( + super_activity = quicksum( M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] for S_t in super_group if S_t not in M.tech_annual @@ -315,7 +334,7 @@ def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): for s in M.TimeSeason[p] for d in M.time_of_day ) - super_activity += sum( + super_activity += quicksum( M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] for S_t in super_group if S_t in M.tech_annual @@ -341,7 +360,9 @@ def LimitActivityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): return expr -def LimitCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): +def LimitCapacityShare_Constraint( + M: 'TemoaModel', r: Region, p: Period, g1: str, g2: str, op: str +) -> Any: r""" The LimitCapacityShare constraint limits the available capacity of a given technology or technology group as a fraction of another technology or group. @@ -350,7 +371,7 @@ def LimitCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): regions = geography.gather_group_regions(M, r) sub_group = technology.gather_group_techs(M, g1) - sub_capacity = sum( + sub_capacity = quicksum( M.V_CapacityAvailableByPeriodAndTech[_r, p, _t] for _t in sub_group for _r in regions @@ -358,7 +379,7 @@ def LimitCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): ) super_group = technology.gather_group_techs(M, g2) - super_capacity = sum( + super_capacity = quicksum( M.V_CapacityAvailableByPeriodAndTech[_r, p, _t] for _t in super_group for _r in regions @@ -372,7 +393,9 @@ def LimitCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): return expr -def LimitNewCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): +def LimitNewCapacityShare_Constraint( + M: 'TemoaModel', r: Region, p: Period, g1: str, g2: str, op: str +) -> Any: r""" The LimitNewCapacityShare constraint limits the share of new capacity of a given technology or group as a fraction of another technology or @@ -381,7 +404,7 @@ def LimitNewCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): regions = geography.gather_group_regions(M, r) sub_group = technology.gather_group_techs(M, g1) - sub_new_cap = sum( + sub_new_cap = quicksum( M.V_NewCapacity[_r, _t, p] for _t in sub_group for _r in regions @@ -389,7 +412,7 @@ def LimitNewCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): ) super_group = technology.gather_group_techs(M, g2) - super_new_cap = sum( + super_new_cap = quicksum( M.V_NewCapacity[_r, _t, p] for _t in super_group for _r in regions @@ -403,7 +426,9 @@ def LimitNewCapacityShare_Constraint(M: 'TemoaModel', r, p, g1, g2, op): return expr -def LimitAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o, op): +def LimitAnnualCapacityFactor_Constraint( + M: 'TemoaModel', r: Region, p: Period, t: Technology, o: str, op: str +) -> Any: r""" The LimitAnnualCapacityFactor sets an upper bound on the annual capacity factor from a specific technology. The first portion of the constraint pertains to @@ -431,7 +456,7 @@ def LimitAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o, op): return Constraint.Skip if t not in M.tech_annual: - activity_rpt = sum( + activity_rpt = quicksum( M.V_FlowOut[_r, p, s, d, S_i, t, S_v, o] for _r in regions for S_v in M.processVintages.get((_r, p, t), []) @@ -440,14 +465,14 @@ def LimitAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o, op): for d in M.time_of_day ) else: - activity_rpt = sum( + activity_rpt = quicksum( M.V_FlowOutAnnual[_r, p, S_i, t, S_v, o] for _r in regions for S_v in M.processVintages.get((_r, p, t), []) for S_i in M.processInputs[_r, p, t, S_v] ) - possible_activity_rpt = sum( + possible_activity_rpt = quicksum( M.V_CapacityAvailableByPeriodAndTech[_r, p, t] * value(M.CapacityToActivity[_r, t]) for _r in regions ) @@ -459,7 +484,9 @@ def LimitAnnualCapacityFactor_Constraint(M: 'TemoaModel', r, p, t, o, op): return expr -def LimitSeasonalCapacityFactor_Constraint(M: 'TemoaModel', r, p, s, t, op): +def LimitSeasonalCapacityFactor_Constraint( + M: 'TemoaModel', r: Region, p: Period, s: str, t: Technology, op: str +) -> Any: r""" The LimitSeasonalCapacityFactor sets an upper bound on the seasonal capacity factor from a specific technology. The first portion of the constraint pertains to @@ -487,7 +514,7 @@ def LimitSeasonalCapacityFactor_Constraint(M: 'TemoaModel', r, p, s, t, op): return Constraint.Skip if t not in M.tech_annual: - activity_rpst = sum( + activity_rpst = quicksum( M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] for _r in regions for S_v in M.processVintages[_r, p, t] @@ -496,7 +523,7 @@ def LimitSeasonalCapacityFactor_Constraint(M: 'TemoaModel', r, p, s, t, op): for d in M.time_of_day ) else: - activity_rpst = sum( + activity_rpst = quicksum( M.V_FlowOutAnnual[_r, p, S_i, t, S_v, S_o] * M.SegFracPerSeason[p, s] for _r in regions for S_v in M.processVintages[_r, p, t] @@ -504,7 +531,7 @@ def LimitSeasonalCapacityFactor_Constraint(M: 'TemoaModel', r, p, s, t, op): for S_o in M.processOutputsByInput[_r, p, t, S_v, S_i] ) - possible_activity_rpst = sum( + possible_activity_rpst = quicksum( M.V_CapacityAvailableByPeriodAndTech[_r, p, t] * value(M.CapacityToActivity[_r, t]) * value(M.SegFracPerSeason[p, s]) @@ -518,19 +545,29 @@ def LimitSeasonalCapacityFactor_Constraint(M: 'TemoaModel', r, p, s, t, op): return expr -def LimitTechInputSplit_Constraint(M: 'TemoaModel', r, p, s, d, i, t, v, op): +def LimitTechInputSplit_Constraint( + M: 'TemoaModel', + r: Region, + p: Period, + s: str, + d: str, + i: str, + t: Technology, + v: Vintage, + op: str, +) -> Any: r""" Allows users to limit shares of commodity inputs to a process producing a single output. These shares can vary by model time period. See LimitTechOutputSplit_Constraint for an analogous explanation. Under this constraint, only the technologies with variable output at the timeslice level (i.e., NOT in the :code:`tech_annual` set) are considered.""" - inp = sum( + inp = quicksum( M.V_FlowOut[r, p, s, d, i, t, v, S_o] / get_variable_efficiency(M, r, p, s, d, i, t, v, S_o) for S_o in M.processOutputsByInput[r, p, t, v, i] ) - total_inp = sum( + total_inp = quicksum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] / get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) for S_i in M.processInputs[r, p, t, v] @@ -543,19 +580,21 @@ def LimitTechInputSplit_Constraint(M: 'TemoaModel', r, p, s, d, i, t, v, op): return expr -def LimitTechInputSplitAnnual_Constraint(M: 'TemoaModel', r, p, i, t, v, op): +def LimitTechInputSplitAnnual_Constraint( + M: 'TemoaModel', r: Region, p: Period, i: str, t: Technology, v: Vintage, op: str +) -> Any: r""" Allows users to limit shares of commodity inputs to a process producing a single output. These shares can vary by model time period. See LimitTechOutputSplitAnnual_Constraint for an analogous explanation. Under this function, only the technologies with constant annual output (i.e., members of the :code:`tech_annual` set) are considered.""" - inp = sum( + inp = quicksum( M.V_FlowOutAnnual[r, p, i, t, v, S_o] / value(M.Efficiency[r, i, t, v, S_o]) for S_o in M.processOutputsByInput[r, p, t, v, i] ) - total_inp = sum( + total_inp = quicksum( M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] / value(M.Efficiency[r, S_i, t, v, S_o]) for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] @@ -567,7 +606,9 @@ def LimitTechInputSplitAnnual_Constraint(M: 'TemoaModel', r, p, i, t, v, op): return expr -def LimitTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v, op: str): +def LimitTechInputSplitAverage_Constraint( + M: 'TemoaModel', r: Region, p: Period, i: str, t: Technology, v: Vintage, op: str +) -> Any: r""" Allows users to limit shares of commodity inputs to a process producing a single output. Under this constraint, only the technologies with variable @@ -576,7 +617,7 @@ def LimitTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v, op: st 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( + inp = quicksum( M.V_FlowOut[r, p, S_s, S_d, i, t, v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) for S_s in M.TimeSeason[p] @@ -584,7 +625,7 @@ def LimitTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v, op: st for S_o in M.processOutputsByInput[r, p, t, v, i] ) - total_inp = sum( + total_inp = quicksum( M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) for S_s in M.TimeSeason[p] @@ -599,7 +640,17 @@ def LimitTechInputSplitAverage_Constraint(M: 'TemoaModel', r, p, i, t, v, op: st return expr -def LimitTechOutputSplit_Constraint(M: 'TemoaModel', r, p, s, d, t, v, o, op): +def LimitTechOutputSplit_Constraint( + M: 'TemoaModel', + r: Region, + p: Period, + s: str, + d: str, + t: Technology, + v: Vintage, + o: str, + op: str, +) -> Any: r""" Some processes take a single input and make multiple outputs, and the user would like to @@ -634,11 +685,11 @@ def LimitTechOutputSplit_Constraint(M: 'TemoaModel', r, p, s, d, t, v, o, op): TOS_{r, p, t, o} \cdot \sum_{I, O, t \not \in T^{a}} \textbf{FO}_{r, p, s, d, i, t, v, o} \forall \{r, p, s, d, t, v, o\} \in \Theta_{\text{LimitTechOutputSplit}}""" - out = sum( + out = quicksum( M.V_FlowOut[r, p, s, d, S_i, t, v, o] for S_i in M.processInputsByOutput[r, p, t, v, o] ) - total_out = sum( + total_out = quicksum( M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] @@ -650,7 +701,9 @@ def LimitTechOutputSplit_Constraint(M: 'TemoaModel', r, p, s, d, t, v, o, op): return expr -def LimitTechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o, op): +def LimitTechOutputSplitAnnual_Constraint( + M: 'TemoaModel', r: Region, p: Period, t: Technology, v: Vintage, o: str, op: str +) -> Any: r""" This constraint operates similarly to LimitTechOutputSplit_Constraint. However, under this function, only the technologies with constant annual @@ -664,11 +717,11 @@ def LimitTechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o, op): TOS_{r, p, t, o} \cdot \sum_{I, O, T^{a}} \textbf{FOA}_{r, p, s, d, i, t \in T^{a}, v, o} \forall \{r, p, t \in T^{a}, v, o\} \in \Theta_{\text{LimitTechOutputSplitAnnual}}""" - out = sum( + out = quicksum( M.V_FlowOutAnnual[r, p, S_i, t, v, o] for S_i in M.processInputsByOutput[r, p, t, v, o] ) - total_out = sum( + total_out = quicksum( M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] @@ -680,7 +733,9 @@ def LimitTechOutputSplitAnnual_Constraint(M: 'TemoaModel', r, p, t, v, o, op): return expr -def LimitTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o, op): +def LimitTechOutputSplitAverage_Constraint( + M: 'TemoaModel', r: Region, p: Period, t: Technology, v: Vintage, o: str, op: str +) -> Any: r""" Allows users to limit shares of commodity outputs from a process. Under this constraint, only the technologies with variable @@ -689,14 +744,14 @@ def LimitTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o, op): so even though it applies to technologies with variable output at the timeslice level, the constraint only fixes the output shares over the course of a year.""" - out = sum( + out = quicksum( M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, o] for S_i in M.processInputsByOutput[r, p, t, v, o] for S_s in M.TimeSeason[p] for S_d in M.time_of_day ) - total_out = sum( + total_out = quicksum( M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] for S_i in M.processInputs[r, p, t, v] for S_o in M.processOutputsByInput[r, p, t, v, S_i] @@ -710,7 +765,7 @@ def LimitTechOutputSplitAverage_Constraint(M: 'TemoaModel', r, p, t, v, o, op): return expr -def LimitEmission_Constraint(M: 'TemoaModel', r, p, e, op): +def LimitEmission_Constraint(M: 'TemoaModel', r: Region, p: Period, e: str, op: str) -> Any: r""" A modeler can track emissions through use of the :code:`commodity_emissions` @@ -752,7 +807,7 @@ def LimitEmission_Constraint(M: 'TemoaModel', r, p, e, op): # Flex flows are deducted from V_FlowOut, so it is NOT NEEDED to tax them again. (See commodity balance constr) # Curtailment does not draw any inputs, so it seems logical that curtailed flows not be taxed either - process_emissions = sum( + process_emissions = quicksum( M.V_FlowOut[reg, p, S_s, S_d, S_i, S_t, S_v, S_o] * value(M.EmissionActivity[reg, e, S_i, S_t, S_v, S_o]) for reg in regions @@ -764,7 +819,7 @@ def LimitEmission_Constraint(M: 'TemoaModel', r, p, e, op): for S_d in M.time_of_day ) - process_emissions_annual = sum( + process_emissions_annual = quicksum( M.V_FlowOutAnnual[reg, p, S_i, S_t, S_v, S_o] * value(M.EmissionActivity[reg, e, S_i, S_t, S_v, S_o]) for reg in regions @@ -774,7 +829,7 @@ def LimitEmission_Constraint(M: 'TemoaModel', r, p, e, op): if (reg, p, S_t, S_v) in M.processInputs ) - embodied_emissions = sum( + embodied_emissions = quicksum( M.V_NewCapacity[reg, t, v] * value(M.EmissionEmbodied[reg, e, t, v]) / value(M.PeriodLength[v]) @@ -783,7 +838,7 @@ def LimitEmission_Constraint(M: 'TemoaModel', r, p, e, op): if v == p and S_r == reg and S_e == e ) - retirement_emissions = sum( + retirement_emissions = quicksum( M.V_AnnualRetirement[reg, p, t, v] * value(M.EmissionEndOfLife[reg, e, t, v]) for reg in regions for (S_r, S_e, t, v) in M.EmissionEndOfLife.sparse_iterkeys() @@ -809,17 +864,23 @@ def LimitEmission_Constraint(M: 'TemoaModel', r, p, e, op): return expr -def LimitGrowthCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): +def LimitGrowthCapacityConstraint_rule( + M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str +) -> Any: r"""Constrain ramp up rate of available capacity""" return LimitGrowthCapacity(M, r, p, t, op, False) -def LimitDegrowthCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): +def LimitDegrowthCapacityConstraint_rule( + M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str +) -> Any: r"""Constrain ramp down rate of available capacity""" return LimitGrowthCapacity(M, r, p, t, op, True) -def LimitGrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): +def LimitGrowthCapacity( + M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str, degrowth: bool = False +) -> Any: r""" Constrain the change of capacity available between periods. Forces the model to ramp up and down the availability of new technologies @@ -858,9 +919,9 @@ def LimitGrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): CapRPT = M.V_CapacityAvailableByPeriodAndTech # relevant r, p, t indices - cap_rpt = set((_r, _p, _t) for _r, _p, _t in CapRPT.keys() if _t in techs and _r in regions) + cap_rpt = {(_r, _p, _t) for _r, _p, _t in CapRPT.keys() if _t in techs and _r in regions} # periods the technology can have capacity in this region (sorted) - periods = sorted(set(_p for _r, _p, _t in cap_rpt)) + periods = sorted({_p for _r, _p, _t in cap_rpt}) if len(periods) == 0: if p == M.time_optimize.first(): @@ -891,7 +952,7 @@ def LimitGrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): logger.warning(msg) # sum available capacity in this period - capacity = sum(CapRPT[_r, _p, _t] for _r, _p, _t in cap_rpt if _p == p) + capacity = quicksum(CapRPT[_r, _p, _t] for _r, _p, _t in cap_rpt if _p == p) if p == M.time_optimize.first(): # First future period. Grab available capacity in last existing period @@ -919,17 +980,23 @@ def LimitGrowthCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): return expr -def LimitGrowthNewCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): +def LimitGrowthNewCapacityConstraint_rule( + M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str +) -> Any: r"""Constrain ramp up rate of new capacity deployment""" return LimitGrowthNewCapacity(M, r, p, t, op, False) -def LimitDegrowthNewCapacityConstraint_rule(M: 'TemoaModel', r, p, t, op): +def LimitDegrowthNewCapacityConstraint_rule( + M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str +) -> Any: r"""Constrain ramp down rate of new capacity deployment""" return LimitGrowthNewCapacity(M, r, p, t, op, True) -def LimitGrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): +def LimitGrowthNewCapacity( + M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str, degrowth: bool = False +) -> Any: r""" Constrain the change of new capacity deployed between periods. Forces the model to ramp up and down the deployment of new technologies @@ -969,9 +1036,9 @@ def LimitGrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False) NewCapRTV = M.V_NewCapacity # relevant r, t, v indices - cap_rtv = set((_r, _t, _v) for _r, _t, _v in NewCapRTV.keys() if _t in techs and _r in regions) + cap_rtv = {(_r, _t, _v) for _r, _t, _v in NewCapRTV.keys() if _t in techs and _r in regions} # periods the technology can be built in this region (sorted) - periods = sorted(set(_v for _r, _t, _v in cap_rtv)) + periods = sorted({_v for _r, _t, _v in cap_rtv}) if len(periods) == 0: if p == M.time_optimize.first(): @@ -1002,7 +1069,7 @@ def LimitGrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False) logger.warning(msg) # sum new capacity in this period - new_cap = sum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p) + new_cap = quicksum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p) if p == M.time_optimize.first(): # First future period. Grab last existing vintage @@ -1028,17 +1095,23 @@ def LimitGrowthNewCapacity(M: 'TemoaModel', r, p, t, op, degrowth: bool = False) return expr -def LimitGrowthNewCapacityDeltaConstraint_rule(M: 'TemoaModel', r, p, t, op): +def LimitGrowthNewCapacityDeltaConstraint_rule( + M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str +) -> Any: r"""Constrain ramp up rate of change in new capacity deployment""" return LimitGrowthNewCapacityDelta(M, r, p, t, op, False) -def LimitDegrowthNewCapacityDeltaConstraint_rule(M: 'TemoaModel', r, p, t, op): +def LimitDegrowthNewCapacityDeltaConstraint_rule( + M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str +) -> Any: r"""Constrain ramp down rate of change in new capacity deployment""" return LimitGrowthNewCapacityDelta(M, r, p, t, op, True) -def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = False): +def LimitGrowthNewCapacityDelta( + M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str, degrowth: bool = False +) -> Any: r""" Constrain the acceleration of new capacity deployed between periods. Forces the model to ramp up and down the change in deployment of new technologies @@ -1081,9 +1154,9 @@ def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = F NewCapRTV = M.V_NewCapacity # relevant r, t, v indices - cap_rtv = set((_r, _t, _v) for _r, _t, _v in NewCapRTV.keys() if _t in techs and _r in regions) + cap_rtv = {(_r, _t, _v) for _r, _t, _v in NewCapRTV.keys() if _t in techs and _r in regions} # periods the technology can be built in this region (sorted) - periods = sorted(set(_v for _r, _t, _v in cap_rtv)) + periods = sorted({_v for _r, _t, _v in cap_rtv}) if len(periods) == 0: if p == M.time_optimize.first(): @@ -1162,7 +1235,7 @@ def LimitGrowthNewCapacityDelta(M: 'TemoaModel', r, p, t, op, degrowth: bool = F return expr -def LimitActivity_Constraint(M: 'TemoaModel', r, p, t, op): +def LimitActivity_Constraint(M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str) -> Any: r""" Sets a limit on the activity from a specific technology. @@ -1191,7 +1264,7 @@ def LimitActivity_Constraint(M: 'TemoaModel', r, p, t, op): regions = geography.gather_group_regions(M, r) techs = technology.gather_group_techs(M, t) - activity = sum( + activity = quicksum( M.V_FlowOut[_r, p, s, d, S_i, _t, S_v, S_o] for _t in techs if _t not in M.tech_annual @@ -1202,7 +1275,7 @@ def LimitActivity_Constraint(M: 'TemoaModel', r, p, t, op): for s in M.TimeSeason[p] for d in M.time_of_day ) - activity += sum( + activity += quicksum( M.V_FlowOutAnnual[_r, p, S_i, _t, S_v, S_o] for _t in techs if _t in M.tech_annual @@ -1220,7 +1293,9 @@ def LimitActivity_Constraint(M: 'TemoaModel', r, p, t, op): return expr -def LimitNewCapacity_Constraint(M: 'TemoaModel', r, p, t, op): +def LimitNewCapacity_Constraint( + M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str +) -> Any: r""" The LimitNewCapacity constraint sets a limit on the newly installed capacity of a given technology or group in a given year. Note that the indices for these constraints are region, @@ -1236,12 +1311,12 @@ def LimitNewCapacity_Constraint(M: 'TemoaModel', r, p, t, op): regions = geography.gather_group_regions(M, r) techs = technology.gather_group_techs(M, t) cap_lim = value(M.LimitNewCapacity[r, p, t, op]) - new_cap = sum(M.V_NewCapacity[_r, _t, p] for _t in techs for _r in regions) + new_cap = quicksum(M.V_NewCapacity[_r, _t, p] for _t in techs for _r in regions) expr = operator_expression(new_cap, Operator(op), cap_lim) return expr -def LimitCapacity_Constraint(M: 'TemoaModel', r, p, t, op): +def LimitCapacity_Constraint(M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str) -> Any: r""" The LimitCapacity constraint sets a limit on the available capacity of a @@ -1257,7 +1332,7 @@ def LimitCapacity_Constraint(M: 'TemoaModel', r, p, t, op): regions = geography.gather_group_regions(M, r) techs = technology.gather_group_techs(M, t) cap_lim = value(M.LimitCapacity[r, p, t, op]) - capacity = sum( + capacity = quicksum( M.V_CapacityAvailableByPeriodAndTech[_r, p, _t] for _t in techs for _r in regions ) expr = operator_expression(capacity, Operator(op), cap_lim) @@ -1269,7 +1344,7 @@ def LimitCapacity_Constraint(M: 'TemoaModel', r, p, t, op): # ============================================================================ -def create_limit_vintage_sets(M: 'TemoaModel'): +def create_limit_vintage_sets(M: 'TemoaModel') -> None: """ Populates vintage-specific dictionaries for input/output split limit constraints. diff --git a/temoa/components/operations.py b/temoa/components/operations.py index 7b9a9a84a..c76804da8 100644 --- a/temoa/components/operations.py +++ b/temoa/components/operations.py @@ -13,9 +13,12 @@ from logging import getLogger from typing import TYPE_CHECKING -from pyomo.core import Set from pyomo.environ import Constraint, value +from temoa.types import ExprLike +from temoa.types.core_types import Period, Region, Season, Technology, TimeOfDay, Vintage +from temoa.types.index_types import RegionPeriodSeasonTimeOfDayTechVintage + if TYPE_CHECKING: from temoa.core.model import TemoaModel @@ -26,48 +29,56 @@ # ============================================================================ -def BaseloadDiurnalConstraintIndices(M: 'TemoaModel'): - indices = set( +def BaseloadDiurnalConstraintIndices( + M: 'TemoaModel', +) -> set[RegionPeriodSeasonTimeOfDayTechVintage]: + indices = { (r, p, s, d, t, v) for r, p, t in M.baseloadVintages for v in M.baseloadVintages[r, p, t] for s in M.TimeSeason[p] for d in M.time_of_day - ) + } return indices -def RampUpDayConstraintIndices(M: 'TemoaModel'): - indices = set( +def RampUpDayConstraintIndices( + M: 'TemoaModel', +) -> set[RegionPeriodSeasonTimeOfDayTechVintage]: + indices = { (r, p, s, d, t, v) for r, p, t in M.rampUpVintages for v in M.rampUpVintages[r, p, t] for s in M.TimeSeason[p] for d in M.time_of_day - ) + } return indices -def RampDownDayConstraintIndices(M: 'TemoaModel'): - indices = set( +def RampDownDayConstraintIndices( + M: 'TemoaModel', +) -> set[RegionPeriodSeasonTimeOfDayTechVintage]: + indices = { (r, p, s, d, t, v) for r, p, t in M.rampDownVintages for v in M.rampDownVintages[r, p, t] for s in M.TimeSeason[p] for d in M.time_of_day - ) + } return indices -def RampUpSeasonConstraintIndices(M: 'TemoaModel'): +def RampUpSeasonConstraintIndices( + M: 'TemoaModel', +) -> set[tuple[Region, Period, Season, Season, Technology, Vintage]]: if M.TimeSequencing.first() == 'consecutive_days': - return Set.Skip # dont need this constraint + return set() # s, s_next indexing ensures we dont build redundant constraints - indices = set( + indices = { (r, p, s, s_next, t, v) for r, p, t in M.rampUpVintages for v in M.rampUpVintages[r, p, t] @@ -77,19 +88,20 @@ def RampUpSeasonConstraintIndices(M: 'TemoaModel'): for s_next in ( M.sequential_to_season[p, s_seq_next], ) # next sequential season's matching season - if s_next - != M.time_next[p, s, M.time_of_day.last()][0] # to avoid redundancy on RampDay constraint - ) + if s_next != M.time_next[p, s, M.time_of_day.last()][0] + } return indices -def RampDownSeasonConstraintIndices(M: 'TemoaModel'): +def RampDownSeasonConstraintIndices( + M: 'TemoaModel', +) -> set[tuple[Region, Period, Season, Season, Technology, Vintage]]: if M.TimeSequencing.first() == 'consecutive_days': - return Set.Skip # dont need this constraint + return set() # s, s_next indexing ensures we dont build redundant constraints - indices = set( + indices = { (r, p, s, s_next, t, v) for r, p, t in M.rampDownVintages for v in M.rampDownVintages[r, p, t] @@ -98,9 +110,8 @@ def RampDownSeasonConstraintIndices(M: 'TemoaModel'): for s_next in ( M.sequential_to_season[p, s_seq_next], ) # next sequential season's matching season - if s_next - != M.time_next[p, s, M.time_of_day.last()][0] # to avoid redundancy on RampDay constraint - ) + if s_next != M.time_next[p, s, M.time_of_day.last()][0] + } return indices @@ -110,7 +121,15 @@ def RampDownSeasonConstraintIndices(M: 'TemoaModel'): # ============================================================================ -def BaseloadDiurnal_Constraint(M: 'TemoaModel', r, p, s, d, t, v): +def BaseloadDiurnal_Constraint( + M: 'TemoaModel', + r: Region, + p: Period, + s: Season, + d: TimeOfDay, + t: Technology, + v: Vintage, +) -> ExprLike: r""" Some electric generators cannot ramp output over a short period of time (e.g., @@ -184,7 +203,7 @@ def BaseloadDiurnal_Constraint(M: 'TemoaModel', r, p, s, d, t, v): # ============================================================================ -def create_operational_vintage_sets(M: 'TemoaModel'): +def create_operational_vintage_sets(M: 'TemoaModel') -> None: """ Populates vintage-based dictionaries for technologies with special operational characteristics like curtailment, baseload, storage, ramping, and reserves. @@ -220,7 +239,15 @@ def create_operational_vintage_sets(M: 'TemoaModel'): M.isSeasonalStorage[t] = t in M.tech_seasonal_storage -def RampUpDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): +def RampUpDay_Constraint( + M: 'TemoaModel', + r: Region, + p: Period, + s: Season, + d: TimeOfDay, + t: Technology, + v: Vintage, +) -> ExprLike: r""" One of two constraints built from the RampUpHourly table, along with the RampUpSeason_Constraint. RampUpDay constrains ramp rates between time slices @@ -321,7 +348,15 @@ def RampUpDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): return expr -def RampDownDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): +def RampDownDay_Constraint( + M: 'TemoaModel', + r: Region, + p: Period, + s: Season, + d: TimeOfDay, + t: Technology, + v: Vintage, +) -> ExprLike: r""" Similar to the :code`RampUpDay` constraint, we use the :code:`RampDownDay` @@ -396,7 +431,15 @@ def RampDownDay_Constraint(M: 'TemoaModel', r, p, s, d, t, v): return expr -def RampUpSeason_Constraint(M: 'TemoaModel', r, p, s, s_next, t, v): +def RampUpSeason_Constraint( + M: 'TemoaModel', + r: Region, + p: Period, + s: Season, + s_next: Season, + t: Technology, + v: Vintage, +) -> ExprLike: r""" Constrains the ramp up rate of activity between time slices at the boundary of sequential seasons. Same as RampUpDay but only applies to the boundary @@ -455,7 +498,15 @@ def RampUpSeason_Constraint(M: 'TemoaModel', r, p, s, s_next, t, v): return expr -def RampDownSeason_Constraint(M: 'TemoaModel', r, p, s, s_next, t, v): +def RampDownSeason_Constraint( + M: 'TemoaModel', + r: Region, + p: Period, + s: Season, + s_next: Season, + t: Technology, + v: Vintage, +) -> ExprLike: r""" Constrains the ramp down rate of activity between time slices at the boundary of sequential seasons. Same as RampDownDay but only applies to the boundary diff --git a/temoa/components/reserves.py b/temoa/components/reserves.py index a0d69cfcb..db5c01a36 100644 --- a/temoa/components/reserves.py +++ b/temoa/components/reserves.py @@ -17,6 +17,7 @@ if TYPE_CHECKING: from temoa.core.model import TemoaModel + from temoa.types import ExprLike logger = getLogger(__name__) @@ -25,15 +26,15 @@ # ============================================================================ -def ReserveMarginIndices(M: 'TemoaModel'): - indices = set( +def ReserveMarginIndices(M: 'TemoaModel') -> set[tuple[str, int, str, str]]: + indices = { (r, p, s, d) for r in M.PlanningReserveMargin.sparse_iterkeys() for p in M.time_optimize if (r, p) in M.processReservePeriods for s in M.TimeSeason[p] for d in M.time_of_day - ) + } return indices @@ -43,7 +44,7 @@ def ReserveMarginIndices(M: 'TemoaModel'): # ============================================================================ -def ReserveMarginDynamic(M: 'TemoaModel', r, p, s, d): +def ReserveMarginDynamic(M: 'TemoaModel', r: str, p: int, s: str, d: str) -> 'ExprLike': r""" A dynamic alternative to the traditional, static reserve margin constraint. Capacity values are calculated from availability of generation in each hour—like an operating reserve margin—\ @@ -152,7 +153,7 @@ def ReserveMarginDynamic(M: 'TemoaModel', r, p, s, d): return available -def ReserveMarginStatic(M: 'TemoaModel', r, p, s, d): +def ReserveMarginStatic(M: 'TemoaModel', r: str, p: int, s: str, d: str) -> 'ExprLike': r""" During each period :math:`p`, the sum of capacity values of all reserve @@ -231,7 +232,7 @@ def ReserveMarginStatic(M: 'TemoaModel', r, p, s, d): # ============================================================================ -def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): +def ReserveMargin_Constraint(M: 'TemoaModel', r: str, p: int, s: str, d: str) -> 'ExprLike': # Get available generation in this time slice depending on method specified in config file match M.ReserveMarginMethod.first(): case 'static': @@ -262,7 +263,7 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r, p, s, d): if S_o in M.commodity_demand else value(M.SegFrac[p, s, d]) ) - * M.V_FlowOutAnnual[r, p, s, d, S_i, t, S_v, S_o] + * M.V_FlowOutAnnual[r, p, S_i, t, S_v, S_o] for (t, S_v) in M.processReservePeriods[r, p] if t in M.tech_annual for S_i in M.processInputs[r, p, t, S_v] diff --git a/temoa/components/storage.py b/temoa/components/storage.py index 4efff8174..f140298ee 100644 --- a/temoa/components/storage.py +++ b/temoa/components/storage.py @@ -15,6 +15,7 @@ from pyomo.environ import Constraint, value +from ..types import ExprLike, Period, Region, Season, Technology, TimeOfDay, Vintage from .utils import Operator, get_variable_efficiency, operator_expression if TYPE_CHECKING: @@ -26,25 +27,34 @@ # ============================================================================ -def StorageLevelVariableIndices(M: 'TemoaModel'): +def StorageLevelVariableIndices( + M: 'TemoaModel', +) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]] | None: return M.storageLevelIndices_rpsdtv -def SeasonalStorageLevelVariableIndices(M: 'TemoaModel'): +def SeasonalStorageLevelVariableIndices( + M: 'TemoaModel', +) -> set[tuple[Region, Period, Season, Technology, Vintage]] | None: return M.seasonalStorageLevelIndices_rpstv -def SeasonalStorageConstraintIndices(M: 'TemoaModel'): - indices = set( - (r, p, s, d, t, v) - for r, p, s, t, v in M.seasonalStorageLevelIndices_rpstv - for d in M.time_of_day - ) - - return indices +def SeasonalStorageConstraintIndices( + M: 'TemoaModel', +) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]]: + if M.seasonalStorageLevelIndices_rpstv: + indices = { + (r, p, s, d, t, v) + for r, p, s, t, v in M.seasonalStorageLevelIndices_rpstv + for d in M.time_of_day + } + return indices + return set() -def StorageConstraintIndices(M: 'TemoaModel'): +def StorageConstraintIndices( + M: 'TemoaModel', +) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]] | None: return M.storageLevelIndices_rpsdtv @@ -55,7 +65,9 @@ def StorageConstraintIndices(M: 'TemoaModel'): # --- Core Energy Balance Constraints --- -def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): +def StorageEnergy_Constraint( + M: 'TemoaModel', r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage +) -> ExprLike: r""" This constraint enforces the continuity of storage level between time slices. storage level in the next time slice (:math:`s_{next}, d_{next}`) is equal to @@ -97,6 +109,8 @@ def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): stored_energy = charge - discharge + s_next: Season + d_next: TimeOfDay s_next, d_next = M.time_next[p, s, d] expr = ( @@ -107,7 +121,9 @@ def StorageEnergy_Constraint(M: 'TemoaModel', r, p, s, d, t, v): return expr -def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_seq, t, v): +def SeasonalStorageEnergy_Constraint( + M: 'TemoaModel', r: Region, p: Period, s_seq: str, t: Technology, v: Vintage +) -> ExprLike: r""" This constraint enforces the continuity of state of charge between seasons for seasonal storage. Sequential season storage level increases by the matched season's net charge @@ -147,7 +163,7 @@ def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_seq, t, v): are each one day. """ - s = M.sequential_to_season[p, s_seq] + s: Season = M.sequential_to_season[p, s_seq] # This is the sum of all input=i sent TO storage tech t of vintage v with # output=o in p,s @@ -166,8 +182,8 @@ def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_seq, t, v): for S_i in M.processInputsByOutput[r, p, t, v, S_o] ) - s_seq_next = M.time_next_sequential[p, s_seq] - s_next = M.sequential_to_season[p, s_seq_next] + s_seq_next: str = M.time_next_sequential[p, s_seq] + s_next: Season = M.sequential_to_season[p, s_seq_next] # Flows and StorageLevel are normalised to the number of days in the non-sequential season, so must # be adjusted to the number of days in the sequential season @@ -196,7 +212,9 @@ def SeasonalStorageEnergy_Constraint(M: 'TemoaModel', r, p, s_seq, t, v): # --- Capacity and Rate Limit Constraints --- -def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): +def StorageEnergyUpperBound_Constraint( + M: 'TemoaModel', r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage +) -> ExprLike: r""" This constraint ensures that the amount of energy stored does not exceed the upper bound set by the energy capacity of the storage device, as calculated @@ -251,7 +269,9 @@ def StorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s, d, t, v): return expr -def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_seq, d, t, v): +def SeasonalStorageEnergyUpperBound_Constraint( + M: 'TemoaModel', r: Region, p: Period, s_seq: str, d: TimeOfDay, t: Technology, v: Vintage +) -> ExprLike: r""" Builds off of StorageEnergyUpperBound_Constraint. Enforces the max charge capacity of seasonal storage, summing the real storage level with the superimposed sequential @@ -304,7 +324,7 @@ def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_seq, d, Unadjusted energy upper bound constraint for seasonal storage. """ - s = M.sequential_to_season[p, s_seq] + s: Season = M.sequential_to_season[p, s_seq] energy_capacity = ( M.V_Capacity[r, p, t, v] @@ -327,7 +347,9 @@ def SeasonalStorageEnergyUpperBound_Constraint(M: 'TemoaModel', r, p, s_seq, d, return expr -def StorageChargeRate_Constraint(M: 'TemoaModel', r, p, s, d, t, v): +def StorageChargeRate_Constraint( + M: 'TemoaModel', r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage +) -> ExprLike: r""" This constraint ensures that the charge rate of the storage unit is @@ -363,7 +385,9 @@ def StorageChargeRate_Constraint(M: 'TemoaModel', r, p, s, d, t, v): return expr -def StorageDischargeRate_Constraint(M: 'TemoaModel', r, p, s, d, t, v): +def StorageDischargeRate_Constraint( + M: 'TemoaModel', r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage +) -> ExprLike: r""" This constraint ensures that the discharge rate of the storage unit @@ -397,7 +421,9 @@ def StorageDischargeRate_Constraint(M: 'TemoaModel', r, p, s, d, t, v): return expr -def StorageThroughput_Constraint(M: 'TemoaModel', r, p, s, d, t, v): +def StorageThroughput_Constraint( + M: 'TemoaModel', r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage +) -> ExprLike: r""" It is not enough to only limit the charge and discharge rate separately. We also @@ -438,7 +464,16 @@ def StorageThroughput_Constraint(M: 'TemoaModel', r, p, s, d, t, v): # A limit but more cohesive here than in limits.py -def LimitStorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v, op): +def LimitStorageFraction_Constraint( + M: 'TemoaModel', + r: Region, + p: Period, + s: Season, + d: TimeOfDay, + t: Technology, + v: Vintage, + op: str, +) -> ExprLike: r""" This constraint is used if the users wishes to force a specific storage charge level @@ -473,7 +508,7 @@ def LimitStorageFraction_Constraint(M: 'TemoaModel', r, p, s, d, t, v, op): ) if M.isSeasonalStorage[t]: - s_seq = s # sequential season + s_seq: str = s # sequential season s = M.sequential_to_season[p, s_seq] # non-sequential season # adjust the storage level to the individual-day level diff --git a/temoa/components/technology.py b/temoa/components/technology.py index a6ce9881f..9cf608eea 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -10,16 +10,15 @@ - Validating model inputs related to technologies, efficiencies, and commodities. """ +from collections.abc import Iterable +from logging import getLogger from typing import TYPE_CHECKING +from pyomo.environ import value + if TYPE_CHECKING: from temoa.core.model import TemoaModel - - -from logging import getLogger -from typing import Iterable - -from pyomo.environ import value + from temoa.types import Period, Region, Technology, Vintage logger = getLogger(__name__) @@ -30,12 +29,11 @@ def gather_group_techs(M: 'TemoaModel', t_or_g: str) -> Iterable[str]: if t_or_g in M.tech_group_names: - techs = M.tech_group_members[t_or_g] + return M.tech_group_members[t_or_g] elif '+' in t_or_g: - techs = t_or_g.split('+') + return t_or_g.split('+') else: - techs = (t_or_g,) - return techs + return (t_or_g,) # ============================================================================ @@ -43,7 +41,9 @@ def gather_group_techs(M: 'TemoaModel', t_or_g: str) -> Iterable[str]: # ============================================================================ -def ModelProcessLifeIndices(M: 'TemoaModel'): +def ModelProcessLifeIndices( + M: 'TemoaModel', +) -> set[tuple['Region', 'Period', 'Technology', 'Vintage']] | None: """ Returns the set of sensical (region, period, tech, vintage) tuples. The tuple indicates the periods in which a process is active, distinct from TechLifeFracIndices that @@ -52,17 +52,19 @@ def ModelProcessLifeIndices(M: 'TemoaModel'): return M.activeActivity_rptv -def LifetimeProcessIndices(M: 'TemoaModel'): +def LifetimeProcessIndices(M: 'TemoaModel') -> set[tuple['Region', 'Technology', 'Vintage']]: """ Based on the Efficiency parameter's indices, this function returns the set of process indices that may be specified in the LifetimeProcess parameter. """ - indices = set((r, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) + indices = {(r, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys()} return indices -def get_default_survival(M: 'TemoaModel', r, p, t, v): +def get_default_survival( + M: 'TemoaModel', r: 'Region', p: 'Period', t: 'Technology', v: 'Vintage' +) -> float: """ Getting LifetimeSurvivalCurve where it is not defined If this is a survival curve process, return 0 (likely beyond EOL) @@ -71,7 +73,9 @@ def get_default_survival(M: 'TemoaModel', r, p, t, v): return 0.0 if M.isSurvivalCurveProcess[r, t, v] else 1.0 -def get_default_process_lifetime(M: 'TemoaModel', r, t, v): +def get_default_process_lifetime( + M: 'TemoaModel', r: 'Region', t: 'Technology', v: 'Vintage' +) -> int: """ This initializer used to initialize the LifetimeProcess parameter from LifetimeTech where needed @@ -85,10 +89,12 @@ def get_default_process_lifetime(M: 'TemoaModel', r, t, v): :param v: vintage :return: the final lifetime value """ - return M.LifetimeTech[r, t] + return value(M.LifetimeTech[r, t]) -def ParamProcessLifeFraction_rule(M: 'TemoaModel', r, p, t, v): +def ParamProcessLifeFraction_rule( + M: 'TemoaModel', r: 'Region', p: 'Period', t: 'Technology', v: 'Vintage' +) -> float: r""" Get the effective capacity of a process :math:`` in a period :math:`p`. @@ -120,7 +126,7 @@ def ParamProcessLifeFraction_rule(M: 'TemoaModel', r, p, t, v): # ============================================================================ -def populate_core_dictionaries(M: 'TemoaModel'): +def populate_core_dictionaries(M: 'TemoaModel') -> None: """ Populates the core sparse dictionaries from the `Efficiency` parameter. @@ -207,7 +213,7 @@ def populate_core_dictionaries(M: 'TemoaModel'): M.processPeriods[r, t, v].add(p) -def CreateSurvivalCurve(M: 'TemoaModel'): +def CreateSurvivalCurve(M: 'TemoaModel') -> None: rtv_interpolated = set() # so we only need one warning for r, _, t, v, _ in M.Efficiency.sparse_iterkeys(): @@ -216,13 +222,13 @@ def CreateSurvivalCurve(M: 'TemoaModel'): # Collect rptv indices into (r, t, v): p dictionary for r, p, t, v in M.LifetimeSurvivalCurve.sparse_iterkeys(): if (r, t, v) not in M.survivalCurvePeriods: - M.survivalCurvePeriods[r, t, v] = list() - M.survivalCurvePeriods[r, t, v].append(p) + M.survivalCurvePeriods[r, t, v] = set() + M.survivalCurvePeriods[r, t, v].add(p) M.isSurvivalCurveProcess[r, t, v] = True # Go through all the periods for each (r, t, v) in order for r, t, v in M.survivalCurvePeriods: - periods_rtv = sorted(M.survivalCurvePeriods[r, t, v]) + periods_rtv: list[int] = sorted(M.survivalCurvePeriods[r, t, v]) p_first = periods_rtv[0] p_last = periods_rtv[-1] @@ -236,12 +242,12 @@ def CreateSurvivalCurve(M: 'TemoaModel'): raise ValueError(msg) if value(M.LifetimeSurvivalCurve[r, v, t, v]) != 1: - msg = ( - 'LifetimeSurvivalCurve must begin at 1 for calculating annual retirements. ', - f'Got {value(M.LifetimeSurvivalCurve[r, v, t, v])} for ({r}, {v}, {t}, {v})', + msg_str = ( + 'LifetimeSurvivalCurve must begin at 1 for calculating annual retirements. ' + f'Got {value(M.LifetimeSurvivalCurve[r, v, t, v])} for ({r}, {v}, {t}, {v})' ) - logger.error(msg) - raise ValueError(msg) + logger.error(msg_str) + raise ValueError(msg_str) # Collect a list of processes that needed to be interpolated, for warning if periods_rtv != list(range(p_first, p_last + 1, 1)): @@ -310,8 +316,7 @@ def CreateSurvivalCurve(M: 'TemoaModel'): logger.error(msg) raise ValueError(msg) - M.survivalCurvePeriods[r, t, v].extend(between_periods) - M.survivalCurvePeriods[r, t, v] = set(M.survivalCurvePeriods[r, t, v]) + M.survivalCurvePeriods[r, t, v].update(between_periods) if rtv_interpolated: msg = ( @@ -322,17 +327,17 @@ def CreateSurvivalCurve(M: 'TemoaModel'): logger.info(msg) -def CheckEfficiencyIndices(M: 'TemoaModel'): +def CheckEfficiencyIndices(M: 'TemoaModel') -> None: """ Ensure that there are no unused items in any of the Efficiency index sets. """ # TODO: This could be upgraded to scan for finer resolution # by checking by REGION and PERIOD... Each region/period is unique. - c_physical = set(i for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) - c_physical = c_physical | set(i for r, i, t, v in M.ConstructionInput.sparse_iterkeys()) - techs = set(t for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) - c_outputs = set(o for r, i, t, v, o in M.Efficiency.sparse_iterkeys()) - c_outputs = c_outputs | set(o for r, t, v, o in M.EndOfLifeOutput.sparse_iterkeys()) + c_physical = {i for r, i, t, v, o in M.Efficiency.sparse_iterkeys()} + c_physical = c_physical | {i for r, i, t, v in M.ConstructionInput.sparse_iterkeys()} + techs = {t for r, i, t, v, o in M.Efficiency.sparse_iterkeys()} + c_outputs = {o for r, i, t, v, o in M.Efficiency.sparse_iterkeys()} + c_outputs = c_outputs | {o for r, t, v, o in M.EndOfLifeOutput.sparse_iterkeys()} symdiff = c_physical.symmetric_difference(M.commodity_physical) if symdiff: @@ -341,8 +346,8 @@ def CheckEfficiencyIndices(M: 'TemoaModel'): 'the following elements to the Set commodity_physical.' '\n\n Element(s): {}' ) - symdiff = (str(i) for i in symdiff) - f_msg = msg.format(', '.join(symdiff)) + symdiff_str: set[str] = {str(i) for i in symdiff} + f_msg = msg.format(', '.join(symdiff_str)) logger.error(f_msg) raise ValueError(f_msg) @@ -353,8 +358,8 @@ def CheckEfficiencyIndices(M: 'TemoaModel'): 'the following technology(ies) to the tech_resource or ' 'tech_production Sets.\n\n Technology(ies): {}' ) - symdiff = (str(i) for i in symdiff) - f_msg = msg.format(', '.join(symdiff)) + symdiff_str2: set[str] = {str(i) for i in symdiff} + f_msg = msg.format(', '.join(symdiff_str2)) logger.error(f_msg) raise ValueError(f_msg) @@ -365,14 +370,14 @@ def CheckEfficiencyIndices(M: 'TemoaModel'): 'following elements to the commodity_demand Set.' '\n\n Element(s): {}' ) - diff = (str(i) for i in diff) - f_msg = msg.format(', '.join(diff)) + diff_str = (str(i) for i in diff) + f_msg = msg.format(', '.join(diff_str)) logger.error(f_msg) raise ValueError(f_msg) -def CheckEfficiencyVariable(M: 'TemoaModel'): - count_rpitvo = dict() +def CheckEfficiencyVariable(M: 'TemoaModel') -> None: + count_rpitvo = {} # Pull non-variable efficiency by default for r, i, t, v, o in M.Efficiency.sparse_iterkeys(): if (r, t, v) not in M.processPeriods: diff --git a/temoa/components/time.py b/temoa/components/time.py index dab6b5345..484ecd351 100644 --- a/temoa/components/time.py +++ b/temoa/components/time.py @@ -18,6 +18,7 @@ if TYPE_CHECKING: from temoa.core.model import TemoaModel + from temoa.types import Period, Season, TimeOfDay logger = getLogger(__name__) @@ -29,7 +30,7 @@ # ============================================================================ -def validate_time(M: 'TemoaModel'): +def validate_time(M: 'TemoaModel') -> None: """ We check for integer status here, rather than asking Pyomo to do this via a 'within=Integers' clause in the definition so that we can have a very @@ -42,7 +43,9 @@ def validate_time(M: 'TemoaModel'): if isinstance(year, int): continue - msg = f'Set "time_exist" requires integer-only elements.\n\n Invalid element: "{year}"' + msg: str = ( + f'Set "time_exist" requires integer-only elements.\n\n Invalid element: "{year}"' + ) logger.error(msg) raise Exception(msg) @@ -68,8 +71,8 @@ def validate_time(M: 'TemoaModel'): # Ensure that the time_exist < time_future if len(M.time_exist) > 0: - max_exist = max(M.time_exist) - min_horizon = min(M.time_future) + max_exist: int = max(M.time_exist) + min_horizon: int = min(M.time_future) if not (max_exist < min_horizon): msg = ( @@ -82,17 +85,21 @@ def validate_time(M: 'TemoaModel'): logger.debug('Finished validating time') -def validate_SegFrac(M: 'TemoaModel'): +def validate_SegFrac(M: 'TemoaModel') -> None: """Ensure that the segment fractions adds up to 1""" for p in M.time_optimize: - expected_keys = set((p, s, d) for s in M.TimeSeason[p] for d in M.time_of_day) - keys = set((_p, s, d) for _p, s, d in M.SegFrac.sparse_iterkeys() if _p == p) + expected_keys: set[tuple[int, str, str]] = { + (p, s, d) for s in M.TimeSeason[p] for d in M.time_of_day + } + keys: set[tuple[int, str, str]] = { + (_p, s, d) for _p, s, d in M.SegFrac.sparse_iterkeys() if _p == p + } if expected_keys != keys: - extra = keys.difference(expected_keys) - missing = expected_keys.difference(keys) - msg = ( + extra: set[tuple[int, str, str]] = keys.difference(expected_keys) + missing: set[tuple[int, str, str]] = expected_keys.difference(keys) + msg: str = ( 'TimeSegmentFraction elements for period {} do not match TimeSeason and TimeOfDay.' '\n\nIndices missing from TimeSegmentFraction:\n{}' '\n\nIndices in TimeSegmentFraction missing from TimeSeason/TimeOfDay:\n{}' @@ -100,23 +107,24 @@ def validate_SegFrac(M: 'TemoaModel'): logger.error(msg) raise ValueError(msg) - total = sum(M.SegFrac[k] for k in keys) + total: float = sum(value(M.SegFrac[k]) for k in keys) if abs(float(total) - 1.0) > 0.001: # We can't explicitly test for "!= 1.0" because of incremental rounding # errors associated with the specification of SegFrac by time slice, # but we check to make sure it is within the specified tolerance. - def get_str_padding(obj): + def get_str_padding(obj: object) -> int: return len(str(obj)) - key_padding = max(map(get_str_padding, keys)) + key_padding: int = max(map(get_str_padding, keys)) - fmt = '%%-%ds = %%s' % key_padding # Works out to something like "%-25s = %s" - items = sorted([(k, M.SegFrac[k]) for k in keys]) - items = '\n '.join(fmt % (str(k), v) for k, v in items) + items_list: list[tuple[tuple[object, object, object], object]] = sorted( + [(k, M.SegFrac[k]) for k in keys] + ) + items: str = '\n '.join(f'{str(k):<{key_padding}} = {v}' for k, v in items_list) msg = ( 'The values of TimeSegmentFraction do not sum to 1 for period {}. ' @@ -127,7 +135,7 @@ def get_str_padding(obj): raise Exception(msg) -def validate_TimeNext(M: 'TemoaModel'): +def validate_TimeNext(M: 'TemoaModel') -> None: """ If using this table, check that defined states are actually valid. TimeSegmentFraction is already compared to other tables so just compare to SegFrac. @@ -136,14 +144,16 @@ def validate_TimeNext(M: 'TemoaModel'): if M.TimeSequencing.first() != 'manual': return - segfrac_psd = set(M.SegFrac.sparse_iterkeys()) - time_next_psd = set((p, s, d) for p, s, d, s_next, d_next in M.TimeNext) - time_next_psd_next = set((p, s_next, d_next) for p, s, d, s_next, d_next in M.TimeNext) + segfrac_psd: set[tuple[int, str, str]] = set(M.SegFrac.sparse_iterkeys()) + time_next_psd: set[tuple[int, str, str]] = {(p, s, d) for p, s, d, s_next, d_next in M.TimeNext} + time_next_psd_next: set[tuple[int, str, str]] = { + (p, s_next, d_next) for p, s, d, s_next, d_next in M.TimeNext + } - missing_psd = segfrac_psd.difference(time_next_psd) - missing_psd_next = segfrac_psd.difference(time_next_psd_next) + missing_psd: set[tuple[int, str, str]] = segfrac_psd.difference(time_next_psd) + missing_psd_next: set[tuple[int, str, str]] = segfrac_psd.difference(time_next_psd_next) if missing_psd or missing_psd_next: - msg = ( + msg: str = ( 'Failed to build state sequence. ' '\nThese states from TimeSegmentFraction were not given a next state:\n{}\n' '\nThese states from TimeSegmentFraction do not follow any state:\n{}' @@ -157,30 +167,30 @@ def validate_TimeNext(M: 'TemoaModel'): # ============================================================================ -def init_set_time_optimize(M: 'TemoaModel'): +def init_set_time_optimize(M: 'TemoaModel') -> list[int]: """Initializes the `time_optimize` set (all future years except the last).""" return sorted(M.time_future)[:-1] -def init_set_vintage_exist(M: 'TemoaModel'): +def init_set_vintage_exist(M: 'TemoaModel') -> list[int]: """Initializes the `vintage_exist` set.""" return sorted(M.time_exist) -def init_set_vintage_optimize(M: 'TemoaModel'): +def init_set_vintage_optimize(M: 'TemoaModel') -> list[int]: """Initializes the `vintage_optimize` set.""" return sorted(M.time_optimize) -def SegFracPerSeason_rule(M: 'TemoaModel', p, s): +def SegFracPerSeason_rule(M: 'TemoaModel', p: 'Period', s: 'Season') -> float: """Rule to calculate the total fraction of a period represented by a season.""" return sum(value(M.SegFrac[p, s, d]) for d in M.time_of_day if (p, s, d) in M.SegFrac) -def ParamPeriodLength(M: 'TemoaModel', p): +def ParamPeriodLength(M: 'TemoaModel', p: 'Period') -> int: """Rule to calculate the length of each optimization period in years.""" - periods = sorted(M.time_future) - i = periods.index(p) + periods: list[int] = sorted(M.time_future) + i: int = periods.index(p) return periods[i + 1] - periods[i] @@ -189,13 +199,15 @@ def ParamPeriodLength(M: 'TemoaModel', p): # ============================================================================ -def loop_period_next_timeslice(M: 'TemoaModel', p, s, d) -> tuple[str, str]: +def loop_period_next_timeslice( + M: 'TemoaModel', p: 'Period', s: 'Season', d: 'TimeOfDay' +) -> tuple['Season', 'TimeOfDay']: # Final time slice of final season (end of period) # Loop state back to initial state of first season # Loop the period if s == M.TimeSeason[p].last() and d == M.time_of_day.last(): - s_next = M.TimeSeason[p].first() - d_next = M.time_of_day.first() + s_next: 'Season' = M.TimeSeason[p].first() + d_next: 'TimeOfDay' = M.time_of_day.first() # Last time slice of any season that is NOT the last season # Carry state to initial state of next season @@ -214,9 +226,11 @@ def loop_period_next_timeslice(M: 'TemoaModel', p, s, d) -> tuple[str, str]: return s_next, d_next -def loop_season_next_timeslice(M: 'TemoaModel', p, s, d) -> tuple[str, str]: +def loop_season_next_timeslice( + M: 'TemoaModel', p: 'Period', s: 'Season', d: 'TimeOfDay' +) -> tuple[str, str]: # We loop each season so never carrying state between seasons - s_next = s + s_next: str = s # Final time slice of any season # Loop state back to initial state of same season @@ -238,13 +252,13 @@ def loop_season_next_timeslice(M: 'TemoaModel', p, s, d) -> tuple[str, str]: # ============================================================================ -def CreateTimeSequence(M: 'TemoaModel'): +def CreateTimeSequence(M: 'TemoaModel') -> None: logger.debug('Creating sequence of time slices.') # Establishing sequence of states match M.TimeSequencing.first(): case 'consecutive_days': - msg = 'Running a consecutive days database.' + msg: str = 'Running a consecutive days database.' for p in M.time_optimize: for s, d in M.TimeSeason[p] * M.time_of_day: M.time_next[p, s, d] = loop_period_next_timeslice(M, p, s, d) @@ -276,7 +290,9 @@ def CreateTimeSequence(M: 'TemoaModel'): # Superimposed sequential seasons for p in M.time_optimize: - seasons = [(s_seq, s) for _p, s_seq, s in M.ordered_season_sequential if _p == p] + seasons: list[tuple[str, str]] = [ + (s_seq, s) for _p, s_seq, s in M.ordered_season_sequential if _p == p + ] for i, (s_seq, s) in enumerate(seasons): M.sequential_to_season[p, s_seq] = s if (s_seq, s) == seasons[-1]: @@ -287,7 +303,7 @@ def CreateTimeSequence(M: 'TemoaModel'): logger.debug('Created time sequence.') -def CreateTimeSeasonSequential(M: 'TemoaModel'): +def CreateTimeSeasonSequential(M: 'TemoaModel') -> None: if all( ( not M.tech_seasonal_storage, @@ -323,10 +339,10 @@ def CreateTimeSeasonSequential(M: 'TemoaModel'): logger.error(msg) raise ValueError(msg) - sequential = dict() - prev_n = 0 + sequential: dict[tuple[int, str], float] = {} + prev_n: float = 0 for p, s_seq, s in M.TimeSeasonSequential.sparse_iterkeys(): - num_days = value(M.TimeSeasonSequential[p, s_seq, s]) + num_days: float = value(M.TimeSeasonSequential[p, s_seq, s]) if ( M.TimeSequencing.first() == 'consecutive_days' and prev_n @@ -347,7 +363,9 @@ def CreateTimeSeasonSequential(M: 'TemoaModel'): sequential[p, s] += num_days # Check that TimeSeasonSequential num_days total to number of days in each period - count_total = dict() # {p: n} total days per period according to TimeSeasonSequential + count_total: dict[ + int, float + ] = {} # {p: n} total days per period according to TimeSeasonSequential for p in M.time_optimize: count_total[p] = sum(sequential[p, s] for _p, s in sequential if _p == p) if abs(count_total[p] - value(M.DaysPerPeriod)) >= 0.001: diff --git a/temoa/components/utils.py b/temoa/components/utils.py index 161f07004..e35eee077 100644 --- a/temoa/components/utils.py +++ b/temoa/components/utils.py @@ -13,8 +13,19 @@ from pyomo.core import Expression from pyomo.environ import value +from temoa.types import ExprLike + if TYPE_CHECKING: from temoa.core.model import TemoaModel + from temoa.types import ( + Commodity, + Period, + Region, + Season, + Technology, + TimeOfDay, + Vintage, + ) logger = getLogger(__name__) @@ -26,7 +37,7 @@ class Operator(str, Enum): GREATER_EQUAL = 'ge' -def operator_expression(lhs: Expression, operator: Operator, rhs: Expression): +def operator_expression(lhs: Expression, operator: Operator, rhs: Expression) -> ExprLike: match operator: case Operator.EQUAL: return lhs == rhs @@ -37,7 +48,17 @@ def operator_expression(lhs: Expression, operator: Operator, rhs: Expression): raise ValueError(f'Invalid operator: {operator!r}') -def get_variable_efficiency(M: 'TemoaModel', r, p, s, d, i, t, v, o) -> float: +def get_variable_efficiency( + M: 'TemoaModel', + r: 'Region', + p: 'Period', + s: 'Season', + d: 'TimeOfDay', + i: 'Commodity', + t: 'Technology', + v: 'Vintage', + o: 'Commodity', +) -> float: """ Calculates the effective efficiency for a process in a specific time slice. From e23b93c1cc2d70d8e019f03c0cdf393084fb845a Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 18 Oct 2025 19:05:52 -0400 Subject: [PATCH 249/587] adding typing to temoa/data_io --- temoa/data_io/hybrid_loader.py | 203 +++++++++++++++++++++---------- temoa/data_io/loader_manifest.py | 21 ++-- 2 files changed, 150 insertions(+), 74 deletions(-) diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index 8d15f63cb..46bfd89ff 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -24,7 +24,7 @@ from collections.abc import Sequence from logging import getLogger from sqlite3 import Connection, Cursor, OperationalError -from typing import Any +from typing import cast from pyomo.core import Param, Set from pyomo.dataportal import DataPortal @@ -91,8 +91,8 @@ def __init__(self, db_connection: Connection, config: TemoaConfig) -> None: # --- Data containers and filters populated during loading --- self.manager: CommodityNetworkManager | None = None - self.efficiency_values: list[tuple] = [] - self.data: dict[str, Any] | None = None + self.efficiency_values: list[tuple[object, ...]] = [] + self.data: dict[str, object] | None = None # --- Viable sets for source-trace filtering --- self.viable_techs: ViableSet | None = None @@ -137,7 +137,7 @@ def load_data_portal(self, myopic_index: MyopicIndex | None = None) -> DataPorta return dp @staticmethod - def data_portal_from_data(data_source: dict) -> DataPortal: + def data_portal_from_data(data_source: dict[str, object]) -> DataPortal: """ Creates a DataPortal object from an existing data dictionary. Useful for model runs where the data has been modified in memory. @@ -153,7 +153,7 @@ def data_portal_from_data(data_source: dict) -> DataPortal: # Main Data Loading Engine # ================================================================================= - def create_data_dict(self, myopic_index: MyopicIndex | None = None) -> dict[str, Any]: + def create_data_dict(self, myopic_index: MyopicIndex | None = None) -> dict[str, object]: """ The main manifest-driven engine for loading model data. @@ -190,7 +190,7 @@ def create_data_dict(self, myopic_index: MyopicIndex | None = None) -> dict[str, self._build_efficiency_dataset(use_raw_data=use_raw_data, myopic_index=myopic_index) - data: dict[str, Any] = {} + data: dict[str, object] = {} cur = self.con.cursor() M = TemoaModel() @@ -274,7 +274,9 @@ def create_data_dict(self, myopic_index: MyopicIndex | None = None) -> dict[str, # ================================================================================= # Core Engine Helpers - def _fetch_data(self, cur: Cursor, item: LoadItem, mi: MyopicIndex | None) -> list[tuple]: + def _fetch_data( + self, cur: Cursor, item: LoadItem, mi: MyopicIndex | None + ) -> list[tuple[object, ...]]: """ Fetches data for a component based on its manifest item. @@ -319,8 +321,8 @@ def _fetch_data(self, cur: Cursor, item: LoadItem, mi: MyopicIndex | None) -> li raise def _filter_data( - self, values: Sequence[tuple], item: LoadItem, use_raw_data: bool - ) -> Sequence[tuple]: + self, values: Sequence[tuple[object, ...]], item: LoadItem, use_raw_data: bool + ) -> Sequence[tuple[object, ...]]: """ Applies validation filters to a list of data tuples. @@ -341,7 +343,10 @@ def _filter_data( ) def _load_component_data( - self, data: dict, component: Set | Param, values: Sequence[tuple] + self, + data: dict[str, object], + component: Set | Param, + values: Sequence[tuple[object, ...]], ) -> None: """ Loads a sequence of values into the data dictionary for a given Pyomo component. @@ -469,8 +474,11 @@ def _build_efficiency_dataset( # --- Core Model Structure --- def _load_regional_global_indices( - self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] - ): + self, + data: dict[str, object], + raw_data: Sequence[tuple[object, ...]], + filtered_data: Sequence[tuple[object, ...]], + ) -> None: """ Aggregates region and group names from the Region table and all Limit tables. """ @@ -496,30 +504,36 @@ def _load_regional_global_indices( self._load_component_data(data, M.regionalGlobalIndices, list_of_groups) def _load_tech_group_members( - self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] - ): + self, + data: dict[str, object], + raw_data: Sequence[tuple[object, ...]], + filtered_data: Sequence[tuple[object, ...]], + ) -> None: """Loads members into the indexed set `tech_group_members`.""" M = TemoaModel() validator = self.viable_techs.members if self.viable_techs else None for group_name, tech in filtered_data: if validator is None or tech in validator: store = data.get(M.tech_group_members.name, defaultdict(list)) - store[group_name].append(tech) + store[group_name].append(tech) # type: ignore[index] data[M.tech_group_members.name] = store # --- Time-Related Components --- def _load_time_season( - self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] - ): + self, + data: dict[str, object], + raw_data: Sequence[tuple[object, ...]], + filtered_data: Sequence[tuple[object, ...]], + ) -> None: """ Loads the indexed TimeSeason set and the simple time_season set, with a dynamic fallback if the table is missing. """ M = TemoaModel() mi = self.myopic_index - time_optimize = data.get('time_optimize', []) + time_optimize = cast(list[int], data.get('time_optimize', [])) - rows_to_load = [] + rows_to_load: list[tuple[object, ...]] = [] if not raw_data: logger.warning('No TimeSeason table found. Loading a single filler season "S".') rows_to_load = [(p, 'S') for p in time_optimize] @@ -533,17 +547,20 @@ def _load_time_season( data.setdefault(M.time_season.name, []) return - unique_seasons = sorted(list(set((row[1],) for row in rows_to_load))) + unique_seasons = sorted(list({(row[1],) for row in rows_to_load})) self._load_component_data(data, M.time_season, unique_seasons) for period, season in rows_to_load: store = data.get(M.TimeSeason.name, defaultdict(list)) - store[period].append(season) + store[period].append(season) # type: ignore[index] data[M.TimeSeason.name] = store def _load_time_season_sequential( - self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] - ): + self, + data: dict[str, object], + raw_data: Sequence[tuple[object, ...]], + filtered_data: Sequence[tuple[object, ...]], + ) -> None: """ Composite loader for TimeSeasonSequential and its associated index sets. """ @@ -552,10 +569,15 @@ def _load_time_season_sequential( if filtered_data: ordered_data = [row[0:3] for row in filtered_data] self._load_component_data(data, M.ordered_season_sequential, ordered_data) - seq_data = sorted(list(set((row[1],) for row in filtered_data))) + seq_data = sorted({(row[1],) for row in filtered_data}) self._load_component_data(data, M.time_season_sequential, seq_data) - def _load_seg_frac(self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple]): + def _load_seg_frac( + self, + data: dict[str, object], + raw_data: Sequence[tuple[object, ...]], + filtered_data: Sequence[tuple[object, ...]], + ) -> None: """Handles dynamic fallbacks for SegFrac if its table is missing.""" M = TemoaModel() if filtered_data: @@ -563,13 +585,16 @@ def _load_seg_frac(self, data: dict, raw_data: Sequence[tuple], filtered_data: S else: logger.warning('No TimeSegmentFraction table found. Generating default SegFrac values.') time_optimize = data.get('time_optimize', []) - fallback = [(p, 'S', 'D', 1.0) for p in time_optimize] + fallback = [(p, 'S', 'D', 1.0) for p in time_optimize] # type: ignore[attr-defined] self._load_component_data(data, M.SegFrac, fallback) # --- Capacity and Cost Components --- def _load_existing_capacity( - self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] - ): + self, + data: dict[str, object], + raw_data: Sequence[tuple[object, ...]], + filtered_data: Sequence[tuple[object, ...]], + ) -> None: """ Handles different queries for myopic vs. standard runs and also populates the `tech_exist` set. @@ -600,67 +625,90 @@ def _load_existing_capacity( self._load_component_data(data, M.tech_exist, tech_exist_data) def _load_cost_invest( - self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] - ): + self, + data: dict[str, object], + raw_data: Sequence[tuple[object, ...]], + filtered_data: Sequence[tuple[object, ...]], + ) -> None: """Handles myopic period filtering for CostInvest.""" M = TemoaModel() - mi = self.myopic_index - data_to_load = [row for row in filtered_data if not mi or row[2] >= mi.base_year] + base_year = self.myopic_index.base_year if self.myopic_index else None + data_to_load = [ + row for row in filtered_data if base_year is None or cast(int, row[2]) >= base_year + ] self._load_component_data(data, M.CostInvest, data_to_load) def _load_loan_rate( - self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] - ): + self, + data: dict[str, object], + raw_data: Sequence[tuple[object, ...]], + filtered_data: Sequence[tuple[object, ...]], + ) -> None: """Handles myopic period filtering for LoanRate.""" M = TemoaModel() mi = self.myopic_index - data_to_load = [row for row in filtered_data if not mi or row[2] >= mi.base_year] + data_to_load = [row for row in filtered_data if not mi or row[2] >= mi.base_year] # type: ignore[operator] self._load_component_data(data, M.LoanRate, data_to_load) # --- Singleton and Configuration-based Components --- def _load_days_per_period( - self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] - ): + self, + data: dict[str, object], + raw_data: Sequence[tuple[object, ...]], + filtered_data: Sequence[tuple[object, ...]], + ) -> None: """Loads the singleton DaysPerPeriod, with a fallback.""" M = TemoaModel() - value = 365 + days = 365 if filtered_data: - value = int(filtered_data[0][0]) + days = cast(int, filtered_data[0][0]) else: logger.info('No value for days_per_period found. Assuming 365 days per period.') - data[M.DaysPerPeriod.name] = {None: value} + data[M.DaysPerPeriod.name] = {None: days} def _load_global_discount_rate( - self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] - ): + self, + data: dict[str, object], + raw_data: Sequence[tuple[object, ...]], + filtered_data: Sequence[tuple[object, ...]], + ) -> None: """Loads the required singleton GlobalDiscountRate.""" M = TemoaModel() if filtered_data: - data[M.GlobalDiscountRate.name] = {None: float(filtered_data[0][0])} + data[M.GlobalDiscountRate.name] = {None: cast(float, filtered_data[0][0])} else: raise ValueError( "Missing required parameter: 'global_discount_rate' not found in MetaDataReal table." ) def _load_default_loan_rate( - self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] - ): + self, + data: dict[str, object], + raw_data: Sequence[tuple[object, ...]], + filtered_data: Sequence[tuple[object, ...]], + ) -> None: """Loads the optional singleton DefaultLoanRate.""" M = TemoaModel() if filtered_data: - data[M.DefaultLoanRate.name] = {None: float(filtered_data[0][0])} + data[M.DefaultLoanRate.name] = {None: cast(float, filtered_data[0][0])} # --- Operational Constraints and Parameters --- def _load_efficiency( - self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] - ): + self, + data: dict[str, object], + raw_data: Sequence[tuple[object, ...]], + filtered_data: Sequence[tuple[object, ...]], + ) -> None: """Loads the main Efficiency parameter, which is pre-calculated.""" M = TemoaModel() self._load_component_data(data, M.Efficiency, self.efficiency_values) def _load_linked_techs( - self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] - ): + self, + data: dict[str, object], + raw_data: Sequence[tuple[object, ...]], + filtered_data: Sequence[tuple[object, ...]], + ) -> None: """Provides critical error checking for LinkedTechs.""" item = self.manifest_map['LinkedTechs'] self._load_component_data(data, item.component, filtered_data) @@ -678,8 +726,11 @@ def _load_linked_techs( raise RuntimeError(msg % (entry,)) def _load_ramping_down( - self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] - ): + self, + data: dict[str, object], + raw_data: Sequence[tuple[object, ...]], + filtered_data: Sequence[tuple[object, ...]], + ) -> None: """Composite loader for RampDownHourly and its index set `tech_downramping`.""" M = TemoaModel() self._load_component_data(data, M.RampDownHourly, filtered_data) @@ -691,8 +742,11 @@ def _load_ramping_down( self._load_component_data(data, M.tech_downramping, tech_filtered) def _load_ramping_up( - self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] - ): + self, + data: dict[str, object], + raw_data: Sequence[tuple[object, ...]], + filtered_data: Sequence[tuple[object, ...]], + ) -> None: """Composite loader for RampUpHourly and its index set `tech_upramping`.""" M = TemoaModel() self._load_component_data(data, M.RampUpHourly, filtered_data) @@ -704,8 +758,11 @@ def _load_ramping_up( self._load_component_data(data, M.tech_upramping, tech_filtered) def _load_rps_requirement( - self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] - ): + self, + data: dict[str, object], + raw_data: Sequence[tuple[object, ...]], + filtered_data: Sequence[tuple[object, ...]], + ) -> None: """Handles deprecation warning for RenewablePortfolioStandard.""" M = TemoaModel() self._load_component_data(data, M.RenewablePortfolioStandard, filtered_data) @@ -716,8 +773,11 @@ def _load_rps_requirement( ) def _load_limit_tech_input_split( - self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] - ): + self, + data: dict[str, object], + raw_data: Sequence[tuple[object, ...]], + filtered_data: Sequence[tuple[object, ...]], + ) -> None: """Provides detailed warnings for filtered LimitTechInputSplit data.""" item = self.manifest_map['LimitTechInputSplit'] self._load_component_data(data, item.component, filtered_data) @@ -734,8 +794,11 @@ def _load_limit_tech_input_split( ) def _load_limit_tech_input_split_annual( - self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] - ): + self, + data: dict[str, object], + raw_data: Sequence[tuple[object, ...]], + filtered_data: Sequence[tuple[object, ...]], + ) -> None: """Provides detailed warnings for filtered LimitTechInputSplitAnnual data.""" item = self.manifest_map['LimitTechInputSplitAnnual'] self._load_component_data(data, item.component, filtered_data) @@ -752,8 +815,11 @@ def _load_limit_tech_input_split_annual( ) def _load_limit_tech_output_split( - self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] - ): + self, + data: dict[str, object], + raw_data: Sequence[tuple[object, ...]], + filtered_data: Sequence[tuple[object, ...]], + ) -> None: """Provides detailed warnings for filtered LimitTechOutputSplit data.""" item = self.manifest_map['LimitTechOutputSplit'] self._load_component_data(data, item.component, filtered_data) @@ -770,8 +836,11 @@ def _load_limit_tech_output_split( ) def _load_limit_tech_output_split_annual( - self, data: dict, raw_data: Sequence[tuple], filtered_data: Sequence[tuple] - ): + self, + data: dict[str, object], + raw_data: Sequence[tuple[object, ...]], + filtered_data: Sequence[tuple[object, ...]], + ) -> None: """Provides detailed warnings for filtered LimitTechOutputSplitAnnual data.""" item = self.manifest_map['LimitTechOutputSplitAnnual'] self._load_component_data(data, item.component, filtered_data) @@ -791,7 +860,7 @@ def _load_limit_tech_output_split_annual( # Finalizer Method # ================================================================================= - def load_param_idx_sets(self, data: dict) -> dict: + def load_param_idx_sets(self, data: dict[str, object]) -> dict[str, object]: """ Builds a dictionary of sparse sets used for indexing parameters. This is a final data enhancement step that runs after all primary data @@ -819,9 +888,9 @@ def load_param_idx_sets(self, data: dict) -> dict: M.RenewablePortfolioStandard.name: M.RenewablePortfolioStandardConstraint_rpg.name, } - res = {} + res: dict[str, object] = {} for p_name, s_name in param_idx_sets.items(): param_data = data.get(p_name) - if param_data: + if isinstance(param_data, dict): res[s_name] = list(param_data.keys()) return res diff --git a/temoa/data_io/loader_manifest.py b/temoa/data_io/loader_manifest.py index 552cc3d52..b0350568f 100644 --- a/temoa/data_io/loader_manifest.py +++ b/temoa/data_io/loader_manifest.py @@ -9,10 +9,17 @@ """ +from __future__ import annotations + from dataclasses import dataclass, field -from typing import Any, Optional +from typing import TYPE_CHECKING, Any + +if TYPE_CHECKING: + from pyomo.core import Param, Set -from pyomo.core import Param, Set + type ComponentType = Set | Param +else: + ComponentType = Any @dataclass @@ -40,13 +47,13 @@ class LoadItem: table is missing or returns no data. """ - component: Set | Param + component: ComponentType table: str columns: list[str] - validator_name: Optional[str] = None + validator_name: str | None = None validation_map: tuple[int, ...] = field(default_factory=tuple) - where_clause: Optional[str] = None + where_clause: str | None = None is_period_filtered: bool = True is_table_required: bool = True - custom_loader_name: Optional[str] = None - fallback_data: Optional[list[tuple[Any, ...]]] = None + custom_loader_name: str | None = None + fallback_data: list[tuple[object, ...]] | None = None From b9e542d03779f9664b784d81a593e1205494720b Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 18 Oct 2025 20:10:58 -0400 Subject: [PATCH 250/587] reflecting changes from core/model to temoa_model for back compat --- temoa/temoa_model/temoa_model.py | 172 ++++++++++++++----------------- 1 file changed, 79 insertions(+), 93 deletions(-) diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py index 0799aaca7..d52f31f3b 100755 --- a/temoa/temoa_model/temoa_model.py +++ b/temoa/temoa_model/temoa_model.py @@ -9,11 +9,11 @@ """ import logging +from typing import TYPE_CHECKING from pyomo.core import BuildCheck, Set, Var from pyomo.environ import ( AbstractModel, - Any, BuildAction, Constraint, Integers, @@ -23,6 +23,15 @@ minimize, ) +from temoa.types.core_types import Technology + +if TYPE_CHECKING: + from pyomo.environ import AbstractModel as PyomoAbstractModel + +else: + PyomoAbstractModel = AbstractModel # type: ignore[misc,assignment] + +from temoa import types as t from temoa.components import ( capacity, commodities, @@ -51,13 +60,11 @@ logger = logging.getLogger(__name__) -def CreateSparseDicts(M: 'TemoaModel'): +def CreateSparseDicts(M: 'TemoaModel') -> None: """ Creates and populates all sparse dictionaries and sets required for the model by calling component-specific precomputation functions. """ - # Initialize a set to track technologies used in the Efficiency table - M.used_techs = set() # Call the decomposed functions in logical order # 1. Populate core relationships from Efficiency table @@ -87,7 +94,7 @@ def CreateSparseDicts(M: 'TemoaModel'): logger.debug('Completed creation of SparseDicts') -class TemoaModel(AbstractModel): +class TemoaModel(PyomoAbstractModel): """ An instance of the abstract Temoa model """ @@ -95,8 +102,8 @@ class TemoaModel(AbstractModel): # this is used in several places outside this class, and this provides no-build access to it default_lifetime_tech = 40 - def __init__(M, *args, **kwargs): - AbstractModel.__init__(M, *args, **kwargs) + def __init__(M, *args: object, **kwargs: object) -> None: + PyomoAbstractModel.__init__(M, *args, **kwargs) ################################################ # Internally used Data Containers # @@ -104,91 +111,77 @@ def __init__(M, *args, **kwargs): ################################################ # Dev Note: The triple-quotes UNDER the items below pop up as dox in most IDEs - M.processInputs = dict() - M.processOutputs = dict() - M.processLoans = dict() - M.activeFlow_rpsditvo = None + M.processInputs: t.ProcessInputsDict = {} + M.processOutputs: t.ProcessOutputsDict = {} + M.processLoans: t.ProcessLoansDict = {} + M.activeFlow_rpsditvo: t.ActiveFlowSet = set() """a flow index for techs NOT in tech_annual""" - M.activeFlow_rpitvo = None + M.activeFlow_rpitvo: t.ActiveFlowAnnualSet = set() """a flow index for techs in tech_annual only""" - M.activeFlex_rpsditvo = None - M.activeFlex_rpitvo = None - M.activeFlowInStorage_rpsditvo = None - M.activeCurtailment_rpsditvo = None - M.activeActivity_rptv = None - M.storageLevelIndices_rpsdtv = None - M.seasonalStorageLevelIndices_rpstv = None + M.activeFlex_rpsditvo: t.ActiveFlexSet = set() + M.activeFlex_rpitvo: t.ActiveFlexAnnualSet = set() + M.activeFlowInStorage_rpsditvo: t.ActiveFlowInStorageSet = set() + M.activeCurtailment_rpsditvo: t.ActiveCurtailmentSet = set() + M.activeActivity_rptv: t.ActiveActivitySet = set() + M.storageLevelIndices_rpsdtv: t.StorageLevelIndicesSet = set() + M.seasonalStorageLevelIndices_rpstv: t.SeasonalStorageLevelIndicesSet = set() """currently available (within lifespan) (r, p, t, v) tuples (from M.processVintages)""" - M.activeRegionsForTech = None + M.activeRegionsForTech: t.ActiveRegionsForTechDict = {} """currently available regions by period and tech {(p, t) : r}""" - M.newCapacity_rtv = None - M.activeCapacityAvailable_rpt = None - M.activeCapacityAvailable_rptv = None - M.groupRegionActiveFlow_rpt = None # Set of valid group-region, period, tech indices - M.commodityBalance_rpc = None # Set of valid region-period-commodity indices to balance - M.commodityDStreamProcess = dict() # The downstream process of a commodity during a period - M.commodityUStreamProcess = dict() # The upstream process of a commodity during a period - M.capacityConsumptionTechs = ( - dict() - ) # New capacity consuming a commodity during a period [r,p,c] -> t - M.retirementProductionProcesses = ( - dict() - ) # Retired capacity producing a commodity during a period [r,p,c] -> t,v - M.processInputsByOutput = dict() - M.processOutputsByInput = dict() - M.processTechs = dict() - M.processReservePeriods = dict() - M.processPeriods = dict() # {(r, t, v): set(p)} - M.retirementPeriods = ( - dict() - ) # {(r, t, v): set(p)} periods in which a process can economically or naturally retire - M.processVintages = dict() - M.survivalCurvePeriods: dict[tuple, set] = ( - dict() - ) # {(r, t, v): set(p)} periods for which the process has a defined survival fraction + M.newCapacity_rtv: t.NewCapacitySet = set() + M.activeCapacityAvailable_rpt: t.ActiveCapacityAvailableSet = set() + M.activeCapacityAvailable_rptv: t.ActiveCapacityAvailableVintageSet = set() + M.groupRegionActiveFlow_rpt: t.GroupRegionActiveFlowSet = ( + set() # Set of valid group-region, period, tech indices + ) + M.commodityBalance_rpc: t.CommodityBalancedSet = ( + set() + ) # Set of valid region-period-commodity indices to balance + M.commodityDStreamProcess: t.CommodityStreamProcessDict = {} # The downstream process of a commodity during a period + M.commodityUStreamProcess: t.CommodityStreamProcessDict = {} # The upstream process of a commodity during a period + M.capacityConsumptionTechs: t.CapacityConsumptionTechsDict = {} # New capacity consuming a commodity during a period [r,p,c] -> t + M.retirementProductionProcesses: t.RetirementProductionProcessesDict = {} # Retired capacity producing a commodity during a period [r,p,c] -> t,v + M.processInputsByOutput: t.ProcessInputsByOutputDict = {} + M.processOutputsByInput: t.ProcessOutputsByInputDict = {} + M.processTechs: t.ProcessTechsDict = {} + M.processReservePeriods: t.ProcessReservePeriodsDict = {} + M.processPeriods: t.ProcessPeriodsDict = {} # {(r, t, v): set(p)} + M.retirementPeriods: t.RetirementPeriodsDict = {} # {(r, t, v): set(p)} periods in which a process can economically or naturally retire + M.processVintages: t.ProcessVintagesDict = {} + M.survivalCurvePeriods: t.SurvivalCurvePeriodsDict = {} # {(r, t, v): set(p)} periods for which the process has a defined survival fraction """current available (within lifespan) vintages {(r, p, t) : set(v)}""" - M.baseloadVintages = dict() - M.curtailmentVintages = dict() - M.storageVintages = dict() - M.rampUpVintages = dict() - M.rampDownVintages = dict() - M.inputSplitVintages = dict() - M.inputSplitAnnualVintages = dict() - M.outputSplitVintages = dict() - M.outputSplitAnnualVintages = dict() - # M.processByPeriodAndOutput = dict() # not currently used - M.exportRegions = dict() - M.importRegions = dict() + M.baseloadVintages: t.BaseloadVintagesDict = {} + M.curtailmentVintages: t.CurtailmentVintagesDict = {} + M.storageVintages: t.StorageVintagesDict = {} + M.rampUpVintages: t.RampUpVintagesDict = {} + M.rampDownVintages: t.RampDownVintagesDict = {} + M.inputSplitVintages: t.InputSplitVintagesDict = {} + M.inputSplitAnnualVintages: t.InputSplitAnnualVintagesDict = {} + M.outputSplitVintages: t.OutputSplitVintagesDict = {} + M.outputSplitAnnualVintages: t.OutputSplitAnnualVintagesDict = {} + # M.processByPeriodAndOutput = {} # not currently used + M.exportRegions: t.ExportRegionsDict = {} + M.importRegions: t.ImportRegionsDict = {} # These establish time sequencing - M.time_next = dict() # {(p, s, d): (s_next, d_next)} sequence of following time slices - M.time_next_sequential = dict() # {(p, s_seq): (s_seq_next)} next virtual storage season - M.sequential_to_season = ( - dict() - ) # {(p, s_seq): (s)} season matching this virtual storage season + M.time_next: t.TimeNextDict = {} # {(p, s, d): (s_next, d_next)} sequence of following time slices + M.time_next_sequential: t.TimeNextSequentialDict = {} # {(p, s_seq): (s_seq_next)} next virtual storage season + M.sequential_to_season: t.SequentialToSeasonDict = {} # {(p, s_seq): (s)} season matching this virtual storage season ################################################ # Switching Sets # # (to avoid slow searches in initialisation) # ################################################ - M.isEfficiencyVariable: dict[tuple, bool] = ( - dict() - ) # {(r, p, i, t, v, o): bool} which efficiencies have variable indexing - M.isCapacityFactorProcess: dict[tuple, bool] = ( - dict() - ) # {(r, p, t, v): bool} which capacity factors have have period-vintage indexing - M.isSeasonalStorage: dict[tuple, bool] = ( - dict() - ) # {t: bool} whether a storage tech is seasonal storage - M.isSurvivalCurveProcess: dict[tuple, bool] = ( - dict() - ) # {(r, t, v): bool} whether a process uses survival curves. + M.isEfficiencyVariable: t.EfficiencyVariableDict = {} # {(r, p, i, t, v, o): bool} which efficiencies have variable indexing + M.isCapacityFactorProcess: t.CapacityFactorProcessDict = {} # {(r, p, t, v): bool} which capacity factors have have period-vintage indexing + M.isSeasonalStorage: t.SeasonalStorageDict = {} # {t: bool} whether a storage tech is seasonal storage + M.isSurvivalCurveProcess: t.SurvivalCurveProcessDict = {} # {(r, t, v): bool} whether a process uses survival curves. ################################################ # Model Sets # @@ -232,7 +225,7 @@ def __init__(M, *args, **kwargs): M.regionalGlobalIndices = Set(validate=region_group_check) # Define technology-related sets - # M.tech_resource = Set() # not actually used by anything + # M.tech_resource = Set() # not actually used by M.tech_production = Set() M.tech_all = Set( initialize=M.tech_production, validate=no_slash_or_pipe @@ -264,6 +257,9 @@ def __init__(M, *args, **kwargs): M.tech_exist = Set() """techs with existing capacity, want to keep these for accounting reasons""" + M.used_techs: set[Technology] = set() + """ track techs used in Efficiency table used in CreateSparseDicts """ + # the below is a convenience for domain checking in params below that should not accept # uncap techs... M.tech_with_capacity = Set(initialize=M.tech_all - M.tech_uncap) @@ -582,23 +578,13 @@ def __init__(M, *args, **kwargs): M.LimitAnnualCapacityFactorConstraint_rpto, validate=validate_0to1 ) - M.LimitGrowthCapacity = Param( - M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any - ) - M.LimitDegrowthCapacity = Param( - M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any - ) - M.LimitGrowthNewCapacity = Param( - M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any - ) - M.LimitDegrowthNewCapacity = Param( - M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any - ) - M.LimitGrowthNewCapacityDelta = Param( - M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any - ) + M.LimitGrowthCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator) + M.LimitDegrowthCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator) + M.LimitGrowthNewCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator) + M.LimitDegrowthNewCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator) + M.LimitGrowthNewCapacityDelta = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator) M.LimitDegrowthNewCapacityDelta = Param( - M.regionalGlobalIndices, M.tech_or_group, M.operator, domain=Any + M.regionalGlobalIndices, M.tech_or_group, M.operator ) M.LimitEmissionConstraint_rpe = Set( @@ -676,7 +662,7 @@ def __init__(M, *args, **kwargs): # Storage duration is expressed in hours M.StorageDuration = Param(M.regions, M.tech_storage, default=4) - M.LinkedTechs = Param(M.regionalIndices, M.tech_all, M.commodity_emissions, within=Any) + M.LinkedTechs = Param(M.regionalIndices, M.tech_all, M.commodity_emissions) # Define parameters associated with electric sector operation M.ReserveMarginMethod = Set() # How contributions to the reserve margin are calculated @@ -1126,6 +1112,6 @@ def __init__(M, *args, **kwargs): M.progress_marker_9 = BuildAction(['Finished Constraints'], rule=progress_check) -def progress_check(M, checkpoint: str): +def progress_check(M: TemoaModel, checkpoint: str) -> None: """A quick widget which is called by BuildAction in order to log creation progress""" logger.debug('Model build progress: %s', checkpoint) From c5260a10893f24703d46a42f41703c153b9f9eb5 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 18 Oct 2025 20:11:36 -0400 Subject: [PATCH 251/587] small typing additions to assorted files --- definitions.py | 14 ++-- main.py | 4 +- .../mga_sequencer.py | 2 +- temoa/utilities/clear_db_outputs.py | 34 ++------- temoa/utilities/db_migration_to_v3.py | 71 ++++++------------- temoa/utilities/db_migration_v3_to_v3_1.py | 46 ++++-------- temoa/utilities/set_spitter.py | 35 ++------- temoa/utilities/unit_cost_explorer.py | 8 ++- 8 files changed, 60 insertions(+), 154 deletions(-) diff --git a/definitions.py b/definitions.py index 3a1682b13..908b109a4 100644 --- a/definitions.py +++ b/definitions.py @@ -2,27 +2,21 @@ top-level folder to provide project-wide definitions & references """ -# Written by: J. F. Hyink -# jeff@westernspark.us -# https://westernspark.us - -# Created on: 6/28/23 - import os from pathlib import Path - PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) -OUTPUT_PATH = None +OUTPUT_PATH: Path | None = None -def get_OUTPUT_PATH(): +def get_OUTPUT_PATH() -> Path: if OUTPUT_PATH is None: raise RuntimeError('Output path not yet defined') + # Use cast to help mypy understand the type return OUTPUT_PATH -def set_OUTPUT_PATH(path: Path): +def set_OUTPUT_PATH(path: Path) -> None: global OUTPUT_PATH OUTPUT_PATH = path diff --git a/main.py b/main.py index fe534043c..3cd1adb60 100644 --- a/main.py +++ b/main.py @@ -27,7 +27,7 @@ @deprecated('currently deprecated functionality') -def runModelUI(config_filename): +def runModelUI(config_filename: str) -> None: """This function launches the model run from the Temoa GUI""" raise NotImplementedError # solver = TemoaSolver(model, config_filename) @@ -162,7 +162,7 @@ def create_output_folder() -> Path: return output_path -def setup_logging(output_path: Path, debug_level=False): +def setup_logging(output_path: Path, debug_level: bool = False) -> None: # set up logger if debug_level: level = logging.DEBUG diff --git a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py index 66e92e567..3566fd5b0 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py +++ b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py @@ -351,7 +351,7 @@ def solve_instance(self, instance: TemoaModel) -> bool: elapsed.total_seconds(), status.name, ) - return status == pyo.TerminationCondition.optimal + return status == pyo.TerminationCondition.convergenceCriteriaSatisfied def process_solve_results(self, instance: TemoaModel): """write the results as required""" diff --git a/temoa/utilities/clear_db_outputs.py b/temoa/utilities/clear_db_outputs.py index 594c34254..bc41dcf98 100644 --- a/temoa/utilities/clear_db_outputs.py +++ b/temoa/utilities/clear_db_outputs.py @@ -1,32 +1,8 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 6/22/24 - A quick utility to clear all of the data in all of the output tables in a Temoa V3 database """ + import sqlite3 import sys from pathlib import Path @@ -49,12 +25,12 @@ print('this utility file expects a CLA for the path to the database to clear') sys.exit(-1) -target_db = sys.argv[1] +target_db_str = sys.argv[1] -proceed = input('This will clear ALL output tables in ' + target_db + '? (y/n): ') +proceed = input('This will clear ALL output tables in ' + target_db_str + '? (y/n): ') if proceed == 'y': - target_db = Path(target_db) - if not Path.exists(target_db): + target_db = Path(target_db_str) + if not target_db.exists(): print(f'path provided to database is invalid: {target_db}') sys.exit(-1) try: diff --git a/temoa/utilities/db_migration_to_v3.py b/temoa/utilities/db_migration_to_v3.py index a441049d2..e1af36e37 100644 --- a/temoa/utilities/db_migration_to_v3.py +++ b/temoa/utilities/db_migration_to_v3.py @@ -1,28 +1,4 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 3/21/24 Transition a legacy database to V3 compliant. @@ -37,7 +13,6 @@ from collections import defaultdict from pathlib import Path - parser = argparse.ArgumentParser() parser.add_argument( '--source', @@ -66,7 +41,7 @@ cur = con_new.cursor() # bring in the new schema and execute -with open(schema_file, 'r') as src: +with open(schema_file) as src: sql_script = src.read() con_new.executescript(sql_script) @@ -153,8 +128,8 @@ new_columns = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] old_columns = [c[1] for c in con_old.execute(f'PRAGMA table_info({old_name});').fetchall()] - cols = str(old_columns[0:len(new_columns)])[1:-1].replace("'","") - + cols = str(old_columns[0 : len(new_columns)])[1:-1].replace("'", '') + try: data = con_old.execute(f'SELECT {cols} FROM {old_name}').fetchall() except sqlite3.OperationalError: @@ -182,8 +157,8 @@ new_columns = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] old_columns = [c[1] for c in con_old.execute(f'PRAGMA table_info({old_name});').fetchall()] - cols = str(old_columns[0:len(new_columns)])[1:-1].replace("'","") - + cols = str(old_columns[0 : len(new_columns)])[1:-1].replace("'", '') + try: data = con_old.execute(f'SELECT {cols} FROM {old_name}').fetchall() except sqlite3.OperationalError: @@ -214,18 +189,18 @@ old_name, new_name = name_pair if old_name == '': old_name = new_name - + new_columns = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] old_columns = [c[1] for c in con_old.execute(f'PRAGMA table_info({old_name});').fetchall()] - cols = str(old_columns[0:len(new_columns)-1])[1:-1].replace("'","") - + cols = str(old_columns[0 : len(new_columns) - 1])[1:-1].replace("'", '') + try: data = con_old.execute(f'SELECT {cols} FROM {old_name}').fetchall() except sqlite3.OperationalError: print(f'mandatory table: {old_name} not found. Operation Failed') sys.exit(-1) count = 1 - num_placeholders = len(new_columns)-1 + num_placeholders = len(new_columns) - 1 for row in data: placeholders = ','.join(['?' for _ in range(num_placeholders)]) query = f'INSERT INTO {new_name} VALUES ({count}, {placeholders})' @@ -239,23 +214,23 @@ '\n --- comparing RPS groups to a common set to see if they can be combined into 1 (except global) ---' ) -groups = defaultdict(set) +groups: dict[str, set[str]] = defaultdict(set) # let's ensure all the non-global entries are consistent (same techs in each region) skip_rps = False try: - entries = con_old.execute('SELECT * FROM tech_rps').fetchall() + rps_entries = con_old.execute('SELECT * FROM tech_rps').fetchall() except sqlite3.OperationalError: print('source does not appear to include RPS techs...skipping') skip_rps = True if not skip_rps: - for region, tech, notes in entries: + for region, tech, _notes in rps_entries: groups[region].add(tech) - common = set() - for group, entries in groups.items(): + common: set[str] = set() + for group, group_entries in groups.items(): if group != 'global': - common |= set(entries) + common |= group_entries techs_common = True for group, techs in groups.items(): @@ -436,22 +411,22 @@ print('\n --- Moving scalar data elements ---') try: - data = con_old.execute('SELECT * FROM MyopicBaseyear').fetchone() + myopic_result = con_old.execute('SELECT * FROM MyopicBaseyear').fetchone() except sqlite3.OperationalError: - data = None -if data: - mby = data[0] + myopic_result = None +if myopic_result: + mby = myopic_result[0] cur.execute("INSERT OR REPLACE INTO MetaData VALUES ('myopic_base_year', ? , '')", (mby,)) print(f'transferred myopic base year: {mby}') else: print('no myopic base year discovered') try: - data = con_old.execute('SELECT * FROM GlobalDiscountRate').fetchone() + discount_result = con_old.execute('SELECT * FROM GlobalDiscountRate').fetchone() except sqlite3.OperationalError: - data = None -if data: - rate = data[0] + discount_result = None +if discount_result: + rate = discount_result[0] cur.execute( "INSERT OR REPLACE INTO MetaDataReal VALUES ('global_discount_rate', ?, '')", (rate,) ) diff --git a/temoa/utilities/db_migration_v3_to_v3_1.py b/temoa/utilities/db_migration_v3_to_v3_1.py index 893fed2b6..8c7fc4fe7 100644 --- a/temoa/utilities/db_migration_v3_to_v3_1.py +++ b/temoa/utilities/db_migration_v3_to_v3_1.py @@ -1,27 +1,4 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - -Written by: I. D. Elder -iandavidelder@gmail.com -Created on: 2025/03/14 - Transition a v3.0 database to a v3.1 database. """ @@ -33,11 +10,13 @@ import pandas as pd +from temoa.core.model import TemoaModel + # Just to get the default lifetime... this_dir = os.path.dirname(__file__) root_dir = os.path.abspath(os.path.join(this_dir, '../..')) sys.path.append(root_dir) -from temoa.core.model import TemoaModel + parser = argparse.ArgumentParser() parser.add_argument( @@ -66,7 +45,7 @@ cur = con_new.cursor() # bring in the new schema and execute -with open(schema_file, 'r') as src: +with open(schema_file) as src: sql_script = src.read() con_new.executescript(sql_script) @@ -185,7 +164,8 @@ def column_check(old_name: str, new_name: str) -> bool: all_good = all_good and column_check(old_name, new_name) for old_name, new_name in period_added_tables: all_good = all_good and column_check(old_name, new_name) -if not all_good: sys.exit(-1) +if not all_good: + sys.exit(1) # Collapse Max/Min constraint tables @@ -202,7 +182,7 @@ def column_check(old_name: str, new_name: str) -> bool: print('No data for: ' + old_name) continue - new_cols: tuple = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] + new_cols: list[str] = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] op_index = new_cols.index('operator') data = [(*row[0:op_index], operator, *row[op_index:len(new_cols)-1]) for row in data] @@ -307,14 +287,14 @@ def column_check(old_name: str, new_name: str) -> bool: for r, t in data[['region','tech']].drop_duplicates().values: periods[r, t] = [ p for p in time_optimize - if any(( + if any( v <= p < v+lifetime_process[r, t, v] for v in [ t[0] for t in con_old.execute( f'SELECT vintage FROM Efficiency WHERE region == "{r}" AND tech == "{t}"' ).fetchall() ] - )) + ) ] data['periods'] = [ periods[r, t] @@ -351,17 +331,17 @@ def column_check(old_name: str, new_name: str) -> bool: print('\n --- Making some final changes ---') -n_del = len(con_new.execute(( +n_del = len(con_new.execute( "SELECT * FROM DemandSpecificDistribution " "WHERE (region, period, demand_name) " "NOT IN (SELECT region, period, commodity FROM Demand)" -)).fetchall()) +).fetchall()) if n_del > 0: - con_new.execute(( + con_new.execute( "DELETE FROM DemandSpecificDistribution " "WHERE (region, period, demand_name) " "NOT IN (SELECT region, period, commodity FROM Demand)" - )) + ) print(f"{n_del} extraneous rows removed from DemandSpecificDistribution after adding period index") # TimeSeason unique seasons to SeasonLabel diff --git a/temoa/utilities/set_spitter.py b/temoa/utilities/set_spitter.py index 1f9dd5176..879fdc9ee 100644 --- a/temoa/utilities/set_spitter.py +++ b/temoa/utilities/set_spitter.py @@ -2,38 +2,15 @@ Quick utility to spit out the set members of a pyomo model """ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 1/16/24 - -""" +from typing import TYPE_CHECKING import pyomo.environ as pyo +if TYPE_CHECKING: + from temoa.core.model import TemoaModel + -def spit_sets(model: pyo.Model, index_sets=False): +def spit_sets(model: TemoaModel, index_sets: bool = False) -> None: """ print out the set data in pyomo pprint format :param model: a built model @@ -48,7 +25,7 @@ def spit_sets(model: pyo.Model, index_sets=False): model_sets[m_set].pprint() -def spit_params(model: pyo.Model): +def spit_params(model: TemoaModel) -> None: """ Print out the parameters in pyomo-built pprint :param model: a built model diff --git a/temoa/utilities/unit_cost_explorer.py b/temoa/utilities/unit_cost_explorer.py index 31367dd89..266585ae2 100644 --- a/temoa/utilities/unit_cost_explorer.py +++ b/temoa/utilities/unit_cost_explorer.py @@ -3,7 +3,11 @@ of storage capacity """ -from temoa._internal.temoa_rules import * +from pyomo.environ import value + +from temoa.components.costs import TotalCost_rule +from temoa.components.storage import StorageEnergyUpperBound_Constraint +from temoa.core.model import TemoaModel # Written by: J. F. Hyink # jeff@westernspark.us @@ -121,7 +125,7 @@ M.V_StorageLevel.construct() M.SegFracPerSeason.construct() -upper_limit = StorageEnergyUpperBound_Constraint(M, 'A', 2020, 'winter', 1, 'battery', 2020) +upper_limit = StorageEnergyUpperBound_Constraint(M, 'A', 2020, 'winter', '1', 'battery', 2020) print('The storage level constraint for the single period in the "super day":\n', upper_limit) # cross-check the multiplier... From 6ad7c26cc4cc09e47c41631a9ea6205450961b28 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 18 Oct 2025 22:10:30 -0400 Subject: [PATCH 252/587] adding ci type checking --- .github/workflows/ci.yml | 39 +++++++++++++++++++++++++++++++++++++-- pyproject.toml | 1 + uv.lock | 4 +++- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a1b0bc731..86e90315e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,23 @@ name: CI on: push: - branches: ["main", "temoa_alpha", "ci_testing", "1.0.0-dev-operator", "temoa_davey_code"] + branches: + [ + "main", + "temoa_alpha", + "ci_testing", + "1.0.0-dev-operator", + "temoa_davey_code", + ] pull_request: - branches: ["main", "temoa_alpha", "ci_testing", "1.0.0-dev-operator", "temoa_davey_code"] + branches: + [ + "main", + "temoa_alpha", + "ci_testing", + "1.0.0-dev-operator", + "temoa_davey_code", + ] jobs: test: @@ -32,3 +46,24 @@ jobs: - name: Run tests run: uv run pytest tests + + type-check: + name: type check + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.12"] + + steps: + - uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + enable-cache: true + + - name: Install the project + run: uv sync --all-extras --dev + + - name: Run mypy + run: uv run mypy --config-file=pyproject.toml temoa/ diff --git a/pyproject.toml b/pyproject.toml index bc753ba55..de1e8d1b6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,6 +44,7 @@ dev = [ "gurobipy>=12.0.3", "types-deprecated>=1.2.15.20250304", "ruff>=0.2.0", + "mypy>=1.0.0", "pre-commit", "pytest", "pytest-cov", diff --git a/uv.lock b/uv.lock index 3a26122be..f6ec15520 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.12" [[package]] @@ -2984,6 +2984,7 @@ plotting = [ [package.dev-dependencies] dev = [ { name = "gurobipy" }, + { name = "mypy" }, { name = "pandas-stubs" }, { name = "pre-commit" }, { name = "pytest" }, @@ -3033,6 +3034,7 @@ provides-extras = ["docs", "plotting"] [package.metadata.requires-dev] dev = [ { name = "gurobipy", specifier = ">=12.0.3" }, + { name = "mypy", specifier = ">=1.0.0" }, { name = "pandas-stubs", specifier = ">=2.3.2.250926" }, { name = "pre-commit" }, { name = "pytest" }, From 0ed8120fcb1b6c6b04f5f5b7d162c410dba1e817 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 18 Oct 2025 22:18:27 -0400 Subject: [PATCH 253/587] removing old version of temoa_model to fix typing error --- temoa/temoa_model/__init__.py | 0 temoa/temoa_model/temoa_model.py | 1117 ------------------------------ 2 files changed, 1117 deletions(-) delete mode 100644 temoa/temoa_model/__init__.py delete mode 100755 temoa/temoa_model/temoa_model.py diff --git a/temoa/temoa_model/__init__.py b/temoa/temoa_model/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/temoa/temoa_model/temoa_model.py b/temoa/temoa_model/temoa_model.py deleted file mode 100755 index d52f31f3b..000000000 --- a/temoa/temoa_model/temoa_model.py +++ /dev/null @@ -1,1117 +0,0 @@ -#!/usr/bin/env python - -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -SPDX-License-Identifier: MIT - -""" - -import logging -from typing import TYPE_CHECKING - -from pyomo.core import BuildCheck, Set, Var -from pyomo.environ import ( - AbstractModel, - BuildAction, - Constraint, - Integers, - NonNegativeReals, - Objective, - Param, - minimize, -) - -from temoa.types.core_types import Technology - -if TYPE_CHECKING: - from pyomo.environ import AbstractModel as PyomoAbstractModel - -else: - PyomoAbstractModel = AbstractModel # type: ignore[misc,assignment] - -from temoa import types as t -from temoa.components import ( - capacity, - commodities, - costs, - emissions, - flows, - geography, - limits, - operations, - reserves, - storage, - technology, - time, -) -from temoa.model_checking.validators import ( - no_slash_or_pipe, - region_check, - region_group_check, - validate_0to1, - validate_Efficiency, - validate_linked_tech, - validate_ReserveMargin, - validate_tech_sets, -) - -logger = logging.getLogger(__name__) - - -def CreateSparseDicts(M: 'TemoaModel') -> None: - """ - Creates and populates all sparse dictionaries and sets required for the model - by calling component-specific precomputation functions. - """ - - # Call the decomposed functions in logical order - # 1. Populate core relationships from Efficiency table - technology.populate_core_dictionaries(M) - - # 2. Classify technologies and commodities - commodities.create_technology_and_commodity_sets(M) - - # 3. Create sets for specific components - operations.create_operational_vintage_sets(M) # For operations, storage, ramping - limits.create_limit_vintage_sets(M) # For limits - geography.create_geography_sets(M) # For geography/exchange - capacity.create_capacity_and_retirement_sets(M) # For capacity - - # 4. Create final aggregated sets for constraints - flows.create_commodity_balance_and_flow_sets(M) # For flows and commodities - - # Final check for unused technologies - unused_techs = M.tech_all - M.used_techs - if unused_techs: - for tech in sorted(unused_techs): - logger.warning( - f"Notice: '{tech}' is specified as a technology but is not " - 'utilized in the Efficiency parameter.' - ) - - logger.debug('Completed creation of SparseDicts') - - -class TemoaModel(PyomoAbstractModel): - """ - An instance of the abstract Temoa model - """ - - # this is used in several places outside this class, and this provides no-build access to it - default_lifetime_tech = 40 - - def __init__(M, *args: object, **kwargs: object) -> None: - PyomoAbstractModel.__init__(M, *args, **kwargs) - - ################################################ - # Internally used Data Containers # - # (not formal model elements) # - ################################################ - - # Dev Note: The triple-quotes UNDER the items below pop up as dox in most IDEs - M.processInputs: t.ProcessInputsDict = {} - M.processOutputs: t.ProcessOutputsDict = {} - M.processLoans: t.ProcessLoansDict = {} - M.activeFlow_rpsditvo: t.ActiveFlowSet = set() - """a flow index for techs NOT in tech_annual""" - - M.activeFlow_rpitvo: t.ActiveFlowAnnualSet = set() - """a flow index for techs in tech_annual only""" - - M.activeFlex_rpsditvo: t.ActiveFlexSet = set() - M.activeFlex_rpitvo: t.ActiveFlexAnnualSet = set() - M.activeFlowInStorage_rpsditvo: t.ActiveFlowInStorageSet = set() - M.activeCurtailment_rpsditvo: t.ActiveCurtailmentSet = set() - M.activeActivity_rptv: t.ActiveActivitySet = set() - M.storageLevelIndices_rpsdtv: t.StorageLevelIndicesSet = set() - M.seasonalStorageLevelIndices_rpstv: t.SeasonalStorageLevelIndicesSet = set() - """currently available (within lifespan) (r, p, t, v) tuples (from M.processVintages)""" - - M.activeRegionsForTech: t.ActiveRegionsForTechDict = {} - """currently available regions by period and tech {(p, t) : r}""" - - M.newCapacity_rtv: t.NewCapacitySet = set() - M.activeCapacityAvailable_rpt: t.ActiveCapacityAvailableSet = set() - M.activeCapacityAvailable_rptv: t.ActiveCapacityAvailableVintageSet = set() - M.groupRegionActiveFlow_rpt: t.GroupRegionActiveFlowSet = ( - set() # Set of valid group-region, period, tech indices - ) - M.commodityBalance_rpc: t.CommodityBalancedSet = ( - set() - ) # Set of valid region-period-commodity indices to balance - M.commodityDStreamProcess: t.CommodityStreamProcessDict = {} # The downstream process of a commodity during a period - M.commodityUStreamProcess: t.CommodityStreamProcessDict = {} # The upstream process of a commodity during a period - M.capacityConsumptionTechs: t.CapacityConsumptionTechsDict = {} # New capacity consuming a commodity during a period [r,p,c] -> t - M.retirementProductionProcesses: t.RetirementProductionProcessesDict = {} # Retired capacity producing a commodity during a period [r,p,c] -> t,v - M.processInputsByOutput: t.ProcessInputsByOutputDict = {} - M.processOutputsByInput: t.ProcessOutputsByInputDict = {} - M.processTechs: t.ProcessTechsDict = {} - M.processReservePeriods: t.ProcessReservePeriodsDict = {} - M.processPeriods: t.ProcessPeriodsDict = {} # {(r, t, v): set(p)} - M.retirementPeriods: t.RetirementPeriodsDict = {} # {(r, t, v): set(p)} periods in which a process can economically or naturally retire - M.processVintages: t.ProcessVintagesDict = {} - M.survivalCurvePeriods: t.SurvivalCurvePeriodsDict = {} # {(r, t, v): set(p)} periods for which the process has a defined survival fraction - """current available (within lifespan) vintages {(r, p, t) : set(v)}""" - - M.baseloadVintages: t.BaseloadVintagesDict = {} - M.curtailmentVintages: t.CurtailmentVintagesDict = {} - M.storageVintages: t.StorageVintagesDict = {} - M.rampUpVintages: t.RampUpVintagesDict = {} - M.rampDownVintages: t.RampDownVintagesDict = {} - M.inputSplitVintages: t.InputSplitVintagesDict = {} - M.inputSplitAnnualVintages: t.InputSplitAnnualVintagesDict = {} - M.outputSplitVintages: t.OutputSplitVintagesDict = {} - M.outputSplitAnnualVintages: t.OutputSplitAnnualVintagesDict = {} - # M.processByPeriodAndOutput = {} # not currently used - M.exportRegions: t.ExportRegionsDict = {} - M.importRegions: t.ImportRegionsDict = {} - - # These establish time sequencing - M.time_next: t.TimeNextDict = {} # {(p, s, d): (s_next, d_next)} sequence of following time slices - M.time_next_sequential: t.TimeNextSequentialDict = {} # {(p, s_seq): (s_seq_next)} next virtual storage season - M.sequential_to_season: t.SequentialToSeasonDict = {} # {(p, s_seq): (s)} season matching this virtual storage season - - ################################################ - # Switching Sets # - # (to avoid slow searches in initialisation) # - ################################################ - - M.isEfficiencyVariable: t.EfficiencyVariableDict = {} # {(r, p, i, t, v, o): bool} which efficiencies have variable indexing - M.isCapacityFactorProcess: t.CapacityFactorProcessDict = {} # {(r, p, t, v): bool} which capacity factors have have period-vintage indexing - M.isSeasonalStorage: t.SeasonalStorageDict = {} # {t: bool} whether a storage tech is seasonal storage - M.isSurvivalCurveProcess: t.SurvivalCurveProcessDict = {} # {(r, t, v): bool} whether a process uses survival curves. - - ################################################ - # Model Sets # - # (used for indexing model elements) # - ################################################ - - M.progress_marker_1 = BuildAction(['Starting to build Sets'], rule=progress_check) - - M.operator = Set() - - # Define time periods - M.time_exist = Set(ordered=True) - M.time_future = Set(ordered=True) - M.time_optimize = Set( - ordered=True, initialize=time.init_set_time_optimize, within=M.time_future - ) - # Define time period vintages to track capacity installation - M.vintage_exist = Set(ordered=True, initialize=time.init_set_vintage_exist) - M.vintage_optimize = Set(ordered=True, initialize=time.init_set_vintage_optimize) - M.vintage_all = Set(initialize=M.time_exist | M.time_optimize) - # Perform some basic validation on the specified time periods. - M.validate_time = BuildAction(rule=time.validate_time) - - # Define the model time slices - M.time_season = Set(ordered=True, validate=no_slash_or_pipe) - M.time_season_sequential = Set(ordered=True, validate=no_slash_or_pipe) - M.TimeSeason = Set(M.time_optimize, within=M.time_season, ordered=True) - M.time_of_day = Set(ordered=True, validate=no_slash_or_pipe) - - # This is just to get the TimeStorageSeason table sequentially. - # There must be a better way but this works for now - M.ordered_season_sequential = Set( - dimen=3, within=M.time_optimize * M.time_season_sequential * M.time_season, ordered=True - ) - - # Define regions - M.regions = Set(validate=region_check) - # RegionalIndices is the set of all the possible combinations of interregional exchanges - # plus original region indices. If tech_exchange is empty, RegionalIndices =regions. - M.regionalIndices = Set(initialize=geography.CreateRegionalIndices) - M.regionalGlobalIndices = Set(validate=region_group_check) - - # Define technology-related sets - # M.tech_resource = Set() # not actually used by - M.tech_production = Set() - M.tech_all = Set( - initialize=M.tech_production, validate=no_slash_or_pipe - ) # was M.tech_resource | M.tech_production - M.tech_baseload = Set(within=M.tech_all) - M.tech_annual = Set(within=M.tech_all) - M.tech_demand = Set(within=M.tech_all) - # annual storage not supported in Storage constraint or TableWriter, so exclude from domain - M.tech_storage = Set(within=M.tech_all) - M.tech_reserve = Set(within=M.tech_all) - M.tech_upramping = Set(within=M.tech_all) - M.tech_downramping = Set(within=M.tech_all) - M.tech_curtailment = Set(within=M.tech_all) - M.tech_flex = Set(within=M.tech_all) - # ensure there is no overlap flex <=> curtailable technologies - M.tech_exchange = Set(within=M.tech_all) - - # Define groups for technologies - M.tech_group_names = Set() - M.tech_group_members = Set(M.tech_group_names, within=M.tech_all) - M.tech_or_group = Set(initialize=M.tech_group_names | M.tech_all) - - M.tech_seasonal_storage = Set(within=M.tech_storage) - """storage technologies using the interseasonal storage feature""" - - M.tech_uncap = Set(within=M.tech_all - M.tech_reserve) - """techs with unlimited capacity, ALWAYS available within lifespan""" - - M.tech_exist = Set() - """techs with existing capacity, want to keep these for accounting reasons""" - - M.used_techs: set[Technology] = set() - """ track techs used in Efficiency table used in CreateSparseDicts """ - - # the below is a convenience for domain checking in params below that should not accept - # uncap techs... - M.tech_with_capacity = Set(initialize=M.tech_all - M.tech_uncap) - """techs eligible for capacitization""" - # Define techs for which economic retirement is an option - # Note: Storage techs cannot (currently) be retired due to linkage to initialization - # process, which is currently incapable of reducing initializations on retirements. - # Note2: I think this has been fixed but I can't tell what the problem was. Suspect - # it was the old StorageInit constraint - M.tech_retirement = Set(within=M.tech_with_capacity) # - M.tech_storage) - - M.validate_techs = BuildAction(rule=validate_tech_sets) - - # Define commodity-related sets - M.commodity_demand = Set() - M.commodity_emissions = Set() - M.commodity_physical = Set() - M.commodity_waste = Set() - M.commodity_flex = Set(within=M.commodity_physical) - M.commodity_source = Set(within=M.commodity_physical) - M.commodity_annual = Set(within=M.commodity_physical) - M.commodity_carrier = Set( - initialize=M.commodity_physical | M.commodity_demand | M.commodity_waste - ) - M.commodity_all = Set( - initialize=M.commodity_carrier | M.commodity_emissions, validate=no_slash_or_pipe - ) - - ################################################ - # Model Parameters # - # (data gathered/derived from source) # - ################################################ - - # --------------------------------------------------------------- - # Dev Note: - # In order to increase model efficiency, we use sparse - # indexing of parameters, variables, and equations to prevent the - # creation of indices for which no data exists. While basic model sets - # are defined above, sparse index sets are defined below adjacent to the - # appropriate parameter, variable, or constraint and all are initialized - # in temoa_initialize.py. - # Because the function calls that define the sparse index sets obscure the - # sets utilized, we use a suffix that includes a one character name for each - # set. Example: "_tv" indicates a set defined over "technology" and "vintage". - # The complete index set is: psditvo, where p=period, s=season, d=day, - # i=input commodity, t=technology, v=vintage, o=output commodity. - # --------------------------------------------------------------- - - # these "progress markers" report build progress in the log, if the level == debug - M.progress_marker_2 = BuildAction(['Starting to build Params'], rule=progress_check) - - M.GlobalDiscountRate = Param(default=0.05) - - # Define time-related parameters - M.PeriodLength = Param(M.time_optimize, initialize=time.ParamPeriodLength) - M.SegFrac = Param(M.time_optimize, M.time_season, M.time_of_day) - M.validate_SegFrac = BuildAction(rule=time.validate_SegFrac) - M.TimeSequencing = Set() # How do states carry between time segments? - M.TimeNext = Set( - ordered=True - ) # This is just to get data from the table. Hidden feature and usually not used - M.validate_TimeNext = BuildAction(rule=time.validate_TimeNext) - - # Define demand- and resource-related parameters - # Dev Note: There does not appear to be a DB table supporting DemandDefaultDistro. - # This does not cause any problems, so let it be for now. - # Doesn't seem to be much point in the table. Just clones SegFrac - # M.DemandDefaultDistribution = Param( - # M.time_optimize, M.time_season, M.time_of_day, mutable=True - # ) - M.DemandSpecificDistribution = Param( - M.regions, - M.time_optimize, - M.time_season, - M.time_of_day, - M.commodity_demand, - mutable=True, - default=0, - ) - - M.DemandConstraint_rpc = Set(within=M.regions * M.time_optimize * M.commodity_demand) - M.Demand = Param(M.DemandConstraint_rpc) - - # Dev Note: This parameter is currently NOT implemented. Preserved for later refactoring - # LimitResource IS implemented but sums cumulatively for a technology rather than - # resource commodity - # M.ResourceConstraint_rpr = Set(within=M.regions * M.time_optimize * M.commodity_physical) - # M.ResourceBound = Param(M.ResourceConstraint_rpr) - - # Define technology performance parameters - M.CapacityToActivity = Param(M.regionalIndices, M.tech_all, default=1) - - M.ExistingCapacity = Param(M.regionalIndices, M.tech_exist, M.vintage_exist) - - # Dev Note: The below is temporarily useful for passing down to validator to find - # set violations - # Uncomment this assignment, and comment out the orig below it... - # M.Efficiency = Param( - # Any, Any, Any, Any, Any, - # within=NonNegativeReals, validate=validate_Efficiency - # ) - - # devnote: need these here or CheckEfficiencyIndices may flag these commodities as unused - M.ConstructionInput = Param( - M.regions, M.commodity_physical, M.tech_with_capacity, M.vintage_optimize - ) - M.EndOfLifeOutput = Param( - M.regions, M.tech_with_capacity, M.vintage_all, M.commodity_carrier - ) - - M.Efficiency = Param( - M.regionalIndices, - M.commodity_physical, - M.tech_all, - M.vintage_all, - M.commodity_carrier, - within=NonNegativeReals, - validate=validate_Efficiency, - ) - M.validate_UsedEfficiencyIndices = BuildAction(rule=technology.CheckEfficiencyIndices) - - M.EfficiencyVariable = Param( - M.regionalIndices, - M.time_optimize, - M.time_season, - M.time_of_day, - M.commodity_physical, - M.tech_all, - M.vintage_all, - M.commodity_carrier, - within=NonNegativeReals, - default=1, - ) - - M.LifetimeTech = Param( - M.regionalIndices, M.tech_all, default=TemoaModel.default_lifetime_tech - ) - - M.LifetimeProcess_rtv = Set(dimen=3, initialize=technology.LifetimeProcessIndices) - M.LifetimeProcess = Param( - M.LifetimeProcess_rtv, default=technology.get_default_process_lifetime - ) - - M.LifetimeSurvivalCurve = Param( - M.regionalIndices, - Integers, - M.tech_all, - M.vintage_all, - default=technology.get_default_survival, - validate=validate_0to1, - mutable=True, - ) - M.Create_SurvivalCurve = BuildAction(rule=technology.CreateSurvivalCurve) - - M.LoanLifetimeProcess_rtv = Set(dimen=3, initialize=costs.LifetimeLoanProcessIndices) - - # Dev Note: The LoanLifetimeProcess table *could* be removed. There is no longer a - # supporting table in the database. It is just a "passthrough" now to the - # default LoanLifetimeTech. It is already stitched in to the model, - # so will leave it for now. Table may be revived. - - M.LoanLifetimeProcess = Param(M.LoanLifetimeProcess_rtv, default=costs.get_loan_life) - - M.LimitTechInputSplit = Param( - M.regions, - M.time_optimize, - M.commodity_physical, - M.tech_all, - M.operator, - validate=validate_0to1, - ) - M.LimitTechInputSplitAnnual = Param( - M.regions, - M.time_optimize, - M.commodity_physical, - M.tech_all, - M.operator, - validate=validate_0to1, - ) - - M.LimitTechOutputSplit = Param( - M.regions, - M.time_optimize, - M.tech_all, - M.commodity_carrier, - M.operator, - validate=validate_0to1, - ) - M.LimitTechOutputSplitAnnual = Param( - M.regions, - M.time_optimize, - M.tech_all, - M.commodity_carrier, - M.operator, - validate=validate_0to1, - ) - - M.RenewablePortfolioStandardConstraint_rpg = Set( - within=M.regions * M.time_optimize * M.tech_group_names - ) - M.RenewablePortfolioStandard = Param( - M.RenewablePortfolioStandardConstraint_rpg, validate=validate_0to1 - ) - - # These need to come before validate_SeasonSequential - M.RampUpHourly = Param(M.regions, M.tech_upramping, validate=validate_0to1) - M.RampDownHourly = Param(M.regions, M.tech_downramping, validate=validate_0to1) - - # Set up representation of time - M.DaysPerPeriod = Param() - M.SegFracPerSeason = Param( - M.time_optimize, M.time_season, initialize=time.SegFracPerSeason_rule - ) - M.TimeSeasonSequential = Param( - M.time_optimize, M.time_season_sequential, M.time_season, mutable=True - ) - M.validate_SeasonSequential = BuildAction(rule=time.CreateTimeSeasonSequential) - M.Create_TimeSequence = BuildAction(rule=time.CreateTimeSequence) - - # The method below creates a series of helper functions that are used to - # perform the sparse matrix of indexing for the parameters, variables, and - # equations below. - M.Create_SparseDicts = BuildAction(rule=CreateSparseDicts) - M.initialize_Demands = BuildAction(rule=commodities.CreateDemands) - - M.CapacityFactor_rpsdt = Set(dimen=5, initialize=capacity.CapacityFactorTechIndices) - M.CapacityFactorTech = Param(M.CapacityFactor_rpsdt, default=1, validate=validate_0to1) - - # Dev note: using a default function below alleviates need to make this set. - # M.CapacityFactor_rsdtv = Set(dimen=5, initialize=CapacityFactorProcessIndices) - M.CapacityFactorProcess = Param( - M.regionalIndices, - M.time_optimize, - M.time_season, - M.time_of_day, - M.tech_with_capacity, - M.vintage_all, - # validate=validate_CapacityFactorProcess, # opting for a quicker validation, just 0->1 - validate=validate_0to1, - default=capacity.get_default_capacity_factor, # slow but only called if a value is missing - ) - - M.CapacityConstraint_rpsdtv = Set(dimen=6, initialize=capacity.CapacityConstraintIndices) - M.initialize_CapacityFactors = BuildAction(rule=capacity.CheckCapacityFactorProcess) - M.initialize_EfficiencyVariable = BuildAction(rule=technology.CheckEfficiencyVariable) - - # Define technology cost parameters - # dev note: the CostFixed_rptv isn't truly needed, but it is included in a constraint, so - # let it go for now - M.CostFixed_rptv = Set(dimen=4, initialize=costs.CostFixedIndices) - M.CostFixed = Param(M.CostFixed_rptv) - - M.CostInvest_rtv = Set(within=M.regionalIndices * M.tech_all * M.time_optimize) - M.CostInvest = Param(M.CostInvest_rtv) - - M.DefaultLoanRate = Param(domain=NonNegativeReals) - M.LoanRate = Param( - M.CostInvest_rtv, domain=NonNegativeReals, default=costs.get_default_loan_rate - ) - M.LoanAnnualize = Param(M.CostInvest_rtv, initialize=costs.ParamLoanAnnualize_rule) - - M.CostVariable_rptv = Set(dimen=4, initialize=costs.CostVariableIndices) - M.CostVariable = Param(M.CostVariable_rptv) - - M.CostEmission_rpe = Set(within=M.regions * M.time_optimize * M.commodity_emissions) - M.CostEmission = Param(M.CostEmission_rpe) - - # devnote: no longer used - # M.ModelProcessLife_rptv = Set(dimen=4, initialize=ModelProcessLifeIndices) - # M.ModelProcessLife = Param(M.ModelProcessLife_rptv, initialize=ParamModelProcessLife_rule) - - M.ProcessLifeFrac_rptv = Set(dimen=4, initialize=technology.ModelProcessLifeIndices) - M.ProcessLifeFrac = Param( - M.ProcessLifeFrac_rptv, initialize=technology.ParamProcessLifeFraction_rule - ) - - M.LimitCapacityConstraint_rpt = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_or_group * M.operator - ) - M.LimitCapacity = Param(M.LimitCapacityConstraint_rpt) - - M.LimitNewCapacityConstraint_rpt = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_or_group * M.operator - ) - M.LimitNewCapacity = Param(M.LimitNewCapacityConstraint_rpt) - - M.LimitResourceConstraint_rt = Set( - within=M.regionalGlobalIndices * M.tech_or_group * M.operator - ) - M.LimitResource = Param(M.LimitResourceConstraint_rt) - - M.LimitActivityConstraint_rpt = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_or_group * M.operator - ) - M.LimitActivity = Param(M.LimitActivityConstraint_rpt) - - M.LimitSeasonalCapacityFactorConstraint_rpst = Set( - within=M.regionalGlobalIndices - * M.time_optimize - * M.time_season - * M.tech_all - * M.operator - ) - M.LimitSeasonalCapacityFactor = Param( - M.LimitSeasonalCapacityFactorConstraint_rpst, validate=validate_0to1 - ) - - M.LimitAnnualCapacityFactorConstraint_rpto = Set( - within=M.regionalGlobalIndices - * M.time_optimize - * M.tech_all - * M.commodity_carrier - * M.operator - ) - M.LimitAnnualCapacityFactor = Param( - M.LimitAnnualCapacityFactorConstraint_rpto, validate=validate_0to1 - ) - - M.LimitGrowthCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator) - M.LimitDegrowthCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator) - M.LimitGrowthNewCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator) - M.LimitDegrowthNewCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator) - M.LimitGrowthNewCapacityDelta = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator) - M.LimitDegrowthNewCapacityDelta = Param( - M.regionalGlobalIndices, M.tech_or_group, M.operator - ) - - M.LimitEmissionConstraint_rpe = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.commodity_emissions * M.operator - ) - M.LimitEmission = Param(M.LimitEmissionConstraint_rpe) - M.EmissionActivity_reitvo = Set(dimen=6, initialize=emissions.EmissionActivityIndices) - M.EmissionActivity = Param(M.EmissionActivity_reitvo) - - # devnote: deprecated when generalising tech/group columns in Limit tables - # M.LimitActivityGroupConstraint_rpg = Set( - # within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names * M.operator - # ) - # M.LimitActivityGroup = Param(M.LimitActivityGroupConstraint_rpg) - - # M.LimitCapacityGroupConstraint_rpg = Set( - # within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names * M.operator - # ) - # M.LimitCapacityGroup = Param(M.LimitCapacityGroupConstraint_rpg) - - # M.LimitNewCapacityGroupConstraint_rpg = Set( - # within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names * M.operator - # ) - # M.LimitNewCapacityGroup = Param(M.LimitNewCapacityGroupConstraint_rpg) - # M.GroupShareIndices = Set(dimen=5, initialize=GroupShareIndices) # doesn't feel worth it - - M.LimitCapacityShareConstraint_rpgg = Set( - within=M.regionalGlobalIndices - * M.time_optimize - * M.tech_or_group - * M.tech_or_group - * M.operator - ) - M.LimitCapacityShare = Param(M.LimitCapacityShareConstraint_rpgg) - - M.LimitActivityShareConstraint_rpgg = Set( - within=M.regionalGlobalIndices - * M.time_optimize - * M.tech_or_group - * M.tech_or_group - * M.operator - ) - M.LimitActivityShare = Param(M.LimitActivityShareConstraint_rpgg) - - M.LimitNewCapacityShareConstraint_rpgg = Set( - within=M.regionalGlobalIndices - * M.time_optimize - * M.tech_or_group - * M.tech_or_group - * M.operator - ) - M.LimitNewCapacityShare = Param(M.LimitNewCapacityShareConstraint_rpgg) - - # devnote: deprecated when generalising tech/group columns in Limit tables - # M.TwoGroupShareIndices = Set(dimen=5, initialize=TwoGroupShareIndices) - - # M.LimitNewCapacityGroupShareConstraint_rpgg = Set(within=M.TwoGroupShareIndices) - # M.LimitNewCapacityGroupShare = Param(M.TwoGroupShareIndices) - - # M.LimitActivityGroupShareConstraint_rpgg = Set(within=M.TwoGroupShareIndices) - # M.LimitActivityGroupShare = Param(M.TwoGroupShareIndices) - - # This set works for all storage-related constraints - M.StorageConstraints_rpsdtv = Set(dimen=6, initialize=storage.StorageConstraintIndices) - M.SeasonalStorageConstraints_rpsdtv = Set( - dimen=6, initialize=storage.SeasonalStorageConstraintIndices - ) - M.LimitStorageFractionConstraint_rpsdtv = Set( - within=(M.StorageConstraints_rpsdtv | M.SeasonalStorageConstraints_rpsdtv) * M.operator - ) - M.LimitStorageFraction = Param( - M.LimitStorageFractionConstraint_rpsdtv, validate=validate_0to1 - ) - - # Storage duration is expressed in hours - M.StorageDuration = Param(M.regions, M.tech_storage, default=4) - - M.LinkedTechs = Param(M.regionalIndices, M.tech_all, M.commodity_emissions) - - # Define parameters associated with electric sector operation - M.ReserveMarginMethod = Set() # How contributions to the reserve margin are calculated - M.CapacityCredit = Param( - M.regionalIndices, - M.time_optimize, - M.tech_reserve, - M.vintage_all, - default=0, - validate=validate_0to1, - ) - M.ReserveCapacityDerate = Param( - M.regionalIndices, - M.time_optimize, - M.time_season, - M.tech_reserve, - M.vintage_all, - default=1, - validate=validate_0to1, - ) - M.PlanningReserveMargin = Param(M.regions) - - M.EmissionEmbodied = Param( - M.regions, M.commodity_emissions, M.tech_with_capacity, M.vintage_optimize - ) - M.EmissionEndOfLife = Param( - M.regions, M.commodity_emissions, M.tech_with_capacity, M.vintage_all - ) - - M.MyopicDiscountingYear = Param(default=0) - - ################################################ - # Model Variables # - # (assigned by solver) # - ################################################ - - # --------------------------------------------------------------- - # Dev Note: - # Decision variables are optimized in order to minimize cost. - # Base decision variables represent the lowest-level variables - # in the model. Derived decision variables are calculated for - # convenience, where 1 or more indices in the base variables are - # summed over. - # --------------------------------------------------------------- - - M.progress_marker_3 = BuildAction(['Starting to build Variables'], rule=progress_check) - - # Define base decision variables - M.FlowVar_rpsditvo = Set(dimen=8, initialize=flows.FlowVariableIndices) - M.V_FlowOut = Var(M.FlowVar_rpsditvo, domain=NonNegativeReals) - - M.FlowVarAnnual_rpitvo = Set(dimen=6, initialize=flows.FlowVariableAnnualIndices) - M.V_FlowOutAnnual = Var(M.FlowVarAnnual_rpitvo, domain=NonNegativeReals) - - M.FlexVar_rpsditvo = Set(dimen=8, initialize=flows.FlexVariablelIndices) - M.V_Flex = Var(M.FlexVar_rpsditvo, domain=NonNegativeReals) - - M.FlexVarAnnual_rpitvo = Set(dimen=6, initialize=flows.FlexVariableAnnualIndices) - M.V_FlexAnnual = Var(M.FlexVarAnnual_rpitvo, domain=NonNegativeReals) - - M.CurtailmentVar_rpsditvo = Set(dimen=8, initialize=flows.CurtailmentVariableIndices) - M.V_Curtailment = Var(M.CurtailmentVar_rpsditvo, domain=NonNegativeReals, initialize=0) - - M.FlowInStorage_rpsditvo = Set(dimen=8, initialize=flows.FlowInStorageVariableIndices) - M.V_FlowIn = Var(M.FlowInStorage_rpsditvo, domain=NonNegativeReals) - - M.StorageLevel_rpsdtv = Set(dimen=6, initialize=storage.StorageLevelVariableIndices) - M.V_StorageLevel = Var(M.StorageLevel_rpsdtv, domain=NonNegativeReals) - - M.SeasonalStorageLevel_rpstv = Set( - dimen=5, initialize=storage.SeasonalStorageLevelVariableIndices - ) - M.V_SeasonalStorageLevel = Var(M.SeasonalStorageLevel_rpstv, domain=NonNegativeReals) - - # Derived decision variables - M.CapacityVar_rptv = Set(dimen=4, initialize=costs.CostFixedIndices) - M.V_Capacity = Var(M.CapacityVar_rptv, domain=NonNegativeReals) - - M.NewCapacityVar_rtv = Set(dimen=3, initialize=capacity.CapacityVariableIndices) - M.V_NewCapacity = Var(M.NewCapacityVar_rtv, domain=NonNegativeReals, initialize=0) - - M.RetiredCapacityVar_rptv = Set(dimen=4, initialize=capacity.RetiredCapacityVariableIndices) - M.V_RetiredCapacity = Var(M.RetiredCapacityVar_rptv, domain=NonNegativeReals, initialize=0) - - M.AnnualRetirementVar_rptv = Set( - dimen=4, initialize=capacity.AnnualRetirementVariableIndices - ) - M.V_AnnualRetirement = Var( - M.AnnualRetirementVar_rptv, domain=NonNegativeReals, initialize=0 - ) - - M.CapacityAvailableVar_rpt = Set( - dimen=3, initialize=capacity.CapacityAvailableVariableIndices - ) - M.V_CapacityAvailableByPeriodAndTech = Var( - M.CapacityAvailableVar_rpt, domain=NonNegativeReals, initialize=0 - ) - - ################################################ - # Objective Function # - # (minimize total cost) # - ################################################ - - M.TotalCost = Objective(rule=costs.TotalCost_rule, sense=minimize) - - ################################################ - # Constraints # - # # - ################################################ - - # --------------------------------------------------------------- - # Dev Note: - # Constraints are specified to ensure proper system behavior, - # and also to calculate some derived quantities. Note that descriptions - # of these constraints are provided in the associated comment blocks - # in temoa_rules.py, where the constraints are defined. - # --------------------------------------------------------------- - M.progress_marker_4 = BuildAction(['Starting to build Constraints'], rule=progress_check) - - # Declare constraints to calculate derived decision variables - M.CapacityConstraint = Constraint( - M.CapacityConstraint_rpsdtv, rule=capacity.Capacity_Constraint - ) - - M.CapacityAnnualConstraint_rptv = Set( - dimen=4, initialize=capacity.CapacityAnnualConstraintIndices - ) - M.CapacityAnnualConstraint = Constraint( - M.CapacityAnnualConstraint_rptv, rule=capacity.CapacityAnnual_Constraint - ) - - M.CapacityAvailableByPeriodAndTechConstraint = Constraint( - M.CapacityAvailableVar_rpt, rule=capacity.CapacityAvailableByPeriodAndTech_Constraint - ) - - # devnote: I think this constraint is redundant - # M.RetiredCapacityConstraint = Constraint( - # M.RetiredCapacityVar_rptv, rule=RetiredCapacity_Constraint - # ) - M.progress_marker_4a = BuildAction( - ['Starting AnnualRetirementConstraint'], rule=progress_check - ) - M.AnnualRetirementConstraint = Constraint( - M.AnnualRetirementVar_rptv, rule=capacity.AnnualRetirement_Constraint - ) - M.progress_marker_4b = BuildAction( - ['Starting AdjustedCapacityConstraint'], rule=progress_check - ) - M.AdjustedCapacityConstraint = Constraint( - M.CostFixed_rptv, rule=capacity.AdjustedCapacity_Constraint - ) - M.progress_marker_5 = BuildAction(['Finished Capacity Constraints'], rule=progress_check) - - # Declare core model constraints that ensure proper system functioning - # In driving order, starting with the need to meet end-use demands - - M.DemandConstraint = Constraint(M.DemandConstraint_rpc, rule=commodities.Demand_Constraint) - - # devnote: testing a workaround - M.DemandActivityConstraint_rpsdtv_dem = Set( - dimen=7, initialize=commodities.DemandActivityConstraintIndices - ) - M.DemandActivityConstraint = Constraint( - M.DemandActivityConstraint_rpsdtv_dem, rule=commodities.DemandActivity_Constraint - ) - - M.CommodityBalanceConstraint_rpsdc = Set( - dimen=5, initialize=commodities.CommodityBalanceConstraintIndices - ) - M.CommodityBalanceConstraint = Constraint( - M.CommodityBalanceConstraint_rpsdc, rule=commodities.CommodityBalance_Constraint - ) - - M.AnnualCommodityBalanceConstraint_rpc = Set( - dimen=3, initialize=commodities.AnnualCommodityBalanceConstraintIndices - ) - M.AnnualCommodityBalanceConstraint = Constraint( - M.AnnualCommodityBalanceConstraint_rpc, - rule=commodities.AnnualCommodityBalance_Constraint, - ) - - # M.ResourceExtractionConstraint = Constraint( - # M.ResourceConstraint_rpr, rule=ResourceExtraction_Constraint - # ) - - M.BaseloadDiurnalConstraint_rpsdtv = Set( - dimen=6, initialize=operations.BaseloadDiurnalConstraintIndices - ) - M.BaseloadDiurnalConstraint = Constraint( - M.BaseloadDiurnalConstraint_rpsdtv, rule=operations.BaseloadDiurnal_Constraint - ) - - M.RegionalExchangeCapacityConstraint_rrptv = Set( - dimen=5, initialize=capacity.RegionalExchangeCapacityConstraintIndices - ) - M.RegionalExchangeCapacityConstraint = Constraint( - M.RegionalExchangeCapacityConstraint_rrptv, - rule=geography.RegionalExchangeCapacity_Constraint, - ) - - M.progress_marker_6 = BuildAction(['Starting Storage Constraints'], rule=progress_check) - - M.StorageEnergyConstraint = Constraint( - M.StorageConstraints_rpsdtv, rule=storage.StorageEnergy_Constraint - ) - - M.StorageEnergyUpperBoundConstraint = Constraint( - M.StorageConstraints_rpsdtv, rule=storage.StorageEnergyUpperBound_Constraint - ) - - M.SeasonalStorageEnergyConstraint = Constraint( - M.SeasonalStorageLevel_rpstv, rule=storage.SeasonalStorageEnergy_Constraint - ) - - M.SeasonalStorageEnergyUpperBoundConstraint = Constraint( - M.SeasonalStorageConstraints_rpsdtv, - rule=storage.SeasonalStorageEnergyUpperBound_Constraint, - ) - - M.StorageChargeRateConstraint = Constraint( - M.StorageConstraints_rpsdtv, rule=storage.StorageChargeRate_Constraint - ) - - M.StorageDischargeRateConstraint = Constraint( - M.StorageConstraints_rpsdtv, rule=storage.StorageDischargeRate_Constraint - ) - - M.StorageThroughputConstraint = Constraint( - M.StorageConstraints_rpsdtv, rule=storage.StorageThroughput_Constraint - ) - - M.LimitStorageFractionConstraint = Constraint( - M.LimitStorageFractionConstraint_rpsdtv, rule=storage.LimitStorageFraction_Constraint - ) - - M.RampUpDayConstraint_rpsdtv = Set( - dimen=6, initialize=operations.RampUpDayConstraintIndices - ) - M.RampUpDayConstraint = Constraint( - M.RampUpDayConstraint_rpsdtv, rule=operations.RampUpDay_Constraint - ) - M.RampDownDayConstraint_rpsdtv = Set( - dimen=6, initialize=operations.RampDownDayConstraintIndices - ) - M.RampDownDayConstraint = Constraint( - M.RampDownDayConstraint_rpsdtv, rule=operations.RampDownDay_Constraint - ) - - M.RampUpSeasonConstraint_rpsstv = Set( - dimen=6, initialize=operations.RampUpSeasonConstraintIndices - ) - M.RampUpSeasonConstraint = Constraint( - M.RampUpSeasonConstraint_rpsstv, rule=operations.RampUpSeason_Constraint - ) - M.RampDownSeasonConstraint_rpsstv = Set( - dimen=6, initialize=operations.RampDownSeasonConstraintIndices - ) - M.RampDownSeasonConstraint = Constraint( - M.RampDownSeasonConstraint_rpsstv, rule=operations.RampDownSeason_Constraint - ) - - M.ReserveMargin_rpsd = Set(dimen=4, initialize=reserves.ReserveMarginIndices) - M.validate_ReserveMargin = BuildAction(rule=validate_ReserveMargin) - M.ReserveMarginConstraint = Constraint( - M.ReserveMargin_rpsd, rule=reserves.ReserveMargin_Constraint - ) - - M.LimitEmissionConstraint = Constraint( - M.LimitEmissionConstraint_rpe, rule=limits.LimitEmission_Constraint - ) - M.progress_marker_7 = BuildAction( - ['Starting LimitGrowth and Activity Constraints'], rule=progress_check - ) - - M.LimitGrowthCapacityConstraint_rpt = Set( - dimen=4, initialize=limits.LimitGrowthCapacityIndices - ) - M.LimitGrowthCapacityConstraint = Constraint( - M.LimitGrowthCapacityConstraint_rpt, rule=limits.LimitGrowthCapacityConstraint_rule - ) - M.LimitDegrowthCapacityConstraint_rpt = Set( - dimen=4, initialize=limits.LimitDegrowthCapacityIndices - ) - M.LimitDegrowthCapacityConstraint = Constraint( - M.LimitDegrowthCapacityConstraint_rpt, rule=limits.LimitDegrowthCapacityConstraint_rule - ) - - M.LimitGrowthNewCapacityConstraint_rpt = Set( - dimen=4, initialize=limits.LimitGrowthNewCapacityIndices - ) - M.LimitGrowthNewCapacityConstraint = Constraint( - M.LimitGrowthNewCapacityConstraint_rpt, - rule=limits.LimitGrowthNewCapacityConstraint_rule, - ) - M.LimitDegrowthNewCapacityConstraint_rpt = Set( - dimen=4, initialize=limits.LimitDegrowthNewCapacityIndices - ) - M.LimitDegrowthNewCapacityConstraint = Constraint( - M.LimitDegrowthNewCapacityConstraint_rpt, - rule=limits.LimitDegrowthNewCapacityConstraint_rule, - ) - - M.LimitGrowthNewCapacityDeltaConstraint_rpt = Set( - dimen=4, initialize=limits.LimitGrowthNewCapacityDeltaIndices - ) - M.LimitGrowthNewCapacityDeltaConstraint = Constraint( - M.LimitGrowthNewCapacityDeltaConstraint_rpt, - rule=limits.LimitGrowthNewCapacityDeltaConstraint_rule, - ) - M.LimitDegrowthNewCapacityDeltaConstraint_rpt = Set( - dimen=4, initialize=limits.LimitDegrowthNewCapacityDeltaIndices - ) - M.LimitDegrowthNewCapacityDeltaConstraint = Constraint( - M.LimitDegrowthNewCapacityDeltaConstraint_rpt, - rule=limits.LimitDegrowthNewCapacityDeltaConstraint_rule, - ) - - M.LimitActivityConstraint = Constraint( - M.LimitActivityConstraint_rpt, rule=limits.LimitActivity_Constraint - ) - - M.LimitSeasonalCapacityFactorConstraint = Constraint( - M.LimitSeasonalCapacityFactorConstraint_rpst, - rule=limits.LimitSeasonalCapacityFactor_Constraint, - ) - - # devnote: deprecated when generalising tech/group columns in Limit tables - # M.LimitActivityGroupConstraint = Constraint( - # M.LimitActivityGroupConstraint_rpg, rule=LimitActivityGroup_Constraint - # ) - - M.LimitCapacityConstraint = Constraint( - M.LimitCapacityConstraint_rpt, rule=limits.LimitCapacity_Constraint - ) - - M.LimitNewCapacityConstraint = Constraint( - M.LimitNewCapacityConstraint_rpt, rule=limits.LimitNewCapacity_Constraint - ) - - # devnote: deprecated when generalising tech/group columns in Limit tables - # M.LimitCapacityGroupConstraint = Constraint( - # M.LimitCapacityGroupConstraint_rpg, rule=LimitCapacityGroup_Constraint - # ) - - # M.LimitNewCapacityGroupConstraint = Constraint( - # M.LimitNewCapacityGroupConstraint_rpg, rule=LimitNewCapacityGroup_Constraint - # ) - - M.LimitCapacityShareConstraint = Constraint( - M.LimitCapacityShareConstraint_rpgg, rule=limits.LimitCapacityShare_Constraint - ) - - M.LimitActivityShareConstraint = Constraint( - M.LimitActivityShareConstraint_rpgg, rule=limits.LimitActivityShare_Constraint - ) - - M.LimitNewCapacityShareConstraint = Constraint( - M.LimitNewCapacityShareConstraint_rpgg, rule=limits.LimitNewCapacityShare_Constraint - ) - - # devnote: deprecated when generalising tech/group columns in Limit tables - # M.LimitNewCapacityGroupShareConstraint = Constraint( - # M.LimitNewCapacityGroupShareConstraint_rpgg, - # rule=LimitNewCapacityGroupShare_Constraint - # ) - - # M.LimitActivityGroupShareConstraint = Constraint( - # M.LimitActivityGroupShareConstraint_rpgg, rule=LimitActivityGroupShare_Constraint - # ) - - M.progress_marker_8 = BuildAction( - ['Starting Limit Capacity and Tech Split Constraints'], rule=progress_check - ) - - M.LimitResourceConstraint = Constraint( - M.LimitResourceConstraint_rt, rule=limits.LimitResource_Constraint - ) - - M.LimitAnnualCapacityFactorConstraint = Constraint( - M.LimitAnnualCapacityFactorConstraint_rpto, - rule=limits.LimitAnnualCapacityFactor_Constraint, - ) - - ## Tech input splits - M.LimitTechInputSplitConstraint_rpsditv = Set( - dimen=8, initialize=limits.LimitTechInputSplitConstraintIndices - ) - M.LimitTechInputSplitConstraint = Constraint( - M.LimitTechInputSplitConstraint_rpsditv, rule=limits.LimitTechInputSplit_Constraint - ) - - M.LimitTechInputSplitAnnualConstraint_rpitv = Set( - dimen=6, initialize=limits.LimitTechInputSplitAnnualConstraintIndices - ) - M.LimitTechInputSplitAnnualConstraint = Constraint( - M.LimitTechInputSplitAnnualConstraint_rpitv, - rule=limits.LimitTechInputSplitAnnual_Constraint, - ) - - M.LimitTechInputSplitAverageConstraint_rpitv = Set( - dimen=6, initialize=limits.LimitTechInputSplitAverageConstraintIndices - ) - M.LimitTechInputSplitAverageConstraint = Constraint( - M.LimitTechInputSplitAverageConstraint_rpitv, - rule=limits.LimitTechInputSplitAverage_Constraint, - ) - - ## Tech output splits - M.LimitTechOutputSplitConstraint_rpsdtvo = Set( - dimen=8, initialize=limits.LimitTechOutputSplitConstraintIndices - ) - M.LimitTechOutputSplitConstraint = Constraint( - M.LimitTechOutputSplitConstraint_rpsdtvo, rule=limits.LimitTechOutputSplit_Constraint - ) - - M.LimitTechOutputSplitAnnualConstraint_rptvo = Set( - dimen=6, initialize=limits.LimitTechOutputSplitAnnualConstraintIndices - ) - M.LimitTechOutputSplitAnnualConstraint = Constraint( - M.LimitTechOutputSplitAnnualConstraint_rptvo, - rule=limits.LimitTechOutputSplitAnnual_Constraint, - ) - - M.LimitTechOutputSplitAverageConstraint_rptvo = Set( - dimen=6, initialize=limits.LimitTechOutputSplitAverageConstraintIndices - ) - M.LimitTechOutputSplitAverageConstraint = Constraint( - M.LimitTechOutputSplitAverageConstraint_rptvo, - rule=limits.LimitTechOutputSplitAverage_Constraint, - ) - - M.RenewablePortfolioStandardConstraint = Constraint( - M.RenewablePortfolioStandardConstraint_rpg, - rule=limits.RenewablePortfolioStandard_Constraint, - ) - - M.LinkedEmissionsTechConstraint_rpsdtve = Set( - dimen=7, initialize=emissions.LinkedTechConstraintIndices - ) - # the validation requires that the set above be built first: - M.validate_LinkedTech_lifetimes = BuildCheck(rule=validate_linked_tech) - - M.LinkedEmissionsTechConstraint = Constraint( - M.LinkedEmissionsTechConstraint_rpsdtve, rule=emissions.LinkedEmissionsTech_Constraint - ) - - M.progress_marker_9 = BuildAction(['Finished Constraints'], rule=progress_check) - - -def progress_check(M: TemoaModel, checkpoint: str) -> None: - """A quick widget which is called by BuildAction in order to log creation progress""" - logger.debug('Model build progress: %s', checkpoint) From bec16224ce9b4976d609b0bef6a2fb2ee533ad61 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Mon, 20 Oct 2025 14:31:20 -0400 Subject: [PATCH 254/587] separating the solver dependency and removing gurobi from core dependency --- pyproject.toml | 5 +++-- requirements.txt | 2 -- uv.lock | 10 +++++----- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index de1e8d1b6..fa8035263 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,7 +33,6 @@ dependencies = [ "networkx>=3.3", "highspy>=1.7.2", "scipy>=1.14.1", - "gurobipy>=11.0.3", "nx-vis-visualizer>=0.1.1", "gravis>=0.1.0", ] @@ -41,7 +40,6 @@ dependencies = [ [dependency-groups] dev = [ - "gurobipy>=12.0.3", "types-deprecated>=1.2.15.20250304", "ruff>=0.2.0", "mypy>=1.0.0", @@ -64,6 +62,9 @@ plotting = [ "matplotlib>=3.9.2", "seaborn>=0.13.2", ] +solver = [ + "gurobipy>=12.0.3,<13", +] [build-system] requires = ["hatchling"] diff --git a/requirements.txt b/requirements.txt index 6dcd06c11..0c196d97f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -80,8 +80,6 @@ gravis==0.1.0 # via temoa (pyproject.toml) greenlet==3.2.3 # via sqlalchemy -gurobipy==12.0.3 - # via temoa (pyproject.toml) h11==0.16.0 # via httpcore h2==4.2.0 diff --git a/uv.lock b/uv.lock index f6ec15520..54305c688 100644 --- a/uv.lock +++ b/uv.lock @@ -2943,7 +2943,6 @@ dependencies = [ { name = "deprecated" }, { name = "graphviz" }, { name = "gravis" }, - { name = "gurobipy" }, { name = "highspy" }, { name = "ipykernel" }, { name = "ipython" }, @@ -2980,10 +2979,12 @@ plotting = [ { name = "matplotlib" }, { name = "seaborn" }, ] +solver = [ + { name = "gurobipy" }, +] [package.dev-dependencies] dev = [ - { name = "gurobipy" }, { name = "mypy" }, { name = "pandas-stubs" }, { name = "pre-commit" }, @@ -2998,7 +2999,7 @@ requires-dist = [ { name = "deprecated", specifier = ">=1.2.14" }, { name = "graphviz", specifier = ">=0.20.3" }, { name = "gravis", specifier = ">=0.1.0" }, - { name = "gurobipy", specifier = ">=11.0.3" }, + { name = "gurobipy", marker = "extra == 'solver'", specifier = ">=12.0.3,<13" }, { name = "highspy", specifier = ">=1.7.2" }, { name = "ipykernel" }, { name = "ipython" }, @@ -3029,11 +3030,10 @@ requires-dist = [ { name = "tabulate", specifier = ">=0.9.0" }, { name = "xlsxwriter", specifier = ">=3.2.0" }, ] -provides-extras = ["docs", "plotting"] +provides-extras = ["docs", "plotting", "solver"] [package.metadata.requires-dev] dev = [ - { name = "gurobipy", specifier = ">=12.0.3" }, { name = "mypy", specifier = ">=1.0.0" }, { name = "pandas-stubs", specifier = ">=2.3.2.250926" }, { name = "pre-commit" }, From 3704b68d0a5dd1487f94aa9001d386e5e63b61d7 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Mon, 20 Oct 2025 14:48:35 -0400 Subject: [PATCH 255/587] removing outdated jupyter notebooks --- notebooks/Network_diagrams.ipynb | 476 --- notebooks/develop_mitigation_curve copy.ipynb | 3461 ----------------- notebooks/loan_cost_primer.ipynb | 470 --- .../temoa_utopia_analysis_with_pyam.ipynb | 439 --- 4 files changed, 4846 deletions(-) delete mode 100644 notebooks/Network_diagrams.ipynb delete mode 100644 notebooks/develop_mitigation_curve copy.ipynb delete mode 100644 notebooks/loan_cost_primer.ipynb delete mode 100644 notebooks/temoa_utopia_analysis_with_pyam.ipynb diff --git a/notebooks/Network_diagrams.ipynb b/notebooks/Network_diagrams.ipynb deleted file mode 100644 index cf8cf4417..000000000 --- a/notebooks/Network_diagrams.ipynb +++ /dev/null @@ -1,476 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "source": [ - "# NOTE: This is preserved, but needs updating!\n", - "## It needs updating for:\n", - "- location (the imports need to be aligned to this file location)\n", - "- V3 database naming. Opening alongside a version 3 database should help ID erroneous names." - ], - "metadata": { - "collapsed": false - } - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Modify path to database in the cell below and run all cells" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "hide_input": false, - "init_cell": true - }, - "outputs": [], - "source": [ - "db_path = '../data_files/temoa_utopia.sqlite'" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "hide_input": true, - "init_cell": true, - "jupyter": { - "source_hidden": true - } - }, - "outputs": [], - "source": [ - "import nbformat as nbf\n", - "import pandas as pd\n", - "import numpy as np\n", - "import os\n", - "import sqlite3\n", - "import tabulate\n", - "import shutil\n", - "import IPython\n", - "from IPython.display import HTML, display, Markdown, Image\n", - "import ipywidgets as widgets\n", - "from ipywidgets import HBox, VBox, Layout\n", - "import graphviz\n", - "from GraphVizUtil import *\n", - "from GraphVizFormats import *\n", - "import warnings\n", - "warnings.filterwarnings('ignore')\n", - "\n", - "def filter_descriptions(tech_comm_desc):\n", - " try:\n", - " tech_comm_desc = tech_comm_desc.values[0][0].replace('#', '').replace('\"','').replace(\"\\n\",'').strip()\n", - " except:\n", - " tech_comm_desc = 'No description provided'\n", - " return tech_comm_desc\n", - " \n", - "\n", - "def create_args_flowd(df_graph):\n", - " nodes, tech, ltech, to_tech, from_tech = set(), set(), set(), set(), set()\n", - " for ind,row in df_graph.iterrows():\n", - " #descriptions:\n", - " input_comm_des = filter_descriptions(pd.read_sql(\"SELECT comm_desc FROM commodities WHERE comm_name='\" + row['input_comm'] + \"'\", con))\n", - " output_comm_des = filter_descriptions(pd.read_sql(\"SELECT comm_desc FROM commodities WHERE comm_name='\" + row['output_comm'] + \"'\", con))\n", - " tech_des = filter_descriptions(pd.read_sql(\"SELECT tech_desc FROM technologies WHERE tech='\" + row['tech'] + \"'\", con))\n", - "\n", - " if 'ethos' in row['input_comm']:\n", - " ltech.add('\"' + row['tech'] + '\"' + ' [tooltip = \"' + tech_des + '\"]')\n", - " else :\n", - " nodes.add('\"' + row['input_comm'] + '\"' + ' [tooltip = \"' + input_comm_des + '\"]')\n", - " nodes.add('\"' + row['output_comm'] + '\"' + ' [tooltip = \"' + output_comm_des + '\"]')\n", - " tech.add('\"' + row['tech'] + '\"' + ' [tooltip = \"' + tech_des + '\"]')\n", - "\n", - " if row['input_comm'] != 'ethos':\n", - " to_tech.add('\"%s\"' % row['input_comm'] + '\\t->\\t\"%s\"' % row['tech']) \n", - " from_tech.add('\"%s\"' % row['tech'] + '\\t->\\t\"%s\"' % row['output_comm'])\n", - " args = dict(\n", - " enodes = \"\".join('%s;\\n\\t\\t' % x for x in nodes),\n", - " tnodes = \"\".join('%s;\\n\\t\\t' % x for x in tech),\n", - " iedges = \"\".join('%s;\\n\\t\\t' % x for x in to_tech),\n", - " oedges = \"\".join('%s;\\n\\t\\t' % x for x in from_tech),\n", - " snodes = \";\".join('%s' %x for x in ltech),\n", - " )\n", - " return args\n", - "\n", - "def return_format_colors():\n", - " colors = {}\n", - " colors.update(getColorConfig(False))\n", - " return colors, quick_run_dot_fmt\n", - "\n", - "def return_flowd_table(final_dem, level):\n", - " df = pd.read_sql(\"SELECT * FROM Efficiency\", con)\n", - " df_sel = df[df['output_comm']==final_dem]\n", - " if len(df_sel)==0:\n", - " df_sel = df[df['tech']==final_dem]\n", - " inputs = df_sel['input_comm'].unique()\n", - " iterval=0\n", - " while len(inputs)>0:\n", - " df_append = df[df['output_comm'].isin(inputs)]\n", - " df_sel = pd.concat([df_sel, df_append])\n", - " inputs = df_append['input_comm'].unique()\n", - " iterval+=1\n", - " if iterval>level:\n", - " break\n", - " df_graph = df_sel[['input_comm', 'tech', 'output_comm']].drop_duplicates()\n", - " return df_graph\n", - "\n", - "\n", - "con = sqlite3.connect(db_path) #change path to database\n", - "cur = con.cursor() \n", - "con.text_factory = str \n", - "\n", - "def controls_rows(w):\n", - " controls = HBox(w.children[:-1], layout = Layout(flex_flow='row wrap', width='max-content'))\n", - " output = w.children[-1]\n", - " display(VBox([controls, output], layout = Layout(flex_flow='columns wrap', width='max-content', height='max-content')))\n", - "\n", - " display(HTML(\"\"))\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "hide_input": false - }, - "source": [ - "### Network diagrams for commodities and technologies\n", - "Select a table, followed by a sector to view the available commodities and technologies. Then select a specific technology/commodity to generate the network diagram. Finally, select the level (upstream connections) of the network to be displayed. Hovering the cursor over each node in the diagram will display the associated description from the commodities or technologies tables." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "hide_input": true, - "init_cell": true, - "jupyter": { - "source_hidden": true - }, - "scrolled": false - }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "16320f95465b4393b8734889efd08d68", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "VBox(children=(HBox(children=(Select(description='Table', layout=Layout(height='50px', width='200px'), options…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "def network_sector(sector, table_name):\n", - " if table_name=='commodities':\n", - " query = \"SELECT * FROM commodities WHERE flag='p' AND comm_name IN \\\n", - " (SELECT DISTINCT(output_comm) FROM efficiency \\\n", - " WHERE tech IN (SELECT DISTINCT(tech) FROM technologies WHERE sector=\"\n", - " elif table_name=='technologies':\n", - " query = \"SELECT * FROM technologies WHERE sector=\"\n", - "\n", - " if sector=='Industry':\n", - " query += \"'industrial'\"\n", - " elif sector=='Transport':\n", - " query += \"'transport'\"\n", - " elif sector=='Residential':\n", - " query += \"'residential'\"\n", - " elif sector=='Commercial':\n", - " query += \"'commercial'\"\n", - " elif sector=='Supply':\n", - " query += \"'supply'\"\n", - " elif sector=='Electric':\n", - " query += \"'electric'\"\n", - " elif sector=='Electric Misc':\n", - " query += \"'electric_misc'\"\n", - " \n", - " if (table_name=='commodities'):\n", - " query +=\"))\"\n", - "\n", - " if (sector=='Final demands') & (table_name=='commodities'):\n", - " query = \"SELECT * FROM commodities WHERE flag='d'\"\n", - " \n", - " if (sector=='Final demands') & (table_name=='technologies'):\n", - " df_demands = pd.DataFrame(columns = pd.read_sql(\"SELECT * FROM technologies\", con).columns)\n", - " else:\n", - " df_demands = pd.read_sql(query, con)\n", - " \n", - " if table_name=='commodities':\n", - " col_filter = 'comm_name'\n", - " elif table_name=='technologies':\n", - " col_filter = 'tech'\n", - "\n", - " df_demands[col_filter] = df_demands[col_filter].str.replace('#', '').str.strip()\n", - "\n", - " def show_desc(desc, level):\n", - " if desc!='':\n", - " col = col_filter\n", - " final_dem = df_demands.loc[df_demands[col_filter]==desc, col].values[0]\n", - " df_graph = return_flowd_table(final_dem, level)\n", - " args = create_args_flowd(df_graph)\n", - " colors, quick_run_dot_fmt = return_format_colors()\n", - " args.update(colors)\n", - " o_str = 'rankdir = \"LR\" ;'\n", - " r_str = 'rankdir = \"LR\" ; \\n\\t size=\"12,12\";'\n", - " quick_run_dot_fmt = quick_run_dot_fmt.replace(o_str, r_str)\n", - " dot_graph = quick_run_dot_fmt % args\n", - " graph = graphviz.Source(dot_graph)\n", - " display(Markdown('Network diagram for ' + final_dem))\n", - " display(graph)\n", - " \n", - " layout = widgets.Layout(width='500px', height='150px')\n", - " df_demands = df_demands.dropna(subset=[col_filter])\n", - " select_options = df_demands[col_filter].unique()\n", - " if len(select_options)==1:\n", - " select_options = list(select_options) + [''] \n", - "\n", - " w1 = widgets.Select(options=np.sort(select_options), description=table_name.replace('ies','y').capitalize() , layout=layout)\n", - " w2 = widgets.IntSlider(\n", - " value=2,\n", - " min=0,\n", - " max=10,\n", - " step=1,\n", - " description='Level:',\n", - " disabled=False,\n", - " continuous_update=False,\n", - " orientation='horizontal',\n", - " readout=True,\n", - " readout_format='d')\n", - " w = widgets.interactive(show_desc, desc = w1, level=w2)\n", - " controls_rows(w)\n", - "\n", - "#selects particular table\n", - "def select_tech_comm():\n", - " def single_table(table_val, sector):\n", - " if table_val=='Technologies':\n", - " network_sector(sector, 'technologies')\n", - " elif table_val=='Commodities':\n", - " network_sector(sector, 'commodities')\n", - " \n", - " layout = widgets.Layout(width='200px', height = '50px')\n", - " w1 = widgets.Select(options=['Technologies', 'Commodities'], \\\n", - " description='Table', layout=layout)\n", - " layout = widgets.Layout(width='200px', height = '150px')\n", - " w2 = widgets.Select(options=['Final demands','Supply','Transport','Residential','Commercial','Industry', 'Electric', 'Electric Misc',], \\\n", - " description='Sector', layout=layout)\n", - " \n", - "\n", - " w = widgets.interactive(single_table, table_val = w1, sector = w2)\n", - " controls_rows(w)\n", - "\n", - "#main function\n", - "select_tech_comm()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Technology data look-up\n", - "Use the tool below to select any technology within the database. Data tables specific to the selected technology will be displayed." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "hide_input": true, - "init_cell": true - }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "f2f5bde2f6d944d2be7cce49dc2f2c99", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Text(value='E21')" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "cf9961ed99dd4a6780256239662828bf", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "w = widgets.Text(value='E21')\n", - "display(w)\n", - "def f(w):\n", - " df = pd.read_sql(\"SELECT * FROM technologies WHERE tech='\" + w + \"'\", con)\n", - "\n", - " if len(df)>0:\n", - " \n", - " df_efficiency= pd.read_sql(\"SELECT regions, input_comm, tech, vintage, output_comm, efficiency FROM Efficiency WHERE tech='\" + w + \"'\", con)\n", - " df_existing_capacity = pd.read_sql(\"SELECT regions, tech, vintage, exist_cap FROM ExistingCapacity WHERE tech='\" + w + \"'\", con)\n", - " df_lifetime = pd.read_sql(\"SELECT regions, tech, life FROM LifetimeTech WHERE tech='\" + w + \"'\", con)\n", - " df_cost_invest = pd.read_sql(\"SELECT regions, tech, vintage, cost_invest FROM CostInvest WHERE tech='\" + w + \"'\", con)\n", - "\n", - " df_all = df_efficiency.merge(df_existing_capacity, on = ['regions','tech','vintage'], how='left')\n", - " df_all = df_all.merge(df_lifetime, on = ['regions','tech'], how='left')\n", - " df_all = df_all.merge(df_cost_invest, on = ['regions','tech','vintage'], how='left')\n", - "\n", - " df_all.fillna(0, inplace=True)\n", - " display(\n", - " HTML(\n", - " tabulate.tabulate(df_all.set_index('regions'),['region'] + list(df_all.set_index('regions').columns.values),tablefmt='html')))\n", - " \n", - " df_costfixed= pd.read_sql(\"SELECT regions, periods, tech, vintage, cost_fixed FROM CostFixed WHERE tech='\" + w + \"'\", con)\n", - " df_costvariable= pd.read_sql(\"SELECT regions, periods, tech, vintage, cost_variable FROM CostVariable WHERE tech='\" + w + \"'\", con)\n", - " df_costsannual = df_costfixed.merge(df_costvariable, on = ['regions','periods','tech','vintage'], how='outer')\n", - " df_costsannual.fillna(0, inplace=True)\n", - " df_costsannual = df_costsannual[['regions', 'periods', 'tech', 'vintage', 'cost_fixed', 'cost_variable']]\n", - " if len(df_costsannual)>0:\n", - " display(\n", - " HTML(\n", - " tabulate.tabulate(df_costsannual.set_index('regions'),['region'] + list(df_costsannual.set_index('regions').columns.values),tablefmt='html')))\n", - "\n", - " else:\n", - " print('')\n", - "\n", - "\n", - "out = widgets.interactive_output(f, {'w': w})\n", - "display(out)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "hide_input": true - }, - "source": [ - "### Technology/commodity look-up tool\n", - "Use the tool below to provide a description for any technology or commodity within the database. Type the commodity or technology name in the box below to view its description." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "hide_input": true, - "init_cell": true, - "jupyter": { - "source_hidden": true - } - }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "ae698f893de748259577009b514828d7", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Text(value='ELC')" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "d85d4ca4cf98497ba36a02ad651456e3", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "w = widgets.Text(value='ELC')\n", - "display(w)\n", - "def f(w):\n", - " df = pd.read_sql(\"SELECT * FROM commodities WHERE comm_name='\" + w + \"'\", con)\n", - " if len(df)==0:\n", - " df = pd.read_sql(\"SELECT * FROM technologies WHERE tech='\" + w + \"'\", con)\n", - "\n", - " if len(df)>0:\n", - " try:\n", - " display(Markdown(df['comm_desc'].values[0].replace('#', '').strip()))\n", - " except:\n", - " display(Markdown(df['tech_desc'].values[0].replace('#', '').strip()))\n", - " else:\n", - " print('')\n", - "\n", - "\n", - "out = widgets.interactive_output(f, {'w': w})\n", - "display(out)\n" - ] - } - ], - "metadata": { - "celltoolbar": "Initialization Cell", - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.3" - }, - "toc": { - "base_numbering": 1, - "nav_menu": {}, - "number_sections": true, - "sideBar": true, - "skip_h1_title": false, - "title_cell": "Table of Contents", - "title_sidebar": "Contents", - "toc_cell": false, - "toc_position": {}, - "toc_section_display": true, - "toc_window_display": true - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/notebooks/develop_mitigation_curve copy.ipynb b/notebooks/develop_mitigation_curve copy.ipynb deleted file mode 100644 index fd38d62cf..000000000 --- a/notebooks/develop_mitigation_curve copy.ipynb +++ /dev/null @@ -1,3461 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "bd2fc2aa", - "metadata": {}, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'matplotlib'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[1], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mpandas\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m \u001b[38;5;21;01mpd\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mmatplotlib\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mpyplot\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m \u001b[38;5;21;01mplt\u001b[39;00m\n\u001b[1;32m 3\u001b[0m get_ipython()\u001b[38;5;241m.\u001b[39mrun_line_magic(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mmatplotlib\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124minline\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01msqlite3\u001b[39;00m\n", - "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'matplotlib'" - ] - } - ], - "source": [ - "import pandas as pd\n", - "import matplotlib.pyplot as plt\n", - "%matplotlib inline\n", - "import sqlite3\n", - "import seaborn as sb\n", - "import numpy as np\n", - "from pandas.api.types import CategoricalDtype\n", - "from itertools import cycle, islice\n", - "import os\n", - "import shutil\n", - "import collections\n", - "import warnings\n", - "warnings.filterwarnings(\"ignore\")\n", - "import matplotlib.ticker as tick\n", - "#!pip install mpl-axes-aligner\n", - "\n", - "\n", - "import mpl_axes_aligner\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "d5bb94fa", - "metadata": {}, - "outputs": [], - "source": [ - "#os.mkdir('carbon_tax_figures_updates')" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "bb7bc9a0", - "metadata": {}, - "outputs": [], - "source": [ - "sb.set(style='whitegrid', font_scale=1.4)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "96751de1", - "metadata": {}, - "outputs": [], - "source": [ - "# map tech categories to energy sources\n", - "col_order = ['Biomass','Geothermal','Hydro','Nuclear','Coal','Natural Gas','Solar','Wind', 'Pumped Hydro',\\\n", - " 'Battery', 'Hydrogen']\n", - "#map powerplant categories\n", - "map_plants = dict()\n", - "map_plants['COAL'] = 'Coal'\n", - "map_plants['GEO'] = 'Geothermal'\n", - "map_plants['BE'] = 'Biomass'\n", - "map_plants['BIO'] = 'Biomass'\n", - "map_plants['HYDPS'] = 'Pumped Hydro'\n", - "map_plants['HYDCONV'] = 'Hydro'\n", - "map_plants['HYDSM'] = 'Hydro'\n", - "map_plants['NGA'] = 'Natural Gas'\n", - "map_plants['WND'] = 'Wind'\n", - "map_plants['SOL'] = 'Solar'\n", - "map_plants['URN'] = 'Nuclear'\n", - "map_plants['Batt'] = 'Battery'\n", - "map_plants['H2'] = 'Hydrogen'\n", - "\n", - "color_dict = dict()\n", - "color_dict['Coal'] = 'dimgray'\n", - "color_dict['Geothermal'] = 'pink'\n", - "color_dict['Biomass'] = 'darkseagreen'\n", - "color_dict['Hydro'] = 'b'\n", - "color_dict['Natural Gas'] = 'peru'\n", - "color_dict['Wind'] = 'lightskyblue'\n", - "color_dict['Solar'] = 'lemonchiffon'\n", - "color_dict['Nuclear'] = 'darkorange'\n", - "color_dict['Pumped Hydro'] = 'lightcoral'\n", - "color_dict['Battery'] = 'red'\n", - "color_dict['Hydrogen'] = '#e5ae38'\n", - "color_dict['Curtailment'] = 'darkgrey'\n", - "\n", - "color_dict['commercial'] = 'darkred'\n", - "color_dict['industrial'] = 'blue'\n", - "color_dict['transport'] = 'darkorange'\n", - "color_dict['residential'] = 'lightskyblue'\n", - "\n", - "color_dict['Petroleum'] = '#ABABAB'\n", - "\n", - "\n", - "\n", - "tech_transport = dict()\n", - "tech_transport['T_Liquids'] = 'Synthetic Fuel'\n", - "tech_transport['DSL_EA'] = 'Diesel'\n", - "tech_transport['BIODSL'] = 'Biodiesel'\n", - "tech_transport['MGO_EA'] = 'Diesel'\n", - "tech_transport['RFO_EA'] = 'Other Fossil'\n", - "tech_transport['CNG_EA'] = 'Other Fossil'\n", - "tech_transport['T_LPG_EA'] = 'Other Fossil'\n", - "tech_transport['T_LNG_EA'] = 'Other Fossil'\n", - "tech_transport['ELC'] = 'Electricity'\n", - "tech_transport['ELC_TRN'] = 'Electricity'\n", - "tech_transport['ELC_HDV_CHRG'] = 'drop'\n", - "tech_transport['ELC_LDV_CHRG'] = 'drop'\n", - "tech_transport['BIO_JTF'] = 'Biodiesel'\n", - "tech_transport['LH2'] = 'Hydrogen'\n", - "tech_transport['H2'] = 'Hydrogen'\n", - "tech_transport['JTF_EA'] = 'Jet Fuel'\n", - "tech_transport['ETHANOL'] = 'Ethanol'\n", - "tech_transport['GAS_EA'] = 'Gasoline'\n", - "\n", - "tech_commercial = dict()\n", - "tech_commercial['C_DISTOIL_EA'] = 'Other Fossil'\n", - "tech_commercial['C_NGA_EA'] = 'Natural Gas'\n", - "tech_commercial['ELC_COM'] = 'Electricity'\n", - "tech_commercial['SNG_100'] = 'Synthetic Natural Gas'\n", - "tech_commercial['C_RFO_EA'] = 'Other Fossil'\n", - "\n", - "tech_residential= dict()\n", - "tech_residential['R_BIO_EA'] = 'Biomass'\n", - "tech_residential['R_NGA_EA'] = 'Natural Gas'\n", - "tech_residential['ELC_RES'] = 'Electricity'\n", - "tech_residential['ELCDIST_R'] = 'Electricity'\n", - "tech_residential['SNG_100'] = 'Synthetic Natural Gas'\n", - "tech_residential['R_DISTOIL_EA'] = 'Other Fossil'\n", - "tech_residential['R_LPG_EA'] = 'Other Fossil'\n", - "tech_residential['RWHSOL'] = 'Residential Solar'\n", - "tech_residential['H2_100'] = 'Hydrogen'\n", - "\n", - "\n", - "tech_industrial = dict()\n", - "tech_industrial['ELC'] = 'Electricity'\n", - "tech_industrial['I_COAL'] = 'Coal'\n", - "tech_industrial['I_GSL_EA'] = 'Gasoline'\n", - "tech_industrial['I_NGA'] = 'Natural Gas'\n", - "tech_industrial['I_OTH_EA'] = 'Other Fossil'\n", - "tech_industrial['I_LPG'] = 'Other Fossil'\n", - "tech_industrial['I_DFO'] = 'Diesel'\n", - "tech_industrial['I_RFO'] = 'Residual Fuel Oil'\n", - "tech_industrial['I_REN'] = 'Biomass'\n", - "tech_industrial['SNG_100'] = 'Synthetic Natural Gas'\n", - "tech_industrial['H2_100'] = 'Hydrogen'\n", - "\n", - "tech_colormap = dict()\n", - "tech_colormap['Synthetic Fuel'] = '#595959'\n", - "tech_colormap['Other Fossil'] = '#ABABAB'\n", - "tech_colormap['Jet Fuel'] = '#8172B2'\n", - "tech_colormap['Diesel'] = 'darkorange'\n", - "tech_colormap['Gasoline'] = '#C44E52'\n", - "tech_colormap['Electricity'] = '#55A868'\n", - "tech_colormap['Biodiesel'] = 'steelblue'\n", - "tech_colormap['Ethanol'] = '#64B5CD'\n", - "tech_colormap['Hydrogen'] = '#e5ae38'\n", - "\n", - "tech_colormap['Natural Gas'] = 'peru'\n", - "tech_colormap['Synthetic Natural Gas'] = 'tan'\n", - "\n", - "tech_colormap['Biomass'] = 'darkseagreen'\n", - "tech_colormap['Residential Solar'] = 'lemonchiffon'\n", - "tech_colormap['Coal'] = 'dimgray'\n", - "\n", - "tech_colormap['Residual Fuel Oil'] = 'chocolate'\n", - "tech_colormap['Distillate Oil'] = '#ABABAB'\n", - "tech_colormap['Petroleum'] = '#ABABAB'\n", - "tech_colormap['Geothermal'] = 'pink'\n", - "\n", - "tech_colormap['Hydro'] = 'b'\n", - "tech_colormap['Other Renewables'] = 'b'\n", - "tech_colormap['Wind'] = 'lightskyblue'\n", - "tech_colormap['Solar'] = 'lemonchiffon'\n", - "tech_colormap['Nuclear'] = 'darkorange'\n", - "\n", - "tech_colormap['ICEV-E10'] = '#C44E52'\n", - "tech_colormap['CI-Diesel'] = 'darkorange'\n", - "tech_colormap['ICEV-CNG'] = 'peru'\n", - "tech_colormap['EV'] = '#55A868'\n", - "tech_colormap['ICEV-E85'] = '#64B5CD'\n", - "tech_colormap['PHEV'] = 'dimgray'\n", - "tech_colormap['ICEV-LPG'] = '#ABABAB'\n", - "tech_colormap['CI-B20'] = 'darkseagreen'\n", - "\n", - "\n", - "color_dict = dict()\n", - "color_dict['DAC to sequestration'] = 'darkorange'\n", - "color_dict['CC to sequestration'] = 'b'\n", - "color_dict['DAC to fuels'] = 'darkred'\n", - "color_dict['CC to fuels'] = 'lightskyblue'\n", - "\n", - "color_dict['Coal'] = 'dimgray'\n", - "color_dict['Geothermal'] = 'pink'\n", - "color_dict['Biomass'] = 'darkseagreen'\n", - "color_dict['Hydro'] = 'b'\n", - "color_dict['Natural Gas'] = 'peru'\n", - "color_dict['Wind'] = 'lightskyblue'\n", - "color_dict['Solar'] = 'lemonchiffon'\n", - "color_dict['Nuclear'] = 'darkorange'\n", - "color_dict['Pumped Hydro'] = 'lightcoral'\n", - "color_dict['Battery'] = 'red'\n", - "color_dict['Hydrogen'] = '#e5ae38'\n", - "color_dict['Curtailment'] = 'darkgrey'\n", - "\n", - "color_dict['Commercial'] = '#C44E52'\n", - "color_dict['Industrial'] = 'darkorange'\n", - "color_dict['Transport'] = '#8172B2'\n", - "color_dict['Residential'] = 'lightskyblue'\n", - "color_dict['Supply'] = 'darkgrey'\n", - "color_dict['Electric'] = '#55A868'\n", - "color_dict['Petroleum'] = '#ABABAB'\n", - "color_dict['Other Renewables'] = 'b'\n", - "\n", - "color_dict['NG SMR (CCS) - Hydrogen'] = 'peru'\n", - "color_dict['BECCS - Electricity'] = 'darkseagreen'\n", - "color_dict['BECCS - Hydrogen'] = '#e5ae38'\n", - "color_dict['DAC'] = 'red'\n", - "\n", - "\n", - "color_dict['TotalInvestment_discounted'] = 'b'\n", - "color_dict['TotalInvestment'] = 'b'" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "7dcc11c4", - "metadata": {}, - "outputs": [], - "source": [ - "def func_stacked_plot(df_list, ax = None, col_order = ['Biomass','Geothermal','Hydro','Nuclear',\\\n", - " 'Coal','Natural Gas','Solar','Wind','Pumped Hydro', 'Battery', 'Hydrogen'], loc='default', color_dict= color_dict):\n", - " # df list needs to come from one of the prep functions above\n", - " bar_width = 1\n", - " if ax is None:\n", - " ax = plt.gca() \n", - " # specify order of energy source stack here\n", - " \n", - "# fig, ax = plt.subplots(figsize=(8, 6))\n", - "\n", - " num_dfs = len(df_list)\n", - " col_spacing = [x - (num_dfs / 1.8 - 0.5) for x in np.arange(num_dfs)]\n", - "\n", - " for df_in_list, spacing in zip(df_list, col_spacing):\n", - " col_order_inst = [\n", - " y for y in col_order for x in df_in_list.index if x == y\n", - " ]\n", - " # plotting the first set of bars to cumulatively add on\n", - " df_in_list = df_in_list.loc[col_order_inst, :]\n", - " ax.bar(df_in_list.columns + spacing,\n", - " df_in_list.iloc[0, :],\n", - " label=df_in_list.index[0],\n", - " width=bar_width,\n", - " color=color_dict[df_in_list.index[0]])\n", - "\n", - " cumsum = df_in_list.iloc[0, :]\n", - "\n", - " for i in np.arange(1, len(df_in_list)):\n", - " ax.bar(df_in_list.columns + spacing,\n", - " df_in_list.iloc[i, :],\n", - " bottom=cumsum,\n", - " label=df_in_list.index[i],\n", - " width=bar_width,\n", - " color=color_dict[df_in_list.index[i]])\n", - " cumsum = cumsum + df_in_list.iloc[i, :]\n", - " \n", - " \n", - " handles, labels = ax.get_legend_handles_labels()\n", - " unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - " if loc=='inside_upper_left':\n", - " plt.legend(*zip(*unique[::-1]), loc='upper left', frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - " elif loc=='inside_upper_right':\n", - " plt.legend(*zip(*unique[::-1]), loc='upper right', frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - " else:\n", - " plt.legend(*zip(*unique[::-1]), loc='upper left',bbox_to_anchor=(1.01, 1), frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - " ax.tick_params(axis = 'x', labelrotation=90)\n", - " return ax" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "cef70285", - "metadata": {}, - "outputs": [], - "source": [ - "#return fuel consumption dataframe for a sector\n", - "def stacked_penergy_sector(con, scenario, sector, region):\n", - " if sector =='commercial':\n", - " fuels_list = ['C_DISTOIL_EA','C_LPG_EA','C_NGA_EA','C_RFO_EA','ELC_COM','SNG_100','H2_100', 'ELCDIST_R']\n", - " elif sector=='residential':\n", - " fuels_list = ['R_DISTOIL_EA','R_LPG_EA','R_NGA_EA','RWHSOL', 'R_BIO_EA','ELC_RES','SNG_100','H2_100', 'ELCDIST_R']\n", - " elif sector == 'transport':\n", - " fuels_list = ['MGO_EA','DSL_EA','GAS_EA','CNG_EA','ETHANOL', 'JTF_EA', 'RFO_EA', 'T_LPG_EA','MEOH', 'T_Liquids', 'ELC_TRN', 'BIODSL', 'BIO_JTF', 'ELCDIST_R', 'LH2', 'H2']\n", - " elif sector == 'industrial':\n", - " fuels_list = ['I_COAL', 'I_DFO', 'I_GSL_EA', 'I_NGA', 'I_REN', 'I_RFO', 'I_LPG', 'I_OTH_EA', 'SNG_100', 'H2_100', 'ELC', 'ELCDIST_R']\n", - " else:\n", - " print('Sector input is either residential, commercial, industrial, or transport')\n", - " \n", - " if region=='All':\n", - " query = \"SELECT input_comm, t_periods, SUM(vflow_in) AS vflow_in FROM Output_VFlow_In \\\n", - " WHERE scenario='\" + scenario + \"' AND sector='\" + sector + \\\n", - " \"' AND vflow_in > 1e-6 GROUP BY input_comm, t_periods\"\n", - " else:\n", - " query = \"SELECT input_comm, t_periods, SUM(vflow_in) AS vflow_in FROM Output_VFlow_In \\\n", - " WHERE scenario='\" + scenario + \"' AND sector='\" + sector + \"' AND regions='\"+ str(region) +\\\n", - " \"' AND vflow_in > 1e-6 GROUP BY input_comm, t_periods\"\n", - "\n", - " df_sector = pd.read_sql_query(query, con)\n", - " df_sector = df_sector[df_sector['input_comm'].isin(fuels_list)]\n", - " \n", - " if (df_sector['input_comm'].str.contains('ELC_').any()):\n", - " df_sector = df_sector[df_sector['input_comm']!='ELC']\n", - "\n", - " \n", - " df_sector = df_sector.pivot_table(values='vflow_in', index='input_comm', columns='t_periods')\n", - " df_sector.fillna(0, inplace=True)\n", - " return df_sector" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "3c1b2e24", - "metadata": {}, - "outputs": [], - "source": [ - "# os.mkdir('carbon_tax_figures_updates')" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "75f3a962", - "metadata": {}, - "outputs": [], - "source": [ - "# list_of_DBs = ['US_9R_8D_CT_neg50.sqlite', 'US_9R_8D_CT_neg10.sqlite', 'US_9R_8D_CT_0.sqlite', \\\n", - "# 'US_9R_8D_CT_10.sqlite','US_9R_8D_CT_50.sqlite','US_9R_8D_CT_100.sqlite',\\\n", - "# 'US_9R_8D_CT_250.sqlite',\\\n", - "# 'US_9R_8D_CT_400.sqlite','US_9R_8D_CT_600.sqlite']\n", - "\n", - "# list_of_DBs = ['US_9R_8D_CT_neg50.sqlite', 'US_9R_8D_CT_neg10.sqlite', 'US_9R_8D_CT_0.sqlite', \\\n", - "# 'US_9R_8D_CT_10.sqlite', 'US_9R_8D_CT_50.sqlite','US_9R_8D_CT_100.sqlite','US_9R_8D_CT_200.sqlite',\\\n", - "# 'US_9R_8D_CT_400.sqlite','US_9R_8D_CT_600.sqlite','US_9R_8D_CT_800.sqlite','US_9R_8D_CT_1000.sqlite']\n", - "\n", - "list_of_DBs = ['US_9R_8D_CTneg10.sqlite','US_9R_8D_CT0.sqlite','US_9R_8D_CT10.sqlite', 'US_9R_8D_CT100.sqlite', 'US_9R_8D_CT200.sqlite', \\\n", - " 'US_9R_8D_CT300.sqlite', 'US_9R_8D_CT400.sqlite', 'US_9R_8D_CT500.sqlite']\n", - "list_of_scenarios = ['test_run', 'test_run', 'test_run', 'test_run', 'test_run', 'test_run', 'test_run', \\\n", - " 'test_run', 'test_run','test_run','test_run','test_run']\n", - "\n", - "list_of_conns = [sqlite3.connect(db) for db in list_of_DBs]" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "b30a0cc0", - "metadata": {}, - "outputs": [], - "source": [ - "query = \"SELECT t_periods, sum(emissions) as emissions FROM Output_Emissions \\\n", - " WHERE emissions_comm='co2' GROUP BY t_periods\"\n", - "emiss_store = dict()\n", - "for conn, db in zip(list_of_conns, list_of_DBs):\n", - " df_read_emissions = pd.read_sql_query(query, conn)\n", - " df_read_emissions['emissions'] /= 1000\n", - " emiss_store[db] = df_read_emissions.set_index('t_periods')\n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "eec17e7e", - "metadata": {}, - "outputs": [], - "source": [ - "query = \"SELECT * FROM Output_Duals WHERE constraint_name LIKE '%EmissionLimit%' AND constraint_name LIKE '%co2%' \\\n", - "AND constraint_name LIKE '%global%'\"\n", - "duals_store = dict()\n", - "for conn, db in zip(list_of_conns, list_of_DBs):\n", - " df_duals = pd.read_sql(query, conn)\n", - " df_duals['t_periods'] = [int(x[1]) for x in df_duals['constraint_name'].str.split(',')]\n", - " df_duals['shadow_price'] = -1*df_duals['dual']*1000\n", - " df_duals.set_index('t_periods',inplace=True)\n", - " duals_store[db] = df_duals\n" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "beb32695", - "metadata": {}, - "outputs": [], - "source": [ - "base = 'US_9R_8D_CT0.sqlite'\n", - "emis_reductions = dict()\n", - "for db in list_of_DBs:\n", - " emis_reductions[db] = emiss_store[base] - emiss_store[db]\n" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "id": "5d4e42b9", - "metadata": {}, - "outputs": [], - "source": [ - "map_scenario_names = dict()\n", - "map_scenario_names['neg50.'] = '-50$/tonne'\n", - "map_scenario_names['neg10.'] = '-10$/tonne'\n", - "map_scenario_names['10.'] = '10$/tonne'\n", - "map_scenario_names['50.'] = '50$/tonne'\n", - "map_scenario_names['100.'] = '100$/tonne'\n", - "map_scenario_names['200.'] = '200$/tonne'\n", - "map_scenario_names['300.'] = '300$/tonne'\n", - "map_scenario_names['400.'] = '400$/tonne'\n", - "map_scenario_names['500.'] = '500$/tonne'\n", - "map_scenario_names['600.'] = '600$/tonne'\n", - "map_scenario_names['800.'] = '800$/tonne'\n", - "map_scenario_names['1000.'] = '1000$/tonne'\n", - "\n", - "\n", - "map_scenario_names[''] = 'No carbon tax'" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "d25052b6", - "metadata": {}, - "outputs": [], - "source": [ - "output_list = []\n", - "scen_name_all = []\n", - "for conn, scenario, db in zip(list_of_conns, list_of_scenarios, list_of_DBs):\n", - "\n", - " query = \"SELECT t_periods, tech, sum(vflow_out) FROM Output_VFlow_Out WHERE input_comm LIKE 'ethos%' AND tech NOT LIKE '%_emissions%' \\\n", - " GROUP BY t_periods, tech\"\n", - " df_s = pd.read_sql_query(query, conn)\n", - "\n", - " ethos_tech_map = dict()\n", - " ethos_tech_map['E_SOLPV'] = 'Solar'\n", - " ethos_tech_map['SOLELC'] = 'Solar'\n", - " ethos_tech_map['E_WND'] = 'Wind'\n", - " ethos_tech_map['E_OFWND_N'] = 'Wind'\n", - " ethos_tech_map['E_GEO'] = 'Other Renewables'\n", - " ethos_tech_map['E_HYD'] = 'Other Renewables'\n", - " ethos_tech_map['Corn'] = 'Biomass'\n", - " ethos_tech_map['Herbaceous'] = 'Biomass'\n", - " ethos_tech_map['Soybeans'] = 'Biomass'\n", - " ethos_tech_map['Waste'] = 'Biomass'\n", - " ethos_tech_map['Woody'] = 'Biomass'\n", - " ethos_tech_map['DFO'] = 'Petroleum'\n", - " ethos_tech_map['DISTOIL'] = 'Petroleum'\n", - " ethos_tech_map['IMPRESNGA'] = 'Natural Gas'\n", - " ethos_tech_map['IMPELCNGA_S3'] = 'Natural Gas'\n", - " ethos_tech_map['IMPCOMNGA'] = 'Natural Gas'\n", - "# ethos_tech_map['NGA'] = 'Natural Gas'\n", - " ethos_tech_map['INDNG'] = 'Natural Gas'\n", - " ethos_tech_map['CNG'] = 'Natural Gas'\n", - " ethos_tech_map['LNG'] = 'Natural Gas'\n", - " ethos_tech_map['COAL'] = 'Coal'\n", - " ethos_tech_map['COAB'] = 'Coal'\n", - " ethos_tech_map['COAS'] = 'Coal'\n", - " ethos_tech_map['URN'] = 'Nuclear'\n", - " ethos_tech_map['RFO'] = 'Petroleum'\n", - " ethos_tech_map['BIO'] = 'Biomass'\n", - " ethos_tech_map['REN'] = 'Biomass'\n", - " ethos_tech_map['GAS'] = 'Petroleum'\n", - " ethos_tech_map['JTF'] = 'Petroleum'\n", - " ethos_tech_map['LPG'] = 'Petroleum'\n", - " ethos_tech_map['DSL'] = 'Petroleum'\n", - " ethos_tech_map['GSL'] = 'Petroleum'\n", - " ethos_tech_map['MGO'] = 'Petroleum'\n", - " ethos_tech_map['IMPINDOTH'] = 'Petroleum'\n", - "\n", - "\n", - " for key in ethos_tech_map.keys():\n", - " mask = df_s['tech'].str.contains(key)\n", - " df_s.loc[mask,'tech_rev'] = ethos_tech_map[key]\n", - " \n", - " df_s_pivot = df_s.groupby(by=['t_periods', 'tech_rev']).sum().reset_index()\n", - " df_s_pivot = df_s_pivot.pivot_table(index='tech_rev', columns='t_periods')\n", - " df_s_pivot.fillna(0, inplace=True)\n", - " df_s_pivot.columns = [x[1] for x in df_s_pivot.columns]\n", - " \n", - " df_s_pivot = df_s_pivot.loc[['Coal','Petroleum','Natural Gas','Nuclear','Other Renewables','Biomass','Solar','Wind']]\n", - " df_s_pivot /= 1000\n", - " output_list.append(df_s_pivot)\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('CT')[1]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " \n", - " scen_name_all.append(scen_name)" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "de9fa722", - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "image/png": "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cIA//vGPbN++nT/96U+9/7aDCYfDXH311Rw4cID3v//9LF26lO7ubp5//nmOHTtGcXExwWCQe+65h3e961188IMfJBqN8ve//50bb7yRX//611x44YX9HvOtt97i8ccf5+qrr6agoIA5c+b03rZ161Yee+wxrrnmGjweD/feey833ngjv/3tb1m1ahUAHR0dbNq0ie7ubq6++mqKiop45JFHuOWWW+ju7uYTn/hEv+d77LHH6Orq4qqrrsLhcPC73/2OG2+8kWeffZacnJxBf+68vDy+/vWv881vfpN3vOMdvOMd7wBg5syZAOzcuZM33niDSy+9lPLyclpaWrjnnnu4+uqreeihhygsLATga1/7Gq+99hr/+q//yn333YfdbueRRx7hkUce4dZbb6WqqmrI370YGzI+i+lE+rOYTqQ/i7Em189y/SxGRsZnMdZkfJbxeVQpMa0cOnRIVVdXqz//+c9KKaUuueSSU57/1ltvqerqanXo0KHeY5/61KcGvd8zzzyjqqur1Y9//ON+x7/zne+o6upq9fLLL/ceu+SSSwYci0ajat26derzn/9877FXX31VVVdXq3e84x2qp6en9/iTTz6pqqur1bPPPtt77JOf/KR65zvfqcLhcL/n/+IXv6hWrFihQqHQKX9WcWbuv/9+VV1drbZu3arq6+vV4sWL1de//vXe20/uN/v371fV1dXq5ptv7vc4v/3tb/v10aH89Kc/VdXV1eqvf/3rgNsMw1BKKZVIJFQ0Gu13WzQaVe985zvVtdde2+94dXW1mj9/vtqzZ8+Ax6uurlbV1dXqrbfe6j3W0dGhVq1apa666qreY9/73vdUdXW12rx5c7/n+9CHPqTOOecc5ff7lVJK1dXVqerqanXeeeep9vb23nP37Nmjqqur1R/+8IdT/uwtLS2qurpa/fSnPx1w28n9Xymlampq1JIlS9QvfvGLfsc3b96s5s+fr370ox+plpYWtXr1anX11Vf3/v7E+JLxWUwn0p/FdCL9WYwVuX6W62dxZmR8FmNFxmcZn8eCpIuZZmbPns2KFSv47ne/y3e+8x1CoRBNTU1Dnv/cc89RUVGR0azPs88+i6ZpfOpTn+p3/B//8R97H6uvyspKzj///N7v7XY7y5cvH3Rb15VXXonD4ej9Pj2zVldXB5jFSzZv3sw73/lOIpEIHR0dvR8XXXQRoVCIXbt2DfsziNHRd7Z3qNxl6f5w3XXX9Tu+adMmvF7voFuV+nr88ceZO3cu733vewfcpmkaABaLBbvdDphbq7q6uggGg6xatYrdu3cPuN+KFStYuHDhoM+3ZMkSVq5c2ft9bm4u73nPe9i6dSvd3d2A+RpYtGgR69at6z3PbrfziU98gnA4PKBa9uWXX05eXl7v9wsXLsTr9fb265FwuVy9X0ciETo7O/H5fFRWVg74mdetW8fVV1/Nr3/9a/7pn/6JeDzObbfd1vv7E+NLxmcxnUh/FtOJ9GcxHuT6Wa6fxemT8VmMBxmfZXweLZIuZprRdZ3f/OY3/PKXv+TRRx+lq6uLDRs2UFVVxec///nerVVpzz33HJdccklGj11fX09BQQFZWVn9jhcVFZGVlUV9fX2/42VlZQMeIzs7e0AOpcHOzc7OBuh98R87dgylFHfccQd33HHHoO1rb2/P6OcQo+P666/ngQce4M477+Q//uM/Btx+/PhxNE3rt2UJzEF7xowZA/rLyWpra9m4ceOw7bjvvvv47W9/y+HDh1FK9R4fbKBNb0kaTGVl5ZDHGhsbyc7Opr6+nksvvXTAeXPnzgXI+DWQ7tcjEY1G+clPfsLf/vY3Wltb+92Wm5s74Pybb76Zp556it27d/PNb36TioqKET+3ODMyPovpRPqzmE6kP4vxItfPJ8j1s8iEjM9ivMj4fIKMzyMnQfZpyOv1ctNNN3HTTTexceNGbrnlFu6++27++Z//GYfD0fvCbmpqYv/+/Xz5y18+4+fs++JP0/XMN0pYLJZTPq5hGABce+21bNiwYdBzq6urM34+ceZOzl12OpRSGc02DnfOQw89xNe+9jU2btzIpz/9afLy8rBardx///089NBDA87vu5og03aeyXnD9euR+M53vsN9993H1VdfzcqVK/H5fOi6zne/+91BH3f//v20tLQAcODAgRE/rxgdMj6L6UT6s5hOpD+L8SDXz8OfJ9fP4mQyPovxIOPz8OfJ+Dw8CbKfBS677DIuuugi1q1bx6OPPtr7R+jZZ5/F7XazZs2afucP9cIvLy/n5Zdfxu/395vtbW1tJRAIUF5ePmY/w4wZMwDzRd13i5aYWH1ne09WUVGBUoojR46wYMGC3uOxWIzjx4+zdu3aUz72zJkzhx00H3nkEWbMmMEvfvGLfv12JBXZa2pqBhw7duwYQG/xk/Lyco4cOTLgvPSx0XoNnOqP7yOPPML73/9+/u3f/q3f8e7u7gEzvT09Pfzrv/4rFRUVbNiwgd///ve8/e1v77cdTEwsGZ/FdCL9WUwn0p/FWJHrZ5NcP4uRkvFZjBUZn00yPo+c5GSfZoLBIIlEYsDxZDKJYRj9Zrqef/551q1b15vzKc3tduP3+wc8xiWXXIJSit/+9rf9jt91110AXHzxxWf+AwwhPz+ftWvX8uc//3nQHFkdHR1j9txiaH1ne0/OjZeekT+5v9x7770Eg8Fh+8tll13GoUOHePjhhwfclp7RTM+k9p3hrKur46mnnjrdH4Vdu3axdevW3u87Ozt56KGHOOecc3q3911yySXs2bOHV199tfe8eDzO7373O1wu14ALupFK5yUbbNuVxWIZMKP70EMP9c7m9vWDH/yA2tpavve97/HlL3+Z6upqvvrVrxIMBkelneL0yPgsphPpz2I6kf4sxpNcP8v1s8icjM9iPMn4LOPzmZKV7NPM7t27+frXv84HP/hBFi9eTCwW48EHH+T3v/898Xi8t8hCNBrl1Vdf5atf/eqAx1iyZAmPP/443/72t1m+fDm6rvPud7+biy++mAsvvJCf//znNDY2smTJErZu3crf//533va2t435DOw3vvENNm3axHvf+14+/OEPU1lZSWdnJ7t37+all15iy5YtY/r8YnDp2d5Dhw71m+mcP38+V111Fffeey+BQIDzzz+fgwcPcu+997J06VLe//73n/Jxr7vuOp544gluvvlmXn75ZZYuXUogEOCFF17gC1/4AqtXr2bjxo088cQT3HDDDWzcuJHm5mb++Mc/UllZyb59+07r56iurub666/n6quvxuPx9P6x/Jd/+Zfecz796U/z8MMPc8MNN3DNNddQWFjII488wrZt27j11lvx+Xyn9ZxD8Xg8zJ49m0ceeYTZs2eTk5NDRUUFy5cvZ+PGjTz44IN4vV7mzZvH3r17efTRR3tXQ6S99tpr/OEPf+C6667rLXjyn//5n3zoQx/iO9/5DrfddtuotFVkTsZnMZ1IfxbTifRnMd7k+lmun0VmZHwW403GZxmfz4QE2aeZhQsX8r73vY/HHnuMX//61/j9fr7zne9QVVXFnXfeyerVqwF49dVXiUQig+b/uvrqqzl06BB///vf+cMf/oBS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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "fig, ax = plt.subplots(figsize=(26,6))\n", - "for ind_iter in np.arange(len(output_list)):\n", - " subp = plt.subplot(1,len(output_list)+2,ind_iter+1)\n", - " plt.stackplot(output_list[ind_iter].columns, output_list[ind_iter], alpha = 0.75, labels=output_list[ind_iter].index, \\\n", - " colors = output_list[ind_iter].index.map(tech_colormap))\n", - " \n", - " \n", - " if ind_iter==0:\n", - " plt.ylabel('Primary energy consumption (EJ)')\n", - " else:\n", - " subp.set(yticklabels=[])\n", - "\n", - " plt.grid(axis='x')\n", - " plt.xticks(rotation='vertical')\n", - " plt.xlim([output_list[ind_iter].columns.min(), output_list[ind_iter].columns.max()])\n", - " plt.title(scen_name_all[ind_iter].replace('$/tonne','\\n $/tonne'))\n", - " plt.ylim([0, 100])\n", - "\n", - "# handles, labels = subp.get_legend_handles_labels()\n", - "# unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - "# if l not in labels[:i]]\n", - "# subp = plt.subplot(1,len(output_list)+2,ind_iter+2)\n", - "# subp.legend(handles[::-1], labels[::-1], loc='upper left', frameon=False)\n", - "\n", - "# dummy_df = pd.DataFrame(index=output_list[ind_iter].index, columns=output_list[ind_iter].columns)\n", - "# dummy_df.transpose().plot.bar(kind='stacked',ax=subp, color = output_list[ind_iter].index.map(tech_colormap))\n", - "# subp.set(yticklabels=[],xticklabels=[] )\n", - "# plt.legend(loc='upper left')\n", - "# plt.grid(False)\n", - "# plt.axis('off')\n", - "\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_scens_all_primaryenergy.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "073b3035", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAA0gAAAI1CAYAAADsLNpwAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8/fFQqAAAACXBIWXMAAAsTAAALEwEAmpwYAACQVklEQVR4nOzdd1gU1/s28Hvo0kUEEbsGMaACKqhYsGDHErsoSlQsiDVYo+arRuwNjA0balRAY2/Ya7AXIsaKDRSVJihlYd8//LGvhDa7LK7K/bkur4uZc+Y8zxCD+zBzzhGkUqkUREREREREBDVVJ0BERERERPS1YIFERERERET0f1ggERERERER/R8WSERERERERP+HBRIREREREdH/YYFERERERET0f1ggERERERER/R8WSERERERERP+HBRIREREREdH/YYFERERERET0f1ggERERERER/R8WSERERERERP+HBRIREREREdH/0ZD3gjdv3iA+Ph6CIKB06dIwNTUtjryIiIiIiIi+uEILpJSUFBw+fBjHjx/HjRs3kJSUlKPd0NAQdnZ2aN26Ndq3bw99ff1iS5aIiIiIiKg4CVKpVJpXQ3x8PNauXYsdO3YgLS0NP/zwA2rXro2KFSvCyMgIUqkUSUlJePbsGe7cuYOHDx9CW1sbvXv3hpeXF0xMTL70vRARERERERVJvgWSg4MDKlSogN69e6Nt27aFvkr35s0bHD16FMHBwXjx4gWuX79eLAkXt6ysLKSkpEBTUxOCIKg6HSIiIqIcpFIpMjIyoKenBzU1TicnUrZ8C6TTp0/DxcVFoUGLcq2qvX//Hvfv31d1GkREREQFsrKygoGBgarTIPru5FsglVSpqan4559/YGVlBS0tLVWnQ0TfiYiICNja2qo6DSL6DqSnp+P+/fuwsbGBjo6OqtMh+u7IvYrd9y77tTotLS1oa2urOBsi+p7wZwoRKROnAhAVjwILpHXr1sk1mLq6OvT19VG9enU4ODjwf1wiIiIiIvqmFFggLV68WKFBBUFA5cqVsWbNGlSuXFmhMYiIiIiIiL60AgukEydOyDWYVCpFSkoKbt++jQULFmDOnDlyP4UiIiIiIiJSlQILJEtLS4UGrVmzJt69e4c1a9YodD0REREREZEqFFggffz4Edra2qLW2E9KSsLz589hY2MDAGjYsCGePn2qnCyJ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3sWIESPybbezs8OqVauUHpeIiIiIiCgvogskR0dHpQf/+PFjoQs/pKSkKD0uERERERFRXtQUuejevXs4efIkTp48iXv37kEqlSoUvGrVqjhz5ky+7WfOnEHlypUVGpuIiIiIiEheop8gAcDBgwexaNEivHr1CgAglUohCALMzc0xYcIEuLm5yRW8Z8+emD17NmbOnIkxY8bAxMQEABAXF4cVK1bg4sWLmDx5slxjEhERERERKUp0gbR7925MnToVVatWha+vL6pUqQKpVIqoqCiEhIRg4sSJyMjIwE8//SQ6uLu7OyIjI7Fz504EBwejTJkyAIB3795BKpWiW7duGDhwoPx3RUREREREpABBKvL9uLZt28LIyAhbtmzJtbx3Wloa3N3d8f79exw9elTuJMLDw3H06FE8f/4cUqkUlStXRtu2bYtl3lNh0tLSEBERAVtbW6Xv90TfqcXK30CZiEqoCYq9sk4lCz+rEBUv0U+QYmJi0L9//zz/R9TW1kaXLl2waNEihZJwcnKCk5OTQtcSEREREREpi+gCqUaNGnj9+nW+7a9evUL16tUVSiI6OhqXL19GXFwc2rdvDwsLC0gkEiQmJsLIyAgaGnJNlSIiIiIiIlKI6Mpj4sSJGDNmDH788cdcm8EePHgQoaGhWLFihdwJ+Pn5YevWrcjMzIQgCKhVqxYsLCyQmpoKV1dXjB49GoMGDZJ7XCIiIiIiInmJLpDWr18PY2NjTJgwAXPnzkXFihUhCAKePXuGd+/eoXLlyggMDERgYKDsGkEQsHbt2nzHDAwMxObNmzF48GA0adIEnp6esjZ9fX24uroiLCyMBRIREREREX0RogukR48eAQAsLCwAQPa6nZaWFiwsLJCeni7rk62wTWBDQkLQuXNn+Pr6Ij4+Ple7lZUVzp8/LzZFIiIiIiKiIhFdIJ08eVLpwaOjozF48OB82/X19ZGUlKT0uERERERERHlRU2VwY2NjxMbG5tt+//59mJubf8GMiIiIiIioJFNpgeTi4oLg4GDExcXlart79y5CQ0PRunVrFWRGREREREQlkUrXzx49ejTOnz+Pzp07w8XFBYIgYNeuXQgODkZYWBgsLS0xYsQIVaZIREREREQliEqfIJUtWxa7du1CixYtEBYWBqlUigMHDuDcuXPo0qULtm/fDiMjI1WmSEREREREJYjKniBl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ERERfdMKLJDMzc3zfb3uv1q3bo3WrVsrJSkiIiIiIiJVKPAVOyIiIiIiopLkqymQYmJiEBERgZSUFFWnQkREREREJZTKC6Tjx4+jTZs2aNmyJXr27Inbt28DAOLi4uDm5oawsDAVZ0hERERERCWFSguk06dPw8fHByYmJvD29s6x55KJiQksLCywe/duFWZIREREREQliUoLpJUrV8LBwQE7duzIczEIOzs7roxHRERERERfjEoLpPv376NDhw75tpctWxbv3r37ghkREREREVFJVuAy3/+VmZmJ8+fP48WLF0hISMjxShwACIIAb29v0eNpaWkhPT093/bo6GgYGBjIkyIREREREZHCRBdIkZGR8Pb2RkxMTK7CKJu8BZKDgwMOHToET0/PXG3JycnYtWsXnJycRI9HRERERERUFKILpP/9739ISUmBv78/HB0dYWhoWOTgo0aNgru7Ozw9PeHm5gYAuHv3LqKiorBhwwa8f/9eroKLiIiIiIioKEQXSHfv3oWPjw9at26ttOC1a9dGYGAgZsyYgalTpwIAFi5cCACoXLkyAgMDUb16daXFIyIiIiIiKojoAsnU1BSamppKT8DR0RFHjhzBvXv38OTJE0ilUlSsWBG2trYQBEHp8YiIiIiIiPIjukAaMGAA9uzZA3d3d6UVSh8/fkSpUqUAANbW1rC2tlbKuERERERERIoQXSCZm5tDXV0dnTp1Qvfu3VG+fHmoqeVeJbygZbv/q1GjRmjRogU6duyIZs2aQUtLS/S1REREREREyia6QBo/frzs6yVLluTZRxAEuQqkn376CceOHcPhw4ehr6+P1q1bo0OHDnB2doa6urrocYiIiIiIiJRBdIEUFBSk9OAzZszAr7/+ir///huHDh1CWFgY9u7dCyMjI7Rp0wYdOnSAk5MT5yIREREREdEXIUjz29RIBSQSCc6fP4+DBw/i5MmT+PDhA0xNTXHu3LkvlkNaWhoiIiJga2sLbW3tLxaXvl3X57qoOgUi+k44TD2t6hToG8DPKkTFS/QTpC9BQ0MDLi4uqFu3LmxsbODv74+3b9+qOi0iIiIiIioh8i2QpkyZAkEQMHv2bKirq2PKlCmFDiYIAubOnatQIsnJyTh27BgOHjyI8PBwZGZmwsrKCh07dlRoPCIiIiIiInnlWyCFh4dDEARkZWVBXV0d4eHhhQ4m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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "i = 0\n", - "df_diff_all = pd.DataFrame()\n", - "for conn, scenario, db in zip(list_of_conns, list_of_scenarios, list_of_DBs):\n", - " if i!=0:\n", - " df_diff = output_list[i] - output_list[i-1]\n", - " else:\n", - " df_diff = output_list[i] - output_list[0]\n", - "\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " df_diff_all.loc[:, scen_name] = df_diff.loc[:,2050]\n", - " i+=1\n", - "\n", - "fig, ax = plt.subplots(figsize=(12,8))\n", - "df_diff_all.transpose().plot(kind='bar',stacked=True, ax = ax, color = df_diff_all.index.map(color_dict), legend=False)\n", - "# plt.ylim([-2000, 3000])\n", - "plt.ylabel('Difference in 2050 primary energy consumption (EJ) \\n relative to preceding scenario (to the left)')\n", - "plt.legend(frameon=False)\n", - "\n", - "handles, labels = ax.get_legend_handles_labels()\n", - "unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - "\n", - "plt.legend(*zip(*unique[::-1]), loc='upper left',bbox_to_anchor=(1.01, 1), frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "plt.tight_layout()\n", - "\n", - "# fig, ax = plt.subplots(figsize=(10,8))\n", - "# df_diff_all.transpose().plot(kind='bar',stacked=True, ax = ax, color = df_diff_all.index.map(tech_colormap))\n", - "# handles, labels = subp.get_legend_handles_labels()\n", - "# unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - "# if l not in labels[:i]]\n", - "# plt.legend(*zip(*unique[::-1]), loc='upper left',bbox_to_anchor=(1.01, 1), frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "# plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_scens_all_primaryenergy_diff.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "id": "721a6f19", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAA9oAAAIqCAYAAADb8jLqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8/fFQqAAAACXBIWXMAAAsTAAALEwEAmpwYAACQAUlEQVR4nOzdZ3RUVfv38d+kk04IhFBDTSABktB77yCgKEhHFJSmgCjY8FYUbsUKinID0pQqKChN6b0ktECQ3qQEEkho6fO84Mn8jWkTMiEJfD9rZa3M2fvsc52ByTnXnF0MRqPRKAAAAAAAYBFWeR0AAAAAAACPExJtAAAAAAAsiEQbAAAAAAALItEGAAAAAMCCSLQBAAAAALAgEm0AAAAAACyIRDsfOHjwoP7zn//o1q1bFm13zpw5mjNnjkXbRO768ssv9csvv+R1GADwWOE6ixRcZwE8KiTaBdyFCxe0efNmxcbG5nUoJhEREdq8ebPFb2gAAHjUuM4CAB6GTV4HgJy5cOGCtmzZosDAQDk4OKQq69u3b57EFBERoS1btsjHx0fu7u55EkNBNXz4cBkMhrwOAwDw/3GdfbxwnQXwqPBEOxckJCTkdQiSJGtra1lbW+d1GMiC0WhUYmKiJMnGxoZ/MwDIAtdZZAfXWQB5gSfaObR582Zt2bJFQ4cO1Y4dO3TixAnZ29vr1VdflSSdPn1a27dv1+XLl2U0GlWyZEm1aNFCpUuXzrTd8+fPa+/evfr77791584dFSpUSJUrV1br1q1N36inHFuSvvrqK9O+/fv3l4+Pj2nc2IABA5SUlKQpU6aocuXK6tatW6pjpVdmNBq1b98+hYSEKDIyUnZ2dqpYsaJatWolV1fXDOM+ePCgfv31V0nS3LlzTdu7dOmiwMBASdJff/2lbdu26dq1a7KxsZGPj49atmwpT0/PrN5uHT16VDt37tSNGzdkMBjk5uamqlWrqmnTpqY6sbGx2rp1q8LDw3X79m05OjqqbNmyat26tSn2pKQkbd++XUeOHNGtW7fk4OAgPz8/tWrVKtUTiy+//FKenp5q3ry51q1bpytXrsjR0VH169dXvXr1Ur2HW7du1cmTJ3Xz5k0lJibKy8tLjRs3lq+vb6pz+M9//qOaNWuqXLly2rp1q27cuKHOnTsrMDBQX375pXx8fNS1a1dT/fv372vDhg3666+/dP/+fRUuXFjBwcGqV68e38oDeOxxnU2N6yzXWQAFA4m2hSxdulTu7u5q3ry5kpKSJElHjhzRihUr5OPjo+bNm8toNOrgwYOaO3euBgwYoFKlSmXY3tGjR3X//n0FBQXJ2dlZ165dU2hoqK5fv64XXnhBklSlShXduHFDR48eVdu2beXo6ChJ6V5Ira2tVaVKFR09elSJiYmysfm/f/rTp08rNjZW/v7+pm2///67QkNDVaNGDdWuXVt37tzR3r17dfHiRQ0ZMiRN97kUZcuWVe3atbVv3z41atRIRYsWlSTTDc+RI0e0fPlyFS9eXC1atFBsbKz27t2rWbNmafDgwSpcuHCG78mZM2e0bNkylStXTi1btpSVlZVu3Lih8+fPm+rEx8drzpw5ioiIUI0aNVSiRAndv39fp06dUlRUlFxdXWU0GrV48WKdPXtWQUFB8vLyUlRUlPbt26crV67ohRdeSPVt961bt7Rw4ULVqFFD1apV09GjR7Vu3ToVLVpUFSpUkCTFxcVp//798vf3V1BQkBISEnTkyBEtWrRIvXv3VsWKFVOdy4ULF3Ts2DHVqVNHzs7OGd78JCYmau7cuYqIiFCtWrXk6empkydPav369YqOjla7du0yfL8A4HHCdfYBrrNcZwEUDCTaFuLp6annnnvO9Do+Pl6rV69W9erVU31rWqtWLX377bfauHGj+vXrl2F7rVu3lq2tbaptpUqV0ooVK3ThwgWVKVNGXl5eKl68uI4ePSo/P78sx2kFBATowIEDOnHihKpWrWraHhYWpkKFCpkuZhcvXlRISEiqb8elBzccM2bM0J49e1J9s/1PhQsXVpkyZbRv3z5VqFBBPj4+prKkpCStX79eRYoU0cCBA2VnZydJ8vPz0//+9z9t2rRJTz/9dIbxpzzF6NOnj6ys0h/1sHPnTl27dk3dunVT9erVTdubNGkio9FoOt+TJ0+qX79+KleunKmOj4+PfvrpJ4WFhalGjRqm7ZGRkerbt6/Kly8vSQoKCtKXX36p0NBQ03vm4OCgUaNGpbqxqlu3rr777jvt2rUrzQ3A9evXNWTIEBUvXjzD85Wk0NBQXbt2TZ07d1ZwcLAkqXbt2lqyZIn27Nmj2rVrq0iRIpm2AQCPA66zD3Cd5ToLoGBgjLaF1KpVK9XrM2fOKDY2VtWqVdO9e/dMPwkJCSpXrpzOnz9v+kY+PSkXf6PRqLi4ON27d8/0bfWVK1ceKkYfHx85OTnp6NGjpm2JiYn666+/5OfnZ/p2+ejRo7Kzs1OlSpVSxe7i4iIPDw+dO3fuoY5/5coV3blzR7Vr1zZd/CXJ29tb5cuX18mTJ00X6fTY29srPj5ep0+fzrDOsWPHVLRo0VQX/xQp3b+OHj2qIkWKyMvLK9X5lSxZUnZ2dmnOz8PDw3Txlx6M7ypVqpRu3rxp2mZlZWW6+CclJen+/fuKi4tT2bJldfny5TSxlC5dOsuLv/TgpsfR0THVjZjBYFCDBg0kSSdPnsyyDQB4HHCdzRrX2f/DdRZAXuOJtoX8uytWZGSkJGnBggUZ7hMbGysnJ6d0y6Kjo/XHH3/o5MmTio+PT7Pfw7CyslLVqlV14MABxcfHy87OTidOnFB8fLwCAgJSxR4fH68pU6ak287DjldKWYYkve5bnp6eOn36tOLi4jLsLle7dm0dO3ZMP/30k1xcXFS+fHn5+fnJ19fXFNPNmzfTjNX6t8jISEVGRurTTz9Nt/zu3bupXqf3BMPBwUHXrl1LtS00NFS7d+/W9evXMz2+9OCmwhy3bt2Sh4dHmicLKV0FWdoFwJOC62zWuM7+H66zAPIaibaF/Lv7Wco3xl26dMlwUpOMLnRGo1ELFizQ3bt3TeOvbG1tZTQa9eOPP2b6bXRWqlWrpn379umvv/4yjYNycnJK1fXMaDSqUKFC6t69e7pt/PtcHxVnZ2e9/PLLOn36tE6dOqXTp0/r0KFDqlixonr16mX2jYnRaFTRokUzHHeVMgYvRUbt/vPf4ciRI1q1apV8fX3VsGFDOTk5ycrKSgcPHtSRI0fS7PvPrm8AgKxxnc19XGcBwHL4K5RLUr55d3JyStUdyhzXrl3TjRs30ozdSvn2PidKlSolNzc3hYWFydfXVydOnFBQUFCqb3ILFy6sM2fOqGTJkrK3t8/xMVOkfGN948YN05irFDdu3JCDg0OWx7O2tlblypVVuXJlGY1GbdiwQTt27NDFixdVpkwZFS5cWBEREZm24eHhocuXL6tcuXIWm0306NGjKly4sHr06JGqzYMHD+aoXXd3d125ckXJycmp/o1u3LhhKgeAJxHX2bS4zmYf11kAuYUx2rmkYsWKcnBw0NatW01rN/7Tv7tN/VNGF6WdO3em2ZYyBuv+/ftmxWUwGOTv72/6ljoxMTFVdzbpwWQuRqNRmzdvTrO/0WjUvXv3Mj1GRjF5e3vL2dlZ+/fvT7UG6tWrV3XmzBlVqlQp0wvyv49rMBhM469SuvlVrVpV169fV1hYWLqxS5K/v7/u3r2rvXv3pqmTnJxs9nv5T+lNGnPz5k2Fh4dnu61/qly5su7du6dDhw6ZthmNRtP/hUqVKuWofQAoqLjOcp3lOgsgP+OJdi6xt7dXp06d9PPPP+u7775TtWrV5OzsrJiYGJ07d052dnbq3bt3uvt6enrKw8ND69evV0xMjAoVKqRTp04pJiYmTd0SJUpIkjZu3KiAgABZW1urXLlyGY5Jkx5c4Hfu3Kk///xTrq6uadYaLVu2rOrUqaPdu3fr2rVrqlixomxtbXXr1i0dP35cQUFBatSoUYbte3t7y2AwaPv27YqNjZWtra1KliypwoULq02bNlq+fLlmz56t6tWrKy4uTnv37pW9vb2aN2+e6Xu6atUq3bt3T+XKlZOrq6tu376tvXv3ytnZWWXLlpUkNWjQQOHh4Vq+fLlOnz6tkiVLKjY2VqdOnVKzZs3k4+Oj6tWr6/jx41q7dq3Onz9v2jcqKkrh4eFq06ZNmpuirFSuXFnh4eFauHChfH19FRMTo/3796tIkSJpxphlR3BwsEJDQ/Xbb7/p6tWrKlKkiE6dOqWTJ0+qbt26zIQK4InFdZbrLNdZAPlZthPt69ev6+bNmzIYDCpcuHCG6xLiwTe6rq6u2rZtm3bv3q2EhAS5uLioZMmSpiUk0mNtba3nn39ea9eu1c6dO2UwGFSxYkX17t1bn332Waq6pUqVUvPmzRUSEqJff/1VRqNR/fv3z/QGwNvbW0WKFFFkZKRq1qyZ7rfb7du3V4kSJbRv3z5t3rxZBoNBrq6uqlChgvz8/DI9bxcXF3Xq1Ek7duzQqlWrZDQa1aVLFxUuXFjVqlWTra2ttm3bpo0bN8ra2lo+Pj5q1apVpmt7Sg/GvYWGhmr//v2mCW4qVaqkpk2bmrrC2dnZacCAAdq8ebOOHz+uw4cPm8bGpVwsDQaDnn32We3du1cHDx7UyZMnZW1tLXd3d1WrVk1lypTJNI70BAYG6u7du9q/f7/OnDkjDw8PtW3bVlFRUTm6AbCxsVG/fv20ceNG05qvhQsXVuvWrVW/fv2HbhcAHgdcZ7nOcp0FkF8ZjFnM+HH37l2tWbNGf/75pw4cOJDm215XV1cFBgaqVatWat++vZydnXM1YAAAAAAA8rMME+2bN29qxowZWrRokeLi4lSpUiVVq1ZNpUuXlpubm4xGo2JiYnThwgUdOXJEp06dkr29vXr06KHBgwebvawCAAAAAACPkwwT7eDgYJUqVUo9evRQ27Zts+wifv36da1bt05LlizRpUuXFBoamisBAwAAAACQn2WYaG/evFnNmjV7qEZzsi8AAAAAAAVZlmO0AQAAAACA+VhHGwAAAAAAC8p0ea///e9/2WrM2tpazs7OqlChgoKDg9NdzgIAAAAAgMdZpl3Hs1rHMcNGDQaVLVtW33//vcqWLfvQweHRO3funObOnatnnnlGAQEBeRbHnDlzJEkDBgzI9r6bN2/Wli1bNGbMGJabAwDADL/88ovCwsL0zjvv5Opxbt26pa+++kpdunRRYGBgtvePj4/X+vXr9ddff+nOnTuqUaOGunbtavE4ASCnMn2ivWHDhmw1ZjQadffuXR0+fFiffPKJJk6cmO2n4vg/8fHx2rlzp3x8fOTj42PRtvfu3Ss7O7uHusg9TngfAAD5zYULF3TmzBnVq1dPDg4OFms3JiZGoaGh8vPzU/HixS3W7qO0c+dOhYSEqFGjRipatKgKFy6siIgIHTt2TIGBgXJ3d8/rEAFAUhaJdsmSJR+qUV9fX0VGRur7779/qP3xQHx8vLZs2SJJuZJoOzs759sEs2/fvo/kOPn9fQAAPHkuXLigLVu2KDAw0OKJ9pYtW+Tu7l5gE+1z587Jy8tLLVu2NG0LCwvTli1b5OPjQ6ININ/IdDK0+/fvKzk52ayGYmJidPToUdPrevXqqV27djmLDk+chIQESQ/G+1tbW+dxNDkXExOj+/fv53UYAIBckJSUpBs3buR1GE+Uu3fvWvTLBwDILZmO0a5SpYo++eQTde7cWZJ0584dDRgwQBMmTFC1atVS1V25cqXefPNNhYeH527ET4iUMUz/9s+xSBEREdqwYYPOnz+vpKQkFS9eXE2aNFGlSpUybfvLL79UdHR0qm1ubm567bXXTGO0n376ad25c0d79uzRnTt35O3trQ4dOsjb2zvVfpGRkdq0aZPOnj2ruLg4FSlSRPXq1VNQUFCW5/jll1/K09NTDRs21IYNG3T16lU1atRIzZo1S3eM9v3797V+/XqFh4fLaDSqQoUKat++vT7//HM1bdrUtHZ7yhjt4cOHa9euXTp27JgSExNVqVIldezYUY6Ojlm+D5Zy8OBB/f777/Lz81NQUJDKlSvHJIEAUMBFRETowIEDOnz4sCpVqmTRMcIp17B/69+/v6l3W2hoqPbs2aPIyEjZ29urYsWKatWqlVxcXDJsN+X6/m8p18+UMdqvvfaa1q5dq5MnT8rKykpVq1ZV+/btZWOTuhNkWFiYdu/erWvXrsna2lply5ZVq1atVLRo0UzPL6Mx2rdv39bmzZt14sQJ3b9/X25ubgoODlaDBg1kMBgyjL9Lly769ddf091ObzUAeSnTruP/zsETEhIUFhamO3fu5GpQkBwdHdW+fXutWbNGfn5+qlKliiSpcOHCkh4kuLNnz5a1tbXq1asnOzs7HTx4UAsXLtSzzz5rqp+edu3a6ffff5eDg4MaN24sSbKzs0tVZ9euXUpOTladOnWUnJysnTt3avHixRoxYoTpSfP169c1e/ZsOTo6msaRnTx5UitXrlRcXJzq1auX5XlGRUVpyZIlCg4OVlBQkNzc3NKtZzQatWjRIl24cEHBwcEqXry4zp49q59++inDtn/++We5uLioefPmioyM1N69e2VlZaVnnnnG7Pchp8qXL69atWrpyJEjCgsLk7u7uwIDAxUYGJjhuQIA8p+4uDiFhYXpwIED+vvvv2VjY6MqVaqodu3aFj1OlSpVdOPGDR09elRt27Y1fTns6ekpSdq+fbs2bNigsmXLqnXr1oqOjta+fft04cIFDRkyJMOnvZ6enmratKm2bNmi4OBg02S1Xl5epjpGo1ELFiyQl5eXWrdurb///luhoaFydHRM1VU7JYYqVaqoevXqio+P1/79+zV79mwNHjzYdK9irrt372rWrFlKSkpSzZo15ezsrAsXLujPP//U7du31a5dO3l6eqpbt276448/Ul23PTw8VLt2be3bt880bluSSpcuna0YAMDSMk20kXfs7OxUtWpVrVmzRl5eXqpevXqq8g0bNighIUEvvvii6eJbs2ZNTZ8+XevWrZOfn1+GT079/Pz0559/ysnJKU27KeLi4vTKK6+YvsH29PTU4sWLdfr0aVWuXFmStHbtWjk7O2vw4MGytbWVJNWuXVvLli3Tpk2bFBwcnGXievPmTfXs2VO+vr6Z1jt+/LguXLigli1bqlGjRqZjrVixQlevXk13H09PTz399NOptu3du1cdO3aUg4ODWe9DTrm6uqpt27Zq3bq1Tp48qYMHD2rr1q3asmWLypcvr6CgIPn6+qZ5UgAAyB/Onz+vAwcO6NixY0pISFCpUqXUqVMnBQQEyN7e3uLH8/LyUvHixXX06FH5+fmlGnN87949bd68WT4+Purbt6+srB6MACxTpowWL16snTt3qkWLFum26+zsrIoVK2rLli0qXbp0ute95ORkVa5c2dRGrVq1dP/+fYWGhpoS7ejoaG3atClVTzLpQY+7b775Rlu3blWXLl2ydc4bN25UYmKiXn75ZdNqIbVq1ZKLi4t27dqlevXqyd3dXdWrV9fWrVvTXLdv3bqlffv2qUKFChaf0wYAHhZ39wVQcnKyTp06pcqVK5uSbEmyt7dXzZo1tXHjRl27di1HE50EBgamSv5Svvm+efOmpAfduM+cOaOmTZsqISHBNLZakipWrKijR4/q8uXLWV7wXF1ds0yyJenUqVMyGAxpnhzUrVtXhw8fTneff9ctW7as9uzZo+jo6Ec+vsvKykq+vr7y9fXV3bt3deTIER08eFDLli1ToUKFVK1aNbVs2dLiT9QBAA9n9+7d2rdvn6KiouTi4qI6deooMDAw1XX3UTtz5oySkpJUr149U5ItPfgCvUiRIjp58mSGiba50rt2/vXXX4qLi5O9vb3Cw8OVnJysgIAA3bt3z1TP2tpapUqV0rlz57J1PKPRqGPHjsnPz09WVlap2qxQoYJ27typc+fO0Q0cQIFDol0A3bt3TwkJCele7FO6TN26dStHifa/uzUXKlRIkkwTe0VFRUmStmzZku5YMulBV7CsmNu9LDo6Ws7OzmmeHhQpUiTDfbI6h+yKj49XfHy86bXBYJCTk5MSEhIUFxeXqm5m63c7OTmpXr16Cg4O1p9//ql9+/Zp7969ql+/Pok2AOQTu3fvVnR0tHx8fNS1a1ezhvvcv39fSUlJptc2NjZycHBQbGysEhMTTdutra1N16TsuHXrliRleP3PbpL7b1ZWVmnGef/z2mlvb6/IyEhJ0jfffJNuGyk93Mx17949xcbG6uDBgzp48GC6dcy5nwCA/CbLRDu97sdM5vT4++c35elJGb9fr169DCdfK1asWJbHyc0u01mdQ3bt3Lkz1ZcKKROnHT16NM1ELBMmTEi3DaPRqPPnz+vQoUM6evSoEhISVLZsWQUFBcnV1dWi8QIAHl6XLl0UEhKi48eP66uvvlKFChUUGBiY6XCfxYsX6/z586bXKROYrl27VocOHTJtL1u2bKrJPi0hk7ltzWbO/V3KcXr37p3udTa794gp7QUEBGQ4kaqHh0e22gSA/CDLLGf8+PF6++23U2176aWX0vxxNXcZMOSco6OjbG1t011SJGVbVutI5vTLkpQn0VZWVipfvnyO2jKHm5ubzpw5Y+q6liLlm/WHlZ33oUaNGipTpozpdcqNVoUKFbJc9zs6OloHDx7UoUOHdPPmTTk7O6tOnToKCgrK9Kk8ACBvlCtXTuXKldP9+/d1+PBhHThwQMuWLZODg4MpKSxRokSqfdq0aaPY2FjT65Snww0bNkw1pvhhhy+lXNtv3LiR5tpx48aNR7KGdMr1383NLcsZxs3h6Ogoe3t7JScnP5L7CQB4VDJNtLt16/ao4kA6UroR/7urs5WVlSpWrKi//vpLkZGRpottXFycQkJC5ObmlmoW0fTY2tqmuhnILicnJ5UrV04hISGqU6dOmi51d+/elZOT00O3/28VK1ZUaGioaVbRFHv27MlRu9l5HwoXLpxuV3cXF5cMl1S5du2a1q1bp7Nnz8rKykqVKlVS27ZtValSJYs/cQcAWF6hQoVUt25d1a1bV5cvX1ZoaKiOHDmi/fv3q2jRomrWrJmqVq0qSWkS7xRFixbNVlL6z+v/P5Pn8uXLy9raWnv27El1HUm5H0iZiducdh9W1apVtXHjRm3evFndu3dP84V1dq//VlZWqlKlig4fPqwrV66kWUY0NjZWtra2phVP0mOJ8wIAS8s00Z40adKjigPpsLOzU5EiRXT06FEVKVJEjo6Ocnd3V6lSpdSiRQudOXNGP/zwg2rXrm1a3is6OlrPPvtslk9qS5QooZCQEG3evFlFihSRnZ2dWZOS/VPHjh01e/ZsfffddwoODpaHh4fu3bunq1ev6tSpUxo/fnxOTj8VPz8/lSpVShs2bNCtW7fk5eWls2fPmiZne1iWeB8yc+XKFcXExKhVq1aqUaNGpmO3AQD5W4kSJVSiRAm1bdtWx44d04EDB3Ty5ElTom3J40gPZuMOCAiQtbW1ypUrJycnJzVr1kwbNmzQ/Pnz5efnp5iYGO3du1fu7u5q0KBBpu16eHjI3t5e+/fvl52dnezt7VWsWDGzhnqlKFy4sFq1aqX169dr5syZqlKligoVKqRbt27p1KlTKlmypDp16pSt823VqpXOnz+v2bNnKygoSMWKFVNcXJyuX7+uY8eOaeTIkZleP729vWUwGLR9+3ZTYl6yZMlsLzMGAJbEZGj5XJcuXbRu3TqtX79eSUlJqlGjhkqVKiVPT0+98MIL2rBhg3bt2qWkpCQVL15czz//fIZjpv+pWbNmun37tnbv3q24uDi5ubllO8EsUqSIBg8erC1btujIkSO6e/euHB0dVbRoUbVp0+ZhTzldBoNBvXr10rp16xQWFqYjR46oQoUK6t69u6ZNm/bQY70t8T5kpmrVqsyUCgCPGVtbW9WoUUM1atRINUmmpZQqVUrNmzdXSEiIfv31VxmNRvXv319OTk5q1KiRHB0dtWfPHv3xxx+m5UBbtmyZZZd0GxsbdevWTRs3btTq1auVnJyspk2bZivRlqT69eurSJEi2rVrl7Zt26bk5GS5urqqTJkyGY6zzoyTk5NefPFFbd26VX/99ZdCQkLk4OCgIkWKqFmzZllOHOfi4qJOnTppx44dWrVqlYxGo7p06UKiDSBPGYwZzJ5x9uxZlStX7qEazcm+QHZcuXJFM2bMULdu3XJtLWwAAAAAyI4MB4l26tRJo0eP1r59+8xqyGg0avfu3Ro5cqQ6d+5ssQCBFP9cqzvF7t27ZTAYslyvGwAAAAAelQz72y5btkyff/65+vbtq6JFi6pevXoKCAhQqVKl5ObmJqPRqOjoaF26dElhYWHavXu3IiMj1ahRIy1duvRRngOeEGvWrFFcXJxKly4tSTp58qTOnDmjWrVqsTQWAAAAgHwjw67jKU6ePKmff/5Zf/75py5duvRgp/8/0VbKrqVKlVLLli31zDPPqHLlyrkcMp5UR44cMX2hk5CQIHd3dwUGBqphw4bM4A0AAAAg38gy0f6niIgInTlzxjTTc+HChVWhQgWLrKMIAAAAAMDjIFuJdn6TnJysu3fvytbWNsvlrADkPqPRqISEBDk5OeWolwGfbQAAAORnWd33Fujlve7evasTJ07kdRgA/qVy5cpycXF56P35bAMAAKAgyOi+t0An2ra2tpIenJydnV0eR4OcCAsLU0BAQF6HgRyKj4/XiRMnTJ/Nh8VnGwAsj2stAFhOVve9BTrRTulSamdnJ3t7+zyOBjnFv+HjI6fdvflsA0Du4G8qAFhWRve9TNUMAAAAAIAFkWgDAAAAAGBBJNoAAAAAAFhQtsdonz59WhcvXtStW7fSLe/atWsOQwIAAAAAoOAyO9G+dOmSxo4dq4MHDyqjpbcNBgOJNgAAAADgiWZ2oj1hwgSFh4dr3LhxqlOnjlxdXXMzLgAAAAAACiSzE+39+/frxRdfVP/+/XMzHgAAAAAACjSzJ0NzcXFR4cKFczMWAAAAAAAKPLMT7aefflpr167NzVgAAAAAACjwzO463qRJE+3YsUP9+vVTz5495e3tLWtr6zT1qlevbtEAAQAAAAAoSMxOtPv06WP6fd++fWnKjUajDAaDwsPDLRMZAAAAAAAFkNmJ9qRJk3IzDgB44qxYsULjxo3T6tWrVaFCBdP2X375RW+++aZ69eqlCRMmmLYnJyerbt26at++veLj4xUWFqbffvvNIrH4+vrqjTfe0KBBgyzSHgAAwJPM7ES7W7duuRkHAFhEYrJRNlaGAnHcmjVrSpJCQkJSJdqhoaEqVKiQQkJCUtU/efKkYmJiFBwcrODgYN27dy/ngQMAAMDizE60/+n27du6fPmyJKlEiRJycXGxaFAA8LBsrAyafCDhkR93XJBttvcpU6aMihYtqtDQUD333HOm7aGhoXr66ae1cOFC3b592/Q3NjQ0VJJUq1YtlSpVyjKBAwAAwOLMnnVckg4fPqzevXurbt266tq1q7p27aq6deuqT58+Onz4cG7FCACPreDg4FRPrmNiYnTq1Ck9++yzcnZ21oEDB0xloaGh8vLyUqlSpTRu3Dh16tTJVLZ8+XL5+voqPDxcQ4YMUWBgoFq1aqUff/wxzTF//vlntWzZUtWrV1fv3r118uTJ3D3Jx1xisjGvQwDMktKLBsjv+LuKx4HZT7QPHz6sPn36yMbGRt27d1fFihVlNBp1+vRp/fbbb+rbt6/mz5/PrOMAkA01a9bUunXrdOPGDXl6eurAgQNycnKSr6+vatSoodDQUDVp0kTSg0Q7qxvlMWPG6Omnn1b//v21atUqffDBB/L19VWtWrUkSVu2bNFbb72lp556Sp07d9bJkyc1bNiwXD/Px1le9aIAgMfVw/QSA/IbsxPtL7/8Up6enlq4cKG8vLxSlQ0bNkzPP/+8vvrqK82aNcviQQLA4+qf47Tbtm2rkJAQBQYGysrKSkFBQdq9e7ckKSIiQpcuXdILL7yQaXu9evUyrRJRu3Ztbdq0SevWrTMl2t9++62CgoL06aefSnqwdKOVlZUmT56cW6cIAADwxDG76/jBgwfVs2fPNEm2JHl5ealnz56pujgCALJWpUoVOTo6msZfh4aGKigoSNKDbuVHjhxRQkKCqXt5Vk+0GzVqZPrd1tZWPj4+unbtmiQpKSlJYWFhateuXap92rZta7HzAQAAQDYSbaPRKCurjKsbDAYZjYynAIDssLa2VmBgoEJCQpSQkKAjR46Ykunq1asrPj5e4eHhCg0NlYuLiypXrpxpe66urqle29raKi4uTpIUFRWlxMREeXh4pKrj6elpwTMCAACA2Yl2tWrVtGTJEt26dStN2a1bt7R06VLGZwPAQ6hZs6bCw8O1f/9+JSQkmP6WOjk5qXLlygoJCTE96c7sC8+seHh4yMbGRlFRUam237hxI0fxAwAAIDWzx2iPHDlSAwcOVLt27dStWzeVL19eknTmzBn98ssvunPnjiZNmpRrgQLA46pmzZpKTEzUnDlz5OvrKycnJ1NZUFCQtm/fruPHj2vEiBE5Oo61tbX8/f21du1aDRgwwLR93bp1OWoXAAAAqZmdaNeqVUuzZ8/WpEmT9MMPP6Qq8/f31/jx41k2AgAeQo0aNWRjY6MtW7aod+/eqcqCgoK0cOFCGY1Gi/yNHTp0qIYMGaI33njDNOv4woULc9wuAAAA/o/Zibb0YAbb5cuX68aNG/r7778lSSVLlmR8HwDkgKOjo6pUqaIjR46YJkJLERQUJKPRKFtbW4sMz2nWrJkmTpyo6dOna82aNfL399e0adP01FNP5bjtJ1VispGlaADAghKTjbKxMuR1GECOGIwFeAazuLg4hYWFKSAgQPb29nkdDnIgJCSEHhGPAUt9JnPSTl5dnLkpeMIlhOZ1BADw+LANzusIgCxldb+a4RPtffv2SXrwFPufr7OSUj8ry5cv1/jx49Ns7927t9577z2z2gCAf8urZJckGwAAACkyTLT79u0rg8GgQ4cOyc7OzvQ6I0ajUQaDQeHh4dkKYObMmXJxcTG9phs6AAAAAKAgyzDRnjdvniTJzs4u1WtL8/f3T7OmKwAAAAAABVWGiXadOnUyfQ0AAAAAANKyMrdiv379tGvXrgzLd+/erX79+mU7gM6dO6tKlSpq0aKFpk2bpsTExGy3AQAAAABAfmH28l579+7Vs88+m2F5VFSU2ROmSVLRokU1YsQIVa9eXdbW1tq6dau+/fZbXbp0SZMnTza7HQAAAAAA8pNsraOdmatXr6pQoUJm12/cuLEaN25set2wYUO5uLho6tSpGjp0qMqUKWN2W2FhYdmKFflTSEhIXoeAfIbPNgoCliYEAMvjvhAFXaaJ9p9//qkNGzaYXi9ZskQ7d+5MUy8mJkY7d+5UjRo1chRM+/btNXXqVB09ejRbiTbraBd8rKP9eEhZT9BS+GwDAPBk4r4Q+V1W972ZJtonT57U77//LkkyGAw6cOCADh06lKqOwWBQoUKFVLNmTb399ts5CtZoNOZofwAAAAAA8lqmifYrr7yiV155RZLk5+enSZMmqXPnzrkWzOrVq2UwGBQQEJBrxwAAAAAAIDeZPUb7+PHjFj3woEGDVLduXVWuXFkGg0Hbtm3TTz/9pO7du6t06dIWPRYA5GerVq3SvHnzdPbsWSUnJ8vLy0vBwcEaPXq0ihQpYnY7y5cv1/jx47Vr1y55eHjkYsQAAADITLYnQzt37py2bt2qy5cvS5JKlCihxo0bq1y5ctlqp3z58vr555917do1JSYmysfHR6+//rr69++f3ZAA4P8YkyWD2SsX5vlxZ86cqSlTpqh///4aMWKEpAfDdlatWqWIiIhsJdoAAADIH8xOtBMTE/XBBx9o2bJlSk5OTlVmMBjUvXt3TZgwQTY25jX59ttv53hMNwCkYbCSEkIf/XFtgx9qt3nz5qlbt24aP368aVuTJk00aNCgNH9rH5WkpCQlJSXJzs4uT44PAABQ0JmdaH/xxRdasmSJunbtqj59+sjHx0eSdPbsWS1YsEBLly6Vq6urxo4dm1uxAsBjJyYmRkWLFk23zMrq/56QJycna8aMGVq6dKmuXbsmb29v9e7dWwMGDMi0/c8//1ybNm3SpUuX5OTkpODgYI0fP17e3t6mOn379pWjo6M6duyo6dOn68KFC5o7d65q1aplkXMEAAB40pidaP/yyy9q166dJk+enGp7tWrV9N///lf379/XihUrSLQBIBv8/f21cOFClSxZUi1atMgw6f7kk080d+5cDR48WLVr19aOHTs0adIk3b17V8OGDcuw/cjISA0ePFjFihXTrVu3NHfuXPXq1Utr1qyRg4ODqd7Ro0d18eJFDRs2TIULF1apUqUsfq4AAABPCrMT7Xv37qlOnToZlterV0/bt2+3SFAA8KSYMGGChg8frvfee0/vvfeeKeHu37+/aWLIqKgoLViwQAMHDtSoUaMkSY0aNdLdu3c1c+ZMDRgwQE5OTum2/9FHH5l+T0pKUp06ddSgQQNt3bpVbdq0MZXdunVLixcvVsmSJXPxbAEAAJ4MZs/cU7t2bYWEhGRYHhISotq1a1skKAB4UlSuXFm//fabZsyYoX79+snV1VXz589Xly5dFB4eLkk6fPiwEhIS1KFDh1T7duzYUffu3TPVS8+WLVvUs2dP1apVS1WrVlW9evWUnJysc+fOpYmDJBsAAMAyzE6033//fYWHh+v999/X6dOnlZCQoISEBJ0+fVoTJkzQ8ePH9f777+diqADweLKzs1PTpk319ttv65dfftHMmTMVGxurb775RpIUHR0tSWm6lXt6ekp68DQ6PYcPH9bQoUNVpEgRTZ48WYsWLdKyZctka2uruLi4dNsCAABAzpnddbxdu3YyGo06c+aMFi9eLIPBIEkyGo2SJGtra7Vr1y7VPgaDQQcPHrRctADwBGjcuLH8/Px0+vRpSZK7u7sk6caNG/Ly8jLVu3HjRqryf/vzzz/l7Oysr7/+WtbW1pKkmzdvKiEhIU3dlL/pAAAAyDmzE+0OHTpwIwYAFnbjxo00T5NjY2N15coVVaxYUdKDSSdtbW21Zs0a+fv7m+qtXr1ajo6Oqlq1arptx8bGysbGJtXs5atWrcqFswAAAMA/mZ1o/3u2cQBAznXu3FnNmzdXo0aNVKxYMUVERGj+/Pm6efOm+vfvL0ny8PBQ3759NXv2bNnZ2Sk4OFi7du3S4sWLNWLECDk6OqbbdsOGDTV37lz95z//Udu2bXXkyBEtWbJEtra2j/IUAQAAnjhmJ9oAUCAYkyXb4Lw5rsHsaS9Mhg8frk2bNmny5MmKioqSg4ODqlatqu+++07NmjUz1Rs7dqxcXV21dOlSzZgxQ8WLF9ebb76pgQMHZth206ZNNXbsWM2fP18rVqxQ9erVNX36dD333HMPc4YAAAAwk8GYMsjaTMeOHdOFCxcUExOj9Hbt0aOHxYLLSlxcnMLCwhQQECB7e/tHdlxYXkhIiGrWrJnXYSCHLPWZ5LONAichNK8jAIDHR158YQ5kU1b3q2Y/0T5z5ozGjBmj48ePp5tgSw8m03mUiTYAAAAAAPmN2Yn2W2+9pXPnzmnMmDGqUaOGXFxccjMuAAAAAAAKJLMT7WPHjmno0KF68cUXczMeAAAAAAAKNLNn7ilZsqQcHBxyMxYAAAAAAAo8sxPtIUOGaNGiRYqJicnNeAAAAAAAKNDM7jretWtXJSUlqXXr1mrZsqWKFy8uK6vUebrBYNCwYcMsHiQAAAAAAAVFtsZof/HFF4qOjtby5cvTrUOiDQAAAAB40pmdaE+YMEEJCQmaPHkys44DAAAAAJABsxPtEydO6NVXX1XXrl1zMRwAAAoWozFZBtvgvA4DAB4bRmOyDAazp5IC8iWz/weXKVNGiYmJuRkLADxxpk6dKl9fX9NPQECA2rZtq2nTpik+Pt5Ur0WLFvrggw/yMFJkJDE5Oa9DAIDHCn9X8Tgw+4n2q6++qo8++kgdOnRQqVKlcjMmAHhoiUmJsrE2+09bvjiug4OD5s6dK0mKi4vTgQMHNHXqVN29e1dvvvmmJGnatGlydXW1WLywHFtrG3Ue82tehwEAj41Vn3XJ6xCAHDP7rnD79u1ydXVV+/btVa9ePXl7e6c76/iECRMsHiQAmMvG2kZfbvjykR/3tZavPfS+VlZWCgwMNL2uW7euzp8/r/Xr15sS7apVq+YwQgAAADwqZifaixYtMv2+bdu2dOuQaAOAZTg5OaUartOiRQs1a9ZM7733nmnbn3/+qW+++UanTp2Si4uL2rRpo7Fjx8rJyUmStGfPHvXr10+zZs3SihUrtHHjRjk5OWnkyJF67rnntHTpUn333Xe6deuWGjdurIkTJ8rZ2VmSFBsbq08//VQ7duzQlStX5OHhofr16+uNN96Qu7u7KYZNmzZp2rRpOnPmjKysrFSmTBm98soratOmjVnlAAAAjyOzE+3jx4/nZhwA8ERLSapTuo7/+uuv6tatW4b1N2zYoOHDh6tt27Z67bXXdOnSJX322Wc6d+6c5syZk6ruhAkT1LVrV02bNk2//PKL3n33XV24cEGHDh3SO++8o8jISH300Uf68ssv9c4770h6kGgnJCTo1VdfVZEiRXTt2jXNmDFDL774opYtWyZJunDhgkaMGKGOHTtq9OjRMhqN+uuvvxQdHW1W+eMiPiGRbo4AYEHxCYmys330w8AAS+J/MADksXv37snf3z/VtiZNmmjMmDEZ7jNt2jRVq1ZNX375pQwGgyTJzc1NY8aM0Z49e1S3bl1T3TZt2mjEiBGSpODgYP3xxx/6+eeftWHDBjk6OkqSjh07prVr15oSbXd391STryUmJqpixYrq2rWrjh49Kn9/fx07dkwJCQl69913TU/CGzVqZNonq/LHhZ2tjfSZIa/DAIDHht0YY16HAOQY8+YDQB5zcHDQsmXLtGzZMi1atEgTJ05UeHi4hg0bJqMx7c3G3bt3FR4ervbt25uSbElq166dbGxstH///lT1/5ncFipUSF5eXgoKCjIl2ZLk4+OjGzdupJrpPOWpelBQkPz9/U3LO547d06S5OvrK2tra73++uvasGGDYmJiUh03q3IAAIDHldlPtP38/FLd0GUkPDw8RwEBwJPGyspK1apVM70OCgqSi4uLXn31VW3ZskXNmjVLVf/27dsyGo3y9PRMtd3Gxkbu7u5pumb/e7ZyW1vbdLcZjUYlJCTIzs5Of/zxh9544w11795dr776qgoXLqyYmBi9+OKLiouLkySVK1dO3333nWbMmKGRI0dKkho2bKh3331XpUuXzrIcAADgcWV2oj1s2LA0iXZSUpIuXbqkDRs2qFy5cmrevLnFAwSAJ1GlSpUkSSdOnEiTaLu4uMhgMCgyMjLV9sTERN26dUtubm45Pv7atWvl5+enjz76yLQtLCwsTb0mTZqoSZMmunv3rnbs2KHJkydrzJgxWrJkiVnlAAAAjyOzE+2U8X3puXbtmp599lmVL1/eIkEBwJPur7/+kiR5eHikKXNyclKVKlW0Zs0aDRw40LR9/fr1SkxMVK1atXJ8/NjYWNnZ2aXatmrVqgzrOzk5qU2bNgoPDzetCZ6dcgAAgMeJRSZD8/LyUs+ePfXNN9+oQ4cOlmgSAJ4YycnJOnjwoKQHT6VPnjypadOmqWjRomrdunW6+wwfPlzDhg3T6NGj1bVrV128eFGff/656tevn2oitIfVoEEDffDBB5o6dapq1qypnTt3auPGjanqLFq0SKGhoWrSpImKFSumy5cva9myZWrYsKFZ5QAAAI8ri8067ubmpgsXLliqOQB4YsTGxqpHjx6SJGtraxUvXlyNGzfWiBEjMuwG3rJlS02dOlXffPONhg4dKhcXF3Xu3Fmvv/66RWLq2bOnLl26pEWLFmn27NmqV6+evv76a9OEaNKDyc42b96s//73v7p586Y8PT3VunVrjRo1yqxyAACAx5XBmN6UttkUFRWlgQMHKi4uTmvXrrVEXGaJi4tTWFiYAgICZG9v/8iOC8sLCQlRzZo18zoM5JClPpM5aScxKVE21o9+5cK8Oi7yCZb3AgDLYXkvFABZ3a+afVfYr1+/dLffvn1bp0+fVmJioj7//POHjxQALCCvkl2SbAAAAKQw+84wvQffBoNBpUqVUoMGDfTss8/Kx8fHkrEBAAAAAFDgmJ1oz58/PzfjAAAAAADgsWCV0waMRqPu3btniVgAAAAAACjwzE60169fr08//TTVthkzZigwMFA1a9bUK6+8ovv371s8QAAAAAAAChKzE+3Zs2crKirK9PrIkSP64osvVL16dT333HPatm2bZs6cmStBAgAAAABQUJg9RvvcuXPq0KGD6fXvv/8ud3d3zZo1S3Z2drK1tdXvv/+uESNG5EqgAAAAAAAUBGY/0b5//74KFSpker19+3Y1btxYdnZ2kiQ/Pz9dvXrV8hECAAAAAFCAmJ1oFy9eXEeOHJH04On2qVOn1LBhQ1P5zZs3012oGwAAAACAJ4nZXce7dOmiqVOnKiIiQqdOnZKbm5tatGhhKj9y5IjKlSuXK0ECAAAAAFBQmP1Ee8iQIRoyZIiuXbsmb29vTZ06VS4uLpKkW7duaf/+/akSbwCA+VavXq3evXsrODhYgYGBevrpp7Vw4UIlJyenqrdnzx599913afafOnWqgoKCHlW4qbRo0UK+vr7y9fVV1apV1aJFC7355pu6cuVKnsST2/bs2SNfX19TL6+MLP/LVb4zKisqNscraQIAgALG7Cfa1tbWeu211/Taa6+lKXN3d9fOnTstGRcAPJT4hCTZ2VoXqONOmjRJc+bM0VNPPaXBgwfL1tZWmzdv1sSJE7Vnzx598cUXMhgMkqS9e/dq9uzZevnlly0Zfo61bdtWL7zwghITExUWFqavv/5ax44d0/Lly2Vra5vX4QEAADxSZifaAFAQ2Nlaq/OYXx/5cVd91uWh9tu0aZPmzJmjl156Sa+//rppe4MGDVSxYkW9++67qlu3rp5//nlLhfpQYmNj5eDgkGG5p6enAgMDJUm1atVSfHy8PvvsM4WFheXZk3YAAIC8kq3+bGfOnNGnn36qkSNHqn///urXr1+qn/79++dWnADwWJozZ45cXFzSfULdvXt3+fj46IcffpD0oHv4tGnTdO/ePVNX7b59+6ba5+TJk+rdu7dq1Kih9u3ba926dWna3bp1q3r27KkaNWqoTp06Gj9+vGJiYkzlKV2jt2zZolGjRqlWrVrZfoLu6+srSam6jxuNRs2ZM0ft2rVTQECAmjVrpunTp8toNJrqpHSBt8R5tGrVSp999pnp9c6dO+Xr66t33nnHtC08PFy+vr4KDw+XJB06dEivvPKKGjVqpMDAQHXu3FlLly5N9xyjoqI0cuRIBQUFqeH88vrugEeW70t8kvTlviJqsbCcAmZWVNvFPloc7paqzumbdhq8poTqzq2gGrMqqs0iH00LybptAACQf5idaP/+++/q3Lmz5s2bp/Pnzys5OVlGozHVz7/HEmZHUlKSunXrJl9fX61du/ah2wGAgiIxMVGhoaGqV6+enJ2d05RbWVmpWbNmOn/+vK5du6Znn31W3bt3l4ODgxYvXqzFixdrwoQJpvoJCQkaPXq0OnfurG+++UZlypTR6NGjdenSJVOdP//8U0OGDFG5cuX09ddf66233tKuXbs0atSoNMd/9913Vbx4cX399dcaMmRIts4tJcEuXbq0advkyZP1+eefq1OnTpoxY4Z69+6t6dOna8aMGan2tdR51K5dW/v27TO93rdvn+zt7dNsc3V1NX0x8PfffysoKEgTJ07Ud999p06dOumDDz7Qjz/+mOYc33vvPZUsWVJff/21nqoUoy/2eWrhMbc09f5p9AZv/XjUXf38b2pGu8tqW+623t9eTL+dcjHVeXldCUXHWeujplf1ffu/9VJglGITGecNAEBBYnbX8a+//lqVK1fWzJkzVaRIEYsHsnDhQkVERFi8XQDIr27evKn4+HiVKFEiwzopZVevXlWNGjVUvHhxWVlZmbpp/1NKgtq8eXNJkr+/vxo2bKg///xTAwYMkNFo1KRJk9S2bVtNmjTJtJ+Pj4969Oih/fv3q1atWqbtTZs21ZtvvmnWuRiNRiUmJiopKUlhYWH6/vvv1bx5c1WrVk2SdPHiRc2bN0/vvvuuevXqJelB93ij0ajvv/9effv2laOjo0XPo3bt2lq1apXu3bsnR0dH7du3T88995zmz5+va9euycvLS/v27VPNmjVlZfUgke3QoUOqc6pVq5aioqK0aNEi9e7dO9U5161b1/T+NN57Qzfu2ei7Ax7qUSVaVoa079Gey4X0xzkXzWh3SU3L3HvwHpS6p1tx1vpqfxF1qnhbUbFWuhBjp/H1/1aLsnclSfVK3Dfr3wAAAOQfZn9FfuXKFXXv3j1XkuwbN27oq6++0pgxYyzeNgAUZCndqlMmQ8uMlZWVGjZsaHpduHBheXh46Nq1a5Kkc+fO6dKlS+rYsaMSExNNPwEBAXJ2dk4zi3Z2VpL46aef5O/vr+rVq6tXr15ycHBI023baDSqXbt2qY5dv3593blzR2fPnrX4edSuXVsJCQk6cOCA4uPjdejQIT311FMqVaqU6an2/v37Vbt2bdOxoqOjNXHiRLVo0UL+/v7y9/fXnDlzdO7cuTTn3Lp161Sv25S7o6t3bXX1bvrfYe+45Cg3+yQ1LHVPicky/TQoeU8XYux0K9ZKhe2TVdI5QZ/v9dTyv1x15Q5TqQAAUBCZfQWvUKGCbt68mStBfPLJJ2rUqJHq1KmTK+0DQH5UuHBh2dnZ6fLlyxnWSemC7eXllWV7Dg4OsrOzS7XNzs5OcXFxkh6MKZak4cOHp7v/v+PIzher7du316BBgxQXF6dt27bpu+++04QJEzRlyhTTsY1Go+rXr5/u/leuXJG/v79Fz6N06dLy9vbW3r17ZWdnJ1tbW/n7+6tOnTrau3ev/Pz8FBUVlSrRHjdunEJDQzV06FBVrlxZzs7O+uWXX7RgwYI0x/HwSD1u2qNQoiTp+j0blXBOTFM/KtZG0XHW8p9ZOf334I6t3B3iNKvDJX2531Mf7iymewlW8isSq3H1rqt+SZ5sAwBQUJidaI8aNUpvvfWWOnbsqHLlylksgH379umPP/7Q6tWrlZSUZLF2ASC/s7GxUXBwsPbu3as7d+6kGaednJysLVu2qGzZsmYl2llxd3eX9GBscfXq1dOU/zuxNucpegoPDw9TN/FatWrp7t27mj9/vvr166fq1avLzc1NBoNBP/30U7rLfZUpUyZXzqNWrVrat2+f7OzsFBwcLGtra9WuXVv/+9//5OfnJycnJ1OCHxcXpy1btuiNN95INbnnL7/8km4cKQm/6fX9B5fUoo5pk2xJcrNPUmGHRP2v/d/plvu4x0uSyrkn6KtWV5SYLB2McNDX+z31yrqS2tTrjAo7PPxcKAAA4NExO9HeuHGjPD091blzZ9WrV08lSpQwjWlLYTAYUk3Mk5XExER98MEHGjx4sLy9vVNNdAMAT4IBAwbo5Zdf1owZMzR69OhUZcuXL9fZs2f1/vvvm7bZ2toqPj5eRqMxW4mwJJUvX17e3t46f/58mvHGljZ8+HAtX75c06dP1/Tp001PsqOiotSqVasctZ2d86hTp44++OADJScnm7rC165dW+PHj9eaNWsUFBQka+sH65/Hx8crKSkp1dP0uLg4rV+/Pt22//jjj1Tdx9efdVYxx0QVd0o/0W5Y8p5mHvKQjUGq4hmX5XnaWEm1isfqlaBIDfi9tC7fsVVhh6z3AwAAec/sRHvRokWm37dv355unewm2vPmzVNsbKwGDRpk9j7pCQsLy9H+yB9CQkLyOgTkMw/z2a5Zs2YuRGKeh/k/7Orqqvbt2+v777/XsWPHVL9+fdnY2OjgwYNat26d6tWrp0qVKqVqOzExURMnTpSvr68KFSqkEiVK6PLly0pKSkoTQ1xcnCIiIkzbe/TooalTp+rChQsKDg6Wg4ODIiMjdfjwYbVr104VK1bUiRMnJEnHjx9XfHx8lufw72OkaNWqlVauXKlffvlFpUuXVtu2bfX666+rY8eOqlSpkpKTk3Xt2jXt379fb731liRZ9DwkydHR0TROu0uXLqb9ixQpor1796pHjx6pjlW+fHlNmzZNN2/elI2NjVavXm0aJ59SL+X92bZtm0aPHq2nn35aO3Z7auUpV73X8Fq6E6FJDyY+a+VzRy+tKalBNaLkVyROcUlWOnPLTocjHPRlqys6HmmnybuLqkP5OyrtGq97CVaaechDxRwTVdE9638LAHhccF+Igs7sRPv48eMWPXBUVJSmTp2qCRMmKDY2VrGxsbpz544kKTY2Vrdv35aLi0sWrTwQEBAge3t7i8aHRyskJCRPEyRYRlxcnEW/+Cpon+2H/T9cs2ZNtWnTRgsWLNC0adOUnJysChUq6N1331WPHj1S9R6qUaOGrl27prVr1+rHH39U7dq1NX/+fO3cuVPW1tZpYrC3t1exYsVM22vWrKnAwEB99913pjWsvb291aBBA7Vs2VKenp5KTHzwRNbPz8/UHTwz/z5GigoVKujPP//Ujh079Omnn6pmzZpauHChFi1apJUrV8rBwUFlypRR8+bNTfta8jxSTJ48WXfu3FH37t1N3dYbNmyolStXqkuXLqmOlTK2fObMmXJxcVHPnj1lZ2dnil+S6f2ZPHmylixZouHDh8tRrnq11g319o/O9L36stVlzTrkocXh7rp021ZOtskq7x6vzpUerP9d1DFJxRyTNONgYUXcs5GTbbKCi8dqYpNrsrcxZto2ADxOuC9EfpfVfa/BmPJV/SMWHh6url27Zlju4uKi/fv3Z9pGyskVtJtxpEWi/Xiw1GcyJ+3EJyTJztb6oY/9sPLquMgnPsteN34AQCbG8MUi8r+s7lezvW7IhQsXtGXLFv3994PJXEqWLKmmTZtmayIb6cHEN/PmzUu17caNGxo9erRGjBihevXqZTc0AMizZJckGwAAACmylWhPnjxZ8+bNU3Jy6llPJ02apH79+mncuHFmt+Xk5KS6deum2pYyGVrFihVVq1at7IQGAAAAAEC+YHaiPWfOHM2ZM0etW7fWoEGDTBPNnDp1SrNnz9bcuXNVvHhxDRgwILdiBQAAAAAg3zM70V6yZImaNm2qqVOnptoeGBior7/+WoMHD9bixYtzlGiXKlVKf/3110PvDwAAAABAXrPKusoDFy9eVNOmTTMsb9q0KetgAwAAAACeeGYn2m5ubjp79myG5efOnZObm5tFggIAAAAAoKAyO9Fu2bKlFi5cqOXLl+ufK4IZjUatWLFCCxcuVKtWrXIlSAAAAAAACgqzx2iPHj1aBw8e1Ntvv60pU6aobNmykh4s9xUZGSk/Pz+NGjUq1wIFAAAAAKAgMDvRdnNz09KlS7VkyRJt3rzZtI52lSpV1Lx5cz377LOys7PLtUABAAAAACgIsrWOtp2dnfr06aM+ffrkVjwAAAAAABRoZo/RjoiI0P79+zMs379/v65fv26RoADgSTF16lT5+vqqR48eacpmzZolX19fix+zb9++GjJkiMXbBQAAwANmJ9r//e9/9fnnn2dY/tVXX+nTTz+1SFAA8NASYwvkcQ8ePKht27ZZKBgAAADkJbO7ju/bt0+9e/fOsLxx48b66aefLBIUADw0GwfpM8OjP+4YY9Z1MuDo6KhKlSpp2rRpaty4sQWDyntGo1Hx8fGyt7fP61AAAAAeGbOfaN+8eTPTdbJdXV0VGRlpkaAA4EkzbNiwTJ9q79mzR76+vjpy5Eiq7ePGjVOnTp1Sbbt27ZrGjRunhg0bqlq1amrTpo2mT5+e6fHPnDmj4cOHq3bt2qpRo4YGDhyokydPpqozZ84cPfPMM6pZs6bq1aunQYMGpamTEs/27dvVrVs3VatWTWvWrDH3bQAAAHgsmP1E28vLS2FhYRmWHzlyRJ6enhYJCgCeNE2bNlWNGjVy/FT75s2b6tGjh5KTkzVixAiVLVtWly5d0vHjxzPc59KlS3r++edVrlw5TZw4Uba2tpo9e7b69eun9evXy8XFRZJ09epV9e7dWyVKlND9+/e1ZMkS9ezZU2vWrFGxYsVM7UVERGjChAl65ZVXVKpUKRUtWvShzwcAAKAgMjvRbt26tebNm6f69eurY8eOqcpWr16tX375JdOu5QCAzA0bNkyDBw/Wtm3bHjrZnjNnjm7cuKE1a9aodOnSZu0zbdo0OTk5ac6cOXJwcJAk1alTR61atdL8+fM1dOhQSQ+eVqdISkpSw4YN1bRpU/3+++8aOHCgqSw6OlrfffedgoODH+ocAAAACjqzE+1hw4Zp586dev311/Xdd9+pUqVKMhgMOnHihE6dOqWKFStqxIgRuRkrADzWLPFUe9euXapXr57ZSbYkbd++Xe3bt5eNjY0SExMlSQ4ODgoMDNThw4dN9Q4ePKivv/5aR48e1a1bt0zbz549m6o9d3d3kmwAAPBEMzvRdnZ21qJFizRz5kytX79eGzZskCSVKVNGw4YN06BBg1SoUKFcCxQAngT/fKr9MG7duqVKlSpla5+bN29q3rx5mjdvXpoyPz8/SdLly5f1wgsvyN/fXxMmTJCXl5fs7Oz06quvKj4+PtU+DCMCAABPOrMTbUkqVKiQRowYwZNrAMgl/3yq3aZNG9P2lFm7ExISUtX/55NlSSpcuLCuXbuWrWO6ubmpadOm6tWrV5qylK7k27Zt07179zRt2rRUE2P++/iSZDDkwazvAAAA+Ui2Em0AQO5Leart6Oho2ubt7S1JOn36tKlb9p07d3Tw4MFUT5Dr16+vmTNn6uLFi2Z3H2/QoIFOnDihqlWrytraOt06sbGxMhgMsrH5v8vGhg0bdPfu3WyfHwAAwOOORBsA8pmUp9o7d+40bfPy8lJQUJCmTp0qZ2dn08zgKU+cUwwYMEArV65U3759NXToUJUpU0aXL1/WsWPH9M4776R7vFdffVXdu3fXwIED1aNHDxUtWlQ3btzQgQMHVK5cOfXq1Uv16tWTJI0fP149e/bU2bNnNWPGDHl4eOTeGwEAAFBAmb2ONgDg0Rk+fHiabVOmTFHFihX11ltv6eOPP1a3bt1MCXAKd3d3LVy4UHXq1NFnn32ml156Sd9//32q5bf+rXTp0lq6dKmKFi2qiRMn6oUXXtCnn36qGzduqFq1apIkX19fTZ48WeHh4Xr55Ze1fPlyffbZZypSpIhlTxwAAOAxYDAajca8DuJhxcXFKSwsTAEBAabxiyiYQkJCVLNmzbwOAzlkqc9kjtpJjJVsHLKuZ2l5dVzkD58xLh0ALGZMgU1P8ATJ6n6VJ9oAHi95leySZAMAAOD/MzvRjo6Ozs04AAAAAAB4LJidaDdq1EgjR47Un3/+mWZ5GQAAAAAA8IDZs4736dNHq1ev1vr16+Xm5qYOHTqoS5cuCgwMzMXwAAAAAAAoWMx+ov3mm29q8+bN+uGHH9S8eXOtXLlSzz//vNq0aaNvvvlGFy9ezM04AQAAAAAoELI1GZrBYFD9+vU1efJk7dy5U1OmTFG5cuU0ffp0tWnTRr169dLixYsVExOTW/ECAAAAAJCvmd11/N/s7e3VsWNHFS9eXPb29lq/fr1CQ0MVGhqqjz/+WM8884xGjx4tZ2dnS8YLAAAAAEC+9lCJ9rlz57Ry5UqtWrVKly5dUpEiRTRw4EB169ZNtra2WrJkiX788UddvXpV3377raVjBgAAAAAg3zI70Y6KitLq1au1cuVKHTlyRLa2tmrZsqXeeecdNW7cWFZW/9cL/c0335Snp6emTp2aK0EDAAAAAJBfmT1Gu0mTJpo4caKsrKz0/vvva8eOHfriiy/UtGnTVEl2ivLly8vDw8OiwQLA42bq1Kny9fVVjx490pTNmjVLvr6+2W5z+fLlWrVqlSXCy7ZLly7J19dXa9euzbLuvXv39P3336tbt24KCgpStWrV1Lp1a33wwQc6ffr0I4gWAAAgd5j9RHvQoEHq1q2bfHx8zKrfvHlzNW/e/GHjAoCHkpwYJysb+wJ33IMHD2rbtm1q3LhxjmNZsWKFHB0d1blz5xy3lVuioqI0YMAA/f333+rdu7dGjRole3t7nT59Wj///LOWLVumw4cP53WYAAAAD8XsRHvUqFG5GQcAWISVjb1CP272yI8b/Nbmh97X0dFRlSpV0rRp0yySaFtabGysHBwcLNrm+++/r4sXL2rx4sWqXLmyaXvdunXVq1cvLVq0yKLHAwAAeJTMTrT37duXabnBYJCdnZ2KFy+uYsWK5TgwAHiSDBs2TIMHD87yqfbnn3+uTZs26dKlS3JyclJwcLDGjx8vb29vSVLfvn21d+9eSTJ1Ox8+fLhGjBihFi1aqFmzZnrvvfdM7e3Zs0f9+vXTsmXLVK1aNdN+Y8aM0d27d/Xzzz/r5s2bOnr0qA4dOqTvvvtOR44c0Z07d1S6dGn169dPzz77bLbO9e+//9b69ev1wgsvpEqy/6lnz57ZOm9JCg0N1eeff67w8HAlJyerRIkS6tOnj55//vlsxQcAAJBTZifaffv2lcFgMKtuuXLlNHLkSLVr1+6hAwOAJ0nTpk1Vo0aNLJ9qR0ZGavDgwSpWrJhu3bqluXPnqlevXlqzZo0cHBw0YcIEjR07Vg4ODnrzzTclScWLF892PPPmzVNAQIA+/PBDxcfHS3qQIAcFBalHjx5ycHDQoUOH9MEHHyg+Pl69e/c2u+19+/bJaDSqUaNGZu+T1XnfuXNHQ4YMUVBQkD7//HPZ2dnpzJkzunPnTrbPHQAAIKfMTrRnzZqlKVOm6P79+3ruuefk4+Mjo9Goc+fOaenSpXJ0dNQrr7yiv//+WwsXLtSoUaNkY2OjVq1a5Wb8APDYMOep9kcffWT6PSkpSXXq1FGDBg20detWtWnTRhUrVpSzs7McHR0VGBj40LG4uLjo22+/TTXZZYcOHUy/G41G1apVS1FRUVq0aFG2Eu2IiAhJab8ASE5OVnJysum1tbW16QverM777NmziomJ0ZgxY0xP8uvXr5+NMwYAALAcsxPtnTt3ytraWitXrpSdnV2qst69e6t37946fPiwxowZo549e6pbt2763//+R6INAGYy56n2li1bNH36dJ06dUq3b982bT937pxFY2nWrFmaFSWio6M1depUbdy4UVevXlVSUpIkpbkmmOvfvaRee+01rVu3zvR63rx5qlu3rqSsz7tMmTJydnbW+++/r759+6pu3boqUqTIQ8UFAACQU2Yv7/Xrr7/qqaeeSveGysHBQV26dNGKFStSvT5x4oTlIgWAJ8CwYcNMM5D/2+HDhzV06FAVKVJEkydP1qJFi7Rs2TLZ2toqLi7OonGkl6SOGzdOq1atUv/+/TVr1iwtW7ZMffr0MXUtN1fKPB5Xr15NtX3s2LFatmyZ/vvf/6babs55u7m56YcffpCzs7PefPNNNWzYUL169dKxY8eyFRsAAIAlmP1E+86dO4qJicmw/NatW6nGwrm7u+coMAB4Ev3zqXabNm1Slf35559ydnbW119/LWtra0nSzZs3lZCQYFbbdnZ2aepGR0enW/ffT5vj4uK0ZcsWvfHGG+rfv79p+y+//GLWsf+pdu3aMhgM2rZtW6ru3aVLl1bp0qXT1Df3vKtXr67//e9/iouL0969e/XZZ59p8ODB2rp1a5qn8wAAALnJ7DuPwMBAzZs3L911TQ8fPqz58+enGg/4119/PdQEPADwpEt5qr19+/ZU22NjY2VjY5MqaVy1alWa/TN6wu3t7a1Tp06l2vbvY2QkPj5eSUlJqXo1xcXFaf369Wbt/08lS5ZUmzZttHDhQrN6Ppl73ins7e3VuHFj9enTR9evX8/0S2IAAIDcYPYT7bffflt9+vRRjx49VK1aNZUtW1aSdP78eR05ckSurq56++23JT24+QoJCUnzNAYAkLWUp9o7d+5Mtb1hw4aaO3eu/vOf/6ht27Y6cuSIlixZIltb21T1ypcvrxUrVmjDhg0qVqyYihUrJi8vL7Vv317vvvuuvv76a9WqVUs7duwwO9F2cXFRtWrVNGPGDLm7u8vOzk4//PDDQ4/Pfv/999W/f389//zz6t27t2rVqqVChQopIiJCq1atksFgUKFChcw+782bN2vp0qVq3bq1vL29FRUVpR9++EH+/v70sAIAAI+c2Yl2pUqV9Ntvv+n777/Xtm3btHbtWkkyrVP64osvysvLS9KDpwkrV67MnYgB4AkwfPhwvfTSS6m2NW3aVGPHjtX8+fO1YsUKVa9eXdOnT9dzzz2Xqt5LL72kCxcuaNy4cYqJiTGto/3MM8/o4sWLWrJkiebMmaPWrVvrnXfe0SuvvGJWTJ999pkmTJigt99+Wy4uLurZs6fs7Oz06aefZvv8PDw8tHjxYs2fP19r1qzRvHnzlJiYKG9vb9WtW1c///yz/P39zT7vMmXKyNraWl999ZWuX78ud3d3NWjQQGPGjMl2bAAAADllMBqNxqwqJSQk6ODBgypatKh8fHweQVjmiYuLU1hYmAICAmRvb5/X4SAHQkJCVLNmzbwOAzlkqc9kTtpJToyTlc2j/3uQV8dFPvGZIes6AADzjMkyPQHyXFb3q2aN0ba2ttbAgQO1Y8cOiwcIAJaUV8kuSTYAAABSmJVoW1lZqWTJkrp7925uxwMAAAAAQIFm9qzj/fv31+LFixUZGZmb8QAAAAAAUKCZPRna3bt35ejoqNatW6t169YqXbp0mr7oBoNBL774osWDBAAAAACgoDA70f7ss89Mv//666/p1iHRBgAAAAA86cxOtDds2GDRA69fv14//PCDzpw5o3v37snLy0utW7fW0KFD5eLiYtFjAQAAAADwqJidaJcsWdKiB46Ojlbt2rU1cOBAubm56cSJE5o2bZr++usvzZ4926LHAgAAAADgUTE70U5x+fJl7d27V1FRUWrfvr28vb2VmJio6Ohoubm5ycbGvCafffbZVK/r1q0re3t7vfvuu7p27Zq8vLyyGxoAAAAAAHkuW4n2pEmTtGDBAiUlJclgMKhKlSry9vZWbGysWrdurZEjR2rAgAEPHYy7u7skKTEx8aHbAAAAAAAgL5m9vNfMmTM1d+5cDRgwQD/88IOMRqOpzNnZWa1bt9Yff/yR7QCSkpIUFxensLAwffPNN2revLnFu6kDAAAAAPComJ1oL126VE899ZTGjh0rPz+/NOWVK1fWuXPnsh1A3bp1Vb16dT3zzDMqWrSoPv/882y3AQAF1dSpU+Xr62v6qVevnvr166f9+/eb3UZ4eLimTp2q+/fvWzS2Fi1a6IMPPrBomwAAAE8Cs7uOX758WYMGDcqw3NnZWTExMdkOYP78+bp//75Onjyp6dOn6+WXX9YPP/wga2trs9sICwvL9nGR/4SEhOR1CMhnHuaz7e/vLwcHh1yIJnOxsbE6evRotve7fPmy7Ozs9Pbbb0uSbt68qRUrVqhfv3766KOPVKZMmSzb2LJli77//nsFBATI1dU12zFkJC4uThEREXw2s1CzZs28DgEAHjtce1DQmZ1ou7u7KyIiIsPyEydOPNQEZlWqVJEkBQcHy9/fX88884z++OMPtWvXzuw2AgICZG9vn+1jI/8ICQnhZvUxkDIMxFIe9rO9bNkyi8Vgru7duz/U/+GdO3fKxsZGPXv2NG3r0qWLWrRooSNHjqhbt25ZtnH+/HlJUo0aNeTh4ZFp3djYWLO/iLC3t1exYsX4bAIAHjmuPcjvsrrvNbvreLNmzbRkyRJFRUWlKTt27JiWLVumVq1aPVyU/1+VKlVkZWWlCxcu5KgdACjISpQoIQ8PD126dEmS9Ouvv6pLly6qVq2aGjZsqEmTJik+Pl6StHz5co0fP16SVL9+ffn6+qpFixamMl9fXx06dEgvvviigoKCTF3BT5w4YdoWHBysl19+2azhP4cPH9YLL7xg2m/EiBG6evWqqXzPnj3y9fXVkSNHUu03btw4derUyfQ6JbajR4/qpZdeUmBgoFq1aqUNGzbIaDTq+++/V+PGjVW3bl29//77pvMFAAAoCMxOtEeOHClra2s99dRT+uyzz2QwGPTzzz9r1KhReu6551S8eHG98sorOQomNDRUycnJKlWqVI7aAYCC7M6dO7p165aKFSumefPmafz48apXr56mT5+u4cOHa8WKFZo4caKkB1+CpvztnTlzphYvXqxp06alam/UqFEKDg7Wt99+q+7du+vKlSvq3bu3rl+/rkmTJmnixIk6f/68evfune6XqSkOHz6s3r17y87OTlOmTNGkSZN07tw5DRo0SElJSQ91rq+//roaNmyoadOmqWzZsnrttdc0efJkHT16VB999JFefvllLVmyRD/++ONDtQ8AAJAXzO46XrRoUf3888/64osvtH79ehmNRv32229ydnZWly5dNGbMGLm5uZl94EGDBqlevXqqVKmS7OzsdOzYMc2aNUu+vr45fjIOAAVNyrKG165d03//+18lJSWpWbNmeuONNzRw4ECNHTvWVNfV1VVjx47V4MGDVapUKdM4bn9//3S7jj/33HN6+eWXTa8nTZqkhIQE/fDDD6b6NWrUUNu2bfXjjz9qxIgR6cb46aefqkqVKpo+fboMBoOkB93727Ztq99++01dunTJ9nn36dNHvXv3liT5+PioZcuW2rFjh1auXCkrKys1adJEu3fv1tq1azVw4MBstw8AAJAXsrWOtoeHhz788EN9+OGHioqKUnJysjw8PGRlZfaDcZPq1atr5cqVpq6RpUqVUq9evTRw4EDZ2dlluz0AKKju3bsnf39/02tXV1e99957cnBw0N27d9WhQwdTIi496CKelJSkY8eOmdUDKKUreYr9+/erXr16qZLykiVLKigoKMPZzmNjYxUSEqI33ngj1dNrLy8vlStXTkeOHHmoRLthw4am30uVKiVbW1vVr18/1XXFx8dHa9asyXbbAAAAeSVbifY/ZTXhTlZeffVVvfrqqzlqAwAeBw4ODlqwYIEMBoMKFy4sb29vWVlZaeXKlZKkp59+Ot39Ll++bFb7np6eqV7HxMSYJqL8d72zZ8+m20Z0dLSSkpI0adIkTZo0KU156dKlzYrl3/49S7qtrW262+Li4h6qfQAAgLyQrUQ7JiZGv/32my5evKjo6GgZjcZU5QaDQR9//LFFAwSAx52VlZWqVauWZnvKcJypU6fK29s7TXl628zh5uamGzdupNl+48aNDIcAubi4yGAwaMiQIekO70lJjlNmiU9ISEhVfuvWrYeKFQAAoCAyO9HetWuXhg8frrt378rZ2TndtVpTxuwBAHIuODhYjo6OunLlitq0aZNhPVtbW0kye2bumjVravHixbp586YKFy4sSbpy5YoOHDigIUOGpLuPo6OjgoKCdOrUKY0aNSrDtlOS/9OnTys4OFjSg8ndDh48mObJOgAAwOPK7ER70qRJcnd3148//ig/P7/cjAkAoAdPkV999VVNmTJFV69eVb169WRra6tLly5p06ZNmjBhgooXL64KFSpIkubPn682bdrIwcFBvr6+GbY7YMAALV++XIMGDdLLL7+spKQkTZ06VW5ubqaJydLz5ptvql+/fho5cqQ6deokNzc3RUREaM+ePWrWrJlatWolLy8vBQUFaerUqXJ2dpatra1mz55t9trdAAAAjwOzE+2zZ89q7NixJNkA8AgNGDBAxYsX1w8//KCffvpJ1tbWKlmypJo0aWLqWVS1alWNGDFCS5cu1ezZs+Xt7a2NGzdm2Ka3t7cWLFigTz75RG+++aYkqU6dOvrmm28ynX8jMDBQCxcu1NSpU/X2228rNjZWXl5eqlOnjipWrGiqN2XKFL333nt66623VLhwYb3yyisKCQlRWFiYhd4VAACA/M1g/PdA6wy0b99e3bp10+DBg3M7JrPFxcUpLCxMAQEBpnGBKJhCQkJUs2bNvA4DOWSpz2RO2klKSpK1tfVDH/th5dVxkU98xtApALCYMWalJ0Ceyup+1ex1uYYMGaLFixczoQ2AfC2vkl2SbAAAAKQwu+v49evX5e7urrZt26pdu3YqUaJEmvWzDQaDXnzxRYsHCQAAAABAQWF2ov3ZZ5+Zfl+8eHG6dUi0AQAAAABPOrMT7Q0bNuRmHAAAAAAAPBbMTrRLliyZm3EAAAAAAPBYMDvRTnH58mXt3btXUVFRat++vby9vZWYmKjo6Gi5ubnJxibbTQIAAAAA8NjIVlY8adIkLViwQElJSTIYDKpSpYq8vb0VGxur1q1ba+TIkRowYEAuhQoAAAAAQP5n9vJeM2fO1Ny5czVgwAD98MMP+ufy287OzmrdurX++OOPXAkSAAAAAICCwuxEe+nSpXrqqac0duxY+fn5pSmvXLmyzp07Z8nYAAAAAAAocMxOtC9fvqxatWplWO7s7KyYmBiLBAUAAAAAQEFldqLt7u6uiIiIDMtPnDghLy8viwQFAE+ibdu26aWXXlLdunUVEBCgpk2b6q233tLp06ctfixfX1/NmjXL4u0CAAAgG4l2s2bNtGTJEkVFRaUpO3bsmJYtW6ZWrVpZNDgAyK6EhIQCedypU6fqxRdflK2trd5//3398MMPGj16tCIiItSzZ08LRQkAAIBHwexZx0eOHKnt27frqaeeUrNmzWQwGPTzzz9ryZIl+uOPP1SyZEm98soruRkrAGTJ1tZWQ4cOfeTH/fbbbx963+3bt2vatGkaMmSIRo8enaqsS5cu2rBhQ07DAwAAwCNk9hPtokWL6ueff1bz5s31xx9/yGg06rffftO2bdvUpUsXLVy4UG5ubrkZKwA8lmbNmqUiRYpoxIgR6Za3bNlSkpScnKzvvvtOLVu2VEBAgFq3bq05c+akqnvmzBmNHj1azZo1U40aNdS+fXt9//33SkxMzO3TAAAAwP+XrXW0PTw89OGHH+rDDz9UVFSUkpOT5eHhISsrs/N1AMA/JCYmKiQkRK1bt5atrW2mdT/55BPNnTtXgwcPVu3atbVjxw5NmjRJd+/e1bBhwyRJ169fV9myZdWxY0c5OzvrxIkTmjp1qqKjo/XGG288ilMCAAB44mUr0f4nDw8PS8YBAE+kW7duKS4uTiVKlMi0XlRUlBYsWKCBAwdq1KhRkqRGjRrp7t27mjlzpgYMGCAnJyfVrVtXdevWlSQZjUbVrFlTycnJmjp1qsaOHSuDwZDr5wQAAPCke+hEGwCQc0ajUZKyTIAPHz6shIQEdejQIdX2jh07avHixQoPD1etWrUUFxenGTNmaNWqVbp8+XKqSdpu3LihokWLWv4kAAAAkAqJNgDkocKFC8ve3l6XL1/OtF50dLQkpUmUPT09JT14Mi5Jn376qZYsWaKhQ4eqWrVqcnFx0c6dO/XFF18oLi7O8icAAACANEi0ASAP2djYqFatWtq1a5cSEhIyHKft7u4u6cFTaS8vL9P2GzdupCpfu3atevTooZdfftlUZ//+/bkTPAAAANLFLGYAkMdeeOEF3bhxQ99880265Zs2bVK1atVka2urNWvWpCpbvXq1HB0dVbVqVUlSXFyc7OzsTOUpK0QAAADg0TH7iXZycjKziwNALmjUqJGGDx+uadOm6dSpU+rUqZM8PT115coV/f777woNDdXevXvVt29fzZ49W3Z2dgoODtauXbu0ePFijRgxQo6OjpKkBg0aaPHixSpfvrw8PT21ZMkSU7dzAAAAPBpmJ9pNmjRR586d9dRTT6lKlSq5GRMAPHFGjBihGjVqaN68eZowYYLu3LkjT09P1a1b17RW9tixY+Xq6qqlS5dqxowZKl68uN58800NHDjQ1M57772nCRMm6OOPP5adnZ06d+6stm3bauzYsXl0ZgAAAE8egzFlytssjBw5Ulu2bFF8fLwqVqyoLl26qHPnzqnGCj5qcXFxCgsLU0BAgOzt7fMsDuRcSEiIatasmddhIIcs9ZnMSTuZjXPOTXl1XOQTn7FsGgBYzBiz0hMgT2V1v2p2X/Cvv/5aO3bs0AcffCB3d3d99tlnat68uQYMGKBffvlF9+7ds2jgAPAw8irZJckGAABAimwNunZ2dtazzz6r+fPna9OmTXrttdcUGRmp8ePHq2HDhho7dqy2b98uMx+SAwAAAADw2Hno2c2KFy+uwYMH63//+5/atWun+/fva9WqVXrppZfUtGlTzZo1S4mJiZaMFQAAAACAfO+h1tG+c+eO1q1bp5UrV2rfvn2ytrZWmzZt1K1bN9na2mrJkiWaMmWKTp06pUmTJlk6ZgAAAAAA8i2zE+2kpCRt3bpVK1eu1KZNmxQbG6vq1avrnXfeUceOHeXm5maq26hRI3311VeaO3cuiTYAAAAA4IlidqLdsGFDRUdHy8vLS/369VPXrl1Vvnz5DOtXrFiRCdIAAAAAAE8csxPtRo0a6emnn1b9+vVlMGS9jEnHjh3VsWPHHAUHAAAAAEBBY9ZkaHFxcfLx8VFycrJZSTYAAAAAAE8qsxJte3t7zZgxQ1euXMnteAAAAAAAKNDMXt6rSpUqOn/+fG7GAgAAAABAgWd2oj169GgtXbpUmzdvzsVwAAAAAAAo2MyeDG3mzJlyc3PTK6+8ouLFi6tUqVJycHBIVcdgMGjGjBkWDxIAAAAAgILC7ET79OnTkiRvb29J0t9//52mDhOlAQAAAACedGYn2hs3bszNOAAAAAAAeCyYPUYbAAAAAABkzewn2v90584d3blzR8nJyWnKSpQokeOgAAAAAAAoqLKVaC9dulQzZ87UhQsXMqwTHh6e46AAAAAAACiozO46vmzZMr377rsqWbKkXnvtNRmNRvXv31+DBw9WkSJFVKVKFX300Ue5GSsAAAAAAPme2Yn23LlzVbduXc2ePVvPPfecJKlp06YaNWqUfv/9d0VHR+v27du5FigAAAAAAAWB2Yn2+fPn1bp16wc7WT3YLSEhQZLk5uamZ599Vj/99JPZB16zZo2GDh2qJk2aKDAwUE899ZSWLl0qo9GYnfgBAAAAAMhXzB6j7ejoaEqCnZycZG1trevXr5vK3d3ddfXqVbMPPGfOHJUsWVLjxo1T4cKFtXPnTr333nu6cuWKRo4cmY1TAAAAAAAg/zA70S5XrpxOnDjxYCcbG/n5+emXX37RU089peTkZP36668qVaqU2QeePn26PDw8TK/r16+vW7duae7cuRo+fLjpqTkAAAAAAAWJ2dlsq1attGXLFsXFxUmSXnnlFe3fv1916tRRvXr1dODAAQ0ePNjsA/8zyU5RpUoV3blzx3QMAAAAAAAKGrOfaA8aNEiDBg0yvW7VqpUWLFigdevWydraWs2bN1edOnVyFExISIhKliypQoUK5agdAAAAAADySrbW0f63mjVrqmbNmhYJZP/+/Vq9erVef/11i7QHAAAAAEBeyFGibSlXr17VqFGjVLt2bQ0YMCDb+4eFhVk+KDxyISEheR0C8hk+2ygILPWFMwDg/3BfiIIuW4n2hg0btGzZMl28eFHR0dFpluIyGAzatm1btgKIiYnRSy+9JHd3d33zzTeytrbO1v6SFBAQIHt7+2zvh/wjJCSEm9XHQFxcnEWTYz7bAAA8mbgvRH6X1X2v2Yn2tGnT9M0338jV1VW+vr4qW7ZsjoOLjY3VkCFDdPv2bS1evFguLi45bhMAAAAAgLxkdqL9448/qn79+vruu+9kZ2eX4wMnJibqtdde05kzZ/Tjjz/Ky8srx20CAAAAAJDXzE60ExMT1aZNG4sk2ZL0n//8R5s2bdK4ceN0584dHTx40FRWsWJFOTs7W+Q4AAAAAAA8SmYn2g0bNrTo2MsdO3ZIkiZPnpymbN68eapbt67FjgUAAAAAwKNidqL93nvv6YUXXtC0adP09NNPy9vbWwaD4aEPvHHjxofeFwAAAACA/MrsRNvDw0MdOnTQF198oW+++SbdOgaDQceOHbNYcAAAAAAAFDRmJ9pTpkzRrFmzVKpUKVWvXp0x1AAAAAAApMPsRHvp0qVq2bKlpk2blpvxAAAAAABQoFmZW9FoNKpRo0a5GQsAAAAAAAWe2Yl2ixYttHfv3tyMBQAAAACAAs/sRHvIkCE6e/as3n33XR06dEgRERGKjIxM8wMAAAAAwJPM7DHa7du3lySFh4dr2bJlGdYLDw/PeVQAAAAAABRQZifaw4YNy9G62QAAAAAAPAnMTrRHjBiRm3EAAAAAAPBYMHuMNgAAAAAAyFqGT7R/+eUXSVKXLl1kMBhMr7PStWtXC4QFAAAAAEDBlGGiPW7cOBkMBnXo0EF2dnYaN25clo0ZDAYSbQAAAADAEy3DRHvDhg2SJDs7u1SvAQAAAABAxjJMtEuWLGn6PTk5WQaDQY6OjnJ3d38UcQEAAAAAUCCZNRlaUlKSWrdurRUrVuR2PAAAAAAAFGhmJdq2trYqVqwY62gDAAAAAJAFs5f36t69u5YvX664uLjcjAcAAAAAgAItwzHa/1amTBkZjUa1b99eXbt2VenSpWVvb5+mXocOHSwaIAAAAAAABYnZifbYsWNNv3/77bfp1klZDgwAAAAAgCeV2Yn2vHnzcjMOAAAAAAAeC2Yn2nXq1MnNOAAAAAAAeCyYnWj/0/Hjx3X58mVJUokSJeTr68uM5AAAAAAAKJuJ9u+//64pU6bo6tWrkiSj0SiDwSAvLy+NGTNGnTt3zpUgAQAAAAAoKMxOtJcvX6633npL5cqV09ixY+Xj4yOj0ahz585p6dKleuONN5SQkKCnn346N+MFAAAAACBfMzvR/v7771W9enXNnz8/zbJeffr0Ue/evfX999+TaAMAAAAAnmhW5la8cuWKOnfunO7a2fb29urSpYupSzkAAAAAAE8qsxPtihUr6tq1axmWX716VRUqVLBIUAAAAAAAFFRmJ9pvvPGGli5dqtWrV6cp+/3337Vs2TK9+eabFg0OAAAAAICCxuwx2rNmzZK7u7vGjBmjjz/+WKVLl5bBYNCFCxcUGRmpsmXLaubMmZo5c6ZpH4PBoBkzZuRK4AAAAAAA5EdmJ9qnT5+WJHl7e0uSqRu5nZ2dvL29FR8fb6qTgrW1AQAAAABPGrMT7Y0bN+ZmHAAAAAAAPBbMHqMNAAAAAACyRqINAAAAAIAFkWgDAAAAAGBBJNoAAAAAAFgQiTYAAAAAABZEog0AAAAAgAWZvbxXiujoaMXGxsrBwUFubm65ERMAAAAAAAVWlol2fHy8Fi1apNWrV+v48eOKi4szldnb28vPz0/t27dXz549ZW9vn6vBAgAAAACQ32WaaEdFRal///46efKkKlWqpE6dOqlYsWKyt7dXXFycIiIidOjQIU2aNEnLli3TnDlzVKRIkUcVOwAAAAAA+U6mifZ///tfRUREaN68eapTp06G9fbs2aORI0fqk08+0X//+1+LBwkAAAAAQEGR6WRomzdv1gsvvJBpki1JdevW1cCBA7V582ZLxgYAAAAAQIGTaaIdHx8vFxcXsxpycXFRfHy8RYICAAAAAKCgyjTRrlatmhYuXKjbt29n2sjt27e1aNEiVa9e3aLBAQAAAABQ0GQ6Rnvs2LHq16+f2rVrp86dO6tatWoqWrSo7OzsFB8fr+vXr+vw4cP67bffdO/ePX388cePKm4AAAAAAPKlTBPtatWqaenSpfrss8+0YMECJSYmymAwmMqNRqNsbGzUqFEjjRkzRpUqVcr1gAEAAAAAyM+yXEe7YsWKmj59uu7evasTJ04oIiJCsbGxcnBwUNGiRVW5cmU5Ozs/1MHPnz+vWbNm6dChQzp58qTKly+v33777aHaAgAAAAAgP8gy0U7h5OSkoKAgix785MmT2rJli2rUqKHk5GQZjUaLtg8AAAAAwKOW6WRoua1FixbasmWLvv76a/n7++dlKAAAAAAAWESmT7STk5NlZZU6F4+OjtacOXO0a9cu3bp1Sx4eHmrSpIn69u0rJyenbB38320DAAAAAFDQZZrp+vv7a9WqVabX165dU7du3TR9+nRFRETI09NTly9f1pdffqmePXvqzp07uR4wAAAAAAD5WaaJ9r/HTE+ePFkRERH64osvtHHjRi1YsECbN2/WxIkTderUKX377be5GiwAAAAAAPmd2ZOhGY1Gbdq0SX369FH79u1TlXXv3l179uzRhg0b9MYbb1g8yKyEhYU98mPC8kJCQvI6BOQzfLZRENSsWTOvQwCAxw73hSjozE607969q9jY2AxvKIKDg7V27VqLBZYdAQEBsre3z5NjwzJCQkK4WX0MxMXFWTQ55rMNAMCTiftC5HdZ3fdmmWjfuXNHkZGRSk5OlqOjo+Li4tKtFxsbyw0xAAAAAOCJl+W03x988IEaNWqkJk2a6N69ezp48GC69U6dOiVvb29LxwcAAAAAQIGS6RPt4cOHp9nm6uqaZlt0dLT++OMPtWvXLlsHv3//vrZs2SJJ+vvvv3Xnzh1T9/Nq1aqpZMmS2WoPAAAAAIC8lu1EOz1ubm7au3dvtg8eGRmpV199NdW2lNeTJk3S008/ne02AQAAAADIS2ZPhpYbSpUqpb/++isvQwAAAAAAwKLMSrQTEhK0d+9eHT16VBEREYqLi5O9vb2KFSsmf39/1alTR7a2trkdKwAAAAAA+V6Wifavv/6qTz/9VJGRkTIajQ92srFRYmKiJMlgMMjDw0Njx45V165dczVYAAAAAADyu0wT7d9++01vvvmm6tSpo/fee081atRQsWLFZDAYZDQaFRERoYMHD2rBggUaP368bGxs1KlTp0cVOwAAAAAA+U6my3vNmDFDzZo107x589SmTRt5eXnJYDBIevAk28vLS23bttX8+fPVpEkTzZgx45EEDQAAAABAfpVpon3u3Dm1bNnSrIZatWqlc+fOWSImAAAAAAAKrEy7jhcpUkQnT540q6ETJ06oSJEiFgkKAICCwph4X4YxxrwOAwAeG8bE+zLYFMrrMIAcyTTR7tq1q2bMmCEPDw/16tVLrq6uaerExMTop59+0k8//aQhQ4bkWqAAAORHBptCCv24WV6HAQCPjeC3Nud1CECOZZpoDxs2TFevXtWXX36pqVOnqnTp0ipatKjs7OwUHx+v69ev6+LFi0pKSlKXLl00dOjQRxU3AAAAAAD5UqaJto2NjSZNmqQ+ffpozZo1Cg8PV0REhGJjY+Xg4KASJUqodevWateunfz9/R9VzAAAAAAA5FtZrqMtSf7+/iTSAAAAAACYIdNZxwEAAAAAQPaYlWjHxMTo8OHDunjxYoZ1oqKitG/fPosFBgAAAABAQZRlov3FF1+oQYMG6tGjh9q0aaPu3bsrPDw8Tb3t27erX79+uRIkAAAAAAAFRaaJ9urVq/X999+rfv36+uCDDzRs2DBduXJFzz33nH777bdHFSMAAAAAAAVGppOhzZs3T/Xr19f//vc/07Z+/frp9ddf1xtvvKGbN2+qb9++uR4kAAAAAAAFRaZPtM+cOaPWrVun2ubq6qrvv/9e3bt318cff6ypU6fmaoAAAAAAABQkmT7RNhgMMhqN6W7/4IMP5OLiom+++Ua3bt1StWrVci1IAAAAAAAKikwT7XLlyunAgQPq3bt3uuVjx46Vk5OTvv76a5UoUSJXAgQAAAAAoCDJtOt448aNtWHDBt28eTPDOkOHDtXbb7+tK1euWDw4AAAAAAAKmkyfaHfv3l3u7u6KiopS4cKFM6zXt29feXt76/jx4xYPEAAAAACAgiTTRNvLyyvDbuP/1qpVK7Vq1coiQQEAAAAAUFBl2nUcAAAAAABkD4k2AAAAAAAWRKINAAAAAIAFkWgDAAAAAGBBJNoAAAAAAFgQiTYAAAAAABaU6fJe/5aUlKTt27fr0qVLunXrloxGY6pyg8GgYcOGWTRAAAAAAAAKErMT7fDwcA0bNkxXrlxJk2CnINEGAAAAADzpzE60//Of/+ju3buaOnWq6tSpI1dX19yMCwAAAACAAsnsRPvYsWMaMWKEWrVqlZvxAAAAAABQoJk9GZqnp6dsbW1zMxYAAAAAAAo8sxPtvn376pdfflFCQkJuxgMAAAAAQIFmdtdxLy8vWVtbq1OnTnrmmWdUokQJWVmlzdM7dOhg0QABAAAAAChIzE60R48ebfr9888/T7eOwWAg0QYAAAAAPNHMTrTnzZuXm3EAAAAAAPBYMDvRrlOnTm7GAQAAAADAY8HsydAAAAAAAEDWMnyiPX78eBkMBn344YeytrbW+PHjs2zMYDDo448/tmiAAAAAAAAUJBkm2nv27JHBYFBycrKsra21Z8+eLBszGAwWDQ4AAAAAgIImw0R748aNmb4GAAAAAABpMUYbAAAAAAALItEGAAAAAMCCSLQBAAAAALAgEm0AAAAAACyIRBsAAAAAAAvK00T73LlzGjRokIKCglSvXj19+OGHun//fl6GBAAAAABAjmS4vFdmrly5osjISJUrV05OTk4PdeCYmBj169dPJUqU0FdffaWoqChNmjRJUVFR+uKLLx6qTQAAAAAA8lq2nmj/+eefatOmjVq0aKFnn31Whw8fliRFRUWpc+fO+uOPP8xua9GiRYqJidG3336rJk2aqGvXrnrnnXe0evVqnTx5MntnAQAAAABAPmF2or1582aNGDFCHh4eGjZsmIxGo6nMw8ND3t7eWr58udkH3rp1q+rVqycPDw/TtrZt28rOzk5bt241ux0AAAAAAPITsxPtb775RsHBwVq0aJF69+6dpjwwMFDHjx83+8CnT59WxYoVU22zs7NTmTJldObMGbPbAQAAAAAgPzE70T5x4oQ6dOiQYXnRokUVGRlp9oFjYmLk6uqaZrurq6uio6PNbgcAAAAAgPzE7MnQ7OzsFB8fn2H55cuX5eLikuOAjEajDAZDtvYJCwvL8XHzs+Dg4Gy/JwVNzZo18zqER8JoNCo0NDSvwygwHvfPNh4PgdUDFPzW5rwOAwAeG0kJcTp4mHsAFGxmJ9rBwcFavXq1Bg4cmKbszp07+vnnn1W3bl2zD+zq6qqYmJg022/fvq0KFSqY3Y4kBQQEyN7ePlv7IH8JCQl5IpJtg8HwWJ9nXFycRZNjPtsoKJYtW5bXIQDAY6N79+6P9f0SHg9Z3fea3XV8+PDh+uuvvzRw4EBt2rRJknTs2DEtXLhQ3bp10+3btzVs2DCzA6tQoYJOnz6dalt8fLwuXLig8uXLm90OAAAAAAD5idmJdrVq1TRz5kxduXJFb731liTp008/1X/+8x9ZWVlp5syZ2XoS3aRJE+3evVs3b940bfvjjz8UHx+vpk2bZuMUAAAAAADIP8zuOi5JderU0dq1a3X8+HGdPXtWRqNRpUuXVkBAQLbHEPfs2VMLFizQ0KFDNXToUEVGRmry5Mnq0KFDmtnIAQAAAAAoKLKVaKfw8/OTn59fjg7s6uqquXPnauLEiRoxYoTs7e3VsWNHjR07NkftAgAAAACQl8xOtJcuXaqtW7dq6tSp6ZaPHDlSzZs3V7du3cw+eLly5TRr1iyz6wMAAAAAkN+ZPUZ74cKF8vT0zLC8WLFi+vHHHy0SFAAAAAAABZXZifa5c+fk6+ubYXnFihV17tw5S8QEAAAAAECBZXaibTAYUs0Q/m+3bt1SUlKSRYICAAAAAKCgMjvR9vf316pVqxQXF5emLDY2VqtWrZK/v79FgwMAAAAAoKAxO9EeMmSIzp49q+eff17r1q3TmTNndPbsWa1bt069evXS2bNnNXjw4NyMFQAAAACAfM/sWccbNmyoSZMmaeLEiXrttddM241Go5ydnfXRRx+pSZMmuREjAAAAAAAFRrbW0e7atatatWqlHTt26MKFCzIajSpbtqwaNmwoZ2fn3IoRAAAAAIACI1uJtiQ5Ozurbdu2uRELAAAAAAAFXrYT7Tt37ujKlSuKjo6W0WhMU167dm2LBAYAAAAAQEFkdqIdHR2tDz/8UGvXrjUt42U0GmUwGFL9Hh4enjuRAgAAAABQAJidaL/33nv6888/1bt3b9WpU0eurq65GRcAAAAAAAWS2Yn21q1b1bdvX40bNy434wEAAAAAoEAzex1tOzs7lS1bNjdjAQAAAACgwDM70W7btq22bt2am7EAAAAAAFDgmZ1oDxo0SBEREXrzzTd18OBBRUREKDIyMs0PAAAAAABPMrPHaLdt21YGg0FHjx7VypUrM6zHrOMAAAAAgCeZ2Yn2sGHDTEt5AQAAAACA9JmdaI8YMSI34wAAAAAA4LFg9hjtf0pKStLNmzeVmJho6XgAAAAAACjQspVoHz58WAMHDlRgYKAaNGigffv2SZKioqI0ePBg7dq1K1eCBAAAAACgoDA70T5w4ID69OmjCxcuqGvXrjIajaYyDw8P3bt3T8uWLcuVIAEAAAAAKCjMTrS/+OIL+fj4aPXq1Ro1alSa8rp16+rQoUMWDQ4AAAAAgILG7ET7yJEjeuaZZ2Rvb5/u7OPFixfX9evXLRocAAAAAAAFjdmJtsFgkJVVxtWvX78uBwcHiwQFAAAAAEBBZXaiHRAQoE2bNqVbFh8fr1WrVikoKMhigQEAAAAAUBCZnWgPGTJEu3fv1ltvvaXjx49LkiIiIrR161b1799fFy9e1Msvv5xrgQIAAAAAUBDYmFuxYcOG+uSTT/Thhx9qxYoVkqRx48bJaDTK1dVVU6ZMUWBgYG7FCQAAAABAgWB2oi1JnTp1UsuWLbVjxw6dO3dOycnJKlOmjBo3biwnJ6fcihEAAAAAgALDrEQ7NjZWnTp1Ur9+/dSvXz+1atUqt+MCAKBASEpKUvfu3fM6DAB4bCQlJcna2jqvwwByxKwx2g4ODrp9+7ZsbW1zOx4AAAoUbgZRUISEhOR1CIBZ+LuKx4HZk6E1a9ZMW7Zsyc1YAAAAAAAo8MxOtAcPHqy///5br776qnbt2qW///5bkZGRaX4AAAAAAHiSmT0ZWseOHSVJJ0+e1Pr16zOsFx4envOoAAAAAAAooMxOtIcNGyaDwZCbsQAAAAAAUOCZnWiPGDEiN+MAAAAAAOCxYPYY7X9KSkrSzZs3lZiYaOl4AAAAAAAo0LKVaB8+fFgDBw5UYGCgGjRooH379kmSoqKiNHjwYO3atStXggQAAAAAoKAwO9E+cOCA+vTpowsXLqhr164yGo2mMg8PD927d0/Lli3LlSABAAAAACgozE60v/jiC/n4+Gj16tUaNWpUmvK6devq0KFDFg0OAAAAAICCxuxE+8iRI3rmmWdkb2+f7uzjxYsX1/Xr1y0aHAAAAAAABY3ZibbBYJCVVcbVr1+/LgcHB4sEBQAAAABAQWV2oh0QEKBNmzalWxYfH69Vq1YpKCjIYoEBAAAAAFAQmZ1oDxkyRLt379Zbb72l48ePS5IiIiK0detW9e/fXxcvXtTLL7+ca4ECAAAAAFAQ2JhbsWHDhvrkk0/04YcfasWKFZKkcePGyWg0ytXVVVOmTFFgYGBuxQkAAAAAQIFgdqItSZ06dVLLli21Y8cOnTt3TsnJySpTpowaN24sJyen3IoxQylLjMXHxz/yY8Py4uLi8joE5FDKZ/Gfy/89DD7bAJA7uNYCgGVkdd9rMGZQ0rJlS7311ltq2bKlJGnatGlq06aNKleunEuhZt/t27d14sSJvA4DwL9Urlz5/7V3t7FVl/f/wD+nlHJTKkOKPDBQE8zowAGbTBA252QzutDpkJmRZcqIqEHYEhOmRk32YFsgZDesKEEZY8QHLnhvlg0YDBDNuOmkc4MAKgwYWOWuLSjlxv4eGPv/I7ToPHyvnrPX69k5FzbvBzbv8+n3XNcVFRUV//V/73cbAIBC0N7n3nafaL/11lvR3Nzc9nrevHlRVVXVqQbt8vLy+OxnPxtdu3Y955VjQLZaW1vj5MmTn/obLn63AQDozM73ubfdQfvSSy+NtWvXxte//vXo1atXRESn+8BbUlLyqZ6aAfmXj2v+/G4DANDZdfS5t92vji9evDhmzZr1iYbrXC4XW7Zs+eQJAQAAoEi0+0R78uTJMWTIkNiwYUMcOHAgnnzyyRg9enRUVVVlmQ8AAAAKSrtPtD+quro65syZEzU1NRc6EwAAABSskvYWxo0bFytXrmx7PX369Bg8eHAmoQAAAKBQtTtof/TU8UceeSS2bduWSSgAAAAoVO0O2h+eOn706NGI+OD48s526jgAAAB0Nk4dBwAAgDzq8NTxoUOHxvr16+PAgQPxhz/8IUaNGuXUcQAAAOiAU8fJXF1dXVx55ZXtrj/99NNxyy23ZJgIAIqHngVI72MP2pAvQ4YMialTp8aMGTOitPT/fani0KFD8dBDD8Xq1attQQCA/5KeBUiv3cPQ4EJ58MEHY8mSJXHrrbfGG2+8ERERq1atipqamti6dWssWrQocUIAKFx6FiC9dp9oV1dXR0lJSWzevDnKysqiurr6vAejOQyNj2vnzp0xc+bMeP3112PUqFGxdu3a+Na3vhUPP/xw9OrVK3U8AChoehYgrXYH7dra2sjlcjFt2rQoKSlpe30+06dPz3tIitOmTZtiypQpceLEiRgyZEgsWbJE+QNAnuhZgHTs0SZzp0+fjtra2li4cGGMGTMmxo8fH7Nnz47u3bvH7NmzY+TIkakjAkDB0rMA6Rm0ydyECRNi586d8eMf/zgmTZoUER8c0PLggw/GmjVr4gc/+EHMnDkzcUoAKEx6FiC9jzVonzhxIp5//vl4+eWXY/fu3XHs2LEoLy+Pqqqq+PKXvxw1NTVRVlaWRV6KwHe+852YM2dOXHbZZWetLV26NGbNmhV1dXXZBwOAIqBnAdI776C9bdu2mDZtWuzbty9aW1ujoqIievbsGe+++240NzdHLpeLAQMGxPz582PQoEFZ5aaAnT59Orp06dLu+p49e2LAgAEZJgKA4qFnAdLrcNA+duxY1NTUxKFDh2LatGlx0003Rf/+/dvWGxoa4rnnnov58+dHv3794vnnn4+ePXtmEhwAAAA6o9KOFp955pnYv39/LF68OEaNGnXWev/+/eOuu+6KYcOGxZQpU+LZZ5+N733vexcsLMVj27Zt8dRTT8WuXbuipaXlrPUlS5YkSAUAxUHPAqRV0tHi6tWrY+zYseccsv9/V199dYwZMyZWrVqV13AUp7q6urjllluirq4u1q1bFydOnIjDhw/Hxo0bY+/evb4VAQCfgp4FSK/DQXv79u1x1VVXfawfNHr06Ni+fXteQlHcfvnLX8bNN98cS5cujdbW1nj44YfjxRdfjGeffTYiIiZOnJg4IQAULj0LkF6Hg3ZjY2P069fvY/2gysrKaGxszEsoituOHTvihhtuiJKSD/73O378eEREVFdXxw9/+MOYO3duyngAUND0LEB6HQ7aJ06ciNLSDrdxt+nSpUucPHkyL6EobrlcLkpLSyOXy0VlZWX85z//aVurrKyMPXv2JEwHAIVNzwKkd94pes+ePfGPf/zjvD9o9+7deQlE8bv88stj9+7dMXr06BgxYkT87ne/i8GDB0fXrl1jwYIFMXDgwNQRAaBg6VmA9Dq83qu6ujpyudzH+kGtra2Ry+Vi69ateQtHcXrhhRdi3759cffdd8cbb7wRU6ZMibfffjsiInr06BG1tbUxduzYxCkBoDDpWYD0Ohy0Pzw045P49re//akC8b/n2LFjsXnz5jh+/HiMGDEi+vbtmzoSABQNPQuQvQ4HbbgQnnvuufjqV78affr0OWvtyJEjsXr16rj55puzDwYARUDPAqTX4WFocCE88MAD7R7Esnfv3njggQcyTgQAxUPPAqRn0CZzHX2JorGxMcrLyzNMAwDFRc8CpPfx7u6CT2nNmjXx0ksvtb1etGhRVFZWnvFvWlpa4pVXXonPfe5zWccDgIKmZwE6F4M2mdi1a1esWrUqIj6433PTpk1RVlZ2xr/p2rVrDB48OO69994UEQGgYOlZgM7FYWhk7rrrrotHH300qqurU0cBgKKjZwHSM2gDAABAHjkMDQAAAPLIoA0AAAB5ZNAGAACAPDJoAwAAQB4ZtAEAACCP3KNNEvv27Yu//OUv8dZbb8WJEyfOWn/ooYcSpAKA4qBnAdJyvReZW758edx7773R2toaF198cXTt2vWM9VwuFytXrkyUDgAKm54FSM+gTea++c1vxsCBA2PWrFnxmc98JnUcACgqehYgPXu0ydy+ffvitttuU/4AcAHoWYD0DNpk7oorroi9e/emjgEARUnPAqRn0CZzP/nJT+KJJ56INWvWxMmTJ1PHAYCiomcB0rNHm8x94QtfiFOnTsWpU6eipKQkunXrdsZ6LpeLurq6ROkAoLDpWYD0XO9F5qZMmRK5XC51DAAoSnoWID1PtAEAACCPPNEmmffeey+2bNkSjY2N0bt37xg6dGh07949dSwAKAp6FiAdgzZJzJ8/Px5//PF477334sMvVfTs2TPuvPPOuPvuuxOnA4DCpmcB0jJok7nFixfH3Llz49Zbb43x48dHZWVlHDhwIP74xz/Gb37zm+jRo0fcfvvtqWMCQEHSswDp2aNN5q6//vr4xje+ETNnzjxrbc6cObFixYpYvnx5gmQAUPj0LEB67tEmc/v374+xY8eec23MmDGxf//+jBMBQPHQswDpGbTJXP/+/WPTpk3nXPv73/8el1xyScaJAKB46FmA9OzRJnMTJ06M2traOHnyZNx4441RWVkZBw8ejD/96U+xaNGimDFjRuqIAFCw9CxAevZok7nW1taYPXt2PPHEE3H69Om297t06RLf//7347777kuYDgAKm54FSM+gTTKHDx+O+vr6aGpqit69e8ewYcOiT58+qWMBQFHQswDpGLQBAAAgj+zRJolDhw7F73//+6ivr4933nkn+vXrF8OHD4/bb789Lr744tTxAKCg6VmAtDzRJnObN2+OO+64I95///0YPXp09O3bNw4ePBh/+9vfIpfLxW9/+9sYMWJE6pgAUJD0LEB6Bm0yN2HChOjWrVs89thjUVFR0fZ+c3NzTJ06NU6ePBlPP/10woQAULj0LEB67tEmc6+//nrceeedZ5R/RERFRUVMnTo1duzYkSgZABQ+PQuQnkGbzFVVVUVTU9M515qbm2PgwIEZJwKA4qFnAdIzaJO5++67L2pra2PDhg1nvL9+/fqYN2+e+z0B4FPQswDp2aNNJmpqas54/fbbb0dTU1NUVFREnz594vDhw9Hc3BwXXXRRXHLJJfHiiy8mSgoAhUfPAnQurvciE0OHDo1cLpc6BgAUJT0L0Ll4og0AAAB5ZI82mWppaYkrrrgiVqxYkToKABQdPQvQORi0yVS3bt2iT58+UVZWljoKABQdPQvQORi0ydyECRPiySefTB0DAIqSngVIz2FoZK68vDz+9a9/xfjx4+Oaa66JysrKMw5wyeVyMXny5HQBAaCA6VmA9ByGRuaqq6s7XM/lcrF169aM0gBAcdGzAOkZtAEAACCP7NEGAACAPLJHm2QaGxvj3//+d7S0tJy19qUvfSlBIgAoHnoWIB2DNplraWmJ+++/P5YtWxbt7VywdwwA/jt6FiA9Xx0nc7/+9a+jvr4+amtro7W1NX7+85/H3LlzY9y4cXHppZfGokWLUkcEgIKlZwHSM2iTuZUrV8Y999wT1157bUREXH755XH99dfHvHnz4uqrr44XXnghbUAAKGB6FiA9gzaZa2hoiKqqqujSpUt069Ytmpqa2tZuuOGGWLVqVcJ0AFDY9CxAegZtMtevX7+20h8wYECsX7++be3NN9+MXC6XKhoAFDw9C5Cew9DI3KhRo2Ljxo1x3XXXxcSJE2P27Nnx5ptvRllZWaxYsSJuuumm1BEBoGDpWYD0cq3tHUcJF8jBgwfjyJEjMWjQoIiIWLx4cfz5z3+OlpaWGDNmTNxzzz3Rs2fPxCkBoDDpWYD0DNoAAACQR/Zok7mdO3fGhg0bzrm2cePG2LVrV7aBAKCI6FmA9AzaZO6nP/1prF69+pxra9eujZ/97GfZBgKAIqJnAdIzaJO5f/7zn3HVVVedc23kyJHx2muvZZwIAIqHngVIz6BN5o4fP97h1SLvvvtuhmkAoLjoWYD0DNpkbtCgQbFs2bJzri1fvrztlFQA4JPTswDpuUebzN12221x//33R2lpaUycODH69+8fDQ0N8dRTT8UzzzwTs2bNSh0RAAqWngVIz/VeJLFw4cJ45JFH4vjx423vde/ePX70ox/F5MmT0wUDgCKgZwHSMmiTzNGjR+PVV1+NI0eORJ8+fWLEiBHRq1ev1LEAoCjoWYB0DNoAAACQRw5DAwAAgDwyaAMAAEAeGbQBAAAgjwzaAAAAkEcGbZJqbW2No0ePhjP5ACD/9CxAGqWpA/C/acOGDTFv3rx49dVX49SpU1FaWhpf/OIXY8aMGTFy5MjU8QCgoOlZgLRc70Xm1q1bF3fddVdcdtllceONN0ZlZWW88847sWzZsti1a1csWLAgxo4dmzomABQkPQuQnkGbzE2cODH69esXjz76aORyubb3W1tbY9q0aXHgwIFYunRpwoQAULj0LEB69miTuR07dsSkSZPOKP+IiFwuF5MmTYrt27cnSgYAhU/PAqRn0CZz5eXl0dDQcM61hoaG6NmzZ8aJAKB46FmA9AzaZO5rX/ta/OIXv4iXXnrpjPfXrVsXv/rVr2LcuHGJkgFA4dOzAOnZo03mGhsb44477ojXXnstevXqFX379o2DBw/GsWPH4vOf/3wsXLgwLrrootQxAaAg6VmA9AzaJPH+++/HX//616irq4umpqbo3bt3XHnllXHttddGSYkvWgDAp6FnAdIyaAMAAEAe+ZMmAAAA5FFp6gD8b6iurj7rmpH25HK52LJlywVOBADFQ88CdC4GbTIxc+bM834AWLduXbzyyisZJQKA4qFnAToXe7RJ7uWXX47a2trYvHlzDB8+PKZPnx5f+cpXUscCgKKgZwGy54k2yXxY/PX19TFs2LB47LHH4pprrkkdCwCKgp4FSMegTeY++pf1BQsWKH4AyBM9C5CeQZvMfLT4/WUdAPJHzwJ0HgZtMvHd73436uvrY/jw4fH444/bGwYAeaRnAToXh6GRierq6oiI6NGjx3lPRc3lclFXV5dFLAAoCnoWoHPxRJtMTJ8+PXUEAChaehagc/FEGwAAAPKoJHUAAAAAKCYGbQAAAMgjgzYAAADkkUEbAAAA8sigDQAAAHlk0AYAAIA8+j8NtIqvYtsiEAAAAABJRU5ErkJggg==\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "fig, ax = plt.subplots(1,2,figsize=(14,8), sharey='row', gridspec_kw={'width_ratios': [1, 3]})\n", - "ax1 = plt.subplot(1,2,1)\n", - "\n", - "i = 0\n", - "df_diff_all = pd.DataFrame()\n", - "ind_notax = list_of_DBs.index('US_9R_8D_CT0.sqlite')\n", - "for conn, scenario, db in zip(list_of_conns, list_of_scenarios, list_of_DBs):\n", - " if ('neg' in db) | ('US_9R_8D_CT0' in db):\n", - " if i!=ind_notax:\n", - " df_diff = output_list[i] - output_list[i+1]\n", - " else:\n", - " df_diff = output_list[i] - output_list[ind_notax]\n", - "\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " df_diff_all.loc[:, scen_name] = df_diff.loc[:,2050]\n", - " i+=1\n", - "df_diff_all.transpose().plot(kind='bar',stacked=True, ax = ax1, color = df_diff_all.index.map(color_dict), legend=False)\n", - "# ax1.set_ylabel('Difference in 2050 primary energy consumption (EJ) \\n relative to succeeding scenario (to the right)')\n", - "ax1.set_title('relative to scenario \\n to the right -->',color='grey')\n", - "ax2 = plt.subplot(1,2,2)\n", - "\n", - "i = 0\n", - "df_diff_all = pd.DataFrame()\n", - "for conn, scenario, db in zip(list_of_conns, list_of_scenarios, list_of_DBs):\n", - " if 'neg' in db:\n", - " pass\n", - " else:\n", - " if i!=ind_notax:\n", - " df_diff = output_list[i] - output_list[i-1]\n", - " else:\n", - " df_diff = output_list[i] - output_list[ind_notax]\n", - "\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " df_diff_all.loc[:, scen_name] = df_diff.loc[:,2050]\n", - " i+=1\n", - "ax2.set_title('relative to scenario \\n <-- to the left',color='grey')\n", - "\n", - "df_diff_all.transpose().plot(kind='bar',stacked=True, ax = ax2, color = df_diff_all.index.map(color_dict))\n", - "ax1.set_ylabel('Difference in 2050 primary energy consumption (EJ)')\n", - "\n", - "# plt.ylim([-2000, 3000])\n", - "plt.legend(frameon=False)\n", - "\n", - "handles, labels = ax2.get_legend_handles_labels()\n", - "unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - "\n", - "plt.legend(*zip(*unique[::-1]), loc='upper left', frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "plt.tight_layout()\n", - "\n", - "# # fig, ax = plt.subplots(figsize=(10,8))\n", - "# # df_diff_all.transpose().plot(kind='bar',stacked=True, ax = ax, color = df_diff_all.index.map(tech_colormap))\n", - "# # handles, labels = subp.get_legend_handles_labels()\n", - "# # unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - "# # if l not in labels[:i]]\n", - "# # plt.legend(*zip(*unique[::-1]), loc='upper left',bbox_to_anchor=(1.01, 1), frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "# # plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_scens_all_primaryenergy_diff_alt.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "937d18b9", - "metadata": {}, - "outputs": [], - "source": [ - "df_diff_all" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "26f940d0", - "metadata": {}, - "outputs": [], - "source": [ - "region = 'US'\n", - "output_list = []\n", - "fig, ax = plt.subplots(figsize=(10,6))\n", - "for conn, scenario in zip(list_of_conns, list_of_scenarios):\n", - " \n", - " if region=='US':\n", - " query = \"SELECT tech, t_periods, sum(vflow_out) as vflow_out FROM Output_VFlow_Out WHERE \\\n", - " sector = 'electric' AND scenario='\" + scenario + \"' \\\n", - " AND vflow_out > 1e-3 GROUP BY tech, t_periods\"\n", - " else:\n", - " query = \"SELECT regions, tech, t_periods, sum(vflow_out) as vflow_out FROM Output_VFlow_Out WHERE \\\n", - " sector = 'electric' AND scenario='\" + scenario + \"' \\\n", - " AND vflow_out > 1e-3 GROUP BY regions, tech, t_periods\"\n", - "\n", - " df_s = pd.read_sql_query(query, conn)\n", - " df_plot = df_s.groupby(['tech' , 't_periods']).sum().pivot_table(values='vflow_out', index='tech', columns='t_periods')\n", - " df_plot = df_plot[~df_plot.index.str.contains('TRANS')]\n", - " df_plot = df_plot[~df_plot.index.str.contains('BLND')]\n", - " df_plot = df_plot[~df_plot.index.str.contains('Batt')]\n", - " df_plot = df_plot[~df_plot.index.str.contains('HYDPS')]\n", - " df_plot = df_plot[~df_plot.index.str.contains('_emissions')]\n", - " \n", - "# df_stor = pd.read_sql_query(\"SELECT DISTINCT tech FROM StorageDuration\", conn)\n", - "# df_plot = df_plot[~df_plot.index.isin(df_stor['tech'])]\n", - " \n", - " df_plot.loc[:,'agg_tech'] = [map_plants[y] for x in df_plot.index for y in map_plants.keys() if y.lower() in x.lower()] #map agg technologies\n", - "\n", - " df_plot = df_plot.groupby('agg_tech').sum()\n", - " df_plot = df_plot.loc[:, df_plot.columns >= 2020]\n", - " df_plot.fillna(0, inplace=True)\n", - " df_plot*=0.277778\n", - "\n", - " df_plot = df_plot[[2020, 2035, 2050]]\n", - "\n", - " output_list.append(df_plot)\n", - "\n", - "\n", - "ax = func_stacked_plot(output_list)\n", - "plt.xticks([2020, 2035, 2050])\n", - "\n", - "num_dfs = len(output_list)\n", - "col_spacing = [x - (num_dfs / 1.8 - 0.5) for x in np.arange(num_dfs)]\n", - "i = 0\n", - "period_placement= 2035\n", - "for spacing in col_spacing:\n", - " db = list_of_DBs[i]\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " plt.annotate(scen_name, (period_placement+spacing, \\\n", - " output_list[i][period_placement].sum()+ output_list[0][period_placement].sum()*0.05), \\\n", - " rotation = 'vertical', \\\n", - " horizontalalignment='center', verticalalignment='bottom', fontsize=14, color='grey')\n", - " i+=1\n", - "\n", - "ax.grid(axis='x')\n", - "plt.ylim([0, 12000])\n", - "ax.get_yaxis().set_major_formatter(\n", - "tick.FuncFormatter(lambda x, p: format(int(x), ',')))\n", - "plt.ylabel('Generation (TWh)')\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_all_scens_gen.jpg')\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2e94a7d4", - "metadata": {}, - "outputs": [], - "source": [ - "i = 0\n", - "df_diff_all = pd.DataFrame()\n", - "for conn, scenario, db in zip(list_of_conns, list_of_scenarios, list_of_DBs):\n", - " if i!=0:\n", - " df_diff = output_list[i] - output_list[i-1]\n", - " else:\n", - " df_diff = output_list[i] - output_list[0]\n", - "\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " df_diff_all.loc[:, scen_name] = df_diff.loc[:,2050]\n", - " i+=1\n", - "\n", - "fig, ax = plt.subplots(figsize=(12,8))\n", - "df_diff_all.transpose().plot(kind='bar',stacked=True, ax = ax, color = df_diff_all.index.map(color_dict), legend=False)\n", - "plt.ylim([-2000, 3000])\n", - "plt.ylabel('Difference in 2050 electricity generation (TWh) \\n relative to preceding scenario (to the left)')\n", - "plt.legend(frameon=False)\n", - "\n", - "handles, labels = ax.get_legend_handles_labels()\n", - "unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - "plt.legend(*zip(*unique[::-1]), loc='upper left',bbox_to_anchor=(1.01, 1), frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "plt.tight_layout()\n", - "\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_all_scens_gen_diff.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "67f1dfe8", - "metadata": {}, - "outputs": [], - "source": [ - "output_list = []\n", - "fig, ax = plt.subplots(figsize=(10,6))\n", - "for conn, scenario in zip(list_of_conns, list_of_scenarios):\n", - " df_plot = stacked_penergy_sector(conn, scenario, 'transport', 'All')\n", - " df_plot /=1000\n", - " df_plot_copy = df_plot.copy()\n", - " df_plot_copy.index = df_plot_copy.index.map(tech_transport)\n", - " df_plot_copy = df_plot_copy.reset_index().groupby(by=['input_comm']).sum()\n", - "\n", - " fuels_order = ['Other Fossil', 'Jet Fuel','Diesel','Gasoline','Biodiesel','Ethanol','Synthetic Fuel','Electricity','Hydrogen']\n", - " add_ind = [x for x in fuels_order if x not in df_plot_copy.index]\n", - " for ind in add_ind:\n", - " df_plot_copy.loc[ind,:] = 0\n", - " df_plot_copy = df_plot_copy.loc[fuels_order]\n", - " df_plot_copy = df_plot_copy[[2020, 2035, 2050]]\n", - "\n", - " \n", - " output_list.append(df_plot_copy)\n", - "ax = func_stacked_plot(output_list, col_order = ['Other Fossil', 'Jet Fuel','Diesel','Gasoline','Biodiesel',\\\n", - " 'Ethanol','Synthetic Fuel','Electricity','Hydrogen'], color_dict = tech_colormap)\n", - "plt.xticks([2020, 2035, 2050])\n", - "\n", - "num_dfs = len(output_list)\n", - "col_spacing = [x - (num_dfs / 1.8 - 0.5) for x in np.arange(num_dfs)]\n", - "i = 0\n", - "period_placement= 2035\n", - "for spacing in col_spacing:\n", - " db = list_of_DBs[i]\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " plt.annotate(scen_name, (period_placement+spacing, \\\n", - " output_list[i][period_placement].sum()+ output_list[0][period_placement].sum()*0.05), \\\n", - " rotation = 'vertical', \\\n", - " horizontalalignment='center', verticalalignment='bottom', fontsize=14, color='grey')\n", - " i+=1\n", - "\n", - "plt.ylabel('Energy consumption (EJ)')\n", - "plt.grid(axis='x')\n", - "plt.ylim([0,30])\n", - "\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_all_scens_transport.jpg')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "33cda9f2", - "metadata": {}, - "outputs": [], - "source": [ - "i = 0\n", - "df_diff_all = pd.DataFrame()\n", - "for conn, scenario, db in zip(list_of_conns, list_of_scenarios, list_of_DBs):\n", - " if i!=0:\n", - " df_diff = output_list[i] - output_list[i-1]\n", - " else:\n", - " df_diff = output_list[i] - output_list[0]\n", - "\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " df_diff_all.loc[:, scen_name] = df_diff.loc[:,2050]\n", - " i+=1\n", - "\n", - "fig, ax = plt.subplots(figsize=(9,8))\n", - "df_diff_all.transpose().plot(kind='bar',stacked=True, ax = ax, color = df_diff_all.index.map(tech_colormap), legend=False)\n", - "# plt.ylim([-6, 4])\n", - "plt.ylabel('Difference in 2050 energy consumption (EJ) \\n relative to preceding scenario (to the left)')\n", - "plt.legend()\n", - "\n", - "handles, labels = ax.get_legend_handles_labels()\n", - "unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - "plt.legend(*zip(*unique[::-1]), loc='lower left', frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "plt.tight_layout()\n", - "\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_all_scens_transportdiff.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8f14d20e", - "metadata": {}, - "outputs": [], - "source": [ - "output_list = []\n", - "fig, ax = plt.subplots(figsize=(10,6))\n", - "for conn, scenario in zip(list_of_conns, list_of_scenarios):\n", - " df_plot = stacked_penergy_sector(conn, scenario, 'industrial', 'All')\n", - " df_plot /=1000\n", - " df_plot_copy = df_plot.copy()\n", - " df_plot_copy.index = df_plot_copy.index.map(tech_industrial)\n", - " df_plot_copy = df_plot_copy.reset_index().groupby(by=['input_comm']).sum()\n", - "\n", - " fuels_order = ['Other Fossil', 'Coal','Diesel','Gasoline','Natural Gas', 'Biomass','Synthetic Natural Gas',\\\n", - " 'Electricity', 'Hydrogen']\n", - " add_ind = [x for x in fuels_order if x not in df_plot_copy.index]\n", - " for ind in add_ind:\n", - " df_plot_copy.loc[ind,:] = 0\n", - " df_plot_copy = df_plot_copy.loc[fuels_order]\n", - " df_plot_copy = df_plot_copy[[2020, 2035, 2050]]\n", - "\n", - " output_list.append(df_plot_copy)\n", - "ax = func_stacked_plot(output_list, col_order = ['Other Fossil', 'Coal','Diesel','Gasoline','Natural Gas', 'Biomass','Synthetic Natural Gas',\\\n", - " 'Electricity', 'Hydrogen'], color_dict = tech_colormap)\n", - "plt.xticks([2020, 2035, 2050])\n", - "\n", - "num_dfs = len(output_list)\n", - "col_spacing = [x - (num_dfs / 1.8 - 0.4) for x in np.arange(num_dfs)]\n", - "i = 0\n", - "period_placement= 2020\n", - "for spacing in col_spacing:\n", - " db = list_of_DBs[i]\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " plt.annotate(scen_name, (period_placement+spacing, \\\n", - " output_list[i][period_placement].sum()+ output_list[0][period_placement].sum()*0.05), \\\n", - " rotation = 'vertical', \\\n", - " horizontalalignment='center', verticalalignment='bottom', fontsize=14, color='grey')\n", - " i+=1\n", - " \n", - "plt.ylabel('Energy consumption (EJ)')\n", - "plt.grid(axis='x')\n", - "plt.ylim([0,30])\n", - "\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_all_scens_industrial.jpg')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3e970fb9", - "metadata": {}, - "outputs": [], - "source": [ - "i = 0\n", - "df_diff_all = pd.DataFrame()\n", - "for conn, scenario, db in zip(list_of_conns, list_of_scenarios, list_of_DBs):\n", - " if i!=0:\n", - " df_diff = output_list[i] - output_list[i-1]\n", - " else:\n", - " df_diff = output_list[i] - output_list[0]\n", - "\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " df_diff_all.loc[:, scen_name] = df_diff.loc[:,2050]\n", - " i+=1\n", - "\n", - "fig, ax = plt.subplots(figsize=(9,8))\n", - "df_diff_all.transpose().plot(kind='bar',stacked=True, ax = ax, color = df_diff_all.index.map(tech_colormap), legend=False)\n", - "# plt.ylim([-6, 4])\n", - "plt.ylabel('Difference in 2050 energy consumption (EJ) \\n relative to preceding scenario (to the left)')\n", - "plt.legend()\n", - "\n", - "handles, labels = ax.get_legend_handles_labels()\n", - "unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - "plt.legend(*zip(*unique[::-1]), loc='lower left', frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "plt.tight_layout()\n", - "\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_all_scens_industrialdiff.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8ec25443", - "metadata": {}, - "outputs": [], - "source": [ - "output_list = []\n", - "fig, ax = plt.subplots(figsize=(10,6))\n", - "for conn, scenario in zip(list_of_conns, list_of_scenarios):\n", - " df_plot = stacked_penergy_sector(conn, scenario, 'residential', 'All')\n", - " df_plot /=1000\n", - " df_plot_copy = df_plot.copy()\n", - " df_plot_copy.index = df_plot_copy.index.map(tech_residential)\n", - " df_plot_copy = df_plot_copy.reset_index().groupby(by=['input_comm']).sum()\n", - "\n", - " fuels_order = ['Other Fossil', 'Biomass','Natural Gas','Residential Solar','Synthetic Natural Gas', 'Electricity', 'Hydrogen']\n", - "\n", - " add_ind = [x for x in fuels_order if x not in df_plot_copy.index]\n", - " for ind in add_ind:\n", - " df_plot_copy.loc[ind,:] = 0\n", - " df_plot_copy = df_plot_copy.loc[fuels_order]\n", - " df_plot_res = df_plot_copy[[2020, 2035, 2050]]\n", - " \n", - " df_plot = stacked_penergy_sector(conn, scenario, 'commercial', 'All')\n", - " df_plot /=1000\n", - " df_plot_copy = df_plot.copy()\n", - " df_plot_copy.index = df_plot_copy.index.map(tech_commercial)\n", - " df_plot_copy = df_plot_copy.reset_index().groupby(by=['input_comm']).sum()\n", - "\n", - " fuels_order = ['Other Fossil', 'Natural Gas','Synthetic Natural Gas','Electricity']\n", - "\n", - " add_ind = [x for x in fuels_order if x not in df_plot_copy.index]\n", - " for ind in add_ind:\n", - " df_plot_copy.loc[ind,:] = 0\n", - " df_plot_copy = df_plot_copy.loc[fuels_order]\n", - " df_plot_comm = df_plot_copy[[2020, 2035, 2050]]\n", - " \n", - " df_plot_bld = pd.concat([df_plot_res, df_plot_comm]).groupby('input_comm').sum()\n", - " output_list.append(df_plot_bld)\n", - " \n", - "fuels_order = ['Other Fossil', 'Biomass','Natural Gas','Residential Solar','Synthetic Natural Gas', 'Electricity', 'Hydrogen']\n", - "ax = func_stacked_plot(output_list, col_order = fuels_order, color_dict = tech_colormap)\n", - "plt.xticks([2020, 2035, 2050])\n", - "\n", - "num_dfs = len(output_list)\n", - "col_spacing = [x - (num_dfs / 1.8 - 0.4) for x in np.arange(num_dfs)]\n", - "i = 0\n", - "period_placement= 2020\n", - "for spacing in col_spacing:\n", - " db = list_of_DBs[i]\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " plt.annotate(scen_name, (period_placement+spacing, \\\n", - " output_list[i][period_placement].sum()+ output_list[0][period_placement].sum()*0.05), \\\n", - " rotation = 'vertical', \\\n", - " horizontalalignment='center', verticalalignment='bottom', fontsize=14, color='grey')\n", - " i+=1\n", - " \n", - "plt.ylabel('Energy consumption (EJ)')\n", - "plt.grid(axis='x')\n", - "plt.ylim([0,25])\n", - "\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_all_scens_buildings.jpg')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f5007e5a", - "metadata": {}, - "outputs": [], - "source": [ - "i = 0\n", - "df_diff_all = pd.DataFrame()\n", - "for conn, scenario, db in zip(list_of_conns, list_of_scenarios, list_of_DBs):\n", - " if i!=0:\n", - " df_diff = output_list[i] - output_list[i-1]\n", - " else:\n", - " df_diff = output_list[i] - output_list[0]\n", - "\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " df_diff_all.loc[:, scen_name] = df_diff.loc[:,2050]\n", - " i+=1\n", - "\n", - "fig, ax = plt.subplots(figsize=(9,8))\n", - "df_diff_all.transpose().plot(kind='bar',stacked=True, ax = ax, color = df_diff_all.index.map(tech_colormap), legend=False)\n", - "# plt.ylim([-6, 4])\n", - "plt.ylabel('Difference in 2050 energy consumption (EJ) \\n relative to preceding scenario (to the left)')\n", - "plt.legend()\n", - "\n", - "handles, labels = ax.get_legend_handles_labels()\n", - "unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - "plt.legend(*zip(*unique[::-1]), loc='lower left', frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "plt.tight_layout()\n", - "\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_all_scens_buildingsdiff.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "id": "975c8af2", - "metadata": {}, - "outputs": [], - "source": [ - "def plot_mit_curve(merge_dbs, xlim, ylim):\n", - " fig, ax = plt.subplots(figsize=(10,6))\n", - "\n", - " w = merge_dbs['emissions'].diff() \n", - " w.iloc[0] = merge_dbs['emissions'].iloc[0]\n", - " w = list(w)\n", - " xticks=[]\n", - " for n, c in enumerate(w):\n", - " xticks.append(sum(w[:n]) + w[n]/2)\n", - "\n", - " plt.bar(xticks,height=merge_dbs['shadow_price'], width =w)\n", - " plt.ylim([0,ylim])\n", - " plt.xlim([0,xlim])\n", - " plt.xlabel('Avoided annual CO$_2$ emissions (million tonnes)')\n", - " plt.ylabel('Shadow price on abated CO$_2$ emissions ($/tonnene CO$_2$)')\n", - " ax.get_yaxis().set_major_formatter(\n", - " tick.FuncFormatter(lambda x, p: format(int(x), ',')))\n" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "1b60e309", - "metadata": {}, - "outputs": [], - "source": [ - "#os.mkdir('carbon_tax_figures_updates')" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "2f7edebf", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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/u/mjU2bNmHq1Klqt4xJJBLo6urCysoKNjY2mo+UiIiIiEiERiW6I0eOFK6Wq6iowKRJkzB48OAWDYyIiIiIqDlEXwG8aNGiloiDiOrwuLIS2v93hjURERGJIzrRffjwIQoLC+u94vf27dswNDREt27dmh0c0fNOWypFVKhXvfWLwj9rxWiIiIg6FtHngIWHh2PhwoX11vv5+WH9+vXNCoqIiIiIqLlEJ7o///wzJk6cWG/9xIkTcezYsWYFRURERJ1XdUWF8HPtO0BELUH01oX79+/jhRdeqLfexMQE9+7da1ZQRERE1HlpyWT4ecbMBtuM+y65laKhzkz0iq6RkREuX75cb/3ly5ehUCiaFRQRERERUXOJTnQdHR3xzTff4MyZM2p1mZmZ+Oabb/Daa69pJDgiIiIioqYSvXXB398fR48exTvvvIPXXnsN5ubmkEgk+PXXX5Geng5jY2MsXry4JWIlIiIiImo00YmuiYkJkpOT8cknnyA1NRU//fQTAEAul2PGjBkICgqCiYmJpuMkIiIiIhJFdKILAMbGxli3bh1qampQUFCAmpoa9OjRAxKJRNPxERERERE1iehE9/bt23WW37lzR+VzfRdKEBERERG1BtGJrrOzc6NWbrOyspoUEBERERGRJohOdMPCwtQS3aqqKty8eRPfffcdevToAQ8PD40FSERERETUFKITXXd393rr5s+fj1mzZqG0tLRZQRERERERNZfoc3QboqenB3d3d+zZs0eT3RIRERERiabRRBcApFIp7t69q+luiYiIiIhE0Wiim52djYSEBJiZmWmyWyIiIiIi0TR26kJxcTGKi4uhq6uL8PBwjQRHRERERNRUohPdV199tc5E18DAAP369YOrqysUCoVGgiMiIiIiairRie66detaIg4iIiIiIo3S+MtoRERERETtwTNXdOu78vdZeAUwEREREbWlZya6jb3y9894BTARtYbHlVXQlnZp6zCIiKgdemai++crf2tqapCQkIBbt27Bzc0NAwYMQE1NDXJzc/HPf/4Tffr0wdy5c1s0aCKiWtrSLli95GCDbVZtdG2laIiIqD15ZqL75yt/Y2Nj8ejRI3z//fcwNDRUqfP398dbb72FgoICzUZJRERERCSS6JfRvvrqK/z1r39VS3IBwMjICLNnz8aXX36pkeCIiIiIiJpKdKKbn5+P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rru7e4OfiYiIiIjaI9EXRhARERERdQRNOnXhf//3f5GUlIQbN27gwYMHqKmpUamXSCTIyMjQSIBERERERE0hOtGNiopCdHQ0FAoFLCws0L9//5aIi4iIiIioWUQnuomJiRgzZgxiYmIgk8laIiYiIiIiomYTvUf38ePHmDRpEpNcIiIiImrXRCe648aNw4ULF1oiFiIiIiIijRGd6K5atQoXLlxAVFQUbt++rfYiGhERERFReyB6j66RkRGmTp2KyMhIREdH19lGIpHgP//5T7ODIyIiIiJqKtGJ7ieffIJdu3ahb9++sLa2hlwub4m4iIiIiIiaRXSiq1QqMWHCBERFRbVEPEREREREGiF6j25NTQ3s7e1bIhYiIiIiIo0Rneg6OzvjX//6V0vEQkRERESkMaIT3ffeew+5ublYuXIlzp07h3v37iE/P1/tFxERERFRWxK9R3fKlCkAgKysLCQlJdXbLisrq+lR1ePbb79FaGioWrmHhwdWrVolfD569Cg2b96MK1euwNTUFPPmzcPcuXPVntu1axcSExORl5cHMzMzBAcHY8yYMRqPm4iIiIhan+hE18/PDxKJpCViabS4uDjo6+sLn42NjYWfMzMzsXDhQsyYMQPLli3DmTNnEBYWBm1tbbz99ttCu127diEyMhKBgYGwtLSEUqmEr68vlEolXn755Vb9PkRERESkeaITXX9//5aIQ5ShQ4fCyMiozrqoqChYWloiLCwMADB69GjcuXMH0dHRePPNN6GlpYWKigrs2LED7777Lnx8fAAAr776Ktzc3LBjxw5s2bKl1b4LEREREbUM0Xt027OKigqcOHECU6dOVSl3dXXF/fv3cfHiRQDAmTNnUFxcjGnTpgltunTpgilTpiA9PZ23vRERERF1Ak1OdG/fvo19+/Zh9+7duHPnDgDg8ePHyM/Px+PHjzUWYF3c3NwwZMgQODs7IyoqShjv+vXrqKysxKBBg1Tam5ubAwCuXr0KAMjJyQEAtXZmZmZ4+PAh7t6926LxExEREVHLE711AQDCw8PxxRdfoKqqChKJBEOGDEGvXr1QVlYGFxcXBAQEwNPTU8OhAiYmJvD394e1tTW6dOmC9PR0bN++HTdv3sS6devw4MEDAIBCoVB5rvZzbX1RURFkMhl0dHRU2hkYGAAACgsL0bNnT43HT0REREStR3SiGxcX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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "fig, ax = plt.subplots(figsize=(10,8))\n", - "x_adj = -1.25\n", - "for db in list_of_DBs:\n", - " if db !=base:\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " ax.bar(emis_reductions[db].index + x_adj,emis_reductions[db]['emissions'], label = scen_name)\n", - " x_adj+=0.5\n", - "plt.ylabel('Annual emissions reductions (million tonnes CO$_2$)')\n", - "plt.legend()\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_mitigation_curve.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "id": "3121b7ad", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "
\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
-1010100200300400500
20201.818989e-12-9.094947e-13-9.094947e-13-2.728484e-12-2.728484e-12-4.547474e-129.094947e-13
2025-5.744561e+014.826871e+017.003515e+029.430930e+021.091853e+031.381918e+031.664550e+03
2030-6.422540e+013.668175e+016.532997e+029.211713e+021.230383e+031.650798e+031.956162e+03
2035-5.962839e+016.782927e+017.155486e+021.025245e+031.553076e+031.950417e+032.260195e+03
2040-7.093354e+015.148444e+017.426683e+021.155758e+031.765291e+032.225288e+032.432806e+03
2045-1.064066e+025.571457e+018.379535e+021.363562e+032.064070e+032.507763e+032.626591e+03
2050-1.667094e+028.162671e+018.476383e+021.467175e+032.178318e+032.599885e+033.046109e+03
\n", - "" - ], - "text/plain": [ - " -10 10 100 200 300 \\\n", - "2020 1.818989e-12 -9.094947e-13 -9.094947e-13 -2.728484e-12 -2.728484e-12 \n", - "2025 -5.744561e+01 4.826871e+01 7.003515e+02 9.430930e+02 1.091853e+03 \n", - "2030 -6.422540e+01 3.668175e+01 6.532997e+02 9.211713e+02 1.230383e+03 \n", - "2035 -5.962839e+01 6.782927e+01 7.155486e+02 1.025245e+03 1.553076e+03 \n", - "2040 -7.093354e+01 5.148444e+01 7.426683e+02 1.155758e+03 1.765291e+03 \n", - "2045 -1.064066e+02 5.571457e+01 8.379535e+02 1.363562e+03 2.064070e+03 \n", - "2050 -1.667094e+02 8.162671e+01 8.476383e+02 1.467175e+03 2.178318e+03 \n", - "\n", - " 400 500 \n", - "2020 -4.547474e-12 9.094947e-13 \n", - "2025 1.381918e+03 1.664550e+03 \n", - "2030 1.650798e+03 1.956162e+03 \n", - "2035 1.950417e+03 2.260195e+03 \n", - "2040 2.225288e+03 2.432806e+03 \n", - "2045 2.507763e+03 2.626591e+03 \n", - "2050 2.599885e+03 3.046109e+03 " - ] - }, - "execution_count": 35, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# fig, ax = plt.subplots(figsize=(10,8))\n", - "x_adj = -1.25\n", - "all_emiss_db = pd.DataFrame(index = [2020, 2025, 2030, 2035, 2040, 2045, 2050])\n", - "for db in list_of_DBs:\n", - " if db !=base:\n", - " dummy = emis_reductions[db]\n", - " \n", - " try:\n", - " scen_name = int(map_scenario_names[db.replace('sqlite','').split('CT')[1]].replace('$/tonne',''))\n", - " except:\n", - " scen_name = 0\n", - " dummy.columns = [scen_name]\n", - " all_emiss_db = pd.merge(all_emiss_db, dummy, left_index= True, right_index=True)\n", - "all_emiss_db" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "id": "7c355833", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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QGg0Gt544w0UCoVBcHmrpKQkioqKjIJ5nU7HmTNnyu1SFw8eadEU9z13d3fWrFnDxIkTGTp0qMFuGQkJCcTExFCvXj1mz55NVFQU77//PtOnT2fcuHGo1Wq2bduGl5cX6enpVq2Xpdfq06cPO3bswNXVlaCgIM6ePcuuXbuMxuWVBYnLli0jKioKBwcHunXrVmG5tra2PP7440RHR6NWq5k4caJRnldffZXff/+d0aNHM3z4cIKDg1EqlVy4cIE9e/awZ88evL29K7yGpedXVUFBAb169eKxxx6jVatWuLq6EhcXx6FDh/S7sZiSpzwzZ87k8OHDjBkzhmeeeQYXFxe2b99Oeno6K1asMHuHlKrWozKmvvczZszgl19+4ZlnnmHMmDHY29uzdetWfH19jQIfc36WZ8+ezeHDhxk/frx+eaMbN26wd+9eVq9eTZMmTSr8ma1fv77R/dSk993R0ZGePXty+PBho9103NzcWLt2LZMmTWLo0KEGOwNlZGRw4MABLl26RPv27fXnmPM+gHnfdXBzws7KlSv1+ct+HnJzc/n+++85f/48EydO1E8EvFVRURH/+Mc/mDJlilH3+J9//kl+fr7VVtgQtZsEmuKBEB4eTkxMDJ988gn79+/nhx9+QKfT0axZM0aNGsWzzz4L3PziXbNmDUuWLOHf//43Pj4+PPfcc7i5uVV5iZmKWHqt119/HXt7e3bu3ElhYSFt2rTho48+4l//+pdBvvbt2zNz5kz++9//Mn/+fLRaLZs2bbpj2VFRUWzevBmg3DX2vLy82Lp1K+vWreOnn35i69at+hnv06dPx8PD447lW3p+VTk7O/PMM89w5MgRfv75ZzQaDU2aNGHu3Ln6fZlNyVOeli1bsmXLFpYtW8ann36KWq0mNDSUDz74QD+xytp1rQpT3/vg4GA++eQT3nvvPdauXUv9+vV55plnqF+/vtGkFXN+ln18fIiOjmbFihXs3LkThUKBj48PPXr00A/5qOhntrwAq6a978OHD2fy5MlcvnzZaKxx69at+e6779i0aRP79u3j559/Rq1W06BBA9q1a8ekSZMMFr43530oY+p3XZmOHTvy/fffs379en7++We2bNmCi4sLbdq0Yc6cOeW+hyqVipdffpnAwEAmT55slL57924aNWokuwIJQPY6F0IIIaxGq9UyePBgevbsydy5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\n", - "text/plain": [ - "

" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "fig, ax = plt.subplots(figsize=(10,8))\n", - "aa = 0.2\n", - "for ind, row in all_emiss_db.iterrows():\n", - " plt.plot(row.values, row.index, color = 'b', alpha=aa, label = ind)\n", - " aa+=0.12\n", - "plt.xlabel('Annual emissions reductions (million tonnes CO$_2$)')\n", - "plt.ylabel('Carbon price (\\$/tonne CO$_2$)')\n", - "\n", - "plt.legend()\n", - "handles, labels = ax.get_legend_handles_labels()\n", - "unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - "plt.legend(*zip(*unique[::-1]), loc='upper left', frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "plt.ylim([-50,1000])\n", - "plt.xlim([-2000, 5000])\n", - "ax2 = ax.twiny()\n", - "sum_emissions = all_emiss_db.sum()/1000*5\n", - "ax2.plot(sum_emissions.values,sum_emissions.index, 'k--', label='Cumulative')\n", - "# ax2.plot(all_emiss_db.loc[2050]*30/1000, sum_emissions.index, edgecolor=\"None\")\n", - "# ax2.plot(all_emiss_db.loc[2020]*30/1000, sum_emissions.index, edgecolor=\"None\")\n", - "\n", - "ax2.set_xlim([-2000/1000*30, 5000/1000*30])\n", - "ax2.set_xlabel('Cumulative emissions reductions (Gt CO$_2$)')\n", - "ax2.legend(loc = 'lower left')\n", - "mpl_axes_aligner.align.xaxes(ax, 0, ax2, 0, 0.4)\n", - "ax.grid(axis='x')\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_mitigation_curve_annual_cumulative_PvsQ.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "id": "0c8e352a", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
index0
0-10-2.626745
1101.708027
210022.487300
320034.380018
430049.414953
540061.580349
650069.932062
\n", - "
" - ], - "text/plain": [ - " index 0\n", - "0 -10 -2.626745\n", - "1 10 1.708027\n", - "2 100 22.487300\n", - "3 200 34.380018\n", - "4 300 49.414953\n", - "5 400 61.580349\n", - "6 500 69.932062" - ] - }, - "execution_count": 37, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dummy =pd.DataFrame(sum_emissions)\n", - "# dummy.loc[0] = 0\n", - "dummy.sort_index(inplace=True)\n", - "# dummy['diff'] = dummy[0].diff()\n", - "# dummy.fillna(0, inplace=True)\n", - "dummy.reset_index(inplace=True)\n", - "dummy" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "id": "4f75051b", - "metadata": {}, - "outputs": [], - "source": [ - "def resource_curve_plot(df_all, xlabel):\n", - " fig, ax = plt.subplots(figsize=(8,6))\n", - " \n", - " df_sel = df_all[df_all[0]>0]\n", - "\n", - " start =0\n", - " for ind, row in df_sel.iterrows():\n", - " x = start + (row[0]-start)/2\n", - " plt.bar(x, row['index'] , width=row[0]-start, color='b')\n", - " start = row[0]\n", - " \n", - " df_sel = df_all[df_all[0]<0]\n", - " df_sel.sort_index(ascending=False, inplace=True)\n", - " start =0\n", - " for ind, row in df_sel.iterrows():\n", - " x = start + (row[0]-start)/2\n", - " plt.bar(x, row['index'] , width=row[0]-start, color='b')\n", - " start = row[0]\n", - " \n", - " plt.ylabel('Carbon tax (\\$/tonne CO$_2$)')\n", - " plt.xlabel(xlabel)\n", - " plt.tight_layout()\n", - "# plt.savefig(country + '_resource_curve.jpg', dpi=400)" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "id": "98d2fd2b", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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0m+NHvr55JNPEBsbiy1btqBnz54YNGgQXF1d8eKLL6JNmzaQSqUQi8W4efMmzp8/jzNnzuDChQuwt7fHmjVrnkYfiIiIqIVqNKjIJmxLS0vD/v378eWXX0IikcDAwEChnVQqhYmJCTw9PTFnzhx4eXkptSEiIiJSh0on0xoYGMDb2xve3t6orq7GhQsXkJubi/v37wMAnn/+edjZ2aFHjx68czIRERFpjNpX/RgbG6NPnz7o06ePNuohIiIiklPr7slERERETxODChEREQkWgwoREREJFoMKERERCRaDChEREQkWgwoREREJltpBpaqqqtE2BQUFTSqGiIiI6FFqB5WAgABcvHixwfVJSUkYN25cs4oiIiIiApq4R2XSpElYv349amtr5cuLioowb948LF++HK6urhotkoiIiPST2kHlwIEDmDBhAtavX49JkyYhJycHR44cgZ+fH3744QdERkZi69at2qiViIiI9IzaU+g/99xz+OCDDzB8+HC8++67GD9+PGpra9G3b1+sXr0aL730kjbqJCIiIj2kdlCRMTQ0hIGBAWpqagAAnTp1Qps2bTRWGBEREZHah34qKyuxcuVKhISEoF27djhw4ACWLl2KI0eOwN/fH6dOndJGnURERKSH1A4q48ePx969exEWFoavv/4ajo6OCAkJwf79+9GuXTuEhoYiMjJSG7Uqqa2tRUBAAJycnHD48GGFdWlpaQgICICbmxt8fX2RkJBQ7za2bt0KHx8f9OzZE4GBgcjIyHgapRMREZEK1A4qRkZG2L17N+bPn49Wrf46cmRvb4/ExETMmTMH3377rUaLbMju3btRWFiotDw7Oxvh4eFwdnbG5s2bERgYiKioKOzevVuh3datWxETE4OgoCBs2rQJXbp0QWhoKC5duvRU6iciIqInUzuofPvtt3Bzc6t3nZGREebOnYu9e/c2u7DG3L17F7GxsViyZInSuvXr18PFxQVRUVHw8PBAeHg4Jk6ciA0bNqCurg7Aw8us4+LiEBwcjJCQEAwaNAj/+te/8NJLLyEuLk7r9RMREVHj1A4qJiYmjbZxdnZuUjHq+OSTT/Dqq69i4MCBCsurqqpw9uxZjBkzRmG5n58f7ty5I5+sLisrC6WlpRg7dqy8jZGREUaPHo309HRIpVKt94GIiIierElX/dy7dw/ffPMNLl68CLFYLN9LIWNgYIAdO3ZopMD6nDt3DkeOHEFKSorCpHMAkJeXh+rqatjZ2Sksd3BwAADk5ubCzc0NOTk5AKDUzt7eHhUVFSgoKECnTp201gciIiJqnNpB5erVq5g6dSoqKirQpUsX/PHHH7C3t0dJSQkKCwtha2uLjh07aqNWAEBNTQ1WrlyJ0NBQdO7cGTdv3lRYX1JSAgCwtLRUWC57LFsvFoshEolgamqq0E52iXVxcTGDChERkY6pHVQ+/fRTtGrVCocOHYKZmRkGDx6Md955B4MGDUJycjJWrVqF6OhobdQKANi5cycqKysREhLyxHYGBgaNLq+vjeyQT0PPb8iFCxfUat/SZGZm6roEndP3MdBV/7s794BZa9PGG2pZv379dF2Czt+Dun59IeAYaJ7aQSUzMxPTpk3DSy+9hOLiYgB/fbn7+fkhMzMTn3zyCXbu3KnRQoGH9xNat24d3nvvPVRWVqKyshJlZWUAHs7vUlpaKt8jIttzIiMWiwH8tWfF0tISEokEEolE4bwbWTt1J69zdXVV6fydligzM1MQH9K6pO9joOv++y/5Tmev/SQH145/qq+ny5+Brt8DQqDPYyCRSLT2B7vaQaW6ulp+aEd22KS0tFS+3tnZGUlJSZqp7jEFBQWoqKjAsmXLlNYtW7YMFhYWOHPmDIyNjZGbm4shQ4bI11+9ehUA0K1bNwB/nZuSk5MDFxcXebucnByYmZlp9fAVERERqUbtoPLoeSGmpqZo3749fv75Z4wcORIAcOXKFZiZmWm2yv9na2urtKfm7t27WLx4MebNmwcPDw+IRCJ4eHggNTUV06dPl7dLTk5G+/bt0aNHDwBA3759YWFhgZSUFHlQqa2tRWpqKjw9PdU+9ENERESap3ZQcXd3x/Hjx7Fo0SIAgL+/P3bs2IHS0lLU1dXJ766sDWZmZnB3d1dYJgtN9vb26N+/PwBgzpw5mDp1KlasWAF/f39kZWUhMTERkZGRMDR8eEW2SCRCWFgYYmJiYGVlBRcXFyQmJiIvLw9r167VSv1ERESkHrWDSmhoKM6fPy8/t2PhwoUoKytDamoqDA0NMW7cOLz99tvaqFVlffr0wcaNGxEdHY2kpCR06NABERERmDJlikI72Qm5CQkJuHv3LhwcHBAfH4/u3bvromwiIiJ6jNpBxdraGtbW1vLHIpEIK1euxMqVKzVamKpefPFFXL58WWm5l5cXvLy8Gn1+SEhIo1cQERERkW6oPTPtuXPnUFRU1OD6oqIinDt3rllFEREREQFNCCrBwcE4ffp0g+vPnj2L4ODgZhVFREREBDQhqDR2D5yqqir5CatEREREzaHSOSplZWXyidCAh9PL37p1S6mdWCzGoUOHOAcJERERaYRKQWX79u3YsGEDgIdTy0dFRSEqKqretlKpVH7pMhEREVFzqBRUBg0aBJFIBACIjo7GmDFjlC7hNTAwQOvWreHq6opevXppvlIiIiLSOyoFlX79+snvX1BVVYURI0bA0dFRq4URERERqT2Pyty5c7VRBxEREZESXp5DREREgsWgQkRERILFoEJERESCxaBCREREgsWgQkRERIKl9lU/MmVlZbh9+zZKSkrqnVZ/wIABzSqMiIiISO2gUlJSglWrVuHw4cOora1VWi+VSmFgYIDff/9dIwUSERGR/lI7qERGRuLo0aMICgrCwIEDYWlpqY26iIiIiNQPKunp6XjzzTexfPlybdRDREREJKf2ybQikQgvv/yyNmohIiIiUqB2UBk5ciTS09O1UQsRERGRArWDSkhICAoLC7Fs2TJkZ2ejsLAQ9+7dU/pHRERE1Fxqn6MycuRIGBgY4OLFizhw4ECD7XjVDxERETWX2kFlzpw5MDAw0EYtRERERArUDirz5s3TRh1EpANV1bUQGRs1ezv9+vXTQDVERMqaPDMtAFy+fBn5+fkAABsbGzg5OWmkKCJ6OkTGRvBf8p2uy2iWg2vH67oEItKiJgWVo0ePIioqCrdv3wbw12y01tbWiIiIgK+vr0aLJCIiIv3UpAnf5s+fj06dOmHRokWws7ODVCpFbm4u9uzZgwULFuCLL76Ap6enNuolIiIiPaJ2UNm4cSPs7Oywe/dumJubK6x74403MGXKFGzcuJFBhYiIiJpN7XlULl26hAkTJiiFFAAwNzfHhAkTeGkyERERaYTaQcXY2BgVFRUNri8vL4exsXGziiIiIiICmhBU+vXrh3//+9+4fv260robN25g165d6N+/vyZqIyIiIj2n9jkqS5YsweTJk+Hn5wcfHx907doVAHDt2jWcOHECpqamWLJkicYLJSIiIv2jdlBxcHDAvn37EB0djVOnTuH7778HADz33HMYOnQoFi1aJA8vRERERM3RpHlUunTpgs8//xx1dXUo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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "resource_curve_plot(pd.DataFrame(sum_emissions).reset_index(), xlabel = 'Cumulative emissions reductions (Gt CO$_2$)')\n", - "# plt.plot(sum_emissions.values,sum_emissions.index, 'k--', label='Cumulative')\n", - "plt.xlim([-20, 120])\n", - "plt.ylim([-100, 1100])\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/co2_mitigation_curve_stacked_alt.jpg', dpi=400)" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "id": "02b01a02", - "metadata": {}, - "outputs": [ - { - "ename": "KeyError", - "evalue": "0", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m/mnt/cephfs/cluster/epp/user/avenkate/pwd/envs/temoa-py3/lib/python3.7/site-packages/pandas/core/indexes/base.py\u001b[0m in \u001b[0;36mget_loc\u001b[0;34m(self, key, method, tolerance)\u001b[0m\n\u001b[1;32m 3360\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 3361\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_engine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcasted_key\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3362\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mKeyError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/mnt/cephfs/cluster/epp/user/avenkate/pwd/envs/temoa-py3/lib/python3.7/site-packages/pandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", - "\u001b[0;32m/mnt/cephfs/cluster/epp/user/avenkate/pwd/envs/temoa-py3/lib/python3.7/site-packages/pandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", - "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.Int64HashTable.get_item\u001b[0;34m()\u001b[0m\n", - "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.Int64HashTable.get_item\u001b[0;34m()\u001b[0m\n", - "\u001b[0;31mKeyError\u001b[0m: 0", - "\nThe above exception was the direct cause of the following exception:\n", - "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m/tmp/ipykernel_13746/1202034546.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mresource_curve_plot\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mall_emiss_db\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mloc\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m2020\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'2020 annual emissions reductions (million tonnes CO$_2$/year)'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m/tmp/ipykernel_13746/105789939.py\u001b[0m in \u001b[0;36mresource_curve_plot\u001b[0;34m(df_all, xlabel)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0mfig\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0max\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mplt\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msubplots\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfigsize\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m8\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m6\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mdf_sel\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdf_all\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mdf_all\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m>\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0mstart\u001b[0m \u001b[0;34m=\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/mnt/cephfs/cluster/epp/user/avenkate/pwd/envs/temoa-py3/lib/python3.7/site-packages/pandas/core/series.py\u001b[0m in \u001b[0;36m__getitem__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 940\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 941\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mkey_is_scalar\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 942\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_get_value\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 943\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 944\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mis_hashable\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/mnt/cephfs/cluster/epp/user/avenkate/pwd/envs/temoa-py3/lib/python3.7/site-packages/pandas/core/series.py\u001b[0m in \u001b[0;36m_get_value\u001b[0;34m(self, label, takeable)\u001b[0m\n\u001b[1;32m 1049\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1050\u001b[0m \u001b[0;31m# Similar to Index.get_value, but we do not fall back to positional\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1051\u001b[0;31m \u001b[0mloc\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mindex\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlabel\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1052\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mindex\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_get_values_for_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mloc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlabel\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1053\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/mnt/cephfs/cluster/epp/user/avenkate/pwd/envs/temoa-py3/lib/python3.7/site-packages/pandas/core/indexes/base.py\u001b[0m in \u001b[0;36mget_loc\u001b[0;34m(self, key, method, tolerance)\u001b[0m\n\u001b[1;32m 3361\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_engine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcasted_key\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3362\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mKeyError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 3363\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mKeyError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3364\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3365\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mis_scalar\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0misna\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhasnans\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mKeyError\u001b[0m: 0" - ] - }, - { - "data": { - "image/png": "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U0xMjMaMGRPpzAAAIEwhX7pfsGCB3n77bbndbrndbjU1NamiokKzZs0K+jR+SUmJvF6vjh07JunyS+333HOP1qxZo6amJt1555367LPPtGXLFs2bN0833nijfY8KAABICvM9+u3bt6u8vFyFhYWKj49Xfn6+iouLg44LBALq6urq+To2NlabN2+Wx+PRli1b1NjYqNtvv12LFy/WsmXLBv+RAACAXsL61P24ceO0bdu2fo+pqKhQRUVF0NqPf/xjrV27NvLpAABAVLh6HQAABiP0AAAYjNADAGAwQg8AgMEIPQAABiP0AAAYjNADAGAwQg8AgMEIPQAABiP0AAAYjNADAGAwQg8AgMEIPQAABiP0AAAYjNADAGAwQg8AgMEIPQAABiP0AAAYjNADAGAwQg8AgMEIPQAABiP0AAAYjNADAGAwQg8AgMEIPQAABiP0AAAYjNADAGAwQg8AgMEIPQAABiP0AAAYjNADAGAwQg8AgMEIPQAABiP0AAAYjNADAGAwQg8AgMEIPQAABiP0AAAYjNADAGAwQg8AgMEIPQAABiP0AAAYjNADAGAwQg8AgMEIPQAABiP0AAAYjNADAGAwQg8AgMEIPQAABiP0AAAYjNADAGAwQg8AgMEIPQAABgsr9KdOndKSJUuUnZ0tl8ulsrIyXbhwIaw7aGtr00svvaScnBxlZGTooYceksfjiWpoAAAQnutDHeDz+VRQUKAxY8bI4/GoublZ69atU3NzszZu3NjvuRcvXlRBQYHa29u1cuVKJSUl6cyZMzp79uygPQAAANC3kKHfsWOHfD6fvF6vEhMTJUmxsbEqKiqS2+1WWlpan+du2bJFX3/9tfbs2aPRo0dLku67775BGh0AAIQS8qX76upquVyunshL0owZM+RwOFRdXd3vuVVVVcrLy+uJPAAAGFohQ19fX6/x48cHrTkcDiUnJ6uhoaHP886cOaNz587ptttuU3FxsbKyspSdna1Vq1apubk5+skBAEBIIUPv8/nkdDp7rTudTrW0tPR5XmNjoyRp69atam1t1aZNm7R69Wr985//1LPPPhv5xAAAIGwh36Pvi2VZiomJ6fP7XV1dki7/gaCyslIOh0OSlJCQoMLCQh05ckRZWVlh319dXV2koyJMtbW1wz3CNYF9th97bD/2eOQIGXqn0ymfz9drvbW1VampqX2ed+ut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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "resource_curve_plot(all_emiss_db.loc[2020], '2020 annual emissions reductions (million tonnes CO$_2$/year)')" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "id": "4cd38242", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAroAAAIqCAYAAADLm+laAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8/fFQqAAAACXBIWXMAAAsTAAALEwEAmpwYAACnoElEQVR4nOzdeViUVf8/8PcMuwyLqKCgiAqYIiEugKlAio+ZII+KpiluJKm4WwmlPpqG5JMLCVIoLpD5VdRcSFIqRXOr4MGSLAVMXFBUxGEdtvn94Y/JcdgGBgbw/bourqs559znfO47l49nzn2OQCqVSkFERERE1MoI1R0AEREREVFjYKJLRERERK0SE10iIiIiapWY6BIRERFRq8REl4iIiIhaJU11B9AaVFRUoKCgAFpaWhAIBOoOh4iIiKjFkEqlKC0thb6+PoRC1c7BMtFVgYKCAly/fl3dYRARERG1WLa2tjAwMFBpn0x0VUBLSwvAs/9B2traao6m9bh69Sr69Omj7jBaFT5T1eMzVS0+T9XjM1U9PlPVKikpwfXr12X5lCox0VWByuUK2tra0NHRUXM0rQufp+rxmaoen6lq8XmqHp+p6vGZql5jLP/ky2hERERE1Cox0SUiIiKiVomJLhERERG1Skx0iYiIiKhVYqJLRERERK0Sd10gIiKiOhOLxcjOzkZpaam6Q1EbTU1NXLt2Td1htBhaWlowNTWFoaFhk4/NRJeIiIjqRCwW48GDB7CwsICent5LexpoQUEB9PX11R1GiyCVSlFUVIS7d+8CQJMnu1y6QERERHWSnZ0NCwsLtGnT5qVNckk5AoEAbdq0gYWFBbKzs5t8fCa6REREVCelpaXQ09NTdxjUAunp6alluQsTXSIiIqozzuRSfajr1w0TXSIiIiJqlZjoEhER0Uvr3LlzmD17NpydndGnTx+4ubnhww8/RHp6urpDk3P58mX07NkTv//+u1LXff/999i7d69C+datW+Ho6Kiq8JotJrpERET0Utq6dSveeecdaGlpYfXq1di1axeWLl2K7OxsTJo0Sd3hqcT333+Pffv2KZRPmDABe/bsUUNETYvbixEREdFL56effkJYWBjeffddLF26VK7O29sbP/zwg5oiaxodO3ZEx44d1R1Go+OMLhEREb10oqKi0K5dOyxYsKDK+uHDhwMAevbsiaioKLm6Y8eOoWfPnsjJyQEA3LlzBz179sTRo0fx8ccfw8nJCc7OzggLCwMA/PDDDxg9ejQcHR3h5+cnt81WdUsSAgMD4enpWeM97N69G+PHj0f//v3h4uICPz8/3LhxQ66Pb775Bjdu3EDPnj3Rs2dPBAYGApBfulBYWAhHR0dERkYqjPHhhx9i5MiRss8lJSXYsmULhg0bhj59+mDkyJHYv39/jXGqE2d0iYiI6KVSVlaGpKQkjBgxAlpaWirrd8uWLRg+fDg2b96Mc+fOYevWrSgsLMTFixexaNEilJeX45NPPsGqVavwxRdfNHi8+/fvY8qUKTA3N0dRUREOHDiASZMmIT4+Hqamppg3bx5ycnKQkZGBzz77DABgYmKi0E+bNm0wbNgwHD9+HP7+/rLykpISJCQkwNfXV1a2dOlSXL58GQEBAbC1tcWlS5ewevVq6Ovr15qYqwMTXSIiInqp5ObmQiKRwNzcXKX92tvbY8WKFQCAwYMH49SpU4iOjsb3338vWyZw7949/Pe//0VxcTF0dXUbNF7l7CwAlJeXY/DgwXBzc8O3336LmTNnwtLSEiYmJrh37x769u1bY1+enp6YM2cObty4ARsbGwDA2bNnIRaLZQns5cuXkZCQgMjISLi5uQEAXnvtNeTm5iI0NJSJLhEREbU+Pj4+CmWenp6YMWMGioqK5GYEK02YMAFvvfUWcnJy5GYRK/n6+sLb2xt3797FokWLFOr9/f3xr3/9q17xSqVSAKrf23XIkCFyn62srGBgYCC3FtbKygpSqRQPHjxA165dGzReSkoKPv/8c6SmpiI3N1dWfvPmTaX7GjJkCIyNjREXF4clS5YAAL799lvY2dmhe/fuAIDz58/DyMgIgwcPRllZmeza1157Dfv370dubi6MjY0bdE+qxkSXiIiIXipt27aFjo4O7t27p9J+DQ0N5T5raWlVWQYAEomkQWPdu3cPs2bNgp2dHf7zn//AzMwM2traWLRoEUpKSpTuT0tLCyNHjpQluoWFhTh9+jQWLlwoa5OTk4OnT5/Czs6uyj6ysrKY6BIREVHrcvDgwWrr9PT0aqw3MTGpsd7CwqLG+vrQ1NTEgAEDcPHiRZSWlta4TldbW1vh6FqxWKyyWHR0dABAYYznZ2ircu7cORQWFiIsLAxGRkZ1vq4mnp6e2L9/P1JSUnD79m0UFxfjzTfflNUbGRmhbdu22L59e5XXW1lZ1XvsxsJdF4iIiOilM2vWLDx69Ajh4eFV1p8+fRoA0KlTJ6SlpcnVXbhwQWVxdOrUCQDkDqjIz89HSkpKjdcVFxdDIBBAU/OfOcsffvgBBQUFcu20tLTqPHs8cOBAdOzYEXFxcfj2229lnysNHjwYT548gaamJuzt7RV+9PT06jROU+KMLhEREb10hgwZgvnz5yMsLAxpaWnw9PRE+/btkZWVhW+//RbJycn4+eefMWrUKERFRaFPnz6wtrZGfHw8/v77b5XFYWZmBkdHR2zduhUikQhaWlrYuXNnrS+qubi4AACCgoIwadIk3Lx5E5GRkQq7KvTo0QMHDx7EsWPH0K1bN7Rt2xadO3eusk+BQIA333wT33zzDfLz87Fy5Uq5+tdeew0eHh6YPXs2/Pz88Morr0AikSAjIwO//fYbtmzZUv8H0UiY6BIREdFLacGCBXBwcEB0dDT+85//ID8/H+3bt4ezszN2794NAJgzZw5ycnLwxRdfQCqV4t///jfeeecdrFu3TmVxfPbZZ1i1ahU+/PBDtG3bFnPnzkVSUhKuXr1a7TU9e/ZESEgIwsLCMGfOHNjY2GDjxo1YvXq1XDsfHx/89ttv+OSTT5Cbm4uxY8ciJCSk2n69vLywc+dO2ZrdF23ZsgVRUVHYv38/7ty5A319fXTv3h1eXl71vv/GJJBWvnpI9SaRSHD16lX06dNHttaGGi4pKQn9+/dXdxitCp+p6vGZqhafp+qp8pleu3YNvXr1UklfLVlBQQH09fXVHUaLU92vn8bMo7hGl4iIiIhaJSa6RERERNQqMdElIiIiolaJiS4RERERtUpMdImIiIioVWKiS0REREStEhNdIiIiImqVmOgSERERUavUrBLdW7duYdWqVfD29kbv3r3h6elZZbvExESMHTsW9vb28PDwQExMTJXtoqKiMGzYMLz66qsYN24cLl68qNAmPz8fq1atgrOzMxwdHTFnzhzcuXNHpfdFRERERE2vWSW6N27cQGJiIrp27YoePXpU2SYlJQXz5s1Dr169sH37dowbNw7BwcHYt2+fXLuoqChs3rwZU6ZMwZdffgkrKyv4+/vjzz//lGu3bNky/Pjjj1i5ciU2b96M7OxszJgxA0VFRY12n0RERETU+DTVHcDzhg0bBg8PDwBAYGBglWc8h4WFoXfv3ggODgYAuLi4ICsrC+Hh4XjrrbcgFApRUlKCiIgITJs2DX5+fgAAJycneHl5ISIiAqGhoQCAK1eu4MyZM4iMjISbmxsAwNbWFiNGjMDhw4cxZcqUprhtIiIiamLx8fE4fvw4rl69CrFYDEtLS/j6+sLHxwcCgUDWLjExEVu2bEFaWhrMzMwwffp0jBs3TlafnZ2N3bt34/z588jMzIRIJMKAAQOwdOlSdOnSRW7M/Px8bNiwASdPnkRJSQmcnZ2xYsUKdO7cucZYVT1GXe/9effv38eoUaNQWFiIixcvwsTEpM7PWp2aVaIrFNY8wVxSUoJLly5h2bJlcuWenp44cOAAUlNTYW9vj+TkZOTl5WH06NGyNhoaGhg1ahR27twJqVQKgUCAxMREGBgYYOjQobJ25ubm6NevH86ePctEl4iIqA6KJKWQlJSrZWwdbQ3o6Wgpfd3u3bthYWGBwMBAtG3bFhcuXMCqVauQlZWFhQsXAvjnW2Rvb28sX74cycnJCA4ORkVFBaZPnw4ASE1NRUJCAsaPHw8HBwc8efIEERERmDhxIuLi4tCuXTvZmMuWLUNqaipWrlwJkUiEzz//HDNmzMDx48ehp6dXbayqHqMu9/6i4OBgtGnTBoWFhUo/a3VqVolubTIzM1FaWqqwrMHGxgYAkJGRAXt7e6SnpwOAQjtra2sUFhbiwYMH6NixI9LT09G9e3eFBNva2ho//fRTI94JERFR6yEpKcej3GK1jN3eWLdeiW5ERITcrOSgQYOQm5uLPXv2YP78+RAKhdV+ixwZGQlfX18IhUL0798f8fHx0NT8J6Xq168f3N3dcfToUcyaNQtAw75FVvUYdbn35507dw6XL1/GnDlzEBISovSzVqdmtUa3Nk+fPgUAGBoaypVXfq6sF4vF0NbWhq6urlw7IyMjAEBubq6snYGBgcI4hoaGsr6IiIio9anqq/devXohPz8fEolE9i3ym2++KdfG09MTjx49QmpqKoBnOcPzCSgAdOzYESYmJnj8+LGsrLZvkWui6jFqu/fnlZSUYN26dVi8eLEsj2pJWtSMbqXq1o88X15VG6lUWqd2NZXXpKo1xdQwSUlJ6g6h1eEzVT0+U9Xi81Q9VT1TTU1NFBQUKJQXF5ehqFg9L3EXFwtQIFTNsonLly/D3NwcFRUVSEtLQ2lpKSwsLOTu2cLCAgBw7do1dO/evcp+bt26hcePH6NLly6ya69fv46uXbsqvOzetWtXXLx4scrnWhNVj/H8vT/fbvv27dDR0YGnpyfi4uIAAIWFhdDR0VEqXuBZ0tzUv79bVKJb+S+JF2dbxWIxgH9mdg0NDSGRSCCRSOT+R1S2q+zH0NAQWVlZCuOIxWKFWeO66NOnT73+x1PVkpKS0L9/f3WH0arwmaoen6lq8Xmqniqf6bVr16Cvr69QXlpRDD1dqUrGUJaurg709XVrb1iLX3/9FadOncJ7770HfX19lJSUAABMTU3l7rny7/ni4uIqn4VUKsXGjRvRoUMHeHp6ytoUFBTA2NhY4Zp27dohLy+vyr6qo+oxXrz3Srdv38bu3buxY8cOGBgYyO69TZs2SsVbSVtbGw4ODgrlEomk0SYLW9TSBUtLS2hpaSEjI0OuPC0tDQBk/7KqXJtbuVa3Unp6OvT19WFmZiZrd/PmTdlM7/P9VfevNCIiImpd7t+/jyVLlmDgwIGYMWOGXJ2y3/xu3boVFy9eREhICEQikVJ9SaVSlJWVyX7Ky6ueqW7IGC+q6d4/+eQTeHh4YMCAAVVe2xK0qERXW1sbLi4uiI+PlyuPi4tDhw4dYGdnB+DZAm0DAwOcOHFC1qa8vBzx8fEYOnSo7H+2m5sbxGIxzp07J2uXlZWF5ORkuLq6NsEdERERkTqJxWLMnj0bxsbGCA8Ph4aGBoC6f4v8vAMHDiA8PBxr1qzBkCFD5OoMDQ1l177YX2VfP//8M+zs7GQ/LyaeqhijLvcOAGfPnsWFCxcwZ84ciMViiMVi2ZKIgoKCFrP7QrNaulBUVITExEQAwN27d5Gfn4/vvvsOAGBvbw8LCwsEBARg6tSpWLFiBby8vJCcnIzY2FisWrVK9pagtrY25s6di82bN8PExAS9e/dGbGwsMjMzsXHjRtl4Dg4OcHd3x0cffYTAwECIRCKEhoaiU6dOcnvkERERUetTXFyMd999F3l5edi/f7/cC+rPf4v8/OTXi98iV0pISMDq1auxcOFCTJgwQWGsHj164MKFC7ItTp/vr7IvOzs7HDx4UFb34vIAVYxRl3sHnu1kJZFI5LZqreTh4YHhw4dj27ZtCnXNTbNKdB8/foxFixbJlVV+Xr9+PcaNGwdHR0ds27YNmzZtwpEjR2BqaoqgoCBMnjxZ7rrKgyJiYmLw6NEj2NjYIDIyEq+88opcu40bN2LDhg1Ys2aNbGPl0NDQGvezIyIiopatrKwMixcvRkZGBvbu3Stb1ljp+W+Rn59ZjYuLQ/v27WXfIgPPXuRaunQpJkyYgICAgCrHc3NzQ3h4OM6dOydLnCu/Rf7www8BACKRCPb29lVer6ox6nLvAPDGG2+gV69ecmXnzp3D9u3bER4eDktLyypjaG6aVaLbuXNn/PXXX7W2c3Nzk+0PVxM/Pz9ZwlsdkUiEjz/+GB9//HGd4yQiIqKWbc2aNTh9+jQCAwORn5+PlJQUWZ21tTVEIlG13yIHBgbKvkVOT09HQEAArKys4O3tLdePSCSCtbU1gIZ9i6zqMepy7x07dkTHjh3l4rh79y6AZ0tEeTIaERERUTN1/vx5AKjyAITo6Gg4OztX+y3y+PHjZW2vXLmCvLw85OXlKXy77OTkhJiYGNnn+n6LrOox6nLvrYVA+uKWA6S0ym0xuL2YanGbIdXjM1U9PlPV4vNUPVVvL/bi19lAyzwCuCEKCgrqtb3Wy666Xz+NmUdxRpeIiIgaRE9Hq8mTTaK6aFHbixERERER1RUTXSIiIiJqlZjoEhEREVGrxESXiIiIiFolJrpERERE1Cox0SUiIiKiVomJLhERERG1Skx0iYiIiKhV4oERRERE9NKJj4/H8ePHcfXqVYjFYlhaWsLX1xc+Pj4QCASydomJidiyZQvS0tJgZmaG6dOnY9y4cbL67Oxs7N69G+fPn0dmZiZEIhEGDBiApUuXokuXLrJ2d+7cwfDhwxXisLGxQVxcXI2x1nUMAMjPz8eGDRtw8uRJ2RHAK1asQOfOnZW+dwDYtWsX9u7di/v378PCwgIzZsxQOIa4OWOiS0RERC+d3bt3w8LCAoGBgWjbti0uXLiAVatWISsrCwsXLgQApKSkYN68efD29sby5cuRnJyM4OBgVFRUYPr06QCA1NRUJCQkYPz48XBwcMCTJ08QERGBiRMnIi4uDu3atZMbd+nSpXB2dpZ91tXVrTVWZcZYtmwZUlNTsXLlSohEInz++eeYMWMGjh8/Dj09vTrfOwCEhYUhIiICc+fOhaOjI06fPo3Vq1dDIBBg0qRJ9X/4TYiJLhERETVIQVEJiiTlahlbT0cD+nraSl8XEREBExMT2edBgwYhNzcXe/bswfz58yEUChEWFobevXsjODgYAODi4oKsrCxERkbC19cXQqEQ/fv3R3x8PDQ1/0mp+vXrB3d3dxw9ehSzZs2SG7dr167o27evUrHWdYwrV67gzJkziIyMhJubGwDA1tYWI0aMwOHDhzFlypQ633txcTGioqLg6+uL+fPnAwAGDx6Me/fuYcuWLfDx8ZGLp7lq/hESERFRs1YkKcf1zCdqGdvWsi309ZS/7vlEr1KvXr1w4MABSCQSaGho4NKlS1i2bJlcG09PTxw4cACpqamwt7eHoaGhQj8dO3aEiYkJHj9+rHxgVajrGImJiTAwMMDQoUNlZebm5ujXrx/Onj0rS3Rru3c9PT3cuHEDhYWFGDJkiFy7oUOH4ocffkBKSgoGDBigkvtrTHwZjYiIiAhAUlISLCwsoKenh8zMTJSWlqJHjx5ybWxsbAAAGRkZ1fZz8+ZNPH78GNbW1gp1a9asQe/eveHs7IygoKB6J8NVjZGeno7u3btDKJRP76ytrWuMF5C/dwDQ0NAAAGhpacm109Z+NnuelpZWr7ibGmd0iYiI6KX366+/4sSJE3jvvfcAAE+fPgWgOJta+bmy/kVSqRTr1q1Dhw4dMGLECFm5trY2Jk+ejCFDhsDQ0BCpqan44osvkJKSgm+++aZOa3VrG0MsFsPAwEChvaGhYbXxAor3DgCWlpYQCoX47bff5NYUX7lypcb7b26Y6BIREdFL7f79+1iyZAkGDhyIGTNmyNW9uAtBbeVbt27FxYsXERkZCZFIJCs3NTXF6tWrZZ+dnJxgZ2cHX19fxMXFwcfHB1KpFOXl/6x1FggEspnVuoxRn3iru3eRSARvb2/s2LEDtra26Nu3L86cOYNjx47V2F9zw6ULRERE9NISi8WYPXs2jI2NER4eLkssjYyMACjOXIrFYgBVr5s9cOAAwsPDsWbNGoW1rVVxcnJCu3btkJqaCgD4+eefYWdnJ/t5MemubQxDQ0NZfC/GXFW81d17pcDAQPTp0wf+/v5wcnJCSEgIFi1aBOBZ4t4ScEaXiIiIXkrFxcV49913kZeXh/3798t97W9paQktLS1kZGTA1dVVVl65NrV79+5yfSUkJGD16tVYuHAhJkyYUOcYpFKp7L/t7Oxw8OBB2Wd9fX2lxujRowcuXLgAqVQqN+OalpamEG9N917J2NgYUVFRePDgAZ4+fQorKyv88MMPAAAHB4c636M6cUaXiIiIXjplZWVYvHgxMjIysGPHDpiZmcnVa2trw8XFBfHx8XLlcXFxaN++Pezs7GRlly9fxtKlSzFhwgQEBATUOYZLly4hJycH9vb2AJ4tF7C3t5f9PJ+c1mUMNzc3iMVinDt3TlaWlZWF5ORkuWS9tnt/kZmZGWxtbaGhoYF9+/bByckJ3bp1q/N9qhNndImIiOils2bNGpw+fRqBgYHIz89HSkqKrM7a2hoikQgBAQGYOnUqVqxYAS8vLyQnJyM2NhaBgYGynQ3S09MREBAAKysreHt7y/UjEolkuyKEhIRAIBCgb9++MDQ0xNWrVxEZGQlbW1uMHj26xljrOoaDgwPc3d3x0UcfITAwECKRCKGhoejUqZPcaW51uXcAOHbsGIqLi2FpaYmHDx9i//79uH79Ovbt21efR64WTHSJiIjopXP+/HkAzxLQF0VHR8PZ2RmOjo7Ytm0bNm3ahCNHjsDU1BRBQUEYP368rO2VK1eQl5eHvLw8haNxnZycEBMTA+DZsoJ9+/YhNjYWRUVFMDU1xZgxY7Bw4ULo6OjUGGtdxwCAjRs3YsOGDVizZo3sCODQ0FDZtmF1vfdKu3fvxp07d6CrqwsXFxccOHAAVlZWNcbbnAikzy8OoXqRSCS4evUq+vTpU+svVqq7pKQk9O/fX91htCp8pqrHZ6pafJ6qp8pneu3aNfTq1UuhvCWejNYQBQUFCutnqXbV/fppzDyKM7pERETUIPp62vU6nYyosfFlNCIiIiJqlZjoEhEREVGrxESXiIiIiFolJrpERERE1Cox0SUiIiKiVomJLhERERG1Skx0iYiIiKhVYqJLRERERK0SE10iIiIiapWY6BIREdFLJz4+HvPmzYOrqyv69u2LMWPGIDY2FlKpVK5dYmIixo4dC3t7e3h4eCAmJkauvqysDEuWLMGIESPg4OAAJycnTJ06FefPn1cYMz8/H6tWrYKzszMcHR0xZ84c3Llzp9ZYs7OzsWHDBnh7e8PR0RFDhw7FkiVLcPv27XqNcerUKUyePBnOzs6y+/r000+Rl5dXbQz379+Ho6MjevbsiZycnFpjbi54BDARERE1SF5hCQqLS9UydhtdLRi00Vb6ut27d8PCwgKBgYFo27YtLly4gFWrViErKwsLFy4EAKSkpGDevHnw9vbG8uXLkZycjODgYFRUVGD69OkAgIqKClRUVMDPzw+WlpaQSCQ4ePAgZs+ejejoaAwYMEA25rJly5CamoqVK1dCJBLh888/x4wZM3D8+HHo6VV/hnJqaioSEhIwfvx4ODg44MmTJ4iIiMDEiRMRFxeHdu3aKTXG06dPMXDgQMycORNGRka4fv06wsLC8Ndff2Hnzp1VxhAcHIw2bdqgsLBQ6WetTkx0iYiIqEEKi0tx6ep9tYzt0qdjvRLdiIgImJiYyD4PGjQIubm52LNnD+bPnw+hUIiwsDD07t0bwcHBz8ZycUFWVhYiIyPh6+sLoVAIbW1thIaGyvXt6uqK4cOH4+jRo7JE98qVKzhz5gwiIyPh5uYGALC1tcWIESNw+PBhTJkypdpY+/fvj/j4eGhq/pO29evXD+7u7jh69ChmzZql1BgTJkyQ69/Z2Rk6OjpYuXIlHjx4ADMzM7n6c+fO4fLly5gzZw5CQkLq/pCbAS5dICIiopfO80lupV69eiE/Px8SiQQlJSW4dOkS3nzzTbk2np6eePToEVJTU6vtW0NDAwYGBigrK5OVJSYmwsDAAEOHDpWVmZubo1+/fjh79myNsRoaGsoluQDQsWNHmJiY4PHjxyoZw9jYGADkYgaAkpISrFu3DosXL4aRkVGNfTRHTHSJiIiIACQlJcHCwgJ6enrIzMxEaWkpevToIdfGxsYGAJCRkSFXLpVKUVZWhpycHERFReHWrVuYOHGirD49PR3du3eHUCifellbWyv0VRc3b97E48ePYW1tXe8xysvLIZFIcPXqVYSHh+P111+HhYWFXJvt27dDT08Pb731ltIxNgdcukBEREQvvV9//RUnTpzAe++9B+DZOlbg2Wzq8yo/V9ZX2rNnD9avXw8AaNOmDTZv3gxHR0dZvVgshoGBgcK4hoaGCn3VRiqVYt26dejQoQNGjBhR7zGcnZ1lL6ANHToUmzZtkqu/ffs2tm/fjh07digkzy0FE10iIiJ6qd2/fx9LlizBwIEDMWPGDLk6gUBQ5TUvlnt5eaF///7IycnBd999h8WLFyMsLEy2VrYufUmlUpSXl8uVa2hoKLTfunUrLl68iMjISIhEonrFCwAxMTEoKirCjRs3EBERgTlz5mDXrl2yMT/55BN4eHjIvVDX0jDRJSIiopeWWCzG7NmzYWxsjPDwcFmSV7ke9cWZULFYDEBxprddu3ay3Q/c3Nzw5MkT/Pe//5UluoaGhsjKyqpy/Mq+fv75Z0ybNk1W5+TkpLCd2YEDBxAeHo5169ZhyJAhcnV1GeN5vXr1AvDsxTY7OzuMHz8eCQkJeOONN3D27FlcuHABhw8flt1zUVERAKCgoAC6urpo06aNQp/NDRNdIiIieikVFxfj3XffRV5eHvbv3y/3tb+lpSW0tLSQkZEBV1dXWXlaWhoAoHv37jX2bWdnJ7eXbo8ePXDhwgVIpVK52dW0tDRZX3Z2djh48KCsTl9fX67PhIQErF69GgsXLlTYOaGuY1SnV69eEAqFyMzMBPBsDbJEIsHo0aMV2np4eGD48OHYtm1bjX02By1zwQURERFRA5SVlWHx4sXIyMjAjh07FLbU0tbWhouLC+Lj4+XK4+Li0L59e9jZ2dXY/6+//oouXbrIPru5uUEsFuPcuXOysqysLCQnJ8sSaZFIBHt7e9nP88np5cuXsXTpUkyYMAEBAQFVjlmXMaqTnJyMiooKdO7cGQDwxhtvIDo6Wu5n9uzZAIDw8HAsXry4xv6aC87oEhER0UtnzZo1OH36NAIDA5Gfn4+UlBRZnbW1NUQiEQICAjB16lSsWLECXl5eSE5ORmxsLAIDA2UvZ8XFxeHMmTNwdXWFmZkZnjx5gqNHj+LSpUtyL3c5ODjA3d0dH330EQIDAyESiRAaGopOnTph3LhxNcaanp6OgIAAWFlZwdvbWy5WkUgk23mhrmP4+fnBxcUFNjY20NbWxh9//IGoqCj07NkTHh4eAJ5tX9axY0e5OO7evQvg2VKHqrZna46Y6BIREdFLp3JZQVUHIERHR8uO0N22bRs2bdqEI0eOwNTUFEFBQRg/frysbffu3REXF4cNGzYgNzcXJiYm6NmzJ7766isMHDhQrt+NGzdiw4YNWLNmDUpKSuDs7IzQ0NAaT0UDnh0EkZeXh7y8PEyePFmu7sV1vHUZ49VXX8WxY8dkRwN37twZb7/9NmbOnAltbeUP32jOBNIXD3UmpVXuQdenTx/o6OioO5xWIykpCf3791d3GK0Kn6nq8ZmqFp+n6qnymV67dk32AtPzWuIRwA1RUFCgsH6Walfdr5/GzKM4o0tEREQNYtBGu8mTTaK64MtoRERERNQqMdElIiIiolaJiS4RERERtUpMdImIiIioVWKiS0REREStEhNdIiIiImqVmOgSERERUavERJeIiIiIWiUmukRERETUKvFkNCIiInrpxMfH4/jx47h69SrEYjEsLS3h6+sLHx8fCAQCWbvExERs2bIFaWlpMDMzw/Tp0zFu3DhZfVlZGd5//31cvXoV2dnZ0NHRga2tLebOnYvBgwfL2t25cwfDhw9XiMPGxgZxcXE1xpqdnY3du3fj/PnzyMzMhEgkwoABA7B06VJ06dJFrm1+fj42bNiAkydPoqSkBM7OzlixYgU6d+4sa3Pq1Cns2rULGRkZKCwshJmZGUaMGIF58+bBwMBArr9du3Zh7969uH//PiwsLDBjxgxMnjy5bg+5GWCiS0RERA0iLpCgSFKmlrH1dDRhqK+j9HW7d++GhYUFAgMD0bZtW1y4cAGrVq1CVlYWFi5cCABISUnBvHnz4O3tjeXLlyM5ORnBwcGoqKjA9OnTAQAVFRWoqKiAn58fLC0tIZFIcPDgQcyePRvR0dEYMGCA3LhLly6Fs7Oz7LOurm6tsaampiIhIQHjx4+Hg4MDnjx5goiICEycOBFxcXFo166drO2yZcuQmpqKlStXQiQS4fPPP8eMGTNw/Phx6OnpAQCePn2KgQMHYubMmTAyMsL169cRFhaGv/76Czt37pT1FRYWhoiICMydOxeOjo44ffo0Vq9eDYFAgEmTJin9zNWBiS4RERE1SJGkDMfOZahl7DFDu9cr0Y2IiICJiYns86BBg5Cbm4s9e/Zg/vz5EAqFCAsLQ+/evREcHAwAcHFxQVZWFiIjI+Hr6wuhUAhtbW2EhobK9e3q6orhw4fj6NGjColu165d0bdvX6Vi7d+/P+Lj46Gp+U/a1q9fP7i7u+Po0aOYNWsWAODKlSs4c+YMIiMj4ebmBgCwtbXFiBEjcPjwYUyZMgUAMGHCBLn+nZ2doaOjg5UrV+LBgwcwMzNDcXExoqKi4Ovri/nz5wMABg8ejHv37mHLli3w8fGRi6e54hpdIiIieuk8n+RW6tWrF/Lz8yGRSFBSUoJLly7hzTfflGvj6emJR48eITU1tdq+NTQ0YGBggLIy1cxyGxoaKiSVHTt2hImJCR4/fiwrS0xMhIGBAYYOHSorMzc3R79+/XD27NkaxzA2NgYAWcw3btxAYWEhhgwZItdu6NChePLkCVJSUhpwR02HiS4RERERgKSkJFhYWEBPTw+ZmZkoLS1Fjx495NrY2NgAADIy5GewpVIpysrKkJOTg6ioKNy6dQsTJ05UGGPNmjXo3bs3nJ2dERQUJJeoKuPmzZt4/PgxrK2tZWXp6eno3r07hEL59M7a2lohXgAoLy+HRCLB1atXER4ejtdffx0WFhYAniXrAKClpSV3jba2NgAgLS2tXnE3teY/50xERETUyH799VecOHEC7733HoBn61iBZ7Opz6v8XFlfac+ePVi/fj0AoE2bNti8eTMcHR1l9dra2pg8eTKGDBkCQ0NDpKam4osvvkBKSgq++eabOq3VrSSVSrFu3Tp06NABI0aMkJWLxWKFl8kqY34xXuDZkoW8vDwAz2ZqN23aJKuztLSEUCjEb7/9Jrem+MqVK1Xef3PFRJeIiIheavfv38eSJUswcOBAzJgxQ67u+R0Yair38vJC//79kZOTg++++w6LFy9GWFiYbK2sqakpVq9eLWvv5OQEOzs7+Pr6Ii4uDj4+PpBKpSgvL5cbo3Jm9Xlbt27FxYsXERkZCZFIVK94ASAmJgZFRUW4ceMGIiIiMGfOHOzatQsaGhoQiUTw9vbGjh07YGtri759++LMmTM4duxYjeM0N0x0iYiI6KUlFosxe/ZsGBsbIzw8XJZYGhkZAVCcuRSLxQAUZ3rbtWsn2/3Azc0NT548wX//+19ZolsVJycntGvXDqmpqfDx8cHPP/+MadOmydXHxMTIXXPgwAGEh4dj3bp1CutnDQ0NkZWVVeU9vhgv8GxNMvDsxTY7OzuMHz8eCQkJeOONNwAAgYGBePjwIfz9/QE8W9e8aNEihISEwNTUtNr7ak6Y6BIREdFLqbi4GO+++y7y8vKwf/9+ua/9LS0toaWlhYyMDLi6usrKK9emdu/evca+7ezscP78+VpjkEqlctccPHhQ9llfX1+ubUJCAlavXo2FCxcq7JwAAD169MCFCxcglUrlZlzT0tJqjbdXr14QCoXIzMyUlRkbGyMqKgoPHjzA06dPYWVlhR9++AEA4ODgUOu9NQd8GY2IiIheOmVlZVi8eDEyMjKwY8cOmJmZydVra2vDxcUF8fHxcuVxcXFo37497Ozsauz/119/VTjM4UWXLl1CTk4O7O3tAQAikQj29vayn+eT08uXL2Pp0qWYMGECAgICquzPzc0NYrEY586dk5VlZWUhOTlZLlmvSnJyMioqKuQOlqhkZmYGW1tbaGhoYN++fXByckK3bt1q7K+54IwuERERvXTWrFmD06dPIzAwEPn5+XLbZVlbW0MkEiEgIABTp07FihUr4OXlheTkZMTGxiIwMFC2s0FcXBzOnDkDV1dXmJmZ4cmTJzh69CguXbok93JXSEgIBAIB+vbtC0NDQ1y9ehWRkZGwtbXF6NGja4w1PT0dAQEBsLKygre3t1ysIpFItvOCg4MD3N3d8dFHHyEwMBAikQihoaHo1KmT3Glufn5+cHFxgY2NDbS1tfHHH38gKioKPXv2hIeHh6zdsWPHUFxcDEtLSzx8+BD79+/H9evXsW/fvoY8+ibFRJeIiIheOpXLCkJCQhTqoqOj4ezsDEdHR2zbtg2bNm3CkSNHYGpqiqCgIIwfP17Wtnv37oiLi8OGDRuQm5sLExMT9OzZE1999RUGDhwoa9ejRw/s27cPsbGxKCoqgqmpKcaMGYOFCxdCR6fmAy+uXLmCvLw85OXlKRy/++I63o0bN2LDhg1Ys2aN7Ajg0NBQ2aloAPDqq6/i2LFjuHPnDgCgc+fOePvttzFz5kzZ9mGVdu/ejTt37kBXVxcuLi44cOAArKysanm6zYdA+vzikBbi+++/x5dffon09HTo6emhX79+WLZsmcKDr+p8al9fX4X+oqKisHfvXjx69AjW1tZ4//33MWjQoDrHU7kHXZ8+fWr9xUp1l5SUhP79+6s7jFaFz1T1+ExVi89T9VT5TK9duyZ7gel5LfEI4IYoKChQWD9Ltavu109j5lEtbkb34sWLmD9/PsaMGYPFixdDLBYjLCwMM2fOxPHjx2XbbFR3PrWmpqbcv4aioqKwefNmLFmyBL1790ZsbCz8/f0RGxuLV155RV23SURE1GIY6us0ebJJVBctLtGNi4uDubk5Pv30U9kbhRYWFpgwYQKSkpJk23hUdz51eHg43nrrLQiFQpSUlCAiIgLTpk2Dn58fgGdfAXh5eSEiIkLh7GoiIiIiajla3K4LZWVl0NfXl9s248VTQGo6n/rhw4ey86mTk5ORl5cntwhcQ0MDo0aNwtmzZ9ECV3UQERER0f/X4hJdHx8fZGRkICYmBmKxGHfu3MGnn36KHj16yNbV1vV86vT0dABQaGdtbY3CwkI8ePCgsW+HiIiIiBpJi0t0Bw4ciLCwMGzevBkDBw7E8OHDcffuXezatUv2pmBdz6cWi8XQ1tZWOF+68jSU3NzcxrwVIiIiImpELW6NbnJyMt5//334+Phg2LBhyM3NxbZt2zB37lx8/fXXcklrXc57rqpN5ZIFZc9xvnr1qlLtqXZJSUnqDqHV4TNVPT5T1eLzVD1VPVNNTU0UFBSopK+Wjs9BeSUlJU3++7vFJbrr1q2Di4sLPvzwQ1lZ37594e7ujqNHj+Ktt96q8/nUhoaGkEgkkEgkcttZVLar7KeuuL2YanGbIdXjM1U9PlPV4vNUPVVvL8Zttbi9WH1pa2tXeXRw5fZijaHFLV1IT09X2ParY8eOaNu2rex85ufPp37ei+dTV67NrVyr+/wY+vr6CscBEhEREVHL0eISXXNzc9muCZXu3r2LJ0+ewMLCAkDN51N36NBBdj51v379YGBggBMnTsjalJeXIz4+HkOHDlV66QIRERERNR8tbunClClTsHbtWqxduxbDhw9Hbm4uIiIiYGJiglGjRsnaVXc+9apVq2TnU2tra2Pu3LnYvHkzTExMZAdGZGZmYuPGjeq6RSIiIiJSgRaZ6GppaeHrr7/G4cOHoa+vDwcHB2zZsgVt27aVtavufOoXz4iuPCgiJiYGjx49go2NDSIjI3kqGhERUSsWHx+P48eP4+rVqxCLxbC0tISvry98fHzkvtFNTEzEli1bkJaWBjMzM0yfPh3jxo2rtt9Tp05hwYIFsLGxQVxcnFxdfn4+NmzYgJMnT6KkpATOzs5YsWIFOnfuXGOs2dnZ2L17N86fP4/MzEyIRCIMGDAAS5cuRZcuXRo0Rnl5OXx8fPDHH38gNDQUb7zxRpXt7t+/j1GjRqGwsBAXL16EiYlJjTE3Fy0u0RUIBHjrrbfw1ltv1drWzc1NdlJaTfz8/GQJLxERESknr7AEkpJytYyto60BgzbaSl+3e/duWFhYIDAwEG3btsWFCxewatUqZGVlYeHChQCAlJQUzJs3D97e3li+fDmSk5MRHByMiooKTJ8+XaHPoqIirF+/Hu3bt69yzGXLliE1NRUrV66ESCTC559/jhkzZuD48ePQ09OrNtbU1FQkJCRg/PjxcHBwwJMnTxAREYGJEyciLi4O7dq1q/cY+/btQ3Z2dq3PKzg4GG3atEFhYWGtbZuTFpfoEhERUfMiKSlH5JHf1TK2/7/tYdBG+esqlz1WGjRoEHJzc7Fnzx7Mnz8fQqEQYWFh6N27N4KDgwEALi4uyMrKQmRkJHx9fWVLIStt27YNnTt3hoWFhcIuAleuXMGZM2cQGRkpm4SztbXFiBEjcPjwYUyZMqXaWPv374/4+Hhoav6TtvXr10+249SsWbPqNcajR48QGhqKoKAgBAUFVTv+uXPncPnyZcyZMwchISHVtmuOWtzLaEREREQNVdVX77169UJ+fj4kEglKSkpw6dIlvPnmm3JtPD098ejRI4UX49PT0xETE4OVK1dWOV5iYiIMDAwwdOhQWZm5uTn69euHs2fP1hiroaGhXJILPNtxysTEBI8fP673GBs2bMCQIUPg5ORU7dglJSVYt24dFi9erPS2q81BgxLdgoKCFjeFTURERFSVpKQkWFhYQE9PD5mZmSgtLZVtRVrJxsYGABS2MF27di18fHxga2tbZd/p6eno3r27wiywtbW1Ql91cfPmTTx+/BjW1tb1GuOXX35BQkICPvjggxrH2b59O/T09Oq0ZLQ5UmrpwsWLF/H9998jKSkJGRkZKC0tBQBoaWmhR48ecHR0xIgRIzBo0KBGCZaIiIioMfz66684ceIE3nvvPQD/HDpVechUpcrPzx9K9e233+Kvv/7C559/Xm3/YrEYBgYGCuWGhoYKB1zVRiqVYt26dejQoQNGjBih9BhlZWX4+OOP4e/vj06dOuHOnTtVjnP79m1s374dO3bsUEieW4paE93S0lLs378fO3fuxL1792BoaAg7Ozv8+9//hpGREaRSKcRiMTIzM3H8+HF8/fXX6NSpE2bNmoVJkyZBS0urKe6DiIiIqF7u37+PJUuWYODAgZgxY4ZcXXV76leW5+fnIyQkBEuXLlVIiqu7prpyqVSK8vJyuXINDQ2F9lu3bsXFixcRGRkJkUik1BgAEB0djeLi4lpfxP/kk0/g4eGBAQMG1NiuOas10f3Xv/4FiUQCb29vvPnmm7C3t6+x/ZUrV/Ddd98hIiICO3fuxOnTp1UWLBEREZEqicVizJ49G8bGxggPD5cllpXrUV+cbRWLxQD+mdn94osvYGxsjBEjRsjqSktLUVFRAbFYDF1dXWhra8PQ0BBZWVlVjl/Z188//4xp06bJ6pycnBATEyPX/sCBAwgPD8e6deswZMgQubq6jJGTk4OtW7fiP//5D4qLi1FcXIz8/HwAQHFxMfLy8mBgYICzZ8/iwoULOHz4sOy+ioqKADxbuqqrq4s2berxFmATqzXRfeedd+Dj4wMdHZ06dejg4AAHBwcsXrwYBw8ebHCARERERI2huLgY7777LvLy8rB//365r/0tLS2hpaWFjIwMuLq6ysrT0tIAAN27dwfwbK3u9evX4ezsrND/wIEDERQUhBkzZqBHjx64cOECpFKp3OxqWlqarC87Ozu53ElfX1+uv4SEBKxevRoLFy7EhAkTFMaryxgPHjxAYWEhli9frnD98uXLYWBggF9//RUZGRmQSCQYPXq0QjsPDw8MHz4c27ZtU6hrbmpNdGva7qImOjo69b6WiIiIqDGVlZVh8eLFyMjIwN69e2FmZiZXr62tDRcXF8THx8stZ4iLi0P79u1hZ2cHAFi8eLHCnrqRkZG4efMm1q9fj65duwJ4trd/eHg4zp07J0ucs7KykJycjA8//BAAIBKJqv3m/PLly1i6dCkmTJiAgICAKtvUZQxLS0tER0fLXffo0SMsXboUCxYsgIuLCwDgjTfeQK9eveTanTt3Dtu3b0d4eDgsLS2rjKG54T66RERE9NJZs2YNTp8+jcDAQOTn5yMlJUVWZ21tDZFIhICAAEydOhUrVqyAl5cXkpOTERsbi8DAQNnLWVXtsvDNN9/gwYMHcrO8Dg4OcHd3x0cffYTAwECIRCKEhoaiU6dONZ60BjzbTSEgIABWVlbw9vaWi1UkEsl2XqjLGPr6+gqzz5Uvo1lbW8vW43bs2BEdO3aUa3f37l0Az/bwfalORpNIJPj777/RpUsXhfUacXFx8PT0VMUwRERE1AzpaGvA/981v8PTmGPXx/nz5wGgygMQoqOj4ezsDEdHR2zbtg2bNm3CkSNHYGpqiqCgIIwfP75eY27cuBEbNmzAmjVrZMfzhoaG1ngqGvDs/ae8vDzk5eVh8uTJcnUvruOt7xitlUAqlUob0kFKSgrmzJkDqVQKiUSCefPmwd/fX1bfr18/JCcnNzjQ5kwikeDq1avo06dPndcyU+2SkpLQv39/dYfRqvCZqh6fqWrxeaqeKp/ptWvXFL7OfhkVFBQorJ+l2lX366cx86gGb4oWEhKCwMBAXL58GYcOHcKpU6cQFBSEiooKAM+2yiAiIiIiamoNTnTT0tLw73//G8Czt/2++uorPHz4EAsXLkRJSUlDuyciIiIiqpcGJ7oGBgZ48OCB7LOuri4iIiKgoaGBd955hzO6RERERKQWDU50Bw0ahEOHDsmVaWlpYfPmzejcuTOKi4sbOgQRERERkdIavOvC6tWr5Y6rqyQUChEcHIz58+c3dAgiIiIiIqXVK9G9ffs20tPTkZ+fD319fVhbW6NLly5VtjU3N29QgERERERE9aFUonvy5Els3boV6enpCnXW1taYP38+Ro4cqbLgiIiIiIjqq86J7ubNmxEZGQmRSARvb2+88sor0NfXR0FBAf7880/8+OOPWLx4Mfz9/bFkyZLGjJmIiIiIqFZ1SnTPnTuHL7/8Ev/617/wySefwMDAQKFNfn4+VqxYgcjISAwcOBBDhgxRebBERERERHVVp10XYmJi0LNnT2zZsqXKJBd4dtbypk2bYGtriz179qg0SCIiIiJVio+Px7x58+Dq6oq+fftizJgxiI2NVdgWNTExEWPHjoW9vT08PDzkjtutyqlTp9CzZ094enrKld+5cwc9e/ZU+HmxXVWys7OxYcMGeHt7w9HREUOHDsWSJUtw+/Zthbb5+flYtWqV7AjjOXPm4M6dO9X2XV5ejrFjx6Jnz5747rvvFOp37doFDw8P9OnTByNHjsS+fftqjbc5qdOM7m+//YZ33nkHQmHNebFQKISXlxd27NihkuCIiIio+SsoKkVZeYVaxtbUEEJfT0vp63bv3g0LCwsEBgaibdu2uHDhAlatWoWsrCwsXLgQAJCSkoJ58+bB29sby5cvR3JyMoKDg1FRUYHp06cr9FlUVIT169ejffv21Y67dOlSODs7yz7r6urWGmtqaioSEhIwfvx4ODg44MmTJ4iIiMDEiRMRFxeHdu3aydouW7YMqampWLlyJUQiET7//HPMmDEDx48fh56enkLf+/btQ3Z2dpXjhoWFISIiAnPnzoWjoyNOnz6N1atXQyAQYNKkSbXG3RzUKdEtLCxE27Zt69ShsbExCgsLGxQUERERtRxl5RVYvf2iWsZePXtQva6LiIiAiYmJ7POgQYOQm5uLPXv2YP78+RAKhQgLC0Pv3r0RHBwMAHBxcUFWVhYiIyPh6+urMAG4bds2dO7cGRYWFrh69WqV43bt2hV9+/ZVKtb+/fsjPj4empr/pG39+vWDu7s7jh49ilmzZgEArly5gjNnziAyMhJubm4AAFtbW4wYMQKHDx/GlClT5Pp99OgRQkNDERQUhKCgILm64uJiREVFwdfXV7ZV7ODBg3Hv3j1s2bIFPj4+cvE0V3VaumBmZobr16/XqcPr16/D1NS0QUERERERNabnk9xKvXr1Qn5+PiQSCUpKSnDp0iW8+eabcm08PT3x6NEjpKamypWnp6cjJiYGK1euVHmshoaGCkllx44dYWJigsePH8vKEhMTYWBggKFDh8rKzM3N0a9fP5w9e1ah3w0bNmDIkCFwcnJSqLtx4wYKCwsV3rkaOnQonjx5gpSUlAbeVdOoU6I7dOhQxMbG4tatWzW2u3XrFg4ePCj7VwQRERFRS5GUlAQLCwvo6ekhMzMTpaWl6NGjh1wbGxsbAEBGRoZc+dq1a+Hj4wNbW9sax1izZg169+4NZ2dnBAUFySWqyrh58yYeP34Ma2trWVl6ejq6d++uMNNsbW2tEO8vv/yChIQEfPDBB1X2r6GhAeDZabfP09bWBgCkpaXVK+6mVqdE991334WmpibefvttHDlyBCUlJXL1JSUlOHLkCKZMmQJNTU34+/s3SrBEREREjeHXX3/FiRMnZF/vP336FMCz2dTnVX6urAeAb7/9Fn/99ZdsbW9VtLW1MXnyZKxduxa7d+/GnDlz8OOPP2Lq1KkoLi5WKlapVIp169ahQ4cOGDFihKxcLBZXuWmAoaGhXLxlZWX4+OOP4e/vj06dOlU5hqWlJYRCIX777Te58itXrgCQv//mrE6LK8zMzBAZGYkFCxYgKCgI//nPf9CtWzeIRCLk5+fj5s2bKCkpQbt27fDll1/CzMysseMmIiIiUon79+9jyZIlGDhwIGbMmCFXJxAIqrymsjw/Px8hISFYunSpQlL8PFNTU6xevVr22cnJCXZ2dvD19UVcXBx8fHwglUpRXl4uN0blzOrztm7diosXL8rON1AmXgCIjo5GcXEx/Pz8qo238tyEHTt2wNbWFn379sWZM2dw7NixGsdpbuq8irhv3744ceIE9u3bh9OnTyM9PR0FBQXQ19dHr169MGzYMEyaNKnG/8lEREREzYlYLMbs2bNhbGyM8PBwWWJpZGQEQHHmUiwWA/hnZveLL76AsbExRowYIasrLS1FRUUFxGIxdHV1ZV/3v8jJyQnt2rVDamoqfHx88PPPP2PatGly9S9uZ3bgwAGEh4dj3bp1CutnDQ0NkZWVVeU9Vsabk5ODrVu34j//+Q+Ki4tRXFyM/Px8AM9eQMvLy5PNCgcGBuLhw4eyb+pNTEywaNEihISEtJj3sZR6Xc7AwAD+/v5cmkBEREQtXnFxMd59913k5eVh//79cl/7W1paQktLCxkZGXB1dZWVV65N7d69O4Bna3WvX78ut2VYpYEDByIoKEhhlvh5z+/ba2dnh4MHD8o+6+vry7VNSEjA6tWrsXDhQkyYMEGhrx49euDChQuQSqVyM65paWmyeB88eIDCwkIsX75c4frly5fDwMAAv/76K4BnO2lFRUXhwYMHePr0KaysrPDDDz8AABwcHKq9p+ak+e8LQURERKRiZWVlWLx4MTIyMrB3716FZZfa2tpwcXFBfHy8XKIaFxeH9u3bw87ODgCwePFihT11IyMjcfPmTaxfvx5du3atNoZLly4hJycH9vb2AJ4tF6j87xddvnwZS5cuxYQJExAQEFBlGzc3N4SHh+PcuXOy5DwrKwvJycn48MMPATxL4KOjo+Wue/ToEZYuXYoFCxbAxcVFoV8zMzOYmZmhvLwc+/btg5OTE7p161btfTUndUp0Hz58CF9fX4wcORJLliyptt3mzZtx6tQp7N27t8ptO4iIiIiagzVr1uD06dMIDAxEfn6+3HZZ1tbWEIlECAgIwNSpU7FixQp4eXkhOTkZsbGxCAwMlO1sUNUuC9988w0ePHggN8sbEhICgUCAvn37wtDQEFevXkVkZCRsbW0xevToGmNNT09HQEAArKys4O3tLRerSCSS7bzg4OAAd3d3fPTRRwgMDIRIJEJoaCg6deqEcePGAXg2S/zi7HPlyWnW1tYYMGCArPzYsWMoLi6GpaUlHj58iP379+P69est6nS0OiW60dHRyM3NxezZs2tsN3v2bOzfvx8xMTFYtGiRSgIkIiIiUrXz588DeJaAvig6Olp2hO62bduwadMmHDlyBKampggKCsL48eOVHq9Hjx7Yt28fYmNjUVRUBFNTU4wZMwYLFy6Ejo5OjddeuXIFeXl5yMvLw+TJk+XqXlzHu3HjRmzYsAFr1qxBSUkJnJ2dERoaWuWpaHWxe/du3LlzB7q6unBxccGBAwdgZWVVr77UQSB98VDnKowZMwYDBw6s0ybI69atwy+//IKjR4+qJMCWQCKR4OrVq+jTp0+tv1ip7pKSktC/f391h9Gq8JmqHp+pavF5qp4qn+m1a9fQq1cvhfKWeARwQ1S+jE/Kqe7XT2PmUXWa0c3MzMTUqVPr1KGtra3cQmoiIiJq3Zo60SSqqzodGCEQCFBRUbd/qVVUVLSYvdWIiIiIqPWqU6JrYWGhcDJGdX7//XdYWFg0KCgiIiIiooaqU6Lr7u6Ob7/9Funp6TW2S09PR1xcHF5//XWVBEdEREREVF91SnRnzZqFNm3aYPr06YiLi0NZWZlcfVlZGeLi4jB9+nSIRCLMnDmzUYIlIiIiIqqrOr2MZmJigsjISAQEBOD999/HihUr0K1bN+jr66OgoAA3b96ERCKBqakpwsPDuYcuEREREaldnU9Gs7e3x7fffot9+/bh9OnTyMjIQH5+PkQiEXr16oVhw4Zh0qRJcsfnERERERGpi1JHABsYGMDf3x/+/v6NFQ8RERERkUrUaY0uEREREVFLw0SXiIiIiFolJrpERET00omPj8e8efPg6uqKvn37YsyYMYiNjYVUKpVrl5iYiLFjx8Le3h4eHh6IiYlR6GvYsGHo2bOnwk9OTo5cu/z8fKxatQrOzs5wdHTEnDlzcOfOnVpjzc7OxoYNG+Dt7Q1HR0cMHToUS5Yswe3btxXa1mWMw4cPVxnvxx9/XG0M9+/fh6OjY5X31ZwptUaXiIiI6EVFkjII1XQoaoUU0NNRPp3ZvXs3LCwsEBgYiLZt2+LChQtYtWoVsrKysHDhQgBASkoK5s2bB29vbyxfvhzJyckIDg5GRUUFpk+fLtffyJEjMWvWLLkyQ0NDuc/Lli1DamoqVq5cCZFIhM8//xwzZszA8ePHoaenV22sqampSEhIwPjx4+Hg4IAnT54gIiICEydORFxcHNq1a1evMXbs2CG3iUD79u2rjSE4OBht2rRBYWFhtW2aIya6RERE1CBCATBrXYJaxt65YkS9rouIiJDbDnXQoEHIzc3Fnj17MH/+fAiFQoSFhaF3794IDg4GALi4uCArKwuRkZHw9fWFUPjPF+Pt27dH3759qx3vypUrOHPmDCIjI+Hm5gYAsLW1xYgRI3D48GFMmTKl2mv79++P+Ph4aGr+k7b169cP7u7uOHr0qCzBVnYMOzu7Om0Je+7cOVy+fBlz5sxBSEhIre2bk3ovXbh37x6OHDmCnTt3IisrC8CzgyMeP36scKAEERERUXNSVYLXq1cv5OfnQyKRoKSkBJcuXcKbb74p18bT0xOPHj1CamqqUuMlJibCwMAAQ4cOlZWZm5ujX79+OHv2bI3XGhoayiW5ANCxY0eYmJjg8ePHKhmjOiUlJVi3bh0WL14MIyOjevWhTvVKdNevX48RI0YgMDAQ//3vf/H3338DAIqLizFixAh89dVXqoyRiIiIqNElJSXBwsICenp6yMzMRGlpKXr06CHXxsbGBgCQkZEhV378+HHY29ujb9++8PPzU0iE09PT0b17d7lZYACwtrZW6Ksubt68icePH8Pa2rreY3h5ecnOQggLC6tyonL79u3Q09PDW2+9pXSMzYHSSxd27NiBPXv2wM/PD0OGDJE77lckEmHEiBFISEjAjBkzVBknERERUaP59ddfceLECbz33nsAgKdPnwJQXGdb+bmyHnj2Mtqrr74Kc3Nz3L17F5GRkZgyZQoOHjwoS0TFYnGVh2oZGhrK9VUXUqkU69atQ4cOHTBixD9LN+o6RocOHbBgwQK8+uqr0NDQwNmzZ7Ft2zbcuXNHbmnC7du3sX37duzYsUMheW4plE50Y2NjMWbMGLz//vt48uSJQr2trS1++uknlQRHRERE1Nju37+PJUuWYODAgQoTdQJB1W/ZPV++YsUK2X8PGDAArq6uGDVqFCIjI7Fhw4Y69yWVSlFeXi5XrqGhodB+69atuHjxIiIjIyESiZSOd+jQoXLLGwYPHgwDAwNs3boV8+bNg6WlJQDgk08+gYeHBwYMGFBlny2B0un5vXv3arxhkUgEsVjcoKCIiIiImoJYLMbs2bNhbGyM8PBwWWJZuR71xdnWyhznxZne57Vt2xYuLi5yyxcMDQ2rzI/EYrGsr59//hl2dnayn6q+HT9w4ADCw8OxZs0aDBkyRK6uLmNUZ9SoUQAgi/ns2bO4cOEC5syZA7FYDLFYjKKiIgBAQUFBi9l9QekZXWNjY2RnZ1dbf/36dZiZmTUoKCIiIqLGVlxcjHfffRd5eXnYv3+/3Nf+lpaW0NLSQkZGBlxdXWXlaWlpAIDu3bvX2PeL+/H26NEDFy5cgFQqlZtdTUtLk/VlZ2eHgwcPyur09fXl+khISMDq1auxcOFCTJgwQWHMuoxR13gzMjIgkUgwevRohbYeHh4YPnw4tm3bVmOfzYHSM7ru7u44cOBAlZsF//HHHzh48CA8PDxUEhwRERFRYygrK8PixYuRkZGBHTt2KEzSaWtrw8XFBfHx8XLlcXFxaN++Pezs7KrtOycnB5cuXYK9vb2szM3NDWKxGOfOnZOVZWVlITk5WZZIi0Qi2Nvby36eT04vX76MpUuXYsKECQgICKhy3LqMUZ0TJ05AIBCgT58+AIA33ngD0dHRcj+zZ88GAISHh2Px4sU19tdcKD2ju3DhQvz0008YM2YM3N3dIRAIcOjQIRw4cAAJCQmwsLDA3LlzGyNWIiIiIpVYs2YNTp8+jcDAQOTn5yMlJUVWZ21tDZFIhICAAEydOhUrVqyAl5cXkpOTERsbi8DAQNnLWXFxcTh9+jRcXV1hZmaGu3fvYvv27SgpKZElhgDg4OAAd3d3fPTRRwgMDIRIJEJoaCg6deqEcePG1Rhreno6AgICYGVlBW9vb7lYRSKR7IW3uo7h5+cHZ2dn2NraQiAQ4Ny5c/j666/h4+ODLl26AHi2fVnHjh3l4rh79y6AZ3v41mX/3eZA6US3Q4cOOHToEDZv3oxTp05BKpUiLi4OIpEI3t7eWLZsWYvcZ42IiIheHufPnweAKg9AiI6Olh2hu23bNmzatAlHjhyBqakpgoKCMH78eFnbzp07Izs7GyEhIRCLxRCJRHBycsLnn3+usDXZxo0bsWHDBqxZswYlJSVwdnZGaGhojaeiAc8OgsjLy0NeXh4mT54sV+fk5CR3LHFdxujevTsOHTqEBw8eoKysDFZWVnjvvfcUTntrDQTSFxdlKCknJwcVFRUwMTFpsVtPNJREIsHVq1fRp08f6OjoqDucViMpKQn9+/dXdxitCp+p6vGZqhafp+qp8pleu3YNvXr1UihviUcAN0RBQYHC+lmqXXW/fhozj2rwr4yWMnVNREREjaOpE02iuqr3r8z8/HxkZWXh6dOnCm/qAcDAgQMbFBgRERERUUMoneg+ffoUa9euxXfffSe3qXGlyi0trl27ppIAiYiIiIjqQ+lEd9WqVfj+++8xZcoUODk51boBMRERERGROiid6J49exa+vr4IDAxsjHiIiIiIiFRC6W0StLW10bVr18aIhYiIiJq5Bm7WRC8pdf26UTrRHTlyJM6ePdsYsRAREVEzpqWlhaKiInWHQS1QUVERtLS0mnxcpRNdPz8/ZGdnY/ny5UhJSUF2djYeP36s8ENERESti6mpKe7evYvCwkLO7FKdSKVSFBYW4u7duzA1NW3y8ZVeozty5EgIBAKkpqbi2LFj1bbjrgtEREStS+UL6Pfu3UNpaamao1GfkpISaGtrqzuMFkNLSwtmZmZq2cBA6UQ3ICAAAoGajj8hIiIitTI0NHzpd1xKSkqCg4ODusOgOlA60V2wYEFjxEFEREREpFJKr9ElIiIiImoJWuwRwMePH8euXbuQlpYGPT099O7dGxs3boSJiQkAIDExEVu2bEFaWhrMzMwwffp0+Pr6KvQTFRWFvXv34tGjR7C2tsb777+PQYMGNWrsRERERNT4WuQRwJGRkfj888/h5+eHDz74APn5+fj5559lC+NTUlIwb948eHt7Y/ny5UhOTkZwcDA0NTUxefJkWT9RUVHYvHkzlixZgt69eyM2Nhb+/v6IjY3FK6+80mjxExEREVHja3FHAN+8eROhoaFYtWoV3nrrLVm5h4eH7L/DwsLQu3dvBAcHAwBcXFyQlZWF8PBwvPXWWxAKhSgpKUFERASmTZsGPz8/AICTkxO8vLwQERGB0NDQJr0vIiIiIlKtFncE8OHDh6GtrY2xY8dWWV9SUoJLly5h2bJlcuWenp44cOAAUlNTYW9vj+TkZOTl5WH06NGyNhoaGhg1ahR27twpm5kmIiIiopapxR0BnJKSgm7duuGbb76Bu7s7evfujbFjx+LChQsAgMzMTJSWlqJHjx5y19nY2AAAMjIyAADp6ekAoNDO2toahYWFePDgQWPfChERERE1ohZ3BPDDhw9x8+ZNbN26FYsXL8aXX34JExMT+Pv749atW3j69CkAKCypqPxcWS8Wi6GtrQ1dXV25dkZGRgCA3NzcRr4TIiIiImpMSi9d8PPzw9KlS7F8+XJMnjwZ5ubm0NDQUGjXrl07lQT4ooqKChQWFmLLli1wc3MD8GyHh+HDh2Pnzp0YM2YMAFS77OD58qraVO4gUZ9lC1evXlX6GqpZUlKSukNodfhMVY/PVLX4PFWPz1T1+ExbhhZ3BHDljKuzs7OsTFdXFw4ODkhPT5fVV87cVhKLxQD+mdk1NDSERCKBRCKBjo6OQrvKfpTRp08fub6oYZKSktC/f391h9Gq8JmqHp+pavF5qh6fqerxmaqWRCJptMnCFncEsLW1NX7//XeFcqlUColEAktLS2hpaSEjIwOurq6y+rS0NABA9+7dAfyzNjc9PR29e/eWtUtPT4e+vj7MzMwa8zaIiIiIqJG1uCOAX3/9dRw+fBgXL17E66+/DgAoKipCSkoKRo4cCW1tbbi4uCA+Ph4zZsyQXRcXF4cOHTrAzs4OANCvXz8YGBjgxIkTskS3vLwc8fHxGDp0KHdcICIiImrh6n0yGgD89ddfuHv3LgDAwsICPXv2VElQNfHw8MCrr76KFStWYNmyZWjXrh12796N4uJizJw5E8CzWeepU6dixYoV8PLyQnJyMmJjY7Fq1SoIhc/ev9PW1sbcuXOxefNmmJiYyA6MyMzMxMaNGxv9PoiIiIiocdUr0f3+++8RHByMrKwsAP+chmZubo6goCC5wxtUTSgU4ssvv8SGDRuwfv16SCQSODg4IDo6WrbtmaOjI7Zt24ZNmzbhyJEjMDU1RVBQkNypaABkB0XExMTg0aNHsLGxQWRkJE9FIyIiImoF6nVgxMKFC9GxY0csWbIEPXr0gFQqRUZGBv7v//4PixYtwhdffIGhQ4c2RrwAABMTE4SEhNTYxs3NTbYrQ038/PxkCS8RERERtR5KJ7rbtm1Djx49sG/fPohEIrm6t99+G5MnT8a2bdsaNdElIiIiIqqN0gdG/Pnnnxg/frxCkgsAIpEI48ePb7StxYiIiIiI6krpRFdLSwuFhYXV1hcUFEBLS6tBQRERERERNZTSiW7//v2xd+9e/P333wp1t27dwtdff40BAwaoIjYiIiIionpTeo3usmXLMGnSJHh6emLYsGHo1q0bAODmzZs4ffo0dHV1sWzZMpUHSkRERESkDKUTXRsbGxw6dAibNm3CuXPncOrUKQCAnp4eXn/9dSxZskSW/BIRERERqUu99tG1srLC559/joqKCuTk5AB4tuVX5WEMRERERETqpnRm+ssvv8iSW6FQiPbt26N9+/ayJDcnJwe//PKLaqMkIiIiIlKS0onutGnTcP78+WrrL126hGnTpjUoKCIiIiKihlI60ZVKpTXWl5SUcAkDEREREaldndbo5ufnQywWyz7n5ubi3r17Cu3EYjG+/fZbmJmZqS5CIiIiIqJ6qFOiu3v3boSHhwMABAIBgoODERwcXGVbqVSKJUuWqC5CIiIiIqJ6qFOiO2jQIGhrawMANm3ahDfffBOvvPKKXBuBQIA2bdqgT58+cHBwUH2kRERERERKqFOie/HiRbi7u6NPnz4oKSnBv/71L9ja2jZ2bERERERE9Vant8YOHz6MCRMmYMiQIbh79y7+/vtvFBQUNHZsRERERET1VqcZ3R9//BF//fUXEhMTcebMGSxZsgRCoRD9+/eHu7s73N3dYWVl1cihEhERERHVXZ1PRuvZsyd69uwJf39/PH36FGfPnsWZM2cQERGBTz/9FJaWlrKkd+DAgdDUrNeha0REREREKlGvbNTIyAheXl7w8vJCRUUFkpOTZbO9e/bsgb6+PgYPHoyZM2fC0dFR1TETEREREdWqwdOuQqEQAwYMwIABA7Bs2TJkZWXhxx9/xNmzZ5GcnMxEl4iIiIjUQuXrCzp16oQpU6ZgypQpqu6aiIiIiKjOVJLoFhUV4cqVK9DR0UGfPn2gpaWlim6JiIiIiOpNqUQ3Li4Of//9N+bPny8ru337NmbMmCE7Etja2ho7duzgMcBEREREpFZ12ke3UkREBB48eCBX9umnnyI/Px/r16/HmjVrkJWVhS1btqgyRiIiIiIipdV5RlcqleLvv//GrFmzZGUSiQSJiYlYunQp/v3vfwMAcnJysH//fpUHSkRERESkjFoT3aCgIABAaWkpysvL8e233+LXX38FAIjFYpSWluLixYu4fv06AODBgwfIzs6WXefh4YHhw4c3VvxERERERFWqNdEdO3YsgGeJblxcnGwrMQA4evQoRCIR3nnnHVn7P//8E0lJSbLrLCwsGiNuIiIiIqIa1ZroOjk5yf7b3NwcKSkp8Pf3R3FxMdauXYvXXntNrs29e/fQsWNHuTKi+mgjMsKj3CJ1hwEAEAikKCuXqjuMWmlqCFFWXlFtvahtJzzIKWjCiJSjpSlERfXhN0vtO3at8teplqZSr0C0OFqaQmgIBSrvt5edPSQlZSrvtzFUSAE9HZ4CStScKfU7dN68eVixYgWcnZ1RUVGB8vJy/Pe//5Vrc+rUKdmML1FDlEs1cD3zibrDAABYdNBHyo1H6g6jVo62HXDy8q1q67MfZMPUzLQJI1KO5+Bu2BX3h7rDUEpubi6MjY0VyueMexVroy41fUBNZH3AEMxal6DyfsvKylrMEfI7V4xQdwhEVAul/jTx8fFBly5dkJiYCA0NDXh5ecHW1lZWLxaLYWxsjLffflvlgRIRERERKUPpfzY7OzvD2dm5yjpDQ0MEBwc3OCgiIiIiooZq3YvIiIiIiOilVWuiKxaL6915Q64lIiIiImqIWhNdd3d3bNy4EXfu3Klzp7dv38ann36K119/vUHBERERERHVV61rdDds2IDQ0FDs2LEDr776KgYNGoQ+ffqgc+fOMDIyglQqhVgsxp07d/D777/jwoULuHr1KqytrfHpp582xT0QERE1mYqKMpSXFqs7DCKqg1oT3cqTzRITE3H48GHs2rULEokEAoH8/olSqRQ6OjoYOnQoAgIC4ObmptCGiIioJZNKpbj+UwyePkhDQeC/oKNtpO6QiKgGddp1QSAQwN3dHe7u7igtLcXVq1eRkZGBJ0+e7XHatm1b9OjRA3Z2dtDS0mrUgImIiNTl9u8ncf/GeXR19IK+vr66wyGiWii9vZiWlhYcHR3h6OjYGPEQERE1W+0t+6JMUgArxzHqDoWI6oDbixEREdWiKO8RpFIp2hh3RPeB47k0j6iFYKJLRERUg4Lce0g68jFu/e+4ukMhIiUx0SUiIqpGSdFT/H7ycwiEGjCzeU3d4RCRkpjoEhERVaG8TILfT21FSZEY9v9aCD2D9uoOiYiUxESXiIioCn8m7kTeo1vo/fpsGHbopu5wiKgelN51odK9e/fw888/IycnB6NGjUKnTp1QVlaGp0+fwsjICJqa9e6aCACgISiHrWVbdYcBABAIpHDp01HdYdRKU0OIMUO7V1ufm9sOxsbNd99PLU0h/P9tr+4wlFJQUFDlNlMaQgFWzx6khoiaRkWFFDtXjFB5v+UVFdAQNo85mMShWrh9+zamTvWtsr5C2sQBEZHS6pWNrl+/Hl999RXKy8shEAjQq1cvdOrUCcXFxRgxYgQWLlyIGTNmqDhUetkU5j9F+57W6g6jVblz80/07G6u7jBalVvpf6Br//7qDqPVSEpKQn81P8/bt2+jS5cu+NcID7XGQUQNp/Q/m3fs2IE9e/ZgxowZ2LVrF6TSf/5JKxKJMGLECCQkJKg0SCIioqZw8uRJDBkyhH+PEbUSSie6sbGxGDNmDN5//3288sorCvW2trb4+++/VREbERFRk/nf//6HefPmwd7eHkOGDFF3OESkAkonuvfu3cOAAQOqrReJRBCLxQ0KioiIqCllZmZixowZMDU1xe7du6Gnp6fukIhIBZROdI2NjZGdnV1t/fXr12FmZtagoIiIiJpKYWEhfH19UVZWhpiYGLRvz23EiFoLpRNdd3d3HDhwADk5OQp1f/zxBw4ePAgPDy7gJyKilkFPTw9vv/02oqKiYG3NF2CJWhOld11YuHAhfvrpJ4wZMwbu7u4QCAQ4dOgQDhw4gISEBFhYWGDu3LmNESsREZHKSKVS3L17F507d8a7776r7nCIqBEoPaPboUMHHDp0CK+//joSEhIglUoRFxeHc+fOwdvbG/v27YORUfPdp5OIiAgAPvvsM3h4eODWrVvqDoWIGkm99tE1MTHB2rVrsXbtWuTk5KCiogImJiYQNpNNvomIiGryf//3f9iyZQsmT54MS0tLdYdDRI1E6cy0sLAQ9+7dk302MTFB+/btZUnuvXv3UFRUpLoIiYiIVOjs2bNYvnw5XF1dsX79eggEAnWHRESNROlEd/369Zg3b1619QEBAfj0008bFBQREVFjSE9Ph7+/P2xsbPDll19CS0tL3SERUSNSOtE9f/58jbsqeHh44KeffmpQUERERI2hS5cueOutt7Bnzx4YGhqqOxwiamRKr9F9+PAhTE1Nq63v0KFDjfvsEhERNbWCggJIJBKYmJhgzZo16g6HiJqI0jO6JiYmuHHjRrX1N27c4L+SiYio2SgrK8OcOXMwbtw4lJSUqDscImpCSie6bm5uOHDgAJKTkxXqUlJScODAAbi6uqokOCIiooaQSqVYsWIFfvzxR/j5+UFbW1vdIRFRE1J66cKCBQuQmJiIqVOnwtXVFTY2NhAIBLh+/TrOnj2L9u3bY9GiRY0RKxERkVK+/PJLxMTEYN68efD19VV3OETUxJROdCsPjPjss8/w/fff48yZMwAAkUgEb29vLF26FB06dFB1nEREREo5efIk1q5dCy8vLwQFBak7HCJSg3odGNG+fXuEhIRAKpUiJycHUqkU7dq1416ERETUbPTr1w/Tp0/HqlWreKAR0UuqXoluJYFAgHbt2qkqFiIioga7f/8+2rVrhw4dOiA4OFjd4RCRGtWa6FaegmZubi73uTaV7YmIiJpKTk4Oxo8fD0dHR4SFhak7HCJSs1oT3WHDhkEgEODKlSvQ1taWfa7NtWvXVBIgERFRXRQXF2PWrFnIysrCli1b1B0OETUDtSa6wcHBEAgEsmMSKz8TERE1FxUVFVi8eDF++eUXfPHFFxg4cKC6QyKiZqDWRHfcuHE1fiYiIlK3zz77DMePH8eKFSvg5eWl7nCIqJlQ6mW04uJieHp6Ytq0aZg2bVpjxURERKSUUaNGAQDmzJmj5kiIqDlRKtHV1dVFXl6ebBkDUWNqIzLCo9yiJh1TIJCirFzapGNWR1NDiLLyCpX2KWrbCQ9yClTWn5amEBWqDbFJaWk2fMspy262eJovUUE0qqGlKYSGsOUuL+tlZw9JSVmVdRVSQE9H/q+tu3fvwsLCAvb29rC3t2+KEImoBVF6ezF3d3ckJiZi8uTJjREPkUy5VAPXM5806ZgWHfSRcuNRk45ZHUfbDjh5+ZZK+8x+kA1TM1OV9ec5uBt2xf2hsv6a2pxxr2Jt1KUG9VFQWAj9Nm1UFFHDrQ8YglnrEtQdRr2VlZVBU7Pqv5p2rhgh9/nq1asYN24cPvjgA7zzzjtNER4RtTBKT2f4+/vj7t27WLRoES5evIi7d+/i8ePHCj9Npby8HGPHjkXPnj3x3XffydUlJiZi7NixsLe3h4eHB2JiYqrsIyoqCsOGDcOrr76KcePG4eLFi00ROhER1dPdu3cxffp0GBkZwdPTU93hEFEzpfSM7ujRowEAN27cwKlTp6pt11Tbi+3btw/Z2dkK5SkpKZg3bx68vb2xfPlyJCcnIzg4GJqamnKz0VFRUdi8eTOWLFmC3r17IzY2Fv7+/oiNjcUrr7zSJPdARER1l5eXh+nTp6OgoADffPMNOnbsqO6QiKiZUjrRDQgIaDbbiz169AihoaEICgpSOMc8LCwMvXv3lp2K4+LigqysLISHh+Ott96CUChESUkJIiIiMG3aNPj5+QEAnJyc4OXlhYiICISGhjb5PRERUfWkUinmzJmDGzduICYmBr169VJ3SETUjCmd6C5YsKAx4qiXDRs2YMiQIXBycpIrLykpwaVLl7Bs2TK5ck9PTxw4cACpqamwt7dHcnIy8vLyZLPUAKChoYFRo0Zh586dkEqlzSapJyKiZ0fPT5w4Ed7e3nB1dVV3OETUzCmd6DYXv/zyCxISEnDixAmUl5fL1WVmZqK0tBQ9evSQK7exsQEAZGRkwN7eHunp6QCg0M7a2hqFhYV48OABvxIjImom7t69i+7dusLb21vdoRBRC1HvRPfChQtITEzEvXv3AADm5uZwdXXF4MGDVRZcdcrKyvDxxx/D398fnTp1wp07d+Tqnz59CgAwNDSUK6/8XFkvFouhra0NXV1duXZGRkYAgNzcXCa6RETNwL0/EzF82Dzs27cPLi4u6g6HiFoIpRPd/Px8LFq0CBcuXIBUKoWRkRGkUinEYjGio6Px2muvITQ0FCKRqDHiBQBER0ejuLhYtq62OtUtO3i+vKo2Uqm0xuurc/XqVaXaU8109E2QnpHRpGMa6nbD7du3m3TM6vTuaojsB4ovWjaUKvssK7dEbm6uyvpralKpFAWFhQ3uRxV9qIz02WRAS/Z8/BXlpcj4+QDuXz8HV1c3AEBSUpK6Qmux+MxUj8+0ZVA60Q0JCcH58+cxb948+Pr6om3btgCAJ0+eIDo6GhEREQgJCcG6detUHiwA5OTkYOvWrfjPf/6D4uJiFBcXIz8/H8Czk9vy8vJkM7KVM7eVxGIxgH9mdg0NDSGRSCCRSKCjo6PQrrKfuurTp49cP9QwV/+8iR7duzfpmAYG+ujSpUuTjlkdHR0dle55C6h+H11NDQ0YGxurrL+mJhAIGrwHbnPbRxcCVLsPbUvw/D66koInSP0hAuKHGejy6hvYERUO/Ta6tfRAL0pKSkL//v3VHUarwmeqWhKJpNEmC5X+0/DUqVOYOHEiFi5cKFfetm1bLFq0CI8ePcLJkycbLdF98OABCgsLsXz5coW65cuXw8DAABcuXICWlhYyMjLkXlZIS0sDAHT//8lT5drc9PR09O7dW9YuPT0d+vr6MDMza5R7ICKi2j28mYT8J3fRe9gcmHYb0KITeCJSD6X/1JBKpTXuL/vKK68oHNygSpaWloiOjpYre/ToEZYuXYoFCxbAxcUF2tracHFxQXx8PGbMmCFrFxcXhw4dOsDOzg4A0K9fPxgYGODEiROyRLe8vBzx8fEYOnQod1wgImpiUqkUxXmPoWvQDhZ2w9Gua1/oGbRXd1hE1EIpnei6urrizJkzePvtt6usP3PmTKNu+aKvrw9nZ2e5ssqX0aytrTFgwAAAz/b7nTp1KlasWAEvLy8kJycjNjYWq1atglD47EA4bW1tzJ07F5s3b4aJiYnswIjMzExs3Lix0e6BiIgUlZdJcP2naDy58zsGjlsDHf22THKJqEGUTnTnzZuHJUuW4N1338WUKVPQtWtXCAQC3Lx5E3v37kV2djYCAwMVjgFu166dyoKuC0dHR2zbtg2bNm3CkSNHYGpqiqCgILlT0QDIXmiLiYnBo0ePYGNjg8jISJ6KRkTUhIryHiL1+23Iz7kDq37e0G6j3DsSRERVqfcRwNevX8fZs2fl6ip3K6jq3PHGPBK4c+fO+OuvvxTK3dzc4ObmVuv1fn5+te7gQEREjSPnzlX8cToSANB7+DyYWjmqOSIiai1a9BHARETU8j1IuwQd/bbo4xEArTYm6g6HiFoRgbRyGpbqrXJbDG4vplrX/kpDBzOLJh1TIJCirLx5/JbQ1BCirLxCpX3m5j6FsbHqvhLW0hSiQrUhNiktTWGD+ygpKYG2trYKolENLU0hNITNfzIiLy8PT5/monPnLigqKoJUKkWbNm1QXlEBDWHV/18qpICeDndeUBa3wlI9PlPVasw8in9iULNVmP8U7XtaqzuMVuXOzT/Rs7u5usNoVZKSrvIvPCWlpaXBz88PWlpaOHnyJIyNDGR1TCCISJUaPp1BRERUR/Hx8Rg9ejSePHmCjz/+GBoaGuoOiYhaMSa6RETU6MrLyxESEoJ33nkHNjY2+O677/Daa6+pOywiauWY6BIRUaMrLS1FYmIi3n77bRw6dAjm5lxCQ0SNj2t0iYio0fzxxx+wsLCAkZERDh48CH19fXWHREQvEc7oEhFRozh06BC8vLywbt06AGCSS0RNrt4zuvn5+cjKysLTp09R1Q5lAwcObFBgRETUMpWWlmLt2rWIiorCoEGD8MEHH6g7JCJ6SSmd6D59+hRr167Fd999h/LycoV6qVQKgUDQqCehERFR85SdnY05c+bg8uXLeOedd7BixQpoaWmpOywiekkpneiuWrUK33//PaZMmQInJycYGho2RlxERNQClZeX4/79+wgLC8PYsWPVHQ4RveSUTnTPnj0LX19fBAYGNkY8RETUwkilUiQkJGD48OHo1KkTzpw506xOiyOil5fSL6Npa2uja9eujRELERG1MMXFxVi2bBlmzpyJgwcPAgCTXCJqNpROdEeOHImzZ882RixERNSC3L17F+PGjcP+/fuxaNEi+Pj4qDskIiI5Sie6fn5+yM7OxvLly5GSkoLs7Gw8fvxY4YeIiFqvS5cu4Y033kB6ejp27tyJDz74gMf5ElGzo/Qa3ZEjR0IgECA1NRXHjh2rth13XSAiar20tbXRqVMnbNu2DdbW1uoOh4ioSkonugEBARAIBI0RCxERNWOFhYU4efIkxo4di379+uG7776DUMhzh4io+VI60V2wYEFjxEFERM3YzZs38c477+D69euwt7eHtbU1k1wiavbqfTIaAPz111+4e/cuAMDCwgI9e/ZUSVBERNR8fP/991iwYAE0NDSwd+9e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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "fig, ax = plt.subplots(figsize=(10,8))\n", - "all_emiss_db_cumu = all_emiss_db*5/1000\n", - "# all_emiss_db_cumu = all_emiss_db_cumu.loc[:,[100, 250, 400, 600]]\n", - "bottom = np.zeros(len(all_emiss_db_cumu.columns))\n", - "aa = 0.2\n", - "for ind, row in all_emiss_db_cumu.iterrows():\n", - " ax.barh(y = row.index, width = row.values,height = 40, left=bottom, label=str(ind) + '-' + str(ind+4), color = 'b', alpha=aa)\n", - " bottom += row.values\n", - " aa+=0.12\n", - "ax.plot(sum_emissions.values,sum_emissions.index, 'k--', label='Cumulative')\n", - "plt.xlabel('Cumulative emissions reduction (Gt CO$_2$)')\n", - "plt.ylabel('Carbon price (\\$/tonne CO$_2$)')\n", - "plt.xlim([-20, 120])\n", - "plt.ylim([-100, 1100])\n", - "plt.legend()\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_mitigation_curve_stackedbarh.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "id": "68034ef9", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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nTsXgwcPRkZGBhISErBy5Uo88cQTAABLS0sAbZsbTca25Jw15zNfN14ikSj9oVafiYkJJkyYgOPHjyMrKwvm5uYabVdHRwf29va4ePGiRuOJujoWukTUbBkZGRgyZIhG60o9PT0xadIkpbYpU6bA19cXhw8fxltvvaXyniFDhijNdNX9d//+/bFz507o6OgAAPr27Ytt27bh559/xrhx4wAAW7ZsQWVlJQ4ePKgosF599VW8/PLL+OijjzBhwgSltY0WFhb4+OOPFa8FQcB//vMfvPfeezA2Nm7y+DSJqbHjaswnn3yC3Nxc7N+/H87Ozor20NBQxczjp59+iqqqKnz77bd48sknAQABAQHo168f9u7di7lz52LgwIFqt5+RkQEAavv19PQgl8s1vrL/p59+gq6uLsaNGwcjIyPY2toiISEBEydOVNl+W+ZGk7EtPWeafuYBID09HUOGDIG+vn6jY2xtbXH8+HHcuXNH40IXAJ555hn8+uuvGo8n6sq4dIGImq2srAyGhoYaje3Zs6fivysqKlBUVARjY2MMHjwYN27cUPuemTNnqm2fPXu2oqAEgDfeeAMAFF9919bW4qeffoK3t7eikAIAIyMjBAQE4P79+7h9+7bSNl9//XWl18899xxqa2sV61Ob0lRMmhxXfXK5HElJSXB3d1cqcuvo6OhAEAR8//338PLygq6uLgoLCxU/7u7ukMvluHDhQqP7qPtKX93FYi+//DJqa2sREBCAb775BiUlJaisrGx0W8nJyXBycoKRkdEjj6utc9PU2Jaes+Z85gHgwYMHTZ6Tuu2pW37zKL169UJNTU2z30fUFXFGl4iazcjICA8ePNBobFVVFSIjI/Htt9+q3Ae37qvthtRdIAUAgwYNUnptamqKXr16KYqZwsJClJeXq6yJBP739Xl2djaGDRumaDczM1MaV1f8lZSUPOqwNI6pvsaOq77CwkKUlZXB2tr6kWNKSkpw5MgRHDlyRO2YgoKCJvelbl2qjY0NDh48iG3btuHkyZN48OABnJ2d4enpiYiICKWZx9raWvz8888ICQnR6LjaMjdNjW3pOWvOZx54WMQ2VYjWbc/Q0BDV1dV49913ce7cOUilUlhZWWHlypUYNWqUyvuaWk9MRP/DQpeIms3CwgK///47qqurm/wqd8OGDTh06BBmz54NJycnGBsbQ1dX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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "fig, ax = plt.subplots(figsize=(10,8))\n", - "all_emiss_db_cumu = all_emiss_db*5/1000\n", - "bottom = np.zeros(len(all_emiss_db_cumu.columns))\n", - "aa = 0.2\n", - "for ind, row in all_emiss_db_cumu.iterrows():\n", - " ax.bar(x = row.index, height = row.values,width = 40, bottom=bottom, label=str(ind) + '-' + str(ind+4), color = 'b', alpha=aa)\n", - " bottom += row.values\n", - " aa+=0.12\n", - "plt.ylim([-20, 120])\n", - "plt.xlim([-100, 1100])\n", - "ax.plot(sum_emissions.index, sum_emissions.values, 'k--', label='Cumulative')\n", - "\n", - "plt.legend()\n", - "plt.ylabel('Cumulative emissions reduction (Gt CO$_2$)')\n", - "plt.xlabel('Carbon price (\\$/tonne CO$_2$)')\n", - "\n", - "handles, labels = ax.get_legend_handles_labels()\n", - "unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - "plt.legend(*zip(*unique[::-1]), loc='upper left', frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_mitigation_curve_stackedbarv.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "id": "ddfa2ee8", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAtUAAAHfCAYAAACfwCSQAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8/fFQqAAAACXBIWXMAAAsTAAALEwEAmpwYAADmdklEQVR4nOzdeVyU1f7A8Q/7NiD7LiqbAqLirqUYauaWZZaaa5pW7ltXLPVm/SKvt9yXsiyXzKtoWZKaejXccyFcyA1QcUEEWYZhX+b3B5fJEVAGQVy+79fL1+vO85w5z3nuQ/CdM+d8v3pqtVqNEEIIIYQQosr0a3sAQgghhBBCPOkkqBZCCCGEEOIhSVAthBBCCCHEQ5KgWgghhBBCiIckQbUQQgghhBAPSYJqIYQQQgghHtITG1T/+OOPNGzYsMy/jz/+WKtdZGQkr776KoGBgXTp0oV169aV29+qVasICQmhSZMm9O3blyNHjpRpo1KpmD17Nm3atCEoKIh3332X69ev18j9CSGEEEI8ia5evcrs2bPp06cP/v7+9OrVq0yb0NDQcuO4nTt3lmlbmRjtcWBY2wN4WN988w2Wlpaa1/b29pr/HR0dzZgxY+jTpw/Tp08nKiqKsLAwDA0NGThwoKbdqlWrWLBgAZMnT8bf35/w8HBGjx5NeHg4jRo10rSbOnUqMTExzJo1C4VCweLFixk+fDjbtm3DzMzs0dywEEIIIcRj7NKlS0RGRtK0aVOKi4upqCRK3bp1+fzzz7WO1a9fX+t1ZWO0x4Hek1r85ccff2TGjBkcOXIEW1vbctu8/fbbZGRkEB4erjk2a9Ys9u3bx/79+9HX1yc/P5/27dvzxhtv8I9//AOAoqIievfujY+PD4sWLQLg1KlTvPHGG6xcuZLg4GAAbt68SdeuXfnggw8YNGhQDd+xEEIIIcTjr7i4GH39ksUQoaGhnD17loiICK02FR2/W2VjtMfFE7v840Hy8/M5evQoPXr00Dreq1cvkpOTiYmJASAqKorMzEx69uypaWNgYED37t3Zv3+/5tNVZGQklpaWdOjQQdPO1dWV5s2bs3///kdwR0IIIYQQj7/SgPphVTZGe1w88cs/evfuTWpqKi4uLvTt25d3330XQ0NDEhISKCgowMvLS6u9j48PAPHx8QQGBhIXFwdQpp23tzfZ2dkkJSXh7OxMXFwcnp6eZX5QvL29OXjwYIXjUyqVKJVKrWOFhYXo6elhbW1dbT94QgghhBA1obi4mNTUVPT19TEwMNA6Z2VlhZWVVZX6TUhIoGXLluTk5ODj48Po0aO1JkMrG6M9Lp7YoNrBwYHx48fTpEkTDAwM2L9/P8uXL+f69evMnTuXjIwMgDIPuvR16XmlUomxsTGmpqZa7erUqQNAeno6zs7OKJVKrbXbd/dX2ld51qxZw9KlS7WOdenShREjRpCSkqLjXQshhBBC1I6PPvqIixcvah0bN24c48eP17kvPz8/AgMD8fb2JjMzk82bNzN58mRyc3Pp27cvUPkY7XHxxAbVHTp00FqK8dxzz2FpacmSJUsYM2aM5rienl6577/7eHltSr9SeFC7+x0HGDZsGK+++qrWsdzcXDIyMnB3d8fc3LzC9z6Mixcv4uvrWyN9i8qRZ1D75BnUPnkGtU+eQe170p9BdnY2169f5/PPP8fCwkLrXFVnqYcNG6b1ukuXLgwdOpTFixdrgmqofIz2OHhig+rydO/enSVLlhATE6NZ5nHvLHLpUozSHwIrKyvy8vLIy8vDxMSkTLvST0NWVlYkJiaWuaZSqbzvD1R5X4tkZmaSkZGBubl5ubPf1aUm+xaVI8+g9skzqH3yDGqfPIPa9zQ8A1dX1xq9j5deeok5c+aQmpqKra1tpWO0x8VTtaD37gXrHh4eGBkZER8fr9UmNjYWAE9PT+DvdTql63ZKxcXFYWFhgZOTk6bd5cuXyyyKj42N1fQlhBBCCCGq5t4Yq7Ix2uPiqQqqt2/fjp6eHo0bN8bY2Ji2bduyY8cOrTYRERE4ODgQEBAAQPPmzbG0tGT79u2aNkVFRezYsYMOHTpovloIDg5GqVRy4MABTbvExESioqLo2LHjI7g7IYQQQoink1qtZufOnbi5uWlSJVc2RntcPLHLP0aOHEmbNm3w9fVFT0+PAwcO8MMPP9CvXz/q1q0LwNixYxk8eDAzZ86kd+/eREVFER4ezuzZszVZN4yNjXnvvfdYsGABtra2msTiCQkJfPHFF5rrNW3alE6dOvHhhx8SGhqKQqFg0aJFmqwjQgghhBACcnJyiIyMBODGjRuoVCpNpcTAwECgJE91z549qVevHkqlkvDwcI4dO8a8efM0/VQ2RntcPLFBtaenJ1u2bCEpKYnCwkLq16/PtGnTtBa+BwUFsXz5cubPn8/WrVtxdHRkxowZWtUUoSRAB1i3bh0pKSn4+PiwcuXKMpV6vvjiC+bNm8ecOXPIz8+nTZs2LFq0SKopCiGEEEL8z507d5g4caLWsdLXn332GSEhISgUClasWMGdO3cwMjLC39+fFStWEBISovW+ysZoj4MntqLikywzM1OzE7imFvyfPHmSFi1a1EjfonLkGdQ+eQa1T55B7ZNnUPue9GfwKOKWp8ETO1MthBBCCG25ubkkJyeTm5tLYWEhAIaGhpw7d66WR/Zse5yfgZGREY6OjlVOjSf+JkG1EEII8RTIyMggKSkJBwcHnJ2dMTQ0RE9Pj6ysrDK5hcWj9bg+A7VaTU5ODjdu3ACqnnNalHiqsn8IIYQQz6qUlBTc3d2xsbHByMjoscuMIB4/enp6mJub4+bmxu3bt2t7OE88CaqFEEKIp0B+fr5snBdVYmZmRkFBQW0P44n3UEF1VlYW2dnZ1TUWIYQQQjwEmZ0WVSE/N9VDpzXVR44cYc+ePZw8eZL4+HjNpxojIyO8vLwICgqia9eutGvXrkYGK4QQQgghxOPogUF1QUEBGzdu5Ntvv+XmzZtYWVkREBDAK6+8Qp06dVCr1SiVShISEti2bRs//PADLi4ujBgxggEDBmBkZPQo7kMIIYQQQoha88Cg+sUXXyQvL48+ffrQo0cPTSWcipw6dYqdO3eyYsUKvv32W/bt21dtgxVPnh07drBt2zbOnj2LUqnEw8ODIUOG0K9fP62vmyIjI1m4cCGxsbE4OTkxbNgwhgwZotVXSEiIZofy3Y4cOaIpaQqgUqmYN28ev/32m6ZIz8yZM3F3d6+5GxVCCFEjDhw4wNq1azl9+jRZWVnY2dnx3HPPMXLkSLy8vGp7eBp//PEHQ4cOZfPmzQ+Mle62Z88ekpKSGDRokNbxJUuW8O233/Lnn39W91BFDXlgUP3222/Tr18/TExMKtVh06ZNadq0KZMmTWLz5s0PPUDxZFu9ejVubm6EhoZiY2PD4cOHmT17NomJiUyYMAGA6OhoxowZQ58+fZg+fTpRUVGEhYVhaGhYpvplt27dGDFihNaxe1MATZ06lZiYGGbNmoVCoWDx4sUMHz6cbdu2ySYeIYR4gixZsoSlS5fSuXNnPvroI+zt7bl58ybbtm1jwIABHD9+vLaH+ND27NnD2bNnywTVr7/+OsHBwbU0KlEVDwyq733IlWViYlLl94qnx4oVK7Rmkdu1a0d6ejpr1qxh3Lhx6Ovrs3TpUvz9/QkLCwOgbdu2JCYmsmzZMvr374++/t/7ae3t7WnWrFmF1zt16hS///47K1eu1Pwy8vX1pWvXrvz444/yMymEEE+IgwcPsnTpUt555x2mTJmida5Pnz7897//raWRPRrOzs44OzvX9jCEDiSlnqhRdwfUpfz8/FCpVOTl5ZGfn8/Ro0fp0aOHVptevXqRnJxMTEyMTteLjIzE0tKSDh06aI65urrSvHlz9u/fX7WbEEII8citWrUKOzs7xo8fX+75zp07A9CwYUNWrVqlde7HH3+kYcOGpKamAnD9+nUaNmzIzz//zMcff0zr1q1p06YNS5cuBeC///0vPXv2JCgoiJEjR2rlbP7jjz9o2LAhZ86c0bpGaGgovXr1uu89rF69mtdee42OHTvStm1bRo4cyaVLl7T6+Omnn7h06RINGzakYcOGhIaGAiWz9EFBQQBkZ2cTFBTEypUry1zjgw8+oFu3bprX+fn5LFy4kJCQEBo3bky3bt3YuHHjfccpqke1VFTMy8vjypUr1K1bF3Nzc61zERERD/yhE8+WkydP4ubmhpmZGbGxsRQUFJRZF+fj4wNAfHy81tq0bdu2ER4ejoGBAS1atGDKlCkEBARozsfFxeHp6ak1uw3g7e3NwYMHa/CuhBBCVJfCwkJOnjxJ165dqzXhwcKFC+ncuTMLFizgwIEDLFmyhOzsbI4cOcLEiRMpKiri008/Zfbs2Xz55ZcPfb1bt24xaNAgbG1tUavVbNq0iQEDBrBjxw4cHR0ZM2YMqampxMfH8/nnnwPlT0aZm5sTEhLCtm3bGD16tOZ4fn4+u3fv1tqDNGXKFP744w/Gjh2Lr68vR48e5aOPPsLCwkLisRr20EF1dHQ07777Lmq1mry8PMaMGaP1wGfPni0PsRoc+PMGkX9er3T79PR0dpz6o9quHxzkTocgt4fu58SJE2zfvp1p06YBJWV1oey66NLXpeehZKNikyZNcHV15caNG6xcuZJBgwaxefNmvL29AVAqlVhaWpa5rpWVlVZfQgjxLOnXr1+ZY7169WL48OHk5OSU2RgOJWt6+/fvT2pqqtbf9VJDhgyhT58+3Lhxg4kTJ5Y5P3r0aF588cUqjTc9PZ28vDxcXV2r9P6KBAYGMnPmTACee+45du3axdq1a9mzZ49mqcXNmzf597//TW5uLqampg91vdJZ56ysLExNTXnuuecIDg7m119/5a233sLDwwNbW1tu3rx536WNUPK83n33XS5duqSZeNq/fz9KpVITZ/3xxx/s3r1bawlk+/btSU9PZ9GiRRKP1bCHXv4xd+5cQkND+eOPP9iyZQu7du1ixowZFBcXAyV15YWAkk/skydPplWrVgwfPlzrXEWJ5+8+PnPmTF5++WVatmxJnz59+P777zE1NS3zdVhl+hJCCPH4Ko0dqvv39vPPP6/1un79+nh5eWmtXa5fvz5qtZqkpKSHvl50dDQjRowgJCQEf39/AgMDSU1N5fLly1Uau7W1NREREZpjv/76KwEBAXh6egJw6NAh6tSpw3PPPUdhYaHmX/v27UlISCA9Pf2h70lU7KFnqmNjY3nllVcA8PLy4vvvv2fcuHFMmDCB+fPnP2z34n86BLnpNFN88uRJWrRoUYMj0o1SqWTUqFFYW1uzbNkyDAwMAKhTpw5AmVlkpVIJlJ3BvpuNjQ1t27bVWndtZWVFYmJiude/X19CCPE0u182LjMzs/uet7W1ve95Nze3as/2ZWNjg4mJCTdv3qzWfu/9O2BkZFTuMShZ2vowbt68yYgRIwgICCA0NBQPDw+MjY2ZOHEi+fn5OvdnZGREt27diIiIYPLkyWRnZ7Nv3z5NJi2A1NRUMjIytJZF3i0xMRFra+uq3pJ4gIcOqi0tLUlKSsLJyQkAU1NTVqxYwbRp03j77bdlplqQm5vLO++8Q2ZmJhs3btRanuHh4YGRkRHx8fF07NhRczw2NhZA8+m7Ivf+fHl5eXH48GHUarXWDEdsbOwD+xJCCPF4MDQ0pGXLlhw5coSCgoL7rqs2NjbWVHguVZ3L/UpTCt97jQfN+h44cIDs7GyWLl2KoaEhFhYWlXrf/fTq1YuNGzcSHR3NtWvXyM3N1droX6dOHWxsbPj666/LfX/9+vWrfG3xYA+9/KNdu3Zs2bJF65iRkRELFizA3d2d3Nzch72EeIIVFhYyadIk4uPj+eabbzQfvkoZGxvTtm1bduzYoXU8IiICBweHCj9tQ8kn8qNHj2ptZAwODkapVHLgwAHNscTERKKiorSCdiGEEI+3ESNGkJKSwrJly8o9X1pczsXFRTMRU6o6N6a7uLgAJRvhS6lUKqKjo+/7vtzcXPT09DA0/Hv+8r///S9ZWVla7YyMjCo9K96qVSucnZ2JiIjg119/1bwu9dxzz5GWloahoSGBgYFl/kmthpr10DPVH330EUVFRWWO6+vrExYWxrhx4x72EuIJNmfOHPbt20doaGiZX0Le3t4oFArGjh3L4MGDmTlzJr179yYqKorw8HBmz56tyeIRERHBvn376NixI05OTty4cYOvv/6a/Px8Ro0apemzadOmdOrUiQ8//JDQ0FAUCgWLFi3CxcWFvn37PurbF0IIUUXPP/8848aNY+nSpcTGxtKrVy/s7e1JTEzk119/JSoqimPHjtG9e3dWrVpF48aN8fb2ZseOHcTHx1fbOJycnAgKCmLJkiUoFAqMjIz49ttvH7iJsW3btgDMmDGDV155hcTERFauXFkmu4eXlxebN2/ml19+oUGDBtjY2FRYAVhPT48ePXrw008/oVKpmDVrltb59u3b06VLF0aNGsXIkSNp1KgReXl5xMfHc/r0aRYuXFj1/yPEA1UpqL527RpxcXGoVCosLCzw9vambt265bat7p274sly6NAhoGRD673Wrl1LmzZtCAoKYvny5cyfP5+tW7fi6OjIjBkztKopuru7c/v2bebOnYtSqUShUNC6dWsWL15cJh3fF198wbx585gzZ46mTPmiRYvkE7oQQjxhxo8fT9OmTVm7di3//Oc/UalU2Nvb06ZNG1avXg3Au+++S2pqKl9++SVqtZpXXnmF9957r0zA+TA+//xzZs+ezQcffICNjQ3vvfceJ0+e5OzZsxW+p2HDhsydO5elS5fy+++/4+PjwxdffMFHH32k1a5fv36cPn2aTz/9lPT0dF599dVy/2aW6t27N99++61mjfW9Fi5cyKpVq9i4cSPXr1/HwsICT09PevfuXeX7F5Wjp9Zh0fNvv/3GkiVLtL4CKeXt7c24cePKfcBCW2ZmJhcvXsTX17fc9G/V4XHbqPgskmdQ++QZ1D55Bo/OuXPn8PPzK3M8KytLs55X1I4n4RlU9PMDjyZueRpUeqZ6wYIFrFy5EoVCQZ8+fWjUqBEWFhZkZWVx/vx59u7dy6RJkxg9ejSTJ0+uyTELIYQQQgjxWKlUUH3gwAG++uorXnzxRT799NNyP6WoVCpmzpzJypUradWqVZlckEIIIYQQQjytKpX9Y926dTRs2JCFCxdWOO2vUCiYP38+vr6+rFmzploHKYQQQgghxOOsUkH16dOn6d27tyYTQ4Wd6evTu3dvzpw5Uy2DE0IIIYQQ4klQqaA6OzsbGxubSnVobW1Ndnb2Qw1KCCGEELqTgmuiKuTnpnpUKqh2cnLi4sWLlerw4sWLODo6PtSghBBCCKEbY2NjcnJyansY4gmUk5Nz36qVonIqFVR36NCB8PBwrl69et92V69eZfPmzQQHB1fL4IQQQghROfb29ly/fp3U1FQKCgpk9lE8kFqtJjs7mxs3bsiEaDWoVPaPd955h4iICN58803ef/99evTogbGxseZ8fn4+27dv5/PPP8fQ0JDRo0fX2ICFEEIIUVadOnUwMTEhOTmZO3fuUFhYCJT8jb77b7Z49B7nZ2BkZISTkxNWVla1PZQnXqWCaicnJ1auXMn48eOZMWMG//znP2nQoAEKhQKVSsXly5fJz8/Hzs6Or776Cicnp5oetxBCCCHuYWpqWqbC8cmTJ2natGktjUiAPINnRaWLvzRr1ozt27ezYcMG9u3bR1xcnKZCkJ+fHyEhIQwYMEA+6QghhBBCiGdOpYNqAEtLS0aPHi3LO0Sl7dixg23btnH27FmUSiUeHh4MGTKEfv36oaenp2kXGRnJwoULiY2NxcnJiWHDhjFkyJAK+921axfjx4/Hx8eHiIgIzfHr16/TuXPnMu3vbSeEEEIIUZ10CqqF0NXq1atxc3MjNDQUGxsbDh8+zOzZs0lMTGTChAkAREdHM2bMGPr06cP06dOJiooiLCwMQ0NDBg4cWKbPnJwcPvvsM+zt7Su87pQpU2jTpo3mtampafXfnBBCCCHE/1QqqE5OTmbIkCF069aNyZMnV9huwYIF7Nq1i/Xr12Nra1ttgxRPrhUrVmj9LLRr14709HTWrFnDuHHj0NfXZ+nSpfj7+xMWFgZA27ZtSUxMZNmyZfTv379M0aHly5fj7u6Om5sbZ8+eLfe69erVo1mzZjV2X0IIIYQQd6tUSr21a9eSnp7OqFGj7ttu1KhRpKWlsW7dumoZnHjylffhys/PD5VKRV5eHvn5+Rw9epQePXpotenVqxfJycnExMRoHY+Li2PdunXMmjWrRscthBBCCKGLSgXVkZGR9OzZE4VCcd92CoWCXr16sXfv3moZnHg6nTx5Ejc3N8zMzEhISKCgoAAvLy+tNj4+PgDEx8drHf/kk0/o168fvr6+973GnDlz8Pf3p02bNsyYMYM7d+5U700IIYQQ4omWlZVVrVXAK7X8IyEhgcGDB1eqQ19fXzZv3vxQgxJlHf/rFn/E3Kp0++TkNI7ER1fb9dsEONPK3/mh+zlx4gTbt29n2rRpAGRkZACUyRpT+rr0PMCvv/7KhQsXWLx4cYX9GxsbM3DgQJ5//nmsrKyIiYnhyy+/JDo6mp9++knWVgshhBDPqCNHjrBnzx5OnjxJfHw8BQUFQEmubi8vL4KCgujatSvt2rWrUv+VCqr19PQoLi6uVIfFxcVaWR2EKHXr1i0mT55Mq1atGD58uNa5in5mSo+rVCrmzp3LlClT7pu20dHRkY8++kjzunXr1gQEBDBkyBAiIiLo16/fQ9+HEEIIIZ4MBQUFbNy4kW+//ZabN29iZWVFQEAAr7zyCnXq1EGtVqNUKklISGDbtm388MMPuLi4MGLECAYMGKBT+fZKBdVubm6cPn2aAQMGPLDtmTNncHNzq/QAROW08tdtpvjkyZO0aNGs5gakI6VSyahRo7C2tmbZsmUYGBgAJRXAQHtGurQ9/D1j/eWXX2JtbU3Xrl015woKCiguLkapVGJqalphtarWrVtjZ2dHTEyMBNVCCCHEM+TFF18kLy+PPn360KNHDwIDA+/b/tSpU+zcuZMVK1bw7bffsm/fvkpfq1JBdadOnVi3bh0jR44ss/b1bnFxcURERDB06NBKD0A8/XJzc3nnnXfIzMxk48aNWFpaas55eHhgZGREfHw8HTt21ByPjY0FwNPTEyhZW33x4kWtNHmlWrVqxYwZM8rMft9NrVZX090IIYQQ4n6uXr3KqlWrOHXqFJcuXcLT01OrVkRRURHffvstkZGRXLp0ieLiYho1asT48eNp3bq1Vl8hISHcuHGjzDWOHDlSqUxzb7/9Nv369cPExKRSY2/atClNmzZl0qRJOi9nrlRQPWLECLZs2cKwYcMIDQ3lpZdewtDw77cWFhayc+dO5s6di0Kh4K233tJpEOLpVVhYyKRJk4iPj2f9+vVlStgbGxvTtm1bduzYoRUUR0RE4ODgQEBAAACTJk1i2LBhWu9duXIlly9f5rPPPqNevXoVjuHo0aOkpqY+8NOpEEIIIR7epUuXiIyMpGnTphQXF5eZ2MrNzWXlypW8+uqrvP322+jr67Np0yaGDRvGqlWraN++vVb7bt26MWLECK1jla3gPWjQoCrdg4mJic7vrVRQbWtry8qVKxk7dizvv/8+M2fOpEGDBlhYWJCVlcXly5fJy8vD0dGRZcuWSY5qoTFnzhz27dtHaGgoKpWK6OhozTlvb28UCgVjx45l8ODBzJw5k969exMVFUV4eDizZ8/W5KguL9vHTz/9RFJSktbs9dy5c9HT06NZs2ZYWVlx9uxZVq5cia+vLz179qzx+xVCCCGedSEhIXTp0gWA0NDQMjUlTE1N2bNnj2YJKMBzzz1Hr169WLt2bZmg2t7e/omoPVHpioqBgYH8+uuvbNiwgX379hEfH49KpUKhUODn50dISAgDBgzQ+mpfiEOHDgElwe691q5dS5s2bQgKCmL58uXMnz+frVu34ujoyIwZM8qtpvggXl5ebNiwgfDwcHJycnB0dOTll19mwoQJlf7qRwghhBBVd2/RtnsZGBhoBdSlxxo2bFjuUo+alpeXx5UrV6hbty7m5uZa5yIiIujVq1el+tGpTLmlpSWjR49m9OjRurxNPMMqm7M8ODiY4OBgnfouL1B//fXXef3113XqRwghhBAPduvWrTKJBaysrCq9FON+CgsLOXXqFG3bti1zbtu2bYSHh2NgYECLFi2YMmWKZnnow4qOjubdd99FrVaTl5fHmDFjtOLc2bNn10xQLarXxYsXa7T/kydP1mj/4sHkGdQ+eQa1T55B7ZNnUPuehmcwfPhwUlJStI6NGzeO8ePHP3Tf33zzDbdu3SqTaS4kJIQmTZrg6urKjRs3WLlyJYMGDWLz5s14e3s/9HXnzp1LaGgor7zyCnFxcUyfPp3Lly/z6aefoq+vr1OiAz21pEV45DIzM7l48SK+vr41tlymJKVeixrpW1SOPIPaJ8+g9skzqH3yDGrfk/4MSuMWKysrzMzMtM49aKa6dE313dk/7nXo0CHNSoiJEyfedyxpaWl0796djh07Mm/ePN1upBwtW7bkxIkTmte5ubmMGzcOU1NT5s+fT5s2bfjzzz8r1VelypQLIYQQQohnm7OzM+7u7lr/HnbpR0xMDOPHj6dnz55MmDDhge1tbGxo27YtMTExD3XdUpaWliQlJWlem5qasmLFCgwMDHj77bd1mqmWoFoIIYQQQjxyV69eZdSoUQQFBfHpp59WuiJ3dS6yaNeuHVu2bNE6ZmRkxIIFC3B3dyc3N7fSfcmaaiGEEEII8Ujdvn2bESNG4OLiwuLFiytdDjw1NZWjR4/ywgsvVMs4PvroI4qKisoc19fXJywsjHHjxlW6r6cmqC4qKqJfv3789ddfLFq0iJdeeklzLjIykoULFxIbG4uTkxPDhg1jyJAhZfpYtWoV69evJyUlBW9vb95//33atWun1UalUjFv3jx+++038vPzadOmDTNnzsTd3b3G71EIIYQQ4nGXk5NDZGQkADdu3EClUrFz506gJEWznZ0do0aNIi0tjQ8//JBLly5pvb80J3VERAT79u2jY8eOODk5cePGDb7++mvy8/MZNWpUlcd37do14uLiUKlUWFhY4O3tTd26dctt6+rqWul+dQ6qjx8/zrlz57RKkW/bto2lS5eiVCrp2bMnH3zwwQNzFFa3DRs2cPv27TLHo6OjGTNmDH369GH69OlERUURFhaGoaGhVh7kVatWsWDBAiZPnoy/vz/h4eGMHj2a8PBwGjVqpGk3depUYmJimDVrFgqFgsWLFzN8+HC2bdtWZvG+EEIIIcSz5s6dO2U2HJa+/uyzz2jdujXnz58H4L333ivz/gsXLgDg7u7O7du3mTt3LkqlEoVCQevWrVm8eDFeXl46j+u3335jyZIlxMXFlTnn7e3NuHHj6Natm879ltI5qF66dCk2NjaaoDouLo4ZM2ZQt25dGjduzPr163F3d9cqOV3TUlJSWLRoETNmzGDGjBllxuvv709YWBgAbdu2JTExkWXLltG/f3/09fXJz89nxYoVDB06lJEjRwLQunVrevfuzYoVK1i0aBEAp06d4vfff2flypWanMq+vr507dqVH3/8scqlMIUQQgghnhbu7u6awLgiDzoPJTPW69atq5YxLViwgJUrV6JQKOjTpw+NGjXSVAY/f/48e/fuZdKkSYwePZrJkydX6Ro6B9WxsbG8/fbbmtfbtm3D1NSU8PBwFAoFoaGhbNmy5ZEG1fPmzeP555+ndevWWsfz8/M5evQoU6dO1Treq1cvNm3aRExMDIGBgURFRZGZmalVxtrAwIDu3bvz7bffolar0dPTIzIyEktLSzp06KBp5+rqSvPmzdm/f78E1UIIIYQQj5kDBw7w1Vdf8eKLL/Lpp5+Wm85YpVIxc+ZMVq5cSatWrXj++ed1vo7OazQyMzO10qccOHCA9u3bo1AoAGjRogXXr1/XeSBVdfz4cXbv3s0//vGPMucSEhIoKCgo8xWBj48PAPHx8QCarwHubeft7U12drYm1UpcXByenp5llrZ4e3tr+rqXUqnk+vXrWv+Sk5OrcKdPph07djBmzBg6duxIs2bNePnllwkPDy+zczcyMpJXX32VwMBAunTp8sBPprt27aJhw4blVjlSqVTMnj1bUwL93XfffaQ/k0IIIYR4fKxbt46GDRuycOHCCuuDKBQK5s+fj6+vL2vWrKnSdXQOqh0cHIiNjQUgKSmJc+fOaUXzKpUKQ8NHs/+xsLCQjz/+mNGjR+Pi4lLmfGkpzXtzKJa+Lj2vVCoxNjbG1NRUq11pXfr09HRNu/IehpWVVZmynaXWrFlD586dtf49KLH502T16tWYmpoSGhrKihUrCA4OZvbs2SxZskTTpnTdu5+fH19//TV9+/YlLCyMDRs2lNtnTk4On332Gfb29uWenzp1Knv37mXWrFksWLCA27dvM3z4cHJycmrkHoUQQgjx+Dp9+jS9e/d+4H4/fX19evfuzZkzZ6p0HZ2j3xdffJH169dTUFDA6dOnMTY2JiQkRHP+/PnzFe6grG5r164lNzdXsw66IhXlPbz7eHltSmdTH9TufseHDRvGq6++qnUsPz+ftLS0+475abFixQpsbW01r9u1a0d6ejpr1qxh3Lhx6OvrV2rd+92WL1+Ou7s7bm5unD17VuucrHsXQgghxN2ys7OxsbGpVFtra2uys7OrdB2dZ6rHjx9Pt27d+OWXX0hJSSEsLEwzY6hSqdi1axft27ev0mB0kZqaypIlSxg7diy5ubkolUpUKhVQUmIyMzNTM9N87yyyUqkE/p6xtrKyIi8vj7y8vHLblfZjZWWlOXZvu4oqCllZWZWpPuTg4FDV237i3B1Ql/Lz80OlUpGXl6dZ996jRw+tNr169SI5OblMxaS4uDjWrVvHrFmzyr3eg9a9CyGEEOLZ4uTkxMWLFyvV9uLFizg6OlbpOjrPVJubm/Pvf/+7wnP79+8vs4yiJiQlJZGdnc306dPLnJs+fTqWlpYcPnwYIyMj4uPj6dixo+Z86fIVT09P4O+11HFxcfj7+2vaxcXFYWFhgZOTk6bd4cOHNRsX7+6vtC/xYCdPnsTNzQ0zMzNiY2MfuO49MDBQc/yTTz6hX79++Pr6ltv3/da9Hzx4sJrvRAghhBCPuw4dOhAeHs6bb75JvXr1Kmx39epVNm/eXGaFQWVVefHzzZs3OXbsGKmpqXTv3h0XFxeKi4vJz89/JPmaPTw8WLt2rdaxlJQUpkyZwvjx42nbti3Gxsa0bduWHTt2aGUjiYiIwMHBgYCAAACaN2+OpaUl27dv1wTVRUVF7Nixgw4dOmgC6ODgYJYtW8aBAwc0QXpiYiJRUVF88MEHNXq/Z2JTOBVb+Q2OiYkZnEs+V23Xb+rtQKB3+WuYdXHixAm2b9/OtGnTgMqvewf49ddfuXDhAosXL66w/6qsexdCCCHE0+udd94hIiKCN998k/fff58ePXpgbGysOZ+fn8/27dv5/PPPMTQ0ZPTo0VW6TpWC6s8++4zvv/+eoqIi9PT08PPzw8XFhdzcXLp27cqECRNqPKWehYUFbdq00TpWmuHB29ubli1bAjB27FgGDx7MzJkz6d27N1FRUYSHhzN79mzNbKaxsTHvvfceCxYswNbWVlP8JSEhgS+++ELTf9OmTenUqRMffvghoaGhKBQKFi1ahIuLC3379q3R+30a3Lp1i8mTJ9OqVasyPx8PWquuUqmYO3cuU6ZMqXCpTWX7EkIIIcSzw8nJiZUrVzJ+/HhmzJjBP//5Txo0aIBCoUClUnH58mXy8/Oxs7Pjq6++0qxQ0JXOQfU333zDmjVrGDlyJM8//zxvvfWW5pxCoaBr167s3r37keapvp+goCCWL1/O/Pnz2bp1K46OjsyYMUOrmiKg2ey4bt06UlJS8PHxYeXKlVrVFAG++OIL5s2bx5w5czRlyhctWlTjs/OB3vY6zRSfPJlNixZ+NTgi3SiVSkaNGoW1tTXLli3DwMAAoNLr3r/88kusra3p2rWr5lxBQQHFxcUolUpMTU0xNjbGysqKxMTEcq//oGBcCCGEEE+nZs2asX37djZs2MC+ffuIi4sjKysLCwsL/Pz8CAkJYcCAAQ8VK+gcVIeHh/Pyyy/z/vvvl5vBwtfXt9bWrlZUwSc4OFiTCeJ+Ro4c+cBMIgqFgo8//piPP/64yuN81uTm5vLOO++QmZnJxo0btZZneHh4VGrde3x8PBcvXizz7QRAq1atmDFjBsOHD5d170IIIYQol6WlJaNHj67y8o4H0Tn7x82bNzVLK8qjUCjKzZAhnk2FhYVMmjSJ+Ph4vvnmmzJfqdy97v1u9657nzRpEmvXrtX69/zzz+Pm5sbatWt56aWXgJIPUEqlkgMHDmj6Kl33fnfQLoQQQghRnXSeqba2tub27dsVnr948WKV16KIp8+cOXPYt28foaGhqFQqoqOjNee8vb1RKBSVWvdeXraPn376iaSkJK3Za1n3LoQQQoi7JScnM2TIELp168bkyZMrbLdgwQJ27drF+vXry00J/CA6z1R36tSJTZs2kZqaWubcX3/9xebNm+nSpYvOAxFPp0OHDgEwd+5c+vfvr/WvNAd16br3M2fOMHLkSMLDw8td915ZX3zxBS+88AJz5sxh4sSJODg48N133z2SrDRCCCGEeLysXbuW9PR0Ro0add92o0aNIi0tjXXr1lXpOjrPVE+YMIGDBw/y8ssv06lTJ/T09NiyZQubNm1i9+7duLm58d5771VpMOLps3fv3kq1q+y697vNnTu33OOy7l0IIYQQpSIjI+nZsycKheK+7RQKBb169WLv3r1MnDhR5+voPFPt4ODAli1beOGFF9i9ezdqtZqIiAgOHDhAnz592LBhgyajgxBCCCGEELUpISGBhg0bVqqtr68vV69erdJ1qpSn2tbWlk8++YRPPvmE1NRUiouLsbW1LVPFTgghhBBCiNqkp6dHcXFxpdoWFxdXua7FQ0fBtra22NvbS0AthBBCCCEeO25ubpw+fbpSbc+cOYObm1uVrlPlMuUqlYrExEQyMjJQq9Vlzrdq1aqqXQshhBBCCFEtOnXqxLp16xg5ciReXl4VtouLiyMiIoKhQ4dW6To6B9UZGRl88skn7Ny5k6KiojLnS4tunDt3rkoDEkIIIYQQorqMGDGCLVu2MGzYMEJDQ3nppZcwNPw7BC4sLGTnzp3MnTsXhUKhVS1cFzoH1bNnz2bPnj0MGjSI1q1bS+lnIYQQQgjx2LK1tWXlypWMHTuW999/n5kzZ9KgQQMsLCzIysri8uXL5OXl4ejoyLJly6qUoxqqEFTv37+fIUOGEBoaWqULCiGEEEII8SgFBgby66+/smHDBvbt20d8fDwqlQqFQoGfnx8hISEMGDAAS0vLKl9D56Da2NiYevXqVfmCQgghhBBCPGqWlpaMHj2a0aNH10j/Oqfs6NatG/v376+JsQghhBBCCPFE0jmoHjlyJLdv32b69OlER0dz+/Zt7ty5U+afEEIIIYQQzwqdl39069YNPT09YmJi+OWXXypsJ9k/BMCOHTvYtm0bZ8+eRalU4uHhwZAhQ+jXr59WcvXIyEgWLlxIbGwsTk5ODBs2jCFDhmjOFxYW8v7773P27Flu376NiYkJvr6+vPfeezz33HOadtevX6dz585lxuHj40NERETN3qwQQgghnlk6B9Vjx46tcqUZ8exZvXo1bm5uhIaGYmNjw+HDh5k9ezaJiYlMmDABgOjoaMaMGUOfPn2YPn06UVFRhIWFYWhoyMCBA4GSCkfFxcWMHDkSDw8P8vLy2Lx5M6NGjWLt2rW0bNlS67pTpkyhTZs2mtempqaP7qaFEEII8czROageP358TYxDPKVWrFihlZqmXbt2pKens2bNGsaNG4e+vj5Lly7F39+fsLAwANq2bUtiYiLLli2jf//+6OvrY2xszKJFi7T67tixI507d+bnn38uE1TXq1ePZs2a1fj9CSGEEELAQ5QpV6lUXLp0iRMnTnD8+PEy/4QAys316Ofnh0qlIi8vj/z8fI4ePUqPHj202vTq1Yvk5GRiYmIq7NvAwABLS0sKCwurfdxCCCGEePocP36c1NTUCs+npqZWOY6tloqKpWXK9fT0pKKieKCTJ0/i5uaGmZkZsbGxFBQUlCkb6uPjA0B8fDyBgYGa42q1mqKiIpRKJT/99BNXr17l448/LnONOXPmMGXKFCwtLQkJCWHatGnY2dnV7I0JIYQQ4rE2dOhQ5s2bR+/evcs9f/ToUaZOnVqlOFYqKj4hLiakcTEhrdLtExJUJObEV9v1fT1s8PWweeh+Tpw4wfbt25k2bRpQ8iENKPNzVPq69HypNWvW8NlnnwFgbm7OggULCAoK0pw3NjZm4MCBPP/881hZWRETE8OXX35JdHQ0P/30k6ytFkIIIZ5hpRPBFcnPz0dfv2oLOaSionhkbt26xeTJk2nVqhXDhw/XOlfR5td7j/fu3ZsWLVqQmprKzp07mTRpEkuXLiU4OBgAR0dHPvroI0371q1bExAQwJAhQ4iIiKBfv37Vek9CCCGEeLypVCqUSqXmdXp6Ojdv3izTTqlU8uuvv+Lk5FSl60hFxSeErjPFJ0+m0aKFZw2OSDdKpZJRo0ZhbW3NsmXLMDAwAKBOnTpA2Rnp0h/+e2ew7ezsNMs4goODSUtL49///rcmqC5P69atsbOzIyYmRoJqIYQQ4hmzevVqli1bBpRM1oWFhWmSI9xLrVYzefLkKl2nSnmq9+/fr0l1JsSD5Obm8s4775CZmcnGjRuxtLTUnPPw8MDIyIj4+Hg6duyoOR4bGwuAp+f9PxgEBARw6NChB47hQV/3CCGEEOLp1K5dO4yNjQGYP38+PXr0oFGjRlpt9PT0MDc3p3HjxjRt2rRK19E5qB45ciRTpkxh+vTpDBw4EFdXV82s491kU5iAkqItkyZNIj4+nvXr15f5SsXY2Ji2bduyY8cOrSUhERERODg4EBAQcN/+T5w4Qd26de/b5ujRo6SmpmpteBRCCCHEs6FFixa0aNECKFkz/eKLL+Lr61vt15GKiqJGzZkzh3379hEaGopKpSI6OlpzztvbG4VCwdixYxk8eDAzZ86kd+/eREVFER4ezuzZszWbBSIiIvj999/p2LEjTk5OpKWl8fPPP3P06FHmz5+v6XPu3Lno6enRrFkzrKysOHv2LCtXrsTX15eePXs+6tsXQgghxGNk3LhxNda3VFQUNap0acbcuXPLnFu7di1t2rQhKCiI5cuXM3/+fLZu3YqjoyMzZszQWmLk6elJREQE8+bNIz09HVtbWxo2bMj3339Pq1atNO28vLzYsGED4eHh5OTk4OjoyMsvv8yECRMwMTGp+RsWQgghxGNnw4YNODg40KVLF6Bk8+KYMWPKtHNzc9NkGdOVVFQUNWrv3r2VahccHHzfzYb+/v58+eWXD+zn9ddf5/XXX6/0+IQQQgjxdNuzZw8ff/wxa9as0RwrKCjg2LFjuLi4aNLtqtVqjh8/Trdu3ejUqZPO19E5qBZCCCGEEOJJsW3bNpo0aULr1q3LnAsLC6Ndu3aa1/379+fnn3+uUlBd5TLlABcuXGDv3r3s3buXCxcuPExXQgghhBDiKXD16lVmz55Nnz598Pf3p1evXuW2i4yM5NVXXyUwMJAuXbqwbt26ctutWrWKkJAQmjRpQt++fTly5IhO4zlz5oxWhrH76dSpE6dOndKp/1JVmqnes2cPYWFhJCYmah13dXVlxowZmvUqQgghhBDi2XLp0iUiIyNp2rQpxcXF5aa1jY6OZsyYMfTp04fp06cTFRVFWFgYhoaGWnuqVq1axYIFC5g8eTL+/v6Eh4czevRowsPDy6TFq0hycjIuLi5ax0xNTRk0aFCZ446OjqSkpFThrqtYUXHChAk4OzszefJkvLy8UKvVxMfH85///IeJEyfy5Zdf0qFDhyoNSAghhBBCPLlCQkI0E6yhoaGcPXu2TJulS5fi7++vKcLStm1bEhMTWbZsGf3790dfX5/8/HxWrFjB0KFDGTlyJFBS0K13796sWLGCRYsWVWo8xsbG5OTkaB0zMzNj1qxZZdrm5uZiaFi11dE6L/9Yvnw5Xl5e/PLLL4wePZrOnTvTpUsXRo8ezS+//IKnpyfLly+v0mCEEEIIIcSTrTQdbkXy8/M5evQoPXr00Dreq1cvkpOTiYmJASAqKorMzEytlLgGBgZ0796d/fv3V7qwm4eHR6WXdERHR+Ph4VGptvfSOag+f/48r732GgqFosw5hULBa6+9JjmqhRBCCCGeMrdu3eL69eta/5RKpc79JCQkUFBQgJeXl9ZxHx8fAOLj4wGIi4sDKNPO29ub7OxskpKSKnW9Tp06sXPnTk1/FYmNjWXnzp2EhIRUqt976Ty/bWRkRHZ2doXns7KyMDIyqtJgnjUXL16s0f5PnjxZo/2LB5NnUPvkGdQ+eQa1T55B7XsansHw4cPLrDceN26czumWMzIyALCystI6Xvq69LxSqcTY2FiT8q5UnTp1AEhPT8fZ2blS4w4PD2fYsGF88MEHvPjii1pLPAoLC9m5cydz587F2tqaoUOH6nQ/pXQOqlu0aMH69evp0aMH9evX1zp39epVfvjhB1q2bFmlwTxrfH19sbS0rJG+T548qSnJKWqHPIPaJ8+g9skzqH3yDGrfk/4MMjMzuXjxIqtXr8bMzEzr3L2BsS4qKiZ49/Hy2pQu+6hsMcI6deqwcuVK3nvvPaZOnYqpqSn169fHwsKCrKwsLl++TF5eHk5OTixfvhxra2vdb4YqBNVTpkxh4MCB9OrVi5CQEBo0aADA5cuX2bdvHyYmJkydOrVKgxFCCCGEEI8nZ2fnapkMLJ1pLp2RLlW6lKQ0ULeysiIvL4+8vDytqsil7Ur7qQx/f39+/fVXNmzYwL59+4iLi0OlUqFQKPD39yckJIQBAwaUu7y5snQOqn19fdmyZQvz58/nwIED7Nq1CyjZRfnCCy8wefJkTaAthBBCCCHE3Tw8PDAyMiI+Pl4rf3RsbCwAnp6ewN9rqePi4vD399e0i4uLw8LCAicnJ52uq1AoGDVqFKNGjXrYWyiXzkH18ePH8fLyYvHixRQXF5OamgqAra0t+vr6pKamcvz4cVq1alXtgxVPnh07drBt2zbOnj2LUqnEw8ODIUOG0K9fP62vbSIjI1m4cCGxsbE4OTkxbNgwhgwZojlfWFjI+++/z9mzZ7l9+zYmJib4+vry3nvv8dxzz2ldU6VSMW/ePH777Tfy8/Np06YNM2fOxN3d/ZHdtxBCCCHKZ2xsTNu2bdmxYwfDhw/XHI+IiMDBwYGAgAAAmjdvjqWlJdu3b9cE1UVFRezYsYMOHTpUevnHo6Jz9o+hQ4dy6NChkjfr62Nvb4+9vb0mfcrRo0ervMBbPH1Wr16NqakpoaGhrFixguDgYGbPns2SJUs0bUoTwPv5+fH111/Tt29fwsLC2LBhg6ZNcXExxcXFjBw5khUrVvCvf/2LOnXqMGrUKE6cOKF1zalTp7J3715mzZrFggULuH37NsOHDy+To1IIIYQQ1S8nJ4edO3eyc+dObty4gUql0noNMHbsWM6ePcvMmTP5448/WLFiBeHh4YwdO1YTUxobG/Pee++xevVqvv32W44ePco//vEPEhISeO+99yo1lqpkJ6nqe3WeqX5QTsD8/PwH5icUz44VK1Zga2ured2uXTvS09NZs2YN48aNQ19fv1IJ4I2Njcskee/YsSOdO3fm559/1myOPXXqFL///jsrV64kODgYKFmy1LVrV3788UcGDRr0iO5cCCGEeDbduXOHiRMnah0rff3ZZ5/Rt29fgoKCWL58OfPnz2fr1q04OjoyY8YMrWqKgKboy7p160hJScHHx4eVK1dWuppip06dGDRoEP3796/0N9bXrl3jhx9+YNOmTTplbalUUK1SqbSi9fT0dG7evFmmnVKp5Ndff9V5jYt4et0dUJfy8/Nj06ZN5OXlYWBgwNGjR8tsbu3VqxebNm0iJiaGwMDAcvs2MDDA0tKSwsJCzbHIyEgsLS21Knq6urrSvHlz9u/fL0G1EEIIUcPc3d25cOHCA9sFBwdrJsDuZ+TIkZrgWlfz5s1j0aJFfPPNNzRp0oR27drRuHFj3N3dqVOnDmq1GqVSyfXr1zlz5gyHDx/m7NmzeHt7869//Uuna1UqqF69ejXLli0DStKXhIWFaWYV76VWq5k8ebJOgxDPlpMnT+Lm5oaZmRmxsbEPTAB/d1CtVqspKipCqVTy008/cfXqVT7++GPN+bi4ODw9Pct8W+Lt7c3Bgwdr8K6EEEII8bjp0qULnTt3JjIykh9//JHvvvuOvLy8Muux1Wo1JiYmdOjQgbFjxxIcHKzzmu1KBdXt2rXD2NgYgPnz59OjR48y0+56enqYm5vTuHFjmjZtqtMgxINdS8ok4VZmpdvHJWSTa1j224Sq8nC2pK7Tw6fROXHiBNu3b2fatGlA5RPAl1qzZg2fffYZAObm5ixYsICgoCDNeaVSWW66HysrqzJ9CSGEEOLpp6enR6dOnejUqRMFBQWcPXuW+Ph40tLSALCxscHLy4uAgICHKmBYqaC6RYsWmqTl+fn5vPjii/j6+lb5ouLZdOvWLSZPnkyrVq20dvtC5RLAA/Tu3ZsWLVqQmprKzp07mTRpEkuXLtX6+qiyfQkhhBDi2WJkZERQUJDWhFx10Xmj4rhx46p9EOLB6jrpNlNsWphIi6auNTgi3SiVSkaNGoW1tTXLli3DwMAAqHwC+FJ2dnbY2dkBJWux0tLS+Pe//60Jqq2srEhMTCz3+g9T9UkIIYQQ4n4kTYeocbm5ubzzzjtkZmbyzTffaC3PuDsB/N3uTQBfkYCAAK5evap57eXlxeXLl8tkqYmNjX1gX0IIIYQQVSVBtahRhYWFTJo0ifj4eL755psymWHuTgB/t3sTwFfkxIkT1K1bV/M6ODgYpVLJgQMHNMcSExOJiorSqtokhBBCCFGddF7+IYQu5syZw759+wgNDUWlUhEdHa055+3tjUKhYOzYsQwePJiZM2fSu3dvoqKiCA8PZ/bs2ZosHhEREfz+++907NgRJycn0tLS+Pnnnzl69Cjz58/X9Nm0aVM6derEhx9+SGhoKAqFgkWLFuHi4kLfvn0f9e0LIYQQ4hnxxAbVu3bt4rvvviM+Pp7s7GycnJzo2rUrY8aM0Vpe8KDy16VWrVrF+vXrSUlJwdvbm/fff5927dpptZHy17orrb45d+7cMufWrl1LmzZtKpUA3tPTk4iICObNm0d6ejq2trY0bNiQ77//nlatWmn1+8UXXzBv3jzmzJmjeU6LFi3CzMysZm9WCCGEEM+sJzaozsjIoFWrVrz11lvUqVOHixcvsnTpUi5cuMC3334L/F3+uk+fPkyfPp2oqCjCwsIwNDTUCthWrVrFggULmDx5Mv7+/oSHhzN69GjCw8O1UgdOnTqVmJgYZs2ahUKhYPHixQwfPpxt27ZJwFaBvXv3VqrdgxLA+/v78+WXX1aqL4VCwccff6yVv1qIJ01OXiFXE5U0ql+2gJIQQojHT5WDapVKRWJiIhkZGeWWLr939rC6vf7661qv27Rpg4mJCbNmzSIpKQknJ6dKlb/Oz89nxYoVDB06VFOtp3Xr1vTu3ZsVK1ZoSmNL+WshxKNQVKwmMuo6m/deJCungGX/6IzCrOp5U4UQQvzt+PHjnDt3jqFDh2qObdu2jaVLl6JUKunZsycffPBBmSJylaFzUJ2RkcEnn3zCzp07KSoqKnNerVajp6fHuXPndB7Mw7K2tgZKNsfl5+dXqvx1VFQUmZmZ9OzZU9PGwMCA7t278+2332ruR8pfCyFq2unYZH747QLXkjLxqWvN4IF+ElALIUQ1Wrp0KTY2NpqgOi4ujhkzZlC3bl0aN27M+vXrcXd3L1NPozJ0Dqpnz57Nnj17GDRoEK1bt6713L9FRUUUFhZy6dIlli1bxgsvvICbm1uly1/HxcUBlGnn7e1NdnY2SUlJODs7V7n8tVKp1ORcLpWfn1/l+xVCPH2uJWXyw2/nOR2bgqONGRP7B9HK30kKFgkhRDWLjY3l7bff1rzetm0bpqamhIeHo1AoCA0NZcuWLY8mqN6/fz9DhgwhNDRU54vVhDZt2pCZWVK+u0OHDppMEJUtf61UKjE2NsbU1FSrXWlRkvT0dJydnatc/nrNmjUsXbpU65ivry8fffRRZW9RCPGUylDlsXnvJX4/eR1TEwPe7NaIF9vUw8hQsp0KIURNyMzM1IoNDxw4QPv27VEoFEBJFfHffvutSn3rHFQbGxtTr169Kl2sJqxbt46cnBwuXbrEihUrePfdd/nuu+805ytTsrq8NqXrxB/U7n7HAYYNG8arr76qdSw/P19Tb14I8ezJLyhix5Er/LI/joLCYrq28eDVTt5YmhvX9tCEEOKp5uDgoCkwl5SUxLlz5+jfv7/mvEqlwtCwalsOdX5Xt27d2L9/v1b2jNrk5+cHQPPmzQkICOC1115j9+7deHt7Aw8uf21lZUVeXh55eXmYmJiUaVc6Y13V8tdWVlZlzmdmZkpQLcQzqLhYzZEziWzcc4E7Gbm0aOTIwBcb4WJvUdtDE0KIZ8KLL77I+vXrKSgo4PTp0xgbGxMSEqI5f/78ea2icrrQ+TvGkSNHcvv2baZPn050dDS3b9/mzp07Zf7VBj8/P/T19UlISKh0+evStdSla6tLxcXFYWFhoakAKOWvhRAP4/zVVP759RGWbzmFpbkxH77VmilvtpCAWgghHqHx48fTrVs3fvnlF1JSUggLC8Pe3h4omaXetWsX7du3r1LfVZqp1tPTIyYmhl9++aXCdrWR/SMqKori4mLc3d21yl/fvdj83vLXzZs3x9LSku3bt+Pv7w+UbH7csWMHHTp00CztCA4OZtmyZRw4cEBT7rq0/PUHH3zwaG9UCPHEuHUni//svsDxv5KwtTLl3Veb8FxTV/T1ZROiEEI8aubm5vz73/+u8Nz+/fvL7LOrLJ2D6rFjxz4WO9JHjhxJ27Zt8fHxwdjYmL/++otVq1bRsGFDunTpAlCp8tfGxsa89957LFiwAFtbW03xl4SEBL744gvN9aT8tRBCF6rsfH6KjGPPsasYGOjTL8SHHs81wMTIoLaHJoQQz7yaqLeic1A9fvx4nS9SE5o0acIvv/zC9evXAXB3d+fNN9/krbfewti4ZLNPZcpfA5qiL+vWrSMlJQUfHx9WrlypVU0RpPy1EOLBCgqL2XM8gZ9+jyUnt5COzd3oF+KDjWXVZj6EEEJUn5qst/LElimfOHEiEydOfGC7B5W/LjVy5EhNcF0RKX+tux07drBt2zbOnj2LUqnEw8ODIUOG0K9fP61vPCIjI1m4cCGxsbE4OTkxbNgwhgwZojl/+/ZtVq9ezaFDh0hISEChUNCyZUumTJmitaHg+vXrdO7cucw4fHx8iIiIqNmbFc80tVrNiXNJbNh1gaTUbAK97HmzW0M8nGs3l78QQoi/1WS9lYcKqi9cuMCNGzcAcHNzo2HDhtUyKPH0WL16NW5uboSGhmJjY8Phw4eZPXs2iYmJTJgwAYDo6GjGjBlDnz59mD59OlFRUYSFhWFoaKj5ViEmJobdu3fz2muv0bRpU9LS0lixYgVvvPEGERER2NnZaV13ypQptGnTRvO6quujhKiM+BsZfL/zHBeupuHmoOAfg1vSxMf+sVgqJ4QQ4m81WW+lSkH1nj17CAsLK5NiztXVlRkzZmjWNAuxYsUKbG1tNa/btWtHeno6a9asYdy4cejr67N06VL8/f0JCwsDoG3btiQmJrJs2TL69++Pvr4+LVq0YMeOHVq5I5s3b06nTp34+eefGTFihNZ169WrR7NmzR7JPYpn152MHDbuucihUzexNDfmrV4BvNDCHQMDKd4ihBCPo5qst6Lzb/79+/drZhgnT57M0qVLWbJkCZMnT0atVjNx4kQOHDhQ7QMVT6a7A+pSfn5+qFQq8vLyyM/P5+jRo/To0UOrTa9evUhOTiYmJgYoyfd9bzJ2Z2dnbG1tay2Fo3h25eQVsnHPBaYu2s8fZ2/xcgdP5k/qSJfWHhJQCyHEY6y03kpN0Hmmevny5Xh5ebFhwwZNScdSb775JgMHDmT58uV06NCh2gYp4HZaNrdTsyvd/srtPEziUqrt+o625jjamFdLXydPnsTNzQ0zMzNiY2MpKCjQ5Asv5ePjA0B8fDyBgYHl9nP58mXu3LmjKfRztzlz5jBlyhQsLS0JCQlh2rRpZZaICKGroqJiIv+8Tvh/L6HMyqd9E1fe6OyLg41sVhZCiCfByJEjmTJlCtOnT2fgwIG4urpiYFA2K1NVYgadg+rz588zadKkMgE1lGzke+2111i4cKHOAxHPhhMnTrB9+3amTZsG/F3x8t6NAqWv762IWUqtVvN///d/ODg40LVrV81xY2NjBg4cyPPPP4+VlRUxMTF8+eWXREdH89NPP8naalFlp2OTWb/zPNdvq/D1sGHqoBZ4u1vX9rCEEELooCbrregcVBsZGZGdXfGMaVZWFkZGRjoPRNyfo41uM8V56Vdp7GVfgyPS3a1bt5g8eTKtWrXSKsgDVLihq6LjS5Ys4ciRI6xcuVLrA56joyMfffSR5nXr1q0JCAhgyJAhRERE0K9fv4e+D/FsuZaUyfrfznMmNgVHGzMmDgiilZ+TbEIUQognUE3WW9E5qG7RogXr16+nR48e1K9fX+vc1atX+eGHH2jZsmV1jU88JZRKJaNGjcLa2pply5ZpvmqpU6cOUHZGWqlUAmVnsAE2bdrEsmXL+L//+z+ef/75B167devW2NnZERMTI0G1qLT0zDw2771EZNR1zEwMGfRSI7q2roeRoayZFkKIJ1VN1lvROaieOnUqAwYMoFevXoSEhNCgQQOgZH3rvn37MDU1ZerUqdU+UPHkys3N5Z133iEzM5ONGzdiaWmpOefh4YGRkRHx8fGa8u8AsbGxAHh6emr1tXv3bj766CMmTJjA66+/XukxlFctSYjy5BcUsf3wFbYdiKOgsJiubTx4tZM3lubGtT00IYQQjzGdg2ofHx+2bNnC/PnzOXDgALt27QLAzMyMF154gcmTJ2sCbSEKCwuZNGkS8fHxrF+/HicnJ63zxsbGtG3blh07dmgtCYmIiMDBwYGAgADNsT/++IMpU6bw+uuvM3bs2EqP4ejRo6Smpla44VEIgOJiNYfP3GTj7oukKnNp6efEgK4NcbG3qO2hCSGEqAHVXW+lSnmq69evz+LFiykuLiY1NRUoSZ2mry9fiwptc+bMYd++fYSGhqJSqYiOjtac8/b2RqFQMHbsWAYPHszMmTPp3bs3UVFRhIeHM3v2bM3PVFxcHGPHjqV+/fr06dNHqx+FQqHJADJ37lz09PRo1qwZVlZWnD17lpUrV+Lr60vPnj0f5a2LJ8j5K6ms33me+JsZ1HexYsxrTfFrUDYdpBBCiCdfTdVbeWBQffPmTc2F7n59r1u3bpUZmBCHDh0CSoLde61du5Y2bdoQFBTE8uXLmT9/Plu3bsXR0ZEZM2ZoqikCnDp1iszMTDIzM7WOQ8ma6XXr1gFo0j2Gh4eTk5ODo6MjL7/8MhMmTMDExKQG71Q8iW7dyWLDrgucOJeErZUp7/ZtwnNNXNHXl02IQgjxNCqtt+Ls7MzkyZPx8vJCrVYTHx/Pf/7zHyZOnMiXX35ZpdTQDwyqQ0JC0NPT49SpUxgbG2teP0hVUpGIp8/evXsr1S44OJjg4OAKz/ft25e+ffs+sJ/XX39dp7XW4tmkys7nx99j2XMsAUNDfV7v7EP39g0wMSqbq1QIIcTToybrrTwwqA4LC0NPT0+TJq/0tRBCPGkKCovZc+wqP0XGkZNbSHBzd/qF+GBtKd9iCCHEs6Am6608MKi+d3awMrOFQgjxOFGr1Rw/l8SGXRe4nZpNoJc9g15qRF0nywe/WQghxFOjJuutVGmjohBCPCnirqfz/c7zXExIw81BwT8Gt6SJj/1j9Y2bWq1GmZVPcloOt9OyuZ2WQ3J6NoWFxYx8uTHGsixFCCGqRU3WW6n0RkVdyUZFIURtSknPIeJYGhcTj2BlYcyI3gF0au6OgUHtZSnKySskuTRoTssmOT2H26klAXR+QZGmnaGBPg425ng4W/IYxf5CCPHEq8l6K5XeqKgr2agohKgNyqx8ftkfx+5jCRQU5NOnky+9n/fE3LRqX+fpqqCwmDsZOST/b7Y5KfXvAFqVna9pp6enh62VKQ42Zni6ueBoa4ajjTkO1mbUUZhIBhIhhKgBNVlvpdIbFYUQ4nGWk1fIjsOX+fXQZfILinm+qSs+DjmEdHi4ZP7lKS5Wk67Ku2vWOUfzv9Myc7UqeCrMjXG0MSfA0w5HGzMcrM1xsDHDro6ZlDwXQjx1hgwZwrFjx8o9N3XqVEaPHk1oaCg//fRTmfOLFi3ipZdequkh1li9FZ03KgohxOOkoLCIPcev8XNkLJnZBbTyd6JfiA/ujpacPHnyofpW5RSUzDLfFTTfTssmJT2HwqJiTTsTY0McrM2o52JJS38nHKzNSgJoG3PMTGTrihDi2fHPf/4TlUqldeznn3/mhx9+oGPHjppjdevW5fPPP9dqd+8a5+rwKOutyG97IcQTqaiomAOnbvLjvkvcycglwNOON7r44u1urVM/+QVFJKfnaILn0k2CyWk5ZOcWaNrp6+thV6dkiUaj+rb/C5xLZp2tLIzlGz0hhABNheO7/d///R++vr40atRIc8zU1JRmzZrV+HgeZb0V2agohHiilKbHC99zkZspWXi61mHUK4EEetlX+J6iYjVpyty/M2v8b41zcloO6Zm5Wm3rKExwtDGnma8DDv9b4+xgY4adlWmtbnIUQogn0ZUrVzhz5gzTpk2rles/ynorslFR1KgdO3awbds2zp49i1KpxMPDgyFDhtCvXz+tn6vIyEgWLlxIbGwsTk5ODBs2jCFDhmjO3759m9WrV3Po0CESEhJQKBS0bNmSKVOmULduXa1rqlQq5s2bx2+//UZ+fj5t2rRh5syZuLu7P7L7FjXjTFwKm/ZcJP5GBq72FkwcEEQrP6cyv6MKCos4dOomh06ms+vsMe6k51JU/PdyDVMTQxxtzPFyr4OjjUvJrLOtOXZ1TDE1li/whBCiuvzyyy/o6+vTu3dvreMJCQm0bNmSnJwcfHx8GD16ND169Kj26z/KeiuyUVHUqNWrV+Pm5kZoaCg2NjYcPnyY2bNnk5iYyIQJEwCIjo5mzJgx9OnTh+nTpxMVFUVYWBiGhoYMHDgQgJiYGHbv3s1rr71G06ZNSUtLY8WKFbzxxhtERERgZ2enuebUqVOJiYlh1qxZKBQKFi9ezPDhw9m2bRtmZma18v+DeDix19PZtOciMfF3sKtjyuhXAnm+qWuZmePiYjVRF27z66HLpGfmYqxXREMXCxp72uNoUxI4O1ibYWFmJL/XhBBCR7du3SIjI0PrmJWVFVZWVhW+JyIiglatWuHs7Kw55ufnR2BgIN7e3mRmZrJ582YmT55Mbm5uje/lO378OF5eXtja2pZ7PjU1lbi4OFq1aqVz33rqu7epi0ciMzOTixcv1vYwhBBCCCEqbcKECaSkpGgdGzduHOPHjy+3fXR0NP379+fTTz+lX79+9+176NChJCQk8Pvvv1fXcMvl5+fHvHnzysycl9q+fTtTp06t2TXVD9o1eS9ZU/1gvr6+WFrWTJnkkydP0qJFixrp+2H98MMPzJkzh+joaAwMDGjevDlTp07lrbfe0rT5448/GDp0KJs3byYwMLDCvtq3b8+rr77K+++/D8DixYtZu3Ytx44d00qNM2TIEMzNzfnqq69q7sbu8Tg/g8ddcloOP+67xMFTNzE2NqBn+/p0b9+g3Ewat1Oz2XYwnrNxKdRRmNDreU+aN3REX19PnsFjQJ5B7ZNnUPue9GdQOhm4evXqMt/43m+W+pdffsHExKRSafJeeukl5syZQ2pqaoWzyNXhQXPJ+fn5VU6tV+k11Y9i16R4Npw8eRI3NzfMzMyIjY2loKAALy8vrTY+Pj4AxMfHVxhUX758mTt37mjtNI6Li8PT07PMfxDe3t4cPHiwmu9EVLcMVR4/74/jv8evAdCtbT1e7uiFlYVxmbaq7Hx+O3qVw2duYmRoQI/2DejUwh0jw6enpLdarZZlKkKIx4azs3OlJwMLCwvZsWMHL7zwAgqF4oHta3LhhEqlQqlUal6np6eXO0msVCr59ddfcXJyqtJ1Kr2m+lHsmhQVU2blk3lXNbYHSVEWcCNZ9eCGlWRpblxuYKOrEydOsH37ds0u4NK1Wfd+0i19fe/arVJqtZr/+7//w8HBga5du2qOK5XKcv+Dt7KyqrAvUfuycwvYfvgKOw6XFG7pGORG3xe8satTdg18QWExB6Kvs+uPBPILimgX6MJL7epjaf7wP5+1La+giGu3MrmSqORKopLM7Hze7dtEcl0LIZ44Bw8eJDU1lZdffvmBbdVqNTt37sTNza1GZqlXr17NsmXLgJJqtmFhYYSFhVU4lsmTJ1fpOjoXf5FiMKKqbt26xeTJk2nVqhXDhw/XOlfRB7WKji9ZsoQjR46wcuXKMp+Ade1L1J6CwiJ2H0vgl/1xZGYX0Nrfmdc7++DqUHZWo7hYTfTFZCIOxZOmzMW/gR29O3jibGdRCyOvHoVFxdy4reJKopKrt5TcTM6iWK3G0EAfd0cFTX3sMTV+embehRDPjl9++QVra2utgi8AN27cIDQ0lJ49e1KvXj2USiXh4eEcO3aMefPm1chY2rVrh7FxycTL/Pnz6dGjh1bObCiJEczNzWncuDFNmzat0nVk+uMJYWWh20zxLSsj3MoJTGqLUqlk1KhRWFtbs2zZMgwMSgKFOnXqAGVnpEu/pilvrdamTZtYtmwZ//d//8fzzz+vdc7KyorExMRyr3+/dV/i0SoqKuZA9A227IslVZlLoLc9/bv40sC1Trnt466n8/P+OK4lZeLqoGDAa03x9bB5xKN+eMXFam7dySoJohOVXLutorCoGD09cLGzoG2gC/VdrHBzUEgJcyHEEysrK4u9e/fyyiuvaFY6lLKwsEChULBixQru3LmDkZER/v7+rFixgpCQkBoZT4sWLTRr2vPz83nxxRfx9fWt9utIUC1qXG5uLu+88w6ZmZls3LhRa3mGh4cHRkZGxMfHa32ajY2NBcDT01Orr927d/PRRx8xYcIEXn/99TLX8vLy4vDhw2XWosbGxpbpSzx6arWa438lsem/F0lMycLb3Zp3+zYhwNOu3Pa307KJOHiZM7HJ1FGYMLBbI1o2ckJf/8n41kGtVpOSnsuVxAyuJCpJSMokL78IAAcbM4J8HajvakVdJ0vJjy2EeGpYWFgQHR1d7jlra2tWrFjxaAd0lxEjRpCenl7h+Zs3b2JjY1OlFLxV+i3+3//+l82bN3Pt2jUyMjLKLC7X09PjwIEDVelaPGUKCwuZNGkS8fHxrF+/vszif2NjY9q2bcuOHTu0loRERETg4OBAQECA5tgff/zBlClTeP311xk7dmy51wsODmbZsmUcOHBAE6QnJiYSFRXFBx98UP03KCpFrVZrCrdcvqnEzUHB5IHNadHIsdxlOVk5Bez64yoHT93A0ECf7u0b0Km5O8ZGj/9SiPTMPK4mKrmcqCThlhJVTkmpc2tLE/zq21LP2Yp6LlYozIwe0JMQQojq9tlnn3HmzBm2bt1a7vmxY8fStGlTPvroI5371jmoXrp0KcuWLcPKyoqGDRtSr149nS8qnh1z5sxh3759hIaGolKptD65ent7o1AoGDt2LIMHD2bmzJn07t2bqKgowsPDmT17tiaLR1xcHGPHjqV+/fr06dNHqx+FQqHJANK0aVM6derEhx9+SGhoKAqFgkWLFuHi4iL7AWpJ7LV0Nu65wF+XU7G3NuPdV5vQvqkrBuXMNhcUFnPw1A12/5FAbn4hbRuXbEKsjk2yNUWVU8DV/62JvnJTSboqDwCFmRH1XKyo/78g2trSpJZHKoQQ4tChQ/eNB7p06cJPP/1Upb51DqrXr19Pu3bt+PLLLzWLvoWoyKFDhwCYO3dumXNr166lTZs2BAUFsXz5cubPn8/WrVtxdHRkxowZmmqKAKdOnSIzM5PMzEyt4wCtW7dm3bp1mtdffPEF8+bNY86cOZoy5YsWLZJqio/YtaRMNu+9xIlzSViaGzO0hz8hLeuWu1ZYrf7fJsSDl0lV5tCovi0vd/DCxf7x24SYm19Iwq1MriYquXJLSXJaDgAmxgbUc7aidYAz9ZytsLc2rdLmWLVazalTp9i6dSudO3emQ4cO1X0LQgjxzEpOTsbR0bHC8w4ODty+fbtKfescVBcWFvLiiy9KQC0qZe/evZVqFxwcTHBwcIXn+/btW+mZZoVCwccff8zHH39cqfaieiWn5bBl3yUOnrqBqbEhr3f24aW29TGtIC3c5ZsZ/Lw/jquJSlztFbzbtwkN69Vc4n9dFRQWcyNZxZWbJeuiE+9koVaDoYE+dR0VNG5hRz0XK5xsLcqdfa+sGzdu8MMPP7B161auXLmCsbExLi4uElQLIUQ1srW15dKlSxWev3TpUpUTG+gcVD/33HOcPXu2ShcTQjy9MlR5bI2MY++JBPT09OjRvgG9O3hWmD86JT2HiIPxnLqUjJWFCQO6NqSVv3Otb0IsKlaTmKLi6q1MrtxUciO5JEOHvp4erg4WtA90pb5rSYYOQ4OHy9Bx48YN9PT0cHV15erVqyxevJj27dszbtw4unfvjrW1dfXclBBCCKBkEm/Tpk10796d5s2ba52Ljo5m06ZN9OzZs0p96xxUz549mxEjRrB06VL69u2Li4uL5P8V4hmWnVvAr4cus+PIFQoKiwkOcufVTl7lFm4pbb/rj6scjL6Jvr4e3drWp1ML91rLfqFWq0lOy+HKrZI0dwm3MskrKMnQ4WRrTvOGjtR3saKusyUm1bBR8s6dO0RERLB161aOHTvG22+/zZw5c2jbti0nTpyociUvIYQQDzZ+/HgiIyMZPHgwHTt2xMfHBz09PS5evMj+/fuxt7dn4sSJVepb579itra29OjRgwULFmiq09xLT0+Pv/76q0oDEkI8GfILitj9x1V+ORCPKqeANgHOvN7Zt8J10AWFxRw6fZPdf1wlO6+QNgHOdG9XnzqKR7uBT61Wk56Zpym4ciVRSXZuIQC2Vqb4e9r9b3OhJeam1ZuhY8yYMURERFBUVISvry//+Mc/eOWVVwDQ19fXBNSlgf6djFwa1beRiQshhKgmDg4ObNmyhc8//5w9e/bw+++/AyVLR/v06cOUKVNwcHCoUt86B9Wff/45q1atwt3dnSZNmlSqnrsQ4ulRVFRM5J83+On3ksItTbzteeM+hVvUajWnL6Ww7WA8dzJy8PWwoU9Hr3KrJtYUVXa+puDKlVuZZPwvQ4eluTGebnWo72JFPWerag3w8/Ly2LdvH4cPH2bOnDno6elRt25d3nvvPfr06YOfn1+ZYDk3r5BL19O5cDWNtMxcTI0NaeBmJTmshRCiGtnb2zN37lzUajWpqamo1Wrs7OweegJD59/U4eHhdO7cmaVLlz7UhYUQT5biYjXH/rrF5v9eIvFOFj51rRnzWlP8GlS8qfBKopKfI+O4kpiBk50Fo19pct/21enqLSUnY7M4ee0MKeklGTrMTAyp52xJ28bO1Hexwtaqahk6KlJYWMjhw4fZunUrO3bsQKlUYmdnx7hx4zRZbe6lVqu5kaziwtU0riQqKVarcbA2p0NTNzzd6jwRubmFEOJJpKenh51d+cXHqkLnoFqtVpcpDS2EeHqVFm7ZuPsiVxKV1HWyZMqbzWnesPzCLQB3MnL49dBl/rxwG0tzY97o0pDWAc4PlR2jslKVufz3eAKXrqWTqcylqZ8xTbztqe9ihaONebVvhFSr1RQUFGBsbMz27dt57733UCgUdO/enVdffZXnnnsOQ8Oyv2pVOQVcvJrGhYQ0VDn5mBgZ4N/Alob1bLG1Mq3WMQohhChx8+bNSrVzdXXVuW+dg+qQkBCOHTvGgAEDdL6YEOLJcjEhjU17LnLuSknhlvdea0K7wPILt0DJJsQ9xxLYH30DfT09Xmxbnxce0SbE3PxCDp++ybG/kjDU1+eFFu4Y5OrTulXDGrne+fPn2bp1Kz///DNDhgxhzJgxdOnSha+++orOnTuXmxe9qFhNwi0l56+mceO2CjVq3B0UtPZ3or6LFQYPmU1ECCHE/YWEhFTqG8pz587p3LfOf+neeecdpkyZwqxZs+jXrx8uLi4YGJT9erI6p9OFEI9WqjKX7yJiiDp/mzoKY4b19OeFFuUXbgEoLCrm8Omb/Ha0ZBNiaz8nurdv8EiqCBYXqzkTm8LvUdfJyi2gqbc9wS3qojAz4uTJxGq/3ooVK9i8eTPnz5/HwMCA559/Hh8fHwDMzc3p1atXmfekKXO5kJDGpWvp5OYXojA1opmvA74eNo91tUghhHjahIWFlQmqi4qKuH79Oj///DN2dnYMGjSoSn3rHFR3794dKIngN2/eXGG7qkT4Qojady0pk3nrTpCdW8AbXXzp1rZehTPNpUtDth2IJyU9B5//bUJ0e0SbEK8lZbL7WAK37mTh7qjgjS4VZx+pquTkZI4dO6bJW3rw4EEUCgWffvopvXr1wt7evtz3FRQWEX8jgwtX00hKy0ZfT496zlY0rGeDm4Oi1vNxCyHEs+h+heRGjRpFv379yMrKqlLfOgfVY8eOlfROQjylzl9NZf76KIyM9Jn9dlvqOVdcVerqLSW/7I8n/kY6TrYWjHolEL/6to/k90OGKo99J6/x1+VUrCyM6dPRC/8G1XdtpVLJjh072Lp1KwcPHiwpox4djb29Pd99912FFWVLU+FduJpG3I10CoqKsVaY0DbABe+61phVUFVSCCFE7bOwsKBv376sXr2awYMH6/x+nX/Djx8/XueLCCEef8dibrFs8ykcbMyYPqQVDjblF2+5exOiwtyY1zv70qaxyyPZhFhQWMTRM7c4crZkWUeHpm60DXTGyLD6MmTs2rWLd999l7y8POrVq8e4ceN45ZVXNDPS5QXU96bCMzLQx9OtDr4eNjjZmstEhBBCPCGMjIxISkqq0nsfGFQrlcoq10B/mPcKIR6d345eZd2Ov/B2t2bqoBbllhbPyStk97GrHPjzBgBdWtejc8u6mD6C2Ve1Ws1fl1PZd/Iayqx8/BvY8kKLug+dV7qgoICDBw+ydetWunTpQu/evWnSpAmDBw/mlVdeISgoqMKAuLxUeI425nRo5oaXW51qDfSFEELUvPPnz7N27Vq8vb2r9P4H/jXs1KkTgwYNon///ri7u1eq02vXrvHDDz+wadMmTp48WaWBCSFqXnGxmk3/vci2A/G0aOTIuNeblcmLXFRUzOEzifx29ApZOQW09HOmx3P1sbF8NGnfElOy2H3sKtdvq3CyNadPRy/qOllWuT+1Ws2JEyf46aefiIiI4M6dO1hZWdGkSRMAnJ2d+fjjjyt8vyo7n4sJ6fekwrOjYT0bSYUnhBCPuYqyf2RmZpKZmYm5uTmfffZZlfp+YFA9b948Fi1axDfffEOTJk1o164djRs3xt3dnTp16qBWq1EqlVy/fp0zZ85w+PBhzp49i7e3N//617+qNCghRM0rKCzm65/PcOjUTTq38mBYT3+tJRxqtZqz8XfYdiCe5LRsvNytHzqg1YUqp4DIk9c4HZeCuYkRPds3INDbvkob/NRqNTdv3sTNzQ09PT1mzJjB5cuX6dq1K6+88govvPACJiYVz3rfmwoPwM3BgjYBztRztpRUeEII8YRo3bp1uUF1nTp18PDwoFevXlVeZfHAoLpLly507tyZyMhIfvzxR7777jvy8vLKDEitVmNiYkKHDh0YO3YswcHBNbqOcMeOHWzbto2zZ8+iVCrx8PBgyJAh9OvXT+u6kZGRLFy4kNjYWJycnBg2bBhDhgwp09+qVatYv349KSkpeHt78/7779OuXTutNiqVinnz5vHbb7+Rn59PmzZtmDlzZqVn8IV4XOTkFbLoP39yJi6F1zv70qejp9Z/N3cyctiw6wJx19NxsDFn5MuNCfB8+BKulVFYVMzxv5I4fPomBUXFtAlwpn0T1yrluk5MTGThwoVs3bqVGzducOrUKczNzVm+fDmurq4oFPfPUlJeKryghiWp8MpbIiOEEOLxNnfu3Brru1J/pfT09OjUqROdOnWioKCAs2fPEh8fT1paGgA2NjZ4eXkREBCAkZFRjQ32bqtXr8bNzY3Q0FBsbGw4fPgws2fPJjExkQkTJgAQHR3NmDFj6NOnD9OnTycqKoqwsDAMDQ0ZOHCgpq9Vq1axYMECJk+ejL+/P+Hh4YwePZrw8HAaNWqkaTd16lRiYmKYNWsWCoWCxYsXM3z4cLZt21ZuoQchHkfpmXn8+/sTJCRl8s6rgXQM0v5QmHBLydc/n6WoSM1rIT60a+zySGZi1Wo1l66l89/jCaRl5uFT15rOrTyqtKTi7Nmz/POf/+To0aMAtGnThhEjRmg+FPj6+lb43oLCIuJuZHBRUuEJIYTQgc5TP0ZGRgQFBREUFFQT46m0FStWYGtrq3ndrl070tPTWbNmDePGjUNfX5+lS5fi7+9PWFgYAG3btiUxMZFly5bRv39/9PX1yc/PZ8WKFQwdOpSRI0cCJV8N9O7dmxUrVrBo0SIATp06xe+//87KlSsJDg4GSv4wd+3alR9//LHKicKFeJQSU7KYu/Y4mdn5THuzBU19HbTOx8TfYc2vf2Fpbsw7rwfiaGv+SMaVnJbDnuMJXL6Zgb21GQO6NsTTrY7O/eTl5WFiYoKBgQEJCQkMGzaMsWPH4ubmdt/3SSo8IYR4OlW2LPm9HkmZ8sfF3QF1KT8/PzZt2kReXh4GBgYcPXqUqVOnarXp1asXmzZtIiYmhsDAQKKiosjMzNQUdgAwMDCge/fufPvtt6jVavT09IiMjMTS0pIOHTpo2rm6utK8eXP2798vQbV47F26lsYX608Cenw4vDVe7tZa5w+dvsmWvZdwd1Qw6pXAR7K8ISevkP1/3uDPC7cxNtLnxTb1CGroqHN6vuPHj/P5559jZ2fH8uXL8fPz48iRI5w6deq+AXVFqfAa1rPF0cZMUuEJIcQTrrJlye/1SMqUP85OnjyJm5sbZmZmxMbGUlBQgJeXl1ab0nLC8fHxBAYGEhcXB1Cmnbe3N9nZ2SQlJeHs7ExcXByenp7o6+uXaXfw4MEKx6RUKlEqlVrH8vPzq3yPQlRF1PnbLNn0J9ZWpoQObYXTXTPQxcVqth++zH+PJ+DfwI6hPf0xMarZdHBFxWr+vHCbA9E3yM0vpHlDRzo0c8PcVLflY3/++SdffPEF+/btw87OjvHjx2s+CBsaVlwFUlLhCSHEs+HesuRqtZq1a9dy48YNevfuTYMGDVCr1Vy+fJlff/0VNze3cvfeVcZTE1SfOHGC7du3M23aNAAyMjIAyuzgLH1del6pVGJsbIypqfa6zTp1Sr56Tk9Px9nZGaVSiaVl2awHVlZWmr7Ks2bNGpYuXap1zNfXl48++kiHuxOi6vaeuMZ322Ko72LFtMEttHI7FxQW85/dF4g6n0S7QFdeC/Gp8SIul29msOdYAsnpOdR3saJLK48qLTNZv349//jHP7CxseHDDz9k+PDhmJtX3M+9qfBMjQ3xb2BHo3o22EgqPCGEeCrdW5Z85cqV5OTksGvXLmxsbLTOjR8/ngEDBpCamlqlaz0VQfWtW7eYPHkyrVq1Yvjw4VrnKpryv/t4eW3UanWl2t3vOMCwYcN49dVXtY7l5+drNnkKUVPUajU/7ovlx99jaerjwIQ3mmkVasnOLeDbbTHEXU+n53MN6NzKo0aXO6Qpc/nviWtcTEjD2tKEfiE++NS11umaf/31F8XFxTRu3JiuXbsyffp0RowYUWEWj6JiNfE3MriQIKnwhBBCwIYNGxg8eHCZgBpKlha//vrr/PDDD7z99ts69/3EB9VKpZJRo0ZhbW3NsmXLMDAo+eq2dKb53lnk0qUYpTPWVlZW5OXlaTY43duutB8rKysSExPLvf798hlaWVmVOZ+ZmSlBtahRRUXFfLstht+jrtMxyI2RLzfG8K4AMk2Zy1dbz5CSlsOgl/xo6edUY2PJKyji8OmbHIu5hb6+Hi+0cKeVv7PWeB7k4sWLfPHFF0RERNCpUyfWr1+Po6OjJtPPvXLyCjkTl8LvZ5TY3ExAYWZMUEMHGnrYoHjMU+EVFatJSs0i4VYmGao8QlrWlSUpQghRTe7cuUNhYWGF54uKirhz506V+n6ig+rc3FzeeecdMjMz2bhxo9byDA8PD4yMjIiPj6djx46a47GxsQB4enoCf6+ljouLw9/fX9MuLi4OCwsLnJycNO0OHz6sWa95d3+lfQnxOMjNL2TJpmiiLybzSrAX/UJ8tH5mbySrWLn1DHn5RYx+NRBfj7Kf1quDWq3mdGwKkVHXUeUU0MTbnk7N3XUKauPi4liwYAFbt27F3NycCRMmMHr06Arb5+QVcvpSMueupFJYpMbW0pBubes/EanwlFn5JNxScu22ivyCIkyNDajvYiUBtRBCVCN/f3/Wr19Pz549y9QZuXbtGuvXr8fPz69KfescVB8/fpxz584xdOhQzbFt27axdOlSlEolPXv25IMPPiizoa+6FRYWMmnSJOLj41m/fr0m+C1lbGxM27Zt2bFjh9aSkIiICBwcHAgICACgefPmWFpasn37dk1QXVRUxI4dO+jQoYMmGAkODmbZsmUcOHBAE6QnJiYSFRXFBx98UKP3KkRlKbPy+fz7E1y+qeStXgF0ae2hdf781VRWR/yFqbEBE/sH4WJvUSPjuH47k91/JJB4Jwt3RwX9Ovvgan//Qivl2bNnDzt37mTMmDG8++675Wb9gZKlLKdjUzh3OZWiYjXe7nUIauhI7IWzj6wCZFUUFBZx/baKhFuZpKvy0NMDFzsLPJytJPuIEELUgNDQUN566y26d+9OSEgI9evXR09Pj/j4ePbt24ehoSGhoaFV6lvnoHrp0qXY2Nhoguq4uDhmzJhB3bp1ady4MevXr8fd3b3M2ubqNmfOHPbt20doaCgqlYro6GjNOW9vbxQKBWPHjmXw4MHMnDmT3r17ExUVRXh4OLNnz9YE/cbGxrz33nssWLAAW1tbTfGXhIQEvvjiC02fTZs2pVOnTnz44YeEhoaiUChYtGgRLi4uZRbBC1Ebbqdm8691x7mTkcvEAUFllnQci7nFxj0XcLa1YNQrgVhbVlyWu6oyVHnsO3mdvy7fwdLcmD4dvfBvYFvp4PDatWssWrSIdu3a8dprrzF06FBee+017O3ty21fJpiua02Qr4PWZszHjVqtJiU9l4QkJYkpWRQVq7GyMKaxpx3uTpY1nnlFCCGeZc2aNWPz5s0sXLiQ/fv389tvvwFgZmZGp06dmDBhgiZTnK50DqpjY2O1Fm9v27YNU1NTwsPDUSgUhIaGsmXLlhoPqg8dOgSUX25y7dq1tGnThqCgIJYvX878+fPZunUrjo6OzJgxQ6uaIqAp+rJu3TpSUlLw8fFh5cqVWtUUAb744gvmzZvHnDlzNGXKFy1aJNUURa27fDODf39/gqIiNR8Mb621pEOtVvPb0av8dvQKPh42jOgVoLVhsToUFBbxR8wtjpxORA0839SVdoEulV66cOPGDZYsWcJ//vMf9PT0qF+/PlDyS668/76exGA6O7eAa0mZJNzKJDuvECNDfTycLfFwsqqRDzhCCCHK5+XlxZIlSyguLiY1NRW1Wo2dnd1Dr7LQ+S9rZmam1sa7AwcO0L59e83u+xYtWmii/pq0d+/eSrULDg7WVEC8n5EjR2qC64ooFAo+/vhjPv7440pdW4hH4XRsMov+8ycKc2NmvtUSV4e/l1kUFRWz6b+XOBaTSCt/Z97o4qvTBsEHUavVnLuSyt4T11Bm5eNX35aQlnV1Cm6//PJL/vWvf6FWqxk4cCDjx4+vsJJVdm4Bpy6lcO5KyS9BL/fHO5guKirmVmo2CbeU3E7LAcDe2oxG9W1xtbeQ7CNCCFFLbt68ybFjx0hNTaV79+7o6+tTVFREeno6derUqbDWwf3o/A4HBwfNZr+kpCTOnTtH//79NedVKlWVBiKE0N2BP2/w9c9ncHNU8I/BLbXyLefmF7Im4i/OX03lxbb1ealtvWpdo3vrTha7jyVwLSkTJ1tzXu7giYdzxZlw7pacnIyZmRkKhQIPDw/69evHxIkTy2waKXVvMO3tbk2zxziYTs/MIyFJyfXbKgoKizEzMaRhPRs8nCx1LnAjhBCien322Wd8//33FBUVoaenh5+fHy4uLuTk5NC1a1cmTJhQpRUXOke/L774IuvXr6egoIDTp09jbGxMSEiI5vz58+epW7euzgMRQlSeWq1m24F4Nu65SICnHZMGBGkFaxmqPFZuPUNiShb9uzakbWOXaru2KqeA/X9e59SlZMxMDOnerj5NfRwqlV0jNTWV5cuX89133zFu3DgmT55Mjx496NGjR7ntS4LpZM5dSXvsg+n8gtJNh0oysvLR19PDxd4CD2dLHKxl06EQQjwOvvnmG9asWcPIkSN5/vnneeuttzTnFAoFXbt2Zffu3Y8mqB4/fjwpKSn88ssvKBQKwsLCNJuIVCoVu3btYtCgQToPRAhROUXFatZt/4vdxxJoF+jCO682wcjw72UEt+5k8dVPZ8jOLWBUn0D8GpSfMUPn6xYVc/xcEodO3aSgqJjW/s4819QVU+MH/xpJS0vjq6++4ttvvyU7O5tXX32VPn36VNj+3mDap641TX0ev2BarVaTnJZDQlImiSlZFKvV1FGY0MTbHndHhaTDE0KIx0x4eDgvv/wy77//frk1Q3x9fTl48GCV+tY5qDY3N+ff//53hef2799fpuS3EKJ65BcUsXzLKY7/lUTP5xowoGtDrRni2GvprNp2FiMDfca93qxa0smp1Wpir6fz3+PXSFXm4u1uTedWdbGrU/kNutOmTWPnzp28/PLLTJkypcKd1Vk5BZyO1Q6mm/k6YmXxeBVsycr536bDpExy8goxNtSnvqsVHk6Wj13gL4QQ4m83b9687x46hUKhKQCoq2pd/Kyvr69VgEUIUX1U2fl88UMUl66lMbi7H93b1dc6H3X+Nj/sOo99HTNGvxqIrdXDf7hNSc9hz/EE4m9kYFfHlP5dfPFyt37g+zIzM1m1ahX9+vXD3d2df/zjH0ybNq3ChPpZOSUz0+evlgTTvnVtaOrr8FgF00VFxdxMySIhKZOU9JJNh4425jT2tMPJzgKDx7y4jBBCCLC2tub27dsVnr948WKZ2ieVVeWgWqVSkZiYSEZGBmq1usz5Vq1aVbVrIcQ9UtJzmLfuBEmp2Yx7vZnWGmm1Ws3eE9eIOBiPl7s1I3oHPPRmuLyCIvZHXefk+dsYG+nTtbUHzRs5PTBwzMrK4rvvvmPFihWkp6djbW3N8OHDadiwYfntn4BgOk2ZS8KtTK4nqygsKsbC1BC/+ra4Oypk06EQQjxhOnXqxKZNm3jzzTfL7HX566+/2Lx5c5nUy5Wlc1CdkZHBJ598ws6dOykqKipzvrSM97lz56o0ICGEtmtJmfxr7XHyCoqYPrQl/g3sNOeKitX8uO8Sh0/fJKihIwNfbKS1vroqbqdm89PvsaRm5hLk60jHILdKBY/ffPMNixcv5s6dO4SEhDBt2jSaNm1abtvSYPrclVSAxy6Yziso0uSUzszOx0BfD1d7BR7OltjVMZVNh0II8YSaMGECBw8e5OWXX6ZTp07o6emxZcsWNm3axO7du3Fzc+O9996rUt86B9WzZ89mz549DBo0iNatW2vlrBZCVK+/Lt9h/g9RmJkYMntkW6010nkFRazbfo6Y+BReaFmXXs95VioDx/2ciU1h55ErmBgbMKhbowemyCsoKMDIqCTgvnDhAgEBAUydOpWWLVuW215VOjNdGkx72NDM1wFL89oPpouL1dxOyyYhKZNbd7JQq8HG0oRmPg64OljIpkMhhKiEH3/8kRkzZpQ5PmjQIGbPnq15HRkZycKFC4mNjcXJyYlhw4YxZMiQGh+fg4MDW7ZsYcGCBezatQu1Wk1ERAQKhYI+ffowdepU6tSpU6W+dQ6q9+/fz5AhQ6pcF10IUTlHziTy5Y+ncbI1Z/rQllobAzOz8/l66xmu31bR9wUfOjRze6hrFRYVs/uPq/x5MZl6zlb0CfZCYVbx7HReXh4bNmxgyZIlfP311zRv3pxPP/0UY+Pyg2NVTgGnLiZz/urjF0yrsvNJSMrkWlImuflFGBsZ4OVmTV0ny8dm5lwIIZ4033zzjdY+u9JMcQDR0dGMGTOGPn36MH36dKKioggLC8PQ0LDKSy90YWtryyeffMInn3xCamoqxcXF2NraPvqKisbGxtSrV++hLiqEuL8dR67w/Y5zNKxnw5Q3W2gFuLfTsln50xmUWfm81TuAQC/7+/T0YGnKXH78PZak1GzaN3GlQzO3CtdO5+fns2nTJhYtWsTNmzdp3bq1Zqa6vID63mC6YT0bmvk4oKjlYLqwqJgbySoSbmWSqsxFD3CyNcfD2QonW/OHnvEXQohnXUBAALa25ad0Xbp0Kf7+/oSFhQHQtm1bEhMTWbZsGf3793/o4LYiubm59OrVi6FDhzJ06FCACsdYFToH1d26dWP//v2P5JOEEM+a4mI1G3ZdYPvhy7Tyd2Jsv6Zayw4u38zgm5/PoqcHY/s1pZ7Lwy2/upiQxraD8ejr6fFGZ1+861pX2FatVtO7d2/Onj1LUFAQX3zxBR06dCh3ffHjGkzfycgh4VYmN5NVFBarUZgZ4d/AlrqOlpiaSCVYIYSoafn5+Rw9epSpU6dqHe/VqxebNm0iJiaGwMDAGrm2qakpmZmZmsmg6qbzX5GRI0cyZcoUpk+fzsCBA3F1dcXAoOxaQzs7u3LeLYSoSEFhMV/9dJojZxLp2tqDIT38tWaMT11K5vsd57C2NGH0K01wsKl8nuh7FRWriYy6xtGzt3C1t+CVYG+sLcvmVy4qKmLXrl1069YNfX19RowYgb29PSEhIeUH09n5RF9K5sLVkoT6j0MwnZtXyLXbJZsOVTkFGOrr4epQuumw6v8f1rSiYjX5BUWYSbAvhHhM3Lp1i4yMDK1jVlZW5e6v6927N6mpqbi4uNC3b1/effddDA0NSUhIoKCgAC8vL632pfUL4uPjayyohpLsH5GRkTUyOaynLi8f3n00atQIPT09TZaPikj2j4plZmZy8eLF2h6GEBUqLi7m4MGDbNiwgRs3bvDPf/6TFi1a1PawhBBC1KIJEyaQkpKidWzcuHGMHz9e8/rAgQOcOnWKJk2aYGBgwP79+1m3bh0vv/wyc+fO5eTJk7z55pts3LiRZs2aad5XWFhIQEAAH374oWZpRk2Ii4tj0qRJeHp6MmDAADw8PMotWliVyWGdp0DGjh0r6aSqia+vb40Vyzl58qQEQbWsss8gTZnLv9ad4GayilGvBGptOiwuVvPLgTgio67T2MueId39MDaqehaKK4lKtkbGUlBYTI/2DQjwLPtL48KFC0yfPp3jx4/TqFEjvv76a1566aVy17ipsvP582IyFxNKZqYb1bOlqY99rc5M38nI4a/4VFIzc0lKvM7zrRvj4WRZ60tP7keVU0ByWjZ3MnLJLyjCQF8PuzpmONiYPfEVGuV3Ue2TZ1D7nvRnUDoZuHr1aszMtL/hu3eWukOHDnTo0EHz+rnnnsPS0pIlS5YwZswYzfGKYsmajjF79uwJwKVLl9i1a1eF7aoyOaxzUH33pxEhxMO5kaxi3toTqHLymTa4BU28HTTnCgqLWb/zHKcuJdOhmRuvBHtXeQOdWq3m8OlE9kdfx66OGX07eWNvXXbpQ1FRESNHjiQtLY358+fz+uuvVz6Y9nW4b8aQmpaemce5K6ncTsvG1NiApj4OJJunaeX1fpzk5hWSnJ5DSnoOOXmF6OnpYWNpgoOrFdaWplKhUQjx2HF2dq7SZGD37t1ZsmQJMTExmmUe9y4jKS0NXtOpmmtycvihFutduHCBGzduAODm5lZh1TQhRFkXE9L4fP1JDA30mDmiDQ1c/86LmZVTwKpfznL5ZgYvd/SiU3P3Kv8SyM4tYNvBeOKuZ9DY047u7euXybl89OhRmjVrhqmpKcuXL8fNza3cr74ys/OJvjuYrm9LU5/aDaZV2fmcv5rGjWQVxob6BDSwo4GrFQYG+ty5+XgFpgWFRaSk55KSnkNmdj4AVhbGuDpYY2tl+tCFe4QQ4nF090pjDw8PjIyMiI+Pp2PHjprjsbGxAHh6etboWGpycrhKQfWePXsICwsjMTER+LuKoqurKzNmzKBLly7VOkghnjYnziWxNDwauzqmTB/SCkdbc825Oxk5fPXTGVKVuQzt4U9QQ8cqX+dmsooff48lK6eAl9rVJ8jXQSs4T01NZc6cOWzevJlZs2bx7rvv0qRJkzL9KLPyOXUxmYvXSoJpv/q2NKnlYDonr5ALV1NJuJWJgb4evnVt8K5b57Er0lJUVMwdZUkgnaHKQ60GC1Mj6rlYYW9thslDLOcRQognwfbt29HT06Nx48YYGxvTtm1bduzYwfDhwzVtIiIicHBwICAgoPYG+pCqVPxlwoQJODs7M3nyZLy8vFCr1cTHx/Of//yHiRMn8uWXX2qtpxFC/G3PsQTW/PoXnm51mDa4hVYBlIRbSr7++SzFxWre69sEL3frKl1DrVZz8vxt9hxPwMrcmKE9/HGxt9A6Hx4ezscff0xmZiYTJkxg2LBhZfq5O5jW09N7LILpvIIiLiWkcflmyVeFDVzr4ONhjanx45Mlo7hYTYYqj+T0HFKVuRQXqzExNsDVQYGDtVmlyr4LIcSTaOTIkbRp0wZfX1/09PQ4cOAAP/zwA/369aNu3bpAyRKMwYMHM3PmTHr37k1UVBTh4eHMnj27xnJUPwo6/xVavnw5Xl5ebNiwAYVCoXXuzTffZODAgSxfvlyCaiHuoVarCf/vJX7eH0eQryPj+zfTmqWMib/Dml//QmFuxOhXAnG2s7hPbxXLKyhi+6HLnLuSik9da3o971kmLdtHH33EN998Q8uWLZk3b16ZpVvZuQWcPHdbK5hu6uOARS0G0wWFxcTdSCfuegZFRcW4O1nSqJ7NYxOgqtVqMrP/t+FQmUthYTGGhvo42phjb22GpbmRbPIWQjz1PD092bJlC0lJSRQWFlK/fn2mTZumNXETFBTE8uXLmT9/Plu3bsXR0ZEZM2Y88TVQdA6qz58/z6RJk8oE1AAKhYLXXnuNhQsXVsfYhHhqFBYVs+rns+yPvkGnFu6M6BWAgcHfn8YPn77J5r2XcHNQMOqVwCqXx76dls1P+2JJy8zjhRZ1advYWRPI5efnk5eXh6WlJW+88Qbe3t4MGjRIa1ZArVYTez2dI2cSKSxS49/AlibetRtMFxUVczlRyaVr6eQXFOFib4FffdvHosQ5lHwAKd1wmJdfhL6+HrZWpjhYl2TukOqMQohnyYcffsiHH374wHbBwcEEBwc/ghE9OjoH1UZGRmRnZ1d4Pisrq8Yq1QjxJMrNK2TRxj85HZvCay9482onb02gq1ar2X7oMnuOJ+DXwI6hPfyqvIzhTGwKO49cwcTYgIHdGlLP+e8d1MeOHWP69Ok0adKERYsWERAQUGbdWlZOAQdP3SQhSYmTrTnBQe61ms6tuFjNtduZXLiaRk5eIQ7WZvg1sMXGsmw+0Uctr6CIlPQcUtJyyMotQE8P6ihMqOtkiZ2VqdYHJiGEEM8Gnf96t2jRgvXr19OjRw/q16+vde7q1av88MMPtGzZsrrGJ8QTLUOVx+ffn+RKopKRLzcmpGVdzbnComL+s+sCJ88n0TbQhX4hvlVKo1ZYVMzuP67y58VkPJwteSXYW7PmOT09nbCwMNavX4+7uzu9e/cu8361Ws2layWz08XFato2diGggV2tzbCq1WoSU7I4dyUVVU4BNpYmBPk6PlQFyepQUFjMnYySGWllVknmDktzYxq41sHe2vSx2yAphBDi0dI5qJ46dSoDBgygV69ehISE0KBBAwAuX77Mvn37MDU1LVPPXYhnUZqqkI++OUq6MpfJbzan+V1ZPLJzC/gu4i9ir6XRo30DurT2qNJ62zRlLj/+HktSajbtm7jSoZmbJjA/duwYo0eP5s6dO7zzzjtMmzYNc3Nzrfercgo4GH2Da7czcba1oGOQW63OTt9OzeavK6lkqPKwNDeitb+z1gbLR62oWE16Zi7JaTmkZeahVqsxMzGkrpMlDtZmmEoJcSGEeKIcP36cc+fOaVVt3LZtG0uXLkWpVNKzZ08++OCDKm2Y1Pkvgo+PD1u2bGH+/PkcOHBAU43GzMyMF154gcmTJ2sCbSGeVXHX0/n+9xRMTUz48K02eNe11pxLy8zlq5/OkJyWzaCX/Gjp51Sla1xMSGPbwXj09fR4o7Ov5hqlKS49PDzw9fVl1qxZBAYGar1XrVZzISGNP87eQq1W0z7QFf8GtrW2kS5Vmcu5y6mkZORgbmJI84aOuDsqamU8arWaDFU+Kek53MnIoahYjbGRAS72Fthbm9Vq5hMhhBAPZ+nSpdjY2GiC6ri4OGbMmEHdunVp3Lix5pvdu9P9VVaVplnq16/P4sWLKS4uJjU1FQBbW9snOg2KENVl/5/X+XZbDMYGevzz7XZaM603klWs3HqGvPwi3nm1Cb4eNjr3X1SsJjLqGkfP3sLFzoJXO3ljbWlCYWEh33zzDYcOHWLt2rU4OzuzadOmMu9XZedzIPoG15NVuNpZ0CHIvcobIx9WhiqP81dSuZWajYmRAU287fFwtqqVaoKq7HyS03M0pcINDfSxq2OGvbUZdRTGkrlDCCGeArGxsbz99tua19u2bcPU1JTw8HAUCgWhoaFs2bLl0QXVpfT19bG3t3+YLoR4ahQUFrN2+1/sPXEN/wa2dPDV0wqoL1xN5buIvzA1NmBC/2a42pfNoPMgmdn5bI2M41pSJi0aOdK5lQeGBvpER0fzj3/8g5iYGLp27UpWVlaZDD1qtZrzV9L4I6akaNNzTVzxq187s9NZOQWcv5rK9dsqjAz18atvi6dbHQwf8Qa/nLxCUtJzSE7PIbe0VLiVCQ7WUipcCCGeRpmZmVql0A8cOED79u01fzNbtGjBb7/9VqW+HxhU37x5EwBXV1et1w9S2l6IZ0FKeg6LNv5J/I0MXu7gSb8QH6Kj/9ScPxZzi417LuBka8HoVwKxttR93fKVRCU/R8aRX1hEn45eBHjakZWVxcf/+hffffcdjo6OfP3113Tv3r1MoJz5v9npG8kq3BwUdGjmVisp6XLzCrl4LY0riUr09fTwdrfGp641xo+wqmBpqfDk9GxU2QVASeYONwcFdnVMH3lgL4QQ4tFxcHDQlERPSkri3Llz9O/fX3NepVJhaFi1OecHviskJAQ9PT1OnTqFsbGx5vWDnDt3rkoDEuJJczo2meWbT1FYpGbywOZaa6TVajW7/rjKziNX8PGw4a1eAWUKsTyIWq3m8OlE9kdfx66OGYM6Nfr/9u48LKrq/wP4e1hGlmHYZV+UxRX3DfclNzRNs9LcKNN+pZJrLpXf0sIyS/2GaaUpluVXpUxNzV3UMg2X3BABFQEFZJthne3+/iAmR1CZYYZF36/n4Xmae88998xcjA+Hcz4fuDj8mwnjwIEDmDBhAubNm6fz23f5tVdu5ODMlbsAgB6tvdDEz7HGZ6eVKjWu385Dclo+NIIAP3cpmvg61thGv4eVCvf3kMKZpcKJiJ4aAwYMwObNm6FUKvH3339rY9ty8fHx2sqP+nrsT7TIyEiIRCJt7umlS5cadCOiJ41GI+CX2CTEHLkO74Z2mDG6rU4VRLVGwP8OJuDPS3fQoZk7XuofrPcsaFGJErtOJCMpNR8tGztjUKg/su9l4t3lH+Hdd9+Fra0tDh06VCGrB1C2Xvn4+TTcyS6E9z+z05Ianp1WqTVITstHYmoelCoNvBtK0NTPqUaKyWg0AuTFaiSk5OqUCvdylcCFpcKJiJ5K06dPx71797Bz505IJBJERkZqlzIXFBRg//79GDt2rEF9PzaoHjlypM5rb29vBAQEwMnJqdL2OTk5SEpKMmgwRPVFQbESa2Iu4HxCFrq18sSrw1roFG0pUajw29k85BQVoH9nPwwO9dd7djg9qwA/HU1EYbESg7r4o1WgEzZtisYnn3wClUqFZ599Fp07d64QUAuCgMvJ2fjragZEIhF6tvFCsG/Nzk6rNQJS7spw7VYuSpVquDnZoJm/U42k65MXKZCVW4x7+cW4fU8BG6dSbanw2tqQSUREdYONjQ0+/fTTh56LjY2FlZVhRcb0/tvrhAkTsGzZskqLSADAqVOnMHv2bC7/oCfWzTsyrNxyFrmyEkwc0hz9H8gxfTtDjh9+i0fqPQXChzVHaIh++wsEQUBcfCYOnkmB1EaMCWHNkZNxE8899yrOnTuHXr16YenSpfDz86twbX5BKWLPpeFuTiF8GtqhexuvGk0BJwgCUjMLEH8zB0WlKjjbW6Gjvxuc7U1buKWkVIWs+zYclpcK93ERo0NTN5YKJyIiHQUFBbhz5w7y8/MhCEKF8x07dtS7T72D6spufD+FQsHUevTEOnY2FRt2X4adjRjvvtoZQT7/psRTqjTY/+ctHDqTAom1JQa3d9A7oC5VqrHn5A1cvZmDIB8HDO3eGFZic7zx2jtISUlBVFQUnnvuuQqzzhqNgMs3svHXlQyYm4vQq603gnwcanR2urwKorxIAXtJA3QJcoWbU8VlKcaiUmu0mTvk/1Q4tJc0gLerBE7/bDiUZ5kzoCYiIq38/HwsWbIE+/btg1qtrnC+vNaDIZPDVQqqCwoKIJPJtK/z8vIqzQIik8nw66+/ws3NsGIWRHWVUqXGpj1Xcfiv22jR2BlTR7XWWcpw664MP+6/hozsQnRs7o7negXg6uW/9bpHZm4Rfj6SiBx5Cfq090bJvWsoKnCGtbMzVq1aBalUCkfHinmt8+SliD2XiozcIvi6SdG9tWeNrFkul5VbjPibOciRl0BibYkOzdzg6WJrkoBeoxGQV1CKrNwi5Mj+rXDo624HFwdrnSU4RERED1q0aBEOHjyIsWPHolOnThU2+FdHlX4Cbdy4EatXrwYAiEQiREZGIjIystK2giBg5syZRhsgUW3Lyi3Gf/93Dsnp/6bLM/9nw6FSpcbeP27iaFwqpLZiTH4uBM0bOet9j4tJ97Dv95toIDbHoA4u+Gb1h/jll1/wxhtv4N133610qYdGI+Bi0j3ExWfCwlyE3u28Eehdc7PTufKyKohZecWwElugTZArfNzsTDIzfP86aZVKA0sLM7g728DV0YYVDomIqMpiY2Mxfvx4zJ8/3+h9VymoDg0NhVhctsHn888/R1hYGJo2barTRiQSwcbGBi1btkTr1q2NPlCi2vB3YhZWb7sAtaZiurwb6fn4cf81ZOUWoUtLDwzrGaB3ujyVWoMDf97CuYQseDe0hTozDmNf+BjFxcWYNWsWpk2bVul1ubISxJ5PQ2ZuEfzdpejW2rPGslnIixS4ejMHd+4VQmxhhhaNndHIQ6r9RcNYHrZO2tXBGvaSBlzWQUREehOLxZVOVBlDlSKA9u3bo3379gDK1kwPGDAAwcHBJhkQUV3wqHR5pUo19v5+A8fOpcHRrgH+b2QrNPGrPBvOo+TKS/DTkURk5BSha4gHzhz5H1auWIHQ0FB8/PHHCAwMrHRcFxPv4a/4DIgtzdG3vQ8ae9nXyOx0UYkS127l4naGHOZmIjTxc0SAlwMsLYwXTD9snTQLsxARkTEMHDgQsbGxGDNmjNH71nsB4sNmzoieFDrp8lp7YtKwltriIIm387DlwDVk5xejW2svDO3eyKB1vAkpudh1IhlqpQJ9WzujS1sfNPUaB18fH7z44ouVBsk5shLEnktFVl4xGnnYo2srjxqZnS5RqHD9dh5uppftq2jsZY8gX0ejFUzhOmkiIqopkyZNwqxZszBv3jyMGTMGnp6eMDev+PPM2Vn/pZx6/7QqKipCXl7eQ8uQp6enw9HREdbWpk2hRWQK96fLCx/SHM/8ky6vRKHC7hM3cPJCGpztrTF1VBsE+jjo3b9aI+DY2ds4dekuiu9dx+Gf1+C0hzu2bdsGd3d3nVKp91/z9/UsnL2WCbGlOfp18EVjL3sjvNtHU6rUSErNR1JqHtQaAT5udmji52i0QP6h66QdrGu8SA0RET0dBg4cCJFIhMuXL2Pnzp0PbWey7B/3W7p0KS5evIgdO3ZUen7q1Klo3bo13n//fb0HQ1Sbjp1Nxbe7LkNqq5suLyElF1sOXEOuvBQ923ojrFsjg2Zp5UUK7DiWhOs30hD/+/9w8sge+Pn5Yfr06Q9dvpGdX4xjZ9OQLStGgJc9QkM89V63ra+CIgVu3ZUj5a4MCpUGni62aObvZJRAt0ShQlbuv+ukRSIRnO25TpqIiGrG1KlTTbZkUu+fzidPnqxQZfF+zzzzDH7++edqDYqoJilVakT/ehVH4srS5U17oQ2ktmIUl6qwMzYJpy7dgaujDSJebINGnobNEN+8I8Mvx5Jw+2Y89mz6CIWFckybNg0zZsyo9K86ao2ACwlZOJeQiQaW5nimo6/B964KtVqD9HuFuHVXhuz8EogAuDvbItjXEQ521auCqFJrkJ1fgqzcIsj+WScttRXDy9WB66SJiKhGTZ8+3WR96x1UZ2VloWHDhg897+rqiszMzGoNiqimZOUWY9X/zuJGugzDejbGqL7BMDcT4eqNHPzv4DXIChXo094Hg7v6w9JC/9lpQRDw+8U7OBp3C66OEkRMGAD5jaOYMWMGmjVrVuk1ZbPTqciWlSDAywFdQzxgZaLZ6Vx5CVLuyJGaVQCVWgNbK0s0b+QEn4Z21brnw9ZJ+7jZwdWR66SJiOjJo/dPNicnJ1y/fv2h569fv27URNpEpnLheha+3H4BGuHfdHlFJUrsOJaEM1fuws3ZFq8MbQE/D8O+n0uVGvzw22XEbNmE1GuncGj/XtjZ2eKrr76qtL1aI+DctUxcuJ6FBmJzDOjkZ/C9H0WhVCM1swC37sogK1TA3EwETxcJ/Dzsql1OvKBIoU2Dp1JpYMF10kREVEddu3YNaWlpAAAvLy80adKkWv3pHVT36tULW7duxeDBg9GuXTudc+fPn8fWrVsxZMiQag2KyJQ0GgE7jiXhp6O66fIuJd3DtkPXIS9S4JlOfhjQ2c/gdHFpWQX4budfOLlvE7IzUhAWFgaVSgHAttL2WbnFiD2Xihx5CYJ8HNGlpbtRZ3MFQUBWXjFS7spx514hNIIAB0kDtAp0gXdDiUGz8OXK10nfyytG8T/rpJ2kDdDQ0YbrpImIqM45ePAgIiMjcefOHZ3jnp6eWLBgAZ555hmD+tX7p/b06dNx7NgxjBs3Dj179kRQUBBEIhESEhIQGxsLFxcXvPXWWwYNhsjUCooU+DLmb1y4noXurT3x6rCWUKo0+G7vVZyNz4CniwSvDW8JHzc7g/rPzi/GwT+TsW71Mlz56xDc3N2xYcMGDBgwoNL2arUGZ69l4u/Ee7BuYIEBnf3g52682emiEiVuZ8iRcleOolIVLC3M4O8hha+7nU6ZdX09bJ20J9dJExFRHRYbG4uIiAi4u7tj5syZCAgIgCAISE5OxpYtW/DWW29h7dq16NGjh9596x1Uu7q6IiYmBsuXL8fBgwdx9OhRAIBEIsHw4cMxa9YsuLq66j0QIlO7kZ6PlVvOIU9egleGNke/jr74+/o9bD9yHUUlSgzs4o9nOvkaFBDmyUtx8FQirqcXwsLMDKrCTAx99ll8/tly2NpWPjudmVuE2HNpyJWXINjHEV1CPIyS+1mtEZCRU4hbd+TIyi2CAMDFwRrNGjnBw9nW4MqHla2TtuI6aSIiqke+/PJLBAQE4Mcff4REItE59/LLL2PMmDH48ssvayaoBgAXFxd8/PHHEAQBOTk5EAQBzs7ONVLVjcgQR8+mYsM/6fLee7UL3JxtEP3rFVy4ngXvhnZ4Y2QreLpKHt/RA+RFCvxyIA6bNnyFpMun8NnabRjQrSlmvbwb58+frzSgVqs1iIsvm522tbLAoC7+Bs+MPziWlLtypGTIoVCqYSW2QJCPI3zd7WBrbXhu6fJ10vfyiqHkOmkiIqrH4uPjMWPGjAoBNVA2Qfz8889j5cqVBvWtd1Cdnp5e6fHK1qUQ1TalSo2Nv17B0bhUtAxwxpvPt0ZSaj427L6MUqUaYV0boW8HH71nb4tKlPjlQBw2rF+Lq3GHYWZmhhdfegk92ng+sjhKRk4RYs+lIq+gFE19ndC5pTvE1ZidVqk1SMsqQModOXLkJRCJylLh+blL0dDR2qBfdFVqDQqLlZAVKiqsk3Z1tIED10kTEVE9ZWlpiaKiooeeLywshKWlYRNRegfVffv2rdIPakMq0RAZ04Pp8gZ08sP2w9dxKekefN2lGDOgCdydK1+a8TAlpSqcunwXR/64jG8/mQIzkQijx4zFzBnTH/mLpEqtwV9XM3ApKRu21pYYHOoP74aGz07nyEpw644M6VkFUGkE2NlYokUjZ3i7SfRahlGiUKGoRIXCYiUKS5QoKlahRKHSnuc6aSIiepK0b98emzdvRlhYGPz9/XXO3bp1Cz/88AM6dOhgUN96B9WRkZEVgmq1Wo3U1FT88ssvcHZ2xtixYw0ajL5u3bqF9evX48KFC7h+/ToaN26M3bt3V2h37NgxrFy5EomJiXBzc8PEiRMxfvz4Cu3Wr1+PzZs34969ewgMDMTcuXMRGhqq06agoADLli3Db7/9BoVCgc6dO+Pdd9+Ft7e3yd4n6e/BdHkaQcCn38dBqVLj2R4B6N3OW6/ZVoVSjd2H47Br7yEEtemHti0D8O5772PY0EHw8PB45LV3swsRey4N+YWlaObvhE7NDZudLlWq/9l0KIO8SAkLMxE8XSXw85DCSWr1yGs1GgHFpfcFz/8E0iq1RtvGqoEFbK0t0NDJGrZWlrC1tqzWLDoREVFdM3v2bIwePRpDhw5F37590ahRIwDAjRs3cOTIEVhZWWH27NkG9a13UP2oaoqTJ0/GqFGjUFhYaNBg9HX9+nUcO3YMrVu3hkajgSAIFdqcP38eb775JoYPH4558+bh7NmziIyMhIWFBcaMGaNtt379eqxYsQIzZ85E8+bNsW3bNkyZMgXbtm1D06ZNte1mz56Ny5cv47333oNEIsF///tfhIeHY9euXZVWxqOaVZYuLxE/HU2Ed0M7vPpsCxw9m4qrN7LRyNMeowc0QUNHmyr3p1RpsOdwHL788gtcjjsCS0sxFr4VjqBGHkCvwEdeq1IL+ONiOi4n50BiY4mwro3gpee6bUEQkJlbjJS7MtzJLoQgAE52VmgT5ABPV0mlKf/Kl2+UzzwXFitRVKrS/vswMxPBxsoCzvZWsLUuC55tGlgYvIGRiIiovggKCkJMTAw+//xzHD9+HPv37wcAWFtbo0+fPpg5c6Y20NaXUbfr29raYuTIkdi4cSPGjRtnzK4r1bdvX20uwfnz5+PSpUsV2kRFRaF58+aIjIwEAHTp0gV37tzB6tWr8dJLL8HMzAwKhQJr1qzBhAkTMGnSJABAp06d8Oyzz2LNmjVYtWoVAODChQs4evQovv76a/Tq1QsAEBwcjP79++Onn36qsRl6qtyD6fJaNHbBt7suQ6MR8FyvQPRo41Xl2Wm1WoPDv1/B8s+W4XLcEZibW2D0mPGYO/stuLm5PfJaQRCQllWA36/KIXHIRvNGzujU3E2vXNBFJUrtpsPiUhXEluZo7GkPX3cppLb/bg4sKVXpzDwXlihRqlBrz4stzWFjZQFPO9uy4NnKAtYNLLipmIiInlr+/v7473//C41Gg5ycHABlxQ3NzKo3uWT0HFiWlpbIyMgwdreVetybVygUOHXqVIVp/KFDh2Lr1q24fPkyQkJCcPbsWcjlcp2iNebm5hg8eDC+/fZbCIIAkUiEY8eOwc7OTifNiqenJ9q1a4fY2FgG1bXo33R5pXihXxDSsgrw89HrCPB2wOj+TeDiULW/Img0Av5OyMDvlzKQmpaOxMt/4sUx4zF/zgw0bNjwkdcWlShxPSUP11JykV9YCgHAkG6N4OlStdlptUbA3exC3LojQ1ZeMQCgoaM1WjZ2houjDRRKNQqLlcjOLy6bfS5RaZdviESAldgCdjZiuDuXBc+2Vly+QURET7fyBBvl+54elnDj7t27Oq8NSbhh1KA6Pj4emzZtQmDgo/8sXlNSUlKgVCoREBCgczwoKAgAkJycjJCQECQlJQFAhXaBgYEoKipCRkYG3N3dkZSUhMaNG1cI5gMDA3HixIlKxyCTySCTyXSOKRSKar0v0nU07jY27L4Ce1sxnu3RCKculf3DGNU3GKEhHlWanRYEAQdiz+LzFSuRm5ON1+d+ilefD8W7k8/Bxubhy0U0GgG3M+W4disXtzPk0AgCPJxt0SbYFXkZpVUKqPMLSpFyV47UTDkUKg0aWJrDy1UCJ7sGUAsCMnOLcOuuDOWrm8zNRLCxtoSLgzVsrCwgsbaEtZUlzJmRg4iISEd5go0LFy5ALBabNOGG0bJ/yOVyyOVy2NjYYOnSpXoPxBTy8/MBAFKpboW68tfl52UyGcRiMaysdDd72dvbAwDy8vLg7u4OmUwGO7uKGRukUqm2rwdFR0cjKipK51hwcDDef/99/d8Q6VCq1Ni4+wqOnk1FsI8D7CRinLyQjmBfR7zUv8ljN+8BZcH0oRNn8dnnK3HxzFGYW1hixKjRGDcwCGLxw3Mw5xeUIiElFwkpeSgqVcK6gQVCAl3QxNdRW6kwLuvh/2iVKg1SM+VITM1DVm4xlGoN7KzFsJeIYSU2h0Kpxt2cIogtzWFrZQknqdU/yzcsYSU25/INIiKiKihPsFGeJq+yhBvGondQ3alTp0oHY29vD19fXwwdOrRCEFvbHvbh3X+8sjblG7se1+5RxydOnIgRI0boHFMoFMjNzX30oOmRMnOLsGrLOdy8I0OrQJeyfMoKNV58pgm6tHSv0j+Ym3dkWLthG77/8n1YWFpi1OgJWPj2DDRsWHlFUJVagxvp+bh2Kxd3sgshggg+bnZo6ucJbze7R84UqzUCikuUuJ0px400GVKzClBSqkIDsTlcHazh4yCBna24bOOgVVnwbGttodc6bCIiItL1YIKNRyXcqC69g+qPP/7YFOMwifKZ5gdnkcuXY5QH/1KpFKWlpSgtLUWDBg0qtCvvRyqVVihyU97uYb9ISKXSCufkcjmD6mq4kJCF1TEXoFJpEOBlj7vZhWjWyBkv9guGg12Dx14f+8c5xJ65DjOpPxr6NseLY1/F/DnT0dDVpdL29/KKce1WLhJT86BQqSG1FaNjMzcE+ThWWqlQoxEgL1LgnkyJhJRc5MpKkJZVgMzcYpQoVBBbmMPT1RaNPKVwd5bA1toS1g0suHyDiIioHjP6RsW6xNfXF5aWlkhOTkbPnj21xxMTEwEAjRs3BvDvWuqkpCQ0b95c2y4pKQm2trbabA8BAQH4/ffftRsX7++vvC8yHY1GwM9HE/Hz0UTY2YphbWsJlVrAywObokMzt8fOTp/88zwiP1mO86ePws0rAF9t+B/aNmkIi3GhFdqWKFRISi2blc6WFcPczAyNPKVo4ucID2fbCvdSqTXIk5ciR1aCPHkplCo1kjNKka3IQGGxEmJLc/i52yHQ2wGNvOxZSIWIiKgWnDlzBlevXsWECRO0x3bt2oWoqCjIZDIMGTIECxcuNCgTyGOD6oftknyculCmXCwWo0uXLti7dy/Cw8O1x3fv3g1XV1e0aNECANCuXTvY2dlhz5492qBarVZj79696NGjhzaA6tWrF1avXo3jx49rg/Q7d+7g7NmzWLhwYc2+uaeMvEiBL7dfwPmELDjYNYDY0gytAl0xqm+Qdg3zw5yOu4jFH32Cc6ePwlJshREvTsR782fA7YFlHoIg4E52Ia7dysWNdBnUGg2cpdboGuKJAG/7CpUKSxQq5MrKAmlZYWlZgRWFGkqlGkUlKiiVApykVmgd5ApfdzvY2Tx8jTYRERGZXlRUFBwdHbVBdVJSEhYsWAAfHx+0bNkSmzdvhre3t07cWFWPDaqrukvyQTVRpry4uBjHjh0DAKSlpaGgoAD79u0DAISEhMDLywtTp07FuHHj8O677+LZZ5/F2bNnsW3bNixatEj7W4hYLMYbb7yBFStWwMnJSVv8JSUlBZ999pn2fq1bt0bv3r3xzjvvYP78+ZBIJFi1ahU8PDxMukbnaXcjPR8rfzyLjNxi2NlYwtGuAUb1DUbbJq6P/N7MkRXjxIV0/PTTb7h07hSee2Ei3p0/Ax5uusF0YbES12/n4lpKLmSFCogtzNHE1xFN/Bx1UvEJgoDCYiVyZCXIlZWisEQJQRCgUgtl6e5KVAAEWJiblQXRZtZ4prOfXpUbiYiI6rO9e/di165duHTpEmQyGXx9fTF+/HiMGjVK+zN7/vz5+Pnnnytcu2rVKgwaNMik40tMTMRrr72mfb1r1y5YWVlh27ZtkEgkmD9/PmJiYkwTVD+4S1IQBGzatAlpaWl49tln0ahRIwiCgBs3buDXX3+Fl5dXpSXATSE7OxtvvfWWzrHy10uXLsXIkSPRtm1bfPnll/j888+xY8cONGzYEAsWLNCppghAW/Tlu+++w7179xAUFISvv/5ap5oiAHz22WdYtmwZPvjgA22Z8lWrVrGaookcibuNb3dehlKtgZNdA3Rq4Y7n+wY9ctb3TNwFLPloGRo4+qJT7+cxbvTz+OjtCfDy+DfPtFojIDVDjvhbuUjN/DcVXrsmDeHvYa+tVKjWCJAVlM1G58pLoVCqAQgARFAo1SgoVkKtEWBuJoKnqy28XCVwc7KBhbkZ4orTGFATEdFTZePGjfDy8sL8+fPh6OiI33//HYsWLcKdO3cQERGhbefj44Ply5frXOvv72/y8cnlcp29bsePH0fXrl0hkZSlwG3fvj1+++03g/p+bFD94Azs119/jeLiYuzfvx+Ojo4656ZPn47Ro0drq9OYmre3N65du/bYdr169dJWQHyUSZMmaYPrh5FIJFi8eDEWL15c5XGS/hRKNb7ddRmHzqTAwrxsPfPo/k3QOqjyzBwAcCbuPJZ8tAxxfx6DuIENnhvdEm883wqS+wLw/IJSXEvJRUJKLopLVZWmwlOq1MjMKUKOvGx9tOafoNnMTAT1P5sQlSoNzEQiuDnZwNPVFm5OtpWWDCciInqarFmzBk5OTtrXoaGhyMvLQ3R0NKZNm6ZdJWBlZYU2bdrU+PhcXV21e+syMjJw9epVvPTSS9rzBQUFsLAwbMuh3lf9+OOPGDduXIWAGigr8fjCCy/ghx9+0JlaJ9JHdn4xIjeexo00GexsLdG3oy+e7xMESSWZNgCguFSFee9+iJgfvoG4gQ2GPh+OhW+/BT/vsplppaosFV5CSlkqPDNRWSq8Jr6O8HGzg5mZCEUlSqRlFSBHVgJ5YVlxHrGlOazEFihRqJBXUIoShRpmIhEaOlrD01UCd2cG0kRERPe7P6Au16xZM2zduhWlpaW1/pf9AQMGYPPmzVAqlfj777+1BWHKxcfHw8fHx6C+9Q6qs7OzoVKpHnperVYjOzvboMEQ5ReU4p01J5GRUwx/DztMGtYSLQMqT3UXd+480nKB63fVECSNEDYyHAvnTkcjX3cIgoCs3GJcS8lBUmq+NhVep2buCPJ1gHUDC8gKFUjJkCNHVoKS0rLvaVtrSzhIGqC4VIUcWQmKSlUQiYCGjjZo7iqBu7MNc0cTEdFT6e7duxXSFFeWOvhBcXFx8PLy0gmoU1JS0KFDBxQXFyMoKAhTpkxBWFiYScZ9v+nTp+PevXvYuXMnJBIJIiMj4eJSFmcUFBRg//79GDt2rEF9i4TyCidVNHr0aKSnp+OHH36At7e3zrnbt2/j5ZdfhpeXF7Zs2WLQgJ4GcrkcCQkJtT2MeisxMRFbtmzB6dOnMXz48Mcu2SEiIqLqi4iIwL1793SOTZs2DdOnT3/oNX/99RfGjx+POXPmaH9eR0dHw8LCAoGBgZDL5di+fTuOHDmi3Q9XWzQaDQoLC2FlZaWtwKgPvYPq8+fP45VXXoFKpULfvn3h7+8PkUiE5ORkHDlyBBYWFtiwYUOtrJOpL8qD6uDg4ErLnhtDXFwc2rdvb5K+TaFUqcZ7X/2O6ym5aBnggnde6VQhhd3Zs+ew+KNPcObUcTSwskXvwS9i/qypCGrkjjv3ChF/Kxc375SlwnOxt0YTP0d4NZSguKRs1jm/QAFBEGBhYQYnOyuYm4tQVKzEnewiFJYoIQLg+s/SDg9nW4gtqzcjXd+ewZOIz6D28RnUPj6D2lffn0F53CKVSiss33jUTPXdu3fxwgsvoFGjRtiwYQPMzR/+c3XChAlISUnB0aNHjTn0GqX38o82bdpg+/btWLlyJWJjY7U7JK2trdG7d29EREQgKCjI6AOlJ5dSpUHkxtNISMlFkLcD5k3oqBNQqzUCLiXdw8LFK5Bw6Rz6PxeOt2e8CT/vhkhIycXWgwmQFf2TCs+vbJ20CEBOfgkuJ5UtRbJuYAFPF1tYmJshv7AUt+7KUFBcFki7OFgjyMcB7i62aFDNQJqIiOhJ5e7uXuXJQJlMhsmTJ8PBwQGrV69+ZEANAIMGDcIHH3yAnJycStdlG0utFn+pTEBAAL744gtoNBrk5ORAEAQ4OzsbNAB6uqk1Alb8eBYXrmfBp6EdFoZ30m5IPHv2LD5c+iladX8BYntvDHlhCj7+OBL2UjskpOTi9yvXIECAu5MtgnwcILG2hKxIidQMOUQiwM5GDH8PKczNRciVlSIpLQ/yorJA2tnBGgHeDvBgIE1ERGRUJSUleP311yGXy/G///2vSoG4ngsnDFarxV8eJj09HadPn0ZOTg4GDx4MMzMzqNVq5OXlwd7e3uB0JPT0EAQBa2Iu4I+L6XB3ssE7r3SCo9QKt27dwszZ8/DnH8dhZWMHvxY9MXZAN6jVGly6mYfi0lxY/VP228neCiqVBiUKNZQqDRzsGsBRagcLczNk5RYh/lYu5EVl2TxcHKzRyNMeHi62FZaWEBERUfWpVCrMmDEDycnJ2Lx5M9zc3B57jSAI2LdvH7y8vEw6Sw3UcvGXyixduhTff/891Go1RCIRmjVrBg8PDxQXF6N///6IiIgwaDD09BAEAdG/XsHhv27DSWqFBeGd4O5si6SkJAx/7nkUFhWi99BwjHrpZZhbWOFcQibU6rKy3+7OtrAWm0MkEkEQAFdHGzhKG8BcJMLdnCJcTs6G7J+0eM72VmgV6AIPZ1tYNWAgTUREZEoffPABjhw5gvnz56OgoADnz5/XngsMDER+fj7mz5+PIUOGwM/PDzKZDNu2bcPp06exbNkyk4+vVou/PGjdunWIjo7GpEmT0L17d7zyyivacxKJBP3798eBAwcYVNMj/XQkETuPJ8PORow549rDz10KtUbAZ19+j+LSUoTPWA5f/wCkZythYaGGs701nKVWaCA2h621JZykVnCUWgEA0rMKcCEhC/n/BNJOUiuEBLjA04WBNBERUU06efIkAODjjz+ucG7Tpk1o0qQJJBIJ1qxZg+zsbFhaWqJ58+ZYs2aNTr5oU6lTxV+2bduGYcOGYe7cucjNza1wPjg4GCdOnDBoMPR02PfHTfywPx42VhaY/lIbNPN3hkKpwq8nb8Kt6QCM8e8CibMLNALg7yGFo9QKDnYNtIG0SqVBWlYBkq5mIL+gFADgZGeFlo2d4ekqgTUDaSIiolpx+PDhx7ZZs2ZNDYykcnWq+Et6evoj8wJLJBLIZDKDBkNPvthzqVj3yyU0sDTHlOdC0KGpG/6Ki8NrU6ai58hZaOjhB2sHJ4Q0dkYjL3s4Sa3gIGmAUqUaaVkFiL+VqxNIt2jsDE8XW9hY6Z9PkoiIiJ4upiz+ondQ7eDggMzMzIeeT0hIqNKidHr6/HU1A1HbLsDCXISxA5uiZ1tv/P7HHxg3bgLE1nawsrKCldgcHZu7o2Pzsu+h9KxCXErKRt4/gbSjXQO0aOQMT1cG0kRERKQfGxsbfPrppw89FxsbCysrK4P61juo7t27N7Zu3YqXX34ZIpFI59yVK1ewfft2jBkzxqDB0JPrUtI9LN8cBxGA53oFIqxbIxw+egyvvvIqrO2c8Gz4f+Dh4YmuIR7w85Dir6sZyJWXBdIOEgbSREREZFpmZmbVKsqnd1AdERGBEydOYNiwYejduzdEIhFiYmKwdetWHDhwAF5eXnjjjTcMHhA9eRJv52Fp9Bmo1RoM7OKHF58Jxh9/nsYrEydC4uiOIRP/Ax8vD3Rr7QlnqRXOXMmAldgczfyd4OUqga01A2kiIiLSX3p6OgDA09NT5/XjlLfXh95BtaurK2JiYrBixQrs378fgiBg9+7dkEgkGD58OGbPng17e3u9B0JPptsZcny44U+UKtTo0cYL4UNboEShwt9p5mjcqi8693sJ/r4e6N7aC+bmIpy/ngUnqRU6t3CvdplwIiIierr17dsXIpEIFy5c0G5KfHClRWWuXr2q970MSpPg5OSEJUuWYMmSJcjJyYFGo4GTkxMrKpKOjJwifLDuFAqKFGjf1A2vjwzBbwcOIjlXipuZpej57Gvw95Cia4gnCkuUuJ1WAO+GErQJbghzs8d/wxMRERE9SmRkJEQiESwtLXVem4JeQXVJSQmGDh2KCRMmaMs7mrryDdVPObISfLDuFHLlJWjRyBnTX2qLrVu3YeH8txHYdgB6PTsJwb6O6NTcHZl5xbiXV4wmvo5o6s/vJyIiIjKOkSNHPvK1MekVVFtZWUEul2ujfaLKyIsUWLL+T2RkFyLQxwEzX26HH3/YjPcXvYOGvi3RdeBYhAS4oG3Thrh1R4aCYiXaNWkIHzfDNwcQERER1SaDsn8cO3aMGT6oUkUlSkRuOI1bd2XwdbPDrJfb4/tNG/Fx5BK4NWqNsJfnoVNLbzRr5ITrKXnQCAK6hnjCxcG6todORERET4FDhw5h+/btuH37NvLz8yEIgs55kUiE48eP692v3kH1lClTMGPGDLz11lsYPXo0fH19K83n5+zsrPdgqH5TKNX49Lu/kJCSCw8XW8x8uR1KiguxevUaeAR0wJCX5yC0tQ/8Pexw7VYurMTm6NzSE3Y24toeOhERET0FoqKisHr1akilUjRp0gR+fn5G61vvoHrIkCEAgOvXr2P//v0PbWfIrkmqv1RqDVZuOYsLiffg6mCN6S+0RgNLc3y77wa6Pv8e/Hzd0aOdH5ylVriWkgcnOyt0aumOBszwQURERDVk8+bNCA0Nxdq1ayEWG3dST++geurUqSbbNUn1k1ojYE3M3/jz8l04Sq3w+ogQRH/zX/x1OQWBoWMRHOCLbq09IRab4+YdGbxcJWgb7Apzc2aLISIiopqjUqkwYMAAowfUgAFB9fTp040+CKq/BEHAxt2XcexsKqQ2YrwypDm+W7cCW3/8Dv4hfdHYU4rubbygVAm4m12EIB8HNPN34i9mREREVOO6deuGS5cumaRvThVStWw9mIB9f9yErbUFXnwmCD+s+xRbf/wOjdsMxAsTZ6BnO28UFKuQV1CKNsGuaN7ImQE1ERER1YpFixbh0qVLiIqKQnp6eoVNitVhUPEXIgDYeTwJMUcSYSU2x7PdG+OX7/+LXb9sQ1CHZ/HihP9D+yZuyJGVQhAEhLb0hKsjM3wQERFR7XFyckJYWBhWrFiB1atXV9pGJBLhypUrevfNoJoMcuhMCjbvjYelhRme6eSLpo2csN3cH01DR2HsxMlo5ueEzNxiWInN0SWEGT6IiIio9i1fvhzr16+Ht7c3WrVqBYlEYrS+GVST3n7/Ox3f7LgEM3MRujR3hTL3Or7+KRNO3iF4dshA+LlLkZlXDEe7BujUwh1WYn6bERERUe3btm0b+vXrh6ioKKP3zTXVpJdz1zIRte0CRCKgdYAD9v3wMd6fPx35OXfRp4M3PF1skS0rgYeLLbq18mRATURERHWGIAjo3r27SfpmUE1VdvVGDj7/4Sw0goBgLxsc+HEpzsedQpt+r2DEgA6Q2jaArEiJQG8HdGzmxpR5REREVKf07dsXp0+fNknfekc9Z86cwaZNm3SO7dq1CwMHDkRoaCg+/PBDaDQaow2Q6obktHws++4MlCo1/FwtcXjrUsRfPocOg17H669NhKWlOUoVarQOckWLxszwQURERHXP66+/jhs3buC9997DhQsXkJmZiezs7ApfhtD7b/NRUVFwdHTEhAkTAABJSUlYsGABfHx80LJlS2zevBne3t4IDw83aEBU96RmyrE0+jSKSlXwc5ei+M4Z3Ei8itCh0xE+7gWoNQLMIEKXlu5o6GRT28MlIiIiqtTgwYMBlFX+3r59+0PbGVIZXO+gOjExEa+99pr29a5du2BlZYVt27ZBIpFg/vz5iImJYVD9hMjMLULkxtOQFSrg4WyDxl5S/CULQdgrH2PYwM5QKtWwtRajcwt32Esa1PZwiYiIiB7KlJXB9Q6q5XI5pFKp9vXx48fRtWtXbUqS9u3b47fffjPeCKnW5MpLELnxNO7llUAqLsXJmJVI6/gSGgc2Qfc2naBQaOBkb40uLdxh1YAbEomIiKhuM2VlcL3XVLu6uiIxMREAkJGRgatXr+rsoiwoKICFBQOs+q6gSIGPo88gPasQNmaF+P2nSGSkJkFqJaBzS3colYB3Qzt0b+3JgJqIiIjqlfT0dOzYsQPffvst7ty5AwBQq9XIzs6GSqUyqE+9o6EBAwZg8+bNUCqV+PvvvyEWi9G3b1/t+fj4ePj4+Bg0GKobSkpVWPbdX7iRLkMDQYbff/oEpcUFGDLhPfTp1RUikQhBPg7ckEhERET1ztKlS/H9999DrVZDJBKhWbNm8PDwQHFxMfr374+IiAiDljHrPVM9ffp0DBw4EDt37sS9e/cQGRkJFxcXAGWz1Pv370fXrl31HgjVDUqVGp//eBbxt3Ih1sjwx0+RKC0pwnOvfoBePULRwNICbYJc0TLAhQE1ERER1Svr1q1DdHQ0wsPDsWHDBgiCoD0nkUjQv39/HDhwwKC+9Z6ptrGxwaeffvrQc7GxsbCysjJoMFS71GoNorZdwPmELEhsLGEucoCDezD6hL2Edm1bwc5GjPbN3ODubFvbQyUiIiLS27Zt2zBs2DDMnTsXubm5Fc4HBwfjxIkTBvVt1OocZmZmsLOzg6WlpTG7pRqg0Qj45pdLOHXxDtSFd6EoKYBSbYaXJs9H2zat4CS1Qvc2XgyoiYiIqN5KT09Hhw4dHnpeIpFAJpMZ1LfBO8wKCgpw584d5Ofn60ydl+vYsaOhXVMNEwQB3+29iiNxt1Gan4Jzez6Ho2cTjJ/6PtydJfB0sUXnlh6w5oZEIiIiqsccHByQmZn50PMJCQlwc3MzqG+9o6T8/HwsWbIE+/btg1qtrnBeEASIRCKDkmZT7dh++Dr2/nEThfeS8PdvqyC2kuDZ0W/A00WCRp72aN/UDZYWLDlORERE9Vvv3r2xdetWvPzyyxX2hl25cgXbt2/HmDFjDOpb76B60aJFOHjwIMaOHYtOnTrp5Kym+mfP7zfw05FE5N+9hksHvoCVrQPGTluK5sH+aOrvhJaNXWBmxg2JREREVP9FRETgxIkTGDZsGHr37g2RSISYmBhs3boVBw4cgJeXF9544w2D+tY7qI6NjcX48eMxf/58g25IdcfRuNv4bu9VCIIGiX/8ABs7F7z85odo3sQf7Zo0RIC3Q20PkYiIiMhoXF1dERMTgxUrVmD//v0QBAG7d++GRCLB8OHDMXv2bNjb2xvUt95BtVgshp+fn0E3o7rjz0t38M0vlyAIgFItoMOQGWge6IGQJr7o3MIDHi7ckEhERERPHicnJyxZsgRLlixBTk4ONBoNnJycYGZWvaWuel89cOBAxMbGVuumVLsuXM9C1PYLuJN4GvGxG2BnbYEOrZugfYtG6N3OhwE1ERERPRWcnJzg4uJS7YAaMCConjRpEjIzMzFv3jycP38emZmZyM7OrvBFddO1Wzn4/IezuH31BK7FfgNlYRaa+dqhTXBD9G7vDQe7BrU9RCIiIqJ6R+/lHwMHDoRIJMLly5exc+fOh7Zj9o+65+YdGT757i8k/30Iyad+gJNXU0ycugShbfzQqYU7M3wQERERGUjvoHrq1KksT10Ppd8rQOSG00iI248bp3+Es08IXo34AH06NEZIIDN8EBEREVWH3kH19OnTTTEOMqGCYiU++vY0smXFEEsawi2gEyZNfQcDuwYi0MehtodHREREVO9Vq0TetWvXkJaWBgDw8vJCkyZNjDKouuzmzZtYsmQJzp49iwYNGmDIkCGYM2cOrK2ta3toD7U25gISrl2GrZMvPBq1xNgXBmNw10bwdJHU9tCIiIjoCVMfYyVjMCioPnjwICIjI3Hnzh0A/1ZR9PT0xIIFC/DMM88YdZB1hUwmw4QJE+Dp6YlVq1YhJycHS5cuRU5ODlasWFHbw6tAEARsP5yAzetXIDPhKFqHzcULfQcgrFtjOEqtant4RERE9ISpL7FSeno6Tp8+jZycHAwePBgeHh5QqVTIz8+Hvb09LCz0D5ENKv4SEREBd3d3zJw5EwEBARAEAcnJydiyZQveeustrF27Fj169NB7MHXdli1bIJPJsGPHDjg5OQEAzM3NMWfOHLz55psICgqq5RH+S6kSEHM4Hovfm4+cW3/Bu0V/THxxEJ7tEQAbK8vaHh4RERE9gepDrLR06VJ8//33UKvVEIlEaNasGTw8PFBSUoL+/fsjIiIC4eHheverd7qHL7/8EgEBAdi5cyemTJmCfv364ZlnnsGUKVOwc+dONG7cGF9++aXeA6kPYmNj0aVLF+03CVCWDUUsFtep3N25shLs/fMOFs2bjpxbfyGg0yis+iwSI/sEMaAmIiIik6nrsdK6desQHR2N8PBwbNiwAYIgaM9JJBL0798fBw4cMKhvvWeq4+PjMWPGDEgkFdfjSiQSPP/881i5cqVBg6nrkpKS8Pzzz+scE4vF8PX1RXJycqXXyGQyyGQynWMKhcJoY5IVKiAv+re/lAwZdsYm48TxP5F/9xqCu7+CFUsi4Opog8zcYqPdlx7vnkyJtKyC2h7GU62+PwM7GzGktuLaHgYREQDg7t27yM/P1zkmlUohlUq1rw2JlWrStm3bMGzYMMydOxe5ubkVzgcHB+PEiRMG9a13UG1paYmioqKHni8sLISl5ZM5GyqTyXS+ccpJpdIK32TloqOjERUVpXMsODgY77//PhISEow+RnO1GqM6W2NU5xFIS+sELy8vqOW3cVdu9FvRY7hILXE35VptD+OpVt+fwd3aHoCRxMXF1fYQnnp8BrXvSXgG4eHhuHfvns6xadOm6WSGMyRWqknp6emYNGnSQ89LJJIKk6FVpXdQ3b59e2zevBlhYWHw9/fXOXfr1i388MMP6NChg0GDqa/KN2pWZuLEiRgxYoTOMYVCgdzcXAQHB8POzq7a9y8qUeK7PVex78gp/H1gDQJ7TIK1gw/mTeiI9iGe1e6fDBMXF4f27dvX9jCeanwGtY/PoPbxGdS++v4M5HI5EhISsHHjxgoZPCoLoCvzqFipJjk4OCAzM/Oh5xMSEuDm5mZQ33oH1bNnz8bo0aMxdOhQ9O3bF40aNQIA3LhxA0eOHIGVlRVmz55t0GDqOqlUWulvL3K5HAEBAQ+95sFvOLlcXumfHAxx+64MX/50AefjzuDyodWwENvA3KIBWvjaIJQBNRERERmJu7v7YycDDYmValLv3r2xdetWvPzyyxWC/CtXrmD79u0YM2aMQX3rHVQHBQUhJiYGn3/+OY4fP479+/cDAKytrdGnTx/MnDlTG2g/aQICApCUlKRzTKFQICUlBSNHjqyVMX276zJO/34UCcfWwdbBDe2GzIKNnTP6t7WvlfEQERHR06suxkr3i4iIwIkTJzBs2DD07t0bIpEIMTEx2Lp1Kw4cOAAvLy+88cYbBvVtUJ5qf39//Pe//4VGo0FOTg4AwMnJCWZmeicTqVd69uyJNWvWIDc3F46OjgCAAwcOQKFQoFevXrUyJokmFfFHv4KzRxD6vTQPGTIBLw9sCjvRw/+0QURERGQKdTFWup+rqytiYmKwYsUK7N+/H4IgYPfu3ZBIJBg+fDhmz54Ne3vDJiarVVHRzMwMLi4u1emiXhk9ejS+//57vPnmm3jzzTeRnZ2Njz/+GGFhYQgMDKyVMQ3q1wsHj76Ibv1G4mZGMZr7S9GnvTfOnmVQTURERDWrLsZKD3JycsKSJUuwZMkS5OTkQKPRGGVy+LFBdXp6OgDA09NT5/XjlLd/kkilUkRHR+PDDz/E9OnTtaU3586dW2tjunIrD4OfGw+FSg2lqhCvDW9ZJzYCEBER0dOnLsZK9zt16hQ6d+6sjZXuz6ddXY8Nqvv27QuRSIQLFy5ALBZrXz/O1atXjTLAuqZRo0ZYv359bQ9Da1TfIPx1NQMrt5zDS88Ew93ZtraHRERERE+xuhYr3S88PBwuLi4YPHgwwsLC0LZtW6P1/digOjIyEiKRSJt7uvw11Q1FJSps/PUK/NylCOv2ZG4QJSIiIjKGlStXYs+ePdi2bRu+//57eHh4ICwsDGFhYWjevHm1+n5sUP3gTs26sHOT/rXjWBJkBQrMGdseFuZP9kZRIiIiouoYNGgQBg0ahKKiIhw8eBB79uxBdHQ01q9fD19fXwwdOhRhYWEGpf+r1kZFqn0+bhJMGtYCjTyZQo+IiIioKmxsbDBs2DAMGzYMcrkc+/btw759+7B27VqsWbMGV65c0btPvac2z5w5g02bNukc27VrFwYOHIjQ0FB8+OGH0Gg0eg+EDNOzrTd6t/ep7WEQERER1UsNGjSAo6MjpFIpLC0tIQiCQf3oPVMdFRUFR0dHTJgwAQCQlJSEBQsWwMfHBy1btsTmzZvh7e2N8PBwgwZERERERGRKarUaJ0+exJ49e3Do0CEUFBTAxcUFL7zwAoYOHWpQn3oH1YmJiXjttde0r3ft2gUrKyts27YNEokE8+fPR0xMDINqIiIiIqpTTp06hT179mD//v3Iz8+HVCrVZgK5P9WeIfQOquVyOaRSqfb18ePH0bVrV0gkEgBA+/bt8dtvvxk8ICIiIiIiUwgPD4etrS369euHIUOGoFu3brCwMM4WQ717cXV1RWJiIgAgIyMDV69exUsvvaQ9X1BQYLTBEREREREZy6pVq9CnTx+IxWKj96139DtgwABs3rwZSqUSf//9t7YgTLn4+Hj4+HDjHBERERHVLQMHDjRZ33oH1dOnT8e9e/ewc+dOSCQSREZGwsXFBUDZLPX+/fsxduxYow+UiIiIiEgf6enpAABPT0+d149T3l4fegfVNjY2+PTTTys9Z2tri9jYWFhZWek9ECIiIiIiY+rbty9EIhEuXLigXV1Rlc2IV69e1fteegfVZ86cwdWrV7Up9YCyDCBRUVGQyWQYMmQIFi5cqPdAiIiIiIiMKTIyEiKRCJaWlgCApUuXmuxezFNNRERERE+kkSNH6rz29vZGQEAAnJycKm2fk5ODpKQkg+6ld0XFxMREtG7dWvv6/jzV33zzDYYPH46YmBiDBkNEREREZCoTJkzAyZMnH3r+1KlTOqsx9KF3UF2VPNWpqakGDYaIiIiIyFQeV4JcoVDAzEzv8BgA81QTERER0ROsoKAAMplM+zovL6/SLCAymQy//vor3NzcDLoP81QTERER0RNr48aNWL16NQBAJBIhMjISkZGRlbYVBAEzZ8406D7MU01ERERET6zQ0FBtBcXPP/8cYWFhaNq0qU4bkUgEGxsbtGzZUmfvoD6MmqfaxsaGeaqJiIiIqM5o37492rdvD6BszfSAAQMQHBxs9PsYdfGzmZkZ7OzsjNklEREREZFRTJs2zWR9PzaorsnyjkREREREppSdnY3t27fj8uXLkMlk0Gg0OudFIhGio6P17vexQXVNlnckIiIiIjKVxMREjBs3DkVFRfD398f169cRGBiI/Px8ZGZmwtfXF+7u7gb1/dig+sHyjuWviYiIiIjqk+XLl8PCwgK//vorbG1t0bVrVyxcuBChoaHYvXs3lixZgs8//9ygvh8bVD9Y3vHB10RERERE9UFcXBwmTpwIHx8f5OXlAfi3IMzQoUMRFxeHZcuWYdOmTXr3bVjJGCIiIiKiekapVGqLu5Rnq5PL5drzzZo1w8WLFw3q26DsH4cOHcL27dtx+/Zt5OfnVyj5KBKJcPz4cYMGRERERERkCh4eHkhNTQVQFlS7urri3LlzGDhwIAAgISEBtra2BvWtd1AdFRWF1atXQyqVokmTJvDz8zPoxkRERERENalz5844fPiwtmris88+i+joaMjlcmg0GuzcuRPPP/+8QX3rHVRv3rwZoaGhWLt2rbY6DRERERFRXTdlyhRcvHgRpaWlaNCgAWbMmIGCggLs3bsXZmZmGDZsGObNm2dQ33oH1SqVCgMGDGBATURERET1iqenp04tFbFYjMWLF2Px4sXV7lvvjYrdunXDpUuXqn1jIiIiIqInhd4z1YsWLcKrr76KqKgojBw5Eh4eHsxbTURERER1TlUrgT/IkMrgegfVTk5OCAsLw4oVK7B69epK24hEIly5ckXvwRARERERGUtVK4E/yJDK4HoH1cuXL8f69evh7e2NVq1aQSKR6H1TIiIiIiJTq8lK4HoH1du2bUO/fv0QFRVlivEQERERERlFTVYC13ujoiAI6N69uynGQkRERERUL+k9U923b1+cPn0ao0ePNsV4iIiIiIhMoqobF2tko+Lrr7+OWbNm4b333sOoUaPg4eEBc3PzCu2cnZ31HgwRERERkalU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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "fig, ax = plt.subplots(figsize=(10,8))\n", - "aa = 0.2\n", - "for ind, row in all_emiss_db.iterrows():\n", - " row.plot(ax=ax, color = 'b', alpha=aa, label = ind)\n", - " aa+=0.12\n", - "plt.ylabel('Annual emissions reductions (million tonnes CO$_2$)')\n", - "plt.legend()\n", - "handles, labels = ax.get_legend_handles_labels()\n", - "unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - "plt.legend(*zip(*unique[::-1]), loc='upper left', frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "plt.xlim([-50,1100])\n", - "plt.ylim([-2000, 5000])\n", - "ax2 = ax.twinx()\n", - "sum_emissions = all_emiss_db.sum()/1000*5\n", - "ax2.plot(sum_emissions.index, sum_emissions.values, 'k--', label='Cumulative')\n", - "# ax2.plot(sum_emissions.index, all_emiss_db.loc[2050]*30/1000, edgecolor=\"None\")\n", - "# ax2.plot(sum_emissions.index, all_emiss_db.loc[2020]*30/1000, edgecolor=\"None\")\n", - "\n", - "ax2.set_ylim([-2000/1000*30, 5000/1000*30])\n", - "ax2.set_ylabel('Cumulative emissions reductions (Gt CO$_2$)')\n", - "ax2.legend()\n", - "mpl_axes_aligner.align.yaxes(ax, 0, ax2, 0, 0.3)\n", - "ax.grid(axis='y')\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_mitigation_curve_annual_cumulative.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "id": "83b942db", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "3992.5384187624477\n", - "3825.828976265355\n", - "3744.2022668633163\n", - "2978.190649859003\n", - "2358.654409597703\n", - "1647.5111792278342\n", - "1225.94386844026\n", - "779.7201676758104\n" - ] - }, - { - "data": { - "image/png": "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P/30E9OmTSMlJaXKuaSkJB588EGuuuqqBqucEEIIIYSoWZ0DuSlTpvDRRx9hsVi47rrraNu2LQEBARQVFbF7925+/vlnHnnkEe677z4mTJhwPusshBBCCCGoYyC3cuVKZsyYwbBhw3jppZcIDAysUqawsJCnn36ajz76iB49etCvX78Gr6wQQgghhDilTulH/v3vf9OmTRveeeedaoM4AIvFwttvv03r1q354osvGrSSQgghhBCiqjoFclu3bmXUqFFotbUX12q1jBo1im3btjVI5YQQQgghRM3qFMgVFxcTHBxcpxcMCgqiuLj4nColhBBCCCHOrE6BXEREBHv37q3TC+7du5dmzZqdU6WEEEIIIcSZ1SmQ69+/P//97385ePBgreUOHjzI7NmzGThwYINUTgghhBBC1KxOgdz999+PXq/nzjvvZM6cOdjtdq/zdrudOXPmMHr0aPR6Pffdd995qawQQgghhDilznutbt68mYceeogTJ05gNBpp2bIlFouFwsJC0tLSsNvthIaGMm3aNLp27Xq+6+1zZN86IYQQvkLuWb6jzgmBu3TpwsKFC5k1axa//PILKSkpFBUVERAQQLt27Rg8eDC33347Vqv1fNa30Rw4cIAXXniBP/74A5PJxMiRI3nsscfw8/Nr7KoJIYQQ4hJVry26AgMDue+++y65odP8/HzGjBlDdHQ0U6dOJTs7m1deeYXs7GymTJnS2NUTQgghxCWqTnPksrKyGD58+BmDlilTpnD11VeTnZ3dIJVrKr7++mvy8/N5//33GTBgANdffz1PP/00CxcuZN++fY1dPSGEEEJcouoUyH355Zfk5uYybty4WsuNGzeOnJwc/v3vfzdI5ZqKFStW0KtXL0JCQtRjV111FUajkRUrVjRizYQQQghxKatTILd8+XJGjhyJxWKptZzFYuGaa67h559/bpDKNRUpKSkkJSV5HTMajcTHx5OamtpItRJCCCHEpa5OgdyhQ4do06ZNnV6wdevWZ8w352vy8/OrXcRhtVrJy8trhBoJIYQQQtRxsYNGo8HtdtfpBd1uNxqN5pwq5SsURan3Z92+fft5qo0QQgghLjV1CuRiYmLYunUrt99++xnLbtu2jZiYmHOuWFNitVrJz8+vcrygoIDExMR6vZbk5BFCCNHUVeSRE01fnYZWBw0axIIFC0hJSam1XEpK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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# output_list = []\n", - "fig, ax = plt.subplots(figsize=(9,6))\n", - "\n", - "max_val = -1\n", - "\n", - "n = len(list_of_DBs)\n", - "colors = plt.cm.RdYlGn(np.linspace(0,1,n))\n", - "\n", - "i=0\n", - "for db, conn, scenario in zip(list_of_DBs,list_of_conns, list_of_scenarios):\n", - " query = \"SELECT t_periods, sum(emissions) as emissions FROM Output_Emissions \\\n", - " WHERE emissions_comm='co2'GROUP BY t_periods\"\n", - " df_read_emissions = pd.read_sql_query(query, conn)\n", - " df_read_emissions['emissions']/=1000\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('CT')[1]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " plt.plot(df_read_emissions['t_periods'], df_read_emissions['emissions'],label=scen_name, color = colors[i])\n", - " if scen_name =='100$/tonne':\n", - " plt.plot(df_read_emissions['t_periods'], df_read_emissions['emissions'],label=scen_name, color = 'y')\n", - "\n", - " max_val = max(max_val, df_read_emissions['emissions'].max())\n", - " va = 'center'\n", - " if '-10$' in scen_name:\n", - " va = 'bottom'\n", - " elif '10$' in scen_name:\n", - " va = 'top'\n", - " plt.annotate(scen_name, (2050, df_read_emissions['emissions'].iloc[-1]), \\\n", - " rotation = 'horizontal', \\\n", - " horizontalalignment='left', verticalalignment=va, fontsize=14, color = colors[i])\n", - " if scen_name =='100$/tonne':\n", - " plt.annotate(scen_name, (2050, df_read_emissions['emissions'].iloc[-1]), \\\n", - " rotation = 'horizontal', \\\n", - " horizontalalignment='left', verticalalignment=va, fontsize=14, color = 'y')\n", - " i+=1\n", - " print(df_read_emissions.iloc[-1,-1])\n", - " \n", - "plt.ylim([-1000, 6000])\n", - "# plt.xlim([2020, 2053])\n", - "ax.grid(axis='x')\n", - "plt.xlim([df_read_emissions['t_periods'].min(), df_read_emissions['t_periods'].max()])\n", - "plt.xticks(rotation='vertical')\n", - "ax.get_yaxis().set_major_formatter(\n", - "tick.FuncFormatter(lambda x, p: format(int(x), ',')))\n", - "\n", - "# plt.legend(frameon=False)\n", - "plt.ylabel('CO$_2$ emissions (million tonnes)')\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_co2_emissions.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d1f25e28", - "metadata": {}, - "outputs": [], - "source": [ - "df_sector_emissions" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a425988c", - "metadata": {}, - "outputs": [], - "source": [ - "df_sector_emissions_all = pd.DataFrame()\n", - "for db, conn, scenario in zip(list_of_DBs,list_of_conns, list_of_scenarios):\n", - " query = \"SELECT tech, sum(emissions) as emissions FROM Output_Emissions \\\n", - " WHERE emissions_comm='co2' AND t_periods = 2050 AND sector='transport' GROUP BY tech\"\n", - " df_sector_emissions = pd.read_sql_query(query, conn)\n", - " df_sector_emissions['emissions']/=1000\n", - "# mask = (df_sector_emissions['sector'].isin(['commercial','residential']))\n", - "# bldg = df_sector_emissions[mask]\n", - "# df_sector_emissions.loc[len(df_sector_emissions),:] = ['buildings', bldg['emissions'].sum()]\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]].replace('$/tonne','')\n", - " except:\n", - " scen_name = 0 #map_scenario_names['']\n", - " df_sector_emissions.loc[:,'db'] = int(scen_name)\n", - " df_sector_emissions_all = pd.concat([df_sector_emissions_all, df_sector_emissions])\n", - "df_sector_emissions_all" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "62aee484", - "metadata": {}, - "outputs": [], - "source": [ - "df_sector_emissions_all[(df_sector_emissions_all['db']==1000) & (df_sector_emissions_all['emissions']>0)].sum()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d6ecf7d9", - "metadata": {}, - "outputs": [], - "source": [ - "df_sector_emissions_all = pd.DataFrame()\n", - "for db, conn, scenario in zip(list_of_DBs,list_of_conns, list_of_scenarios):\n", - " query = \"SELECT sector, sum(emissions) as emissions FROM Output_Emissions \\\n", - " WHERE emissions_comm='co2' AND t_periods = 2050 GROUP BY sector\"\n", - " df_sector_emissions = pd.read_sql_query(query, conn)\n", - " df_sector_emissions['emissions']/=1000\n", - " mask = (df_sector_emissions['sector'].isin(['commercial','residential']))\n", - " bldg = df_sector_emissions[mask]\n", - " df_sector_emissions.loc[len(df_sector_emissions),:] = ['buildings', bldg['emissions'].sum()]\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]].replace('$/tonne','')\n", - " except:\n", - " scen_name = 0 #map_scenario_names['']\n", - " df_sector_emissions.loc[:,'db'] = int(scen_name)\n", - " df_sector_emissions_all = pd.concat([df_sector_emissions_all, df_sector_emissions])\n", - "df_sector_emissions_all" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "379fefcc", - "metadata": {}, - "outputs": [], - "source": [ - "fig, ax = plt.subplots(figsize=(7,6))\n", - "for sector in df_sector_emissions_all['sector'].unique():\n", - " if sector in ['buildings','electric','industrial','transport']:\n", - " df_sector_plot = df_sector_emissions_all[df_sector_emissions_all['sector']==sector]\n", - " plt.plot(df_sector_plot['db'], df_sector_plot['emissions'], label=sector)\n", - "\n", - "plt.legend(frameon=False)\n", - "plt.ylim([-400, 1400])\n", - "plt.xlim([-100, 1000])\n", - "plt.ylabel('CO$_2$ emissions in 2050 (million tonnes)')\n", - "plt.xlabel('Carbon tax ($/tonne)')\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/sectoral_co2_20450.jpg', dpi=400)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d163aa73", - "metadata": {}, - "outputs": [], - "source": [ - "list_of_DBs = ['US_9R_8D_CT_neg50.sqlite', 'US_9R_8D_CT_neg10.sqlite', \\\n", - " 'US_9R_8D_CT_0.sqlite', 'US_9R_8D_CT_10.sqlite', 'US_9R_8D_CT_50.sqlite']\n", - "\n", - "list_of_scenarios = ['test_run', 'test_run', 'test_run', 'test_run', 'test_run', 'test_run', 'test_run', 'test_run','test_run']\n", - "\n", - "list_of_conns = [sqlite3.connect(db) for db in list_of_DBs]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "49129fa4", - "metadata": {}, - "outputs": [], - "source": [ - "output_list = []\n", - "scen_name_all = []\n", - "for conn, scenario, db in zip(list_of_conns, list_of_scenarios, list_of_DBs):\n", - "\n", - " query = \"SELECT t_periods, tech, sum(vflow_out) FROM Output_VFlow_Out WHERE input_comm LIKE 'ethos%' AND tech NOT LIKE '%_emissions%' \\\n", - " GROUP BY t_periods, tech\"\n", - " df_s = pd.read_sql_query(query, conn)\n", - "\n", - " ethos_tech_map = dict()\n", - " ethos_tech_map['E_SOLPV'] = 'Solar'\n", - " ethos_tech_map['SOLELC'] = 'Solar'\n", - " ethos_tech_map['E_WND'] = 'Wind'\n", - " ethos_tech_map['E_OFWND_N'] = 'Wind'\n", - " ethos_tech_map['E_GEO'] = 'Other Renewables'\n", - " ethos_tech_map['E_HYD'] = 'Other Renewables'\n", - " ethos_tech_map['Corn'] = 'Biomass'\n", - " ethos_tech_map['Herbaceous'] = 'Biomass'\n", - " ethos_tech_map['Soybeans'] = 'Biomass'\n", - " ethos_tech_map['Waste'] = 'Biomass'\n", - " ethos_tech_map['Woody'] = 'Biomass'\n", - " ethos_tech_map['DFO'] = 'Petroleum'\n", - " ethos_tech_map['DISTOIL'] = 'Petroleum'\n", - " ethos_tech_map['IMPRESNGA'] = 'Natural Gas'\n", - " ethos_tech_map['IMPELCNGA_S3'] = 'Natural Gas'\n", - " ethos_tech_map['IMPCOMNGA'] = 'Natural Gas'\n", - "# ethos_tech_map['NGA'] = 'Natural Gas'\n", - " ethos_tech_map['INDNG'] = 'Natural Gas'\n", - " ethos_tech_map['CNG'] = 'Natural Gas'\n", - " ethos_tech_map['LNG'] = 'Natural Gas'\n", - " ethos_tech_map['COAL'] = 'Coal'\n", - " ethos_tech_map['COAB'] = 'Coal'\n", - " ethos_tech_map['COAS'] = 'Coal'\n", - " ethos_tech_map['URN'] = 'Nuclear'\n", - " ethos_tech_map['RFO'] = 'Petroleum'\n", - " ethos_tech_map['BIO'] = 'Biomass'\n", - " ethos_tech_map['REN'] = 'Biomass'\n", - " ethos_tech_map['GAS'] = 'Petroleum'\n", - " ethos_tech_map['JTF'] = 'Petroleum'\n", - " ethos_tech_map['LPG'] = 'Petroleum'\n", - " ethos_tech_map['DSL'] = 'Petroleum'\n", - " ethos_tech_map['GSL'] = 'Petroleum'\n", - " ethos_tech_map['MGO'] = 'Petroleum'\n", - " ethos_tech_map['IMPINDOTH'] = 'Petroleum'\n", - "\n", - "\n", - " for key in ethos_tech_map.keys():\n", - " mask = df_s['tech'].str.contains(key)\n", - " df_s.loc[mask,'tech_rev'] = ethos_tech_map[key]\n", - " \n", - " df_s_pivot = df_s.groupby(by=['t_periods', 'tech_rev']).sum().reset_index()\n", - " df_s_pivot = df_s_pivot.pivot_table(index='tech_rev', columns='t_periods')\n", - " df_s_pivot.fillna(0, inplace=True)\n", - " df_s_pivot.columns = [x[1] for x in df_s_pivot.columns]\n", - " \n", - " df_s_pivot = df_s_pivot.loc[['Coal','Petroleum','Natural Gas','Nuclear','Other Renewables','Biomass','Solar','Wind']]\n", - " df_s_pivot /= 1000\n", - " output_list.append(df_s_pivot)\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " \n", - " scen_name_all.append(scen_name)\n", - "# fig, ax = plt.subplots(figsize=(12,6))\n", - "\n", - "# ax = func_stacked_plot(output_list, col_order = ['Coal','Petroleum','Natural Gas','Nuclear',\\\n", - "# 'Other Renewables','Biomass','Solar','Wind'])\n", - "\n", - "# ax.grid(axis='x')\n", - "\n", - "# plt.ylabel('Primary energy consumption (EJ)')\n", - "# plt.tight_layout()\n", - "# plt.savefig('carbon_tax_figures_updates/'+list_of_DBs[0].replace('.sqlite','_compare_scens_primaryenergy.jpg'))\n", - "\n", - "\n", - "fig, ax = plt.subplots(figsize=(16,6))\n", - "for ind_iter in np.arange(len(output_list)):\n", - " subp = plt.subplot(1,len(output_list)+2,ind_iter+1)\n", - " plt.stackplot(output_list[ind_iter].columns, output_list[ind_iter], alpha = 0.75, labels=output_list[ind_iter].index, \\\n", - " colors = output_list[ind_iter].index.map(tech_colormap))\n", - " \n", - " \n", - " if ind_iter==0:\n", - " plt.ylabel('Primary energy consumption (EJ)')\n", - " else:\n", - " subp.set(yticklabels=[])\n", - "\n", - " plt.grid(axis='x')\n", - " plt.xticks(rotation='vertical')\n", - " plt.xlim([output_list[ind_iter].columns.min(), output_list[ind_iter].columns.max()])\n", - " plt.title(scen_name_all[ind_iter])\n", - " plt.ylim([0, 100])\n", - "\n", - "# handles, labels = subp.get_legend_handles_labels()\n", - "# unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - "# if l not in labels[:i]]\n", - "subp = plt.subplot(1,len(output_list)+2,ind_iter+2)\n", - "# subp.legend(handles[::-1], labels[::-1], loc='upper left', frameon=False)\n", - "\n", - "# dummy_df = pd.DataFrame(index=output_list[ind_iter].index, columns=output_list[ind_iter].columns)\n", - "# dummy_df.transpose().plot.bar(kind='stacked',ax=subp, color = output_list[ind_iter].index.map(tech_colormap))\n", - "# subp.set(yticklabels=[],xticklabels=[] )\n", - "plt.legend(loc='upper left')\n", - "plt.grid(False)\n", - "plt.axis('off')\n", - "\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_scens_primaryenergy.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5fa547e1", - "metadata": {}, - "outputs": [], - "source": [ - "i = 0\n", - "df_diff_all = pd.DataFrame()\n", - "for conn, scenario, db in zip(list_of_conns, list_of_scenarios, list_of_DBs):\n", - " if i!=0:\n", - " df_diff = output_list[i] - output_list[i-1]\n", - " else:\n", - " df_diff = output_list[i] - output_list[0]\n", - "\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " df_diff_all.loc[:, scen_name] = df_diff.loc[:,2050]\n", - " i+=1\n", - "\n", - "fig, ax = plt.subplots(figsize=(9,8))\n", - "df_diff_all.transpose().plot(kind='bar',stacked=True, ax = ax, color = df_diff_all.index.map(tech_colormap), legend=False)\n", - "plt.ylim([-15, 20])\n", - "plt.ylabel('Difference in primary energy consumption (EJ) \\n relative to preceding scenario (to the left)')\n", - "plt.legend(frameon=False)\n", - "\n", - "handles, labels = subp.get_legend_handles_labels()\n", - "unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_scens_primaryenergy_diff.jpg')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "68ea9912", - "metadata": {}, - "outputs": [], - "source": [ - "output_list = []\n", - "scen_name_all = []\n", - "for conn, scenario, db in zip(list_of_conns, list_of_scenarios, list_of_DBs):\n", - "\n", - " query = \"SELECT t_periods, tech, sum(vflow_out) FROM Output_VFlow_Out WHERE input_comm LIKE 'ethos%' AND tech NOT LIKE '%_emissions%' \\\n", - " AND tech LIKE '%NGA%' GROUP BY t_periods, tech\"\n", - " df_s = pd.read_sql_query(query, conn)\n", - " df_s_pivot = df_s.pivot_table(index='tech', columns='t_periods')\n", - " output_list.append(df_s_pivot)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0b9c326f", - "metadata": {}, - "outputs": [], - "source": [ - "region = 'US'\n", - "output_list = []\n", - "fig, ax = plt.subplots(figsize=(10,6))\n", - "for conn, scenario in zip(list_of_conns, list_of_scenarios):\n", - " \n", - " if region=='US':\n", - " query = \"SELECT tech, t_periods, sum(vflow_out) as vflow_out FROM Output_VFlow_Out WHERE \\\n", - " sector = 'electric' AND scenario='\" + scenario + \"' \\\n", - " AND vflow_out > 1e-3 GROUP BY tech, t_periods\"\n", - " else:\n", - " query = \"SELECT regions, tech, t_periods, sum(vflow_out) as vflow_out FROM Output_VFlow_Out WHERE \\\n", - " sector = 'electric' AND scenario='\" + scenario + \"' \\\n", - " AND vflow_out > 1e-3 GROUP BY regions, tech, t_periods\"\n", - "\n", - " df_s = pd.read_sql_query(query, conn)\n", - " df_plot = df_s.groupby(['tech' , 't_periods']).sum().pivot_table(values='vflow_out', index='tech', columns='t_periods')\n", - " df_plot = df_plot[~df_plot.index.str.contains('TRANS')]\n", - " df_plot = df_plot[~df_plot.index.str.contains('BLND')]\n", - " df_plot = df_plot[~df_plot.index.str.contains('_emissions')]\n", - " \n", - "# df_stor = pd.read_sql_query(\"SELECT DISTINCT tech FROM StorageDuration\", conn)\n", - "# df_plot = df_plot[~df_plot.index.isin(df_stor['tech'])]\n", - " \n", - " df_plot.loc[:,'agg_tech'] = [map_plants[y] for x in df_plot.index for y in map_plants.keys() if y.lower() in x.lower()] #map agg technologies\n", - "\n", - " df_plot = df_plot.groupby('agg_tech').sum()\n", - " df_plot = df_plot.loc[:, df_plot.columns >= 2020]\n", - " df_plot.fillna(0, inplace=True)\n", - " df_plot*=0.277778\n", - "\n", - " df_plot = df_plot[[2020, 2030, 2040, 2050]]\n", - "\n", - " output_list.append(df_plot)\n", - "\n", - "\n", - "ax = func_stacked_plot(output_list)\n", - "\n", - "num_dfs = len(output_list)\n", - "col_spacing = [x - (num_dfs / 1.8 - 0.5) for x in np.arange(num_dfs)]\n", - "i = 0\n", - "period_placement= 2020\n", - "for spacing in col_spacing:\n", - " db = list_of_DBs[i]\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " plt.annotate(scen_name, (period_placement+spacing, \\\n", - " output_list[i][period_placement].sum()+ output_list[0][period_placement].sum()*0.05), \\\n", - " rotation = 'vertical', \\\n", - " horizontalalignment='center', verticalalignment='bottom', fontsize=14, color='grey')\n", - " i+=1\n", - "\n", - "ax.grid(axis='x')\n", - "plt.ylim([0, 6000])\n", - "ax.get_yaxis().set_major_formatter(\n", - "tick.FuncFormatter(lambda x, p: format(int(x), ',')))\n", - "plt.ylabel('Generation (TWh)')\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_scens_gen.jpg')\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "09395b87", - "metadata": {}, - "outputs": [], - "source": [ - "i = 0\n", - "df_diff_all = pd.DataFrame()\n", - "for conn, scenario, db in zip(list_of_conns, list_of_scenarios, list_of_DBs):\n", - " if i!=0:\n", - " df_diff = output_list[i] - output_list[i-1]\n", - " else:\n", - " df_diff = output_list[i] - output_list[0]\n", - "\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " df_diff_all.loc[:, scen_name] = df_diff.loc[:,2050]\n", - " i+=1\n", - "\n", - "fig, ax = plt.subplots(figsize=(9,8))\n", - "df_diff_all.transpose().plot(kind='bar',stacked=True, ax = ax, color = df_diff_all.index.map(color_dict), legend=False)\n", - "# plt.ylim([-15, 20])\n", - "plt.ylabel('Difference in 2050 electricity generation (TWh) \\n relative to preceding scenario (to the left)')\n", - "plt.legend(frameon=False)\n", - "\n", - "handles, labels = subp.get_legend_handles_labels()\n", - "unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - "plt.legend(*zip(*unique[::-1]), loc='upper left', frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "plt.tight_layout()\n", - "\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_scens_gen_diff.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "92b8c629", - "metadata": {}, - "outputs": [], - "source": [ - "output_list = []\n", - "fig, ax = plt.subplots(figsize=(10,6))\n", - "for conn, scenario in zip(list_of_conns, list_of_scenarios):\n", - " df_plot = stacked_penergy_sector(conn, scenario, 'transport', 'All')\n", - " df_plot /=1000\n", - " df_plot_copy = df_plot.copy()\n", - " df_plot_copy.index = df_plot_copy.index.map(tech_transport)\n", - " df_plot_copy = df_plot_copy.reset_index().groupby(by=['input_comm']).sum()\n", - "\n", - " fuels_order = ['Other Fossil', 'Jet Fuel','Diesel','Gasoline','Biodiesel','Ethanol','Synthetic Fuel','Electricity','Hydrogen']\n", - " add_ind = [x for x in fuels_order if x not in df_plot_copy.index]\n", - " for ind in add_ind:\n", - " df_plot_copy.loc[ind,:] = 0\n", - " df_plot_copy = df_plot_copy.loc[fuels_order]\n", - " df_plot_copy = df_plot_copy[[2020, 2030, 2040, 2050]]\n", - "\n", - " \n", - " output_list.append(df_plot_copy)\n", - "ax = func_stacked_plot(output_list, col_order = ['Other Fossil', 'Jet Fuel','Diesel','Gasoline','Biodiesel',\\\n", - " 'Ethanol','Synthetic Fuel','Electricity','Hydrogen'], color_dict = tech_colormap)\n", - "\n", - "num_dfs = len(output_list)\n", - "col_spacing = [x - (num_dfs / 1.8 - 0.5) for x in np.arange(num_dfs)]\n", - "i = 0\n", - "period_placement= 2020\n", - "for spacing in col_spacing:\n", - " db = list_of_DBs[i]\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " plt.annotate(scen_name, (period_placement+spacing, \\\n", - " output_list[i][period_placement].sum()+ output_list[0][period_placement].sum()*0.05), \\\n", - " rotation = 'vertical', \\\n", - " horizontalalignment='center', verticalalignment='bottom', fontsize=14, color='grey')\n", - " i+=1\n", - "\n", - "plt.ylabel('Energy consumption (EJ)')\n", - "plt.grid(axis='x')\n", - "plt.ylim([0,30])\n", - "\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_transport.jpg')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c8af4799", - "metadata": {}, - "outputs": [], - "source": [ - "i = 0\n", - "df_diff_all = pd.DataFrame()\n", - "for conn, scenario, db in zip(list_of_conns, list_of_scenarios, list_of_DBs):\n", - " if i!=0:\n", - " df_diff = output_list[i] - output_list[i-1]\n", - " else:\n", - " df_diff = output_list[i] - output_list[0]\n", - "\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " df_diff_all.loc[:, scen_name] = df_diff.loc[:,2050]\n", - " i+=1\n", - "\n", - "fig, ax = plt.subplots(figsize=(9,8))\n", - "df_diff_all.transpose().plot(kind='bar',stacked=True, ax = ax, color = df_diff_all.index.map(tech_colormap), legend=False)\n", - "# plt.ylim([-6, 4])\n", - "plt.ylabel('Difference in 2050 energy consumption (EJ) \\n relative to preceding scenario (to the left)')\n", - "plt.legend()\n", - "\n", - "handles, labels = subp.get_legend_handles_labels()\n", - "unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - "plt.legend(*zip(*unique[::-1]), loc='lower left', frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "plt.tight_layout()\n", - "\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_transportdiff.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4c8a5717", - "metadata": {}, - "outputs": [], - "source": [ - "output_list = []\n", - "fig, ax = plt.subplots(figsize=(10,6))\n", - "for conn, scenario in zip(list_of_conns, list_of_scenarios):\n", - " df_plot = stacked_penergy_sector(conn, scenario, 'industrial', 'All')\n", - " df_plot /=1000\n", - " df_plot_copy = df_plot.copy()\n", - " df_plot_copy.index = df_plot_copy.index.map(tech_industrial)\n", - " df_plot_copy = df_plot_copy.reset_index().groupby(by=['input_comm']).sum()\n", - "\n", - " fuels_order = ['Other Fossil', 'Coal','Diesel','Gasoline','Natural Gas', 'Biomass','Synthetic Natural Gas',\\\n", - " 'Electricity', 'Hydrogen']\n", - " add_ind = [x for x in fuels_order if x not in df_plot_copy.index]\n", - " for ind in add_ind:\n", - " df_plot_copy.loc[ind,:] = 0\n", - " df_plot_copy = df_plot_copy.loc[fuels_order]\n", - " df_plot_copy = df_plot_copy[[2020, 2030, 2040, 2050]]\n", - "\n", - " output_list.append(df_plot_copy)\n", - "ax = func_stacked_plot(output_list, col_order = ['Other Fossil', 'Coal','Diesel','Gasoline','Natural Gas', 'Biomass','Synthetic Natural Gas',\\\n", - " 'Electricity', 'Hydrogen'], color_dict = tech_colormap)\n", - "\n", - "num_dfs = len(output_list)\n", - "col_spacing = [x - (num_dfs / 1.8 - 0.4) for x in np.arange(num_dfs)]\n", - "i = 0\n", - "period_placement= 2020\n", - "for spacing in col_spacing:\n", - " db = list_of_DBs[i]\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " plt.annotate(scen_name, (period_placement+spacing, \\\n", - " output_list[i][period_placement].sum()+ output_list[0][period_placement].sum()*0.05), \\\n", - " rotation = 'vertical', \\\n", - " horizontalalignment='center', verticalalignment='bottom', fontsize=14, color='grey')\n", - " i+=1\n", - " \n", - "plt.ylabel('Energy consumption (EJ)')\n", - "plt.grid(axis='x')\n", - "plt.ylim([0,30])\n", - "\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_industrial.jpg')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "798ab89f", - "metadata": {}, - "outputs": [], - "source": [ - "i = 0\n", - "df_diff_all = pd.DataFrame()\n", - "for conn, scenario, db in zip(list_of_conns, list_of_scenarios, list_of_DBs):\n", - " if i!=0:\n", - " df_diff = output_list[i] - output_list[i-1]\n", - " else:\n", - " df_diff = output_list[i] - output_list[0]\n", - "\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " df_diff_all.loc[:, scen_name] = df_diff.loc[:,2050]\n", - " i+=1\n", - "\n", - "fig, ax = plt.subplots(figsize=(9,8))\n", - "df_diff_all.transpose().plot(kind='bar',stacked=True, ax = ax, color = df_diff_all.index.map(tech_colormap), legend=False)\n", - "# plt.ylim([-6, 4])\n", - "plt.ylabel('Difference in 2050 energy consumption (EJ) \\n relative to preceding scenario (to the left)')\n", - "plt.legend()\n", - "\n", - "handles, labels = subp.get_legend_handles_labels()\n", - "unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - "plt.legend(*zip(*unique[::-1]), loc='lower left', frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "plt.tight_layout()\n", - "\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_industrialdiff.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b1005280", - "metadata": {}, - "outputs": [], - "source": [ - "output_list = []\n", - "fig, ax = plt.subplots(figsize=(10,6))\n", - "for conn, scenario in zip(list_of_conns, list_of_scenarios):\n", - " df_plot = stacked_penergy_sector(conn, scenario, 'residential', 'All')\n", - " df_plot /=1000\n", - " df_plot_copy = df_plot.copy()\n", - " df_plot_copy.index = df_plot_copy.index.map(tech_residential)\n", - " df_plot_copy = df_plot_copy.reset_index().groupby(by=['input_comm']).sum()\n", - "\n", - " fuels_order = ['Other Fossil', 'Biomass','Natural Gas','Residential Solar','Synthetic Natural Gas', 'Electricity', 'Hydrogen']\n", - "\n", - " add_ind = [x for x in fuels_order if x not in df_plot_copy.index]\n", - " for ind in add_ind:\n", - " df_plot_copy.loc[ind,:] = 0\n", - " df_plot_copy = df_plot_copy.loc[fuels_order]\n", - " df_plot_res = df_plot_copy[[2020, 2030, 2040, 2050]]\n", - " \n", - " df_plot = stacked_penergy_sector(conn, scenario, 'commercial', 'All')\n", - " df_plot /=1000\n", - " df_plot_copy = df_plot.copy()\n", - " df_plot_copy.index = df_plot_copy.index.map(tech_commercial)\n", - " df_plot_copy = df_plot_copy.reset_index().groupby(by=['input_comm']).sum()\n", - "\n", - " fuels_order = ['Other Fossil', 'Natural Gas','Synthetic Natural Gas','Electricity']\n", - "\n", - " add_ind = [x for x in fuels_order if x not in df_plot_copy.index]\n", - " for ind in add_ind:\n", - " df_plot_copy.loc[ind,:] = 0\n", - " df_plot_copy = df_plot_copy.loc[fuels_order]\n", - " df_plot_comm = df_plot_copy[[2020, 2030, 2040, 2050]]\n", - " \n", - " df_plot_bld = pd.concat([df_plot_res, df_plot_comm]).groupby('input_comm').sum()\n", - " output_list.append(df_plot_bld)\n", - " \n", - "fuels_order = ['Other Fossil', 'Biomass','Natural Gas','Residential Solar','Synthetic Natural Gas', 'Electricity', 'Hydrogen']\n", - "ax = func_stacked_plot(output_list, col_order = fuels_order, color_dict = tech_colormap)\n", - "\n", - "num_dfs = len(output_list)\n", - "col_spacing = [x - (num_dfs / 1.8 - 0.4) for x in np.arange(num_dfs)]\n", - "i = 0\n", - "period_placement= 2020\n", - "for spacing in col_spacing:\n", - " db = list_of_DBs[i]\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " plt.annotate(scen_name, (period_placement+spacing, \\\n", - " output_list[i][period_placement].sum()+ output_list[0][period_placement].sum()*0.05), \\\n", - " rotation = 'vertical', \\\n", - " horizontalalignment='center', verticalalignment='bottom', fontsize=14, color='grey')\n", - " i+=1\n", - " \n", - "plt.ylabel('Energy consumption (EJ)')\n", - "plt.grid(axis='x')\n", - "plt.ylim([0,25])\n", - "\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_buildings.jpg')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f6c4cf67", - "metadata": {}, - "outputs": [], - "source": [ - "i = 0\n", - "df_diff_all = pd.DataFrame()\n", - "for conn, scenario, db in zip(list_of_conns, list_of_scenarios, list_of_DBs):\n", - " if i!=0:\n", - " df_diff = output_list[i] - output_list[i-1]\n", - " else:\n", - " df_diff = output_list[i] - output_list[0]\n", - "\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " df_diff_all.loc[:, scen_name] = df_diff.loc[:,2050]\n", - " i+=1\n", - "\n", - "fig, ax = plt.subplots(figsize=(9,8))\n", - "df_diff_all.transpose().plot(kind='bar',stacked=True, ax = ax, color = df_diff_all.index.map(tech_colormap), legend=False)\n", - "# plt.ylim([-6, 4])\n", - "plt.ylabel('Difference in 2050 energy consumption (EJ) \\n relative to preceding scenario (to the left)')\n", - "plt.legend()\n", - "\n", - "handles, labels = subp.get_legend_handles_labels()\n", - "unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - "plt.legend(*zip(*unique[::-1]), loc='lower left', frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "plt.tight_layout()\n", - "\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_buildingsdiff.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0d997945", - "metadata": {}, - "outputs": [], - "source": [ - "output_list = []\n", - "fig, ax = plt.subplots(figsize=(10,6))\n", - "for conn, scenario in zip(list_of_conns, list_of_scenarios):\n", - " df_plot = stacked_penergy_sector(conn, scenario, 'commercial', 'All')\n", - " df_plot /=1000\n", - " df_plot_copy = df_plot.copy()\n", - " df_plot_copy.index = df_plot_copy.index.map(tech_commercial)\n", - " df_plot_copy = df_plot_copy.reset_index().groupby(by=['input_comm']).sum()\n", - "\n", - " fuels_order = ['Other Fossil', 'Natural Gas','Synthetic Natural Gas','Electricity']\n", - "\n", - " add_ind = [x for x in fuels_order if x not in df_plot_copy.index]\n", - " for ind in add_ind:\n", - " df_plot_copy.loc[ind,:] = 0\n", - " df_plot_copy = df_plot_copy.loc[fuels_order]\n", - " df_plot_copy = df_plot_copy[[2020, 2030, 2040, 2050]]\n", - "\n", - " output_list.append(df_plot_copy)\n", - "ax = func_stacked_plot(output_list, col_order = fuels_order, color_dict = tech_colormap)\n", - "\n", - "num_dfs = len(output_list)\n", - "col_spacing = [x - (num_dfs / 1.8 - 0.4) for x in np.arange(num_dfs)]\n", - "i = 0\n", - "period_placement= 2020\n", - "for spacing in col_spacing:\n", - " db = list_of_DBs[i]\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " plt.annotate(scen_name, (period_placement+spacing, \\\n", - " output_list[i][period_placement].sum()+ output_list[0][period_placement].sum()*0.05), \\\n", - " rotation = 'vertical', \\\n", - " horizontalalignment='center', verticalalignment='bottom', fontsize=14, color='grey')\n", - " i+=1\n", - " \n", - "plt.ylabel('Energy consumption (EJ)')\n", - "plt.grid(axis='x')\n", - "plt.ylim([0,15])\n", - "\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_commercial.jpg')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "47342aca", - "metadata": {}, - "outputs": [], - "source": [ - "list_of_DBs = ['US_9R_8D_CT_0.sqlite', 'US_9R_8D_CT_10.sqlite', 'US_9R_8D_CT_50.sqlite', 'US_9R_8D_CT_100.sqlite', 'US_9R_8D_CT_200.sqlite', \\\n", - " 'US_9R_8D_CT_400.sqlite', 'US_9R_8D_CT_600.sqlite', 'US_9R_8D_CT_800.sqlite', 'US_9R_8D_CT_1000.sqlite']\n", - "\n", - "list_of_scenarios = ['test_run', 'test_run', 'test_run', 'test_run', 'test_run', 'test_run', 'test_run', 'test_run','test_run','test_run', 'test_run','test_run']\n", - "\n", - "list_of_conns = [sqlite3.connect(db) for db in list_of_DBs]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "19d8bd55", - "metadata": {}, - "outputs": [], - "source": [ - "output_list = []\n", - "scen_name_all = []\n", - "for conn, scenario, db in zip(list_of_conns, list_of_scenarios, list_of_DBs):\n", - "\n", - " query = \"SELECT t_periods, tech, sum(vflow_out) FROM Output_VFlow_Out WHERE input_comm LIKE 'ethos%' AND tech NOT LIKE '%_emissions%' \\\n", - " GROUP BY t_periods, tech\"\n", - " df_s = pd.read_sql_query(query, conn)\n", - "\n", - " ethos_tech_map = dict()\n", - " ethos_tech_map['E_SOLPV'] = 'Solar'\n", - " ethos_tech_map['SOLELC'] = 'Solar'\n", - " ethos_tech_map['E_WND'] = 'Wind'\n", - " ethos_tech_map['E_OFWND_N'] = 'Wind'\n", - " ethos_tech_map['E_GEO'] = 'Other Renewables'\n", - " ethos_tech_map['E_HYD'] = 'Other Renewables'\n", - " ethos_tech_map['Corn'] = 'Biomass'\n", - " ethos_tech_map['Herbaceous'] = 'Biomass'\n", - " ethos_tech_map['Soybeans'] = 'Biomass'\n", - " ethos_tech_map['Waste'] = 'Biomass'\n", - " ethos_tech_map['Woody'] = 'Biomass'\n", - " ethos_tech_map['DFO'] = 'Petroleum'\n", - " ethos_tech_map['DISTOIL'] = 'Petroleum'\n", - " ethos_tech_map['IMPRESNGA'] = 'Natural Gas'\n", - " ethos_tech_map['IMPELCNGA_S3'] = 'Natural Gas'\n", - " ethos_tech_map['IMPCOMNGA'] = 'Natural Gas'\n", - "# ethos_tech_map['NGA'] = 'Natural Gas' \n", - " ethos_tech_map['INDNG'] = 'Natural Gas'\n", - " ethos_tech_map['CNG'] = 'Natural Gas'\n", - " ethos_tech_map['LNG'] = 'Natural Gas'\n", - " ethos_tech_map['COAL'] = 'Coal'\n", - " ethos_tech_map['COAB'] = 'Coal'\n", - " ethos_tech_map['COAS'] = 'Coal'\n", - " ethos_tech_map['URN'] = 'Nuclear'\n", - " ethos_tech_map['RFO'] = 'Petroleum'\n", - " ethos_tech_map['BIO'] = 'Biomass'\n", - " ethos_tech_map['REN'] = 'Biomass'\n", - " ethos_tech_map['GAS'] = 'Petroleum'\n", - " ethos_tech_map['JTF'] = 'Petroleum'\n", - " ethos_tech_map['LPG'] = 'Petroleum'\n", - " ethos_tech_map['DSL'] = 'Petroleum'\n", - " ethos_tech_map['GSL'] = 'Petroleum'\n", - " ethos_tech_map['MGO'] = 'Petroleum'\n", - " ethos_tech_map['IMPINDOTH'] = 'Petroleum'\n", - "\n", - "\n", - " for key in ethos_tech_map.keys():\n", - " mask = df_s['tech'].str.contains(key)\n", - " df_s.loc[mask,'tech_rev'] = ethos_tech_map[key]\n", - " \n", - " df_s_pivot = df_s.groupby(by=['t_periods', 'tech_rev']).sum().reset_index()\n", - " df_s_pivot = df_s_pivot.pivot_table(index='tech_rev', columns='t_periods')\n", - " df_s_pivot.fillna(0, inplace=True)\n", - " df_s_pivot.columns = [x[1] for x in df_s_pivot.columns]\n", - " \n", - " df_s_pivot = df_s_pivot.loc[['Coal','Petroleum','Natural Gas','Nuclear','Other Renewables','Biomass','Solar','Wind']]\n", - " df_s_pivot /= 1000\n", - " output_list.append(df_s_pivot)\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " \n", - " scen_name_all.append(scen_name)\n", - "# fig, ax = plt.subplots(figsize=(12,6))\n", - "\n", - "# ax = func_stacked_plot(output_list, col_order = ['Coal','Petroleum','Natural Gas','Nuclear',\\\n", - "# 'Other Renewables','Biomass','Solar','Wind'])\n", - "\n", - "# ax.grid(axis='x')\n", - "\n", - "# plt.ylabel('Primary energy consumption (EJ)')\n", - "# plt.tight_layout()\n", - "# plt.savefig('carbon_tax_figures_updates/'+list_of_DBs[0].replace('.sqlite','_compare_scens_primaryenergy.jpg'))\n", - "\n", - "\n", - "fig, ax = plt.subplots(figsize=(16,6))\n", - "for ind_iter in np.arange(len(output_list)):\n", - " subp = plt.subplot(1,len(output_list)+2,ind_iter+1)\n", - " plt.stackplot(output_list[ind_iter].columns, output_list[ind_iter], alpha = 0.75, labels=output_list[ind_iter].index, \\\n", - " colors = output_list[ind_iter].index.map(tech_colormap))\n", - " \n", - " \n", - " if ind_iter==0:\n", - " plt.ylabel('Primary energy consumption (EJ)')\n", - " else:\n", - " subp.set(yticklabels=[])\n", - "\n", - " plt.grid(axis='x')\n", - " plt.xticks(rotation='vertical')\n", - " plt.xlim([output_list[ind_iter].columns.min(), output_list[ind_iter].columns.max()])\n", - " plt.title(scen_name_all[ind_iter])\n", - " plt.ylim([0, 100])\n", - "\n", - "# handles, labels = subp.get_legend_handles_labels()\n", - "# unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - "# if l not in labels[:i]]\n", - "subp = plt.subplot(1,len(output_list)+2,ind_iter+2)\n", - "# subp.legend(handles[::-1], labels[::-1], loc='upper left', frameon=False)\n", - "\n", - "# dummy_df = pd.DataFrame(index=output_list[ind_iter].index, columns=output_list[ind_iter].columns)\n", - "# dummy_df.transpose().plot.bar(kind='stacked',ax=subp, color = output_list[ind_iter].index.map(tech_colormap))\n", - "# subp.set(yticklabels=[],xticklabels=[] )\n", - "plt.legend(loc='upper left')\n", - "plt.grid(False)\n", - "plt.axis('off')\n", - "\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_scens_highC_primaryenergy.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c31d2500", - "metadata": {}, - "outputs": [], - "source": [ - "i = 0\n", - "df_diff_all = pd.DataFrame()\n", - "for conn, scenario, db in zip(list_of_conns, list_of_scenarios, list_of_DBs):\n", - " if i!=0:\n", - " df_diff = output_list[i] - output_list[i-1]\n", - " else:\n", - " df_diff = output_list[i] - output_list[0]\n", - "\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " df_diff_all.loc[:, scen_name] = df_diff.loc[:,2050]\n", - " i+=1\n", - "\n", - "fig, ax = plt.subplots(figsize=(9,8))\n", - "df_diff_all.transpose().plot(kind='bar',stacked=True, ax = ax, color = df_diff_all.index.map(tech_colormap), legend=False)\n", - "plt.ylim([-15, 20])\n", - "plt.ylabel('Difference in primary energy consumption (EJ) \\n relative to preceding scenario (to the left)')\n", - "plt.legend(frameon=False)\n", - "\n", - "handles, labels = subp.get_legend_handles_labels()\n", - "unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - "plt.legend(*zip(*unique[::-1]), loc='upper left', frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "plt.tight_layout()\n", - "\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_scens_highC_primaryenergy_diff.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0feb23d0", - "metadata": {}, - "outputs": [], - "source": [ - "region = 'US'\n", - "output_list = []\n", - "fig, ax = plt.subplots(figsize=(10,6))\n", - "for conn, scenario in zip(list_of_conns, list_of_scenarios):\n", - " \n", - " if region=='US':\n", - " query = \"SELECT tech, t_periods, sum(vflow_out) as vflow_out FROM Output_VFlow_Out WHERE \\\n", - " sector = 'electric' AND scenario='\" + scenario + \"' \\\n", - " AND vflow_out > 1e-3 GROUP BY tech, t_periods\"\n", - " else:\n", - " query = \"SELECT regions, tech, t_periods, sum(vflow_out) as vflow_out FROM Output_VFlow_Out WHERE \\\n", - " sector = 'electric' AND scenario='\" + scenario + \"' \\\n", - " AND vflow_out > 1e-3 GROUP BY regions, tech, t_periods\"\n", - "\n", - " df_s = pd.read_sql_query(query, conn)\n", - " df_plot = df_s.groupby(['tech' , 't_periods']).sum().pivot_table(values='vflow_out', index='tech', columns='t_periods')\n", - " df_plot = df_plot[~df_plot.index.str.contains('TRANS')]\n", - " df_plot = df_plot[~df_plot.index.str.contains('BLND')]\n", - " df_plot = df_plot[~df_plot.index.str.contains('_emissions')]\n", - " \n", - "# df_stor = pd.read_sql_query(\"SELECT DISTINCT tech FROM StorageDuration\", conn)\n", - "# df_plot = df_plot[~df_plot.index.isin(df_stor['tech'])]\n", - " \n", - " df_plot.loc[:,'agg_tech'] = [map_plants[y] for x in df_plot.index for y in map_plants.keys() if y.lower() in x.lower()] #map agg technologies\n", - "\n", - " df_plot = df_plot.groupby('agg_tech').sum()\n", - " df_plot = df_plot.loc[:, df_plot.columns >= 2020]\n", - " df_plot.fillna(0, inplace=True)\n", - " df_plot*=0.277778\n", - " \n", - " df_plot = df_plot[[2020, 2030, 2040, 2050]]\n", - " output_list.append(df_plot)\n", - "\n", - "\n", - "ax = func_stacked_plot(output_list)\n", - "num_dfs = len(output_list)\n", - "col_spacing = [x - (num_dfs / 1.8 - 0.4) for x in np.arange(num_dfs)]\n", - "i = 0\n", - "period_placement= 2020\n", - "for spacing in col_spacing:\n", - " db = list_of_DBs[i]\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " plt.annotate(scen_name, (period_placement+spacing, \\\n", - " output_list[i][period_placement].sum()+ output_list[0][period_placement].sum()*0.05), \\\n", - " rotation = 'vertical', \\\n", - " horizontalalignment='center', verticalalignment='bottom', fontsize=14, color='grey')\n", - " i+=1\n", - "ax.grid(axis='x')\n", - "plt.ylim([0, 12000])\n", - "ax.get_yaxis().set_major_formatter(\n", - "tick.FuncFormatter(lambda x, p: format(int(x), ',')))\n", - "plt.ylabel('Generation (TWh)')\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_scens_highC_gen.jpg')\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b632ba32", - "metadata": {}, - "outputs": [], - "source": [ - "i = 0\n", - "df_diff_all = pd.DataFrame()\n", - "for conn, scenario, db in zip(list_of_conns, list_of_scenarios, list_of_DBs):\n", - " if i!=0:\n", - " df_diff = output_list[i] - output_list[i-1]\n", - " else:\n", - " df_diff = output_list[i] - output_list[0]\n", - "\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " df_diff_all.loc[:, scen_name] = df_diff.loc[:,2050]\n", - " i+=1\n", - "\n", - "fig, ax = plt.subplots(figsize=(9,8))\n", - "df_diff_all.transpose().plot(kind='bar',stacked=True, ax = ax, color = df_diff_all.index.map(color_dict), legend=False)\n", - "# plt.ylim([-15, 20])\n", - "plt.ylabel('Difference in 2050 electricity generation (TWh) \\n relative to preceding scenario (to the left)')\n", - "plt.legend(frameon=False)\n", - "\n", - "handles, labels = subp.get_legend_handles_labels()\n", - "unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - "plt.legend(*zip(*unique[::-1]), loc='upper left', frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "plt.tight_layout()\n", - "\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_scens_highC_gen_diff.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bfd76560", - "metadata": {}, - "outputs": [], - "source": [ - "output_list = []\n", - "fig, ax = plt.subplots(figsize=(10,6))\n", - "for conn, scenario in zip(list_of_conns, list_of_scenarios):\n", - " df_plot = stacked_penergy_sector(conn, scenario, 'transport', 'All')\n", - " df_plot /=1000\n", - " df_plot_copy = df_plot.copy()\n", - " df_plot_copy.index = df_plot_copy.index.map(tech_transport)\n", - " df_plot_copy = df_plot_copy.reset_index().groupby(by=['input_comm']).sum()\n", - "\n", - " fuels_order = ['Other Fossil', 'Jet Fuel','Diesel','Gasoline','Biodiesel','Ethanol','Synthetic Fuel','Electricity','Hydrogen']\n", - " add_ind = [x for x in fuels_order if x not in df_plot_copy.index]\n", - " for ind in add_ind:\n", - " df_plot_copy.loc[ind,:] = 0\n", - " df_plot_copy = df_plot_copy.loc[fuels_order]\n", - " df_plot_copy = df_plot_copy[[2020, 2030, 2040, 2050]]\n", - "\n", - " output_list.append(df_plot_copy)\n", - "ax = func_stacked_plot(output_list, col_order = ['Other Fossil', 'Jet Fuel','Diesel','Gasoline','Biodiesel',\\\n", - " 'Ethanol','Synthetic Fuel','Electricity','Hydrogen'], color_dict = tech_colormap)\n", - "\n", - "num_dfs = len(output_list)\n", - "col_spacing = [x - (num_dfs / 1.8 - 0.4) for x in np.arange(num_dfs)]\n", - "i = 0\n", - "period_placement= 2020\n", - "for spacing in col_spacing:\n", - " db = list_of_DBs[i]\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " plt.annotate(scen_name, (period_placement+spacing, \\\n", - " output_list[i][period_placement].sum()+ output_list[0][period_placement].sum()*0.05), \\\n", - " rotation = 'vertical', \\\n", - " horizontalalignment='center', verticalalignment='bottom', fontsize=14, color='grey')\n", - " i+=1\n", - " \n", - "plt.ylabel('Energy consumption (EJ)')\n", - "plt.grid(axis='x')\n", - "plt.ylim([0,30])\n", - "\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_highC_transport.jpg')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f07f3da8", - "metadata": {}, - "outputs": [], - "source": [ - "i = 0\n", - "df_diff_all = pd.DataFrame()\n", - "for conn, scenario, db in zip(list_of_conns, list_of_scenarios, list_of_DBs):\n", - " if i!=0:\n", - " df_diff = output_list[i] - output_list[i-1]\n", - " else:\n", - " df_diff = output_list[i] - output_list[0]\n", - "\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " df_diff_all.loc[:, scen_name] = df_diff.loc[:,2050]\n", - " i+=1\n", - "\n", - "fig, ax = plt.subplots(figsize=(9,8))\n", - "df_diff_all.transpose().plot(kind='bar',stacked=True, ax = ax, color = df_diff_all.index.map(tech_colormap), legend=False)\n", - "plt.ylim([-6, 4])\n", - "plt.ylabel('Difference in 2050 energy consumption (EJ) \\n relative to preceding scenario (to the left)')\n", - "plt.legend()\n", - "\n", - "handles, labels = subp.get_legend_handles_labels()\n", - "unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - "plt.legend(*zip(*unique[::-1]), loc='lower left', frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "plt.tight_layout()\n", - "\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_highC_transportdiff.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "34207b30", - "metadata": {}, - "outputs": [], - "source": [ - "output_list = []\n", - "fig, ax = plt.subplots(figsize=(10,6))\n", - "for conn, scenario in zip(list_of_conns, list_of_scenarios):\n", - " df_plot = stacked_penergy_sector(conn, scenario, 'industrial', 'All')\n", - " df_plot /=1000\n", - " df_plot_copy = df_plot.copy()\n", - " df_plot_copy.index = df_plot_copy.index.map(tech_industrial)\n", - " df_plot_copy = df_plot_copy.reset_index().groupby(by=['input_comm']).sum()\n", - "\n", - " fuels_order = ['Other Fossil', 'Coal','Diesel','Gasoline','Natural Gas', 'Biomass','Synthetic Natural Gas',\\\n", - " 'Electricity', 'Hydrogen']\n", - " add_ind = [x for x in fuels_order if x not in df_plot_copy.index]\n", - " for ind in add_ind:\n", - " df_plot_copy.loc[ind,:] = 0\n", - " df_plot_copy = df_plot_copy.loc[fuels_order]\n", - " df_plot_copy = df_plot_copy[[2020, 2030, 2040, 2050]]\n", - "\n", - " output_list.append(df_plot_copy)\n", - "ax = func_stacked_plot(output_list, col_order = ['Other Fossil', 'Coal','Diesel','Gasoline','Natural Gas', 'Biomass','Synthetic Natural Gas',\\\n", - " 'Electricity', 'Hydrogen'], color_dict = tech_colormap)\n", - "\n", - "num_dfs = len(output_list)\n", - "col_spacing = [x - (num_dfs / 1.8 - 0.4) for x in np.arange(num_dfs)]\n", - "i = 0\n", - "period_placement= 2020\n", - "for spacing in col_spacing:\n", - " db = list_of_DBs[i]\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " plt.annotate(scen_name, (period_placement+spacing, \\\n", - " output_list[i][period_placement].sum()+ output_list[0][period_placement].sum()*0.05), \\\n", - " rotation = 'vertical', \\\n", - " horizontalalignment='center', verticalalignment='bottom', fontsize=14, color='grey')\n", - " i+=1\n", - " \n", - "plt.ylabel('Energy consumption (EJ)')\n", - "plt.grid(axis='x')\n", - "plt.ylim([0,30])\n", - "\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_highC_industrial.jpg')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "19578ac7", - "metadata": {}, - "outputs": [], - "source": [ - "i = 0\n", - "df_diff_all = pd.DataFrame()\n", - "for conn, scenario, db in zip(list_of_conns, list_of_scenarios, list_of_DBs):\n", - " if i!=0:\n", - " df_diff = output_list[i] - output_list[i-1]\n", - " else:\n", - " df_diff = output_list[i] - output_list[0]\n", - "\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " df_diff_all.loc[:, scen_name] = df_diff.loc[:,2050]\n", - " i+=1\n", - "\n", - "fig, ax = plt.subplots(figsize=(9,8))\n", - "df_diff_all.transpose().plot(kind='bar',stacked=True, ax = ax, color = df_diff_all.index.map(tech_colormap), legend=False)\n", - "# plt.ylim([-6, 4])\n", - "plt.ylabel('Difference in 2050 energy consumption (EJ) \\n relative to preceding scenario (to the left)')\n", - "plt.legend()\n", - "\n", - "handles, labels = subp.get_legend_handles_labels()\n", - "unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - "plt.legend(*zip(*unique[::-1]), loc='lower left', frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "plt.tight_layout()\n", - "\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_highC_industrialdiff.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6cb57956", - "metadata": {}, - "outputs": [], - "source": [ - "output_list = []\n", - "fig, ax = plt.subplots(figsize=(10,6))\n", - "for conn, scenario in zip(list_of_conns, list_of_scenarios):\n", - " df_plot = stacked_penergy_sector(conn, scenario, 'residential', 'All')\n", - " df_plot /=1000\n", - " df_plot_copy = df_plot.copy()\n", - " df_plot_copy.index = df_plot_copy.index.map(tech_residential)\n", - " df_plot_copy = df_plot_copy.reset_index().groupby(by=['input_comm']).sum()\n", - "\n", - " fuels_order = ['Other Fossil', 'Biomass','Natural Gas','Residential Solar','Synthetic Natural Gas', 'Electricity', 'Hydrogen']\n", - "\n", - " add_ind = [x for x in fuels_order if x not in df_plot_copy.index]\n", - " for ind in add_ind:\n", - " df_plot_copy.loc[ind,:] = 0\n", - " df_plot_copy = df_plot_copy.loc[fuels_order]\n", - " df_plot_res = df_plot_copy[[2020, 2030, 2040, 2050]]\n", - " \n", - " df_plot = stacked_penergy_sector(conn, scenario, 'commercial', 'All')\n", - " df_plot /=1000\n", - " df_plot_copy = df_plot.copy()\n", - " df_plot_copy.index = df_plot_copy.index.map(tech_commercial)\n", - " df_plot_copy = df_plot_copy.reset_index().groupby(by=['input_comm']).sum()\n", - "\n", - " fuels_order = ['Other Fossil', 'Natural Gas','Synthetic Natural Gas','Electricity']\n", - "\n", - " add_ind = [x for x in fuels_order if x not in df_plot_copy.index]\n", - " for ind in add_ind:\n", - " df_plot_copy.loc[ind,:] = 0\n", - " df_plot_copy = df_plot_copy.loc[fuels_order]\n", - " df_plot_comm = df_plot_copy[[2020, 2030, 2040, 2050]]\n", - " \n", - " df_plot_bld = pd.concat([df_plot_res, df_plot_comm]).groupby('input_comm').sum()\n", - " output_list.append(df_plot_bld)\n", - " \n", - "fuels_order = ['Other Fossil', 'Biomass','Natural Gas','Residential Solar','Synthetic Natural Gas', 'Electricity', 'Hydrogen']\n", - "ax = func_stacked_plot(output_list, col_order = fuels_order, color_dict = tech_colormap)\n", - "\n", - "num_dfs = len(output_list)\n", - "col_spacing = [x - (num_dfs / 1.8 - 0.4) for x in np.arange(num_dfs)]\n", - "i = 0\n", - "period_placement= 2020\n", - "for spacing in col_spacing:\n", - " db = list_of_DBs[i]\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " plt.annotate(scen_name, (period_placement+spacing, \\\n", - " output_list[i][period_placement].sum()+ output_list[0][period_placement].sum()*0.05), \\\n", - " rotation = 'vertical', \\\n", - " horizontalalignment='center', verticalalignment='bottom', fontsize=14, color='grey')\n", - " i+=1\n", - " \n", - "plt.ylabel('Energy consumption (EJ)')\n", - "plt.grid(axis='x')\n", - "plt.ylim([0,25])\n", - "\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_highC_buildings.jpg')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "971a11b7", - "metadata": {}, - "outputs": [], - "source": [ - "i = 0\n", - "df_diff_all = pd.DataFrame()\n", - "for conn, scenario, db in zip(list_of_conns, list_of_scenarios, list_of_DBs):\n", - " if i!=0:\n", - " df_diff = output_list[i] - output_list[i-1]\n", - " else:\n", - " df_diff = output_list[i] - output_list[0]\n", - "\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " df_diff_all.loc[:, scen_name] = df_diff.loc[:,2050]\n", - " i+=1\n", - "\n", - "fig, ax = plt.subplots(figsize=(9,8))\n", - "df_diff_all.transpose().plot(kind='bar',stacked=True, ax = ax, color = df_diff_all.index.map(tech_colormap), legend=False)\n", - "# plt.ylim([-6, 4])\n", - "plt.ylabel('Difference in 2050 energy consumption (EJ) \\n relative to preceding scenario (to the left)')\n", - "plt.legend()\n", - "\n", - "handles, labels = subp.get_legend_handles_labels()\n", - "unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - "plt.legend(*zip(*unique[::-1]), loc='lower left', frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "plt.tight_layout()\n", - "\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_highC_buidlingsdiff.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "17fdc74d", - "metadata": {}, - "outputs": [], - "source": [ - "output_list = []\n", - "fig, ax = plt.subplots(figsize=(10,6))\n", - "for conn, scenario in zip(list_of_conns, list_of_scenarios):\n", - " df_plot = stacked_penergy_sector(conn, scenario, 'commercial', 'All')\n", - " df_plot /=1000\n", - " df_plot_copy = df_plot.copy()\n", - " df_plot_copy.index = df_plot_copy.index.map(tech_commercial)\n", - " df_plot_copy = df_plot_copy.reset_index().groupby(by=['input_comm']).sum()\n", - "\n", - " fuels_order = ['Other Fossil', 'Natural Gas','Synthetic Natural Gas','Electricity']\n", - "\n", - " add_ind = [x for x in fuels_order if x not in df_plot_copy.index]\n", - " for ind in add_ind:\n", - " df_plot_copy.loc[ind,:] = 0\n", - " df_plot_copy = df_plot_copy.loc[fuels_order]\n", - " df_plot_copy = df_plot_copy[[2020, 2030, 2040, 2050]]\n", - "\n", - " output_list.append(df_plot_copy)\n", - "ax = func_stacked_plot(output_list, col_order = fuels_order, color_dict = tech_colormap)\n", - "\n", - "num_dfs = len(output_list)\n", - "col_spacing = [x - (num_dfs / 1.8 - 0.4) for x in np.arange(num_dfs)]\n", - "i = 0\n", - "period_placement= 2020\n", - "for spacing in col_spacing:\n", - " db = list_of_DBs[i]\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " plt.annotate(scen_name, (period_placement+spacing, \\\n", - " output_list[i][period_placement].sum()+ output_list[0][period_placement].sum()*0.05), \\\n", - " rotation = 'vertical', \\\n", - " horizontalalignment='center', verticalalignment='bottom', fontsize=14, color='grey')\n", - " i+=1\n", - " \n", - "plt.ylabel('Energy consumption (EJ)')\n", - "plt.grid(axis='x')\n", - "plt.ylim([0,15])\n", - "\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_highC_commercial.jpg')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3a5f1884", - "metadata": {}, - "outputs": [], - "source": [ - "i = 0\n", - "df_diff_all = pd.DataFrame()\n", - "for conn, scenario, db in zip(list_of_conns, list_of_scenarios, list_of_DBs):\n", - " if i!=0:\n", - " df_diff = output_list[i] - output_list[i-1]\n", - " else:\n", - " df_diff = output_list[i] - output_list[0]\n", - "\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " df_diff_all.loc[:, scen_name] = df_diff.loc[:,2050]\n", - " i+=1\n", - "\n", - "fig, ax = plt.subplots(figsize=(9,8))\n", - "df_diff_all.transpose().plot(kind='bar',stacked=True, ax = ax, color = df_diff_all.index.map(tech_colormap), legend=False)\n", - "# plt.ylim([-6, 4])\n", - "plt.ylabel('Difference in 2050 energy consumption (EJ) \\n relative to preceding scenario (to the left)')\n", - "plt.legend()\n", - "\n", - "handles, labels = subp.get_legend_handles_labels()\n", - "unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - "plt.legend(*zip(*unique[::-1]), loc='lower left', frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "plt.tight_layout()\n", - "\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_highC_commercialdiff.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7ec4ac4a", - "metadata": {}, - "outputs": [], - "source": [ - "output_list = []\n", - "\n", - "for conn, scenario in zip(list_of_conns, list_of_scenarios):\n", - "\n", - " query = \"SELECT t_periods, tech, sum(emissions) as emissions FROM Output_Emissions \\\n", - " WHERE emissions_comm='co2' AND emissions <-0.001 GROUP BY t_periods, tech\"\n", - " df_read_emissions_cdr = pd.read_sql_query(query, conn)\n", - " df_read_emissions_cdr['emissions']/=1000\n", - " df_read_emissions_cdr = df_read_emissions_cdr.pivot_table(index='tech', columns='t_periods', values = 'emissions')\n", - " output_list.append(df_read_emissions_cdr)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "93819ec2", - "metadata": {}, - "outputs": [], - "source": [ - "fig, ax = plt.subplots(figsize=(10,6))\n", - "i=0\n", - "plt.xlim([2020, 2050])\n", - "for db in output_list:\n", - " \n", - " try:\n", - " scen_name = map_scenario_names[list_of_DBs[i].replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " plt.plot(-db.loc['CO2_Capture_ground'], label = scen_name)\n", - " i+=1\n", - " \n", - "plt.legend()\n", - "\n", - "handles, labels = ax.get_legend_handles_labels()\n", - "unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - "plt.legend(*zip(*unique[::-1]), loc='upper left', frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "ax.tick_params(axis = 'x', labelrotation=90)\n", - "plt.ylim([0, 1400])\n", - "plt.ylabel('CO$_2$ DAC to sequestration (million tonnes)')\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_highC_DAC_ground.jpg')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "446e9891", - "metadata": {}, - "outputs": [], - "source": [ - "fig, ax = plt.subplots(figsize=(10,6))\n", - "i=0\n", - "plt.xlim([2020, 2050])\n", - "for db in output_list:\n", - " try:\n", - " scen_name = map_scenario_names[list_of_DBs[i].replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " plt.plot(-db.loc['BECCS_H2_N'] - db.loc['E_BECCS_N'], label = scen_name)\n", - " i+=1\n", - " \n", - "plt.ylim([0, 1400])\n", - "plt.legend()\n", - "\n", - "handles, labels = ax.get_legend_handles_labels()\n", - "unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - "plt.legend(*zip(*unique[::-1]), loc='upper left', frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "ax.tick_params(axis = 'x', labelrotation=90)\n", - "\n", - "plt.ylabel('CO$_2$ BECCS (million tonnes)')\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_highC_BECCS.jpg')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3ecce831", - "metadata": {}, - "outputs": [], - "source": [ - "#compare hydrogen use across sectors\n", - "def return_h2_shares(conn):\n", - " query = \"SELECT t_periods, input_comm, sum(vflow_out) as Transport FROM Output_VFlow_Out WHERE sector = 'transport' AND \\\n", - " (input_comm = 'H2' OR input_comm = 'LH2' OR input_comm='T_Liquids' OR input_comm='SNG_100' OR input_comm = 'MEOH') GROUP BY t_periods, input_comm\"\n", - " df_h2_transport = pd.read_sql_query(query, conn)\n", - "\n", - " query = \"SELECT t_periods,input_comm, sum(vflow_out) as Industrial FROM Output_VFlow_Out WHERE sector = 'industrial' AND \\\n", - " (input_comm = 'H2_100' OR input_comm='SNG_100') GROUP BY t_periods, input_comm\"\n", - " df_h2_industrial = pd.read_sql_query(query, conn)\n", - "\n", - " query = \"SELECT t_periods, input_comm, sum(vflow_out) as Residential FROM Output_VFlow_Out WHERE sector = 'residential' AND \\\n", - " (input_comm = 'SNG_100') GROUP BY t_periods, input_comm\"\n", - " df_h2_residential = pd.read_sql_query(query, conn)\n", - "\n", - " query = \"SELECT t_periods, input_comm, sum(vflow_out) as Commercial FROM Output_VFlow_Out WHERE sector = 'commercial' AND \\\n", - " (input_comm = 'SNG_100') GROUP BY t_periods, input_comm\"\n", - " df_h2_commercial = pd.read_sql_query(query, conn)\n", - " \n", - " query = \"SELECT t_periods, sum(vflow_out) as Electric FROM Output_VFlow_Out WHERE sector LIKE 'electric%' AND \\\n", - " (input_comm = 'H2_100') GROUP BY t_periods\"\n", - " df_h2_electric = pd.read_sql_query(query, conn)\n", - "\n", - " #t_liquids\n", - " query = \"SELECT t_periods, input_comm, sum(vflow_out) AS t_liquids FROM Output_VFlow_Out WHERE \\\n", - " (input_comm = 'H2_100' AND output_comm='T_Liquids' ) GROUP BY t_periods, input_comm\"\n", - " df_h2_t_liq_out = pd.read_sql_query(query, conn)\n", - "\n", - " query = \"SELECT t_periods, input_comm, sum(vflow_in) AS h2_100 FROM Output_VFlow_In WHERE \\\n", - " (input_comm = 'H2_100' AND output_comm='T_Liquids' ) GROUP BY t_periods, input_comm\"\n", - " df_h2_t_liq_in = pd.read_sql_query(query, conn)\n", - "\n", - " df_h2_t_liq = pd.merge(df_h2_t_liq_in, df_h2_t_liq_out)\n", - " df_h2_t_liq['ratio'] = df_h2_t_liq['h2_100']/df_h2_t_liq['t_liquids']\n", - "\n", - " mask = df_h2_transport['input_comm']=='T_Liquids'\n", - " ratios = df_h2_transport.loc[mask].merge(df_h2_t_liq, on='t_periods', how='left')['ratio'].values\n", - " df_h2_transport.loc[mask, 'Transport'] *= ratios\n", - " \n", - " #MEOH\n", - " query = \"SELECT t_periods, input_comm, sum(vflow_out) AS meoh FROM Output_VFlow_Out WHERE \\\n", - " (input_comm = 'H2_100' AND output_comm='MEOH' ) GROUP BY t_periods, input_comm\"\n", - " df_h2_meoh_out = pd.read_sql_query(query, conn)\n", - "\n", - " query = \"SELECT t_periods, input_comm, sum(vflow_in) AS h2_100 FROM Output_VFlow_In WHERE \\\n", - " (input_comm = 'H2_100' AND output_comm='MEOH' ) GROUP BY t_periods, input_comm\"\n", - " df_h2_meoh_in = pd.read_sql_query(query, conn)\n", - "\n", - " df_h2_meoh = pd.merge(df_h2_meoh_in, df_h2_meoh_out)\n", - " df_h2_meoh['ratio'] = df_h2_meoh['h2_100']/df_h2_meoh['meoh']\n", - "\n", - " mask = df_h2_transport['input_comm']=='MEOH'\n", - " ratios = df_h2_transport.loc[mask].merge(df_h2_meoh, on='t_periods', how='left')['ratio'].values\n", - " df_h2_transport.loc[mask, 'Transport'] *= ratios\n", - "\n", - "\n", - " #SNG\n", - " query = \"SELECT t_periods, input_comm, sum(vflow_out) AS sng_20 FROM Output_VFlow_Out WHERE \\\n", - " (input_comm = 'H2_100' AND output_comm='SNG_20' ) GROUP BY t_periods, input_comm\"\n", - " df_h2_sng_100_out = pd.read_sql_query(query, conn)\n", - "\n", - " query = \"SELECT t_periods, input_comm, sum(vflow_in) AS h2_100 FROM Output_VFlow_In WHERE \\\n", - " (input_comm = 'H2_100' AND output_comm='SNG_20' ) GROUP BY t_periods, input_comm\"\n", - " df_h2_sng_100_in = pd.read_sql_query(query, conn)\n", - "\n", - " df_h2_sng_100 = pd.merge(df_h2_sng_100_in, df_h2_sng_100_out)\n", - " df_h2_sng_100['ratio'] = df_h2_sng_100['h2_100']/df_h2_sng_100['sng_20']\n", - "\n", - " mask = df_h2_residential['input_comm']=='SNG_100'\n", - " ratios = df_h2_residential.loc[mask].merge(df_h2_sng_100, on='t_periods', how='left')['ratio'].values\n", - " df_h2_residential.loc[mask, 'Residential'] *= ratios\n", - "\n", - " mask = df_h2_commercial['input_comm']=='SNG_100'\n", - " ratios = df_h2_commercial.loc[mask].merge(df_h2_sng_100, on='t_periods', how='left')['ratio'].values\n", - " df_h2_commercial.loc[mask, 'Commercial'] *= ratios\n", - "\n", - " mask = df_h2_transport['input_comm']=='SNG_100'\n", - " ratios = df_h2_transport.loc[mask].merge(df_h2_sng_100, on='t_periods', how='left')['ratio'].values\n", - " df_h2_transport.loc[mask, 'Transport'] *= ratios\n", - " \n", - " mask = df_h2_industrial['input_comm']=='SNG_100'\n", - " ratios = df_h2_industrial.loc[mask].merge(df_h2_sng_100, on='t_periods', how='left')['ratio'].values\n", - " df_h2_industrial.loc[mask, 'Industrial'] *= ratios\n", - "\n", - " df_h2_transport = df_h2_transport.groupby('t_periods')['Transport'].sum().reset_index()\n", - " df_h2_residential = df_h2_residential.groupby('t_periods')['Residential'].sum().reset_index()\n", - " df_h2_commercial = df_h2_commercial.groupby('t_periods')['Commercial'].sum().reset_index()\n", - " df_h2_industrial = df_h2_industrial.groupby('t_periods')['Industrial'].sum().reset_index()\n", - "\n", - " df_h2 = pd.merge(df_h2_transport, df_h2_industrial, on = 't_periods', how='outer')\n", - " df_h2 = pd.merge(df_h2, df_h2_residential, on = 't_periods', how='outer')\n", - " df_h2 = pd.merge(df_h2, df_h2_commercial, on = 't_periods', how='outer')\n", - " df_h2 = pd.merge(df_h2, df_h2_electric, on = 't_periods', how='outer')\n", - "\n", - " df_h2 = df_h2.sort_values(by='t_periods')\n", - " df_h2.set_index('t_periods',inplace=True)\n", - " df_h2.fillna(0, inplace=True)\n", - " df_h2[df_h2<0]=0\n", - " return df_h2\n", - "\n", - "output_list = []\n", - "for conn, scenario in zip(list_of_conns, list_of_scenarios):\n", - " df_h2 = return_h2_shares(conn)\n", - " output_list.append(df_h2.transpose())\n", - "\n", - "fig, ax = plt.subplots(figsize=(8,6))\n", - "\n", - "func_stacked_plot(output_list, ax= ax, col_order = \\\n", - " ['Electric','Transport', 'Industrial','Residential','Commercial'], loc='inside_upper_left')\n", - "\n", - "num_dfs = len(output_list)\n", - "col_spacing = [x - (num_dfs / 1.8 - 0.5) for x in np.arange(num_dfs)]\n", - "i = 0\n", - "period_placement= 2035\n", - "for spacing in col_spacing:\n", - " db = list_of_DBs[i]\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('.sqlite','').split('_')[3]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " plt.annotate(scen_name, (period_placement+spacing, \\\n", - " output_list[i][period_placement].sum()+ output_list[0][period_placement].sum()*0.05), \\\n", - " rotation = 'vertical', \\\n", - " horizontalalignment='center', verticalalignment='bottom', fontsize=14, color='grey')\n", - " i+=1\n", - " \n", - "ax.grid(axis='x')\n", - "# plt.ylim([0, 5000])\n", - "ax.get_yaxis().set_major_formatter(\n", - "tick.FuncFormatter(lambda x, p: format(int(x), ',')))\n", - "plt.ylabel('Hydrogen consumption (PJ)')\n", - "plt.tight_layout()\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_hydrogen_consumption_highC.jpg')\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "16b43746", - "metadata": {}, - "outputs": [], - "source": [ - "i = 0\n", - "df_diff_all = pd.DataFrame()\n", - "for conn, scenario, db in zip(list_of_conns, list_of_scenarios, list_of_DBs):\n", - " if i!=0:\n", - " df_diff = output_list[i] - output_list[i-1]\n", - " else:\n", - " df_diff = output_list[i] - output_list[0]\n", - "\n", - " try:\n", - " scen_name = map_scenario_names[db.replace('sqlite','').split('_')[4]]\n", - " except:\n", - " scen_name = map_scenario_names['']\n", - " df_diff_all.loc[:, scen_name] = df_diff.loc[:,2050]\n", - " i+=1\n", - "\n", - "fig, ax = plt.subplots(figsize=(9,8))\n", - "df_diff_all.transpose().plot(kind='bar',stacked=True, ax = ax, color = df_diff_all.index.map(color_dict), legend=False)\n", - "# plt.ylim([-6, 4])\n", - "plt.ylabel('Difference in 2050 energy consumption (PJ) \\n relative to preceding scenario (to the left)')\n", - "plt.legend()\n", - "\n", - "handles, labels = subp.get_legend_handles_labels()\n", - "unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels))\n", - " if l not in labels[:i]]\n", - "plt.legend(*zip(*unique[::-1]), loc='lower left', frameon=False) # changing plt to ax gives you legends for each of the graphs\n", - "\n", - "plt.tight_layout()\n", - "\n", - "plt.savefig('carbon_tax_figures_updates/carbontax_compare_hydrogen_consumption_highC_diff.jpg')\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.0" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/loan_cost_primer.ipynb b/notebooks/loan_cost_primer.ipynb deleted file mode 100644 index 7182558eb..000000000 --- a/notebooks/loan_cost_primer.ipynb +++ /dev/null @@ -1,470 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "source": [ - "## Loan Costing Discussion\n", - "This example uses the cost formulae from the `temoa_rules.py` file in order to verify costs used for loan. The Temoa dox for the loan cost explain the original formula fairly well. The original pointer to the formula is from Kevin Hunter et. all paper in ~2013. See equation (15) on the included document and description. Of particular note, that document uses the loan lifetime in a few spots, and somewhere along the way the tech lifetime crept into the formula in the form of the `lifetime_process` variable, which seems like a mistake\n", - "\n" - ], - "metadata": { - "collapsed": false - }, - "id": "54ecbe852dc90f38" - }, - { - "cell_type": "markdown", - "source": [ - "### Key Questions:\n", - "1. What is `discount_rate`? It looks and smells like the loan rate. The dox are just wrong.\n", - "2. Is the inclusion of the process lifetime in the loan cost calculation a typo? Seems it should be loan life across the board\n", - "3. Is the approach to undiscounted correct?\n", - "4. It is unclear what the plan is for \"hurdle rate\" -- and if any support from me is needed on that\n", - "\n", - "### Ponderings...\n", - "- Note that in none of these approaches renders the \"full cost\" of a scenario visible because of the eclipsing effect of the end of the window in perfect foresight or the end of the shorter myopic windows.\n", - "- A corollary of that (that I stumbled into the other day during testing) is that it is impossible to compare costs when using different myopic view depths. More clearly: When I changed from a view depth of 1 to 2 (seeing further into the future), I expected cost to go down--as they should--but they went up, which is attributable to having more of the loan lives visible to the calculation. This may/may not be important to the team. It is just an observation.\n", - "- It wouldn't be too much work to enable a 3rd mode for these to calculate the \"full cost\" by making the windowing feature conditional on some flag." - ], - "metadata": { - "collapsed": false - }, - "id": "8bb6c026095b6680" - }, - { - "cell_type": "markdown", - "source": [ - "### Desired outcome:\n", - "- Concurrence or edits to formulae\n", - "- About 4 test values that I can incorporate into unit tests that exercise the discount rate, GDR, and eclipsing effect of the period end, and discounted/undiscounted test values (similar to what is used below)" - ], - "metadata": { - "collapsed": false - }, - "id": "fcf4ce5e6305e7ef" - }, - { - "cell_type": "markdown", - "source": [ - "### Formulae\n", - "The below 2 formulae are the current implementations in the model that I have extracted out of the cost computation so that they can be used both by the model and in post-processing--basically single-sourcing the formula. It was replicated in several areas before, which is an invitation for problems." - ], - "metadata": { - "collapsed": false - }, - "id": "e706138552927b3c" - }, - { - "cell_type": "markdown", - "source": [ - "### Notes: \n", - "#### \"Undiscounted\" cost\n", - "This was previously calculated in post-processing (not used at all in the model) was pretty wonky. I have disregarded it and I think the below is a better place to **start** the discussion. The intent of the fomula for loan_cost is to produce a undiscounted cost when GDR==0.\n", - "#### discount_rate\n", - "I have not renamed this, but this is central to the discussion. It is applied as and probably should be renamed as the `loan_rate`. TBD on how you want to handle \"hurdle rate.\"\n" - ], - "metadata": { - "collapsed": false - }, - "id": "2fe340463d16c00b" - }, - { - "cell_type": "code", - "source": [ - "from pyomo.environ import Var, Expression" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-09T20:34:40.165454Z", - "start_time": "2024-04-09T20:34:40.163675Z" - } - }, - "id": "6786fe13296c8574", - "execution_count": 14, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "def loan_annualization_rate(loan_rate: float | None, loan_life: int | float) -> float:\n", - " \"\"\"\n", - " This calculation is broken out specifically so that it can be used for param creation\n", - " and separately to calculate loan costs rather than rely on fully-built model parameters\n", - " :param loan_rate: The loan rate\n", - " :param loan_life: The term (years) of the loan\n", - "\n", - " \"\"\"\n", - " if not loan_rate:\n", - " # dev note: this should not be needed as the LoanRate param has a default (see the definition)\n", - " return 1.0 / loan_life\n", - " annualized_rate = loan_rate / (1.0 - (1.0 + loan_rate) ** (-loan_life))\n", - " return annualized_rate" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-09T20:34:40.178102Z", - "start_time": "2024-04-09T20:34:40.176150Z" - } - }, - "id": "6fc96307ef6013fb", - "execution_count": 15, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "def loan_cost(\n", - " capacity: float | Var,\n", - " invest_cost: float,\n", - " loan_annualize: float,\n", - " lifetime_loan_process: float | int,\n", - " P_0: int,\n", - " P_e: int,\n", - " GDR: float,\n", - " vintage: int,\n", - ") -> float | Expression:\n", - " \"\"\"\n", - " function to calculate the loan cost. It can be used with fixed values to produce a hard number or\n", - " pyomo variables/params to make a pyomo Expression\n", - " :param capacity: The capacity to use to calculate cost\n", - " :param invest_cost: the cost/capacity\n", - " :param loan_annualize: parameter\n", - " :param lifetime_loan_process: lifetime of the loan\n", - " :param P_0: the year to discount the costs back to\n", - " :param P_e: the 'end year' or cutoff year for loan payments\n", - " :param GDR: Global Discount Rate\n", - " :param vintage: the base year of the loan\n", - " :return: fixed number or pyomo expression based on input types\n", - " \"\"\"\n", - " if GDR == 0: # return the non-discounted result\n", - " regular_payment = capacity * invest_cost * loan_annualize\n", - " payments_made = min(lifetime_loan_process, P_e - vintage)\n", - " return regular_payment * payments_made\n", - " x = 1 + GDR # a convenience\n", - " res = (\n", - " capacity\n", - " * (\n", - " invest_cost\n", - " * loan_annualize\n", - " * (\n", - " lifetime_loan_process\n", - " if not GDR\n", - " else (x ** (P_0 - vintage + 1) * (1 - x ** (-lifetime_loan_process)) / GDR)\n", - " )\n", - " )\n", - " * (\n", - " (1 - x ** (-min(lifetime_loan_process, P_e - vintage)))\n", - " / (1 - x ** (-lifetime_loan_process))\n", - " )\n", - " )\n", - " return res" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-09T20:34:40.218556Z", - "start_time": "2024-04-09T20:34:40.193819Z" - } - }, - "id": "44ece17e11ca078a", - "execution_count": 16, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### Exemplar tech data\n", - "Consider an anonymous `tech` in a myopic run with periods @ 5 year increments [2020, 2050] and a myopic view of 1 period at a time.\n", - "In the myopic window 2030 -> 2035 a decision is made to build 100K capacity units:\n" - ], - "metadata": { - "collapsed": false - }, - "id": "bf57ce2583a5b515" - }, - { - "cell_type": "code", - "source": [ - "capacity = 100_000 # units\n", - "cost_invest = 1 # $/unit of capacity\n", - "loan_life = 40\n", - "loan_rate = 0.08\n", - "GDR = 0.05\n", - "tech_lifetime = 50\n", - "base_year = 2020 # the \"myopic base year\" to which all prices are discounted\n", - "vintage = 2030 # the vintage of the new 'tech'\n", - "window_end = 2035 # last year in the myopic view" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-09T20:34:40.221183Z", - "start_time": "2024-04-09T20:34:40.219509Z" - } - }, - "id": "ce1bcf1453d44d6", - "execution_count": 17, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "#### We need LoanAnnualize...\n", - "LoanAnnualize is a model parameter that is computed within the model using the discount rate specific to that process. I have also \"extracted the math\" to a separate function that can is also dual-use (making the parameter, or externally producing a hard number)\n" - ], - "metadata": { - "collapsed": false - }, - "id": "58218ee0e550b94a" - }, - { - "cell_type": "code", - "source": "loan_annualize = loan_annualization_rate(loan_rate=loan_rate, loan_life=loan_life)", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-09T20:34:40.223325Z", - "start_time": "2024-04-09T20:34:40.221840Z" - } - }, - "id": "a790bdc43d4fb128", - "execution_count": 18, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "print(f\"Loan annualization rate: {loan_annualize:0.4f}\")" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-09T20:34:40.225797Z", - "start_time": "2024-04-09T20:34:40.224302Z" - } - }, - "id": "ee945bc2df5c8f70", - "execution_count": 19, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "cost = loan_cost(\n", - " capacity=capacity,\n", - " invest_cost=cost_invest,\n", - " loan_annualize=loan_annualize,\n", - " lifetime_loan_process=loan_life,\n", - " P_0=base_year,\n", - " P_e=window_end,\n", - " GDR=GDR,\n", - " vintage=vintage\n", - ")" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-09T20:34:40.227870Z", - "start_time": "2024-04-09T20:34:40.226388Z" - } - }, - "id": "675f7cf04200c8f8", - "execution_count": 20, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "print(f\"Loan cost: ${cost:,.2f}\")" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-09T20:34:40.229793Z", - "start_time": "2024-04-09T20:34:40.228285Z" - } - }, - "id": "3d6354622519237e", - "execution_count": 21, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "#### And the Undiscounted ..." - ], - "metadata": { - "collapsed": false - }, - "id": "57e9ba26dccbcef7" - }, - { - "cell_type": "code", - "source": [ - "undiscounted_cost = loan_cost(\n", - " capacity=capacity,\n", - " invest_cost=cost_invest,\n", - " loan_annualize=loan_annualize,\n", - " lifetime_loan_process=loan_life,\n", - " P_0=base_year,\n", - " P_e=window_end,\n", - " GDR=0, # <-- override with a zero\n", - " vintage=vintage\n", - ")" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-09T20:34:40.232090Z", - "start_time": "2024-04-09T20:34:40.230405Z" - } - }, - "id": "82b8f08bc0780562", - "execution_count": 22, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "print(f\"Undiscounted Loan cost: ${undiscounted_cost:,.2f}\")" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-09T20:34:40.234124Z", - "start_time": "2024-04-09T20:34:40.232706Z" - } - }, - "id": "e99fb0c033558324", - "execution_count": 23, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### Are these correct?\n", - "The end of the window is eclipsing most future payments.\n", - "If the problem were \"perfect foresight\" then..." - ], - "metadata": { - "collapsed": false - }, - "id": "969780f884c44684" - }, - { - "cell_type": "code", - "source": [ - "window_end = 2050 # overwrite the value of the window end\n", - "\n", - "cost = loan_cost(\n", - " capacity=capacity,\n", - " invest_cost=cost_invest,\n", - " loan_annualize=loan_annualize,\n", - " lifetime_loan_process=loan_life,\n", - " P_0=base_year,\n", - " P_e=window_end,\n", - " GDR=GDR,\n", - " vintage=vintage\n", - ")\n", - "print(f\"Loan cost: ${cost:,.2f}\")" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-09T20:34:40.236367Z", - "start_time": "2024-04-09T20:34:40.234543Z" - } - }, - "id": "63eaa2ed2074c123", - "execution_count": 24, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### Or if the end of the window exposed the entire loan life...\n" - ], - "metadata": { - "collapsed": false - }, - "id": "b1ebba20323f39c4" - }, - { - "cell_type": "code", - "source": [ - "window_end = 2100 # override to expose full loan length\n", - "\n", - "cost = loan_cost(\n", - " capacity=capacity,\n", - " invest_cost=cost_invest,\n", - " loan_annualize=loan_annualize,\n", - " lifetime_loan_process=loan_life,\n", - " P_0=base_year,\n", - " P_e=window_end,\n", - " GDR=GDR,\n", - " vintage=vintage\n", - ")\n", - "print(f\"Loan cost: ${cost:,.2f}\")" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-09T20:34:40.239344Z", - "start_time": "2024-04-09T20:34:40.237873Z" - } - }, - "id": "1cee546365df4909", - "execution_count": 25, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "undiscounted_cost = loan_cost(\n", - " capacity=capacity,\n", - " invest_cost=cost_invest,\n", - " loan_annualize=loan_annualize,\n", - " lifetime_loan_process=loan_life,\n", - " P_0=base_year,\n", - " P_e=window_end,\n", - " GDR=0, # <-- set to zero\n", - " vintage=vintage\n", - ")\n", - "print(f\"Undiscounted Loan cost: ${undiscounted_cost:,.2f}\")" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-09T20:34:40.241538Z", - "start_time": "2024-04-09T20:34:40.239871Z" - } - }, - "id": "7a13599b5a10281", - "execution_count": 26, - "outputs": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/temoa_utopia_analysis_with_pyam.ipynb b/notebooks/temoa_utopia_analysis_with_pyam.ipynb deleted file mode 100644 index c8dd8af56..000000000 --- a/notebooks/temoa_utopia_analysis_with_pyam.ipynb +++ /dev/null @@ -1,439 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Analysis of Temoa Utopia results using pyam\n", - "\n", - "The file `temoa_utopia_pyam.xlsx` used in this notebook is created by running the \"Utopia\" model\n", - "\n", - " $ python temoa_model/ --config=temoa_model/config_sample\n", - "\n", - "Running **Temoa** exports the results (among other formats) in an Excel format compatible\n", - "with the IAMC timeseries template\n", - "used by the IPCC WG3, the Energy Modeling Forum, and numerous EU Horizon 2020 projects\n", - "([read more](https://pyam-iamc.readthedocs.io/en/stable/data.html)).\n", - "\n", - "The **pyam** package provides a suite of tools for analysis and visualization\n", - "of energy systems scenarios based on that format - [read the docs](https://pyam-iamc.readthedocs.io)!" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "application/javascript": [ - "IPython.OutputArea.prototype._should_scroll = function(lines) { return false; }" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import pyam" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "pyam - INFO: Running in a notebook, setting up a basic logging config at level INFO\n", - "pyam.core - INFO: Reading file temoa_utopia_test_run_model/test_run_pyam.xlsx\n", - "pyam.core - INFO: Reading meta indicators\n" - ] - } - ], - "source": [ - "df = pyam.IamDataFrame('temoa_utopia_test_run_model/test_run_pyam.xlsx')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Visualization of CO2 emissions by species and sectors\n", - "\n", - "The first plot shows the aggregate CO2 and NOx emissions over the model horizon." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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lBRq1KhBbGws5zbzVIHCGENqaiopKSm0bNnS6XCUUh4E7eWgzMxM6tWrpwkggIkI9erV07M1pQJY0CYBQBNAENDPSKnAFtRJQCmlQtXB45lM/HoTx0/n+HQ+QXtPQCmlQtGR9CwmL9rBpyt24zKGS1vXY0D7hj6bn54JlENERARdunQ583j55ZdL/N79+/dz8803l3qeI0eOZNOmTaV+X1HK2pLj888/p1OnTnTq1IlLL72UpKQkr8alVDg5fiqH1+Zups+rC/lw2U6u79yEBY/29WkCAD0TKJcqVaqQmJhYpvc2adKEL774otTve//998s0P19o2bIlixcvpk6dOnz33XeMGjWKX375xemwlAoqJzNz+GjZLt77KZn0rFyu69SEsQPa0rp+db/MPySSwPNfb2TT/hNenWb7JjWZcF2HMr03NjaWO+64g4ULF5KTk8OUKVMYN24c27dv5/HHH2f06NHs2rWLIUOGsGHDBjZu3Mi9995LdnY2LpeLL7/8kiZNmnDLLbeQkpJCXl4ezzzzDLfeeit9+/bl9ddfJz4+noSEBP7xj39gjOHaa6/llVdeAaB69eqMHTuWb775hipVqjB79mwaNmzIjBkzeP7554mIiKBWrVosWbLkvNi///57nn76afLy8oiOjubHH3/k6NGjjBgxguTkZKpWrcqUKVPOHP3n69mzJykpfvvVQqWC3unsPD5ZvovJi3dw7FQOg9o35JFBcVzYqKZf4wiJJOCU06dP06VLlzN/jxs3jltvvRWA5s2bs3z5ch5++GGGDx/OsmXLyMzMpEOHDowePfqc6UyePJmxY8cybNgwsrOzycvL43//+x9NmjTh22+/BeD48ePnvGf//v08+eSTrF69mjp16jBo0CBmzZrFjTfeSEZGBj179uTFF1/kiSee4L333mP8+PFMnDiRuXPn0rRpU9LS0s5bnsOHD3PfffexZMkSWrZsydGjRwGYMGECXbt2ZdasWSxYsIC77777vDOgDz74gKuvLulP/yoVvrJy85j6617eXridwyezuCKuPo8OiqNTs9qOxBMSSaCsR+zlVdTloOuvvx6Ajh07kp6eTo0aNahRowZRUVHn7YB79erFiy++SEpKCkOHDqVt27Z07NiRxx57jCeffJIhQ4bQu/e5v2e+cuVK+vbtS/36VpfYYcOGsWTJEm688UYqVarE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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "df.filter(variable='Emissions|*', level=0).plot()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The next plot shows the CO2 emissions by sector." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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bNjOiuZLTk5WTk5OcX5+fsPy07Kysg49+uijhc8++2xbSdq4cWNyp06dvh6gtH///vvLLxOvT58+B7Kzsw/WpL7VoSUDQJ1Lm/jXWimnYMoVtVIOat/BgweTunbtmhV7fu+992644447dkhSp06dDi1ZsmTV7bff3mnEiBFpCxcuXLV///6kHj16dJ8wYcIRg1hNnTo1dcyYMZtGjx69/cCBA1ZaWqrXX3/9jHbt2pXMmzdvjSRt27atQfwyBQUFyZMnT+6wePHilampqaXf/va3M2bMmHHmTTfdtHP//v1JAwcOLJ46der6UaNGdZw6dWrqo48+umHKlClnvf3226u7dOlSsnXr1iPKk6SioqLI2LFj0+bNm7eqa9euhzZt2tRAkiZMmNA+Ozt739/+9rfPZ8+e3fyWW27pUr4FZ+rUqW0uuuiiXTXZb4MHD94zatSozqWlpXrttddaTZ8+fd0TTzxxVvn59uzZk/Tee++1mDRp0vqKyvnWt761b+3atY0k6Uc/+tHmW2+99RvPPPPMvkGDBu0ePXr0trS0tJKa1OdE0ZIBAKh1sdMlsUcsYEjStddeu1OSevbsua9Pnz57W7ZsWda+ffvShg0blpX/gh84cODexx577KwHH3ywXX5+fkqzZs28T58++//xj3+0GD16dIe5c+c2a9269eH4ZebPn990wIABe9q3b1+anJys6667bvu7777bTJKSk5P9+uuv3yVJffv23btu3boUSerXr1/xDTfckPbYY4+1KS0tPWp75s2b1zQnJ2dP165dD0lS27ZtD0vSRx991Pz222/fJklXXnnlnp07d0biQ8+cOXOaz5w5s81TTz31VU32WyQS8ZycnOIXXnih1YEDB5IyMzMPxU8vLCxs2LVr16ycnJyugwcP3nXttdfurqgc939eXHT11VfvXrNmzbLbbrtta15eXuO+fftmFRUV1UkjAyEDAFCnGjVq5JKUlJSklJSUr78Nk5KSVFJSYvHzjho1avubb765pnHjxmVDhgzJmD17dvNevXod/OSTT3J79uy5/8EHH+xw3333HfFLP/4LtrxIJOKxTpWRSESlpaUmSX/605++/OUvf1lUWFiY0rt37+4bN248Iuy4u8zsqPIqWpeZuRT0fRgzZkznWbNmrWnXrt3ho2asxA033LB94sSJZw8fPnxH+WmxPhkrV67M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zUeMmBobu2TVqlUrVq9e3XjmzJlnVlfmo48+mvr3v/+9xeLFi1fm5+evWLBgQV7sRpzjx4/vUFxcnLR27drl69atW37llVfu/O53v3tuWVmZJGnEiBFbZ8+efVx3+5TqIGSYWQMz+9TM3gp7XQCAxNahQ4eeY8eO7dC7d++uPXr06DZ//vwm559/fnqnTp16PProo6mSlJeXl5Kent5dkhYtWtSoZ8+e3bp27ZqVkZGRtWzZsoa7d+9OGjRo0LmZmZlZ6enp3WPDyOfk5GS+9957TSTpueeea5WRkZGVnp7effTo0R1i62/SpMl548aN65CZmZmVnZ3dtbCwMCJJ06dPb5ment49MzMzq1+/fpkV1f31119vkZWV1S0zMzNr4MCBGVIwhsmll156TkZGRlZ2dnbXhQsXNpakyy67bG9qauphKRj3ZOPGjSkVlVne8OHDt7/88sutJGnmzJlnDhs2bGdF8yUnJysnJ6c4Pz+/YXVlPvHEE+2ee+65L1u1alUmSa1btz48bty4bXv27El69dVX2zz77LOFkUhwYuOuu+7alpKSUjZnzpzmkjRkyJDi1NTUo4elraG6aMm4S1KN7tcOADg1xMYuiT1iQUCSOnXqdGjJkiWr+vfvXzxixIi0OXPmfL5w4cJVU6ZMaV++nKlTp6aOGTNm06pVq3KXLl26skuXLofeeOONFu3atSvJy8vLzc/PXzF8+PAjhjsvKChInjx5cod58+atzs3NXfHpp582nTFjxpmStH///qSBAwcW5+Xl5Q4cOLB46tSpqZI0ZcqUs95+++3VeXl5uXPnzl1Tvh5FRUWRsWPHpr3xxhuf5+Xl5c6aNetzSZowYUL77OzsfatXr879xS9+sf6WW27pUsE2tLnooot21WS/DR48eM+HH37YLDaw280331zhIGl79uxJeu+991r06tVrv/TPIeBjjz/+8Y+pUjAg2t69ext07979qEHacnNzG5511lmHYuEjpnfv3vuWLVvWuCb1rU6oIcPMOkq6QtILYa4HAJBYyp8uueOOO74etvzaa6/dKUk9e/bc16dPn70tW7Ysa9++fWnDhg3Ltm7desQQ6wMHDtz72GOPnfXggw+2y8/PT2nWrJn36dNn/z/+8Y8Wo0eP7jB37txm5e+eOX/+/KYDBgzY0759+9Lk5GRdd9112999991mkpScnOzXX3/9Lknq27fv3nXr1qVIUr9+/YpvuOGGtMcee6xNaenRP9znzZvXNCcnZ0/Xrl0PScHQ6ZL00UcfNb/99tu3SdKVV165Z+fOnZFt27Z9vQ1z5sxpPnPmzDZPPfXUVzXZb5FIxHNycopfeOGFVgcOHEgqP75JLEzk5OR0HTx48K5rr712t3TEaZTcVatW5d58881bpMqHqJeksrKyr4elj1fVMscq7JaMJyVNkFRWzXwAgNNEo0aNXApGG01JSfn6Sy4pKUklJSVHfLuNGjVq+5tvvrmmcePGZUOGDMmYPXt28169eh385JNPcnv27Ln/wQcf7HDfffedFb9MVQN/RiIRj3WqjEQiKi0tNUn605/+9OUvf/nLosLCwpTevXt337hx4xFhp7Iv3orWFfviXrhwYeMxY8Z0njVr1pp27drV+DbiN9xww/aJEyeePXz48B3lp8XCxMqVK3Mff/zxourKatWqVVnjxo3LcnNzjzpd071794NFRUUNd+zYcUQWWLp0aZMePXrsLz//8QgtZJjZUEmb3b3KXshmdqeZLTKzRVu2bAmrOgCAk1Bubm5Kt27dDj700EObBw8evHPJkiWNCwoKkps3b142ZsyY7XffffemJUuWNIlf5oILLti7cOHC5hs2bIjETjsMGjSouKr1rFixouHFF1+898knnyxq2bJl6RdffHHEl/JFF120d+HChc1XrVqVIgV9MSRpwIABe1588cXWkvTWW281b9myZWmrVq3K8vPzU6655ppzpk+fvrZXr15HnaqoyuWXX148fvz4DSNGjKjwVMmxuvvuuzeMGjWq8/bt25Mkafv27Um/+c1v2rRo0aLse9/73tbRo0d3irXe/Pa3v2194MCBpGHDhu2pjXWHeQnrv0q60sz+XVIjSS3MbKa73xg/k7s/L+l5KRjqPcT6AMBpqSaXnNa2WJ+M2POLL75417Rp09YfazkzZsxo9dprr7WORCKemppa8sgjjxTNnz+/6QMPPNAxKSlJkUjEp02bti5+mc6dO5dMmjRp/YUXXpjh7nbJJZfsuvHGG3dWtZ577rmnY0FBQUN3t/PPP3/3gAEDjvgl3759+9Knn3664Kqrrjq3rKxMrVu3LlmwYEH+r3/966If/OAHaRkZGVmNGzcue+mll9ZK0kMPPXTWzp07I+PGjessBS0oy5cvr1H/xKSkJMUu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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "df.filter(variable='Emissions|co2|*').plot.bar()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Or if you prefer stacked bar charts..." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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Mh9bQIiIiMh0TECIiIjIdK1iILKOHTtqZGSk1WEQEbUqX3/99UlVDb32kkTmaxUJSGRkJLKzs60Og4ioVRGR2kPKE7UYvARDREREpmMCQkRERKZjAkJERESmYwJCREREpmMCQkRERKZjAkJERESmYwJCREREpmMCQkRERKZrFQOREdHNIe7PcVaH4FW7J+22OgSiFoMtIERERGQ6JiBERERkOiYgREREZDomIERERGQ6JiBERERkOq8lICKyUkROiMieWtPTRcQhIntF5AVv1U9EREQtlzdbQN4FcK/nBBEZBOA+APGq2gvAi16sn4iIiFooryUgqroVQGmtyTMALFXVC65lTnirfiIiImq5zO4DEg3g30UkS0S2iMiP6ltQRB4VkWwRyS4pKTExRCIiIvI2sxMQO4BgACkAfg3gQxGRuhZU1bdVNUlVk0JDQ82MkYiIiLzM7ATkOwCr1fAlACeAjibHQERERBYzOwFZA2AwAIhINAA/ACdNjoGIiIgs5rWH0YnIXwEMBNBRRL4D8DsAKwGsdN2aexHAJFVVb8VARERELZPXEhBVfbCeWRO8VScRERG1DhwJlYiIiEzHBISIiIhMxwSEiIiITMcEhIiIiEzHBISIiIhMxwSEiIiITMcEhIiIiEzHBISIiIhMxwSEiIiITMcEhIiIiEzHBISIiIhMxwSEiIiITMcEhIiIiEzHBISIiIhMxwSEiIiITMcEhIiIiEzntQRERFaKyAkR2VPHvCdFREWko7fqJyIiopbLmy0g7wK4t/ZEEYkAcA+AI16sm4iIiFowryUgqroVQGkds14BMBeAeqtuIiIiatlM7QMiIqMAHFXVnY1Y9lERyRaR7JKSEhOiIyIiIrOYloCISFsACwAsaszyqvq2qiapalJoaKh3gyMiIiJTmdkCcgeAbgB2ikgBgC4AvhGRzibGQERERC2A3ayKVHU3gB+437uSkCRVPWlWDERERNQyePM23L8C+AJAjIh8JyKPeKsuIiIial281gKiqg9eY36kt+omIiKilo0joRIREZHpmIAQERGR6ZiAEBERkemYgBAREZHpmIAQERGR6ZiAEBERkemYgBAREZHpmIAQERGR6ZiAEBERkemYgBAREZHpmIAQERGR6ZiAEBERkemYgBAREZHpmIAQERGR6ZiAEBERkem8loCIyEoROSEiezym/W8R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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "df.filter(variable='Emissions|co2|*').plot.bar(stacked=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Further analysis of emissions\n", - "\n", - "So you want to \"look\" at the actual values of some timeseries?\n", - "\n", - "Here, we first select aggregate CO2 and the emissions by each technology starting with 'IMP'\n", - "(because the other technologies are zero anyway, as we have seen from the plots above)." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
199020002010
modelscenarioregionvariableunit
Temoatest_runutopiaEmissions|co2?5.69633712.15880016.747008
Emissions|co2|IMPDSL1?2.8948052.4549225.453948
Emissions|co2|IMPGSL1?1.4935071.9610392.250000
Emissions|co2|IMPHCO1?1.3080257.7428399.043060
\n", - "
" - ], - "text/plain": [ - " 1990 2000 \\\n", - "model scenario region variable unit \n", - "Temoa test_run utopia Emissions|co2 ? 5.696337 12.158800 \n", - " Emissions|co2|IMPDSL1 ? 2.894805 2.454922 \n", - " Emissions|co2|IMPGSL1 ? 1.493507 1.961039 \n", - " Emissions|co2|IMPHCO1 ? 1.308025 7.742839 \n", - "\n", - " 2010 \n", - "model scenario region variable unit \n", - "Temoa test_run utopia Emissions|co2 ? 16.747008 \n", - " Emissions|co2|IMPDSL1 ? 5.453948 \n", - " Emissions|co2|IMPGSL1 ? 2.250000 \n", - " Emissions|co2|IMPHCO1 ? 9.043060 " - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "co2 = df.filter(variable=['Emissions|co2', 'Emissions|co2|IMP*']).timeseries()\n", - "co2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The next cell uses the [pyam.cumulative](https://pyam-iamc.readthedocs.io/en/stable/api/timeseries.html#pyam.cumulative) function\n", - "to compute the emissions on the timeseries data selected above." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "model scenario region variable unit\n", - "Temoa test_run utopia Emissions|co2 ? 245.026399\n", - " Emissions|co2|IMPDSL1 ? 70.467368\n", - " Emissions|co2|IMPGSL1 ? 40.199675\n", - " Emissions|co2|IMPHCO1 ? 134.359356\n", - "dtype: float64" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "co2.apply(pyam.cumulative, first_year=1990, last_year=2010, axis=1)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And just to prove the usefulness of this function:\n", - "it also works if you select a `first_year` argument that is not a native model year!" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "model scenario region variable unit\n", - "Temoa test_run utopia Emissions|co2 ? 210.082252\n", - " Emissions|co2|IMPDSL1 ? 56.433225\n", - " Emissions|co2|IMPGSL1 ? 32.264610\n", - " Emissions|co2|IMPHCO1 ? 121.384416\n", - "dtype: float64" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "co2.apply(pyam.cumulative, first_year=1995, last_year=2010, axis=1)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Exporting to different file formats\n", - "\n", - "You can use pyam to export your data in different file formats,\n", - "for example as a [frictionless data package](https://frictionlessdata.io)!" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.to_datapackage('utopia.zip')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
\n", - "\n", - "## Questions?\n", - "\n", - "Take a look at [this tutorial](https://pyam-iamc.readthedocs.io/en/stable/tutorials/pyam_first_steps.html) for *first steps with pyam* - then join our [mailing list](https://groups.io/g/pyam)!\n", - "\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} From 0d0cce6f3e0e7f27ad266e6d3700be8b61fb265c Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Mon, 20 Oct 2025 15:03:56 -0400 Subject: [PATCH 256/587] Update unit cost explorer for temoa v4 --- temoa/utilities/unit_cost_explorer.py | 30 +++++++++++++++------------ 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/temoa/utilities/unit_cost_explorer.py b/temoa/utilities/unit_cost_explorer.py index 266585ae2..d2472bcf7 100644 --- a/temoa/utilities/unit_cost_explorer.py +++ b/temoa/utilities/unit_cost_explorer.py @@ -31,6 +31,12 @@ # indices rtv = ('A', 'battery', 2020) # rtv rptv = ('A', 2020, 'battery', 2020) # rptv +M.time_future.construct([2020, 2025, 2030]) # needs to go 1 period beyond optimize horizon +M.time_optimize.construct([2020, 2025]) +M.PeriodLength.construct() +M.tech_all.construct(data=['battery']) +M.regions.construct(data=['A']) +M.regionalIndices.construct(data=['A']) # make SETS M.NewCapacityVar_rtv.construct(data=rtv) @@ -38,20 +44,14 @@ M.CostInvest_rtv.construct(data=rtv) M.CostFixed_rptv.construct(data=rptv) M.LoanLifetimeProcess_rtv.construct(data=rtv) -M.Loan_rtv.construct(data=rtv) -M.LoanRate_rtv.construct(data=rtv) +# M.Loan_rtv.construct(data=rtv) +# M.LoanRate_rtv.construct(data=rtv) M.LifetimeProcess_rtv.construct(data=rtv) -M.regionalIndices.construct(data=['A']) M.MyopicDiscountingYear.construct(data={None: 0}) -M.ModelProcessLife_rptv.construct(data=rptv) +# M.ModelProcessLife_rptv.construct(data=rptv) # make PARAMS -M.time_optimize.construct([2020, 2025]) -M.time_future.construct([2020, 2025, 2030]) # needs to go 1 period beyond optimize horizon -M.PeriodLength.construct() -M.tech_all.construct(data=['battery']) -M.regions.construct(data=['A']) M.CostInvest.construct(data={rtv: 1300}) # US_9R_8D M.CostFixed.construct(data={rptv: 20}) # US_9R_8D M.LoanLifetimeProcess.construct(data={rtv: 10}) @@ -59,8 +59,9 @@ M.LoanAnnualize.construct() M.LifetimeTech.construct(data={('A', 'battery'): 20}) M.LifetimeProcess.construct(data={rtv: 40}) -M.ModelProcessLife.construct(data={rptv: 20}) +# M.ModelProcessLife.construct(data={rptv: 20}) M.GlobalDiscountRate.construct(data={None: 0.05}) +M.isSurvivalCurveProcess[rtv] = False # make/fix VARS M.V_NewCapacity.construct() @@ -94,7 +95,9 @@ print('building storage level constraint...') # More SETS -M.TimeSeason.construct(data=['winter', 'summer']) +M.time_season.construct(['winter', 'summer']) +M.TimeSeason.construct(data={2020:{'winter', 'summer'}, 2025:{'winter', 'summer'}}) +M.DaysPerPeriod.construct(data={None: 365}) tod_slices = 2 M.time_of_day.construct(data=range(1, tod_slices + 1)) M.tech_storage.construct(data=['battery']) @@ -115,7 +118,7 @@ M.StorageDuration.construct(data={('A', 'battery'): 4}) seasonal_fractions = {'winter': 0.4, 'summer': 0.6} M.SegFrac.construct( - data={(s, d): seasonal_fractions[s] / tod_slices for d in M.time_of_day for s in M.TimeSeason} + data={(p, s, d): seasonal_fractions[s] / tod_slices for d in M.time_of_day for p in M.time_optimize for s in M.TimeSeason[p] } ) # QA the total print(f'quality check. Total of all SegFrac: {sum(M.SegFrac.values()):0.3f}') @@ -125,7 +128,8 @@ M.V_StorageLevel.construct() M.SegFracPerSeason.construct() -upper_limit = StorageEnergyUpperBound_Constraint(M, 'A', 2020, 'winter', '1', 'battery', 2020) +M.isSeasonalStorage['battery'] = False +upper_limit = StorageEnergyUpperBound_Constraint(M, 'A', 2020, 'winter', 1, 'battery', 2020) print('The storage level constraint for the single period in the "super day":\n', upper_limit) # cross-check the multiplier... From b87c484bd44cc64f3692c205c72aae28d23e142b Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 21 Oct 2025 12:42:21 -0400 Subject: [PATCH 257/587] polishing element_checker and adding more typing info --- temoa/model_checking/element_checker.py | 298 ++++++++++++++---------- 1 file changed, 177 insertions(+), 121 deletions(-) diff --git a/temoa/model_checking/element_checker.py b/temoa/model_checking/element_checker.py index d9a5865ee..ac327f938 100644 --- a/temoa/model_checking/element_checker.py +++ b/temoa/model_checking/element_checker.py @@ -1,30 +1,5 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 4/24/24 - -class to hold members of "validation sets" used by loader to validate elements as they are +Class to hold members of "validation sets" used by loader to validate elements as they are read in to the DataPortal or other structure. Motivation is to contain the values AND any extra validation information in one instance. @@ -33,102 +8,151 @@ class to hold members of "validation sets" used by loader to validate elements a import re from collections.abc import Iterable, Sequence from operator import itemgetter +from typing import Self, TypeAlias + +# For clarity in type hints +ValidationPrimitive: TypeAlias = str | int | float | None +ValidationElement: TypeAlias = tuple[ValidationPrimitive, ...] +InputElement: TypeAlias = ValidationPrimitive | ValidationElement class ViableSet: - # automatic approvals for regions. Stored here for reference - REGION_REGEXES = [ + """ + Manages a set of valid elements and rules for "exception-based" matches. + + This class is designed for filtering data where an element is considered + valid if it either: + 1. Exactly matches a pre-defined tuple of values. + 2. Matches a pre-defined tuple in all positions *except* for one, where + the value at that "exception position" matches a given regex pattern. + + Example: + - Core elements: {('a', 1), ('a', 2)} + - Exception: location 0, regexes {r'dog', r'cat'} + + This will match: + - ('a', 1), ('a', 2) (exact matches) + - ('dog', 1), ('cat', 1) (exception matches, since the non-exception part, (1,), is valid) + - ('dog', 2), ('cat', 2) (exception matches, since the non-exception part, (2,), is valid) + + This will NOT match: + - ('a', 4) (non-exception part (4,) is not in the valid set) + - ('cat', 3) (non-exception part (3,) is not in the valid set) + """ + + # Stored for reference; these are examples of common automatic approvals. + REGION_REGEXES: list[str] = [ r'\+', # any grouping with a plus sign r'^global\Z', # the exact word 'global' with no leader/trailer ] def __init__( self, - elements: Iterable, + elements: Iterable[InputElement], exception_loc: int | None = None, exception_vals: Iterable[str] | None = None, ): """ - Construct a match object. The direct matches and the location/item for exceptions - :param elements: The core elements to match against - :param exception_loc: The location to consider for the exception - :param exception_vals: Iterable of exception regexes to match against - - Example: core elements {('a', 1), ('a', 2)} - exceptions {0: {r'dog', r'cat'}} - should "match" for ('a', 1), ('a', 2), ('dog', 1), ('cat', 1) - fail for: ('a', 4), ('cat', 3), etc. + Constructs a ViableSet instance. + + Args: + elements: The core elements to match against. + exception_loc: The index within an element to apply exception regexes. + exception_vals: An iterable of regex patterns to match against. """ + self._elements: set[ValidationElement] = {self._tupleize(el) for el in elements} + self.dim: int = self._calculate_dim() + self._exception_loc: int | None = None + self._exceptions: frozenset[str] = frozenset() + self.non_excepted_items: set[ValidationElement] | None = set() - self._elements: set[tuple] = {self.tupleize(element) for element in elements} + if exception_loc is not None and exception_vals is not None: + self.set_val_exceptions(exception_loc, exception_vals) - if exception_vals and exception_loc is None: - raise ValueError('cannot have exception_vals without a location') - self._exception_loc = exception_loc - self._exceptions = exception_vals - self.non_excepted_items = set() + @staticmethod + def _tupleize(element: InputElement) -> ValidationElement: + """Ensures an element is a tuple.""" + return element if isinstance(element, tuple) else (element,) - self.calc_dim() + def _calculate_dim(self) -> int: + """Calculates the dimension of the elements.""" + if not self._elements: + return 0 + # Get an arbitrary element to determine the dimension + return len(next(iter(self._elements))) - if self._exceptions and self.dim > 0: - self._update() + def _update_internals(self) -> None: + """ + Updates internal lookup sets based on current elements and exceptions. + This pre-calculates values for efficient filtering. + """ + self.dim = self._calculate_dim() + if self._exception_loc is None or not self._exceptions: + self.non_excepted_items = set() + return - def calc_dim(self): - # calculate the dimension... - if self._elements: - an_element = self._elements.pop() - self._elements.add(an_element) - self.dim = len(an_element) - else: - self.dim = 0 - - def _update(self): - """construct the set of non-excepted items in tuple format""" - # we need to remove the item at the "excepted" location - locs = list(range(self.dim)) - locs.remove(self._exception_loc) - if len(locs) == 0: + # Locations of items *not* at the exception index + non_excepted_locs = [i for i in range(self.dim) if i != self._exception_loc] + + if not non_excepted_locs: + # This occurs if dim is 1 and exception_loc is 0. + # There are no other items to validate against. self.non_excepted_items = None - return - self.non_excepted_items = {itemgetter(*locs)(t) for t in self._elements} + else: + getter = itemgetter(*non_excepted_locs) + self.non_excepted_items = {self._tupleize(getter(t)) for t in self._elements} @property - def exception_loc(self): + def exception_loc(self) -> int | None: return self._exception_loc @property - def val_exceptions(self) -> Iterable[str]: + def val_exceptions(self) -> frozenset[str]: return self._exceptions - def set_val_exceptions(self, exception_loc: int, exception_vals: Iterable): - if exception_loc is None or exception_vals is None: - raise ValueError('cannot have exception_vals without a location') + def set_val_exceptions(self, exception_loc: int, exception_vals: Iterable[str]) -> Self: + """ + Sets or updates the validation exceptions. + + Args: + exception_loc: The index for the exception. + exception_vals: An iterable of regex patterns. + + Returns: + The instance (self) to allow for method chaining. + """ + if not (isinstance(exception_loc, int) and exception_loc >= 0): + raise ValueError('exception_loc must be a non-negative integer') + self._exception_loc = exception_loc - self._exceptions = exception_vals - self._update() + # Use a frozenset for immutability and performance + self._exceptions = frozenset(exception_vals) + self._update_internals() + return self @property - def member_tuples(self): - """the elements of the membership set AS TUPLES, including singleton tuples""" + def member_tuples(self) -> set[ValidationElement]: + """The elements of the membership set as tuples.""" return self._elements - @staticmethod - def tupleize(element): - return element if isinstance(element, tuple) else (element,) - @member_tuples.setter - def member_tuples(self, elements): - self._elements = {self.tupleize(element) for element in elements} - self.calc_dim() - self._update() + def member_tuples(self, elements: Iterable[InputElement]) -> None: + """Sets the core elements, ensuring they are stored as tuples.""" + self._elements = {self._tupleize(el) for el in elements} + self._update_internals() @property - def members(self): - """the members of the validation set""" + def members(self) -> set[ValidationElement] | set[ValidationPrimitive]: + """ + The members of the validation set. + Unwraps single-element tuples for convenience. + """ if self.dim > 1: + # This branch returns set[ValidationElement] return self.member_tuples - else: - return {t[0] for t in self.member_tuples} + + # This branch returns set[ValidationPrimitive] + return {t[0] for t in self.member_tuples} # dev note: The reason for this filtering construct is to allow passage of items that either @@ -141,48 +165,80 @@ def members(self): # actually legal combinations on-the-fly from data, which would be more complex # and mask the intent of the original data. def filter_elements( - values: Sequence[tuple], validation: ViableSet, value_locations: tuple = (0,) -) -> list: + values: Sequence[tuple[ValidationPrimitive, ...]], + validation: ViableSet, + value_locations: tuple[int, ...], +) -> list[tuple[ValidationPrimitive, ...]]: """ - Filter elements according to a set of criteria. - :param values: the values to filter - :param validation: the validation item to use for filtering - :param value_locations: the locations in the value items corresponding to the values in the validation - :return: a list of filtered elements - - Ex: if filtering by (region, tech, vintage) and the data is (region, _, _, tech, vintage, value) we need to identify - the location of r, t, v in the element under review by the tuple (0, 3, 4) + Filters a sequence of elements based on the rules in a ViableSet. + + Args: + values: The sequence of data tuples to filter. + validation: The ViableSet instance containing the validation rules. + value_locations: A tuple of indices that maps a data tuple from `values` + to the format expected by `validation`. + + Returns: + A list of the items from `values` that passed validation. + + Example: + - A data item is `('USA', 'other', 'cars', 2020, 1.5)` + - `validation` expects `(region, tech, vintage)` + - `value_locations` would be `(0, 2, 3)` to extract ('USA', 'cars', 2020) """ if not isinstance(validation, ViableSet): - raise ValueError("'validation' must be an instance of ViableSet") - if 0 < validation.dim != len(value_locations): - # if validation.dim == 0, it is empty, but might still be used for exempted items - raise ValueError('the value locations must have same dimensionality as the validation set') + raise TypeError("'validation' must be an instance of ViableSet") + + if validation.dim > 0 and validation.dim != len(value_locations): + raise ValueError( + 'The number of value_locations must match the dimensionality of the validation set.' + ) + + exception_regexes = [re.compile(p) for p in validation.val_exceptions] - # determine the location of the non-exempted items for comparison by removing the exempted location - non_exempt_item_locs = None - if validation.val_exceptions: - non_exempt_item_locs = list(value_locations) - non_exempt_item_locs.remove(validation.exception_loc) + # Pre-build itemgetters for performance + full_element_getter = itemgetter(*value_locations) - res = [] + # --- Simplified path for no exceptions --- + if not exception_regexes: + return [ + item + for item in values + if validation._tupleize(full_element_getter(item)) in validation.member_tuples + ] + assert validation.exception_loc is not None # for mypy type checking + + # --- Main logic for filtering with exceptions --- + non_exempt_item_locs: list[int] = [ + loc for i, loc in enumerate(value_locations) if i != validation.exception_loc + ] + non_exempt_getter = itemgetter(*non_exempt_item_locs) if non_exempt_item_locs else None + + filtered_list = [] for item in values: - # check the "base case" first: it's in the fundamental elements - element = itemgetter(*value_locations)(item) - if not isinstance(element, tuple): - element = (element,) - if element in validation.member_tuples: - res.append(item) - elif validation.val_exceptions: # check each of the exceptions - if ( - validation.non_excepted_items - and itemgetter(*non_exempt_item_locs)(item) not in validation.non_excepted_items - ): + element_to_check = validation._tupleize(full_element_getter(item)) + + # 1. Check for a direct match + if element_to_check in validation.member_tuples: + filtered_list.append(item) + continue + + # 2. Check for an exception-based match + if validation.non_excepted_items is None: # dim=1 case + pass + elif non_exempt_getter: + non_exempt_part = validation._tupleize(non_exempt_getter(item)) + if non_exempt_part not in validation.non_excepted_items: continue - for val_exception in validation.val_exceptions: - if re.search(val_exception, str(item[validation.exception_loc])): - res.append(item) - break - return res + # Check if the value at the exception location matches any regex + exception_loc_in_item = value_locations[validation.exception_loc] + value_at_exception_loc = str(item[exception_loc_in_item]) + + for pattern in exception_regexes: + if pattern.search(value_at_exception_loc): + filtered_list.append(item) + break + + return filtered_list From 1a4f9accb52f79bb7d0f6718502bba645e93c47e Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 21 Oct 2025 17:27:19 -0400 Subject: [PATCH 258/587] making the network model data test less brittle by using a dispatcher mock --- tests/test_network_model_data.py | 317 ++++++++++++++----------------- 1 file changed, 138 insertions(+), 179 deletions(-) diff --git a/tests/test_network_model_data.py b/tests/test_network_model_data.py index 61dfa1811..dffa502a2 100644 --- a/tests/test_network_model_data.py +++ b/tests/test_network_model_data.py @@ -1,31 +1,3 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 3/11/24 - -""" - from itertools import chain from unittest.mock import MagicMock @@ -34,145 +6,111 @@ from temoa.model_checking import network_model_data from temoa.model_checking.commodity_network import CommodityNetwork -# a couple of test cases with diagrams in the flow... -params = [ - # let's model this basic faulty network as a trial: - # - t4(2) -> p3 - # / - # s1 -> t1 -> p1 -> t2 -> d1 - # / - # p2 -> t3 - - # - # p2 -> t5 -> d2 - # the above should produce: - # 2 valid techs, t1, t2 - # 2 supply-side orphans (both instances of t4 of differing vintage) - # 1 demand-side orphan: t3 +# ============================================================================== +# Test Scenarios +# ============================================================================== +# Each scenario defines the mock database data and the expected outcomes. +# The `db_data` dictionary keys are specific, unique fragments of SQL queries. +# This makes the mock robust against changes in the order of execution, +# ensuring backwards compatibility with older versions of the code. +# ============================================================================== +test_scenarios = [ + # Scenario 1: A basic network with several orphan technologies. { 'name': 'basic', - 'data': [ - [], # retirement techs - [], # survival curve techs - [ - (2020,), - (2025,), - ], # periods - [(t,) for t in ['s1', 'p1', 'p2', 'p3', 'd1', 'd2']], # all commodities - [], # waste commodities - [ - (t,) - for t in [ - 's1', - ] - ], # sources - [('R1', 2020, 'd1'), ('R1', 2020, 'd2')], # demands - [ + 'db_data': { + 'Technology WHERE retire==1': [], + 'FROM SurvivalCurve': [], + 'FROM TimePeriod': [(2020,), (2025,)], + # Unique keys for each Commodity query + "Commodity WHERE flag LIKE '%p%'": [ + ('s1',), + ('p1',), + ('p2',), + ('p3',), + ('d1',), + ('d2',), + ], + "Commodity WHERE flag LIKE '%w%'": [], + "Commodity WHERE flag = 's'": [('s1',)], + 'FROM main.Demand': [('R1', 2020, 'd1'), ('R1', 2020, 'd2')], + # Unique keys for Efficiency and optional tables + 'FROM main.Efficiency': [ ('R1', 's1', 't4', 2000, 'p3', 100), ('R1', 's1', 't4', 1990, 'p3', 100), ('R1', 's1', 't1', 2000, 'p1', 100), ('R1', 'p1', 't2', 2000, 'd1', 100), ('R1', 'p2', 't3', 2000, 'd1', 100), ('R1', 'p2', 't5', 2000, 'd2', 100), - ], # techs - [ - (2020,), - (2025,), - ], # periods - [], # no linked techs - [], # no negative cost techs - ], - 'res': { - 'demands': 2, - 'techs': 6, + ], + 'FROM EndOfLifeOutput': [], + 'FROM ConstructionInput': [], + 'FROM main.LinkedTech': [], + 'FROM CostVariable': [], + }, + 'expected': { + 'demands_count': 2, + 'techs_count': 6, 'valid_techs': 2, 'demand_orphans': 2, 'other_orphans': 2, 'unsupported_demands': {'d2'}, }, }, - # p1 -> driven -> d2 - # | - # - t4 -> p3 - # / - # s1 -> t1 -> d1 - # - # bad link tech set. t4 should be other orphan and the linked "driven" should be a demand side orphan + # Scenario 2: A network with a misconfigured linked technology. { 'name': 'bad linked tech', - 'data': [ - [], # retirement techs - [], # survival curve techs - [ - (2020,), - (2025,), - ], # periods - [(t,) for t in ['s1', 'p3', 'd1', 'd2']], # all commodities - [], # waste commodities - [ - (t,) - for t in [ - 's1', - ] - ], # sources - [('R1', 2020, 'd1'), ('R1', 2020, 'd2')], # demands - [ + 'db_data': { + 'Technology WHERE retire==1': [], + 'FROM SurvivalCurve': [], + 'FROM TimePeriod': [(2020,), (2025,)], + "Commodity WHERE flag LIKE '%p%'": [('s1',), ('p3',), ('d1',), ('d2',)], + "Commodity WHERE flag LIKE '%w%'": [], + "Commodity WHERE flag = 's'": [('s1',)], + 'FROM main.Demand': [('R1', 2020, 'd1'), ('R1', 2020, 'd2')], + 'FROM main.Efficiency': [ ('R1', 's1', 't4', 2000, 'p3', 100), ('R1', 'p1', 'driven', 1990, 'd2', 100), ('R1', 's1', 't1', 2000, 'd1', 100), - ], # techs - [ - (2020,), - (2025,), - ], # periods - [('R1', 't4', 'nox', 'driven')], # t4 drives 'driven' with 'nox' emission - [], # no negative cost techs - ], - 'res': { - 'demands': 2, - 'techs': 3, + ], + 'FROM EndOfLifeOutput': [], + 'FROM ConstructionInput': [], + 'FROM main.LinkedTech': [('R1', 't4', 'nox', 'driven')], + 'FROM CostVariable': [], + }, + 'expected': { + 'demands_count': 2, + 'techs_count': 3, 'valid_techs': 1, 'demand_orphans': 0, - 'other_orphans': 2, # driven and t4 will both be culled as "other orphans" because t4 is a supply-orphan + 'other_orphans': 2, 'unsupported_demands': {'d2'}, }, }, + # Scenario 3: A network with a correctly configured linked technology. { - # iteration with a "good linked tech" - # system should give a synthetic link from t4's input to driven - # s2 -> driven -> d2 - # | - # - t4 -> d2 - # / - # s1 -> t1 -> d1 - # - # 'name': 'good linked tech', - 'data': [ - [], # retirement techs - [], # survival curve techs - [ - (2020,), - (2025,), - ], # periods - [(t,) for t in ['s1', 'd1', 'd2', 's2']], # all commodities - [], # waste commodities - [(t,) for t in ['s1', 's2']], # sources - [('R1', 2020, 'd1'), ('R1', 2020, 'd2')], # demands - [ + 'db_data': { + 'Technology WHERE retire==1': [], + 'FROM SurvivalCurve': [], + 'FROM TimePeriod': [(2020,), (2025,)], + "Commodity WHERE flag LIKE '%p%'": [('s1',), ('d1',), ('d2',), ('s2',)], + "Commodity WHERE flag LIKE '%w%'": [], + "Commodity WHERE flag = 's'": [('s1',), ('s2',)], + 'FROM main.Demand': [('R1', 2020, 'd1'), ('R1', 2020, 'd2')], + 'FROM main.Efficiency': [ ('R1', 's1', 't4', 2000, 'd2', 100), ('R1', 's2', 'driven', 1990, 'd2', 100), ('R1', 's1', 't1', 2000, 'd1', 100), - ], # techs - [ - (2020,), - (2025,), - ], # periods - [('R1', 't4', 'nox', 'driven')], # t4 drives 'driven' with 'nox' emission - [], # no negative cost techs - ], - 'res': { - 'demands': 2, - 'techs': 3, + ], + 'FROM EndOfLifeOutput': [], + 'FROM ConstructionInput': [], + 'FROM main.LinkedTech': [('R1', 't4', 'nox', 'driven')], + 'FROM CostVariable': [], + }, + 'expected': { + 'demands_count': 2, + 'techs_count': 3, 'valid_techs': 3, 'demand_orphans': 0, 'other_orphans': 0, @@ -182,63 +120,84 @@ ] -# we need a small fixture to simulate the database here +# ============================================================================== +# Fixtures +# ============================================================================== @pytest.fixture() def mock_db_connection(request): - mock_con = MagicMock() - mock_cursor = MagicMock() + """ + A robust mock of a database connection. + + This fixture uses a "dispatcher" function as a side_effect. The dispatcher + inspects the SQL query and returns the corresponding data from the + test scenario's `db_data` dictionary. This makes the test independent + of the order of SQL calls in the code being tested. + """ + db_data = request.param['db_data'] + mock_con = MagicMock(name='mock_connection') + mock_cursor = MagicMock(name='mock_cursor') mock_con.cursor.return_value = mock_cursor - mock_execute = MagicMock() - mock_cursor.execute.return_value = mock_execute - mock_execute.fetchall.side_effect = request.param['data'] - return mock_con, request.param['res'] + def dispatcher(query, *args): + for key, data in db_data.items(): + if key in query: + execute_mock = MagicMock(name=f'execute_mock_for_{key}') + execute_mock.fetchall.return_value = data + return execute_mock + raise ValueError(f'Mock database received unexpected query: {query}') -@pytest.mark.parametrize( - 'mock_db_connection', params, indirect=True, ids=[d['name'] for d in params] -) -def test_build_from_db(mock_db_connection): - """test a couple values in the load""" - conn, expected = mock_db_connection - network_data = network_model_data._build_from_db(conn) - assert len(tuple(chain(*network_data.demand_commodities.values()))) == expected['demands'], ( - 'demand count failed' - ) - assert len(network_data.available_techs['R1', 2020]) == expected['techs'], ( - '6 techs are available' - ) + mock_cursor.execute.side_effect = dispatcher + return mock_con, request.param['expected'] +# ============================================================================== +# Tests +# ============================================================================== @pytest.mark.parametrize( - 'mock_db_connection', params, indirect=True, ids=[d['name'] for d in params] + 'mock_db_connection', test_scenarios, indirect=True, ids=[d['name'] for d in test_scenarios] ) -def test_source_trace(mock_db_connection): - """analyze the network and check results""" +def test_network_build_and_analysis(mock_db_connection): + """Tests both data model construction and network analysis in one go.""" conn, expected = mock_db_connection + + # --- 1. Build the data object --- network_data = network_model_data._build_from_db(conn) + + # --- 2. Test initial data loading --- + assert len(tuple(chain(*network_data.demand_commodities.values()))) == expected['demands_count'] + assert len(network_data.available_techs[('R1', 2020)]) == expected['techs_count'] + + # --- 3. Perform network analysis --- cn = CommodityNetwork(region='R1', period=2020, model_data=network_data) cn.analyze_network() - # test the outputs - assert len(cn.get_valid_tech()) == expected['valid_techs'], 'should have this many valid techs' - assert len(cn.get_demand_side_orphans()) == expected['demand_orphans'], 'demand orphans' - assert len(cn.get_other_orphans()) == expected['other_orphans'], 'other orphans' - assert cn.unsupported_demands() == expected['unsupported_demands'], 'unsupported demands' + # --- 4. Test analysis results --- + assert len(cn.get_valid_tech()) == expected['valid_techs'], 'Incorrect number of valid techs' + assert len(cn.get_demand_side_orphans()) == expected['demand_orphans'], ( + 'Incorrect number of demand orphans' + ) + assert len(cn.get_other_orphans()) == expected['other_orphans'], ( + 'Incorrect number of other orphans' + ) + assert cn.unsupported_demands() == expected['unsupported_demands'], ( + 'Incorrect set of unsupported demands' + ) -@pytest.mark.parametrize( - 'mock_db_connection', - [ - params[0], - ], - indirect=True, -) +@pytest.mark.parametrize('mock_db_connection', [test_scenarios[0]], indirect=True) def test_clone(mock_db_connection): - """quick test to ensure cloning is working OK""" - conn, expected = mock_db_connection + """Verifies that the clone() method creates a deep enough copy.""" + conn, _ = mock_db_connection network_data = network_model_data._build_from_db(conn) + clone = network_data.clone() - assert clone is not network_data, 'should be different objects' - assert network_data.available_techs == clone.available_techs, 'should be a direct copy' - clone.available_techs.pop(('R1', 2020)) # remove a known region-period - assert network_data.available_techs != clone.available_techs, 'should be different now' + + assert clone is not network_data, 'Clone should be a new object' + assert network_data.available_techs == clone.available_techs, ( + 'Data should be identical after cloning' + ) + + clone.available_techs.pop(('R1', 2020)) + assert network_data.available_techs != clone.available_techs, ( + 'Modifying clone should not affect original' + ) From 64d46597c10427892fa85ad870f61b439c11949f Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 21 Oct 2025 18:52:53 -0400 Subject: [PATCH 259/587] polishing network_model_data and adding more typing info --- temoa/model_checking/network_model_data.py | 589 +++++++++++---------- 1 file changed, 307 insertions(+), 282 deletions(-) diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index 3af5b9064..a83e35ed5 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -1,348 +1,373 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 3/10/24 - The purpose of this module is to build an Object to hold all of the network data for the entire model in a usable format for the commodity_network_manager to use in building the individual network. - """ +from __future__ import annotations + +import copy import logging import sqlite3 -from collections import defaultdict, namedtuple +from collections import defaultdict +from collections.abc import Callable +from dataclasses import dataclass, field from itertools import chain -from typing import Any, Self +from typing import NamedTuple, Self, TypeAlias, TypedDict import deprecated -from pyomo.core import ConcreteModel +from pyomo.core.base import ConcreteModel +from pyomo.core.base.block import Block from temoa.core.model import TemoaModel from temoa.extensions.myopic.myopic_index import MyopicIndex +from temoa.types import Commodity, Period, Region, Technology, Vintage +from temoa.types.core_types import ParameterValue -Tech = namedtuple('Tech', ['region', 'ic', 'name', 'vintage', 'oc']) -LinkedTech = namedtuple('LinkedTech', ['region', 'driver', 'emission', 'driven']) -logger = logging.getLogger(__name__) +# --- Type Definitions --- +class Tech(NamedTuple): + region: Region + ic: Commodity + name: Technology + vintage: Vintage + oc: Commodity -class NetworkModelData: - """A simple encapsulation of data needed for the Commodity Network""" +class LinkedTech(NamedTuple): + region: Region + driver: Technology + emission: Commodity + driven: Technology - def __init__(self, **kwargs): - self.demand_commodities: dict[tuple[str, int | str], set[str]] = kwargs.get( - 'demand_commodities' - ) - self.waste_commodities: set[str] = kwargs.get('waste_commodities') - self.capacity_commodities: set[str] = kwargs.get('capacity_commodities') - self.exchange_commodities: set[str] = kwargs.get('exchange_commodities') - self.source_commodities: dict[tuple[str, int | str], set[str]] = kwargs.get( - 'source_commodities' - ) - self.physical_commodities: set[str] = kwargs.get('all_commodities') - # dict of (region, period): {Tech} - self._available_techs: dict[tuple[str, int | str], set[Tech]] = kwargs.get( - 'available_techs' - ) - self.available_linked_techs: set[LinkedTech] = kwargs.get('available_linked_techs', set()) - # a catch-all for indicators for techs...growth potential - # dev note: this is indexed by tech name, and is blind to vintage. The intended use is in the - # network graph, which is also blind to vintage. So it is interpreted as "at least one" - # tech (and likely all) have/has this characteristic if multi-vintage - self.tech_data: dict[str, dict[str, Any]] = defaultdict(dict) - def clone(self) -> Self: - """create a copy of the current""" - return NetworkModelData( - demand_commodities=self.demand_commodities.copy(), - waste_commodities=self.waste_commodities.copy(), - source_commodities=self.source_commodities.copy(), - capacity_commodities=self.capacity_commodities.copy(), - exchange_commodities=self.exchange_commodities.copy(), - all_commodities=self.physical_commodities.copy(), - available_techs=self.available_techs.copy(), - available_linked_techs=self.available_linked_techs.copy(), - ) +TechAttributeValue: TypeAlias = ParameterValue +DbConnection: TypeAlias = sqlite3.Connection +ModelBlock: TypeAlias = TemoaModel | ConcreteModel | Block + + +class BasicData(TypedDict): + """Defines the shape of the data returned by _fetch_basic_data.""" + + tech_retire: set[Technology] + tech_survival_curve: set[tuple[Region, Technology, Vintage]] + periods: list[Period] + period_length: dict[Period, int] + physical_commodities: set[Commodity] + waste_commodities_all: set[Commodity] + source_commodities_all: set[Commodity] + demand_commodities: defaultdict[tuple[Region, Period], set[Commodity]] + + +class LookupData(TypedDict): + """Defines the shape of the data returned by _fetch_lookup_data.""" - @property - def available_techs(self) -> dict[tuple[str, int | str], set[Tech]]: - return self._available_techs + eol: defaultdict[tuple[Region, Technology, Vintage], list[Commodity]] + construction: list[tuple[Region, Commodity, Technology, Vintage]] + linked: set[tuple[Region, Technology, Commodity, Technology]] + neg_cost_techs: set[Technology] - @available_techs.setter - def available_techs(self, available_techs: dict[tuple[str, int], set[Tech]]) -> None: - # check for region violations - for r, p in available_techs: - for tech in available_techs[r, p]: + +logger = logging.getLogger(__name__) + + +# --- Data Structure --- +@dataclass +class NetworkModelData: + """A simple encapsulation of data needed for the Commodity Network using a dataclass.""" + + demand_commodities: defaultdict[tuple[Region, Period], set[Commodity]] = field( + default_factory=lambda: defaultdict(set) + ) + waste_commodities: defaultdict[tuple[Region, Period], set[Commodity]] = field( + default_factory=lambda: defaultdict(set) + ) + capacity_commodities: set[Commodity] = field(default_factory=set) + exchange_commodities: set[Commodity] = field(default_factory=set) + source_commodities: defaultdict[tuple[Region, Period], set[Commodity]] = field( + default_factory=lambda: defaultdict(set) + ) + physical_commodities: set[Commodity] = field(default_factory=set) + available_techs: defaultdict[tuple[Region, Period], set[Tech]] = field( + default_factory=lambda: defaultdict(set) + ) + available_linked_techs: set[LinkedTech] = field(default_factory=set) + tech_data: defaultdict[Technology, dict[str, TechAttributeValue]] = field( + default_factory=lambda: defaultdict(dict) + ) + + def __post_init__(self) -> None: + """Validate data consistency after initialization.""" + for (r, _), techs in self.available_techs.items(): + for tech in techs: if tech.region != r: raise ValueError( f'Improperly constructed set of techs for region {r}, tech: {tech}' ) - self._available_techs = available_techs - - def update_tech_data(self, tech: str, element: str, value: Any) -> None: - """ - Update a data element for a tech - :param tech: the tech - :param element: the string name of the data element - :param value: the new value - :return: - """ + + def clone(self) -> Self: + """Create a deep copy of the current object.""" + return copy.deepcopy(self) + + def update_tech_data(self, tech: Technology, element: str, value: TechAttributeValue) -> None: + """Update a data element for a tech.""" self.tech_data[tech][element] = value - def get_driven_techs(self, region, period) -> set[Tech]: - """identifies all linked techs by name from the linked tech names""" - driven_tech_names = {linked_tech.driven for linked_tech in self.available_linked_techs} - driven_techs = { - tech for tech in self.available_techs[region, period] if tech.name in driven_tech_names + def get_driven_techs(self, region: Region, period: Period) -> set[Tech]: + """Identifies all linked techs by name from the linked tech names.""" + driven_tech_names = {lt.driven for lt in self.available_linked_techs} + return { + tech + for tech in self.available_techs.get((region, period), set()) + if tech.name in driven_tech_names } - return driven_techs - def __str__(self): + def __str__(self) -> str: return ( f'all commodities: {len(self.physical_commodities)}, demand commodities: {len(self.demand_commodities)}, ' - f'source commodities: {len(self.source_commodities)},' + f'source commodities: {len(self.source_commodities)}, ' f'available techs: {len(tuple(chain(*self.available_techs.values())))}, ' f'linked techs: {len(self.available_linked_techs)}' ) -def build(data, *args, **kwargs) -> NetworkModelData: +# --- Builder Factory --- +def build( + data: ModelBlock | DbConnection, *args: ParameterValue, **kwargs: ParameterValue +) -> NetworkModelData: + """Factory function to dispatch to the correct builder based on data type.""" builder = _get_builder(data) return builder(data, *args, **kwargs) -def _get_builder(data): - if isinstance(data, TemoaModel | ConcreteModel): - # dev note: The built instance will be a ConcreteModel - builder = _build_from_model - return builder - elif isinstance(data, sqlite3.Connection): - builder = _build_from_db - return builder - else: - raise NotImplementedError('cannot build from that type of data') +def _get_builder(data: ModelBlock | DbConnection) -> Callable[..., NetworkModelData]: # type: ignore[explicit-any] + """Selects the appropriate builder function based on the input data type.""" + if isinstance(data, (TemoaModel, ConcreteModel)): + return _build_from_model + if isinstance(data, sqlite3.Connection): + return _build_from_db + raise NotImplementedError(f'Cannot build NetworkModelData from type: {type(data)}') +# --- Builder Implementations --- @deprecated.deprecated('no longer supported... build from db connection instead') -def _build_from_model(M: TemoaModel, myopic_index=None) -> NetworkModelData: - """Build a NetworkModelData from a TemoaModel""" +def _build_from_model(M: TemoaModel, myopic_index: MyopicIndex | None = None) -> NetworkModelData: + """Build a NetworkModelData from a TemoaModel.""" if myopic_index is not None: - raise NotImplementedError('cannot build network data from model using a MyopicIndex') - res = NetworkModelData() - res.physical_commodities = set(M.commodity_all) - source_com = defaultdict(set) + raise NotImplementedError('Cannot build network data from model using a MyopicIndex') + dem_com = defaultdict(set) for r, p, d in M.Demand.sparse_iterkeys(): dem_com[r, p].add(d) - res.demand_commodities = dem_com - techs = defaultdict(set) - # scan non-annual techs... - for r, p, s, d, ic, tech, v, oc in M.activeFlow_rpsditvo: - techs[r, p].add(Tech(r, ic, tech, v, oc)) - # scan annual techs... - for r, p, ic, tech, v, oc in M.activeFlow_rpitvo: - techs[r, p].add(Tech(r, ic, tech, v, oc)) - res.available_techs = techs - linked_techs = set() - for r, driver, emission, driven in M.LinkedTechs.sparse_iterkeys(): - linked_techs.add(LinkedTech(r, driver, emission, driven)) - res.available_linked_techs = linked_techs - logger.debug('built network data: %s', res.__str__()) + + techs: defaultdict[tuple[Region, Period], set[Tech]] = defaultdict(set) + if M.activeFlow_rpsditvo is not None: + for r, p, _s, _d, ic, tech, v, oc in M.activeFlow_rpsditvo: + techs[r, p].add(Tech(r, ic, tech, v, oc)) + if M.activeFlow_rpitvo is not None: + for r, p, ic, tech, v, oc in M.activeFlow_rpitvo: + techs[r, p].add(Tech(r, ic, tech, v, oc)) + + linked_techs = { + LinkedTech(r, driver, emission, driven) + for r, driver, emission, driven in M.LinkedTechs.sparse_iterkeys() + } + + res = NetworkModelData( + physical_commodities=set(M.commodity_all), + demand_commodities=dem_com, + available_techs=techs, + available_linked_techs=linked_techs, + ) + logger.debug('built network data: %s', res) return res -def _build_from_db( - con: sqlite3.Connection, myopic_index: MyopicIndex | None = None -) -> NetworkModelData: - """Build NetworkModelData object from a sqlite database.""" - # dev note: sadly, this will duplicate some code, I think. Perhaps a later refactoring can - # re-use some of the hybrid loader code in a clear way. Not too much overlap, though - res = NetworkModelData() - cur = con.cursor() - raw = cur.execute('SELECT tech FROM Technology WHERE retire==1').fetchall() - tech_retire = {t[0] for t in raw} - tech_survival_curve = set() +# --- Database Builder Refactored --- + + +def _fetch_basic_data(cur: sqlite3.Cursor) -> BasicData: + """Fetches simple, required tables and parameters from the DB.""" + tech_retire = { + t[0] for t in cur.execute('SELECT tech FROM Technology WHERE retire==1').fetchall() + } try: - raw = cur.execute('SELECT DISTINCT region, tech, vintage FROM SurvivalCurve').fetchall() - tech_survival_curve = set(raw) - except: - # table didn't exist - pass - raw = cur.execute('SELECT period FROM TimePeriod').fetchall() - periods = [p[0] for p in sorted(raw)] - period_length = {periods[i]: periods[i + 1] - periods[i] for i in range(len(periods) - 1)} - periods = periods[:-1] - raw = cur.execute( - "SELECT name FROM main.Commodity WHERE flag LIKE '%p%' OR flag = 's' OR flag LIKE '%a%'" - ).fetchall() - res.physical_commodities = {c[0] for c in raw} - res.capacity_commodities = set() - res.exchange_commodities = set() - raw = cur.execute("SELECT Commodity.name FROM Commodity WHERE flag LIKE '%w%'").fetchall() - waste_comms = {c[0] for c in raw} - waste_dict = defaultdict(set) - raw = cur.execute("SELECT Commodity.name FROM Commodity WHERE flag = 's'").fetchall() - source_comms = {c[0] for c in raw} - source_dict = defaultdict(set) - # use Demand to get the region, period specific demand comms - raw = cur.execute('SELECT region, period, commodity FROM main.Demand').fetchall() - demand_dict = defaultdict(set) - for r, p, d in raw: - demand_dict[r, p].add(d) - # need lifetime to screen techs... :/ - default_lifetime = TemoaModel.default_lifetime_tech - if not myopic_index: - query = ( - ' SELECT main.Efficiency.region, input_comm, Efficiency.tech, Efficiency.vintage, output_comm, ' - f' coalesce(main.LifetimeProcess.lifetime, main.LifetimeTech.lifetime, {default_lifetime}) AS lifetime ' - ' FROM main.Efficiency ' - ' LEFT JOIN main.LifetimeProcess ' - ' ON main.Efficiency.tech = LifetimeProcess.tech ' - ' AND main.Efficiency.vintage = LifetimeProcess.vintage ' - ' AND main.Efficiency.region = LifetimeProcess.region ' - ' LEFT JOIN main.LifetimeTech ' - ' ON main.Efficiency.tech = main.LifetimeTech.tech ' - ' AND main.Efficiency.region = main.LifeTimeTech.region ' - ' JOIN TimePeriod ' - ' ON Efficiency.vintage = TimePeriod.period ' + tech_survival_curve = set( + cur.execute('SELECT DISTINCT region, tech, vintage FROM SurvivalCurve').fetchall() ) - else: # we need to pull from the MyopicEfficiency Table - query = ( - ' SELECT main.MyopicEfficiency.region, input_comm, MyopicEfficiency.tech, MyopicEfficiency.vintage, output_comm, ' - f' coalesce(main.LifetimeProcess.lifetime, main.LifetimeTech.lifetime, {default_lifetime}) AS lifetime ' - ' FROM main.MyopicEfficiency ' - ' LEFT JOIN main.LifetimeProcess ' - ' ON main.MyopicEfficiency.tech = LifetimeProcess.tech ' - ' AND main.MyopicEfficiency.vintage = LifetimeProcess.vintage ' - ' AND main.MyopicEfficiency.region = LifetimeProcess.region ' - ' LEFT JOIN main.LifetimeTech ' - ' ON main.MyopicEfficiency.tech = main.LifetimeTech.tech ' - ' AND main.MyopicEfficiency.region = main.LifeTimeTech.region ' - ' JOIN TimePeriod ' - ' ON MyopicEfficiency.vintage = TimePeriod.period ' - # f' WHERE main.MyopicEfficiency.vintage <= {myopic_index.last_demand_year}' + except sqlite3.OperationalError: + tech_survival_curve = set() + + periods_full = sorted(p[0] for p in cur.execute('SELECT period FROM TimePeriod').fetchall()) + periods = periods_full[:-1] + period_length = { + periods_full[i]: periods_full[i + 1] - periods_full[i] for i in range(len(periods_full) - 1) + } + + physical_commodities = { + c[0] + for c in cur.execute( + "SELECT name FROM main.Commodity WHERE flag LIKE '%p%' OR flag = 's' OR flag LIKE '%a%'" + ).fetchall() + } + waste_commodities_all = { + c[0] for c in cur.execute("SELECT name FROM Commodity WHERE flag LIKE '%w%'").fetchall() + } + source_commodities_all = { + c[0] for c in cur.execute("SELECT name FROM Commodity WHERE flag = 's'").fetchall() + } + + demand_commodities: defaultdict[tuple[str, Period], set[str]] = defaultdict(set) + for r, p, d in cur.execute('SELECT region, period, commodity FROM main.Demand').fetchall(): + demand_commodities[r, p].add(d) + + return BasicData( + tech_retire=tech_retire, + tech_survival_curve=tech_survival_curve, + periods=periods, + period_length=period_length, + physical_commodities=physical_commodities, + waste_commodities_all=waste_commodities_all, + source_commodities_all=source_commodities_all, + demand_commodities=demand_commodities, + ) + + +def _fetch_all_tech_definitions( + cur: sqlite3.Cursor, myopic_index: MyopicIndex | None +) -> list[tuple[Region, Commodity, Technology, Vintage, Commodity, int]]: + """Fetches the main block of technology efficiency and lifetime data.""" + default_lifetime = TemoaModel.default_lifetime_tech + table = 'MyopicEfficiency' if myopic_index else 'Efficiency' + query = f""" + SELECT + eff.region, eff.input_comm, eff.tech, eff.vintage, eff.output_comm, + COALESCE(lp.lifetime, lt.lifetime, ?) AS lifetime + FROM main.{table} AS eff + LEFT JOIN main.LifetimeProcess AS lp ON eff.tech = lp.tech AND eff.vintage = lp.vintage AND eff.region = lp.region + LEFT JOIN main.LifetimeTech AS lt ON eff.tech = lt.tech AND eff.region = lt.region + JOIN main.TimePeriod AS tp ON eff.vintage = tp.period + """ + cursor = cur.execute(query, (default_lifetime,)) + return cursor.fetchall() + + +def _fetch_lookup_data(cur: sqlite3.Cursor) -> LookupData: + """Fetches data from all optional tables to avoid N+1 queries.""" + lookups = LookupData(eol=defaultdict(list), construction=[], linked=set(), neg_cost_techs=set()) + + try: + for r, tech, v, oc in cur.execute( + 'SELECT region, tech, vintage, output_comm FROM EndOfLifeOutput' + ).fetchall(): + lookups['eol'][(r, tech, v)].append(oc) + except sqlite3.OperationalError: + logger.warning('Table EndOfLifeOutput not found, skipping.') + + try: + lookups['construction'] = cur.execute( + 'SELECT region, input_comm, tech, vintage FROM ConstructionInput' + ).fetchall() + except sqlite3.OperationalError: + logger.warning('Table ConstructionInput not found, skipping.') + + try: + lookups['linked'] = set( + cur.execute( + 'SELECT primary_region, primary_tech, emis_comm, driven_tech FROM main.LinkedTech' + ).fetchall() ) - raw = cur.execute(query).fetchall() - # need to exclude the final year which is a non-demand year and should have no tech data - # This ensures that the periods in this will match the periods in the hybrid loader. + except sqlite3.OperationalError: + logger.warning('Table LinkedTech not found, skipping.') + + try: + lookups['neg_cost_techs'] = { + tech + for (tech,) in cur.execute( + 'SELECT DISTINCT tech FROM CostVariable WHERE cost < 0' + ).fetchall() + } + except sqlite3.OperationalError: + logger.warning('Table CostVariable not found, skipping.') - # filter further if myopic + return lookups + + +def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) -> NetworkModelData: + """Build NetworkModelData object from a sqlite database.""" + cur = con.cursor() + res = NetworkModelData() + + # --- 1. Fetch all data from DB --- + basic_data = _fetch_basic_data(cur) + raw_techs = _fetch_all_tech_definitions(cur, myopic_index) + lookup_data = _fetch_lookup_data(cur) + + res.physical_commodities = basic_data['physical_commodities'] + res.demand_commodities = basic_data['demand_commodities'] + + periods: list[Period] | set[Period] = basic_data['periods'] if myopic_index: periods = { p for p in periods if myopic_index.base_year <= p <= myopic_index.last_demand_year } - techs = defaultdict(set) - living_techs = set() # for screening the linked techs below - # filter out the dead ones... - for element in raw: - (r, ic, tech, v, oc, lifetime) = element - for p in periods: - if v <= p < v + lifetime: - if '-' in r: - r1, r2 = r.split('-') - source = f'{ic} ({r1})' - destination = f'{oc} ({r2})' - techs[r2, p].add(Tech(r2, source, tech, v, oc)) - techs[r1, p].add(Tech(r1, ic, tech, v, destination)) - techs[r, p].add(Tech(r, ic, tech, v, oc)) - source_dict[r2, p].add(source) - demand_dict[r1, p].add(destination) - res.physical_commodities.add(source) - res.exchange_commodities.add(source) - res.physical_commodities.add(destination) - res.exchange_commodities.add(destination) - else: - techs[r, p].add(Tech(r, ic, tech, v, oc)) - living_techs.add(tech) - if ic in source_comms: - source_dict[r, p].add(ic) - if oc in waste_comms: - waste_dict[r, p].add(oc) - - # End of life output - if any( - ( - p <= v + lifetime < p + period_length[p], # natural eol this period - tech in tech_retire - and v < p <= v + lifetime - period_length[p], # allowed early retirement - tech in tech_survival_curve and v <= p <= v + lifetime, - ) - ): - try: - raw_eol = cur.execute( - 'SELECT region, tech, vintage, output_comm FROM EndOfLifeOutput ' - f' WHERE region == "{r}" AND tech == "{tech}" AND vintage == {v}' - ).fetchall() - - for _r, _tech, _v, _oc in raw_eol: - techs[_r, p].add(Tech(_r, _tech, 'EndOfLife', _v, _oc)) - source_dict[_r, p].add(_tech) - res.capacity_commodities.add(_tech) - living_techs.add(_tech) - if _oc in waste_comms: - waste_dict[_r, p].add(_oc) - except: - # EndOfLifeOutput table did not exist TODO remove this eventually - pass - - # Construction input - try: - raw = cur.execute( - 'SELECT region, input_comm, tech, vintage FROM ConstructionInput' - ).fetchall() - for r, ic, tech, v in raw: - techs[r, v].add(Tech(r, ic, 'Construction', v, tech)) - demand_dict[r, v].add(tech) - res.capacity_commodities.add(tech) - living_techs.add(tech) - except: - # ConstructionInput table did not exist TODO remove this eventually - pass - res.available_techs = techs - res.demand_commodities = demand_dict - res.source_commodities = source_dict - res.waste_commodities = waste_dict + living_techs: set[str] = set() - # pick up the linked techs... - try: - raw = cur.execute( - 'SELECT primary_region, primary_tech, emis_comm, driven_tech FROM main.LinkedTech' - ).fetchall() - except: - raw = [] + # --- 2. Process technologies --- + for r, ic, tech, v, oc, lifetime in raw_techs: + for p in periods: + if not (v <= p < v + lifetime): + continue + + living_techs.add(tech) + if '-' in r: # Inter-regional transfer + r1, r2 = r.split('-') + source_comm, dest_comm = f'{ic} ({r1})', f'{oc} ({r2})' + res.available_techs[r2, p].add(Tech(r2, source_comm, tech, v, oc)) + res.available_techs[r1, p].add(Tech(r1, ic, tech, v, dest_comm)) + res.available_techs[r, p].add(Tech(r, ic, tech, v, oc)) + res.source_commodities[r2, p].add(source_comm) + res.demand_commodities[r1, p].add(dest_comm) + res.physical_commodities.update([source_comm, dest_comm]) + res.exchange_commodities.update([source_comm, dest_comm]) + else: # Standard technology + res.available_techs[r, p].add(Tech(r, ic, tech, v, oc)) + if ic in basic_data['source_commodities_all']: + res.source_commodities[r, p].add(ic) + if oc in basic_data['waste_commodities_all']: + res.waste_commodities[r, p].add(oc) + + is_natural_eol = p <= v + lifetime < p + basic_data['period_length'][p] + is_retireable = ( + tech in basic_data['tech_retire'] + and v < p <= v + lifetime - basic_data['period_length'][p] + ) + has_survival = (r, tech, v) in basic_data['tech_survival_curve'] + + if is_natural_eol or is_retireable or has_survival: + for eol_oc in lookup_data['eol'].get((r, tech, v), []): + res.available_techs[r, p].add(Tech(r, tech, 'EndOfLife', v, eol_oc)) + res.source_commodities[r, p].add(tech) + res.capacity_commodities.add(tech) + if eol_oc in basic_data['waste_commodities_all']: + res.waste_commodities[r, p].add(eol_oc) + + # --- 3. Process Construction --- + for r, ic, tech, v in lookup_data['construction']: + res.available_techs[r, v].add(Tech(r, ic, 'Construction', v, tech)) + res.demand_commodities[r, v].add(tech) + res.capacity_commodities.add(tech) + living_techs.add(tech) + + # --- 4. Process Linked Techs and Other Metadata --- res.available_linked_techs = { - LinkedTech(region=r, driver=driver, emission=emiss, driven=driven) - for (r, driver, emiss, driven) in raw + LinkedTech(r, driver, emiss, driven) + for r, driver, emiss, driven in lookup_data['linked'] if driver in living_techs and driven in living_techs } - - # pick up negative costs... - raw = cur.execute('SELECT DISTINCT tech FROM CostVariable where cost < 0').fetchall() - for row in raw: - tech = row[0] + for tech in lookup_data['neg_cost_techs']: res.update_tech_data(tech=tech, element='neg_cost', value=True) - logger.debug('built network data: %s', res.__str__()) + + logger.debug('built network data: %s', res) return res From 88c5481f192a199be0a8ebc97a80eecbb93ed279 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 22 Oct 2025 09:02:33 -0400 Subject: [PATCH 260/587] fixing typing issues in pricing_check.py --- temoa/model_checking/pricing_check.py | 28 ++------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/temoa/model_checking/pricing_check.py b/temoa/model_checking/pricing_check.py index dee54fd14..4867d53c2 100644 --- a/temoa/model_checking/pricing_check.py +++ b/temoa/model_checking/pricing_check.py @@ -14,30 +14,6 @@ 3. Technologies that any entry for a fixed or variable cost, but do not extend through all years in the tech_lifetime - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 11/5/23 - -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . """ from collections import defaultdict @@ -147,7 +123,7 @@ def price_checker(M: 'TemoaModel') -> bool: f'the base (vintage) year, but not all:\n' ) err += ' missing (r, v):\n' - for r, v in sorted(missing_techs.get(t)): + for r, v in sorted(missing_techs[t]): err += f' ({r}, {v})\n' err += ' available (r, v):\n' for r, tt, v in compaprable_fc: @@ -173,7 +149,7 @@ def price_checker(M: 'TemoaModel') -> bool: f'check 1b:\ntech {t} has Investment Cost in some vintage/regions but not all\n' ) err += ' missing (r, v):\n' - for r, v in sorted(missing_techs.get(t)): + for r, v in sorted(missing_techs[t]): err += f' ({r}, {v})\n' err += ' available (r, v):\n' for r, tt, v in compaprable_ic: From 4836f331e9b273ba013faba4aab5b08b5e384d1b Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 22 Oct 2025 16:01:38 -0400 Subject: [PATCH 261/587] Polishing commodity network with switch to iterative DFS, encapsulating helpers, and more type hints --- pyproject.toml | 2 +- temoa/model_checking/commodity_network.py | 584 +++++++++------------- tests/test_source_check.py | 291 ++++++----- 3 files changed, 417 insertions(+), 460 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index fa8035263..b07c394d2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -105,7 +105,7 @@ python_version = "3.12" mypy_path = "stubs" # Exclude specific directories from type checking will try to add them back gradually -exclude = "(?x)(^tests/|^temoa/model_checking/|^temoa/data_processing/|^temoa/extensions/|^temoa/utilities/|^docs/)" +exclude = "(?x)(^tests/|^temoa/data_processing/|^temoa/extensions/|^temoa/utilities/|^docs/)" # Strict typing for our own code disallow_untyped_defs = true diff --git a/temoa/model_checking/commodity_network.py b/temoa/model_checking/commodity_network.py index 67a8da368..63ecf72f5 100644 --- a/temoa/model_checking/commodity_network.py +++ b/temoa/model_checking/commodity_network.py @@ -1,405 +1,319 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 3/11/24 - +This module provides the CommodityNetwork class, a tool for analyzing and +validating the structure of an energy system model for a specific region +and time period within the Temoa framework. + +The primary purpose is to perform a "source trace" analysis to ensure that all +technologies supplying a demand are fully connected back to a designated source +commodity (e.g., crude oil, natural gas, solar radiation). This process +identifies two types of modeling errors: +1. Demand-Side Orphans: Technologies that are part of a chain serving a demand + but are not connected to a valid source. +2. Other Orphans: Technologies that are not connected to any demand chain at all. + +The analysis is performed using a depth first search on a directed graph where +commodities are nodes and technologies are edges. """ from collections import defaultdict -from itertools import chain from logging import getLogger +from typing import TypeAlias from temoa.model_checking.network_model_data import NetworkModelData, Tech +from temoa.types.core_types import Commodity, Technology logger = getLogger(__name__) +# Represents a technology link: (input_commodity, tech_name) +TechLink: TypeAlias = tuple[Commodity, Technology] +# Represents a full connection: (input_commodity, tech_name, output_commodity) +TechConnection: TypeAlias = tuple[Commodity, Technology, Commodity] +# Adjacency dict mapping: {output_comm: set of (input_comm, tech_name)} +ForwardConnections: TypeAlias = dict[Commodity, set[TechLink]] +# Adjacency dict mapping: {input_comm: set of (output_comm, tech_name)} +ReverseConnections: TypeAlias = dict[Commodity, set[TechLink]] + class CommodityNetwork: """ - class to hold the network for a particular region/period. Note that the commodity network here is blind - to vintage. Determining whether a connection is valid/invalid is independent of vintage or how many - vintages are represented. It is the responsibility of the commodity network manager to use these - determinations correctly across available vintages + Holds and analyzes the commodity-technology network for a specific region and period. + + This class is blind to vintage; it determines network validity based on connections + independent of vintage. It is the responsibility of the manager to apply these + findings across available vintages. """ - def __init__(self, region, period: int, model_data: NetworkModelData): + def __init__(self, region: str, period: int, model_data: NetworkModelData): """ - make the network - :param region: region - :param period: period - :param model_data: a NetworkModelData object + Initializes and builds the network for a given region and period. + + :param region: The region to analyze. + :param period: The period to analyze. + :param model_data: A NetworkModelData object containing all model connections. """ - # check the marking of source commodities first, as the db may not be configured for source check... - self.model_data = model_data - if not self.model_data.source_commodities: - logger.error( - 'No source commodities discovered when initializing Commodity Network. ' - 'Have source commodities been identified in commodities ' - "table with 's'?" - ) - raise ValueError( - 'Attempted to do source trace with no source commodities marked. ' - 'Have source commodities been identified in commodities ' - "table with 's'?" - ) - self.demand_orphans: set[tuple] = set() - self.other_orphans: set[tuple] = set() - self.good_connections: set[tuple] = set() self.region = region self.period = period - # the cataloguing of inputs/outputs by tech is needed for implicit links like via emissions in LinkedTech - self.tech_inputs: dict[str, set[str]] = defaultdict(set) - self.tech_outputs: dict[str, set[str]] = defaultdict(set) - self.connections: dict[str, set[tuple[str, str]]] = defaultdict(set) - """All connections in the model {oc: {(ic, tech), ...}}""" - - self.viable_linked_tech: set[tuple[str, str]] = set() # name-name pairings + self.model_data = model_data - self.orig_connex: set[tuple] = set() + if not self.model_data.source_commodities: + msg = ( + "No source commodities found. Have they been marked with 's' " + 'in the commodities table?' + ) + logger.error(msg) + raise ValueError(msg) - # devnote: changing this from error to info as a power sector model might have - # transmission-only nodes (exchange techs only, no demands) if not self.model_data.demand_commodities[self.region, self.period]: msg = ( - f'No demand commodities discovered in region {self.region} period {self.period}. Ignore this ' - 'if this was intentional.' + f'No demand commodities discovered in region {self.region} ' + f'period {self.period}. Ignore this if this was intentional.' ) logger.info(msg) - # dev note: This code was originally designed/tested to run on tuples of (ic, tech_name, oc) - # since the implementation of Tech named tuple, we could switch over to that soon, - # but it will be work to re-work the tests. The networks are smaller this way - # because of reduced redundant links for multi-vintages, but we will have to - # filter the Tech tuples for output generation against the names... - - # scan techs for this r, p - for tech in self.model_data.available_techs[self.region, self.period]: - self.connections[tech.oc].add((tech.ic, tech.name)) - self.tech_inputs[tech.name].add(tech.ic) - self.tech_outputs[tech.name].add(tech.oc) - # make synthetic connection between linked techs - self.prescreen_linked_tech() + # Final results of the analysis + self.good_connections: set[TechConnection] = set() + self.demand_orphans: set[TechConnection] = set() + self.other_orphans: set[TechConnection] = set() - def remove_tech_by_name(self, tech_name: str) -> None: - """ - Remove a tech by name from the network - :param tech_name: The string name of the tech - :return: - """ - # remove from data sources - self.tech_inputs.pop(tech_name, None) - self.tech_outputs.pop(tech_name, None) + # Internal state for the analysis + self.tech_inputs: dict[str, set[str]] = defaultdict(set) + self.tech_outputs: dict[str, set[str]] = defaultdict(set) + self.connections: ForwardConnections = defaultdict(set) + self.viable_linked_tech: set[tuple[str, str]] = set() - removed = set() - for oc, s in self.connections.items(): - removals = set() - for ic, name in s: - if name == tech_name: # we found a reference - removals.add((ic, name)) - removed.add((ic, tech_name, oc)) - s -= removals # take out all the removals from the connection - # add every removed tech to the orphan list, so it can be processed by the manager - for r in removed: - self.other_orphans.add(r) - logger.debug('removed %s with a by-name removal', r) - - def reload(self, connections: set[Tech]): - """ - reload the network model with a new set of connections and clear existing ones - :param connections: a set of connections (Techs) to evaluate - :return: None - """ + self._load_connections() + self.prescreen_linked_tech() + + def _load_connections(self) -> None: + """Populate internal connection structures from model_data.""" self.tech_inputs.clear() self.tech_outputs.clear() self.connections.clear() - self.orig_connex.clear() - # reload 'em - for tech in connections: + + techs = self.model_data.available_techs[self.region, self.period] + for tech in techs: self.connections[tech.oc].add((tech.ic, tech.name)) self.tech_inputs[tech.name].add(tech.ic) self.tech_outputs[tech.name].add(tech.oc) - def get_valid_tech(self) -> set[Tech]: - return { - tech - for tech in self.model_data.available_techs[self.region, self.period] - if (tech.ic, tech.name, tech.oc) in self.good_connections - } - - def get_demand_side_orphans(self) -> set[Tech]: - return { - tech - for tech in self.model_data.available_techs[self.region, self.period] - if (tech.ic, tech.name, tech.oc) in self.demand_orphans - } + def reload(self, connections: set[Tech]) -> None: + """ + Reload the network model with a new set of connections. - def get_other_orphans(self) -> set[Tech]: - return { - tech - for tech in self.model_data.available_techs[self.region, self.period] - if (tech.ic, tech.name, tech.oc) in self.other_orphans - } + :param connections: A set of connections (Tech objects) to evaluate. + """ + # Overwrite the model data's available techs for this region/period + self.model_data.available_techs[self.region, self.period] = connections + # Clear all existing state and reload + self.good_connections.clear() + self.demand_orphans.clear() + self.other_orphans.clear() + self.viable_linked_tech.clear() + self._load_connections() - def prescreen_linked_tech(self): - """Screen the linked tech to ensure both members of the available link are available. If not, remove strays""" + def remove_tech_by_name(self, tech_name: str) -> None: + """Remove all connections associated with a given technology name.""" + self.tech_inputs.pop(tech_name, None) + self.tech_outputs.pop(tech_name, None) - for r, driver, emission, driven in self.model_data.available_linked_techs: + removed_connections: set[TechConnection] = set() + # Use list() to avoid issues with modifying the dict during iteration + for oc, links in list(self.connections.items()): + removals = {link for link in links if link[1] == tech_name} + if removals: + links -= removals + for ic, name in removals: + removed_connections.add((ic, name, oc)) + if not links: + self.connections.pop(oc, None) + + self.other_orphans.update(removed_connections) + for r in removed_connections: + logger.debug(f'Removed {r} via by-name removal') + + def prescreen_linked_tech(self) -> None: + """ + Screen linked techs to ensure both members of a pair are available. + If not, the stray member is removed from the network analysis. + """ + for r, driver, _, driven in self.model_data.available_linked_techs: if r == self.region: - # check that the driver & driven techs both exist... we only check by NAME for LinkedTech - if driver in self.tech_outputs and driven in self.tech_outputs: # we're gtg. - logger.debug( - 'Both %s and %s are available in region %s, period %s to establish link', - driver, - driven, - self.region, - self.period, - ) - self.viable_linked_tech.add((driver, driven)) + driver_exists = driver in self.tech_outputs + driven_exists = driven in self.tech_outputs - # else, document errors in linkage... - elif driver not in self.tech_outputs and driven not in self.tech_outputs: - # neither tech is present, not a problem + if driver_exists and driven_exists: logger.debug( - 'Note (no action reqd.): Neither linked tech %s nor %s are active in region %s, period %s', - driver, - driven, - self.region, - self.period, + f'Both {driver} and {driven} are available in region ' + f'{self.region}, period {self.period} to establish link' ) - elif driver in self.tech_outputs and driven not in self.tech_outputs: + self.viable_linked_tech.add((driver, driven)) + elif driver_exists and not driven_exists: logger.info( - 'No driven linked tech available for driver %s in region %s, period %d. ' - 'Driver REMOVED.', - driver, - self.region, - self.period, + f'No driven linked tech for driver {driver} in region ' + f'{self.region}, period {self.period}. Driver REMOVED.' ) self.remove_tech_by_name(driver) - else: # ... only the driven tech is present + elif not driver_exists and driven_exists: logger.warning( - 'Driven linked tech %s is not connected to an active or available ' - 'driver in region %s, period %d. Driven tech REMOVED.', - driven, - self.region, - self.period, + f'Driven linked tech {driven} has no active driver in ' + f'region {self.region}, period {self.period}. ' + f'Driven tech REMOVED.' ) self.remove_tech_by_name(driven) - def analyze_network(self): - # Due to fact that each "scan" is static, we may discover that only 1 member of a linked tech - # is viable. IF that happens, we need to remove the partner and go again. In a bizarre situation, - # this may be an iterative process, so we might as well do it till done... - done = False - demand_side_connections = set() - while not done: - done = True # assume the best! - # dev note: send a copy of connections... - # it is consumed by the function. (easier than managing it in the recursion) - discovered_sources, demand_side_connections = _visited_dfs( + def analyze_network(self) -> None: + """ + Analyzes the network to find valid and orphaned connections. + + This process may be iterative if linked technologies are found to be invalid, + as removing one requires removing its partner and re-running the analysis. + """ + while True: + demand_nodes = ( self.model_data.demand_commodities[self.region, self.period] - | self.model_data.waste_commodities[self.region, self.period], - self.model_data.source_commodities[self.region, self.period], - self.connections.copy(), + | self.model_data.waste_commodities[self.region, self.period] ) - self.good_connections = _mark_good_connections( - good_ic=discovered_sources, connections=demand_side_connections.copy() + source_nodes = self.model_data.source_commodities[self.region, self.period] + + ( + discovered_sources, + reverse_connex, + ) = self._trace_backward_from_demands( + start_nodes=demand_nodes, + end_nodes=source_nodes, + connections=self.connections, ) - observed_tech = {tech for (ic, tech, oc) in self.good_connections} - sour_links = set() - for link in self.viable_linked_tech: - if not all((link[0] in observed_tech, link[1] in observed_tech)): - sour_links.add(link) - self.remove_tech_by_name(link[0]) - self.remove_tech_by_name(link[1]) - done = False - logger.warning( - 'Both members of link %s are not valid in the network. Both members REMOVED in region %s, period %s', - link, - self.region, - self.period, - ) + + self.good_connections = self._trace_forward_from_sources( + start_nodes=discovered_sources, connections=reverse_connex + ) + + observed_tech_names = {tech for _, tech, _ in self.good_connections} + sour_links = { + link + for link in self.viable_linked_tech + if not (link[0] in observed_tech_names and link[1] in observed_tech_names) + } + + if not sour_links: + break # Analysis is stable, exit loop. + + for driver, driven in sour_links: + logger.warning( + f'Both members of link ({driver}, {driven}) are not valid. ' + f'Removing both in region {self.region}, period {self.period}.' + ) + self.remove_tech_by_name(driver) + self.remove_tech_by_name(driven) self.viable_linked_tech -= sour_links - logger.debug( - 'Got %d good technologies (possibly multi-vintage) from %d techs in region %s, period %d', - len(self.good_connections), - len(tuple(chain(*self.connections.values()))), - self.region, - self.period, - ) - - # Sort out the demand-side and supply-side orphans - # Now we should have: - # 1. The original connections - # 2. The demand-side connections from the first search (all things backward from Demands) - # 3. The "good" connections that have full linkage from source back to demand - - # So we can infer (these are set operations): - # 4. demand-side orphans = demand_side_connections - good_connections - # 5. other orphans = original_connections - demand_side_connections - good_connections - - # flat lists are easier for comparison, so... - self.orig_connex: set[tuple] = { - (ic, tech, oc) for oc in self.connections for (ic, tech) in self.connections[oc] + all_connections = { + (ic, name, oc) for oc, links in self.connections.items() for ic, name in links } - # dev note: recall, the demand connex are inventoried by IC for use in the 2nd search, so we need to poll by IC... - demand_connex: set[tuple] = { - (ic, tech, oc) - for ic in demand_side_connections - for (oc, tech) in demand_side_connections[ic] + demand_reachable_connections = { + (ic, name, oc) for ic, links in reverse_connex.items() for oc, name in links } - self.demand_orphans = demand_connex - self.good_connections - # we may already have some removed things in "other orphans" so add to it... - self.other_orphans |= self.orig_connex - demand_connex - self.good_connections - + self.demand_orphans = demand_reachable_connections - self.good_connections + self.other_orphans |= all_connections - demand_reachable_connections + + self._log_orphans() + + def _trace_backward_from_demands( + self, + start_nodes: set[str], + end_nodes: set[str], + connections: ForwardConnections, + ) -> tuple[set[str], ReverseConnections]: + """Iterative DFS tracing backward from demand nodes.""" + stack = list(start_nodes) + visited_nodes = set() + discovered_sources = set() + reachable_subgraph: ReverseConnections = defaultdict(set) + + while stack: + current_oc = stack.pop() + if current_oc in visited_nodes: + continue + visited_nodes.add(current_oc) + + for ic, tech in connections.get(current_oc, set()): + reachable_subgraph[ic].add((current_oc, tech)) + if ic in end_nodes: + discovered_sources.add(ic) + if ic not in visited_nodes: + stack.append(ic) + + return discovered_sources, reachable_subgraph + + def _trace_forward_from_sources( + self, start_nodes: set[str], connections: ReverseConnections + ) -> set[TechConnection]: + """Iterative DFS tracing forward from discovered source nodes.""" + stack = list(start_nodes) + visited_nodes = set(start_nodes) + good_connections: set[TechConnection] = set() + + while stack: + current_ic = stack.pop() + + for oc, tech in connections.get(current_ic, set()): + good_connections.add((current_ic, tech, oc)) + if oc not in visited_nodes: + visited_nodes.add(oc) + stack.append(oc) + + return good_connections + + def _log_orphans(self) -> None: + """Helper to log discovered orphaned processes.""" if self.other_orphans: logger.info( - 'Source tracing revealed %d "other" (non-demand) orphaned processes in region %s, period %d.', - len(self.other_orphans), - self.region, - self.period, + f"Source tracing revealed {len(self.other_orphans)} 'other' " + f'(non-demand) orphaned processes in region {self.region}, ' + f'period {self.period}.' ) for orphan in sorted(self.other_orphans, key=lambda x: x[1]): - logger.info( - 'Discovered orphaned process: %s in region %s, period %d', - orphan, - self.region, - self.period, - ) + logger.info(f'Discovered orphaned process: {orphan}') + if self.demand_orphans: logger.info( - 'Source tracing revealed %d demand-side orphaned processes in region %s, period %d.', - len(self.demand_orphans), - self.region, - self.period, + f'Source tracing revealed {len(self.demand_orphans)} demand-side ' + f'orphaned processes in region {self.region}, period {self.period}.' ) for orphan in sorted(self.demand_orphans, key=lambda x: x[1]): - logger.info( - 'Discovered orphaned process: %s in region %s, period %d', - orphan, - self.region, - self.period, - ) + logger.info(f'Discovered orphaned process: {orphan}') - def unsupported_demands(self) -> set[str]: - """ - Look for demand commodities that are not connected via a "good connection" - :return: set of improperly supported demands - """ - supported_demands = {t[2] for t in self.good_connections} - bad_demands = { - d - for d in self.model_data.demand_commodities[self.region, self.period] - if d not in supported_demands + def get_valid_tech(self) -> set[Tech]: + """Returns the set of Tech objects that are part of a valid connection.""" + return { + tech + for tech in self.model_data.available_techs[self.region, self.period] + if (tech.ic, tech.name, tech.oc) in self.good_connections } - return bad_demands + def get_demand_side_orphans(self) -> set[Tech]: + """Returns Tech objects for demand-side orphans.""" + return { + tech + for tech in self.model_data.available_techs[self.region, self.period] + if (tech.ic, tech.name, tech.oc) in self.demand_orphans + } -def _mark_good_connections( - good_ic: set[str], connections: dict[str, set[tuple]], start: str | None = None -) -> set[tuple]: - """ - Now that we have ID'ed the good ic that have been discovered, we need to work back up - the chain of visited nodes to identify the good connections (this is the reverse of the - previous search where we looked backward from demand. Here we look up from the Input Commodities - :param start: The current node to start from - :param good_ic: The set of Input Commodities that were discovered by the first search - :param connections: The set of connections to analyze. It is consumed by the function via pop() - :return: - """ + def get_other_orphans(self) -> set[Tech]: + """Returns Tech objects for non-demand-side orphans.""" + return { + tech + for tech in self.model_data.available_techs[self.region, self.period] + if (tech.ic, tech.name, tech.oc) in self.other_orphans + } - # end conditions... - if not good_ic and not start: # nothing to discover - return set() - else: - good_connections = set() - - if not start: - for start in good_ic: - good_connections |= _mark_good_connections(good_ic, connections, start=start) - - # recurse... - for oc, tech in connections.pop(start, []): # prevent re-expanding this later by popping - good_connections.add((start, tech, oc)) - # explore all upstream - good_connections |= _mark_good_connections( - good_ic=good_ic, connections=connections, start=oc - ) - return good_connections - - -def _visited_dfs( - start_nodes: set[str], - end_nodes: set[str], - connections: dict[str, set[tuple]], - current_start=None, -) -> tuple[set, dict[str, set[tuple]]]: - """ - recursive depth-first search to identify discovered source nodes and connections from - a start point and set of connections - :param start_nodes: the set of demand commodities (oc ∈ demand) - :param end_nodes: source nodes, or ones traceable to source nodes - :param connections: the connections to explore {output: {(ic, tech)}} - :param current_start: the current node (ic) index - :return: the set of viable tech tuples (ic, tech, oc) - """ - # setup... - discovered_sources = set() - visited = defaultdict(set) - - # end conditions... - if not current_start and not start_nodes: # no more starts, we're done - return set(), dict() - if not current_start: # start from each node in the starts - for node in start_nodes: - ds, v = _visited_dfs( - start_nodes=start_nodes, - end_nodes=end_nodes, - connections=connections, - current_start=node, - ) - discovered_sources.update(ds) - for k in v: - visited[k].update(v[k]) - return discovered_sources, visited - - # we have a start node, dig from here. - for ic, tech in connections.pop(current_start, []): # we can pop, no need to re-explore - visited[ic].add((current_start, tech)) - if ic in end_nodes: # we have struck gold - # add the current ic to discoveries - discovered_sources.add(ic) - else: - # explore from here - ds, v = _visited_dfs( - start_nodes, - end_nodes, - connections, - current_start=ic, - ) - discovered_sources.update(ds) - for k in v: - visited[k].update(v[k]) - return discovered_sources, visited + def unsupported_demands(self) -> set[str]: + """ + Finds demand commodities that are not supplied by any valid connection. + + :return: A set of unsupported demand commodity names. + """ + supported_demands = {oc for (_, _, oc) in self.good_connections} + all_demands = self.model_data.demand_commodities[self.region, self.period] + return all_demands - supported_demands diff --git a/tests/test_source_check.py b/tests/test_source_check.py index 702ae9a99..a9b3fee09 100644 --- a/tests/test_source_check.py +++ b/tests/test_source_check.py @@ -1,85 +1,72 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 2/6/24 +Tests for the CommodityNetwork analysis class. +This test suite verifies the core logic of the network analysis, ensuring that +it correctly identifies valid ("good") connections, demand-side orphans, and +other orphans under various network topologies. """ -from temoa.model_checking.commodity_network import _mark_good_connections, _visited_dfs +from collections import defaultdict +from unittest.mock import MagicMock +import pytest -def test_network_analysis(): - """ - tests of the dfs connection maker - :return: - """ - # s = source commodity - # p = physical commodity - # d = demand commodity (starts for DFS) - # t = techs +# Assuming the refactored code is in this location +from temoa.model_checking.commodity_network import CommodityNetwork +from temoa.model_checking.network_model_data import Tech - # s1 -> t1 -> p1 -> t2 -> d1 - start_nodes = {'d1'} - end_nodes = {'s1'} - connections = {'d1': {('p1', 't2')}, 'p1': {('s1', 't1')}} - good_tech = {('s1', 't1', 'p1'), ('p1', 't2', 'd1')} - discovered_sources, visited = _visited_dfs( - start_nodes=start_nodes, end_nodes=end_nodes, connections=connections - ) - t = _mark_good_connections(discovered_sources, visited) - assert t == good_tech, 'should match up!' +# --- Test Case Definitions --- +# Each tuple contains: +# 1. test_id (str): A descriptive name for the test case. +# 2. start_nodes (set): Demand commodities to start the backward trace from. +# 3. end_nodes (set): Source commodities that validate a path. +# 4. connections (dict): The network structure {output: {(input, tech)}}. +# 5. expected_good (set): The connections that should be fully valid. +# 6. expected_demand_orphans (set): Connections reachable from demand but not a source. +# 7. expected_other_orphans (set): Connections not reachable from demand at all. +TEST_CASES = [ + # s = source commodity, p = physical commodity, d = demand, t = tech + # Test 1: A simple, valid, linear chain from source to demand. + # s1 -> t1 -> p1 -> t2 -> d1 + ( + 'simple_linear_chain', + {'d1'}, + {'s1'}, + {'d1': {('p1', 't2')}, 'p1': {('s1', 't1')}}, + {('s1', 't1', 'p1'), ('p1', 't2', 'd1')}, + set(), + set(), + ), + # Test 2: One valid chain and one orphaned branch feeding into the same demand. # s1 -> t1 -> p1 -> t2 -> d1 # / # p2 -> t3 - - - start_nodes = {'d1'} - end_nodes = {'s1'} - connections = {'d1': {('p1', 't2'), ('p2', 't3')}, 'p1': {('s1', 't1')}} - good_tech = {('s1', 't1', 'p1'), ('p1', 't2', 'd1')} - discovered_sources, visited = _visited_dfs( - start_nodes=start_nodes, end_nodes=end_nodes, connections=connections - ) - t = _mark_good_connections(discovered_sources, visited) - assert t == good_tech, 'should match up!' - + ( + 'one_good_one_orphan_branch', + {'d1'}, + {'s1'}, + {'d1': {('p1', 't2'), ('p2', 't3')}, 'p1': {('s1', 't1')}}, + {('s1', 't1', 'p1'), ('p1', 't2', 'd1')}, + {('p2', 't3', 'd1')}, + set(), + ), + # Test 3: Multiple valid paths from one intermediate commodity, plus an orphan branch. # - t4 - # / \ # s1 -> t1 -> p1 -> t2 -> d1 # / # p2 -> t3 - - - start_nodes = {'d1'} - end_nodes = {'s1'} - connections = {'d1': {('p1', 't2'), ('p2', 't3'), ('p1', 't4')}, 'p1': {('s1', 't1')}} - good_tech = {('s1', 't1', 'p1'), ('p1', 't2', 'd1'), ('p1', 't4', 'd1')} - discovered_sources, visited = _visited_dfs( - start_nodes=start_nodes, end_nodes=end_nodes, connections=connections - ) - t = _mark_good_connections(discovered_sources, visited) - assert t == good_tech, 'should match up!' - + ( + 'multiple_paths_from_one_source', + {'d1'}, + {'s1'}, + {'d1': {('p1', 't2'), ('p2', 't3'), ('p1', 't4')}, 'p1': {('s1', 't1')}}, + {('s1', 't1', 'p1'), ('p1', 't2', 'd1'), ('p1', 't4', 'd1')}, + {('p2', 't3', 'd1')}, + set(), + ), + # Test 4: Two independent, valid supply chains for two different demands. # - t4 - # / \ # s1 -> t1 -> p1 -> t2 -> d1 @@ -87,22 +74,20 @@ def test_network_analysis(): # p2 -> t3 - # # s2 -> t5 -> d2 - - start_nodes = {'d1', 'd2'} - end_nodes = {'s1', 's2'} - connections = { - 'd1': {('p1', 't2'), ('p2', 't3'), ('p1', 't4')}, - 'p1': {('s1', 't1')}, - 'd2': {('s2', 't5')}, - } - good_tech = {('s1', 't1', 'p1'), ('p1', 't2', 'd1'), ('p1', 't4', 'd1'), ('s2', 't5', 'd2')} - discovered_sources, visited = _visited_dfs( - start_nodes=start_nodes, end_nodes=end_nodes, connections=connections - ) - t = _mark_good_connections(discovered_sources, visited) - assert t == good_tech, 'should match up!' - - # demand 2 (d2) with no path back to any source... + ( + 'multiple_demands_and_sources', + {'d1', 'd2'}, + {'s1', 's2'}, + { + 'd1': {('p1', 't2'), ('p2', 't3'), ('p1', 't4')}, + 'p1': {('s1', 't1')}, + 'd2': {('s2', 't5')}, + }, + {('s1', 't1', 'p1'), ('p1', 't2', 'd1'), ('p1', 't4', 'd1'), ('s2', 't5', 'd2')}, + {('p2', 't3', 'd1')}, + set(), + ), + # Test 5: One demand is valid, the other is completely orphaned (no path to any source). # - t4 - # / \ # s1 -> t1 -> p1 -> t2 -> d1 @@ -110,53 +95,111 @@ def test_network_analysis(): # p2 -> t3 - # # p3 -> t5 -> d2 - - start_nodes = {'d1', 'd2'} - end_nodes = {'s1'} - connections = { - 'd1': {('p1', 't2'), ('p2', 't3'), ('p1', 't4')}, - 'p1': {('s1', 't1')}, - 'd2': {('p3', 't5')}, - } - good_tech = {('s1', 't1', 'p1'), ('p1', 't2', 'd1'), ('p1', 't4', 'd1')} - discovered_sources, visited = _visited_dfs( - start_nodes=start_nodes, end_nodes=end_nodes, connections=connections - ) - t = _mark_good_connections(discovered_sources, visited) - assert t == good_tech, 'should match up!' - - # test with loop: t4 is like storage with I/O the same + ( + 'one_demand_is_fully_orphaned', + {'d1', 'd2'}, + {'s1'}, + { + 'd1': {('p1', 't2'), ('p2', 't3'), ('p1', 't4')}, + 'p1': {('s1', 't1')}, + 'd2': {('p3', 't5')}, + }, + {('s1', 't1', 'p1'), ('p1', 't2', 'd1'), ('p1', 't4', 'd1')}, + {('p2', 't3', 'd1'), ('p3', 't5', 'd2')}, + set(), + ), + # Test 6: A valid network that includes a loop (e.g., storage technology). # - t4 - # \ / # s1 -> t1 -> p1 -> t2 -> d1 # / # p2 -> t3 - - # - - start_nodes = {'d1'} - end_nodes = {'s1', 's2'} - connections = { - 'd1': {('p1', 't2'), ('p2', 't3'), ('p1', 't4')}, - 'p1': {('s1', 't1'), ('p1', 't4')}, + ( + 'network_with_a_loop', + {'d1'}, + {'s1', 's2'}, + { + 'd1': {('p1', 't2'), ('p2', 't3'), ('p1', 't4')}, + 'p1': {('s1', 't1'), ('p1', 't4')}, # t4 loops on p1 + }, + {('s1', 't1', 'p1'), ('p1', 't2', 'd1'), ('p1', 't4', 'd1'), ('p1', 't4', 'p1')}, + {('p2', 't3', 'd1')}, + set(), + ), + # Test 7: No source nodes are defined, so no connections can be "good". + # s1 -> t1 -> p1 -> t2 -> d1 + # s2 -> t5 -> d2 + ( + 'no_source_nodes_defined', + {'d1', 'd2'}, + set(), # No sources + { + 'd1': {('p1', 't2'), ('p2', 't3'), ('p1', 't4')}, + 'p1': {('s1', 't1')}, + 'd2': {('s2', 't5')}, + }, + set(), # No good connections are possible + { + ('p1', 't2', 'd1'), + ('p2', 't3', 'd1'), + ('p1', 't4', 'd1'), + ('s1', 't1', 'p1'), + ('s2', 't5', 'd2'), + }, + set(), + ), +] + + +@pytest.mark.parametrize( + 'test_id, start_nodes, end_nodes, connections, expected_good, expected_demand_orphans, expected_other_orphans', + TEST_CASES, + ids=[case[0] for case in TEST_CASES], +) +def test_network_analysis( + test_id, + start_nodes, + end_nodes, + connections, + expected_good, + expected_demand_orphans, + expected_other_orphans, +): + """ + Tests the CommodityNetwork analysis logic against various topologies. + """ + # 1. Setup mock model data for the test case + mock_model_data = MagicMock() + region = 'test_region' + period = 2025 + + # The mock needs to return the correct data for the (region, period) key + mock_model_data.demand_commodities = defaultdict(set, {(region, period): start_nodes}) + mock_model_data.source_commodities = defaultdict(set, {(region, period): end_nodes}) + mock_model_data.waste_commodities = defaultdict(set) # Assume empty + mock_model_data.available_linked_techs = [] # Assume no linked techs + + # Convert the connections dict into a set of Tech namedtuples + available_techs = { + Tech(ic=ic, oc=oc, name=tech, vintage=period, region=region) + for oc, links in connections.items() + for ic, tech in links } - good_tech = {('s1', 't1', 'p1'), ('p1', 't2', 'd1'), ('p1', 't4', 'd1'), ('p1', 't4', 'p1')} - discovered_sources, visited = _visited_dfs( - start_nodes=start_nodes, end_nodes=end_nodes, connections=connections - ) - t = _mark_good_connections(discovered_sources, visited) - assert t == good_tech, 'should match up!' + mock_model_data.available_techs = defaultdict(set, {(region, period): available_techs}) - # no good tech - start_nodes = {'d1', 'd2'} - end_nodes = set() - connections = { - 'd1': {('p1', 't2'), ('p2', 't3'), ('p1', 't4')}, - 'p1': {('s1', 't1')}, - 'd2': {('s2', 't5')}, - } - good_tech = set() - discovered_sources, visited = _visited_dfs( - start_nodes=start_nodes, end_nodes=end_nodes, connections=connections + # 2. Instantiate the class with the mock data + network = CommodityNetwork(region=region, period=period, model_data=mock_model_data) + + # 3. Run the analysis + network.analyze_network() + + # 4. Assert the results + assert network.good_connections == expected_good, ( + f'[{test_id}] Failed to identify good connections' + ) + assert network.demand_orphans == expected_demand_orphans, ( + f'[{test_id}] Failed to identify demand-side orphans' + ) + assert network.other_orphans == expected_other_orphans, ( + f'[{test_id}] Failed to identify other orphans' ) - t = _mark_good_connections(discovered_sources, visited) - assert t == good_tech, 'should match up!' From 76c12efda6f457b1568e495785aef17757f59a95 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 22 Oct 2025 16:24:05 -0400 Subject: [PATCH 262/587] slight typing polish to commodity_network_manager --- pyproject.toml | 2 +- temoa/model_checking/commodity_graph.py | 10 +- temoa/model_checking/commodity_network.py | 10 +- .../commodity_network_manager.py | 266 +++++++++--------- temoa/model_checking/network_model_data.py | 32 +-- tests/test_source_check.py | 4 +- 6 files changed, 161 insertions(+), 163 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index b07c394d2..07da8d9ae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -127,7 +127,7 @@ disallow_any_generics = true disallow_any_unimported = true disallow_any_expr = false # temporarily false to ease transition disallow_any_decorated = true -disallow_any_explicit = true +disallow_any_explicit = false # Module-specific overrides for external dependencies [[tool.mypy.overrides]] diff --git a/temoa/model_checking/commodity_graph.py b/temoa/model_checking/commodity_graph.py index 662cfb30b..4c2e2df22 100644 --- a/temoa/model_checking/commodity_graph.py +++ b/temoa/model_checking/commodity_graph.py @@ -4,14 +4,14 @@ """ import logging +from collections.abc import Iterable from pathlib import Path -from typing import Iterable import gravis as gv import networkx as nx from temoa.core.config import TemoaConfig -from temoa.model_checking.network_model_data import NetworkModelData, Tech +from temoa.model_checking.network_model_data import NetworkModelData, TechTuple """ Tools for Energy Model Optimization and Analysis (Temoa): @@ -48,9 +48,9 @@ def generate_graph( region, period, network_data: NetworkModelData, - demand_orphans: Iterable[Tech], - other_orphans: Iterable[Tech], - driven_techs: Iterable[Tech], + demand_orphans: Iterable[TechTuple], + other_orphans: Iterable[TechTuple], + driven_techs: Iterable[TechTuple], config: TemoaConfig, ): """ diff --git a/temoa/model_checking/commodity_network.py b/temoa/model_checking/commodity_network.py index 63ecf72f5..8588a80f0 100644 --- a/temoa/model_checking/commodity_network.py +++ b/temoa/model_checking/commodity_network.py @@ -19,7 +19,7 @@ from logging import getLogger from typing import TypeAlias -from temoa.model_checking.network_model_data import NetworkModelData, Tech +from temoa.model_checking.network_model_data import NetworkModelData, TechTuple from temoa.types.core_types import Commodity, Technology logger = getLogger(__name__) @@ -96,7 +96,7 @@ def _load_connections(self) -> None: self.tech_inputs[tech.name].add(tech.ic) self.tech_outputs[tech.name].add(tech.oc) - def reload(self, connections: set[Tech]) -> None: + def reload(self, connections: set[TechTuple]) -> None: """ Reload the network model with a new set of connections. @@ -284,7 +284,7 @@ def _log_orphans(self) -> None: for orphan in sorted(self.demand_orphans, key=lambda x: x[1]): logger.info(f'Discovered orphaned process: {orphan}') - def get_valid_tech(self) -> set[Tech]: + def get_valid_tech(self) -> set[TechTuple]: """Returns the set of Tech objects that are part of a valid connection.""" return { tech @@ -292,7 +292,7 @@ def get_valid_tech(self) -> set[Tech]: if (tech.ic, tech.name, tech.oc) in self.good_connections } - def get_demand_side_orphans(self) -> set[Tech]: + def get_demand_side_orphans(self) -> set[TechTuple]: """Returns Tech objects for demand-side orphans.""" return { tech @@ -300,7 +300,7 @@ def get_demand_side_orphans(self) -> set[Tech]: if (tech.ic, tech.name, tech.oc) in self.demand_orphans } - def get_other_orphans(self) -> set[Tech]: + def get_other_orphans(self) -> set[TechTuple]: """Returns Tech objects for non-demand-side orphans.""" return { tech diff --git a/temoa/model_checking/commodity_network_manager.py b/temoa/model_checking/commodity_network_manager.py index 094c4f617..7e1eb5d8f 100644 --- a/temoa/model_checking/commodity_network_manager.py +++ b/temoa/model_checking/commodity_network_manager.py @@ -1,198 +1,196 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 3/11/24 - -This module is responsible for running the network analysis and generating the filters -that can be used to filter down the data to valid data. It uses the NetworkModelData -and subdivides this into regions and periods and analyzes each one. - +This module provides the CommodityNetworkManager, which orchestrates the network +analysis across all regions and time periods of a Temoa model. + +Its primary responsibility is to identify and filter out "orphaned" technologies— +those that are not part of a valid, complete supply chain from a source commodity +to a demand commodity. It iteratively analyzes the model until a stable, fully- +connected network is achieved, and then generates data filters that can be used +by other parts of the Temoa framework to ensure only valid data is used. """ from collections import defaultdict +from collections.abc import Iterable from logging import getLogger -from typing import Iterable +from typing import Any, TypeAlias from temoa.core.config import TemoaConfig from temoa.model_checking.commodity_graph import generate_graph from temoa.model_checking.commodity_network import CommodityNetwork from temoa.model_checking.element_checker import ViableSet -from temoa.model_checking.network_model_data import NetworkModelData, Tech +from temoa.model_checking.network_model_data import NetworkModelData, TechTuple +from temoa.types.core_types import Period, Region logger = getLogger(__name__) +# Type alias for clarity in dictionary keys +RegionPeriodKey: TypeAlias = tuple[Region, Period] + class CommodityNetworkManager: - """Manager to run the network analysis recursively for a region and set of periods""" + """ + Manages the iterative network analysis for all regions across a set of periods. + """ def __init__(self, periods: Iterable[str | int], network_data: NetworkModelData): - self.regions = None - self.analyzed = False - self.periods = sorted(periods) - self.orig_data = network_data + self.analyzed: bool = False + self.periods: list[int] = sorted(map(int, periods)) + self.orig_data: NetworkModelData = network_data self.filtered_data: NetworkModelData | None = None + self.regions: set[str] | None = None - # outputs / saves for graphing networks - # orig_tech is saved copy of the links for graphing purposes - # this is a quick "deep copy" + # Store a deep copy of the original connections for graphing purposes self.orig_tech = {k: v.copy() for k, v in network_data.available_techs.items()} - self.demand_orphans: dict[tuple[str, str], set[Tech]] = defaultdict(set) - self.other_orphans: dict[tuple[str, str], set[Tech]] = defaultdict(set) + # Final collections of all orphans found, organized by (region, period) + self.demand_orphans: dict[RegionPeriodKey, set[TechTuple]] = defaultdict(set) + self.other_orphans: dict[RegionPeriodKey, set[TechTuple]] = defaultdict(set) - def _analyze_region(self, region: str, data: NetworkModelData): + def _analyze_region(self, region: Region, data: NetworkModelData) -> None: """ - Iteratively whittle away at the region, within the window until no new invalid techs appear - - Note: this is done in a "while" loop because actions taken in one particular period *might* - have repercussions in another period. For instance, if a tech is deemed an "orphan" in - period 5 and needs to be removed, but it was alive in periods 1-4, those periods now need to - be re-analyzed post-removal. In practice, this seems to work very quickly with few iterations, but some - datasets with complex lifetime relationships between dependent techs and few alternative - vintages or such may take a few iterations to clean. + Iteratively analyzes a region's network until no new orphans are found. + + This process is iterative because removing an orphan technology in one + period (e.g., its last available vintage) can have cascading effects, + potentially orphaning dependent technologies in earlier periods. The loop + continues until a pass over all periods finds no new orphans, signifying + a stable, valid network. """ - done = False - iter_count = 0 + for pass_num in range(1, 100): # Safety break after 100 iterations + orphans_this_pass: set[TechTuple] = set() - while not done: - iter_count += 1 - demand_orphans_this_pass: set[Tech] = set() - other_orphans_this_pass: set[Tech] = set() for period in self.periods: cn = CommodityNetwork(region=region, period=period, model_data=data) cn.analyze_network() - # check for unsupported demands.. - unsupported_demands = cn.unsupported_demands() - for commodity in unsupported_demands: + # Log any demands that are not fully supported + for commodity in cn.unsupported_demands(): logger.error( - 'Demand %s is not supported back to source commodities in region %s period %d', + 'Demand %s is not supported back to a source in region %s, period %d', commodity, - cn.region, - cn.period, + region, + period, ) - # gather orphans... + # Collect newly identified orphans from this period's analysis new_demand_orphans = cn.get_demand_side_orphans() new_other_orphans = cn.get_other_orphans() - # add the orphans to the orphanages... - self.demand_orphans[region, period] |= new_demand_orphans - self.other_orphans[region, period] |= new_other_orphans + # Add to the main collections, ensuring no duplicates + self.demand_orphans[region, period].update(new_demand_orphans) + self.other_orphans[region, period].update(new_other_orphans) - # add them to the collections for the "pass" - demand_orphans_this_pass |= new_demand_orphans - other_orphans_this_pass |= new_other_orphans + orphans_this_pass.update(new_demand_orphans) + orphans_this_pass.update(new_other_orphans) - # clean up the good tech listing and decide whether to go again... - # dev note: we could clean up the good techs in the loop, before processing next period, but - # by doing it this way, we properly capture full set of orphans by period/region - # for later use - for period in self.periods: - # any orphans need to be removed from all periods where they exist - data.available_techs[region, period] -= demand_orphans_this_pass - data.available_techs[region, period] -= other_orphans_this_pass + if not orphans_this_pass: + logger.debug( + 'Region %s analysis stable after %d pass(es).', + region, + pass_num - 1, + ) + break # Exit the loop if the network is stable - done = not demand_orphans_this_pass and not other_orphans_this_pass logger.debug( - 'Finished %d pass(es) on region %s during removal of orphan techs', - iter_count, + 'Pass %d for region %s: Found and removed %d orphan(s).', + pass_num, region, + len(orphans_this_pass), ) - logger.debug( - 'Removed %d orphans', len(demand_orphans_this_pass) + len(other_orphans_this_pass) - ) - for orphan in sorted(demand_orphans_this_pass): - logger.warning('Removed %s as demand-side orphan', orphan) - for orphan in sorted(other_orphans_this_pass): - logger.warning('Removed %s as other orphan', orphan) + for orphan in sorted(orphans_this_pass): + logger.warning('Removing orphan across all periods: %s', orphan) + + # Remove all orphans found in this pass from all periods in the region + for period in self.periods: + data.available_techs[region, period] -= orphans_this_pass + else: + logger.error('Region %s analysis did not converge after 100 passes.', region) def analyze_network(self) -> bool: """ - Analyze all regions in the model, excluding exchanges - :return: True if all regions come back "clean" (no orphans), False otherwise - """ - # NOTE: by excluding '-' regions, we are deciding NOT to screen any regional exchange techs, - # which would be a whole different level of difficulty to do. + Analyze all regions in the model. + Note: By design, this excludes inter-regional exchange technologies, + which would require a more complex, multi-region analysis. + + :return: True if the model is "clean" (no orphans found), False otherwise. + """ self.filtered_data = self.orig_data.clone() + # Identify regions to analyze (excluding exchange pseudo-regions) self.regions = {r for (r, p) in self.orig_data.available_techs if '-' not in r} - for region in self.regions: - logger.info('starting network analysis for region %s', region) + + for region in sorted(list(self.regions)): + logger.info('Starting network analysis for region %s', region) self._analyze_region(region, data=self.filtered_data) + self.analyzed = True orphans_found = any(self.demand_orphans.values()) or any(self.other_orphans.values()) return not orphans_found def build_filters(self) -> dict[str, ViableSet]: - """populate the filters from the data, after network analysis""" - if not self.analyzed: - raise RuntimeError('Trying to build filters before network analysis. Code error') - valid_ritvo = set() - valid_rtv = set() - valid_rt = set() - valid_rpit = set() - valid_rpto = set() - valid_t = set() - valid_input_commodities = set() - valid_output_commodities = set() - valid_vintages = set() - for r, p in self.filtered_data.available_techs: - for tech in self.filtered_data.available_techs[r, p]: - valid_ritvo.add((tech.region, tech.ic, tech.name, tech.vintage, tech.oc)) - valid_rtv.add((tech.region, tech.name, tech.vintage)) - valid_rt.add((tech.region, tech.name)) - valid_rpit.add((tech.region, p, tech.ic, tech.name)) - valid_rpto.add((tech.region, p, tech.name, tech.oc)) - valid_t.add(tech.name) - valid_input_commodities.add(tech.ic) - valid_output_commodities.add(tech.oc) - valid_vintages.add(tech.vintage) - - filts = { + """ + Constructs ViableSet filters based on the valid technologies remaining + after the network analysis is complete. + """ + if not self.analyzed or self.filtered_data is None: + raise RuntimeError('Cannot build filters before calling analyze_network().') + + # Use defaultdicts to easily collect unique elements + valid_elements: defaultdict[str, set[Any]] = defaultdict(set) + + for (_r, p), techs in self.filtered_data.available_techs.items(): + if not techs: + continue + for tech in techs: + valid_elements['ritvo'].add( + (tech.region, tech.ic, tech.name, tech.vintage, tech.oc) + ) + valid_elements['rtv'].add((tech.region, tech.name, tech.vintage)) + valid_elements['rt'].add((tech.region, tech.name)) + valid_elements['rpit'].add((tech.region, p, tech.ic, tech.name)) + valid_elements['rpto'].add((tech.region, p, tech.name, tech.oc)) + valid_elements['t'].add(tech.name) + valid_elements['v'].add(tech.vintage) + valid_elements['ic'].add(tech.ic) + valid_elements['oc'].add(tech.oc) + + return { 'ritvo': ViableSet( - elements=valid_ritvo, exception_loc=0, exception_vals=ViableSet.REGION_REGEXES + elements=valid_elements['ritvo'], + exception_loc=0, + exception_vals=ViableSet.REGION_REGEXES, ), 'rtv': ViableSet( - elements=valid_rtv, exception_loc=0, exception_vals=ViableSet.REGION_REGEXES + elements=valid_elements['rtv'], + exception_loc=0, + exception_vals=ViableSet.REGION_REGEXES, ), 'rt': ViableSet( - elements=valid_rt, exception_loc=0, exception_vals=ViableSet.REGION_REGEXES + elements=valid_elements['rt'], + exception_loc=0, + exception_vals=ViableSet.REGION_REGEXES, + ), + 'rpit': ViableSet( + elements=valid_elements['rpit'], + exception_loc=0, + exception_vals=ViableSet.REGION_REGEXES, + ), + 'rpto': ViableSet( + elements=valid_elements['rpto'], + exception_loc=0, + exception_vals=ViableSet.REGION_REGEXES, ), - 'rpit': ViableSet(valid_rpit, exception_loc=0, exception_vals=ViableSet.REGION_REGEXES), - 'rpto': ViableSet(valid_rpto, exception_loc=0, exception_vals=ViableSet.REGION_REGEXES), - 't': ViableSet(elements=valid_t), - 'v': ViableSet(elements=valid_vintages), - 'ic': ViableSet(elements=valid_input_commodities), - 'oc': ViableSet(elements=valid_output_commodities), + 't': ViableSet(elements=valid_elements['t']), + 'v': ViableSet(elements=valid_elements['v']), + 'ic': ViableSet(elements=valid_elements['ic']), + 'oc': ViableSet(elements=valid_elements['oc']), } - return filts - def analyze_graphs(self, config: TemoaConfig): - if not self.analyzed: - raise RuntimeError( - 'Trying to build/analyze graphs before network analysis. Code error' - ) + def analyze_graphs(self, config: TemoaConfig) -> None: + """ + Generates and saves visual graphs of the network for each region and period. + """ + if not self.analyzed or self.regions is None: + raise RuntimeError('Cannot generate graphs before calling analyze_network().') for region in self.regions: for period in self.periods: generate_graph( diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index a83e35ed5..0763df7a4 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -26,7 +26,7 @@ # --- Type Definitions --- -class Tech(NamedTuple): +class TechTuple(NamedTuple): region: Region ic: Commodity name: Technology @@ -34,7 +34,7 @@ class Tech(NamedTuple): oc: Commodity -class LinkedTech(NamedTuple): +class LinkedTechTuple(NamedTuple): region: Region driver: Technology emission: Commodity @@ -88,10 +88,10 @@ class NetworkModelData: default_factory=lambda: defaultdict(set) ) physical_commodities: set[Commodity] = field(default_factory=set) - available_techs: defaultdict[tuple[Region, Period], set[Tech]] = field( + available_techs: defaultdict[tuple[Region, Period], set[TechTuple]] = field( default_factory=lambda: defaultdict(set) ) - available_linked_techs: set[LinkedTech] = field(default_factory=set) + available_linked_techs: set[LinkedTechTuple] = field(default_factory=set) tech_data: defaultdict[Technology, dict[str, TechAttributeValue]] = field( default_factory=lambda: defaultdict(dict) ) @@ -113,7 +113,7 @@ def update_tech_data(self, tech: Technology, element: str, value: TechAttributeV """Update a data element for a tech.""" self.tech_data[tech][element] = value - def get_driven_techs(self, region: Region, period: Period) -> set[Tech]: + def get_driven_techs(self, region: Region, period: Period) -> set[TechTuple]: """Identifies all linked techs by name from the linked tech names.""" driven_tech_names = {lt.driven for lt in self.available_linked_techs} return { @@ -160,16 +160,16 @@ def _build_from_model(M: TemoaModel, myopic_index: MyopicIndex | None = None) -> for r, p, d in M.Demand.sparse_iterkeys(): dem_com[r, p].add(d) - techs: defaultdict[tuple[Region, Period], set[Tech]] = defaultdict(set) + techs: defaultdict[tuple[Region, Period], set[TechTuple]] = defaultdict(set) if M.activeFlow_rpsditvo is not None: for r, p, _s, _d, ic, tech, v, oc in M.activeFlow_rpsditvo: - techs[r, p].add(Tech(r, ic, tech, v, oc)) + techs[r, p].add(TechTuple(r, ic, tech, v, oc)) if M.activeFlow_rpitvo is not None: for r, p, ic, tech, v, oc in M.activeFlow_rpitvo: - techs[r, p].add(Tech(r, ic, tech, v, oc)) + techs[r, p].add(TechTuple(r, ic, tech, v, oc)) linked_techs = { - LinkedTech(r, driver, emission, driven) + LinkedTechTuple(r, driver, emission, driven) for r, driver, emission, driven in M.LinkedTechs.sparse_iterkeys() } @@ -324,15 +324,15 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - if '-' in r: # Inter-regional transfer r1, r2 = r.split('-') source_comm, dest_comm = f'{ic} ({r1})', f'{oc} ({r2})' - res.available_techs[r2, p].add(Tech(r2, source_comm, tech, v, oc)) - res.available_techs[r1, p].add(Tech(r1, ic, tech, v, dest_comm)) - res.available_techs[r, p].add(Tech(r, ic, tech, v, oc)) + res.available_techs[r2, p].add(TechTuple(r2, source_comm, tech, v, oc)) + res.available_techs[r1, p].add(TechTuple(r1, ic, tech, v, dest_comm)) + res.available_techs[r, p].add(TechTuple(r, ic, tech, v, oc)) res.source_commodities[r2, p].add(source_comm) res.demand_commodities[r1, p].add(dest_comm) res.physical_commodities.update([source_comm, dest_comm]) res.exchange_commodities.update([source_comm, dest_comm]) else: # Standard technology - res.available_techs[r, p].add(Tech(r, ic, tech, v, oc)) + res.available_techs[r, p].add(TechTuple(r, ic, tech, v, oc)) if ic in basic_data['source_commodities_all']: res.source_commodities[r, p].add(ic) if oc in basic_data['waste_commodities_all']: @@ -347,7 +347,7 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - if is_natural_eol or is_retireable or has_survival: for eol_oc in lookup_data['eol'].get((r, tech, v), []): - res.available_techs[r, p].add(Tech(r, tech, 'EndOfLife', v, eol_oc)) + res.available_techs[r, p].add(TechTuple(r, tech, 'EndOfLife', v, eol_oc)) res.source_commodities[r, p].add(tech) res.capacity_commodities.add(tech) if eol_oc in basic_data['waste_commodities_all']: @@ -355,14 +355,14 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - # --- 3. Process Construction --- for r, ic, tech, v in lookup_data['construction']: - res.available_techs[r, v].add(Tech(r, ic, 'Construction', v, tech)) + res.available_techs[r, v].add(TechTuple(r, ic, 'Construction', v, tech)) res.demand_commodities[r, v].add(tech) res.capacity_commodities.add(tech) living_techs.add(tech) # --- 4. Process Linked Techs and Other Metadata --- res.available_linked_techs = { - LinkedTech(r, driver, emiss, driven) + LinkedTechTuple(r, driver, emiss, driven) for r, driver, emiss, driven in lookup_data['linked'] if driver in living_techs and driven in living_techs } diff --git a/tests/test_source_check.py b/tests/test_source_check.py index a9b3fee09..229ad4033 100644 --- a/tests/test_source_check.py +++ b/tests/test_source_check.py @@ -13,7 +13,7 @@ # Assuming the refactored code is in this location from temoa.model_checking.commodity_network import CommodityNetwork -from temoa.model_checking.network_model_data import Tech +from temoa.model_checking.network_model_data import TechTuple # --- Test Case Definitions --- # Each tuple contains: @@ -181,7 +181,7 @@ def test_network_analysis( # Convert the connections dict into a set of Tech namedtuples available_techs = { - Tech(ic=ic, oc=oc, name=tech, vintage=period, region=region) + TechTuple(ic=ic, oc=oc, name=tech, vintage=period, region=region) for oc, links in connections.items() for ic, tech in links } From 2bf9980806e3ca1caa01d5090984188a99f68bb8 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 22 Oct 2025 16:59:43 -0400 Subject: [PATCH 263/587] fixing propagated type errors from model_checking --- temoa/data_io/hybrid_loader.py | 21 +++++++-- temoa/model_checking/network_model_data.py | 5 +- temoa/model_checking/validators.py | 54 +++++++++++++++------- 3 files changed, 54 insertions(+), 26 deletions(-) diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index 46bfd89ff..b0403e687 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -37,7 +37,7 @@ from temoa.extensions.myopic.myopic_index import MyopicIndex from temoa.model_checking import element_checker, network_model_data from temoa.model_checking.commodity_network_manager import CommodityNetworkManager -from temoa.model_checking.element_checker import ViableSet +from temoa.model_checking.element_checker import ValidationPrimitive, ViableSet logger = getLogger(__name__) @@ -338,8 +338,9 @@ def _filter_data( if validator is None: return values + typed_values = cast(Sequence[tuple[ValidationPrimitive, ...]], values) return element_checker.filter_elements( - values=values, validation=validator, value_locations=item.validation_map + values=typed_values, validation=validator, value_locations=item.validation_map ) def _load_component_data( @@ -399,7 +400,10 @@ def _source_trace(self, myopic_index: MyopicIndex | None = None) -> None: """ Performs the source-trace analysis to identify viable components. """ - network_data = network_model_data.build(self.con, myopic_index=myopic_index) + # The `build` function is a generic factory. Mypy cannot follow the + # dynamic dispatch to the correctly-typed `_build_from_db` function, + # so we ignore the resulting argument type error here. + network_data = network_model_data.build(self.con, myopic_index) # type: ignore[arg-type] cur = self.con.cursor() periods = set( [ @@ -454,8 +458,15 @@ def _build_efficiency_dataset( self.viable_techs = filts['t'] self.viable_input_comms = filts['ic'] self.viable_output_comms = filts['oc'] - self.viable_comms = ViableSet(elements=filts['ic'].members | filts['oc'].members) - rtt = {(r, t1, t2) for r, t1 in filts['rt'].members for t2 in filts['t'].members} + + # NOTE: Using member_tuples here is safer as it's unambiguously typed + ic_tuples = self.viable_input_comms.member_tuples + oc_tuples = self.viable_output_comms.member_tuples + self.viable_comms = ViableSet(elements=ic_tuples | oc_tuples) + + rt_tuples = filts['rt'].member_tuples + t_tuples = filts['t'].member_tuples + rtt = {(r, t1, t2) for r, t1 in rt_tuples for (t2,) in t_tuples} self.viable_rtt = ViableSet( elements=rtt, exception_loc=0, exception_vals=ViableSet.REGION_REGEXES ) diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index 0763df7a4..3707e9ea4 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -140,7 +140,7 @@ def build( return builder(data, *args, **kwargs) -def _get_builder(data: ModelBlock | DbConnection) -> Callable[..., NetworkModelData]: # type: ignore[explicit-any] +def _get_builder(data: ModelBlock | DbConnection) -> Callable[..., NetworkModelData]: """Selects the appropriate builder function based on the input data type.""" if isinstance(data, (TemoaModel, ConcreteModel)): return _build_from_model @@ -183,9 +183,6 @@ def _build_from_model(M: TemoaModel, myopic_index: MyopicIndex | None = None) -> return res -# --- Database Builder Refactored --- - - def _fetch_basic_data(cur: sqlite3.Cursor) -> BasicData: """Fetches simple, required tables and parameters from the DB.""" tech_retire = { diff --git a/temoa/model_checking/validators.py b/temoa/model_checking/validators.py index 4ab092c8b..3debc1d90 100644 --- a/temoa/model_checking/validators.py +++ b/temoa/model_checking/validators.py @@ -28,11 +28,14 @@ import re from logging import getLogger -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any import deprecated +from pyomo.core import Set from pyomo.environ import NonNegativeReals +from temoa.types.core_types import Commodity, Period, Region, Season, Technology, TimeOfDay, Vintage + if TYPE_CHECKING: from temoa.core.model import TemoaModel @@ -106,7 +109,7 @@ def validate_linked_tech(M: 'TemoaModel') -> bool: return True -def no_slash_or_pipe(M: 'TemoaModel', element) -> bool: +def no_slash_or_pipe(M: 'TemoaModel', element: object) -> bool: """ No slash character in element :param M: @@ -122,7 +125,7 @@ def no_slash_or_pipe(M: 'TemoaModel', element) -> bool: return True -def region_check(M: 'TemoaModel', region) -> bool: +def region_check(M: 'TemoaModel', region: Region) -> bool: """ Validate the region name (letters + numbers only + underscore) """ @@ -139,7 +142,7 @@ def region_check(M: 'TemoaModel', region) -> bool: return False -def linked_region_check(M: 'TemoaModel', region_pair) -> bool: +def linked_region_check(M: 'TemoaModel', region_pair: str) -> bool: """ Validate a pair of regions (r-r format where r ∈ M.R ) """ @@ -154,7 +157,7 @@ def linked_region_check(M: 'TemoaModel', region_pair) -> bool: return False -def region_group_check(M: 'TemoaModel', rg) -> bool: +def region_group_check(M: 'TemoaModel', rg: str) -> bool: """ Validate the region-group name (region or regions separated by '+') """ @@ -175,7 +178,7 @@ def region_group_check(M: 'TemoaModel', rg) -> bool: @deprecated.deprecated('needs to be updated if re-instated to accommodate group restructuring') -def tech_groups_set_check(M: 'TemoaModel', rg, g, t) -> bool: +def tech_groups_set_check(M: 'TemoaModel', rg: str, g: str, t: str) -> bool: """ Validate this entry to the tech_groups set :param M: the model @@ -193,7 +196,7 @@ def tech_groups_set_check(M: 'TemoaModel', rg, g, t) -> bool: # the buildAction approach -def activity_param_check(M: 'TemoaModel', val, rg, p, t) -> bool: +def activity_param_check(M: 'TemoaModel', val: float, rg: str, p: Period, t: Technology) -> bool: """ Validate the index and the value for an entry into an activity param indexed with region-groups :param M: the model @@ -213,7 +216,9 @@ def activity_param_check(M: 'TemoaModel', val, rg, p, t) -> bool: ) -def capacity_param_check(M: 'TemoaModel', val, rg, p, t, carrier) -> bool: +def capacity_param_check( + M: 'TemoaModel', val: float, rg: str, p: Period, t: Technology, carrier: Commodity +) -> bool: """ validate entries to capacity params :param M: the model @@ -235,7 +240,7 @@ def capacity_param_check(M: 'TemoaModel', val, rg, p, t, carrier) -> bool: ) -def activity_group_param_check(M: 'TemoaModel', val, rg, p, g) -> bool: +def activity_group_param_check(M: 'TemoaModel', val: float, rg: str, p: Period, g: str) -> bool: """ validate entries into capacity groups :param M: the model @@ -255,7 +260,9 @@ def activity_group_param_check(M: 'TemoaModel', val, rg, p, g) -> bool: ) -def emission_limit_param_check(M: 'TemoaModel', val, rg, p, e) -> bool: +def emission_limit_param_check( + M: 'TemoaModel', val: float, rg: str, p: Period, e: Commodity +) -> bool: """ validate entries into EmissionLimit param :param M: the model @@ -268,7 +275,16 @@ def emission_limit_param_check(M: 'TemoaModel', val, rg, p, e) -> bool: return all((region_group_check(M, rg), p in M.time_optimize, e in M.commodity_emissions)) -def validate_CapacityFactorProcess(M: 'TemoaModel', val, r, p, s, d, t, v) -> bool: +def validate_CapacityFactorProcess( + M: 'TemoaModel', + val: float, + r: Region, + p: Period, + s: Season, + d: TimeOfDay, + t: Technology, + v: Vintage, +) -> bool: """ validate the rsdtv index :param val: the parameter value @@ -296,7 +312,9 @@ def validate_CapacityFactorProcess(M: 'TemoaModel', val, r, p, s, d, t, v) -> bo ) -def validate_Efficiency(M: 'TemoaModel', val, r, si, t, v, so) -> bool: +def validate_Efficiency( + M: 'TemoaModel', val: float, r: Region, si: Commodity, t: Technology, v: Vintage, so: Commodity +) -> bool: """Handy for troubleshooting problematic entries""" if all( @@ -320,7 +338,7 @@ def validate_Efficiency(M: 'TemoaModel', val, r, si, t, v, so) -> bool: return False -def validate_ReserveMargin(M: 'TemoaModel'): +def validate_ReserveMargin(M: 'TemoaModel') -> None: for r in M.PlanningReserveMargin.sparse_iterkeys(): if all((r, p) not in M.processReservePeriods for p in M.time_optimize): logger.warning( @@ -329,7 +347,7 @@ def validate_ReserveMargin(M: 'TemoaModel'): ) -def validate_tech_sets(M: 'TemoaModel'): +def validate_tech_sets(M: 'TemoaModel') -> None: """ Check tech sets for any forbidden intersections """ @@ -348,7 +366,7 @@ def validate_tech_sets(M: 'TemoaModel'): raise ValueError('Technology sets failed to validate. Check log file for details.') -def check_no_intersection(set_one, set_two): +def check_no_intersection(set_one: Set, set_two: Set) -> bool: violations = set_one & set_two if violations: msg = f'The following are in both {set_one} and {set_two}, which is not permitted:\n{list(violations)}' @@ -358,7 +376,9 @@ def check_no_intersection(set_one, set_two): # Seems unused -def validate_tech_split(M: 'TemoaModel', val, r, p, c, t): +def validate_tech_split( + M: 'TemoaModel', val: float, r: Region, p: Period, c: Commodity, t: Technology +) -> bool: if all( ( r in M.regions, @@ -375,5 +395,5 @@ def validate_tech_split(M: 'TemoaModel', val, r, p, c, t): return False -def validate_0to1(M: 'TemoaModel', val, *args): +def validate_0to1(M: 'TemoaModel', val: float, *args: Any) -> bool: return 0.0 <= val <= 1.0 From 6e7af56f65e41a0f56246c3a78e6371628aee8ff Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 22 Oct 2025 17:03:20 -0400 Subject: [PATCH 264/587] temporarily ignoring commodity_graph from type checking --- pyproject.toml | 2 +- temoa/model_checking/__init__.py | 27 --------------------------- 2 files changed, 1 insertion(+), 28 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 07da8d9ae..1045f79ae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -105,7 +105,7 @@ python_version = "3.12" mypy_path = "stubs" # Exclude specific directories from type checking will try to add them back gradually -exclude = "(?x)(^tests/|^temoa/data_processing/|^temoa/extensions/|^temoa/utilities/|^docs/)" +exclude = "(?x)(^tests/|^temoa/data_processing/|^temoa/extensions/|^temoa/utilities/|^docs/|^temoa/model_checking/commodity_graph.py)" # Strict typing for our own code disallow_untyped_defs = true diff --git a/temoa/model_checking/__init__.py b/temoa/model_checking/__init__.py index 130d21721..e69de29bb 100644 --- a/temoa/model_checking/__init__.py +++ b/temoa/model_checking/__init__.py @@ -1,27 +0,0 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 3/10/24 - -""" From 44c469de62ff109ff4a05b28a0cf108d13816beb Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 22 Oct 2025 21:04:05 -0400 Subject: [PATCH 265/587] removing mypy ignore by tightening network_model_data.build typing --- temoa/data_io/hybrid_loader.py | 5 +---- temoa/model_checking/network_model_data.py | 22 ++++++++++++---------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index b0403e687..7382c9910 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -400,10 +400,7 @@ def _source_trace(self, myopic_index: MyopicIndex | None = None) -> None: """ Performs the source-trace analysis to identify viable components. """ - # The `build` function is a generic factory. Mypy cannot follow the - # dynamic dispatch to the correctly-typed `_build_from_db` function, - # so we ignore the resulting argument type error here. - network_data = network_model_data.build(self.con, myopic_index) # type: ignore[arg-type] + network_data = network_model_data.build(self.con, myopic_index) cur = self.con.cursor() periods = set( [ diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index 3707e9ea4..50e75050b 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -13,7 +13,7 @@ from collections.abc import Callable from dataclasses import dataclass, field from itertools import chain -from typing import NamedTuple, Self, TypeAlias, TypedDict +from typing import NamedTuple, Self, TypedDict, overload import deprecated from pyomo.core.base import ConcreteModel @@ -41,9 +41,9 @@ class LinkedTechTuple(NamedTuple): driven: Technology -TechAttributeValue: TypeAlias = ParameterValue -DbConnection: TypeAlias = sqlite3.Connection -ModelBlock: TypeAlias = TemoaModel | ConcreteModel | Block +type TechAttributeValue = ParameterValue +type DbConnection = sqlite3.Connection +type ModelBlock = TemoaModel | ConcreteModel | Block class BasicData(TypedDict): @@ -132,15 +132,17 @@ def __str__(self) -> str: # --- Builder Factory --- -def build( - data: ModelBlock | DbConnection, *args: ParameterValue, **kwargs: ParameterValue -) -> NetworkModelData: +@overload +def build(data: DbConnection, myopic_index: MyopicIndex | None = ...) -> NetworkModelData: ... +@overload +def build(data: ModelBlock, *args: object, **kwargs: object) -> NetworkModelData: ... +def build(data: ModelBlock | DbConnection, *args: object, **kwargs: object) -> NetworkModelData: """Factory function to dispatch to the correct builder based on data type.""" builder = _get_builder(data) return builder(data, *args, **kwargs) -def _get_builder(data: ModelBlock | DbConnection) -> Callable[..., NetworkModelData]: +def _get_builder(data: ModelBlock | DbConnection) -> Callable[..., NetworkModelData]: # type: ignore [explicit-any] """Selects the appropriate builder function based on the input data type.""" if isinstance(data, (TemoaModel, ConcreteModel)): return _build_from_model @@ -214,7 +216,7 @@ def _fetch_basic_data(cur: sqlite3.Cursor) -> BasicData: c[0] for c in cur.execute("SELECT name FROM Commodity WHERE flag = 's'").fetchall() } - demand_commodities: defaultdict[tuple[str, Period], set[str]] = defaultdict(set) + demand_commodities: defaultdict[tuple[Region, Period], set[Commodity]] = defaultdict(set) for r, p, d in cur.execute('SELECT region, period, commodity FROM main.Demand').fetchall(): demand_commodities[r, p].add(d) @@ -309,7 +311,7 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - p for p in periods if myopic_index.base_year <= p <= myopic_index.last_demand_year } - living_techs: set[str] = set() + living_techs: set[Technology] = set() # --- 2. Process technologies --- for r, ic, tech, v, oc, lifetime in raw_techs: From 35d1a65d5551612901b9b0ee714facdda706a85f Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 22 Oct 2025 21:15:30 -0400 Subject: [PATCH 266/587] minor typing updates --- pyproject.toml | 5 ++--- temoa/model_checking/commodity_network.py | 13 ++++++------- temoa/model_checking/commodity_network_manager.py | 8 ++++---- temoa/model_checking/element_checker.py | 13 ++++++------- temoa/model_checking/validators.py | 2 +- 5 files changed, 19 insertions(+), 22 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1045f79ae..49eed387f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -105,7 +105,7 @@ python_version = "3.12" mypy_path = "stubs" # Exclude specific directories from type checking will try to add them back gradually -exclude = "(?x)(^tests/|^temoa/data_processing/|^temoa/extensions/|^temoa/utilities/|^docs/|^temoa/model_checking/commodity_graph.py)" +exclude = "(?x)(^tests/|^temoa/data_processing/|^temoa/extensions/|^temoa/utilities/|^docs/|^temoa/model_checking/commodity_graph.py)" # TODO: Remove model_checking exclusion after gravis dep is removed # Strict typing for our own code disallow_untyped_defs = true @@ -127,7 +127,7 @@ disallow_any_generics = true disallow_any_unimported = true disallow_any_expr = false # temporarily false to ease transition disallow_any_decorated = true -disallow_any_explicit = false +disallow_any_explicit = true # Module-specific overrides for external dependencies [[tool.mypy.overrides]] @@ -148,7 +148,6 @@ disallow_incomplete_defs = false module = [ "temoa.data_processing.*", "temoa.extensions.*", - "temoa.model_checking.*", ] follow_imports = "silent" diff --git a/temoa/model_checking/commodity_network.py b/temoa/model_checking/commodity_network.py index 8588a80f0..25674f9dd 100644 --- a/temoa/model_checking/commodity_network.py +++ b/temoa/model_checking/commodity_network.py @@ -17,7 +17,6 @@ from collections import defaultdict from logging import getLogger -from typing import TypeAlias from temoa.model_checking.network_model_data import NetworkModelData, TechTuple from temoa.types.core_types import Commodity, Technology @@ -25,13 +24,13 @@ logger = getLogger(__name__) # Represents a technology link: (input_commodity, tech_name) -TechLink: TypeAlias = tuple[Commodity, Technology] +type TechLink = tuple[Commodity, Technology] # Represents a full connection: (input_commodity, tech_name, output_commodity) -TechConnection: TypeAlias = tuple[Commodity, Technology, Commodity] +type TechConnection = tuple[Commodity, Technology, Commodity] # Adjacency dict mapping: {output_comm: set of (input_comm, tech_name)} -ForwardConnections: TypeAlias = dict[Commodity, set[TechLink]] +type ForwardConnections = dict[Commodity, set[TechLink]] # Adjacency dict mapping: {input_comm: set of (output_comm, tech_name)} -ReverseConnections: TypeAlias = dict[Commodity, set[TechLink]] +type ReverseConnections = dict[Commodity, set[TechLink]] class CommodityNetwork: @@ -43,7 +42,7 @@ class CommodityNetwork: findings across available vintages. """ - def __init__(self, region: str, period: int, model_data: NetworkModelData): + def __init__(self, region: str, period: int, model_data: NetworkModelData) -> None: """ Initializes and builds the network for a given region and period. @@ -308,7 +307,7 @@ def get_other_orphans(self) -> set[TechTuple]: if (tech.ic, tech.name, tech.oc) in self.other_orphans } - def unsupported_demands(self) -> set[str]: + def unsupported_demands(self) -> set[Commodity]: """ Finds demand commodities that are not supplied by any valid connection. diff --git a/temoa/model_checking/commodity_network_manager.py b/temoa/model_checking/commodity_network_manager.py index 7e1eb5d8f..44c01f5d6 100644 --- a/temoa/model_checking/commodity_network_manager.py +++ b/temoa/model_checking/commodity_network_manager.py @@ -12,7 +12,7 @@ from collections import defaultdict from collections.abc import Iterable from logging import getLogger -from typing import Any, TypeAlias +from typing import Any from temoa.core.config import TemoaConfig from temoa.model_checking.commodity_graph import generate_graph @@ -24,7 +24,7 @@ logger = getLogger(__name__) # Type alias for clarity in dictionary keys -RegionPeriodKey: TypeAlias = tuple[Region, Period] +type RegionPeriodKey = tuple[Region, Period] class CommodityNetworkManager: @@ -32,7 +32,7 @@ class CommodityNetworkManager: Manages the iterative network analysis for all regions across a set of periods. """ - def __init__(self, periods: Iterable[str | int], network_data: NetworkModelData): + def __init__(self, periods: Iterable[str | int], network_data: NetworkModelData) -> None: self.analyzed: bool = False self.periods: list[int] = sorted(map(int, periods)) self.orig_data: NetworkModelData = network_data @@ -135,7 +135,7 @@ def build_filters(self) -> dict[str, ViableSet]: raise RuntimeError('Cannot build filters before calling analyze_network().') # Use defaultdicts to easily collect unique elements - valid_elements: defaultdict[str, set[Any]] = defaultdict(set) + valid_elements: defaultdict[str, set[Any]] = defaultdict(set) # type: ignore [explicit-any] for (_r, p), techs in self.filtered_data.available_techs.items(): if not techs: diff --git a/temoa/model_checking/element_checker.py b/temoa/model_checking/element_checker.py index ac327f938..7042604bd 100644 --- a/temoa/model_checking/element_checker.py +++ b/temoa/model_checking/element_checker.py @@ -8,12 +8,11 @@ import re from collections.abc import Iterable, Sequence from operator import itemgetter -from typing import Self, TypeAlias +from typing import Self, ClassVar -# For clarity in type hints -ValidationPrimitive: TypeAlias = str | int | float | None -ValidationElement: TypeAlias = tuple[ValidationPrimitive, ...] -InputElement: TypeAlias = ValidationPrimitive | ValidationElement +type ValidationPrimitive = str | int | float | None +type ValidationElement = tuple[ValidationPrimitive, ...] +type InputElement = ValidationPrimitive | ValidationElement class ViableSet: @@ -41,7 +40,7 @@ class ViableSet: """ # Stored for reference; these are examples of common automatic approvals. - REGION_REGEXES: list[str] = [ + REGION_REGEXES: ClassVar[list[str]] = [ r'\+', # any grouping with a plus sign r'^global\Z', # the exact word 'global' with no leader/trailer ] @@ -51,7 +50,7 @@ def __init__( elements: Iterable[InputElement], exception_loc: int | None = None, exception_vals: Iterable[str] | None = None, - ): + ) -> None: """ Constructs a ViableSet instance. diff --git a/temoa/model_checking/validators.py b/temoa/model_checking/validators.py index 3debc1d90..d7aa28bb4 100644 --- a/temoa/model_checking/validators.py +++ b/temoa/model_checking/validators.py @@ -395,5 +395,5 @@ def validate_tech_split( return False -def validate_0to1(M: 'TemoaModel', val: float, *args: Any) -> bool: +def validate_0to1(M: 'TemoaModel', val: float, *args: object) -> bool: return 0.0 <= val <= 1.0 From 07343f798dc1c1d18f7654bc3e05c6ca7fea7e4f Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 22 Oct 2025 21:17:37 -0400 Subject: [PATCH 267/587] Logging improvements --- temoa/model_checking/commodity_network.py | 46 ++++++++++++------- .../commodity_network_manager.py | 6 +-- temoa/model_checking/element_checker.py | 2 +- temoa/model_checking/validators.py | 2 +- tests/test_network_model_data.py | 5 +- tests/test_source_check.py | 12 ++++- 6 files changed, 47 insertions(+), 26 deletions(-) diff --git a/temoa/model_checking/commodity_network.py b/temoa/model_checking/commodity_network.py index 25674f9dd..eace39a68 100644 --- a/temoa/model_checking/commodity_network.py +++ b/temoa/model_checking/commodity_network.py @@ -128,7 +128,7 @@ def remove_tech_by_name(self, tech_name: str) -> None: self.other_orphans.update(removed_connections) for r in removed_connections: - logger.debug(f'Removed {r} via by-name removal') + logger.debug('Removed %s via by-name removal', r) def prescreen_linked_tech(self) -> None: """ @@ -142,21 +142,27 @@ def prescreen_linked_tech(self) -> None: if driver_exists and driven_exists: logger.debug( - f'Both {driver} and {driven} are available in region ' - f'{self.region}, period {self.period} to establish link' + 'Both %s and %s are available in region %s, period %s to establish link', + driver, + driven, + self.region, + self.period, ) self.viable_linked_tech.add((driver, driven)) elif driver_exists and not driven_exists: logger.info( - f'No driven linked tech for driver {driver} in region ' - f'{self.region}, period {self.period}. Driver REMOVED.' + 'No driven linked tech for driver %s in region %s, period %s. Driver REMOVED.', + driver, + self.region, + self.period, ) self.remove_tech_by_name(driver) elif not driver_exists and driven_exists: logger.warning( - f'Driven linked tech {driven} has no active driver in ' - f'region {self.region}, period {self.period}. ' - f'Driven tech REMOVED.' + 'Driven linked tech %s has no active driver in region %s, period %s. Driven tech REMOVED.', + driven, + self.region, + self.period, ) self.remove_tech_by_name(driven) @@ -199,8 +205,11 @@ def analyze_network(self) -> None: for driver, driven in sour_links: logger.warning( - f'Both members of link ({driver}, {driven}) are not valid. ' - f'Removing both in region {self.region}, period {self.period}.' + 'Both members of link (%s, %s) are not valid. Removing both in region %s, period %s.', + driver, + driven, + self.region, + self.period, ) self.remove_tech_by_name(driver) self.remove_tech_by_name(driven) @@ -268,20 +277,23 @@ def _log_orphans(self) -> None: """Helper to log discovered orphaned processes.""" if self.other_orphans: logger.info( - f"Source tracing revealed {len(self.other_orphans)} 'other' " - f'(non-demand) orphaned processes in region {self.region}, ' - f'period {self.period}.' + "Source tracing revealed %s 'other' (non-demand) orphaned processes in region %s, period %s.", + len(self.other_orphans), + self.region, + self.period, ) for orphan in sorted(self.other_orphans, key=lambda x: x[1]): - logger.info(f'Discovered orphaned process: {orphan}') + logger.info('Discovered orphaned process: %s', orphan) if self.demand_orphans: logger.info( - f'Source tracing revealed {len(self.demand_orphans)} demand-side ' - f'orphaned processes in region {self.region}, period {self.period}.' + 'Source tracing revealed %s demand-side orphaned processes in region %s, period %s.', + len(self.demand_orphans), + self.region, + self.period, ) for orphan in sorted(self.demand_orphans, key=lambda x: x[1]): - logger.info(f'Discovered orphaned process: {orphan}') + logger.info('Discovered orphaned process: %s', orphan) def get_valid_tech(self) -> set[TechTuple]: """Returns the set of Tech objects that are part of a valid connection.""" diff --git a/temoa/model_checking/commodity_network_manager.py b/temoa/model_checking/commodity_network_manager.py index 44c01f5d6..398851026 100644 --- a/temoa/model_checking/commodity_network_manager.py +++ b/temoa/model_checking/commodity_network_manager.py @@ -118,7 +118,7 @@ def analyze_network(self) -> bool: # Identify regions to analyze (excluding exchange pseudo-regions) self.regions = {r for (r, p) in self.orig_data.available_techs if '-' not in r} - for region in sorted(list(self.regions)): + for region in sorted(self.regions): logger.info('Starting network analysis for region %s', region) self._analyze_region(region, data=self.filtered_data) @@ -132,7 +132,7 @@ def build_filters(self) -> dict[str, ViableSet]: after the network analysis is complete. """ if not self.analyzed or self.filtered_data is None: - raise RuntimeError('Cannot build filters before calling analyze_network().') + raise RuntimeError('analyze_network() must be called before build_filters().') # Use defaultdicts to easily collect unique elements valid_elements: defaultdict[str, set[Any]] = defaultdict(set) # type: ignore [explicit-any] @@ -190,7 +190,7 @@ def analyze_graphs(self, config: TemoaConfig) -> None: Generates and saves visual graphs of the network for each region and period. """ if not self.analyzed or self.regions is None: - raise RuntimeError('Cannot generate graphs before calling analyze_network().') + raise RuntimeError('analyze_network() must be called before analyze_graphs().') for region in self.regions: for period in self.periods: generate_graph( diff --git a/temoa/model_checking/element_checker.py b/temoa/model_checking/element_checker.py index 7042604bd..21f6e759b 100644 --- a/temoa/model_checking/element_checker.py +++ b/temoa/model_checking/element_checker.py @@ -8,7 +8,7 @@ import re from collections.abc import Iterable, Sequence from operator import itemgetter -from typing import Self, ClassVar +from typing import ClassVar, Self type ValidationPrimitive = str | int | float | None type ValidationElement = tuple[ValidationPrimitive, ...] diff --git a/temoa/model_checking/validators.py b/temoa/model_checking/validators.py index d7aa28bb4..59d4979e2 100644 --- a/temoa/model_checking/validators.py +++ b/temoa/model_checking/validators.py @@ -28,7 +28,7 @@ import re from logging import getLogger -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING import deprecated from pyomo.core import Set diff --git a/tests/test_network_model_data.py b/tests/test_network_model_data.py index dffa502a2..d05df613d 100644 --- a/tests/test_network_model_data.py +++ b/tests/test_network_model_data.py @@ -123,7 +123,7 @@ # ============================================================================== # Fixtures # ============================================================================== -@pytest.fixture() +@pytest.fixture def mock_db_connection(request): """ A robust mock of a database connection. @@ -138,11 +138,12 @@ def mock_db_connection(request): mock_cursor = MagicMock(name='mock_cursor') mock_con.cursor.return_value = mock_cursor - def dispatcher(query, *args): + def dispatcher(query: str, *_: object) -> MagicMock: for key, data in db_data.items(): if key in query: execute_mock = MagicMock(name=f'execute_mock_for_{key}') execute_mock.fetchall.return_value = data + execute_mock.fetchone.return_value = data[0] if data else None return execute_mock raise ValueError(f'Mock database received unexpected query: {query}') diff --git a/tests/test_source_check.py b/tests/test_source_check.py index 229ad4033..661f6934f 100644 --- a/tests/test_source_check.py +++ b/tests/test_source_check.py @@ -152,7 +152,15 @@ @pytest.mark.parametrize( - 'test_id, start_nodes, end_nodes, connections, expected_good, expected_demand_orphans, expected_other_orphans', + ( + 'test_id', + 'start_nodes', + 'end_nodes', + 'connections', + 'expected_good', + 'expected_demand_orphans', + 'expected_other_orphans', + ), TEST_CASES, ids=[case[0] for case in TEST_CASES], ) @@ -177,7 +185,7 @@ def test_network_analysis( mock_model_data.demand_commodities = defaultdict(set, {(region, period): start_nodes}) mock_model_data.source_commodities = defaultdict(set, {(region, period): end_nodes}) mock_model_data.waste_commodities = defaultdict(set) # Assume empty - mock_model_data.available_linked_techs = [] # Assume no linked techs + mock_model_data.available_linked_techs = set() # Assume no linked techs # Convert the connections dict into a set of Tech namedtuples available_techs = { From 74c3fe84781ce70c7dfdca0f54d45a5e95ac32b1 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 22 Oct 2025 21:20:27 -0400 Subject: [PATCH 268/587] variable typo fix in pricing_check --- temoa/model_checking/pricing_check.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/temoa/model_checking/pricing_check.py b/temoa/model_checking/pricing_check.py index 4867d53c2..040a2ef27 100644 --- a/temoa/model_checking/pricing_check.py +++ b/temoa/model_checking/pricing_check.py @@ -115,9 +115,9 @@ def price_checker(M: 'TemoaModel') -> bool: missing_techs[t].add((r, v)) for t in missing_techs: # get set of fixed cost for all {rtv} if the tech matches - compaprable_fc = sorted(filter(lambda x: x[1] == t, base_year_fixed_cost_rtv)) + comparable_fc = sorted(filter(lambda x: x[1] == t, base_year_fixed_cost_rtv)) err = None - if compaprable_fc: + if comparable_fc: err = ( f'Check 1b:\ntech {t} has Fixed Cost in some vintage/regions for ' f'the base (vintage) year, but not all:\n' @@ -126,7 +126,7 @@ def price_checker(M: 'TemoaModel') -> bool: for r, v in sorted(missing_techs[t]): err += f' ({r}, {v})\n' err += ' available (r, v):\n' - for r, tt, v in compaprable_fc: + for r, tt, v in comparable_fc: err += f' ({r}, {v}): {M.CostFixed[r, v, tt, v]}\n' if err: logger.warning(err) From 98f421c938025e09c0d7ca23d69ab963a7766734 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 22 Oct 2025 21:30:46 -0400 Subject: [PATCH 269/587] using domain types where possible --- temoa/model_checking/commodity_network.py | 20 +++++++++---------- .../commodity_network_manager.py | 2 +- temoa/model_checking/network_model_data.py | 3 +-- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/temoa/model_checking/commodity_network.py b/temoa/model_checking/commodity_network.py index eace39a68..afb8771ec 100644 --- a/temoa/model_checking/commodity_network.py +++ b/temoa/model_checking/commodity_network.py @@ -19,7 +19,7 @@ from logging import getLogger from temoa.model_checking.network_model_data import NetworkModelData, TechTuple -from temoa.types.core_types import Commodity, Technology +from temoa.types.core_types import Commodity, Period, Region, Technology logger = getLogger(__name__) @@ -42,7 +42,7 @@ class CommodityNetwork: findings across available vintages. """ - def __init__(self, region: str, period: int, model_data: NetworkModelData) -> None: + def __init__(self, region: Region, period: Period, model_data: NetworkModelData) -> None: """ Initializes and builds the network for a given region and period. @@ -75,10 +75,10 @@ def __init__(self, region: str, period: int, model_data: NetworkModelData) -> No self.other_orphans: set[TechConnection] = set() # Internal state for the analysis - self.tech_inputs: dict[str, set[str]] = defaultdict(set) - self.tech_outputs: dict[str, set[str]] = defaultdict(set) + self.tech_inputs: dict[Technology, set[Commodity]] = defaultdict(set) + self.tech_outputs: dict[Technology, set[Commodity]] = defaultdict(set) self.connections: ForwardConnections = defaultdict(set) - self.viable_linked_tech: set[tuple[str, str]] = set() + self.viable_linked_tech: set[TechLink] = set() self._load_connections() self.prescreen_linked_tech() @@ -110,7 +110,7 @@ def reload(self, connections: set[TechTuple]) -> None: self.viable_linked_tech.clear() self._load_connections() - def remove_tech_by_name(self, tech_name: str) -> None: + def remove_tech_by_name(self, tech_name: Technology) -> None: """Remove all connections associated with a given technology name.""" self.tech_inputs.pop(tech_name, None) self.tech_outputs.pop(tech_name, None) @@ -229,10 +229,10 @@ def analyze_network(self) -> None: def _trace_backward_from_demands( self, - start_nodes: set[str], - end_nodes: set[str], + start_nodes: set[Commodity], + end_nodes: set[Commodity], connections: ForwardConnections, - ) -> tuple[set[str], ReverseConnections]: + ) -> tuple[set[Commodity], ReverseConnections]: """Iterative DFS tracing backward from demand nodes.""" stack = list(start_nodes) visited_nodes = set() @@ -255,7 +255,7 @@ def _trace_backward_from_demands( return discovered_sources, reachable_subgraph def _trace_forward_from_sources( - self, start_nodes: set[str], connections: ReverseConnections + self, start_nodes: set[Commodity], connections: ReverseConnections ) -> set[TechConnection]: """Iterative DFS tracing forward from discovered source nodes.""" stack = list(start_nodes) diff --git a/temoa/model_checking/commodity_network_manager.py b/temoa/model_checking/commodity_network_manager.py index 398851026..e6bed73a2 100644 --- a/temoa/model_checking/commodity_network_manager.py +++ b/temoa/model_checking/commodity_network_manager.py @@ -37,7 +37,7 @@ def __init__(self, periods: Iterable[str | int], network_data: NetworkModelData) self.periods: list[int] = sorted(map(int, periods)) self.orig_data: NetworkModelData = network_data self.filtered_data: NetworkModelData | None = None - self.regions: set[str] | None = None + self.regions: set[Region] | None = None # Store a deep copy of the original connections for graphing purposes self.orig_tech = {k: v.copy() for k, v in network_data.available_techs.items()} diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index 50e75050b..5653e980c 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -17,7 +17,6 @@ import deprecated from pyomo.core.base import ConcreteModel -from pyomo.core.base.block import Block from temoa.core.model import TemoaModel from temoa.extensions.myopic.myopic_index import MyopicIndex @@ -43,7 +42,7 @@ class LinkedTechTuple(NamedTuple): type TechAttributeValue = ParameterValue type DbConnection = sqlite3.Connection -type ModelBlock = TemoaModel | ConcreteModel | Block +type ModelBlock = TemoaModel | ConcreteModel class BasicData(TypedDict): From c3fe548f9d16751a71c7214c2589cd079e1989ed Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 22 Oct 2025 21:34:39 -0400 Subject: [PATCH 270/587] simplifying assertion in test_network_build_and_analysis --- tests/test_network_model_data.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/test_network_model_data.py b/tests/test_network_model_data.py index d05df613d..758799a5e 100644 --- a/tests/test_network_model_data.py +++ b/tests/test_network_model_data.py @@ -1,4 +1,3 @@ -from itertools import chain from unittest.mock import MagicMock import pytest @@ -157,7 +156,7 @@ def dispatcher(query: str, *_: object) -> MagicMock: @pytest.mark.parametrize( 'mock_db_connection', test_scenarios, indirect=True, ids=[d['name'] for d in test_scenarios] ) -def test_network_build_and_analysis(mock_db_connection): +def test_network_build_and_analysis(mock_db_connection) -> None: """Tests both data model construction and network analysis in one go.""" conn, expected = mock_db_connection @@ -165,7 +164,9 @@ def test_network_build_and_analysis(mock_db_connection): network_data = network_model_data._build_from_db(conn) # --- 2. Test initial data loading --- - assert len(tuple(chain(*network_data.demand_commodities.values()))) == expected['demands_count'] + assert ( + sum(len(s) for s in network_data.demand_commodities.values()) == expected['demands_count'] + ) assert len(network_data.available_techs[('R1', 2020)]) == expected['techs_count'] # --- 3. Perform network analysis --- From 0471da934f08d820ada1a8e80d3df82b291db80f Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 23 Oct 2025 13:33:22 -0400 Subject: [PATCH 271/587] correcting import in mga_sequencer to reflect change in pyomo api --- .../modeling_to_generate_alternatives/mga_sequencer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py index 3566fd5b0..1d37e8157 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py +++ b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py @@ -39,7 +39,7 @@ from queue import Empty import pyomo.environ as pyo -from pyomo.contrib.solver.results import Results +from pyomo.contrib.solver.common.results import Results from pyomo.dataportal import DataPortal from pyomo.opt import check_optimal_termination From de88d210704849d3acbac5443157e22655f998f2 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 22 Oct 2025 21:41:50 -0400 Subject: [PATCH 272/587] caching regex in filter_elements --- temoa/model_checking/element_checker.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/temoa/model_checking/element_checker.py b/temoa/model_checking/element_checker.py index 21f6e759b..6551ad838 100644 --- a/temoa/model_checking/element_checker.py +++ b/temoa/model_checking/element_checker.py @@ -64,6 +64,8 @@ def __init__( self._exception_loc: int | None = None self._exceptions: frozenset[str] = frozenset() self.non_excepted_items: set[ValidationElement] | None = set() + # Cache for compiled regex patterns + self._compiled_val_exceptions: list[re.Pattern[str]] = [] if exception_loc is not None and exception_vals is not None: self.set_val_exceptions(exception_loc, exception_vals) @@ -126,6 +128,7 @@ def set_val_exceptions(self, exception_loc: int, exception_vals: Iterable[str]) self._exception_loc = exception_loc # Use a frozenset for immutability and performance self._exceptions = frozenset(exception_vals) + self._compiled_val_exceptions = [re.compile(p) for p in self._exceptions] self._update_internals() return self @@ -193,7 +196,10 @@ def filter_elements( 'The number of value_locations must match the dimensionality of the validation set.' ) - exception_regexes = [re.compile(p) for p in validation.val_exceptions] + # Use the cached compiled regexes. Fall back to compiling for backward compatibility. + exception_regexes = getattr( + validation, '_compiled_val_exceptions', [re.compile(p) for p in validation.val_exceptions] + ) # Pre-build itemgetters for performance full_element_getter = itemgetter(*value_locations) From b16451a13a63d12368e5109e01e79ea7fbc09a9f Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 28 Oct 2025 09:49:51 -0400 Subject: [PATCH 273/587] Adding templates for in house network visualization --- .../network_vis_templates/graph_script.js | 260 ++++++++++++++++++ .../network_vis_templates/graph_styles.css | 29 ++ .../network_vis_templates/graph_template.html | 55 ++++ 3 files changed, 344 insertions(+) create mode 100644 temoa/utilities/network_vis_templates/graph_script.js create mode 100644 temoa/utilities/network_vis_templates/graph_styles.css create mode 100644 temoa/utilities/network_vis_templates/graph_template.html diff --git a/temoa/utilities/network_vis_templates/graph_script.js b/temoa/utilities/network_vis_templates/graph_script.js new file mode 100644 index 000000000..78e77b915 --- /dev/null +++ b/temoa/utilities/network_vis_templates/graph_script.js @@ -0,0 +1,260 @@ +document.addEventListener('DOMContentLoaded', function () { + // --- Master Datasets (Read embedded JSON safely) --- + let data = null; + const dataEl = document.getElementById('graph-data'); + if (dataEl && dataEl.textContent) { + try { + data = JSON.parse(dataEl.textContent); + } catch (e) { + console.error('Failed to parse graph data JSON:', e); + } + } + + // If data failed to load, stop immediately to prevent further errors. + if (!data) { + console.error('Could not find or parse GRAPH_DATA. Halting script.'); + return; + } + + const { + nodes_json_primary: allNodesPrimary, + edges_json_primary: allEdgesPrimary, + nodes_json_secondary: allNodesSecondary, + edges_json_secondary: allEdgesSecondary, + options_json_str: optionsRaw, + sectors_json_str: allSectors, + color_legend_json_str: colorLegendData, + style_legend_json_str: styleLegendData, + primary_view_name: primaryViewName, + secondary_view_name: secondaryViewName, + } = data; + const optionsObject = (typeof optionsRaw === 'string') ? JSON.parse(optionsRaw) : optionsRaw; + // --- State --- + let currentView = 'primary'; + let primaryViewPositions = null; + let secondaryViewPositions = null; + + // --- DOM Elements --- + const configWrapper = document.getElementById('config-panel-wrapper'); + const configHeader = document.querySelector('.config-panel-header'); + const configToggleButton = document.querySelector('.config-toggle-btn'); + const advancedControlsToggle = document.getElementById('advanced-controls-toggle'); + const visConfigContainer = document.getElementById('vis-config-container'); + const searchInput = document.getElementById('search-input'); + const resetButton = document.getElementById('reset-view-btn'); + const sectorTogglesContainer = document.getElementById('sector-toggles'); + const viewToggleButton = document.getElementById('view-toggle-btn'); + const graphContainer = document.getElementById('mynetwork'); + + // --- Config Panel Toggle --- + if (optionsObject.configure && optionsObject.configure.enabled) { + optionsObject.configure.container = visConfigContainer; + configHeader.addEventListener('click', () => { + const isCollapsed = configWrapper.classList.toggle('collapsed'); + configToggleButton.setAttribute('aria-expanded', !isCollapsed); + }); + advancedControlsToggle.addEventListener('click', function(e) { + e.preventDefault(); + const isHidden = visConfigContainer.style.display === 'none'; + visConfigContainer.style.display = isHidden ? 'block' : 'none'; + this.textContent = isHidden ? 'Hide Advanced Physics Controls' : 'Show Advanced Physics Controls'; + }); + } + + // --- Vis.js Network Initialization --- + const nodes = new vis.DataSet(allNodesPrimary); + const edges = new vis.DataSet(allEdgesPrimary); + const network = new vis.Network(graphContainer, { nodes, edges }, optionsObject); + + // --- Core Functions --- + function applyPositions(positions) { + if (!positions) return; + const updates = Object.keys(positions).map(nodeId => ({ + id: nodeId, x: positions[nodeId].x, y: positions[nodeId].y, + })); + if (updates.length > 0) nodes.update(updates); + } + + function switchView() { + if (currentView === 'primary') { + primaryViewPositions = network.getPositions(); + } else { + secondaryViewPositions = network.getPositions(); + } + nodes.clear(); edges.clear(); + + if (currentView === 'primary') { + nodes.add(allNodesSecondary); edges.add(allEdgesSecondary); + currentView = 'secondary'; + viewToggleButton.textContent = `Switch to ${primaryViewName}`; + viewToggleButton.setAttribute('aria-pressed', 'true'); + applyPositions(secondaryViewPositions); + } else { + nodes.add(allNodesPrimary); edges.add(allEdgesPrimary); + currentView = 'primary'; + viewToggleButton.textContent = `Switch to ${secondaryViewName}`; + viewToggleButton.setAttribute('aria-pressed', 'false'); + applyPositions(primaryViewPositions); + } + applyAllFilters(); + network.fit(); + } + + function applyAllFilters() { + // Preserve current positions so filtering doesn't reset layout + const currentPositions = network.getPositions(); + const checkedSectors = new Set(Array.from(sectorTogglesContainer.querySelectorAll('input:checked')).map(c => c.value)); + const searchQuery = searchInput.value; + let regex = null; + if (searchQuery) { + try { regex = new RegExp(searchQuery, 'i'); } catch (e) { console.error("Invalid Regex:", e); return; } + } + const activeNodesData = (currentView === 'primary') ? allNodesPrimary : allNodesSecondary; + const activeEdgesData = (currentView === 'primary') ? allEdgesPrimary : allEdgesSecondary; + const sectorFilteredNodes = activeNodesData.filter(node => { + let match = node.group === null || node.group === undefined || checkedSectors.has(node.group); + if (currentView === 'primary' && node.alwaysVisible === true) { + match = true; + } + return match; + }); + let visibleNodes, visibleEdges; + if (regex) { + const seedNodes = sectorFilteredNodes.filter(node => regex.test(node.label || node.id)); + const seedNodeIds = new Set(seedNodes.map(n => n.id)); + const nodesToShowIds = new Set(seedNodeIds); + activeEdgesData.forEach(edge => { + if (seedNodeIds.has(edge.from)) nodesToShowIds.add(edge.to); + if (seedNodeIds.has(edge.to)) nodesToShowIds.add(edge.from); + }); + visibleNodes = activeNodesData.filter(node => nodesToShowIds.has(node.id)); + visibleEdges = activeEdgesData.filter(edge => nodesToShowIds.has(edge.from) && nodesToShowIds.has(edge.to)); + } else { + visibleNodes = sectorFilteredNodes; + const visibleNodeIds = new Set(visibleNodes.map(n => n.id)); + visibleEdges = activeEdgesData.filter(edge => visibleNodeIds.has(edge.from) && visibleNodeIds.has(edge.to)); + } + nodes.clear(); edges.clear(); + nodes.add(visibleNodes); edges.add(visibleEdges); + applyPositions(currentPositions); + } + + function createStyleLegend() { + const container = document.getElementById('style-legend-container'); + if (!container || !styleLegendData || styleLegendData.length === 0) return; + styleLegendData.forEach(itemData => { + const item = document.createElement('div'); + item.className = 'legend-item'; + const swatch = document.createElement('div'); + swatch.className = 'legend-color-swatch'; + if (itemData.borderColor) swatch.style.borderColor = itemData.borderColor; + if (itemData.borderWidth) swatch.style.borderWidth = itemData.borderWidth + 'px'; + const label = document.createElement('span'); + label.className = 'legend-label'; + label.textContent = itemData.label; + item.append(swatch, label); + container.appendChild(item); + }); + } + + function createSectorLegend() { + const container = document.getElementById('legend-container'); + if (!container || !colorLegendData || Object.keys(colorLegendData).length === 0) return; + Object.keys(colorLegendData).sort().forEach(key => { + const item = document.createElement('div'); + item.className = 'legend-item'; + const swatch = document.createElement('div'); + swatch.className = 'legend-color-swatch'; + swatch.style.backgroundColor = colorLegendData[key]; + const label = document.createElement('span'); + label.className = 'legend-label'; + label.textContent = key; + item.append(swatch, label); + container.appendChild(item); + }); + } + + function createSectorToggles() { + if (!allSectors || allSectors.length === 0) { + sectorTogglesContainer.style.display = 'none'; + return; + } + allSectors.forEach(sector => { + const item = document.createElement('div'); + item.className = 'sector-toggle-item'; + const checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + checkbox.id = `toggle-${sector}`; + checkbox.value = sector; + checkbox.checked = true; + checkbox.addEventListener('change', applyAllFilters); + const swatch = document.createElement('div'); + swatch.className = 'toggle-color-swatch'; + swatch.style.backgroundColor = colorLegendData[sector] || '#ccc'; + const label = document.createElement('label'); + label.htmlFor = checkbox.id; + label.textContent = sector; + item.append(swatch, checkbox, label); + item.addEventListener('click', e => { + if (e.target.tagName === 'INPUT') return; + e.preventDefault(); + checkbox.checked = !checkbox.checked; + checkbox.dispatchEvent(new Event('change', { bubbles: true })); + }); + sectorTogglesContainer.appendChild(item); + }); + } + + function resetView() { + searchInput.value = ""; + primaryViewPositions = null; + secondaryViewPositions = null; + if (currentView !== 'primary') { + switchView(); // This will switch back to primary and apply null positions + } else { + // If already on primary, just reload the original data + nodes.clear(); edges.clear(); + nodes.add(allNodesPrimary); edges.add(allEdgesPrimary); + applyPositions(primaryViewPositions); // Apply null to reset + network.fit(); + } + sectorTogglesContainer.querySelectorAll('input[type=checkbox]').forEach(c => c.checked = true); + applyAllFilters(); + } + + function showNeighborhood(nodeId) { + const activeNodes = (currentView === 'primary') ? allNodesPrimary : allNodesSecondary; + const activeEdges = (currentView === 'primary') ? allEdgesPrimary : allEdgesSecondary; + searchInput.value = ""; + const nodesToShow = new Set([nodeId]); + activeEdges.forEach(edge => { + if (edge.from === nodeId) nodesToShow.add(edge.to); + else if (edge.to === nodeId) nodesToShow.add(edge.from); + }); + const filteredNodes = activeNodes.filter(node => nodesToShow.has(node.id)); + const filteredEdges = activeEdges.filter(edge => nodesToShow.has(edge.from) && nodesToShow.has(edge.to)); + nodes.clear(); edges.clear(); + nodes.add(filteredNodes); + edges.add(filteredEdges); + network.fit(); + } + + // --- Event Listeners & Initial Setup --- + if (allNodesSecondary && allNodesSecondary.length > 0) { + viewToggleButton.textContent = `Switch to ${secondaryViewName}`; + viewToggleButton.addEventListener('click', switchView); + } else { + document.getElementById('view-toggle-panel').style.display = 'none'; + } + resetButton.addEventListener('click', resetView); + searchInput.addEventListener('input', applyAllFilters); + network.on("doubleClick", params => { + if (params.nodes.length > 0) { + showNeighborhood(params.nodes[0]); + } + }); + + createStyleLegend(); + createSectorLegend(); + createSectorToggles(); +}); diff --git a/temoa/utilities/network_vis_templates/graph_styles.css b/temoa/utilities/network_vis_templates/graph_styles.css new file mode 100644 index 000000000..0402c090e --- /dev/null +++ b/temoa/utilities/network_vis_templates/graph_styles.css @@ -0,0 +1,29 @@ +body, html { + margin: 0; padding: 0; width: 100%; height: 100%; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + background-color: #f4f6f8; display: flex; flex-direction: column; overflow: hidden; +} +.config-panel-wrapper { width: 100%; background-color: #ffffff; box-shadow: 0 2px 4px rgba(0,0,0,0.1); z-index: 10; flex-shrink: 0; } +.config-panel-header { display: flex; justify-content: space-between; align-items: center; padding: 10px 15px; border-bottom: 1px solid #e0e0e0; cursor: pointer; background-color: #f9f9f9; } +.config-panel-header h3 { margin: 0; font-size: 16px; font-weight: 600; } +.config-toggle-btn::after { content: '\25BC'; display: inline-block; transition: transform 0.2s ease-in-out; } +.collapsed .config-toggle-btn::after { transform: rotate(-90deg); } +#config-container-content { max-height: 40vh; overflow-y: auto; padding: 15px; box-sizing: border-box; background-color: #ffffff; transition: max-height 0.3s ease-in-out, padding 0.3s ease-in-out; } +.collapsed #config-container-content { max-height: 0; padding-top: 0; padding-bottom: 0; overflow: hidden; } +#mynetwork { width: 100%; flex-grow: 1; min-height: 0; } +.filter-panel { display: flex; align-items: center; gap: 10px; padding: 8px 15px; background-color: #e9ecef; border-bottom: 1px solid #dee2e6; } +.filter-panel input[type=text] { flex-grow: 1; padding: 6px 8px; border: 1px solid #ced4da; border-radius: 4px; } +.filter-panel button { padding: 6px 12px; border-radius: 4px; border: 1px solid #6c757d; background-color: #6c757d; color: white; cursor: pointer; } +.info-panel { padding: 8px 15px; background-color: #f8f9fa; font-size: 13px; text-align: center; border-bottom: 1px solid #dee2e6; } +.sector-toggles { padding: 10px 15px; background-color: #f8f9fa; border-bottom: 1px solid #dee2e6; display: flex; flex-wrap: wrap; gap: 10px; align-items: center; } +.sector-toggles-title { font-weight: 600; } +.sector-toggle-item { display: flex; align-items: center; gap: 8px; padding: 5px 10px; border: 1px solid #ccc; border-radius: 16px; background-color: #fff; cursor: pointer; user-select: none; } +.toggle-color-swatch { width: 14px; height: 14px; border-radius: 50%; } +.legend-section { margin-bottom: 15px; } +.legend-section h4 { margin-top: 0; margin-bottom: 10px; font-size: 14px; font-weight: 600; } +.legend-container { display: flex; flex-wrap: wrap; gap: 15px; } +.legend-item { display: flex; align-items: center; margin-bottom: 6px; } +.legend-color-swatch { width: 18px; height: 18px; margin-right: 8px; flex-shrink: 0; border: 1px solid #ccc; background-color: #f0f0f0; box-sizing: border-box; } +.legend-label { font-size: 13px; } +#advanced-controls-toggle { font-size: 12px; color: #007bff; cursor: pointer; text-decoration: none; margin-top: 15px; display: block; } +.view-toggle-panel { padding: 8px 15px; background-color: #343a40; color: white; display: flex; justify-content: center; align-items: center; } +.view-toggle-panel button { font-size: 14px; font-weight: 600; padding: 8px 16px; border-radius: 5px; border: 1px solid #6c757d; background-color: #495057; color: white; cursor: pointer; } diff --git a/temoa/utilities/network_vis_templates/graph_template.html b/temoa/utilities/network_vis_templates/graph_template.html new file mode 100644 index 000000000..8ec0a1f08 --- /dev/null +++ b/temoa/utilities/network_vis_templates/graph_template.html @@ -0,0 +1,55 @@ + + + + + + + __HTML_PAGE_TITLE__ + + + + + +
+
+

Configuration & Legend

+ +
+
+
+

Style Legend

+
+
+
+

Sector Legend

+
+
+ Show Advanced Physics Controls + +
+
+
+ +
+
+ Filter Sectors: +
+
+ + + +
+
+ Tip: Double-click a node to isolate. Single-click to select. Use 'Reset View' to clear. +
+
+ + + + + + + From 6c9d1e872f6a36d2b2075e6cf59dae4347240963 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 28 Oct 2025 09:51:31 -0400 Subject: [PATCH 274/587] generic graph creation and visualization framework --- temoa/utilities/graph_utils.py | 243 ++++++++++++++++++++++++++ temoa/utilities/visualizer.py | 305 +++++++++++++++++++++++++++++++++ 2 files changed, 548 insertions(+) create mode 100644 temoa/utilities/graph_utils.py create mode 100644 temoa/utilities/visualizer.py diff --git a/temoa/utilities/graph_utils.py b/temoa/utilities/graph_utils.py new file mode 100644 index 000000000..37ec3718a --- /dev/null +++ b/temoa/utilities/graph_utils.py @@ -0,0 +1,243 @@ +# temoa/utilities/graph_utils.py +""" +Utility functions for calculating node positions for network graphs. + +These functions provide deterministic starting positions for nodes based on +their layer (role) and sector, which helps the physics-based layout engine +in vis.js converge to a cleaner and more readable state faster. +""" + +import json +import logging +import math +import random +import uuid +from collections.abc import Iterable +from typing import Any, TypeVar + +import networkx as nx + +from temoa.model_checking.network_model_data import EdgeTuple + +logger = logging.getLogger(__name__) + +GraphType = TypeVar('GraphType', nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph) + + +def convert_graph_to_json( + nx_graph: GraphType, + override_node_properties: dict[str, Any] | None, + override_edge_properties: dict[str, Any] | None, + verbosity: int, +) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]: + """Helper to convert a single NetworkX graph to JSON-serializable lists.""" + nodes_data: list[dict[str, Any]] = [] + node_ids_map: dict[Any, str] = {} + + for node_obj, attrs in nx_graph.nodes(data=True): + node_id_str = str(node_obj) + node_ids_map[node_obj] = node_id_str + node_entry: dict[str, Any] = {'id': node_id_str} + if 'label' not in attrs: + node_entry['label'] = node_id_str + for key, value in attrs.items(): + try: + # Test if the value is JSON serializable + json.dumps(value) + node_entry[key] = value + except (TypeError, OverflowError): + # If not, fall back to a string representation + if verbosity >= 2: + logger.debug( + "Node %s attr '%s' not JSON serializable, converting to string.", + node_id_str, + key, + ) + node_entry[key] = str(value) + if override_node_properties: + node_entry.update({k: v for k, v in override_node_properties.items() if k != 'id'}) + nodes_data.append(node_entry) + + edges_data: list[dict[str, Any]] = [] + for u_obj, v_obj, attrs in nx_graph.edges(data=True): + edge_entry: dict[str, Any] = { + 'from': node_ids_map[u_obj], + 'to': node_ids_map[v_obj], + } + if 'id' not in attrs and nx_graph.is_multigraph(): + edge_entry['id'] = str(uuid.uuid4()) + for key, value in attrs.items(): + try: + # Test if the value is JSON serializable + json.dumps(value) + edge_entry[key] = value + except (TypeError, OverflowError): + # If not, fall back to a string representation + if verbosity >= 2: + logger.debug( + "Edge (%s-%s) attr '%s' not JSON serializable, converting to string.", + u_obj, + v_obj, + key, + ) + edge_entry[key] = str(value) + if override_edge_properties: + edge_entry.update( + {k: v for k, v in override_edge_properties.items() if k not in {'id', 'from', 'to'}} + ) + + edges_data.append(edge_entry) + + return nodes_data, edges_data + + +def calculate_source_positions( + node_layer_map: dict[str, int], + x_pos: int = 0, + y_separation: int = 500, +) -> dict[str, dict[str, Any]]: + """ + Calculates fixed (x, y) positions for SOURCE nodes (Layer 1) only. + + Args: + node_layer_map: Mapping from commodity name to layer ID (1, 2, or 3). + x_pos: The fixed horizontal coordinate for all source nodes. + y_separation: The vertical distance between source nodes. + + Returns: + A dictionary mapping only source node names to their position attributes. + e.g., {'SourceA': {'x': 0, 'y': 0, 'fixed': True}} + """ + positions = {} + # Filter for source nodes (layer 1) and sort them for consistent layout + source_nodes = sorted([node for node, layer in node_layer_map.items() if layer == 1]) + + if not source_nodes: + return {} + + # Calculate a starting y-offset to center the group vertically + num_nodes = len(source_nodes) + start_y = -((num_nodes - 1) * y_separation) / 2 + + for i, node_name in enumerate(source_nodes): + y_pos = start_y + i * y_separation + # Set fixed position only for these source nodes + positions[node_name] = {'x': x_pos, 'y': y_pos, 'fixed': True} + + return positions + + +def calculate_initial_positions( + node_layer_map: dict[str, int], + commodity_to_primary_sector: dict[str, str], + unique_sectors: list[str], +) -> dict[str, dict[str, Any]]: + """ + Calculates an initial (x, y) layout for all nodes to provide a better + starting point for the physics engine. + + - Source nodes (Layer 1) are fixed on the left. + - Other nodes are arranged in clusters based on their primary sector, + with the clusters themselves arranged in a large circle. + """ + positions = {} + + # Prepare to lay out the remaining (non-fixed) nodes: all layers except 1 + nodes_to_place = {n for n, layer in node_layer_map.items() if layer != 1} + if not nodes_to_place: + return positions + + # Use provided unique_sectors if available; else derive from mapping + sectors_to_place = ( + sorted(unique_sectors) + if unique_sectors + else sorted({s for c, s in commodity_to_primary_sector.items() if c in nodes_to_place}) + ) + # ------------------------------------ + + if not sectors_to_place: + return positions + + # Arrange sector "anchors" in a large circle + layout_radius = 2000 # The radius of the main circle for sectors + jitter_radius = 1000 # How far nodes can be from their sector anchor + sector_anchors = {} + num_sectors = len(sectors_to_place) + + for i, sector in enumerate(sectors_to_place): + angle = (i / num_sectors) * 2 * math.pi + cx = layout_radius * math.cos(angle) + cy = layout_radius * math.sin(angle) + sector_anchors[sector] = (cx, cy) + + # Place each remaining node near its sector's anchor point + for node_name in nodes_to_place: + primary_sector = commodity_to_primary_sector.get(node_name) + if not primary_sector or primary_sector not in sector_anchors: + # Place nodes without a sector or a new sector at the center + cx, cy = 0, 0 + else: + cx, cy = sector_anchors[primary_sector] + + # Stable jitter derived from node name + seed = uuid.uuid5(uuid.NAMESPACE_DNS, node_name).int + rand_angle = ((seed % 3600) / 3600.0) * 2 * math.pi + rand_radius = (seed // 3600) % jitter_radius + x = cx + rand_radius * math.cos(rand_angle) + y = cy + rand_radius * math.sin(rand_angle) + + # Add the position but DO NOT set 'fixed: True' + positions[node_name] = {'x': x, 'y': y} + + return positions + + +def calculate_tech_graph_positions( + all_edges: Iterable[EdgeTuple], +) -> dict[str, dict[str, Any]]: + """ + Calculates an initial (x, y) layout for the technology graph. + All technologies are arranged in clusters by sector, with clusters + arranged in a large circle. No nodes are fixed. + """ + positions = {} + + # 1. Identify all unique sectors present in the technology list + sectors_to_place = sorted({tech.sector for tech in all_edges if tech.sector}) + + if not sectors_to_place: + # If no sectors, just return empty positions and let physics handle it + return {} + + # 2. Arrange sector "anchors" in a large circle + layout_radius = 2500 # Use a large radius to ensure initial separation + jitter_radius = 600 # Controls the size of the initial clusters + sector_anchors = {} + num_sectors = len(sectors_to_place) + + for i, sector in enumerate(sectors_to_place): + angle = (i / num_sectors) * 2 * math.pi + cx = layout_radius * math.cos(angle) + cy = layout_radius * math.sin(angle) + sector_anchors[sector] = (cx, cy) + + # 3. Place each technology node near its sector's anchor point with jitter + for edge_tuple in all_edges: + primary_sector = edge_tuple.sector + if not primary_sector or primary_sector not in sector_anchors: + # Place nodes without a defined sector at the center + cx, cy = 0, 0 + else: + cx, cy = sector_anchors[primary_sector] + + # Apply deterministic "jitter" to prevent stacking (stable per-tech) + seed = uuid.uuid5(uuid.NAMESPACE_DNS, str(edge_tuple.tech)).int + rng = random.Random(seed) + rand_angle = rng.uniform(0, 2 * math.pi) + rand_radius = rng.uniform(0, jitter_radius) + x = cx + rand_radius * math.cos(rand_angle) + y = cy + rand_radius * math.sin(rand_angle) + + positions[edge_tuple.tech] = {'x': x, 'y': y} + + return positions diff --git a/temoa/utilities/visualizer.py b/temoa/utilities/visualizer.py new file mode 100644 index 000000000..04da87dce --- /dev/null +++ b/temoa/utilities/visualizer.py @@ -0,0 +1,305 @@ +# temoa/utilities/visualizer.py +""" +Tools for converting NetworkX graphs to interactive vis.js visualizations. + +This module provides the `nx_to_vis` function which takes one or two +NetworkX graphs and generates a self-contained HTML file for exploration. +It includes features for toggling between views, filtering by sector or node +name, and an interactive configuration panel. + +This code is designed to replace previous graphing dependencies like `gravis`. +""" + +import copy +import json +import logging +import uuid +from collections import defaultdict +from collections.abc import Iterable +from pathlib import Path +from typing import Any + +import networkx as nx + +from temoa.utilities.graph_utils import ( + GraphType, + convert_graph_to_json, +) + +logger = logging.getLogger(__name__) + + +def deep_merge_dicts(source: dict[str, Any], destination: dict[str, Any]) -> dict[str, Any]: + """Deep merge two dictionaries.""" + for key, source_value in source.items(): + dest_value = destination.get(key) + if isinstance(source_value, dict) and isinstance(dest_value, dict): + deep_merge_dicts(source_value, dest_value) + else: + destination[key] = source_value + return destination + + +def make_nx_graph( + connections: Iterable[tuple[str, str, str, str | None]], + edge_attributes_map: dict[tuple, dict[str, Any]], + node_layer_map: dict[str, int], + node_positions: dict[str, dict[str, Any]], + commodity_to_primary_sector: dict[str, str], + driven_tech_names: set[str], + other_orphan_names: set[str], + demand_orphan_names: set[str], + driven_commodities: set[str], + other_orphan_commodities: set[str], + demand_orphan_commodities: set[str], +) -> nx.MultiDiGraph: + """ + Make an nx graph, grouping parallel edges to prevent label overlap. + """ + + dg = nx.MultiDiGraph() + connections = tuple(connections) # Freeze for multiple iterations + + node_styles_by_layer = { + 1: {'size': 25, 'shape': 'ellipse'}, + 2: {'size': 15, 'shape': 'dot'}, + 3: {'size': 20, 'shape': 'box'}, + } + default_node_style = {'size': 15, 'shape': 'dot'} + + # 1. Add all nodes first to ensure they exist before adding edges + all_nodes_in_connections = {c[0] for c in connections} | {c[2] for c in connections} + for node_name in sorted(all_nodes_in_connections): # Sort for consistency + if node_name in dg: + continue + layer = node_layer_map.get(node_name, 2) + style = node_styles_by_layer.get(layer, default_node_style) + pos_attrs = node_positions.get(node_name, {}) + group_name = commodity_to_primary_sector.get(node_name) + + # Start with the base attributes for the node. + node_attrs: dict[str, Any] = { + 'label': node_name, + 'title': f'Commodity: {node_name}\nLayer: {layer}\nSector: {group_name or "N/A"}', + 'group': group_name, + 'size': style.get('size'), + 'shape': style.get('shape'), + 'borderWidth': 2, # Default + 'color': {}, # Initialize the color object + **pos_attrs, + } + + # Now, conditionally modify the attributes + color_obj = node_attrs['color'] + + # Set background color and alwaysVisible flag based on layer + if layer == 1: + color_obj['background'] = '#2ca02c' + node_attrs['alwaysVisible'] = True # Now this is safe to do + elif layer == 3: + color_obj['background'] = '#78facf' + + # Set border color based on special status + if node_name in demand_orphan_commodities: + color_obj['border'] = '#d62728' + node_attrs['borderWidth'] = 4 + elif node_name in other_orphan_commodities: + color_obj['border'] = '#ff7f0e' + node_attrs['borderWidth'] = 4 + elif node_name in driven_commodities: + color_obj['border'] = '#1f77b4' + node_attrs['borderWidth'] = 4 + + # Add shadow and update title for highlighted nodes + if node_attrs['borderWidth'] > 2: + node_attrs['shadow'] = {'enabled': True, 'color': 'rgba(0,0,0,0.5)', 'x': 2, 'y': 2} + status = 'Unknown' + if node_name in demand_orphan_commodities: + status = 'Connected to Demand Orphan' + elif node_name in other_orphan_commodities: + status = 'Connected to Other Orphan' + elif node_name in driven_commodities: + status = 'Connected to Driven Tech' + node_attrs['title'] += f'\nStatus: {status}' + + dg.add_node(node_name, **node_attrs) + + # 2. Group technologies by their input/output commodity pair + grouped_edges = defaultdict(list) + for ic, tech, oc, sector in connections: + edge_key = (ic, tech, oc, sector) + attrs = edge_attributes_map.get(edge_key, {}) + grouped_edges[(ic, oc)].append({'tech': tech, 'sector': sector, 'attrs': attrs}) + + # 3. Create a single, combined edge for each group + for (ic, oc), techs_info in grouped_edges.items(): + combined_attrs = {} + tech_names = [info['tech'] for info in techs_info] + + # Combine labels: Show up to 2 names, then "X techs" + if len(tech_names) <= 2: + combined_attrs['label'] = ', '.join(tech_names) + else: + combined_attrs['label'] = f'{len(tech_names)} technologies' + + # Combine tooltips (titles) to list all techs + tooltip_lines = [] + # Sort by tech name for a consistent order in the tooltip + for info in sorted(techs_info, key=lambda x: x['tech']): + tech_name = info['tech'] + sector_name = info.get('sector', 'N/A') + + tech_type_info = '' + if tech_name in demand_orphan_names: + tech_type_info = ' [Demand Orphan]' + elif tech_name in other_orphan_names: + tech_type_info = ' [Other Orphan]' + elif tech_name in driven_tech_names: + tech_type_info = ' [Driven Tech]' + + tooltip_lines.append(f'- {tech_name} (Sector: {sector_name}){tech_type_info}') + + combined_attrs['title'] = f'Technologies ({ic} → {oc}):\n' + '\n'.join(tooltip_lines) + + # Combine visual properties + all_sectors = {info['sector'] for info in techs_info if info['sector']} + if len(all_sectors) > 1: + combined_attrs['color'] = '#888888' + elif len(all_sectors) == 1: + # Find a tech that actually has the sector + tech_with_sector = next((info for info in techs_info if info['sector']), techs_info[0]) + combined_attrs['color'] = tech_with_sector['attrs'].get('color', '#888888') + + # If any underlying edge is dashed, the combined edge is dashed. + if any(info['attrs'].get('dashes', False) for info in techs_info): + combined_attrs['dashes'] = True + + combined_attrs['value'] = sum(info['attrs'].get('value', 1) for info in techs_info) + edge_key = f'{ic}-{oc}-{uuid.uuid4().hex[:8]}' + dg.add_edge(ic, oc, key=edge_key, **combined_attrs) + + return dg + + +def nx_to_vis( + nx_graph: GraphType, + output_filename: Path, # Changed to Path object for clarity + html_title: str = 'NetworkX to vis.js Graph', + vis_options: dict[str, Any] | None = None, + override_node_properties: dict[str, Any] | None = None, + override_edge_properties: dict[str, Any] | None = None, + sectors: list[str] | None = None, + color_legend_map: dict[str, str] | None = None, + style_legend_map: list[dict[str, Any]] | None = None, + secondary_graph: GraphType | None = None, + primary_view_name: str = 'Commodity View', + secondary_view_name: str = 'Technology View', + *, + show_browser: bool = True, +) -> str | None: + """ + Generates an interactive HTML file and its assets (CSS, JS) for graph visualization. + """ + nodes_data_primary, edges_data_primary = convert_graph_to_json( + nx_graph, override_node_properties, override_edge_properties, 0 + ) + nodes_data_secondary, edges_data_secondary = [], [] + if secondary_graph: + nodes_data_secondary, edges_data_secondary = convert_graph_to_json( + secondary_graph, override_node_properties, override_edge_properties, 0 + ) + + current_options = copy.deepcopy(DEFAULT_VIS_OPTIONS) + if vis_options: + deep_merge_dicts(vis_options, current_options) + + try: + template_dir = Path(__file__).parent / 'network_vis_templates' + html_template = (template_dir / 'graph_template.html').read_text(encoding='utf-8') + css_template = (template_dir / 'graph_styles.css').read_text(encoding='utf-8') + js_template = (template_dir / 'graph_script.js').read_text(encoding='utf-8') + except FileNotFoundError: + logger.exception( + "Template files not found. Ensure the 'network_vis_templates' directory exists next to visualizer.py." + ) + return None + + # Prepare all data for injection into the HTML + graph_data = { + 'nodes_json_primary': nodes_data_primary, + 'edges_json_primary': edges_data_primary, + 'nodes_json_secondary': nodes_data_secondary, + 'edges_json_secondary': edges_data_secondary, + 'options_json_str': current_options, + 'sectors_json_str': sorted(sectors) if sectors else [], + 'color_legend_json_str': color_legend_map or {}, + 'style_legend_json_str': style_legend_map or [], + 'primary_view_name': primary_view_name, + 'secondary_view_name': secondary_view_name, + } + + try: + output_filename.parent.mkdir(parents=True, exist_ok=True) + output_filename.with_name('graph_styles.css').write_text(css_template, encoding='utf-8') + output_filename.with_name('graph_script.js').write_text(js_template, encoding='utf-8') + + html_content = html_template.replace('__HTML_PAGE_TITLE__', html_title).replace( + '__GRAPH_DATA_JSON__', json.dumps(graph_data) + ) + output_filename.write_text(html_content, encoding='utf-8') + abs_path = str(output_filename.resolve()) + except OSError: + logger.exception('Failed to write graph visualization files.') + return None + else: + logger.info('Generated graph HTML at: %s', abs_path) + if show_browser: + import webbrowser + + webbrowser.open('file://' + abs_path) + return abs_path + + +DEFAULT_VIS_OPTIONS = { + 'autoResize': True, + 'nodes': { + 'shape': 'dot', + 'size': 16, + 'font': {'size': 14, 'color': '#333'}, + 'borderWidth': 2, + }, + 'edges': { + 'width': 2, + 'smooth': {'type': 'continuous', 'roundness': 0.5}, + 'arrows': {'to': {'enabled': False, 'scaleFactor': 1}}, + }, + 'physics': { + 'enabled': False, + 'barnesHut': { + 'gravitationalConstant': -15000, + 'springConstant': 0.04, + 'springLength': 200, + 'damping': 0.09, + 'avoidOverlap': 0.1, + }, + 'solver': 'barnesHut', + 'minVelocity': 0.75, + 'timestep': 0.05, + 'stabilization': {'enabled': False}, + }, + 'interaction': { + 'hover': True, + 'dragNodes': True, + 'dragView': True, + 'zoomView': True, + 'tooltipDelay': 200, + 'navigationButtons': False, + 'keyboard': {'enabled': True, 'bindToWindow': False}, + }, + 'layout': {'randomSeed': None, 'improvedLayout': True}, + 'configure': { + 'enabled': True, + 'showButton': False, # We have our own header, so hide the default floating button + 'container': None, # We will set this dynamically in the HTML + }, +} From 7c66f0b7f30d5d9bef87c73872838fd0ea9640b1 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 28 Oct 2025 09:53:30 -0400 Subject: [PATCH 275/587] updating network model data tests for sector handling --- tests/test_network_model_data.py | 205 ++++++++++++++++++++++++++++++- 1 file changed, 199 insertions(+), 6 deletions(-) diff --git a/tests/test_network_model_data.py b/tests/test_network_model_data.py index 758799a5e..197503a61 100644 --- a/tests/test_network_model_data.py +++ b/tests/test_network_model_data.py @@ -1,3 +1,4 @@ +import sqlite3 from unittest.mock import MagicMock import pytest @@ -22,6 +23,7 @@ 'FROM SurvivalCurve': [], 'FROM TimePeriod': [(2020,), (2025,)], # Unique keys for each Commodity query + 'FROM main.Commodity': [('s1',), ('p1',), ('p2',), ('p3',), ('d1',), ('d2',)], "Commodity WHERE flag LIKE '%p%'": [ ('s1',), ('p1',), @@ -32,6 +34,14 @@ ], "Commodity WHERE flag LIKE '%w%'": [], "Commodity WHERE flag = 's'": [('s1',)], + "Commodity WHERE flag LIKE '%p%' OR flag = 's' OR flag LIKE '%a%'": [ + ('s1',), + ('p1',), + ('p2',), + ('p3',), + ('d1',), + ('d2',), + ], 'FROM main.Demand': [('R1', 2020, 'd1'), ('R1', 2020, 'd2')], # Unique keys for Efficiency and optional tables 'FROM main.Efficiency': [ @@ -63,9 +73,16 @@ 'Technology WHERE retire==1': [], 'FROM SurvivalCurve': [], 'FROM TimePeriod': [(2020,), (2025,)], + 'FROM main.Commodity': [('s1',), ('p1',), ('p3',), ('d1',), ('d2',)], "Commodity WHERE flag LIKE '%p%'": [('s1',), ('p3',), ('d1',), ('d2',)], "Commodity WHERE flag LIKE '%w%'": [], "Commodity WHERE flag = 's'": [('s1',)], + "Commodity WHERE flag LIKE '%p%' OR flag = 's' OR flag LIKE '%a%'": [ + ('s1',), + ('p3',), + ('d1',), + ('d2',), + ], 'FROM main.Demand': [('R1', 2020, 'd1'), ('R1', 2020, 'd2')], 'FROM main.Efficiency': [ ('R1', 's1', 't4', 2000, 'p3', 100), @@ -93,9 +110,16 @@ 'Technology WHERE retire==1': [], 'FROM SurvivalCurve': [], 'FROM TimePeriod': [(2020,), (2025,)], + 'FROM main.Commodity': [('s1',), ('p1',), ('d1',), ('d2',), ('s2',)], "Commodity WHERE flag LIKE '%p%'": [('s1',), ('d1',), ('d2',), ('s2',)], "Commodity WHERE flag LIKE '%w%'": [], "Commodity WHERE flag = 's'": [('s1',), ('s2',)], + "Commodity WHERE flag LIKE '%p%' OR flag = 's' OR flag LIKE '%a%'": [ + ('s1',), + ('d1',), + ('d2',), + ('s2',), + ], 'FROM main.Demand': [('R1', 2020, 'd1'), ('R1', 2020, 'd2')], 'FROM main.Efficiency': [ ('R1', 's1', 't4', 2000, 'd2', 100), @@ -138,13 +162,15 @@ def mock_db_connection(request): mock_con.cursor.return_value = mock_cursor def dispatcher(query: str, *_: object) -> MagicMock: - for key, data in db_data.items(): + if 'sector FROM Technology' in query: + raise sqlite3.OperationalError('no such column: sector') + for key, data in sorted(db_data.items(), key=lambda kv: -len(kv[0])): if key in query: - execute_mock = MagicMock(name=f'execute_mock_for_{key}') - execute_mock.fetchall.return_value = data - execute_mock.fetchone.return_value = data[0] if data else None - return execute_mock - raise ValueError(f'Mock database received unexpected query: {query}') + m = MagicMock(name=f'execute_mock_for_{key}') + m.fetchall.return_value = data + m.fetchone.return_value = data[0] if data else None + return m + raise AssertionError('Unexpected SQL: ' + query) mock_cursor.execute.side_effect = dispatcher return mock_con, request.param['expected'] @@ -203,3 +229,170 @@ def test_clone(mock_db_connection): assert network_data.available_techs != clone.available_techs, ( 'Modifying clone should not affect original' ) + + +def test_sector_handling_with_sectors() -> None: + """Test that sectors are properly handled when they exist in the database.""" + # Mock database with sector column + mock_con = MagicMock(name='mock_connection') + mock_cursor = MagicMock(name='mock_cursor') + mock_con.cursor.return_value = mock_cursor + + # Mock the sector column check to return True + sector_check_mock = MagicMock() + sector_check_mock.fetchall.return_value = [('Other',)] + sector_check_mock.fetchone.return_value = ('Other',) + + # Mock efficiency data with sectors + efficiency_mock = MagicMock() + efficiency_mock.fetchall.return_value = [ + ('R1', 's1', 't1', 2000, 'p1', 100, 'supply'), + ('R1', 'p1', 't2', 2000, 'd1', 100, 'demand'), + ] + + def dispatcher(query: str, *_: object) -> MagicMock: + if 'sector FROM Technology' in query: + return sector_check_mock + elif 'FROM main.Efficiency' in query: + return efficiency_mock + elif 'Technology WHERE retire==1' in query: + m = MagicMock() + m.fetchall.return_value = [] + return m + elif 'FROM SurvivalCurve' in query: + m = MagicMock() + m.fetchall.return_value = [] + return m + elif 'FROM TimePeriod' in query: + m = MagicMock() + m.fetchall.return_value = [(2020,), (2025,)] + return m + elif "Commodity WHERE flag LIKE '%p%'" in query: + m = MagicMock() + m.fetchall.return_value = [('s1',), ('p1',), ('d1',)] + return m + elif "Commodity WHERE flag LIKE '%w%'" in query: + m = MagicMock() + m.fetchall.return_value = [] + return m + elif "Commodity WHERE flag = 's'" in query: + m = MagicMock() + m.fetchall.return_value = [('s1',)] + return m + elif 'FROM main.Demand' in query: + m = MagicMock() + m.fetchall.return_value = [('R1', 2020, 'd1')] + return m + elif 'FROM EndOfLifeOutput' in query: + m = MagicMock() + m.fetchall.return_value = [] + return m + elif 'FROM ConstructionInput' in query: + m = MagicMock() + m.fetchall.return_value = [] + return m + elif 'FROM main.LinkedTech' in query: + m = MagicMock() + m.fetchall.return_value = [] + return m + elif 'FROM CostVariable' in query: + m = MagicMock() + m.fetchall.return_value = [] + return m + raise AssertionError('Mock database received unexpected query: ' + query) + + mock_cursor.execute.side_effect = dispatcher + + # Build network data + network_data = network_model_data._build_from_db(mock_con) + + # Verify sectors are included in EfficiencyTuple + techs = list(network_data.available_techs[('R1', 2020)]) + assert len(techs) == 2 + # Fields: region, ic, tech, vintage, oc, lifetime, sector + assert all(len(tech) == 7 for tech in techs) + assert any(tech.sector == 'supply' for tech in techs) + assert any(tech.sector == 'demand' for tech in techs) + + +def test_sector_handling_without_sectors() -> None: + """Test that sectors are handled gracefully when they don't exist in the database.""" + # Mock database without sector column + mock_con = MagicMock(name='mock_connection') + mock_cursor = MagicMock(name='mock_cursor') + mock_con.cursor.return_value = mock_cursor + + # Mock the sector column check to raise OperationalError (column doesn't exist) + def dispatcher(query: str, *_: object) -> MagicMock: + if 'sector FROM Technology' in query: + # Simulate column not existing + raise sqlite3.OperationalError('no such column: sector') + elif 'FROM main.Efficiency' in query: + # Return data without sector column + mock = MagicMock() + mock.fetchall.return_value = [ + ('R1', 's1', 't1', 2000, 'p1', 100), + ('R1', 'p1', 't2', 2000, 'd1', 100), + ] + return mock + elif 'FROM main.Commodity' in query: + m = MagicMock() + m.fetchall.return_value = [('s1',), ('p1',), ('d1',)] + return m + elif 'Technology WHERE retire==1' in query: + m = MagicMock() + m.fetchall.return_value = [] + return m + elif 'FROM SurvivalCurve' in query: + m = MagicMock() + m.fetchall.return_value = [] + return m + elif 'FROM TimePeriod' in query: + m = MagicMock() + m.fetchall.return_value = [(2020,), (2025,)] + return m + elif "Commodity WHERE flag LIKE '%p%'" in query: + m = MagicMock() + m.fetchall.return_value = [('s1',), ('p1',), ('d1',)] + return m + elif "Commodity WHERE flag LIKE '%w%'" in query: + m = MagicMock() + m.fetchall.return_value = [] + return m + elif "Commodity WHERE flag = 's'" in query: + m = MagicMock() + m.fetchall.return_value = [('s1',)] + return m + elif 'FROM main.Demand' in query: + m = MagicMock() + m.fetchall.return_value = [('R1', 2020, 'd1')] + return m + elif 'FROM EndOfLifeOutput' in query: + m = MagicMock() + m.fetchall.return_value = [] + return m + elif 'FROM ConstructionInput' in query: + m = MagicMock() + m.fetchall.return_value = [] + return m + elif 'FROM main.LinkedTech' in query: + m = MagicMock() + m.fetchall.return_value = [] + return m + elif 'FROM CostVariable' in query: + m = MagicMock() + m.fetchall.return_value = [] + return m + raise ValueError(f'Mock database received unexpected query: {query}') + + mock_cursor.execute.side_effect = dispatcher + + # Build network data + network_data = network_model_data._build_from_db(mock_con) + + # Verify sectors default to None + techs = list(network_data.available_techs[('R1', 2020)]) + assert len(techs) == 2 + # Fields: region, ic, tech, vintage, oc, lifetime, sector (sector None here) + assert all(len(tech) == 7 for tech in techs) + assert all(tech.sector is None for tech in techs) From f86ebe79d579aa83e8e9a745da70f2502f2018d1 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 28 Oct 2025 09:54:39 -0400 Subject: [PATCH 276/587] Removing gravis dependency and adapting commodity_graph to work with new network visualization --- pyproject.toml | 33 +- requirements-dev.txt | 9 +- requirements.txt | 9 +- temoa/model_checking/commodity_graph.py | 513 ++++++++++-------- temoa/model_checking/commodity_network.py | 41 +- .../commodity_network_manager.py | 52 +- temoa/model_checking/network_model_data.py | 166 ++++-- temoa/types/core_types.py | 1 + tests/test_source_check.py | 4 +- uv.lock | 44 +- 10 files changed, 489 insertions(+), 383 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 49eed387f..52dfabb10 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,8 +33,6 @@ dependencies = [ "networkx>=3.3", "highspy>=1.7.2", "scipy>=1.14.1", - "nx-vis-visualizer>=0.1.1", - "gravis>=0.1.0", ] @@ -47,6 +45,7 @@ dev = [ "pytest", "pytest-cov", "pandas-stubs>=2.3.2.250926", + "types-networkx>=3.5.0.20251001", ] [project.optional-dependencies] @@ -105,7 +104,7 @@ python_version = "3.12" mypy_path = "stubs" # Exclude specific directories from type checking will try to add them back gradually -exclude = "(?x)(^tests/|^temoa/data_processing/|^temoa/extensions/|^temoa/utilities/|^docs/|^temoa/model_checking/commodity_graph.py)" # TODO: Remove model_checking exclusion after gravis dep is removed +exclude = "(?x)(^tests/|^temoa/data_processing/|^temoa/extensions/|^temoa/utilities/|^docs/)" # Strict typing for our own code disallow_untyped_defs = true @@ -127,29 +126,8 @@ disallow_any_generics = true disallow_any_unimported = true disallow_any_expr = false # temporarily false to ease transition disallow_any_decorated = true -disallow_any_explicit = true +disallow_any_explicit = false # temporarily false to ease transition -# Module-specific overrides for external dependencies -[[tool.mypy.overrides]] -module = [ - "pyomo.*", -] -ignore_missing_imports = true - -# Less strict for test files initially -[[tool.mypy.overrides]] -module = "tests.*" -disallow_untyped_defs = false - -disallow_incomplete_defs = false - -# Silence errors from excluded modules (follow imports but don't report errors) -[[tool.mypy.overrides]] -module = [ - "temoa.data_processing.*", - "temoa.extensions.*", -] -follow_imports = "silent" # Enable strict checking for core modules [[tool.mypy.overrides]] @@ -169,11 +147,6 @@ check_untyped_defs = true module = "temoa.types.*" disallow_any_explicit = false -# Relax Any restrictions for Pyomo-related code -[[tool.mypy.overrides]] -module = ["temoa.components.*", "temoa._internal.*"] -disallow_any_explicit = false -disallow_any_unimported = false [project.urls] diff --git a/requirements-dev.txt b/requirements-dev.txt index 51527dabd..fdc91723d 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -86,8 +86,6 @@ fqdn==1.5.1 # via jsonschema graphviz==0.21 # via temoa (pyproject.toml) -gravis==0.1.0 - # via temoa (pyproject.toml) greenlet==3.2.3 # via sqlalchemy gurobipy==12.0.3 @@ -275,9 +273,7 @@ nbformat==5.10.4 nest-asyncio==1.6.0 # via ipykernel networkx==3.5 - # via - # temoa (pyproject.toml) - # nx-vis-visualizer + # via temoa (pyproject.toml) nose==1.3.7 # via pyutilib notebook==7.4.4 @@ -303,8 +299,6 @@ numpy==2.3.1 # scipy # seaborn # wquantiles -nx-vis-visualizer==0.2.0 - # via temoa (pyproject.toml) openpyxl==3.1.5 # via # temoa (pyproject.toml) @@ -484,7 +478,6 @@ send2trash==1.8.3 # via jupyter-server setuptools==80.9.0 # via - # gravis # jupyter-contrib-core # jupyterlab shellingham==1.5.4 diff --git a/requirements.txt b/requirements.txt index 0c196d97f..2934aa242 100644 --- a/requirements.txt +++ b/requirements.txt @@ -76,8 +76,6 @@ fqdn==1.5.1 # via jsonschema graphviz==0.21 # via temoa (pyproject.toml) -gravis==0.1.0 - # via temoa (pyproject.toml) greenlet==3.2.3 # via sqlalchemy h11==0.16.0 @@ -258,9 +256,7 @@ nbformat==5.10.4 nest-asyncio==1.6.0 # via ipykernel networkx==3.5 - # via - # temoa (pyproject.toml) - # nx-vis-visualizer + # via temoa (pyproject.toml) nose==1.3.7 # via pyutilib notebook==7.4.4 @@ -286,8 +282,6 @@ numpy==2.3.1 # scipy # seaborn # wquantiles -nx-vis-visualizer==0.2.0 - # via temoa (pyproject.toml) openpyxl==3.1.5 # via # temoa (pyproject.toml) @@ -455,7 +449,6 @@ send2trash==1.8.3 # via jupyter-server setuptools==80.9.0 # via - # gravis # jupyter-contrib-core # jupyterlab shellingham==1.5.4 diff --git a/temoa/model_checking/commodity_graph.py b/temoa/model_checking/commodity_graph.py index 4c2e2df22..5b3aeb22f 100644 --- a/temoa/model_checking/commodity_graph.py +++ b/temoa/model_checking/commodity_graph.py @@ -1,261 +1,310 @@ -""" -A quick & dirty graph of the commodity network for troubleshooting purposes. Future -development may enhance this quite a bit.... lots of opportunity! -""" +from __future__ import annotations import logging +from collections import defaultdict from collections.abc import Iterable -from pathlib import Path +from typing import Any -import gravis as gv import networkx as nx from temoa.core.config import TemoaConfig -from temoa.model_checking.network_model_data import NetworkModelData, TechTuple +from temoa.model_checking.network_model_data import EdgeTuple, NetworkModelData +from temoa.types.core_types import Period, Region +from temoa.utilities.graph_utils import ( + calculate_initial_positions, + calculate_tech_graph_positions, +) +from temoa.utilities.visualizer import make_nx_graph, nx_to_vis + +logger = logging.getLogger(__name__) -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling -Copyright (C) 2015, NC State University +def generate_technology_graph( + all_edges: Iterable[EdgeTuple], + source_commodities: set[str], + demand_commodities: set[str], + sector_colors: dict[str, str], +) -> nx.MultiDiGraph[str]: + """ + Generates a technology-centric graph with a pre-computed initial layout. + """ + tg: nx.MultiDiGraph[str] = nx.MultiDiGraph() + tech_positions = calculate_tech_graph_positions(all_edges) -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. + # Pass 1: Aggregate information for each unique technology. + tech_info: dict[str, dict[str, Any]] = defaultdict( + lambda: {'is_source': False, 'is_demand': False, 'sector': None} + ) + for tech_tuple in all_edges: + info = tech_info[tech_tuple.tech] + if tech_tuple.input_comm in source_commodities: + info['is_source'] = True + if tech_tuple.output_comm in demand_commodities: + info['is_demand'] = True + # Use the sector from the first tuple we see for a given tech + if not info['sector']: + info['sector'] = tech_tuple.sector -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + # Pass 2: Create a single, correctly styled node for each unique technology. + for tech_name, info in tech_info.items(): + pos_attrs = tech_positions.get(tech_name, {}) + sector = info['sector'] -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 . + color_obj: dict[str, str] = {} + if sector and (bg := sector_colors.get(sector)): + color_obj['background'] = bg + border_width = 1 + title = f'Tech: {tech_name}' + # Apply styles based on the aggregated status + if info['is_source']: + color_obj['border'] = '#2ca02c' # Green border + border_width = 4 + title += '\nType: Source Technology' + if info['is_demand']: + color_obj['border'] = '#e377c2' # Magenta/Pink border + border_width = 4 + title += '\nType: Demand Technology' -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 2/14/24 + node_attrs: dict[str, Any] = { + 'label': tech_name, + 'title': title + (f'\nSector: {sector}' if sector else ''), + 'shape': 'box', + 'color': color_obj, + 'borderWidth': border_width, + **pos_attrs, + } + tg.add_node(tech_name, **node_attrs) -""" + # Create edges representing commodity flows + commodity_map: defaultdict[str, dict[str, set[str]]] = defaultdict( + lambda: {'producers': set(), 'consumers': set()} + ) + for tech_tuple in all_edges: + commodity_map[tech_tuple.output_comm]['producers'].add(tech_tuple.tech) + commodity_map[tech_tuple.input_comm]['consumers'].add(tech_tuple.tech) -logger = logging.getLogger(__name__) + for commodity, roles in commodity_map.items(): + if commodity in source_commodities or commodity in demand_commodities: + continue + for producer in roles['producers']: + for consumer in roles['consumers']: + if producer != consumer: + tg.add_edge( + producer, + consumer, + label=commodity, + title=f'Commodity Flow: {commodity}', + arrows='to', + color='#555555', + ) + return tg -def generate_graph( - region, - period, +def generate_commodity_graph( + region: Region, + period: Period, network_data: NetworkModelData, - demand_orphans: Iterable[TechTuple], - other_orphans: Iterable[TechTuple], - driven_techs: Iterable[TechTuple], - config: TemoaConfig, -): + demand_orphans: Iterable[EdgeTuple], + other_orphans: Iterable[EdgeTuple], + driven_techs: Iterable[EdgeTuple], +) -> tuple[nx.MultiDiGraph[str], dict[str, str]]: """ - generate graph for region/period from network data - :param region: region of interest - :param period: period of interest - :param network_data: the data showing all edges to be graphed. "orphans" will be added, if they aren't included - :param demand_orphans: container of orphans [orphanage ;)] - :param other_orphans: container of orphans - :param driven_techs: the "driven" techs in LinkedTech pairs - :param config: - :return: + Generates the commodity-centric graph and its associated color scheme. + In this view, commodities are nodes and technologies are grouped into edges. """ - layers = {} - for c in network_data.waste_commodities[region, period]: - layers[c] = 6 - for c in network_data.physical_commodities: - layers[c] = 2 # physical - for c in network_data.source_commodities[region, period]: - layers[c] = 1 - for c in network_data.demand_commodities[region, period]: - layers[c] = 3 - for c in network_data.capacity_commodities: - layers[c] = 4 - for c in network_data.exchange_commodities: - layers[c] = 5 - - edge_colors = {} - edge_weights = {} - # dev note: the generators below do 2 things: put the data in the format expected by the - # graphing code and reduce redundant vintages to 1 representation - # Note that there is a heirarchy here and the latter loops may overwrite earlier color/weight - # decisions, so primary stuff goes last! - all_edges = { - (tech.ic, tech.name, tech.oc) for tech in network_data.available_techs[region, period] + all_edge_tuples = ( + set(network_data.available_techs.get((region, period), set())) + | set(demand_orphans) + | set(other_orphans) + | set(driven_techs) + ) + + # 1. Prepare sector-based mappings for coloring + unique_sectors = sorted({tech.sector for tech in all_edge_tuples if tech.sector}) + color_palette = [ + '#1f77b4', + '#ff7f0e', + '#2ca02c', + '#d62728', + '#9467bd', + '#8c564b', + '#e377c2', + '#7f7f7f', + '#bcbd22', + '#17becf', + ] + sector_colors = { + sector: color_palette[i % len(color_palette)] for i, sector in enumerate(unique_sectors) } - cap_edges = { - (tech.ic, tech.name, tech.oc) - for tech in network_data.available_techs[region, period] - if tech.name in ('Construction', 'EndOfLife') + default_color = '#A9A9A9' + + commodity_sector_counts: defaultdict[str, defaultdict[str, int]] = defaultdict( + lambda: defaultdict(int) + ) + for tech in all_edge_tuples: + if tech.sector: + commodity_sector_counts[tech.input_comm][tech.sector] += 1 + commodity_sector_counts[tech.output_comm][tech.sector] += 1 + + commodity_to_primary_sector = { + comm: max(counts, key=lambda k: counts[k]) + for comm, counts in commodity_sector_counts.items() + if counts } - exc_edges = { - (tech.ic, tech.name, tech.oc) - for tech in network_data.available_techs[region, period] - if tech.ic in network_data.exchange_commodities - or tech.oc in network_data.exchange_commodities + + # 2. Define node layers (1: source, 2: intermediate, 3: sink) + layer_map: dict[str, int] = dict.fromkeys( + network_data.physical_commodities, 2 + ) # all intermediates + for c in network_data.source_commodities.get((region, period), []): + layer_map[c] = 1 + for c in network_data.demand_commodities.get((region, period), []): + layer_map[c] = 3 + + node_positions = calculate_initial_positions( + layer_map, + commodity_to_primary_sector, + unique_sectors, + ) + + # 3. Prepare edge attributes with sector-based coloring + edge_attributes_map: dict[tuple[str, str, str, str | None], dict[str, Any]] = {} + all_connections: set[tuple[str, str, str, str | None]] = { + (tech.input_comm, tech.tech, tech.output_comm, tech.sector) for tech in all_edge_tuples } - # troll through the tech_data and label things of low importance - for edge in all_edges: - tech = edge[1] - characteristics = network_data.tech_data.get(tech, None) - if characteristics and characteristics.get('neg_cost', False): - edge_weights[edge] = 3 - edge_colors[edge] = 'green' - # other growth here... - # label other things of higher importance (these will override) - for edge in ((tech.ic, tech.name, tech.oc) for tech in driven_techs): - edge_colors[edge] = 'blue' - edge_weights[edge] = 2 - all_edges.add(edge) - for edge in ((tech.ic, tech.name, tech.oc) for tech in other_orphans): - edge_colors[edge] = 'yellow' - edge_weights[edge] = 3 - all_edges.add(edge) - for edge in ((tech.ic, tech.name, tech.oc) for tech in demand_orphans): - edge_colors[edge] = 'red' - edge_weights[edge] = 5 - all_edges.add(edge) - for edge in cap_edges: - edge_colors[edge] = 'darkgreen' - edge_weights[edge] = 2 - all_edges.add(edge) - for edge in exc_edges: - edge_colors[edge] = 'darkblue' - edge_weights[edge] = 2 - all_edges.add(edge) - - dg = make_nx_graph(all_edges, edge_colors, edge_weights, layers) - - # loop finder... - try: - cycles = nx.simple_cycles(G=dg) - for cycle in cycles: - cycle = list(cycle) - if len(cycle) < 2: # a storage item--not reportable - continue - res = '' - first = cycle[0] - last_node = first - try: - for node in cycle: - if node.split(' (')[0] == last_node.split(' (')[0]: - # This is just an exchange tech loop. Ignore. - # These are labelled in the graph as {base_tech} ({other region}) - # so we split on ' (' to compare the base techs - raise ValueError('Just an exchange tech') - res += f'{node} --> ' - last_node = node - except ValueError: - # This is just a trick to continue the outer loop instead of the inner loop - # this cycle wasn't really a cycle so just continue - continue - res += first - logger.info( - 'Found cycle in region %s, period %d. No action needed if this is correct: %s', - region, - period, - res, - ) - except nx.NetworkXError as e: - logger.warning('NetworkX exception encountered: %s. Loop evaluation NOT performed.', e) - if config.plot_commodity_network: - filename_label = f'{region}_{period}' - _graph_connections( - directed_graph=dg, - file_label=filename_label, - output_path=config.output_path, - ) - - -def _graph_connections( - directed_graph: nx.MultiDiGraph | nx.DiGraph, - file_label: str, - output_path: Path, -): + driven_names = {t.tech for t in driven_techs} + other_orphan_names = {t.tech for t in other_orphans} + demand_orphan_names = {t.tech for t in demand_orphans} + + driven_commodities: set[str] = set() + other_orphan_commodities: set[str] = set() + demand_orphan_commodities: set[str] = set() + + for ic, tech_name, oc, sector in all_connections: + key = (ic, tech_name, oc, sector) + color = default_color + if sector: + color = sector_colors.get(sector, default_color) + + attrs: dict[str, Any] = { + 'color': color, + 'value': 1, # Default thickness + } + + tech_data = network_data.tech_data.get(tech_name, {}) + if tech_data.get('neg_cost', False): + attrs['value'] = 3 + + if tech_name in driven_names: + attrs.update({'color': '#1f77b4', 'value': 3, 'dashes': True}) + driven_commodities.update({ic, oc}) + elif tech_name in other_orphan_names: + attrs.update({'color': '#ff7f0e', 'value': 4, 'dashes': True}) + other_orphan_commodities.update({ic, oc}) + elif tech_name in demand_orphan_names: + attrs.update({'color': '#d62728', 'value': 6, 'dashes': True}) + demand_orphan_commodities.update({ic, oc}) + + edge_attributes_map[key] = attrs + + # 4. Create the NetworkX graph using the utility function + dg = make_nx_graph( + all_connections, + edge_attributes_map, + layer_map, + node_positions, + commodity_to_primary_sector, + driven_names, + other_orphan_names, + demand_orphan_names, + driven_commodities=driven_commodities, + other_orphan_commodities=other_orphan_commodities, + demand_orphan_commodities=demand_orphan_commodities, + ) + + return dg, sector_colors + + +def visualize_graph( + region: Region, + period: Period, + network_data: NetworkModelData, + demand_orphans: Iterable[EdgeTuple], + other_orphans: Iterable[EdgeTuple], + driven_techs: Iterable[EdgeTuple], + config: TemoaConfig, +) -> None: """ - Make an HTML file containing the network graph - :param file_label: the name of the output file - :param output_path: the output directory - :return: + Generates and saves an interactive HTML file with two graph views if + config.plot_commodity_network is True. """ - try: - fig = gv.d3( - directed_graph, - show_menu=True, - show_node_label=True, - node_label_data_source='label', - show_edge_label=True, - edge_label_data_source='label', - edge_curvature=0.4, - graph_height=1000, - zoom_factor=1.0, - node_drag_fix=True, - node_label_size_factor=0.5, - layout_algorithm_active=True, - ) - except Exception as e: - logger.error('Failed to create a figure for the network graph: %s', e) + # 1. Check the configuration flag first. If false, do nothing. + if not config.plot_commodity_network: + logger.info("Skipping network graph generation because 'plot_commodity_network' is false.") return - filename = f'Commodity_Graph_{file_label}.html' - output_path = output_path / filename + + # --- All generation logic now only runs if the flag is True --- + + # 2. Generate the primary (commodity-centric) graph and its color legend + commodity_graph, sector_colors = generate_commodity_graph( + region, period, network_data, demand_orphans, other_orphans, driven_techs + ) + + # 3. Collect all technology tuples needed for the secondary graph + all_techs_for_period = ( + set(network_data.available_techs.get((region, period), set())) + | set(demand_orphans) + | set(other_orphans) + | set(driven_techs) + ) + + # 4. Generate the secondary (technology-centric) graph + tech_graph = generate_technology_graph( + all_techs_for_period, + network_data.source_commodities.get((region, period), set()), + network_data.demand_commodities.get((region, period), set()), + sector_colors, + ) + + # 5. Define the style legend data + style_legend_map = [ + # Styles for the Commodity View + {'label': 'Connected to Demand Orphan', 'borderColor': '#d62728', 'borderWidth': 4}, + {'label': 'Connected to Other Orphan', 'borderColor': '#ff7f0e', 'borderWidth': 4}, + {'label': 'Connected to Driven Tech', 'borderColor': '#1f77b4', 'borderWidth': 4}, + # Styles for the Technology View + {'label': 'Source Technology', 'borderColor': '#2ca02c', 'borderWidth': 4}, + {'label': 'Demand Technology', 'borderColor': '#e377c2', 'borderWidth': 4}, + ] + + # 6. Create the interactive HTML visualization + output_file = config.output_path / f'Network_Graph_{region}_{period}.html' + unique_sectors = sorted(sector_colors) + + graph_path = nx_to_vis( + nx_graph=commodity_graph, + secondary_graph=tech_graph, + output_filename=output_file, + html_title=f'Network Graphs - {region} {period}', + sectors=unique_sectors, + color_legend_map=sector_colors, + style_legend_map=style_legend_map, + show_browser=False, + ) + + if graph_path: + logger.info('Generated network graphs at: %s', graph_path) + else: + logger.error('Failed to generate network graphs') + + # 7. Perform cycle detection on the commodity graph try: - fig.export_html(output_path, overwrite=True) - except UnicodeEncodeError as e: - logger.warning( - 'Failed to export the network graph into HTML. Bad character in names of commodities or ' - 'tech?\n Error message: %s', - e, - ) - except Exception as e: - logger.error('Failed to export the network graph into HTML. Error message: %s', e) - - -def make_nx_graph(connections, edge_colors, edge_weights, layer_map) -> nx.MultiDiGraph: - """ - Make a nx graph of the commodity network. Additional info passed in to embed it within the nx data - :param connections: an iterable container of connections of format (input_comm, tech, output_comm) - :param edge_colors: An map of the layers. 1: source commodity, 2: physical commodity, 3: demand commodity - :param edge_weights: color map of edges (technologies). Non-entries default to black - :param layer_map: weight map of edges (technologies). Non-entries default to 1.0 - :return: a nx MultiDiGraph - """ - dg = nx.MultiDiGraph() # networkx multi(edge) directed graph - layer_colors = { - 1: 'limegreen', - 2: 'violet', - 3: 'darkorange', - 4: 'darkgreen', - 5: 'darkblue', - 6: 'darkred', - } - node_size = {1: 50, 2: 15, 3: 30, 4: 20, 5: 20, 6: 30} - for ic, tech, oc in connections: - dg.add_node( - ic, - name=ic, - layer=layer_map[ic], - label=ic, - color=layer_colors[layer_map[ic]], - size=node_size[layer_map[ic]], - ) - dg.add_node( - oc, - name=oc, - layer=layer_map[oc], - label=oc, - color=layer_colors[layer_map[oc]], - size=node_size[layer_map[oc]], - ) - dg.add_edge( - ic, - oc, - label=tech, - color=edge_colors.get((ic, tech, oc), 'black'), - size=edge_weights.get((ic, tech, oc), 1), - ) - return dg + for cycle in nx.simple_cycles(G=commodity_graph): + if len(cycle) < 2: + continue + cycle_str = ' -> '.join(cycle) + f' -> {cycle[0]}' + logger.warning('Cycle detected: %s', cycle_str) + except nx.NetworkXError as e: + logger.warning('NetworkXError during cycle detection: %s', e, exc_info=True) diff --git a/temoa/model_checking/commodity_network.py b/temoa/model_checking/commodity_network.py index afb8771ec..ebe6c9ef8 100644 --- a/temoa/model_checking/commodity_network.py +++ b/temoa/model_checking/commodity_network.py @@ -18,7 +18,7 @@ from collections import defaultdict from logging import getLogger -from temoa.model_checking.network_model_data import NetworkModelData, TechTuple +from temoa.model_checking.network_model_data import EdgeTuple, NetworkModelData from temoa.types.core_types import Commodity, Period, Region, Technology logger = getLogger(__name__) @@ -89,13 +89,13 @@ def _load_connections(self) -> None: self.tech_outputs.clear() self.connections.clear() - techs = self.model_data.available_techs[self.region, self.period] - for tech in techs: - self.connections[tech.oc].add((tech.ic, tech.name)) - self.tech_inputs[tech.name].add(tech.ic) - self.tech_outputs[tech.name].add(tech.oc) + edge_tuples = self.model_data.available_techs[self.region, self.period] + for edge_tuple in edge_tuples: + self.connections[edge_tuple.output_comm].add((edge_tuple.input_comm, edge_tuple.tech)) + self.tech_inputs[edge_tuple.tech].add(edge_tuple.input_comm) + self.tech_outputs[edge_tuple.tech].add(edge_tuple.output_comm) - def reload(self, connections: set[TechTuple]) -> None: + def reload(self, connections: set[EdgeTuple]) -> None: """ Reload the network model with a new set of connections. @@ -295,28 +295,31 @@ def _log_orphans(self) -> None: for orphan in sorted(self.demand_orphans, key=lambda x: x[1]): logger.info('Discovered orphaned process: %s', orphan) - def get_valid_tech(self) -> set[TechTuple]: + def get_valid_tech(self) -> set[EdgeTuple]: """Returns the set of Tech objects that are part of a valid connection.""" return { - tech - for tech in self.model_data.available_techs[self.region, self.period] - if (tech.ic, tech.name, tech.oc) in self.good_connections + edge_tuple + for edge_tuple in self.model_data.available_techs[self.region, self.period] + if (edge_tuple.input_comm, edge_tuple.tech, edge_tuple.output_comm) + in self.good_connections } - def get_demand_side_orphans(self) -> set[TechTuple]: + def get_demand_side_orphans(self) -> set[EdgeTuple]: """Returns Tech objects for demand-side orphans.""" return { - tech - for tech in self.model_data.available_techs[self.region, self.period] - if (tech.ic, tech.name, tech.oc) in self.demand_orphans + edge_tuple + for edge_tuple in self.model_data.available_techs[self.region, self.period] + if (edge_tuple.input_comm, edge_tuple.tech, edge_tuple.output_comm) + in self.demand_orphans } - def get_other_orphans(self) -> set[TechTuple]: + def get_other_orphans(self) -> set[EdgeTuple]: """Returns Tech objects for non-demand-side orphans.""" return { - tech - for tech in self.model_data.available_techs[self.region, self.period] - if (tech.ic, tech.name, tech.oc) in self.other_orphans + edge_tuple + for edge_tuple in self.model_data.available_techs[self.region, self.period] + if (edge_tuple.input_comm, edge_tuple.tech, edge_tuple.output_comm) + in self.other_orphans } def unsupported_demands(self) -> set[Commodity]: diff --git a/temoa/model_checking/commodity_network_manager.py b/temoa/model_checking/commodity_network_manager.py index e6bed73a2..6253ddd69 100644 --- a/temoa/model_checking/commodity_network_manager.py +++ b/temoa/model_checking/commodity_network_manager.py @@ -15,10 +15,10 @@ from typing import Any from temoa.core.config import TemoaConfig -from temoa.model_checking.commodity_graph import generate_graph +from temoa.model_checking.commodity_graph import visualize_graph from temoa.model_checking.commodity_network import CommodityNetwork from temoa.model_checking.element_checker import ViableSet -from temoa.model_checking.network_model_data import NetworkModelData, TechTuple +from temoa.model_checking.network_model_data import EdgeTuple, NetworkModelData from temoa.types.core_types import Period, Region logger = getLogger(__name__) @@ -42,8 +42,8 @@ def __init__(self, periods: Iterable[str | int], network_data: NetworkModelData) # Store a deep copy of the original connections for graphing purposes self.orig_tech = {k: v.copy() for k, v in network_data.available_techs.items()} # Final collections of all orphans found, organized by (region, period) - self.demand_orphans: dict[RegionPeriodKey, set[TechTuple]] = defaultdict(set) - self.other_orphans: dict[RegionPeriodKey, set[TechTuple]] = defaultdict(set) + self.demand_orphans: dict[RegionPeriodKey, set[EdgeTuple]] = defaultdict(set) + self.other_orphans: dict[RegionPeriodKey, set[EdgeTuple]] = defaultdict(set) def _analyze_region(self, region: Region, data: NetworkModelData) -> None: """ @@ -56,7 +56,7 @@ def _analyze_region(self, region: Region, data: NetworkModelData) -> None: a stable, valid network. """ for pass_num in range(1, 100): # Safety break after 100 iterations - orphans_this_pass: set[TechTuple] = set() + orphans_this_pass: set[EdgeTuple] = set() for period in self.periods: cn = CommodityNetwork(region=region, period=period, model_data=data) @@ -116,9 +116,9 @@ def analyze_network(self) -> bool: """ self.filtered_data = self.orig_data.clone() # Identify regions to analyze (excluding exchange pseudo-regions) - self.regions = {r for (r, p) in self.orig_data.available_techs if '-' not in r} + self.regions = set(sorted({r for (r, p) in self.orig_data.available_techs if '-' not in r})) - for region in sorted(self.regions): + for region in self.regions: logger.info('Starting network analysis for region %s', region) self._analyze_region(region, data=self.filtered_data) @@ -135,23 +135,33 @@ def build_filters(self) -> dict[str, ViableSet]: raise RuntimeError('analyze_network() must be called before build_filters().') # Use defaultdicts to easily collect unique elements - valid_elements: defaultdict[str, set[Any]] = defaultdict(set) # type: ignore [explicit-any] + valid_elements: defaultdict[str, set[Any]] = defaultdict(set) - for (_r, p), techs in self.filtered_data.available_techs.items(): - if not techs: + for (_r, p), edge_tuples in self.filtered_data.available_techs.items(): + if not edge_tuples: continue - for tech in techs: + for edge_tuple in edge_tuples: valid_elements['ritvo'].add( - (tech.region, tech.ic, tech.name, tech.vintage, tech.oc) + ( + edge_tuple.region, + edge_tuple.input_comm, + edge_tuple.tech, + edge_tuple.vintage, + edge_tuple.output_comm, + ) + ) + valid_elements['rtv'].add((edge_tuple.region, edge_tuple.tech, edge_tuple.vintage)) + valid_elements['rt'].add((edge_tuple.region, edge_tuple.tech)) + valid_elements['rpit'].add( + (edge_tuple.region, p, edge_tuple.input_comm, edge_tuple.tech) + ) + valid_elements['rpto'].add( + (edge_tuple.region, p, edge_tuple.tech, edge_tuple.output_comm) ) - valid_elements['rtv'].add((tech.region, tech.name, tech.vintage)) - valid_elements['rt'].add((tech.region, tech.name)) - valid_elements['rpit'].add((tech.region, p, tech.ic, tech.name)) - valid_elements['rpto'].add((tech.region, p, tech.name, tech.oc)) - valid_elements['t'].add(tech.name) - valid_elements['v'].add(tech.vintage) - valid_elements['ic'].add(tech.ic) - valid_elements['oc'].add(tech.oc) + valid_elements['t'].add(edge_tuple.tech) + valid_elements['v'].add(edge_tuple.vintage) + valid_elements['ic'].add(edge_tuple.input_comm) + valid_elements['oc'].add(edge_tuple.output_comm) return { 'ritvo': ViableSet( @@ -193,7 +203,7 @@ def analyze_graphs(self, config: TemoaConfig) -> None: raise RuntimeError('analyze_network() must be called before analyze_graphs().') for region in self.regions: for period in self.periods: - generate_graph( + visualize_graph( region, period, network_data=self.orig_data, diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index 5653e980c..7b859fd7f 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -25,12 +25,14 @@ # --- Type Definitions --- -class TechTuple(NamedTuple): +class EdgeTuple(NamedTuple): region: Region - ic: Commodity - name: Technology + input_comm: Commodity + tech: Technology vintage: Vintage - oc: Commodity + output_comm: Commodity + lifetime: int | None = None + sector: str | None = None class LinkedTechTuple(NamedTuple): @@ -87,7 +89,7 @@ class NetworkModelData: default_factory=lambda: defaultdict(set) ) physical_commodities: set[Commodity] = field(default_factory=set) - available_techs: defaultdict[tuple[Region, Period], set[TechTuple]] = field( + available_techs: defaultdict[tuple[Region, Period], set[EdgeTuple]] = field( default_factory=lambda: defaultdict(set) ) available_linked_techs: set[LinkedTechTuple] = field(default_factory=set) @@ -112,19 +114,20 @@ def update_tech_data(self, tech: Technology, element: str, value: TechAttributeV """Update a data element for a tech.""" self.tech_data[tech][element] = value - def get_driven_techs(self, region: Region, period: Period) -> set[TechTuple]: + def get_driven_techs(self, region: Region, period: Period) -> set[EdgeTuple]: """Identifies all linked techs by name from the linked tech names.""" driven_tech_names = {lt.driven for lt in self.available_linked_techs} return { - tech - for tech in self.available_techs.get((region, period), set()) - if tech.name in driven_tech_names + efficiencyTuple + for efficiencyTuple in self.available_techs.get((region, period), set()) + if efficiencyTuple.tech in driven_tech_names } def __str__(self) -> str: return ( - f'all commodities: {len(self.physical_commodities)}, demand commodities: {len(self.demand_commodities)}, ' - f'source commodities: {len(self.source_commodities)}, ' + f'physical commodities: {len(self.physical_commodities)}, ' + f'demand commodities: {len({c for s in self.demand_commodities.values() for c in s})}, ' + f'source commodities: {len({c for s in self.source_commodities.values() for c in s})}, ' f'available techs: {len(tuple(chain(*self.available_techs.values())))}, ' f'linked techs: {len(self.available_linked_techs)}' ) @@ -141,7 +144,7 @@ def build(data: ModelBlock | DbConnection, *args: object, **kwargs: object) -> N return builder(data, *args, **kwargs) -def _get_builder(data: ModelBlock | DbConnection) -> Callable[..., NetworkModelData]: # type: ignore [explicit-any] +def _get_builder(data: ModelBlock | DbConnection) -> Callable[..., NetworkModelData]: """Selects the appropriate builder function based on the input data type.""" if isinstance(data, (TemoaModel, ConcreteModel)): return _build_from_model @@ -161,13 +164,13 @@ def _build_from_model(M: TemoaModel, myopic_index: MyopicIndex | None = None) -> for r, p, d in M.Demand.sparse_iterkeys(): dem_com[r, p].add(d) - techs: defaultdict[tuple[Region, Period], set[TechTuple]] = defaultdict(set) + techs: defaultdict[tuple[Region, Period], set[EdgeTuple]] = defaultdict(set) if M.activeFlow_rpsditvo is not None: for r, p, _s, _d, ic, tech, v, oc in M.activeFlow_rpsditvo: - techs[r, p].add(TechTuple(r, ic, tech, v, oc)) + techs[r, p].add(EdgeTuple(r, ic, tech, v, oc)) if M.activeFlow_rpitvo is not None: for r, p, ic, tech, v, oc in M.activeFlow_rpitvo: - techs[r, p].add(TechTuple(r, ic, tech, v, oc)) + techs[r, p].add(EdgeTuple(r, ic, tech, v, oc)) linked_techs = { LinkedTechTuple(r, driver, emission, driven) @@ -233,19 +236,46 @@ def _fetch_basic_data(cur: sqlite3.Cursor) -> BasicData: def _fetch_all_tech_definitions( cur: sqlite3.Cursor, myopic_index: MyopicIndex | None -) -> list[tuple[Region, Commodity, Technology, Vintage, Commodity, int]]: +) -> list[ + tuple[Region, Commodity, Technology, Vintage, Commodity, int] + | tuple[Region, Commodity, Technology, Vintage, Commodity, int, str] +]: """Fetches the main block of technology efficiency and lifetime data.""" default_lifetime = TemoaModel.default_lifetime_tech table = 'MyopicEfficiency' if myopic_index else 'Efficiency' - query = f""" - SELECT - eff.region, eff.input_comm, eff.tech, eff.vintage, eff.output_comm, - COALESCE(lp.lifetime, lt.lifetime, ?) AS lifetime - FROM main.{table} AS eff - LEFT JOIN main.LifetimeProcess AS lp ON eff.tech = lp.tech AND eff.vintage = lp.vintage AND eff.region = lp.region - LEFT JOIN main.LifetimeTech AS lt ON eff.tech = lt.tech AND eff.region = lt.region - JOIN main.TimePeriod AS tp ON eff.vintage = tp.period - """ + + # Check if Technology table has sector column + try: + cur.execute('SELECT sector FROM Technology LIMIT 1') + has_sector = True + except sqlite3.OperationalError: + has_sector = False + except (sqlite3.DatabaseError, AttributeError): + # For atypical cursors/mocks without schema + has_sector = False + + if has_sector: + query = f""" + SELECT + eff.region, eff.input_comm, eff.tech, eff.vintage, eff.output_comm, + COALESCE(lp.lifetime, lt.lifetime, ?) AS lifetime, + COALESCE(tech_dim.sector, 'Other') AS sector + FROM main.{table} AS eff + LEFT JOIN main.LifetimeProcess AS lp ON eff.tech = lp.tech AND eff.vintage = lp.vintage AND eff.region = lp.region + LEFT JOIN main.LifetimeTech AS lt ON eff.tech = lt.tech AND eff.region = lt.region + LEFT JOIN main.Technology AS tech_dim ON eff.tech = tech_dim.tech + JOIN main.TimePeriod AS tp ON eff.vintage = tp.period + """ + else: + query = f""" + SELECT + eff.region, eff.input_comm, eff.tech, eff.vintage, eff.output_comm, + COALESCE(lp.lifetime, lt.lifetime, ?) AS lifetime + FROM main.{table} AS eff + LEFT JOIN main.LifetimeProcess AS lp ON eff.tech = lp.tech AND eff.vintage = lp.vintage AND eff.region = lp.region + LEFT JOIN main.LifetimeTech AS lt ON eff.tech = lt.tech AND eff.region = lt.region + JOIN main.TimePeriod AS tp ON eff.vintage = tp.period + """ cursor = cur.execute(query, (default_lifetime,)) return cursor.fetchall() @@ -313,24 +343,71 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - living_techs: set[Technology] = set() # --- 2. Process technologies --- - for r, ic, tech, v, oc, lifetime in raw_techs: + for tech_data in raw_techs: + logger.debug(tech_data) + if len(tech_data) == 7: # Has sector + r, ic, tech, v, oc, lifetime, sector = tech_data + else: # No sector + r, ic, tech, v, oc, lifetime = tech_data + sector = None + for p in periods: if not (v <= p < v + lifetime): continue living_techs.add(tech) - if '-' in r: # Inter-regional transfer - r1, r2 = r.split('-') + if '-' in r and r.count('-') == 1: # Inter-regional transfer + r1, r2 = r.split('-', 1) source_comm, dest_comm = f'{ic} ({r1})', f'{oc} ({r2})' - res.available_techs[r2, p].add(TechTuple(r2, source_comm, tech, v, oc)) - res.available_techs[r1, p].add(TechTuple(r1, ic, tech, v, dest_comm)) - res.available_techs[r, p].add(TechTuple(r, ic, tech, v, oc)) + res.available_techs[r2, p].add( + EdgeTuple( + region=r2, + input_comm=source_comm, + tech=tech, + vintage=v, + output_comm=oc, + lifetime=lifetime, + sector=sector, + ) + ) + res.available_techs[r1, p].add( + EdgeTuple( + region=r1, + input_comm=ic, + tech=tech, + vintage=v, + output_comm=dest_comm, + lifetime=lifetime, + sector=sector, + ) + ) + res.available_techs[r, p].add( + EdgeTuple( + region=r, + input_comm=ic, + tech=tech, + vintage=v, + output_comm=oc, + lifetime=lifetime, + sector=sector, + ) + ) res.source_commodities[r2, p].add(source_comm) res.demand_commodities[r1, p].add(dest_comm) res.physical_commodities.update([source_comm, dest_comm]) res.exchange_commodities.update([source_comm, dest_comm]) else: # Standard technology - res.available_techs[r, p].add(TechTuple(r, ic, tech, v, oc)) + res.available_techs[r, p].add( + EdgeTuple( + region=r, + input_comm=ic, + tech=tech, + vintage=v, + output_comm=oc, + lifetime=lifetime, + sector=sector, + ) + ) if ic in basic_data['source_commodities_all']: res.source_commodities[r, p].add(ic) if oc in basic_data['waste_commodities_all']: @@ -345,7 +422,17 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - if is_natural_eol or is_retireable or has_survival: for eol_oc in lookup_data['eol'].get((r, tech, v), []): - res.available_techs[r, p].add(TechTuple(r, tech, 'EndOfLife', v, eol_oc)) + res.available_techs[r, p].add( + EdgeTuple( + region=r, + input_comm=tech, + tech='EndOfLife', + vintage=v, + output_comm=eol_oc, + lifetime=lifetime, + sector='Other', + ) + ) res.source_commodities[r, p].add(tech) res.capacity_commodities.add(tech) if eol_oc in basic_data['waste_commodities_all']: @@ -353,7 +440,18 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - # --- 3. Process Construction --- for r, ic, tech, v in lookup_data['construction']: - res.available_techs[r, v].add(TechTuple(r, ic, 'Construction', v, tech)) + construction_lifetime = basic_data['period_length'].get(v, 1) + res.available_techs[r, v].add( + EdgeTuple( + region=r, + input_comm=ic, + tech='Construction', + vintage=v, + output_comm=tech, + lifetime=construction_lifetime, + sector='Other', + ) + ) res.demand_commodities[r, v].add(tech) res.capacity_commodities.add(tech) living_techs.add(tech) diff --git a/temoa/types/core_types.py b/temoa/types/core_types.py index 7d572bf01..d0e8c19ae 100644 --- a/temoa/types/core_types.py +++ b/temoa/types/core_types.py @@ -13,6 +13,7 @@ Region = str Period = int Technology = str +Sector = str Vintage = int Season = str TimeOfDay = str diff --git a/tests/test_source_check.py b/tests/test_source_check.py index 661f6934f..ad6a34c85 100644 --- a/tests/test_source_check.py +++ b/tests/test_source_check.py @@ -13,7 +13,7 @@ # Assuming the refactored code is in this location from temoa.model_checking.commodity_network import CommodityNetwork -from temoa.model_checking.network_model_data import TechTuple +from temoa.model_checking.network_model_data import EdgeTuple # --- Test Case Definitions --- # Each tuple contains: @@ -189,7 +189,7 @@ def test_network_analysis( # Convert the connections dict into a set of Tech namedtuples available_techs = { - TechTuple(ic=ic, oc=oc, name=tech, vintage=period, region=region) + EdgeTuple(input_comm=ic, output_comm=oc, tech=tech, vintage=period, region=region) for oc, links in connections.items() for ic, tech in links } diff --git a/uv.lock b/uv.lock index 54305c688..2a89e8614 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 3 +revision = 2 requires-python = ">=3.12" [[package]] @@ -571,18 +571,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/91/4c/e0ce1ef95d4000ebc1c11801f9b944fa5910ecc15b5e351865763d8657f8/graphviz-0.21-py3-none-any.whl", hash = "sha256:54f33de9f4f911d7e84e4191749cac8cc5653f815b06738c54db9a15ab8b1e42", size = 47300, upload-time = "2025-06-15T09:35:04.433Z" }, ] -[[package]] -name = "gravis" -version = "0.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "setuptools" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/73/76/10b6264a45fffb565b9ad26b9fbc4ba91c2ca700f8dbfba84dcdebf5cbdd/gravis-0.1.0.tar.gz", hash = "sha256:a36342602aa7da3bbd674c970439717926a8f7ca0678aa82cc5d756e8c2a529b", size = 648634, upload-time = "2021-12-08T21:43:19.456Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/fb/6a1659424cfab2d8df49f3f02ca11bf7ca303775681f105239b556c9146c/gravis-0.1.0-py3-none-any.whl", hash = "sha256:ccfb4dbba13c7570f1f33b35ab5d536868acf5ce8a0c427fd898340cf4e414f4", size = 659146, upload-time = "2021-12-08T21:43:15.348Z" }, -] - [[package]] name = "greenlet" version = "3.2.3" @@ -1692,18 +1680,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d4/ca/af82bf0fad4c3e573c6930ed743b5308492ff19917c7caaf2f9b6f9e2e98/numpy-2.3.1-cp313-cp313t-win_arm64.whl", hash = "sha256:eccb9a159db9aed60800187bc47a6d3451553f0e1b08b068d8b277ddfbb9b244", size = 10260376, upload-time = "2025-06-21T12:24:56.884Z" }, ] -[[package]] -name = "nx-vis-visualizer" -version = "0.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "networkx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c3/f5/9ed4f232274c23786a241db69d21dd5f17f55eb3cd7f024fe9b1289f34b6/nx_vis_visualizer-0.2.0.tar.gz", hash = "sha256:96b04a21473d1079c98eb49411d9557e76edf152a0565502d42718779ee6dfe7", size = 17849, upload-time = "2025-06-12T00:29:20.942Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9c/5e/ef8786748d6b015d70941979adf611600df3e999667ec6955903338347f7/nx_vis_visualizer-0.2.0-py3-none-any.whl", hash = "sha256:d334366863f0a5acd6fcce604e2ef16d555f7472e2b5ea7d889e1afa77362168", size = 12072, upload-time = "2025-06-12T00:29:19.765Z" }, -] - [[package]] name = "openpyxl" version = "3.1.5" @@ -2942,7 +2918,6 @@ source = { editable = "." } dependencies = [ { name = "deprecated" }, { name = "graphviz" }, - { name = "gravis" }, { name = "highspy" }, { name = "ipykernel" }, { name = "ipython" }, @@ -2952,7 +2927,6 @@ dependencies = [ { name = "matplotlib" }, { name = "networkx" }, { name = "numpy" }, - { name = "nx-vis-visualizer" }, { name = "openpyxl" }, { name = "pandas" }, { name = "pyam-iamc" }, @@ -2992,13 +2966,13 @@ dev = [ { name = "pytest-cov" }, { name = "ruff" }, { name = "types-deprecated" }, + { name = "types-networkx" }, ] [package.metadata] requires-dist = [ { name = "deprecated", specifier = ">=1.2.14" }, { name = "graphviz", specifier = ">=0.20.3" }, - { name = "gravis", specifier = ">=0.1.0" }, { name = "gurobipy", marker = "extra == 'solver'", specifier = ">=12.0.3,<13" }, { name = "highspy", specifier = ">=1.7.2" }, { name = "ipykernel" }, @@ -3010,7 +2984,6 @@ requires-dist = [ { name = "matplotlib", marker = "extra == 'plotting'", specifier = ">=3.9.2" }, { name = "networkx", specifier = ">=3.3" }, { name = "numpy", specifier = ">=2.1.0" }, - { name = "nx-vis-visualizer", specifier = ">=0.1.1" }, { name = "openpyxl", specifier = ">=3.1.5" }, { name = "pandas", specifier = ">=2.2.2" }, { name = "pyam-iamc", specifier = ">=2.2.4" }, @@ -3041,6 +3014,7 @@ dev = [ { name = "pytest-cov" }, { name = "ruff", specifier = ">=0.2.0" }, { name = "types-deprecated", specifier = ">=1.2.15.20250304" }, + { name = "types-networkx", specifier = ">=3.5.0.20251001" }, ] [[package]] @@ -3142,6 +3116,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4d/e3/c18aa72ab84e0bc127a3a94e93be1a6ac2cb281371d3a45376ab7cfdd31c/types_deprecated-1.2.15.20250304-py3-none-any.whl", hash = "sha256:86a65aa550ea8acf49f27e226b8953288cd851de887970fbbdf2239c116c3107", size = 8553, upload-time = "2025-03-04T02:48:16.666Z" }, ] +[[package]] +name = "types-networkx" +version = "3.5.0.20251001" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/5b/d903d119f6159e0c9291c53db0e92ea33cb725331f75069d1b45b83b4405/types_networkx-3.5.0.20251001.tar.gz", hash = "sha256:8e3c5c491ba5870d75e175751d70ddeac81df43caf2a64bae161e181f5e8ea7a", size = 71748, upload-time = "2025-10-01T03:04:26.155Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/41/cdd9498383b30290cce9de6dbed75fa75d6dc06fe4b47d6da6de4b156aa0/types_networkx-3.5.0.20251001-py3-none-any.whl", hash = "sha256:4bb9dd0378a52ca57d68f8215f8662e736d800a8ff892b457646eccd828a0230", size = 160095, upload-time = "2025-10-01T03:04:24.821Z" }, +] + [[package]] name = "types-python-dateutil" version = "2.9.0.20250708" From 64d78e5ae537b1e0fb0d347666912a70d78e6a94 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 28 Oct 2025 14:29:26 -0400 Subject: [PATCH 277/587] fixing module name casing in data_processing --- docs/source/Documentation.rst | 124 +++++++++--------- temoa/_internal/run_actions.py | 2 +- temoa/data_processing/README.md | 33 ++--- .../{DatabaseUtil.py => database_util.py} | 86 +++++++----- .../{DB_to_Excel.py => db_to_excel.py} | 45 ++++--- ...GraphVizFormats.py => graphviz_formats.py} | 83 ++++++------ .../{GraphVizUtil.py => graphviz_util.py} | 4 +- .../{MakeGraphviz.py => make_graphviz.py} | 22 ++-- ...akeOutputPlots.py => make_output_plots.py} | 17 ++- temoa/extensions/myopic/myopic_sequencer.py | 47 ++----- 10 files changed, 230 insertions(+), 233 deletions(-) rename temoa/data_processing/{DatabaseUtil.py => database_util.py} (84%) rename temoa/data_processing/{DB_to_Excel.py => db_to_excel.py} (87%) rename temoa/data_processing/{GraphVizFormats.py => graphviz_formats.py} (71%) rename temoa/data_processing/{GraphVizUtil.py => graphviz_util.py} (98%) rename temoa/data_processing/{MakeGraphviz.py => make_graphviz.py} (96%) rename temoa/data_processing/{MakeOutputPlots.py => make_output_plots.py} (98%) diff --git a/docs/source/Documentation.rst b/docs/source/Documentation.rst index f1d3ac238..27b6e45c9 100644 --- a/docs/source/Documentation.rst +++ b/docs/source/Documentation.rst @@ -6,13 +6,13 @@ Preface This manual, in both `PDF`_ and `HTML`_ form, is the official documentation of -Tools for Energy Model Optimization and Analysis (Temoa). It describes all -functionality of the Temoa model, and provides a mathematical description of +Tools for Energy Model Optimization and Analysis (Temoa). It describes all +functionality of the Temoa model, and provides a mathematical description of the implemented equations. -Besides this documentation, there are a couple other sources for Temoa-oriented +Besides this documentation, there are a couple other sources for Temoa-oriented information. The most interactive is the `mailing list`_, and we encourage any -and all questions related to energy system modeling. Publications are good +and all questions related to energy system modeling. Publications are good introductory resources, but are not guaranteed to be the most up-to-date as information and implementations evolve quickly. As with many software-oriented projects, even before this manual, `the code is the most definitive resource`. @@ -22,12 +22,12 @@ discrepancies you find, and we will fix it as soon as possible. What is Temoa? -------------- -Temoa is an energy system optimization model (ESOM). Briefly, ESOMs optimize the -installation and utilization of energy technology capacity over a user-defined -time horizon. Optimal decisions are driven by an objective function that minimizes -the cost of energy supply. Conceptually, one may think of an ESOM as a "left-to-right" -network graph, with a set of energy sources on the lefthand side of the graph that -are transformed into consumable energy commodities by a set of energy technologies, +Temoa is an energy system optimization model (ESOM). Briefly, ESOMs optimize the +installation and utilization of energy technology capacity over a user-defined +time horizon. Optimal decisions are driven by an objective function that minimizes +the cost of energy supply. Conceptually, one may think of an ESOM as a "left-to-right" +network graph, with a set of energy sources on the lefthand side of the graph that +are transformed into consumable energy commodities by a set of energy technologies, which are ultimately used to meet demands on the righthand side of the network graph. [#esom_definition]_ @@ -90,9 +90,9 @@ language, meaning "to seek something." :figclass: center :figwidth: 50% -One pronounces the word 'Temoa' as "teh", "moe", "uh". Though TEMOA is an acronym -for 'Tools for Energy Model Optimization and Analysis', we generally use 'Temoa' -as a proper noun, and so forgo the need for all-caps. +One pronounces the word 'Temoa' as "teh", "moe", "uh". Though TEMOA is an acronym +for 'Tools for Energy Model Optimization and Analysis', we generally use 'Temoa' +as a proper noun, and so forgo the need for all-caps. Bug Reporting @@ -358,13 +358,13 @@ structure but no data added) to begin building your own database file. We recomm leaving the database structure intact, and simply adding data to the schema file, or constructing an empty database from the schema file and then using a database editor to import data. -Once the sql file is complete, you can convert it into a binary sqlite file by +Once the sql file is complete, you can convert it into a binary sqlite file by installing sqlite3 and executing the following command: .. parsed-literal:: $ sqlite3 my_database.sqlite < my_database.sql -Now you can specify this database as the source for both input and output data +Now you can specify this database as the source for both input and output data in the config file. ============ @@ -465,7 +465,7 @@ by the flow of energy commodities, a directed network graph represents an excell to visualize a given energy system representation in a Temoa-compatible input database. Temoa utilizes an open source graphics package called `Graphviz`_ to create a series of data-specific and interactive energy-system maps. Currently, the output graphs consist of -a full energy system map as well as capacity and activity results per model time period. +a full energy system map as well as capacity and activity results per model time period. In addition, users can create subgraphs focused on a particular commodity or technology. There are a couple ways to utilize Graphviz. The first way is to use the version embedded @@ -478,12 +478,12 @@ The second way is to use graphviz from the command line. To do so, navigate to t graphviz options, use the :code:`--help` flag: .. parsed-literal:: - $ python MakeGraphviz.py --help + $ python make_graphviz.py --help The most basic way to use graphviz is to view the full energy system map: .. parsed-literal:: - $ python MakeGraphviz.py -i ../data_files/temoa_utopia.sqlite + $ python make_graphviz.py -i ../data_files/temoa_utopia.sqlite In the command above, note that we have to point the Graphviz module to the :code:`temoa_utopia` database file, which resides in the :code:`data_files` @@ -494,15 +494,15 @@ directory. The resultant system map will look like this: :figclass: center :figwidth: 60% - This is a map of the simple 'Utopia' system, which we often use for testing - purposes. The map shows the possible commodity flows through the system, - providing a comprehensive overview of the system. Creating the simple system - map is useful for debugging purposes in order to make sure that technologies + This is a map of the simple 'Utopia' system, which we often use for testing + purposes. The map shows the possible commodity flows through the system, + providing a comprehensive overview of the system. Creating the simple system + map is useful for debugging purposes in order to make sure that technologies are linked together properly via commodity flows. -It is also possible to create a system map showing the optimal installed capacity -and technology flows in a particular model time period. These results are associated -with a specific model run stored in the model database. To view the results, include +It is also possible to create a system map showing the optimal installed capacity +and technology flows in a particular model time period. These results are associated +with a specific model run stored in the model database. To view the results, include the scenario flag (:code:`-s`) and a specific model year (:code:`-y`). Note that when Graphiz runs, it creates a folder within the :code:`data_processing` @@ -515,29 +515,29 @@ another means to debug the model and create an archive of visualizations for aud purposes. In addition, we have taken care to make these intermediate files well-formatted. .. parsed-literal:: - $ python MakeGraphviz.py -i ../data_files/temoa_utopia.sqlite -s test_run -y 1990 + $ python make_graphviz.py -i ../data_files/temoa_utopia.sqlite -s test_run -y 1990 .. figure:: images/global_results.* :align: center :figclass: center :figwidth: 60% - This graph shows the optimal installed capacity and commodity flows from the + This graph shows the optimal installed capacity and commodity flows from the 'utopia' test system in 2010. -The output can also be fine-tuned to show results associated with a specific +The output can also be fine-tuned to show results associated with a specific commodity or technology. For example: .. parsed-literal:: - $ python MakeGraphviz.py -i ../data_files/temoa_utopia.sqlite -s test_run -y 2010 -b E31 + $ python make_graphviz.py -i ../data_files/temoa_utopia.sqlite -s test_run -y 2010 -b E31 .. figure:: images/techvintage_results.* :align: center :figclass: center :figwidth: 60% - In this case, the graph shows the commodity flow in and out of - technology 'E31' in 2010, which is from the 'test_run' scenario drawn from the + In this case, the graph shows the commodity flow in and out of + technology 'E31' in 2010, which is from the 'test_run' scenario drawn from the 'temoa_utopia' database. Output Graphs @@ -547,13 +547,13 @@ Temoa can also be used to generate output graphs using `matplotlib -c -y 2010``` note how this input file passes a relative link up to the data_files directory, assuming standard location in the project - 3. `Network_diagrams.ipynb/` Notebook to interactively view network diagrams for a user-specified database. Create and activate the Temoa environment, as follows: - ```$ conda env create``` - - ```$ source activate temoa-py3``` - - Once the Temoa environment is created and activated, enable the following extensions from from the command line. - This will need to be done only once, before using notebooks within the Temoa environment. - - ```(temoa-py3) $ jupyter nbextension enable init_cell/main``` - - ```(temoa-py3) $ jupyter nbextension enable hide_input/main``` - - Once these extensions are enabled, navigate to the `temoa/data_processing/` folder and then open notebooks as follows. - - ```(temoa-py3) $ jupyter notebook``` + ```$ conda env create``` - Navigate to the `Network_diagrams.ipynb/` file and select technology/commodity options to interactively view their network diagrams. - The notebook also includes an interactive technology/commodity lookup tool. - The "Toggle selected cell input display" button (below and to the right of the Help menu) can be used to view hidden code cells. + ```$ source activate temoa-py3``` + Once the Temoa environment is created and activated, enable the following extensions from from the command line. + This will need to be done only once, before using notebooks within the Temoa environment. + ```(temoa-py3) $ jupyter nbextension enable init_cell/main``` + ```(temoa-py3) $ jupyter nbextension enable hide_input/main``` + Once these extensions are enabled, navigate to the `temoa/data_processing/` folder and then open notebooks as follows. + ```(temoa-py3) $ jupyter notebook``` + Navigate to the `Network_diagrams.ipynb/` file and select technology/commodity options to interactively view their network diagrams. + The notebook also includes an interactive technology/commodity lookup tool. + The "Toggle selected cell input display" button (below and to the right of the Help menu) can be used to view hidden code cells. diff --git a/temoa/data_processing/DatabaseUtil.py b/temoa/data_processing/database_util.py similarity index 84% rename from temoa/data_processing/DatabaseUtil.py rename to temoa/data_processing/database_util.py index c2b5b7cce..3ae3f6381 100644 --- a/temoa/data_processing/DatabaseUtil.py +++ b/temoa/data_processing/database_util.py @@ -1,3 +1,12 @@ +""" +Utility class for interacting with a Temoa scenario database (SQLite). + +This module provides the DatabaseUtil class to abstract the database connection +and querying process. It offers methods to retrieve specific data slices +such as technologies, commodities, capacity, and flows for given scenarios, +periods, and regions. +""" + import os import re import sqlite3 @@ -6,7 +15,22 @@ import pandas as pd -class DatabaseUtil(object): +class DatabaseUtil: + """ + A utility to connect to and query a Temoa SQLite database. + + This class provides methods to extract data from the database, handling + connection management and query construction. It can be used as a context + manager to ensure database connections are closed properly. + + Args: + database_path (str or Path): The file path to the SQLite database. + scenario (Optional[str]): The specific scenario to query within the database. + + Raises: + ValueError: If the database path does not exist or if connecting fails. + """ + def __init__(self, databasePath, scenario=None): self.database = os.path.abspath(databasePath) self.scenario = scenario @@ -20,8 +44,8 @@ def __init__(self, databasePath, scenario=None): self.con.text_factory = ( str # this ensures data is explored with the correct UTF-8 encoding ) - except Exception: - raise ValueError('Unable to connect to database') + except sqlite3.Error as e: + raise ValueError(f'Unable to connect to database: {e}') from e elif self.database.endswith('.dat'): raise ValueError('Reading .dat files is no longer supported') @@ -82,7 +106,7 @@ def readFromDatFile(self, inp_comm, inp_tech): ) return result[['input_comm', 'tech', 'output_comm']] - def getTimePeridosForFlags(self, flags=[]): + def getTimePeridosForFlags(self, flags=None): if self.cur is None: raise ValueError('Invalid Operation For dat file') query = '' @@ -101,7 +125,7 @@ def getTimePeridosForFlags(self, flags=[]): return result - def getTechnologiesForFlags(self, flags=[]): + def getTechnologiesForFlags(self, flags=None): if self.cur is None: raise ValueError('Invalid Operation For dat file') query = '' @@ -136,7 +160,7 @@ def getCommoditiesAndTech(self, inp_comm, inp_tech, region): else: inp_tech = "'" + inp_tech + "'" - if region == None: + if region is None: self.cur.execute( 'SELECT input_comm, tech, output_comm FROM Efficiency WHERE input_comm is ' + inp_comm @@ -174,7 +198,7 @@ def getExistingTechnologiesForCommodity(self, comm, region, comm_type='input'): result = pd.DataFrame(self.cur.fetchall(), columns=['tech']) return result - def getCommoditiesForFlags(self, flags=[]): + def getCommoditiesForFlags(self, flags=None): if self.cur is None: raise ValueError('Invalid Operation For dat file') query = '' @@ -337,34 +361,34 @@ def getCommodityWiseInputAndOutputFlow(self, tech, period, region): query = ( "SELECT OF.input_comm, OF.output_comm, OF.vintage, OF.region,\ - SUM(OF.vflow_in) vflow_in, SUM(OFO.vflow_out) vflow_out, OC.capacity \ -FROM (SELECT region, scenario, sector, period, input_comm, tech, vintage, output_comm, sum(flow) AS vflow_in \ - FROM OutputFlowIn GROUP BY region, scenario, sector, period, input_comm, tech, vintage, output_comm) AS OF \ -INNER JOIN (SELECT region, scenario, sector, period, input_comm, tech, vintage, output_comm, sum(flow) AS vflow_out \ - FROM OutputFlowOut GROUP BY region, scenario, sector, period, input_comm, tech, vintage, output_comm) AS OFO \ -ON \ - OF.region = OFO.region AND \ - OF.scenario = OFO.scenario AND \ - OF.period = OFO.period AND \ - OF.tech = OFO.tech AND \ - OF.input_comm = OFO.input_comm AND \ - OF.vintage = OFO.vintage AND \ - OF.output_comm = OFO.output_comm \ -INNER JOIN \ - OutputNetCapacity OC \ -ON \ - OF.region = OC.region AND \ - OF.scenario = OC.scenario AND \ - OF.tech = OC.tech AND \ - OF.vintage = OC.vintage \ -WHERE \ - OF.period ='" + SUM(OF.vflow_in) vflow_in, SUM(OFO.vflow_out) vflow_out, OC.capacity \ + FROM (SELECT region, scenario, sector, period, input_comm, tech, vintage, output_comm, sum(flow) AS vflow_in \ + FROM OutputFlowIn GROUP BY region, scenario, sector, period, input_comm, tech, vintage, output_comm) AS OF \ + INNER JOIN (SELECT region, scenario, sector, period, input_comm, tech, vintage, output_comm, sum(flow) AS vflow_out \ + FROM OutputFlowOut GROUP BY region, scenario, sector, period, input_comm, tech, vintage, output_comm) AS OFO \ + ON \ + OF.region = OFO.region AND \ + OF.scenario = OFO.scenario AND \ + OF.period = OFO.period AND \ + OF.tech = OFO.tech AND \ + OF.input_comm = OFO.input_comm AND \ + OF.vintage = OFO.vintage AND \ + OF.output_comm = OFO.output_comm \ + INNER JOIN \ + OutputNetCapacity OC \ + ON \ + OF.region = OC.region AND \ + OF.scenario = OC.scenario AND \ + OF.tech = OC.tech AND \ + OF.vintage = OC.vintage \ + WHERE \ + OF.period ='" + str(period) + "' AND \ - OF.tech is '" + OF.tech is '" + tech + "' AND \ - OF.scenario is '" + OF.scenario is '" + self.scenario + "'" ) diff --git a/temoa/data_processing/DB_to_Excel.py b/temoa/data_processing/db_to_excel.py similarity index 87% rename from temoa/data_processing/DB_to_Excel.py rename to temoa/data_processing/db_to_excel.py index 8460d0545..acf3a19a3 100644 --- a/temoa/data_processing/DB_to_Excel.py +++ b/temoa/data_processing/db_to_excel.py @@ -1,3 +1,16 @@ +""" +This script processes a Temoa database file (SQLite) and converts the data +into two Excel formats: one for human-readable analysis and another +compatible with the pyam library for integrated assessment modeling. + +The script extracts capacity, activity, emissions, and cost data for a +specified scenario, formats it, and saves it to separate sheets in an +Excel workbook. It also creates an aggregated `pyam`-compatible Excel file. + +Usage: + python db_to_excel.py -i -s [-o ] +""" + import getopt import itertools import re @@ -11,13 +24,9 @@ def make_excel(ifile, ofile: Path, scenario): if ifile is None: - raise "You did not specify the input file, remember to use '-i' option" - print( - 'Use as :\n python DB_to_Excel.py -i (Optional -o )\n Use -h for help.' - ) - sys.exit(2) - else: - file_type = re.search(r'(\w+)\.(\w+)\b', ifile) # Extract the input filename and extension + raise ValueError("You did not specify the input file. Remember to use the '-i' option.") + + file_type = re.search(r'(\w+)\.(\w+)\b', ifile) # Extract the input filename and extension if not file_type: print('The file type %s is not recognized. Use a db file.' % ifile) sys.exit(2) @@ -45,7 +54,7 @@ def make_excel(ifile, ofile: Path, scenario): ) query = 'SELECT DISTINCT Efficiency.region, Efficiency.tech, Technology.sector FROM Efficiency \ - INNER JOIN Technology ON Efficiency.tech=Technology.tech' + INNER JOIN Technology ON Efficiency.tech=Technology.tech' all_techs = pd.read_sql_query(query, con) query = f"SELECT region, tech, sector, period, sum(capacity) as capacity FROM OutputNetCapacity WHERE scenario= '{scenario}' GROUP BY region, tech, sector, period" @@ -74,7 +83,7 @@ def make_excel(ifile, ofile: Path, scenario): "SELECT region, tech, sector, period, sum(flow) as vflow_out FROM OutputFlowOut WHERE scenario='" + scenario + "' GROUP BY \ - region, tech, sector, period" + region, tech, sector, period" ) df_activity = pd.read_sql_query(query, con) for sector in sorted(df_activity['sector'].unique()): @@ -99,13 +108,13 @@ def make_excel(ifile, ofile: Path, scenario): query = ( 'SELECT DISTINCT EmissionActivity.region, EmissionActivity.tech, EmissionActivity.emis_comm, Technology.sector FROM EmissionActivity \ - INNER JOIN Technology ON EmissionActivity.tech=Technology.tech' + INNER JOIN Technology ON EmissionActivity.tech=Technology.tech' ) try: all_emis_techs = pd.read_sql_query(query, con) - except: - all_emis_techs = {} - + except sqlite3.OperationalError: + all_emis_techs = pd.DataFrame() + query = ( "SELECT region, tech, sector, period, emis_comm, sum(emission) as emissions FROM OutputEmission WHERE scenario='" + scenario @@ -155,7 +164,7 @@ def make_excel(ifile, ofile: Path, scenario): for col, val in enumerate(df_costs.columns): worksheet.write(0, col, val, header_format) - writer._save() + writer.close() # prepare results for IamDataFrame df_emissions_raw['scenario'] = scenario @@ -204,8 +213,8 @@ def get_data(inputs): ofile = None scenario = set() - if inputs is None: - raise 'no arguments found' + if not inputs: + raise ValueError('No arguments found') for opt, arg in inputs.items(): if opt in ('-i', '--input'): @@ -216,7 +225,7 @@ def get_data(inputs): scenario.add(arg) elif opt in ('-h', '--help'): print( - 'Use as :\n python DB_to_Excel.py -i (Optional -o )\n Use -h for help.' + 'Use as :\n python db_to_excel.py -i (Optional -o )\n Use -h for help.' ) sys.exit() @@ -229,7 +238,7 @@ def get_data(inputs): opts, args = getopt.getopt(argv, 'hi:o:s:', ['help', 'input=', 'output=', 'scenario=']) except getopt.GetoptError: print( - "Something's Wrong. Use as :\n python DB_to_Excel.py -i (Optional -o )\n Use -h for help." + "Something's Wrong. Use as :\n python db_to_excel.py -i (Optional -o )\n Use -h for help." ) sys.exit(2) diff --git a/temoa/data_processing/GraphVizFormats.py b/temoa/data_processing/graphviz_formats.py similarity index 71% rename from temoa/data_processing/GraphVizFormats.py rename to temoa/data_processing/graphviz_formats.py index 799363b40..a517e1bba 100644 --- a/temoa/data_processing/GraphVizFormats.py +++ b/temoa/data_processing/graphviz_formats.py @@ -13,10 +13,10 @@ subgraph unused_techs { node [ - color = "%(unused_color)s", - fontcolor = "%(unusedfont_color)s", - shape = "box", - fontcolor = "%(font_color)s" + color = "%(unused_color)s", + fontcolor = "%(unusedfont_color)s", + shape = "box", + fontcolor = "%(font_color)s" ] ; %(dtechs)s @@ -24,10 +24,10 @@ subgraph unused_energy_carriers { node [ - color = "%(unused_color)s", - fontcolor = "%(unusedfont_color)s", - shape = "circle", - fillcolor = "%(fill_color)s" + color = "%(unused_color)s", + fontcolor = "%(unusedfont_color)s", + shape = "circle", + fillcolor = "%(fill_color)s" ] ; %(dcarriers)s @@ -35,10 +35,10 @@ subgraph unused_emissions { node [ - color = "%(unused_color)s", - fontcolor = "%(unusedfont_color)s", - shape = "circle", - fillcolor = "%(fill_color)s" + color = "%(unused_color)s", + fontcolor = "%(unusedfont_color)s", + shape = "circle", + fillcolor = "%(fill_color)s" ] %(demissions)s @@ -46,11 +46,10 @@ subgraph in_use_techs { node [ - color = "%(tech_color)s", - fontcolor = "%(usedfont_color)s", - shape = "box" - fontcolor = "%(font_color)s" - + color = "%(tech_color)s", + fontcolor = "%(usedfont_color)s", + shape = "box", + fontcolor = "%(font_color)s" ] ; %(etechs)s @@ -58,10 +57,10 @@ subgraph in_use_energy_carriers { node [ - color = "%(commodity_color)s", - fontcolor = "%(usedfont_color)s", - shape = "circle", - fillcolor = "%(fill_color)s" + color = "%(commodity_color)s", + fontcolor = "%(usedfont_color)s", + shape = "circle", + fillcolor = "%(fill_color)s" ] ; %(ecarriers)s @@ -69,10 +68,10 @@ subgraph in_use_emissions { node [ - color = "%(commodity_color)s", - fontcolor = "%(usedfont_color)s", - shape = "circle", - fillcolor = "%(fill_color)s" + color = "%(commodity_color)s", + fontcolor = "%(usedfont_color)s", + shape = "circle", + fillcolor = "%(fill_color)s" ] ; %(eemissions)s @@ -97,7 +96,7 @@ %(eflowso)s } } - + {rank = same; %(xnodes)s} } """ @@ -129,10 +128,10 @@ subgraph energy_carriers { node [ - color = "%(commodity_color)s", - fontcolor = "%(usedfont_color)s", - shape = "circle", - fillcolor = "%(fill_color)s" + color = "%(commodity_color)s", + fontcolor = "%(usedfont_color)s", + shape = "circle", + fillcolor = "%(fill_color)s" ] ; %(enodes)s @@ -178,10 +177,10 @@ subgraph energy_carriers { node [ - color = "%(commodity_color)s", - fontcolor = "%(usedfont_color)s", - shape = "circle", - fillcolor = "%(fill_color)s" + color = "%(commodity_color)s", + fontcolor = "%(usedfont_color)s", + shape = "circle", + fillcolor = "%(fill_color)s" ] ; %(enodes)s @@ -212,13 +211,13 @@ node [ shape="box", style="filled", fontcolor="%(font_color)s" ] ; edge [ - arrowhead = "vee", - fontsize = "8", - label = " ", - labelfloat = "False", - labelfontcolor = "lightgreen" - len = "2", - weight = "0.5", + arrowhead = "vee", + fontsize = "8", + label = " ", + labelfloat = "False", + labelfontcolor = "lightgreen" + len = "2", + weight = "0.5", ] ; %(resource_node)s @@ -282,7 +281,7 @@ %(oedges)s } - + {rank = same; %(snodes)s} } """ diff --git a/temoa/data_processing/GraphVizUtil.py b/temoa/data_processing/graphviz_util.py similarity index 98% rename from temoa/data_processing/GraphVizUtil.py rename to temoa/data_processing/graphviz_util.py index 9871ed34c..fd6511634 100644 --- a/temoa/data_processing/GraphVizUtil.py +++ b/temoa/data_processing/graphviz_util.py @@ -195,7 +195,7 @@ def create_text_nodes(nodes, indent=1): # Step 3: create each node, and place string representation in a set to # guarantee uniqueness q = '"%s"' # enforce quoting for all nodes - gviz = set(nfmt_attr.format(q % n, a) for n, a in nodes if a) + gviz = {nfmt_attr.format(q % n, a) for n, a in nodes if a} gviz.update(nfmt_noa.format(q % n) for n, a in nodes if not a) # Step 4: return a sorted version of nodes, as a single string @@ -231,7 +231,7 @@ def create_text_edges(edges, indent=1): # Step 3: add each edge to a set (to guarantee unique entries only) q = '"%s"' # enforce quoting for all tokens - gviz = set(efmt_attr.format(q % i, q % t, a) for i, t, a in edges if a) + gviz = {efmt_attr.format(q % i, q % t, a) for i, t, a in edges if a} gviz.update(efmt_noa.format(q % i, q % t) for i, t, a in edges if not a) # Step 4: return a sorted version of the edges, as a single string diff --git a/temoa/data_processing/MakeGraphviz.py b/temoa/data_processing/make_graphviz.py similarity index 96% rename from temoa/data_processing/MakeGraphviz.py rename to temoa/data_processing/make_graphviz.py index 82aa60e69..262749ba4 100644 --- a/temoa/data_processing/MakeGraphviz.py +++ b/temoa/data_processing/make_graphviz.py @@ -2,17 +2,17 @@ import sys from subprocess import call -from DatabaseUtil import DatabaseUtil -from GraphVizFormats import ( - results_dot_fmt, - tech_results_dot_fmt, +from database_util import DatabaseUtil +from graphviz_formats import ( commodity_dot_fmt, quick_run_dot_fmt, + results_dot_fmt, + tech_results_dot_fmt, ) -from GraphVizUtil import create_text_nodes, create_text_edges, getColorConfig, processInput +from graphviz_util import create_text_edges, create_text_nodes, getColorConfig, processInput -class GraphvizDiagramGenerator(object): +class GraphvizDiagramGenerator: def __init__(self, dbFile, scenario=None, region=None, outDir='.', verbose=1): self.dbFile = dbFile self.qName = os.path.splitext(os.path.basename(self.dbFile))[0] @@ -92,10 +92,6 @@ def CreateMainResultsDiagram(self, period, region, outputFormat='svg'): # self.__log__('CreateMainResultsDiagram: graph already exists at path, returning') # return self.outDir, outputName + '.' + outputFormat - time_exist = self.dbUtil.getTimePeridosForFlags(flags=['e']) - time_future = self.dbUtil.getTimePeridosForFlags(flags=['f']) - time_optimize = set(sorted(time_future)[:-1]) - tech_all = self.dbUtil.getTechnologiesForFlags(flags=['r', 'p', 'pb', 'ps']) commodity_carrier = self.dbUtil.getCommoditiesForFlags(flags=['d', 'p']) @@ -220,7 +216,7 @@ def CreateTechResultsDiagrams(self, period, region, tech, outputFormat='svg'): if not os.path.exists(os.path.join(self.outDir, self.folder['tech'])): os.makedirs(os.path.join(self.outDir, self.folder['tech'])) - outputName = os.path.join(self.folder['tech'], 'results_%s_%s' % (tech, period)) + outputName = os.path.join(self.folder['tech'], f'results_{tech}_{period}') if self.region: outputName += '_' + self.region outputName = os.path.join(self.outDir, outputName) @@ -293,7 +289,7 @@ def CreateCommodityPartialResults(self, period, region, comm, outputFormat='svg' if not os.path.exists(os.path.join(self.outDir, self.folder['comm'])): os.makedirs(os.path.join(self.outDir, self.folder['comm'])) - outputName = os.path.join(self.folder['comm'], 'rc_%s_%s' % (comm, period)) + outputName = os.path.join(self.folder['comm'], f'rc_{comm}_{period}') if self.region: outputName += '_' + self.region outputName = os.path.join(self.outDir, outputName) @@ -318,7 +314,7 @@ def CreateCommodityPartialResults(self, period, region, comm, outputFormat='svg' self.__log__('CreateCommodityPartialResults: database fetched successfully') - period_results_url_fmt = '../results/results%%s.%s' % outputFormat + # period_results_url_fmt = '../results/results%%s.%s' % outputFormat # node_attr_fmt = 'href="../results/results_%%s_%%s.%s"' % outputFormat # rc_node_fmt = 'color="%s", href="%s", shape="circle", fillcolor="%s", fontcolor="black"' diff --git a/temoa/data_processing/MakeOutputPlots.py b/temoa/data_processing/make_output_plots.py similarity index 98% rename from temoa/data_processing/MakeOutputPlots.py rename to temoa/data_processing/make_output_plots.py index c7b634136..71ff1d937 100644 --- a/temoa/data_processing/MakeOutputPlots.py +++ b/temoa/data_processing/make_output_plots.py @@ -4,10 +4,13 @@ import matplotlib matplotlib.use('Agg') -from matplotlib import pyplot as plt, cm as cmx, colors -import random -import os import argparse +import os +import random + +from matplotlib import cm as cmx +from matplotlib import colors +from matplotlib import pyplot as plt class OutputPlotGenerator: @@ -234,7 +237,7 @@ def get_random_color(self, pastel_factor=0.5): ] def color_distance(self, c1, c2): - return sum([abs(x[0] - x[1]) for x in zip(c1, c2)]) + return sum([abs(x[0] - x[1]) for x in zip(c1, c2, strict=False)]) def get_cmap(self, N): """Returns a function that maps each index in 0, 1, ... N-1 to a distinct @@ -251,7 +254,7 @@ def map_index_to_rgb_color(index): def generate_new_color(self, existing_colors, pastel_factor=0.5): max_distance = None best_color = None - for i in range(0, 100): + for _ in range(0, 100): color = self.get_random_color(pastel_factor=pastel_factor) if not existing_colors: return color @@ -270,7 +273,6 @@ def makeStackedBarPlot(self, data, xlabel, ylabel, xvar, title): data.pop(xvar, 0) stackedBars = data.keys() colorMapForBars = dict() - colors = [] plt.figure() cmap = self.get_cmap(len(stackedBars)) @@ -307,8 +309,6 @@ def make_line_plot(self, plot_var, label, title): techs = plot_var.keys() random.seed(10) color_map = dict() - colors = [] - width = 1.5 plt.figure() cmap = self.get_cmap(len(techs)) @@ -317,7 +317,6 @@ def make_line_plot(self, plot_var, label, title): # color_map[plot_var.keys()[i]]=colors[i] color_map[plot_var.keys()[i]] = cmap(i) - b = [0] * len(periods) for tech in techs: h = plt.plot(periods, plot_var[tech], color=color_map[tech], linestyle='--', marker='o') handles.append(h) diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index 9a073127e..a648bb4fd 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -1,29 +1,6 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 1/15/24 - +This module provides the MyopicSequencer class, which orchestrates the +process of solving a sequence of myopic optimization problems. """ import logging @@ -40,7 +17,7 @@ from temoa.core.config import TemoaConfig from temoa.core.model import TemoaModel from temoa.data_io.hybrid_loader import HybridLoader -from temoa.data_processing.DB_to_Excel import make_excel +from temoa.data_processing.db_to_excel import make_excel from temoa.extensions.myopic.myopic_index import MyopicIndex from temoa.extensions.myopic.myopic_progress_mapper import MyopicProgressMapper from temoa.model_checking.pricing_check import price_checker @@ -508,7 +485,7 @@ def execute_script(self, script_file: Path): A utility to execute a sql script on the current db connection :return: """ - with open(script_file, 'r') as table_script: + with open(script_file) as table_script: sql_commands = table_script.read() logger.debug('Executing sql from file: %s on connection: %s', script_file, self.output_con) self.cursor.executescript(sql_commands) @@ -527,15 +504,15 @@ def clear_old_results(self): f'DELETE FROM {table} WHERE scenario = ? OR scenario like ?', (scenario_name, f'{scenario_name}-%'), ) - except sqlite3.OperationalError: - SE.write(f'no scenario ref in table {table}\n') - raise sqlite3.OperationalError + except sqlite3.OperationalError as e: + SE.write(f'Could not clear scenario from table {table}.\n') + raise sqlite3.OperationalError from e for table in self.tables_without_scenario_reference: try: self.cursor.execute(f'DELETE FROM {table} WHERE 1') - except sqlite3.OperationalError: + except sqlite3.OperationalError as e: SE.write(f'Failed to clear table {table}.\n') - raise sqlite3.OperationalError + raise sqlite3.OperationalError from e self.output_con.commit() def clear_results_after(self, period): @@ -559,9 +536,9 @@ def clear_results_after(self, period): f'DELETE FROM {table} WHERE period >= (?) and scenario = (?)', (period, self.config.scenario), ) - except sqlite3.OperationalError: - SE.write(f'Failed trying to clear periods from table {table}\n') - raise sqlite3.OperationalError + except sqlite3.OperationalError as e: + SE.write(f'Failed to clear periods from table {table}.\n') + raise sqlite3.OperationalError from e # special case... new capacity has vintage only... self.cursor.execute( From 0466cc9c9a701b63b5348cce1c49972a7f2d85ea Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 28 Oct 2025 15:19:23 -0400 Subject: [PATCH 278/587] fixing naming in core and _internal --- pyproject.toml | 5 + temoa/_internal/exchange_tech_cost_ledger.py | 55 +- temoa/_internal/run_actions.py | 39 +- temoa/_internal/table_data_puller.py | 298 ++--- temoa/_internal/table_writer.py | 60 +- temoa/core/config.py | 4 +- temoa/core/model.py | 1011 +++++++++-------- temoa/extensions/method_of_morris/morris.py | 6 +- .../method_of_morris/morris_evaluate.py | 2 +- .../mga_sequencer.py | 2 +- temoa/extensions/myopic/myopic_sequencer.py | 12 +- 11 files changed, 783 insertions(+), 711 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 52dfabb10..10b8dfa17 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -84,11 +84,16 @@ select = [ "F", # pyflakes "I", # isort "B", # flake8-bugbear + "N", # flake8-naming ] ignore = [ "E501", # line too long temporarily ignored ] +[tool.ruff.lint.pep8-naming] +ignore-names = ["MGA", "SVMGA"] # Allow these names to violate naming conventions + + [tool.pytest.ini_options] minversion = "8.0" addopts = "-ra -q" diff --git a/temoa/_internal/exchange_tech_cost_ledger.py b/temoa/_internal/exchange_tech_cost_ledger.py index 5277e3d24..6e820c075 100644 --- a/temoa/_internal/exchange_tech_cost_ledger.py +++ b/temoa/_internal/exchange_tech_cost_ledger.py @@ -13,6 +13,7 @@ from pyomo.common.numeric_types import value from temoa.core.model import TemoaModel +from temoa.types.core_types import Period, Technology, Vintage if TYPE_CHECKING: from tests.utilities.namespace_mock import Namespace @@ -31,15 +32,21 @@ class CostType(Enum): class ExchangeTechCostLedger: - def __init__(self, M: Union[TemoaModel, 'Namespace']) -> None: + def __init__(self, model: Union[TemoaModel, 'Namespace']) -> None: self.cost_records: dict[CostType, dict[tuple[str, str, str, int, int], float]] = ( defaultdict(dict) ) # could be a Namespace for testing purposes... See the related test - self.M = M + self.M = model def add_cost_record( - self, link: str, period: int, tech: str, vintage: int, cost: float, cost_type: CostType + self, + link: str, + period: Period, + tech: Technology, + vintage: Vintage, + cost: float, + cost_type: CostType, ) -> None: """ add a cost associated with an exchange tech @@ -52,7 +59,7 @@ def add_cost_record( self.cost_records[cost_type][r1, r2, tech, vintage, period] = cost def get_use_ratio( - self, exporter: str, importer: str, period: int, tech: str, vintage: int + self, exporter: str, importer: str, period: Period, tech: Technology, vintage: Vintage ) -> float: """ use flow to calculate the use ratio for these 2 entities for cost apportioning purposes @@ -65,50 +72,50 @@ def get_use_ratio( """ # Cast to TemoaModel for type checking - at runtime this will be either TemoaModel or Namespace # Both have the same attributes, but mypy doesn't know about Namespace's dynamic attributes - M = cast(TemoaModel, self.M) + model = cast(TemoaModel, self.M) # need to temporarily reconstitute the names rr1 = '-'.join([exporter, importer]) rr2 = '-'.join([importer, exporter]) if any( ( - period >= vintage + value(M.LifetimeProcess[rr1, tech, vintage]), - period >= vintage + value(M.LifetimeProcess[rr2, tech, vintage]), + period >= vintage + value(model.LifetimeProcess[rr1, tech, vintage]), + period >= vintage + value(model.LifetimeProcess[rr2, tech, vintage]), period < vintage, ) ): raise ValueError('received a bogus cost for an illegal period.') - if tech not in M.tech_annual: + if tech not in model.tech_annual: act_dir1 = value( sum( - M.V_FlowOut[rr1, period, s, d, S_i, tech, vintage, S_o] - for s in M.TimeSeason[period] - for d in M.time_of_day - for S_i in M.processInputs[rr1, period, tech, vintage] - for S_o in M.processOutputsByInput[rr1, period, tech, vintage, S_i] + model.V_FlowOut[rr1, period, s, d, S_i, tech, vintage, S_o] + for s in model.TimeSeason[period] + for d in model.time_of_day + for S_i in model.processInputs[rr1, period, tech, vintage] + for S_o in model.processOutputsByInput[rr1, period, tech, vintage, S_i] ) ) act_dir2 = value( sum( - M.V_FlowOut[rr2, period, s, d, S_i, tech, vintage, S_o] - for s in M.TimeSeason[period] - for d in M.time_of_day - for S_i in M.processInputs[rr2, period, tech, vintage] - for S_o in M.processOutputsByInput[rr2, period, tech, vintage, S_i] + model.V_FlowOut[rr2, period, s, d, S_i, tech, vintage, S_o] + for s in model.TimeSeason[period] + for d in model.time_of_day + for S_i in model.processInputs[rr2, period, tech, vintage] + for S_o in model.processOutputsByInput[rr2, period, tech, vintage, S_i] ) ) else: act_dir1 = value( sum( - M.V_FlowOutAnnual[rr1, period, S_i, tech, vintage, S_o] - for S_i in M.processInputs[rr1, period, tech, vintage] - for S_o in M.processOutputsByInput[rr1, period, tech, vintage, S_i] + model.V_FlowOutAnnual[rr1, period, S_i, tech, vintage, S_o] + for S_i in model.processInputs[rr1, period, tech, vintage] + for S_o in model.processOutputsByInput[rr1, period, tech, vintage, S_i] ) ) act_dir2 = value( sum( - M.V_FlowOutAnnual[rr2, period, S_i, tech, vintage, S_o] - for S_i in M.processInputs[rr2, period, tech, vintage] - for S_o in M.processOutputsByInput[rr2, period, tech, vintage, S_i] + model.V_FlowOutAnnual[rr2, period, S_i, tech, vintage, S_o] + for S_i in model.processInputs[rr2, period, tech, vintage] + for S_o in model.processOutputsByInput[rr2, period, tech, vintage, S_i] ) ) diff --git a/temoa/_internal/run_actions.py b/temoa/_internal/run_actions.py index 11ec66c85..068cb7ae7 100644 --- a/temoa/_internal/run_actions.py +++ b/temoa/_internal/run_actions.py @@ -31,7 +31,6 @@ import sys from logging import getLogger from pathlib import Path -from sys import stderr as SE from sys import version_info from time import time @@ -104,7 +103,7 @@ def check_database_version(config: TemoaConfig, db_major_reqd: int, min_db_minor logger.error( 'Database does not appear to have MetaData table with required versioning info. See schema for v3+.' ) - SE.write( + sys.stderr.write( 'Database does not appear to have MetaData table with required. Is this version 3+ compatible?\n' 'If required, see dox on using the database migrator to move to v3.' ) @@ -151,8 +150,8 @@ def build_instance( hack = time() if not silent: - SE.write('[ ] Creating model instance.') - SE.flush() + sys.stderr.write('[ ] Creating model instance.') + sys.stderr.flush() logger.info('Started creating model instance from data') instance = model.create_instance(loaded_portal, name=model_name) if not silent: @@ -165,20 +164,20 @@ def build_instance( for line in f ) if warnings_found: - SE.write( + sys.stderr.write( '\r[%8.2f] Instance created with warnings. Check log file.\n' % (time() - hack) ) else: - SE.write( + sys.stderr.write( '\r[%8.2f] Instance created. \n' % (time() - hack) ) # needs spaces to clear previous line - SE.flush() + sys.stderr.flush() except Exception: - SE.write( + sys.stderr.write( '\r[%8.2f] Instance created. \n' % (time() - hack) ) # needs spaces to clear previous line - SE.flush() + sys.stderr.flush() logger.info('Finished creating model instance from data') # save LP if requested @@ -241,8 +240,8 @@ def solve_instance( hack = time() if not silent: - SE.write('[ ] Solving.') - SE.flush() + sys.stderr.write('[ ] Solving.') + sys.stderr.flush() logger.info( 'Starting the solve process using %s solver on model %s', solver_name, instance.name @@ -317,7 +316,7 @@ def solve_instance( logger.error( 'Solver reported termination condition (if any): %s', result['Solution'].Status ) - SE.write('solver failure. See log file.') + sys.stderr.write('solver failure. See log file.') sys.exit(-1) if check_optimal_termination(result): @@ -330,8 +329,8 @@ def solve_instance( logger.debug('Solver results: \n %s', result.solver) if not silent: - SE.write('\r[%8.2f] Model solved.\n' % (time() - hack)) - SE.flush() + sys.stderr.write('\r[%8.2f] Model solved.\n' % (time() - hack)) + sys.stderr.flush() return instance, result @@ -362,13 +361,13 @@ def handle_results( if not config.silent: msg = '[ ] Calculating reporting variables and formatting results.' # yield 'Calculating reporting variables and formatting results.' - SE.write(msg) - SE.flush() + sys.stderr.write(msg) + sys.stderr.flush() table_writer = TableWriter(config=config) if config.save_duals: table_writer.write_results( - M=instance, + model=instance, results_with_duals=results, save_storage_levels=config.save_storage_levels, append=append, @@ -376,17 +375,17 @@ def handle_results( ) else: table_writer.write_results( - M=instance, + model=instance, append=append, save_storage_levels=config.save_storage_levels, iteration=iteration, ) if not config.silent: - SE.write( + sys.stderr.write( '\r[%8.2f] Results processed. \n' % (time() - hack) ) - SE.flush() + sys.stderr.flush() if config.save_excel: scenario_name = ( diff --git a/temoa/_internal/table_data_puller.py b/temoa/_internal/table_data_puller.py index 8e83b5d94..448b19f0b 100644 --- a/temoa/_internal/table_data_puller.py +++ b/temoa/_internal/table_data_puller.py @@ -64,7 +64,7 @@ def rpetv(fi: FI, e: str) -> tuple[str, int, str, str, int]: return fi.r, fi.p, e, fi.t, fi.v -def poll_capacity_results(M: TemoaModel, epsilon: float = 1e-5) -> CapData: +def poll_capacity_results(model: TemoaModel, epsilon: float = 1e-5) -> CapData: """ Poll a solved model for capacity results. :param M: Solved Model @@ -73,9 +73,9 @@ def poll_capacity_results(M: TemoaModel, epsilon: float = 1e-5) -> CapData: """ # Built Capacity built = [] - for r, t, v in M.V_NewCapacity.keys(): - if v in M.time_optimize: - val = value(M.V_NewCapacity[r, t, v]) + for r, t, v in model.V_NewCapacity.keys(): + if v in model.time_optimize: + val = value(model.V_NewCapacity[r, t, v]) if abs(val) < epsilon: continue new_cap = (r, t, v, val) @@ -83,8 +83,8 @@ def poll_capacity_results(M: TemoaModel, epsilon: float = 1e-5) -> CapData: # NetCapacity net = [] - for r, p, t, v in M.V_Capacity.keys(): - val = value(M.V_Capacity[r, p, t, v]) + for r, p, t, v in model.V_Capacity.keys(): + val = value(model.V_Capacity[r, p, t, v]) if abs(val) < epsilon: continue new_net_cap = (r, p, t, v, val) @@ -92,14 +92,14 @@ def poll_capacity_results(M: TemoaModel, epsilon: float = 1e-5) -> CapData: # Retired Capacity ret = [] - for r, t, v in M.retirementPeriods: - lifetime = value(M.LifetimeProcess[r, t, v]) - for p in M.retirementPeriods[r, t, v]: + for r, t, v in model.retirementPeriods: + lifetime = value(model.LifetimeProcess[r, t, v]) + for p in model.retirementPeriods[r, t, v]: # We want to output period retirement, not annual retirement, so multiply by PeriodLength - eol = value(M.PeriodLength[p]) * value(M.V_AnnualRetirement[r, p, t, v]) + eol = value(model.PeriodLength[p]) * value(model.V_AnnualRetirement[r, p, t, v]) early = 0 - if t in M.tech_retirement and v < p <= v + lifetime - value(M.PeriodLength[p]): - early = value(M.V_RetiredCapacity[r, p, t, v]) + if t in model.tech_retirement and v < p <= v + lifetime - value(model.PeriodLength[p]): + early = value(model.V_RetiredCapacity[r, p, t, v]) eol -= early early = 0 if abs(early) < epsilon else early eol = 0 if abs(eol) < epsilon else eol @@ -111,7 +111,7 @@ def poll_capacity_results(M: TemoaModel, epsilon: float = 1e-5) -> CapData: return CapData(built=built, net=net, retired=ret) -def poll_flow_results(M: TemoaModel, epsilon: float = 1e-5) -> dict[FI, dict[FlowType, float]]: +def poll_flow_results(model: TemoaModel, epsilon: float = 1e-5) -> dict[FI, dict[FlowType, float]]: """ Poll a solved model for flow results. :param M: A solved Model @@ -124,39 +124,39 @@ def poll_flow_results(M: TemoaModel, epsilon: float = 1e-5) -> dict[FI, dict[Flo # ---- NON-annual ---- # Storage, which has a unique v_flow_in (non-storage techs do not have this variable) - for key in M.V_FlowIn.keys(): + for key in model.V_FlowIn.keys(): fi = FI(*key) - flow = value(M.V_FlowIn[fi]) + flow = value(model.V_FlowIn[fi]) if abs(flow) < epsilon: continue res[fi][FlowType.IN] = flow - res[fi][FlowType.LOST] = (1 - get_variable_efficiency(M, *key)) * flow + res[fi][FlowType.LOST] = (1 - get_variable_efficiency(model, *key)) * flow # regular flows - for key in M.V_FlowOut.keys(): + for key in model.V_FlowOut.keys(): fi = FI(*key) - flow = value(M.V_FlowOut[fi]) + flow = value(model.V_FlowOut[fi]) if abs(flow) < epsilon: continue res[fi][FlowType.OUT] = flow - if fi.t not in M.tech_storage: # we can get the flow in by out/eff... - flow = value(M.V_FlowOut[fi]) / get_variable_efficiency(M, *key) + if fi.t not in model.tech_storage: # we can get the flow in by out/eff... + flow = value(model.V_FlowOut[fi]) / get_variable_efficiency(model, *key) res[fi][FlowType.IN] = flow - res[fi][FlowType.LOST] = (1 - get_variable_efficiency(M, *key)) * flow + res[fi][FlowType.LOST] = (1 - get_variable_efficiency(model, *key)) * flow # curtailment flows - for key in M.V_Curtailment.keys(): + for key in model.V_Curtailment.keys(): fi = FI(*key) - val = value(M.V_Curtailment[fi]) + val = value(model.V_Curtailment[fi]) if abs(val) < epsilon: continue res[fi][FlowType.CURTAIL] = val # flex techs. This will subtract the flex from their output flow IOT make OUT the "net" - for key in M.V_Flex.keys(): + for key in model.V_Flex.keys(): fi = FI(*key) - flow = value(M.V_Flex[fi]) + flow = value(model.V_Flex[fi]) if abs(flow) < epsilon: continue res[fi][FlowType.FLEX] = flow @@ -165,60 +165,64 @@ def poll_flow_results(M: TemoaModel, epsilon: float = 1e-5) -> dict[FI, dict[Flo # ---- annual ---- # basic annual flows - for r, p, i, t, v, o in M.V_FlowOutAnnual.keys(): + for r, p, i, t, v, o in model.V_FlowOutAnnual.keys(): # Make sure this isn't just a non-annual demand tech - if t not in M.tech_annual: + if t not in model.tech_annual: continue - for s in M.TimeSeason[p]: - for d in M.time_of_day: - if o in M.commodity_demand: - distribution = value(M.DemandSpecificDistribution[r, p, s, d, o]) + for s in model.TimeSeason[p]: + for d in model.time_of_day: + if o in model.commodity_demand: + distribution = value(model.DemandSpecificDistribution[r, p, s, d, o]) else: - distribution = value(M.SegFrac[p, s, d]) + distribution = value(model.SegFrac[p, s, d]) fi = FI(r, p, s, d, i, t, v, o) - flow = value(M.V_FlowOutAnnual[r, p, i, t, v, o]) * distribution + flow = value(model.V_FlowOutAnnual[r, p, i, t, v, o]) * distribution if abs(flow) < epsilon: continue res[fi][FlowType.OUT] = flow - res[fi][FlowType.IN] = flow / value(M.Efficiency[ritvo(fi)]) - res[fi][FlowType.LOST] = (1 - value(M.Efficiency[ritvo(fi)])) * res[fi][FlowType.IN] + res[fi][FlowType.IN] = flow / value(model.Efficiency[ritvo(fi)]) + res[fi][FlowType.LOST] = (1 - value(model.Efficiency[ritvo(fi)])) * res[fi][ + FlowType.IN + ] # flex annual - for r, p, i, t, v, o in M.V_FlexAnnual.keys(): - for s in M.TimeSeason[p]: - for d in M.time_of_day: + for r, p, i, t, v, o in model.V_FlexAnnual.keys(): + for s in model.TimeSeason[p]: + for d in model.time_of_day: fi = FI(r, p, s, d, i, t, v, o) - flow = value(M.V_FlexAnnual[r, p, i, t, v, o]) * value(M.SegFrac[p, s, d]) + flow = value(model.V_FlexAnnual[r, p, i, t, v, o]) * value(model.SegFrac[p, s, d]) if abs(flow) < epsilon: continue res[fi][FlowType.FLEX] = flow res[fi][FlowType.OUT] -= flow # construction flows - for r, i, t, v in M.ConstructionInput.sparse_iterkeys(): + for r, i, t, v in model.ConstructionInput.sparse_iterkeys(): annual = ( - value(M.ConstructionInput[r, i, t, v]) - * value(M.V_NewCapacity[r, t, v]) - / value(M.PeriodLength[v]) + value(model.ConstructionInput[r, i, t, v]) + * value(model.V_NewCapacity[r, t, v]) + / value(model.PeriodLength[v]) ) - for s in M.TimeSeason[v]: - for d in M.time_of_day: + for s in model.TimeSeason[v]: + for d in model.time_of_day: fi = FI(r, v, s, d, i, t, v, 'ConstructionInput') - flow = annual * value(M.SegFrac[v, s, d]) + flow = annual * value(model.SegFrac[v, s, d]) if abs(flow) < epsilon: continue res[fi][FlowType.IN] = flow # end of life flows - for r, t, v, o in M.EndOfLifeOutput.sparse_iterkeys(): - if (r, t, v) not in M.retirementPeriods: + for r, t, v, o in model.EndOfLifeOutput.sparse_iterkeys(): + if (r, t, v) not in model.retirementPeriods: continue - for p in M.retirementPeriods[r, t, v]: - annual = value(M.EndOfLifeOutput[r, t, v, o]) * value(M.V_AnnualRetirement[r, p, t, v]) - for s in M.TimeSeason[p]: - for d in M.time_of_day: + for p in model.retirementPeriods[r, t, v]: + annual = value(model.EndOfLifeOutput[r, t, v, o]) * value( + model.V_AnnualRetirement[r, p, t, v] + ) + for s in model.TimeSeason[p]: + for d in model.time_of_day: fi = FI(r, p, s, d, 'EndOfLifeOutput', t, v, o) - flow = annual * value(M.SegFrac[p, s, d]) + flow = annual * value(model.SegFrac[p, s, d]) if abs(flow) < epsilon: continue res[fi][FlowType.OUT] = flow @@ -226,7 +230,7 @@ def poll_flow_results(M: TemoaModel, epsilon: float = 1e-5) -> dict[FI, dict[Flo return res -def poll_storage_level_results(M: TemoaModel, epsilon: float = 1e-5) -> dict[SLI, float]: +def poll_storage_level_results(model: TemoaModel, epsilon: float = 1e-5) -> dict[SLI, float]: """ Poll a solved model for flow results. :param M: A solved Model @@ -236,29 +240,29 @@ def poll_storage_level_results(M: TemoaModel, epsilon: float = 1e-5) -> dict[SLI res: dict[SLI, float] = defaultdict(float) # Storage level, the state variable for all but last time slice of each season - for r, p, s, d, t, v in M.StorageLevel_rpsdtv: - if t in M.tech_seasonal_storage: + for r, p, s, d, t, v in model.StorageLevel_rpsdtv: + if t in model.tech_seasonal_storage: continue - state = value(M.V_StorageLevel[r, p, s, d, t, v]) / ( - value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod) + state = value(model.V_StorageLevel[r, p, s, d, t, v]) / ( + value(model.SegFracPerSeason[p, s]) * value(model.DaysPerPeriod) ) sli = SLI(r, p, s, d, t, v) if abs(state) < epsilon: state = 0 # still want to know but decimals are ugly res[sli] = state - for r, p, s_seq, t, v in M.SeasonalStorageLevel_rpstv: - s = M.sequential_to_season[p, s_seq] + for r, p, s_seq, t, v in model.SeasonalStorageLevel_rpstv: + s = model.sequential_to_season[p, s_seq] # Ratio of days in virtual storage season to days in actual season # Flows and StorageLevel are normalised to the number of days in the ACTUAL season, so must # be adjusted to the number of days in the virtual storage season - days_adjust = value(M.TimeSeasonSequential[p, s_seq, s]) / ( - value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod) + days_adjust = value(model.TimeSeasonSequential[p, s_seq, s]) / ( + value(model.SegFracPerSeason[p, s]) * value(model.DaysPerPeriod) ) - for d in M.time_of_day: + for d in model.time_of_day: state = ( - value(M.V_SeasonalStorageLevel[r, p, s_seq, t, v]) - + value(M.V_StorageLevel[r, p, s, d, t, v]) * days_adjust + value(model.V_SeasonalStorageLevel[r, p, s_seq, t, v]) + + value(model.V_StorageLevel[r, p, s, d, t, v]) * days_adjust ) sli = SLI(r, p, s_seq, d, t, v) if abs(state) < epsilon: @@ -268,9 +272,9 @@ def poll_storage_level_results(M: TemoaModel, epsilon: float = 1e-5) -> dict[SLI return res -def poll_objective(M: TemoaModel) -> list[tuple[str, float]]: +def poll_objective(model: TemoaModel) -> list[tuple[str, float]]: """gather objective name, value tuples for all active objectives""" - objs: list[Objective] = list(M.component_data_objects(Objective)) + objs: list[Objective] = list(model.component_data_objects(Objective)) active_objs = [obj for obj in objs if obj.active] if len(active_objs) > 1: logger.warning('Multiple active objectives found. All will be logged in db') @@ -282,7 +286,7 @@ def poll_objective(M: TemoaModel) -> list[tuple[str, float]]: def poll_cost_results( - M: TemoaModel, p_0: int | None, epsilon: float = 1e-5 + model: TemoaModel, p_0: int | None, epsilon: float = 1e-5 ) -> tuple[ dict[tuple[str, int, str, int], dict[CostType, float]], dict[tuple[str, int, str, int], dict[CostType, float]], @@ -296,40 +300,40 @@ def poll_cost_results( """ p_0_true: int if p_0 is None: - p_0_true = min(M.time_optimize) + p_0_true = min(model.time_optimize) else: p_0_true = p_0 - p_e = M.time_future.last() + p_e = model.time_future.last() # conveniences... - GDR = value(M.GlobalDiscountRate) + global_discount_rate = value(model.GlobalDiscountRate) # MPL = M.ModelProcessLife - LLN = M.LoanLifetimeProcess + loan_lifetime_process = model.LoanLifetimeProcess - exchange_costs = ExchangeTechCostLedger(M) + exchange_costs = ExchangeTechCostLedger(model) entries: dict[tuple[str, int, str, int], dict[CostType, float]] = defaultdict(dict) - for r, t, v in M.CostInvest.sparse_iterkeys(): # Returns only non-zero values + for r, t, v in model.CostInvest.sparse_iterkeys(): # Returns only non-zero values # gather details... - cap = value(M.V_NewCapacity[r, t, v]) + cap = value(model.V_NewCapacity[r, t, v]) if abs(cap) < epsilon: continue - loan_life = value(LLN[r, t, v]) - loan_rate = value(M.LoanRate[r, t, v]) + loan_life = value(loan_lifetime_process[r, t, v]) + loan_rate = value(model.LoanRate[r, t, v]) - if M.isSurvivalCurveProcess[r, t, v]: + if model.isSurvivalCurveProcess[r, t, v]: model_loan_cost, undiscounted_cost = loan_costs_survival_curve( - M=M, + model=model, r=r, t=t, v=v, loan_rate=loan_rate, loan_life=loan_life, capacity=cap, - invest_cost=value(M.CostInvest[r, t, v]), + invest_cost=value(model.CostInvest[r, t, v]), p_0=p_0_true, p_e=p_e, - global_discount_rate=GDR, + global_discount_rate=global_discount_rate, vintage=v, ) else: @@ -337,11 +341,11 @@ def poll_cost_results( loan_rate=loan_rate, loan_life=loan_life, capacity=cap, - invest_cost=value(M.CostInvest[r, t, v]), - process_life=value(M.LifetimeProcess[r, t, v]), + invest_cost=value(model.CostInvest[r, t, v]), + process_life=value(model.LifetimeProcess[r, t, v]), p_0=p_0_true, p_e=p_e, - global_discount_rate=GDR, + global_discount_rate=global_discount_rate, vintage=v, ) # screen for linked region... @@ -368,19 +372,19 @@ def poll_cost_results( {CostType.D_INVEST: model_loan_cost, CostType.INVEST: undiscounted_cost} ) - for r, p, t, v in M.CostFixed.sparse_iterkeys(): - cap = value(M.V_Capacity[r, p, t, v]) + for r, p, t, v in model.CostFixed.sparse_iterkeys(): + cap = value(model.V_Capacity[r, p, t, v]) if abs(cap) < epsilon: continue - fixed_cost = value(M.CostFixed[r, p, t, v]) - undiscounted_fixed_cost = cap * fixed_cost * value(M.PeriodLength[p]) + fixed_cost = value(model.CostFixed[r, p, t, v]) + undiscounted_fixed_cost = cap * fixed_cost * value(model.PeriodLength[p]) model_fixed_cost = costs.fixed_or_variable_cost( cap, value(fixed_cost), - value(M.PeriodLength[p]), - GDR=GDR, + value(model.PeriodLength[p]), + GDR=global_discount_rate, P_0=float(p_0) if p_0 is not None else 0.0, p=p, ) @@ -409,32 +413,32 @@ def poll_cost_results( } ) - for r, p, t, v in M.CostVariable.sparse_iterkeys(): - if t not in M.tech_annual: + for r, p, t, v in model.CostVariable.sparse_iterkeys(): + if t not in model.tech_annual: activity = sum( - value(M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o]) - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day + value(model.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o]) + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] + for S_s in model.TimeSeason[p] + for S_d in model.time_of_day ) else: activity = sum( - value(M.V_FlowOutAnnual[r, p, S_i, t, v, S_o]) - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + value(model.V_FlowOutAnnual[r, p, S_i, t, v, S_o]) + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) if abs(activity) < epsilon: continue - var_cost = value(M.CostVariable[r, p, t, v]) - undiscounted_var_cost = activity * var_cost * value(M.PeriodLength[p]) + var_cost = value(model.CostVariable[r, p, t, v]) + undiscounted_var_cost = activity * var_cost * value(model.PeriodLength[p]) model_var_cost = costs.fixed_or_variable_cost( activity, var_cost, - value(M.PeriodLength[p]), - GDR=GDR, + value(model.PeriodLength[p]), + GDR=global_discount_rate, P_0=float(p_0) if p_0 is not None else 0.0, p=p, ) @@ -513,7 +517,7 @@ def loan_costs( def loan_costs_survival_curve( - M: TemoaModel, + model: TemoaModel, r: str, t: str, v: int, @@ -535,7 +539,7 @@ def loan_costs_survival_curve( # model uses for these costs loan_ar = costs.pv_to_annuity(rate=loan_rate, periods=int(loan_life)) model_ic = costs.loan_cost_survival_curve( - M, + model, r, t, v, @@ -550,7 +554,7 @@ def loan_costs_survival_curve( # Override the GDR to get the undiscounted value global_discount_rate = 0 undiscounted_cost = costs.loan_cost_survival_curve( - M, + model, r, t, v, @@ -566,7 +570,7 @@ def loan_costs_survival_curve( def poll_emissions( - M: TemoaModel, p_0: int | None = None, epsilon: float = 1e-5 + model: TemoaModel, p_0: int | None = None, epsilon: float = 1e-5 ) -> tuple[dict[tuple[str, int, str, int], dict[CostType, float]], dict[EI, float]]: """ Gather all emission flows, cost them and provide a tuple of costs and flows @@ -580,11 +584,11 @@ def poll_emissions( # see the note on emissions in the Cost function in temoa_rules p_0_true: int if p_0 is None: - p_0_true = min(M.time_optimize) + p_0_true = min(model.time_optimize) else: p_0_true = p_0 - GDR = value(M.GlobalDiscountRate) + global_discount_rate = value(model.GlobalDiscountRate) ########################### # Process Emissions @@ -592,31 +596,33 @@ def poll_emissions( base = [ (r, p, e, i, t, v, o) - for (r, e, i, t, v, o) in M.EmissionActivity.sparse_iterkeys() - for p in M.time_optimize - if (r, p, t, v) in M.processInputs + for (r, e, i, t, v, o) in model.EmissionActivity.sparse_iterkeys() + for p in model.time_optimize + if (r, p, t, v) in model.processInputs ] # The "base set" can be expanded now to cover normal/annual indexing sets normal = [ (r, p, e, s, d, i, t, v, o) for (r, p, e, i, t, v, o) in base - for s in M.TimeSeason[p] - for d in M.time_of_day - if t not in M.tech_annual + for s in model.TimeSeason[p] + for d in model.time_of_day + if t not in model.tech_annual ] - annual = [(r, p, e, i, t, v, o) for (r, p, e, i, t, v, o) in base if t in M.tech_annual] + annual = [(r, p, e, i, t, v, o) for (r, p, e, i, t, v, o) in base if t in model.tech_annual] flows: dict[EI, float] = defaultdict(float) # iterate through the normal and annual and accumulate flow values for r, p, e, s, d, i, t, v, o in normal: flows[EI(r, p, t, v, e)] += ( - value(M.V_FlowOut[r, p, s, d, i, t, v, o]) * M.EmissionActivity[r, e, i, t, v, o] + value(model.V_FlowOut[r, p, s, d, i, t, v, o]) + * model.EmissionActivity[r, e, i, t, v, o] ) for r, p, e, i, t, v, o in annual: flows[EI(r, p, t, v, e)] += ( - value(M.V_FlowOutAnnual[r, p, i, t, v, o]) * M.EmissionActivity[r, e, i, t, v, o] + value(model.V_FlowOutAnnual[r, p, i, t, v, o]) + * model.EmissionActivity[r, e, i, t, v, o] ) # gather costs @@ -629,16 +635,16 @@ def poll_emissions( continue # screen to see if there is an associated cost cost_index = (ei.r, ei.p, ei.e) - if cost_index not in M.CostEmission: + if cost_index not in model.CostEmission: continue undiscounted_emiss_cost = ( - flows[ei] * M.CostEmission[ei.r, ei.p, ei.e] * M.PeriodLength[ei.p] + flows[ei] * model.CostEmission[ei.r, ei.p, ei.e] * model.PeriodLength[ei.p] ) discounted_emiss_cost = costs.fixed_or_variable_cost( cap_or_flow=flows[ei], - cost_factor=value(M.CostEmission[ei.r, ei.p, ei.e]), - cost_years=M.PeriodLength[ei.p], - GDR=GDR, + cost_factor=value(model.CostEmission[ei.r, ei.p, ei.e]), + cost_years=model.PeriodLength[ei.p], + GDR=global_discount_rate, P_0=p_0_true, p=ei.p, ) @@ -651,12 +657,16 @@ def poll_emissions( # iterate through embodied flows embodied_flows: dict[EI, float] = defaultdict(float) - for r, e, t, v in M.EmissionEmbodied.sparse_iterkeys(): + for r, e, t, v in model.EmissionEmbodied.sparse_iterkeys(): embodied_flows[EI(r, v, t, v, e)] += value( - M.V_NewCapacity[r, t, v] * M.EmissionEmbodied[r, e, t, v] / M.PeriodLength[v] + model.V_NewCapacity[r, t, v] + * model.EmissionEmbodied[r, e, t, v] + / model.PeriodLength[v] ) # for embodied costs flows[EI(r, v, t, v, e)] += value( - M.V_NewCapacity[r, t, v] * M.EmissionEmbodied[r, e, t, v] / M.PeriodLength[v] + model.V_NewCapacity[r, t, v] + * model.EmissionEmbodied[r, e, t, v] + / model.PeriodLength[v] ) # add embodied to process emissions # add embodied costs to process costs @@ -667,20 +677,20 @@ def poll_emissions( continue # screen to see if there is an associated cost cost_index = (ei.r, ei.v, ei.e) - if cost_index not in M.CostEmission: + if cost_index not in model.CostEmission: continue undiscounted_emiss_cost = ( embodied_flows[ei] - * M.CostEmission[ei.r, ei.v, ei.e] - * M.PeriodLength[ei.v] # treat as fixed cost distributed over construction period + * model.CostEmission[ei.r, ei.v, ei.e] + * model.PeriodLength[ei.v] # treat as fixed cost distributed over construction period ) discounted_emiss_cost = costs.fixed_or_variable_cost( cap_or_flow=embodied_flows[ei], - cost_factor=value(M.CostEmission[ei.r, ei.v, ei.e]), - cost_years=M.PeriodLength[ + cost_factor=value(model.CostEmission[ei.r, ei.v, ei.e]), + cost_years=model.PeriodLength[ ei.v ], # treat as fixed cost distributed over construction period - GDR=GDR, + GDR=global_discount_rate, P_0=p_0_true, p=ei.v, ) @@ -693,15 +703,15 @@ def poll_emissions( # iterate through end of life flows eol_flows: dict[EI, float] = defaultdict(float) - for r, e, t, v in M.EmissionEndOfLife.sparse_iterkeys(): - if (r, t, v) not in M.retirementPeriods: + for r, e, t, v in model.EmissionEndOfLife.sparse_iterkeys(): + if (r, t, v) not in model.retirementPeriods: continue - for p in M.retirementPeriods[r, t, v]: + for p in model.retirementPeriods[r, t, v]: eol_flows[EI(r, p, t, v, e)] += value( - M.V_AnnualRetirement[r, p, t, v] * M.EmissionEndOfLife[r, e, t, v] + model.V_AnnualRetirement[r, p, t, v] * model.EmissionEndOfLife[r, e, t, v] ) # for eol costs flows[EI(r, p, t, v, e)] += value( - M.V_AnnualRetirement[r, p, t, v] * M.EmissionEndOfLife[r, e, t, v] + model.V_AnnualRetirement[r, p, t, v] * model.EmissionEndOfLife[r, e, t, v] ) # add eol to process emissions # add embodied costs to process costs @@ -712,20 +722,20 @@ def poll_emissions( continue # screen to see if there is an associated cost cost_index = (ei.r, ei.p, ei.e) - if cost_index not in M.CostEmission: + if cost_index not in model.CostEmission: continue undiscounted_emiss_cost = ( eol_flows[ei] - * M.CostEmission[ei.r, ei.p, ei.e] - * M.PeriodLength[ei.p] # treat as fixed cost distributed over retirement period + * model.CostEmission[ei.r, ei.p, ei.e] + * model.PeriodLength[ei.p] # treat as fixed cost distributed over retirement period ) discounted_emiss_cost = costs.fixed_or_variable_cost( cap_or_flow=eol_flows[ei], - cost_factor=value(M.CostEmission[ei.r, ei.p, ei.e]), - cost_years=M.PeriodLength[ + cost_factor=value(model.CostEmission[ei.r, ei.p, ei.e]), + cost_years=model.PeriodLength[ ei.p ], # treat as fixed cost distributed over retirement period - GDR=GDR, + GDR=global_discount_rate, P_0=p_0_true, p=ei.p, ) diff --git a/temoa/_internal/table_writer.py b/temoa/_internal/table_writer.py index 129802036..1ae2e81a3 100644 --- a/temoa/_internal/table_writer.py +++ b/temoa/_internal/table_writer.py @@ -106,7 +106,7 @@ def __init__(self, config: TemoaConfig, epsilon: float = 1e-5) -> None: def write_results( self, - M: TemoaModel, + model: TemoaModel, results_with_duals: SolverResults | None = None, save_storage_levels: bool = False, append: bool = False, @@ -124,30 +124,30 @@ def write_results( self.clear_scenario() if not self.tech_sectors: self._set_tech_sectors() - self.write_objective(M, iteration=iteration) - self.write_capacity_tables(M, iteration=iteration) + self.write_objective(model, iteration=iteration) + self.write_capacity_tables(model, iteration=iteration) # analyze the emissions to get the costs and flows if self.config.scenario_mode == TemoaMode.MYOPIC: - p_0 = M.MyopicDiscountingYear + p_0 = model.MyopicDiscountingYear else: p_0 = None # min year will be used in poll - e_costs, e_flows = poll_emissions(M=M, p_0=value(p_0)) + e_costs, e_flows = poll_emissions(model=model, p_0=value(p_0)) self.emission_register = e_flows self.write_emissions(iteration=iteration) - self.write_costs(M, emission_entries=e_costs, iteration=iteration) - self.flow_register = self.calculate_flows(M) - self.check_flow_balance(M) + self.write_costs(model, emission_entries=e_costs, iteration=iteration) + self.flow_register = self.calculate_flows(model) + self.check_flow_balance(model) self.write_flow_tables(iteration=iteration) if results_with_duals: # write the duals self.write_dual_variables(results_with_duals, iteration=iteration) if save_storage_levels: - self.write_storage_level(M, iteration=iteration) + self.write_storage_level(model, iteration=iteration) # catch-all self.con.commit() self.con.execute('VACUUM') - def write_mm_results(self, M: TemoaModel, iteration: int) -> None: + def write_mm_results(self, model: TemoaModel, iteration: int) -> None: """ tailored writer function for Method of Morris which: (a) appends data (so scenario needs to be cleared elsewhere @@ -159,9 +159,9 @@ def write_mm_results(self, M: TemoaModel, iteration: int) -> None: """ if not self.tech_sectors: self._set_tech_sectors() - self.write_objective(M, iteration=iteration) + self.write_objective(model, iteration=iteration) # analyze the emissions to get the costs and flows - e_costs, e_flows = poll_emissions(M=M) + e_costs, e_flows = poll_emissions(model=model) self.emission_register = e_flows self.write_emissions(iteration=iteration) self.con.commit() @@ -230,10 +230,10 @@ def clear_iterative_runs(self) -> None: pass self.con.commit() - def write_storage_level(self, M: TemoaModel, iteration: int | None = None) -> None: + def write_storage_level(self, model: TemoaModel, iteration: int | None = None) -> None: """Write the storage level table to the DB""" - storage_levels = poll_storage_level_results(M=M) + storage_levels = poll_storage_level_results(model=model) scenario_name = ( self.config.scenario + f'-{iteration}' @@ -254,9 +254,9 @@ def write_storage_level(self, M: TemoaModel, iteration: int | None = None) -> No self.con.executemany(qry, data) self.con.commit() - def write_objective(self, M: TemoaModel, iteration: int | None = None) -> None: + def write_objective(self, model: TemoaModel, iteration: int | None = None) -> None: """Write the value of all ACTIVE objectives to the DB""" - obj_vals = poll_objective(M=M) + obj_vals = poll_objective(model=model) self._insert_objective_results(obj_vals, iteration=iteration) def _insert_objective_results( @@ -352,9 +352,9 @@ def _insert_capacity_results(self, cap_data: CapData, iteration: int | None) -> self.con.executemany(qry, data_ret) self.con.commit() - def write_capacity_tables(self, M: TemoaModel, iteration: int | None = None) -> None: + def write_capacity_tables(self, model: TemoaModel, iteration: int | None = None) -> None: """Write the capacity tables to the DB""" - cap_data = poll_capacity_results(M=M) + cap_data = poll_capacity_results(model=model) self._insert_capacity_results(cap_data=cap_data, iteration=iteration) def write_flow_tables(self, iteration: int | None = None) -> None: @@ -395,7 +395,7 @@ def write_flow_tables(self, iteration: int | None = None) -> None: self.con.commit() - def write_summary_flow(self, M: TemoaModel, iteration: int | None = None) -> None: + def write_summary_flow(self, model: TemoaModel, iteration: int | None = None) -> None: """ This is normally called from MGA (other?) iterative solves where capturing the annual summary of flow out is desired vs. flows by season, tod for @@ -404,7 +404,7 @@ def write_summary_flow(self, M: TemoaModel, iteration: int | None = None) -> Non :param M: The solved model :return: None """ - flow_data = self.calculate_flows(M=M) + flow_data = self.calculate_flows(model=model) self._insert_summary_flow_results(flow_data=flow_data, iteration=iteration) def _insert_summary_flow_results( @@ -461,7 +461,7 @@ def _insert_summary_flow_results( # def poll_summary_flow_results( M:TemoaModel) -> dict: # flow_data = self.calculate_flows(M) - def check_flow_balance(self, M: TemoaModel) -> bool: + def check_flow_balance(self, model: TemoaModel) -> bool: """ An easy sanity check to ensure that the flow tables are balanced, except for storage and construction/end of life flows @@ -470,7 +470,7 @@ def check_flow_balance(self, M: TemoaModel) -> bool: all_good = True deltas = defaultdict(float) for fi in flows: - if fi.t in M.tech_storage: + if fi.t in model.tech_storage: continue if fi.i == 'EndOfLifeOutput': continue @@ -485,8 +485,8 @@ def check_flow_balance(self, M: TemoaModel) -> bool: flost = flows[fi][FlowType.LOST] # some identifiers tech = fi.t - flex_tech = fi.t in M.tech_flex - annual_tech = fi.t in M.tech_annual + flex_tech = fi.t in model.tech_flex + annual_tech = fi.t in model.tech_annual # ----- flow balance equation ----- deltas[fi] = fin - fout - flost - fflex @@ -523,13 +523,13 @@ def check_flow_balance(self, M: TemoaModel) -> bool: ) return all_good - def calculate_flows(self, M: TemoaModel) -> dict[FI, dict[FlowType, float]]: + def calculate_flows(self, model: TemoaModel) -> dict[FI, dict[FlowType, float]]: """Gather all flows by Flow Index and Type""" - return poll_flow_results(M, self.epsilon) + return poll_flow_results(model, self.epsilon) def write_costs( self, - M: TemoaModel, + model: TemoaModel, emission_entries: dict[tuple[str, int, str, int], dict[CostType, float]] | None = None, iteration: int | None = None, ) -> None: @@ -544,11 +544,11 @@ def write_costs( # P_0 is usually the first optimization year, but if running myopic, we could assign it via # table entry. Perhaps in future it is just always the first optimization year of the 1st iter. if self.config.scenario_mode == TemoaMode.MYOPIC: - p_0 = M.MyopicDiscountingYear + p_0 = model.MyopicDiscountingYear else: - p_0 = min(M.time_optimize) + p_0 = min(model.time_optimize) - entries, exchange_entries = poll_cost_results(M, value(p_0), self.epsilon) + entries, exchange_entries = poll_cost_results(model, value(p_0), self.epsilon) # write to table self._insert_cost_results(entries, exchange_entries, emission_entries, iteration) diff --git a/temoa/core/config.py b/temoa/core/config.py index 1f769b9c7..72dff879c 100644 --- a/temoa/core/config.py +++ b/temoa/core/config.py @@ -19,10 +19,10 @@ received this license file. If not, see . """ +import sys import tomllib from logging import getLogger from pathlib import Path -from sys import stderr as SE from temoa.core.modes import TemoaMode @@ -150,7 +150,7 @@ def __init__( ) logger.warning(msg) if not self.silent: - SE.write('Warning: ' + msg) + sys.stderr.write('Warning: ' + msg) @staticmethod def build_config(config_file: Path, output_path: Path, silent: bool = False) -> 'TemoaConfig': diff --git a/temoa/core/model.py b/temoa/core/model.py index d52f31f3b..1b2c202d7 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -60,7 +60,7 @@ logger = logging.getLogger(__name__) -def CreateSparseDicts(M: 'TemoaModel') -> None: +def create_sparse_dicts(model: 'TemoaModel') -> None: """ Creates and populates all sparse dictionaries and sets required for the model by calling component-specific precomputation functions. @@ -68,22 +68,22 @@ def CreateSparseDicts(M: 'TemoaModel') -> None: # Call the decomposed functions in logical order # 1. Populate core relationships from Efficiency table - technology.populate_core_dictionaries(M) + technology.populate_core_dictionaries(model) # 2. Classify technologies and commodities - commodities.create_technology_and_commodity_sets(M) + commodities.create_technology_and_commodity_sets(model) # 3. Create sets for specific components - operations.create_operational_vintage_sets(M) # For operations, storage, ramping - limits.create_limit_vintage_sets(M) # For limits - geography.create_geography_sets(M) # For geography/exchange - capacity.create_capacity_and_retirement_sets(M) # For capacity + operations.create_operational_vintage_sets(model) # For operations, storage, ramping + limits.create_limit_vintage_sets(model) # For limits + geography.create_geography_sets(model) # For geography/exchange + capacity.create_capacity_and_retirement_sets(model) # For capacity # 4. Create final aggregated sets for constraints - flows.create_commodity_balance_and_flow_sets(M) # For flows and commodities + flows.create_commodity_balance_and_flow_sets(model) # For flows and commodities # Final check for unused technologies - unused_techs = M.tech_all - M.used_techs + unused_techs = model.tech_all - model.used_techs if unused_techs: for tech in sorted(unused_techs): logger.warning( @@ -102,8 +102,8 @@ class TemoaModel(PyomoAbstractModel): # this is used in several places outside this class, and this provides no-build access to it default_lifetime_tech = 40 - def __init__(M, *args: object, **kwargs: object) -> None: - PyomoAbstractModel.__init__(M, *args, **kwargs) + def __init__(self, *args: object, **kwargs: object) -> None: + PyomoAbstractModel.__init__(self, *args, **kwargs) ################################################ # Internally used Data Containers # @@ -111,181 +111,184 @@ def __init__(M, *args: object, **kwargs: object) -> None: ################################################ # Dev Note: The triple-quotes UNDER the items below pop up as dox in most IDEs - M.processInputs: t.ProcessInputsDict = {} - M.processOutputs: t.ProcessOutputsDict = {} - M.processLoans: t.ProcessLoansDict = {} - M.activeFlow_rpsditvo: t.ActiveFlowSet = set() + self.processInputs: t.ProcessInputsDict = {} + self.processOutputs: t.ProcessOutputsDict = {} + self.processLoans: t.ProcessLoansDict = {} + self.activeFlow_rpsditvo: t.ActiveFlowSet = set() """a flow index for techs NOT in tech_annual""" - M.activeFlow_rpitvo: t.ActiveFlowAnnualSet = set() + self.activeFlow_rpitvo: t.ActiveFlowAnnualSet = set() """a flow index for techs in tech_annual only""" - M.activeFlex_rpsditvo: t.ActiveFlexSet = set() - M.activeFlex_rpitvo: t.ActiveFlexAnnualSet = set() - M.activeFlowInStorage_rpsditvo: t.ActiveFlowInStorageSet = set() - M.activeCurtailment_rpsditvo: t.ActiveCurtailmentSet = set() - M.activeActivity_rptv: t.ActiveActivitySet = set() - M.storageLevelIndices_rpsdtv: t.StorageLevelIndicesSet = set() - M.seasonalStorageLevelIndices_rpstv: t.SeasonalStorageLevelIndicesSet = set() + self.activeFlex_rpsditvo: t.ActiveFlexSet = set() + self.activeFlex_rpitvo: t.ActiveFlexAnnualSet = set() + self.activeFlowInStorage_rpsditvo: t.ActiveFlowInStorageSet = set() + self.activeCurtailment_rpsditvo: t.ActiveCurtailmentSet = set() + self.activeActivity_rptv: t.ActiveActivitySet = set() + self.storageLevelIndices_rpsdtv: t.StorageLevelIndicesSet = set() + self.seasonalStorageLevelIndices_rpstv: t.SeasonalStorageLevelIndicesSet = set() """currently available (within lifespan) (r, p, t, v) tuples (from M.processVintages)""" - M.activeRegionsForTech: t.ActiveRegionsForTechDict = {} + self.activeRegionsForTech: t.ActiveRegionsForTechDict = {} """currently available regions by period and tech {(p, t) : r}""" - M.newCapacity_rtv: t.NewCapacitySet = set() - M.activeCapacityAvailable_rpt: t.ActiveCapacityAvailableSet = set() - M.activeCapacityAvailable_rptv: t.ActiveCapacityAvailableVintageSet = set() - M.groupRegionActiveFlow_rpt: t.GroupRegionActiveFlowSet = ( + self.newCapacity_rtv: t.NewCapacitySet = set() + self.activeCapacityAvailable_rpt: t.ActiveCapacityAvailableSet = set() + self.activeCapacityAvailable_rptv: t.ActiveCapacityAvailableVintageSet = set() + self.groupRegionActiveFlow_rpt: t.GroupRegionActiveFlowSet = ( set() # Set of valid group-region, period, tech indices ) - M.commodityBalance_rpc: t.CommodityBalancedSet = ( + self.commodityBalance_rpc: t.CommodityBalancedSet = ( set() ) # Set of valid region-period-commodity indices to balance - M.commodityDStreamProcess: t.CommodityStreamProcessDict = {} # The downstream process of a commodity during a period - M.commodityUStreamProcess: t.CommodityStreamProcessDict = {} # The upstream process of a commodity during a period - M.capacityConsumptionTechs: t.CapacityConsumptionTechsDict = {} # New capacity consuming a commodity during a period [r,p,c] -> t - M.retirementProductionProcesses: t.RetirementProductionProcessesDict = {} # Retired capacity producing a commodity during a period [r,p,c] -> t,v - M.processInputsByOutput: t.ProcessInputsByOutputDict = {} - M.processOutputsByInput: t.ProcessOutputsByInputDict = {} - M.processTechs: t.ProcessTechsDict = {} - M.processReservePeriods: t.ProcessReservePeriodsDict = {} - M.processPeriods: t.ProcessPeriodsDict = {} # {(r, t, v): set(p)} - M.retirementPeriods: t.RetirementPeriodsDict = {} # {(r, t, v): set(p)} periods in which a process can economically or naturally retire - M.processVintages: t.ProcessVintagesDict = {} - M.survivalCurvePeriods: t.SurvivalCurvePeriodsDict = {} # {(r, t, v): set(p)} periods for which the process has a defined survival fraction + self.commodityDStreamProcess: t.CommodityStreamProcessDict = {} # The downstream process of a commodity during a period + self.commodityUStreamProcess: t.CommodityStreamProcessDict = {} # The upstream process of a commodity during a period + self.capacityConsumptionTechs: t.CapacityConsumptionTechsDict = {} # New capacity consuming a commodity during a period [r,p,c] -> t + self.retirementProductionProcesses: t.RetirementProductionProcessesDict = {} # Retired capacity producing a commodity during a period [r,p,c] -> t,v + self.processInputsByOutput: t.ProcessInputsByOutputDict = {} + self.processOutputsByInput: t.ProcessOutputsByInputDict = {} + self.processTechs: t.ProcessTechsDict = {} + self.processReservePeriods: t.ProcessReservePeriodsDict = {} + self.processPeriods: t.ProcessPeriodsDict = {} # {(r, t, v): set(p)} + self.retirementPeriods: t.RetirementPeriodsDict = {} # {(r, t, v): set(p)} periods in which a process can economically or naturally retire + self.processVintages: t.ProcessVintagesDict = {} + self.survivalCurvePeriods: t.SurvivalCurvePeriodsDict = {} # {(r, t, v): set(p)} periods for which the process has a defined survival fraction """current available (within lifespan) vintages {(r, p, t) : set(v)}""" - M.baseloadVintages: t.BaseloadVintagesDict = {} - M.curtailmentVintages: t.CurtailmentVintagesDict = {} - M.storageVintages: t.StorageVintagesDict = {} - M.rampUpVintages: t.RampUpVintagesDict = {} - M.rampDownVintages: t.RampDownVintagesDict = {} - M.inputSplitVintages: t.InputSplitVintagesDict = {} - M.inputSplitAnnualVintages: t.InputSplitAnnualVintagesDict = {} - M.outputSplitVintages: t.OutputSplitVintagesDict = {} - M.outputSplitAnnualVintages: t.OutputSplitAnnualVintagesDict = {} + self.baseloadVintages: t.BaseloadVintagesDict = {} + self.curtailmentVintages: t.CurtailmentVintagesDict = {} + self.storageVintages: t.StorageVintagesDict = {} + self.rampUpVintages: t.RampUpVintagesDict = {} + self.rampDownVintages: t.RampDownVintagesDict = {} + self.inputSplitVintages: t.InputSplitVintagesDict = {} + self.inputSplitAnnualVintages: t.InputSplitAnnualVintagesDict = {} + self.outputSplitVintages: t.OutputSplitVintagesDict = {} + self.outputSplitAnnualVintages: t.OutputSplitAnnualVintagesDict = {} # M.processByPeriodAndOutput = {} # not currently used - M.exportRegions: t.ExportRegionsDict = {} - M.importRegions: t.ImportRegionsDict = {} + self.exportRegions: t.ExportRegionsDict = {} + self.importRegions: t.ImportRegionsDict = {} # These establish time sequencing - M.time_next: t.TimeNextDict = {} # {(p, s, d): (s_next, d_next)} sequence of following time slices - M.time_next_sequential: t.TimeNextSequentialDict = {} # {(p, s_seq): (s_seq_next)} next virtual storage season - M.sequential_to_season: t.SequentialToSeasonDict = {} # {(p, s_seq): (s)} season matching this virtual storage season + self.time_next: t.TimeNextDict = {} # {(p, s, d): (s_next, d_next)} sequence of following time slices + self.time_next_sequential: t.TimeNextSequentialDict = {} # {(p, s_seq): (s_seq_next)} next virtual storage season + self.sequential_to_season: t.SequentialToSeasonDict = {} # {(p, s_seq): (s)} season matching this virtual storage season ################################################ # Switching Sets # # (to avoid slow searches in initialisation) # ################################################ - M.isEfficiencyVariable: t.EfficiencyVariableDict = {} # {(r, p, i, t, v, o): bool} which efficiencies have variable indexing - M.isCapacityFactorProcess: t.CapacityFactorProcessDict = {} # {(r, p, t, v): bool} which capacity factors have have period-vintage indexing - M.isSeasonalStorage: t.SeasonalStorageDict = {} # {t: bool} whether a storage tech is seasonal storage - M.isSurvivalCurveProcess: t.SurvivalCurveProcessDict = {} # {(r, t, v): bool} whether a process uses survival curves. + self.isEfficiencyVariable: t.EfficiencyVariableDict = {} # {(r, p, i, t, v, o): bool} which efficiencies have variable indexing + self.isCapacityFactorProcess: t.CapacityFactorProcessDict = {} # {(r, p, t, v): bool} which capacity factors have have period-vintage indexing + self.isSeasonalStorage: t.SeasonalStorageDict = {} # {t: bool} whether a storage tech is seasonal storage + self.isSurvivalCurveProcess: t.SurvivalCurveProcessDict = {} # {(r, t, v): bool} whether a process uses survival curves. ################################################ # Model Sets # # (used for indexing model elements) # ################################################ - M.progress_marker_1 = BuildAction(['Starting to build Sets'], rule=progress_check) + self.progress_marker_1 = BuildAction(['Starting to build Sets'], rule=progress_check) - M.operator = Set() + self.operator = Set() # Define time periods - M.time_exist = Set(ordered=True) - M.time_future = Set(ordered=True) - M.time_optimize = Set( - ordered=True, initialize=time.init_set_time_optimize, within=M.time_future + self.time_exist = Set(ordered=True) + self.time_future = Set(ordered=True) + self.time_optimize = Set( + ordered=True, initialize=time.init_set_time_optimize, within=self.time_future ) # Define time period vintages to track capacity installation - M.vintage_exist = Set(ordered=True, initialize=time.init_set_vintage_exist) - M.vintage_optimize = Set(ordered=True, initialize=time.init_set_vintage_optimize) - M.vintage_all = Set(initialize=M.time_exist | M.time_optimize) + self.vintage_exist = Set(ordered=True, initialize=time.init_set_vintage_exist) + self.vintage_optimize = Set(ordered=True, initialize=time.init_set_vintage_optimize) + self.vintage_all = Set(initialize=self.time_exist | self.time_optimize) # Perform some basic validation on the specified time periods. - M.validate_time = BuildAction(rule=time.validate_time) + self.validate_time = BuildAction(rule=time.validate_time) # Define the model time slices - M.time_season = Set(ordered=True, validate=no_slash_or_pipe) - M.time_season_sequential = Set(ordered=True, validate=no_slash_or_pipe) - M.TimeSeason = Set(M.time_optimize, within=M.time_season, ordered=True) - M.time_of_day = Set(ordered=True, validate=no_slash_or_pipe) + self.time_season = Set(ordered=True, validate=no_slash_or_pipe) + self.time_season_sequential = Set(ordered=True, validate=no_slash_or_pipe) + self.TimeSeason = Set(self.time_optimize, within=self.time_season, ordered=True) + self.time_of_day = Set(ordered=True, validate=no_slash_or_pipe) # This is just to get the TimeStorageSeason table sequentially. # There must be a better way but this works for now - M.ordered_season_sequential = Set( - dimen=3, within=M.time_optimize * M.time_season_sequential * M.time_season, ordered=True + self.ordered_season_sequential = Set( + dimen=3, + within=self.time_optimize * self.time_season_sequential * self.time_season, + ordered=True, ) # Define regions - M.regions = Set(validate=region_check) + self.regions = Set(validate=region_check) # RegionalIndices is the set of all the possible combinations of interregional exchanges # plus original region indices. If tech_exchange is empty, RegionalIndices =regions. - M.regionalIndices = Set(initialize=geography.CreateRegionalIndices) - M.regionalGlobalIndices = Set(validate=region_group_check) + self.regionalIndices = Set(initialize=geography.CreateRegionalIndices) + self.regionalGlobalIndices = Set(validate=region_group_check) # Define technology-related sets # M.tech_resource = Set() # not actually used by - M.tech_production = Set() - M.tech_all = Set( - initialize=M.tech_production, validate=no_slash_or_pipe + self.tech_production = Set() + self.tech_all = Set( + initialize=self.tech_production, validate=no_slash_or_pipe ) # was M.tech_resource | M.tech_production - M.tech_baseload = Set(within=M.tech_all) - M.tech_annual = Set(within=M.tech_all) - M.tech_demand = Set(within=M.tech_all) + self.tech_baseload = Set(within=self.tech_all) + self.tech_annual = Set(within=self.tech_all) + self.tech_demand = Set(within=self.tech_all) # annual storage not supported in Storage constraint or TableWriter, so exclude from domain - M.tech_storage = Set(within=M.tech_all) - M.tech_reserve = Set(within=M.tech_all) - M.tech_upramping = Set(within=M.tech_all) - M.tech_downramping = Set(within=M.tech_all) - M.tech_curtailment = Set(within=M.tech_all) - M.tech_flex = Set(within=M.tech_all) + self.tech_storage = Set(within=self.tech_all) + self.tech_reserve = Set(within=self.tech_all) + self.tech_upramping = Set(within=self.tech_all) + self.tech_downramping = Set(within=self.tech_all) + self.tech_curtailment = Set(within=self.tech_all) + self.tech_flex = Set(within=self.tech_all) # ensure there is no overlap flex <=> curtailable technologies - M.tech_exchange = Set(within=M.tech_all) + self.tech_exchange = Set(within=self.tech_all) # Define groups for technologies - M.tech_group_names = Set() - M.tech_group_members = Set(M.tech_group_names, within=M.tech_all) - M.tech_or_group = Set(initialize=M.tech_group_names | M.tech_all) + self.tech_group_names = Set() + self.tech_group_members = Set(self.tech_group_names, within=self.tech_all) + self.tech_or_group = Set(initialize=self.tech_group_names | self.tech_all) - M.tech_seasonal_storage = Set(within=M.tech_storage) + self.tech_seasonal_storage = Set(within=self.tech_storage) """storage technologies using the interseasonal storage feature""" - M.tech_uncap = Set(within=M.tech_all - M.tech_reserve) + self.tech_uncap = Set(within=self.tech_all - self.tech_reserve) """techs with unlimited capacity, ALWAYS available within lifespan""" - M.tech_exist = Set() + self.tech_exist = Set() """techs with existing capacity, want to keep these for accounting reasons""" - M.used_techs: set[Technology] = set() - """ track techs used in Efficiency table used in CreateSparseDicts """ + self.used_techs: set[Technology] = set() + """ track techs used in Efficiency table used in create_sparse_dicts """ # the below is a convenience for domain checking in params below that should not accept # uncap techs... - M.tech_with_capacity = Set(initialize=M.tech_all - M.tech_uncap) + self.tech_with_capacity = Set(initialize=self.tech_all - self.tech_uncap) """techs eligible for capacitization""" # Define techs for which economic retirement is an option # Note: Storage techs cannot (currently) be retired due to linkage to initialization # process, which is currently incapable of reducing initializations on retirements. # Note2: I think this has been fixed but I can't tell what the problem was. Suspect # it was the old StorageInit constraint - M.tech_retirement = Set(within=M.tech_with_capacity) # - M.tech_storage) + self.tech_retirement = Set(within=self.tech_with_capacity) # - M.tech_storage) - M.validate_techs = BuildAction(rule=validate_tech_sets) + self.validate_techs = BuildAction(rule=validate_tech_sets) # Define commodity-related sets - M.commodity_demand = Set() - M.commodity_emissions = Set() - M.commodity_physical = Set() - M.commodity_waste = Set() - M.commodity_flex = Set(within=M.commodity_physical) - M.commodity_source = Set(within=M.commodity_physical) - M.commodity_annual = Set(within=M.commodity_physical) - M.commodity_carrier = Set( - initialize=M.commodity_physical | M.commodity_demand | M.commodity_waste + self.commodity_demand = Set() + self.commodity_emissions = Set() + self.commodity_physical = Set() + self.commodity_waste = Set() + self.commodity_flex = Set(within=self.commodity_physical) + self.commodity_source = Set(within=self.commodity_physical) + self.commodity_annual = Set(within=self.commodity_physical) + self.commodity_carrier = Set( + initialize=self.commodity_physical | self.commodity_demand | self.commodity_waste ) - M.commodity_all = Set( - initialize=M.commodity_carrier | M.commodity_emissions, validate=no_slash_or_pipe + self.commodity_all = Set( + initialize=self.commodity_carrier | self.commodity_emissions, + validate=no_slash_or_pipe, ) ################################################ @@ -309,19 +312,19 @@ def __init__(M, *args: object, **kwargs: object) -> None: # --------------------------------------------------------------- # these "progress markers" report build progress in the log, if the level == debug - M.progress_marker_2 = BuildAction(['Starting to build Params'], rule=progress_check) + self.progress_marker_2 = BuildAction(['Starting to build Params'], rule=progress_check) - M.GlobalDiscountRate = Param(default=0.05) + self.GlobalDiscountRate = Param(default=0.05) # Define time-related parameters - M.PeriodLength = Param(M.time_optimize, initialize=time.ParamPeriodLength) - M.SegFrac = Param(M.time_optimize, M.time_season, M.time_of_day) - M.validate_SegFrac = BuildAction(rule=time.validate_SegFrac) - M.TimeSequencing = Set() # How do states carry between time segments? - M.TimeNext = Set( + self.PeriodLength = Param(self.time_optimize, initialize=time.ParamPeriodLength) + self.SegFrac = Param(self.time_optimize, self.time_season, self.time_of_day) + self.validate_SegFrac = BuildAction(rule=time.validate_SegFrac) + self.TimeSequencing = Set() # How do states carry between time segments? + self.TimeNext = Set( ordered=True ) # This is just to get data from the table. Hidden feature and usually not used - M.validate_TimeNext = BuildAction(rule=time.validate_TimeNext) + self.validate_TimeNext = BuildAction(rule=time.validate_TimeNext) # Define demand- and resource-related parameters # Dev Note: There does not appear to be a DB table supporting DemandDefaultDistro. @@ -330,18 +333,20 @@ def __init__(M, *args: object, **kwargs: object) -> None: # M.DemandDefaultDistribution = Param( # M.time_optimize, M.time_season, M.time_of_day, mutable=True # ) - M.DemandSpecificDistribution = Param( - M.regions, - M.time_optimize, - M.time_season, - M.time_of_day, - M.commodity_demand, + self.DemandSpecificDistribution = Param( + self.regions, + self.time_optimize, + self.time_season, + self.time_of_day, + self.commodity_demand, mutable=True, default=0, ) - M.DemandConstraint_rpc = Set(within=M.regions * M.time_optimize * M.commodity_demand) - M.Demand = Param(M.DemandConstraint_rpc) + self.DemandConstraint_rpc = Set( + within=self.regions * self.time_optimize * self.commodity_demand + ) + self.Demand = Param(self.DemandConstraint_rpc) # Dev Note: This parameter is currently NOT implemented. Preserved for later refactoring # LimitResource IS implemented but sums cumulatively for a technology rather than @@ -350,9 +355,9 @@ def __init__(M, *args: object, **kwargs: object) -> None: # M.ResourceBound = Param(M.ResourceConstraint_rpr) # Define technology performance parameters - M.CapacityToActivity = Param(M.regionalIndices, M.tech_all, default=1) + self.CapacityToActivity = Param(self.regionalIndices, self.tech_all, default=1) - M.ExistingCapacity = Param(M.regionalIndices, M.tech_exist, M.vintage_exist) + self.ExistingCapacity = Param(self.regionalIndices, self.tech_exist, self.vintage_exist) # Dev Note: The below is temporarily useful for passing down to validator to find # set violations @@ -363,236 +368,265 @@ def __init__(M, *args: object, **kwargs: object) -> None: # ) # devnote: need these here or CheckEfficiencyIndices may flag these commodities as unused - M.ConstructionInput = Param( - M.regions, M.commodity_physical, M.tech_with_capacity, M.vintage_optimize - ) - M.EndOfLifeOutput = Param( - M.regions, M.tech_with_capacity, M.vintage_all, M.commodity_carrier - ) - - M.Efficiency = Param( - M.regionalIndices, - M.commodity_physical, - M.tech_all, - M.vintage_all, - M.commodity_carrier, + self.ConstructionInput = Param( + self.regions, + self.commodity_physical, + self.tech_with_capacity, + self.vintage_optimize, + ) + self.EndOfLifeOutput = Param( + self.regions, self.tech_with_capacity, self.vintage_all, self.commodity_carrier + ) + + self.Efficiency = Param( + self.regionalIndices, + self.commodity_physical, + self.tech_all, + self.vintage_all, + self.commodity_carrier, within=NonNegativeReals, validate=validate_Efficiency, ) - M.validate_UsedEfficiencyIndices = BuildAction(rule=technology.CheckEfficiencyIndices) - - M.EfficiencyVariable = Param( - M.regionalIndices, - M.time_optimize, - M.time_season, - M.time_of_day, - M.commodity_physical, - M.tech_all, - M.vintage_all, - M.commodity_carrier, + self.validate_UsedEfficiencyIndices = BuildAction(rule=technology.CheckEfficiencyIndices) + + self.EfficiencyVariable = Param( + self.regionalIndices, + self.time_optimize, + self.time_season, + self.time_of_day, + self.commodity_physical, + self.tech_all, + self.vintage_all, + self.commodity_carrier, within=NonNegativeReals, default=1, ) - M.LifetimeTech = Param( - M.regionalIndices, M.tech_all, default=TemoaModel.default_lifetime_tech + self.LifetimeTech = Param( + self.regionalIndices, self.tech_all, default=TemoaModel.default_lifetime_tech ) - M.LifetimeProcess_rtv = Set(dimen=3, initialize=technology.LifetimeProcessIndices) - M.LifetimeProcess = Param( - M.LifetimeProcess_rtv, default=technology.get_default_process_lifetime + self.LifetimeProcess_rtv = Set(dimen=3, initialize=technology.LifetimeProcessIndices) + self.LifetimeProcess = Param( + self.LifetimeProcess_rtv, default=technology.get_default_process_lifetime ) - M.LifetimeSurvivalCurve = Param( - M.regionalIndices, + self.LifetimeSurvivalCurve = Param( + self.regionalIndices, Integers, - M.tech_all, - M.vintage_all, + self.tech_all, + self.vintage_all, default=technology.get_default_survival, validate=validate_0to1, mutable=True, ) - M.Create_SurvivalCurve = BuildAction(rule=technology.CreateSurvivalCurve) + self.Create_SurvivalCurve = BuildAction(rule=technology.CreateSurvivalCurve) - M.LoanLifetimeProcess_rtv = Set(dimen=3, initialize=costs.LifetimeLoanProcessIndices) + self.LoanLifetimeProcess_rtv = Set(dimen=3, initialize=costs.LifetimeLoanProcessIndices) # Dev Note: The LoanLifetimeProcess table *could* be removed. There is no longer a # supporting table in the database. It is just a "passthrough" now to the # default LoanLifetimeTech. It is already stitched in to the model, # so will leave it for now. Table may be revived. - M.LoanLifetimeProcess = Param(M.LoanLifetimeProcess_rtv, default=costs.get_loan_life) + self.LoanLifetimeProcess = Param(self.LoanLifetimeProcess_rtv, default=costs.get_loan_life) - M.LimitTechInputSplit = Param( - M.regions, - M.time_optimize, - M.commodity_physical, - M.tech_all, - M.operator, + self.LimitTechInputSplit = Param( + self.regions, + self.time_optimize, + self.commodity_physical, + self.tech_all, + self.operator, validate=validate_0to1, ) - M.LimitTechInputSplitAnnual = Param( - M.regions, - M.time_optimize, - M.commodity_physical, - M.tech_all, - M.operator, + self.LimitTechInputSplitAnnual = Param( + self.regions, + self.time_optimize, + self.commodity_physical, + self.tech_all, + self.operator, validate=validate_0to1, ) - M.LimitTechOutputSplit = Param( - M.regions, - M.time_optimize, - M.tech_all, - M.commodity_carrier, - M.operator, + self.LimitTechOutputSplit = Param( + self.regions, + self.time_optimize, + self.tech_all, + self.commodity_carrier, + self.operator, validate=validate_0to1, ) - M.LimitTechOutputSplitAnnual = Param( - M.regions, - M.time_optimize, - M.tech_all, - M.commodity_carrier, - M.operator, + self.LimitTechOutputSplitAnnual = Param( + self.regions, + self.time_optimize, + self.tech_all, + self.commodity_carrier, + self.operator, validate=validate_0to1, ) - M.RenewablePortfolioStandardConstraint_rpg = Set( - within=M.regions * M.time_optimize * M.tech_group_names + self.RenewablePortfolioStandardConstraint_rpg = Set( + within=self.regions * self.time_optimize * self.tech_group_names ) - M.RenewablePortfolioStandard = Param( - M.RenewablePortfolioStandardConstraint_rpg, validate=validate_0to1 + self.RenewablePortfolioStandard = Param( + self.RenewablePortfolioStandardConstraint_rpg, validate=validate_0to1 ) # These need to come before validate_SeasonSequential - M.RampUpHourly = Param(M.regions, M.tech_upramping, validate=validate_0to1) - M.RampDownHourly = Param(M.regions, M.tech_downramping, validate=validate_0to1) + self.RampUpHourly = Param(self.regions, self.tech_upramping, validate=validate_0to1) + self.RampDownHourly = Param(self.regions, self.tech_downramping, validate=validate_0to1) # Set up representation of time - M.DaysPerPeriod = Param() - M.SegFracPerSeason = Param( - M.time_optimize, M.time_season, initialize=time.SegFracPerSeason_rule + self.DaysPerPeriod = Param() + self.SegFracPerSeason = Param( + self.time_optimize, self.time_season, initialize=time.SegFracPerSeason_rule ) - M.TimeSeasonSequential = Param( - M.time_optimize, M.time_season_sequential, M.time_season, mutable=True + self.TimeSeasonSequential = Param( + self.time_optimize, self.time_season_sequential, self.time_season, mutable=True ) - M.validate_SeasonSequential = BuildAction(rule=time.CreateTimeSeasonSequential) - M.Create_TimeSequence = BuildAction(rule=time.CreateTimeSequence) + self.validate_SeasonSequential = BuildAction(rule=time.CreateTimeSeasonSequential) + self.Create_TimeSequence = BuildAction(rule=time.CreateTimeSequence) # The method below creates a series of helper functions that are used to # perform the sparse matrix of indexing for the parameters, variables, and # equations below. - M.Create_SparseDicts = BuildAction(rule=CreateSparseDicts) - M.initialize_Demands = BuildAction(rule=commodities.CreateDemands) + self.Create_SparseDicts = BuildAction(rule=create_sparse_dicts) + self.initialize_Demands = BuildAction(rule=commodities.CreateDemands) - M.CapacityFactor_rpsdt = Set(dimen=5, initialize=capacity.CapacityFactorTechIndices) - M.CapacityFactorTech = Param(M.CapacityFactor_rpsdt, default=1, validate=validate_0to1) + self.CapacityFactor_rpsdt = Set(dimen=5, initialize=capacity.CapacityFactorTechIndices) + self.CapacityFactorTech = Param( + self.CapacityFactor_rpsdt, default=1, validate=validate_0to1 + ) # Dev note: using a default function below alleviates need to make this set. # M.CapacityFactor_rsdtv = Set(dimen=5, initialize=CapacityFactorProcessIndices) - M.CapacityFactorProcess = Param( - M.regionalIndices, - M.time_optimize, - M.time_season, - M.time_of_day, - M.tech_with_capacity, - M.vintage_all, + self.CapacityFactorProcess = Param( + self.regionalIndices, + self.time_optimize, + self.time_season, + self.time_of_day, + self.tech_with_capacity, + self.vintage_all, # validate=validate_CapacityFactorProcess, # opting for a quicker validation, just 0->1 validate=validate_0to1, default=capacity.get_default_capacity_factor, # slow but only called if a value is missing ) - M.CapacityConstraint_rpsdtv = Set(dimen=6, initialize=capacity.CapacityConstraintIndices) - M.initialize_CapacityFactors = BuildAction(rule=capacity.CheckCapacityFactorProcess) - M.initialize_EfficiencyVariable = BuildAction(rule=technology.CheckEfficiencyVariable) + self.CapacityConstraint_rpsdtv = Set(dimen=6, initialize=capacity.CapacityConstraintIndices) + self.initialize_CapacityFactors = BuildAction(rule=capacity.CheckCapacityFactorProcess) + self.initialize_EfficiencyVariable = BuildAction(rule=technology.CheckEfficiencyVariable) # Define technology cost parameters # dev note: the CostFixed_rptv isn't truly needed, but it is included in a constraint, so # let it go for now - M.CostFixed_rptv = Set(dimen=4, initialize=costs.CostFixedIndices) - M.CostFixed = Param(M.CostFixed_rptv) + self.CostFixed_rptv = Set(dimen=4, initialize=costs.CostFixedIndices) + self.CostFixed = Param(self.CostFixed_rptv) - M.CostInvest_rtv = Set(within=M.regionalIndices * M.tech_all * M.time_optimize) - M.CostInvest = Param(M.CostInvest_rtv) + self.CostInvest_rtv = Set(within=self.regionalIndices * self.tech_all * self.time_optimize) + self.CostInvest = Param(self.CostInvest_rtv) - M.DefaultLoanRate = Param(domain=NonNegativeReals) - M.LoanRate = Param( - M.CostInvest_rtv, domain=NonNegativeReals, default=costs.get_default_loan_rate + self.DefaultLoanRate = Param(domain=NonNegativeReals) + self.LoanRate = Param( + self.CostInvest_rtv, domain=NonNegativeReals, default=costs.get_default_loan_rate ) - M.LoanAnnualize = Param(M.CostInvest_rtv, initialize=costs.ParamLoanAnnualize_rule) + self.LoanAnnualize = Param(self.CostInvest_rtv, initialize=costs.ParamLoanAnnualize_rule) - M.CostVariable_rptv = Set(dimen=4, initialize=costs.CostVariableIndices) - M.CostVariable = Param(M.CostVariable_rptv) + self.CostVariable_rptv = Set(dimen=4, initialize=costs.CostVariableIndices) + self.CostVariable = Param(self.CostVariable_rptv) - M.CostEmission_rpe = Set(within=M.regions * M.time_optimize * M.commodity_emissions) - M.CostEmission = Param(M.CostEmission_rpe) + self.CostEmission_rpe = Set( + within=self.regions * self.time_optimize * self.commodity_emissions + ) + self.CostEmission = Param(self.CostEmission_rpe) # devnote: no longer used # M.ModelProcessLife_rptv = Set(dimen=4, initialize=ModelProcessLifeIndices) # M.ModelProcessLife = Param(M.ModelProcessLife_rptv, initialize=ParamModelProcessLife_rule) - M.ProcessLifeFrac_rptv = Set(dimen=4, initialize=technology.ModelProcessLifeIndices) - M.ProcessLifeFrac = Param( - M.ProcessLifeFrac_rptv, initialize=technology.ParamProcessLifeFraction_rule + self.ProcessLifeFrac_rptv = Set(dimen=4, initialize=technology.ModelProcessLifeIndices) + self.ProcessLifeFrac = Param( + self.ProcessLifeFrac_rptv, initialize=technology.ParamProcessLifeFraction_rule ) - M.LimitCapacityConstraint_rpt = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_or_group * M.operator + self.LimitCapacityConstraint_rpt = Set( + within=self.regionalGlobalIndices + * self.time_optimize + * self.tech_or_group + * self.operator ) - M.LimitCapacity = Param(M.LimitCapacityConstraint_rpt) + self.LimitCapacity = Param(self.LimitCapacityConstraint_rpt) - M.LimitNewCapacityConstraint_rpt = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_or_group * M.operator + self.LimitNewCapacityConstraint_rpt = Set( + within=self.regionalGlobalIndices + * self.time_optimize + * self.tech_or_group + * self.operator ) - M.LimitNewCapacity = Param(M.LimitNewCapacityConstraint_rpt) + self.LimitNewCapacity = Param(self.LimitNewCapacityConstraint_rpt) - M.LimitResourceConstraint_rt = Set( - within=M.regionalGlobalIndices * M.tech_or_group * M.operator + self.LimitResourceConstraint_rt = Set( + within=self.regionalGlobalIndices * self.tech_or_group * self.operator ) - M.LimitResource = Param(M.LimitResourceConstraint_rt) + self.LimitResource = Param(self.LimitResourceConstraint_rt) - M.LimitActivityConstraint_rpt = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.tech_or_group * M.operator + self.LimitActivityConstraint_rpt = Set( + within=self.regionalGlobalIndices + * self.time_optimize + * self.tech_or_group + * self.operator ) - M.LimitActivity = Param(M.LimitActivityConstraint_rpt) + self.LimitActivity = Param(self.LimitActivityConstraint_rpt) - M.LimitSeasonalCapacityFactorConstraint_rpst = Set( - within=M.regionalGlobalIndices - * M.time_optimize - * M.time_season - * M.tech_all - * M.operator + self.LimitSeasonalCapacityFactorConstraint_rpst = Set( + within=self.regionalGlobalIndices + * self.time_optimize + * self.time_season + * self.tech_all + * self.operator ) - M.LimitSeasonalCapacityFactor = Param( - M.LimitSeasonalCapacityFactorConstraint_rpst, validate=validate_0to1 + self.LimitSeasonalCapacityFactor = Param( + self.LimitSeasonalCapacityFactorConstraint_rpst, validate=validate_0to1 ) - M.LimitAnnualCapacityFactorConstraint_rpto = Set( - within=M.regionalGlobalIndices - * M.time_optimize - * M.tech_all - * M.commodity_carrier - * M.operator + self.LimitAnnualCapacityFactorConstraint_rpto = Set( + within=self.regionalGlobalIndices + * self.time_optimize + * self.tech_all + * self.commodity_carrier + * self.operator ) - M.LimitAnnualCapacityFactor = Param( - M.LimitAnnualCapacityFactorConstraint_rpto, validate=validate_0to1 + self.LimitAnnualCapacityFactor = Param( + self.LimitAnnualCapacityFactorConstraint_rpto, validate=validate_0to1 ) - M.LimitGrowthCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator) - M.LimitDegrowthCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator) - M.LimitGrowthNewCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator) - M.LimitDegrowthNewCapacity = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator) - M.LimitGrowthNewCapacityDelta = Param(M.regionalGlobalIndices, M.tech_or_group, M.operator) - M.LimitDegrowthNewCapacityDelta = Param( - M.regionalGlobalIndices, M.tech_or_group, M.operator + self.LimitGrowthCapacity = Param( + self.regionalGlobalIndices, self.tech_or_group, self.operator + ) + self.LimitDegrowthCapacity = Param( + self.regionalGlobalIndices, self.tech_or_group, self.operator + ) + self.LimitGrowthNewCapacity = Param( + self.regionalGlobalIndices, self.tech_or_group, self.operator + ) + self.LimitDegrowthNewCapacity = Param( + self.regionalGlobalIndices, self.tech_or_group, self.operator + ) + self.LimitGrowthNewCapacityDelta = Param( + self.regionalGlobalIndices, self.tech_or_group, self.operator + ) + self.LimitDegrowthNewCapacityDelta = Param( + self.regionalGlobalIndices, self.tech_or_group, self.operator ) - M.LimitEmissionConstraint_rpe = Set( - within=M.regionalGlobalIndices * M.time_optimize * M.commodity_emissions * M.operator + self.LimitEmissionConstraint_rpe = Set( + within=self.regionalGlobalIndices + * self.time_optimize + * self.commodity_emissions + * self.operator ) - M.LimitEmission = Param(M.LimitEmissionConstraint_rpe) - M.EmissionActivity_reitvo = Set(dimen=6, initialize=emissions.EmissionActivityIndices) - M.EmissionActivity = Param(M.EmissionActivity_reitvo) + self.LimitEmission = Param(self.LimitEmissionConstraint_rpe) + self.EmissionActivity_reitvo = Set(dimen=6, initialize=emissions.EmissionActivityIndices) + self.EmissionActivity = Param(self.EmissionActivity_reitvo) # devnote: deprecated when generalising tech/group columns in Limit tables # M.LimitActivityGroupConstraint_rpg = Set( @@ -611,32 +645,32 @@ def __init__(M, *args: object, **kwargs: object) -> None: # M.LimitNewCapacityGroup = Param(M.LimitNewCapacityGroupConstraint_rpg) # M.GroupShareIndices = Set(dimen=5, initialize=GroupShareIndices) # doesn't feel worth it - M.LimitCapacityShareConstraint_rpgg = Set( - within=M.regionalGlobalIndices - * M.time_optimize - * M.tech_or_group - * M.tech_or_group - * M.operator + self.LimitCapacityShareConstraint_rpgg = Set( + within=self.regionalGlobalIndices + * self.time_optimize + * self.tech_or_group + * self.tech_or_group + * self.operator ) - M.LimitCapacityShare = Param(M.LimitCapacityShareConstraint_rpgg) + self.LimitCapacityShare = Param(self.LimitCapacityShareConstraint_rpgg) - M.LimitActivityShareConstraint_rpgg = Set( - within=M.regionalGlobalIndices - * M.time_optimize - * M.tech_or_group - * M.tech_or_group - * M.operator + self.LimitActivityShareConstraint_rpgg = Set( + within=self.regionalGlobalIndices + * self.time_optimize + * self.tech_or_group + * self.tech_or_group + * self.operator ) - M.LimitActivityShare = Param(M.LimitActivityShareConstraint_rpgg) + self.LimitActivityShare = Param(self.LimitActivityShareConstraint_rpgg) - M.LimitNewCapacityShareConstraint_rpgg = Set( - within=M.regionalGlobalIndices - * M.time_optimize - * M.tech_or_group - * M.tech_or_group - * M.operator + self.LimitNewCapacityShareConstraint_rpgg = Set( + within=self.regionalGlobalIndices + * self.time_optimize + * self.tech_or_group + * self.tech_or_group + * self.operator ) - M.LimitNewCapacityShare = Param(M.LimitNewCapacityShareConstraint_rpgg) + self.LimitNewCapacityShare = Param(self.LimitNewCapacityShareConstraint_rpgg) # devnote: deprecated when generalising tech/group columns in Limit tables # M.TwoGroupShareIndices = Set(dimen=5, initialize=TwoGroupShareIndices) @@ -648,51 +682,55 @@ def __init__(M, *args: object, **kwargs: object) -> None: # M.LimitActivityGroupShare = Param(M.TwoGroupShareIndices) # This set works for all storage-related constraints - M.StorageConstraints_rpsdtv = Set(dimen=6, initialize=storage.StorageConstraintIndices) - M.SeasonalStorageConstraints_rpsdtv = Set( + self.StorageConstraints_rpsdtv = Set(dimen=6, initialize=storage.StorageConstraintIndices) + self.SeasonalStorageConstraints_rpsdtv = Set( dimen=6, initialize=storage.SeasonalStorageConstraintIndices ) - M.LimitStorageFractionConstraint_rpsdtv = Set( - within=(M.StorageConstraints_rpsdtv | M.SeasonalStorageConstraints_rpsdtv) * M.operator + self.LimitStorageFractionConstraint_rpsdtv = Set( + within=(self.StorageConstraints_rpsdtv | self.SeasonalStorageConstraints_rpsdtv) + * self.operator ) - M.LimitStorageFraction = Param( - M.LimitStorageFractionConstraint_rpsdtv, validate=validate_0to1 + self.LimitStorageFraction = Param( + self.LimitStorageFractionConstraint_rpsdtv, validate=validate_0to1 ) # Storage duration is expressed in hours - M.StorageDuration = Param(M.regions, M.tech_storage, default=4) + self.StorageDuration = Param(self.regions, self.tech_storage, default=4) - M.LinkedTechs = Param(M.regionalIndices, M.tech_all, M.commodity_emissions) + self.LinkedTechs = Param(self.regionalIndices, self.tech_all, self.commodity_emissions) # Define parameters associated with electric sector operation - M.ReserveMarginMethod = Set() # How contributions to the reserve margin are calculated - M.CapacityCredit = Param( - M.regionalIndices, - M.time_optimize, - M.tech_reserve, - M.vintage_all, + self.ReserveMarginMethod = Set() # How contributions to the reserve margin are calculated + self.CapacityCredit = Param( + self.regionalIndices, + self.time_optimize, + self.tech_reserve, + self.vintage_all, default=0, validate=validate_0to1, ) - M.ReserveCapacityDerate = Param( - M.regionalIndices, - M.time_optimize, - M.time_season, - M.tech_reserve, - M.vintage_all, + self.ReserveCapacityDerate = Param( + self.regionalIndices, + self.time_optimize, + self.time_season, + self.tech_reserve, + self.vintage_all, default=1, validate=validate_0to1, ) - M.PlanningReserveMargin = Param(M.regions) + self.PlanningReserveMargin = Param(self.regions) - M.EmissionEmbodied = Param( - M.regions, M.commodity_emissions, M.tech_with_capacity, M.vintage_optimize + self.EmissionEmbodied = Param( + self.regions, + self.commodity_emissions, + self.tech_with_capacity, + self.vintage_optimize, ) - M.EmissionEndOfLife = Param( - M.regions, M.commodity_emissions, M.tech_with_capacity, M.vintage_all + self.EmissionEndOfLife = Param( + self.regions, self.commodity_emissions, self.tech_with_capacity, self.vintage_all ) - M.MyopicDiscountingYear = Param(default=0) + self.MyopicDiscountingYear = Param(default=0) ################################################ # Model Variables # @@ -708,57 +746,63 @@ def __init__(M, *args: object, **kwargs: object) -> None: # summed over. # --------------------------------------------------------------- - M.progress_marker_3 = BuildAction(['Starting to build Variables'], rule=progress_check) + self.progress_marker_3 = BuildAction(['Starting to build Variables'], rule=progress_check) # Define base decision variables - M.FlowVar_rpsditvo = Set(dimen=8, initialize=flows.FlowVariableIndices) - M.V_FlowOut = Var(M.FlowVar_rpsditvo, domain=NonNegativeReals) + self.FlowVar_rpsditvo = Set(dimen=8, initialize=flows.FlowVariableIndices) + self.V_FlowOut = Var(self.FlowVar_rpsditvo, domain=NonNegativeReals) - M.FlowVarAnnual_rpitvo = Set(dimen=6, initialize=flows.FlowVariableAnnualIndices) - M.V_FlowOutAnnual = Var(M.FlowVarAnnual_rpitvo, domain=NonNegativeReals) + self.FlowVarAnnual_rpitvo = Set(dimen=6, initialize=flows.FlowVariableAnnualIndices) + self.V_FlowOutAnnual = Var(self.FlowVarAnnual_rpitvo, domain=NonNegativeReals) - M.FlexVar_rpsditvo = Set(dimen=8, initialize=flows.FlexVariablelIndices) - M.V_Flex = Var(M.FlexVar_rpsditvo, domain=NonNegativeReals) + self.FlexVar_rpsditvo = Set(dimen=8, initialize=flows.FlexVariablelIndices) + self.V_Flex = Var(self.FlexVar_rpsditvo, domain=NonNegativeReals) - M.FlexVarAnnual_rpitvo = Set(dimen=6, initialize=flows.FlexVariableAnnualIndices) - M.V_FlexAnnual = Var(M.FlexVarAnnual_rpitvo, domain=NonNegativeReals) + self.FlexVarAnnual_rpitvo = Set(dimen=6, initialize=flows.FlexVariableAnnualIndices) + self.V_FlexAnnual = Var(self.FlexVarAnnual_rpitvo, domain=NonNegativeReals) - M.CurtailmentVar_rpsditvo = Set(dimen=8, initialize=flows.CurtailmentVariableIndices) - M.V_Curtailment = Var(M.CurtailmentVar_rpsditvo, domain=NonNegativeReals, initialize=0) + self.CurtailmentVar_rpsditvo = Set(dimen=8, initialize=flows.CurtailmentVariableIndices) + self.V_Curtailment = Var( + self.CurtailmentVar_rpsditvo, domain=NonNegativeReals, initialize=0 + ) - M.FlowInStorage_rpsditvo = Set(dimen=8, initialize=flows.FlowInStorageVariableIndices) - M.V_FlowIn = Var(M.FlowInStorage_rpsditvo, domain=NonNegativeReals) + self.FlowInStorage_rpsditvo = Set(dimen=8, initialize=flows.FlowInStorageVariableIndices) + self.V_FlowIn = Var(self.FlowInStorage_rpsditvo, domain=NonNegativeReals) - M.StorageLevel_rpsdtv = Set(dimen=6, initialize=storage.StorageLevelVariableIndices) - M.V_StorageLevel = Var(M.StorageLevel_rpsdtv, domain=NonNegativeReals) + self.StorageLevel_rpsdtv = Set(dimen=6, initialize=storage.StorageLevelVariableIndices) + self.V_StorageLevel = Var(self.StorageLevel_rpsdtv, domain=NonNegativeReals) - M.SeasonalStorageLevel_rpstv = Set( + self.SeasonalStorageLevel_rpstv = Set( dimen=5, initialize=storage.SeasonalStorageLevelVariableIndices ) - M.V_SeasonalStorageLevel = Var(M.SeasonalStorageLevel_rpstv, domain=NonNegativeReals) + self.V_SeasonalStorageLevel = Var(self.SeasonalStorageLevel_rpstv, domain=NonNegativeReals) # Derived decision variables - M.CapacityVar_rptv = Set(dimen=4, initialize=costs.CostFixedIndices) - M.V_Capacity = Var(M.CapacityVar_rptv, domain=NonNegativeReals) + self.CapacityVar_rptv = Set(dimen=4, initialize=costs.CostFixedIndices) + self.V_Capacity = Var(self.CapacityVar_rptv, domain=NonNegativeReals) - M.NewCapacityVar_rtv = Set(dimen=3, initialize=capacity.CapacityVariableIndices) - M.V_NewCapacity = Var(M.NewCapacityVar_rtv, domain=NonNegativeReals, initialize=0) + self.NewCapacityVar_rtv = Set(dimen=3, initialize=capacity.CapacityVariableIndices) + self.V_NewCapacity = Var(self.NewCapacityVar_rtv, domain=NonNegativeReals, initialize=0) - M.RetiredCapacityVar_rptv = Set(dimen=4, initialize=capacity.RetiredCapacityVariableIndices) - M.V_RetiredCapacity = Var(M.RetiredCapacityVar_rptv, domain=NonNegativeReals, initialize=0) + self.RetiredCapacityVar_rptv = Set( + dimen=4, initialize=capacity.RetiredCapacityVariableIndices + ) + self.V_RetiredCapacity = Var( + self.RetiredCapacityVar_rptv, domain=NonNegativeReals, initialize=0 + ) - M.AnnualRetirementVar_rptv = Set( + self.AnnualRetirementVar_rptv = Set( dimen=4, initialize=capacity.AnnualRetirementVariableIndices ) - M.V_AnnualRetirement = Var( - M.AnnualRetirementVar_rptv, domain=NonNegativeReals, initialize=0 + self.V_AnnualRetirement = Var( + self.AnnualRetirementVar_rptv, domain=NonNegativeReals, initialize=0 ) - M.CapacityAvailableVar_rpt = Set( + self.CapacityAvailableVar_rpt = Set( dimen=3, initialize=capacity.CapacityAvailableVariableIndices ) - M.V_CapacityAvailableByPeriodAndTech = Var( - M.CapacityAvailableVar_rpt, domain=NonNegativeReals, initialize=0 + self.V_CapacityAvailableByPeriodAndTech = Var( + self.CapacityAvailableVar_rpt, domain=NonNegativeReals, initialize=0 ) ################################################ @@ -766,7 +810,7 @@ def __init__(M, *args: object, **kwargs: object) -> None: # (minimize total cost) # ################################################ - M.TotalCost = Objective(rule=costs.TotalCost_rule, sense=minimize) + self.TotalCost = Objective(rule=costs.TotalCost_rule, sense=minimize) ################################################ # Constraints # @@ -780,67 +824,70 @@ def __init__(M, *args: object, **kwargs: object) -> None: # of these constraints are provided in the associated comment blocks # in temoa_rules.py, where the constraints are defined. # --------------------------------------------------------------- - M.progress_marker_4 = BuildAction(['Starting to build Constraints'], rule=progress_check) + self.progress_marker_4 = BuildAction(['Starting to build Constraints'], rule=progress_check) # Declare constraints to calculate derived decision variables - M.CapacityConstraint = Constraint( - M.CapacityConstraint_rpsdtv, rule=capacity.Capacity_Constraint + self.CapacityConstraint = Constraint( + self.CapacityConstraint_rpsdtv, rule=capacity.Capacity_Constraint ) - M.CapacityAnnualConstraint_rptv = Set( + self.CapacityAnnualConstraint_rptv = Set( dimen=4, initialize=capacity.CapacityAnnualConstraintIndices ) - M.CapacityAnnualConstraint = Constraint( - M.CapacityAnnualConstraint_rptv, rule=capacity.CapacityAnnual_Constraint + self.CapacityAnnualConstraint = Constraint( + self.CapacityAnnualConstraint_rptv, rule=capacity.CapacityAnnual_Constraint ) - M.CapacityAvailableByPeriodAndTechConstraint = Constraint( - M.CapacityAvailableVar_rpt, rule=capacity.CapacityAvailableByPeriodAndTech_Constraint + self.CapacityAvailableByPeriodAndTechConstraint = Constraint( + self.CapacityAvailableVar_rpt, + rule=capacity.CapacityAvailableByPeriodAndTech_Constraint, ) # devnote: I think this constraint is redundant # M.RetiredCapacityConstraint = Constraint( # M.RetiredCapacityVar_rptv, rule=RetiredCapacity_Constraint # ) - M.progress_marker_4a = BuildAction( + self.progress_marker_4a = BuildAction( ['Starting AnnualRetirementConstraint'], rule=progress_check ) - M.AnnualRetirementConstraint = Constraint( - M.AnnualRetirementVar_rptv, rule=capacity.AnnualRetirement_Constraint + self.AnnualRetirementConstraint = Constraint( + self.AnnualRetirementVar_rptv, rule=capacity.AnnualRetirement_Constraint ) - M.progress_marker_4b = BuildAction( + self.progress_marker_4b = BuildAction( ['Starting AdjustedCapacityConstraint'], rule=progress_check ) - M.AdjustedCapacityConstraint = Constraint( - M.CostFixed_rptv, rule=capacity.AdjustedCapacity_Constraint + self.AdjustedCapacityConstraint = Constraint( + self.CostFixed_rptv, rule=capacity.AdjustedCapacity_Constraint ) - M.progress_marker_5 = BuildAction(['Finished Capacity Constraints'], rule=progress_check) + self.progress_marker_5 = BuildAction(['Finished Capacity Constraints'], rule=progress_check) # Declare core model constraints that ensure proper system functioning # In driving order, starting with the need to meet end-use demands - M.DemandConstraint = Constraint(M.DemandConstraint_rpc, rule=commodities.Demand_Constraint) + self.DemandConstraint = Constraint( + self.DemandConstraint_rpc, rule=commodities.Demand_Constraint + ) # devnote: testing a workaround - M.DemandActivityConstraint_rpsdtv_dem = Set( + self.DemandActivityConstraint_rpsdtv_dem = Set( dimen=7, initialize=commodities.DemandActivityConstraintIndices ) - M.DemandActivityConstraint = Constraint( - M.DemandActivityConstraint_rpsdtv_dem, rule=commodities.DemandActivity_Constraint + self.DemandActivityConstraint = Constraint( + self.DemandActivityConstraint_rpsdtv_dem, rule=commodities.DemandActivity_Constraint ) - M.CommodityBalanceConstraint_rpsdc = Set( + self.CommodityBalanceConstraint_rpsdc = Set( dimen=5, initialize=commodities.CommodityBalanceConstraintIndices ) - M.CommodityBalanceConstraint = Constraint( - M.CommodityBalanceConstraint_rpsdc, rule=commodities.CommodityBalance_Constraint + self.CommodityBalanceConstraint = Constraint( + self.CommodityBalanceConstraint_rpsdc, rule=commodities.CommodityBalance_Constraint ) - M.AnnualCommodityBalanceConstraint_rpc = Set( + self.AnnualCommodityBalanceConstraint_rpc = Set( dimen=3, initialize=commodities.AnnualCommodityBalanceConstraintIndices ) - M.AnnualCommodityBalanceConstraint = Constraint( - M.AnnualCommodityBalanceConstraint_rpc, + self.AnnualCommodityBalanceConstraint = Constraint( + self.AnnualCommodityBalanceConstraint_rpc, rule=commodities.AnnualCommodityBalance_Constraint, ) @@ -848,144 +895,146 @@ def __init__(M, *args: object, **kwargs: object) -> None: # M.ResourceConstraint_rpr, rule=ResourceExtraction_Constraint # ) - M.BaseloadDiurnalConstraint_rpsdtv = Set( + self.BaseloadDiurnalConstraint_rpsdtv = Set( dimen=6, initialize=operations.BaseloadDiurnalConstraintIndices ) - M.BaseloadDiurnalConstraint = Constraint( - M.BaseloadDiurnalConstraint_rpsdtv, rule=operations.BaseloadDiurnal_Constraint + self.BaseloadDiurnalConstraint = Constraint( + self.BaseloadDiurnalConstraint_rpsdtv, rule=operations.BaseloadDiurnal_Constraint ) - M.RegionalExchangeCapacityConstraint_rrptv = Set( + self.RegionalExchangeCapacityConstraint_rrptv = Set( dimen=5, initialize=capacity.RegionalExchangeCapacityConstraintIndices ) - M.RegionalExchangeCapacityConstraint = Constraint( - M.RegionalExchangeCapacityConstraint_rrptv, + self.RegionalExchangeCapacityConstraint = Constraint( + self.RegionalExchangeCapacityConstraint_rrptv, rule=geography.RegionalExchangeCapacity_Constraint, ) - M.progress_marker_6 = BuildAction(['Starting Storage Constraints'], rule=progress_check) + self.progress_marker_6 = BuildAction(['Starting Storage Constraints'], rule=progress_check) - M.StorageEnergyConstraint = Constraint( - M.StorageConstraints_rpsdtv, rule=storage.StorageEnergy_Constraint + self.StorageEnergyConstraint = Constraint( + self.StorageConstraints_rpsdtv, rule=storage.StorageEnergy_Constraint ) - M.StorageEnergyUpperBoundConstraint = Constraint( - M.StorageConstraints_rpsdtv, rule=storage.StorageEnergyUpperBound_Constraint + self.StorageEnergyUpperBoundConstraint = Constraint( + self.StorageConstraints_rpsdtv, rule=storage.StorageEnergyUpperBound_Constraint ) - M.SeasonalStorageEnergyConstraint = Constraint( - M.SeasonalStorageLevel_rpstv, rule=storage.SeasonalStorageEnergy_Constraint + self.SeasonalStorageEnergyConstraint = Constraint( + self.SeasonalStorageLevel_rpstv, rule=storage.SeasonalStorageEnergy_Constraint ) - M.SeasonalStorageEnergyUpperBoundConstraint = Constraint( - M.SeasonalStorageConstraints_rpsdtv, + self.SeasonalStorageEnergyUpperBoundConstraint = Constraint( + self.SeasonalStorageConstraints_rpsdtv, rule=storage.SeasonalStorageEnergyUpperBound_Constraint, ) - M.StorageChargeRateConstraint = Constraint( - M.StorageConstraints_rpsdtv, rule=storage.StorageChargeRate_Constraint + self.StorageChargeRateConstraint = Constraint( + self.StorageConstraints_rpsdtv, rule=storage.StorageChargeRate_Constraint ) - M.StorageDischargeRateConstraint = Constraint( - M.StorageConstraints_rpsdtv, rule=storage.StorageDischargeRate_Constraint + self.StorageDischargeRateConstraint = Constraint( + self.StorageConstraints_rpsdtv, rule=storage.StorageDischargeRate_Constraint ) - M.StorageThroughputConstraint = Constraint( - M.StorageConstraints_rpsdtv, rule=storage.StorageThroughput_Constraint + self.StorageThroughputConstraint = Constraint( + self.StorageConstraints_rpsdtv, rule=storage.StorageThroughput_Constraint ) - M.LimitStorageFractionConstraint = Constraint( - M.LimitStorageFractionConstraint_rpsdtv, rule=storage.LimitStorageFraction_Constraint + self.LimitStorageFractionConstraint = Constraint( + self.LimitStorageFractionConstraint_rpsdtv, + rule=storage.LimitStorageFraction_Constraint, ) - M.RampUpDayConstraint_rpsdtv = Set( + self.RampUpDayConstraint_rpsdtv = Set( dimen=6, initialize=operations.RampUpDayConstraintIndices ) - M.RampUpDayConstraint = Constraint( - M.RampUpDayConstraint_rpsdtv, rule=operations.RampUpDay_Constraint + self.RampUpDayConstraint = Constraint( + self.RampUpDayConstraint_rpsdtv, rule=operations.RampUpDay_Constraint ) - M.RampDownDayConstraint_rpsdtv = Set( + self.RampDownDayConstraint_rpsdtv = Set( dimen=6, initialize=operations.RampDownDayConstraintIndices ) - M.RampDownDayConstraint = Constraint( - M.RampDownDayConstraint_rpsdtv, rule=operations.RampDownDay_Constraint + self.RampDownDayConstraint = Constraint( + self.RampDownDayConstraint_rpsdtv, rule=operations.RampDownDay_Constraint ) - M.RampUpSeasonConstraint_rpsstv = Set( + self.RampUpSeasonConstraint_rpsstv = Set( dimen=6, initialize=operations.RampUpSeasonConstraintIndices ) - M.RampUpSeasonConstraint = Constraint( - M.RampUpSeasonConstraint_rpsstv, rule=operations.RampUpSeason_Constraint + self.RampUpSeasonConstraint = Constraint( + self.RampUpSeasonConstraint_rpsstv, rule=operations.RampUpSeason_Constraint ) - M.RampDownSeasonConstraint_rpsstv = Set( + self.RampDownSeasonConstraint_rpsstv = Set( dimen=6, initialize=operations.RampDownSeasonConstraintIndices ) - M.RampDownSeasonConstraint = Constraint( - M.RampDownSeasonConstraint_rpsstv, rule=operations.RampDownSeason_Constraint + self.RampDownSeasonConstraint = Constraint( + self.RampDownSeasonConstraint_rpsstv, rule=operations.RampDownSeason_Constraint ) - M.ReserveMargin_rpsd = Set(dimen=4, initialize=reserves.ReserveMarginIndices) - M.validate_ReserveMargin = BuildAction(rule=validate_ReserveMargin) - M.ReserveMarginConstraint = Constraint( - M.ReserveMargin_rpsd, rule=reserves.ReserveMargin_Constraint + self.ReserveMargin_rpsd = Set(dimen=4, initialize=reserves.ReserveMarginIndices) + self.validate_ReserveMargin = BuildAction(rule=validate_ReserveMargin) + self.ReserveMarginConstraint = Constraint( + self.ReserveMargin_rpsd, rule=reserves.ReserveMargin_Constraint ) - M.LimitEmissionConstraint = Constraint( - M.LimitEmissionConstraint_rpe, rule=limits.LimitEmission_Constraint + self.LimitEmissionConstraint = Constraint( + self.LimitEmissionConstraint_rpe, rule=limits.LimitEmission_Constraint ) - M.progress_marker_7 = BuildAction( + self.progress_marker_7 = BuildAction( ['Starting LimitGrowth and Activity Constraints'], rule=progress_check ) - M.LimitGrowthCapacityConstraint_rpt = Set( + self.LimitGrowthCapacityConstraint_rpt = Set( dimen=4, initialize=limits.LimitGrowthCapacityIndices ) - M.LimitGrowthCapacityConstraint = Constraint( - M.LimitGrowthCapacityConstraint_rpt, rule=limits.LimitGrowthCapacityConstraint_rule + self.LimitGrowthCapacityConstraint = Constraint( + self.LimitGrowthCapacityConstraint_rpt, rule=limits.LimitGrowthCapacityConstraint_rule ) - M.LimitDegrowthCapacityConstraint_rpt = Set( + self.LimitDegrowthCapacityConstraint_rpt = Set( dimen=4, initialize=limits.LimitDegrowthCapacityIndices ) - M.LimitDegrowthCapacityConstraint = Constraint( - M.LimitDegrowthCapacityConstraint_rpt, rule=limits.LimitDegrowthCapacityConstraint_rule + self.LimitDegrowthCapacityConstraint = Constraint( + self.LimitDegrowthCapacityConstraint_rpt, + rule=limits.LimitDegrowthCapacityConstraint_rule, ) - M.LimitGrowthNewCapacityConstraint_rpt = Set( + self.LimitGrowthNewCapacityConstraint_rpt = Set( dimen=4, initialize=limits.LimitGrowthNewCapacityIndices ) - M.LimitGrowthNewCapacityConstraint = Constraint( - M.LimitGrowthNewCapacityConstraint_rpt, + self.LimitGrowthNewCapacityConstraint = Constraint( + self.LimitGrowthNewCapacityConstraint_rpt, rule=limits.LimitGrowthNewCapacityConstraint_rule, ) - M.LimitDegrowthNewCapacityConstraint_rpt = Set( + self.LimitDegrowthNewCapacityConstraint_rpt = Set( dimen=4, initialize=limits.LimitDegrowthNewCapacityIndices ) - M.LimitDegrowthNewCapacityConstraint = Constraint( - M.LimitDegrowthNewCapacityConstraint_rpt, + self.LimitDegrowthNewCapacityConstraint = Constraint( + self.LimitDegrowthNewCapacityConstraint_rpt, rule=limits.LimitDegrowthNewCapacityConstraint_rule, ) - M.LimitGrowthNewCapacityDeltaConstraint_rpt = Set( + self.LimitGrowthNewCapacityDeltaConstraint_rpt = Set( dimen=4, initialize=limits.LimitGrowthNewCapacityDeltaIndices ) - M.LimitGrowthNewCapacityDeltaConstraint = Constraint( - M.LimitGrowthNewCapacityDeltaConstraint_rpt, + self.LimitGrowthNewCapacityDeltaConstraint = Constraint( + self.LimitGrowthNewCapacityDeltaConstraint_rpt, rule=limits.LimitGrowthNewCapacityDeltaConstraint_rule, ) - M.LimitDegrowthNewCapacityDeltaConstraint_rpt = Set( + self.LimitDegrowthNewCapacityDeltaConstraint_rpt = Set( dimen=4, initialize=limits.LimitDegrowthNewCapacityDeltaIndices ) - M.LimitDegrowthNewCapacityDeltaConstraint = Constraint( - M.LimitDegrowthNewCapacityDeltaConstraint_rpt, + self.LimitDegrowthNewCapacityDeltaConstraint = Constraint( + self.LimitDegrowthNewCapacityDeltaConstraint_rpt, rule=limits.LimitDegrowthNewCapacityDeltaConstraint_rule, ) - M.LimitActivityConstraint = Constraint( - M.LimitActivityConstraint_rpt, rule=limits.LimitActivity_Constraint + self.LimitActivityConstraint = Constraint( + self.LimitActivityConstraint_rpt, rule=limits.LimitActivity_Constraint ) - M.LimitSeasonalCapacityFactorConstraint = Constraint( - M.LimitSeasonalCapacityFactorConstraint_rpst, + self.LimitSeasonalCapacityFactorConstraint = Constraint( + self.LimitSeasonalCapacityFactorConstraint_rpst, rule=limits.LimitSeasonalCapacityFactor_Constraint, ) @@ -994,12 +1043,12 @@ def __init__(M, *args: object, **kwargs: object) -> None: # M.LimitActivityGroupConstraint_rpg, rule=LimitActivityGroup_Constraint # ) - M.LimitCapacityConstraint = Constraint( - M.LimitCapacityConstraint_rpt, rule=limits.LimitCapacity_Constraint + self.LimitCapacityConstraint = Constraint( + self.LimitCapacityConstraint_rpt, rule=limits.LimitCapacity_Constraint ) - M.LimitNewCapacityConstraint = Constraint( - M.LimitNewCapacityConstraint_rpt, rule=limits.LimitNewCapacity_Constraint + self.LimitNewCapacityConstraint = Constraint( + self.LimitNewCapacityConstraint_rpt, rule=limits.LimitNewCapacity_Constraint ) # devnote: deprecated when generalising tech/group columns in Limit tables @@ -1011,16 +1060,16 @@ def __init__(M, *args: object, **kwargs: object) -> None: # M.LimitNewCapacityGroupConstraint_rpg, rule=LimitNewCapacityGroup_Constraint # ) - M.LimitCapacityShareConstraint = Constraint( - M.LimitCapacityShareConstraint_rpgg, rule=limits.LimitCapacityShare_Constraint + self.LimitCapacityShareConstraint = Constraint( + self.LimitCapacityShareConstraint_rpgg, rule=limits.LimitCapacityShare_Constraint ) - M.LimitActivityShareConstraint = Constraint( - M.LimitActivityShareConstraint_rpgg, rule=limits.LimitActivityShare_Constraint + self.LimitActivityShareConstraint = Constraint( + self.LimitActivityShareConstraint_rpgg, rule=limits.LimitActivityShare_Constraint ) - M.LimitNewCapacityShareConstraint = Constraint( - M.LimitNewCapacityShareConstraint_rpgg, rule=limits.LimitNewCapacityShare_Constraint + self.LimitNewCapacityShareConstraint = Constraint( + self.LimitNewCapacityShareConstraint_rpgg, rule=limits.LimitNewCapacityShare_Constraint ) # devnote: deprecated when generalising tech/group columns in Limit tables @@ -1033,85 +1082,87 @@ def __init__(M, *args: object, **kwargs: object) -> None: # M.LimitActivityGroupShareConstraint_rpgg, rule=LimitActivityGroupShare_Constraint # ) - M.progress_marker_8 = BuildAction( + self.progress_marker_8 = BuildAction( ['Starting Limit Capacity and Tech Split Constraints'], rule=progress_check ) - M.LimitResourceConstraint = Constraint( - M.LimitResourceConstraint_rt, rule=limits.LimitResource_Constraint + self.LimitResourceConstraint = Constraint( + self.LimitResourceConstraint_rt, rule=limits.LimitResource_Constraint ) - M.LimitAnnualCapacityFactorConstraint = Constraint( - M.LimitAnnualCapacityFactorConstraint_rpto, + self.LimitAnnualCapacityFactorConstraint = Constraint( + self.LimitAnnualCapacityFactorConstraint_rpto, rule=limits.LimitAnnualCapacityFactor_Constraint, ) ## Tech input splits - M.LimitTechInputSplitConstraint_rpsditv = Set( + self.LimitTechInputSplitConstraint_rpsditv = Set( dimen=8, initialize=limits.LimitTechInputSplitConstraintIndices ) - M.LimitTechInputSplitConstraint = Constraint( - M.LimitTechInputSplitConstraint_rpsditv, rule=limits.LimitTechInputSplit_Constraint + self.LimitTechInputSplitConstraint = Constraint( + self.LimitTechInputSplitConstraint_rpsditv, rule=limits.LimitTechInputSplit_Constraint ) - M.LimitTechInputSplitAnnualConstraint_rpitv = Set( + self.LimitTechInputSplitAnnualConstraint_rpitv = Set( dimen=6, initialize=limits.LimitTechInputSplitAnnualConstraintIndices ) - M.LimitTechInputSplitAnnualConstraint = Constraint( - M.LimitTechInputSplitAnnualConstraint_rpitv, + self.LimitTechInputSplitAnnualConstraint = Constraint( + self.LimitTechInputSplitAnnualConstraint_rpitv, rule=limits.LimitTechInputSplitAnnual_Constraint, ) - M.LimitTechInputSplitAverageConstraint_rpitv = Set( + self.LimitTechInputSplitAverageConstraint_rpitv = Set( dimen=6, initialize=limits.LimitTechInputSplitAverageConstraintIndices ) - M.LimitTechInputSplitAverageConstraint = Constraint( - M.LimitTechInputSplitAverageConstraint_rpitv, + self.LimitTechInputSplitAverageConstraint = Constraint( + self.LimitTechInputSplitAverageConstraint_rpitv, rule=limits.LimitTechInputSplitAverage_Constraint, ) ## Tech output splits - M.LimitTechOutputSplitConstraint_rpsdtvo = Set( + self.LimitTechOutputSplitConstraint_rpsdtvo = Set( dimen=8, initialize=limits.LimitTechOutputSplitConstraintIndices ) - M.LimitTechOutputSplitConstraint = Constraint( - M.LimitTechOutputSplitConstraint_rpsdtvo, rule=limits.LimitTechOutputSplit_Constraint + self.LimitTechOutputSplitConstraint = Constraint( + self.LimitTechOutputSplitConstraint_rpsdtvo, + rule=limits.LimitTechOutputSplit_Constraint, ) - M.LimitTechOutputSplitAnnualConstraint_rptvo = Set( + self.LimitTechOutputSplitAnnualConstraint_rptvo = Set( dimen=6, initialize=limits.LimitTechOutputSplitAnnualConstraintIndices ) - M.LimitTechOutputSplitAnnualConstraint = Constraint( - M.LimitTechOutputSplitAnnualConstraint_rptvo, + self.LimitTechOutputSplitAnnualConstraint = Constraint( + self.LimitTechOutputSplitAnnualConstraint_rptvo, rule=limits.LimitTechOutputSplitAnnual_Constraint, ) - M.LimitTechOutputSplitAverageConstraint_rptvo = Set( + self.LimitTechOutputSplitAverageConstraint_rptvo = Set( dimen=6, initialize=limits.LimitTechOutputSplitAverageConstraintIndices ) - M.LimitTechOutputSplitAverageConstraint = Constraint( - M.LimitTechOutputSplitAverageConstraint_rptvo, + self.LimitTechOutputSplitAverageConstraint = Constraint( + self.LimitTechOutputSplitAverageConstraint_rptvo, rule=limits.LimitTechOutputSplitAverage_Constraint, ) - M.RenewablePortfolioStandardConstraint = Constraint( - M.RenewablePortfolioStandardConstraint_rpg, + self.RenewablePortfolioStandardConstraint = Constraint( + self.RenewablePortfolioStandardConstraint_rpg, rule=limits.RenewablePortfolioStandard_Constraint, ) - M.LinkedEmissionsTechConstraint_rpsdtve = Set( + self.LinkedEmissionsTechConstraint_rpsdtve = Set( dimen=7, initialize=emissions.LinkedTechConstraintIndices ) # the validation requires that the set above be built first: - M.validate_LinkedTech_lifetimes = BuildCheck(rule=validate_linked_tech) + self.validate_LinkedTech_lifetimes = BuildCheck(rule=validate_linked_tech) - M.LinkedEmissionsTechConstraint = Constraint( - M.LinkedEmissionsTechConstraint_rpsdtve, rule=emissions.LinkedEmissionsTech_Constraint + self.LinkedEmissionsTechConstraint = Constraint( + self.LinkedEmissionsTechConstraint_rpsdtve, + rule=emissions.LinkedEmissionsTech_Constraint, ) - M.progress_marker_9 = BuildAction(['Finished Constraints'], rule=progress_check) + self.progress_marker_9 = BuildAction(['Finished Constraints'], rule=progress_check) -def progress_check(M: TemoaModel, checkpoint: str) -> None: +def progress_check(model: TemoaModel, checkpoint: str) -> None: """A quick widget which is called by BuildAction in order to log creation progress""" logger.debug('Model build progress: %s', checkpoint) diff --git a/temoa/extensions/method_of_morris/morris.py b/temoa/extensions/method_of_morris/morris.py index 50d952be4..9f6d1f29b 100644 --- a/temoa/extensions/method_of_morris/morris.py +++ b/temoa/extensions/method_of_morris/morris.py @@ -44,7 +44,7 @@ def evaluate(param_names, param_values, data: dict, k): if not status: raise RuntimeError('Bad solve during Method of Morris') table_writer = TableWriter(config) - table_writer.write_results(M=mdl) + table_writer.write_results(model=mdl) con = sqlite3.connect(db_file) cur = con.cursor() @@ -175,13 +175,13 @@ def evaluate(param_names, param_values, data: dict, k): groups, unique_group_names = compute_groups_matrix(problem['groups']) number_of_groups = len(unique_group_names) print( - '{0:<30} {1:>10} {2:>10} {3:>15} {4:>10}'.format( + '{:<30} {:>10} {:>10} {:>15} {:>10}'.format( 'Parameter', 'Mu_Star', 'Mu', 'Mu_Star_Conf', 'Sigma' ) ) for j in list(range(number_of_groups)): print( - '{0:30} {1:10.3f} {2:10.3f} {3:15.3f} {4:10.3f}'.format( + '{:30} {:10.3f} {:10.3f} {:15.3f} {:10.3f}'.format( Si_OF['names'][j], Si_OF['mu_star'][j], Si_OF['mu'][j], diff --git a/temoa/extensions/method_of_morris/morris_evaluate.py b/temoa/extensions/method_of_morris/morris_evaluate.py index c105ce1af..03a4f2cca 100644 --- a/temoa/extensions/method_of_morris/morris_evaluate.py +++ b/temoa/extensions/method_of_morris/morris_evaluate.py @@ -99,7 +99,7 @@ def evaluate(param_info, mm_sample, data, i, config: TemoaConfig, log_queue, log if not status: raise RuntimeError('Bad solve during Method of Morris') table_writer = TableWriter(config) - table_writer.write_mm_results(M=mdl, iteration=i) + table_writer.write_mm_results(model=mdl, iteration=i) con = sqlite3.connect(config.input_database) cur = con.cursor() scenario_name = config.scenario + f'-{i}' diff --git a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py index 1d37e8157..0ac1ff775 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py +++ b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py @@ -364,7 +364,7 @@ def process_solve_results(self, instance: TemoaModel): if idx in self.seen_instance_indices: raise ValueError('Instance index already seen. Likely coding error') self.seen_instance_indices.add(idx) - self.writer.write_capacity_tables(M=instance, iteration=idx) + self.writer.write_capacity_tables(model=instance, iteration=idx) self.writer.write_summary_flow(instance, iteration=idx) def __del__(self): diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index a648bb4fd..fc573ad22 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -9,7 +9,7 @@ from collections import deque from pathlib import Path from sqlite3 import Connection -from sys import stderr as SE +import sys import definitions from temoa._internal import run_actions @@ -131,7 +131,7 @@ def get_connection(self) -> Connection: 'to the same db or make a copy to preserve the original and point both input/output\n' 'to the copy.' ) - SE.write(msg) + sys.stderr.write(msg) logger.error('Run aborted. I/O database pointers are different') sys.exit(-1) @@ -249,7 +249,7 @@ def start(self): if not self.config.silent: self.progress_mapper.report(idx, 'report') # write results by appending. We have already cleared necessary items - self.table_writer.write_results(M=model, append=True) + self.table_writer.write_results(model=model, append=True) # handle side-case for writing duals if self.config.save_duals: self.table_writer.write_dual_variables(results=results, iteration=idx.base_year) @@ -505,13 +505,13 @@ def clear_old_results(self): (scenario_name, f'{scenario_name}-%'), ) except sqlite3.OperationalError as e: - SE.write(f'Could not clear scenario from table {table}.\n') + sys.stderr.write(f'Could not clear scenario from table {table}.\n') raise sqlite3.OperationalError from e for table in self.tables_without_scenario_reference: try: self.cursor.execute(f'DELETE FROM {table} WHERE 1') except sqlite3.OperationalError as e: - SE.write(f'Failed to clear table {table}.\n') + sys.stderr.write(f'Failed to clear table {table}.\n') raise sqlite3.OperationalError from e self.output_con.commit() @@ -537,7 +537,7 @@ def clear_results_after(self, period): (period, self.config.scenario), ) except sqlite3.OperationalError as e: - SE.write(f'Failed to clear periods from table {table}.\n') + sys.stderr.write(f'Failed to clear periods from table {table}.\n') raise sqlite3.OperationalError from e # special case... new capacity has vintage only... From 4251e5396020efe01aa72a6fcf5f119d59f4df1e Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 28 Oct 2025 17:38:52 -0400 Subject: [PATCH 279/587] fixing naming in components --- temoa/_internal/table_data_puller.py | 44 +- temoa/components/capacity.py | 353 +++---- temoa/components/commodities.py | 436 +++++---- temoa/components/costs.py | 323 ++++--- temoa/components/emissions.py | 88 +- temoa/components/flows.py | 181 ++-- temoa/components/geography.py | 44 +- temoa/components/limits.py | 874 +++++++++--------- temoa/components/operations.py | 261 +++--- temoa/components/reserves.py | 193 ++-- temoa/components/storage.py | 212 +++-- temoa/components/technology.py | 184 ++-- temoa/components/time.py | 178 ++-- temoa/components/utils.py | 28 +- temoa/core/model.py | 227 ++--- .../mga_sequencer.py | 4 +- temoa/extensions/myopic/myopic_sequencer.py | 1 - .../single_vector_mga/sv_mga_sequencer.py | 41 +- temoa/utilities/unit_cost_explorer.py | 17 +- 19 files changed, 1936 insertions(+), 1753 deletions(-) diff --git a/temoa/_internal/table_data_puller.py b/temoa/_internal/table_data_puller.py index 448b19f0b..62979475c 100644 --- a/temoa/_internal/table_data_puller.py +++ b/temoa/_internal/table_data_puller.py @@ -384,8 +384,8 @@ def poll_cost_results( cap, value(fixed_cost), value(model.PeriodLength[p]), - GDR=global_discount_rate, - P_0=float(p_0) if p_0 is not None else 0.0, + global_discount_rate=global_discount_rate, + p_0=float(p_0) if p_0 is not None else 0.0, p=p, ) if '-' in r: @@ -438,8 +438,8 @@ def poll_cost_results( activity, var_cost, value(model.PeriodLength[p]), - GDR=global_discount_rate, - P_0=float(p_0) if p_0 is not None else 0.0, + global_discount_rate=global_discount_rate, + p_0=float(p_0) if p_0 is not None else 0.0, p=p, ) if '-' in r: @@ -495,9 +495,9 @@ def loan_costs( loan_annualize=float(value(loan_ar)), lifetime_loan_process=loan_life, lifetime_process=process_life, - P_0=p_0, - P_e=p_e, - GDR=global_discount_rate, + p_0=p_0, + p_e=p_e, + global_discount_rate=global_discount_rate, vintage=vintage, ) # Override the GDR to get the undiscounted value @@ -508,9 +508,9 @@ def loan_costs( loan_annualize=float(value(loan_ar)), lifetime_loan_process=loan_life, lifetime_process=process_life, - P_0=p_0, - P_e=p_e, - GDR=global_discount_rate, + p_0=p_0, + p_e=p_e, + global_discount_rate=global_discount_rate, vintage=vintage, ) return float(value(model_ic)), float(value(undiscounted_cost)) @@ -547,9 +547,9 @@ def loan_costs_survival_curve( invest_cost, loan_annualize=float(value(loan_ar)), lifetime_loan_process=loan_life, - P_0=p_0, - P_e=p_e, - GDR=global_discount_rate, + p_0=p_0, + p_e=p_e, + global_discount_rate=global_discount_rate, ) # Override the GDR to get the undiscounted value global_discount_rate = 0 @@ -562,9 +562,9 @@ def loan_costs_survival_curve( invest_cost, loan_annualize=float(value(loan_ar)), lifetime_loan_process=loan_life, - P_0=p_0, - P_e=p_e, - GDR=global_discount_rate, + p_0=p_0, + p_e=p_e, + global_discount_rate=global_discount_rate, ) return float(value(model_ic)), float(value(undiscounted_cost)) @@ -644,8 +644,8 @@ def poll_emissions( cap_or_flow=flows[ei], cost_factor=value(model.CostEmission[ei.r, ei.p, ei.e]), cost_years=model.PeriodLength[ei.p], - GDR=global_discount_rate, - P_0=p_0_true, + global_discount_rate=global_discount_rate, + p_0=p_0_true, p=ei.p, ) ud_costs[ei.r, ei.p, ei.t, ei.v] += float(value(undiscounted_emiss_cost)) @@ -690,8 +690,8 @@ def poll_emissions( cost_years=model.PeriodLength[ ei.v ], # treat as fixed cost distributed over construction period - GDR=global_discount_rate, - P_0=p_0_true, + global_discount_rate=global_discount_rate, + p_0=p_0_true, p=ei.v, ) ud_costs[ei.r, ei.v, ei.t, ei.v] += float(value(undiscounted_emiss_cost)) @@ -735,8 +735,8 @@ def poll_emissions( cost_years=model.PeriodLength[ ei.p ], # treat as fixed cost distributed over retirement period - GDR=global_discount_rate, - P_0=p_0_true, + global_discount_rate=global_discount_rate, + p_0=p_0_true, p=ei.p, ) ud_costs[ei.r, ei.p, ei.t, ei.v] += float(value(undiscounted_emiss_cost)) diff --git a/temoa/components/capacity.py b/temoa/components/capacity.py index 6349e76ab..1ba005ab7 100644 --- a/temoa/components/capacity.py +++ b/temoa/components/capacity.py @@ -13,11 +13,13 @@ from itertools import product as cross_product from logging import getLogger -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING from deprecated import deprecated from pyomo.environ import value +from temoa.types import ExprLike + if TYPE_CHECKING: from temoa.core.model import TemoaModel from temoa.types import ( @@ -38,17 +40,17 @@ # ============================================================================ -def CheckCapacityFactorProcess(M: TemoaModel) -> None: - count_rptv: dict[tuple[Any, Any, Any, Any], int] = {} +def check_capacity_factor_process(model: TemoaModel) -> None: + count_rptv: dict[tuple[Region, Period, Technology, Vintage], int] = {} # Pull CapacityFactorTech by default - for r, p, _s, _d, t in M.CapacityFactor_rpsdt: - for v in M.processVintages[r, p, t]: - M.isCapacityFactorProcess[r, p, t, v] = False + for r, p, _s, _d, t in model.CapacityFactor_rpsdt: + for v in model.processVintages[r, p, t]: + model.isCapacityFactorProcess[r, p, t, v] = False count_rptv[r, p, t, v] = 0 # Check for bad values and count up the good ones - for r, p, _s, _d, t, v in M.CapacityFactorProcess.sparse_iterkeys(): - if v not in M.processVintages[r, p, t]: + for r, p, _s, _d, t, v in model.CapacityFactorProcess.sparse_iterkeys(): + if v not in model.processVintages[r, p, t]: msg = f'Invalid process {p, v} for {r, t} in CapacityFactorProcess table' logger.error(msg) raise ValueError(msg) @@ -59,9 +61,9 @@ def CheckCapacityFactorProcess(M: TemoaModel) -> None: # Check if all possible values have been set by process # log a warning if some are missing (allowed but maybe accidental) for (r, p, t, v), count in count_rptv.items(): - num_seg = len(M.TimeSeason[p]) * len(M.time_of_day) + num_seg = len(model.TimeSeason[p]) * len(model.time_of_day) if count > 0: - M.isCapacityFactorProcess[r, p, t, v] = True + model.isCapacityFactorProcess[r, p, t, v] = True if count < num_seg: logger.info( 'Some but not all processes were set in CapacityFactorProcess (%i out of a possible %i) for: %s' @@ -73,28 +75,27 @@ def CheckCapacityFactorProcess(M: TemoaModel) -> None: @deprecated('should not be needed. We are pulling the default on-the-fly where used') -def CreateCapacityFactors(M: TemoaModel) -> None: +def create_capacity_factors(model: TemoaModel) -> None: """ Steps to creating capacity factors: 1. Collect all possible processes 2. Find the ones _not_ specified in CapacityFactorProcess 3. Set them, based on CapacityFactorTech. """ - # Shorter names, for us lazy programmer types - CFP = M.CapacityFactorProcess + capacity_factor_process = model.CapacityFactorProcess # Step 1 - processes = {(r, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys()} + processes = {(r, t, v) for r, i, t, v, o in model.Efficiency.sparse_iterkeys()} all_cfs = { (r, p, s, d, t, v) for (r, t, v) in processes - for p in M.processPeriods[r, t, v] - for s, d in cross_product(M.TimeSeason[p], M.time_of_day) + for p in model.processPeriods[r, t, v] + for s, d in cross_product(model.TimeSeason[p], model.time_of_day) } # Step 2 - unspecified_cfs = all_cfs.difference(CFP.sparse_iterkeys()) + unspecified_cfs = all_cfs.difference(capacity_factor_process.sparse_iterkeys()) # Step 3 @@ -106,7 +107,7 @@ def CreateCapacityFactors(M: TemoaModel) -> None: if unspecified_cfs: # CFP._constructed = False for r, p, s, d, t, v in unspecified_cfs: - CFP[r, p, s, d, t, v] = M.CapacityFactorTech[r, p, s, d, t] + capacity_factor_process[r, p, s, d, t, v] = model.CapacityFactorTech[r, p, s, d, t] logger.debug( 'Created Capacity Factors for %d processes without an explicit specification', len(unspecified_cfs), @@ -115,7 +116,7 @@ def CreateCapacityFactors(M: TemoaModel) -> None: def get_default_capacity_factor( - M: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage + model: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage ) -> float: """ This initializer is used to fill the CapacityFactorProcess from the CapacityFactorTech where needed. @@ -132,16 +133,16 @@ def get_default_capacity_factor( :param v: vintage :return: the capacity factor """ - return value(M.CapacityFactorTech[r, p, s, d, t]) + return value(model.CapacityFactorTech[r, p, s, d, t]) def get_capacity_factor( - M: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage + model: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage ) -> float: - if M.isCapacityFactorProcess[r, p, t, v]: - return value(M.CapacityFactorProcess[r, p, s, d, t, v]) + if model.isCapacityFactorProcess[r, p, t, v]: + return value(model.CapacityFactorProcess[r, p, s, d, t, v]) else: - return value(M.CapacityFactorTech[r, p, s, d, t]) + return value(model.CapacityFactorTech[r, p, s, d, t]) # ============================================================================ @@ -149,55 +150,59 @@ def get_capacity_factor( # ============================================================================ -def CapacityVariableIndices( - M: TemoaModel, +def capacity_variable_indices( + model: TemoaModel, ) -> set[tuple[Region, Technology, Vintage]] | None: - return M.newCapacity_rtv + return model.newCapacity_rtv -def RetiredCapacityVariableIndices( - M: TemoaModel, +def retired_capacity_variable_indices( + model: TemoaModel, ) -> set[tuple[Region, Period, Technology, Vintage]]: return { (r, p, t, v) - for r, p, t in M.processVintages - if t in M.tech_retirement and t not in M.tech_uncap - for v in M.processVintages[r, p, t] - if v < p <= v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[p]) + for r, p, t in model.processVintages + if t in model.tech_retirement and t not in model.tech_uncap + for v in model.processVintages[r, p, t] + if v < p <= v + value(model.LifetimeProcess[r, t, v]) - value(model.PeriodLength[p]) } -def AnnualRetirementVariableIndices( - M: TemoaModel, +def annual_retirement_variable_indices( + model: TemoaModel, ) -> set[tuple[Region, Period, Technology, Vintage]]: - return {(r, p, t, v) for r, t, v in M.retirementPeriods for p in M.retirementPeriods[r, t, v]} + return { + (r, p, t, v) + for r, t, v in model.retirementPeriods + for p in model.retirementPeriods[r, t, v] + } -def CapacityAvailableVariableIndices( - M: TemoaModel, +def capacity_available_variable_indices( + model: TemoaModel, ) -> set[tuple[Region, Period, Technology]] | None: - return M.activeCapacityAvailable_rpt + return model.activeCapacityAvailable_rpt -def RegionalExchangeCapacityConstraintIndices( - M: TemoaModel, +def regional_exchange_capacity_constraint_indices( + model: TemoaModel, ) -> set[tuple[Region, Region, Period, Technology, Vintage]]: indices: set[tuple[Region, Region, Period, Technology, Vintage]] = set() - for r_e, p, i in M.exportRegions: - for r_i, t, v, _o in M.exportRegions[r_e, p, i]: + for r_e, p, i in model.exportRegions: + for r_i, t, v, _o in model.exportRegions[r_e, p, i]: indices.add((r_e, r_i, p, t, v)) return indices -def CapacityAnnualConstraintIndices( - M: TemoaModel, +def capacity_annual_constraint_indices( + model: TemoaModel, ) -> set[tuple[Region, Period, Technology, Vintage]]: capacity_indices: set[tuple[Region, Period, Technology, Vintage]] = set() - if M.activeActivity_rptv: - for r, p, t, v in M.activeActivity_rptv: - if t in M.tech_annual and t not in M.tech_demand: - if t not in M.tech_uncap: + if model.activeActivity_rptv: + for r, p, t, v in model.activeActivity_rptv: + if t in model.tech_annual and t not in model.tech_demand: + if t not in model.tech_uncap: capacity_indices.add((r, p, t, v)) else: return set() @@ -205,17 +210,17 @@ def CapacityAnnualConstraintIndices( return capacity_indices -def CapacityConstraintIndices( - M: TemoaModel, +def capacity_constraint_indices( + model: TemoaModel, ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]]: capacity_indices: set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]] = set() - if M.activeActivity_rptv: - for r, p, t, v in M.activeActivity_rptv: - if t not in M.tech_annual or t in M.tech_demand: - if t not in M.tech_uncap: - if t not in M.tech_storage: - for s in M.TimeSeason[p]: - for d in M.time_of_day: + if model.activeActivity_rptv: + for r, p, t, v in model.activeActivity_rptv: + if t not in model.tech_annual or t in model.tech_demand: + if t not in model.tech_uncap: + if t not in model.tech_storage: + for s in model.TimeSeason[p]: + for d in model.time_of_day: capacity_indices.add((r, p, s, d, t, v)) else: return set() @@ -224,36 +229,36 @@ def CapacityConstraintIndices( @deprecated('switched over to validator... this set is typically VERY empty') -def CapacityFactorProcessIndices( - M: TemoaModel, -) -> set[tuple[str, str, str, str, int]]: +def capacity_factor_process_indices( + model: TemoaModel, +) -> set[tuple[Region, Season, TimeOfDay, Technology, Vintage]]: indices: set[tuple[Region, Season, TimeOfDay, Technology, Vintage]] = set() - for r, _i, t, v, _o in M.Efficiency.sparse_iterkeys(): - for p in M.time_optimize: - for s in M.TimeSeason[p]: - for d in M.time_of_day: + for r, _i, t, v, _o in model.Efficiency.sparse_iterkeys(): + for p in model.time_optimize: + for s in model.TimeSeason[p]: + for d in model.time_of_day: indices.add((r, s, d, t, v)) return indices -def CapacityFactorTechIndices( - M: TemoaModel, +def capacity_factor_tech_indices( + model: TemoaModel, ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology]]: all_cfs: set[tuple[Region, Period, Season, TimeOfDay, Technology]] = set() - if M.activeCapacityAvailable_rpt: - for r, p, t in M.activeCapacityAvailable_rpt: - for s in M.TimeSeason[p]: - for d in M.time_of_day: + if model.activeCapacityAvailable_rpt: + for r, p, t in model.activeCapacityAvailable_rpt: + for s in model.TimeSeason[p]: + for d in model.time_of_day: all_cfs.add((r, p, s, d, t)) else: return set() return all_cfs -def CapacityAvailableVariableIndicesVintage( - M: TemoaModel, +def capacity_available_variable_indices_vintage( + model: TemoaModel, ) -> set[tuple[Region, Period, Technology, Vintage]] | None: - return M.activeCapacityAvailable_rptv + return model.activeCapacityAvailable_rptv # ============================================================================ @@ -261,9 +266,9 @@ def CapacityAvailableVariableIndicesVintage( # ============================================================================ -def AnnualRetirement_Constraint( - M: TemoaModel, r: Region, p: Period, t: Technology, v: Vintage -) -> Any: +def annual_retirement_constraint( + model: TemoaModel, r: Region, p: Period, t: Technology, v: Vintage +) -> ExprLike: r""" Get the annualised retirement rate for a process in a given period. Used to output retirement (including end of life, EOL) and to model end of @@ -295,57 +300,57 @@ def AnnualRetirement_Constraint( """ ## Get the capacity at the start of this period - if p == v + value(M.LifetimeProcess[r, t, v]): + if p == v + value(model.LifetimeProcess[r, t, v]): # Exact EOL. No V_Capacity or V_RetiredCapacity for this period. - if p == M.time_optimize.first(): + if p == model.time_optimize.first(): # Must be existing capacity. Apply survival curve to existing cap - cap_begin = M.ExistingCapacity[r, t, v] * M.LifetimeSurvivalCurve[r, p, t, v] + cap_begin = model.ExistingCapacity[r, t, v] * model.LifetimeSurvivalCurve[r, p, t, v] else: # Get previous capacity and continue survival curve - p_prev = M.time_optimize.prev(p) + p_prev = model.time_optimize.prev(p) cap_begin = ( - M.V_Capacity[r, p_prev, t, v] - * value(M.LifetimeSurvivalCurve[r, p, t, v]) - / value(M.ProcessLifeFrac[r, p_prev, t, v]) + model.V_Capacity[r, p_prev, t, v] + * value(model.LifetimeSurvivalCurve[r, p, t, v]) + / value(model.ProcessLifeFrac[r, p_prev, t, v]) ) else: # The capacity at the beginning of the period cap_begin = ( - M.V_Capacity[r, p, t, v] - * value(M.LifetimeSurvivalCurve[r, p, t, v]) - / value(M.ProcessLifeFrac[r, p, t, v]) + model.V_Capacity[r, p, t, v] + * value(model.LifetimeSurvivalCurve[r, p, t, v]) + / value(model.ProcessLifeFrac[r, p, t, v]) ) ## Get the capacity at the end of this period - if p <= v + value(M.LifetimeProcess[r, t, v]) < p + value(M.PeriodLength[p]): + if p <= v + value(model.LifetimeProcess[r, t, v]) < p + value(model.PeriodLength[p]): # EOL so capacity ends on zero cap_end = 0 else: # Mid-life period, ending capacity is beginning capacity of next period - p_next = M.time_future.next(p) + p_next = model.time_future.next(p) - if p == M.time_optimize.last() or p_next == v + value(M.LifetimeProcess[r, t, v]): + if p == model.time_optimize.last() or p_next == v + value(model.LifetimeProcess[r, t, v]): # No V_Capacity or V_RetiredCapacity for next period so just continue down the survival curve cap_end = ( cap_begin - * value(M.LifetimeSurvivalCurve[r, p_next, t, v]) - / value(M.LifetimeSurvivalCurve[r, p, t, v]) + * value(model.LifetimeSurvivalCurve[r, p_next, t, v]) + / value(model.LifetimeSurvivalCurve[r, p, t, v]) ) else: # Get the next period's beginning capacity cap_end = ( - M.V_Capacity[r, p_next, t, v] - * value(M.LifetimeSurvivalCurve[r, p_next, t, v]) - / value(M.ProcessLifeFrac[r, p_next, t, v]) + model.V_Capacity[r, p_next, t, v] + * value(model.LifetimeSurvivalCurve[r, p_next, t, v]) + / value(model.ProcessLifeFrac[r, p_next, t, v]) ) - annualised_retirement = (cap_begin - cap_end) / M.PeriodLength[p] - return M.V_AnnualRetirement[r, p, t, v] == annualised_retirement + annualised_retirement = (cap_begin - cap_end) / model.PeriodLength[p] + return model.V_AnnualRetirement[r, p, t, v] == annualised_retirement -def CapacityAvailableByPeriodAndTech_Constraint( - M: TemoaModel, r: Region, p: Period, t: Technology -) -> Any: +def capacity_available_by_period_and_tech_constraint( + model: TemoaModel, r: Region, p: Period, t: Technology +) -> ExprLike: r""" The :math:`\textbf{CAPAVL}` variable is nominally for reporting solution values, @@ -359,15 +364,15 @@ def CapacityAvailableByPeriodAndTech_Constraint( \\ \forall p \in \text{P}^o, r \in R, t \in T """ - cap_avail = sum(M.V_Capacity[r, p, t, S_v] for S_v in M.processVintages[r, p, t]) + cap_avail = sum(model.V_Capacity[r, p, t, S_v] for S_v in model.processVintages[r, p, t]) - expr = M.V_CapacityAvailableByPeriodAndTech[r, p, t] == cap_avail + expr = model.V_CapacityAvailableByPeriodAndTech[r, p, t] == cap_avail return expr -def CapacityAnnual_Constraint( - M: TemoaModel, r: Region, p: Period, t: Technology, v: Vintage -) -> Any: +def capacity_annual_constraint( + model: TemoaModel, r: Region, p: Period, t: Technology, v: Vintage +) -> ExprLike: r""" Similar to Capacity_Constraint, but for technologies belonging to the :code:`tech_annual` set. Technologies in the tech_annual set have constant output @@ -390,17 +395,17 @@ def CapacityAnnual_Constraint( \forall \{r, p, t \in T^{a}, v\} \in \Theta_{\text{Activity}} """ activity_rptv = sum( - M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + model.V_FlowOutAnnual[r, p, S_i, t, v, S_o] + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) - return value(M.CapacityToActivity[r, t]) * M.V_Capacity[r, p, t, v] >= activity_rptv + return value(model.CapacityToActivity[r, t]) * model.V_Capacity[r, p, t, v] >= activity_rptv -def Capacity_Constraint( - M: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage -) -> Any: +def capacity_constraint( + model: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage +) -> ExprLike: r""" This constraint ensures that the capacity of a given process is sufficient to support its activity across all time periods and time slices. The calculation @@ -433,48 +438,48 @@ def Capacity_Constraint( # The expressions below are defined in-line to minimize the amount of # expression cloning taking place with Pyomo. - if t in M.tech_annual: + if t in model.tech_annual: # Annual demand technology useful_activity = sum( ( - value(M.DemandSpecificDistribution[r, p, s, d, S_o]) - if S_o in M.commodity_demand - else value(M.SegFrac[p, s, d]) + value(model.DemandSpecificDistribution[r, p, s, d, S_o]) + if S_o in model.commodity_demand + else value(model.SegFrac[p, s, d]) ) - * M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + * model.V_FlowOutAnnual[r, p, S_i, t, v, S_o] + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) else: useful_activity = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) - if t in M.tech_curtailment: + if t in model.tech_curtailment: # If technologies are present in the curtailment set, then enough # capacity must be available to cover both activity and curtailment. - return get_capacity_factor(M, r, p, s, d, t, v) * value(M.CapacityToActivity[r, t]) * value( - M.SegFrac[p, s, d] - ) * M.V_Capacity[r, p, t, v] == useful_activity + sum( - M.V_Curtailment[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + return get_capacity_factor(model, r, p, s, d, t, v) * value( + model.CapacityToActivity[r, t] + ) * value(model.SegFrac[p, s, d]) * model.V_Capacity[r, p, t, v] == useful_activity + sum( + model.V_Curtailment[r, p, s, d, S_i, t, v, S_o] + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) else: return ( - get_capacity_factor(M, r, p, s, d, t, v) - * value(M.CapacityToActivity[r, t]) - * value(M.SegFrac[p, s, d]) - * M.V_Capacity[r, p, t, v] + get_capacity_factor(model, r, p, s, d, t, v) + * value(model.CapacityToActivity[r, t]) + * value(model.SegFrac[p, s, d]) + * model.V_Capacity[r, p, t, v] >= useful_activity ) -def AdjustedCapacity_Constraint( - M: TemoaModel, r: Region, p: Period, t: Technology, v: Vintage -) -> Any: +def adjusted_capacity_constraint( + model: TemoaModel, r: Region, p: Period, t: Technology, v: Vintage +) -> ExprLike: r""" This constraint updates the capacity of a process by taking into account retirements and end of life. For a given :code:`(r,p,t,v)` index, this constraint sets the capacity @@ -544,22 +549,24 @@ def AdjustedCapacity_Constraint( the time when that retirement occurred (treated here as at the beginning of each period). """ - if v in M.time_exist: - built_capacity = value(M.ExistingCapacity[r, t, v]) + if v in model.time_exist: + built_capacity = value(model.ExistingCapacity[r, t, v]) else: - built_capacity = M.V_NewCapacity[r, t, v] + built_capacity = model.V_NewCapacity[r, t, v] early_retirements = 0 - if t in M.tech_retirement: + if t in model.tech_retirement: early_retirements = sum( - M.V_RetiredCapacity[r, S_p, t, v] / value(M.LifetimeSurvivalCurve[r, S_p, t, v]) - for S_p in M.time_optimize + model.V_RetiredCapacity[r, S_p, t, v] / value(model.LifetimeSurvivalCurve[r, S_p, t, v]) + for S_p in model.time_optimize if v < S_p <= p - and S_p < v + value(M.LifetimeProcess[r, t, v]) - value(M.PeriodLength[S_p]) + and S_p < v + value(model.LifetimeProcess[r, t, v]) - value(model.PeriodLength[S_p]) ) - remaining_capacity = (built_capacity - early_retirements) * value(M.ProcessLifeFrac[r, p, t, v]) - return M.V_Capacity[r, p, t, v] == remaining_capacity + remaining_capacity = (built_capacity - early_retirements) * value( + model.ProcessLifeFrac[r, p, t, v] + ) + return model.V_Capacity[r, p, t, v] == remaining_capacity # ============================================================================ @@ -567,7 +574,7 @@ def AdjustedCapacity_Constraint( # ============================================================================ -def create_capacity_and_retirement_sets(M: TemoaModel) -> None: +def create_capacity_and_retirement_sets(model: TemoaModel) -> None: """ Creates and populates component-specific Python sets and dictionaries on the model object. @@ -590,43 +597,45 @@ def create_capacity_and_retirement_sets(M: TemoaModel) -> None: logger.debug('Creating capacity, retirement, and construction/EOL sets.') # Calculate retirement periods based on lifetime and survival curves - for r, _i, t, v, _o in M.Efficiency.sparse_iterkeys(): - lifetime = value(M.LifetimeProcess[r, t, v]) - for p in M.time_optimize: - is_natural_eol = p <= v + lifetime < p + value(M.PeriodLength[p]) - is_early_retire = t in M.tech_retirement and v < p <= v + lifetime - value( - M.PeriodLength[p] + for r, _i, t, v, _o in model.Efficiency.sparse_iterkeys(): + lifetime = value(model.LifetimeProcess[r, t, v]) + for p in model.time_optimize: + is_natural_eol = p <= v + lifetime < p + value(model.PeriodLength[p]) + is_early_retire = t in model.tech_retirement and v < p <= v + lifetime - value( + model.PeriodLength[p] ) - is_survival_curve = M.isSurvivalCurveProcess[r, t, v] and v <= p <= v + lifetime + is_survival_curve = model.isSurvivalCurveProcess[r, t, v] and v <= p <= v + lifetime - if t not in M.tech_uncap and any((is_natural_eol, is_early_retire, is_survival_curve)): - M.retirementPeriods.setdefault((r, t, v), set()).add(p) + if t not in model.tech_uncap and any( + (is_natural_eol, is_early_retire, is_survival_curve) + ): + model.retirementPeriods.setdefault((r, t, v), set()).add(p) # Link construction materials to technologies - for r, i, t, v in M.ConstructionInput.sparse_iterkeys(): - M.capacityConsumptionTechs.setdefault((r, v, i), set()).add(t) + for r, i, t, v in model.ConstructionInput.sparse_iterkeys(): + model.capacityConsumptionTechs.setdefault((r, v, i), set()).add(t) # Link end-of-life materials to retiring technologies - for r, t, v, o in M.EndOfLifeOutput.sparse_iterkeys(): - if (r, t, v) in M.retirementPeriods: - for p in M.retirementPeriods[r, t, v]: - M.retirementProductionProcesses.setdefault((r, p, o), set()).add((t, v)) + for r, t, v, o in model.EndOfLifeOutput.sparse_iterkeys(): + if (r, t, v) in model.retirementPeriods: + for p in model.retirementPeriods[r, t, v]: + model.retirementProductionProcesses.setdefault((r, p, o), set()).add((t, v)) # Create active capacity index sets from the now-populated processVintages - M.newCapacity_rtv = { + model.newCapacity_rtv = { (r, t, v) - for r, p, t in M.processVintages - for v in M.processVintages[r, p, t] - if t not in M.tech_uncap and v in M.time_optimize + for r, p, t in model.processVintages + for v in model.processVintages[r, p, t] + if t not in model.tech_uncap and v in model.time_optimize } - M.activeCapacityAvailable_rpt = { + model.activeCapacityAvailable_rpt = { (r, p, t) - for r, p, t in M.processVintages - if M.processVintages[r, p, t] and t not in M.tech_uncap + for r, p, t in model.processVintages + if model.processVintages[r, p, t] and t not in model.tech_uncap } - M.activeCapacityAvailable_rptv = { + model.activeCapacityAvailable_rptv = { (r, p, t, v) - for r, p, t in M.processVintages - for v in M.processVintages[r, p, t] - if t not in M.tech_uncap + for r, p, t in model.processVintages + for v in model.processVintages[r, p, t] + if t not in model.tech_uncap } diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index 5336dcf43..7b6ac0bbe 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -8,6 +8,8 @@ drive the model's energy system solution. """ +from __future__ import annotations + import sys from itertools import product as cross_product from logging import getLogger @@ -16,10 +18,12 @@ from pyomo.environ import value +from temoa.types.core_types import Season, Technology, TimeOfDay, Vintage + if TYPE_CHECKING: from temoa.core.model import TemoaModel -from ..types import Commodity, Period, Region +from ..types import Commodity, ExprLike, Period, Region from .utils import get_variable_efficiency logger = getLogger(name=__name__) @@ -29,8 +33,8 @@ # ============================================================================ -def CommodityBalanceConstraintErrorCheck( - supplied: Any, demanded: Any, r: Region, p: Period, s: str, d: str, c: Commodity +def commodity_balance_constraint_error_check( + supplied: Any, demanded: Any, r: Region, p: Period, s: Season, d: TimeOfDay, c: Commodity ) -> None: # note: if a pyomo equation simplifies to an int, there are no variables in it, which # is an indicator of a problem. How this might come up I do not know @@ -52,7 +56,7 @@ def CommodityBalanceConstraintErrorCheck( raise Exception(msg.format(c, r, p, s, d, expr)) -def AnnualCommodityBalanceConstraintErrorCheck( +def annual_commodity_balance_constraint_error_check( supplied: Any, demanded: Any, r: Region, p: Period, c: Commodity ) -> None: # note: if a pyomo equation simplifies to an int, there are no variables in it, which @@ -75,7 +79,7 @@ def AnnualCommodityBalanceConstraintErrorCheck( raise Exception(msg.format(c, r, p, expr)) -def DemandConstraintErrorCheck(supply: Any, r: Region, p: Period, dem: Commodity) -> None: +def demand_constraint_error_check(supply: Any, r: Region, p: Period, dem: Commodity) -> None: # note: if a pyomo equation simplifies to an int, there are no variables in it, which # is an indicator of a problem if isinstance(supply, int): @@ -95,49 +99,49 @@ def DemandConstraintErrorCheck(supply: Any, r: Region, p: Period, dem: Commodity # ============================================================================ -def DemandActivityConstraintIndices( - M: 'TemoaModel', -) -> set[tuple[Region, Period, str, str, str, int, Commodity]]: +def demand_activity_constraint_indices( + model: TemoaModel, +) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage, Commodity]]: indices = { (r, p, s, d, t, v, dem) - for r, p, dem in M.DemandConstraint_rpc - for t, v in M.commodityUStreamProcess[r, p, dem] - if t not in M.tech_annual - for s in M.TimeSeason[p] - for d in M.time_of_day + for r, p, dem in model.DemandConstraint_rpc + for t, v in model.commodityUStreamProcess[r, p, dem] + if t not in model.tech_annual + for s in model.TimeSeason[p] + for d in model.time_of_day } return indices -def CommodityBalanceConstraintIndices( - M: 'TemoaModel', -) -> set[tuple[Region, Period, str, str, Commodity]]: +def commodity_balance_constraint_indices( + model: TemoaModel, +) -> set[tuple[Region, Period, Season, TimeOfDay, Commodity]]: # Generate indices only for those commodities that are produced by # technologies with varying output at the time slice level. indices = { (r, p, s, d, c) - for r, p, c in M.commodityBalance_rpc + for r, p, c in model.commodityBalance_rpc # r in this line includes interregional transfer combinations (not needed). - if r in M.regions # this line ensures only the regions are included. - and c not in M.commodity_annual - for s in M.TimeSeason[p] - for d in M.time_of_day + if r in model.regions # this line ensures only the regions are included. + and c not in model.commodity_annual + for s in model.TimeSeason[p] + for d in model.time_of_day } return indices -def AnnualCommodityBalanceConstraintIndices( - M: 'TemoaModel', +def annual_commodity_balance_constraint_indices( + model: TemoaModel, ) -> set[tuple[Region, Period, Commodity]]: # Generate indices only for those commodities that are produced by # technologies with constant annual output. indices = { (r, p, c) - for r, p, c in M.commodityBalance_rpc + for r, p, c in model.commodityBalance_rpc # r in this line includes interregional transfer combinations (not needed). - if r in M.regions # this line ensures only the regions are included. - and c in M.commodity_annual + if r in model.regions # this line ensures only the regions are included. + and c in model.commodity_annual } return indices @@ -148,7 +152,7 @@ def AnnualCommodityBalanceConstraintIndices( # ============================================================================ -def Demand_Constraint(M: 'TemoaModel', r: Region, p: Period, dem: Commodity) -> Any: +def demand_constraint(model: TemoaModel, r: Region, p: Period, dem: Commodity) -> ExprLike: r""" The Demand constraint drives the model. This constraint ensures that supply at @@ -181,22 +185,29 @@ def Demand_Constraint(M: 'TemoaModel', r: Region, p: Period, dem: Commodity) -> # ) supply_annual = sum( - M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, dem] - for S_t, S_v in M.commodityUStreamProcess[r, p, dem] - for S_i in M.processInputsByOutput[r, p, S_t, S_v, dem] + model.V_FlowOutAnnual[r, p, S_i, S_t, S_v, dem] + for S_t, S_v in model.commodityUStreamProcess[r, p, dem] + for S_i in model.processInputsByOutput[r, p, S_t, S_v, dem] ) - DemandConstraintErrorCheck(supply_annual, r, p, dem) + demand_constraint_error_check(supply_annual, r, p, dem) - expr = supply_annual == value(M.Demand[r, p, dem]) + expr = supply_annual == value(model.Demand[r, p, dem]) return expr # devnote: no longer needed -def DemandActivity_Constraint( - M: 'TemoaModel', r: Region, p: Period, s: str, d: str, t: str, v: int, dem: Commodity -) -> Any: +def demand_activity_constraint( + model: TemoaModel, + r: Region, + p: Period, + s: Season, + d: TimeOfDay, + t: Technology, + v: Vintage, + dem: Commodity, +) -> ExprLike: r""" For end-use demands, it is unreasonable to let the model arbitrarily shift the @@ -227,20 +238,22 @@ def DemandActivity_Constraint( """ activity = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, dem] for S_i in M.processInputsByOutput[r, p, t, v, dem] + model.V_FlowOut[r, p, s, d, S_i, t, v, dem] + for S_i in model.processInputsByOutput[r, p, t, v, dem] ) annual_activity = sum( - M.V_FlowOutAnnual[r, p, S_i, t, v, dem] for S_i in M.processInputsByOutput[r, p, t, v, dem] + model.V_FlowOutAnnual[r, p, S_i, t, v, dem] + for S_i in model.processInputsByOutput[r, p, t, v, dem] ) - expr = annual_activity * value(M.DemandSpecificDistribution[r, p, s, d, dem]) == activity + expr = annual_activity * value(model.DemandSpecificDistribution[r, p, s, d, dem]) == activity return expr -def CommodityBalance_Constraint( - M: 'TemoaModel', r: Region, p: Period, s: str, d: str, c: Commodity -) -> Any: +def commodity_balance_constraint( + model: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay, c: Commodity +) -> ExprLike: r""" Where the Demand constraint :eq:`Demand` ensures that end-use demands are met, the CommodityBalance constraint ensures that the endogenous system demands are @@ -341,122 +354,123 @@ def CommodityBalance_Constraint( produced = 0 consumed = 0 - if (r, p, c) in M.commodityDStreamProcess: + if (r, p, c) in model.commodityDStreamProcess: # Only storage techs have a flow in variable # For other techs, it would be redundant as in = out / eff consumed += sum( - M.V_FlowIn[r, p, s, d, c, S_t, S_v, S_o] - for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t in M.tech_storage - for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] + model.V_FlowIn[r, p, s, d, c, S_t, S_v, S_o] + for S_t, S_v in model.commodityDStreamProcess[r, p, c] + if S_t in model.tech_storage + for S_o in model.processOutputsByInput[r, p, S_t, S_v, c] ) # Into flows consumed += sum( - M.V_FlowOut[r, p, s, d, c, S_t, S_v, S_o] - / get_variable_efficiency(M, r, p, s, d, c, S_t, S_v, S_o) - for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t not in M.tech_storage and S_t not in M.tech_annual - for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] + model.V_FlowOut[r, p, s, d, c, S_t, S_v, S_o] + / get_variable_efficiency(model, r, p, s, d, c, S_t, S_v, S_o) + for S_t, S_v in model.commodityDStreamProcess[r, p, c] + if S_t not in model.tech_storage and S_t not in model.tech_annual + for S_o in model.processOutputsByInput[r, p, S_t, S_v, c] ) # Into annual flows consumed += sum( ( - value(M.DemandSpecificDistribution[r, p, s, d, S_o]) - if S_o in M.commodity_demand - else value(M.SegFrac[p, s, d]) + value(model.DemandSpecificDistribution[r, p, s, d, S_o]) + if S_o in model.commodity_demand + else value(model.SegFrac[p, s, d]) ) - * M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] - / get_variable_efficiency(M, r, p, s, d, c, S_t, S_v, S_o) - for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t in M.tech_annual - for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] + * model.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] + / get_variable_efficiency(model, r, p, s, d, c, S_t, S_v, S_o) + for S_t, S_v in model.commodityDStreamProcess[r, p, c] + if S_t in model.tech_annual + for S_o in model.processOutputsByInput[r, p, S_t, S_v, c] ) - if (r, p, c) in M.capacityConsumptionTechs: + if (r, p, c) in model.capacityConsumptionTechs: # Consumed by building capacity # Assume evenly distributed over a year consumed += ( - value(M.SegFrac[p, s, d]) + value(model.SegFrac[p, s, d]) * sum( - value(M.ConstructionInput[r, c, S_t, p]) * M.V_NewCapacity[r, S_t, p] - for S_t in M.capacityConsumptionTechs[r, p, c] + value(model.ConstructionInput[r, c, S_t, p]) * model.V_NewCapacity[r, S_t, p] + for S_t in model.capacityConsumptionTechs[r, p, c] ) - / M.PeriodLength[p] + / model.PeriodLength[p] ) - if (r, p, c) in M.commodityUStreamProcess: + if (r, p, c) in model.commodityUStreamProcess: # From flows including output from storage produced += sum( - M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, c] - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t not in M.tech_annual - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + model.V_FlowOut[r, p, s, d, S_i, S_t, S_v, c] + for S_t, S_v in model.commodityUStreamProcess[r, p, c] + if S_t not in model.tech_annual + for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] ) # From annual flows - produced += value(M.SegFrac[p, s, d]) * sum( - M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, c] - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t in M.tech_annual - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + produced += value(model.SegFrac[p, s, d]) * sum( + model.V_FlowOutAnnual[r, p, S_i, S_t, S_v, c] + for S_t, S_v in model.commodityUStreamProcess[r, p, c] + if S_t in model.tech_annual + for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] ) - if c in M.commodity_flex: + if c in model.commodity_flex: # Wasted by flex flows consumed += sum( - M.V_Flex[r, p, s, d, S_i, S_t, S_v, c] - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t not in M.tech_annual and S_t in M.tech_flex - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + model.V_Flex[r, p, s, d, S_i, S_t, S_v, c] + for S_t, S_v in model.commodityUStreamProcess[r, p, c] + if S_t not in model.tech_annual and S_t in model.tech_flex + for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] ) # Wasted by annual flex flows - consumed += value(M.SegFrac[p, s, d]) * sum( - M.V_FlexAnnual[r, p, S_i, S_t, S_v, c] - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t in M.tech_annual and S_t in M.tech_flex - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + consumed += value(model.SegFrac[p, s, d]) * sum( + model.V_FlexAnnual[r, p, S_i, S_t, S_v, c] + for S_t, S_v in model.commodityUStreamProcess[r, p, c] + if S_t in model.tech_annual and S_t in model.tech_flex + for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] ) - if (r, p, c) in M.retirementProductionProcesses: + if (r, p, c) in model.retirementProductionProcesses: # Produced by retiring capacity # Assume evenly distributed over a year - produced += value(M.SegFrac[p, s, d]) * sum( - value(M.EndOfLifeOutput[r, S_t, S_v, c]) * M.V_AnnualRetirement[r, p, S_t, S_v] - for S_t, S_v in M.retirementProductionProcesses[r, p, c] + produced += value(model.SegFrac[p, s, d]) * sum( + value(model.EndOfLifeOutput[r, S_t, S_v, c]) * model.V_AnnualRetirement[r, p, S_t, S_v] + for S_t, S_v in model.retirementProductionProcesses[r, p, c] ) # export of commodity c from region r to other regions - if (r, p, c) in M.exportRegions: + if (r, p, c) in model.exportRegions: consumed += sum( - M.V_FlowOut[r + '-' + reg, p, s, d, c, S_t, S_v, S_o] - / get_variable_efficiency(M, r + '-' + reg, p, s, d, c, S_t, S_v, S_o) - for reg, S_t, S_v, S_o in M.exportRegions[r, p, c] - if S_t not in M.tech_annual + model.V_FlowOut[r + '-' + reg, p, s, d, c, S_t, S_v, S_o] + / get_variable_efficiency(model, r + '-' + reg, p, s, d, c, S_t, S_v, S_o) + for reg, S_t, S_v, S_o in model.exportRegions[r, p, c] + if S_t not in model.tech_annual ) consumed += sum( - value(M.SegFrac[p, s, d]) - * M.V_FlowOutAnnual[r + '-' + reg, p, c, S_t, S_v, S_o] - / get_variable_efficiency(M, r + '-' + reg, p, s, d, c, S_t, S_v, S_o) - for reg, S_t, S_v, S_o in M.exportRegions[r, p, c] - if S_t in M.tech_annual + value(model.SegFrac[p, s, d]) + * model.V_FlowOutAnnual[r + '-' + reg, p, c, S_t, S_v, S_o] + / get_variable_efficiency(model, r + '-' + reg, p, s, d, c, S_t, S_v, S_o) + for reg, S_t, S_v, S_o in model.exportRegions[r, p, c] + if S_t in model.tech_annual ) # import of commodity c from other regions into region r - if (r, p, c) in M.importRegions: + if (r, p, c) in model.importRegions: produced += sum( - M.V_FlowOut[reg + '-' + r, p, s, d, S_i, S_t, S_v, c] - for reg, S_t, S_v, S_i in M.importRegions[r, p, c] - if S_t not in M.tech_annual + model.V_FlowOut[reg + '-' + r, p, s, d, S_i, S_t, S_v, c] + for reg, S_t, S_v, S_i in model.importRegions[r, p, c] + if S_t not in model.tech_annual ) produced += sum( - value(M.SegFrac[p, s, d]) * M.V_FlowOutAnnual[reg + '-' + r, p, S_i, S_t, S_v, c] - for reg, S_t, S_v, S_i in M.importRegions[r, p, c] - if S_t in M.tech_annual + value(model.SegFrac[p, s, d]) + * model.V_FlowOutAnnual[reg + '-' + r, p, S_i, S_t, S_v, c] + for reg, S_t, S_v, S_i in model.importRegions[r, p, c] + if S_t in model.tech_annual ) - CommodityBalanceConstraintErrorCheck( + commodity_balance_constraint_error_check( produced, consumed, r, @@ -466,7 +480,7 @@ def CommodityBalance_Constraint( c, ) - if c in M.commodity_waste: + if c in model.commodity_waste: expr = produced >= consumed else: expr = produced == consumed @@ -474,7 +488,9 @@ def CommodityBalance_Constraint( return expr -def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r: Region, p: Period, c: Commodity) -> Any: +def annual_commodity_balance_constraint( + model: TemoaModel, r: Region, p: Period, c: Commodity +) -> ExprLike: r""" Similar to CommodityBalance_Constraint but only balances the supply and demand of the commodity at the period level, summing all flows over the period but allowing imbalances at the time slice @@ -484,121 +500,122 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r: Region, p: Period, c: produced = 0 consumed = 0 - if (r, p, c) in M.commodityDStreamProcess: + if (r, p, c) in model.commodityDStreamProcess: # Only storage techs have a flow in variable # For other techs, it would be redundant as in = out / eff consumed += sum( - M.V_FlowIn[r, p, S_s, S_d, c, S_t, S_v, S_o] - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day - for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t in M.tech_storage - for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] + model.V_FlowIn[r, p, S_s, S_d, c, S_t, S_v, S_o] + for S_s in model.TimeSeason[p] + for S_d in model.time_of_day + for S_t, S_v in model.commodityDStreamProcess[r, p, c] + if S_t in model.tech_storage + for S_o in model.processOutputsByInput[r, p, S_t, S_v, c] ) consumed += sum( - M.V_FlowOut[r, p, S_s, S_d, c, S_t, S_v, S_o] - / get_variable_efficiency(M, r, p, S_s, S_d, c, S_t, S_v, S_o) - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day - for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t not in M.tech_storage and S_t not in M.tech_annual - for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] + model.V_FlowOut[r, p, S_s, S_d, c, S_t, S_v, S_o] + / get_variable_efficiency(model, r, p, S_s, S_d, c, S_t, S_v, S_o) + for S_s in model.TimeSeason[p] + for S_d in model.time_of_day + for S_t, S_v in model.commodityDStreamProcess[r, p, c] + if S_t not in model.tech_storage and S_t not in model.tech_annual + for S_o in model.processOutputsByInput[r, p, S_t, S_v, c] ) consumed += sum( - M.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] / value(M.Efficiency[r, c, S_t, S_v, S_o]) - for S_t, S_v in M.commodityDStreamProcess[r, p, c] - if S_t in M.tech_annual - for S_o in M.processOutputsByInput[r, p, S_t, S_v, c] + model.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] + / value(model.Efficiency[r, c, S_t, S_v, S_o]) + for S_t, S_v in model.commodityDStreamProcess[r, p, c] + if S_t in model.tech_annual + for S_o in model.processOutputsByInput[r, p, S_t, S_v, c] ) - if (r, p, c) in M.capacityConsumptionTechs: + if (r, p, c) in model.capacityConsumptionTechs: # Consumed by building capacity # Assume evenly distributed over a year consumed += ( sum( - value(M.ConstructionInput[r, c, S_t, p]) * M.V_NewCapacity[r, S_t, p] - for S_t in M.capacityConsumptionTechs[r, p, c] + value(model.ConstructionInput[r, c, S_t, p]) * model.V_NewCapacity[r, S_t, p] + for S_t in model.capacityConsumptionTechs[r, p, c] ) - / M.PeriodLength[p] + / model.PeriodLength[p] ) - if (r, p, c) in M.commodityUStreamProcess: + if (r, p, c) in model.commodityUStreamProcess: # Includes output from storage produced += sum( - M.V_FlowOut[r, p, S_s, S_d, S_i, S_t, S_v, c] - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t not in M.tech_annual - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + model.V_FlowOut[r, p, S_s, S_d, S_i, S_t, S_v, c] + for S_s in model.TimeSeason[p] + for S_d in model.time_of_day + for S_t, S_v in model.commodityUStreamProcess[r, p, c] + if S_t not in model.tech_annual + for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] ) produced += sum( - M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, c] - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t in M.tech_annual - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + model.V_FlowOutAnnual[r, p, S_i, S_t, S_v, c] + for S_t, S_v in model.commodityUStreamProcess[r, p, c] + if S_t in model.tech_annual + for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] ) - if c in M.commodity_flex: + if c in model.commodity_flex: consumed += sum( - M.V_Flex[r, p, S_s, S_d, S_i, S_t, S_v, c] - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t not in M.tech_annual and S_t in M.tech_flex - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + model.V_Flex[r, p, S_s, S_d, S_i, S_t, S_v, c] + for S_s in model.TimeSeason[p] + for S_d in model.time_of_day + for S_t, S_v in model.commodityUStreamProcess[r, p, c] + if S_t not in model.tech_annual and S_t in model.tech_flex + for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] ) consumed += sum( - M.V_FlexAnnual[r, p, S_i, S_t, S_v, c] - for S_t, S_v in M.commodityUStreamProcess[r, p, c] - if S_t in M.tech_flex and S_t in M.tech_annual - for S_i in M.processInputsByOutput[r, p, S_t, S_v, c] + model.V_FlexAnnual[r, p, S_i, S_t, S_v, c] + for S_t, S_v in model.commodityUStreamProcess[r, p, c] + if S_t in model.tech_flex and S_t in model.tech_annual + for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] ) - if (r, p, c) in M.retirementProductionProcesses: + if (r, p, c) in model.retirementProductionProcesses: # Produced by retiring capacity # Assume evenly distributed over a year produced += sum( - value(M.EndOfLifeOutput[r, S_t, S_v, c]) * M.V_AnnualRetirement[r, p, S_t, S_v] - for S_t, S_v in M.retirementProductionProcesses[r, p, c] + value(model.EndOfLifeOutput[r, S_t, S_v, c]) * model.V_AnnualRetirement[r, p, S_t, S_v] + for S_t, S_v in model.retirementProductionProcesses[r, p, c] ) # export of commodity c from region r to other regions - if (r, p, c) in M.exportRegions: + if (r, p, c) in model.exportRegions: consumed += sum( - M.V_FlowOut[r + '-' + S_r, p, S_s, S_d, c, S_t, S_v, S_o] - / get_variable_efficiency(M, r + '-' + S_r, p, S_s, S_d, c, S_t, S_v, S_o) - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day - for S_r, S_t, S_v, S_o in M.exportRegions[r, p, c] - if S_t not in M.tech_annual + model.V_FlowOut[r + '-' + S_r, p, S_s, S_d, c, S_t, S_v, S_o] + / get_variable_efficiency(model, r + '-' + S_r, p, S_s, S_d, c, S_t, S_v, S_o) + for S_s in model.TimeSeason[p] + for S_d in model.time_of_day + for S_r, S_t, S_v, S_o in model.exportRegions[r, p, c] + if S_t not in model.tech_annual ) consumed += sum( - M.V_FlowOutAnnual[r + '-' + S_r, p, c, S_t, S_v, S_o] - / M.Efficiency[r + '-' + S_r, c, S_t, S_v, S_o] - for S_r, S_t, S_v, S_o in M.exportRegions[r, p, c] - if S_t in M.tech_annual + model.V_FlowOutAnnual[r + '-' + S_r, p, c, S_t, S_v, S_o] + / model.Efficiency[r + '-' + S_r, c, S_t, S_v, S_o] + for S_r, S_t, S_v, S_o in model.exportRegions[r, p, c] + if S_t in model.tech_annual ) # import of commodity c from other regions into region r - if (r, p, c) in M.importRegions: + if (r, p, c) in model.importRegions: produced += sum( - M.V_FlowOut[S_r + '-' + r, p, S_s, S_d, S_i, S_t, S_v, c] - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day - for S_r, S_t, S_v, S_i in M.importRegions[r, p, c] - if S_t not in M.tech_annual + model.V_FlowOut[S_r + '-' + r, p, S_s, S_d, S_i, S_t, S_v, c] + for S_s in model.TimeSeason[p] + for S_d in model.time_of_day + for S_r, S_t, S_v, S_i in model.importRegions[r, p, c] + if S_t not in model.tech_annual ) produced += sum( - M.V_FlowOutAnnual[S_r + '-' + r, p, S_i, S_t, S_v, c] - for S_r, S_t, S_v, S_i in M.importRegions[r, p, c] - if S_t in M.tech_annual + model.V_FlowOutAnnual[S_r + '-' + r, p, S_i, S_t, S_v, c] + for S_r, S_t, S_v, S_i in model.importRegions[r, p, c] + if S_t in model.tech_annual ) - AnnualCommodityBalanceConstraintErrorCheck( + annual_commodity_balance_constraint_error_check( produced, consumed, r, @@ -606,7 +623,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r: Region, p: Period, c: c, ) - if c in M.commodity_waste: + if c in model.commodity_waste: expr = produced >= consumed else: expr = produced == consumed @@ -619,7 +636,7 @@ def AnnualCommodityBalance_Constraint(M: 'TemoaModel', r: Region, p: Period, c: # ============================================================================ -def create_technology_and_commodity_sets(M: 'TemoaModel') -> None: +def create_technology_and_commodity_sets(model: TemoaModel) -> None: """ Populates technology and commodity subset definitions based on their roles (e.g., demand, flexible) identified from the Efficiency parameter. @@ -632,15 +649,15 @@ def create_technology_and_commodity_sets(M: 'TemoaModel') -> None: - M.tech_demand: Technologies that directly satisfy an end-use demand. """ logger.debug('Creating technology and commodity subsets.') - for _r, _i, t, _v, o in M.Efficiency.sparse_iterkeys(): - if t in M.tech_flex and o not in M.commodity_flex: - M.commodity_flex.add(o) + for _r, _i, t, _v, o in model.Efficiency.sparse_iterkeys(): + if t in model.tech_flex and o not in model.commodity_flex: + model.commodity_flex.add(o) - if o in M.commodity_demand and t not in M.tech_demand: - M.tech_demand.add(t) + if o in model.commodity_demand and t not in model.tech_demand: + model.tech_demand.add(t) -def CreateDemands(M: 'TemoaModel') -> None: +def create_demands(model: TemoaModel) -> None: """ Steps to create the demand distributions 1. Use Demand keys to ensure that all demands in commodity_demand are used @@ -659,13 +676,13 @@ def CreateDemands(M: 'TemoaModel') -> None: # Step 0: some setup for a couple of reusable items # Get the nth element from the tuple (r, p, s, d, dem) # So we only have to update these indices in one place if they change - DSD_region = iget(0) - DSD_period = iget(1) - DSD_dem = iget(4) + demand_specific_distribution_region = iget(0) + demand_specific_distribution_period = iget(1) + demand_specific_distributon_dem = iget(4) # Step 1: Check if any demand commodities are going unused - used_dems = {dem for r, p, dem in M.Demand.sparse_iterkeys()} - unused_dems = sorted(M.commodity_demand.difference(used_dems)) + used_dems = {dem for r, p, dem in model.Demand.sparse_iterkeys()} + unused_dems = sorted(model.commodity_demand.difference(used_dems)) if unused_dems: for dem in unused_dems: msg = "Warning: Demand '{}' is unused\n" @@ -714,41 +731,54 @@ def CreateDemands(M: 'TemoaModel') -> None: # raise ValueError(msg.format(items, total)) # Step 4: Fill out demand specific distribution table and check sums to 1 by region and demand - DSD = M.DemandSpecificDistribution + demand_specific_distribution = model.DemandSpecificDistribution - demands_specified = set(map(DSD_dem, (i for i in DSD.sparse_iterkeys()))) + demands_specified = set( + map( + demand_specific_distributon_dem, + (i for i in demand_specific_distribution.sparse_iterkeys()), + ) + ) unset_demand_distributions = used_dems.difference( demands_specified ) # the demands not mentioned in DSD *at all* if unset_demand_distributions: - for p in M.time_optimize: + for p in model.time_optimize: unset_distributions = set( cross_product( - M.regions, (p,), M.TimeSeason[p], M.time_of_day, unset_demand_distributions + model.regions, + (p,), + model.TimeSeason[p], + model.time_of_day, + unset_demand_distributions, ) ) for r, p, s, d, dem in unset_distributions: - DSD[r, p, s, d, dem] = value(M.SegFrac[p, s, d]) # DSD._constructed = True + demand_specific_distribution[r, p, s, d, dem] = value( + model.SegFrac[p, s, d] + ) # DSD._constructed = True # Step 5: A final "sum to 1" check for all DSD members (which now should be everything) # Also check that all keys are made... The demand distro should be supported # by the full set of (r, p, dem) keys because it is an equality constraint # and we need to ensure even the zeros are passed in - used_rp_dems = {(r, p, dem) for r, p, dem in M.Demand.sparse_iterkeys()} + used_rp_dems = {(r, p, dem) for r, p, dem in model.Demand.sparse_iterkeys()} for r, p, dem in used_rp_dems: - expected_key_length = len(M.TimeSeason[p]) * len(M.time_of_day) + expected_key_length = len(model.TimeSeason[p]) * len(model.time_of_day) keys = [ k - for k in DSD.sparse_iterkeys() - if DSD_region(k) == r and DSD_period(k) == p and DSD_dem(k) == dem + for k in demand_specific_distribution.sparse_iterkeys() + if demand_specific_distribution_region(k) == r + and demand_specific_distribution_period(k) == p + and demand_specific_distributon_dem(k) == dem ] if len(keys) != expected_key_length: # this could be very slow but only calls when there's a problem missing = { (s, d) - for s in M.TimeSeason[p] - for d in M.time_of_day + for s in model.TimeSeason[p] + for d in model.time_of_day if (r, p, s, d, dem) not in keys } logger.info( @@ -756,7 +786,7 @@ def CreateDemands(M: 'TemoaModel') -> None: (r, p, dem), missing, ) - total = sum(value(DSD[i]) for i in keys) + total = sum(value(demand_specific_distribution[i]) for i in keys) if abs(value(total) - 1.0) > 0.001: # We can't explicitly test for "!= 1.0" because of incremental rounding # errors associated with the specification of demand shares by time slice, @@ -769,7 +799,9 @@ def get_str_padding(obj: Any) -> int: fmt = '%%-%ds = %%s' % key_padding # Works out to something like "%-25s = %s" - items_list: list[tuple[Any, Any]] = sorted([(k, value(DSD[k])) for k in keys]) + items_list: list[tuple[Any, Any]] = sorted( + [(k, value(demand_specific_distribution[k])) for k in keys] + ) items = '\n '.join(fmt % (str(k), v) for k, v in items_list) msg = ( 'The values of the DemandSpecificDistribution parameter do not ' diff --git a/temoa/components/costs.py b/temoa/components/costs.py index caeb96db7..7ab7ccbb7 100644 --- a/temoa/components/costs.py +++ b/temoa/components/costs.py @@ -20,6 +20,8 @@ from pyomo.core.base.component import ComponentData from pyomo.environ import quicksum, value +from temoa.types.core_types import Period, Region, Technology, Vintage + if TYPE_CHECKING: from temoa.core.model import TemoaModel @@ -33,9 +35,9 @@ # ============================================================================ -def get_default_loan_rate(M: TemoaModel, *_: Any) -> float: +def get_default_loan_rate(model: TemoaModel, *_: Any) -> float: """get the default loan rate from the DefaultLoanRate param""" - return value(M.DefaultLoanRate) + return value(model.DefaultLoanRate) def annuity_to_pv(rate: float, periods: int) -> float | Expression: @@ -85,8 +87,8 @@ def fv_to_pv(rate: float, periods: int) -> float | Expression: return 1 / (1 + rate) ** periods -def get_loan_life(M: TemoaModel, r: str, t: str, v: int) -> int: - return value(M.LifetimeProcess[r, t, v]) +def get_loan_life(model: TemoaModel, r: Region, t: Technology, v: Vintage) -> int: + return value(model.LifetimeProcess[r, t, v]) # ============================================================================ @@ -94,28 +96,30 @@ def get_loan_life(M: TemoaModel, r: str, t: str, v: int) -> int: # ============================================================================ -def CostFixedIndices(M: TemoaModel) -> set[tuple[str, int, str, int]]: +def cost_fixed_indices(model: TemoaModel) -> set[tuple[Region, Period, Technology, Vintage]]: # we pull the unlimited capacity techs from this index. They cannot have fixed costs - if M.activeActivity_rptv: - return {(r, p, t, v) for r, p, t, v in M.activeActivity_rptv if t not in M.tech_uncap} + if model.activeActivity_rptv: + return { + (r, p, t, v) for r, p, t, v in model.activeActivity_rptv if t not in model.tech_uncap + } return set() -def CostVariableIndices(M: TemoaModel) -> set[tuple[str, int, str, int]]: - if M.activeActivity_rptv: - return M.activeActivity_rptv +def cost_variable_indices(model: TemoaModel) -> set[tuple[Region, Period, Technology, Vintage]]: + if model.activeActivity_rptv: + return model.activeActivity_rptv return set() -def LifetimeLoanProcessIndices(M: TemoaModel) -> set[tuple[str, str, int]]: +def lifetime_loan_process_indices(model: TemoaModel) -> set[tuple[Region, Technology, Vintage]]: """ Based on the Efficiency parameter's indices and time_future parameter, this function returns the set of process indices that may be specified in the CostInvest parameter. """ - min_period = min(M.vintage_optimize) + min_period = min(model.vintage_optimize) - indices = {(r, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys() if v >= min_period} + indices = {(r, t, v) for r, i, t, v, o in model.Efficiency.sparse_iterkeys() if v >= min_period} return indices @@ -132,9 +136,9 @@ def loan_cost( loan_annualize: float, lifetime_loan_process: float | int, lifetime_process: int, - P_0: int, - P_e: int, - GDR: float, + p_0: int, + p_e: int, + global_discount_rate: float, vintage: int, ) -> float | Expression: """ @@ -158,14 +162,14 @@ def loan_cost( * loan_annualize # calculate loan annuities for investment cost, if used ) - if not GDR: + if not global_discount_rate: # Undiscounted result res = ( annuity * lifetime_loan_process # sum of loan payments over loan period / lifetime_process # redistributed over lifetime of process * min( - lifetime_process, P_e - vintage + lifetime_process, p_e - vintage ) # sum of redistributed costs for life of process (within planning horizon) ) else: @@ -173,19 +177,23 @@ def loan_cost( res = ( annuity * annuity_to_pv( - GDR, int(lifetime_loan_process) + global_discount_rate, int(lifetime_loan_process) ) # PV of all loan payments, discounted to vintage year using GDR - * pv_to_annuity(GDR, lifetime_process) # reamortised over lifetime of process using GDR + * pv_to_annuity( + global_discount_rate, lifetime_process + ) # reamortised over lifetime of process using GDR * annuity_to_pv( - GDR, min(lifetime_process, P_e - vintage) + global_discount_rate, min(lifetime_process, p_e - vintage) ) # PV of all reamortised costs (within planning horizon) - * fv_to_pv(GDR, vintage - P_0) # finally, discounted from vintage year to P_0 + * fv_to_pv( + global_discount_rate, vintage - p_0 + ) # finally, discounted from vintage year to P_0 ) return res def loan_cost_survival_curve( - M: TemoaModel, + model: TemoaModel, r: str, t: str, v: int, @@ -193,9 +201,9 @@ def loan_cost_survival_curve( invest_cost: float, loan_annualize: float, lifetime_loan_process: float | int, - P_0: int, - P_e: int, - GDR: float, + p_0: int, + p_e: int, + global_discount_rate: float, ) -> float | Expression: """ function to calculate the loan cost only in the case of processes :math:`(r, t, v)` using @@ -218,20 +226,20 @@ def loan_cost_survival_curve( * loan_annualize # calculate loan annuities for investment cost, if used ) - if not GDR: + if not global_discount_rate: # Undiscounted result res = ( annuity * lifetime_loan_process # sum of loan payments over loan period / sum( # redistributed over survival curve within horizon - value(M.LifetimeSurvivalCurve[r, p, t, v]) - for p in M.survivalCurvePeriods[r, t, v] + value(model.LifetimeSurvivalCurve[r, p, t, v]) + for p in model.survivalCurvePeriods[r, t, v] if v <= p ) * sum( # summed over survival curve within horizon - value(M.LifetimeSurvivalCurve[r, p, t, v]) - for p in M.survivalCurvePeriods[r, t, v] - if v <= p < P_e + value(model.LifetimeSurvivalCurve[r, p, t, v]) + for p in model.survivalCurvePeriods[r, t, v] + if v <= p < p_e ) ) else: @@ -239,22 +247,27 @@ def loan_cost_survival_curve( res = ( annuity * annuity_to_pv( - GDR, int(lifetime_loan_process) + global_discount_rate, int(lifetime_loan_process) ) # PV of all loan payments, discounted to vintage year using GDR / sum( # redistributed over survival curve within horizon value( - M.LifetimeSurvivalCurve[r, p, t, v] + model.LifetimeSurvivalCurve[r, p, t, v] ) # reamortised over survival curve of process using GDR - * fv_to_pv(GDR, p - v + 1) # +1 because LSC is indexed to start of p not end of p - for p in M.survivalCurvePeriods[r, t, v] + * fv_to_pv( + global_discount_rate, p - v + 1 + ) # +1 because LSC is indexed to start of p not end of p + for p in model.survivalCurvePeriods[r, t, v] if v <= p # this shouldnt be possible but play it safe ) * sum( # PV of all reamortised costs (within planning horizon) - value(M.LifetimeSurvivalCurve[r, p, t, v]) * fv_to_pv(GDR, p - v + 1) - for p in M.survivalCurvePeriods[r, t, v] - if v <= p < P_e + value(model.LifetimeSurvivalCurve[r, p, t, v]) + * fv_to_pv(global_discount_rate, p - v + 1) + for p in model.survivalCurvePeriods[r, t, v] + if v <= p < p_e ) - * fv_to_pv(GDR, v - P_0) # finally, discounted from vintage year to P_0 + * fv_to_pv( + global_discount_rate, v - p_0 + ) # finally, discounted from vintage year to P_0 ) return res @@ -263,8 +276,8 @@ def fixed_or_variable_cost( cap_or_flow: float | Var | ComponentData, cost_factor: float, cost_years: float | ComponentData, - GDR: float | None, - P_0: float, + global_discount_rate: float | None, + p_0: float, p: int, ) -> float | Expression: """ @@ -281,7 +294,7 @@ def fixed_or_variable_cost( annual_cost = cap_or_flow * cost_factor # annual fixed, variable, or emission cost - if not GDR: + if not global_discount_rate: # Undiscounted result return annual_cost * cost_years # annual cost times years paying that cost else: @@ -289,9 +302,9 @@ def fixed_or_variable_cost( return ( annual_cost * annuity_to_pv( - GDR, int(cost_years) + global_discount_rate, int(cost_years) ) # PV of annual costs over this period, discounted to period p - * fv_to_pv(GDR, int(p - P_0)) # discounted from p to p_0 + * fv_to_pv(global_discount_rate, int(p - p_0)) # discounted from p to p_0 ) @@ -300,91 +313,91 @@ def fixed_or_variable_cost( # ============================================================================ -def PeriodCost_rule(M: TemoaModel, p: int) -> float | Expression: - P_0 = min(M.time_optimize) - P_e = M.time_future.last() # End point of modeled horizon - GDR = value(M.GlobalDiscountRate) +def period_cost_rule(model: TemoaModel, p: int) -> float | Expression: + p_0 = min(model.time_optimize) + p_e = model.time_future.last() # End point of modeled horizon + global_discount_rate = value(model.GlobalDiscountRate) # MPL = M.ModelProcessLife - if value(M.MyopicDiscountingYear) != 0: - P_0 = value(M.MyopicDiscountingYear) + if value(model.MyopicDiscountingYear) != 0: + p_0 = value(model.MyopicDiscountingYear) loan_costs = quicksum( loan_cost( - M.V_NewCapacity[r, S_t, S_v], - value(M.CostInvest[r, S_t, S_v]), - value(M.LoanAnnualize[r, S_t, S_v]), - value(M.LoanLifetimeProcess[r, S_t, S_v]), - value(M.LifetimeProcess[r, S_t, S_v]), - P_0, - P_e, - GDR, + model.V_NewCapacity[r, S_t, S_v], + value(model.CostInvest[r, S_t, S_v]), + value(model.LoanAnnualize[r, S_t, S_v]), + value(model.LoanLifetimeProcess[r, S_t, S_v]), + value(model.LifetimeProcess[r, S_t, S_v]), + p_0, + p_e, + global_discount_rate, vintage=S_v, ) - for r, S_t, S_v in M.CostInvest.sparse_iterkeys() - if S_v == p and not M.isSurvivalCurveProcess[r, S_t, S_v] + for r, S_t, S_v in model.CostInvest.sparse_iterkeys() + if S_v == p and not model.isSurvivalCurveProcess[r, S_t, S_v] ) loan_costs += quicksum( loan_cost_survival_curve( - M, + model, r, S_t, S_v, - M.V_NewCapacity[r, S_t, S_v], - value(M.CostInvest[r, S_t, S_v]), - value(M.LoanAnnualize[r, S_t, S_v]), - value(M.LoanLifetimeProcess[r, S_t, S_v]), - P_0, - P_e, - GDR, + model.V_NewCapacity[r, S_t, S_v], + value(model.CostInvest[r, S_t, S_v]), + value(model.LoanAnnualize[r, S_t, S_v]), + value(model.LoanLifetimeProcess[r, S_t, S_v]), + p_0, + p_e, + global_discount_rate, ) - for r, S_t, S_v in M.CostInvest.sparse_iterkeys() - if S_v == p and M.isSurvivalCurveProcess[r, S_t, S_v] + for r, S_t, S_v in model.CostInvest.sparse_iterkeys() + if S_v == p and model.isSurvivalCurveProcess[r, S_t, S_v] ) fixed_costs = quicksum( fixed_or_variable_cost( - M.V_Capacity[r, p, S_t, S_v], - value(M.CostFixed[r, p, S_t, S_v]), - value(M.PeriodLength[p]), - GDR, - P_0, + model.V_Capacity[r, p, S_t, S_v], + value(model.CostFixed[r, p, S_t, S_v]), + value(model.PeriodLength[p]), + global_discount_rate, + p_0, p=p, ) - for r, S_p, S_t, S_v in M.CostFixed.sparse_iterkeys() + for r, S_p, S_t, S_v in model.CostFixed.sparse_iterkeys() if S_p == p ) variable_costs = quicksum( fixed_or_variable_cost( - M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, S_o], - value(M.CostVariable[r, p, S_t, S_v]), - value(M.PeriodLength[p]), - GDR, - P_0, + model.V_FlowOut[r, p, s, d, S_i, S_t, S_v, S_o], + value(model.CostVariable[r, p, S_t, S_v]), + value(model.PeriodLength[p]), + global_discount_rate, + p_0, p, ) - for r, S_p, S_t, S_v in M.CostVariable.sparse_iterkeys() - if S_p == p and S_t not in M.tech_annual - for S_i in M.processInputs[r, S_p, S_t, S_v] - for S_o in M.processOutputsByInput[r, S_p, S_t, S_v, S_i] - for s in M.TimeSeason[p] - for d in M.time_of_day + for r, S_p, S_t, S_v in model.CostVariable.sparse_iterkeys() + if S_p == p and S_t not in model.tech_annual + for S_i in model.processInputs[r, S_p, S_t, S_v] + for S_o in model.processOutputsByInput[r, S_p, S_t, S_v, S_i] + for s in model.TimeSeason[p] + for d in model.time_of_day ) variable_costs_annual = quicksum( fixed_or_variable_cost( - M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, S_o], - value(M.CostVariable[r, p, S_t, S_v]), - value(M.PeriodLength[p]), - GDR, - P_0, + model.V_FlowOutAnnual[r, p, S_i, S_t, S_v, S_o], + value(model.CostVariable[r, p, S_t, S_v]), + value(model.PeriodLength[p]), + global_discount_rate, + p_0, p, ) - for r, S_p, S_t, S_v in M.CostVariable.sparse_iterkeys() - if S_p == p and S_t in M.tech_annual - for S_i in M.processInputs[r, S_p, S_t, S_v] - for S_o in M.processOutputsByInput[r, S_p, S_t, S_v, S_i] + for r, S_p, S_t, S_v in model.CostVariable.sparse_iterkeys() + if S_p == p and S_t in model.tech_annual + for S_i in model.processInputs[r, S_p, S_t, S_v] + for S_o in model.processOutputsByInput[r, S_p, S_t, S_v, S_i] ) # The emissions costs occur over the five possible emission sources. @@ -401,31 +414,31 @@ def PeriodCost_rule(M: TemoaModel, p: int) -> float | Expression: base = [ (r, p, e, i, t, v, o) - for (r, e, i, t, v, o) in M.EmissionActivity.sparse_iterkeys() - if (r, p, e) in M.CostEmission # tightest filter first - and (r, p, t, v) in M.processInputs + for (r, e, i, t, v, o) in model.EmissionActivity.sparse_iterkeys() + if (r, p, e) in model.CostEmission # tightest filter first + and (r, p, t, v) in model.processInputs ] # then expand the base for the normal (season/tod) set and annual separately: normal = [ (r, p, e, s, d, i, t, v, o) for (r, p, e, i, t, v, o) in base - for s in M.TimeSeason[p] - for d in M.time_of_day - if t not in M.tech_annual + for s in model.TimeSeason[p] + for d in model.time_of_day + if t not in model.tech_annual ] - annual = [(r, p, e, i, t, v, o) for (r, p, e, i, t, v, o) in base if t in M.tech_annual] + annual = [(r, p, e, i, t, v, o) for (r, p, e, i, t, v, o) in base if t in model.tech_annual] # 1. variable emissions var_emissions = quicksum( fixed_or_variable_cost( - cap_or_flow=M.V_FlowOut[r, p, s, d, i, t, v, o] - * value(M.EmissionActivity[r, e, i, t, v, o]), - cost_factor=value(M.CostEmission[r, p, e]), - cost_years=value(M.PeriodLength[p]), - GDR=GDR, - P_0=P_0, + cap_or_flow=model.V_FlowOut[r, p, s, d, i, t, v, o] + * value(model.EmissionActivity[r, e, i, t, v, o]), + cost_factor=value(model.CostEmission[r, p, e]), + cost_years=value(model.PeriodLength[p]), + global_discount_rate=global_discount_rate, + p_0=p_0, p=p, ) for (r, p, e, s, d, i, t, v, o) in normal @@ -438,16 +451,16 @@ def PeriodCost_rule(M: TemoaModel, p: int) -> float | Expression: # 4. annual emissions var_annual_emissions = quicksum( fixed_or_variable_cost( - cap_or_flow=M.V_FlowOutAnnual[r, p, i, t, v, o] - * value(M.EmissionActivity[r, e, i, t, v, o]), - cost_factor=value(M.CostEmission[r, p, e]), - cost_years=value(M.PeriodLength[p]), - GDR=GDR, - P_0=P_0, + cap_or_flow=model.V_FlowOutAnnual[r, p, i, t, v, o] + * value(model.EmissionActivity[r, e, i, t, v, o]), + cost_factor=value(model.CostEmission[r, p, e]), + cost_years=value(model.PeriodLength[p]), + global_discount_rate=global_discount_rate, + p_0=p_0, p=p, ) for (r, p, e, i, t, v, o) in annual - if t not in M.tech_flex + if t not in model.tech_flex ) # 5. flex annual emissions -- removed (double counting, flex wastes are SUBTRACTIVE from flowout) @@ -455,37 +468,38 @@ def PeriodCost_rule(M: TemoaModel, p: int) -> float | Expression: # 6. embodied - treated as a fixed cost distributed over the deployment period (vintage) embodied_emissions = quicksum( fixed_or_variable_cost( - cap_or_flow=M.V_NewCapacity[r, t, v] - * value(M.EmissionEmbodied[r, e, t, v]) - / value(M.PeriodLength[p]), - cost_factor=value(M.CostEmission[r, p, e]), + cap_or_flow=model.V_NewCapacity[r, t, v] + * value(model.EmissionEmbodied[r, e, t, v]) + / value(model.PeriodLength[p]), + cost_factor=value(model.CostEmission[r, p, e]), cost_years=value( - M.PeriodLength[v] + model.PeriodLength[v] ), # We assume the embodied emissions are emitted in the same year as the capacity is installed. - GDR=GDR, - P_0=P_0, + global_discount_rate=global_discount_rate, + p_0=p_0, p=p, ) - for (r, e, t, v) in M.EmissionEmbodied.sparse_iterkeys() - if (r, p, e) in M.CostEmission + for (r, e, t, v) in model.EmissionEmbodied.sparse_iterkeys() + if (r, p, e) in model.CostEmission if v == p ) # 6. endoflife - treated as a fixed cost distributed over the retirement period endoflife_emissions = quicksum( fixed_or_variable_cost( - cap_or_flow=M.V_AnnualRetirement[r, p, t, v] * value(M.EmissionEndOfLife[r, e, t, v]), - cost_factor=value(M.CostEmission[r, p, e]), + cap_or_flow=model.V_AnnualRetirement[r, p, t, v] + * value(model.EmissionEndOfLife[r, e, t, v]), + cost_factor=value(model.CostEmission[r, p, e]), cost_years=value( - M.PeriodLength[p] + model.PeriodLength[p] ), # We assume the embodied emissions are emitted in the same year as the capacity is installed. - GDR=GDR, - P_0=P_0, + global_discount_rate=global_discount_rate, + p_0=p_0, p=p, ) - for (r, e, t, v) in M.EmissionEndOfLife.sparse_iterkeys() - if (r, p, e) in M.CostEmission - if (r, t, v) in M.retirementPeriods and p in M.retirementPeriods[r, t, v] + for (r, e, t, v) in model.EmissionEndOfLife.sparse_iterkeys() + if (r, p, e) in model.CostEmission + if (r, t, v) in model.retirementPeriods and p in model.retirementPeriods[r, t, v] ) period_emission_cost = ( @@ -501,7 +515,7 @@ def PeriodCost_rule(M: TemoaModel, p: int) -> float | Expression: # --------------------------------------------------------------- # Define the Objective Function # --------------------------------------------------------------- -def TotalCost_rule(M: TemoaModel) -> Expression: +def total_cost_rule(model: TemoaModel) -> Expression: r""" Using the :code:`FlowOut` and :code:`Capacity` variables, the Temoa objective @@ -635,7 +649,7 @@ def TotalCost_rule(M: TemoaModel) -> Expression: \end{aligned} """ - return quicksum(PeriodCost_rule(M, p) for p in M.time_optimize) + return quicksum(period_cost_rule(model, p) for p in model.time_optimize) # ============================================================================ @@ -644,7 +658,7 @@ def TotalCost_rule(M: TemoaModel) -> Expression: @deprecated(reason='vintage defaults are no longer available, so this should not be needed') -def CreateCosts(M: TemoaModel) -> None: +def create_costs(model: TemoaModel) -> None: """ Steps to creating fixed and variable costs: 1. Collect all possible cost indices (CostFixed, CostVariable) @@ -652,17 +666,16 @@ def CreateCosts(M: TemoaModel) -> None: 3. Set them, based on Cost*VintageDefault """ logger.debug('Started Creating Fixed and Variable costs in CreateCosts()') - # Shorter names, for us lazy programmer types - CF = M.CostFixed - CV = M.CostVariable + cost_fixed = model.CostFixed + cost_variable = model.CostVariable # Step 1 - fixed_indices = set(M.CostFixed_rptv) - var_indices = set(M.CostVariable_rptv) + fixed_indices = set(model.CostFixed_rptv) + var_indices = set(model.CostVariable_rptv) # Step 2 - unspecified_fixed_prices = fixed_indices.difference(CF.sparse_iterkeys()) - unspecified_var_prices = var_indices.difference(CV.sparse_iterkeys()) + unspecified_fixed_prices = fixed_indices.difference(cost_fixed.sparse_iterkeys()) + unspecified_var_prices = var_indices.difference(cost_variable.sparse_iterkeys()) # Step 3 @@ -674,23 +687,27 @@ def CreateCosts(M: TemoaModel) -> None: if unspecified_fixed_prices: # CF._constructed = False for r, p, t, v in unspecified_fixed_prices: - if (r, t, v) in M.CostFixedVintageDefault: - CF[r, p, t, v] = M.CostFixedVintageDefault[r, t, v] # CF._constructed = True + if (r, t, v) in model.CostFixedVintageDefault: + cost_fixed[r, p, t, v] = model.CostFixedVintageDefault[ + r, t, v + ] # CF._constructed = True if unspecified_var_prices: # CV._constructed = False for r, p, t, v in unspecified_var_prices: - if (r, t, v) in M.CostVariableVintageDefault: - CV[r, p, t, v] = M.CostVariableVintageDefault[r, t, v] + if (r, t, v) in model.CostVariableVintageDefault: + cost_variable[r, p, t, v] = model.CostVariableVintageDefault[r, t, v] # CV._constructed = True - logger.debug('Created M.CostFixed with size: %d', len(value(M.CostFixed))) - logger.debug('Created M.CostVariable with size: %d', len(value(M.CostVariable))) + logger.debug('Created M.CostFixed with size: %d', len(value(model.CostFixed))) + logger.debug('Created M.CostVariable with size: %d', len(value(model.CostVariable))) logger.debug('Finished creating Fixed and Variable costs') -def ParamLoanAnnualize_rule(M: TemoaModel, r: str, t: str, v: int) -> float | Expression: +def param_loan_annualize_rule( + model: TemoaModel, r: Region, t: Technology, v: Vintage +) -> float | Expression: """Rule to calculate the annualized loan rate from the loan rate and lifetime.""" - dr = value(M.LoanRate[r, t, v]) - lln = value(M.LoanLifetimeProcess[r, t, v]) + dr = value(model.LoanRate[r, t, v]) + lln = value(model.LoanLifetimeProcess[r, t, v]) annualized_rate = pv_to_annuity(dr, lln) return annualized_rate diff --git a/temoa/components/emissions.py b/temoa/components/emissions.py index 19997aa0f..57a62da99 100644 --- a/temoa/components/emissions.py +++ b/temoa/components/emissions.py @@ -9,12 +9,15 @@ input to a downstream process (e.g., synthetic fuel production). """ +from __future__ import annotations + from typing import TYPE_CHECKING from pyomo.core import quicksum from pyomo.environ import value from temoa.types import ExprLike +from temoa.types.core_types import Commodity, Period, Region, Season, Technology, TimeOfDay, Vintage if TYPE_CHECKING: from temoa.core.model import TemoaModel @@ -25,27 +28,31 @@ # ============================================================================ -def EmissionActivityIndices(M: 'TemoaModel') -> set[tuple[str, str, str, str, int, str]]: +def emission_activity_indices( + model: TemoaModel, +) -> set[tuple[Region, Commodity, Commodity, Technology, Vintage, Commodity]]: indices = { (r, e, i, t, v, o) - for r, i, t, v, o in M.Efficiency.sparse_iterkeys() - for e in M.commodity_emissions - if r in M.regions # omit any exchange/groups + for r, i, t, v, o in model.Efficiency.sparse_iterkeys() + for e in model.commodity_emissions + if r in model.regions # omit any exchange/groups } return indices -def LinkedTechConstraintIndices(M: 'TemoaModel') -> set[tuple[str, int, str, str, str, int, str]]: +def linked_tech_constraint_indices( + model: TemoaModel, +) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage, Commodity]]: linkedtech_indices = { (r, p, s, d, t, v, e) - for r, t, e in M.LinkedTechs.sparse_iterkeys() - for p in M.time_optimize - if (r, p, t) in M.processVintages - for v in M.processVintages[r, p, t] - if M.activeActivity_rptv and (r, p, t, v) in M.activeActivity_rptv - for s in M.TimeSeason[p] - for d in M.time_of_day + for r, t, e in model.LinkedTechs.sparse_iterkeys() + for p in model.time_optimize + if (r, p, t) in model.processVintages + for v in model.processVintages[r, p, t] + if model.activeActivity_rptv and (r, p, t, v) in model.activeActivity_rptv + for s in model.TimeSeason[p] + for d in model.time_of_day } return linkedtech_indices @@ -56,8 +63,15 @@ def LinkedTechConstraintIndices(M: 'TemoaModel') -> set[tuple[str, int, str, str # ============================================================================ -def LinkedEmissionsTech_Constraint( - M: 'TemoaModel', r: str, p: int, s: str, d: str, t: str, v: int, e: str +def linked_emissions_tech_constraint( + model: TemoaModel, + r: Region, + p: Period, + s: Season, + d: TimeOfDay, + t: Technology, + v: Vintage, + e: Commodity, ) -> ExprLike: r""" This constraint is necessary for carbon capture technologies that produce @@ -82,27 +96,27 @@ def LinkedEmissionsTech_Constraint( of the primary and linked technologies should be specified and identical. """ - if t in M.tech_annual: + if t in model.tech_annual: primary_flow = quicksum( ( - value(M.DemandSpecificDistribution[r, p, s, d, S_o]) - if S_o in M.commodity_demand - else value(M.SegFrac[p, s, d]) + value(model.DemandSpecificDistribution[r, p, s, d, S_o]) + if S_o in model.commodity_demand + else value(model.SegFrac[p, s, d]) ) - * M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] - * value(M.EmissionActivity[r, e, S_i, t, v, S_o]) - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + * model.V_FlowOutAnnual[r, p, S_i, t, v, S_o] + * value(model.EmissionActivity[r, e, S_i, t, v, S_o]) + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) else: primary_flow = quicksum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - * value(M.EmissionActivity[r, e, S_i, t, v, S_o]) - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + * value(model.EmissionActivity[r, e, S_i, t, v, S_o]) + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) - linked_t = value(M.LinkedTechs[r, t, e]) + linked_t = value(model.LinkedTechs[r, t, e]) # linked_flow = sum( # M.V_FlowOut[r, p, s, d, S_i, linked_t, v, S_o] @@ -110,22 +124,22 @@ def LinkedEmissionsTech_Constraint( # for S_o in M.processOutputsByInput[r, p, linked_t, v, S_i] # ) - if linked_t in M.tech_annual: + if linked_t in model.tech_annual: linked_flow = quicksum( ( - value(M.DemandSpecificDistribution[r, p, s, d, S_o]) - if S_o in M.commodity_demand - else value(M.SegFrac[p, s, d]) + value(model.DemandSpecificDistribution[r, p, s, d, S_o]) + if S_o in model.commodity_demand + else value(model.SegFrac[p, s, d]) ) - * M.V_FlowOutAnnual[r, p, S_i, linked_t, v, S_o] - for S_i in M.processInputs[r, p, linked_t, v] - for S_o in M.processOutputsByInput[r, p, linked_t, v, S_i] + * model.V_FlowOutAnnual[r, p, S_i, linked_t, v, S_o] + for S_i in model.processInputs[r, p, linked_t, v] + for S_o in model.processOutputsByInput[r, p, linked_t, v, S_i] ) else: linked_flow = quicksum( - M.V_FlowOut[r, p, s, d, S_i, linked_t, v, S_o] - for S_i in M.processInputs[r, p, linked_t, v] - for S_o in M.processOutputsByInput[r, p, linked_t, v, S_i] + model.V_FlowOut[r, p, s, d, S_i, linked_t, v, S_o] + for S_i in model.processInputs[r, p, linked_t, v] + for S_o in model.processOutputsByInput[r, p, linked_t, v, S_i] ) return -primary_flow == linked_flow diff --git a/temoa/components/flows.py b/temoa/components/flows.py index 7cfec112a..918b1f475 100644 --- a/temoa/components/flows.py +++ b/temoa/components/flows.py @@ -9,16 +9,27 @@ decision variables (V_FlowOut, V_FlowIn, V_Flex, etc.). """ +from __future__ import annotations + from logging import getLogger from typing import TYPE_CHECKING +from temoa.types.core_types import ( + Commodity, + Period, + Region, + Season, + Technology, + TimeOfDay, + Vintage, +) + if TYPE_CHECKING: from temoa.core.model import TemoaModel from temoa.types import ( ActiveFlexAnnualSet, ActiveFlowAnnualSet, - RegionPeriodSeasonTimeInputTechVintageOutput, ) logger = getLogger(__name__) @@ -29,40 +40,48 @@ # ============================================================================ -def FlowVariableIndices( - M: 'TemoaModel', -) -> set[RegionPeriodSeasonTimeInputTechVintageOutput] | None: - return M.activeFlow_rpsditvo +def flow_variable_indices( + model: TemoaModel, +) -> ( + set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] | None +): + return model.activeFlow_rpsditvo -def FlowVariableAnnualIndices( - M: 'TemoaModel', +def flow_variable_annual_indices( + model: TemoaModel, ) -> ActiveFlowAnnualSet: - return M.activeFlow_rpitvo + return model.activeFlow_rpitvo -def FlexVariablelIndices( - M: 'TemoaModel', -) -> set[RegionPeriodSeasonTimeInputTechVintageOutput] | None: - return M.activeFlex_rpsditvo +def flex_variable_indices( + model: TemoaModel, +) -> ( + set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] | None +): + return model.activeFlex_rpsditvo -def FlexVariableAnnualIndices( - M: 'TemoaModel', +def flex_variable_annual_indices( + model: TemoaModel, ) -> ActiveFlexAnnualSet: - return M.activeFlex_rpitvo + return model.activeFlex_rpitvo -def FlowInStorageVariableIndices( - M: 'TemoaModel', -) -> set[RegionPeriodSeasonTimeInputTechVintageOutput] | None: - return M.activeFlowInStorage_rpsditvo +def flow_in_storage_variable_indices( + model: TemoaModel, +) -> ( + set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] | None +): + return model.activeFlowInStorage_rpsditvo -def CurtailmentVariableIndices( - M: 'TemoaModel', -) -> set[RegionPeriodSeasonTimeInputTechVintageOutput] | None: - return M.activeCurtailment_rpsditvo +def curtailment_variable_indices( + model: TemoaModel, +) -> ( + set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] | None +): + return model.activeCurtailment_rpsditvo # ============================================================================ @@ -70,7 +89,7 @@ def CurtailmentVariableIndices( # ============================================================================ -def create_commodity_balance_and_flow_sets(M: 'TemoaModel') -> None: +def create_commodity_balance_and_flow_sets(model: TemoaModel) -> None: """ Creates aggregated sets for commodity balances and detailed index sets for active flows. @@ -93,96 +112,96 @@ def create_commodity_balance_and_flow_sets(M: 'TemoaModel') -> None: logger.debug('Creating commodity balance and active flow index sets.') # 1. Commodity Balance commodity_upstream = set( - M.commodityUStreamProcess | M.retirementProductionProcesses | M.importRegions + model.commodityUStreamProcess | model.retirementProductionProcesses | model.importRegions ) commodity_downstream = set( - M.commodityDStreamProcess | M.capacityConsumptionTechs | M.exportRegions + model.commodityDStreamProcess | model.capacityConsumptionTechs | model.exportRegions ) - M.commodityBalance_rpc = commodity_upstream.intersection(commodity_downstream) + model.commodityBalance_rpc = commodity_upstream.intersection(commodity_downstream) # 2. Active Flow Indices (Time-Sliced) - M.activeFlow_rpsditvo = { + model.activeFlow_rpsditvo = { (r, p, s, d, i, t, v, o) - for r, p, t in M.processVintages - if t not in M.tech_annual - for v in M.processVintages[r, p, t] - for i in M.processInputs.get((r, p, t, v), set()) - for o in M.processOutputsByInput.get((r, p, t, v, i), set()) - for s in M.TimeSeason[p] # REVERTED THIS LINE - for d in M.time_of_day + for r, p, t in model.processVintages + if t not in model.tech_annual + for v in model.processVintages[r, p, t] + for i in model.processInputs.get((r, p, t, v), set()) + for o in model.processOutputsByInput.get((r, p, t, v, i), set()) + for s in model.TimeSeason[p] # REVERTED THIS LINE + for d in model.time_of_day } # 3. Active Flow Indices (Annual) - M.activeFlow_rpitvo = { + model.activeFlow_rpitvo = { (r, p, i, t, v, o) - for r, p, t in M.processVintages - for v in M.processVintages[r, p, t] - for i in M.processInputs.get((r, p, t, v), set()) - for o in M.processOutputsByInput.get((r, p, t, v, i), set()) - if t in M.tech_annual or (t in M.tech_demand and o in M.commodity_demand) + for r, p, t in model.processVintages + for v in model.processVintages[r, p, t] + for i in model.processInputs.get((r, p, t, v), set()) + for o in model.processOutputsByInput.get((r, p, t, v, i), set()) + if t in model.tech_annual or (t in model.tech_demand and o in model.commodity_demand) } # 4. Active Flexible Technology Flow Indices - M.activeFlex_rpsditvo = { + model.activeFlex_rpsditvo = { (r, p, s, d, i, t, v, o) - for r, p, t in M.processVintages - if (t not in M.tech_annual) and (t in M.tech_flex) - for v in M.processVintages[r, p, t] - for i in M.processInputs.get((r, p, t, v), set()) - for o in M.processOutputsByInput.get((r, p, t, v, i), set()) - for s in M.TimeSeason[p] # REVERTED THIS LINE - for d in M.time_of_day + for r, p, t in model.processVintages + if (t not in model.tech_annual) and (t in model.tech_flex) + for v in model.processVintages[r, p, t] + for i in model.processInputs.get((r, p, t, v), set()) + for o in model.processOutputsByInput.get((r, p, t, v, i), set()) + for s in model.TimeSeason[p] # REVERTED THIS LINE + for d in model.time_of_day } - M.activeFlex_rpitvo = { + model.activeFlex_rpitvo = { (r, p, i, t, v, o) - for r, p, t in M.processVintages - if (t in M.tech_annual) and (t in M.tech_flex) - for v in M.processVintages[r, p, t] - for i in M.processInputs.get((r, p, t, v), set()) - for o in M.processOutputsByInput.get((r, p, t, v, i), set()) + for r, p, t in model.processVintages + if (t in model.tech_annual) and (t in model.tech_flex) + for v in model.processVintages[r, p, t] + for i in model.processInputs.get((r, p, t, v), set()) + for o in model.processOutputsByInput.get((r, p, t, v, i), set()) } # 5. Active Storage and Curtailment Indices - M.activeFlowInStorage_rpsditvo = { + model.activeFlowInStorage_rpsditvo = { (r, p, s, d, i, t, v, o) - for r, p, t in M.storageVintages - for v in M.storageVintages[r, p, t] - for i in M.processInputs.get((r, p, t, v), set()) - for o in M.processOutputsByInput.get((r, p, t, v, i), set()) - for s in M.TimeSeason[p] # REVERTED THIS LINE - for d in M.time_of_day + for r, p, t in model.storageVintages + for v in model.storageVintages[r, p, t] + for i in model.processInputs.get((r, p, t, v), set()) + for o in model.processOutputsByInput.get((r, p, t, v, i), set()) + for s in model.TimeSeason[p] # REVERTED THIS LINE + for d in model.time_of_day } - M.activeCurtailment_rpsditvo = { + model.activeCurtailment_rpsditvo = { (r, p, s, d, i, t, v, o) - for r, p, t in M.curtailmentVintages - for v in M.curtailmentVintages[r, p, t] - for i in M.processInputs.get((r, p, t, v), set()) - for o in M.processOutputsByInput.get((r, p, t, v, i), set()) - for s in M.TimeSeason[p] # REVERTED THIS LINE - for d in M.time_of_day + for r, p, t in model.curtailmentVintages + for v in model.curtailmentVintages[r, p, t] + for i in model.processInputs.get((r, p, t, v), set()) + for o in model.processOutputsByInput.get((r, p, t, v, i), set()) + for s in model.TimeSeason[p] # REVERTED THIS LINE + for d in model.time_of_day } # 6. Active Technology and Capacity Indices - M.activeActivity_rptv = { - (r, p, t, v) for r, p, t in M.processVintages for v in M.processVintages[r, p, t] + model.activeActivity_rptv = { + (r, p, t, v) for r, p, t in model.processVintages for v in model.processVintages[r, p, t] } # 7. Storage Level Indices - M.storageLevelIndices_rpsdtv = { + model.storageLevelIndices_rpsdtv = { (r, p, s, d, t, v) - for r, p, t in M.storageVintages - for v in M.storageVintages[r, p, t] - for s in M.TimeSeason[p] # REVERTED THIS LINE - for d in M.time_of_day + for r, p, t in model.storageVintages + for v in model.storageVintages[r, p, t] + for s in model.TimeSeason[p] # REVERTED THIS LINE + for d in model.time_of_day } - M.seasonalStorageLevelIndices_rpstv = { + model.seasonalStorageLevelIndices_rpstv = { (r, p, s_stor, t, v) - for r, p, t in M.storageVintages - if t in M.tech_seasonal_storage - for v in M.storageVintages[r, p, t] - for _p, s_stor in M.sequential_to_season + for r, p, t in model.storageVintages + if t in model.tech_seasonal_storage + for v in model.storageVintages[r, p, t] + for _p, s_stor in model.sequential_to_season if _p == p } diff --git a/temoa/components/geography.py b/temoa/components/geography.py index f92b4d5e0..63280032e 100644 --- a/temoa/components/geography.py +++ b/temoa/components/geography.py @@ -10,6 +10,8 @@ - Defining constraints that govern inter-regional capacity and flows. """ +from __future__ import annotations + from collections.abc import Iterable from logging import getLogger from typing import TYPE_CHECKING @@ -21,7 +23,7 @@ from temoa.core.model import TemoaModel # Import type annotations -from temoa.types import Period, Region, Technology, Vintage +from temoa.types import ExprLike, Period, Region, Technology, Vintage logger = getLogger(name=__name__) @@ -30,10 +32,10 @@ # ============================================================================ -def gather_group_regions(M: 'TemoaModel', region: Region) -> Iterable[Region]: +def gather_group_regions(model: TemoaModel, region: Region) -> Iterable[Region]: regions: list[Region] if region == 'global': - regions = list(M.regions) + regions = list(model.regions) elif '+' in region: regions = region.split('+') else: @@ -46,14 +48,14 @@ def gather_group_regions(M: 'TemoaModel', region: Region) -> Iterable[Region]: # ============================================================================ -def CreateRegionalIndices(M: 'TemoaModel') -> list[Region]: +def create_regional_indices(model: TemoaModel) -> list[Region]: """Create the set of all regions and all region-region pairs""" regional_indices: set[Region] = set() - for r_i in M.regions: + for r_i in model.regions: if '-' in r_i: logger.error("Individual region names can not have '-' in their names: %s", str(r_i)) raise ValueError("Individual region names can not have '-' in their names: " + str(r_i)) - for r_j in M.regions: + for r_j in model.regions: if r_i == r_j: regional_indices.add(r_i) else: @@ -63,16 +65,16 @@ def CreateRegionalIndices(M: 'TemoaModel') -> list[Region]: @deprecated('No longer used. See the region_group_check in validators.py') -def RegionalGlobalInitializedIndices(M: 'TemoaModel') -> set[Region]: +def regional_global_initialized_indices(model: TemoaModel) -> set[Region]: from itertools import permutations indices: set[Region] = set() - for n in range(1, len(M.regions) + 1): - regional_perms = permutations(M.regions, n) + for n in range(1, len(model.regions) + 1): + regional_perms = permutations(model.regions, n) for i in regional_perms: indices.add('+'.join(i)) indices.add('global') - indices = indices.union(M.regionalIndices) + indices = indices.union(model.regionalIndices) return indices @@ -82,9 +84,9 @@ def RegionalGlobalInitializedIndices(M: 'TemoaModel') -> set[Region]: # ============================================================================ -def RegionalExchangeCapacity_Constraint( - M: 'TemoaModel', r_e: Region, r_i: Region, p: Period, t: Technology, v: Vintage -) -> object: +def regional_exchange_capacity_constraint( + model: TemoaModel, r_e: Region, r_i: Region, p: Period, t: Technology, v: Vintage +) -> ExprLike: r""" This constraint ensures that the process (t,v) connecting regions @@ -101,7 +103,7 @@ def RegionalExchangeCapacity_Constraint( \forall \{r_e, r_i, t, v\} \in \Theta_{\text{RegionalExchangeCapacity}} """ - expr = M.V_Capacity[r_e + '-' + r_i, p, t, v] == M.V_Capacity[r_i + '-' + r_e, p, t, v] + expr = model.V_Capacity[r_e + '-' + r_i, p, t, v] == model.V_Capacity[r_i + '-' + r_e, p, t, v] return expr @@ -111,7 +113,7 @@ def RegionalExchangeCapacity_Constraint( # ============================================================================ -def create_geography_sets(M: 'TemoaModel') -> None: +def create_geography_sets(model: TemoaModel) -> None: """ Populates dictionaries related to inter-regional commodity exchange. @@ -126,8 +128,8 @@ def create_geography_sets(M: 'TemoaModel') -> None: of (region_from, t, v, i) tuples. """ logger.debug('Creating geography-related sets for exchange technologies.') - for r, i, t, v, o in M.Efficiency.sparse_iterkeys(): - if t not in M.tech_exchange: + for r, i, t, v, o in model.Efficiency.sparse_iterkeys(): + if t not in model.tech_exchange: continue if '-' not in r: @@ -137,8 +139,8 @@ def create_geography_sets(M: 'TemoaModel') -> None: region_from, region_to = r.split('-', 1) - lifetime: float = value(M.LifetimeProcess[r, t, v]) - for p in M.time_optimize: + lifetime: float = value(model.LifetimeProcess[r, t, v]) + for p in model.time_optimize: if p >= v and v + lifetime > p: - M.exportRegions.setdefault((region_from, p, i), set()).add((region_to, t, v, o)) - M.importRegions.setdefault((region_to, p, o), set()).add((region_from, t, v, i)) + model.exportRegions.setdefault((region_from, p, i), set()).add((region_to, t, v, o)) + model.importRegions.setdefault((region_to, p, o), set()).add((region_from, t, v, i)) diff --git a/temoa/components/limits.py b/temoa/components/limits.py index 4e8d310f9..6fbfcc645 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -10,16 +10,19 @@ - Absolute limits on capacity, new investment, or emissions. """ +from __future__ import annotations + import sys from logging import getLogger -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING from pyomo.environ import Constraint, quicksum, value import temoa.components.geography as geography import temoa.components.technology as technology from temoa.components.utils import Operator, get_variable_efficiency, operator_expression -from temoa.types import Period, Region, Technology, Vintage +from temoa.types import ExprLike, Period, Region, Technology, Vintage +from temoa.types.core_types import Commodity, Season, TimeOfDay if TYPE_CHECKING: from temoa.core.model import TemoaModel @@ -31,19 +34,19 @@ # ============================================================================ -def LimitTechInputSplitConstraintIndices( - M: 'TemoaModel', -) -> set[tuple[Region, Period, str, str, str, str, Vintage, str]]: +def limit_tech_input_split_constraint_indices( + model: TemoaModel, +) -> set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, str]]: indices = { (r, p, s, d, i, t, v, op) - for r, p, i, t, op in M.inputSplitVintages - if t not in M.tech_annual - for v in M.inputSplitVintages[r, p, i, t, op] - for s in M.TimeSeason[p] - for d in M.time_of_day + for r, p, i, t, op in model.inputSplitVintages + if t not in model.tech_annual + for v in model.inputSplitVintages[r, p, i, t, op] + for s in model.TimeSeason[p] + for d in model.time_of_day } ann_indices = { - (r, p, i, t, op) for r, p, i, t, op in M.inputSplitVintages if t in M.tech_annual + (r, p, i, t, op) for r, p, i, t, op in model.inputSplitVintages if t in model.tech_annual } if len(ann_indices) > 0: msg = ( @@ -55,44 +58,44 @@ def LimitTechInputSplitConstraintIndices( return indices -def LimitTechInputSplitAnnualConstraintIndices( - M: 'TemoaModel', -) -> set[tuple[Region, Period, str, str, Vintage, str]]: +def limit_tech_input_split_annual_constraint_indices( + model: TemoaModel, +) -> set[tuple[Region, Period, Commodity, Technology, Vintage, str]]: indices = { (r, p, i, t, v, op) - for r, p, i, t, op in M.inputSplitAnnualVintages - if t in M.tech_annual - for v in M.inputSplitAnnualVintages[r, p, i, t, op] + for r, p, i, t, op in model.inputSplitAnnualVintages + if t in model.tech_annual + for v in model.inputSplitAnnualVintages[r, p, i, t, op] } return indices -def LimitTechInputSplitAverageConstraintIndices( - M: 'TemoaModel', -) -> set[tuple[Region, Period, str, str, Vintage, str]]: +def limit_tech_input_split_average_constraint_indices( + model: TemoaModel, +) -> set[tuple[Region, Period, Commodity, Technology, Vintage, str]]: indices = { (r, p, i, t, v, op) - for r, p, i, t, op in M.inputSplitAnnualVintages - if t not in M.tech_annual - for v in M.inputSplitAnnualVintages[r, p, i, t, op] + for r, p, i, t, op in model.inputSplitAnnualVintages + if t not in model.tech_annual + for v in model.inputSplitAnnualVintages[r, p, i, t, op] } return indices -def LimitTechOutputSplitConstraintIndices( - M: 'TemoaModel', -) -> set[tuple[Region, Period, str, str, str, Vintage, str, str]]: +def limit_tech_output_split_constraint_indices( + model: TemoaModel, +) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage, Commodity, str]]: indices = { (r, p, s, d, t, v, o, op) - for r, p, t, o, op in M.outputSplitVintages - if t not in M.tech_annual - for v in M.outputSplitVintages[r, p, t, o, op] - for s in M.TimeSeason[p] - for d in M.time_of_day + for r, p, t, o, op in model.outputSplitVintages + if t not in model.tech_annual + for v in model.outputSplitVintages[r, p, t, o, op] + for s in model.TimeSeason[p] + for d in model.time_of_day } ann_indices = { - (r, p, t, o, op) for r, p, t, o, op in M.outputSplitVintages if t in M.tech_annual + (r, p, t, o, op) for r, p, t, o, op in model.outputSplitVintages if t in model.tech_annual } if len(ann_indices) > 0: msg = ( @@ -104,84 +107,90 @@ def LimitTechOutputSplitConstraintIndices( return indices -def LimitTechOutputSplitAnnualConstraintIndices( - M: 'TemoaModel', -) -> set[tuple[Region, Period, str, Vintage, str, str]]: +def limit_tech_output_split_annual_constraint_indices( + model: TemoaModel, +) -> set[tuple[Region, Period, Technology, Vintage, Commodity, str]]: indices = { (r, p, t, v, o, op) - for r, p, t, o, op in M.outputSplitAnnualVintages - if t in M.tech_annual - for v in M.outputSplitAnnualVintages[r, p, t, o, op] + for r, p, t, o, op in model.outputSplitAnnualVintages + if t in model.tech_annual + for v in model.outputSplitAnnualVintages[r, p, t, o, op] } return indices -def LimitTechOutputSplitAverageConstraintIndices( - M: 'TemoaModel', -) -> set[tuple[Region, Period, str, Vintage, str, str]]: +def limit_tech_output_split_average_constraint_indices( + model: TemoaModel, +) -> set[tuple[Region, Period, Technology, Vintage, Commodity, str]]: indices = { (r, p, t, v, o, op) - for r, p, t, o, op in M.outputSplitAnnualVintages - if t not in M.tech_annual - for v in M.outputSplitAnnualVintages[r, p, t, o, op] + for r, p, t, o, op in model.outputSplitAnnualVintages + if t not in model.tech_annual + for v in model.outputSplitAnnualVintages[r, p, t, o, op] } return indices -def LimitGrowthCapacityIndices(M: 'TemoaModel') -> set[tuple[Region, Period, Technology, str]]: +def limit_growth_capacity_indices(model: TemoaModel) -> set[tuple[Region, Period, Technology, str]]: indices = { (r, p, t, op) - for r, t, op in M.LimitGrowthCapacity.sparse_iterkeys() - for p in M.time_optimize + for r, t, op in model.LimitGrowthCapacity.sparse_iterkeys() + for p in model.time_optimize } return indices -def LimitDegrowthCapacityIndices(M: 'TemoaModel') -> set[tuple[Region, Period, Technology, str]]: +def limit_degrowth_capacity_indices( + model: TemoaModel, +) -> set[tuple[Region, Period, Technology, str]]: indices = { (r, p, t, op) - for r, t, op in M.LimitDegrowthCapacity.sparse_iterkeys() - for p in M.time_optimize + for r, t, op in model.LimitDegrowthCapacity.sparse_iterkeys() + for p in model.time_optimize } return indices -def LimitGrowthNewCapacityIndices(M: 'TemoaModel') -> set[tuple[Region, Period, Technology, str]]: +def limit_growth_new_capacity_indices( + model: TemoaModel, +) -> set[tuple[Region, Period, Technology, str]]: indices = { (r, p, t, op) - for r, t, op in M.LimitGrowthNewCapacity.sparse_iterkeys() - for p in M.time_optimize + for r, t, op in model.LimitGrowthNewCapacity.sparse_iterkeys() + for p in model.time_optimize } return indices -def LimitDegrowthNewCapacityIndices(M: 'TemoaModel') -> set[tuple[Region, Period, Technology, str]]: +def limit_degrowth_new_capacity_indices( + model: TemoaModel, +) -> set[tuple[Region, Period, Technology, str]]: indices = { (r, p, t, op) - for r, t, op in M.LimitDegrowthNewCapacity.sparse_iterkeys() - for p in M.time_optimize + for r, t, op in model.LimitDegrowthNewCapacity.sparse_iterkeys() + for p in model.time_optimize } return indices -def LimitGrowthNewCapacityDeltaIndices( - M: 'TemoaModel', +def limit_growth_new_capacity_delta_indices( + model: TemoaModel, ) -> set[tuple[Region, Period, Technology, str]]: indices = { (r, p, t, op) - for r, t, op in M.LimitGrowthNewCapacityDelta.sparse_iterkeys() - for p in M.time_optimize + for r, t, op in model.LimitGrowthNewCapacityDelta.sparse_iterkeys() + for p in model.time_optimize } return indices -def LimitDegrowthNewCapacityDeltaIndices( - M: 'TemoaModel', +def limit_degrowth_new_capacity_delta_indices( + model: TemoaModel, ) -> set[tuple[Region, Period, Technology, str]]: indices = { (r, p, t, op) - for r, t, op in M.LimitDegrowthNewCapacityDelta.sparse_iterkeys() - for p in M.time_optimize + for r, t, op in model.LimitDegrowthNewCapacityDelta.sparse_iterkeys() + for p in model.time_optimize } return indices @@ -192,7 +201,9 @@ def LimitDegrowthNewCapacityDeltaIndices( # @deprecated('Deprecated. Use LimitActivityGroupShare instead') # doesn't play well with pyomo -def RenewablePortfolioStandard_Constraint(M: 'TemoaModel', r: Region, p: Period, g: str) -> Any: +def renewable_portfolio_standard_constraint( + model: TemoaModel, r: Region, p: Period, g: str +) -> ExprLike: r""" Allows users to specify the share of electricity generation in a region coming from RPS-eligible technologies. @@ -202,30 +213,30 @@ def RenewablePortfolioStandard_Constraint(M: 'TemoaModel', r: Region, p: Period, # it has been deprecated in favour of the LimitActivityGroupShare constraint. inp = quicksum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for t in M.tech_group_members[g] - for (_t, v) in M.processReservePeriods.get((r, p), []) + model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for t in model.tech_group_members[g] + for (_t, v) in model.processReservePeriods.get((r, p), []) if _t == t - for s in M.TimeSeason[p] - for d in M.time_of_day - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + for s in model.TimeSeason[p] + for d in model.time_of_day + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) total_inp = quicksum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for (t, v) in M.processReservePeriods[r, p] - for s in M.TimeSeason[p] - for d in M.time_of_day - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for (t, v) in model.processReservePeriods[r, p] + for s in model.TimeSeason[p] + for d in model.time_of_day + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) - expr = inp >= (value(M.RenewablePortfolioStandard[r, p, g]) * total_inp) + expr = inp >= (value(model.RenewablePortfolioStandard[r, p, g]) * total_inp) return expr -def LimitResource_Constraint(M: 'TemoaModel', r: Region, t: Technology, op: str) -> Any: +def limit_resource_constraint(model: TemoaModel, r: Region, t: Technology, op: str) -> ExprLike: r""" The LimitResource constraint sets a limit on the available resource of a @@ -247,42 +258,42 @@ def LimitResource_Constraint(M: 'TemoaModel', r: Region, t: Technology, op: str) # dev note: this would generally be applied to a "dummy import" technology to restrict something like # oil/mineral extraction across all model periods. Looks fine to me. - regions = geography.gather_group_regions(M, r) - techs = technology.gather_group_techs(M, t) + regions = geography.gather_group_regions(model, r) + techs = technology.gather_group_techs(model, t) activity = quicksum( - M.V_FlowOutAnnual[_r, p, S_i, _t, S_v, S_o] + model.V_FlowOutAnnual[_r, p, S_i, _t, S_v, S_o] for _t in techs - if _t in M.tech_annual - for p in M.time_optimize + if _t in model.tech_annual + for p in model.time_optimize for _r in regions - if (_r, p, _t) in M.processVintages - 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] + if (_r, p, _t) in model.processVintages + for S_v in model.processVintages[_r, p, _t] + for S_i in model.processInputs[_r, p, _t, S_v] + for S_o in model.processOutputsByInput[_r, p, _t, S_v, S_i] ) activity += quicksum( - M.V_FlowOut[_r, p, s, d, S_i, _t, S_v, S_o] + model.V_FlowOut[_r, p, s, d, S_i, _t, S_v, S_o] for _t in techs - if _t not in M.tech_annual - for p in M.time_optimize + if _t not in model.tech_annual + for p in model.time_optimize for _r in regions - if (_r, p, _t) in M.processVintages - 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.TimeSeason[p] - for d in M.time_of_day + if (_r, p, _t) in model.processVintages + for S_v in model.processVintages[_r, p, _t] + for S_i in model.processInputs[_r, p, _t, S_v] + for S_o in model.processOutputsByInput[_r, p, _t, S_v, S_i] + for s in model.TimeSeason[p] + for d in model.time_of_day ) - resource_lim = value(M.LimitResource[r, t, op]) + resource_lim = value(model.LimitResource[r, t, op]) expr = operator_expression(activity, Operator(op), resource_lim) return expr -def LimitActivityShare_Constraint( - M: 'TemoaModel', r: Region, p: Period, g1: str, g2: str, op: str -) -> Any: +def limit_activity_share_constraint( + model: TemoaModel, r: Region, p: Period, g1: str, g2: str, op: str +) -> ExprLike: r""" Limits the activity of a given technology or group as a fraction of another technology or group, summed over a period. This can be used to set, for example, @@ -298,53 +309,53 @@ def LimitActivityShare_Constraint( \qquad \forall \{r, p, g_1, g_2\} \in \Theta_{\text{LimitActivityShare}} """ - regions = geography.gather_group_regions(M, r) + regions = geography.gather_group_regions(model, r) - sub_group = technology.gather_group_techs(M, g1) + sub_group = technology.gather_group_techs(model, g1) sub_activity = quicksum( - M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] + model.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] for S_t in sub_group - if S_t not in M.tech_annual + if S_t not in model.tech_annual for _r in regions - for S_v in M.processVintages.get((_r, p, S_t), []) - for S_i in M.processInputs[_r, p, S_t, S_v] - for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - for s in M.TimeSeason[p] - for d in M.time_of_day + for S_v in model.processVintages.get((_r, p, S_t), []) + for S_i in model.processInputs[_r, p, S_t, S_v] + for S_o in model.processOutputsByInput[_r, p, S_t, S_v, S_i] + for s in model.TimeSeason[p] + for d in model.time_of_day ) sub_activity += quicksum( - M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] + model.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] for S_t in sub_group - if S_t in M.tech_annual + if S_t in model.tech_annual for _r in regions - for S_v in M.processVintages.get((_r, p, S_t), []) - for S_i in M.processInputs[_r, p, S_t, S_v] - for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] + for S_v in model.processVintages.get((_r, p, S_t), []) + for S_i in model.processInputs[_r, p, S_t, S_v] + for S_o in model.processOutputsByInput[_r, p, S_t, S_v, S_i] ) - super_group = technology.gather_group_techs(M, g2) + super_group = technology.gather_group_techs(model, g2) super_activity = quicksum( - M.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] + model.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] for S_t in super_group - if S_t not in M.tech_annual + if S_t not in model.tech_annual for _r in regions - for S_v in M.processVintages.get((_r, p, S_t), []) - for S_i in M.processInputs[_r, p, S_t, S_v] - for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] - for s in M.TimeSeason[p] - for d in M.time_of_day + for S_v in model.processVintages.get((_r, p, S_t), []) + for S_i in model.processInputs[_r, p, S_t, S_v] + for S_o in model.processOutputsByInput[_r, p, S_t, S_v, S_i] + for s in model.TimeSeason[p] + for d in model.time_of_day ) super_activity += quicksum( - M.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] + model.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] for S_t in super_group - if S_t in M.tech_annual + if S_t in model.tech_annual for _r in regions - for S_v in M.processVintages.get((_r, p, S_t), []) - for S_i in M.processInputs[_r, p, S_t, S_v] - for S_o in M.processOutputsByInput[_r, p, S_t, S_v, S_i] + for S_v in model.processVintages.get((_r, p, S_t), []) + for S_i in model.processInputs[_r, p, S_t, S_v] + for S_o in model.processOutputsByInput[_r, p, S_t, S_v, S_i] ) - share_lim = value(M.LimitActivityShare[r, p, g1, g2, op]) + share_lim = value(model.LimitActivityShare[r, p, g1, g2, op]) expr = operator_expression(sub_activity, Operator(op), share_lim * super_activity) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated @@ -360,32 +371,32 @@ def LimitActivityShare_Constraint( return expr -def LimitCapacityShare_Constraint( - M: 'TemoaModel', r: Region, p: Period, g1: str, g2: str, op: str -) -> Any: +def limit_capacity_share_constraint( + model: TemoaModel, r: Region, p: Period, g1: str, g2: str, op: str +) -> ExprLike: r""" The LimitCapacityShare constraint limits the available capacity of a given technology or technology group as a fraction of another technology or group. """ - regions = geography.gather_group_regions(M, r) + regions = geography.gather_group_regions(model, r) - sub_group = technology.gather_group_techs(M, g1) + sub_group = technology.gather_group_techs(model, g1) sub_capacity = quicksum( - M.V_CapacityAvailableByPeriodAndTech[_r, p, _t] + model.V_CapacityAvailableByPeriodAndTech[_r, p, _t] for _t in sub_group for _r in regions - if (_r, p, _t) in M.processVintages + if (_r, p, _t) in model.processVintages ) - super_group = technology.gather_group_techs(M, g2) + super_group = technology.gather_group_techs(model, g2) super_capacity = quicksum( - M.V_CapacityAvailableByPeriodAndTech[_r, p, _t] + model.V_CapacityAvailableByPeriodAndTech[_r, p, _t] for _t in super_group for _r in regions - if (_r, p, _t) in M.processVintages + if (_r, p, _t) in model.processVintages ) - share_lim = value(M.LimitCapacityShare[r, p, g1, g2, op]) + share_lim = value(model.LimitCapacityShare[r, p, g1, g2, op]) expr = operator_expression(sub_capacity, Operator(op), share_lim * super_capacity) if isinstance(expr, bool): @@ -393,42 +404,42 @@ def LimitCapacityShare_Constraint( return expr -def LimitNewCapacityShare_Constraint( - M: 'TemoaModel', r: Region, p: Period, g1: str, g2: str, op: str -) -> Any: +def limit_new_capacity_share_constraint( + model: TemoaModel, r: Region, p: Period, g1: str, g2: str, op: str +) -> ExprLike: r""" The LimitNewCapacityShare constraint limits the share of new capacity of a given technology or group as a fraction of another technology or group.""" - regions = geography.gather_group_regions(M, r) + regions = geography.gather_group_regions(model, r) - sub_group = technology.gather_group_techs(M, g1) + sub_group = technology.gather_group_techs(model, g1) sub_new_cap = quicksum( - M.V_NewCapacity[_r, _t, p] + model.V_NewCapacity[_r, _t, p] for _t in sub_group for _r in regions - if (_r, _t, p) in M.processPeriods + if (_r, _t, p) in model.processPeriods ) - super_group = technology.gather_group_techs(M, g2) + super_group = technology.gather_group_techs(model, g2) super_new_cap = quicksum( - M.V_NewCapacity[_r, _t, p] + model.V_NewCapacity[_r, _t, p] for _t in super_group for _r in regions - if (_r, _t, p) in M.processPeriods + if (_r, _t, p) in model.processPeriods ) - share_lim = value(M.LimitNewCapacityShare[r, p, g1, g2, op]) + share_lim = value(model.LimitNewCapacityShare[r, p, g1, g2, op]) expr = operator_expression(sub_new_cap, Operator(op), share_lim * super_new_cap) if isinstance(expr, bool): return Constraint.Skip return expr -def LimitAnnualCapacityFactor_Constraint( - M: 'TemoaModel', r: Region, p: Period, t: Technology, o: str, op: str -) -> Any: +def limit_annual_capacity_factor_constraint( + model: TemoaModel, r: Region, p: Period, t: Technology, o: Commodity, op: str +) -> ExprLike: r""" The LimitAnnualCapacityFactor sets an upper bound on the annual capacity factor from a specific technology. The first portion of the constraint pertains to @@ -449,34 +460,34 @@ def LimitAnnualCapacityFactor_Constraint( """ # r can be an individual region (r='US'), or a combination of regions separated by plus (r='Mexico+US+Canada'), or 'global'. # if r == 'global', the constraint is system-wide - regions = geography.gather_group_regions(M, r) + regions = geography.gather_group_regions(model, r) # we need to screen here because it is possible that the restriction extends beyond the # lifetime of any vintage of the tech... - if all((_r, p, t) not in M.V_CapacityAvailableByPeriodAndTech for _r in regions): + if all((_r, p, t) not in model.V_CapacityAvailableByPeriodAndTech for _r in regions): return Constraint.Skip - if t not in M.tech_annual: + if t not in model.tech_annual: activity_rpt = quicksum( - M.V_FlowOut[_r, p, s, d, S_i, t, S_v, o] + model.V_FlowOut[_r, p, s, d, S_i, t, S_v, o] for _r in regions - for S_v in M.processVintages.get((_r, p, t), []) - for S_i in M.processInputs[_r, p, t, S_v] - for s in M.TimeSeason[p] - for d in M.time_of_day + for S_v in model.processVintages.get((_r, p, t), []) + for S_i in model.processInputs[_r, p, t, S_v] + for s in model.TimeSeason[p] + for d in model.time_of_day ) else: activity_rpt = quicksum( - M.V_FlowOutAnnual[_r, p, S_i, t, S_v, o] + model.V_FlowOutAnnual[_r, p, S_i, t, S_v, o] for _r in regions - for S_v in M.processVintages.get((_r, p, t), []) - for S_i in M.processInputs[_r, p, t, S_v] + for S_v in model.processVintages.get((_r, p, t), []) + for S_i in model.processInputs[_r, p, t, S_v] ) possible_activity_rpt = quicksum( - M.V_CapacityAvailableByPeriodAndTech[_r, p, t] * value(M.CapacityToActivity[_r, t]) + model.V_CapacityAvailableByPeriodAndTech[_r, p, t] * value(model.CapacityToActivity[_r, t]) for _r in regions ) - annual_cf = value(M.LimitAnnualCapacityFactor[r, p, t, o, op]) + annual_cf = value(model.LimitAnnualCapacityFactor[r, p, t, o, op]) expr = operator_expression(activity_rpt, Operator(op), annual_cf * possible_activity_rpt) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated @@ -484,9 +495,9 @@ def LimitAnnualCapacityFactor_Constraint( return expr -def LimitSeasonalCapacityFactor_Constraint( - M: 'TemoaModel', r: Region, p: Period, s: str, t: Technology, op: str -) -> Any: +def limit_seasonal_capacity_factor_constraint( + model: TemoaModel, r: Region, p: Period, s: Season, t: Technology, op: str +) -> ExprLike: r""" The LimitSeasonalCapacityFactor sets an upper bound on the seasonal capacity factor from a specific technology. The first portion of the constraint pertains to @@ -507,37 +518,37 @@ def LimitSeasonalCapacityFactor_Constraint( """ # r can be an individual region (r='US'), or a combination of regions separated by plus (r='Mexico+US+Canada'), or 'global'. # if r == 'global', the constraint is system-wide - regions = geography.gather_group_regions(M, r) + regions = geography.gather_group_regions(model, r) # we need to screen here because it is possible that the restriction extends beyond the # lifetime of any vintage of the tech... - if all((_r, p, t) not in M.V_CapacityAvailableByPeriodAndTech for _r in regions): + if all((_r, p, t) not in model.V_CapacityAvailableByPeriodAndTech for _r in regions): return Constraint.Skip - if t not in M.tech_annual: + if t not in model.tech_annual: activity_rpst = quicksum( - M.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] + model.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] for _r in regions - 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 d in M.time_of_day + for S_v in model.processVintages[_r, p, t] + for S_i in model.processInputs[_r, p, t, S_v] + for S_o in model.processOutputsByInput[_r, p, t, S_v, S_i] + for d in model.time_of_day ) else: activity_rpst = quicksum( - M.V_FlowOutAnnual[_r, p, S_i, t, S_v, S_o] * M.SegFracPerSeason[p, s] + model.V_FlowOutAnnual[_r, p, S_i, t, S_v, S_o] * model.SegFracPerSeason[p, s] for _r in regions - 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_v in model.processVintages[_r, p, t] + for S_i in model.processInputs[_r, p, t, S_v] + for S_o in model.processOutputsByInput[_r, p, t, S_v, S_i] ) possible_activity_rpst = quicksum( - M.V_CapacityAvailableByPeriodAndTech[_r, p, t] - * value(M.CapacityToActivity[_r, t]) - * value(M.SegFracPerSeason[p, s]) + model.V_CapacityAvailableByPeriodAndTech[_r, p, t] + * value(model.CapacityToActivity[_r, t]) + * value(model.SegFracPerSeason[p, s]) for _r in regions ) - seasonal_cf = value(M.LimitSeasonalCapacityFactor[r, p, s, t, op]) + seasonal_cf = value(model.LimitSeasonalCapacityFactor[r, p, s, t, op]) expr = operator_expression(activity_rpst, Operator(op), seasonal_cf * possible_activity_rpst) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated @@ -545,17 +556,17 @@ def LimitSeasonalCapacityFactor_Constraint( return expr -def LimitTechInputSplit_Constraint( - M: 'TemoaModel', +def limit_tech_input_split_constraint( + model: TemoaModel, r: Region, p: Period, - s: str, - d: str, - i: str, + s: Season, + d: TimeOfDay, + i: Commodity, t: Technology, v: Vintage, op: str, -) -> Any: +) -> ExprLike: r""" Allows users to limit shares of commodity inputs to a process producing a single output. These shares can vary by model time period. See @@ -563,26 +574,27 @@ def LimitTechInputSplit_Constraint( only the technologies with variable output at the timeslice level (i.e., NOT in the :code:`tech_annual` set) are considered.""" inp = quicksum( - M.V_FlowOut[r, p, s, d, i, t, v, S_o] / get_variable_efficiency(M, r, p, s, d, i, t, v, S_o) - for S_o in M.processOutputsByInput[r, p, t, v, i] + model.V_FlowOut[r, p, s, d, i, t, v, S_o] + / get_variable_efficiency(model, r, p, s, d, i, t, v, S_o) + for S_o in model.processOutputsByInput[r, p, t, v, i] ) total_inp = quicksum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - / get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + / get_variable_efficiency(model, r, p, s, d, S_i, t, v, S_o) + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) expr = operator_expression( - inp, Operator(op), value(M.LimitTechInputSplit[r, p, i, t, op]) * total_inp + inp, Operator(op), value(model.LimitTechInputSplit[r, p, i, t, op]) * total_inp ) return expr -def LimitTechInputSplitAnnual_Constraint( - M: 'TemoaModel', r: Region, p: Period, i: str, t: Technology, v: Vintage, op: str -) -> Any: +def limit_tech_input_split_annual_constraint( + model: TemoaModel, r: Region, p: Period, i: Commodity, t: Technology, v: Vintage, op: str +) -> ExprLike: r""" Allows users to limit shares of commodity inputs to a process producing a single output. These shares can vary by model time period. See @@ -590,25 +602,25 @@ def LimitTechInputSplitAnnual_Constraint( function, only the technologies with constant annual output (i.e., members of the :code:`tech_annual` set) are considered.""" inp = quicksum( - M.V_FlowOutAnnual[r, p, i, t, v, S_o] / value(M.Efficiency[r, i, t, v, S_o]) - for S_o in M.processOutputsByInput[r, p, t, v, i] + model.V_FlowOutAnnual[r, p, i, t, v, S_o] / value(model.Efficiency[r, i, t, v, S_o]) + for S_o in model.processOutputsByInput[r, p, t, v, i] ) total_inp = quicksum( - M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] / value(M.Efficiency[r, S_i, t, v, S_o]) - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + model.V_FlowOutAnnual[r, p, S_i, t, v, S_o] / value(model.Efficiency[r, S_i, t, v, S_o]) + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) expr = operator_expression( - inp, Operator(op), value(M.LimitTechInputSplitAnnual[r, p, i, t, op]) * total_inp + inp, Operator(op), value(model.LimitTechInputSplitAnnual[r, p, i, t, op]) * total_inp ) return expr -def LimitTechInputSplitAverage_Constraint( - M: 'TemoaModel', r: Region, p: Period, i: str, t: Technology, v: Vintage, op: str -) -> Any: +def limit_tech_input_split_average_constraint( + model: TemoaModel, r: Region, p: Period, i: Commodity, t: Technology, v: Vintage, op: str +) -> ExprLike: r""" Allows users to limit shares of commodity inputs to a process producing a single output. Under this constraint, only the technologies with variable @@ -618,39 +630,39 @@ def LimitTechInputSplitAverage_Constraint( the constraint only fixes the input shares over the course of a year.""" inp = quicksum( - M.V_FlowOut[r, p, S_s, S_d, i, t, v, S_o] - / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day - for S_o in M.processOutputsByInput[r, p, t, v, i] + model.V_FlowOut[r, p, S_s, S_d, i, t, v, S_o] + / get_variable_efficiency(model, r, p, S_s, S_d, i, t, v, S_o) + for S_s in model.TimeSeason[p] + for S_d in model.time_of_day + for S_o in model.processOutputsByInput[r, p, t, v, i] ) total_inp = quicksum( - M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] - / get_variable_efficiency(M, r, p, S_s, S_d, i, t, v, S_o) - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, i] + model.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] + / get_variable_efficiency(model, r, p, S_s, S_d, i, t, v, S_o) + for S_s in model.TimeSeason[p] + for S_d in model.time_of_day + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, i] ) expr = operator_expression( - inp, Operator(op), value(M.LimitTechInputSplitAnnual[r, p, i, t, op]) * total_inp + inp, Operator(op), value(model.LimitTechInputSplitAnnual[r, p, i, t, op]) * total_inp ) return expr -def LimitTechOutputSplit_Constraint( - M: 'TemoaModel', +def limit_tech_output_split_constraint( + model: TemoaModel, r: Region, p: Period, - s: str, - d: str, + s: Season, + d: TimeOfDay, t: Technology, v: Vintage, - o: str, + o: Commodity, op: str, -) -> Any: +) -> ExprLike: r""" Some processes take a single input and make multiple outputs, and the user would like to @@ -686,24 +698,25 @@ def LimitTechOutputSplit_Constraint( \forall \{r, p, s, d, t, v, o\} \in \Theta_{\text{LimitTechOutputSplit}}""" out = quicksum( - M.V_FlowOut[r, p, s, d, S_i, t, v, o] for S_i in M.processInputsByOutput[r, p, t, v, o] + model.V_FlowOut[r, p, s, d, S_i, t, v, o] + for S_i in model.processInputsByOutput[r, p, t, v, o] ) total_out = quicksum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) expr = operator_expression( - out, Operator(op), value(M.LimitTechOutputSplit[r, p, t, o, op]) * total_out + out, Operator(op), value(model.LimitTechOutputSplit[r, p, t, o, op]) * total_out ) return expr -def LimitTechOutputSplitAnnual_Constraint( - M: 'TemoaModel', r: Region, p: Period, t: Technology, v: Vintage, o: str, op: str -) -> Any: +def limit_tech_output_split_annual_constraint( + model: TemoaModel, r: Region, p: Period, t: Technology, v: Vintage, o: Commodity, op: str +) -> ExprLike: r""" This constraint operates similarly to LimitTechOutputSplit_Constraint. However, under this function, only the technologies with constant annual @@ -718,24 +731,25 @@ def LimitTechOutputSplitAnnual_Constraint( \forall \{r, p, t \in T^{a}, v, o\} \in \Theta_{\text{LimitTechOutputSplitAnnual}}""" out = quicksum( - M.V_FlowOutAnnual[r, p, S_i, t, v, o] for S_i in M.processInputsByOutput[r, p, t, v, o] + model.V_FlowOutAnnual[r, p, S_i, t, v, o] + for S_i in model.processInputsByOutput[r, p, t, v, o] ) total_out = quicksum( - M.V_FlowOutAnnual[r, p, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + model.V_FlowOutAnnual[r, p, S_i, t, v, S_o] + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) expr = operator_expression( - out, Operator(op), value(M.LimitTechOutputSplitAnnual[r, p, t, o, op]) * total_out + out, Operator(op), value(model.LimitTechOutputSplitAnnual[r, p, t, o, op]) * total_out ) return expr -def LimitTechOutputSplitAverage_Constraint( - M: 'TemoaModel', r: Region, p: Period, t: Technology, v: Vintage, o: str, op: str -) -> Any: +def limit_tech_output_split_average_constraint( + model: TemoaModel, r: Region, p: Period, t: Technology, v: Vintage, o: Commodity, op: str +) -> ExprLike: r""" Allows users to limit shares of commodity outputs from a process. Under this constraint, only the technologies with variable @@ -745,27 +759,29 @@ def LimitTechOutputSplitAverage_Constraint( the constraint only fixes the output shares over the course of a year.""" out = quicksum( - M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, o] - for S_i in M.processInputsByOutput[r, p, t, v, o] - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day + model.V_FlowOut[r, p, S_s, S_d, S_i, t, v, o] + for S_i in model.processInputsByOutput[r, p, t, v, o] + for S_s in model.TimeSeason[p] + for S_d in model.time_of_day ) total_out = quicksum( - M.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day + model.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] + for S_s in model.TimeSeason[p] + for S_d in model.time_of_day ) expr = operator_expression( - out, Operator(op), value(M.LimitTechOutputSplitAnnual[r, p, t, o, op]) * total_out + out, Operator(op), value(model.LimitTechOutputSplitAnnual[r, p, t, o, op]) * total_out ) return expr -def LimitEmission_Constraint(M: 'TemoaModel', r: Region, p: Period, e: str, op: str) -> Any: +def limit_emission_constraint( + model: TemoaModel, r: Region, p: Period, e: Commodity, op: str +) -> ExprLike: r""" A modeler can track emissions through use of the :code:`commodity_emissions` @@ -793,7 +809,7 @@ def LimitEmission_Constraint(M: 'TemoaModel', r: Region, p: Period, e: str, op: & \forall \{r, p, e\} \in \Theta_{\text{LimitEmission}} """ - emission_limit = value(M.LimitEmission[r, p, e, op]) + emission_limit = value(model.LimitEmission[r, p, e, op]) # 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 @@ -801,48 +817,48 @@ def LimitEmission_Constraint(M: 'TemoaModel', r: Region, p: Period, e: str, op: # if r == 'global', the constraint is system-wide - regions = geography.gather_group_regions(M, r) + regions = geography.gather_group_regions(model, r) # ================= Emissions and Flex and Curtailment ================= # Flex flows are deducted from V_FlowOut, so it is NOT NEEDED to tax them again. (See commodity balance constr) # Curtailment does not draw any inputs, so it seems logical that curtailed flows not be taxed either process_emissions = quicksum( - M.V_FlowOut[reg, p, S_s, S_d, S_i, S_t, S_v, S_o] - * value(M.EmissionActivity[reg, e, S_i, S_t, S_v, S_o]) + model.V_FlowOut[reg, p, S_s, S_d, S_i, S_t, S_v, S_o] + * value(model.EmissionActivity[reg, e, S_i, S_t, S_v, S_o]) for reg in regions - for tmp_r, tmp_e, S_i, S_t, S_v, S_o in M.EmissionActivity.sparse_iterkeys() - if tmp_e == e and tmp_r == reg and S_t not in M.tech_annual + for tmp_r, tmp_e, S_i, S_t, S_v, S_o in model.EmissionActivity.sparse_iterkeys() + if tmp_e == e and tmp_r == reg and S_t not in model.tech_annual # EmissionsActivity not indexed by p, so make sure (r,p,t,v) combos valid - if (reg, p, S_t, S_v) in M.processInputs - for S_s in M.TimeSeason[p] - for S_d in M.time_of_day + if (reg, p, S_t, S_v) in model.processInputs + for S_s in model.TimeSeason[p] + for S_d in model.time_of_day ) process_emissions_annual = quicksum( - M.V_FlowOutAnnual[reg, p, S_i, S_t, S_v, S_o] - * value(M.EmissionActivity[reg, e, S_i, S_t, S_v, S_o]) + model.V_FlowOutAnnual[reg, p, S_i, S_t, S_v, S_o] + * value(model.EmissionActivity[reg, e, S_i, S_t, S_v, S_o]) for reg in regions - for tmp_r, tmp_e, S_i, S_t, S_v, S_o in M.EmissionActivity.sparse_iterkeys() - if tmp_e == e and tmp_r == reg and S_t in M.tech_annual + for tmp_r, tmp_e, S_i, S_t, S_v, S_o in model.EmissionActivity.sparse_iterkeys() + if tmp_e == e and tmp_r == reg and S_t in model.tech_annual # EmissionsActivity not indexed by p, so make sure (r,p,t,v) combos valid - if (reg, p, S_t, S_v) in M.processInputs + if (reg, p, S_t, S_v) in model.processInputs ) embodied_emissions = quicksum( - M.V_NewCapacity[reg, t, v] - * value(M.EmissionEmbodied[reg, e, t, v]) - / value(M.PeriodLength[v]) + model.V_NewCapacity[reg, t, v] + * value(model.EmissionEmbodied[reg, e, t, v]) + / value(model.PeriodLength[v]) for reg in regions - for (S_r, S_e, t, v) in M.EmissionEmbodied.sparse_iterkeys() + for (S_r, S_e, t, v) in model.EmissionEmbodied.sparse_iterkeys() if v == p and S_r == reg and S_e == e ) retirement_emissions = quicksum( - M.V_AnnualRetirement[reg, p, t, v] * value(M.EmissionEndOfLife[reg, e, t, v]) + model.V_AnnualRetirement[reg, p, t, v] * value(model.EmissionEndOfLife[reg, e, t, v]) for reg in regions - for (S_r, S_e, t, v) in M.EmissionEndOfLife.sparse_iterkeys() - if (r, t, v) in M.retirementPeriods and p in M.retirementPeriods[r, t, v] + for (S_r, S_e, t, v) in model.EmissionEndOfLife.sparse_iterkeys() + if (r, t, v) in model.retirementPeriods and p in model.retirementPeriods[r, t, v] if S_r == reg and S_e == e ) @@ -864,23 +880,23 @@ def LimitEmission_Constraint(M: 'TemoaModel', r: Region, p: Period, e: str, op: return expr -def LimitGrowthCapacityConstraint_rule( - M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str -) -> Any: +def limit_growth_capacity_constraint_rule( + model: TemoaModel, r: Region, p: Period, t: Technology, op: str +) -> ExprLike: r"""Constrain ramp up rate of available capacity""" - return LimitGrowthCapacity(M, r, p, t, op, False) + return limit_growth_capacity(model, r, p, t, op, False) -def LimitDegrowthCapacityConstraint_rule( - M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str -) -> Any: +def limit_degrowth_capacity_constraint_rule( + model: TemoaModel, r: Region, p: Period, t: Technology, op: str +) -> ExprLike: r"""Constrain ramp down rate of available capacity""" - return LimitGrowthCapacity(M, r, p, t, op, True) + return limit_growth_capacity(model, r, p, t, op, True) -def LimitGrowthCapacity( - M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str, degrowth: bool = False -) -> Any: +def limit_growth_capacity( + model: TemoaModel, r: Region, p: Period, t: Technology, op: str, degrowth: bool = False +) -> ExprLike: r""" Constrain the change of capacity available between periods. Forces the model to ramp up and down the availability of new technologies @@ -910,21 +926,21 @@ def LimitGrowthCapacity( \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitDegrowthCapacity}} """ - regions = geography.gather_group_regions(M, r) - techs = technology.gather_group_techs(M, t) + regions = geography.gather_group_regions(model, r) + techs = technology.gather_group_techs(model, t) - growth = M.LimitDegrowthCapacity if degrowth else M.LimitGrowthCapacity - RATE = 1 + value(growth[r, t, op][0]) - SEED = value(growth[r, t, op][1]) - CapRPT = M.V_CapacityAvailableByPeriodAndTech + growth = model.LimitDegrowthCapacity if degrowth else model.LimitGrowthCapacity + rate = 1 + value(growth[r, t, op][0]) + seed = value(growth[r, t, op][1]) + cap_rpt = model.V_CapacityAvailableByPeriodAndTech # relevant r, p, t indices - cap_rpt = {(_r, _p, _t) for _r, _p, _t in CapRPT.keys() if _t in techs and _r in regions} + cap_indices = {(_r, _p, _t) for _r, _p, _t in cap_rpt.keys() if _t in techs and _r in regions} # periods the technology can have capacity in this region (sorted) periods = sorted({_p for _r, _p, _t in cap_rpt}) if len(periods) == 0: - if p == M.time_optimize.first(): + if p == model.time_optimize.first(): msg = ( 'Tried to set {}rowthCapacity constraint {} but there are no periods where this ' 'technology is available in this region. Constraint skipped.' @@ -934,14 +950,16 @@ def LimitGrowthCapacity( # Only warn in p0 so we dont dump multiple warnings if p == periods[0]: - if SEED == 0: + if seed == 0: msg = ( 'No constant term (seed) provided for {}rowthCapacity constraint {}. ' 'No capacity will be built in any period following one with zero capacity.' ).format('Deg' if degrowth else 'G', (r, t)) logger.info(msg) gaps = [ - _p for _p in M.time_optimize if _p not in periods and min(periods) < _p < max(periods) + _p + for _p in model.time_optimize + if _p not in periods and min(periods) < _p < max(periods) ] if gaps: msg = ( @@ -952,27 +970,29 @@ def LimitGrowthCapacity( logger.warning(msg) # sum available capacity in this period - capacity = quicksum(CapRPT[_r, _p, _t] for _r, _p, _t in cap_rpt if _p == p) + capacity = quicksum(cap_rpt[_r, _p, _t] for _r, _p, _t in cap_indices if _p == p) - if p == M.time_optimize.first(): + if p == model.time_optimize.first(): # First future period. Grab available capacity in last existing period # Adjust in-line for past PLF because we are constraining available capacity - p_prev = M.time_exist.last() + p_prev = model.time_exist.last() capacity_prev = sum( - value(M.ExistingCapacity[_r, _t, _v]) - * min(1.0, (_v + value(M.LifetimeProcess[_r, _t, _v]) - p_prev) / (p - p_prev)) - for _r, _t, _v in M.ExistingCapacity.sparse_iterkeys() - if _r in regions and _t in techs and _v + value(M.LifetimeProcess[_r, _t, _v]) > p_prev + value(model.ExistingCapacity[_r, _t, _v]) + * min(1.0, (_v + value(model.LifetimeProcess[_r, _t, _v]) - p_prev) / (p - p_prev)) + for _r, _t, _v in model.ExistingCapacity.sparse_iterkeys() + if _r in regions + and _t in techs + and _v + value(model.LifetimeProcess[_r, _t, _v]) > p_prev ) else: # Otherwise, grab previous future period - p_prev = M.time_optimize.prev(p) - capacity_prev = sum(CapRPT[_r, _p, _t] for _r, _p, _t in cap_rpt if _p == p_prev) + p_prev = model.time_optimize.prev(p) + capacity_prev = quicksum(cap_rpt[_r, _p, _t] for _r, _p, _t in cap_indices if _p == p_prev) if degrowth: - expr = operator_expression(capacity_prev, Operator(op), SEED + capacity * RATE) + expr = operator_expression(capacity_prev, Operator(op), seed + capacity * rate) else: - expr = operator_expression(capacity, Operator(op), SEED + capacity_prev * RATE) + expr = operator_expression(capacity, Operator(op), seed + capacity_prev * rate) # Check if any variables are actually included before returning if isinstance(expr, bool): @@ -980,23 +1000,23 @@ def LimitGrowthCapacity( return expr -def LimitGrowthNewCapacityConstraint_rule( - M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str -) -> Any: +def limit_growth_new_capacity_constraint_rule( + model: TemoaModel, r: Region, p: Period, t: Technology, op: str +) -> ExprLike: r"""Constrain ramp up rate of new capacity deployment""" - return LimitGrowthNewCapacity(M, r, p, t, op, False) + return limit_growth_new_capacity(model, r, p, t, op, False) -def LimitDegrowthNewCapacityConstraint_rule( - M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str -) -> Any: +def limit_degrowth_new_capacity_constraint_rule( + model: TemoaModel, r: Region, p: Period, t: Technology, op: str +) -> ExprLike: r"""Constrain ramp down rate of new capacity deployment""" - return LimitGrowthNewCapacity(M, r, p, t, op, True) + return limit_growth_new_capacity(model, r, p, t, op, True) -def LimitGrowthNewCapacity( - M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str, degrowth: bool = False -) -> Any: +def limit_growth_new_capacity( + model: TemoaModel, r: Region, p: Period, t: Technology, op: str, degrowth: bool = False +) -> ExprLike: r""" Constrain the change of new capacity deployed between periods. Forces the model to ramp up and down the deployment of new technologies @@ -1027,21 +1047,21 @@ def LimitGrowthNewCapacity( \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitDegrowthCapacity}} """ - regions = geography.gather_group_regions(M, r) - techs = technology.gather_group_techs(M, t) + regions = geography.gather_group_regions(model, r) + techs = technology.gather_group_techs(model, t) - growth = M.LimitDegrowthNewCapacity if degrowth else M.LimitGrowthNewCapacity - RATE = 1 + value(growth[r, t, op][0]) - SEED = value(growth[r, t, op][1]) - NewCapRTV = M.V_NewCapacity + growth = model.LimitDegrowthNewCapacity if degrowth else model.LimitGrowthNewCapacity + rate = 1 + value(growth[r, t, op][0]) + seed = value(growth[r, t, op][1]) + new_cap_rtv = model.V_NewCapacity # relevant r, t, v indices - cap_rtv = {(_r, _t, _v) for _r, _t, _v in NewCapRTV.keys() if _t in techs and _r in regions} + cap_rtv = {(_r, _t, _v) for _r, _t, _v in new_cap_rtv.keys() if _t in techs and _r in regions} # periods the technology can be built in this region (sorted) periods = sorted({_v for _r, _t, _v in cap_rtv}) if len(periods) == 0: - if p == M.time_optimize.first(): + if p == model.time_optimize.first(): msg = ( 'Tried to set {}rowthNewCapacity constraint {} but there are no periods where this ' 'technology can be built in this region. Constraint skipped.' @@ -1051,14 +1071,16 @@ def LimitGrowthNewCapacity( # Only warn in p0 so we dont dump multiple warnings if p == periods[0]: - if SEED == 0: + if seed == 0: msg = ( 'No constant term (seed) provided for {}rowthNewCapacity constraint {}. ' 'No capacity will be built in any period following one with zero new capacity.' ).format('Deg' if degrowth else 'G', (r, t)) logger.info(msg) gaps = [ - _p for _p in M.time_optimize if _p not in periods and min(periods) < _p < max(periods) + _p + for _p in model.time_optimize + if _p not in periods and min(periods) < _p < max(periods) ] if gaps: msg = ( @@ -1069,25 +1091,25 @@ def LimitGrowthNewCapacity( logger.warning(msg) # sum new capacity in this period - new_cap = quicksum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p) + new_cap = quicksum(new_cap_rtv[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p) - if p == M.time_optimize.first(): + if p == model.time_optimize.first(): # First future period. Grab last existing vintage - p_prev = M.time_exist.last() + p_prev = model.time_exist.last() new_cap_prev = sum( - value(M.ExistingCapacity[_r, _t, _v]) - for _r, _t, _v in M.ExistingCapacity.sparse_iterkeys() + value(model.ExistingCapacity[_r, _t, _v]) + for _r, _t, _v in model.ExistingCapacity.sparse_iterkeys() if _r in regions and _t in techs and _v == p_prev ) else: # Otherwise, grab previous future vintage - p_prev = M.time_optimize.prev(p) - new_cap_prev = sum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p_prev) + p_prev = model.time_optimize.prev(p) + new_cap_prev = sum(new_cap_rtv[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p_prev) if degrowth: - expr = operator_expression(new_cap_prev, Operator(op), SEED + new_cap * RATE) + expr = operator_expression(new_cap_prev, Operator(op), seed + new_cap * rate) else: - expr = operator_expression(new_cap, Operator(op), SEED + new_cap_prev * RATE) + expr = operator_expression(new_cap, Operator(op), seed + new_cap_prev * rate) # Check if any variables are actually included before returning if isinstance(expr, bool): @@ -1095,23 +1117,23 @@ def LimitGrowthNewCapacity( return expr -def LimitGrowthNewCapacityDeltaConstraint_rule( - M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str -) -> Any: +def limit_growth_new_capacity_delta_constraint_rule( + model: TemoaModel, r: Region, p: Period, t: Technology, op: str +) -> ExprLike: r"""Constrain ramp up rate of change in new capacity deployment""" - return LimitGrowthNewCapacityDelta(M, r, p, t, op, False) + return limit_growth_new_capacity_delta(model, r, p, t, op, False) -def LimitDegrowthNewCapacityDeltaConstraint_rule( - M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str -) -> Any: +def limit_degrowth_new_capacity_delta_constraint_rule( + model: TemoaModel, r: Region, p: Period, t: Technology, op: str +) -> ExprLike: r"""Constrain ramp down rate of change in new capacity deployment""" - return LimitGrowthNewCapacityDelta(M, r, p, t, op, True) + return limit_growth_new_capacity_delta(model, r, p, t, op, True) -def LimitGrowthNewCapacityDelta( - M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str, degrowth: bool = False -) -> Any: +def limit_growth_new_capacity_delta( + model: TemoaModel, r: Region, p: Period, t: Technology, op: str, degrowth: bool = False +) -> ExprLike: r""" Constrain the acceleration of new capacity deployed between periods. Forces the model to ramp up and down the change in deployment of new technologies @@ -1145,21 +1167,21 @@ def LimitGrowthNewCapacityDelta( \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitDegrowthCapacityDelta}} """ - regions = geography.gather_group_regions(M, r) - techs = technology.gather_group_techs(M, t) + regions = geography.gather_group_regions(model, r) + techs = technology.gather_group_techs(model, t) - growth = M.LimitDegrowthNewCapacityDelta if degrowth else M.LimitGrowthNewCapacityDelta - RATE = 1 + value(growth[r, t, op][0]) - SEED = value(growth[r, t, op][1]) - NewCapRTV = M.V_NewCapacity + growth = model.LimitDegrowthNewCapacityDelta if degrowth else model.LimitGrowthNewCapacityDelta + rate = 1 + value(growth[r, t, op][0]) + seed = value(growth[r, t, op][1]) + new_cap_rtv = model.V_NewCapacity # relevant r, t, v indices - cap_rtv = {(_r, _t, _v) for _r, _t, _v in NewCapRTV.keys() if _t in techs and _r in regions} + cap_rtv = {(_r, _t, _v) for _r, _t, _v in new_cap_rtv.keys() if _t in techs and _r in regions} # periods the technology can be built in this region (sorted) periods = sorted({_v for _r, _t, _v in cap_rtv}) if len(periods) == 0: - if p == M.time_optimize.first(): + if p == model.time_optimize.first(): msg = ( 'Tried to set {}rowthNewCapacityDelta constraint {} but there are no periods where this ' 'technology can be built in this region. Constraint skipped.' @@ -1169,7 +1191,7 @@ def LimitGrowthNewCapacityDelta( # Only warn in p0 so we dont dump multiple warnings if p == periods[0]: - if SEED == 0: + if seed == 0: msg = ( 'No constant term (seed) provided for {}rowthNewCapacityDelta constraint {}. ' 'This is not recommended as deployment rates cannot inflect (change from ' @@ -1177,7 +1199,9 @@ def LimitGrowthNewCapacityDelta( ).format('Deg' if degrowth else 'G', (r, t)) logger.warning(msg) gaps = [ - _p for _p in M.time_optimize if _p not in periods and min(periods) < _p < max(periods) + _p + for _p in model.time_optimize + if _p not in periods and min(periods) < _p < max(periods) ] if gaps: msg = ( @@ -1188,46 +1212,46 @@ def LimitGrowthNewCapacityDelta( logger.warning(msg) # sum new capacity in this period - new_cap = sum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p) + new_cap = sum(new_cap_rtv[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p) - if p == M.time_optimize.first(): + if p == model.time_optimize.first(): # First planning period, pull last two existing vintages - p_prev = M.time_exist.last() + p_prev = model.time_exist.last() new_cap_prev = sum( - value(M.ExistingCapacity[_r, _t, _v]) - for _r, _t, _v in M.ExistingCapacity.sparse_iterkeys() + value(model.ExistingCapacity[_r, _t, _v]) + for _r, _t, _v in model.ExistingCapacity.sparse_iterkeys() if _r in regions and _t in techs and _v == p_prev ) - p_prev2 = M.time_exist.prev(p_prev) + p_prev2 = model.time_exist.prev(p_prev) new_cap_prev2 = sum( - value(M.ExistingCapacity[_r, _t, _v]) - for _r, _t, _v in M.ExistingCapacity.sparse_iterkeys() + value(model.ExistingCapacity[_r, _t, _v]) + for _r, _t, _v in model.ExistingCapacity.sparse_iterkeys() if _r in regions and _t in techs and _v == p_prev2 ) else: # Not the first future period. Grab previous future period - p_prev = M.time_optimize.prev(p) - new_cap_prev = sum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p_prev) - if p == M.time_optimize.at(2): # apparently pyomo sets are indexed 1-based + p_prev = model.time_optimize.prev(p) + new_cap_prev = sum(new_cap_rtv[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p_prev) + if p == model.time_optimize.at(2): # apparently pyomo sets are indexed 1-based # Second future period, grab last existing vintage - p_prev2 = M.time_exist.last() + p_prev2 = model.time_exist.last() new_cap_prev2 = sum( - value(M.ExistingCapacity[_r, _t, _v]) - for _r, _t, _v in M.ExistingCapacity.sparse_iterkeys() + value(model.ExistingCapacity[_r, _t, _v]) + for _r, _t, _v in model.ExistingCapacity.sparse_iterkeys() if _r in regions and _t in techs and _v == p_prev2 ) else: # At least the third future period. Grab last two future vintages - p_prev2 = M.time_optimize.prev(p_prev) - new_cap_prev2 = sum(NewCapRTV[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p_prev2) + p_prev2 = model.time_optimize.prev(p_prev) + new_cap_prev2 = sum(new_cap_rtv[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p_prev2) nc_delta_prev = new_cap_prev - new_cap_prev2 nc_delta = new_cap - new_cap_prev if degrowth: - expr = operator_expression(nc_delta_prev, Operator(op), SEED + nc_delta * RATE) + expr = operator_expression(nc_delta_prev, Operator(op), seed + nc_delta * rate) else: - expr = operator_expression(nc_delta, Operator(op), SEED + nc_delta_prev * RATE) + expr = operator_expression(nc_delta, Operator(op), seed + nc_delta_prev * rate) # Check if any variables are actually included before returning if isinstance(expr, bool): @@ -1235,7 +1259,9 @@ def LimitGrowthNewCapacityDelta( return expr -def LimitActivity_Constraint(M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str) -> Any: +def limit_activity_constraint( + model: TemoaModel, r: Region, p: Period, t: Technology, op: str +) -> ExprLike: r""" Sets a limit on the activity from a specific technology. @@ -1261,31 +1287,31 @@ def LimitActivity_Constraint(M: 'TemoaModel', r: Region, p: Period, t: Technolog # r can be an individual region (r='US'), or a combination of regions separated by # a + (r='Mexico+US+Canada'), or 'global'. # if r == 'global', the constraint is system-wide - regions = geography.gather_group_regions(M, r) - techs = technology.gather_group_techs(M, t) + regions = geography.gather_group_regions(model, r) + techs = technology.gather_group_techs(model, t) activity = quicksum( - M.V_FlowOut[_r, p, s, d, S_i, _t, S_v, S_o] + model.V_FlowOut[_r, p, s, d, S_i, _t, S_v, S_o] for _t in techs - if _t not in M.tech_annual + if _t not in model.tech_annual for _r in regions - for S_v in M.processVintages.get((_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.TimeSeason[p] - for d in M.time_of_day + for S_v in model.processVintages.get((_r, p, _t), []) + for S_i in model.processInputs[_r, p, _t, S_v] + for S_o in model.processOutputsByInput[_r, p, _t, S_v, S_i] + for s in model.TimeSeason[p] + for d in model.time_of_day ) activity += quicksum( - M.V_FlowOutAnnual[_r, p, S_i, _t, S_v, S_o] + model.V_FlowOutAnnual[_r, p, S_i, _t, S_v, S_o] for _t in techs - if _t in M.tech_annual + if _t in model.tech_annual for _r in regions - for S_v in M.processVintages.get((_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_v in model.processVintages.get((_r, p, _t), []) + for S_i in model.processInputs[_r, p, _t, S_v] + for S_o in model.processOutputsByInput[_r, p, _t, S_v, S_i] ) - act_lim = value(M.LimitActivity[r, p, t, op]) + act_lim = value(model.LimitActivity[r, p, t, op]) expr = operator_expression(activity, Operator(op), act_lim) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated @@ -1293,9 +1319,9 @@ def LimitActivity_Constraint(M: 'TemoaModel', r: Region, p: Period, t: Technolog return expr -def LimitNewCapacity_Constraint( - M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str -) -> Any: +def limit_new_capacity_constraint( + model: TemoaModel, r: Region, p: Period, t: Technology, op: str +) -> ExprLike: r""" The LimitNewCapacity constraint sets a limit on the newly installed capacity of a given technology or group in a given year. Note that the indices for these constraints are region, @@ -1308,15 +1334,17 @@ def LimitNewCapacity_Constraint( \text{where }v=p """ - regions = geography.gather_group_regions(M, r) - techs = technology.gather_group_techs(M, t) - cap_lim = value(M.LimitNewCapacity[r, p, t, op]) - new_cap = quicksum(M.V_NewCapacity[_r, _t, p] for _t in techs for _r in regions) + regions = geography.gather_group_regions(model, r) + techs = technology.gather_group_techs(model, t) + cap_lim = value(model.LimitNewCapacity[r, p, t, op]) + new_cap = quicksum(model.V_NewCapacity[_r, _t, p] for _t in techs for _r in regions) expr = operator_expression(new_cap, Operator(op), cap_lim) return expr -def LimitCapacity_Constraint(M: 'TemoaModel', r: Region, p: Period, t: Technology, op: str) -> Any: +def limit_capacity_constraint( + model: TemoaModel, r: Region, p: Period, t: Technology, op: str +) -> ExprLike: r""" The LimitCapacity constraint sets a limit on the available capacity of a @@ -1329,11 +1357,11 @@ def LimitCapacity_Constraint(M: 'TemoaModel', r: Region, p: Period, t: Technolog \textbf{CAPAVL}_{r, p, t} \le LC_{r, p, t} \forall \{r, p, t\} \in \Theta_{\text{LimitCapacity}}""" - regions = geography.gather_group_regions(M, r) - techs = technology.gather_group_techs(M, t) - cap_lim = value(M.LimitCapacity[r, p, t, op]) + regions = geography.gather_group_regions(model, r) + techs = technology.gather_group_techs(model, t) + cap_lim = value(model.LimitCapacity[r, p, t, op]) capacity = quicksum( - M.V_CapacityAvailableByPeriodAndTech[_r, p, _t] for _t in techs for _r in regions + model.V_CapacityAvailableByPeriodAndTech[_r, p, _t] for _t in techs for _r in regions ) expr = operator_expression(capacity, Operator(op), cap_lim) return expr @@ -1344,7 +1372,7 @@ def LimitCapacity_Constraint(M: 'TemoaModel', r: Region, p: Period, t: Technolog # ============================================================================ -def create_limit_vintage_sets(M: 'TemoaModel') -> None: +def create_limit_vintage_sets(model: TemoaModel) -> None: """ Populates vintage-specific dictionaries for input/output split limit constraints. @@ -1360,18 +1388,18 @@ def create_limit_vintage_sets(M: 'TemoaModel') -> None: """ logger.debug('Creating vintage sets for split limits.') # Assuming M.processVintages is already populated - for r, p, t in M.processVintages: - for v in M.processVintages[r, p, t]: - for i in M.processInputs.get((r, p, t, v), []): - for op in M.operator: - if (r, p, i, t, op) in M.LimitTechInputSplit: - M.inputSplitVintages.setdefault((r, p, i, t, op), set()).add(v) - if (r, p, i, t, op) in M.LimitTechInputSplitAnnual: - M.inputSplitAnnualVintages.setdefault((r, p, i, t, op), set()).add(v) - - for o in M.processOutputs.get((r, p, t, v), []): - for op in M.operator: - if (r, p, t, o, op) in M.LimitTechOutputSplit: - M.outputSplitVintages.setdefault((r, p, t, o, op), set()).add(v) - if (r, p, t, o, op) in M.LimitTechOutputSplitAnnual: - M.outputSplitAnnualVintages.setdefault((r, p, t, o, op), set()).add(v) + for r, p, t in model.processVintages: + for v in model.processVintages[r, p, t]: + for i in model.processInputs.get((r, p, t, v), []): + for op in model.operator: + if (r, p, i, t, op) in model.LimitTechInputSplit: + model.inputSplitVintages.setdefault((r, p, i, t, op), set()).add(v) + if (r, p, i, t, op) in model.LimitTechInputSplitAnnual: + model.inputSplitAnnualVintages.setdefault((r, p, i, t, op), set()).add(v) + + for o in model.processOutputs.get((r, p, t, v), []): + for op in model.operator: + if (r, p, t, o, op) in model.LimitTechOutputSplit: + model.outputSplitVintages.setdefault((r, p, t, o, op), set()).add(v) + if (r, p, t, o, op) in model.LimitTechOutputSplitAnnual: + model.outputSplitAnnualVintages.setdefault((r, p, t, o, op), set()).add(v) diff --git a/temoa/components/operations.py b/temoa/components/operations.py index c76804da8..9184082ab 100644 --- a/temoa/components/operations.py +++ b/temoa/components/operations.py @@ -10,6 +10,8 @@ adjacent time slices. """ +from __future__ import annotations + from logging import getLogger from typing import TYPE_CHECKING @@ -17,7 +19,6 @@ from temoa.types import ExprLike from temoa.types.core_types import Period, Region, Season, Technology, TimeOfDay, Vintage -from temoa.types.index_types import RegionPeriodSeasonTimeOfDayTechVintage if TYPE_CHECKING: from temoa.core.model import TemoaModel @@ -29,88 +30,88 @@ # ============================================================================ -def BaseloadDiurnalConstraintIndices( - M: 'TemoaModel', -) -> set[RegionPeriodSeasonTimeOfDayTechVintage]: +def baseload_diurnal_constraint_indices( + model: TemoaModel, +) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]]: indices = { (r, p, s, d, t, v) - for r, p, t in M.baseloadVintages - for v in M.baseloadVintages[r, p, t] - for s in M.TimeSeason[p] - for d in M.time_of_day + for r, p, t in model.baseloadVintages + for v in model.baseloadVintages[r, p, t] + for s in model.TimeSeason[p] + for d in model.time_of_day } return indices -def RampUpDayConstraintIndices( - M: 'TemoaModel', -) -> set[RegionPeriodSeasonTimeOfDayTechVintage]: +def ramp_up_day_constraint_indices( + model: TemoaModel, +) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]]: indices = { (r, p, s, d, t, v) - for r, p, t in M.rampUpVintages - for v in M.rampUpVintages[r, p, t] - for s in M.TimeSeason[p] - for d in M.time_of_day + for r, p, t in model.rampUpVintages + for v in model.rampUpVintages[r, p, t] + for s in model.TimeSeason[p] + for d in model.time_of_day } return indices -def RampDownDayConstraintIndices( - M: 'TemoaModel', -) -> set[RegionPeriodSeasonTimeOfDayTechVintage]: +def ramp_down_day_constraint_indices( + model: TemoaModel, +) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]]: indices = { (r, p, s, d, t, v) - for r, p, t in M.rampDownVintages - for v in M.rampDownVintages[r, p, t] - for s in M.TimeSeason[p] - for d in M.time_of_day + for r, p, t in model.rampDownVintages + for v in model.rampDownVintages[r, p, t] + for s in model.TimeSeason[p] + for d in model.time_of_day } return indices -def RampUpSeasonConstraintIndices( - M: 'TemoaModel', +def ramp_up_season_constraint_indices( + model: TemoaModel, ) -> set[tuple[Region, Period, Season, Season, Technology, Vintage]]: - if M.TimeSequencing.first() == 'consecutive_days': + if model.TimeSequencing.first() == 'consecutive_days': return set() # s, s_next indexing ensures we dont build redundant constraints indices = { (r, p, s, s_next, t, v) - for r, p, t in M.rampUpVintages - for v in M.rampUpVintages[r, p, t] - for _p, s_seq, s in M.ordered_season_sequential + for r, p, t in model.rampUpVintages + for v in model.rampUpVintages[r, p, t] + for _p, s_seq, s in model.ordered_season_sequential if _p == p - for s_seq_next in (M.time_next_sequential[p, s_seq],) # next sequential season + for s_seq_next in (model.time_next_sequential[p, s_seq],) # next sequential season for s_next in ( - M.sequential_to_season[p, s_seq_next], + model.sequential_to_season[p, s_seq_next], ) # next sequential season's matching season - if s_next != M.time_next[p, s, M.time_of_day.last()][0] + if s_next != model.time_next[p, s, model.time_of_day.last()][0] } return indices -def RampDownSeasonConstraintIndices( - M: 'TemoaModel', +def ramp_down_season_constraint_indices( + model: TemoaModel, ) -> set[tuple[Region, Period, Season, Season, Technology, Vintage]]: - if M.TimeSequencing.first() == 'consecutive_days': + if model.TimeSequencing.first() == 'consecutive_days': return set() # s, s_next indexing ensures we dont build redundant constraints indices = { (r, p, s, s_next, t, v) - for r, p, t in M.rampDownVintages - for v in M.rampDownVintages[r, p, t] - for _p, s_seq, s in M.ordered_season_sequential - for s_seq_next in (M.time_next_sequential[p, s_seq],) # next sequential season + for r, p, t in model.rampDownVintages + for v in model.rampDownVintages[r, p, t] + for _p, s_seq, s in model.ordered_season_sequential + for s_seq_next in (model.time_next_sequential[p, s_seq],) # next sequential season for s_next in ( - M.sequential_to_season[p, s_seq_next], + model.sequential_to_season[p, s_seq_next], ) # next sequential season's matching season - if s_next != M.time_next[p, s, M.time_of_day.last()][0] + if s_next != model.time_next[p, s, model.time_of_day.last()][0] } return indices @@ -121,8 +122,8 @@ def RampDownSeasonConstraintIndices( # ============================================================================ -def BaseloadDiurnal_Constraint( - M: 'TemoaModel', +def baseload_diurnal_constraint( + model: TemoaModel, r: Region, p: Period, s: Season, @@ -157,7 +158,7 @@ def BaseloadDiurnal_Constraint( # Question: How to set the different times of day equal to each other? # Step 1: Acquire a "canonical" representation of the times of day - l_times = sorted(M.time_of_day) # i.e. a sorted Python list. + l_times = sorted(model.time_of_day) # i.e. a sorted Python list. # This is the commonality between invocations of this method. index = l_times.index(d) @@ -182,18 +183,20 @@ def BaseloadDiurnal_Constraint( # computationally, however, multiplication is cheaper than division, so: # (ActA * SegB) == (ActB * SegA) activity_sd = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) activity_sd_0 = sum( - M.V_FlowOut[r, p, s, d_0, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + model.V_FlowOut[r, p, s, d_0, S_i, t, v, S_o] + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) - expr = activity_sd * value(M.SegFrac[p, s, d_0]) == activity_sd_0 * value(M.SegFrac[p, s, d]) + expr = activity_sd * value(model.SegFrac[p, s, d_0]) == activity_sd_0 * value( + model.SegFrac[p, s, d] + ) return expr @@ -203,7 +206,7 @@ def BaseloadDiurnal_Constraint( # ============================================================================ -def create_operational_vintage_sets(M: 'TemoaModel') -> None: +def create_operational_vintage_sets(model: TemoaModel) -> None: """ Populates vintage-based dictionaries for technologies with special operational characteristics like curtailment, baseload, storage, ramping, and reserves. @@ -217,30 +220,30 @@ def create_operational_vintage_sets(M: 'TemoaModel') -> None: """ logger.debug('Creating vintage sets for operational constraints.') - for r, p, t in M.processVintages: - for v in M.processVintages[r, p, t]: + for r, p, t in model.processVintages: + for v in model.processVintages[r, p, t]: key_rpt = (r, p, t) key_rp = (r, p) - if t in M.tech_curtailment: - M.curtailmentVintages.setdefault(key_rpt, set()).add(v) - if t in M.tech_baseload: - M.baseloadVintages.setdefault(key_rpt, set()).add(v) - if t in M.tech_storage: - M.storageVintages.setdefault(key_rpt, set()).add(v) - if t in M.tech_upramping: - M.rampUpVintages.setdefault(key_rpt, set()).add(v) - if t in M.tech_downramping: - M.rampDownVintages.setdefault(key_rpt, set()).add(v) - if t in M.tech_reserve: - M.processReservePeriods.setdefault(key_rp, set()).add((t, v)) + if t in model.tech_curtailment: + model.curtailmentVintages.setdefault(key_rpt, set()).add(v) + if t in model.tech_baseload: + model.baseloadVintages.setdefault(key_rpt, set()).add(v) + if t in model.tech_storage: + model.storageVintages.setdefault(key_rpt, set()).add(v) + if t in model.tech_upramping: + model.rampUpVintages.setdefault(key_rpt, set()).add(v) + if t in model.tech_downramping: + model.rampDownVintages.setdefault(key_rpt, set()).add(v) + if t in model.tech_reserve: + model.processReservePeriods.setdefault(key_rp, set()).add((t, v)) # A dictionary of whether a storage tech is seasonal, just to speed things up - for t in M.tech_storage: - M.isSeasonalStorage[t] = t in M.tech_seasonal_storage + for t in model.tech_storage: + model.isSeasonalStorage[t] = t in model.tech_seasonal_storage -def RampUpDay_Constraint( - M: 'TemoaModel', +def ramp_up_day_constraint( + model: TemoaModel, r: Region, p: Period, s: Season, @@ -299,25 +302,25 @@ def RampUpDay_Constraint( - :math:`CAP \cdot C2A` gives the maximum hourly change in activity """ - s_next, d_next = M.time_next[p, s, d] + s_next, d_next = model.time_next[p, s, d] # How many hours does this time slice represent - hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 + hours_adjust = value(model.SegFrac[p, s, d]) * value(model.DaysPerPeriod) * 24 hourly_activity_sd = ( sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) / hours_adjust ) hourly_activity_sd_next = ( sum( - M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + model.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) / hours_adjust ) @@ -327,11 +330,11 @@ def RampUpDay_Constraint( 24 / 2 * ( - value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) - + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + value(model.SegFrac[p, s, d]) / value(model.SegFracPerSeason[p, s]) + + value(model.SegFrac[p, s_next, d_next]) / value(model.SegFracPerSeason[p, s_next]) ) ) - ramp_fraction = hours_elapsed * value(M.RampUpHourly[r, t]) + ramp_fraction = hours_elapsed * value(model.RampUpHourly[r, t]) if ramp_fraction >= 1: msg = ( @@ -342,14 +345,16 @@ def RampUpDay_Constraint( return Constraint.Skip activity_increase = hourly_activity_sd_next - hourly_activity_sd # opposite sign from rampdown - rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) + rampable_activity = ( + ramp_fraction * model.V_Capacity[r, p, t, v] * value(model.CapacityToActivity[r, t]) + ) expr = activity_increase <= rampable_activity return expr -def RampDownDay_Constraint( - M: 'TemoaModel', +def ramp_down_day_constraint( + model: TemoaModel, r: Region, p: Period, s: Season, @@ -382,25 +387,25 @@ def RampDownDay_Constraint( \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampDownDay}} """ - s_next, d_next = M.time_next[p, s, d] + s_next, d_next = model.time_next[p, s, d] # How many hours does this time slice represent - hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 + hours_adjust = value(model.SegFrac[p, s, d]) * value(model.DaysPerPeriod) * 24 hourly_activity_sd = ( sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) / hours_adjust ) hourly_activity_sd_next = ( sum( - M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + model.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) / hours_adjust ) @@ -410,11 +415,11 @@ def RampDownDay_Constraint( 24 / 2 * ( - value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) - + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + value(model.SegFrac[p, s, d]) / value(model.SegFracPerSeason[p, s]) + + value(model.SegFrac[p, s_next, d_next]) / value(model.SegFracPerSeason[p, s_next]) ) ) - ramp_fraction = hours_elapsed * value(M.RampDownHourly[r, t]) + ramp_fraction = hours_elapsed * value(model.RampDownHourly[r, t]) if ramp_fraction >= 1: msg = ( @@ -425,14 +430,16 @@ def RampDownDay_Constraint( return Constraint.Skip activity_decrease = hourly_activity_sd - hourly_activity_sd_next # opposite sign from rampup - rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) + rampable_activity = ( + ramp_fraction * model.V_Capacity[r, p, t, v] * value(model.CapacityToActivity[r, t]) + ) expr = activity_decrease <= rampable_activity return expr -def RampUpSeason_Constraint( - M: 'TemoaModel', +def ramp_up_season_constraint( + model: TemoaModel, r: Region, p: Period, s: Season, @@ -448,26 +455,26 @@ def RampUpSeason_Constraint( TimeSeason table. """ - d = M.time_of_day.last() - d_next = M.time_of_day.first() + d = model.time_of_day.last() + d_next = model.time_of_day.first() # How many hours does this time slice represent - hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 + hours_adjust = value(model.SegFrac[p, s, d]) * value(model.DaysPerPeriod) * 24 hourly_activity_sd = ( sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) / hours_adjust ) hourly_activity_sd_next = ( sum( - M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + model.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) / hours_adjust ) @@ -477,11 +484,11 @@ def RampUpSeason_Constraint( 24 / 2 * ( - value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) - + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + value(model.SegFrac[p, s, d]) / value(model.SegFracPerSeason[p, s]) + + value(model.SegFrac[p, s_next, d_next]) / value(model.SegFracPerSeason[p, s_next]) ) ) - ramp_fraction = hours_elapsed * value(M.RampUpHourly[r, t]) + ramp_fraction = hours_elapsed * value(model.RampUpHourly[r, t]) if ramp_fraction >= 1: msg = ( @@ -492,14 +499,16 @@ def RampUpSeason_Constraint( return Constraint.Skip activity_increase = hourly_activity_sd_next - hourly_activity_sd # opposite sign from rampdown - rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) + rampable_activity = ( + ramp_fraction * model.V_Capacity[r, p, t, v] * value(model.CapacityToActivity[r, t]) + ) expr = activity_increase <= rampable_activity return expr -def RampDownSeason_Constraint( - M: 'TemoaModel', +def ramp_down_season_constraint( + model: TemoaModel, r: Region, p: Period, s: Season, @@ -515,26 +524,26 @@ def RampDownSeason_Constraint( TimeSeason table. """ - d = M.time_of_day.last() - d_next = M.time_of_day.first() + d = model.time_of_day.last() + d_next = model.time_of_day.first() # How many hours does this time slice represent - hours_adjust = value(M.SegFrac[p, s, d]) * value(M.DaysPerPeriod) * 24 + hours_adjust = value(model.SegFrac[p, s, d]) * value(model.DaysPerPeriod) * 24 hourly_activity_sd = ( sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) / hours_adjust ) hourly_activity_sd_next = ( sum( - M.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + model.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) / hours_adjust ) @@ -544,11 +553,11 @@ def RampDownSeason_Constraint( 24 / 2 * ( - value(M.SegFrac[p, s, d]) / value(M.SegFracPerSeason[p, s]) - + value(M.SegFrac[p, s_next, d_next]) / value(M.SegFracPerSeason[p, s_next]) + value(model.SegFrac[p, s, d]) / value(model.SegFracPerSeason[p, s]) + + value(model.SegFrac[p, s_next, d_next]) / value(model.SegFracPerSeason[p, s_next]) ) ) - ramp_fraction = hours_elapsed * value(M.RampDownHourly[r, t]) + ramp_fraction = hours_elapsed * value(model.RampDownHourly[r, t]) if ramp_fraction >= 1: msg = ( @@ -559,7 +568,9 @@ def RampDownSeason_Constraint( return Constraint.Skip activity_decrease = hourly_activity_sd - hourly_activity_sd_next # opposite sign from rampup - rampable_activity = ramp_fraction * M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) + rampable_activity = ( + ramp_fraction * model.V_Capacity[r, p, t, v] * value(model.CapacityToActivity[r, t]) + ) expr = activity_decrease <= rampable_activity return expr diff --git a/temoa/components/reserves.py b/temoa/components/reserves.py index db5c01a36..ab271dad6 100644 --- a/temoa/components/reserves.py +++ b/temoa/components/reserves.py @@ -8,11 +8,15 @@ in a time slice) formulation for calculating available reserves. """ +from __future__ import annotations + from logging import getLogger from typing import TYPE_CHECKING from pyomo.environ import Constraint, value +from temoa.types.core_types import Period, Region, Season, TimeOfDay + from .utils import get_variable_efficiency if TYPE_CHECKING: @@ -26,14 +30,14 @@ # ============================================================================ -def ReserveMarginIndices(M: 'TemoaModel') -> set[tuple[str, int, str, str]]: +def reserve_margin_indices(model: TemoaModel) -> set[tuple[Region, Period, Season, TimeOfDay]]: indices = { (r, p, s, d) - for r in M.PlanningReserveMargin.sparse_iterkeys() - for p in M.time_optimize - if (r, p) in M.processReservePeriods - for s in M.TimeSeason[p] - for d in M.time_of_day + for r in model.PlanningReserveMargin.sparse_iterkeys() + for p in model.time_optimize + if (r, p) in model.processReservePeriods + for s in model.TimeSeason[p] + for d in model.time_of_day } return indices @@ -44,7 +48,9 @@ def ReserveMarginIndices(M: 'TemoaModel') -> set[tuple[str, int, str, str]]: # ============================================================================ -def ReserveMarginDynamic(M: 'TemoaModel', r: str, p: int, s: str, d: str) -> 'ExprLike': +def reserve_margin_dynamic( + model: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay +) -> ExprLike: r""" A dynamic alternative to the traditional, static reserve margin constraint. Capacity values are calculated from availability of generation in each hour—like an operating reserve margin—\ @@ -85,38 +91,38 @@ def ReserveMarginDynamic(M: 'TemoaModel', r: str, p: int, s: str, d: str) -> 'Ex &\qquad \qquad \forall \{r, p, s, d\} \in \ \Theta_{\text{ReserveMargin}} \text{ and } \forall r_i \in R """ - if (not M.tech_reserve) or ( - (r, p) not in M.processReservePeriods + if (not model.tech_reserve) or ( + (r, p) not in model.processReservePeriods ): # If reserve set empty or if r,p not in M.processReservePeriod, skip the constraint return Constraint.Skip # Everything but storage and exchange techs # Derated available generation available = sum( - M.V_Capacity[r, p, t, v] - * value(M.ReserveCapacityDerate[r, p, s, t, v]) - * value(M.CapacityFactorProcess[r, p, s, d, t, v]) - * value(M.CapacityToActivity[r, t]) - * value(M.SegFrac[p, s, d]) - for (t, v) in M.processReservePeriods[r, p] - if t not in M.tech_uncap and t not in M.tech_storage + model.V_Capacity[r, p, t, v] + * value(model.ReserveCapacityDerate[r, p, s, t, v]) + * value(model.CapacityFactorProcess[r, p, s, d, t, v]) + * value(model.CapacityToActivity[r, t]) + * value(model.SegFrac[p, s, d]) + for (t, v) in model.processReservePeriods[r, p] + if t not in model.tech_uncap and t not in model.tech_storage ) # Storage # Derated net output flow available += sum( - M.V_FlowOut[r, p, s, d, i, t, v, o] * value(M.ReserveCapacityDerate[r, p, s, t, v]) - for (t, v) in M.processReservePeriods[r, p] - if t in M.tech_storage - for i in M.processInputs[r, p, t, v] - for o in M.processOutputsByInput[r, p, t, v, i] + model.V_FlowOut[r, p, s, d, i, t, v, o] * value(model.ReserveCapacityDerate[r, p, s, t, v]) + for (t, v) in model.processReservePeriods[r, p] + if t in model.tech_storage + for i in model.processInputs[r, p, t, v] + for o in model.processOutputsByInput[r, p, t, v, i] ) available -= sum( - M.V_FlowIn[r, p, s, d, i, t, v, o] * value(M.ReserveCapacityDerate[r, p, s, t, v]) - for (t, v) in M.processReservePeriods[r, p] - if t in M.tech_storage - for i in M.processInputs[r, p, t, v] - for o in M.processOutputsByInput[r, p, t, v, i] + model.V_FlowIn[r, p, s, d, i, t, v, o] * value(model.ReserveCapacityDerate[r, p, s, t, v]) + for (t, v) in model.processReservePeriods[r, p] + if t in model.tech_storage + for i in model.processInputs[r, p, t, v] + for o in model.processOutputsByInput[r, p, t, v, i] ) # The above code does not consider exchange techs, e.g. electricity @@ -127,10 +133,13 @@ def ReserveMarginDynamic(M: 'TemoaModel', r: str, p: int, s: str, d: str) -> 'Ex # First, determine the amount of firm capacity each exchange tech # contributes. - for r1r2 in M.regionalIndices: + for r1r2 in model.regionalIndices: if '-' not in r1r2: continue - if (r1r2, p) not in M.processReservePeriods: # ensure r1r2 is a valid reserve provider in p + if ( + r1r2, + p, + ) not in model.processReservePeriods: # ensure r1r2 is a valid reserve provider in p continue r1, r2 = r1r2.split('-') @@ -141,19 +150,21 @@ def ReserveMarginDynamic(M: 'TemoaModel', r: str, p: int, s: str, d: str) -> 'Ex # add the available output of the exchange tech. available += sum( - M.V_Capacity[r1r2, p, t, v] - * value(M.ReserveCapacityDerate[r, p, s, t, v]) - * value(M.CapacityFactorProcess[r, p, s, d, t, v]) - * value(M.CapacityToActivity[r1r2, t]) - * value(M.SegFrac[p, s, d]) - for (t, v) in M.processReservePeriods[r1r2, p] - for t in M.tech_reserve + model.V_Capacity[r1r2, p, t, v] + * value(model.ReserveCapacityDerate[r, p, s, t, v]) + * value(model.CapacityFactorProcess[r, p, s, d, t, v]) + * value(model.CapacityToActivity[r1r2, t]) + * value(model.SegFrac[p, s, d]) + for (t, v) in model.processReservePeriods[r1r2, p] + for t in model.tech_reserve ) return available -def ReserveMarginStatic(M: 'TemoaModel', r: str, p: int, s: str, d: str) -> 'ExprLike': +def reserve_margin_static( + model: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay +) -> ExprLike: r""" During each period :math:`p`, the sum of capacity values of all reserve @@ -180,18 +191,18 @@ def ReserveMarginStatic(M: 'TemoaModel', r: str, p: int, s: str, d: str) -> 'Exp \\ &\qquad\qquad\forall \{r, p, s, d\} \in \Theta_{\text{ReserveMargin}} \text{and} \forall r_i \in R """ - if (not M.tech_reserve) or ( - (r, p) not in M.processReservePeriods + if (not model.tech_reserve) or ( + (r, p) not in model.processReservePeriods ): # If reserve set empty or if r,p not in M.processReservePeriod, skip the constraint return Constraint.Skip available = sum( - value(M.CapacityCredit[r, p, t, v]) - * M.V_Capacity[r, p, t, v] - * value(M.CapacityToActivity[r, t]) - * value(M.SegFrac[p, s, d]) - for (t, v) in M.processReservePeriods[r, p] - if t not in M.tech_uncap + value(model.CapacityCredit[r, p, t, v]) + * model.V_Capacity[r, p, t, v] + * value(model.CapacityToActivity[r, t]) + * value(model.SegFrac[p, s, d]) + for (t, v) in model.processReservePeriods[r, p] + if t not in model.tech_uncap ) # The above code does not consider exchange techs, e.g. electricity @@ -202,10 +213,13 @@ def ReserveMarginStatic(M: 'TemoaModel', r: str, p: int, s: str, d: str) -> 'Exp # First, determine the amount of firm capacity each exchange tech # contributes. - for r1r2 in M.regionalIndices: + for r1r2 in model.regionalIndices: if '-' not in r1r2: continue - if (r1r2, p) not in M.processReservePeriods: # ensure r1r2 is a valid reserve provider in p + if ( + r1r2, + p, + ) not in model.processReservePeriods: # ensure r1r2 is a valid reserve provider in p continue r1, r2 = r1r2.split('-') @@ -216,12 +230,12 @@ def ReserveMarginStatic(M: 'TemoaModel', r: str, p: int, s: str, d: str) -> 'Exp # add the available capacity of the exchange tech. available += sum( - value(M.CapacityCredit[r1r2, p, t, v]) - * M.V_Capacity[r1r2, p, t, v] - * value(M.CapacityToActivity[r1r2, t]) - * value(M.SegFrac[p, s, d]) - for (t, v) in M.processReservePeriods[r1r2, p] - for t in M.tech_reserve + value(model.CapacityCredit[r1r2, p, t, v]) + * model.V_Capacity[r1r2, p, t, v] + * value(model.CapacityToActivity[r1r2, t]) + * value(model.SegFrac[p, s, d]) + for (t, v) in model.processReservePeriods[r1r2, p] + for t in model.tech_reserve ) return available @@ -232,15 +246,17 @@ def ReserveMarginStatic(M: 'TemoaModel', r: str, p: int, s: str, d: str) -> 'Exp # ============================================================================ -def ReserveMargin_Constraint(M: 'TemoaModel', r: str, p: int, s: str, d: str) -> 'ExprLike': +def reserve_margin_constraint( + model: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay +) -> ExprLike: # Get available generation in this time slice depending on method specified in config file - match M.ReserveMarginMethod.first(): + match model.ReserveMarginMethod.first(): case 'static': - available = ReserveMarginStatic(M, r, p, s, d) + available = reserve_margin_static(model, r, p, s, d) case 'dynamic': - available = ReserveMarginDynamic(M, r, p, s, d) + available = reserve_margin_dynamic(model, r, p, s, d) case _: - msg = f"Invalid reserve margin parameter '{M.ReserveMarginMethod.first()}'. Check the config file." + msg = f"Invalid reserve margin parameter '{model.ReserveMarginMethod.first()}'. Check the config file." logger.error(msg) raise ValueError(msg) @@ -248,66 +264,69 @@ def ReserveMargin_Constraint(M: 'TemoaModel', r: str, p: int, s: str, d: str) -> # generation instead as a proxy for electricity demand. # Non-annual generation total_generation = sum( - M.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] - for (t, S_v) in M.processReservePeriods[r, p] - if t not in M.tech_annual - for S_i in M.processInputs[r, p, t, S_v] - for S_o in M.processOutputsByInput[r, p, t, S_v, S_i] + model.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] + for (t, S_v) in model.processReservePeriods[r, p] + if t not in model.tech_annual + for S_i in model.processInputs[r, p, t, S_v] + for S_o in model.processOutputsByInput[r, p, t, S_v, S_i] ) # Generators might serve demands directly # Annual generation total_generation += sum( ( - value(M.DemandSpecificDistribution[r, p, s, d, S_o]) - if S_o in M.commodity_demand - else value(M.SegFrac[p, s, d]) + value(model.DemandSpecificDistribution[r, p, s, d, S_o]) + if S_o in model.commodity_demand + else value(model.SegFrac[p, s, d]) ) - * M.V_FlowOutAnnual[r, p, S_i, t, S_v, S_o] - for (t, S_v) in M.processReservePeriods[r, p] - if t in M.tech_annual - for S_i in M.processInputs[r, p, t, S_v] - for S_o in M.processOutputsByInput[r, p, t, S_v, S_i] + * model.V_FlowOutAnnual[r, p, S_i, t, S_v, S_o] + for (t, S_v) in model.processReservePeriods[r, p] + if t in model.tech_annual + for S_i in model.processInputs[r, p, t, S_v] + for S_o in model.processOutputsByInput[r, p, t, S_v, S_i] ) # We must take into account flows into storage technologies. # Flows into storage technologies need to be subtracted from the # load calculation. total_generation -= sum( - M.V_FlowIn[r, p, s, d, S_i, t, S_v, S_o] - for (t, S_v) in M.processReservePeriods[r, p] - if t in M.tech_storage - for S_i in M.processInputs[r, p, t, S_v] - for S_o in M.processOutputsByInput[r, p, t, S_v, S_i] + model.V_FlowIn[r, p, s, d, S_i, t, S_v, S_o] + for (t, S_v) in model.processReservePeriods[r, p] + if t in model.tech_storage + for S_i in model.processInputs[r, p, t, S_v] + for S_o in model.processOutputsByInput[r, p, t, S_v, S_i] ) # Electricity imports and exports via exchange techs are accounted # for below: - for r1r2 in M.regionalIndices: # ensure the region is of the form r1-r2 + for r1r2 in model.regionalIndices: # ensure the region is of the form r1-r2 if '-' not in r1r2: continue - if (r1r2, p) not in M.processReservePeriods: # ensure r1r2 is a valid reserve provider in p + if ( + r1r2, + p, + ) not in model.processReservePeriods: # ensure r1r2 is a valid reserve provider in p continue r1, r2 = r1r2.split('-') # First, determine the exports, and subtract this value from the # total generation. if r1 == r: total_generation -= sum( - M.V_FlowOut[r1r2, p, s, d, S_i, t, S_v, S_o] - / get_variable_efficiency(M, r1r2, p, s, d, S_i, t, S_v, S_o) - for (t, S_v) in M.processReservePeriods[r1r2, p] - for S_i in M.processInputs[r1r2, p, t, S_v] - for S_o in M.processOutputsByInput[r1r2, p, t, S_v, S_i] + model.V_FlowOut[r1r2, p, s, d, S_i, t, S_v, S_o] + / get_variable_efficiency(model, r1r2, p, s, d, S_i, t, S_v, S_o) + for (t, S_v) in model.processReservePeriods[r1r2, p] + for S_i in model.processInputs[r1r2, p, t, S_v] + for S_o in model.processOutputsByInput[r1r2, p, t, S_v, S_i] ) # Second, determine the imports, and add this value from the # total generation. elif r2 == r: total_generation += sum( - M.V_FlowOut[r1r2, p, s, d, S_i, t, S_v, S_o] - for (t, S_v) in M.processReservePeriods[r1r2, p] - for S_i in M.processInputs[r1r2, p, t, S_v] - for S_o in M.processOutputsByInput[r1r2, p, t, S_v, S_i] + model.V_FlowOut[r1r2, p, s, d, S_i, t, S_v, S_o] + for (t, S_v) in model.processReservePeriods[r1r2, p] + for S_i in model.processInputs[r1r2, p, t, S_v] + for S_o in model.processOutputsByInput[r1r2, p, t, S_v, S_i] ) - requirement = total_generation * (1 + value(M.PlanningReserveMargin[r])) + requirement = total_generation * (1 + value(model.PlanningReserveMargin[r])) return available >= requirement diff --git a/temoa/components/storage.py b/temoa/components/storage.py index f140298ee..88f9a3471 100644 --- a/temoa/components/storage.py +++ b/temoa/components/storage.py @@ -11,6 +11,8 @@ device's power capacity. """ +from __future__ import annotations + from typing import TYPE_CHECKING from pyomo.environ import Constraint, value @@ -27,35 +29,35 @@ # ============================================================================ -def StorageLevelVariableIndices( - M: 'TemoaModel', +def storage_level_variable_indices( + model: TemoaModel, ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]] | None: - return M.storageLevelIndices_rpsdtv + return model.storageLevelIndices_rpsdtv -def SeasonalStorageLevelVariableIndices( - M: 'TemoaModel', +def seasonal_storage_level_variable_indices( + model: TemoaModel, ) -> set[tuple[Region, Period, Season, Technology, Vintage]] | None: - return M.seasonalStorageLevelIndices_rpstv + return model.seasonalStorageLevelIndices_rpstv -def SeasonalStorageConstraintIndices( - M: 'TemoaModel', +def seasonal_storage_constraint_indices( + model: TemoaModel, ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]]: - if M.seasonalStorageLevelIndices_rpstv: + if model.seasonalStorageLevelIndices_rpstv: indices = { (r, p, s, d, t, v) - for r, p, s, t, v in M.seasonalStorageLevelIndices_rpstv - for d in M.time_of_day + for r, p, s, t, v in model.seasonalStorageLevelIndices_rpstv + for d in model.time_of_day } return indices return set() -def StorageConstraintIndices( - M: 'TemoaModel', +def storage_constraint_indices( + model: TemoaModel, ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]] | None: - return M.storageLevelIndices_rpsdtv + return model.storageLevelIndices_rpsdtv # ============================================================================ @@ -65,8 +67,8 @@ def StorageConstraintIndices( # --- Core Energy Balance Constraints --- -def StorageEnergy_Constraint( - M: 'TemoaModel', r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage +def storage_energy_constraint( + model: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage ) -> ExprLike: r""" This constraint enforces the continuity of storage level between time slices. @@ -87,42 +89,42 @@ def StorageEnergy_Constraint( """ # We allow a non-zero daily delta only in the case of seasonal storage - if M.isSeasonalStorage[t] and d == M.time_of_day.last(): + if model.isSeasonalStorage[t] and d == model.time_of_day.last(): return Constraint.Skip # handled by SeasonalStorageEnergy_Constraint # This is the sum of all input=i sent TO storage tech t of vintage v with # output=o in p,s,d charge = sum( - M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] - * get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + model.V_FlowIn[r, p, s, d, S_i, t, v, S_o] + * get_variable_efficiency(model, r, p, s, d, S_i, t, v, S_o) + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) # This is the sum of all output=o withdrawn FROM storage tech t of vintage v # with input=i in p,s,d discharge = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_o in M.processOutputs[r, p, t, v] - for S_i in M.processInputsByOutput[r, p, t, v, S_o] + model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_o in model.processOutputs[r, p, t, v] + for S_i in model.processInputsByOutput[r, p, t, v, S_o] ) stored_energy = charge - discharge s_next: Season d_next: TimeOfDay - s_next, d_next = M.time_next[p, s, d] + s_next, d_next = model.time_next[p, s, d] expr = ( - M.V_StorageLevel[r, p, s, d, t, v] + stored_energy - == M.V_StorageLevel[r, p, s_next, d_next, t, v] + model.V_StorageLevel[r, p, s, d, t, v] + stored_energy + == model.V_StorageLevel[r, p, s_next, d_next, t, v] ) return expr -def SeasonalStorageEnergy_Constraint( - M: 'TemoaModel', r: Region, p: Period, s_seq: str, t: Technology, v: Vintage +def seasonal_storage_energy_constraint( + model: TemoaModel, r: Region, p: Period, s_seq: str, t: Technology, v: Vintage ) -> ExprLike: r""" This constraint enforces the continuity of state of charge between seasons for seasonal @@ -163,46 +165,46 @@ def SeasonalStorageEnergy_Constraint( are each one day. """ - s: Season = M.sequential_to_season[p, s_seq] + s: Season = model.sequential_to_season[p, s_seq] # This is the sum of all input=i sent TO storage tech t of vintage v with # output=o in p,s charge = sum( - M.V_FlowIn[r, p, s, M.time_of_day.last(), S_i, t, v, S_o] - * get_variable_efficiency(M, r, p, s, M.time_of_day.last(), S_i, t, v, S_o) - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + model.V_FlowIn[r, p, s, model.time_of_day.last(), S_i, t, v, S_o] + * get_variable_efficiency(model, r, p, s, model.time_of_day.last(), S_i, t, v, S_o) + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) # This is the sum of all output=o withdrawn FROM storage tech t of vintage v # with input=i in p,s discharge = sum( - M.V_FlowOut[r, p, s, M.time_of_day.last(), S_i, t, v, S_o] - for S_o in M.processOutputs[r, p, t, v] - for S_i in M.processInputsByOutput[r, p, t, v, S_o] + model.V_FlowOut[r, p, s, model.time_of_day.last(), S_i, t, v, S_o] + for S_o in model.processOutputs[r, p, t, v] + for S_i in model.processInputsByOutput[r, p, t, v, S_o] ) - s_seq_next: str = M.time_next_sequential[p, s_seq] - s_next: Season = M.sequential_to_season[p, s_seq_next] + s_seq_next: str = model.time_next_sequential[p, s_seq] + s_next: Season = model.sequential_to_season[p, s_seq_next] # Flows and StorageLevel are normalised to the number of days in the non-sequential season, so must # be adjusted to the number of days in the sequential season - days_adjust = value(M.TimeSeasonSequential[p, s_seq, s]) / ( - value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod) + days_adjust = value(model.TimeSeasonSequential[p, s_seq, s]) / ( + value(model.SegFracPerSeason[p, s]) * value(model.DaysPerPeriod) ) - days_adjust_next = value(M.TimeSeasonSequential[p, s_seq_next, s_next]) / ( - value(M.SegFracPerSeason[p, s_next]) * value(M.DaysPerPeriod) + days_adjust_next = value(model.TimeSeasonSequential[p, s_seq_next, s_next]) / ( + value(model.SegFracPerSeason[p, s_next]) * value(model.DaysPerPeriod) ) stored_energy = (charge - discharge) * days_adjust start = ( - M.V_SeasonalStorageLevel[r, p, s_seq, t, v] - + M.V_StorageLevel[r, p, s, M.time_of_day.last(), t, v] * days_adjust + model.V_SeasonalStorageLevel[r, p, s_seq, t, v] + + model.V_StorageLevel[r, p, s, model.time_of_day.last(), t, v] * days_adjust ) end = ( - M.V_SeasonalStorageLevel[r, p, s_seq_next, t, v] - + M.V_StorageLevel[r, p, s_next, M.time_of_day.first(), t, v] * days_adjust_next + model.V_SeasonalStorageLevel[r, p, s_seq_next, t, v] + + model.V_StorageLevel[r, p, s_next, model.time_of_day.first(), t, v] * days_adjust_next ) expr = start + stored_energy == end @@ -212,8 +214,8 @@ def SeasonalStorageEnergy_Constraint( # --- Capacity and Rate Limit Constraints --- -def StorageEnergyUpperBound_Constraint( - M: 'TemoaModel', r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage +def storage_energy_upper_bound_constraint( + model: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage ) -> ExprLike: r""" This constraint ensures that the amount of energy stored does not exceed @@ -253,24 +255,24 @@ def StorageEnergyUpperBound_Constraint( Representation of a 3-day season for non-seasonal (daily) storage. """ - if M.isSeasonalStorage[t]: + if model.isSeasonalStorage[t]: return Constraint.Skip # redundant on SeasonalStorageEnergyUpperBound energy_capacity = ( - M.V_Capacity[r, p, t, v] - * value(M.CapacityToActivity[r, t]) - * (value(M.StorageDuration[r, t]) / (24 * value(M.DaysPerPeriod))) - * value(M.SegFracPerSeason[p, s]) - * M.DaysPerPeriod # adjust for days in season + model.V_Capacity[r, p, t, v] + * value(model.CapacityToActivity[r, t]) + * (value(model.StorageDuration[r, t]) / (24 * value(model.DaysPerPeriod))) + * value(model.SegFracPerSeason[p, s]) + * model.DaysPerPeriod # adjust for days in season ) - expr = M.V_StorageLevel[r, p, s, d, t, v] <= energy_capacity + expr = model.V_StorageLevel[r, p, s, d, t, v] <= energy_capacity return expr -def SeasonalStorageEnergyUpperBound_Constraint( - M: 'TemoaModel', r: Region, p: Period, s_seq: str, d: TimeOfDay, t: Technology, v: Vintage +def seasonal_storage_energy_upper_bound_constraint( + model: TemoaModel, r: Region, p: Period, s_seq: str, d: TimeOfDay, t: Technology, v: Vintage ) -> ExprLike: r""" Builds off of StorageEnergyUpperBound_Constraint. Enforces the max charge capacity @@ -324,31 +326,31 @@ def SeasonalStorageEnergyUpperBound_Constraint( Unadjusted energy upper bound constraint for seasonal storage. """ - s: Season = M.sequential_to_season[p, s_seq] + s: Season = model.sequential_to_season[p, s_seq] energy_capacity = ( - M.V_Capacity[r, p, t, v] - * value(M.CapacityToActivity[r, t]) - * (value(M.StorageDuration[r, t]) / (24 * value(M.DaysPerPeriod))) + model.V_Capacity[r, p, t, v] + * value(model.CapacityToActivity[r, t]) + * (value(model.StorageDuration[r, t]) / (24 * value(model.DaysPerPeriod))) ) # Flows and StorageLevel are normalised to the number of days in the non-sequential season, so must # be adjusted to the number of days in the sequential season - days_adjust = value(M.TimeSeasonSequential[p, s_seq, s]) / ( - value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod) + days_adjust = value(model.TimeSeasonSequential[p, s_seq, s]) / ( + value(model.SegFracPerSeason[p, s]) * value(model.DaysPerPeriod) ) # V_StorageLevel tracks the running cumulative delta in the non-sequential season, so must be adjusted # to the size of the sequential season - running_day_delta = M.V_StorageLevel[r, p, s, d, t, v] * days_adjust + running_day_delta = model.V_StorageLevel[r, p, s, d, t, v] * days_adjust - expr = M.V_SeasonalStorageLevel[r, p, s_seq, t, v] + running_day_delta <= energy_capacity + expr = model.V_SeasonalStorageLevel[r, p, s_seq, t, v] + running_day_delta <= energy_capacity return expr -def StorageChargeRate_Constraint( - M: 'TemoaModel', r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage +def storage_charge_rate_constraint( + model: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage ) -> ExprLike: r""" @@ -368,15 +370,17 @@ def StorageChargeRate_Constraint( """ # Calculate energy charge in each time slice slice_charge = sum( - M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] - * get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + model.V_FlowIn[r, p, s, d, S_i, t, v, S_o] + * get_variable_efficiency(model, r, p, s, d, S_i, t, v, S_o) + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) # Maximum energy charge in each time slice max_charge = ( - M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[p, s, d]) + model.V_Capacity[r, p, t, v] + * value(model.CapacityToActivity[r, t]) + * value(model.SegFrac[p, s, d]) ) # Energy charge cannot exceed the power capacity of the storage unit @@ -385,8 +389,8 @@ def StorageChargeRate_Constraint( return expr -def StorageDischargeRate_Constraint( - M: 'TemoaModel', r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage +def storage_discharge_rate_constraint( + model: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage ) -> ExprLike: r""" @@ -405,14 +409,16 @@ def StorageDischargeRate_Constraint( """ # Calculate energy discharge in each time slice slice_discharge = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_o in M.processOutputs[r, p, t, v] - for S_i in M.processInputsByOutput[r, p, t, v, S_o] + model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_o in model.processOutputs[r, p, t, v] + for S_i in model.processInputsByOutput[r, p, t, v, S_o] ) # Maximum energy discharge in each time slice max_discharge = ( - M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[p, s, d]) + model.V_Capacity[r, p, t, v] + * value(model.CapacityToActivity[r, t]) + * value(model.SegFrac[p, s, d]) ) # Energy discharge cannot exceed the capacity of the storage unit @@ -421,8 +427,8 @@ def StorageDischargeRate_Constraint( return expr -def StorageThroughput_Constraint( - M: 'TemoaModel', r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage +def storage_throughput_constraint( + model: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage ) -> ExprLike: r""" @@ -443,29 +449,31 @@ def StorageThroughput_Constraint( \forall \{r, p, s, d, t, v\} \in \Theta_{\text{StorageThroughput}} """ discharge = sum( - M.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_o in M.processOutputs[r, p, t, v] - for S_i in M.processInputsByOutput[r, p, t, v, S_o] + model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + for S_o in model.processOutputs[r, p, t, v] + for S_i in model.processInputsByOutput[r, p, t, v, S_o] ) charge = sum( - M.V_FlowIn[r, p, s, d, S_i, t, v, S_o] - * get_variable_efficiency(M, r, p, s, d, S_i, t, v, S_o) - for S_i in M.processInputs[r, p, t, v] - for S_o in M.processOutputsByInput[r, p, t, v, S_i] + model.V_FlowIn[r, p, s, d, S_i, t, v, S_o] + * get_variable_efficiency(model, r, p, s, d, S_i, t, v, S_o) + for S_i in model.processInputs[r, p, t, v] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) throughput = charge + discharge max_throughput = ( - M.V_Capacity[r, p, t, v] * value(M.CapacityToActivity[r, t]) * value(M.SegFrac[p, s, d]) + model.V_Capacity[r, p, t, v] + * value(model.CapacityToActivity[r, t]) + * value(model.SegFrac[p, s, d]) ) expr = throughput <= max_throughput return expr # A limit but more cohesive here than in limits.py -def LimitStorageFraction_Constraint( - M: 'TemoaModel', +def limit_storage_fraction_constraint( + model: TemoaModel, r: Region, p: Period, s: Season, @@ -501,25 +509,25 @@ def LimitStorageFraction_Constraint( """ energy_limit = ( - M.V_Capacity[r, p, t, v] - * value(M.CapacityToActivity[r, t]) - * (value(M.StorageDuration[r, t]) / (24 * value(M.DaysPerPeriod))) - * value(M.LimitStorageFraction[r, p, s, d, t, v, op]) + model.V_Capacity[r, p, t, v] + * value(model.CapacityToActivity[r, t]) + * (value(model.StorageDuration[r, t]) / (24 * value(model.DaysPerPeriod))) + * value(model.LimitStorageFraction[r, p, s, d, t, v, op]) ) - if M.isSeasonalStorage[t]: + if model.isSeasonalStorage[t]: s_seq: str = s # sequential season - s = M.sequential_to_season[p, s_seq] # non-sequential season + s = model.sequential_to_season[p, s_seq] # non-sequential season # adjust the storage level to the individual-day level - energy_level = M.V_StorageLevel[r, p, s, d, t, v] / ( - value(M.SegFracPerSeason[p, s]) * value(M.DaysPerPeriod) + energy_level = model.V_StorageLevel[r, p, s, d, t, v] / ( + value(model.SegFracPerSeason[p, s]) * value(model.DaysPerPeriod) ) - if M.isSeasonalStorage[t]: + if model.isSeasonalStorage[t]: # seasonal storage upper energy limit is absolute - energy_level = M.V_SeasonalStorageLevel[r, p, s_seq, t, v] + energy_level * value( - M.TimeSeasonSequential[p, s_seq, s] + energy_level = model.V_SeasonalStorageLevel[r, p, s_seq, t, v] + energy_level * value( + model.TimeSeasonSequential[p, s_seq, s] ) expr = operator_expression(energy_level, Operator(op), energy_limit) diff --git a/temoa/components/technology.py b/temoa/components/technology.py index 9cf608eea..26a1778f9 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -10,6 +10,8 @@ - Validating model inputs related to technologies, efficiencies, and commodities. """ +from __future__ import annotations + from collections.abc import Iterable from logging import getLogger from typing import TYPE_CHECKING @@ -27,9 +29,9 @@ # ============================================================================ -def gather_group_techs(M: 'TemoaModel', t_or_g: str) -> Iterable[str]: - if t_or_g in M.tech_group_names: - return M.tech_group_members[t_or_g] +def gather_group_techs(model: TemoaModel, t_or_g: str) -> Iterable[str]: + if t_or_g in model.tech_group_names: + return model.tech_group_members[t_or_g] elif '+' in t_or_g: return t_or_g.split('+') else: @@ -41,41 +43,39 @@ def gather_group_techs(M: 'TemoaModel', t_or_g: str) -> Iterable[str]: # ============================================================================ -def ModelProcessLifeIndices( - M: 'TemoaModel', -) -> set[tuple['Region', 'Period', 'Technology', 'Vintage']] | None: +def model_process_life_indices( + model: TemoaModel, +) -> set[tuple[Region, Period, Technology, Vintage]] | None: """ Returns the set of sensical (region, period, tech, vintage) tuples. The tuple indicates the periods in which a process is active, distinct from TechLifeFracIndices that returns indices only for processes that EOL mid-period. """ - return M.activeActivity_rptv + return model.activeActivity_rptv -def LifetimeProcessIndices(M: 'TemoaModel') -> set[tuple['Region', 'Technology', 'Vintage']]: +def lifetime_process_indices(model: TemoaModel) -> set[tuple[Region, Technology, Vintage]]: """ Based on the Efficiency parameter's indices, this function returns the set of process indices that may be specified in the LifetimeProcess parameter. """ - indices = {(r, t, v) for r, i, t, v, o in M.Efficiency.sparse_iterkeys()} + indices = {(r, t, v) for r, i, t, v, o in model.Efficiency.sparse_iterkeys()} return indices def get_default_survival( - M: 'TemoaModel', r: 'Region', p: 'Period', t: 'Technology', v: 'Vintage' + model: TemoaModel, r: Region, p: Period, t: Technology, v: Vintage ) -> float: """ Getting LifetimeSurvivalCurve where it is not defined If this is a survival curve process, return 0 (likely beyond EOL) Otherwise return 1 (no survival curve based EOL) """ - return 0.0 if M.isSurvivalCurveProcess[r, t, v] else 1.0 + return 0.0 if model.isSurvivalCurveProcess[r, t, v] else 1.0 -def get_default_process_lifetime( - M: 'TemoaModel', r: 'Region', t: 'Technology', v: 'Vintage' -) -> int: +def get_default_process_lifetime(model: TemoaModel, r: Region, t: Technology, v: Vintage) -> int: """ This initializer used to initialize the LifetimeProcess parameter from LifetimeTech where needed @@ -89,11 +89,11 @@ def get_default_process_lifetime( :param v: vintage :return: the final lifetime value """ - return value(M.LifetimeTech[r, t]) + return value(model.LifetimeTech[r, t]) -def ParamProcessLifeFraction_rule( - M: 'TemoaModel', r: 'Region', p: 'Period', t: 'Technology', v: 'Vintage' +def param_process_life_fraction_rule( + model: TemoaModel, r: Region, p: Period, t: Technology, v: Vintage ) -> float: r""" Get the effective capacity of a process :math:`` in a period :math:`p`. @@ -102,16 +102,16 @@ def ParamProcessLifeFraction_rule( for processes using survival curves. """ - period_length = value(M.PeriodLength[p]) + period_length = value(model.PeriodLength[p]) - if M.isSurvivalCurveProcess[r, t, v]: + if model.isSurvivalCurveProcess[r, t, v]: # Sum survival fraction over the period years_remaining = sum( - value(M.LifetimeSurvivalCurve[r, _p, t, v]) for _p in range(p, p + period_length, 1) + value(model.LifetimeSurvivalCurve[r, _p, t, v]) for _p in range(p, p + period_length, 1) ) else: # Remaining life years within the EOL period - years_remaining = v + value(M.LifetimeProcess[r, t, v]) - p + years_remaining = v + value(model.LifetimeProcess[r, t, v]) - p if years_remaining >= period_length: # try to avoid floating point round-off errors for the common case. @@ -126,7 +126,7 @@ def ParamProcessLifeFraction_rule( # ============================================================================ -def populate_core_dictionaries(M: 'TemoaModel') -> None: +def populate_core_dictionaries(model: TemoaModel) -> None: """ Populates the core sparse dictionaries from the `Efficiency` parameter. @@ -141,21 +141,21 @@ def populate_core_dictionaries(M: 'TemoaModel') -> None: - M.used_techs """ logger.debug('Populating core sparse dictionaries from Efficiency parameter.') - first_period = min(M.time_future) - exist_indices = M.ExistingCapacity.sparse_keys() + first_period = min(model.time_future) + exist_indices = model.ExistingCapacity.sparse_keys() - for r, i, t, v, o in M.Efficiency.sparse_iterkeys(): + for r, i, t, v, o in model.Efficiency.sparse_iterkeys(): # A. Basic data validation and warnings process = (r, t, v) - lifetime = value(M.LifetimeProcess[process]) - if v in M.vintage_exist: - if process not in exist_indices and t not in M.tech_uncap: + lifetime = value(model.LifetimeProcess[process]) + if v in model.vintage_exist: + if process not in exist_indices and t not in model.tech_uncap: logger.warning( f'Warning: {process} has a specified Efficiency, but does not ' f'have any existing install base (ExistingCapacity).' ) continue - if t not in M.tech_uncap and M.ExistingCapacity[process] == 0: + if t not in model.tech_uncap and model.ExistingCapacity[process] == 0: logger.warning( f'Notice: Unnecessary specification of ExistingCapacity for {process}. ' f'Declaring a capacity of zero may be omitted.' @@ -168,17 +168,17 @@ def populate_core_dictionaries(M: 'TemoaModel') -> None: f'beginning of time_future ({first_period}).' ) - if M.Efficiency[r, i, t, v, o] == 0: + if model.Efficiency[r, i, t, v, o] == 0: logger.info( f'Notice: Unnecessary specification of Efficiency for {(r, i, t, v, o)}. ' f'Specifying an efficiency of zero may be omitted.' ) continue - M.used_techs.add(t) + model.used_techs.add(t) # B. Loop through time periods to build time-dependent relationships - for p in M.time_optimize: + for p in model.time_optimize: # Skip if tech is not invented or is already retired if p < v or v + lifetime <= p: continue @@ -186,49 +186,49 @@ def populate_core_dictionaries(M: 'TemoaModel') -> None: pindex = (r, p, t, v) # C. Initialize dictionary keys if not present - if pindex not in M.processInputs: - M.processInputs[pindex] = set() - M.processOutputs[pindex] = set() - if (r, p, i) not in M.commodityDStreamProcess: - M.commodityDStreamProcess[r, p, i] = set() - if (r, p, o) not in M.commodityUStreamProcess: - M.commodityUStreamProcess[r, p, o] = set() - if (r, p, t, v, i) not in M.processOutputsByInput: - M.processOutputsByInput[r, p, t, v, i] = set() - if (r, p, t, v, o) not in M.processInputsByOutput: - M.processInputsByOutput[r, p, t, v, o] = set() - if (r, p, t) not in M.processVintages: - M.processVintages[r, p, t] = set() - if (r, t, v) not in M.processPeriods: - M.processPeriods[r, t, v] = set() + if pindex not in model.processInputs: + model.processInputs[pindex] = set() + model.processOutputs[pindex] = set() + if (r, p, i) not in model.commodityDStreamProcess: + model.commodityDStreamProcess[r, p, i] = set() + if (r, p, o) not in model.commodityUStreamProcess: + model.commodityUStreamProcess[r, p, o] = set() + if (r, p, t, v, i) not in model.processOutputsByInput: + model.processOutputsByInput[r, p, t, v, i] = set() + if (r, p, t, v, o) not in model.processInputsByOutput: + model.processInputsByOutput[r, p, t, v, o] = set() + if (r, p, t) not in model.processVintages: + model.processVintages[r, p, t] = set() + if (r, t, v) not in model.processPeriods: + model.processPeriods[r, t, v] = set() # D. Populate the dictionaries - M.processInputs[pindex].add(i) - M.processOutputs[pindex].add(o) - M.commodityDStreamProcess[r, p, i].add((t, v)) - M.commodityUStreamProcess[r, p, o].add((t, v)) - M.processOutputsByInput[r, p, t, v, i].add(o) - M.processInputsByOutput[r, p, t, v, o].add(i) - M.processVintages[r, p, t].add(v) - M.processPeriods[r, t, v].add(p) + model.processInputs[pindex].add(i) + model.processOutputs[pindex].add(o) + model.commodityDStreamProcess[r, p, i].add((t, v)) + model.commodityUStreamProcess[r, p, o].add((t, v)) + model.processOutputsByInput[r, p, t, v, i].add(o) + model.processInputsByOutput[r, p, t, v, o].add(i) + model.processVintages[r, p, t].add(v) + model.processPeriods[r, t, v].add(p) -def CreateSurvivalCurve(M: 'TemoaModel') -> None: +def create_survival_curve(model: TemoaModel) -> None: rtv_interpolated = set() # so we only need one warning - for r, _, t, v, _ in M.Efficiency.sparse_iterkeys(): - M.isSurvivalCurveProcess[r, t, v] = False # by default + for r, _, t, v, _ in model.Efficiency.sparse_iterkeys(): + model.isSurvivalCurveProcess[r, t, v] = False # by default # Collect rptv indices into (r, t, v): p dictionary - for r, p, t, v in M.LifetimeSurvivalCurve.sparse_iterkeys(): - if (r, t, v) not in M.survivalCurvePeriods: - M.survivalCurvePeriods[r, t, v] = set() - M.survivalCurvePeriods[r, t, v].add(p) - M.isSurvivalCurveProcess[r, t, v] = True + for r, p, t, v in model.LifetimeSurvivalCurve.sparse_iterkeys(): + if (r, t, v) not in model.survivalCurvePeriods: + model.survivalCurvePeriods[r, t, v] = set() + model.survivalCurvePeriods[r, t, v].add(p) + model.isSurvivalCurveProcess[r, t, v] = True # Go through all the periods for each (r, t, v) in order - for r, t, v in M.survivalCurvePeriods: - periods_rtv: list[int] = sorted(M.survivalCurvePeriods[r, t, v]) + for r, t, v in model.survivalCurvePeriods: + periods_rtv: list[int] = sorted(model.survivalCurvePeriods[r, t, v]) p_first = periods_rtv[0] p_last = periods_rtv[-1] @@ -241,10 +241,10 @@ def CreateSurvivalCurve(M: 'TemoaModel') -> None: logger.error(msg) raise ValueError(msg) - if value(M.LifetimeSurvivalCurve[r, v, t, v]) != 1: + if value(model.LifetimeSurvivalCurve[r, v, t, v]) != 1: msg_str = ( 'LifetimeSurvivalCurve must begin at 1 for calculating annual retirements. ' - f'Got {value(M.LifetimeSurvivalCurve[r, v, t, v])} for ({r}, {v}, {t}, {v})' + f'Got {value(model.LifetimeSurvivalCurve[r, v, t, v])} for ({r}, {v}, {t}, {v})' ) logger.error(msg_str) raise ValueError(msg_str) @@ -260,8 +260,8 @@ def CreateSurvivalCurve(M: 'TemoaModel') -> None: # Check that the survival curve monotonically decreases p_prev = periods_rtv[i - 1] - lsc = value(M.LifetimeSurvivalCurve[r, p, t, v]) - lsc_prev = value(M.LifetimeSurvivalCurve[r, p_prev, t, v]) + lsc = value(model.LifetimeSurvivalCurve[r, p, t, v]) + lsc_prev = value(model.LifetimeSurvivalCurve[r, p_prev, t, v]) if lsc - lsc_prev > 0.0001: msg = ( 'LifetimeSurvivalCurve fraction increases going forward in time from {} to {}. ' @@ -275,7 +275,7 @@ def CreateSurvivalCurve(M: 'TemoaModel') -> None: for _p in _between_periods: x = (_p - p_prev) / (p - p_prev) lsc_x = lsc_prev + x * (lsc - lsc_prev) - M.LifetimeSurvivalCurve[r, _p, t, v] = lsc_x + model.LifetimeSurvivalCurve[r, _p, t, v] = lsc_x between_periods.extend(_between_periods) if lsc < 0.0001: @@ -287,7 +287,7 @@ def CreateSurvivalCurve(M: 'TemoaModel') -> None: logger.info(msg) # Make sure the lifetime for this process aligns with survival curve end - if value(M.LifetimeProcess[r, t, v]) < p - v: + if value(model.LifetimeProcess[r, t, v]) < p - v: msg = ( f'The LifetimeProcess parameter for process ({r, t, v}) with survival curve ' f'does not extend beyond the end of that survival curve in {p}. To agree with ' @@ -295,7 +295,7 @@ def CreateSurvivalCurve(M: 'TemoaModel') -> None: ) logger.error(msg) raise ValueError(msg) - elif value(M.LifetimeProcess[r, t, v]) != p - v: + elif value(model.LifetimeProcess[r, t, v]) != p - v: msg = ( f'The LifetimeProcess parameter for process ({r, t, v}) with survival curve ' f'does match the end of that survival curve in {p}. This will waste compute. ' @@ -316,7 +316,7 @@ def CreateSurvivalCurve(M: 'TemoaModel') -> None: logger.error(msg) raise ValueError(msg) - M.survivalCurvePeriods[r, t, v].update(between_periods) + model.survivalCurvePeriods[r, t, v].update(between_periods) if rtv_interpolated: msg = ( @@ -327,19 +327,19 @@ def CreateSurvivalCurve(M: 'TemoaModel') -> None: logger.info(msg) -def CheckEfficiencyIndices(M: 'TemoaModel') -> None: +def check_efficiency_indices(model: TemoaModel) -> None: """ Ensure that there are no unused items in any of the Efficiency index sets. """ # TODO: This could be upgraded to scan for finer resolution # by checking by REGION and PERIOD... Each region/period is unique. - c_physical = {i for r, i, t, v, o in M.Efficiency.sparse_iterkeys()} - c_physical = c_physical | {i for r, i, t, v in M.ConstructionInput.sparse_iterkeys()} - techs = {t for r, i, t, v, o in M.Efficiency.sparse_iterkeys()} - c_outputs = {o for r, i, t, v, o in M.Efficiency.sparse_iterkeys()} - c_outputs = c_outputs | {o for r, t, v, o in M.EndOfLifeOutput.sparse_iterkeys()} + c_physical = {i for r, i, t, v, o in model.Efficiency.sparse_iterkeys()} + c_physical = c_physical | {i for r, i, t, v in model.ConstructionInput.sparse_iterkeys()} + techs = {t for r, i, t, v, o in model.Efficiency.sparse_iterkeys()} + c_outputs = {o for r, i, t, v, o in model.Efficiency.sparse_iterkeys()} + c_outputs = c_outputs | {o for r, t, v, o in model.EndOfLifeOutput.sparse_iterkeys()} - symdiff = c_physical.symmetric_difference(M.commodity_physical) + symdiff = c_physical.symmetric_difference(model.commodity_physical) if symdiff: msg = ( 'Unused or unspecified physical carriers. Either add or remove ' @@ -351,7 +351,7 @@ def CheckEfficiencyIndices(M: 'TemoaModel') -> None: logger.error(f_msg) raise ValueError(f_msg) - symdiff = techs.symmetric_difference(M.tech_all) + symdiff = techs.symmetric_difference(model.tech_all) if symdiff: msg = ( 'Unused or unspecified technologies. Either add or remove ' @@ -363,7 +363,7 @@ def CheckEfficiencyIndices(M: 'TemoaModel') -> None: logger.error(f_msg) raise ValueError(f_msg) - diff = M.commodity_demand - c_outputs + diff = model.commodity_demand - c_outputs if diff: msg = ( 'Unused or unspecified outputs. Either add or remove the ' @@ -376,27 +376,27 @@ def CheckEfficiencyIndices(M: 'TemoaModel') -> None: raise ValueError(f_msg) -def CheckEfficiencyVariable(M: 'TemoaModel') -> None: +def check_efficiency_variable(model: TemoaModel) -> None: count_rpitvo = {} # Pull non-variable efficiency by default - for r, i, t, v, o in M.Efficiency.sparse_iterkeys(): - if (r, t, v) not in M.processPeriods: + for r, i, t, v, o in model.Efficiency.sparse_iterkeys(): + if (r, t, v) not in model.processPeriods: # Probably an existing vintage that retires in p0 # Still want it for end of life flows continue - for p in M.processPeriods[r, t, v]: - M.isEfficiencyVariable[r, p, i, t, v, o] = False + for p in model.processPeriods[r, t, v]: + model.isEfficiencyVariable[r, p, i, t, v, o] = False count_rpitvo[r, p, i, t, v, o] = 0 annual = set() # Check for bad values and count up the good ones - for r, p, _s, _d, i, t, v, o in M.EfficiencyVariable.sparse_iterkeys(): - if p not in M.processPeriods[r, t, v]: + for r, p, _s, _d, i, t, v, o in model.EfficiencyVariable.sparse_iterkeys(): + if p not in model.processPeriods[r, t, v]: msg = f'Invalid period {p} for process {r, t, v} in EfficiencyVariable table' logger.error(msg) raise ValueError(msg) - if t in M.tech_annual: + if t in model.tech_annual: annual.add(t) # Good value, pull from EfficiencyVariable table @@ -412,10 +412,10 @@ def CheckEfficiencyVariable(M: 'TemoaModel') -> None: # Check if all possible values have been set as variable # log a warning if some are missing (allowed but maybe accidental) - num_seg = len(M.TimeSeason[p]) * len(M.time_of_day) + num_seg = len(model.TimeSeason[p]) * len(model.time_of_day) for (r, p, i, t, v, o), count in count_rpitvo.items(): if count > 0: - M.isEfficiencyVariable[r, p, i, t, v, o] = True + model.isEfficiencyVariable[r, p, i, t, v, o] = True if count < num_seg: logger.info( 'Some but not all EfficiencyVariable values were set (%i out of a possible %i) for: %s' diff --git a/temoa/components/time.py b/temoa/components/time.py index 484ecd351..98fff362c 100644 --- a/temoa/components/time.py +++ b/temoa/components/time.py @@ -11,6 +11,8 @@ seasonal storage and inter-season ramping constraints. """ +from __future__ import annotations + from logging import getLogger from typing import TYPE_CHECKING @@ -30,7 +32,7 @@ # ============================================================================ -def validate_time(M: 'TemoaModel') -> None: +def validate_time(model: TemoaModel) -> None: """ We check for integer status here, rather than asking Pyomo to do this via a 'within=Integers' clause in the definition so that we can have a very @@ -39,7 +41,7 @@ def validate_time(M: 'TemoaModel') -> None: that has proven to be scary and/or impenetrable for the typical modeler. """ logger.debug('Started validating time index') - for year in M.time_exist: + for year in model.time_exist: if isinstance(year, int): continue @@ -49,7 +51,7 @@ def validate_time(M: 'TemoaModel') -> None: logger.error(msg) raise Exception(msg) - for year in M.time_future: + for year in model.time_future: if isinstance(year, int): continue @@ -57,7 +59,7 @@ def validate_time(M: 'TemoaModel') -> None: logger.error(msg) raise Exception(msg) - if len(M.time_future) < 2: + if len(model.time_future) < 2: msg = ( 'Set "time_future" needs at least 2 specified years. \nTemoa ' 'treats the integer numbers specified in this set as boundary years \n' @@ -70,9 +72,9 @@ def validate_time(M: 'TemoaModel') -> None: raise RuntimeError(msg) # Ensure that the time_exist < time_future - if len(M.time_exist) > 0: - max_exist: int = max(M.time_exist) - min_horizon: int = min(M.time_future) + if len(model.time_exist) > 0: + max_exist: int = max(model.time_exist) + min_horizon: int = min(model.time_future) if not (max_exist < min_horizon): msg = ( @@ -85,15 +87,15 @@ def validate_time(M: 'TemoaModel') -> None: logger.debug('Finished validating time') -def validate_SegFrac(M: 'TemoaModel') -> None: +def validate_segment_fraction(model: TemoaModel) -> None: """Ensure that the segment fractions adds up to 1""" - for p in M.time_optimize: + for p in model.time_optimize: expected_keys: set[tuple[int, str, str]] = { - (p, s, d) for s in M.TimeSeason[p] for d in M.time_of_day + (p, s, d) for s in model.TimeSeason[p] for d in model.time_of_day } keys: set[tuple[int, str, str]] = { - (_p, s, d) for _p, s, d in M.SegFrac.sparse_iterkeys() if _p == p + (_p, s, d) for _p, s, d in model.SegFrac.sparse_iterkeys() if _p == p } if expected_keys != keys: @@ -107,7 +109,7 @@ def validate_SegFrac(M: 'TemoaModel') -> None: logger.error(msg) raise ValueError(msg) - total: float = sum(value(M.SegFrac[k]) for k in keys) + total: float = sum(value(model.SegFrac[k]) for k in keys) if abs(float(total) - 1.0) > 0.001: # We can't explicitly test for "!= 1.0" because of incremental rounding @@ -122,7 +124,7 @@ def get_str_padding(obj: object) -> int: # Works out to something like "%-25s = %s" items_list: list[tuple[tuple[object, object, object], object]] = sorted( - [(k, M.SegFrac[k]) for k in keys] + [(k, model.SegFrac[k]) for k in keys] ) items: str = '\n '.join(f'{str(k):<{key_padding}} = {v}' for k, v in items_list) @@ -135,19 +137,21 @@ def get_str_padding(obj: object) -> int: raise Exception(msg) -def validate_TimeNext(M: 'TemoaModel') -> None: +def validate_time_next(model: TemoaModel) -> None: """ If using this table, check that defined states are actually valid. TimeSegmentFraction is already compared to other tables so just compare to SegFrac. """ # Only check TimeNext if it is actually being used - if M.TimeSequencing.first() != 'manual': + if model.TimeSequencing.first() != 'manual': return - segfrac_psd: set[tuple[int, str, str]] = set(M.SegFrac.sparse_iterkeys()) - time_next_psd: set[tuple[int, str, str]] = {(p, s, d) for p, s, d, s_next, d_next in M.TimeNext} + segfrac_psd: set[tuple[int, str, str]] = set(model.SegFrac.sparse_iterkeys()) + time_next_psd: set[tuple[int, str, str]] = { + (p, s, d) for p, s, d, s_next, d_next in model.TimeNext + } time_next_psd_next: set[tuple[int, str, str]] = { - (p, s_next, d_next) for p, s, d, s_next, d_next in M.TimeNext + (p, s_next, d_next) for p, s, d, s_next, d_next in model.TimeNext } missing_psd: set[tuple[int, str, str]] = segfrac_psd.difference(time_next_psd) @@ -167,29 +171,31 @@ def validate_TimeNext(M: 'TemoaModel') -> None: # ============================================================================ -def init_set_time_optimize(M: 'TemoaModel') -> list[int]: +def init_set_time_optimize(model: TemoaModel) -> list[int]: """Initializes the `time_optimize` set (all future years except the last).""" - return sorted(M.time_future)[:-1] + return sorted(model.time_future)[:-1] -def init_set_vintage_exist(M: 'TemoaModel') -> list[int]: +def init_set_vintage_exist(model: TemoaModel) -> list[int]: """Initializes the `vintage_exist` set.""" - return sorted(M.time_exist) + return sorted(model.time_exist) -def init_set_vintage_optimize(M: 'TemoaModel') -> list[int]: +def init_set_vintage_optimize(model: TemoaModel) -> list[int]: """Initializes the `vintage_optimize` set.""" - return sorted(M.time_optimize) + return sorted(model.time_optimize) -def SegFracPerSeason_rule(M: 'TemoaModel', p: 'Period', s: 'Season') -> float: +def seg_frac_per_season_rule(model: TemoaModel, p: Period, s: Season) -> float: """Rule to calculate the total fraction of a period represented by a season.""" - return sum(value(M.SegFrac[p, s, d]) for d in M.time_of_day if (p, s, d) in M.SegFrac) + return sum( + value(model.SegFrac[p, s, d]) for d in model.time_of_day if (p, s, d) in model.SegFrac + ) -def ParamPeriodLength(M: 'TemoaModel', p: 'Period') -> int: +def param_period_length(model: TemoaModel, p: Period) -> int: """Rule to calculate the length of each optimization period in years.""" - periods: list[int] = sorted(M.time_future) + periods: list[int] = sorted(model.time_future) i: int = periods.index(p) return periods[i + 1] - periods[i] @@ -200,34 +206,34 @@ def ParamPeriodLength(M: 'TemoaModel', p: 'Period') -> int: def loop_period_next_timeslice( - M: 'TemoaModel', p: 'Period', s: 'Season', d: 'TimeOfDay' -) -> tuple['Season', 'TimeOfDay']: + model: TemoaModel, p: Period, s: Season, d: TimeOfDay +) -> tuple[Season, TimeOfDay]: # Final time slice of final season (end of period) # Loop state back to initial state of first season # Loop the period - if s == M.TimeSeason[p].last() and d == M.time_of_day.last(): - s_next: 'Season' = M.TimeSeason[p].first() - d_next: 'TimeOfDay' = M.time_of_day.first() + if s == model.TimeSeason[p].last() and d == model.time_of_day.last(): + s_next: Season = model.TimeSeason[p].first() + d_next: TimeOfDay = model.time_of_day.first() # Last time slice of any season that is NOT the last season # Carry state to initial state of next season # Carry state between seasons - elif d == M.time_of_day.last(): - s_next = M.TimeSeason[p].next(s) - d_next = M.time_of_day.first() + elif d == model.time_of_day.last(): + s_next = model.TimeSeason[p].next(s) + d_next = model.time_of_day.first() # Any other time slice # Carry state to next time slice in the same season # Continuing through this season else: s_next = s - d_next = M.time_of_day.next(d) + d_next = model.time_of_day.next(d) return s_next, d_next def loop_season_next_timeslice( - M: 'TemoaModel', p: 'Period', s: 'Season', d: 'TimeOfDay' + model: TemoaModel, p: Period, s: Season, d: TimeOfDay ) -> tuple[str, str]: # We loop each season so never carrying state between seasons s_next: str = s @@ -235,14 +241,14 @@ def loop_season_next_timeslice( # Final time slice of any season # Loop state back to initial state of same season # Loop each season - if d == M.time_of_day.last(): - d_next = M.time_of_day.first() + if d == model.time_of_day.last(): + d_next = model.time_of_day.first() # Any other time slice # Carry state to next time slice in the same season # Continuing through this season else: - d_next = M.time_of_day.next(d) + d_next = model.time_of_day.next(d) return s_next, d_next @@ -252,34 +258,34 @@ def loop_season_next_timeslice( # ============================================================================ -def CreateTimeSequence(M: 'TemoaModel') -> None: +def create_time_sequence(model: TemoaModel) -> None: logger.debug('Creating sequence of time slices.') # Establishing sequence of states - match M.TimeSequencing.first(): + match model.TimeSequencing.first(): case 'consecutive_days': msg: str = 'Running a consecutive days database.' - for p in M.time_optimize: - for s, d in M.TimeSeason[p] * M.time_of_day: - M.time_next[p, s, d] = loop_period_next_timeslice(M, p, s, d) + for p in model.time_optimize: + for s, d in model.TimeSeason[p] * model.time_of_day: + model.time_next[p, s, d] = loop_period_next_timeslice(model, p, s, d) case 'seasonal_timeslices': msg = 'Running a seasonal time slice database.' - for p in M.time_optimize: - for s, d in M.TimeSeason[p] * M.time_of_day: - M.time_next[p, s, d] = loop_season_next_timeslice(M, p, s, d) + for p in model.time_optimize: + for s, d in model.TimeSeason[p] * model.time_of_day: + model.time_next[p, s, d] = loop_season_next_timeslice(model, p, s, d) case 'representative_periods': msg = 'Running a representative periods database.' - for p in M.time_optimize: - for s, d in M.TimeSeason[p] * M.time_of_day: - M.time_next[p, s, d] = loop_season_next_timeslice(M, p, s, d) + for p in model.time_optimize: + for s, d in model.TimeSeason[p] * model.time_of_day: + model.time_next[p, s, d] = loop_season_next_timeslice(model, p, s, d) case 'manual': # Hidden feature. Define the sequence directly in the TimeNext table msg = 'Pulling time sequence from TimeNext table.' - for p, s, d, s_next, d_next in M.TimeNext: - M.time_next[p, s, d] = s_next, d_next + for p, s, d, s_next, d_next in model.TimeNext: + model.time_next[p, s, d] = s_next, d_next case _: # This should have been caught in hybrid_loader - msg = f"Invalid time sequencing parameter loaded '{M.TimeSequencing.first()}'. Likely code error." + msg = f"Invalid time sequencing parameter loaded '{model.TimeSequencing.first()}'. Likely code error." logger.error(msg) raise ValueError(msg) @@ -289,49 +295,49 @@ def CreateTimeSequence(M: 'TemoaModel') -> None: logger.debug('Creating superimposed sequential seasons.') # Superimposed sequential seasons - for p in M.time_optimize: + for p in model.time_optimize: seasons: list[tuple[str, str]] = [ - (s_seq, s) for _p, s_seq, s in M.ordered_season_sequential if _p == p + (s_seq, s) for _p, s_seq, s in model.ordered_season_sequential if _p == p ] for i, (s_seq, s) in enumerate(seasons): - M.sequential_to_season[p, s_seq] = s + model.sequential_to_season[p, s_seq] = s if (s_seq, s) == seasons[-1]: - M.time_next_sequential[p, s_seq] = seasons[0][0] + model.time_next_sequential[p, s_seq] = seasons[0][0] else: - M.time_next_sequential[p, s_seq] = seasons[i + 1][0] + model.time_next_sequential[p, s_seq] = seasons[i + 1][0] logger.debug('Created time sequence.') -def CreateTimeSeasonSequential(M: 'TemoaModel') -> None: +def create_time_season_sequential(model: TemoaModel) -> None: if all( ( - not M.tech_seasonal_storage, - not M.RampUpHourly, - not M.RampDownHourly, + not model.tech_seasonal_storage, + not model.RampUpHourly, + not model.RampDownHourly, ) ): # Don't need it anyway return - if not M.TimeSeasonSequential: - if M.TimeSequencing.first() in ('consecutive_days', 'seasonal_timeslices'): + if not model.TimeSeasonSequential: + if model.TimeSequencing.first() in ('consecutive_days', 'seasonal_timeslices'): logger.info( 'No data in TimeSeasonSequential. By default, assuming sequential seasons ' 'match TimeSeason and TimeSegmentFraction.' ) - for s in M.time_season: - M.time_season_sequential.add(s) - for p in M.TimeSeason: - for s in M.TimeSeason[p]: - M.ordered_season_sequential.add((p, s, s)) - M.TimeSeasonSequential[p, s, s] = value(M.SegFracPerSeason[p, s]) * value( - M.DaysPerPeriod - ) + for s in model.time_season: + model.time_season_sequential.add(s) + for p in model.TimeSeason: + for s in model.TimeSeason[p]: + model.ordered_season_sequential.add((p, s, s)) + model.TimeSeasonSequential[p, s, s] = value( + model.SegFracPerSeason[p, s] + ) * value(model.DaysPerPeriod) else: msg = ( - f'No data in TimeSeasonSequential but time_sequencing parameter set to {M.TimeSequencing.first()} ' + f'No data in TimeSeasonSequential but time_sequencing parameter set to {model.TimeSequencing.first()} ' 'and inter-season features used. TimeSeasonSequential must be filled for this type of time ' 'sequencing if seasonal storage or inter-season constraints like RampUp/RampDown are used. Check ' 'the config file.' @@ -341,10 +347,10 @@ def CreateTimeSeasonSequential(M: 'TemoaModel') -> None: sequential: dict[tuple[int, str], float] = {} prev_n: float = 0 - for p, s_seq, s in M.TimeSeasonSequential.sparse_iterkeys(): - num_days: float = value(M.TimeSeasonSequential[p, s_seq, s]) + for p, s_seq, s in model.TimeSeasonSequential.sparse_iterkeys(): + num_days: float = value(model.TimeSeasonSequential[p, s_seq, s]) if ( - M.TimeSequencing.first() == 'consecutive_days' + model.TimeSequencing.first() == 'consecutive_days' and prev_n and abs(num_days - prev_n) >= 0.001 ): @@ -366,18 +372,18 @@ def CreateTimeSeasonSequential(M: 'TemoaModel') -> None: count_total: dict[ int, float ] = {} # {p: n} total days per period according to TimeSeasonSequential - for p in M.time_optimize: + for p in model.time_optimize: count_total[p] = sum(sequential[p, s] for _p, s in sequential if _p == p) - if abs(count_total[p] - value(M.DaysPerPeriod)) >= 0.001: + if abs(count_total[p] - value(model.DaysPerPeriod)) >= 0.001: logger.warning( f'Sum of num_days in TimeSeasonSequential ({count_total[p]}) ' - f'for period {p} does not sum to days_per_period ({value(M.DaysPerPeriod)}) ' + f'for period {p} does not sum to days_per_period ({value(model.DaysPerPeriod)}) ' 'from the MetaData table.' ) # Check that seasons using in storage seasons are actual seasons for p, s in sequential: - if (p, s) not in M.SegFracPerSeason: + if (p, s) not in model.SegFracPerSeason: msg = ( f'Period-season index {(p, s)} that does not exist in ' 'TimeSegmentFraction referenced in TimeSeasonSequential .' @@ -385,8 +391,8 @@ def CreateTimeSeasonSequential(M: 'TemoaModel') -> None: logger.error(msg) raise ValueError(msg) - for p, s in M.SegFracPerSeason.sparse_iterkeys(): - if s not in M.TimeSeason[p]: + for p, s in model.SegFracPerSeason.sparse_iterkeys(): + if s not in model.TimeSeason[p]: continue # Check that all seasons are used in sequential seasons @@ -395,14 +401,14 @@ def CreateTimeSeasonSequential(M: 'TemoaModel') -> None: logger.warning(msg) # Check that the two tables agree on the total seasonal composition of each period - segfrac = value(M.SegFracPerSeason[p, s]) + segfrac = value(model.SegFracPerSeason[p, s]) segfracseq = sequential[p, s] / count_total[p] if abs(segfrac - segfracseq) >= 0.001: msg = ( 'Discrepancy of total period-season composition between ' 'TimeSegmentFraction and TimeSeasonSequential. Total fraction of each ' 'period assigned to each season should match: ' - f'TimeSegmentFraction: {(p, s, value(M.SegFracPerSeason[p, s]))}' + f'TimeSegmentFraction: {(p, s, value(model.SegFracPerSeason[p, s]))}' f', TimeSeasonSequential: {(p, s, segfracseq)}' ) logger.warning(msg) diff --git a/temoa/components/utils.py b/temoa/components/utils.py index e35eee077..a56c1ae33 100644 --- a/temoa/components/utils.py +++ b/temoa/components/utils.py @@ -6,6 +6,8 @@ building Pyomo expressions from strings or calculating time-variable efficiencies. """ +from __future__ import annotations + from enum import Enum from logging import getLogger from typing import TYPE_CHECKING @@ -49,15 +51,15 @@ def operator_expression(lhs: Expression, operator: Operator, rhs: Expression) -> def get_variable_efficiency( - M: 'TemoaModel', - r: 'Region', - p: 'Period', - s: 'Season', - d: 'TimeOfDay', - i: 'Commodity', - t: 'Technology', - v: 'Vintage', - o: 'Commodity', + model: TemoaModel, + r: Region, + p: Period, + s: Season, + d: TimeOfDay, + i: Commodity, + t: Technology, + v: Vintage, + o: Commodity, ) -> float: """ Calculates the effective efficiency for a process in a specific time slice. @@ -72,9 +74,9 @@ def get_variable_efficiency( This dictionary-lookup approach is used for performance, as it is much faster than repeatedly checking the indices of a large Pyomo parameter during model build. """ - if M.isEfficiencyVariable.get((r, p, i, t, v, o), False): - return value(M.Efficiency[r, i, t, v, o]) * value( - M.EfficiencyVariable[r, p, s, d, i, t, v, o] + if model.isEfficiencyVariable.get((r, p, i, t, v, o), False): + return value(model.Efficiency[r, i, t, v, o]) * value( + model.EfficiencyVariable[r, p, s, d, i, t, v, o] ) else: - return value(M.Efficiency[r, i, t, v, o]) + return value(model.Efficiency[r, i, t, v, o]) diff --git a/temoa/core/model.py b/temoa/core/model.py index 1b2c202d7..847a2a279 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -223,7 +223,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.regions = Set(validate=region_check) # RegionalIndices is the set of all the possible combinations of interregional exchanges # plus original region indices. If tech_exchange is empty, RegionalIndices =regions. - self.regionalIndices = Set(initialize=geography.CreateRegionalIndices) + self.regionalIndices = Set(initialize=geography.create_regional_indices) self.regionalGlobalIndices = Set(validate=region_group_check) # Define technology-related sets @@ -317,14 +317,14 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.GlobalDiscountRate = Param(default=0.05) # Define time-related parameters - self.PeriodLength = Param(self.time_optimize, initialize=time.ParamPeriodLength) + self.PeriodLength = Param(self.time_optimize, initialize=time.param_period_length) self.SegFrac = Param(self.time_optimize, self.time_season, self.time_of_day) - self.validate_SegFrac = BuildAction(rule=time.validate_SegFrac) + self.validate_SegFrac = BuildAction(rule=time.validate_segment_fraction) self.TimeSequencing = Set() # How do states carry between time segments? self.TimeNext = Set( ordered=True ) # This is just to get data from the table. Hidden feature and usually not used - self.validate_TimeNext = BuildAction(rule=time.validate_TimeNext) + self.validate_TimeNext = BuildAction(rule=time.validate_time_next) # Define demand- and resource-related parameters # Dev Note: There does not appear to be a DB table supporting DemandDefaultDistro. @@ -387,7 +387,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: within=NonNegativeReals, validate=validate_Efficiency, ) - self.validate_UsedEfficiencyIndices = BuildAction(rule=technology.CheckEfficiencyIndices) + self.validate_UsedEfficiencyIndices = BuildAction(rule=technology.check_efficiency_indices) self.EfficiencyVariable = Param( self.regionalIndices, @@ -406,7 +406,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.regionalIndices, self.tech_all, default=TemoaModel.default_lifetime_tech ) - self.LifetimeProcess_rtv = Set(dimen=3, initialize=technology.LifetimeProcessIndices) + self.LifetimeProcess_rtv = Set(dimen=3, initialize=technology.lifetime_process_indices) self.LifetimeProcess = Param( self.LifetimeProcess_rtv, default=technology.get_default_process_lifetime ) @@ -420,9 +420,9 @@ def __init__(self, *args: object, **kwargs: object) -> None: validate=validate_0to1, mutable=True, ) - self.Create_SurvivalCurve = BuildAction(rule=technology.CreateSurvivalCurve) + self.Create_SurvivalCurve = BuildAction(rule=technology.create_survival_curve) - self.LoanLifetimeProcess_rtv = Set(dimen=3, initialize=costs.LifetimeLoanProcessIndices) + self.LoanLifetimeProcess_rtv = Set(dimen=3, initialize=costs.lifetime_loan_process_indices) # Dev Note: The LoanLifetimeProcess table *could* be removed. There is no longer a # supporting table in the database. It is just a "passthrough" now to the @@ -479,21 +479,21 @@ def __init__(self, *args: object, **kwargs: object) -> None: # Set up representation of time self.DaysPerPeriod = Param() self.SegFracPerSeason = Param( - self.time_optimize, self.time_season, initialize=time.SegFracPerSeason_rule + self.time_optimize, self.time_season, initialize=time.seg_frac_per_season_rule ) self.TimeSeasonSequential = Param( self.time_optimize, self.time_season_sequential, self.time_season, mutable=True ) - self.validate_SeasonSequential = BuildAction(rule=time.CreateTimeSeasonSequential) - self.Create_TimeSequence = BuildAction(rule=time.CreateTimeSequence) + self.validate_SeasonSequential = BuildAction(rule=time.create_time_season_sequential) + self.Create_TimeSequence = BuildAction(rule=time.create_time_sequence) # The method below creates a series of helper functions that are used to # perform the sparse matrix of indexing for the parameters, variables, and # equations below. self.Create_SparseDicts = BuildAction(rule=create_sparse_dicts) - self.initialize_Demands = BuildAction(rule=commodities.CreateDemands) + self.initialize_Demands = BuildAction(rule=commodities.create_demands) - self.CapacityFactor_rpsdt = Set(dimen=5, initialize=capacity.CapacityFactorTechIndices) + self.CapacityFactor_rpsdt = Set(dimen=5, initialize=capacity.capacity_factor_tech_indices) self.CapacityFactorTech = Param( self.CapacityFactor_rpsdt, default=1, validate=validate_0to1 ) @@ -512,14 +512,16 @@ def __init__(self, *args: object, **kwargs: object) -> None: default=capacity.get_default_capacity_factor, # slow but only called if a value is missing ) - self.CapacityConstraint_rpsdtv = Set(dimen=6, initialize=capacity.CapacityConstraintIndices) - self.initialize_CapacityFactors = BuildAction(rule=capacity.CheckCapacityFactorProcess) - self.initialize_EfficiencyVariable = BuildAction(rule=technology.CheckEfficiencyVariable) + self.CapacityConstraint_rpsdtv = Set( + dimen=6, initialize=capacity.capacity_constraint_indices + ) + self.initialize_CapacityFactors = BuildAction(rule=capacity.check_capacity_factor_process) + self.initialize_EfficiencyVariable = BuildAction(rule=technology.check_efficiency_variable) # Define technology cost parameters # dev note: the CostFixed_rptv isn't truly needed, but it is included in a constraint, so # let it go for now - self.CostFixed_rptv = Set(dimen=4, initialize=costs.CostFixedIndices) + self.CostFixed_rptv = Set(dimen=4, initialize=costs.cost_fixed_indices) self.CostFixed = Param(self.CostFixed_rptv) self.CostInvest_rtv = Set(within=self.regionalIndices * self.tech_all * self.time_optimize) @@ -529,9 +531,9 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.LoanRate = Param( self.CostInvest_rtv, domain=NonNegativeReals, default=costs.get_default_loan_rate ) - self.LoanAnnualize = Param(self.CostInvest_rtv, initialize=costs.ParamLoanAnnualize_rule) + self.LoanAnnualize = Param(self.CostInvest_rtv, initialize=costs.param_loan_annualize_rule) - self.CostVariable_rptv = Set(dimen=4, initialize=costs.CostVariableIndices) + self.CostVariable_rptv = Set(dimen=4, initialize=costs.cost_variable_indices) self.CostVariable = Param(self.CostVariable_rptv) self.CostEmission_rpe = Set( @@ -543,9 +545,9 @@ def __init__(self, *args: object, **kwargs: object) -> None: # M.ModelProcessLife_rptv = Set(dimen=4, initialize=ModelProcessLifeIndices) # M.ModelProcessLife = Param(M.ModelProcessLife_rptv, initialize=ParamModelProcessLife_rule) - self.ProcessLifeFrac_rptv = Set(dimen=4, initialize=technology.ModelProcessLifeIndices) + self.ProcessLifeFrac_rptv = Set(dimen=4, initialize=technology.model_process_life_indices) self.ProcessLifeFrac = Param( - self.ProcessLifeFrac_rptv, initialize=technology.ParamProcessLifeFraction_rule + self.ProcessLifeFrac_rptv, initialize=technology.param_process_life_fraction_rule ) self.LimitCapacityConstraint_rpt = Set( @@ -625,7 +627,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: * self.operator ) self.LimitEmission = Param(self.LimitEmissionConstraint_rpe) - self.EmissionActivity_reitvo = Set(dimen=6, initialize=emissions.EmissionActivityIndices) + self.EmissionActivity_reitvo = Set(dimen=6, initialize=emissions.emission_activity_indices) self.EmissionActivity = Param(self.EmissionActivity_reitvo) # devnote: deprecated when generalising tech/group columns in Limit tables @@ -682,9 +684,9 @@ def __init__(self, *args: object, **kwargs: object) -> None: # M.LimitActivityGroupShare = Param(M.TwoGroupShareIndices) # This set works for all storage-related constraints - self.StorageConstraints_rpsdtv = Set(dimen=6, initialize=storage.StorageConstraintIndices) + self.StorageConstraints_rpsdtv = Set(dimen=6, initialize=storage.storage_constraint_indices) self.SeasonalStorageConstraints_rpsdtv = Set( - dimen=6, initialize=storage.SeasonalStorageConstraintIndices + dimen=6, initialize=storage.seasonal_storage_constraint_indices ) self.LimitStorageFractionConstraint_rpsdtv = Set( within=(self.StorageConstraints_rpsdtv | self.SeasonalStorageConstraints_rpsdtv) @@ -749,57 +751,59 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.progress_marker_3 = BuildAction(['Starting to build Variables'], rule=progress_check) # Define base decision variables - self.FlowVar_rpsditvo = Set(dimen=8, initialize=flows.FlowVariableIndices) + self.FlowVar_rpsditvo = Set(dimen=8, initialize=flows.flow_variable_indices) self.V_FlowOut = Var(self.FlowVar_rpsditvo, domain=NonNegativeReals) - self.FlowVarAnnual_rpitvo = Set(dimen=6, initialize=flows.FlowVariableAnnualIndices) + self.FlowVarAnnual_rpitvo = Set(dimen=6, initialize=flows.flow_variable_annual_indices) self.V_FlowOutAnnual = Var(self.FlowVarAnnual_rpitvo, domain=NonNegativeReals) - self.FlexVar_rpsditvo = Set(dimen=8, initialize=flows.FlexVariablelIndices) + self.FlexVar_rpsditvo = Set(dimen=8, initialize=flows.flex_variable_indices) self.V_Flex = Var(self.FlexVar_rpsditvo, domain=NonNegativeReals) - self.FlexVarAnnual_rpitvo = Set(dimen=6, initialize=flows.FlexVariableAnnualIndices) + self.FlexVarAnnual_rpitvo = Set(dimen=6, initialize=flows.flex_variable_annual_indices) self.V_FlexAnnual = Var(self.FlexVarAnnual_rpitvo, domain=NonNegativeReals) - self.CurtailmentVar_rpsditvo = Set(dimen=8, initialize=flows.CurtailmentVariableIndices) + self.CurtailmentVar_rpsditvo = Set(dimen=8, initialize=flows.curtailment_variable_indices) self.V_Curtailment = Var( self.CurtailmentVar_rpsditvo, domain=NonNegativeReals, initialize=0 ) - self.FlowInStorage_rpsditvo = Set(dimen=8, initialize=flows.FlowInStorageVariableIndices) + self.FlowInStorage_rpsditvo = Set( + dimen=8, initialize=flows.flow_in_storage_variable_indices + ) self.V_FlowIn = Var(self.FlowInStorage_rpsditvo, domain=NonNegativeReals) - self.StorageLevel_rpsdtv = Set(dimen=6, initialize=storage.StorageLevelVariableIndices) + self.StorageLevel_rpsdtv = Set(dimen=6, initialize=storage.storage_level_variable_indices) self.V_StorageLevel = Var(self.StorageLevel_rpsdtv, domain=NonNegativeReals) self.SeasonalStorageLevel_rpstv = Set( - dimen=5, initialize=storage.SeasonalStorageLevelVariableIndices + dimen=5, initialize=storage.seasonal_storage_level_variable_indices ) self.V_SeasonalStorageLevel = Var(self.SeasonalStorageLevel_rpstv, domain=NonNegativeReals) # Derived decision variables - self.CapacityVar_rptv = Set(dimen=4, initialize=costs.CostFixedIndices) + self.CapacityVar_rptv = Set(dimen=4, initialize=costs.cost_fixed_indices) self.V_Capacity = Var(self.CapacityVar_rptv, domain=NonNegativeReals) - self.NewCapacityVar_rtv = Set(dimen=3, initialize=capacity.CapacityVariableIndices) + self.NewCapacityVar_rtv = Set(dimen=3, initialize=capacity.capacity_variable_indices) self.V_NewCapacity = Var(self.NewCapacityVar_rtv, domain=NonNegativeReals, initialize=0) self.RetiredCapacityVar_rptv = Set( - dimen=4, initialize=capacity.RetiredCapacityVariableIndices + dimen=4, initialize=capacity.retired_capacity_variable_indices ) self.V_RetiredCapacity = Var( self.RetiredCapacityVar_rptv, domain=NonNegativeReals, initialize=0 ) self.AnnualRetirementVar_rptv = Set( - dimen=4, initialize=capacity.AnnualRetirementVariableIndices + dimen=4, initialize=capacity.annual_retirement_variable_indices ) self.V_AnnualRetirement = Var( self.AnnualRetirementVar_rptv, domain=NonNegativeReals, initialize=0 ) self.CapacityAvailableVar_rpt = Set( - dimen=3, initialize=capacity.CapacityAvailableVariableIndices + dimen=3, initialize=capacity.capacity_available_variable_indices ) self.V_CapacityAvailableByPeriodAndTech = Var( self.CapacityAvailableVar_rpt, domain=NonNegativeReals, initialize=0 @@ -810,7 +814,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: # (minimize total cost) # ################################################ - self.TotalCost = Objective(rule=costs.TotalCost_rule, sense=minimize) + self.TotalCost = Objective(rule=costs.total_cost_rule, sense=minimize) ################################################ # Constraints # @@ -828,19 +832,19 @@ def __init__(self, *args: object, **kwargs: object) -> None: # Declare constraints to calculate derived decision variables self.CapacityConstraint = Constraint( - self.CapacityConstraint_rpsdtv, rule=capacity.Capacity_Constraint + self.CapacityConstraint_rpsdtv, rule=capacity.capacity_constraint ) self.CapacityAnnualConstraint_rptv = Set( - dimen=4, initialize=capacity.CapacityAnnualConstraintIndices + dimen=4, initialize=capacity.capacity_annual_constraint_indices ) self.CapacityAnnualConstraint = Constraint( - self.CapacityAnnualConstraint_rptv, rule=capacity.CapacityAnnual_Constraint + self.CapacityAnnualConstraint_rptv, rule=capacity.capacity_annual_constraint ) self.CapacityAvailableByPeriodAndTechConstraint = Constraint( self.CapacityAvailableVar_rpt, - rule=capacity.CapacityAvailableByPeriodAndTech_Constraint, + rule=capacity.capacity_available_by_period_and_tech_constraint, ) # devnote: I think this constraint is redundant @@ -851,13 +855,13 @@ def __init__(self, *args: object, **kwargs: object) -> None: ['Starting AnnualRetirementConstraint'], rule=progress_check ) self.AnnualRetirementConstraint = Constraint( - self.AnnualRetirementVar_rptv, rule=capacity.AnnualRetirement_Constraint + self.AnnualRetirementVar_rptv, rule=capacity.annual_retirement_constraint ) self.progress_marker_4b = BuildAction( ['Starting AdjustedCapacityConstraint'], rule=progress_check ) self.AdjustedCapacityConstraint = Constraint( - self.CostFixed_rptv, rule=capacity.AdjustedCapacity_Constraint + self.CostFixed_rptv, rule=capacity.adjusted_capacity_constraint ) self.progress_marker_5 = BuildAction(['Finished Capacity Constraints'], rule=progress_check) @@ -865,30 +869,30 @@ def __init__(self, *args: object, **kwargs: object) -> None: # In driving order, starting with the need to meet end-use demands self.DemandConstraint = Constraint( - self.DemandConstraint_rpc, rule=commodities.Demand_Constraint + self.DemandConstraint_rpc, rule=commodities.demand_constraint ) # devnote: testing a workaround self.DemandActivityConstraint_rpsdtv_dem = Set( - dimen=7, initialize=commodities.DemandActivityConstraintIndices + dimen=7, initialize=commodities.demand_activity_constraint_indices ) self.DemandActivityConstraint = Constraint( - self.DemandActivityConstraint_rpsdtv_dem, rule=commodities.DemandActivity_Constraint + self.DemandActivityConstraint_rpsdtv_dem, rule=commodities.demand_activity_constraint ) self.CommodityBalanceConstraint_rpsdc = Set( - dimen=5, initialize=commodities.CommodityBalanceConstraintIndices + dimen=5, initialize=commodities.commodity_balance_constraint_indices ) self.CommodityBalanceConstraint = Constraint( - self.CommodityBalanceConstraint_rpsdc, rule=commodities.CommodityBalance_Constraint + self.CommodityBalanceConstraint_rpsdc, rule=commodities.commodity_balance_constraint ) self.AnnualCommodityBalanceConstraint_rpc = Set( - dimen=3, initialize=commodities.AnnualCommodityBalanceConstraintIndices + dimen=3, initialize=commodities.annual_commodity_balance_constraint_indices ) self.AnnualCommodityBalanceConstraint = Constraint( self.AnnualCommodityBalanceConstraint_rpc, - rule=commodities.AnnualCommodityBalance_Constraint, + rule=commodities.annual_commodity_balance_constraint, ) # M.ResourceExtractionConstraint = Constraint( @@ -896,146 +900,147 @@ def __init__(self, *args: object, **kwargs: object) -> None: # ) self.BaseloadDiurnalConstraint_rpsdtv = Set( - dimen=6, initialize=operations.BaseloadDiurnalConstraintIndices + dimen=6, initialize=operations.baseload_diurnal_constraint_indices ) self.BaseloadDiurnalConstraint = Constraint( - self.BaseloadDiurnalConstraint_rpsdtv, rule=operations.BaseloadDiurnal_Constraint + self.BaseloadDiurnalConstraint_rpsdtv, rule=operations.baseload_diurnal_constraint ) self.RegionalExchangeCapacityConstraint_rrptv = Set( - dimen=5, initialize=capacity.RegionalExchangeCapacityConstraintIndices + dimen=5, initialize=capacity.regional_exchange_capacity_constraint_indices ) self.RegionalExchangeCapacityConstraint = Constraint( self.RegionalExchangeCapacityConstraint_rrptv, - rule=geography.RegionalExchangeCapacity_Constraint, + rule=geography.regional_exchange_capacity_constraint, ) self.progress_marker_6 = BuildAction(['Starting Storage Constraints'], rule=progress_check) self.StorageEnergyConstraint = Constraint( - self.StorageConstraints_rpsdtv, rule=storage.StorageEnergy_Constraint + self.StorageConstraints_rpsdtv, rule=storage.storage_energy_constraint ) self.StorageEnergyUpperBoundConstraint = Constraint( - self.StorageConstraints_rpsdtv, rule=storage.StorageEnergyUpperBound_Constraint + self.StorageConstraints_rpsdtv, rule=storage.storage_energy_upper_bound_constraint ) self.SeasonalStorageEnergyConstraint = Constraint( - self.SeasonalStorageLevel_rpstv, rule=storage.SeasonalStorageEnergy_Constraint + self.SeasonalStorageLevel_rpstv, rule=storage.seasonal_storage_energy_constraint ) self.SeasonalStorageEnergyUpperBoundConstraint = Constraint( self.SeasonalStorageConstraints_rpsdtv, - rule=storage.SeasonalStorageEnergyUpperBound_Constraint, + rule=storage.seasonal_storage_energy_upper_bound_constraint, ) self.StorageChargeRateConstraint = Constraint( - self.StorageConstraints_rpsdtv, rule=storage.StorageChargeRate_Constraint + self.StorageConstraints_rpsdtv, rule=storage.storage_charge_rate_constraint ) self.StorageDischargeRateConstraint = Constraint( - self.StorageConstraints_rpsdtv, rule=storage.StorageDischargeRate_Constraint + self.StorageConstraints_rpsdtv, rule=storage.storage_discharge_rate_constraint ) self.StorageThroughputConstraint = Constraint( - self.StorageConstraints_rpsdtv, rule=storage.StorageThroughput_Constraint + self.StorageConstraints_rpsdtv, rule=storage.storage_throughput_constraint ) self.LimitStorageFractionConstraint = Constraint( self.LimitStorageFractionConstraint_rpsdtv, - rule=storage.LimitStorageFraction_Constraint, + rule=storage.limit_storage_fraction_constraint, ) self.RampUpDayConstraint_rpsdtv = Set( - dimen=6, initialize=operations.RampUpDayConstraintIndices + dimen=6, initialize=operations.ramp_up_day_constraint_indices ) self.RampUpDayConstraint = Constraint( - self.RampUpDayConstraint_rpsdtv, rule=operations.RampUpDay_Constraint + self.RampUpDayConstraint_rpsdtv, rule=operations.ramp_up_day_constraint ) self.RampDownDayConstraint_rpsdtv = Set( - dimen=6, initialize=operations.RampDownDayConstraintIndices + dimen=6, initialize=operations.ramp_down_day_constraint_indices ) self.RampDownDayConstraint = Constraint( - self.RampDownDayConstraint_rpsdtv, rule=operations.RampDownDay_Constraint + self.RampDownDayConstraint_rpsdtv, rule=operations.ramp_down_day_constraint ) self.RampUpSeasonConstraint_rpsstv = Set( - dimen=6, initialize=operations.RampUpSeasonConstraintIndices + dimen=6, initialize=operations.ramp_up_season_constraint_indices ) self.RampUpSeasonConstraint = Constraint( - self.RampUpSeasonConstraint_rpsstv, rule=operations.RampUpSeason_Constraint + self.RampUpSeasonConstraint_rpsstv, rule=operations.ramp_up_season_constraint ) self.RampDownSeasonConstraint_rpsstv = Set( - dimen=6, initialize=operations.RampDownSeasonConstraintIndices + dimen=6, initialize=operations.ramp_down_season_constraint_indices ) self.RampDownSeasonConstraint = Constraint( - self.RampDownSeasonConstraint_rpsstv, rule=operations.RampDownSeason_Constraint + self.RampDownSeasonConstraint_rpsstv, rule=operations.ramp_down_season_constraint ) - self.ReserveMargin_rpsd = Set(dimen=4, initialize=reserves.ReserveMarginIndices) + self.ReserveMargin_rpsd = Set(dimen=4, initialize=reserves.reserve_margin_indices) self.validate_ReserveMargin = BuildAction(rule=validate_ReserveMargin) self.ReserveMarginConstraint = Constraint( - self.ReserveMargin_rpsd, rule=reserves.ReserveMargin_Constraint + self.ReserveMargin_rpsd, rule=reserves.reserve_margin_constraint ) self.LimitEmissionConstraint = Constraint( - self.LimitEmissionConstraint_rpe, rule=limits.LimitEmission_Constraint + self.LimitEmissionConstraint_rpe, rule=limits.limit_emission_constraint ) self.progress_marker_7 = BuildAction( ['Starting LimitGrowth and Activity Constraints'], rule=progress_check ) self.LimitGrowthCapacityConstraint_rpt = Set( - dimen=4, initialize=limits.LimitGrowthCapacityIndices + dimen=4, initialize=limits.limit_growth_capacity_indices ) self.LimitGrowthCapacityConstraint = Constraint( - self.LimitGrowthCapacityConstraint_rpt, rule=limits.LimitGrowthCapacityConstraint_rule + self.LimitGrowthCapacityConstraint_rpt, + rule=limits.limit_growth_capacity_constraint_rule, ) self.LimitDegrowthCapacityConstraint_rpt = Set( - dimen=4, initialize=limits.LimitDegrowthCapacityIndices + dimen=4, initialize=limits.limit_degrowth_capacity_indices ) self.LimitDegrowthCapacityConstraint = Constraint( self.LimitDegrowthCapacityConstraint_rpt, - rule=limits.LimitDegrowthCapacityConstraint_rule, + rule=limits.limit_degrowth_capacity_constraint_rule, ) self.LimitGrowthNewCapacityConstraint_rpt = Set( - dimen=4, initialize=limits.LimitGrowthNewCapacityIndices + dimen=4, initialize=limits.limit_growth_new_capacity_indices ) self.LimitGrowthNewCapacityConstraint = Constraint( self.LimitGrowthNewCapacityConstraint_rpt, - rule=limits.LimitGrowthNewCapacityConstraint_rule, + rule=limits.limit_growth_new_capacity_constraint_rule, ) self.LimitDegrowthNewCapacityConstraint_rpt = Set( - dimen=4, initialize=limits.LimitDegrowthNewCapacityIndices + dimen=4, initialize=limits.limit_degrowth_new_capacity_indices ) self.LimitDegrowthNewCapacityConstraint = Constraint( self.LimitDegrowthNewCapacityConstraint_rpt, - rule=limits.LimitDegrowthNewCapacityConstraint_rule, + rule=limits.limit_degrowth_new_capacity_constraint_rule, ) self.LimitGrowthNewCapacityDeltaConstraint_rpt = Set( - dimen=4, initialize=limits.LimitGrowthNewCapacityDeltaIndices + dimen=4, initialize=limits.limit_growth_new_capacity_delta_indices ) self.LimitGrowthNewCapacityDeltaConstraint = Constraint( self.LimitGrowthNewCapacityDeltaConstraint_rpt, - rule=limits.LimitGrowthNewCapacityDeltaConstraint_rule, + rule=limits.limit_growth_new_capacity_delta_constraint_rule, ) self.LimitDegrowthNewCapacityDeltaConstraint_rpt = Set( - dimen=4, initialize=limits.LimitDegrowthNewCapacityDeltaIndices + dimen=4, initialize=limits.limit_degrowth_new_capacity_delta_indices ) self.LimitDegrowthNewCapacityDeltaConstraint = Constraint( self.LimitDegrowthNewCapacityDeltaConstraint_rpt, - rule=limits.LimitDegrowthNewCapacityDeltaConstraint_rule, + rule=limits.limit_degrowth_new_capacity_delta_constraint_rule, ) self.LimitActivityConstraint = Constraint( - self.LimitActivityConstraint_rpt, rule=limits.LimitActivity_Constraint + self.LimitActivityConstraint_rpt, rule=limits.limit_activity_constraint ) self.LimitSeasonalCapacityFactorConstraint = Constraint( self.LimitSeasonalCapacityFactorConstraint_rpst, - rule=limits.LimitSeasonalCapacityFactor_Constraint, + rule=limits.limit_seasonal_capacity_factor_constraint, ) # devnote: deprecated when generalising tech/group columns in Limit tables @@ -1044,11 +1049,11 @@ def __init__(self, *args: object, **kwargs: object) -> None: # ) self.LimitCapacityConstraint = Constraint( - self.LimitCapacityConstraint_rpt, rule=limits.LimitCapacity_Constraint + self.LimitCapacityConstraint_rpt, rule=limits.limit_capacity_constraint ) self.LimitNewCapacityConstraint = Constraint( - self.LimitNewCapacityConstraint_rpt, rule=limits.LimitNewCapacity_Constraint + self.LimitNewCapacityConstraint_rpt, rule=limits.limit_new_capacity_constraint ) # devnote: deprecated when generalising tech/group columns in Limit tables @@ -1061,15 +1066,16 @@ def __init__(self, *args: object, **kwargs: object) -> None: # ) self.LimitCapacityShareConstraint = Constraint( - self.LimitCapacityShareConstraint_rpgg, rule=limits.LimitCapacityShare_Constraint + self.LimitCapacityShareConstraint_rpgg, rule=limits.limit_capacity_share_constraint ) self.LimitActivityShareConstraint = Constraint( - self.LimitActivityShareConstraint_rpgg, rule=limits.LimitActivityShare_Constraint + self.LimitActivityShareConstraint_rpgg, rule=limits.limit_activity_share_constraint ) self.LimitNewCapacityShareConstraint = Constraint( - self.LimitNewCapacityShareConstraint_rpgg, rule=limits.LimitNewCapacityShare_Constraint + self.LimitNewCapacityShareConstraint_rpgg, + rule=limits.limit_new_capacity_share_constraint, ) # devnote: deprecated when generalising tech/group columns in Limit tables @@ -1087,77 +1093,78 @@ def __init__(self, *args: object, **kwargs: object) -> None: ) self.LimitResourceConstraint = Constraint( - self.LimitResourceConstraint_rt, rule=limits.LimitResource_Constraint + self.LimitResourceConstraint_rt, rule=limits.limit_resource_constraint ) self.LimitAnnualCapacityFactorConstraint = Constraint( self.LimitAnnualCapacityFactorConstraint_rpto, - rule=limits.LimitAnnualCapacityFactor_Constraint, + rule=limits.limit_annual_capacity_factor_constraint, ) ## Tech input splits self.LimitTechInputSplitConstraint_rpsditv = Set( - dimen=8, initialize=limits.LimitTechInputSplitConstraintIndices + dimen=8, initialize=limits.limit_tech_input_split_constraint_indices ) self.LimitTechInputSplitConstraint = Constraint( - self.LimitTechInputSplitConstraint_rpsditv, rule=limits.LimitTechInputSplit_Constraint + self.LimitTechInputSplitConstraint_rpsditv, + rule=limits.limit_tech_input_split_constraint, ) self.LimitTechInputSplitAnnualConstraint_rpitv = Set( - dimen=6, initialize=limits.LimitTechInputSplitAnnualConstraintIndices + dimen=6, initialize=limits.limit_tech_input_split_annual_constraint_indices ) self.LimitTechInputSplitAnnualConstraint = Constraint( self.LimitTechInputSplitAnnualConstraint_rpitv, - rule=limits.LimitTechInputSplitAnnual_Constraint, + rule=limits.limit_tech_input_split_annual_constraint, ) self.LimitTechInputSplitAverageConstraint_rpitv = Set( - dimen=6, initialize=limits.LimitTechInputSplitAverageConstraintIndices + dimen=6, initialize=limits.limit_tech_input_split_average_constraint_indices ) self.LimitTechInputSplitAverageConstraint = Constraint( self.LimitTechInputSplitAverageConstraint_rpitv, - rule=limits.LimitTechInputSplitAverage_Constraint, + rule=limits.limit_tech_input_split_average_constraint, ) ## Tech output splits self.LimitTechOutputSplitConstraint_rpsdtvo = Set( - dimen=8, initialize=limits.LimitTechOutputSplitConstraintIndices + dimen=8, initialize=limits.limit_tech_output_split_constraint_indices ) self.LimitTechOutputSplitConstraint = Constraint( self.LimitTechOutputSplitConstraint_rpsdtvo, - rule=limits.LimitTechOutputSplit_Constraint, + rule=limits.limit_tech_output_split_constraint, ) self.LimitTechOutputSplitAnnualConstraint_rptvo = Set( - dimen=6, initialize=limits.LimitTechOutputSplitAnnualConstraintIndices + dimen=6, initialize=limits.limit_tech_output_split_annual_constraint_indices ) self.LimitTechOutputSplitAnnualConstraint = Constraint( self.LimitTechOutputSplitAnnualConstraint_rptvo, - rule=limits.LimitTechOutputSplitAnnual_Constraint, + rule=limits.limit_tech_output_split_annual_constraint, ) self.LimitTechOutputSplitAverageConstraint_rptvo = Set( - dimen=6, initialize=limits.LimitTechOutputSplitAverageConstraintIndices + dimen=6, initialize=limits.limit_tech_output_split_average_constraint_indices ) self.LimitTechOutputSplitAverageConstraint = Constraint( self.LimitTechOutputSplitAverageConstraint_rptvo, - rule=limits.LimitTechOutputSplitAverage_Constraint, + rule=limits.limit_tech_output_split_average_constraint, ) self.RenewablePortfolioStandardConstraint = Constraint( self.RenewablePortfolioStandardConstraint_rpg, - rule=limits.RenewablePortfolioStandard_Constraint, + rule=limits.renewable_portfolio_standard_constraint, ) self.LinkedEmissionsTechConstraint_rpsdtve = Set( - dimen=7, initialize=emissions.LinkedTechConstraintIndices + dimen=7, initialize=emissions.linked_tech_constraint_indices ) # the validation requires that the set above be built first: self.validate_LinkedTech_lifetimes = BuildCheck(rule=validate_linked_tech) self.LinkedEmissionsTechConstraint = Constraint( self.LinkedEmissionsTechConstraint_rpsdtve, - rule=emissions.LinkedEmissionsTech_Constraint, + rule=emissions.linked_emissions_tech_constraint, ) self.progress_marker_9 = BuildAction(['Finished Constraints'], rule=progress_check) diff --git a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py index 0ac1ff775..927ff5c83 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py +++ b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py @@ -46,7 +46,7 @@ from definitions import PROJECT_ROOT, get_OUTPUT_PATH from temoa._internal.run_actions import build_instance from temoa._internal.table_writer import TableWriter -from temoa.components.costs import TotalCost_rule +from temoa.components.costs import total_cost_rule from temoa.core.config import TemoaConfig from temoa.core.model import TemoaModel from temoa.data_io.hybrid_loader import HybridLoader @@ -192,7 +192,7 @@ def start(self): logger.info('Completed initial solve with total cost: %0.2f', tot_cost) logger.info('Relaxing cost by fraction: %0.3f', self.cost_epsilon) # get hook on the expression generator for total cost... - cost_expression = TotalCost_rule(instance) + cost_expression = total_cost_rule(instance) instance.cost_cap = pyo.Constraint( expr=cost_expression <= (1 + self.cost_epsilon) * tot_cost ) diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index fc573ad22..71d08375d 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -9,7 +9,6 @@ from collections import deque from pathlib import Path from sqlite3 import Connection -import sys import definitions from temoa._internal import run_actions diff --git a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py index 6b4b92725..694b99546 100644 --- a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py +++ b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py @@ -40,7 +40,7 @@ from temoa._internal.run_actions import build_instance, handle_results, save_lp, solve_instance from temoa._internal.table_writer import TableWriter -from temoa.components.costs import TotalCost_rule +from temoa.components.costs import total_cost_rule from temoa.core.config import TemoaConfig from temoa.core.model import TemoaModel from temoa.data_io.hybrid_loader import HybridLoader @@ -134,7 +134,7 @@ def start(self): logger.info('Completed initial solve with total cost: %0.2f', tot_cost) logger.info('Relaxing cost by fraction: %0.3f', self.cost_epsilon) # get hook on the expression generator for total cost... - cost_expression = TotalCost_rule(instance) + cost_expression = total_cost_rule(instance) instance.cost_cap = Constraint(expr=cost_expression <= (1 + self.cost_epsilon) * tot_cost) # 3b. remove the old objective @@ -182,17 +182,17 @@ def start(self): logger.error('The baseline SVMGA solve failed. Terminating run.') raise RuntimeError('Baseline SVMGA solve failed. Terminating run.') logger.info( - 'Completed secondary solve with total cost: %0.2f', value(TotalCost_rule(instance)) + 'Completed secondary solve with total cost: %0.2f', value(total_cost_rule(instance)) ) # record the 1-solve in all tables handle_results(instance, results=res, config=self.config, append=True, iteration=1) if not self.config.silent: - summarize(self.config, tot_cost, value(TotalCost_rule(instance))) + summarize(self.config, tot_cost, value(total_cost_rule(instance))) @staticmethod - def flow_idxs_from_eac_idx(M: TemoaModel, reitvo: tuple) -> tuple[list[tuple], ...]: + def flow_idxs_from_eac_idx(model: TemoaModel, reitvo: tuple) -> tuple[list[tuple], ...]: """ From the emission index, expand to create the full list of possible flow indices for regular and annual flows. These may/may not be valid and must be screened @@ -200,16 +200,19 @@ def flow_idxs_from_eac_idx(M: TemoaModel, reitvo: tuple) -> tuple[list[tuple], . """ r, _, i, t, v, o = reitvo psd_set = [ - (p, s, d) for p in M.time_optimize for s in M.TimeSeason[p] for d in M.time_of_day + (p, s, d) + for p in model.time_optimize + for s in model.TimeSeason[p] + for d in model.time_of_day ] flow_idxs = [(r, *psd, i, t, v, o) for psd in psd_set] - annual_flow_idxs = [(r, p, i, t, v, o) for p in M.time_optimize] + annual_flow_idxs = [(r, p, i, t, v, o) for p in model.time_optimize] return flow_idxs, annual_flow_idxs @staticmethod def construct_obj( - M: TemoaModel, + model: TemoaModel, emission_labels: Iterable[str], capacity_labels: Iterable[str], activity_labels: Iterable[str], @@ -250,36 +253,38 @@ def construct_obj( # handle emissions... for label in emission_labels: - idxs = [idx for idx in M.EmissionActivity if idx[1] == label] + idxs = [idx for idx in model.EmissionActivity if idx[1] == label] logger.debug('Located %d items for emission label: %s', len(idxs), label) for idx in idxs: # for each indexed item in EmissionActivity, we need to search both the regular # flows and the annual flows. And, we need to sum across the "expanded" index # for both which includes period, season, tod or just period respectively - expanded_idxs, expanded_annual_idxs = SvMgaSequencer.flow_idxs_from_eac_idx(M, idx) + expanded_idxs, expanded_annual_idxs = SvMgaSequencer.flow_idxs_from_eac_idx( + model, idx + ) element = sum( - M.V_FlowOut[flow_idx] * M.EmissionActivity[idx] + model.V_FlowOut[flow_idx] * model.EmissionActivity[idx] for flow_idx in expanded_idxs - if flow_idx in M.V_FlowOut + if flow_idx in model.V_FlowOut ) expr += element annual_element = sum( - M.V_FlowOutAnnual[annual_flow_idx] * M.EmissionActivity[idx] + model.V_FlowOutAnnual[annual_flow_idx] * model.EmissionActivity[idx] for annual_flow_idx in expanded_annual_idxs - if annual_flow_idx in M.V_FlowOutAnnual + if annual_flow_idx in model.V_FlowOutAnnual ) expr += annual_element # handle activity... for label in activity_labels: - idxs = [idx for idx in M.V_FlowOut if idx[5] == label] + idxs = [idx for idx in model.V_FlowOut if idx[5] == label] logger.debug('Located %d items for activity label: %s', len(idxs), label) - expr += sum(M.V_FlowOut[idx] for idx in idxs) + expr += sum(model.V_FlowOut[idx] for idx in idxs) # handle capacity... for label in capacity_labels: - idxs = [idx for idx in M.V_Capacity if idx[2] == label] + idxs = [idx for idx in model.V_Capacity if idx[2] == label] logger.debug('Located %d items for capacity label: %s', len(idxs), label) - expr += sum(M.V_Capacity[idx] for idx in idxs) + expr += sum(model.V_Capacity[idx] for idx in idxs) return expr diff --git a/temoa/utilities/unit_cost_explorer.py b/temoa/utilities/unit_cost_explorer.py index d2472bcf7..0c8969ea6 100644 --- a/temoa/utilities/unit_cost_explorer.py +++ b/temoa/utilities/unit_cost_explorer.py @@ -5,8 +5,8 @@ from pyomo.environ import value -from temoa.components.costs import TotalCost_rule -from temoa.components.storage import StorageEnergyUpperBound_Constraint +from temoa.components.costs import total_cost_rule +from temoa.components.storage import storage_energy_upper_bound_constraint from temoa.core.model import TemoaModel # Written by: J. F. Hyink @@ -71,7 +71,7 @@ M.V_Capacity[rptv].set_value(1) # run the total cost rule on our "model": -tot_cost_expr = TotalCost_rule(M) +tot_cost_expr = total_cost_rule(M) total_cost = value(tot_cost_expr) print() print(f'Total cost for building 1 capacity unit of storage: ${total_cost:0.2f} [$M]') @@ -96,7 +96,7 @@ # More SETS M.time_season.construct(['winter', 'summer']) -M.TimeSeason.construct(data={2020:{'winter', 'summer'}, 2025:{'winter', 'summer'}}) +M.TimeSeason.construct(data={2020: {'winter', 'summer'}, 2025: {'winter', 'summer'}}) M.DaysPerPeriod.construct(data={None: 365}) tod_slices = 2 M.time_of_day.construct(data=range(1, tod_slices + 1)) @@ -118,7 +118,12 @@ M.StorageDuration.construct(data={('A', 'battery'): 4}) seasonal_fractions = {'winter': 0.4, 'summer': 0.6} M.SegFrac.construct( - data={(p, s, d): seasonal_fractions[s] / tod_slices for d in M.time_of_day for p in M.time_optimize for s in M.TimeSeason[p] } + data={ + (p, s, d): seasonal_fractions[s] / tod_slices + for d in M.time_of_day + for p in M.time_optimize + for s in M.TimeSeason[p] + } ) # QA the total print(f'quality check. Total of all SegFrac: {sum(M.SegFrac.values()):0.3f}') @@ -129,7 +134,7 @@ M.SegFracPerSeason.construct() M.isSeasonalStorage['battery'] = False -upper_limit = StorageEnergyUpperBound_Constraint(M, 'A', 2020, 'winter', 1, 'battery', 2020) +upper_limit = storage_energy_upper_bound_constraint(M, 'A', 2020, 'winter', 1, 'battery', 2020) print('The storage level constraint for the single period in the "super day":\n', upper_limit) # cross-check the multiplier... From 54266f75e3e95d1d1514b5142711600df64a8df3 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 28 Oct 2025 18:02:19 -0400 Subject: [PATCH 280/587] fixing naming in data_io --- temoa/data_io/component_manifest.py | 156 ++++++++++++++-------------- temoa/data_io/hybrid_loader.py | 132 +++++++++++------------ 2 files changed, 145 insertions(+), 143 deletions(-) diff --git a/temoa/data_io/component_manifest.py b/temoa/data_io/component_manifest.py index 330738884..c449c16f0 100644 --- a/temoa/data_io/component_manifest.py +++ b/temoa/data_io/component_manifest.py @@ -20,7 +20,7 @@ from temoa.data_io.loader_manifest import LoadItem -def build_manifest(M: TemoaModel) -> list[LoadItem]: +def build_manifest(model: TemoaModel) -> list[LoadItem]: """ Builds the manifest of all data components to be loaded into the Pyomo model. @@ -39,13 +39,13 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: # Core Model Structure (Regions, Techs, Commodities, Groups) # ========================================================================= LoadItem( - component=M.regions, + component=model.regions, table='Region', columns=['region'], is_period_filtered=False, ), LoadItem( - component=M.regionalGlobalIndices, + component=model.regionalGlobalIndices, table='meta_regional_groups', # Placeholder, custom loader does the work columns=['region_or_group'], custom_loader_name='_load_regional_global_indices', @@ -53,7 +53,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.tech_production, + component=model.tech_production, table='Technology', columns=['tech'], where_clause="flag LIKE 'p%'", @@ -62,7 +62,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_period_filtered=False, ), LoadItem( - component=M.tech_uncap, + component=model.tech_uncap, table='Technology', columns=['tech'], where_clause='unlim_cap > 0', @@ -72,7 +72,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.tech_baseload, + component=model.tech_baseload, table='Technology', columns=['tech'], where_clause="flag = 'pb'", @@ -81,7 +81,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_period_filtered=False, ), LoadItem( - component=M.tech_storage, + component=model.tech_storage, table='Technology', columns=['tech'], where_clause="flag = 'ps'", @@ -90,7 +90,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_period_filtered=False, ), LoadItem( - component=M.tech_seasonal_storage, + component=model.tech_seasonal_storage, table='Technology', columns=['tech'], where_clause="flag = 'ps' AND seas_stor > 0", @@ -99,7 +99,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_period_filtered=False, ), LoadItem( - component=M.tech_reserve, + component=model.tech_reserve, table='Technology', columns=['tech'], where_clause='reserve > 0', @@ -108,7 +108,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_period_filtered=False, ), LoadItem( - component=M.tech_curtailment, + component=model.tech_curtailment, table='Technology', columns=['tech'], where_clause='curtail > 0', @@ -117,7 +117,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_period_filtered=False, ), LoadItem( - component=M.tech_flex, + component=model.tech_flex, table='Technology', columns=['tech'], where_clause='flex > 0', @@ -126,7 +126,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_period_filtered=False, ), LoadItem( - component=M.tech_exchange, + component=model.tech_exchange, table='Technology', columns=['tech'], where_clause='exchange > 0', @@ -135,7 +135,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_period_filtered=False, ), LoadItem( - component=M.tech_annual, + component=model.tech_annual, table='Technology', columns=['tech'], where_clause='annual > 0', @@ -144,7 +144,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_period_filtered=False, ), LoadItem( - component=M.tech_retirement, + component=model.tech_retirement, table='Technology', columns=['tech'], where_clause='retire > 0', @@ -153,14 +153,14 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_period_filtered=False, ), LoadItem( - component=M.tech_group_names, + component=model.tech_group_names, table='TechGroup', columns=['group_name'], is_period_filtered=False, is_table_required=False, ), LoadItem( - component=M.tech_group_members, + component=model.tech_group_members, table='TechGroupMember', columns=['group_name', 'tech'], custom_loader_name='_load_tech_group_members', @@ -168,7 +168,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.commodity_demand, + component=model.commodity_demand, table='Commodity', columns=['name'], where_clause="flag = 'd'", @@ -177,14 +177,14 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_period_filtered=False, ), LoadItem( - component=M.commodity_emissions, + component=model.commodity_emissions, table='Commodity', columns=['name'], where_clause="flag = 'e'", is_period_filtered=False, ), LoadItem( - component=M.commodity_physical, + component=model.commodity_physical, table='Commodity', columns=['name'], where_clause="flag LIKE '%p%' OR flag = 's' OR flag LIKE '%a%'", @@ -193,7 +193,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_period_filtered=False, ), LoadItem( - component=M.commodity_source, + component=model.commodity_source, table='Commodity', columns=['name'], where_clause="flag = 's'", @@ -202,7 +202,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_period_filtered=False, ), LoadItem( - component=M.commodity_annual, + component=model.commodity_annual, table='Commodity', columns=['name'], where_clause="flag LIKE '%a%'", @@ -211,7 +211,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_period_filtered=False, ), LoadItem( - component=M.commodity_waste, + component=model.commodity_waste, table='Commodity', columns=['name'], where_clause="flag LIKE '%w%'", @@ -220,7 +220,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_period_filtered=False, ), LoadItem( - component=M.operator, + component=model.operator, table='Operator', columns=['operator'], is_period_filtered=False, @@ -230,7 +230,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: # Time-Related Components # ========================================================================= LoadItem( - component=M.time_of_day, + component=model.time_of_day, table='TimeOfDay', columns=['tod'], is_period_filtered=False, @@ -238,7 +238,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: fallback_data=[('D',)], ), LoadItem( - component=M.TimeSeason, + component=model.TimeSeason, table='TimeSeason', columns=['period', 'season'], custom_loader_name='_load_time_season', @@ -246,14 +246,14 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.TimeSeasonSequential, + component=model.TimeSeasonSequential, table='TimeSeasonSequential', columns=['period', 'seas_seq', 'season', 'num_days'], custom_loader_name='_load_time_season_sequential', is_table_required=False, ), LoadItem( - component=M.SegFrac, + component=model.SegFrac, table='TimeSegmentFraction', columns=['period', 'season', 'tod', 'segfrac'], custom_loader_name='_load_seg_frac', @@ -263,7 +263,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: # Capacity and Cost Components # ========================================================================= LoadItem( - component=M.ExistingCapacity, + component=model.ExistingCapacity, table='ExistingCapacity', columns=['region', 'tech', 'vintage', 'capacity'], custom_loader_name='_load_existing_capacity', @@ -271,7 +271,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.CostInvest, + component=model.CostInvest, table='CostInvest', columns=['region', 'tech', 'vintage', 'cost'], validator_name='viable_rtv', @@ -281,27 +281,27 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.CostFixed, + component=model.CostFixed, table='CostFixed', columns=['region', 'period', 'tech', 'vintage', 'cost'], validator_name='viable_rtv', validation_map=(0, 2, 3), ), LoadItem( - component=M.CostVariable, + component=model.CostVariable, table='CostVariable', columns=['region', 'period', 'tech', 'vintage', 'cost'], validator_name='viable_rtv', validation_map=(0, 2, 3), ), LoadItem( - component=M.CostEmission, + component=model.CostEmission, table='CostEmission', columns=['region', 'period', 'emis_comm', 'cost'], is_table_required=False, ), LoadItem( - component=M.LoanRate, + component=model.LoanRate, table='LoanRate', columns=['region', 'tech', 'vintage', 'rate'], validator_name='viable_rtv', @@ -314,7 +314,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: # Singleton and Configuration-based Components # ========================================================================= LoadItem( - component=M.DaysPerPeriod, + component=model.DaysPerPeriod, table='MetaData', columns=['value'], where_clause="element == 'days_per_period'", @@ -323,7 +323,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.GlobalDiscountRate, + component=model.GlobalDiscountRate, table='MetaDataReal', columns=['value'], where_clause="element = 'global_discount_rate'", @@ -332,7 +332,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.DefaultLoanRate, + component=model.DefaultLoanRate, table='MetaDataReal', columns=['value'], where_clause="element = 'default_loan_rate'", @@ -344,7 +344,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: # Operational Constraints and Parameters # ========================================================================= LoadItem( - component=M.Efficiency, + component=model.Efficiency, table='meta_efficiency', # Placeholder, custom loader does the work columns=[], custom_loader_name='_load_efficiency', @@ -352,7 +352,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.EfficiencyVariable, + component=model.EfficiencyVariable, table='EfficiencyVariable', columns=[ 'region', @@ -370,16 +370,18 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.Demand, table='Demand', columns=['region', 'period', 'commodity', 'demand'] + component=model.Demand, + table='Demand', + columns=['region', 'period', 'commodity', 'demand'], ), LoadItem( - component=M.DemandSpecificDistribution, + component=model.DemandSpecificDistribution, table='DemandSpecificDistribution', columns=['region', 'period', 'season', 'tod', 'demand_name', 'dsd'], is_table_required=False, ), LoadItem( - component=M.CapacityToActivity, + component=model.CapacityToActivity, table='CapacityToActivity', columns=['region', 'tech', 'c2a'], validator_name='viable_rt', @@ -388,7 +390,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.CapacityFactorTech, + component=model.CapacityFactorTech, table='CapacityFactorTech', columns=['region', 'period', 'season', 'tod', 'tech', 'factor'], validator_name='viable_rt', @@ -396,7 +398,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.CapacityFactorProcess, + component=model.CapacityFactorProcess, table='CapacityFactorProcess', columns=['region', 'period', 'season', 'tod', 'tech', 'vintage', 'factor'], validator_name='viable_rtv', @@ -404,7 +406,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.LifetimeTech, + component=model.LifetimeTech, table='LifetimeTech', columns=['region', 'tech', 'lifetime'], validator_name='viable_rt', @@ -413,7 +415,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.LifetimeProcess, + component=model.LifetimeProcess, table='LifetimeProcess', columns=['region', 'tech', 'vintage', 'lifetime'], validator_name='viable_rtv', @@ -422,7 +424,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.LifetimeSurvivalCurve, + component=model.LifetimeSurvivalCurve, table='LifetimeSurvivalCurve', columns=['region', 'period', 'tech', 'vintage', 'fraction'], validator_name='viable_rtv', @@ -431,7 +433,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.LoanLifetimeProcess, + component=model.LoanLifetimeProcess, table='LoanLifetimeProcess', columns=['region', 'tech', 'vintage', 'lifetime'], validator_name='viable_rtv', @@ -440,7 +442,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.RampUpHourly, + component=model.RampUpHourly, table='RampUpHourly', columns=['region', 'tech', 'rate'], custom_loader_name='_load_ramping_up', @@ -450,7 +452,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.tech_upramping, + component=model.tech_upramping, table='RampUpHourly', columns=['tech'], validator_name='viable_techs', @@ -458,7 +460,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_period_filtered=False, ), LoadItem( - component=M.RampDownHourly, + component=model.RampDownHourly, table='RampDownHourly', columns=['region', 'tech', 'rate'], custom_loader_name='_load_ramping_down', @@ -468,7 +470,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.tech_downramping, + component=model.tech_downramping, table='RampDownHourly', columns=['tech'], validator_name='viable_techs', @@ -476,14 +478,14 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_period_filtered=False, ), LoadItem( - component=M.RenewablePortfolioStandard, + component=model.RenewablePortfolioStandard, table='RPSRequirement', columns=['region', 'period', 'tech_group', 'requirement'], custom_loader_name='_load_rps_requirement', is_table_required=False, ), LoadItem( - component=M.CapacityCredit, + component=model.CapacityCredit, table='CapacityCredit', columns=['region', 'period', 'tech', 'vintage', 'credit'], validator_name='viable_rtv', @@ -491,7 +493,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.ReserveCapacityDerate, + component=model.ReserveCapacityDerate, table='ReserveCapacityDerate', columns=['region', 'period', 'season', 'tech', 'vintage', 'factor'], validator_name='viable_rtv', @@ -499,14 +501,14 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.PlanningReserveMargin, + component=model.PlanningReserveMargin, table='PlanningReserveMargin', columns=['region', 'margin'], is_period_filtered=False, is_table_required=False, ), LoadItem( - component=M.StorageDuration, + component=model.StorageDuration, table='StorageDuration', columns=['region', 'tech', 'duration'], validator_name='viable_rt', @@ -515,7 +517,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.LimitStorageFraction, + component=model.LimitStorageFraction, table='LimitStorageLevelFraction', columns=[ 'region', @@ -532,7 +534,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.EmissionActivity, + component=model.EmissionActivity, table='EmissionActivity', columns=[ 'region', @@ -549,7 +551,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.EmissionEmbodied, + component=model.EmissionEmbodied, table='EmissionEmbodied', columns=['region', 'emis_comm', 'tech', 'vintage', 'value'], validator_name='viable_rtv', @@ -558,7 +560,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.EmissionEndOfLife, + component=model.EmissionEndOfLife, table='EmissionEndOfLife', columns=['region', 'emis_comm', 'tech', 'vintage', 'value'], validator_name='viable_rtv', @@ -567,7 +569,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.ConstructionInput, + component=model.ConstructionInput, table='ConstructionInput', columns=['region', 'input_comm', 'tech', 'vintage', 'value'], validator_name='viable_rtv', @@ -576,7 +578,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.EndOfLifeOutput, + component=model.EndOfLifeOutput, table='EndOfLifeOutput', columns=['region', 'tech', 'vintage', 'output_comm', 'value'], validator_name='viable_rtv', @@ -588,50 +590,50 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: # Limit Constraints # ========================================================================= LoadItem( - component=M.LimitCapacity, + component=model.LimitCapacity, table='LimitCapacity', columns=['region', 'period', 'tech_or_group', 'operator', 'capacity'], is_table_required=False, ), LoadItem( - component=M.LimitNewCapacity, + component=model.LimitNewCapacity, table='LimitNewCapacity', columns=['region', 'period', 'tech_or_group', 'operator', 'new_cap'], is_table_required=False, ), LoadItem( - component=M.LimitCapacityShare, + component=model.LimitCapacityShare, table='LimitCapacityShare', columns=['region', 'period', 'sub_group', 'super_group', 'operator', 'share'], is_table_required=False, ), LoadItem( - component=M.LimitNewCapacityShare, + component=model.LimitNewCapacityShare, table='LimitNewCapacityShare', columns=['region', 'period', 'sub_group', 'super_group', 'operator', 'share'], is_table_required=False, ), LoadItem( - component=M.LimitActivity, + component=model.LimitActivity, table='LimitActivity', columns=['region', 'period', 'tech_or_group', 'operator', 'activity'], is_table_required=False, ), LoadItem( - component=M.LimitActivityShare, + component=model.LimitActivityShare, table='LimitActivityShare', columns=['region', 'period', 'sub_group', 'super_group', 'operator', 'share'], is_table_required=False, ), LoadItem( - component=M.LimitResource, + component=model.LimitResource, table='LimitResource', columns=['region', 'tech_or_group', 'operator', 'cum_act'], is_period_filtered=False, is_table_required=False, ), LoadItem( - component=M.LimitSeasonalCapacityFactor, + component=model.LimitSeasonalCapacityFactor, table='LimitSeasonalCapacityFactor', columns=['region', 'period', 'season', 'tech', 'operator', 'factor'], validator_name='viable_rt', @@ -639,7 +641,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.LimitAnnualCapacityFactor, + component=model.LimitAnnualCapacityFactor, table='LimitAnnualCapacityFactor', columns=['region', 'period', 'tech', 'output_comm', 'operator', 'factor'], validator_name='viable_rpto', @@ -647,13 +649,13 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.LimitEmission, + component=model.LimitEmission, table='LimitEmission', columns=['region', 'period', 'emis_comm', 'operator', 'value'], is_table_required=False, ), LoadItem( - component=M.LimitTechInputSplit, + component=model.LimitTechInputSplit, table='LimitTechInputSplit', columns=['region', 'period', 'input_comm', 'tech', 'operator', 'proportion'], validator_name='viable_rpit', @@ -662,7 +664,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.LimitTechInputSplitAnnual, + component=model.LimitTechInputSplitAnnual, table='LimitTechInputSplitAnnual', columns=['region', 'period', 'input_comm', 'tech', 'operator', 'proportion'], validator_name='viable_rpit', @@ -671,7 +673,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.LimitTechOutputSplit, + component=model.LimitTechOutputSplit, table='LimitTechOutputSplit', columns=['region', 'period', 'tech', 'output_comm', 'operator', 'proportion'], validator_name='viable_rpto', @@ -680,7 +682,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.LimitTechOutputSplitAnnual, + component=model.LimitTechOutputSplitAnnual, table='LimitTechOutputSplitAnnual', columns=['region', 'period', 'tech', 'output_comm', 'operator', 'proportion'], validator_name='viable_rpto', @@ -689,7 +691,7 @@ def build_manifest(M: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=M.LinkedTechs, + component=model.LinkedTechs, table='LinkedTech', columns=['primary_region', 'primary_tech', 'emis_comm', 'driven_tech'], validator_name='viable_rtt', diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index 7382c9910..ca5ec5813 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -85,8 +85,8 @@ def __init__(self, db_connection: Connection, config: TemoaConfig) -> None: self.myopic_index: MyopicIndex | None = None # Build the data loading manifest and a name-based map for quick lookup - M = TemoaModel() - self.manifest = build_manifest(M) + model = TemoaModel() + self.manifest = build_manifest(model) self.manifest_map = {item.component.name: item for item in self.manifest} # --- Data containers and filters populated during loading --- @@ -192,7 +192,7 @@ def create_data_dict(self, myopic_index: MyopicIndex | None = None) -> dict[str, data: dict[str, object] = {} cur = self.con.cursor() - M = TemoaModel() + model = TemoaModel() # Load critical time sets first, as they index other components if myopic_index: @@ -211,8 +211,8 @@ def create_data_dict(self, myopic_index: MyopicIndex | None = None) -> dict[str, raw_future = cur.execute( "SELECT period FROM TimePeriod WHERE flag = 'f' ORDER BY sequence" ).fetchall() - self._load_component_data(data, M.time_exist, raw_exist) - self._load_component_data(data, M.time_future, raw_future) + self._load_component_data(data, model.time_exist, raw_exist) + self._load_component_data(data, model.time_future, raw_future) data['time_optimize'] = [p[0] for p in raw_future[:-1]] # --------------------------------------------------------------------- @@ -256,14 +256,14 @@ def create_data_dict(self, myopic_index: MyopicIndex | None = None) -> dict[str, # Finalization # --------------------------------------------------------------------- # Load simple config-based or myopic-specific values - self._load_component_data(data, M.TimeSequencing, [(self.config.time_sequencing,)]) - self._load_component_data(data, M.ReserveMarginMethod, [(self.config.reserve_margin,)]) + self._load_component_data(data, model.TimeSequencing, [(self.config.time_sequencing,)]) + self._load_component_data(data, model.ReserveMarginMethod, [(self.config.reserve_margin,)]) if myopic_index: p0_result = cur.execute( "SELECT min(period) FROM TimePeriod WHERE flag == 'f'" ).fetchone() if p0_result: - data[M.MyopicDiscountingYear.name] = {None: int(p0_result[0])} + data[model.MyopicDiscountingYear.name] = {None: int(p0_result[0])} # Create derived index sets for parameters now that all base data is loaded set_data = self.load_param_idx_sets(data=data) @@ -490,7 +490,7 @@ def _load_regional_global_indices( """ Aggregates region and group names from the Region table and all Limit tables. """ - M = TemoaModel() + model = TemoaModel() cur = self.con.cursor() regions_and_groups: set[str] = set() @@ -509,7 +509,7 @@ def _load_regional_global_indices( raise ValueError('A table has an empty entry for its region column.') list_of_groups = sorted((t,) for t in regions_and_groups) - self._load_component_data(data, M.regionalGlobalIndices, list_of_groups) + self._load_component_data(data, model.regionalGlobalIndices, list_of_groups) def _load_tech_group_members( self, @@ -518,13 +518,13 @@ def _load_tech_group_members( filtered_data: Sequence[tuple[object, ...]], ) -> None: """Loads members into the indexed set `tech_group_members`.""" - M = TemoaModel() + model = TemoaModel() validator = self.viable_techs.members if self.viable_techs else None for group_name, tech in filtered_data: if validator is None or tech in validator: - store = data.get(M.tech_group_members.name, defaultdict(list)) + store = data.get(model.tech_group_members.name, defaultdict(list)) store[group_name].append(tech) # type: ignore[index] - data[M.tech_group_members.name] = store + data[model.tech_group_members.name] = store # --- Time-Related Components --- def _load_time_season( @@ -537,7 +537,7 @@ def _load_time_season( Loads the indexed TimeSeason set and the simple time_season set, with a dynamic fallback if the table is missing. """ - M = TemoaModel() + model = TemoaModel() mi = self.myopic_index time_optimize = cast(list[int], data.get('time_optimize', [])) @@ -552,16 +552,16 @@ def _load_time_season( rows_to_load = list(raw_data) if not rows_to_load: - data.setdefault(M.time_season.name, []) + data.setdefault(model.time_season.name, []) return unique_seasons = sorted(list({(row[1],) for row in rows_to_load})) - self._load_component_data(data, M.time_season, unique_seasons) + self._load_component_data(data, model.time_season, unique_seasons) for period, season in rows_to_load: - store = data.get(M.TimeSeason.name, defaultdict(list)) + store = data.get(model.TimeSeason.name, defaultdict(list)) store[period].append(season) # type: ignore[index] - data[M.TimeSeason.name] = store + data[model.TimeSeason.name] = store def _load_time_season_sequential( self, @@ -572,13 +572,13 @@ def _load_time_season_sequential( """ Composite loader for TimeSeasonSequential and its associated index sets. """ - M = TemoaModel() - self._load_component_data(data, M.TimeSeasonSequential, filtered_data) + model = TemoaModel() + self._load_component_data(data, model.TimeSeasonSequential, filtered_data) if filtered_data: ordered_data = [row[0:3] for row in filtered_data] - self._load_component_data(data, M.ordered_season_sequential, ordered_data) + self._load_component_data(data, model.ordered_season_sequential, ordered_data) seq_data = sorted({(row[1],) for row in filtered_data}) - self._load_component_data(data, M.time_season_sequential, seq_data) + self._load_component_data(data, model.time_season_sequential, seq_data) def _load_seg_frac( self, @@ -587,14 +587,14 @@ def _load_seg_frac( filtered_data: Sequence[tuple[object, ...]], ) -> None: """Handles dynamic fallbacks for SegFrac if its table is missing.""" - M = TemoaModel() + model = TemoaModel() if filtered_data: - self._load_component_data(data, M.SegFrac, filtered_data) + self._load_component_data(data, model.SegFrac, filtered_data) else: logger.warning('No TimeSegmentFraction table found. Generating default SegFrac values.') time_optimize = data.get('time_optimize', []) fallback = [(p, 'S', 'D', 1.0) for p in time_optimize] # type: ignore[attr-defined] - self._load_component_data(data, M.SegFrac, fallback) + self._load_component_data(data, model.SegFrac, fallback) # --- Capacity and Cost Components --- def _load_existing_capacity( @@ -607,7 +607,7 @@ def _load_existing_capacity( Handles different queries for myopic vs. standard runs and also populates the `tech_exist` set. """ - M = TemoaModel() + model = TemoaModel() cur = self.con.cursor() mi = self.myopic_index @@ -627,10 +627,10 @@ def _load_existing_capacity( 'SELECT region, tech, vintage, capacity FROM ExistingCapacity' ).fetchall() - self._load_component_data(data, M.ExistingCapacity, rows_to_load) + self._load_component_data(data, model.ExistingCapacity, rows_to_load) if rows_to_load: tech_exist_data = sorted(list({(row[1],) for row in rows_to_load})) - self._load_component_data(data, M.tech_exist, tech_exist_data) + self._load_component_data(data, model.tech_exist, tech_exist_data) def _load_cost_invest( self, @@ -639,12 +639,12 @@ def _load_cost_invest( filtered_data: Sequence[tuple[object, ...]], ) -> None: """Handles myopic period filtering for CostInvest.""" - M = TemoaModel() + model = TemoaModel() base_year = self.myopic_index.base_year if self.myopic_index else None data_to_load = [ row for row in filtered_data if base_year is None or cast(int, row[2]) >= base_year ] - self._load_component_data(data, M.CostInvest, data_to_load) + self._load_component_data(data, model.CostInvest, data_to_load) def _load_loan_rate( self, @@ -653,10 +653,10 @@ def _load_loan_rate( filtered_data: Sequence[tuple[object, ...]], ) -> None: """Handles myopic period filtering for LoanRate.""" - M = TemoaModel() + model = TemoaModel() mi = self.myopic_index data_to_load = [row for row in filtered_data if not mi or row[2] >= mi.base_year] # type: ignore[operator] - self._load_component_data(data, M.LoanRate, data_to_load) + self._load_component_data(data, model.LoanRate, data_to_load) # --- Singleton and Configuration-based Components --- def _load_days_per_period( @@ -666,13 +666,13 @@ def _load_days_per_period( filtered_data: Sequence[tuple[object, ...]], ) -> None: """Loads the singleton DaysPerPeriod, with a fallback.""" - M = TemoaModel() + model = TemoaModel() days = 365 if filtered_data: days = cast(int, filtered_data[0][0]) else: logger.info('No value for days_per_period found. Assuming 365 days per period.') - data[M.DaysPerPeriod.name] = {None: days} + data[model.DaysPerPeriod.name] = {None: days} def _load_global_discount_rate( self, @@ -681,9 +681,9 @@ def _load_global_discount_rate( filtered_data: Sequence[tuple[object, ...]], ) -> None: """Loads the required singleton GlobalDiscountRate.""" - M = TemoaModel() + model = TemoaModel() if filtered_data: - data[M.GlobalDiscountRate.name] = {None: cast(float, filtered_data[0][0])} + data[model.GlobalDiscountRate.name] = {None: cast(float, filtered_data[0][0])} else: raise ValueError( "Missing required parameter: 'global_discount_rate' not found in MetaDataReal table." @@ -696,9 +696,9 @@ def _load_default_loan_rate( filtered_data: Sequence[tuple[object, ...]], ) -> None: """Loads the optional singleton DefaultLoanRate.""" - M = TemoaModel() + model = TemoaModel() if filtered_data: - data[M.DefaultLoanRate.name] = {None: cast(float, filtered_data[0][0])} + data[model.DefaultLoanRate.name] = {None: cast(float, filtered_data[0][0])} # --- Operational Constraints and Parameters --- def _load_efficiency( @@ -708,8 +708,8 @@ def _load_efficiency( filtered_data: Sequence[tuple[object, ...]], ) -> None: """Loads the main Efficiency parameter, which is pre-calculated.""" - M = TemoaModel() - self._load_component_data(data, M.Efficiency, self.efficiency_values) + model = TemoaModel() + self._load_component_data(data, model.Efficiency, self.efficiency_values) def _load_linked_techs( self, @@ -740,14 +740,14 @@ def _load_ramping_down( filtered_data: Sequence[tuple[object, ...]], ) -> None: """Composite loader for RampDownHourly and its index set `tech_downramping`.""" - M = TemoaModel() - self._load_component_data(data, M.RampDownHourly, filtered_data) + model = TemoaModel() + self._load_component_data(data, model.RampDownHourly, filtered_data) if filtered_data: tech_data = sorted(list({(row[1],) for row in filtered_data})) tech_filtered = self._filter_data( - tech_data, self.manifest_map[M.tech_downramping.name], use_raw_data=False + tech_data, self.manifest_map[model.tech_downramping.name], use_raw_data=False ) - self._load_component_data(data, M.tech_downramping, tech_filtered) + self._load_component_data(data, model.tech_downramping, tech_filtered) def _load_ramping_up( self, @@ -756,14 +756,14 @@ def _load_ramping_up( filtered_data: Sequence[tuple[object, ...]], ) -> None: """Composite loader for RampUpHourly and its index set `tech_upramping`.""" - M = TemoaModel() - self._load_component_data(data, M.RampUpHourly, filtered_data) + model = TemoaModel() + self._load_component_data(data, model.RampUpHourly, filtered_data) if filtered_data: tech_data = sorted(list({(row[1],) for row in filtered_data})) tech_filtered = self._filter_data( - tech_data, self.manifest_map[M.tech_upramping.name], use_raw_data=False + tech_data, self.manifest_map[model.tech_upramping.name], use_raw_data=False ) - self._load_component_data(data, M.tech_upramping, tech_filtered) + self._load_component_data(data, model.tech_upramping, tech_filtered) def _load_rps_requirement( self, @@ -772,8 +772,8 @@ def _load_rps_requirement( filtered_data: Sequence[tuple[object, ...]], ) -> None: """Handles deprecation warning for RenewablePortfolioStandard.""" - M = TemoaModel() - self._load_component_data(data, M.RenewablePortfolioStandard, filtered_data) + model = TemoaModel() + self._load_component_data(data, model.RenewablePortfolioStandard, filtered_data) if filtered_data: logger.warning( 'The RenewablePortfolioStandard constraint is deprecated. Use LimitActivityShare instead. ' @@ -877,23 +877,23 @@ def load_param_idx_sets(self, data: dict[str, object]) -> dict[str, object]: :param data: The main data dictionary. :return: A dictionary of the new index sets to be added. """ - M = TemoaModel() + model = TemoaModel() param_idx_sets = { - M.CostInvest.name: M.CostInvest_rtv.name, - M.CostEmission.name: M.CostEmission_rpe.name, - M.Demand.name: M.DemandConstraint_rpc.name, - M.LimitEmission.name: M.LimitEmissionConstraint_rpe.name, - M.LimitActivity.name: M.LimitActivityConstraint_rpt.name, - M.LimitSeasonalCapacityFactor.name: M.LimitSeasonalCapacityFactorConstraint_rpst.name, - M.LimitActivityShare.name: M.LimitActivityShareConstraint_rpgg.name, - M.LimitAnnualCapacityFactor.name: M.LimitAnnualCapacityFactorConstraint_rpto.name, - M.LimitCapacity.name: M.LimitCapacityConstraint_rpt.name, - M.LimitCapacityShare.name: M.LimitCapacityShareConstraint_rpgg.name, - M.LimitNewCapacity.name: M.LimitNewCapacityConstraint_rpt.name, - M.LimitNewCapacityShare.name: M.LimitNewCapacityShareConstraint_rpgg.name, - M.LimitResource.name: M.LimitResourceConstraint_rt.name, - M.LimitStorageFraction.name: M.LimitStorageFractionConstraint_rpsdtv.name, - M.RenewablePortfolioStandard.name: M.RenewablePortfolioStandardConstraint_rpg.name, + model.CostInvest.name: model.CostInvest_rtv.name, + model.CostEmission.name: model.CostEmission_rpe.name, + model.Demand.name: model.DemandConstraint_rpc.name, + model.LimitEmission.name: model.LimitEmissionConstraint_rpe.name, + model.LimitActivity.name: model.LimitActivityConstraint_rpt.name, + model.LimitSeasonalCapacityFactor.name: model.LimitSeasonalCapacityFactorConstraint_rpst.name, + model.LimitActivityShare.name: model.LimitActivityShareConstraint_rpgg.name, + model.LimitAnnualCapacityFactor.name: model.LimitAnnualCapacityFactorConstraint_rpto.name, + model.LimitCapacity.name: model.LimitCapacityConstraint_rpt.name, + model.LimitCapacityShare.name: model.LimitCapacityShareConstraint_rpgg.name, + model.LimitNewCapacity.name: model.LimitNewCapacityConstraint_rpt.name, + model.LimitNewCapacityShare.name: model.LimitNewCapacityShareConstraint_rpgg.name, + model.LimitResource.name: model.LimitResourceConstraint_rt.name, + model.LimitStorageFraction.name: model.LimitStorageFractionConstraint_rpsdtv.name, + model.RenewablePortfolioStandard.name: model.RenewablePortfolioStandardConstraint_rpg.name, } res: dict[str, object] = {} From a8b6b772ed3c4b7f222a1e8e43a152cef2e664ab Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 28 Oct 2025 18:34:43 -0400 Subject: [PATCH 281/587] fixing naming in data_processing --- temoa/data_processing/database_util.py | 30 ++-- temoa/data_processing/graphviz_util.py | 10 +- temoa/data_processing/make_graphviz.py | 196 +++++++++++---------- temoa/data_processing/make_output_plots.py | 80 ++++----- 4 files changed, 162 insertions(+), 154 deletions(-) diff --git a/temoa/data_processing/database_util.py b/temoa/data_processing/database_util.py index 3ae3f6381..0fe8a6496 100644 --- a/temoa/data_processing/database_util.py +++ b/temoa/data_processing/database_util.py @@ -31,13 +31,13 @@ class DatabaseUtil: ValueError: If the database path does not exist or if connecting fails. """ - def __init__(self, databasePath, scenario=None): - self.database = os.path.abspath(databasePath) + def __init__(self, database_path, scenario=None): + self.database = os.path.abspath(database_path) self.scenario = scenario if not os.path.exists(self.database): raise ValueError("The database file path doesn't exist") - if self.isDataBaseFile(self.database): + if self.is_database_file(self.database): try: self.con = sqlite3.connect(self.database) self.cur = self.con.cursor() @@ -56,14 +56,14 @@ def close(self): self.con.close() @staticmethod - def isDataBaseFile(file): + def is_database_file(file): if file.endswith('.db') or file.endswith('.sqlite') or file.endswith('.sqlite3'): return True else: return False @deprecated.deprecated('reading from .dat files no longer supported') - def readFromDatFile(self, inp_comm, inp_tech): + def read_from_dat_file(self, inp_comm, inp_tech): if self.cur is not None: raise ValueError('Invalid Operation For Database file') if inp_comm is None and inp_tech is None: @@ -106,7 +106,7 @@ def readFromDatFile(self, inp_comm, inp_tech): ) return result[['input_comm', 'tech', 'output_comm']] - def getTimePeridosForFlags(self, flags=None): + def get_time_peridos_for_flags(self, flags=None): if self.cur is None: raise ValueError('Invalid Operation For dat file') query = '' @@ -125,7 +125,7 @@ def getTimePeridosForFlags(self, flags=None): return result - def getTechnologiesForFlags(self, flags=None): + def get_technologies_for_flags(self, flags=None): if self.cur is None: raise ValueError('Invalid Operation For dat file') query = '' @@ -144,7 +144,7 @@ def getTechnologiesForFlags(self, flags=None): return result # TODO: Merge this with next function (getExistingTechnologiesForCommodity) - def getCommoditiesAndTech(self, inp_comm, inp_tech, region): + def get_commodities_and_tech(self, inp_comm, inp_tech, region): if self.cur is None: raise ValueError('Invalid Operation For dat file') if inp_comm is None and inp_tech is None: @@ -183,7 +183,7 @@ def getCommoditiesAndTech(self, inp_comm, inp_tech, region): ) return pd.DataFrame(self.cur.fetchall(), columns=['input_comm', 'tech', 'output_comm']) - def getExistingTechnologiesForCommodity(self, comm, region, comm_type='input'): + def get_existing_technologies_for_commodity(self, comm, region, comm_type='input'): if self.cur is None: raise ValueError('Invalid Operation For dat file') query = '' @@ -198,7 +198,7 @@ def getExistingTechnologiesForCommodity(self, comm, region, comm_type='input'): result = pd.DataFrame(self.cur.fetchall(), columns=['tech']) return result - def getCommoditiesForFlags(self, flags=None): + def get_commodities_for_flags(self, flags=None): if self.cur is None: raise ValueError('Invalid Operation For dat file') query = '' @@ -217,7 +217,7 @@ def getCommoditiesForFlags(self, flags=None): return result # comm_type can be 'input' or 'output' - def getCommoditiesByTechnology(self, region, comm_type='input'): + def get_commodities_by_technology(self, region, comm_type='input'): if self.cur is None: raise ValueError('Invalid Operation For dat file') query = '' @@ -236,7 +236,7 @@ def getCommoditiesByTechnology(self, region, comm_type='input'): return result - def getCapacityForTechAndPeriod(self, tech=None, period=None, region=None): + def get_capacity_for_tech_and_period(self, tech=None, period=None, region=None): if self.cur is None: raise ValueError('Invalid Operation For dat file') if self.scenario is None or self.scenario == '': @@ -286,7 +286,7 @@ def getCapacityForTechAndPeriod(self, tech=None, period=None, region=None): else: return result.groupby(by='tech').sum().reset_index() - def getOutputFlowForPeriod(self, period, region, comm_type='input', commodity=None): + def get_output_flow_for_period(self, period, region, comm_type='input', commodity=None): if self.cur is None: raise ValueError('Invalid Operation For dat file') if self.scenario is None or self.scenario == '': @@ -332,7 +332,7 @@ def getOutputFlowForPeriod(self, period, region, comm_type='input', commodity=No result = pd.DataFrame(self.cur.fetchall(), columns=columns) return result - def getEmissionsActivityForPeriod(self, period, region): + def get_emissions_activity_for_period(self, period, region): if self.cur is None: raise ValueError('Invalid Operation For dat file') if self.scenario is None or self.scenario == '': @@ -353,7 +353,7 @@ def getEmissionsActivityForPeriod(self, period, region): result = pd.DataFrame(self.cur.fetchall(), columns=['emis_comm', 'tech', 'emis_activity']) return result - def getCommodityWiseInputAndOutputFlow(self, tech, period, region): + def get_commodity_wise_input_and_output_flow(self, tech, period, region): if self.cur is None: raise ValueError('Invalid Operation For dat file') if self.scenario is None or self.scenario == '': diff --git a/temoa/data_processing/graphviz_util.py b/temoa/data_processing/graphviz_util.py index fd6511634..a1ba46dcd 100644 --- a/temoa/data_processing/graphviz_util.py +++ b/temoa/data_processing/graphviz_util.py @@ -1,7 +1,7 @@ import argparse -def processInput(args): +def process_input(args): parser = argparse.ArgumentParser(description='Generate Output Plot') parser.add_argument( '-i', @@ -118,7 +118,7 @@ def processInput(args): return vars(options) -def getColorConfig(grey_flag): +def get_color_config(grey_flag): grey_flag = not (grey_flag) kwargs = dict( tech_color='darkseagreen' if grey_flag else 'black', @@ -161,7 +161,7 @@ def getColorConfig(grey_flag): return kwargs -def _getLen(key): +def _get_len(key): def wrapped(obj): return len(obj[key]) @@ -185,7 +185,7 @@ def create_text_nodes(nodes, indent=1): assert len(nodes) == sum(1 for a, b in nodes) # Step 1: for alignment, get max item length in node list - maxl = max(map(_getLen(0), nodes)) + 2 # account for two extra quotes + maxl = max(map(_get_len(0), nodes)) + 2 # account for two extra quotes # Step 2: prepare a text format based on max node size that pads all # lines with attributes @@ -221,7 +221,7 @@ def create_text_edges(edges, indent=1): # Step 1: for alignment, get max length of items on left and right side of # graph operator token ('->') - maxl, maxr = max(map(_getLen(0), edges)), max(map(_getLen(1), edges)) + maxl, maxr = max(map(_get_len(0), edges)), max(map(_get_len(1), edges)) maxl += 2 # account for additional two quotes maxr += 2 # account for additional two quotes diff --git a/temoa/data_processing/make_graphviz.py b/temoa/data_processing/make_graphviz.py index 262749ba4..658adbf3e 100644 --- a/temoa/data_processing/make_graphviz.py +++ b/temoa/data_processing/make_graphviz.py @@ -9,16 +9,16 @@ results_dot_fmt, tech_results_dot_fmt, ) -from graphviz_util import create_text_edges, create_text_nodes, getColorConfig, processInput +from graphviz_util import create_text_edges, create_text_nodes, get_color_config, process_input class GraphvizDiagramGenerator: - def __init__(self, dbFile, scenario=None, region=None, outDir='.', verbose=1): - self.dbFile = dbFile + def __init__(self, db_file, scenario=None, region=None, out_dir='.', verbose=1): + self.dbFile = db_file self.qName = os.path.splitext(os.path.basename(self.dbFile))[0] self.scenario = scenario self.region = region - self.outDir = outDir + self.outDir = out_dir self.folder = {'results': 'whole_system', 'tech': 'processes', 'comm': 'commodities'} self.verbose = verbose self.colors = {} @@ -26,15 +26,15 @@ def __init__(self, dbFile, scenario=None, region=None, outDir='.', verbose=1): def connect(self): self.dbUtil = DatabaseUtil(self.dbFile, self.scenario) self.logger = open(os.path.join(self.outDir, 'graphviz.log'), 'w') - self.setGraphicOptions(False, False) + self.set_graphic_options(False, False) self.__log__('--------------------------------------') self.__log__('GraphvizDiagramGenerator: connected') if self.scenario: - outDir = self.qName + '_' + self.scenario + '_graphviz' + out_dir = self.qName + '_' + self.scenario + '_graphviz' else: - outDir = self.qName + '_input_graphviz' + out_dir = self.qName + '_input_graphviz' - self.outDir = os.path.join(self.outDir, outDir) + self.outDir = os.path.join(self.outDir, out_dir) if not os.path.exists(self.outDir): os.mkdir(self.outDir) # os.chdir(self.outDir) @@ -51,22 +51,22 @@ def __log__(self, msg): print(msg) self.logger.write(msg + '\n') - def __generateGraph__(self, dotFormat, dotArgs, outputName, outputFormat): - dotArgs.update(self.colors) - with open(outputName + '.dot', 'w') as f: - f.write(dotFormat % dotArgs) + def __generate_graph__(self, dot_format, dot_args, output_name, output_format): + dot_args.update(self.colors) + with open(output_name + '.dot', 'w') as f: + f.write(dot_format % dot_args) cmd = ( 'dot', - '-T' + outputFormat, - '-o' + outputName + '.' + outputFormat, - outputName + '.dot', + '-T' + output_format, + '-o' + output_name + '.' + output_format, + output_name + '.dot', ) call(cmd) - def setGraphicOptions(self, greyFlag=None, splinevar=None): - if greyFlag is not None: - self.greyFlag = greyFlag - self.colors.update(getColorConfig(self.greyFlag)) + def set_graphic_options(self, grey_flag=None, splinevar=None): + if grey_flag is not None: + self.greyFlag = grey_flag + self.colors.update(get_color_config(self.greyFlag)) if splinevar is not None: self.colors['splinevar'] = splinevar self.__log__( @@ -76,36 +76,40 @@ def setGraphicOptions(self, greyFlag=None, splinevar=None): + str(self.colors['splinevar']) ) - def CreateMainResultsDiagram(self, period, region, outputFormat='svg'): + def create_main_results_diagram(self, period, region, output_format='svg'): self.__log__('CreateMainResultsDiagram: started with period = ' + str(period)) if not os.path.exists(os.path.join(self.outDir, self.folder['results'])): os.makedirs(os.path.join(self.outDir, self.folder['results'])) - outputName = os.path.join(self.folder['results'], 'results%s' % period) + output_name = os.path.join(self.folder['results'], 'results%s' % period) if self.region: - outputName += '_' + self.region - outputName = os.path.join(self.outDir, outputName) + output_name += '_' + self.region + output_name = os.path.join(self.outDir, output_name) if self.greyFlag: - outputName += '.grey' + output_name += '.grey' # if (os.path.exists(outputName + '.' + outputFormat)): # self.__log__('CreateMainResultsDiagram: graph already exists at path, returning') # return self.outDir, outputName + '.' + outputFormat - tech_all = self.dbUtil.getTechnologiesForFlags(flags=['r', 'p', 'pb', 'ps']) + tech_all = self.dbUtil.get_technologies_for_flags(flags=['r', 'p', 'pb', 'ps']) - commodity_carrier = self.dbUtil.getCommoditiesForFlags(flags=['d', 'p']) - commodity_emissions = self.dbUtil.getCommoditiesForFlags(flags=['e']) + commodity_carrier = self.dbUtil.get_commodities_for_flags(flags=['d', 'p']) + commodity_emissions = self.dbUtil.get_commodities_for_flags(flags=['e']) - Efficiency_Input = self.dbUtil.getCommoditiesByTechnology(region, comm_type='input') - Efficiency_Output = self.dbUtil.getCommoditiesByTechnology(region, comm_type='output') + efficiency_input = self.dbUtil.get_commodities_by_technology(region, comm_type='input') + efficiency_output = self.dbUtil.get_commodities_by_technology(region, comm_type='output') - V_Cap2 = self.dbUtil.getCapacityForTechAndPeriod(period=period, region=region) + v_cap2 = self.dbUtil.get_capacity_for_tech_and_period(period=period, region=region) - EI2 = self.dbUtil.getOutputFlowForPeriod(period=period, region=region, comm_type='input') - EO2 = self.dbUtil.getOutputFlowForPeriod(period=period, region=region, comm_type='output') + ei_2 = self.dbUtil.get_output_flow_for_period( + period=period, region=region, comm_type='input' + ) + eo_2 = self.dbUtil.get_output_flow_for_period( + period=period, region=region, comm_type='output' + ) - EmiO2 = self.dbUtil.getEmissionsActivityForPeriod(period=period, region=region) + emio_2 = self.dbUtil.get_emissions_activity_for_period(period=period, region=region) self.__log__('CreateMainResultsDiagram: database fetched successfully') @@ -123,20 +127,20 @@ def CreateMainResultsDiagram(self, period, region, outputFormat='svg'): eflowsi, eflowso, dflows = set(), set(), set() # edges usedc, usede = set(), set() # used carriers, used emissions - V_Cap2.index = V_Cap2.tech - for tech in set(tech_all) - set(V_Cap2.tech): + v_cap2.index = v_cap2.tech + for tech in set(tech_all) - set(v_cap2.tech): dtechs.add((tech, None)) - for i in range(len(V_Cap2)): - row = V_Cap2.iloc[i] + for i in range(len(v_cap2)): + row = v_cap2.iloc[i] etechs.add( (row['tech'], tech_attr_fmt % (row['tech'], row['capacity'], row['tech'], period)) ) # etechs.add( (row['tech'], tech_attr_fmt % (row['tech'], row['capacity'], row['tech'], period)) ) udflows = set() - for i in range(len(EI2)): - row = EI2.iloc[i] + for i in range(len(ei_2)): + row = ei_2.iloc[i] if row['input_comm'] != 'ethos': eflowsi.add((row['input_comm'], row['tech'], flow_fmt % row['flow'])) ecarriers.add((row['input_comm'], commodity_fmt % (row['input_comm'], period))) @@ -144,32 +148,32 @@ def CreateMainResultsDiagram(self, period, region, outputFormat='svg'): else: # check to see if this tech is in the unlim_cap set tech = row['tech'] - if tech not in V_Cap2.tech: + if tech not in v_cap2.tech: cap = 99999 else: - cap = V_Cap2.loc[row['tech']].capacity + cap = v_cap2.loc[row['tech']].capacity xnodes.add((row['tech'], tech_attr_fmt % (row['tech'], cap, row['tech'], period))) udflows.add((row['input_comm'], row['tech'])) - for row in set(Efficiency_Input) - udflows: + for row in set(efficiency_input) - udflows: if row[0] != 'ethos': dflows.add((row[0], row[1], None)) else: xnodes.add((row[1], None)) udflows = set() - for i in range(len(EO2)): - row = EO2.iloc[i] + for i in range(len(eo_2)): + row = eo_2.iloc[i] eflowso.add((row['tech'], row['output_comm'], flow_fmt % row['flow'])) ecarriers.add((row['output_comm'], commodity_fmt % (row['output_comm'], period))) usedc.add(row['output_comm']) udflows.add((row['tech'], row['output_comm'])) - for row in set(Efficiency_Output) - udflows: + for row in set(efficiency_output) - udflows: dflows.add((row[0], row[1], None)) - for i in range(len(EmiO2)): - row = EmiO2.iloc[i] + for i in range(len(emio_2)): + row = emio_2.iloc[i] if row['emis_activity'] >= epsilon: eflowso.add((row['tech'], row['emis_comm'], flow_fmt % row['emis_activity'])) eemissions.add((row['emis_comm'], None)) @@ -200,12 +204,14 @@ def CreateMainResultsDiagram(self, period, region, outputFormat='svg'): eflowso=create_text_edges(eflowso, indent=3), ) - self.__generateGraph__(results_dot_fmt, args, outputName, outputFormat) + self.__generate_graph__(results_dot_fmt, args, output_name, output_format) self.__log__('CreateMainResultsDiagram: graph generated, returning') - return self.outDir, outputName + '.' + outputFormat + return self.outDir, output_name + '.' + output_format # Needs some small fixing - cases where no input but output is there. # Check sample graphs - def CreateTechResultsDiagrams(self, period, region, tech, outputFormat='svg'): # tech results + def create_tech_results_diagrams( + self, period, region, tech, output_format='svg' + ): # tech results self.__log__( 'CreateTechResultsDiagrams: started with period = ' + str(period) @@ -216,12 +222,12 @@ def CreateTechResultsDiagrams(self, period, region, tech, outputFormat='svg'): if not os.path.exists(os.path.join(self.outDir, self.folder['tech'])): os.makedirs(os.path.join(self.outDir, self.folder['tech'])) - outputName = os.path.join(self.folder['tech'], f'results_{tech}_{period}') + output_name = os.path.join(self.folder['tech'], f'results_{tech}_{period}') if self.region: - outputName += '_' + self.region - outputName = os.path.join(self.outDir, outputName) + output_name += '_' + self.region + output_name = os.path.join(self.outDir, output_name) if self.greyFlag: - outputName += '.grey' + output_name += '.grey' # if (os.path.exists(outputName + '.' + outputFormat)): # self.__log__('CreateTechResultsDiagrams: graph already exists at path, returning') # return self.outDir, outputName + '.' + outputFormat @@ -233,8 +239,8 @@ def CreateTechResultsDiagrams(self, period, region, tech, outputFormat='svg'): vnode_attr_fmt = "href=\"#\", onclick=\"loadNextGraphvizGraph('%s', '%s', '%s')\"" vnode_attr_fmt += 'label="%s\\nCap: %.2f"' - total_cap = self.dbUtil.getCapacityForTechAndPeriod(tech, period, region) - flows = self.dbUtil.getCommodityWiseInputAndOutputFlow(tech, period, region) + total_cap = self.dbUtil.get_capacity_for_tech_and_period(tech, period, region) + flows = self.dbUtil.get_commodity_wise_input_and_output_flow(tech, period, region) self.__log__('CreateTechResultsDiagrams: database fetched successfully') @@ -271,14 +277,14 @@ def CreateTechResultsDiagrams(self, period, region, tech, outputFormat='svg'): iedges=create_text_edges(iedges, indent=2), oedges=create_text_edges(oedges, indent=2), ) - self.__generateGraph__(tech_results_dot_fmt, args, outputName, outputFormat) + self.__generate_graph__(tech_results_dot_fmt, args, output_name, output_format) else: self.__log__('CreateTechResultsDiagrams: nothing to create') self.__log__('CreateTechResultsDiagrams: graph generated, returning') - return self.outDir, outputName + '.' + outputFormat + return self.outDir, output_name + '.' + output_format - def CreateCommodityPartialResults(self, period, region, comm, outputFormat='svg'): + def create_commodity_partial_results(self, period, region, comm, output_format='svg'): self.__log__( 'CreateCommodityPartialResults: started with period = ' + str(period) @@ -289,27 +295,27 @@ def CreateCommodityPartialResults(self, period, region, comm, outputFormat='svg' if not os.path.exists(os.path.join(self.outDir, self.folder['comm'])): os.makedirs(os.path.join(self.outDir, self.folder['comm'])) - outputName = os.path.join(self.folder['comm'], f'rc_{comm}_{period}') + output_name = os.path.join(self.folder['comm'], f'rc_{comm}_{period}') if self.region: - outputName += '_' + self.region - outputName = os.path.join(self.outDir, outputName) + output_name += '_' + self.region + output_name = os.path.join(self.outDir, output_name) if self.greyFlag: - outputName += '.grey' + output_name += '.grey' # if (os.path.exists(outputName + '.' + outputFormat)): # self.__log__('CreateCommodityPartialResults: graph already exists at path, returning') # return self.outDir, outputName + '.' + outputFormat input_total = set( - self.dbUtil.getExistingTechnologiesForCommodity(comm, region, 'output')['tech'] + self.dbUtil.get_existing_technologies_for_commodity(comm, region, 'output')['tech'] ) output_total = set( - self.dbUtil.getExistingTechnologiesForCommodity(comm, region, 'input')['tech'] + self.dbUtil.get_existing_technologies_for_commodity(comm, region, 'input')['tech'] ) - flow_in = self.dbUtil.getOutputFlowForPeriod(period, region, 'input', comm) + flow_in = self.dbUtil.get_output_flow_for_period(period, region, 'input', comm) otechs = set(flow_in['tech']) - flow_out = self.dbUtil.getOutputFlowForPeriod(period, region, 'output', comm) + flow_out = self.dbUtil.get_output_flow_for_period(period, region, 'output', comm) itechs = set(flow_out['tech']) self.__log__('CreateCommodityPartialResults: database fetched successfully') @@ -356,51 +362,53 @@ def CreateCommodityPartialResults(self, period, region, comm, outputFormat='svg' used_edges=create_text_edges(eedges, indent=2), unused_edges=create_text_edges(dedges, indent=2), ) - self.__generateGraph__(commodity_dot_fmt, args, outputName, outputFormat) + self.__generate_graph__(commodity_dot_fmt, args, output_name, output_format) self.__log__('CreateCommodityPartialResults: graph generated, returning') - return self.outDir, outputName + '.' + outputFormat + return self.outDir, output_name + '.' + output_format # Function for generating the Input Graph - def createCompleteInputGraph(self, region, inp_tech=None, inp_comm=None, outputFormat='svg'): + def create_complete_input_graph( + self, region, inp_tech=None, inp_comm=None, output_format='svg' + ): self.__log__( 'createCompleteInputGraph: started with inp_tech = ' + str(inp_tech) + ' and inp_comm = ' + str(inp_comm) ) - outputName = self.qName + output_name = self.qName if inp_tech: - outputName += '_' + str(inp_tech) + output_name += '_' + str(inp_tech) if not os.path.exists(os.path.join(self.outDir, self.folder['tech'])): os.makedirs(os.path.join(self.outDir, self.folder['tech'])) - outputName = os.path.join(self.folder['tech'], outputName) + output_name = os.path.join(self.folder['tech'], output_name) elif inp_comm: - outputName += '_' + str(inp_comm) + output_name += '_' + str(inp_comm) if not os.path.exists(os.path.join(self.outDir, self.folder['comm'])): os.makedirs(os.path.join(self.outDir, self.folder['comm'])) - outputName = os.path.join(self.folder['comm'], outputName) + output_name = os.path.join(self.folder['comm'], output_name) else: if not os.path.exists(os.path.join(self.outDir, self.folder['results'])): os.makedirs(os.path.join(self.outDir, self.folder['results'])) - outputName = os.path.join(self.folder['results'], outputName) + output_name = os.path.join(self.folder['results'], output_name) if self.region: - outputName += '_' + self.region + output_name += '_' + self.region - outputName = os.path.join(self.outDir, outputName) + output_name = os.path.join(self.outDir, output_name) if self.greyFlag: - outputName += '.grey' + output_name += '.grey' # if (os.path.exists(outputName + '.' + outputFormat)): # self.__log__('createCompleteInputGraph: graph already exists at path, returning') # return self.outDir, outputName + '.' + outputFormat nodes, tech, ltech, to_tech, from_tech = set(), set(), set(), set(), set() - if DatabaseUtil.isDataBaseFile(self.dbFile): - res = self.dbUtil.getCommoditiesAndTech(inp_comm, inp_tech, region) + if DatabaseUtil.is_database_file(self.dbFile): + res = self.dbUtil.get_commodities_and_tech(inp_comm, inp_tech, region) else: - res = self.dbUtil.readFromDatFile(inp_comm, inp_tech) + res = self.dbUtil.read_from_dat_file(inp_comm, inp_tech) self.__log__('createCompleteInputGraph: database fetched successfully') # Create nodes and edges using the data frames from database @@ -426,31 +434,31 @@ def createCompleteInputGraph(self, region, inp_tech=None, inp_comm=None, outputF oedges=''.join('%s;\n\t\t' % x for x in from_tech), snodes=';'.join('"%s"' % x for x in ltech), ) - self.__generateGraph__(quick_run_dot_fmt, args, outputName, outputFormat) + self.__generate_graph__(quick_run_dot_fmt, args, output_name, output_format) self.__log__('createCompleteInputGraph: graph generated, returning') - return self.outDir, outputName + '.' + outputFormat + return self.outDir, output_name + '.' + output_format if __name__ == '__main__': - input = processInput(sys.argv[1:]) - graphGen = GraphvizDiagramGenerator( - input['ifile'], input['scenario_name'], input['region'], outDir=input['res_dir'] + input = process_input(sys.argv[1:]) + graph_gen = GraphvizDiagramGenerator( + input['ifile'], input['scenario_name'], input['region'], out_dir=input['res_dir'] ) - graphGen.connect() - graphGen.setGraphicOptions(greyFlag=input['grey_flag'], splinevar=input['splinevar']) + graph_gen.connect() + graph_gen.set_graphic_options(grey_flag=input['grey_flag'], splinevar=input['splinevar']) if input['scenario_name'] is None: - res = graphGen.createCompleteInputGraph( + res = graph_gen.create_complete_input_graph( input['region'], input['inp_technology'], input['inp_commodity'] ) elif input['inp_technology'] is None and input['inp_commodity'] is None: - res = graphGen.CreateMainResultsDiagram(input['period'], input['region']) + res = graph_gen.create_main_results_diagram(input['period'], input['region']) elif input['inp_commodity'] is None: - res = graphGen.CreateTechResultsDiagrams( + res = graph_gen.create_tech_results_diagrams( input['period'], input['region'], input['inp_technology'] ) elif input['inp_technology'] is None: - res = graphGen.CreateCommodityPartialResults( + res = graph_gen.create_commodity_partial_results( input['period'], input['region'], input['inp_commodity'] ) - graphGen.close() + graph_gen.close() print('Check graph generated at ', res[1], ' and all results at ', res[0]) diff --git a/temoa/data_processing/make_output_plots.py b/temoa/data_processing/make_output_plots.py index 71ff1d937..33db1d53c 100644 --- a/temoa/data_processing/make_output_plots.py +++ b/temoa/data_processing/make_output_plots.py @@ -14,7 +14,7 @@ class OutputPlotGenerator: - def __init__(self, path_to_db, region, scenario, super_categories=False): + def __init__(self, path_to_db, region, scenario, super_categories=False) -> None: self.db_path = os.path.abspath(path_to_db) if region == 'global': self.region = '%' @@ -31,7 +31,7 @@ def __init__(self, path_to_db, region, scenario, super_categories=False): ) # self.extractFromDatabase() - def extractFromDatabase(self, mode): + def extract_from_database(self, mode) -> None: """ Based on the type of the plot being generated, extract data from the corresponding table from database """ @@ -73,11 +73,11 @@ def extractFromDatabase(self, mode): self.tech_categories = [[str(word) for word in t] for t in self.tech_categories] con.close() - def getSectors(self, type): + def get_sectors(self, type): """ Based on the type of the plot being generated, returns a list of sectors available in the database """ - self.extractFromDatabase(type) + self.extract_from_database(type) sectors = set() data = None @@ -96,14 +96,14 @@ def getSectors(self, type): res.insert(0, 'all') return res - def processData(self, inputData, sector, super_categories=False): + def process_data(self, input_data, sector, super_categories=False): """ Processes data for a particular sector to make it ready for plotting purposes """ periods = set() techs = set() - for row in inputData: + for row in input_data: row[0] = str(row[0]) row[1] = int(row[1]) row[2] = str(row[2]) @@ -111,10 +111,10 @@ def processData(self, inputData, sector, super_categories=False): tech_dict = dict(self.tech_categories) if super_categories: - for row in inputData: + for row in input_data: row[2] = tech_dict.get(row[2], row[2]) - for row in inputData: + for row in input_data: if row[0] == sector or sector == 'all': periods.add(row[1]) # Reminder: indexing starts at 0 techs.add(row[2]) @@ -128,7 +128,7 @@ def processData(self, inputData, sector, super_categories=False): if tech == 'None' or tech == '': continue output_values[tech] = [0] * len(periods) # this just creates a blank table - for row in inputData: + for row in input_data: if row[2] == 'None' or row[2] == '': continue if row[0] == sector or sector == 'all': @@ -137,7 +137,7 @@ def processData(self, inputData, sector, super_categories=False): output_values['periods'] = periods return output_values - def handleOutputPath(self, plot_type, sector, super_categories, output_dir): + def handle_output_path(self, plot_type, sector, super_categories, output_dir): outfile = plot_type + '_' + sector # +'_'+str(int(time.time()*1000))+'.png' if super_categories: outfile += '_merged' @@ -152,70 +152,70 @@ def handleOutputPath(self, plot_type, sector, super_categories, output_dir): self.output_file_name = self.output_file_name.replace(' ', '') return outfile2 - def generatePlotForCapacity(self, sector, super_categories=False, output_dir='.'): + def generate_plot_for_capacity(self, sector, super_categories=False, output_dir='.'): """ Generates Plot for Capacity of a given sector """ - outfile2 = self.handleOutputPath('capacity', sector, super_categories, output_dir) + outfile2 = self.handle_output_path('capacity', sector, super_categories, output_dir) if os.path.exists(self.output_file_name): print('not generating new capacity plot') return outfile2 - sectors = self.getSectors(1) + sectors = self.get_sectors(1) if sector not in sectors: return '' - output_values = self.processData(self.capacity_output, sector, super_categories) + output_values = self.process_data(self.capacity_output, sector, super_categories) if self.region == '%': title = 'Capacity Plot for ' + sector + ' across all regions' else: title = 'Capacity Plot for ' + sector + ' sector in region ' + self.region - self.makeStackedBarPlot(output_values, 'Years', 'Capacity ', 'periods', title) + self.make_stacked_bar_plot(output_values, 'Years', 'Capacity ', 'periods', title) return outfile2 - def generatePlotForOutputFlow(self, sector, super_categories=False, output_dir='.'): + def generate_plot_for_output_flow(self, sector, super_categories=False, output_dir='.'): """ Generates Plot for Output Flow of a given sector """ - outfile2 = self.handleOutputPath('flow', sector, super_categories, output_dir) + outfile2 = self.handle_output_path('flow', sector, super_categories, output_dir) if os.path.exists(self.output_file_name): print('not generating new flow plot') return outfile2 - sectors = self.getSectors(2) + sectors = self.get_sectors(2) if sector not in sectors: return '' - output_values = self.processData(self.output_vflow, sector, super_categories) + output_values = self.process_data(self.output_vflow, sector, super_categories) if self.region == '%': title = 'Output Flow Plot for ' + sector + ' across all regions' else: title = 'Output Flow Plot for ' + sector + ' sector in region ' + self.region - self.makeStackedBarPlot(output_values, 'Years', 'Activity ', 'periods', title) + self.make_stacked_bar_plot(output_values, 'Years', 'Activity ', 'periods', title) return outfile2 - def generatePlotForEmissions(self, sector, super_categories=False, output_dir='.'): + def generate_plot_for_emissions(self, sector, super_categories=False, output_dir='.'): """ Generates Plot for Emissions of a given sector """ - outfile2 = self.handleOutputPath('emissions', sector, super_categories, output_dir) + outfile2 = self.handle_output_path('emissions', sector, super_categories, output_dir) if os.path.exists(self.output_file_name): print('not generating new emissions plot') return outfile2 - sectors = self.getSectors(3) + sectors = self.get_sectors(3) if sector not in sectors: return '' - output_values = self.processData(self.output_emissions, sector, super_categories) + output_values = self.process_data(self.output_emissions, sector, super_categories) if self.region == '%': title = 'Emissions Plot for ' + sector + ' across all regions' @@ -239,10 +239,10 @@ def get_random_color(self, pastel_factor=0.5): def color_distance(self, c1, c2): return sum([abs(x[0] - x[1]) for x in zip(c1, c2, strict=False)]) - def get_cmap(self, N): + def get_cmap(self, size): """Returns a function that maps each index in 0, 1, ... N-1 to a distinct RGB color.""" - color_norm = colors.Normalize(vmin=0, vmax=N - 1) + color_norm = colors.Normalize(vmin=0, vmax=size - 1) # More colormaps: https://matplotlib.org/examples/color/colormaps_reference.html scalar_map = cmx.ScalarMappable(norm=color_norm, cmap='viridis') @@ -264,30 +264,30 @@ def generate_new_color(self, existing_colors, pastel_factor=0.5): best_color = color return best_color - def makeStackedBarPlot(self, data, xlabel, ylabel, xvar, title): + def make_stacked_bar_plot(self, data, xlabel, ylabel, xvar, title): random.seed(10) handles = list() xaxis = data[xvar] data.pop('c', 0) data.pop(xvar, 0) - stackedBars = data.keys() - colorMapForBars = dict() + stacked_bars = data.keys() + color_map_for_bars = dict() plt.figure() - cmap = self.get_cmap(len(stackedBars)) - for i in range(0, len(stackedBars)): + cmap = self.get_cmap(len(stacked_bars)) + for i in range(0, len(stacked_bars)): # colors.append(self.generate_new_color(colors,pastel_factor = 0.9)) # colorMapForBars[data.keys()[i]]=colors[i] - colorMapForBars[list(data.keys())[i]] = cmap(i) + color_map_for_bars[list(data.keys())[i]] = cmap(i) width = min([xaxis[i + 1] - xaxis[i] for i in range(0, len(xaxis) - 1)]) / 2.0 b = [0] * len(xaxis) # plt.figure() - for bar in stackedBars: - h = plt.bar(xaxis, data[bar], width, bottom=b, color=colorMapForBars[bar]) + for bar in stacked_bars: + h = plt.bar(xaxis, data[bar], width, bottom=b, color=color_map_for_bars[bar]) handles.append(h) b = [b[j] + data[bar][j] for j in range(0, len(b))] @@ -297,7 +297,7 @@ def makeStackedBarPlot(self, data, xlabel, ylabel, xvar, title): plt.xticks([i for i in xaxis], [str(i) for i in xaxis]) plt.title(title) lgd = plt.legend( - [h[0] for h in handles], stackedBars, bbox_to_anchor=(1.2, 1), fontsize=7.5 + [h[0] for h in handles], stacked_bars, bbox_to_anchor=(1.2, 1), fontsize=7.5 ) # plt.show() plt.savefig(self.output_file_name, bbox_extra_artists=(lgd,), bbox_inches='tight') @@ -332,7 +332,7 @@ def make_line_plot(self, plot_var, label, title): # Function used for command line purposes. Parses arguments and then calls relevent functions. -def GeneratePlot(args): +def generate_plot(args): parser = argparse.ArgumentParser(description='Generate Output Plot') parser.add_argument( '-i', @@ -398,15 +398,15 @@ def GeneratePlot(args): ) error = '' if options.type == 'capacity': - error = result.generatePlotForCapacity( + error = result.generate_plot_for_capacity( options.sector, options.super_categories, options.output_dir ) elif options.type == 'flow': - error = result.generatePlotForOutputFlow( + error = result.generate_plot_for_output_flow( options.sector, options.super_categories, options.output_dir ) elif options.type == 'emissions': - error = result.generatePlotForEmissions( + error = result.generate_plot_for_emissions( options.sector, options.super_categories, options.output_dir ) @@ -420,4 +420,4 @@ def GeneratePlot(args): if __name__ == '__main__': - GeneratePlot(sys.argv[1:]) + generate_plot(sys.argv[1:]) From 7d09341de416f6eb30ad0893469dc0e00874ca2d Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 28 Oct 2025 18:41:52 -0400 Subject: [PATCH 282/587] fixing naming in model_checking --- temoa/core/model.py | 8 +- temoa/model_checking/network_model_data.py | 18 +- temoa/model_checking/pricing_check.py | 55 ++++--- temoa/model_checking/validators.py | 183 ++++++++++----------- tests/test_validators.py | 2 +- 5 files changed, 129 insertions(+), 137 deletions(-) diff --git a/temoa/core/model.py b/temoa/core/model.py index 847a2a279..9fa36b3a9 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -51,9 +51,9 @@ region_check, region_group_check, validate_0to1, - validate_Efficiency, + validate_efficiency, validate_linked_tech, - validate_ReserveMargin, + validate_reserve_margin, validate_tech_sets, ) @@ -385,7 +385,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.vintage_all, self.commodity_carrier, within=NonNegativeReals, - validate=validate_Efficiency, + validate=validate_efficiency, ) self.validate_UsedEfficiencyIndices = BuildAction(rule=technology.check_efficiency_indices) @@ -977,7 +977,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: ) self.ReserveMargin_rpsd = Set(dimen=4, initialize=reserves.reserve_margin_indices) - self.validate_ReserveMargin = BuildAction(rule=validate_ReserveMargin) + self.validate_ReserveMargin = BuildAction(rule=validate_reserve_margin) self.ReserveMarginConstraint = Constraint( self.ReserveMargin_rpsd, rule=reserves.reserve_margin_constraint ) diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index 7b859fd7f..fd8242979 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -155,30 +155,32 @@ def _get_builder(data: ModelBlock | DbConnection) -> Callable[..., NetworkModelD # --- Builder Implementations --- @deprecated.deprecated('no longer supported... build from db connection instead') -def _build_from_model(M: TemoaModel, myopic_index: MyopicIndex | None = None) -> NetworkModelData: +def _build_from_model( + model: TemoaModel, myopic_index: MyopicIndex | None = None +) -> NetworkModelData: """Build a NetworkModelData from a TemoaModel.""" if myopic_index is not None: raise NotImplementedError('Cannot build network data from model using a MyopicIndex') dem_com = defaultdict(set) - for r, p, d in M.Demand.sparse_iterkeys(): + for r, p, d in model.Demand.sparse_iterkeys(): dem_com[r, p].add(d) techs: defaultdict[tuple[Region, Period], set[EdgeTuple]] = defaultdict(set) - if M.activeFlow_rpsditvo is not None: - for r, p, _s, _d, ic, tech, v, oc in M.activeFlow_rpsditvo: + if model.activeFlow_rpsditvo is not None: + for r, p, _s, _d, ic, tech, v, oc in model.activeFlow_rpsditvo: techs[r, p].add(EdgeTuple(r, ic, tech, v, oc)) - if M.activeFlow_rpitvo is not None: - for r, p, ic, tech, v, oc in M.activeFlow_rpitvo: + if model.activeFlow_rpitvo is not None: + for r, p, ic, tech, v, oc in model.activeFlow_rpitvo: techs[r, p].add(EdgeTuple(r, ic, tech, v, oc)) linked_techs = { LinkedTechTuple(r, driver, emission, driven) - for r, driver, emission, driven in M.LinkedTechs.sparse_iterkeys() + for r, driver, emission, driven in model.LinkedTechs.sparse_iterkeys() } res = NetworkModelData( - physical_commodities=set(M.commodity_all), + physical_commodities=set(model.commodity_all), demand_commodities=dem_com, available_techs=techs, available_linked_techs=linked_techs, diff --git a/temoa/model_checking/pricing_check.py b/temoa/model_checking/pricing_check.py index 040a2ef27..7ccc71553 100644 --- a/temoa/model_checking/pricing_check.py +++ b/temoa/model_checking/pricing_check.py @@ -16,6 +16,8 @@ but do not extend through all years in the tech_lifetime """ +from __future__ import annotations + from collections import defaultdict from logging import getLogger from typing import TYPE_CHECKING @@ -28,20 +30,21 @@ logger = getLogger(__name__) -def price_checker(M: 'TemoaModel') -> bool: +def price_checker(model: TemoaModel) -> bool: """ Check the cost data for common errors :param M: :return: True if "clean" (no warnings), else False """ - logger.info('Started price checking model: %s', M.name) + logger.info('Started price checking model: %s', model.name) warnings = False # flag # some sets for x-checking registered_inv_costs = { - (region, tech, vintage) for (region, tech, vintage) in M.CostInvest.sparse_iterkeys() + (region, tech, vintage) for (region, tech, vintage) in model.CostInvest.sparse_iterkeys() } efficiency_rtv = { - (region, tech, vintage) for (region, _, tech, vintage, __) in M.Efficiency.sparse_iterkeys() + (region, tech, vintage) + for (region, _, tech, vintage, __) in model.Efficiency.sparse_iterkeys() } sorted_efficiency_rtv = sorted(efficiency_rtv, key=lambda rtv: (rtv[1], rtv[0], rtv[2])) @@ -55,11 +58,11 @@ def price_checker(M: 'TemoaModel') -> bool: # var costs for the period = vintage year base_year_variable_cost_rtv = set() - for r, p, t, v in M.CostFixed.sparse_iterkeys(): + for r, p, t, v in model.CostFixed.sparse_iterkeys(): fixed_costs[r, t, v].add(p) if p == v: base_year_fixed_cost_rtv.add((r, t, v)) - for r, p, t, v in M.CostVariable.sparse_iterkeys(): + for r, p, t, v in model.CostVariable.sparse_iterkeys(): var_costs[r, t, v].add(p) if p == v: base_year_variable_cost_rtv.add((r, t, v)) @@ -83,11 +86,11 @@ def price_checker(M: 'TemoaModel') -> bool: # pull the details... for region, tech, vintage in sorted_efficiency_rtv: # disregard "unrestricted capacity" technologies that should NOT have a fixed/invest cost - if tech in M.tech_uncap: + if tech in model.tech_uncap: continue # disregard vintages that are not in the optimization period, their capacity decisions # are already made and the lack of fixed/invest cost is non-impactful - if vintage not in M.time_optimize: + if vintage not in model.time_optimize: continue has_fc = (region, tech, vintage) in fixed_costs @@ -111,7 +114,7 @@ def price_checker(M: 'TemoaModel') -> bool: if missing_fc: missing_techs = defaultdict(set) for r, t, v in missing_fc: - if v in M.time_optimize: + if v in model.time_optimize: missing_techs[t].add((r, v)) for t in missing_techs: # get set of fixed cost for all {rtv} if the tech matches @@ -127,7 +130,7 @@ def price_checker(M: 'TemoaModel') -> bool: err += f' ({r}, {v})\n' err += ' available (r, v):\n' for r, tt, v in comparable_fc: - err += f' ({r}, {v}): {M.CostFixed[r, v, tt, v]}\n' + err += f' ({r}, {v}): {model.CostFixed[r, v, tt, v]}\n' if err: logger.warning(err) warnings = True @@ -139,7 +142,7 @@ def price_checker(M: 'TemoaModel') -> bool: if missing_ic: missing_techs = defaultdict(set) for r, t, v in missing_ic: - if v in M.time_optimize: + if v in model.time_optimize: missing_techs[t].add((r, v)) for t in missing_techs: compaprable_ic = sorted(filter(lambda x: x[1] == t, registered_inv_costs)) @@ -153,7 +156,7 @@ def price_checker(M: 'TemoaModel') -> bool: err += f' ({r}, {v})\n' err += ' available (r, v):\n' for r, tt, v in compaprable_ic: - err += f' ({r}, {v}): {M.CostInvest[r, tt, v]}\n' + err += f' ({r}, {v}): {model.CostInvest[r, tt, v]}\n' if err: logger.warning(err) warnings = True @@ -206,9 +209,9 @@ def price_checker(M: 'TemoaModel') -> bool: # continue # get the lifetime of the tech, or default - lifetime = value(M.LifetimeProcess[region, tech, vintage]) + lifetime = value(model.LifetimeProcess[region, tech, vintage]) # get all applicable future periods that should be priced for this item - expected_periods = {p for p in M.time_optimize if vintage <= p < vintage + lifetime} + expected_periods = {p for p in model.time_optimize if vintage <= p < vintage + lifetime} missing_fixed_costs = ( expected_periods - fixed_costs[region, tech, vintage] if fixed_costs[region, tech, vintage] @@ -243,13 +246,13 @@ def price_checker(M: 'TemoaModel') -> bool: ) warnings = True # continue by checking the uncap techs... - warnings &= check_tech_uncap(M) + warnings &= check_tech_uncap(model) logger.info('Finished Price Checking Build Action') return not warnings -def check_tech_uncap(M: 'TemoaModel') -> bool: +def check_tech_uncap(model: TemoaModel) -> bool: """ Check that the tech_uncap set members... 1. do not have fixed or invest costs @@ -259,16 +262,16 @@ def check_tech_uncap(M: 'TemoaModel') -> bool: :param M: :return: True if "clean" (no warnings), else False """ - if len(M.tech_uncap) == 0: + if len(model.tech_uncap) == 0: return True logger.debug('starting price check #4: uncapacitated techs') efficiency_rtv = { (region, tech, vintage) - for (region, _, tech, vintage, __) in M.Efficiency.sparse_iterkeys() - if tech in M.tech_uncap + for (region, _, tech, vintage, __) in model.Efficiency.sparse_iterkeys() + if tech in model.tech_uncap } - fixed_cost_periods = {(r, t, v): p for r, p, t, v in M.CostFixed.sparse_iterkeys()} + fixed_cost_periods = {(r, t, v): p for r, p, t, v in model.CostFixed.sparse_iterkeys()} rtv_with_fixed_cost = efficiency_rtv & set(fixed_cost_periods.keys()) if rtv_with_fixed_cost: logger.error( @@ -277,7 +280,7 @@ def check_tech_uncap(M: 'TemoaModel') -> bool: for rtv in rtv_with_fixed_cost: logger.error('%s: %s', rtv, fixed_cost_periods[rtv]) - rtv_with_invest_cost = efficiency_rtv & set(M.CostInvest.sparse_iterkeys()) + rtv_with_invest_cost = efficiency_rtv & set(model.CostInvest.sparse_iterkeys()) if rtv_with_invest_cost: logger.error( 'The following technologies are labeled as unlimited capacity, but have an INVEST cost' @@ -287,14 +290,14 @@ def check_tech_uncap(M: 'TemoaModel') -> bool: var_cost_periods = defaultdict(set) # by starting from the cost side, we will naturally omit anything with NO var costs at all. - for r, p, t, v in M.CostVariable.sparse_iterkeys(): + for r, p, t, v in model.CostVariable.sparse_iterkeys(): if (r, t, v) in efficiency_rtv: var_cost_periods[(r, t, v)].add(p) # use it to check for all/none var costs in viable periods - all_periods = M.time_optimize + all_periods = model.time_optimize bad_var_costs = False for r, t, v in var_cost_periods: - lifetime = M.LifetimeProcess[r, t, v] + lifetime = model.LifetimeProcess[r, t, v] expected_periods = {p for p in all_periods if v <= p < v + lifetime} missing_periods = expected_periods - var_cost_periods[r, t, v] if missing_periods: @@ -315,10 +318,10 @@ def check_tech_uncap(M: 'TemoaModel') -> bool: extra_periods, ) - capacity_params = (M.ExistingCapacity,) + capacity_params = (model.ExistingCapacity,) bad_cap_entries = False for param in capacity_params: - bad_entries = {(r, t, v) for r, t, v in param.sparse_iterkeys() if t in M.tech_uncap} + bad_entries = {(r, t, v) for r, t, v in param.sparse_iterkeys() if t in model.tech_uncap} if bad_entries: for entry in bad_entries: logger.error( diff --git a/temoa/model_checking/validators.py b/temoa/model_checking/validators.py index 59d4979e2..0277dad50 100644 --- a/temoa/model_checking/validators.py +++ b/temoa/model_checking/validators.py @@ -1,31 +1,10 @@ """ These "validators" are used as validation tools for several elements in the TemoaModel -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 9/27/23 - -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . """ +from __future__ import annotations + import re from logging import getLogger from typing import TYPE_CHECKING @@ -50,14 +29,14 @@ 'region_check', 'region_group_check', 'validate_0to1', - 'validate_Efficiency', + 'validate_efficiency', 'validate_linked_tech', - 'validate_ReserveMargin', + 'validate_reserve_margin', 'validate_tech_sets', ] -def validate_linked_tech(M: 'TemoaModel') -> bool: +def validate_linked_tech(model: TemoaModel) -> bool: """ A validation that for all the linked techs, they have the same lifetime in each possible vintage @@ -74,17 +53,17 @@ def validate_linked_tech(M: 'TemoaModel') -> bool: """ logger.debug('Starting to validate linked techs.') - base_idx = M.LinkedEmissionsTechConstraint_rpsdtve + base_idx = model.LinkedEmissionsTechConstraint_rpsdtve drivers = {(r, t, v, e) for r, p, s, d, t, v, e in base_idx} for r, t_driver, v, e in drivers: # get the linked tech of same region, emission - t_driven = M.LinkedTechs[r, t_driver, e] + t_driven = model.LinkedTechs[r, t_driver, e] # check for equality in lifetimes for vintage v - driver_lifetime = M.LifetimeProcess[r, t_driver, v] + driver_lifetime = model.LifetimeProcess[r, t_driver, v] try: - driven_lifetime = M.LifetimeProcess[r, t_driven, v] + driven_lifetime = model.LifetimeProcess[r, t_driven, v] except KeyError: logger.error( 'Linked Tech Error: Driven tech %s does not have a vintage entry %d to match driver %s', @@ -109,7 +88,7 @@ def validate_linked_tech(M: 'TemoaModel') -> bool: return True -def no_slash_or_pipe(M: 'TemoaModel', element: object) -> bool: +def no_slash_or_pipe(model: TemoaModel, element: object) -> bool: """ No slash character in element :param M: @@ -125,7 +104,7 @@ def no_slash_or_pipe(M: 'TemoaModel', element: object) -> bool: return True -def region_check(M: 'TemoaModel', region: Region) -> bool: +def region_check(model: TemoaModel, region: Region) -> bool: """ Validate the region name (letters + numbers only + underscore) """ @@ -142,7 +121,7 @@ def region_check(M: 'TemoaModel', region: Region) -> bool: return False -def linked_region_check(M: 'TemoaModel', region_pair: str) -> bool: +def linked_region_check(model: TemoaModel, region_pair: str) -> bool: """ Validate a pair of regions (r-r format where r ∈ M.R ) """ @@ -151,34 +130,34 @@ def linked_region_check(M: 'TemoaModel', region_pair: str) -> bool: r1 = linked_regions.group(1) r2 = linked_regions.group(2) if ( - all(r in M.regions for r in (r1, r2)) and r1 != r2 + all(r in model.regions for r in (r1, r2)) and r1 != r2 ): # both captured regions are in the set of M.R return True return False -def region_group_check(M: 'TemoaModel', rg: str) -> bool: +def region_group_check(model: TemoaModel, rg: str) -> bool: """ Validate the region-group name (region or regions separated by '+') """ if '-' in rg: # it should just be evaluated as a linked_region - return linked_region_check(M, rg) + return linked_region_check(model, rg) if re.search(r'\A[a-zA-Z0-9\+_]+\Z', rg): # it has legal characters only if '+' in rg: # break up the group contained_regions = rg.strip().split('+') - if all(t in M.regions for t in contained_regions) and len( + if all(t in model.regions for t in contained_regions) and len( set(contained_regions) ) == len(contained_regions): # no dupes return True else: # it is a singleton - return (rg in M.regions) or rg == 'global' + return (rg in model.regions) or rg == 'global' return False @deprecated.deprecated('needs to be updated if re-instated to accommodate group restructuring') -def tech_groups_set_check(M: 'TemoaModel', rg: str, g: str, t: str) -> bool: +def tech_groups_set_check(model: TemoaModel, rg: str, g: str, t: str) -> bool: """ Validate this entry to the tech_groups set :param M: the model @@ -187,7 +166,7 @@ def tech_groups_set_check(M: 'TemoaModel', rg: str, g: str, t: str) -> bool: :param t: tech :return: True if valid entry, else False """ - return all((region_group_check(M, rg), g in M.tech_group_names, t in M.tech_all)) + return all((region_group_check(model, rg), g in model.tech_group_names, t in model.tech_all)) # TODO: Several of these param checkers below are not in use because the params cannot @@ -196,7 +175,7 @@ def tech_groups_set_check(M: 'TemoaModel', rg: str, g: str, t: str) -> bool: # the buildAction approach -def activity_param_check(M: 'TemoaModel', val: float, rg: str, p: Period, t: Technology) -> bool: +def activity_param_check(model: TemoaModel, val: float, rg: str, p: Period, t: Technology) -> bool: """ Validate the index and the value for an entry into an activity param indexed with region-groups :param M: the model @@ -209,15 +188,15 @@ def activity_param_check(M: 'TemoaModel', val: float, rg: str, p: Period, t: Tec return all( ( val in NonNegativeReals, # the value should be in this set - region_group_check(M, rg), - p in M.time_optimize, - t in M.tech_all, + region_group_check(model, rg), + p in model.time_optimize, + t in model.tech_all, ) ) def capacity_param_check( - M: 'TemoaModel', val: float, rg: str, p: Period, t: Technology, carrier: Commodity + model: TemoaModel, val: float, rg: str, p: Period, t: Technology, carrier: Commodity ) -> bool: """ validate entries to capacity params @@ -232,15 +211,15 @@ def capacity_param_check( return all( ( val in NonNegativeReals, - region_group_check(M, rg), - p in M.time_optimize, - t in M.tech_all, - carrier in M.commodity_carrier, + region_group_check(model, rg), + p in model.time_optimize, + t in model.tech_all, + carrier in model.commodity_carrier, ) ) -def activity_group_param_check(M: 'TemoaModel', val: float, rg: str, p: Period, g: str) -> bool: +def activity_group_param_check(model: TemoaModel, val: float, rg: str, p: Period, g: str) -> bool: """ validate entries into capacity groups :param M: the model @@ -253,15 +232,15 @@ def activity_group_param_check(M: 'TemoaModel', val: float, rg: str, p: Period, return all( ( val in NonNegativeReals, - region_group_check(M, rg), - p in M.time_optimize, - g in M.tech_group_names, + region_group_check(model, rg), + p in model.time_optimize, + g in model.tech_group_names, ) ) def emission_limit_param_check( - M: 'TemoaModel', val: float, rg: str, p: Period, e: Commodity + model: TemoaModel, val: float, rg: str, p: Period, e: Commodity ) -> bool: """ validate entries into EmissionLimit param @@ -272,11 +251,13 @@ def emission_limit_param_check( :param e: commodity emission :return: True if all OK """ - return all((region_group_check(M, rg), p in M.time_optimize, e in M.commodity_emissions)) + return all( + (region_group_check(model, rg), p in model.time_optimize, e in model.commodity_emissions) + ) -def validate_CapacityFactorProcess( - M: 'TemoaModel', +def validate_capacity_factor_process( + model: TemoaModel, val: float, r: Region, p: Period, @@ -301,19 +282,25 @@ def validate_CapacityFactorProcess( # Doesn't seem worth the compute time return all( ( - r in M.regions, - p in M.time_optimize, - s in M.TimeSeason[p], - d in M.time_of_day, - t in M.tech_with_capacity, - v in M.vintage_all, + r in model.regions, + p in model.time_optimize, + s in model.TimeSeason[p], + d in model.time_of_day, + t in model.tech_with_capacity, + v in model.vintage_all, 0 <= val <= 1.0, ) ) -def validate_Efficiency( - M: 'TemoaModel', val: float, r: Region, si: Commodity, t: Technology, v: Vintage, so: Commodity +def validate_efficiency( + model: TemoaModel, + val: float, + r: Region, + si: Commodity, + t: Technology, + v: Vintage, + so: Commodity, ) -> bool: """Handy for troubleshooting problematic entries""" @@ -321,46 +308,46 @@ def validate_Efficiency( ( isinstance(val, float), val > 0, - r in M.regionalIndices, - si in M.commodity_physical, - t in M.tech_all, - so in M.commodity_carrier, - v in M.vintage_all, + r in model.regionalIndices, + si in model.commodity_physical, + t in model.tech_all, + so in model.commodity_carrier, + v in model.vintage_all, ) ): return True print('Element Validations:') - print('region', r in M.regionalIndices) - print('input_commodity', si in M.commodity_physical) - print('tech', t in M.tech_all) - print('vintage', v in M.vintage_all) - print('output_commodity', so in M.commodity_carrier) + print('region', r in model.regionalIndices) + print('input_commodity', si in model.commodity_physical) + print('tech', t in model.tech_all) + print('vintage', v in model.vintage_all) + print('output_commodity', so in model.commodity_carrier) return False -def validate_ReserveMargin(M: 'TemoaModel') -> None: - for r in M.PlanningReserveMargin.sparse_iterkeys(): - if all((r, p) not in M.processReservePeriods for p in M.time_optimize): +def validate_reserve_margin(model: TemoaModel) -> None: + for r in model.PlanningReserveMargin.sparse_iterkeys(): + if all((r, p) not in model.processReservePeriods for p in model.time_optimize): logger.warning( 'Planning reserve margin provided but there are no reserve ' - f'technologies serving this region: {r, M.PlanningReserveMargin[r]}' + f'technologies serving this region: {r, model.PlanningReserveMargin[r]}' ) -def validate_tech_sets(M: 'TemoaModel') -> None: +def validate_tech_sets(model: TemoaModel) -> None: """ Check tech sets for any forbidden intersections """ if not all( ( - check_no_intersection(M.tech_annual, M.tech_baseload), - check_no_intersection(M.tech_annual, M.tech_storage), - check_no_intersection(M.tech_annual, M.tech_upramping), - check_no_intersection(M.tech_annual, M.tech_downramping), - check_no_intersection(M.tech_annual, M.tech_curtailment), - check_no_intersection(M.tech_curtailment, M.tech_flex), - check_no_intersection(M.tech_all, M.tech_group_names), - check_no_intersection(M.tech_uncap, M.tech_reserve), + check_no_intersection(model.tech_annual, model.tech_baseload), + check_no_intersection(model.tech_annual, model.tech_storage), + check_no_intersection(model.tech_annual, model.tech_upramping), + check_no_intersection(model.tech_annual, model.tech_downramping), + check_no_intersection(model.tech_annual, model.tech_curtailment), + check_no_intersection(model.tech_curtailment, model.tech_flex), + check_no_intersection(model.tech_all, model.tech_group_names), + check_no_intersection(model.tech_uncap, model.tech_reserve), ) ): raise ValueError('Technology sets failed to validate. Check log file for details.') @@ -377,23 +364,23 @@ def check_no_intersection(set_one: Set, set_two: Set) -> bool: # Seems unused def validate_tech_split( - M: 'TemoaModel', val: float, r: Region, p: Period, c: Commodity, t: Technology + model: TemoaModel, val: float, r: Region, p: Period, c: Commodity, t: Technology ) -> bool: if all( ( - r in M.regions, - p in M.time_optimize, - c in M.commodity_physical, - t in M.tech_all, + r in model.regions, + p in model.time_optimize, + c in model.commodity_physical, + t in model.tech_all, ) ): return True - print('r', r in M.regions) - print('p', p in M.time_optimize) - print('c', c in M.commodity_physical) - print('t', t in M.tech_all) + print('r', r in model.regions) + print('p', p in model.time_optimize) + print('c', c in model.commodity_physical) + print('t', t in model.tech_all) return False -def validate_0to1(M: 'TemoaModel', val: float, *args: object) -> bool: +def validate_0to1(model: TemoaModel, val: float, *args: object) -> bool: return 0.0 <= val <= 1.0 diff --git a/tests/test_validators.py b/tests/test_validators.py index e8c17da42..9e41e8eac 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -108,4 +108,4 @@ def test_region_group_check(): @pytest.mark.parametrize('value, expected', params) def test_no_slash(value, expected): - assert no_slash_or_pipe(M=None, element=value) == expected + assert no_slash_or_pipe(model=None, element=value) == expected From 8703ad90140de0db5c91c97618c4f22e8b4ef818 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 29 Oct 2025 09:18:52 -0400 Subject: [PATCH 283/587] fixing non model_type naming in types --- temoa/core/model.py | 1 - temoa/types/dict_types.py | 107 +++++++++++------------------------- temoa/types/model_types.py | 20 +++---- temoa/types/set_types.py | 42 +++++--------- temoa/types/solver_types.py | 20 +++---- 5 files changed, 65 insertions(+), 125 deletions(-) diff --git a/temoa/core/model.py b/temoa/core/model.py index 9fa36b3a9..1ca4d698d 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -110,7 +110,6 @@ def __init__(self, *args: object, **kwargs: object) -> None: # (not formal model elements) # ################################################ - # Dev Note: The triple-quotes UNDER the items below pop up as dox in most IDEs self.processInputs: t.ProcessInputsDict = {} self.processOutputs: t.ProcessOutputsDict = {} self.processLoans: t.ProcessLoansDict = {} diff --git a/temoa/types/dict_types.py b/temoa/types/dict_types.py index d725e14d0..8fb2fb3da 100644 --- a/temoa/types/dict_types.py +++ b/temoa/types/dict_types.py @@ -8,106 +8,65 @@ from .core_types import Commodity, Period, Region, Season, Technology, TimeOfDay, Vintage # Process-related dictionary types -ProcessInputsdict = dict[tuple[Region, Period, Technology, Vintage], set[Commodity]] -ProcessOutputsdict = dict[tuple[Region, Period, Technology, Vintage], set[Commodity]] -ProcessLoansdict = dict[tuple[Region, Technology, Vintage], float] -ProcessInputsByOutputdict = dict[ +ProcessInputsDict = dict[tuple[Region, Period, Technology, Vintage], set[Commodity]] +ProcessOutputsDict = dict[tuple[Region, Period, Technology, Vintage], set[Commodity]] +ProcessLoansDict = dict[tuple[Region, Technology, Vintage], float] +ProcessInputsByOutputDict = dict[ tuple[Region, Period, Technology, Vintage, Commodity], set[Commodity] ] -ProcessOutputsByInputdict = dict[ +ProcessOutputsByInputDict = dict[ tuple[Region, Period, Technology, Vintage, Commodity], set[Commodity] ] -ProcessTechsdict = dict[tuple[Region, Period, Commodity], set[Technology]] -ProcessReservePeriodsdict = dict[tuple[Region, Period], set[tuple[Technology, Vintage]]] -ProcessPeriodsdict = dict[tuple[Region, Technology, Vintage], set[Period]] -RetirementPeriodsdict = dict[tuple[Region, Technology, Vintage], set[Period]] -ProcessVintagesdict = dict[tuple[Region, Period, Technology], set[Vintage]] -SurvivalCurvePeriodsdict = dict[tuple[Region, Technology, Vintage], set[Period]] -CapacityConsumptionTechsdict = dict[tuple[Region, Period, Commodity], set[Technology]] -RetirementProductionProcessesdict = dict[ +ProcessTechsDict = dict[tuple[Region, Period, Commodity], set[Technology]] +ProcessReservePeriodsDict = dict[tuple[Region, Period], set[tuple[Technology, Vintage]]] +ProcessPeriodsDict = dict[tuple[Region, Technology, Vintage], set[Period]] +RetirementPeriodsDict = dict[tuple[Region, Technology, Vintage], set[Period]] +ProcessVintagesDict = dict[tuple[Region, Period, Technology], set[Vintage]] +SurvivalCurvePeriodsDict = dict[tuple[Region, Technology, Vintage], set[Period]] +CapacityConsumptionTechsDict = dict[tuple[Region, Period, Commodity], set[Technology]] +RetirementProductionProcessesDict = dict[ tuple[Region, Period, Commodity], set[tuple[Technology, Vintage]] ] -# Capitalized aliases for compatibility -ProcessInputsDict = ProcessInputsdict -ProcessOutputsDict = ProcessOutputsdict -ProcessLoansDict = ProcessLoansdict -ProcessInputsByOutputDict = ProcessInputsByOutputdict -ProcessOutputsByInputDict = ProcessOutputsByInputdict -ProcessTechsDict = ProcessTechsdict -ProcessReservePeriodsDict = ProcessReservePeriodsdict -ProcessPeriodsDict = ProcessPeriodsdict -RetirementPeriodsDict = RetirementPeriodsdict -ProcessVintagesDict = ProcessVintagesdict -SurvivalCurvePeriodsDict = SurvivalCurvePeriodsdict -CapacityConsumptionTechsDict = CapacityConsumptionTechsdict -RetirementProductionProcessesDict = RetirementProductionProcessesdict # Commodity flow dictionary types -CommodityStreamProcessdict = dict[tuple[Region, Period, Commodity], set[tuple[Technology, Vintage]]] +CommodityStreamProcessDict = dict[tuple[Region, Period, Commodity], set[tuple[Technology, Vintage]]] -# Capitalized aliases for compatibility -CommodityStreamProcessDict = CommodityStreamProcessdict - # Technology classification dictionary types -BaseloadVintagesdict = dict[tuple[Region, Period, Technology], set[Vintage]] -CurtailmentVintagesdict = dict[tuple[Region, Period, Technology], set[Vintage]] -StorageVintagesdict = dict[tuple[Region, Period, Technology], set[Vintage]] -RampUpVintagesdict = dict[tuple[Region, Period, Technology], set[Vintage]] -RampDownVintagesdict = dict[tuple[Region, Period, Technology], set[Vintage]] -InputSplitVintagesdict = dict[tuple[Region, Period, Commodity, Technology, str], set[Vintage]] -InputSplitAnnualVintagesdict = dict[tuple[Region, Period, Commodity, Technology, str], set[Vintage]] -OutputSplitVintagesdict = dict[tuple[Region, Period, Technology, Commodity, str], set[Vintage]] -OutputSplitAnnualVintagesdict = dict[ +BaseloadVintagesDict = dict[tuple[Region, Period, Technology], set[Vintage]] +CurtailmentVintagesDict = dict[tuple[Region, Period, Technology], set[Vintage]] +StorageVintagesDict = dict[tuple[Region, Period, Technology], set[Vintage]] +RampUpVintagesDict = dict[tuple[Region, Period, Technology], set[Vintage]] +RampDownVintagesDict = dict[tuple[Region, Period, Technology], set[Vintage]] +InputSplitVintagesDict = dict[tuple[Region, Period, Commodity, Technology, str], set[Vintage]] +InputSplitAnnualVintagesDict = dict[tuple[Region, Period, Commodity, Technology, str], set[Vintage]] +OutputSplitVintagesDict = dict[tuple[Region, Period, Technology, Commodity, str], set[Vintage]] +OutputSplitAnnualVintagesDict = dict[ tuple[Region, Period, Technology, Commodity, str], set[Vintage] ] -# Capitalized aliases for compatibility -BaseloadVintagesDict = BaseloadVintagesdict -CurtailmentVintagesDict = CurtailmentVintagesdict -StorageVintagesDict = StorageVintagesdict -RampUpVintagesDict = RampUpVintagesdict -RampDownVintagesDict = RampDownVintagesdict -InputSplitVintagesDict = InputSplitVintagesdict -InputSplitAnnualVintagesDict = InputSplitAnnualVintagesdict -OutputSplitVintagesDict = OutputSplitVintagesdict -OutputSplitAnnualVintagesDict = OutputSplitAnnualVintagesdict # Time sequencing dictionary types -TimeNextdict = dict[tuple[Period, Season, TimeOfDay], tuple[Season, TimeOfDay]] -TimeNextSequentialdict = dict[tuple[Period, Season], Season] -SequentialToSeasondict = dict[tuple[Period, Season], Season] +TimeNextDict = dict[tuple[Period, Season, TimeOfDay], tuple[Season, TimeOfDay]] +TimeNextSequentialDict = dict[tuple[Period, Season], Season] +SequentialToSeasonDict = dict[tuple[Period, Season], Season] -# Capitalized aliases for compatibility -TimeNextDict = TimeNextdict -TimeNextSequentialDict = TimeNextSequentialdict -SequentialToSeasonDict = SequentialToSeasondict # Geography/exchange dictionary types -ExportRegionsdict = dict[ +ExportRegionsDict = dict[ tuple[Region, Period, Commodity], set[tuple[Region, Technology, Vintage, Commodity]] ] -ImportRegionsdict = dict[ +ImportRegionsDict = dict[ tuple[Region, Period, Commodity], set[tuple[Region, Technology, Vintage, Commodity]] ] -ActiveRegionsForTechdict = dict[tuple[Period, Technology], set[Region]] +ActiveRegionsForTechDict = dict[tuple[Period, Technology], set[Region]] -# Capitalized aliases for compatibility -ExportRegionsDict = ExportRegionsdict -ImportRegionsDict = ImportRegionsdict -ActiveRegionsForTechDict = ActiveRegionsForTechdict # Switching/boolean flag dictionary types -EfficiencyVariabledict = dict[ +EfficiencyVariableDict = dict[ tuple[Region, Period, Commodity, Technology, Vintage, Commodity], bool ] -CapacityFactorProcessdict = dict[tuple[Region, Period, Technology, Vintage], bool] -SeasonalStoragedict = dict[Technology, bool] -SurvivalCurveProcessdict = dict[tuple[Region, Technology, Vintage], bool] - -# Capitalized aliases for compatibility -EfficiencyVariableDict = EfficiencyVariabledict -CapacityFactorProcessDict = CapacityFactorProcessdict -SeasonalStorageDict = SeasonalStoragedict -SurvivalCurveProcessDict = SurvivalCurveProcessdict +CapacityFactorProcessDict = dict[tuple[Region, Period, Technology, Vintage], bool] +SeasonalStorageDict = dict[Technology, bool] +SurvivalCurveProcessDict = dict[tuple[Region, Technology, Vintage], bool] diff --git a/temoa/types/model_types.py b/temoa/types/model_types.py index ed6dbea1b..7cc5cdfe1 100644 --- a/temoa/types/model_types.py +++ b/temoa/types/model_types.py @@ -19,8 +19,6 @@ CommoditySet, Period, Region, - RegionPeriodSeasonTimeInputTechVintageOutput, - RegionPeriodTechVintage, RegionSet, Season, SparseIndex, @@ -30,13 +28,10 @@ Vintage, ) -# Import Pyomo stub types if TYPE_CHECKING: from pyomo.core import ( AbstractModel, - BuildAction, Constraint, - Objective, Param, Set, Var, @@ -47,8 +42,6 @@ Param = Any # AbstractModel.Param Var = Any # AbstractModel.Var Constraint = Any # AbstractModel.Constraint - BuildAction = Any # AbstractModel.BuildAction - Objective = Any # AbstractModel.Objective # Type aliases for model data structures ProcessInputs = dict[tuple[Region, Period, Commodity, Technology, Vintage, Commodity], float] @@ -141,8 +134,11 @@ class TemoaModelProtocol(Protocol): # Internal data structures processInputs: ProcessInputs processOutputs: ProcessOutputs - activeFlow_rpsditvo: set[RegionPeriodSeasonTimeInputTechVintageOutput] | None - activeActivity_rptv: set[RegionPeriodTechVintage] | None + activeFlow_rpsditvo: ( + set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] + | None + ) + activeActivity_rptv: set[tuple[Region, Period, Technology, Vintage]] | None def __init__(self, *args: object, **kwargs: object) -> None: ... @@ -220,8 +216,10 @@ class TemoaModel(AbstractModel): processInputs: ProcessInputs processOutputs: ProcessOutputs used_techs: TechSet - activeFlow_rpsditvo: set[RegionPeriodSeasonTimeInputTechVintageOutput] - activeActivity_rptv: set[RegionPeriodTechVintage] + activeFlow_rpsditvo: set[ + tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity] + ] + activeActivity_rptv: set[tuple[Region, Period, Technology, Vintage]] def __init__(self, *args: object, **kwargs: object) -> None: ... diff --git a/temoa/types/set_types.py b/temoa/types/set_types.py index b83eebb92..ad2b73e9d 100644 --- a/temoa/types/set_types.py +++ b/temoa/types/set_types.py @@ -10,48 +10,32 @@ from .core_types import Commodity, Period, Region, Season, Technology, TimeOfDay, Vintage # Set types for sparse indexing -ActiveFlowset = Optional[ +ActiveFlowSet = Optional[ set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] ] -ActiveFlowAnnualset = Optional[ +ActiveFlowAnnualSet = Optional[ set[tuple[Region, Period, Commodity, Technology, Vintage, Commodity]] ] -ActiveFlexset = Optional[ +ActiveFlexSet = Optional[ set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] ] -ActiveFlexAnnualset = Optional[ +ActiveFlexAnnualSet = Optional[ set[tuple[Region, Period, Commodity, Technology, Vintage, Commodity]] ] -ActiveFlowInStorageset = Optional[ +ActiveFlowInStorageSet = Optional[ set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] ] -ActiveCurtailmentset = Optional[ +ActiveCurtailmentSet = Optional[ set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] ] -ActiveActivityset = Optional[set[tuple[Region, Period, Technology, Vintage]]] -StorageLevelIndicesset = Optional[ +ActiveActivitySet = Optional[set[tuple[Region, Period, Technology, Vintage]]] +StorageLevelIndicesSet = Optional[ set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]] ] -SeasonalStorageLevelIndicesset = Optional[set[tuple[Region, Period, Season, Technology, Vintage]]] -NewCapacityset = Optional[set[tuple[Region, Technology, Vintage]]] -ActiveCapacityAvailableset = Optional[set[tuple[Region, Period, Technology]]] -ActiveCapacityAvailableVintageset = Optional[set[tuple[Region, Period, Technology, Vintage]]] -GroupRegionActiveFlowset = Optional[set[tuple[Region, Period, Technology]]] +SeasonalStorageLevelIndicesSet = Optional[set[tuple[Region, Period, Season, Technology, Vintage]]] +NewCapacitySet = Optional[set[tuple[Region, Technology, Vintage]]] +ActiveCapacityAvailableSet = Optional[set[tuple[Region, Period, Technology]]] +ActiveCapacityAvailableVintageSet = Optional[set[tuple[Region, Period, Technology, Vintage]]] +GroupRegionActiveFlowSet = Optional[set[tuple[Region, Period, Technology]]] CommodityBalancedSet = set[tuple[Region, Period, Commodity]] - - -# Capitalized aliases for compatibility -ActiveFlowSet = ActiveFlowset -ActiveFlowAnnualSet = ActiveFlowAnnualset -ActiveFlexSet = ActiveFlexset -ActiveFlexAnnualSet = ActiveFlexAnnualset -ActiveFlowInStorageSet = ActiveFlowInStorageset -ActiveCurtailmentSet = ActiveCurtailmentset -ActiveActivitySet = ActiveActivityset -StorageLevelIndicesSet = StorageLevelIndicesset -SeasonalStorageLevelIndicesSet = SeasonalStorageLevelIndicesset -NewCapacitySet = NewCapacityset -ActiveCapacityAvailableSet = ActiveCapacityAvailableset -ActiveCapacityAvailableVintageSet = ActiveCapacityAvailableVintageset -GroupRegionActiveFlowSet = GroupRegionActiveFlowset diff --git a/temoa/types/solver_types.py b/temoa/types/solver_types.py index 0b6e968d3..1893f8fa4 100644 --- a/temoa/types/solver_types.py +++ b/temoa/types/solver_types.py @@ -40,19 +40,19 @@ class TerminationConditionEnum(int, Enum): Updated to match Pyomo 6.9.2 integer-based enum values. """ - convergenceCriteriaSatisfied = 0 - maxTimeLimit = 1 - iterationLimit = 2 - objectiveLimit = 3 - minStepLength = 4 + convergence_criteria_satisfied = 0 + max_time_limit = 1 + iteration_limit = 2 + objective_limit = 3 + min_step_length = 4 unbounded = 5 - provenInfeasible = 6 - locallyInfeasible = 7 - infeasibleOrUnbounded = 8 + proven_infeasible = 6 + locally_infeasible = 7 + infeasible_or_unbounded = 8 error = 9 interrupted = 10 - licensingProblems = 11 - emptyModel = 12 + licensing_problems = 11 + empty_model = 12 unknown = 42 From c884339498728a5a5d07ceaff80a4ff30d8694b2 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 30 Oct 2025 09:45:44 -0400 Subject: [PATCH 284/587] fixing minor inconsistencies --- temoa/_internal/table_data_puller.py | 2 +- temoa/components/capacity.py | 12 +-- temoa/components/flows.py | 30 ++++---- temoa/core/model.py | 9 +-- temoa/data_processing/README.md | 4 +- temoa/data_processing/make_graphviz.py | 7 +- temoa/model_checking/pricing_check.py | 3 +- temoa/utilities/unit_cost_explorer.py | 100 ++++++++++++------------- tests/test_pricing_check.py | 54 ++++++------- 9 files changed, 109 insertions(+), 112 deletions(-) diff --git a/temoa/_internal/table_data_puller.py b/temoa/_internal/table_data_puller.py index 62979475c..4e302730b 100644 --- a/temoa/_internal/table_data_puller.py +++ b/temoa/_internal/table_data_puller.py @@ -385,7 +385,7 @@ def poll_cost_results( value(fixed_cost), value(model.PeriodLength[p]), global_discount_rate=global_discount_rate, - p_0=float(p_0) if p_0 is not None else 0.0, + p_0=float(p_0_true), p=p, ) if '-' in r: diff --git a/temoa/components/capacity.py b/temoa/components/capacity.py index 1ba005ab7..a3a71864c 100644 --- a/temoa/components/capacity.py +++ b/temoa/components/capacity.py @@ -584,15 +584,15 @@ def create_capacity_and_retirement_sets(model: TemoaModel) -> None: used by other functions in this module to build Pyomo components. Populates: - - M.retirementPeriods: dict mapping (r, t, v) to a set of periods `p` + - model.retirementPeriods: dict mapping (r, t, v) to a set of periods `p` where retirement can occur. - - M.capacityConsumptionTechs: dict mapping (r, v, i) to a set of techs `t` + - model.capacityConsumptionTechs: dict mapping (r, v, i) to a set of techs `t` that consume commodity `i` for construction. - - M.retirementProductionProcesses: dict mapping (r, p, o) to a set of `(t, v)` + - model.retirementProductionProcesses: dict mapping (r, p, o) to a set of `(t, v)` processes that produce commodity `o` at end-of-life. - - M.newCapacity_rtv: set of (r, t, v) for new capacity investments. - - M.activeCapacityAvailable_rpt: set of (r, p, t) where capacity is active. - - M.activeCapacityAvailable_rptv: set of (r, p, t, v) where vintage capacity is active. + - model.newCapacity_rtv: set of (r, t, v) for new capacity investments. + - model.activeCapacityAvailable_rpt: set of (r, p, t) where capacity is active. + - model.activeCapacityAvailable_rptv: set of (r, p, t, v) where vintage capacity is active. """ logger.debug('Creating capacity, retirement, and construction/EOL sets.') diff --git a/temoa/components/flows.py b/temoa/components/flows.py index 918b1f475..feaf07a10 100644 --- a/temoa/components/flows.py +++ b/temoa/components/flows.py @@ -98,16 +98,16 @@ def create_commodity_balance_and_flow_sets(model: TemoaModel) -> None: for flows, capacity, and storage levels will be created. Populates: - - M.commodityBalance_rpc: The master set of (r, p, c) for balance constraints. - - M.activeFlow_rpsditvo: Indices for time-sliced flows (V_FlowOut). - - M.activeFlow_rpitvo: Indices for annual flows (V_FlowOutAnnual). - - M.activeFlex_rpsditvo: Indices for flexible time-sliced flows (V_Flex). - - M.activeFlex_rpitvo: Indices for flexible annual flows (V_FlexAnnual). - - M.activeFlowInStorage_rpsditvo: Indices for flows into storage (V_FlowIn). - - M.activeCurtailment_rpsditvo: Indices for curtailed generation (V_Curtailment). - - M.activeActivity_rptv: Master set of active (r, p, t, v) processes. - - M.storageLevelIndices_rpsdtv: Indices for storage state variables (V_StorageLevel). - - M.seasonalStorageLevelIndices_rpstv: Indices for seasonal storage levels. + - model.commodityBalance_rpc: The master set of (r, p, c) for balance constraints. + - model.activeFlow_rpsditvo: Indices for time-sliced flows (V_FlowOut). + - model.activeFlow_rpitvo: Indices for annual flows (V_FlowOutAnnual). + - model.activeFlex_rpsditvo: Indices for flexible time-sliced flows (V_Flex). + - model.activeFlex_rpitvo: Indices for flexible annual flows (V_FlexAnnual). + - model.activeFlowInStorage_rpsditvo: Indices for flows into storage (V_FlowIn). + - model.activeCurtailment_rpsditvo: Indices for curtailed generation (V_Curtailment). + - model.activeActivity_rptv: Master set of active (r, p, t, v) processes. + - model.storageLevelIndices_rpsdtv: Indices for storage state variables (V_StorageLevel). + - model.seasonalStorageLevelIndices_rpstv: Indices for seasonal storage levels. """ logger.debug('Creating commodity balance and active flow index sets.') # 1. Commodity Balance @@ -127,7 +127,7 @@ def create_commodity_balance_and_flow_sets(model: TemoaModel) -> None: for v in model.processVintages[r, p, t] for i in model.processInputs.get((r, p, t, v), set()) for o in model.processOutputsByInput.get((r, p, t, v, i), set()) - for s in model.TimeSeason[p] # REVERTED THIS LINE + for s in model.TimeSeason[p] for d in model.time_of_day } @@ -149,7 +149,7 @@ def create_commodity_balance_and_flow_sets(model: TemoaModel) -> None: for v in model.processVintages[r, p, t] for i in model.processInputs.get((r, p, t, v), set()) for o in model.processOutputsByInput.get((r, p, t, v, i), set()) - for s in model.TimeSeason[p] # REVERTED THIS LINE + for s in model.TimeSeason[p] for d in model.time_of_day } @@ -169,7 +169,7 @@ def create_commodity_balance_and_flow_sets(model: TemoaModel) -> None: for v in model.storageVintages[r, p, t] for i in model.processInputs.get((r, p, t, v), set()) for o in model.processOutputsByInput.get((r, p, t, v, i), set()) - for s in model.TimeSeason[p] # REVERTED THIS LINE + for s in model.TimeSeason[p] for d in model.time_of_day } @@ -179,7 +179,7 @@ def create_commodity_balance_and_flow_sets(model: TemoaModel) -> None: for v in model.curtailmentVintages[r, p, t] for i in model.processInputs.get((r, p, t, v), set()) for o in model.processOutputsByInput.get((r, p, t, v, i), set()) - for s in model.TimeSeason[p] # REVERTED THIS LINE + for s in model.TimeSeason[p] for d in model.time_of_day } @@ -193,7 +193,7 @@ def create_commodity_balance_and_flow_sets(model: TemoaModel) -> None: (r, p, s, d, t, v) for r, p, t in model.storageVintages for v in model.storageVintages[r, p, t] - for s in model.TimeSeason[p] # REVERTED THIS LINE + for s in model.TimeSeason[p] for d in model.time_of_day } diff --git a/temoa/core/model.py b/temoa/core/model.py index 1ca4d698d..fefb811cf 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -126,7 +126,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.activeActivity_rptv: t.ActiveActivitySet = set() self.storageLevelIndices_rpsdtv: t.StorageLevelIndicesSet = set() self.seasonalStorageLevelIndices_rpstv: t.SeasonalStorageLevelIndicesSet = set() - """currently available (within lifespan) (r, p, t, v) tuples (from M.processVintages)""" + """currently available (within lifespan) (r, p, t, v) tuples (from model.processVintages)""" self.activeRegionsForTech: t.ActiveRegionsForTechDict = {} """currently available regions by period and tech {(p, t) : r}""" @@ -820,13 +820,6 @@ def __init__(self, *args: object, **kwargs: object) -> None: # # ################################################ - # --------------------------------------------------------------- - # Dev Note: - # Constraints are specified to ensure proper system behavior, - # and also to calculate some derived quantities. Note that descriptions - # of these constraints are provided in the associated comment blocks - # in temoa_rules.py, where the constraints are defined. - # --------------------------------------------------------------- self.progress_marker_4 = BuildAction(['Starting to build Constraints'], rule=progress_check) # Declare constraints to calculate derived decision variables diff --git a/temoa/data_processing/README.md b/temoa/data_processing/README.md index 3d4823a12..eda947288 100644 --- a/temoa/data_processing/README.md +++ b/temoa/data_processing/README.md @@ -5,7 +5,7 @@ This folder contains files used to manage Temoa input/output data. Included file 1. `db_to_excel.py/` Python script that queries database output tables to create an Excel file containing scenario-specific results. -2. `Make_Graphviz.py/` +2. `make_graphviz.py/` Python script that creates a Graphviz diagram for the database. The most basic way to use graphviz is to view the full energy system map: ```$ python make_graphviz.py -i temoa_utopia.sqlite``` Other options include a capacitated @@ -20,7 +20,7 @@ Create and activate the Temoa environment, as follows: ```$ source activate temoa-py3``` - Once the Temoa environment is created and activated, enable the following extensions from from the command line. + Once the Temoa environment is created and activated, enable the following extensions from the command line. This will need to be done only once, before using notebooks within the Temoa environment. ```(temoa-py3) $ jupyter nbextension enable init_cell/main``` diff --git a/temoa/data_processing/make_graphviz.py b/temoa/data_processing/make_graphviz.py index 658adbf3e..1df9fffe9 100644 --- a/temoa/data_processing/make_graphviz.py +++ b/temoa/data_processing/make_graphviz.py @@ -2,14 +2,15 @@ import sys from subprocess import call -from database_util import DatabaseUtil -from graphviz_formats import ( +from graphviz_util import create_text_edges, create_text_nodes, get_color_config, process_input + +from .database_util import DatabaseUtil +from .graphviz_formats import ( commodity_dot_fmt, quick_run_dot_fmt, results_dot_fmt, tech_results_dot_fmt, ) -from graphviz_util import create_text_edges, create_text_nodes, get_color_config, process_input class GraphvizDiagramGenerator: diff --git a/temoa/model_checking/pricing_check.py b/temoa/model_checking/pricing_check.py index 7ccc71553..a91154e0b 100644 --- a/temoa/model_checking/pricing_check.py +++ b/temoa/model_checking/pricing_check.py @@ -246,7 +246,8 @@ def price_checker(model: TemoaModel) -> bool: ) warnings = True # continue by checking the uncap techs... - warnings &= check_tech_uncap(model) + if not check_tech_uncap(model): + warnings = True logger.info('Finished Price Checking Build Action') return not warnings diff --git a/temoa/utilities/unit_cost_explorer.py b/temoa/utilities/unit_cost_explorer.py index 0c8969ea6..d650737fb 100644 --- a/temoa/utilities/unit_cost_explorer.py +++ b/temoa/utilities/unit_cost_explorer.py @@ -15,7 +15,7 @@ # Created on: 12/30/23 -M = TemoaModel() +model = TemoaModel() """ let's fill in what we need to cost 1 item... @@ -31,47 +31,47 @@ # indices rtv = ('A', 'battery', 2020) # rtv rptv = ('A', 2020, 'battery', 2020) # rptv -M.time_future.construct([2020, 2025, 2030]) # needs to go 1 period beyond optimize horizon -M.time_optimize.construct([2020, 2025]) -M.PeriodLength.construct() -M.tech_all.construct(data=['battery']) -M.regions.construct(data=['A']) -M.regionalIndices.construct(data=['A']) +model.time_future.construct([2020, 2025, 2030]) # needs to go 1 period beyond optimize horizon +model.time_optimize.construct([2020, 2025]) +model.PeriodLength.construct() +model.tech_all.construct(data=['battery']) +model.regions.construct(data=['A']) +model.regionalIndices.construct(data=['A']) # make SETS -M.NewCapacityVar_rtv.construct(data=rtv) -M.CapacityVar_rptv.construct(data=rptv) -M.CostInvest_rtv.construct(data=rtv) -M.CostFixed_rptv.construct(data=rptv) -M.LoanLifetimeProcess_rtv.construct(data=rtv) +model.NewCapacityVar_rtv.construct(data=rtv) +model.CapacityVar_rptv.construct(data=rptv) +model.CostInvest_rtv.construct(data=rtv) +model.CostFixed_rptv.construct(data=rptv) +model.LoanLifetimeProcess_rtv.construct(data=rtv) # M.Loan_rtv.construct(data=rtv) # M.LoanRate_rtv.construct(data=rtv) -M.LifetimeProcess_rtv.construct(data=rtv) -M.MyopicDiscountingYear.construct(data={None: 0}) +model.LifetimeProcess_rtv.construct(data=rtv) +model.MyopicDiscountingYear.construct(data={None: 0}) # M.ModelProcessLife_rptv.construct(data=rptv) # make PARAMS -M.CostInvest.construct(data={rtv: 1300}) # US_9R_8D -M.CostFixed.construct(data={rptv: 20}) # US_9R_8D -M.LoanLifetimeProcess.construct(data={rtv: 10}) -M.LoanRate.construct(data={rtv: 0.05}) -M.LoanAnnualize.construct() -M.LifetimeTech.construct(data={('A', 'battery'): 20}) -M.LifetimeProcess.construct(data={rtv: 40}) +model.CostInvest.construct(data={rtv: 1300}) # US_9R_8D +model.CostFixed.construct(data={rptv: 20}) # US_9R_8D +model.LoanLifetimeProcess.construct(data={rtv: 10}) +model.LoanRate.construct(data={rtv: 0.05}) +model.LoanAnnualize.construct() +model.LifetimeTech.construct(data={('A', 'battery'): 20}) +model.LifetimeProcess.construct(data={rtv: 40}) # M.ModelProcessLife.construct(data={rptv: 20}) -M.GlobalDiscountRate.construct(data={None: 0.05}) -M.isSurvivalCurveProcess[rtv] = False +model.GlobalDiscountRate.construct(data={None: 0.05}) +model.isSurvivalCurveProcess[rtv] = False # make/fix VARS -M.V_NewCapacity.construct() -M.V_NewCapacity[rtv].set_value(1) +model.V_NewCapacity.construct() +model.V_NewCapacity[rtv].set_value(1) -M.V_Capacity.construct() -M.V_Capacity[rptv].set_value(1) +model.V_Capacity.construct() +model.V_Capacity[rptv].set_value(1) # run the total cost rule on our "model": -tot_cost_expr = total_cost_rule(M) +tot_cost_expr = total_cost_rule(model) total_cost = value(tot_cost_expr) print() print(f'Total cost for building 1 capacity unit of storage: ${total_cost:0.2f} [$M]') @@ -95,50 +95,50 @@ print('building storage level constraint...') # More SETS -M.time_season.construct(['winter', 'summer']) -M.TimeSeason.construct(data={2020: {'winter', 'summer'}, 2025: {'winter', 'summer'}}) -M.DaysPerPeriod.construct(data={None: 365}) +model.time_season.construct(['winter', 'summer']) +model.TimeSeason.construct(data={2020: {'winter', 'summer'}, 2025: {'winter', 'summer'}}) +model.DaysPerPeriod.construct(data={None: 365}) tod_slices = 2 -M.time_of_day.construct(data=range(1, tod_slices + 1)) -M.tech_storage.construct(data=['battery']) -M.ProcessLifeFrac_rptv.construct(data=[rptv]) -M.StorageLevel_rpsdtv.construct( +model.time_of_day.construct(data=range(1, tod_slices + 1)) +model.tech_storage.construct(data=['battery']) +model.ProcessLifeFrac_rptv.construct(data=[rptv]) +model.StorageLevel_rpsdtv.construct( data=[ ('A', 2020, 'winter', 1, 'battery', 2020), ] ) -M.StorageConstraints_rpsdtv.construct( +model.StorageConstraints_rpsdtv.construct( data=[ ('A', 2020, 'winter', 1, 'battery', 2020), ] ) # More PARAMS -M.CapacityToActivity.construct(data={('A', 'battery'): 31.536}) -M.StorageDuration.construct(data={('A', 'battery'): 4}) +model.CapacityToActivity.construct(data={('A', 'battery'): 31.536}) +model.StorageDuration.construct(data={('A', 'battery'): 4}) seasonal_fractions = {'winter': 0.4, 'summer': 0.6} -M.SegFrac.construct( +model.SegFrac.construct( data={ (p, s, d): seasonal_fractions[s] / tod_slices - for d in M.time_of_day - for p in M.time_optimize - for s in M.TimeSeason[p] + for d in model.time_of_day + for p in model.time_optimize + for s in model.TimeSeason[p] } ) # QA the total -print(f'quality check. Total of all SegFrac: {sum(M.SegFrac.values()):0.3f}') -M.ProcessLifeFrac.construct(data={('A', 2020, 'battery', 2020): 1.0}) +print(f'quality check. Total of all SegFrac: {sum(model.SegFrac.values()):0.3f}') +model.ProcessLifeFrac.construct(data={('A', 2020, 'battery', 2020): 1.0}) # More VARS -M.V_StorageLevel.construct() -M.SegFracPerSeason.construct() +model.V_StorageLevel.construct() +model.SegFracPerSeason.construct() -M.isSeasonalStorage['battery'] = False -upper_limit = storage_energy_upper_bound_constraint(M, 'A', 2020, 'winter', 1, 'battery', 2020) +model.isSeasonalStorage['battery'] = False +upper_limit = storage_energy_upper_bound_constraint(model, 'A', 2020, 'winter', 1, 'battery', 2020) print('The storage level constraint for the single period in the "super day":\n', upper_limit) # cross-check the multiplier... -mulitplier = storage_dur * M.SegFracPerSeason[2020, 'winter'] * M.DaysPerPeriod * c2a * c +mulitplier = storage_dur * model.SegFracPerSeason[2020, 'winter'] * model.DaysPerPeriod * c2a * c print(f'The multiplier for the storage should be: {mulitplier}') -M.StorageEnergyUpperBoundConstraint.construct() +model.StorageEnergyUpperBoundConstraint.construct() diff --git a/tests/test_pricing_check.py b/tests/test_pricing_check.py index 78b5bfba9..f5144c502 100644 --- a/tests/test_pricing_check.py +++ b/tests/test_pricing_check.py @@ -35,19 +35,21 @@ @pytest.fixture def mock_model(): """let's see how tough this is to work with...""" - M = ConcreteModel('mock') - M.tech_uncap = Set(initialize=['refinery']) - M.time_optimize = Set(initialize=[2000, 2010, 2020, 2030]) - M.LifetimeProcess = Param(Any, Any, Any, initialize={('CA', 'refinery', 2020): 30}) - M.Efficiency = Param(Any, Any, Any, Any, Any, initialize={('CA', 0, 'refinery', 2020, 0): 1.0}) - - M.ExistingCapacity = Param(Any, Any, Any, mutable=True) - M.CostFixed = Param(Any, Any, Any, Any, mutable=True) - M.CostInvest = Param(Any, Any, Any, mutable=True) - M.CostVariable = Param(Any, Any, Any, Any, mutable=True) - M.MaxCapacity = Param(Any, Any, Any, mutable=True) - M.MinCapacity = Param(Any, Any, Any, mutable=True) - return M + model = ConcreteModel('mock') + model.tech_uncap = Set(initialize=['refinery']) + model.time_optimize = Set(initialize=[2000, 2010, 2020, 2030]) + model.LifetimeProcess = Param(Any, Any, Any, initialize={('CA', 'refinery', 2020): 30}) + model.Efficiency = Param( + Any, Any, Any, Any, Any, initialize={('CA', 0, 'refinery', 2020, 0): 1.0} + ) + + model.ExistingCapacity = Param(Any, Any, Any, mutable=True) + model.CostFixed = Param(Any, Any, Any, Any, mutable=True) + model.CostInvest = Param(Any, Any, Any, mutable=True) + model.CostVariable = Param(Any, Any, Any, Any, mutable=True) + model.MaxCapacity = Param(Any, Any, Any, mutable=True) + model.MinCapacity = Param(Any, Any, Any, mutable=True) + return model def test_check_tech_uncap(mock_model): @@ -56,14 +58,14 @@ def test_check_tech_uncap(mock_model): :param mock_model: :return: """ - M = mock_model + model = mock_model - assert check_tech_uncap(M), 'should pass for no fixed/invest/variable costs' - M.CostVariable[('CA', 2020, 'refinery', 2020)] = 42 - assert not check_tech_uncap(M), 'should fail. Has cost in 2020, but missing in 2030' + assert check_tech_uncap(model), 'should pass for no fixed/invest/variable costs' + model.CostVariable[('CA', 2020, 'refinery', 2020)] = 42 + assert not check_tech_uncap(model), 'should fail. Has cost in 2020, but missing in 2030' # add in missing cost... - M.CostVariable[('CA', 2030, 'refinery', 2020)] = 42 - assert check_tech_uncap(M), 'should pass for all periods having var cost' + model.CostVariable[('CA', 2030, 'refinery', 2020)] = 42 + assert check_tech_uncap(model), 'should pass for all periods having var cost' def test_detect_fixed_cost(mock_model): @@ -72,10 +74,10 @@ def test_detect_fixed_cost(mock_model): :param mock_model: :return: """ - M = mock_model - assert check_tech_uncap(M), 'should have cleared and passed again' - M.CostFixed[('CA', 2020, 'refinery', 2020)] = 42 - assert not check_tech_uncap(M), 'should fail with any fixed cost' + model = mock_model + assert check_tech_uncap(model), 'should have cleared and passed again' + model.CostFixed[('CA', 2020, 'refinery', 2020)] = 42 + assert not check_tech_uncap(model), 'should fail with any fixed cost' def test_detect_invest_cost(mock_model): @@ -84,6 +86,6 @@ def test_detect_invest_cost(mock_model): :param mock_model: :return: """ - M = mock_model - M.CostInvest['CA', 'refinery', 2020] = 42 - assert not check_tech_uncap(M), 'should fail with any investment cost' + model = mock_model + model.CostInvest['CA', 'refinery', 2020] = 42 + assert not check_tech_uncap(model), 'should fail with any investment cost' From b291ee51600624cff4ac5621ef9c92b31c09736a Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 30 Oct 2025 09:51:03 -0400 Subject: [PATCH 285/587] fixing rebind bug in exchange reserve loops --- temoa/components/reserves.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/temoa/components/reserves.py b/temoa/components/reserves.py index ab271dad6..58e2fc785 100644 --- a/temoa/components/reserves.py +++ b/temoa/components/reserves.py @@ -156,7 +156,6 @@ def reserve_margin_dynamic( * value(model.CapacityToActivity[r1r2, t]) * value(model.SegFrac[p, s, d]) for (t, v) in model.processReservePeriods[r1r2, p] - for t in model.tech_reserve ) return available @@ -235,7 +234,6 @@ def reserve_margin_static( * value(model.CapacityToActivity[r1r2, t]) * value(model.SegFrac[p, s, d]) for (t, v) in model.processReservePeriods[r1r2, p] - for t in model.tech_reserve ) return available From d5c96c2f735776ad70924460aaad0f8df6ed0279 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 30 Oct 2025 09:53:50 -0400 Subject: [PATCH 286/587] fixing typo in checking retirement periods --- temoa/components/limits.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temoa/components/limits.py b/temoa/components/limits.py index 6fbfcc645..19d1184b5 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -858,7 +858,7 @@ def limit_emission_constraint( model.V_AnnualRetirement[reg, p, t, v] * value(model.EmissionEndOfLife[reg, e, t, v]) for reg in regions for (S_r, S_e, t, v) in model.EmissionEndOfLife.sparse_iterkeys() - if (r, t, v) in model.retirementPeriods and p in model.retirementPeriods[r, t, v] + if (reg, t, v) in model.retirementPeriods and p in model.retirementPeriods[reg, t, v] if S_r == reg and S_e == e ) From 67733183434a32dcc6dabf5fc82c004e03252c86 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 30 Oct 2025 10:02:28 -0400 Subject: [PATCH 287/587] adding period guard and simplyifying nested loop in seasonal_ramp indices --- temoa/components/operations.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/temoa/components/operations.py b/temoa/components/operations.py index 9184082ab..6f4ad89ce 100644 --- a/temoa/components/operations.py +++ b/temoa/components/operations.py @@ -85,10 +85,7 @@ def ramp_up_season_constraint_indices( for v in model.rampUpVintages[r, p, t] for _p, s_seq, s in model.ordered_season_sequential if _p == p - for s_seq_next in (model.time_next_sequential[p, s_seq],) # next sequential season - for s_next in ( - model.sequential_to_season[p, s_seq_next], - ) # next sequential season's matching season + for s_next in (model.sequential_to_season[p, model.time_next_sequential[p, s_seq]],) if s_next != model.time_next[p, s, model.time_of_day.last()][0] } @@ -107,10 +104,8 @@ def ramp_down_season_constraint_indices( for r, p, t in model.rampDownVintages for v in model.rampDownVintages[r, p, t] for _p, s_seq, s in model.ordered_season_sequential - for s_seq_next in (model.time_next_sequential[p, s_seq],) # next sequential season - for s_next in ( - model.sequential_to_season[p, s_seq_next], - ) # next sequential season's matching season + if _p == p + for s_next in (model.sequential_to_season[p, model.time_next_sequential[p, s_seq]],) if s_next != model.time_next[p, s, model.time_of_day.last()][0] } From 428f277da562bd5223dcda897e93a1acf41f290d Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 30 Oct 2025 10:07:29 -0400 Subject: [PATCH 288/587] fixing ramping averaging denominator --- temoa/components/operations.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/temoa/components/operations.py b/temoa/components/operations.py index 6f4ad89ce..198b688ea 100644 --- a/temoa/components/operations.py +++ b/temoa/components/operations.py @@ -301,6 +301,7 @@ def ramp_up_day_constraint( # How many hours does this time slice represent hours_adjust = value(model.SegFrac[p, s, d]) * value(model.DaysPerPeriod) * 24 + hours_adjust_next = value(model.SegFrac[p, s_next, d_next]) * value(model.DaysPerPeriod) * 24 hourly_activity_sd = ( sum( @@ -317,7 +318,7 @@ def ramp_up_day_constraint( for S_i in model.processInputs[r, p, t, v] for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) - / hours_adjust + / hours_adjust_next ) # elapsed hours from middle of this time slice to middle of next time slice @@ -386,6 +387,7 @@ def ramp_down_day_constraint( # How many hours does this time slice represent hours_adjust = value(model.SegFrac[p, s, d]) * value(model.DaysPerPeriod) * 24 + hours_adjust_next = value(model.SegFrac[p, s_next, d_next]) * value(model.DaysPerPeriod) * 24 hourly_activity_sd = ( sum( @@ -402,7 +404,7 @@ def ramp_down_day_constraint( for S_i in model.processInputs[r, p, t, v] for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) - / hours_adjust + / hours_adjust_next ) # elapsed hours from middle of this time slice to middle of next time slice @@ -455,6 +457,7 @@ def ramp_up_season_constraint( # How many hours does this time slice represent hours_adjust = value(model.SegFrac[p, s, d]) * value(model.DaysPerPeriod) * 24 + hours_adjust_next = value(model.SegFrac[p, s_next, d_next]) * value(model.DaysPerPeriod) * 24 hourly_activity_sd = ( sum( @@ -471,7 +474,7 @@ def ramp_up_season_constraint( for S_i in model.processInputs[r, p, t, v] for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) - / hours_adjust + / hours_adjust_next ) # elapsed hours from middle of this time slice to middle of next time slice @@ -524,6 +527,7 @@ def ramp_down_season_constraint( # How many hours does this time slice represent hours_adjust = value(model.SegFrac[p, s, d]) * value(model.DaysPerPeriod) * 24 + hours_adjust_next = value(model.SegFrac[p, s_next, d_next]) * value(model.DaysPerPeriod) * 24 hourly_activity_sd = ( sum( @@ -540,7 +544,7 @@ def ramp_down_season_constraint( for S_i in model.processInputs[r, p, t, v] for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) - / hours_adjust + / hours_adjust_next ) # elapsed hours from middle of this time slice to middle of next time slice From 91c35c392f5bf2d09f51b5894e01aeed3d9b029d Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 30 Oct 2025 10:22:24 -0400 Subject: [PATCH 289/587] minor consistency improvement --- temoa/_internal/table_data_puller.py | 2 +- temoa/data_processing/make_graphviz.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/temoa/_internal/table_data_puller.py b/temoa/_internal/table_data_puller.py index 4e302730b..ac7e34935 100644 --- a/temoa/_internal/table_data_puller.py +++ b/temoa/_internal/table_data_puller.py @@ -439,7 +439,7 @@ def poll_cost_results( var_cost, value(model.PeriodLength[p]), global_discount_rate=global_discount_rate, - p_0=float(p_0) if p_0 is not None else 0.0, + p_0=float(p_0_true), p=p, ) if '-' in r: diff --git a/temoa/data_processing/make_graphviz.py b/temoa/data_processing/make_graphviz.py index 1df9fffe9..83f639fae 100644 --- a/temoa/data_processing/make_graphviz.py +++ b/temoa/data_processing/make_graphviz.py @@ -2,8 +2,6 @@ import sys from subprocess import call -from graphviz_util import create_text_edges, create_text_nodes, get_color_config, process_input - from .database_util import DatabaseUtil from .graphviz_formats import ( commodity_dot_fmt, @@ -11,6 +9,7 @@ results_dot_fmt, tech_results_dot_fmt, ) +from .graphviz_util import create_text_edges, create_text_nodes, get_color_config, process_input class GraphvizDiagramGenerator: From bfb4fd56b58d46ca2a44d5ffc8cb6adb20628187 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 30 Oct 2025 10:43:36 -0400 Subject: [PATCH 290/587] fixing typo in total-input aggregation --- temoa/components/limits.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/temoa/components/limits.py b/temoa/components/limits.py index 19d1184b5..009a7b3ec 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -636,14 +636,13 @@ def limit_tech_input_split_average_constraint( for S_d in model.time_of_day for S_o in model.processOutputsByInput[r, p, t, v, i] ) - total_inp = quicksum( model.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] - / get_variable_efficiency(model, r, p, S_s, S_d, i, t, v, S_o) + / get_variable_efficiency(model, r, p, S_s, S_d, S_i, t, v, S_o) for S_s in model.TimeSeason[p] for S_d in model.time_of_day for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, i] + for S_o in model.processOutputsByInput[r, p, t, v, S_i] ) expr = operator_expression( From 450202939169c81b96a5454453a0eaeec8e278e8 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 30 Oct 2025 10:54:25 -0400 Subject: [PATCH 291/587] fixing attribute casing in make_graphviz --- temoa/data_processing/make_graphviz.py | 127 +++++++++++-------------- 1 file changed, 57 insertions(+), 70 deletions(-) diff --git a/temoa/data_processing/make_graphviz.py b/temoa/data_processing/make_graphviz.py index 83f639fae..3629470d7 100644 --- a/temoa/data_processing/make_graphviz.py +++ b/temoa/data_processing/make_graphviz.py @@ -14,33 +14,32 @@ class GraphvizDiagramGenerator: def __init__(self, db_file, scenario=None, region=None, out_dir='.', verbose=1): - self.dbFile = db_file - self.qName = os.path.splitext(os.path.basename(self.dbFile))[0] + self.db_file = db_file + self.q_name = os.path.splitext(os.path.basename(self.db_file))[0] self.scenario = scenario self.region = region - self.outDir = out_dir + self.out_dir = out_dir self.folder = {'results': 'whole_system', 'tech': 'processes', 'comm': 'commodities'} self.verbose = verbose self.colors = {} def connect(self): - self.dbUtil = DatabaseUtil(self.dbFile, self.scenario) - self.logger = open(os.path.join(self.outDir, 'graphviz.log'), 'w') + self.db_util = DatabaseUtil(self.db_file, self.scenario) + self.logger = open(os.path.join(self.out_dir, 'graphviz.log'), 'w') self.set_graphic_options(False, False) self.__log__('--------------------------------------') self.__log__('GraphvizDiagramGenerator: connected') if self.scenario: - out_dir = self.qName + '_' + self.scenario + '_graphviz' + out_dir = self.q_name + '_' + self.scenario + '_graphviz' else: - out_dir = self.qName + '_input_graphviz' + out_dir = self.q_name + '_input_graphviz' - self.outDir = os.path.join(self.outDir, out_dir) - if not os.path.exists(self.outDir): - os.mkdir(self.outDir) - # os.chdir(self.outDir) + self.out_dir = os.path.join(self.out_dir, out_dir) + if not os.path.exists(self.out_dir): + os.mkdir(self.out_dir) def close(self): - self.dbUtil.close() + self.db_util.close() self.__log__('GraphvizDiagramGenerator: disconnected') self.__log__('--------------------------------------') self.logger.close() @@ -65,13 +64,13 @@ def __generate_graph__(self, dot_format, dot_args, output_name, output_format): def set_graphic_options(self, grey_flag=None, splinevar=None): if grey_flag is not None: - self.greyFlag = grey_flag - self.colors.update(get_color_config(self.greyFlag)) + self.grey_flag = grey_flag + self.colors.update(get_color_config(self.grey_flag)) if splinevar is not None: self.colors['splinevar'] = splinevar self.__log__( 'setGraphicOption: updated greyFlag = ' - + str(self.greyFlag) + + str(self.grey_flag) + ' and splinevar = ' + str(self.colors['splinevar']) ) @@ -79,37 +78,34 @@ def set_graphic_options(self, grey_flag=None, splinevar=None): def create_main_results_diagram(self, period, region, output_format='svg'): self.__log__('CreateMainResultsDiagram: started with period = ' + str(period)) - if not os.path.exists(os.path.join(self.outDir, self.folder['results'])): - os.makedirs(os.path.join(self.outDir, self.folder['results'])) + if not os.path.exists(os.path.join(self.out_dir, self.folder['results'])): + os.makedirs(os.path.join(self.out_dir, self.folder['results'])) output_name = os.path.join(self.folder['results'], 'results%s' % period) if self.region: output_name += '_' + self.region - output_name = os.path.join(self.outDir, output_name) - if self.greyFlag: + output_name = os.path.join(self.out_dir, output_name) + if self.grey_flag: output_name += '.grey' - # if (os.path.exists(outputName + '.' + outputFormat)): - # self.__log__('CreateMainResultsDiagram: graph already exists at path, returning') - # return self.outDir, outputName + '.' + outputFormat - tech_all = self.dbUtil.get_technologies_for_flags(flags=['r', 'p', 'pb', 'ps']) + tech_all = self.db_util.get_technologies_for_flags(flags=['r', 'p', 'pb', 'ps']) - commodity_carrier = self.dbUtil.get_commodities_for_flags(flags=['d', 'p']) - commodity_emissions = self.dbUtil.get_commodities_for_flags(flags=['e']) + commodity_carrier = self.db_util.get_commodities_for_flags(flags=['d', 'p']) + commodity_emissions = self.db_util.get_commodities_for_flags(flags=['e']) - efficiency_input = self.dbUtil.get_commodities_by_technology(region, comm_type='input') - efficiency_output = self.dbUtil.get_commodities_by_technology(region, comm_type='output') + efficiency_input = self.db_util.get_commodities_by_technology(region, comm_type='input') + efficiency_output = self.db_util.get_commodities_by_technology(region, comm_type='output') - v_cap2 = self.dbUtil.get_capacity_for_tech_and_period(period=period, region=region) + v_cap2 = self.db_util.get_capacity_for_tech_and_period(period=period, region=region) - ei_2 = self.dbUtil.get_output_flow_for_period( + ei_2 = self.db_util.get_output_flow_for_period( period=period, region=region, comm_type='input' ) - eo_2 = self.dbUtil.get_output_flow_for_period( + eo_2 = self.db_util.get_output_flow_for_period( period=period, region=region, comm_type='output' ) - emio_2 = self.dbUtil.get_emissions_activity_for_period(period=period, region=region) + emio_2 = self.db_util.get_emissions_activity_for_period(period=period, region=region) self.__log__('CreateMainResultsDiagram: database fetched successfully') @@ -206,7 +202,7 @@ def create_main_results_diagram(self, period, region, output_format='svg'): self.__generate_graph__(results_dot_fmt, args, output_name, output_format) self.__log__('CreateMainResultsDiagram: graph generated, returning') - return self.outDir, output_name + '.' + output_format + return self.out_dir, output_name + '.' + output_format # Needs some small fixing - cases where no input but output is there. # Check sample graphs def create_tech_results_diagrams( @@ -219,18 +215,15 @@ def create_tech_results_diagrams( + str(tech) ) - if not os.path.exists(os.path.join(self.outDir, self.folder['tech'])): - os.makedirs(os.path.join(self.outDir, self.folder['tech'])) + if not os.path.exists(os.path.join(self.out_dir, self.folder['tech'])): + os.makedirs(os.path.join(self.out_dir, self.folder['tech'])) output_name = os.path.join(self.folder['tech'], f'results_{tech}_{period}') if self.region: output_name += '_' + self.region - output_name = os.path.join(self.outDir, output_name) - if self.greyFlag: + output_name = os.path.join(self.out_dir, output_name) + if self.grey_flag: output_name += '.grey' - # if (os.path.exists(outputName + '.' + outputFormat)): - # self.__log__('CreateTechResultsDiagrams: graph already exists at path, returning') - # return self.outDir, outputName + '.' + outputFormat # enode_attr_fmt = 'href="../commodities/rc_%%s_%%s.%s"' % outputFormat # vnode_attr_fmt = 'href="results_%%s_p%%sv%%s_segments.%s", ' % outputFormat @@ -239,8 +232,8 @@ def create_tech_results_diagrams( vnode_attr_fmt = "href=\"#\", onclick=\"loadNextGraphvizGraph('%s', '%s', '%s')\"" vnode_attr_fmt += 'label="%s\\nCap: %.2f"' - total_cap = self.dbUtil.get_capacity_for_tech_and_period(tech, period, region) - flows = self.dbUtil.get_commodity_wise_input_and_output_flow(tech, period, region) + total_cap = self.db_util.get_capacity_for_tech_and_period(tech, period, region) + flows = self.db_util.get_commodity_wise_input_and_output_flow(tech, period, region) self.__log__('CreateTechResultsDiagrams: database fetched successfully') @@ -282,7 +275,7 @@ def create_tech_results_diagrams( self.__log__('CreateTechResultsDiagrams: nothing to create') self.__log__('CreateTechResultsDiagrams: graph generated, returning') - return self.outDir, output_name + '.' + output_format + return self.out_dir, output_name + '.' + output_format def create_commodity_partial_results(self, period, region, comm, output_format='svg'): self.__log__( @@ -292,30 +285,27 @@ def create_commodity_partial_results(self, period, region, comm, output_format=' + str(comm) ) - if not os.path.exists(os.path.join(self.outDir, self.folder['comm'])): - os.makedirs(os.path.join(self.outDir, self.folder['comm'])) + if not os.path.exists(os.path.join(self.out_dir, self.folder['comm'])): + os.makedirs(os.path.join(self.out_dir, self.folder['comm'])) output_name = os.path.join(self.folder['comm'], f'rc_{comm}_{period}') if self.region: output_name += '_' + self.region - output_name = os.path.join(self.outDir, output_name) - if self.greyFlag: + output_name = os.path.join(self.out_dir, output_name) + if self.grey_flag: output_name += '.grey' - # if (os.path.exists(outputName + '.' + outputFormat)): - # self.__log__('CreateCommodityPartialResults: graph already exists at path, returning') - # return self.outDir, outputName + '.' + outputFormat input_total = set( - self.dbUtil.get_existing_technologies_for_commodity(comm, region, 'output')['tech'] + self.db_util.get_existing_technologies_for_commodity(comm, region, 'output')['tech'] ) output_total = set( - self.dbUtil.get_existing_technologies_for_commodity(comm, region, 'input')['tech'] + self.db_util.get_existing_technologies_for_commodity(comm, region, 'input')['tech'] ) - flow_in = self.dbUtil.get_output_flow_for_period(period, region, 'input', comm) + flow_in = self.db_util.get_output_flow_for_period(period, region, 'input', comm) otechs = set(flow_in['tech']) - flow_out = self.dbUtil.get_output_flow_for_period(period, region, 'output', comm) + flow_out = self.db_util.get_output_flow_for_period(period, region, 'output', comm) itechs = set(flow_out['tech']) self.__log__('CreateCommodityPartialResults: database fetched successfully') @@ -364,7 +354,7 @@ def create_commodity_partial_results(self, period, region, comm, output_format=' ) self.__generate_graph__(commodity_dot_fmt, args, output_name, output_format) self.__log__('CreateCommodityPartialResults: graph generated, returning') - return self.outDir, output_name + '.' + output_format + return self.out_dir, output_name + '.' + output_format # Function for generating the Input Graph def create_complete_input_graph( @@ -376,39 +366,36 @@ def create_complete_input_graph( + ' and inp_comm = ' + str(inp_comm) ) - output_name = self.qName + output_name = self.q_name if inp_tech: output_name += '_' + str(inp_tech) - if not os.path.exists(os.path.join(self.outDir, self.folder['tech'])): - os.makedirs(os.path.join(self.outDir, self.folder['tech'])) + if not os.path.exists(os.path.join(self.out_dir, self.folder['tech'])): + os.makedirs(os.path.join(self.out_dir, self.folder['tech'])) output_name = os.path.join(self.folder['tech'], output_name) elif inp_comm: output_name += '_' + str(inp_comm) - if not os.path.exists(os.path.join(self.outDir, self.folder['comm'])): - os.makedirs(os.path.join(self.outDir, self.folder['comm'])) + if not os.path.exists(os.path.join(self.out_dir, self.folder['comm'])): + os.makedirs(os.path.join(self.out_dir, self.folder['comm'])) output_name = os.path.join(self.folder['comm'], output_name) else: - if not os.path.exists(os.path.join(self.outDir, self.folder['results'])): - os.makedirs(os.path.join(self.outDir, self.folder['results'])) + if not os.path.exists(os.path.join(self.out_dir, self.folder['results'])): + os.makedirs(os.path.join(self.out_dir, self.folder['results'])) output_name = os.path.join(self.folder['results'], output_name) if self.region: output_name += '_' + self.region - output_name = os.path.join(self.outDir, output_name) - if self.greyFlag: + output_name = os.path.join(self.out_dir, output_name) + if self.grey_flag: output_name += '.grey' - # if (os.path.exists(outputName + '.' + outputFormat)): - # self.__log__('createCompleteInputGraph: graph already exists at path, returning') - # return self.outDir, outputName + '.' + outputFormat nodes, tech, ltech, to_tech, from_tech = set(), set(), set(), set(), set() - if DatabaseUtil.is_database_file(self.dbFile): - res = self.dbUtil.get_commodities_and_tech(inp_comm, inp_tech, region) + if DatabaseUtil.is_database_file(self.db_file): + res = self.db_util.get_commodities_and_tech(inp_comm, inp_tech, region) else: - res = self.dbUtil.read_from_dat_file(inp_comm, inp_tech) + res = self.db_util.read_from_dat_file(inp_comm, inp_tech) self.__log__('createCompleteInputGraph: database fetched successfully') # Create nodes and edges using the data frames from database @@ -436,7 +423,7 @@ def create_complete_input_graph( ) self.__generate_graph__(quick_run_dot_fmt, args, output_name, output_format) self.__log__('createCompleteInputGraph: graph generated, returning') - return self.outDir, output_name + '.' + output_format + return self.out_dir, output_name + '.' + output_format if __name__ == '__main__': From afb32f0c92e1042405a100b71baaca3f963dfc2b Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 30 Oct 2025 11:57:00 -0400 Subject: [PATCH 292/587] reworking db_to_excel to remove pyam-iamc, removing stale dependencies --- pyproject.toml | 5 - requirements-dev.txt | 483 +------ requirements.txt | 485 +------ temoa/data_processing/db_to_excel.py | 311 ++-- uv.lock | 1994 +------------------------- 5 files changed, 247 insertions(+), 3031 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 10b8dfa17..af0900224 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,6 @@ authors = [ dependencies = [ "pyomo>=6.8.0", - "ipython", "matplotlib==3.9.2", "pandas>=2.2.2", "numpy>=2.1.0", @@ -20,13 +19,9 @@ dependencies = [ "pydoe>=0.3.8", "pyutilib>=6.0.0", "graphviz>=0.20.3", - "ipykernel", - "jupyter", - "jupyter_contrib_nbextensions", "seaborn>=0.13.2", "tabulate>=0.9.0", "xlsxwriter>=3.2.0", - "pyam-iamc>=2.2.4", "pytest>=8.3.2", "deprecated>=1.2.14", "openpyxl>=3.1.5", diff --git a/requirements-dev.txt b/requirements-dev.txt index fdc91723d..175e567ff 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -2,62 +2,16 @@ # uv pip compile pyproject.toml --all-extras -o requirements-dev.txt alabaster==1.0.0 # via sphinx -alembic==1.16.4 - # via ixmp4 -annotated-types==0.7.0 - # via pydantic -anyio==4.9.0 - # via - # httpx - # jupyter-server - # starlette -argon2-cffi==25.1.0 - # via jupyter-server -argon2-cffi-bindings==21.2.0 - # via argon2-cffi -arrow==1.3.0 - # via isoduration -asttokens==3.0.0 - # via stack-data -async-lru==2.0.5 - # via jupyterlab -attrs==25.3.0 - # via - # jsonschema - # referencing babel==2.17.0 - # via - # jupyterlab-server - # sphinx -beautifulsoup4==4.13.4 - # via nbconvert -bleach==6.2.0 - # via nbconvert + # via sphinx certifi==2025.7.14 - # via - # httpcore - # httpx - # requests -cffi==1.17.1 - # via argon2-cffi-bindings + # via requests charset-normalizer==3.4.2 # via requests -click==8.2.1 - # via typer -comm==0.2.2 - # via - # ipykernel - # ipywidgets contourpy==1.3.2 # via matplotlib cycler==0.12.1 # via matplotlib -debugpy==1.8.15 - # via ipykernel -decorator==5.2.1 - # via ipython -defusedxml==0.7.1 - # via nbconvert deprecated==1.2.18 # via temoa (pyproject.toml) dill==0.4.0 @@ -70,222 +24,41 @@ docutils==0.21.2 # sphinxcontrib-bibtex et-xmlfile==2.0.0 # via openpyxl -executing==2.2.0 - # via stack-data -fastapi==0.116.1 - # via ixmp4 -fastjsonschema==2.21.1 - # via nbformat -flexcache==0.3 - # via pint -flexparser==0.4 - # via pint fonttools==4.59.0 # via matplotlib -fqdn==1.5.1 - # via jsonschema graphviz==0.21 # via temoa (pyproject.toml) -greenlet==3.2.3 - # via sqlalchemy gurobipy==12.0.3 # via temoa (pyproject.toml) -h11==0.16.0 - # via httpcore -h2==4.2.0 - # via httpx highspy==1.11.0 # via temoa (pyproject.toml) -hpack==4.1.0 - # via h2 -httpcore==1.0.9 - # via httpx -httpx==0.28.1 - # via - # ixmp4 - # jupyterlab -hyperframe==6.1.0 - # via h2 -iam-units==2023.9.12 - # via pyam-iamc idna==3.10 - # via - # anyio - # httpx - # jsonschema - # requests + # via requests imagesize==1.4.1 # via sphinx iniconfig==2.1.0 # via pytest -ipykernel==6.29.5 - # via - # temoa (pyproject.toml) - # jupyter - # jupyter-console - # jupyterlab -ipython==9.4.0 - # via - # temoa (pyproject.toml) - # ipykernel - # ipywidgets - # jupyter-console -ipython-genutils==0.2.0 - # via jupyter-contrib-nbextensions -ipython-pygments-lexers==1.1.1 - # via ipython -ipywidgets==8.1.7 - # via jupyter -isoduration==20.11.0 - # via jsonschema -ixmp4==0.11.1 - # via pyam-iamc -jedi==0.19.2 - # via ipython jinja2==3.1.6 - # via - # jupyter-server - # jupyterlab - # jupyterlab-server - # nbconvert - # sphinx + # via sphinx joblib==1.5.1 # via temoa (pyproject.toml) -json5==0.12.0 - # via jupyterlab-server -jsonpointer==3.0.0 - # via jsonschema -jsonschema==4.24.0 - # via - # jupyter-events - # jupyterlab-server - # nbformat -jsonschema-specifications==2025.4.1 - # via jsonschema -jupyter==1.1.1 - # via temoa (pyproject.toml) -jupyter-client==8.6.3 - # via - # ipykernel - # jupyter-console - # jupyter-server - # nbclient -jupyter-console==6.6.3 - # via jupyter -jupyter-contrib-core==0.4.2 - # via - # jupyter-contrib-nbextensions - # jupyter-nbextensions-configurator -jupyter-contrib-nbextensions==0.7.0 - # via temoa (pyproject.toml) -jupyter-core==5.8.1 - # via - # ipykernel - # jupyter-client - # jupyter-console - # jupyter-contrib-core - # jupyter-contrib-nbextensions - # jupyter-nbextensions-configurator - # jupyter-server - # jupyterlab - # nbclient - # nbconvert - # nbformat -jupyter-events==0.12.0 - # via jupyter-server -jupyter-highlight-selected-word==0.2.0 - # via jupyter-contrib-nbextensions -jupyter-lsp==2.2.5 - # via jupyterlab -jupyter-nbextensions-configurator==0.6.4 - # via jupyter-contrib-nbextensions -jupyter-server==2.16.0 - # via - # jupyter-lsp - # jupyter-nbextensions-configurator - # jupyterlab - # jupyterlab-server - # notebook - # notebook-shim -jupyter-server-terminals==0.5.3 - # via jupyter-server -jupyterlab==4.4.4 - # via - # jupyter - # notebook -jupyterlab-pygments==0.3.0 - # via nbconvert -jupyterlab-server==2.27.3 - # via - # jupyterlab - # notebook -jupyterlab-widgets==3.0.15 - # via ipywidgets kiwisolver==1.4.8 # via matplotlib latexcodec==3.0.1 # via pybtex -lxml==6.0.0 - # via jupyter-contrib-nbextensions -mako==1.3.10 - # via alembic -markdown-it-py==3.0.0 - # via rich markupsafe==3.0.2 - # via - # jinja2 - # mako - # nbconvert + # via jinja2 matplotlib==3.9.2 # via # temoa (pyproject.toml) - # pyam-iamc # salib # seaborn -matplotlib-inline==0.1.7 - # via - # ipykernel - # ipython -mdurl==0.1.2 - # via markdown-it-py -mistune==3.1.3 - # via nbconvert multiprocess==0.70.18 # via salib -mypy==1.17.0 - # via sqlalchemy -mypy-extensions==1.1.0 - # via - # mypy - # typing-inspect -nbclient==0.10.2 - # via nbconvert -nbconvert==7.16.6 - # via - # jupyter - # jupyter-contrib-nbextensions - # jupyter-server -nbformat==5.10.4 - # via - # jupyter-server - # nbclient - # nbconvert -nest-asyncio==1.6.0 - # via ipykernel networkx==3.5 # via temoa (pyproject.toml) nose==1.3.7 # via pyutilib -notebook==7.4.4 - # via - # jupyter - # jupyter-contrib-core - # jupyter-contrib-nbextensions - # jupyter-nbextensions-configurator -notebook-shim==0.2.4 - # via - # jupyterlab - # notebook numpy==2.3.1 # via # temoa (pyproject.toml) @@ -293,113 +66,40 @@ numpy==2.3.1 # highspy # matplotlib # pandas - # pyam-iamc # pydoe # salib # scipy # seaborn - # wquantiles openpyxl==3.1.5 - # via - # temoa (pyproject.toml) - # ixmp4 - # pyam-iamc -overrides==7.7.0 - # via jupyter-server + # via temoa (pyproject.toml) packaging==25.0 # via - # ipykernel - # jupyter-events - # jupyter-server - # jupyterlab - # jupyterlab-server # matplotlib - # nbconvert - # pandera # pytest # sphinx pandas==2.3.1 # via # temoa (pyproject.toml) - # ixmp4 - # pyam-iamc # salib # seaborn -pandera==0.25.0 - # via ixmp4 -pandocfilters==1.5.1 - # via nbconvert -parso==0.8.4 - # via jedi -pathspec==0.12.1 - # via mypy -pexpect==4.9.0 - # via ipython pillow==11.3.0 # via matplotlib -pint==0.24.4 - # via - # iam-units - # pyam-iamc -platformdirs==4.3.8 - # via - # jupyter-core - # pint pluggy==1.6.0 # via pytest ply==3.11 # via pyomo -prometheus-client==0.22.1 - # via jupyter-server -prompt-toolkit==3.0.51 - # via - # ipython - # jupyter-console -psutil==7.0.0 - # via ipykernel -psycopg==3.2.9 - # via ixmp4 -psycopg-binary==3.2.9 - # via psycopg -ptyprocess==0.7.0 - # via - # pexpect - # terminado -pure-eval==0.2.3 - # via stack-data -pyam-iamc==3.0.0 - # via temoa (pyproject.toml) pybtex==0.25.1 # via # pybtex-docutils # sphinxcontrib-bibtex pybtex-docutils==1.0.3 # via sphinxcontrib-bibtex -pycparser==2.22 - # via cffi -pydantic==2.11.7 - # via - # fastapi - # ixmp4 - # pandera - # pydantic-settings -pydantic-core==2.33.2 - # via pydantic -pydantic-settings==2.10.1 - # via ixmp4 pydoe==0.3.8 # via temoa (pyproject.toml) pygments==2.19.2 # via - # ipython - # ipython-pygments-lexers - # jupyter-console - # nbconvert # pytest - # rich # sphinx -pyjwt==2.10.1 - # via ixmp4 pyomo==6.9.2 # via temoa (pyproject.toml) pyparsing==3.2.3 @@ -408,91 +108,33 @@ pytest==8.4.1 # via temoa (pyproject.toml) python-dateutil==2.9.0.post0 # via - # arrow - # jupyter-client # matplotlib # pandas -python-dotenv==1.1.1 - # via - # ixmp4 - # pydantic-settings -python-json-logger==3.3.0 - # via jupyter-events pytz==2025.2 # via pandas pyutilib==6.0.0 # via temoa (pyproject.toml) pyyaml==6.0.2 - # via - # jupyter-events - # jupyter-nbextensions-configurator - # pyam-iamc - # pybtex -pyzmq==27.0.0 - # via - # ipykernel - # jupyter-client - # jupyter-console - # jupyter-server -referencing==0.36.2 - # via - # jsonschema - # jsonschema-specifications - # jupyter-events + # via pybtex requests==2.32.4 - # via - # jupyterlab-server - # pyam-iamc - # sphinx -rfc3339-validator==0.1.4 - # via - # jsonschema - # jupyter-events -rfc3986-validator==0.1.1 - # via - # jsonschema - # jupyter-events -rich==14.0.0 - # via - # ixmp4 - # typer + # via sphinx roman-numerals-py==3.1.0 # via sphinx -rpds-py==0.26.0 - # via - # jsonschema - # referencing salib==1.5.1 # via temoa (pyproject.toml) scipy==1.16.0 # via # temoa (pyproject.toml) - # pyam-iamc # pydoe # salib seaborn==0.13.2 - # via - # temoa (pyproject.toml) - # pyam-iamc -send2trash==1.8.3 - # via jupyter-server -setuptools==80.9.0 - # via - # jupyter-contrib-core - # jupyterlab -shellingham==1.5.4 - # via typer + # via temoa (pyproject.toml) six==1.17.0 # via # python-dateutil # pyutilib - # rfc3339-validator -sniffio==1.3.1 - # via anyio snowballstemmer==3.0.1 # via sphinx -soupsieve==2.7 - # via beautifulsoup4 sphinx==8.2.3 # via # temoa (pyproject.toml) @@ -521,118 +163,13 @@ sphinxcontrib-serializinghtml==2.0.0 # via # temoa (pyproject.toml) # sphinx -sqlalchemy==2.0.41 - # via - # alembic - # ixmp4 - # sqlalchemy-continuum - # sqlalchemy-utils -sqlalchemy-continuum==1.4.2 - # via ixmp4 -sqlalchemy-utils==0.41.2 - # via - # ixmp4 - # sqlalchemy-continuum -stack-data==0.6.3 - # via ipython -starlette==0.47.1 - # via fastapi tabulate==0.9.0 # via temoa (pyproject.toml) -terminado==0.18.1 - # via - # jupyter-server - # jupyter-server-terminals -tinycss2==1.4.0 - # via bleach -toml==0.10.2 - # via ixmp4 -tornado==6.5.1 - # via - # ipykernel - # jupyter-client - # jupyter-contrib-core - # jupyter-contrib-nbextensions - # jupyter-nbextensions-configurator - # jupyter-server - # jupyterlab - # notebook - # terminado -traitlets==5.14.3 - # via - # comm - # ipykernel - # ipython - # ipywidgets - # jupyter-client - # jupyter-console - # jupyter-contrib-core - # jupyter-contrib-nbextensions - # jupyter-core - # jupyter-events - # jupyter-nbextensions-configurator - # jupyter-server - # jupyterlab - # matplotlib-inline - # nbclient - # nbconvert - # nbformat -typeguard==4.4.4 - # via pandera -typer==0.16.0 - # via ixmp4 -types-python-dateutil==2.9.0.20250708 - # via arrow -typing-extensions==4.14.1 - # via - # alembic - # anyio - # beautifulsoup4 - # fastapi - # flexcache - # flexparser - # mypy - # pandera - # pint - # psycopg - # pydantic - # pydantic-core - # referencing - # sqlalchemy - # starlette - # typeguard - # typer - # typing-inspect - # typing-inspection -typing-inspect==0.9.0 - # via pandera -typing-inspection==0.4.1 - # via - # pydantic - # pydantic-settings tzdata==2025.2 # via pandas -uri-template==1.3.0 - # via jsonschema urllib3==2.5.0 # via requests -wcwidth==0.2.13 - # via prompt-toolkit -webcolors==24.11.1 - # via jsonschema -webencodings==0.5.1 - # via - # bleach - # tinycss2 -websocket-client==1.8.0 - # via jupyter-server -widgetsnbextension==4.0.14 - # via ipywidgets -wquantiles==0.6 - # via pyam-iamc wrapt==1.17.2 # via deprecated xlsxwriter==3.2.5 - # via - # temoa (pyproject.toml) - # pyam-iamc + # via temoa (pyproject.toml) diff --git a/requirements.txt b/requirements.txt index 2934aa242..b276a8e9a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,274 +1,38 @@ # This file was autogenerated by uv via the following command: # uv pip compile pyproject.toml -o requirements.txt -alembic==1.16.4 - # via ixmp4 -annotated-types==0.7.0 - # via pydantic -anyio==4.9.0 - # via - # httpx - # jupyter-server - # starlette -argon2-cffi==25.1.0 - # via jupyter-server -argon2-cffi-bindings==21.2.0 - # via argon2-cffi -arrow==1.3.0 - # via isoduration -asttokens==3.0.0 - # via stack-data -async-lru==2.0.5 - # via jupyterlab -attrs==25.3.0 - # via - # jsonschema - # referencing -babel==2.17.0 - # via jupyterlab-server -beautifulsoup4==4.13.4 - # via nbconvert -bleach==6.2.0 - # via nbconvert -certifi==2025.7.14 - # via - # httpcore - # httpx - # requests -cffi==1.17.1 - # via argon2-cffi-bindings -charset-normalizer==3.4.2 - # via requests -click==8.2.1 - # via typer -comm==0.2.2 - # via - # ipykernel - # ipywidgets contourpy==1.3.2 # via matplotlib cycler==0.12.1 # via matplotlib -debugpy==1.8.15 - # via ipykernel -decorator==5.2.1 - # via ipython -defusedxml==0.7.1 - # via nbconvert deprecated==1.2.18 # via temoa (pyproject.toml) dill==0.4.0 # via multiprocess et-xmlfile==2.0.0 # via openpyxl -executing==2.2.0 - # via stack-data -fastapi==0.116.1 - # via ixmp4 -fastjsonschema==2.21.1 - # via nbformat -flexcache==0.3 - # via pint -flexparser==0.4 - # via pint fonttools==4.59.0 # via matplotlib -fqdn==1.5.1 - # via jsonschema graphviz==0.21 # via temoa (pyproject.toml) -greenlet==3.2.3 - # via sqlalchemy -h11==0.16.0 - # via httpcore -h2==4.2.0 - # via httpx highspy==1.11.0 # via temoa (pyproject.toml) -hpack==4.1.0 - # via h2 -httpcore==1.0.9 - # via httpx -httpx==0.28.1 - # via - # ixmp4 - # jupyterlab -hyperframe==6.1.0 - # via h2 -iam-units==2023.9.12 - # via pyam-iamc -idna==3.10 - # via - # anyio - # httpx - # jsonschema - # requests iniconfig==2.1.0 # via pytest -ipykernel==6.29.5 - # via - # temoa (pyproject.toml) - # jupyter - # jupyter-console - # jupyterlab -ipython==9.4.0 - # via - # temoa (pyproject.toml) - # ipykernel - # ipywidgets - # jupyter-console -ipython-genutils==0.2.0 - # via jupyter-contrib-nbextensions -ipython-pygments-lexers==1.1.1 - # via ipython -ipywidgets==8.1.7 - # via jupyter -isoduration==20.11.0 - # via jsonschema -ixmp4==0.11.1 - # via pyam-iamc -jedi==0.19.2 - # via ipython -jinja2==3.1.6 - # via - # jupyter-server - # jupyterlab - # jupyterlab-server - # nbconvert joblib==1.5.1 # via temoa (pyproject.toml) -json5==0.12.0 - # via jupyterlab-server -jsonpointer==3.0.0 - # via jsonschema -jsonschema==4.24.0 - # via - # jupyter-events - # jupyterlab-server - # nbformat -jsonschema-specifications==2025.4.1 - # via jsonschema -jupyter==1.1.1 - # via temoa (pyproject.toml) -jupyter-client==8.6.3 - # via - # ipykernel - # jupyter-console - # jupyter-server - # nbclient -jupyter-console==6.6.3 - # via jupyter -jupyter-contrib-core==0.4.2 - # via - # jupyter-contrib-nbextensions - # jupyter-nbextensions-configurator -jupyter-contrib-nbextensions==0.7.0 - # via temoa (pyproject.toml) -jupyter-core==5.8.1 - # via - # ipykernel - # jupyter-client - # jupyter-console - # jupyter-contrib-core - # jupyter-contrib-nbextensions - # jupyter-nbextensions-configurator - # jupyter-server - # jupyterlab - # nbclient - # nbconvert - # nbformat -jupyter-events==0.12.0 - # via jupyter-server -jupyter-highlight-selected-word==0.2.0 - # via jupyter-contrib-nbextensions -jupyter-lsp==2.2.5 - # via jupyterlab -jupyter-nbextensions-configurator==0.6.4 - # via jupyter-contrib-nbextensions -jupyter-server==2.16.0 - # via - # jupyter-lsp - # jupyter-nbextensions-configurator - # jupyterlab - # jupyterlab-server - # notebook - # notebook-shim -jupyter-server-terminals==0.5.3 - # via jupyter-server -jupyterlab==4.4.4 - # via - # jupyter - # notebook -jupyterlab-pygments==0.3.0 - # via nbconvert -jupyterlab-server==2.27.3 - # via - # jupyterlab - # notebook -jupyterlab-widgets==3.0.15 - # via ipywidgets kiwisolver==1.4.8 # via matplotlib -lxml==6.0.0 - # via jupyter-contrib-nbextensions -mako==1.3.10 - # via alembic -markdown-it-py==3.0.0 - # via rich -markupsafe==3.0.2 - # via - # jinja2 - # mako - # nbconvert matplotlib==3.9.2 # via # temoa (pyproject.toml) - # pyam-iamc # salib # seaborn -matplotlib-inline==0.1.7 - # via - # ipykernel - # ipython -mdurl==0.1.2 - # via markdown-it-py -mistune==3.1.3 - # via nbconvert multiprocess==0.70.18 # via salib -mypy==1.17.0 - # via sqlalchemy -mypy-extensions==1.1.0 - # via - # mypy - # typing-inspect -nbclient==0.10.2 - # via nbconvert -nbconvert==7.16.6 - # via - # jupyter - # jupyter-contrib-nbextensions - # jupyter-server -nbformat==5.10.4 - # via - # jupyter-server - # nbclient - # nbconvert -nest-asyncio==1.6.0 - # via ipykernel networkx==3.5 # via temoa (pyproject.toml) nose==1.3.7 # via pyutilib -notebook==7.4.4 - # via - # jupyter - # jupyter-contrib-core - # jupyter-contrib-nbextensions - # jupyter-nbextensions-configurator -notebook-shim==0.2.4 - # via - # jupyterlab - # notebook numpy==2.3.1 # via # temoa (pyproject.toml) @@ -276,105 +40,31 @@ numpy==2.3.1 # highspy # matplotlib # pandas - # pyam-iamc # pydoe # salib # scipy # seaborn - # wquantiles openpyxl==3.1.5 - # via - # temoa (pyproject.toml) - # ixmp4 - # pyam-iamc -overrides==7.7.0 - # via jupyter-server + # via temoa (pyproject.toml) packaging==25.0 # via - # ipykernel - # jupyter-events - # jupyter-server - # jupyterlab - # jupyterlab-server # matplotlib - # nbconvert - # pandera # pytest pandas==2.3.1 # via # temoa (pyproject.toml) - # ixmp4 - # pyam-iamc # salib # seaborn -pandera==0.25.0 - # via ixmp4 -pandocfilters==1.5.1 - # via nbconvert -parso==0.8.4 - # via jedi -pathspec==0.12.1 - # via mypy -pexpect==4.9.0 - # via ipython pillow==11.3.0 # via matplotlib -pint==0.24.4 - # via - # iam-units - # pyam-iamc -platformdirs==4.3.8 - # via - # jupyter-core - # pint pluggy==1.6.0 # via pytest ply==3.11 # via pyomo -prometheus-client==0.22.1 - # via jupyter-server -prompt-toolkit==3.0.51 - # via - # ipython - # jupyter-console -psutil==7.0.0 - # via ipykernel -psycopg==3.2.9 - # via ixmp4 -psycopg-binary==3.2.9 - # via psycopg -ptyprocess==0.7.0 - # via - # pexpect - # terminado -pure-eval==0.2.3 - # via stack-data -pyam-iamc==3.0.0 - # via temoa (pyproject.toml) -pycparser==2.22 - # via cffi -pydantic==2.11.7 - # via - # fastapi - # ixmp4 - # pandera - # pydantic-settings -pydantic-core==2.33.2 - # via pydantic -pydantic-settings==2.10.1 - # via ixmp4 pydoe==0.3.8 # via temoa (pyproject.toml) pygments==2.19.2 - # via - # ipython - # ipython-pygments-lexers - # jupyter-console - # nbconvert - # pytest - # rich -pyjwt==2.10.1 - # via ixmp4 + # via pytest pyomo==6.9.2 # via temoa (pyproject.toml) pyparsing==3.2.3 @@ -383,197 +73,30 @@ pytest==8.4.1 # via temoa (pyproject.toml) python-dateutil==2.9.0.post0 # via - # arrow - # jupyter-client # matplotlib # pandas -python-dotenv==1.1.1 - # via - # ixmp4 - # pydantic-settings -python-json-logger==3.3.0 - # via jupyter-events pytz==2025.2 # via pandas pyutilib==6.0.0 # via temoa (pyproject.toml) -pyyaml==6.0.2 - # via - # jupyter-events - # jupyter-nbextensions-configurator - # pyam-iamc -pyzmq==27.0.0 - # via - # ipykernel - # jupyter-client - # jupyter-console - # jupyter-server -referencing==0.36.2 - # via - # jsonschema - # jsonschema-specifications - # jupyter-events -requests==2.32.4 - # via - # jupyterlab-server - # pyam-iamc -rfc3339-validator==0.1.4 - # via - # jsonschema - # jupyter-events -rfc3986-validator==0.1.1 - # via - # jsonschema - # jupyter-events -rich==14.0.0 - # via - # ixmp4 - # typer -rpds-py==0.26.0 - # via - # jsonschema - # referencing salib==1.5.1 # via temoa (pyproject.toml) scipy==1.16.0 # via # temoa (pyproject.toml) - # pyam-iamc # pydoe # salib seaborn==0.13.2 - # via - # temoa (pyproject.toml) - # pyam-iamc -send2trash==1.8.3 - # via jupyter-server -setuptools==80.9.0 - # via - # jupyter-contrib-core - # jupyterlab -shellingham==1.5.4 - # via typer + # via temoa (pyproject.toml) six==1.17.0 # via # python-dateutil # pyutilib - # rfc3339-validator -sniffio==1.3.1 - # via anyio -soupsieve==2.7 - # via beautifulsoup4 -sqlalchemy==2.0.41 - # via - # alembic - # ixmp4 - # sqlalchemy-continuum - # sqlalchemy-utils -sqlalchemy-continuum==1.4.2 - # via ixmp4 -sqlalchemy-utils==0.41.2 - # via - # ixmp4 - # sqlalchemy-continuum -stack-data==0.6.3 - # via ipython -starlette==0.47.1 - # via fastapi tabulate==0.9.0 # via temoa (pyproject.toml) -terminado==0.18.1 - # via - # jupyter-server - # jupyter-server-terminals -tinycss2==1.4.0 - # via bleach -toml==0.10.2 - # via ixmp4 -tornado==6.5.1 - # via - # ipykernel - # jupyter-client - # jupyter-contrib-core - # jupyter-contrib-nbextensions - # jupyter-nbextensions-configurator - # jupyter-server - # jupyterlab - # notebook - # terminado -traitlets==5.14.3 - # via - # comm - # ipykernel - # ipython - # ipywidgets - # jupyter-client - # jupyter-console - # jupyter-contrib-core - # jupyter-contrib-nbextensions - # jupyter-core - # jupyter-events - # jupyter-nbextensions-configurator - # jupyter-server - # jupyterlab - # matplotlib-inline - # nbclient - # nbconvert - # nbformat -typeguard==4.4.4 - # via pandera -typer==0.16.0 - # via ixmp4 -types-python-dateutil==2.9.0.20250708 - # via arrow -typing-extensions==4.14.1 - # via - # alembic - # anyio - # beautifulsoup4 - # fastapi - # flexcache - # flexparser - # mypy - # pandera - # pint - # psycopg - # pydantic - # pydantic-core - # referencing - # sqlalchemy - # starlette - # typeguard - # typer - # typing-inspect - # typing-inspection -typing-inspect==0.9.0 - # via pandera -typing-inspection==0.4.1 - # via - # pydantic - # pydantic-settings tzdata==2025.2 # via pandas -uri-template==1.3.0 - # via jsonschema -urllib3==2.5.0 - # via requests -wcwidth==0.2.13 - # via prompt-toolkit -webcolors==24.11.1 - # via jsonschema -webencodings==0.5.1 - # via - # bleach - # tinycss2 -websocket-client==1.8.0 - # via jupyter-server -widgetsnbextension==4.0.14 - # via ipywidgets -wquantiles==0.6 - # via pyam-iamc wrapt==1.17.2 # via deprecated xlsxwriter==3.2.5 - # via - # temoa (pyproject.toml) - # pyam-iamc + # via temoa (pyproject.toml) diff --git a/temoa/data_processing/db_to_excel.py b/temoa/data_processing/db_to_excel.py index acf3a19a3..64c0a9ff9 100644 --- a/temoa/data_processing/db_to_excel.py +++ b/temoa/data_processing/db_to_excel.py @@ -1,11 +1,11 @@ """ This script processes a Temoa database file (SQLite) and converts the data into two Excel formats: one for human-readable analysis and another -compatible with the pyam library for integrated assessment modeling. +compatible with the IAMC format for integrated assessment modeling. The script extracts capacity, activity, emissions, and cost data for a specified scenario, formats it, and saves it to separate sheets in an -Excel workbook. It also creates an aggregated `pyam`-compatible Excel file. +Excel workbook. It also creates an aggregated IAMC-compatible Excel file. Usage: python db_to_excel.py -i -s [-o ] @@ -19,116 +19,131 @@ from pathlib import Path import pandas as pd -from pyam import IamDataFrame +from pandas import DataFrame -def make_excel(ifile, ofile: Path, scenario): +def make_excel(ifile: str | None, ofile: Path | None, scenario: set[str]) -> None: + """ + Processes a Temoa database to produce human-readable and IAMC-format + Excel files. + """ if ifile is None: raise ValueError("You did not specify the input file. Remember to use the '-i' option.") - file_type = re.search(r'(\w+)\.(\w+)\b', ifile) # Extract the input filename and extension - if not file_type: - print('The file type %s is not recognized. Use a db file.' % ifile) + file_match = re.search(r'(\w+)\.(\w+)\b', ifile) + if not file_match: + print(f'The file type {ifile} is not recognized. Use a .db file.') sys.exit(2) + if ofile is None: - ofile = file_type.group(1) - print('Look for output in %s_*.xls' % ofile) + ofile = Path(file_match.group(1)) + print(f'Look for output in {ofile}_*.xlsx') con = sqlite3.connect(ifile) - cur = con.cursor() # a database cursor is a control structure that enables traversal over the records in a database - con.text_factory = str # this ensures data is explored with the correct UTF-8 encoding - scenario = scenario.pop() + con.text_factory = str + scenario_name = scenario.pop() ofile = ofile.with_suffix('.xlsx') + writer = pd.ExcelWriter( - ofile, engine='xlsxwriter', engine_kwargs={'options': {'strings_to_formulas': False}} + ofile, + engine='xlsxwriter', + engine_kwargs={'options': {'strings_to_formulas': False}}, ) - workbook = writer.book - - header_format = workbook.add_format( - { - 'bold': True, - 'text_wrap': True, - 'align': 'left', - } - ) - - query = 'SELECT DISTINCT Efficiency.region, Efficiency.tech, Technology.sector FROM Efficiency \ - INNER JOIN Technology ON Efficiency.tech=Technology.tech' - all_techs = pd.read_sql_query(query, con) - - query = f"SELECT region, tech, sector, period, sum(capacity) as capacity FROM OutputNetCapacity WHERE scenario= '{scenario}' GROUP BY region, tech, sector, period" - df_capacity = pd.read_sql_query(query, con) + header_format = workbook.add_format({'bold': True, 'text_wrap': True, 'align': 'left'}) + + query_all_techs = """ + SELECT DISTINCT Efficiency.region, Efficiency.tech, Technology.sector + FROM Efficiency + INNER JOIN Technology ON Efficiency.tech = Technology.tech + """ + all_techs = pd.read_sql_query(query_all_techs, con) + + query_capacity = f""" + SELECT region, tech, sector, period, SUM(capacity) as capacity + FROM OutputNetCapacity WHERE scenario = '{scenario_name}' + GROUP BY region, tech, sector, period + """ + df_capacity = pd.read_sql_query(query_capacity, con) for sector in sorted(df_capacity['sector'].unique()): - df_capacity_sector = df_capacity[df_capacity['sector'] == sector] - df_capacity_sector = df_capacity_sector.drop(columns=['sector']).pivot_table( - values='capacity', index=['region', 'tech'], columns='period' + df_sector = ( + df_capacity[df_capacity['sector'] == sector] + .drop(columns=['sector']) + .pivot_table(values='capacity', index=['region', 'tech'], columns='period') + .reset_index() ) - df_capacity_sector.reset_index(inplace=True) sector_techs = all_techs[all_techs['sector'] == sector] - df_capacity_sector = pd.merge( - sector_techs[['region', 'tech']], df_capacity_sector, on=['region', 'tech'], how='left' - ) - df_capacity_sector.rename(columns={'region': 'Region', 'tech': 'Technology'}, inplace=True) - df_capacity_sector.to_excel( - writer, sheet_name='Capacity_' + sector, index=False, startrow=1, header=False + df_sector = pd.merge( + sector_techs[['region', 'tech']], + df_sector, + on=['region', 'tech'], + how='left', ) - worksheet = writer.sheets['Capacity_' + sector] + df_sector.rename(columns={'region': 'Region', 'tech': 'Technology'}, inplace=True) + sheet_name = f'Capacity_{sector}' + df_sector.to_excel(writer, sheet_name=sheet_name, index=False, startrow=1, header=False) + worksheet = writer.sheets[sheet_name] worksheet.set_column('A:A', 10) worksheet.set_column('B:B', 10) - for col, val in enumerate(df_capacity_sector.columns.values): + for col, val in enumerate(df_sector.columns.values): worksheet.write(0, col, val, header_format) - query = ( - "SELECT region, tech, sector, period, sum(flow) as vflow_out FROM OutputFlowOut WHERE scenario='" - + scenario - + "' GROUP BY \ - region, tech, sector, period" - ) - df_activity = pd.read_sql_query(query, con) + query_activity = f""" + SELECT region, tech, sector, period, SUM(flow) as vflow_out + FROM OutputFlowOut WHERE scenario = '{scenario_name}' + GROUP BY region, tech, sector, period + """ + df_activity = pd.read_sql_query(query_activity, con) for sector in sorted(df_activity['sector'].unique()): - df_activity_sector = df_activity[df_activity['sector'] == sector] - df_activity_sector = df_activity_sector.drop(columns=['sector']).pivot_table( - values='vflow_out', index=['region', 'tech'], columns='period' + df_sector = ( + df_activity[df_activity['sector'] == sector] + .drop(columns=['sector']) + .pivot_table(values='vflow_out', index=['region', 'tech'], columns='period') + .reset_index() ) - df_activity_sector.reset_index(inplace=True) sector_techs = all_techs[all_techs['sector'] == sector] - df_activity_sector = pd.merge( - sector_techs[['region', 'tech']], df_activity_sector, on=['region', 'tech'], how='left' + df_sector = pd.merge( + sector_techs[['region', 'tech']], + df_sector, + on=['region', 'tech'], + how='left', ) - df_activity_sector.rename(columns={'region': 'Region', 'tech': 'Technology'}, inplace=True) - df_activity_sector.to_excel( - writer, sheet_name='Activity_' + sector, index=False, startrow=1, header=False - ) - worksheet = writer.sheets['Activity_' + sector] + df_sector.rename(columns={'region': 'Region', 'tech': 'Technology'}, inplace=True) + sheet_name = f'Activity_{sector}' + df_sector.to_excel(writer, sheet_name=sheet_name, index=False, startrow=1, header=False) + worksheet = writer.sheets[sheet_name] worksheet.set_column('A:A', 10) worksheet.set_column('B:B', 10) - for col, val in enumerate(df_activity_sector.columns.values): + for col, val in enumerate(df_sector.columns.values): worksheet.write(0, col, val, header_format) - query = ( - 'SELECT DISTINCT EmissionActivity.region, EmissionActivity.tech, EmissionActivity.emis_comm, Technology.sector FROM EmissionActivity \ - INNER JOIN Technology ON EmissionActivity.tech=Technology.tech' - ) + query_all_emis = """ + SELECT DISTINCT ea.region, ea.tech, ea.emis_comm, t.sector + FROM EmissionActivity ea + INNER JOIN Technology t ON ea.tech = t.tech + """ try: - all_emis_techs = pd.read_sql_query(query, con) + all_emis_techs = pd.read_sql_query(query_all_emis, con) except sqlite3.OperationalError: all_emis_techs = pd.DataFrame() - query = ( - "SELECT region, tech, sector, period, emis_comm, sum(emission) as emissions FROM OutputEmission WHERE scenario='" - + scenario - + "' GROUP BY \ - region, tech, sector, period, emis_comm" - ) - df_emissions_raw = pd.read_sql_query(query, con) + query_emissions = f""" + SELECT region, tech, sector, period, emis_comm, SUM(emission) as emissions + FROM OutputEmission WHERE scenario = '{scenario_name}' + GROUP BY region, tech, sector, period, emis_comm + """ + df_emissions_raw = pd.read_sql_query(query_emissions, con) if not df_emissions_raw.empty: df_emissions = df_emissions_raw.pivot_table( - values='emissions', index=['region', 'tech', 'sector', 'emis_comm'], columns='period' - ) - df_emissions.reset_index(inplace=True) + values='emissions', + index=['region', 'tech', 'sector', 'emis_comm'], + columns='period', + ).reset_index() df_emissions = pd.merge( - all_emis_techs, df_emissions, on=['region', 'tech', 'sector', 'emis_comm'], how='left' + all_emis_techs, + df_emissions, + on=['region', 'tech', 'sector', 'emis_comm'], + how='left', ) df_emissions.rename( columns={ @@ -148,12 +163,14 @@ def make_excel(ifile, ofile: Path, scenario): for col, val in enumerate(df_emissions.columns.values): worksheet.write(0, col, val, header_format) - query = ( - 'SELECT region, OutputCost.tech, Technology.sector, vintage, d_invest + d_var + d_fixed + d_emiss FROM OutputCost ' - ' JOIN main.Technology ON OutputCost.tech = main.Technology.tech ' - f" WHERE scenario = '{scenario}'" - ) - df_costs = pd.read_sql_query(query, con) + query_costs = f""" + SELECT region, oc.tech, t.sector, vintage, + d_invest + d_var + d_fixed + d_emiss as cost + FROM OutputCost oc + JOIN Technology t ON oc.tech = t.tech + WHERE scenario = '{scenario_name}' + """ + df_costs = pd.read_sql_query(query_costs, con) df_costs.columns = ['Region', 'Technology', 'Sector', 'Vintage', 'Cost'] df_costs.to_excel(writer, sheet_name='Costs', index=False, startrow=1, header=False) worksheet = writer.sheets['Costs'] @@ -166,82 +183,98 @@ def make_excel(ifile, ofile: Path, scenario): writer.close() - # prepare results for IamDataFrame - df_emissions_raw['scenario'] = scenario - df_emissions_raw['unit'] = '?' df_emissions_raw['variable'] = ( 'Emissions|' + df_emissions_raw['emis_comm'] + '|' + df_emissions_raw['tech'] ) - df_emissions_raw.rename(columns={'period': 'year', 'emissions': 'value'}, inplace=True) + df_emissions_iamc = df_emissions_raw.rename(columns={'period': 'year', 'emissions': 'value'}) - df_capacity['scenario'] = scenario - df_capacity['unit'] = '?' df_capacity['variable'] = 'Capacity|' + df_capacity['sector'] + '|' + df_capacity['tech'] - df_capacity.rename(columns={'period': 'year', 'capacity': 'value'}, inplace=True) + df_capacity_iamc = df_capacity.rename(columns={'period': 'year', 'capacity': 'value'}) - df_activity['scenario'] = scenario - df_activity['unit'] = '?' df_activity['variable'] = 'Activity|' + df_activity['sector'] + '|' + df_activity['tech'] - df_activity.rename(columns={'period': 'year', 'vflow_out': 'value'}, inplace=True) - - # cast results to IamDataFrame and write to xlsx - columns = ['scenario', 'region', 'variable', 'year', 'value', 'unit'] - _results = pd.concat([df_emissions_raw[columns], df_activity[columns], df_capacity[columns]]) - df = IamDataFrame(_results, model='Temoa') - - emiss = df_emissions_raw['emis_comm'].unique() - sector = df_capacity['sector'].unique() - - # adding aggregates of emissions for each species - df.aggregate([f'Emissions|{q}' for q in emiss], append=True) - - # adding aggregates of activity/capacity for each sector - prod = itertools.product(['Activity', 'Capacity'], sector) - df.aggregate([f'{t}|{s}' for t, s in prod], append=True) - - # write IamDataFrame to xlsx - base_name = ofile.name.split('.')[0] - excel_pyam_filename = ofile.with_name(base_name + '_pyam.xlsx') - df.to_excel(excel_pyam_filename) + df_activity_iamc = df_activity.rename(columns={'period': 'year', 'vflow_out': 'value'}) + + iamc_columns = ['region', 'variable', 'year', 'value'] + df_iamc = pd.concat( + [ + df_emissions_iamc[iamc_columns], + df_activity_iamc[iamc_columns], + df_capacity_iamc[iamc_columns], + ], + ignore_index=True, + ) + df_iamc['unit'] = '?' + df_iamc['scenario'] = scenario_name + + aggregates_to_add: list[DataFrame] = [] + grouping_cols = ['scenario', 'region', 'year', 'unit'] + + emiss_types = df_emissions_raw['emis_comm'].unique() + for emiss in emiss_types: + new_variable_name = f'Emissions|{emiss}' + mask = df_iamc['variable'].str.startswith(f'{new_variable_name}|') + if mask.any(): + agg = df_iamc[mask].groupby(grouping_cols, as_index=False).sum(numeric_only=True) + agg['variable'] = new_variable_name + aggregates_to_add.append(agg) + + sector_types = df_capacity['sector'].unique() + for var_type, sector in itertools.product(['Activity', 'Capacity'], sector_types): + new_variable_name = f'{var_type}|{sector}' + mask = df_iamc['variable'].str.startswith(f'{new_variable_name}|') + if mask.any(): + agg = df_iamc[mask].groupby(grouping_cols, as_index=False).sum(numeric_only=True) + agg['variable'] = new_variable_name + aggregates_to_add.append(agg) + + if aggregates_to_add: + df_final_iamc = pd.concat([df_iamc, *aggregates_to_add], ignore_index=True) + else: + df_final_iamc = df_iamc + + df_final_iamc['model'] = 'Temoa' + final_cols = ['model', 'scenario', 'region', 'variable', 'unit', 'year', 'value'] + df_final_iamc = df_final_iamc[final_cols] + + base_name = ofile.stem + excel_pyam_filename = ofile.with_name(f'{base_name}_pyam.xlsx') + df_final_iamc.to_excel(excel_pyam_filename, index=False) - cur.close() con.close() -def get_data(inputs): - ifile = None - ofile = None - scenario = set() - - if not inputs: - raise ValueError('No arguments found') +def get_data(inputs: dict[str, str]) -> None: + """Parses command-line arguments and calls the main excel creation function.""" + ifile = inputs.get('-i') or inputs.get('--input') + ofile_str = inputs.get('-o') or inputs.get('--output') + ofile = Path(ofile_str) if ofile_str else None + scenario = {s for k, s in inputs.items() if k in ('-s', '--scenario')} - for opt, arg in inputs.items(): - if opt in ('-i', '--input'): - ifile = arg - elif opt in ('-o', '--output'): - ofile = arg - elif opt in ('-s', '--scenario'): - scenario.add(arg) - elif opt in ('-h', '--help'): - print( - 'Use as :\n python db_to_excel.py -i (Optional -o )\n Use -h for help.' - ) - sys.exit() + if not scenario: + raise ValueError("You must specify a scenario with the '-s' option.") make_excel(ifile, ofile, scenario) if __name__ == '__main__': try: - argv = sys.argv[1:] - opts, args = getopt.getopt(argv, 'hi:o:s:', ['help', 'input=', 'output=', 'scenario=']) - except getopt.GetoptError: - print( - "Something's Wrong. Use as :\n python db_to_excel.py -i (Optional -o )\n Use -h for help." + opts, _ = getopt.getopt( + sys.argv[1:], + 'hi:o:s:', + ['help', 'input=', 'output=', 'scenario='], ) + except getopt.GetoptError as err: + print(err) + print('Use -h or --help for usage instructions.') sys.exit(2) - print(opts) + opts_dict = dict(opts) + if '-h' in opts_dict or '--help' in opts_dict: + print(__doc__) + sys.exit() - get_data(dict(opts)) + try: + get_data(opts_dict) + except (ValueError, FileNotFoundError) as e: + print(f'Error: {e}') + sys.exit(2) diff --git a/uv.lock b/uv.lock index 2a89e8614..14ae00565 100644 --- a/uv.lock +++ b/uv.lock @@ -11,125 +11,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929, upload-time = "2024-07-26T18:15:02.05Z" }, ] -[[package]] -name = "alembic" -version = "1.16.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mako" }, - { name = "sqlalchemy" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/83/52/72e791b75c6b1efa803e491f7cbab78e963695e76d4ada05385252927e76/alembic-1.16.4.tar.gz", hash = "sha256:efab6ada0dd0fae2c92060800e0bf5c1dc26af15a10e02fb4babff164b4725e2", size = 1968161, upload-time = "2025-07-10T16:17:20.192Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/62/96b5217b742805236614f05904541000f55422a6060a90d7fd4ce26c172d/alembic-1.16.4-py3-none-any.whl", hash = "sha256:b05e51e8e82efc1abd14ba2af6392897e145930c3e0a2faf2b0da2f7f7fd660d", size = 247026, upload-time = "2025-07-10T16:17:21.845Z" }, -] - -[[package]] -name = "annotated-types" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, -] - -[[package]] -name = "anyio" -version = "4.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, - { name = "sniffio" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949, upload-time = "2025-03-17T00:02:54.77Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916, upload-time = "2025-03-17T00:02:52.713Z" }, -] - -[[package]] -name = "appnope" -version = "0.1.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170, upload-time = "2024-02-06T09:43:11.258Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321, upload-time = "2024-02-06T09:43:09.663Z" }, -] - -[[package]] -name = "argon2-cffi" -version = "25.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "argon2-cffi-bindings" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706, upload-time = "2025-06-03T06:55:32.073Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741", size = 14657, upload-time = "2025-06-03T06:55:30.804Z" }, -] - -[[package]] -name = "argon2-cffi-bindings" -version = "21.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b9/e9/184b8ccce6683b0aa2fbb7ba5683ea4b9c5763f1356347f1312c32e3c66e/argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3", size = 1779911, upload-time = "2021-12-01T08:52:55.68Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/13/838ce2620025e9666aa8f686431f67a29052241692a3dd1ae9d3692a89d3/argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367", size = 29658, upload-time = "2021-12-01T09:09:17.016Z" }, - { url = "https://files.pythonhosted.org/packages/b3/02/f7f7bb6b6af6031edb11037639c697b912e1dea2db94d436e681aea2f495/argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d", size = 80583, upload-time = "2021-12-01T09:09:19.546Z" }, - { url = "https://files.pythonhosted.org/packages/ec/f7/378254e6dd7ae6f31fe40c8649eea7d4832a42243acaf0f1fff9083b2bed/argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae", size = 86168, upload-time = "2021-12-01T09:09:21.445Z" }, - { url = "https://files.pythonhosted.org/packages/74/f6/4a34a37a98311ed73bb80efe422fed95f2ac25a4cacc5ae1d7ae6a144505/argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c", size = 82709, upload-time = "2021-12-01T09:09:18.182Z" }, - { url = "https://files.pythonhosted.org/packages/74/2b/73d767bfdaab25484f7e7901379d5f8793cccbb86c6e0cbc4c1b96f63896/argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86", size = 83613, upload-time = "2021-12-01T09:09:22.741Z" }, - { url = "https://files.pythonhosted.org/packages/4f/fd/37f86deef67ff57c76f137a67181949c2d408077e2e3dd70c6c42912c9bf/argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f", size = 84583, upload-time = "2021-12-01T09:09:24.177Z" }, - { url = "https://files.pythonhosted.org/packages/6f/52/5a60085a3dae8fded8327a4f564223029f5f54b0cb0455a31131b5363a01/argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e", size = 88475, upload-time = "2021-12-01T09:09:26.673Z" }, - { url = "https://files.pythonhosted.org/packages/8b/95/143cd64feb24a15fa4b189a3e1e7efbaeeb00f39a51e99b26fc62fbacabd/argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082", size = 27698, upload-time = "2021-12-01T09:09:27.87Z" }, - { url = "https://files.pythonhosted.org/packages/37/2c/e34e47c7dee97ba6f01a6203e0383e15b60fb85d78ac9a15cd066f6fe28b/argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f", size = 30817, upload-time = "2021-12-01T09:09:30.267Z" }, - { url = "https://files.pythonhosted.org/packages/5a/e4/bf8034d25edaa495da3c8a3405627d2e35758e44ff6eaa7948092646fdcc/argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93", size = 53104, upload-time = "2021-12-01T09:09:31.335Z" }, -] - -[[package]] -name = "arrow" -version = "1.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "python-dateutil" }, - { name = "types-python-dateutil" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2e/00/0f6e8fcdb23ea632c866620cc872729ff43ed91d284c866b515c6342b173/arrow-1.3.0.tar.gz", hash = "sha256:d4540617648cb5f895730f1ad8c82a65f2dad0166f57b75f3ca54759c4d67a85", size = 131960, upload-time = "2023-09-30T22:11:18.25Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/ed/e97229a566617f2ae958a6b13e7cc0f585470eac730a73e9e82c32a3cdd2/arrow-1.3.0-py3-none-any.whl", hash = "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80", size = 66419, upload-time = "2023-09-30T22:11:16.072Z" }, -] - -[[package]] -name = "asttokens" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4a/e7/82da0a03e7ba5141f05cce0d302e6eed121ae055e0456ca228bf693984bc/asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", size = 61978, upload-time = "2024-11-30T04:30:14.439Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918, upload-time = "2024-11-30T04:30:10.946Z" }, -] - -[[package]] -name = "async-lru" -version = "2.0.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/4d/71ec4d3939dc755264f680f6c2b4906423a304c3d18e96853f0a595dfe97/async_lru-2.0.5.tar.gz", hash = "sha256:481d52ccdd27275f42c43a928b4a50c3bfb2d67af4e78b170e3e0bb39c66e5bb", size = 10380, upload-time = "2025-03-16T17:25:36.919Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/03/49/d10027df9fce941cb8184e78a02857af36360d33e1721df81c5ed2179a1a/async_lru-2.0.5-py3-none-any.whl", hash = "sha256:ab95404d8d2605310d345932697371a5f40def0487c03d6d0ad9138de52c9943", size = 6069, upload-time = "2025-03-16T17:25:35.422Z" }, -] - -[[package]] -name = "attrs" -version = "25.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, -] - [[package]] name = "babel" version = "2.17.0" @@ -139,36 +20,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, ] -[[package]] -name = "beautifulsoup4" -version = "4.13.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "soupsieve" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d8/e4/0c4c39e18fd76d6a628d4dd8da40543d136ce2d1752bd6eeeab0791f4d6b/beautifulsoup4-4.13.4.tar.gz", hash = "sha256:dbb3c4e1ceae6aefebdaf2423247260cd062430a410e38c66f2baa50a8437195", size = 621067, upload-time = "2025-04-15T17:05:13.836Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/50/cd/30110dc0ffcf3b131156077b90e9f60ed75711223f306da4db08eff8403b/beautifulsoup4-4.13.4-py3-none-any.whl", hash = "sha256:9bbbb14bfde9d79f38b8cd5f8c7c85f4b8f2523190ebed90e950a8dea4cb1c4b", size = 187285, upload-time = "2025-04-15T17:05:12.221Z" }, -] - -[[package]] -name = "bleach" -version = "6.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "webencodings" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/76/9a/0e33f5054c54d349ea62c277191c020c2d6ef1d65ab2cb1993f91ec846d1/bleach-6.2.0.tar.gz", hash = "sha256:123e894118b8a599fd80d3ec1a6d4cc7ce4e5882b1317a7e1ba69b56e95f991f", size = 203083, upload-time = "2024-10-29T18:30:40.477Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/55/96142937f66150805c25c4d0f31ee4132fd33497753400734f9dfdcbdc66/bleach-6.2.0-py3-none-any.whl", hash = "sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e", size = 163406, upload-time = "2024-10-29T18:30:38.186Z" }, -] - -[package.optional-dependencies] -css = [ - { name = "tinycss2" }, -] - [[package]] name = "certifi" version = "2025.7.14" @@ -178,39 +29,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4f/52/34c6cf5bb9285074dc3531c437b3919e825d976fde097a7a73f79e726d03/certifi-2025.7.14-py3-none-any.whl", hash = "sha256:6b31f564a415d79ee77df69d757bb49a5bb53bd9f756cbbe24394ffd6fc1f4b2", size = 162722, upload-time = "2025-07-14T03:29:26.863Z" }, ] -[[package]] -name = "cffi" -version = "1.17.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pycparser" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621, upload-time = "2024-09-04T20:45:21.852Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178, upload-time = "2024-09-04T20:44:12.232Z" }, - { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840, upload-time = "2024-09-04T20:44:13.739Z" }, - { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803, upload-time = "2024-09-04T20:44:15.231Z" }, - { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850, upload-time = "2024-09-04T20:44:17.188Z" }, - { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729, upload-time = "2024-09-04T20:44:18.688Z" }, - { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256, upload-time = "2024-09-04T20:44:20.248Z" }, - { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424, upload-time = "2024-09-04T20:44:21.673Z" }, - { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568, upload-time = "2024-09-04T20:44:23.245Z" }, - { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736, upload-time = "2024-09-04T20:44:24.757Z" }, - { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448, upload-time = "2024-09-04T20:44:26.208Z" }, - { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976, upload-time = "2024-09-04T20:44:27.578Z" }, - { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989, upload-time = "2024-09-04T20:44:28.956Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802, upload-time = "2024-09-04T20:44:30.289Z" }, - { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792, upload-time = "2024-09-04T20:44:32.01Z" }, - { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893, upload-time = "2024-09-04T20:44:33.606Z" }, - { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810, upload-time = "2024-09-04T20:44:35.191Z" }, - { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200, upload-time = "2024-09-04T20:44:36.743Z" }, - { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447, upload-time = "2024-09-04T20:44:38.492Z" }, - { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358, upload-time = "2024-09-04T20:44:40.046Z" }, - { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469, upload-time = "2024-09-04T20:44:41.616Z" }, - { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475, upload-time = "2024-09-04T20:44:43.733Z" }, - { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009, upload-time = "2024-09-04T20:44:45.309Z" }, -] - [[package]] name = "cfgv" version = "3.4.0" @@ -255,18 +73,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, ] -[[package]] -name = "click" -version = "8.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" }, -] - [[package]] name = "colorama" version = "0.4.6" @@ -276,18 +82,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] -[[package]] -name = "comm" -version = "0.2.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e9/a8/fb783cb0abe2b5fded9f55e5703015cdf1c9c85b3669087c538dd15a6a86/comm-0.2.2.tar.gz", hash = "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e", size = 6210, upload-time = "2024-03-12T16:53:41.133Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/75/49e5bfe642f71f272236b5b2d2691cf915a7283cc0ceda56357b61daa538/comm-0.2.2-py3-none-any.whl", hash = "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3", size = 7180, upload-time = "2024-03-12T16:53:39.226Z" }, -] - [[package]] name = "contourpy" version = "1.3.2" @@ -380,41 +174,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, ] -[[package]] -name = "debugpy" -version = "1.8.15" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/3a9a28ddb750a76eaec445c7f4d3147ea2c579a97dbd9e25d39001b92b21/debugpy-1.8.15.tar.gz", hash = "sha256:58d7a20b7773ab5ee6bdfb2e6cf622fdf1e40c9d5aef2857d85391526719ac00", size = 1643279, upload-time = "2025-07-15T16:43:29.135Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/4a/4508d256e52897f5cdfee6a6d7580974811e911c6d01321df3264508a5ac/debugpy-1.8.15-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:3dcc7225cb317469721ab5136cda9ff9c8b6e6fb43e87c9e15d5b108b99d01ba", size = 2511197, upload-time = "2025-07-15T16:43:42.343Z" }, - { url = "https://files.pythonhosted.org/packages/99/8d/7f6ef1097e7fecf26b4ef72338d08e41644a41b7ee958a19f494ffcffc29/debugpy-1.8.15-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:047a493ca93c85ccede1dbbaf4e66816794bdc214213dde41a9a61e42d27f8fc", size = 4229517, upload-time = "2025-07-15T16:43:44.14Z" }, - { url = "https://files.pythonhosted.org/packages/3f/e8/e8c6a9aa33a9c9c6dacbf31747384f6ed2adde4de2e9693c766bdf323aa3/debugpy-1.8.15-cp312-cp312-win32.whl", hash = "sha256:b08e9b0bc260cf324c890626961dad4ffd973f7568fbf57feb3c3a65ab6b6327", size = 5276132, upload-time = "2025-07-15T16:43:45.529Z" }, - { url = "https://files.pythonhosted.org/packages/e9/ad/231050c6177b3476b85fcea01e565dac83607b5233d003ff067e2ee44d8f/debugpy-1.8.15-cp312-cp312-win_amd64.whl", hash = "sha256:e2a4fe357c92334272eb2845fcfcdbec3ef9f22c16cf613c388ac0887aed15fa", size = 5317645, upload-time = "2025-07-15T16:43:46.968Z" }, - { url = "https://files.pythonhosted.org/packages/28/70/2928aad2310726d5920b18ed9f54b9f06df5aa4c10cf9b45fa18ff0ab7e8/debugpy-1.8.15-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:f5e01291ad7d6649aed5773256c5bba7a1a556196300232de1474c3c372592bf", size = 2495538, upload-time = "2025-07-15T16:43:48.927Z" }, - { url = "https://files.pythonhosted.org/packages/9e/c6/9b8ffb4ca91fac8b2877eef63c9cc0e87dd2570b1120054c272815ec4cd0/debugpy-1.8.15-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94dc0f0d00e528d915e0ce1c78e771475b2335b376c49afcc7382ee0b146bab6", size = 4221874, upload-time = "2025-07-15T16:43:50.282Z" }, - { url = "https://files.pythonhosted.org/packages/55/8a/9b8d59674b4bf489318c7c46a1aab58e606e583651438084b7e029bf3c43/debugpy-1.8.15-cp313-cp313-win32.whl", hash = "sha256:fcf0748d4f6e25f89dc5e013d1129ca6f26ad4da405e0723a4f704583896a709", size = 5275949, upload-time = "2025-07-15T16:43:52.079Z" }, - { url = "https://files.pythonhosted.org/packages/72/83/9e58e6fdfa8710a5e6ec06c2401241b9ad48b71c0a7eb99570a1f1edb1d3/debugpy-1.8.15-cp313-cp313-win_amd64.whl", hash = "sha256:73c943776cb83e36baf95e8f7f8da765896fd94b05991e7bc162456d25500683", size = 5317720, upload-time = "2025-07-15T16:43:53.703Z" }, - { url = "https://files.pythonhosted.org/packages/07/d5/98748d9860e767a1248b5e31ffa7ce8cb7006e97bf8abbf3d891d0a8ba4e/debugpy-1.8.15-py2.py3-none-any.whl", hash = "sha256:bce2e6c5ff4f2e00b98d45e7e01a49c7b489ff6df5f12d881c67d2f1ac635f3d", size = 5282697, upload-time = "2025-07-15T16:44:07.996Z" }, -] - -[[package]] -name = "decorator" -version = "5.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, -] - -[[package]] -name = "defusedxml" -version = "0.7.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, -] - [[package]] name = "deprecated" version = "1.2.18" @@ -463,38 +222,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c1/8b/5fe2cc11fee489817272089c4203e679c63b570a5aaeb18d852ae3cbba6a/et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa", size = 18059, upload-time = "2024-10-25T17:25:39.051Z" }, ] -[[package]] -name = "executing" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/91/50/a9d80c47ff289c611ff12e63f7c5d13942c65d68125160cefd768c73e6e4/executing-2.2.0.tar.gz", hash = "sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755", size = 978693, upload-time = "2025-01-22T15:41:29.403Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa", size = 26702, upload-time = "2025-01-22T15:41:25.929Z" }, -] - -[[package]] -name = "fastapi" -version = "0.116.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "starlette" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/78/d7/6c8b3bfe33eeffa208183ec037fee0cce9f7f024089ab1c5d12ef04bd27c/fastapi-0.116.1.tar.gz", hash = "sha256:ed52cbf946abfd70c5a0dccb24673f0670deeb517a88b3544d03c2a6bf283143", size = 296485, upload-time = "2025-07-11T16:22:32.057Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/47/d63c60f59a59467fda0f93f46335c9d18526d7071f025cb5b89d5353ea42/fastapi-0.116.1-py3-none-any.whl", hash = "sha256:c46ac7c312df840f0c9e220f7964bada936781bc4e2e6eb71f1c4d7553786565", size = 95631, upload-time = "2025-07-11T16:22:30.485Z" }, -] - -[[package]] -name = "fastjsonschema" -version = "2.21.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8b/50/4b769ce1ac4071a1ef6d86b1a3fb56cdc3a37615e8c5519e1af96cdac366/fastjsonschema-2.21.1.tar.gz", hash = "sha256:794d4f0a58f848961ba16af7b9c85a3e88cd360df008c59aac6fc5ae9323b5d4", size = 373939, upload-time = "2024-12-02T10:55:15.133Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/90/2b/0817a2b257fe88725c25589d89aec060581aabf668707a8d03b2e9e0cb2a/fastjsonschema-2.21.1-py3-none-any.whl", hash = "sha256:c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667", size = 23924, upload-time = "2024-12-02T10:55:07.599Z" }, -] - [[package]] name = "filelock" version = "3.18.0" @@ -504,30 +231,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215, upload-time = "2025-03-14T07:11:39.145Z" }, ] -[[package]] -name = "flexcache" -version = "0.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/55/b0/8a21e330561c65653d010ef112bf38f60890051d244ede197ddaa08e50c1/flexcache-0.3.tar.gz", hash = "sha256:18743bd5a0621bfe2cf8d519e4c3bfdf57a269c15d1ced3fb4b64e0ff4600656", size = 15816, upload-time = "2024-03-09T03:21:07.555Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/27/cd/c883e1a7c447479d6e13985565080e3fea88ab5a107c21684c813dba1875/flexcache-0.3-py3-none-any.whl", hash = "sha256:d43c9fea82336af6e0115e308d9d33a185390b8346a017564611f1466dcd2e32", size = 13263, upload-time = "2024-03-09T03:21:05.635Z" }, -] - -[[package]] -name = "flexparser" -version = "0.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/82/99/b4de7e39e8eaf8207ba1a8fa2241dd98b2ba72ae6e16960d8351736d8702/flexparser-0.4.tar.gz", hash = "sha256:266d98905595be2ccc5da964fe0a2c3526fbbffdc45b65b3146d75db992ef6b2", size = 31799, upload-time = "2024-11-07T02:00:56.249Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/5e/3be305568fe5f34448807976dc82fc151d76c3e0e03958f34770286278c1/flexparser-0.4-py3-none-any.whl", hash = "sha256:3738b456192dcb3e15620f324c447721023c0293f6af9955b481e91d00179846", size = 27625, upload-time = "2024-11-07T02:00:54.523Z" }, -] - [[package]] name = "fonttools" version = "4.59.0" @@ -553,15 +256,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d0/9c/df0ef2c51845a13043e5088f7bb988ca6cd5bb82d5d4203d6a158aa58cf2/fonttools-4.59.0-py3-none-any.whl", hash = "sha256:241313683afd3baacb32a6bd124d0bce7404bc5280e12e291bae1b9bba28711d", size = 1128050, upload-time = "2025-07-16T12:04:52.687Z" }, ] -[[package]] -name = "fqdn" -version = "1.5.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/3e/a80a8c077fd798951169626cde3e239adeba7dab75deb3555716415bd9b0/fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", size = 6015, upload-time = "2021-03-11T07:16:29.08Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121, upload-time = "2021-03-11T07:16:28.351Z" }, -] - [[package]] name = "graphviz" version = "0.21" @@ -571,673 +265,107 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/91/4c/e0ce1ef95d4000ebc1c11801f9b944fa5910ecc15b5e351865763d8657f8/graphviz-0.21-py3-none-any.whl", hash = "sha256:54f33de9f4f911d7e84e4191749cac8cc5653f815b06738c54db9a15ab8b1e42", size = 47300, upload-time = "2025-06-15T09:35:04.433Z" }, ] -[[package]] -name = "greenlet" -version = "3.2.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c9/92/bb85bd6e80148a4d2e0c59f7c0c2891029f8fd510183afc7d8d2feeed9b6/greenlet-3.2.3.tar.gz", hash = "sha256:8b0dd8ae4c0d6f5e54ee55ba935eeb3d735a9b58a8a1e5b5cbab64e01a39f365", size = 185752, upload-time = "2025-06-05T16:16:09.955Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/94/ad0d435f7c48debe960c53b8f60fb41c2026b1d0fa4a99a1cb17c3461e09/greenlet-3.2.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:25ad29caed5783d4bd7a85c9251c651696164622494c00802a139c00d639242d", size = 271992, upload-time = "2025-06-05T16:11:23.467Z" }, - { url = "https://files.pythonhosted.org/packages/93/5d/7c27cf4d003d6e77749d299c7c8f5fd50b4f251647b5c2e97e1f20da0ab5/greenlet-3.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88cd97bf37fe24a6710ec6a3a7799f3f81d9cd33317dcf565ff9950c83f55e0b", size = 638820, upload-time = "2025-06-05T16:38:52.882Z" }, - { url = "https://files.pythonhosted.org/packages/c6/7e/807e1e9be07a125bb4c169144937910bf59b9d2f6d931578e57f0bce0ae2/greenlet-3.2.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:baeedccca94880d2f5666b4fa16fc20ef50ba1ee353ee2d7092b383a243b0b0d", size = 653046, upload-time = "2025-06-05T16:41:36.343Z" }, - { url = "https://files.pythonhosted.org/packages/9d/ab/158c1a4ea1068bdbc78dba5a3de57e4c7aeb4e7fa034320ea94c688bfb61/greenlet-3.2.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:be52af4b6292baecfa0f397f3edb3c6092ce071b499dd6fe292c9ac9f2c8f264", size = 647701, upload-time = "2025-06-05T16:48:19.604Z" }, - { url = "https://files.pythonhosted.org/packages/cc/0d/93729068259b550d6a0288da4ff72b86ed05626eaf1eb7c0d3466a2571de/greenlet-3.2.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0cc73378150b8b78b0c9fe2ce56e166695e67478550769536a6742dca3651688", size = 649747, upload-time = "2025-06-05T16:13:04.628Z" }, - { url = "https://files.pythonhosted.org/packages/f6/f6/c82ac1851c60851302d8581680573245c8fc300253fc1ff741ae74a6c24d/greenlet-3.2.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:706d016a03e78df129f68c4c9b4c4f963f7d73534e48a24f5f5a7101ed13dbbb", size = 605461, upload-time = "2025-06-05T16:12:50.792Z" }, - { url = "https://files.pythonhosted.org/packages/98/82/d022cf25ca39cf1200650fc58c52af32c90f80479c25d1cbf57980ec3065/greenlet-3.2.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:419e60f80709510c343c57b4bb5a339d8767bf9aef9b8ce43f4f143240f88b7c", size = 1121190, upload-time = "2025-06-05T16:36:48.59Z" }, - { url = "https://files.pythonhosted.org/packages/f5/e1/25297f70717abe8104c20ecf7af0a5b82d2f5a980eb1ac79f65654799f9f/greenlet-3.2.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:93d48533fade144203816783373f27a97e4193177ebaaf0fc396db19e5d61163", size = 1149055, upload-time = "2025-06-05T16:12:40.457Z" }, - { url = "https://files.pythonhosted.org/packages/1f/8f/8f9e56c5e82eb2c26e8cde787962e66494312dc8cb261c460e1f3a9c88bc/greenlet-3.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:7454d37c740bb27bdeddfc3f358f26956a07d5220818ceb467a483197d84f849", size = 297817, upload-time = "2025-06-05T16:29:49.244Z" }, - { url = "https://files.pythonhosted.org/packages/b1/cf/f5c0b23309070ae93de75c90d29300751a5aacefc0a3ed1b1d8edb28f08b/greenlet-3.2.3-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:500b8689aa9dd1ab26872a34084503aeddefcb438e2e7317b89b11eaea1901ad", size = 270732, upload-time = "2025-06-05T16:10:08.26Z" }, - { url = "https://files.pythonhosted.org/packages/48/ae/91a957ba60482d3fecf9be49bc3948f341d706b52ddb9d83a70d42abd498/greenlet-3.2.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a07d3472c2a93117af3b0136f246b2833fdc0b542d4a9799ae5f41c28323faef", size = 639033, upload-time = "2025-06-05T16:38:53.983Z" }, - { url = "https://files.pythonhosted.org/packages/6f/df/20ffa66dd5a7a7beffa6451bdb7400d66251374ab40b99981478c69a67a8/greenlet-3.2.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:8704b3768d2f51150626962f4b9a9e4a17d2e37c8a8d9867bbd9fa4eb938d3b3", size = 652999, upload-time = "2025-06-05T16:41:37.89Z" }, - { url = "https://files.pythonhosted.org/packages/51/b4/ebb2c8cb41e521f1d72bf0465f2f9a2fd803f674a88db228887e6847077e/greenlet-3.2.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:5035d77a27b7c62db6cf41cf786cfe2242644a7a337a0e155c80960598baab95", size = 647368, upload-time = "2025-06-05T16:48:21.467Z" }, - { url = "https://files.pythonhosted.org/packages/8e/6a/1e1b5aa10dced4ae876a322155705257748108b7fd2e4fae3f2a091fe81a/greenlet-3.2.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2d8aa5423cd4a396792f6d4580f88bdc6efcb9205891c9d40d20f6e670992efb", size = 650037, upload-time = "2025-06-05T16:13:06.402Z" }, - { url = "https://files.pythonhosted.org/packages/26/f2/ad51331a157c7015c675702e2d5230c243695c788f8f75feba1af32b3617/greenlet-3.2.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2c724620a101f8170065d7dded3f962a2aea7a7dae133a009cada42847e04a7b", size = 608402, upload-time = "2025-06-05T16:12:51.91Z" }, - { url = "https://files.pythonhosted.org/packages/26/bc/862bd2083e6b3aff23300900a956f4ea9a4059de337f5c8734346b9b34fc/greenlet-3.2.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:873abe55f134c48e1f2a6f53f7d1419192a3d1a4e873bace00499a4e45ea6af0", size = 1119577, upload-time = "2025-06-05T16:36:49.787Z" }, - { url = "https://files.pythonhosted.org/packages/86/94/1fc0cc068cfde885170e01de40a619b00eaa8f2916bf3541744730ffb4c3/greenlet-3.2.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:024571bbce5f2c1cfff08bf3fbaa43bbc7444f580ae13b0099e95d0e6e67ed36", size = 1147121, upload-time = "2025-06-05T16:12:42.527Z" }, - { url = "https://files.pythonhosted.org/packages/27/1a/199f9587e8cb08a0658f9c30f3799244307614148ffe8b1e3aa22f324dea/greenlet-3.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:5195fb1e75e592dd04ce79881c8a22becdfa3e6f500e7feb059b1e6fdd54d3e3", size = 297603, upload-time = "2025-06-05T16:20:12.651Z" }, - { url = "https://files.pythonhosted.org/packages/d8/ca/accd7aa5280eb92b70ed9e8f7fd79dc50a2c21d8c73b9a0856f5b564e222/greenlet-3.2.3-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:3d04332dddb10b4a211b68111dabaee2e1a073663d117dc10247b5b1642bac86", size = 271479, upload-time = "2025-06-05T16:10:47.525Z" }, - { url = "https://files.pythonhosted.org/packages/55/71/01ed9895d9eb49223280ecc98a557585edfa56b3d0e965b9fa9f7f06b6d9/greenlet-3.2.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8186162dffde068a465deab08fc72c767196895c39db26ab1c17c0b77a6d8b97", size = 683952, upload-time = "2025-06-05T16:38:55.125Z" }, - { url = "https://files.pythonhosted.org/packages/ea/61/638c4bdf460c3c678a0a1ef4c200f347dff80719597e53b5edb2fb27ab54/greenlet-3.2.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f4bfbaa6096b1b7a200024784217defedf46a07c2eee1a498e94a1b5f8ec5728", size = 696917, upload-time = "2025-06-05T16:41:38.959Z" }, - { url = "https://files.pythonhosted.org/packages/22/cc/0bd1a7eb759d1f3e3cc2d1bc0f0b487ad3cc9f34d74da4b80f226fde4ec3/greenlet-3.2.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:ed6cfa9200484d234d8394c70f5492f144b20d4533f69262d530a1a082f6ee9a", size = 692443, upload-time = "2025-06-05T16:48:23.113Z" }, - { url = "https://files.pythonhosted.org/packages/67/10/b2a4b63d3f08362662e89c103f7fe28894a51ae0bc890fabf37d1d780e52/greenlet-3.2.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:02b0df6f63cd15012bed5401b47829cfd2e97052dc89da3cfaf2c779124eb892", size = 692995, upload-time = "2025-06-05T16:13:07.972Z" }, - { url = "https://files.pythonhosted.org/packages/5a/c6/ad82f148a4e3ce9564056453a71529732baf5448ad53fc323e37efe34f66/greenlet-3.2.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:86c2d68e87107c1792e2e8d5399acec2487a4e993ab76c792408e59394d52141", size = 655320, upload-time = "2025-06-05T16:12:53.453Z" }, - { url = "https://files.pythonhosted.org/packages/5c/4f/aab73ecaa6b3086a4c89863d94cf26fa84cbff63f52ce9bc4342b3087a06/greenlet-3.2.3-cp314-cp314-win_amd64.whl", hash = "sha256:8c47aae8fbbfcf82cc13327ae802ba13c9c36753b67e760023fd116bc124a62a", size = 301236, upload-time = "2025-06-05T16:15:20.111Z" }, -] - [[package]] name = "gurobipy" version = "12.0.3" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6f/bb/b3784497115c64c2bd122cc9d411f167026d4ec42a26b1ff3c43a779275d/gurobipy-12.0.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:020f23277f630e079eac114385eabd1bd9fb4ac22f8796ed5ba6d915ce4f141b", size = 12222234, upload-time = "2025-07-15T07:19:24.64Z" }, - { url = "https://files.pythonhosted.org/packages/18/ea/c065984de5287c99fd30ee8d700fd78f83692e992471f9667ab5d36612b9/gurobipy-12.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:72bbf544bc05060bb93909b79715ace4c0f416198f7622a985cabb9e8e99aa1c", size = 62583866, upload-time = "2025-07-15T07:20:17.576Z" }, - { url = "https://files.pythonhosted.org/packages/9b/8b/2b9f26e4e19a258229b8a8ffc377ca372cc2059a22a0a7c67572efe308d8/gurobipy-12.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b3f971caf270f671b6ffcf5b937b3c0430a5264b0f01529dc8681d61c221f215", size = 14268480, upload-time = "2025-07-15T07:20:26.898Z" }, - { url = "https://files.pythonhosted.org/packages/26/0f/3544a323635f37cdfe1e011d2903b7ef94ba18e10224fa1419f64d0c1968/gurobipy-12.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:af18fd03d5dc3f6e5f590c372ad288b8430a6d88a5b5e66cfcd8432f86ee8650", size = 11121565, upload-time = "2025-07-15T07:20:34.576Z" }, - { url = "https://files.pythonhosted.org/packages/5e/95/f0e5b5cf85298f42482cf4e53d8114c45bb962f55195d531fe4e62b5afa1/gurobipy-12.0.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a8552e47673cb6f1fd351edf8fcad86b02f832cbfb57d90ef21e0397e96d138e", size = 12183439, upload-time = "2025-07-15T07:20:44.224Z" }, - { url = "https://files.pythonhosted.org/packages/61/6e/aea725b4143faa4eb6878414a91fa74e7871aba0ab9453803a9eeef781c2/gurobipy-12.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:be05c074141c8a126c8aaeccc41795ab091a666eabb39ca1ff98a74bde81e663", size = 62583451, upload-time = "2025-07-15T07:21:38.825Z" }, - { url = "https://files.pythonhosted.org/packages/75/47/7b9c63ce2cd85d796403b91a6d211d5c8baac7b694edd94e2151f365d6a9/gurobipy-12.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:79a333766e27fef7902ceeefbcf0279a1ca393a27a72ea62f8e301b21aa17d59", size = 14271076, upload-time = "2025-07-15T07:21:55.102Z" }, - { url = "https://files.pythonhosted.org/packages/2a/93/b10cd6112c05675fed5c817fd7933c9d4ba3a7039e42cba844a9ac09242a/gurobipy-12.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:e0f9ed55077e622021369bb9df2ca3b00c86b678792a3b1556cc59f67348fab0", size = 11111414, upload-time = "2025-07-15T07:22:05.079Z" }, -] - -[[package]] -name = "h11" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, -] - -[[package]] -name = "h2" -version = "4.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "hpack" }, - { name = "hyperframe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1b/38/d7f80fd13e6582fb8e0df8c9a653dcc02b03ca34f4d72f34869298c5baf8/h2-4.2.0.tar.gz", hash = "sha256:c8a52129695e88b1a0578d8d2cc6842bbd79128ac685463b887ee278126ad01f", size = 2150682, upload-time = "2025-02-02T07:43:51.815Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/9e/984486f2d0a0bd2b024bf4bc1c62688fcafa9e61991f041fb0e2def4a982/h2-4.2.0-py3-none-any.whl", hash = "sha256:479a53ad425bb29af087f3458a61d30780bc818e4ebcf01f0b536ba916462ed0", size = 60957, upload-time = "2025-02-01T11:02:26.481Z" }, -] - -[[package]] -name = "highspy" -version = "1.11.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b4/fc/aa1325331c320598ce60cc31060087681cd05123b6fb2a8a571e882b7f05/highspy-1.11.0.tar.gz", hash = "sha256:771e58c076122d207ff1b19759c21d3227f0da5b80dfd89a4145681524969cef", size = 1285415, upload-time = "2025-06-06T00:47:22.562Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/ad/b54ad6740b950faab3b7f1465fbb5c740fc522928a8d9f01cac181f8f9a6/highspy-1.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28fffd3e733833a7b2569df6761088046e8aca868ab328828711dbe15b102ad4", size = 2232856, upload-time = "2025-06-06T00:46:11.161Z" }, - { url = "https://files.pythonhosted.org/packages/a3/0c/3921a207f47d52abc81a9d00d8f4d579b05b85670e23bc7140e39268490d/highspy-1.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:20a3adf8820a5f7a9cee6fc76df625e651ecfd8b5898af2a77042e79269ce0bc", size = 1908641, upload-time = "2025-06-06T00:46:12.706Z" }, - { url = "https://files.pythonhosted.org/packages/0a/b6/ea7ea6c4c3f781b007fe928b2aefa40c49287b4689985d04c3b20d383475/highspy-1.11.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d4bc0a84cf613bb8565f9b5f610eb0655384162f509b5d86f9c888570275fdc", size = 2119574, upload-time = "2025-06-06T00:46:14.261Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0c/94f1ccb6606e8445a7a0c68d983e47f64899582c64fcea651f488eaaaea0/highspy-1.11.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:543789b75c396a904cb550de34eb333f1a184e123dadc9903b5e6dbca18a007b", size = 2441487, upload-time = "2025-06-06T00:46:16.286Z" }, - { url = "https://files.pythonhosted.org/packages/ad/aa/e7c4ac05162187c484bb121f50d8e037c13bf894ed5cf4e781e1cff68762/highspy-1.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a23949e4f44b6df0ed8c387a7c733d683a0fa66e3ff15d65719979ce2099ee99", size = 2302302, upload-time = "2025-06-06T00:46:18.819Z" }, - { url = "https://files.pythonhosted.org/packages/04/ce/fd2473bed635eb06d116f987767d5c5fe3c62b317fb1a788c31966d7fa0a/highspy-1.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:50dacf300ebe7c4dca92891c0bf61b694f2ca744207cf7d0d24f2a30ffb5608c", size = 3101885, upload-time = "2025-06-06T00:46:20.774Z" }, - { url = "https://files.pythonhosted.org/packages/6e/e1/bf174389656de5d302ed53dd5cdeb5f7e9ad84156ad2fc95d5a63ba023f2/highspy-1.11.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a782c242b4b047f86110787b0dafce9d77cc10f079adab1fd51c5331e5760127", size = 3647952, upload-time = "2025-06-06T00:46:22.847Z" }, - { url = "https://files.pythonhosted.org/packages/f3/f5/42f6f2ce99c5b9d7aa864ac3abeaf8a2b66da707821ab42b0a31ec2a0dc1/highspy-1.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:15b804387089a389e5f01b056a4b3ad74c7d1cf00ab00a0faaf3b4a582bb664c", size = 3309616, upload-time = "2025-06-06T00:46:24.888Z" }, - { url = "https://files.pythonhosted.org/packages/47/f5/cf13640ed65ea934b45e0c3e786497f4696f286faf45e8e62579a0f15462/highspy-1.11.0-cp312-cp312-win32.whl", hash = "sha256:8c33f68df8ab9666d379b0d64d04775c0a9db31882d4f87b3ec8cece0003b47d", size = 1710641, upload-time = "2025-06-06T00:46:26.462Z" }, - { url = "https://files.pythonhosted.org/packages/b7/2f/7acfea5b8d32b86bdec018f858bc195236b804a22a7cd3349da711498692/highspy-1.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0aed8c80d33e2fc2eb1def75dbd34c9fa463acb589d19a5ed5dcc0178ae7062", size = 1985767, upload-time = "2025-06-06T00:46:28.144Z" }, - { url = "https://files.pythonhosted.org/packages/96/84/3e899c5d95dc9d5400a308e0aaf4a5143f69016a4f46dd528ff7cd65d341/highspy-1.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f675cda73860c7c8a22546db3c80db985720baea84866b08a971cfa03cc7a156", size = 2232867, upload-time = "2025-06-06T00:46:29.651Z" }, - { url = "https://files.pythonhosted.org/packages/74/e2/2853095a74e9fc2c2081340647be8edba7122696534ebbaf159ceb53f9b4/highspy-1.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7babebfc01b7682c69c95e0520614ec9400e10cec1b84d3fb7cd48535c606244", size = 1908601, upload-time = "2025-06-06T00:46:31.232Z" }, - { url = "https://files.pythonhosted.org/packages/e6/36/3cabdd3ae8610912962bad96f4d4d6702255d6c01d050754e4050a9eaa4a/highspy-1.11.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39fb60d84d7a58e58f923ea6f0641e6978eb9049033b84de1a2add723e01cd3f", size = 2119726, upload-time = "2025-06-06T00:46:32.796Z" }, - { url = "https://files.pythonhosted.org/packages/a9/da/200d3f13ca9ad3f9fc11a1f3f76cc2734de42dae064510365d42caeb5ed4/highspy-1.11.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c2e7cf4d504287cd8910de322a726d58428af43bb985d6bae602bf84a7454b9", size = 2441449, upload-time = "2025-06-06T00:46:35.147Z" }, - { url = "https://files.pythonhosted.org/packages/6c/58/fc3775850dc668006039637a4f23f03a9c0eb533643c9d3a7370f9d63de2/highspy-1.11.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79682aa7855d94106ccbbb750082d156dcbb57dff9d489f167320ae0ce768867", size = 2302685, upload-time = "2025-06-06T00:46:36.791Z" }, - { url = "https://files.pythonhosted.org/packages/b5/16/e13326a9706c407d32e39ad14aa79a696c1eb49bb13d50fde5d96afb02b5/highspy-1.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:65232aa496fb27be56cc85b2c7c785fac866107c32ea00cc38ec474d6a9f6494", size = 3102306, upload-time = "2025-06-06T00:46:38.341Z" }, - { url = "https://files.pythonhosted.org/packages/0e/93/468e63b16d9bf123174e7f8f7b8bd5a2f96b18d7370a2cc35e6485871749/highspy-1.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f78f27e18275d3c7868dcd0314ea535ed361322e7f0817363872d75a4cc15abc", size = 3648234, upload-time = "2025-06-06T00:46:40.895Z" }, - { url = "https://files.pythonhosted.org/packages/dc/c5/37b849a69c9cbccf533a9a51e309a49e83d704f06bf45370c2e78ceb15d4/highspy-1.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6156a7d643268456427b6fe310626ad9ee9d908ff812cc64ee8bad7b9872ea98", size = 3309724, upload-time = "2025-06-06T00:46:43.083Z" }, - { url = "https://files.pythonhosted.org/packages/90/0f/89c579b2f718dc419fd76067a03ecb3c96e6919b7cffee1b9f5a2dfe4f56/highspy-1.11.0-cp313-cp313-win32.whl", hash = "sha256:e61facebb0127eb3661db79a11c7665e47229ec63d2b425996d04aeede26d46b", size = 1710676, upload-time = "2025-06-06T00:46:45.132Z" }, - { url = "https://files.pythonhosted.org/packages/20/ca/ba2af91f2418bee0d0e99df71dcd171ca863675de6a5260bbf06c120f084/highspy-1.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:ceac08be37f75dc0af95669a0cfb073e5db5f07ead05cdcc81fd4b4394708d53", size = 1985967, upload-time = "2025-06-06T00:46:46.767Z" }, -] - -[[package]] -name = "hpack" -version = "4.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2c/48/71de9ed269fdae9c8057e5a4c0aa7402e8bb16f2c6e90b3aa53327b113f8/hpack-4.1.0.tar.gz", hash = "sha256:ec5eca154f7056aa06f196a557655c5b009b382873ac8d1e66e79e87535f1dca", size = 51276, upload-time = "2025-01-22T21:44:58.347Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/07/c6/80c95b1b2b94682a72cbdbfb85b81ae2daffa4291fbfa1b1464502ede10d/hpack-4.1.0-py3-none-any.whl", hash = "sha256:157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496", size = 34357, upload-time = "2025-01-22T21:44:56.92Z" }, -] - -[[package]] -name = "httpcore" -version = "1.0.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, -] - -[[package]] -name = "httpx" -version = "0.28.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, -] - -[package.optional-dependencies] -http2 = [ - { name = "h2" }, -] - -[[package]] -name = "hyperframe" -version = "6.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/02/e7/94f8232d4a74cc99514c13a9f995811485a6903d48e5d952771ef6322e30/hyperframe-6.1.0.tar.gz", hash = "sha256:f630908a00854a7adeabd6382b43923a4c4cd4b821fcb527e6ab9e15382a3b08", size = 26566, upload-time = "2025-01-22T21:41:49.302Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl", hash = "sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5", size = 13007, upload-time = "2025-01-22T21:41:47.295Z" }, -] - -[[package]] -name = "iam-units" -version = "2023.9.12" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pint" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/cb/24/7c77cbbbdc077954c89d2a110c4847a0ab5fed61f5c7bc704274eda22912/iam_units-2023.9.12.tar.gz", hash = "sha256:89cfbcf5ab88d0dfd0b0639cabffe29ddf9f967f851184b3f3d86cd5ba7f43c9", size = 60039, upload-time = "2023-09-12T11:06:51.165Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/38/78/3335cc52bc960c567328ed4a62ca030d93a98e393e75c127ac130fc8bbb3/iam_units-2023.9.12-py3-none-any.whl", hash = "sha256:dbd6065d6a991796ff7cfaf63a8e46c5d3b264d532a567251dd1f57d5d44547a", size = 49408, upload-time = "2023-09-12T11:06:49.37Z" }, -] - -[[package]] -name = "identify" -version = "2.6.12" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/88/d193a27416618628a5eea64e3223acd800b40749a96ffb322a9b55a49ed1/identify-2.6.12.tar.gz", hash = "sha256:d8de45749f1efb108badef65ee8386f0f7bb19a7f26185f74de6367bffbaf0e6", size = 99254, upload-time = "2025-05-23T20:37:53.3Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/cd/18f8da995b658420625f7ef13f037be53ae04ec5ad33f9b718240dcfd48c/identify-2.6.12-py2.py3-none-any.whl", hash = "sha256:ad9672d5a72e0d2ff7c5c8809b62dfa60458626352fb0eb7b55e69bdc45334a2", size = 99145, upload-time = "2025-05-23T20:37:51.495Z" }, -] - -[[package]] -name = "idna" -version = "3.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, -] - -[[package]] -name = "imagesize" -version = "1.4.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026, upload-time = "2022-07-01T12:21:05.687Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769, upload-time = "2022-07-01T12:21:02.467Z" }, -] - -[[package]] -name = "iniconfig" -version = "2.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, -] - -[[package]] -name = "ipykernel" -version = "6.29.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "appnope", marker = "sys_platform == 'darwin'" }, - { name = "comm" }, - { name = "debugpy" }, - { name = "ipython" }, - { name = "jupyter-client" }, - { name = "jupyter-core" }, - { name = "matplotlib-inline" }, - { name = "nest-asyncio" }, - { name = "packaging" }, - { name = "psutil" }, - { name = "pyzmq" }, - { name = "tornado" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e9/5c/67594cb0c7055dc50814b21731c22a601101ea3b1b50a9a1b090e11f5d0f/ipykernel-6.29.5.tar.gz", hash = "sha256:f093a22c4a40f8828f8e330a9c297cb93dcab13bd9678ded6de8e5cf81c56215", size = 163367, upload-time = "2024-07-01T14:07:22.543Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/5c/368ae6c01c7628438358e6d337c19b05425727fbb221d2a3c4303c372f42/ipykernel-6.29.5-py3-none-any.whl", hash = "sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5", size = 117173, upload-time = "2024-07-01T14:07:19.603Z" }, -] - -[[package]] -name = "ipython" -version = "9.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "decorator" }, - { name = "ipython-pygments-lexers" }, - { name = "jedi" }, - { name = "matplotlib-inline" }, - { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "prompt-toolkit" }, - { name = "pygments" }, - { name = "stack-data" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/54/80/406f9e3bde1c1fd9bf5a0be9d090f8ae623e401b7670d8f6fdf2ab679891/ipython-9.4.0.tar.gz", hash = "sha256:c033c6d4e7914c3d9768aabe76bbe87ba1dc66a92a05db6bfa1125d81f2ee270", size = 4385338, upload-time = "2025-07-01T11:11:30.606Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/63/f8/0031ee2b906a15a33d6bfc12dd09c3dfa966b3cb5b284ecfb7549e6ac3c4/ipython-9.4.0-py3-none-any.whl", hash = "sha256:25850f025a446d9b359e8d296ba175a36aedd32e83ca9b5060430fe16801f066", size = 611021, upload-time = "2025-07-01T11:11:27.85Z" }, -] - -[[package]] -name = "ipython-genutils" -version = "0.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/69/fbeffffc05236398ebfcfb512b6d2511c622871dca1746361006da310399/ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8", size = 22208, upload-time = "2017-03-13T22:12:26.393Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/bc/9bd3b5c2b4774d5f33b2d544f1460be9df7df2fe42f352135381c347c69a/ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8", size = 26343, upload-time = "2017-03-13T22:12:25.412Z" }, -] - -[[package]] -name = "ipython-pygments-lexers" -version = "1.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" }, -] - -[[package]] -name = "ipywidgets" -version = "8.1.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "comm" }, - { name = "ipython" }, - { name = "jupyterlab-widgets" }, - { name = "traitlets" }, - { name = "widgetsnbextension" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3e/48/d3dbac45c2814cb73812f98dd6b38bbcc957a4e7bb31d6ea9c03bf94ed87/ipywidgets-8.1.7.tar.gz", hash = "sha256:15f1ac050b9ccbefd45dccfbb2ef6bed0029d8278682d569d71b8dd96bee0376", size = 116721, upload-time = "2025-05-05T12:42:03.489Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/58/6a/9166369a2f092bd286d24e6307de555d63616e8ddb373ebad2b5635ca4cd/ipywidgets-8.1.7-py3-none-any.whl", hash = "sha256:764f2602d25471c213919b8a1997df04bef869251db4ca8efba1b76b1bd9f7bb", size = 139806, upload-time = "2025-05-05T12:41:56.833Z" }, -] - -[[package]] -name = "isoduration" -version = "20.11.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "arrow" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7c/1a/3c8edc664e06e6bd06cce40c6b22da5f1429aa4224d0c590f3be21c91ead/isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", size = 11649, upload-time = "2020-11-01T11:00:00.312Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321, upload-time = "2020-11-01T10:59:58.02Z" }, -] - -[[package]] -name = "ixmp4" -version = "0.11.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "alembic" }, - { name = "fastapi" }, - { name = "httpx", extra = ["http2"] }, - { name = "openpyxl" }, - { name = "pandas" }, - { name = "pandera" }, - { name = "psycopg", extra = ["binary"] }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "pyjwt" }, - { name = "python-dotenv" }, - { name = "rich" }, - { name = "sqlalchemy", extra = ["mypy"] }, - { name = "sqlalchemy-continuum" }, - { name = "sqlalchemy-utils" }, - { name = "toml" }, - { name = "typer" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e9/e5/ad234fadbb0cd0fbe89b8c1eb23cf1797a1f1b56d34f235bf01efcaf94e8/ixmp4-0.11.1.tar.gz", hash = "sha256:8197ce437cbf32784ca6ae588eb09a17074e2c201c187bb14b3bbfe91a30ce19", size = 119459, upload-time = "2025-07-09T10:05:37.015Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ac/f2/20254152f70c1388e628625a76bd098bd295bdd8c2d4ddd7491c2a495994/ixmp4-0.11.1-py3-none-any.whl", hash = "sha256:c4033554c58ba5fa19cdf3159b3925520de9af37003d96027c2a709590b9841b", size = 246401, upload-time = "2025-07-09T10:05:35.009Z" }, -] - -[[package]] -name = "jedi" -version = "0.19.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "parso" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, -] - -[[package]] -name = "jinja2" -version = "3.1.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, -] - -[[package]] -name = "joblib" -version = "1.5.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/dc/fe/0f5a938c54105553436dbff7a61dc4fed4b1b2c98852f8833beaf4d5968f/joblib-1.5.1.tar.gz", hash = "sha256:f4f86e351f39fe3d0d32a9f2c3d8af1ee4cec285aafcb27003dda5205576b444", size = 330475, upload-time = "2025-05-23T12:04:37.097Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7d/4f/1195bbac8e0c2acc5f740661631d8d750dc38d4a32b23ee5df3cde6f4e0d/joblib-1.5.1-py3-none-any.whl", hash = "sha256:4719a31f054c7d766948dcd83e9613686b27114f190f717cec7eaa2084f8a74a", size = 307746, upload-time = "2025-05-23T12:04:35.124Z" }, -] - -[[package]] -name = "json5" -version = "0.12.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/12/be/c6c745ec4c4539b25a278b70e29793f10382947df0d9efba2fa09120895d/json5-0.12.0.tar.gz", hash = "sha256:0b4b6ff56801a1c7dc817b0241bca4ce474a0e6a163bfef3fc594d3fd263ff3a", size = 51907, upload-time = "2025-04-03T16:33:13.201Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/41/9f/3500910d5a98549e3098807493851eeef2b89cdd3032227558a104dfe926/json5-0.12.0-py3-none-any.whl", hash = "sha256:6d37aa6c08b0609f16e1ec5ff94697e2cbbfbad5ac112afa05794da9ab7810db", size = 36079, upload-time = "2025-04-03T16:33:11.927Z" }, -] - -[[package]] -name = "jsonpointer" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, -] - -[[package]] -name = "jsonschema" -version = "4.24.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "attrs" }, - { name = "jsonschema-specifications" }, - { name = "referencing" }, - { name = "rpds-py" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bf/d3/1cf5326b923a53515d8f3a2cd442e6d7e94fcc444716e879ea70a0ce3177/jsonschema-4.24.0.tar.gz", hash = "sha256:0b4e8069eb12aedfa881333004bccaec24ecef5a8a6a4b6df142b2cc9599d196", size = 353480, upload-time = "2025-05-26T18:48:10.459Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/3d/023389198f69c722d039351050738d6755376c8fd343e91dc493ea485905/jsonschema-4.24.0-py3-none-any.whl", hash = "sha256:a462455f19f5faf404a7902952b6f0e3ce868f3ee09a359b05eca6673bd8412d", size = 88709, upload-time = "2025-05-26T18:48:08.417Z" }, -] - -[package.optional-dependencies] -format-nongpl = [ - { name = "fqdn" }, - { name = "idna" }, - { name = "isoduration" }, - { name = "jsonpointer" }, - { name = "rfc3339-validator" }, - { name = "rfc3986-validator" }, - { name = "uri-template" }, - { name = "webcolors" }, -] - -[[package]] -name = "jsonschema-specifications" -version = "2025.4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "referencing" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bf/ce/46fbd9c8119cfc3581ee5643ea49464d168028cfb5caff5fc0596d0cf914/jsonschema_specifications-2025.4.1.tar.gz", hash = "sha256:630159c9f4dbea161a6a2205c3011cc4f18ff381b189fff48bb39b9bf26ae608", size = 15513, upload-time = "2025-04-23T12:34:07.418Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/01/0e/b27cdbaccf30b890c40ed1da9fd4a3593a5cf94dae54fb34f8a4b74fcd3f/jsonschema_specifications-2025.4.1-py3-none-any.whl", hash = "sha256:4653bffbd6584f7de83a67e0d620ef16900b390ddc7939d56684d6c81e33f1af", size = 18437, upload-time = "2025-04-23T12:34:05.422Z" }, -] - -[[package]] -name = "jupyter" -version = "1.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ipykernel" }, - { name = "ipywidgets" }, - { name = "jupyter-console" }, - { name = "jupyterlab" }, - { name = "nbconvert" }, - { name = "notebook" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/58/f3/af28ea964ab8bc1e472dba2e82627d36d470c51f5cd38c37502eeffaa25e/jupyter-1.1.1.tar.gz", hash = "sha256:d55467bceabdea49d7e3624af7e33d59c37fff53ed3a350e1ac957bed731de7a", size = 5714959, upload-time = "2024-08-30T07:15:48.299Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl", hash = "sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83", size = 2657, upload-time = "2024-08-30T07:15:47.045Z" }, -] - -[[package]] -name = "jupyter-client" -version = "8.6.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jupyter-core" }, - { name = "python-dateutil" }, - { name = "pyzmq" }, - { name = "tornado" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/71/22/bf9f12fdaeae18019a468b68952a60fe6dbab5d67cd2a103cac7659b41ca/jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419", size = 342019, upload-time = "2024-09-17T10:44:17.613Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/11/85/b0394e0b6fcccd2c1eeefc230978a6f8cb0c5df1e4cd3e7625735a0d7d1e/jupyter_client-8.6.3-py3-none-any.whl", hash = "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f", size = 106105, upload-time = "2024-09-17T10:44:15.218Z" }, -] - -[[package]] -name = "jupyter-console" -version = "6.6.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ipykernel" }, - { name = "ipython" }, - { name = "jupyter-client" }, - { name = "jupyter-core" }, - { name = "prompt-toolkit" }, - { name = "pygments" }, - { name = "pyzmq" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bd/2d/e2fd31e2fc41c14e2bcb6c976ab732597e907523f6b2420305f9fc7fdbdb/jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539", size = 34363, upload-time = "2023-03-06T14:13:31.02Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485", size = 24510, upload-time = "2023-03-06T14:13:28.229Z" }, -] - -[[package]] -name = "jupyter-contrib-core" -version = "0.4.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jupyter-core" }, - { name = "notebook" }, - { name = "setuptools" }, - { name = "tornado" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/50/94/0d37e5b49ea1c8bf204c46f9b0257c1f3319a4ab88acbd401da2cab25e55/jupyter_contrib_core-0.4.2.tar.gz", hash = "sha256:1887212f3ca9d4487d624c0705c20dfdf03d5a0b9ea2557d3aaeeb4c38bdcabb", size = 17490, upload-time = "2022-11-15T16:21:53.357Z" } - -[[package]] -name = "jupyter-contrib-nbextensions" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ipython-genutils" }, - { name = "jupyter-contrib-core" }, - { name = "jupyter-core" }, - { name = "jupyter-highlight-selected-word" }, - { name = "jupyter-nbextensions-configurator" }, - { name = "lxml" }, - { name = "nbconvert" }, - { name = "notebook" }, - { name = "tornado" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/50/91/78cc4362611dbde2b0cd068204aaf1b8899d0459c50d8ff9daca8c069791/jupyter_contrib_nbextensions-0.7.0.tar.gz", hash = "sha256:06e33f005885eb92f89cbe82711e921278201298d08ab0d886d1ba09e8c3e9ca", size = 23462252, upload-time = "2022-11-15T17:31:27.754Z" } - -[[package]] -name = "jupyter-core" -version = "5.8.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "platformdirs" }, - { name = "pywin32", marker = "platform_python_implementation != 'PyPy' and sys_platform == 'win32'" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/99/1b/72906d554acfeb588332eaaa6f61577705e9ec752ddb486f302dafa292d9/jupyter_core-5.8.1.tar.gz", hash = "sha256:0a5f9706f70e64786b75acba995988915ebd4601c8a52e534a40b51c95f59941", size = 88923, upload-time = "2025-05-27T07:38:16.655Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/57/6bffd4b20b88da3800c5d691e0337761576ee688eb01299eae865689d2df/jupyter_core-5.8.1-py3-none-any.whl", hash = "sha256:c28d268fc90fb53f1338ded2eb410704c5449a358406e8a948b75706e24863d0", size = 28880, upload-time = "2025-05-27T07:38:15.137Z" }, -] - -[[package]] -name = "jupyter-events" -version = "0.12.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jsonschema", extra = ["format-nongpl"] }, - { name = "packaging" }, - { name = "python-json-logger" }, - { name = "pyyaml" }, - { name = "referencing" }, - { name = "rfc3339-validator" }, - { name = "rfc3986-validator" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9d/c3/306d090461e4cf3cd91eceaff84bede12a8e52cd821c2d20c9a4fd728385/jupyter_events-0.12.0.tar.gz", hash = "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b", size = 62196, upload-time = "2025-02-03T17:23:41.485Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl", hash = "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb", size = 19430, upload-time = "2025-02-03T17:23:38.643Z" }, -] - -[[package]] -name = "jupyter-highlight-selected-word" -version = "0.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/a5/3dfeb7c8643ef502e82969fdebb201b63b33ded15a7761b27299bacebc3a/jupyter_highlight_selected_word-0.2.0.tar.gz", hash = "sha256:9fa740424859a807950ca08d2bfd28a35154cd32dd6d50ac4e0950022adc0e7b", size = 12592, upload-time = "2018-04-07T13:56:22.498Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/50/d7/19ab7cfd60bf268d2abbacc52d4295a40f52d74dfc0d938e4761ee5e598b/jupyter_highlight_selected_word-0.2.0-py2.py3-none-any.whl", hash = "sha256:9545dfa9cb057eebe3a5795604dcd3a5294ea18637e553f61a0b67c1b5903c58", size = 11699, upload-time = "2018-04-07T13:56:20.715Z" }, -] - -[[package]] -name = "jupyter-lsp" -version = "2.2.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jupyter-server" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/85/b4/3200b0b09c12bc3b72d943d923323c398eff382d1dcc7c0dbc8b74630e40/jupyter-lsp-2.2.5.tar.gz", hash = "sha256:793147a05ad446f809fd53ef1cd19a9f5256fd0a2d6b7ce943a982cb4f545001", size = 48741, upload-time = "2024-04-09T17:59:44.918Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/07/e0/7bd7cff65594fd9936e2f9385701e44574fc7d721331ff676ce440b14100/jupyter_lsp-2.2.5-py3-none-any.whl", hash = "sha256:45fbddbd505f3fbfb0b6cb2f1bc5e15e83ab7c79cd6e89416b248cb3c00c11da", size = 69146, upload-time = "2024-04-09T17:59:43.388Z" }, + { url = "https://files.pythonhosted.org/packages/6f/bb/b3784497115c64c2bd122cc9d411f167026d4ec42a26b1ff3c43a779275d/gurobipy-12.0.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:020f23277f630e079eac114385eabd1bd9fb4ac22f8796ed5ba6d915ce4f141b", size = 12222234, upload-time = "2025-07-15T07:19:24.64Z" }, + { url = "https://files.pythonhosted.org/packages/18/ea/c065984de5287c99fd30ee8d700fd78f83692e992471f9667ab5d36612b9/gurobipy-12.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:72bbf544bc05060bb93909b79715ace4c0f416198f7622a985cabb9e8e99aa1c", size = 62583866, upload-time = "2025-07-15T07:20:17.576Z" }, + { url = "https://files.pythonhosted.org/packages/9b/8b/2b9f26e4e19a258229b8a8ffc377ca372cc2059a22a0a7c67572efe308d8/gurobipy-12.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b3f971caf270f671b6ffcf5b937b3c0430a5264b0f01529dc8681d61c221f215", size = 14268480, upload-time = "2025-07-15T07:20:26.898Z" }, + { url = "https://files.pythonhosted.org/packages/26/0f/3544a323635f37cdfe1e011d2903b7ef94ba18e10224fa1419f64d0c1968/gurobipy-12.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:af18fd03d5dc3f6e5f590c372ad288b8430a6d88a5b5e66cfcd8432f86ee8650", size = 11121565, upload-time = "2025-07-15T07:20:34.576Z" }, + { url = "https://files.pythonhosted.org/packages/5e/95/f0e5b5cf85298f42482cf4e53d8114c45bb962f55195d531fe4e62b5afa1/gurobipy-12.0.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a8552e47673cb6f1fd351edf8fcad86b02f832cbfb57d90ef21e0397e96d138e", size = 12183439, upload-time = "2025-07-15T07:20:44.224Z" }, + { url = "https://files.pythonhosted.org/packages/61/6e/aea725b4143faa4eb6878414a91fa74e7871aba0ab9453803a9eeef781c2/gurobipy-12.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:be05c074141c8a126c8aaeccc41795ab091a666eabb39ca1ff98a74bde81e663", size = 62583451, upload-time = "2025-07-15T07:21:38.825Z" }, + { url = "https://files.pythonhosted.org/packages/75/47/7b9c63ce2cd85d796403b91a6d211d5c8baac7b694edd94e2151f365d6a9/gurobipy-12.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:79a333766e27fef7902ceeefbcf0279a1ca393a27a72ea62f8e301b21aa17d59", size = 14271076, upload-time = "2025-07-15T07:21:55.102Z" }, + { url = "https://files.pythonhosted.org/packages/2a/93/b10cd6112c05675fed5c817fd7933c9d4ba3a7039e42cba844a9ac09242a/gurobipy-12.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:e0f9ed55077e622021369bb9df2ca3b00c86b678792a3b1556cc59f67348fab0", size = 11111414, upload-time = "2025-07-15T07:22:05.079Z" }, ] [[package]] -name = "jupyter-nbextensions-configurator" -version = "0.6.4" +name = "highspy" +version = "1.11.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "jupyter-contrib-core" }, - { name = "jupyter-core" }, - { name = "jupyter-server" }, - { name = "notebook" }, - { name = "pyyaml" }, - { name = "tornado" }, - { name = "traitlets" }, + { name = "numpy" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/b4/fc/aa1325331c320598ce60cc31060087681cd05123b6fb2a8a571e882b7f05/highspy-1.11.0.tar.gz", hash = "sha256:771e58c076122d207ff1b19759c21d3227f0da5b80dfd89a4145681524969cef", size = 1285415, upload-time = "2025-06-06T00:47:22.562Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/05/fe/cffb14a4fbb43cf276aa3047e42c3f9ecfda851ba3c466295401f6b1e085/jupyter_nbextensions_configurator-0.6.4-py2.py3-none-any.whl", hash = "sha256:fe7a7b0805b5926449692fb077e0e659bab8b27563bc68cba26854532fdf99c7", size = 466890, upload-time = "2024-06-05T16:08:37.236Z" }, + { url = "https://files.pythonhosted.org/packages/bb/ad/b54ad6740b950faab3b7f1465fbb5c740fc522928a8d9f01cac181f8f9a6/highspy-1.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28fffd3e733833a7b2569df6761088046e8aca868ab328828711dbe15b102ad4", size = 2232856, upload-time = "2025-06-06T00:46:11.161Z" }, + { url = "https://files.pythonhosted.org/packages/a3/0c/3921a207f47d52abc81a9d00d8f4d579b05b85670e23bc7140e39268490d/highspy-1.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:20a3adf8820a5f7a9cee6fc76df625e651ecfd8b5898af2a77042e79269ce0bc", size = 1908641, upload-time = "2025-06-06T00:46:12.706Z" }, + { url = "https://files.pythonhosted.org/packages/0a/b6/ea7ea6c4c3f781b007fe928b2aefa40c49287b4689985d04c3b20d383475/highspy-1.11.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d4bc0a84cf613bb8565f9b5f610eb0655384162f509b5d86f9c888570275fdc", size = 2119574, upload-time = "2025-06-06T00:46:14.261Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0c/94f1ccb6606e8445a7a0c68d983e47f64899582c64fcea651f488eaaaea0/highspy-1.11.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:543789b75c396a904cb550de34eb333f1a184e123dadc9903b5e6dbca18a007b", size = 2441487, upload-time = "2025-06-06T00:46:16.286Z" }, + { url = "https://files.pythonhosted.org/packages/ad/aa/e7c4ac05162187c484bb121f50d8e037c13bf894ed5cf4e781e1cff68762/highspy-1.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a23949e4f44b6df0ed8c387a7c733d683a0fa66e3ff15d65719979ce2099ee99", size = 2302302, upload-time = "2025-06-06T00:46:18.819Z" }, + { url = "https://files.pythonhosted.org/packages/04/ce/fd2473bed635eb06d116f987767d5c5fe3c62b317fb1a788c31966d7fa0a/highspy-1.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:50dacf300ebe7c4dca92891c0bf61b694f2ca744207cf7d0d24f2a30ffb5608c", size = 3101885, upload-time = "2025-06-06T00:46:20.774Z" }, + { url = "https://files.pythonhosted.org/packages/6e/e1/bf174389656de5d302ed53dd5cdeb5f7e9ad84156ad2fc95d5a63ba023f2/highspy-1.11.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a782c242b4b047f86110787b0dafce9d77cc10f079adab1fd51c5331e5760127", size = 3647952, upload-time = "2025-06-06T00:46:22.847Z" }, + { url = "https://files.pythonhosted.org/packages/f3/f5/42f6f2ce99c5b9d7aa864ac3abeaf8a2b66da707821ab42b0a31ec2a0dc1/highspy-1.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:15b804387089a389e5f01b056a4b3ad74c7d1cf00ab00a0faaf3b4a582bb664c", size = 3309616, upload-time = "2025-06-06T00:46:24.888Z" }, + { url = "https://files.pythonhosted.org/packages/47/f5/cf13640ed65ea934b45e0c3e786497f4696f286faf45e8e62579a0f15462/highspy-1.11.0-cp312-cp312-win32.whl", hash = "sha256:8c33f68df8ab9666d379b0d64d04775c0a9db31882d4f87b3ec8cece0003b47d", size = 1710641, upload-time = "2025-06-06T00:46:26.462Z" }, + { url = "https://files.pythonhosted.org/packages/b7/2f/7acfea5b8d32b86bdec018f858bc195236b804a22a7cd3349da711498692/highspy-1.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0aed8c80d33e2fc2eb1def75dbd34c9fa463acb589d19a5ed5dcc0178ae7062", size = 1985767, upload-time = "2025-06-06T00:46:28.144Z" }, + { url = "https://files.pythonhosted.org/packages/96/84/3e899c5d95dc9d5400a308e0aaf4a5143f69016a4f46dd528ff7cd65d341/highspy-1.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f675cda73860c7c8a22546db3c80db985720baea84866b08a971cfa03cc7a156", size = 2232867, upload-time = "2025-06-06T00:46:29.651Z" }, + { url = "https://files.pythonhosted.org/packages/74/e2/2853095a74e9fc2c2081340647be8edba7122696534ebbaf159ceb53f9b4/highspy-1.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7babebfc01b7682c69c95e0520614ec9400e10cec1b84d3fb7cd48535c606244", size = 1908601, upload-time = "2025-06-06T00:46:31.232Z" }, + { url = "https://files.pythonhosted.org/packages/e6/36/3cabdd3ae8610912962bad96f4d4d6702255d6c01d050754e4050a9eaa4a/highspy-1.11.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39fb60d84d7a58e58f923ea6f0641e6978eb9049033b84de1a2add723e01cd3f", size = 2119726, upload-time = "2025-06-06T00:46:32.796Z" }, + { url = "https://files.pythonhosted.org/packages/a9/da/200d3f13ca9ad3f9fc11a1f3f76cc2734de42dae064510365d42caeb5ed4/highspy-1.11.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c2e7cf4d504287cd8910de322a726d58428af43bb985d6bae602bf84a7454b9", size = 2441449, upload-time = "2025-06-06T00:46:35.147Z" }, + { url = "https://files.pythonhosted.org/packages/6c/58/fc3775850dc668006039637a4f23f03a9c0eb533643c9d3a7370f9d63de2/highspy-1.11.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79682aa7855d94106ccbbb750082d156dcbb57dff9d489f167320ae0ce768867", size = 2302685, upload-time = "2025-06-06T00:46:36.791Z" }, + { url = "https://files.pythonhosted.org/packages/b5/16/e13326a9706c407d32e39ad14aa79a696c1eb49bb13d50fde5d96afb02b5/highspy-1.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:65232aa496fb27be56cc85b2c7c785fac866107c32ea00cc38ec474d6a9f6494", size = 3102306, upload-time = "2025-06-06T00:46:38.341Z" }, + { url = "https://files.pythonhosted.org/packages/0e/93/468e63b16d9bf123174e7f8f7b8bd5a2f96b18d7370a2cc35e6485871749/highspy-1.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f78f27e18275d3c7868dcd0314ea535ed361322e7f0817363872d75a4cc15abc", size = 3648234, upload-time = "2025-06-06T00:46:40.895Z" }, + { url = "https://files.pythonhosted.org/packages/dc/c5/37b849a69c9cbccf533a9a51e309a49e83d704f06bf45370c2e78ceb15d4/highspy-1.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6156a7d643268456427b6fe310626ad9ee9d908ff812cc64ee8bad7b9872ea98", size = 3309724, upload-time = "2025-06-06T00:46:43.083Z" }, + { url = "https://files.pythonhosted.org/packages/90/0f/89c579b2f718dc419fd76067a03ecb3c96e6919b7cffee1b9f5a2dfe4f56/highspy-1.11.0-cp313-cp313-win32.whl", hash = "sha256:e61facebb0127eb3661db79a11c7665e47229ec63d2b425996d04aeede26d46b", size = 1710676, upload-time = "2025-06-06T00:46:45.132Z" }, + { url = "https://files.pythonhosted.org/packages/20/ca/ba2af91f2418bee0d0e99df71dcd171ca863675de6a5260bbf06c120f084/highspy-1.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:ceac08be37f75dc0af95669a0cfb073e5db5f07ead05cdcc81fd4b4394708d53", size = 1985967, upload-time = "2025-06-06T00:46:46.767Z" }, ] [[package]] -name = "jupyter-server" -version = "2.16.0" +name = "identify" +version = "2.6.12" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "argon2-cffi" }, - { name = "jinja2" }, - { name = "jupyter-client" }, - { name = "jupyter-core" }, - { name = "jupyter-events" }, - { name = "jupyter-server-terminals" }, - { name = "nbconvert" }, - { name = "nbformat" }, - { name = "overrides" }, - { name = "packaging" }, - { name = "prometheus-client" }, - { name = "pywinpty", marker = "os_name == 'nt'" }, - { name = "pyzmq" }, - { name = "send2trash" }, - { name = "terminado" }, - { name = "tornado" }, - { name = "traitlets" }, - { name = "websocket-client" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/41/c8/ba2bbcd758c47f1124c4ca14061e8ce60d9c6fd537faee9534a95f83521a/jupyter_server-2.16.0.tar.gz", hash = "sha256:65d4b44fdf2dcbbdfe0aa1ace4a842d4aaf746a2b7b168134d5aaed35621b7f6", size = 728177, upload-time = "2025-05-12T16:44:46.245Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/88/d193a27416618628a5eea64e3223acd800b40749a96ffb322a9b55a49ed1/identify-2.6.12.tar.gz", hash = "sha256:d8de45749f1efb108badef65ee8386f0f7bb19a7f26185f74de6367bffbaf0e6", size = 99254, upload-time = "2025-05-23T20:37:53.3Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/46/1f/5ebbced977171d09a7b0c08a285ff9a20aafb9c51bde07e52349ff1ddd71/jupyter_server-2.16.0-py3-none-any.whl", hash = "sha256:3d8db5be3bc64403b1c65b400a1d7f4647a5ce743f3b20dbdefe8ddb7b55af9e", size = 386904, upload-time = "2025-05-12T16:44:43.335Z" }, + { url = "https://files.pythonhosted.org/packages/7a/cd/18f8da995b658420625f7ef13f037be53ae04ec5ad33f9b718240dcfd48c/identify-2.6.12-py2.py3-none-any.whl", hash = "sha256:ad9672d5a72e0d2ff7c5c8809b62dfa60458626352fb0eb7b55e69bdc45334a2", size = 99145, upload-time = "2025-05-23T20:37:51.495Z" }, ] [[package]] -name = "jupyter-server-terminals" -version = "0.5.3" +name = "idna" +version = "3.10" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pywinpty", marker = "os_name == 'nt'" }, - { name = "terminado" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/d5/562469734f476159e99a55426d697cbf8e7eb5efe89fb0e0b4f83a3d3459/jupyter_server_terminals-0.5.3.tar.gz", hash = "sha256:5ae0295167220e9ace0edcfdb212afd2b01ee8d179fe6f23c899590e9b8a5269", size = 31430, upload-time = "2024-03-12T14:37:03.049Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/2d/2b32cdbe8d2a602f697a649798554e4f072115438e92249624e532e8aca6/jupyter_server_terminals-0.5.3-py3-none-any.whl", hash = "sha256:41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa", size = 13656, upload-time = "2024-03-12T14:37:00.708Z" }, + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, ] [[package]] -name = "jupyterlab" -version = "4.4.4" +name = "imagesize" +version = "1.4.1" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "async-lru" }, - { name = "httpx" }, - { name = "ipykernel" }, - { name = "jinja2" }, - { name = "jupyter-core" }, - { name = "jupyter-lsp" }, - { name = "jupyter-server" }, - { name = "jupyterlab-server" }, - { name = "notebook-shim" }, - { name = "packaging" }, - { name = "setuptools" }, - { name = "tornado" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e2/4d/7ca5b46ea56742880d71a768a9e6fb8f8482228427eb89492d55c5d0bb7d/jupyterlab-4.4.4.tar.gz", hash = "sha256:163fee1ef702e0a057f75d2eed3ed1da8a986d59eb002cbeb6f0c2779e6cd153", size = 23044296, upload-time = "2025-06-28T13:07:20.708Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026, upload-time = "2022-07-01T12:21:05.687Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/82/66910ce0995dbfdb33609f41c99fe32ce483b9624a3e7d672af14ff63b9f/jupyterlab-4.4.4-py3-none-any.whl", hash = "sha256:711611e4f59851152eb93316c3547c3ec6291f16bb455f1f4fa380d25637e0dd", size = 12296310, upload-time = "2025-06-28T13:07:15.676Z" }, + { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769, upload-time = "2022-07-01T12:21:02.467Z" }, ] [[package]] -name = "jupyterlab-pygments" -version = "0.3.0" +name = "iniconfig" +version = "2.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/90/51/9187be60d989df97f5f0aba133fa54e7300f17616e065d1ada7d7646b6d6/jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", size = 512900, upload-time = "2023-11-23T09:26:37.44Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", size = 15884, upload-time = "2023-11-23T09:26:34.325Z" }, + { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, ] [[package]] -name = "jupyterlab-server" -version = "2.27.3" +name = "jinja2" +version = "3.1.6" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "babel" }, - { name = "jinja2" }, - { name = "json5" }, - { name = "jsonschema" }, - { name = "jupyter-server" }, - { name = "packaging" }, - { name = "requests" }, + { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0a/c9/a883ce65eb27905ce77ace410d83587c82ea64dc85a48d1f7ed52bcfa68d/jupyterlab_server-2.27.3.tar.gz", hash = "sha256:eb36caca59e74471988f0ae25c77945610b887f777255aa21f8065def9e51ed4", size = 76173, upload-time = "2024-07-16T17:02:04.149Z" } +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/09/2032e7d15c544a0e3cd831c51d77a8ca57f7555b2e1b2922142eddb02a84/jupyterlab_server-2.27.3-py3-none-any.whl", hash = "sha256:e697488f66c3db49df675158a77b3b017520d772c6e1548c7d9bcc5df7944ee4", size = 59700, upload-time = "2024-07-16T17:02:01.115Z" }, + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, ] [[package]] -name = "jupyterlab-widgets" -version = "3.0.15" +name = "joblib" +version = "1.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b9/7d/160595ca88ee87ac6ba95d82177d29ec60aaa63821d3077babb22ce031a5/jupyterlab_widgets-3.0.15.tar.gz", hash = "sha256:2920888a0c2922351a9202817957a68c07d99673504d6cd37345299e971bb08b", size = 213149, upload-time = "2025-05-05T12:32:31.004Z" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/fe/0f5a938c54105553436dbff7a61dc4fed4b1b2c98852f8833beaf4d5968f/joblib-1.5.1.tar.gz", hash = "sha256:f4f86e351f39fe3d0d32a9f2c3d8af1ee4cec285aafcb27003dda5205576b444", size = 330475, upload-time = "2025-05-23T12:04:37.097Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/43/6a/ca128561b22b60bd5a0c4ea26649e68c8556b82bc70a0c396eebc977fe86/jupyterlab_widgets-3.0.15-py3-none-any.whl", hash = "sha256:d59023d7d7ef71400d51e6fee9a88867f6e65e10a4201605d2d7f3e8f012a31c", size = 216571, upload-time = "2025-05-05T12:32:29.534Z" }, + { url = "https://files.pythonhosted.org/packages/7d/4f/1195bbac8e0c2acc5f740661631d8d750dc38d4a32b23ee5df3cde6f4e0d/joblib-1.5.1-py3-none-any.whl", hash = "sha256:4719a31f054c7d766948dcd83e9613686b27114f190f717cec7eaa2084f8a74a", size = 307746, upload-time = "2025-05-23T12:04:35.124Z" }, ] [[package]] @@ -1300,70 +428,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b5/40/23569737873cc9637fd488606347e9dd92b9fa37ba4fcda1f98ee5219a97/latexcodec-3.0.1-py3-none-any.whl", hash = "sha256:a9eb8200bff693f0437a69581f7579eb6bca25c4193515c09900ce76451e452e", size = 18532, upload-time = "2025-06-17T18:47:30.726Z" }, ] -[[package]] -name = "lxml" -version = "6.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c5/ed/60eb6fa2923602fba988d9ca7c5cdbd7cf25faa795162ed538b527a35411/lxml-6.0.0.tar.gz", hash = "sha256:032e65120339d44cdc3efc326c9f660f5f7205f3a535c1fdbf898b29ea01fb72", size = 4096938, upload-time = "2025-06-26T16:28:19.373Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/89/c3/d01d735c298d7e0ddcedf6f028bf556577e5ab4f4da45175ecd909c79378/lxml-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78718d8454a6e928470d511bf8ac93f469283a45c354995f7d19e77292f26108", size = 8429515, upload-time = "2025-06-26T16:26:06.776Z" }, - { url = "https://files.pythonhosted.org/packages/06/37/0e3eae3043d366b73da55a86274a590bae76dc45aa004b7042e6f97803b1/lxml-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:84ef591495ffd3f9dcabffd6391db7bb70d7230b5c35ef5148354a134f56f2be", size = 4601387, upload-time = "2025-06-26T16:26:09.511Z" }, - { url = "https://files.pythonhosted.org/packages/a3/28/e1a9a881e6d6e29dda13d633885d13acb0058f65e95da67841c8dd02b4a8/lxml-6.0.0-cp312-cp312-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:2930aa001a3776c3e2601cb8e0a15d21b8270528d89cc308be4843ade546b9ab", size = 5228928, upload-time = "2025-06-26T16:26:12.337Z" }, - { url = "https://files.pythonhosted.org/packages/9a/55/2cb24ea48aa30c99f805921c1c7860c1f45c0e811e44ee4e6a155668de06/lxml-6.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:219e0431ea8006e15005767f0351e3f7f9143e793e58519dc97fe9e07fae5563", size = 4952289, upload-time = "2025-06-28T18:47:25.602Z" }, - { url = "https://files.pythonhosted.org/packages/31/c0/b25d9528df296b9a3306ba21ff982fc5b698c45ab78b94d18c2d6ae71fd9/lxml-6.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bd5913b4972681ffc9718bc2d4c53cde39ef81415e1671ff93e9aa30b46595e7", size = 5111310, upload-time = "2025-06-28T18:47:28.136Z" }, - { url = "https://files.pythonhosted.org/packages/e9/af/681a8b3e4f668bea6e6514cbcb297beb6de2b641e70f09d3d78655f4f44c/lxml-6.0.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:390240baeb9f415a82eefc2e13285016f9c8b5ad71ec80574ae8fa9605093cd7", size = 5025457, upload-time = "2025-06-26T16:26:15.068Z" }, - { url = "https://files.pythonhosted.org/packages/99/b6/3a7971aa05b7be7dfebc7ab57262ec527775c2c3c5b2f43675cac0458cad/lxml-6.0.0-cp312-cp312-manylinux_2_27_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d6e200909a119626744dd81bae409fc44134389e03fbf1d68ed2a55a2fb10991", size = 5657016, upload-time = "2025-07-03T19:19:06.008Z" }, - { url = "https://files.pythonhosted.org/packages/69/f8/693b1a10a891197143c0673fcce5b75fc69132afa81a36e4568c12c8faba/lxml-6.0.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ca50bd612438258a91b5b3788c6621c1f05c8c478e7951899f492be42defc0da", size = 5257565, upload-time = "2025-06-26T16:26:17.906Z" }, - { url = "https://files.pythonhosted.org/packages/a8/96/e08ff98f2c6426c98c8964513c5dab8d6eb81dadcd0af6f0c538ada78d33/lxml-6.0.0-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:c24b8efd9c0f62bad0439283c2c795ef916c5a6b75f03c17799775c7ae3c0c9e", size = 4713390, upload-time = "2025-06-26T16:26:20.292Z" }, - { url = "https://files.pythonhosted.org/packages/a8/83/6184aba6cc94d7413959f6f8f54807dc318fdcd4985c347fe3ea6937f772/lxml-6.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:afd27d8629ae94c5d863e32ab0e1d5590371d296b87dae0a751fb22bf3685741", size = 5066103, upload-time = "2025-06-26T16:26:22.765Z" }, - { url = "https://files.pythonhosted.org/packages/ee/01/8bf1f4035852d0ff2e36a4d9aacdbcc57e93a6cd35a54e05fa984cdf73ab/lxml-6.0.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:54c4855eabd9fc29707d30141be99e5cd1102e7d2258d2892314cf4c110726c3", size = 4791428, upload-time = "2025-06-26T16:26:26.461Z" }, - { url = "https://files.pythonhosted.org/packages/29/31/c0267d03b16954a85ed6b065116b621d37f559553d9339c7dcc4943a76f1/lxml-6.0.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c907516d49f77f6cd8ead1322198bdfd902003c3c330c77a1c5f3cc32a0e4d16", size = 5678523, upload-time = "2025-07-03T19:19:09.837Z" }, - { url = "https://files.pythonhosted.org/packages/5c/f7/5495829a864bc5f8b0798d2b52a807c89966523140f3d6fa3a58ab6720ea/lxml-6.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:36531f81c8214e293097cd2b7873f178997dae33d3667caaae8bdfb9666b76c0", size = 5281290, upload-time = "2025-06-26T16:26:29.406Z" }, - { url = "https://files.pythonhosted.org/packages/79/56/6b8edb79d9ed294ccc4e881f4db1023af56ba451909b9ce79f2a2cd7c532/lxml-6.0.0-cp312-cp312-win32.whl", hash = "sha256:690b20e3388a7ec98e899fd54c924e50ba6693874aa65ef9cb53de7f7de9d64a", size = 3613495, upload-time = "2025-06-26T16:26:31.588Z" }, - { url = "https://files.pythonhosted.org/packages/0b/1e/cc32034b40ad6af80b6fd9b66301fc0f180f300002e5c3eb5a6110a93317/lxml-6.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:310b719b695b3dd442cdfbbe64936b2f2e231bb91d998e99e6f0daf991a3eba3", size = 4014711, upload-time = "2025-06-26T16:26:33.723Z" }, - { url = "https://files.pythonhosted.org/packages/55/10/dc8e5290ae4c94bdc1a4c55865be7e1f31dfd857a88b21cbba68b5fea61b/lxml-6.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:8cb26f51c82d77483cdcd2b4a53cda55bbee29b3c2f3ddeb47182a2a9064e4eb", size = 3674431, upload-time = "2025-06-26T16:26:35.959Z" }, - { url = "https://files.pythonhosted.org/packages/79/21/6e7c060822a3c954ff085e5e1b94b4a25757c06529eac91e550f3f5cd8b8/lxml-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6da7cd4f405fd7db56e51e96bff0865b9853ae70df0e6720624049da76bde2da", size = 8414372, upload-time = "2025-06-26T16:26:39.079Z" }, - { url = "https://files.pythonhosted.org/packages/a4/f6/051b1607a459db670fc3a244fa4f06f101a8adf86cda263d1a56b3a4f9d5/lxml-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b34339898bb556a2351a1830f88f751679f343eabf9cf05841c95b165152c9e7", size = 4593940, upload-time = "2025-06-26T16:26:41.891Z" }, - { url = "https://files.pythonhosted.org/packages/8e/74/dd595d92a40bda3c687d70d4487b2c7eff93fd63b568acd64fedd2ba00fe/lxml-6.0.0-cp313-cp313-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:51a5e4c61a4541bd1cd3ba74766d0c9b6c12d6a1a4964ef60026832aac8e79b3", size = 5214329, upload-time = "2025-06-26T16:26:44.669Z" }, - { url = "https://files.pythonhosted.org/packages/52/46/3572761efc1bd45fcafb44a63b3b0feeb5b3f0066886821e94b0254f9253/lxml-6.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d18a25b19ca7307045581b18b3ec9ead2b1db5ccd8719c291f0cd0a5cec6cb81", size = 4947559, upload-time = "2025-06-28T18:47:31.091Z" }, - { url = "https://files.pythonhosted.org/packages/94/8a/5e40de920e67c4f2eef9151097deb9b52d86c95762d8ee238134aff2125d/lxml-6.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d4f0c66df4386b75d2ab1e20a489f30dc7fd9a06a896d64980541506086be1f1", size = 5102143, upload-time = "2025-06-28T18:47:33.612Z" }, - { url = "https://files.pythonhosted.org/packages/7c/4b/20555bdd75d57945bdabfbc45fdb1a36a1a0ff9eae4653e951b2b79c9209/lxml-6.0.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9f4b481b6cc3a897adb4279216695150bbe7a44c03daba3c894f49d2037e0a24", size = 5021931, upload-time = "2025-06-26T16:26:47.503Z" }, - { url = "https://files.pythonhosted.org/packages/b6/6e/cf03b412f3763d4ca23b25e70c96a74cfece64cec3addf1c4ec639586b13/lxml-6.0.0-cp313-cp313-manylinux_2_27_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a78d6c9168f5bcb20971bf3329c2b83078611fbe1f807baadc64afc70523b3a", size = 5645469, upload-time = "2025-07-03T19:19:13.32Z" }, - { url = "https://files.pythonhosted.org/packages/d4/dd/39c8507c16db6031f8c1ddf70ed95dbb0a6d466a40002a3522c128aba472/lxml-6.0.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ae06fbab4f1bb7db4f7c8ca9897dc8db4447d1a2b9bee78474ad403437bcc29", size = 5247467, upload-time = "2025-06-26T16:26:49.998Z" }, - { url = "https://files.pythonhosted.org/packages/4d/56/732d49def0631ad633844cfb2664563c830173a98d5efd9b172e89a4800d/lxml-6.0.0-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:1fa377b827ca2023244a06554c6e7dc6828a10aaf74ca41965c5d8a4925aebb4", size = 4720601, upload-time = "2025-06-26T16:26:52.564Z" }, - { url = "https://files.pythonhosted.org/packages/8f/7f/6b956fab95fa73462bca25d1ea7fc8274ddf68fb8e60b78d56c03b65278e/lxml-6.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1676b56d48048a62ef77a250428d1f31f610763636e0784ba67a9740823988ca", size = 5060227, upload-time = "2025-06-26T16:26:55.054Z" }, - { url = "https://files.pythonhosted.org/packages/97/06/e851ac2924447e8b15a294855caf3d543424364a143c001014d22c8ca94c/lxml-6.0.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:0e32698462aacc5c1cf6bdfebc9c781821b7e74c79f13e5ffc8bfe27c42b1abf", size = 4790637, upload-time = "2025-06-26T16:26:57.384Z" }, - { url = "https://files.pythonhosted.org/packages/06/d4/fd216f3cd6625022c25b336c7570d11f4a43adbaf0a56106d3d496f727a7/lxml-6.0.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4d6036c3a296707357efb375cfc24bb64cd955b9ec731abf11ebb1e40063949f", size = 5662049, upload-time = "2025-07-03T19:19:16.409Z" }, - { url = "https://files.pythonhosted.org/packages/52/03/0e764ce00b95e008d76b99d432f1807f3574fb2945b496a17807a1645dbd/lxml-6.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7488a43033c958637b1a08cddc9188eb06d3ad36582cebc7d4815980b47e27ef", size = 5272430, upload-time = "2025-06-26T16:27:00.031Z" }, - { url = "https://files.pythonhosted.org/packages/5f/01/d48cc141bc47bc1644d20fe97bbd5e8afb30415ec94f146f2f76d0d9d098/lxml-6.0.0-cp313-cp313-win32.whl", hash = "sha256:5fcd7d3b1d8ecb91445bd71b9c88bdbeae528fefee4f379895becfc72298d181", size = 3612896, upload-time = "2025-06-26T16:27:04.251Z" }, - { url = "https://files.pythonhosted.org/packages/f4/87/6456b9541d186ee7d4cb53bf1b9a0d7f3b1068532676940fdd594ac90865/lxml-6.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:2f34687222b78fff795feeb799a7d44eca2477c3d9d3a46ce17d51a4f383e32e", size = 4013132, upload-time = "2025-06-26T16:27:06.415Z" }, - { url = "https://files.pythonhosted.org/packages/b7/42/85b3aa8f06ca0d24962f8100f001828e1f1f1a38c954c16e71154ed7d53a/lxml-6.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:21db1ec5525780fd07251636eb5f7acb84003e9382c72c18c542a87c416ade03", size = 3672642, upload-time = "2025-06-26T16:27:09.888Z" }, -] - -[[package]] -name = "mako" -version = "1.3.10" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9e/38/bd5b78a920a64d708fe6bc8e0a2c075e1389d53bef8413725c63ba041535/mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28", size = 392474, upload-time = "2025-04-10T12:44:31.16Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59", size = 78509, upload-time = "2025-04-10T12:50:53.297Z" }, -] - -[[package]] -name = "markdown-it-py" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, -] - [[package]] name = "markupsafe" version = "3.0.2" @@ -1438,36 +502,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/01/8a/760f7fce66b39f447ad160800619d0bd5d0936d2b4633587116534a4afe0/matplotlib-3.9.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5816b1e1fe8c192cbc013f8f3e3368ac56fbecf02fb41b8f8559303f24c5015e", size = 9093770, upload-time = "2024-08-13T01:45:15.562Z" }, ] -[[package]] -name = "matplotlib-inline" -version = "0.1.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/99/5b/a36a337438a14116b16480db471ad061c36c3694df7c2084a0da7ba538b7/matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", size = 8159, upload-time = "2024-04-15T13:44:44.803Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899, upload-time = "2024-04-15T13:44:43.265Z" }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, -] - -[[package]] -name = "mistune" -version = "3.1.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c4/79/bda47f7dd7c3c55770478d6d02c9960c430b0cf1773b72366ff89126ea31/mistune-3.1.3.tar.gz", hash = "sha256:a7035c21782b2becb6be62f8f25d3df81ccb4d6fa477a6525b15af06539f02a0", size = 94347, upload-time = "2025-03-19T14:27:24.955Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/01/4d/23c4e4f09da849e127e9f123241946c23c1e30f45a88366879e064211815/mistune-3.1.3-py3-none-any.whl", hash = "sha256:1a32314113cff28aa6432e99e522677c8587fd83e3d51c29b82a52409c842bd9", size = 53410, upload-time = "2025-03-19T14:27:23.451Z" }, -] - [[package]] name = "multiprocess" version = "0.70.18" @@ -1520,70 +554,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, ] -[[package]] -name = "nbclient" -version = "0.10.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jupyter-client" }, - { name = "jupyter-core" }, - { name = "nbformat" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/87/66/7ffd18d58eae90d5721f9f39212327695b749e23ad44b3881744eaf4d9e8/nbclient-0.10.2.tar.gz", hash = "sha256:90b7fc6b810630db87a6d0c2250b1f0ab4cf4d3c27a299b0cde78a4ed3fd9193", size = 62424, upload-time = "2024-12-19T10:32:27.164Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/34/6d/e7fa07f03a4a7b221d94b4d586edb754a9b0dc3c9e2c93353e9fa4e0d117/nbclient-0.10.2-py3-none-any.whl", hash = "sha256:4ffee11e788b4a27fabeb7955547e4318a5298f34342a4bfd01f2e1faaeadc3d", size = 25434, upload-time = "2024-12-19T10:32:24.139Z" }, -] - -[[package]] -name = "nbconvert" -version = "7.16.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "beautifulsoup4" }, - { name = "bleach", extra = ["css"] }, - { name = "defusedxml" }, - { name = "jinja2" }, - { name = "jupyter-core" }, - { name = "jupyterlab-pygments" }, - { name = "markupsafe" }, - { name = "mistune" }, - { name = "nbclient" }, - { name = "nbformat" }, - { name = "packaging" }, - { name = "pandocfilters" }, - { name = "pygments" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a3/59/f28e15fc47ffb73af68a8d9b47367a8630d76e97ae85ad18271b9db96fdf/nbconvert-7.16.6.tar.gz", hash = "sha256:576a7e37c6480da7b8465eefa66c17844243816ce1ccc372633c6b71c3c0f582", size = 857715, upload-time = "2025-01-28T09:29:14.724Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/9a/cd673b2f773a12c992f41309ef81b99da1690426bd2f96957a7ade0d3ed7/nbconvert-7.16.6-py3-none-any.whl", hash = "sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b", size = 258525, upload-time = "2025-01-28T09:29:12.551Z" }, -] - -[[package]] -name = "nbformat" -version = "5.10.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "fastjsonschema" }, - { name = "jsonschema" }, - { name = "jupyter-core" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/91545e604bc3dad7dca9ed03284086039b294c6b3d75c0d2fa45f9e9caf3/nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", size = 142749, upload-time = "2024-04-04T11:20:37.371Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454, upload-time = "2024-04-04T11:20:34.895Z" }, -] - -[[package]] -name = "nest-asyncio" -version = "1.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418, upload-time = "2024-01-21T14:25:19.227Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, -] - [[package]] name = "networkx" version = "3.5" @@ -1611,34 +581,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/15/d8/dd071918c040f50fa1cf80da16423af51ff8ce4a0f2399b7bf8de45ac3d9/nose-1.3.7-py3-none-any.whl", hash = "sha256:9ff7c6cc443f8c51994b34a667bbcf45afd6d945be7477b52e97516fd17c53ac", size = 154731, upload-time = "2015-06-02T09:12:40.57Z" }, ] -[[package]] -name = "notebook" -version = "7.4.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jupyter-server" }, - { name = "jupyterlab" }, - { name = "jupyterlab-server" }, - { name = "notebook-shim" }, - { name = "tornado" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b1/4e/a40b5a94eb01fc51746db7854296d88b84905ab18ee0fcef853a60d708a3/notebook-7.4.4.tar.gz", hash = "sha256:392fd501e266f2fb3466c6fcd3331163a2184968cb5c5accf90292e01dfe528c", size = 13883628, upload-time = "2025-06-30T13:04:18.099Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/c0/e64d2047fd752249b0b69f6aee2a7049eb94e7273e5baabc8b8ad05cc068/notebook-7.4.4-py3-none-any.whl", hash = "sha256:32840f7f777b6bff79bb101159336e9b332bdbfba1495b8739e34d1d65cbc1c0", size = 14288000, upload-time = "2025-06-30T13:04:14.584Z" }, -] - -[[package]] -name = "notebook-shim" -version = "0.2.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jupyter-server" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/54/d2/92fa3243712b9a3e8bafaf60aac366da1cada3639ca767ff4b5b3654ec28/notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb", size = 13167, upload-time = "2024-02-14T23:35:18.353Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", size = 13307, upload-time = "2024-02-14T23:35:16.286Z" }, -] - [[package]] name = "numpy" version = "2.3.1" @@ -1692,15 +634,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c0/da/977ded879c29cbd04de313843e76868e6e13408a94ed6b987245dc7c8506/openpyxl-3.1.5-py2.py3-none-any.whl", hash = "sha256:5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2", size = 250910, upload-time = "2024-06-28T14:03:41.161Z" }, ] -[[package]] -name = "overrides" -version = "7.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812, upload-time = "2024-01-27T21:01:33.423Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832, upload-time = "2024-01-27T21:01:31.393Z" }, -] - [[package]] name = "packaging" version = "25.0" @@ -1757,40 +690,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/40/96/1e4a035eaf4dce9610aac6e43026d0c6baa05773daf6d21e635a4fe19e21/pandas_stubs-2.3.2.250926-py3-none-any.whl", hash = "sha256:81121818453dcfe00f45c852f4dceee043640b813830f6e7bd084a4ef7ff7270", size = 159995, upload-time = "2025-09-26T19:50:38.241Z" }, ] -[[package]] -name = "pandera" -version = "0.25.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging" }, - { name = "pydantic" }, - { name = "typeguard" }, - { name = "typing-extensions" }, - { name = "typing-inspect" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/13/c1/02f78cd18cd32a009405c847dcf430a97d1a8c162f6e8872acae928c8f20/pandera-0.25.0.tar.gz", hash = "sha256:af3bbaa163672c91b83d59d70715f25c4134dbccfc8bc89a642a2f0e23db951e", size = 555391, upload-time = "2025-07-08T19:20:22.106Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/71/e0/234707103c742555e1c23bff51f3f0e496c144cd76fcf5a6b800dfe193f2/pandera-0.25.0-py3-none-any.whl", hash = "sha256:365a555accc46404466641203e297722d424d74a1315f077ab899e1344f82303", size = 293336, upload-time = "2025-07-08T19:20:20.44Z" }, -] - -[[package]] -name = "pandocfilters" -version = "1.5.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/70/6f/3dd4940bbe001c06a65f88e36bad298bc7a0de5036115639926b0c5c0458/pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", size = 8454, upload-time = "2024-01-18T20:08:13.726Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663, upload-time = "2024-01-18T20:08:11.28Z" }, -] - -[[package]] -name = "parso" -version = "0.8.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/66/94/68e2e17afaa9169cf6412ab0f28623903be73d1b32e208d9e8e541bb086d/parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d", size = 400609, upload-time = "2024-04-05T09:43:55.897Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", size = 103650, upload-time = "2024-04-05T09:43:53.299Z" }, -] - [[package]] name = "pathspec" version = "0.12.1" @@ -1800,18 +699,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, ] -[[package]] -name = "pexpect" -version = "4.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ptyprocess" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, -] - [[package]] name = "pillow" version = "11.3.0" @@ -1878,21 +765,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/89/c7/5572fa4a3f45740eaab6ae86fcdf7195b55beac1371ac8c619d880cfe948/pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa", size = 2512835, upload-time = "2025-07-01T09:15:50.399Z" }, ] -[[package]] -name = "pint" -version = "0.24.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "flexcache" }, - { name = "flexparser" }, - { name = "platformdirs" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/20/bb/52b15ddf7b7706ed591134a895dbf6e41c8348171fb635e655e0a4bbb0ea/pint-0.24.4.tar.gz", hash = "sha256:35275439b574837a6cd3020a5a4a73645eb125ce4152a73a2f126bf164b91b80", size = 342225, upload-time = "2024-11-07T16:29:46.061Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/16/bd2f5904557265882108dc2e04f18abc05ab0c2b7082ae9430091daf1d5c/Pint-0.24.4-py3-none-any.whl", hash = "sha256:aa54926c8772159fcf65f82cc0d34de6768c151b32ad1deb0331291c38fe7659", size = 302029, upload-time = "2024-11-07T16:29:43.976Z" }, -] - [[package]] name = "platformdirs" version = "4.3.8" @@ -1928,137 +800,12 @@ dependencies = [ { name = "cfgv" }, { name = "identify" }, { name = "nodeenv" }, - { name = "pyyaml" }, - { name = "virtualenv" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/08/39/679ca9b26c7bb2999ff122d50faa301e49af82ca9c066ec061cfbc0c6784/pre_commit-4.2.0.tar.gz", hash = "sha256:601283b9757afd87d40c4c4a9b2b5de9637a8ea02eaff7adc2d0fb4e04841146", size = 193424, upload-time = "2025-03-18T21:35:20.987Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/74/a88bf1b1efeae488a0c0b7bdf71429c313722d1fc0f377537fbe554e6180/pre_commit-4.2.0-py2.py3-none-any.whl", hash = "sha256:a009ca7205f1eb497d10b845e52c838a98b6cdd2102a6c8e4540e94ee75c58bd", size = 220707, upload-time = "2025-03-18T21:35:19.343Z" }, -] - -[[package]] -name = "prometheus-client" -version = "0.22.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5e/cf/40dde0a2be27cc1eb41e333d1a674a74ce8b8b0457269cc640fd42b07cf7/prometheus_client-0.22.1.tar.gz", hash = "sha256:190f1331e783cf21eb60bca559354e0a4d4378facecf78f5428c39b675d20d28", size = 69746, upload-time = "2025-06-02T14:29:01.152Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/32/ae/ec06af4fe3ee72d16973474f122541746196aaa16cea6f66d18b963c6177/prometheus_client-0.22.1-py3-none-any.whl", hash = "sha256:cca895342e308174341b2cbf99a56bef291fbc0ef7b9e5412a0f26d653ba7094", size = 58694, upload-time = "2025-06-02T14:29:00.068Z" }, -] - -[[package]] -name = "prompt-toolkit" -version = "3.0.51" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "wcwidth" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bb/6e/9d084c929dfe9e3bfe0c6a47e31f78a25c54627d64a66e884a8bf5474f1c/prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed", size = 428940, upload-time = "2025-04-15T09:18:47.731Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/4f/5249960887b1fbe561d9ff265496d170b55a735b76724f10ef19f9e40716/prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07", size = 387810, upload-time = "2025-04-15T09:18:44.753Z" }, -] - -[[package]] -name = "psutil" -version = "7.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2a/80/336820c1ad9286a4ded7e845b2eccfcb27851ab8ac6abece774a6ff4d3de/psutil-7.0.0.tar.gz", hash = "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456", size = 497003, upload-time = "2025-02-13T21:54:07.946Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/e6/2d26234410f8b8abdbf891c9da62bee396583f713fb9f3325a4760875d22/psutil-7.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25", size = 238051, upload-time = "2025-02-13T21:54:12.36Z" }, - { url = "https://files.pythonhosted.org/packages/04/8b/30f930733afe425e3cbfc0e1468a30a18942350c1a8816acfade80c005c4/psutil-7.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da", size = 239535, upload-time = "2025-02-13T21:54:16.07Z" }, - { url = "https://files.pythonhosted.org/packages/2a/ed/d362e84620dd22876b55389248e522338ed1bf134a5edd3b8231d7207f6d/psutil-7.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91", size = 275004, upload-time = "2025-02-13T21:54:18.662Z" }, - { url = "https://files.pythonhosted.org/packages/bf/b9/b0eb3f3cbcb734d930fdf839431606844a825b23eaf9a6ab371edac8162c/psutil-7.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34", size = 277986, upload-time = "2025-02-13T21:54:21.811Z" }, - { url = "https://files.pythonhosted.org/packages/eb/a2/709e0fe2f093556c17fbafda93ac032257242cabcc7ff3369e2cb76a97aa/psutil-7.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993", size = 279544, upload-time = "2025-02-13T21:54:24.68Z" }, - { url = "https://files.pythonhosted.org/packages/50/e6/eecf58810b9d12e6427369784efe814a1eec0f492084ce8eb8f4d89d6d61/psutil-7.0.0-cp37-abi3-win32.whl", hash = "sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99", size = 241053, upload-time = "2025-02-13T21:54:34.31Z" }, - { url = "https://files.pythonhosted.org/packages/50/1b/6921afe68c74868b4c9fa424dad3be35b095e16687989ebbb50ce4fceb7c/psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553", size = 244885, upload-time = "2025-02-13T21:54:37.486Z" }, -] - -[[package]] -name = "psycopg" -version = "3.2.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, - { name = "tzdata", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/27/4a/93a6ab570a8d1a4ad171a1f4256e205ce48d828781312c0bbaff36380ecb/psycopg-3.2.9.tar.gz", hash = "sha256:2fbb46fcd17bc81f993f28c47f1ebea38d66ae97cc2dbc3cad73b37cefbff700", size = 158122, upload-time = "2025-05-13T16:11:15.533Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/44/b0/a73c195a56eb6b92e937a5ca58521a5c3346fb233345adc80fd3e2f542e2/psycopg-3.2.9-py3-none-any.whl", hash = "sha256:01a8dadccdaac2123c916208c96e06631641c0566b22005493f09663c7a8d3b6", size = 202705, upload-time = "2025-05-13T16:06:26.584Z" }, -] - -[package.optional-dependencies] -binary = [ - { name = "psycopg-binary", marker = "implementation_name != 'pypy'" }, -] - -[[package]] -name = "psycopg-binary" -version = "3.2.9" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/29/6f/ec9957e37a606cd7564412e03f41f1b3c3637a5be018d0849914cb06e674/psycopg_binary-3.2.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:be7d650a434921a6b1ebe3fff324dbc2364393eb29d7672e638ce3e21076974e", size = 4022205, upload-time = "2025-05-13T16:07:48.195Z" }, - { url = "https://files.pythonhosted.org/packages/6b/ba/497b8bea72b20a862ac95a94386967b745a472d9ddc88bc3f32d5d5f0d43/psycopg_binary-3.2.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6a76b4722a529390683c0304501f238b365a46b1e5fb6b7249dbc0ad6fea51a0", size = 4083795, upload-time = "2025-05-13T16:07:50.917Z" }, - { url = "https://files.pythonhosted.org/packages/42/07/af9503e8e8bdad3911fd88e10e6a29240f9feaa99f57d6fac4a18b16f5a0/psycopg_binary-3.2.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96a551e4683f1c307cfc3d9a05fec62c00a7264f320c9962a67a543e3ce0d8ff", size = 4655043, upload-time = "2025-05-13T16:07:54.857Z" }, - { url = "https://files.pythonhosted.org/packages/28/ed/aff8c9850df1648cc6a5cc7a381f11ee78d98a6b807edd4a5ae276ad60ad/psycopg_binary-3.2.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:61d0a6ceed8f08c75a395bc28cb648a81cf8dee75ba4650093ad1a24a51c8724", size = 4477972, upload-time = "2025-05-13T16:07:57.925Z" }, - { url = "https://files.pythonhosted.org/packages/5c/bd/8e9d1b77ec1a632818fe2f457c3a65af83c68710c4c162d6866947d08cc5/psycopg_binary-3.2.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad280bbd409bf598683dda82232f5215cfc5f2b1bf0854e409b4d0c44a113b1d", size = 4737516, upload-time = "2025-05-13T16:08:01.616Z" }, - { url = "https://files.pythonhosted.org/packages/46/ec/222238f774cd5a0881f3f3b18fb86daceae89cc410f91ef6a9fb4556f236/psycopg_binary-3.2.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76eddaf7fef1d0994e3d536ad48aa75034663d3a07f6f7e3e601105ae73aeff6", size = 4436160, upload-time = "2025-05-13T16:08:04.278Z" }, - { url = "https://files.pythonhosted.org/packages/37/78/af5af2a1b296eeca54ea7592cd19284739a844974c9747e516707e7b3b39/psycopg_binary-3.2.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:52e239cd66c4158e412318fbe028cd94b0ef21b0707f56dcb4bdc250ee58fd40", size = 3753518, upload-time = "2025-05-13T16:08:07.567Z" }, - { url = "https://files.pythonhosted.org/packages/ec/ac/8a3ed39ea069402e9e6e6a2f79d81a71879708b31cc3454283314994b1ae/psycopg_binary-3.2.9-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:08bf9d5eabba160dd4f6ad247cf12f229cc19d2458511cab2eb9647f42fa6795", size = 3313598, upload-time = "2025-05-13T16:08:09.999Z" }, - { url = "https://files.pythonhosted.org/packages/da/43/26549af068347c808fbfe5f07d2fa8cef747cfff7c695136172991d2378b/psycopg_binary-3.2.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1b2cf018168cad87580e67bdde38ff5e51511112f1ce6ce9a8336871f465c19a", size = 3407289, upload-time = "2025-05-13T16:08:12.66Z" }, - { url = "https://files.pythonhosted.org/packages/67/55/ea8d227c77df8e8aec880ded398316735add8fda5eb4ff5cc96fac11e964/psycopg_binary-3.2.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:14f64d1ac6942ff089fc7e926440f7a5ced062e2ed0949d7d2d680dc5c00e2d4", size = 3472493, upload-time = "2025-05-13T16:08:15.672Z" }, - { url = "https://files.pythonhosted.org/packages/3c/02/6ff2a5bc53c3cd653d281666728e29121149179c73fddefb1e437024c192/psycopg_binary-3.2.9-cp312-cp312-win_amd64.whl", hash = "sha256:7a838852e5afb6b4126f93eb409516a8c02a49b788f4df8b6469a40c2157fa21", size = 2927400, upload-time = "2025-05-13T16:08:18.652Z" }, - { url = "https://files.pythonhosted.org/packages/28/0b/f61ff4e9f23396aca674ed4d5c9a5b7323738021d5d72d36d8b865b3deaf/psycopg_binary-3.2.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:98bbe35b5ad24a782c7bf267596638d78aa0e87abc7837bdac5b2a2ab954179e", size = 4017127, upload-time = "2025-05-13T16:08:21.391Z" }, - { url = "https://files.pythonhosted.org/packages/bc/00/7e181fb1179fbfc24493738b61efd0453d4b70a0c4b12728e2b82db355fd/psycopg_binary-3.2.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:72691a1615ebb42da8b636c5ca9f2b71f266be9e172f66209a361c175b7842c5", size = 4080322, upload-time = "2025-05-13T16:08:24.049Z" }, - { url = "https://files.pythonhosted.org/packages/58/fd/94fc267c1d1392c4211e54ccb943be96ea4032e761573cf1047951887494/psycopg_binary-3.2.9-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25ab464bfba8c401f5536d5aa95f0ca1dd8257b5202eede04019b4415f491351", size = 4655097, upload-time = "2025-05-13T16:08:27.376Z" }, - { url = "https://files.pythonhosted.org/packages/41/17/31b3acf43de0b2ba83eac5878ff0dea5a608ca2a5c5dd48067999503a9de/psycopg_binary-3.2.9-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e8aeefebe752f46e3c4b769e53f1d4ad71208fe1150975ef7662c22cca80fab", size = 4482114, upload-time = "2025-05-13T16:08:30.781Z" }, - { url = "https://files.pythonhosted.org/packages/85/78/b4d75e5fd5a85e17f2beb977abbba3389d11a4536b116205846b0e1cf744/psycopg_binary-3.2.9-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7e4e4dd177a8665c9ce86bc9caae2ab3aa9360b7ce7ec01827ea1baea9ff748", size = 4737693, upload-time = "2025-05-13T16:08:34.625Z" }, - { url = "https://files.pythonhosted.org/packages/3b/95/7325a8550e3388b00b5e54f4ced5e7346b531eb4573bf054c3dbbfdc14fe/psycopg_binary-3.2.9-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fc2915949e5c1ea27a851f7a472a7da7d0a40d679f0a31e42f1022f3c562e87", size = 4437423, upload-time = "2025-05-13T16:08:37.444Z" }, - { url = "https://files.pythonhosted.org/packages/1a/db/cef77d08e59910d483df4ee6da8af51c03bb597f500f1fe818f0f3b925d3/psycopg_binary-3.2.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a1fa38a4687b14f517f049477178093c39c2a10fdcced21116f47c017516498f", size = 3758667, upload-time = "2025-05-13T16:08:40.116Z" }, - { url = "https://files.pythonhosted.org/packages/95/3e/252fcbffb47189aa84d723b54682e1bb6d05c8875fa50ce1ada914ae6e28/psycopg_binary-3.2.9-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5be8292d07a3ab828dc95b5ee6b69ca0a5b2e579a577b39671f4f5b47116dfd2", size = 3320576, upload-time = "2025-05-13T16:08:43.243Z" }, - { url = "https://files.pythonhosted.org/packages/1c/cd/9b5583936515d085a1bec32b45289ceb53b80d9ce1cea0fef4c782dc41a7/psycopg_binary-3.2.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:778588ca9897b6c6bab39b0d3034efff4c5438f5e3bd52fda3914175498202f9", size = 3411439, upload-time = "2025-05-13T16:08:47.321Z" }, - { url = "https://files.pythonhosted.org/packages/45/6b/6f1164ea1634c87956cdb6db759e0b8c5827f989ee3cdff0f5c70e8331f2/psycopg_binary-3.2.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f0d5b3af045a187aedbd7ed5fc513bd933a97aaff78e61c3745b330792c4345b", size = 3477477, upload-time = "2025-05-13T16:08:51.166Z" }, - { url = "https://files.pythonhosted.org/packages/7b/1d/bf54cfec79377929da600c16114f0da77a5f1670f45e0c3af9fcd36879bc/psycopg_binary-3.2.9-cp313-cp313-win_amd64.whl", hash = "sha256:2290bc146a1b6a9730350f695e8b670e1d1feb8446597bed0bbe7c3c30e0abcb", size = 2928009, upload-time = "2025-05-13T16:08:53.67Z" }, -] - -[[package]] -name = "ptyprocess" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, -] - -[[package]] -name = "pure-eval" -version = "0.2.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, -] - -[[package]] -name = "pyam-iamc" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "iam-units" }, - { name = "ixmp4" }, - { name = "matplotlib" }, - { name = "numpy" }, - { name = "openpyxl" }, - { name = "pandas" }, - { name = "pint" }, - { name = "pyyaml" }, - { name = "requests" }, - { name = "scipy" }, - { name = "seaborn" }, - { name = "wquantiles" }, - { name = "xlsxwriter" }, + { name = "pyyaml" }, + { name = "virtualenv" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/da/8d/9598f38cceed935f83778b53c7368408b5c293e84d33734b3a34c1a54ffe/pyam_iamc-3.0.0.tar.gz", hash = "sha256:ef333da4d239e66516ff31801879cac38384e8ebed70fe7705eec77af1305530", size = 91089, upload-time = "2024-12-19T13:40:52.289Z" } +sdist = { url = "https://files.pythonhosted.org/packages/08/39/679ca9b26c7bb2999ff122d50faa301e49af82ca9c066ec061cfbc0c6784/pre_commit-4.2.0.tar.gz", hash = "sha256:601283b9757afd87d40c4c4a9b2b5de9637a8ea02eaff7adc2d0fb4e04841146", size = 193424, upload-time = "2025-03-18T21:35:20.987Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/a9/10d819bad953f2a83b01e602c1f64cb3c3b3ad0366f3198b995be76910c3/pyam_iamc-3.0.0-py3-none-any.whl", hash = "sha256:54f2b79b286e8c78083184c3b275bd8de7f8107bf6c0694ce4e1f1c9ad561378", size = 99422, upload-time = "2024-12-19T13:40:49.564Z" }, + { url = "https://files.pythonhosted.org/packages/88/74/a88bf1b1efeae488a0c0b7bdf71429c313722d1fc0f377537fbe554e6180/pre_commit-4.2.0-py2.py3-none-any.whl", hash = "sha256:a009ca7205f1eb497d10b845e52c838a98b6cdd2102a6c8e4540e94ee75c58bd", size = 220707, upload-time = "2025-03-18T21:35:19.343Z" }, ] [[package]] @@ -2087,86 +834,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/11/b1/ce1f4596211efb5410e178a803f08e59b20bedb66837dcf41e21c54f9ec1/pybtex_docutils-1.0.3-py3-none-any.whl", hash = "sha256:8fd290d2ae48e32fcb54d86b0efb8d573198653c7e2447d5bec5847095f430b9", size = 6385, upload-time = "2023-08-22T06:43:20.513Z" }, ] -[[package]] -name = "pycparser" -version = "2.22" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736, upload-time = "2024-03-30T13:22:22.564Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552, upload-time = "2024-03-30T13:22:20.476Z" }, -] - -[[package]] -name = "pydantic" -version = "2.11.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350, upload-time = "2025-06-14T08:33:17.137Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782, upload-time = "2025-06-14T08:33:14.905Z" }, -] - -[[package]] -name = "pydantic-core" -version = "2.33.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" }, - { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" }, - { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" }, - { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" }, - { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" }, - { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" }, - { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" }, - { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" }, - { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" }, - { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" }, - { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" }, - { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" }, - { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" }, - { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" }, - { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" }, - { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" }, - { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" }, - { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" }, - { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" }, - { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" }, - { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" }, - { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" }, - { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" }, - { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" }, - { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" }, - { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" }, - { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" }, - { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" }, - { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" }, - { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" }, - { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" }, -] - -[[package]] -name = "pydantic-settings" -version = "2.10.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "python-dotenv" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/68/85/1ea668bbab3c50071ca613c6ab30047fb36ab0da1b92fa8f17bbc38fd36c/pydantic_settings-2.10.1.tar.gz", hash = "sha256:06f0062169818d0f5524420a360d632d5857b83cffd4d42fe29597807a1614ee", size = 172583, upload-time = "2025-06-24T13:26:46.841Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/58/f0/427018098906416f580e3cf1366d3b1abfb408a0652e9f31600c24a1903c/pydantic_settings-2.10.1-py3-none-any.whl", hash = "sha256:a60952460b99cf661dc25c29c0ef171721f98bfcb52ef8d9ea4c943d7c8cc796", size = 45235, upload-time = "2025-06-24T13:26:45.485Z" }, -] - [[package]] name = "pydoe" version = "0.3.8" @@ -2186,15 +853,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] -[[package]] -name = "pyjwt" -version = "2.10.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785, upload-time = "2024-11-28T03:43:29.933Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" }, -] - [[package]] name = "pyomo" version = "6.9.2" @@ -2266,24 +924,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, ] -[[package]] -name = "python-dotenv" -version = "1.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f6/b0/4bc07ccd3572a2f9df7e6782f52b0c6c90dcbb803ac4a167702d7d0dfe1e/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab", size = 41978, upload-time = "2025-06-24T04:21:07.341Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" }, -] - -[[package]] -name = "python-json-logger" -version = "3.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9e/de/d3144a0bceede957f961e975f3752760fbe390d57fbe194baf709d8f1f7b/python_json_logger-3.3.0.tar.gz", hash = "sha256:12b7e74b17775e7d565129296105bbe3910842d9d0eb083fc83a6a617aa8df84", size = 16642, upload-time = "2025-03-07T07:08:27.301Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/08/20/0f2523b9e50a8052bc6a8b732dfc8568abbdc42010aef03a2d750bdab3b2/python_json_logger-3.3.0-py3-none-any.whl", hash = "sha256:dd980fae8cffb24c13caf6e158d3d61c0d6d22342f932cb6e9deedab3d35eec7", size = 15163, upload-time = "2025-03-07T07:08:25.627Z" }, -] - [[package]] name = "pytz" version = "2025.2" @@ -2306,33 +946,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e1/e7/c3e5994b4e5c90280b5c14ffef409875ec5436d1d0d9f8585794993a7d77/PyUtilib-6.0.0-py2.py3-none-any.whl", hash = "sha256:f1f82d05ad8c42baeef915c8d3d97c0a3cbed6c506c857ab0ab7694dea50ebd8", size = 254187, upload-time = "2020-06-19T14:30:50.656Z" }, ] -[[package]] -name = "pywin32" -version = "311" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/ab/01ea1943d4eba0f850c3c61e78e8dd59757ff815ff3ccd0a84de5f541f42/pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31", size = 8706543, upload-time = "2025-07-14T20:13:20.765Z" }, - { url = "https://files.pythonhosted.org/packages/d1/a8/a0e8d07d4d051ec7502cd58b291ec98dcc0c3fff027caad0470b72cfcc2f/pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067", size = 9495040, upload-time = "2025-07-14T20:13:22.543Z" }, - { url = "https://files.pythonhosted.org/packages/ba/3a/2ae996277b4b50f17d61f0603efd8253cb2d79cc7ae159468007b586396d/pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852", size = 8710102, upload-time = "2025-07-14T20:13:24.682Z" }, - { url = "https://files.pythonhosted.org/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700, upload-time = "2025-07-14T20:13:26.471Z" }, - { url = "https://files.pythonhosted.org/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700, upload-time = "2025-07-14T20:13:28.243Z" }, - { url = "https://files.pythonhosted.org/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318, upload-time = "2025-07-14T20:13:30.348Z" }, - { url = "https://files.pythonhosted.org/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload-time = "2025-07-14T20:13:32.449Z" }, - { url = "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload-time = "2025-07-14T20:13:34.312Z" }, - { url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" }, -] - -[[package]] -name = "pywinpty" -version = "2.0.15" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2d/7c/917f9c4681bb8d34bfbe0b79d36bbcd902651aeab48790df3d30ba0202fb/pywinpty-2.0.15.tar.gz", hash = "sha256:312cf39153a8736c617d45ce8b6ad6cd2107de121df91c455b10ce6bba7a39b2", size = 29017, upload-time = "2025-02-03T21:53:23.265Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/e5/9714def18c3a411809771a3fbcec70bffa764b9675afb00048a620fca604/pywinpty-2.0.15-cp312-cp312-win_amd64.whl", hash = "sha256:83a8f20b430bbc5d8957249f875341a60219a4e971580f2ba694fbfb54a45ebc", size = 1405243, upload-time = "2025-02-03T21:56:52.476Z" }, - { url = "https://files.pythonhosted.org/packages/fb/16/2ab7b3b7f55f3c6929e5f629e1a68362981e4e5fed592a2ed1cb4b4914a5/pywinpty-2.0.15-cp313-cp313-win_amd64.whl", hash = "sha256:ab5920877dd632c124b4ed17bc6dd6ef3b9f86cd492b963ffdb1a67b85b0f408", size = 1405020, upload-time = "2025-02-03T21:56:04.753Z" }, - { url = "https://files.pythonhosted.org/packages/7c/16/edef3515dd2030db2795dbfbe392232c7a0f3dc41b98e92b38b42ba497c7/pywinpty-2.0.15-cp313-cp313t-win_amd64.whl", hash = "sha256:a4560ad8c01e537708d2790dbe7da7d986791de805d89dd0d3697ca59e9e4901", size = 1404151, upload-time = "2025-02-03T21:55:53.628Z" }, -] - [[package]] name = "pyyaml" version = "6.0.2" @@ -2359,50 +972,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, ] -[[package]] -name = "pyzmq" -version = "27.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi", marker = "implementation_name == 'pypy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f1/06/50a4e9648b3e8b992bef8eb632e457307553a89d294103213cfd47b3da69/pyzmq-27.0.0.tar.gz", hash = "sha256:b1f08eeb9ce1510e6939b6e5dcd46a17765e2333daae78ecf4606808442e52cf", size = 280478, upload-time = "2025-06-13T14:09:07.087Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/93/a7/9ad68f55b8834ede477842214feba6a4c786d936c022a67625497aacf61d/pyzmq-27.0.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:cbabc59dcfaac66655c040dfcb8118f133fb5dde185e5fc152628354c1598e52", size = 1305438, upload-time = "2025-06-13T14:07:31.676Z" }, - { url = "https://files.pythonhosted.org/packages/ba/ee/26aa0f98665a22bc90ebe12dced1de5f3eaca05363b717f6fb229b3421b3/pyzmq-27.0.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:cb0ac5179cba4b2f94f1aa208fbb77b62c4c9bf24dd446278b8b602cf85fcda3", size = 895095, upload-time = "2025-06-13T14:07:33.104Z" }, - { url = "https://files.pythonhosted.org/packages/cf/85/c57e7ab216ecd8aa4cc7e3b83b06cc4e9cf45c87b0afc095f10cd5ce87c1/pyzmq-27.0.0-cp312-abi3-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53a48f0228eab6cbf69fde3aa3c03cbe04e50e623ef92ae395fce47ef8a76152", size = 651826, upload-time = "2025-06-13T14:07:34.831Z" }, - { url = "https://files.pythonhosted.org/packages/69/9a/9ea7e230feda9400fb0ae0d61d7d6ddda635e718d941c44eeab22a179d34/pyzmq-27.0.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:111db5f395e09f7e775f759d598f43cb815fc58e0147623c4816486e1a39dc22", size = 839750, upload-time = "2025-06-13T14:07:36.553Z" }, - { url = "https://files.pythonhosted.org/packages/08/66/4cebfbe71f3dfbd417011daca267539f62ed0fbc68105357b68bbb1a25b7/pyzmq-27.0.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c8878011653dcdc27cc2c57e04ff96f0471e797f5c19ac3d7813a245bcb24371", size = 1641357, upload-time = "2025-06-13T14:07:38.21Z" }, - { url = "https://files.pythonhosted.org/packages/ac/f6/b0f62578c08d2471c791287149cb8c2aaea414ae98c6e995c7dbe008adfb/pyzmq-27.0.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:c0ed2c1f335ba55b5fdc964622254917d6b782311c50e138863eda409fbb3b6d", size = 2020281, upload-time = "2025-06-13T14:07:39.599Z" }, - { url = "https://files.pythonhosted.org/packages/37/b9/4f670b15c7498495da9159edc374ec09c88a86d9cd5a47d892f69df23450/pyzmq-27.0.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e918d70862d4cfd4b1c187310015646a14e1f5917922ab45b29f28f345eeb6be", size = 1877110, upload-time = "2025-06-13T14:07:41.027Z" }, - { url = "https://files.pythonhosted.org/packages/66/31/9dee25c226295b740609f0d46db2fe972b23b6f5cf786360980524a3ba92/pyzmq-27.0.0-cp312-abi3-win32.whl", hash = "sha256:88b4e43cab04c3c0f0d55df3b1eef62df2b629a1a369b5289a58f6fa8b07c4f4", size = 559297, upload-time = "2025-06-13T14:07:42.533Z" }, - { url = "https://files.pythonhosted.org/packages/9b/12/52da5509800f7ff2d287b2f2b4e636e7ea0f001181cba6964ff6c1537778/pyzmq-27.0.0-cp312-abi3-win_amd64.whl", hash = "sha256:dce4199bf5f648a902ce37e7b3afa286f305cd2ef7a8b6ec907470ccb6c8b371", size = 619203, upload-time = "2025-06-13T14:07:43.843Z" }, - { url = "https://files.pythonhosted.org/packages/93/6d/7f2e53b19d1edb1eb4f09ec7c3a1f945ca0aac272099eab757d15699202b/pyzmq-27.0.0-cp312-abi3-win_arm64.whl", hash = "sha256:56e46bbb85d52c1072b3f809cc1ce77251d560bc036d3a312b96db1afe76db2e", size = 551927, upload-time = "2025-06-13T14:07:45.51Z" }, - { url = "https://files.pythonhosted.org/packages/19/62/876b27c4ff777db4ceba1c69ea90d3c825bb4f8d5e7cd987ce5802e33c55/pyzmq-27.0.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:c36ad534c0c29b4afa088dc53543c525b23c0797e01b69fef59b1a9c0e38b688", size = 1340826, upload-time = "2025-06-13T14:07:46.881Z" }, - { url = "https://files.pythonhosted.org/packages/43/69/58ef8f4f59d3bcd505260c73bee87b008850f45edca40ddaba54273c35f4/pyzmq-27.0.0-cp313-cp313t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:67855c14173aec36395d7777aaba3cc527b393821f30143fd20b98e1ff31fd38", size = 897283, upload-time = "2025-06-13T14:07:49.562Z" }, - { url = "https://files.pythonhosted.org/packages/43/15/93a0d0396700a60475ad3c5d42c5f1c308d3570bc94626b86c71ef9953e0/pyzmq-27.0.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8617c7d43cd8ccdb62aebe984bfed77ca8f036e6c3e46dd3dddda64b10f0ab7a", size = 660567, upload-time = "2025-06-13T14:07:51.364Z" }, - { url = "https://files.pythonhosted.org/packages/0e/b3/fe055513e498ca32f64509abae19b9c9eb4d7c829e02bd8997dd51b029eb/pyzmq-27.0.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:67bfbcbd0a04c575e8103a6061d03e393d9f80ffdb9beb3189261e9e9bc5d5e9", size = 847681, upload-time = "2025-06-13T14:07:52.77Z" }, - { url = "https://files.pythonhosted.org/packages/b6/4f/ff15300b00b5b602191f3df06bbc8dd4164e805fdd65bb77ffbb9c5facdc/pyzmq-27.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5cd11d46d7b7e5958121b3eaf4cd8638eff3a720ec527692132f05a57f14341d", size = 1650148, upload-time = "2025-06-13T14:07:54.178Z" }, - { url = "https://files.pythonhosted.org/packages/c4/6f/84bdfff2a224a6f26a24249a342e5906993c50b0761e311e81b39aef52a7/pyzmq-27.0.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:b801c2e40c5aa6072c2f4876de8dccd100af6d9918d4d0d7aa54a1d982fd4f44", size = 2023768, upload-time = "2025-06-13T14:07:55.714Z" }, - { url = "https://files.pythonhosted.org/packages/64/39/dc2db178c26a42228c5ac94a9cc595030458aa64c8d796a7727947afbf55/pyzmq-27.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:20d5cb29e8c5f76a127c75b6e7a77e846bc4b655c373baa098c26a61b7ecd0ef", size = 1885199, upload-time = "2025-06-13T14:07:57.166Z" }, - { url = "https://files.pythonhosted.org/packages/c7/21/dae7b06a1f8cdee5d8e7a63d99c5d129c401acc40410bef2cbf42025e26f/pyzmq-27.0.0-cp313-cp313t-win32.whl", hash = "sha256:a20528da85c7ac7a19b7384e8c3f8fa707841fd85afc4ed56eda59d93e3d98ad", size = 575439, upload-time = "2025-06-13T14:07:58.959Z" }, - { url = "https://files.pythonhosted.org/packages/eb/bc/1709dc55f0970cf4cb8259e435e6773f9946f41a045c2cb90e870b7072da/pyzmq-27.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:d8229f2efece6a660ee211d74d91dbc2a76b95544d46c74c615e491900dc107f", size = 639933, upload-time = "2025-06-13T14:08:00.777Z" }, -] - -[[package]] -name = "referencing" -version = "0.36.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "attrs" }, - { name = "rpds-py" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2f/db/98b5c277be99dd18bfd91dd04e1b759cad18d1a338188c936e92f921c7e2/referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", size = 74744, upload-time = "2025-01-25T08:48:16.138Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0", size = 26775, upload-time = "2025-01-25T08:48:14.241Z" }, -] - [[package]] name = "requests" version = "2.32.4" @@ -2418,40 +987,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, ] -[[package]] -name = "rfc3339-validator" -version = "0.1.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513, upload-time = "2021-05-12T16:37:54.178Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490, upload-time = "2021-05-12T16:37:52.536Z" }, -] - -[[package]] -name = "rfc3986-validator" -version = "0.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/da/88/f270de456dd7d11dcc808abfa291ecdd3f45ff44e3b549ffa01b126464d0/rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055", size = 6760, upload-time = "2019-10-28T16:00:19.144Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", size = 4242, upload-time = "2019-10-28T16:00:13.976Z" }, -] - -[[package]] -name = "rich" -version = "14.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078, upload-time = "2025-03-30T14:15:14.23Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229, upload-time = "2025-03-30T14:15:12.283Z" }, -] - [[package]] name = "roman-numerals-py" version = "3.1.0" @@ -2461,82 +996,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/53/97/d2cbbaa10c9b826af0e10fdf836e1bf344d9f0abb873ebc34d1f49642d3f/roman_numerals_py-3.1.0-py3-none-any.whl", hash = "sha256:9da2ad2fb670bcf24e81070ceb3be72f6c11c440d73bd579fbeca1e9f330954c", size = 7742, upload-time = "2025-02-22T07:34:52.422Z" }, ] -[[package]] -name = "rpds-py" -version = "0.26.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/aa/4456d84bbb54adc6a916fb10c9b374f78ac840337644e4a5eda229c81275/rpds_py-0.26.0.tar.gz", hash = "sha256:20dae58a859b0906f0685642e591056f1e787f3a8b39c8e8749a45dc7d26bdb0", size = 27385, upload-time = "2025-07-01T15:57:13.958Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/86/90eb87c6f87085868bd077c7a9938006eb1ce19ed4d06944a90d3560fce2/rpds_py-0.26.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:894514d47e012e794f1350f076c427d2347ebf82f9b958d554d12819849a369d", size = 363933, upload-time = "2025-07-01T15:54:15.734Z" }, - { url = "https://files.pythonhosted.org/packages/63/78/4469f24d34636242c924626082b9586f064ada0b5dbb1e9d096ee7a8e0c6/rpds_py-0.26.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc921b96fa95a097add244da36a1d9e4f3039160d1d30f1b35837bf108c21136", size = 350447, upload-time = "2025-07-01T15:54:16.922Z" }, - { url = "https://files.pythonhosted.org/packages/ad/91/c448ed45efdfdade82348d5e7995e15612754826ea640afc20915119734f/rpds_py-0.26.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e1157659470aa42a75448b6e943c895be8c70531c43cb78b9ba990778955582", size = 384711, upload-time = "2025-07-01T15:54:18.101Z" }, - { url = "https://files.pythonhosted.org/packages/ec/43/e5c86fef4be7f49828bdd4ecc8931f0287b1152c0bb0163049b3218740e7/rpds_py-0.26.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:521ccf56f45bb3a791182dc6b88ae5f8fa079dd705ee42138c76deb1238e554e", size = 400865, upload-time = "2025-07-01T15:54:19.295Z" }, - { url = "https://files.pythonhosted.org/packages/55/34/e00f726a4d44f22d5c5fe2e5ddd3ac3d7fd3f74a175607781fbdd06fe375/rpds_py-0.26.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9def736773fd56b305c0eef698be5192c77bfa30d55a0e5885f80126c4831a15", size = 517763, upload-time = "2025-07-01T15:54:20.858Z" }, - { url = "https://files.pythonhosted.org/packages/52/1c/52dc20c31b147af724b16104500fba13e60123ea0334beba7b40e33354b4/rpds_py-0.26.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cdad4ea3b4513b475e027be79e5a0ceac8ee1c113a1a11e5edc3c30c29f964d8", size = 406651, upload-time = "2025-07-01T15:54:22.508Z" }, - { url = "https://files.pythonhosted.org/packages/2e/77/87d7bfabfc4e821caa35481a2ff6ae0b73e6a391bb6b343db2c91c2b9844/rpds_py-0.26.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82b165b07f416bdccf5c84546a484cc8f15137ca38325403864bfdf2b5b72f6a", size = 386079, upload-time = "2025-07-01T15:54:23.987Z" }, - { url = "https://files.pythonhosted.org/packages/e3/d4/7f2200c2d3ee145b65b3cddc4310d51f7da6a26634f3ac87125fd789152a/rpds_py-0.26.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d04cab0a54b9dba4d278fe955a1390da3cf71f57feb78ddc7cb67cbe0bd30323", size = 421379, upload-time = "2025-07-01T15:54:25.073Z" }, - { url = "https://files.pythonhosted.org/packages/ae/13/9fdd428b9c820869924ab62236b8688b122baa22d23efdd1c566938a39ba/rpds_py-0.26.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:79061ba1a11b6a12743a2b0f72a46aa2758613d454aa6ba4f5a265cc48850158", size = 562033, upload-time = "2025-07-01T15:54:26.225Z" }, - { url = "https://files.pythonhosted.org/packages/f3/e1/b69686c3bcbe775abac3a4c1c30a164a2076d28df7926041f6c0eb5e8d28/rpds_py-0.26.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f405c93675d8d4c5ac87364bb38d06c988e11028a64b52a47158a355079661f3", size = 591639, upload-time = "2025-07-01T15:54:27.424Z" }, - { url = "https://files.pythonhosted.org/packages/5c/c9/1e3d8c8863c84a90197ac577bbc3d796a92502124c27092413426f670990/rpds_py-0.26.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dafd4c44b74aa4bed4b250f1aed165b8ef5de743bcca3b88fc9619b6087093d2", size = 557105, upload-time = "2025-07-01T15:54:29.93Z" }, - { url = "https://files.pythonhosted.org/packages/9f/c5/90c569649057622959f6dcc40f7b516539608a414dfd54b8d77e3b201ac0/rpds_py-0.26.0-cp312-cp312-win32.whl", hash = "sha256:3da5852aad63fa0c6f836f3359647870e21ea96cf433eb393ffa45263a170d44", size = 223272, upload-time = "2025-07-01T15:54:31.128Z" }, - { url = "https://files.pythonhosted.org/packages/7d/16/19f5d9f2a556cfed454eebe4d354c38d51c20f3db69e7b4ce6cff904905d/rpds_py-0.26.0-cp312-cp312-win_amd64.whl", hash = "sha256:cf47cfdabc2194a669dcf7a8dbba62e37a04c5041d2125fae0233b720da6f05c", size = 234995, upload-time = "2025-07-01T15:54:32.195Z" }, - { url = "https://files.pythonhosted.org/packages/83/f0/7935e40b529c0e752dfaa7880224771b51175fce08b41ab4a92eb2fbdc7f/rpds_py-0.26.0-cp312-cp312-win_arm64.whl", hash = "sha256:20ab1ae4fa534f73647aad289003f1104092890849e0266271351922ed5574f8", size = 223198, upload-time = "2025-07-01T15:54:33.271Z" }, - { url = "https://files.pythonhosted.org/packages/6a/67/bb62d0109493b12b1c6ab00de7a5566aa84c0e44217c2d94bee1bd370da9/rpds_py-0.26.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:696764a5be111b036256c0b18cd29783fab22154690fc698062fc1b0084b511d", size = 363917, upload-time = "2025-07-01T15:54:34.755Z" }, - { url = "https://files.pythonhosted.org/packages/4b/f3/34e6ae1925a5706c0f002a8d2d7f172373b855768149796af87bd65dcdb9/rpds_py-0.26.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1e6c15d2080a63aaed876e228efe4f814bc7889c63b1e112ad46fdc8b368b9e1", size = 350073, upload-time = "2025-07-01T15:54:36.292Z" }, - { url = "https://files.pythonhosted.org/packages/75/83/1953a9d4f4e4de7fd0533733e041c28135f3c21485faaef56a8aadbd96b5/rpds_py-0.26.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:390e3170babf42462739a93321e657444f0862c6d722a291accc46f9d21ed04e", size = 384214, upload-time = "2025-07-01T15:54:37.469Z" }, - { url = "https://files.pythonhosted.org/packages/48/0e/983ed1b792b3322ea1d065e67f4b230f3b96025f5ce3878cc40af09b7533/rpds_py-0.26.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7da84c2c74c0f5bc97d853d9e17bb83e2dcafcff0dc48286916001cc114379a1", size = 400113, upload-time = "2025-07-01T15:54:38.954Z" }, - { url = "https://files.pythonhosted.org/packages/69/7f/36c0925fff6f660a80be259c5b4f5e53a16851f946eb080351d057698528/rpds_py-0.26.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c5fe114a6dd480a510b6d3661d09d67d1622c4bf20660a474507aaee7eeeee9", size = 515189, upload-time = "2025-07-01T15:54:40.57Z" }, - { url = "https://files.pythonhosted.org/packages/13/45/cbf07fc03ba7a9b54662c9badb58294ecfb24f828b9732970bd1a431ed5c/rpds_py-0.26.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3100b3090269f3a7ea727b06a6080d4eb7439dca4c0e91a07c5d133bb1727ea7", size = 406998, upload-time = "2025-07-01T15:54:43.025Z" }, - { url = "https://files.pythonhosted.org/packages/6c/b0/8fa5e36e58657997873fd6a1cf621285ca822ca75b4b3434ead047daa307/rpds_py-0.26.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c03c9b0c64afd0320ae57de4c982801271c0c211aa2d37f3003ff5feb75bb04", size = 385903, upload-time = "2025-07-01T15:54:44.752Z" }, - { url = "https://files.pythonhosted.org/packages/4b/f7/b25437772f9f57d7a9fbd73ed86d0dcd76b4c7c6998348c070d90f23e315/rpds_py-0.26.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5963b72ccd199ade6ee493723d18a3f21ba7d5b957017607f815788cef50eaf1", size = 419785, upload-time = "2025-07-01T15:54:46.043Z" }, - { url = "https://files.pythonhosted.org/packages/a7/6b/63ffa55743dfcb4baf2e9e77a0b11f7f97ed96a54558fcb5717a4b2cd732/rpds_py-0.26.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9da4e873860ad5bab3291438525cae80169daecbfafe5657f7f5fb4d6b3f96b9", size = 561329, upload-time = "2025-07-01T15:54:47.64Z" }, - { url = "https://files.pythonhosted.org/packages/2f/07/1f4f5e2886c480a2346b1e6759c00278b8a69e697ae952d82ae2e6ee5db0/rpds_py-0.26.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5afaddaa8e8c7f1f7b4c5c725c0070b6eed0228f705b90a1732a48e84350f4e9", size = 590875, upload-time = "2025-07-01T15:54:48.9Z" }, - { url = "https://files.pythonhosted.org/packages/cc/bc/e6639f1b91c3a55f8c41b47d73e6307051b6e246254a827ede730624c0f8/rpds_py-0.26.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4916dc96489616a6f9667e7526af8fa693c0fdb4f3acb0e5d9f4400eb06a47ba", size = 556636, upload-time = "2025-07-01T15:54:50.619Z" }, - { url = "https://files.pythonhosted.org/packages/05/4c/b3917c45566f9f9a209d38d9b54a1833f2bb1032a3e04c66f75726f28876/rpds_py-0.26.0-cp313-cp313-win32.whl", hash = "sha256:2a343f91b17097c546b93f7999976fd6c9d5900617aa848c81d794e062ab302b", size = 222663, upload-time = "2025-07-01T15:54:52.023Z" }, - { url = "https://files.pythonhosted.org/packages/e0/0b/0851bdd6025775aaa2365bb8de0697ee2558184c800bfef8d7aef5ccde58/rpds_py-0.26.0-cp313-cp313-win_amd64.whl", hash = "sha256:0a0b60701f2300c81b2ac88a5fb893ccfa408e1c4a555a77f908a2596eb875a5", size = 234428, upload-time = "2025-07-01T15:54:53.692Z" }, - { url = "https://files.pythonhosted.org/packages/ed/e8/a47c64ed53149c75fb581e14a237b7b7cd18217e969c30d474d335105622/rpds_py-0.26.0-cp313-cp313-win_arm64.whl", hash = "sha256:257d011919f133a4746958257f2c75238e3ff54255acd5e3e11f3ff41fd14256", size = 222571, upload-time = "2025-07-01T15:54:54.822Z" }, - { url = "https://files.pythonhosted.org/packages/89/bf/3d970ba2e2bcd17d2912cb42874107390f72873e38e79267224110de5e61/rpds_py-0.26.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:529c8156d7506fba5740e05da8795688f87119cce330c244519cf706a4a3d618", size = 360475, upload-time = "2025-07-01T15:54:56.228Z" }, - { url = "https://files.pythonhosted.org/packages/82/9f/283e7e2979fc4ec2d8ecee506d5a3675fce5ed9b4b7cb387ea5d37c2f18d/rpds_py-0.26.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f53ec51f9d24e9638a40cabb95078ade8c99251945dad8d57bf4aabe86ecee35", size = 346692, upload-time = "2025-07-01T15:54:58.561Z" }, - { url = "https://files.pythonhosted.org/packages/e3/03/7e50423c04d78daf391da3cc4330bdb97042fc192a58b186f2d5deb7befd/rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab504c4d654e4a29558eaa5bb8cea5fdc1703ea60a8099ffd9c758472cf913f", size = 379415, upload-time = "2025-07-01T15:54:59.751Z" }, - { url = "https://files.pythonhosted.org/packages/57/00/d11ee60d4d3b16808432417951c63df803afb0e0fc672b5e8d07e9edaaae/rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd0641abca296bc1a00183fe44f7fced8807ed49d501f188faa642d0e4975b83", size = 391783, upload-time = "2025-07-01T15:55:00.898Z" }, - { url = "https://files.pythonhosted.org/packages/08/b3/1069c394d9c0d6d23c5b522e1f6546b65793a22950f6e0210adcc6f97c3e/rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69b312fecc1d017b5327afa81d4da1480f51c68810963a7336d92203dbb3d4f1", size = 512844, upload-time = "2025-07-01T15:55:02.201Z" }, - { url = "https://files.pythonhosted.org/packages/08/3b/c4fbf0926800ed70b2c245ceca99c49f066456755f5d6eb8863c2c51e6d0/rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c741107203954f6fc34d3066d213d0a0c40f7bb5aafd698fb39888af277c70d8", size = 402105, upload-time = "2025-07-01T15:55:03.698Z" }, - { url = "https://files.pythonhosted.org/packages/1c/b0/db69b52ca07413e568dae9dc674627a22297abb144c4d6022c6d78f1e5cc/rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc3e55a7db08dc9a6ed5fb7103019d2c1a38a349ac41901f9f66d7f95750942f", size = 383440, upload-time = "2025-07-01T15:55:05.398Z" }, - { url = "https://files.pythonhosted.org/packages/4c/e1/c65255ad5b63903e56b3bb3ff9dcc3f4f5c3badde5d08c741ee03903e951/rpds_py-0.26.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9e851920caab2dbcae311fd28f4313c6953993893eb5c1bb367ec69d9a39e7ed", size = 412759, upload-time = "2025-07-01T15:55:08.316Z" }, - { url = "https://files.pythonhosted.org/packages/e4/22/bb731077872377a93c6e93b8a9487d0406c70208985831034ccdeed39c8e/rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:dfbf280da5f876d0b00c81f26bedce274e72a678c28845453885a9b3c22ae632", size = 556032, upload-time = "2025-07-01T15:55:09.52Z" }, - { url = "https://files.pythonhosted.org/packages/e0/8b/393322ce7bac5c4530fb96fc79cc9ea2f83e968ff5f6e873f905c493e1c4/rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1cc81d14ddfa53d7f3906694d35d54d9d3f850ef8e4e99ee68bc0d1e5fed9a9c", size = 585416, upload-time = "2025-07-01T15:55:11.216Z" }, - { url = "https://files.pythonhosted.org/packages/49/ae/769dc372211835bf759319a7aae70525c6eb523e3371842c65b7ef41c9c6/rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dca83c498b4650a91efcf7b88d669b170256bf8017a5db6f3e06c2bf031f57e0", size = 554049, upload-time = "2025-07-01T15:55:13.004Z" }, - { url = "https://files.pythonhosted.org/packages/6b/f9/4c43f9cc203d6ba44ce3146246cdc38619d92c7bd7bad4946a3491bd5b70/rpds_py-0.26.0-cp313-cp313t-win32.whl", hash = "sha256:4d11382bcaf12f80b51d790dee295c56a159633a8e81e6323b16e55d81ae37e9", size = 218428, upload-time = "2025-07-01T15:55:14.486Z" }, - { url = "https://files.pythonhosted.org/packages/7e/8b/9286b7e822036a4a977f2f1e851c7345c20528dbd56b687bb67ed68a8ede/rpds_py-0.26.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff110acded3c22c033e637dd8896e411c7d3a11289b2edf041f86663dbc791e9", size = 231524, upload-time = "2025-07-01T15:55:15.745Z" }, - { url = "https://files.pythonhosted.org/packages/55/07/029b7c45db910c74e182de626dfdae0ad489a949d84a468465cd0ca36355/rpds_py-0.26.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:da619979df60a940cd434084355c514c25cf8eb4cf9a508510682f6c851a4f7a", size = 364292, upload-time = "2025-07-01T15:55:17.001Z" }, - { url = "https://files.pythonhosted.org/packages/13/d1/9b3d3f986216b4d1f584878dca15ce4797aaf5d372d738974ba737bf68d6/rpds_py-0.26.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ea89a2458a1a75f87caabefe789c87539ea4e43b40f18cff526052e35bbb4fdf", size = 350334, upload-time = "2025-07-01T15:55:18.922Z" }, - { url = "https://files.pythonhosted.org/packages/18/98/16d5e7bc9ec715fa9668731d0cf97f6b032724e61696e2db3d47aeb89214/rpds_py-0.26.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feac1045b3327a45944e7dcbeb57530339f6b17baff154df51ef8b0da34c8c12", size = 384875, upload-time = "2025-07-01T15:55:20.399Z" }, - { url = "https://files.pythonhosted.org/packages/f9/13/aa5e2b1ec5ab0e86a5c464d53514c0467bec6ba2507027d35fc81818358e/rpds_py-0.26.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b818a592bd69bfe437ee8368603d4a2d928c34cffcdf77c2e761a759ffd17d20", size = 399993, upload-time = "2025-07-01T15:55:21.729Z" }, - { url = "https://files.pythonhosted.org/packages/17/03/8021810b0e97923abdbab6474c8b77c69bcb4b2c58330777df9ff69dc559/rpds_py-0.26.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a8b0dd8648709b62d9372fc00a57466f5fdeefed666afe3fea5a6c9539a0331", size = 516683, upload-time = "2025-07-01T15:55:22.918Z" }, - { url = "https://files.pythonhosted.org/packages/dc/b1/da8e61c87c2f3d836954239fdbbfb477bb7b54d74974d8f6fcb34342d166/rpds_py-0.26.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6d3498ad0df07d81112aa6ec6c95a7e7b1ae00929fb73e7ebee0f3faaeabad2f", size = 408825, upload-time = "2025-07-01T15:55:24.207Z" }, - { url = "https://files.pythonhosted.org/packages/38/bc/1fc173edaaa0e52c94b02a655db20697cb5fa954ad5a8e15a2c784c5cbdd/rpds_py-0.26.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24a4146ccb15be237fdef10f331c568e1b0e505f8c8c9ed5d67759dac58ac246", size = 387292, upload-time = "2025-07-01T15:55:25.554Z" }, - { url = "https://files.pythonhosted.org/packages/7c/eb/3a9bb4bd90867d21916f253caf4f0d0be7098671b6715ad1cead9fe7bab9/rpds_py-0.26.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a9a63785467b2d73635957d32a4f6e73d5e4df497a16a6392fa066b753e87387", size = 420435, upload-time = "2025-07-01T15:55:27.798Z" }, - { url = "https://files.pythonhosted.org/packages/cd/16/e066dcdb56f5632713445271a3f8d3d0b426d51ae9c0cca387799df58b02/rpds_py-0.26.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:de4ed93a8c91debfd5a047be327b7cc8b0cc6afe32a716bbbc4aedca9e2a83af", size = 562410, upload-time = "2025-07-01T15:55:29.057Z" }, - { url = "https://files.pythonhosted.org/packages/60/22/ddbdec7eb82a0dc2e455be44c97c71c232983e21349836ce9f272e8a3c29/rpds_py-0.26.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:caf51943715b12af827696ec395bfa68f090a4c1a1d2509eb4e2cb69abbbdb33", size = 590724, upload-time = "2025-07-01T15:55:30.719Z" }, - { url = "https://files.pythonhosted.org/packages/2c/b4/95744085e65b7187d83f2fcb0bef70716a1ea0a9e5d8f7f39a86e5d83424/rpds_py-0.26.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4a59e5bc386de021f56337f757301b337d7ab58baa40174fb150accd480bc953", size = 558285, upload-time = "2025-07-01T15:55:31.981Z" }, - { url = "https://files.pythonhosted.org/packages/37/37/6309a75e464d1da2559446f9c811aa4d16343cebe3dbb73701e63f760caa/rpds_py-0.26.0-cp314-cp314-win32.whl", hash = "sha256:92c8db839367ef16a662478f0a2fe13e15f2227da3c1430a782ad0f6ee009ec9", size = 223459, upload-time = "2025-07-01T15:55:33.312Z" }, - { url = "https://files.pythonhosted.org/packages/d9/6f/8e9c11214c46098b1d1391b7e02b70bb689ab963db3b19540cba17315291/rpds_py-0.26.0-cp314-cp314-win_amd64.whl", hash = "sha256:b0afb8cdd034150d4d9f53926226ed27ad15b7f465e93d7468caaf5eafae0d37", size = 236083, upload-time = "2025-07-01T15:55:34.933Z" }, - { url = "https://files.pythonhosted.org/packages/47/af/9c4638994dd623d51c39892edd9d08e8be8220a4b7e874fa02c2d6e91955/rpds_py-0.26.0-cp314-cp314-win_arm64.whl", hash = "sha256:ca3f059f4ba485d90c8dc75cb5ca897e15325e4e609812ce57f896607c1c0867", size = 223291, upload-time = "2025-07-01T15:55:36.202Z" }, - { url = "https://files.pythonhosted.org/packages/4d/db/669a241144460474aab03e254326b32c42def83eb23458a10d163cb9b5ce/rpds_py-0.26.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:5afea17ab3a126006dc2f293b14ffc7ef3c85336cf451564a0515ed7648033da", size = 361445, upload-time = "2025-07-01T15:55:37.483Z" }, - { url = "https://files.pythonhosted.org/packages/3b/2d/133f61cc5807c6c2fd086a46df0eb8f63a23f5df8306ff9f6d0fd168fecc/rpds_py-0.26.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:69f0c0a3df7fd3a7eec50a00396104bb9a843ea6d45fcc31c2d5243446ffd7a7", size = 347206, upload-time = "2025-07-01T15:55:38.828Z" }, - { url = "https://files.pythonhosted.org/packages/05/bf/0e8fb4c05f70273469eecf82f6ccf37248558526a45321644826555db31b/rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:801a71f70f9813e82d2513c9a96532551fce1e278ec0c64610992c49c04c2dad", size = 380330, upload-time = "2025-07-01T15:55:40.175Z" }, - { url = "https://files.pythonhosted.org/packages/d4/a8/060d24185d8b24d3923322f8d0ede16df4ade226a74e747b8c7c978e3dd3/rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:df52098cde6d5e02fa75c1f6244f07971773adb4a26625edd5c18fee906fa84d", size = 392254, upload-time = "2025-07-01T15:55:42.015Z" }, - { url = "https://files.pythonhosted.org/packages/b9/7b/7c2e8a9ee3e6bc0bae26bf29f5219955ca2fbb761dca996a83f5d2f773fe/rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bc596b30f86dc6f0929499c9e574601679d0341a0108c25b9b358a042f51bca", size = 516094, upload-time = "2025-07-01T15:55:43.603Z" }, - { url = "https://files.pythonhosted.org/packages/75/d6/f61cafbed8ba1499b9af9f1777a2a199cd888f74a96133d8833ce5eaa9c5/rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9dfbe56b299cf5875b68eb6f0ebaadc9cac520a1989cac0db0765abfb3709c19", size = 402889, upload-time = "2025-07-01T15:55:45.275Z" }, - { url = "https://files.pythonhosted.org/packages/92/19/c8ac0a8a8df2dd30cdec27f69298a5c13e9029500d6d76718130f5e5be10/rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac64f4b2bdb4ea622175c9ab7cf09444e412e22c0e02e906978b3b488af5fde8", size = 384301, upload-time = "2025-07-01T15:55:47.098Z" }, - { url = "https://files.pythonhosted.org/packages/41/e1/6b1859898bc292a9ce5776016c7312b672da00e25cec74d7beced1027286/rpds_py-0.26.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:181ef9b6bbf9845a264f9aa45c31836e9f3c1f13be565d0d010e964c661d1e2b", size = 412891, upload-time = "2025-07-01T15:55:48.412Z" }, - { url = "https://files.pythonhosted.org/packages/ef/b9/ceb39af29913c07966a61367b3c08b4f71fad841e32c6b59a129d5974698/rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:49028aa684c144ea502a8e847d23aed5e4c2ef7cadfa7d5eaafcb40864844b7a", size = 557044, upload-time = "2025-07-01T15:55:49.816Z" }, - { url = "https://files.pythonhosted.org/packages/2f/27/35637b98380731a521f8ec4f3fd94e477964f04f6b2f8f7af8a2d889a4af/rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e5d524d68a474a9688336045bbf76cb0def88549c1b2ad9dbfec1fb7cfbe9170", size = 585774, upload-time = "2025-07-01T15:55:51.192Z" }, - { url = "https://files.pythonhosted.org/packages/52/d9/3f0f105420fecd18551b678c9a6ce60bd23986098b252a56d35781b3e7e9/rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c1851f429b822831bd2edcbe0cfd12ee9ea77868f8d3daf267b189371671c80e", size = 554886, upload-time = "2025-07-01T15:55:52.541Z" }, - { url = "https://files.pythonhosted.org/packages/6b/c5/347c056a90dc8dd9bc240a08c527315008e1b5042e7a4cf4ac027be9d38a/rpds_py-0.26.0-cp314-cp314t-win32.whl", hash = "sha256:7bdb17009696214c3b66bb3590c6d62e14ac5935e53e929bcdbc5a495987a84f", size = 219027, upload-time = "2025-07-01T15:55:53.874Z" }, - { url = "https://files.pythonhosted.org/packages/75/04/5302cea1aa26d886d34cadbf2dc77d90d7737e576c0065f357b96dc7a1a6/rpds_py-0.26.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f14440b9573a6f76b4ee4770c13f0b5921f71dde3b6fcb8dabbefd13b7fe05d7", size = 232821, upload-time = "2025-07-01T15:55:55.167Z" }, -] - [[package]] name = "ruff" version = "0.12.3" @@ -2630,33 +1089,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987", size = 294914, upload-time = "2024-01-25T13:21:49.598Z" }, ] -[[package]] -name = "send2trash" -version = "1.8.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fd/3a/aec9b02217bb79b87bbc1a21bc6abc51e3d5dcf65c30487ac96c0908c722/Send2Trash-1.8.3.tar.gz", hash = "sha256:b18e7a3966d99871aefeb00cfbcfdced55ce4871194810fc71f4aa484b953abf", size = 17394, upload-time = "2024-04-07T00:01:09.267Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/40/b0/4562db6223154aa4e22f939003cb92514c79f3d4dccca3444253fd17f902/Send2Trash-1.8.3-py3-none-any.whl", hash = "sha256:0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9", size = 18072, upload-time = "2024-04-07T00:01:07.438Z" }, -] - -[[package]] -name = "setuptools" -version = "80.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, -] - -[[package]] -name = "shellingham" -version = "1.5.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, -] - [[package]] name = "six" version = "1.17.0" @@ -2666,15 +1098,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, ] -[[package]] -name = "sniffio" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, -] - [[package]] name = "snowballstemmer" version = "3.0.1" @@ -2684,15 +1107,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c8/78/3565d011c61f5a43488987ee32b6f3f656e7f107ac2782dd57bdd7d91d9a/snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064", size = 103274, upload-time = "2025-05-09T16:34:50.371Z" }, ] -[[package]] -name = "soupsieve" -version = "2.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3f/f4/4a80cd6ef364b2e8b65b15816a843c0980f7a5a2b4dc701fc574952aa19f/soupsieve-2.7.tar.gz", hash = "sha256:ad282f9b6926286d2ead4750552c8a6142bc4c783fd66b0293547c8fe6ae126a", size = 103418, upload-time = "2025-04-20T18:50:08.518Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/9c/0e6afc12c269578be5c0c1c9f4b49a8d32770a080260c333ac04cc1c832d/soupsieve-2.7-py3-none-any.whl", hash = "sha256:6e60cc5c1ffaf1cebcc12e8188320b72071e922c2e897f737cadce79ad5d30c4", size = 36677, upload-time = "2025-04-20T18:50:07.196Z" }, -] - [[package]] name = "sphinx" version = "8.2.3" @@ -2816,92 +1230,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072, upload-time = "2024-07-29T01:10:08.203Z" }, ] -[[package]] -name = "sqlalchemy" -version = "2.0.41" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "greenlet", marker = "(python_full_version < '3.14' and platform_machine == 'AMD64') or (python_full_version < '3.14' and platform_machine == 'WIN32') or (python_full_version < '3.14' and platform_machine == 'aarch64') or (python_full_version < '3.14' and platform_machine == 'amd64') or (python_full_version < '3.14' and platform_machine == 'ppc64le') or (python_full_version < '3.14' and platform_machine == 'win32') or (python_full_version < '3.14' and platform_machine == 'x86_64')" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/63/66/45b165c595ec89aa7dcc2c1cd222ab269bc753f1fc7a1e68f8481bd957bf/sqlalchemy-2.0.41.tar.gz", hash = "sha256:edba70118c4be3c2b1f90754d308d0b79c6fe2c0fdc52d8ddf603916f83f4db9", size = 9689424, upload-time = "2025-05-14T17:10:32.339Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3e/2a/f1f4e068b371154740dd10fb81afb5240d5af4aa0087b88d8b308b5429c2/sqlalchemy-2.0.41-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:81f413674d85cfd0dfcd6512e10e0f33c19c21860342a4890c3a2b59479929f9", size = 2119645, upload-time = "2025-05-14T17:55:24.854Z" }, - { url = "https://files.pythonhosted.org/packages/9b/e8/c664a7e73d36fbfc4730f8cf2bf930444ea87270f2825efbe17bf808b998/sqlalchemy-2.0.41-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:598d9ebc1e796431bbd068e41e4de4dc34312b7aa3292571bb3674a0cb415dd1", size = 2107399, upload-time = "2025-05-14T17:55:28.097Z" }, - { url = "https://files.pythonhosted.org/packages/5c/78/8a9cf6c5e7135540cb682128d091d6afa1b9e48bd049b0d691bf54114f70/sqlalchemy-2.0.41-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a104c5694dfd2d864a6f91b0956eb5d5883234119cb40010115fd45a16da5e70", size = 3293269, upload-time = "2025-05-14T17:50:38.227Z" }, - { url = "https://files.pythonhosted.org/packages/3c/35/f74add3978c20de6323fb11cb5162702670cc7a9420033befb43d8d5b7a4/sqlalchemy-2.0.41-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6145afea51ff0af7f2564a05fa95eb46f542919e6523729663a5d285ecb3cf5e", size = 3303364, upload-time = "2025-05-14T17:51:49.829Z" }, - { url = "https://files.pythonhosted.org/packages/6a/d4/c990f37f52c3f7748ebe98883e2a0f7d038108c2c5a82468d1ff3eec50b7/sqlalchemy-2.0.41-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b46fa6eae1cd1c20e6e6f44e19984d438b6b2d8616d21d783d150df714f44078", size = 3229072, upload-time = "2025-05-14T17:50:39.774Z" }, - { url = "https://files.pythonhosted.org/packages/15/69/cab11fecc7eb64bc561011be2bd03d065b762d87add52a4ca0aca2e12904/sqlalchemy-2.0.41-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41836fe661cc98abfae476e14ba1906220f92c4e528771a8a3ae6a151242d2ae", size = 3268074, upload-time = "2025-05-14T17:51:51.736Z" }, - { url = "https://files.pythonhosted.org/packages/5c/ca/0c19ec16858585d37767b167fc9602593f98998a68a798450558239fb04a/sqlalchemy-2.0.41-cp312-cp312-win32.whl", hash = "sha256:a8808d5cf866c781150d36a3c8eb3adccfa41a8105d031bf27e92c251e3969d6", size = 2084514, upload-time = "2025-05-14T17:55:49.915Z" }, - { url = "https://files.pythonhosted.org/packages/7f/23/4c2833d78ff3010a4e17f984c734f52b531a8c9060a50429c9d4b0211be6/sqlalchemy-2.0.41-cp312-cp312-win_amd64.whl", hash = "sha256:5b14e97886199c1f52c14629c11d90c11fbb09e9334fa7bb5f6d068d9ced0ce0", size = 2111557, upload-time = "2025-05-14T17:55:51.349Z" }, - { url = "https://files.pythonhosted.org/packages/d3/ad/2e1c6d4f235a97eeef52d0200d8ddda16f6c4dd70ae5ad88c46963440480/sqlalchemy-2.0.41-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4eeb195cdedaf17aab6b247894ff2734dcead6c08f748e617bfe05bd5a218443", size = 2115491, upload-time = "2025-05-14T17:55:31.177Z" }, - { url = "https://files.pythonhosted.org/packages/cf/8d/be490e5db8400dacc89056f78a52d44b04fbf75e8439569d5b879623a53b/sqlalchemy-2.0.41-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d4ae769b9c1c7757e4ccce94b0641bc203bbdf43ba7a2413ab2523d8d047d8dc", size = 2102827, upload-time = "2025-05-14T17:55:34.921Z" }, - { url = "https://files.pythonhosted.org/packages/a0/72/c97ad430f0b0e78efaf2791342e13ffeafcbb3c06242f01a3bb8fe44f65d/sqlalchemy-2.0.41-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a62448526dd9ed3e3beedc93df9bb6b55a436ed1474db31a2af13b313a70a7e1", size = 3225224, upload-time = "2025-05-14T17:50:41.418Z" }, - { url = "https://files.pythonhosted.org/packages/5e/51/5ba9ea3246ea068630acf35a6ba0d181e99f1af1afd17e159eac7e8bc2b8/sqlalchemy-2.0.41-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc56c9788617b8964ad02e8fcfeed4001c1f8ba91a9e1f31483c0dffb207002a", size = 3230045, upload-time = "2025-05-14T17:51:54.722Z" }, - { url = "https://files.pythonhosted.org/packages/78/2f/8c14443b2acea700c62f9b4a8bad9e49fc1b65cfb260edead71fd38e9f19/sqlalchemy-2.0.41-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c153265408d18de4cc5ded1941dcd8315894572cddd3c58df5d5b5705b3fa28d", size = 3159357, upload-time = "2025-05-14T17:50:43.483Z" }, - { url = "https://files.pythonhosted.org/packages/fc/b2/43eacbf6ccc5276d76cea18cb7c3d73e294d6fb21f9ff8b4eef9b42bbfd5/sqlalchemy-2.0.41-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f67766965996e63bb46cfbf2ce5355fc32d9dd3b8ad7e536a920ff9ee422e23", size = 3197511, upload-time = "2025-05-14T17:51:57.308Z" }, - { url = "https://files.pythonhosted.org/packages/fa/2e/677c17c5d6a004c3c45334ab1dbe7b7deb834430b282b8a0f75ae220c8eb/sqlalchemy-2.0.41-cp313-cp313-win32.whl", hash = "sha256:bfc9064f6658a3d1cadeaa0ba07570b83ce6801a1314985bf98ec9b95d74e15f", size = 2082420, upload-time = "2025-05-14T17:55:52.69Z" }, - { url = "https://files.pythonhosted.org/packages/e9/61/e8c1b9b6307c57157d328dd8b8348ddc4c47ffdf1279365a13b2b98b8049/sqlalchemy-2.0.41-cp313-cp313-win_amd64.whl", hash = "sha256:82ca366a844eb551daff9d2e6e7a9e5e76d2612c8564f58db6c19a726869c1df", size = 2108329, upload-time = "2025-05-14T17:55:54.495Z" }, - { url = "https://files.pythonhosted.org/packages/1c/fc/9ba22f01b5cdacc8f5ed0d22304718d2c758fce3fd49a5372b886a86f37c/sqlalchemy-2.0.41-py3-none-any.whl", hash = "sha256:57df5dc6fdb5ed1a88a1ed2195fd31927e705cad62dedd86b46972752a80f576", size = 1911224, upload-time = "2025-05-14T17:39:42.154Z" }, -] - -[package.optional-dependencies] -mypy = [ - { name = "mypy" }, -] - -[[package]] -name = "sqlalchemy-continuum" -version = "1.4.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "sqlalchemy" }, - { name = "sqlalchemy-utils" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/05/81/76e0b16ca8575463ba83e014afe8a89443bbc6a896dad3c48068ce571611/sqlalchemy_continuum-1.4.2.tar.gz", hash = "sha256:0fd2be79f718eda47c2206879d92ec4ebf1889364637b3caf3ee5d34bd19c8e3", size = 81713, upload-time = "2024-05-02T20:03:43.192Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/84/d4/c404ce46dc2d53e536f470e76d7f657de46cf091d5ba05d19040d420d825/SQLAlchemy_Continuum-1.4.2-py3-none-any.whl", hash = "sha256:154588d79deb8b1683b5f39c130e6f0ad793c0b2f27e8c210565c23fb6fe74de", size = 44789, upload-time = "2024-05-02T20:03:41.009Z" }, -] - -[[package]] -name = "sqlalchemy-utils" -version = "0.41.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "sqlalchemy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/4d/bf/abfd5474cdd89ddd36dbbde9c6efba16bfa7f5448913eba946fed14729da/SQLAlchemy-Utils-0.41.2.tar.gz", hash = "sha256:bc599c8c3b3319e53ce6c5c3c471120bd325d0071fb6f38a10e924e3d07b9990", size = 138017, upload-time = "2024-03-24T15:17:28.196Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/f0/dc4757b83ac1ab853cf222df8535ed73973e0c203d983982ba7b8bc60508/SQLAlchemy_Utils-0.41.2-py3-none-any.whl", hash = "sha256:85cf3842da2bf060760f955f8467b87983fb2e30f1764fd0e24a48307dc8ec6e", size = 93083, upload-time = "2024-03-24T15:17:24.533Z" }, -] - -[[package]] -name = "stack-data" -version = "0.6.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "asttokens" }, - { name = "executing" }, - { name = "pure-eval" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, -] - -[[package]] -name = "starlette" -version = "0.47.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0a/69/662169fdb92fb96ec3eaee218cf540a629d629c86d7993d9651226a6789b/starlette-0.47.1.tar.gz", hash = "sha256:aef012dd2b6be325ffa16698f9dc533614fb1cebd593a906b90dc1025529a79b", size = 2583072, upload-time = "2025-06-21T04:03:17.337Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/82/95/38ef0cd7fa11eaba6a99b3c4f5ac948d8bc6ff199aabd327a29cc000840c/starlette-0.47.1-py3-none-any.whl", hash = "sha256:5e11c9f5c7c3f24959edbf2dffdc01bba860228acf657129467d8a7468591527", size = 72747, upload-time = "2025-06-21T04:03:15.705Z" }, -] - [[package]] name = "tabulate" version = "0.9.0" @@ -2919,17 +1247,12 @@ dependencies = [ { name = "deprecated" }, { name = "graphviz" }, { name = "highspy" }, - { name = "ipykernel" }, - { name = "ipython" }, { name = "joblib" }, - { name = "jupyter" }, - { name = "jupyter-contrib-nbextensions" }, { name = "matplotlib" }, { name = "networkx" }, { name = "numpy" }, { name = "openpyxl" }, { name = "pandas" }, - { name = "pyam-iamc" }, { name = "pydoe" }, { name = "pyomo" }, { name = "pytest" }, @@ -2975,18 +1298,13 @@ requires-dist = [ { name = "graphviz", specifier = ">=0.20.3" }, { name = "gurobipy", marker = "extra == 'solver'", specifier = ">=12.0.3,<13" }, { name = "highspy", specifier = ">=1.7.2" }, - { name = "ipykernel" }, - { name = "ipython" }, { name = "joblib" }, - { name = "jupyter" }, - { name = "jupyter-contrib-nbextensions" }, { name = "matplotlib", specifier = "==3.9.2" }, { name = "matplotlib", marker = "extra == 'plotting'", specifier = ">=3.9.2" }, { name = "networkx", specifier = ">=3.3" }, { name = "numpy", specifier = ">=2.1.0" }, { name = "openpyxl", specifier = ">=3.1.5" }, { name = "pandas", specifier = ">=2.2.2" }, - { name = "pyam-iamc", specifier = ">=2.2.4" }, { name = "pydoe", specifier = ">=0.3.8" }, { name = "pyomo", specifier = ">=6.8.0" }, { name = "pytest", specifier = ">=8.3.2" }, @@ -3017,96 +1335,6 @@ dev = [ { name = "types-networkx", specifier = ">=3.5.0.20251001" }, ] -[[package]] -name = "terminado" -version = "0.18.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ptyprocess", marker = "os_name != 'nt'" }, - { name = "pywinpty", marker = "os_name == 'nt'" }, - { name = "tornado" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8a/11/965c6fd8e5cc254f1fe142d547387da17a8ebfd75a3455f637c663fb38a0/terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e", size = 32701, upload-time = "2024-03-12T14:34:39.026Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154, upload-time = "2024-03-12T14:34:36.569Z" }, -] - -[[package]] -name = "tinycss2" -version = "1.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "webencodings" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085, upload-time = "2024-10-24T14:58:29.895Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610, upload-time = "2024-10-24T14:58:28.029Z" }, -] - -[[package]] -name = "toml" -version = "0.10.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253, upload-time = "2020-11-01T01:40:22.204Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" }, -] - -[[package]] -name = "tornado" -version = "6.5.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/51/89/c72771c81d25d53fe33e3dca61c233b665b2780f21820ba6fd2c6793c12b/tornado-6.5.1.tar.gz", hash = "sha256:84ceece391e8eb9b2b95578db65e920d2a61070260594819589609ba9bc6308c", size = 509934, upload-time = "2025-05-22T18:15:38.788Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/77/89/f4532dee6843c9e0ebc4e28d4be04c67f54f60813e4bf73d595fe7567452/tornado-6.5.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d50065ba7fd11d3bd41bcad0825227cc9a95154bad83239357094c36708001f7", size = 441948, upload-time = "2025-05-22T18:15:20.862Z" }, - { url = "https://files.pythonhosted.org/packages/15/9a/557406b62cffa395d18772e0cdcf03bed2fff03b374677348eef9f6a3792/tornado-6.5.1-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9e9ca370f717997cb85606d074b0e5b247282cf5e2e1611568b8821afe0342d6", size = 440112, upload-time = "2025-05-22T18:15:22.591Z" }, - { url = "https://files.pythonhosted.org/packages/55/82/7721b7319013a3cf881f4dffa4f60ceff07b31b394e459984e7a36dc99ec/tornado-6.5.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b77e9dfa7ed69754a54c89d82ef746398be82f749df69c4d3abe75c4d1ff4888", size = 443672, upload-time = "2025-05-22T18:15:24.027Z" }, - { url = "https://files.pythonhosted.org/packages/7d/42/d11c4376e7d101171b94e03cef0cbce43e823ed6567ceda571f54cf6e3ce/tornado-6.5.1-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:253b76040ee3bab8bcf7ba9feb136436a3787208717a1fb9f2c16b744fba7331", size = 443019, upload-time = "2025-05-22T18:15:25.735Z" }, - { url = "https://files.pythonhosted.org/packages/7d/f7/0c48ba992d875521ac761e6e04b0a1750f8150ae42ea26df1852d6a98942/tornado-6.5.1-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:308473f4cc5a76227157cdf904de33ac268af770b2c5f05ca6c1161d82fdd95e", size = 443252, upload-time = "2025-05-22T18:15:27.499Z" }, - { url = "https://files.pythonhosted.org/packages/89/46/d8d7413d11987e316df4ad42e16023cd62666a3c0dfa1518ffa30b8df06c/tornado-6.5.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:caec6314ce8a81cf69bd89909f4b633b9f523834dc1a352021775d45e51d9401", size = 443930, upload-time = "2025-05-22T18:15:29.299Z" }, - { url = "https://files.pythonhosted.org/packages/78/b2/f8049221c96a06df89bed68260e8ca94beca5ea532ffc63b1175ad31f9cc/tornado-6.5.1-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:13ce6e3396c24e2808774741331638ee6c2f50b114b97a55c5b442df65fd9692", size = 443351, upload-time = "2025-05-22T18:15:31.038Z" }, - { url = "https://files.pythonhosted.org/packages/76/ff/6a0079e65b326cc222a54720a748e04a4db246870c4da54ece4577bfa702/tornado-6.5.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5cae6145f4cdf5ab24744526cc0f55a17d76f02c98f4cff9daa08ae9a217448a", size = 443328, upload-time = "2025-05-22T18:15:32.426Z" }, - { url = "https://files.pythonhosted.org/packages/49/18/e3f902a1d21f14035b5bc6246a8c0f51e0eef562ace3a2cea403c1fb7021/tornado-6.5.1-cp39-abi3-win32.whl", hash = "sha256:e0a36e1bc684dca10b1aa75a31df8bdfed656831489bc1e6a6ebed05dc1ec365", size = 444396, upload-time = "2025-05-22T18:15:34.205Z" }, - { url = "https://files.pythonhosted.org/packages/7b/09/6526e32bf1049ee7de3bebba81572673b19a2a8541f795d887e92af1a8bc/tornado-6.5.1-cp39-abi3-win_amd64.whl", hash = "sha256:908e7d64567cecd4c2b458075589a775063453aeb1d2a1853eedb806922f568b", size = 444840, upload-time = "2025-05-22T18:15:36.1Z" }, - { url = "https://files.pythonhosted.org/packages/55/a7/535c44c7bea4578e48281d83c615219f3ab19e6abc67625ef637c73987be/tornado-6.5.1-cp39-abi3-win_arm64.whl", hash = "sha256:02420a0eb7bf617257b9935e2b754d1b63897525d8a289c9d65690d580b4dcf7", size = 443596, upload-time = "2025-05-22T18:15:37.433Z" }, -] - -[[package]] -name = "traitlets" -version = "5.14.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, -] - -[[package]] -name = "typeguard" -version = "4.4.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c7/68/71c1a15b5f65f40e91b65da23b8224dad41349894535a97f63a52e462196/typeguard-4.4.4.tar.gz", hash = "sha256:3a7fd2dffb705d4d0efaed4306a704c89b9dee850b688f060a8b1615a79e5f74", size = 75203, upload-time = "2025-06-18T09:56:07.624Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1b/a9/e3aee762739c1d7528da1c3e06d518503f8b6c439c35549b53735ba52ead/typeguard-4.4.4-py3-none-any.whl", hash = "sha256:b5f562281b6bfa1f5492470464730ef001646128b180769880468bd84b68b09e", size = 34874, upload-time = "2025-06-18T09:56:05.999Z" }, -] - -[[package]] -name = "typer" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "shellingham" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c5/8c/7d682431efca5fd290017663ea4588bf6f2c6aad085c7f108c5dbc316e70/typer-0.16.0.tar.gz", hash = "sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b", size = 102625, upload-time = "2025-05-26T14:30:31.824Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/42/3efaf858001d2c2913de7f354563e3a3a2f0decae3efe98427125a8f441e/typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855", size = 46317, upload-time = "2025-05-26T14:30:30.523Z" }, -] - [[package]] name = "types-deprecated" version = "1.2.15.20250304" @@ -3128,15 +1356,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9a/41/cdd9498383b30290cce9de6dbed75fa75d6dc06fe4b47d6da6de4b156aa0/types_networkx-3.5.0.20251001-py3-none-any.whl", hash = "sha256:4bb9dd0378a52ca57d68f8215f8662e736d800a8ff892b457646eccd828a0230", size = 160095, upload-time = "2025-10-01T03:04:24.821Z" }, ] -[[package]] -name = "types-python-dateutil" -version = "2.9.0.20250708" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c9/95/6bdde7607da2e1e99ec1c1672a759d42f26644bbacf939916e086db34870/types_python_dateutil-2.9.0.20250708.tar.gz", hash = "sha256:ccdbd75dab2d6c9696c350579f34cffe2c281e4c5f27a585b2a2438dd1d5c8ab", size = 15834, upload-time = "2025-07-08T03:14:03.382Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/72/52/43e70a8e57fefb172c22a21000b03ebcc15e47e97f5cb8495b9c2832efb4/types_python_dateutil-2.9.0.20250708-py3-none-any.whl", hash = "sha256:4d6d0cc1cc4d24a2dc3816024e502564094497b713f7befda4d5bc7a8e3fd21f", size = 17724, upload-time = "2025-07-08T03:14:02.593Z" }, -] - [[package]] name = "types-pytz" version = "2025.2.0.20250809" @@ -3155,31 +1374,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b5/00/d631e67a838026495268c2f6884f3711a15a9a2a96cd244fdaea53b823fb/typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76", size = 43906, upload-time = "2025-07-04T13:28:32.743Z" }, ] -[[package]] -name = "typing-inspect" -version = "0.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mypy-extensions" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/dc/74/1789779d91f1961fa9438e9a8710cdae6bd138c80d7303996933d117264a/typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78", size = 13825, upload-time = "2023-05-24T20:25:47.612Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f", size = 8827, upload-time = "2023-05-24T20:25:45.287Z" }, -] - -[[package]] -name = "typing-inspection" -version = "0.4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, -] - [[package]] name = "tzdata" version = "2025.2" @@ -3189,15 +1383,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" }, ] -[[package]] -name = "uri-template" -version = "1.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/31/c7/0336f2bd0bcbada6ccef7aaa25e443c118a704f828a0620c6fa0207c1b64/uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7", size = 21678, upload-time = "2023-06-21T01:49:05.374Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363", size = 11140, upload-time = "2023-06-21T01:49:03.467Z" }, -] - [[package]] name = "urllib3" version = "2.5.0" @@ -3221,63 +1406,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f3/40/b1c265d4b2b62b58576588510fc4d1fe60a86319c8de99fd8e9fec617d2c/virtualenv-20.31.2-py3-none-any.whl", hash = "sha256:36efd0d9650ee985f0cad72065001e66d49a6f24eb44d98980f630686243cf11", size = 6057982, upload-time = "2025-05-08T17:58:21.15Z" }, ] -[[package]] -name = "wcwidth" -version = "0.2.13" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301, upload-time = "2024-01-06T02:10:57.829Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166, upload-time = "2024-01-06T02:10:55.763Z" }, -] - -[[package]] -name = "webcolors" -version = "24.11.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7b/29/061ec845fb58521848f3739e466efd8250b4b7b98c1b6c5bf4d40b419b7e/webcolors-24.11.1.tar.gz", hash = "sha256:ecb3d768f32202af770477b8b65f318fa4f566c22948673a977b00d589dd80f6", size = 45064, upload-time = "2024-11-11T07:43:24.224Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/60/e8/c0e05e4684d13459f93d312077a9a2efbe04d59c393bc2b8802248c908d4/webcolors-24.11.1-py3-none-any.whl", hash = "sha256:515291393b4cdf0eb19c155749a096f779f7d909f7cceea072791cb9095b92e9", size = 14934, upload-time = "2024-11-11T07:43:22.529Z" }, -] - -[[package]] -name = "webencodings" -version = "0.5.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721, upload-time = "2017-04-05T20:21:34.189Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774, upload-time = "2017-04-05T20:21:32.581Z" }, -] - -[[package]] -name = "websocket-client" -version = "1.8.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e6/30/fba0d96b4b5fbf5948ed3f4681f7da2f9f64512e1d303f94b4cc174c24a5/websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da", size = 54648, upload-time = "2024-04-23T22:16:16.976Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", size = 58826, upload-time = "2024-04-23T22:16:14.422Z" }, -] - -[[package]] -name = "widgetsnbextension" -version = "4.0.14" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/41/53/2e0253c5efd69c9656b1843892052a31c36d37ad42812b5da45c62191f7e/widgetsnbextension-4.0.14.tar.gz", hash = "sha256:a3629b04e3edb893212df862038c7232f62973373869db5084aed739b437b5af", size = 1097428, upload-time = "2025-04-10T13:01:25.628Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/51/5447876806d1088a0f8f71e16542bf350918128d0a69437df26047c8e46f/widgetsnbextension-4.0.14-py3-none-any.whl", hash = "sha256:4875a9eaf72fbf5079dc372a51a9f268fc38d46f767cbf85c43a36da5cb9b575", size = 2196503, upload-time = "2025-04-10T13:01:23.086Z" }, -] - -[[package]] -name = "wquantiles" -version = "0.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/eb/24/ae0216512052aee6cf68cba89f83ce011e06feff7a4cae5b03d78d078b24/wquantiles-0.6.tar.gz", hash = "sha256:a9e5b61277c8bf414394131bba4af0fc565de379ca73d6f7a336ba60184fa5c4", size = 2948, upload-time = "2021-05-26T10:38:08.815Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/75/3cce30508bf46121b7cabce57b9cacbf8d935fa555cb3c5fca43f8dd0414/wquantiles-0.6-py3-none-any.whl", hash = "sha256:1b90d68fa05251bb96f8806a346e8d7dec9a9bb99f381ad5094707b46ab85218", size = 3291, upload-time = "2021-05-26T10:38:07.38Z" }, -] - [[package]] name = "wrapt" version = "1.17.2" From 0e5ffb26b8741f221fd5e9f1e77d20413e826044 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 30 Oct 2025 12:30:09 -0400 Subject: [PATCH 293/587] assert locking in uv ci --- .github/workflows/ci.yml | 4 ++-- pyproject.toml | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 86e90315e..d5a425a82 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,7 +37,7 @@ jobs: enable-cache: true - name: Install the project - run: uv sync --all-extras --dev + run: uv sync --locked --all-extras --dev - name: Install CBC solver run: | @@ -63,7 +63,7 @@ jobs: enable-cache: true - name: Install the project - run: uv sync --all-extras --dev + run: uv sync --locked --all-extras --dev - name: Run mypy run: uv run mypy --config-file=pyproject.toml temoa/ diff --git a/pyproject.toml b/pyproject.toml index af0900224..ac1cd3fef 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -95,6 +95,9 @@ addopts = "-ra -q" testpaths = [ "tests", ] +filterwarnings = [ + "ignore:invalid escape sequence:SyntaxWarning:pyutilib.misc.misc", +] [tool.mypy] # Python version targeting From 406960f8793fafb4c83ef6a1bda958e94c85b072 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 30 Oct 2025 12:47:40 -0400 Subject: [PATCH 294/587] making sql queries literals and polishing exceptions --- temoa/data_processing/db_to_excel.py | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/temoa/data_processing/db_to_excel.py b/temoa/data_processing/db_to_excel.py index 64c0a9ff9..cc42d8a7f 100644 --- a/temoa/data_processing/db_to_excel.py +++ b/temoa/data_processing/db_to_excel.py @@ -32,15 +32,13 @@ def make_excel(ifile: str | None, ofile: Path | None, scenario: set[str]) -> Non file_match = re.search(r'(\w+)\.(\w+)\b', ifile) if not file_match: - print(f'The file type {ifile} is not recognized. Use a .db file.') - sys.exit(2) + raise ValueError(f'The file type {ifile} is not recognized. Use a database file.') if ofile is None: ofile = Path(file_match.group(1)) print(f'Look for output in {ofile}_*.xlsx') con = sqlite3.connect(ifile) - con.text_factory = str scenario_name = scenario.pop() ofile = ofile.with_suffix('.xlsx') @@ -59,12 +57,12 @@ def make_excel(ifile: str | None, ofile: Path | None, scenario: set[str]) -> Non """ all_techs = pd.read_sql_query(query_all_techs, con) - query_capacity = f""" + query_capacity = """ SELECT region, tech, sector, period, SUM(capacity) as capacity - FROM OutputNetCapacity WHERE scenario = '{scenario_name}' + FROM OutputNetCapacity WHERE scenario = ? GROUP BY region, tech, sector, period """ - df_capacity = pd.read_sql_query(query_capacity, con) + df_capacity = pd.read_sql_query(query_capacity, con, params=(scenario_name,)) for sector in sorted(df_capacity['sector'].unique()): df_sector = ( df_capacity[df_capacity['sector'] == sector] @@ -88,12 +86,12 @@ def make_excel(ifile: str | None, ofile: Path | None, scenario: set[str]) -> Non for col, val in enumerate(df_sector.columns.values): worksheet.write(0, col, val, header_format) - query_activity = f""" + query_activity = """ SELECT region, tech, sector, period, SUM(flow) as vflow_out - FROM OutputFlowOut WHERE scenario = '{scenario_name}' + FROM OutputFlowOut WHERE scenario = ? GROUP BY region, tech, sector, period """ - df_activity = pd.read_sql_query(query_activity, con) + df_activity = pd.read_sql_query(query_activity, con, params=(scenario_name,)) for sector in sorted(df_activity['sector'].unique()): df_sector = ( df_activity[df_activity['sector'] == sector] @@ -127,12 +125,12 @@ def make_excel(ifile: str | None, ofile: Path | None, scenario: set[str]) -> Non except sqlite3.OperationalError: all_emis_techs = pd.DataFrame() - query_emissions = f""" + query_emissions = """ SELECT region, tech, sector, period, emis_comm, SUM(emission) as emissions - FROM OutputEmission WHERE scenario = '{scenario_name}' + FROM OutputEmission WHERE scenario = ? GROUP BY region, tech, sector, period, emis_comm """ - df_emissions_raw = pd.read_sql_query(query_emissions, con) + df_emissions_raw = pd.read_sql_query(query_emissions, con, params=(scenario_name,)) if not df_emissions_raw.empty: df_emissions = df_emissions_raw.pivot_table( values='emissions', @@ -163,14 +161,14 @@ def make_excel(ifile: str | None, ofile: Path | None, scenario: set[str]) -> Non for col, val in enumerate(df_emissions.columns.values): worksheet.write(0, col, val, header_format) - query_costs = f""" + query_costs = """ SELECT region, oc.tech, t.sector, vintage, d_invest + d_var + d_fixed + d_emiss as cost FROM OutputCost oc JOIN Technology t ON oc.tech = t.tech - WHERE scenario = '{scenario_name}' + WHERE scenario = ? """ - df_costs = pd.read_sql_query(query_costs, con) + df_costs = pd.read_sql_query(query_costs, con, params=(scenario_name,)) df_costs.columns = ['Region', 'Technology', 'Sector', 'Vintage', 'Cost'] df_costs.to_excel(writer, sheet_name='Costs', index=False, startrow=1, header=False) worksheet = writer.sheets['Costs'] From 6388fc82b1a9da50aff5190b09060486f4272cd9 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 30 Oct 2025 12:51:14 -0400 Subject: [PATCH 295/587] updating pytest config to treat most warnings as errors --- .github/workflows/ci.yml | 2 +- pyproject.toml | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d5a425a82..3b5d6dff5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,7 +45,7 @@ jobs: sudo apt-get install -y coinor-cbc - name: Run tests - run: uv run pytest tests + run: uv run pytest -c pyproject.toml tests type-check: name: type check diff --git a/pyproject.toml b/pyproject.toml index ac1cd3fef..199490b2a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -90,13 +90,18 @@ ignore-names = ["MGA", "SVMGA"] # Allow these names to violate naming conventio [tool.pytest.ini_options] -minversion = "8.0" -addopts = "-ra -q" testpaths = [ "tests", ] filterwarnings = [ - "ignore:invalid escape sequence:SyntaxWarning:pyutilib.misc.misc", + # Raise all warnings as errors except for the ones we specifically ignore + "error::DeprecationWarning", + "error::FutureWarning", + "error::RuntimeWarning", + "error::UserWarning", + + # Ignore deprecation warnings from dependencies + "error:invalid escape sequence:SyntaxWarning:pyutilib.misc.misc", ] [tool.mypy] From 7f092bfcaeb4712dcf0e4307a962d47ccba2f9d2 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 30 Oct 2025 14:35:34 -0400 Subject: [PATCH 296/587] removing pyutilib dependency --- pyproject.toml | 3 --- requirements-dev.txt | 8 +------- requirements.txt | 8 +------- uv.lock | 26 +------------------------- 4 files changed, 3 insertions(+), 42 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 199490b2a..e2cba8a5b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,6 @@ dependencies = [ "joblib", "salib>=1.5.1", "pydoe>=0.3.8", - "pyutilib>=6.0.0", "graphviz>=0.20.3", "seaborn>=0.13.2", "tabulate>=0.9.0", @@ -100,8 +99,6 @@ filterwarnings = [ "error::RuntimeWarning", "error::UserWarning", - # Ignore deprecation warnings from dependencies - "error:invalid escape sequence:SyntaxWarning:pyutilib.misc.misc", ] [tool.mypy] diff --git a/requirements-dev.txt b/requirements-dev.txt index 175e567ff..4fa08e198 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -57,8 +57,6 @@ multiprocess==0.70.18 # via salib networkx==3.5 # via temoa (pyproject.toml) -nose==1.3.7 - # via pyutilib numpy==2.3.1 # via # temoa (pyproject.toml) @@ -112,8 +110,6 @@ python-dateutil==2.9.0.post0 # pandas pytz==2025.2 # via pandas -pyutilib==6.0.0 - # via temoa (pyproject.toml) pyyaml==6.0.2 # via pybtex requests==2.32.4 @@ -130,9 +126,7 @@ scipy==1.16.0 seaborn==0.13.2 # via temoa (pyproject.toml) six==1.17.0 - # via - # python-dateutil - # pyutilib + # via python-dateutil snowballstemmer==3.0.1 # via sphinx sphinx==8.2.3 diff --git a/requirements.txt b/requirements.txt index b276a8e9a..99fc9963c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -31,8 +31,6 @@ multiprocess==0.70.18 # via salib networkx==3.5 # via temoa (pyproject.toml) -nose==1.3.7 - # via pyutilib numpy==2.3.1 # via # temoa (pyproject.toml) @@ -77,8 +75,6 @@ python-dateutil==2.9.0.post0 # pandas pytz==2025.2 # via pandas -pyutilib==6.0.0 - # via temoa (pyproject.toml) salib==1.5.1 # via temoa (pyproject.toml) scipy==1.16.0 @@ -89,9 +85,7 @@ scipy==1.16.0 seaborn==0.13.2 # via temoa (pyproject.toml) six==1.17.0 - # via - # python-dateutil - # pyutilib + # via python-dateutil tabulate==0.9.0 # via temoa (pyproject.toml) tzdata==2025.2 diff --git a/uv.lock b/uv.lock index 14ae00565..6317513aa 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.12" [[package]] @@ -572,15 +572,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, ] -[[package]] -name = "nose" -version = "1.3.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/a5/0dc93c3ec33f4e281849523a5a913fa1eea9a3068acfa754d44d88107a44/nose-1.3.7.tar.gz", hash = "sha256:f1bffef9cbc82628f6e7d7b40d7e255aefaa1adb6a1b1d26c69a8b79e6208a98", size = 280488, upload-time = "2015-06-02T09:12:32.961Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/15/d8/dd071918c040f50fa1cf80da16423af51ff8ce4a0f2399b7bf8de45ac3d9/nose-1.3.7-py3-none-any.whl", hash = "sha256:9ff7c6cc443f8c51994b34a667bbcf45afd6d945be7477b52e97516fd17c53ac", size = 154731, upload-time = "2015-06-02T09:12:40.57Z" }, -] - [[package]] name = "numpy" version = "2.3.1" @@ -933,19 +924,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, ] -[[package]] -name = "pyutilib" -version = "6.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nose" }, - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c6/fd/9cf9313b26398d1a77ee8b86b5e467ccae55b066cdc4a466186903e4000b/PyUtilib-6.0.0.tar.gz", hash = "sha256:d3c14f8ed9028a831b2bf51b8ab7776eba87e66cfc58a06b99c359aaa640f040", size = 178746, upload-time = "2020-06-19T14:30:52.51Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e1/e7/c3e5994b4e5c90280b5c14ffef409875ec5436d1d0d9f8585794993a7d77/PyUtilib-6.0.0-py2.py3-none-any.whl", hash = "sha256:f1f82d05ad8c42baeef915c8d3d97c0a3cbed6c506c857ab0ab7694dea50ebd8", size = 254187, upload-time = "2020-06-19T14:30:50.656Z" }, -] - [[package]] name = "pyyaml" version = "6.0.2" @@ -1256,7 +1234,6 @@ dependencies = [ { name = "pydoe" }, { name = "pyomo" }, { name = "pytest" }, - { name = "pyutilib" }, { name = "salib" }, { name = "scipy" }, { name = "seaborn" }, @@ -1308,7 +1285,6 @@ requires-dist = [ { name = "pydoe", specifier = ">=0.3.8" }, { name = "pyomo", specifier = ">=6.8.0" }, { name = "pytest", specifier = ">=8.3.2" }, - { name = "pyutilib", specifier = ">=6.0.0" }, { name = "salib", specifier = ">=1.5.1" }, { name = "scipy", specifier = ">=1.14.1" }, { name = "seaborn", specifier = ">=0.13.2" }, From d31318a1ec9e6368621ddacf0193a75e39abd279 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 30 Oct 2025 14:40:56 -0400 Subject: [PATCH 297/587] reenabling caching for uv --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e68f85987..e24e9f3d1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,7 @@ jobs: with: version: "0.9.6" python-version: ${{ matrix.python-version }} - enable-cache: false + enable-cache: true - name: Install the project run: uv sync --locked --all-extras --dev @@ -66,7 +66,7 @@ jobs: with: version: "0.9.6" python-version: ${{ matrix.python-version }} - enable-cache: false + enable-cache: true - name: Install the project run: uv sync --locked --all-extras --dev From 02390bbd6e432b147828e400bd2af3f50946a43d Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 30 Oct 2025 19:10:57 -0400 Subject: [PATCH 298/587] turning core type aliases to newTypes for stricter checking --- temoa/_internal/data_brick.py | 17 +- temoa/_internal/exchange_tech_cost_ledger.py | 60 +++-- temoa/_internal/table_data_puller.py | 98 ++++---- temoa/_internal/table_writer.py | 19 +- temoa/components/commodities.py | 244 ++++++++++--------- temoa/components/costs.py | 18 +- temoa/components/geography.py | 14 +- temoa/components/limits.py | 6 +- temoa/components/storage.py | 8 +- temoa/components/technology.py | 10 +- temoa/components/time.py | 6 +- temoa/types/core_types.py | 24 +- temoa/types/dict_types.py | 2 +- 13 files changed, 265 insertions(+), 261 deletions(-) diff --git a/temoa/_internal/data_brick.py b/temoa/_internal/data_brick.py index 312521a8a..735576179 100644 --- a/temoa/_internal/data_brick.py +++ b/temoa/_internal/data_brick.py @@ -15,6 +15,7 @@ poll_objective, ) from temoa.core.model import TemoaModel +from temoa.types.core_types import Period, Region, Technology, Vintage from temoa.types.model_types import EI, FI, CapData, FlowType @@ -26,13 +27,13 @@ class DataBrick: def __init__( self, name: str, - emission_costs: dict[tuple[str, int, str, int], dict[CostType, float]], + emission_costs: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]], emission_flows: dict[EI, float], capacity_data: CapData, flow_data: dict[FI, dict[FlowType, float]], obj_data: list[tuple[str, float]], - regular_costs: dict[tuple[str, int, str, int], dict[CostType, float]], - exchange_costs: dict[tuple[str, int, str, int], dict[CostType, float]], + regular_costs: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]], + exchange_costs: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]], ): self._name = name self._emission_costs = emission_costs @@ -64,15 +65,19 @@ def obj_data(self) -> list[tuple[str, float]]: return self._obj_data @property - def cost_data(self) -> dict[tuple[str, int, str, int], dict[CostType, float]]: + def cost_data(self) -> dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]]: return self._regular_costs @property - def exchange_cost_data(self) -> dict[tuple[str, int, str, int], dict[CostType, float]]: + def exchange_cost_data( + self, + ) -> dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]]: return self._exchange_costs @property - def emission_cost_data(self) -> dict[tuple[str, int, str, int], dict[CostType, float]]: + def emission_cost_data( + self, + ) -> dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]]: return self._emission_costs diff --git a/temoa/_internal/exchange_tech_cost_ledger.py b/temoa/_internal/exchange_tech_cost_ledger.py index 6e820c075..7976711cf 100644 --- a/temoa/_internal/exchange_tech_cost_ledger.py +++ b/temoa/_internal/exchange_tech_cost_ledger.py @@ -6,14 +6,16 @@ """ +from __future__ import annotations + from collections import defaultdict from enum import Enum, unique -from typing import TYPE_CHECKING, Union, cast +from typing import TYPE_CHECKING, cast from pyomo.common.numeric_types import value from temoa.core.model import TemoaModel -from temoa.types.core_types import Period, Technology, Vintage +from temoa.types.core_types import Period, Region, Technology, Vintage if TYPE_CHECKING: from tests.utilities.namespace_mock import Namespace @@ -32,16 +34,16 @@ class CostType(Enum): class ExchangeTechCostLedger: - def __init__(self, model: Union[TemoaModel, 'Namespace']) -> None: - self.cost_records: dict[CostType, dict[tuple[str, str, str, int, int], float]] = ( - defaultdict(dict) - ) + def __init__(self, model: TemoaModel | Namespace) -> None: + self.cost_records: dict[ + CostType, dict[tuple[Region, Region, Technology, Vintage, Period], float] + ] = defaultdict(dict) # could be a Namespace for testing purposes... See the related test - self.M = model + self.model = model def add_cost_record( self, - link: str, + link: Region, period: Period, tech: Technology, vintage: Vintage, @@ -52,14 +54,14 @@ def add_cost_record( add a cost associated with an exchange tech :return: """ - r1, r2 = link.split('-') + r1, r2 = (cast(Region, r) for r in link.split('-')) if not r1 and r2: raise ValueError(f'problem splitting region-region: {link}') # add to the "seen" records for appropriate cost type self.cost_records[cost_type][r1, r2, tech, vintage, period] = cost def get_use_ratio( - self, exporter: str, importer: str, period: Period, tech: Technology, vintage: Vintage + self, exporter: Region, importer: Region, period: Period, tech: Technology, vintage: Vintage ) -> float: """ use flow to calculate the use ratio for these 2 entities for cost apportioning purposes @@ -72,10 +74,10 @@ def get_use_ratio( """ # Cast to TemoaModel for type checking - at runtime this will be either TemoaModel or Namespace # Both have the same attributes, but mypy doesn't know about Namespace's dynamic attributes - model = cast(TemoaModel, self.M) + model = cast(TemoaModel, self.model) # need to temporarily reconstitute the names - rr1 = '-'.join([exporter, importer]) - rr2 = '-'.join([importer, exporter]) + rr1 = cast(Region, '-'.join([exporter, importer])) + rr2 = cast(Region, '-'.join([importer, exporter])) if any( ( period >= vintage + value(model.LifetimeProcess[rr1, tech, vintage]), @@ -87,35 +89,35 @@ def get_use_ratio( if tech not in model.tech_annual: act_dir1 = value( sum( - model.V_FlowOut[rr1, period, s, d, S_i, tech, vintage, S_o] + model.V_FlowOut[rr1, period, s, d, s_i, tech, vintage, s_o] for s in model.TimeSeason[period] for d in model.time_of_day - for S_i in model.processInputs[rr1, period, tech, vintage] - for S_o in model.processOutputsByInput[rr1, period, tech, vintage, S_i] + for s_i in model.processInputs[rr1, period, tech, vintage] + for s_o in model.processOutputsByInput[rr1, period, tech, vintage, s_i] ) ) act_dir2 = value( sum( - model.V_FlowOut[rr2, period, s, d, S_i, tech, vintage, S_o] + model.V_FlowOut[rr2, period, s, d, s_i, tech, vintage, s_o] for s in model.TimeSeason[period] for d in model.time_of_day - for S_i in model.processInputs[rr2, period, tech, vintage] - for S_o in model.processOutputsByInput[rr2, period, tech, vintage, S_i] + for s_i in model.processInputs[rr2, period, tech, vintage] + for s_o in model.processOutputsByInput[rr2, period, tech, vintage, s_i] ) ) else: act_dir1 = value( sum( - model.V_FlowOutAnnual[rr1, period, S_i, tech, vintage, S_o] - for S_i in model.processInputs[rr1, period, tech, vintage] - for S_o in model.processOutputsByInput[rr1, period, tech, vintage, S_i] + model.V_FlowOutAnnual[rr1, period, s_i, tech, vintage, s_o] + for s_i in model.processInputs[rr1, period, tech, vintage] + for s_o in model.processOutputsByInput[rr1, period, tech, vintage, s_i] ) ) act_dir2 = value( sum( - model.V_FlowOutAnnual[rr2, period, S_i, tech, vintage, S_o] - for S_i in model.processInputs[rr2, period, tech, vintage] - for S_o in model.processOutputsByInput[rr2, period, tech, vintage, S_i] + model.V_FlowOutAnnual[rr2, period, s_i, tech, vintage, s_o] + for s_i in model.processInputs[rr2, period, tech, vintage] + for s_o in model.processOutputsByInput[rr2, period, tech, vintage, s_i] ) ) @@ -123,8 +125,12 @@ def get_use_ratio( return act_dir1 / (act_dir1 + act_dir2) return 0.5 - def get_entries(self) -> dict[tuple[str, int, str, int], dict[CostType, float]]: - region_costs: dict[tuple[str, int, str, int], dict[CostType, float]] = defaultdict(dict) + def get_entries( + self, + ) -> dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]]: + region_costs: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]] = ( + defaultdict(dict) + ) # iterate through each region pairing, pull the cost records and decide if/how to split each one for cost_type in self.cost_records: # make a copy, this will be destructive operation diff --git a/temoa/_internal/table_data_puller.py b/temoa/_internal/table_data_puller.py index ac7e34935..d8de0a621 100644 --- a/temoa/_internal/table_data_puller.py +++ b/temoa/_internal/table_data_puller.py @@ -1,29 +1,4 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 12/5/24 - A companion module to the table writer to hold some data-pulling functions and small utilities and separate them from the writing process for organization and to isolate the DB access in the writer such that these functions can be called on a model instance without any DB interactions. (Intended to support use @@ -34,6 +9,7 @@ import functools import logging from collections import defaultdict +from typing import cast from pyomo.common.numeric_types import value from pyomo.core import Objective @@ -42,6 +18,7 @@ from temoa.components import costs from temoa.components.utils import get_variable_efficiency from temoa.core.model import TemoaModel +from temoa.types.core_types import Commodity, Period, Region, Technology, Vintage from temoa.types.model_types import EI, FI, SLI, CapData, FlowType logger = logging.getLogger(__name__) @@ -54,12 +31,12 @@ def _marks(num: int) -> str: return marks -def ritvo(fi: FI) -> tuple[str, str, str, int, str]: +def ritvo(fi: FI) -> tuple[Region, Commodity, Technology, Vintage, Commodity]: """convert FI to ritvo index""" return fi.r, fi.i, fi.t, fi.v, fi.o -def rpetv(fi: FI, e: str) -> tuple[str, int, str, str, int]: +def rpetv(fi: FI, e: Commodity) -> tuple[Region, Period, Commodity, Technology, Vintage]: """convert FI and emission to rpetv index""" return fi.r, fi.p, e, fi.t, fi.v @@ -205,7 +182,7 @@ def poll_flow_results(model: TemoaModel, epsilon: float = 1e-5) -> dict[FI, dict ) for s in model.TimeSeason[v]: for d in model.time_of_day: - fi = FI(r, v, s, d, i, t, v, 'ConstructionInput') + fi = FI(r, v, s, d, i, t, v, cast(Commodity, 'ConstructionInput')) flow = annual * value(model.SegFrac[v, s, d]) if abs(flow) < epsilon: continue @@ -221,7 +198,7 @@ def poll_flow_results(model: TemoaModel, epsilon: float = 1e-5) -> dict[FI, dict ) for s in model.TimeSeason[p]: for d in model.time_of_day: - fi = FI(r, p, s, d, 'EndOfLifeOutput', t, v, o) + fi = FI(r, p, s, d, cast(Commodity, 'EndOfLifeOutput'), t, v, o) flow = annual * value(model.SegFrac[p, s, d]) if abs(flow) < epsilon: continue @@ -286,10 +263,10 @@ def poll_objective(model: TemoaModel) -> list[tuple[str, float]]: def poll_cost_results( - model: TemoaModel, p_0: int | None, epsilon: float = 1e-5 + model: TemoaModel, p_0: Period | None, epsilon: float = 1e-5 ) -> tuple[ - dict[tuple[str, int, str, int], dict[CostType, float]], - dict[tuple[str, int, str, int], dict[CostType, float]], + dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]], + dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]], ]: """ Poll a solved model for all cost results @@ -298,7 +275,7 @@ def poll_cost_results( :param epsilon: epsilon (default 1e-5) :return: tuple of cost_dict, exchange_cost_dict (for exchange techs) """ - p_0_true: int + p_0_true: Period if p_0 is None: p_0_true = min(model.time_optimize) else: @@ -312,7 +289,9 @@ def poll_cost_results( loan_lifetime_process = model.LoanLifetimeProcess exchange_costs = ExchangeTechCostLedger(model) - entries: dict[tuple[str, int, str, int], dict[CostType, float]] = defaultdict(dict) + entries: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]] = defaultdict( + dict + ) for r, t, v in model.CostInvest.sparse_iterkeys(): # Returns only non-zero values # gather details... cap = value(model.V_NewCapacity[r, t, v]) @@ -367,8 +346,9 @@ def poll_cost_results( cost_type=CostType.INVEST, ) else: - # enter it into the entries table with period of cost = vintage (p=v) - entries[r, v, t, v].update( + # The period `p` for an investment cost is its vintage `v`. + key = (cast(Region, r), cast(Period, v), cast(Technology, t), cast(Vintage, v)) + entries[key].update( {CostType.D_INVEST: model_loan_cost, CostType.INVEST: undiscounted_cost} ) @@ -518,17 +498,17 @@ def loan_costs( def loan_costs_survival_curve( model: TemoaModel, - r: str, - t: str, - v: int, + r: Region, + t: Technology, + v: Vintage, loan_rate: float, # this is referred to as LoanRate in parameters loan_life: float, capacity: float, invest_cost: float, - p_0: int, - p_e: int, + p_0: Period, + p_e: Period, global_discount_rate: float, - vintage: int, + vintage: Vintage, **kwargs: object, ) -> tuple[float, float]: """ @@ -570,8 +550,10 @@ def loan_costs_survival_curve( def poll_emissions( - model: TemoaModel, p_0: int | None = None, epsilon: float = 1e-5 -) -> tuple[dict[tuple[str, int, str, int], dict[CostType, float]], dict[EI, float]]: + model: TemoaModel, p_0: Period | None = None, epsilon: float = 1e-5 +) -> tuple[ + dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]], dict[EI, float] +]: """ Gather all emission flows, cost them and provide a tuple of costs and flows :param M: the model @@ -582,7 +564,7 @@ def poll_emissions( # UPDATE: older versions brought forward had some accounting errors here for flex/curtailed emissions # see the note on emissions in the Cost function in temoa_rules - p_0_true: int + p_0_true: Period if p_0 is None: p_0_true = min(model.time_optimize) else: @@ -626,8 +608,8 @@ def poll_emissions( ) # gather costs - ud_costs: dict[tuple[str, int, str, int], float] = defaultdict(float) - d_costs: dict[tuple[str, int, str, int], float] = defaultdict(float) + ud_costs: dict[tuple[Region, Period, Technology, Vintage], float] = defaultdict(float) + d_costs: dict[tuple[Region, Period, Technology, Vintage], float] = defaultdict(float) for ei in flows: # zero out tiny flows if abs(flows[ei]) < epsilon: @@ -676,26 +658,28 @@ def poll_emissions( flows[ei] = 0.0 continue # screen to see if there is an associated cost - cost_index = (ei.r, ei.v, ei.e) + cost_index = (ei.r, cast(Period, ei.v), ei.e) if cost_index not in model.CostEmission: continue undiscounted_emiss_cost = ( embodied_flows[ei] - * model.CostEmission[ei.r, ei.v, ei.e] - * model.PeriodLength[ei.v] # treat as fixed cost distributed over construction period + * model.CostEmission[ei.r, cast(Period, ei.v), ei.e] + * model.PeriodLength[ + cast(Period, ei.v) + ] # treat as fixed cost distributed over construction period ) discounted_emiss_cost = costs.fixed_or_variable_cost( cap_or_flow=embodied_flows[ei], - cost_factor=value(model.CostEmission[ei.r, ei.v, ei.e]), + cost_factor=value(model.CostEmission[ei.r, cast(Period, ei.v), ei.e]), cost_years=model.PeriodLength[ - ei.v + cast(Period, ei.v) ], # treat as fixed cost distributed over construction period global_discount_rate=global_discount_rate, p_0=p_0_true, - p=ei.v, + p=cast(Period, ei.v), ) - ud_costs[ei.r, ei.v, ei.t, ei.v] += float(value(undiscounted_emiss_cost)) - d_costs[ei.r, ei.v, ei.t, ei.v] += float(value(discounted_emiss_cost)) + ud_costs[ei.r, cast(Period, ei.v), ei.t, ei.v] += float(value(undiscounted_emiss_cost)) + d_costs[ei.r, cast(Period, ei.v), ei.t, ei.v] += float(value(discounted_emiss_cost)) ########################### # End of life Emissions @@ -743,7 +727,9 @@ def poll_emissions( d_costs[ei.r, ei.p, ei.t, ei.v] += float(value(discounted_emiss_cost)) # finally, now that all costs are added up for each rptv, put in cost dict - costs_dict: dict[tuple[str, int, str, int], dict[CostType, float]] = defaultdict(dict) + costs_dict: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]] = ( + defaultdict(dict) + ) for rptv in ud_costs: costs_dict[rptv][CostType.EMISS] = ud_costs[rptv] for rptv in d_costs: diff --git a/temoa/_internal/table_writer.py b/temoa/_internal/table_writer.py index 1ae2e81a3..84a3b0d1f 100644 --- a/temoa/_internal/table_writer.py +++ b/temoa/_internal/table_writer.py @@ -8,7 +8,7 @@ from collections.abc import Iterable from logging import getLogger from pathlib import Path -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, cast from pyomo.core import value from pyomo.opt import SolverResults @@ -33,6 +33,7 @@ from temoa.core.model import TemoaModel from temoa.core.modes import TemoaMode from temoa.extensions.monte_carlo.mc_run import ChangeRecord +from temoa.types.core_types import Period, Region, Technology, Vintage if TYPE_CHECKING: pass @@ -292,9 +293,9 @@ def write_emissions(self, iteration: int | None = None) -> None: if abs(val) < self.epsilon: continue if hasattr(ei, 'p'): # emissions from flows - entry = (scenario, ei.r, sector, ei.p, ei.e, ei.t, ei.v, val) + entry = (scenario, ei.r, sector, cast(int, ei.p), ei.e, ei.t, ei.v, val) else: # embodied emissions - entry = (scenario, ei.r, sector, ei.v, ei.e, ei.t, ei.v, val) + entry = (scenario, ei.r, sector, cast(int, ei.v), ei.e, ei.t, ei.v, val) data.append(entry) qry = f'INSERT INTO OutputEmission VALUES {_marks(8)}' self.con.executemany(qry, data) @@ -530,7 +531,8 @@ def calculate_flows(self, model: TemoaModel) -> dict[FI, dict[FlowType, float]]: def write_costs( self, model: TemoaModel, - emission_entries: dict[tuple[str, int, str, int], dict[CostType, float]] | None = None, + emission_entries: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]] + | None = None, iteration: int | None = None, ) -> None: """ @@ -555,9 +557,10 @@ def write_costs( def _insert_cost_results( self, - regular_entries: dict[tuple[str, int, str, int], dict[CostType, float]], - exchange_entries: dict[tuple[str, int, str, int], dict[CostType, float]], - emission_entries: dict[tuple[str, int, str, int], dict[CostType, float]] | None, + regular_entries: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]], + exchange_entries: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]], + emission_entries: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]] + | None, iteration: int | None, ) -> None: # add the emission costs to the same row data, if provided @@ -569,7 +572,7 @@ def _insert_cost_results( def _write_cost_rows( self, - entries: dict[tuple[str, int, str, int], dict[CostType, float]], + entries: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]], iteration: int | None = None, ) -> None: """Write the entries to the OutputCost table""" diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index 7b6ac0bbe..7c8528161 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -14,7 +14,7 @@ from itertools import product as cross_product from logging import getLogger from operator import itemgetter as iget -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, cast from pyomo.environ import value @@ -178,16 +178,16 @@ def demand_constraint(model: TemoaModel, r: Region, p: Period, dem: Commodity) - # All demand techs are annual now # supply = sum( - # M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, dem] - # for S_t, S_v in M.commodityUStreamProcess[r, p, dem] - # if S_t not in M.tech_annual - # for S_i in M.processInputsByOutput[r, p, S_t, S_v, dem] + # M.V_FlowOut[r, p, s, d, s_i, s_t, s_v, dem] + # for s_t, s_v in M.commodityUStreamProcess[r, p, dem] + # if s_t not in M.tech_annual + # for s_i in M.processInputsByOutput[r, p, s_t, s_v, dem] # ) supply_annual = sum( - model.V_FlowOutAnnual[r, p, S_i, S_t, S_v, dem] - for S_t, S_v in model.commodityUStreamProcess[r, p, dem] - for S_i in model.processInputsByOutput[r, p, S_t, S_v, dem] + model.V_FlowOutAnnual[r, p, s_i, s_t, s_v, dem] + for s_t, s_v in model.commodityUStreamProcess[r, p, dem] + for s_i in model.processInputsByOutput[r, p, s_t, s_v, dem] ) demand_constraint_error_check(supply_annual, r, p, dem) @@ -238,13 +238,13 @@ def demand_activity_constraint( """ activity = sum( - model.V_FlowOut[r, p, s, d, S_i, t, v, dem] - for S_i in model.processInputsByOutput[r, p, t, v, dem] + model.V_FlowOut[r, p, s, d, s_i, t, v, dem] + for s_i in model.processInputsByOutput[r, p, t, v, dem] ) annual_activity = sum( - model.V_FlowOutAnnual[r, p, S_i, t, v, dem] - for S_i in model.processInputsByOutput[r, p, t, v, dem] + model.V_FlowOutAnnual[r, p, s_i, t, v, dem] + for s_i in model.processInputsByOutput[r, p, t, v, dem] ) expr = annual_activity * value(model.DemandSpecificDistribution[r, p, s, d, dem]) == activity @@ -358,33 +358,33 @@ def commodity_balance_constraint( # Only storage techs have a flow in variable # For other techs, it would be redundant as in = out / eff consumed += sum( - model.V_FlowIn[r, p, s, d, c, S_t, S_v, S_o] - for S_t, S_v in model.commodityDStreamProcess[r, p, c] - if S_t in model.tech_storage - for S_o in model.processOutputsByInput[r, p, S_t, S_v, c] + model.V_FlowIn[r, p, s, d, c, s_t, s_v, s_o] + for s_t, s_v in model.commodityDStreamProcess[r, p, c] + if s_t in model.tech_storage + for s_o in model.processOutputsByInput[r, p, s_t, s_v, c] ) # Into flows consumed += sum( - model.V_FlowOut[r, p, s, d, c, S_t, S_v, S_o] - / get_variable_efficiency(model, r, p, s, d, c, S_t, S_v, S_o) - for S_t, S_v in model.commodityDStreamProcess[r, p, c] - if S_t not in model.tech_storage and S_t not in model.tech_annual - for S_o in model.processOutputsByInput[r, p, S_t, S_v, c] + model.V_FlowOut[r, p, s, d, c, s_t, s_v, s_o] + / get_variable_efficiency(model, r, p, s, d, c, s_t, s_v, s_o) + for s_t, s_v in model.commodityDStreamProcess[r, p, c] + if s_t not in model.tech_storage and s_t not in model.tech_annual + for s_o in model.processOutputsByInput[r, p, s_t, s_v, c] ) # Into annual flows consumed += sum( ( - value(model.DemandSpecificDistribution[r, p, s, d, S_o]) - if S_o in model.commodity_demand + value(model.DemandSpecificDistribution[r, p, s, d, s_o]) + if s_o in model.commodity_demand else value(model.SegFrac[p, s, d]) ) - * model.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] - / get_variable_efficiency(model, r, p, s, d, c, S_t, S_v, S_o) - for S_t, S_v in model.commodityDStreamProcess[r, p, c] - if S_t in model.tech_annual - for S_o in model.processOutputsByInput[r, p, S_t, S_v, c] + * model.V_FlowOutAnnual[r, p, c, s_t, s_v, s_o] + / get_variable_efficiency(model, r, p, s, d, c, s_t, s_v, s_o) + for s_t, s_v in model.commodityDStreamProcess[r, p, c] + if s_t in model.tech_annual + for s_o in model.processOutputsByInput[r, p, s_t, s_v, c] ) if (r, p, c) in model.capacityConsumptionTechs: @@ -393,8 +393,8 @@ def commodity_balance_constraint( consumed += ( value(model.SegFrac[p, s, d]) * sum( - value(model.ConstructionInput[r, c, S_t, p]) * model.V_NewCapacity[r, S_t, p] - for S_t in model.capacityConsumptionTechs[r, p, c] + value(model.ConstructionInput[r, c, s_t, p]) * model.V_NewCapacity[r, s_t, p] + for s_t in model.capacityConsumptionTechs[r, p, c] ) / model.PeriodLength[p] ) @@ -402,72 +402,72 @@ def commodity_balance_constraint( if (r, p, c) in model.commodityUStreamProcess: # From flows including output from storage produced += sum( - model.V_FlowOut[r, p, s, d, S_i, S_t, S_v, c] - for S_t, S_v in model.commodityUStreamProcess[r, p, c] - if S_t not in model.tech_annual - for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] + model.V_FlowOut[r, p, s, d, s_i, s_t, s_v, c] + for s_t, s_v in model.commodityUStreamProcess[r, p, c] + if s_t not in model.tech_annual + for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] ) # From annual flows produced += value(model.SegFrac[p, s, d]) * sum( - model.V_FlowOutAnnual[r, p, S_i, S_t, S_v, c] - for S_t, S_v in model.commodityUStreamProcess[r, p, c] - if S_t in model.tech_annual - for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] + model.V_FlowOutAnnual[r, p, s_i, s_t, s_v, c] + for s_t, s_v in model.commodityUStreamProcess[r, p, c] + if s_t in model.tech_annual + for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] ) if c in model.commodity_flex: # Wasted by flex flows consumed += sum( - model.V_Flex[r, p, s, d, S_i, S_t, S_v, c] - for S_t, S_v in model.commodityUStreamProcess[r, p, c] - if S_t not in model.tech_annual and S_t in model.tech_flex - for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] + model.V_Flex[r, p, s, d, s_i, s_t, s_v, c] + for s_t, s_v in model.commodityUStreamProcess[r, p, c] + if s_t not in model.tech_annual and s_t in model.tech_flex + for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] ) # Wasted by annual flex flows consumed += value(model.SegFrac[p, s, d]) * sum( - model.V_FlexAnnual[r, p, S_i, S_t, S_v, c] - for S_t, S_v in model.commodityUStreamProcess[r, p, c] - if S_t in model.tech_annual and S_t in model.tech_flex - for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] + model.V_FlexAnnual[r, p, s_i, s_t, s_v, c] + for s_t, s_v in model.commodityUStreamProcess[r, p, c] + if s_t in model.tech_annual and s_t in model.tech_flex + for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] ) if (r, p, c) in model.retirementProductionProcesses: # Produced by retiring capacity # Assume evenly distributed over a year produced += value(model.SegFrac[p, s, d]) * sum( - value(model.EndOfLifeOutput[r, S_t, S_v, c]) * model.V_AnnualRetirement[r, p, S_t, S_v] - for S_t, S_v in model.retirementProductionProcesses[r, p, c] + value(model.EndOfLifeOutput[r, s_t, s_v, c]) * model.V_AnnualRetirement[r, p, s_t, s_v] + for s_t, s_v in model.retirementProductionProcesses[r, p, c] ) # export of commodity c from region r to other regions if (r, p, c) in model.exportRegions: consumed += sum( - model.V_FlowOut[r + '-' + reg, p, s, d, c, S_t, S_v, S_o] - / get_variable_efficiency(model, r + '-' + reg, p, s, d, c, S_t, S_v, S_o) - for reg, S_t, S_v, S_o in model.exportRegions[r, p, c] - if S_t not in model.tech_annual + model.V_FlowOut[r + '-' + reg, p, s, d, c, s_t, s_v, S_o] + / get_variable_efficiency(model, cast(Region, r + '-' + reg), p, s, d, c, s_t, s_v, S_o) + for reg, s_t, s_v, S_o in model.exportRegions[r, p, c] + if s_t not in model.tech_annual ) consumed += sum( value(model.SegFrac[p, s, d]) - * model.V_FlowOutAnnual[r + '-' + reg, p, c, S_t, S_v, S_o] - / get_variable_efficiency(model, r + '-' + reg, p, s, d, c, S_t, S_v, S_o) - for reg, S_t, S_v, S_o in model.exportRegions[r, p, c] - if S_t in model.tech_annual + * model.V_FlowOutAnnual[r + '-' + reg, p, c, s_t, s_v, S_o] + / get_variable_efficiency(model, cast(Region, r + '-' + reg), p, s, d, c, s_t, s_v, S_o) + for reg, s_t, s_v, S_o in model.exportRegions[r, p, c] + if s_t in model.tech_annual ) # import of commodity c from other regions into region r if (r, p, c) in model.importRegions: produced += sum( - model.V_FlowOut[reg + '-' + r, p, s, d, S_i, S_t, S_v, c] - for reg, S_t, S_v, S_i in model.importRegions[r, p, c] - if S_t not in model.tech_annual + model.V_FlowOut[reg + '-' + r, p, s, d, s_i, s_t, s_v, c] + for reg, s_t, s_v, s_i in model.importRegions[r, p, c] + if s_t not in model.tech_annual ) produced += sum( value(model.SegFrac[p, s, d]) - * model.V_FlowOutAnnual[reg + '-' + r, p, S_i, S_t, S_v, c] - for reg, S_t, S_v, S_i in model.importRegions[r, p, c] - if S_t in model.tech_annual + * model.V_FlowOutAnnual[reg + '-' + r, p, s_i, s_t, s_v, c] + for reg, s_t, s_v, s_i in model.importRegions[r, p, c] + if s_t in model.tech_annual ) commodity_balance_constraint_error_check( @@ -504,30 +504,30 @@ def annual_commodity_balance_constraint( # Only storage techs have a flow in variable # For other techs, it would be redundant as in = out / eff consumed += sum( - model.V_FlowIn[r, p, S_s, S_d, c, S_t, S_v, S_o] - for S_s in model.TimeSeason[p] - for S_d in model.time_of_day - for S_t, S_v in model.commodityDStreamProcess[r, p, c] - if S_t in model.tech_storage - for S_o in model.processOutputsByInput[r, p, S_t, S_v, c] + model.V_FlowIn[r, p, s_s, s_d, c, s_t, s_v, s_o] + for s_s in model.TimeSeason[p] + for s_d in model.time_of_day + for s_t, s_v in model.commodityDStreamProcess[r, p, c] + if s_t in model.tech_storage + for s_o in model.processOutputsByInput[r, p, s_t, s_v, c] ) consumed += sum( - model.V_FlowOut[r, p, S_s, S_d, c, S_t, S_v, S_o] - / get_variable_efficiency(model, r, p, S_s, S_d, c, S_t, S_v, S_o) - for S_s in model.TimeSeason[p] - for S_d in model.time_of_day - for S_t, S_v in model.commodityDStreamProcess[r, p, c] - if S_t not in model.tech_storage and S_t not in model.tech_annual - for S_o in model.processOutputsByInput[r, p, S_t, S_v, c] + model.V_FlowOut[r, p, s_s, s_d, c, s_t, s_v, s_o] + / get_variable_efficiency(model, r, p, s_s, s_d, c, s_t, s_v, s_o) + for s_s in model.TimeSeason[p] + for s_d in model.time_of_day + for s_t, s_v in model.commodityDStreamProcess[r, p, c] + if s_t not in model.tech_storage and s_t not in model.tech_annual + for s_o in model.processOutputsByInput[r, p, s_t, s_v, c] ) consumed += sum( - model.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] - / value(model.Efficiency[r, c, S_t, S_v, S_o]) - for S_t, S_v in model.commodityDStreamProcess[r, p, c] - if S_t in model.tech_annual - for S_o in model.processOutputsByInput[r, p, S_t, S_v, c] + model.V_FlowOutAnnual[r, p, c, s_t, s_v, s_o] + / value(model.Efficiency[r, c, s_t, s_v, s_o]) + for s_t, s_v in model.commodityDStreamProcess[r, p, c] + if s_t in model.tech_annual + for s_o in model.processOutputsByInput[r, p, s_t, s_v, c] ) if (r, p, c) in model.capacityConsumptionTechs: @@ -535,8 +535,8 @@ def annual_commodity_balance_constraint( # Assume evenly distributed over a year consumed += ( sum( - value(model.ConstructionInput[r, c, S_t, p]) * model.V_NewCapacity[r, S_t, p] - for S_t in model.capacityConsumptionTechs[r, p, c] + value(model.ConstructionInput[r, c, s_t, p]) * model.V_NewCapacity[r, s_t, p] + for s_t in model.capacityConsumptionTechs[r, p, c] ) / model.PeriodLength[p] ) @@ -544,75 +544,77 @@ def annual_commodity_balance_constraint( if (r, p, c) in model.commodityUStreamProcess: # Includes output from storage produced += sum( - model.V_FlowOut[r, p, S_s, S_d, S_i, S_t, S_v, c] - for S_s in model.TimeSeason[p] - for S_d in model.time_of_day - for S_t, S_v in model.commodityUStreamProcess[r, p, c] - if S_t not in model.tech_annual - for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] + model.V_FlowOut[r, p, s_s, s_d, s_i, s_t, s_v, c] + for s_s in model.TimeSeason[p] + for s_d in model.time_of_day + for s_t, s_v in model.commodityUStreamProcess[r, p, c] + if s_t not in model.tech_annual + for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] ) produced += sum( - model.V_FlowOutAnnual[r, p, S_i, S_t, S_v, c] - for S_t, S_v in model.commodityUStreamProcess[r, p, c] - if S_t in model.tech_annual - for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] + model.V_FlowOutAnnual[r, p, s_i, s_t, s_v, c] + for s_t, s_v in model.commodityUStreamProcess[r, p, c] + if s_t in model.tech_annual + for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] ) if c in model.commodity_flex: consumed += sum( - model.V_Flex[r, p, S_s, S_d, S_i, S_t, S_v, c] - for S_s in model.TimeSeason[p] - for S_d in model.time_of_day - for S_t, S_v in model.commodityUStreamProcess[r, p, c] - if S_t not in model.tech_annual and S_t in model.tech_flex - for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] + model.V_Flex[r, p, s_s, s_d, s_i, s_t, s_v, c] + for s_s in model.TimeSeason[p] + for s_d in model.time_of_day + for s_t, s_v in model.commodityUStreamProcess[r, p, c] + if s_t not in model.tech_annual and s_t in model.tech_flex + for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] ) consumed += sum( - model.V_FlexAnnual[r, p, S_i, S_t, S_v, c] - for S_t, S_v in model.commodityUStreamProcess[r, p, c] - if S_t in model.tech_flex and S_t in model.tech_annual - for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] + model.V_FlexAnnual[r, p, s_i, s_t, s_v, c] + for s_t, s_v in model.commodityUStreamProcess[r, p, c] + if s_t in model.tech_flex and s_t in model.tech_annual + for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] ) if (r, p, c) in model.retirementProductionProcesses: # Produced by retiring capacity # Assume evenly distributed over a year produced += sum( - value(model.EndOfLifeOutput[r, S_t, S_v, c]) * model.V_AnnualRetirement[r, p, S_t, S_v] - for S_t, S_v in model.retirementProductionProcesses[r, p, c] + value(model.EndOfLifeOutput[r, s_t, s_v, c]) * model.V_AnnualRetirement[r, p, s_t, s_v] + for s_t, s_v in model.retirementProductionProcesses[r, p, c] ) # export of commodity c from region r to other regions if (r, p, c) in model.exportRegions: consumed += sum( - model.V_FlowOut[r + '-' + S_r, p, S_s, S_d, c, S_t, S_v, S_o] - / get_variable_efficiency(model, r + '-' + S_r, p, S_s, S_d, c, S_t, S_v, S_o) - for S_s in model.TimeSeason[p] - for S_d in model.time_of_day - for S_r, S_t, S_v, S_o in model.exportRegions[r, p, c] - if S_t not in model.tech_annual + model.V_FlowOut[cast(Region, r + '-' + s_r), p, s_s, s_d, c, s_t, s_v, s_o] + / get_variable_efficiency( + model, cast(Region, r + '-' + s_r), p, s_s, s_d, c, s_t, s_v, s_o + ) + for s_s in model.TimeSeason[p] + for s_d in model.time_of_day + for s_r, s_t, s_v, s_o in model.exportRegions[r, p, c] + if s_t not in model.tech_annual ) consumed += sum( - model.V_FlowOutAnnual[r + '-' + S_r, p, c, S_t, S_v, S_o] - / model.Efficiency[r + '-' + S_r, c, S_t, S_v, S_o] - for S_r, S_t, S_v, S_o in model.exportRegions[r, p, c] - if S_t in model.tech_annual + model.V_FlowOutAnnual[cast(Region, r + '-' + s_r), p, c, s_t, s_v, s_o] + / model.Efficiency[cast(Region, r + '-' + s_r), c, s_t, s_v, s_o] + for s_r, s_t, s_v, s_o in model.exportRegions[r, p, c] + if s_t in model.tech_annual ) # import of commodity c from other regions into region r if (r, p, c) in model.importRegions: produced += sum( - model.V_FlowOut[S_r + '-' + r, p, S_s, S_d, S_i, S_t, S_v, c] - for S_s in model.TimeSeason[p] + model.V_FlowOut[cast(Region, s_r + '-' + r), p, s_s, S_d, s_i, s_t, s_v, c] + for s_s in model.TimeSeason[p] for S_d in model.time_of_day - for S_r, S_t, S_v, S_i in model.importRegions[r, p, c] - if S_t not in model.tech_annual + for s_r, s_t, s_v, s_i in model.importRegions[r, p, c] + if s_t not in model.tech_annual ) produced += sum( - model.V_FlowOutAnnual[S_r + '-' + r, p, S_i, S_t, S_v, c] - for S_r, S_t, S_v, S_i in model.importRegions[r, p, c] - if S_t in model.tech_annual + model.V_FlowOutAnnual[cast(Region, s_r + '-' + r), p, s_i, s_t, s_v, c] + for s_r, s_t, s_v, s_i in model.importRegions[r, p, c] + if s_t in model.tech_annual ) annual_commodity_balance_constraint_error_check( diff --git a/temoa/components/costs.py b/temoa/components/costs.py index 7ab7ccbb7..4ea4aeacc 100644 --- a/temoa/components/costs.py +++ b/temoa/components/costs.py @@ -40,7 +40,7 @@ def get_default_loan_rate(model: TemoaModel, *_: Any) -> float: return value(model.DefaultLoanRate) -def annuity_to_pv(rate: float, periods: int) -> float | Expression: +def annuity_to_pv(rate: float, periods: float) -> float | Expression: r""" Multiplication factor to convert an annuity to net present value @@ -59,7 +59,7 @@ def annuity_to_pv(rate: float, periods: int) -> float | Expression: return ((1 + rate) ** periods - 1) / (rate * (1 + rate) ** periods) -def pv_to_annuity(rate: float, periods: int) -> float | Expression: +def pv_to_annuity(rate: float, periods: float) -> float | Expression: r""" Multiplication factor to convert net present value to an annuity @@ -73,7 +73,7 @@ def pv_to_annuity(rate: float, periods: int) -> float | Expression: return (rate * (1 + rate) ** periods) / ((1 + rate) ** periods - 1) -def fv_to_pv(rate: float, periods: int) -> float | Expression: +def fv_to_pv(rate: float, periods: float) -> float | Expression: r""" Multiplication factor to convert a future value to net present value @@ -135,7 +135,7 @@ def loan_cost( invest_cost: float, loan_annualize: float, lifetime_loan_process: float | int, - lifetime_process: int, + lifetime_process: float, p_0: int, p_e: int, global_discount_rate: float, @@ -194,15 +194,15 @@ def loan_cost( def loan_cost_survival_curve( model: TemoaModel, - r: str, - t: str, - v: int, + r: Region, + t: Technology, + v: Vintage, capacity: float | Var | ComponentData, invest_cost: float, loan_annualize: float, lifetime_loan_process: float | int, - p_0: int, - p_e: int, + p_0: Period, + p_e: Period, global_discount_rate: float, ) -> float | Expression: """ diff --git a/temoa/components/geography.py b/temoa/components/geography.py index 63280032e..065c7c662 100644 --- a/temoa/components/geography.py +++ b/temoa/components/geography.py @@ -14,7 +14,7 @@ from collections.abc import Iterable from logging import getLogger -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, cast from deprecated import deprecated from pyomo.environ import value @@ -37,7 +37,7 @@ def gather_group_regions(model: TemoaModel, region: Region) -> Iterable[Region]: if region == 'global': regions = list(model.regions) elif '+' in region: - regions = region.split('+') + regions = [cast(Region, r) for r in region.split('+')] else: regions = [region] return regions @@ -59,7 +59,7 @@ def create_regional_indices(model: TemoaModel) -> list[Region]: if r_i == r_j: regional_indices.add(r_i) else: - regional_indices.add(r_i + '-' + r_j) + regional_indices.add(cast(Region, r_i + '-' + r_j)) # dev note: Sorting these passed them to pyomo in an ordered container and prevents warnings return sorted(regional_indices) @@ -72,8 +72,8 @@ def regional_global_initialized_indices(model: TemoaModel) -> set[Region]: for n in range(1, len(model.regions) + 1): regional_perms = permutations(model.regions, n) for i in regional_perms: - indices.add('+'.join(i)) - indices.add('global') + indices.add(cast(Region, '+'.join(i))) + indices.add(cast(Region, 'global')) indices = indices.union(model.regionalIndices) return indices @@ -137,7 +137,9 @@ def create_geography_sets(model: TemoaModel) -> None: logger.error(msg) raise ValueError(msg) - region_from, region_to = r.split('-', 1) + region_from_str, region_to_str = r.split('-', 1) + region_from = cast(Region, region_from_str) + region_to = cast(Region, region_to_str) lifetime: float = value(model.LifetimeProcess[r, t, v]) for p in model.time_optimize: diff --git a/temoa/components/limits.py b/temoa/components/limits.py index 009a7b3ec..e6651ef6c 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -292,7 +292,7 @@ def limit_resource_constraint(model: TemoaModel, r: Region, t: Technology, op: s def limit_activity_share_constraint( - model: TemoaModel, r: Region, p: Period, g1: str, g2: str, op: str + model: TemoaModel, r: Region, p: Period, g1: Technology, g2: Technology, op: str ) -> ExprLike: r""" Limits the activity of a given technology or group as a fraction of another @@ -372,7 +372,7 @@ def limit_activity_share_constraint( def limit_capacity_share_constraint( - model: TemoaModel, r: Region, p: Period, g1: str, g2: str, op: str + model: TemoaModel, r: Region, p: Period, g1: Technology, g2: Technology, op: str ) -> ExprLike: r""" The LimitCapacityShare constraint limits the available capacity of a given @@ -405,7 +405,7 @@ def limit_capacity_share_constraint( def limit_new_capacity_share_constraint( - model: TemoaModel, r: Region, p: Period, g1: str, g2: str, op: str + model: TemoaModel, r: Region, p: Period, g1: Technology, g2: Technology, op: str ) -> ExprLike: r""" The LimitNewCapacityShare constraint limits the share of new capacity diff --git a/temoa/components/storage.py b/temoa/components/storage.py index 88f9a3471..28ec5e27d 100644 --- a/temoa/components/storage.py +++ b/temoa/components/storage.py @@ -124,7 +124,7 @@ def storage_energy_constraint( def seasonal_storage_energy_constraint( - model: TemoaModel, r: Region, p: Period, s_seq: str, t: Technology, v: Vintage + model: TemoaModel, r: Region, p: Period, s_seq: Season, t: Technology, v: Vintage ) -> ExprLike: r""" This constraint enforces the continuity of state of charge between seasons for seasonal @@ -184,7 +184,7 @@ def seasonal_storage_energy_constraint( for S_i in model.processInputsByOutput[r, p, t, v, S_o] ) - s_seq_next: str = model.time_next_sequential[p, s_seq] + s_seq_next: Season = model.time_next_sequential[p, s_seq] s_next: Season = model.sequential_to_season[p, s_seq_next] # Flows and StorageLevel are normalised to the number of days in the non-sequential season, so must @@ -272,7 +272,7 @@ def storage_energy_upper_bound_constraint( def seasonal_storage_energy_upper_bound_constraint( - model: TemoaModel, r: Region, p: Period, s_seq: str, d: TimeOfDay, t: Technology, v: Vintage + model: TemoaModel, r: Region, p: Period, s_seq: Season, d: TimeOfDay, t: Technology, v: Vintage ) -> ExprLike: r""" Builds off of StorageEnergyUpperBound_Constraint. Enforces the max charge capacity @@ -516,7 +516,7 @@ def limit_storage_fraction_constraint( ) if model.isSeasonalStorage[t]: - s_seq: str = s # sequential season + s_seq: Season = s # sequential season s = model.sequential_to_season[p, s_seq] # non-sequential season # adjust the storage level to the individual-day level diff --git a/temoa/components/technology.py b/temoa/components/technology.py index 26a1778f9..42f55dc86 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -14,7 +14,7 @@ from collections.abc import Iterable from logging import getLogger -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, cast from pyomo.environ import value @@ -29,11 +29,11 @@ # ============================================================================ -def gather_group_techs(model: TemoaModel, t_or_g: str) -> Iterable[str]: +def gather_group_techs(model: TemoaModel, t_or_g: Technology) -> Iterable[Technology]: if t_or_g in model.tech_group_names: return model.tech_group_members[t_or_g] elif '+' in t_or_g: - return t_or_g.split('+') + return [cast(Technology, tech) for tech in t_or_g.split('+')] else: return (t_or_g,) @@ -253,7 +253,7 @@ def create_survival_curve(model: TemoaModel) -> None: if periods_rtv != list(range(p_first, p_last + 1, 1)): rtv_interpolated.add((r, t, v)) - between_periods = [] + between_periods: list[Period] = [] for i, p in enumerate(periods_rtv): if i == 0: continue # Cant look back from first period. Could be zero but hey why not @@ -271,7 +271,7 @@ def create_survival_curve(model: TemoaModel) -> None: raise ValueError(msg) if p - p_prev > 1: - _between_periods = list(range(p_prev + 1, p, 1)) + _between_periods = [cast(Period, _p) for _p in range(p_prev + 1, p, 1)] for _p in _between_periods: x = (_p - p_prev) / (p - p_prev) lsc_x = lsc_prev + x * (lsc - lsc_prev) diff --git a/temoa/components/time.py b/temoa/components/time.py index 98fff362c..9558dd70c 100644 --- a/temoa/components/time.py +++ b/temoa/components/time.py @@ -234,9 +234,9 @@ def loop_period_next_timeslice( def loop_season_next_timeslice( model: TemoaModel, p: Period, s: Season, d: TimeOfDay -) -> tuple[str, str]: +) -> tuple[Season, TimeOfDay]: # We loop each season so never carrying state between seasons - s_next: str = s + s_next: Season = s # Final time slice of any season # Loop state back to initial state of same season @@ -296,7 +296,7 @@ def create_time_sequence(model: TemoaModel) -> None: # Superimposed sequential seasons for p in model.time_optimize: - seasons: list[tuple[str, str]] = [ + seasons: list[tuple[Season, Season]] = [ (s_seq, s) for _p, s_seq, s in model.ordered_season_sequential if _p == p ] for i, (s_seq, s) in enumerate(seasons): diff --git a/temoa/types/core_types.py b/temoa/types/core_types.py index d0e8c19ae..12b0634ea 100644 --- a/temoa/types/core_types.py +++ b/temoa/types/core_types.py @@ -7,20 +7,20 @@ from collections.abc import Callable from dataclasses import dataclass, field -from typing import Any +from typing import Any, NewType # Core type aliases for commonly used dimensions -Region = str -Period = int -Technology = str -Sector = str -Vintage = int -Season = str -TimeOfDay = str -Commodity = str -InputCommodity = str -OutputCommodity = str -Process = str +Region = NewType('Region', str) +Period = NewType('Period', int) +Technology = NewType('Technology', str) +Sector = NewType('Sector', str) +Vintage = NewType('Vintage', int) +Season = NewType('Season', str) +TimeOfDay = NewType('TimeOfDay', str) +Commodity = NewType('Commodity', str) +InputCommodity = NewType('InputCommodity', Commodity) +OutputCommodity = NewType('OutputCommodity', Commodity) +Process = NewType('Process', str) # Type aliases for common data structures SparseIndex = ( diff --git a/temoa/types/dict_types.py b/temoa/types/dict_types.py index 8fb2fb3da..5a0f7c667 100644 --- a/temoa/types/dict_types.py +++ b/temoa/types/dict_types.py @@ -19,7 +19,7 @@ ] ProcessTechsDict = dict[tuple[Region, Period, Commodity], set[Technology]] ProcessReservePeriodsDict = dict[tuple[Region, Period], set[tuple[Technology, Vintage]]] -ProcessPeriodsDict = dict[tuple[Region, Technology, Vintage], set[Period]] +ProcessPeriodsDict = dict[tuple[Region, Technology, Period], set[Period]] RetirementPeriodsDict = dict[tuple[Region, Technology, Vintage], set[Period]] ProcessVintagesDict = dict[tuple[Region, Period, Technology], set[Vintage]] SurvivalCurvePeriodsDict = dict[tuple[Region, Technology, Vintage], set[Period]] From 5698798c5b2aef71cbc413b3d51e917dadc3f2b0 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 31 Oct 2025 15:14:54 -0400 Subject: [PATCH 299/587] further refining typing and adding more directories to type checking --- pyproject.toml | 2 +- temoa/model_checking/commodity_graph.py | 17 ++++----- .../commodity_network_manager.py | 2 +- temoa/model_checking/network_model_data.py | 13 ++++--- temoa/types/__init__.py | 2 ++ temoa/utilities/graph_utils.py | 13 +++++-- temoa/utilities/visualizer.py | 36 ++++++++++--------- 7 files changed, 50 insertions(+), 35 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e2cba8a5b..f1a14c526 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -109,7 +109,7 @@ python_version = "3.12" mypy_path = "stubs" # Exclude specific directories from type checking will try to add them back gradually -exclude = "(?x)(^tests/|^temoa/data_processing/|^temoa/extensions/|^temoa/utilities/|^docs/)" +exclude = "(?x)(^tests/|^temoa/extensions/|^docs/)" # Strict typing for our own code disallow_untyped_defs = true diff --git a/temoa/model_checking/commodity_graph.py b/temoa/model_checking/commodity_graph.py index 5b3aeb22f..80845812e 100644 --- a/temoa/model_checking/commodity_graph.py +++ b/temoa/model_checking/commodity_graph.py @@ -9,7 +9,7 @@ from temoa.core.config import TemoaConfig from temoa.model_checking.network_model_data import EdgeTuple, NetworkModelData -from temoa.types.core_types import Period, Region +from temoa.types.core_types import Commodity, Period, Region, Sector, Technology from temoa.utilities.graph_utils import ( calculate_initial_positions, calculate_tech_graph_positions, @@ -21,8 +21,8 @@ def generate_technology_graph( all_edges: Iterable[EdgeTuple], - source_commodities: set[str], - demand_commodities: set[str], + source_commodities: set[Commodity], + demand_commodities: set[Commodity], sector_colors: dict[str, str], ) -> nx.MultiDiGraph[str]: """ @@ -170,17 +170,18 @@ def generate_commodity_graph( # 3. Prepare edge attributes with sector-based coloring edge_attributes_map: dict[tuple[str, str, str, str | None], dict[str, Any]] = {} - all_connections: set[tuple[str, str, str, str | None]] = { - (tech.input_comm, tech.tech, tech.output_comm, tech.sector) for tech in all_edge_tuples + all_connections: set[tuple[Commodity, Technology, Commodity, Sector | None]] = { + (edge_tuple.input_comm, edge_tuple.tech, edge_tuple.output_comm, edge_tuple.sector) + for edge_tuple in all_edge_tuples } driven_names = {t.tech for t in driven_techs} other_orphan_names = {t.tech for t in other_orphans} demand_orphan_names = {t.tech for t in demand_orphans} - driven_commodities: set[str] = set() - other_orphan_commodities: set[str] = set() - demand_orphan_commodities: set[str] = set() + driven_commodities: set[Commodity] = set() + other_orphan_commodities: set[Commodity] = set() + demand_orphan_commodities: set[Commodity] = set() for ic, tech_name, oc, sector in all_connections: key = (ic, tech_name, oc, sector) diff --git a/temoa/model_checking/commodity_network_manager.py b/temoa/model_checking/commodity_network_manager.py index 6253ddd69..61f6486a8 100644 --- a/temoa/model_checking/commodity_network_manager.py +++ b/temoa/model_checking/commodity_network_manager.py @@ -34,7 +34,7 @@ class CommodityNetworkManager: def __init__(self, periods: Iterable[str | int], network_data: NetworkModelData) -> None: self.analyzed: bool = False - self.periods: list[int] = sorted(map(int, periods)) + self.periods: list[Period] = sorted(map(int, periods)) self.orig_data: NetworkModelData = network_data self.filtered_data: NetworkModelData | None = None self.regions: set[Region] | None = None diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index fd8242979..3b4532cac 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -13,14 +13,14 @@ from collections.abc import Callable from dataclasses import dataclass, field from itertools import chain -from typing import NamedTuple, Self, TypedDict, overload +from typing import NamedTuple, Self, TypedDict, cast, overload import deprecated from pyomo.core.base import ConcreteModel from temoa.core.model import TemoaModel from temoa.extensions.myopic.myopic_index import MyopicIndex -from temoa.types import Commodity, Period, Region, Technology, Vintage +from temoa.types import Commodity, Period, Region, Sector, Technology, Vintage from temoa.types.core_types import ParameterValue @@ -32,7 +32,7 @@ class EdgeTuple(NamedTuple): vintage: Vintage output_comm: Commodity lifetime: int | None = None - sector: str | None = None + sector: Sector | None = None class LinkedTechTuple(NamedTuple): @@ -359,8 +359,11 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - living_techs.add(tech) if '-' in r and r.count('-') == 1: # Inter-regional transfer - r1, r2 = r.split('-', 1) - source_comm, dest_comm = f'{ic} ({r1})', f'{oc} ({r2})' + r1, r2 = (cast(Region, reg) for reg in r.split('-', 1)) + source_comm, dest_comm = ( + cast(Commodity, f'{ic} ({r1})'), + cast(Commodity, f'{oc} ({r2})'), + ) res.available_techs[r2, p].add( EdgeTuple( region=r2, diff --git a/temoa/types/__init__.py b/temoa/types/__init__.py index 8ecfc80c5..6241d6a41 100644 --- a/temoa/types/__init__.py +++ b/temoa/types/__init__.py @@ -16,6 +16,7 @@ 'TechSet', 'TimeOfDay', 'Vintage', + 'Sector', # Dictionary types 'ActiveRegionsForTechDict', 'BaseloadVintagesDict', @@ -81,6 +82,7 @@ Region, RegionSet, Season, + Sector, SparseIndex, Technology, TechSet, diff --git a/temoa/utilities/graph_utils.py b/temoa/utilities/graph_utils.py index 37ec3718a..756e7e24f 100644 --- a/temoa/utilities/graph_utils.py +++ b/temoa/utilities/graph_utils.py @@ -18,10 +18,17 @@ import networkx as nx from temoa.model_checking.network_model_data import EdgeTuple +from temoa.types.core_types import Commodity, Technology logger = logging.getLogger(__name__) -GraphType = TypeVar('GraphType', nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph) +GraphType = TypeVar( + 'GraphType', + nx.Graph[Commodity | Technology | str], + nx.DiGraph[Commodity | Technology | str], + nx.MultiGraph[Commodity | Technology | str], + nx.MultiDiGraph[Commodity | Technology | str], +) def convert_graph_to_json( @@ -140,7 +147,7 @@ def calculate_initial_positions( - Other nodes are arranged in clusters based on their primary sector, with the clusters themselves arranged in a large circle. """ - positions = {} + positions: dict[str, dict[str, Any]] = {} # Prepare to lay out the remaining (non-fixed) nodes: all layers except 1 nodes_to_place = {n for n, layer in node_layer_map.items() if layer != 1} @@ -194,7 +201,7 @@ def calculate_initial_positions( def calculate_tech_graph_positions( all_edges: Iterable[EdgeTuple], -) -> dict[str, dict[str, Any]]: +) -> dict[Technology, dict[str, Any]]: """ Calculates an initial (x, y) layout for the technology graph. All technologies are arranged in clusters by sector, with clusters diff --git a/temoa/utilities/visualizer.py b/temoa/utilities/visualizer.py index 04da87dce..2ea4761dd 100644 --- a/temoa/utilities/visualizer.py +++ b/temoa/utilities/visualizer.py @@ -21,6 +21,7 @@ import networkx as nx +from temoa.types.core_types import Commodity, Sector, Technology from temoa.utilities.graph_utils import ( GraphType, convert_graph_to_json, @@ -41,23 +42,23 @@ def deep_merge_dicts(source: dict[str, Any], destination: dict[str, Any]) -> dic def make_nx_graph( - connections: Iterable[tuple[str, str, str, str | None]], - edge_attributes_map: dict[tuple, dict[str, Any]], + connections: Iterable[tuple[Commodity, Technology, Commodity, Sector | None]], + edge_attributes_map: dict[tuple[str, str, str, str | None], dict[str, Any]], node_layer_map: dict[str, int], node_positions: dict[str, dict[str, Any]], - commodity_to_primary_sector: dict[str, str], - driven_tech_names: set[str], - other_orphan_names: set[str], - demand_orphan_names: set[str], - driven_commodities: set[str], - other_orphan_commodities: set[str], - demand_orphan_commodities: set[str], -) -> nx.MultiDiGraph: + commodity_to_primary_sector: dict[Commodity, Sector], + driven_tech_names: set[Technology], + other_orphan_names: set[Commodity], + demand_orphan_names: set[Commodity], + driven_commodities: set[Commodity], + other_orphan_commodities: set[Commodity], + demand_orphan_commodities: set[Commodity], +) -> nx.MultiDiGraph[str]: """ Make an nx graph, grouping parallel edges to prevent label overlap. """ - dg = nx.MultiDiGraph() + dg: nx.MultiDiGraph[str] = nx.MultiDiGraph() connections = tuple(connections) # Freeze for multiple iterations node_styles_by_layer = { @@ -125,7 +126,7 @@ def make_nx_graph( dg.add_node(node_name, **node_attrs) # 2. Group technologies by their input/output commodity pair - grouped_edges = defaultdict(list) + grouped_edges: dict[tuple[Commodity, Commodity], list[dict[str, Any]]] = defaultdict(list) for ic, tech, oc, sector in connections: edge_key = (ic, tech, oc, sector) attrs = edge_attributes_map.get(edge_key, {}) @@ -133,7 +134,7 @@ def make_nx_graph( # 3. Create a single, combined edge for each group for (ic, oc), techs_info in grouped_edges.items(): - combined_attrs = {} + combined_attrs: dict[str, Any] = {} tech_names = [info['tech'] for info in techs_info] # Combine labels: Show up to 2 names, then "X techs" @@ -175,15 +176,15 @@ def make_nx_graph( combined_attrs['dashes'] = True combined_attrs['value'] = sum(info['attrs'].get('value', 1) for info in techs_info) - edge_key = f'{ic}-{oc}-{uuid.uuid4().hex[:8]}' - dg.add_edge(ic, oc, key=edge_key, **combined_attrs) + multi_edge_key = f'{ic}-{oc}-{uuid.uuid4().hex[:8]}' + dg.add_edge(ic, oc, key=multi_edge_key, **combined_attrs) return dg def nx_to_vis( nx_graph: GraphType, - output_filename: Path, # Changed to Path object for clarity + output_filename: Path, html_title: str = 'NetworkX to vis.js Graph', vis_options: dict[str, Any] | None = None, override_node_properties: dict[str, Any] | None = None, @@ -203,7 +204,8 @@ def nx_to_vis( nodes_data_primary, edges_data_primary = convert_graph_to_json( nx_graph, override_node_properties, override_edge_properties, 0 ) - nodes_data_secondary, edges_data_secondary = [], [] + nodes_data_secondary: list[dict[str, Any]] = [] + edges_data_secondary: list[dict[str, Any]] = [] if secondary_graph: nodes_data_secondary, edges_data_secondary = convert_graph_to_json( secondary_graph, override_node_properties, override_edge_properties, 0 From bd7f36483b3877fd7bcadac63ccc064fed0eb71c Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 31 Oct 2025 16:04:47 -0400 Subject: [PATCH 300/587] adding typing for data_processing --- temoa/data_processing/database_util.py | 472 +++++++++------------ temoa/data_processing/db_query.py | 89 ++-- temoa/data_processing/graphviz_util.py | 116 ++--- temoa/data_processing/make_graphviz.py | 321 +++++++------- temoa/data_processing/make_output_plots.py | 411 +++++++++--------- temoa/model_checking/network_model_data.py | 2 +- 6 files changed, 688 insertions(+), 723 deletions(-) diff --git a/temoa/data_processing/database_util.py b/temoa/data_processing/database_util.py index 0fe8a6496..6a1fb1280 100644 --- a/temoa/data_processing/database_util.py +++ b/temoa/data_processing/database_util.py @@ -10,6 +10,7 @@ import os import re import sqlite3 +from os import PathLike import deprecated import pandas as pd @@ -24,14 +25,19 @@ class DatabaseUtil: manager to ensure database connections are closed properly. Args: - database_path (str or Path): The file path to the SQLite database. - scenario (Optional[str]): The specific scenario to query within the database. + database_path: The file path to the SQLite database. + scenario: The specific scenario to query within the database. Raises: ValueError: If the database path does not exist or if connecting fails. """ - def __init__(self, database_path, scenario=None): + database: str + scenario: str | None + con: sqlite3.Connection + cur: sqlite3.Cursor + + def __init__(self, database_path: str | PathLike[str], scenario: str | None = None) -> None: self.database = os.path.abspath(database_path) self.scenario = scenario if not os.path.exists(self.database): @@ -41,361 +47,284 @@ def __init__(self, database_path, scenario=None): try: self.con = sqlite3.connect(self.database) self.cur = self.con.cursor() - self.con.text_factory = ( - str # this ensures data is explored with the correct UTF-8 encoding - ) + self.con.text_factory = str except sqlite3.Error as e: raise ValueError(f'Unable to connect to database: {e}') from e elif self.database.endswith('.dat'): raise ValueError('Reading .dat files is no longer supported') - def close(self): + def close(self) -> None: + """Closes the database cursor and connection.""" if self.cur: self.cur.close() if self.con: self.con.close() @staticmethod - def is_database_file(file): - if file.endswith('.db') or file.endswith('.sqlite') or file.endswith('.sqlite3'): - return True - else: - return False - - @deprecated.deprecated('reading from .dat files no longer supported') - def read_from_dat_file(self, inp_comm, inp_tech): - if self.cur is not None: + def is_database_file(file: str | PathLike[str]) -> bool: + """Checks if a file has a common SQLite database extension.""" + return str(file).endswith(('.db', '.sqlite', '.sqlite3')) + + @deprecated.deprecated(version='0.9.0', reason='Reading from .dat files is no longer supported') + def read_from_dat_file(self, inp_comm: str | None, inp_tech: str | None) -> pd.DataFrame: + """ + This method is deprecated and will raise a ValueError if called on a + database connection. + """ + # This check ensures the method is unreachable with a valid DB connection. + if hasattr(self, 'cur') and self.cur is not None: raise ValueError('Invalid Operation For Database file') - if inp_comm is None and inp_tech is None: - inp_comm = r'\w+' - inp_tech = r'\w+' - else: - if inp_comm is None: - inp_comm = r'\W+' - if inp_tech is None: - inp_tech = r'\W+' - test2 = [] + # The following code is unreachable in the current design but is kept + # to document the deprecated functionality. + inp_comm_re = inp_comm if inp_comm is not None else r'\w+' + inp_tech_re = inp_tech if inp_tech is not None else r'\w+' + + rows: list[tuple[str, ...]] = [] eff_flag = False - with open(self.database) as f: + with open(self.database, encoding='utf-8') as f: for line in f: - if eff_flag is False and re.search( - r'^\s*param\s+efficiency\s*[:][=]', line, flags=re.I - ): - # Search for the line param Efficiency := (The script recognizes the commodities specified in this section) + if not eff_flag and re.search(r'^\s*param\s+efficiency\s*[:][=]', line, re.I): eff_flag = True elif eff_flag: line = re.sub(r'[#].*$', ' ', line) if re.search(r'^\s*;\s*$', line): - break # Finish searching this section when encounter a ';' + break if re.search(r'^\s+$', line): continue - line = re.sub(r'^\s+|\s+$', '', line) - row = re.split(r'\s+', line) + line = line.strip() + row_parts = tuple(re.split(r'\s+', line)) if ( - not re.search(inp_comm, row[0]) - and not re.search(inp_comm, row[3]) - and not re.search(inp_tech, row[1]) + len(row_parts) >= 4 + and not re.search(inp_comm_re, row_parts[0]) + and not re.search(inp_comm_re, row_parts[3]) + and not re.search(inp_tech_re, row_parts[1]) ): continue + rows.append(row_parts) - test2.append(tuple(row)) - - result = pd.DataFrame( - test2, columns=['input_comm', 'tech', 'period', 'output_comm', 'flow'] - ) + result = pd.DataFrame(rows, columns=['input_comm', 'tech', 'period', 'output_comm', 'flow']) return result[['input_comm', 'tech', 'output_comm']] - def get_time_peridos_for_flags(self, flags=None): - if self.cur is None: - raise ValueError('Invalid Operation For dat file') - query = '' + def get_time_peridos_for_flags(self, flags: list[str] | None = None) -> set[int]: + """Retrieves a set of time periods, optionally filtered by flags.""" if (flags is None) or (not flags): query = 'SELECT period FROM TimePeriod' else: - flag = flags[0] - query = "SELECT period FROM TimePeriod WHERE flag is '" + flag + "'" - for i in range(1, len(flags)): - query += " OR flag is '" + flags[i] + "'" + in_clause = ', '.join(f"'{flag}'" for flag in flags) + query = f'SELECT period FROM TimePeriod WHERE flag IN ({in_clause})' self.cur.execute(query) - result = set() - for row in self.cur: - result.add(int(row[0])) + return {int(row[0]) for row in self.cur} - return result - - def get_technologies_for_flags(self, flags=None): - if self.cur is None: - raise ValueError('Invalid Operation For dat file') - query = '' + def get_technologies_for_flags(self, flags: list[str] | None = None) -> set[str]: + """Retrieves a set of technologies, optionally filtered by flags.""" if (flags is None) or (not flags): query = 'SELECT tech FROM Technology' else: - flag = flags[0] - query = "SELECT tech FROM Technology WHERE flag='" + flag + "'" - for i in range(1, len(flags)): - query += " OR flag='" + flags[i] + "'" - - result = set() - for row in self.cur.execute(query): - result.add(row[0]) - - return result - - # TODO: Merge this with next function (getExistingTechnologiesForCommodity) - def get_commodities_and_tech(self, inp_comm, inp_tech, region): - if self.cur is None: - raise ValueError('Invalid Operation For dat file') - if inp_comm is None and inp_tech is None: - inp_comm = 'NOT NULL' - inp_tech = 'NOT NULL' - else: - if inp_comm is None: - inp_comm = 'NULL' - else: - inp_comm = "'" + inp_comm + "'" - if inp_tech is None: - inp_tech = 'NULL' - else: - inp_tech = "'" + inp_tech + "'" - - if region is None: - self.cur.execute( - 'SELECT input_comm, tech, output_comm FROM Efficiency WHERE input_comm is ' - + inp_comm - + ' or output_comm is ' - + inp_comm - + ' or tech is ' - + inp_tech - ) - else: - self.cur.execute( - "SELECT input_comm, tech, output_comm FROM Efficiency WHERE region LIKE '%" - + region - + "%' and (input_comm is " - + inp_comm - + ' or output_comm is ' - + inp_comm - + ' or tech is ' - + inp_tech - + ')' - ) + in_clause = ', '.join(f"'{flag}'" for flag in flags) + query = f'SELECT tech FROM Technology WHERE flag IN ({in_clause})' + + return {row[0] for row in self.cur.execute(query)} + + def get_commodities_and_tech( + self, inp_comm: str | None, inp_tech: str | None, region: str | None + ) -> pd.DataFrame: + """Retrieves technologies and commodities based on filters.""" + inp_comm_sql = f"'{inp_comm}'" if inp_comm else 'NULL' + inp_tech_sql = f"'{inp_tech}'" if inp_tech else 'NULL' + + if not inp_comm and not inp_tech: + inp_comm_sql = 'NOT NULL' + inp_tech_sql = 'NOT NULL' + + where_clause = f'(input_comm IS {inp_comm_sql} OR output_comm IS {inp_comm_sql} OR tech IS {inp_tech_sql})' + if region: + where_clause = f"region LIKE '%{region}%' AND {where_clause}" + + query = f'SELECT input_comm, tech, output_comm FROM Efficiency WHERE {where_clause}' + self.cur.execute(query) return pd.DataFrame(self.cur.fetchall(), columns=['input_comm', 'tech', 'output_comm']) - def get_existing_technologies_for_commodity(self, comm, region, comm_type='input'): - if self.cur is None: - raise ValueError('Invalid Operation For dat file') - query = '' + def get_existing_technologies_for_commodity( + self, comm: str, region: str | None, comm_type: str = 'input' + ) -> pd.DataFrame: + """Retrieves technologies associated with a specific commodity.""" if comm_type == 'input': - query = "SELECT DISTINCT tech FROM Efficiency WHERE input_comm is '" + comm + "'" + query = f"SELECT DISTINCT tech FROM Efficiency WHERE input_comm IS '{comm}'" else: - query = "SELECT DISTINCT tech FROM Efficiency WHERE output_comm is '" + comm + "'" + query = f"SELECT DISTINCT tech FROM Efficiency WHERE output_comm IS '{comm}'" if region: - query += " AND region LIKE '%" + region + "%'" + query += f" AND region LIKE '%{region}%'" self.cur.execute(query) - result = pd.DataFrame(self.cur.fetchall(), columns=['tech']) - return result + return pd.DataFrame(self.cur.fetchall(), columns=['tech']) - def get_commodities_for_flags(self, flags=None): - if self.cur is None: - raise ValueError('Invalid Operation For dat file') - query = '' + def get_commodities_for_flags(self, flags: list[str] | None = None) -> set[str]: + """Retrieves a set of commodities, optionally filtered by flags.""" if (flags is None) or (not flags): query = 'SELECT name FROM Commodity' else: - flag = flags[0] - query = "SELECT name FROM Commodity WHERE flag is '" + flag + "'" - for i in range(1, len(flags)): - query += " OR flag is '" + flags[i] + "'" - - result = set() - for row in self.cur.execute(query): - result.add(row[0]) - - return result - - # comm_type can be 'input' or 'output' - def get_commodities_by_technology(self, region, comm_type='input'): - if self.cur is None: - raise ValueError('Invalid Operation For dat file') - query = '' + in_clause = ', '.join(f"'{flag}'" for flag in flags) + query = f'SELECT name FROM Commodity WHERE flag IN ({in_clause})' + + return {row[0] for row in self.cur.execute(query)} + + def get_commodities_by_technology( + self, region: str | None, comm_type: str = 'input' + ) -> set[tuple[str, str]]: + """Retrieves commodity-technology pairs.""" if comm_type == 'input': query = 'SELECT DISTINCT input_comm, tech FROM Efficiency' elif comm_type == 'output': query = 'SELECT DISTINCT tech, output_comm FROM Efficiency' else: - raise ValueError('Invalid commodity comm_type: can only be input or output') + raise ValueError("Invalid comm_type: can only be 'input' or 'output'") if region: - query += " WHERE region LIKE '%" + region + "%'" - result = set() - for row in self.cur.execute(query): - result.add((row[0], row[1])) + query += f" WHERE region LIKE '%{region}%'" - return result + return {tuple(row) for row in self.cur.execute(query)} - def get_capacity_for_tech_and_period(self, tech=None, period=None, region=None): - if self.cur is None: - raise ValueError('Invalid Operation For dat file') - if self.scenario is None or self.scenario == '': - raise ValueError('For Output related queries, please set a scenario first') + def get_capacity_for_tech_and_period( + self, tech: str | None = None, period: int | None = None, region: str | None = None + ) -> pd.DataFrame | pd.Series: + """Retrieves capacity data, aggregated by technology.""" + if not self.scenario: + raise ValueError('A scenario must be set for output-related queries') - columns = [] - if tech is None: - columns.append('tech') - if period is None: - columns.append('period') - columns.append('sum(capacity)') - columns.append('region') - - query = 'SELECT ' + columns[0] - - for col in columns[1:]: - query += ', ' + col - - query += " FROM OutputNetCapacity WHERE scenario == '" + self.scenario + "'" + columns = ['tech', 'period', 'SUM(capacity)', 'region'] + query = f"SELECT {', '.join(columns)} FROM OutputNetCapacity WHERE scenario IS '{self.scenario}'" if region: - query += " AND region LIKE '" + region + "%'" + query += f" AND region LIKE '{region}%'" if tech: - query += " AND tech is '" + tech + "'" + query += f" AND tech IS '{tech}'" if period: - query += " AND period == '" + str(period) + "'" + query += f" AND period IS '{period}'" - # sum over vintages query += ' GROUP BY tech, region, period, sector;' - self.cur.execute(query) - # quick hack...change the column name for capacity - new_columns = [] - for col in columns: - new_col = col.replace('sum(capacity)', 'capacity') - new_columns.append(new_col) - columns = new_columns - result = pd.DataFrame(self.cur.fetchall(), columns=columns) - if region is None: + + df_columns = [col.replace('SUM(capacity)', 'capacity') for col in columns] + result = pd.DataFrame(self.cur.fetchall(), columns=df_columns) + + if region is None and not result.empty: mask = result['region'].str.contains('-') - # TODO: somebody needs to verify this halving of capacity...? result.loc[mask, 'capacity'] /= 2 result.drop(columns=['region'], inplace=True) - if len(columns) == 2: + if len(df_columns) == 2: return result.sum() else: return result.groupby(by='tech').sum().reset_index() - def get_output_flow_for_period(self, period, region, comm_type='input', commodity=None): - if self.cur is None: - raise ValueError('Invalid Operation For dat file') - if self.scenario is None or self.scenario == '': - raise ValueError('For Output related queries, please set a scenario first') - columns = [] + def get_output_flow_for_period( + self, + period: int, + region: str | None, + comm_type: str = 'input', + commodity: str | None = None, + ) -> pd.DataFrame: + """Retrieves aggregated output flow data.""" + if not self.scenario: + raise ValueError('A scenario must be set for output-related queries') + + columns: list[str] = [] table = '' - col = '' if comm_type == 'input': table = 'OutputFlowIn' if commodity is None: columns.append('input_comm') - col = 'flow' - columns.append('tech') - if comm_type == 'output': + elif comm_type == 'output': table = 'OutputFlowOut' if commodity is None: columns.append('output_comm') - col = 'flow' + columns.append('tech') - query = 'SELECT DISTINCT ' - for c in columns: - query += c + ', ' - query += ( - 'SUM(' + col + ') AS flow FROM ' + table + " WHERE scenario is '" + self.scenario + "'" - ) - if (region) and (comm_type == 'input'): - query += " AND region LIKE '" + region + "%'" - if (region) and (comm_type == 'output'): - query += " AND region LIKE '%" + region + "'" - query += " AND period is '" + str(period) + "' " - - query2 = ' GROUP BY tech' - if commodity is not None: - query += ' AND ' + comm_type + "_comm is '" + commodity + "'" + query = f"SELECT DISTINCT {', '.join(columns)}, SUM(flow) AS flow FROM {table} WHERE scenario IS '{self.scenario}'" + + if region: + query += f" AND region LIKE '{region}%'" + query += f" AND period IS '{period}'" + + group_by = ['tech'] + if commodity: + query += f" AND {comm_type}_comm IS '{commodity}'" if comm_type == 'output': - query += " AND input_comm != 'ethos' " + query += " AND input_comm != 'ethos'" else: - query2 += ', ' + comm_type + '_comm' + group_by.append(f'{comm_type}_comm') - query += query2 - columns.append('flow') + query += f' GROUP BY {", ".join(group_by)}' self.cur.execute(query) - result = pd.DataFrame(self.cur.fetchall(), columns=columns) - return result - - def get_emissions_activity_for_period(self, period, region): - if self.cur is None: - raise ValueError('Invalid Operation For dat file') - if self.scenario is None or self.scenario == '': - raise ValueError('For Output related queries, please set a scenario first') - query = ( - 'SELECT E.emis_comm, E.tech, SUM(E.activity*O.flow) FROM EmissionActivity E, OutputFlowOut O ' - + "WHERE E.input_comm == O.input_comm AND E.tech == O.tech AND E.vintage == O.vintage AND E.output_comm == O.output_comm AND O.scenario == '" - + self.scenario - + "' " - + "and O.period == '" - + str(period) - + "'" - ) + + df_columns = columns + ['flow'] + return pd.DataFrame(self.cur.fetchall(), columns=df_columns) + + def get_emissions_activity_for_period(self, period: int, region: str | None) -> pd.DataFrame: + """Retrieves emissions activity data.""" + if not self.scenario: + raise ValueError('A scenario must be set for output-related queries') + + query = f""" + SELECT E.emis_comm, E.tech, SUM(E.activity * O.flow) + FROM EmissionActivity E, OutputFlowOut O + WHERE E.input_comm = O.input_comm + AND E.tech = O.tech + AND E.vintage = O.vintage + AND E.output_comm = O.output_comm + AND O.scenario = '{self.scenario}' + AND O.period = '{period}' + """ if region: - query += " AND E.region LIKE '%" + region + "%'" + query += f" AND E.region LIKE '%{region}%'" query += ' GROUP BY E.tech, E.emis_comm' self.cur.execute(query) - result = pd.DataFrame(self.cur.fetchall(), columns=['emis_comm', 'tech', 'emis_activity']) - return result - - def get_commodity_wise_input_and_output_flow(self, tech, period, region): - if self.cur is None: - raise ValueError('Invalid Operation For dat file') - if self.scenario is None or self.scenario == '': - raise ValueError('For Output related queries, please set a scenario first') - - query = ( - "SELECT OF.input_comm, OF.output_comm, OF.vintage, OF.region,\ - SUM(OF.vflow_in) vflow_in, SUM(OFO.vflow_out) vflow_out, OC.capacity \ - FROM (SELECT region, scenario, sector, period, input_comm, tech, vintage, output_comm, sum(flow) AS vflow_in \ - FROM OutputFlowIn GROUP BY region, scenario, sector, period, input_comm, tech, vintage, output_comm) AS OF \ - INNER JOIN (SELECT region, scenario, sector, period, input_comm, tech, vintage, output_comm, sum(flow) AS vflow_out \ - FROM OutputFlowOut GROUP BY region, scenario, sector, period, input_comm, tech, vintage, output_comm) AS OFO \ - ON \ - OF.region = OFO.region AND \ - OF.scenario = OFO.scenario AND \ - OF.period = OFO.period AND \ - OF.tech = OFO.tech AND \ - OF.input_comm = OFO.input_comm AND \ - OF.vintage = OFO.vintage AND \ - OF.output_comm = OFO.output_comm \ - INNER JOIN \ - OutputNetCapacity OC \ - ON \ - OF.region = OC.region AND \ - OF.scenario = OC.scenario AND \ - OF.tech = OC.tech AND \ - OF.vintage = OC.vintage \ - WHERE \ - OF.period ='" - + str(period) - + "' AND \ - OF.tech is '" - + tech - + "' AND \ - OF.scenario is '" - + self.scenario - + "'" - ) - + return pd.DataFrame(self.cur.fetchall(), columns=['emis_comm', 'tech', 'emis_activity']) + + def get_commodity_wise_input_and_output_flow( + self, tech: str, period: int, region: str | None + ) -> pd.DataFrame: + """Retrieves detailed input and output flows for a technology.""" + if not self.scenario: + raise ValueError('A scenario must be set for output-related queries') + + query = f""" + SELECT + OF.input_comm, OF.output_comm, OF.vintage, OF.region, + SUM(OF.vflow_in) AS vflow_in, + SUM(OFO.vflow_out) AS vflow_out, + OC.capacity + FROM ( + SELECT region, scenario, period, input_comm, tech, vintage, output_comm, SUM(flow) AS vflow_in + FROM OutputFlowIn + GROUP BY region, scenario, period, input_comm, tech, vintage, output_comm + ) AS OF + INNER JOIN ( + SELECT region, scenario, period, input_comm, tech, vintage, output_comm, SUM(flow) AS vflow_out + FROM OutputFlowOut + GROUP BY region, scenario, period, input_comm, tech, vintage, output_comm + ) AS OFO ON + OF.region = OFO.region AND + OF.scenario = OFO.scenario AND + OF.period = OFO.period AND + OF.tech = OFO.tech AND + OF.input_comm = OFO.input_comm AND + OF.vintage = OFO.vintage AND + OF.output_comm = OFO.output_comm + INNER JOIN OutputNetCapacity OC ON + OF.region = OC.region AND + OF.scenario = OC.scenario AND + OF.tech = OC.tech AND + OF.vintage = OC.vintage + WHERE + OF.period = '{period}' AND + OF.tech IS '{tech}' AND + OF.scenario IS '{self.scenario}' + """ if region: - query += " AND OF.region LIKE '%" + region + "%'" - + query += f" AND OF.region LIKE '%{region}%'" query += ' GROUP BY OF.region, OF.vintage, OF.input_comm, OF.output_comm' self.cur.execute(query) @@ -411,7 +340,6 @@ def get_commodity_wise_input_and_output_flow(self, tech, period, region): 'capacity', ], ) - result = pd.DataFrame( - result.groupby(['input_comm', 'output_comm', 'vintage']).sum().reset_index() + return pd.DataFrame( + result.groupby(['input_comm', 'output_comm', 'vintage'], as_index=False).sum() ) - return result diff --git a/temoa/data_processing/db_query.py b/temoa/data_processing/db_query.py index 36449e55b..7db428b0c 100644 --- a/temoa/data_processing/db_query.py +++ b/temoa/data_processing/db_query.py @@ -1,51 +1,85 @@ # Dev Note: This module is unused and appears to be just a query executor. Retained for now. 12JUN2024 +""" +A command-line utility for sending a direct SQL query to a Temoa database. + +This script allows a user to specify a Temoa SQLite database and an SQL query +string to execute against it, printing the results to the console. +""" import getopt import re import sqlite3 import sys +from os import PathLike +from typing import Any + +def send_query(inp_f: str | PathLike[str], query_string: str) -> str: + """ + Connects to a database, executes a query, and returns the result as a string. -def send_query(inp_f, query_string): - db_result = [] + Args: + inp_f: The file path to the SQLite database. + query_string: The SQL query to execute. + + Returns: + A string containing the query results or an error message. + """ + db_result: list[tuple[Any, ...]] = [] try: con = sqlite3.connect(inp_f) - cur = con.cursor() # a database cursor is a control structure that enables traversal over the records in a database - con.text_factory = str # this ensures data is explored with the correct UTF-8 encoding + cur = con.cursor() + con.text_factory = str - print(inp_f) + print(f'Executing query on: {inp_f}') cur.execute(query_string) - for row in cur: - db_result.append(row) + db_result.extend(cur) cur.close() con.close() - return 'Query Result: %s' % ''.join(db_result) + # Convert list of tuples to a more readable string representation + result_str = '\n'.join(map(str, db_result)) + return f'Query Result:\n{result_str}' except sqlite3.Error as e: - print('Error in Query %s' % e.args[0]) - return 'Query Result: Error in Query %s' % e.args[0] + error_msg = f'Error in Query: {e.args[0]}' + print(error_msg) + return f'Query Result: {error_msg}' -def help_user(): +def help_user() -> None: + """Prints the help message for the script to the console.""" print( """Use as: - python db_query.py -i (or --input) - | -q (or --query) - | -h (or --help) """ + python db_query.py -i (or --input) + | -q (or --query) + | -h (or --help)""" ) -def get_flags(inputs): - inp_file = None - query_string = None +def get_flags(inputs: dict[str, str]) -> str | None: + """ + Parses command-line options and executes the database query. + + Args: + inputs: A dictionary of command-line options to their arguments. - if inputs is None: + Returns: + The result of the database query as a string, or None if no query was run. + + Raises: + TypeError: If no arguments are provided. + ValueError: If the input file is not specified or is not a valid database file. + """ + inp_file: str | None = None + query_string: str | None = None + + if not inputs: raise TypeError('no arguments found') for opt, arg in inputs.items(): - print('%s == %s' % (opt, arg)) + print(f'{opt} == {arg}') if opt in ('-i', '--input'): inp_file = arg @@ -56,15 +90,12 @@ def get_flags(inputs): sys.exit(2) if inp_file is None: - raise Exception('Input file not specified') - - file_ty = re.search(r'(\w+)\.(\w+)\b', inp_file) # Extract the input filename and extension + raise ValueError('Input file not specified') - if not file_ty: - raise 'The file type %s is not recognized. Please specify a database file.' % inp_file + file_ty = re.search(r'\.(\w+)$', inp_file) - elif file_ty.group(2) not in ('db', 'sqlite', 'sqlite3', 'sqlitedb'): - raise 'The file type %s is not recognized. Please specify a database file.' % inp_file + if not file_ty or file_ty.group(1) not in ('db', 'sqlite', 'sqlite3', 'sqlitedb'): + raise ValueError(f'The file type of "{inp_file}" is not a recognized database file.') if query_string is None: print('No query specified.') @@ -75,10 +106,12 @@ def get_flags(inputs): if __name__ == '__main__': try: - argv = sys.argv[1:] + argv: list[str] = sys.argv[1:] + opts: list[tuple[str, str]] + args: list[str] opts, args = getopt.getopt(argv, 'hi:q:', ['help', 'input=', 'query=']) - print(opts) + print(f'Options found: {opts}') except getopt.GetoptError: help_user() diff --git a/temoa/data_processing/graphviz_util.py b/temoa/data_processing/graphviz_util.py index a1ba46dcd..478c00eb3 100644 --- a/temoa/data_processing/graphviz_util.py +++ b/temoa/data_processing/graphviz_util.py @@ -1,7 +1,10 @@ import argparse +from collections.abc import Callable, Iterable, Sequence, Sized +from typing import Any -def process_input(args): +def process_input(args: list[str]) -> dict[str, Any]: + """Parse command line arguments.""" parser = argparse.ArgumentParser(description='Generate Output Plot') parser.add_argument( '-i', @@ -118,9 +121,10 @@ def process_input(args): return vars(options) -def get_color_config(grey_flag): +def get_color_config(grey_flag: bool) -> dict[str, str | tuple[str, ...]]: + """Return a dictionary of color configurations for the graph.""" grey_flag = not (grey_flag) - kwargs = dict( + kwargs: dict[str, str | tuple[str, ...]] = dict( tech_color='darkseagreen' if grey_flag else 'black', commodity_color='lightsteelblue' if grey_flag else 'black', unused_color='powderblue' if grey_flag else 'gray75', @@ -141,55 +145,57 @@ def get_color_config(grey_flag): sb_arrow_color='forestgreen' if grey_flag else 'black', # SUBGRAPH 1 ARROW COLORS color_list=( - 'red', - 'orange', - 'gold', - 'green', - 'blue', - 'purple', - 'hotpink', - 'cyan', - 'burlywood', - 'coral', - 'limegreen', - 'black', - 'brown', - ) - if grey_flag - else ('black', 'black'), + ( + 'red', + 'orange', + 'gold', + 'green', + 'blue', + 'purple', + 'hotpink', + 'cyan', + 'burlywood', + 'coral', + 'limegreen', + 'black', + 'brown', + ) + if grey_flag + else ('black', 'black') + ), ) return kwargs -def _get_len(key): - def wrapped(obj): +def _get_len(key: int) -> Callable[[Sequence[Sized]], int]: + """Return a function that gets the length of an item at a specific index in a sequence.""" + + def wrapped(obj: Sequence[Sized]) -> int: return len(obj[key]) return wrapped -def create_text_nodes(nodes, indent=1): - """\ -Return a set of text nodes in Graphviz DOT format, optimally padded for easier -reading and debugging. - -nodes: iterable of (id, attribute) node tuples - e.g. [(node1, attr1), (node2, attr2), ...] +def create_text_nodes(nodes: Iterable[tuple[str, str]], indent: int = 1) -> str: + """ + Return a set of text nodes in Graphviz DOT format, optimally padded for + easier reading and debugging. -indent: integer, number of tabs with which to indent all Dot node lines -""" + Args: + nodes: iterable of (id, attribute) node tuples + e.g. [(node1, attr1), (node2, attr2), ...] + indent: integer, number of tabs with which to indent all Dot node lines + """ if not nodes: return '// no nodes in this section' - # guarantee basic structure of nodes arg - assert len(nodes) == sum(1 for a, b in nodes) - # Step 1: for alignment, get max item length in node list - maxl = max(map(_get_len(0), nodes)) + 2 # account for two extra quotes + # The `+ 2` accounts for the two extra quotes that will be added. + maxl = max(map(_get_len(0), nodes), default=0) + 2 # Step 2: prepare a text format based on max node size that pads all # lines with attributes - nfmt_attr = '{0:<%d} [ {1} ] ;' % maxl # node text format + nfmt_attr = f'{{0:<{maxl}}} [ {{1}} ] ;' # node text format nfmt_noa = '{0} ;' # Step 3: create each node, and place string representation in a set to @@ -199,35 +205,31 @@ def create_text_nodes(nodes, indent=1): gviz.update(nfmt_noa.format(q % n) for n, a in nodes if not a) # Step 4: return a sorted version of nodes, as a single string - indent = '\n' + '\t' * indent - return indent.join(sorted(gviz)) + indent_str = '\n' + '\t' * indent + return indent_str.join(sorted(gviz)) -def create_text_edges(edges, indent=1): - """\ -Return a set of text edge definitions in Graphviz DOT format, optimally padded -for easier reading and debugging. +def create_text_edges(edges: Iterable[tuple[str, str, str]], indent: int = 1) -> str: + """ + Return a set of text edge definitions in Graphviz DOT format, optimally + padded for easier reading and debugging. -edges: iterable of (from, to, attribute) edge tuples - e.g. [(inp1, tech1, attr1), (inp2, tech2, attr2), ...] - -indent: integer, number of tabs with which to indent all Dot edge lines -""" + Args: + edges: iterable of (from, to, attribute) edge tuples + e.g. [(inp1, tech1, attr1), (inp2, tech2, attr2), ...] + indent: integer, number of tabs with which to indent all Dot edge lines + """ if not edges: return '// no edges in this section' - # guarantee basic structure of edges arg - assert len(edges) == sum(1 for a, b, c in edges) - # Step 1: for alignment, get max length of items on left and right side of - # graph operator token ('->') - maxl, maxr = max(map(_get_len(0), edges)), max(map(_get_len(1), edges)) - maxl += 2 # account for additional two quotes - maxr += 2 # account for additional two quotes + # graph operator token ('->'). The `+ 2` accounts for the two extra quotes. + maxl = max(map(_get_len(0), edges), default=0) + 2 + maxr = max(map(_get_len(1), edges), default=0) + 2 # Step 2: prepare format to be "\n\tinp+PADDING -> out+PADDING [..." - efmt_attr = '{0:<%d} -> {1:<%d} [ {2} ] ;' % (maxl, maxr) # with attributes - efmt_noa = '{0:<%d} -> {1} ;' % maxl # no attributes + efmt_attr = f'{{0:<{maxl}}} -> {{1:<{maxr}}} [ {{2}} ] ;' # with attributes + efmt_noa = f'{{0:<{maxl}}} -> {{1}} ;' # no attributes # Step 3: add each edge to a set (to guarantee unique entries only) q = '"%s"' # enforce quoting for all tokens @@ -235,5 +237,5 @@ def create_text_edges(edges, indent=1): gviz.update(efmt_noa.format(q % i, q % t) for i, t, a in edges if not a) # Step 4: return a sorted version of the edges, as a single string - indent = '\n' + '\t' * indent - return indent.join(sorted(gviz)) + indent_str = '\n' + '\t' * indent + return indent_str.join(sorted(gviz)) diff --git a/temoa/data_processing/make_graphviz.py b/temoa/data_processing/make_graphviz.py index 3629470d7..3f4ff8730 100644 --- a/temoa/data_processing/make_graphviz.py +++ b/temoa/data_processing/make_graphviz.py @@ -1,6 +1,7 @@ import os import sys from subprocess import call +from typing import Any, TextIO from .database_util import DatabaseUtil from .graphviz_formats import ( @@ -13,7 +14,29 @@ class GraphvizDiagramGenerator: - def __init__(self, db_file, scenario=None, region=None, out_dir='.', verbose=1): + """Generates Graphviz diagrams for Temoa models.""" + + db_file: str + q_name: str + scenario: str | None + region: str | None + out_dir: str + folder: dict[str, str] + verbose: int + colors: dict[str, Any] + db_util: DatabaseUtil + logger: TextIO + grey_flag: bool + + def __init__( + self, + db_file: str, + scenario: str | None = None, + region: str | None = None, + out_dir: str = '.', + verbose: int = 1, + ) -> None: + """Initialize the GraphvizDiagramGenerator.""" self.db_file = db_file self.q_name = os.path.splitext(os.path.basename(self.db_file))[0] self.scenario = scenario @@ -22,119 +45,125 @@ def __init__(self, db_file, scenario=None, region=None, out_dir='.', verbose=1): self.folder = {'results': 'whole_system', 'tech': 'processes', 'comm': 'commodities'} self.verbose = verbose self.colors = {} + self.grey_flag = False - def connect(self): + def connect(self) -> None: + """Connect to the database and set up output directories.""" self.db_util = DatabaseUtil(self.db_file, self.scenario) self.logger = open(os.path.join(self.out_dir, 'graphviz.log'), 'w') self.set_graphic_options(False, False) self.__log__('--------------------------------------') self.__log__('GraphvizDiagramGenerator: connected') if self.scenario: - out_dir = self.q_name + '_' + self.scenario + '_graphviz' + out_dir = f'{self.q_name}_{self.scenario}_graphviz' else: - out_dir = self.q_name + '_input_graphviz' + out_dir = f'{self.q_name}_input_graphviz' self.out_dir = os.path.join(self.out_dir, out_dir) if not os.path.exists(self.out_dir): os.mkdir(self.out_dir) - def close(self): + def close(self) -> None: + """Disconnect from the database and close the logger.""" self.db_util.close() self.__log__('GraphvizDiagramGenerator: disconnected') self.__log__('--------------------------------------') self.logger.close() - # os.chdir('..') - def __log__(self, msg): + def __log__(self, msg: str) -> None: + """Log a message to the console and a log file.""" if self.verbose == 1: print(msg) self.logger.write(msg + '\n') - def __generate_graph__(self, dot_format, dot_args, output_name, output_format): + def __generate_graph__( + self, dot_format: str, dot_args: dict[str, Any], output_name: str, output_format: str + ) -> None: + """Generate a graph from a DOT format string.""" dot_args.update(self.colors) with open(output_name + '.dot', 'w') as f: f.write(dot_format % dot_args) cmd = ( 'dot', - '-T' + output_format, - '-o' + output_name + '.' + output_format, - output_name + '.dot', + f'-T{output_format}', + f'-o{output_name}.{output_format}', + f'{output_name}.dot', ) call(cmd) - def set_graphic_options(self, grey_flag=None, splinevar=None): + def set_graphic_options( + self, grey_flag: bool | None = None, splinevar: bool | None = None + ) -> None: + """Set graphic options for the diagrams.""" if grey_flag is not None: self.grey_flag = grey_flag self.colors.update(get_color_config(self.grey_flag)) if splinevar is not None: - self.colors['splinevar'] = splinevar + self.colors['splinevar'] = 'spline' if splinevar else 'line' self.__log__( - 'setGraphicOption: updated greyFlag = ' - + str(self.grey_flag) - + ' and splinevar = ' - + str(self.colors['splinevar']) + f'setGraphicOption: updated greyFlag = {self.grey_flag} ' + f'and splinevar = {self.colors.get("splinevar", "line")}' ) - def create_main_results_diagram(self, period, region, output_format='svg'): - self.__log__('CreateMainResultsDiagram: started with period = ' + str(period)) + def create_main_results_diagram( + self, period: int, region: str | None, output_format: str = 'svg' + ) -> tuple[str, str]: + """Create the main results diagram for a specific period.""" + self.__log__(f'CreateMainResultsDiagram: started with period = {period}') - if not os.path.exists(os.path.join(self.out_dir, self.folder['results'])): - os.makedirs(os.path.join(self.out_dir, self.folder['results'])) + results_dir = os.path.join(self.out_dir, self.folder['results']) + if not os.path.exists(results_dir): + os.makedirs(results_dir) - output_name = os.path.join(self.folder['results'], 'results%s' % period) + output_name = os.path.join(self.folder['results'], f'results{period}') if self.region: - output_name += '_' + self.region + output_name += f'_{self.region}' output_name = os.path.join(self.out_dir, output_name) if self.grey_flag: output_name += '.grey' tech_all = self.db_util.get_technologies_for_flags(flags=['r', 'p', 'pb', 'ps']) - commodity_carrier = self.db_util.get_commodities_for_flags(flags=['d', 'p']) commodity_emissions = self.db_util.get_commodities_for_flags(flags=['e']) - efficiency_input = self.db_util.get_commodities_by_technology(region, comm_type='input') efficiency_output = self.db_util.get_commodities_by_technology(region, comm_type='output') - v_cap2 = self.db_util.get_capacity_for_tech_and_period(period=period, region=region) - ei_2 = self.db_util.get_output_flow_for_period( period=period, region=region, comm_type='input' ) eo_2 = self.db_util.get_output_flow_for_period( period=period, region=region, comm_type='output' ) - emio_2 = self.db_util.get_emissions_activity_for_period(period=period, region=region) self.__log__('CreateMainResultsDiagram: database fetched successfully') tech_attr_fmt = 'label="%s\\nCapacity: %.2f", href="#", onclick="loadNextGraphvizGraph(\'results\', \'%s\', \'%s\')"' - # tech_attr_fmt = 'label="%%s\\nCapacity: %%.2f", href="results_%%s_%%s.%s"' - # tech_attr_fmt %= outputFormat - # commodity_fmt = 'href="../commodities/rc_%%s_%%s.%s"' % outputFormat commodity_fmt = "href=\"#\", onclick=\"loadNextGraphvizGraph('results', '%s', '%s')\"" flow_fmt = 'label="%.2f"' - epsilon = 0.005 - etechs, dtechs, ecarriers, xnodes = set(), set(), set(), set() - eemissions = set() - eflowsi, eflowso, dflows = set(), set(), set() # edges + etechs: set[tuple[str, str]] = set() + dtechs: set[tuple[str, str]] = set() + ecarriers: set[tuple[str, str]] = set() + xnodes: set[tuple[str, str]] = set() + eemissions: set[tuple[str, str]] = set() + eflowsi: set[tuple[str, str, str]] = set() + eflowso: set[tuple[str, str, str]] = set() + dflows: set[tuple[str, str, str]] = set() usedc, usede = set(), set() # used carriers, used emissions v_cap2.index = v_cap2.tech for tech in set(tech_all) - set(v_cap2.tech): - dtechs.add((tech, None)) + dtechs.add((tech, '')) for i in range(len(v_cap2)): row = v_cap2.iloc[i] etechs.add( (row['tech'], tech_attr_fmt % (row['tech'], row['capacity'], row['tech'], period)) ) - # etechs.add( (row['tech'], tech_attr_fmt % (row['tech'], row['capacity'], row['tech'], period)) ) - udflows = set() + udflows: set[tuple[str, str]] = set() for i in range(len(ei_2)): row = ei_2.iloc[i] if row['input_comm'] != 'ethos': @@ -142,20 +171,16 @@ def create_main_results_diagram(self, period, region, output_format='svg'): ecarriers.add((row['input_comm'], commodity_fmt % (row['input_comm'], period))) usedc.add(row['input_comm']) else: - # check to see if this tech is in the unlim_cap set tech = row['tech'] - if tech not in v_cap2.tech: - cap = 99999 - else: - cap = v_cap2.loc[row['tech']].capacity + cap = v_cap2.loc[row['tech']].capacity if tech in v_cap2.tech else 99999 xnodes.add((row['tech'], tech_attr_fmt % (row['tech'], cap, row['tech'], period))) udflows.add((row['input_comm'], row['tech'])) for row in set(efficiency_input) - udflows: if row[0] != 'ethos': - dflows.add((row[0], row[1], None)) + dflows.add((row[0], row[1], '')) else: - xnodes.add((row[1], None)) + xnodes.add((row[1], '')) udflows = set() for i in range(len(eo_2)): @@ -166,23 +191,17 @@ def create_main_results_diagram(self, period, region, output_format='svg'): udflows.add((row['tech'], row['output_comm'])) for row in set(efficiency_output) - udflows: - dflows.add((row[0], row[1], None)) + dflows.add((row[0], row[1], '')) for i in range(len(emio_2)): row = emio_2.iloc[i] if row['emis_activity'] >= epsilon: eflowso.add((row['tech'], row['emis_comm'], flow_fmt % row['emis_activity'])) - eemissions.add((row['emis_comm'], None)) + eemissions.add((row['emis_comm'], '')) usede.add(row['emis_comm']) - dcarriers = set() - demissions = set() - for cc in commodity_carrier: - if cc not in usedc and cc != 'ethos': - dcarriers.add((cc, None)) - for ee in commodity_emissions: - if ee not in usede: - demissions.add((ee, None)) + dcarriers = {(cc, '') for cc in commodity_carrier if cc not in usedc and cc != 'ethos'} + demissions = {(ee, '') for ee in commodity_emissions if ee not in usede} self.__log__('CreateMainResultsDiagram: creating diagrams') args = dict( @@ -200,44 +219,43 @@ def create_main_results_diagram(self, period, region, output_format='svg'): eflowso=create_text_edges(eflowso, indent=3), ) + output_path = output_name + '.' + output_format self.__generate_graph__(results_dot_fmt, args, output_name, output_format) self.__log__('CreateMainResultsDiagram: graph generated, returning') - return self.out_dir, output_name + '.' + output_format + return self.out_dir, output_path - # Needs some small fixing - cases where no input but output is there. # Check sample graphs def create_tech_results_diagrams( - self, period, region, tech, output_format='svg' - ): # tech results - self.__log__( - 'CreateTechResultsDiagrams: started with period = ' - + str(period) - + ' and tech = ' - + str(tech) - ) + self, period: int, region: str | None, tech: str, output_format: str = 'svg' + ) -> tuple[str, str]: + """Create technology-specific results diagrams.""" + self.__log__(f'CreateTechResultsDiagrams: started with period = {period} and tech = {tech}') - if not os.path.exists(os.path.join(self.out_dir, self.folder['tech'])): - os.makedirs(os.path.join(self.out_dir, self.folder['tech'])) + tech_dir = os.path.join(self.out_dir, self.folder['tech']) + if not os.path.exists(tech_dir): + os.makedirs(tech_dir) output_name = os.path.join(self.folder['tech'], f'results_{tech}_{period}') if self.region: - output_name += '_' + self.region + output_name += f'_{self.region}' output_name = os.path.join(self.out_dir, output_name) if self.grey_flag: output_name += '.grey' - # enode_attr_fmt = 'href="../commodities/rc_%%s_%%s.%s"' % outputFormat - # vnode_attr_fmt = 'href="results_%%s_p%%sv%%s_segments.%s", ' % outputFormat - # vnode_attr_fmt += 'label="%s\\nCap: %.2f"' enode_attr_fmt = "href=\"#\", onclick=\"loadNextGraphvizGraph('results', '%s', '%s')\"" - vnode_attr_fmt = "href=\"#\", onclick=\"loadNextGraphvizGraph('%s', '%s', '%s')\"" - vnode_attr_fmt += 'label="%s\\nCap: %.2f"' + vnode_attr_fmt = ( + "href=\"#\", onclick=\"loadNextGraphvizGraph('%s', '%s', '%s')\", " + 'label="%s\\nCap: %.2f"' + ) total_cap = self.db_util.get_capacity_for_tech_and_period(tech, period, region) flows = self.db_util.get_commodity_wise_input_and_output_flow(tech, period, region) - self.__log__('CreateTechResultsDiagrams: database fetched successfully') - enodes, vnodes, iedges, oedges = set(), set(), set(), set() + enodes: set[tuple[str, str]] = set() + vnodes: set[tuple[str, str]] = set() + iedges: set[tuple[str, str, str]] = set() + oedges: set[tuple[str, str, str]] = set() + for i in range(len(flows)): row = flows.iloc[i] vnode = str(row['vintage']) @@ -255,13 +273,11 @@ def create_tech_results_diagrams( enodes.add((row['output_comm'], enode_attr_fmt % (row['output_comm'], period))) oedges.add((vnode, row['output_comm'], 'label="%.2f"' % row['flow_out'])) - # cluster_vintage_url = "results%s.%s" % (period, outputFormat) - cluster_vintage_url = '#' - + output_path = output_name + '.' + output_format if vnodes: self.__log__('CreateTechResultsDiagrams: creating diagrams') - args = dict( - cluster_vintage_url=cluster_vintage_url, + args: dict[str, Any] = dict( + cluster_vintage_url='#', total_cap=total_cap, inp_technology=tech, period=period, @@ -275,22 +291,23 @@ def create_tech_results_diagrams( self.__log__('CreateTechResultsDiagrams: nothing to create') self.__log__('CreateTechResultsDiagrams: graph generated, returning') - return self.out_dir, output_name + '.' + output_format + return self.out_dir, output_path - def create_commodity_partial_results(self, period, region, comm, output_format='svg'): + def create_commodity_partial_results( + self, period: int, region: str | None, comm: str, output_format: str = 'svg' + ) -> tuple[str, str]: + """Create commodity-specific partial results diagrams.""" self.__log__( - 'CreateCommodityPartialResults: started with period = ' - + str(period) - + ' and comm = ' - + str(comm) + f'CreateCommodityPartialResults: started with period = {period} and comm = {comm}' ) - if not os.path.exists(os.path.join(self.out_dir, self.folder['comm'])): - os.makedirs(os.path.join(self.out_dir, self.folder['comm'])) + comm_dir = os.path.join(self.out_dir, self.folder['comm']) + if not os.path.exists(comm_dir): + os.makedirs(comm_dir) output_name = os.path.join(self.folder['comm'], f'rc_{comm}_{period}') if self.region: - output_name += '_' + self.region + output_name += f'_{self.region}' output_name = os.path.join(self.out_dir, output_name) if self.grey_flag: output_name += '.grey' @@ -301,28 +318,22 @@ def create_commodity_partial_results(self, period, region, comm, output_format=' output_total = set( self.db_util.get_existing_technologies_for_commodity(comm, region, 'input')['tech'] ) - flow_in = self.db_util.get_output_flow_for_period(period, region, 'input', comm) otechs = set(flow_in['tech']) - flow_out = self.db_util.get_output_flow_for_period(period, region, 'output', comm) itechs = set(flow_out['tech']) - self.__log__('CreateCommodityPartialResults: database fetched successfully') - # period_results_url_fmt = '../results/results%%s.%s' % outputFormat - # node_attr_fmt = 'href="../results/results_%%s_%%s.%s"' % outputFormat - # rc_node_fmt = 'color="%s", href="%s", shape="circle", fillcolor="%s", fontcolor="black"' - node_attr_fmt = "href=\"#\", onclick=\"loadNextGraphvizGraph('results', '%s', '%s')\"" rc_node_fmt = 'color="%s", href="%s", shape="circle", fillcolor="%s", fontcolor="black"' - # url = period_results_url_fmt % period - url = '#' - enodes, dnodes, eedges, dedges = set(), set(), set(), set() + enodes: set[tuple[str, str]] = set() + dnodes: set[tuple[str, str]] = set() + eedges: set[tuple[str, str, str]] = set() + dedges: set[tuple[str, str, str]] = set() rcnode = ( - (comm, rc_node_fmt % (self.colors['commodity_color'], url, self.colors['fill_color'])), + (comm, rc_node_fmt % (self.colors['commodity_color'], '#', self.colors['fill_color'])), ) for i in range(len(flow_in)): @@ -331,16 +342,16 @@ def create_commodity_partial_results(self, period, region, comm, output_format=' enodes.add((t, node_attr_fmt % (t, period))) eedges.add((comm, t, 'label="%.2f"' % f)) for t in output_total - otechs: - dnodes.add((t, None)) - dedges.add((comm, t, None)) + dnodes.add((t, '')) + dedges.add((comm, t, '')) for i in range(len(flow_out)): t = flow_out.iloc[i]['tech'] f = flow_out.iloc[i]['flow'] enodes.add((t, node_attr_fmt % (t, period))) eedges.add((t, comm, 'label="%.2f"' % f)) for t in input_total - itechs: - dnodes.add((t, None)) - dedges.add((t, comm, None)) + dnodes.add((t, '')) + dedges.add((t, comm, '')) self.__log__('CreateCommodityPartialResults: creating diagrams') args = dict( @@ -352,39 +363,45 @@ def create_commodity_partial_results(self, period, region, comm, output_format=' used_edges=create_text_edges(eedges, indent=2), unused_edges=create_text_edges(dedges, indent=2), ) + output_path = output_name + '.' + output_format self.__generate_graph__(commodity_dot_fmt, args, output_name, output_format) self.__log__('CreateCommodityPartialResults: graph generated, returning') - return self.out_dir, output_name + '.' + output_format + return self.out_dir, output_path - # Function for generating the Input Graph def create_complete_input_graph( - self, region, inp_tech=None, inp_comm=None, output_format='svg' - ): + self, + region: str | None, + inp_tech: str | None = None, + inp_comm: str | None = None, + output_format: str = 'svg', + ) -> tuple[str, str]: + """Generate the complete input graph.""" self.__log__( - 'createCompleteInputGraph: started with inp_tech = ' - + str(inp_tech) - + ' and inp_comm = ' - + str(inp_comm) + f'createCompleteInputGraph: started with inp_tech = {inp_tech} ' + f'and inp_comm = {inp_comm}' ) output_name = self.q_name if inp_tech: - output_name += '_' + str(inp_tech) - if not os.path.exists(os.path.join(self.out_dir, self.folder['tech'])): - os.makedirs(os.path.join(self.out_dir, self.folder['tech'])) + output_name += f'_{inp_tech}' + tech_dir = os.path.join(self.out_dir, self.folder['tech']) + if not os.path.exists(tech_dir): + os.makedirs(tech_dir) output_name = os.path.join(self.folder['tech'], output_name) elif inp_comm: - output_name += '_' + str(inp_comm) - if not os.path.exists(os.path.join(self.out_dir, self.folder['comm'])): - os.makedirs(os.path.join(self.out_dir, self.folder['comm'])) + output_name += f'_{inp_comm}' + comm_dir = os.path.join(self.out_dir, self.folder['comm']) + if not os.path.exists(comm_dir): + os.makedirs(comm_dir) output_name = os.path.join(self.folder['comm'], output_name) else: - if not os.path.exists(os.path.join(self.out_dir, self.folder['results'])): - os.makedirs(os.path.join(self.out_dir, self.folder['results'])) + results_dir = os.path.join(self.out_dir, self.folder['results']) + if not os.path.exists(results_dir): + os.makedirs(results_dir) output_name = os.path.join(self.folder['results'], output_name) if self.region: - output_name += '_' + self.region + output_name += f'_{self.region}' output_name = os.path.join(self.out_dir, output_name) if self.grey_flag: @@ -392,13 +409,13 @@ def create_complete_input_graph( nodes, tech, ltech, to_tech, from_tech = set(), set(), set(), set(), set() - if DatabaseUtil.is_database_file(self.db_file): - res = self.db_util.get_commodities_and_tech(inp_comm, inp_tech, region) - else: - res = self.db_util.read_from_dat_file(inp_comm, inp_tech) + res = ( + self.db_util.get_commodities_and_tech(inp_comm, inp_tech, region) + if DatabaseUtil.is_database_file(self.db_file) + else self.db_util.read_from_dat_file(inp_comm, inp_tech) + ) self.__log__('createCompleteInputGraph: database fetched successfully') - # Create nodes and edges using the data frames from database for i in range(len(res)): row = res.iloc[i] if row['input_comm'] != 'ethos': @@ -409,43 +426,49 @@ def create_complete_input_graph( tech.add(row['tech']) if row['input_comm'] != 'ethos': - to_tech.add('"%s"' % row['input_comm'] + '\t->\t"%s"' % row['tech']) - from_tech.add('"%s"' % row['tech'] + '\t->\t"%s"' % row['output_comm']) + to_tech.add(f'"{row["input_comm"]}"\t->\t"{row["tech"]}"') + from_tech.add(f'"{row["tech"]}"\t->\t"{row["output_comm"]}"') self.__log__('createCompleteInputGraph: creating diagrams') args = dict( - enodes=''.join('"%s";\n\t\t' % x for x in nodes), - tnodes=''.join('"%s";\n\t\t' % x for x in tech), - iedges=''.join('%s;\n\t\t' % x for x in to_tech), - oedges=''.join('%s;\n\t\t' % x for x in from_tech), - snodes=';'.join('"%s"' % x for x in ltech), + enodes=''.join(f'"{x}";\n\t\t' for x in nodes), + tnodes=''.join(f'"{x}";\n\t\t' for x in tech), + iedges=''.join(f'{x};\n\t\t' for x in to_tech), + oedges=''.join(f'{x};\n\t\t' for x in from_tech), + snodes=';'.join(f'"{x}"' for x in ltech), ) + output_path = output_name + '.' + output_format self.__generate_graph__(quick_run_dot_fmt, args, output_name, output_format) self.__log__('createCompleteInputGraph: graph generated, returning') - return self.out_dir, output_name + '.' + output_format + return self.out_dir, output_path if __name__ == '__main__': - input = process_input(sys.argv[1:]) + cli_input = process_input(sys.argv[1:]) graph_gen = GraphvizDiagramGenerator( - input['ifile'], input['scenario_name'], input['region'], out_dir=input['res_dir'] + cli_input['ifile'], + cli_input['scenario_name'], + cli_input['region'], + out_dir=cli_input['res_dir'], ) graph_gen.connect() - graph_gen.set_graphic_options(grey_flag=input['grey_flag'], splinevar=input['splinevar']) - if input['scenario_name'] is None: - res = graph_gen.create_complete_input_graph( - input['region'], input['inp_technology'], input['inp_commodity'] + graph_gen.set_graphic_options( + grey_flag=cli_input['grey_flag'], splinevar=cli_input['splinevar'] + ) + if cli_input['scenario_name'] is None: + result = graph_gen.create_complete_input_graph( + cli_input['region'], cli_input['inp_technology'], cli_input['inp_commodity'] ) - elif input['inp_technology'] is None and input['inp_commodity'] is None: - res = graph_gen.create_main_results_diagram(input['period'], input['region']) - elif input['inp_commodity'] is None: - res = graph_gen.create_tech_results_diagrams( - input['period'], input['region'], input['inp_technology'] + elif cli_input['inp_technology'] is None and cli_input['inp_commodity'] is None: + result = graph_gen.create_main_results_diagram(cli_input['period'], cli_input['region']) + elif cli_input['inp_commodity'] is None: + result = graph_gen.create_tech_results_diagrams( + cli_input['period'], cli_input['region'], cli_input['inp_technology'] ) - elif input['inp_technology'] is None: - res = graph_gen.create_commodity_partial_results( - input['period'], input['region'], input['inp_commodity'] + else: # 'inp_technology' is None + result = graph_gen.create_commodity_partial_results( + cli_input['period'], cli_input['region'], cli_input['inp_commodity'] ) graph_gen.close() - print('Check graph generated at ', res[1], ' and all results at ', res[0]) + print(f'Check graph generated at {result[1]} and all results at {result[0]}') diff --git a/temoa/data_processing/make_output_plots.py b/temoa/data_processing/make_output_plots.py index 33db1d53c..7c1116d8d 100644 --- a/temoa/data_processing/make_output_plots.py +++ b/temoa/data_processing/make_output_plots.py @@ -1,107 +1,116 @@ -import sqlite3 -import sys - -import matplotlib - -matplotlib.use('Agg') import argparse import os import random +import sqlite3 +import sys +from collections.abc import Callable +from typing import cast +import matplotlib from matplotlib import cm as cmx from matplotlib import colors from matplotlib import pyplot as plt +from matplotlib.figure import Figure +from matplotlib.legend import Legend + +matplotlib.use('Agg') + +# Type aliases for clarity using modern built-in generics +DbRow = list[str | int | float] +# All numeric lists are floats for consistency in plotting data. +PlotData = dict[str, list[float]] +Color = tuple[float, float, float, float] +ColorMapFunc = Callable[[int | float], Color] class OutputPlotGenerator: - def __init__(self, path_to_db, region, scenario, super_categories=False) -> None: + """Generates plots from Temoa model output databases.""" + + db_path: str + region: str + scenario: str + folder_name: str + output_file_name: str + capacity_output: list[DbRow] + output_vflow: list[DbRow] + output_emissions: list[DbRow] + tech_categories: list[list[str]] + + def __init__( + self, path_to_db: str, region: str, scenario: str, super_categories: bool = False + ) -> None: self.db_path = os.path.abspath(path_to_db) - if region == 'global': - self.region = '%' - else: - self.region = region + self.region = '%' if region == 'global' else region self.scenario = scenario self.folder_name = ( - os.path.splitext(os.path.basename(path_to_db))[0] - + '_' - + region - + '_' - + scenario - + '_plots' + f'{os.path.splitext(os.path.basename(path_to_db))[0]}_{region}_{scenario}_plots' ) - # self.extractFromDatabase() + self.capacity_output = [] + self.output_vflow = [] + self.output_emissions = [] + self.tech_categories = [] + self.output_file_name = '' - def extract_from_database(self, mode) -> None: + def extract_from_database(self, mode: int) -> None: """ - Based on the type of the plot being generated, extract data from the corresponding table from database + Based on the type of the plot being generated, extract data from the + corresponding table from the database. """ con = sqlite3.connect(self.db_path) cur = con.cursor() if mode == 1: cur.execute( - "SELECT sector, period, tech, capacity FROM OutputNetCapacity WHERE scenario == '" - + self.scenario - + "' AND region LIKE '" - + self.region - + "'" + f'SELECT sector, period, tech, capacity FROM OutputNetCapacity ' + f"WHERE scenario == '{self.scenario}' AND region LIKE '{self.region}'" ) - self.capacity_output = cur.fetchall() - self.capacity_output = [list(elem) for elem in self.capacity_output] + self.capacity_output = [list(elem) for elem in cur.fetchall()] elif mode == 2: cur.execute( - "SELECT sector, period, tech, SUM(flow) FROM OutputFlowOut WHERE scenario == '" - + self.scenario - + "' AND region LIKE '" - + self.region - + "' GROUP BY sector, period, tech" + f'SELECT sector, period, tech, SUM(flow) FROM OutputFlowOut ' + f"WHERE scenario == '{self.scenario}' AND region LIKE '{self.region}' " + f'GROUP BY sector, period, tech' ) - self.output_vflow = cur.fetchall() - self.output_vflow = [list(elem) for elem in self.output_vflow] + self.output_vflow = [list(elem) for elem in cur.fetchall()] elif mode == 3: cur.execute( - "SELECT sector, period, emis_comm, SUM(emission) FROM OutputEmission WHERE scenario == '" - + self.scenario - + "' AND region LIKE '" - + self.region - + "' GROUP BY sector, period, emis_comm" + f'SELECT sector, period, emis_comm, SUM(emission) FROM OutputEmission ' + f"WHERE scenario == '{self.scenario}' AND region LIKE '{self.region}' " + f'GROUP BY sector, period, emis_comm' ) - self.output_emissions = cur.fetchall() - self.output_emissions = [list(elem) for elem in self.output_emissions] + self.output_emissions = [list(elem) for elem in cur.fetchall()] cur.execute('SELECT tech, category FROM Technology') - self.tech_categories = cur.fetchall() - self.tech_categories = [[str(word) for word in t] for t in self.tech_categories] + self.tech_categories = [[str(word) for word in t] for t in cur.fetchall()] con.close() - def get_sectors(self, type): + def get_sectors(self, plot_type: int) -> list[str]: """ - Based on the type of the plot being generated, returns a list of sectors available in the database + Based on the type of the plot, returns a list of sectors available in the database. """ - self.extract_from_database(type) - sectors = set() - - data = None + self.extract_from_database(plot_type) + sectors: set[str] = set() + data: list[DbRow] = [] - if type == 1: + if plot_type == 1: data = self.capacity_output - elif type == 2: + elif plot_type == 2: data = self.output_vflow - elif type == 3: + elif plot_type == 3: data = self.output_emissions for row in data: - sectors.add(row[0]) + sectors.add(str(row[0])) - res = list(sectors) + res = sorted(list(sectors)) res.insert(0, 'all') return res - def process_data(self, input_data, sector, super_categories=False): - """ - Processes data for a particular sector to make it ready for plotting purposes - """ - periods = set() - techs = set() + def process_data( + self, input_data: list[DbRow], sector: str, super_categories: bool + ) -> PlotData: + """Processes data for a particular sector to make it ready for plotting.""" + periods_set: set[int] = set() + techs_set: set[str] = set() for row in input_data: row[0] = str(row[0]) @@ -112,227 +121,199 @@ def process_data(self, input_data, sector, super_categories=False): tech_dict = dict(self.tech_categories) if super_categories: for row in input_data: - row[2] = tech_dict.get(row[2], row[2]) + row[2] = tech_dict.get(str(row[2]), str(row[2])) for row in input_data: if row[0] == sector or sector == 'all': - periods.add(row[1]) # Reminder: indexing starts at 0 - techs.add(row[2]) + periods_set.add(int(row[1])) + techs_set.add(str(row[2])) - periods = list(periods) - techs = list(techs) - periods.sort() + periods = sorted(list(periods_set)) + techs = sorted(list(techs_set)) - output_values = dict() # Each row in a dictionary is a list + output_values: PlotData = {} for tech in techs: - if tech == 'None' or tech == '': + if tech in ('None', ''): continue - output_values[tech] = [0] * len(periods) # this just creates a blank table + output_values[tech] = [0.0] * len(periods) + for row in input_data: - if row[2] == 'None' or row[2] == '': + tech_name = str(row[2]) + if tech_name not in output_values: continue if row[0] == sector or sector == 'all': - output_values[row[2]][periods.index(row[1])] += row[-1] + output_values[tech_name][periods.index(int(row[1]))] += float(row[-1]) - output_values['periods'] = periods + output_values['periods'] = [float(p) for p in periods] return output_values - def handle_output_path(self, plot_type, sector, super_categories, output_dir): - outfile = plot_type + '_' + sector # +'_'+str(int(time.time()*1000))+'.png' + def handle_output_path( + self, plot_type: str, sector: str, super_categories: bool, output_dir: str + ) -> str: + """Constructs and creates the output path for the plot.""" + outfile = f'{plot_type}_{sector}' if super_categories: outfile += '_merged' outfile += '.png' - outfile2 = os.path.join(self.folder_name, outfile) - output_dir = os.path.join(output_dir, self.folder_name) - if not os.path.exists(output_dir): - os.makedirs(output_dir) - self.output_file_name = os.path.join(output_dir, outfile) + full_output_dir = os.path.join(output_dir, self.folder_name) + if not os.path.exists(full_output_dir): + os.makedirs(full_output_dir) - self.output_file_name = self.output_file_name.replace(' ', '') - return outfile2 - - def generate_plot_for_capacity(self, sector, super_categories=False, output_dir='.'): - """ - Generates Plot for Capacity of a given sector - """ + self.output_file_name = os.path.join(full_output_dir, outfile).replace(' ', '') + return os.path.join(self.folder_name, outfile) - outfile2 = self.handle_output_path('capacity', sector, super_categories, output_dir) + def generate_plot_for_capacity( + self, sector: str, super_categories: bool = False, output_dir: str = '.' + ) -> str: + """Generates a plot for the capacity of a given sector.""" + relative_path = self.handle_output_path('capacity', sector, super_categories, output_dir) if os.path.exists(self.output_file_name): print('not generating new capacity plot') - return outfile2 + return relative_path sectors = self.get_sectors(1) - if sector not in sectors: return '' output_values = self.process_data(self.capacity_output, sector, super_categories) - - if self.region == '%': - title = 'Capacity Plot for ' + sector + ' across all regions' - else: - title = 'Capacity Plot for ' + sector + ' sector in region ' + self.region - - self.make_stacked_bar_plot(output_values, 'Years', 'Capacity ', 'periods', title) - - return outfile2 - - def generate_plot_for_output_flow(self, sector, super_categories=False, output_dir='.'): - """ - Generates Plot for Output Flow of a given sector - """ - outfile2 = self.handle_output_path('flow', sector, super_categories, output_dir) + title = ( + f'Capacity Plot for {sector} across all regions' + if self.region == '%' + else f'Capacity Plot for {sector} sector in region {self.region}' + ) + self.make_stacked_bar_plot(output_values, 'Years', 'Capacity', 'periods', title) + return relative_path + + def generate_plot_for_output_flow( + self, sector: str, super_categories: bool = False, output_dir: str = '.' + ) -> str: + """Generates a plot for the output flow of a given sector.""" + relative_path = self.handle_output_path('flow', sector, super_categories, output_dir) if os.path.exists(self.output_file_name): print('not generating new flow plot') - return outfile2 + return relative_path sectors = self.get_sectors(2) if sector not in sectors: return '' output_values = self.process_data(self.output_vflow, sector, super_categories) - - if self.region == '%': - title = 'Output Flow Plot for ' + sector + ' across all regions' - else: - title = 'Output Flow Plot for ' + sector + ' sector in region ' + self.region - - self.make_stacked_bar_plot(output_values, 'Years', 'Activity ', 'periods', title) - - return outfile2 - - def generate_plot_for_emissions(self, sector, super_categories=False, output_dir='.'): - """ - Generates Plot for Emissions of a given sector - """ - outfile2 = self.handle_output_path('emissions', sector, super_categories, output_dir) + title = ( + f'Output Flow Plot for {sector} across all regions' + if self.region == '%' + else f'Output Flow Plot for {sector} sector in region {self.region}' + ) + self.make_stacked_bar_plot(output_values, 'Years', 'Activity', 'periods', title) + return relative_path + + def generate_plot_for_emissions( + self, sector: str, super_categories: bool = False, output_dir: str = '.' + ) -> str: + """Generates a plot for the emissions of a given sector.""" + relative_path = self.handle_output_path('emissions', sector, super_categories, output_dir) if os.path.exists(self.output_file_name): print('not generating new emissions plot') - return outfile2 + return relative_path sectors = self.get_sectors(3) if sector not in sectors: return '' output_values = self.process_data(self.output_emissions, sector, super_categories) - - if self.region == '%': - title = 'Emissions Plot for ' + sector + ' across all regions' - else: - title = 'Emissions Plot for ' + sector + ' sector in region ' + self.region - + title = ( + f'Emissions Plot for {sector} across all regions' + if self.region == '%' + else f'Emissions Plot for {sector} sector in region {self.region}' + ) self.make_line_plot(output_values.copy(), 'Emissions', title) + return relative_path - return outfile2 + # --------------------------- Plot Generation related functions -------------------------------------- - """ - --------------------------- Plot Generation related functions -------------------------------------- - """ - - def get_random_color(self, pastel_factor=0.5): - return [ - (x + pastel_factor) / (1.0 + pastel_factor) - for x in [random.uniform(0, 1.0) for i in [1, 2, 3]] - ] - - def color_distance(self, c1, c2): - return sum([abs(x[0] - x[1]) for x in zip(c1, c2, strict=False)]) - - def get_cmap(self, size): - """Returns a function that maps each index in 0, 1, ... N-1 to a distinct - RGB color.""" + def get_cmap(self, size: int) -> ColorMapFunc: + """Returns a function that maps an index to a distinct RGB color.""" color_norm = colors.Normalize(vmin=0, vmax=size - 1) - # More colormaps: https://matplotlib.org/examples/color/colormaps_reference.html scalar_map = cmx.ScalarMappable(norm=color_norm, cmap='viridis') - def map_index_to_rgb_color(index): - return scalar_map.to_rgba(index) - - return map_index_to_rgb_color - - def generate_new_color(self, existing_colors, pastel_factor=0.5): - max_distance = None - best_color = None - for _ in range(0, 100): - color = self.get_random_color(pastel_factor=pastel_factor) - if not existing_colors: - return color - best_distance = min([self.color_distance(color, c) for c in existing_colors]) - if not max_distance or best_distance > max_distance: - max_distance = best_distance - best_color = color - return best_color - - def make_stacked_bar_plot(self, data, xlabel, ylabel, xvar, title): + def wrapper(index: int | float) -> Color: + # We ignore the arg-type error. Mypy expects a NumPy array based on the + # library's type stubs, but matplotlib's to_rgba function correctly + # handles scalar inputs at runtime. This is a known limitation of the stubs. + rgba_value = scalar_map.to_rgba(index) # type: ignore[arg-type] + return cast(Color, rgba_value) + + return wrapper + + def make_stacked_bar_plot( + self, data: PlotData, xlabel: str, ylabel: str, xvar: str, title: str + ) -> None: + """Creates and saves a stacked bar plot.""" random.seed(10) + data_copy = data.copy() - handles = list() - xaxis = data[xvar] - data.pop('c', 0) - data.pop(xvar, 0) - stacked_bars = data.keys() - color_map_for_bars = dict() - plt.figure() + xaxis = data_copy.pop(xvar, []) + data_copy.pop('c', None) + stacked_bars = list(data_copy.keys()) + fig: Figure = plt.figure() cmap = self.get_cmap(len(stacked_bars)) - for i in range(0, len(stacked_bars)): - # colors.append(self.generate_new_color(colors,pastel_factor = 0.9)) - # colorMapForBars[data.keys()[i]]=colors[i] - color_map_for_bars[list(data.keys())[i]] = cmap(i) - - width = min([xaxis[i + 1] - xaxis[i] for i in range(0, len(xaxis) - 1)]) / 2.0 - b = [0] * len(xaxis) + color_map_for_bars = {bar_name: cmap(i) for i, bar_name in enumerate(stacked_bars)} - # plt.figure() + width = ( + min(xaxis[i + 1] - xaxis[i] for i in range(len(xaxis) - 1)) / 2.0 + if len(xaxis) > 1 + else 1.0 + ) + bottom = [0.0] * len(xaxis) + handles = [] for bar in stacked_bars: - h = plt.bar(xaxis, data[bar], width, bottom=b, color=color_map_for_bars[bar]) + values = data_copy[bar] + h = plt.bar(xaxis, values, width, bottom=bottom, color=color_map_for_bars[bar]) handles.append(h) - b = [b[j] + data[bar][j] for j in range(0, len(b))] + bottom = [b + v for b, v in zip(bottom, values, strict=False)] plt.xlabel(xlabel) plt.ylabel(ylabel) - # plt.xticks([width*0.5 + i for i in xaxis], [str(i) for i in xaxis]) - plt.xticks([i for i in xaxis], [str(i) for i in xaxis]) + plt.xticks(xaxis, [str(int(x)) for x in xaxis]) plt.title(title) - lgd = plt.legend( + lgd: Legend = plt.legend( [h[0] for h in handles], stacked_bars, bbox_to_anchor=(1.2, 1), fontsize=7.5 ) - # plt.show() plt.savefig(self.output_file_name, bbox_extra_artists=(lgd,), bbox_inches='tight') + plt.close(fig) - def make_line_plot(self, plot_var, label, title): - handles = list() - periods = plot_var['periods'] - plot_var.pop('periods', 0) - techs = plot_var.keys() + def make_line_plot(self, plot_var: PlotData, label: str, title: str) -> None: + """Creates and saves a line plot.""" random.seed(10) - color_map = dict() - plt.figure() + periods = plot_var.pop('periods', []) + techs = list(plot_var.keys()) + + fig: Figure = plt.figure() cmap = self.get_cmap(len(techs)) - for i in range(0, len(techs)): - # colors.append(self.generate_new_color(colors,pastel_factor = 0.9)) - # color_map[plot_var.keys()[i]]=colors[i] - color_map[plot_var.keys()[i]] = cmap(i) + color_map = {tech: cmap(i) for i, tech in enumerate(techs)} + handles = [] for tech in techs: - h = plt.plot(periods, plot_var[tech], color=color_map[tech], linestyle='--', marker='o') + values = plot_var[tech] + h = plt.plot(periods, values, color=color_map[tech], linestyle='--', marker='o') handles.append(h) plt.xlabel('Years') plt.ylabel(label) - # plt.xticks([i + width*0.5 for i in periods], [str(i) for i in periods]) - plt.xticks(periods) + plt.xticks(periods, [str(int(p)) for p in periods]) plt.title(title) - lgd = plt.legend([h[0] for h in handles], techs, bbox_to_anchor=(1.2, 1), fontsize=7.5) - # plt.show() + lgd: Legend = plt.legend( + [h[0] for h in handles], techs, bbox_to_anchor=(1.2, 1), fontsize=7.5 + ) plt.savefig(self.output_file_name, bbox_extra_artists=(lgd,), bbox_inches='tight') + plt.close(fig) -# Function used for command line purposes. Parses arguments and then calls relevent functions. -def generate_plot(args): +def generate_plot(args: list[str]) -> None: + """Parses command line arguments and calls relevant functions.""" parser = argparse.ArgumentParser(description='Generate Output Plot') parser.add_argument( '-i', @@ -355,7 +336,7 @@ def generate_plot(args): '--scenario', action='store', dest='scenario', - help='Model run scenario name', + help='Model run a scenario name', required=True, ) parser.add_argument( @@ -392,31 +373,29 @@ def generate_plot(args): ) options = parser.parse_args(args) - - result = OutputPlotGenerator( + result_generator = OutputPlotGenerator( options.input, options.region, options.scenario, options.super_categories ) - error = '' + + error_path = '' if options.type == 'capacity': - error = result.generate_plot_for_capacity( + error_path = result_generator.generate_plot_for_capacity( options.sector, options.super_categories, options.output_dir ) elif options.type == 'flow': - error = result.generate_plot_for_output_flow( + error_path = result_generator.generate_plot_for_output_flow( options.sector, options.super_categories, options.output_dir ) elif options.type == 'emissions': - error = result.generate_plot_for_emissions( + error_path = result_generator.generate_plot_for_emissions( options.sector, options.super_categories, options.output_dir ) - if error == '': - print("Error: The sector doesn't exist for the selected plot type and database") + if not error_path: + print("Error: The sector doesn't exist for the selected plot type and database.") else: - print( - 'Done. Look for output plot images in directory:' - + os.path.join(options.output_dir, error) - ) + full_path = os.path.join(options.output_dir, os.path.dirname(error_path)) + print(f'Done. Look for output plot images in directory: {os.path.abspath(full_path)}') if __name__ == '__main__': diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index 3b4532cac..8d53bbcec 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -240,7 +240,7 @@ def _fetch_all_tech_definitions( cur: sqlite3.Cursor, myopic_index: MyopicIndex | None ) -> list[ tuple[Region, Commodity, Technology, Vintage, Commodity, int] - | tuple[Region, Commodity, Technology, Vintage, Commodity, int, str] + | tuple[Region, Commodity, Technology, Vintage, Commodity, int, Sector] ]: """Fetches the main block of technology efficiency and lifetime data.""" default_lifetime = TemoaModel.default_lifetime_tech From 4d244b613eed226fcf49d618b83b0f4c19552ff8 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 31 Oct 2025 16:20:44 -0400 Subject: [PATCH 301/587] fixing test failures caused by typing imports at runtime --- temoa/components/technology.py | 2 +- temoa/utilities/graph_utils.py | 24 ++++++++++++++++-------- temoa/utilities/visualizer.py | 4 ++-- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/temoa/components/technology.py b/temoa/components/technology.py index 42f55dc86..121dc4714 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -20,7 +20,7 @@ if TYPE_CHECKING: from temoa.core.model import TemoaModel - from temoa.types import Period, Region, Technology, Vintage +from temoa.types import Period, Region, Technology, Vintage logger = getLogger(__name__) diff --git a/temoa/utilities/graph_utils.py b/temoa/utilities/graph_utils.py index 756e7e24f..33984a000 100644 --- a/temoa/utilities/graph_utils.py +++ b/temoa/utilities/graph_utils.py @@ -7,13 +7,15 @@ in vis.js converge to a cleaner and more readable state faster. """ +from __future__ import annotations + import json import logging import math import random import uuid from collections.abc import Iterable -from typing import Any, TypeVar +from typing import TYPE_CHECKING, Any, TypeVar import networkx as nx @@ -22,13 +24,19 @@ logger = logging.getLogger(__name__) -GraphType = TypeVar( - 'GraphType', - nx.Graph[Commodity | Technology | str], - nx.DiGraph[Commodity | Technology | str], - nx.MultiGraph[Commodity | Technology | str], - nx.MultiDiGraph[Commodity | Technology | str], -) + +if TYPE_CHECKING: + GraphType = TypeVar( + 'GraphType', + nx.Graph[Commodity | Technology | str], + nx.DiGraph[Commodity | Technology | str], + nx.MultiGraph[Commodity | Technology | str], + nx.MultiDiGraph[Commodity | Technology | str], + ) +else: + # At runtime, use the base types which are not subscripted. + # The TypeVar still enforces that the graph type is one of these. + GraphType = TypeVar('GraphType', nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph) def convert_graph_to_json( diff --git a/temoa/utilities/visualizer.py b/temoa/utilities/visualizer.py index 2ea4761dd..faf9de663 100644 --- a/temoa/utilities/visualizer.py +++ b/temoa/utilities/visualizer.py @@ -53,12 +53,12 @@ def make_nx_graph( driven_commodities: set[Commodity], other_orphan_commodities: set[Commodity], demand_orphan_commodities: set[Commodity], -) -> nx.MultiDiGraph[str]: +) -> nx.MultiDiGraph: """ Make an nx graph, grouping parallel edges to prevent label overlap. """ - dg: nx.MultiDiGraph[str] = nx.MultiDiGraph() + dg: nx.MultiDiGraph = nx.MultiDiGraph() connections = tuple(connections) # Freeze for multiple iterations node_styles_by_layer = { From c73192cac7741adbf98cf097b860cfe689c68d58 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sun, 2 Nov 2025 19:14:02 -0500 Subject: [PATCH 302/587] expanding typing more broadly and using stricter types --- docs/source/conf.py | 4 +-- pyproject.toml | 2 +- temoa/model_checking/commodity_graph.py | 14 +++++----- temoa/model_checking/commodity_network.py | 4 ++- .../commodity_network_manager.py | 2 +- temoa/model_checking/network_model_data.py | 26 ++++++++++--------- temoa/utilities/graph_utils.py | 12 ++++----- temoa/utilities/visualizer.py | 14 +++++----- 8 files changed, 42 insertions(+), 36 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 00bd4b367..8c897df11 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,8 +1,8 @@ -# -*- coding: utf-8 -*- # import os import sys import time +from typing import Any # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -96,7 +96,7 @@ # this stylesheet eliminates fixed width and is located in the _static directory -def setup(app): +def setup(app: Any) -> None: app.add_css_file('my_theme.css') diff --git a/pyproject.toml b/pyproject.toml index f1a14c526..d649d2551 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -109,7 +109,7 @@ python_version = "3.12" mypy_path = "stubs" # Exclude specific directories from type checking will try to add them back gradually -exclude = "(?x)(^tests/|^temoa/extensions/|^docs/)" +exclude = "(?x)(^tests/|^temoa/extensions/|^temoa/utilities/)" # Strict typing for our own code disallow_untyped_defs = true diff --git a/temoa/model_checking/commodity_graph.py b/temoa/model_checking/commodity_graph.py index 80845812e..66001ee22 100644 --- a/temoa/model_checking/commodity_graph.py +++ b/temoa/model_checking/commodity_graph.py @@ -3,7 +3,7 @@ import logging from collections import defaultdict from collections.abc import Iterable -from typing import Any +from typing import Any, cast import networkx as nx @@ -23,7 +23,7 @@ def generate_technology_graph( all_edges: Iterable[EdgeTuple], source_commodities: set[Commodity], demand_commodities: set[Commodity], - sector_colors: dict[str, str], + sector_colors: dict[Sector, str], ) -> nx.MultiDiGraph[str]: """ Generates a technology-centric graph with a pre-computed initial layout. @@ -47,7 +47,7 @@ def generate_technology_graph( # Pass 2: Create a single, correctly styled node for each unique technology. for tech_name, info in tech_info.items(): - pos_attrs = tech_positions.get(tech_name, {}) + pos_attrs = tech_positions.get(cast(Technology, tech_name)) or {} sector = info['sector'] color_obj: dict[str, str] = {} @@ -108,7 +108,7 @@ def generate_commodity_graph( demand_orphans: Iterable[EdgeTuple], other_orphans: Iterable[EdgeTuple], driven_techs: Iterable[EdgeTuple], -) -> tuple[nx.MultiDiGraph[str], dict[str, str]]: +) -> tuple[nx.MultiDiGraph[str], dict[Sector, str]]: """ Generates the commodity-centric graph and its associated color scheme. In this view, commodities are nodes and technologies are grouped into edges. @@ -147,8 +147,8 @@ def generate_commodity_graph( commodity_sector_counts[tech.input_comm][tech.sector] += 1 commodity_sector_counts[tech.output_comm][tech.sector] += 1 - commodity_to_primary_sector = { - comm: max(counts, key=lambda k: counts[k]) + commodity_to_primary_sector: dict[Commodity, Sector] = { + cast(Commodity, comm): cast(Sector, max(counts, key=lambda k: counts[k])) for comm, counts in commodity_sector_counts.items() if counts } @@ -290,7 +290,7 @@ def visualize_graph( output_filename=output_file, html_title=f'Network Graphs - {region} {period}', sectors=unique_sectors, - color_legend_map=sector_colors, + color_legend_map=cast(dict[str, str], sector_colors), style_legend_map=style_legend_map, show_browser=False, ) diff --git a/temoa/model_checking/commodity_network.py b/temoa/model_checking/commodity_network.py index ebe6c9ef8..b21d65bc1 100644 --- a/temoa/model_checking/commodity_network.py +++ b/temoa/model_checking/commodity_network.py @@ -25,6 +25,8 @@ # Represents a technology link: (input_commodity, tech_name) type TechLink = tuple[Commodity, Technology] +# Represents a pair of linked technologies: (driver_tech, driven_tech) +type LinkedTechPair = tuple[Technology, Technology] # Represents a full connection: (input_commodity, tech_name, output_commodity) type TechConnection = tuple[Commodity, Technology, Commodity] # Adjacency dict mapping: {output_comm: set of (input_comm, tech_name)} @@ -78,7 +80,7 @@ def __init__(self, region: Region, period: Period, model_data: NetworkModelData) self.tech_inputs: dict[Technology, set[Commodity]] = defaultdict(set) self.tech_outputs: dict[Technology, set[Commodity]] = defaultdict(set) self.connections: ForwardConnections = defaultdict(set) - self.viable_linked_tech: set[TechLink] = set() + self.viable_linked_tech: set[LinkedTechPair] = set() self._load_connections() self.prescreen_linked_tech() diff --git a/temoa/model_checking/commodity_network_manager.py b/temoa/model_checking/commodity_network_manager.py index 61f6486a8..11d065492 100644 --- a/temoa/model_checking/commodity_network_manager.py +++ b/temoa/model_checking/commodity_network_manager.py @@ -34,7 +34,7 @@ class CommodityNetworkManager: def __init__(self, periods: Iterable[str | int], network_data: NetworkModelData) -> None: self.analyzed: bool = False - self.periods: list[Period] = sorted(map(int, periods)) + self.periods: list[Period] = sorted([Period(int(p)) for p in periods]) self.orig_data: NetworkModelData = network_data self.filtered_data: NetworkModelData | None = None self.regions: set[Region] | None = None diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index 8d53bbcec..3721d09a6 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -430,35 +430,37 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - res.available_techs[r, p].add( EdgeTuple( region=r, - input_comm=tech, - tech='EndOfLife', + input_comm=cast(Commodity, tech), + tech=cast(Technology, 'EndOfLife'), vintage=v, output_comm=eol_oc, lifetime=lifetime, - sector='Other', + sector=cast(Sector, 'Other'), ) ) - res.source_commodities[r, p].add(tech) - res.capacity_commodities.add(tech) + res.source_commodities[r, p].add(cast(Commodity, tech)) + res.capacity_commodities.add(cast(Commodity, tech)) if eol_oc in basic_data['waste_commodities_all']: res.waste_commodities[r, p].add(eol_oc) # --- 3. Process Construction --- for r, ic, tech, v in lookup_data['construction']: - construction_lifetime = basic_data['period_length'].get(v, 1) - res.available_techs[r, v].add( + construction_lifetime = basic_data['period_length'].get(cast(Period, v), cast(Period, 1)) + res.available_techs[r, cast(Period, v)].add( EdgeTuple( region=r, input_comm=ic, - tech='Construction', + tech=cast(Technology, 'Construction'), vintage=v, - output_comm=tech, + output_comm=cast( + Commodity, tech + ), # commodity is kind of input to the capacity of the technology/vice versa lifetime=construction_lifetime, - sector='Other', + sector=cast(Sector, 'Other'), ) ) - res.demand_commodities[r, v].add(tech) - res.capacity_commodities.add(tech) + res.demand_commodities[r, cast(Period, v)].add(cast(Commodity, tech)) + res.capacity_commodities.add(cast(Commodity, tech)) living_techs.add(tech) # --- 4. Process Linked Techs and Other Metadata --- diff --git a/temoa/utilities/graph_utils.py b/temoa/utilities/graph_utils.py index 33984a000..4975270fb 100644 --- a/temoa/utilities/graph_utils.py +++ b/temoa/utilities/graph_utils.py @@ -14,13 +14,13 @@ import math import random import uuid -from collections.abc import Iterable -from typing import TYPE_CHECKING, Any, TypeVar +from collections.abc import Iterable, Sequence +from typing import TYPE_CHECKING, Any, TypeVar, cast import networkx as nx from temoa.model_checking.network_model_data import EdgeTuple -from temoa.types.core_types import Commodity, Technology +from temoa.types.core_types import Commodity, Sector, Technology logger = logging.getLogger(__name__) @@ -144,8 +144,8 @@ def calculate_source_positions( def calculate_initial_positions( node_layer_map: dict[str, int], - commodity_to_primary_sector: dict[str, str], - unique_sectors: list[str], + commodity_to_primary_sector: dict[Commodity, Sector], + unique_sectors: Sequence[Sector] | None = None, ) -> dict[str, dict[str, Any]]: """ Calculates an initial (x, y) layout for all nodes to provide a better @@ -158,7 +158,7 @@ def calculate_initial_positions( positions: dict[str, dict[str, Any]] = {} # Prepare to lay out the remaining (non-fixed) nodes: all layers except 1 - nodes_to_place = {n for n, layer in node_layer_map.items() if layer != 1} + nodes_to_place = {cast(Commodity, n) for n, layer in node_layer_map.items() if layer != 1} if not nodes_to_place: return positions diff --git a/temoa/utilities/visualizer.py b/temoa/utilities/visualizer.py index faf9de663..a30d10a49 100644 --- a/temoa/utilities/visualizer.py +++ b/temoa/utilities/visualizer.py @@ -10,12 +10,14 @@ This code is designed to replace previous graphing dependencies like `gravis`. """ +from __future__ import annotations + import copy import json import logging import uuid from collections import defaultdict -from collections.abc import Iterable +from collections.abc import Iterable, Sequence from pathlib import Path from typing import Any @@ -48,17 +50,17 @@ def make_nx_graph( node_positions: dict[str, dict[str, Any]], commodity_to_primary_sector: dict[Commodity, Sector], driven_tech_names: set[Technology], - other_orphan_names: set[Commodity], - demand_orphan_names: set[Commodity], + other_orphan_names: set[Technology], + demand_orphan_names: set[Technology], driven_commodities: set[Commodity], other_orphan_commodities: set[Commodity], demand_orphan_commodities: set[Commodity], -) -> nx.MultiDiGraph: +) -> nx.MultiDiGraph[str]: """ Make an nx graph, grouping parallel edges to prevent label overlap. """ - dg: nx.MultiDiGraph = nx.MultiDiGraph() + dg: nx.MultiDiGraph[str] = nx.MultiDiGraph() connections = tuple(connections) # Freeze for multiple iterations node_styles_by_layer = { @@ -189,7 +191,7 @@ def nx_to_vis( vis_options: dict[str, Any] | None = None, override_node_properties: dict[str, Any] | None = None, override_edge_properties: dict[str, Any] | None = None, - sectors: list[str] | None = None, + sectors: Sequence[Sector] | None = None, color_legend_map: dict[str, str] | None = None, style_legend_map: list[dict[str, Any]] | None = None, secondary_graph: GraphType | None = None, From d5e4754a76f891d3bdab7f2e51bc638b0fcd1f3b Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Mon, 3 Nov 2025 08:48:24 -0500 Subject: [PATCH 303/587] making some typing cleaner --- temoa/components/limits.py | 6 +++--- temoa/model_checking/commodity_graph.py | 4 ++-- temoa/types/core_types.py | 2 -- temoa/types/dict_types.py | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/temoa/components/limits.py b/temoa/components/limits.py index e6651ef6c..97b1a35d4 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -14,7 +14,7 @@ import sys from logging import getLogger -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, cast from pyomo.environ import Constraint, quicksum, value @@ -419,7 +419,7 @@ def limit_new_capacity_share_constraint( model.V_NewCapacity[_r, _t, p] for _t in sub_group for _r in regions - if (_r, _t, p) in model.processPeriods + if (_r, _t, cast(Vintage, p)) in model.processPeriods ) super_group = technology.gather_group_techs(model, g2) @@ -427,7 +427,7 @@ def limit_new_capacity_share_constraint( model.V_NewCapacity[_r, _t, p] for _t in super_group for _r in regions - if (_r, _t, p) in model.processPeriods + if (_r, _t, cast(Vintage, p)) in model.processPeriods ) share_lim = value(model.LimitNewCapacityShare[r, p, g1, g2, op]) diff --git a/temoa/model_checking/commodity_graph.py b/temoa/model_checking/commodity_graph.py index 66001ee22..17c1eb716 100644 --- a/temoa/model_checking/commodity_graph.py +++ b/temoa/model_checking/commodity_graph.py @@ -139,7 +139,7 @@ def generate_commodity_graph( } default_color = '#A9A9A9' - commodity_sector_counts: defaultdict[str, defaultdict[str, int]] = defaultdict( + commodity_sector_counts: defaultdict[Commodity, defaultdict[Sector, int]] = defaultdict( lambda: defaultdict(int) ) for tech in all_edge_tuples: @@ -148,7 +148,7 @@ def generate_commodity_graph( commodity_sector_counts[tech.output_comm][tech.sector] += 1 commodity_to_primary_sector: dict[Commodity, Sector] = { - cast(Commodity, comm): cast(Sector, max(counts, key=lambda k: counts[k])) + comm: max(counts, key=lambda k: counts[k]) for comm, counts in commodity_sector_counts.items() if counts } diff --git a/temoa/types/core_types.py b/temoa/types/core_types.py index 12b0634ea..bfb91037f 100644 --- a/temoa/types/core_types.py +++ b/temoa/types/core_types.py @@ -18,8 +18,6 @@ Season = NewType('Season', str) TimeOfDay = NewType('TimeOfDay', str) Commodity = NewType('Commodity', str) -InputCommodity = NewType('InputCommodity', Commodity) -OutputCommodity = NewType('OutputCommodity', Commodity) Process = NewType('Process', str) # Type aliases for common data structures diff --git a/temoa/types/dict_types.py b/temoa/types/dict_types.py index 5a0f7c667..8fb2fb3da 100644 --- a/temoa/types/dict_types.py +++ b/temoa/types/dict_types.py @@ -19,7 +19,7 @@ ] ProcessTechsDict = dict[tuple[Region, Period, Commodity], set[Technology]] ProcessReservePeriodsDict = dict[tuple[Region, Period], set[tuple[Technology, Vintage]]] -ProcessPeriodsDict = dict[tuple[Region, Technology, Period], set[Period]] +ProcessPeriodsDict = dict[tuple[Region, Technology, Vintage], set[Period]] RetirementPeriodsDict = dict[tuple[Region, Technology, Vintage], set[Period]] ProcessVintagesDict = dict[tuple[Region, Period, Technology], set[Vintage]] SurvivalCurvePeriodsDict = dict[tuple[Region, Technology, Vintage], set[Period]] From 4890fb468c644a57ea76c61969a3b59e4a7fa2b5 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Mon, 3 Nov 2025 11:44:40 -0500 Subject: [PATCH 304/587] modernized CLI, streamlined temoasequencer API, added and updated tests --- .gitignore | 1 - main.py | 186 --------------- pyproject.toml | 6 + requirements-dev.txt | 17 ++ requirements.txt | 20 +- temoa/_internal/temoa_sequencer.py | 353 ++++++++++++---------------- temoa/cli.py | 202 ++++++++++++++++ tests/conftest.py | 56 ++--- tests/test_cli.py | 79 +++++++ tests/test_emission_results.py | 53 ++--- tests/test_main.py | 59 ----- tests/test_material_results.py | 64 ++--- tests/test_model.py | 53 ++--- tests/test_set_consistency.py | 51 ++-- tests/test_temoa_sequencer.py | 94 ++++---- uv.lock | 360 ++++++++++++++++++++--------- 16 files changed, 850 insertions(+), 804 deletions(-) delete mode 100644 main.py create mode 100644 temoa/cli.py create mode 100644 tests/test_cli.py delete mode 100644 tests/test_main.py diff --git a/.gitignore b/.gitignore index 221ddf110..7a18524ea 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,6 @@ !CONTRIBUTING.md !.pre-commit-config.yaml !.coderabbit.yaml -!FEATURE_BRANCH.md # recursively re-ignore __pycache__ diff --git a/main.py b/main.py deleted file mode 100644 index 3cd1adb60..000000000 --- a/main.py +++ /dev/null @@ -1,186 +0,0 @@ -""" -Entry point for running the model. -""" - -import argparse -import logging -import os -import sys -from datetime import datetime -from pathlib import Path - -from deprecated import deprecated - -import definitions -from definitions import PROJECT_ROOT -from temoa._internal.temoa_sequencer import TemoaSequencer -from temoa.core.model import TemoaModel -from temoa.core.modes import TemoaMode -from temoa.version_information import TEMOA_MAJOR, TEMOA_MINOR - -# Written by: J. F. Hyink -# jeff@westernspark.us -# https://westernspark.us -# Created on: 7/18/23 - -logger = logging.getLogger(__name__) - - -@deprecated('currently deprecated functionality') -def runModelUI(config_filename: str) -> None: - """This function launches the model run from the Temoa GUI""" - raise NotImplementedError - # solver = TemoaSolver(model, config_filename) - # for k in solver.createAndSolve(): - # yield k - # # yield " " * 1024 - - -def runModel(arg_list: list[str] | None = None) -> TemoaModel | None: - """ - Start the program - :param arg_list: optional arg_list - :return: A TemoaModel instance (if asked for), more likely None - """ - options = parse_args(arg_list=arg_list) - mode = TemoaMode.BUILD_ONLY if options.build_only else None - ts = TemoaSequencer( - config_file=options.config_file, - output_path=options.output_path, - mode_override=mode, - silent=options.silent, - ) - result = ts.start() - return result - - -def parse_args(arg_list: list[str] | None) -> argparse.Namespace: - """ - Parse the command line args (CLA) if None is passed in (normal operation) or the arg_list, - if provided :param arg_list: default None --> process sys.argv :return: options Namespace - """ - parser = argparse.ArgumentParser() - parser.add_argument( - '--config', - help='Path to file containing configuration information.', - action='store', - dest='config_file', - default=None, - ) - parser.add_argument( - '-b', - '--build_only', - help='Build and return an unsolved TemoaModel instance.', - action='store_true', - dest='build_only', - ) - parser.add_argument( - '-s', '--silent', help='Silent run. No prompts.', action='store_true', dest='silent' - ) - parser.add_argument( - '-d', - '--debug', - help='Set logging level to DEBUG to see debugging output in log file.', - action='store_true', - dest='debug', - ) - parser.add_argument( - '-o', - '--output_path', - help='Set the path for log and program outputs to an existing directory. ' - 'Default is time-stamped folder in output_files.', - action='store', - dest='output_path', - ) - parser.add_argument( - '--how_to_cite', - help='Show citation information for publishing purposes.', - action='store_true', - dest='how_to_cite', - ) - parser.add_argument( - '-v', '--version', help='Show current Temoa version', action='store_true', dest='version' - ) - - options = parser.parse_args(args=arg_list) # dev note: The default (if None) is sys.argv - - # handle the non-execution options and quit - if options.how_to_cite or options.version: - if options.version: - version = f'{TEMOA_MAJOR}.{TEMOA_MINOR}' - print(f'Temoa Version: {version}') - if options.how_to_cite: - raise NotImplementedError('Need this information...') - sys.exit() - - # validate the output folder if provided, or make the default - output_path: Path - if options.output_path: - if not Path(options.output_path).is_dir(): - raise FileNotFoundError( - f'The selected output path directory {options.output_path} could not be located.' - ) - else: - output_path = Path(options.output_path) - else: - output_path = create_output_folder() - # capture it in options - options.output_path = output_path - definitions.set_OUTPUT_PATH(options.output_path) - - # initialize the logging now that option & path are known... - setup_logging(output_path=output_path, debug_level=options.debug) - - # check for config file existence - if not options.config_file: - logger.error( - 'No config file found in CLA. Temoa needs a config file to operate, see documentation.' - ) - raise AttributeError('no config file provided.') - else: - # convert it to a Path, if it isn't one already - options.config_file = Path(options.config_file) - if not options.config_file.is_file(): - logger.error('Config file provided: %s is not valid', options.config_file) - raise FileNotFoundError('Config file not found. See log for info.') - - logger.debug('Received Command Line Args: %s', sys.argv[1:]) - - if options.build_only: - logger.info('Build-only selected.') - return options - - -def create_output_folder() -> Path: - """ - create a time-stamped folder as the default catch-all for outputs - :return: Path to default folder - """ - output_path = Path(PROJECT_ROOT, 'output_files', datetime.now().strftime('%Y-%m-%d %H%Mh')) - if not output_path.is_dir(): - output_path.mkdir() - return output_path - - -def setup_logging(output_path: Path, debug_level: bool = False) -> None: - # set up logger - if debug_level: - level = logging.DEBUG - else: - level = logging.INFO - logging.getLogger('pyomo').setLevel(logging.WARNING) - logging.getLogger('matplotlib').setLevel(logging.WARNING) - filename = 'log.log' - logging.basicConfig( - filename=os.path.join(output_path, filename), - filemode='w', - format='%(asctime)s | %(module)s | %(levelname)s | %(message)s', - datefmt='%d-%b-%y %H:%M:%S', - level=level, - force=True, - ) - logger.info('*** STARTING TEMOA ***') - - -if __name__ == '__main__': - options = runModel() diff --git a/pyproject.toml b/pyproject.toml index d649d2551..f682745cc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,6 +9,7 @@ authors = [ { name = "TemoaProject Team", email = "info@temoaproject.org" } ] + dependencies = [ "pyomo>=6.8.0", "matplotlib==3.9.2", @@ -27,9 +28,14 @@ dependencies = [ "networkx>=3.3", "highspy>=1.7.2", "scipy>=1.14.1", + "typer>=0.20.0", + "rich>=14.2.0", ] +[project.scripts] +temoa = "temoa.cli:app" + [dependency-groups] dev = [ "types-deprecated>=1.2.15.20250304", diff --git a/requirements-dev.txt b/requirements-dev.txt index 4fa08e198..f86d17a9a 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -8,6 +8,8 @@ certifi==2025.7.14 # via requests charset-normalizer==3.4.2 # via requests +click==8.3.0 + # via typer contourpy==1.3.2 # via matplotlib cycler==0.12.1 @@ -46,6 +48,8 @@ kiwisolver==1.4.8 # via matplotlib latexcodec==3.0.1 # via pybtex +markdown-it-py==4.0.0 + # via rich markupsafe==3.0.2 # via jinja2 matplotlib==3.9.2 @@ -53,6 +57,8 @@ matplotlib==3.9.2 # temoa (pyproject.toml) # salib # seaborn +mdurl==0.1.2 + # via markdown-it-py multiprocess==0.70.18 # via salib networkx==3.5 @@ -97,6 +103,7 @@ pydoe==0.3.8 pygments==2.19.2 # via # pytest + # rich # sphinx pyomo==6.9.2 # via temoa (pyproject.toml) @@ -114,6 +121,10 @@ pyyaml==6.0.2 # via pybtex requests==2.32.4 # via sphinx +rich==14.2.0 + # via + # temoa (pyproject.toml) + # typer roman-numerals-py==3.1.0 # via sphinx salib==1.5.1 @@ -125,6 +136,8 @@ scipy==1.16.0 # salib seaborn==0.13.2 # via temoa (pyproject.toml) +shellingham==1.5.4 + # via typer six==1.17.0 # via python-dateutil snowballstemmer==3.0.1 @@ -159,6 +172,10 @@ sphinxcontrib-serializinghtml==2.0.0 # sphinx tabulate==0.9.0 # via temoa (pyproject.toml) +typer==0.20.0 + # via temoa (pyproject.toml) +typing-extensions==4.15.0 + # via typer tzdata==2025.2 # via pandas urllib3==2.5.0 diff --git a/requirements.txt b/requirements.txt index 99fc9963c..4fe33fddb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,7 @@ # This file was autogenerated by uv via the following command: # uv pip compile pyproject.toml -o requirements.txt +click==8.3.0 + # via typer contourpy==1.3.2 # via matplotlib cycler==0.12.1 @@ -22,11 +24,15 @@ joblib==1.5.1 # via temoa (pyproject.toml) kiwisolver==1.4.8 # via matplotlib +markdown-it-py==4.0.0 + # via rich matplotlib==3.9.2 # via # temoa (pyproject.toml) # salib # seaborn +mdurl==0.1.2 + # via markdown-it-py multiprocess==0.70.18 # via salib networkx==3.5 @@ -62,7 +68,9 @@ ply==3.11 pydoe==0.3.8 # via temoa (pyproject.toml) pygments==2.19.2 - # via pytest + # via + # pytest + # rich pyomo==6.9.2 # via temoa (pyproject.toml) pyparsing==3.2.3 @@ -75,6 +83,10 @@ python-dateutil==2.9.0.post0 # pandas pytz==2025.2 # via pandas +rich==14.2.0 + # via + # temoa (pyproject.toml) + # typer salib==1.5.1 # via temoa (pyproject.toml) scipy==1.16.0 @@ -84,10 +96,16 @@ scipy==1.16.0 # salib seaborn==0.13.2 # via temoa (pyproject.toml) +shellingham==1.5.4 + # via typer six==1.17.0 # via python-dateutil tabulate==0.9.0 # via temoa (pyproject.toml) +typer==0.20.0 + # via temoa (pyproject.toml) +typing-extensions==4.15.0 + # via typer tzdata==2025.2 # via pandas wrapt==1.17.2 diff --git a/temoa/_internal/temoa_sequencer.py b/temoa/_internal/temoa_sequencer.py index 6b020f557..b6eaf5904 100644 --- a/temoa/_internal/temoa_sequencer.py +++ b/temoa/_internal/temoa_sequencer.py @@ -4,35 +4,10 @@ up the necessary run(s) to accomplish that. Several processing modes have requirements for multiple runs, and the Temoa Sequencer may hand off to a mode-specific sequencer -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 11/14/23 - -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . """ import sqlite3 -import sys from logging import getLogger -from pathlib import Path import pyomo.opt @@ -65,229 +40,191 @@ class TemoaSequencer: - """A Sequencer instance to control all runs for a scenario based on the TemoaMode""" + """A Sequencer instance to control all runs for a scenario based on the TemoaMode.""" def __init__( self, - config_file: str | Path, - output_path: str | Path, + config: TemoaConfig, mode_override: TemoaMode | None = None, - silent: bool = False, - **kwargs: object, ) -> None: """ - Create a new Sequencer - :param config_file: Optional path to config file. If not provided, it will be read - from Command Line Args - :param mode_override: Optional override to execution mode. If not provided, - it will be read from config file - :param silent: boolean to indicate whether to silence run-time feedback - """ - self.config: TemoaConfig | None = None - self.temoa_mode: TemoaMode - - self.config_file: Path = Path(config_file) - # check it... - if not self.config_file.is_file(): - logger.error( - 'Config file location passed %s does not point to a file', self.config_file - ) - raise FileNotFoundError(f'Invalid config file: {self.config_file}') - - self.output_path: Path = Path(output_path) - # check it... - if not self.output_path.is_dir(): - logger.error('Output directory does not exist: %s', self.output_path) - raise FileNotFoundError(f'Invalid output directory: {self.output_path}') + Create a new Sequencer. - self.mode_override: TemoaMode | None = mode_override + :param config: A fully constructed TemoaConfig object. + :param mode_override: Optional override to the execution mode from the config. + """ + self.config = config + self.temoa_mode = config.scenario_mode - # for feedback to user - self.silent = silent + # Handle and log the mode override if provided + if mode_override and mode_override != self.config.scenario_mode: + self.temoa_mode = mode_override + self.config.scenario_mode = mode_override + logger.info(f'Temoa Mode overridden by caller to: {self.temoa_mode}') - # for results catching for perfect_foresight, other modes / testing + # for results catching for perfect_foresight or testing self.pf_results: pyomo.opt.SolverResults | None = None self.pf_solved_instance: TemoaModel | None = None - def start(self) -> TemoaModel | None: - """Start the processing of the scenario""" - - # ----- Run the "preliminaries" - # Build a TemoaConfig - self.config = TemoaConfig.build_config( - config_file=self.config_file, output_path=self.output_path, silent=self.silent - ) - - # Run some checks... - good = True - good &= check_python_version(MIN_PYTHON_MAJOR, MIN_PYTHON_MINOR) - good &= check_database_version( + def _run_preliminary_checks(self) -> None: + """Runs pre-flight checks and raises an error if any fail.""" + checks_ok = True + checks_ok &= check_python_version(MIN_PYTHON_MAJOR, MIN_PYTHON_MINOR) + checks_ok &= check_database_version( self.config, db_major_reqd=DB_MAJOR_VERSION, min_db_minor=MIN_DB_MINOR_VERSION ) - if not good: - logger.error('Failed pre-run checks... See log file for details') - sys.exit(-1) - - # Distill the TemoaMode - if self.mode_override and self.mode_override != self.config.scenario_mode: - # capture and log the override... - self.temoa_mode = self.mode_override - if self.config: # register the override in the config - self.config.scenario_mode = self.mode_override - logger.info('Temoa Mode overridden to be: %s', self.temoa_mode) - else: - self.temoa_mode = self.config.scenario_mode - # check it... - if not isinstance(self.temoa_mode, TemoaMode): - logger.error( # type: ignore[unreachable] - 'Temoa Mode not set properly. Override: %s, Config File: %s', - self.mode_override, - self.config.scenario_mode, - ) - raise RuntimeError('Problem with mode selection, see log file.') - - # Get user confirmation if not silent - if not self.silent: - try: - print(self.config.__repr__()) - print('\nPlease press enter to continue or Ctrl+C to quit.\n') - input() # Give the user a chance to confirm input - except KeyboardInterrupt: - logger.warning('User aborted from confirmation page. Exiting') - print('\n\nUser requested quit. Exiting Temoa ...\n') - sys.exit() - - # ---- Select execution path based on mode ---- + if not checks_ok: + # The specific reasons for failure are already in the log. + raise RuntimeError('Failed pre-run checks. See log file for details.') + + def build_model(self) -> TemoaModel: + """ + Builds and returns an unsolved TemoaModel instance. + This is the dedicated method for the 'BUILD_ONLY' mode. + """ + logger.info('Starting model build process (build-only mode).') + # Ensure certain features that don't apply to a simple build are disabled + if self.config.source_trace: + self.config.source_trace = False + logger.warning('Source trace disabled for build-only mode.') + if self.config.plot_commodity_network: + self.config.plot_commodity_network = False + logger.warning('Commodity network plotting disabled for build-only mode.') + if self.config.price_check: + logger.warning('Price check disabled for build-only mode.') + + with sqlite3.connect(self.config.input_database) as con: + hybrid_loader = HybridLoader(db_connection=con, config=self.config) + data_portal = hybrid_loader.load_data_portal(myopic_index=None) + instance = build_instance(data_portal, silent=self.config.silent) + + logger.info('Model build process complete.') + return instance + + def start(self) -> None: + """ + Executes the full scenario run to completion. + This method returns None on success and raises an exception on failure. + """ + self._run_preliminary_checks() + + # The mode is now definitively set, so we can proceed. + logger.info(f'Executing scenario in mode: {self.temoa_mode}') + + # Select execution path based on mode match self.temoa_mode: case TemoaMode.BUILD_ONLY: - # override the "extras" - if self.config.source_trace: - self.config.source_trace = False - logger.warning('Source trace disabled for BUILD_ONLY') - if self.config.plot_commodity_network: - self.config.plot_commodity_network = False - logger.warning('Plot commodity network disabled for BUILD_ONLY') - if self.config.price_check: - logger.warning('Price check disabled for BUILD_ONLY') - con = sqlite3.connect(self.config.input_database) - hybrid_loader = HybridLoader(db_connection=con, config=self.config) - data_portal = hybrid_loader.load_data_portal(myopic_index=None) - instance = build_instance(data_portal, silent=self.config.silent) - con.close() - return instance + # The `start` method's contract is to run to completion, not return a model. + # Raise an error to guide the developer to the correct API. + raise RuntimeError( + "For BUILD_ONLY mode, please use the 'build_model()' method instead of 'start()'." + ) case TemoaMode.CHECK: - con = sqlite3.connect(self.config.input_database) - if self.config.source_trace is False: - logger.warning('Source trace automatic for CHECK') - self.config.source_trace = True - hybrid_loader = HybridLoader(db_connection=con, config=self.config) - data_portal = hybrid_loader.load_data_portal(myopic_index=None) - instance = build_instance( - data_portal, - silent=self.config.silent, - keep_lp_file=self.config.save_lp_file, - lp_path=self.config.output_path, - ) - # disregard what the config says about price_check and source_trace and just do it... - if self.config.price_check is False: - logger.warning('Price check of model is automatic with CHECK') - good_prices = price_checker(instance) - if not good_prices and not self.config.silent: - print('Warning: Cost anomalies discovered. Check log file for details.') - con.close() - return None + self._run_check_mode() case TemoaMode.PERFECT_FORESIGHT: - con = sqlite3.connect(self.config.input_database) - hybrid_loader = HybridLoader(db_connection=con, config=self.config) - data_portal = hybrid_loader.load_data_portal(myopic_index=None) - instance = build_instance( - data_portal, - silent=self.config.silent, - keep_lp_file=self.config.save_lp_file, - lp_path=self.config.output_path, - ) - if self.config.price_check: - good_prices = price_checker(instance) - if not good_prices and not self.config.silent: - print('Warning: Cost anomalies discovered. Check log file for details.') - suffixes = ( - [ - 'dual', - ] - if self.config.save_duals - else None - ) - self.pf_solved_instance, self.pf_results = solve_instance( - instance, - self.config.solver_name, - silent=self.config.silent, - solver_suffixes=suffixes, - ) - good_solve, msg = check_solve_status(self.pf_results) - if not good_solve: - logger.error('The solve result is reported as %s. Aborting', msg) - logger.error( - 'This may be the result of the output messaging of the chosen solver' - 'If this is deemed an acceptable status, adjustment may be needed to the ' - 'function check_solve_status in run_actions.py' - ) - sys.exit(-1) - handle_results(self.pf_solved_instance, self.pf_results, self.config) - con.close() - return None + self._run_perfect_foresight() case TemoaMode.MYOPIC: - # create a myopic sequencer and shift control to it myopic_sequencer = MyopicSequencer(config=self.config) myopic_sequencer.start() - return None case TemoaMode.MGA: if self.config.solver_name == 'appsi_highs': raise ValueError( - 'Multiprocessing currently not working with HiGHS solver. ' - 'Unknown fix...appears to be pyomo issue. Gurobi, CBC, Ipopt all work.' + 'MGA mode is not compatible with the HiGHS solver due to a multiprocessing issue.' ) mga_sequencer = MgaSequencer(config=self.config) mga_sequencer.start() - return None case TemoaMode.SVMGA: sv_mga_sequencer = SvMgaSequencer(config=self.config) sv_mga_sequencer.start() - return None case TemoaMode.METHOD_OF_MORRIS: mm_sequencer = MorrisSequencer(config=self.config) mm_sequencer.start() - return None case TemoaMode.MONTE_CARLO: - if self.config.solver_name == 'appsi_highs': - raise ValueError( - 'Multiprocessing currently not working with HiGHS solver. ' - 'Unknown fix...appears to be pyomo issue. Gurobi, CBC, Ipopt all work.' - ) - if self.config.plot_commodity_network: - self.config.plot_commodity_network = False - logger.warning('Plot commodity network disabled for MONTE_CARLO') - if self.config.price_check: - self.config.price_check = False - logger.warning('Price check disabled for MONTE_CARLO') - if self.config.save_excel: - self.config.save_excel = False - logger.warning('Save excel disabled for MONTE_CARLO') - if self.config.save_lp_file: - self.config.save_lp_file = False - logger.warning('Save lp file disabled for MONTE_CARLO') - if self.config.save_duals: - self.config.save_duals = False - logger.warning('Save duals disabled for MONTE_CARLO') - mc_sequencer = MCSequencer(config=self.config) - mc_sequencer.start() - return None + self._run_monte_carlo() case _: - raise NotImplementedError('not yet built') + raise NotImplementedError( + f"The scenario mode '{self.temoa_mode}' is not yet implemented." + ) + + def _run_check_mode(self) -> None: + """Encapsulated logic for the CHECK mode.""" + with sqlite3.connect(self.config.input_database) as con: + if not self.config.source_trace: + logger.warning('Source trace is automatically enabled for CHECK mode.') + self.config.source_trace = True + hybrid_loader = HybridLoader(db_connection=con, config=self.config) + data_portal = hybrid_loader.load_data_portal(myopic_index=None) + instance = build_instance( + data_portal, + silent=self.config.silent, + keep_lp_file=self.config.save_lp_file, + lp_path=self.config.output_path, + ) + if not self.config.price_check: + logger.warning('Price check is automatically enabled for CHECK mode.') + price_checker(instance) + + def _run_perfect_foresight(self) -> None: + """Encapsulated logic for the PERFECT_FORESIGHT mode.""" + with sqlite3.connect(self.config.input_database) as con: + hybrid_loader = HybridLoader(db_connection=con, config=self.config) + data_portal = hybrid_loader.load_data_portal(myopic_index=None) + instance = build_instance( + data_portal, + silent=self.config.silent, + keep_lp_file=self.config.save_lp_file, + lp_path=self.config.output_path, + ) + if self.config.price_check: + price_checker(instance) + + suffixes = ['dual'] if self.config.save_duals else None + self.pf_solved_instance, self.pf_results = solve_instance( + instance, + self.config.solver_name, + silent=self.config.silent, + solver_suffixes=suffixes, + ) + good_solve, msg = check_solve_status(self.pf_results) + if not good_solve: + raise RuntimeError( + f"The solver reported a non-optimal status: '{msg}'. Aborting run. " + "This may be due to the solver's output messaging. If this status is " + 'acceptable, the `check_solve_status` function may need adjustment.' + ) + handle_results(self.pf_solved_instance, self.pf_results, self.config) + + def _run_monte_carlo(self) -> None: + """Encapsulated logic for the MONTE_CARLO mode.""" + if self.config.solver_name == 'appsi_highs': + raise ValueError( + 'Monte Carlo mode is not compatible with the HiGHS solver due to a multiprocessing issue.' + ) + + # Disable features not typically used in Monte Carlo runs to reduce noise/overhead + if self.config.plot_commodity_network: + self.config.plot_commodity_network = False + logger.warning('Commodity network plotting disabled for MONTE_CARLO mode.') + if self.config.price_check: + self.config.price_check = False + logger.warning('Price check disabled for MONTE_CARLO mode.') + if self.config.save_excel: + self.config.save_excel = False + logger.warning('Excel output disabled for MONTE_CARLO mode.') + if self.config.save_lp_file: + self.config.save_lp_file = False + logger.warning('LP file saving disabled for MONTE_CARLO mode.') + if self.config.save_duals: + self.config.save_duals = False + logger.warning('Saving of duals disabled for MONTE_CARLO mode.') + + mc_sequencer = MCSequencer(config=self.config) + mc_sequencer.start() diff --git a/temoa/cli.py b/temoa/cli.py new file mode 100644 index 000000000..bae776e1e --- /dev/null +++ b/temoa/cli.py @@ -0,0 +1,202 @@ +import logging +from datetime import datetime +from pathlib import Path +from typing import Annotated + +import rich +import typer +from rich.logging import RichHandler + +from definitions import set_OUTPUT_PATH + +# Updated imports to bring in the config object +from temoa._internal.temoa_sequencer import TemoaSequencer +from temoa.core.config import TemoaConfig +from temoa.core.modes import TemoaMode +from temoa.version_information import TEMOA_MAJOR, TEMOA_MINOR + +# ============================================================================= +# Logging Setup +# ============================================================================= +logger = logging.getLogger(__name__) + + +# ============================================================================= +# Helper Functions +# ============================================================================= +def _create_output_folder() -> Path: + """Create a default time-stamped folder for outputs.""" + output_path = Path('output_files', datetime.now().strftime('%Y-%m-%d_%H%M%S')) + output_path.mkdir(parents=True, exist_ok=True) + return output_path + + +def _setup_logging(output_path: Path, debug: bool = False) -> None: + """Set up logging to a file and a rich console.""" + level = logging.DEBUG if debug else logging.INFO + log_format = '%(asctime)s | %(name)s | %(levelname)s | %(message)s' + date_format = '%Y-%m-%d %H:%M:%S' + log_file = output_path / 'temoa-run.log' + file_handler = logging.FileHandler(log_file) + file_handler.setFormatter(logging.Formatter(log_format, date_format)) + rich_handler = RichHandler(rich_tracebacks=True, show_path=False, log_time_format='[%X]') + root_logger = logging.getLogger() + root_logger.setLevel(level) + root_logger.handlers = [file_handler, rich_handler] + logging.getLogger('pyomo').setLevel(logging.WARNING) + logging.getLogger('matplotlib').setLevel(logging.WARNING) + logger.info(f'Logging initialized. Log file at: {log_file}') + + +def _version_callback(value: bool) -> None: + """Callback to print version information and exit.""" + if value: + version = f'{TEMOA_MAJOR}.{TEMOA_MINOR}' + rich.print(f'Temoa Version: [bold green]{version}[/bold green]') + raise typer.Exit() + + +def _cite_callback(value: bool) -> None: + """Callback to print citation information and exit.""" + if value: + citation_text = """ + [bold]How to Cite Temoa:[/bold] + + Please consult the project documentation or associated publications + for the most up-to-date citation information. + """ + rich.print(citation_text) + raise typer.Exit() + + +# ============================================================================= +# Typer Application Setup +# ============================================================================= +app = typer.Typer( + name='temoa', + help='The Temoa Project: Tools for Energy Model Optimization and Analysis.', + rich_markup_mode='markdown', + no_args_is_help=True, + context_settings={'help_option_names': ['-h', '--help']}, +) + + +# ============================================================================= +# Main 'run' Subcommand +# ============================================================================= +@app.command() +def run( + config_file: Annotated[ + Path, + typer.Argument( + help='Path to the model configuration file.', + exists=True, + file_okay=True, + dir_okay=False, + readable=True, + resolve_path=True, + ), + ], + output_path: Annotated[ + Path | None, + typer.Option( + '--output', + '-o', + help='Directory to save outputs. Defaults to a new time-stamped folder.', + file_okay=False, + dir_okay=True, + writable=True, + resolve_path=True, + ), + ] = None, + build_only: Annotated[ + bool, + typer.Option( + '--build-only', + '-b', + help='Build an unsolved TemoaModel instance without solving.', + ), + ] = False, + silent: Annotated[ + bool, typer.Option('--silent', '-s', help='Silent run. No interactive prompts.') + ] = False, + debug: Annotated[ + bool, typer.Option('--debug', '-d', help='Enable debug-level logging.') + ] = False, +) -> None: + """ + Builds and solves a Temoa model based on the provided configuration. + """ + final_output_path = output_path if output_path else _create_output_folder() + final_output_path.mkdir(parents=True, exist_ok=True) + + _setup_logging(final_output_path, debug) + set_OUTPUT_PATH(final_output_path) + + try: + # Step 1: Create the configuration object first. + config = TemoaConfig.build_config( + config_file=config_file, output_path=final_output_path, silent=silent + ) + + # Step 2: Handle user interaction in the CLI, not the sequencer. + if not silent: + rich.print(config) # Print the rich representation of the config + # Use Typer's confirmation prompt, which aborts on "n". + typer.confirm('\nPlease confirm the settings above to continue', abort=True) + + # Step 3: Instantiate the sequencer and decide which method to call. + mode_override = TemoaMode.BUILD_ONLY if build_only else None + ts = TemoaSequencer(config=config, mode_override=mode_override) + + if build_only: + logger.info('Build-only mode selected. Calling build_model().') + # The returned model is not used here, but could be in other contexts. + _ = ts.build_model() + rich.print('\n[bold green]āœ… Model built successfully.[/bold green]') + rich.print(f'Log file is available in: [cyan]{final_output_path}[/cyan]') + else: + logger.info('Full run mode selected. Calling start().') + ts.start() + rich.print('\n[bold green]āœ… Temoa run completed successfully.[/bold green]') + rich.print(f'Outputs are available in: [cyan]{final_output_path}[/cyan]') + + except typer.Abort: + # This catches the "n" from the confirmation prompt. + rich.print('\n[yellow]Run aborted by user.[/yellow]') + raise typer.Exit() from None + + except Exception as e: + # This now correctly catches all errors raised from the sequencer. + logger.exception('An unhandled error occurred during the Temoa run.') + rich.print(f'\n[bold red]āŒ An error occurred:[/bold red] {e}') + raise typer.Exit(code=1) from e + + +# ============================================================================= +# Global Options +# ============================================================================= +@app.callback() +def main_options( + version: bool | None = typer.Option( + None, + '--version', + '-v', + help='Show Temoa version and exit.', + callback=_version_callback, + is_eager=True, + ), + how_to_cite: bool | None = typer.Option( + None, + '--how-to-cite', + help='Show citation information and exit.', + callback=_cite_callback, + is_eager=True, + ), +) -> None: + """Manage global options for the Temoa CLI.""" + pass + + +if __name__ == '__main__': + app() diff --git a/tests/conftest.py b/tests/conftest.py index 53e37b4e7..dbc332e3e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,33 +1,3 @@ -""" -pytest configuration - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 6/27/23 - -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -""" - import logging import os import sqlite3 @@ -37,8 +7,9 @@ import pytest from pyomo.opt import SolverResults -from definitions import PROJECT_ROOT +from definitions import PROJECT_ROOT, set_OUTPUT_PATH from temoa._internal.temoa_sequencer import TemoaSequencer +from temoa.core.config import TemoaConfig from temoa.core.model import TemoaModel logger = logging.getLogger(__name__) @@ -85,7 +56,7 @@ def refresh_databases() -> None: os.remove(data_output_path / db) # make a new one and fill it con = sqlite3.connect(data_output_path / db) - with open(data_source_path / src, 'r') as script: + with open(data_source_path / src) as script: con.executescript(script.read()) con.close() @@ -103,15 +74,24 @@ def system_test_run( data_name = request.param['name'] logger.info('Setting up and solving: %s', data_name) filename = request.param['filename'] - options = {'silent': True, 'debug': True} config_file = Path(PROJECT_ROOT, 'tests', 'testing_configs', filename) - sequencer = TemoaSequencer( + set_OUTPUT_PATH(tmp_path) + + config = TemoaConfig.build_config( config_file=config_file, output_path=tmp_path, - **options, + silent=True, ) + + sequencer = TemoaSequencer(config=config) + sequencer.start() - res = sequencer.pf_results - mdl = sequencer.pf_solved_instance - return data_name, res, mdl, sequencer + + # The rest of the fixture returns the solved instance from the sequencer + return ( + data_name, + sequencer.pf_results, + sequencer.pf_solved_instance, + sequencer, + ) diff --git a/tests/test_cli.py b/tests/test_cli.py new file mode 100644 index 000000000..1d5e2a909 --- /dev/null +++ b/tests/test_cli.py @@ -0,0 +1,79 @@ +from pathlib import Path + +from typer.testing import CliRunner + +from temoa.cli import app + +runner = CliRunner() + +# Path to the configuration file template we will use for tests. +TESTING_CONFIGS_DIR = Path(__file__).parent / 'testing_configs' +UTOPIA_CONFIG_TEMPLATE = TESTING_CONFIGS_DIR / 'config_utopia.toml' + + +def create_test_config(tmp_path: Path, db_path: Path) -> Path: + """ + Reads the config template, replaces a placeholder path with the correct + test database path, and writes a new, runnable config file. + """ + template_content = UTOPIA_CONFIG_TEMPLATE.read_text() + + placeholder = 'path = "tests/testing_outputs/utopia.sqlite"' + replacement = f'path = "{db_path.as_posix()}"' + + config_content = template_content.replace(placeholder, replacement) + + test_config_path = tmp_path / 'test_config.toml' + test_config_path.write_text(config_content) + + return test_config_path + + +def test_cli_version(): + """Test the `temoa --version` command.""" + result = runner.invoke(app, ['--version']) + assert result.exit_code == 0 + assert 'Temoa Version' in result.stdout + + +def test_cli_run_command_success(tmp_path): + """Test a successful run by creating a self-contained config.""" + db_path = Path(__file__).parent / 'testing_outputs' / 'utopia.sqlite' + test_config_path = create_test_config(tmp_path, db_path) + + args = ['run', str(test_config_path), '--output', str(tmp_path), '--silent'] + result = runner.invoke(app, args) + + assert result.exit_code == 0, f'CLI crashed with error: {result.exception}' + assert 'Temoa run completed successfully' in result.stdout + assert (tmp_path / 'temoa-run.log').exists() + + +def test_cli_run_build_only(tmp_path): + """Test the --build-only flag with a self-contained config.""" + db_path = Path(__file__).parent / 'testing_outputs' / 'utopia.sqlite' + test_config_path = create_test_config(tmp_path, db_path) + + args = ['run', str(test_config_path), '--output', str(tmp_path), '--build-only', '--silent'] + result = runner.invoke(app, args) + + assert result.exit_code == 0, f'CLI crashed with error: {result.exception}' + assert 'Model built successfully' in result.stdout + + +def test_cli_run_missing_config(): + """Test graceful failure for a missing config file.""" + args = ['run', 'non_existent_file.toml'] + result = runner.invoke(app, args) + + assert result.exit_code != 0 + + # Normalize the stderr string to be immune to rich's word wrapping + # by removing formatting characters and collapsing whitespace. + cleaned_stderr = ' '.join(result.stderr.replace('│', '').split()) + + # Now, check for the logical error message in the cleaned string. + assert ( + "Invalid value for 'CONFIG_FILE': File 'non_existent_file.toml' does not exist." + in cleaned_stderr + ) diff --git a/tests/test_emission_results.py b/tests/test_emission_results.py index 2ab61d0b7..dd742c6dd 100644 --- a/tests/test_emission_results.py +++ b/tests/test_emission_results.py @@ -1,28 +1,6 @@ """ Test some emissions and curtailment results for some basic technology archetypes -Written by: Ian David Elder -iandavidelder@gmail.com -Created on: 2024/06/03 - -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . """ import logging @@ -31,8 +9,9 @@ import pytest -from definitions import PROJECT_ROOT +# Import TemoaConfig, which is now needed to set up the sequencer from temoa._internal.temoa_sequencer import TemoaSequencer +from temoa.core.config import TemoaConfig logger = logging.getLogger(__name__) @@ -40,25 +19,25 @@ @pytest.fixture(scope='module') def solved_connection(request, tmp_path_factory): """ - spin up the model, solve it, and hand over a connection to the results db + Spins up the model, solves it, and hands over a connection to the results db. + This fixture is now updated to use the refactored TemoaSequencer API. """ - data_name = 'emissions' - logger.info('Setting up and solving: %s', data_name) - filename = 'config_emissions.toml' - options = {'silent': True, 'debug': True} - config_file = Path(PROJECT_ROOT, 'tests', 'testing_configs', filename) + logger.info(f'Setting up and solving for test case: {request.param["name"]}') + + config_file = Path(__file__).parent / 'testing_configs' / 'config_emissions.toml' tmp_path = tmp_path_factory.mktemp('data') - sequencer = TemoaSequencer( - config_file=config_file, - output_path=tmp_path, - **options, - ) + config = TemoaConfig.build_config(config_file=config_file, output_path=tmp_path, silent=True) + sequencer = TemoaSequencer(config=config) + + # Step 3: Run the sequencer to completion. sequencer.start() - # make connection here as in your code... + con = sqlite3.connect(sequencer.config.output_database) - yield con, request.param['name'], request.param['tech'], request.param['target'] - con.close() + try: + yield con, request.param['name'], request.param['tech'], request.param['target'] + finally: + con.close() # List of tech archetypes to test and their correct emission value diff --git a/tests/test_main.py b/tests/test_main.py deleted file mode 100644 index fe2d27249..000000000 --- a/tests/test_main.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -quick test of some of the argument parsing - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 11/26/23 - -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . -""" - -import pytest - -import main - - -def test_parse_args(tmp_path, capsys): - config_file = tmp_path / 'config.toml' - config_file.write_text('nada') - - # missing config - with pytest.raises(AttributeError) as e: - main.parse_args(f'--output_path {tmp_path}'.split()) - - # bad file - with pytest.raises(FileNotFoundError) as e: - main.parse_args(f'--config sasquatch_bait.toml --output_path {tmp_path}'.split()) - - # good file - main.parse_args(f'--config {config_file} --output_path {tmp_path}'.split()) - - # good output path - options = main.parse_args(f'--config {config_file} --output_path {tmp_path}'.split()) - assert options.output_path == tmp_path - - # bad output path - with pytest.raises(FileNotFoundError) as e: - main.parse_args(f'--config {config_file} --output_path big_bird'.split()) - - # options setting - options = main.parse_args(f'--config {config_file} --output_path {tmp_path} -s -d -b'.split()) - assert all((options.silent, options.debug, options.build_only)) diff --git a/tests/test_material_results.py b/tests/test_material_results.py index b076bda9d..8a5f1d3a8 100644 --- a/tests/test_material_results.py +++ b/tests/test_material_results.py @@ -1,30 +1,3 @@ -""" -Test some emissions and curtailment results for some basic technology archetypes - -Written by: Ian David Elder -iandavidelder@gmail.com -Created on: 2025/05/01 - -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . -""" - import logging import sqlite3 from pathlib import Path @@ -33,6 +6,7 @@ from definitions import PROJECT_ROOT from temoa._internal.temoa_sequencer import TemoaSequencer +from temoa.core.config import TemoaConfig logger = logging.getLogger(__name__) @@ -45,26 +19,25 @@ def solved_connection(request, tmp_path_factory): data_name = 'materials' logger.info('Setting up and solving: %s', data_name) filename = 'config_materials.toml' - options = {'silent': True, 'debug': True} config_file = Path(PROJECT_ROOT, 'tests', 'testing_configs', filename) tmp_path = tmp_path_factory.mktemp('data') - sequencer = TemoaSequencer( - config_file=config_file, - output_path=tmp_path, - **options, - ) + config = TemoaConfig.build_config(config_file=config_file, output_path=tmp_path, silent=True) + sequencer = TemoaSequencer(config=config) sequencer.start() - # make connection here as in your code... + con = sqlite3.connect(sequencer.config.output_database) - yield ( - con, - request.param['name'], - request.param['tech'], - request.param['period'], - request.param['target'], - ) - con.close() + try: + # Pass all necessary params for this specific test + yield ( + con, + request.param['name'], + request.param['tech'], + request.param['period'], + request.param['target'], + ) + finally: + con.close() # List of tech archetypes to test and their correct flowout value @@ -85,13 +58,16 @@ def test_flows(solved_connection): Test that the emissions from each technology archetype are correct, and check total emissions """ con, name, tech, period, flow_target = solved_connection - flow = ( + row = ( con.cursor() .execute( f"SELECT SUM(flow) FROM main.OutputFlowOut WHERE tech == '{tech}' AND period == {period}" ) - .fetchone()[0] + .fetchone() ) + # If the query returns no rows, row will be None. If it finds rows but the sum is NULL, row[0] will be None. + flow = row[0] if row and row[0] is not None else 0.0 + assert flow == pytest.approx( flow_target, rel=1e-5, diff --git a/tests/test_model.py b/tests/test_model.py index 9ef34567c..35cfaf6fc 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -1,29 +1,5 @@ """ A series of tests focused on the model entity. - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 12/6/23 - -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . """ import pathlib @@ -31,29 +7,26 @@ from definitions import PROJECT_ROOT from temoa._internal.temoa_sequencer import TemoaSequencer +from temoa.core.config import TemoaConfig from temoa.core.modes import TemoaMode def test_serialization(): """ - Test to ensure the model pickles properly. This is used when employing mpi4py which requires - that jobs passed are pickle-able + Test to ensure the model pickles properly. This is used when employing mpi4py which requires + that jobs passed are pickle-able. """ - config_file = 'config_utopia.toml' - config_file = pathlib.Path(PROJECT_ROOT, 'tests', 'testing_configs', config_file) + config_filename = 'config_utopia.toml' + config_file_path = pathlib.Path(PROJECT_ROOT, 'tests', 'testing_configs', config_filename) output_path = pathlib.Path(PROJECT_ROOT, 'tests', 'testing_outputs') - options = {'silent': True, 'debug': True} - ts = TemoaSequencer( - config_file=config_file, - output_path=output_path, - mode_override=TemoaMode.BUILD_ONLY, - **options, - ) - built_instance = ts.start() + config = TemoaConfig.build_config( + config_file=config_file_path, output_path=output_path, silent=True + ) + ts = TemoaSequencer(config=config, mode_override=TemoaMode.BUILD_ONLY) - pickled_model = pickle.dumps(built_instance) - assert pickled_model, 'model should have pickled successfully, but did not.' + # Use the correct method for build-only mode + built_instance = ts.build_model() - recovered_model = pickle.loads(pickled_model) - assert recovered_model, 'unable to recover model.' + # The actual test: try to pickle the model + pickle.dumps(built_instance) diff --git a/tests/test_set_consistency.py b/tests/test_set_consistency.py index e211d30fa..be3b1bca3 100644 --- a/tests/test_set_consistency.py +++ b/tests/test_set_consistency.py @@ -1,33 +1,6 @@ """ These tests are designed to check the construction of the numerous sets in the 2 exemplar models: Utopia and Test System. - -They construct all the pyomo Sets associated with the model and compare them with cached results that are stored -in json files - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 9/26/23 - -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . """ import json @@ -38,8 +11,12 @@ from definitions import PROJECT_ROOT from temoa._internal.temoa_sequencer import TemoaSequencer +from temoa.core.config import TemoaConfig from temoa.core.modes import TemoaMode +TESTING_CONFIGS_DIR = pathlib.Path(__file__).parent / 'testing_configs' + +# Update params to just be filenames, we will construct the path inside the test params = [ ('utopia', 'config_utopia.toml', 'utopia_sets.json'), ('test_system', 'config_test_system.toml', 'test_system_sets.json'), @@ -54,22 +31,24 @@ def test_set_consistency(data_name, config_file, set_file, tmp_path): """ test the set membership of the utopia model against cached values to ensure consistency """ - config_file = pathlib.Path(PROJECT_ROOT, 'tests', 'testing_configs', config_file) - options = {'silent': True, 'debug': True} - ts = TemoaSequencer( - config_file=config_file, output_path=tmp_path, mode_override=TemoaMode.BUILD_ONLY, **options + full_config_path = TESTING_CONFIGS_DIR / config_file + + config = TemoaConfig.build_config( + config_file=full_config_path, output_path=tmp_path, silent=True ) + ts = TemoaSequencer(config=config, mode_override=TemoaMode.BUILD_ONLY) + + built_instance = ts.build_model() - built_instance = ts.start() model_sets = built_instance.component_map(ctype=pyo.Set) model_sets = {k: set(v) for k, v in model_sets.items()} # retrieve the cache and convert the set values from list -> set (json can't store sets) cache_file = pathlib.Path(PROJECT_ROOT, 'tests', 'testing_data', set_file) - with open(cache_file, 'r') as src: + with open(cache_file) as src: cached_sets = json.load(src) cached_sets = { - k: set(tuple(t) if isinstance(t, list) else t for t in v) for (k, v) in cached_sets.items() + k: {tuple(t) if isinstance(t, list) else t for t in v} for (k, v) in cached_sets.items() } # compare sets where they exist in the model. @@ -123,6 +102,6 @@ def test_set_consistency(data_name, config_file, set_file, tmp_path): f'The {data_name} run-produced sets did not match cached values' ) if cache_extra_sets: - assert False, 'Cache has extra sets' + assert False, 'Cache has extra sets' # noqa B011 if model_extra_sets: - assert False, 'Model has extra sets' + assert False, 'Model has extra sets' # noqa B011 diff --git a/tests/test_temoa_sequencer.py b/tests/test_temoa_sequencer.py index 4adf3278e..6a5b38b90 100644 --- a/tests/test_temoa_sequencer.py +++ b/tests/test_temoa_sequencer.py @@ -1,57 +1,71 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 3/14/24 - -""" - from pathlib import Path import pytest +from pyomo.environ import ConcreteModel -from definitions import PROJECT_ROOT +# Import the new dependencies from temoa._internal.temoa_sequencer import TemoaSequencer +from temoa.core.config import TemoaConfig from temoa.core.modes import TemoaMode -params = [ - {'name': 'build-only', 'mode': TemoaMode.BUILD_ONLY}, +# Define the config file path once +TESTING_CONFIGS_DIR = Path(__file__).parent / 'testing_configs' +UTOPIA_MYOPIC_CONFIG = TESTING_CONFIGS_DIR / 'config_utopia_myopic.toml' + +# Define test parameters +# Note: Separated BUILD_ONLY as it uses a different method now +run_params = [ {'name': 'check', 'mode': TemoaMode.CHECK}, {'name': 'pf', 'mode': TemoaMode.PERFECT_FORESIGHT}, {'name': 'myopic', 'mode': TemoaMode.MYOPIC}, {'name': 'MGA', 'mode': TemoaMode.MGA}, ] -# using the myopic config file for now below, becuase (a) it is most current db, (b) it is self-referencing -# for the database, which is needed for myopic, and (c) the mode is overriden anyhow! -config_file = Path(PROJECT_ROOT, 'tests', 'testing_configs', 'config_utopia_myopic.toml') -@pytest.mark.parametrize('run_data', params, ids=lambda p: p['name']) -def test_start(run_data, tmp_path): - options = {'silent': True, 'debug': True, 'mode_override': run_data['mode']} +@pytest.mark.parametrize('run_data', run_params, ids=lambda p: p['name']) +def test_sequencer_start(run_data, tmp_path): + """ + Tests the main `start()` method for various run modes. + """ + # Step 1: Create the TemoaConfig object first. + # The 'silent' flag is now part of the config. + config = TemoaConfig.build_config( + config_file=UTOPIA_MYOPIC_CONFIG, + output_path=tmp_path, + silent=True, + ) + + # Step 2: Instantiate the sequencer with the config object. + # The mode is passed as an override. sequencer = TemoaSequencer( - config_file=config_file, + config=config, + mode_override=run_data['mode'], + ) + + # Step 3: Call the `start()` method and assert it returns None on success. + # Any failure will raise an exception, which pytest will catch. + result = sequencer.start() + assert result is None, 'sequencer.start() should return None on success' + + +def test_sequencer_build_model(tmp_path): + """ + Tests the dedicated `build_model()` method for the BUILD_ONLY mode. + """ + # Step 1: Create the config object. + config = TemoaConfig.build_config( + config_file=UTOPIA_MYOPIC_CONFIG, output_path=tmp_path, - **options, + silent=True, ) - sequencer.start() + + # Step 2: Instantiate the sequencer. + sequencer = TemoaSequencer( + config=config, + mode_override=TemoaMode.BUILD_ONLY, + ) + + # Step 3: Call the `build_model()` method and check the return value. + model = sequencer.build_model() + assert model is not None, 'sequencer.build_model() should return a model' + assert isinstance(model, ConcreteModel), 'Should return a Pyomo ConcreteModel' diff --git a/uv.lock b/uv.lock index 6317513aa..994cbc838 100644 --- a/uv.lock +++ b/uv.lock @@ -73,6 +73,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, ] +[[package]] +name = "click" +version = "8.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/46/61/de6cd827efad202d7057d93e0fed9294b96952e188f7384832791c7b2254/click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4", size = 276943, upload-time = "2025-09-18T17:32:23.696Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/d3/9dcc0f5797f070ec8edf30fbadfb200e71d9db6b84d211e3b2085a7589a0/click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc", size = 107295, upload-time = "2025-09-18T17:32:22.42Z" }, +] + [[package]] name = "colorama" version = "0.4.6" @@ -176,14 +188,14 @@ wheels = [ [[package]] name = "deprecated" -version = "1.2.18" +version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/98/97/06afe62762c9a8a86af0cfb7bfdab22a43ad17138b07af5b1a58442690a2/deprecated-1.2.18.tar.gz", hash = "sha256:422b6f6d859da6f2ef57857761bfb392480502a64c3028ca9bbe86085d72115d", size = 2928744, upload-time = "2025-01-27T10:46:25.7Z" } +sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", size = 2932523, upload-time = "2025-10-30T08:19:02.757Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6e/c6/ac0b6c1e2d138f1002bcf799d330bd6d85084fece321e662a14223794041/Deprecated-1.2.18-py2.py3-none-any.whl", hash = "sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec", size = 9998, upload-time = "2025-01-27T10:46:09.186Z" }, + { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298, upload-time = "2025-10-30T08:19:00.758Z" }, ] [[package]] @@ -282,33 +294,33 @@ wheels = [ [[package]] name = "highspy" -version = "1.11.0" +version = "1.12.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b4/fc/aa1325331c320598ce60cc31060087681cd05123b6fb2a8a571e882b7f05/highspy-1.11.0.tar.gz", hash = "sha256:771e58c076122d207ff1b19759c21d3227f0da5b80dfd89a4145681524969cef", size = 1285415, upload-time = "2025-06-06T00:47:22.562Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/ad/b54ad6740b950faab3b7f1465fbb5c740fc522928a8d9f01cac181f8f9a6/highspy-1.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28fffd3e733833a7b2569df6761088046e8aca868ab328828711dbe15b102ad4", size = 2232856, upload-time = "2025-06-06T00:46:11.161Z" }, - { url = "https://files.pythonhosted.org/packages/a3/0c/3921a207f47d52abc81a9d00d8f4d579b05b85670e23bc7140e39268490d/highspy-1.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:20a3adf8820a5f7a9cee6fc76df625e651ecfd8b5898af2a77042e79269ce0bc", size = 1908641, upload-time = "2025-06-06T00:46:12.706Z" }, - { url = "https://files.pythonhosted.org/packages/0a/b6/ea7ea6c4c3f781b007fe928b2aefa40c49287b4689985d04c3b20d383475/highspy-1.11.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d4bc0a84cf613bb8565f9b5f610eb0655384162f509b5d86f9c888570275fdc", size = 2119574, upload-time = "2025-06-06T00:46:14.261Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0c/94f1ccb6606e8445a7a0c68d983e47f64899582c64fcea651f488eaaaea0/highspy-1.11.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:543789b75c396a904cb550de34eb333f1a184e123dadc9903b5e6dbca18a007b", size = 2441487, upload-time = "2025-06-06T00:46:16.286Z" }, - { url = "https://files.pythonhosted.org/packages/ad/aa/e7c4ac05162187c484bb121f50d8e037c13bf894ed5cf4e781e1cff68762/highspy-1.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a23949e4f44b6df0ed8c387a7c733d683a0fa66e3ff15d65719979ce2099ee99", size = 2302302, upload-time = "2025-06-06T00:46:18.819Z" }, - { url = "https://files.pythonhosted.org/packages/04/ce/fd2473bed635eb06d116f987767d5c5fe3c62b317fb1a788c31966d7fa0a/highspy-1.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:50dacf300ebe7c4dca92891c0bf61b694f2ca744207cf7d0d24f2a30ffb5608c", size = 3101885, upload-time = "2025-06-06T00:46:20.774Z" }, - { url = "https://files.pythonhosted.org/packages/6e/e1/bf174389656de5d302ed53dd5cdeb5f7e9ad84156ad2fc95d5a63ba023f2/highspy-1.11.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a782c242b4b047f86110787b0dafce9d77cc10f079adab1fd51c5331e5760127", size = 3647952, upload-time = "2025-06-06T00:46:22.847Z" }, - { url = "https://files.pythonhosted.org/packages/f3/f5/42f6f2ce99c5b9d7aa864ac3abeaf8a2b66da707821ab42b0a31ec2a0dc1/highspy-1.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:15b804387089a389e5f01b056a4b3ad74c7d1cf00ab00a0faaf3b4a582bb664c", size = 3309616, upload-time = "2025-06-06T00:46:24.888Z" }, - { url = "https://files.pythonhosted.org/packages/47/f5/cf13640ed65ea934b45e0c3e786497f4696f286faf45e8e62579a0f15462/highspy-1.11.0-cp312-cp312-win32.whl", hash = "sha256:8c33f68df8ab9666d379b0d64d04775c0a9db31882d4f87b3ec8cece0003b47d", size = 1710641, upload-time = "2025-06-06T00:46:26.462Z" }, - { url = "https://files.pythonhosted.org/packages/b7/2f/7acfea5b8d32b86bdec018f858bc195236b804a22a7cd3349da711498692/highspy-1.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0aed8c80d33e2fc2eb1def75dbd34c9fa463acb589d19a5ed5dcc0178ae7062", size = 1985767, upload-time = "2025-06-06T00:46:28.144Z" }, - { url = "https://files.pythonhosted.org/packages/96/84/3e899c5d95dc9d5400a308e0aaf4a5143f69016a4f46dd528ff7cd65d341/highspy-1.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f675cda73860c7c8a22546db3c80db985720baea84866b08a971cfa03cc7a156", size = 2232867, upload-time = "2025-06-06T00:46:29.651Z" }, - { url = "https://files.pythonhosted.org/packages/74/e2/2853095a74e9fc2c2081340647be8edba7122696534ebbaf159ceb53f9b4/highspy-1.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7babebfc01b7682c69c95e0520614ec9400e10cec1b84d3fb7cd48535c606244", size = 1908601, upload-time = "2025-06-06T00:46:31.232Z" }, - { url = "https://files.pythonhosted.org/packages/e6/36/3cabdd3ae8610912962bad96f4d4d6702255d6c01d050754e4050a9eaa4a/highspy-1.11.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39fb60d84d7a58e58f923ea6f0641e6978eb9049033b84de1a2add723e01cd3f", size = 2119726, upload-time = "2025-06-06T00:46:32.796Z" }, - { url = "https://files.pythonhosted.org/packages/a9/da/200d3f13ca9ad3f9fc11a1f3f76cc2734de42dae064510365d42caeb5ed4/highspy-1.11.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c2e7cf4d504287cd8910de322a726d58428af43bb985d6bae602bf84a7454b9", size = 2441449, upload-time = "2025-06-06T00:46:35.147Z" }, - { url = "https://files.pythonhosted.org/packages/6c/58/fc3775850dc668006039637a4f23f03a9c0eb533643c9d3a7370f9d63de2/highspy-1.11.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79682aa7855d94106ccbbb750082d156dcbb57dff9d489f167320ae0ce768867", size = 2302685, upload-time = "2025-06-06T00:46:36.791Z" }, - { url = "https://files.pythonhosted.org/packages/b5/16/e13326a9706c407d32e39ad14aa79a696c1eb49bb13d50fde5d96afb02b5/highspy-1.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:65232aa496fb27be56cc85b2c7c785fac866107c32ea00cc38ec474d6a9f6494", size = 3102306, upload-time = "2025-06-06T00:46:38.341Z" }, - { url = "https://files.pythonhosted.org/packages/0e/93/468e63b16d9bf123174e7f8f7b8bd5a2f96b18d7370a2cc35e6485871749/highspy-1.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f78f27e18275d3c7868dcd0314ea535ed361322e7f0817363872d75a4cc15abc", size = 3648234, upload-time = "2025-06-06T00:46:40.895Z" }, - { url = "https://files.pythonhosted.org/packages/dc/c5/37b849a69c9cbccf533a9a51e309a49e83d704f06bf45370c2e78ceb15d4/highspy-1.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6156a7d643268456427b6fe310626ad9ee9d908ff812cc64ee8bad7b9872ea98", size = 3309724, upload-time = "2025-06-06T00:46:43.083Z" }, - { url = "https://files.pythonhosted.org/packages/90/0f/89c579b2f718dc419fd76067a03ecb3c96e6919b7cffee1b9f5a2dfe4f56/highspy-1.11.0-cp313-cp313-win32.whl", hash = "sha256:e61facebb0127eb3661db79a11c7665e47229ec63d2b425996d04aeede26d46b", size = 1710676, upload-time = "2025-06-06T00:46:45.132Z" }, - { url = "https://files.pythonhosted.org/packages/20/ca/ba2af91f2418bee0d0e99df71dcd171ca863675de6a5260bbf06c120f084/highspy-1.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:ceac08be37f75dc0af95669a0cfb073e5db5f07ead05cdcc81fd4b4394708d53", size = 1985967, upload-time = "2025-06-06T00:46:46.767Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/32/cc/dc47527beec1f44274186713a59fca13e6e1c71088ed6d18980dc8b90ee9/highspy-1.12.0.tar.gz", hash = "sha256:91a2da2c090597e34cd2cb57a751816ca6857c8cca8b09ae4d33960fb89ad42c", size = 1399992, upload-time = "2025-10-25T18:09:46.242Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6c/69/eacc8742d1a4ac68109a8ce3c808e81cab1c499926815e23dd39106595a3/highspy-1.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8c8b098a57b4035d5bdbffa2a80a96232c99e4d085aa822e283e98c50a1438b8", size = 2212070, upload-time = "2025-10-25T18:08:46.974Z" }, + { url = "https://files.pythonhosted.org/packages/d7/50/25e2adb149b56354aaa31165b44304c85763f66a560e8a1492e09ce6a9a5/highspy-1.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3db2958b934d46c0e112e8f9fdba96bb1fb84cfc6f70ddd4492ea62da890fe56", size = 2029063, upload-time = "2025-10-25T18:08:48.597Z" }, + { url = "https://files.pythonhosted.org/packages/36/0f/9d5b3f27a4bc8ebf4c2a18cd1ef39db77fabd8b007629143416c4d6cd4fd/highspy-1.12.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:ecc5bdee740118e18ce928feaf9e309eb4a4a076f27a6780b8b363f1446801b5", size = 2562998, upload-time = "2025-10-25T18:08:49.968Z" }, + { url = "https://files.pythonhosted.org/packages/3d/b8/901d9702873f6e103a3b9d1a6e8e403b486d4e672e4e925d6bc1a92f8114/highspy-1.12.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f6045d1d49627e1dc2f649cda4190c57c823f0cf71bec9d466363f00abbc65a7", size = 2296309, upload-time = "2025-10-25T18:08:51.651Z" }, + { url = "https://files.pythonhosted.org/packages/26/c7/34fbaacecdc363d847ef9f73ff169447db9728a100ca41c4ad1a4d3fb21a/highspy-1.12.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3a72ecea18c0b2cd041e87599d2e0bf6f96cea7133aba838f0128608089e92f", size = 2500486, upload-time = "2025-10-25T18:08:52.981Z" }, + { url = "https://files.pythonhosted.org/packages/ef/69/46910999e0fa30f85b15b3a3d5a7a16ed5af8763323e351f0ddd7fbcfed3/highspy-1.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1df858cfc71fafef789fe87793e331a17768065f9e9505df1ff10239e4fa6a8d", size = 3355868, upload-time = "2025-10-25T18:08:54.308Z" }, + { url = "https://files.pythonhosted.org/packages/e0/d3/9c1c13e09cd2dd1aed77a897272d974dab36be25bcc27a0af1f704153781/highspy-1.12.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:455b8688d93124b714e93f0787fb17040fcb5b1b90c59684bd44f66b3b947dbc", size = 3918497, upload-time = "2025-10-25T18:08:56.096Z" }, + { url = "https://files.pythonhosted.org/packages/50/f9/6dd6f8694c8f631057199bdbcadbc2078023029021feb9f0dbdbb9b0aed5/highspy-1.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:948db9f948c79a52f5faafeb71cd8990a84b462245bb2c493d3e16938f038782", size = 3581509, upload-time = "2025-10-25T18:08:57.862Z" }, + { url = "https://files.pythonhosted.org/packages/d2/87/24074f2bdb92b194d2c625a1071241a9bf23f475db850331b4256bda047f/highspy-1.12.0-cp312-cp312-win32.whl", hash = "sha256:869bdcedd7c309647efef2d4968dc05609815b537f8ccd8144ec2b81c0801a8b", size = 1843171, upload-time = "2025-10-25T18:08:59.195Z" }, + { url = "https://files.pythonhosted.org/packages/6c/48/ae627c5b16e2ae0f56537b25e6176e1e7db8ea26ea85fab047518979be2f/highspy-1.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:90c3f9d575a93f0e08490f101b72b8597c7d1ad801d429f31b6ae962a1492a56", size = 2183875, upload-time = "2025-10-25T18:09:00.525Z" }, + { url = "https://files.pythonhosted.org/packages/c7/80/81269c182ee4dc36e3add646088d027cc87a6cabe640901848b1dc9b1355/highspy-1.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:79a346e811e330fb757a96e3a234b71b5d58ace44e1eba9611b13c2b6efaf0e9", size = 2212158, upload-time = "2025-10-25T18:09:01.834Z" }, + { url = "https://files.pythonhosted.org/packages/00/bd/ac5d300201f1ad8581c5b468ed1608ecd47e1e9d88a74cdaebf0cf74ae65/highspy-1.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:57512dc19e18e2daa572acc0ea9561a5c4050d592d21f6db3f8367dd38e50362", size = 2029098, upload-time = "2025-10-25T18:09:03.132Z" }, + { url = "https://files.pythonhosted.org/packages/be/cc/3ed5a545ce807fb9c4a1e28e83ee474c560bc1a83335c791127a113f634b/highspy-1.12.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:a856e6e33d6d20d177fdc1a6eb34b3b58385a6c757a05695c4b214a5c377e044", size = 2562864, upload-time = "2025-10-25T18:09:04.478Z" }, + { url = "https://files.pythonhosted.org/packages/3c/d9/f2f409200654a64759e8970533315364ebae1dc1c90e3aa71127804abf5a/highspy-1.12.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:550ddee715934937da6cfe58f7adceca86b0847e5f8ebd7429cc275218179b95", size = 2296446, upload-time = "2025-10-25T18:09:05.869Z" }, + { url = "https://files.pythonhosted.org/packages/6d/cd/e9441001cb3e523ac620982af75d7900b702f97f08656797cec2a8db6222/highspy-1.12.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a5c58dbd6170073f4ba1bd31e0c7b276404d1456080cb190ed51b4c817629d6", size = 2500363, upload-time = "2025-10-25T18:09:07.214Z" }, + { url = "https://files.pythonhosted.org/packages/25/58/92b5849a2150db172a1b17ddf165b5aeda8871eabb59efd9f2c1df025b33/highspy-1.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a112865dbaace2c9b7e2234bd4415dd6f2b31cb53b53d007d3e53fc3ebfdd387", size = 3356311, upload-time = "2025-10-25T18:09:08.509Z" }, + { url = "https://files.pythonhosted.org/packages/9d/c8/04b6bcbb0c9cc09efd6370ba3e6afc7aaf3b6a2f61f415ace8d223328506/highspy-1.12.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:32f970c5d35fb6f92ef40a21b27faa9f348783a1de119facd0ee8dbfa52ef478", size = 3917867, upload-time = "2025-10-25T18:09:09.848Z" }, + { url = "https://files.pythonhosted.org/packages/51/c5/2c1b386a219eea79af16ee29435d940baccf159ca26647715d330868aba0/highspy-1.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:aa040786e1a321e2703834dd5bedf23d6998d6b42984c4b14e157036da655fd0", size = 3581079, upload-time = "2025-10-25T18:09:11.329Z" }, + { url = "https://files.pythonhosted.org/packages/b6/47/3d27048c6a640326f314e2b5c8b3d80ef8459633413a08a90336b56b1e2f/highspy-1.12.0-cp313-cp313-win32.whl", hash = "sha256:adb1735c625e164d1cc114a74f0628cea944b5f4a346ba0726386edbaa838479", size = 1843105, upload-time = "2025-10-25T18:09:12.774Z" }, + { url = "https://files.pythonhosted.org/packages/f0/20/3b36ca44864baced84355aa37c1b66e95d46009a74887fead515ccff88b1/highspy-1.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:dd826ca82035d125ad3f59ed62878ca2676db1c66870e2b55e025adfa9f9e785", size = 2183790, upload-time = "2025-10-25T18:09:14.559Z" }, ] [[package]] @@ -361,11 +373,11 @@ wheels = [ [[package]] name = "joblib" -version = "1.5.1" +version = "1.5.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/dc/fe/0f5a938c54105553436dbff7a61dc4fed4b1b2c98852f8833beaf4d5968f/joblib-1.5.1.tar.gz", hash = "sha256:f4f86e351f39fe3d0d32a9f2c3d8af1ee4cec285aafcb27003dda5205576b444", size = 330475, upload-time = "2025-05-23T12:04:37.097Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/5d/447af5ea094b9e4c4054f82e223ada074c552335b9b4b2d14bd9b35a67c4/joblib-1.5.2.tar.gz", hash = "sha256:3faa5c39054b2f03ca547da9b2f52fde67c06240c31853f306aea97f13647b55", size = 331077, upload-time = "2025-08-27T12:15:46.575Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7d/4f/1195bbac8e0c2acc5f740661631d8d750dc38d4a32b23ee5df3cde6f4e0d/joblib-1.5.1-py3-none-any.whl", hash = "sha256:4719a31f054c7d766948dcd83e9613686b27114f190f717cec7eaa2084f8a74a", size = 307746, upload-time = "2025-05-23T12:04:35.124Z" }, + { url = "https://files.pythonhosted.org/packages/1e/e8/685f47e0d754320684db4425a0967f7d3fa70126bffd76110b7009a0090f/joblib-1.5.2-py3-none-any.whl", hash = "sha256:4e1f0bdbb987e6d843c70cf43714cb276623def372df3c22fe5266b2670bc241", size = 308396, upload-time = "2025-08-27T12:15:45.188Z" }, ] [[package]] @@ -428,6 +440,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b5/40/23569737873cc9637fd488606347e9dd92b9fa37ba4fcda1f98ee5219a97/latexcodec-3.0.1-py3-none-any.whl", hash = "sha256:a9eb8200bff693f0437a69581f7579eb6bca25c4193515c09900ce76451e452e", size = 18532, upload-time = "2025-06-17T18:47:30.726Z" }, ] +[[package]] +name = "markdown-it-py" +version = "4.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, +] + [[package]] name = "markupsafe" version = "3.0.2" @@ -502,6 +526,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/01/8a/760f7fce66b39f447ad160800619d0bd5d0936d2b4633587116534a4afe0/matplotlib-3.9.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5816b1e1fe8c192cbc013f8f3e3368ac56fbecf02fb41b8f8559303f24c5015e", size = 9093770, upload-time = "2024-08-13T01:45:15.562Z" }, ] +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + [[package]] name = "multiprocess" version = "0.70.18" @@ -846,22 +879,30 @@ wheels = [ [[package]] name = "pyomo" -version = "6.9.2" +version = "6.9.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ply" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/53/69/84bbedd016eb8a4ab2bcc9dbffd346b266ff631d44552baea01b87862555/pyomo-6.9.2.tar.gz", hash = "sha256:81b2b14ea619244824e1c547cc12602fe9a6e19309cbf0742868c5b1ef37cb35", size = 2946406, upload-time = "2025-04-16T18:55:23.354Z" } +sdist = { url = "https://files.pythonhosted.org/packages/87/d8/f32e0dcacc8219694709200d4402c86a6e28d3af50380a5ccf7f7e15ffae/pyomo-6.9.5.tar.gz", hash = "sha256:0734020fcd5cc03ee200fd3f79d143fbfc14e6be116e0d16bab79f3f89609879", size = 3067399, upload-time = "2025-10-17T20:21:56.877Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/61/db/67f81a488173406b71cc8e2bcdb92b4598377a791d598ed5f540c86b2c8a/pyomo-6.9.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3a2f80da2afa3f6eadd17f9d897b15459c91b299325aa5b788f961e28d2802ab", size = 4133679, upload-time = "2025-04-16T18:55:38.504Z" }, - { url = "https://files.pythonhosted.org/packages/85/50/4b7f748c9983b39f4f8cabded63b17677e79211ac5238b6399d21c4b5b3b/pyomo-6.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:afd6944ff800554944fe5d5bc07d071c69c5d96df22b1edac4f784d3fbe2ff37", size = 4124480, upload-time = "2025-04-16T18:55:40.116Z" }, - { url = "https://files.pythonhosted.org/packages/85/00/894a72c888791dd381d179c43c52bf2138e71603fb970d78608eaa760c9f/pyomo-6.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d91d84c0632d98e417313c00612be87d04e59cc7056308b40901c4607bc206a", size = 4186850, upload-time = "2025-04-16T19:03:11.246Z" }, - { url = "https://files.pythonhosted.org/packages/00/2a/cd77620274a8c7053d637aa6cdbd76427f53217432f07aaf41110bc40a60/pyomo-6.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d890f67053d10d89a3a2b8bc3901dc7d926fbf225b4bd219167c00f9550a5ff", size = 4208175, upload-time = "2025-04-16T18:55:41.735Z" }, - { url = "https://files.pythonhosted.org/packages/dc/38/efe3c09a335869fa4d9a68f83ed207e73e8594eb4cccb753703ae4ec7d6b/pyomo-6.9.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f5f50e8247ffe2b26c44c496b2324b255b53e2d663d2f3f7db62ee376acfe9b2", size = 4133861, upload-time = "2025-04-16T18:55:43.489Z" }, - { url = "https://files.pythonhosted.org/packages/c8/4e/25d6eae73a8c4636fd8ac6e4a4f7d636d091a3aa4bc75ce3074c17e735c3/pyomo-6.9.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:58d830239f193d9f0a272602a35d1d1e39e72cac9ef26f7d88a0564862d56b2c", size = 4124667, upload-time = "2025-04-16T18:55:46.144Z" }, - { url = "https://files.pythonhosted.org/packages/a7/6e/575252f1cd70a39dc718f93235e1ad7d25bfbf8e558ac116a95c55139226/pyomo-6.9.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74776a900757c47b4269e4461766925e7cd4eb8f34a8565abfdec171e3fd73ed", size = 4186741, upload-time = "2025-04-16T19:03:12.767Z" }, - { url = "https://files.pythonhosted.org/packages/9f/1b/9929f2e8573b3486ea9fdb1d6b9018fe7199c64d96bf98e2f16cae725e60/pyomo-6.9.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16122a46beeff66f98f03a0291058bb956796da1fd93c82fb9c41336e3f2912f", size = 4208224, upload-time = "2025-04-16T18:55:47.732Z" }, - { url = "https://files.pythonhosted.org/packages/7f/88/0a07233e39357d3d620186485b927074d6d0ae0f64ad72cc5222ae05844e/pyomo-6.9.2-py3-none-any.whl", hash = "sha256:13ebb2f974f97afa626c2712d4f27e09a1c3d18ca11755676b743504a76e5161", size = 3799154, upload-time = "2025-04-16T18:55:52.044Z" }, + { url = "https://files.pythonhosted.org/packages/f8/63/5f163b231a924ba7a5f6c58466c751f70be88568fa446524b6e806c98e4b/pyomo-6.9.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:549ee4226cab6e2ff6efe5b3b9891ce1dfd866d38a024715315ea850fa1bf0ec", size = 4308708, upload-time = "2025-10-17T20:25:28.506Z" }, + { url = "https://files.pythonhosted.org/packages/2d/bf/0cebcfce70be04d6d7aa19fbcbdeecdd5843caac617424f34ab3feb8e96e/pyomo-6.9.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b382cc8c3728199c8332024d64eed8622dabb3f8aebe5874c86a036489064f7a", size = 4295507, upload-time = "2025-10-17T20:25:33.266Z" }, + { url = "https://files.pythonhosted.org/packages/14/27/967545514a2d0f4ca5ac6b595661cb0927cdcd10c3bb2832c5aa0ee15990/pyomo-6.9.5-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:43c6e425ca5231b530cd23460e371b7ca9119224dd57237c34580e15f31e4d72", size = 4358265, upload-time = "2025-10-17T21:06:36.892Z" }, + { url = "https://files.pythonhosted.org/packages/85/fe/691e5eb26f58ee4a072add6cc484756d9e3c367901ec6701d2c6789b394d/pyomo-6.9.5-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a1923c358e1e8009a05ada911fc72e615c9e2ce6988f0979ec1ecc75880ee1f7", size = 4389545, upload-time = "2025-10-17T20:25:37.684Z" }, + { url = "https://files.pythonhosted.org/packages/c7/b3/ae47340790f2f1f92f76b176acf475890717f0cb7def073e504b9857a057/pyomo-6.9.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:694262dc2eb53ca1ab245261f432a5ed1ec30cf3e651b5a6a1c276bc2dd81076", size = 4308795, upload-time = "2025-10-17T20:25:42.533Z" }, + { url = "https://files.pythonhosted.org/packages/29/e9/7f782864afd28a9eb53057c9d046541be6535b2da35e11c2bcb80839c6bd/pyomo-6.9.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f99ce91f2710d60b380a3a519288282d2183c44e1d66c131909313a3b63e7a2", size = 4295577, upload-time = "2025-10-17T20:25:47.185Z" }, + { url = "https://files.pythonhosted.org/packages/cd/4d/9ca17a602e31a1c3f3148c455a5739fcbe23c102b80a12ec3e6d3bf5e847/pyomo-6.9.5-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d22f99e0ba8e2fb7d0e806bf630b8ce9b0a41d777c51f22711adbcb905f7486e", size = 4359087, upload-time = "2025-10-17T21:06:41.413Z" }, + { url = "https://files.pythonhosted.org/packages/44/2e/78c3ac876791b59c836338b73dc49317b01cef574b01af061999a04a064a/pyomo-6.9.5-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5953e490b9e9ea42d28804dd0358a9d3ef82560022c2b538e70a638790bc392", size = 4390954, upload-time = "2025-10-17T20:25:51.388Z" }, + { url = "https://files.pythonhosted.org/packages/3c/27/3eb3db8e9ed6a01dee63219389aec761d5cc29b6dc5015b32f826f2a9225/pyomo-6.9.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:058eddde05b4354307975f1ecd25cfda9f8a282ad2e3b4f168ff8fee3c3623a1", size = 4310036, upload-time = "2025-10-17T20:25:56.782Z" }, + { url = "https://files.pythonhosted.org/packages/9a/31/7f4750fc9bb0ec18a9534549e4c80ea63f1267aa828d495a48bbf0018f49/pyomo-6.9.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:105a073c47a2d2d6e74e48ed6fc82c6f6d19027488d5003aabb7ed5d10271483", size = 4297011, upload-time = "2025-10-17T20:26:00.976Z" }, + { url = "https://files.pythonhosted.org/packages/f8/67/639d0006eddab30cf415b0154763ccc51f3c15b934e866eb4fb07bc2b6ed/pyomo-6.9.5-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f2c636c2c640b33dde3b119f6f0941a1bbde39397c392dba55351b0438d8600f", size = 4360501, upload-time = "2025-10-17T21:06:45.673Z" }, + { url = "https://files.pythonhosted.org/packages/67/ef/023b74b8f161f15a51febdd160354f1e3fd7e1475abbe5ccfb3d7588cf1f/pyomo-6.9.5-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e02813b4021eeed7214a1ca5d7daecbdc78d3db7059962553a57fd138d747c22", size = 4391836, upload-time = "2025-10-17T20:26:05.491Z" }, + { url = "https://files.pythonhosted.org/packages/a0/ca/edab1b532fd5e2d146d0cb96836eb5ae387b8a5bd255213e306793f6168e/pyomo-6.9.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:83789ce89271da31e0ff5bbef692af1621ab1747798183a5603b6577b7074277", size = 4330906, upload-time = "2025-10-17T20:26:09.977Z" }, + { url = "https://files.pythonhosted.org/packages/a9/3c/2745386f57030bc60b626adba002b68db3f9538d5b52900f48026a4a17d7/pyomo-6.9.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1f449aaceac5078daaecc21d19b96a15529f9ac8aa90f6472e8811cc07112ecc", size = 4316124, upload-time = "2025-10-17T20:26:14.339Z" }, + { url = "https://files.pythonhosted.org/packages/f1/93/2058af0890b13f7e1a26e4925ff8d681c23d9cbdc2ecc9db17c744941617/pyomo-6.9.5-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f94d03f122fcf04a769c28ad48c423cd7b6d3d2c40da20bc8ea1a41bb20d0c36", size = 4356089, upload-time = "2025-10-17T21:06:50.178Z" }, + { url = "https://files.pythonhosted.org/packages/de/30/c808931fc034851a16d3f8360d045b087ac743ea97bfe96cdb4b1df47c21/pyomo-6.9.5-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:96ff300e96cdab75e2e6983c99e3a61eaff2a6d0f5ed83acd939e74e361de537", size = 4382150, upload-time = "2025-10-17T20:26:18.734Z" }, + { url = "https://files.pythonhosted.org/packages/68/29/394967f7df51788cbdf1b4aedfb7c5a3a62e11b85b4c9d806b86cc576be4/pyomo-6.9.5-py3-none-any.whl", hash = "sha256:60326f7d3143ee7d0f5c5c4a3cbf871b53e08cc6c2b0c9e6d25568880233472f", size = 3938900, upload-time = "2025-10-17T20:22:07.473Z" }, ] [[package]] @@ -965,6 +1006,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, ] +[[package]] +name = "rich" +version = "14.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fb/d2/8920e102050a0de7bfabeb4c4614a49248cf8d5d7a8d01885fbb24dc767a/rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4", size = 219990, upload-time = "2025-10-09T14:16:53.064Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393, upload-time = "2025-10-09T14:16:51.245Z" }, +] + [[package]] name = "roman-numerals-py" version = "3.1.0" @@ -1001,7 +1055,7 @@ wheels = [ [[package]] name = "salib" -version = "1.5.1" +version = "1.5.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "matplotlib" }, @@ -1010,47 +1064,70 @@ dependencies = [ { name = "pandas" }, { name = "scipy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/8c/3e09d6b40f90ccf04b1308a88b7bf496596704e01ca30782a524d025a0e1/salib-1.5.1.tar.gz", hash = "sha256:e4a9c319b8dd02995a8dc983f57c452cb7e5b6dbd43e7b7856c90cb6a332bb5f", size = 725018, upload-time = "2024-08-19T16:35:25.825Z" } +sdist = { url = "https://files.pythonhosted.org/packages/16/63/bdde6c303e95e2c819c668076fb3255f4453ee2041103d0edd18a90b6839/salib-1.5.2.tar.gz", hash = "sha256:a8eeedc4e87cf070f7ef450b76cdecd120d1e5c602a9c35855ec7777591f949f", size = 725859, upload-time = "2025-10-12T02:38:50.303Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e1/40/393b381779d379afbb0e281d9f69cb511022e41a726f7871a929faec2b11/salib-1.5.1-py3-none-any.whl", hash = "sha256:a978b619c5a93eb14dd8c527f12e22d354b02f1f7143aba3cb84c1c7bc1382e5", size = 778858, upload-time = "2024-08-19T16:35:23.951Z" }, + { url = "https://files.pythonhosted.org/packages/13/e2/9fbf2d571c0d5360f9cf6656de6c94b273d08ede1b628f23f319fa1a910d/salib-1.5.2-py3-none-any.whl", hash = "sha256:6f4b6bebc1eeed1d081c8f951fa8c2ad7b0cd8a7159d206af48ef137cc806c43", size = 780059, upload-time = "2025-10-12T02:38:48.878Z" }, ] [[package]] name = "scipy" -version = "1.16.0" +version = "1.16.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/81/18/b06a83f0c5ee8cddbde5e3f3d0bb9b702abfa5136ef6d4620ff67df7eee5/scipy-1.16.0.tar.gz", hash = "sha256:b5ef54021e832869c8cfb03bc3bf20366cbcd426e02a58e8a58d7584dfbb8f62", size = 30581216, upload-time = "2025-06-22T16:27:55.782Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/01/c0/c943bc8d2bbd28123ad0f4f1eef62525fa1723e84d136b32965dcb6bad3a/scipy-1.16.0-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:7eb6bd33cef4afb9fa5f1fb25df8feeb1e52d94f21a44f1d17805b41b1da3180", size = 36459071, upload-time = "2025-06-22T16:19:06.605Z" }, - { url = "https://files.pythonhosted.org/packages/99/0d/270e2e9f1a4db6ffbf84c9a0b648499842046e4e0d9b2275d150711b3aba/scipy-1.16.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:1dbc8fdba23e4d80394ddfab7a56808e3e6489176d559c6c71935b11a2d59db1", size = 28490500, upload-time = "2025-06-22T16:19:11.775Z" }, - { url = "https://files.pythonhosted.org/packages/1c/22/01d7ddb07cff937d4326198ec8d10831367a708c3da72dfd9b7ceaf13028/scipy-1.16.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:7dcf42c380e1e3737b343dec21095c9a9ad3f9cbe06f9c05830b44b1786c9e90", size = 20762345, upload-time = "2025-06-22T16:19:15.813Z" }, - { url = "https://files.pythonhosted.org/packages/34/7f/87fd69856569ccdd2a5873fe5d7b5bbf2ad9289d7311d6a3605ebde3a94b/scipy-1.16.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:26ec28675f4a9d41587266084c626b02899db373717d9312fa96ab17ca1ae94d", size = 23418563, upload-time = "2025-06-22T16:19:20.746Z" }, - { url = "https://files.pythonhosted.org/packages/f6/f1/e4f4324fef7f54160ab749efbab6a4bf43678a9eb2e9817ed71a0a2fd8de/scipy-1.16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:952358b7e58bd3197cfbd2f2f2ba829f258404bdf5db59514b515a8fe7a36c52", size = 33203951, upload-time = "2025-06-22T16:19:25.813Z" }, - { url = "https://files.pythonhosted.org/packages/6d/f0/b6ac354a956384fd8abee2debbb624648125b298f2c4a7b4f0d6248048a5/scipy-1.16.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:03931b4e870c6fef5b5c0970d52c9f6ddd8c8d3e934a98f09308377eba6f3824", size = 35070225, upload-time = "2025-06-22T16:19:31.416Z" }, - { url = "https://files.pythonhosted.org/packages/e5/73/5cbe4a3fd4bc3e2d67ffad02c88b83edc88f381b73ab982f48f3df1a7790/scipy-1.16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:512c4f4f85912767c351a0306824ccca6fd91307a9f4318efe8fdbd9d30562ef", size = 35389070, upload-time = "2025-06-22T16:19:37.387Z" }, - { url = "https://files.pythonhosted.org/packages/86/e8/a60da80ab9ed68b31ea5a9c6dfd3c2f199347429f229bf7f939a90d96383/scipy-1.16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e69f798847e9add03d512eaf5081a9a5c9a98757d12e52e6186ed9681247a1ac", size = 37825287, upload-time = "2025-06-22T16:19:43.375Z" }, - { url = "https://files.pythonhosted.org/packages/ea/b5/29fece1a74c6a94247f8a6fb93f5b28b533338e9c34fdcc9cfe7a939a767/scipy-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:adf9b1999323ba335adc5d1dc7add4781cb5a4b0ef1e98b79768c05c796c4e49", size = 38431929, upload-time = "2025-06-22T16:19:49.385Z" }, - { url = "https://files.pythonhosted.org/packages/46/95/0746417bc24be0c2a7b7563946d61f670a3b491b76adede420e9d173841f/scipy-1.16.0-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:e9f414cbe9ca289a73e0cc92e33a6a791469b6619c240aa32ee18abdce8ab451", size = 36418162, upload-time = "2025-06-22T16:19:56.3Z" }, - { url = "https://files.pythonhosted.org/packages/19/5a/914355a74481b8e4bbccf67259bbde171348a3f160b67b4945fbc5f5c1e5/scipy-1.16.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:bbba55fb97ba3cdef9b1ee973f06b09d518c0c7c66a009c729c7d1592be1935e", size = 28465985, upload-time = "2025-06-22T16:20:01.238Z" }, - { url = "https://files.pythonhosted.org/packages/58/46/63477fc1246063855969cbefdcee8c648ba4b17f67370bd542ba56368d0b/scipy-1.16.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:58e0d4354eacb6004e7aa1cd350e5514bd0270acaa8d5b36c0627bb3bb486974", size = 20737961, upload-time = "2025-06-22T16:20:05.913Z" }, - { url = "https://files.pythonhosted.org/packages/93/86/0fbb5588b73555e40f9d3d6dde24ee6fac7d8e301a27f6f0cab9d8f66ff2/scipy-1.16.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:75b2094ec975c80efc273567436e16bb794660509c12c6a31eb5c195cbf4b6dc", size = 23377941, upload-time = "2025-06-22T16:20:10.668Z" }, - { url = "https://files.pythonhosted.org/packages/ca/80/a561f2bf4c2da89fa631b3cbf31d120e21ea95db71fd9ec00cb0247c7a93/scipy-1.16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6b65d232157a380fdd11a560e7e21cde34fdb69d65c09cb87f6cc024ee376351", size = 33196703, upload-time = "2025-06-22T16:20:16.097Z" }, - { url = "https://files.pythonhosted.org/packages/11/6b/3443abcd0707d52e48eb315e33cc669a95e29fc102229919646f5a501171/scipy-1.16.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d8747f7736accd39289943f7fe53a8333be7f15a82eea08e4afe47d79568c32", size = 35083410, upload-time = "2025-06-22T16:20:21.734Z" }, - { url = "https://files.pythonhosted.org/packages/20/ab/eb0fc00e1e48961f1bd69b7ad7e7266896fe5bad4ead91b5fc6b3561bba4/scipy-1.16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eb9f147a1b8529bb7fec2a85cf4cf42bdfadf9e83535c309a11fdae598c88e8b", size = 35387829, upload-time = "2025-06-22T16:20:27.548Z" }, - { url = "https://files.pythonhosted.org/packages/57/9e/d6fc64e41fad5d481c029ee5a49eefc17f0b8071d636a02ceee44d4a0de2/scipy-1.16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d2b83c37edbfa837a8923d19c749c1935ad3d41cf196006a24ed44dba2ec4358", size = 37841356, upload-time = "2025-06-22T16:20:35.112Z" }, - { url = "https://files.pythonhosted.org/packages/7c/a7/4c94bbe91f12126b8bf6709b2471900577b7373a4fd1f431f28ba6f81115/scipy-1.16.0-cp313-cp313-win_amd64.whl", hash = "sha256:79a3c13d43c95aa80b87328a46031cf52508cf5f4df2767602c984ed1d3c6bbe", size = 38403710, upload-time = "2025-06-22T16:21:54.473Z" }, - { url = "https://files.pythonhosted.org/packages/47/20/965da8497f6226e8fa90ad3447b82ed0e28d942532e92dd8b91b43f100d4/scipy-1.16.0-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:f91b87e1689f0370690e8470916fe1b2308e5b2061317ff76977c8f836452a47", size = 36813833, upload-time = "2025-06-22T16:20:43.925Z" }, - { url = "https://files.pythonhosted.org/packages/28/f4/197580c3dac2d234e948806e164601c2df6f0078ed9f5ad4a62685b7c331/scipy-1.16.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:88a6ca658fb94640079e7a50b2ad3b67e33ef0f40e70bdb7dc22017dae73ac08", size = 28974431, upload-time = "2025-06-22T16:20:51.302Z" }, - { url = "https://files.pythonhosted.org/packages/8a/fc/e18b8550048d9224426e76906694c60028dbdb65d28b1372b5503914b89d/scipy-1.16.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:ae902626972f1bd7e4e86f58fd72322d7f4ec7b0cfc17b15d4b7006efc385176", size = 21246454, upload-time = "2025-06-22T16:20:57.276Z" }, - { url = "https://files.pythonhosted.org/packages/8c/48/07b97d167e0d6a324bfd7484cd0c209cc27338b67e5deadae578cf48e809/scipy-1.16.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:8cb824c1fc75ef29893bc32b3ddd7b11cf9ab13c1127fe26413a05953b8c32ed", size = 23772979, upload-time = "2025-06-22T16:21:03.363Z" }, - { url = "https://files.pythonhosted.org/packages/4c/4f/9efbd3f70baf9582edf271db3002b7882c875ddd37dc97f0f675ad68679f/scipy-1.16.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:de2db7250ff6514366a9709c2cba35cb6d08498e961cba20d7cff98a7ee88938", size = 33341972, upload-time = "2025-06-22T16:21:11.14Z" }, - { url = "https://files.pythonhosted.org/packages/3f/dc/9e496a3c5dbe24e76ee24525155ab7f659c20180bab058ef2c5fa7d9119c/scipy-1.16.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e85800274edf4db8dd2e4e93034f92d1b05c9421220e7ded9988b16976f849c1", size = 35185476, upload-time = "2025-06-22T16:21:19.156Z" }, - { url = "https://files.pythonhosted.org/packages/ce/b3/21001cff985a122ba434c33f2c9d7d1dc3b669827e94f4fc4e1fe8b9dfd8/scipy-1.16.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4f720300a3024c237ace1cb11f9a84c38beb19616ba7c4cdcd771047a10a1706", size = 35570990, upload-time = "2025-06-22T16:21:27.797Z" }, - { url = "https://files.pythonhosted.org/packages/e5/d3/7ba42647d6709251cdf97043d0c107e0317e152fa2f76873b656b509ff55/scipy-1.16.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:aad603e9339ddb676409b104c48a027e9916ce0d2838830691f39552b38a352e", size = 37950262, upload-time = "2025-06-22T16:21:36.976Z" }, - { url = "https://files.pythonhosted.org/packages/eb/c4/231cac7a8385394ebbbb4f1ca662203e9d8c332825ab4f36ffc3ead09a42/scipy-1.16.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f56296fefca67ba605fd74d12f7bd23636267731a72cb3947963e76b8c0a25db", size = 38515076, upload-time = "2025-06-22T16:21:45.694Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/0a/ca/d8ace4f98322d01abcd52d381134344bf7b431eba7ed8b42bdea5a3c2ac9/scipy-1.16.3.tar.gz", hash = "sha256:01e87659402762f43bd2fee13370553a17ada367d42e7487800bf2916535aecb", size = 30597883, upload-time = "2025-10-28T17:38:54.068Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/41/5bf55c3f386b1643812f3a5674edf74b26184378ef0f3e7c7a09a7e2ca7f/scipy-1.16.3-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:81fc5827606858cf71446a5e98715ba0e11f0dbc83d71c7409d05486592a45d6", size = 36659043, upload-time = "2025-10-28T17:32:40.285Z" }, + { url = "https://files.pythonhosted.org/packages/1e/0f/65582071948cfc45d43e9870bf7ca5f0e0684e165d7c9ef4e50d783073eb/scipy-1.16.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:c97176013d404c7346bf57874eaac5187d969293bf40497140b0a2b2b7482e07", size = 28898986, upload-time = "2025-10-28T17:32:45.325Z" }, + { url = "https://files.pythonhosted.org/packages/96/5e/36bf3f0ac298187d1ceadde9051177d6a4fe4d507e8f59067dc9dd39e650/scipy-1.16.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:2b71d93c8a9936046866acebc915e2af2e292b883ed6e2cbe5c34beb094b82d9", size = 20889814, upload-time = "2025-10-28T17:32:49.277Z" }, + { url = "https://files.pythonhosted.org/packages/80/35/178d9d0c35394d5d5211bbff7ac4f2986c5488b59506fef9e1de13ea28d3/scipy-1.16.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3d4a07a8e785d80289dfe66b7c27d8634a773020742ec7187b85ccc4b0e7b686", size = 23565795, upload-time = "2025-10-28T17:32:53.337Z" }, + { url = "https://files.pythonhosted.org/packages/fa/46/d1146ff536d034d02f83c8afc3c4bab2eddb634624d6529a8512f3afc9da/scipy-1.16.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0553371015692a898e1aa858fed67a3576c34edefa6b7ebdb4e9dde49ce5c203", size = 33349476, upload-time = "2025-10-28T17:32:58.353Z" }, + { url = "https://files.pythonhosted.org/packages/79/2e/415119c9ab3e62249e18c2b082c07aff907a273741b3f8160414b0e9193c/scipy-1.16.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:72d1717fd3b5e6ec747327ce9bda32d5463f472c9dce9f54499e81fbd50245a1", size = 35676692, upload-time = "2025-10-28T17:33:03.88Z" }, + { url = "https://files.pythonhosted.org/packages/27/82/df26e44da78bf8d2aeaf7566082260cfa15955a5a6e96e6a29935b64132f/scipy-1.16.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1fb2472e72e24d1530debe6ae078db70fb1605350c88a3d14bc401d6306dbffe", size = 36019345, upload-time = "2025-10-28T17:33:09.773Z" }, + { url = "https://files.pythonhosted.org/packages/82/31/006cbb4b648ba379a95c87262c2855cd0d09453e500937f78b30f02fa1cd/scipy-1.16.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c5192722cffe15f9329a3948c4b1db789fbb1f05c97899187dcf009b283aea70", size = 38678975, upload-time = "2025-10-28T17:33:15.809Z" }, + { url = "https://files.pythonhosted.org/packages/c2/7f/acbd28c97e990b421af7d6d6cd416358c9c293fc958b8529e0bd5d2a2a19/scipy-1.16.3-cp312-cp312-win_amd64.whl", hash = "sha256:56edc65510d1331dae01ef9b658d428e33ed48b4f77b1d51caf479a0253f96dc", size = 38555926, upload-time = "2025-10-28T17:33:21.388Z" }, + { url = "https://files.pythonhosted.org/packages/ce/69/c5c7807fd007dad4f48e0a5f2153038dc96e8725d3345b9ee31b2b7bed46/scipy-1.16.3-cp312-cp312-win_arm64.whl", hash = "sha256:a8a26c78ef223d3e30920ef759e25625a0ecdd0d60e5a8818b7513c3e5384cf2", size = 25463014, upload-time = "2025-10-28T17:33:25.975Z" }, + { url = "https://files.pythonhosted.org/packages/72/f1/57e8327ab1508272029e27eeef34f2302ffc156b69e7e233e906c2a5c379/scipy-1.16.3-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:d2ec56337675e61b312179a1ad124f5f570c00f920cc75e1000025451b88241c", size = 36617856, upload-time = "2025-10-28T17:33:31.375Z" }, + { url = "https://files.pythonhosted.org/packages/44/13/7e63cfba8a7452eb756306aa2fd9b37a29a323b672b964b4fdeded9a3f21/scipy-1.16.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:16b8bc35a4cc24db80a0ec836a9286d0e31b2503cb2fd7ff7fb0e0374a97081d", size = 28874306, upload-time = "2025-10-28T17:33:36.516Z" }, + { url = "https://files.pythonhosted.org/packages/15/65/3a9400efd0228a176e6ec3454b1fa998fbbb5a8defa1672c3f65706987db/scipy-1.16.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:5803c5fadd29de0cf27fa08ccbfe7a9e5d741bf63e4ab1085437266f12460ff9", size = 20865371, upload-time = "2025-10-28T17:33:42.094Z" }, + { url = "https://files.pythonhosted.org/packages/33/d7/eda09adf009a9fb81827194d4dd02d2e4bc752cef16737cc4ef065234031/scipy-1.16.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:b81c27fc41954319a943d43b20e07c40bdcd3ff7cf013f4fb86286faefe546c4", size = 23524877, upload-time = "2025-10-28T17:33:48.483Z" }, + { url = "https://files.pythonhosted.org/packages/7d/6b/3f911e1ebc364cb81320223a3422aab7d26c9c7973109a9cd0f27c64c6c0/scipy-1.16.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0c3b4dd3d9b08dbce0f3440032c52e9e2ab9f96ade2d3943313dfe51a7056959", size = 33342103, upload-time = "2025-10-28T17:33:56.495Z" }, + { url = "https://files.pythonhosted.org/packages/21/f6/4bfb5695d8941e5c570a04d9fcd0d36bce7511b7d78e6e75c8f9791f82d0/scipy-1.16.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7dc1360c06535ea6116a2220f760ae572db9f661aba2d88074fe30ec2aa1ff88", size = 35697297, upload-time = "2025-10-28T17:34:04.722Z" }, + { url = "https://files.pythonhosted.org/packages/04/e1/6496dadbc80d8d896ff72511ecfe2316b50313bfc3ebf07a3f580f08bd8c/scipy-1.16.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:663b8d66a8748051c3ee9c96465fb417509315b99c71550fda2591d7dd634234", size = 36021756, upload-time = "2025-10-28T17:34:13.482Z" }, + { url = "https://files.pythonhosted.org/packages/fe/bd/a8c7799e0136b987bda3e1b23d155bcb31aec68a4a472554df5f0937eef7/scipy-1.16.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eab43fae33a0c39006a88096cd7b4f4ef545ea0447d250d5ac18202d40b6611d", size = 38696566, upload-time = "2025-10-28T17:34:22.384Z" }, + { url = "https://files.pythonhosted.org/packages/cd/01/1204382461fcbfeb05b6161b594f4007e78b6eba9b375382f79153172b4d/scipy-1.16.3-cp313-cp313-win_amd64.whl", hash = "sha256:062246acacbe9f8210de8e751b16fc37458213f124bef161a5a02c7a39284304", size = 38529877, upload-time = "2025-10-28T17:35:51.076Z" }, + { url = "https://files.pythonhosted.org/packages/7f/14/9d9fbcaa1260a94f4bb5b64ba9213ceb5d03cd88841fe9fd1ffd47a45b73/scipy-1.16.3-cp313-cp313-win_arm64.whl", hash = "sha256:50a3dbf286dbc7d84f176f9a1574c705f277cb6565069f88f60db9eafdbe3ee2", size = 25455366, upload-time = "2025-10-28T17:35:59.014Z" }, + { url = "https://files.pythonhosted.org/packages/e2/a3/9ec205bd49f42d45d77f1730dbad9ccf146244c1647605cf834b3a8c4f36/scipy-1.16.3-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:fb4b29f4cf8cc5a8d628bc8d8e26d12d7278cd1f219f22698a378c3d67db5e4b", size = 37027931, upload-time = "2025-10-28T17:34:31.451Z" }, + { url = "https://files.pythonhosted.org/packages/25/06/ca9fd1f3a4589cbd825b1447e5db3a8ebb969c1eaf22c8579bd286f51b6d/scipy-1.16.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:8d09d72dc92742988b0e7750bddb8060b0c7079606c0d24a8cc8e9c9c11f9079", size = 29400081, upload-time = "2025-10-28T17:34:39.087Z" }, + { url = "https://files.pythonhosted.org/packages/6a/56/933e68210d92657d93fb0e381683bc0e53a965048d7358ff5fbf9e6a1b17/scipy-1.16.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:03192a35e661470197556de24e7cb1330d84b35b94ead65c46ad6f16f6b28f2a", size = 21391244, upload-time = "2025-10-28T17:34:45.234Z" }, + { url = "https://files.pythonhosted.org/packages/a8/7e/779845db03dc1418e215726329674b40576879b91814568757ff0014ad65/scipy-1.16.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:57d01cb6f85e34f0946b33caa66e892aae072b64b034183f3d87c4025802a119", size = 23929753, upload-time = "2025-10-28T17:34:51.793Z" }, + { url = "https://files.pythonhosted.org/packages/4c/4b/f756cf8161d5365dcdef9e5f460ab226c068211030a175d2fc7f3f41ca64/scipy-1.16.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:96491a6a54e995f00a28a3c3badfff58fd093bf26cd5fb34a2188c8c756a3a2c", size = 33496912, upload-time = "2025-10-28T17:34:59.8Z" }, + { url = "https://files.pythonhosted.org/packages/09/b5/222b1e49a58668f23839ca1542a6322bb095ab8d6590d4f71723869a6c2c/scipy-1.16.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cd13e354df9938598af2be05822c323e97132d5e6306b83a3b4ee6724c6e522e", size = 35802371, upload-time = "2025-10-28T17:35:08.173Z" }, + { url = "https://files.pythonhosted.org/packages/c1/8d/5964ef68bb31829bde27611f8c9deeac13764589fe74a75390242b64ca44/scipy-1.16.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:63d3cdacb8a824a295191a723ee5e4ea7768ca5ca5f2838532d9f2e2b3ce2135", size = 36190477, upload-time = "2025-10-28T17:35:16.7Z" }, + { url = "https://files.pythonhosted.org/packages/ab/f2/b31d75cb9b5fa4dd39a0a931ee9b33e7f6f36f23be5ef560bf72e0f92f32/scipy-1.16.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e7efa2681ea410b10dde31a52b18b0154d66f2485328830e45fdf183af5aefc6", size = 38796678, upload-time = "2025-10-28T17:35:26.354Z" }, + { url = "https://files.pythonhosted.org/packages/b4/1e/b3723d8ff64ab548c38d87055483714fefe6ee20e0189b62352b5e015bb1/scipy-1.16.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2d1ae2cf0c350e7705168ff2429962a89ad90c2d49d1dd300686d8b2a5af22fc", size = 38640178, upload-time = "2025-10-28T17:35:35.304Z" }, + { url = "https://files.pythonhosted.org/packages/8e/f3/d854ff38789aca9b0cc23008d607ced9de4f7ab14fa1ca4329f86b3758ca/scipy-1.16.3-cp313-cp313t-win_arm64.whl", hash = "sha256:0c623a54f7b79dd88ef56da19bc2873afec9673a48f3b85b18e4d402bdd29a5a", size = 25803246, upload-time = "2025-10-28T17:35:42.155Z" }, + { url = "https://files.pythonhosted.org/packages/99/f6/99b10fd70f2d864c1e29a28bbcaa0c6340f9d8518396542d9ea3b4aaae15/scipy-1.16.3-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:875555ce62743e1d54f06cdf22c1e0bc47b91130ac40fe5d783b6dfa114beeb6", size = 36606469, upload-time = "2025-10-28T17:36:08.741Z" }, + { url = "https://files.pythonhosted.org/packages/4d/74/043b54f2319f48ea940dd025779fa28ee360e6b95acb7cd188fad4391c6b/scipy-1.16.3-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:bb61878c18a470021fb515a843dc7a76961a8daceaaaa8bad1332f1bf4b54657", size = 28872043, upload-time = "2025-10-28T17:36:16.599Z" }, + { url = "https://files.pythonhosted.org/packages/4d/e1/24b7e50cc1c4ee6ffbcb1f27fe9f4c8b40e7911675f6d2d20955f41c6348/scipy-1.16.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:f2622206f5559784fa5c4b53a950c3c7c1cf3e84ca1b9c4b6c03f062f289ca26", size = 20862952, upload-time = "2025-10-28T17:36:22.966Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3a/3e8c01a4d742b730df368e063787c6808597ccb38636ed821d10b39ca51b/scipy-1.16.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:7f68154688c515cdb541a31ef8eb66d8cd1050605be9dcd74199cbd22ac739bc", size = 23508512, upload-time = "2025-10-28T17:36:29.731Z" }, + { url = "https://files.pythonhosted.org/packages/1f/60/c45a12b98ad591536bfe5330cb3cfe1850d7570259303563b1721564d458/scipy-1.16.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3c820ddb80029fe9f43d61b81d8b488d3ef8ca010d15122b152db77dc94c22", size = 33413639, upload-time = "2025-10-28T17:36:37.982Z" }, + { url = "https://files.pythonhosted.org/packages/71/bc/35957d88645476307e4839712642896689df442f3e53b0fa016ecf8a3357/scipy-1.16.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d3837938ae715fc0fe3c39c0202de3a8853aff22ca66781ddc2ade7554b7e2cc", size = 35704729, upload-time = "2025-10-28T17:36:46.547Z" }, + { url = "https://files.pythonhosted.org/packages/3b/15/89105e659041b1ca11c386e9995aefacd513a78493656e57789f9d9eab61/scipy-1.16.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:aadd23f98f9cb069b3bd64ddc900c4d277778242e961751f77a8cb5c4b946fb0", size = 36086251, upload-time = "2025-10-28T17:36:55.161Z" }, + { url = "https://files.pythonhosted.org/packages/1a/87/c0ea673ac9c6cc50b3da2196d860273bc7389aa69b64efa8493bdd25b093/scipy-1.16.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b7c5f1bda1354d6a19bc6af73a649f8285ca63ac6b52e64e658a5a11d4d69800", size = 38716681, upload-time = "2025-10-28T17:37:04.1Z" }, + { url = "https://files.pythonhosted.org/packages/91/06/837893227b043fb9b0d13e4bd7586982d8136cb249ffb3492930dab905b8/scipy-1.16.3-cp314-cp314-win_amd64.whl", hash = "sha256:e5d42a9472e7579e473879a1990327830493a7047506d58d73fc429b84c1d49d", size = 39358423, upload-time = "2025-10-28T17:38:20.005Z" }, + { url = "https://files.pythonhosted.org/packages/95/03/28bce0355e4d34a7c034727505a02d19548549e190bedd13a721e35380b7/scipy-1.16.3-cp314-cp314-win_arm64.whl", hash = "sha256:6020470b9d00245926f2d5bb93b119ca0340f0d564eb6fbaad843eaebf9d690f", size = 26135027, upload-time = "2025-10-28T17:38:24.966Z" }, + { url = "https://files.pythonhosted.org/packages/b2/6f/69f1e2b682efe9de8fe9f91040f0cd32f13cfccba690512ba4c582b0bc29/scipy-1.16.3-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:e1d27cbcb4602680a49d787d90664fa4974063ac9d4134813332a8c53dbe667c", size = 37028379, upload-time = "2025-10-28T17:37:14.061Z" }, + { url = "https://files.pythonhosted.org/packages/7c/2d/e826f31624a5ebbab1cd93d30fd74349914753076ed0593e1d56a98c4fb4/scipy-1.16.3-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:9b9c9c07b6d56a35777a1b4cc8966118fb16cfd8daf6743867d17d36cfad2d40", size = 29400052, upload-time = "2025-10-28T17:37:21.709Z" }, + { url = "https://files.pythonhosted.org/packages/69/27/d24feb80155f41fd1f156bf144e7e049b4e2b9dd06261a242905e3bc7a03/scipy-1.16.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:3a4c460301fb2cffb7f88528f30b3127742cff583603aa7dc964a52c463b385d", size = 21391183, upload-time = "2025-10-28T17:37:29.559Z" }, + { url = "https://files.pythonhosted.org/packages/f8/d3/1b229e433074c5738a24277eca520a2319aac7465eea7310ea6ae0e98ae2/scipy-1.16.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:f667a4542cc8917af1db06366d3f78a5c8e83badd56409f94d1eac8d8d9133fa", size = 23930174, upload-time = "2025-10-28T17:37:36.306Z" }, + { url = "https://files.pythonhosted.org/packages/16/9d/d9e148b0ec680c0f042581a2be79a28a7ab66c0c4946697f9e7553ead337/scipy-1.16.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f379b54b77a597aa7ee5e697df0d66903e41b9c85a6dd7946159e356319158e8", size = 33497852, upload-time = "2025-10-28T17:37:42.228Z" }, + { url = "https://files.pythonhosted.org/packages/2f/22/4e5f7561e4f98b7bea63cf3fd7934bff1e3182e9f1626b089a679914d5c8/scipy-1.16.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4aff59800a3b7f786b70bfd6ab551001cb553244988d7d6b8299cb1ea653b353", size = 35798595, upload-time = "2025-10-28T17:37:48.102Z" }, + { url = "https://files.pythonhosted.org/packages/83/42/6644d714c179429fc7196857866f219fef25238319b650bb32dde7bf7a48/scipy-1.16.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:da7763f55885045036fabcebd80144b757d3db06ab0861415d1c3b7c69042146", size = 36186269, upload-time = "2025-10-28T17:37:53.72Z" }, + { url = "https://files.pythonhosted.org/packages/ac/70/64b4d7ca92f9cf2e6fc6aaa2eecf80bb9b6b985043a9583f32f8177ea122/scipy-1.16.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ffa6eea95283b2b8079b821dc11f50a17d0571c92b43e2b5b12764dc5f9b285d", size = 38802779, upload-time = "2025-10-28T17:37:59.393Z" }, + { url = "https://files.pythonhosted.org/packages/61/82/8d0e39f62764cce5ffd5284131e109f07cf8955aef9ab8ed4e3aa5e30539/scipy-1.16.3-cp314-cp314t-win_amd64.whl", hash = "sha256:d9f48cafc7ce94cf9b15c6bffdc443a81a27bf7075cf2dcd5c8b40f85d10c4e7", size = 39471128, upload-time = "2025-10-28T17:38:05.259Z" }, + { url = "https://files.pythonhosted.org/packages/64/47/a494741db7280eae6dc033510c319e34d42dd41b7ac0c7ead39354d1a2b5/scipy-1.16.3-cp314-cp314t-win_arm64.whl", hash = "sha256:21d9d6b197227a12dcbf9633320a4e34c6b0e51c57268df255a0942983bac562", size = 26464127, upload-time = "2025-10-28T17:38:11.34Z" }, ] [[package]] @@ -1067,6 +1144,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987", size = 294914, upload-time = "2024-01-25T13:21:49.598Z" }, ] +[[package]] +name = "shellingham" +version = "1.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, +] + [[package]] name = "six" version = "1.17.0" @@ -1234,10 +1320,12 @@ dependencies = [ { name = "pydoe" }, { name = "pyomo" }, { name = "pytest" }, + { name = "rich" }, { name = "salib" }, { name = "scipy" }, { name = "seaborn" }, { name = "tabulate" }, + { name = "typer" }, { name = "xlsxwriter" }, ] @@ -1285,6 +1373,7 @@ requires-dist = [ { name = "pydoe", specifier = ">=0.3.8" }, { name = "pyomo", specifier = ">=6.8.0" }, { name = "pytest", specifier = ">=8.3.2" }, + { name = "rich", specifier = ">=14.2.0" }, { name = "salib", specifier = ">=1.5.1" }, { name = "scipy", specifier = ">=1.14.1" }, { name = "seaborn", specifier = ">=0.13.2" }, @@ -1295,6 +1384,7 @@ requires-dist = [ { name = "sphinxcontrib-htmlhelp", marker = "extra == 'docs'", specifier = ">=2.1.0" }, { name = "sphinxcontrib-serializinghtml", marker = "extra == 'docs'", specifier = ">=2.0.0" }, { name = "tabulate", specifier = ">=0.9.0" }, + { name = "typer", specifier = ">=0.20.0" }, { name = "xlsxwriter", specifier = ">=3.2.0" }, ] provides-extras = ["docs", "plotting", "solver"] @@ -1311,6 +1401,21 @@ dev = [ { name = "types-networkx", specifier = ">=3.5.0.20251001" }, ] +[[package]] +name = "typer" +version = "0.20.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "rich" }, + { name = "shellingham" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8f/28/7c85c8032b91dbe79725b6f17d2fffc595dff06a35c7a30a37bef73a1ab4/typer-0.20.0.tar.gz", hash = "sha256:1aaf6494031793e4876fb0bacfa6a912b551cf43c1e63c800df8b1a866720c37", size = 106492, upload-time = "2025-10-20T17:03:49.445Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/64/7713ffe4b5983314e9d436a90d5bd4f63b6054e2aca783a3cfc44cb95bbf/typer-0.20.0-py3-none-any.whl", hash = "sha256:5b463df6793ec1dca6213a3cf4c0f03bc6e322ac5e16e13ddd622a889489784a", size = 47028, upload-time = "2025-10-20T17:03:47.617Z" }, +] + [[package]] name = "types-deprecated" version = "1.2.15.20250304" @@ -1384,51 +1489,78 @@ wheels = [ [[package]] name = "wrapt" -version = "1.17.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c3/fc/e91cc220803d7bc4db93fb02facd8461c37364151b8494762cc88b0fbcef/wrapt-1.17.2.tar.gz", hash = "sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3", size = 55531, upload-time = "2025-01-14T10:35:45.465Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/bd/ab55f849fd1f9a58ed7ea47f5559ff09741b25f00c191231f9f059c83949/wrapt-1.17.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d5e2439eecc762cd85e7bd37161d4714aa03a33c5ba884e26c81559817ca0925", size = 53799, upload-time = "2025-01-14T10:33:57.4Z" }, - { url = "https://files.pythonhosted.org/packages/53/18/75ddc64c3f63988f5a1d7e10fb204ffe5762bc663f8023f18ecaf31a332e/wrapt-1.17.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fc7cb4c1c744f8c05cd5f9438a3caa6ab94ce8344e952d7c45a8ed59dd88392", size = 38821, upload-time = "2025-01-14T10:33:59.334Z" }, - { url = "https://files.pythonhosted.org/packages/48/2a/97928387d6ed1c1ebbfd4efc4133a0633546bec8481a2dd5ec961313a1c7/wrapt-1.17.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8fdbdb757d5390f7c675e558fd3186d590973244fab0c5fe63d373ade3e99d40", size = 38919, upload-time = "2025-01-14T10:34:04.093Z" }, - { url = "https://files.pythonhosted.org/packages/73/54/3bfe5a1febbbccb7a2f77de47b989c0b85ed3a6a41614b104204a788c20e/wrapt-1.17.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bb1d0dbf99411f3d871deb6faa9aabb9d4e744d67dcaaa05399af89d847a91d", size = 88721, upload-time = "2025-01-14T10:34:07.163Z" }, - { url = "https://files.pythonhosted.org/packages/25/cb/7262bc1b0300b4b64af50c2720ef958c2c1917525238d661c3e9a2b71b7b/wrapt-1.17.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d18a4865f46b8579d44e4fe1e2bcbc6472ad83d98e22a26c963d46e4c125ef0b", size = 80899, upload-time = "2025-01-14T10:34:09.82Z" }, - { url = "https://files.pythonhosted.org/packages/2a/5a/04cde32b07a7431d4ed0553a76fdb7a61270e78c5fd5a603e190ac389f14/wrapt-1.17.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc570b5f14a79734437cb7b0500376b6b791153314986074486e0b0fa8d71d98", size = 89222, upload-time = "2025-01-14T10:34:11.258Z" }, - { url = "https://files.pythonhosted.org/packages/09/28/2e45a4f4771fcfb109e244d5dbe54259e970362a311b67a965555ba65026/wrapt-1.17.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6d9187b01bebc3875bac9b087948a2bccefe464a7d8f627cf6e48b1bbae30f82", size = 86707, upload-time = "2025-01-14T10:34:12.49Z" }, - { url = "https://files.pythonhosted.org/packages/c6/d2/dcb56bf5f32fcd4bd9aacc77b50a539abdd5b6536872413fd3f428b21bed/wrapt-1.17.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9e8659775f1adf02eb1e6f109751268e493c73716ca5761f8acb695e52a756ae", size = 79685, upload-time = "2025-01-14T10:34:15.043Z" }, - { url = "https://files.pythonhosted.org/packages/80/4e/eb8b353e36711347893f502ce91c770b0b0929f8f0bed2670a6856e667a9/wrapt-1.17.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e8b2816ebef96d83657b56306152a93909a83f23994f4b30ad4573b00bd11bb9", size = 87567, upload-time = "2025-01-14T10:34:16.563Z" }, - { url = "https://files.pythonhosted.org/packages/17/27/4fe749a54e7fae6e7146f1c7d914d28ef599dacd4416566c055564080fe2/wrapt-1.17.2-cp312-cp312-win32.whl", hash = "sha256:468090021f391fe0056ad3e807e3d9034e0fd01adcd3bdfba977b6fdf4213ea9", size = 36672, upload-time = "2025-01-14T10:34:17.727Z" }, - { url = "https://files.pythonhosted.org/packages/15/06/1dbf478ea45c03e78a6a8c4be4fdc3c3bddea5c8de8a93bc971415e47f0f/wrapt-1.17.2-cp312-cp312-win_amd64.whl", hash = "sha256:ec89ed91f2fa8e3f52ae53cd3cf640d6feff92ba90d62236a81e4e563ac0e991", size = 38865, upload-time = "2025-01-14T10:34:19.577Z" }, - { url = "https://files.pythonhosted.org/packages/ce/b9/0ffd557a92f3b11d4c5d5e0c5e4ad057bd9eb8586615cdaf901409920b14/wrapt-1.17.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6ed6ffac43aecfe6d86ec5b74b06a5be33d5bb9243d055141e8cabb12aa08125", size = 53800, upload-time = "2025-01-14T10:34:21.571Z" }, - { url = "https://files.pythonhosted.org/packages/c0/ef/8be90a0b7e73c32e550c73cfb2fa09db62234227ece47b0e80a05073b375/wrapt-1.17.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:35621ae4c00e056adb0009f8e86e28eb4a41a4bfa8f9bfa9fca7d343fe94f998", size = 38824, upload-time = "2025-01-14T10:34:22.999Z" }, - { url = "https://files.pythonhosted.org/packages/36/89/0aae34c10fe524cce30fe5fc433210376bce94cf74d05b0d68344c8ba46e/wrapt-1.17.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a604bf7a053f8362d27eb9fefd2097f82600b856d5abe996d623babd067b1ab5", size = 38920, upload-time = "2025-01-14T10:34:25.386Z" }, - { url = "https://files.pythonhosted.org/packages/3b/24/11c4510de906d77e0cfb5197f1b1445d4fec42c9a39ea853d482698ac681/wrapt-1.17.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cbabee4f083b6b4cd282f5b817a867cf0b1028c54d445b7ec7cfe6505057cf8", size = 88690, upload-time = "2025-01-14T10:34:28.058Z" }, - { url = "https://files.pythonhosted.org/packages/71/d7/cfcf842291267bf455b3e266c0c29dcb675b5540ee8b50ba1699abf3af45/wrapt-1.17.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49703ce2ddc220df165bd2962f8e03b84c89fee2d65e1c24a7defff6f988f4d6", size = 80861, upload-time = "2025-01-14T10:34:29.167Z" }, - { url = "https://files.pythonhosted.org/packages/d5/66/5d973e9f3e7370fd686fb47a9af3319418ed925c27d72ce16b791231576d/wrapt-1.17.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8112e52c5822fc4253f3901b676c55ddf288614dc7011634e2719718eaa187dc", size = 89174, upload-time = "2025-01-14T10:34:31.702Z" }, - { url = "https://files.pythonhosted.org/packages/a7/d3/8e17bb70f6ae25dabc1aaf990f86824e4fd98ee9cadf197054e068500d27/wrapt-1.17.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9fee687dce376205d9a494e9c121e27183b2a3df18037f89d69bd7b35bcf59e2", size = 86721, upload-time = "2025-01-14T10:34:32.91Z" }, - { url = "https://files.pythonhosted.org/packages/6f/54/f170dfb278fe1c30d0ff864513cff526d624ab8de3254b20abb9cffedc24/wrapt-1.17.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:18983c537e04d11cf027fbb60a1e8dfd5190e2b60cc27bc0808e653e7b218d1b", size = 79763, upload-time = "2025-01-14T10:34:34.903Z" }, - { url = "https://files.pythonhosted.org/packages/4a/98/de07243751f1c4a9b15c76019250210dd3486ce098c3d80d5f729cba029c/wrapt-1.17.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:703919b1633412ab54bcf920ab388735832fdcb9f9a00ae49387f0fe67dad504", size = 87585, upload-time = "2025-01-14T10:34:36.13Z" }, - { url = "https://files.pythonhosted.org/packages/f9/f0/13925f4bd6548013038cdeb11ee2cbd4e37c30f8bfd5db9e5a2a370d6e20/wrapt-1.17.2-cp313-cp313-win32.whl", hash = "sha256:abbb9e76177c35d4e8568e58650aa6926040d6a9f6f03435b7a522bf1c487f9a", size = 36676, upload-time = "2025-01-14T10:34:37.962Z" }, - { url = "https://files.pythonhosted.org/packages/bf/ae/743f16ef8c2e3628df3ddfd652b7d4c555d12c84b53f3d8218498f4ade9b/wrapt-1.17.2-cp313-cp313-win_amd64.whl", hash = "sha256:69606d7bb691b50a4240ce6b22ebb319c1cfb164e5f6569835058196e0f3a845", size = 38871, upload-time = "2025-01-14T10:34:39.13Z" }, - { url = "https://files.pythonhosted.org/packages/3d/bc/30f903f891a82d402ffb5fda27ec1d621cc97cb74c16fea0b6141f1d4e87/wrapt-1.17.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:4a721d3c943dae44f8e243b380cb645a709ba5bd35d3ad27bc2ed947e9c68192", size = 56312, upload-time = "2025-01-14T10:34:40.604Z" }, - { url = "https://files.pythonhosted.org/packages/8a/04/c97273eb491b5f1c918857cd26f314b74fc9b29224521f5b83f872253725/wrapt-1.17.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:766d8bbefcb9e00c3ac3b000d9acc51f1b399513f44d77dfe0eb026ad7c9a19b", size = 40062, upload-time = "2025-01-14T10:34:45.011Z" }, - { url = "https://files.pythonhosted.org/packages/4e/ca/3b7afa1eae3a9e7fefe499db9b96813f41828b9fdb016ee836c4c379dadb/wrapt-1.17.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e496a8ce2c256da1eb98bd15803a79bee00fc351f5dfb9ea82594a3f058309e0", size = 40155, upload-time = "2025-01-14T10:34:47.25Z" }, - { url = "https://files.pythonhosted.org/packages/89/be/7c1baed43290775cb9030c774bc53c860db140397047cc49aedaf0a15477/wrapt-1.17.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d615e4fe22f4ad3528448c193b218e077656ca9ccb22ce2cb20db730f8d306", size = 113471, upload-time = "2025-01-14T10:34:50.934Z" }, - { url = "https://files.pythonhosted.org/packages/32/98/4ed894cf012b6d6aae5f5cc974006bdeb92f0241775addad3f8cd6ab71c8/wrapt-1.17.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a5aaeff38654462bc4b09023918b7f21790efb807f54c000a39d41d69cf552cb", size = 101208, upload-time = "2025-01-14T10:34:52.297Z" }, - { url = "https://files.pythonhosted.org/packages/ea/fd/0c30f2301ca94e655e5e057012e83284ce8c545df7661a78d8bfca2fac7a/wrapt-1.17.2-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a7d15bbd2bc99e92e39f49a04653062ee6085c0e18b3b7512a4f2fe91f2d681", size = 109339, upload-time = "2025-01-14T10:34:53.489Z" }, - { url = "https://files.pythonhosted.org/packages/75/56/05d000de894c4cfcb84bcd6b1df6214297b8089a7bd324c21a4765e49b14/wrapt-1.17.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e3890b508a23299083e065f435a492b5435eba6e304a7114d2f919d400888cc6", size = 110232, upload-time = "2025-01-14T10:34:55.327Z" }, - { url = "https://files.pythonhosted.org/packages/53/f8/c3f6b2cf9b9277fb0813418e1503e68414cd036b3b099c823379c9575e6d/wrapt-1.17.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8c8b293cd65ad716d13d8dd3624e42e5a19cc2a2f1acc74b30c2c13f15cb61a6", size = 100476, upload-time = "2025-01-14T10:34:58.055Z" }, - { url = "https://files.pythonhosted.org/packages/a7/b1/0bb11e29aa5139d90b770ebbfa167267b1fc548d2302c30c8f7572851738/wrapt-1.17.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c82b8785d98cdd9fed4cac84d765d234ed3251bd6afe34cb7ac523cb93e8b4f", size = 106377, upload-time = "2025-01-14T10:34:59.3Z" }, - { url = "https://files.pythonhosted.org/packages/6a/e1/0122853035b40b3f333bbb25f1939fc1045e21dd518f7f0922b60c156f7c/wrapt-1.17.2-cp313-cp313t-win32.whl", hash = "sha256:13e6afb7fe71fe7485a4550a8844cc9ffbe263c0f1a1eea569bc7091d4898555", size = 37986, upload-time = "2025-01-14T10:35:00.498Z" }, - { url = "https://files.pythonhosted.org/packages/09/5e/1655cf481e079c1f22d0cabdd4e51733679932718dc23bf2db175f329b76/wrapt-1.17.2-cp313-cp313t-win_amd64.whl", hash = "sha256:eaf675418ed6b3b31c7a989fd007fa7c3be66ce14e5c3b27336383604c9da85c", size = 40750, upload-time = "2025-01-14T10:35:03.378Z" }, - { url = "https://files.pythonhosted.org/packages/2d/82/f56956041adef78f849db6b289b282e72b55ab8045a75abad81898c28d19/wrapt-1.17.2-py3-none-any.whl", hash = "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8", size = 23594, upload-time = "2025-01-14T10:35:44.018Z" }, +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/49/19/5e5bcd855d808892fe02d49219f97a50f64cd6d8313d75df3494ee97b1a3/wrapt-2.0.0.tar.gz", hash = "sha256:35a542cc7a962331d0279735c30995b024e852cf40481e384fd63caaa391cbb9", size = 81722, upload-time = "2025-10-19T23:47:54.07Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/28/7f266b5bf50c3ad0c99c524d99faa0f7d6eecb045d950e7d2c9e1f0e1338/wrapt-2.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73c6f734aecb1a030d9a265c13a425897e1ea821b73249bb14471445467ca71c", size = 78078, upload-time = "2025-10-19T23:45:58.855Z" }, + { url = "https://files.pythonhosted.org/packages/06/0c/bbdcad7eb535fae9d6b0fcfa3995c364797cd8e2b423bba5559ab2d88dcf/wrapt-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b4a7f8023b8ce8a36370154733c747f8d65c8697cb977d8b6efeb89291fff23e", size = 61158, upload-time = "2025-10-19T23:46:00.096Z" }, + { url = "https://files.pythonhosted.org/packages/d3/8a/bba3e7a4ebf4d1624103ee59d97b78a1fbb08fb5753ff5d1b69f5ef5e863/wrapt-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a1cb62f686c50e9dab5983c68f6c8e9cbf14a6007935e683662898a7d892fa69", size = 61646, upload-time = "2025-10-19T23:46:01.279Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0c/0f565294897a72493dbafe7b46229b5f09f3776795a894d6b737e98387de/wrapt-2.0.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:43dc0550ae15e33e6bb45a82a5e1b5495be2587fbaa996244b509921810ee49f", size = 121442, upload-time = "2025-10-19T23:46:04.287Z" }, + { url = "https://files.pythonhosted.org/packages/da/80/7f03501a8a078ad79b19b1a888f9192a9494e62ddf8985267902766a4f30/wrapt-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39c5b45b056d630545e40674d1f5e1b51864b3546f25ab6a4a331943de96262e", size = 123018, upload-time = "2025-10-19T23:46:06.052Z" }, + { url = "https://files.pythonhosted.org/packages/37/6b/ad0e1ff98359f13b4b0c2c52848e792841146fe79ac5f56899b9a028fc0d/wrapt-2.0.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:804e88f824b76240a1b670330637ccfd2d18b9efa3bb4f02eb20b2f64880b324", size = 117369, upload-time = "2025-10-19T23:46:02.53Z" }, + { url = "https://files.pythonhosted.org/packages/ac/6c/a90437bba8cb1ce2ed639af979515e09784678c2a7f4ffc79f2cf7de809e/wrapt-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c2c476aa3fc2b9899c3f7b20963fac4f952e7edb74a31fc92f7745389a2e3618", size = 121453, upload-time = "2025-10-19T23:46:07.747Z" }, + { url = "https://files.pythonhosted.org/packages/2c/a9/b3982f9bd15bd45857a23c48b7c36e47d05db4a4dcc5061c31f169238845/wrapt-2.0.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:8d851e526891216f89fcb7a1820dad9bd503ba3468fb9635ee28e93c781aa98e", size = 116250, upload-time = "2025-10-19T23:46:09.385Z" }, + { url = "https://files.pythonhosted.org/packages/73/e2/b7a8b1afac9f791d8f5eac0d9726559f1d7ec4a2b5a6b4e67ac145b007a5/wrapt-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b95733c2360c4a8656ee93c7af78e84c0bd617da04a236d7a456c8faa34e7a2d", size = 120575, upload-time = "2025-10-19T23:46:11.882Z" }, + { url = "https://files.pythonhosted.org/packages/a2/0f/37920eeea96094f450ae35505d39f1135df951a2cdee0d4e01d4f843396a/wrapt-2.0.0-cp312-cp312-win32.whl", hash = "sha256:ea56817176834edf143df1109ae8fdaa087be82fdad3492648de0baa8ae82bf2", size = 58175, upload-time = "2025-10-19T23:46:15.678Z" }, + { url = "https://files.pythonhosted.org/packages/f0/db/b395f3b0c7f2c60d9219afacc54ceb699801ccf2d3d969ba556dc6d3af20/wrapt-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:3c7d3bee7be7a2665286103f4d1f15405c8074e6e1f89dac5774f9357c9a3809", size = 60415, upload-time = "2025-10-19T23:46:12.913Z" }, + { url = "https://files.pythonhosted.org/packages/86/22/33d660214548af47fc59d9eec8c0e0693bcedc5b3a0b52e8cbdd61f3b646/wrapt-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:680f707e1d26acbc60926659799b15659f077df5897a6791c7c598a5d4a211c4", size = 58911, upload-time = "2025-10-19T23:46:13.889Z" }, + { url = "https://files.pythonhosted.org/packages/18/0a/dd88abfe756b1aa79f0777e5ee4ce9e4b5dc4999bd805e9b04b52efc7b18/wrapt-2.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e2ea096db28d5eb64d381af0e93464621ace38a7003a364b6b5ffb7dd713aabe", size = 78083, upload-time = "2025-10-19T23:46:16.937Z" }, + { url = "https://files.pythonhosted.org/packages/7f/b9/8afebc1655a863bb2178b23c2d699b8743f3a7dab466904adc6155f3c858/wrapt-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c92b5a82d28491e3f14f037e1aae99a27a5e6e0bb161e65f52c0445a3fa7c940", size = 61156, upload-time = "2025-10-19T23:46:17.927Z" }, + { url = "https://files.pythonhosted.org/packages/bb/8b/f710a6528ccc52e21943f42c8cf64814cde90f9adbd3bcd58c7c274b4f75/wrapt-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:81d234718aabe632d179fac52c7f69f0f99fbaac4d4bcd670e62462bbcbfcad7", size = 61641, upload-time = "2025-10-19T23:46:19.229Z" }, + { url = "https://files.pythonhosted.org/packages/e4/5f/e4eabd0cc6684c5b208c2abc5c3459449c4d15be1694a9bbcf51e0e135fd/wrapt-2.0.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:db2eea83c43f84e4e41dbbb4c1de371a53166e55f900a6b130c3ef51c6345c1a", size = 121454, upload-time = "2025-10-19T23:46:21.808Z" }, + { url = "https://files.pythonhosted.org/packages/6f/c4/ec31ee17cc7866960d323609ba7402be786d211a6d713a59f776c4270bb3/wrapt-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:65f50e356c425c061e1e17fe687ff30e294fed9bf3441dc1f13ef73859c2a817", size = 123063, upload-time = "2025-10-19T23:46:23.545Z" }, + { url = "https://files.pythonhosted.org/packages/b0/2b/a4b10c3c0022e40aeae9bec009bafb049f440493f0575ebb27ecf61c32f8/wrapt-2.0.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:887f2a667e3cbfb19e204032d42ad7dedaa43972e4861dc7a3d51ae951d9b578", size = 117401, upload-time = "2025-10-19T23:46:20.433Z" }, + { url = "https://files.pythonhosted.org/packages/2a/4a/ade23a76967e1f148e461076a4d0e24a7950a5f18b394c9107fe60224ae2/wrapt-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9054829da4be461e3ad3192e4b6bbf1fc18af64c9975ce613aec191924e004dc", size = 121485, upload-time = "2025-10-19T23:46:24.85Z" }, + { url = "https://files.pythonhosted.org/packages/cb/ba/33b5f3e2edede4e1cfd259f0d9c203cf370f259bb9b215dd58fc6cbb94e9/wrapt-2.0.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:b952ffd77133a5a2798ee3feb18e51b0a299d2f440961e5bb7737dbb02e57289", size = 116276, upload-time = "2025-10-19T23:46:27.006Z" }, + { url = "https://files.pythonhosted.org/packages/eb/bf/b7f95bb4529a35ca11eb95d48f9d1a563b495471f7cf404c644566fb4293/wrapt-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e25fde03c480061b8234d8ee4863eb5f40a9be4fb258ce105b364de38fc6bcf9", size = 120578, upload-time = "2025-10-19T23:46:28.679Z" }, + { url = "https://files.pythonhosted.org/packages/f8/71/984849df6f052592474a44aafd6b847e1cffad39b0debc5390a04aa46331/wrapt-2.0.0-cp313-cp313-win32.whl", hash = "sha256:49e982b7860d325094978292a49e0418833fc7fc42c0dc7cd0b7524d7d06ee74", size = 58178, upload-time = "2025-10-19T23:46:32.372Z" }, + { url = "https://files.pythonhosted.org/packages/f9/3b/4e1fc0f2e1355fbc55ab248311bf4c958dbbd96bd9183b9e96882cc16213/wrapt-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:6e5c86389d9964050ce50babe247d172a5e3911d59a64023b90db2b4fa00ae7c", size = 60423, upload-time = "2025-10-19T23:46:30.041Z" }, + { url = "https://files.pythonhosted.org/packages/20/0a/9384e0551f56fe361f41bb8f209a13bb9ef689c3a18264225b249849b12c/wrapt-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:b96fdaa4611e05c7231937930567d3c16782be9dbcf03eb9f60d83e57dd2f129", size = 58918, upload-time = "2025-10-19T23:46:31.056Z" }, + { url = "https://files.pythonhosted.org/packages/68/70/37b90d3ee5bf0d0dc4859306383da08b685c9a51abff6fd6b0a7c052e117/wrapt-2.0.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f2c7b7fead096dbf1dcc455b7f59facb05de3f5bfb04f60a69f98cdfe6049e5f", size = 81980, upload-time = "2025-10-19T23:46:33.368Z" }, + { url = "https://files.pythonhosted.org/packages/95/23/0ce69cc90806b90b3ee4cfd9ad8d2ee9becc3a1aab7df3c3bfc7d0904cb6/wrapt-2.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:04c7c8393f25b11c0faa5d907dd9eb462e87e4e7ba55e308a046d7ed37f4bbe2", size = 62900, upload-time = "2025-10-19T23:46:34.415Z" }, + { url = "https://files.pythonhosted.org/packages/54/76/03ec08170c02f38f3be3646977920976b968e0b704a0693a98f95d02f4d2/wrapt-2.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a93e0f8b376c0735b2f4daf58018b4823614d2b896cb72b6641c4d3dbdca1d75", size = 63636, upload-time = "2025-10-19T23:46:35.643Z" }, + { url = "https://files.pythonhosted.org/packages/75/c1/04ce0511e504cdcd84cdb6980bc7d4efa38ac358e8103d6dd0cd278bfc6d/wrapt-2.0.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b42d13603da4416c43c430dbc6313c8d7ff745c40942f146ed4f6dd02c7d2547", size = 152650, upload-time = "2025-10-19T23:46:38.717Z" }, + { url = "https://files.pythonhosted.org/packages/17/06/cd2e32b5f744701189c954f9ab5eee449c86695b13f414bb8ea7a83f6d48/wrapt-2.0.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8bbd2472abf8c33480ad2314b1f8fac45d592aba6cc093e8839a7b2045660e6", size = 158811, upload-time = "2025-10-19T23:46:40.875Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a2/a6d920695cca62563c1b969064e5cd2051344a6e330c184b6f80383d87e4/wrapt-2.0.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e64a3a1fd9a308ab9b815a2ad7a65b679730629dbf85f8fc3f7f970d634ee5df", size = 146033, upload-time = "2025-10-19T23:46:37.351Z" }, + { url = "https://files.pythonhosted.org/packages/c6/90/7fd2abe4ec646bc43cb6b0d05086be6fcf15e64f06f51fc4198804396d68/wrapt-2.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d61214525eaf88e0d0edf3d1ad5b5889863c6f88e588c6cdc6aa4ee5d1f10a4a", size = 155673, upload-time = "2025-10-19T23:46:42.582Z" }, + { url = "https://files.pythonhosted.org/packages/5f/8d/6cce7f8c41633e677ac8aa34e84b53a22a645ec2a680deb991785ca2798d/wrapt-2.0.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:04f7a5f92c5f7324a1735043cc467b1295a1c5b4e0c1395472b7c44706e3dc61", size = 144364, upload-time = "2025-10-19T23:46:44.381Z" }, + { url = "https://files.pythonhosted.org/packages/72/42/9570349e03afa9d83daf7f33ffb17e8cdc62d7e84c0d09005d0f51912efa/wrapt-2.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2356f76cb99b3de5b4e5b8210367fbbb81c7309fe39b622f5d199dd88eb7f765", size = 150275, upload-time = "2025-10-19T23:46:45.662Z" }, + { url = "https://files.pythonhosted.org/packages/f2/d8/448728e6fe030e5c4f1022c82cd3af1de1c672fa53d2d5b36b32a55ce7bf/wrapt-2.0.0-cp313-cp313t-win32.whl", hash = "sha256:0a921b657a224e40e4bc161b5d33934583b34f0c9c5bdda4e6ac66f9d2fcb849", size = 59867, upload-time = "2025-10-19T23:46:49.593Z" }, + { url = "https://files.pythonhosted.org/packages/8f/b1/ad812b1fe1cd85f6498dc3a3c9809a1e880d6108283b1735119bec217041/wrapt-2.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:c16f6d4eea98080f6659a8a7fc559d4a0a337ee66960659265cad2c8a40f7c0f", size = 63170, upload-time = "2025-10-19T23:46:46.87Z" }, + { url = "https://files.pythonhosted.org/packages/7f/29/c105b1e76650c82823c491952a7a8eafe09b78944f7a43f22d37ed860229/wrapt-2.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:52878edc13dc151c58a9966621d67163a80654bc6cff4b2e1c79fa62d0352b26", size = 60339, upload-time = "2025-10-19T23:46:47.862Z" }, + { url = "https://files.pythonhosted.org/packages/f8/38/0dd39f83163fd28326afba84e3e416656938df07e60a924ac4d992b30220/wrapt-2.0.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:79a53d86c2aff7b32cc77267e3a308365d1fcb881e74bc9cbe26f63ee90e37f0", size = 78242, upload-time = "2025-10-19T23:46:51.096Z" }, + { url = "https://files.pythonhosted.org/packages/08/ef/fa7a5c1d73f8690c712f9d2e4615700c6809942536dd3f441b9ba650a310/wrapt-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d731a4f22ed6ffa4cb551b4d2b0c24ff940c27a88edaf8e3490a5ee3a05aef71", size = 61207, upload-time = "2025-10-19T23:46:52.558Z" }, + { url = "https://files.pythonhosted.org/packages/23/d9/67cb93da492eb0a1cb17b7ed18220d059e58f00467ce6728b674d3441b3d/wrapt-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3e02ab8c0ac766a5a6e81cd3b6cc39200c69051826243182175555872522bd5a", size = 61748, upload-time = "2025-10-19T23:46:54.468Z" }, + { url = "https://files.pythonhosted.org/packages/e5/be/912bbd70cc614f491b526a1d7fe85695b283deed19287b9f32460178c54d/wrapt-2.0.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:895870602d65d7338edb3b6a717d856632ad9f14f7ff566214e4fb11f0816649", size = 120424, upload-time = "2025-10-19T23:46:57.575Z" }, + { url = "https://files.pythonhosted.org/packages/b2/e1/10df8937e7da2aa9bc3662a4b623e51a323c68f42cad7b13f0e61a700ce2/wrapt-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b9ad4fab76a0086dc364c4f17f39ad289600e73ef5c6e9ab529aff22cac1ac3", size = 122804, upload-time = "2025-10-19T23:46:59.308Z" }, + { url = "https://files.pythonhosted.org/packages/f3/60/576751b1919adab9f63168e3b5fd46c0d1565871b1cc4c2569503ccf4be6/wrapt-2.0.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e7ca0562606d7bad2736b2c18f61295d61f50cd3f4bfc51753df13614dbcce1b", size = 117398, upload-time = "2025-10-19T23:46:55.814Z" }, + { url = "https://files.pythonhosted.org/packages/ec/55/243411f360cc27bae5f8e21c16f1a8d87674c5534f4558e8a97c1e0d1c6f/wrapt-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fe089d9f5a4a3dea0108a8ae34bced114d0c4cca417bada1c5e8f42d98af9050", size = 121230, upload-time = "2025-10-19T23:47:01.347Z" }, + { url = "https://files.pythonhosted.org/packages/d6/23/2f21f692c3b3f0857cb82708ce0c341fbac55a489d4025ae4e3fd5d5de8c/wrapt-2.0.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e761f2d2f8dbc80384af3d547b522a80e67db3e319c7b02e7fd97aded0a8a678", size = 116296, upload-time = "2025-10-19T23:47:02.659Z" }, + { url = "https://files.pythonhosted.org/packages/bd/ed/678957fad212cfb1b65b2359d62f5619f5087d1d1cf296c6a996be45171c/wrapt-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:17ba1bdc52d0c783481850996aa26cea5237720769197335abea2ae6b4c23bc0", size = 119602, upload-time = "2025-10-19T23:47:03.775Z" }, + { url = "https://files.pythonhosted.org/packages/dc/e3/aeb4c3b052d3eed95e61babc20dcb1a512651e098cca4b84a6896585c06a/wrapt-2.0.0-cp314-cp314-win32.whl", hash = "sha256:f73318741b141223a4674ba96992aa2291b1b3f7a5e85cb3c2c964f86171eb45", size = 58649, upload-time = "2025-10-19T23:47:07.382Z" }, + { url = "https://files.pythonhosted.org/packages/aa/2a/a71c51cb211798405b59172c7df5789a5b934b18317223cf22e0c6f852de/wrapt-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:8e08d4edb13cafe7b3260f31d4de033f73d3205774540cf583bffaa4bec97db9", size = 60897, upload-time = "2025-10-19T23:47:04.862Z" }, + { url = "https://files.pythonhosted.org/packages/f8/a5/acc5628035d06f69e9144cca543ca54c33b42a5a23b6f1e8fa131026db89/wrapt-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:af01695c2b7bbd8d67b869d8e3de2b123a7bfbee0185bdd138c2775f75373b83", size = 59306, upload-time = "2025-10-19T23:47:05.883Z" }, + { url = "https://files.pythonhosted.org/packages/a7/e6/1318ca07d7fcee57e4592a78dacd9d5493b8ddd971c553a62904fb2c0cf2/wrapt-2.0.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:057f02c13cce7b26c79624c06a3e1c2353e6dc9708525232232f6768118042ca", size = 81987, upload-time = "2025-10-19T23:47:08.7Z" }, + { url = "https://files.pythonhosted.org/packages/e7/bf/ffac358ddf61c3923d94a8b0e7620f2af1cd1b637a0fe4963a3919aa62b7/wrapt-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:79bdd84570267f3f43d609c892ae2d30b91ee4b8614c2cbfd311a2965f1c9bdb", size = 62902, upload-time = "2025-10-19T23:47:10.248Z" }, + { url = "https://files.pythonhosted.org/packages/b5/af/387c51f9e7b544fe95d852fc94f9f3866e3f7d7d39c2ee65041752f90bc2/wrapt-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:93c8b4f4d54fd401a817abbfc9bf482aa72fd447f8adf19ce81d035b3f5c762c", size = 63635, upload-time = "2025-10-19T23:47:11.746Z" }, + { url = "https://files.pythonhosted.org/packages/7c/99/d38d8c80b9cc352531d4d539a17e3674169a5cc25a7e6e5e3c27bc29893e/wrapt-2.0.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5e09ffd31001dce71c2c2a4fc201bdba9a2f9f62b23700cf24af42266e784741", size = 152659, upload-time = "2025-10-19T23:47:15.344Z" }, + { url = "https://files.pythonhosted.org/packages/5a/2a/e154432f274e22ecf2465583386c5ceffa5e0bab3947c1c5b26cc8e7b275/wrapt-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d87c285ff04e26083c4b03546e7b74df7ba4f1f32f1dcb92e9ac13c2dbb4c379", size = 158818, upload-time = "2025-10-19T23:47:17.569Z" }, + { url = "https://files.pythonhosted.org/packages/c5/7a/3a40c453300e2898e99c27495b8109ff7cd526997d12cfb8ebd1843199a4/wrapt-2.0.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e52e50ea0a72ea48d1291cf8b8aaedcc99072d9dc5baba6b820486dcf4c67da8", size = 146113, upload-time = "2025-10-19T23:47:13.026Z" }, + { url = "https://files.pythonhosted.org/packages/9e/e2/3116a9eade8bea2bf5eedba3fa420e3c7d193d4b047440330d8eaf1098de/wrapt-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1fd4c95536975895f32571073446e614d5e2810b666b64955586dcddfd438fd3", size = 155689, upload-time = "2025-10-19T23:47:19.397Z" }, + { url = "https://files.pythonhosted.org/packages/43/1c/277d3fbe9d177830ab9e54fe9253f38455b75a22d639a4bd9fa092d55ae5/wrapt-2.0.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d6ebfe9283209220ed9de80a3e9442aab8fc2be5a9bbf8491b99e02ca9349a89", size = 144403, upload-time = "2025-10-19T23:47:20.779Z" }, + { url = "https://files.pythonhosted.org/packages/d8/37/ab6ddaf182248aac5ed925725ef4c69a510594764665ecbd95bdd4481f16/wrapt-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5d3ebd784804f146b7ea55359beb138e23cc18e5a5cc2cf26ad438723c00ce3a", size = 150307, upload-time = "2025-10-19T23:47:22.604Z" }, + { url = "https://files.pythonhosted.org/packages/f6/d7/df9e2d8040a3af618ff9496261cf90ca4f886fd226af0f4a69ac0c020c3b/wrapt-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:9b15940ae9debc8b40b15dc57e1ce4433f7fb9d3f8761c7fab1ddd94cb999d99", size = 60557, upload-time = "2025-10-19T23:47:26.73Z" }, + { url = "https://files.pythonhosted.org/packages/b4/c2/502bd4557a3a9199ea73cc5932cf83354bd362682162f0b14164d2e90216/wrapt-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:7a0efbbc06d3e2077476a04f55859819d23206600b4c33f791359a8e6fa3c362", size = 63988, upload-time = "2025-10-19T23:47:23.826Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f2/632b13942f45db7af709f346ff38b8992c8c21b004e61ab320b0dec525fe/wrapt-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:7fec8a9455c029c8cf4ff143a53b6e7c463268d42be6c17efa847ebd2f809965", size = 60584, upload-time = "2025-10-19T23:47:25.396Z" }, + { url = "https://files.pythonhosted.org/packages/00/5c/c34575f96a0a038579683c7f10fca943c15c7946037d1d254ab9db1536ec/wrapt-2.0.0-py3-none-any.whl", hash = "sha256:02482fb0df89857e35427dfb844319417e14fae05878f295ee43fa3bf3b15502", size = 43998, upload-time = "2025-10-19T23:47:52.858Z" }, ] [[package]] name = "xlsxwriter" -version = "3.2.5" +version = "3.2.9" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/47/7704bac42ac6fe1710ae099b70e6a1e68ed173ef14792b647808c357da43/xlsxwriter-3.2.5.tar.gz", hash = "sha256:7e88469d607cdc920151c0ab3ce9cf1a83992d4b7bc730c5ffdd1a12115a7dbe", size = 213306, upload-time = "2025-06-17T08:59:14.619Z" } +sdist = { url = "https://files.pythonhosted.org/packages/46/2c/c06ef49dc36e7954e55b802a8b231770d286a9758b3d936bd1e04ce5ba88/xlsxwriter-3.2.9.tar.gz", hash = "sha256:254b1c37a368c444eac6e2f867405cc9e461b0ed97a3233b2ac1e574efb4140c", size = 215940, upload-time = "2025-09-16T00:16:21.63Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/34/a22e6664211f0c8879521328000bdcae9bf6dbafa94a923e531f6d5b3f73/xlsxwriter-3.2.5-py3-none-any.whl", hash = "sha256:4f4824234e1eaf9d95df9a8fe974585ff91d0f5e3d3f12ace5b71e443c1c6abd", size = 172347, upload-time = "2025-06-17T08:59:13.453Z" }, + { url = "https://files.pythonhosted.org/packages/3a/0c/3662f4a66880196a590b202f0db82d919dd2f89e99a27fadef91c4a33d41/xlsxwriter-3.2.9-py3-none-any.whl", hash = "sha256:9a5db42bc5dff014806c58a20b9eae7322a134abb6fce3c92c181bfb275ec5b3", size = 175315, upload-time = "2025-09-16T00:16:20.108Z" }, ] From 0d0ce5547641d50e8b1c81b2dc039389d2972226 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Mon, 3 Nov 2025 13:23:19 -0500 Subject: [PATCH 305/587] added a validation method to the cli and associated tests --- temoa/_internal/temoa_sequencer.py | 7 ++ temoa/cli.py | 194 ++++++++++++++++++++--------- tests/test_cli.py | 77 +++++++++--- 3 files changed, 197 insertions(+), 81 deletions(-) diff --git a/temoa/_internal/temoa_sequencer.py b/temoa/_internal/temoa_sequencer.py index b6eaf5904..d707c1387 100644 --- a/temoa/_internal/temoa_sequencer.py +++ b/temoa/_internal/temoa_sequencer.py @@ -82,6 +82,7 @@ def build_model(self) -> TemoaModel: Builds and returns an unsolved TemoaModel instance. This is the dedicated method for the 'BUILD_ONLY' mode. """ + self._run_preliminary_checks() logger.info('Starting model build process (build-only mode).') # Ensure certain features that don't apply to a simple build are disabled if self.config.source_trace: @@ -93,6 +94,12 @@ def build_model(self) -> TemoaModel: if self.config.price_check: logger.warning('Price check disabled for build-only mode.') + # Validate database before attempting to build model + if not check_database_version( + self.config, db_major_reqd=DB_MAJOR_VERSION, min_db_minor=MIN_DB_MINOR_VERSION + ): + raise RuntimeError('Database version check failed. See log file for details.') + with sqlite3.connect(self.config.input_database) as con: hybrid_loader = HybridLoader(db_connection=con, config=self.config) data_portal = hybrid_loader.load_data_portal(myopic_index=None) diff --git a/temoa/cli.py b/temoa/cli.py index bae776e1e..5e730831c 100644 --- a/temoa/cli.py +++ b/temoa/cli.py @@ -8,22 +8,17 @@ from rich.logging import RichHandler from definitions import set_OUTPUT_PATH - -# Updated imports to bring in the config object from temoa._internal.temoa_sequencer import TemoaSequencer from temoa.core.config import TemoaConfig from temoa.core.modes import TemoaMode from temoa.version_information import TEMOA_MAJOR, TEMOA_MINOR # ============================================================================= -# Logging Setup +# Logging & Helper Setup # ============================================================================= logger = logging.getLogger(__name__) -# ============================================================================= -# Helper Functions -# ============================================================================= def _create_output_folder() -> Path: """Create a default time-stamped folder for outputs.""" output_path = Path('output_files', datetime.now().strftime('%Y-%m-%d_%H%M%S')) @@ -31,25 +26,78 @@ def _create_output_folder() -> Path: return output_path -def _setup_logging(output_path: Path, debug: bool = False) -> None: - """Set up logging to a file and a rich console.""" - level = logging.DEBUG if debug else logging.INFO - log_format = '%(asctime)s | %(name)s | %(levelname)s | %(message)s' - date_format = '%Y-%m-%d %H:%M:%S' +def _setup_logging(output_path: Path, debug: bool = False, silent: bool = False) -> None: + """Set up logging with different levels for console and file.""" + # The root logger should be set to the most verbose level required by any handler. + # The file handler will always be more verbose than the console in silent mode. + root_level = logging.DEBUG if debug else logging.INFO + + # Determine console level based on flags. `debug` takes precedence. + if debug: + console_level = logging.DEBUG + elif silent: + console_level = logging.WARNING + else: + console_level = logging.INFO + + # Configure the rich handler for the console + rich_handler = RichHandler( + level=console_level, + rich_tracebacks=True, + show_path=False, + log_time_format='[%X]', + ) + + # Configure the file handler (always verbose) log_file = output_path / 'temoa-run.log' file_handler = logging.FileHandler(log_file) - file_handler.setFormatter(logging.Formatter(log_format, date_format)) - rich_handler = RichHandler(rich_tracebacks=True, show_path=False, log_time_format='[%X]') + file_handler.setLevel(root_level) + file_handler.setFormatter( + logging.Formatter( + '%(asctime)s | %(name)s | %(levelname)s | %(message)s', + '%Y-%m-%d %H:%M:%S', + ) + ) + + # Configure the root logger root_logger = logging.getLogger() - root_logger.setLevel(level) + root_logger.setLevel(root_level) root_logger.handlers = [file_handler, rich_handler] + + # Silence other overly verbose libraries logging.getLogger('pyomo').setLevel(logging.WARNING) logging.getLogger('matplotlib').setLevel(logging.WARNING) + + # Log the initialization message (will go to file, and to console if not silent) logger.info(f'Logging initialized. Log file at: {log_file}') +def _setup_sequencer( + config_file: Path, + output_path: Path | None, + silent: bool, + debug: bool, + mode_override: TemoaMode | None = None, +) -> tuple[TemoaSequencer, Path]: + """Handles the common setup logic for creating and configuring the sequencer.""" + final_output_path = output_path if output_path else _create_output_folder() + final_output_path.mkdir(parents=True, exist_ok=True) + + # Pass the silent flag to the logging setup + _setup_logging(final_output_path, debug=debug, silent=silent) + + set_OUTPUT_PATH(final_output_path) + config = TemoaConfig.build_config( + config_file=config_file, output_path=final_output_path, silent=silent + ) + sequencer = TemoaSequencer(config=config, mode_override=mode_override) + return sequencer, final_output_path + + +# ============================================================================= +# Callbacks and Typer App Setup +# ============================================================================= def _version_callback(value: bool) -> None: - """Callback to print version information and exit.""" if value: version = f'{TEMOA_MAJOR}.{TEMOA_MINOR}' rich.print(f'Temoa Version: [bold green]{version}[/bold green]') @@ -57,7 +105,6 @@ def _version_callback(value: bool) -> None: def _cite_callback(value: bool) -> None: - """Callback to print citation information and exit.""" if value: citation_text = """ [bold]How to Cite Temoa:[/bold] @@ -69,9 +116,6 @@ def _cite_callback(value: bool) -> None: raise typer.Exit() -# ============================================================================= -# Typer Application Setup -# ============================================================================= app = typer.Typer( name='temoa', help='The Temoa Project: Tools for Energy Model Optimization and Analysis.', @@ -82,14 +126,14 @@ def _cite_callback(value: bool) -> None: # ============================================================================= -# Main 'run' Subcommand +# CLI Commands # ============================================================================= @app.command() -def run( +def validate( config_file: Annotated[ Path, typer.Argument( - help='Path to the model configuration file.', + help='Path to the configuration file to validate.', exists=True, file_okay=True, dir_okay=False, @@ -99,26 +143,65 @@ def run( ], output_path: Annotated[ Path | None, - typer.Option( - '--output', - '-o', - help='Directory to save outputs. Defaults to a new time-stamped folder.', - file_okay=False, - dir_okay=True, - writable=True, + typer.Option('--output', '-o', help='Directory to save validation log.'), + ] = None, + silent: Annotated[ + bool, typer.Option('--silent', '-s', help='Suppress informational output on success.') + ] = False, + debug: Annotated[ + bool, typer.Option('--debug', '-d', help='Enable debug-level logging.') + ] = False, +) -> None: + """ + Validates a configuration file and database by building the model instance without solving it. + """ + if not silent: + rich.print(f'Validating configuration: [cyan]{config_file}[/cyan]') + try: + ts, final_output_path = _setup_sequencer( + config_file=config_file, + output_path=output_path, + silent=True, # Sequencer is always non-interactive for validation + debug=debug, + mode_override=TemoaMode.BUILD_ONLY, + ) + _ = ts.build_model() + if not silent: + rich.print('\n[bold green]āœ… Validation successful.[/bold green]') + rich.print('The model can be built from the provided configuration.') + rich.print(f'Log file is available in: [cyan]{final_output_path}[/cyan]') + except Exception as e: + logger.exception('An error occurred during validation.') + rich.print(f'\n[bold red]āŒ Validation failed:[/bold red] {e}') + raise typer.Exit(code=1) from e + + +@app.command() +def run( + config_file: Annotated[ + Path, + typer.Argument( + help='Path to the model configuration file.', + exists=True, + file_okay=True, + dir_okay=False, + readable=True, resolve_path=True, ), + ], + output_path: Annotated[ + Path | None, + typer.Option('--output', '-o', help='Directory to save outputs.'), ] = None, build_only: Annotated[ bool, - typer.Option( - '--build-only', - '-b', - help='Build an unsolved TemoaModel instance without solving.', - ), + typer.Option('--build-only', '-b', help='Build the model without solving.'), ] = False, silent: Annotated[ - bool, typer.Option('--silent', '-s', help='Silent run. No interactive prompts.') + bool, + typer.Option( + '--silent', '-s', help='Silent run. No interactive prompts or INFO logs on console.' + ), ] = False, debug: Annotated[ bool, typer.Option('--debug', '-d', help='Enable debug-level logging.') @@ -127,47 +210,34 @@ def run( """ Builds and solves a Temoa model based on the provided configuration. """ - final_output_path = output_path if output_path else _create_output_folder() - final_output_path.mkdir(parents=True, exist_ok=True) - - _setup_logging(final_output_path, debug) - set_OUTPUT_PATH(final_output_path) - try: - # Step 1: Create the configuration object first. - config = TemoaConfig.build_config( - config_file=config_file, output_path=final_output_path, silent=silent + mode_override = TemoaMode.BUILD_ONLY if build_only else None + ts, final_output_path = _setup_sequencer( + config_file=config_file, + output_path=output_path, + silent=silent, + debug=debug, + mode_override=mode_override, ) - - # Step 2: Handle user interaction in the CLI, not the sequencer. if not silent: - rich.print(config) # Print the rich representation of the config - # Use Typer's confirmation prompt, which aborts on "n". + rich.print(ts.config) typer.confirm('\nPlease confirm the settings above to continue', abort=True) - - # Step 3: Instantiate the sequencer and decide which method to call. - mode_override = TemoaMode.BUILD_ONLY if build_only else None - ts = TemoaSequencer(config=config, mode_override=mode_override) - if build_only: logger.info('Build-only mode selected. Calling build_model().') - # The returned model is not used here, but could be in other contexts. _ = ts.build_model() - rich.print('\n[bold green]āœ… Model built successfully.[/bold green]') - rich.print(f'Log file is available in: [cyan]{final_output_path}[/cyan]') + if not silent: + rich.print('\n[bold green]āœ… Model built successfully.[/bold green]') + rich.print(f'Log file is available in: [cyan]{final_output_path}[/cyan]') else: logger.info('Full run mode selected. Calling start().') ts.start() - rich.print('\n[bold green]āœ… Temoa run completed successfully.[/bold green]') - rich.print(f'Outputs are available in: [cyan]{final_output_path}[/cyan]') - + if not silent: + rich.print('\n[bold green]āœ… Temoa run completed successfully.[/bold green]') + rich.print(f'Outputs are available in: [cyan]{final_output_path}[/cyan]') except typer.Abort: - # This catches the "n" from the confirmation prompt. rich.print('\n[yellow]Run aborted by user.[/yellow]') raise typer.Exit() from None - except Exception as e: - # This now correctly catches all errors raised from the sequencer. logger.exception('An unhandled error occurred during the Temoa run.') rich.print(f'\n[bold red]āŒ An error occurred:[/bold red] {e}') raise typer.Exit(code=1) from e diff --git a/tests/test_cli.py b/tests/test_cli.py index 1d5e2a909..37e792339 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -17,15 +17,12 @@ def create_test_config(tmp_path: Path, db_path: Path) -> Path: test database path, and writes a new, runnable config file. """ template_content = UTOPIA_CONFIG_TEMPLATE.read_text() - - placeholder = 'path = "tests/testing_outputs/utopia.sqlite"' - replacement = f'path = "{db_path.as_posix()}"' - + # NOTE: This placeholder is specific to the `config_utopia.toml` file. + placeholder = 'input_database = "tests/testing_outputs/utopia.sqlite"' + replacement = f'input_database = "{db_path.as_posix()}"' config_content = template_content.replace(placeholder, replacement) - test_config_path = tmp_path / 'test_config.toml' test_config_path.write_text(config_content) - return test_config_path @@ -36,29 +33,76 @@ def test_cli_version(): assert 'Temoa Version' in result.stdout -def test_cli_run_command_success(tmp_path): - """Test a successful run by creating a self-contained config.""" +def test_cli_run_command_success_silent(tmp_path): + """Test a successful silent run of the `temoa run` command.""" db_path = Path(__file__).parent / 'testing_outputs' / 'utopia.sqlite' test_config_path = create_test_config(tmp_path, db_path) - args = ['run', str(test_config_path), '--output', str(tmp_path), '--silent'] result = runner.invoke(app, args) assert result.exit_code == 0, f'CLI crashed with error: {result.exception}' - assert 'Temoa run completed successfully' in result.stdout + assert 'Temoa run completed successfully' not in result.stdout assert (tmp_path / 'temoa-run.log').exists() -def test_cli_run_build_only(tmp_path): - """Test the --build-only flag with a self-contained config.""" +def test_cli_run_build_only_silent(tmp_path): + """Test the `temoa run --build-only --silent` flags.""" db_path = Path(__file__).parent / 'testing_outputs' / 'utopia.sqlite' test_config_path = create_test_config(tmp_path, db_path) - args = ['run', str(test_config_path), '--output', str(tmp_path), '--build-only', '--silent'] result = runner.invoke(app, args) assert result.exit_code == 0, f'CLI crashed with error: {result.exception}' - assert 'Model built successfully' in result.stdout + assert 'Model built successfully' not in result.stdout + assert (tmp_path / 'temoa-run.log').exists() + + +# ============================================================================= +# Tests for the `validate` command +# ============================================================================= + + +def test_cli_validate_success_verbose(tmp_path): + """Test a successful verbose run of the `temoa validate` command.""" + db_path = Path(__file__).parent / 'testing_outputs' / 'utopia.sqlite' + test_config_path = create_test_config(tmp_path, db_path) + args = ['validate', str(test_config_path), '--output', str(tmp_path)] + result = runner.invoke(app, args) + + assert result.exit_code == 0, f'CLI crashed with error: {result.exception}' + assert 'Validation successful' in result.stdout + assert (tmp_path / 'temoa-run.log').exists() + + +def test_cli_validate_success_silent(tmp_path): + """Test a successful silent run of the `temoa validate` command.""" + db_path = Path(__file__).parent / 'testing_outputs' / 'utopia.sqlite' + test_config_path = create_test_config(tmp_path, db_path) + args = ['validate', str(test_config_path), '--output', str(tmp_path), '--silent'] + result = runner.invoke(app, args) + + assert result.exit_code == 0, f'CLI crashed with error: {result.exception}' + assert 'Validation successful' not in result.stdout + assert (tmp_path / 'temoa-run.log').exists() + + +def test_cli_validate_failure_on_invalid_db(tmp_path): + """Test a failing run of `temoa validate` with an invalid database.""" + # Create a file that is not a valid Temoa database (an empty file). + # This will cause the version check inside the sequencer to fail. + invalid_db_path = tmp_path / 'invalid.sqlite' + invalid_db_path.touch() + + # Create a valid config file that points to this invalid database. + test_config_path = create_test_config(tmp_path, invalid_db_path) + + args = ['validate', str(test_config_path), '--output', str(tmp_path)] + result = runner.invoke(app, args) + + assert result.exit_code != 0, 'CLI should exit with a non-zero code on failure' + assert 'Validation failed' in result.stdout + # Check that the log was still created, containing the detailed error + assert (tmp_path / 'temoa-run.log').exists() def test_cli_run_missing_config(): @@ -67,12 +111,7 @@ def test_cli_run_missing_config(): result = runner.invoke(app, args) assert result.exit_code != 0 - - # Normalize the stderr string to be immune to rich's word wrapping - # by removing formatting characters and collapsing whitespace. cleaned_stderr = ' '.join(result.stderr.replace('│', '').split()) - - # Now, check for the logical error message in the cleaned string. assert ( "Invalid value for 'CONFIG_FILE': File 'non_existent_file.toml' does not exist." in cleaned_stderr From ca9244171b0b3833416ce28a04da7bfe553e7dd2 Mon Sep 17 00:00:00 2001 From: Anil Radhakrishnan Date: Mon, 3 Nov 2025 13:24:57 -0500 Subject: [PATCH 306/587] turning core type aliases to newTypes for stricter checking (#184) --- docs/source/conf.py | 4 +- pyproject.toml | 2 +- temoa/_internal/data_brick.py | 17 +- temoa/_internal/exchange_tech_cost_ledger.py | 60 ++- temoa/_internal/table_data_puller.py | 98 ++-- temoa/_internal/table_writer.py | 19 +- temoa/components/commodities.py | 244 ++++----- temoa/components/costs.py | 18 +- temoa/components/geography.py | 14 +- temoa/components/limits.py | 12 +- temoa/components/storage.py | 8 +- temoa/components/technology.py | 12 +- temoa/components/time.py | 6 +- temoa/data_processing/database_util.py | 472 ++++++++---------- temoa/data_processing/db_query.py | 89 ++-- temoa/data_processing/graphviz_util.py | 116 ++--- temoa/data_processing/make_graphviz.py | 321 ++++++------ temoa/data_processing/make_output_plots.py | 411 ++++++++------- temoa/model_checking/commodity_graph.py | 31 +- temoa/model_checking/commodity_network.py | 4 +- .../commodity_network_manager.py | 2 +- temoa/model_checking/network_model_data.py | 41 +- temoa/types/__init__.py | 2 + temoa/types/core_types.py | 22 +- temoa/utilities/graph_utils.py | 31 +- temoa/utilities/visualizer.py | 42 +- 26 files changed, 1047 insertions(+), 1051 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 00bd4b367..8c897df11 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,8 +1,8 @@ -# -*- coding: utf-8 -*- # import os import sys import time +from typing import Any # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -96,7 +96,7 @@ # this stylesheet eliminates fixed width and is located in the _static directory -def setup(app): +def setup(app: Any) -> None: app.add_css_file('my_theme.css') diff --git a/pyproject.toml b/pyproject.toml index e2cba8a5b..d649d2551 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -109,7 +109,7 @@ python_version = "3.12" mypy_path = "stubs" # Exclude specific directories from type checking will try to add them back gradually -exclude = "(?x)(^tests/|^temoa/data_processing/|^temoa/extensions/|^temoa/utilities/|^docs/)" +exclude = "(?x)(^tests/|^temoa/extensions/|^temoa/utilities/)" # Strict typing for our own code disallow_untyped_defs = true diff --git a/temoa/_internal/data_brick.py b/temoa/_internal/data_brick.py index 312521a8a..735576179 100644 --- a/temoa/_internal/data_brick.py +++ b/temoa/_internal/data_brick.py @@ -15,6 +15,7 @@ poll_objective, ) from temoa.core.model import TemoaModel +from temoa.types.core_types import Period, Region, Technology, Vintage from temoa.types.model_types import EI, FI, CapData, FlowType @@ -26,13 +27,13 @@ class DataBrick: def __init__( self, name: str, - emission_costs: dict[tuple[str, int, str, int], dict[CostType, float]], + emission_costs: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]], emission_flows: dict[EI, float], capacity_data: CapData, flow_data: dict[FI, dict[FlowType, float]], obj_data: list[tuple[str, float]], - regular_costs: dict[tuple[str, int, str, int], dict[CostType, float]], - exchange_costs: dict[tuple[str, int, str, int], dict[CostType, float]], + regular_costs: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]], + exchange_costs: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]], ): self._name = name self._emission_costs = emission_costs @@ -64,15 +65,19 @@ def obj_data(self) -> list[tuple[str, float]]: return self._obj_data @property - def cost_data(self) -> dict[tuple[str, int, str, int], dict[CostType, float]]: + def cost_data(self) -> dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]]: return self._regular_costs @property - def exchange_cost_data(self) -> dict[tuple[str, int, str, int], dict[CostType, float]]: + def exchange_cost_data( + self, + ) -> dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]]: return self._exchange_costs @property - def emission_cost_data(self) -> dict[tuple[str, int, str, int], dict[CostType, float]]: + def emission_cost_data( + self, + ) -> dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]]: return self._emission_costs diff --git a/temoa/_internal/exchange_tech_cost_ledger.py b/temoa/_internal/exchange_tech_cost_ledger.py index 6e820c075..7976711cf 100644 --- a/temoa/_internal/exchange_tech_cost_ledger.py +++ b/temoa/_internal/exchange_tech_cost_ledger.py @@ -6,14 +6,16 @@ """ +from __future__ import annotations + from collections import defaultdict from enum import Enum, unique -from typing import TYPE_CHECKING, Union, cast +from typing import TYPE_CHECKING, cast from pyomo.common.numeric_types import value from temoa.core.model import TemoaModel -from temoa.types.core_types import Period, Technology, Vintage +from temoa.types.core_types import Period, Region, Technology, Vintage if TYPE_CHECKING: from tests.utilities.namespace_mock import Namespace @@ -32,16 +34,16 @@ class CostType(Enum): class ExchangeTechCostLedger: - def __init__(self, model: Union[TemoaModel, 'Namespace']) -> None: - self.cost_records: dict[CostType, dict[tuple[str, str, str, int, int], float]] = ( - defaultdict(dict) - ) + def __init__(self, model: TemoaModel | Namespace) -> None: + self.cost_records: dict[ + CostType, dict[tuple[Region, Region, Technology, Vintage, Period], float] + ] = defaultdict(dict) # could be a Namespace for testing purposes... See the related test - self.M = model + self.model = model def add_cost_record( self, - link: str, + link: Region, period: Period, tech: Technology, vintage: Vintage, @@ -52,14 +54,14 @@ def add_cost_record( add a cost associated with an exchange tech :return: """ - r1, r2 = link.split('-') + r1, r2 = (cast(Region, r) for r in link.split('-')) if not r1 and r2: raise ValueError(f'problem splitting region-region: {link}') # add to the "seen" records for appropriate cost type self.cost_records[cost_type][r1, r2, tech, vintage, period] = cost def get_use_ratio( - self, exporter: str, importer: str, period: Period, tech: Technology, vintage: Vintage + self, exporter: Region, importer: Region, period: Period, tech: Technology, vintage: Vintage ) -> float: """ use flow to calculate the use ratio for these 2 entities for cost apportioning purposes @@ -72,10 +74,10 @@ def get_use_ratio( """ # Cast to TemoaModel for type checking - at runtime this will be either TemoaModel or Namespace # Both have the same attributes, but mypy doesn't know about Namespace's dynamic attributes - model = cast(TemoaModel, self.M) + model = cast(TemoaModel, self.model) # need to temporarily reconstitute the names - rr1 = '-'.join([exporter, importer]) - rr2 = '-'.join([importer, exporter]) + rr1 = cast(Region, '-'.join([exporter, importer])) + rr2 = cast(Region, '-'.join([importer, exporter])) if any( ( period >= vintage + value(model.LifetimeProcess[rr1, tech, vintage]), @@ -87,35 +89,35 @@ def get_use_ratio( if tech not in model.tech_annual: act_dir1 = value( sum( - model.V_FlowOut[rr1, period, s, d, S_i, tech, vintage, S_o] + model.V_FlowOut[rr1, period, s, d, s_i, tech, vintage, s_o] for s in model.TimeSeason[period] for d in model.time_of_day - for S_i in model.processInputs[rr1, period, tech, vintage] - for S_o in model.processOutputsByInput[rr1, period, tech, vintage, S_i] + for s_i in model.processInputs[rr1, period, tech, vintage] + for s_o in model.processOutputsByInput[rr1, period, tech, vintage, s_i] ) ) act_dir2 = value( sum( - model.V_FlowOut[rr2, period, s, d, S_i, tech, vintage, S_o] + model.V_FlowOut[rr2, period, s, d, s_i, tech, vintage, s_o] for s in model.TimeSeason[period] for d in model.time_of_day - for S_i in model.processInputs[rr2, period, tech, vintage] - for S_o in model.processOutputsByInput[rr2, period, tech, vintage, S_i] + for s_i in model.processInputs[rr2, period, tech, vintage] + for s_o in model.processOutputsByInput[rr2, period, tech, vintage, s_i] ) ) else: act_dir1 = value( sum( - model.V_FlowOutAnnual[rr1, period, S_i, tech, vintage, S_o] - for S_i in model.processInputs[rr1, period, tech, vintage] - for S_o in model.processOutputsByInput[rr1, period, tech, vintage, S_i] + model.V_FlowOutAnnual[rr1, period, s_i, tech, vintage, s_o] + for s_i in model.processInputs[rr1, period, tech, vintage] + for s_o in model.processOutputsByInput[rr1, period, tech, vintage, s_i] ) ) act_dir2 = value( sum( - model.V_FlowOutAnnual[rr2, period, S_i, tech, vintage, S_o] - for S_i in model.processInputs[rr2, period, tech, vintage] - for S_o in model.processOutputsByInput[rr2, period, tech, vintage, S_i] + model.V_FlowOutAnnual[rr2, period, s_i, tech, vintage, s_o] + for s_i in model.processInputs[rr2, period, tech, vintage] + for s_o in model.processOutputsByInput[rr2, period, tech, vintage, s_i] ) ) @@ -123,8 +125,12 @@ def get_use_ratio( return act_dir1 / (act_dir1 + act_dir2) return 0.5 - def get_entries(self) -> dict[tuple[str, int, str, int], dict[CostType, float]]: - region_costs: dict[tuple[str, int, str, int], dict[CostType, float]] = defaultdict(dict) + def get_entries( + self, + ) -> dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]]: + region_costs: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]] = ( + defaultdict(dict) + ) # iterate through each region pairing, pull the cost records and decide if/how to split each one for cost_type in self.cost_records: # make a copy, this will be destructive operation diff --git a/temoa/_internal/table_data_puller.py b/temoa/_internal/table_data_puller.py index ac7e34935..d8de0a621 100644 --- a/temoa/_internal/table_data_puller.py +++ b/temoa/_internal/table_data_puller.py @@ -1,29 +1,4 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 12/5/24 - A companion module to the table writer to hold some data-pulling functions and small utilities and separate them from the writing process for organization and to isolate the DB access in the writer such that these functions can be called on a model instance without any DB interactions. (Intended to support use @@ -34,6 +9,7 @@ import functools import logging from collections import defaultdict +from typing import cast from pyomo.common.numeric_types import value from pyomo.core import Objective @@ -42,6 +18,7 @@ from temoa.components import costs from temoa.components.utils import get_variable_efficiency from temoa.core.model import TemoaModel +from temoa.types.core_types import Commodity, Period, Region, Technology, Vintage from temoa.types.model_types import EI, FI, SLI, CapData, FlowType logger = logging.getLogger(__name__) @@ -54,12 +31,12 @@ def _marks(num: int) -> str: return marks -def ritvo(fi: FI) -> tuple[str, str, str, int, str]: +def ritvo(fi: FI) -> tuple[Region, Commodity, Technology, Vintage, Commodity]: """convert FI to ritvo index""" return fi.r, fi.i, fi.t, fi.v, fi.o -def rpetv(fi: FI, e: str) -> tuple[str, int, str, str, int]: +def rpetv(fi: FI, e: Commodity) -> tuple[Region, Period, Commodity, Technology, Vintage]: """convert FI and emission to rpetv index""" return fi.r, fi.p, e, fi.t, fi.v @@ -205,7 +182,7 @@ def poll_flow_results(model: TemoaModel, epsilon: float = 1e-5) -> dict[FI, dict ) for s in model.TimeSeason[v]: for d in model.time_of_day: - fi = FI(r, v, s, d, i, t, v, 'ConstructionInput') + fi = FI(r, v, s, d, i, t, v, cast(Commodity, 'ConstructionInput')) flow = annual * value(model.SegFrac[v, s, d]) if abs(flow) < epsilon: continue @@ -221,7 +198,7 @@ def poll_flow_results(model: TemoaModel, epsilon: float = 1e-5) -> dict[FI, dict ) for s in model.TimeSeason[p]: for d in model.time_of_day: - fi = FI(r, p, s, d, 'EndOfLifeOutput', t, v, o) + fi = FI(r, p, s, d, cast(Commodity, 'EndOfLifeOutput'), t, v, o) flow = annual * value(model.SegFrac[p, s, d]) if abs(flow) < epsilon: continue @@ -286,10 +263,10 @@ def poll_objective(model: TemoaModel) -> list[tuple[str, float]]: def poll_cost_results( - model: TemoaModel, p_0: int | None, epsilon: float = 1e-5 + model: TemoaModel, p_0: Period | None, epsilon: float = 1e-5 ) -> tuple[ - dict[tuple[str, int, str, int], dict[CostType, float]], - dict[tuple[str, int, str, int], dict[CostType, float]], + dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]], + dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]], ]: """ Poll a solved model for all cost results @@ -298,7 +275,7 @@ def poll_cost_results( :param epsilon: epsilon (default 1e-5) :return: tuple of cost_dict, exchange_cost_dict (for exchange techs) """ - p_0_true: int + p_0_true: Period if p_0 is None: p_0_true = min(model.time_optimize) else: @@ -312,7 +289,9 @@ def poll_cost_results( loan_lifetime_process = model.LoanLifetimeProcess exchange_costs = ExchangeTechCostLedger(model) - entries: dict[tuple[str, int, str, int], dict[CostType, float]] = defaultdict(dict) + entries: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]] = defaultdict( + dict + ) for r, t, v in model.CostInvest.sparse_iterkeys(): # Returns only non-zero values # gather details... cap = value(model.V_NewCapacity[r, t, v]) @@ -367,8 +346,9 @@ def poll_cost_results( cost_type=CostType.INVEST, ) else: - # enter it into the entries table with period of cost = vintage (p=v) - entries[r, v, t, v].update( + # The period `p` for an investment cost is its vintage `v`. + key = (cast(Region, r), cast(Period, v), cast(Technology, t), cast(Vintage, v)) + entries[key].update( {CostType.D_INVEST: model_loan_cost, CostType.INVEST: undiscounted_cost} ) @@ -518,17 +498,17 @@ def loan_costs( def loan_costs_survival_curve( model: TemoaModel, - r: str, - t: str, - v: int, + r: Region, + t: Technology, + v: Vintage, loan_rate: float, # this is referred to as LoanRate in parameters loan_life: float, capacity: float, invest_cost: float, - p_0: int, - p_e: int, + p_0: Period, + p_e: Period, global_discount_rate: float, - vintage: int, + vintage: Vintage, **kwargs: object, ) -> tuple[float, float]: """ @@ -570,8 +550,10 @@ def loan_costs_survival_curve( def poll_emissions( - model: TemoaModel, p_0: int | None = None, epsilon: float = 1e-5 -) -> tuple[dict[tuple[str, int, str, int], dict[CostType, float]], dict[EI, float]]: + model: TemoaModel, p_0: Period | None = None, epsilon: float = 1e-5 +) -> tuple[ + dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]], dict[EI, float] +]: """ Gather all emission flows, cost them and provide a tuple of costs and flows :param M: the model @@ -582,7 +564,7 @@ def poll_emissions( # UPDATE: older versions brought forward had some accounting errors here for flex/curtailed emissions # see the note on emissions in the Cost function in temoa_rules - p_0_true: int + p_0_true: Period if p_0 is None: p_0_true = min(model.time_optimize) else: @@ -626,8 +608,8 @@ def poll_emissions( ) # gather costs - ud_costs: dict[tuple[str, int, str, int], float] = defaultdict(float) - d_costs: dict[tuple[str, int, str, int], float] = defaultdict(float) + ud_costs: dict[tuple[Region, Period, Technology, Vintage], float] = defaultdict(float) + d_costs: dict[tuple[Region, Period, Technology, Vintage], float] = defaultdict(float) for ei in flows: # zero out tiny flows if abs(flows[ei]) < epsilon: @@ -676,26 +658,28 @@ def poll_emissions( flows[ei] = 0.0 continue # screen to see if there is an associated cost - cost_index = (ei.r, ei.v, ei.e) + cost_index = (ei.r, cast(Period, ei.v), ei.e) if cost_index not in model.CostEmission: continue undiscounted_emiss_cost = ( embodied_flows[ei] - * model.CostEmission[ei.r, ei.v, ei.e] - * model.PeriodLength[ei.v] # treat as fixed cost distributed over construction period + * model.CostEmission[ei.r, cast(Period, ei.v), ei.e] + * model.PeriodLength[ + cast(Period, ei.v) + ] # treat as fixed cost distributed over construction period ) discounted_emiss_cost = costs.fixed_or_variable_cost( cap_or_flow=embodied_flows[ei], - cost_factor=value(model.CostEmission[ei.r, ei.v, ei.e]), + cost_factor=value(model.CostEmission[ei.r, cast(Period, ei.v), ei.e]), cost_years=model.PeriodLength[ - ei.v + cast(Period, ei.v) ], # treat as fixed cost distributed over construction period global_discount_rate=global_discount_rate, p_0=p_0_true, - p=ei.v, + p=cast(Period, ei.v), ) - ud_costs[ei.r, ei.v, ei.t, ei.v] += float(value(undiscounted_emiss_cost)) - d_costs[ei.r, ei.v, ei.t, ei.v] += float(value(discounted_emiss_cost)) + ud_costs[ei.r, cast(Period, ei.v), ei.t, ei.v] += float(value(undiscounted_emiss_cost)) + d_costs[ei.r, cast(Period, ei.v), ei.t, ei.v] += float(value(discounted_emiss_cost)) ########################### # End of life Emissions @@ -743,7 +727,9 @@ def poll_emissions( d_costs[ei.r, ei.p, ei.t, ei.v] += float(value(discounted_emiss_cost)) # finally, now that all costs are added up for each rptv, put in cost dict - costs_dict: dict[tuple[str, int, str, int], dict[CostType, float]] = defaultdict(dict) + costs_dict: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]] = ( + defaultdict(dict) + ) for rptv in ud_costs: costs_dict[rptv][CostType.EMISS] = ud_costs[rptv] for rptv in d_costs: diff --git a/temoa/_internal/table_writer.py b/temoa/_internal/table_writer.py index 1ae2e81a3..84a3b0d1f 100644 --- a/temoa/_internal/table_writer.py +++ b/temoa/_internal/table_writer.py @@ -8,7 +8,7 @@ from collections.abc import Iterable from logging import getLogger from pathlib import Path -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, cast from pyomo.core import value from pyomo.opt import SolverResults @@ -33,6 +33,7 @@ from temoa.core.model import TemoaModel from temoa.core.modes import TemoaMode from temoa.extensions.monte_carlo.mc_run import ChangeRecord +from temoa.types.core_types import Period, Region, Technology, Vintage if TYPE_CHECKING: pass @@ -292,9 +293,9 @@ def write_emissions(self, iteration: int | None = None) -> None: if abs(val) < self.epsilon: continue if hasattr(ei, 'p'): # emissions from flows - entry = (scenario, ei.r, sector, ei.p, ei.e, ei.t, ei.v, val) + entry = (scenario, ei.r, sector, cast(int, ei.p), ei.e, ei.t, ei.v, val) else: # embodied emissions - entry = (scenario, ei.r, sector, ei.v, ei.e, ei.t, ei.v, val) + entry = (scenario, ei.r, sector, cast(int, ei.v), ei.e, ei.t, ei.v, val) data.append(entry) qry = f'INSERT INTO OutputEmission VALUES {_marks(8)}' self.con.executemany(qry, data) @@ -530,7 +531,8 @@ def calculate_flows(self, model: TemoaModel) -> dict[FI, dict[FlowType, float]]: def write_costs( self, model: TemoaModel, - emission_entries: dict[tuple[str, int, str, int], dict[CostType, float]] | None = None, + emission_entries: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]] + | None = None, iteration: int | None = None, ) -> None: """ @@ -555,9 +557,10 @@ def write_costs( def _insert_cost_results( self, - regular_entries: dict[tuple[str, int, str, int], dict[CostType, float]], - exchange_entries: dict[tuple[str, int, str, int], dict[CostType, float]], - emission_entries: dict[tuple[str, int, str, int], dict[CostType, float]] | None, + regular_entries: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]], + exchange_entries: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]], + emission_entries: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]] + | None, iteration: int | None, ) -> None: # add the emission costs to the same row data, if provided @@ -569,7 +572,7 @@ def _insert_cost_results( def _write_cost_rows( self, - entries: dict[tuple[str, int, str, int], dict[CostType, float]], + entries: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]], iteration: int | None = None, ) -> None: """Write the entries to the OutputCost table""" diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index 7b6ac0bbe..7c8528161 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -14,7 +14,7 @@ from itertools import product as cross_product from logging import getLogger from operator import itemgetter as iget -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, cast from pyomo.environ import value @@ -178,16 +178,16 @@ def demand_constraint(model: TemoaModel, r: Region, p: Period, dem: Commodity) - # All demand techs are annual now # supply = sum( - # M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, dem] - # for S_t, S_v in M.commodityUStreamProcess[r, p, dem] - # if S_t not in M.tech_annual - # for S_i in M.processInputsByOutput[r, p, S_t, S_v, dem] + # M.V_FlowOut[r, p, s, d, s_i, s_t, s_v, dem] + # for s_t, s_v in M.commodityUStreamProcess[r, p, dem] + # if s_t not in M.tech_annual + # for s_i in M.processInputsByOutput[r, p, s_t, s_v, dem] # ) supply_annual = sum( - model.V_FlowOutAnnual[r, p, S_i, S_t, S_v, dem] - for S_t, S_v in model.commodityUStreamProcess[r, p, dem] - for S_i in model.processInputsByOutput[r, p, S_t, S_v, dem] + model.V_FlowOutAnnual[r, p, s_i, s_t, s_v, dem] + for s_t, s_v in model.commodityUStreamProcess[r, p, dem] + for s_i in model.processInputsByOutput[r, p, s_t, s_v, dem] ) demand_constraint_error_check(supply_annual, r, p, dem) @@ -238,13 +238,13 @@ def demand_activity_constraint( """ activity = sum( - model.V_FlowOut[r, p, s, d, S_i, t, v, dem] - for S_i in model.processInputsByOutput[r, p, t, v, dem] + model.V_FlowOut[r, p, s, d, s_i, t, v, dem] + for s_i in model.processInputsByOutput[r, p, t, v, dem] ) annual_activity = sum( - model.V_FlowOutAnnual[r, p, S_i, t, v, dem] - for S_i in model.processInputsByOutput[r, p, t, v, dem] + model.V_FlowOutAnnual[r, p, s_i, t, v, dem] + for s_i in model.processInputsByOutput[r, p, t, v, dem] ) expr = annual_activity * value(model.DemandSpecificDistribution[r, p, s, d, dem]) == activity @@ -358,33 +358,33 @@ def commodity_balance_constraint( # Only storage techs have a flow in variable # For other techs, it would be redundant as in = out / eff consumed += sum( - model.V_FlowIn[r, p, s, d, c, S_t, S_v, S_o] - for S_t, S_v in model.commodityDStreamProcess[r, p, c] - if S_t in model.tech_storage - for S_o in model.processOutputsByInput[r, p, S_t, S_v, c] + model.V_FlowIn[r, p, s, d, c, s_t, s_v, s_o] + for s_t, s_v in model.commodityDStreamProcess[r, p, c] + if s_t in model.tech_storage + for s_o in model.processOutputsByInput[r, p, s_t, s_v, c] ) # Into flows consumed += sum( - model.V_FlowOut[r, p, s, d, c, S_t, S_v, S_o] - / get_variable_efficiency(model, r, p, s, d, c, S_t, S_v, S_o) - for S_t, S_v in model.commodityDStreamProcess[r, p, c] - if S_t not in model.tech_storage and S_t not in model.tech_annual - for S_o in model.processOutputsByInput[r, p, S_t, S_v, c] + model.V_FlowOut[r, p, s, d, c, s_t, s_v, s_o] + / get_variable_efficiency(model, r, p, s, d, c, s_t, s_v, s_o) + for s_t, s_v in model.commodityDStreamProcess[r, p, c] + if s_t not in model.tech_storage and s_t not in model.tech_annual + for s_o in model.processOutputsByInput[r, p, s_t, s_v, c] ) # Into annual flows consumed += sum( ( - value(model.DemandSpecificDistribution[r, p, s, d, S_o]) - if S_o in model.commodity_demand + value(model.DemandSpecificDistribution[r, p, s, d, s_o]) + if s_o in model.commodity_demand else value(model.SegFrac[p, s, d]) ) - * model.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] - / get_variable_efficiency(model, r, p, s, d, c, S_t, S_v, S_o) - for S_t, S_v in model.commodityDStreamProcess[r, p, c] - if S_t in model.tech_annual - for S_o in model.processOutputsByInput[r, p, S_t, S_v, c] + * model.V_FlowOutAnnual[r, p, c, s_t, s_v, s_o] + / get_variable_efficiency(model, r, p, s, d, c, s_t, s_v, s_o) + for s_t, s_v in model.commodityDStreamProcess[r, p, c] + if s_t in model.tech_annual + for s_o in model.processOutputsByInput[r, p, s_t, s_v, c] ) if (r, p, c) in model.capacityConsumptionTechs: @@ -393,8 +393,8 @@ def commodity_balance_constraint( consumed += ( value(model.SegFrac[p, s, d]) * sum( - value(model.ConstructionInput[r, c, S_t, p]) * model.V_NewCapacity[r, S_t, p] - for S_t in model.capacityConsumptionTechs[r, p, c] + value(model.ConstructionInput[r, c, s_t, p]) * model.V_NewCapacity[r, s_t, p] + for s_t in model.capacityConsumptionTechs[r, p, c] ) / model.PeriodLength[p] ) @@ -402,72 +402,72 @@ def commodity_balance_constraint( if (r, p, c) in model.commodityUStreamProcess: # From flows including output from storage produced += sum( - model.V_FlowOut[r, p, s, d, S_i, S_t, S_v, c] - for S_t, S_v in model.commodityUStreamProcess[r, p, c] - if S_t not in model.tech_annual - for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] + model.V_FlowOut[r, p, s, d, s_i, s_t, s_v, c] + for s_t, s_v in model.commodityUStreamProcess[r, p, c] + if s_t not in model.tech_annual + for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] ) # From annual flows produced += value(model.SegFrac[p, s, d]) * sum( - model.V_FlowOutAnnual[r, p, S_i, S_t, S_v, c] - for S_t, S_v in model.commodityUStreamProcess[r, p, c] - if S_t in model.tech_annual - for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] + model.V_FlowOutAnnual[r, p, s_i, s_t, s_v, c] + for s_t, s_v in model.commodityUStreamProcess[r, p, c] + if s_t in model.tech_annual + for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] ) if c in model.commodity_flex: # Wasted by flex flows consumed += sum( - model.V_Flex[r, p, s, d, S_i, S_t, S_v, c] - for S_t, S_v in model.commodityUStreamProcess[r, p, c] - if S_t not in model.tech_annual and S_t in model.tech_flex - for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] + model.V_Flex[r, p, s, d, s_i, s_t, s_v, c] + for s_t, s_v in model.commodityUStreamProcess[r, p, c] + if s_t not in model.tech_annual and s_t in model.tech_flex + for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] ) # Wasted by annual flex flows consumed += value(model.SegFrac[p, s, d]) * sum( - model.V_FlexAnnual[r, p, S_i, S_t, S_v, c] - for S_t, S_v in model.commodityUStreamProcess[r, p, c] - if S_t in model.tech_annual and S_t in model.tech_flex - for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] + model.V_FlexAnnual[r, p, s_i, s_t, s_v, c] + for s_t, s_v in model.commodityUStreamProcess[r, p, c] + if s_t in model.tech_annual and s_t in model.tech_flex + for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] ) if (r, p, c) in model.retirementProductionProcesses: # Produced by retiring capacity # Assume evenly distributed over a year produced += value(model.SegFrac[p, s, d]) * sum( - value(model.EndOfLifeOutput[r, S_t, S_v, c]) * model.V_AnnualRetirement[r, p, S_t, S_v] - for S_t, S_v in model.retirementProductionProcesses[r, p, c] + value(model.EndOfLifeOutput[r, s_t, s_v, c]) * model.V_AnnualRetirement[r, p, s_t, s_v] + for s_t, s_v in model.retirementProductionProcesses[r, p, c] ) # export of commodity c from region r to other regions if (r, p, c) in model.exportRegions: consumed += sum( - model.V_FlowOut[r + '-' + reg, p, s, d, c, S_t, S_v, S_o] - / get_variable_efficiency(model, r + '-' + reg, p, s, d, c, S_t, S_v, S_o) - for reg, S_t, S_v, S_o in model.exportRegions[r, p, c] - if S_t not in model.tech_annual + model.V_FlowOut[r + '-' + reg, p, s, d, c, s_t, s_v, S_o] + / get_variable_efficiency(model, cast(Region, r + '-' + reg), p, s, d, c, s_t, s_v, S_o) + for reg, s_t, s_v, S_o in model.exportRegions[r, p, c] + if s_t not in model.tech_annual ) consumed += sum( value(model.SegFrac[p, s, d]) - * model.V_FlowOutAnnual[r + '-' + reg, p, c, S_t, S_v, S_o] - / get_variable_efficiency(model, r + '-' + reg, p, s, d, c, S_t, S_v, S_o) - for reg, S_t, S_v, S_o in model.exportRegions[r, p, c] - if S_t in model.tech_annual + * model.V_FlowOutAnnual[r + '-' + reg, p, c, s_t, s_v, S_o] + / get_variable_efficiency(model, cast(Region, r + '-' + reg), p, s, d, c, s_t, s_v, S_o) + for reg, s_t, s_v, S_o in model.exportRegions[r, p, c] + if s_t in model.tech_annual ) # import of commodity c from other regions into region r if (r, p, c) in model.importRegions: produced += sum( - model.V_FlowOut[reg + '-' + r, p, s, d, S_i, S_t, S_v, c] - for reg, S_t, S_v, S_i in model.importRegions[r, p, c] - if S_t not in model.tech_annual + model.V_FlowOut[reg + '-' + r, p, s, d, s_i, s_t, s_v, c] + for reg, s_t, s_v, s_i in model.importRegions[r, p, c] + if s_t not in model.tech_annual ) produced += sum( value(model.SegFrac[p, s, d]) - * model.V_FlowOutAnnual[reg + '-' + r, p, S_i, S_t, S_v, c] - for reg, S_t, S_v, S_i in model.importRegions[r, p, c] - if S_t in model.tech_annual + * model.V_FlowOutAnnual[reg + '-' + r, p, s_i, s_t, s_v, c] + for reg, s_t, s_v, s_i in model.importRegions[r, p, c] + if s_t in model.tech_annual ) commodity_balance_constraint_error_check( @@ -504,30 +504,30 @@ def annual_commodity_balance_constraint( # Only storage techs have a flow in variable # For other techs, it would be redundant as in = out / eff consumed += sum( - model.V_FlowIn[r, p, S_s, S_d, c, S_t, S_v, S_o] - for S_s in model.TimeSeason[p] - for S_d in model.time_of_day - for S_t, S_v in model.commodityDStreamProcess[r, p, c] - if S_t in model.tech_storage - for S_o in model.processOutputsByInput[r, p, S_t, S_v, c] + model.V_FlowIn[r, p, s_s, s_d, c, s_t, s_v, s_o] + for s_s in model.TimeSeason[p] + for s_d in model.time_of_day + for s_t, s_v in model.commodityDStreamProcess[r, p, c] + if s_t in model.tech_storage + for s_o in model.processOutputsByInput[r, p, s_t, s_v, c] ) consumed += sum( - model.V_FlowOut[r, p, S_s, S_d, c, S_t, S_v, S_o] - / get_variable_efficiency(model, r, p, S_s, S_d, c, S_t, S_v, S_o) - for S_s in model.TimeSeason[p] - for S_d in model.time_of_day - for S_t, S_v in model.commodityDStreamProcess[r, p, c] - if S_t not in model.tech_storage and S_t not in model.tech_annual - for S_o in model.processOutputsByInput[r, p, S_t, S_v, c] + model.V_FlowOut[r, p, s_s, s_d, c, s_t, s_v, s_o] + / get_variable_efficiency(model, r, p, s_s, s_d, c, s_t, s_v, s_o) + for s_s in model.TimeSeason[p] + for s_d in model.time_of_day + for s_t, s_v in model.commodityDStreamProcess[r, p, c] + if s_t not in model.tech_storage and s_t not in model.tech_annual + for s_o in model.processOutputsByInput[r, p, s_t, s_v, c] ) consumed += sum( - model.V_FlowOutAnnual[r, p, c, S_t, S_v, S_o] - / value(model.Efficiency[r, c, S_t, S_v, S_o]) - for S_t, S_v in model.commodityDStreamProcess[r, p, c] - if S_t in model.tech_annual - for S_o in model.processOutputsByInput[r, p, S_t, S_v, c] + model.V_FlowOutAnnual[r, p, c, s_t, s_v, s_o] + / value(model.Efficiency[r, c, s_t, s_v, s_o]) + for s_t, s_v in model.commodityDStreamProcess[r, p, c] + if s_t in model.tech_annual + for s_o in model.processOutputsByInput[r, p, s_t, s_v, c] ) if (r, p, c) in model.capacityConsumptionTechs: @@ -535,8 +535,8 @@ def annual_commodity_balance_constraint( # Assume evenly distributed over a year consumed += ( sum( - value(model.ConstructionInput[r, c, S_t, p]) * model.V_NewCapacity[r, S_t, p] - for S_t in model.capacityConsumptionTechs[r, p, c] + value(model.ConstructionInput[r, c, s_t, p]) * model.V_NewCapacity[r, s_t, p] + for s_t in model.capacityConsumptionTechs[r, p, c] ) / model.PeriodLength[p] ) @@ -544,75 +544,77 @@ def annual_commodity_balance_constraint( if (r, p, c) in model.commodityUStreamProcess: # Includes output from storage produced += sum( - model.V_FlowOut[r, p, S_s, S_d, S_i, S_t, S_v, c] - for S_s in model.TimeSeason[p] - for S_d in model.time_of_day - for S_t, S_v in model.commodityUStreamProcess[r, p, c] - if S_t not in model.tech_annual - for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] + model.V_FlowOut[r, p, s_s, s_d, s_i, s_t, s_v, c] + for s_s in model.TimeSeason[p] + for s_d in model.time_of_day + for s_t, s_v in model.commodityUStreamProcess[r, p, c] + if s_t not in model.tech_annual + for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] ) produced += sum( - model.V_FlowOutAnnual[r, p, S_i, S_t, S_v, c] - for S_t, S_v in model.commodityUStreamProcess[r, p, c] - if S_t in model.tech_annual - for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] + model.V_FlowOutAnnual[r, p, s_i, s_t, s_v, c] + for s_t, s_v in model.commodityUStreamProcess[r, p, c] + if s_t in model.tech_annual + for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] ) if c in model.commodity_flex: consumed += sum( - model.V_Flex[r, p, S_s, S_d, S_i, S_t, S_v, c] - for S_s in model.TimeSeason[p] - for S_d in model.time_of_day - for S_t, S_v in model.commodityUStreamProcess[r, p, c] - if S_t not in model.tech_annual and S_t in model.tech_flex - for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] + model.V_Flex[r, p, s_s, s_d, s_i, s_t, s_v, c] + for s_s in model.TimeSeason[p] + for s_d in model.time_of_day + for s_t, s_v in model.commodityUStreamProcess[r, p, c] + if s_t not in model.tech_annual and s_t in model.tech_flex + for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] ) consumed += sum( - model.V_FlexAnnual[r, p, S_i, S_t, S_v, c] - for S_t, S_v in model.commodityUStreamProcess[r, p, c] - if S_t in model.tech_flex and S_t in model.tech_annual - for S_i in model.processInputsByOutput[r, p, S_t, S_v, c] + model.V_FlexAnnual[r, p, s_i, s_t, s_v, c] + for s_t, s_v in model.commodityUStreamProcess[r, p, c] + if s_t in model.tech_flex and s_t in model.tech_annual + for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] ) if (r, p, c) in model.retirementProductionProcesses: # Produced by retiring capacity # Assume evenly distributed over a year produced += sum( - value(model.EndOfLifeOutput[r, S_t, S_v, c]) * model.V_AnnualRetirement[r, p, S_t, S_v] - for S_t, S_v in model.retirementProductionProcesses[r, p, c] + value(model.EndOfLifeOutput[r, s_t, s_v, c]) * model.V_AnnualRetirement[r, p, s_t, s_v] + for s_t, s_v in model.retirementProductionProcesses[r, p, c] ) # export of commodity c from region r to other regions if (r, p, c) in model.exportRegions: consumed += sum( - model.V_FlowOut[r + '-' + S_r, p, S_s, S_d, c, S_t, S_v, S_o] - / get_variable_efficiency(model, r + '-' + S_r, p, S_s, S_d, c, S_t, S_v, S_o) - for S_s in model.TimeSeason[p] - for S_d in model.time_of_day - for S_r, S_t, S_v, S_o in model.exportRegions[r, p, c] - if S_t not in model.tech_annual + model.V_FlowOut[cast(Region, r + '-' + s_r), p, s_s, s_d, c, s_t, s_v, s_o] + / get_variable_efficiency( + model, cast(Region, r + '-' + s_r), p, s_s, s_d, c, s_t, s_v, s_o + ) + for s_s in model.TimeSeason[p] + for s_d in model.time_of_day + for s_r, s_t, s_v, s_o in model.exportRegions[r, p, c] + if s_t not in model.tech_annual ) consumed += sum( - model.V_FlowOutAnnual[r + '-' + S_r, p, c, S_t, S_v, S_o] - / model.Efficiency[r + '-' + S_r, c, S_t, S_v, S_o] - for S_r, S_t, S_v, S_o in model.exportRegions[r, p, c] - if S_t in model.tech_annual + model.V_FlowOutAnnual[cast(Region, r + '-' + s_r), p, c, s_t, s_v, s_o] + / model.Efficiency[cast(Region, r + '-' + s_r), c, s_t, s_v, s_o] + for s_r, s_t, s_v, s_o in model.exportRegions[r, p, c] + if s_t in model.tech_annual ) # import of commodity c from other regions into region r if (r, p, c) in model.importRegions: produced += sum( - model.V_FlowOut[S_r + '-' + r, p, S_s, S_d, S_i, S_t, S_v, c] - for S_s in model.TimeSeason[p] + model.V_FlowOut[cast(Region, s_r + '-' + r), p, s_s, S_d, s_i, s_t, s_v, c] + for s_s in model.TimeSeason[p] for S_d in model.time_of_day - for S_r, S_t, S_v, S_i in model.importRegions[r, p, c] - if S_t not in model.tech_annual + for s_r, s_t, s_v, s_i in model.importRegions[r, p, c] + if s_t not in model.tech_annual ) produced += sum( - model.V_FlowOutAnnual[S_r + '-' + r, p, S_i, S_t, S_v, c] - for S_r, S_t, S_v, S_i in model.importRegions[r, p, c] - if S_t in model.tech_annual + model.V_FlowOutAnnual[cast(Region, s_r + '-' + r), p, s_i, s_t, s_v, c] + for s_r, s_t, s_v, s_i in model.importRegions[r, p, c] + if s_t in model.tech_annual ) annual_commodity_balance_constraint_error_check( diff --git a/temoa/components/costs.py b/temoa/components/costs.py index 7ab7ccbb7..4ea4aeacc 100644 --- a/temoa/components/costs.py +++ b/temoa/components/costs.py @@ -40,7 +40,7 @@ def get_default_loan_rate(model: TemoaModel, *_: Any) -> float: return value(model.DefaultLoanRate) -def annuity_to_pv(rate: float, periods: int) -> float | Expression: +def annuity_to_pv(rate: float, periods: float) -> float | Expression: r""" Multiplication factor to convert an annuity to net present value @@ -59,7 +59,7 @@ def annuity_to_pv(rate: float, periods: int) -> float | Expression: return ((1 + rate) ** periods - 1) / (rate * (1 + rate) ** periods) -def pv_to_annuity(rate: float, periods: int) -> float | Expression: +def pv_to_annuity(rate: float, periods: float) -> float | Expression: r""" Multiplication factor to convert net present value to an annuity @@ -73,7 +73,7 @@ def pv_to_annuity(rate: float, periods: int) -> float | Expression: return (rate * (1 + rate) ** periods) / ((1 + rate) ** periods - 1) -def fv_to_pv(rate: float, periods: int) -> float | Expression: +def fv_to_pv(rate: float, periods: float) -> float | Expression: r""" Multiplication factor to convert a future value to net present value @@ -135,7 +135,7 @@ def loan_cost( invest_cost: float, loan_annualize: float, lifetime_loan_process: float | int, - lifetime_process: int, + lifetime_process: float, p_0: int, p_e: int, global_discount_rate: float, @@ -194,15 +194,15 @@ def loan_cost( def loan_cost_survival_curve( model: TemoaModel, - r: str, - t: str, - v: int, + r: Region, + t: Technology, + v: Vintage, capacity: float | Var | ComponentData, invest_cost: float, loan_annualize: float, lifetime_loan_process: float | int, - p_0: int, - p_e: int, + p_0: Period, + p_e: Period, global_discount_rate: float, ) -> float | Expression: """ diff --git a/temoa/components/geography.py b/temoa/components/geography.py index 63280032e..065c7c662 100644 --- a/temoa/components/geography.py +++ b/temoa/components/geography.py @@ -14,7 +14,7 @@ from collections.abc import Iterable from logging import getLogger -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, cast from deprecated import deprecated from pyomo.environ import value @@ -37,7 +37,7 @@ def gather_group_regions(model: TemoaModel, region: Region) -> Iterable[Region]: if region == 'global': regions = list(model.regions) elif '+' in region: - regions = region.split('+') + regions = [cast(Region, r) for r in region.split('+')] else: regions = [region] return regions @@ -59,7 +59,7 @@ def create_regional_indices(model: TemoaModel) -> list[Region]: if r_i == r_j: regional_indices.add(r_i) else: - regional_indices.add(r_i + '-' + r_j) + regional_indices.add(cast(Region, r_i + '-' + r_j)) # dev note: Sorting these passed them to pyomo in an ordered container and prevents warnings return sorted(regional_indices) @@ -72,8 +72,8 @@ def regional_global_initialized_indices(model: TemoaModel) -> set[Region]: for n in range(1, len(model.regions) + 1): regional_perms = permutations(model.regions, n) for i in regional_perms: - indices.add('+'.join(i)) - indices.add('global') + indices.add(cast(Region, '+'.join(i))) + indices.add(cast(Region, 'global')) indices = indices.union(model.regionalIndices) return indices @@ -137,7 +137,9 @@ def create_geography_sets(model: TemoaModel) -> None: logger.error(msg) raise ValueError(msg) - region_from, region_to = r.split('-', 1) + region_from_str, region_to_str = r.split('-', 1) + region_from = cast(Region, region_from_str) + region_to = cast(Region, region_to_str) lifetime: float = value(model.LifetimeProcess[r, t, v]) for p in model.time_optimize: diff --git a/temoa/components/limits.py b/temoa/components/limits.py index 009a7b3ec..97b1a35d4 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -14,7 +14,7 @@ import sys from logging import getLogger -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, cast from pyomo.environ import Constraint, quicksum, value @@ -292,7 +292,7 @@ def limit_resource_constraint(model: TemoaModel, r: Region, t: Technology, op: s def limit_activity_share_constraint( - model: TemoaModel, r: Region, p: Period, g1: str, g2: str, op: str + model: TemoaModel, r: Region, p: Period, g1: Technology, g2: Technology, op: str ) -> ExprLike: r""" Limits the activity of a given technology or group as a fraction of another @@ -372,7 +372,7 @@ def limit_activity_share_constraint( def limit_capacity_share_constraint( - model: TemoaModel, r: Region, p: Period, g1: str, g2: str, op: str + model: TemoaModel, r: Region, p: Period, g1: Technology, g2: Technology, op: str ) -> ExprLike: r""" The LimitCapacityShare constraint limits the available capacity of a given @@ -405,7 +405,7 @@ def limit_capacity_share_constraint( def limit_new_capacity_share_constraint( - model: TemoaModel, r: Region, p: Period, g1: str, g2: str, op: str + model: TemoaModel, r: Region, p: Period, g1: Technology, g2: Technology, op: str ) -> ExprLike: r""" The LimitNewCapacityShare constraint limits the share of new capacity @@ -419,7 +419,7 @@ def limit_new_capacity_share_constraint( model.V_NewCapacity[_r, _t, p] for _t in sub_group for _r in regions - if (_r, _t, p) in model.processPeriods + if (_r, _t, cast(Vintage, p)) in model.processPeriods ) super_group = technology.gather_group_techs(model, g2) @@ -427,7 +427,7 @@ def limit_new_capacity_share_constraint( model.V_NewCapacity[_r, _t, p] for _t in super_group for _r in regions - if (_r, _t, p) in model.processPeriods + if (_r, _t, cast(Vintage, p)) in model.processPeriods ) share_lim = value(model.LimitNewCapacityShare[r, p, g1, g2, op]) diff --git a/temoa/components/storage.py b/temoa/components/storage.py index 88f9a3471..28ec5e27d 100644 --- a/temoa/components/storage.py +++ b/temoa/components/storage.py @@ -124,7 +124,7 @@ def storage_energy_constraint( def seasonal_storage_energy_constraint( - model: TemoaModel, r: Region, p: Period, s_seq: str, t: Technology, v: Vintage + model: TemoaModel, r: Region, p: Period, s_seq: Season, t: Technology, v: Vintage ) -> ExprLike: r""" This constraint enforces the continuity of state of charge between seasons for seasonal @@ -184,7 +184,7 @@ def seasonal_storage_energy_constraint( for S_i in model.processInputsByOutput[r, p, t, v, S_o] ) - s_seq_next: str = model.time_next_sequential[p, s_seq] + s_seq_next: Season = model.time_next_sequential[p, s_seq] s_next: Season = model.sequential_to_season[p, s_seq_next] # Flows and StorageLevel are normalised to the number of days in the non-sequential season, so must @@ -272,7 +272,7 @@ def storage_energy_upper_bound_constraint( def seasonal_storage_energy_upper_bound_constraint( - model: TemoaModel, r: Region, p: Period, s_seq: str, d: TimeOfDay, t: Technology, v: Vintage + model: TemoaModel, r: Region, p: Period, s_seq: Season, d: TimeOfDay, t: Technology, v: Vintage ) -> ExprLike: r""" Builds off of StorageEnergyUpperBound_Constraint. Enforces the max charge capacity @@ -516,7 +516,7 @@ def limit_storage_fraction_constraint( ) if model.isSeasonalStorage[t]: - s_seq: str = s # sequential season + s_seq: Season = s # sequential season s = model.sequential_to_season[p, s_seq] # non-sequential season # adjust the storage level to the individual-day level diff --git a/temoa/components/technology.py b/temoa/components/technology.py index 26a1778f9..121dc4714 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -14,13 +14,13 @@ from collections.abc import Iterable from logging import getLogger -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, cast from pyomo.environ import value if TYPE_CHECKING: from temoa.core.model import TemoaModel - from temoa.types import Period, Region, Technology, Vintage +from temoa.types import Period, Region, Technology, Vintage logger = getLogger(__name__) @@ -29,11 +29,11 @@ # ============================================================================ -def gather_group_techs(model: TemoaModel, t_or_g: str) -> Iterable[str]: +def gather_group_techs(model: TemoaModel, t_or_g: Technology) -> Iterable[Technology]: if t_or_g in model.tech_group_names: return model.tech_group_members[t_or_g] elif '+' in t_or_g: - return t_or_g.split('+') + return [cast(Technology, tech) for tech in t_or_g.split('+')] else: return (t_or_g,) @@ -253,7 +253,7 @@ def create_survival_curve(model: TemoaModel) -> None: if periods_rtv != list(range(p_first, p_last + 1, 1)): rtv_interpolated.add((r, t, v)) - between_periods = [] + between_periods: list[Period] = [] for i, p in enumerate(periods_rtv): if i == 0: continue # Cant look back from first period. Could be zero but hey why not @@ -271,7 +271,7 @@ def create_survival_curve(model: TemoaModel) -> None: raise ValueError(msg) if p - p_prev > 1: - _between_periods = list(range(p_prev + 1, p, 1)) + _between_periods = [cast(Period, _p) for _p in range(p_prev + 1, p, 1)] for _p in _between_periods: x = (_p - p_prev) / (p - p_prev) lsc_x = lsc_prev + x * (lsc - lsc_prev) diff --git a/temoa/components/time.py b/temoa/components/time.py index 98fff362c..9558dd70c 100644 --- a/temoa/components/time.py +++ b/temoa/components/time.py @@ -234,9 +234,9 @@ def loop_period_next_timeslice( def loop_season_next_timeslice( model: TemoaModel, p: Period, s: Season, d: TimeOfDay -) -> tuple[str, str]: +) -> tuple[Season, TimeOfDay]: # We loop each season so never carrying state between seasons - s_next: str = s + s_next: Season = s # Final time slice of any season # Loop state back to initial state of same season @@ -296,7 +296,7 @@ def create_time_sequence(model: TemoaModel) -> None: # Superimposed sequential seasons for p in model.time_optimize: - seasons: list[tuple[str, str]] = [ + seasons: list[tuple[Season, Season]] = [ (s_seq, s) for _p, s_seq, s in model.ordered_season_sequential if _p == p ] for i, (s_seq, s) in enumerate(seasons): diff --git a/temoa/data_processing/database_util.py b/temoa/data_processing/database_util.py index 0fe8a6496..6a1fb1280 100644 --- a/temoa/data_processing/database_util.py +++ b/temoa/data_processing/database_util.py @@ -10,6 +10,7 @@ import os import re import sqlite3 +from os import PathLike import deprecated import pandas as pd @@ -24,14 +25,19 @@ class DatabaseUtil: manager to ensure database connections are closed properly. Args: - database_path (str or Path): The file path to the SQLite database. - scenario (Optional[str]): The specific scenario to query within the database. + database_path: The file path to the SQLite database. + scenario: The specific scenario to query within the database. Raises: ValueError: If the database path does not exist or if connecting fails. """ - def __init__(self, database_path, scenario=None): + database: str + scenario: str | None + con: sqlite3.Connection + cur: sqlite3.Cursor + + def __init__(self, database_path: str | PathLike[str], scenario: str | None = None) -> None: self.database = os.path.abspath(database_path) self.scenario = scenario if not os.path.exists(self.database): @@ -41,361 +47,284 @@ def __init__(self, database_path, scenario=None): try: self.con = sqlite3.connect(self.database) self.cur = self.con.cursor() - self.con.text_factory = ( - str # this ensures data is explored with the correct UTF-8 encoding - ) + self.con.text_factory = str except sqlite3.Error as e: raise ValueError(f'Unable to connect to database: {e}') from e elif self.database.endswith('.dat'): raise ValueError('Reading .dat files is no longer supported') - def close(self): + def close(self) -> None: + """Closes the database cursor and connection.""" if self.cur: self.cur.close() if self.con: self.con.close() @staticmethod - def is_database_file(file): - if file.endswith('.db') or file.endswith('.sqlite') or file.endswith('.sqlite3'): - return True - else: - return False - - @deprecated.deprecated('reading from .dat files no longer supported') - def read_from_dat_file(self, inp_comm, inp_tech): - if self.cur is not None: + def is_database_file(file: str | PathLike[str]) -> bool: + """Checks if a file has a common SQLite database extension.""" + return str(file).endswith(('.db', '.sqlite', '.sqlite3')) + + @deprecated.deprecated(version='0.9.0', reason='Reading from .dat files is no longer supported') + def read_from_dat_file(self, inp_comm: str | None, inp_tech: str | None) -> pd.DataFrame: + """ + This method is deprecated and will raise a ValueError if called on a + database connection. + """ + # This check ensures the method is unreachable with a valid DB connection. + if hasattr(self, 'cur') and self.cur is not None: raise ValueError('Invalid Operation For Database file') - if inp_comm is None and inp_tech is None: - inp_comm = r'\w+' - inp_tech = r'\w+' - else: - if inp_comm is None: - inp_comm = r'\W+' - if inp_tech is None: - inp_tech = r'\W+' - test2 = [] + # The following code is unreachable in the current design but is kept + # to document the deprecated functionality. + inp_comm_re = inp_comm if inp_comm is not None else r'\w+' + inp_tech_re = inp_tech if inp_tech is not None else r'\w+' + + rows: list[tuple[str, ...]] = [] eff_flag = False - with open(self.database) as f: + with open(self.database, encoding='utf-8') as f: for line in f: - if eff_flag is False and re.search( - r'^\s*param\s+efficiency\s*[:][=]', line, flags=re.I - ): - # Search for the line param Efficiency := (The script recognizes the commodities specified in this section) + if not eff_flag and re.search(r'^\s*param\s+efficiency\s*[:][=]', line, re.I): eff_flag = True elif eff_flag: line = re.sub(r'[#].*$', ' ', line) if re.search(r'^\s*;\s*$', line): - break # Finish searching this section when encounter a ';' + break if re.search(r'^\s+$', line): continue - line = re.sub(r'^\s+|\s+$', '', line) - row = re.split(r'\s+', line) + line = line.strip() + row_parts = tuple(re.split(r'\s+', line)) if ( - not re.search(inp_comm, row[0]) - and not re.search(inp_comm, row[3]) - and not re.search(inp_tech, row[1]) + len(row_parts) >= 4 + and not re.search(inp_comm_re, row_parts[0]) + and not re.search(inp_comm_re, row_parts[3]) + and not re.search(inp_tech_re, row_parts[1]) ): continue + rows.append(row_parts) - test2.append(tuple(row)) - - result = pd.DataFrame( - test2, columns=['input_comm', 'tech', 'period', 'output_comm', 'flow'] - ) + result = pd.DataFrame(rows, columns=['input_comm', 'tech', 'period', 'output_comm', 'flow']) return result[['input_comm', 'tech', 'output_comm']] - def get_time_peridos_for_flags(self, flags=None): - if self.cur is None: - raise ValueError('Invalid Operation For dat file') - query = '' + def get_time_peridos_for_flags(self, flags: list[str] | None = None) -> set[int]: + """Retrieves a set of time periods, optionally filtered by flags.""" if (flags is None) or (not flags): query = 'SELECT period FROM TimePeriod' else: - flag = flags[0] - query = "SELECT period FROM TimePeriod WHERE flag is '" + flag + "'" - for i in range(1, len(flags)): - query += " OR flag is '" + flags[i] + "'" + in_clause = ', '.join(f"'{flag}'" for flag in flags) + query = f'SELECT period FROM TimePeriod WHERE flag IN ({in_clause})' self.cur.execute(query) - result = set() - for row in self.cur: - result.add(int(row[0])) + return {int(row[0]) for row in self.cur} - return result - - def get_technologies_for_flags(self, flags=None): - if self.cur is None: - raise ValueError('Invalid Operation For dat file') - query = '' + def get_technologies_for_flags(self, flags: list[str] | None = None) -> set[str]: + """Retrieves a set of technologies, optionally filtered by flags.""" if (flags is None) or (not flags): query = 'SELECT tech FROM Technology' else: - flag = flags[0] - query = "SELECT tech FROM Technology WHERE flag='" + flag + "'" - for i in range(1, len(flags)): - query += " OR flag='" + flags[i] + "'" - - result = set() - for row in self.cur.execute(query): - result.add(row[0]) - - return result - - # TODO: Merge this with next function (getExistingTechnologiesForCommodity) - def get_commodities_and_tech(self, inp_comm, inp_tech, region): - if self.cur is None: - raise ValueError('Invalid Operation For dat file') - if inp_comm is None and inp_tech is None: - inp_comm = 'NOT NULL' - inp_tech = 'NOT NULL' - else: - if inp_comm is None: - inp_comm = 'NULL' - else: - inp_comm = "'" + inp_comm + "'" - if inp_tech is None: - inp_tech = 'NULL' - else: - inp_tech = "'" + inp_tech + "'" - - if region is None: - self.cur.execute( - 'SELECT input_comm, tech, output_comm FROM Efficiency WHERE input_comm is ' - + inp_comm - + ' or output_comm is ' - + inp_comm - + ' or tech is ' - + inp_tech - ) - else: - self.cur.execute( - "SELECT input_comm, tech, output_comm FROM Efficiency WHERE region LIKE '%" - + region - + "%' and (input_comm is " - + inp_comm - + ' or output_comm is ' - + inp_comm - + ' or tech is ' - + inp_tech - + ')' - ) + in_clause = ', '.join(f"'{flag}'" for flag in flags) + query = f'SELECT tech FROM Technology WHERE flag IN ({in_clause})' + + return {row[0] for row in self.cur.execute(query)} + + def get_commodities_and_tech( + self, inp_comm: str | None, inp_tech: str | None, region: str | None + ) -> pd.DataFrame: + """Retrieves technologies and commodities based on filters.""" + inp_comm_sql = f"'{inp_comm}'" if inp_comm else 'NULL' + inp_tech_sql = f"'{inp_tech}'" if inp_tech else 'NULL' + + if not inp_comm and not inp_tech: + inp_comm_sql = 'NOT NULL' + inp_tech_sql = 'NOT NULL' + + where_clause = f'(input_comm IS {inp_comm_sql} OR output_comm IS {inp_comm_sql} OR tech IS {inp_tech_sql})' + if region: + where_clause = f"region LIKE '%{region}%' AND {where_clause}" + + query = f'SELECT input_comm, tech, output_comm FROM Efficiency WHERE {where_clause}' + self.cur.execute(query) return pd.DataFrame(self.cur.fetchall(), columns=['input_comm', 'tech', 'output_comm']) - def get_existing_technologies_for_commodity(self, comm, region, comm_type='input'): - if self.cur is None: - raise ValueError('Invalid Operation For dat file') - query = '' + def get_existing_technologies_for_commodity( + self, comm: str, region: str | None, comm_type: str = 'input' + ) -> pd.DataFrame: + """Retrieves technologies associated with a specific commodity.""" if comm_type == 'input': - query = "SELECT DISTINCT tech FROM Efficiency WHERE input_comm is '" + comm + "'" + query = f"SELECT DISTINCT tech FROM Efficiency WHERE input_comm IS '{comm}'" else: - query = "SELECT DISTINCT tech FROM Efficiency WHERE output_comm is '" + comm + "'" + query = f"SELECT DISTINCT tech FROM Efficiency WHERE output_comm IS '{comm}'" if region: - query += " AND region LIKE '%" + region + "%'" + query += f" AND region LIKE '%{region}%'" self.cur.execute(query) - result = pd.DataFrame(self.cur.fetchall(), columns=['tech']) - return result + return pd.DataFrame(self.cur.fetchall(), columns=['tech']) - def get_commodities_for_flags(self, flags=None): - if self.cur is None: - raise ValueError('Invalid Operation For dat file') - query = '' + def get_commodities_for_flags(self, flags: list[str] | None = None) -> set[str]: + """Retrieves a set of commodities, optionally filtered by flags.""" if (flags is None) or (not flags): query = 'SELECT name FROM Commodity' else: - flag = flags[0] - query = "SELECT name FROM Commodity WHERE flag is '" + flag + "'" - for i in range(1, len(flags)): - query += " OR flag is '" + flags[i] + "'" - - result = set() - for row in self.cur.execute(query): - result.add(row[0]) - - return result - - # comm_type can be 'input' or 'output' - def get_commodities_by_technology(self, region, comm_type='input'): - if self.cur is None: - raise ValueError('Invalid Operation For dat file') - query = '' + in_clause = ', '.join(f"'{flag}'" for flag in flags) + query = f'SELECT name FROM Commodity WHERE flag IN ({in_clause})' + + return {row[0] for row in self.cur.execute(query)} + + def get_commodities_by_technology( + self, region: str | None, comm_type: str = 'input' + ) -> set[tuple[str, str]]: + """Retrieves commodity-technology pairs.""" if comm_type == 'input': query = 'SELECT DISTINCT input_comm, tech FROM Efficiency' elif comm_type == 'output': query = 'SELECT DISTINCT tech, output_comm FROM Efficiency' else: - raise ValueError('Invalid commodity comm_type: can only be input or output') + raise ValueError("Invalid comm_type: can only be 'input' or 'output'") if region: - query += " WHERE region LIKE '%" + region + "%'" - result = set() - for row in self.cur.execute(query): - result.add((row[0], row[1])) + query += f" WHERE region LIKE '%{region}%'" - return result + return {tuple(row) for row in self.cur.execute(query)} - def get_capacity_for_tech_and_period(self, tech=None, period=None, region=None): - if self.cur is None: - raise ValueError('Invalid Operation For dat file') - if self.scenario is None or self.scenario == '': - raise ValueError('For Output related queries, please set a scenario first') + def get_capacity_for_tech_and_period( + self, tech: str | None = None, period: int | None = None, region: str | None = None + ) -> pd.DataFrame | pd.Series: + """Retrieves capacity data, aggregated by technology.""" + if not self.scenario: + raise ValueError('A scenario must be set for output-related queries') - columns = [] - if tech is None: - columns.append('tech') - if period is None: - columns.append('period') - columns.append('sum(capacity)') - columns.append('region') - - query = 'SELECT ' + columns[0] - - for col in columns[1:]: - query += ', ' + col - - query += " FROM OutputNetCapacity WHERE scenario == '" + self.scenario + "'" + columns = ['tech', 'period', 'SUM(capacity)', 'region'] + query = f"SELECT {', '.join(columns)} FROM OutputNetCapacity WHERE scenario IS '{self.scenario}'" if region: - query += " AND region LIKE '" + region + "%'" + query += f" AND region LIKE '{region}%'" if tech: - query += " AND tech is '" + tech + "'" + query += f" AND tech IS '{tech}'" if period: - query += " AND period == '" + str(period) + "'" + query += f" AND period IS '{period}'" - # sum over vintages query += ' GROUP BY tech, region, period, sector;' - self.cur.execute(query) - # quick hack...change the column name for capacity - new_columns = [] - for col in columns: - new_col = col.replace('sum(capacity)', 'capacity') - new_columns.append(new_col) - columns = new_columns - result = pd.DataFrame(self.cur.fetchall(), columns=columns) - if region is None: + + df_columns = [col.replace('SUM(capacity)', 'capacity') for col in columns] + result = pd.DataFrame(self.cur.fetchall(), columns=df_columns) + + if region is None and not result.empty: mask = result['region'].str.contains('-') - # TODO: somebody needs to verify this halving of capacity...? result.loc[mask, 'capacity'] /= 2 result.drop(columns=['region'], inplace=True) - if len(columns) == 2: + if len(df_columns) == 2: return result.sum() else: return result.groupby(by='tech').sum().reset_index() - def get_output_flow_for_period(self, period, region, comm_type='input', commodity=None): - if self.cur is None: - raise ValueError('Invalid Operation For dat file') - if self.scenario is None or self.scenario == '': - raise ValueError('For Output related queries, please set a scenario first') - columns = [] + def get_output_flow_for_period( + self, + period: int, + region: str | None, + comm_type: str = 'input', + commodity: str | None = None, + ) -> pd.DataFrame: + """Retrieves aggregated output flow data.""" + if not self.scenario: + raise ValueError('A scenario must be set for output-related queries') + + columns: list[str] = [] table = '' - col = '' if comm_type == 'input': table = 'OutputFlowIn' if commodity is None: columns.append('input_comm') - col = 'flow' - columns.append('tech') - if comm_type == 'output': + elif comm_type == 'output': table = 'OutputFlowOut' if commodity is None: columns.append('output_comm') - col = 'flow' + columns.append('tech') - query = 'SELECT DISTINCT ' - for c in columns: - query += c + ', ' - query += ( - 'SUM(' + col + ') AS flow FROM ' + table + " WHERE scenario is '" + self.scenario + "'" - ) - if (region) and (comm_type == 'input'): - query += " AND region LIKE '" + region + "%'" - if (region) and (comm_type == 'output'): - query += " AND region LIKE '%" + region + "'" - query += " AND period is '" + str(period) + "' " - - query2 = ' GROUP BY tech' - if commodity is not None: - query += ' AND ' + comm_type + "_comm is '" + commodity + "'" + query = f"SELECT DISTINCT {', '.join(columns)}, SUM(flow) AS flow FROM {table} WHERE scenario IS '{self.scenario}'" + + if region: + query += f" AND region LIKE '{region}%'" + query += f" AND period IS '{period}'" + + group_by = ['tech'] + if commodity: + query += f" AND {comm_type}_comm IS '{commodity}'" if comm_type == 'output': - query += " AND input_comm != 'ethos' " + query += " AND input_comm != 'ethos'" else: - query2 += ', ' + comm_type + '_comm' + group_by.append(f'{comm_type}_comm') - query += query2 - columns.append('flow') + query += f' GROUP BY {", ".join(group_by)}' self.cur.execute(query) - result = pd.DataFrame(self.cur.fetchall(), columns=columns) - return result - - def get_emissions_activity_for_period(self, period, region): - if self.cur is None: - raise ValueError('Invalid Operation For dat file') - if self.scenario is None or self.scenario == '': - raise ValueError('For Output related queries, please set a scenario first') - query = ( - 'SELECT E.emis_comm, E.tech, SUM(E.activity*O.flow) FROM EmissionActivity E, OutputFlowOut O ' - + "WHERE E.input_comm == O.input_comm AND E.tech == O.tech AND E.vintage == O.vintage AND E.output_comm == O.output_comm AND O.scenario == '" - + self.scenario - + "' " - + "and O.period == '" - + str(period) - + "'" - ) + + df_columns = columns + ['flow'] + return pd.DataFrame(self.cur.fetchall(), columns=df_columns) + + def get_emissions_activity_for_period(self, period: int, region: str | None) -> pd.DataFrame: + """Retrieves emissions activity data.""" + if not self.scenario: + raise ValueError('A scenario must be set for output-related queries') + + query = f""" + SELECT E.emis_comm, E.tech, SUM(E.activity * O.flow) + FROM EmissionActivity E, OutputFlowOut O + WHERE E.input_comm = O.input_comm + AND E.tech = O.tech + AND E.vintage = O.vintage + AND E.output_comm = O.output_comm + AND O.scenario = '{self.scenario}' + AND O.period = '{period}' + """ if region: - query += " AND E.region LIKE '%" + region + "%'" + query += f" AND E.region LIKE '%{region}%'" query += ' GROUP BY E.tech, E.emis_comm' self.cur.execute(query) - result = pd.DataFrame(self.cur.fetchall(), columns=['emis_comm', 'tech', 'emis_activity']) - return result - - def get_commodity_wise_input_and_output_flow(self, tech, period, region): - if self.cur is None: - raise ValueError('Invalid Operation For dat file') - if self.scenario is None or self.scenario == '': - raise ValueError('For Output related queries, please set a scenario first') - - query = ( - "SELECT OF.input_comm, OF.output_comm, OF.vintage, OF.region,\ - SUM(OF.vflow_in) vflow_in, SUM(OFO.vflow_out) vflow_out, OC.capacity \ - FROM (SELECT region, scenario, sector, period, input_comm, tech, vintage, output_comm, sum(flow) AS vflow_in \ - FROM OutputFlowIn GROUP BY region, scenario, sector, period, input_comm, tech, vintage, output_comm) AS OF \ - INNER JOIN (SELECT region, scenario, sector, period, input_comm, tech, vintage, output_comm, sum(flow) AS vflow_out \ - FROM OutputFlowOut GROUP BY region, scenario, sector, period, input_comm, tech, vintage, output_comm) AS OFO \ - ON \ - OF.region = OFO.region AND \ - OF.scenario = OFO.scenario AND \ - OF.period = OFO.period AND \ - OF.tech = OFO.tech AND \ - OF.input_comm = OFO.input_comm AND \ - OF.vintage = OFO.vintage AND \ - OF.output_comm = OFO.output_comm \ - INNER JOIN \ - OutputNetCapacity OC \ - ON \ - OF.region = OC.region AND \ - OF.scenario = OC.scenario AND \ - OF.tech = OC.tech AND \ - OF.vintage = OC.vintage \ - WHERE \ - OF.period ='" - + str(period) - + "' AND \ - OF.tech is '" - + tech - + "' AND \ - OF.scenario is '" - + self.scenario - + "'" - ) - + return pd.DataFrame(self.cur.fetchall(), columns=['emis_comm', 'tech', 'emis_activity']) + + def get_commodity_wise_input_and_output_flow( + self, tech: str, period: int, region: str | None + ) -> pd.DataFrame: + """Retrieves detailed input and output flows for a technology.""" + if not self.scenario: + raise ValueError('A scenario must be set for output-related queries') + + query = f""" + SELECT + OF.input_comm, OF.output_comm, OF.vintage, OF.region, + SUM(OF.vflow_in) AS vflow_in, + SUM(OFO.vflow_out) AS vflow_out, + OC.capacity + FROM ( + SELECT region, scenario, period, input_comm, tech, vintage, output_comm, SUM(flow) AS vflow_in + FROM OutputFlowIn + GROUP BY region, scenario, period, input_comm, tech, vintage, output_comm + ) AS OF + INNER JOIN ( + SELECT region, scenario, period, input_comm, tech, vintage, output_comm, SUM(flow) AS vflow_out + FROM OutputFlowOut + GROUP BY region, scenario, period, input_comm, tech, vintage, output_comm + ) AS OFO ON + OF.region = OFO.region AND + OF.scenario = OFO.scenario AND + OF.period = OFO.period AND + OF.tech = OFO.tech AND + OF.input_comm = OFO.input_comm AND + OF.vintage = OFO.vintage AND + OF.output_comm = OFO.output_comm + INNER JOIN OutputNetCapacity OC ON + OF.region = OC.region AND + OF.scenario = OC.scenario AND + OF.tech = OC.tech AND + OF.vintage = OC.vintage + WHERE + OF.period = '{period}' AND + OF.tech IS '{tech}' AND + OF.scenario IS '{self.scenario}' + """ if region: - query += " AND OF.region LIKE '%" + region + "%'" - + query += f" AND OF.region LIKE '%{region}%'" query += ' GROUP BY OF.region, OF.vintage, OF.input_comm, OF.output_comm' self.cur.execute(query) @@ -411,7 +340,6 @@ def get_commodity_wise_input_and_output_flow(self, tech, period, region): 'capacity', ], ) - result = pd.DataFrame( - result.groupby(['input_comm', 'output_comm', 'vintage']).sum().reset_index() + return pd.DataFrame( + result.groupby(['input_comm', 'output_comm', 'vintage'], as_index=False).sum() ) - return result diff --git a/temoa/data_processing/db_query.py b/temoa/data_processing/db_query.py index 36449e55b..7db428b0c 100644 --- a/temoa/data_processing/db_query.py +++ b/temoa/data_processing/db_query.py @@ -1,51 +1,85 @@ # Dev Note: This module is unused and appears to be just a query executor. Retained for now. 12JUN2024 +""" +A command-line utility for sending a direct SQL query to a Temoa database. + +This script allows a user to specify a Temoa SQLite database and an SQL query +string to execute against it, printing the results to the console. +""" import getopt import re import sqlite3 import sys +from os import PathLike +from typing import Any + +def send_query(inp_f: str | PathLike[str], query_string: str) -> str: + """ + Connects to a database, executes a query, and returns the result as a string. -def send_query(inp_f, query_string): - db_result = [] + Args: + inp_f: The file path to the SQLite database. + query_string: The SQL query to execute. + + Returns: + A string containing the query results or an error message. + """ + db_result: list[tuple[Any, ...]] = [] try: con = sqlite3.connect(inp_f) - cur = con.cursor() # a database cursor is a control structure that enables traversal over the records in a database - con.text_factory = str # this ensures data is explored with the correct UTF-8 encoding + cur = con.cursor() + con.text_factory = str - print(inp_f) + print(f'Executing query on: {inp_f}') cur.execute(query_string) - for row in cur: - db_result.append(row) + db_result.extend(cur) cur.close() con.close() - return 'Query Result: %s' % ''.join(db_result) + # Convert list of tuples to a more readable string representation + result_str = '\n'.join(map(str, db_result)) + return f'Query Result:\n{result_str}' except sqlite3.Error as e: - print('Error in Query %s' % e.args[0]) - return 'Query Result: Error in Query %s' % e.args[0] + error_msg = f'Error in Query: {e.args[0]}' + print(error_msg) + return f'Query Result: {error_msg}' -def help_user(): +def help_user() -> None: + """Prints the help message for the script to the console.""" print( """Use as: - python db_query.py -i (or --input) - | -q (or --query) - | -h (or --help) """ + python db_query.py -i (or --input) + | -q (or --query) + | -h (or --help)""" ) -def get_flags(inputs): - inp_file = None - query_string = None +def get_flags(inputs: dict[str, str]) -> str | None: + """ + Parses command-line options and executes the database query. + + Args: + inputs: A dictionary of command-line options to their arguments. - if inputs is None: + Returns: + The result of the database query as a string, or None if no query was run. + + Raises: + TypeError: If no arguments are provided. + ValueError: If the input file is not specified or is not a valid database file. + """ + inp_file: str | None = None + query_string: str | None = None + + if not inputs: raise TypeError('no arguments found') for opt, arg in inputs.items(): - print('%s == %s' % (opt, arg)) + print(f'{opt} == {arg}') if opt in ('-i', '--input'): inp_file = arg @@ -56,15 +90,12 @@ def get_flags(inputs): sys.exit(2) if inp_file is None: - raise Exception('Input file not specified') - - file_ty = re.search(r'(\w+)\.(\w+)\b', inp_file) # Extract the input filename and extension + raise ValueError('Input file not specified') - if not file_ty: - raise 'The file type %s is not recognized. Please specify a database file.' % inp_file + file_ty = re.search(r'\.(\w+)$', inp_file) - elif file_ty.group(2) not in ('db', 'sqlite', 'sqlite3', 'sqlitedb'): - raise 'The file type %s is not recognized. Please specify a database file.' % inp_file + if not file_ty or file_ty.group(1) not in ('db', 'sqlite', 'sqlite3', 'sqlitedb'): + raise ValueError(f'The file type of "{inp_file}" is not a recognized database file.') if query_string is None: print('No query specified.') @@ -75,10 +106,12 @@ def get_flags(inputs): if __name__ == '__main__': try: - argv = sys.argv[1:] + argv: list[str] = sys.argv[1:] + opts: list[tuple[str, str]] + args: list[str] opts, args = getopt.getopt(argv, 'hi:q:', ['help', 'input=', 'query=']) - print(opts) + print(f'Options found: {opts}') except getopt.GetoptError: help_user() diff --git a/temoa/data_processing/graphviz_util.py b/temoa/data_processing/graphviz_util.py index a1ba46dcd..478c00eb3 100644 --- a/temoa/data_processing/graphviz_util.py +++ b/temoa/data_processing/graphviz_util.py @@ -1,7 +1,10 @@ import argparse +from collections.abc import Callable, Iterable, Sequence, Sized +from typing import Any -def process_input(args): +def process_input(args: list[str]) -> dict[str, Any]: + """Parse command line arguments.""" parser = argparse.ArgumentParser(description='Generate Output Plot') parser.add_argument( '-i', @@ -118,9 +121,10 @@ def process_input(args): return vars(options) -def get_color_config(grey_flag): +def get_color_config(grey_flag: bool) -> dict[str, str | tuple[str, ...]]: + """Return a dictionary of color configurations for the graph.""" grey_flag = not (grey_flag) - kwargs = dict( + kwargs: dict[str, str | tuple[str, ...]] = dict( tech_color='darkseagreen' if grey_flag else 'black', commodity_color='lightsteelblue' if grey_flag else 'black', unused_color='powderblue' if grey_flag else 'gray75', @@ -141,55 +145,57 @@ def get_color_config(grey_flag): sb_arrow_color='forestgreen' if grey_flag else 'black', # SUBGRAPH 1 ARROW COLORS color_list=( - 'red', - 'orange', - 'gold', - 'green', - 'blue', - 'purple', - 'hotpink', - 'cyan', - 'burlywood', - 'coral', - 'limegreen', - 'black', - 'brown', - ) - if grey_flag - else ('black', 'black'), + ( + 'red', + 'orange', + 'gold', + 'green', + 'blue', + 'purple', + 'hotpink', + 'cyan', + 'burlywood', + 'coral', + 'limegreen', + 'black', + 'brown', + ) + if grey_flag + else ('black', 'black') + ), ) return kwargs -def _get_len(key): - def wrapped(obj): +def _get_len(key: int) -> Callable[[Sequence[Sized]], int]: + """Return a function that gets the length of an item at a specific index in a sequence.""" + + def wrapped(obj: Sequence[Sized]) -> int: return len(obj[key]) return wrapped -def create_text_nodes(nodes, indent=1): - """\ -Return a set of text nodes in Graphviz DOT format, optimally padded for easier -reading and debugging. - -nodes: iterable of (id, attribute) node tuples - e.g. [(node1, attr1), (node2, attr2), ...] +def create_text_nodes(nodes: Iterable[tuple[str, str]], indent: int = 1) -> str: + """ + Return a set of text nodes in Graphviz DOT format, optimally padded for + easier reading and debugging. -indent: integer, number of tabs with which to indent all Dot node lines -""" + Args: + nodes: iterable of (id, attribute) node tuples + e.g. [(node1, attr1), (node2, attr2), ...] + indent: integer, number of tabs with which to indent all Dot node lines + """ if not nodes: return '// no nodes in this section' - # guarantee basic structure of nodes arg - assert len(nodes) == sum(1 for a, b in nodes) - # Step 1: for alignment, get max item length in node list - maxl = max(map(_get_len(0), nodes)) + 2 # account for two extra quotes + # The `+ 2` accounts for the two extra quotes that will be added. + maxl = max(map(_get_len(0), nodes), default=0) + 2 # Step 2: prepare a text format based on max node size that pads all # lines with attributes - nfmt_attr = '{0:<%d} [ {1} ] ;' % maxl # node text format + nfmt_attr = f'{{0:<{maxl}}} [ {{1}} ] ;' # node text format nfmt_noa = '{0} ;' # Step 3: create each node, and place string representation in a set to @@ -199,35 +205,31 @@ def create_text_nodes(nodes, indent=1): gviz.update(nfmt_noa.format(q % n) for n, a in nodes if not a) # Step 4: return a sorted version of nodes, as a single string - indent = '\n' + '\t' * indent - return indent.join(sorted(gviz)) + indent_str = '\n' + '\t' * indent + return indent_str.join(sorted(gviz)) -def create_text_edges(edges, indent=1): - """\ -Return a set of text edge definitions in Graphviz DOT format, optimally padded -for easier reading and debugging. +def create_text_edges(edges: Iterable[tuple[str, str, str]], indent: int = 1) -> str: + """ + Return a set of text edge definitions in Graphviz DOT format, optimally + padded for easier reading and debugging. -edges: iterable of (from, to, attribute) edge tuples - e.g. [(inp1, tech1, attr1), (inp2, tech2, attr2), ...] - -indent: integer, number of tabs with which to indent all Dot edge lines -""" + Args: + edges: iterable of (from, to, attribute) edge tuples + e.g. [(inp1, tech1, attr1), (inp2, tech2, attr2), ...] + indent: integer, number of tabs with which to indent all Dot edge lines + """ if not edges: return '// no edges in this section' - # guarantee basic structure of edges arg - assert len(edges) == sum(1 for a, b, c in edges) - # Step 1: for alignment, get max length of items on left and right side of - # graph operator token ('->') - maxl, maxr = max(map(_get_len(0), edges)), max(map(_get_len(1), edges)) - maxl += 2 # account for additional two quotes - maxr += 2 # account for additional two quotes + # graph operator token ('->'). The `+ 2` accounts for the two extra quotes. + maxl = max(map(_get_len(0), edges), default=0) + 2 + maxr = max(map(_get_len(1), edges), default=0) + 2 # Step 2: prepare format to be "\n\tinp+PADDING -> out+PADDING [..." - efmt_attr = '{0:<%d} -> {1:<%d} [ {2} ] ;' % (maxl, maxr) # with attributes - efmt_noa = '{0:<%d} -> {1} ;' % maxl # no attributes + efmt_attr = f'{{0:<{maxl}}} -> {{1:<{maxr}}} [ {{2}} ] ;' # with attributes + efmt_noa = f'{{0:<{maxl}}} -> {{1}} ;' # no attributes # Step 3: add each edge to a set (to guarantee unique entries only) q = '"%s"' # enforce quoting for all tokens @@ -235,5 +237,5 @@ def create_text_edges(edges, indent=1): gviz.update(efmt_noa.format(q % i, q % t) for i, t, a in edges if not a) # Step 4: return a sorted version of the edges, as a single string - indent = '\n' + '\t' * indent - return indent.join(sorted(gviz)) + indent_str = '\n' + '\t' * indent + return indent_str.join(sorted(gviz)) diff --git a/temoa/data_processing/make_graphviz.py b/temoa/data_processing/make_graphviz.py index 3629470d7..3f4ff8730 100644 --- a/temoa/data_processing/make_graphviz.py +++ b/temoa/data_processing/make_graphviz.py @@ -1,6 +1,7 @@ import os import sys from subprocess import call +from typing import Any, TextIO from .database_util import DatabaseUtil from .graphviz_formats import ( @@ -13,7 +14,29 @@ class GraphvizDiagramGenerator: - def __init__(self, db_file, scenario=None, region=None, out_dir='.', verbose=1): + """Generates Graphviz diagrams for Temoa models.""" + + db_file: str + q_name: str + scenario: str | None + region: str | None + out_dir: str + folder: dict[str, str] + verbose: int + colors: dict[str, Any] + db_util: DatabaseUtil + logger: TextIO + grey_flag: bool + + def __init__( + self, + db_file: str, + scenario: str | None = None, + region: str | None = None, + out_dir: str = '.', + verbose: int = 1, + ) -> None: + """Initialize the GraphvizDiagramGenerator.""" self.db_file = db_file self.q_name = os.path.splitext(os.path.basename(self.db_file))[0] self.scenario = scenario @@ -22,119 +45,125 @@ def __init__(self, db_file, scenario=None, region=None, out_dir='.', verbose=1): self.folder = {'results': 'whole_system', 'tech': 'processes', 'comm': 'commodities'} self.verbose = verbose self.colors = {} + self.grey_flag = False - def connect(self): + def connect(self) -> None: + """Connect to the database and set up output directories.""" self.db_util = DatabaseUtil(self.db_file, self.scenario) self.logger = open(os.path.join(self.out_dir, 'graphviz.log'), 'w') self.set_graphic_options(False, False) self.__log__('--------------------------------------') self.__log__('GraphvizDiagramGenerator: connected') if self.scenario: - out_dir = self.q_name + '_' + self.scenario + '_graphviz' + out_dir = f'{self.q_name}_{self.scenario}_graphviz' else: - out_dir = self.q_name + '_input_graphviz' + out_dir = f'{self.q_name}_input_graphviz' self.out_dir = os.path.join(self.out_dir, out_dir) if not os.path.exists(self.out_dir): os.mkdir(self.out_dir) - def close(self): + def close(self) -> None: + """Disconnect from the database and close the logger.""" self.db_util.close() self.__log__('GraphvizDiagramGenerator: disconnected') self.__log__('--------------------------------------') self.logger.close() - # os.chdir('..') - def __log__(self, msg): + def __log__(self, msg: str) -> None: + """Log a message to the console and a log file.""" if self.verbose == 1: print(msg) self.logger.write(msg + '\n') - def __generate_graph__(self, dot_format, dot_args, output_name, output_format): + def __generate_graph__( + self, dot_format: str, dot_args: dict[str, Any], output_name: str, output_format: str + ) -> None: + """Generate a graph from a DOT format string.""" dot_args.update(self.colors) with open(output_name + '.dot', 'w') as f: f.write(dot_format % dot_args) cmd = ( 'dot', - '-T' + output_format, - '-o' + output_name + '.' + output_format, - output_name + '.dot', + f'-T{output_format}', + f'-o{output_name}.{output_format}', + f'{output_name}.dot', ) call(cmd) - def set_graphic_options(self, grey_flag=None, splinevar=None): + def set_graphic_options( + self, grey_flag: bool | None = None, splinevar: bool | None = None + ) -> None: + """Set graphic options for the diagrams.""" if grey_flag is not None: self.grey_flag = grey_flag self.colors.update(get_color_config(self.grey_flag)) if splinevar is not None: - self.colors['splinevar'] = splinevar + self.colors['splinevar'] = 'spline' if splinevar else 'line' self.__log__( - 'setGraphicOption: updated greyFlag = ' - + str(self.grey_flag) - + ' and splinevar = ' - + str(self.colors['splinevar']) + f'setGraphicOption: updated greyFlag = {self.grey_flag} ' + f'and splinevar = {self.colors.get("splinevar", "line")}' ) - def create_main_results_diagram(self, period, region, output_format='svg'): - self.__log__('CreateMainResultsDiagram: started with period = ' + str(period)) + def create_main_results_diagram( + self, period: int, region: str | None, output_format: str = 'svg' + ) -> tuple[str, str]: + """Create the main results diagram for a specific period.""" + self.__log__(f'CreateMainResultsDiagram: started with period = {period}') - if not os.path.exists(os.path.join(self.out_dir, self.folder['results'])): - os.makedirs(os.path.join(self.out_dir, self.folder['results'])) + results_dir = os.path.join(self.out_dir, self.folder['results']) + if not os.path.exists(results_dir): + os.makedirs(results_dir) - output_name = os.path.join(self.folder['results'], 'results%s' % period) + output_name = os.path.join(self.folder['results'], f'results{period}') if self.region: - output_name += '_' + self.region + output_name += f'_{self.region}' output_name = os.path.join(self.out_dir, output_name) if self.grey_flag: output_name += '.grey' tech_all = self.db_util.get_technologies_for_flags(flags=['r', 'p', 'pb', 'ps']) - commodity_carrier = self.db_util.get_commodities_for_flags(flags=['d', 'p']) commodity_emissions = self.db_util.get_commodities_for_flags(flags=['e']) - efficiency_input = self.db_util.get_commodities_by_technology(region, comm_type='input') efficiency_output = self.db_util.get_commodities_by_technology(region, comm_type='output') - v_cap2 = self.db_util.get_capacity_for_tech_and_period(period=period, region=region) - ei_2 = self.db_util.get_output_flow_for_period( period=period, region=region, comm_type='input' ) eo_2 = self.db_util.get_output_flow_for_period( period=period, region=region, comm_type='output' ) - emio_2 = self.db_util.get_emissions_activity_for_period(period=period, region=region) self.__log__('CreateMainResultsDiagram: database fetched successfully') tech_attr_fmt = 'label="%s\\nCapacity: %.2f", href="#", onclick="loadNextGraphvizGraph(\'results\', \'%s\', \'%s\')"' - # tech_attr_fmt = 'label="%%s\\nCapacity: %%.2f", href="results_%%s_%%s.%s"' - # tech_attr_fmt %= outputFormat - # commodity_fmt = 'href="../commodities/rc_%%s_%%s.%s"' % outputFormat commodity_fmt = "href=\"#\", onclick=\"loadNextGraphvizGraph('results', '%s', '%s')\"" flow_fmt = 'label="%.2f"' - epsilon = 0.005 - etechs, dtechs, ecarriers, xnodes = set(), set(), set(), set() - eemissions = set() - eflowsi, eflowso, dflows = set(), set(), set() # edges + etechs: set[tuple[str, str]] = set() + dtechs: set[tuple[str, str]] = set() + ecarriers: set[tuple[str, str]] = set() + xnodes: set[tuple[str, str]] = set() + eemissions: set[tuple[str, str]] = set() + eflowsi: set[tuple[str, str, str]] = set() + eflowso: set[tuple[str, str, str]] = set() + dflows: set[tuple[str, str, str]] = set() usedc, usede = set(), set() # used carriers, used emissions v_cap2.index = v_cap2.tech for tech in set(tech_all) - set(v_cap2.tech): - dtechs.add((tech, None)) + dtechs.add((tech, '')) for i in range(len(v_cap2)): row = v_cap2.iloc[i] etechs.add( (row['tech'], tech_attr_fmt % (row['tech'], row['capacity'], row['tech'], period)) ) - # etechs.add( (row['tech'], tech_attr_fmt % (row['tech'], row['capacity'], row['tech'], period)) ) - udflows = set() + udflows: set[tuple[str, str]] = set() for i in range(len(ei_2)): row = ei_2.iloc[i] if row['input_comm'] != 'ethos': @@ -142,20 +171,16 @@ def create_main_results_diagram(self, period, region, output_format='svg'): ecarriers.add((row['input_comm'], commodity_fmt % (row['input_comm'], period))) usedc.add(row['input_comm']) else: - # check to see if this tech is in the unlim_cap set tech = row['tech'] - if tech not in v_cap2.tech: - cap = 99999 - else: - cap = v_cap2.loc[row['tech']].capacity + cap = v_cap2.loc[row['tech']].capacity if tech in v_cap2.tech else 99999 xnodes.add((row['tech'], tech_attr_fmt % (row['tech'], cap, row['tech'], period))) udflows.add((row['input_comm'], row['tech'])) for row in set(efficiency_input) - udflows: if row[0] != 'ethos': - dflows.add((row[0], row[1], None)) + dflows.add((row[0], row[1], '')) else: - xnodes.add((row[1], None)) + xnodes.add((row[1], '')) udflows = set() for i in range(len(eo_2)): @@ -166,23 +191,17 @@ def create_main_results_diagram(self, period, region, output_format='svg'): udflows.add((row['tech'], row['output_comm'])) for row in set(efficiency_output) - udflows: - dflows.add((row[0], row[1], None)) + dflows.add((row[0], row[1], '')) for i in range(len(emio_2)): row = emio_2.iloc[i] if row['emis_activity'] >= epsilon: eflowso.add((row['tech'], row['emis_comm'], flow_fmt % row['emis_activity'])) - eemissions.add((row['emis_comm'], None)) + eemissions.add((row['emis_comm'], '')) usede.add(row['emis_comm']) - dcarriers = set() - demissions = set() - for cc in commodity_carrier: - if cc not in usedc and cc != 'ethos': - dcarriers.add((cc, None)) - for ee in commodity_emissions: - if ee not in usede: - demissions.add((ee, None)) + dcarriers = {(cc, '') for cc in commodity_carrier if cc not in usedc and cc != 'ethos'} + demissions = {(ee, '') for ee in commodity_emissions if ee not in usede} self.__log__('CreateMainResultsDiagram: creating diagrams') args = dict( @@ -200,44 +219,43 @@ def create_main_results_diagram(self, period, region, output_format='svg'): eflowso=create_text_edges(eflowso, indent=3), ) + output_path = output_name + '.' + output_format self.__generate_graph__(results_dot_fmt, args, output_name, output_format) self.__log__('CreateMainResultsDiagram: graph generated, returning') - return self.out_dir, output_name + '.' + output_format + return self.out_dir, output_path - # Needs some small fixing - cases where no input but output is there. # Check sample graphs def create_tech_results_diagrams( - self, period, region, tech, output_format='svg' - ): # tech results - self.__log__( - 'CreateTechResultsDiagrams: started with period = ' - + str(period) - + ' and tech = ' - + str(tech) - ) + self, period: int, region: str | None, tech: str, output_format: str = 'svg' + ) -> tuple[str, str]: + """Create technology-specific results diagrams.""" + self.__log__(f'CreateTechResultsDiagrams: started with period = {period} and tech = {tech}') - if not os.path.exists(os.path.join(self.out_dir, self.folder['tech'])): - os.makedirs(os.path.join(self.out_dir, self.folder['tech'])) + tech_dir = os.path.join(self.out_dir, self.folder['tech']) + if not os.path.exists(tech_dir): + os.makedirs(tech_dir) output_name = os.path.join(self.folder['tech'], f'results_{tech}_{period}') if self.region: - output_name += '_' + self.region + output_name += f'_{self.region}' output_name = os.path.join(self.out_dir, output_name) if self.grey_flag: output_name += '.grey' - # enode_attr_fmt = 'href="../commodities/rc_%%s_%%s.%s"' % outputFormat - # vnode_attr_fmt = 'href="results_%%s_p%%sv%%s_segments.%s", ' % outputFormat - # vnode_attr_fmt += 'label="%s\\nCap: %.2f"' enode_attr_fmt = "href=\"#\", onclick=\"loadNextGraphvizGraph('results', '%s', '%s')\"" - vnode_attr_fmt = "href=\"#\", onclick=\"loadNextGraphvizGraph('%s', '%s', '%s')\"" - vnode_attr_fmt += 'label="%s\\nCap: %.2f"' + vnode_attr_fmt = ( + "href=\"#\", onclick=\"loadNextGraphvizGraph('%s', '%s', '%s')\", " + 'label="%s\\nCap: %.2f"' + ) total_cap = self.db_util.get_capacity_for_tech_and_period(tech, period, region) flows = self.db_util.get_commodity_wise_input_and_output_flow(tech, period, region) - self.__log__('CreateTechResultsDiagrams: database fetched successfully') - enodes, vnodes, iedges, oedges = set(), set(), set(), set() + enodes: set[tuple[str, str]] = set() + vnodes: set[tuple[str, str]] = set() + iedges: set[tuple[str, str, str]] = set() + oedges: set[tuple[str, str, str]] = set() + for i in range(len(flows)): row = flows.iloc[i] vnode = str(row['vintage']) @@ -255,13 +273,11 @@ def create_tech_results_diagrams( enodes.add((row['output_comm'], enode_attr_fmt % (row['output_comm'], period))) oedges.add((vnode, row['output_comm'], 'label="%.2f"' % row['flow_out'])) - # cluster_vintage_url = "results%s.%s" % (period, outputFormat) - cluster_vintage_url = '#' - + output_path = output_name + '.' + output_format if vnodes: self.__log__('CreateTechResultsDiagrams: creating diagrams') - args = dict( - cluster_vintage_url=cluster_vintage_url, + args: dict[str, Any] = dict( + cluster_vintage_url='#', total_cap=total_cap, inp_technology=tech, period=period, @@ -275,22 +291,23 @@ def create_tech_results_diagrams( self.__log__('CreateTechResultsDiagrams: nothing to create') self.__log__('CreateTechResultsDiagrams: graph generated, returning') - return self.out_dir, output_name + '.' + output_format + return self.out_dir, output_path - def create_commodity_partial_results(self, period, region, comm, output_format='svg'): + def create_commodity_partial_results( + self, period: int, region: str | None, comm: str, output_format: str = 'svg' + ) -> tuple[str, str]: + """Create commodity-specific partial results diagrams.""" self.__log__( - 'CreateCommodityPartialResults: started with period = ' - + str(period) - + ' and comm = ' - + str(comm) + f'CreateCommodityPartialResults: started with period = {period} and comm = {comm}' ) - if not os.path.exists(os.path.join(self.out_dir, self.folder['comm'])): - os.makedirs(os.path.join(self.out_dir, self.folder['comm'])) + comm_dir = os.path.join(self.out_dir, self.folder['comm']) + if not os.path.exists(comm_dir): + os.makedirs(comm_dir) output_name = os.path.join(self.folder['comm'], f'rc_{comm}_{period}') if self.region: - output_name += '_' + self.region + output_name += f'_{self.region}' output_name = os.path.join(self.out_dir, output_name) if self.grey_flag: output_name += '.grey' @@ -301,28 +318,22 @@ def create_commodity_partial_results(self, period, region, comm, output_format=' output_total = set( self.db_util.get_existing_technologies_for_commodity(comm, region, 'input')['tech'] ) - flow_in = self.db_util.get_output_flow_for_period(period, region, 'input', comm) otechs = set(flow_in['tech']) - flow_out = self.db_util.get_output_flow_for_period(period, region, 'output', comm) itechs = set(flow_out['tech']) - self.__log__('CreateCommodityPartialResults: database fetched successfully') - # period_results_url_fmt = '../results/results%%s.%s' % outputFormat - # node_attr_fmt = 'href="../results/results_%%s_%%s.%s"' % outputFormat - # rc_node_fmt = 'color="%s", href="%s", shape="circle", fillcolor="%s", fontcolor="black"' - node_attr_fmt = "href=\"#\", onclick=\"loadNextGraphvizGraph('results', '%s', '%s')\"" rc_node_fmt = 'color="%s", href="%s", shape="circle", fillcolor="%s", fontcolor="black"' - # url = period_results_url_fmt % period - url = '#' - enodes, dnodes, eedges, dedges = set(), set(), set(), set() + enodes: set[tuple[str, str]] = set() + dnodes: set[tuple[str, str]] = set() + eedges: set[tuple[str, str, str]] = set() + dedges: set[tuple[str, str, str]] = set() rcnode = ( - (comm, rc_node_fmt % (self.colors['commodity_color'], url, self.colors['fill_color'])), + (comm, rc_node_fmt % (self.colors['commodity_color'], '#', self.colors['fill_color'])), ) for i in range(len(flow_in)): @@ -331,16 +342,16 @@ def create_commodity_partial_results(self, period, region, comm, output_format=' enodes.add((t, node_attr_fmt % (t, period))) eedges.add((comm, t, 'label="%.2f"' % f)) for t in output_total - otechs: - dnodes.add((t, None)) - dedges.add((comm, t, None)) + dnodes.add((t, '')) + dedges.add((comm, t, '')) for i in range(len(flow_out)): t = flow_out.iloc[i]['tech'] f = flow_out.iloc[i]['flow'] enodes.add((t, node_attr_fmt % (t, period))) eedges.add((t, comm, 'label="%.2f"' % f)) for t in input_total - itechs: - dnodes.add((t, None)) - dedges.add((t, comm, None)) + dnodes.add((t, '')) + dedges.add((t, comm, '')) self.__log__('CreateCommodityPartialResults: creating diagrams') args = dict( @@ -352,39 +363,45 @@ def create_commodity_partial_results(self, period, region, comm, output_format=' used_edges=create_text_edges(eedges, indent=2), unused_edges=create_text_edges(dedges, indent=2), ) + output_path = output_name + '.' + output_format self.__generate_graph__(commodity_dot_fmt, args, output_name, output_format) self.__log__('CreateCommodityPartialResults: graph generated, returning') - return self.out_dir, output_name + '.' + output_format + return self.out_dir, output_path - # Function for generating the Input Graph def create_complete_input_graph( - self, region, inp_tech=None, inp_comm=None, output_format='svg' - ): + self, + region: str | None, + inp_tech: str | None = None, + inp_comm: str | None = None, + output_format: str = 'svg', + ) -> tuple[str, str]: + """Generate the complete input graph.""" self.__log__( - 'createCompleteInputGraph: started with inp_tech = ' - + str(inp_tech) - + ' and inp_comm = ' - + str(inp_comm) + f'createCompleteInputGraph: started with inp_tech = {inp_tech} ' + f'and inp_comm = {inp_comm}' ) output_name = self.q_name if inp_tech: - output_name += '_' + str(inp_tech) - if not os.path.exists(os.path.join(self.out_dir, self.folder['tech'])): - os.makedirs(os.path.join(self.out_dir, self.folder['tech'])) + output_name += f'_{inp_tech}' + tech_dir = os.path.join(self.out_dir, self.folder['tech']) + if not os.path.exists(tech_dir): + os.makedirs(tech_dir) output_name = os.path.join(self.folder['tech'], output_name) elif inp_comm: - output_name += '_' + str(inp_comm) - if not os.path.exists(os.path.join(self.out_dir, self.folder['comm'])): - os.makedirs(os.path.join(self.out_dir, self.folder['comm'])) + output_name += f'_{inp_comm}' + comm_dir = os.path.join(self.out_dir, self.folder['comm']) + if not os.path.exists(comm_dir): + os.makedirs(comm_dir) output_name = os.path.join(self.folder['comm'], output_name) else: - if not os.path.exists(os.path.join(self.out_dir, self.folder['results'])): - os.makedirs(os.path.join(self.out_dir, self.folder['results'])) + results_dir = os.path.join(self.out_dir, self.folder['results']) + if not os.path.exists(results_dir): + os.makedirs(results_dir) output_name = os.path.join(self.folder['results'], output_name) if self.region: - output_name += '_' + self.region + output_name += f'_{self.region}' output_name = os.path.join(self.out_dir, output_name) if self.grey_flag: @@ -392,13 +409,13 @@ def create_complete_input_graph( nodes, tech, ltech, to_tech, from_tech = set(), set(), set(), set(), set() - if DatabaseUtil.is_database_file(self.db_file): - res = self.db_util.get_commodities_and_tech(inp_comm, inp_tech, region) - else: - res = self.db_util.read_from_dat_file(inp_comm, inp_tech) + res = ( + self.db_util.get_commodities_and_tech(inp_comm, inp_tech, region) + if DatabaseUtil.is_database_file(self.db_file) + else self.db_util.read_from_dat_file(inp_comm, inp_tech) + ) self.__log__('createCompleteInputGraph: database fetched successfully') - # Create nodes and edges using the data frames from database for i in range(len(res)): row = res.iloc[i] if row['input_comm'] != 'ethos': @@ -409,43 +426,49 @@ def create_complete_input_graph( tech.add(row['tech']) if row['input_comm'] != 'ethos': - to_tech.add('"%s"' % row['input_comm'] + '\t->\t"%s"' % row['tech']) - from_tech.add('"%s"' % row['tech'] + '\t->\t"%s"' % row['output_comm']) + to_tech.add(f'"{row["input_comm"]}"\t->\t"{row["tech"]}"') + from_tech.add(f'"{row["tech"]}"\t->\t"{row["output_comm"]}"') self.__log__('createCompleteInputGraph: creating diagrams') args = dict( - enodes=''.join('"%s";\n\t\t' % x for x in nodes), - tnodes=''.join('"%s";\n\t\t' % x for x in tech), - iedges=''.join('%s;\n\t\t' % x for x in to_tech), - oedges=''.join('%s;\n\t\t' % x for x in from_tech), - snodes=';'.join('"%s"' % x for x in ltech), + enodes=''.join(f'"{x}";\n\t\t' for x in nodes), + tnodes=''.join(f'"{x}";\n\t\t' for x in tech), + iedges=''.join(f'{x};\n\t\t' for x in to_tech), + oedges=''.join(f'{x};\n\t\t' for x in from_tech), + snodes=';'.join(f'"{x}"' for x in ltech), ) + output_path = output_name + '.' + output_format self.__generate_graph__(quick_run_dot_fmt, args, output_name, output_format) self.__log__('createCompleteInputGraph: graph generated, returning') - return self.out_dir, output_name + '.' + output_format + return self.out_dir, output_path if __name__ == '__main__': - input = process_input(sys.argv[1:]) + cli_input = process_input(sys.argv[1:]) graph_gen = GraphvizDiagramGenerator( - input['ifile'], input['scenario_name'], input['region'], out_dir=input['res_dir'] + cli_input['ifile'], + cli_input['scenario_name'], + cli_input['region'], + out_dir=cli_input['res_dir'], ) graph_gen.connect() - graph_gen.set_graphic_options(grey_flag=input['grey_flag'], splinevar=input['splinevar']) - if input['scenario_name'] is None: - res = graph_gen.create_complete_input_graph( - input['region'], input['inp_technology'], input['inp_commodity'] + graph_gen.set_graphic_options( + grey_flag=cli_input['grey_flag'], splinevar=cli_input['splinevar'] + ) + if cli_input['scenario_name'] is None: + result = graph_gen.create_complete_input_graph( + cli_input['region'], cli_input['inp_technology'], cli_input['inp_commodity'] ) - elif input['inp_technology'] is None and input['inp_commodity'] is None: - res = graph_gen.create_main_results_diagram(input['period'], input['region']) - elif input['inp_commodity'] is None: - res = graph_gen.create_tech_results_diagrams( - input['period'], input['region'], input['inp_technology'] + elif cli_input['inp_technology'] is None and cli_input['inp_commodity'] is None: + result = graph_gen.create_main_results_diagram(cli_input['period'], cli_input['region']) + elif cli_input['inp_commodity'] is None: + result = graph_gen.create_tech_results_diagrams( + cli_input['period'], cli_input['region'], cli_input['inp_technology'] ) - elif input['inp_technology'] is None: - res = graph_gen.create_commodity_partial_results( - input['period'], input['region'], input['inp_commodity'] + else: # 'inp_technology' is None + result = graph_gen.create_commodity_partial_results( + cli_input['period'], cli_input['region'], cli_input['inp_commodity'] ) graph_gen.close() - print('Check graph generated at ', res[1], ' and all results at ', res[0]) + print(f'Check graph generated at {result[1]} and all results at {result[0]}') diff --git a/temoa/data_processing/make_output_plots.py b/temoa/data_processing/make_output_plots.py index 33db1d53c..7c1116d8d 100644 --- a/temoa/data_processing/make_output_plots.py +++ b/temoa/data_processing/make_output_plots.py @@ -1,107 +1,116 @@ -import sqlite3 -import sys - -import matplotlib - -matplotlib.use('Agg') import argparse import os import random +import sqlite3 +import sys +from collections.abc import Callable +from typing import cast +import matplotlib from matplotlib import cm as cmx from matplotlib import colors from matplotlib import pyplot as plt +from matplotlib.figure import Figure +from matplotlib.legend import Legend + +matplotlib.use('Agg') + +# Type aliases for clarity using modern built-in generics +DbRow = list[str | int | float] +# All numeric lists are floats for consistency in plotting data. +PlotData = dict[str, list[float]] +Color = tuple[float, float, float, float] +ColorMapFunc = Callable[[int | float], Color] class OutputPlotGenerator: - def __init__(self, path_to_db, region, scenario, super_categories=False) -> None: + """Generates plots from Temoa model output databases.""" + + db_path: str + region: str + scenario: str + folder_name: str + output_file_name: str + capacity_output: list[DbRow] + output_vflow: list[DbRow] + output_emissions: list[DbRow] + tech_categories: list[list[str]] + + def __init__( + self, path_to_db: str, region: str, scenario: str, super_categories: bool = False + ) -> None: self.db_path = os.path.abspath(path_to_db) - if region == 'global': - self.region = '%' - else: - self.region = region + self.region = '%' if region == 'global' else region self.scenario = scenario self.folder_name = ( - os.path.splitext(os.path.basename(path_to_db))[0] - + '_' - + region - + '_' - + scenario - + '_plots' + f'{os.path.splitext(os.path.basename(path_to_db))[0]}_{region}_{scenario}_plots' ) - # self.extractFromDatabase() + self.capacity_output = [] + self.output_vflow = [] + self.output_emissions = [] + self.tech_categories = [] + self.output_file_name = '' - def extract_from_database(self, mode) -> None: + def extract_from_database(self, mode: int) -> None: """ - Based on the type of the plot being generated, extract data from the corresponding table from database + Based on the type of the plot being generated, extract data from the + corresponding table from the database. """ con = sqlite3.connect(self.db_path) cur = con.cursor() if mode == 1: cur.execute( - "SELECT sector, period, tech, capacity FROM OutputNetCapacity WHERE scenario == '" - + self.scenario - + "' AND region LIKE '" - + self.region - + "'" + f'SELECT sector, period, tech, capacity FROM OutputNetCapacity ' + f"WHERE scenario == '{self.scenario}' AND region LIKE '{self.region}'" ) - self.capacity_output = cur.fetchall() - self.capacity_output = [list(elem) for elem in self.capacity_output] + self.capacity_output = [list(elem) for elem in cur.fetchall()] elif mode == 2: cur.execute( - "SELECT sector, period, tech, SUM(flow) FROM OutputFlowOut WHERE scenario == '" - + self.scenario - + "' AND region LIKE '" - + self.region - + "' GROUP BY sector, period, tech" + f'SELECT sector, period, tech, SUM(flow) FROM OutputFlowOut ' + f"WHERE scenario == '{self.scenario}' AND region LIKE '{self.region}' " + f'GROUP BY sector, period, tech' ) - self.output_vflow = cur.fetchall() - self.output_vflow = [list(elem) for elem in self.output_vflow] + self.output_vflow = [list(elem) for elem in cur.fetchall()] elif mode == 3: cur.execute( - "SELECT sector, period, emis_comm, SUM(emission) FROM OutputEmission WHERE scenario == '" - + self.scenario - + "' AND region LIKE '" - + self.region - + "' GROUP BY sector, period, emis_comm" + f'SELECT sector, period, emis_comm, SUM(emission) FROM OutputEmission ' + f"WHERE scenario == '{self.scenario}' AND region LIKE '{self.region}' " + f'GROUP BY sector, period, emis_comm' ) - self.output_emissions = cur.fetchall() - self.output_emissions = [list(elem) for elem in self.output_emissions] + self.output_emissions = [list(elem) for elem in cur.fetchall()] cur.execute('SELECT tech, category FROM Technology') - self.tech_categories = cur.fetchall() - self.tech_categories = [[str(word) for word in t] for t in self.tech_categories] + self.tech_categories = [[str(word) for word in t] for t in cur.fetchall()] con.close() - def get_sectors(self, type): + def get_sectors(self, plot_type: int) -> list[str]: """ - Based on the type of the plot being generated, returns a list of sectors available in the database + Based on the type of the plot, returns a list of sectors available in the database. """ - self.extract_from_database(type) - sectors = set() - - data = None + self.extract_from_database(plot_type) + sectors: set[str] = set() + data: list[DbRow] = [] - if type == 1: + if plot_type == 1: data = self.capacity_output - elif type == 2: + elif plot_type == 2: data = self.output_vflow - elif type == 3: + elif plot_type == 3: data = self.output_emissions for row in data: - sectors.add(row[0]) + sectors.add(str(row[0])) - res = list(sectors) + res = sorted(list(sectors)) res.insert(0, 'all') return res - def process_data(self, input_data, sector, super_categories=False): - """ - Processes data for a particular sector to make it ready for plotting purposes - """ - periods = set() - techs = set() + def process_data( + self, input_data: list[DbRow], sector: str, super_categories: bool + ) -> PlotData: + """Processes data for a particular sector to make it ready for plotting.""" + periods_set: set[int] = set() + techs_set: set[str] = set() for row in input_data: row[0] = str(row[0]) @@ -112,227 +121,199 @@ def process_data(self, input_data, sector, super_categories=False): tech_dict = dict(self.tech_categories) if super_categories: for row in input_data: - row[2] = tech_dict.get(row[2], row[2]) + row[2] = tech_dict.get(str(row[2]), str(row[2])) for row in input_data: if row[0] == sector or sector == 'all': - periods.add(row[1]) # Reminder: indexing starts at 0 - techs.add(row[2]) + periods_set.add(int(row[1])) + techs_set.add(str(row[2])) - periods = list(periods) - techs = list(techs) - periods.sort() + periods = sorted(list(periods_set)) + techs = sorted(list(techs_set)) - output_values = dict() # Each row in a dictionary is a list + output_values: PlotData = {} for tech in techs: - if tech == 'None' or tech == '': + if tech in ('None', ''): continue - output_values[tech] = [0] * len(periods) # this just creates a blank table + output_values[tech] = [0.0] * len(periods) + for row in input_data: - if row[2] == 'None' or row[2] == '': + tech_name = str(row[2]) + if tech_name not in output_values: continue if row[0] == sector or sector == 'all': - output_values[row[2]][periods.index(row[1])] += row[-1] + output_values[tech_name][periods.index(int(row[1]))] += float(row[-1]) - output_values['periods'] = periods + output_values['periods'] = [float(p) for p in periods] return output_values - def handle_output_path(self, plot_type, sector, super_categories, output_dir): - outfile = plot_type + '_' + sector # +'_'+str(int(time.time()*1000))+'.png' + def handle_output_path( + self, plot_type: str, sector: str, super_categories: bool, output_dir: str + ) -> str: + """Constructs and creates the output path for the plot.""" + outfile = f'{plot_type}_{sector}' if super_categories: outfile += '_merged' outfile += '.png' - outfile2 = os.path.join(self.folder_name, outfile) - output_dir = os.path.join(output_dir, self.folder_name) - if not os.path.exists(output_dir): - os.makedirs(output_dir) - self.output_file_name = os.path.join(output_dir, outfile) + full_output_dir = os.path.join(output_dir, self.folder_name) + if not os.path.exists(full_output_dir): + os.makedirs(full_output_dir) - self.output_file_name = self.output_file_name.replace(' ', '') - return outfile2 - - def generate_plot_for_capacity(self, sector, super_categories=False, output_dir='.'): - """ - Generates Plot for Capacity of a given sector - """ + self.output_file_name = os.path.join(full_output_dir, outfile).replace(' ', '') + return os.path.join(self.folder_name, outfile) - outfile2 = self.handle_output_path('capacity', sector, super_categories, output_dir) + def generate_plot_for_capacity( + self, sector: str, super_categories: bool = False, output_dir: str = '.' + ) -> str: + """Generates a plot for the capacity of a given sector.""" + relative_path = self.handle_output_path('capacity', sector, super_categories, output_dir) if os.path.exists(self.output_file_name): print('not generating new capacity plot') - return outfile2 + return relative_path sectors = self.get_sectors(1) - if sector not in sectors: return '' output_values = self.process_data(self.capacity_output, sector, super_categories) - - if self.region == '%': - title = 'Capacity Plot for ' + sector + ' across all regions' - else: - title = 'Capacity Plot for ' + sector + ' sector in region ' + self.region - - self.make_stacked_bar_plot(output_values, 'Years', 'Capacity ', 'periods', title) - - return outfile2 - - def generate_plot_for_output_flow(self, sector, super_categories=False, output_dir='.'): - """ - Generates Plot for Output Flow of a given sector - """ - outfile2 = self.handle_output_path('flow', sector, super_categories, output_dir) + title = ( + f'Capacity Plot for {sector} across all regions' + if self.region == '%' + else f'Capacity Plot for {sector} sector in region {self.region}' + ) + self.make_stacked_bar_plot(output_values, 'Years', 'Capacity', 'periods', title) + return relative_path + + def generate_plot_for_output_flow( + self, sector: str, super_categories: bool = False, output_dir: str = '.' + ) -> str: + """Generates a plot for the output flow of a given sector.""" + relative_path = self.handle_output_path('flow', sector, super_categories, output_dir) if os.path.exists(self.output_file_name): print('not generating new flow plot') - return outfile2 + return relative_path sectors = self.get_sectors(2) if sector not in sectors: return '' output_values = self.process_data(self.output_vflow, sector, super_categories) - - if self.region == '%': - title = 'Output Flow Plot for ' + sector + ' across all regions' - else: - title = 'Output Flow Plot for ' + sector + ' sector in region ' + self.region - - self.make_stacked_bar_plot(output_values, 'Years', 'Activity ', 'periods', title) - - return outfile2 - - def generate_plot_for_emissions(self, sector, super_categories=False, output_dir='.'): - """ - Generates Plot for Emissions of a given sector - """ - outfile2 = self.handle_output_path('emissions', sector, super_categories, output_dir) + title = ( + f'Output Flow Plot for {sector} across all regions' + if self.region == '%' + else f'Output Flow Plot for {sector} sector in region {self.region}' + ) + self.make_stacked_bar_plot(output_values, 'Years', 'Activity', 'periods', title) + return relative_path + + def generate_plot_for_emissions( + self, sector: str, super_categories: bool = False, output_dir: str = '.' + ) -> str: + """Generates a plot for the emissions of a given sector.""" + relative_path = self.handle_output_path('emissions', sector, super_categories, output_dir) if os.path.exists(self.output_file_name): print('not generating new emissions plot') - return outfile2 + return relative_path sectors = self.get_sectors(3) if sector not in sectors: return '' output_values = self.process_data(self.output_emissions, sector, super_categories) - - if self.region == '%': - title = 'Emissions Plot for ' + sector + ' across all regions' - else: - title = 'Emissions Plot for ' + sector + ' sector in region ' + self.region - + title = ( + f'Emissions Plot for {sector} across all regions' + if self.region == '%' + else f'Emissions Plot for {sector} sector in region {self.region}' + ) self.make_line_plot(output_values.copy(), 'Emissions', title) + return relative_path - return outfile2 + # --------------------------- Plot Generation related functions -------------------------------------- - """ - --------------------------- Plot Generation related functions -------------------------------------- - """ - - def get_random_color(self, pastel_factor=0.5): - return [ - (x + pastel_factor) / (1.0 + pastel_factor) - for x in [random.uniform(0, 1.0) for i in [1, 2, 3]] - ] - - def color_distance(self, c1, c2): - return sum([abs(x[0] - x[1]) for x in zip(c1, c2, strict=False)]) - - def get_cmap(self, size): - """Returns a function that maps each index in 0, 1, ... N-1 to a distinct - RGB color.""" + def get_cmap(self, size: int) -> ColorMapFunc: + """Returns a function that maps an index to a distinct RGB color.""" color_norm = colors.Normalize(vmin=0, vmax=size - 1) - # More colormaps: https://matplotlib.org/examples/color/colormaps_reference.html scalar_map = cmx.ScalarMappable(norm=color_norm, cmap='viridis') - def map_index_to_rgb_color(index): - return scalar_map.to_rgba(index) - - return map_index_to_rgb_color - - def generate_new_color(self, existing_colors, pastel_factor=0.5): - max_distance = None - best_color = None - for _ in range(0, 100): - color = self.get_random_color(pastel_factor=pastel_factor) - if not existing_colors: - return color - best_distance = min([self.color_distance(color, c) for c in existing_colors]) - if not max_distance or best_distance > max_distance: - max_distance = best_distance - best_color = color - return best_color - - def make_stacked_bar_plot(self, data, xlabel, ylabel, xvar, title): + def wrapper(index: int | float) -> Color: + # We ignore the arg-type error. Mypy expects a NumPy array based on the + # library's type stubs, but matplotlib's to_rgba function correctly + # handles scalar inputs at runtime. This is a known limitation of the stubs. + rgba_value = scalar_map.to_rgba(index) # type: ignore[arg-type] + return cast(Color, rgba_value) + + return wrapper + + def make_stacked_bar_plot( + self, data: PlotData, xlabel: str, ylabel: str, xvar: str, title: str + ) -> None: + """Creates and saves a stacked bar plot.""" random.seed(10) + data_copy = data.copy() - handles = list() - xaxis = data[xvar] - data.pop('c', 0) - data.pop(xvar, 0) - stacked_bars = data.keys() - color_map_for_bars = dict() - plt.figure() + xaxis = data_copy.pop(xvar, []) + data_copy.pop('c', None) + stacked_bars = list(data_copy.keys()) + fig: Figure = plt.figure() cmap = self.get_cmap(len(stacked_bars)) - for i in range(0, len(stacked_bars)): - # colors.append(self.generate_new_color(colors,pastel_factor = 0.9)) - # colorMapForBars[data.keys()[i]]=colors[i] - color_map_for_bars[list(data.keys())[i]] = cmap(i) - - width = min([xaxis[i + 1] - xaxis[i] for i in range(0, len(xaxis) - 1)]) / 2.0 - b = [0] * len(xaxis) + color_map_for_bars = {bar_name: cmap(i) for i, bar_name in enumerate(stacked_bars)} - # plt.figure() + width = ( + min(xaxis[i + 1] - xaxis[i] for i in range(len(xaxis) - 1)) / 2.0 + if len(xaxis) > 1 + else 1.0 + ) + bottom = [0.0] * len(xaxis) + handles = [] for bar in stacked_bars: - h = plt.bar(xaxis, data[bar], width, bottom=b, color=color_map_for_bars[bar]) + values = data_copy[bar] + h = plt.bar(xaxis, values, width, bottom=bottom, color=color_map_for_bars[bar]) handles.append(h) - b = [b[j] + data[bar][j] for j in range(0, len(b))] + bottom = [b + v for b, v in zip(bottom, values, strict=False)] plt.xlabel(xlabel) plt.ylabel(ylabel) - # plt.xticks([width*0.5 + i for i in xaxis], [str(i) for i in xaxis]) - plt.xticks([i for i in xaxis], [str(i) for i in xaxis]) + plt.xticks(xaxis, [str(int(x)) for x in xaxis]) plt.title(title) - lgd = plt.legend( + lgd: Legend = plt.legend( [h[0] for h in handles], stacked_bars, bbox_to_anchor=(1.2, 1), fontsize=7.5 ) - # plt.show() plt.savefig(self.output_file_name, bbox_extra_artists=(lgd,), bbox_inches='tight') + plt.close(fig) - def make_line_plot(self, plot_var, label, title): - handles = list() - periods = plot_var['periods'] - plot_var.pop('periods', 0) - techs = plot_var.keys() + def make_line_plot(self, plot_var: PlotData, label: str, title: str) -> None: + """Creates and saves a line plot.""" random.seed(10) - color_map = dict() - plt.figure() + periods = plot_var.pop('periods', []) + techs = list(plot_var.keys()) + + fig: Figure = plt.figure() cmap = self.get_cmap(len(techs)) - for i in range(0, len(techs)): - # colors.append(self.generate_new_color(colors,pastel_factor = 0.9)) - # color_map[plot_var.keys()[i]]=colors[i] - color_map[plot_var.keys()[i]] = cmap(i) + color_map = {tech: cmap(i) for i, tech in enumerate(techs)} + handles = [] for tech in techs: - h = plt.plot(periods, plot_var[tech], color=color_map[tech], linestyle='--', marker='o') + values = plot_var[tech] + h = plt.plot(periods, values, color=color_map[tech], linestyle='--', marker='o') handles.append(h) plt.xlabel('Years') plt.ylabel(label) - # plt.xticks([i + width*0.5 for i in periods], [str(i) for i in periods]) - plt.xticks(periods) + plt.xticks(periods, [str(int(p)) for p in periods]) plt.title(title) - lgd = plt.legend([h[0] for h in handles], techs, bbox_to_anchor=(1.2, 1), fontsize=7.5) - # plt.show() + lgd: Legend = plt.legend( + [h[0] for h in handles], techs, bbox_to_anchor=(1.2, 1), fontsize=7.5 + ) plt.savefig(self.output_file_name, bbox_extra_artists=(lgd,), bbox_inches='tight') + plt.close(fig) -# Function used for command line purposes. Parses arguments and then calls relevent functions. -def generate_plot(args): +def generate_plot(args: list[str]) -> None: + """Parses command line arguments and calls relevant functions.""" parser = argparse.ArgumentParser(description='Generate Output Plot') parser.add_argument( '-i', @@ -355,7 +336,7 @@ def generate_plot(args): '--scenario', action='store', dest='scenario', - help='Model run scenario name', + help='Model run a scenario name', required=True, ) parser.add_argument( @@ -392,31 +373,29 @@ def generate_plot(args): ) options = parser.parse_args(args) - - result = OutputPlotGenerator( + result_generator = OutputPlotGenerator( options.input, options.region, options.scenario, options.super_categories ) - error = '' + + error_path = '' if options.type == 'capacity': - error = result.generate_plot_for_capacity( + error_path = result_generator.generate_plot_for_capacity( options.sector, options.super_categories, options.output_dir ) elif options.type == 'flow': - error = result.generate_plot_for_output_flow( + error_path = result_generator.generate_plot_for_output_flow( options.sector, options.super_categories, options.output_dir ) elif options.type == 'emissions': - error = result.generate_plot_for_emissions( + error_path = result_generator.generate_plot_for_emissions( options.sector, options.super_categories, options.output_dir ) - if error == '': - print("Error: The sector doesn't exist for the selected plot type and database") + if not error_path: + print("Error: The sector doesn't exist for the selected plot type and database.") else: - print( - 'Done. Look for output plot images in directory:' - + os.path.join(options.output_dir, error) - ) + full_path = os.path.join(options.output_dir, os.path.dirname(error_path)) + print(f'Done. Look for output plot images in directory: {os.path.abspath(full_path)}') if __name__ == '__main__': diff --git a/temoa/model_checking/commodity_graph.py b/temoa/model_checking/commodity_graph.py index 5b3aeb22f..17c1eb716 100644 --- a/temoa/model_checking/commodity_graph.py +++ b/temoa/model_checking/commodity_graph.py @@ -3,13 +3,13 @@ import logging from collections import defaultdict from collections.abc import Iterable -from typing import Any +from typing import Any, cast import networkx as nx from temoa.core.config import TemoaConfig from temoa.model_checking.network_model_data import EdgeTuple, NetworkModelData -from temoa.types.core_types import Period, Region +from temoa.types.core_types import Commodity, Period, Region, Sector, Technology from temoa.utilities.graph_utils import ( calculate_initial_positions, calculate_tech_graph_positions, @@ -21,9 +21,9 @@ def generate_technology_graph( all_edges: Iterable[EdgeTuple], - source_commodities: set[str], - demand_commodities: set[str], - sector_colors: dict[str, str], + source_commodities: set[Commodity], + demand_commodities: set[Commodity], + sector_colors: dict[Sector, str], ) -> nx.MultiDiGraph[str]: """ Generates a technology-centric graph with a pre-computed initial layout. @@ -47,7 +47,7 @@ def generate_technology_graph( # Pass 2: Create a single, correctly styled node for each unique technology. for tech_name, info in tech_info.items(): - pos_attrs = tech_positions.get(tech_name, {}) + pos_attrs = tech_positions.get(cast(Technology, tech_name)) or {} sector = info['sector'] color_obj: dict[str, str] = {} @@ -108,7 +108,7 @@ def generate_commodity_graph( demand_orphans: Iterable[EdgeTuple], other_orphans: Iterable[EdgeTuple], driven_techs: Iterable[EdgeTuple], -) -> tuple[nx.MultiDiGraph[str], dict[str, str]]: +) -> tuple[nx.MultiDiGraph[str], dict[Sector, str]]: """ Generates the commodity-centric graph and its associated color scheme. In this view, commodities are nodes and technologies are grouped into edges. @@ -139,7 +139,7 @@ def generate_commodity_graph( } default_color = '#A9A9A9' - commodity_sector_counts: defaultdict[str, defaultdict[str, int]] = defaultdict( + commodity_sector_counts: defaultdict[Commodity, defaultdict[Sector, int]] = defaultdict( lambda: defaultdict(int) ) for tech in all_edge_tuples: @@ -147,7 +147,7 @@ def generate_commodity_graph( commodity_sector_counts[tech.input_comm][tech.sector] += 1 commodity_sector_counts[tech.output_comm][tech.sector] += 1 - commodity_to_primary_sector = { + commodity_to_primary_sector: dict[Commodity, Sector] = { comm: max(counts, key=lambda k: counts[k]) for comm, counts in commodity_sector_counts.items() if counts @@ -170,17 +170,18 @@ def generate_commodity_graph( # 3. Prepare edge attributes with sector-based coloring edge_attributes_map: dict[tuple[str, str, str, str | None], dict[str, Any]] = {} - all_connections: set[tuple[str, str, str, str | None]] = { - (tech.input_comm, tech.tech, tech.output_comm, tech.sector) for tech in all_edge_tuples + all_connections: set[tuple[Commodity, Technology, Commodity, Sector | None]] = { + (edge_tuple.input_comm, edge_tuple.tech, edge_tuple.output_comm, edge_tuple.sector) + for edge_tuple in all_edge_tuples } driven_names = {t.tech for t in driven_techs} other_orphan_names = {t.tech for t in other_orphans} demand_orphan_names = {t.tech for t in demand_orphans} - driven_commodities: set[str] = set() - other_orphan_commodities: set[str] = set() - demand_orphan_commodities: set[str] = set() + driven_commodities: set[Commodity] = set() + other_orphan_commodities: set[Commodity] = set() + demand_orphan_commodities: set[Commodity] = set() for ic, tech_name, oc, sector in all_connections: key = (ic, tech_name, oc, sector) @@ -289,7 +290,7 @@ def visualize_graph( output_filename=output_file, html_title=f'Network Graphs - {region} {period}', sectors=unique_sectors, - color_legend_map=sector_colors, + color_legend_map=cast(dict[str, str], sector_colors), style_legend_map=style_legend_map, show_browser=False, ) diff --git a/temoa/model_checking/commodity_network.py b/temoa/model_checking/commodity_network.py index ebe6c9ef8..b21d65bc1 100644 --- a/temoa/model_checking/commodity_network.py +++ b/temoa/model_checking/commodity_network.py @@ -25,6 +25,8 @@ # Represents a technology link: (input_commodity, tech_name) type TechLink = tuple[Commodity, Technology] +# Represents a pair of linked technologies: (driver_tech, driven_tech) +type LinkedTechPair = tuple[Technology, Technology] # Represents a full connection: (input_commodity, tech_name, output_commodity) type TechConnection = tuple[Commodity, Technology, Commodity] # Adjacency dict mapping: {output_comm: set of (input_comm, tech_name)} @@ -78,7 +80,7 @@ def __init__(self, region: Region, period: Period, model_data: NetworkModelData) self.tech_inputs: dict[Technology, set[Commodity]] = defaultdict(set) self.tech_outputs: dict[Technology, set[Commodity]] = defaultdict(set) self.connections: ForwardConnections = defaultdict(set) - self.viable_linked_tech: set[TechLink] = set() + self.viable_linked_tech: set[LinkedTechPair] = set() self._load_connections() self.prescreen_linked_tech() diff --git a/temoa/model_checking/commodity_network_manager.py b/temoa/model_checking/commodity_network_manager.py index 6253ddd69..11d065492 100644 --- a/temoa/model_checking/commodity_network_manager.py +++ b/temoa/model_checking/commodity_network_manager.py @@ -34,7 +34,7 @@ class CommodityNetworkManager: def __init__(self, periods: Iterable[str | int], network_data: NetworkModelData) -> None: self.analyzed: bool = False - self.periods: list[int] = sorted(map(int, periods)) + self.periods: list[Period] = sorted([Period(int(p)) for p in periods]) self.orig_data: NetworkModelData = network_data self.filtered_data: NetworkModelData | None = None self.regions: set[Region] | None = None diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index fd8242979..3721d09a6 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -13,14 +13,14 @@ from collections.abc import Callable from dataclasses import dataclass, field from itertools import chain -from typing import NamedTuple, Self, TypedDict, overload +from typing import NamedTuple, Self, TypedDict, cast, overload import deprecated from pyomo.core.base import ConcreteModel from temoa.core.model import TemoaModel from temoa.extensions.myopic.myopic_index import MyopicIndex -from temoa.types import Commodity, Period, Region, Technology, Vintage +from temoa.types import Commodity, Period, Region, Sector, Technology, Vintage from temoa.types.core_types import ParameterValue @@ -32,7 +32,7 @@ class EdgeTuple(NamedTuple): vintage: Vintage output_comm: Commodity lifetime: int | None = None - sector: str | None = None + sector: Sector | None = None class LinkedTechTuple(NamedTuple): @@ -240,7 +240,7 @@ def _fetch_all_tech_definitions( cur: sqlite3.Cursor, myopic_index: MyopicIndex | None ) -> list[ tuple[Region, Commodity, Technology, Vintage, Commodity, int] - | tuple[Region, Commodity, Technology, Vintage, Commodity, int, str] + | tuple[Region, Commodity, Technology, Vintage, Commodity, int, Sector] ]: """Fetches the main block of technology efficiency and lifetime data.""" default_lifetime = TemoaModel.default_lifetime_tech @@ -359,8 +359,11 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - living_techs.add(tech) if '-' in r and r.count('-') == 1: # Inter-regional transfer - r1, r2 = r.split('-', 1) - source_comm, dest_comm = f'{ic} ({r1})', f'{oc} ({r2})' + r1, r2 = (cast(Region, reg) for reg in r.split('-', 1)) + source_comm, dest_comm = ( + cast(Commodity, f'{ic} ({r1})'), + cast(Commodity, f'{oc} ({r2})'), + ) res.available_techs[r2, p].add( EdgeTuple( region=r2, @@ -427,35 +430,37 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - res.available_techs[r, p].add( EdgeTuple( region=r, - input_comm=tech, - tech='EndOfLife', + input_comm=cast(Commodity, tech), + tech=cast(Technology, 'EndOfLife'), vintage=v, output_comm=eol_oc, lifetime=lifetime, - sector='Other', + sector=cast(Sector, 'Other'), ) ) - res.source_commodities[r, p].add(tech) - res.capacity_commodities.add(tech) + res.source_commodities[r, p].add(cast(Commodity, tech)) + res.capacity_commodities.add(cast(Commodity, tech)) if eol_oc in basic_data['waste_commodities_all']: res.waste_commodities[r, p].add(eol_oc) # --- 3. Process Construction --- for r, ic, tech, v in lookup_data['construction']: - construction_lifetime = basic_data['period_length'].get(v, 1) - res.available_techs[r, v].add( + construction_lifetime = basic_data['period_length'].get(cast(Period, v), cast(Period, 1)) + res.available_techs[r, cast(Period, v)].add( EdgeTuple( region=r, input_comm=ic, - tech='Construction', + tech=cast(Technology, 'Construction'), vintage=v, - output_comm=tech, + output_comm=cast( + Commodity, tech + ), # commodity is kind of input to the capacity of the technology/vice versa lifetime=construction_lifetime, - sector='Other', + sector=cast(Sector, 'Other'), ) ) - res.demand_commodities[r, v].add(tech) - res.capacity_commodities.add(tech) + res.demand_commodities[r, cast(Period, v)].add(cast(Commodity, tech)) + res.capacity_commodities.add(cast(Commodity, tech)) living_techs.add(tech) # --- 4. Process Linked Techs and Other Metadata --- diff --git a/temoa/types/__init__.py b/temoa/types/__init__.py index 8ecfc80c5..6241d6a41 100644 --- a/temoa/types/__init__.py +++ b/temoa/types/__init__.py @@ -16,6 +16,7 @@ 'TechSet', 'TimeOfDay', 'Vintage', + 'Sector', # Dictionary types 'ActiveRegionsForTechDict', 'BaseloadVintagesDict', @@ -81,6 +82,7 @@ Region, RegionSet, Season, + Sector, SparseIndex, Technology, TechSet, diff --git a/temoa/types/core_types.py b/temoa/types/core_types.py index d0e8c19ae..bfb91037f 100644 --- a/temoa/types/core_types.py +++ b/temoa/types/core_types.py @@ -7,20 +7,18 @@ from collections.abc import Callable from dataclasses import dataclass, field -from typing import Any +from typing import Any, NewType # Core type aliases for commonly used dimensions -Region = str -Period = int -Technology = str -Sector = str -Vintage = int -Season = str -TimeOfDay = str -Commodity = str -InputCommodity = str -OutputCommodity = str -Process = str +Region = NewType('Region', str) +Period = NewType('Period', int) +Technology = NewType('Technology', str) +Sector = NewType('Sector', str) +Vintage = NewType('Vintage', int) +Season = NewType('Season', str) +TimeOfDay = NewType('TimeOfDay', str) +Commodity = NewType('Commodity', str) +Process = NewType('Process', str) # Type aliases for common data structures SparseIndex = ( diff --git a/temoa/utilities/graph_utils.py b/temoa/utilities/graph_utils.py index 37ec3718a..4975270fb 100644 --- a/temoa/utilities/graph_utils.py +++ b/temoa/utilities/graph_utils.py @@ -7,21 +7,36 @@ in vis.js converge to a cleaner and more readable state faster. """ +from __future__ import annotations + import json import logging import math import random import uuid -from collections.abc import Iterable -from typing import Any, TypeVar +from collections.abc import Iterable, Sequence +from typing import TYPE_CHECKING, Any, TypeVar, cast import networkx as nx from temoa.model_checking.network_model_data import EdgeTuple +from temoa.types.core_types import Commodity, Sector, Technology logger = logging.getLogger(__name__) -GraphType = TypeVar('GraphType', nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph) + +if TYPE_CHECKING: + GraphType = TypeVar( + 'GraphType', + nx.Graph[Commodity | Technology | str], + nx.DiGraph[Commodity | Technology | str], + nx.MultiGraph[Commodity | Technology | str], + nx.MultiDiGraph[Commodity | Technology | str], + ) +else: + # At runtime, use the base types which are not subscripted. + # The TypeVar still enforces that the graph type is one of these. + GraphType = TypeVar('GraphType', nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph) def convert_graph_to_json( @@ -129,8 +144,8 @@ def calculate_source_positions( def calculate_initial_positions( node_layer_map: dict[str, int], - commodity_to_primary_sector: dict[str, str], - unique_sectors: list[str], + commodity_to_primary_sector: dict[Commodity, Sector], + unique_sectors: Sequence[Sector] | None = None, ) -> dict[str, dict[str, Any]]: """ Calculates an initial (x, y) layout for all nodes to provide a better @@ -140,10 +155,10 @@ def calculate_initial_positions( - Other nodes are arranged in clusters based on their primary sector, with the clusters themselves arranged in a large circle. """ - positions = {} + positions: dict[str, dict[str, Any]] = {} # Prepare to lay out the remaining (non-fixed) nodes: all layers except 1 - nodes_to_place = {n for n, layer in node_layer_map.items() if layer != 1} + nodes_to_place = {cast(Commodity, n) for n, layer in node_layer_map.items() if layer != 1} if not nodes_to_place: return positions @@ -194,7 +209,7 @@ def calculate_initial_positions( def calculate_tech_graph_positions( all_edges: Iterable[EdgeTuple], -) -> dict[str, dict[str, Any]]: +) -> dict[Technology, dict[str, Any]]: """ Calculates an initial (x, y) layout for the technology graph. All technologies are arranged in clusters by sector, with clusters diff --git a/temoa/utilities/visualizer.py b/temoa/utilities/visualizer.py index 04da87dce..a30d10a49 100644 --- a/temoa/utilities/visualizer.py +++ b/temoa/utilities/visualizer.py @@ -10,17 +10,20 @@ This code is designed to replace previous graphing dependencies like `gravis`. """ +from __future__ import annotations + import copy import json import logging import uuid from collections import defaultdict -from collections.abc import Iterable +from collections.abc import Iterable, Sequence from pathlib import Path from typing import Any import networkx as nx +from temoa.types.core_types import Commodity, Sector, Technology from temoa.utilities.graph_utils import ( GraphType, convert_graph_to_json, @@ -41,23 +44,23 @@ def deep_merge_dicts(source: dict[str, Any], destination: dict[str, Any]) -> dic def make_nx_graph( - connections: Iterable[tuple[str, str, str, str | None]], - edge_attributes_map: dict[tuple, dict[str, Any]], + connections: Iterable[tuple[Commodity, Technology, Commodity, Sector | None]], + edge_attributes_map: dict[tuple[str, str, str, str | None], dict[str, Any]], node_layer_map: dict[str, int], node_positions: dict[str, dict[str, Any]], - commodity_to_primary_sector: dict[str, str], - driven_tech_names: set[str], - other_orphan_names: set[str], - demand_orphan_names: set[str], - driven_commodities: set[str], - other_orphan_commodities: set[str], - demand_orphan_commodities: set[str], -) -> nx.MultiDiGraph: + commodity_to_primary_sector: dict[Commodity, Sector], + driven_tech_names: set[Technology], + other_orphan_names: set[Technology], + demand_orphan_names: set[Technology], + driven_commodities: set[Commodity], + other_orphan_commodities: set[Commodity], + demand_orphan_commodities: set[Commodity], +) -> nx.MultiDiGraph[str]: """ Make an nx graph, grouping parallel edges to prevent label overlap. """ - dg = nx.MultiDiGraph() + dg: nx.MultiDiGraph[str] = nx.MultiDiGraph() connections = tuple(connections) # Freeze for multiple iterations node_styles_by_layer = { @@ -125,7 +128,7 @@ def make_nx_graph( dg.add_node(node_name, **node_attrs) # 2. Group technologies by their input/output commodity pair - grouped_edges = defaultdict(list) + grouped_edges: dict[tuple[Commodity, Commodity], list[dict[str, Any]]] = defaultdict(list) for ic, tech, oc, sector in connections: edge_key = (ic, tech, oc, sector) attrs = edge_attributes_map.get(edge_key, {}) @@ -133,7 +136,7 @@ def make_nx_graph( # 3. Create a single, combined edge for each group for (ic, oc), techs_info in grouped_edges.items(): - combined_attrs = {} + combined_attrs: dict[str, Any] = {} tech_names = [info['tech'] for info in techs_info] # Combine labels: Show up to 2 names, then "X techs" @@ -175,20 +178,20 @@ def make_nx_graph( combined_attrs['dashes'] = True combined_attrs['value'] = sum(info['attrs'].get('value', 1) for info in techs_info) - edge_key = f'{ic}-{oc}-{uuid.uuid4().hex[:8]}' - dg.add_edge(ic, oc, key=edge_key, **combined_attrs) + multi_edge_key = f'{ic}-{oc}-{uuid.uuid4().hex[:8]}' + dg.add_edge(ic, oc, key=multi_edge_key, **combined_attrs) return dg def nx_to_vis( nx_graph: GraphType, - output_filename: Path, # Changed to Path object for clarity + output_filename: Path, html_title: str = 'NetworkX to vis.js Graph', vis_options: dict[str, Any] | None = None, override_node_properties: dict[str, Any] | None = None, override_edge_properties: dict[str, Any] | None = None, - sectors: list[str] | None = None, + sectors: Sequence[Sector] | None = None, color_legend_map: dict[str, str] | None = None, style_legend_map: list[dict[str, Any]] | None = None, secondary_graph: GraphType | None = None, @@ -203,7 +206,8 @@ def nx_to_vis( nodes_data_primary, edges_data_primary = convert_graph_to_json( nx_graph, override_node_properties, override_edge_properties, 0 ) - nodes_data_secondary, edges_data_secondary = [], [] + nodes_data_secondary: list[dict[str, Any]] = [] + edges_data_secondary: list[dict[str, Any]] = [] if secondary_graph: nodes_data_secondary, edges_data_secondary = convert_graph_to_json( secondary_graph, override_node_properties, override_edge_properties, 0 From db3ef3733121f3e9af5483dbf76bb72ca71ff2ff Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Mon, 3 Nov 2025 13:50:47 -0500 Subject: [PATCH 307/587] relaxing test string to get it pass in CI --- tests/test_cli.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index 37e792339..1075bf794 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -111,8 +111,6 @@ def test_cli_run_missing_config(): result = runner.invoke(app, args) assert result.exit_code != 0 - cleaned_stderr = ' '.join(result.stderr.replace('│', '').split()) - assert ( - "Invalid value for 'CONFIG_FILE': File 'non_existent_file.toml' does not exist." - in cleaned_stderr - ) + # Check that the error mentions the missing file (more robust than exact string match) + assert 'non_existent_file.toml' in result.stderr + assert 'does not' in result.stderr and 'exist' in result.stderr From 869fcff90c5765fa8a69f1030d18ee7d0eeb2e44 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Mon, 3 Nov 2025 17:27:38 -0500 Subject: [PATCH 308/587] removing any config change persistance --- temoa/_internal/temoa_sequencer.py | 57 ++++++++++++++++++------------ temoa/cli.py | 2 +- tests/test_material_results.py | 12 +++---- 3 files changed, 41 insertions(+), 30 deletions(-) diff --git a/temoa/_internal/temoa_sequencer.py b/temoa/_internal/temoa_sequencer.py index d707c1387..6e8bf991b 100644 --- a/temoa/_internal/temoa_sequencer.py +++ b/temoa/_internal/temoa_sequencer.py @@ -84,29 +84,42 @@ def build_model(self) -> TemoaModel: """ self._run_preliminary_checks() logger.info('Starting model build process (build-only mode).') - # Ensure certain features that don't apply to a simple build are disabled - if self.config.source_trace: - self.config.source_trace = False - logger.warning('Source trace disabled for build-only mode.') - if self.config.plot_commodity_network: - self.config.plot_commodity_network = False - logger.warning('Commodity network plotting disabled for build-only mode.') - if self.config.price_check: - logger.warning('Price check disabled for build-only mode.') - - # Validate database before attempting to build model - if not check_database_version( - self.config, db_major_reqd=DB_MAJOR_VERSION, min_db_minor=MIN_DB_MINOR_VERSION - ): - raise RuntimeError('Database version check failed. See log file for details.') - with sqlite3.connect(self.config.input_database) as con: - hybrid_loader = HybridLoader(db_connection=con, config=self.config) - data_portal = hybrid_loader.load_data_portal(myopic_index=None) - instance = build_instance(data_portal, silent=self.config.silent) - - logger.info('Model build process complete.') - return instance + # Capture original values to restore later + original_source_trace = self.config.source_trace + original_plot_commodity_network = self.config.plot_commodity_network + original_price_check = self.config.price_check + + try: + # Ensure certain features that don't apply to a simple build are disabled + if self.config.source_trace: + self.config.source_trace = False + logger.warning('Source trace disabled for build-only mode.') + if self.config.plot_commodity_network: + self.config.plot_commodity_network = False + logger.warning('Commodity network plotting disabled for build-only mode.') + if self.config.price_check: + self.config.price_check = False + logger.warning('Price check disabled for build-only mode.') + + # Validate database before attempting to build model + if not check_database_version( + self.config, db_major_reqd=DB_MAJOR_VERSION, min_db_minor=MIN_DB_MINOR_VERSION + ): + raise RuntimeError('Database version check failed. See log file for details.') + + with sqlite3.connect(self.config.input_database) as con: + hybrid_loader = HybridLoader(db_connection=con, config=self.config) + data_portal = hybrid_loader.load_data_portal(myopic_index=None) + instance = build_instance(data_portal, silent=self.config.silent) + + logger.info('Model build process complete.') + return instance + finally: + # Restore original config values + self.config.source_trace = original_source_trace + self.config.plot_commodity_network = original_plot_commodity_network + self.config.price_check = original_price_check def start(self) -> None: """ diff --git a/temoa/cli.py b/temoa/cli.py index 5e730831c..eafa09bb0 100644 --- a/temoa/cli.py +++ b/temoa/cli.py @@ -222,7 +222,7 @@ def run( if not silent: rich.print(ts.config) typer.confirm('\nPlease confirm the settings above to continue', abort=True) - if build_only: + if build_only or ts.temoa_mode is TemoaMode.BUILD_ONLY: logger.info('Build-only mode selected. Calling build_model().') _ = ts.build_model() if not silent: diff --git a/tests/test_material_results.py b/tests/test_material_results.py index 8a5f1d3a8..e16454b2f 100644 --- a/tests/test_material_results.py +++ b/tests/test_material_results.py @@ -58,13 +58,11 @@ def test_flows(solved_connection): Test that the emissions from each technology archetype are correct, and check total emissions """ con, name, tech, period, flow_target = solved_connection - row = ( - con.cursor() - .execute( - f"SELECT SUM(flow) FROM main.OutputFlowOut WHERE tech == '{tech}' AND period == {period}" - ) - .fetchone() - ) + cursor = con.cursor() + row = cursor.execute( + 'SELECT SUM(flow) FROM main.OutputFlowOut WHERE tech = ? AND period = ?', + (tech, period), + ).fetchone() # If the query returns no rows, row will be None. If it finds rows but the sum is NULL, row[0] will be None. flow = row[0] if row and row[0] is not None else 0.0 From 5da6a5e6144276ca47829be9839bcc53ebf60261 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 4 Nov 2025 15:25:42 -0500 Subject: [PATCH 309/587] adding citation information --- temoa/cli.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/temoa/cli.py b/temoa/cli.py index eafa09bb0..b10c7fb66 100644 --- a/temoa/cli.py +++ b/temoa/cli.py @@ -6,6 +6,7 @@ import rich import typer from rich.logging import RichHandler +from rich.text import Text from definitions import set_OUTPUT_PATH from temoa._internal.temoa_sequencer import TemoaSequencer @@ -106,12 +107,25 @@ def _version_callback(value: bool) -> None: def _cite_callback(value: bool) -> None: if value: - citation_text = """ - [bold]How to Cite Temoa:[/bold] + citation_text = Text() + citation_text.append('[bold]How to Cite Temoa:[/bold]\n\n', style='bold') + citation_text.append( + 'If you use Temoa in your research, please cite the following publication:\n\n' + ) + + citation_text.append( + """Hunter, K., Sreepathi, S., & DeCarolis, J. F. (2013). """ + """Modeling for insight using Tools for Energy Model Optimization and Analysis (Temoa). """ + """Energy Economics, 40, 339–349. """ + """https://doi.org/10.1016/j.eneco.2013.07.014""", + style='italic', + ) + citation_text.append('\n\n') + citation_text.append( + 'You can also find citation information in the CITATION.cff file in the repository.', + style='dim', + ) - Please consult the project documentation or associated publications - for the most up-to-date citation information. - """ rich.print(citation_text) raise typer.Exit() From b2c98ff07a8b5f70fb58f21b3cf6a28037a56783 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 4 Nov 2025 15:28:35 -0500 Subject: [PATCH 310/587] adding citation information --- .gitignore | 1 + CITATION.cff | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 CITATION.cff diff --git a/.gitignore b/.gitignore index 221ddf110..5996f68b7 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ !.pre-commit-config.yaml !.coderabbit.yaml !FEATURE_BRANCH.md +!CITATION.cff # recursively re-ignore __pycache__ diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 000000000..277c7e49c --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,17 @@ +cff-version: 1.2.0 +message: "If you use this software, please cite it as below." +authors: + - family-name: "Hunter" + given-names: "Kevin" + - family-name: "Sreepathi" + given-names: "Sarat" + - family-name: "DeCarolis" + given-names: "Joseph F." +title: "Modeling for insight using Tools for Energy Model Optimization and Analysis (Temoa)" +journal: "Energy Economics" +volume: "40" +pages: "339-349" +year: 2013 +month: 11 # November +doi: "10.1016/j.eneco.2013.07.014" +url: "https://doi.org/10.1016/j.eneco.2013.07.014" From 84c1a3175d634d35f1646afe43da4756bba8587a Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 4 Nov 2025 16:22:06 -0500 Subject: [PATCH 311/587] final polish --- temoa/cli.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/temoa/cli.py b/temoa/cli.py index b10c7fb66..a69456e0f 100644 --- a/temoa/cli.py +++ b/temoa/cli.py @@ -70,7 +70,7 @@ def _setup_logging(output_path: Path, debug: bool = False, silent: bool = False) logging.getLogger('matplotlib').setLevel(logging.WARNING) # Log the initialization message (will go to file, and to console if not silent) - logger.info(f'Logging initialized. Log file at: {log_file}') + logger.info('Logging initialized. Log file at: %s', log_file) def _setup_sequencer( @@ -116,7 +116,7 @@ def _cite_callback(value: bool) -> None: citation_text.append( """Hunter, K., Sreepathi, S., & DeCarolis, J. F. (2013). """ """Modeling for insight using Tools for Energy Model Optimization and Analysis (Temoa). """ - """Energy Economics, 40, 339–349. """ + """Energy Economics, 40, 339-349. """ """https://doi.org/10.1016/j.eneco.2013.07.014""", style='italic', ) @@ -279,7 +279,6 @@ def main_options( ), ) -> None: """Manage global options for the Temoa CLI.""" - pass if __name__ == '__main__': From 2ff8570f91ef6e915a418c30427c605e94e96d51 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 7 Nov 2025 09:49:04 -0500 Subject: [PATCH 312/587] model pass 1 --- data_files/example_dbs/materials.sql | 820 ++++++++-------- data_files/example_dbs/morris_utopia.sql | 916 +++++++++--------- data_files/example_dbs/seasonal_storage.sql | 164 ++-- data_files/example_dbs/stepped_demand.sql | 412 ++++---- data_files/example_dbs/survival_curve.sql | 352 +++---- data_files/example_dbs/test_system.sql | 812 ++++++++-------- data_files/example_dbs/utopia.sql | 912 ++++++++--------- data_files/monte_carlo/run_settings_1.csv | 4 +- data_files/temoa_basics_0.sql | 16 +- data_files/temoa_basics_1.sql | 28 +- data_files/temoa_basics_2.sql | 60 +- docs/Database Upgrade and Troubleshooting.md | 24 +- docs/commodity network notes.md | 58 +- docs/source/Documentation.rst | 394 ++++---- docs/source/images/adjusted_capacity_plf.svg | 2 +- docs/source/images/coal_process.dot | 4 +- pyproject.toml | 4 +- temoa/_internal/exchange_tech_cost_ledger.py | 32 +- temoa/_internal/run_actions.py | 6 +- temoa/_internal/table_data_puller.py | 228 ++--- temoa/_internal/table_writer.py | 8 +- temoa/components/capacity.py | 245 ++--- temoa/components/commodities.py | 264 ++--- temoa/components/costs.py | 192 ++-- temoa/components/emissions.py | 58 +- temoa/components/flows.py | 122 +-- temoa/components/geography.py | 22 +- temoa/components/limits.py | 508 +++++----- temoa/components/operations.py | 182 ++-- temoa/components/reserves.py | 134 +-- temoa/components/storage.py | 156 +-- temoa/components/technology.py | 197 ++-- temoa/components/time.py | 126 +-- temoa/components/utils.py | 14 +- temoa/core/model.py | 802 ++++++++------- temoa/data_io/component_manifest.py | 190 ++-- temoa/data_io/hybrid_loader.py | 170 ++-- temoa/data_processing/database_util.py | 12 +- temoa/data_processing/db_to_excel.py | 8 +- temoa/extensions/breakeven/breakeven.py | 184 ++-- temoa/extensions/get_comm_tech.py | 32 +- .../extensions/method_of_morris/MM_README.md | 42 +- .../Method_of_Morris_README.txt | 16 +- temoa/extensions/method_of_morris/morris.py | 18 +- .../method_of_morris/morris_sequencer.py | 16 +- .../mga_sequencer.py | 4 +- .../tech_activity_vector_manager.py | 11 +- .../example_builds/scenario_maker.py | 11 +- .../extensions/myopic/make_myopic_tables.sql | 6 +- temoa/extensions/myopic/myopic table notes.md | 15 +- temoa/extensions/myopic/myopic_sequencer.py | 92 +- .../single_vector_mga/sv_mga_sequencer.py | 28 +- temoa/extensions/stochastics/VSS.py | 24 +- .../generate_scenario_tree-nonhomogenous.py | 39 +- .../stochastics/generate_scenario_tree.py | 37 +- .../legacy_files/scenariomodels.py | 4 +- .../extensions/stochastics/options/iew2012.py | 4 +- .../stochastics/options/utopia_coal_vs_nuc.py | 4 +- .../stochastics/stochastics_README.txt | 32 +- .../stochastics/temoa_stochastic.py | 15 +- temoa/model_checking/network_model_data.py | 34 +- temoa/model_checking/pricing_check.py | 32 +- temoa/model_checking/validators.py | 22 +- temoa/utilities/unit_cost_explorer.py | 86 +- tests/legacy_test_values.py | 16 +- tests/test_exchange_cost_ledger.py | 10 +- tests/test_full_runs.py | 4 +- tests/test_network_model_data.py | 44 +- tests/test_pricing_check.py | 20 +- tests/test_set_consistency.py | 2 +- tests/test_storage.py | 50 +- .../config_annualised_demand.toml | 18 +- tests/testing_configs/config_emissions.toml | 18 +- tests/testing_configs/config_link_test.toml | 18 +- tests/testing_configs/config_materials.toml | 18 +- tests/testing_configs/config_mediumville.toml | 18 +- .../config_seasonal_storage.toml | 18 +- .../testing_configs/config_storageville.toml | 18 +- .../config_survival_curve.toml | 16 +- tests/testing_configs/config_test_system.toml | 18 +- tests/testing_configs/config_utopia.toml | 18 +- .../testing_configs/config_utopia_myopic.toml | 16 +- .../US_9R_8D_legacy_set_sizes.json | 100 +- tests/testing_data/US_9R_8D_set_sizes.json | 88 +- tests/testing_data/annualised_demand.sql | 136 +-- tests/testing_data/emissions.sql | 158 +-- tests/testing_data/materials.sql | 820 ++++++++-------- tests/testing_data/mediumville.sql | 312 +++--- tests/testing_data/mediumville_sets.json | 142 +-- tests/testing_data/seasonal_storage.sql | 164 ++-- tests/testing_data/simple_linked_tech.sql | 122 +-- tests/testing_data/storageville.sql | 132 +-- tests/testing_data/survival_curve.sql | 352 +++---- tests/testing_data/test_system.sql | 812 ++++++++-------- tests/testing_data/test_system_sets.json | 142 +-- tests/testing_data/utopia.sql | 912 ++++++++--------- tests/testing_data/utopia_sets.json | 142 +-- 97 files changed, 7152 insertions(+), 7188 deletions(-) diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index d77376460..596efc87c 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -19,7 +19,7 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,'Discount Rate for future costs'); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -47,7 +47,7 @@ CREATE TABLE SectorLabel sector TEXT PRIMARY KEY, notes TEXT ); -CREATE TABLE CapacityCredit +CREATE TABLE capacity_credit ( region TEXT, period INTEGER @@ -60,7 +60,7 @@ CREATE TABLE CapacityCredit PRIMARY KEY (region, period, tech, vintage), CHECK (credit >= 0 AND credit <= 1) ); -CREATE TABLE CapacityFactorProcess +CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER @@ -77,7 +77,7 @@ CREATE TABLE CapacityFactorProcess PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE CapacityFactorTech +CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER @@ -93,102 +93,102 @@ CREATE TABLE CapacityFactorTech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'spring','overnight','SOL_PV',0.0,NULL); CREATE TABLE CapacityToActivity ( region TEXT, @@ -235,7 +235,7 @@ INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); INSERT INTO CommodityType VALUES('s','source commodity'); -CREATE TABLE ConstructionInput +CREATE TABLE construction_input ( region TEXT, input_comm TEXT @@ -249,19 +249,19 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -INSERT INTO ConstructionInput VALUES('RegionA','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionA','battery_lfp','CAR_PHEV',2000,0.1000000000000000055,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionA','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionA','battery_lfp','CAR_PHEV',2010,0.1000000000000000055,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionA','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionA','battery_lfp','CAR_PHEV',2020,0.1000000000000000055,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionB','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionB','battery_lfp','CAR_PHEV',2000,0.1000000000000000055,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionB','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionB','battery_lfp','CAR_PHEV',2010,0.1000000000000000055,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionB','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionB','battery_lfp','CAR_PHEV',2020,0.1000000000000000055,NULL,NULL); -CREATE TABLE CostEmission +INSERT INTO construction_input VALUES('RegionA','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO construction_input VALUES('RegionA','battery_lfp','CAR_PHEV',2000,0.1000000000000000055,NULL,NULL); +INSERT INTO construction_input VALUES('RegionA','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO construction_input VALUES('RegionA','battery_lfp','CAR_PHEV',2010,0.1000000000000000055,NULL,NULL); +INSERT INTO construction_input VALUES('RegionA','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO construction_input VALUES('RegionA','battery_lfp','CAR_PHEV',2020,0.1000000000000000055,NULL,NULL); +INSERT INTO construction_input VALUES('RegionB','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO construction_input VALUES('RegionB','battery_lfp','CAR_PHEV',2000,0.1000000000000000055,NULL,NULL); +INSERT INTO construction_input VALUES('RegionB','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO construction_input VALUES('RegionB','battery_lfp','CAR_PHEV',2010,0.1000000000000000055,NULL,NULL); +INSERT INTO construction_input VALUES('RegionB','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO construction_input VALUES('RegionB','battery_lfp','CAR_PHEV',2020,0.1000000000000000055,NULL,NULL); +CREATE TABLE cost_emission ( region TEXT, period INTEGER @@ -273,13 +273,13 @@ CREATE TABLE CostEmission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -INSERT INTO CostEmission VALUES('RegionA',2000,'co2e',1.0,NULL,NULL); -INSERT INTO CostEmission VALUES('RegionA',2010,'co2e',1.0,NULL,NULL); -INSERT INTO CostEmission VALUES('RegionA',2020,'co2e',1.0,NULL,NULL); -INSERT INTO CostEmission VALUES('RegionB',2000,'co2e',1.0,NULL,NULL); -INSERT INTO CostEmission VALUES('RegionB',2010,'co2e',1.0,NULL,NULL); -INSERT INTO CostEmission VALUES('RegionB',2020,'co2e',1.0,NULL,NULL); -CREATE TABLE CostFixed +INSERT INTO cost_emission VALUES('RegionA',2000,'co2e',1.0,NULL,NULL); +INSERT INTO cost_emission VALUES('RegionA',2010,'co2e',1.0,NULL,NULL); +INSERT INTO cost_emission VALUES('RegionA',2020,'co2e',1.0,NULL,NULL); +INSERT INTO cost_emission VALUES('RegionB',2000,'co2e',1.0,NULL,NULL); +INSERT INTO cost_emission VALUES('RegionB',2010,'co2e',1.0,NULL,NULL); +INSERT INTO cost_emission VALUES('RegionB',2020,'co2e',1.0,NULL,NULL); +CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -293,7 +293,7 @@ CREATE TABLE CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE CostInvest +CREATE TABLE cost_invest ( region TEXT, tech TEXT @@ -305,41 +305,41 @@ CREATE TABLE CostInvest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO CostInvest VALUES('RegionA','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','CAR_PHEV',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','CAR_PHEV',2010,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','CAR_PHEV',2020,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','CAR_ICE',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','CAR_ICE',2010,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','CAR_ICE',2020,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','RECYCLE_NMC',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','RECYCLE_LFP',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','MANUFAC_NMC',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','MANUFAC_LFP',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','BATT_GRID',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','SOL_PV',2000,10.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','GEN_DSL',2000,2.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','CAR_PHEV',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','CAR_PHEV',2010,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','CAR_PHEV',2020,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','CAR_ICE',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','CAR_ICE',2010,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','CAR_ICE',2020,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','RECYCLE_NMC',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','RECYCLE_LFP',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','MANUFAC_NMC',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','MANUFAC_LFP',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','BATT_GRID',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','GEN_DSL',2000,2.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA-RegionB','ELEC_INTERTIE',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB-RegionA','ELEC_INTERTIE',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','SOL_PV',2000,1.0,NULL,NULL); -CREATE TABLE CostVariable +INSERT INTO cost_invest VALUES('RegionA','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','CAR_PHEV',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','CAR_PHEV',2010,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','CAR_PHEV',2020,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','CAR_ICE',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','CAR_ICE',2010,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','CAR_ICE',2020,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','RECYCLE_NMC',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','RECYCLE_LFP',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','MANUFAC_NMC',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','MANUFAC_LFP',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','BATT_GRID',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','SOL_PV',2000,10.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','GEN_DSL',2000,2.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','CAR_PHEV',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','CAR_PHEV',2010,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','CAR_PHEV',2020,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','CAR_ICE',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','CAR_ICE',2010,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','CAR_ICE',2020,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','RECYCLE_NMC',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','RECYCLE_LFP',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','MANUFAC_NMC',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','MANUFAC_LFP',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','BATT_GRID',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','GEN_DSL',2000,2.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA-RegionB','ELEC_INTERTIE',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB-RegionA','ELEC_INTERTIE',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','SOL_PV',2000,1.0,NULL,NULL); +CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -353,42 +353,42 @@ CREATE TABLE CostVariable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostVariable VALUES('RegionA',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2000,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2010,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2020,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2000,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2010,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2020,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2000,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2010,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2020,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2000,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2010,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2020,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2000,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2010,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2020,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2000,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2010,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2020,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2000,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2010,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2020,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2000,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2010,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2020,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2000,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2010,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2020,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2000,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2010,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2020,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2000,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2010,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2020,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2000,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2010,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2020,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2000,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2010,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2020,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2000,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2010,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2020,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2000,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2010,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2020,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2000,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2010,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2020,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); CREATE TABLE Demand ( region TEXT, @@ -525,7 +525,7 @@ INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'summer','overnight INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','overnight','heating',0.1199999999999999956,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','overnight','heating',0.1600000000000000033,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'spring','overnight','heating',0.0,NULL); -CREATE TABLE EndOfLifeOutput +CREATE TABLE end_of_life_output ( region TEXT, tech TEXT @@ -539,37 +539,37 @@ CREATE TABLE EndOfLifeOutput notes TEXT, PRIMARY KEY (region, tech, vintage, output_comm) ); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',1990,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2000,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2010,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',1990,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2000,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2010,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); -CREATE TABLE Efficiency +INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',1990,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',2000,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',2010,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',1990,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',2000,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',2010,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); +CREATE TABLE efficiency ( region TEXT, input_comm TEXT @@ -585,85 +585,85 @@ CREATE TABLE Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO Efficiency VALUES('RegionA','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2000000000000000111,NULL); -INSERT INTO Efficiency VALUES('RegionA','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2000000000000000111,NULL); -INSERT INTO Efficiency VALUES('RegionA','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','electricity','RECYCLE_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); -INSERT INTO Efficiency VALUES('RegionA','electricity','RECYCLE_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); -INSERT INTO Efficiency VALUES('RegionA','electricity','MANUFAC_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); -INSERT INTO Efficiency VALUES('RegionA','electricity','MANUFAC_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); -INSERT INTO Efficiency VALUES('RegionA','diesel','GEN_DSL',2000,'electricity',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','ethos','SOL_PV',2000,'electricity',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','electricity','BATT_GRID',2000,'electricity',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','diesel','FURNACE',2000,'heating',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','electricity','HEATPUMP',2000,'heating',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2000000000000000111,NULL); -INSERT INTO Efficiency VALUES('RegionB','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2000000000000000111,NULL); -INSERT INTO Efficiency VALUES('RegionB','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','electricity','RECYCLE_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); -INSERT INTO Efficiency VALUES('RegionB','electricity','RECYCLE_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); -INSERT INTO Efficiency VALUES('RegionB','electricity','MANUFAC_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); -INSERT INTO Efficiency VALUES('RegionB','electricity','MANUFAC_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); -INSERT INTO Efficiency VALUES('RegionB','diesel','GEN_DSL',2000,'electricity',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','ethos','SOL_PV',2000,'electricity',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','electricity','BATT_GRID',2000,'electricity',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','diesel','FURNACE',2000,'heating',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','electricity','HEATPUMP',2000,'heating',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA-RegionB','electricity','ELEC_INTERTIE',2000,'electricity',0.9000000000000000222,NULL); -INSERT INTO Efficiency VALUES('RegionB-RegionA','electricity','ELEC_INTERTIE',2000,'electricity',0.9000000000000000222,NULL); -CREATE TABLE EfficiencyVariable +INSERT INTO efficiency VALUES('RegionA','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2000000000000000111,NULL); +INSERT INTO efficiency VALUES('RegionA','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2000000000000000111,NULL); +INSERT INTO efficiency VALUES('RegionA','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','electricity','RECYCLE_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('RegionA','electricity','RECYCLE_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('RegionA','electricity','MANUFAC_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('RegionA','electricity','MANUFAC_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('RegionA','diesel','GEN_DSL',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','ethos','SOL_PV',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','electricity','BATT_GRID',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','diesel','FURNACE',2000,'heating',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','electricity','HEATPUMP',2000,'heating',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2000000000000000111,NULL); +INSERT INTO efficiency VALUES('RegionB','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2000000000000000111,NULL); +INSERT INTO efficiency VALUES('RegionB','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','electricity','RECYCLE_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('RegionB','electricity','RECYCLE_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('RegionB','electricity','MANUFAC_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('RegionB','electricity','MANUFAC_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('RegionB','diesel','GEN_DSL',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','ethos','SOL_PV',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','electricity','BATT_GRID',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','diesel','FURNACE',2000,'heating',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','electricity','HEATPUMP',2000,'heating',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA-RegionB','electricity','ELEC_INTERTIE',2000,'electricity',0.9000000000000000222,NULL); +INSERT INTO efficiency VALUES('RegionB-RegionA','electricity','ELEC_INTERTIE',2000,'electricity',0.9000000000000000222,NULL); +CREATE TABLE efficiency_variable ( region TEXT, period INTEGER @@ -685,7 +685,7 @@ CREATE TABLE EfficiencyVariable PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -CREATE TABLE EmissionActivity +CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT @@ -703,9 +703,9 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('RegionA','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); -INSERT INTO EmissionActivity VALUES('RegionB','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); -CREATE TABLE EmissionEmbodied +INSERT INTO emission_activity VALUES('RegionA','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); +INSERT INTO emission_activity VALUES('RegionB','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); +CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT @@ -719,7 +719,7 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE EmissionEndOfLife +CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT @@ -733,7 +733,7 @@ CREATE TABLE EmissionEndOfLife notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE ExistingCapacity +CREATE TABLE existing_capacity ( region TEXT, tech TEXT @@ -745,19 +745,19 @@ CREATE TABLE ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO ExistingCapacity VALUES('RegionA','CAR_BEV',1990,1.0,NULL,NULL); -INSERT INTO ExistingCapacity VALUES('RegionA','CAR_PHEV',1990,1.0,NULL,NULL); -INSERT INTO ExistingCapacity VALUES('RegionA','CAR_ICE',1990,1.0,NULL,NULL); -INSERT INTO ExistingCapacity VALUES('RegionB','CAR_BEV',1990,1.0,NULL,NULL); -INSERT INTO ExistingCapacity VALUES('RegionB','CAR_PHEV',1990,1.0,NULL,NULL); -INSERT INTO ExistingCapacity VALUES('RegionB','CAR_ICE',1990,1.0,NULL,NULL); +INSERT INTO existing_capacity VALUES('RegionA','CAR_BEV',1990,1.0,NULL,NULL); +INSERT INTO existing_capacity VALUES('RegionA','CAR_PHEV',1990,1.0,NULL,NULL); +INSERT INTO existing_capacity VALUES('RegionA','CAR_ICE',1990,1.0,NULL,NULL); +INSERT INTO existing_capacity VALUES('RegionB','CAR_BEV',1990,1.0,NULL,NULL); +INSERT INTO existing_capacity VALUES('RegionB','CAR_PHEV',1990,1.0,NULL,NULL); +INSERT INTO existing_capacity VALUES('RegionB','CAR_ICE',1990,1.0,NULL,NULL); CREATE TABLE TechGroup ( group_name TEXT PRIMARY KEY, notes TEXT ); -CREATE TABLE LoanLifetimeProcess +CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT @@ -768,7 +768,7 @@ CREATE TABLE LoanLifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LoanRate +CREATE TABLE loan_rate ( region TEXT, tech TEXT @@ -779,7 +779,7 @@ CREATE TABLE LoanRate notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeProcess +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -790,7 +790,7 @@ CREATE TABLE LifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeTech +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT @@ -799,12 +799,12 @@ CREATE TABLE LifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO LifetimeTech VALUES('RegionA','CAR_BEV',10.0,NULL); -INSERT INTO LifetimeTech VALUES('RegionA','CAR_PHEV',10.0,NULL); -INSERT INTO LifetimeTech VALUES('RegionA','CAR_ICE',10.0,NULL); -INSERT INTO LifetimeTech VALUES('RegionB','CAR_BEV',10.0,NULL); -INSERT INTO LifetimeTech VALUES('RegionB','CAR_PHEV',10.0,NULL); -INSERT INTO LifetimeTech VALUES('RegionB','CAR_ICE',10.0,NULL); +INSERT INTO lifetime_tech VALUES('RegionA','CAR_BEV',10.0,NULL); +INSERT INTO lifetime_tech VALUES('RegionA','CAR_PHEV',10.0,NULL); +INSERT INTO lifetime_tech VALUES('RegionA','CAR_ICE',10.0,NULL); +INSERT INTO lifetime_tech VALUES('RegionB','CAR_BEV',10.0,NULL); +INSERT INTO lifetime_tech VALUES('RegionB','CAR_PHEV',10.0,NULL); +INSERT INTO lifetime_tech VALUES('RegionB','CAR_ICE',10.0,NULL); CREATE TABLE Operator ( operator TEXT PRIMARY KEY, @@ -813,7 +813,7 @@ CREATE TABLE Operator INSERT INTO Operator VALUES('e','equal to'); INSERT INTO Operator VALUES('le','less than or equal to'); INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE LimitGrowthCapacity +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, @@ -825,7 +825,7 @@ CREATE TABLE LimitGrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthCapacity +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, @@ -837,7 +837,7 @@ CREATE TABLE LimitDegrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacity +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -849,7 +849,7 @@ CREATE TABLE LimitGrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -861,7 +861,7 @@ CREATE TABLE LimitDegrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacityDelta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -873,7 +873,7 @@ CREATE TABLE LimitGrowthNewCapacityDelta notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacityDelta +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -904,7 +904,7 @@ CREATE TABLE LimitStorageLevelFraction notes TEXT, PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE LimitActivity +CREATE TABLE limit_activity ( region TEXT, period INTEGER @@ -917,7 +917,7 @@ CREATE TABLE LimitActivity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitActivityShare +CREATE TABLE limit_activity_share ( region TEXT, period INTEGER @@ -930,7 +930,7 @@ CREATE TABLE LimitActivityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitAnnualCapacityFactor +CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER @@ -946,7 +946,7 @@ CREATE TABLE LimitAnnualCapacityFactor PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE LimitCapacity +CREATE TABLE limit_capacity ( region TEXT, period INTEGER @@ -959,7 +959,7 @@ CREATE TABLE LimitCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitCapacityShare +CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER @@ -972,7 +972,7 @@ CREATE TABLE LimitCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitNewCapacity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER @@ -985,7 +985,7 @@ CREATE TABLE LimitNewCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitNewCapacityShare +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -998,7 +998,7 @@ CREATE TABLE LimitNewCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitResource +CREATE TABLE limit_resource ( region TEXT, tech_or_group TEXT, @@ -1009,7 +1009,7 @@ CREATE TABLE LimitResource notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitSeasonalCapacityFactor +CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES Region (region), @@ -1025,7 +1025,7 @@ CREATE TABLE LimitSeasonalCapacityFactor notes TEXT, PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE LimitTechInputSplit +CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER @@ -1040,7 +1040,7 @@ CREATE TABLE LimitTechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechInputSplitAnnual +CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER @@ -1055,61 +1055,61 @@ CREATE TABLE LimitTechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'diesel','CAR_PHEV','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'diesel','CAR_PHEV','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'diesel','CAR_PHEV','le',0.8000000000000000444,NULL); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'diesel','CAR_PHEV','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'diesel','CAR_PHEV','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'diesel','CAR_PHEV','le',0.8000000000000000444,NULL); -CREATE TABLE LimitTechOutputSplit +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'diesel','CAR_PHEV','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'diesel','CAR_PHEV','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'diesel','CAR_PHEV','le',0.8000000000000000444,NULL); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'diesel','CAR_PHEV','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'diesel','CAR_PHEV','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'diesel','CAR_PHEV','le',0.8000000000000000444,NULL); +CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER @@ -1124,7 +1124,7 @@ CREATE TABLE LimitTechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitTechOutputSplitAnnual +CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER @@ -1139,7 +1139,7 @@ CREATE TABLE LimitTechOutputSplitAnnual notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitEmission +CREATE TABLE limit_emission ( region TEXT, period INTEGER @@ -1296,7 +1296,7 @@ CREATE TABLE OutputStorageLevel level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); -CREATE TABLE PlanningReserveMargin +CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY @@ -1304,7 +1304,7 @@ CREATE TABLE PlanningReserveMargin margin REAL, notes TEXT ); -CREATE TABLE RampDownHourly +CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT @@ -1313,7 +1313,7 @@ CREATE TABLE RampDownHourly notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUpHourly +CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT @@ -1330,7 +1330,7 @@ CREATE TABLE Region ); INSERT INTO Region VALUES('RegionA',NULL); INSERT INTO Region VALUES('RegionB',NULL); -CREATE TABLE ReserveCapacityDerate +CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER @@ -1346,7 +1346,7 @@ CREATE TABLE ReserveCapacityDerate CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE TimeSegmentFraction -( +( period INTEGER REFERENCES TimePeriod (period), season TEXT @@ -1406,7 +1406,7 @@ INSERT INTO TimeSegmentFraction VALUES(2020,'summer','overnight',0.0625,NULL); INSERT INTO TimeSegmentFraction VALUES(2020,'autumn','overnight',0.0625,NULL); INSERT INTO TimeSegmentFraction VALUES(2020,'winter','overnight',0.0625,NULL); INSERT INTO TimeSegmentFraction VALUES(2020,'spring','overnight',0.0625,NULL); -CREATE TABLE StorageDuration +CREATE TABLE storage_duration ( region TEXT, tech TEXT, @@ -1414,9 +1414,9 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO StorageDuration VALUES('RegionA','BATT_GRID',2.0,'2 hours energy storage'); -INSERT INTO StorageDuration VALUES('RegionB','BATT_GRID',2.0,'2 hours energy storage'); -CREATE TABLE LifetimeSurvivalCurve +INSERT INTO storage_duration VALUES('RegionA','BATT_GRID',2.0,'2 hours energy storage'); +INSERT INTO storage_duration VALUES('RegionB','BATT_GRID',2.0,'2 hours energy storage'); +CREATE TABLE lifetime_survival_curve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -1482,7 +1482,7 @@ INSERT INTO TimeSeason VALUES(2020,9,'summer',NULL); INSERT INTO TimeSeason VALUES(2020,10,'autumn',NULL); INSERT INTO TimeSeason VALUES(2020,11,'winter',NULL); INSERT INTO TimeSeason VALUES(2020,12,'spring',NULL); -CREATE TABLE TimeSeasonSequential +CREATE TABLE time_season_sequential ( period INTEGER REFERENCES TimePeriod (period), diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index eba96479a..c695e6b7b 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -19,7 +19,7 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); CREATE TABLE OutputDualVariable ( @@ -53,7 +53,7 @@ INSERT INTO SectorLabel VALUES('transport',NULL); INSERT INTO SectorLabel VALUES('commercial',NULL); INSERT INTO SectorLabel VALUES('residential',NULL); INSERT INTO SectorLabel VALUES('industrial',NULL); -CREATE TABLE CapacityCredit +CREATE TABLE capacity_credit ( region TEXT, period INTEGER @@ -66,7 +66,7 @@ CREATE TABLE CapacityCredit PRIMARY KEY (region, period, tech, vintage), CHECK (credit >= 0 AND credit <= 1) ); -CREATE TABLE CapacityFactorProcess +CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER @@ -83,25 +83,25 @@ CREATE TABLE CapacityFactorProcess PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2010,0.2756000000000000116,''); -CREATE TABLE CapacityFactorTech +INSERT INTO capacity_factor_process VALUES('utopia',2000,'inter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2000,'inter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2000,'winter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2000,'winter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2000,'summer','day','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2000,'summer','night','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','day','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','night','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','day','E31',2010,0.2756000000000000116,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','night','E31',2010,0.2756000000000000116,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','day','E31',2010,0.2756000000000000116,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','night','E31',2010,0.2756000000000000116,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','day','E31',2010,0.2756000000000000116,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','night','E31',2010,0.2756000000000000116,''); +CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER @@ -117,96 +117,96 @@ CREATE TABLE CapacityFactorTech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E70',0.8000000000000000444,''); CREATE TABLE CapacityToActivity ( region TEXT, @@ -264,7 +264,7 @@ INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); -CREATE TABLE ConstructionInput +CREATE TABLE construction_input ( region TEXT, input_comm TEXT @@ -278,7 +278,7 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -CREATE TABLE CostEmission +CREATE TABLE cost_emission ( region TEXT, period INTEGER @@ -290,9 +290,9 @@ CREATE TABLE CostEmission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -INSERT INTO CostEmission VALUES('utopia',2000,'nox',5.0,NULL,NULL); -INSERT INTO CostEmission VALUES('utopia',2010,'co2',6.0,NULL,NULL); -CREATE TABLE CostFixed +INSERT INTO cost_emission VALUES('utopia',2000,'nox',5.0,NULL,NULL); +INSERT INTO cost_emission VALUES('utopia',2010,'co2',6.0,NULL,NULL); +CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -306,89 +306,89 @@ CREATE TABLE CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostFixed VALUES('utopia',1990,'E01',1960,40.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E01',1970,40.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E01',1980,40.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E01',1990,40.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E01',1970,70.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E01',1980,70.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E01',1990,70.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E01',2000,70.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E01',1980,100.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E01',1990,100.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E01',2000,100.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E01',2010,100.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E21',1990,500.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E21',1990,500.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E21',1990,500.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E21',2000,500.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E21',2000,500.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E21',2010,500.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E31',1980,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E31',1990,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E31',1980,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E31',1990,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E31',2000,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E31',1980,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E31',1990,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E31',2000,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E31',2010,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E51',1980,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E51',1990,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E51',1980,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E51',1990,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E51',2000,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E51',1980,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E51',1990,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E51',2000,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E51',2010,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E70',1960,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E70',1970,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E70',1980,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E70',1990,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E70',1970,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E70',1980,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E70',1990,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E70',2000,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E70',1980,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E70',1990,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E70',2000,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E70',2010,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RHO',1970,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RHO',1980,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RHO',1990,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'RHO',1980,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'RHO',1990,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'RHO',2000,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'RHO',1990,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'RHO',2000,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'RHO',2010,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1980,9.46000000000000086,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1990,9.46000000000000086,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'RL1',2000,9.46000000000000086,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'RL1',2010,9.46000000000000086,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1970,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1980,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1990,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXD',1980,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXD',1990,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXD',2000,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'TXD',2000,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'TXD',2010,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'TXE',1990,100.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXE',1990,90.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXE',2000,90.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'TXE',2000,80.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'TXE',2010,80.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'TXG',1970,48.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'TXG',1980,48.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'TXG',1990,48.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXG',1980,48.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXG',1990,48.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXG',2000,48.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'TXG',2000,48.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'TXG',2010,48.0,'',''); -CREATE TABLE CostInvest +INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1960,40.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1970,40.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1980,40.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1990,40.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E01',1970,70.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E01',1980,70.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E01',1990,70.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E01',2000,70.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E01',1980,100.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E01',1990,100.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E01',2000,100.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E01',2010,100.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E21',1990,500.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E21',1990,500.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E21',1990,500.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E21',2000,500.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E21',2000,500.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E21',2010,500.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E31',1980,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E31',1990,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E31',1980,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E31',1990,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E31',2000,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E31',1980,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E31',1990,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E31',2000,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E31',2010,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E51',1980,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E51',1990,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E51',1980,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E51',1990,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E51',2000,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E51',1980,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E51',1990,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E51',2000,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E51',2010,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1960,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1970,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1980,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1990,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E70',1970,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E70',1980,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E70',1990,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E70',2000,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E70',1980,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E70',1990,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E70',2000,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E70',2010,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'RHO',1970,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'RHO',1980,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'RHO',1990,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'RHO',1980,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'RHO',1990,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'RHO',2000,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'RHO',1990,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'RHO',2000,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'RHO',2010,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'RL1',1980,9.46000000000000086,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'RL1',1990,9.46000000000000086,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'RL1',2000,9.46000000000000086,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'RL1',2010,9.46000000000000086,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'TXD',1970,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'TXD',1980,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'TXD',1990,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXD',1980,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXD',1990,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXD',2000,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'TXD',2000,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'TXD',2010,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'TXE',1990,100.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXE',1990,90.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXE',2000,90.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'TXE',2000,80.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'TXE',2010,80.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'TXG',1970,48.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'TXG',1980,48.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'TXG',1990,48.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXG',1980,48.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXG',1990,48.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXG',2000,48.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'TXG',2000,48.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'TXG',2010,48.0,'',''); +CREATE TABLE cost_invest ( region TEXT, tech TEXT @@ -401,40 +401,40 @@ CREATE TABLE CostInvest MMAnalysis TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO CostInvest VALUES('utopia','E01',1990,2000.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E01',2000,1300.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E01',2010,1200.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E21',1990,5000.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E21',2000,5000.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E21',2010,5000.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E31',1990,3000.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E31',2000,3000.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E31',2010,3000.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E51',1990,900.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E51',2000,900.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E51',2010,900.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E70',1990,1000.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E70',2000,1000.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','E70',2010,1000.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','RHE',1990,90.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','RHE',2000,90.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','RHE',2010,90.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','RHO',1990,100.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','RHO',2000,100.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','RHO',2010,100.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','SRE',1990,100.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','SRE',2000,100.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','SRE',2010,100.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','TXD',1990,1044.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','TXD',2000,1044.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','TXD',2010,1044.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','TXE',1990,2000.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','TXE',2000,1750.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','TXE',2010,1500.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','TXG',1990,1044.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','TXG',2000,1044.0,'','',NULL); -INSERT INTO CostInvest VALUES('utopia','TXG',2010,1044.0,'','',NULL); -CREATE TABLE CostVariable +INSERT INTO cost_invest VALUES('utopia','E01',1990,2000.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','E01',2000,1300.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','E01',2010,1200.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','E21',1990,5000.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','E21',2000,5000.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','E21',2010,5000.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','E31',1990,3000.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','E31',2000,3000.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','E31',2010,3000.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','E51',1990,900.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','E51',2000,900.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','E51',2010,900.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','E70',1990,1000.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','E70',2000,1000.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','E70',2010,1000.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','RHE',1990,90.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','RHE',2000,90.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','RHE',2010,90.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','RHO',1990,100.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','RHO',2000,100.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','RHO',2010,100.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','SRE',1990,100.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','SRE',2000,100.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','SRE',2010,100.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','TXD',1990,1044.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','TXD',2000,1044.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','TXD',2010,1044.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','TXE',1990,2000.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','TXE',2000,1750.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','TXE',2010,1500.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','TXG',1990,1044.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','TXG',2000,1044.0,'','',NULL); +INSERT INTO cost_invest VALUES('utopia','TXG',2010,1044.0,'','',NULL); +CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -449,57 +449,57 @@ CREATE TABLE CostVariable MMAnalysis TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostVariable VALUES('utopia',1990,'IMPDSL1',1990,10.0,'','','OIL_COST'); -INSERT INTO CostVariable VALUES('utopia',2000,'IMPDSL1',1990,10.0,'','','OIL_COST'); -INSERT INTO CostVariable VALUES('utopia',2010,'IMPDSL1',1990,10.0,'','','OIL_COST'); -INSERT INTO CostVariable VALUES('utopia',1990,'IMPGSL1',1990,15.0,'','','OIL_COST'); -INSERT INTO CostVariable VALUES('utopia',2000,'IMPGSL1',1990,15.0,'','','OIL_COST'); -INSERT INTO CostVariable VALUES('utopia',2010,'IMPGSL1',1990,15.0,'','','OIL_COST'); -INSERT INTO CostVariable VALUES('utopia',1990,'IMPHCO1',1990,2.0,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'IMPHCO1',1990,2.0,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'IMPHCO1',1990,2.0,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'IMPOIL1',1990,8.0,'','','OIL_COST'); -INSERT INTO CostVariable VALUES('utopia',2000,'IMPOIL1',1990,8.0,'','','OIL_COST'); -INSERT INTO CostVariable VALUES('utopia',2010,'IMPOIL1',1990,8.0,'','','OIL_COST'); -INSERT INTO CostVariable VALUES('utopia',1990,'IMPURN1',1990,2.0,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'IMPURN1',1990,2.0,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'IMPURN1',1990,2.0,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1960,0.2999999999999999889,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1970,0.2999999999999999889,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1980,0.2999999999999999889,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1990,0.2999999999999999889,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1970,0.2999999999999999889,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1980,0.2999999999999999889,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1990,0.2999999999999999889,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',2000,0.2999999999999999889,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',1980,0.2999999999999999889,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',1990,0.2999999999999999889,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',2000,0.2999999999999999889,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',2010,0.2999999999999999889,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E21',1990,1.5,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E21',1990,1.5,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E21',1990,1.5,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E21',2000,1.5,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E21',2000,1.5,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E21',2010,1.5,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1960,0.4000000000000000222,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1970,0.4000000000000000222,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1980,0.4000000000000000222,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1990,0.4000000000000000222,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1970,0.4000000000000000222,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1980,0.4000000000000000222,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1990,0.4000000000000000222,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',2000,0.4000000000000000222,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',1980,0.4000000000000000222,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',1990,0.4000000000000000222,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',2000,0.4000000000000000222,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',2010,0.4000000000000000222,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',1990,'SRE',1990,10.0,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'SRE',1990,10.0,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2000,'SRE',2000,10.0,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'SRE',1990,10.0,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'SRE',2000,10.0,'','',NULL); -INSERT INTO CostVariable VALUES('utopia',2010,'SRE',2010,10.0,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',1990,'IMPDSL1',1990,10.0,'','','OIL_COST'); +INSERT INTO cost_variable VALUES('utopia',2000,'IMPDSL1',1990,10.0,'','','OIL_COST'); +INSERT INTO cost_variable VALUES('utopia',2010,'IMPDSL1',1990,10.0,'','','OIL_COST'); +INSERT INTO cost_variable VALUES('utopia',1990,'IMPGSL1',1990,15.0,'','','OIL_COST'); +INSERT INTO cost_variable VALUES('utopia',2000,'IMPGSL1',1990,15.0,'','','OIL_COST'); +INSERT INTO cost_variable VALUES('utopia',2010,'IMPGSL1',1990,15.0,'','','OIL_COST'); +INSERT INTO cost_variable VALUES('utopia',1990,'IMPHCO1',1990,2.0,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2000,'IMPHCO1',1990,2.0,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2010,'IMPHCO1',1990,2.0,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',1990,'IMPOIL1',1990,8.0,'','','OIL_COST'); +INSERT INTO cost_variable VALUES('utopia',2000,'IMPOIL1',1990,8.0,'','','OIL_COST'); +INSERT INTO cost_variable VALUES('utopia',2010,'IMPOIL1',1990,8.0,'','','OIL_COST'); +INSERT INTO cost_variable VALUES('utopia',1990,'IMPURN1',1990,2.0,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2000,'IMPURN1',1990,2.0,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2010,'IMPURN1',1990,2.0,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',1990,'E01',1960,0.2999999999999999889,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',1990,'E01',1970,0.2999999999999999889,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',1990,'E01',1980,0.2999999999999999889,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',1990,'E01',1990,0.2999999999999999889,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2000,'E01',1970,0.2999999999999999889,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2000,'E01',1980,0.2999999999999999889,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2000,'E01',1990,0.2999999999999999889,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2000,'E01',2000,0.2999999999999999889,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2010,'E01',1980,0.2999999999999999889,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2010,'E01',1990,0.2999999999999999889,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2010,'E01',2000,0.2999999999999999889,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2010,'E01',2010,0.2999999999999999889,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',1990,'E21',1990,1.5,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2000,'E21',1990,1.5,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2010,'E21',1990,1.5,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2000,'E21',2000,1.5,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2010,'E21',2000,1.5,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2010,'E21',2010,1.5,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',1990,'E70',1960,0.4000000000000000222,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',1990,'E70',1970,0.4000000000000000222,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',1990,'E70',1980,0.4000000000000000222,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',1990,'E70',1990,0.4000000000000000222,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2000,'E70',1970,0.4000000000000000222,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2000,'E70',1980,0.4000000000000000222,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2000,'E70',1990,0.4000000000000000222,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2000,'E70',2000,0.4000000000000000222,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2010,'E70',1980,0.4000000000000000222,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2010,'E70',1990,0.4000000000000000222,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2010,'E70',2000,0.4000000000000000222,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2010,'E70',2010,0.4000000000000000222,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',1990,'SRE',1990,10.0,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2000,'SRE',1990,10.0,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2000,'SRE',2000,10.0,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2010,'SRE',1990,10.0,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2010,'SRE',2000,10.0,'','',NULL); +INSERT INTO cost_variable VALUES('utopia',2010,'SRE',2010,10.0,'','',NULL); CREATE TABLE Demand ( region TEXT, @@ -567,7 +567,7 @@ INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','night','RL INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RL',0.5,''); INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RL',0.1000000000000000055,''); INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RH',0.1199999999999999956,NULL); -CREATE TABLE EndOfLifeOutput +CREATE TABLE end_of_life_output ( region TEXT, tech TEXT @@ -581,7 +581,7 @@ CREATE TABLE EndOfLifeOutput notes TEXT, PRIMARY KEY (region, tech, vintage, output_comm) ); -CREATE TABLE Efficiency +CREATE TABLE efficiency ( region TEXT, input_comm TEXT @@ -598,71 +598,71 @@ CREATE TABLE Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPDSL1',1990,'DSL',1.0,'',NULL); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPGSL1',1990,'GSL',1.0,'',NULL); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPHCO1',1990,'HCO',1.0,'',NULL); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,'',NULL); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,'',NULL); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,'',NULL); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,'',NULL); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1960,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1970,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1980,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1990,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',2000,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',2010,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',1990,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2000,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2010,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','URN','E21',1990,'ELC',0.4000000000000000222,'# 1/2.5',NULL); -INSERT INTO Efficiency VALUES('utopia','URN','E21',2000,'ELC',0.4000000000000000222,'# 1/2.5',NULL); -INSERT INTO Efficiency VALUES('utopia','URN','E21',2010,'ELC',0.4000000000000000222,'# 1/2.5',NULL); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',1980,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',1990,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',2000,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',2010,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1960,'ELC',0.2939999999999999836,'# 1/3.4',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1970,'ELC',0.2939999999999999836,'# 1/3.4',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1980,'ELC',0.2939999999999999836,'# 1/3.4',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1990,'ELC',0.2939999999999999836,'# 1/3.4',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',2000,'ELC',0.2939999999999999836,'# 1/3.4',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',2010,'ELC',0.2939999999999999836,'# 1/3.4',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',1980,'ELC',0.7199999999999999734,'# 1/1.3889',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',1990,'ELC',0.7199999999999999734,'# 1/1.3889',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',2000,'ELC',0.7199999999999999734,'# 1/1.3889',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',2010,'ELC',0.7199999999999999734,'# 1/1.3889',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','RHE',1990,'RH',1.0,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','RHE',2000,'RH',1.0,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','RHE',2010,'RH',1.0,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1970,'RH',0.6999999999999999556,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1980,'RH',0.6999999999999999556,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1990,'RH',0.6999999999999999556,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2000,'RH',0.6999999999999999556,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2010,'RH',0.6999999999999999556,'# direct translation from DMD_EFF','Res_heating_2010_eff'); -INSERT INTO Efficiency VALUES('utopia','ELC','RL1',1980,'RL',1.0,'# direct translation from DMD_EFF','Res_lighting_eff'); -INSERT INTO Efficiency VALUES('utopia','ELC','RL1',1990,'RL',1.0,'# direct translation from DMD_EFF','Res_lighting_eff'); -INSERT INTO Efficiency VALUES('utopia','ELC','RL1',2000,'RL',1.0,'# direct translation from DMD_EFF','Res_lighting_eff'); -INSERT INTO Efficiency VALUES('utopia','ELC','RL1',2010,'RL',1.0,'# direct translation from DMD_EFF','Res_lighting_eff'); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',1990,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2000,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',1990,'TX',0.8269999999999999574,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2000,'TX',0.8269999999999999574,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2010,'TX',0.8269999999999999574,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); -CREATE TABLE EfficiencyVariable +INSERT INTO efficiency VALUES('utopia','ethos','IMPDSL1',1990,'DSL',1.0,'',NULL); +INSERT INTO efficiency VALUES('utopia','ethos','IMPGSL1',1990,'GSL',1.0,'',NULL); +INSERT INTO efficiency VALUES('utopia','ethos','IMPHCO1',1990,'HCO',1.0,'',NULL); +INSERT INTO efficiency VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,'',NULL); +INSERT INTO efficiency VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,'',NULL); +INSERT INTO efficiency VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,'',NULL); +INSERT INTO efficiency VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,'',NULL); +INSERT INTO efficiency VALUES('utopia','HCO','E01',1960,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO efficiency VALUES('utopia','HCO','E01',1970,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO efficiency VALUES('utopia','HCO','E01',1980,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO efficiency VALUES('utopia','HCO','E01',1990,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO efficiency VALUES('utopia','HCO','E01',2000,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO efficiency VALUES('utopia','HCO','E01',2010,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO efficiency VALUES('utopia','FEQ','E21',1990,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO efficiency VALUES('utopia','FEQ','E21',2000,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO efficiency VALUES('utopia','FEQ','E21',2010,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO efficiency VALUES('utopia','URN','E21',1990,'ELC',0.4000000000000000222,'# 1/2.5',NULL); +INSERT INTO efficiency VALUES('utopia','URN','E21',2000,'ELC',0.4000000000000000222,'# 1/2.5',NULL); +INSERT INTO efficiency VALUES('utopia','URN','E21',2010,'ELC',0.4000000000000000222,'# 1/2.5',NULL); +INSERT INTO efficiency VALUES('utopia','HYD','E31',1980,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO efficiency VALUES('utopia','HYD','E31',1990,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO efficiency VALUES('utopia','HYD','E31',2000,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO efficiency VALUES('utopia','HYD','E31',2010,'ELC',0.3200000000000000066,'# 1/3.125',NULL); +INSERT INTO efficiency VALUES('utopia','DSL','E70',1960,'ELC',0.2939999999999999836,'# 1/3.4',NULL); +INSERT INTO efficiency VALUES('utopia','DSL','E70',1970,'ELC',0.2939999999999999836,'# 1/3.4',NULL); +INSERT INTO efficiency VALUES('utopia','DSL','E70',1980,'ELC',0.2939999999999999836,'# 1/3.4',NULL); +INSERT INTO efficiency VALUES('utopia','DSL','E70',1990,'ELC',0.2939999999999999836,'# 1/3.4',NULL); +INSERT INTO efficiency VALUES('utopia','DSL','E70',2000,'ELC',0.2939999999999999836,'# 1/3.4',NULL); +INSERT INTO efficiency VALUES('utopia','DSL','E70',2010,'ELC',0.2939999999999999836,'# 1/3.4',NULL); +INSERT INTO efficiency VALUES('utopia','ELC','E51',1980,'ELC',0.7199999999999999734,'# 1/1.3889',NULL); +INSERT INTO efficiency VALUES('utopia','ELC','E51',1990,'ELC',0.7199999999999999734,'# 1/1.3889',NULL); +INSERT INTO efficiency VALUES('utopia','ELC','E51',2000,'ELC',0.7199999999999999734,'# 1/1.3889',NULL); +INSERT INTO efficiency VALUES('utopia','ELC','E51',2010,'ELC',0.7199999999999999734,'# 1/1.3889',NULL); +INSERT INTO efficiency VALUES('utopia','ELC','RHE',1990,'RH',1.0,'# direct translation from DMD_EFF',NULL); +INSERT INTO efficiency VALUES('utopia','ELC','RHE',2000,'RH',1.0,'# direct translation from DMD_EFF',NULL); +INSERT INTO efficiency VALUES('utopia','ELC','RHE',2010,'RH',1.0,'# direct translation from DMD_EFF',NULL); +INSERT INTO efficiency VALUES('utopia','DSL','RHO',1970,'RH',0.6999999999999999556,'# direct translation from DMD_EFF',NULL); +INSERT INTO efficiency VALUES('utopia','DSL','RHO',1980,'RH',0.6999999999999999556,'# direct translation from DMD_EFF',NULL); +INSERT INTO efficiency VALUES('utopia','DSL','RHO',1990,'RH',0.6999999999999999556,'# direct translation from DMD_EFF',NULL); +INSERT INTO efficiency VALUES('utopia','DSL','RHO',2000,'RH',0.6999999999999999556,'# direct translation from DMD_EFF',NULL); +INSERT INTO efficiency VALUES('utopia','DSL','RHO',2010,'RH',0.6999999999999999556,'# direct translation from DMD_EFF','Res_heating_2010_eff'); +INSERT INTO efficiency VALUES('utopia','ELC','RL1',1980,'RL',1.0,'# direct translation from DMD_EFF','Res_lighting_eff'); +INSERT INTO efficiency VALUES('utopia','ELC','RL1',1990,'RL',1.0,'# direct translation from DMD_EFF','Res_lighting_eff'); +INSERT INTO efficiency VALUES('utopia','ELC','RL1',2000,'RL',1.0,'# direct translation from DMD_EFF','Res_lighting_eff'); +INSERT INTO efficiency VALUES('utopia','ELC','RL1',2010,'RL',1.0,'# direct translation from DMD_EFF','Res_lighting_eff'); +INSERT INTO efficiency VALUES('utopia','OIL','SRE',1990,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); +INSERT INTO efficiency VALUES('utopia','OIL','SRE',2000,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); +INSERT INTO efficiency VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); +INSERT INTO efficiency VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); +INSERT INTO efficiency VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); +INSERT INTO efficiency VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); +INSERT INTO efficiency VALUES('utopia','DSL','TXD',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); +INSERT INTO efficiency VALUES('utopia','DSL','TXD',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); +INSERT INTO efficiency VALUES('utopia','DSL','TXD',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); +INSERT INTO efficiency VALUES('utopia','DSL','TXD',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); +INSERT INTO efficiency VALUES('utopia','DSL','TXD',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); +INSERT INTO efficiency VALUES('utopia','ELC','TXE',1990,'TX',0.8269999999999999574,'# direct translation from DMD_EFF',NULL); +INSERT INTO efficiency VALUES('utopia','ELC','TXE',2000,'TX',0.8269999999999999574,'# direct translation from DMD_EFF',NULL); +INSERT INTO efficiency VALUES('utopia','ELC','TXE',2010,'TX',0.8269999999999999574,'# direct translation from DMD_EFF',NULL); +INSERT INTO efficiency VALUES('utopia','GSL','TXG',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); +INSERT INTO efficiency VALUES('utopia','GSL','TXG',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); +INSERT INTO efficiency VALUES('utopia','GSL','TXG',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); +INSERT INTO efficiency VALUES('utopia','GSL','TXG',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); +INSERT INTO efficiency VALUES('utopia','GSL','TXG',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); +CREATE TABLE efficiency_variable ( region TEXT, period INTEGER @@ -684,7 +684,7 @@ CREATE TABLE EfficiencyVariable PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -CREATE TABLE EmissionActivity +CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT @@ -702,21 +702,21 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.07499999999999999723,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.07499999999999999723,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',0.0889999999999999819,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.07499999999999999723,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1970,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1980,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1990,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',2000,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',2010,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',1970,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',1980,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',1990,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',2000,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',2010,'TX',1.0,'',''); -CREATE TABLE EmissionEmbodied +INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.07499999999999999723,'',''); +INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.07499999999999999723,'',''); +INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',0.0889999999999999819,'',''); +INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.07499999999999999723,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',1970,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',1980,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',1990,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',2000,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',2010,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',1970,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',1980,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',1990,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',2000,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',2010,'TX',1.0,'',''); +CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT @@ -730,7 +730,7 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE EmissionEndOfLife +CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT @@ -744,7 +744,7 @@ CREATE TABLE EmissionEndOfLife notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE ExistingCapacity +CREATE TABLE existing_capacity ( region TEXT, tech TEXT @@ -756,28 +756,28 @@ CREATE TABLE ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1960,0.1749999999999999889,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1970,0.1749999999999999889,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1980,0.1499999999999999945,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E31',1980,0.1000000000000000055,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E51',1980,0.5,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1960,0.05000000000000000277,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1970,0.05000000000000000277,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1980,0.2000000000000000111,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','RHO',1970,12.5,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','RHO',1980,12.5,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','RL1',1980,5.599999999999999645,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXD',1970,0.4000000000000000222,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXD',1980,0.2000000000000000111,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXG',1970,3.100000000000000088,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXG',1980,1.5,'',''); +INSERT INTO existing_capacity VALUES('utopia','E01',1960,0.1749999999999999889,'',''); +INSERT INTO existing_capacity VALUES('utopia','E01',1970,0.1749999999999999889,'',''); +INSERT INTO existing_capacity VALUES('utopia','E01',1980,0.1499999999999999945,'',''); +INSERT INTO existing_capacity VALUES('utopia','E31',1980,0.1000000000000000055,'',''); +INSERT INTO existing_capacity VALUES('utopia','E51',1980,0.5,'',''); +INSERT INTO existing_capacity VALUES('utopia','E70',1960,0.05000000000000000277,'',''); +INSERT INTO existing_capacity VALUES('utopia','E70',1970,0.05000000000000000277,'',''); +INSERT INTO existing_capacity VALUES('utopia','E70',1980,0.2000000000000000111,'',''); +INSERT INTO existing_capacity VALUES('utopia','RHO',1970,12.5,'',''); +INSERT INTO existing_capacity VALUES('utopia','RHO',1980,12.5,'',''); +INSERT INTO existing_capacity VALUES('utopia','RL1',1980,5.599999999999999645,'',''); +INSERT INTO existing_capacity VALUES('utopia','TXD',1970,0.4000000000000000222,'',''); +INSERT INTO existing_capacity VALUES('utopia','TXD',1980,0.2000000000000000111,'',''); +INSERT INTO existing_capacity VALUES('utopia','TXG',1970,3.100000000000000088,'',''); +INSERT INTO existing_capacity VALUES('utopia','TXG',1980,1.5,'',''); CREATE TABLE TechGroup ( group_name TEXT PRIMARY KEY, notes TEXT ); -CREATE TABLE LoanLifetimeProcess +CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT @@ -788,7 +788,7 @@ CREATE TABLE LoanLifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LoanRate +CREATE TABLE loan_rate ( region TEXT, tech TEXT @@ -799,7 +799,7 @@ CREATE TABLE LoanRate notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeProcess +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -810,12 +810,12 @@ CREATE TABLE LifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO LifetimeProcess VALUES('utopia','RL1',1980,20.0,'#forexistingcap'); -INSERT INTO LifetimeProcess VALUES('utopia','TXD',1970,30.0,'#forexistingcap'); -INSERT INTO LifetimeProcess VALUES('utopia','TXD',1980,30.0,'#forexistingcap'); -INSERT INTO LifetimeProcess VALUES('utopia','TXG',1970,30.0,'#forexistingcap'); -INSERT INTO LifetimeProcess VALUES('utopia','TXG',1980,30.0,'#forexistingcap'); -CREATE TABLE LifetimeTech +INSERT INTO lifetime_process VALUES('utopia','RL1',1980,20.0,'#forexistingcap'); +INSERT INTO lifetime_process VALUES('utopia','TXD',1970,30.0,'#forexistingcap'); +INSERT INTO lifetime_process VALUES('utopia','TXD',1980,30.0,'#forexistingcap'); +INSERT INTO lifetime_process VALUES('utopia','TXG',1970,30.0,'#forexistingcap'); +INSERT INTO lifetime_process VALUES('utopia','TXG',1980,30.0,'#forexistingcap'); +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT @@ -824,25 +824,25 @@ CREATE TABLE LifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO LifetimeTech VALUES('utopia','E01',40.0,''); -INSERT INTO LifetimeTech VALUES('utopia','E21',40.0,''); -INSERT INTO LifetimeTech VALUES('utopia','E31',100.0,''); -INSERT INTO LifetimeTech VALUES('utopia','E51',100.0,''); -INSERT INTO LifetimeTech VALUES('utopia','E70',40.0,''); -INSERT INTO LifetimeTech VALUES('utopia','RHE',30.0,''); -INSERT INTO LifetimeTech VALUES('utopia','RHO',30.0,''); -INSERT INTO LifetimeTech VALUES('utopia','RL1',10.0,''); -INSERT INTO LifetimeTech VALUES('utopia','SRE',50.0,''); -INSERT INTO LifetimeTech VALUES('utopia','TXD',15.0,''); -INSERT INTO LifetimeTech VALUES('utopia','TXE',15.0,''); -INSERT INTO LifetimeTech VALUES('utopia','TXG',15.0,''); -INSERT INTO LifetimeTech VALUES('utopia','IMPDSL1',1000.0,''); -INSERT INTO LifetimeTech VALUES('utopia','IMPGSL1',1000.0,''); -INSERT INTO LifetimeTech VALUES('utopia','IMPHCO1',1000.0,''); -INSERT INTO LifetimeTech VALUES('utopia','IMPOIL1',1000.0,''); -INSERT INTO LifetimeTech VALUES('utopia','IMPURN1',1000.0,''); -INSERT INTO LifetimeTech VALUES('utopia','IMPHYD',1000.0,''); -INSERT INTO LifetimeTech VALUES('utopia','IMPFEQ',1000.0,''); +INSERT INTO lifetime_tech VALUES('utopia','E01',40.0,''); +INSERT INTO lifetime_tech VALUES('utopia','E21',40.0,''); +INSERT INTO lifetime_tech VALUES('utopia','E31',100.0,''); +INSERT INTO lifetime_tech VALUES('utopia','E51',100.0,''); +INSERT INTO lifetime_tech VALUES('utopia','E70',40.0,''); +INSERT INTO lifetime_tech VALUES('utopia','RHE',30.0,''); +INSERT INTO lifetime_tech VALUES('utopia','RHO',30.0,''); +INSERT INTO lifetime_tech VALUES('utopia','RL1',10.0,''); +INSERT INTO lifetime_tech VALUES('utopia','SRE',50.0,''); +INSERT INTO lifetime_tech VALUES('utopia','TXD',15.0,''); +INSERT INTO lifetime_tech VALUES('utopia','TXE',15.0,''); +INSERT INTO lifetime_tech VALUES('utopia','TXG',15.0,''); +INSERT INTO lifetime_tech VALUES('utopia','IMPDSL1',1000.0,''); +INSERT INTO lifetime_tech VALUES('utopia','IMPGSL1',1000.0,''); +INSERT INTO lifetime_tech VALUES('utopia','IMPHCO1',1000.0,''); +INSERT INTO lifetime_tech VALUES('utopia','IMPOIL1',1000.0,''); +INSERT INTO lifetime_tech VALUES('utopia','IMPURN1',1000.0,''); +INSERT INTO lifetime_tech VALUES('utopia','IMPHYD',1000.0,''); +INSERT INTO lifetime_tech VALUES('utopia','IMPFEQ',1000.0,''); CREATE TABLE Operator ( operator TEXT PRIMARY KEY, @@ -851,7 +851,7 @@ CREATE TABLE Operator INSERT INTO Operator VALUES('e','equal to'); INSERT INTO Operator VALUES('le','less than or equal to'); INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE LimitGrowthCapacity +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, @@ -863,7 +863,7 @@ CREATE TABLE LimitGrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthCapacity +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, @@ -875,7 +875,7 @@ CREATE TABLE LimitDegrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacity +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -887,7 +887,7 @@ CREATE TABLE LimitGrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -899,7 +899,7 @@ CREATE TABLE LimitDegrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacityDelta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -911,7 +911,7 @@ CREATE TABLE LimitGrowthNewCapacityDelta notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacityDelta +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -942,7 +942,7 @@ CREATE TABLE LimitStorageLevelFraction notes TEXT, PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE LimitActivity +CREATE TABLE limit_activity ( region TEXT, period INTEGER @@ -955,7 +955,7 @@ CREATE TABLE LimitActivity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitActivityShare +CREATE TABLE limit_activity_share ( region TEXT, period INTEGER @@ -968,7 +968,7 @@ CREATE TABLE LimitActivityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitAnnualCapacityFactor +CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER @@ -984,7 +984,7 @@ CREATE TABLE LimitAnnualCapacityFactor PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE LimitCapacity +CREATE TABLE limit_capacity ( region TEXT, period INTEGER @@ -997,18 +997,18 @@ CREATE TABLE LimitCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO LimitCapacity VALUES('utopia',1990,'E31','ge',0.1300000000000000044,'',''); -INSERT INTO LimitCapacity VALUES('utopia',2000,'E31','ge',0.1300000000000000044,'',''); -INSERT INTO LimitCapacity VALUES('utopia',2010,'E31','ge',0.1300000000000000044,'',''); -INSERT INTO LimitCapacity VALUES('utopia',1990,'SRE','ge',0.1000000000000000055,'',''); -INSERT INTO LimitCapacity VALUES('utopia',1990,'E31','le',0.1300000000000000044,'',''); -INSERT INTO LimitCapacity VALUES('utopia',2000,'E31','le',0.1700000000000000122,'',''); -INSERT INTO LimitCapacity VALUES('utopia',2010,'E31','le',0.21000000000000002,'',''); -INSERT INTO LimitCapacity VALUES('utopia',1990,'RHE','le',0.0,'',''); -INSERT INTO LimitCapacity VALUES('utopia',1990,'TXD','le',0.5999999999999999778,'',''); -INSERT INTO LimitCapacity VALUES('utopia',2000,'TXD','le',1.760000000000000008,'',''); -INSERT INTO LimitCapacity VALUES('utopia',2010,'TXD','le',4.759999999999999787,'',''); -CREATE TABLE LimitCapacityShare +INSERT INTO limit_capacity VALUES('utopia',1990,'E31','ge',0.1300000000000000044,'',''); +INSERT INTO limit_capacity VALUES('utopia',2000,'E31','ge',0.1300000000000000044,'',''); +INSERT INTO limit_capacity VALUES('utopia',2010,'E31','ge',0.1300000000000000044,'',''); +INSERT INTO limit_capacity VALUES('utopia',1990,'SRE','ge',0.1000000000000000055,'',''); +INSERT INTO limit_capacity VALUES('utopia',1990,'E31','le',0.1300000000000000044,'',''); +INSERT INTO limit_capacity VALUES('utopia',2000,'E31','le',0.1700000000000000122,'',''); +INSERT INTO limit_capacity VALUES('utopia',2010,'E31','le',0.21000000000000002,'',''); +INSERT INTO limit_capacity VALUES('utopia',1990,'RHE','le',0.0,'',''); +INSERT INTO limit_capacity VALUES('utopia',1990,'TXD','le',0.5999999999999999778,'',''); +INSERT INTO limit_capacity VALUES('utopia',2000,'TXD','le',1.760000000000000008,'',''); +INSERT INTO limit_capacity VALUES('utopia',2010,'TXD','le',4.759999999999999787,'',''); +CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER @@ -1021,7 +1021,7 @@ CREATE TABLE LimitCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitNewCapacity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER @@ -1034,7 +1034,7 @@ CREATE TABLE LimitNewCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitNewCapacityShare +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -1047,7 +1047,7 @@ CREATE TABLE LimitNewCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitResource +CREATE TABLE limit_resource ( region TEXT, tech_or_group TEXT, @@ -1058,7 +1058,7 @@ CREATE TABLE LimitResource notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitSeasonalCapacityFactor +CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES Region (region), @@ -1074,7 +1074,7 @@ CREATE TABLE LimitSeasonalCapacityFactor notes TEXT, PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE LimitTechInputSplit +CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER @@ -1089,7 +1089,7 @@ CREATE TABLE LimitTechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechInputSplitAnnual +CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER @@ -1104,7 +1104,7 @@ CREATE TABLE LimitTechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechOutputSplit +CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER @@ -1119,13 +1119,13 @@ CREATE TABLE LimitTechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -INSERT INTO LimitTechOutputSplit VALUES('utopia',1990,'SRE','DSL','ge',0.6999999999999999556,''); -INSERT INTO LimitTechOutputSplit VALUES('utopia',2000,'SRE','DSL','ge',0.6999999999999999556,''); -INSERT INTO LimitTechOutputSplit VALUES('utopia',2010,'SRE','DSL','ge',0.6999999999999999556,''); -INSERT INTO LimitTechOutputSplit VALUES('utopia',1990,'SRE','GSL','ge',0.2999999999999999889,''); -INSERT INTO LimitTechOutputSplit VALUES('utopia',2000,'SRE','GSL','ge',0.2999999999999999889,''); -INSERT INTO LimitTechOutputSplit VALUES('utopia',2010,'SRE','GSL','ge',0.2999999999999999889,''); -CREATE TABLE LimitTechOutputSplitAnnual +INSERT INTO limit_tech_output_split VALUES('utopia',1990,'SRE','DSL','ge',0.6999999999999999556,''); +INSERT INTO limit_tech_output_split VALUES('utopia',2000,'SRE','DSL','ge',0.6999999999999999556,''); +INSERT INTO limit_tech_output_split VALUES('utopia',2010,'SRE','DSL','ge',0.6999999999999999556,''); +INSERT INTO limit_tech_output_split VALUES('utopia',1990,'SRE','GSL','ge',0.2999999999999999889,''); +INSERT INTO limit_tech_output_split VALUES('utopia',2000,'SRE','GSL','ge',0.2999999999999999889,''); +INSERT INTO limit_tech_output_split VALUES('utopia',2010,'SRE','GSL','ge',0.2999999999999999889,''); +CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER @@ -1140,7 +1140,7 @@ CREATE TABLE LimitTechOutputSplitAnnual notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitEmission +CREATE TABLE limit_emission ( region TEXT, period INTEGER @@ -1297,7 +1297,7 @@ CREATE TABLE OutputStorageLevel level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); -CREATE TABLE PlanningReserveMargin +CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY @@ -1305,7 +1305,7 @@ CREATE TABLE PlanningReserveMargin margin REAL, notes TEXT ); -CREATE TABLE RampDownHourly +CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT @@ -1314,7 +1314,7 @@ CREATE TABLE RampDownHourly notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUpHourly +CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT @@ -1330,7 +1330,7 @@ CREATE TABLE Region notes TEXT ); INSERT INTO Region VALUES('utopia',NULL); -CREATE TABLE ReserveCapacityDerate +CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER @@ -1346,7 +1346,7 @@ CREATE TABLE ReserveCapacityDerate CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE TimeSegmentFraction -( +( period INTEGER REFERENCES TimePeriod (period), season TEXT @@ -1376,7 +1376,7 @@ INSERT INTO TimeSegmentFraction VALUES(2010,'summer','day',0.166699999999999987, INSERT INTO TimeSegmentFraction VALUES(2010,'summer','night',0.08329999999999999905,'# S-N'); INSERT INTO TimeSegmentFraction VALUES(2010,'winter','day',0.3332999999999999852,'# W-D'); INSERT INTO TimeSegmentFraction VALUES(2010,'winter','night',0.166699999999999987,'# W-N'); -CREATE TABLE StorageDuration +CREATE TABLE storage_duration ( region TEXT, tech TEXT, @@ -1384,7 +1384,7 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE LifetimeSurvivalCurve +CREATE TABLE lifetime_survival_curve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -1447,7 +1447,7 @@ INSERT INTO TimeSeason VALUES(2000,1,'inter',NULL); INSERT INTO TimeSeason VALUES(2010,2,'summer',NULL); INSERT INTO TimeSeason VALUES(2010,3,'winter',NULL); INSERT INTO TimeSeason VALUES(2010,1,'inter',NULL); -CREATE TABLE TimeSeasonSequential +CREATE TABLE time_season_sequential ( period INTEGER REFERENCES TimePeriod (period), diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql index 2c368a71a..3064c30c3 100644 --- a/data_files/example_dbs/seasonal_storage.sql +++ b/data_files/example_dbs/seasonal_storage.sql @@ -19,7 +19,7 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -60,7 +60,7 @@ CREATE TABLE SectorLabel notes TEXT ); INSERT INTO SectorLabel VALUES('electricity',NULL); -CREATE TABLE CapacityCredit +CREATE TABLE capacity_credit ( region TEXT, period INTEGER @@ -73,7 +73,7 @@ CREATE TABLE CapacityCredit PRIMARY KEY (region, period, tech, vintage), CHECK (credit >= 0 AND credit <= 1) ); -CREATE TABLE CapacityFactorProcess +CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER @@ -90,7 +90,7 @@ CREATE TABLE CapacityFactorProcess PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE CapacityFactorTech +CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER @@ -106,14 +106,14 @@ CREATE TABLE CapacityFactorTech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','a','generator',1.0,NULL); -INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','b','generator',1.0,NULL); -INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','c','generator',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','d','generator',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','a','generator',0.1,NULL); -INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','b','generator',0.1,NULL); -INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','c','generator',0.01,NULL); -INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','d','generator',0.01,NULL); +INSERT INTO capacity_factor_tech VALUES('region',2000,'charge','a','generator',1.0,NULL); +INSERT INTO capacity_factor_tech VALUES('region',2000,'charge','b','generator',1.0,NULL); +INSERT INTO capacity_factor_tech VALUES('region',2000,'charge','c','generator',0.2,NULL); +INSERT INTO capacity_factor_tech VALUES('region',2000,'charge','d','generator',0.2,NULL); +INSERT INTO capacity_factor_tech VALUES('region',2000,'discharge','a','generator',0.1,NULL); +INSERT INTO capacity_factor_tech VALUES('region',2000,'discharge','b','generator',0.1,NULL); +INSERT INTO capacity_factor_tech VALUES('region',2000,'discharge','c','generator',0.01,NULL); +INSERT INTO capacity_factor_tech VALUES('region',2000,'discharge','d','generator',0.01,NULL); CREATE TABLE CapacityToActivity ( region TEXT, @@ -152,7 +152,7 @@ INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('w','waste commodity'); INSERT INTO CommodityType VALUES('wa','waste annual commodity'); INSERT INTO CommodityType VALUES('wp','waste physical commodity'); -CREATE TABLE ConstructionInput +CREATE TABLE construction_input ( region TEXT, input_comm TEXT @@ -166,7 +166,7 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -CREATE TABLE CostEmission +CREATE TABLE cost_emission ( region TEXT, period INTEGER @@ -178,7 +178,7 @@ CREATE TABLE CostEmission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -CREATE TABLE CostFixed +CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -192,7 +192,7 @@ CREATE TABLE CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE CostInvest +CREATE TABLE cost_invest ( region TEXT, tech TEXT @@ -204,11 +204,11 @@ CREATE TABLE CostInvest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO CostInvest VALUES('region','generator',2000,1000.0,'',NULL); -INSERT INTO CostInvest VALUES('region','dly_stor',2000,1.0,'',NULL); -INSERT INTO CostInvest VALUES('region','seas_stor',2000,100.0,'',NULL); -INSERT INTO CostInvest VALUES('region','demand',2000,1.0,'',NULL); -CREATE TABLE CostVariable +INSERT INTO cost_invest VALUES('region','generator',2000,1000.0,'',NULL); +INSERT INTO cost_invest VALUES('region','dly_stor',2000,1.0,'',NULL); +INSERT INTO cost_invest VALUES('region','seas_stor',2000,100.0,'',NULL); +INSERT INTO cost_invest VALUES('region','demand',2000,1.0,'',NULL); +CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -222,8 +222,8 @@ CREATE TABLE CostVariable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostVariable VALUES('region',2000,'generator',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2000,'demand',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2000,'generator',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2000,'demand',2000,1.0,NULL,NULL); CREATE TABLE Demand ( region TEXT, @@ -261,7 +261,7 @@ INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','a','dem INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','b','demand',0.2,NULL); INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','c','demand',0.2,NULL); INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','d','demand',0.4,NULL); -CREATE TABLE EndOfLifeOutput +CREATE TABLE end_of_life_output ( region TEXT, tech TEXT @@ -275,7 +275,7 @@ CREATE TABLE EndOfLifeOutput notes TEXT, PRIMARY KEY (region, tech, vintage, output_comm) ); -CREATE TABLE Efficiency +CREATE TABLE efficiency ( region TEXT, input_comm TEXT @@ -291,11 +291,11 @@ CREATE TABLE Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO Efficiency VALUES('region','ethos','generator',2000,'electricity',1.0,NULL); -INSERT INTO Efficiency VALUES('region','electricity','dly_stor',2000,'electricity',1.0,NULL); -INSERT INTO Efficiency VALUES('region','electricity','seas_stor',2000,'electricity',1.0,NULL); -INSERT INTO Efficiency VALUES('region','electricity','demand',2000,'demand',1.0,NULL); -CREATE TABLE EfficiencyVariable +INSERT INTO efficiency VALUES('region','ethos','generator',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('region','electricity','dly_stor',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('region','electricity','seas_stor',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('region','electricity','demand',2000,'demand',1.0,NULL); +CREATE TABLE efficiency_variable ( region TEXT, period INTEGER @@ -317,7 +317,7 @@ CREATE TABLE EfficiencyVariable PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -CREATE TABLE EmissionActivity +CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT @@ -335,7 +335,7 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -CREATE TABLE EmissionEmbodied +CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT @@ -349,7 +349,7 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE EmissionEndOfLife +CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT @@ -363,7 +363,7 @@ CREATE TABLE EmissionEndOfLife notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE ExistingCapacity +CREATE TABLE existing_capacity ( region TEXT, tech TEXT @@ -381,7 +381,7 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE LoanLifetimeTech +CREATE TABLE Loanlifetime_tech ( region TEXT, tech TEXT @@ -390,7 +390,7 @@ CREATE TABLE LoanLifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE LoanRate +CREATE TABLE loan_rate ( region TEXT, tech TEXT @@ -401,7 +401,7 @@ CREATE TABLE LoanRate notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeProcess +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -412,7 +412,7 @@ CREATE TABLE LifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeTech +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT @@ -429,7 +429,7 @@ CREATE TABLE Operator INSERT INTO Operator VALUES('e','equal to'); INSERT INTO Operator VALUES('le','less than or equal to'); INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE LimitGrowthCapacity +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, @@ -441,7 +441,7 @@ CREATE TABLE LimitGrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthCapacity +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, @@ -453,7 +453,7 @@ CREATE TABLE LimitDegrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacity +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -465,7 +465,7 @@ CREATE TABLE LimitGrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -477,7 +477,7 @@ CREATE TABLE LimitDegrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacityDelta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -489,7 +489,7 @@ CREATE TABLE LimitGrowthNewCapacityDelta notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacityDelta +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -522,7 +522,7 @@ CREATE TABLE LimitStorageLevelFraction ); INSERT INTO LimitStorageLevelFraction VALUES('region', 2000, 'winter', 'b', 'seas_stor', 2000, 'e', 0.5, NULL); INSERT INTO LimitStorageLevelFraction VALUES('region', 2000, 'charge', 'b', 'dly_stor', 2000, 'e', 0.5, NULL); -CREATE TABLE LimitActivity +CREATE TABLE limit_activity ( region TEXT, period INTEGER @@ -535,7 +535,7 @@ CREATE TABLE LimitActivity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitActivityShare +CREATE TABLE limit_activity_share ( region TEXT, period INTEGER @@ -548,7 +548,7 @@ CREATE TABLE LimitActivityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitAnnualCapacityFactor +CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER @@ -564,7 +564,7 @@ CREATE TABLE LimitAnnualCapacityFactor PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE LimitCapacity +CREATE TABLE limit_capacity ( region TEXT, period INTEGER @@ -577,7 +577,7 @@ CREATE TABLE LimitCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitCapacityShare +CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER @@ -590,7 +590,7 @@ CREATE TABLE LimitCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitNewCapacity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER @@ -603,7 +603,7 @@ CREATE TABLE LimitNewCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitNewCapacityShare +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -616,7 +616,7 @@ CREATE TABLE LimitNewCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitResource +CREATE TABLE limit_resource ( region TEXT, tech_or_group TEXT, @@ -627,7 +627,7 @@ CREATE TABLE LimitResource notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitSeasonalCapacityFactor +CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES Region (region), @@ -643,7 +643,7 @@ CREATE TABLE LimitSeasonalCapacityFactor notes TEXT, PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE LimitTechInputSplit +CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER @@ -658,7 +658,7 @@ CREATE TABLE LimitTechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechInputSplitAnnual +CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER @@ -673,7 +673,7 @@ CREATE TABLE LimitTechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechOutputSplit +CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER @@ -688,7 +688,7 @@ CREATE TABLE LimitTechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitTechOutputSplitAnnual +CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER @@ -703,7 +703,7 @@ CREATE TABLE LimitTechOutputSplitAnnual notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitEmission +CREATE TABLE limit_emission ( region TEXT, period INTEGER @@ -860,7 +860,7 @@ CREATE TABLE OutputStorageLevel level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); -CREATE TABLE PlanningReserveMargin +CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY @@ -868,7 +868,7 @@ CREATE TABLE PlanningReserveMargin margin REAL, notes TEXT ); -CREATE TABLE RampDownHourly +CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT @@ -877,7 +877,7 @@ CREATE TABLE RampDownHourly notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUpHourly +CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT @@ -893,7 +893,7 @@ CREATE TABLE Region notes TEXT ); INSERT INTO Region VALUES('region',NULL); -CREATE TABLE ReserveCapacityDerate +CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER @@ -909,7 +909,7 @@ CREATE TABLE ReserveCapacityDerate CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE TimeSegmentFraction -( +( period INTEGER REFERENCES TimePeriod (period), season TEXT @@ -929,7 +929,7 @@ INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','a',0.125,NULL); INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','b',0.125,NULL); INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','c',0.125,NULL); INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','d',0.125,NULL); -CREATE TABLE StorageDuration +CREATE TABLE storage_duration ( region TEXT, tech TEXT, @@ -937,9 +937,9 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO StorageDuration VALUES('region','dly_stor',4.0,NULL); -INSERT INTO StorageDuration VALUES('region','seas_stor',8760.0,NULL); -CREATE TABLE LifetimeSurvivalCurve +INSERT INTO storage_duration VALUES('region','dly_stor',4.0,NULL); +INSERT INTO storage_duration VALUES('region','seas_stor',8760.0,NULL); +CREATE TABLE lifetime_survival_curve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -1078,7 +1078,7 @@ CREATE TABLE OutputCost FOREIGN KEY (vintage) REFERENCES TimePeriod (period), FOREIGN KEY (tech) REFERENCES Technology (tech) ); -CREATE TABLE TimeSeasonSequential +CREATE TABLE time_season_sequential ( period INTEGER REFERENCES TimePeriod (period), @@ -1091,18 +1091,18 @@ CREATE TABLE TimeSeasonSequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -INSERT INTO TimeSeasonSequential VALUES(2000,1,'summer','charge',152.5,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,2,'sept_w1','discharge',7,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,3,'sept_w2','charge',7,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,4,'sept_w3','discharge',7,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,5,'sept_w4','charge',7,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,6,'sept_29th','discharge',1,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,7,'sept_30th','charge',1,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,8,'winter','discharge',152.5,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,9,'apr_w1','charge',7,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,10,'apr_w2','discharge',7,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,11,'apr_w3','charge',7,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,12,'apr_w4','discharge',7,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,13,'apr_29th','charge',1,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,14,'apr_30th','discharge',1,NULL); +INSERT INTO time_season_sequential VALUES(2000,1,'summer','charge',152.5,NULL); +INSERT INTO time_season_sequential VALUES(2000,2,'sept_w1','discharge',7,NULL); +INSERT INTO time_season_sequential VALUES(2000,3,'sept_w2','charge',7,NULL); +INSERT INTO time_season_sequential VALUES(2000,4,'sept_w3','discharge',7,NULL); +INSERT INTO time_season_sequential VALUES(2000,5,'sept_w4','charge',7,NULL); +INSERT INTO time_season_sequential VALUES(2000,6,'sept_29th','discharge',1,NULL); +INSERT INTO time_season_sequential VALUES(2000,7,'sept_30th','charge',1,NULL); +INSERT INTO time_season_sequential VALUES(2000,8,'winter','discharge',152.5,NULL); +INSERT INTO time_season_sequential VALUES(2000,9,'apr_w1','charge',7,NULL); +INSERT INTO time_season_sequential VALUES(2000,10,'apr_w2','discharge',7,NULL); +INSERT INTO time_season_sequential VALUES(2000,11,'apr_w3','charge',7,NULL); +INSERT INTO time_season_sequential VALUES(2000,12,'apr_w4','discharge',7,NULL); +INSERT INTO time_season_sequential VALUES(2000,13,'apr_29th','charge',1,NULL); +INSERT INTO time_season_sequential VALUES(2000,14,'apr_30th','discharge',1,NULL); COMMIT; diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index a399d02cd..fd176f069 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -18,7 +18,7 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); CREATE TABLE OutputDualVariable ( @@ -52,7 +52,7 @@ INSERT INTO SectorLabel VALUES('transport',NULL); INSERT INTO SectorLabel VALUES('commercial',NULL); INSERT INTO SectorLabel VALUES('residential',NULL); INSERT INTO SectorLabel VALUES('industrial',NULL); -CREATE TABLE CapacityCredit +CREATE TABLE capacity_credit ( region TEXT, period INTEGER @@ -65,7 +65,7 @@ CREATE TABLE CapacityCredit PRIMARY KEY (region, period, tech, vintage), CHECK (credit >= 0 AND credit <= 1) ); -CREATE TABLE CapacityFactorProcess +CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER @@ -82,7 +82,7 @@ CREATE TABLE CapacityFactorProcess PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE CapacityFactorTech +CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER @@ -98,72 +98,72 @@ CREATE TABLE CapacityFactorTech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('electricville',2000,'inter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2000,'winter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2000,'summer','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2000,'inter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2000,'winter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2000,'summer','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2005,'inter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2005,'winter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2005,'summer','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2005,'inter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2005,'winter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2005,'summer','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2010,'inter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2010,'winter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2010,'summer','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2010,'inter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2010,'winter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2010,'summer','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2015,'inter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2015,'winter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2015,'summer','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2015,'inter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2015,'winter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2015,'summer','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2020,'inter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2020,'winter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2020,'summer','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2020,'inter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2020,'winter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2020,'summer','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2025,'inter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2025,'winter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2025,'summer','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2025,'inter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2025,'winter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2025,'summer','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2030,'inter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2030,'winter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2030,'summer','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2030,'inter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2030,'winter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2030,'summer','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2035,'inter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2035,'winter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2035,'summer','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2035,'inter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2035,'winter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2035,'summer','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2040,'inter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2040,'winter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2040,'summer','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2040,'inter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2040,'winter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2040,'summer','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2045,'inter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2045,'winter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2045,'summer','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2045,'inter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2045,'winter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2045,'summer','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2050,'inter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2050,'winter','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2050,'summer','day','EF',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2050,'inter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2050,'winter','day','EH',1.0,''); -INSERT INTO CapacityFactorTech VALUES('electricville',2050,'summer','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2000,'inter','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2000,'winter','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2000,'summer','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2000,'inter','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2000,'winter','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2000,'summer','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2005,'inter','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2005,'winter','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2005,'summer','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2005,'inter','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2005,'winter','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2005,'summer','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2010,'inter','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2010,'winter','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2010,'summer','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2010,'inter','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2010,'winter','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2010,'summer','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2015,'inter','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2015,'winter','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2015,'summer','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2015,'inter','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2015,'winter','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2015,'summer','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2020,'inter','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2020,'winter','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2020,'summer','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2020,'inter','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2020,'winter','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2020,'summer','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2025,'inter','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2025,'winter','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2025,'summer','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2025,'inter','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2025,'winter','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2025,'summer','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2030,'inter','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2030,'winter','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2030,'summer','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2030,'inter','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2030,'winter','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2030,'summer','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2035,'inter','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2035,'winter','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2035,'summer','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2035,'inter','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2035,'winter','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2035,'summer','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2040,'inter','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2040,'winter','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2040,'summer','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2040,'inter','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2040,'winter','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2040,'summer','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2045,'inter','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2045,'winter','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2045,'summer','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2045,'inter','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2045,'winter','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2045,'summer','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2050,'inter','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2050,'winter','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2050,'summer','day','EF',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2050,'inter','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2050,'winter','day','EH',1.0,''); +INSERT INTO capacity_factor_tech VALUES('electricville',2050,'summer','day','EH',1.0,''); CREATE TABLE CapacityToActivity ( region TEXT, @@ -201,7 +201,7 @@ INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); -CREATE TABLE ConstructionInput +CREATE TABLE construction_input ( region TEXT, input_comm TEXT @@ -215,7 +215,7 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -CREATE TABLE CostEmission +CREATE TABLE cost_emission ( region TEXT, period INTEGER @@ -227,7 +227,7 @@ CREATE TABLE CostEmission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -CREATE TABLE CostFixed +CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -241,37 +241,37 @@ CREATE TABLE CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostFixed VALUES('electricville',2000,'EH',1995,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2005,'EH',1995,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2010,'EH',1995,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2015,'EH',1995,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2020,'EH',1995,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2025,'EH',1995,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2035,'EH',1995,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2040,'EH',1995,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2045,'EH',1995,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2050,'EH',1995,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2010,'EF',2010,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2015,'EF',2010,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2020,'EF',2010,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2025,'EF',2010,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2030,'EF',2010,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2035,'EF',2010,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2040,'EF',2010,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2045,'EF',2010,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2050,'EF',2010,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2000,'EH',2000,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2005,'EH',2000,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2010,'EH',2000,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2015,'EH',2000,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2020,'EH',2000,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2025,'EH',2000,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2030,'EH',2000,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2035,'EH',2000,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2040,'EH',2000,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2045,'EH',2000,2.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2050,'EH',2000,2.0,'',''); -CREATE TABLE CostInvest +INSERT INTO cost_fixed VALUES('electricville',2000,'EH',1995,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2005,'EH',1995,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2010,'EH',1995,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2015,'EH',1995,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2020,'EH',1995,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2025,'EH',1995,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2035,'EH',1995,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2040,'EH',1995,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2045,'EH',1995,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2050,'EH',1995,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2010,'EF',2010,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2015,'EF',2010,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2020,'EF',2010,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2025,'EF',2010,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2030,'EF',2010,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2035,'EF',2010,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2040,'EF',2010,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2045,'EF',2010,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2050,'EF',2010,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2000,'EH',2000,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2005,'EH',2000,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2010,'EH',2000,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2015,'EH',2000,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2020,'EH',2000,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2025,'EH',2000,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2030,'EH',2000,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2035,'EH',2000,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2040,'EH',2000,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2045,'EH',2000,2.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2050,'EH',2000,2.0,'',''); +CREATE TABLE cost_invest ( region TEXT, tech TEXT @@ -283,9 +283,9 @@ CREATE TABLE CostInvest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO CostInvest VALUES('electricville','EF',2010,200.0,'',''); -INSERT INTO CostInvest VALUES('electricville','EH',2000,100.0,'',''); -CREATE TABLE CostVariable +INSERT INTO cost_invest VALUES('electricville','EF',2010,200.0,'',''); +INSERT INTO cost_invest VALUES('electricville','EH',2000,100.0,'',''); +CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -299,39 +299,39 @@ CREATE TABLE CostVariable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostVariable VALUES('electricville',2010,'EF',2010,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2015,'EF',2010,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2020,'EF',2010,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2025,'EF',2010,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2030,'EF',2010,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2035,'EF',2010,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2040,'EF',2010,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2045,'EF',2010,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2050,'EF',2010,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2000,'EH',1995,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2005,'EH',1995,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2010,'EH',1995,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2015,'EH',1995,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2020,'EH',1995,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2025,'EH',1995,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2030,'EH',1995,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2035,'EH',1995,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2040,'EH',1995,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2045,'EH',1995,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2050,'EH',1995,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2000,'EH',2000,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2005,'EH',2000,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2010,'EH',2000,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2015,'EH',2000,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2020,'EH',2000,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2025,'EH',2000,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2030,'EH',2000,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2035,'EH',2000,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2040,'EH',2000,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2045,'EH',2000,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2050,'EH',2000,2.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2000,'well',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('electricville',2010,'well',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('electricville',2010,'EF',2010,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2015,'EF',2010,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2020,'EF',2010,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2025,'EF',2010,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2030,'EF',2010,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2035,'EF',2010,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2040,'EF',2010,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2045,'EF',2010,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2050,'EF',2010,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2000,'EH',1995,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2005,'EH',1995,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2010,'EH',1995,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2015,'EH',1995,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2020,'EH',1995,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2025,'EH',1995,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2030,'EH',1995,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2035,'EH',1995,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2040,'EH',1995,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2045,'EH',1995,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2050,'EH',1995,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2000,'EH',2000,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2005,'EH',2000,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2010,'EH',2000,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2015,'EH',2000,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2020,'EH',2000,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2025,'EH',2000,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2030,'EH',2000,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2035,'EH',2000,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2040,'EH',2000,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2045,'EH',2000,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2050,'EH',2000,2.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2000,'well',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('electricville',2010,'well',2000,1.0,NULL,NULL); CREATE TABLE Demand ( region TEXT, @@ -404,7 +404,7 @@ INSERT INTO DemandSpecificDistribution VALUES('electricville',2045,'winter','day INSERT INTO DemandSpecificDistribution VALUES('electricville',2050,'inter','day','RL',0.3332999999999999852,''); INSERT INTO DemandSpecificDistribution VALUES('electricville',2050,'summer','day','RL',0.3332999999999999852,''); INSERT INTO DemandSpecificDistribution VALUES('electricville',2050,'winter','day','RL',0.3332999999999999852,''); -CREATE TABLE EndOfLifeOutput +CREATE TABLE end_of_life_output ( region TEXT, tech TEXT @@ -418,7 +418,7 @@ CREATE TABLE EndOfLifeOutput notes TEXT, PRIMARY KEY (region, tech, vintage, output_comm) ); -CREATE TABLE Efficiency +CREATE TABLE efficiency ( region TEXT, input_comm TEXT @@ -434,13 +434,13 @@ CREATE TABLE Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO Efficiency VALUES('electricville','HYD','EH',1995,'ELC',1.0,'est'); -INSERT INTO Efficiency VALUES('electricville','HYD','EH',2000,'ELC',1.0,'est'); -INSERT INTO Efficiency VALUES('electricville','HYD','EF',2010,'ELC',10.0,'est'); -INSERT INTO Efficiency VALUES('electricville','ELC','bulbs',2000,'RL',1.0,NULL); -INSERT INTO Efficiency VALUES('electricville','earth','well',2000,'HYD',1.0,'water source'); -INSERT INTO Efficiency VALUES('electricville','HYD','EH',2020,'ELC',1.0,NULL); -CREATE TABLE EfficiencyVariable +INSERT INTO efficiency VALUES('electricville','HYD','EH',1995,'ELC',1.0,'est'); +INSERT INTO efficiency VALUES('electricville','HYD','EH',2000,'ELC',1.0,'est'); +INSERT INTO efficiency VALUES('electricville','HYD','EF',2010,'ELC',10.0,'est'); +INSERT INTO efficiency VALUES('electricville','ELC','bulbs',2000,'RL',1.0,NULL); +INSERT INTO efficiency VALUES('electricville','earth','well',2000,'HYD',1.0,'water source'); +INSERT INTO efficiency VALUES('electricville','HYD','EH',2020,'ELC',1.0,NULL); +CREATE TABLE efficiency_variable ( region TEXT, period INTEGER @@ -462,7 +462,7 @@ CREATE TABLE EfficiencyVariable PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -CREATE TABLE EmissionActivity +CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT @@ -480,10 +480,10 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('electricville','co2','HYD','EH',1995,'ELC',0.05000000000000000277,'',''); -INSERT INTO EmissionActivity VALUES('electricville','co2','HYD','EF',2010,'ELC',0.0100000000000000002,'',''); -INSERT INTO EmissionActivity VALUES('electricville','co2','HYD','EH',2000,'ELC',0.02000000000000000041,NULL,NULL); -CREATE TABLE EmissionEmbodied +INSERT INTO emission_activity VALUES('electricville','co2','HYD','EH',1995,'ELC',0.05000000000000000277,'',''); +INSERT INTO emission_activity VALUES('electricville','co2','HYD','EF',2010,'ELC',0.0100000000000000002,'',''); +INSERT INTO emission_activity VALUES('electricville','co2','HYD','EH',2000,'ELC',0.02000000000000000041,NULL,NULL); +CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT @@ -497,7 +497,7 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE EmissionEndOfLife +CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT @@ -511,7 +511,7 @@ CREATE TABLE EmissionEndOfLife notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE ExistingCapacity +CREATE TABLE existing_capacity ( region TEXT, tech TEXT @@ -523,7 +523,7 @@ CREATE TABLE ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO ExistingCapacity VALUES('electricville','EH',1995,0.5,'',''); +INSERT INTO existing_capacity VALUES('electricville','EH',1995,0.5,'',''); CREATE TABLE TechGroup ( group_name TEXT @@ -532,7 +532,7 @@ CREATE TABLE TechGroup ); INSERT INTO TechGroup VALUES('RPS_global',''); INSERT INTO TechGroup VALUES('RPS_common',''); -CREATE TABLE LoanLifetimeProcess +CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT @@ -543,8 +543,8 @@ CREATE TABLE LoanLifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO LoanLifetimeProcess VALUES('electricville','EF',2010,50.0,''); -CREATE TABLE LoanRate +INSERT INTO loan_lifetime_process VALUES('electricville','EF',2010,50.0,''); +CREATE TABLE loan_rate ( region TEXT, tech TEXT @@ -555,7 +555,7 @@ CREATE TABLE LoanRate notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeProcess +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -566,8 +566,8 @@ CREATE TABLE LifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO LifetimeProcess VALUES('electricville','EH',1995,80.0,'#forexistingcap'); -CREATE TABLE LifetimeTech +INSERT INTO lifetime_process VALUES('electricville','EH',1995,80.0,'#forexistingcap'); +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT @@ -576,10 +576,10 @@ CREATE TABLE LifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO LifetimeTech VALUES('electricville','EH',100.0,''); -INSERT INTO LifetimeTech VALUES('electricville','EF',100.0,''); -INSERT INTO LifetimeTech VALUES('electricville','bulbs',100.0,'super LED!'); -INSERT INTO LifetimeTech VALUES('electricville','well',100.0,NULL); +INSERT INTO lifetime_tech VALUES('electricville','EH',100.0,''); +INSERT INTO lifetime_tech VALUES('electricville','EF',100.0,''); +INSERT INTO lifetime_tech VALUES('electricville','bulbs',100.0,'super LED!'); +INSERT INTO lifetime_tech VALUES('electricville','well',100.0,NULL); CREATE TABLE Operator ( operator TEXT PRIMARY KEY, @@ -588,7 +588,7 @@ CREATE TABLE Operator INSERT INTO Operator VALUES('e','equal to'); INSERT INTO Operator VALUES('le','less than or equal to'); INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE LimitGrowthCapacity +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, @@ -600,7 +600,7 @@ CREATE TABLE LimitGrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthCapacity +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, @@ -612,7 +612,7 @@ CREATE TABLE LimitDegrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacity +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -624,7 +624,7 @@ CREATE TABLE LimitGrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -636,7 +636,7 @@ CREATE TABLE LimitDegrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacityDelta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -648,7 +648,7 @@ CREATE TABLE LimitGrowthNewCapacityDelta notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacityDelta +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -679,7 +679,7 @@ CREATE TABLE LimitStorageLevelFraction notes TEXT, PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE LimitActivity +CREATE TABLE limit_activity ( region TEXT, period INTEGER @@ -692,7 +692,7 @@ CREATE TABLE LimitActivity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitActivityShare +CREATE TABLE limit_activity_share ( region TEXT, period INTEGER @@ -705,7 +705,7 @@ CREATE TABLE LimitActivityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitAnnualCapacityFactor +CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER @@ -721,7 +721,7 @@ CREATE TABLE LimitAnnualCapacityFactor PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE LimitCapacity +CREATE TABLE limit_capacity ( region TEXT, period INTEGER @@ -734,18 +734,18 @@ CREATE TABLE LimitCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO LimitCapacity VALUES('electricville',2000,'EH','ge',0.2000000000000000111,'',''); -INSERT INTO LimitCapacity VALUES('electricville',2005,'EH','ge',0.2000000000000000111,'',''); -INSERT INTO LimitCapacity VALUES('electricville',2010,'EH','ge',0.2000000000000000111,'',''); -INSERT INTO LimitCapacity VALUES('electricville',2015,'EH','ge',0.2000000000000000111,'',''); -INSERT INTO LimitCapacity VALUES('electricville',2000,'EH','le',5.0,'',''); -INSERT INTO LimitCapacity VALUES('electricville',2005,'EH','le',5.0,'',''); -INSERT INTO LimitCapacity VALUES('electricville',2010,'EH','le',5.0,'',''); -INSERT INTO LimitCapacity VALUES('electricville',2015,'EH','le',5.0,'',''); -INSERT INTO LimitCapacity VALUES('electricville',2020,'EH','le',5.0,'',''); -INSERT INTO LimitCapacity VALUES('electricville',2025,'EH','le',5.0,'',''); -INSERT INTO LimitCapacity VALUES('electricville',2030,'EH','le',5.0,'',''); -CREATE TABLE LimitCapacityShare +INSERT INTO limit_capacity VALUES('electricville',2000,'EH','ge',0.2000000000000000111,'',''); +INSERT INTO limit_capacity VALUES('electricville',2005,'EH','ge',0.2000000000000000111,'',''); +INSERT INTO limit_capacity VALUES('electricville',2010,'EH','ge',0.2000000000000000111,'',''); +INSERT INTO limit_capacity VALUES('electricville',2015,'EH','ge',0.2000000000000000111,'',''); +INSERT INTO limit_capacity VALUES('electricville',2000,'EH','le',5.0,'',''); +INSERT INTO limit_capacity VALUES('electricville',2005,'EH','le',5.0,'',''); +INSERT INTO limit_capacity VALUES('electricville',2010,'EH','le',5.0,'',''); +INSERT INTO limit_capacity VALUES('electricville',2015,'EH','le',5.0,'',''); +INSERT INTO limit_capacity VALUES('electricville',2020,'EH','le',5.0,'',''); +INSERT INTO limit_capacity VALUES('electricville',2025,'EH','le',5.0,'',''); +INSERT INTO limit_capacity VALUES('electricville',2030,'EH','le',5.0,'',''); +CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER @@ -758,7 +758,7 @@ CREATE TABLE LimitCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitNewCapacity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER @@ -771,7 +771,7 @@ CREATE TABLE LimitNewCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitNewCapacityShare +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -784,7 +784,7 @@ CREATE TABLE LimitNewCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitResource +CREATE TABLE limit_resource ( region TEXT, tech_or_group TEXT, @@ -795,7 +795,7 @@ CREATE TABLE LimitResource notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitSeasonalCapacityFactor +CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES Region (region), @@ -811,7 +811,7 @@ CREATE TABLE LimitSeasonalCapacityFactor notes TEXT, PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE LimitTechInputSplit +CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER @@ -826,7 +826,7 @@ CREATE TABLE LimitTechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechInputSplitAnnual +CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER @@ -841,7 +841,7 @@ CREATE TABLE LimitTechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechOutputSplit +CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER @@ -856,7 +856,7 @@ CREATE TABLE LimitTechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitTechOutputSplitAnnual +CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER @@ -871,7 +871,7 @@ CREATE TABLE LimitTechOutputSplitAnnual notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitEmission +CREATE TABLE limit_emission ( region TEXT, period INTEGER @@ -1028,7 +1028,7 @@ CREATE TABLE OutputStorageLevel level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); -CREATE TABLE PlanningReserveMargin +CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY @@ -1036,7 +1036,7 @@ CREATE TABLE PlanningReserveMargin margin REAL, notes TEXT ); -CREATE TABLE RampDownHourly +CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT @@ -1045,7 +1045,7 @@ CREATE TABLE RampDownHourly notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUpHourly +CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT @@ -1061,7 +1061,7 @@ CREATE TABLE Region notes TEXT ); INSERT INTO Region VALUES('electricville',NULL); -CREATE TABLE ReserveCapacityDerate +CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER @@ -1077,7 +1077,7 @@ CREATE TABLE ReserveCapacityDerate CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE TimeSegmentFraction -( +( period INTEGER REFERENCES TimePeriod (period), season TEXT @@ -1122,7 +1122,7 @@ INSERT INTO TimeSegmentFraction VALUES(2045,'winter','day',0.3332999999999999852 INSERT INTO TimeSegmentFraction VALUES(2050,'inter','day',0.3332999999999999852,'# I-D'); INSERT INTO TimeSegmentFraction VALUES(2050,'summer','day',0.3332999999999999852,'# S-D'); INSERT INTO TimeSegmentFraction VALUES(2050,'winter','day',0.3332999999999999852,'# W-D'); -CREATE TABLE StorageDuration +CREATE TABLE storage_duration ( region TEXT, tech TEXT, @@ -1130,7 +1130,7 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE LifetimeSurvivalCurve +CREATE TABLE lifetime_survival_curve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -1222,7 +1222,7 @@ INSERT INTO TimeSeason VALUES(2045,3,'winter',NULL); INSERT INTO TimeSeason VALUES(2050,1,'inter',NULL); INSERT INTO TimeSeason VALUES(2050,2,'summer',NULL); INSERT INTO TimeSeason VALUES(2050,3,'winter',NULL); -CREATE TABLE TimeSeasonSequential +CREATE TABLE time_season_sequential ( period INTEGER REFERENCES TimePeriod (period), diff --git a/data_files/example_dbs/survival_curve.sql b/data_files/example_dbs/survival_curve.sql index df443dd87..b0c6560ad 100644 --- a/data_files/example_dbs/survival_curve.sql +++ b/data_files/example_dbs/survival_curve.sql @@ -19,7 +19,7 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -44,7 +44,7 @@ CREATE TABLE SectorLabel sector TEXT PRIMARY KEY, notes TEXT ); -CREATE TABLE CapacityCredit +CREATE TABLE capacity_credit ( region TEXT, period INTEGER @@ -57,7 +57,7 @@ CREATE TABLE CapacityCredit PRIMARY KEY (region, period, tech, vintage), CHECK (credit >= 0 AND credit <= 1) ); -CREATE TABLE CapacityFactorProcess +CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER @@ -74,7 +74,7 @@ CREATE TABLE CapacityFactorProcess PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE CapacityFactorTech +CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER @@ -123,7 +123,7 @@ INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('w','waste commodity'); INSERT INTO CommodityType VALUES('wa','waste annual commodity'); INSERT INTO CommodityType VALUES('wp','waste physical commodity'); -CREATE TABLE ConstructionInput +CREATE TABLE construction_input ( region TEXT, input_comm TEXT @@ -137,7 +137,7 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -CREATE TABLE CostEmission +CREATE TABLE cost_emission ( region TEXT, period INTEGER @@ -149,7 +149,7 @@ CREATE TABLE CostEmission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -CREATE TABLE CostFixed +CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -163,33 +163,33 @@ CREATE TABLE CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostFixed VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); -CREATE TABLE CostInvest +INSERT INTO cost_fixed VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); +CREATE TABLE cost_invest ( region TEXT, tech TEXT @@ -201,13 +201,13 @@ CREATE TABLE CostInvest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO CostInvest VALUES('region','tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('region','tech_future',2030,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('region','tech_future',2035,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('region','tech_future',2040,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('region','tech_future',2045,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('region','tech_future',2050,1.0,NULL,NULL); -CREATE TABLE CostVariable +INSERT INTO cost_invest VALUES('region','tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('region','tech_future',2030,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('region','tech_future',2035,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('region','tech_future',2040,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('region','tech_future',2045,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('region','tech_future',2050,1.0,NULL,NULL); +CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -221,32 +221,32 @@ CREATE TABLE CostVariable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostVariable VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); CREATE TABLE Demand ( region TEXT, @@ -281,7 +281,7 @@ CREATE TABLE DemandSpecificDistribution PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -CREATE TABLE EndOfLifeOutput +CREATE TABLE end_of_life_output ( region TEXT, tech TEXT @@ -295,7 +295,7 @@ CREATE TABLE EndOfLifeOutput notes TEXT, PRIMARY KEY (region, tech, vintage, output_comm) ); -CREATE TABLE Efficiency +CREATE TABLE efficiency ( region TEXT, input_comm TEXT @@ -311,15 +311,15 @@ CREATE TABLE Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO Efficiency VALUES('region','source','tech_ancient',1994,'demand',1.0,NULL); -INSERT INTO Efficiency VALUES('region','source','tech_old',2010,'demand',1.0,NULL); -INSERT INTO Efficiency VALUES('region','source','tech_current',2025,'demand',1.0,NULL); -INSERT INTO Efficiency VALUES('region','source','tech_future',2030,'demand',1.0,NULL); -INSERT INTO Efficiency VALUES('region','source','tech_future',2035,'demand',1.0,NULL); -INSERT INTO Efficiency VALUES('region','source','tech_future',2040,'demand',1.0,NULL); -INSERT INTO Efficiency VALUES('region','source','tech_future',2045,'demand',1.0,NULL); -INSERT INTO Efficiency VALUES('region','source','tech_future',2050,'demand',1.0,NULL); -CREATE TABLE EfficiencyVariable +INSERT INTO efficiency VALUES('region','source','tech_ancient',1994,'demand',1.0,NULL); +INSERT INTO efficiency VALUES('region','source','tech_old',2010,'demand',1.0,NULL); +INSERT INTO efficiency VALUES('region','source','tech_current',2025,'demand',1.0,NULL); +INSERT INTO efficiency VALUES('region','source','tech_future',2030,'demand',1.0,NULL); +INSERT INTO efficiency VALUES('region','source','tech_future',2035,'demand',1.0,NULL); +INSERT INTO efficiency VALUES('region','source','tech_future',2040,'demand',1.0,NULL); +INSERT INTO efficiency VALUES('region','source','tech_future',2045,'demand',1.0,NULL); +INSERT INTO efficiency VALUES('region','source','tech_future',2050,'demand',1.0,NULL); +CREATE TABLE efficiency_variable ( region TEXT, period INTEGER @@ -341,7 +341,7 @@ CREATE TABLE EfficiencyVariable PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -CREATE TABLE EmissionActivity +CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT @@ -359,7 +359,7 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -CREATE TABLE EmissionEmbodied +CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT @@ -373,7 +373,7 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE EmissionEndOfLife +CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT @@ -387,7 +387,7 @@ CREATE TABLE EmissionEndOfLife notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE ExistingCapacity +CREATE TABLE existing_capacity ( region TEXT, tech TEXT @@ -399,15 +399,15 @@ CREATE TABLE ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO ExistingCapacity VALUES('region','tech_ancient',1994,3.0,NULL,NULL); -INSERT INTO ExistingCapacity VALUES('region','tech_old',2010,0.7,NULL,NULL); +INSERT INTO existing_capacity VALUES('region','tech_ancient',1994,3.0,NULL,NULL); +INSERT INTO existing_capacity VALUES('region','tech_old',2010,0.7,NULL,NULL); CREATE TABLE TechGroup ( group_name TEXT PRIMARY KEY, notes TEXT ); -CREATE TABLE LoanLifetimeProcess +CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT @@ -418,7 +418,7 @@ CREATE TABLE LoanLifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LoanRate +CREATE TABLE loan_rate ( region TEXT, tech TEXT @@ -429,7 +429,7 @@ CREATE TABLE LoanRate notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeProcess +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -440,7 +440,7 @@ CREATE TABLE LifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeTech +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT @@ -449,10 +449,10 @@ CREATE TABLE LifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO LifetimeTech VALUES('region','tech_ancient',35.0,NULL); -INSERT INTO LifetimeTech VALUES('region','tech_old',35.0,NULL); -INSERT INTO LifetimeTech VALUES('region','tech_current',35.0,NULL); -INSERT INTO LifetimeTech VALUES('region','tech_future',35.0,NULL); +INSERT INTO lifetime_tech VALUES('region','tech_ancient',35.0,NULL); +INSERT INTO lifetime_tech VALUES('region','tech_old',35.0,NULL); +INSERT INTO lifetime_tech VALUES('region','tech_current',35.0,NULL); +INSERT INTO lifetime_tech VALUES('region','tech_future',35.0,NULL); CREATE TABLE Operator ( operator TEXT PRIMARY KEY, @@ -461,7 +461,7 @@ CREATE TABLE Operator INSERT INTO Operator VALUES('e','equal to'); INSERT INTO Operator VALUES('le','less than or equal to'); INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE LimitGrowthCapacity +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, @@ -473,7 +473,7 @@ CREATE TABLE LimitGrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthCapacity +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, @@ -485,7 +485,7 @@ CREATE TABLE LimitDegrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacity +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -497,7 +497,7 @@ CREATE TABLE LimitGrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -509,7 +509,7 @@ CREATE TABLE LimitDegrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacityDelta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -521,7 +521,7 @@ CREATE TABLE LimitGrowthNewCapacityDelta notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacityDelta +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -552,7 +552,7 @@ CREATE TABLE LimitStorageLevelFraction notes TEXT, PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE LimitActivity +CREATE TABLE limit_activity ( region TEXT, period INTEGER @@ -565,7 +565,7 @@ CREATE TABLE LimitActivity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitActivityShare +CREATE TABLE limit_activity_share ( region TEXT, period INTEGER @@ -578,7 +578,7 @@ CREATE TABLE LimitActivityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitAnnualCapacityFactor +CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER @@ -594,7 +594,7 @@ CREATE TABLE LimitAnnualCapacityFactor PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE LimitCapacity +CREATE TABLE limit_capacity ( region TEXT, period INTEGER @@ -607,7 +607,7 @@ CREATE TABLE LimitCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitCapacityShare +CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER @@ -620,7 +620,7 @@ CREATE TABLE LimitCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitNewCapacity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER @@ -633,7 +633,7 @@ CREATE TABLE LimitNewCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitNewCapacityShare +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -646,7 +646,7 @@ CREATE TABLE LimitNewCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitResource +CREATE TABLE limit_resource ( region TEXT, tech_or_group TEXT, @@ -657,7 +657,7 @@ CREATE TABLE LimitResource notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitSeasonalCapacityFactor +CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES Region (region), @@ -673,7 +673,7 @@ CREATE TABLE LimitSeasonalCapacityFactor notes TEXT, PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE LimitTechInputSplit +CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER @@ -688,7 +688,7 @@ CREATE TABLE LimitTechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechInputSplitAnnual +CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER @@ -703,7 +703,7 @@ CREATE TABLE LimitTechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechOutputSplit +CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER @@ -718,7 +718,7 @@ CREATE TABLE LimitTechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitTechOutputSplitAnnual +CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER @@ -733,7 +733,7 @@ CREATE TABLE LimitTechOutputSplitAnnual notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitEmission +CREATE TABLE limit_emission ( region TEXT, period INTEGER @@ -890,7 +890,7 @@ CREATE TABLE OutputStorageLevel level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); -CREATE TABLE PlanningReserveMargin +CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY @@ -898,7 +898,7 @@ CREATE TABLE PlanningReserveMargin margin REAL, notes TEXT ); -CREATE TABLE RampDownHourly +CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT @@ -907,7 +907,7 @@ CREATE TABLE RampDownHourly notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUpHourly +CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT @@ -923,7 +923,7 @@ CREATE TABLE Region notes TEXT ); INSERT INTO Region VALUES('region',NULL); -CREATE TABLE ReserveCapacityDerate +CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER @@ -939,7 +939,7 @@ CREATE TABLE ReserveCapacityDerate CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE TimeSegmentFraction -( +( period INTEGER REFERENCES TimePeriod (period), season TEXT @@ -957,7 +957,7 @@ INSERT INTO TimeSegmentFraction VALUES(2035,'s','d',1.0,NULL); INSERT INTO TimeSegmentFraction VALUES(2040,'s','d',1.0,NULL); INSERT INTO TimeSegmentFraction VALUES(2045,'s','d',1.0,NULL); INSERT INTO TimeSegmentFraction VALUES(2050,'s','d',1.0,NULL); -CREATE TABLE StorageDuration +CREATE TABLE storage_duration ( region TEXT, tech TEXT, @@ -965,7 +965,7 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE LifetimeSurvivalCurve +CREATE TABLE lifetime_survival_curve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -977,62 +977,62 @@ CREATE TABLE LifetimeSurvivalCurve notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO LifetimeSurvivalCurve VALUES('region',1994,'tech_ancient',1994,1,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',1999,'tech_ancient',1994,0.96999999999999992894,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2004,'tech_ancient',1994,0.88000000000000007105,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2009,'tech_ancient',1994,0.62000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2014,'tech_ancient',1994,0.27000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2019,'tech_ancient',1994,0.08,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2029,'tech_ancient',1994,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2010,'tech_old',2010,1,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2015,'tech_old',2010,0.96999999999999992894,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2020,'tech_old',2010,0.88000000000000007105,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2025,'tech_old',2010,0.62000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2030,'tech_old',2010,0.27000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_old',2010,0.08,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_old',2010,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2025,'tech_current',2025,1,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2030,'tech_current',2025,0.96999999999999992894,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_current',2025,0.88000000000000007105,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_current',2025,0.62000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_current',2025,0.27000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_current',2025,0.08,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_current',2025,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2030,'tech_future',2030,1,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_future',2030,0.96999999999999992894,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_future',2030,0.88000000000000007105,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2030,0.62000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2030,0.27000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2030,0.08,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2030,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_future',2035,1,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_future',2035,0.96999999999999992894,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2035,0.88000000000000007105,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2035,0.62000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2035,0.27000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2035,0.08,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2070,'tech_future',2035,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_future',2040,1,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2040,0.96999999999999992894,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2040,0.88000000000000007105,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2040,0.62000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2040,0.27000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2040,0.08,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2075,'tech_future',2040,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2045,1,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2045,0.96999999999999992894,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2045,0.88000000000000007105,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2045,0.62000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2045,0.27000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2070,'tech_future',2045,0.08,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2080,'tech_future',2045,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2050,1,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2050,0.96999999999999992894,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2050,0.88000000000000007105,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2050,0.62000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2070,'tech_future',2050,0.27000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2075,'tech_future',2050,0.08,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2085,'tech_future',2050,0.0,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',1994,'tech_ancient',1994,1,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',1999,'tech_ancient',1994,0.96999999999999992894,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2004,'tech_ancient',1994,0.88000000000000007105,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2009,'tech_ancient',1994,0.62000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2014,'tech_ancient',1994,0.27000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2019,'tech_ancient',1994,0.08,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2029,'tech_ancient',1994,0.0,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2010,'tech_old',2010,1,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2015,'tech_old',2010,0.96999999999999992894,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2020,'tech_old',2010,0.88000000000000007105,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2025,'tech_old',2010,0.62000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2030,'tech_old',2010,0.27000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2035,'tech_old',2010,0.08,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_old',2010,0.0,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2025,'tech_current',2025,1,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2030,'tech_current',2025,0.96999999999999992894,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2035,'tech_current',2025,0.88000000000000007105,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2040,'tech_current',2025,0.62000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_current',2025,0.27000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_current',2025,0.08,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2060,'tech_current',2025,0.0,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2030,'tech_future',2030,1,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2035,'tech_future',2030,0.96999999999999992894,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2040,'tech_future',2030,0.88000000000000007105,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_future',2030,0.62000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_future',2030,0.27000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2055,'tech_future',2030,0.08,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2065,'tech_future',2030,0.0,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2035,'tech_future',2035,1,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2040,'tech_future',2035,0.96999999999999992894,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_future',2035,0.88000000000000007105,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_future',2035,0.62000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2055,'tech_future',2035,0.27000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2060,'tech_future',2035,0.08,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2070,'tech_future',2035,0.0,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2040,'tech_future',2040,1,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_future',2040,0.96999999999999992894,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_future',2040,0.88000000000000007105,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2055,'tech_future',2040,0.62000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2060,'tech_future',2040,0.27000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2065,'tech_future',2040,0.08,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2075,'tech_future',2040,0.0,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_future',2045,1,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_future',2045,0.96999999999999992894,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2055,'tech_future',2045,0.88000000000000007105,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2060,'tech_future',2045,0.62000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2065,'tech_future',2045,0.27000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2070,'tech_future',2045,0.08,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2080,'tech_future',2045,0.0,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_future',2050,1,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2055,'tech_future',2050,0.96999999999999992894,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2060,'tech_future',2050,0.88000000000000007105,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2065,'tech_future',2050,0.62000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2070,'tech_future',2050,0.27000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2075,'tech_future',2050,0.08,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2085,'tech_future',2050,0.0,NULL); CREATE TABLE TechnologyType ( label TEXT @@ -1082,7 +1082,7 @@ INSERT INTO TimeSeason VALUES(2035,2,'s',NULL); INSERT INTO TimeSeason VALUES(2040,3,'s',NULL); INSERT INTO TimeSeason VALUES(2045,4,'s',NULL); INSERT INTO TimeSeason VALUES(2050,5,'s',NULL); -CREATE TABLE TimeSeasonSequential +CREATE TABLE time_season_sequential ( period INTEGER REFERENCES TimePeriod (period), diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index 8933934ea..32f88b035 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -18,7 +18,7 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); CREATE TABLE OutputDualVariable ( @@ -53,7 +53,7 @@ INSERT INTO SectorLabel VALUES('transport',NULL); INSERT INTO SectorLabel VALUES('commercial',NULL); INSERT INTO SectorLabel VALUES('residential',NULL); INSERT INTO SectorLabel VALUES('industrial',NULL); -CREATE TABLE CapacityCredit +CREATE TABLE capacity_credit ( region TEXT, period INTEGER @@ -66,7 +66,7 @@ CREATE TABLE CapacityCredit PRIMARY KEY (region, period, tech, vintage), CHECK (credit >= 0 AND credit <= 1) ); -CREATE TABLE CapacityFactorProcess +CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER @@ -83,7 +83,7 @@ CREATE TABLE CapacityFactorProcess PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE CapacityFactorTech +CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER @@ -99,54 +99,54 @@ CREATE TABLE CapacityFactorTech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'spring','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'summer','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'fall','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'winter','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'winter','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'spring','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'summer','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'fall','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'winter','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'winter','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'spring','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'summer','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'fall','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'winter','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'winter','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'spring','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'summer','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'fall','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'winter','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'winter','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'spring','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'summer','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'fall','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'winter','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'winter','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'spring','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'summer','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'fall','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'winter','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'winter','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2020,'spring','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2020,'spring','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2020,'summer','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2020,'summer','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2020,'fall','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2020,'fall','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2020,'winter','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2020,'winter','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2020,'spring','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2020,'spring','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2020,'summer','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2020,'summer','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2020,'fall','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2020,'fall','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2020,'winter','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2020,'winter','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2025,'spring','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2025,'spring','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2025,'summer','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2025,'summer','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2025,'fall','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2025,'fall','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2025,'winter','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2025,'winter','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2025,'spring','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2025,'spring','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2025,'summer','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2025,'summer','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2025,'fall','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2025,'fall','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2025,'winter','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2025,'winter','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2030,'spring','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2030,'spring','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2030,'summer','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2030,'summer','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2030,'fall','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2030,'fall','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2030,'winter','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2030,'winter','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2030,'spring','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2030,'spring','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2030,'summer','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2030,'summer','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2030,'fall','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2030,'fall','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2030,'winter','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2030,'winter','night','E_SOLPV',0.0,''); CREATE TABLE CapacityToActivity ( region TEXT, @@ -223,7 +223,7 @@ INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); -CREATE TABLE ConstructionInput +CREATE TABLE construction_input ( region TEXT, input_comm TEXT @@ -237,7 +237,7 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -CREATE TABLE CostEmission +CREATE TABLE cost_emission ( region TEXT, period INTEGER @@ -249,7 +249,7 @@ CREATE TABLE CostEmission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -CREATE TABLE CostFixed +CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -263,55 +263,55 @@ CREATE TABLE CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostFixed VALUES('R1',2020,'E_NGCC',2020,30.60000000000000142,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_NGCC',2020,9.77999999999999937,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_NGCC',2025,9.77999999999999937,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2020,9.77999999999999937,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2025,9.77999999999999937,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2030,9.77999999999999937,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2020,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_SOLPV',2025,9.099999999999999645,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2025,9.099999999999999645,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2030,9.099999999999999645,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2020,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_NUCLEAR',2025,98.0999999999999801,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2025,98.0999999999999801,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2030,98.0999999999999801,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2020,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_BATT',2025,7.049999999999999823,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2025,7.049999999999999823,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2030,7.049999999999999823,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2020,'E_NGCC',2020,24.48000000000000042,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_NGCC',2020,7.823999999999999844,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_NGCC',2025,7.823999999999999844,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2020,7.823999999999999844,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2025,7.823999999999999844,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2030,7.823999999999999844,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2020,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_SOLPV',2025,7.280000000000000248,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2025,7.280000000000000248,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2030,7.280000000000000248,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2020,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_NUCLEAR',2025,78.48000000000000397,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2025,78.48000000000000397,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2030,78.48000000000000397,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2020,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_BATT',2025,5.639999999999999681,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2025,5.639999999999999681,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2030,5.639999999999999681,'$M/GWyr',''); -CREATE TABLE CostInvest +INSERT INTO cost_fixed VALUES('R1',2020,'E_NGCC',2020,30.60000000000000142,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2025,'E_NGCC',2020,9.77999999999999937,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2025,'E_NGCC',2025,9.77999999999999937,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_NGCC',2020,9.77999999999999937,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_NGCC',2025,9.77999999999999937,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_NGCC',2030,9.77999999999999937,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2020,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2025,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2025,'E_SOLPV',2025,9.099999999999999645,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_SOLPV',2025,9.099999999999999645,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_SOLPV',2030,9.099999999999999645,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2020,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2025,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2025,'E_NUCLEAR',2025,98.0999999999999801,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_NUCLEAR',2025,98.0999999999999801,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_NUCLEAR',2030,98.0999999999999801,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2020,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2025,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2025,'E_BATT',2025,7.049999999999999823,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_BATT',2025,7.049999999999999823,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_BATT',2030,7.049999999999999823,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2020,'E_NGCC',2020,24.48000000000000042,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2025,'E_NGCC',2020,7.823999999999999844,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2025,'E_NGCC',2025,7.823999999999999844,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_NGCC',2020,7.823999999999999844,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_NGCC',2025,7.823999999999999844,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_NGCC',2030,7.823999999999999844,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2020,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2025,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2025,'E_SOLPV',2025,7.280000000000000248,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_SOLPV',2025,7.280000000000000248,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_SOLPV',2030,7.280000000000000248,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2020,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2025,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2025,'E_NUCLEAR',2025,78.48000000000000397,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_NUCLEAR',2025,78.48000000000000397,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_NUCLEAR',2030,78.48000000000000397,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2020,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2025,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2025,'E_BATT',2025,5.639999999999999681,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_BATT',2025,5.639999999999999681,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_BATT',2030,5.639999999999999681,'$M/GWyr',''); +CREATE TABLE cost_invest ( region TEXT, tech TEXT @@ -323,61 +323,61 @@ CREATE TABLE CostInvest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO CostInvest VALUES('R1','E_NGCC',2020,1050.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','E_NGCC',2025,1025.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','E_NGCC',2030,1000.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','E_SOLPV',2020,900.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','E_SOLPV',2025,560.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','E_SOLPV',2030,800.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','E_NUCLEAR',2020,6145.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','E_NUCLEAR',2025,6045.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','E_NUCLEAR',2030,5890.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','E_BATT',2020,1150.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','E_BATT',2025,720.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','E_BATT',2030,480.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','T_GSL',2020,2570.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R1','T_GSL',2025,2700.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R1','T_GSL',2030,2700.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R1','T_DSL',2020,2715.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R1','T_DSL',2025,2810.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R1','T_DSL',2030,2810.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R1','T_EV',2020,3100.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R1','T_EV',2025,3030.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R1','T_EV',2030,2925.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R1','R_EH',2020,4.099999999999999644,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_EH',2025,4.099999999999999644,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_EH',2030,4.099999999999999644,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_NGH',2020,7.599999999999999645,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_NGH',2025,7.599999999999999645,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_NGH',2030,7.599999999999999645,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R2','E_NGCC',2020,840.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','E_NGCC',2025,820.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','E_NGCC',2030,800.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','E_SOLPV',2020,720.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','E_SOLPV',2025,448.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','E_SOLPV',2030,640.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','E_NUCLEAR',2020,4916.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','E_NUCLEAR',2025,4836.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','E_NUCLEAR',2030,4712.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','E_BATT',2020,920.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','E_BATT',2025,576.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','E_BATT',2030,384.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','T_GSL',2020,2056.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R2','T_GSL',2025,2160.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R2','T_GSL',2030,2160.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R2','T_DSL',2020,2172.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R2','T_DSL',2025,2248.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R2','T_DSL',2030,2248.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R2','T_EV',2020,2480.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R2','T_EV',2025,2424.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R2','T_EV',2030,2340.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R2','R_EH',2020,3.279999999999999805,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R2','R_EH',2025,3.279999999999999805,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R2','R_EH',2030,3.279999999999999805,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R2','R_NGH',2020,6.080000000000000071,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R2','R_NGH',2025,6.080000000000000071,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R2','R_NGH',2030,6.080000000000000071,'$/PJ/yr',''); -CREATE TABLE CostVariable +INSERT INTO cost_invest VALUES('R1','E_NGCC',2020,1050.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','E_NGCC',2025,1025.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','E_NGCC',2030,1000.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','E_SOLPV',2020,900.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','E_SOLPV',2025,560.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','E_SOLPV',2030,800.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','E_NUCLEAR',2020,6145.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','E_NUCLEAR',2025,6045.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','E_NUCLEAR',2030,5890.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','E_BATT',2020,1150.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','E_BATT',2025,720.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','E_BATT',2030,480.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','T_GSL',2020,2570.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R1','T_GSL',2025,2700.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R1','T_GSL',2030,2700.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R1','T_DSL',2020,2715.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R1','T_DSL',2025,2810.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R1','T_DSL',2030,2810.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R1','T_EV',2020,3100.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R1','T_EV',2025,3030.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R1','T_EV',2030,2925.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R1','R_EH',2020,4.099999999999999644,'$/PJ/yr',''); +INSERT INTO cost_invest VALUES('R1','R_EH',2025,4.099999999999999644,'$/PJ/yr',''); +INSERT INTO cost_invest VALUES('R1','R_EH',2030,4.099999999999999644,'$/PJ/yr',''); +INSERT INTO cost_invest VALUES('R1','R_NGH',2020,7.599999999999999645,'$/PJ/yr',''); +INSERT INTO cost_invest VALUES('R1','R_NGH',2025,7.599999999999999645,'$/PJ/yr',''); +INSERT INTO cost_invest VALUES('R1','R_NGH',2030,7.599999999999999645,'$/PJ/yr',''); +INSERT INTO cost_invest VALUES('R2','E_NGCC',2020,840.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','E_NGCC',2025,820.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','E_NGCC',2030,800.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','E_SOLPV',2020,720.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','E_SOLPV',2025,448.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','E_SOLPV',2030,640.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','E_NUCLEAR',2020,4916.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','E_NUCLEAR',2025,4836.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','E_NUCLEAR',2030,4712.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','E_BATT',2020,920.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','E_BATT',2025,576.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','E_BATT',2030,384.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','T_GSL',2020,2056.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R2','T_GSL',2025,2160.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R2','T_GSL',2030,2160.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R2','T_DSL',2020,2172.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R2','T_DSL',2025,2248.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R2','T_DSL',2030,2248.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R2','T_EV',2020,2480.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R2','T_EV',2025,2424.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R2','T_EV',2030,2340.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R2','R_EH',2020,3.279999999999999805,'$/PJ/yr',''); +INSERT INTO cost_invest VALUES('R2','R_EH',2025,3.279999999999999805,'$/PJ/yr',''); +INSERT INTO cost_invest VALUES('R2','R_EH',2030,3.279999999999999805,'$/PJ/yr',''); +INSERT INTO cost_invest VALUES('R2','R_NGH',2020,6.080000000000000071,'$/PJ/yr',''); +INSERT INTO cost_invest VALUES('R2','R_NGH',2025,6.080000000000000071,'$/PJ/yr',''); +INSERT INTO cost_invest VALUES('R2','R_NGH',2030,6.080000000000000071,'$/PJ/yr',''); +CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -391,60 +391,60 @@ CREATE TABLE CostVariable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostVariable VALUES('R1',2020,'S_IMPETH',2020,32.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'S_IMPETH',2020,32.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'S_IMPETH',2020,32.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2020,'S_IMPOIL',2020,20.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'S_IMPOIL',2020,20.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'S_IMPOIL',2020,20.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2020,'S_IMPNG',2020,4.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'S_IMPNG',2020,4.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'S_IMPNG',2020,4.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2020,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2020,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'E_NGCC',2025,1.699999999999999956,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2025,1.699999999999999956,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2030,1.800000000000000044,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2020,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'E_NUCLEAR',2025,0.25,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2025,0.25,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2030,0.2600000000000000088,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'E_NGCC',2025,1.360000000000000097,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2025,1.360000000000000097,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2030,1.439999999999999947,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'E_NUCLEAR',2025,0.2000000000000000111,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2025,0.2000000000000000111,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2030,0.2080000000000000183,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1-R2',2020,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1-R2',2025,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1-R2',2030,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2-R1',2020,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2-R1',2025,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2-R1',2030,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2020,'S_IMPETH',2020,32.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2025,'S_IMPETH',2020,32.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2030,'S_IMPETH',2020,32.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2020,'S_IMPOIL',2020,20.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2025,'S_IMPOIL',2020,20.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2030,'S_IMPOIL',2020,20.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2020,'S_IMPNG',2020,4.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2025,'S_IMPNG',2020,4.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2030,'S_IMPNG',2020,4.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2020,'S_OILREF',2020,1.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2025,'S_OILREF',2020,1.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2030,'S_OILREF',2020,1.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2020,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2025,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2025,'E_NGCC',2025,1.699999999999999956,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2030,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2030,'E_NGCC',2025,1.699999999999999956,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2030,'E_NGCC',2030,1.800000000000000044,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2020,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2025,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2025,'E_NUCLEAR',2025,0.25,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2030,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2030,'E_NUCLEAR',2025,0.25,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2030,'E_NUCLEAR',2030,0.2600000000000000088,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2020,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2025,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2030,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2020,'S_IMPOIL',2020,16.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2025,'S_IMPOIL',2020,16.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2030,'S_IMPOIL',2020,16.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2020,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2025,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2030,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2020,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2025,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2030,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2020,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2025,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2025,'E_NGCC',2025,1.360000000000000097,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2030,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2030,'E_NGCC',2025,1.360000000000000097,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2030,'E_NGCC',2030,1.439999999999999947,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2020,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2025,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2025,'E_NUCLEAR',2025,0.2000000000000000111,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2030,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2030,'E_NUCLEAR',2025,0.2000000000000000111,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2030,'E_NUCLEAR',2030,0.2080000000000000183,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1-R2',2020,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1-R2',2025,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1-R2',2030,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2-R1',2020,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2-R1',2025,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2-R1',2030,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); CREATE TABLE Demand ( region TEXT, @@ -533,7 +533,7 @@ INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'fall','day','RH',0.0500 INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'fall','night','RH',0.1000000000000000055,''); INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'winter','day','RH',0.2999999999999999889,''); INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'winter','night','RH',0.4000000000000000222,''); -CREATE TABLE EndOfLifeOutput +CREATE TABLE end_of_life_output ( region TEXT, tech TEXT @@ -547,7 +547,7 @@ CREATE TABLE EndOfLifeOutput notes TEXT, PRIMARY KEY (region, tech, vintage, output_comm) ); -CREATE TABLE Efficiency +CREATE TABLE efficiency ( region TEXT, input_comm TEXT @@ -563,81 +563,81 @@ CREATE TABLE Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO Efficiency VALUES('R1','ethos','S_IMPETH',2020,'ETH',1.0,''); -INSERT INTO Efficiency VALUES('R1','ethos','S_IMPOIL',2020,'OIL',1.0,''); -INSERT INTO Efficiency VALUES('R1','ethos','S_IMPNG',2020,'NG',1.0,''); -INSERT INTO Efficiency VALUES('R1','ethos','S_IMPURN',2020,'URN',1.0,''); -INSERT INTO Efficiency VALUES('R1','OIL','S_OILREF',2020,'GSL',1.0,''); -INSERT INTO Efficiency VALUES('R1','OIL','S_OILREF',2020,'DSL',1.0,''); -INSERT INTO Efficiency VALUES('R1','ETH','T_BLND',2020,'E10',1.0,''); -INSERT INTO Efficiency VALUES('R1','GSL','T_BLND',2020,'E10',1.0,''); -INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2020,'ELC',0.5500000000000000444,''); -INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2025,'ELC',0.5500000000000000444,''); -INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2030,'ELC',0.5500000000000000444,''); -INSERT INTO Efficiency VALUES('R1','SOL','E_SOLPV',2020,'ELC',1.0,''); -INSERT INTO Efficiency VALUES('R1','SOL','E_SOLPV',2025,'ELC',1.0,''); -INSERT INTO Efficiency VALUES('R1','SOL','E_SOLPV',2030,'ELC',1.0,''); -INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2015,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2020,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2025,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2030,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2020,'ELC',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2025,'ELC',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2030,'ELC',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R1','E10','T_GSL',2020,'VMT',0.25,''); -INSERT INTO Efficiency VALUES('R1','E10','T_GSL',2025,'VMT',0.25,''); -INSERT INTO Efficiency VALUES('R1','E10','T_GSL',2030,'VMT',0.25,''); -INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2020,'VMT',0.2999999999999999889,''); -INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2025,'VMT',0.2999999999999999889,''); -INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2030,'VMT',0.2999999999999999889,''); -INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2020,'VMT',0.8900000000000000133,''); -INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2025,'VMT',0.8900000000000000133,''); -INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2030,'VMT',0.8900000000000000133,''); -INSERT INTO Efficiency VALUES('R1','ELC','R_EH',2020,'RH',1.0,''); -INSERT INTO Efficiency VALUES('R1','ELC','R_EH',2025,'RH',1.0,''); -INSERT INTO Efficiency VALUES('R1','ELC','R_EH',2030,'RH',1.0,''); -INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2020,'RH',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2025,'RH',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2030,'RH',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R2','ethos','S_IMPETH',2020,'ETH',1.0,''); -INSERT INTO Efficiency VALUES('R2','ethos','S_IMPOIL',2020,'OIL',1.0,''); -INSERT INTO Efficiency VALUES('R2','ethos','S_IMPNG',2020,'NG',1.0,''); -INSERT INTO Efficiency VALUES('R2','ethos','S_IMPURN',2020,'URN',1.0,''); -INSERT INTO Efficiency VALUES('R2','OIL','S_OILREF',2020,'GSL',1.0,''); -INSERT INTO Efficiency VALUES('R2','OIL','S_OILREF',2020,'DSL',1.0,''); -INSERT INTO Efficiency VALUES('R2','ETH','T_BLND',2020,'E10',1.0,''); -INSERT INTO Efficiency VALUES('R2','GSL','T_BLND',2020,'E10',1.0,''); -INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2020,'ELC',0.5500000000000000444,''); -INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2025,'ELC',0.5500000000000000444,''); -INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2030,'ELC',0.5500000000000000444,''); -INSERT INTO Efficiency VALUES('R2','SOL','E_SOLPV',2020,'ELC',1.0,''); -INSERT INTO Efficiency VALUES('R2','SOL','E_SOLPV',2025,'ELC',1.0,''); -INSERT INTO Efficiency VALUES('R2','SOL','E_SOLPV',2030,'ELC',1.0,''); -INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2015,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2020,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2025,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2030,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2020,'ELC',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2025,'ELC',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2030,'ELC',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R2','E10','T_GSL',2020,'VMT',0.25,''); -INSERT INTO Efficiency VALUES('R2','E10','T_GSL',2025,'VMT',0.25,''); -INSERT INTO Efficiency VALUES('R2','E10','T_GSL',2030,'VMT',0.25,''); -INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2020,'VMT',0.2999999999999999889,''); -INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2025,'VMT',0.2999999999999999889,''); -INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2030,'VMT',0.2999999999999999889,''); -INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2020,'VMT',0.8900000000000000133,''); -INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2025,'VMT',0.8900000000000000133,''); -INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2030,'VMT',0.8900000000000000133,''); -INSERT INTO Efficiency VALUES('R2','ELC','R_EH',2020,'RH',1.0,''); -INSERT INTO Efficiency VALUES('R2','ELC','R_EH',2025,'RH',1.0,''); -INSERT INTO Efficiency VALUES('R2','ELC','R_EH',2030,'RH',1.0,''); -INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2020,'RH',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2025,'RH',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2030,'RH',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R1-R2','ELC','E_TRANS',2015,'ELC',0.9000000000000000222,''); -INSERT INTO Efficiency VALUES('R2-R1','ELC','E_TRANS',2015,'ELC',0.9000000000000000222,''); -CREATE TABLE EfficiencyVariable +INSERT INTO efficiency VALUES('R1','ethos','S_IMPETH',2020,'ETH',1.0,''); +INSERT INTO efficiency VALUES('R1','ethos','S_IMPOIL',2020,'OIL',1.0,''); +INSERT INTO efficiency VALUES('R1','ethos','S_IMPNG',2020,'NG',1.0,''); +INSERT INTO efficiency VALUES('R1','ethos','S_IMPURN',2020,'URN',1.0,''); +INSERT INTO efficiency VALUES('R1','OIL','S_OILREF',2020,'GSL',1.0,''); +INSERT INTO efficiency VALUES('R1','OIL','S_OILREF',2020,'DSL',1.0,''); +INSERT INTO efficiency VALUES('R1','ETH','T_BLND',2020,'E10',1.0,''); +INSERT INTO efficiency VALUES('R1','GSL','T_BLND',2020,'E10',1.0,''); +INSERT INTO efficiency VALUES('R1','NG','E_NGCC',2020,'ELC',0.5500000000000000444,''); +INSERT INTO efficiency VALUES('R1','NG','E_NGCC',2025,'ELC',0.5500000000000000444,''); +INSERT INTO efficiency VALUES('R1','NG','E_NGCC',2030,'ELC',0.5500000000000000444,''); +INSERT INTO efficiency VALUES('R1','SOL','E_SOLPV',2020,'ELC',1.0,''); +INSERT INTO efficiency VALUES('R1','SOL','E_SOLPV',2025,'ELC',1.0,''); +INSERT INTO efficiency VALUES('R1','SOL','E_SOLPV',2030,'ELC',1.0,''); +INSERT INTO efficiency VALUES('R1','URN','E_NUCLEAR',2015,'ELC',0.4000000000000000222,''); +INSERT INTO efficiency VALUES('R1','URN','E_NUCLEAR',2020,'ELC',0.4000000000000000222,''); +INSERT INTO efficiency VALUES('R1','URN','E_NUCLEAR',2025,'ELC',0.4000000000000000222,''); +INSERT INTO efficiency VALUES('R1','URN','E_NUCLEAR',2030,'ELC',0.4000000000000000222,''); +INSERT INTO efficiency VALUES('R1','ELC','E_BATT',2020,'ELC',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R1','ELC','E_BATT',2025,'ELC',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R1','ELC','E_BATT',2030,'ELC',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R1','E10','T_GSL',2020,'VMT',0.25,''); +INSERT INTO efficiency VALUES('R1','E10','T_GSL',2025,'VMT',0.25,''); +INSERT INTO efficiency VALUES('R1','E10','T_GSL',2030,'VMT',0.25,''); +INSERT INTO efficiency VALUES('R1','DSL','T_DSL',2020,'VMT',0.2999999999999999889,''); +INSERT INTO efficiency VALUES('R1','DSL','T_DSL',2025,'VMT',0.2999999999999999889,''); +INSERT INTO efficiency VALUES('R1','DSL','T_DSL',2030,'VMT',0.2999999999999999889,''); +INSERT INTO efficiency VALUES('R1','ELC','T_EV',2020,'VMT',0.8900000000000000133,''); +INSERT INTO efficiency VALUES('R1','ELC','T_EV',2025,'VMT',0.8900000000000000133,''); +INSERT INTO efficiency VALUES('R1','ELC','T_EV',2030,'VMT',0.8900000000000000133,''); +INSERT INTO efficiency VALUES('R1','ELC','R_EH',2020,'RH',1.0,''); +INSERT INTO efficiency VALUES('R1','ELC','R_EH',2025,'RH',1.0,''); +INSERT INTO efficiency VALUES('R1','ELC','R_EH',2030,'RH',1.0,''); +INSERT INTO efficiency VALUES('R1','NG','R_NGH',2020,'RH',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R1','NG','R_NGH',2025,'RH',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R1','NG','R_NGH',2030,'RH',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R2','ethos','S_IMPETH',2020,'ETH',1.0,''); +INSERT INTO efficiency VALUES('R2','ethos','S_IMPOIL',2020,'OIL',1.0,''); +INSERT INTO efficiency VALUES('R2','ethos','S_IMPNG',2020,'NG',1.0,''); +INSERT INTO efficiency VALUES('R2','ethos','S_IMPURN',2020,'URN',1.0,''); +INSERT INTO efficiency VALUES('R2','OIL','S_OILREF',2020,'GSL',1.0,''); +INSERT INTO efficiency VALUES('R2','OIL','S_OILREF',2020,'DSL',1.0,''); +INSERT INTO efficiency VALUES('R2','ETH','T_BLND',2020,'E10',1.0,''); +INSERT INTO efficiency VALUES('R2','GSL','T_BLND',2020,'E10',1.0,''); +INSERT INTO efficiency VALUES('R2','NG','E_NGCC',2020,'ELC',0.5500000000000000444,''); +INSERT INTO efficiency VALUES('R2','NG','E_NGCC',2025,'ELC',0.5500000000000000444,''); +INSERT INTO efficiency VALUES('R2','NG','E_NGCC',2030,'ELC',0.5500000000000000444,''); +INSERT INTO efficiency VALUES('R2','SOL','E_SOLPV',2020,'ELC',1.0,''); +INSERT INTO efficiency VALUES('R2','SOL','E_SOLPV',2025,'ELC',1.0,''); +INSERT INTO efficiency VALUES('R2','SOL','E_SOLPV',2030,'ELC',1.0,''); +INSERT INTO efficiency VALUES('R2','URN','E_NUCLEAR',2015,'ELC',0.4000000000000000222,''); +INSERT INTO efficiency VALUES('R2','URN','E_NUCLEAR',2020,'ELC',0.4000000000000000222,''); +INSERT INTO efficiency VALUES('R2','URN','E_NUCLEAR',2025,'ELC',0.4000000000000000222,''); +INSERT INTO efficiency VALUES('R2','URN','E_NUCLEAR',2030,'ELC',0.4000000000000000222,''); +INSERT INTO efficiency VALUES('R2','ELC','E_BATT',2020,'ELC',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R2','ELC','E_BATT',2025,'ELC',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R2','ELC','E_BATT',2030,'ELC',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R2','E10','T_GSL',2020,'VMT',0.25,''); +INSERT INTO efficiency VALUES('R2','E10','T_GSL',2025,'VMT',0.25,''); +INSERT INTO efficiency VALUES('R2','E10','T_GSL',2030,'VMT',0.25,''); +INSERT INTO efficiency VALUES('R2','DSL','T_DSL',2020,'VMT',0.2999999999999999889,''); +INSERT INTO efficiency VALUES('R2','DSL','T_DSL',2025,'VMT',0.2999999999999999889,''); +INSERT INTO efficiency VALUES('R2','DSL','T_DSL',2030,'VMT',0.2999999999999999889,''); +INSERT INTO efficiency VALUES('R2','ELC','T_EV',2020,'VMT',0.8900000000000000133,''); +INSERT INTO efficiency VALUES('R2','ELC','T_EV',2025,'VMT',0.8900000000000000133,''); +INSERT INTO efficiency VALUES('R2','ELC','T_EV',2030,'VMT',0.8900000000000000133,''); +INSERT INTO efficiency VALUES('R2','ELC','R_EH',2020,'RH',1.0,''); +INSERT INTO efficiency VALUES('R2','ELC','R_EH',2025,'RH',1.0,''); +INSERT INTO efficiency VALUES('R2','ELC','R_EH',2030,'RH',1.0,''); +INSERT INTO efficiency VALUES('R2','NG','R_NGH',2020,'RH',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R2','NG','R_NGH',2025,'RH',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R2','NG','R_NGH',2030,'RH',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R1-R2','ELC','E_TRANS',2015,'ELC',0.9000000000000000222,''); +INSERT INTO efficiency VALUES('R2-R1','ELC','E_TRANS',2015,'ELC',0.9000000000000000222,''); +CREATE TABLE efficiency_variable ( region TEXT, period INTEGER @@ -659,7 +659,7 @@ CREATE TABLE EfficiencyVariable PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -CREATE TABLE EmissionActivity +CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT @@ -677,13 +677,13 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('R1','CO2','ethos','S_IMPNG',2020,'NG',50.29999999999999005,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R1','CO2','OIL','S_OILREF',2020,'GSL',67.20000000000000284,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R1','CO2','OIL','S_OILREF',2020,'DSL',69.40000000000000569,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R2','CO2','ethos','S_IMPNG',2020,'NG',50.29999999999999005,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R2','CO2','OIL','S_OILREF',2020,'GSL',67.20000000000000284,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R2','CO2','OIL','S_OILREF',2020,'DSL',69.40000000000000569,'kT/PJ','taken from MIT Energy Fact Sheet'); -CREATE TABLE EmissionEmbodied +INSERT INTO emission_activity VALUES('R1','CO2','ethos','S_IMPNG',2020,'NG',50.29999999999999005,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO emission_activity VALUES('R1','CO2','OIL','S_OILREF',2020,'GSL',67.20000000000000284,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO emission_activity VALUES('R1','CO2','OIL','S_OILREF',2020,'DSL',69.40000000000000569,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO emission_activity VALUES('R2','CO2','ethos','S_IMPNG',2020,'NG',50.29999999999999005,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO emission_activity VALUES('R2','CO2','OIL','S_OILREF',2020,'GSL',67.20000000000000284,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO emission_activity VALUES('R2','CO2','OIL','S_OILREF',2020,'DSL',69.40000000000000569,'kT/PJ','taken from MIT Energy Fact Sheet'); +CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT @@ -697,7 +697,7 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE EmissionEndOfLife +CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT @@ -711,7 +711,7 @@ CREATE TABLE EmissionEndOfLife notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE ExistingCapacity +CREATE TABLE existing_capacity ( region TEXT, tech TEXT @@ -723,17 +723,17 @@ CREATE TABLE ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO ExistingCapacity VALUES('R1','E_NUCLEAR',2015,0.07000000000000000667,'GW',''); -INSERT INTO ExistingCapacity VALUES('R2','E_NUCLEAR',2015,0.02999999999999999889,'GW',''); -INSERT INTO ExistingCapacity VALUES('R1-R2','E_TRANS',2015,10.0,'GW',''); -INSERT INTO ExistingCapacity VALUES('R2-R1','E_TRANS',2015,10.0,'GW',''); +INSERT INTO existing_capacity VALUES('R1','E_NUCLEAR',2015,0.07000000000000000667,'GW',''); +INSERT INTO existing_capacity VALUES('R2','E_NUCLEAR',2015,0.02999999999999999889,'GW',''); +INSERT INTO existing_capacity VALUES('R1-R2','E_TRANS',2015,10.0,'GW',''); +INSERT INTO existing_capacity VALUES('R2-R1','E_TRANS',2015,10.0,'GW',''); CREATE TABLE TechGroup ( group_name TEXT PRIMARY KEY, notes TEXT ); -CREATE TABLE LoanLifetimeProcess +CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT @@ -744,7 +744,7 @@ CREATE TABLE LoanLifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LoanRate +CREATE TABLE loan_rate ( region TEXT, tech TEXT @@ -755,7 +755,7 @@ CREATE TABLE LoanRate notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeProcess +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -766,7 +766,7 @@ CREATE TABLE LifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeTech +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT @@ -775,38 +775,38 @@ CREATE TABLE LifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO LifetimeTech VALUES('R1','S_IMPETH',100.0,''); -INSERT INTO LifetimeTech VALUES('R1','S_IMPOIL',100.0,''); -INSERT INTO LifetimeTech VALUES('R1','S_IMPNG',100.0,''); -INSERT INTO LifetimeTech VALUES('R1','S_IMPURN',100.0,''); -INSERT INTO LifetimeTech VALUES('R1','S_OILREF',100.0,''); -INSERT INTO LifetimeTech VALUES('R1','E_NGCC',30.0,''); -INSERT INTO LifetimeTech VALUES('R1','E_SOLPV',30.0,''); -INSERT INTO LifetimeTech VALUES('R1','E_BATT',20.0,''); -INSERT INTO LifetimeTech VALUES('R1','E_NUCLEAR',50.0,''); -INSERT INTO LifetimeTech VALUES('R1','T_BLND',100.0,''); -INSERT INTO LifetimeTech VALUES('R1','T_DSL',12.0,''); -INSERT INTO LifetimeTech VALUES('R1','T_GSL',12.0,''); -INSERT INTO LifetimeTech VALUES('R1','T_EV',12.0,''); -INSERT INTO LifetimeTech VALUES('R1','R_EH',20.0,''); -INSERT INTO LifetimeTech VALUES('R1','R_NGH',20.0,''); -INSERT INTO LifetimeTech VALUES('R2','S_IMPETH',100.0,''); -INSERT INTO LifetimeTech VALUES('R2','S_IMPOIL',100.0,''); -INSERT INTO LifetimeTech VALUES('R2','S_IMPNG',100.0,''); -INSERT INTO LifetimeTech VALUES('R2','S_IMPURN',100.0,''); -INSERT INTO LifetimeTech VALUES('R2','S_OILREF',100.0,''); -INSERT INTO LifetimeTech VALUES('R2','E_NGCC',30.0,''); -INSERT INTO LifetimeTech VALUES('R2','E_SOLPV',30.0,''); -INSERT INTO LifetimeTech VALUES('R2','E_BATT',20.0,''); -INSERT INTO LifetimeTech VALUES('R2','E_NUCLEAR',50.0,''); -INSERT INTO LifetimeTech VALUES('R2','T_BLND',100.0,''); -INSERT INTO LifetimeTech VALUES('R2','T_DSL',12.0,''); -INSERT INTO LifetimeTech VALUES('R2','T_GSL',12.0,''); -INSERT INTO LifetimeTech VALUES('R2','T_EV',12.0,''); -INSERT INTO LifetimeTech VALUES('R2','R_EH',20.0,''); -INSERT INTO LifetimeTech VALUES('R2','R_NGH',20.0,''); -INSERT INTO LifetimeTech VALUES('R1-R2','E_TRANS',30.0,''); -INSERT INTO LifetimeTech VALUES('R2-R1','E_TRANS',30.0,''); +INSERT INTO lifetime_tech VALUES('R1','S_IMPETH',100.0,''); +INSERT INTO lifetime_tech VALUES('R1','S_IMPOIL',100.0,''); +INSERT INTO lifetime_tech VALUES('R1','S_IMPNG',100.0,''); +INSERT INTO lifetime_tech VALUES('R1','S_IMPURN',100.0,''); +INSERT INTO lifetime_tech VALUES('R1','S_OILREF',100.0,''); +INSERT INTO lifetime_tech VALUES('R1','E_NGCC',30.0,''); +INSERT INTO lifetime_tech VALUES('R1','E_SOLPV',30.0,''); +INSERT INTO lifetime_tech VALUES('R1','E_BATT',20.0,''); +INSERT INTO lifetime_tech VALUES('R1','E_NUCLEAR',50.0,''); +INSERT INTO lifetime_tech VALUES('R1','T_BLND',100.0,''); +INSERT INTO lifetime_tech VALUES('R1','T_DSL',12.0,''); +INSERT INTO lifetime_tech VALUES('R1','T_GSL',12.0,''); +INSERT INTO lifetime_tech VALUES('R1','T_EV',12.0,''); +INSERT INTO lifetime_tech VALUES('R1','R_EH',20.0,''); +INSERT INTO lifetime_tech VALUES('R1','R_NGH',20.0,''); +INSERT INTO lifetime_tech VALUES('R2','S_IMPETH',100.0,''); +INSERT INTO lifetime_tech VALUES('R2','S_IMPOIL',100.0,''); +INSERT INTO lifetime_tech VALUES('R2','S_IMPNG',100.0,''); +INSERT INTO lifetime_tech VALUES('R2','S_IMPURN',100.0,''); +INSERT INTO lifetime_tech VALUES('R2','S_OILREF',100.0,''); +INSERT INTO lifetime_tech VALUES('R2','E_NGCC',30.0,''); +INSERT INTO lifetime_tech VALUES('R2','E_SOLPV',30.0,''); +INSERT INTO lifetime_tech VALUES('R2','E_BATT',20.0,''); +INSERT INTO lifetime_tech VALUES('R2','E_NUCLEAR',50.0,''); +INSERT INTO lifetime_tech VALUES('R2','T_BLND',100.0,''); +INSERT INTO lifetime_tech VALUES('R2','T_DSL',12.0,''); +INSERT INTO lifetime_tech VALUES('R2','T_GSL',12.0,''); +INSERT INTO lifetime_tech VALUES('R2','T_EV',12.0,''); +INSERT INTO lifetime_tech VALUES('R2','R_EH',20.0,''); +INSERT INTO lifetime_tech VALUES('R2','R_NGH',20.0,''); +INSERT INTO lifetime_tech VALUES('R1-R2','E_TRANS',30.0,''); +INSERT INTO lifetime_tech VALUES('R2-R1','E_TRANS',30.0,''); CREATE TABLE Operator ( operator TEXT PRIMARY KEY, @@ -815,7 +815,7 @@ CREATE TABLE Operator INSERT INTO Operator VALUES('e','equal to'); INSERT INTO Operator VALUES('le','less than or equal to'); INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE LimitGrowthCapacity +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, @@ -827,7 +827,7 @@ CREATE TABLE LimitGrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthCapacity +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, @@ -839,7 +839,7 @@ CREATE TABLE LimitDegrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacity +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -851,7 +851,7 @@ CREATE TABLE LimitGrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -863,7 +863,7 @@ CREATE TABLE LimitDegrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacityDelta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -875,7 +875,7 @@ CREATE TABLE LimitGrowthNewCapacityDelta notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacityDelta +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -908,7 +908,7 @@ CREATE TABLE LimitStorageLevelFraction ); INSERT INTO LimitStorageLevelFraction VALUES('R1',2025,'winter','day','E_BATT',2025,'e',0.5,''); INSERT INTO LimitStorageLevelFraction VALUES('R2',2020,'summer','day','E_BATT',2020,'e',0.5,''); -CREATE TABLE LimitActivity +CREATE TABLE limit_activity ( region TEXT, period INTEGER @@ -921,13 +921,13 @@ CREATE TABLE LimitActivity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO LimitActivity VALUES('R1',2020,'T_GSL','ge',35.0,'',''); -INSERT INTO LimitActivity VALUES('R1',2025,'T_GSL','ge',35.0,'',''); -INSERT INTO LimitActivity VALUES('R1',2030,'T_GSL','ge',35.0,'',''); -INSERT INTO LimitActivity VALUES('R2',2020,'T_GSL','ge',15.0,'',''); -INSERT INTO LimitActivity VALUES('R2',2025,'T_GSL','ge',15.0,'',''); -INSERT INTO LimitActivity VALUES('R2',2030,'T_GSL','ge',15.0,'',''); -CREATE TABLE LimitActivityShare +INSERT INTO limit_activity VALUES('R1',2020,'T_GSL','ge',35.0,'',''); +INSERT INTO limit_activity VALUES('R1',2025,'T_GSL','ge',35.0,'',''); +INSERT INTO limit_activity VALUES('R1',2030,'T_GSL','ge',35.0,'',''); +INSERT INTO limit_activity VALUES('R2',2020,'T_GSL','ge',15.0,'',''); +INSERT INTO limit_activity VALUES('R2',2025,'T_GSL','ge',15.0,'',''); +INSERT INTO limit_activity VALUES('R2',2030,'T_GSL','ge',15.0,'',''); +CREATE TABLE limit_activity_share ( region TEXT, period INTEGER @@ -940,7 +940,7 @@ CREATE TABLE LimitActivityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitAnnualCapacityFactor +CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER @@ -956,7 +956,7 @@ CREATE TABLE LimitAnnualCapacityFactor PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE LimitCapacity +CREATE TABLE limit_capacity ( region TEXT, period INTEGER @@ -969,7 +969,7 @@ CREATE TABLE LimitCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitCapacityShare +CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER @@ -982,7 +982,7 @@ CREATE TABLE LimitCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitNewCapacity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER @@ -995,7 +995,7 @@ CREATE TABLE LimitNewCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitNewCapacityShare +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -1008,7 +1008,7 @@ CREATE TABLE LimitNewCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitResource +CREATE TABLE limit_resource ( region TEXT, tech_or_group TEXT, @@ -1019,7 +1019,7 @@ CREATE TABLE LimitResource notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitSeasonalCapacityFactor +CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES Region (region), @@ -1035,7 +1035,7 @@ CREATE TABLE LimitSeasonalCapacityFactor notes TEXT, PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE LimitTechInputSplit +CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER @@ -1050,19 +1050,19 @@ CREATE TABLE LimitTechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -INSERT INTO LimitTechInputSplit VALUES('R1',2020,'GSL','T_BLND','ge',0.9000000000000000222,''); -INSERT INTO LimitTechInputSplit VALUES('R1',2020,'ETH','T_BLND','ge',0.1000000000000000055,''); -INSERT INTO LimitTechInputSplit VALUES('R1',2025,'GSL','T_BLND','ge',0.9000000000000000222,''); -INSERT INTO LimitTechInputSplit VALUES('R1',2025,'ETH','T_BLND','ge',0.1000000000000000055,''); -INSERT INTO LimitTechInputSplit VALUES('R1',2030,'GSL','T_BLND','ge',0.9000000000000000222,''); -INSERT INTO LimitTechInputSplit VALUES('R1',2030,'ETH','T_BLND','ge',0.1000000000000000055,''); -INSERT INTO LimitTechInputSplit VALUES('R2',2020,'GSL','T_BLND','ge',0.7199999999999999734,''); -INSERT INTO LimitTechInputSplit VALUES('R2',2020,'ETH','T_BLND','ge',0.08000000000000000166,''); -INSERT INTO LimitTechInputSplit VALUES('R2',2025,'GSL','T_BLND','ge',0.7199999999999999734,''); -INSERT INTO LimitTechInputSplit VALUES('R2',2025,'ETH','T_BLND','ge',0.08000000000000000166,''); -INSERT INTO LimitTechInputSplit VALUES('R2',2030,'GSL','T_BLND','ge',0.7199999999999999734,''); -INSERT INTO LimitTechInputSplit VALUES('R2',2030,'ETH','T_BLND','ge',0.08000000000000000166,''); -CREATE TABLE LimitTechInputSplitAnnual +INSERT INTO limit_tech_input_split VALUES('R1',2020,'GSL','T_BLND','ge',0.9000000000000000222,''); +INSERT INTO limit_tech_input_split VALUES('R1',2020,'ETH','T_BLND','ge',0.1000000000000000055,''); +INSERT INTO limit_tech_input_split VALUES('R1',2025,'GSL','T_BLND','ge',0.9000000000000000222,''); +INSERT INTO limit_tech_input_split VALUES('R1',2025,'ETH','T_BLND','ge',0.1000000000000000055,''); +INSERT INTO limit_tech_input_split VALUES('R1',2030,'GSL','T_BLND','ge',0.9000000000000000222,''); +INSERT INTO limit_tech_input_split VALUES('R1',2030,'ETH','T_BLND','ge',0.1000000000000000055,''); +INSERT INTO limit_tech_input_split VALUES('R2',2020,'GSL','T_BLND','ge',0.7199999999999999734,''); +INSERT INTO limit_tech_input_split VALUES('R2',2020,'ETH','T_BLND','ge',0.08000000000000000166,''); +INSERT INTO limit_tech_input_split VALUES('R2',2025,'GSL','T_BLND','ge',0.7199999999999999734,''); +INSERT INTO limit_tech_input_split VALUES('R2',2025,'ETH','T_BLND','ge',0.08000000000000000166,''); +INSERT INTO limit_tech_input_split VALUES('R2',2030,'GSL','T_BLND','ge',0.7199999999999999734,''); +INSERT INTO limit_tech_input_split VALUES('R2',2030,'ETH','T_BLND','ge',0.08000000000000000166,''); +CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER @@ -1077,7 +1077,7 @@ CREATE TABLE LimitTechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechOutputSplit +CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER @@ -1092,19 +1092,19 @@ CREATE TABLE LimitTechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -INSERT INTO LimitTechOutputSplit VALUES('R1',2020,'S_OILREF','GSL','ge',0.9000000000000000222,''); -INSERT INTO LimitTechOutputSplit VALUES('R1',2020,'S_OILREF','DSL','ge',0.1000000000000000055,''); -INSERT INTO LimitTechOutputSplit VALUES('R1',2025,'S_OILREF','GSL','ge',0.9000000000000000222,''); -INSERT INTO LimitTechOutputSplit VALUES('R1',2025,'S_OILREF','DSL','ge',0.1000000000000000055,''); -INSERT INTO LimitTechOutputSplit VALUES('R1',2030,'S_OILREF','GSL','ge',0.9000000000000000222,''); -INSERT INTO LimitTechOutputSplit VALUES('R1',2030,'S_OILREF','DSL','ge',0.1000000000000000055,''); -INSERT INTO LimitTechOutputSplit VALUES('R2',2020,'S_OILREF','GSL','ge',0.7199999999999999734,''); -INSERT INTO LimitTechOutputSplit VALUES('R2',2020,'S_OILREF','DSL','ge',0.08000000000000000166,''); -INSERT INTO LimitTechOutputSplit VALUES('R2',2025,'S_OILREF','GSL','ge',0.7199999999999999734,''); -INSERT INTO LimitTechOutputSplit VALUES('R2',2025,'S_OILREF','DSL','ge',0.08000000000000000166,''); -INSERT INTO LimitTechOutputSplit VALUES('R2',2030,'S_OILREF','GSL','ge',0.7199999999999999734,''); -INSERT INTO LimitTechOutputSplit VALUES('R2',2030,'S_OILREF','DSL','ge',0.08000000000000000166,''); -CREATE TABLE LimitTechOutputSplitAnnual +INSERT INTO limit_tech_output_split VALUES('R1',2020,'S_OILREF','GSL','ge',0.9000000000000000222,''); +INSERT INTO limit_tech_output_split VALUES('R1',2020,'S_OILREF','DSL','ge',0.1000000000000000055,''); +INSERT INTO limit_tech_output_split VALUES('R1',2025,'S_OILREF','GSL','ge',0.9000000000000000222,''); +INSERT INTO limit_tech_output_split VALUES('R1',2025,'S_OILREF','DSL','ge',0.1000000000000000055,''); +INSERT INTO limit_tech_output_split VALUES('R1',2030,'S_OILREF','GSL','ge',0.9000000000000000222,''); +INSERT INTO limit_tech_output_split VALUES('R1',2030,'S_OILREF','DSL','ge',0.1000000000000000055,''); +INSERT INTO limit_tech_output_split VALUES('R2',2020,'S_OILREF','GSL','ge',0.7199999999999999734,''); +INSERT INTO limit_tech_output_split VALUES('R2',2020,'S_OILREF','DSL','ge',0.08000000000000000166,''); +INSERT INTO limit_tech_output_split VALUES('R2',2025,'S_OILREF','GSL','ge',0.7199999999999999734,''); +INSERT INTO limit_tech_output_split VALUES('R2',2025,'S_OILREF','DSL','ge',0.08000000000000000166,''); +INSERT INTO limit_tech_output_split VALUES('R2',2030,'S_OILREF','GSL','ge',0.7199999999999999734,''); +INSERT INTO limit_tech_output_split VALUES('R2',2030,'S_OILREF','DSL','ge',0.08000000000000000166,''); +CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER @@ -1119,7 +1119,7 @@ CREATE TABLE LimitTechOutputSplitAnnual notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitEmission +CREATE TABLE limit_emission ( region TEXT, period INTEGER @@ -1133,12 +1133,12 @@ CREATE TABLE LimitEmission notes TEXT, PRIMARY KEY (region, period, emis_comm, operator) ); -INSERT INTO LimitEmission VALUES('R1',2020,'CO2','le',25000.0,'kT CO2',''); -INSERT INTO LimitEmission VALUES('R1',2025,'CO2','le',24000.0,'kT CO2',''); -INSERT INTO LimitEmission VALUES('R1',2030,'CO2','le',23000.0,'kT CO2',''); -INSERT INTO LimitEmission VALUES('global',2020,'CO2','le',37500.0,'kT CO2',''); -INSERT INTO LimitEmission VALUES('global',2025,'CO2','le',36000.0,'kT CO2',''); -INSERT INTO LimitEmission VALUES('global',2030,'CO2','le',34500.0,'kT CO2',''); +INSERT INTO limit_emission VALUES('R1',2020,'CO2','le',25000.0,'kT CO2',''); +INSERT INTO limit_emission VALUES('R1',2025,'CO2','le',24000.0,'kT CO2',''); +INSERT INTO limit_emission VALUES('R1',2030,'CO2','le',23000.0,'kT CO2',''); +INSERT INTO limit_emission VALUES('global',2020,'CO2','le',37500.0,'kT CO2',''); +INSERT INTO limit_emission VALUES('global',2025,'CO2','le',36000.0,'kT CO2',''); +INSERT INTO limit_emission VALUES('global',2030,'CO2','le',34500.0,'kT CO2',''); CREATE TABLE LinkedTech ( primary_region TEXT, @@ -1282,7 +1282,7 @@ CREATE TABLE OutputStorageLevel level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); -CREATE TABLE PlanningReserveMargin +CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY @@ -1290,7 +1290,7 @@ CREATE TABLE PlanningReserveMargin margin REAL, notes TEXT ); -CREATE TABLE RampDownHourly +CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT @@ -1299,7 +1299,7 @@ CREATE TABLE RampDownHourly notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUpHourly +CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT @@ -1316,7 +1316,7 @@ CREATE TABLE Region ); INSERT INTO Region VALUES('R1',NULL); INSERT INTO Region VALUES('R2',NULL); -CREATE TABLE ReserveCapacityDerate +CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER @@ -1332,7 +1332,7 @@ CREATE TABLE ReserveCapacityDerate CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE TimeSegmentFraction -( +( period INTEGER REFERENCES TimePeriod (period), season TEXT @@ -1368,7 +1368,7 @@ INSERT INTO TimeSegmentFraction VALUES(2030,'fall','day',0.125,'Fall - Day'); INSERT INTO TimeSegmentFraction VALUES(2030,'fall','night',0.125,'Fall - Night'); INSERT INTO TimeSegmentFraction VALUES(2030,'winter','day',0.125,'Winter - Day'); INSERT INTO TimeSegmentFraction VALUES(2030,'winter','night',0.125,'Winter - Night'); -CREATE TABLE StorageDuration +CREATE TABLE storage_duration ( region TEXT, tech TEXT, @@ -1376,9 +1376,9 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO StorageDuration VALUES('R1','E_BATT',8.0,'8-hour duration specified as fraction of a day'); -INSERT INTO StorageDuration VALUES('R2','E_BATT',8.0,'8-hour duration specified as fraction of a day'); -CREATE TABLE LifetimeSurvivalCurve +INSERT INTO storage_duration VALUES('R1','E_BATT',8.0,'8-hour duration specified as fraction of a day'); +INSERT INTO storage_duration VALUES('R2','E_BATT',8.0,'8-hour duration specified as fraction of a day'); +CREATE TABLE lifetime_survival_curve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -1442,7 +1442,7 @@ INSERT INTO TimeSeason VALUES(2030,1,'spring',NULL); INSERT INTO TimeSeason VALUES(2030,2,'summer',NULL); INSERT INTO TimeSeason VALUES(2030,3,'fall',NULL); INSERT INTO TimeSeason VALUES(2030,4,'winter',NULL); -CREATE TABLE TimeSeasonSequential +CREATE TABLE time_season_sequential ( period INTEGER REFERENCES TimePeriod (period), diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index f32cc2236..6cc795edb 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -18,7 +18,7 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); CREATE TABLE OutputDualVariable ( @@ -52,7 +52,7 @@ INSERT INTO SectorLabel VALUES('transport',NULL); INSERT INTO SectorLabel VALUES('commercial',NULL); INSERT INTO SectorLabel VALUES('residential',NULL); INSERT INTO SectorLabel VALUES('industrial',NULL); -CREATE TABLE CapacityCredit +CREATE TABLE capacity_credit ( region TEXT, period INTEGER @@ -65,7 +65,7 @@ CREATE TABLE CapacityCredit PRIMARY KEY (region, period, tech, vintage), CHECK (credit >= 0 AND credit <= 1) ); -CREATE TABLE CapacityFactorProcess +CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER @@ -82,25 +82,25 @@ CREATE TABLE CapacityFactorProcess PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2010,0.2756000000000000116,''); -CREATE TABLE CapacityFactorTech +INSERT INTO capacity_factor_process VALUES('utopia',2000,'inter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2000,'inter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2000,'winter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2000,'winter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2000,'summer','day','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2000,'summer','night','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','day','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','night','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','day','E31',2010,0.2756000000000000116,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','night','E31',2010,0.2756000000000000116,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','day','E31',2010,0.2756000000000000116,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','night','E31',2010,0.2756000000000000116,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','day','E31',2010,0.2756000000000000116,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','night','E31',2010,0.2756000000000000116,''); +CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER @@ -116,96 +116,96 @@ CREATE TABLE CapacityFactorTech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E70',0.8000000000000000444,''); CREATE TABLE CapacityToActivity ( region TEXT, @@ -263,7 +263,7 @@ INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); -CREATE TABLE ConstructionInput +CREATE TABLE construction_input ( region TEXT, input_comm TEXT @@ -277,7 +277,7 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -CREATE TABLE CostEmission +CREATE TABLE cost_emission ( region TEXT, period INTEGER @@ -289,7 +289,7 @@ CREATE TABLE CostEmission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -CREATE TABLE CostFixed +CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -303,89 +303,89 @@ CREATE TABLE CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostFixed VALUES('utopia',1990,'E01',1960,40.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E01',1970,40.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E01',1980,40.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E01',1990,40.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E01',1970,70.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E01',1980,70.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E01',1990,70.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E01',2000,70.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E01',1980,100.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E01',1990,100.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E01',2000,100.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E01',2010,100.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E21',1990,500.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E21',1990,500.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E21',1990,500.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E21',2000,500.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E21',2000,500.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E21',2010,500.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E31',1980,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E31',1990,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E31',1980,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E31',1990,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E31',2000,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E31',1980,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E31',1990,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E31',2000,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E31',2010,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E51',1980,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E51',1990,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E51',1980,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E51',1990,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E51',2000,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E51',1980,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E51',1990,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E51',2000,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E51',2010,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E70',1960,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E70',1970,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E70',1980,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E70',1990,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E70',1970,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E70',1980,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E70',1990,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E70',2000,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E70',1980,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E70',1990,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E70',2000,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E70',2010,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RHO',1970,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RHO',1980,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RHO',1990,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'RHO',1980,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'RHO',1990,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'RHO',2000,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'RHO',1990,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'RHO',2000,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'RHO',2010,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1980,9.46000000000000086,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1990,9.46000000000000086,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'RL1',2000,9.46000000000000086,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'RL1',2010,9.46000000000000086,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1970,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1980,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1990,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXD',1980,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXD',1990,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXD',2000,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'TXD',2000,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'TXD',2010,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'TXE',1990,100.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXE',1990,90.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXE',2000,90.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'TXE',2000,80.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'TXE',2010,80.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'TXG',1970,48.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'TXG',1980,48.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'TXG',1990,48.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXG',1980,48.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXG',1990,48.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXG',2000,48.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'TXG',2000,48.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'TXG',2010,48.0,'',''); -CREATE TABLE CostInvest +INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1960,40.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1970,40.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1980,40.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1990,40.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E01',1970,70.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E01',1980,70.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E01',1990,70.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E01',2000,70.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E01',1980,100.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E01',1990,100.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E01',2000,100.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E01',2010,100.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E21',1990,500.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E21',1990,500.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E21',1990,500.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E21',2000,500.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E21',2000,500.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E21',2010,500.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E31',1980,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E31',1990,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E31',1980,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E31',1990,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E31',2000,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E31',1980,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E31',1990,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E31',2000,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E31',2010,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E51',1980,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E51',1990,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E51',1980,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E51',1990,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E51',2000,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E51',1980,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E51',1990,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E51',2000,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E51',2010,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1960,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1970,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1980,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1990,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E70',1970,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E70',1980,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E70',1990,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E70',2000,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E70',1980,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E70',1990,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E70',2000,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E70',2010,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'RHO',1970,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'RHO',1980,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'RHO',1990,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'RHO',1980,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'RHO',1990,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'RHO',2000,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'RHO',1990,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'RHO',2000,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'RHO',2010,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'RL1',1980,9.46000000000000086,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'RL1',1990,9.46000000000000086,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'RL1',2000,9.46000000000000086,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'RL1',2010,9.46000000000000086,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'TXD',1970,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'TXD',1980,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'TXD',1990,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXD',1980,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXD',1990,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXD',2000,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'TXD',2000,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'TXD',2010,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'TXE',1990,100.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXE',1990,90.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXE',2000,90.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'TXE',2000,80.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'TXE',2010,80.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'TXG',1970,48.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'TXG',1980,48.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'TXG',1990,48.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXG',1980,48.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXG',1990,48.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXG',2000,48.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'TXG',2000,48.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'TXG',2010,48.0,'',''); +CREATE TABLE cost_invest ( region TEXT, tech TEXT @@ -397,40 +397,40 @@ CREATE TABLE CostInvest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO CostInvest VALUES('utopia','E01',1990,2000.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E01',2000,1300.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E01',2010,1200.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E21',1990,5000.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E21',2000,5000.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E21',2010,5000.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E31',1990,3000.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E31',2000,3000.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E31',2010,3000.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E51',1990,900.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E51',2000,900.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E51',2010,900.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E70',1990,1000.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E70',2000,1000.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E70',2010,1000.0,'',''); -INSERT INTO CostInvest VALUES('utopia','RHE',1990,90.0,'',''); -INSERT INTO CostInvest VALUES('utopia','RHE',2000,90.0,'',''); -INSERT INTO CostInvest VALUES('utopia','RHE',2010,90.0,'',''); -INSERT INTO CostInvest VALUES('utopia','RHO',1990,100.0,'',''); -INSERT INTO CostInvest VALUES('utopia','RHO',2000,100.0,'',''); -INSERT INTO CostInvest VALUES('utopia','RHO',2010,100.0,'',''); -INSERT INTO CostInvest VALUES('utopia','SRE',1990,100.0,'',''); -INSERT INTO CostInvest VALUES('utopia','SRE',2000,100.0,'',''); -INSERT INTO CostInvest VALUES('utopia','SRE',2010,100.0,'',''); -INSERT INTO CostInvest VALUES('utopia','TXD',1990,1044.0,'',''); -INSERT INTO CostInvest VALUES('utopia','TXD',2000,1044.0,'',''); -INSERT INTO CostInvest VALUES('utopia','TXD',2010,1044.0,'',''); -INSERT INTO CostInvest VALUES('utopia','TXE',1990,2000.0,'',''); -INSERT INTO CostInvest VALUES('utopia','TXE',2000,1750.0,'',''); -INSERT INTO CostInvest VALUES('utopia','TXE',2010,1500.0,'',''); -INSERT INTO CostInvest VALUES('utopia','TXG',1990,1044.0,'',''); -INSERT INTO CostInvest VALUES('utopia','TXG',2000,1044.0,'',''); -INSERT INTO CostInvest VALUES('utopia','TXG',2010,1044.0,'',''); -CREATE TABLE CostVariable +INSERT INTO cost_invest VALUES('utopia','E01',1990,2000.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E01',2000,1300.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E01',2010,1200.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E21',1990,5000.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E21',2000,5000.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E21',2010,5000.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E31',1990,3000.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E31',2000,3000.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E31',2010,3000.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E51',1990,900.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E51',2000,900.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E51',2010,900.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E70',1990,1000.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E70',2000,1000.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E70',2010,1000.0,'',''); +INSERT INTO cost_invest VALUES('utopia','RHE',1990,90.0,'',''); +INSERT INTO cost_invest VALUES('utopia','RHE',2000,90.0,'',''); +INSERT INTO cost_invest VALUES('utopia','RHE',2010,90.0,'',''); +INSERT INTO cost_invest VALUES('utopia','RHO',1990,100.0,'',''); +INSERT INTO cost_invest VALUES('utopia','RHO',2000,100.0,'',''); +INSERT INTO cost_invest VALUES('utopia','RHO',2010,100.0,'',''); +INSERT INTO cost_invest VALUES('utopia','SRE',1990,100.0,'',''); +INSERT INTO cost_invest VALUES('utopia','SRE',2000,100.0,'',''); +INSERT INTO cost_invest VALUES('utopia','SRE',2010,100.0,'',''); +INSERT INTO cost_invest VALUES('utopia','TXD',1990,1044.0,'',''); +INSERT INTO cost_invest VALUES('utopia','TXD',2000,1044.0,'',''); +INSERT INTO cost_invest VALUES('utopia','TXD',2010,1044.0,'',''); +INSERT INTO cost_invest VALUES('utopia','TXE',1990,2000.0,'',''); +INSERT INTO cost_invest VALUES('utopia','TXE',2000,1750.0,'',''); +INSERT INTO cost_invest VALUES('utopia','TXE',2010,1500.0,'',''); +INSERT INTO cost_invest VALUES('utopia','TXG',1990,1044.0,'',''); +INSERT INTO cost_invest VALUES('utopia','TXG',2000,1044.0,'',''); +INSERT INTO cost_invest VALUES('utopia','TXG',2010,1044.0,'',''); +CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -444,57 +444,57 @@ CREATE TABLE CostVariable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostVariable VALUES('utopia',1990,'IMPDSL1',1990,10.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'IMPDSL1',1990,10.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'IMPDSL1',1990,10.0,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'IMPGSL1',1990,15.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'IMPGSL1',1990,15.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'IMPGSL1',1990,15.0,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'IMPHCO1',1990,2.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'IMPHCO1',1990,2.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'IMPHCO1',1990,2.0,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'IMPOIL1',1990,8.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'IMPOIL1',1990,8.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'IMPOIL1',1990,8.0,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'IMPURN1',1990,2.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'IMPURN1',1990,2.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'IMPURN1',1990,2.0,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1960,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1970,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1980,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1990,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1970,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1980,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1990,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',2000,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',1980,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',1990,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',2000,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',2010,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E21',1990,1.5,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E21',1990,1.5,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E21',1990,1.5,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E21',2000,1.5,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E21',2000,1.5,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E21',2010,1.5,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1960,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1970,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1980,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1990,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1970,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1980,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1990,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',2000,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',1980,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',1990,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',2000,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',2010,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'SRE',1990,10.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'SRE',1990,10.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'SRE',2000,10.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'SRE',1990,10.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'SRE',2000,10.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'SRE',2010,10.0,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'IMPDSL1',1990,10.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'IMPDSL1',1990,10.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'IMPDSL1',1990,10.0,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'IMPGSL1',1990,15.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'IMPGSL1',1990,15.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'IMPGSL1',1990,15.0,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'IMPHCO1',1990,2.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'IMPHCO1',1990,2.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'IMPHCO1',1990,2.0,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'IMPOIL1',1990,8.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'IMPOIL1',1990,8.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'IMPOIL1',1990,8.0,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'IMPURN1',1990,2.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'IMPURN1',1990,2.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'IMPURN1',1990,2.0,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'E01',1960,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'E01',1970,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'E01',1980,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'E01',1990,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'E01',1970,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'E01',1980,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'E01',1990,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'E01',2000,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'E01',1980,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'E01',1990,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'E01',2000,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'E01',2010,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'E21',1990,1.5,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'E21',1990,1.5,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'E21',1990,1.5,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'E21',2000,1.5,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'E21',2000,1.5,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'E21',2010,1.5,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'E70',1960,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'E70',1970,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'E70',1980,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'E70',1990,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'E70',1970,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'E70',1980,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'E70',1990,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'E70',2000,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'E70',1980,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'E70',1990,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'E70',2000,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'E70',2010,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'SRE',1990,10.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'SRE',1990,10.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'SRE',2000,10.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'SRE',1990,10.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'SRE',2000,10.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'SRE',2010,10.0,'',''); CREATE TABLE Demand ( region TEXT, @@ -562,7 +562,7 @@ INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','day','RL', INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','night','RL',0.05000000000000000277,''); INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RL',0.5,''); INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RL',0.1000000000000000055,''); -CREATE TABLE EndOfLifeOutput +CREATE TABLE end_of_life_output ( region TEXT, tech TEXT @@ -576,7 +576,7 @@ CREATE TABLE EndOfLifeOutput notes TEXT, PRIMARY KEY (region, tech, vintage, output_comm) ); -CREATE TABLE Efficiency +CREATE TABLE efficiency ( region TEXT, input_comm TEXT @@ -592,71 +592,71 @@ CREATE TABLE Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPDSL1',1990,'DSL',1.0,''); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPGSL1',1990,'GSL',1.0,''); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPHCO1',1990,'HCO',1.0,''); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,''); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,''); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,''); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,''); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1960,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1970,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1980,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1990,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',2000,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',2010,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',1990,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2000,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2010,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','URN','E21',1990,'ELC',0.4000000000000000222,'# 1/2.5'); -INSERT INTO Efficiency VALUES('utopia','URN','E21',2000,'ELC',0.4000000000000000222,'# 1/2.5'); -INSERT INTO Efficiency VALUES('utopia','URN','E21',2010,'ELC',0.4000000000000000222,'# 1/2.5'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',1980,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',1990,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',2000,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',2010,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1960,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1970,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1980,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1990,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',2000,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',2010,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',1980,'ELC',0.7199999999999999734,'# 1/1.3889'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',1990,'ELC',0.7199999999999999734,'# 1/1.3889'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',2000,'ELC',0.7199999999999999734,'# 1/1.3889'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',2010,'ELC',0.7199999999999999734,'# 1/1.3889'); -INSERT INTO Efficiency VALUES('utopia','ELC','RHE',1990,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','RHE',2000,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','RHE',2010,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1970,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1980,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1990,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2000,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2010,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','RL1',1980,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','RL1',1990,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','RL1',2000,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','RL1',2010,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',1990,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2000,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',1990,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2000,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2010,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -CREATE TABLE EfficiencyVariable +INSERT INTO efficiency VALUES('utopia','ethos','IMPDSL1',1990,'DSL',1.0,''); +INSERT INTO efficiency VALUES('utopia','ethos','IMPGSL1',1990,'GSL',1.0,''); +INSERT INTO efficiency VALUES('utopia','ethos','IMPHCO1',1990,'HCO',1.0,''); +INSERT INTO efficiency VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,''); +INSERT INTO efficiency VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,''); +INSERT INTO efficiency VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,''); +INSERT INTO efficiency VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,''); +INSERT INTO efficiency VALUES('utopia','HCO','E01',1960,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','HCO','E01',1970,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','HCO','E01',1980,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','HCO','E01',1990,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','HCO','E01',2000,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','HCO','E01',2010,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','FEQ','E21',1990,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','FEQ','E21',2000,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','FEQ','E21',2010,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','URN','E21',1990,'ELC',0.4000000000000000222,'# 1/2.5'); +INSERT INTO efficiency VALUES('utopia','URN','E21',2000,'ELC',0.4000000000000000222,'# 1/2.5'); +INSERT INTO efficiency VALUES('utopia','URN','E21',2010,'ELC',0.4000000000000000222,'# 1/2.5'); +INSERT INTO efficiency VALUES('utopia','HYD','E31',1980,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','HYD','E31',1990,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','HYD','E31',2000,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','HYD','E31',2010,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','DSL','E70',1960,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO efficiency VALUES('utopia','DSL','E70',1970,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO efficiency VALUES('utopia','DSL','E70',1980,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO efficiency VALUES('utopia','DSL','E70',1990,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO efficiency VALUES('utopia','DSL','E70',2000,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO efficiency VALUES('utopia','DSL','E70',2010,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO efficiency VALUES('utopia','ELC','E51',1980,'ELC',0.7199999999999999734,'# 1/1.3889'); +INSERT INTO efficiency VALUES('utopia','ELC','E51',1990,'ELC',0.7199999999999999734,'# 1/1.3889'); +INSERT INTO efficiency VALUES('utopia','ELC','E51',2000,'ELC',0.7199999999999999734,'# 1/1.3889'); +INSERT INTO efficiency VALUES('utopia','ELC','E51',2010,'ELC',0.7199999999999999734,'# 1/1.3889'); +INSERT INTO efficiency VALUES('utopia','ELC','RHE',1990,'RH',1.0,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','ELC','RHE',2000,'RH',1.0,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','ELC','RHE',2010,'RH',1.0,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','DSL','RHO',1970,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','DSL','RHO',1980,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','DSL','RHO',1990,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','DSL','RHO',2000,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','DSL','RHO',2010,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','ELC','RL1',1980,'RL',1.0,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','ELC','RL1',1990,'RL',1.0,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','ELC','RL1',2000,'RL',1.0,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','ELC','RL1',2010,'RL',1.0,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','OIL','SRE',1990,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO efficiency VALUES('utopia','OIL','SRE',2000,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO efficiency VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO efficiency VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO efficiency VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO efficiency VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO efficiency VALUES('utopia','DSL','TXD',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','DSL','TXD',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','DSL','TXD',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','DSL','TXD',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','DSL','TXD',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','ELC','TXE',1990,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','ELC','TXE',2000,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','ELC','TXE',2010,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','GSL','TXG',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','GSL','TXG',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','GSL','TXG',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','GSL','TXG',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','GSL','TXG',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +CREATE TABLE efficiency_variable ( region TEXT, period INTEGER @@ -678,7 +678,7 @@ CREATE TABLE EfficiencyVariable PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -CREATE TABLE EmissionActivity +CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT @@ -696,21 +696,21 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.07499999999999999723,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.07499999999999999723,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',0.0889999999999999819,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.07499999999999999723,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1970,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1980,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1990,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',2000,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',2010,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',1970,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',1980,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',1990,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',2000,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',2010,'TX',1.0,'',''); -CREATE TABLE EmissionEmbodied +INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.07499999999999999723,'',''); +INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.07499999999999999723,'',''); +INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',0.0889999999999999819,'',''); +INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.07499999999999999723,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',1970,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',1980,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',1990,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',2000,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',2010,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',1970,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',1980,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',1990,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',2000,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',2010,'TX',1.0,'',''); +CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT @@ -724,7 +724,7 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE EmissionEndOfLife +CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT @@ -738,7 +738,7 @@ CREATE TABLE EmissionEndOfLife notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE ExistingCapacity +CREATE TABLE existing_capacity ( region TEXT, tech TEXT @@ -750,28 +750,28 @@ CREATE TABLE ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1960,0.1749999999999999889,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1970,0.1749999999999999889,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1980,0.1499999999999999945,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E31',1980,0.1000000000000000055,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E51',1980,0.5,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1960,0.05000000000000000277,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1970,0.05000000000000000277,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1980,0.2000000000000000111,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','RHO',1970,12.5,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','RHO',1980,12.5,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','RL1',1980,5.599999999999999645,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXD',1970,0.4000000000000000222,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXD',1980,0.2000000000000000111,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXG',1970,3.100000000000000088,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXG',1980,1.5,'',''); +INSERT INTO existing_capacity VALUES('utopia','E01',1960,0.1749999999999999889,'',''); +INSERT INTO existing_capacity VALUES('utopia','E01',1970,0.1749999999999999889,'',''); +INSERT INTO existing_capacity VALUES('utopia','E01',1980,0.1499999999999999945,'',''); +INSERT INTO existing_capacity VALUES('utopia','E31',1980,0.1000000000000000055,'',''); +INSERT INTO existing_capacity VALUES('utopia','E51',1980,0.5,'',''); +INSERT INTO existing_capacity VALUES('utopia','E70',1960,0.05000000000000000277,'',''); +INSERT INTO existing_capacity VALUES('utopia','E70',1970,0.05000000000000000277,'',''); +INSERT INTO existing_capacity VALUES('utopia','E70',1980,0.2000000000000000111,'',''); +INSERT INTO existing_capacity VALUES('utopia','RHO',1970,12.5,'',''); +INSERT INTO existing_capacity VALUES('utopia','RHO',1980,12.5,'',''); +INSERT INTO existing_capacity VALUES('utopia','RL1',1980,5.599999999999999645,'',''); +INSERT INTO existing_capacity VALUES('utopia','TXD',1970,0.4000000000000000222,'',''); +INSERT INTO existing_capacity VALUES('utopia','TXD',1980,0.2000000000000000111,'',''); +INSERT INTO existing_capacity VALUES('utopia','TXG',1970,3.100000000000000088,'',''); +INSERT INTO existing_capacity VALUES('utopia','TXG',1980,1.5,'',''); CREATE TABLE TechGroup ( group_name TEXT PRIMARY KEY, notes TEXT ); -CREATE TABLE LoanLifetimeProcess +CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT @@ -782,7 +782,7 @@ CREATE TABLE LoanLifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LoanRate +CREATE TABLE loan_rate ( region TEXT, tech TEXT @@ -793,7 +793,7 @@ CREATE TABLE LoanRate notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeProcess +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -804,12 +804,12 @@ CREATE TABLE LifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO LifetimeProcess VALUES('utopia','RL1',1980,20.0,'#forexistingcap'); -INSERT INTO LifetimeProcess VALUES('utopia','TXD',1970,30.0,'#forexistingcap'); -INSERT INTO LifetimeProcess VALUES('utopia','TXD',1980,30.0,'#forexistingcap'); -INSERT INTO LifetimeProcess VALUES('utopia','TXG',1970,30.0,'#forexistingcap'); -INSERT INTO LifetimeProcess VALUES('utopia','TXG',1980,30.0,'#forexistingcap'); -CREATE TABLE LifetimeTech +INSERT INTO lifetime_process VALUES('utopia','RL1',1980,20.0,'#forexistingcap'); +INSERT INTO lifetime_process VALUES('utopia','TXD',1970,30.0,'#forexistingcap'); +INSERT INTO lifetime_process VALUES('utopia','TXD',1980,30.0,'#forexistingcap'); +INSERT INTO lifetime_process VALUES('utopia','TXG',1970,30.0,'#forexistingcap'); +INSERT INTO lifetime_process VALUES('utopia','TXG',1980,30.0,'#forexistingcap'); +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT @@ -818,25 +818,25 @@ CREATE TABLE LifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO LifetimeTech VALUES('utopia','E01',40.0,''); -INSERT INTO LifetimeTech VALUES('utopia','E21',40.0,''); -INSERT INTO LifetimeTech VALUES('utopia','E31',100.0,''); -INSERT INTO LifetimeTech VALUES('utopia','E51',100.0,''); -INSERT INTO LifetimeTech VALUES('utopia','E70',40.0,''); -INSERT INTO LifetimeTech VALUES('utopia','RHE',30.0,''); -INSERT INTO LifetimeTech VALUES('utopia','RHO',30.0,''); -INSERT INTO LifetimeTech VALUES('utopia','RL1',10.0,''); -INSERT INTO LifetimeTech VALUES('utopia','SRE',50.0,''); -INSERT INTO LifetimeTech VALUES('utopia','TXD',15.0,''); -INSERT INTO LifetimeTech VALUES('utopia','TXE',15.0,''); -INSERT INTO LifetimeTech VALUES('utopia','TXG',15.0,''); -INSERT INTO LifetimeTech VALUES('utopia','IMPDSL1',1000.0,''); -INSERT INTO LifetimeTech VALUES('utopia','IMPGSL1',1000.0,''); -INSERT INTO LifetimeTech VALUES('utopia','IMPHCO1',1000.0,''); -INSERT INTO LifetimeTech VALUES('utopia','IMPOIL1',1000.0,''); -INSERT INTO LifetimeTech VALUES('utopia','IMPURN1',1000.0,''); -INSERT INTO LifetimeTech VALUES('utopia','IMPHYD',1000.0,''); -INSERT INTO LifetimeTech VALUES('utopia','IMPFEQ',1000.0,''); +INSERT INTO lifetime_tech VALUES('utopia','E01',40.0,''); +INSERT INTO lifetime_tech VALUES('utopia','E21',40.0,''); +INSERT INTO lifetime_tech VALUES('utopia','E31',100.0,''); +INSERT INTO lifetime_tech VALUES('utopia','E51',100.0,''); +INSERT INTO lifetime_tech VALUES('utopia','E70',40.0,''); +INSERT INTO lifetime_tech VALUES('utopia','RHE',30.0,''); +INSERT INTO lifetime_tech VALUES('utopia','RHO',30.0,''); +INSERT INTO lifetime_tech VALUES('utopia','RL1',10.0,''); +INSERT INTO lifetime_tech VALUES('utopia','SRE',50.0,''); +INSERT INTO lifetime_tech VALUES('utopia','TXD',15.0,''); +INSERT INTO lifetime_tech VALUES('utopia','TXE',15.0,''); +INSERT INTO lifetime_tech VALUES('utopia','TXG',15.0,''); +INSERT INTO lifetime_tech VALUES('utopia','IMPDSL1',1000.0,''); +INSERT INTO lifetime_tech VALUES('utopia','IMPGSL1',1000.0,''); +INSERT INTO lifetime_tech VALUES('utopia','IMPHCO1',1000.0,''); +INSERT INTO lifetime_tech VALUES('utopia','IMPOIL1',1000.0,''); +INSERT INTO lifetime_tech VALUES('utopia','IMPURN1',1000.0,''); +INSERT INTO lifetime_tech VALUES('utopia','IMPHYD',1000.0,''); +INSERT INTO lifetime_tech VALUES('utopia','IMPFEQ',1000.0,''); CREATE TABLE Operator ( operator TEXT PRIMARY KEY, @@ -845,7 +845,7 @@ CREATE TABLE Operator INSERT INTO Operator VALUES('e','equal to'); INSERT INTO Operator VALUES('le','less than or equal to'); INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE LimitGrowthCapacity +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, @@ -857,7 +857,7 @@ CREATE TABLE LimitGrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthCapacity +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, @@ -869,7 +869,7 @@ CREATE TABLE LimitDegrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacity +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -881,7 +881,7 @@ CREATE TABLE LimitGrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -893,7 +893,7 @@ CREATE TABLE LimitDegrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacityDelta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -905,7 +905,7 @@ CREATE TABLE LimitGrowthNewCapacityDelta notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacityDelta +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -936,7 +936,7 @@ CREATE TABLE LimitStorageLevelFraction notes TEXT, PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE LimitActivity +CREATE TABLE limit_activity ( region TEXT, period INTEGER @@ -949,7 +949,7 @@ CREATE TABLE LimitActivity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitActivityShare +CREATE TABLE limit_activity_share ( region TEXT, period INTEGER @@ -962,7 +962,7 @@ CREATE TABLE LimitActivityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitAnnualCapacityFactor +CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER @@ -978,7 +978,7 @@ CREATE TABLE LimitAnnualCapacityFactor PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE LimitCapacity +CREATE TABLE limit_capacity ( region TEXT, period INTEGER @@ -991,18 +991,18 @@ CREATE TABLE LimitCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO LimitCapacity VALUES('utopia',1990,'E31','ge',0.1300000000000000044,'',''); -INSERT INTO LimitCapacity VALUES('utopia',2000,'E31','ge',0.1300000000000000044,'',''); -INSERT INTO LimitCapacity VALUES('utopia',2010,'E31','ge',0.1300000000000000044,'',''); -INSERT INTO LimitCapacity VALUES('utopia',1990,'SRE','ge',0.1000000000000000055,'',''); -INSERT INTO LimitCapacity VALUES('utopia',1990,'E31','le',0.1300000000000000044,'',''); -INSERT INTO LimitCapacity VALUES('utopia',2000,'E31','le',0.1700000000000000122,'',''); -INSERT INTO LimitCapacity VALUES('utopia',2010,'E31','le',0.21000000000000002,'',''); -INSERT INTO LimitCapacity VALUES('utopia',1990,'RHE','le',0.0,'',''); -INSERT INTO LimitCapacity VALUES('utopia',1990,'TXD','le',0.5999999999999999778,'',''); -INSERT INTO LimitCapacity VALUES('utopia',2000,'TXD','le',1.760000000000000008,'',''); -INSERT INTO LimitCapacity VALUES('utopia',2010,'TXD','le',4.759999999999999787,'',''); -CREATE TABLE LimitCapacityShare +INSERT INTO limit_capacity VALUES('utopia',1990,'E31','ge',0.1300000000000000044,'',''); +INSERT INTO limit_capacity VALUES('utopia',2000,'E31','ge',0.1300000000000000044,'',''); +INSERT INTO limit_capacity VALUES('utopia',2010,'E31','ge',0.1300000000000000044,'',''); +INSERT INTO limit_capacity VALUES('utopia',1990,'SRE','ge',0.1000000000000000055,'',''); +INSERT INTO limit_capacity VALUES('utopia',1990,'E31','le',0.1300000000000000044,'',''); +INSERT INTO limit_capacity VALUES('utopia',2000,'E31','le',0.1700000000000000122,'',''); +INSERT INTO limit_capacity VALUES('utopia',2010,'E31','le',0.21000000000000002,'',''); +INSERT INTO limit_capacity VALUES('utopia',1990,'RHE','le',0.0,'',''); +INSERT INTO limit_capacity VALUES('utopia',1990,'TXD','le',0.5999999999999999778,'',''); +INSERT INTO limit_capacity VALUES('utopia',2000,'TXD','le',1.760000000000000008,'',''); +INSERT INTO limit_capacity VALUES('utopia',2010,'TXD','le',4.759999999999999787,'',''); +CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER @@ -1015,7 +1015,7 @@ CREATE TABLE LimitCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitNewCapacity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER @@ -1028,7 +1028,7 @@ CREATE TABLE LimitNewCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitNewCapacityShare +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -1041,7 +1041,7 @@ CREATE TABLE LimitNewCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitResource +CREATE TABLE limit_resource ( region TEXT, tech_or_group TEXT, @@ -1052,7 +1052,7 @@ CREATE TABLE LimitResource notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitSeasonalCapacityFactor +CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES Region (region), @@ -1068,7 +1068,7 @@ CREATE TABLE LimitSeasonalCapacityFactor notes TEXT, PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE LimitTechInputSplit +CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER @@ -1083,7 +1083,7 @@ CREATE TABLE LimitTechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechInputSplitAnnual +CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER @@ -1098,7 +1098,7 @@ CREATE TABLE LimitTechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechOutputSplit +CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER @@ -1113,13 +1113,13 @@ CREATE TABLE LimitTechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -INSERT INTO LimitTechOutputSplit VALUES('utopia',1990,'SRE','DSL','ge',0.6999999999999999556,''); -INSERT INTO LimitTechOutputSplit VALUES('utopia',2000,'SRE','DSL','ge',0.6999999999999999556,''); -INSERT INTO LimitTechOutputSplit VALUES('utopia',2010,'SRE','DSL','ge',0.6999999999999999556,''); -INSERT INTO LimitTechOutputSplit VALUES('utopia',1990,'SRE','GSL','ge',0.2999999999999999889,''); -INSERT INTO LimitTechOutputSplit VALUES('utopia',2000,'SRE','GSL','ge',0.2999999999999999889,''); -INSERT INTO LimitTechOutputSplit VALUES('utopia',2010,'SRE','GSL','ge',0.2999999999999999889,''); -CREATE TABLE LimitTechOutputSplitAnnual +INSERT INTO limit_tech_output_split VALUES('utopia',1990,'SRE','DSL','ge',0.6999999999999999556,''); +INSERT INTO limit_tech_output_split VALUES('utopia',2000,'SRE','DSL','ge',0.6999999999999999556,''); +INSERT INTO limit_tech_output_split VALUES('utopia',2010,'SRE','DSL','ge',0.6999999999999999556,''); +INSERT INTO limit_tech_output_split VALUES('utopia',1990,'SRE','GSL','ge',0.2999999999999999889,''); +INSERT INTO limit_tech_output_split VALUES('utopia',2000,'SRE','GSL','ge',0.2999999999999999889,''); +INSERT INTO limit_tech_output_split VALUES('utopia',2010,'SRE','GSL','ge',0.2999999999999999889,''); +CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER @@ -1134,7 +1134,7 @@ CREATE TABLE LimitTechOutputSplitAnnual notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitEmission +CREATE TABLE limit_emission ( region TEXT, period INTEGER @@ -1291,7 +1291,7 @@ CREATE TABLE OutputStorageLevel level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); -CREATE TABLE PlanningReserveMargin +CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY @@ -1299,7 +1299,7 @@ CREATE TABLE PlanningReserveMargin margin REAL, notes TEXT ); -CREATE TABLE RampDownHourly +CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT @@ -1308,7 +1308,7 @@ CREATE TABLE RampDownHourly notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUpHourly +CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT @@ -1324,7 +1324,7 @@ CREATE TABLE Region notes TEXT ); INSERT INTO Region VALUES('utopia',NULL); -CREATE TABLE ReserveCapacityDerate +CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER @@ -1340,7 +1340,7 @@ CREATE TABLE ReserveCapacityDerate CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE TimeSegmentFraction -( +( period INTEGER REFERENCES TimePeriod (period), season TEXT @@ -1370,7 +1370,7 @@ INSERT INTO TimeSegmentFraction VALUES(2010,'summer','day',0.166699999999999987, INSERT INTO TimeSegmentFraction VALUES(2010,'summer','night',0.08329999999999999905,'# S-N'); INSERT INTO TimeSegmentFraction VALUES(2010,'winter','day',0.3332999999999999852,'# W-D'); INSERT INTO TimeSegmentFraction VALUES(2010,'winter','night',0.166699999999999987,'# W-N'); -CREATE TABLE StorageDuration +CREATE TABLE storage_duration ( region TEXT, tech TEXT, @@ -1378,7 +1378,7 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE LifetimeSurvivalCurve +CREATE TABLE lifetime_survival_curve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -1441,7 +1441,7 @@ INSERT INTO TimeSeason VALUES(2000,3,'winter',NULL); INSERT INTO TimeSeason VALUES(2010,1,'inter',NULL); INSERT INTO TimeSeason VALUES(2010,2,'summer',NULL); INSERT INTO TimeSeason VALUES(2010,3,'winter',NULL); -CREATE TABLE TimeSeasonSequential +CREATE TABLE time_season_sequential ( period INTEGER REFERENCES TimePeriod (period), diff --git a/data_files/monte_carlo/run_settings_1.csv b/data_files/monte_carlo/run_settings_1.csv index 869ee12dd..4b785e061 100644 --- a/data_files/monte_carlo/run_settings_1.csv +++ b/data_files/monte_carlo/run_settings_1.csv @@ -1,5 +1,5 @@ run,param,index,mod,value,notes 1,MaxCapacity,utopia|2010|TXD,a,-1.0,reduce the max capacity of TXD in region Utopia in period 2010 by 1.0 units (absolute) 2,Demand,utopia|*|RH,r,0.5,make Res Heat costlier by 50% in all 3 periods -2,CostVariable,*|1990/2000|IMPOIL1|*,s,20.0,substitute cost of 20.0 for var cost of IMPOIL in periods 1990/2000 in all regions (just utopia exists) for all vintages -3,CostVariable,china|1990|IMPOIL1|*,s,1000,bad input: unknown region (china) should fail and be logged \ No newline at end of file +2,cost_variable,*|1990/2000|IMPOIL1|*,s,20.0,substitute cost of 20.0 for var cost of IMPOIL in periods 1990/2000 in all regions (just utopia exists) for all vintages +3,cost_variable,china|1990|IMPOIL1|*,s,1000,bad input: unknown region (china) should fail and be logged diff --git a/data_files/temoa_basics_0.sql b/data_files/temoa_basics_0.sql index 280e3e6a4..effa1ced0 100644 --- a/data_files/temoa_basics_0.sql +++ b/data_files/temoa_basics_0.sql @@ -23,7 +23,7 @@ CREATE TABLE IF NOT EXISTS MetaDataReal REPLACE INTO MetaDataReal VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); REPLACE INTO MetaDataReal -VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in LoanRate table'); +VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in loan_rate table'); CREATE TABLE IF NOT EXISTS Commodity ( @@ -45,7 +45,7 @@ REPLACE INTO CommodityType VALUES ('p', 'physical commodity'); REPLACE INTO CommodityType VALUES ('d', 'demand commodity'); -CREATE TABLE IF NOT EXISTS CostFixed +CREATE TABLE IF NOT EXISTS cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -59,7 +59,7 @@ CREATE TABLE IF NOT EXISTS CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE IF NOT EXISTS CostInvest +CREATE TABLE IF NOT EXISTS cost_invest ( region TEXT, tech TEXT @@ -71,7 +71,7 @@ CREATE TABLE IF NOT EXISTS CostInvest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE IF NOT EXISTS CostVariable +CREATE TABLE IF NOT EXISTS cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -97,7 +97,7 @@ CREATE TABLE IF NOT EXISTS Demand notes TEXT, PRIMARY KEY (region, period, commodity) ); -CREATE TABLE IF NOT EXISTS Efficiency +CREATE TABLE IF NOT EXISTS efficiency ( region TEXT, input_comm TEXT @@ -113,7 +113,7 @@ CREATE TABLE IF NOT EXISTS Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -CREATE TABLE IF NOT EXISTS LifetimeProcess +CREATE TABLE IF NOT EXISTS lifetime_process ( region TEXT, tech TEXT @@ -124,7 +124,7 @@ CREATE TABLE IF NOT EXISTS LifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE IF NOT EXISTS LifetimeTech +CREATE TABLE IF NOT EXISTS lifetime_tech ( region TEXT, tech TEXT @@ -371,4 +371,4 @@ REPLACE INTO TimePeriodType VALUES('f', 'future'); COMMIT; -PRAGMA FOREIGN_KEYS = 1; \ No newline at end of file +PRAGMA FOREIGN_KEYS = 1; diff --git a/data_files/temoa_basics_1.sql b/data_files/temoa_basics_1.sql index 717c9ee18..d951941e1 100644 --- a/data_files/temoa_basics_1.sql +++ b/data_files/temoa_basics_1.sql @@ -25,9 +25,9 @@ CREATE TABLE IF NOT EXISTS MetaDataReal REPLACE INTO MetaDataReal VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); REPLACE INTO MetaDataReal -VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in LoanRate table'); +VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in loan_rate table'); -CREATE TABLE IF NOT EXISTS CapacityFactorTech +CREATE TABLE IF NOT EXISTS capacity_factor_tech ( region TEXT, period INTEGER @@ -76,7 +76,7 @@ REPLACE INTO CommodityType VALUES ('d', 'demand commodity'); REPLACE INTO CommodityType VALUES ('e', 'emissions commodity'); -CREATE TABLE IF NOT EXISTS CostEmission +CREATE TABLE IF NOT EXISTS cost_emission ( region TEXT, period INTEGER @@ -88,7 +88,7 @@ CREATE TABLE IF NOT EXISTS CostEmission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -CREATE TABLE IF NOT EXISTS CostFixed +CREATE TABLE IF NOT EXISTS cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -102,7 +102,7 @@ CREATE TABLE IF NOT EXISTS CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE IF NOT EXISTS CostInvest +CREATE TABLE IF NOT EXISTS cost_invest ( region TEXT, tech TEXT @@ -114,7 +114,7 @@ CREATE TABLE IF NOT EXISTS CostInvest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE IF NOT EXISTS CostVariable +CREATE TABLE IF NOT EXISTS cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -156,7 +156,7 @@ CREATE TABLE IF NOT EXISTS DemandSpecificDistribution PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -CREATE TABLE IF NOT EXISTS Efficiency +CREATE TABLE IF NOT EXISTS efficiency ( region TEXT, input_comm TEXT @@ -172,7 +172,7 @@ CREATE TABLE IF NOT EXISTS Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -CREATE TABLE IF NOT EXISTS EmissionActivity +CREATE TABLE IF NOT EXISTS emission_activity ( region TEXT, emis_comm TEXT @@ -190,7 +190,7 @@ CREATE TABLE IF NOT EXISTS EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -CREATE TABLE IF NOT EXISTS ExistingCapacity +CREATE TABLE IF NOT EXISTS existing_capacity ( region TEXT, tech TEXT @@ -202,7 +202,7 @@ CREATE TABLE IF NOT EXISTS ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE IF NOT EXISTS LifetimeProcess +CREATE TABLE IF NOT EXISTS lifetime_process ( region TEXT, tech TEXT @@ -213,7 +213,7 @@ CREATE TABLE IF NOT EXISTS LifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE IF NOT EXISTS LifetimeTech +CREATE TABLE IF NOT EXISTS lifetime_tech ( region TEXT, tech TEXT @@ -419,7 +419,7 @@ CREATE TABLE IF NOT EXISTS SectorLabel sector TEXT PRIMARY KEY, notes TEXT ); -CREATE TABLE IF NOT EXISTS StorageDuration +CREATE TABLE IF NOT EXISTS storage_duration ( region TEXT, tech TEXT, @@ -492,7 +492,7 @@ CREATE TABLE IF NOT EXISTS TimeSeason PRIMARY KEY (period, sequence, season) ); CREATE TABLE IF NOT EXISTS TimeSegmentFraction -( +( period INTEGER REFERENCES TimePeriod (period), season TEXT @@ -506,4 +506,4 @@ CREATE TABLE IF NOT EXISTS TimeSegmentFraction ); COMMIT; -PRAGMA FOREIGN_KEYS = 1; \ No newline at end of file +PRAGMA FOREIGN_KEYS = 1; diff --git a/data_files/temoa_basics_2.sql b/data_files/temoa_basics_2.sql index 24a4797b5..f65169e0b 100644 --- a/data_files/temoa_basics_2.sql +++ b/data_files/temoa_basics_2.sql @@ -25,9 +25,9 @@ CREATE TABLE IF NOT EXISTS MetaDataReal REPLACE INTO MetaDataReal VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); REPLACE INTO MetaDataReal -VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in LoanRate table'); +VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in loan_rate table'); -CREATE TABLE IF NOT EXISTS CapacityFactorTech +CREATE TABLE IF NOT EXISTS capacity_factor_tech ( region TEXT, period INTEGER @@ -76,7 +76,7 @@ REPLACE INTO CommodityType VALUES ('d', 'demand commodity'); REPLACE INTO CommodityType VALUES ('e', 'emissions commodity'); -CREATE TABLE IF NOT EXISTS CostEmission +CREATE TABLE IF NOT EXISTS cost_emission ( region TEXT, period INTEGER @@ -88,7 +88,7 @@ CREATE TABLE IF NOT EXISTS CostEmission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -CREATE TABLE IF NOT EXISTS CostFixed +CREATE TABLE IF NOT EXISTS cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -102,7 +102,7 @@ CREATE TABLE IF NOT EXISTS CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE IF NOT EXISTS CostInvest +CREATE TABLE IF NOT EXISTS cost_invest ( region TEXT, tech TEXT @@ -114,7 +114,7 @@ CREATE TABLE IF NOT EXISTS CostInvest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE IF NOT EXISTS CostVariable +CREATE TABLE IF NOT EXISTS cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -156,7 +156,7 @@ CREATE TABLE IF NOT EXISTS DemandSpecificDistribution PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -CREATE TABLE IF NOT EXISTS Efficiency +CREATE TABLE IF NOT EXISTS efficiency ( region TEXT, input_comm TEXT @@ -172,7 +172,7 @@ CREATE TABLE IF NOT EXISTS Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -CREATE TABLE IF NOT EXISTS EmissionActivity +CREATE TABLE IF NOT EXISTS emission_activity ( region TEXT, emis_comm TEXT @@ -190,7 +190,7 @@ CREATE TABLE IF NOT EXISTS EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -CREATE TABLE IF NOT EXISTS ExistingCapacity +CREATE TABLE IF NOT EXISTS existing_capacity ( region TEXT, tech TEXT @@ -202,7 +202,7 @@ CREATE TABLE IF NOT EXISTS ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE IF NOT EXISTS LifetimeProcess +CREATE TABLE IF NOT EXISTS lifetime_process ( region TEXT, tech TEXT @@ -213,7 +213,7 @@ CREATE TABLE IF NOT EXISTS LifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE IF NOT EXISTS LifetimeTech +CREATE TABLE IF NOT EXISTS lifetime_tech ( region TEXT, tech TEXT @@ -222,7 +222,7 @@ CREATE TABLE IF NOT EXISTS LifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE IF NOT EXISTS LimitActivity +CREATE TABLE IF NOT EXISTS limit_activity ( region TEXT, period INTEGER @@ -235,7 +235,7 @@ CREATE TABLE IF NOT EXISTS LimitActivity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE IF NOT EXISTS LimitActivityShare +CREATE TABLE IF NOT EXISTS limit_activity_share ( region TEXT, period INTEGER @@ -248,7 +248,7 @@ CREATE TABLE IF NOT EXISTS LimitActivityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE IF NOT EXISTS LimitAnnualCapacityFactor +CREATE TABLE IF NOT EXISTS limit_annual_capacity_factor ( region TEXT, period INTEGER @@ -264,7 +264,7 @@ CREATE TABLE IF NOT EXISTS LimitAnnualCapacityFactor PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE IF NOT EXISTS LimitCapacity +CREATE TABLE IF NOT EXISTS limit_capacity ( region TEXT, period INTEGER @@ -277,7 +277,7 @@ CREATE TABLE IF NOT EXISTS LimitCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE IF NOT EXISTS LimitCapacityShare +CREATE TABLE IF NOT EXISTS limit_capacity_share ( region TEXT, period INTEGER @@ -290,7 +290,7 @@ CREATE TABLE IF NOT EXISTS LimitCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE IF NOT EXISTS LimitDegrowthCapacity +CREATE TABLE IF NOT EXISTS limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, @@ -302,7 +302,7 @@ CREATE TABLE IF NOT EXISTS LimitDegrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE IF NOT EXISTS LimitEmission +CREATE TABLE IF NOT EXISTS limit_emission ( region TEXT, period INTEGER @@ -316,7 +316,7 @@ CREATE TABLE IF NOT EXISTS LimitEmission notes TEXT, PRIMARY KEY (region, period, emis_comm, operator) ); -CREATE TABLE IF NOT EXISTS LimitGrowthCapacity +CREATE TABLE IF NOT EXISTS limit_growth_capacity ( region TEXT, tech_or_group TEXT, @@ -328,7 +328,7 @@ CREATE TABLE IF NOT EXISTS LimitGrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE IF NOT EXISTS LimitNewCapacity +CREATE TABLE IF NOT EXISTS limit_new_capacity ( region TEXT, period INTEGER @@ -341,7 +341,7 @@ CREATE TABLE IF NOT EXISTS LimitNewCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE IF NOT EXISTS LimitNewCapacityShare +CREATE TABLE IF NOT EXISTS limit_new_capacity_share ( region TEXT, period INTEGER @@ -354,7 +354,7 @@ CREATE TABLE IF NOT EXISTS LimitNewCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE IF NOT EXISTS LimitResource +CREATE TABLE IF NOT EXISTS limit_resource ( region TEXT, tech_or_group TEXT, @@ -365,7 +365,7 @@ CREATE TABLE IF NOT EXISTS LimitResource notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE IF NOT EXISTS LimitSeasonalCapacityFactor +CREATE TABLE IF NOT EXISTS limit_seasonal_capacity_factor ( region TEXT REFERENCES Region (region), @@ -400,7 +400,7 @@ CREATE TABLE IF NOT EXISTS LimitStorageLevelFraction notes TEXT, PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE IF NOT EXISTS LimitTechInputSplit +CREATE TABLE IF NOT EXISTS limit_tech_input_split ( region TEXT, period INTEGER @@ -415,7 +415,7 @@ CREATE TABLE IF NOT EXISTS LimitTechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE IF NOT EXISTS LimitTechInputSplitAnnual +CREATE TABLE IF NOT EXISTS limit_tech_input_split_annual ( region TEXT, period INTEGER @@ -430,7 +430,7 @@ CREATE TABLE IF NOT EXISTS LimitTechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE IF NOT EXISTS LimitTechOutputSplit +CREATE TABLE IF NOT EXISTS limit_tech_output_split ( region TEXT, period INTEGER @@ -445,7 +445,7 @@ CREATE TABLE IF NOT EXISTS LimitTechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE IF NOT EXISTS LimitTechOutputSplitAnnual +CREATE TABLE IF NOT EXISTS limit_tech_output_split_annual ( region TEXT, period INTEGER @@ -665,7 +665,7 @@ CREATE TABLE IF NOT EXISTS SectorLabel sector TEXT PRIMARY KEY, notes TEXT ); -CREATE TABLE IF NOT EXISTS StorageDuration +CREATE TABLE IF NOT EXISTS storage_duration ( region TEXT, tech TEXT, @@ -738,7 +738,7 @@ CREATE TABLE IF NOT EXISTS TimeSeason PRIMARY KEY (period, sequence, season) ); CREATE TABLE IF NOT EXISTS TimeSegmentFraction -( +( period INTEGER REFERENCES TimePeriod (period), season TEXT @@ -752,4 +752,4 @@ CREATE TABLE IF NOT EXISTS TimeSegmentFraction ); COMMIT; -PRAGMA FOREIGN_KEYS = 1; \ No newline at end of file +PRAGMA FOREIGN_KEYS = 1; diff --git a/docs/Database Upgrade and Troubleshooting.md b/docs/Database Upgrade and Troubleshooting.md index e71f82874..0a47e2b92 100644 --- a/docs/Database Upgrade and Troubleshooting.md +++ b/docs/Database Upgrade and Troubleshooting.md @@ -5,12 +5,12 @@ The upgrades in Version 3 of the Temoa codebase include much tighter scrutiny of the commodity network via source tracing. Source tracing is optional in some modes, but mandatory in Myopic mode. The goal of source tracing is to ensure the network of commodities is performing properly and not allowing -artificial sources of commodities to enter the network. Additional details on this process are in +artificial sources of commodities to enter the network. Additional details on this process are in the `commodity network notes.md` file. The complexity of some of the larger databases and networks and the actions of source tracing can pose challenges in troubleshooting models that are infeasible or unbounded. This set of notes -is intended to help modelers working with new large datasets or transitioned datasets in +is intended to help modelers working with new large datasets or transitioned datasets in working through infeasibilities and "getting the model breathing" so that refinements can be made. ## First steps @@ -21,13 +21,13 @@ following **must** be done to get the model working. 1. Mark Source Commodities. In the `Commodity` table, source commodities must be marked with an "s" for the flag value. This action identifies them as bedrock sources that serve as sources for network analysis. Things like "Ethos" are typically sources. A source commodity -is interpreted as a freely available starting commodity that has no predecessors. Multiple +is interpreted as a freely available starting commodity that has no predecessors. Multiple sources are possible for bookkeeping or model clarity. 2. Identify Unlimited Capacity Technologies. The `Technology` table has a new field labeled -`unlim_cap` to identify technologies that have no capacity limit. This may represent things +`unlim_cap` to identify technologies that have no capacity limit. This may represent things like imports or use taxes or other notions that don't logically support a capacity determination/assignment. Assigning technologies to this category does several things. -First, it makes the model smaller and more flexible because capacity variables are +First, it makes the model smaller and more flexible because capacity variables are excluded for the technology, although activity is still an active variable. It also enables modes like Myopic to function more cleanly because the model does not make capacity decisions on things that may need to be revised with higher demands in later @@ -42,21 +42,21 @@ the log file should be addressed. If the model does not solve after the steps above the following are possible actions to take. Note that several of these involve altering the model code and should be done carefully. A suggested approach for items that involve injecting or commenting out code is to try them, -make corrections as needed to the data, and then use Git's `rollback` feature on the +make corrections as needed to the data, and then use Git's `rollback` feature on the core model code to undo any "hacks" or patches that were used. In no particular order: -- If the model is unbounded. Look at negative cost items carefully. A technique to +- If the model is unbounded. Look at negative cost items carefully. A technique to limit runaway activity is to limit all flows in the model. The following code can be slipped in to the `temoa_model.py` code anywhere in the constraint section. It will limit **all** flows to an upper bound. If using this approach, the -modeler should also limit any arbitrarily large demands in the +modeler should also limit any arbitrarily large demands in the demand table that may need to be revised downward in conjuction with this limit. The `OutputFlowOut` table can then be inspected for unusually high activity. ``` -@M.Constraint(M.FlowVar_rpsditvo) +@M.Constraint(M.flow_var_rpsditvo) def flow_max(M, *rpsditvo): - return M.V_FlowOut[rpsditvo] <= 10_000_000 + return M.v_flow_out[rpsditvo] <= 10_000_000 ``` - Double check that items in the first period that should be marked as `unlim_capacity` @@ -69,7 +69,7 @@ Of note in this example, 2020 is the first optimization period: -- technologies unique to first period SELECT t.tech, unlim_cap FROM Technology t - LEFT OUTER JOIN (SELECT DISTINCT e.tech FROM Efficiency e WHERE e.vintage != 2020) AS base + LEFT OUTER JOIN (SELECT DISTINCT e.tech FROM efficiency e WHERE e.vintage != 2020) AS base ON t.tech = base.tech WHERE base.tech IS NULL; ``` @@ -79,4 +79,4 @@ easily by commenting out the read-in process for parameter data in `hybrid_loade It should be possible to search for the table name and then just comment out the entire block that reads in that table. Much easier than manipulating the database. Consideration for excluding MinActivity, MaxActivity, EmissionLimit, etc. is -suggested. \ No newline at end of file +suggested. diff --git a/docs/commodity network notes.md b/docs/commodity network notes.md index 1cc57ca7c..123e60a2f 100644 --- a/docs/commodity network notes.md +++ b/docs/commodity network notes.md @@ -14,7 +14,7 @@ In a standard, static, and lossless ``s-t`` network, flow balance constraints fa place naturally. The input flow at the source, ``s`` is set to equal the output flow at termination point ``t`` and for all intermediary nodes, flow in is constrained to equal flow out. Temoa's energy network, however, is not static and has losses in the form -of efficiency losses within the ``tech`` processes that serve as the links between +of efficiency losses within the ``tech`` processes that serve as the links between ``commodity`` nodes. When a model is solved over several time periods with "perfect foresight" the network may look quite different in each region and time period based on endogenous selections of new technologies, lifetime expirations, etc. This diversification of networks is compounded when running the @@ -28,12 +28,12 @@ to help avoid pitfalls.... The energy network in each region and period is built dynamically from the `techs` that are identified as existing capacity and whatever the model has ability to build from elements in -the optimization window identified in the ``Efficiency`` table. In order enforce conservation of +the optimization window identified in the ``efficiency`` table. In order enforce conservation of flow constraints, the model identifies output flows (commodities), including the demand commodities and inventories all possible `techs` (existing or available) that *could* produce that commodity from any input commodity and enforces flow balance by requiring capacity in one of the available technologies, so that *some tech* must provide the flow to support that output. -This is the basis for satisfying demands at the termination of the network. +This is the basis for satisfying demands at the termination of the network. If at any point along the chain there are no `techs` available to produce the commodity in question, the model *assumes this is a base or source commodity* for @@ -56,9 +56,10 @@ During pre-processing, before the model is built, Temoa can identify breaks in t data before the model is loaded/built. Temoa can also check network integrity on a built model before solve is initiated. Currently, discrepancies are noted in the log file for the model. The user can also request network plots, which are browser-capable html files that can be used in diagnosis of problem areas. The general intent is to ensure that all flows to Demand -commodities can be cleanly traced back to original sources. +commodities can be cleanly traced back to original sources. + +#### An example -#### An example: Consider the simple network below with one source, one demand, and intermediate physical commodities ``{P1, P2, P3, P4}`` and the connective technologies ``T1`` through ``T6``. This well-connected network works as intended and the singular demand is traceable via either path @@ -66,35 +67,32 @@ back to source. ![Good Network](source/images/commodity_network.png) - A defective network (shown below) may occur for a several reasons, as cited in the previous section. Suppose that for some reason `T3` is no longer available in this or a subsequent period (never made available, lifetime expiration earlier than other links, not selected by myopic process--which would normally remove the other links as well, unless they had replacement vintages and ``T3`` did not, etc.) Several problems now exist: -1. Supply side orphans. Technology ``T1`` is now a "supply side" orphan, which shouldn't cause model problems, but represents bloat +1. Supply side orphans. Technology ``T1`` is now a "supply side" orphan, which shouldn't cause model problems, but represents bloat in the model. Legacy (pre version 3.0) Temoa does screen for unused outputs (like ``P1`` in this case) that are not used by other processes and are not end demands, but it is currently only done 'globally' in all periods/regions. Resultantly, -this orphan may not trigger a model error if it were used in another region/period. +this orphan may not trigger a model error if it were used in another region/period. These will now generate **WARNING** level log entries with source tracing. It *could* be a source of unbounded behavior in the case where the -modeler attempts to use negative values for costs. +modeler attempts to use negative values for costs. -2. Technology ``T5`` and perhaps a now-available new vintage ``T5'`` are now "demand-side" orphans. These are -problematic and will generate **WARNING** level log entries by source tracing because they would allow a +2. Technology ``T5`` and perhaps a now-available new vintage ``T5'`` are now "demand-side" orphans. These are +problematic and will generate **WARNING** level log entries by source tracing because they would allow a false/unlimited supply of ``P3`` as their inputs. -3. New technology ``T7`` (and any other linkages that are not reachable from either source or demand) +3. New technology ``T7`` (and any other linkages that are not reachable from either source or demand) are complete orphans. They will generate a **WARNING** level log entry during source tracing. - - ![Bad Network](source/images/broken_commodity_network.png) Tech Suppression --------------- -When source tracing is used, Temoa will attempt to remedy network escapes as described above by suppressing +When source tracing is used, Temoa will attempt to remedy network escapes as described above by suppressing problematic `techs` or chains of technologies. During runs where source tracing is enabled, Temoa's internal `Network Data Magager` will preload essential data in order to analyze all networks (each region/period) within the current optimization window. Network tracing from demands down and sources up reveals `techs` that are "orphaned" @@ -102,28 +100,29 @@ These `techs` and any unused commodities, etc. are removed with log entries and used to filter the ingestion of the full model data to support the build. ### Basic rules for `tech` Suppression + - All demand side orphans (and chains of orphans) are suppressed -- All supply-side orphans (and chains of orpahns) are suppressed -- For technologies that have multiple inputs or outputs, EACH commodity is treated separately (as it is -represented in the `Efficiency` table.) The modeler is advised to screen the log file for these entries if a +* All supply-side orphans (and chains of orpahns) are suppressed +* For technologies that have multiple inputs or outputs, EACH commodity is treated separately (as it is +represented in the `efficiency` table.) The modeler is advised to screen the log file for these entries if a particular commodity is essential (a catalyst for example?) to a particular operation. -- For linked technologies, an "all or nothing" logic is implemented such that both the driver and driven +* For linked technologies, an "all or nothing" logic is implemented such that both the driver and driven technologies must prove independently viable (without regard for the emission linkage) or the pair will be suppressed. -- Currently, exchange technologies are not checked during source tracing. Any `tech` with a region link -(denoted with a dash `R1-R2`) provided for the region name is assumed good. It behooves the modeler to +* Currently, exchange technologies are not checked during source tracing. Any `tech` with a region link +(denoted with a dash `R1-R2`) provided for the region name is assumed good. It behooves the modeler to ensure that both ends of each link are well-connected in the model and to review their performance in output. ### Views across modeling periods -The approach descibed above is applied individually to each region-period pair within the optimization window. +The approach descibed above is applied individually to each region-period pair within the optimization window. Recall, that for perfect foresight runs, this will be all future periods. For myopic or other limited-visibility runs, -this will be applied to each period within view. The orphans are identified on a by period-region basis, but _the -suppression is applied for all periods within the view._ For example, if technology `power_plant` has a vintage of +this will be applied to each period within view. The orphans are identified on a by period-region basis, but *the +suppression is applied for all periods within the view.* For example, if technology `power_plant` has a vintage of 2020 and a lifetime of 40 years covering model periods {2020, 2030, 2040, 2050} and it is not viable in 2030, it will be suppressed and not available in any of the periods. Currently, for myopic applications, this decision is made on a per-iteration basis, so the technology may be -suppressed within the current iteration only. For example, if the myopic view was 1 period, and if the `power_plant` +suppressed within the current iteration only. For example, if the myopic view was 1 period, and if the `power_plant` was selected for build in its vintage year, 2020, the modeler may see that it is used in 2020, "suppressed" in 2030 because it may run freely or cause problems in that period, but available again in 2040-2050. This may/may not be desired behavior and the modeler should be aware of these behaviors logged in the log file. @@ -134,12 +133,3 @@ before there is a user of same) or via myopic actions were a technology in a cha rendering other processes in the chain irrelevant in a later period. The main goal of using tracing and suppression is to prevent "free" midstream commodities from erroneously feeding processes and prevent free-running techs that might have a negative cost from making the model unbounded or infeasible. - - - - - - - - - diff --git a/docs/source/Documentation.rst b/docs/source/Documentation.rst index 27b6e45c9..02ff833e8 100644 --- a/docs/source/Documentation.rst +++ b/docs/source/Documentation.rst @@ -329,28 +329,28 @@ recommend that you populate input tables in the following order: * MetaData (days_per_period) * Demand * DemandSpecificDistribution - * Efficiency - * ExistingCapacity + * efficiency + * existing_capacity * CapacityFactor - * CapacityFactorProcess (only if CF varies by vintage; overwrites CapacityFactor) + * capacity_factor_process (only if CF varies by vintage; overwrites CapacityFactor) * CapacityToActivity - * CostFixed - * CostInvest - * CostVariable - * EmissionActivity - * LifetimeTech - * LifetimeProcess (only if LT varies by vintage; overwrites LifetimeTech) + * cost_fixed + * cost_invest + * cost_variable + * emission_activity + * lifetime_tech + * lifetime_process (only if LT varies by vintage; overwrites lifetime_tech) * TimeSegmentFraction: proportion of each period represented by each time slice **Group 4: parameters used to define constraints within Temoa** - * LimitActivity - * LimitCapacity - * LimitEmission - * LimitGrowthCapacity - * LimitNewCapacity - * LimitResource - * LimitTechInputSplit - * LimitTechOutputSplit + * limit_activity + * limit_capacity + * limit_emission + * limit_growth_capacity + * limit_new_capacity + * limit_resource + * limit_tech_input_split + * limit_tech_output_split For help getting started, take a look at how :code:`data_files/temoa_utopia.sql` is constructed. Use :code:`data_files/temoa_schema.sql` (a database file with the requisite @@ -940,54 +940,54 @@ Parameters :header: "Parameter","Temoa Name","Domain","Short Description" :widths: 14, 27, 10, 49 - ":math:`\text{CC}_{r,p,t,v}`","CapacityCredit",":math:`\mathbb{I}`","Process-specific capacity credit" - ":math:`\text{CFT}_{r,s,d,t}`","CapacityFactorTech",":math:`\mathbb{I}`","Technology-specific capacity factor" - ":math:`\text{CFP}_{r,s,d,t,v}`","CapacityFactorProcess",":math:`\mathbb{I}`","Process-specific capacity factor" + ":math:`\text{CC}_{r,p,t,v}`","capacity_credit",":math:`\mathbb{I}`","Process-specific capacity credit" + ":math:`\text{CFT}_{r,s,d,t}`","capacity_factor_tech",":math:`\mathbb{I}`","Technology-specific capacity factor" + ":math:`\text{CFP}_{r,s,d,t,v}`","capacity_factor_process",":math:`\mathbb{I}`","Process-specific capacity factor" ":math:`\text{C2A}_{r,t,v}`","CapacityToActivity",":math:`\mathbb{R}^+_0`","Converts from capacity to activity units" - ":math:`\text{CF}_{r,p,t,v}`","CostFixed",":math:`\mathbb{R}`","Fixed operations \& maintenance cost" - ":math:`\text{CI}_{r,t,v}`","CostInvest",":math:`\mathbb{R}`","Tech-specific investment cost" - ":math:`\text{CV}_{r,p,t,v}`","CostVariable",":math:`\mathbb{R}`","Variable operations \& maintenance cost" - ":math:`\text{CON}_{r,i,t,v}`","ConstructionInput",":math:`\mathbb{R}`","Commodities consumed by creation of process capacity" + ":math:`\text{CF}_{r,p,t,v}`","cost_fixed",":math:`\mathbb{R}`","Fixed operations \& maintenance cost" + ":math:`\text{CI}_{r,t,v}`","cost_invest",":math:`\mathbb{R}`","Tech-specific investment cost" + ":math:`\text{CV}_{r,p,t,v}`","cost_variable",":math:`\mathbb{R}`","Variable operations \& maintenance cost" + ":math:`\text{CON}_{r,i,t,v}`","construction_input",":math:`\mathbb{R}`","Commodities consumed by creation of process capacity" ":math:`\text{DEM}_{r,p,c}`","Demand",":math:`\mathbb{R}^+_0`","End-use demands, by period" ":math:`\text{DDD}_{p,s,d}`","DemandDefaultDistribution",":math:`\mathbb{I}`","Default demand distribution (currently not supported)" ":math:`\text{DSD}_{r,p,s,d,c}`","DemandSpecificDistribution",":math:`\mathbb{I}`","Demand-specific distribution" - ":math:`\text{EFF}_{r,i,t,v,o}`","Efficiency",":math:`\mathbb{R}^+_0`","Tech- and commodity-specific efficiency" - ":math:`\text{EAC}_{r,i,t,v,o,e}`","EmissionActivity",":math:`\mathbb{R}`","Tech-specific emissions rate" - ":math:`\text{EE}_{r,t,v,e}`","EmissionEmbodied",":math:`\mathbb{R}`","Emissions associated with the creation of capacity" - ":math:`\text{EEOL}_{r,t,v,e}`","EmissionEndOfLife",":math:`\mathbb{R}`","Emissions associated with the retirement/end of life of capacity" - ":math:`\text{EOLO}_{r,t,v,o}`","EndOfLifeOutput",":math:`\mathbb{R}`","Commodities produced by retirement/end of life of capacity" - ":math:`\text{ECAP}_{r,t,v}`","ExistingCapacity",":math:`\mathbb{R}^+_0`","Pre-existing capacity" + ":math:`\text{EFF}_{r,i,t,v,o}`","efficiency",":math:`\mathbb{R}^+_0`","Tech- and commodity-specific efficiency" + ":math:`\text{EAC}_{r,i,t,v,o,e}`","emission_activity",":math:`\mathbb{R}`","Tech-specific emissions rate" + ":math:`\text{EE}_{r,t,v,e}`","emission_embodied",":math:`\mathbb{R}`","Emissions associated with the creation of capacity" + ":math:`\text{EEOL}_{r,t,v,e}`","emission_end_of_life",":math:`\mathbb{R}`","Emissions associated with the retirement/end of life of capacity" + ":math:`\text{EOLO}_{r,t,v,o}`","end_of_life_output",":math:`\mathbb{R}`","Commodities produced by retirement/end of life of capacity" + ":math:`\text{ECAP}_{r,t,v}`","existing_capacity",":math:`\mathbb{R}^+_0`","Pre-existing capacity" ":math:`\text{GDR}`","GlobalDiscountRate",":math:`\mathbb{R}`","Global rate used to calculate present cost" - ":math:`\text{LTP}_{r,t,v}`","LifetimeProcess",":math:`\mathbb{N}`","Tech- and vintage-specific lifetime (default=LifetimeTech)" - ":math:`\text{LTT}_{r,t}`","LifetimeTech",":math:`\mathbb{N}`","Tech-specific lifetime (default=40 years)" - ":math:`\text{LSC}_{r,p,t,v}`","LifetimeSurvivalCurve",":math:`\mathbb{R}^+_0`","Surviving fraction of original capacity" - ":math:`\text{LIT}_{r,t,e,t}`","LinkedTechs","text","Dummy techs used to convert CO2 emissions to physical commodity" - ":math:`\text{LLP}_{r,t,v}`","LoanLifetimeProcess",":math:`\mathbb{N}`","Process-specific loan term (default=LifetimeProcess)" - ":math:`\text{LR}_{r,t,v}`","LoanRate",":math:`\mathbb{R}`","Process-specific interest rate on investment cost" - ":math:`\text{LE}_{r,p,e}`","LimitEmission",":math:`\mathbb{R}^+_0`","Limit emissions by region and period" - ":math:`\text{LA}_{r,p,t}`","LimitActivity",":math:`\mathbb{R}^+_0`","Limit tech-specific activity by region and period" - ":math:`\text{LC}_{r,p,t}`","LimitCapacity",":math:`\mathbb{R}^+_0`","Limit tech-specific capacity by period" - ":math:`\text{LR}_{r,t}`","LimitResource",":math:`\mathbb{R}^+_0`","Limit resource production by tech across time periods" + ":math:`\text{LTP}_{r,t,v}`","lifetime_process",":math:`\mathbb{N}`","Tech- and vintage-specific lifetime (default=lifetime_tech)" + ":math:`\text{LTT}_{r,t}`","lifetime_tech",":math:`\mathbb{N}`","Tech-specific lifetime (default=40 years)" + ":math:`\text{LSC}_{r,p,t,v}`","lifetime_survival_curve",":math:`\mathbb{R}^+_0`","Surviving fraction of original capacity" + ":math:`\text{LIT}_{r,t,e,t}`","linked_techs","text","Dummy techs used to convert CO2 emissions to physical commodity" + ":math:`\text{LLP}_{r,t,v}`","loan_lifetime_process",":math:`\mathbb{N}`","Process-specific loan term (default=lifetime_process)" + ":math:`\text{LR}_{r,t,v}`","loan_rate",":math:`\mathbb{R}`","Process-specific interest rate on investment cost" + ":math:`\text{LE}_{r,p,e}`","limit_emission",":math:`\mathbb{R}^+_0`","Limit emissions by region and period" + ":math:`\text{LA}_{r,p,t}`","limit_activity",":math:`\mathbb{R}^+_0`","Limit tech-specific activity by region and period" + ":math:`\text{LC}_{r,p,t}`","limit_capacity",":math:`\mathbb{R}^+_0`","Limit tech-specific capacity by period" + ":math:`\text{LR}_{r,t}`","limit_resource",":math:`\mathbb{R}^+_0`","Limit resource production by tech across time periods" ":math:`\text{LSF}_{r,p,s,d,t,v}`","LimitStorageLevelFraction",":math:`\mathbb{R}^+_0`","Limit storage level in any time slice" - ":math:`\text{MDY}`","MyopicDiscountingYear",":math:`\mathbb{N}`","Objective function NPV year when running myopically" - ":math:`\text{PRM}_{r}`","PlanningReserveMargin",":math:`\mathbb{I}`","Margin used to ensure sufficient generating capacity" - ":math:`\text{RDH}_{r,t}`","RampDownHourly",":math:`\mathbb{R}`","Hourly rate at which generation techs can ramp output down" - ":math:`\text{RUH}_{r,t}`","RampUpHourly",":math:`\mathbb{R}`","Hourly rate at which generation techs can ramp output up" - ":math:`\text{SD}_{r,t}`","StorageDuration",":math:`\mathbb{N}`","Storage duration per technology, specified in hours" - ":math:`\text{SEG}_{s,d}`","SegFrac",":math:`\mathbb{I}`","Fraction of year represented by each (s, d) tuple" + ":math:`\text{MDY}`","myopic_discounting_year",":math:`\mathbb{N}`","Objective function NPV year when running myopically" + ":math:`\text{PRM}_{r}`","planning_reserve_margin",":math:`\mathbb{I}`","Margin used to ensure sufficient generating capacity" + ":math:`\text{RDH}_{r,t}`","ramp_down_hourly",":math:`\mathbb{R}`","Hourly rate at which generation techs can ramp output down" + ":math:`\text{RUH}_{r,t}`","ramp_up_hourly",":math:`\mathbb{R}`","Hourly rate at which generation techs can ramp output up" + ":math:`\text{SD}_{r,t}`","storage_duration",":math:`\mathbb{N}`","Storage duration per technology, specified in hours" + ":math:`\text{SEG}_{s,d}`","segment_fraction",":math:`\mathbb{I}`","Fraction of year represented by each (s, d) tuple" ":math:`\text{TIS}_{r,i,t}`","TechInputSplit",":math:`\mathbb{I}`","Technology input fuel ratio at time slice level" ":math:`\text{TISA}_{r,i,t}`","TechInputSplitAnnual",":math:`\mathbb{I}`","Average annual technology input fuel ratio" ":math:`\text{TOS}_{r,t,o}`","TechOutputSplit",":math:`\mathbb{I}`","Technology output fuel ratio at time slice level" ":math:`\text{TISA}_{r,i,t}`","TechOutputSplitAnnual",":math:`\mathbb{I}`","Average annual technology output fuel ratio" - ":math:`{}^*\text{LA}_{t,v}`","LoanAnnualize",":math:`\mathbb{R}^+_0`","Loan amortization by tech and vintage; based on :math:`DR_t`" + ":math:`{}^*\text{LA}_{t,v}`","loan_annualize",":math:`\mathbb{R}^+_0`","Loan amortization by tech and vintage; based on :math:`DR_t`" ":math:`{}^*\text{MPL}_{p,t,v}`","ModelProcessLife",":math:`\mathbb{N}`","Smaller of remaining model horizon or process tech life" - ":math:`{}^*\text{PLF}_{r,p,t,v}`","ProcessLifeFrac",":math:`\mathbb{I}`","Fraction of available process capacity by region and period " + ":math:`{}^*\text{PLF}_{r,p,t,v}`","process_life_frac",":math:`\mathbb{I}`","Fraction of available process capacity by region and period " ":math:`{}^*\text{LEN}_p`","PeriodLength",":math:`\mathbb{N}`","Number of years in period :math:`p`" .. _influential_efficiency: -Efficiency +efficiency ^^^^^^^^^^ :math:`{EFF}_{r \in R, i \in C_p, t \in T, v \in V, o \in C_c}` @@ -1003,9 +1003,9 @@ efficiency table,\ [#efficiency_table]_ Temoa assumes it is not a valid process and will provide the user a warning with pointed debugging information. -.. _CapacityFactorTech: +.. _capacity_factor_tech: -CapacityCredit +capacity_credit ^^^^^^^^^^^^^^ :math:`{CC}_{r \in R, p \in P, t \in T, v \in V}` @@ -1015,23 +1015,23 @@ a process that can be relied upon during the time slice in which peak electricity demand occurs. This parameter is used in the :math:`ReserveMargin` constraint. -CapacityFactorTech +capacity_factor_tech ^^^^^^^^^^^^^^^^^^ :math:`{CFT}_{r \in R, s \in S, d \in D, t \in T}` -Temoa indexes the :code:`CapacityFactorTech` parameter by season, time-of-day, +Temoa indexes the :code:`capacity_factor_tech` parameter by season, time-of-day, and technology. -CapacityFactorProcess +capacity_factor_process ^^^^^^^^^^^^^^^^^^^^^ :math:`{CFP}_{r \in R, s \in S, d \in D, t \in T, v \in V}` -In addition to :ref:`CapacityFactorTech`, there may be cases where different +In addition to :ref:`capacity_factor_tech`, there may be cases where different vintages of the same technology have different capacity factors. For example, newer vintages of wind turbines may have higher capacity factors. So, -:code:`CapacityFactorProcess` allows users to specify the capacity factor by +:code:`capacity_factor_process` allows users to specify the capacity factor by season, time-of-day, technology, and vintage. @@ -1066,12 +1066,12 @@ the context of the question: "How much activity would this capacity create, if used 100% of the time?" -CostFixed +cost_fixed ^^^^^^^^^ :math:`{CF}_{r \in R, p \in P, t \in T, v \in V}` -The :code:`CostFixed` parameter specifies the fixed cost associated with any +The :code:`cost_fixed` parameter specifies the fixed cost associated with any process. Fixed costs are those that must be paid, regardless of how much the process is utilized. For instance, if the model decides to build a nuclear power plant, even if it decides not utilize the plant, the model must pay the @@ -1084,35 +1084,35 @@ parameter in units of currency per unit capacity (:math:`\tfrac{Dollars}{Unit Cap}`). -CostInvest +cost_invest ^^^^^^^^^^ :math:`{CI}_{r \in R, t \in T, v \in P}` -The :code:`CostInvest` parameter specifies the process-specific investment cost. -Unlike the :code:`CostFixed` and :code:`CostVariable` parameters, -:code:`CostInvest` only applies to vintages of technologies within the model -optimization horizon (:math:`\text{P}^o`). Like :code:`CostFixed`, -:code:`CostInvest` is specified in units of cost per unit of capacity and is +The :code:`cost_invest` parameter specifies the process-specific investment cost. +Unlike the :code:`cost_fixed` and :code:`cost_variable` parameters, +:code:`cost_invest` only applies to vintages of technologies within the model +optimization horizon (:math:`\text{P}^o`). Like :code:`cost_fixed`, +:code:`cost_invest` is specified in units of cost per unit of capacity and is only used in the default objective function (:math:`\tfrac{Dollars}{Unit Cap}`). -CostVariable +cost_variable ^^^^^^^^^^^^ :math:`{CV}_{r \in R, p \in P,t \in T,v \in V}` -The :code:`CostVariable` parameter represents the cost of a process-specific unit +The :code:`cost_variable` parameter represents the cost of a process-specific unit of activity. Thus the incurred variable costs are proportional to the activity of the process. -ConstructionInput +construction_input ^^^^^^^^^^^^^^^^^ :math:`{CON}_{r \in R, i \in C^p,t \in T \setminus T^u,v \in V}` -The :code:`ConstructionInput` parameter allows the modeller to attach commodity +The :code:`construction_input` parameter allows the modeller to attach commodity input flows to the production of new capacity, in units of activity per unit capacity. Assumes that capacity is produced evenly over years in its vintage period. @@ -1126,7 +1126,7 @@ Demand :math:`{DEM}_{r \in r, p \in P, c \in C^d}` The :code:`Demand` parameter allows the modeler to define the total end-use -demand levels for all periods. In combination with the :code:`Efficiency` +demand levels for all periods. In combination with the :code:`efficiency` parameter, this parameter is the most important because without it, the rest of model has no incentive to build anything. This parameter specifies the end-use demands that appear at the far right edge of the system diagram. @@ -1154,16 +1154,16 @@ from the TimeSegmentFraction. By default, Temoa assumes that end-use demands (:ref:`Demand`) are evenly distributed throughout a year. In other words, the Demand will be apportioned -by the :code:`SegFrac` parameter via: +by the :code:`segment_fraction` parameter via: .. math:: - \text{EndUseDemand}_{s, d, c} = {SegFrac}_{s, d} \cdot {Demand}_{p, c} + \text{EndUseDemand}_{s, d, c} = {segment_fraction}_{s, d} \cdot {Demand}_{p, c} Temoa enables this default action by automatically setting DDD equivalent to -:code:`SegFrac` for all seasons and times of day. If a modeler would like a +:code:`segment_fraction` for all seasons and times of day. If a modeler would like a different default demand distribution, the indices and values of the DDD -parameter must be specified. Like the :ref:`SegFrac` parameter, the sum of +parameter must be specified. Like the :ref:`segment_fraction` parameter, the sum of DDD must be 1. @@ -1175,59 +1175,59 @@ DemandSpecificDistribution If there is an end-use demand that varies over the course of a day or across seasons -- for example, heating or cooling in the summer or winter -- the modeler may specify the fraction of annual demand occurring in each time slice. -Like :ref:`SegFrac` and :ref:`DDD`, the sum of DSD for each :math:`c` must be 1. +Like :ref:`segment_fraction` and :ref:`DDD`, the sum of DSD for each :math:`c` must be 1. If the modeler does not define DSD for a season, time of day, and demand commodity, Temoa automatically populates this parameter according to DDD. It is this parameter that is actually multiplied by the :code:`Demand` parameter in the Demand constraint. -EmissionActivity +emission_activity ^^^^^^^^^^^^^^^^ :math:`{EAC}_{e \in C_e,\{r,i,t,v,o\} \in \Theta_{\text{efficiency}}}` Temoa currently has two methods for enabling a process to produce an output: the -:code:`Efficiency` parameter, and the :code:`EmissionActivity` parameter. Where -the :code:`Efficiency` parameter defines the amount of output energy a process -produces per unit of input, the :code:`EmissionActivity` parameter allows for +:code:`efficiency` parameter, and the :code:`emission_activity` parameter. Where +the :code:`efficiency` parameter defines the amount of output energy a process +produces per unit of input, the :code:`emission_activity` parameter allows for secondary outputs. As the name suggests, this parameter was originally intended to account for emissions per unit activity, but it more accurately describes *parallel* activity. It is restricted to emissions accounting (by the :math:`e \in C^e` set restriction). -EmissionEmbodied +emission_embodied ^^^^^^^^^^^^^^^^ :math:`{EE}_{r \in R,t \in T \setminus T^u, v \in V,e \in C_e}` -Like the EmissionActivity parameter, but attaches emission outputs to the creation +Like the emission_activity parameter, but attaches emission outputs to the creation of capacity instead of activity flows. Assumes that capacity is produced evenly over each year in the deployment vintage. -EmissionEndOfLife +emission_end_of_life ^^^^^^^^^^^^^^^^^ :math:`{EEOL}_{r \in R,t \in T \setminus T^u, v \in V,e \in C_e}` -Like EmissionEmbodied, but attaches emissions to the retirement/end of life of +Like emission_embodied, but attaches emissions to the retirement/end of life of capacity rather than production of capacity. Assumes that retirement or end of life occur evenly over years in that period. -EndOfLifeOutput +end_of_life_output ^^^^^^^^^^^^^^^ :math:`{EOLO}_{r \in R,t \in T \setminus T^u, v \in V,o \in C_p}` -Like ConstructionInput, but attaches flows to the retirement/end of life of +Like construction_input, but attaches flows to the retirement/end of life of capacity rather than production of capacity. Assumes that retirement or end of life occur evenly over years in that period. -.. LimitEmission +.. limit_emission .. ^^^^^^^^^^^^^ .. :math:`{LE}_{r \in R, p \in P, e \in C^e}` @@ -1237,12 +1237,12 @@ life occur evenly over years in that period. .. :math:`p`. -ExistingCapacity +existing_capacity ^^^^^^^^^^^^^^^^ :math:`{ECAP}_{r \in R, t \in T, v \in \text{P}^e}` -The :code:`ExistingCapacity` parameter defines the capacity installed prior to the +The :code:`existing_capacity` parameter defines the capacity installed prior to the beginning of :code:`time_optimize`. Note that processes with existing capacity require all of the engineering-economic characteristics of a standard process, with the exception of an investment cost. @@ -1252,7 +1252,7 @@ RetiredCapacity :math:`{ECAP}_{r \in R, t \in T, v \in \text{P}^e}` -The :code:`ExistingCapacity` parameter defines the capacity installed prior to the +The :code:`existing_capacity` parameter defines the capacity installed prior to the beginning of :code:`time_optimize`. Note that processes with existing capacity require all of the engineering-economic characteristics of a standard process, with the exception of an investment cost. @@ -1304,13 +1304,13 @@ first installed in a given time period. The growth rate is applied to this initi capacity seed in subsequent time periods. -LoanLifetimeProcess +loan_lifetime_process ^^^^^^^^^^^^^^^^^^^ :math:`{LLP}_{r \in R, t \in T, v \in P}` **Note**: :code:`LifetimeLoanProcess` is currently not supported in the database. -Modelers should use the :code:`LoanLifetimeTech` below. +Modelers should use the :code:`Loanlifetime_tech` below. Temoa gives the modeler the ability to separate the loan lifetime from the useful life of a process. This parameter specifies the loan term associated @@ -1318,17 +1318,17 @@ with capital investment in a process, in years. If not specified, the model assigns the technology lifetime to the loan period in :code:`temoa_initialize.py`. -LoanLifetimeTech +Loanlifetime_tech ^^^^^^^^^^^^^^^^ :math:`{LLT}_{r \in R, t \in T}` -Same as the :code:`LoanLifetimeProcess` but without the vintage index. If all +Same as the :code:`loan_lifetime_process` but without the vintage index. If all vintages of a given technology are assumed to have the same loan term, then -:code:`LoanLifetimeTech` can be defined instead of :code:`LoanLifetimeProcess`. +:code:`Loanlifetime_tech` can be defined instead of :code:`loan_lifetime_process`. -LifetimeProcess +lifetime_process ^^^^^^^^^^^^^^^ :math:`{LTP}_{r \in R, t \in T, v \in P}` @@ -1336,17 +1336,17 @@ LifetimeProcess This parameter specifies the total useful life of a given process in years. -LifetimeTech +lifetime_tech ^^^^^^^^^^^^ :math:`{LTT}_{r \in R, t \in T}` -Similar to LifetimeProcess, this parameter specifies the total useful life of a +Similar to lifetime_process, this parameter specifies the total useful life of a given technology in years. If all vintages of a given technology have the same lifetime, then :code:`LifeTimeTech` can be used instead of :code:`LifeTimeProcess`. -LinkedTechs +linked_techs ^^^^^^^^^^^ :math:`{LIT}_{r \in R, t \in T, e \in C^e, t \in T}` @@ -1354,14 +1354,14 @@ LinkedTechs In power-to-gas pathways, :math:`CO2` is an input to some processes, including synthetic natural gas production and liquid fuel production via Fischer-Tropsch. Within the model, :math:`CO2` must be converted from an emissions commodity to a -physical commodity that can be included in the :code:`Efficiency` table. The -:code:`LinkedTechs` parameter specifies the dummy technology used to convert an +physical commodity that can be included in the :code:`efficiency` table. The +:code:`linked_techs` parameter specifies the dummy technology used to convert an emissions commodity to a physical commodity. Note that the first :code:`t` represents the primary upstream technology linked to the dummy linked technology, which is represented by the second :code:`t` index. -LoanRate +loan_rate ^^^^^^^^ :math:`{LR}_{r \in r, t \in T, v \in V}` @@ -1488,12 +1488,12 @@ all future costs are discounted. This parameter is located in the :code:`MetaDa table in the database. -PlanningReserveMargin +planning_reserve_margin ^^^^^^^^^^^^^^^^^^^^^ :math:`{PRM}_{r \in R}` -The :code:`PlanningReserveMargin` parameter specifies that capacity reserve margin +The :code:`planning_reserve_margin` parameter specifies that capacity reserve margin in the electric sector by region. The capacity reserve margin represents the installed generating capacity - expressed as a share of peak load - that must be available to meet contingencies. Note that since electricity demand is often @@ -1548,24 +1548,24 @@ Note that the :code:`MaxResource` parameter is similar, but constrains total cumulative resource consumption across all model time periods. -.. _SegFrac: +.. _segment_fraction: -SegFrac +segment_fraction ^^^^^^^ :math:`{SEG}_{s \in S,d \in D}` -The :code:`SegFrac` parameter specifies the fraction of the year represented by +The :code:`segment_fraction` parameter specifies the fraction of the year represented by each combination of season and time of day. The sum of all combinations within -:code:`SegFrac` must be 1, representing 100% of a year. +:code:`segment_fraction` must be 1, representing 100% of a year. -StorageDuration +storage_duration ^^^^^^^^^^^^^^^ :math:`{SD}_{r \in R, t \in T^{S}}` -The :code:`StorageDuration` parameter represents the number of hours over which +The :code:`storage_duration` parameter represents the number of hours over which storage can discharge if it starts at full charge and produces maximum output until empty. The parameter value defaults to 4 hours if not specified by the user. @@ -1622,7 +1622,7 @@ across all model time slices. This parameter is used in :code:`TechOutputSplit_Constraint`. -\*LoanAnnualize +\*loan_annualize ^^^^^^^^^^^^^^^ :math:`{LA}_{r \in R, t \in T, v \in P}` @@ -1636,7 +1636,7 @@ calculated via the formula: LA_{t,v} = \frac{DR_{r,t,v}}{1 - (1 + DR_{r,t,v})^{{}^- LLN_{r,t,v}}} - \forall \{t, v\} \in \Theta_\text{CostInvest} + \forall \{t, v\} \in \Theta_\text{cost_invest} ModelProcessLife @@ -1645,7 +1645,7 @@ ModelProcessLife :math:`{MPL}_{r \in R, p \in P, t \in T, v \in P}` The :code:`ModelProcessLife` parameter is internally-derived by the model calcuated in -:code:`ParamModelProcessLife_rule` and which makes use of the :code:`LifetimeProcess` +:code:`ParamModelProcessLife_rule` and which makes use of the :code:`lifetime_process` parameter. For a given technology vintage in a given model time period, it returns the lesser of the period length and the remaining process lifetime. This parameter is used to sum the annual :code:`fixed_costs` and :code:`variable_costs` across all years within @@ -1692,7 +1692,7 @@ Note that LEN is only defined for elements in :math:`\text{P}^o`, and is specifically not defined for the final element in :math:`\text{P}^f`. -\*ProcessLifeFrac +\*process_life_frac ^^^^^^^^^^^^^^^^^ :math:`{PLF}_{r \in R, p \in P,t \in T,v \in P}` @@ -1716,7 +1716,7 @@ as: p & = max(P | p < v + LTP_{t,v}) Note that this parameter is defined over the same indices as -:code:`CostVariable` -- the active periods for each process :math:`\{p, t, +:code:`cost_variable` -- the active periods for each process :math:`\{p, t, v\}`. As an example, if a model has :math:`P = \{2010, 2012, 2020, 2030\}`, and a process :math:`\{t, v\} = \{car, 2010\}` has a useful lifetime of 5 years, then this parameter would include only the first two @@ -1734,46 +1734,46 @@ Variables :header: "Variable","Temoa Name","Domain","Short Description" :widths: 18, 22, 10, 50 - ":math:`FO_{r,p,s,d,i,t,v,o}`","V_FlowOut",":math:`\mathbb{R}^+_0`","Commodity flow by time slice out of a tech based on a given input" - ":math:`FOA_{r,p,s,d,i,t,v,o}`","V_FlowOutAnnual",":math:`\mathbb{R}^+_0`","Annual commodity flow out of a tech based on a given input" - ":math:`FIS_{r,p,s,d,i,t,v,o}`","V_FlowIn",":math:`\mathbb{R}^+_0`","Commodity flow into a storage tech to produce a given output" - ":math:`FLX_{r,p,s,d,i,t,v,o}`","V_Flex",":math:`\mathbb{R}^+_0`","The portion of commodity production exceeding demand" - ":math:`FLXA_{r,p,i,t,v,o}`","V_FlexAnnual",":math:`\mathbb{R}^+_0`","The portion of commodity production from constant production techs exceeding demand" - ":math:`CUR_{r,p,s,d,i,t,v,o}`","V_Curtailment",":math:`\mathbb{R}^+_0`","Commodity flow out of a tech that is curtailed" - ":math:`CAP_{r,t,v}`","V_Capacity",":math:`\mathbb{R}^+_0`","Required tech capacity to support associated activity" - ":math:`CAPAVL_{r,p,t}`","V_CapacityAvailable ByPeriodAndTech",":math:`\mathbb{R}^+_0`","Derived variable representing the capacity of technology :math:`t` available in period :math:`p`" + ":math:`FO_{r,p,s,d,i,t,v,o}`","v_flow_out",":math:`\mathbb{R}^+_0`","Commodity flow by time slice out of a tech based on a given input" + ":math:`FOA_{r,p,s,d,i,t,v,o}`","v_flow_out_annual",":math:`\mathbb{R}^+_0`","Annual commodity flow out of a tech based on a given input" + ":math:`FIS_{r,p,s,d,i,t,v,o}`","v_flow_in",":math:`\mathbb{R}^+_0`","Commodity flow into a storage tech to produce a given output" + ":math:`FLX_{r,p,s,d,i,t,v,o}`","v_flex",":math:`\mathbb{R}^+_0`","The portion of commodity production exceeding demand" + ":math:`FLXA_{r,p,i,t,v,o}`","v_flex_annual",":math:`\mathbb{R}^+_0`","The portion of commodity production from constant production techs exceeding demand" + ":math:`CUR_{r,p,s,d,i,t,v,o}`","v_curtailment",":math:`\mathbb{R}^+_0`","Commodity flow out of a tech that is curtailed" + ":math:`CAP_{r,t,v}`","v_capacity",":math:`\mathbb{R}^+_0`","Required tech capacity to support associated activity" + ":math:`CAPAVL_{r,p,t}`","v_capacityAvailable ByPeriodAndTech",":math:`\mathbb{R}^+_0`","Derived variable representing the capacity of technology :math:`t` available in period :math:`p`" ":math:`SI_{r,t,v}`","V_StorageInit",":math:`\mathbb{R}^+_0`","Initial charge level associated with storage techs" - ":math:`SL_{r,p,s,d,t,v}`","V_StorageLevel",":math:`\mathbb{R}^+_0`","Charge level each time slice associated with storage techs" - ":math:`SSL_{r,p,s,t,v}`","V_SeasonalStorageLevel",":math:`\mathbb{R}^+_0`","Base charge level of sequential seasons for seasonal storage" - ":math:`RCAP_{r,p,t,v}`","V_RetiredCapacity",":math:`\mathbb{R}^+_0`","Capacity retired before end of life" - ":math:`ART_{r,p,t,v}`","V_AnnualRetirement",":math:`\mathbb{R}^+_0`","Annualised capacity retiring or reaching end of life" - ":math:`NCAP_{r,t,v}`","V_NewCapacity",":math:`\mathbb{R}^+_0`","New deployed capacity" + ":math:`SL_{r,p,s,d,t,v}`","v_storage_level",":math:`\mathbb{R}^+_0`","Charge level each time slice associated with storage techs" + ":math:`SSL_{r,p,s,t,v}`","v_seasonal_storage_level",":math:`\mathbb{R}^+_0`","Base charge level of sequential seasons for seasonal storage" + ":math:`RCAP_{r,p,t,v}`","v_retired_capacity",":math:`\mathbb{R}^+_0`","Capacity retired before end of life" + ":math:`ART_{r,p,t,v}`","v_annual_retirement",":math:`\mathbb{R}^+_0`","Annualised capacity retiring or reaching end of life" + ":math:`NCAP_{r,t,v}`","v_new_capacity",":math:`\mathbb{R}^+_0`","New deployed capacity" -V_FlowOut +v_flow_out ^^^^^^^^^ :math:`FO_{r,p,s,d,i,t,v,o}` The most fundamental variable in the Temoa formulation is the -:code:`V_FlowOut` variable. It describes the commodity flow out of a +:code:`v_flow_out` variable. It describes the commodity flow out of a process in a given time slice. To balance input and output flows in the :code:`CommodityBalance_Constraint`, the commodity flow into a given process can be calculated as :math:`\sum_{T, V, O} \textbf{FO}_{p, s, d, c, t, v, o} /EFF_{c,t,v,o}`. -V_FlowOutAnnual +v_flow_out_annual ^^^^^^^^^^^^^^^ :math:`FOA_{r,p,i,t,v,o}` -Similar to :code:`V_FlowOut`, but used for technologies that are members +Similar to :code:`v_flow_out`, but used for technologies that are members of the :code:`tech_annual` set, whose output does not vary across seasons and times-of-day. Eliminating the :code:`s,d` indices for these technologies improves computational performance. -V_Flex +v_flex ^^^^^^ :math:`FLX_{r,p,s,d,i,t,v,o}` @@ -1794,23 +1794,23 @@ variable (:math:`\textbf{FLX}_{r, p, s, d, i, t, v, c}`)representing the excess production in the :code:`CommodityBalanceAnnual_Constraint`. -V_FlexAnnual +v_flex_annual ^^^^^^^^^^^^ :math:`FLXA_{r,p,i,t,v,o}` -Similar to :code:`V_Flex`, but used for technologies that are members +Similar to :code:`v_flex`, but used for technologies that are members of the :code:`tech_flex` set, whose output does not vary across seasons and times-of-day. Eliminating the :code:`s,d` indices for these technologies improves computational performance. -V_Curtailment +v_curtailment ^^^^^^^^^^^^^ :math:`CUR_{r,p,s,d,i,t,v,o}` -The :code:`V_Curtailment` variable is an accounting tool to help calculate +The :code:`v_curtailment` variable is an accounting tool to help calculate the unused production capacity of technologies annotated in the Technology database table as curtailable technologies belonging to the :code:`tech_curtailment` set. @@ -1829,27 +1829,27 @@ capacity of 10 units, and a CF of 0.8 and a usage of 5 units, then the reported curtailment is 3 units (0.8 x 10 - 5). -V_FlowInStorage +v_flow_inStorage ^^^^^^^^^^^^^^^ :math:`FIS_{r,p,s,d,i,t,v,o}` Because the production and consumption associated with storage techs occur across different time slices, the comodity flow into a storage technologiy -cannot be discerned from :code:`V_FlowOut`. Thus an explicit :math:`FlowIn` +cannot be discerned from :code:`v_flow_out`. Thus an explicit :math:`FlowIn` variable is required for storage. -V_Capacity +v_capacity ^^^^^^^^^^ :math:`CAP_{r,t,v}` -The :code:`V_Capacity` variable determines the required capacity of all processes +The :code:`v_capacity` variable determines the required capacity of all processes across the user-defined system. It is indexed for each process (t,v), and Temoa constrains the capacity variable to be able to meet the total commodity flow out of that process in all time slices in which it is active :eq:`Capacity`. -V_CapacityAvailableByPeriodAndTech +v_capacity_available_by_period_and_tech ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :math:`CAPAVL_{r,p,t}` @@ -1870,12 +1870,12 @@ of each technology can have a different optimal initial value. Note that this value also determines the ending storage charge level at the end of the last time slice within each model time period. -V_StorageLevel +v_storage_level ^^^^^^^^^^^^^^ :math:`SL_{r,p,s,d,t,v}` -The :code:`V_StorageLevel` variable tracks the storage charge level across ordered +The :code:`v_storage_level` variable tracks the storage charge level across ordered time slices and is critical to ensure that storage charge and dispatch is constrained by the energy available in the storage units. @@ -1998,7 +1998,7 @@ Objective Function .. autofunction:: temoa_rules.fv_to_pv -.. autofunction:: temoa_rules.TotalCost_rule +.. autofunction:: temoa_rules.total_cost_rule User-Specific Constraints @@ -2008,51 +2008,51 @@ The constraints provided in this section are not required for proper system operation, but allow the modeler some further degree of system specification. .. commented out... not used? - .. autofunction:: temoa_rules.ExistingCapacity_Constraint + .. autofunction:: temoa_rules.existing_capacity_Constraint -.. autofunction:: temoa_rules.LimitEmission_Constraint +.. autofunction:: temoa_rules.limit_emission_Constraint -.. autofunction:: temoa_rules.LimitActivity_Constraint +.. autofunction:: temoa_rules.limit_activity_Constraint -.. autofunction:: temoa_rules.LimitActivityShare_Constraint +.. autofunction:: temoa_rules.limit_activity_share_Constraint .. _MaxCapacity_Constraint: -.. autofunction:: temoa_rules.LimitCapacity_Constraint +.. autofunction:: temoa_rules.limit_capacity_Constraint -.. autofunction:: temoa_rules.LimitNewCapacity_Constraint +.. autofunction:: temoa_rules.limit_new_capacity_Constraint -.. autofunction:: temoa_rules.LimitCapacityShare_Constraint +.. autofunction:: temoa_rules.limit_capacity_share_Constraint -.. autofunction:: temoa_rules.LimitNewCapacityShare_Constraint +.. autofunction:: temoa_rules.limit_new_capacity_share_Constraint -.. autofunction:: temoa_rules.LimitResource_Constraint +.. autofunction:: temoa_rules.limit_resource_Constraint .. _TechOutputSplit_Constraint: -.. autofunction:: temoa_rules.LimitTechInputSplit_Constraint +.. autofunction:: temoa_rules.limit_tech_input_split_Constraint -.. autofunction:: temoa_rules.LimitTechOutputSplit_Constraint +.. autofunction:: temoa_rules.limit_tech_output_split_Constraint -.. autofunction:: temoa_rules.LimitTechInputSplitAnnual_Constraint +.. autofunction:: temoa_rules.limit_tech_input_split_annual_Constraint -.. autofunction:: temoa_rules.LimitTechOutputSplitAnnual_Constraint +.. autofunction:: temoa_rules.limit_tech_output_split_annual_Constraint -.. autofunction:: temoa_rules.LimitTechInputSplitAverage_Constraint +.. autofunction:: temoa_rules.limit_tech_input_splitAverage_Constraint -.. autofunction:: temoa_rules.LimitTechOutputSplitAverage_Constraint +.. autofunction:: temoa_rules.limit_tech_output_splitAverage_Constraint -.. autofunction:: temoa_rules.LimitAnnualCapacityFactor_Constraint +.. autofunction:: temoa_rules.limit_annual_capacity_factor_Constraint -.. autofunction:: temoa_rules.LimitSeasonalCapacityFactor_Constraint +.. autofunction:: temoa_rules.limit_seasonal_capacity_factor_Constraint -.. autofunction:: temoa_rules.LimitStorageFraction_Constraint +.. autofunction:: temoa_rules.limit_storage_fraction_Constraint -.. autofunction:: temoa_rules.LimitGrowthCapacity +.. autofunction:: temoa_rules.limit_growth_capacity -.. autofunction:: temoa_rules.LimitGrowthNewCapacity +.. autofunction:: temoa_rules.limit_growth_new_capacity -.. autofunction:: temoa_rules.LimitGrowthNewCapacityDelta +.. autofunction:: temoa_rules.limit_growth_new_capacity_delta @@ -2065,7 +2065,7 @@ conventional power plant might simply emit excess heat as exhaust, a cogeneration plant harnesses some or all of that heat for heating purposes, either very close to the plant, or generally as hot water for district heating. Temoa's flow variables can track both flows through a process, but each flow -will have its own efficiency from the Efficiency parameter. This implies that +will have its own efficiency from the efficiency parameter. This implies that to produce 1 unit of electricity will require :math:`\frac{1}{elc eff}` units of input. At the same time, to produce 1 unit of heat will require units of input energy, and to produce both output units of heat and energy, both flows must be @@ -2074,7 +2074,7 @@ active, and the desired activity will be double-counted by Temoa. To model a parallel output device (c.f., a cogeneration plant), the modeler must currently set up the process with the :code:`TechInputSplit` and :code:`TechOutputSplit` parameters, appropriately adding each flow to the -Efficiency parameter and accounting for the overall process efficiency through +efficiency parameter and accounting for the overall process efficiency through all flows. @@ -2151,13 +2151,13 @@ A simple definition of this constraint is: .. code-block:: python :linenos: - M.DemandConstraint = Constraint( + M.demand_constraint = Constraint( M.regions, M.time_optimize, M.time_season, M.time_of_day, M.commodity_demand, rule=Demand_Constraint ) -In line 1, '``M.DemandConstraint =``' creates a place holder in the model object -``M``, called 'DemandConstraint'. Like a variable, this is the name through +In line 1, '``M.demand_constraint =``' creates a place holder in the model object +``M``, called 'demand_constraint'. Like a variable, this is the name through which Pyomo will reference this class of constraints. ``Constraint(...)`` is a Pyomo-specific function that creates each individual constraint in the class. The first arguments (line 2) are the index sets of the constraint class. Line 2 @@ -2182,18 +2182,18 @@ is: return Constraint.Skip # Pyomo to ignore this constraint index. supply = sum( - M.V_FlowOut[r, p, s, d, S_i, S_t, S_v, dem] - for S_t, S_v in M.commodityUStreamProcess[r, p, dem] if S_t not in M.tech_annual + M.v_flow_out[r, p, s, d, S_i, S_t, S_v, dem] + for S_t, S_v in M.commodity_up_stream_process[r, p, dem] if S_t not in M.tech_annual for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, dem] ) supply_annual = sum( - M.V_FlowOutAnnual[r, p, S_i, S_t, S_v, dem] - for S_t, S_v in M.commodityUStreamProcess[r, p, dem] if S_t in M.tech_annual + M.v_flow_out_annual[r, p, S_i, S_t, S_v, dem] + for S_t, S_v in M.commodity_up_stream_process[r, p, dem] if S_t in M.tech_annual for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, dem] - ) * value( M.SegFrac[ s, d]) + ) * value( M.segment_fraction[ s, d]) - DemandConstraintErrorCheck(supply + supply_annual, r, p, s, d, dem) + demand_constraintErrorCheck(supply + supply_annual, r, p, s, d, dem) expr = supply + supply_annual == M.Demand[r, p, dem] * M.DemandSpecificDistribution[r, s, d, dem] return expr @@ -2245,7 +2245,7 @@ Consider a naive approach to calculating the supply:: for S_t in M.tech_all: for S_v in M.vintage_all: for S_i in ProcessInputsByOutput( p, S_t, S_v, dem ): - to_sum.append( M.V_FlowOut[p, s, d, S_i, S_t, S_v, dem] ) + to_sum.append( M.v_flow_out[p, s, d, S_i, S_t, S_v, dem] ) supply = sum( to_sum ) This implementation creates an extra list (:code:`to_sum`), then builds the list @@ -2261,7 +2261,7 @@ one:: for S_t in M.tech_all: for S_v in M.vintage_all: for S_i in ProcessInputsByOutput( p, S_t, S_v, dem ): - supply += M.V_FlowOut[p, s, d, S_i, S_t, S_v, dem] + supply += M.v_flow_out[p, s, d, S_i, S_t, S_v, dem] Why is list comprehension necessary? Strictly speaking, it is not, especially in light of this last example, which may read more familiar to those comfortable @@ -2302,23 +2302,23 @@ implementation above. .. code-block:: python :linenos: - M.DemandConstraint_rpsdc = Set( dimen=5, rule=DemandConstraintIndices ) + M.demand_constraint_rpsdc = Set( dimen=5, rule=demand_constraintIndices ) # ... - M.DemandConstraint = Constraint( M.DemandConstraint_rpsdc, rule=Demand_Constraint ) + M.demand_constraint = Constraint( M.demand_constraint_rpsdc, rule=Demand_Constraint ) -As discussed above, the DemandConstraint is only valid for certain +As discussed above, the demand_constraint is only valid for certain :math:`\{r, p, s, d, dem\}` tuples. Since the modeler can specify the demand distribution per commodity (necessary to model demands like heating, that do not apply in all time slices), Temoa must ascertain the valid tuples. We have -implemented this logic in the function :code:`DemandConstraintIndices` in +implemented this logic in the function :code:`demand_constraintIndices` in ``temoa_initialize.py``. Thus, Line 1 tells Pyomo to instantiate -:code:`DemandConstraint_rpsdc` as a Set of 5-length tuples indices +:code:`demand_constraint_rpsdc` as a Set of 5-length tuples indices (:code:`dimen=5`), and populate it with what Temoa's rule -:code:`DemandConstraintIndices` returns. We omit here an explanation of the -implementation of the :code:`DemandConstraintIndices` function, stating merely -that it returns the exact indices over which the DemandConstraint must to be -created. With the sparse set :code:`DemandConstraint_rpsdc` created, we can now +:code:`demand_constraintIndices` returns. We omit here an explanation of the +implementation of the :code:`demand_constraintIndices` function, stating merely +that it returns the exact indices over which the demand_constraint must to be +created. With the sparse set :code:`demand_constraint_rpsdc` created, we can now can use it in place of the five sets specified in the non-sparse implementation. Pyomo will now call the constraint implementation rule the minimum number of times. @@ -2327,10 +2327,10 @@ On the choice of the :code:`_rpsdc` suffix for the index set name, there is no Pyomo-enforced restriction. However, use of an index set in place of the non-sparse specification obfuscates over what indexes a constraint is defined. While it is not impossible to deduce, either from this documentation -or from looking at the :code:`DemandConstraintIndices` or +or from looking at the :code:`demand_constraintIndices` or :code:`Demand_Constraint` implementations, the Temoa convention includes index set names that feature the one-character representation of each set dimension. -In this case, the name :code:`DemandConstraint_rpsdc` implies that this set has a +In this case, the name :code:`demand_constraint_rpsdc` implies that this set has a dimensionality of 5, and (following the :ref:`naming scheme `) the first index of each tuple will be an element of :code:`region`, the second an element of :code:`time_optimize`, the third @@ -2352,15 +2352,15 @@ look like: .. code-block:: ampl - s.t. DemandConstraint{(p, s, d, dem) in sDemand_psd_dem} : + s.t. demand_constraint{(p, s, d, dem) in sDemand_psd_dem} : sum{(p, s, d, Si, St, Sv, dem) in sFlowVar_psditvo} - V_FlowOut[p, s, d, Si, St, Sv, dem] + v_flow_out[p, s, d, Si, St, Sv, dem] = pDemand[p, s, d, dem]; While the syntax is not a direct translation, the indices of the constraint (``p``, ``s``, ``d``, and ``dem``) are clear, and by inference, so are the -indices of summation (``i``, ``t``, ``v``) and operand (``V_FlowOut``). This +indices of summation (``i``, ``t``, ``v``) and operand (``v_flow_out``). This one-line definition creates an inequality for each period, season, time of day, and demand, ensuring that total output meets each demand in each time slice -- almost exactly as we have formulated the demand constraint :eq:`Demand`. In @@ -2377,7 +2377,7 @@ reasons: tools (e.g. numpy, matplotlib) that are not as cleanly available to other AMLs. For instance, there is minimal capability in MathProg to error check a model before a solve, and providing interactive feedback like what Temoa's - DemandConstraintErrorCheck function does is difficult, if not impossible. + demand_constraintErrorCheck function does is difficult, if not impossible. While a subtle addition, specific and directed error messages are an effective measure to reduce the learning curve for new modelers. @@ -2561,12 +2561,12 @@ repository use the ``diff`` command to ``git``: @@ -246,7 +246,7 @@ def InitializeProcessParameters ( M ): if l_vin in M.vintage_exist: if l_process not in l_exist_indices: - msg = ('Warning: %s has a specified Efficiency, but does not ' - - 'have any existing install base (ExistingCapacity)\n.') - + 'have any existing install base (ExistingCapacity).\n') + msg = ('Warning: %s has a specified efficiency, but does not ' + - 'have any existing install base (existing_capacity)\n.') + + 'have any existing install base (existing_capacity).\n') SE.write( msg % str(l_process) ) continue - if 0 == M.ExistingCapacity[ l_process ]: + if 0 == M.existing_capacity[ l_process ]: [ ... ] For a crash course on git, here is a handy `quick start guide`_. @@ -2783,7 +2783,7 @@ same prefix and ``Constraint`` suffix, but separate them with an underscore .. code-block:: python - M.CapacityConstraint = Constraint( M.CapacityVar_tv, rule=Capacity_Constraint ) + M.capacity_constraint = Constraint( M.CapacityVar_tv, rule=Capacity_Constraint ) When providing the implementation for a constraint rule, use a consistent naming scheme between functions and constraint definitions. For instance, we have diff --git a/docs/source/images/adjusted_capacity_plf.svg b/docs/source/images/adjusted_capacity_plf.svg index 7f5f7fe87..400831421 100644 --- a/docs/source/images/adjusted_capacity_plf.svg +++ b/docs/source/images/adjusted_capacity_plf.svg @@ -144,7 +144,7 @@ id="tspan219" x="450.91309" y="405.55908" - style="font-size:22px;line-height:19.5555px;text-align:end;text-anchor:end;fill:#000000;fill-opacity:1">ProcessLifeFraction adjustment + style="font-size:22px;line-height:19.5555px;text-align:end;text-anchor:end;fill:#000000;fill-opacity:1">process_life_fraction adjustment coal_plant [ label="Input, (V_FlowIn)" ]; - coal_plant -> electricity [ label="Output, (V_FlowOut)"]; + coal -> coal_plant [ label="Input, (v_flow_in)" ]; + coal_plant -> electricity [ label="Output, (v_flow_out)"]; } diff --git a/pyproject.toml b/pyproject.toml index f682745cc..5a7e4d548 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -72,7 +72,9 @@ build-backend = "hatchling.build" [tool.ruff] line-length = 100 indent-width = 4 -exclude = ["stubs"] +exclude = ["stubs", + "temoa/extensions/" +] [tool.ruff.format] quote-style = "single" diff --git a/temoa/_internal/exchange_tech_cost_ledger.py b/temoa/_internal/exchange_tech_cost_ledger.py index 7976711cf..83ce1b1e9 100644 --- a/temoa/_internal/exchange_tech_cost_ledger.py +++ b/temoa/_internal/exchange_tech_cost_ledger.py @@ -80,8 +80,8 @@ def get_use_ratio( rr2 = cast(Region, '-'.join([importer, exporter])) if any( ( - period >= vintage + value(model.LifetimeProcess[rr1, tech, vintage]), - period >= vintage + value(model.LifetimeProcess[rr2, tech, vintage]), + period >= vintage + value(model.lifetime_process[rr1, tech, vintage]), + period >= vintage + value(model.lifetime_process[rr2, tech, vintage]), period < vintage, ) ): @@ -89,35 +89,35 @@ def get_use_ratio( if tech not in model.tech_annual: act_dir1 = value( sum( - model.V_FlowOut[rr1, period, s, d, s_i, tech, vintage, s_o] - for s in model.TimeSeason[period] + model.v_flow_out[rr1, period, s, d, s_i, tech, vintage, s_o] + for s in model.time_season[period] for d in model.time_of_day - for s_i in model.processInputs[rr1, period, tech, vintage] - for s_o in model.processOutputsByInput[rr1, period, tech, vintage, s_i] + for s_i in model.process_inputs[rr1, period, tech, vintage] + for s_o in model.process_outputs_by_input[rr1, period, tech, vintage, s_i] ) ) act_dir2 = value( sum( - model.V_FlowOut[rr2, period, s, d, s_i, tech, vintage, s_o] - for s in model.TimeSeason[period] + model.v_flow_out[rr2, period, s, d, s_i, tech, vintage, s_o] + for s in model.time_season[period] for d in model.time_of_day - for s_i in model.processInputs[rr2, period, tech, vintage] - for s_o in model.processOutputsByInput[rr2, period, tech, vintage, s_i] + for s_i in model.process_inputs[rr2, period, tech, vintage] + for s_o in model.process_outputs_by_input[rr2, period, tech, vintage, s_i] ) ) else: act_dir1 = value( sum( - model.V_FlowOutAnnual[rr1, period, s_i, tech, vintage, s_o] - for s_i in model.processInputs[rr1, period, tech, vintage] - for s_o in model.processOutputsByInput[rr1, period, tech, vintage, s_i] + model.v_flow_out_annual[rr1, period, s_i, tech, vintage, s_o] + for s_i in model.process_inputs[rr1, period, tech, vintage] + for s_o in model.process_outputs_by_input[rr1, period, tech, vintage, s_i] ) ) act_dir2 = value( sum( - model.V_FlowOutAnnual[rr2, period, s_i, tech, vintage, s_o] - for s_i in model.processInputs[rr2, period, tech, vintage] - for s_o in model.processOutputsByInput[rr2, period, tech, vintage, s_i] + model.v_flow_out_annual[rr2, period, s_i, tech, vintage, s_o] + for s_i in model.process_inputs[rr2, period, tech, vintage] + for s_o in model.process_outputs_by_input[rr2, period, tech, vintage, s_i] ) ) diff --git a/temoa/_internal/run_actions.py b/temoa/_internal/run_actions.py index 068cb7ae7..9815495e1 100644 --- a/temoa/_internal/run_actions.py +++ b/temoa/_internal/run_actions.py @@ -396,7 +396,7 @@ def handle_results( excel_filename = config.output_path / scenario_name make_excel(str(config.output_database), excel_filename, temp_scenario) - # normal (non-MGA) run will have a TotalCost as the OBJ: - if hasattr(instance, 'TotalCost'): - logger.info('TotalCost value: %0.2f', value(instance.TotalCost)) + # normal (non-MGA) run will have a total_cost as the OBJ: + if hasattr(instance, 'total_cost'): + logger.info('total_cost value: %0.2f', value(instance.total_cost)) return diff --git a/temoa/_internal/table_data_puller.py b/temoa/_internal/table_data_puller.py index d8de0a621..b78ac7e8d 100644 --- a/temoa/_internal/table_data_puller.py +++ b/temoa/_internal/table_data_puller.py @@ -50,9 +50,9 @@ def poll_capacity_results(model: TemoaModel, epsilon: float = 1e-5) -> CapData: """ # Built Capacity built = [] - for r, t, v in model.V_NewCapacity.keys(): + for r, t, v in model.v_new_capacity.keys(): if v in model.time_optimize: - val = value(model.V_NewCapacity[r, t, v]) + val = value(model.v_new_capacity[r, t, v]) if abs(val) < epsilon: continue new_cap = (r, t, v, val) @@ -60,8 +60,8 @@ def poll_capacity_results(model: TemoaModel, epsilon: float = 1e-5) -> CapData: # NetCapacity net = [] - for r, p, t, v in model.V_Capacity.keys(): - val = value(model.V_Capacity[r, p, t, v]) + for r, p, t, v in model.v_capacity.keys(): + val = value(model.v_capacity[r, p, t, v]) if abs(val) < epsilon: continue new_net_cap = (r, p, t, v, val) @@ -69,14 +69,14 @@ def poll_capacity_results(model: TemoaModel, epsilon: float = 1e-5) -> CapData: # Retired Capacity ret = [] - for r, t, v in model.retirementPeriods: - lifetime = value(model.LifetimeProcess[r, t, v]) - for p in model.retirementPeriods[r, t, v]: + for r, t, v in model.retirement_periods: + lifetime = value(model.lifetime_process[r, t, v]) + for p in model.retirement_periods[r, t, v]: # We want to output period retirement, not annual retirement, so multiply by PeriodLength - eol = value(model.PeriodLength[p]) * value(model.V_AnnualRetirement[r, p, t, v]) + eol = value(model.period_length[p]) * value(model.v_annual_retirement[r, p, t, v]) early = 0 - if t in model.tech_retirement and v < p <= v + lifetime - value(model.PeriodLength[p]): - early = value(model.V_RetiredCapacity[r, p, t, v]) + if t in model.tech_retirement and v < p <= v + lifetime - value(model.period_length[p]): + early = value(model.v_retired_capacity[r, p, t, v]) eol -= early early = 0 if abs(early) < epsilon else early eol = 0 if abs(eol) < epsilon else eol @@ -101,39 +101,39 @@ def poll_flow_results(model: TemoaModel, epsilon: float = 1e-5) -> dict[FI, dict # ---- NON-annual ---- # Storage, which has a unique v_flow_in (non-storage techs do not have this variable) - for key in model.V_FlowIn.keys(): + for key in model.v_flow_in.keys(): fi = FI(*key) - flow = value(model.V_FlowIn[fi]) + flow = value(model.v_flow_in[fi]) if abs(flow) < epsilon: continue res[fi][FlowType.IN] = flow res[fi][FlowType.LOST] = (1 - get_variable_efficiency(model, *key)) * flow # regular flows - for key in model.V_FlowOut.keys(): + for key in model.v_flow_out.keys(): fi = FI(*key) - flow = value(model.V_FlowOut[fi]) + flow = value(model.v_flow_out[fi]) if abs(flow) < epsilon: continue res[fi][FlowType.OUT] = flow if fi.t not in model.tech_storage: # we can get the flow in by out/eff... - flow = value(model.V_FlowOut[fi]) / get_variable_efficiency(model, *key) + flow = value(model.v_flow_out[fi]) / get_variable_efficiency(model, *key) res[fi][FlowType.IN] = flow res[fi][FlowType.LOST] = (1 - get_variable_efficiency(model, *key)) * flow # curtailment flows - for key in model.V_Curtailment.keys(): + for key in model.v_curtailment.keys(): fi = FI(*key) - val = value(model.V_Curtailment[fi]) + val = value(model.v_curtailment[fi]) if abs(val) < epsilon: continue res[fi][FlowType.CURTAIL] = val # flex techs. This will subtract the flex from their output flow IOT make OUT the "net" - for key in model.V_Flex.keys(): + for key in model.v_flex.keys(): fi = FI(*key) - flow = value(model.V_Flex[fi]) + flow = value(model.v_flex[fi]) if abs(flow) < epsilon: continue res[fi][FlowType.FLEX] = flow @@ -142,64 +142,66 @@ def poll_flow_results(model: TemoaModel, epsilon: float = 1e-5) -> dict[FI, dict # ---- annual ---- # basic annual flows - for r, p, i, t, v, o in model.V_FlowOutAnnual.keys(): + for r, p, i, t, v, o in model.v_flow_out_annual.keys(): # Make sure this isn't just a non-annual demand tech if t not in model.tech_annual: continue - for s in model.TimeSeason[p]: + for s in model.time_season[p]: for d in model.time_of_day: if o in model.commodity_demand: - distribution = value(model.DemandSpecificDistribution[r, p, s, d, o]) + distribution = value(model.demand_specific_distribution[r, p, s, d, o]) else: - distribution = value(model.SegFrac[p, s, d]) + distribution = value(model.segment_fraction[p, s, d]) fi = FI(r, p, s, d, i, t, v, o) - flow = value(model.V_FlowOutAnnual[r, p, i, t, v, o]) * distribution + flow = value(model.v_flow_out_annual[r, p, i, t, v, o]) * distribution if abs(flow) < epsilon: continue res[fi][FlowType.OUT] = flow - res[fi][FlowType.IN] = flow / value(model.Efficiency[ritvo(fi)]) - res[fi][FlowType.LOST] = (1 - value(model.Efficiency[ritvo(fi)])) * res[fi][ + res[fi][FlowType.IN] = flow / value(model.efficiency[ritvo(fi)]) + res[fi][FlowType.LOST] = (1 - value(model.efficiency[ritvo(fi)])) * res[fi][ FlowType.IN ] # flex annual - for r, p, i, t, v, o in model.V_FlexAnnual.keys(): - for s in model.TimeSeason[p]: + for r, p, i, t, v, o in model.v_flex_annual.keys(): + for s in model.time_season[p]: for d in model.time_of_day: fi = FI(r, p, s, d, i, t, v, o) - flow = value(model.V_FlexAnnual[r, p, i, t, v, o]) * value(model.SegFrac[p, s, d]) + flow = value(model.v_flex_annual[r, p, i, t, v, o]) * value( + model.segment_fraction[p, s, d] + ) if abs(flow) < epsilon: continue res[fi][FlowType.FLEX] = flow res[fi][FlowType.OUT] -= flow # construction flows - for r, i, t, v in model.ConstructionInput.sparse_iterkeys(): + for r, i, t, v in model.construction_input.sparse_iterkeys(): annual = ( - value(model.ConstructionInput[r, i, t, v]) - * value(model.V_NewCapacity[r, t, v]) - / value(model.PeriodLength[v]) + value(model.construction_input[r, i, t, v]) + * value(model.v_new_capacity[r, t, v]) + / value(model.period_length[v]) ) - for s in model.TimeSeason[v]: + for s in model.time_season[v]: for d in model.time_of_day: - fi = FI(r, v, s, d, i, t, v, cast(Commodity, 'ConstructionInput')) - flow = annual * value(model.SegFrac[v, s, d]) + fi = FI(r, v, s, d, i, t, v, cast(Commodity, 'construction_input')) + flow = annual * value(model.segment_fraction[v, s, d]) if abs(flow) < epsilon: continue res[fi][FlowType.IN] = flow # end of life flows - for r, t, v, o in model.EndOfLifeOutput.sparse_iterkeys(): - if (r, t, v) not in model.retirementPeriods: + for r, t, v, o in model.end_of_life_output.sparse_iterkeys(): + if (r, t, v) not in model.retirement_periods: continue - for p in model.retirementPeriods[r, t, v]: - annual = value(model.EndOfLifeOutput[r, t, v, o]) * value( - model.V_AnnualRetirement[r, p, t, v] + for p in model.retirement_periods[r, t, v]: + annual = value(model.end_of_life_output[r, t, v, o]) * value( + model.v_annual_retirement[r, p, t, v] ) - for s in model.TimeSeason[p]: + for s in model.time_season[p]: for d in model.time_of_day: - fi = FI(r, p, s, d, cast(Commodity, 'EndOfLifeOutput'), t, v, o) - flow = annual * value(model.SegFrac[p, s, d]) + fi = FI(r, p, s, d, cast(Commodity, 'end_of_life_output'), t, v, o) + flow = annual * value(model.segment_fraction[p, s, d]) if abs(flow) < epsilon: continue res[fi][FlowType.OUT] = flow @@ -217,29 +219,29 @@ def poll_storage_level_results(model: TemoaModel, epsilon: float = 1e-5) -> dict res: dict[SLI, float] = defaultdict(float) # Storage level, the state variable for all but last time slice of each season - for r, p, s, d, t, v in model.StorageLevel_rpsdtv: + for r, p, s, d, t, v in model.storage_level_rpsdtv: if t in model.tech_seasonal_storage: continue - state = value(model.V_StorageLevel[r, p, s, d, t, v]) / ( - value(model.SegFracPerSeason[p, s]) * value(model.DaysPerPeriod) + state = value(model.v_storage_level[r, p, s, d, t, v]) / ( + value(model.segment_fraction_per_season[p, s]) * value(model.days_per_period) ) sli = SLI(r, p, s, d, t, v) if abs(state) < epsilon: state = 0 # still want to know but decimals are ugly res[sli] = state - for r, p, s_seq, t, v in model.SeasonalStorageLevel_rpstv: + for r, p, s_seq, t, v in model.seasonal_storage_level_rpstv: s = model.sequential_to_season[p, s_seq] # Ratio of days in virtual storage season to days in actual season # Flows and StorageLevel are normalised to the number of days in the ACTUAL season, so must # be adjusted to the number of days in the virtual storage season - days_adjust = value(model.TimeSeasonSequential[p, s_seq, s]) / ( - value(model.SegFracPerSeason[p, s]) * value(model.DaysPerPeriod) + days_adjust = value(model.time_season_sequential[p, s_seq, s]) / ( + value(model.segment_fraction_per_season[p, s]) * value(model.days_per_period) ) for d in model.time_of_day: state = ( - value(model.V_SeasonalStorageLevel[r, p, s_seq, t, v]) - + value(model.V_StorageLevel[r, p, s, d, t, v]) * days_adjust + value(model.v_seasonal_storage_level[r, p, s_seq, t, v]) + + value(model.v_storage_level[r, p, s, d, t, v]) * days_adjust ) sli = SLI(r, p, s_seq, d, t, v) if abs(state) < epsilon: @@ -284,23 +286,23 @@ def poll_cost_results( p_e = model.time_future.last() # conveniences... - global_discount_rate = value(model.GlobalDiscountRate) + global_discount_rate = value(model.global_discount_rate) # MPL = M.ModelProcessLife - loan_lifetime_process = model.LoanLifetimeProcess + loan_lifetime_process = model.loan_lifetime_process exchange_costs = ExchangeTechCostLedger(model) entries: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]] = defaultdict( dict ) - for r, t, v in model.CostInvest.sparse_iterkeys(): # Returns only non-zero values + for r, t, v in model.cost_invest.sparse_iterkeys(): # Returns only non-zero values # gather details... - cap = value(model.V_NewCapacity[r, t, v]) + cap = value(model.v_new_capacity[r, t, v]) if abs(cap) < epsilon: continue loan_life = value(loan_lifetime_process[r, t, v]) - loan_rate = value(model.LoanRate[r, t, v]) + loan_rate = value(model.loan_rate[r, t, v]) - if model.isSurvivalCurveProcess[r, t, v]: + if model.is_survival_curve_process[r, t, v]: model_loan_cost, undiscounted_cost = loan_costs_survival_curve( model=model, r=r, @@ -309,7 +311,7 @@ def poll_cost_results( loan_rate=loan_rate, loan_life=loan_life, capacity=cap, - invest_cost=value(model.CostInvest[r, t, v]), + invest_cost=value(model.cost_invest[r, t, v]), p_0=p_0_true, p_e=p_e, global_discount_rate=global_discount_rate, @@ -320,8 +322,8 @@ def poll_cost_results( loan_rate=loan_rate, loan_life=loan_life, capacity=cap, - invest_cost=value(model.CostInvest[r, t, v]), - process_life=value(model.LifetimeProcess[r, t, v]), + invest_cost=value(model.cost_invest[r, t, v]), + process_life=value(model.lifetime_process[r, t, v]), p_0=p_0_true, p_e=p_e, global_discount_rate=global_discount_rate, @@ -352,18 +354,18 @@ def poll_cost_results( {CostType.D_INVEST: model_loan_cost, CostType.INVEST: undiscounted_cost} ) - for r, p, t, v in model.CostFixed.sparse_iterkeys(): - cap = value(model.V_Capacity[r, p, t, v]) + for r, p, t, v in model.cost_fixed.sparse_iterkeys(): + cap = value(model.v_capacity[r, p, t, v]) if abs(cap) < epsilon: continue - fixed_cost = value(model.CostFixed[r, p, t, v]) - undiscounted_fixed_cost = cap * fixed_cost * value(model.PeriodLength[p]) + fixed_cost = value(model.cost_fixed[r, p, t, v]) + undiscounted_fixed_cost = cap * fixed_cost * value(model.period_length[p]) model_fixed_cost = costs.fixed_or_variable_cost( cap, value(fixed_cost), - value(model.PeriodLength[p]), + value(model.period_length[p]), global_discount_rate=global_discount_rate, p_0=float(p_0_true), p=p, @@ -393,31 +395,31 @@ def poll_cost_results( } ) - for r, p, t, v in model.CostVariable.sparse_iterkeys(): + for r, p, t, v in model.cost_variable.sparse_iterkeys(): if t not in model.tech_annual: activity = sum( - value(model.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o]) - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] - for S_s in model.TimeSeason[p] + value(model.v_flow_out[r, p, S_s, S_d, S_i, t, v, S_o]) + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] + for S_s in model.time_season[p] for S_d in model.time_of_day ) else: activity = sum( - value(model.V_FlowOutAnnual[r, p, S_i, t, v, S_o]) - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + value(model.v_flow_out_annual[r, p, S_i, t, v, S_o]) + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) if abs(activity) < epsilon: continue - var_cost = value(model.CostVariable[r, p, t, v]) - undiscounted_var_cost = activity * var_cost * value(model.PeriodLength[p]) + var_cost = value(model.cost_variable[r, p, t, v]) + undiscounted_var_cost = activity * var_cost * value(model.period_length[p]) model_var_cost = costs.fixed_or_variable_cost( activity, var_cost, - value(model.PeriodLength[p]), + value(model.period_length[p]), global_discount_rate=global_discount_rate, p_0=float(p_0_true), p=p, @@ -451,7 +453,7 @@ def poll_cost_results( def loan_costs( - loan_rate: float, # this is referred to as LoanRate in parameters + loan_rate: float, # this is referred to as loan_rate in parameters loan_life: float, capacity: float, invest_cost: float, @@ -501,7 +503,7 @@ def loan_costs_survival_curve( r: Region, t: Technology, v: Vintage, - loan_rate: float, # this is referred to as LoanRate in parameters + loan_rate: float, # this is referred to as loan_rate in parameters loan_life: float, capacity: float, invest_cost: float, @@ -570,7 +572,7 @@ def poll_emissions( else: p_0_true = p_0 - global_discount_rate = value(model.GlobalDiscountRate) + global_discount_rate = value(model.global_discount_rate) ########################### # Process Emissions @@ -578,16 +580,16 @@ def poll_emissions( base = [ (r, p, e, i, t, v, o) - for (r, e, i, t, v, o) in model.EmissionActivity.sparse_iterkeys() + for (r, e, i, t, v, o) in model.emission_activity.sparse_iterkeys() for p in model.time_optimize - if (r, p, t, v) in model.processInputs + if (r, p, t, v) in model.process_inputs ] # The "base set" can be expanded now to cover normal/annual indexing sets normal = [ (r, p, e, s, d, i, t, v, o) for (r, p, e, i, t, v, o) in base - for s in model.TimeSeason[p] + for s in model.time_season[p] for d in model.time_of_day if t not in model.tech_annual ] @@ -597,14 +599,14 @@ def poll_emissions( # iterate through the normal and annual and accumulate flow values for r, p, e, s, d, i, t, v, o in normal: flows[EI(r, p, t, v, e)] += ( - value(model.V_FlowOut[r, p, s, d, i, t, v, o]) - * model.EmissionActivity[r, e, i, t, v, o] + value(model.v_flow_out[r, p, s, d, i, t, v, o]) + * model.emission_activity[r, e, i, t, v, o] ) for r, p, e, i, t, v, o in annual: flows[EI(r, p, t, v, e)] += ( - value(model.V_FlowOutAnnual[r, p, i, t, v, o]) - * model.EmissionActivity[r, e, i, t, v, o] + value(model.v_flow_out_annual[r, p, i, t, v, o]) + * model.emission_activity[r, e, i, t, v, o] ) # gather costs @@ -617,15 +619,15 @@ def poll_emissions( continue # screen to see if there is an associated cost cost_index = (ei.r, ei.p, ei.e) - if cost_index not in model.CostEmission: + if cost_index not in model.cost_emission: continue undiscounted_emiss_cost = ( - flows[ei] * model.CostEmission[ei.r, ei.p, ei.e] * model.PeriodLength[ei.p] + flows[ei] * model.cost_emission[ei.r, ei.p, ei.e] * model.period_length[ei.p] ) discounted_emiss_cost = costs.fixed_or_variable_cost( cap_or_flow=flows[ei], - cost_factor=value(model.CostEmission[ei.r, ei.p, ei.e]), - cost_years=model.PeriodLength[ei.p], + cost_factor=value(model.cost_emission[ei.r, ei.p, ei.e]), + cost_years=model.period_length[ei.p], global_discount_rate=global_discount_rate, p_0=p_0_true, p=ei.p, @@ -639,16 +641,16 @@ def poll_emissions( # iterate through embodied flows embodied_flows: dict[EI, float] = defaultdict(float) - for r, e, t, v in model.EmissionEmbodied.sparse_iterkeys(): + for r, e, t, v in model.emission_embodied.sparse_iterkeys(): embodied_flows[EI(r, v, t, v, e)] += value( - model.V_NewCapacity[r, t, v] - * model.EmissionEmbodied[r, e, t, v] - / model.PeriodLength[v] + model.v_new_capacity[r, t, v] + * model.emission_embodied[r, e, t, v] + / model.period_length[v] ) # for embodied costs flows[EI(r, v, t, v, e)] += value( - model.V_NewCapacity[r, t, v] - * model.EmissionEmbodied[r, e, t, v] - / model.PeriodLength[v] + model.v_new_capacity[r, t, v] + * model.emission_embodied[r, e, t, v] + / model.period_length[v] ) # add embodied to process emissions # add embodied costs to process costs @@ -659,19 +661,19 @@ def poll_emissions( continue # screen to see if there is an associated cost cost_index = (ei.r, cast(Period, ei.v), ei.e) - if cost_index not in model.CostEmission: + if cost_index not in model.cost_emission: continue undiscounted_emiss_cost = ( embodied_flows[ei] - * model.CostEmission[ei.r, cast(Period, ei.v), ei.e] - * model.PeriodLength[ + * model.cost_emission[ei.r, cast(Period, ei.v), ei.e] + * model.period_length[ cast(Period, ei.v) ] # treat as fixed cost distributed over construction period ) discounted_emiss_cost = costs.fixed_or_variable_cost( cap_or_flow=embodied_flows[ei], - cost_factor=value(model.CostEmission[ei.r, cast(Period, ei.v), ei.e]), - cost_years=model.PeriodLength[ + cost_factor=value(model.cost_emission[ei.r, cast(Period, ei.v), ei.e]), + cost_years=model.period_length[ cast(Period, ei.v) ], # treat as fixed cost distributed over construction period global_discount_rate=global_discount_rate, @@ -687,15 +689,15 @@ def poll_emissions( # iterate through end of life flows eol_flows: dict[EI, float] = defaultdict(float) - for r, e, t, v in model.EmissionEndOfLife.sparse_iterkeys(): - if (r, t, v) not in model.retirementPeriods: + for r, e, t, v in model.emission_end_of_life.sparse_iterkeys(): + if (r, t, v) not in model.retirement_periods: continue - for p in model.retirementPeriods[r, t, v]: + for p in model.retirement_periods[r, t, v]: eol_flows[EI(r, p, t, v, e)] += value( - model.V_AnnualRetirement[r, p, t, v] * model.EmissionEndOfLife[r, e, t, v] + model.v_annual_retirement[r, p, t, v] * model.emission_end_of_life[r, e, t, v] ) # for eol costs flows[EI(r, p, t, v, e)] += value( - model.V_AnnualRetirement[r, p, t, v] * model.EmissionEndOfLife[r, e, t, v] + model.v_annual_retirement[r, p, t, v] * model.emission_end_of_life[r, e, t, v] ) # add eol to process emissions # add embodied costs to process costs @@ -706,17 +708,17 @@ def poll_emissions( continue # screen to see if there is an associated cost cost_index = (ei.r, ei.p, ei.e) - if cost_index not in model.CostEmission: + if cost_index not in model.cost_emission: continue undiscounted_emiss_cost = ( eol_flows[ei] - * model.CostEmission[ei.r, ei.p, ei.e] - * model.PeriodLength[ei.p] # treat as fixed cost distributed over retirement period + * model.cost_emission[ei.r, ei.p, ei.e] + * model.period_length[ei.p] # treat as fixed cost distributed over retirement period ) discounted_emiss_cost = costs.fixed_or_variable_cost( cap_or_flow=eol_flows[ei], - cost_factor=value(model.CostEmission[ei.r, ei.p, ei.e]), - cost_years=model.PeriodLength[ + cost_factor=value(model.cost_emission[ei.r, ei.p, ei.e]), + cost_years=model.period_length[ ei.p ], # treat as fixed cost distributed over retirement period global_discount_rate=global_discount_rate, diff --git a/temoa/_internal/table_writer.py b/temoa/_internal/table_writer.py index 84a3b0d1f..5a516bf76 100644 --- a/temoa/_internal/table_writer.py +++ b/temoa/_internal/table_writer.py @@ -129,7 +129,7 @@ def write_results( self.write_capacity_tables(model, iteration=iteration) # analyze the emissions to get the costs and flows if self.config.scenario_mode == TemoaMode.MYOPIC: - p_0 = model.MyopicDiscountingYear + p_0 = model.myopic_discounting_year else: p_0 = None # min year will be used in poll e_costs, e_flows = poll_emissions(model=model, p_0=value(p_0)) @@ -473,9 +473,9 @@ def check_flow_balance(self, model: TemoaModel) -> bool: for fi in flows: if fi.t in model.tech_storage: continue - if fi.i == 'EndOfLifeOutput': + if fi.i == 'end_of_life_output': continue - if fi.o == 'ConstructionInput': + if fi.o == 'construction_input': continue # some conveniences for the players... @@ -546,7 +546,7 @@ def write_costs( # P_0 is usually the first optimization year, but if running myopic, we could assign it via # table entry. Perhaps in future it is just always the first optimization year of the 1st iter. if self.config.scenario_mode == TemoaMode.MYOPIC: - p_0 = model.MyopicDiscountingYear + p_0 = model.myopic_discounting_year else: p_0 = min(model.time_optimize) diff --git a/temoa/components/capacity.py b/temoa/components/capacity.py index a3a71864c..9738645df 100644 --- a/temoa/components/capacity.py +++ b/temoa/components/capacity.py @@ -42,32 +42,32 @@ def check_capacity_factor_process(model: TemoaModel) -> None: count_rptv: dict[tuple[Region, Period, Technology, Vintage], int] = {} - # Pull CapacityFactorTech by default - for r, p, _s, _d, t in model.CapacityFactor_rpsdt: - for v in model.processVintages[r, p, t]: - model.isCapacityFactorProcess[r, p, t, v] = False + # Pull capacity_factor_tech by default + for r, p, _s, _d, t in model.capacity_factor_rpsdt: + for v in model.process_vintages[r, p, t]: + model.is_capacity_factor_process[r, p, t, v] = False count_rptv[r, p, t, v] = 0 # Check for bad values and count up the good ones - for r, p, _s, _d, t, v in model.CapacityFactorProcess.sparse_iterkeys(): - if v not in model.processVintages[r, p, t]: - msg = f'Invalid process {p, v} for {r, t} in CapacityFactorProcess table' + for r, p, _s, _d, t, v in model.capacity_factor_process.sparse_iterkeys(): + if v not in model.process_vintages[r, p, t]: + msg = f'Invalid process {p, v} for {r, t} in capacity_factor_process table' logger.error(msg) raise ValueError(msg) - # Good value, pull from CapacityFactorProcess table + # Good value, pull from capacity_factor_process table count_rptv[r, p, t, v] += 1 # Check if all possible values have been set by process # log a warning if some are missing (allowed but maybe accidental) for (r, p, t, v), count in count_rptv.items(): - num_seg = len(model.TimeSeason[p]) * len(model.time_of_day) + num_seg = len(model.time_season[p]) * len(model.time_of_day) if count > 0: - model.isCapacityFactorProcess[r, p, t, v] = True + model.is_capacity_factor_process[r, p, t, v] = True if count < num_seg: logger.info( - 'Some but not all processes were set in CapacityFactorProcess (%i out of a possible %i) for: %s' - ' Missing values will default to CapacityFactorTech value or 1 if that is not set either.', + 'Some but not all processes were set in capacity_factor_process (%i out of a possible %i) for: %s' + ' Missing values will default to capacity_factor_tech value or 1 if that is not set either.', count, num_seg, (r, p, t, v), @@ -79,19 +79,19 @@ def create_capacity_factors(model: TemoaModel) -> None: """ Steps to creating capacity factors: 1. Collect all possible processes - 2. Find the ones _not_ specified in CapacityFactorProcess - 3. Set them, based on CapacityFactorTech. + 2. Find the ones _not_ specified in capacity_factor_process + 3. Set them, based on capacity_factor_tech. """ - capacity_factor_process = model.CapacityFactorProcess + capacity_factor_process = model.capacity_factor_process # Step 1 - processes = {(r, t, v) for r, i, t, v, o in model.Efficiency.sparse_iterkeys()} + processes = {(r, t, v) for r, i, t, v, o in model.efficiency.sparse_iterkeys()} all_cfs = { (r, p, s, d, t, v) for (r, t, v) in processes - for p in model.processPeriods[r, t, v] - for s, d in cross_product(model.TimeSeason[p], model.time_of_day) + for p in model.process_periods[r, t, v] + for s, d in cross_product(model.time_season[p], model.time_of_day) } # Step 2 @@ -107,7 +107,7 @@ def create_capacity_factors(model: TemoaModel) -> None: if unspecified_cfs: # CFP._constructed = False for r, p, s, d, t, v in unspecified_cfs: - capacity_factor_process[r, p, s, d, t, v] = model.CapacityFactorTech[r, p, s, d, t] + capacity_factor_process[r, p, s, d, t, v] = model.capacity_factor_tech[r, p, s, d, t] logger.debug( 'Created Capacity Factors for %d processes without an explicit specification', len(unspecified_cfs), @@ -119,12 +119,12 @@ def get_default_capacity_factor( model: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage ) -> float: """ - This initializer is used to fill the CapacityFactorProcess from the CapacityFactorTech where needed. + This initializer is used to fill the capacity_factor_process from the capacity_factor_tech where needed. Priority: 1. As specified in data input (this function not called) 2. Here - 3. The default from CapacityFactorTech param + 3. The default from capacity_factor_tech param :param M: generic model reference :param r: region :param s: season @@ -133,16 +133,16 @@ def get_default_capacity_factor( :param v: vintage :return: the capacity factor """ - return value(model.CapacityFactorTech[r, p, s, d, t]) + return value(model.capacity_factor_tech[r, p, s, d, t]) def get_capacity_factor( model: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage ) -> float: - if model.isCapacityFactorProcess[r, p, t, v]: - return value(model.CapacityFactorProcess[r, p, s, d, t, v]) + if model.is_capacity_factor_process[r, p, t, v]: + return value(model.capacity_factor_process[r, p, s, d, t, v]) else: - return value(model.CapacityFactorTech[r, p, s, d, t]) + return value(model.capacity_factor_tech[r, p, s, d, t]) # ============================================================================ @@ -153,7 +153,7 @@ def get_capacity_factor( def capacity_variable_indices( model: TemoaModel, ) -> set[tuple[Region, Technology, Vintage]] | None: - return model.newCapacity_rtv + return model.new_capacity_rtv def retired_capacity_variable_indices( @@ -161,10 +161,10 @@ def retired_capacity_variable_indices( ) -> set[tuple[Region, Period, Technology, Vintage]]: return { (r, p, t, v) - for r, p, t in model.processVintages + for r, p, t in model.process_vintages if t in model.tech_retirement and t not in model.tech_uncap - for v in model.processVintages[r, p, t] - if v < p <= v + value(model.LifetimeProcess[r, t, v]) - value(model.PeriodLength[p]) + for v in model.process_vintages[r, p, t] + if v < p <= v + value(model.lifetime_process[r, t, v]) - value(model.period_length[p]) } @@ -173,23 +173,23 @@ def annual_retirement_variable_indices( ) -> set[tuple[Region, Period, Technology, Vintage]]: return { (r, p, t, v) - for r, t, v in model.retirementPeriods - for p in model.retirementPeriods[r, t, v] + for r, t, v in model.retirement_periods + for p in model.retirement_periods[r, t, v] } def capacity_available_variable_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Technology]] | None: - return model.activeCapacityAvailable_rpt + return model.active_capacity_available_rpt def regional_exchange_capacity_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Region, Period, Technology, Vintage]]: indices: set[tuple[Region, Region, Period, Technology, Vintage]] = set() - for r_e, p, i in model.exportRegions: - for r_i, t, v, _o in model.exportRegions[r_e, p, i]: + for r_e, p, i in model.export_regions: + for r_i, t, v, _o in model.export_regions[r_e, p, i]: indices.add((r_e, r_i, p, t, v)) return indices @@ -199,8 +199,8 @@ def capacity_annual_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Technology, Vintage]]: capacity_indices: set[tuple[Region, Period, Technology, Vintage]] = set() - if model.activeActivity_rptv: - for r, p, t, v in model.activeActivity_rptv: + if model.active_activity_rptv: + for r, p, t, v in model.active_activity_rptv: if t in model.tech_annual and t not in model.tech_demand: if t not in model.tech_uncap: capacity_indices.add((r, p, t, v)) @@ -214,12 +214,12 @@ def capacity_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]]: capacity_indices: set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]] = set() - if model.activeActivity_rptv: - for r, p, t, v in model.activeActivity_rptv: + if model.active_activity_rptv: + for r, p, t, v in model.active_activity_rptv: if t not in model.tech_annual or t in model.tech_demand: if t not in model.tech_uncap: if t not in model.tech_storage: - for s in model.TimeSeason[p]: + for s in model.time_season[p]: for d in model.time_of_day: capacity_indices.add((r, p, s, d, t, v)) else: @@ -233,9 +233,9 @@ def capacity_factor_process_indices( model: TemoaModel, ) -> set[tuple[Region, Season, TimeOfDay, Technology, Vintage]]: indices: set[tuple[Region, Season, TimeOfDay, Technology, Vintage]] = set() - for r, _i, t, v, _o in model.Efficiency.sparse_iterkeys(): + for r, _i, t, v, _o in model.efficiency.sparse_iterkeys(): for p in model.time_optimize: - for s in model.TimeSeason[p]: + for s in model.time_season[p]: for d in model.time_of_day: indices.add((r, s, d, t, v)) return indices @@ -245,9 +245,9 @@ def capacity_factor_tech_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology]]: all_cfs: set[tuple[Region, Period, Season, TimeOfDay, Technology]] = set() - if model.activeCapacityAvailable_rpt: - for r, p, t in model.activeCapacityAvailable_rpt: - for s in model.TimeSeason[p]: + if model.active_capacity_available_rpt: + for r, p, t in model.active_capacity_available_rpt: + for s in model.time_season[p]: for d in model.time_of_day: all_cfs.add((r, p, s, d, t)) else: @@ -258,7 +258,7 @@ def capacity_factor_tech_indices( def capacity_available_variable_indices_vintage( model: TemoaModel, ) -> set[tuple[Region, Period, Technology, Vintage]] | None: - return model.activeCapacityAvailable_rptv + return model.active_capacity_available_rptv # ============================================================================ @@ -300,52 +300,52 @@ def annual_retirement_constraint( """ ## Get the capacity at the start of this period - if p == v + value(model.LifetimeProcess[r, t, v]): - # Exact EOL. No V_Capacity or V_RetiredCapacity for this period. + if p == v + value(model.lifetime_process[r, t, v]): + # Exact EOL. No v_capacity or v_retired_capacity for this period. if p == model.time_optimize.first(): # Must be existing capacity. Apply survival curve to existing cap - cap_begin = model.ExistingCapacity[r, t, v] * model.LifetimeSurvivalCurve[r, p, t, v] + cap_begin = model.existing_capacity[r, t, v] * model.lifetime_survival_curve[r, p, t, v] else: # Get previous capacity and continue survival curve p_prev = model.time_optimize.prev(p) cap_begin = ( - model.V_Capacity[r, p_prev, t, v] - * value(model.LifetimeSurvivalCurve[r, p, t, v]) - / value(model.ProcessLifeFrac[r, p_prev, t, v]) + model.v_capacity[r, p_prev, t, v] + * value(model.lifetime_survival_curve[r, p, t, v]) + / value(model.process_life_frac[r, p_prev, t, v]) ) else: # The capacity at the beginning of the period cap_begin = ( - model.V_Capacity[r, p, t, v] - * value(model.LifetimeSurvivalCurve[r, p, t, v]) - / value(model.ProcessLifeFrac[r, p, t, v]) + model.v_capacity[r, p, t, v] + * value(model.lifetime_survival_curve[r, p, t, v]) + / value(model.process_life_frac[r, p, t, v]) ) ## Get the capacity at the end of this period - if p <= v + value(model.LifetimeProcess[r, t, v]) < p + value(model.PeriodLength[p]): + if p <= v + value(model.lifetime_process[r, t, v]) < p + value(model.period_length[p]): # EOL so capacity ends on zero cap_end = 0 else: # Mid-life period, ending capacity is beginning capacity of next period p_next = model.time_future.next(p) - if p == model.time_optimize.last() or p_next == v + value(model.LifetimeProcess[r, t, v]): - # No V_Capacity or V_RetiredCapacity for next period so just continue down the survival curve + if p == model.time_optimize.last() or p_next == v + value(model.lifetime_process[r, t, v]): + # No v_capacity or v_retired_capacity for next period so just continue down the survival curve cap_end = ( cap_begin - * value(model.LifetimeSurvivalCurve[r, p_next, t, v]) - / value(model.LifetimeSurvivalCurve[r, p, t, v]) + * value(model.lifetime_survival_curve[r, p_next, t, v]) + / value(model.lifetime_survival_curve[r, p, t, v]) ) else: # Get the next period's beginning capacity cap_end = ( - model.V_Capacity[r, p_next, t, v] - * value(model.LifetimeSurvivalCurve[r, p_next, t, v]) - / value(model.ProcessLifeFrac[r, p_next, t, v]) + model.v_capacity[r, p_next, t, v] + * value(model.lifetime_survival_curve[r, p_next, t, v]) + / value(model.process_life_frac[r, p_next, t, v]) ) - annualised_retirement = (cap_begin - cap_end) / model.PeriodLength[p] - return model.V_AnnualRetirement[r, p, t, v] == annualised_retirement + annualised_retirement = (cap_begin - cap_end) / model.period_length[p] + return model.v_annual_retirement[r, p, t, v] == annualised_retirement def capacity_available_by_period_and_tech_constraint( @@ -364,9 +364,9 @@ def capacity_available_by_period_and_tech_constraint( \\ \forall p \in \text{P}^o, r \in R, t \in T """ - cap_avail = sum(model.V_Capacity[r, p, t, S_v] for S_v in model.processVintages[r, p, t]) + cap_avail = sum(model.v_capacity[r, p, t, S_v] for S_v in model.process_vintages[r, p, t]) - expr = model.V_CapacityAvailableByPeriodAndTech[r, p, t] == cap_avail + expr = model.v_capacity_available_by_period_and_tech[r, p, t] == cap_avail return expr @@ -380,7 +380,7 @@ def capacity_annual_constraint( that installed capacity is sufficient across all timeslices, thus saving some computational effort. Instead, annual output is sufficient to calculate capacity. Hourly capacity factors cannot be defined to annual technologies - but annual capacity factors can be set using LimitAnnualCapacityFactor, + but annual capacity factors can be set using limit_annual_capacity_factor, which will be implicitly accounted for here. .. math:: @@ -395,12 +395,12 @@ def capacity_annual_constraint( \forall \{r, p, t \in T^{a}, v\} \in \Theta_{\text{Activity}} """ activity_rptv = sum( - model.V_FlowOutAnnual[r, p, S_i, t, v, S_o] - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + model.v_flow_out_annual[r, p, S_i, t, v, S_o] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) - return value(model.CapacityToActivity[r, t]) * model.V_Capacity[r, p, t, v] >= activity_rptv + return value(model.capacity_to_activity[r, t]) * model.v_capacity[r, p, t, v] >= activity_rptv def capacity_constraint( @@ -442,37 +442,39 @@ def capacity_constraint( # Annual demand technology useful_activity = sum( ( - value(model.DemandSpecificDistribution[r, p, s, d, S_o]) + value(model.demand_specific_distribution[r, p, s, d, S_o]) if S_o in model.commodity_demand - else value(model.SegFrac[p, s, d]) + else value(model.segment_fraction[p, s, d]) ) - * model.V_FlowOutAnnual[r, p, S_i, t, v, S_o] - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + * model.v_flow_out_annual[r, p, S_i, t, v, S_o] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) else: useful_activity = sum( - model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + model.v_flow_out[r, p, s, d, S_i, t, v, S_o] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) if t in model.tech_curtailment: # If technologies are present in the curtailment set, then enough # capacity must be available to cover both activity and curtailment. return get_capacity_factor(model, r, p, s, d, t, v) * value( - model.CapacityToActivity[r, t] - ) * value(model.SegFrac[p, s, d]) * model.V_Capacity[r, p, t, v] == useful_activity + sum( - model.V_Curtailment[r, p, s, d, S_i, t, v, S_o] - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + model.capacity_to_activity[r, t] + ) * value(model.segment_fraction[p, s, d]) * model.v_capacity[ + r, p, t, v + ] == useful_activity + sum( + model.v_curtailment[r, p, s, d, S_i, t, v, S_o] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) else: return ( get_capacity_factor(model, r, p, s, d, t, v) - * value(model.CapacityToActivity[r, t]) - * value(model.SegFrac[p, s, d]) - * model.V_Capacity[r, p, t, v] + * value(model.capacity_to_activity[r, t]) + * value(model.segment_fraction[p, s, d]) + * model.v_capacity[r, p, t, v] >= useful_activity ) @@ -550,23 +552,24 @@ def adjusted_capacity_constraint( """ if v in model.time_exist: - built_capacity = value(model.ExistingCapacity[r, t, v]) + built_capacity = value(model.existing_capacity[r, t, v]) else: - built_capacity = model.V_NewCapacity[r, t, v] + built_capacity = model.v_new_capacity[r, t, v] early_retirements = 0 if t in model.tech_retirement: early_retirements = sum( - model.V_RetiredCapacity[r, S_p, t, v] / value(model.LifetimeSurvivalCurve[r, S_p, t, v]) + model.v_retired_capacity[r, S_p, t, v] + / value(model.lifetime_survival_curve[r, S_p, t, v]) for S_p in model.time_optimize if v < S_p <= p - and S_p < v + value(model.LifetimeProcess[r, t, v]) - value(model.PeriodLength[S_p]) + and S_p < v + value(model.lifetime_process[r, t, v]) - value(model.period_length[S_p]) ) remaining_capacity = (built_capacity - early_retirements) * value( - model.ProcessLifeFrac[r, p, t, v] + model.process_life_frac[r, p, t, v] ) - return model.V_Capacity[r, p, t, v] == remaining_capacity + return model.v_capacity[r, p, t, v] == remaining_capacity # ============================================================================ @@ -584,58 +587,58 @@ def create_capacity_and_retirement_sets(model: TemoaModel) -> None: used by other functions in this module to build Pyomo components. Populates: - - model.retirementPeriods: dict mapping (r, t, v) to a set of periods `p` + - model.retirement_periods: dict mapping (r, t, v) to a set of periods `p` where retirement can occur. - - model.capacityConsumptionTechs: dict mapping (r, v, i) to a set of techs `t` + - model.capacity_consumption_techs: dict mapping (r, v, i) to a set of techs `t` that consume commodity `i` for construction. - - model.retirementProductionProcesses: dict mapping (r, p, o) to a set of `(t, v)` + - model.retirement_production_processes: dict mapping (r, p, o) to a set of `(t, v)` processes that produce commodity `o` at end-of-life. - - model.newCapacity_rtv: set of (r, t, v) for new capacity investments. - - model.activeCapacityAvailable_rpt: set of (r, p, t) where capacity is active. - - model.activeCapacityAvailable_rptv: set of (r, p, t, v) where vintage capacity is active. + - model.new_capacity_rtv: set of (r, t, v) for new capacity investments. + - model.active_capacity_available_rpt: set of (r, p, t) where capacity is active. + - model.active_capacity_available_rptv: set of (r, p, t, v) where vintage capacity is active. """ logger.debug('Creating capacity, retirement, and construction/EOL sets.') # Calculate retirement periods based on lifetime and survival curves - for r, _i, t, v, _o in model.Efficiency.sparse_iterkeys(): - lifetime = value(model.LifetimeProcess[r, t, v]) + for r, _i, t, v, _o in model.efficiency.sparse_iterkeys(): + lifetime = value(model.lifetime_process[r, t, v]) for p in model.time_optimize: - is_natural_eol = p <= v + lifetime < p + value(model.PeriodLength[p]) + is_natural_eol = p <= v + lifetime < p + value(model.period_length[p]) is_early_retire = t in model.tech_retirement and v < p <= v + lifetime - value( - model.PeriodLength[p] + model.period_length[p] ) - is_survival_curve = model.isSurvivalCurveProcess[r, t, v] and v <= p <= v + lifetime + is_survival_curve = model.is_survival_curve_process[r, t, v] and v <= p <= v + lifetime if t not in model.tech_uncap and any( (is_natural_eol, is_early_retire, is_survival_curve) ): - model.retirementPeriods.setdefault((r, t, v), set()).add(p) + model.retirement_periods.setdefault((r, t, v), set()).add(p) # Link construction materials to technologies - for r, i, t, v in model.ConstructionInput.sparse_iterkeys(): - model.capacityConsumptionTechs.setdefault((r, v, i), set()).add(t) + for r, i, t, v in model.construction_input.sparse_iterkeys(): + model.capacity_consumption_techs.setdefault((r, v, i), set()).add(t) # Link end-of-life materials to retiring technologies - for r, t, v, o in model.EndOfLifeOutput.sparse_iterkeys(): - if (r, t, v) in model.retirementPeriods: - for p in model.retirementPeriods[r, t, v]: - model.retirementProductionProcesses.setdefault((r, p, o), set()).add((t, v)) + for r, t, v, o in model.end_of_life_output.sparse_iterkeys(): + if (r, t, v) in model.retirement_periods: + for p in model.retirement_periods[r, t, v]: + model.retirement_production_processes.setdefault((r, p, o), set()).add((t, v)) - # Create active capacity index sets from the now-populated processVintages - model.newCapacity_rtv = { + # Create active capacity index sets from the now-populated process_vintages + model.new_capacity_rtv = { (r, t, v) - for r, p, t in model.processVintages - for v in model.processVintages[r, p, t] + for r, p, t in model.process_vintages + for v in model.process_vintages[r, p, t] if t not in model.tech_uncap and v in model.time_optimize } - model.activeCapacityAvailable_rpt = { + model.active_capacity_available_rpt = { (r, p, t) - for r, p, t in model.processVintages - if model.processVintages[r, p, t] and t not in model.tech_uncap + for r, p, t in model.process_vintages + if model.process_vintages[r, p, t] and t not in model.tech_uncap } - model.activeCapacityAvailable_rptv = { + model.active_capacity_available_rptv = { (r, p, t, v) - for r, p, t in model.processVintages - for v in model.processVintages[r, p, t] + for r, p, t in model.process_vintages + for v in model.process_vintages[r, p, t] if t not in model.tech_uncap } diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index 7c8528161..4699598b1 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -49,7 +49,7 @@ def commodity_balance_constraint_error_check( " - Is there a missing tech in set 'tech_resource'?\n" " - Is there a missing tech in set 'tech_production'?\n" " - Is there a missing commodity in set 'commodity_physical'?\n" - ' - Are there missing entries in the Efficiency table?\n' + ' - Are there missing entries in the efficiency table?\n' ' - Does a process need a longer Lifetime?' ) logger.error(msg.format(c, r, p, s, d, expr)) @@ -72,7 +72,7 @@ def annual_commodity_balance_constraint_error_check( " - Is there a missing tech in set 'tech_resource'?\n" " - Is there a missing tech in set 'tech_production'?\n" " - Is there a missing commodity in set 'commodity_physical'?\n" - ' - Are there missing entries in the Efficiency table?\n' + ' - Are there missing entries in the efficiency table?\n' ' - Does a process need a longer Lifetime?' ) logger.error(msg.format(c, r, p, expr)) @@ -86,7 +86,7 @@ def demand_constraint_error_check(supply: Any, r: Region, p: Period, dem: Commod msg = ( "Error: Demand '{}' for ({}, {}) unable to be met by any " 'technology.\n\tPossible reasons:\n' - ' - Is the Efficiency parameter missing an entry for this demand?\n' + ' - Is the efficiency parameter missing an entry for this demand?\n' ' - Does a tech that satisfies this demand need a longer ' 'Lifetime?\n' ) @@ -104,10 +104,10 @@ def demand_activity_constraint_indices( ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage, Commodity]]: indices = { (r, p, s, d, t, v, dem) - for r, p, dem in model.DemandConstraint_rpc - for t, v in model.commodityUStreamProcess[r, p, dem] + for r, p, dem in model.demand_constraint_rpc + for t, v in model.commodity_up_stream_process[r, p, dem] if t not in model.tech_annual - for s in model.TimeSeason[p] + for s in model.time_season[p] for d in model.time_of_day } return indices @@ -124,7 +124,7 @@ def commodity_balance_constraint_indices( # r in this line includes interregional transfer combinations (not needed). if r in model.regions # this line ensures only the regions are included. and c not in model.commodity_annual - for s in model.TimeSeason[p] + for s in model.time_season[p] for d in model.time_of_day } @@ -178,21 +178,21 @@ def demand_constraint(model: TemoaModel, r: Region, p: Period, dem: Commodity) - # All demand techs are annual now # supply = sum( - # M.V_FlowOut[r, p, s, d, s_i, s_t, s_v, dem] - # for s_t, s_v in M.commodityUStreamProcess[r, p, dem] + # M.v_flow_out[r, p, s, d, s_i, s_t, s_v, dem] + # for s_t, s_v in M.commodity_up_stream_process[r, p, dem] # if s_t not in M.tech_annual - # for s_i in M.processInputsByOutput[r, p, s_t, s_v, dem] + # for s_i in M.process_inputs_by_output[r, p, s_t, s_v, dem] # ) supply_annual = sum( - model.V_FlowOutAnnual[r, p, s_i, s_t, s_v, dem] - for s_t, s_v in model.commodityUStreamProcess[r, p, dem] - for s_i in model.processInputsByOutput[r, p, s_t, s_v, dem] + model.v_flow_out_annual[r, p, s_i, s_t, s_v, dem] + for s_t, s_v in model.commodity_up_stream_process[r, p, dem] + for s_i in model.process_inputs_by_output[r, p, s_t, s_v, dem] ) demand_constraint_error_check(supply_annual, r, p, dem) - expr = supply_annual == value(model.Demand[r, p, dem]) + expr = supply_annual == value(model.demand[r, p, dem]) return expr @@ -238,16 +238,16 @@ def demand_activity_constraint( """ activity = sum( - model.V_FlowOut[r, p, s, d, s_i, t, v, dem] - for s_i in model.processInputsByOutput[r, p, t, v, dem] + model.v_flow_out[r, p, s, d, s_i, t, v, dem] + for s_i in model.process_inputs_by_output[r, p, t, v, dem] ) annual_activity = sum( - model.V_FlowOutAnnual[r, p, s_i, t, v, dem] - for s_i in model.processInputsByOutput[r, p, t, v, dem] + model.v_flow_out_annual[r, p, s_i, t, v, dem] + for s_i in model.process_inputs_by_output[r, p, t, v, dem] ) - expr = annual_activity * value(model.DemandSpecificDistribution[r, p, s, d, dem]) == activity + expr = annual_activity * value(model.demand_specific_distribution[r, p, s, d, dem]) == activity return expr @@ -354,119 +354,120 @@ def commodity_balance_constraint( produced = 0 consumed = 0 - if (r, p, c) in model.commodityDStreamProcess: + if (r, p, c) in model.commodity_down_stream_process: # Only storage techs have a flow in variable # For other techs, it would be redundant as in = out / eff consumed += sum( - model.V_FlowIn[r, p, s, d, c, s_t, s_v, s_o] - for s_t, s_v in model.commodityDStreamProcess[r, p, c] + model.v_flow_in[r, p, s, d, c, s_t, s_v, s_o] + for s_t, s_v in model.commodity_down_stream_process[r, p, c] if s_t in model.tech_storage - for s_o in model.processOutputsByInput[r, p, s_t, s_v, c] + for s_o in model.process_outputs_by_input[r, p, s_t, s_v, c] ) # Into flows consumed += sum( - model.V_FlowOut[r, p, s, d, c, s_t, s_v, s_o] + model.v_flow_out[r, p, s, d, c, s_t, s_v, s_o] / get_variable_efficiency(model, r, p, s, d, c, s_t, s_v, s_o) - for s_t, s_v in model.commodityDStreamProcess[r, p, c] + for s_t, s_v in model.commodity_down_stream_process[r, p, c] if s_t not in model.tech_storage and s_t not in model.tech_annual - for s_o in model.processOutputsByInput[r, p, s_t, s_v, c] + for s_o in model.process_outputs_by_input[r, p, s_t, s_v, c] ) # Into annual flows consumed += sum( ( - value(model.DemandSpecificDistribution[r, p, s, d, s_o]) + value(model.demand_specific_distribution[r, p, s, d, s_o]) if s_o in model.commodity_demand - else value(model.SegFrac[p, s, d]) + else value(model.segment_fraction[p, s, d]) ) - * model.V_FlowOutAnnual[r, p, c, s_t, s_v, s_o] + * model.v_flow_out_annual[r, p, c, s_t, s_v, s_o] / get_variable_efficiency(model, r, p, s, d, c, s_t, s_v, s_o) - for s_t, s_v in model.commodityDStreamProcess[r, p, c] + for s_t, s_v in model.commodity_down_stream_process[r, p, c] if s_t in model.tech_annual - for s_o in model.processOutputsByInput[r, p, s_t, s_v, c] + for s_o in model.process_outputs_by_input[r, p, s_t, s_v, c] ) - if (r, p, c) in model.capacityConsumptionTechs: + if (r, p, c) in model.capacity_consumption_techs: # Consumed by building capacity # Assume evenly distributed over a year consumed += ( - value(model.SegFrac[p, s, d]) + value(model.segment_fraction[p, s, d]) * sum( - value(model.ConstructionInput[r, c, s_t, p]) * model.V_NewCapacity[r, s_t, p] - for s_t in model.capacityConsumptionTechs[r, p, c] + value(model.construction_input[r, c, s_t, p]) * model.v_new_capacity[r, s_t, p] + for s_t in model.capacity_consumption_techs[r, p, c] ) - / model.PeriodLength[p] + / model.period_length[p] ) - if (r, p, c) in model.commodityUStreamProcess: + if (r, p, c) in model.commodity_up_stream_process: # From flows including output from storage produced += sum( - model.V_FlowOut[r, p, s, d, s_i, s_t, s_v, c] - for s_t, s_v in model.commodityUStreamProcess[r, p, c] + model.v_flow_out[r, p, s, d, s_i, s_t, s_v, c] + for s_t, s_v in model.commodity_up_stream_process[r, p, c] if s_t not in model.tech_annual - for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] + for s_i in model.process_inputs_by_output[r, p, s_t, s_v, c] ) # From annual flows - produced += value(model.SegFrac[p, s, d]) * sum( - model.V_FlowOutAnnual[r, p, s_i, s_t, s_v, c] - for s_t, s_v in model.commodityUStreamProcess[r, p, c] + produced += value(model.segment_fraction[p, s, d]) * sum( + model.v_flow_out_annual[r, p, s_i, s_t, s_v, c] + for s_t, s_v in model.commodity_up_stream_process[r, p, c] if s_t in model.tech_annual - for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] + for s_i in model.process_inputs_by_output[r, p, s_t, s_v, c] ) if c in model.commodity_flex: # Wasted by flex flows consumed += sum( - model.V_Flex[r, p, s, d, s_i, s_t, s_v, c] - for s_t, s_v in model.commodityUStreamProcess[r, p, c] + model.v_flex[r, p, s, d, s_i, s_t, s_v, c] + for s_t, s_v in model.commodity_up_stream_process[r, p, c] if s_t not in model.tech_annual and s_t in model.tech_flex - for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] + for s_i in model.process_inputs_by_output[r, p, s_t, s_v, c] ) # Wasted by annual flex flows - consumed += value(model.SegFrac[p, s, d]) * sum( - model.V_FlexAnnual[r, p, s_i, s_t, s_v, c] - for s_t, s_v in model.commodityUStreamProcess[r, p, c] + consumed += value(model.segment_fraction[p, s, d]) * sum( + model.v_flex_annual[r, p, s_i, s_t, s_v, c] + for s_t, s_v in model.commodity_up_stream_process[r, p, c] if s_t in model.tech_annual and s_t in model.tech_flex - for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] + for s_i in model.process_inputs_by_output[r, p, s_t, s_v, c] ) - if (r, p, c) in model.retirementProductionProcesses: + if (r, p, c) in model.retirement_production_processes: # Produced by retiring capacity # Assume evenly distributed over a year - produced += value(model.SegFrac[p, s, d]) * sum( - value(model.EndOfLifeOutput[r, s_t, s_v, c]) * model.V_AnnualRetirement[r, p, s_t, s_v] - for s_t, s_v in model.retirementProductionProcesses[r, p, c] + produced += value(model.segment_fraction[p, s, d]) * sum( + value(model.end_of_life_output[r, s_t, s_v, c]) + * model.v_annual_retirement[r, p, s_t, s_v] + for s_t, s_v in model.retirement_production_processes[r, p, c] ) # export of commodity c from region r to other regions - if (r, p, c) in model.exportRegions: + if (r, p, c) in model.export_regions: consumed += sum( - model.V_FlowOut[r + '-' + reg, p, s, d, c, s_t, s_v, S_o] + model.v_flow_out[r + '-' + reg, p, s, d, c, s_t, s_v, S_o] / get_variable_efficiency(model, cast(Region, r + '-' + reg), p, s, d, c, s_t, s_v, S_o) - for reg, s_t, s_v, S_o in model.exportRegions[r, p, c] + for reg, s_t, s_v, S_o in model.export_regions[r, p, c] if s_t not in model.tech_annual ) consumed += sum( - value(model.SegFrac[p, s, d]) - * model.V_FlowOutAnnual[r + '-' + reg, p, c, s_t, s_v, S_o] + value(model.segment_fraction[p, s, d]) + * model.v_flow_out_annual[r + '-' + reg, p, c, s_t, s_v, S_o] / get_variable_efficiency(model, cast(Region, r + '-' + reg), p, s, d, c, s_t, s_v, S_o) - for reg, s_t, s_v, S_o in model.exportRegions[r, p, c] + for reg, s_t, s_v, S_o in model.export_regions[r, p, c] if s_t in model.tech_annual ) # import of commodity c from other regions into region r - if (r, p, c) in model.importRegions: + if (r, p, c) in model.import_regions: produced += sum( - model.V_FlowOut[reg + '-' + r, p, s, d, s_i, s_t, s_v, c] - for reg, s_t, s_v, s_i in model.importRegions[r, p, c] + model.v_flow_out[reg + '-' + r, p, s, d, s_i, s_t, s_v, c] + for reg, s_t, s_v, s_i in model.import_regions[r, p, c] if s_t not in model.tech_annual ) produced += sum( - value(model.SegFrac[p, s, d]) - * model.V_FlowOutAnnual[reg + '-' + r, p, s_i, s_t, s_v, c] - for reg, s_t, s_v, s_i in model.importRegions[r, p, c] + value(model.segment_fraction[p, s, d]) + * model.v_flow_out_annual[reg + '-' + r, p, s_i, s_t, s_v, c] + for reg, s_t, s_v, s_i in model.import_regions[r, p, c] if s_t in model.tech_annual ) @@ -500,120 +501,121 @@ def annual_commodity_balance_constraint( produced = 0 consumed = 0 - if (r, p, c) in model.commodityDStreamProcess: + if (r, p, c) in model.commodity_down_stream_process: # Only storage techs have a flow in variable # For other techs, it would be redundant as in = out / eff consumed += sum( - model.V_FlowIn[r, p, s_s, s_d, c, s_t, s_v, s_o] - for s_s in model.TimeSeason[p] + model.v_flow_in[r, p, s_s, s_d, c, s_t, s_v, s_o] + for s_s in model.time_season[p] for s_d in model.time_of_day - for s_t, s_v in model.commodityDStreamProcess[r, p, c] + for s_t, s_v in model.commodity_down_stream_process[r, p, c] if s_t in model.tech_storage - for s_o in model.processOutputsByInput[r, p, s_t, s_v, c] + for s_o in model.process_outputs_by_input[r, p, s_t, s_v, c] ) consumed += sum( - model.V_FlowOut[r, p, s_s, s_d, c, s_t, s_v, s_o] + model.v_flow_out[r, p, s_s, s_d, c, s_t, s_v, s_o] / get_variable_efficiency(model, r, p, s_s, s_d, c, s_t, s_v, s_o) - for s_s in model.TimeSeason[p] + for s_s in model.time_season[p] for s_d in model.time_of_day - for s_t, s_v in model.commodityDStreamProcess[r, p, c] + for s_t, s_v in model.commodity_down_stream_process[r, p, c] if s_t not in model.tech_storage and s_t not in model.tech_annual - for s_o in model.processOutputsByInput[r, p, s_t, s_v, c] + for s_o in model.process_outputs_by_input[r, p, s_t, s_v, c] ) consumed += sum( - model.V_FlowOutAnnual[r, p, c, s_t, s_v, s_o] - / value(model.Efficiency[r, c, s_t, s_v, s_o]) - for s_t, s_v in model.commodityDStreamProcess[r, p, c] + model.v_flow_out_annual[r, p, c, s_t, s_v, s_o] + / value(model.efficiency[r, c, s_t, s_v, s_o]) + for s_t, s_v in model.commodity_down_stream_process[r, p, c] if s_t in model.tech_annual - for s_o in model.processOutputsByInput[r, p, s_t, s_v, c] + for s_o in model.process_outputs_by_input[r, p, s_t, s_v, c] ) - if (r, p, c) in model.capacityConsumptionTechs: + if (r, p, c) in model.capacity_consumption_techs: # Consumed by building capacity # Assume evenly distributed over a year consumed += ( sum( - value(model.ConstructionInput[r, c, s_t, p]) * model.V_NewCapacity[r, s_t, p] - for s_t in model.capacityConsumptionTechs[r, p, c] + value(model.construction_input[r, c, s_t, p]) * model.v_new_capacity[r, s_t, p] + for s_t in model.capacity_consumption_techs[r, p, c] ) - / model.PeriodLength[p] + / model.period_length[p] ) - if (r, p, c) in model.commodityUStreamProcess: + if (r, p, c) in model.commodity_up_stream_process: # Includes output from storage produced += sum( - model.V_FlowOut[r, p, s_s, s_d, s_i, s_t, s_v, c] - for s_s in model.TimeSeason[p] + model.v_flow_out[r, p, s_s, s_d, s_i, s_t, s_v, c] + for s_s in model.time_season[p] for s_d in model.time_of_day - for s_t, s_v in model.commodityUStreamProcess[r, p, c] + for s_t, s_v in model.commodity_up_stream_process[r, p, c] if s_t not in model.tech_annual - for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] + for s_i in model.process_inputs_by_output[r, p, s_t, s_v, c] ) produced += sum( - model.V_FlowOutAnnual[r, p, s_i, s_t, s_v, c] - for s_t, s_v in model.commodityUStreamProcess[r, p, c] + model.v_flow_out_annual[r, p, s_i, s_t, s_v, c] + for s_t, s_v in model.commodity_up_stream_process[r, p, c] if s_t in model.tech_annual - for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] + for s_i in model.process_inputs_by_output[r, p, s_t, s_v, c] ) if c in model.commodity_flex: consumed += sum( - model.V_Flex[r, p, s_s, s_d, s_i, s_t, s_v, c] - for s_s in model.TimeSeason[p] + model.v_flex[r, p, s_s, s_d, s_i, s_t, s_v, c] + for s_s in model.time_season[p] for s_d in model.time_of_day - for s_t, s_v in model.commodityUStreamProcess[r, p, c] + for s_t, s_v in model.commodity_up_stream_process[r, p, c] if s_t not in model.tech_annual and s_t in model.tech_flex - for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] + for s_i in model.process_inputs_by_output[r, p, s_t, s_v, c] ) consumed += sum( - model.V_FlexAnnual[r, p, s_i, s_t, s_v, c] - for s_t, s_v in model.commodityUStreamProcess[r, p, c] + model.v_flex_annual[r, p, s_i, s_t, s_v, c] + for s_t, s_v in model.commodity_up_stream_process[r, p, c] if s_t in model.tech_flex and s_t in model.tech_annual - for s_i in model.processInputsByOutput[r, p, s_t, s_v, c] + for s_i in model.process_inputs_by_output[r, p, s_t, s_v, c] ) - if (r, p, c) in model.retirementProductionProcesses: + if (r, p, c) in model.retirement_production_processes: # Produced by retiring capacity # Assume evenly distributed over a year produced += sum( - value(model.EndOfLifeOutput[r, s_t, s_v, c]) * model.V_AnnualRetirement[r, p, s_t, s_v] - for s_t, s_v in model.retirementProductionProcesses[r, p, c] + value(model.end_of_life_output[r, s_t, s_v, c]) + * model.v_annual_retirement[r, p, s_t, s_v] + for s_t, s_v in model.retirement_production_processes[r, p, c] ) # export of commodity c from region r to other regions - if (r, p, c) in model.exportRegions: + if (r, p, c) in model.export_regions: consumed += sum( - model.V_FlowOut[cast(Region, r + '-' + s_r), p, s_s, s_d, c, s_t, s_v, s_o] + model.v_flow_out[cast(Region, r + '-' + s_r), p, s_s, s_d, c, s_t, s_v, s_o] / get_variable_efficiency( model, cast(Region, r + '-' + s_r), p, s_s, s_d, c, s_t, s_v, s_o ) - for s_s in model.TimeSeason[p] + for s_s in model.time_season[p] for s_d in model.time_of_day - for s_r, s_t, s_v, s_o in model.exportRegions[r, p, c] + for s_r, s_t, s_v, s_o in model.export_regions[r, p, c] if s_t not in model.tech_annual ) consumed += sum( - model.V_FlowOutAnnual[cast(Region, r + '-' + s_r), p, c, s_t, s_v, s_o] - / model.Efficiency[cast(Region, r + '-' + s_r), c, s_t, s_v, s_o] - for s_r, s_t, s_v, s_o in model.exportRegions[r, p, c] + model.v_flow_out_annual[cast(Region, r + '-' + s_r), p, c, s_t, s_v, s_o] + / model.efficiency[cast(Region, r + '-' + s_r), c, s_t, s_v, s_o] + for s_r, s_t, s_v, s_o in model.export_regions[r, p, c] if s_t in model.tech_annual ) # import of commodity c from other regions into region r - if (r, p, c) in model.importRegions: + if (r, p, c) in model.import_regions: produced += sum( - model.V_FlowOut[cast(Region, s_r + '-' + r), p, s_s, S_d, s_i, s_t, s_v, c] - for s_s in model.TimeSeason[p] + model.v_flow_out[cast(Region, s_r + '-' + r), p, s_s, S_d, s_i, s_t, s_v, c] + for s_s in model.time_season[p] for S_d in model.time_of_day - for s_r, s_t, s_v, s_i in model.importRegions[r, p, c] + for s_r, s_t, s_v, s_i in model.import_regions[r, p, c] if s_t not in model.tech_annual ) produced += sum( - model.V_FlowOutAnnual[cast(Region, s_r + '-' + r), p, s_i, s_t, s_v, c] - for s_r, s_t, s_v, s_i in model.importRegions[r, p, c] + model.v_flow_out_annual[cast(Region, s_r + '-' + r), p, s_i, s_t, s_v, c] + for s_r, s_t, s_v, s_i in model.import_regions[r, p, c] if s_t in model.tech_annual ) @@ -641,9 +643,9 @@ def annual_commodity_balance_constraint( def create_technology_and_commodity_sets(model: TemoaModel) -> None: """ Populates technology and commodity subset definitions based on their roles - (e.g., demand, flexible) identified from the Efficiency parameter. + (e.g., demand, flexible) identified from the efficiency parameter. - This function iterates through the `Efficiency` parameter to identify and + This function iterates through the `efficiency` parameter to identify and add technologies and commodities to special `Pyomo.Set` objects on the model. Populates: @@ -651,7 +653,7 @@ def create_technology_and_commodity_sets(model: TemoaModel) -> None: - M.tech_demand: Technologies that directly satisfy an end-use demand. """ logger.debug('Creating technology and commodity subsets.') - for _r, _i, t, _v, o in model.Efficiency.sparse_iterkeys(): + for _r, _i, t, _v, o in model.efficiency.sparse_iterkeys(): if t in model.tech_flex and o not in model.commodity_flex: model.commodity_flex.add(o) @@ -664,7 +666,7 @@ def create_demands(model: TemoaModel) -> None: Steps to create the demand distributions 1. Use Demand keys to ensure that all demands in commodity_demand are used 2. Find any slices not set in DemandDefaultDistribution, and set them based - on the associated SegFrac slice. + on the associated segment_fraction slice. 3. Validate that the DemandDefaultDistribution sums to 1. 4. Find any per-demand DemandSpecificDistribution values not set, and set them from DemandDefaultDistribution. Note that this only sets a @@ -683,7 +685,7 @@ def create_demands(model: TemoaModel) -> None: demand_specific_distributon_dem = iget(4) # Step 1: Check if any demand commodities are going unused - used_dems = {dem for r, p, dem in model.Demand.sparse_iterkeys()} + used_dems = {dem for r, p, dem in model.demand.sparse_iterkeys()} unused_dems = sorted(model.commodity_demand.difference(used_dems)) if unused_dems: for dem in unused_dems: @@ -691,11 +693,11 @@ def create_demands(model: TemoaModel) -> None: logger.warning(msg.format(dem)) sys.stderr.write(msg.format(dem)) - # devnote: DDD just clones SegFrac. Unless we want to specify it in the database, - # makes sense to just use SegFrac directly + # devnote: DDD just clones segment_fraction. Unless we want to specify it in the database, + # makes sense to just use segment_fraction directly # Step 2: Build the demand default distribution (= segfrac) # DDD = M.DemandDefaultDistribution # Shorter, for us lazy programmer types - # unset_defaults = set(M.SegFrac.sparse_iterkeys()) + # unset_defaults = set(M.segment_fraction.sparse_iterkeys()) # unset_defaults.difference_update(DDD.sparse_iterkeys()) # if unset_defaults: # Some hackery because Pyomo thinks that this Param is constructed. @@ -704,10 +706,10 @@ def create_demands(model: TemoaModel) -> None: # valid, and that we will need. # DDD._constructed = False # for tslice in unset_defaults: - # DDD[tslice] = M.SegFrac[tslice] # DDD._constructed = True + # DDD[tslice] = M.segment_fraction[tslice] # DDD._constructed = True # Step 3: Check that DDD sums to 1 - # devnote: this seems redundant to the SegFrac sum to 1 check. + # devnote: this seems redundant to the segment_fraction sum to 1 check. # total = sum(i for i in DDD.values()) # if abs(value(total) - 1.0) > 0.001: # # We can't explicitly test for "!= 1.0" because of incremental rounding @@ -733,7 +735,7 @@ def create_demands(model: TemoaModel) -> None: # raise ValueError(msg.format(items, total)) # Step 4: Fill out demand specific distribution table and check sums to 1 by region and demand - demand_specific_distribution = model.DemandSpecificDistribution + demand_specific_distribution = model.demand_specific_distribution demands_specified = set( map( @@ -751,23 +753,23 @@ def create_demands(model: TemoaModel) -> None: cross_product( model.regions, (p,), - model.TimeSeason[p], + model.time_season[p], model.time_of_day, unset_demand_distributions, ) ) for r, p, s, d, dem in unset_distributions: demand_specific_distribution[r, p, s, d, dem] = value( - model.SegFrac[p, s, d] + model.segment_fraction[p, s, d] ) # DSD._constructed = True # Step 5: A final "sum to 1" check for all DSD members (which now should be everything) # Also check that all keys are made... The demand distro should be supported # by the full set of (r, p, dem) keys because it is an equality constraint # and we need to ensure even the zeros are passed in - used_rp_dems = {(r, p, dem) for r, p, dem in model.Demand.sparse_iterkeys()} + used_rp_dems = {(r, p, dem) for r, p, dem in model.demand.sparse_iterkeys()} for r, p, dem in used_rp_dems: - expected_key_length = len(model.TimeSeason[p]) * len(model.time_of_day) + expected_key_length = len(model.time_season[p]) * len(model.time_of_day) keys = [ k for k in demand_specific_distribution.sparse_iterkeys() @@ -779,7 +781,7 @@ def create_demands(model: TemoaModel) -> None: # this could be very slow but only calls when there's a problem missing = { (s, d) - for s in model.TimeSeason[p] + for s in model.time_season[p] for d in model.time_of_day if (r, p, s, d, dem) not in keys } diff --git a/temoa/components/costs.py b/temoa/components/costs.py index 4ea4aeacc..362e4fd6c 100644 --- a/temoa/components/costs.py +++ b/temoa/components/costs.py @@ -7,7 +7,7 @@ - Pre-computing and populating cost parameters. - Defining the rules for calculating all investment, fixed, variable, and emission-related costs incurred over the model horizon. -- Defining the model's objective function (TotalCost_rule) to minimize the +- Defining the model's objective function (total_cost_rule) to minimize the net present value of the total system cost. """ @@ -36,8 +36,8 @@ def get_default_loan_rate(model: TemoaModel, *_: Any) -> float: - """get the default loan rate from the DefaultLoanRate param""" - return value(model.DefaultLoanRate) + """get the default loan rate from the default_loan_rate param""" + return value(model.default_loan_rate) def annuity_to_pv(rate: float, periods: float) -> float | Expression: @@ -88,7 +88,7 @@ def fv_to_pv(rate: float, periods: float) -> float | Expression: def get_loan_life(model: TemoaModel, r: Region, t: Technology, v: Vintage) -> int: - return value(model.LifetimeProcess[r, t, v]) + return value(model.lifetime_process[r, t, v]) # ============================================================================ @@ -98,28 +98,28 @@ def get_loan_life(model: TemoaModel, r: Region, t: Technology, v: Vintage) -> in def cost_fixed_indices(model: TemoaModel) -> set[tuple[Region, Period, Technology, Vintage]]: # we pull the unlimited capacity techs from this index. They cannot have fixed costs - if model.activeActivity_rptv: + if model.active_activity_rptv: return { - (r, p, t, v) for r, p, t, v in model.activeActivity_rptv if t not in model.tech_uncap + (r, p, t, v) for r, p, t, v in model.active_activity_rptv if t not in model.tech_uncap } return set() def cost_variable_indices(model: TemoaModel) -> set[tuple[Region, Period, Technology, Vintage]]: - if model.activeActivity_rptv: - return model.activeActivity_rptv + if model.active_activity_rptv: + return model.active_activity_rptv return set() def lifetime_loan_process_indices(model: TemoaModel) -> set[tuple[Region, Technology, Vintage]]: """ - Based on the Efficiency parameter's indices and time_future parameter, this + Based on the efficiency parameter's indices and time_future parameter, this function returns the set of process indices that may be specified in the - CostInvest parameter. + cost_invest parameter. """ min_period = min(model.vintage_optimize) - indices = {(r, t, v) for r, i, t, v, o in model.Efficiency.sparse_iterkeys() if v >= min_period} + indices = {(r, t, v) for r, i, t, v, o in model.efficiency.sparse_iterkeys() if v >= min_period} return indices @@ -158,7 +158,7 @@ def loan_cost( # calculate the amortised loan repayment (annuity) annuity = ( capacity - * invest_cost # lump investment cost is capacity times CostInvest + * invest_cost # lump investment cost is capacity times cost_invest * loan_annualize # calculate loan annuities for investment cost, if used ) @@ -222,7 +222,7 @@ def loan_cost_survival_curve( # calculate the amortised loan repayment (annuity) annuity = ( capacity - * invest_cost # lump investment cost is capacity times CostInvest + * invest_cost # lump investment cost is capacity times cost_invest * loan_annualize # calculate loan annuities for investment cost, if used ) @@ -232,13 +232,13 @@ def loan_cost_survival_curve( annuity * lifetime_loan_process # sum of loan payments over loan period / sum( # redistributed over survival curve within horizon - value(model.LifetimeSurvivalCurve[r, p, t, v]) - for p in model.survivalCurvePeriods[r, t, v] + value(model.lifetime_survival_curve[r, p, t, v]) + for p in model.survival_curve_periods[r, t, v] if v <= p ) * sum( # summed over survival curve within horizon - value(model.LifetimeSurvivalCurve[r, p, t, v]) - for p in model.survivalCurvePeriods[r, t, v] + value(model.lifetime_survival_curve[r, p, t, v]) + for p in model.survival_curve_periods[r, t, v] if v <= p < p_e ) ) @@ -251,18 +251,18 @@ def loan_cost_survival_curve( ) # PV of all loan payments, discounted to vintage year using GDR / sum( # redistributed over survival curve within horizon value( - model.LifetimeSurvivalCurve[r, p, t, v] + model.lifetime_survival_curve[r, p, t, v] ) # reamortised over survival curve of process using GDR * fv_to_pv( global_discount_rate, p - v + 1 ) # +1 because LSC is indexed to start of p not end of p - for p in model.survivalCurvePeriods[r, t, v] + for p in model.survival_curve_periods[r, t, v] if v <= p # this shouldnt be possible but play it safe ) * sum( # PV of all reamortised costs (within planning horizon) - value(model.LifetimeSurvivalCurve[r, p, t, v]) + value(model.lifetime_survival_curve[r, p, t, v]) * fv_to_pv(global_discount_rate, p - v + 1) - for p in model.survivalCurvePeriods[r, t, v] + for p in model.survival_curve_periods[r, t, v] if v <= p < p_e ) * fv_to_pv( @@ -316,26 +316,26 @@ def fixed_or_variable_cost( def period_cost_rule(model: TemoaModel, p: int) -> float | Expression: p_0 = min(model.time_optimize) p_e = model.time_future.last() # End point of modeled horizon - global_discount_rate = value(model.GlobalDiscountRate) + global_discount_rate = value(model.global_discount_rate) # MPL = M.ModelProcessLife - if value(model.MyopicDiscountingYear) != 0: - p_0 = value(model.MyopicDiscountingYear) + if value(model.myopic_discounting_year) != 0: + p_0 = value(model.myopic_discounting_year) loan_costs = quicksum( loan_cost( - model.V_NewCapacity[r, S_t, S_v], - value(model.CostInvest[r, S_t, S_v]), - value(model.LoanAnnualize[r, S_t, S_v]), - value(model.LoanLifetimeProcess[r, S_t, S_v]), - value(model.LifetimeProcess[r, S_t, S_v]), + model.v_new_capacity[r, S_t, S_v], + value(model.cost_invest[r, S_t, S_v]), + value(model.loan_annualize[r, S_t, S_v]), + value(model.loan_lifetime_process[r, S_t, S_v]), + value(model.lifetime_process[r, S_t, S_v]), p_0, p_e, global_discount_rate, vintage=S_v, ) - for r, S_t, S_v in model.CostInvest.sparse_iterkeys() - if S_v == p and not model.isSurvivalCurveProcess[r, S_t, S_v] + for r, S_t, S_v in model.cost_invest.sparse_iterkeys() + if S_v == p and not model.is_survival_curve_process[r, S_t, S_v] ) loan_costs += quicksum( loan_cost_survival_curve( @@ -343,87 +343,87 @@ def period_cost_rule(model: TemoaModel, p: int) -> float | Expression: r, S_t, S_v, - model.V_NewCapacity[r, S_t, S_v], - value(model.CostInvest[r, S_t, S_v]), - value(model.LoanAnnualize[r, S_t, S_v]), - value(model.LoanLifetimeProcess[r, S_t, S_v]), + model.v_new_capacity[r, S_t, S_v], + value(model.cost_invest[r, S_t, S_v]), + value(model.loan_annualize[r, S_t, S_v]), + value(model.loan_lifetime_process[r, S_t, S_v]), p_0, p_e, global_discount_rate, ) - for r, S_t, S_v in model.CostInvest.sparse_iterkeys() - if S_v == p and model.isSurvivalCurveProcess[r, S_t, S_v] + for r, S_t, S_v in model.cost_invest.sparse_iterkeys() + if S_v == p and model.is_survival_curve_process[r, S_t, S_v] ) fixed_costs = quicksum( fixed_or_variable_cost( - model.V_Capacity[r, p, S_t, S_v], - value(model.CostFixed[r, p, S_t, S_v]), - value(model.PeriodLength[p]), + model.v_capacity[r, p, S_t, S_v], + value(model.cost_fixed[r, p, S_t, S_v]), + value(model.period_length[p]), global_discount_rate, p_0, p=p, ) - for r, S_p, S_t, S_v in model.CostFixed.sparse_iterkeys() + for r, S_p, S_t, S_v in model.cost_fixed.sparse_iterkeys() if S_p == p ) variable_costs = quicksum( fixed_or_variable_cost( - model.V_FlowOut[r, p, s, d, S_i, S_t, S_v, S_o], - value(model.CostVariable[r, p, S_t, S_v]), - value(model.PeriodLength[p]), + model.v_flow_out[r, p, s, d, S_i, S_t, S_v, S_o], + value(model.cost_variable[r, p, S_t, S_v]), + value(model.period_length[p]), global_discount_rate, p_0, p, ) - for r, S_p, S_t, S_v in model.CostVariable.sparse_iterkeys() + for r, S_p, S_t, S_v in model.cost_variable.sparse_iterkeys() if S_p == p and S_t not in model.tech_annual - for S_i in model.processInputs[r, S_p, S_t, S_v] - for S_o in model.processOutputsByInput[r, S_p, S_t, S_v, S_i] - for s in model.TimeSeason[p] + for S_i in model.process_inputs[r, S_p, S_t, S_v] + for S_o in model.process_outputs_by_input[r, S_p, S_t, S_v, S_i] + for s in model.time_season[p] for d in model.time_of_day ) variable_costs_annual = quicksum( fixed_or_variable_cost( - model.V_FlowOutAnnual[r, p, S_i, S_t, S_v, S_o], - value(model.CostVariable[r, p, S_t, S_v]), - value(model.PeriodLength[p]), + model.v_flow_out_annual[r, p, S_i, S_t, S_v, S_o], + value(model.cost_variable[r, p, S_t, S_v]), + value(model.period_length[p]), global_discount_rate, p_0, p, ) - for r, S_p, S_t, S_v in model.CostVariable.sparse_iterkeys() + for r, S_p, S_t, S_v in model.cost_variable.sparse_iterkeys() if S_p == p and S_t in model.tech_annual - for S_i in model.processInputs[r, S_p, S_t, S_v] - for S_o in model.processOutputsByInput[r, S_p, S_t, S_v, S_i] + for S_i in model.process_inputs[r, S_p, S_t, S_v] + for S_o in model.process_outputs_by_input[r, S_p, S_t, S_v, S_i] ) # The emissions costs occur over the five possible emission sources. # to do any/all of them we need 2 baseline sets: The regular and annual sets # of indices that are valid which is basically the filter of: - # EmissionActivty by CostEmission + # EmissionActivty by cost_emission # and to ensure that the techology is active we need to filter that # result with processInput # ================= Emissions and Flex and Curtailment ================= - # Flex flows are deducted from V_FlowOut, so it is NOT NEEDED to tax them again. (See commodity balance constr) + # Flex flows are deducted from v_flow_out, so it is NOT NEEDED to tax them again. (See commodity balance constr) # Curtailment does not draw any inputs, so it seems logical that curtailed flows not be taxed either # Earlier versions of this code had accounting for flex & curtailment that have been removed. base = [ (r, p, e, i, t, v, o) - for (r, e, i, t, v, o) in model.EmissionActivity.sparse_iterkeys() - if (r, p, e) in model.CostEmission # tightest filter first - and (r, p, t, v) in model.processInputs + for (r, e, i, t, v, o) in model.emission_activity.sparse_iterkeys() + if (r, p, e) in model.cost_emission # tightest filter first + and (r, p, t, v) in model.process_inputs ] # then expand the base for the normal (season/tod) set and annual separately: normal = [ (r, p, e, s, d, i, t, v, o) for (r, p, e, i, t, v, o) in base - for s in model.TimeSeason[p] + for s in model.time_season[p] for d in model.time_of_day if t not in model.tech_annual ] @@ -433,10 +433,10 @@ def period_cost_rule(model: TemoaModel, p: int) -> float | Expression: # 1. variable emissions var_emissions = quicksum( fixed_or_variable_cost( - cap_or_flow=model.V_FlowOut[r, p, s, d, i, t, v, o] - * value(model.EmissionActivity[r, e, i, t, v, o]), - cost_factor=value(model.CostEmission[r, p, e]), - cost_years=value(model.PeriodLength[p]), + cap_or_flow=model.v_flow_out[r, p, s, d, i, t, v, o] + * value(model.emission_activity[r, e, i, t, v, o]), + cost_factor=value(model.cost_emission[r, p, e]), + cost_years=value(model.period_length[p]), global_discount_rate=global_discount_rate, p_0=p_0, p=p, @@ -451,10 +451,10 @@ def period_cost_rule(model: TemoaModel, p: int) -> float | Expression: # 4. annual emissions var_annual_emissions = quicksum( fixed_or_variable_cost( - cap_or_flow=model.V_FlowOutAnnual[r, p, i, t, v, o] - * value(model.EmissionActivity[r, e, i, t, v, o]), - cost_factor=value(model.CostEmission[r, p, e]), - cost_years=value(model.PeriodLength[p]), + cap_or_flow=model.v_flow_out_annual[r, p, i, t, v, o] + * value(model.emission_activity[r, e, i, t, v, o]), + cost_factor=value(model.cost_emission[r, p, e]), + cost_years=value(model.period_length[p]), global_discount_rate=global_discount_rate, p_0=p_0, p=p, @@ -468,38 +468,38 @@ def period_cost_rule(model: TemoaModel, p: int) -> float | Expression: # 6. embodied - treated as a fixed cost distributed over the deployment period (vintage) embodied_emissions = quicksum( fixed_or_variable_cost( - cap_or_flow=model.V_NewCapacity[r, t, v] - * value(model.EmissionEmbodied[r, e, t, v]) - / value(model.PeriodLength[p]), - cost_factor=value(model.CostEmission[r, p, e]), + cap_or_flow=model.v_new_capacity[r, t, v] + * value(model.emission_embodied[r, e, t, v]) + / value(model.period_length[p]), + cost_factor=value(model.cost_emission[r, p, e]), cost_years=value( - model.PeriodLength[v] + model.period_length[v] ), # We assume the embodied emissions are emitted in the same year as the capacity is installed. global_discount_rate=global_discount_rate, p_0=p_0, p=p, ) - for (r, e, t, v) in model.EmissionEmbodied.sparse_iterkeys() - if (r, p, e) in model.CostEmission + for (r, e, t, v) in model.emission_embodied.sparse_iterkeys() + if (r, p, e) in model.cost_emission if v == p ) # 6. endoflife - treated as a fixed cost distributed over the retirement period endoflife_emissions = quicksum( fixed_or_variable_cost( - cap_or_flow=model.V_AnnualRetirement[r, p, t, v] - * value(model.EmissionEndOfLife[r, e, t, v]), - cost_factor=value(model.CostEmission[r, p, e]), + cap_or_flow=model.v_annual_retirement[r, p, t, v] + * value(model.emission_end_of_life[r, e, t, v]), + cost_factor=value(model.cost_emission[r, p, e]), cost_years=value( - model.PeriodLength[p] + model.period_length[p] ), # We assume the embodied emissions are emitted in the same year as the capacity is installed. global_discount_rate=global_discount_rate, p_0=p_0, p=p, ) - for (r, e, t, v) in model.EmissionEndOfLife.sparse_iterkeys() - if (r, p, e) in model.CostEmission - if (r, t, v) in model.retirementPeriods and p in model.retirementPeriods[r, t, v] + for (r, e, t, v) in model.emission_end_of_life.sparse_iterkeys() + if (r, p, e) in model.cost_emission + if (r, t, v) in model.retirement_periods and p in model.retirement_periods[r, t, v] ) period_emission_cost = ( @@ -661,17 +661,17 @@ def total_cost_rule(model: TemoaModel) -> Expression: def create_costs(model: TemoaModel) -> None: """ Steps to creating fixed and variable costs: - 1. Collect all possible cost indices (CostFixed, CostVariable) - 2. Find the ones _not_ specified in CostFixed and CostVariable + 1. Collect all possible cost indices (cost_fixed, cost_variable) + 2. Find the ones _not_ specified in cost_fixed and cost_variable 3. Set them, based on Cost*VintageDefault """ logger.debug('Started Creating Fixed and Variable costs in CreateCosts()') - cost_fixed = model.CostFixed - cost_variable = model.CostVariable + cost_fixed = model.cost_fixed + cost_variable = model.cost_variable # Step 1 - fixed_indices = set(model.CostFixed_rptv) - var_indices = set(model.CostVariable_rptv) + fixed_indices = set(model.cost_fixed_rptv) + var_indices = set(model.cost_variable_rptv) # Step 2 unspecified_fixed_prices = fixed_indices.difference(cost_fixed.sparse_iterkeys()) @@ -687,19 +687,19 @@ def create_costs(model: TemoaModel) -> None: if unspecified_fixed_prices: # CF._constructed = False for r, p, t, v in unspecified_fixed_prices: - if (r, t, v) in model.CostFixedVintageDefault: - cost_fixed[r, p, t, v] = model.CostFixedVintageDefault[ + if (r, t, v) in model.cost_fixedVintageDefault: + cost_fixed[r, p, t, v] = model.cost_fixedVintageDefault[ r, t, v ] # CF._constructed = True if unspecified_var_prices: # CV._constructed = False for r, p, t, v in unspecified_var_prices: - if (r, t, v) in model.CostVariableVintageDefault: - cost_variable[r, p, t, v] = model.CostVariableVintageDefault[r, t, v] + if (r, t, v) in model.cost_variableVintageDefault: + cost_variable[r, p, t, v] = model.cost_variableVintageDefault[r, t, v] # CV._constructed = True - logger.debug('Created M.CostFixed with size: %d', len(value(model.CostFixed))) - logger.debug('Created M.CostVariable with size: %d', len(value(model.CostVariable))) + logger.debug('Created M.cost_fixed with size: %d', len(value(model.cost_fixed))) + logger.debug('Created M.cost_variable with size: %d', len(value(model.cost_variable))) logger.debug('Finished creating Fixed and Variable costs') @@ -707,7 +707,7 @@ def param_loan_annualize_rule( model: TemoaModel, r: Region, t: Technology, v: Vintage ) -> float | Expression: """Rule to calculate the annualized loan rate from the loan rate and lifetime.""" - dr = value(model.LoanRate[r, t, v]) - lln = value(model.LoanLifetimeProcess[r, t, v]) + dr = value(model.loan_rate[r, t, v]) + lln = value(model.loan_lifetime_process[r, t, v]) annualized_rate = pv_to_annuity(dr, lln) return annualized_rate diff --git a/temoa/components/emissions.py b/temoa/components/emissions.py index 57a62da99..414624514 100644 --- a/temoa/components/emissions.py +++ b/temoa/components/emissions.py @@ -33,7 +33,7 @@ def emission_activity_indices( ) -> set[tuple[Region, Commodity, Commodity, Technology, Vintage, Commodity]]: indices = { (r, e, i, t, v, o) - for r, i, t, v, o in model.Efficiency.sparse_iterkeys() + for r, i, t, v, o in model.efficiency.sparse_iterkeys() for e in model.commodity_emissions if r in model.regions # omit any exchange/groups } @@ -46,12 +46,12 @@ def linked_tech_constraint_indices( ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage, Commodity]]: linkedtech_indices = { (r, p, s, d, t, v, e) - for r, t, e in model.LinkedTechs.sparse_iterkeys() + for r, t, e in model.linked_techs.sparse_iterkeys() for p in model.time_optimize - if (r, p, t) in model.processVintages - for v in model.processVintages[r, p, t] - if model.activeActivity_rptv and (r, p, t, v) in model.activeActivity_rptv - for s in model.TimeSeason[p] + if (r, p, t) in model.process_vintages + for v in model.process_vintages[r, p, t] + if model.active_activity_rptv and (r, p, t, v) in model.active_activity_rptv + for s in model.time_season[p] for d in model.time_of_day } @@ -87,10 +87,10 @@ def linked_emissions_tech_constraint( - \sum_{I, O} \textbf{FO}_{r, p, s, d, i, t, v, o} \cdot EAC_{r, e, i, t, v, o} = \sum_{I, O} \textbf{FO}_{r, p, s, d, i, t, v, o} - \forall \{r, p, s, d, t, v, e\} \in \Theta_{\text{LinkedTechs}} + \forall \{r, p, s, d, t, v, e\} \in \Theta_{\text{linked_techs}} The relationship between the primary and linked technologies is given - in the :code:`LinkedTechs` table. Note that the primary and linked + in the :code:`linked_techs` 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. @@ -99,47 +99,47 @@ def linked_emissions_tech_constraint( if t in model.tech_annual: primary_flow = quicksum( ( - value(model.DemandSpecificDistribution[r, p, s, d, S_o]) + value(model.demand_specific_distribution[r, p, s, d, S_o]) if S_o in model.commodity_demand - else value(model.SegFrac[p, s, d]) + else value(model.segment_fraction[p, s, d]) ) - * model.V_FlowOutAnnual[r, p, S_i, t, v, S_o] - * value(model.EmissionActivity[r, e, S_i, t, v, S_o]) - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + * model.v_flow_out_annual[r, p, S_i, t, v, S_o] + * value(model.emission_activity[r, e, S_i, t, v, S_o]) + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) else: primary_flow = quicksum( - model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - * value(model.EmissionActivity[r, e, S_i, t, v, S_o]) - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + model.v_flow_out[r, p, s, d, S_i, t, v, S_o] + * value(model.emission_activity[r, e, S_i, t, v, S_o]) + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) - linked_t = value(model.LinkedTechs[r, t, e]) + linked_t = value(model.linked_techs[r, t, e]) # linked_flow = sum( - # M.V_FlowOut[r, p, s, d, S_i, linked_t, v, S_o] + # M.v_flow_out[r, p, s, d, S_i, linked_t, v, S_o] # for S_i in M.processInputs[r, p, linked_t, v] - # for S_o in M.processOutputsByInput[r, p, linked_t, v, S_i] + # for S_o in M.process_outputs_by_input[r, p, linked_t, v, S_i] # ) if linked_t in model.tech_annual: linked_flow = quicksum( ( - value(model.DemandSpecificDistribution[r, p, s, d, S_o]) + value(model.demand_specific_distribution[r, p, s, d, S_o]) if S_o in model.commodity_demand - else value(model.SegFrac[p, s, d]) + else value(model.segment_fraction[p, s, d]) ) - * model.V_FlowOutAnnual[r, p, S_i, linked_t, v, S_o] - for S_i in model.processInputs[r, p, linked_t, v] - for S_o in model.processOutputsByInput[r, p, linked_t, v, S_i] + * model.v_flow_out_annual[r, p, S_i, linked_t, v, S_o] + for S_i in model.process_inputs[r, p, linked_t, v] + for S_o in model.process_outputs_by_input[r, p, linked_t, v, S_i] ) else: linked_flow = quicksum( - model.V_FlowOut[r, p, s, d, S_i, linked_t, v, S_o] - for S_i in model.processInputs[r, p, linked_t, v] - for S_o in model.processOutputsByInput[r, p, linked_t, v, S_i] + model.v_flow_out[r, p, s, d, S_i, linked_t, v, S_o] + for S_i in model.process_inputs[r, p, linked_t, v] + for S_o in model.process_outputs_by_input[r, p, linked_t, v, S_i] ) return -primary_flow == linked_flow diff --git a/temoa/components/flows.py b/temoa/components/flows.py index feaf07a10..e31188216 100644 --- a/temoa/components/flows.py +++ b/temoa/components/flows.py @@ -6,7 +6,7 @@ - Pre-computing the sparse index sets for all types of commodity flows (standard, annual, flexible, storage, curtailment). - Defining the Pyomo index set functions used to construct the flow-related - decision variables (V_FlowOut, V_FlowIn, V_Flex, etc.). + decision variables (v_flow_out, v_flow_in, v_flex, etc.). """ from __future__ import annotations @@ -45,13 +45,13 @@ def flow_variable_indices( ) -> ( set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] | None ): - return model.activeFlow_rpsditvo + return model.active_flow_rpsditvo def flow_variable_annual_indices( model: TemoaModel, ) -> ActiveFlowAnnualSet: - return model.activeFlow_rpitvo + return model.active_flow_rpitvo def flex_variable_indices( @@ -59,13 +59,13 @@ def flex_variable_indices( ) -> ( set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] | None ): - return model.activeFlex_rpsditvo + return model.active_flex_rpsditvo def flex_variable_annual_indices( model: TemoaModel, ) -> ActiveFlexAnnualSet: - return model.activeFlex_rpitvo + return model.active_flex_rpitvo def flow_in_storage_variable_indices( @@ -73,7 +73,7 @@ def flow_in_storage_variable_indices( ) -> ( set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] | None ): - return model.activeFlowInStorage_rpsditvo + return model.active_flow_in_storage_rpsditvo def curtailment_variable_indices( @@ -81,7 +81,7 @@ def curtailment_variable_indices( ) -> ( set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] | None ): - return model.activeCurtailment_rpsditvo + return model.active_curtailment_rpsditvo # ============================================================================ @@ -99,109 +99,113 @@ def create_commodity_balance_and_flow_sets(model: TemoaModel) -> None: Populates: - model.commodityBalance_rpc: The master set of (r, p, c) for balance constraints. - - model.activeFlow_rpsditvo: Indices for time-sliced flows (V_FlowOut). - - model.activeFlow_rpitvo: Indices for annual flows (V_FlowOutAnnual). - - model.activeFlex_rpsditvo: Indices for flexible time-sliced flows (V_Flex). - - model.activeFlex_rpitvo: Indices for flexible annual flows (V_FlexAnnual). - - model.activeFlowInStorage_rpsditvo: Indices for flows into storage (V_FlowIn). - - model.activeCurtailment_rpsditvo: Indices for curtailed generation (V_Curtailment). + - model.activeFlow_rpsditvo: Indices for time-sliced flows (v_flow_out). + - model.activeFlow_rpitvo: Indices for annual flows (v_flow_out_annual). + - model.activeFlex_rpsditvo: Indices for flexible time-sliced flows (v_flex). + - model.activeFlex_rpitvo: Indices for flexible annual flows (v_flex_annual). + - model.activeflow_in_storage_rpsditvo: Indices for flows into storage (v_flow_in). + - model.activeCurtailment_rpsditvo: Indices for curtailed generation (v_curtailment). - model.activeActivity_rptv: Master set of active (r, p, t, v) processes. - - model.storageLevelIndices_rpsdtv: Indices for storage state variables (V_StorageLevel). + - model.storageLevelIndices_rpsdtv: Indices for storage state variables (v_storage_level). - model.seasonalStorageLevelIndices_rpstv: Indices for seasonal storage levels. """ logger.debug('Creating commodity balance and active flow index sets.') # 1. Commodity Balance commodity_upstream = set( - model.commodityUStreamProcess | model.retirementProductionProcesses | model.importRegions + model.commodity_up_stream_process + | model.retirement_production_processes + | model.import_regions ) commodity_downstream = set( - model.commodityDStreamProcess | model.capacityConsumptionTechs | model.exportRegions + model.commodity_down_stream_process + | model.capacity_consumption_techs + | model.export_regions ) model.commodityBalance_rpc = commodity_upstream.intersection(commodity_downstream) # 2. Active Flow Indices (Time-Sliced) - model.activeFlow_rpsditvo = { + model.active_flow_rpsditvo = { (r, p, s, d, i, t, v, o) - for r, p, t in model.processVintages + for r, p, t in model.process_vintages if t not in model.tech_annual - for v in model.processVintages[r, p, t] - for i in model.processInputs.get((r, p, t, v), set()) - for o in model.processOutputsByInput.get((r, p, t, v, i), set()) - for s in model.TimeSeason[p] + for v in model.process_vintages[r, p, t] + for i in model.process_inputs.get((r, p, t, v), set()) + for o in model.process_outputs_by_input.get((r, p, t, v, i), set()) + for s in model.time_season[p] for d in model.time_of_day } # 3. Active Flow Indices (Annual) - model.activeFlow_rpitvo = { + model.active_flow_rpitvo = { (r, p, i, t, v, o) - for r, p, t in model.processVintages - for v in model.processVintages[r, p, t] - for i in model.processInputs.get((r, p, t, v), set()) - for o in model.processOutputsByInput.get((r, p, t, v, i), set()) + for r, p, t in model.process_vintages + for v in model.process_vintages[r, p, t] + for i in model.process_inputs.get((r, p, t, v), set()) + for o in model.process_outputs_by_input.get((r, p, t, v, i), set()) if t in model.tech_annual or (t in model.tech_demand and o in model.commodity_demand) } # 4. Active Flexible Technology Flow Indices - model.activeFlex_rpsditvo = { + model.active_flex_rpsditvo = { (r, p, s, d, i, t, v, o) - for r, p, t in model.processVintages + for r, p, t in model.process_vintages if (t not in model.tech_annual) and (t in model.tech_flex) - for v in model.processVintages[r, p, t] - for i in model.processInputs.get((r, p, t, v), set()) - for o in model.processOutputsByInput.get((r, p, t, v, i), set()) - for s in model.TimeSeason[p] + for v in model.process_vintages[r, p, t] + for i in model.process_inputs.get((r, p, t, v), set()) + for o in model.process_outputs_by_input.get((r, p, t, v, i), set()) + for s in model.time_season[p] for d in model.time_of_day } - model.activeFlex_rpitvo = { + model.active_flex_rpitvo = { (r, p, i, t, v, o) - for r, p, t in model.processVintages + for r, p, t in model.process_vintages if (t in model.tech_annual) and (t in model.tech_flex) - for v in model.processVintages[r, p, t] - for i in model.processInputs.get((r, p, t, v), set()) - for o in model.processOutputsByInput.get((r, p, t, v, i), set()) + for v in model.process_vintages[r, p, t] + for i in model.process_inputs.get((r, p, t, v), set()) + for o in model.process_outputs_by_input.get((r, p, t, v, i), set()) } # 5. Active Storage and Curtailment Indices - model.activeFlowInStorage_rpsditvo = { + model.active_flow_in_storage_rpsditvo = { (r, p, s, d, i, t, v, o) - for r, p, t in model.storageVintages - for v in model.storageVintages[r, p, t] - for i in model.processInputs.get((r, p, t, v), set()) - for o in model.processOutputsByInput.get((r, p, t, v, i), set()) - for s in model.TimeSeason[p] + for r, p, t in model.storage_vintages + for v in model.storage_vintages[r, p, t] + for i in model.process_inputs.get((r, p, t, v), set()) + for o in model.process_outputs_by_input.get((r, p, t, v, i), set()) + for s in model.time_season[p] for d in model.time_of_day } - model.activeCurtailment_rpsditvo = { + model.active_curtailment_rpsditvo = { (r, p, s, d, i, t, v, o) - for r, p, t in model.curtailmentVintages - for v in model.curtailmentVintages[r, p, t] - for i in model.processInputs.get((r, p, t, v), set()) - for o in model.processOutputsByInput.get((r, p, t, v, i), set()) - for s in model.TimeSeason[p] + for r, p, t in model.curtailment_vintages + for v in model.curtailment_vintages[r, p, t] + for i in model.process_inputs.get((r, p, t, v), set()) + for o in model.process_outputs_by_input.get((r, p, t, v, i), set()) + for s in model.time_season[p] for d in model.time_of_day } # 6. Active Technology and Capacity Indices - model.activeActivity_rptv = { - (r, p, t, v) for r, p, t in model.processVintages for v in model.processVintages[r, p, t] + model.active_activity_rptv = { + (r, p, t, v) for r, p, t in model.process_vintages for v in model.process_vintages[r, p, t] } # 7. Storage Level Indices - model.storageLevelIndices_rpsdtv = { + model.storage_level_indices_rpsdtv = { (r, p, s, d, t, v) - for r, p, t in model.storageVintages - for v in model.storageVintages[r, p, t] - for s in model.TimeSeason[p] + for r, p, t in model.storage_vintages + for v in model.storage_vintages[r, p, t] + for s in model.time_season[p] for d in model.time_of_day } - model.seasonalStorageLevelIndices_rpstv = { + model.seasonal_storage_level_indices_rpstv = { (r, p, s_stor, t, v) - for r, p, t in model.storageVintages + for r, p, t in model.storage_vintages if t in model.tech_seasonal_storage - for v in model.storageVintages[r, p, t] + for v in model.storage_vintages[r, p, t] for _p, s_stor in model.sequential_to_season if _p == p } diff --git a/temoa/components/geography.py b/temoa/components/geography.py index 065c7c662..c105e8850 100644 --- a/temoa/components/geography.py +++ b/temoa/components/geography.py @@ -74,7 +74,7 @@ def regional_global_initialized_indices(model: TemoaModel) -> set[Region]: for i in regional_perms: indices.add(cast(Region, '+'.join(i))) indices.add(cast(Region, 'global')) - indices = indices.union(model.regionalIndices) + indices = indices.union(model.regional_indices) return indices @@ -103,7 +103,7 @@ def regional_exchange_capacity_constraint( \forall \{r_e, r_i, t, v\} \in \Theta_{\text{RegionalExchangeCapacity}} """ - expr = model.V_Capacity[r_e + '-' + r_i, p, t, v] == model.V_Capacity[r_i + '-' + r_e, p, t, v] + expr = model.v_capacity[r_e + '-' + r_i, p, t, v] == model.v_capacity[r_i + '-' + r_e, p, t, v] return expr @@ -118,17 +118,17 @@ def create_geography_sets(model: TemoaModel) -> None: Populates dictionaries related to inter-regional commodity exchange. This function iterates through exchange technologies (identified by a '-' in - their region name) and populates the `M.exportRegions` and `M.importRegions` + their region name) and populates the `M.export_regions` and `M.import_regions` dictionaries. These are used later in the commodity balance constraints. Populates: - - M.exportRegions: dict mapping (region_from, p, commodity) to a set + - M.export_regions: dict mapping (region_from, p, commodity) to a set of (region_to, t, v, o) tuples. - - M.importRegions: dict mapping (region_to, p, commodity) to a set + - M.import_regions: dict mapping (region_to, p, commodity) to a set of (region_from, t, v, i) tuples. """ logger.debug('Creating geography-related sets for exchange technologies.') - for r, i, t, v, o in model.Efficiency.sparse_iterkeys(): + for r, i, t, v, o in model.efficiency.sparse_iterkeys(): if t not in model.tech_exchange: continue @@ -141,8 +141,12 @@ def create_geography_sets(model: TemoaModel) -> None: region_from = cast(Region, region_from_str) region_to = cast(Region, region_to_str) - lifetime: float = value(model.LifetimeProcess[r, t, v]) + lifetime: float = value(model.lifetime_process[r, t, v]) for p in model.time_optimize: if p >= v and v + lifetime > p: - model.exportRegions.setdefault((region_from, p, i), set()).add((region_to, t, v, o)) - model.importRegions.setdefault((region_to, p, o), set()).add((region_from, t, v, i)) + model.export_regions.setdefault((region_from, p, i), set()).add( + (region_to, t, v, o) + ) + model.import_regions.setdefault((region_to, p, o), set()).add( + (region_from, t, v, i) + ) diff --git a/temoa/components/limits.py b/temoa/components/limits.py index 97b1a35d4..a7dcae9eb 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -39,19 +39,19 @@ def limit_tech_input_split_constraint_indices( ) -> set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, str]]: indices = { (r, p, s, d, i, t, v, op) - for r, p, i, t, op in model.inputSplitVintages + for r, p, i, t, op in model.input_split_vintages if t not in model.tech_annual - for v in model.inputSplitVintages[r, p, i, t, op] - for s in model.TimeSeason[p] + for v in model.input_split_vintages[r, p, i, t, op] + for s in model.time_season[p] for d in model.time_of_day } ann_indices = { - (r, p, i, t, op) for r, p, i, t, op in model.inputSplitVintages if t in model.tech_annual + (r, p, i, t, op) for r, p, i, t, op in model.input_split_vintages if t in model.tech_annual } if len(ann_indices) > 0: msg = ( - 'Warning: Annual technologies included in LimitTechInputSplit table. ' - 'Use LimitTechInputSplitAnnual table instead or these constraints will be ignored: {}' + 'Warning: Annual technologies included in limit_tech_input_split table. ' + 'Use limit_tech_input_split_annual table instead or these constraints will be ignored: {}' ) logger.warning(msg.format(ann_indices)) @@ -63,9 +63,9 @@ def limit_tech_input_split_annual_constraint_indices( ) -> set[tuple[Region, Period, Commodity, Technology, Vintage, str]]: indices = { (r, p, i, t, v, op) - for r, p, i, t, op in model.inputSplitAnnualVintages + for r, p, i, t, op in model.input_split_annual_vintages if t in model.tech_annual - for v in model.inputSplitAnnualVintages[r, p, i, t, op] + for v in model.input_split_annual_vintages[r, p, i, t, op] } return indices @@ -76,9 +76,9 @@ def limit_tech_input_split_average_constraint_indices( ) -> set[tuple[Region, Period, Commodity, Technology, Vintage, str]]: indices = { (r, p, i, t, v, op) - for r, p, i, t, op in model.inputSplitAnnualVintages + for r, p, i, t, op in model.input_split_annual_vintages if t not in model.tech_annual - for v in model.inputSplitAnnualVintages[r, p, i, t, op] + for v in model.input_split_annual_vintages[r, p, i, t, op] } return indices @@ -88,19 +88,19 @@ def limit_tech_output_split_constraint_indices( ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage, Commodity, str]]: indices = { (r, p, s, d, t, v, o, op) - for r, p, t, o, op in model.outputSplitVintages + for r, p, t, o, op in model.output_split_vintages if t not in model.tech_annual - for v in model.outputSplitVintages[r, p, t, o, op] - for s in model.TimeSeason[p] + for v in model.output_split_vintages[r, p, t, o, op] + for s in model.time_season[p] for d in model.time_of_day } ann_indices = { - (r, p, t, o, op) for r, p, t, o, op in model.outputSplitVintages if t in model.tech_annual + (r, p, t, o, op) for r, p, t, o, op in model.output_split_vintages if t in model.tech_annual } if len(ann_indices) > 0: msg = ( - 'Warning: Annual technologies included in LimitTechOutputSplit table. ' - 'Use LimitTechOutputSplitAnnual table instead or these constraints will be ignored: {}' + 'Warning: Annual technologies included in limit_tech_output_split table. ' + 'Use limit_tech_output_split_annual table instead or these constraints will be ignored: {}' ) logger.warning(msg.format(ann_indices)) @@ -112,9 +112,9 @@ def limit_tech_output_split_annual_constraint_indices( ) -> set[tuple[Region, Period, Technology, Vintage, Commodity, str]]: indices = { (r, p, t, v, o, op) - for r, p, t, o, op in model.outputSplitAnnualVintages + for r, p, t, o, op in model.output_split_annual_vintages if t in model.tech_annual - for v in model.outputSplitAnnualVintages[r, p, t, o, op] + for v in model.output_split_annual_vintages[r, p, t, o, op] } return indices @@ -124,9 +124,9 @@ def limit_tech_output_split_average_constraint_indices( ) -> set[tuple[Region, Period, Technology, Vintage, Commodity, str]]: indices = { (r, p, t, v, o, op) - for r, p, t, o, op in model.outputSplitAnnualVintages + for r, p, t, o, op in model.output_split_annual_vintages if t not in model.tech_annual - for v in model.outputSplitAnnualVintages[r, p, t, o, op] + for v in model.output_split_annual_vintages[r, p, t, o, op] } return indices @@ -134,7 +134,7 @@ def limit_tech_output_split_average_constraint_indices( def limit_growth_capacity_indices(model: TemoaModel) -> set[tuple[Region, Period, Technology, str]]: indices = { (r, p, t, op) - for r, t, op in model.LimitGrowthCapacity.sparse_iterkeys() + for r, t, op in model.limit_growth_capacity.sparse_iterkeys() for p in model.time_optimize } return indices @@ -145,7 +145,7 @@ def limit_degrowth_capacity_indices( ) -> set[tuple[Region, Period, Technology, str]]: indices = { (r, p, t, op) - for r, t, op in model.LimitDegrowthCapacity.sparse_iterkeys() + for r, t, op in model.limit_degrowth_capacity.sparse_iterkeys() for p in model.time_optimize } return indices @@ -156,7 +156,7 @@ def limit_growth_new_capacity_indices( ) -> set[tuple[Region, Period, Technology, str]]: indices = { (r, p, t, op) - for r, t, op in model.LimitGrowthNewCapacity.sparse_iterkeys() + for r, t, op in model.limit_growth_new_capacity.sparse_iterkeys() for p in model.time_optimize } return indices @@ -167,7 +167,7 @@ def limit_degrowth_new_capacity_indices( ) -> set[tuple[Region, Period, Technology, str]]: indices = { (r, p, t, op) - for r, t, op in model.LimitDegrowthNewCapacity.sparse_iterkeys() + for r, t, op in model.limit_degrowth_new_capacity.sparse_iterkeys() for p in model.time_optimize } return indices @@ -178,7 +178,7 @@ def limit_growth_new_capacity_delta_indices( ) -> set[tuple[Region, Period, Technology, str]]: indices = { (r, p, t, op) - for r, t, op in model.LimitGrowthNewCapacityDelta.sparse_iterkeys() + for r, t, op in model.limit_growth_new_capacity_delta.sparse_iterkeys() for p in model.time_optimize } return indices @@ -189,7 +189,7 @@ def limit_degrowth_new_capacity_delta_indices( ) -> set[tuple[Region, Period, Technology, str]]: indices = { (r, p, t, op) - for r, t, op in model.LimitDegrowthNewCapacityDelta.sparse_iterkeys() + for r, t, op in model.limit_degrowth_new_capacity_delta.sparse_iterkeys() for p in model.time_optimize } return indices @@ -200,7 +200,7 @@ def limit_degrowth_new_capacity_delta_indices( # ============================================================================ -# @deprecated('Deprecated. Use LimitActivityGroupShare instead') # doesn't play well with pyomo +# @deprecated('Deprecated. Use limit_activityGroupShare instead') # doesn't play well with pyomo def renewable_portfolio_standard_constraint( model: TemoaModel, r: Region, p: Period, g: str ) -> ExprLike: @@ -210,41 +210,41 @@ def renewable_portfolio_standard_constraint( """ # devnote: this formulation leans on the reserve set, which is not necessarily # the super set we want. We can also generalise this to all groups and so - # it has been deprecated in favour of the LimitActivityGroupShare constraint. + # it has been deprecated in favour of the limit_activityGroupShare constraint. inp = quicksum( - model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + model.v_flow_out[r, p, s, d, S_i, t, v, S_o] for t in model.tech_group_members[g] - for (_t, v) in model.processReservePeriods.get((r, p), []) + for (_t, v) in model.process_reserve_periods.get((r, p), []) if _t == t - for s in model.TimeSeason[p] + for s in model.time_season[p] for d in model.time_of_day - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) total_inp = quicksum( - model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for (t, v) in model.processReservePeriods[r, p] - for s in model.TimeSeason[p] + model.v_flow_out[r, p, s, d, S_i, t, v, S_o] + for (t, v) in model.process_reserve_periods[r, p] + for s in model.time_season[p] for d in model.time_of_day - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) - expr = inp >= (value(model.RenewablePortfolioStandard[r, p, g]) * total_inp) + expr = inp >= (value(model.renewable_portfolio_standard[r, p, g]) * total_inp) return expr def limit_resource_constraint(model: TemoaModel, r: Region, t: Technology, op: str) -> ExprLike: r""" - The LimitResource constraint sets a limit on the available resource of a + The limit_resource constraint sets a limit on the available resource of a given technology across all model time periods. Note that the indices for these constraints are region and tech. .. math:: - :label: LimitResource + :label: limit_resource \sum_{P,S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t \notin T^a, v, o} @@ -252,7 +252,7 @@ def limit_resource_constraint(model: TemoaModel, r: Region, t: Technology, op: s \le LR_{r, t} - \forall \{r, t\} \in \Theta_{\text{LimitResource}}""" + \forall \{r, t\} \in \Theta_{\text{limit_resource}}""" # dev note: this constraint is a misnomer. It is actually a "global activity constraint on a tech" # regardless of whatever "resources" are consumed. # dev note: this would generally be applied to a "dummy import" technology to restrict something like @@ -262,31 +262,31 @@ def limit_resource_constraint(model: TemoaModel, r: Region, t: Technology, op: s techs = technology.gather_group_techs(model, t) activity = quicksum( - model.V_FlowOutAnnual[_r, p, S_i, _t, S_v, S_o] + model.v_flow_out_annual[_r, p, S_i, _t, S_v, S_o] for _t in techs if _t in model.tech_annual for p in model.time_optimize for _r in regions - if (_r, p, _t) in model.processVintages - for S_v in model.processVintages[_r, p, _t] - for S_i in model.processInputs[_r, p, _t, S_v] - for S_o in model.processOutputsByInput[_r, p, _t, S_v, S_i] + if (_r, p, _t) in model.process_vintages + for S_v in model.process_vintages[_r, p, _t] + for S_i in model.process_inputs[_r, p, _t, S_v] + for S_o in model.process_outputs_by_input[_r, p, _t, S_v, S_i] ) activity += quicksum( - model.V_FlowOut[_r, p, s, d, S_i, _t, S_v, S_o] + model.v_flow_out[_r, p, s, d, S_i, _t, S_v, S_o] for _t in techs if _t not in model.tech_annual for p in model.time_optimize for _r in regions - if (_r, p, _t) in model.processVintages - for S_v in model.processVintages[_r, p, _t] - for S_i in model.processInputs[_r, p, _t, S_v] - for S_o in model.processOutputsByInput[_r, p, _t, S_v, S_i] - for s in model.TimeSeason[p] + if (_r, p, _t) in model.process_vintages + for S_v in model.process_vintages[_r, p, _t] + for S_i in model.process_inputs[_r, p, _t, S_v] + for S_o in model.process_outputs_by_input[_r, p, _t, S_v, S_i] + for s in model.time_season[p] for d in model.time_of_day ) - resource_lim = value(model.LimitResource[r, t, op]) + resource_lim = value(model.limit_resource[r, t, op]) expr = operator_expression(activity, Operator(op), resource_lim) return expr @@ -306,56 +306,56 @@ def limit_activity_share_constraint( \leq LAS_{r,p,g_1,g_2} \cdot \sum_{R_g \subseteq R,\ S,\ D,\ I,\ T^{g_2} \subseteq T,\ V,\ O} \mathbf{FO}_{r,p,s,d,i,t,v,o} - \qquad \forall \{r, p, g_1, g_2\} \in \Theta_{\text{LimitActivityShare}} + \qquad \forall \{r, p, g_1, g_2\} \in \Theta_{\text{limit_activity_share}} """ regions = geography.gather_group_regions(model, r) sub_group = technology.gather_group_techs(model, g1) sub_activity = quicksum( - model.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] + model.v_flow_out[_r, p, s, d, S_i, S_t, S_v, S_o] for S_t in sub_group if S_t not in model.tech_annual for _r in regions - for S_v in model.processVintages.get((_r, p, S_t), []) - for S_i in model.processInputs[_r, p, S_t, S_v] - for S_o in model.processOutputsByInput[_r, p, S_t, S_v, S_i] - for s in model.TimeSeason[p] + for S_v in model.process_vintages.get((_r, p, S_t), []) + for S_i in model.process_inputs[_r, p, S_t, S_v] + for S_o in model.process_outputs_by_input[_r, p, S_t, S_v, S_i] + for s in model.time_season[p] for d in model.time_of_day ) sub_activity += quicksum( - model.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] + model.v_flow_out_annual[_r, p, S_i, S_t, S_v, S_o] for S_t in sub_group if S_t in model.tech_annual for _r in regions - for S_v in model.processVintages.get((_r, p, S_t), []) - for S_i in model.processInputs[_r, p, S_t, S_v] - for S_o in model.processOutputsByInput[_r, p, S_t, S_v, S_i] + for S_v in model.process_vintages.get((_r, p, S_t), []) + for S_i in model.process_inputs[_r, p, S_t, S_v] + for S_o in model.process_outputs_by_input[_r, p, S_t, S_v, S_i] ) super_group = technology.gather_group_techs(model, g2) super_activity = quicksum( - model.V_FlowOut[_r, p, s, d, S_i, S_t, S_v, S_o] + model.v_flow_out[_r, p, s, d, S_i, S_t, S_v, S_o] for S_t in super_group if S_t not in model.tech_annual for _r in regions - for S_v in model.processVintages.get((_r, p, S_t), []) - for S_i in model.processInputs[_r, p, S_t, S_v] - for S_o in model.processOutputsByInput[_r, p, S_t, S_v, S_i] - for s in model.TimeSeason[p] + for S_v in model.process_vintages.get((_r, p, S_t), []) + for S_i in model.process_inputs[_r, p, S_t, S_v] + for S_o in model.process_outputs_by_input[_r, p, S_t, S_v, S_i] + for s in model.time_season[p] for d in model.time_of_day ) super_activity += quicksum( - model.V_FlowOutAnnual[_r, p, S_i, S_t, S_v, S_o] + model.v_flow_out_annual[_r, p, S_i, S_t, S_v, S_o] for S_t in super_group if S_t in model.tech_annual for _r in regions - for S_v in model.processVintages.get((_r, p, S_t), []) - for S_i in model.processInputs[_r, p, S_t, S_v] - for S_o in model.processOutputsByInput[_r, p, S_t, S_v, S_i] + for S_v in model.process_vintages.get((_r, p, S_t), []) + for S_i in model.process_inputs[_r, p, S_t, S_v] + for S_o in model.process_outputs_by_input[_r, p, S_t, S_v, S_i] ) - share_lim = value(model.LimitActivityShare[r, p, g1, g2, op]) + share_lim = value(model.limit_activity_share[r, p, g1, g2, op]) expr = operator_expression(sub_activity, Operator(op), share_lim * super_activity) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated @@ -375,7 +375,7 @@ def limit_capacity_share_constraint( model: TemoaModel, r: Region, p: Period, g1: Technology, g2: Technology, op: str ) -> ExprLike: r""" - The LimitCapacityShare constraint limits the available capacity of a given + The limit_capacity_share constraint limits the available capacity of a given technology or technology group as a fraction of another technology or group. """ @@ -383,20 +383,20 @@ def limit_capacity_share_constraint( sub_group = technology.gather_group_techs(model, g1) sub_capacity = quicksum( - model.V_CapacityAvailableByPeriodAndTech[_r, p, _t] + model.v_capacity_available_by_period_and_tech[_r, p, _t] for _t in sub_group for _r in regions - if (_r, p, _t) in model.processVintages + if (_r, p, _t) in model.process_vintages ) super_group = technology.gather_group_techs(model, g2) super_capacity = quicksum( - model.V_CapacityAvailableByPeriodAndTech[_r, p, _t] + model.v_capacity_available_by_period_and_tech[_r, p, _t] for _t in super_group for _r in regions - if (_r, p, _t) in model.processVintages + if (_r, p, _t) in model.process_vintages ) - share_lim = value(model.LimitCapacityShare[r, p, g1, g2, op]) + share_lim = value(model.limit_capacity_share[r, p, g1, g2, op]) expr = operator_expression(sub_capacity, Operator(op), share_lim * super_capacity) if isinstance(expr, bool): @@ -408,7 +408,7 @@ def limit_new_capacity_share_constraint( model: TemoaModel, r: Region, p: Period, g1: Technology, g2: Technology, op: str ) -> ExprLike: r""" - The LimitNewCapacityShare constraint limits the share of new capacity + The limit_new_capacity_share constraint limits the share of new capacity of a given technology or group as a fraction of another technology or group.""" @@ -416,21 +416,21 @@ def limit_new_capacity_share_constraint( sub_group = technology.gather_group_techs(model, g1) sub_new_cap = quicksum( - model.V_NewCapacity[_r, _t, p] + model.v_new_capacity[_r, _t, p] for _t in sub_group for _r in regions - if (_r, _t, cast(Vintage, p)) in model.processPeriods + if (_r, _t, cast(Vintage, p)) in model.process_periods ) super_group = technology.gather_group_techs(model, g2) super_new_cap = quicksum( - model.V_NewCapacity[_r, _t, p] + model.v_new_capacity[_r, _t, p] for _t in super_group for _r in regions - if (_r, _t, cast(Vintage, p)) in model.processPeriods + if (_r, _t, cast(Vintage, p)) in model.process_periods ) - share_lim = value(model.LimitNewCapacityShare[r, p, g1, g2, op]) + share_lim = value(model.limit_new_capacity_share[r, p, g1, g2, op]) expr = operator_expression(sub_new_cap, Operator(op), share_lim * super_new_cap) if isinstance(expr, bool): return Constraint.Skip @@ -441,53 +441,54 @@ def limit_annual_capacity_factor_constraint( model: TemoaModel, r: Region, p: Period, t: Technology, o: Commodity, op: str ) -> ExprLike: r""" - The LimitAnnualCapacityFactor sets an upper bound on the annual capacity factor + The limit_annual_capacity_factor 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: LimitAnnualCapacityFactor + :label: limit_annual_capacity_factor \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMACF_{r, p, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} - \forall \{r, p, t \notin T^{a}, o\} \in \Theta_{\text{LimitAnnualCapacityFactor}} + \forall \{r, p, t \notin T^{a}, o\} \in \Theta_{\text{limit_annual_capacity_factor}} \\\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \ge LIMACF_{r, p, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} - \forall \{r, p, t \in T^{a}, o\} \in \Theta_{\text{LimitAnnualCapacityFactor}} + \forall \{r, p, t \in T^{a}, o\} \in \Theta_{\text{limit_annual_capacity_factor}} """ # r can be an individual region (r='US'), or a combination of regions separated by plus (r='Mexico+US+Canada'), or 'global'. # if r == 'global', the constraint is system-wide regions = geography.gather_group_regions(model, r) # we need to screen here because it is possible that the restriction extends beyond the # lifetime of any vintage of the tech... - if all((_r, p, t) not in model.V_CapacityAvailableByPeriodAndTech for _r in regions): + if all((_r, p, t) not in model.v_capacity_available_by_period_and_tech for _r in regions): return Constraint.Skip if t not in model.tech_annual: activity_rpt = quicksum( - model.V_FlowOut[_r, p, s, d, S_i, t, S_v, o] + model.v_flow_out[_r, p, s, d, S_i, t, S_v, o] for _r in regions - for S_v in model.processVintages.get((_r, p, t), []) - for S_i in model.processInputs[_r, p, t, S_v] - for s in model.TimeSeason[p] + for S_v in model.process_vintages.get((_r, p, t), []) + for S_i in model.process_inputs[_r, p, t, S_v] + for s in model.time_season[p] for d in model.time_of_day ) else: activity_rpt = quicksum( - model.V_FlowOutAnnual[_r, p, S_i, t, S_v, o] + model.v_flow_out_annual[_r, p, S_i, t, S_v, o] for _r in regions - for S_v in model.processVintages.get((_r, p, t), []) - for S_i in model.processInputs[_r, p, t, S_v] + for S_v in model.process_vintages.get((_r, p, t), []) + for S_i in model.process_inputs[_r, p, t, S_v] ) possible_activity_rpt = quicksum( - model.V_CapacityAvailableByPeriodAndTech[_r, p, t] * value(model.CapacityToActivity[_r, t]) + model.v_capacity_available_by_period_and_tech[_r, p, t] + * value(model.capacity_to_activity[_r, t]) for _r in regions ) - annual_cf = value(model.LimitAnnualCapacityFactor[r, p, t, o, op]) + annual_cf = value(model.limit_annual_capacity_factor[r, p, t, o, op]) expr = operator_expression(activity_rpt, Operator(op), annual_cf * possible_activity_rpt) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated @@ -499,7 +500,7 @@ def limit_seasonal_capacity_factor_constraint( model: TemoaModel, r: Region, p: Period, s: Season, t: Technology, op: str ) -> ExprLike: r""" - The LimitSeasonalCapacityFactor sets an upper bound on the seasonal capacity factor + The limit_seasonal_capacity_factor sets an upper bound on the seasonal 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 @@ -510,45 +511,46 @@ def limit_seasonal_capacity_factor_constraint( \sum_{D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMSCF_{r, p, s, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} - \forall \{r, p, t \notin T^{a}, o\} \in \Theta_{\text{LimitSeasonalCapacityFactor}} + \forall \{r, p, t \notin T^{a}, o\} \in \Theta_{\text{limit_seasonal_capacity_factor}} \\\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \cdot \sum_{D} SEG_{s,d} \le LIMSCF_{r, p, s, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} - \forall \{r, p, t \in T^{a}, o\} \in \Theta_{\text{LimitSeasonalCapacityFactor}} + \forall \{r, p, t \in T^{a}, o\} \in \Theta_{\text{limit_seasonal_capacity_factor}} """ # r can be an individual region (r='US'), or a combination of regions separated by plus (r='Mexico+US+Canada'), or 'global'. # if r == 'global', the constraint is system-wide regions = geography.gather_group_regions(model, r) # we need to screen here because it is possible that the restriction extends beyond the # lifetime of any vintage of the tech... - if all((_r, p, t) not in model.V_CapacityAvailableByPeriodAndTech for _r in regions): + if all((_r, p, t) not in model.v_capacity_available_by_period_and_tech for _r in regions): return Constraint.Skip if t not in model.tech_annual: activity_rpst = quicksum( - model.V_FlowOut[_r, p, s, d, S_i, t, S_v, S_o] + model.v_flow_out[_r, p, s, d, S_i, t, S_v, S_o] for _r in regions - for S_v in model.processVintages[_r, p, t] - for S_i in model.processInputs[_r, p, t, S_v] - for S_o in model.processOutputsByInput[_r, p, t, S_v, S_i] + for S_v in model.process_vintages[_r, p, t] + for S_i in model.process_inputs[_r, p, t, S_v] + for S_o in model.process_outputs_by_input[_r, p, t, S_v, S_i] for d in model.time_of_day ) else: activity_rpst = quicksum( - model.V_FlowOutAnnual[_r, p, S_i, t, S_v, S_o] * model.SegFracPerSeason[p, s] + model.v_flow_out_annual[_r, p, S_i, t, S_v, S_o] + * model.segment_fraction_per_season[p, s] for _r in regions - for S_v in model.processVintages[_r, p, t] - for S_i in model.processInputs[_r, p, t, S_v] - for S_o in model.processOutputsByInput[_r, p, t, S_v, S_i] + for S_v in model.process_vintages[_r, p, t] + for S_i in model.process_inputs[_r, p, t, S_v] + for S_o in model.process_outputs_by_input[_r, p, t, S_v, S_i] ) possible_activity_rpst = quicksum( - model.V_CapacityAvailableByPeriodAndTech[_r, p, t] - * value(model.CapacityToActivity[_r, t]) - * value(model.SegFracPerSeason[p, s]) + model.v_capacity_available_by_period_and_tech[_r, p, t] + * value(model.capacity_to_activity[_r, t]) + * value(model.segment_fraction_per_season[p, s]) for _r in regions ) - seasonal_cf = value(model.LimitSeasonalCapacityFactor[r, p, s, t, op]) + seasonal_cf = value(model.limit_seasonal_capacity_factor[r, p, s, t, op]) expr = operator_expression(activity_rpst, Operator(op), seasonal_cf * possible_activity_rpst) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated @@ -570,24 +572,24 @@ def limit_tech_input_split_constraint( r""" Allows users to limit shares of commodity inputs to a process producing a single output. These shares can vary by model time period. See - LimitTechOutputSplit_Constraint for an analogous explanation. Under this constraint, + limit_tech_output_split_Constraint for an analogous explanation. Under this constraint, only the technologies with variable output at the timeslice level (i.e., NOT in the :code:`tech_annual` set) are considered.""" inp = quicksum( - model.V_FlowOut[r, p, s, d, i, t, v, S_o] + model.v_flow_out[r, p, s, d, i, t, v, S_o] / get_variable_efficiency(model, r, p, s, d, i, t, v, S_o) - for S_o in model.processOutputsByInput[r, p, t, v, i] + for S_o in model.process_outputs_by_input[r, p, t, v, i] ) total_inp = quicksum( - model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] + model.v_flow_out[r, p, s, d, S_i, t, v, S_o] / get_variable_efficiency(model, r, p, s, d, S_i, t, v, S_o) - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) expr = operator_expression( - inp, Operator(op), value(model.LimitTechInputSplit[r, p, i, t, op]) * total_inp + inp, Operator(op), value(model.limit_tech_input_split[r, p, i, t, op]) * total_inp ) return expr @@ -598,22 +600,22 @@ def limit_tech_input_split_annual_constraint( r""" Allows users to limit shares of commodity inputs to a process producing a single output. These shares can vary by model time period. See - LimitTechOutputSplitAnnual_Constraint for an analogous explanation. Under this + limit_tech_output_split_annual_Constraint for an analogous explanation. Under this function, only the technologies with constant annual output (i.e., members of the :code:`tech_annual` set) are considered.""" inp = quicksum( - model.V_FlowOutAnnual[r, p, i, t, v, S_o] / value(model.Efficiency[r, i, t, v, S_o]) - for S_o in model.processOutputsByInput[r, p, t, v, i] + model.v_flow_out_annual[r, p, i, t, v, S_o] / value(model.efficiency[r, i, t, v, S_o]) + for S_o in model.process_outputs_by_input[r, p, t, v, i] ) total_inp = quicksum( - model.V_FlowOutAnnual[r, p, S_i, t, v, S_o] / value(model.Efficiency[r, S_i, t, v, S_o]) - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + model.v_flow_out_annual[r, p, S_i, t, v, S_o] / value(model.efficiency[r, S_i, t, v, S_o]) + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) expr = operator_expression( - inp, Operator(op), value(model.LimitTechInputSplitAnnual[r, p, i, t, op]) * total_inp + inp, Operator(op), value(model.limit_tech_input_split_annual[r, p, i, t, op]) * total_inp ) return expr @@ -625,28 +627,28 @@ def limit_tech_input_split_average_constraint( Allows users to limit shares of commodity inputs to a process 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 LimitTechInputSplit as it specifies shares on an annual basis, + This constraint differs from limit_tech_input_split 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.""" inp = quicksum( - model.V_FlowOut[r, p, S_s, S_d, i, t, v, S_o] + model.v_flow_out[r, p, S_s, S_d, i, t, v, S_o] / get_variable_efficiency(model, r, p, S_s, S_d, i, t, v, S_o) - for S_s in model.TimeSeason[p] + for S_s in model.time_season[p] for S_d in model.time_of_day - for S_o in model.processOutputsByInput[r, p, t, v, i] + for S_o in model.process_outputs_by_input[r, p, t, v, i] ) total_inp = quicksum( - model.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] + model.v_flow_out[r, p, S_s, S_d, S_i, t, v, S_o] / get_variable_efficiency(model, r, p, S_s, S_d, S_i, t, v, S_o) - for S_s in model.TimeSeason[p] + for S_s in model.time_season[p] for S_d in model.time_of_day - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) expr = operator_expression( - inp, Operator(op), value(model.LimitTechInputSplitAnnual[r, p, i, t, op]) * total_inp + inp, Operator(op), value(model.limit_tech_input_split_annual[r, p, i, t, op]) * total_inp ) return expr @@ -689,26 +691,26 @@ def limit_tech_output_split_constraint( The constraint is formulated as follows: .. math:: - :label: LimitTechOutputSplit + :label: limit_tech_output_split \sum_{I, t \not \in T^{a}} \textbf{FO}_{r, p, s, d, i, t, v, o} \geq TOS_{r, p, t, o} \cdot \sum_{I, O, t \not \in T^{a}} \textbf{FO}_{r, p, s, d, i, t, v, o} - \forall \{r, p, s, d, t, v, o\} \in \Theta_{\text{LimitTechOutputSplit}}""" + \forall \{r, p, s, d, t, v, o\} \in \Theta_{\text{limit_tech_output_split}}""" out = quicksum( - model.V_FlowOut[r, p, s, d, S_i, t, v, o] - for S_i in model.processInputsByOutput[r, p, t, v, o] + model.v_flow_out[r, p, s, d, S_i, t, v, o] + for S_i in model.process_inputs_by_output[r, p, t, v, o] ) total_out = quicksum( - model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + model.v_flow_out[r, p, s, d, S_i, t, v, S_o] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) expr = operator_expression( - out, Operator(op), value(model.LimitTechOutputSplit[r, p, t, o, op]) * total_out + out, Operator(op), value(model.limit_tech_output_split[r, p, t, o, op]) * total_out ) return expr @@ -717,31 +719,31 @@ def limit_tech_output_split_annual_constraint( model: TemoaModel, r: Region, p: Period, t: Technology, v: Vintage, o: Commodity, op: str ) -> ExprLike: r""" - This constraint operates similarly to LimitTechOutputSplit_Constraint. + This constraint operates similarly to limit_tech_output_split_Constraint. However, under this function, only the technologies with constant annual output (i.e., members of the :code:`tech_annual` set) are considered. .. math:: - :label: LimitTechOutputSplitAnnual + :label: limit_tech_output_split_annual \sum_{I, T^{a}} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} \geq TOS_{r, p, t, o} \cdot \sum_{I, O, T^{a}} \textbf{FOA}_{r, p, s, d, i, t \in T^{a}, v, o} - \forall \{r, p, t \in T^{a}, v, o\} \in \Theta_{\text{LimitTechOutputSplitAnnual}}""" + \forall \{r, p, t \in T^{a}, v, o\} \in \Theta_{\text{limit_tech_output_split_annual}}""" out = quicksum( - model.V_FlowOutAnnual[r, p, S_i, t, v, o] - for S_i in model.processInputsByOutput[r, p, t, v, o] + model.v_flow_out_annual[r, p, S_i, t, v, o] + for S_i in model.process_inputs_by_output[r, p, t, v, o] ) total_out = quicksum( - model.V_FlowOutAnnual[r, p, S_i, t, v, S_o] - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + model.v_flow_out_annual[r, p, S_i, t, v, S_o] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) expr = operator_expression( - out, Operator(op), value(model.LimitTechOutputSplitAnnual[r, p, t, o, op]) * total_out + out, Operator(op), value(model.limit_tech_output_split_annual[r, p, t, o, op]) * total_out ) return expr @@ -753,27 +755,27 @@ def limit_tech_output_split_average_constraint( Allows users to limit shares of commodity outputs from a process. 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 LimitTechOutputSplit as it specifies shares on an annual basis, + This constraint differs from limit_tech_output_split 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 output shares over the course of a year.""" out = quicksum( - model.V_FlowOut[r, p, S_s, S_d, S_i, t, v, o] - for S_i in model.processInputsByOutput[r, p, t, v, o] - for S_s in model.TimeSeason[p] + model.v_flow_out[r, p, S_s, S_d, S_i, t, v, o] + for S_i in model.process_inputs_by_output[r, p, t, v, o] + for S_s in model.time_season[p] for S_d in model.time_of_day ) total_out = quicksum( - model.V_FlowOut[r, p, S_s, S_d, S_i, t, v, S_o] - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] - for S_s in model.TimeSeason[p] + model.v_flow_out[r, p, S_s, S_d, S_i, t, v, S_o] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] + for S_s in model.time_season[p] for S_d in model.time_of_day ) expr = operator_expression( - out, Operator(op), value(model.LimitTechOutputSplitAnnual[r, p, t, o, op]) * total_out + out, Operator(op), value(model.limit_tech_output_split_annual[r, p, t, o, op]) * total_out ) return expr @@ -784,15 +786,15 @@ def limit_emission_constraint( r""" A modeler can track emissions through use of the :code:`commodity_emissions` - set and :code:`EmissionActivity` parameter. The :math:`EAC` parameter is + set and :code:`emission_activity` parameter. The :math:`EAC` parameter is analogous to the efficiency table, tying emissions to a unit of activity. The - LimitEmission constraint allows the modeler to assign an upper bound per period + limit_emission constraint allows the modeler to assign an upper bound per period to each emission commodity. Note that this constraint sums emissions from technologies with output varying at the time slice and those with constant annual output in separate terms. .. math:: - :label: LimitEmission + :label: limit_emission \sum_{S,D,I,T,V,O|{r,e,i,t,v,o} \in EAC} \left ( EAC_{r, e, i, t, v, o} \cdot \textbf{FO}_{r, p, s, d, i, t, v, o} @@ -805,10 +807,10 @@ def limit_emission_constraint( ELM_{r, p, e} \\ - & \forall \{r, p, e\} \in \Theta_{\text{LimitEmission}} + & \forall \{r, p, e\} \in \Theta_{\text{limit_emission}} """ - emission_limit = value(model.LimitEmission[r, p, e, op]) + emission_limit = value(model.limit_emission[r, p, e, op]) # 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 @@ -819,45 +821,45 @@ def limit_emission_constraint( regions = geography.gather_group_regions(model, r) # ================= Emissions and Flex and Curtailment ================= - # Flex flows are deducted from V_FlowOut, so it is NOT NEEDED to tax them again. (See commodity balance constr) + # Flex flows are deducted from v_flow_out, so it is NOT NEEDED to tax them again. (See commodity balance constr) # Curtailment does not draw any inputs, so it seems logical that curtailed flows not be taxed either process_emissions = quicksum( - model.V_FlowOut[reg, p, S_s, S_d, S_i, S_t, S_v, S_o] - * value(model.EmissionActivity[reg, e, S_i, S_t, S_v, S_o]) + model.v_flow_out[reg, p, S_s, S_d, S_i, S_t, S_v, S_o] + * value(model.emission_activity[reg, e, S_i, S_t, S_v, S_o]) for reg in regions - for tmp_r, tmp_e, S_i, S_t, S_v, S_o in model.EmissionActivity.sparse_iterkeys() + for tmp_r, tmp_e, S_i, S_t, S_v, S_o in model.emission_activity.sparse_iterkeys() if tmp_e == e and tmp_r == reg and S_t not in model.tech_annual # EmissionsActivity not indexed by p, so make sure (r,p,t,v) combos valid - if (reg, p, S_t, S_v) in model.processInputs - for S_s in model.TimeSeason[p] + if (reg, p, S_t, S_v) in model.process_inputs + for S_s in model.time_season[p] for S_d in model.time_of_day ) process_emissions_annual = quicksum( - model.V_FlowOutAnnual[reg, p, S_i, S_t, S_v, S_o] - * value(model.EmissionActivity[reg, e, S_i, S_t, S_v, S_o]) + model.v_flow_out_annual[reg, p, S_i, S_t, S_v, S_o] + * value(model.emission_activity[reg, e, S_i, S_t, S_v, S_o]) for reg in regions - for tmp_r, tmp_e, S_i, S_t, S_v, S_o in model.EmissionActivity.sparse_iterkeys() + for tmp_r, tmp_e, S_i, S_t, S_v, S_o in model.emission_activity.sparse_iterkeys() if tmp_e == e and tmp_r == reg and S_t in model.tech_annual # EmissionsActivity not indexed by p, so make sure (r,p,t,v) combos valid - if (reg, p, S_t, S_v) in model.processInputs + if (reg, p, S_t, S_v) in model.process_inputs ) embodied_emissions = quicksum( - model.V_NewCapacity[reg, t, v] - * value(model.EmissionEmbodied[reg, e, t, v]) - / value(model.PeriodLength[v]) + model.v_new_capacity[reg, t, v] + * value(model.emission_embodied[reg, e, t, v]) + / value(model.period_length[v]) for reg in regions - for (S_r, S_e, t, v) in model.EmissionEmbodied.sparse_iterkeys() + for (S_r, S_e, t, v) in model.emission_embodied.sparse_iterkeys() if v == p and S_r == reg and S_e == e ) retirement_emissions = quicksum( - model.V_AnnualRetirement[reg, p, t, v] * value(model.EmissionEndOfLife[reg, e, t, v]) + model.v_annual_retirement[reg, p, t, v] * value(model.emission_end_of_life[reg, e, t, v]) for reg in regions - for (S_r, S_e, t, v) in model.EmissionEndOfLife.sparse_iterkeys() - if (reg, t, v) in model.retirementPeriods and p in model.retirementPeriods[reg, t, v] + for (S_r, S_e, t, v) in model.emission_end_of_life.sparse_iterkeys() + if (reg, t, v) in model.retirement_periods and p in model.retirement_periods[reg, t, v] if S_r == reg and S_e == e ) @@ -914,7 +916,7 @@ def limit_growth_capacity( \leq S_{r,t} + (1+R_{r,t}) \cdot \mathbf{CAPAVL}_{r,p_{prev},t} \end{aligned} - \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitGrowthCapacity}} + \qquad \forall \{r, p, t\} \in \Theta_{\text{limit_growth_capacity}} \begin{aligned}\text{Degrowth:}\\ @@ -922,16 +924,16 @@ def limit_growth_capacity( \leq S_{r,t} + (1+R_{r,t}) \cdot \mathbf{CAPAVL}_{r,p,t} \end{aligned} - \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitDegrowthCapacity}} + \qquad \forall \{r, p, t\} \in \Theta_{\text{limit_degrowth_capacity}} """ regions = geography.gather_group_regions(model, r) techs = technology.gather_group_techs(model, t) - growth = model.LimitDegrowthCapacity if degrowth else model.LimitGrowthCapacity + growth = model.limit_degrowth_capacity if degrowth else model.limit_growth_capacity rate = 1 + value(growth[r, t, op][0]) seed = value(growth[r, t, op][1]) - cap_rpt = model.V_CapacityAvailableByPeriodAndTech + cap_rpt = model.v_capacity_available_by_period_and_tech # relevant r, p, t indices cap_indices = {(_r, _p, _t) for _r, _p, _t in cap_rpt.keys() if _t in techs and _r in regions} @@ -976,12 +978,12 @@ def limit_growth_capacity( # Adjust in-line for past PLF because we are constraining available capacity p_prev = model.time_exist.last() capacity_prev = sum( - value(model.ExistingCapacity[_r, _t, _v]) - * min(1.0, (_v + value(model.LifetimeProcess[_r, _t, _v]) - p_prev) / (p - p_prev)) - for _r, _t, _v in model.ExistingCapacity.sparse_iterkeys() + value(model.existing_capacity[_r, _t, _v]) + * min(1.0, (_v + value(model.lifetime_process[_r, _t, _v]) - p_prev) / (p - p_prev)) + for _r, _t, _v in model.existing_capacity.sparse_iterkeys() if _r in regions and _t in techs - and _v + value(model.LifetimeProcess[_r, _t, _v]) > p_prev + and _v + value(model.lifetime_process[_r, _t, _v]) > p_prev ) else: # Otherwise, grab previous future period @@ -1035,7 +1037,7 @@ def limit_growth_new_capacity( \text{ where } v=p \end{aligned} - \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitGrowthCapacity}} + \qquad \forall \{r, p, t\} \in \Theta_{\text{limit_growth_capacity}} \begin{aligned}\text{Degrowth:}\\ &\mathbf{NCAP}_{r,t,v_{prev}} @@ -1043,16 +1045,16 @@ def limit_growth_new_capacity( \text{ where } v=p \end{aligned} - \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitDegrowthCapacity}} + \qquad \forall \{r, p, t\} \in \Theta_{\text{limit_degrowth_capacity}} """ regions = geography.gather_group_regions(model, r) techs = technology.gather_group_techs(model, t) - growth = model.LimitDegrowthNewCapacity if degrowth else model.LimitGrowthNewCapacity + growth = model.limit_degrowth_new_capacity if degrowth else model.limit_growth_new_capacity rate = 1 + value(growth[r, t, op][0]) seed = value(growth[r, t, op][1]) - new_cap_rtv = model.V_NewCapacity + new_cap_rtv = model.v_new_capacity # relevant r, t, v indices cap_rtv = {(_r, _t, _v) for _r, _t, _v in new_cap_rtv.keys() if _t in techs and _r in regions} @@ -1096,8 +1098,8 @@ def limit_growth_new_capacity( # First future period. Grab last existing vintage p_prev = model.time_exist.last() new_cap_prev = sum( - value(model.ExistingCapacity[_r, _t, _v]) - for _r, _t, _v in model.ExistingCapacity.sparse_iterkeys() + value(model.existing_capacity[_r, _t, _v]) + for _r, _t, _v in model.existing_capacity.sparse_iterkeys() if _r in regions and _t in techs and _v == p_prev ) else: @@ -1154,7 +1156,7 @@ def limit_growth_new_capacity_delta( \text{ where } v_i=p - \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitGrowthCapacityDelta}} + \qquad \forall \{r, p, t\} \in \Theta_{\text{limit_growth_capacityDelta}} \begin{aligned}\text{Degrowth:}\\ &\mathbf{NCAP}_{r,t,v_{i-1}} - \mathbf{NCAP}_{r,t,v_{i-2}} @@ -1163,16 +1165,20 @@ def limit_growth_new_capacity_delta( \text{ where } v_i=p - \qquad \forall \{r, p, t\} \in \Theta_{\text{LimitDegrowthCapacityDelta}} + \qquad \forall \{r, p, t\} \in \Theta_{\text{limit_degrowth_capacityDelta}} """ regions = geography.gather_group_regions(model, r) techs = technology.gather_group_techs(model, t) - growth = model.LimitDegrowthNewCapacityDelta if degrowth else model.LimitGrowthNewCapacityDelta + growth = ( + model.limit_degrowth_new_capacity_delta + if degrowth + else model.limit_growth_new_capacity_delta + ) rate = 1 + value(growth[r, t, op][0]) seed = value(growth[r, t, op][1]) - new_cap_rtv = model.V_NewCapacity + new_cap_rtv = model.v_new_capacity # relevant r, t, v indices cap_rtv = {(_r, _t, _v) for _r, _t, _v in new_cap_rtv.keys() if _t in techs and _r in regions} @@ -1217,14 +1223,14 @@ def limit_growth_new_capacity_delta( # First planning period, pull last two existing vintages p_prev = model.time_exist.last() new_cap_prev = sum( - value(model.ExistingCapacity[_r, _t, _v]) - for _r, _t, _v in model.ExistingCapacity.sparse_iterkeys() + value(model.existing_capacity[_r, _t, _v]) + for _r, _t, _v in model.existing_capacity.sparse_iterkeys() if _r in regions and _t in techs and _v == p_prev ) p_prev2 = model.time_exist.prev(p_prev) new_cap_prev2 = sum( - value(model.ExistingCapacity[_r, _t, _v]) - for _r, _t, _v in model.ExistingCapacity.sparse_iterkeys() + value(model.existing_capacity[_r, _t, _v]) + for _r, _t, _v in model.existing_capacity.sparse_iterkeys() if _r in regions and _t in techs and _v == p_prev2 ) else: @@ -1235,8 +1241,8 @@ def limit_growth_new_capacity_delta( # Second future period, grab last existing vintage p_prev2 = model.time_exist.last() new_cap_prev2 = sum( - value(model.ExistingCapacity[_r, _t, _v]) - for _r, _t, _v in model.ExistingCapacity.sparse_iterkeys() + value(model.existing_capacity[_r, _t, _v]) + for _r, _t, _v in model.existing_capacity.sparse_iterkeys() if _r in regions and _t in techs and _v == p_prev2 ) else: @@ -1271,15 +1277,15 @@ def limit_activity_constraint( set. .. math:: - :label: LimitActivity + :label: limit_activity \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} - \forall \{r, p, t \notin T^{a}\} \in \Theta_{\text{LimitActivity}} + \forall \{r, p, t \notin T^{a}\} \in \Theta_{\text{limit_activity}} +\sum_{I,V,O} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} - \forall \{r, p, t \in T^{a}\} \in \Theta_{\text{LimitActivity}} + \forall \{r, p, t \in T^{a}\} \in \Theta_{\text{limit_activity}} \le LA_{r, p, t} """ @@ -1290,27 +1296,27 @@ def limit_activity_constraint( techs = technology.gather_group_techs(model, t) activity = quicksum( - model.V_FlowOut[_r, p, s, d, S_i, _t, S_v, S_o] + model.v_flow_out[_r, p, s, d, S_i, _t, S_v, S_o] for _t in techs if _t not in model.tech_annual for _r in regions - for S_v in model.processVintages.get((_r, p, _t), []) - for S_i in model.processInputs[_r, p, _t, S_v] - for S_o in model.processOutputsByInput[_r, p, _t, S_v, S_i] - for s in model.TimeSeason[p] + for S_v in model.process_vintages.get((_r, p, _t), []) + for S_i in model.process_inputs[_r, p, _t, S_v] + for S_o in model.process_outputs_by_input[_r, p, _t, S_v, S_i] + for s in model.time_season[p] for d in model.time_of_day ) activity += quicksum( - model.V_FlowOutAnnual[_r, p, S_i, _t, S_v, S_o] + model.v_flow_out_annual[_r, p, S_i, _t, S_v, S_o] for _t in techs if _t in model.tech_annual for _r in regions - for S_v in model.processVintages.get((_r, p, _t), []) - for S_i in model.processInputs[_r, p, _t, S_v] - for S_o in model.processOutputsByInput[_r, p, _t, S_v, S_i] + for S_v in model.process_vintages.get((_r, p, _t), []) + for S_i in model.process_inputs[_r, p, _t, S_v] + for S_o in model.process_outputs_by_input[_r, p, _t, S_v, S_i] ) - act_lim = value(model.LimitActivity[r, p, t, op]) + act_lim = value(model.limit_activity[r, p, t, op]) expr = operator_expression(activity, Operator(op), act_lim) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated @@ -1322,12 +1328,12 @@ def limit_new_capacity_constraint( model: TemoaModel, r: Region, p: Period, t: Technology, op: str ) -> ExprLike: r""" - The LimitNewCapacity constraint sets a limit on the newly installed capacity of a + The limit_new_capacity constraint sets a limit on the newly installed capacity of a given technology or group in a given year. Note that the indices for these constraints are region, period and tech. .. math:: - :label: LimitNewCapacity + :label: limit_new_capacity \textbf{NCAP}_{r, t, v} \le LNC_{r, p, t} @@ -1335,8 +1341,8 @@ def limit_new_capacity_constraint( """ regions = geography.gather_group_regions(model, r) techs = technology.gather_group_techs(model, t) - cap_lim = value(model.LimitNewCapacity[r, p, t, op]) - new_cap = quicksum(model.V_NewCapacity[_r, _t, p] for _t in techs for _r in regions) + cap_lim = value(model.limit_new_capacity[r, p, t, op]) + new_cap = quicksum(model.v_new_capacity[_r, _t, p] for _t in techs for _r in regions) expr = operator_expression(new_cap, Operator(op), cap_lim) return expr @@ -1346,21 +1352,21 @@ def limit_capacity_constraint( ) -> ExprLike: r""" - The LimitCapacity constraint sets a limit on the available capacity of a + The limit_capacity constraint sets a limit on the available capacity of a given technology. Note that the indices for these constraints are region, period and tech, not tech and vintage. .. math:: - :label: LimitCapacity + :label: limit_capacity \textbf{CAPAVL}_{r, p, t} \le LC_{r, p, t} - \forall \{r, p, t\} \in \Theta_{\text{LimitCapacity}}""" + \forall \{r, p, t\} \in \Theta_{\text{limit_capacity}}""" regions = geography.gather_group_regions(model, r) techs = technology.gather_group_techs(model, t) - cap_lim = value(model.LimitCapacity[r, p, t, op]) + cap_lim = value(model.limit_capacity[r, p, t, op]) capacity = quicksum( - model.V_CapacityAvailableByPeriodAndTech[_r, p, _t] for _t in techs for _r in regions + model.v_capacity_available_by_period_and_tech[_r, p, _t] for _t in techs for _r in regions ) expr = operator_expression(capacity, Operator(op), cap_lim) return expr @@ -1380,25 +1386,27 @@ def create_limit_vintage_sets(model: TemoaModel) -> None: the index set functions below. Populates: - - M.inputSplitVintages: dict mapping (r, p, i, t, op) to a set of vintages `v`. - - M.inputSplitAnnualVintages: dict for annual-specific input splits. - - M.outputSplitVintages: dict mapping (r, p, t, o, op) to a set of vintages `v`. - - M.outputSplitAnnualVintages: dict for annual-specific output splits. + - M.input_split_vintages: dict mapping (r, p, i, t, op) to a set of vintages `v`. + - M.input_split_annual_vintages: dict for annual-specific input splits. + - M.output_split_vintages: dict mapping (r, p, t, o, op) to a set of vintages `v`. + - M.output_split_annual_vintages: dict for annual-specific output splits. """ logger.debug('Creating vintage sets for split limits.') - # Assuming M.processVintages is already populated - for r, p, t in model.processVintages: - for v in model.processVintages[r, p, t]: - for i in model.processInputs.get((r, p, t, v), []): + # Assuming M.process_vintages is already populated + for r, p, t in model.process_vintages: + for v in model.process_vintages[r, p, t]: + for i in model.process_inputs.get((r, p, t, v), []): for op in model.operator: - if (r, p, i, t, op) in model.LimitTechInputSplit: - model.inputSplitVintages.setdefault((r, p, i, t, op), set()).add(v) - if (r, p, i, t, op) in model.LimitTechInputSplitAnnual: - model.inputSplitAnnualVintages.setdefault((r, p, i, t, op), set()).add(v) + if (r, p, i, t, op) in model.limit_tech_input_split: + model.input_split_vintages.setdefault((r, p, i, t, op), set()).add(v) + if (r, p, i, t, op) in model.limit_tech_input_split_annual: + model.input_split_annual_vintages.setdefault((r, p, i, t, op), set()).add(v) - for o in model.processOutputs.get((r, p, t, v), []): + for o in model.process_outputs.get((r, p, t, v), []): for op in model.operator: - if (r, p, t, o, op) in model.LimitTechOutputSplit: - model.outputSplitVintages.setdefault((r, p, t, o, op), set()).add(v) - if (r, p, t, o, op) in model.LimitTechOutputSplitAnnual: - model.outputSplitAnnualVintages.setdefault((r, p, t, o, op), set()).add(v) + if (r, p, t, o, op) in model.limit_tech_output_split: + model.output_split_vintages.setdefault((r, p, t, o, op), set()).add(v) + if (r, p, t, o, op) in model.limit_tech_output_split_annual: + model.output_split_annual_vintages.setdefault((r, p, t, o, op), set()).add( + v + ) diff --git a/temoa/components/operations.py b/temoa/components/operations.py index 198b688ea..e01579970 100644 --- a/temoa/components/operations.py +++ b/temoa/components/operations.py @@ -35,9 +35,9 @@ def baseload_diurnal_constraint_indices( ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]]: indices = { (r, p, s, d, t, v) - for r, p, t in model.baseloadVintages - for v in model.baseloadVintages[r, p, t] - for s in model.TimeSeason[p] + for r, p, t in model.baseload_vintages + for v in model.baseload_vintages[r, p, t] + for s in model.time_season[p] for d in model.time_of_day } @@ -49,9 +49,9 @@ def ramp_up_day_constraint_indices( ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]]: indices = { (r, p, s, d, t, v) - for r, p, t in model.rampUpVintages - for v in model.rampUpVintages[r, p, t] - for s in model.TimeSeason[p] + for r, p, t in model.ramp_up_vintages + for v in model.ramp_up_vintages[r, p, t] + for s in model.time_season[p] for d in model.time_of_day } @@ -63,9 +63,9 @@ def ramp_down_day_constraint_indices( ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]]: indices = { (r, p, s, d, t, v) - for r, p, t in model.rampDownVintages - for v in model.rampDownVintages[r, p, t] - for s in model.TimeSeason[p] + for r, p, t in model.ramp_down_vintages + for v in model.ramp_down_vintages[r, p, t] + for s in model.time_season[p] for d in model.time_of_day } @@ -75,14 +75,14 @@ def ramp_down_day_constraint_indices( def ramp_up_season_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Season, Season, Technology, Vintage]]: - if model.TimeSequencing.first() == 'consecutive_days': + if model.time_sequencing.first() == 'consecutive_days': return set() # s, s_next indexing ensures we dont build redundant constraints indices = { (r, p, s, s_next, t, v) - for r, p, t in model.rampUpVintages - for v in model.rampUpVintages[r, p, t] + for r, p, t in model.ramp_up_vintages + for v in model.ramp_up_vintages[r, p, t] for _p, s_seq, s in model.ordered_season_sequential if _p == p for s_next in (model.sequential_to_season[p, model.time_next_sequential[p, s_seq]],) @@ -95,14 +95,14 @@ def ramp_up_season_constraint_indices( def ramp_down_season_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Season, Season, Technology, Vintage]]: - if model.TimeSequencing.first() == 'consecutive_days': + if model.time_sequencing.first() == 'consecutive_days': return set() # s, s_next indexing ensures we dont build redundant constraints indices = { (r, p, s, s_next, t, v) - for r, p, t in model.rampDownVintages - for v in model.rampDownVintages[r, p, t] + for r, p, t in model.ramp_down_vintages + for v in model.ramp_down_vintages[r, p, t] for _p, s_seq, s in model.ordered_season_sequential if _p == p for s_next in (model.sequential_to_season[p, model.time_next_sequential[p, s_seq]],) @@ -178,19 +178,19 @@ def baseload_diurnal_constraint( # computationally, however, multiplication is cheaper than division, so: # (ActA * SegB) == (ActB * SegA) activity_sd = sum( - model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + model.v_flow_out[r, p, s, d, S_i, t, v, S_o] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) activity_sd_0 = sum( - model.V_FlowOut[r, p, s, d_0, S_i, t, v, S_o] - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + model.v_flow_out[r, p, s, d_0, S_i, t, v, S_o] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) - expr = activity_sd * value(model.SegFrac[p, s, d_0]) == activity_sd_0 * value( - model.SegFrac[p, s, d] + expr = activity_sd * value(model.segment_fraction[p, s, d_0]) == activity_sd_0 * value( + model.segment_fraction[p, s, d] ) return expr @@ -207,34 +207,34 @@ def create_operational_vintage_sets(model: TemoaModel) -> None: operational characteristics like curtailment, baseload, storage, ramping, and reserves. Populates: - - M.curtailmentVintages, M.baseloadVintages, M.storageVintages, - M.rampUpVintages, M.rampDownVintages: Dictionaries mapping (r, p, t) + - M.curtailment_vintages, M.baseload_vintages, M.storage_vintages, + M.ramp_up_vintages, M.ramp_down_vintages: Dictionaries mapping (r, p, t) to a set of vintages `v`. - - M.processReservePeriods: Dictionary mapping (r, p) to a set of (t, v) tuples. - - M.isSeasonalStorage: A boolean lookup for seasonal storage technologies. + - M.process_reserve_periods: Dictionary mapping (r, p) to a set of (t, v) tuples. + - M.is_seasonal_storage: A boolean lookup for seasonal storage technologies. """ logger.debug('Creating vintage sets for operational constraints.') - for r, p, t in model.processVintages: - for v in model.processVintages[r, p, t]: + for r, p, t in model.process_vintages: + for v in model.process_vintages[r, p, t]: key_rpt = (r, p, t) key_rp = (r, p) if t in model.tech_curtailment: - model.curtailmentVintages.setdefault(key_rpt, set()).add(v) + model.curtailment_vintages.setdefault(key_rpt, set()).add(v) if t in model.tech_baseload: - model.baseloadVintages.setdefault(key_rpt, set()).add(v) + model.baseload_vintages.setdefault(key_rpt, set()).add(v) if t in model.tech_storage: - model.storageVintages.setdefault(key_rpt, set()).add(v) + model.storage_vintages.setdefault(key_rpt, set()).add(v) if t in model.tech_upramping: - model.rampUpVintages.setdefault(key_rpt, set()).add(v) + model.ramp_up_vintages.setdefault(key_rpt, set()).add(v) if t in model.tech_downramping: - model.rampDownVintages.setdefault(key_rpt, set()).add(v) + model.ramp_down_vintages.setdefault(key_rpt, set()).add(v) if t in model.tech_reserve: - model.processReservePeriods.setdefault(key_rp, set()).add((t, v)) + model.process_reserve_periods.setdefault(key_rp, set()).add((t, v)) # A dictionary of whether a storage tech is seasonal, just to speed things up for t in model.tech_storage: - model.isSeasonalStorage[t] = t in model.tech_seasonal_storage + model.is_seasonal_storage[t] = t in model.tech_seasonal_storage def ramp_up_day_constraint( @@ -247,7 +247,7 @@ def ramp_up_day_constraint( v: Vintage, ) -> ExprLike: r""" - One of two constraints built from the RampUpHourly table, along with the + One of two constraints built from the ramp_up_hourly table, along with the RampUpSeason_Constraint. RampUpDay constrains ramp rates between time slices within each season and RampUpSeason constrains ramp rates between sequential seasons. If the :code:`time_sequencing` parameter is set to :code:`consecutive_days` @@ -300,23 +300,25 @@ def ramp_up_day_constraint( s_next, d_next = model.time_next[p, s, d] # How many hours does this time slice represent - hours_adjust = value(model.SegFrac[p, s, d]) * value(model.DaysPerPeriod) * 24 - hours_adjust_next = value(model.SegFrac[p, s_next, d_next]) * value(model.DaysPerPeriod) * 24 + hours_adjust = value(model.segment_fraction[p, s, d]) * value(model.days_per_period) * 24 + hours_adjust_next = ( + value(model.segment_fraction[p, s_next, d_next]) * value(model.days_per_period) * 24 + ) hourly_activity_sd = ( sum( - model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + model.v_flow_out[r, p, s, d, S_i, t, v, S_o] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) / hours_adjust ) hourly_activity_sd_next = ( sum( - model.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + model.v_flow_out[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) / hours_adjust_next ) @@ -326,11 +328,12 @@ def ramp_up_day_constraint( 24 / 2 * ( - value(model.SegFrac[p, s, d]) / value(model.SegFracPerSeason[p, s]) - + value(model.SegFrac[p, s_next, d_next]) / value(model.SegFracPerSeason[p, s_next]) + value(model.segment_fraction[p, s, d]) / value(model.segment_fraction_per_season[p, s]) + + value(model.segment_fraction[p, s_next, d_next]) + / value(model.segment_fraction_per_season[p, s_next]) ) ) - ramp_fraction = hours_elapsed * value(model.RampUpHourly[r, t]) + ramp_fraction = hours_elapsed * value(model.ramp_up_hourly[r, t]) if ramp_fraction >= 1: msg = ( @@ -342,7 +345,7 @@ def ramp_up_day_constraint( activity_increase = hourly_activity_sd_next - hourly_activity_sd # opposite sign from rampdown rampable_activity = ( - ramp_fraction * model.V_Capacity[r, p, t, v] * value(model.CapacityToActivity[r, t]) + ramp_fraction * model.v_capacity[r, p, t, v] * value(model.capacity_to_activity[r, t]) ) expr = activity_increase <= rampable_activity @@ -386,23 +389,25 @@ def ramp_down_day_constraint( s_next, d_next = model.time_next[p, s, d] # How many hours does this time slice represent - hours_adjust = value(model.SegFrac[p, s, d]) * value(model.DaysPerPeriod) * 24 - hours_adjust_next = value(model.SegFrac[p, s_next, d_next]) * value(model.DaysPerPeriod) * 24 + hours_adjust = value(model.segment_fraction[p, s, d]) * value(model.days_per_period) * 24 + hours_adjust_next = ( + value(model.segment_fraction[p, s_next, d_next]) * value(model.days_per_period) * 24 + ) hourly_activity_sd = ( sum( - model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + model.v_flow_out[r, p, s, d, S_i, t, v, S_o] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) / hours_adjust ) hourly_activity_sd_next = ( sum( - model.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + model.v_flow_out[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) / hours_adjust_next ) @@ -412,11 +417,12 @@ def ramp_down_day_constraint( 24 / 2 * ( - value(model.SegFrac[p, s, d]) / value(model.SegFracPerSeason[p, s]) - + value(model.SegFrac[p, s_next, d_next]) / value(model.SegFracPerSeason[p, s_next]) + value(model.segment_fraction[p, s, d]) / value(model.segment_fraction_per_season[p, s]) + + value(model.segment_fraction[p, s_next, d_next]) + / value(model.segment_fraction_per_season[p, s_next]) ) ) - ramp_fraction = hours_elapsed * value(model.RampDownHourly[r, t]) + ramp_fraction = hours_elapsed * value(model.ramp_down_hourly[r, t]) if ramp_fraction >= 1: msg = ( @@ -428,7 +434,7 @@ def ramp_down_day_constraint( activity_decrease = hourly_activity_sd - hourly_activity_sd_next # opposite sign from rampup rampable_activity = ( - ramp_fraction * model.V_Capacity[r, p, t, v] * value(model.CapacityToActivity[r, t]) + ramp_fraction * model.v_capacity[r, p, t, v] * value(model.capacity_to_activity[r, t]) ) expr = activity_decrease <= rampable_activity @@ -456,23 +462,25 @@ def ramp_up_season_constraint( d_next = model.time_of_day.first() # How many hours does this time slice represent - hours_adjust = value(model.SegFrac[p, s, d]) * value(model.DaysPerPeriod) * 24 - hours_adjust_next = value(model.SegFrac[p, s_next, d_next]) * value(model.DaysPerPeriod) * 24 + hours_adjust = value(model.segment_fraction[p, s, d]) * value(model.days_per_period) * 24 + hours_adjust_next = ( + value(model.segment_fraction[p, s_next, d_next]) * value(model.days_per_period) * 24 + ) hourly_activity_sd = ( sum( - model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + model.v_flow_out[r, p, s, d, S_i, t, v, S_o] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) / hours_adjust ) hourly_activity_sd_next = ( sum( - model.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + model.v_flow_out[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) / hours_adjust_next ) @@ -482,11 +490,12 @@ def ramp_up_season_constraint( 24 / 2 * ( - value(model.SegFrac[p, s, d]) / value(model.SegFracPerSeason[p, s]) - + value(model.SegFrac[p, s_next, d_next]) / value(model.SegFracPerSeason[p, s_next]) + value(model.segment_fraction[p, s, d]) / value(model.segment_fraction_per_season[p, s]) + + value(model.segment_fraction[p, s_next, d_next]) + / value(model.segment_fraction_per_season[p, s_next]) ) ) - ramp_fraction = hours_elapsed * value(model.RampUpHourly[r, t]) + ramp_fraction = hours_elapsed * value(model.ramp_up_hourly[r, t]) if ramp_fraction >= 1: msg = ( @@ -498,7 +507,7 @@ def ramp_up_season_constraint( activity_increase = hourly_activity_sd_next - hourly_activity_sd # opposite sign from rampdown rampable_activity = ( - ramp_fraction * model.V_Capacity[r, p, t, v] * value(model.CapacityToActivity[r, t]) + ramp_fraction * model.v_capacity[r, p, t, v] * value(model.capacity_to_activity[r, t]) ) expr = activity_increase <= rampable_activity @@ -526,23 +535,25 @@ def ramp_down_season_constraint( d_next = model.time_of_day.first() # How many hours does this time slice represent - hours_adjust = value(model.SegFrac[p, s, d]) * value(model.DaysPerPeriod) * 24 - hours_adjust_next = value(model.SegFrac[p, s_next, d_next]) * value(model.DaysPerPeriod) * 24 + hours_adjust = value(model.segment_fraction[p, s, d]) * value(model.days_per_period) * 24 + hours_adjust_next = ( + value(model.segment_fraction[p, s_next, d_next]) * value(model.days_per_period) * 24 + ) hourly_activity_sd = ( sum( - model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + model.v_flow_out[r, p, s, d, S_i, t, v, S_o] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) / hours_adjust ) hourly_activity_sd_next = ( sum( - model.V_FlowOut[r, p, s_next, d_next, S_i, t, v, S_o] - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + model.v_flow_out[r, p, s_next, d_next, S_i, t, v, S_o] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) / hours_adjust_next ) @@ -552,11 +563,12 @@ def ramp_down_season_constraint( 24 / 2 * ( - value(model.SegFrac[p, s, d]) / value(model.SegFracPerSeason[p, s]) - + value(model.SegFrac[p, s_next, d_next]) / value(model.SegFracPerSeason[p, s_next]) + value(model.segment_fraction[p, s, d]) / value(model.segment_fraction_per_season[p, s]) + + value(model.segment_fraction[p, s_next, d_next]) + / value(model.segment_fraction_per_season[p, s_next]) ) ) - ramp_fraction = hours_elapsed * value(model.RampDownHourly[r, t]) + ramp_fraction = hours_elapsed * value(model.ramp_down_hourly[r, t]) if ramp_fraction >= 1: msg = ( @@ -568,7 +580,7 @@ def ramp_down_season_constraint( activity_decrease = hourly_activity_sd - hourly_activity_sd_next # opposite sign from rampup rampable_activity = ( - ramp_fraction * model.V_Capacity[r, p, t, v] * value(model.CapacityToActivity[r, t]) + ramp_fraction * model.v_capacity[r, p, t, v] * value(model.capacity_to_activity[r, t]) ) expr = activity_decrease <= rampable_activity diff --git a/temoa/components/reserves.py b/temoa/components/reserves.py index 58e2fc785..f27d87989 100644 --- a/temoa/components/reserves.py +++ b/temoa/components/reserves.py @@ -33,10 +33,10 @@ def reserve_margin_indices(model: TemoaModel) -> set[tuple[Region, Period, Season, TimeOfDay]]: indices = { (r, p, s, d) - for r in model.PlanningReserveMargin.sparse_iterkeys() + for r in model.planning_reserve_margin.sparse_iterkeys() for p in model.time_optimize - if (r, p) in model.processReservePeriods - for s in model.TimeSeason[p] + if (r, p) in model.process_reserve_periods + for s in model.time_season[p] for d in model.time_of_day } @@ -92,37 +92,39 @@ def reserve_margin_dynamic( \Theta_{\text{ReserveMargin}} \text{ and } \forall r_i \in R """ if (not model.tech_reserve) or ( - (r, p) not in model.processReservePeriods + (r, p) not in model.process_reserve_periods ): # If reserve set empty or if r,p not in M.processReservePeriod, skip the constraint return Constraint.Skip # Everything but storage and exchange techs # Derated available generation available = sum( - model.V_Capacity[r, p, t, v] - * value(model.ReserveCapacityDerate[r, p, s, t, v]) - * value(model.CapacityFactorProcess[r, p, s, d, t, v]) - * value(model.CapacityToActivity[r, t]) - * value(model.SegFrac[p, s, d]) - for (t, v) in model.processReservePeriods[r, p] + model.v_capacity[r, p, t, v] + * value(model.reserve_capacity_derate[r, p, s, t, v]) + * value(model.capacity_factor_process[r, p, s, d, t, v]) + * value(model.capacity_to_activity[r, t]) + * value(model.segment_fraction[p, s, d]) + for (t, v) in model.process_reserve_periods[r, p] if t not in model.tech_uncap and t not in model.tech_storage ) # Storage # Derated net output flow available += sum( - model.V_FlowOut[r, p, s, d, i, t, v, o] * value(model.ReserveCapacityDerate[r, p, s, t, v]) - for (t, v) in model.processReservePeriods[r, p] + model.v_flow_out[r, p, s, d, i, t, v, o] + * value(model.reserve_capacity_derate[r, p, s, t, v]) + for (t, v) in model.process_reserve_periods[r, p] if t in model.tech_storage - for i in model.processInputs[r, p, t, v] - for o in model.processOutputsByInput[r, p, t, v, i] + for i in model.process_inputs[r, p, t, v] + for o in model.process_outputs_by_input[r, p, t, v, i] ) available -= sum( - model.V_FlowIn[r, p, s, d, i, t, v, o] * value(model.ReserveCapacityDerate[r, p, s, t, v]) - for (t, v) in model.processReservePeriods[r, p] + model.v_flow_in[r, p, s, d, i, t, v, o] + * value(model.reserve_capacity_derate[r, p, s, t, v]) + for (t, v) in model.process_reserve_periods[r, p] if t in model.tech_storage - for i in model.processInputs[r, p, t, v] - for o in model.processOutputsByInput[r, p, t, v, i] + for i in model.process_inputs[r, p, t, v] + for o in model.process_outputs_by_input[r, p, t, v, i] ) # The above code does not consider exchange techs, e.g. electricity @@ -133,13 +135,13 @@ def reserve_margin_dynamic( # First, determine the amount of firm capacity each exchange tech # contributes. - for r1r2 in model.regionalIndices: + for r1r2 in model.regional_indices: if '-' not in r1r2: continue if ( r1r2, p, - ) not in model.processReservePeriods: # ensure r1r2 is a valid reserve provider in p + ) not in model.process_reserve_periods: # ensure r1r2 is a valid reserve provider in p continue r1, r2 = r1r2.split('-') @@ -150,12 +152,12 @@ def reserve_margin_dynamic( # add the available output of the exchange tech. available += sum( - model.V_Capacity[r1r2, p, t, v] - * value(model.ReserveCapacityDerate[r, p, s, t, v]) - * value(model.CapacityFactorProcess[r, p, s, d, t, v]) - * value(model.CapacityToActivity[r1r2, t]) - * value(model.SegFrac[p, s, d]) - for (t, v) in model.processReservePeriods[r1r2, p] + model.v_capacity[r1r2, p, t, v] + * value(model.reserve_capacity_derate[r, p, s, t, v]) + * value(model.capacity_factor_process[r, p, s, d, t, v]) + * value(model.capacity_to_activity[r1r2, t]) + * value(model.segment_fraction[p, s, d]) + for (t, v) in model.process_reserve_periods[r1r2, p] ) return available @@ -191,16 +193,16 @@ def reserve_margin_static( &\qquad\qquad\forall \{r, p, s, d\} \in \Theta_{\text{ReserveMargin}} \text{and} \forall r_i \in R """ if (not model.tech_reserve) or ( - (r, p) not in model.processReservePeriods + (r, p) not in model.process_reserve_periods ): # If reserve set empty or if r,p not in M.processReservePeriod, skip the constraint return Constraint.Skip available = sum( - value(model.CapacityCredit[r, p, t, v]) - * model.V_Capacity[r, p, t, v] - * value(model.CapacityToActivity[r, t]) - * value(model.SegFrac[p, s, d]) - for (t, v) in model.processReservePeriods[r, p] + value(model.capacity_credit[r, p, t, v]) + * model.v_capacity[r, p, t, v] + * value(model.capacity_to_activity[r, t]) + * value(model.segment_fraction[p, s, d]) + for (t, v) in model.process_reserve_periods[r, p] if t not in model.tech_uncap ) @@ -212,13 +214,13 @@ def reserve_margin_static( # First, determine the amount of firm capacity each exchange tech # contributes. - for r1r2 in model.regionalIndices: + for r1r2 in model.regional_indices: if '-' not in r1r2: continue if ( r1r2, p, - ) not in model.processReservePeriods: # ensure r1r2 is a valid reserve provider in p + ) not in model.process_reserve_periods: # ensure r1r2 is a valid reserve provider in p continue r1, r2 = r1r2.split('-') @@ -229,11 +231,11 @@ def reserve_margin_static( # add the available capacity of the exchange tech. available += sum( - value(model.CapacityCredit[r1r2, p, t, v]) - * model.V_Capacity[r1r2, p, t, v] - * value(model.CapacityToActivity[r1r2, t]) - * value(model.SegFrac[p, s, d]) - for (t, v) in model.processReservePeriods[r1r2, p] + value(model.capacity_credit[r1r2, p, t, v]) + * model.v_capacity[r1r2, p, t, v] + * value(model.capacity_to_activity[r1r2, t]) + * value(model.segment_fraction[p, s, d]) + for (t, v) in model.process_reserve_periods[r1r2, p] ) return available @@ -248,13 +250,13 @@ def reserve_margin_constraint( model: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay ) -> ExprLike: # Get available generation in this time slice depending on method specified in config file - match model.ReserveMarginMethod.first(): + match model.reserve_margin_method.first(): case 'static': available = reserve_margin_static(model, r, p, s, d) case 'dynamic': available = reserve_margin_dynamic(model, r, p, s, d) case _: - msg = f"Invalid reserve margin parameter '{model.ReserveMarginMethod.first()}'. Check the config file." + msg = f"Invalid reserve margin parameter '{model.reserve_margin_method.first()}'. Check the config file." logger.error(msg) raise ValueError(msg) @@ -262,69 +264,69 @@ def reserve_margin_constraint( # generation instead as a proxy for electricity demand. # Non-annual generation total_generation = sum( - model.V_FlowOut[r, p, s, d, S_i, t, S_v, S_o] - for (t, S_v) in model.processReservePeriods[r, p] + model.v_flow_out[r, p, s, d, S_i, t, S_v, S_o] + for (t, S_v) in model.process_reserve_periods[r, p] if t not in model.tech_annual - for S_i in model.processInputs[r, p, t, S_v] - for S_o in model.processOutputsByInput[r, p, t, S_v, S_i] + for S_i in model.process_inputs[r, p, t, S_v] + for S_o in model.process_outputs_by_input[r, p, t, S_v, S_i] ) # Generators might serve demands directly # Annual generation total_generation += sum( ( - value(model.DemandSpecificDistribution[r, p, s, d, S_o]) + value(model.demand_specific_distribution[r, p, s, d, S_o]) if S_o in model.commodity_demand - else value(model.SegFrac[p, s, d]) + else value(model.segment_fraction[p, s, d]) ) - * model.V_FlowOutAnnual[r, p, S_i, t, S_v, S_o] - for (t, S_v) in model.processReservePeriods[r, p] + * model.v_flow_out_annual[r, p, S_i, t, S_v, S_o] + for (t, S_v) in model.process_reserve_periods[r, p] if t in model.tech_annual - for S_i in model.processInputs[r, p, t, S_v] - for S_o in model.processOutputsByInput[r, p, t, S_v, S_i] + for S_i in model.process_inputs[r, p, t, S_v] + for S_o in model.process_outputs_by_input[r, p, t, S_v, S_i] ) # We must take into account flows into storage technologies. # Flows into storage technologies need to be subtracted from the # load calculation. total_generation -= sum( - model.V_FlowIn[r, p, s, d, S_i, t, S_v, S_o] - for (t, S_v) in model.processReservePeriods[r, p] + model.v_flow_in[r, p, s, d, S_i, t, S_v, S_o] + for (t, S_v) in model.process_reserve_periods[r, p] if t in model.tech_storage - for S_i in model.processInputs[r, p, t, S_v] - for S_o in model.processOutputsByInput[r, p, t, S_v, S_i] + for S_i in model.process_inputs[r, p, t, S_v] + for S_o in model.process_outputs_by_input[r, p, t, S_v, S_i] ) # Electricity imports and exports via exchange techs are accounted # for below: - for r1r2 in model.regionalIndices: # ensure the region is of the form r1-r2 + for r1r2 in model.regional_indices: # ensure the region is of the form r1-r2 if '-' not in r1r2: continue if ( r1r2, p, - ) not in model.processReservePeriods: # ensure r1r2 is a valid reserve provider in p + ) not in model.process_reserve_periods: # ensure r1r2 is a valid reserve provider in p continue r1, r2 = r1r2.split('-') # First, determine the exports, and subtract this value from the # total generation. if r1 == r: total_generation -= sum( - model.V_FlowOut[r1r2, p, s, d, S_i, t, S_v, S_o] + model.v_flow_out[r1r2, p, s, d, S_i, t, S_v, S_o] / get_variable_efficiency(model, r1r2, p, s, d, S_i, t, S_v, S_o) - for (t, S_v) in model.processReservePeriods[r1r2, p] - for S_i in model.processInputs[r1r2, p, t, S_v] - for S_o in model.processOutputsByInput[r1r2, p, t, S_v, S_i] + for (t, S_v) in model.process_reserve_periods[r1r2, p] + for S_i in model.process_inputs[r1r2, p, t, S_v] + for S_o in model.process_outputs_by_input[r1r2, p, t, S_v, S_i] ) # Second, determine the imports, and add this value from the # total generation. elif r2 == r: total_generation += sum( - model.V_FlowOut[r1r2, p, s, d, S_i, t, S_v, S_o] - for (t, S_v) in model.processReservePeriods[r1r2, p] - for S_i in model.processInputs[r1r2, p, t, S_v] - for S_o in model.processOutputsByInput[r1r2, p, t, S_v, S_i] + model.v_flow_out[r1r2, p, s, d, S_i, t, S_v, S_o] + for (t, S_v) in model.process_reserve_periods[r1r2, p] + for S_i in model.process_inputs[r1r2, p, t, S_v] + for S_o in model.process_outputs_by_input[r1r2, p, t, S_v, S_i] ) - requirement = total_generation * (1 + value(model.PlanningReserveMargin[r])) + requirement = total_generation * (1 + value(model.planning_reserve_margin[r])) return available >= requirement diff --git a/temoa/components/storage.py b/temoa/components/storage.py index 28ec5e27d..c9be6c546 100644 --- a/temoa/components/storage.py +++ b/temoa/components/storage.py @@ -32,22 +32,22 @@ def storage_level_variable_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]] | None: - return model.storageLevelIndices_rpsdtv + return model.storage_level_indices_rpsdtv def seasonal_storage_level_variable_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Season, Technology, Vintage]] | None: - return model.seasonalStorageLevelIndices_rpstv + return model.seasonal_storage_level_indices_rpstv def seasonal_storage_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]]: - if model.seasonalStorageLevelIndices_rpstv: + if model.seasonal_storage_level_indices_rpstv: indices = { (r, p, s, d, t, v) - for r, p, s, t, v in model.seasonalStorageLevelIndices_rpstv + for r, p, s, t, v in model.seasonal_storage_level_indices_rpstv for d in model.time_of_day } return indices @@ -57,7 +57,7 @@ def seasonal_storage_constraint_indices( def storage_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]] | None: - return model.storageLevelIndices_rpsdtv + return model.storage_level_indices_rpsdtv # ============================================================================ @@ -89,24 +89,24 @@ def storage_energy_constraint( """ # We allow a non-zero daily delta only in the case of seasonal storage - if model.isSeasonalStorage[t] and d == model.time_of_day.last(): + if model.is_seasonal_storage[t] and d == model.time_of_day.last(): return Constraint.Skip # handled by SeasonalStorageEnergy_Constraint # This is the sum of all input=i sent TO storage tech t of vintage v with # output=o in p,s,d charge = sum( - model.V_FlowIn[r, p, s, d, S_i, t, v, S_o] + model.v_flow_in[r, p, s, d, S_i, t, v, S_o] * get_variable_efficiency(model, r, p, s, d, S_i, t, v, S_o) - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) # This is the sum of all output=o withdrawn FROM storage tech t of vintage v # with input=i in p,s,d discharge = sum( - model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_o in model.processOutputs[r, p, t, v] - for S_i in model.processInputsByOutput[r, p, t, v, S_o] + model.v_flow_out[r, p, s, d, S_i, t, v, S_o] + for S_o in model.process_outputs[r, p, t, v] + for S_i in model.process_inputs_by_output[r, p, t, v, S_o] ) stored_energy = charge - discharge @@ -116,8 +116,8 @@ def storage_energy_constraint( s_next, d_next = model.time_next[p, s, d] expr = ( - model.V_StorageLevel[r, p, s, d, t, v] + stored_energy - == model.V_StorageLevel[r, p, s_next, d_next, t, v] + model.v_storage_level[r, p, s, d, t, v] + stored_energy + == model.v_storage_level[r, p, s_next, d_next, t, v] ) return expr @@ -156,7 +156,7 @@ def seasonal_storage_energy_constraint( :figwidth: 60% How sequential seasons chain together for seasonal storage. Hatched area is - SeasonalStorageLevel :math:`SSL_{r,p,s^{seq},t,v}`. Vertical lines are + seasonal_storage_level :math:`SSL_{r,p,s^{seq},t,v}`. Vertical lines are StorageLevel :math:`SL_{r,p,s^*,d,t,v}`. Green line is net seasonal storage level :math:`SSL_{r,p,s^{seq},t,v} + SL_{r,p,s^*,d,t,v}`. Background grey lines show how storage levels from non-sequential seasons are combined @@ -170,18 +170,18 @@ def seasonal_storage_energy_constraint( # This is the sum of all input=i sent TO storage tech t of vintage v with # output=o in p,s charge = sum( - model.V_FlowIn[r, p, s, model.time_of_day.last(), S_i, t, v, S_o] + model.v_flow_in[r, p, s, model.time_of_day.last(), S_i, t, v, S_o] * get_variable_efficiency(model, r, p, s, model.time_of_day.last(), S_i, t, v, S_o) - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) # This is the sum of all output=o withdrawn FROM storage tech t of vintage v # with input=i in p,s discharge = sum( - model.V_FlowOut[r, p, s, model.time_of_day.last(), S_i, t, v, S_o] - for S_o in model.processOutputs[r, p, t, v] - for S_i in model.processInputsByOutput[r, p, t, v, S_o] + model.v_flow_out[r, p, s, model.time_of_day.last(), S_i, t, v, S_o] + for S_o in model.process_outputs[r, p, t, v] + for S_i in model.process_inputs_by_output[r, p, t, v, S_o] ) s_seq_next: Season = model.time_next_sequential[p, s_seq] @@ -189,22 +189,22 @@ def seasonal_storage_energy_constraint( # Flows and StorageLevel are normalised to the number of days in the non-sequential season, so must # be adjusted to the number of days in the sequential season - days_adjust = value(model.TimeSeasonSequential[p, s_seq, s]) / ( - value(model.SegFracPerSeason[p, s]) * value(model.DaysPerPeriod) + days_adjust = value(model.time_season_sequential[p, s_seq, s]) / ( + value(model.segment_fraction_per_season[p, s]) * value(model.days_per_period) ) - days_adjust_next = value(model.TimeSeasonSequential[p, s_seq_next, s_next]) / ( - value(model.SegFracPerSeason[p, s_next]) * value(model.DaysPerPeriod) + days_adjust_next = value(model.time_season_sequential[p, s_seq_next, s_next]) / ( + value(model.segment_fraction_per_season[p, s_next]) * value(model.days_per_period) ) stored_energy = (charge - discharge) * days_adjust start = ( - model.V_SeasonalStorageLevel[r, p, s_seq, t, v] - + model.V_StorageLevel[r, p, s, model.time_of_day.last(), t, v] * days_adjust + model.v_seasonal_storage_level[r, p, s_seq, t, v] + + model.v_storage_level[r, p, s, model.time_of_day.last(), t, v] * days_adjust ) end = ( - model.V_SeasonalStorageLevel[r, p, s_seq_next, t, v] - + model.V_StorageLevel[r, p, s_next, model.time_of_day.first(), t, v] * days_adjust_next + model.v_seasonal_storage_level[r, p, s_seq_next, t, v] + + model.v_storage_level[r, p, s_next, model.time_of_day.first(), t, v] * days_adjust_next ) expr = start + stored_energy == end @@ -255,18 +255,18 @@ def storage_energy_upper_bound_constraint( Representation of a 3-day season for non-seasonal (daily) storage. """ - if model.isSeasonalStorage[t]: + if model.is_seasonal_storage[t]: return Constraint.Skip # redundant on SeasonalStorageEnergyUpperBound energy_capacity = ( - model.V_Capacity[r, p, t, v] - * value(model.CapacityToActivity[r, t]) - * (value(model.StorageDuration[r, t]) / (24 * value(model.DaysPerPeriod))) - * value(model.SegFracPerSeason[p, s]) - * model.DaysPerPeriod # adjust for days in season + model.v_capacity[r, p, t, v] + * value(model.capacity_to_activity[r, t]) + * (value(model.storage_duration[r, t]) / (24 * value(model.days_per_period))) + * value(model.segment_fraction_per_season[p, s]) + * model.days_per_period # adjust for days in season ) - expr = model.V_StorageLevel[r, p, s, d, t, v] <= energy_capacity + expr = model.v_storage_level[r, p, s, d, t, v] <= energy_capacity return expr @@ -329,22 +329,22 @@ def seasonal_storage_energy_upper_bound_constraint( s: Season = model.sequential_to_season[p, s_seq] energy_capacity = ( - model.V_Capacity[r, p, t, v] - * value(model.CapacityToActivity[r, t]) - * (value(model.StorageDuration[r, t]) / (24 * value(model.DaysPerPeriod))) + model.v_capacity[r, p, t, v] + * value(model.capacity_to_activity[r, t]) + * (value(model.storage_duration[r, t]) / (24 * value(model.days_per_period))) ) # Flows and StorageLevel are normalised to the number of days in the non-sequential season, so must # be adjusted to the number of days in the sequential season - days_adjust = value(model.TimeSeasonSequential[p, s_seq, s]) / ( - value(model.SegFracPerSeason[p, s]) * value(model.DaysPerPeriod) + days_adjust = value(model.time_season_sequential[p, s_seq, s]) / ( + value(model.segment_fraction_per_season[p, s]) * value(model.days_per_period) ) - # V_StorageLevel tracks the running cumulative delta in the non-sequential season, so must be adjusted + # v_storage_level tracks the running cumulative delta in the non-sequential season, so must be adjusted # to the size of the sequential season - running_day_delta = model.V_StorageLevel[r, p, s, d, t, v] * days_adjust + running_day_delta = model.v_storage_level[r, p, s, d, t, v] * days_adjust - expr = model.V_SeasonalStorageLevel[r, p, s_seq, t, v] + running_day_delta <= energy_capacity + expr = model.v_seasonal_storage_level[r, p, s_seq, t, v] + running_day_delta <= energy_capacity return expr @@ -370,17 +370,17 @@ def storage_charge_rate_constraint( """ # Calculate energy charge in each time slice slice_charge = sum( - model.V_FlowIn[r, p, s, d, S_i, t, v, S_o] + model.v_flow_in[r, p, s, d, S_i, t, v, S_o] * get_variable_efficiency(model, r, p, s, d, S_i, t, v, S_o) - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) # Maximum energy charge in each time slice max_charge = ( - model.V_Capacity[r, p, t, v] - * value(model.CapacityToActivity[r, t]) - * value(model.SegFrac[p, s, d]) + model.v_capacity[r, p, t, v] + * value(model.capacity_to_activity[r, t]) + * value(model.segment_fraction[p, s, d]) ) # Energy charge cannot exceed the power capacity of the storage unit @@ -409,16 +409,16 @@ def storage_discharge_rate_constraint( """ # Calculate energy discharge in each time slice slice_discharge = sum( - model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_o in model.processOutputs[r, p, t, v] - for S_i in model.processInputsByOutput[r, p, t, v, S_o] + model.v_flow_out[r, p, s, d, S_i, t, v, S_o] + for S_o in model.process_outputs[r, p, t, v] + for S_i in model.process_inputs_by_output[r, p, t, v, S_o] ) # Maximum energy discharge in each time slice max_discharge = ( - model.V_Capacity[r, p, t, v] - * value(model.CapacityToActivity[r, t]) - * value(model.SegFrac[p, s, d]) + model.v_capacity[r, p, t, v] + * value(model.capacity_to_activity[r, t]) + * value(model.segment_fraction[p, s, d]) ) # Energy discharge cannot exceed the capacity of the storage unit @@ -449,23 +449,23 @@ def storage_throughput_constraint( \forall \{r, p, s, d, t, v\} \in \Theta_{\text{StorageThroughput}} """ discharge = sum( - model.V_FlowOut[r, p, s, d, S_i, t, v, S_o] - for S_o in model.processOutputs[r, p, t, v] - for S_i in model.processInputsByOutput[r, p, t, v, S_o] + model.v_flow_out[r, p, s, d, S_i, t, v, S_o] + for S_o in model.process_outputs[r, p, t, v] + for S_i in model.process_inputs_by_output[r, p, t, v, S_o] ) charge = sum( - model.V_FlowIn[r, p, s, d, S_i, t, v, S_o] + model.v_flow_in[r, p, s, d, S_i, t, v, S_o] * get_variable_efficiency(model, r, p, s, d, S_i, t, v, S_o) - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) throughput = charge + discharge max_throughput = ( - model.V_Capacity[r, p, t, v] - * value(model.CapacityToActivity[r, t]) - * value(model.SegFrac[p, s, d]) + model.v_capacity[r, p, t, v] + * value(model.capacity_to_activity[r, t]) + * value(model.segment_fraction[p, s, d]) ) expr = throughput <= max_throughput return expr @@ -496,38 +496,38 @@ def limit_storage_fraction_constraint( .. math:: - :label: LimitStorageFraction + :label: limit_storage_fraction \textbf{SF}_{r,p,s,d,t,v} \le \ SF_{r,p,s,d,t,v} \cdot \textbf{CAP}_{r,p,t,v} \cdot C2A_{r,t} \cdot \frac {SD_{r,t}}{(24 \cdot DPP hrs/yr} - \cdot \sum_{d} SEG_{s,d} \cdot M.DaysPerPeriod days/yr \cdot MPL_{r,p,t,v} + \cdot \sum_{d} SEG_{s,d} \cdot M.days_per_period days/yr \cdot MPL_{r,p,t,v} \\ - \forall \{r, p, s, d, t, v\} \in \Theta_{\text{LimitStorageFraction}} + \forall \{r, p, s, d, t, v\} \in \Theta_{\text{limit_storage_fraction}} """ energy_limit = ( - model.V_Capacity[r, p, t, v] - * value(model.CapacityToActivity[r, t]) - * (value(model.StorageDuration[r, t]) / (24 * value(model.DaysPerPeriod))) - * value(model.LimitStorageFraction[r, p, s, d, t, v, op]) + model.v_capacity[r, p, t, v] + * value(model.capacity_to_activity[r, t]) + * (value(model.storage_duration[r, t]) / (24 * value(model.days_per_period))) + * value(model.limit_storage_fraction[r, p, s, d, t, v, op]) ) - if model.isSeasonalStorage[t]: + if model.is_seasonal_storage[t]: s_seq: Season = s # sequential season s = model.sequential_to_season[p, s_seq] # non-sequential season # adjust the storage level to the individual-day level - energy_level = model.V_StorageLevel[r, p, s, d, t, v] / ( - value(model.SegFracPerSeason[p, s]) * value(model.DaysPerPeriod) + energy_level = model.v_storage_level[r, p, s, d, t, v] / ( + value(model.segment_fraction_per_season[p, s]) * value(model.days_per_period) ) - if model.isSeasonalStorage[t]: + if model.is_seasonal_storage[t]: # seasonal storage upper energy limit is absolute - energy_level = model.V_SeasonalStorageLevel[r, p, s_seq, t, v] + energy_level * value( - model.TimeSeasonSequential[p, s_seq, s] + energy_level = model.v_seasonal_storage_level[r, p, s_seq, t, v] + energy_level * value( + model.time_season_sequential[p, s_seq, s] ) expr = operator_expression(energy_level, Operator(op), energy_limit) diff --git a/temoa/components/technology.py b/temoa/components/technology.py index 121dc4714..7c8f7833e 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -4,7 +4,7 @@ This module is the foundation of the model, responsible for: - Pre-computing the core data structures that link technologies to commodities, - time periods, and vintages based on the `Efficiency` parameter. + time periods, and vintages based on the `efficiency` parameter. - Handling technology lifetimes, including survival curve validation and interpolation. - Defining Pyomo index sets for core technology parameters. - Validating model inputs related to technologies, efficiencies, and commodities. @@ -51,15 +51,15 @@ def model_process_life_indices( the periods in which a process is active, distinct from TechLifeFracIndices that returns indices only for processes that EOL mid-period. """ - return model.activeActivity_rptv + return model.active_activity_rptv def lifetime_process_indices(model: TemoaModel) -> set[tuple[Region, Technology, Vintage]]: """ - Based on the Efficiency parameter's indices, this function returns the set of - process indices that may be specified in the LifetimeProcess parameter. + Based on the efficiency parameter's indices, this function returns the set of + process indices that may be specified in the lifetime_process parameter. """ - indices = {(r, t, v) for r, i, t, v, o in model.Efficiency.sparse_iterkeys()} + indices = {(r, t, v) for r, i, t, v, o in model.efficiency.sparse_iterkeys()} return indices @@ -68,28 +68,28 @@ def get_default_survival( model: TemoaModel, r: Region, p: Period, t: Technology, v: Vintage ) -> float: """ - Getting LifetimeSurvivalCurve where it is not defined + Getting lifetime_survival_curve where it is not defined If this is a survival curve process, return 0 (likely beyond EOL) Otherwise return 1 (no survival curve based EOL) """ - return 0.0 if model.isSurvivalCurveProcess[r, t, v] else 1.0 + return 0.0 if model.is_survival_curve_process[r, t, v] else 1.0 def get_default_process_lifetime(model: TemoaModel, r: Region, t: Technology, v: Vintage) -> int: """ - This initializer used to initialize the LifetimeProcess parameter from LifetimeTech where needed + This initializer used to initialize the lifetime_process parameter from lifetime_tech where needed Priority: - 1. Specified in LifetimeProcess data (provided as a fill and would not call this function) - 2. Specified in LifetimeTech data - 3. The default value from the LifetimeTech param (automatic) + 1. Specified in lifetime_process data (provided as a fill and would not call this function) + 2. Specified in lifetime_tech data + 3. The default value from the lifetime_tech param (automatic) :param M: generic model reference (not used) :param r: region :param t: tech :param v: vintage :return: the final lifetime value """ - return value(model.LifetimeTech[r, t]) + return value(model.lifetime_tech[r, t]) def param_process_life_fraction_rule( @@ -102,16 +102,17 @@ def param_process_life_fraction_rule( for processes using survival curves. """ - period_length = value(model.PeriodLength[p]) + period_length = value(model.period_length[p]) - if model.isSurvivalCurveProcess[r, t, v]: + if model.is_survival_curve_process[r, t, v]: # Sum survival fraction over the period years_remaining = sum( - value(model.LifetimeSurvivalCurve[r, _p, t, v]) for _p in range(p, p + period_length, 1) + value(model.lifetime_survival_curve[r, _p, t, v]) + for _p in range(p, p + period_length, 1) ) else: # Remaining life years within the EOL period - years_remaining = v + value(model.LifetimeProcess[r, t, v]) - p + years_remaining = v + value(model.lifetime_process[r, t, v]) - p if years_remaining >= period_length: # try to avoid floating point round-off errors for the common case. @@ -128,49 +129,49 @@ def param_process_life_fraction_rule( def populate_core_dictionaries(model: TemoaModel) -> None: """ - Populates the core sparse dictionaries from the `Efficiency` parameter. + Populates the core sparse dictionaries from the `efficiency` parameter. This function is foundational for creating the sparse indices used throughout the model, defining process relationships, inputs, outputs, and active periods. Populates: - - M.processInputs, M.processOutputs - - M.commodityDStreamProcess, M.commodityUStreamProcess - - M.processOutputsByInput, M.processInputsByOutput - - M.processVintages, M.processPeriods + - M.process_inputs, M.process_outputs + - M.commodity_down_stream_process, M.commodity_up_stream_process + - M.process_outputs_by_input, M.process_inputs_by_output + - M.process_vintages, M.process_periods - M.used_techs """ - logger.debug('Populating core sparse dictionaries from Efficiency parameter.') + logger.debug('Populating core sparse dictionaries from efficiency parameter.') first_period = min(model.time_future) - exist_indices = model.ExistingCapacity.sparse_keys() + exist_indices = model.existing_capacity.sparse_keys() - for r, i, t, v, o in model.Efficiency.sparse_iterkeys(): + for r, i, t, v, o in model.efficiency.sparse_iterkeys(): # A. Basic data validation and warnings process = (r, t, v) - lifetime = value(model.LifetimeProcess[process]) + lifetime = value(model.lifetime_process[process]) if v in model.vintage_exist: if process not in exist_indices and t not in model.tech_uncap: logger.warning( - f'Warning: {process} has a specified Efficiency, but does not ' - f'have any existing install base (ExistingCapacity).' + f'Warning: {process} has a specified efficiency, but does not ' + f'have any existing install base (existing_capacity).' ) continue - if t not in model.tech_uncap and model.ExistingCapacity[process] == 0: + if t not in model.tech_uncap and model.existing_capacity[process] == 0: logger.warning( - f'Notice: Unnecessary specification of ExistingCapacity for {process}. ' + f'Notice: Unnecessary specification of existing_capacity for {process}. ' f'Declaring a capacity of zero may be omitted.' ) continue if v + lifetime <= first_period: logger.info( - f'{process} specified as ExistingCapacity, but its ' + f'{process} specified as existing_capacity, but its ' f'lifetime ({lifetime} years) does not extend past the ' f'beginning of time_future ({first_period}).' ) - if model.Efficiency[r, i, t, v, o] == 0: + if model.efficiency[r, i, t, v, o] == 0: logger.info( - f'Notice: Unnecessary specification of Efficiency for {(r, i, t, v, o)}. ' + f'Notice: Unnecessary specification of efficiency for {(r, i, t, v, o)}. ' f'Specifying an efficiency of zero may be omitted.' ) continue @@ -186,65 +187,65 @@ def populate_core_dictionaries(model: TemoaModel) -> None: pindex = (r, p, t, v) # C. Initialize dictionary keys if not present - if pindex not in model.processInputs: - model.processInputs[pindex] = set() - model.processOutputs[pindex] = set() - if (r, p, i) not in model.commodityDStreamProcess: - model.commodityDStreamProcess[r, p, i] = set() - if (r, p, o) not in model.commodityUStreamProcess: - model.commodityUStreamProcess[r, p, o] = set() - if (r, p, t, v, i) not in model.processOutputsByInput: - model.processOutputsByInput[r, p, t, v, i] = set() - if (r, p, t, v, o) not in model.processInputsByOutput: - model.processInputsByOutput[r, p, t, v, o] = set() - if (r, p, t) not in model.processVintages: - model.processVintages[r, p, t] = set() - if (r, t, v) not in model.processPeriods: - model.processPeriods[r, t, v] = set() + if pindex not in model.process_inputs: + model.process_inputs[pindex] = set() + model.process_outputs[pindex] = set() + if (r, p, i) not in model.commodity_down_stream_process: + model.commodity_down_stream_process[r, p, i] = set() + if (r, p, o) not in model.commodity_up_stream_process: + model.commodity_up_stream_process[r, p, o] = set() + if (r, p, t, v, i) not in model.process_outputs_by_input: + model.process_outputs_by_input[r, p, t, v, i] = set() + if (r, p, t, v, o) not in model.process_inputs_by_output: + model.process_inputs_by_output[r, p, t, v, o] = set() + if (r, p, t) not in model.process_vintages: + model.process_vintages[r, p, t] = set() + if (r, t, v) not in model.process_periods: + model.process_periods[r, t, v] = set() # D. Populate the dictionaries - model.processInputs[pindex].add(i) - model.processOutputs[pindex].add(o) - model.commodityDStreamProcess[r, p, i].add((t, v)) - model.commodityUStreamProcess[r, p, o].add((t, v)) - model.processOutputsByInput[r, p, t, v, i].add(o) - model.processInputsByOutput[r, p, t, v, o].add(i) - model.processVintages[r, p, t].add(v) - model.processPeriods[r, t, v].add(p) + model.process_inputs[pindex].add(i) + model.process_outputs[pindex].add(o) + model.commodity_down_stream_process[r, p, i].add((t, v)) + model.commodity_up_stream_process[r, p, o].add((t, v)) + model.process_outputs_by_input[r, p, t, v, i].add(o) + model.process_inputs_by_output[r, p, t, v, o].add(i) + model.process_vintages[r, p, t].add(v) + model.process_periods[r, t, v].add(p) def create_survival_curve(model: TemoaModel) -> None: rtv_interpolated = set() # so we only need one warning - for r, _, t, v, _ in model.Efficiency.sparse_iterkeys(): - model.isSurvivalCurveProcess[r, t, v] = False # by default + for r, _, t, v, _ in model.efficiency.sparse_iterkeys(): + model.is_survival_curve_process[r, t, v] = False # by default # Collect rptv indices into (r, t, v): p dictionary - for r, p, t, v in model.LifetimeSurvivalCurve.sparse_iterkeys(): - if (r, t, v) not in model.survivalCurvePeriods: - model.survivalCurvePeriods[r, t, v] = set() - model.survivalCurvePeriods[r, t, v].add(p) - model.isSurvivalCurveProcess[r, t, v] = True + for r, p, t, v in model.lifetime_survival_curve.sparse_iterkeys(): + if (r, t, v) not in model.survival_curve_periods: + model.survival_curve_periods[r, t, v] = set() + model.survival_curve_periods[r, t, v].add(p) + model.is_survival_curve_process[r, t, v] = True # Go through all the periods for each (r, t, v) in order - for r, t, v in model.survivalCurvePeriods: - periods_rtv: list[int] = sorted(model.survivalCurvePeriods[r, t, v]) + for r, t, v in model.survival_curve_periods: + periods_rtv: list[int] = sorted(model.survival_curve_periods[r, t, v]) p_first = periods_rtv[0] p_last = periods_rtv[-1] if p_first != v: msg = ( - 'LifetimeSurvivalCurve must be defined starting in the vintage period. Must ' + 'lifetime_survival_curve must be defined starting in the vintage period. Must ' f'define ({r}, >{v}<, {t}, {v})' ) logger.error(msg) raise ValueError(msg) - if value(model.LifetimeSurvivalCurve[r, v, t, v]) != 1: + if value(model.lifetime_survival_curve[r, v, t, v]) != 1: msg_str = ( - 'LifetimeSurvivalCurve must begin at 1 for calculating annual retirements. ' - f'Got {value(model.LifetimeSurvivalCurve[r, v, t, v])} for ({r}, {v}, {t}, {v})' + 'lifetime_survival_curve must begin at 1 for calculating annual retirements. ' + f'Got {value(model.lifetime_survival_curve[r, v, t, v])} for ({r}, {v}, {t}, {v})' ) logger.error(msg_str) raise ValueError(msg_str) @@ -260,11 +261,11 @@ def create_survival_curve(model: TemoaModel) -> None: # Check that the survival curve monotonically decreases p_prev = periods_rtv[i - 1] - lsc = value(model.LifetimeSurvivalCurve[r, p, t, v]) - lsc_prev = value(model.LifetimeSurvivalCurve[r, p_prev, t, v]) + lsc = value(model.lifetime_survival_curve[r, p, t, v]) + lsc_prev = value(model.lifetime_survival_curve[r, p_prev, t, v]) if lsc - lsc_prev > 0.0001: msg = ( - 'LifetimeSurvivalCurve fraction increases going forward in time from {} to {}. ' + 'lifetime_survival_curve fraction increases going forward in time from {} to {}. ' 'This is not allowed.' ).format((r, p_prev, t, v), (r, p, t, v)) logger.error(msg) @@ -275,7 +276,7 @@ def create_survival_curve(model: TemoaModel) -> None: for _p in _between_periods: x = (_p - p_prev) / (p - p_prev) lsc_x = lsc_prev + x * (lsc - lsc_prev) - model.LifetimeSurvivalCurve[r, _p, t, v] = lsc_x + model.lifetime_survival_curve[r, _p, t, v] = lsc_x between_periods.extend(_between_periods) if lsc < 0.0001: @@ -287,20 +288,20 @@ def create_survival_curve(model: TemoaModel) -> None: logger.info(msg) # Make sure the lifetime for this process aligns with survival curve end - if value(model.LifetimeProcess[r, t, v]) < p - v: + if value(model.lifetime_process[r, t, v]) < p - v: msg = ( - f'The LifetimeProcess parameter for process ({r, t, v}) with survival curve ' + f'The lifetime_process parameter for process ({r, t, v}) with survival curve ' f'does not extend beyond the end of that survival curve in {p}. To agree with ' - f'the survival curve, set LifetimeProcess[{r, t, v}] >= {p - v}' + f'the survival curve, set lifetime_process[{r, t, v}] >= {p - v}' ) logger.error(msg) raise ValueError(msg) - elif value(model.LifetimeProcess[r, t, v]) != p - v: + elif value(model.lifetime_process[r, t, v]) != p - v: msg = ( - f'The LifetimeProcess parameter for process ({r, t, v}) with survival curve ' + f'The lifetime_process parameter for process ({r, t, v}) with survival curve ' f'does match the end of that survival curve in {p}. This will waste compute. ' 'To agree with the survival curve and suppress this warning, set ' - f'LifetimeProcess[{r, t, v}] = {p - v}' + f'lifetime_process[{r, t, v}] = {p - v}' ) logger.warning(msg) @@ -316,11 +317,11 @@ def create_survival_curve(model: TemoaModel) -> None: logger.error(msg) raise ValueError(msg) - model.survivalCurvePeriods[r, t, v].update(between_periods) + model.survival_curve_periods[r, t, v].update(between_periods) if rtv_interpolated: msg = ( - 'For the purposes of investment cost accounting, LifetimeSurvivalCurve must be defined ' + 'For the purposes of investment cost accounting, lifetime_survival_curve must be defined ' 'for each individual year. Gaps between defined years will be filled by linear interpolation. ' 'Otherwise, these individual years can be defined manually. Interpolated processes: {}' ).format([rtv for rtv in rtv_interpolated]) @@ -329,15 +330,15 @@ def create_survival_curve(model: TemoaModel) -> None: def check_efficiency_indices(model: TemoaModel) -> None: """ - Ensure that there are no unused items in any of the Efficiency index sets. + Ensure that there are no unused items in any of the efficiency index sets. """ # TODO: This could be upgraded to scan for finer resolution # by checking by REGION and PERIOD... Each region/period is unique. - c_physical = {i for r, i, t, v, o in model.Efficiency.sparse_iterkeys()} - c_physical = c_physical | {i for r, i, t, v in model.ConstructionInput.sparse_iterkeys()} - techs = {t for r, i, t, v, o in model.Efficiency.sparse_iterkeys()} - c_outputs = {o for r, i, t, v, o in model.Efficiency.sparse_iterkeys()} - c_outputs = c_outputs | {o for r, t, v, o in model.EndOfLifeOutput.sparse_iterkeys()} + c_physical = {i for r, i, t, v, o in model.efficiency.sparse_iterkeys()} + c_physical = c_physical | {i for r, i, t, v in model.construction_input.sparse_iterkeys()} + techs = {t for r, i, t, v, o in model.efficiency.sparse_iterkeys()} + c_outputs = {o for r, i, t, v, o in model.efficiency.sparse_iterkeys()} + c_outputs = c_outputs | {o for r, t, v, o in model.end_of_life_output.sparse_iterkeys()} symdiff = c_physical.symmetric_difference(model.commodity_physical) if symdiff: @@ -379,27 +380,27 @@ def check_efficiency_indices(model: TemoaModel) -> None: def check_efficiency_variable(model: TemoaModel) -> None: count_rpitvo = {} # Pull non-variable efficiency by default - for r, i, t, v, o in model.Efficiency.sparse_iterkeys(): - if (r, t, v) not in model.processPeriods: + for r, i, t, v, o in model.efficiency.sparse_iterkeys(): + if (r, t, v) not in model.process_periods: # Probably an existing vintage that retires in p0 # Still want it for end of life flows continue - for p in model.processPeriods[r, t, v]: - model.isEfficiencyVariable[r, p, i, t, v, o] = False + for p in model.process_periods[r, t, v]: + model.is_efficiency_variable[r, p, i, t, v, o] = False count_rpitvo[r, p, i, t, v, o] = 0 annual = set() # Check for bad values and count up the good ones - for r, p, _s, _d, i, t, v, o in model.EfficiencyVariable.sparse_iterkeys(): - if p not in model.processPeriods[r, t, v]: - msg = f'Invalid period {p} for process {r, t, v} in EfficiencyVariable table' + for r, p, _s, _d, i, t, v, o in model.efficiency_variable.sparse_iterkeys(): + if p not in model.process_periods[r, t, v]: + msg = f'Invalid period {p} for process {r, t, v} in efficiency_variable table' logger.error(msg) raise ValueError(msg) if t in model.tech_annual: annual.add(t) - # Good value, pull from EfficiencyVariable table + # Good value, pull from efficiency_variable table count_rpitvo[r, p, i, t, v, o] += 1 for t in annual: @@ -412,14 +413,14 @@ def check_efficiency_variable(model: TemoaModel) -> None: # Check if all possible values have been set as variable # log a warning if some are missing (allowed but maybe accidental) - num_seg = len(model.TimeSeason[p]) * len(model.time_of_day) + num_seg = len(model.time_season[p]) * len(model.time_of_day) for (r, p, i, t, v, o), count in count_rpitvo.items(): if count > 0: - model.isEfficiencyVariable[r, p, i, t, v, o] = True + model.is_efficiency_variable[r, p, i, t, v, o] = True if count < num_seg: logger.info( - 'Some but not all EfficiencyVariable values were set (%i out of a possible %i) for: %s' - ' Missing values will default to value set in Efficiency table.', + 'Some but not all efficiency_variable values were set (%i out of a possible %i) for: %s' + ' Missing values will default to value set in efficiency table.', count, num_seg, (r, p, i, t, v, o), diff --git a/temoa/components/time.py b/temoa/components/time.py index 9558dd70c..57ebdea5a 100644 --- a/temoa/components/time.py +++ b/temoa/components/time.py @@ -92,10 +92,10 @@ def validate_segment_fraction(model: TemoaModel) -> None: for p in model.time_optimize: expected_keys: set[tuple[int, str, str]] = { - (p, s, d) for s in model.TimeSeason[p] for d in model.time_of_day + (p, s, d) for s in model.time_season[p] for d in model.time_of_day } keys: set[tuple[int, str, str]] = { - (_p, s, d) for _p, s, d in model.SegFrac.sparse_iterkeys() if _p == p + (_p, s, d) for _p, s, d in model.segment_fraction.sparse_iterkeys() if _p == p } if expected_keys != keys: @@ -109,11 +109,11 @@ def validate_segment_fraction(model: TemoaModel) -> None: logger.error(msg) raise ValueError(msg) - total: float = sum(value(model.SegFrac[k]) for k in keys) + total: float = sum(value(model.segment_fraction[k]) for k in keys) if abs(float(total) - 1.0) > 0.001: # We can't explicitly test for "!= 1.0" because of incremental rounding - # errors associated with the specification of SegFrac by time slice, + # errors associated with the specification of segment_fraction by time slice, # but we check to make sure it is within the specified tolerance. def get_str_padding(obj: object) -> int: @@ -124,38 +124,38 @@ def get_str_padding(obj: object) -> int: # Works out to something like "%-25s = %s" items_list: list[tuple[tuple[object, object, object], object]] = sorted( - [(k, model.SegFrac[k]) for k in keys] + [(k, model.segment_fraction[k]) for k in keys] ) items: str = '\n '.join(f'{str(k):<{key_padding}} = {v}' for k, v in items_list) msg = ( 'The values of TimeSegmentFraction do not sum to 1 for period {}. ' - 'Each item in SegFrac represents a fraction of a year, so they must ' + 'Each item in segment_fraction represents a fraction of a year, so they must ' 'total to 1. Current values:\n {}\n\tsum = {}' ).format(p, items, total) logger.error(msg) raise Exception(msg) -def validate_time_next(model: TemoaModel) -> None: +def validate_time_manual(model: TemoaModel) -> None: """ If using this table, check that defined states are actually valid. - TimeSegmentFraction is already compared to other tables so just compare to SegFrac. + TimeSegmentFraction is already compared to other tables so just compare to segment_fraction. """ # Only check TimeNext if it is actually being used - if model.TimeSequencing.first() != 'manual': + if model.time_sequencing.first() != 'manual': return - segfrac_psd: set[tuple[int, str, str]] = set(model.SegFrac.sparse_iterkeys()) - time_next_psd: set[tuple[int, str, str]] = { - (p, s, d) for p, s, d, s_next, d_next in model.TimeNext + segfrac_psd: set[tuple[int, str, str]] = set(model.segment_fraction.sparse_iterkeys()) + time_manual_psd: set[tuple[int, str, str]] = { + (p, s, d) for p, s, d, s_next, d_next in model.time_manual } - time_next_psd_next: set[tuple[int, str, str]] = { - (p, s_next, d_next) for p, s, d, s_next, d_next in model.TimeNext + time_manual_psd_next: set[tuple[int, str, str]] = { + (p, s_next, d_next) for p, s, d, s_next, d_next in model.time_manual } - missing_psd: set[tuple[int, str, str]] = segfrac_psd.difference(time_next_psd) - missing_psd_next: set[tuple[int, str, str]] = segfrac_psd.difference(time_next_psd_next) + missing_psd: set[tuple[int, str, str]] = segfrac_psd.difference(time_manual_psd) + missing_psd_next: set[tuple[int, str, str]] = segfrac_psd.difference(time_manual_psd_next) if missing_psd or missing_psd_next: msg: str = ( 'Failed to build state sequence. ' @@ -186,10 +186,12 @@ def init_set_vintage_optimize(model: TemoaModel) -> list[int]: return sorted(model.time_optimize) -def seg_frac_per_season_rule(model: TemoaModel, p: Period, s: Season) -> float: +def segment_fraction_per_season_rule(model: TemoaModel, p: Period, s: Season) -> float: """Rule to calculate the total fraction of a period represented by a season.""" return sum( - value(model.SegFrac[p, s, d]) for d in model.time_of_day if (p, s, d) in model.SegFrac + value(model.segment_fraction[p, s, d]) + for d in model.time_of_day + if (p, s, d) in model.segment_fraction ) @@ -211,15 +213,15 @@ def loop_period_next_timeslice( # Final time slice of final season (end of period) # Loop state back to initial state of first season # Loop the period - if s == model.TimeSeason[p].last() and d == model.time_of_day.last(): - s_next: Season = model.TimeSeason[p].first() + if s == model.time_season[p].last() and d == model.time_of_day.last(): + s_next: Season = model.time_season[p].first() d_next: TimeOfDay = model.time_of_day.first() # Last time slice of any season that is NOT the last season # Carry state to initial state of next season # Carry state between seasons elif d == model.time_of_day.last(): - s_next = model.TimeSeason[p].next(s) + s_next = model.time_season[p].next(s) d_next = model.time_of_day.first() # Any other time slice @@ -262,30 +264,30 @@ def create_time_sequence(model: TemoaModel) -> None: logger.debug('Creating sequence of time slices.') # Establishing sequence of states - match model.TimeSequencing.first(): + match model.time_sequencing.first(): case 'consecutive_days': msg: str = 'Running a consecutive days database.' for p in model.time_optimize: - for s, d in model.TimeSeason[p] * model.time_of_day: + for s, d in model.time_season[p] * model.time_of_day: model.time_next[p, s, d] = loop_period_next_timeslice(model, p, s, d) case 'seasonal_timeslices': msg = 'Running a seasonal time slice database.' for p in model.time_optimize: - for s, d in model.TimeSeason[p] * model.time_of_day: + for s, d in model.time_season[p] * model.time_of_day: model.time_next[p, s, d] = loop_season_next_timeslice(model, p, s, d) case 'representative_periods': msg = 'Running a representative periods database.' for p in model.time_optimize: - for s, d in model.TimeSeason[p] * model.time_of_day: + for s, d in model.time_season[p] * model.time_of_day: model.time_next[p, s, d] = loop_season_next_timeslice(model, p, s, d) case 'manual': - # Hidden feature. Define the sequence directly in the TimeNext table + # Hidden feature. Define the sequence directly in the TimeManual table msg = 'Pulling time sequence from TimeNext table.' - for p, s, d, s_next, d_next in model.TimeNext: - model.time_next[p, s, d] = s_next, d_next + for p, s, d, s_next, d_next in model.time_manual: + model.time_manual[p, s, d] = s_next, d_next case _: # This should have been caught in hybrid_loader - msg = f"Invalid time sequencing parameter loaded '{model.TimeSequencing.first()}'. Likely code error." + msg = f"Invalid time sequencing parameter loaded '{model.time_sequencing.first()}'. Likely code error." logger.error(msg) raise ValueError(msg) @@ -309,36 +311,36 @@ def create_time_sequence(model: TemoaModel) -> None: logger.debug('Created time sequence.') -def create_time_season_sequential(model: TemoaModel) -> None: +def create_time_season_to_sequential(model: TemoaModel) -> None: if all( ( not model.tech_seasonal_storage, - not model.RampUpHourly, - not model.RampDownHourly, + not model.ramp_up_hourly, + not model.ramp_down_hourly, ) ): # Don't need it anyway return - if not model.TimeSeasonSequential: - if model.TimeSequencing.first() in ('consecutive_days', 'seasonal_timeslices'): + if not model.time_season_sequential: + if model.time_sequencing.first() in ('consecutive_days', 'seasonal_timeslices'): logger.info( - 'No data in TimeSeasonSequential. By default, assuming sequential seasons ' + 'No data in time_season_sequential. By default, assuming sequential seasons ' 'match TimeSeason and TimeSegmentFraction.' ) - for s in model.time_season: - model.time_season_sequential.add(s) - for p in model.TimeSeason: - for s in model.TimeSeason[p]: + for s in model.time_season_all: + model.time_season_to_sequential.add(s) + for p in model.time_season: + for s in model.time_season[p]: model.ordered_season_sequential.add((p, s, s)) - model.TimeSeasonSequential[p, s, s] = value( - model.SegFracPerSeason[p, s] - ) * value(model.DaysPerPeriod) + model.time_season_sequential[p, s, s] = value( + model.segment_fraction_per_season[p, s] + ) * value(model.days_per_period) else: msg = ( - f'No data in TimeSeasonSequential but time_sequencing parameter set to {model.TimeSequencing.first()} ' - 'and inter-season features used. TimeSeasonSequential must be filled for this type of time ' + f'No data in time_season_sequential but time_sequencing parameter set to {model.time_sequencing.first()} ' + 'and inter-season features used. time_season_sequential must be filled for this type of time ' 'sequencing if seasonal storage or inter-season constraints like RampUp/RampDown are used. Check ' 'the config file.' ) @@ -347,15 +349,15 @@ def create_time_season_sequential(model: TemoaModel) -> None: sequential: dict[tuple[int, str], float] = {} prev_n: float = 0 - for p, s_seq, s in model.TimeSeasonSequential.sparse_iterkeys(): - num_days: float = value(model.TimeSeasonSequential[p, s_seq, s]) + for p, s_seq, s in model.time_season_sequential.sparse_iterkeys(): + num_days: float = value(model.time_season_sequential[p, s_seq, s]) if ( - model.TimeSequencing.first() == 'consecutive_days' + model.time_sequencing.first() == 'consecutive_days' and prev_n and abs(num_days - prev_n) >= 0.001 ): msg = ( - 'TimeSequencing set to consecutive_days but two consecutive seasons do not represent the same ' + 'time_sequencing set to consecutive_days but two consecutive seasons do not represent the same ' f'number of days. This discontinuity will lead to bad model behaviour: {p, s}, days: {num_days}. ' f'Previous number of days: {prev_n}. Check the config file for more information.' ) @@ -368,47 +370,47 @@ def create_time_season_sequential(model: TemoaModel) -> None: sequential[p, s] = 0 sequential[p, s] += num_days - # Check that TimeSeasonSequential num_days total to number of days in each period + # Check that time_season_sequential num_days total to number of days in each period count_total: dict[ int, float - ] = {} # {p: n} total days per period according to TimeSeasonSequential + ] = {} # {p: n} total days per period according to time_season_sequential for p in model.time_optimize: count_total[p] = sum(sequential[p, s] for _p, s in sequential if _p == p) - if abs(count_total[p] - value(model.DaysPerPeriod)) >= 0.001: + if abs(count_total[p] - value(model.days_per_period)) >= 0.001: logger.warning( - f'Sum of num_days in TimeSeasonSequential ({count_total[p]}) ' - f'for period {p} does not sum to days_per_period ({value(model.DaysPerPeriod)}) ' + f'Sum of num_days in time_season_sequential ({count_total[p]}) ' + f'for period {p} does not sum to days_per_period ({value(model.days_per_period)}) ' 'from the MetaData table.' ) # Check that seasons using in storage seasons are actual seasons for p, s in sequential: - if (p, s) not in model.SegFracPerSeason: + if (p, s) not in model.segment_fraction_per_season: msg = ( f'Period-season index {(p, s)} that does not exist in ' - 'TimeSegmentFraction referenced in TimeSeasonSequential .' + 'TimeSegmentFraction referenced in time_season_sequential .' ) logger.error(msg) raise ValueError(msg) - for p, s in model.SegFracPerSeason.sparse_iterkeys(): - if s not in model.TimeSeason[p]: + for p, s in model.segment_fraction_per_season.sparse_iterkeys(): + if s not in model.time_season[p]: continue # Check that all seasons are used in sequential seasons if (p, s) not in sequential: - msg = f'Period-season index {(p, s)} absent from TimeSeasonSequential' + msg = f'Period-season index {(p, s)} absent from time_season_sequential' logger.warning(msg) # Check that the two tables agree on the total seasonal composition of each period - segfrac = value(model.SegFracPerSeason[p, s]) + segfrac = value(model.segment_fraction_per_season[p, s]) segfracseq = sequential[p, s] / count_total[p] if abs(segfrac - segfracseq) >= 0.001: msg = ( 'Discrepancy of total period-season composition between ' - 'TimeSegmentFraction and TimeSeasonSequential. Total fraction of each ' + 'TimeSegmentFraction and time_season_sequential. Total fraction of each ' 'period assigned to each season should match: ' - f'TimeSegmentFraction: {(p, s, value(model.SegFracPerSeason[p, s]))}' - f', TimeSeasonSequential: {(p, s, segfracseq)}' + f'TimeSegmentFraction: {(p, s, value(model.segment_fraction_per_season[p, s]))}' + f', time_season_sequential: {(p, s, segfracseq)}' ) logger.warning(msg) diff --git a/temoa/components/utils.py b/temoa/components/utils.py index a56c1ae33..1f6a383a5 100644 --- a/temoa/components/utils.py +++ b/temoa/components/utils.py @@ -65,18 +65,18 @@ def get_variable_efficiency( Calculates the effective efficiency for a process in a specific time slice. This function handles time-varying efficiencies. It checks a pre-computed boolean, - `M.isEfficiencyVariable`, to determine if a variable efficiency is defined for + `M.is_efficiency_variable`, to determine if a variable efficiency is defined for the given process. - - If True, it returns `Efficiency * EfficiencyVariable`. - - If False, it returns the base `Efficiency`. + - If True, it returns `efficiency * efficiency_variable`. + - If False, it returns the base `efficiency`. This dictionary-lookup approach is used for performance, as it is much faster than repeatedly checking the indices of a large Pyomo parameter during model build. """ - if model.isEfficiencyVariable.get((r, p, i, t, v, o), False): - return value(model.Efficiency[r, i, t, v, o]) * value( - model.EfficiencyVariable[r, p, s, d, i, t, v, o] + if model.is_efficiency_variable.get((r, p, i, t, v, o), False): + return value(model.efficiency[r, i, t, v, o]) * value( + model.efficiency_variable[r, p, s, d, i, t, v, o] ) else: - return value(model.Efficiency[r, i, t, v, o]) + return value(model.efficiency[r, i, t, v, o]) diff --git a/temoa/core/model.py b/temoa/core/model.py index fefb811cf..6056002bf 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -9,7 +9,6 @@ """ import logging -from typing import TYPE_CHECKING from pyomo.core import BuildCheck, Set, Var from pyomo.environ import ( @@ -23,14 +22,6 @@ minimize, ) -from temoa.types.core_types import Technology - -if TYPE_CHECKING: - from pyomo.environ import AbstractModel as PyomoAbstractModel - -else: - PyomoAbstractModel = AbstractModel # type: ignore[misc,assignment] - from temoa import types as t from temoa.components import ( capacity, @@ -56,6 +47,7 @@ validate_reserve_margin, validate_tech_sets, ) +from temoa.types.core_types import Technology logger = logging.getLogger(__name__) @@ -67,7 +59,7 @@ def create_sparse_dicts(model: 'TemoaModel') -> None: """ # Call the decomposed functions in logical order - # 1. Populate core relationships from Efficiency table + # 1. Populate core relationships from efficiency table technology.populate_core_dictionaries(model) # 2. Classify technologies and commodities @@ -88,13 +80,13 @@ def create_sparse_dicts(model: 'TemoaModel') -> None: for tech in sorted(unused_techs): logger.warning( f"Notice: '{tech}' is specified as a technology but is not " - 'utilized in the Efficiency parameter.' + 'utilized in the efficiency parameter.' ) logger.debug('Completed creation of SparseDicts') -class TemoaModel(PyomoAbstractModel): +class TemoaModel(AbstractModel): """ An instance of the abstract Temoa model """ @@ -103,69 +95,69 @@ class TemoaModel(PyomoAbstractModel): default_lifetime_tech = 40 def __init__(self, *args: object, **kwargs: object) -> None: - PyomoAbstractModel.__init__(self, *args, **kwargs) + AbstractModel.__init__(self, *args, **kwargs) ################################################ # Internally used Data Containers # # (not formal model elements) # ################################################ - self.processInputs: t.ProcessInputsDict = {} - self.processOutputs: t.ProcessOutputsDict = {} - self.processLoans: t.ProcessLoansDict = {} - self.activeFlow_rpsditvo: t.ActiveFlowSet = set() + self.process_inputs: t.ProcessInputsDict = {} + self.process_outputs: t.ProcessOutputsDict = {} + self.process_loans: t.ProcessLoansDict = {} + self.active_flow_rpsditvo: t.ActiveFlowSet = set() """a flow index for techs NOT in tech_annual""" - self.activeFlow_rpitvo: t.ActiveFlowAnnualSet = set() + self.active_flow_rpitvo: t.ActiveFlowAnnualSet = set() """a flow index for techs in tech_annual only""" - self.activeFlex_rpsditvo: t.ActiveFlexSet = set() - self.activeFlex_rpitvo: t.ActiveFlexAnnualSet = set() - self.activeFlowInStorage_rpsditvo: t.ActiveFlowInStorageSet = set() - self.activeCurtailment_rpsditvo: t.ActiveCurtailmentSet = set() - self.activeActivity_rptv: t.ActiveActivitySet = set() - self.storageLevelIndices_rpsdtv: t.StorageLevelIndicesSet = set() - self.seasonalStorageLevelIndices_rpstv: t.SeasonalStorageLevelIndicesSet = set() - """currently available (within lifespan) (r, p, t, v) tuples (from model.processVintages)""" + self.active_flex_rpsditvo: t.ActiveFlexSet = set() + self.active_flex_rpitvo: t.ActiveFlexAnnualSet = set() + self.active_flow_in_storage_rpsditvo: t.ActiveFlowInStorageSet = set() + self.active_curtailment_rpsditvo: t.ActiveCurtailmentSet = set() + self.active_activity_rptv: t.ActiveActivitySet = set() + self.storage_level_indices_rpsdtv: t.StorageLevelIndicesSet = set() + self.seasonal_storage_level_indices_rpstv: t.SeasonalStorageLevelIndicesSet = set() + """currently available (within lifespan) (r, p, t, v) tuples (from model.process_vintages)""" - self.activeRegionsForTech: t.ActiveRegionsForTechDict = {} + self.active_regions_for_tech: t.ActiveRegionsForTechDict = {} """currently available regions by period and tech {(p, t) : r}""" - self.newCapacity_rtv: t.NewCapacitySet = set() - self.activeCapacityAvailable_rpt: t.ActiveCapacityAvailableSet = set() - self.activeCapacityAvailable_rptv: t.ActiveCapacityAvailableVintageSet = set() - self.groupRegionActiveFlow_rpt: t.GroupRegionActiveFlowSet = ( + self.new_capacity_rtv: t.NewCapacitySet = set() + self.active_capacity_available_rpt: t.ActiveCapacityAvailableSet = set() + self.active_capacity_available_rptv: t.ActiveCapacityAvailableVintageSet = set() + self.group_region_active_flow_rpt: t.GroupRegionActiveFlowSet = ( set() # Set of valid group-region, period, tech indices ) self.commodityBalance_rpc: t.CommodityBalancedSet = ( set() ) # Set of valid region-period-commodity indices to balance - self.commodityDStreamProcess: t.CommodityStreamProcessDict = {} # The downstream process of a commodity during a period - self.commodityUStreamProcess: t.CommodityStreamProcessDict = {} # The upstream process of a commodity during a period - self.capacityConsumptionTechs: t.CapacityConsumptionTechsDict = {} # New capacity consuming a commodity during a period [r,p,c] -> t - self.retirementProductionProcesses: t.RetirementProductionProcessesDict = {} # Retired capacity producing a commodity during a period [r,p,c] -> t,v - self.processInputsByOutput: t.ProcessInputsByOutputDict = {} - self.processOutputsByInput: t.ProcessOutputsByInputDict = {} - self.processTechs: t.ProcessTechsDict = {} - self.processReservePeriods: t.ProcessReservePeriodsDict = {} - self.processPeriods: t.ProcessPeriodsDict = {} # {(r, t, v): set(p)} - self.retirementPeriods: t.RetirementPeriodsDict = {} # {(r, t, v): set(p)} periods in which a process can economically or naturally retire - self.processVintages: t.ProcessVintagesDict = {} - self.survivalCurvePeriods: t.SurvivalCurvePeriodsDict = {} # {(r, t, v): set(p)} periods for which the process has a defined survival fraction + self.commodity_down_stream_process: t.CommodityStreamProcessDict = {} # The downstream process of a commodity during a period + self.commodity_up_stream_process: t.CommodityStreamProcessDict = {} # The upstream process of a commodity during a period + self.capacity_consumption_techs: t.CapacityConsumptionTechsDict = {} # New capacity consuming a commodity during a period [r,p,c] -> t + self.retirement_production_processes: t.RetirementProductionProcessesDict = {} # Retired capacity producing a commodity during a period [r,p,c] -> t,v + self.process_inputs_by_output: t.ProcessInputsByOutputDict = {} + self.process_outputs_by_input: t.ProcessOutputsByInputDict = {} + self.process_techs: t.ProcessTechsDict = {} + self.process_reserve_periods: t.ProcessReservePeriodsDict = {} + self.process_periods: t.ProcessPeriodsDict = {} # {(r, t, v): set(p)} + self.retirement_periods: t.RetirementPeriodsDict = {} # {(r, t, v): set(p)} periods in which a process can economically or naturally retire + self.process_vintages: t.ProcessVintagesDict = {} + self.survival_curve_periods: t.SurvivalCurvePeriodsDict = {} # {(r, t, v): set(p)} periods for which the process has a defined survival fraction """current available (within lifespan) vintages {(r, p, t) : set(v)}""" - self.baseloadVintages: t.BaseloadVintagesDict = {} - self.curtailmentVintages: t.CurtailmentVintagesDict = {} - self.storageVintages: t.StorageVintagesDict = {} - self.rampUpVintages: t.RampUpVintagesDict = {} - self.rampDownVintages: t.RampDownVintagesDict = {} - self.inputSplitVintages: t.InputSplitVintagesDict = {} - self.inputSplitAnnualVintages: t.InputSplitAnnualVintagesDict = {} - self.outputSplitVintages: t.OutputSplitVintagesDict = {} - self.outputSplitAnnualVintages: t.OutputSplitAnnualVintagesDict = {} + self.baseload_vintages: t.BaseloadVintagesDict = {} + self.curtailment_vintages: t.CurtailmentVintagesDict = {} + self.storage_vintages: t.StorageVintagesDict = {} + self.ramp_up_vintages: t.RampUpVintagesDict = {} + self.ramp_down_vintages: t.RampDownVintagesDict = {} + self.input_split_vintages: t.InputSplitVintagesDict = {} + self.input_split_annual_vintages: t.InputSplitAnnualVintagesDict = {} + self.output_split_vintages: t.OutputSplitVintagesDict = {} + self.output_split_annual_vintages: t.OutputSplitAnnualVintagesDict = {} # M.processByPeriodAndOutput = {} # not currently used - self.exportRegions: t.ExportRegionsDict = {} - self.importRegions: t.ImportRegionsDict = {} + self.export_regions: t.ExportRegionsDict = {} + self.import_regions: t.ImportRegionsDict = {} # These establish time sequencing self.time_next: t.TimeNextDict = {} # {(p, s, d): (s_next, d_next)} sequence of following time slices @@ -177,10 +169,10 @@ def __init__(self, *args: object, **kwargs: object) -> None: # (to avoid slow searches in initialisation) # ################################################ - self.isEfficiencyVariable: t.EfficiencyVariableDict = {} # {(r, p, i, t, v, o): bool} which efficiencies have variable indexing - self.isCapacityFactorProcess: t.CapacityFactorProcessDict = {} # {(r, p, t, v): bool} which capacity factors have have period-vintage indexing - self.isSeasonalStorage: t.SeasonalStorageDict = {} # {t: bool} whether a storage tech is seasonal storage - self.isSurvivalCurveProcess: t.SurvivalCurveProcessDict = {} # {(r, t, v): bool} whether a process uses survival curves. + self.is_efficiency_variable: t.EfficiencyVariableDict = {} # {(r, p, i, t, v, o): bool} which efficiencies have variable indexing + self.is_capacity_factor_process: t.CapacityFactorProcessDict = {} # {(r, p, t, v): bool} which capacity factors have have period-vintage indexing + self.is_seasonal_storage: t.SeasonalStorageDict = {} # {t: bool} whether a storage tech is seasonal storage + self.is_survival_curve_process: t.SurvivalCurveProcessDict = {} # {(r, t, v): bool} whether a process uses survival curves. ################################################ # Model Sets # @@ -205,25 +197,25 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.validate_time = BuildAction(rule=time.validate_time) # Define the model time slices - self.time_season = Set(ordered=True, validate=no_slash_or_pipe) - self.time_season_sequential = Set(ordered=True, validate=no_slash_or_pipe) - self.TimeSeason = Set(self.time_optimize, within=self.time_season, ordered=True) + self.time_season_all = Set(ordered=True, validate=no_slash_or_pipe) + self.time_season_to_sequential = Set(ordered=True, validate=no_slash_or_pipe) + self.time_season = Set(self.time_optimize, within=self.time_season_all, ordered=True) self.time_of_day = Set(ordered=True, validate=no_slash_or_pipe) # This is just to get the TimeStorageSeason table sequentially. # There must be a better way but this works for now self.ordered_season_sequential = Set( dimen=3, - within=self.time_optimize * self.time_season_sequential * self.time_season, + within=self.time_optimize * self.time_season_to_sequential * self.time_season_all, ordered=True, ) # Define regions self.regions = Set(validate=region_check) - # RegionalIndices is the set of all the possible combinations of interregional exchanges + # regional_indices is the set of all the possible combinations of interregional exchanges # plus original region indices. If tech_exchange is empty, RegionalIndices =regions. - self.regionalIndices = Set(initialize=geography.create_regional_indices) - self.regionalGlobalIndices = Set(validate=region_group_check) + self.regional_indices = Set(initialize=geography.create_regional_indices) + self.regional_global_indices = Set(validate=region_group_check) # Define technology-related sets # M.tech_resource = Set() # not actually used by @@ -259,7 +251,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: """techs with existing capacity, want to keep these for accounting reasons""" self.used_techs: set[Technology] = set() - """ track techs used in Efficiency table used in create_sparse_dicts """ + """ track techs used in efficiency table used in create_sparse_dicts """ # the below is a convenience for domain checking in params below that should not accept # uncap techs... @@ -313,72 +305,72 @@ def __init__(self, *args: object, **kwargs: object) -> None: # these "progress markers" report build progress in the log, if the level == debug self.progress_marker_2 = BuildAction(['Starting to build Params'], rule=progress_check) - self.GlobalDiscountRate = Param(default=0.05) + self.global_discount_rate = Param(default=0.05) # Define time-related parameters - self.PeriodLength = Param(self.time_optimize, initialize=time.param_period_length) - self.SegFrac = Param(self.time_optimize, self.time_season, self.time_of_day) - self.validate_SegFrac = BuildAction(rule=time.validate_segment_fraction) - self.TimeSequencing = Set() # How do states carry between time segments? - self.TimeNext = Set( + self.period_length = Param(self.time_optimize, initialize=time.param_period_length) + self.segment_fraction = Param(self.time_optimize, self.time_season_all, self.time_of_day) + self.validate_segment_fraction = BuildAction(rule=time.validate_segment_fraction) + self.time_sequencing = Set() # How do states carry between time segments? + self.time_manual = Set( ordered=True ) # This is just to get data from the table. Hidden feature and usually not used - self.validate_TimeNext = BuildAction(rule=time.validate_time_next) + self.validate_time_next = BuildAction(rule=time.validate_time_manual) # Define demand- and resource-related parameters # Dev Note: There does not appear to be a DB table supporting DemandDefaultDistro. # This does not cause any problems, so let it be for now. - # Doesn't seem to be much point in the table. Just clones SegFrac + # Doesn't seem to be much point in the table. Just clones segment_fraction # M.DemandDefaultDistribution = Param( # M.time_optimize, M.time_season, M.time_of_day, mutable=True # ) - self.DemandSpecificDistribution = Param( + self.demand_specific_distribution = Param( self.regions, self.time_optimize, - self.time_season, + self.time_season_all, self.time_of_day, self.commodity_demand, mutable=True, default=0, ) - self.DemandConstraint_rpc = Set( + self.demand_constraint_rpc = Set( within=self.regions * self.time_optimize * self.commodity_demand ) - self.Demand = Param(self.DemandConstraint_rpc) + self.demand = Param(self.demand_constraint_rpc) # Dev Note: This parameter is currently NOT implemented. Preserved for later refactoring - # LimitResource IS implemented but sums cumulatively for a technology rather than + # limit_resource IS implemented but sums cumulatively for a technology rather than # resource commodity # M.ResourceConstraint_rpr = Set(within=M.regions * M.time_optimize * M.commodity_physical) # M.ResourceBound = Param(M.ResourceConstraint_rpr) # Define technology performance parameters - self.CapacityToActivity = Param(self.regionalIndices, self.tech_all, default=1) + self.capacity_to_activity = Param(self.regional_indices, self.tech_all, default=1) - self.ExistingCapacity = Param(self.regionalIndices, self.tech_exist, self.vintage_exist) + self.existing_capacity = Param(self.regional_indices, self.tech_exist, self.vintage_exist) # Dev Note: The below is temporarily useful for passing down to validator to find # set violations # Uncomment this assignment, and comment out the orig below it... - # M.Efficiency = Param( + # M.efficiency = Param( # Any, Any, Any, Any, Any, - # within=NonNegativeReals, validate=validate_Efficiency + # within=NonNegativeReals, validate=validate_efficiency # ) - # devnote: need these here or CheckEfficiencyIndices may flag these commodities as unused - self.ConstructionInput = Param( + # devnote: need these here or CheckefficiencyIndices may flag these commodities as unused + self.construction_input = Param( self.regions, self.commodity_physical, self.tech_with_capacity, self.vintage_optimize, ) - self.EndOfLifeOutput = Param( + self.end_of_life_output = Param( self.regions, self.tech_with_capacity, self.vintage_all, self.commodity_carrier ) - self.Efficiency = Param( - self.regionalIndices, + self.efficiency = Param( + self.regional_indices, self.commodity_physical, self.tech_all, self.vintage_all, @@ -386,12 +378,14 @@ def __init__(self, *args: object, **kwargs: object) -> None: within=NonNegativeReals, validate=validate_efficiency, ) - self.validate_UsedEfficiencyIndices = BuildAction(rule=technology.check_efficiency_indices) + self.validate_used_efficiency_indices = BuildAction( + rule=technology.check_efficiency_indices + ) - self.EfficiencyVariable = Param( - self.regionalIndices, + self.efficiency_variable = Param( + self.regional_indices, self.time_optimize, - self.time_season, + self.time_season_all, self.time_of_day, self.commodity_physical, self.tech_all, @@ -401,17 +395,17 @@ def __init__(self, *args: object, **kwargs: object) -> None: default=1, ) - self.LifetimeTech = Param( - self.regionalIndices, self.tech_all, default=TemoaModel.default_lifetime_tech + self.lifetime_tech = Param( + self.regional_indices, self.tech_all, default=TemoaModel.default_lifetime_tech ) - self.LifetimeProcess_rtv = Set(dimen=3, initialize=technology.lifetime_process_indices) - self.LifetimeProcess = Param( - self.LifetimeProcess_rtv, default=technology.get_default_process_lifetime + self.lifetime_process_rtv = Set(dimen=3, initialize=technology.lifetime_process_indices) + self.lifetime_process = Param( + self.lifetime_process_rtv, default=technology.get_default_process_lifetime ) - self.LifetimeSurvivalCurve = Param( - self.regionalIndices, + self.lifetime_survival_curve = Param( + self.regional_indices, Integers, self.tech_all, self.vintage_all, @@ -419,18 +413,22 @@ def __init__(self, *args: object, **kwargs: object) -> None: validate=validate_0to1, mutable=True, ) - self.Create_SurvivalCurve = BuildAction(rule=technology.create_survival_curve) + self.create_survival_curve = BuildAction(rule=technology.create_survival_curve) - self.LoanLifetimeProcess_rtv = Set(dimen=3, initialize=costs.lifetime_loan_process_indices) + self.loan_lifetime_process_rtv = Set( + dimen=3, initialize=costs.lifetime_loan_process_indices + ) - # Dev Note: The LoanLifetimeProcess table *could* be removed. There is no longer a + # Dev Note: The loan_lifetime_process table *could* be removed. There is no longer a # supporting table in the database. It is just a "passthrough" now to the - # default LoanLifetimeTech. It is already stitched in to the model, + # default Loanlifetime_tech. It is already stitched in to the model, # so will leave it for now. Table may be revived. - self.LoanLifetimeProcess = Param(self.LoanLifetimeProcess_rtv, default=costs.get_loan_life) + self.loan_lifetime_process = Param( + self.loan_lifetime_process_rtv, default=costs.get_loan_life + ) - self.LimitTechInputSplit = Param( + self.limit_tech_input_split = Param( self.regions, self.time_optimize, self.commodity_physical, @@ -438,7 +436,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.operator, validate=validate_0to1, ) - self.LimitTechInputSplitAnnual = Param( + self.limit_tech_input_split_annual = Param( self.regions, self.time_optimize, self.commodity_physical, @@ -447,7 +445,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: validate=validate_0to1, ) - self.LimitTechOutputSplit = Param( + self.limit_tech_output_split = Param( self.regions, self.time_optimize, self.tech_all, @@ -455,7 +453,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.operator, validate=validate_0to1, ) - self.LimitTechOutputSplitAnnual = Param( + self.limit_tech_output_split_annual = Param( self.regions, self.time_optimize, self.tech_all, @@ -464,274 +462,252 @@ def __init__(self, *args: object, **kwargs: object) -> None: validate=validate_0to1, ) - self.RenewablePortfolioStandardConstraint_rpg = Set( + self.renewable_portfolio_standard_constraint_rpg = Set( within=self.regions * self.time_optimize * self.tech_group_names ) - self.RenewablePortfolioStandard = Param( - self.RenewablePortfolioStandardConstraint_rpg, validate=validate_0to1 + self.renewable_portfolio_standard = Param( + self.renewable_portfolio_standard_constraint_rpg, validate=validate_0to1 ) - # These need to come before validate_SeasonSequential - self.RampUpHourly = Param(self.regions, self.tech_upramping, validate=validate_0to1) - self.RampDownHourly = Param(self.regions, self.tech_downramping, validate=validate_0to1) + # These need to come before validate_season_sequential + self.ramp_up_hourly = Param(self.regions, self.tech_upramping, validate=validate_0to1) + self.ramp_down_hourly = Param(self.regions, self.tech_downramping, validate=validate_0to1) # Set up representation of time - self.DaysPerPeriod = Param() - self.SegFracPerSeason = Param( - self.time_optimize, self.time_season, initialize=time.seg_frac_per_season_rule + self.days_per_period = Param() + self.segment_fraction_per_season = Param( + self.time_optimize, + self.time_season_all, + initialize=time.segment_fraction_per_season_rule, ) - self.TimeSeasonSequential = Param( - self.time_optimize, self.time_season_sequential, self.time_season, mutable=True + self.time_season_sequential = Param( + self.time_optimize, self.time_season_to_sequential, self.time_season_all, mutable=True ) - self.validate_SeasonSequential = BuildAction(rule=time.create_time_season_sequential) - self.Create_TimeSequence = BuildAction(rule=time.create_time_sequence) + self.validate_season_sequential = BuildAction(rule=time.create_time_season_to_sequential) + self.create_time_sequence = BuildAction(rule=time.create_time_sequence) # The method below creates a series of helper functions that are used to # perform the sparse matrix of indexing for the parameters, variables, and # equations below. - self.Create_SparseDicts = BuildAction(rule=create_sparse_dicts) - self.initialize_Demands = BuildAction(rule=commodities.create_demands) + self.create_sparse_dicts = BuildAction(rule=create_sparse_dicts) + self.initialize_demands = BuildAction(rule=commodities.create_demands) - self.CapacityFactor_rpsdt = Set(dimen=5, initialize=capacity.capacity_factor_tech_indices) - self.CapacityFactorTech = Param( - self.CapacityFactor_rpsdt, default=1, validate=validate_0to1 + self.capacity_factor_rpsdt = Set(dimen=5, initialize=capacity.capacity_factor_tech_indices) + self.capacity_factor_tech = Param( + self.capacity_factor_rpsdt, default=1, validate=validate_0to1 ) # Dev note: using a default function below alleviates need to make this set. - # M.CapacityFactor_rsdtv = Set(dimen=5, initialize=CapacityFactorProcessIndices) - self.CapacityFactorProcess = Param( - self.regionalIndices, + # M.CapacityFactor_rsdtv = Set(dimen=5, initialize=capacity_factor_processIndices) + self.capacity_factor_process = Param( + self.regional_indices, self.time_optimize, - self.time_season, + self.time_season_all, self.time_of_day, self.tech_with_capacity, self.vintage_all, - # validate=validate_CapacityFactorProcess, # opting for a quicker validation, just 0->1 + # validate=validate_capacity_factor_process, # opting for a quicker validation, just 0->1 validate=validate_0to1, default=capacity.get_default_capacity_factor, # slow but only called if a value is missing ) - self.CapacityConstraint_rpsdtv = Set( + self.capacity_constraint_rpsdtv = Set( dimen=6, initialize=capacity.capacity_constraint_indices ) self.initialize_CapacityFactors = BuildAction(rule=capacity.check_capacity_factor_process) - self.initialize_EfficiencyVariable = BuildAction(rule=technology.check_efficiency_variable) + self.initialize_efficiency_variable = BuildAction(rule=technology.check_efficiency_variable) # Define technology cost parameters - # dev note: the CostFixed_rptv isn't truly needed, but it is included in a constraint, so + # dev note: the cost_fixed_rptv isn't truly needed, but it is included in a constraint, so # let it go for now - self.CostFixed_rptv = Set(dimen=4, initialize=costs.cost_fixed_indices) - self.CostFixed = Param(self.CostFixed_rptv) + self.cost_fixed_rptv = Set(dimen=4, initialize=costs.cost_fixed_indices) + self.cost_fixed = Param(self.cost_fixed_rptv) - self.CostInvest_rtv = Set(within=self.regionalIndices * self.tech_all * self.time_optimize) - self.CostInvest = Param(self.CostInvest_rtv) + self.cost_invest_rtv = Set( + within=self.regional_indices * self.tech_all * self.time_optimize + ) + self.cost_invest = Param(self.cost_invest_rtv) - self.DefaultLoanRate = Param(domain=NonNegativeReals) - self.LoanRate = Param( - self.CostInvest_rtv, domain=NonNegativeReals, default=costs.get_default_loan_rate + self.default_loan_rate = Param(domain=NonNegativeReals) + self.loan_rate = Param( + self.cost_invest_rtv, domain=NonNegativeReals, default=costs.get_default_loan_rate + ) + self.loan_annualize = Param( + self.cost_invest_rtv, initialize=costs.param_loan_annualize_rule ) - self.LoanAnnualize = Param(self.CostInvest_rtv, initialize=costs.param_loan_annualize_rule) - self.CostVariable_rptv = Set(dimen=4, initialize=costs.cost_variable_indices) - self.CostVariable = Param(self.CostVariable_rptv) + self.cost_variable_rptv = Set(dimen=4, initialize=costs.cost_variable_indices) + self.cost_variable = Param(self.cost_variable_rptv) - self.CostEmission_rpe = Set( + self.cost_emission_rpe = Set( within=self.regions * self.time_optimize * self.commodity_emissions ) - self.CostEmission = Param(self.CostEmission_rpe) + self.cost_emission = Param(self.cost_emission_rpe) - # devnote: no longer used - # M.ModelProcessLife_rptv = Set(dimen=4, initialize=ModelProcessLifeIndices) - # M.ModelProcessLife = Param(M.ModelProcessLife_rptv, initialize=ParamModelProcessLife_rule) - - self.ProcessLifeFrac_rptv = Set(dimen=4, initialize=technology.model_process_life_indices) - self.ProcessLifeFrac = Param( - self.ProcessLifeFrac_rptv, initialize=technology.param_process_life_fraction_rule + self.process_life_frac_rptv = Set(dimen=4, initialize=technology.model_process_life_indices) + self.process_life_frac = Param( + self.process_life_frac_rptv, initialize=technology.param_process_life_fraction_rule ) - self.LimitCapacityConstraint_rpt = Set( - within=self.regionalGlobalIndices + self.limit_capacity_constraint_rpt = Set( + within=self.regional_global_indices * self.time_optimize * self.tech_or_group * self.operator ) - self.LimitCapacity = Param(self.LimitCapacityConstraint_rpt) + self.limit_capacity = Param(self.limit_capacity_constraint_rpt) - self.LimitNewCapacityConstraint_rpt = Set( - within=self.regionalGlobalIndices + self.limit_new_capacity_constraint_rpt = Set( + within=self.regional_global_indices * self.time_optimize * self.tech_or_group * self.operator ) - self.LimitNewCapacity = Param(self.LimitNewCapacityConstraint_rpt) + self.limit_new_capacity = Param(self.limit_new_capacity_constraint_rpt) - self.LimitResourceConstraint_rt = Set( - within=self.regionalGlobalIndices * self.tech_or_group * self.operator + self.limit_resource_constraint_rt = Set( + within=self.regional_global_indices * self.tech_or_group * self.operator ) - self.LimitResource = Param(self.LimitResourceConstraint_rt) + self.limit_resource = Param(self.limit_resource_constraint_rt) - self.LimitActivityConstraint_rpt = Set( - within=self.regionalGlobalIndices + self.limit_activity_constraint_rpt = Set( + within=self.regional_global_indices * self.time_optimize * self.tech_or_group * self.operator ) - self.LimitActivity = Param(self.LimitActivityConstraint_rpt) + self.limit_activity = Param(self.limit_activity_constraint_rpt) - self.LimitSeasonalCapacityFactorConstraint_rpst = Set( - within=self.regionalGlobalIndices + self.limit_seasonal_capacity_factor_constraint_rpst = Set( + within=self.regional_global_indices * self.time_optimize - * self.time_season + * self.time_season_all * self.tech_all * self.operator ) - self.LimitSeasonalCapacityFactor = Param( - self.LimitSeasonalCapacityFactorConstraint_rpst, validate=validate_0to1 + self.limit_seasonal_capacity_factor = Param( + self.limit_seasonal_capacity_factor_constraint_rpst, validate=validate_0to1 ) - self.LimitAnnualCapacityFactorConstraint_rpto = Set( - within=self.regionalGlobalIndices + self.limit_annual_capacity_factor_constraint_rpto = Set( + within=self.regional_global_indices * self.time_optimize * self.tech_all * self.commodity_carrier * self.operator ) - self.LimitAnnualCapacityFactor = Param( - self.LimitAnnualCapacityFactorConstraint_rpto, validate=validate_0to1 + self.limit_annual_capacity_factor = Param( + self.limit_annual_capacity_factor_constraint_rpto, validate=validate_0to1 ) - self.LimitGrowthCapacity = Param( - self.regionalGlobalIndices, self.tech_or_group, self.operator + self.limit_growth_capacity = Param( + self.regional_global_indices, self.tech_or_group, self.operator ) - self.LimitDegrowthCapacity = Param( - self.regionalGlobalIndices, self.tech_or_group, self.operator + self.limit_degrowth_capacity = Param( + self.regional_global_indices, self.tech_or_group, self.operator ) - self.LimitGrowthNewCapacity = Param( - self.regionalGlobalIndices, self.tech_or_group, self.operator + self.limit_growth_new_capacity = Param( + self.regional_global_indices, self.tech_or_group, self.operator ) - self.LimitDegrowthNewCapacity = Param( - self.regionalGlobalIndices, self.tech_or_group, self.operator + self.limit_degrowth_new_capacity = Param( + self.regional_global_indices, self.tech_or_group, self.operator ) - self.LimitGrowthNewCapacityDelta = Param( - self.regionalGlobalIndices, self.tech_or_group, self.operator + self.limit_growth_new_capacity_delta = Param( + self.regional_global_indices, self.tech_or_group, self.operator ) - self.LimitDegrowthNewCapacityDelta = Param( - self.regionalGlobalIndices, self.tech_or_group, self.operator + self.limit_degrowth_new_capacity_delta = Param( + self.regional_global_indices, self.tech_or_group, self.operator ) - self.LimitEmissionConstraint_rpe = Set( - within=self.regionalGlobalIndices + self.limit_emission_constraint_rpe = Set( + within=self.regional_global_indices * self.time_optimize * self.commodity_emissions * self.operator ) - self.LimitEmission = Param(self.LimitEmissionConstraint_rpe) - self.EmissionActivity_reitvo = Set(dimen=6, initialize=emissions.emission_activity_indices) - self.EmissionActivity = Param(self.EmissionActivity_reitvo) - - # devnote: deprecated when generalising tech/group columns in Limit tables - # M.LimitActivityGroupConstraint_rpg = Set( - # within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names * M.operator - # ) - # M.LimitActivityGroup = Param(M.LimitActivityGroupConstraint_rpg) - - # M.LimitCapacityGroupConstraint_rpg = Set( - # within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names * M.operator - # ) - # M.LimitCapacityGroup = Param(M.LimitCapacityGroupConstraint_rpg) + self.limit_emission = Param(self.limit_emission_constraint_rpe) + self.emission_activity_reitvo = Set(dimen=6, initialize=emissions.emission_activity_indices) + self.emission_activity = Param(self.emission_activity_reitvo) - # M.LimitNewCapacityGroupConstraint_rpg = Set( - # within=M.regionalGlobalIndices * M.time_optimize * M.tech_group_names * M.operator - # ) - # M.LimitNewCapacityGroup = Param(M.LimitNewCapacityGroupConstraint_rpg) - # M.GroupShareIndices = Set(dimen=5, initialize=GroupShareIndices) # doesn't feel worth it - - self.LimitCapacityShareConstraint_rpgg = Set( - within=self.regionalGlobalIndices + self.limit_capacity_share_constraint_rpgg = Set( + within=self.regional_global_indices * self.time_optimize * self.tech_or_group * self.tech_or_group * self.operator ) - self.LimitCapacityShare = Param(self.LimitCapacityShareConstraint_rpgg) + self.limit_capacity_share = Param(self.limit_capacity_share_constraint_rpgg) - self.LimitActivityShareConstraint_rpgg = Set( - within=self.regionalGlobalIndices + self.limit_activity_share_constraint_rpgg = Set( + within=self.regional_global_indices * self.time_optimize * self.tech_or_group * self.tech_or_group * self.operator ) - self.LimitActivityShare = Param(self.LimitActivityShareConstraint_rpgg) + self.limit_activity_share = Param(self.limit_activity_share_constraint_rpgg) - self.LimitNewCapacityShareConstraint_rpgg = Set( - within=self.regionalGlobalIndices + self.limit_new_capacity_share_constraint_rpgg = Set( + within=self.regional_global_indices * self.time_optimize * self.tech_or_group * self.tech_or_group * self.operator ) - self.LimitNewCapacityShare = Param(self.LimitNewCapacityShareConstraint_rpgg) - - # devnote: deprecated when generalising tech/group columns in Limit tables - # M.TwoGroupShareIndices = Set(dimen=5, initialize=TwoGroupShareIndices) - - # M.LimitNewCapacityGroupShareConstraint_rpgg = Set(within=M.TwoGroupShareIndices) - # M.LimitNewCapacityGroupShare = Param(M.TwoGroupShareIndices) - - # M.LimitActivityGroupShareConstraint_rpgg = Set(within=M.TwoGroupShareIndices) - # M.LimitActivityGroupShare = Param(M.TwoGroupShareIndices) + self.limit_new_capacity_share = Param(self.limit_new_capacity_share_constraint_rpgg) # This set works for all storage-related constraints - self.StorageConstraints_rpsdtv = Set(dimen=6, initialize=storage.storage_constraint_indices) - self.SeasonalStorageConstraints_rpsdtv = Set( + self.storage_constraints_rpsdtv = Set( + dimen=6, initialize=storage.storage_constraint_indices + ) + self.seasonal_storage_constraints_rpsdtv = Set( dimen=6, initialize=storage.seasonal_storage_constraint_indices ) - self.LimitStorageFractionConstraint_rpsdtv = Set( - within=(self.StorageConstraints_rpsdtv | self.SeasonalStorageConstraints_rpsdtv) + self.limit_storage_fraction_constraint_rpsdtv = Set( + within=(self.storage_constraints_rpsdtv | self.seasonal_storage_constraints_rpsdtv) * self.operator ) - self.LimitStorageFraction = Param( - self.LimitStorageFractionConstraint_rpsdtv, validate=validate_0to1 + self.limit_storage_fraction = Param( + self.limit_storage_fraction_constraint_rpsdtv, validate=validate_0to1 ) # Storage duration is expressed in hours - self.StorageDuration = Param(self.regions, self.tech_storage, default=4) + self.storage_duration = Param(self.regions, self.tech_storage, default=4) - self.LinkedTechs = Param(self.regionalIndices, self.tech_all, self.commodity_emissions) + self.linked_techs = Param(self.regional_indices, self.tech_all, self.commodity_emissions) # Define parameters associated with electric sector operation - self.ReserveMarginMethod = Set() # How contributions to the reserve margin are calculated - self.CapacityCredit = Param( - self.regionalIndices, + self.reserve_margin_method = Set() # How contributions to the reserve margin are calculated + self.capacity_credit = Param( + self.regional_indices, self.time_optimize, self.tech_reserve, self.vintage_all, default=0, validate=validate_0to1, ) - self.ReserveCapacityDerate = Param( - self.regionalIndices, + self.reserve_capacity_derate = Param( + self.regional_indices, self.time_optimize, - self.time_season, + self.time_season_all, self.tech_reserve, self.vintage_all, default=1, validate=validate_0to1, ) - self.PlanningReserveMargin = Param(self.regions) + self.planning_reserve_margin = Param(self.regions) - self.EmissionEmbodied = Param( + self.emission_embodied = Param( self.regions, self.commodity_emissions, self.tech_with_capacity, self.vintage_optimize, ) - self.EmissionEndOfLife = Param( + self.emission_end_of_life = Param( self.regions, self.commodity_emissions, self.tech_with_capacity, self.vintage_all ) - self.MyopicDiscountingYear = Param(default=0) + self.myopic_discounting_year = Param(default=0) ################################################ # Model Variables # @@ -750,62 +726,64 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.progress_marker_3 = BuildAction(['Starting to build Variables'], rule=progress_check) # Define base decision variables - self.FlowVar_rpsditvo = Set(dimen=8, initialize=flows.flow_variable_indices) - self.V_FlowOut = Var(self.FlowVar_rpsditvo, domain=NonNegativeReals) + self.flow_var_rpsditvo = Set(dimen=8, initialize=flows.flow_variable_indices) + self.v_flow_out = Var(self.flow_var_rpsditvo, domain=NonNegativeReals) - self.FlowVarAnnual_rpitvo = Set(dimen=6, initialize=flows.flow_variable_annual_indices) - self.V_FlowOutAnnual = Var(self.FlowVarAnnual_rpitvo, domain=NonNegativeReals) + self.flow_var_annual_rpitvo = Set(dimen=6, initialize=flows.flow_variable_annual_indices) + self.v_flow_out_annual = Var(self.flow_var_annual_rpitvo, domain=NonNegativeReals) - self.FlexVar_rpsditvo = Set(dimen=8, initialize=flows.flex_variable_indices) - self.V_Flex = Var(self.FlexVar_rpsditvo, domain=NonNegativeReals) + self.flex_var_rpsditvo = Set(dimen=8, initialize=flows.flex_variable_indices) + self.v_flex = Var(self.flex_var_rpsditvo, domain=NonNegativeReals) - self.FlexVarAnnual_rpitvo = Set(dimen=6, initialize=flows.flex_variable_annual_indices) - self.V_FlexAnnual = Var(self.FlexVarAnnual_rpitvo, domain=NonNegativeReals) + self.flex_var_annual_rpitvo = Set(dimen=6, initialize=flows.flex_variable_annual_indices) + self.v_flex_annual = Var(self.flex_var_annual_rpitvo, domain=NonNegativeReals) - self.CurtailmentVar_rpsditvo = Set(dimen=8, initialize=flows.curtailment_variable_indices) - self.V_Curtailment = Var( - self.CurtailmentVar_rpsditvo, domain=NonNegativeReals, initialize=0 + self.curtailment_var_rpsditvo = Set(dimen=8, initialize=flows.curtailment_variable_indices) + self.v_curtailment = Var( + self.curtailment_var_rpsditvo, domain=NonNegativeReals, initialize=0 ) - self.FlowInStorage_rpsditvo = Set( + self.flow_in_storage_rpsditvo = Set( dimen=8, initialize=flows.flow_in_storage_variable_indices ) - self.V_FlowIn = Var(self.FlowInStorage_rpsditvo, domain=NonNegativeReals) + self.v_flow_in = Var(self.flow_in_storage_rpsditvo, domain=NonNegativeReals) - self.StorageLevel_rpsdtv = Set(dimen=6, initialize=storage.storage_level_variable_indices) - self.V_StorageLevel = Var(self.StorageLevel_rpsdtv, domain=NonNegativeReals) + self.storage_level_rpsdtv = Set(dimen=6, initialize=storage.storage_level_variable_indices) + self.v_storage_level = Var(self.storage_level_rpsdtv, domain=NonNegativeReals) - self.SeasonalStorageLevel_rpstv = Set( + self.seasonal_storage_level_rpstv = Set( dimen=5, initialize=storage.seasonal_storage_level_variable_indices ) - self.V_SeasonalStorageLevel = Var(self.SeasonalStorageLevel_rpstv, domain=NonNegativeReals) + self.v_seasonal_storage_level = Var( + self.seasonal_storage_level_rpstv, domain=NonNegativeReals + ) # Derived decision variables - self.CapacityVar_rptv = Set(dimen=4, initialize=costs.cost_fixed_indices) - self.V_Capacity = Var(self.CapacityVar_rptv, domain=NonNegativeReals) + self.capacity_var_rptv = Set(dimen=4, initialize=costs.cost_fixed_indices) + self.v_capacity = Var(self.capacity_var_rptv, domain=NonNegativeReals) - self.NewCapacityVar_rtv = Set(dimen=3, initialize=capacity.capacity_variable_indices) - self.V_NewCapacity = Var(self.NewCapacityVar_rtv, domain=NonNegativeReals, initialize=0) + self.new_capacity_var_rtv = Set(dimen=3, initialize=capacity.capacity_variable_indices) + self.v_new_capacity = Var(self.new_capacity_var_rtv, domain=NonNegativeReals, initialize=0) - self.RetiredCapacityVar_rptv = Set( + self.retired_capacity_var_rptv = Set( dimen=4, initialize=capacity.retired_capacity_variable_indices ) - self.V_RetiredCapacity = Var( - self.RetiredCapacityVar_rptv, domain=NonNegativeReals, initialize=0 + self.v_retired_capacity = Var( + self.retired_capacity_var_rptv, domain=NonNegativeReals, initialize=0 ) - self.AnnualRetirementVar_rptv = Set( + self.annual_retirement_var_rptv = Set( dimen=4, initialize=capacity.annual_retirement_variable_indices ) - self.V_AnnualRetirement = Var( - self.AnnualRetirementVar_rptv, domain=NonNegativeReals, initialize=0 + self.v_annual_retirement = Var( + self.annual_retirement_var_rptv, domain=NonNegativeReals, initialize=0 ) - self.CapacityAvailableVar_rpt = Set( + self.capacity_available_var_rpt = Set( dimen=3, initialize=capacity.capacity_available_variable_indices ) - self.V_CapacityAvailableByPeriodAndTech = Var( - self.CapacityAvailableVar_rpt, domain=NonNegativeReals, initialize=0 + self.v_capacity_available_by_period_and_tech = Var( + self.capacity_available_var_rpt, domain=NonNegativeReals, initialize=0 ) ################################################ @@ -813,7 +791,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: # (minimize total cost) # ################################################ - self.TotalCost = Objective(rule=costs.total_cost_rule, sense=minimize) + self.total_cost = Objective(rule=costs.total_cost_rule, sense=minimize) ################################################ # Constraints # @@ -823,67 +801,67 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.progress_marker_4 = BuildAction(['Starting to build Constraints'], rule=progress_check) # Declare constraints to calculate derived decision variables - self.CapacityConstraint = Constraint( - self.CapacityConstraint_rpsdtv, rule=capacity.capacity_constraint + self.capacity_constraint = Constraint( + self.capacity_constraint_rpsdtv, rule=capacity.capacity_constraint ) - self.CapacityAnnualConstraint_rptv = Set( + self.capacity_annual_constraint_rptv = Set( dimen=4, initialize=capacity.capacity_annual_constraint_indices ) - self.CapacityAnnualConstraint = Constraint( - self.CapacityAnnualConstraint_rptv, rule=capacity.capacity_annual_constraint + self.capacity_annual_constraint = Constraint( + self.capacity_annual_constraint_rptv, rule=capacity.capacity_annual_constraint ) - self.CapacityAvailableByPeriodAndTechConstraint = Constraint( - self.CapacityAvailableVar_rpt, + self.capacity_available_by_period_and_tech_constraint = Constraint( + self.capacity_available_var_rpt, rule=capacity.capacity_available_by_period_and_tech_constraint, ) # devnote: I think this constraint is redundant - # M.RetiredCapacityConstraint = Constraint( - # M.RetiredCapacityVar_rptv, rule=RetiredCapacity_Constraint + # M.Retiredcapacity_constraint = Constraint( + # M.retired_capacity_var_rptv, rule=RetiredCapacity_Constraint # ) self.progress_marker_4a = BuildAction( - ['Starting AnnualRetirementConstraint'], rule=progress_check + ['Starting annual_retirement_constraint'], rule=progress_check ) - self.AnnualRetirementConstraint = Constraint( - self.AnnualRetirementVar_rptv, rule=capacity.annual_retirement_constraint + self.annual_retirement_constraint = Constraint( + self.annual_retirement_var_rptv, rule=capacity.annual_retirement_constraint ) self.progress_marker_4b = BuildAction( - ['Starting AdjustedCapacityConstraint'], rule=progress_check + ['Starting adjusted_capacity_constraint'], rule=progress_check ) - self.AdjustedCapacityConstraint = Constraint( - self.CostFixed_rptv, rule=capacity.adjusted_capacity_constraint + self.adjusted_capacity_constraint = Constraint( + self.cost_fixed_rptv, rule=capacity.adjusted_capacity_constraint ) self.progress_marker_5 = BuildAction(['Finished Capacity Constraints'], rule=progress_check) # Declare core model constraints that ensure proper system functioning # In driving order, starting with the need to meet end-use demands - self.DemandConstraint = Constraint( - self.DemandConstraint_rpc, rule=commodities.demand_constraint + self.demand_constraint = Constraint( + self.demand_constraint_rpc, rule=commodities.demand_constraint ) # devnote: testing a workaround - self.DemandActivityConstraint_rpsdtv_dem = Set( + self.demand_activity_constraint_rpsdtv_dem = Set( dimen=7, initialize=commodities.demand_activity_constraint_indices ) - self.DemandActivityConstraint = Constraint( - self.DemandActivityConstraint_rpsdtv_dem, rule=commodities.demand_activity_constraint + self.demand_activity_constraint = Constraint( + self.demand_activity_constraint_rpsdtv_dem, rule=commodities.demand_activity_constraint ) - self.CommodityBalanceConstraint_rpsdc = Set( + self.commodity_balance_constraint_rpsdc = Set( dimen=5, initialize=commodities.commodity_balance_constraint_indices ) - self.CommodityBalanceConstraint = Constraint( - self.CommodityBalanceConstraint_rpsdc, rule=commodities.commodity_balance_constraint + self.commodity_balance_constraint = Constraint( + self.commodity_balance_constraint_rpsdc, rule=commodities.commodity_balance_constraint ) - self.AnnualCommodityBalanceConstraint_rpc = Set( + self.annual_commodity_balance_constraint_rpc = Set( dimen=3, initialize=commodities.annual_commodity_balance_constraint_indices ) - self.AnnualCommodityBalanceConstraint = Constraint( - self.AnnualCommodityBalanceConstraint_rpc, + self.annual_commodity_balance_constraint = Constraint( + self.annual_commodity_balance_constraint_rpc, rule=commodities.annual_commodity_balance_constraint, ) @@ -891,271 +869,247 @@ def __init__(self, *args: object, **kwargs: object) -> None: # M.ResourceConstraint_rpr, rule=ResourceExtraction_Constraint # ) - self.BaseloadDiurnalConstraint_rpsdtv = Set( + self.baseload_diurnal_constraint_rpsdtv = Set( dimen=6, initialize=operations.baseload_diurnal_constraint_indices ) - self.BaseloadDiurnalConstraint = Constraint( - self.BaseloadDiurnalConstraint_rpsdtv, rule=operations.baseload_diurnal_constraint + self.baseload_diurnal_constraint = Constraint( + self.baseload_diurnal_constraint_rpsdtv, rule=operations.baseload_diurnal_constraint ) - self.RegionalExchangeCapacityConstraint_rrptv = Set( + self.regional_exchange_capacity_constraint_rrptv = Set( dimen=5, initialize=capacity.regional_exchange_capacity_constraint_indices ) - self.RegionalExchangeCapacityConstraint = Constraint( - self.RegionalExchangeCapacityConstraint_rrptv, + self.regional_exchange_capacity_constraint = Constraint( + self.regional_exchange_capacity_constraint_rrptv, rule=geography.regional_exchange_capacity_constraint, ) self.progress_marker_6 = BuildAction(['Starting Storage Constraints'], rule=progress_check) - self.StorageEnergyConstraint = Constraint( - self.StorageConstraints_rpsdtv, rule=storage.storage_energy_constraint + self.storage_energy_constraint = Constraint( + self.storage_constraints_rpsdtv, rule=storage.storage_energy_constraint ) - self.StorageEnergyUpperBoundConstraint = Constraint( - self.StorageConstraints_rpsdtv, rule=storage.storage_energy_upper_bound_constraint + self.storage_energy_upper_bound_constraint = Constraint( + self.storage_constraints_rpsdtv, rule=storage.storage_energy_upper_bound_constraint ) - self.SeasonalStorageEnergyConstraint = Constraint( - self.SeasonalStorageLevel_rpstv, rule=storage.seasonal_storage_energy_constraint + self.seasonal_storage_energy_constraint = Constraint( + self.seasonal_storage_level_rpstv, rule=storage.seasonal_storage_energy_constraint ) - self.SeasonalStorageEnergyUpperBoundConstraint = Constraint( - self.SeasonalStorageConstraints_rpsdtv, + self.seasonal_storage_energy_upper_bound_constraint = Constraint( + self.seasonal_storage_constraints_rpsdtv, rule=storage.seasonal_storage_energy_upper_bound_constraint, ) - self.StorageChargeRateConstraint = Constraint( - self.StorageConstraints_rpsdtv, rule=storage.storage_charge_rate_constraint + self.storage_charge_rate_constraint = Constraint( + self.storage_constraints_rpsdtv, rule=storage.storage_charge_rate_constraint ) - self.StorageDischargeRateConstraint = Constraint( - self.StorageConstraints_rpsdtv, rule=storage.storage_discharge_rate_constraint + self.storage_discharge_rate_constraint = Constraint( + self.storage_constraints_rpsdtv, rule=storage.storage_discharge_rate_constraint ) - self.StorageThroughputConstraint = Constraint( - self.StorageConstraints_rpsdtv, rule=storage.storage_throughput_constraint + self.storage_throughput_constraint = Constraint( + self.storage_constraints_rpsdtv, rule=storage.storage_throughput_constraint ) - self.LimitStorageFractionConstraint = Constraint( - self.LimitStorageFractionConstraint_rpsdtv, + self.limit_storage_fraction_constraint = Constraint( + self.limit_storage_fraction_constraint_rpsdtv, rule=storage.limit_storage_fraction_constraint, ) - self.RampUpDayConstraint_rpsdtv = Set( + self.ramp_up_day_constraint_rpsdtv = Set( dimen=6, initialize=operations.ramp_up_day_constraint_indices ) - self.RampUpDayConstraint = Constraint( - self.RampUpDayConstraint_rpsdtv, rule=operations.ramp_up_day_constraint + self.ramp_up_day_constraint = Constraint( + self.ramp_up_day_constraint_rpsdtv, rule=operations.ramp_up_day_constraint ) - self.RampDownDayConstraint_rpsdtv = Set( + self.ramp_down_day_constraint_rpsdtv = Set( dimen=6, initialize=operations.ramp_down_day_constraint_indices ) - self.RampDownDayConstraint = Constraint( - self.RampDownDayConstraint_rpsdtv, rule=operations.ramp_down_day_constraint + self.ramp_down_day_constraint = Constraint( + self.ramp_down_day_constraint_rpsdtv, rule=operations.ramp_down_day_constraint ) - self.RampUpSeasonConstraint_rpsstv = Set( + self.ramp_up_season_constraint_rpsstv = Set( dimen=6, initialize=operations.ramp_up_season_constraint_indices ) - self.RampUpSeasonConstraint = Constraint( - self.RampUpSeasonConstraint_rpsstv, rule=operations.ramp_up_season_constraint + self.ramp_up_season_constraint = Constraint( + self.ramp_up_season_constraint_rpsstv, rule=operations.ramp_up_season_constraint ) - self.RampDownSeasonConstraint_rpsstv = Set( + self.ramp_down_season_constraint_rpsstv = Set( dimen=6, initialize=operations.ramp_down_season_constraint_indices ) - self.RampDownSeasonConstraint = Constraint( - self.RampDownSeasonConstraint_rpsstv, rule=operations.ramp_down_season_constraint + self.ramp_down_season_constraint = Constraint( + self.ramp_down_season_constraint_rpsstv, rule=operations.ramp_down_season_constraint ) - self.ReserveMargin_rpsd = Set(dimen=4, initialize=reserves.reserve_margin_indices) - self.validate_ReserveMargin = BuildAction(rule=validate_reserve_margin) - self.ReserveMarginConstraint = Constraint( - self.ReserveMargin_rpsd, rule=reserves.reserve_margin_constraint + self.reserve_margin_rpsd = Set(dimen=4, initialize=reserves.reserve_margin_indices) + self.validate_reserve_margin = BuildAction(rule=validate_reserve_margin) + self.reserve_margin_constraint = Constraint( + self.reserve_margin_rpsd, rule=reserves.reserve_margin_constraint ) - self.LimitEmissionConstraint = Constraint( - self.LimitEmissionConstraint_rpe, rule=limits.limit_emission_constraint + self.limit_emission_constraint = Constraint( + self.limit_emission_constraint_rpe, rule=limits.limit_emission_constraint ) self.progress_marker_7 = BuildAction( ['Starting LimitGrowth and Activity Constraints'], rule=progress_check ) - self.LimitGrowthCapacityConstraint_rpt = Set( + self.limit_growth_capacity_constraint_rpt = Set( dimen=4, initialize=limits.limit_growth_capacity_indices ) - self.LimitGrowthCapacityConstraint = Constraint( - self.LimitGrowthCapacityConstraint_rpt, + self.limit_growth_capacity_constraint = Constraint( + self.limit_growth_capacity_constraint_rpt, rule=limits.limit_growth_capacity_constraint_rule, ) - self.LimitDegrowthCapacityConstraint_rpt = Set( + self.limit_degrowth_capacity_constraint_rpt = Set( dimen=4, initialize=limits.limit_degrowth_capacity_indices ) - self.LimitDegrowthCapacityConstraint = Constraint( - self.LimitDegrowthCapacityConstraint_rpt, + self.limit_degrowth_capacity_constraint = Constraint( + self.limit_degrowth_capacity_constraint_rpt, rule=limits.limit_degrowth_capacity_constraint_rule, ) - self.LimitGrowthNewCapacityConstraint_rpt = Set( + self.limit_growth_new_capacity_constraint_rpt = Set( dimen=4, initialize=limits.limit_growth_new_capacity_indices ) - self.LimitGrowthNewCapacityConstraint = Constraint( - self.LimitGrowthNewCapacityConstraint_rpt, + self.limit_growth_new_capacity_constraint = Constraint( + self.limit_growth_new_capacity_constraint_rpt, rule=limits.limit_growth_new_capacity_constraint_rule, ) - self.LimitDegrowthNewCapacityConstraint_rpt = Set( + self.limit_degrowth_new_capacity_constraint_rpt = Set( dimen=4, initialize=limits.limit_degrowth_new_capacity_indices ) - self.LimitDegrowthNewCapacityConstraint = Constraint( - self.LimitDegrowthNewCapacityConstraint_rpt, + self.limit_degrowth_new_capacity_constraint = Constraint( + self.limit_degrowth_new_capacity_constraint_rpt, rule=limits.limit_degrowth_new_capacity_constraint_rule, ) - self.LimitGrowthNewCapacityDeltaConstraint_rpt = Set( + self.limit_growth_new_capacity_delta_constraint_rpt = Set( dimen=4, initialize=limits.limit_growth_new_capacity_delta_indices ) - self.LimitGrowthNewCapacityDeltaConstraint = Constraint( - self.LimitGrowthNewCapacityDeltaConstraint_rpt, + self.limit_growth_new_capacity_delta_constraint = Constraint( + self.limit_growth_new_capacity_delta_constraint_rpt, rule=limits.limit_growth_new_capacity_delta_constraint_rule, ) - self.LimitDegrowthNewCapacityDeltaConstraint_rpt = Set( + self.limit_degrowth_new_capacity_delta_constraint_rpt = Set( dimen=4, initialize=limits.limit_degrowth_new_capacity_delta_indices ) - self.LimitDegrowthNewCapacityDeltaConstraint = Constraint( - self.LimitDegrowthNewCapacityDeltaConstraint_rpt, + self.limit_degrowth_new_capacity_delta_constraint = Constraint( + self.limit_degrowth_new_capacity_delta_constraint_rpt, rule=limits.limit_degrowth_new_capacity_delta_constraint_rule, ) - self.LimitActivityConstraint = Constraint( - self.LimitActivityConstraint_rpt, rule=limits.limit_activity_constraint + self.limit_activity_constraint = Constraint( + self.limit_activity_constraint_rpt, rule=limits.limit_activity_constraint ) - self.LimitSeasonalCapacityFactorConstraint = Constraint( - self.LimitSeasonalCapacityFactorConstraint_rpst, + self.limit_seasonal_capacity_factor_constraint = Constraint( + self.limit_seasonal_capacity_factor_constraint_rpst, rule=limits.limit_seasonal_capacity_factor_constraint, ) - # devnote: deprecated when generalising tech/group columns in Limit tables - # M.LimitActivityGroupConstraint = Constraint( - # M.LimitActivityGroupConstraint_rpg, rule=LimitActivityGroup_Constraint - # ) - - self.LimitCapacityConstraint = Constraint( - self.LimitCapacityConstraint_rpt, rule=limits.limit_capacity_constraint + self.limit_capacity_constraint = Constraint( + self.limit_capacity_constraint_rpt, rule=limits.limit_capacity_constraint ) - self.LimitNewCapacityConstraint = Constraint( - self.LimitNewCapacityConstraint_rpt, rule=limits.limit_new_capacity_constraint + self.limit_new_capacity_constraint = Constraint( + self.limit_new_capacity_constraint_rpt, rule=limits.limit_new_capacity_constraint ) - # devnote: deprecated when generalising tech/group columns in Limit tables - # M.LimitCapacityGroupConstraint = Constraint( - # M.LimitCapacityGroupConstraint_rpg, rule=LimitCapacityGroup_Constraint - # ) - - # M.LimitNewCapacityGroupConstraint = Constraint( - # M.LimitNewCapacityGroupConstraint_rpg, rule=LimitNewCapacityGroup_Constraint - # ) - - self.LimitCapacityShareConstraint = Constraint( - self.LimitCapacityShareConstraint_rpgg, rule=limits.limit_capacity_share_constraint + self.limit_capacity_share_constraint = Constraint( + self.limit_capacity_share_constraint_rpgg, rule=limits.limit_capacity_share_constraint ) - self.LimitActivityShareConstraint = Constraint( - self.LimitActivityShareConstraint_rpgg, rule=limits.limit_activity_share_constraint + self.limit_activity_share_constraint = Constraint( + self.limit_activity_share_constraint_rpgg, rule=limits.limit_activity_share_constraint ) - self.LimitNewCapacityShareConstraint = Constraint( - self.LimitNewCapacityShareConstraint_rpgg, + self.limit_new_capacity_share_constraint = Constraint( + self.limit_new_capacity_share_constraint_rpgg, rule=limits.limit_new_capacity_share_constraint, ) - # devnote: deprecated when generalising tech/group columns in Limit tables - # M.LimitNewCapacityGroupShareConstraint = Constraint( - # M.LimitNewCapacityGroupShareConstraint_rpgg, - # rule=LimitNewCapacityGroupShare_Constraint - # ) - - # M.LimitActivityGroupShareConstraint = Constraint( - # M.LimitActivityGroupShareConstraint_rpgg, rule=LimitActivityGroupShare_Constraint - # ) - self.progress_marker_8 = BuildAction( ['Starting Limit Capacity and Tech Split Constraints'], rule=progress_check ) - self.LimitResourceConstraint = Constraint( - self.LimitResourceConstraint_rt, rule=limits.limit_resource_constraint + self.limit_resource_constraint = Constraint( + self.limit_resource_constraint_rt, rule=limits.limit_resource_constraint ) - self.LimitAnnualCapacityFactorConstraint = Constraint( - self.LimitAnnualCapacityFactorConstraint_rpto, + self.limit_annual_capacity_factor_constraint = Constraint( + self.limit_annual_capacity_factor_constraint_rpto, rule=limits.limit_annual_capacity_factor_constraint, ) ## Tech input splits - self.LimitTechInputSplitConstraint_rpsditv = Set( + self.limit_tech_input_split_constraint_rpsditv = Set( dimen=8, initialize=limits.limit_tech_input_split_constraint_indices ) - self.LimitTechInputSplitConstraint = Constraint( - self.LimitTechInputSplitConstraint_rpsditv, + self.limit_tech_input_split_constraint = Constraint( + self.limit_tech_input_split_constraint_rpsditv, rule=limits.limit_tech_input_split_constraint, ) - self.LimitTechInputSplitAnnualConstraint_rpitv = Set( + self.limit_tech_input_split_annual_constraint_rpitv = Set( dimen=6, initialize=limits.limit_tech_input_split_annual_constraint_indices ) - self.LimitTechInputSplitAnnualConstraint = Constraint( - self.LimitTechInputSplitAnnualConstraint_rpitv, + self.limit_tech_input_split_annual_constraint = Constraint( + self.limit_tech_input_split_annual_constraint_rpitv, rule=limits.limit_tech_input_split_annual_constraint, ) - self.LimitTechInputSplitAverageConstraint_rpitv = Set( + self.limit_tech_input_split_average_constraint_rpitv = Set( dimen=6, initialize=limits.limit_tech_input_split_average_constraint_indices ) - self.LimitTechInputSplitAverageConstraint = Constraint( - self.LimitTechInputSplitAverageConstraint_rpitv, + self.limit_tech_input_split_average_constraint = Constraint( + self.limit_tech_input_split_average_constraint_rpitv, rule=limits.limit_tech_input_split_average_constraint, ) ## Tech output splits - self.LimitTechOutputSplitConstraint_rpsdtvo = Set( + self.limit_tech_output_split_constraint_rpsdtvo = Set( dimen=8, initialize=limits.limit_tech_output_split_constraint_indices ) - self.LimitTechOutputSplitConstraint = Constraint( - self.LimitTechOutputSplitConstraint_rpsdtvo, + self.limit_tech_output_split_constraint = Constraint( + self.limit_tech_output_split_constraint_rpsdtvo, rule=limits.limit_tech_output_split_constraint, ) - self.LimitTechOutputSplitAnnualConstraint_rptvo = Set( + self.limit_tech_output_split_annual_constraint_rptvo = Set( dimen=6, initialize=limits.limit_tech_output_split_annual_constraint_indices ) - self.LimitTechOutputSplitAnnualConstraint = Constraint( - self.LimitTechOutputSplitAnnualConstraint_rptvo, + self.limit_tech_output_split_annual_constraint = Constraint( + self.limit_tech_output_split_annual_constraint_rptvo, rule=limits.limit_tech_output_split_annual_constraint, ) - self.LimitTechOutputSplitAverageConstraint_rptvo = Set( + self.limit_tech_output_split_average_constraint_rptvo = Set( dimen=6, initialize=limits.limit_tech_output_split_average_constraint_indices ) - self.LimitTechOutputSplitAverageConstraint = Constraint( - self.LimitTechOutputSplitAverageConstraint_rptvo, + self.limit_tech_output_split_average_constraint = Constraint( + self.limit_tech_output_split_average_constraint_rptvo, rule=limits.limit_tech_output_split_average_constraint, ) - self.RenewablePortfolioStandardConstraint = Constraint( - self.RenewablePortfolioStandardConstraint_rpg, + self.renewable_portfolio_standard_constraint = Constraint( + self.renewable_portfolio_standard_constraint_rpg, rule=limits.renewable_portfolio_standard_constraint, ) - self.LinkedEmissionsTechConstraint_rpsdtve = Set( + self.linked_emissions_tech_constraint_rpsdtve = Set( dimen=7, initialize=emissions.linked_tech_constraint_indices ) # the validation requires that the set above be built first: self.validate_LinkedTech_lifetimes = BuildCheck(rule=validate_linked_tech) - self.LinkedEmissionsTechConstraint = Constraint( - self.LinkedEmissionsTechConstraint_rpsdtve, + self.linked_emissions_tech_constraint = Constraint( + self.linked_emissions_tech_constraint_rpsdtve, rule=emissions.linked_emissions_tech_constraint, ) diff --git a/temoa/data_io/component_manifest.py b/temoa/data_io/component_manifest.py index c449c16f0..8665a23a3 100644 --- a/temoa/data_io/component_manifest.py +++ b/temoa/data_io/component_manifest.py @@ -45,7 +45,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: is_period_filtered=False, ), LoadItem( - component=model.regionalGlobalIndices, + component=model.regional_global_indices, table='meta_regional_groups', # Placeholder, custom loader does the work columns=['region_or_group'], custom_loader_name='_load_regional_global_indices', @@ -238,7 +238,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: fallback_data=[('D',)], ), LoadItem( - component=model.TimeSeason, + component=model.time_season, table='TimeSeason', columns=['period', 'season'], custom_loader_name='_load_time_season', @@ -246,33 +246,33 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=model.TimeSeasonSequential, - table='TimeSeasonSequential', + component=model.time_season_sequential, + table='time_season_sequential', columns=['period', 'seas_seq', 'season', 'num_days'], - custom_loader_name='_load_time_season_sequential', + custom_loader_name='_load_time_season_to_sequential', is_table_required=False, ), LoadItem( - component=model.SegFrac, + component=model.segment_fraction, table='TimeSegmentFraction', columns=['period', 'season', 'tod', 'segfrac'], - custom_loader_name='_load_seg_frac', + custom_loader_name='_load_segment_fraction', is_table_required=False, ), # ========================================================================= # Capacity and Cost Components # ========================================================================= LoadItem( - component=model.ExistingCapacity, - table='ExistingCapacity', + component=model.existing_capacity, + table='existing_capacity', columns=['region', 'tech', 'vintage', 'capacity'], custom_loader_name='_load_existing_capacity', is_period_filtered=False, # Custom loader handles all logic is_table_required=False, ), LoadItem( - component=model.CostInvest, - table='CostInvest', + component=model.cost_invest, + table='cost_invest', columns=['region', 'tech', 'vintage', 'cost'], validator_name='viable_rtv', validation_map=(0, 1, 2), @@ -281,28 +281,28 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=model.CostFixed, - table='CostFixed', + component=model.cost_fixed, + table='cost_fixed', columns=['region', 'period', 'tech', 'vintage', 'cost'], validator_name='viable_rtv', validation_map=(0, 2, 3), ), LoadItem( - component=model.CostVariable, - table='CostVariable', + component=model.cost_variable, + table='cost_variable', columns=['region', 'period', 'tech', 'vintage', 'cost'], validator_name='viable_rtv', validation_map=(0, 2, 3), ), LoadItem( - component=model.CostEmission, - table='CostEmission', + component=model.cost_emission, + table='cost_emission', columns=['region', 'period', 'emis_comm', 'cost'], is_table_required=False, ), LoadItem( - component=model.LoanRate, - table='LoanRate', + component=model.loan_rate, + table='loan_rate', columns=['region', 'tech', 'vintage', 'rate'], validator_name='viable_rtv', validation_map=(0, 1, 2), @@ -314,7 +314,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: # Singleton and Configuration-based Components # ========================================================================= LoadItem( - component=model.DaysPerPeriod, + component=model.days_per_period, table='MetaData', columns=['value'], where_clause="element == 'days_per_period'", @@ -323,7 +323,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=model.GlobalDiscountRate, + component=model.global_discount_rate, table='MetaDataReal', columns=['value'], where_clause="element = 'global_discount_rate'", @@ -332,7 +332,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=model.DefaultLoanRate, + component=model.default_loan_rate, table='MetaDataReal', columns=['value'], where_clause="element = 'default_loan_rate'", @@ -344,7 +344,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: # Operational Constraints and Parameters # ========================================================================= LoadItem( - component=model.Efficiency, + component=model.efficiency, table='meta_efficiency', # Placeholder, custom loader does the work columns=[], custom_loader_name='_load_efficiency', @@ -352,8 +352,8 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=model.EfficiencyVariable, - table='EfficiencyVariable', + component=model.efficiency_variable, + table='efficiency_variable', columns=[ 'region', 'period', @@ -370,18 +370,18 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=model.Demand, + component=model.demand, table='Demand', columns=['region', 'period', 'commodity', 'demand'], ), LoadItem( - component=model.DemandSpecificDistribution, + component=model.demand_specific_distribution, table='DemandSpecificDistribution', columns=['region', 'period', 'season', 'tod', 'demand_name', 'dsd'], is_table_required=False, ), LoadItem( - component=model.CapacityToActivity, + component=model.capacity_to_activity, table='CapacityToActivity', columns=['region', 'tech', 'c2a'], validator_name='viable_rt', @@ -390,24 +390,24 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=model.CapacityFactorTech, - table='CapacityFactorTech', + component=model.capacity_factor_tech, + table='capacity_factor_tech', columns=['region', 'period', 'season', 'tod', 'tech', 'factor'], validator_name='viable_rt', validation_map=(0, 4), is_table_required=False, ), LoadItem( - component=model.CapacityFactorProcess, - table='CapacityFactorProcess', + component=model.capacity_factor_process, + table='capacity_factor_process', columns=['region', 'period', 'season', 'tod', 'tech', 'vintage', 'factor'], validator_name='viable_rtv', validation_map=(0, 4, 5), is_table_required=False, ), LoadItem( - component=model.LifetimeTech, - table='LifetimeTech', + component=model.lifetime_tech, + table='lifetime_tech', columns=['region', 'tech', 'lifetime'], validator_name='viable_rt', validation_map=(0, 1), @@ -415,8 +415,8 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=model.LifetimeProcess, - table='LifetimeProcess', + component=model.lifetime_process, + table='lifetime_process', columns=['region', 'tech', 'vintage', 'lifetime'], validator_name='viable_rtv', validation_map=(0, 1, 2), @@ -424,8 +424,8 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=model.LifetimeSurvivalCurve, - table='LifetimeSurvivalCurve', + component=model.lifetime_survival_curve, + table='lifetime_survival_curve', columns=['region', 'period', 'tech', 'vintage', 'fraction'], validator_name='viable_rtv', validation_map=(0, 2, 3), @@ -433,8 +433,8 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=model.LoanLifetimeProcess, - table='LoanLifetimeProcess', + component=model.loan_lifetime_process, + table='loan_lifetime_process', columns=['region', 'tech', 'vintage', 'lifetime'], validator_name='viable_rtv', validation_map=(0, 1, 2), @@ -442,8 +442,8 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=model.RampUpHourly, - table='RampUpHourly', + component=model.ramp_up_hourly, + table='ramp_up_hourly', columns=['region', 'tech', 'rate'], custom_loader_name='_load_ramping_up', validator_name='viable_rt', @@ -453,15 +453,15 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.tech_upramping, - table='RampUpHourly', + table='ramp_up_hourly', columns=['tech'], validator_name='viable_techs', validation_map=(0,), is_period_filtered=False, ), LoadItem( - component=model.RampDownHourly, - table='RampDownHourly', + component=model.ramp_down_hourly, + table='ramp_down_hourly', columns=['region', 'tech', 'rate'], custom_loader_name='_load_ramping_down', validator_name='viable_rt', @@ -471,45 +471,45 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.tech_downramping, - table='RampDownHourly', + table='ramp_down_hourly', columns=['tech'], validator_name='viable_techs', validation_map=(0,), is_period_filtered=False, ), LoadItem( - component=model.RenewablePortfolioStandard, + component=model.renewable_portfolio_standard, table='RPSRequirement', columns=['region', 'period', 'tech_group', 'requirement'], custom_loader_name='_load_rps_requirement', is_table_required=False, ), LoadItem( - component=model.CapacityCredit, - table='CapacityCredit', + component=model.capacity_credit, + table='capacity_credit', columns=['region', 'period', 'tech', 'vintage', 'credit'], validator_name='viable_rtv', validation_map=(0, 2, 3), is_table_required=False, ), LoadItem( - component=model.ReserveCapacityDerate, - table='ReserveCapacityDerate', + component=model.reserve_capacity_derate, + table='reserve_capacity_derate', columns=['region', 'period', 'season', 'tech', 'vintage', 'factor'], validator_name='viable_rtv', validation_map=(0, 3, 4), is_table_required=False, ), LoadItem( - component=model.PlanningReserveMargin, - table='PlanningReserveMargin', + component=model.planning_reserve_margin, + table='planning_reserve_margin', columns=['region', 'margin'], is_period_filtered=False, is_table_required=False, ), LoadItem( - component=model.StorageDuration, - table='StorageDuration', + component=model.storage_duration, + table='storage_duration', columns=['region', 'tech', 'duration'], validator_name='viable_rt', validation_map=(0, 1), @@ -517,7 +517,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=model.LimitStorageFraction, + component=model.limit_storage_fraction, table='LimitStorageLevelFraction', columns=[ 'region', @@ -534,8 +534,8 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=model.EmissionActivity, - table='EmissionActivity', + component=model.emission_activity, + table='emission_activity', columns=[ 'region', 'emis_comm', @@ -551,8 +551,8 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=model.EmissionEmbodied, - table='EmissionEmbodied', + component=model.emission_embodied, + table='emission_embodied', columns=['region', 'emis_comm', 'tech', 'vintage', 'value'], validator_name='viable_rtv', validation_map=(0, 2, 3), @@ -560,8 +560,8 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=model.EmissionEndOfLife, - table='EmissionEndOfLife', + component=model.emission_end_of_life, + table='emission_end_of_life', columns=['region', 'emis_comm', 'tech', 'vintage', 'value'], validator_name='viable_rtv', validation_map=(0, 2, 3), @@ -569,8 +569,8 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=model.ConstructionInput, - table='ConstructionInput', + component=model.construction_input, + table='construction_input', columns=['region', 'input_comm', 'tech', 'vintage', 'value'], validator_name='viable_rtv', validation_map=(0, 2, 3), @@ -578,8 +578,8 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=model.EndOfLifeOutput, - table='EndOfLifeOutput', + component=model.end_of_life_output, + table='end_of_life_output', columns=['region', 'tech', 'vintage', 'output_comm', 'value'], validator_name='viable_rtv', validation_map=(0, 1, 2), @@ -590,73 +590,73 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: # Limit Constraints # ========================================================================= LoadItem( - component=model.LimitCapacity, - table='LimitCapacity', + component=model.limit_capacity, + table='limit_capacity', columns=['region', 'period', 'tech_or_group', 'operator', 'capacity'], is_table_required=False, ), LoadItem( - component=model.LimitNewCapacity, - table='LimitNewCapacity', + component=model.limit_new_capacity, + table='limit_new_capacity', columns=['region', 'period', 'tech_or_group', 'operator', 'new_cap'], is_table_required=False, ), LoadItem( - component=model.LimitCapacityShare, - table='LimitCapacityShare', + component=model.limit_capacity_share, + table='limit_capacity_share', columns=['region', 'period', 'sub_group', 'super_group', 'operator', 'share'], is_table_required=False, ), LoadItem( - component=model.LimitNewCapacityShare, - table='LimitNewCapacityShare', + component=model.limit_new_capacity_share, + table='limit_new_capacity_share', columns=['region', 'period', 'sub_group', 'super_group', 'operator', 'share'], is_table_required=False, ), LoadItem( - component=model.LimitActivity, - table='LimitActivity', + component=model.limit_activity, + table='limit_activity', columns=['region', 'period', 'tech_or_group', 'operator', 'activity'], is_table_required=False, ), LoadItem( - component=model.LimitActivityShare, - table='LimitActivityShare', + component=model.limit_activity_share, + table='limit_activity_share', columns=['region', 'period', 'sub_group', 'super_group', 'operator', 'share'], is_table_required=False, ), LoadItem( - component=model.LimitResource, - table='LimitResource', + component=model.limit_resource, + table='limit_resource', columns=['region', 'tech_or_group', 'operator', 'cum_act'], is_period_filtered=False, is_table_required=False, ), LoadItem( - component=model.LimitSeasonalCapacityFactor, - table='LimitSeasonalCapacityFactor', + component=model.limit_seasonal_capacity_factor, + table='limit_seasonal_capacity_factor', columns=['region', 'period', 'season', 'tech', 'operator', 'factor'], validator_name='viable_rt', validation_map=(0, 3), is_table_required=False, ), LoadItem( - component=model.LimitAnnualCapacityFactor, - table='LimitAnnualCapacityFactor', + component=model.limit_annual_capacity_factor, + table='limit_annual_capacity_factor', columns=['region', 'period', 'tech', 'output_comm', 'operator', 'factor'], validator_name='viable_rpto', validation_map=(0, 1, 2, 3), is_table_required=False, ), LoadItem( - component=model.LimitEmission, - table='LimitEmission', + component=model.limit_emission, + table='limit_emission', columns=['region', 'period', 'emis_comm', 'operator', 'value'], is_table_required=False, ), LoadItem( - component=model.LimitTechInputSplit, - table='LimitTechInputSplit', + component=model.limit_tech_input_split, + table='limit_tech_input_split', columns=['region', 'period', 'input_comm', 'tech', 'operator', 'proportion'], validator_name='viable_rpit', validation_map=(0, 1, 2, 3), @@ -664,8 +664,8 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=model.LimitTechInputSplitAnnual, - table='LimitTechInputSplitAnnual', + component=model.limit_tech_input_split_annual, + table='limit_tech_input_split_annual', columns=['region', 'period', 'input_comm', 'tech', 'operator', 'proportion'], validator_name='viable_rpit', validation_map=(0, 1, 2, 3), @@ -673,8 +673,8 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=model.LimitTechOutputSplit, - table='LimitTechOutputSplit', + component=model.limit_tech_output_split, + table='limit_tech_output_split', columns=['region', 'period', 'tech', 'output_comm', 'operator', 'proportion'], validator_name='viable_rpto', validation_map=(0, 1, 2, 3), @@ -682,8 +682,8 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=model.LimitTechOutputSplitAnnual, - table='LimitTechOutputSplitAnnual', + component=model.limit_tech_output_split_annual, + table='limit_tech_output_split_annual', columns=['region', 'period', 'tech', 'output_comm', 'operator', 'proportion'], validator_name='viable_rpto', validation_map=(0, 1, 2, 3), @@ -691,7 +691,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: is_table_required=False, ), LoadItem( - component=model.LinkedTechs, + component=model.linked_techs, table='LinkedTech', columns=['primary_region', 'primary_tech', 'emis_comm', 'driven_tech'], validator_name='viable_rtt', diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index ca5ec5813..107caa8f5 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -43,22 +43,22 @@ # A manifest of tables that may contain region groups, used by a custom loader. tables_with_regional_groups = { - 'LimitAnnualCapacityFactor': 'region', - 'LimitEmission': 'region', - 'LimitSeasonalCapacityFactor': 'region', - 'LimitCapacity': 'region', - 'LimitActivity': 'region', - 'LimitNewCapacity': 'region', - 'LimitActivityShare': 'region', - 'LimitCapacityShare': 'region', - 'LimitNewCapacityShare': 'region', - 'LimitResource': 'region', - 'LimitGrowthCapacity': 'region', - 'LimitDegrowthCapacity': 'region', - 'LimitGrowthNewCapacity': 'region', - 'LimitDegrowthNewCapacity': 'region', - 'LimitGrowthNewCapacityDelta': 'region', - 'LimitDegrowthNewCapacityDelta': 'region', + 'limit_annual_capacity_factor': 'region', + 'limit_emission': 'region', + 'limit_seasonal_capacity_factor': 'region', + 'limit_capacity': 'region', + 'limit_activity': 'region', + 'limit_new_capacity': 'region', + 'limit_activity_share': 'region', + 'limit_capacity_share': 'region', + 'limit_new_capacity_share': 'region', + 'limit_resource': 'region', + 'limit_growth_capacity': 'region', + 'limit_degrowth_capacity': 'region', + 'limit_growth_new_capacity': 'region', + 'limit_degrowth_new_capacity': 'region', + 'limit_growth_new_capacity_delta': 'region', + 'limit_degrowth_new_capacity_delta': 'region', } @@ -256,14 +256,16 @@ def create_data_dict(self, myopic_index: MyopicIndex | None = None) -> dict[str, # Finalization # --------------------------------------------------------------------- # Load simple config-based or myopic-specific values - self._load_component_data(data, model.TimeSequencing, [(self.config.time_sequencing,)]) - self._load_component_data(data, model.ReserveMarginMethod, [(self.config.reserve_margin,)]) + self._load_component_data(data, model.time_sequencing, [(self.config.time_sequencing,)]) + self._load_component_data( + data, model.reserve_margin_method, [(self.config.reserve_margin,)] + ) if myopic_index: p0_result = cur.execute( "SELECT min(period) FROM TimePeriod WHERE flag == 'f'" ).fetchone() if p0_result: - data[model.MyopicDiscountingYear.name] = {None: int(p0_result[0])} + data[model.myopic_discounting_year.name] = {None: int(p0_result[0])} # Create derived index sets for parameters now that all base data is loaded set_data = self.load_param_idx_sets(data=data) @@ -431,12 +433,12 @@ def _build_efficiency_dataset( if myopic_index: contents = cur.execute( 'SELECT region, input_comm, tech, vintage, output_comm, efficiency, lifetime ' - 'FROM MyopicEfficiency WHERE vintage + lifetime > ?', + 'FROM Myopicefficiency WHERE vintage + lifetime > ?', (myopic_index.base_year,), ).fetchall() else: contents = cur.execute( - 'SELECT region, input_comm, tech, vintage, output_comm, efficiency, NULL FROM main.Efficiency' + 'SELECT region, input_comm, tech, vintage, output_comm, efficiency, NULL FROM main.efficiency' ).fetchall() if use_raw_data: @@ -473,7 +475,7 @@ def _build_efficiency_dataset( for row in contents if (row[0], row[1], row[2], row[3], row[4]) in self.viable_ritvo.members } - logger.debug('Polled %d elements from Efficiency tables', len(efficiency_entries)) + logger.debug('Polled %d elements from efficiency tables', len(efficiency_entries)) self.efficiency_values = sorted(efficiency_entries) # ================================================================================= @@ -509,7 +511,7 @@ def _load_regional_global_indices( raise ValueError('A table has an empty entry for its region column.') list_of_groups = sorted((t,) for t in regions_and_groups) - self._load_component_data(data, model.regionalGlobalIndices, list_of_groups) + self._load_component_data(data, model.regional_global_indices, list_of_groups) def _load_tech_group_members( self, @@ -552,49 +554,51 @@ def _load_time_season( rows_to_load = list(raw_data) if not rows_to_load: - data.setdefault(model.time_season.name, []) + data.setdefault(model.time_season_all.name, []) return unique_seasons = sorted(list({(row[1],) for row in rows_to_load})) - self._load_component_data(data, model.time_season, unique_seasons) + self._load_component_data(data, model.time_season_all, unique_seasons) for period, season in rows_to_load: - store = data.get(model.TimeSeason.name, defaultdict(list)) + store = data.get(model.time_season.name, defaultdict(list)) store[period].append(season) # type: ignore[index] - data[model.TimeSeason.name] = store + data[model.time_season.name] = store - def _load_time_season_sequential( + def _load_time_season_to_sequential( self, data: dict[str, object], raw_data: Sequence[tuple[object, ...]], filtered_data: Sequence[tuple[object, ...]], ) -> None: """ - Composite loader for TimeSeasonSequential and its associated index sets. + Composite loader for time_season_sequential and its associated index sets. """ model = TemoaModel() - self._load_component_data(data, model.TimeSeasonSequential, filtered_data) + self._load_component_data(data, model.time_season_sequential, filtered_data) if filtered_data: ordered_data = [row[0:3] for row in filtered_data] self._load_component_data(data, model.ordered_season_sequential, ordered_data) seq_data = sorted({(row[1],) for row in filtered_data}) - self._load_component_data(data, model.time_season_sequential, seq_data) + self._load_component_data(data, model.time_season_to_sequential, seq_data) - def _load_seg_frac( + def _load_segment_fraction( self, data: dict[str, object], raw_data: Sequence[tuple[object, ...]], filtered_data: Sequence[tuple[object, ...]], ) -> None: - """Handles dynamic fallbacks for SegFrac if its table is missing.""" + """Handles dynamic fallbacks for segment_fraction if its table is missing.""" model = TemoaModel() if filtered_data: - self._load_component_data(data, model.SegFrac, filtered_data) + self._load_component_data(data, model.segment_fraction, filtered_data) else: - logger.warning('No TimeSegmentFraction table found. Generating default SegFrac values.') + logger.warning( + 'No TimeSegmentFraction table found. Generating default segment_fraction values.' + ) time_optimize = data.get('time_optimize', []) fallback = [(p, 'S', 'D', 1.0) for p in time_optimize] # type: ignore[attr-defined] - self._load_component_data(data, model.SegFrac, fallback) + self._load_component_data(data, model.segment_fraction, fallback) # --- Capacity and Cost Components --- def _load_existing_capacity( @@ -619,15 +623,15 @@ def _load_existing_capacity( prev_period = prev_period_res[0] if prev_period_res else -1 rows_to_load = cur.execute( 'SELECT region, tech, vintage, capacity FROM OutputBuiltCapacity WHERE vintage <= ? AND scenario = ? ' - 'UNION SELECT region, tech, vintage, capacity FROM ExistingCapacity', + 'UNION SELECT region, tech, vintage, capacity FROM existing_capacity', (prev_period, self.config.scenario), ).fetchall() - elif self.table_exists('ExistingCapacity'): + elif self.table_exists('existing_capacity'): rows_to_load = cur.execute( - 'SELECT region, tech, vintage, capacity FROM ExistingCapacity' + 'SELECT region, tech, vintage, capacity FROM existing_capacity' ).fetchall() - self._load_component_data(data, model.ExistingCapacity, rows_to_load) + self._load_component_data(data, model.existing_capacity, rows_to_load) if rows_to_load: tech_exist_data = sorted(list({(row[1],) for row in rows_to_load})) self._load_component_data(data, model.tech_exist, tech_exist_data) @@ -638,13 +642,13 @@ def _load_cost_invest( raw_data: Sequence[tuple[object, ...]], filtered_data: Sequence[tuple[object, ...]], ) -> None: - """Handles myopic period filtering for CostInvest.""" + """Handles myopic period filtering for cost_invest.""" model = TemoaModel() base_year = self.myopic_index.base_year if self.myopic_index else None data_to_load = [ row for row in filtered_data if base_year is None or cast(int, row[2]) >= base_year ] - self._load_component_data(data, model.CostInvest, data_to_load) + self._load_component_data(data, model.cost_invest, data_to_load) def _load_loan_rate( self, @@ -652,11 +656,11 @@ def _load_loan_rate( raw_data: Sequence[tuple[object, ...]], filtered_data: Sequence[tuple[object, ...]], ) -> None: - """Handles myopic period filtering for LoanRate.""" + """Handles myopic period filtering for loan_rate.""" model = TemoaModel() mi = self.myopic_index data_to_load = [row for row in filtered_data if not mi or row[2] >= mi.base_year] # type: ignore[operator] - self._load_component_data(data, model.LoanRate, data_to_load) + self._load_component_data(data, model.loan_rate, data_to_load) # --- Singleton and Configuration-based Components --- def _load_days_per_period( @@ -665,14 +669,14 @@ def _load_days_per_period( raw_data: Sequence[tuple[object, ...]], filtered_data: Sequence[tuple[object, ...]], ) -> None: - """Loads the singleton DaysPerPeriod, with a fallback.""" + """Loads the singleton days_per_period, with a fallback.""" model = TemoaModel() days = 365 if filtered_data: days = cast(int, filtered_data[0][0]) else: logger.info('No value for days_per_period found. Assuming 365 days per period.') - data[model.DaysPerPeriod.name] = {None: days} + data[model.days_per_period.name] = {None: days} def _load_global_discount_rate( self, @@ -683,7 +687,7 @@ def _load_global_discount_rate( """Loads the required singleton GlobalDiscountRate.""" model = TemoaModel() if filtered_data: - data[model.GlobalDiscountRate.name] = {None: cast(float, filtered_data[0][0])} + data[model.global_discount_rate.name] = {None: cast(float, filtered_data[0][0])} else: raise ValueError( "Missing required parameter: 'global_discount_rate' not found in MetaDataReal table." @@ -695,10 +699,10 @@ def _load_default_loan_rate( raw_data: Sequence[tuple[object, ...]], filtered_data: Sequence[tuple[object, ...]], ) -> None: - """Loads the optional singleton DefaultLoanRate.""" + """Loads the optional singleton default_loan_rate.""" model = TemoaModel() if filtered_data: - data[model.DefaultLoanRate.name] = {None: cast(float, filtered_data[0][0])} + data[model.default_loan_rate.name] = {None: cast(float, filtered_data[0][0])} # --- Operational Constraints and Parameters --- def _load_efficiency( @@ -707,9 +711,9 @@ def _load_efficiency( raw_data: Sequence[tuple[object, ...]], filtered_data: Sequence[tuple[object, ...]], ) -> None: - """Loads the main Efficiency parameter, which is pre-calculated.""" + """Loads the main efficiency parameter, which is pre-calculated.""" model = TemoaModel() - self._load_component_data(data, model.Efficiency, self.efficiency_values) + self._load_component_data(data, model.efficiency, self.efficiency_values) def _load_linked_techs( self, @@ -717,8 +721,8 @@ def _load_linked_techs( raw_data: Sequence[tuple[object, ...]], filtered_data: Sequence[tuple[object, ...]], ) -> None: - """Provides critical error checking for LinkedTechs.""" - item = self.manifest_map['LinkedTechs'] + """Provides critical error checking for linked_techs.""" + item = self.manifest_map['linked_techs'] self._load_component_data(data, item.component, filtered_data) if len(filtered_data) < len(raw_data): missing = set(raw_data) - set(filtered_data) @@ -739,9 +743,9 @@ def _load_ramping_down( raw_data: Sequence[tuple[object, ...]], filtered_data: Sequence[tuple[object, ...]], ) -> None: - """Composite loader for RampDownHourly and its index set `tech_downramping`.""" + """Composite loader for ramp_down_hourly and its index set `tech_downramping`.""" model = TemoaModel() - self._load_component_data(data, model.RampDownHourly, filtered_data) + self._load_component_data(data, model.ramp_down_hourly, filtered_data) if filtered_data: tech_data = sorted(list({(row[1],) for row in filtered_data})) tech_filtered = self._filter_data( @@ -755,9 +759,9 @@ def _load_ramping_up( raw_data: Sequence[tuple[object, ...]], filtered_data: Sequence[tuple[object, ...]], ) -> None: - """Composite loader for RampUpHourly and its index set `tech_upramping`.""" + """Composite loader for ramp_up_hourly and its index set `tech_upramping`.""" model = TemoaModel() - self._load_component_data(data, model.RampUpHourly, filtered_data) + self._load_component_data(data, model.ramp_up_hourly, filtered_data) if filtered_data: tech_data = sorted(list({(row[1],) for row in filtered_data})) tech_filtered = self._filter_data( @@ -771,12 +775,12 @@ def _load_rps_requirement( raw_data: Sequence[tuple[object, ...]], filtered_data: Sequence[tuple[object, ...]], ) -> None: - """Handles deprecation warning for RenewablePortfolioStandard.""" + """Handles deprecation warning for renewable_portfolio_standard.""" model = TemoaModel() - self._load_component_data(data, model.RenewablePortfolioStandard, filtered_data) + self._load_component_data(data, model.renewable_portfolio_standard, filtered_data) if filtered_data: logger.warning( - 'The RenewablePortfolioStandard constraint is deprecated. Use LimitActivityShare instead. ' + 'The renewable_portfolio_standard constraint is deprecated. Use limit_activity_share instead. ' 'The constraint has been applied but this feature may be removed in the future.' ) @@ -786,8 +790,8 @@ def _load_limit_tech_input_split( raw_data: Sequence[tuple[object, ...]], filtered_data: Sequence[tuple[object, ...]], ) -> None: - """Provides detailed warnings for filtered LimitTechInputSplit data.""" - item = self.manifest_map['LimitTechInputSplit'] + """Provides detailed warnings for filtered limit_tech_input_split data.""" + item = self.manifest_map['limit_tech_input_split'] self._load_component_data(data, item.component, filtered_data) if len(filtered_data) < len(raw_data): missing = set(raw_data) - set(filtered_data) @@ -807,8 +811,8 @@ def _load_limit_tech_input_split_annual( raw_data: Sequence[tuple[object, ...]], filtered_data: Sequence[tuple[object, ...]], ) -> None: - """Provides detailed warnings for filtered LimitTechInputSplitAnnual data.""" - item = self.manifest_map['LimitTechInputSplitAnnual'] + """Provides detailed warnings for filtered limit_tech_input_split_annual data.""" + item = self.manifest_map['limit_tech_input_split_annual'] self._load_component_data(data, item.component, filtered_data) if len(filtered_data) < len(raw_data): missing = set(raw_data) - set(filtered_data) @@ -828,8 +832,8 @@ def _load_limit_tech_output_split( raw_data: Sequence[tuple[object, ...]], filtered_data: Sequence[tuple[object, ...]], ) -> None: - """Provides detailed warnings for filtered LimitTechOutputSplit data.""" - item = self.manifest_map['LimitTechOutputSplit'] + """Provides detailed warnings for filtered limit_tech_output_split data.""" + item = self.manifest_map['limit_tech_output_split'] self._load_component_data(data, item.component, filtered_data) if len(filtered_data) < len(raw_data): missing = set(raw_data) - set(filtered_data) @@ -849,8 +853,8 @@ def _load_limit_tech_output_split_annual( raw_data: Sequence[tuple[object, ...]], filtered_data: Sequence[tuple[object, ...]], ) -> None: - """Provides detailed warnings for filtered LimitTechOutputSplitAnnual data.""" - item = self.manifest_map['LimitTechOutputSplitAnnual'] + """Provides detailed warnings for filtered limit_tech_output_split_annual data.""" + item = self.manifest_map['limit_tech_output_split_annual'] self._load_component_data(data, item.component, filtered_data) if len(filtered_data) < len(raw_data): missing = set(raw_data) - set(filtered_data) @@ -879,21 +883,21 @@ def load_param_idx_sets(self, data: dict[str, object]) -> dict[str, object]: """ model = TemoaModel() param_idx_sets = { - model.CostInvest.name: model.CostInvest_rtv.name, - model.CostEmission.name: model.CostEmission_rpe.name, - model.Demand.name: model.DemandConstraint_rpc.name, - model.LimitEmission.name: model.LimitEmissionConstraint_rpe.name, - model.LimitActivity.name: model.LimitActivityConstraint_rpt.name, - model.LimitSeasonalCapacityFactor.name: model.LimitSeasonalCapacityFactorConstraint_rpst.name, - model.LimitActivityShare.name: model.LimitActivityShareConstraint_rpgg.name, - model.LimitAnnualCapacityFactor.name: model.LimitAnnualCapacityFactorConstraint_rpto.name, - model.LimitCapacity.name: model.LimitCapacityConstraint_rpt.name, - model.LimitCapacityShare.name: model.LimitCapacityShareConstraint_rpgg.name, - model.LimitNewCapacity.name: model.LimitNewCapacityConstraint_rpt.name, - model.LimitNewCapacityShare.name: model.LimitNewCapacityShareConstraint_rpgg.name, - model.LimitResource.name: model.LimitResourceConstraint_rt.name, - model.LimitStorageFraction.name: model.LimitStorageFractionConstraint_rpsdtv.name, - model.RenewablePortfolioStandard.name: model.RenewablePortfolioStandardConstraint_rpg.name, + model.cost_invest.name: model.cost_invest_rtv.name, + model.cost_emission.name: model.cost_emission_rpe.name, + model.demand.name: model.demand_constraint_rpc.name, + model.limit_emission.name: model.limit_emission_constraint_rpe.name, + model.limit_activity.name: model.limit_activity_constraint_rpt.name, + model.limit_seasonal_capacity_factor.name: model.limit_seasonal_capacity_factor_constraint_rpst.name, + model.limit_activity_share.name: model.limit_activity_share_constraint_rpgg.name, + model.limit_annual_capacity_factor.name: model.limit_annual_capacity_factor_constraint_rpto.name, + model.limit_capacity.name: model.limit_capacity_constraint_rpt.name, + model.limit_capacity_share.name: model.limit_capacity_share_constraint_rpgg.name, + model.limit_new_capacity.name: model.limit_new_capacity_constraint_rpt.name, + model.limit_new_capacity_share.name: model.limit_new_capacity_share_constraint_rpgg.name, + model.limit_resource.name: model.limit_resource_constraint_rt.name, + model.limit_storage_fraction.name: model.limit_storage_fraction_constraint_rpsdtv.name, + model.renewable_portfolio_standard.name: model.renewable_portfolio_standard_constraint_rpg.name, } res: dict[str, object] = {} diff --git a/temoa/data_processing/database_util.py b/temoa/data_processing/database_util.py index 6a1fb1280..a9fed2109 100644 --- a/temoa/data_processing/database_util.py +++ b/temoa/data_processing/database_util.py @@ -142,7 +142,7 @@ def get_commodities_and_tech( if region: where_clause = f"region LIKE '%{region}%' AND {where_clause}" - query = f'SELECT input_comm, tech, output_comm FROM Efficiency WHERE {where_clause}' + query = f'SELECT input_comm, tech, output_comm FROM efficiency WHERE {where_clause}' self.cur.execute(query) return pd.DataFrame(self.cur.fetchall(), columns=['input_comm', 'tech', 'output_comm']) @@ -151,9 +151,9 @@ def get_existing_technologies_for_commodity( ) -> pd.DataFrame: """Retrieves technologies associated with a specific commodity.""" if comm_type == 'input': - query = f"SELECT DISTINCT tech FROM Efficiency WHERE input_comm IS '{comm}'" + query = f"SELECT DISTINCT tech FROM efficiency WHERE input_comm IS '{comm}'" else: - query = f"SELECT DISTINCT tech FROM Efficiency WHERE output_comm IS '{comm}'" + query = f"SELECT DISTINCT tech FROM efficiency WHERE output_comm IS '{comm}'" if region: query += f" AND region LIKE '%{region}%'" @@ -175,9 +175,9 @@ def get_commodities_by_technology( ) -> set[tuple[str, str]]: """Retrieves commodity-technology pairs.""" if comm_type == 'input': - query = 'SELECT DISTINCT input_comm, tech FROM Efficiency' + query = 'SELECT DISTINCT input_comm, tech FROM efficiency' elif comm_type == 'output': - query = 'SELECT DISTINCT tech, output_comm FROM Efficiency' + query = 'SELECT DISTINCT tech, output_comm FROM efficiency' else: raise ValueError("Invalid comm_type: can only be 'input' or 'output'") @@ -269,7 +269,7 @@ def get_emissions_activity_for_period(self, period: int, region: str | None) -> query = f""" SELECT E.emis_comm, E.tech, SUM(E.activity * O.flow) - FROM EmissionActivity E, OutputFlowOut O + FROM emission_activity E, OutputFlowOut O WHERE E.input_comm = O.input_comm AND E.tech = O.tech AND E.vintage = O.vintage diff --git a/temoa/data_processing/db_to_excel.py b/temoa/data_processing/db_to_excel.py index cc42d8a7f..c6cbd04bf 100644 --- a/temoa/data_processing/db_to_excel.py +++ b/temoa/data_processing/db_to_excel.py @@ -51,9 +51,9 @@ def make_excel(ifile: str | None, ofile: Path | None, scenario: set[str]) -> Non header_format = workbook.add_format({'bold': True, 'text_wrap': True, 'align': 'left'}) query_all_techs = """ - SELECT DISTINCT Efficiency.region, Efficiency.tech, Technology.sector - FROM Efficiency - INNER JOIN Technology ON Efficiency.tech = Technology.tech + SELECT DISTINCT efficiency.region, efficiency.tech, Technology.sector + FROM efficiency + INNER JOIN Technology ON efficiency.tech = Technology.tech """ all_techs = pd.read_sql_query(query_all_techs, con) @@ -117,7 +117,7 @@ def make_excel(ifile: str | None, ofile: Path | None, scenario: set[str]) -> Non query_all_emis = """ SELECT DISTINCT ea.region, ea.tech, ea.emis_comm, t.sector - FROM EmissionActivity ea + FROM emission_activity ea INNER JOIN Technology t ON ea.tech = t.tech """ try: diff --git a/temoa/extensions/breakeven/breakeven.py b/temoa/extensions/breakeven/breakeven.py index 7f8459e75..714c6f044 100644 --- a/temoa/extensions/breakeven/breakeven.py +++ b/temoa/extensions/breakeven/breakeven.py @@ -3,8 +3,8 @@ from collections import defaultdict from time import time -import CplexSolverError import cplex +import CplexSolverError import pandas as pd from matplotlib import pyplot as plt from openpyxl import Workbook @@ -81,19 +81,19 @@ def coef_IC(instance, target_tech, target_year): P_e = instance.time_future.last() GDR = value(instance.GlobalDiscountRate) MPL = instance.ModelProcessLife - LLN = instance.LoanLifetimeProcess + LLN = instance.loan_lifetime_process x = 1 + GDR # convenience variable, nothing more. period_available = set() for p in instance.time_future: - if (p, t, v) in instance.CostFixed.keys(): + if (p, t, v) in instance.cost_fixed.keys(): period_available.add(p) c_i = ( - instance.CostInvest[t, v] - * instance.LoanAnnualize[t, v] + instance.cost_invest[t, v] + * instance.loan_annualize[t, v] * (LLN[t, v] if not GDR else (x ** (P_0 - v + 1) * (1 - x ** (-value(LLN[t, v]))) / GDR)) ) * ( - (1 - x ** (-min(value(instance.LifetimeProcess[t, v]), P_e - v))) - / (1 - x ** (-value(instance.LifetimeProcess[t, v]))) + (1 - x ** (-min(value(instance.lifetime_process[t, v]), P_e - v))) + / (1 - x ** (-value(instance.lifetime_process[t, v]))) ) return value(c_i) @@ -106,15 +106,15 @@ def coef_FC(instance, target_tech, target_year): P_e = instance.time_future.last() GDR = value(instance.GlobalDiscountRate) MPL = instance.ModelProcessLife - LLN = instance.LoanLifetimeProcess + LLN = instance.loan_lifetime_process x = 1 + GDR # convenience variable, nothing more. period_available = set() for p in instance.time_future: - if (p, t, v) in instance.CostFixed.keys(): + if (p, t, v) in instance.cost_fixed.keys(): period_available.add(p) c_f = sum( - instance.CostFixed[p, t, v] + instance.cost_fixed[p, t, v] * ( MPL[p, t, v] if not GDR @@ -173,7 +173,7 @@ def sensitivity(dat, techs): P_0 = min(instance.time_optimize) GDR = value(instance.GlobalDiscountRate) MPL = instance.ModelProcessLife - LLN = instance.LoanLifetimeProcess + LLN = instance.loan_lifetime_process x = 1 + GDR # convenience variable, nothing more. bic_s[t] = list() @@ -183,11 +183,11 @@ def sensitivity(dat, techs): for v in vintages: period_available = set() for p in instance.time_future: - if (p, t, v) in instance.CostFixed.keys(): + if (p, t, v) in instance.cost_fixed.keys(): period_available.add(p) c_i = ( - instance.CostInvest[t, v] - * instance.LoanAnnualize[t, v] + instance.cost_invest[t, v] + * instance.loan_annualize[t, v] * ( LLN[t, v] if not GDR @@ -196,7 +196,7 @@ def sensitivity(dat, techs): ) c_s = (-1) * ( - value(instance.CostInvest[t, v]) + value(instance.cost_invest[t, v]) * value(instance.SalvageRate[t, v]) / ( 1 @@ -207,7 +207,7 @@ def sensitivity(dat, techs): ) c_f = sum( - instance.CostFixed[p, t, v] + instance.cost_fixed[p, t, v] * ( MPL[p, t, v] if not GDR @@ -217,12 +217,12 @@ def sensitivity(dat, techs): ) c = c_i + c_s + c_f - s = (c - instance.lrc[instance.V_Capacity[t, v]]) / c + s = (c - instance.lrc[instance.v_capacity[t, v]]) / c coef_CAP[t, v] = c scal_CAP[t, v] = s # Must reduce TO this percentage - bic_s[t].append(scal_CAP[t, v] * instance.CostInvest[t, v]) - ic_s[t].append(instance.CostInvest[t, v]) - cap_s[t].append(value(instance.V_Capacity[t, v])) + bic_s[t].append(scal_CAP[t, v] * instance.cost_invest[t, v]) + ic_s[t].append(instance.cost_invest[t, v]) + cap_s[t].append(value(instance.v_capacity[t, v])) # print("Tech\tVintage\tL. RC\tCoef\tU .RC\tScale\tBE IC\tBE FC\tIC\tFC\tCap") print( @@ -241,8 +241,8 @@ def sensitivity(dat, techs): ) ) for v in vintages: - lrc = instance.lrc[instance.V_Capacity[t, v]] - urc = instance.urc[instance.V_Capacity[t, v]] + lrc = instance.lrc[instance.v_capacity[t, v]] + urc = instance.urc[instance.v_capacity[t, v]] # print("{:>s}\t{:>g}\t{:>.0f}\t{:>.0f}\t{:>.0f}\t{:>.3f}\t{:>.1f}\t{:>.1f}\t{:>.0f}\t{:>.0f}\t{:>.3f}".format() print( @@ -253,11 +253,11 @@ def sensitivity(dat, techs): coef_CAP[t, v], urc, scal_CAP[t, v], - scal_CAP[t, v] * instance.CostInvest[t, v], - scal_CAP[t, v] * instance.CostFixed[v, t, v], # Use the FC of the first period - instance.CostInvest[t, v], - instance.CostFixed[v, t, v], - value(instance.V_Capacity[t, v]), + scal_CAP[t, v] * instance.cost_invest[t, v], + scal_CAP[t, v] * instance.cost_fixed[v, t, v], # Use the FC of the first period + instance.cost_invest[t, v], + instance.cost_fixed[v, t, v], + value(instance.v_capacity[t, v]), ) ) @@ -283,8 +283,8 @@ def sensitivity(dat, techs): p, s, tod, - instance.dual[instance.DemandConstraint[p, s, tod, c]], - instance.slack[instance.DemandConstraint[p, s, tod, c]], + instance.dual[instance.demand_constraint[p, s, tod, c]], + instance.slack[instance.demand_constraint[p, s, tod, c]], ) @@ -341,7 +341,7 @@ def sensitivity_api(instance, techs, algorithm=None): ic_s[t] = list() cap_s[t] = list() for v in vintages: - target_var = 'V_Capacity(' + t + '_' + str(v) + ')' + target_var = 'v_capacity(' + t + '_' + str(v) + ')' c0 = c.objective.get_linear(target_var) clb, cub = c.solution.sensitivity.objective( target_var @@ -356,10 +356,10 @@ def sensitivity_api(instance, techs, algorithm=None): sys.exit(0) coef_CAP[t, v] = c0 scal_CAP[t, v] = clb / c0 # Break-even cost 1: Scaling both IC and FC - alpha = c_i / value(instance.CostInvest[t, v]) + alpha = c_i / value(instance.cost_invest[t, v]) bic = (clb - c_f) / alpha # Break-even cost 2: Only decrease IC bic_s[t].append(bic) - ic_s[t].append(value(instance.CostInvest[t, v])) + ic_s[t].append(value(instance.cost_invest[t, v])) cap_s[t].append(c.solution.get_values(target_var)) print( @@ -390,7 +390,7 @@ def sensitivity_api(instance, techs, algorithm=None): for v in vintages: deployed = abs(cap_s[t][vintages.index(v)]) >= 1e-3 tmp_beic_cs = ( - value(instance.CostInvest[t, v]) if deployed else bic_s[t][vintages.index(v)] + value(instance.cost_invest[t, v]) if deployed else bic_s[t][vintages.index(v)] ) tmp_bes_cs = 1 if deployed else scal_CAP[t, v] row = { @@ -403,7 +403,7 @@ def sensitivity_api(instance, techs, algorithm=None): 'coef upper bound': cub_s[t, v], 'scale': scal_CAP[t, v], 'BE IC': bic_s[t][vintages.index(v)], - 'IC': value(instance.CostInvest[t, v]), + 'IC': value(instance.cost_invest[t, v]), 'capacity': cap_s[t][vintages.index(v)], 'BE IC (CS)': tmp_beic_cs, 'scale (CS)': tmp_bes_cs, @@ -418,7 +418,7 @@ def sensitivity_api(instance, techs, algorithm=None): cub_s[t, v], scal_CAP[t, v], bic_s[t][vintages.index(v)], - value(instance.CostInvest[t, v]), + value(instance.cost_invest[t, v]), cap_s[t][vintages.index(v)], ) ) @@ -431,7 +431,7 @@ def sensitivity_api(instance, techs, algorithm=None): cub_s[t, v], scal_CAP[t, v], bic_s[t][vintages.index(v)], - value(instance.CostInvest[t, v]), + value(instance.cost_invest[t, v]), cap_s[t][vintages.index(v)], ) msg += '\n' @@ -473,16 +473,16 @@ def bin_search(tech, vintage, dat, eps=0.01, all_v=False): fc0 = dict() if all_v: for v in time_optimize: - if (monitor_tech, v) in data['CostInvest']: - ic0[monitor_tech, v] = data['CostInvest'][monitor_tech, v] + if (monitor_tech, v) in data['cost_invest']: + ic0[monitor_tech, v] = data['cost_invest'][monitor_tech, v] for p in time_optimize: - if (p, monitor_tech, v) in data['CostFixed']: - fc0[p, monitor_tech, v] = data['CostFixed'][p, monitor_tech, v] + if (p, monitor_tech, v) in data['cost_fixed']: + fc0[p, monitor_tech, v] = data['cost_fixed'][p, monitor_tech, v] else: - ic0[monitor_tech, monitor_year] = data['CostInvest'][monitor_tech, monitor_year] + ic0[monitor_tech, monitor_year] = data['cost_invest'][monitor_tech, monitor_year] for p in time_optimize: - if (p, monitor_tech, monitor_year) in data['CostFixed']: - fc0[p, monitor_tech, monitor_year] = data['CostFixed'][ + if (p, monitor_tech, monitor_year) in data['cost_fixed']: + fc0[p, monitor_tech, monitor_year] = data['cost_fixed'][ p, monitor_tech, monitor_year ] @@ -497,14 +497,14 @@ def bin_search(tech, vintage, dat, eps=0.01, all_v=False): counter = 0 scale_this = scale_u # Starting scale - print('Iteration # {} starts at {} s'.format(counter, time_mark())) + print(f'Iteration # {counter} starts at {time_mark()} s') instance = model.create_instance(data) instance.preprocess() results = optimizer.solve(instance, suffixes=['dual', 'urc', 'slack', 'lrc']) instance.solutions.load_from(results) - cap_target = value(instance.V_Capacity[monitor_tech, monitor_year]) - print('Iteration # {} solved at {} s'.format(counter, time_mark())) - print('Iteration # {}, scale: {:1.2f}, capacity: {} GW'.format(counter, scale_this, cap_target)) + cap_target = value(instance.v_capacity[monitor_tech, monitor_year]) + print(f'Iteration # {counter} solved at {time_mark()} s') + print(f'Iteration # {counter}, scale: {scale_this:1.2f}, capacity: {cap_target} GW') if 1.0 - scale_this <= eps and cap_target > 0: return scale_this @@ -519,17 +519,17 @@ def bin_search(tech, vintage, dat, eps=0.01, all_v=False): scale_this = (scale_u + scale_l) * 0.5 for k in ic0: - data['CostInvest'][k] = scale_this * ic0[k] + data['cost_invest'][k] = scale_this * ic0[k] for k in fc0: - data['CostFixed'][k] = scale_this * fc0[k] + data['cost_fixed'][k] = scale_this * fc0[k] - print('Iteration # {} starts at {} s'.format(counter, time_mark())) + print(f'Iteration # {counter} starts at {time_mark()} s') instance = model.create_instance(data) instance.preprocess() results = optimizer.solve(instance, suffixes=['dual', 'urc', 'slack', 'lrc']) instance.solutions.load_from(results) - cap_target = value(instance.V_Capacity[monitor_tech, monitor_year]) - print('Iteration # {} solved at {} s'.format(counter, time_mark())) + cap_target = value(instance.v_capacity[monitor_tech, monitor_year]) + print(f'Iteration # {counter} solved at {time_mark()} s') print( 'Iteration # {}, scale: {:1.2f}, capacity: {} GW'.format( counter, scale_this, cap_target @@ -581,7 +581,7 @@ def return_row(c0, scale, capacity): msg = '' target_year = v target_tech = t - target_var0 = 'V_Capacity(' + target_tech + '_' + str(target_year) + ')' + target_var0 = 'v_capacity(' + target_tech + '_' + str(target_year) + ')' t0 = time() time_mark = lambda: time() - t0 @@ -599,8 +599,8 @@ def return_row(c0, scale, capacity): counter = 0 scale_this = scale_u # Starting scale - print('Iteration # {} starts at {} s'.format(counter, time_mark())) - msg += 'Iteration # {} starts at {} s\n'.format(counter, time_mark()) + print(f'Iteration # {counter} starts at {time_mark()} s') + msg += f'Iteration # {counter} starts at {time_mark()} s\n' try: cplex_instance.solve() except CplexSolverError: @@ -608,11 +608,9 @@ def return_row(c0, scale, capacity): msg += 'Exception raised during solve\n' return msg, None cap_target0 = cplex_instance.solution.get_values(target_var0) - print('Iteration # {} solved at {} s'.format(counter, time_mark())) - msg += 'Iteration # {} solved at {} s\n'.format(counter, time_mark()) - print( - 'Iteration # {}, scale: {:1.2f}, capacity: {} GW'.format(counter, scale_this, cap_target0) - ) + print(f'Iteration # {counter} solved at {time_mark()} s') + msg += f'Iteration # {counter} solved at {time_mark()} s\n' + print(f'Iteration # {counter}, scale: {scale_this:1.2f}, capacity: {cap_target0} GW') if 1.0 - scale_this <= eps and cap_target0 > 0: row = return_row(c0, scale_this, cap_target0) return msg, pd.DataFrame([row]) @@ -630,8 +628,8 @@ def return_row(c0, scale, capacity): scale_this = (scale_u + scale_l) * 0.5 cplex_instance.objective.set_linear(target_var0, scale_this * c0) - print('Iteration # {} starts at {} s'.format(counter, time_mark())) - msg += 'Iteration # {} starts at {} s'.format(counter, time_mark()) + print(f'Iteration # {counter} starts at {time_mark()} s') + msg += f'Iteration # {counter} starts at {time_mark()} s' try: cplex_instance.solve() except CplexSolverError: @@ -639,8 +637,8 @@ def return_row(c0, scale, capacity): msg += 'Exception raised during solve\n' return msg, None cap_target = cplex_instance.solution.get_values(target_var0) - print('Iteration # {} solved at {} s'.format(counter, time_mark())) - msg += 'Iteration # {} solved at {} s\n'.format(counter, time_mark()) + print(f'Iteration # {counter} solved at {time_mark()} s') + msg += f'Iteration # {counter} solved at {time_mark()} s\n' print( 'Iteration # {}, scale: {:1.2f}, capacity: {} GW'.format( counter, scale_this, cap_target @@ -654,13 +652,13 @@ def sen_range_api(tech, vintage, scales, list_dat): # This function is adapted from CPLEX's example script lpex2.py # It does the same thing as sen_range, but with CPLEX API for Python - # Given a range of scaling factor for coefficient of a specific V_Capacity, + # Given a range of scaling factor for coefficient of a specific v_capacity, # returns objective value, reduced cost, capacity etc. for each scaling # factor target_year = vintage target_tech = tech - target_var0 = 'V_Capacity(' + target_tech + '_' + str(target_year) + ')' + target_var0 = 'v_capacity(' + target_tech + '_' + str(target_year) + ')' algmap = { 'primal simplex': 'p', 'dual simplex': 'd', @@ -675,8 +673,8 @@ def sen_range_api(tech, vintage, scales, list_dat): data = return_Temoa_data(model, list_dat) instance = model.create_instance(data) - ic0 = data['CostInvest'][target_tech, target_year] - fc0 = data['CostFixed'][target_year, target_tech, target_year] + ic0 = data['cost_invest'][target_tech, target_year] + fc0 = data['cost_fixed'][target_year, target_tech, target_year] all_periods = data['time_future'] obj = dict() @@ -691,7 +689,7 @@ def sen_range_api(tech, vintage, scales, list_dat): rc = dict() # Reduced cost for algorithm in ['barrier', 'dual simplex', 'primal simplex']: - print('Algorithm: {}'.format(algorithm)) + print(f'Algorithm: {algorithm}') instance.write('tmp.lp', io_options={'symbolic_solver_labels': True}) c = cplex.Cplex('tmp.lp') os.remove('tmp.lp') @@ -700,7 +698,7 @@ def sen_range_api(tech, vintage, scales, list_dat): if not validate_coef(c0, instance, target_tech, target_year): print('Error!') sys.exit(0) - print('[{:>9.2f}] CPLEX model loaded.'.format(time_mark())) + print(f'[{time_mark():>9.2f}] CPLEX model loaded.') if algmap[algorithm] == 'o': c.parameters.lpmethod.set(c.parameters.lpmethod.values.auto) @@ -731,7 +729,7 @@ def sen_range_api(tech, vintage, scales, list_dat): cub_alg = defaultdict(list) rc_alg = defaultdict(list) for s in scales: - print('[{:>9.2f}] Scale: {:>.3f} starts'.format(time_mark(), s)) + print(f'[{time_mark():>9.2f}] Scale: {s:>.3f} starts') c.objective.set_linear(target_var0, s * c0) try: @@ -743,7 +741,7 @@ def sen_range_api(tech, vintage, scales, list_dat): obj_alg.append(c.solution.get_objective_value()) for y in instance.time_optimize: key = str(y) - target_var = 'V_Capacity(' + target_tech + '_' + key + ')' + target_var = 'v_capacity(' + target_tech + '_' + key + ')' coefficient = c.objective.get_linear(target_var) if y != target_year: if not validate_coef(coefficient, instance, target_tech, y): @@ -760,8 +758,8 @@ def sen_range_api(tech, vintage, scales, list_dat): except: c_bound = [None, None] s_be = None - cost_i = s * value(instance.CostInvest[target_tech, y]) - cost_f = s * value(instance.CostFixed[y, target_tech, y]) + cost_i = s * value(instance.cost_invest[target_tech, y]) + cost_f = s * value(instance.cost_fixed[y, target_tech, y]) cap_alg[key].append(capacity) coef_alg[key].append(coefficient) @@ -789,7 +787,7 @@ def sen_range_api(tech, vintage, scales, list_dat): rc[algorithm] = rc_alg # Write to Excel spreadsheet - print('[{:>9.2f}] Saving to Excel spreadsheet'.format(time_mark())) + print(f'[{time_mark():>9.2f}] Saving to Excel spreadsheet') row_title = [ 'scale', 'obj', @@ -842,7 +840,7 @@ def sen_range_api(tech, vintage, scales, list_dat): def sen_range(tech, vintage, scales, dat): - # Given a range of scaling factor for coefficient of a specific V_Capacity, + # Given a range of scaling factor for coefficient of a specific v_capacity, # returns objective value, reduced cost, capacity etc. for each scaling # factor from openpyxl import Workbook @@ -863,8 +861,8 @@ def sen_range(tech, vintage, scales, dat): data = return_Temoa_data(model, dat) optimizer = SolverFactory('cplex') - ic0 = data['CostInvest'][target_tech, target_year] - fc0 = data['CostFixed'][target_year, target_tech, target_year] + ic0 = data['cost_invest'][target_tech, target_year] + fc0 = data['cost_fixed'][target_year, target_tech, target_year] all_periods = data['time_future'] obj = dict() @@ -879,7 +877,7 @@ def sen_range(tech, vintage, scales, dat): for algorithm in ['barrier', 'dual simplex', 'primal simplex']: optimizer.options['lpmethod'] = algmap[algorithm] - print('Algorithm: {}'.format(algorithm)) + print(f'Algorithm: {algorithm}') obj_alg = list() cap_alg = defaultdict(list) @@ -891,26 +889,26 @@ def sen_range(tech, vintage, scales, dat): ic_alg = defaultdict(list) fc_alg = defaultdict(list) for s in scales: - print('[{:>9.2f}] Scale: {:>.3f} starts'.format(time_mark(), s)) - data['CostInvest'][target_tech, target_year] = s * ic0 + print(f'[{time_mark():>9.2f}] Scale: {s:>.3f} starts') + data['cost_invest'][target_tech, target_year] = s * ic0 for y in data['time_future']: - if (y, target_tech, target_year) in data['CostFixed']: - data['CostFixed'][y, target_tech, target_year] = s * fc0 + if (y, target_tech, target_year) in data['cost_fixed']: + data['cost_fixed'][y, target_tech, target_year] = s * fc0 instance = model.create_instance(data) instance.preprocess() results = optimizer.solve(instance, suffixes=['dual', 'urc', 'slack', 'lrc']) instance.solutions.load_from(results) - obj_alg.append(value(instance.TotalCost)) + obj_alg.append(value(instance.total_cost)) for y in instance.time_optimize: key = str(y) c_vector = return_c_vector(instance, []) - coefficient = c_vector[('V_Capacity', (target_tech, y))] - capacity = value(instance.V_Capacity[target_tech, y]) - lower_rc = value(instance.lrc[instance.V_Capacity[target_tech, y]]) - upper_rc = value(instance.urc[instance.V_Capacity[target_tech, y]]) - cost_i = value(instance.CostInvest[target_tech, y]) - cost_f = value(instance.CostFixed[y, target_tech, y]) + coefficient = c_vector[('v_capacity', (target_tech, y))] + capacity = value(instance.v_capacity[target_tech, y]) + lower_rc = value(instance.lrc[instance.v_capacity[target_tech, y]]) + upper_rc = value(instance.urc[instance.v_capacity[target_tech, y]]) + cost_i = value(instance.cost_invest[target_tech, y]) + cost_f = value(instance.cost_fixed[y, target_tech, y]) s_be = (coefficient - lower_rc) / coefficient # Break-even scale cap_alg[key].append(capacity) @@ -933,7 +931,7 @@ def sen_range(tech, vintage, scales, dat): fc[algorithm] = fc_alg # Write to Excel spreadsheet - print('[{:>9.2f}] Saving to Excel spreadsheet'.format(time_mark())) + print(f'[{time_mark():>9.2f}] Saving to Excel spreadsheet') row_title = ['scale', 'obj', 'cap', 'lrc', 'coef', 'urc', 'bic', 'bfc', 'ic', 'fc'] wb = Workbook() # for ws_title in cap_alg: @@ -987,7 +985,7 @@ def explore_Cost_marginal(dat): instance = model.create_instance(data) # Deactivate the DemandActivity constraint - # instance.DemandActivityConstraint.deactivate() + # instance.demand_activity_constraint.deactivate() # instance.preprocess() optimizer = SolverFactory('cplex') @@ -1011,7 +1009,7 @@ def explore_Cost_marginal(dat): # for p in instance.time_optimize: # for s in instance.time_season: # for tod in instance.time_of_day: - # print(p, s, tod, instance.dual[instance.DemandConstraint[p,s,tod,c]], instance.slack[instance.DemandConstraint[p,s,tod,c]]) + # print(p, s, tod, instance.dual[instance.demand_constraint[p,s,tod,c]], instance.slack[instance.demand_constraint[p,s,tod,c]]) def plot_breakeven(years, bic, ic): diff --git a/temoa/extensions/get_comm_tech.py b/temoa/extensions/get_comm_tech.py index c4a36f8df..bc059d81c 100644 --- a/temoa/extensions/get_comm_tech.py +++ b/temoa/extensions/get_comm_tech.py @@ -103,25 +103,25 @@ def get_comm(inp_f, db_dat): with open(inp_f) as f: for line in f: if eff_flag is False and re.search( - '^\s*param\s+efficiency\s*[:][=]', line, flags=re.I + r'^\s*param\s+efficiency\s*[:][=]', line, flags=re.I ): - # Search for the line param Efficiency := (The script recognizes the commodities specified in this section) + # Search for the line param efficiency := (The script recognizes the commodities specified in this section) eff_flag = True elif eff_flag: line = re.sub('[#].*$', ' ', line) - if re.search('^\s*;\s*$', line): + if re.search(r'^\s*;\s*$', line): break # Finish searching this section when encounter a ';' - if re.search('^\s+$', line): + if re.search(r'^\s+$', line): continue - line = re.sub('^\s+|\s+$', '', line) - row = re.split('\s+', line) + line = re.sub(r'^\s+|\s+$', '', line) + row = re.split(r'\s+', line) if row[0] != 'ethos': comm_set.add(row[0]) comm_set.add(row[3]) if eff_flag is False: print( - 'Error: The Efficiency Parameters cannot be found in the specified file - ' + inp_f + 'Error: The efficiency Parameters cannot be found in the specified file - ' + inp_f ) sys.exit(2) @@ -164,23 +164,23 @@ def get_tech(inp_f, db_dat): with open(inp_f) as f: for line in f: if eff_flag is False and re.search( - '^\s*param\s+efficiency\s*[:][=]', line, flags=re.I + r'^\s*param\s+efficiency\s*[:][=]', line, flags=re.I ): - # Search for the line param Efficiency := (The script recognizes the commodities specified in this section) + # Search for the line param efficiency := (The script recognizes the commodities specified in this section) eff_flag = True elif eff_flag: line = re.sub('[#].*$', ' ', line) - if re.search('^\s*;\s*$', line): + if re.search(r'^\s*;\s*$', line): break # Finish searching this section when encounter a ';' - if re.search('^\s+$', line): + if re.search(r'^\s+$', line): continue - line = re.sub('^\s+|\s+$', '', line) - row = re.split('\s+', line) + line = re.sub(r'^\s+|\s+$', '', line) + row = re.split(r'\s+', line) tech_set.add(row[1]) if eff_flag is False: print( - 'Error: The Efficiency Parameters cannot be found in the specified file - ' + inp_f + 'Error: The efficiency Parameters cannot be found in the specified file - ' + inp_f ) sys.exit(2) @@ -261,7 +261,7 @@ def get_info(inputs): raise Exception('no arguments found') for opt, arg in inputs.items(): - print('%s == %s' % (opt, arg)) + print(f'{opt} == {arg}') if opt in ('-i', '--input'): inp_file = arg @@ -297,7 +297,7 @@ def get_info(inputs): file_ty = re.search(r'(\w+)\.(\w+)\b', inp_file) # Extract the input filename and extension if not file_ty: - raise Exception('The file type {} is not recognized.'.format(file_ty)) + raise Exception(f'The file type {file_ty} is not recognized.') elif file_ty.group(2) in ('db', 'sqlite', 'sqlite3', 'sqlitedb'): db_or_dat = False diff --git a/temoa/extensions/method_of_morris/MM_README.md b/temoa/extensions/method_of_morris/MM_README.md index 2af27950e..8152e43a8 100644 --- a/temoa/extensions/method_of_morris/MM_README.md +++ b/temoa/extensions/method_of_morris/MM_README.md @@ -1,56 +1,60 @@ # Method of Morris -### This document gives a _brief_ description of MM application and shows how to execute the provided example. +### This document gives a _brief_ description of MM application and shows how to execute the provided example ## Background -- MM is a Sensitivity Analysis (SA) technique that uses a unique Design Of Experiments (DOE) application to + +- MM is a Sensitivity Analysis (SA) technique that uses a unique Design Of Experiments (DOE) application to explore the input space. -- The MM techniques in Temoa utilize `SALib` which has fairly -thorough [documentation](https://salib.readthedocs.io/en/latest/api.html#method-of-morris) online, +- The MM techniques in Temoa utilize `SALib` which has fairly +thorough [documentation](https://salib.readthedocs.io/en/latest/api.html#method-of-morris) online, which also refers to relevant studies. ## Use + - The current MM setup in Temoa is capable of exploring input parameters from 3 tables: - - CostVariable - - CostInvest - - Efficiency -- The MM application will analyze effects of marked parameters (or groups) on the cost function + - cost_variable + - cost_invest + - efficiency +- The MM application will analyze effects of marked parameters (or groups) on the cost function (objective) and on co2 emissions specifically. - - It should be noted that co2 is _not_ optimized in any way, it is just the co2 emission + - It should be noted that co2 is _not_ optimized in any way, it is just the co2 emission for the optimal cost solution - - Further, the code is currently hard-coded to look for _exactly_ the string `co2` in the - `OutputEmissions` table. It is highly advisable to do a "regular" run on the data to ensure + - Further, the code is currently hard-coded to look for _exactly_ the string `co2` in the + `OutputEmissions` table. It is highly advisable to do a "regular" run on the data to ensure that `co2` is properly represented in the commodity and output tables. -- The basic sequence is: marking of input parameters (by user) and domains (through the `perturbation` +- The basic sequence is: marking of input parameters (by user) and domains (through the `perturbation` value in the `config`) -> make a MM Sample set -> run Temoa on the samples -> conduct MM analysis. -- In order to use MM in Temoa, the subject database needs to be augmented slightly to allow +- In order to use MM in Temoa, the subject database needs to be augmented slightly to allow relevant parameters to be marked for analysis. -- After Parameters are marked with group labels, the `morris` options should be set in the +- After Parameters are marked with group labels, the `morris` options should be set in the relevant `config.toml` file which can then be run. - Outputs are stored in the standard time-stamped output folder. ### Example: `morris_utopia` + 1. Convert the `.sql` file in the `example_dbs` folder back to a database: `data_files/example_dbs % sqlite3 morris_utopia.sqlite < morris_utopia.sql` -2. Observe the markings (3 groups) in the `MMAnalysis` columns in `CostVariable` and `Efficiency`. +2. Observe the markings (3 groups) in the `MMAnalysis` columns in `cost_variable` and `efficiency`. 3. Observe the `morris` configuration comments in the corresponding `morris_utopia.toml` file in `my_configs`. 4. Run the config as normal. 5. MM analysis is reported on screen and in 2 csv files for the objective and `co2` in the Outputs folder 6. The DB will contain updated values (tagged by scenario name and "dash run") in `OutputObjective` and `OutputEmissions` -_only_ which might be of secondary value to the modeler. Other output tables are *not* updated. +_only_ which might be of secondary value to the modeler. Other output tables are _not_ updated. ### Preparing Other Databases (or modifying `morris_utopia`) -1. Augment all 3 of the tables (`CostInvest`, `CostInvest`, `Efficiency`) with a column (field) `MMAnalysis` + +1. Augment all 3 of the tables (`cost_invest`, `cost_invest`, `efficiency`) with a column (field) `MMAnalysis` that is `TEXT` data type, allowing NULL. 2. Add labels within that column for analysis. Note: - Labels that are repeated (in any table) are treated as a "Group" for MM purposes. - Labels that are used singly are a "group of 1". - - The number of runs will be: `(GROUPS + 1) x N` where `N` is the number of trajectories in the `config`. + - The number of runs will be: `(GROUPS + 1) x N` where `N` is the number of trajectories in the `config`. - Note: number runs is _independent_ of the total params marked (groups can be large and are varied together) - - The modeler need to consider how to group multiple vintages/periods for specific techs and/or group + - The modeler need to consider how to group multiple vintages/periods for specific techs and/or group related techs. 3. The modeler should consider the architecture used to run the model for cpu utilization. The number of cores to use is selectable in the `config` for parallel use. A `0` can be used to utilize all available cores diff --git a/temoa/extensions/method_of_morris/Method_of_Morris_README.txt b/temoa/extensions/method_of_morris/Method_of_Morris_README.txt index a2ed46e75..9c4957614 100644 --- a/temoa/extensions/method_of_morris/Method_of_Morris_README.txt +++ b/temoa/extensions/method_of_morris/Method_of_Morris_README.txt @@ -13,17 +13,17 @@ https://groups.google.com/forum/#!topic/temoa-project/SEqlvJOpnb0 1. Install SALib (pip install SALib). It's an open source python sensitivity analysis library. -2. Download the attached file and put it in your "temoa-energysystem" directory. Basically what this script does, is reading the baseline values of the parameters you want to do the sensitivity analysis on (say price of a specific fuel or technology), perturbing them by -+10% and creating text files which include all the parameters and their corresponding ranges of change (0.9*baseline=lower bound, 1.1*baseline=upper bound), sending the text files to SALib to generate the sampling matrix (param_values parameter in the script), running the model with the sampling matrix as many times as needed (you can control the number of the runs changing the N in line 141), reading the objective function values and CO2 emissions from the database for each run and sending their corresponding values to SALib to do the analysis. +2. Download the attached file and put it in your "temoa-energysystem" directory. Basically what this script does, is reading the baseline values of the parameters you want to do the sensitivity analysis on (say price of a specific fuel or technology), perturbing them by -+10% and creating text files which include all the parameters and their corresponding ranges of change (0.9*baseline=lower bound, 1.1*baseline=upper bound), sending the text files to SALib to generate the sampling matrix (param_values parameter in the script), running the model with the sampling matrix as many times as needed (you can control the number of the runs changing the N in line 141), reading the objective function values and CO2 emissions from the database for each run and sending their corresponding values to SALib to do the analysis. -3. Currently the sensitivity analysis can be done only on the parameters in the tables: CostInvest, CostVariable and Efficiency. You need to add a new column in your sqlite database for these tables. You do this by just executing these 3 lines: +3. Currently the sensitivity analysis can be done only on the parameters in the tables: cost_invest, cost_variable and efficiency. You need to add a new column in your sqlite database for these tables. You do this by just executing these 3 lines: -ALTER TABLE 'CostInvest' ADD 'MMAnalysis' -ALTER TABLE 'CostVariable' ADD 'MMAnalysis' -ALTER TABLE 'Efficiency' ADD 'MMAnalysis' +ALTER TABLE 'cost_invest' ADD 'MMAnalysis' +ALTER TABLE 'cost_variable' ADD 'MMAnalysis' +ALTER TABLE 'efficiency' ADD 'MMAnalysis' -4. Once this additional column is added for the 3 tables, you need to add names to the cell under MMAnalysis column which corresponds to the parameters you want to do the sensitivity analysis for. For example in Utopia case study, suppose you want to do the sensitivity analysis on gasoline, diesel and coal prices. +4. Once this additional column is added for the 3 tables, you need to add names to the cell under MMAnalysis column which corresponds to the parameters you want to do the sensitivity analysis for. For example in Utopia case study, suppose you want to do the sensitivity analysis on gasoline, diesel and coal prices. -Here, parameters with the same text in the MMAnalysis column are seen as "groups" of parameters and are changed simultaneously during the sampling process. If you don't want to use groups, you can put different names on each parameters and the MM only considers the sensitivity with respect to that specific variable. The former gives the sensitivity for a group of parameters. +Here, parameters with the same text in the MMAnalysis column are seen as "groups" of parameters and are changed simultaneously during the sampling process. If you don't want to use groups, you can put different names on each parameters and the MM only considers the sensitivity with respect to that specific variable. The former gives the sensitivity for a group of parameters. 5. Change your database name to "Method_of_Morris.sqlite" and like other databases ran by Temoa, put it in db_io/dbs directory. @@ -36,4 +36,4 @@ Other implementation-related issues you should know: 1. The scripts parallelizes all the cores in your machine when running the model. It might not be significant in small case studies for bigger models, using all the cores saves the time need to run the model. 2. It's very important that the reference to your input and output sqlite files in the config_sample file (--input=db_io/dbs/Method_of_Morris.sqlite and --output=db_io/dbs/Method_of_Morris.sqlite) are placed in the 14th and 21nd lines of config_sample file. 3. Since you are using sqlite and not .db, change all the ".db" texts in the attached script to ".sqlite". -4. I would suggest keeping num_levels=4, grid_jump=2. For this setting should be greater than 10. The total number of the runs is N*(number of groups+1). \ No newline at end of file +4. I would suggest keeping num_levels=4, grid_jump=2. For this setting should be greater than 10. The total number of the runs is N*(number of groups+1). diff --git a/temoa/extensions/method_of_morris/morris.py b/temoa/extensions/method_of_morris/morris.py index 9f6d1f29b..52de436bd 100644 --- a/temoa/extensions/method_of_morris/morris.py +++ b/temoa/extensions/method_of_morris/morris.py @@ -28,11 +28,11 @@ def evaluate(param_names, param_values, data: dict, k): names = param_names[j] match names[0]: - case 'CostInvest': + case 'cost_invest': data[names[0]][tuple(names[1:4])] = param_values[j] - case 'CostVariable': + case 'cost_variable': data[names[0]][tuple(names[1:5])] = param_values[j] - case 'Efficiency': + case 'efficiency': data[names[0]][tuple(names[1:6])] = param_values[j] case _: raise ValueError(f'Unrecognized parameter: {names[0]}') @@ -73,13 +73,13 @@ def evaluate(param_names, param_values, data: dict, k): param_names = {} cur = con.cursor() cur.execute( - 'SELECT region, period, tech, vintage, cost, MMAnalysis FROM CostVariable WHERE MMAnalysis is not NULL' + 'SELECT region, period, tech, vintage, cost, MMAnalysis FROM cost_variable WHERE MMAnalysis is not NULL' ) output_query = cur.fetchall() g1 = len(output_query) for i in range(0, len(output_query)): param_names[i] = [ - 'CostVariable', + 'cost_variable', *output_query[i][:4], 'cost_variable', ] @@ -94,12 +94,12 @@ def evaluate(param_names, param_values, data: dict, k): file.write('\n') cur.execute( - 'SELECT region, tech, vintage, cost, MMAnalysis FROM CostInvest WHERE MMAnalysis is not NULL' + 'SELECT region, tech, vintage, cost, MMAnalysis FROM cost_invest WHERE MMAnalysis is not NULL' ) output_query = cur.fetchall() g2 = len(output_query) for i in range(0, len(output_query)): - param_names[i + g1] = ['CostInvest', *output_query[i][:3], 'cost_invest'] + param_names[i + g1] = ['cost_invest', *output_query[i][:3], 'cost_invest'] file.write('x' + str(i + g1)) file.write(' ') @@ -110,13 +110,13 @@ def evaluate(param_names, param_values, data: dict, k): file.write(output_query[i][-1]) file.write('\n') cur.execute( - 'SELECT DISTINCT region, input_comm, tech, vintage, output_comm, efficiency, MMAnalysis FROM Efficiency WHERE MMAnalysis is not NULL' + 'SELECT DISTINCT region, input_comm, tech, vintage, output_comm, efficiency, MMAnalysis FROM efficiency WHERE MMAnalysis is not NULL' ) output_query = cur.fetchall() g3 = len(output_query) for i in range(0, len(output_query)): param_names[i + g1 + g2] = [ - 'Efficiency', + 'efficiency', *output_query[i][:5], 'efficiency', ] diff --git a/temoa/extensions/method_of_morris/morris_sequencer.py b/temoa/extensions/method_of_morris/morris_sequencer.py index 9e7267d8e..9f41f98fe 100644 --- a/temoa/extensions/method_of_morris/morris_sequencer.py +++ b/temoa/extensions/method_of_morris/morris_sequencer.py @@ -253,13 +253,13 @@ def process_results(self, problem, mm_samples, morris_results): for category in analysis.keys(): print(f'\nAnalysis of {category}:') print( - '{0:<30} {1:>10} {2:>10} {3:>20} {4:>10}'.format( + '{:<30} {:>10} {:>10} {:>20} {:>10}'.format( 'Parameter', 'Mu_Star', 'Mu', mu_star_conf_label, 'Sigma' ) ) for j in list(range(number_of_groups)): print( - '{0:30} {1:10.3f} {2:10.3f} {3:20.3f} {4:10.3f}'.format( + '{:30} {:10.3f} {:10.3f} {:20.3f} {:10.3f}'.format( analysis[category]['names'][j], analysis[category]['mu_star'][j], analysis[category]['mu'][j], @@ -298,12 +298,12 @@ def gather_parameters(self): with open(self.param_file, 'w') as f: v_idx = 4 # index of variable to perturb raw = cur.execute( - 'SELECT region, period, tech, vintage, cost, MMAnalysis FROM CostVariable WHERE MMAnalysis IS NOT NULL' + 'SELECT region, period, tech, vintage, cost, MMAnalysis FROM cost_variable WHERE MMAnalysis IS NOT NULL' ).fetchall() g1 = len(raw) for i in range(0, len(raw)): param_names[i] = [ - 'CostVariable', + 'cost_variable', *raw[i][:4], 'cost_variable', ] @@ -317,11 +317,11 @@ def gather_parameters(self): v_idx = 3 raw = cur.execute( - 'SELECT region, tech, vintage, cost, MMAnalysis FROM CostInvest WHERE MMAnalysis IS NOT NULL' + 'SELECT region, tech, vintage, cost, MMAnalysis FROM cost_invest WHERE MMAnalysis IS NOT NULL' ).fetchall() g2 = len(raw) for i in range(0, len(raw)): - param_names[i + g1] = ['CostInvest', *raw[i][:3], 'cost_invest'] + param_names[i + g1] = ['cost_invest', *raw[i][:3], 'cost_invest'] iter = f'x{i + g1}' low = str(raw[i][v_idx] * (1 - self.mm_perturbation)) @@ -334,13 +334,13 @@ def gather_parameters(self): v_idx = 5 raw = cur.execute( 'SELECT DISTINCT region, input_comm, tech, vintage, output_comm, efficiency, ' - 'MMAnalysis FROM Efficiency WHERE MMAnalysis IS NOT NULL' + 'MMAnalysis FROM efficiency WHERE MMAnalysis IS NOT NULL' ).fetchall() g3 = len(raw) for i in range(0, len(raw)): param_names[i + g1 + g2] = [ - 'Efficiency', + 'efficiency', *raw[i][:5], 'efficiency', ] diff --git a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py index 927ff5c83..bda3cf224 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py +++ b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py @@ -188,7 +188,7 @@ def start(self): self.writer.write_summary_flow(instance, iteration=0) # 3a. Capture cost and make it a constraint - tot_cost = pyo.value(instance.TotalCost) + tot_cost = pyo.value(instance.total_cost) logger.info('Completed initial solve with total cost: %0.2f', tot_cost) logger.info('Relaxing cost by fraction: %0.3f', self.cost_epsilon) # get hook on the expression generator for total cost... @@ -198,7 +198,7 @@ def start(self): ) # 3b. remove the old objective and prep for iterative solving - instance.del_component(instance.TotalCost) + instance.del_component(instance.total_cost) # 4. Instantiate the vector manager vector_manager: VectorManager = get_manager( diff --git a/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py b/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py index ec9ac323c..0828dc3a7 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py +++ b/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py @@ -29,11 +29,10 @@ import queue import sqlite3 from collections import defaultdict -from collections.abc import Iterator +from collections.abc import Iterable, Iterator from logging import getLogger from pathlib import Path from queue import Queue -from typing import Iterable import numpy as np from matplotlib import pyplot as plt @@ -134,14 +133,14 @@ def initialize(self) -> None: logger.debug('Category %s members: %d', cat, len(self.category_mapping[cat])) # now pull the flow variables and map them - for idx in self.base_model.activeFlow_rpsditvo: + for idx in self.base_model.active_flow_rpsditvo: tech = idx[5] self.technology_size[tech] += 1 - self.variable_index_mapping[tech][self.base_model.V_FlowOut.name].append(idx) - for idx in self.base_model.activeFlow_rpitvo: + self.variable_index_mapping[tech][self.base_model.v_flow_out.name].append(idx) + for idx in self.base_model.active_flow_rpitvo: tech = idx[3] self.technology_size[tech] += 1 - self.variable_index_mapping[tech][self.base_model.V_FlowOutAnnual.name].append(idx) + self.variable_index_mapping[tech][self.base_model.v_flow_out_annual.name].append(idx) logger.debug('Catalogued %d Technology Variables', sum(self.technology_size.values())) @property diff --git a/temoa/extensions/monte_carlo/example_builds/scenario_maker.py b/temoa/extensions/monte_carlo/example_builds/scenario_maker.py index c93d53e1c..0768b3fd5 100644 --- a/temoa/extensions/monte_carlo/example_builds/scenario_maker.py +++ b/temoa/extensions/monte_carlo/example_builds/scenario_maker.py @@ -41,6 +41,7 @@ Let's make a set of 500 runs and explore output """ + from pathlib import Path import matplotlib.pyplot as plt @@ -73,11 +74,13 @@ f.write('run,param,index,mod,value,notes\n') for run_idx in range(num_runs): f.write( - f'{run_idx+1},CostVariable,*|*|IMPOIL1|*,r,{price_devs[run_idx, 0]},oil relative change\n' + f'{run_idx + 1},cost_variable,*|*|IMPOIL1|*,r,{price_devs[run_idx, 0]},oil relative change\n' + ) + f.write( + f'{run_idx + 1},Demand,*|*|RH,r,{price_devs[run_idx, 1]},res heat relative change\n' ) - f.write(f'{run_idx+1},Demand,*|*|RH,r,{price_devs[run_idx, 1]},res heat relative change\n') f.write( - f'{run_idx+1},CostInvest,*|E21|2000/2010,r,{nuc_dev[run_idx]},nuclear invest relative discount\n' + f'{run_idx + 1},cost_invest,*|E21|2000/2010,r,{nuc_dev[run_idx]},nuclear invest relative discount\n' ) if nuc_dev[run_idx] < 0: - f.write(f'{run_idx+1},CostFixed,*|*|E21|2000/2010,s,0.0,nuclear op cost covered\n') + f.write(f'{run_idx + 1},cost_fixed,*|*|E21|2000/2010,s,0.0,nuclear op cost covered\n') diff --git a/temoa/extensions/myopic/make_myopic_tables.sql b/temoa/extensions/myopic/make_myopic_tables.sql index b72d891bc..4f18f8241 100644 --- a/temoa/extensions/myopic/make_myopic_tables.sql +++ b/temoa/extensions/myopic/make_myopic_tables.sql @@ -1,6 +1,6 @@ BEGIN; -CREATE TABLE IF NOT EXISTS MyopicEfficiency +CREATE TABLE IF NOT EXISTS Myopicefficiency ( base_year integer, region text, @@ -15,7 +15,7 @@ CREATE TABLE IF NOT EXISTS MyopicEfficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm) ); -- for efficient searching by rtv: -CREATE INDEX IF NOT EXISTS region_tech_vintage ON MyopicEfficiency (region, tech, vintage); +CREATE INDEX IF NOT EXISTS region_tech_vintage ON Myopicefficiency (region, tech, vintage); -COMMIT; \ No newline at end of file +COMMIT; diff --git a/temoa/extensions/myopic/myopic table notes.md b/temoa/extensions/myopic/myopic table notes.md index 36689f020..bbfd9349c 100644 --- a/temoa/extensions/myopic/myopic table notes.md +++ b/temoa/extensions/myopic/myopic table notes.md @@ -1,18 +1,17 @@ -Notes on Myopic +Notes on Myopic =============== -MyopicEfficiency Table +Myopicefficiency Table ---------------- -- Largely similar to baseline Efficiency table +- Largely similar to baseline efficiency table - Built sequentially during myopic run from capacity built, not built, or retired in previous period. This table -needs to be "actively maintained" during the run because it is the source of filtering for all other model elements. - - Notable actions: +needs to be "actively maintained" during the run because it is the source of filtering for all other model elements. + - Notable actions: - Items NOT built in previous myopic windows are removed in the subsequent iteration. During normal model runs, - the model will add entries from the normal Efficiency tables for consideration, and then in the subsequent + the model will add entries from the normal efficiency tables for consideration, and then in the subsequent iteration, it will houseclean and remove any that were not selected for build. - Items that become fully retired *during their normal lifespan* are also deleted upon retirement. - Uses base-year field (column) as reference to when added, and ``-1`` indicates original existing capacity -- Adds a computed Lifetime field, which is handy for future computations and used internally to screen active +- Adds a computed Lifetime field, which is handy for future computations and used internally to screen active technologies during data loading. - diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index 71d08375d..bb1f8985d 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -48,11 +48,11 @@ class MyopicSequencer: 'OutputStorageLevel', ] tables_without_scenario_reference = [ - 'MyopicEfficiency', + 'Myopicefficiency', ] # Tables that may be cleaned by period during myopic run - # note: below excludes MyopicEfficiency, which is managed separately + # note: below excludes Myopicefficiency, which is managed separately tables_with_period = [ 'OutputCost', @@ -146,14 +146,14 @@ def start(self): # clear out the old riff-raff self.clear_old_results() - # start building the MyopicEfficiency table. + # start building the Myopicefficiency table. self.initialize_myopic_efficiency_table() # start the fundamental control loop # 1. get feedback from previous instance execution (optimal/infeasible/...) # 2. decide what to do about it # 3. pull the next instance from the queue (if !empty & if needed) - # 4. Update the MyopicEfficiency table (clean up history / add stuff now in visibility) + # 4. Update the Myopicefficiency table (clean up history / add stuff now in visibility) # 5. pull data for next run and filter it with source tracing # 6. build instance # 7. run checks (price check) on the model, if selected @@ -196,7 +196,7 @@ def start(self): if not self.config.silent: self.progress_mapper.report(idx, 'load') - # 4. update the MyopicEfficiency table so it is ready for the upcoming data pull. + # 4. update the Myopicefficiency table so it is ready for the upcoming data pull. self.update_myopic_efficiency_table(myopic_index=idx, prev_base=last_base_year) # 5. pull the data @@ -272,7 +272,7 @@ def start(self): self.output_con.execute( f"""INSERT INTO OutputObjective(scenario, objective_name, total_system_cost) - VALUES('{self.config.scenario}', 'TotalCost', {total_cost})""" + VALUES('{self.config.scenario}', 'total_cost', {total_cost})""" ) self.output_con.commit() @@ -284,11 +284,11 @@ def start(self): def initialize_myopic_efficiency_table(self): """ - create a new MyopicEfficiency table and pre-load it with all ExistingCapacity + create a new Myopicefficiency table and pre-load it with all existing_capacity :return: """ # clear out everything from previous runs - self.cursor.execute('DELETE FROM MyopicEfficiency WHERE 1') + self.cursor.execute('DELETE FROM Myopicefficiency WHERE 1') self.output_con.commit() # the -1 for base year is used to indicate "existing" for flag purposes @@ -297,19 +297,19 @@ def initialize_myopic_efficiency_table(self): # the "coalesce" is an if-else structure to pluck out the correct lifetime value, precedence left->right default_lifetime = TemoaModel.default_lifetime_tech query = ( - 'INSERT INTO MyopicEfficiency ' - ' SELECT -1, main.Efficiency.region, input_comm, Efficiency.tech, Efficiency.vintage, output_comm, efficiency, ' - f' coalesce(main.LifetimeProcess.lifetime, main.LifetimeTech.lifetime, {default_lifetime}) AS lifetime ' - ' FROM main.Efficiency ' - ' LEFT JOIN main.LifetimeProcess ' - ' ON main.Efficiency.tech = LifetimeProcess.tech ' - ' AND main.Efficiency.vintage = LifetimeProcess.vintage ' - ' AND main.Efficiency.region = LifetimeProcess.region ' - ' LEFT JOIN main.LifetimeTech ' - ' ON main.Efficiency.tech = main.LifetimeTech.tech ' - ' AND main.Efficiency.region = main.LifeTimeTech.region ' + 'INSERT INTO Myopicefficiency ' + ' SELECT -1, main.efficiency.region, input_comm, efficiency.tech, efficiency.vintage, output_comm, efficiency, ' + f' coalesce(main.lifetime_process.lifetime, main.lifetime_tech.lifetime, {default_lifetime}) AS lifetime ' + ' FROM main.efficiency ' + ' LEFT JOIN main.lifetime_process ' + ' ON main.efficiency.tech = lifetime_process.tech ' + ' AND main.efficiency.vintage = lifetime_process.vintage ' + ' AND main.efficiency.region = lifetime_process.region ' + ' LEFT JOIN main.lifetime_tech ' + ' ON main.efficiency.tech = main.lifetime_tech.tech ' + ' AND main.efficiency.region = main.lifetime_tech.region ' ' JOIN TimePeriod ' - ' ON Efficiency.vintage = TimePeriod.period ' + ' ON efficiency.vintage = TimePeriod.period ' " WHERE flag = 'e'" ) @@ -321,9 +321,9 @@ def initialize_myopic_efficiency_table(self): if self.debugging: q2 = ( "SELECT '-1', region, input_comm, tech, vintage, output_comm, efficiency " - 'FROM Efficiency ' + 'FROM efficiency ' ' JOIN TimePeriod ' - ' ON Efficiency.vintage = TimePeriod.period ' + ' ON efficiency.vintage = TimePeriod.period ' " WHERE flag = 'e'" ) res = self.cursor.execute(q2).fetchall() @@ -331,7 +331,7 @@ def initialize_myopic_efficiency_table(self): def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: int): """ - This function adds to the MyopicEfficiency table in the db with data specific + This function adds to the Myopicefficiency table in the db with data specific to the current MyopicIndex timeframe. Basically: prep it for the current iteration. :return: """ @@ -340,7 +340,7 @@ def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: i # efficiency table, we can bounce our other queries off of it to get accurate # data out of the DB, instead of dealing with it model-side - # We already captured the ExistingCapacity efficiency values when the table + # We already captured the existing_capacity efficiency values when the table # was initialized, so now we need to incrementally: # 0. Clear from base year forward: # REMOVE anything past the current base year that may have been added previously @@ -355,13 +355,13 @@ def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: i base = myopic_index.base_year last_demand_year = myopic_index.last_demand_year - logger.info('Starting update of MyopicEfficiency Table retaining [%s, %s)', prev_base, base) + logger.info('Starting update of Myopicefficiency Table retaining [%s, %s)', prev_base, base) # 0. Clear any future things past the base year for housekeeping # ease with steps, depth, etc. These may have been added if we are stepping less # than the previous solve depth or if backtracking. self.cursor.execute( - 'DELETE FROM MyopicEfficiency WHERE MyopicEfficiency.vintage >= ?', (base,) + 'DELETE FROM Myopicefficiency WHERE Myopicefficiency.vintage >= ?', (base,) ) self.output_con.commit() @@ -374,7 +374,7 @@ def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: i if flag == 'f': # the prior period should have an OutputNetCapacity entry # Delete anything that doesn't have capacity remaining at the end of last interval delete_qry = ( - 'DELETE FROM MyopicEfficiency ' + 'DELETE FROM Myopicefficiency ' 'WHERE (SELECT region, tech, vintage) ' ' NOT IN (SELECT region, tech, vintage FROM OutputNetCapacity ' ' WHERE period = ? AND scenario = ?) ' @@ -383,7 +383,7 @@ def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: i if self.debugging: debug_query = ( - 'SELECT * FROM MyopicEfficiency ' + 'SELECT * FROM Myopicefficiency ' 'WHERE (SELECT region, tech, vintage) ' ' NOT IN (SELECT region, tech, vintage FROM OutputNetCapacity ' ' WHERE period = ? AND scenario = ?) ' @@ -403,31 +403,31 @@ def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: i # process lifetime > tech lifetime > lifetime default lifetime = TemoaModel.default_lifetime_tech query = ( - 'INSERT INTO MyopicEfficiency ' - f'SELECT {base}, Efficiency.region, input_comm, ' - ' Efficiency.tech, Efficiency.vintage, output_comm, efficiency, ' - f' coalesce(main.LifetimeProcess.lifetime, main.LifetimeTech.lifetime, {lifetime}) ' + 'INSERT INTO Myopicefficiency ' + f'SELECT {base}, efficiency.region, input_comm, ' + ' efficiency.tech, efficiency.vintage, output_comm, efficiency, ' + f' coalesce(main.lifetime_process.lifetime, main.lifetime_tech.lifetime, {lifetime}) ' f' AS lifetime ' - ' FROM main.Efficiency ' - ' LEFT JOIN main.LifetimeProcess ' - ' ON main.Efficiency.tech = LifetimeProcess.tech ' - ' AND main.Efficiency.vintage = LifetimeProcess.vintage ' - ' AND main.Efficiency.region = LifetimeProcess.region ' - ' LEFT JOIN main.LifetimeTech ' - ' ON main.Efficiency.tech = main.LifetimeTech.tech ' - ' AND main.Efficiency.region = main.LifeTimeTech.region ' - f' WHERE Efficiency.vintage >= {base}' - f' AND Efficiency.vintage <= {last_demand_year}' + ' FROM main.efficiency ' + ' LEFT JOIN main.lifetime_process ' + ' ON main.efficiency.tech = lifetime_process.tech ' + ' AND main.efficiency.vintage = lifetime_process.vintage ' + ' AND main.efficiency.region = lifetime_process.region ' + ' LEFT JOIN main.lifetime_tech ' + ' ON main.efficiency.tech = main.lifetime_tech.tech ' + ' AND main.efficiency.region = main.lifetime_tech.region ' + f' WHERE efficiency.vintage >= {base}' + f' AND efficiency.vintage <= {last_demand_year}' ) if self.debugging: # note: the debug query below omits the lifetime computation for brevity, but is very useful without... raw = self.cursor.execute( f'SELECT {base}, region, input_comm, tech, vintage, output_comm, efficiency ' - 'FROM Efficiency ' - f' WHERE Efficiency.vintage >= {base}' - f' AND Efficiency.vintage <= {last_demand_year}' + 'FROM efficiency ' + f' WHERE efficiency.vintage >= {base}' + f' AND efficiency.vintage <= {last_demand_year}' ).fetchall() - print('\n\n **** adding to MyopicEfficiency table from newly visible techs ****') + print('\n\n **** adding to Myopicefficiency table from newly visible techs ****') for idx, t in enumerate(raw): print(idx, t) print() diff --git a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py index 694b99546..2511a1735 100644 --- a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py +++ b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py @@ -130,7 +130,7 @@ def start(self): handle_results(instance, results=res, config=self.config, append=False, iteration=0) # 3a. Capture cost and make it a constraint - tot_cost = value(instance.TotalCost) + tot_cost = value(instance.total_cost) logger.info('Completed initial solve with total cost: %0.2f', tot_cost) logger.info('Relaxing cost by fraction: %0.3f', self.cost_epsilon) # get hook on the expression generator for total cost... @@ -138,8 +138,8 @@ def start(self): instance.cost_cap = Constraint(expr=cost_expression <= (1 + self.cost_epsilon) * tot_cost) # 3b. remove the old objective - # instance.TotalCost.deactivate() - instance.del_component(instance.TotalCost) + # instance.total_cost.deactivate() + instance.del_component(instance.total_cost) # 4. Reconstruct the OBJ function... emission_labels = self.config.svmga_inputs.get('emission_labels', []) @@ -202,7 +202,7 @@ def flow_idxs_from_eac_idx(model: TemoaModel, reitvo: tuple) -> tuple[list[tuple psd_set = [ (p, s, d) for p in model.time_optimize - for s in model.TimeSeason[p] + for s in model.time_season[p] for d in model.time_of_day ] flow_idxs = [(r, *psd, i, t, v, o) for psd in psd_set] @@ -253,38 +253,38 @@ def construct_obj( # handle emissions... for label in emission_labels: - idxs = [idx for idx in model.EmissionActivity if idx[1] == label] + idxs = [idx for idx in model.emission_activity if idx[1] == label] logger.debug('Located %d items for emission label: %s', len(idxs), label) for idx in idxs: - # for each indexed item in EmissionActivity, we need to search both the regular + # for each indexed item in emission_activity, we need to search both the regular # flows and the annual flows. And, we need to sum across the "expanded" index # for both which includes period, season, tod or just period respectively expanded_idxs, expanded_annual_idxs = SvMgaSequencer.flow_idxs_from_eac_idx( model, idx ) element = sum( - model.V_FlowOut[flow_idx] * model.EmissionActivity[idx] + model.v_flow_out[flow_idx] * model.emission_activity[idx] for flow_idx in expanded_idxs - if flow_idx in model.V_FlowOut + if flow_idx in model.v_flow_out ) expr += element annual_element = sum( - model.V_FlowOutAnnual[annual_flow_idx] * model.EmissionActivity[idx] + model.v_flow_out_annual[annual_flow_idx] * model.emission_activity[idx] for annual_flow_idx in expanded_annual_idxs - if annual_flow_idx in model.V_FlowOutAnnual + if annual_flow_idx in model.v_flow_out_annual ) expr += annual_element # handle activity... for label in activity_labels: - idxs = [idx for idx in model.V_FlowOut if idx[5] == label] + idxs = [idx for idx in model.v_flow_out if idx[5] == label] logger.debug('Located %d items for activity label: %s', len(idxs), label) - expr += sum(model.V_FlowOut[idx] for idx in idxs) + expr += sum(model.v_flow_out[idx] for idx in idxs) # handle capacity... for label in capacity_labels: - idxs = [idx for idx in model.V_Capacity if idx[2] == label] + idxs = [idx for idx in model.v_capacity if idx[2] == label] logger.debug('Located %d items for capacity label: %s', len(idxs), label) - expr += sum(model.V_Capacity[idx] for idx in idxs) + expr += sum(model.v_capacity[idx] for idx in idxs) return expr diff --git a/temoa/extensions/stochastics/VSS.py b/temoa/extensions/stochastics/VSS.py index f8e885779..a5d0f6fa4 100755 --- a/temoa/extensions/stochastics/VSS.py +++ b/temoa/extensions/stochastics/VSS.py @@ -7,8 +7,8 @@ def organize_csv(): # This function was imported from the EVPI script - from csv import reader, writer from collections import OrderedDict + from csv import reader, writer rows = list() tech = list() @@ -47,8 +47,8 @@ def organize_csv(): def my_ef_writer(scenario_tree): # This function was imported from the EVPI script - from csv import writer from collections import OrderedDict + from csv import writer rows = dict() # Key is the variable's name for stage in scenario_tree._stages: @@ -146,7 +146,7 @@ def solve_ef_fix(ef_options, avg_instance): time_fut = avg_instance.time_future.data() techs = avg_instance.tech_all.data() - dV_Capacity = avg_instance.V_Capacity.get_values() # Getting dec vars that matters to be fixed + dv_capacity = avg_instance.v_capacity.get_values() # Getting dec vars that matters to be fixed # dV_HydroStorage = avg_instance.V_HydroStorage.get_values() # Storing techs and future time periods in vector for easy access @@ -157,10 +157,10 @@ def solve_ef_fix(ef_options, avg_instance): k = k + 1 # Fixing Capacity values for first stage at the ef instance with values from the deterministic instance - for iaux1, iaux2 in dV_Capacity: + for iaux1, iaux2 in dv_capacity: if iaux2 == vtime_fut[0]: - ef._binding_instance.S0s0s0.V_Capacity[iaux1, iaux2].fix(dV_Capacity[iaux1, iaux2]) - # ef._binding_instance.S0.V_Capacity[iaux1, iaux2].fix(3) #just for checking if fixing at one scen also fix in the other - ok for now + ef._binding_instance.S0s0s0.v_capacity[iaux1, iaux2].fix(dv_capacity[iaux1, iaux2]) + # ef._binding_instance.S0.v_capacity[iaux1, iaux2].fix(3) #just for checking if fixing at one scen also fix in the other - ok for now # Fixing Hydro Storage values for first stage # for iaux1 , iaux2 in dV_HydroStorage: @@ -197,8 +197,8 @@ def return_obj(instance): # Assuming there is only one objective function return obj_values[0] - import sys import os + import sys (head, tail) = os.path.split(p_model) sys.path.insert(0, head) @@ -228,7 +228,7 @@ def return_obj(instance): # Writting to the Shell sys.stdout.write('\nSolved deterministic model with uncertainty at average valures \n') - sys.stdout.write(' Total cost: {}\n'.format(obj_val)) + sys.stdout.write(f' Total cost: {obj_val}\n') os.chdir(pwd) return instance # Returning instance solved, values will be used later @@ -253,8 +253,8 @@ def runVSS(): # As input, this function requires the path of the stochastic folder and temoa_stochastic.py file # It assumes that an instance named ReferenceModel.dat is located inside the stochastic folder - from time import time import sys + from time import time sys.stderr.write('\nFinding the Value of the Stochastic Solution using Temoa\n') @@ -270,7 +270,7 @@ def runVSS(): p_model, p_data, optsolver ) # Here we have all the information with respect to objfunc and decvars - zdm_result = dm_instance.TotalCost.value + zdm_result = dm_instance.total_cost.value # --------------------- # Solving the extensive model for the recoursive problem # --------------------- @@ -283,8 +283,8 @@ def runVSS(): sys.stderr.write('\nSolving extensive form\n') ef_result = solve_ef(ef_options) - msg = '\nrunef time: {} s\n'.format(time() - start_time) - msg += 'runef objective value: {}\n'.format(ef_result) + msg = f'\nrunef time: {time() - start_time} s\n' + msg += f'runef objective value: {ef_result}\n' sys.stderr.write(msg) # --------------------- diff --git a/temoa/extensions/stochastics/generate_scenario_tree-nonhomogenous.py b/temoa/extensions/stochastics/generate_scenario_tree-nonhomogenous.py index b422cfdb2..13814df4a 100755 --- a/temoa/extensions/stochastics/generate_scenario_tree-nonhomogenous.py +++ b/temoa/extensions/stochastics/generate_scenario_tree-nonhomogenous.py @@ -1,7 +1,7 @@ #!/usr/bin/env pyomo_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 . """ @@ -25,9 +25,10 @@ import sys from io import StringIO from pprint import pformat -from shutil import copy as copyfile, rmtree +from shutil import copy as copyfile +from shutil import rmtree -from pyomo.core.base.sets import _SetProduct, _SetContainer +from pyomo.core.base.sets import _SetContainer, _SetProduct SE = sys.stderr instance = None @@ -45,7 +46,7 @@ def __str__(self): __repr__ = __str__ -class Param(object): +class Param: # will be common to all Parameters, so no sense in storing it N times stochasticset = None @@ -136,8 +137,8 @@ class _tmp: return _tmp() def __str__(self): - x = '; '.join('(%s, %s)' % (self[i].value, self[i].rate) for i in self) - return 'Param(%s): %s' % (self.name, x) + x = '; '.join(f'({self[i].value}, {self[i].rate})' for i in self) + return f'Param({self.name}): {x}' __repr__ = __str__ @@ -194,7 +195,7 @@ def anonymous_function(obj): return data.getvalue() -class TreeNode(object): +class TreeNode: __slots__ = ('name', 'parent', 'spoint', 'prob', 'params', 'bname', 'children') def __init__(self, *args, **kwargs): @@ -220,7 +221,7 @@ def __init__(self, *args, **kwargs): 'spoint': self.spoint, 'stochastic_index': sindices[key], } - decision = '{}{}'.format(self.parent, self.name) + decision = f'{self.parent}{self.name}' paramkwargs.update({'rates': decisions[decision]}) myparams[key] = Param(**paramkwargs) @@ -236,7 +237,7 @@ def __repr__(self): x = self.name if isinstance(self.name, tuple): x = ', '.join(x) - return '%s(%s): ' % (self.spoint, x) + ', '.join(str(i) for i in self.params.values()) + return f'{self.spoint}({x}): ' + ', '.join(str(i) for i in self.params.values()) def __str__(self, indent=' ', space=''): x = ''.join(i.__str__(indent, space + indent) for i in self.children) @@ -308,12 +309,12 @@ def write_scenario_file(stochasticset, tree): leaves = '\n '.join(scenario_fmt % {'i': i} for i in scenarios) nodes = '\n '.join(nodes) - nodestage = '\n '.join((' '.join(ns) for ns in nodestage)) + nodestage = '\n '.join(' '.join(ns) for ns in nodestage) scenarios = 'S%s' % '\n S'.join(scenarios) stagecost = '\n '.join(stagecost_fmt % (s, s) for s in stochasticset) stages = '\n s'.join(str(se) for se in stochasticset) - probability = '\n '.join((' '.join(str(i) for i in p) for p in probability)) + probability = '\n '.join(' '.join(str(i) for i in p) for p in probability) children = '\n'.join(child_fmt % (c[0], '\n '.join(c[1])) for c in children) # XXX: Temporary and absolute hack, that currently only works for Temoa @@ -323,17 +324,17 @@ def write_scenario_file(stochasticset, tree): stage_var_sets = list() for se in stochasticset: # se = "stochastic element" - flow_keys = [index for index in instance.V_FlowOut.keys() if index[0] == se] + flow_keys = [index for index in instance.v_flow_out.keys() if index[0] == se] processes = [(t, v) for p, s, d, i, t, v, o in flow_keys if v == se] stage_vars = list() stage_vars.extend( - sorted('V_FlowIn[{},{},{},{},{},{},{}]'.format(*index) for index in flow_keys) + sorted('v_flow_in[{},{},{},{},{},{},{}]'.format(*index) for index in flow_keys) ) stage_vars.extend( - sorted('V_FlowOut[{},{},{},{},{},{},{}]'.format(*index) for index in flow_keys) + sorted('v_flow_out[{},{},{},{},{},{},{}]'.format(*index) for index in flow_keys) ) - stage_vars.extend(sorted('V_Capacity[{},{}]'.format(*index) for index in processes)) + stage_vars.extend(sorted('v_capacity[{},{}]'.format(*index) for index in processes)) stage_var_sets.append(stages_fmt.format(se, '\n '.join(stage_vars))) stage_var_sets = '\n\n'.join(stage_var_sets) @@ -367,7 +368,7 @@ def write_scenario_file(stochasticset, tree): %(leaves)s ; -param StageCostVariable := +param Stagecost_variable := %(stagecost)s ; @@ -541,7 +542,7 @@ def main(): opts = sys.modules[module_name] except ImportError: - msg = 'Unable to import {}.\n\nRun this script with no arguments for ' 'more information.\n' + msg = 'Unable to import {}.\n\nRun this script with no arguments for more information.\n' SE.write(msg.format(sys.argv[1])) raise diff --git a/temoa/extensions/stochastics/generate_scenario_tree.py b/temoa/extensions/stochastics/generate_scenario_tree.py index 960280652..4c060d6c9 100755 --- a/temoa/extensions/stochastics/generate_scenario_tree.py +++ b/temoa/extensions/stochastics/generate_scenario_tree.py @@ -1,7 +1,7 @@ #!/usr/bin/env pyomo_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 . """ @@ -25,9 +25,10 @@ import sys from io import StringIO from pprint import pformat -from shutil import copy as copyfile, rmtree +from shutil import copy as copyfile +from shutil import rmtree -from pyomo.core.base.sets import _SetProduct, SimpleSet +from pyomo.core.base.sets import SimpleSet, _SetProduct SE = sys.stderr instance = None @@ -45,7 +46,7 @@ def __str__(self): __repr__ = __str__ -class Param(object): +class Param: # will be common to all Parameters, so no sense in storing it N times stochasticset = None @@ -138,8 +139,8 @@ class _tmp: return _tmp() def __str__(self): - x = '; '.join('(%s, %s)' % (self[i].value, self[i].rate) for i in self) - return 'Param(%s): %s' % (self.name, x) + x = '; '.join(f'({self[i].value}, {self[i].rate})' for i in self) + return f'Param({self.name}): {x}' __repr__ = __str__ @@ -196,7 +197,7 @@ def anonymous_function(obj): return data.getvalue() -class TreeNode(object): +class TreeNode: __slots__ = ('name', 'spoint', 'prob', 'params', 'bname', 'children') def __init__(self, *args, **kwargs): @@ -236,7 +237,7 @@ def __repr__(self): x = self.name if isinstance(self.name, tuple): x = ', '.join(x) - return '%s(%s): ' % (self.spoint, x) + ', '.join(str(i) for i in self.params.values()) + return f'{self.spoint}({x}): ' + ', '.join(str(i) for i in self.params.values()) def __str__(self, indent=' ', space=''): x = ''.join(i.__str__(indent, space + indent) for i in self.children) @@ -308,12 +309,12 @@ def write_scenario_file(stochasticset, tree): leaves = '\n '.join(scenario_fmt % {'i': i} for i in scenarios) nodes = '\n '.join(nodes) - nodestage = '\n '.join((' '.join(ns) for ns in nodestage)) + nodestage = '\n '.join(' '.join(ns) for ns in nodestage) scenarios = 'S%s' % '\n S'.join(scenarios) stagecost = '\n '.join(stagecost_fmt % (s, s) for s in stochasticset) stages = '\n s'.join(str(se) for se in stochasticset) - probability = '\n '.join((' '.join(str(i) for i in p) for p in probability)) + probability = '\n '.join(' '.join(str(i) for i in p) for p in probability) children = '\n'.join(child_fmt % (c[0], '\n '.join(c[1])) for c in children) # XXX: Absolute hack, that currently only works for Temoa models. I have @@ -321,17 +322,17 @@ def write_scenario_file(stochasticset, tree): stage_var_sets = list() for se in stochasticset: # se = "stochastic element" - flow_keys = [index for index in instance.V_FlowOut.keys() if index[0] == se] + flow_keys = [index for index in instance.v_flow_out.keys() if index[0] == se] processes = [(t, v) for p, s, d, i, t, v, o in flow_keys if v == se] stage_vars = list() stage_vars.extend( - sorted(set('V_FlowIn[{},{},{},{},{},{},{}]'.format(*index) for index in flow_keys)) + sorted({'v_flow_in[{},{},{},{},{},{},{}]'.format(*index) for index in flow_keys}) ) stage_vars.extend( - sorted(set('V_FlowOut[{},{},{},{},{},{},{}]'.format(*index) for index in flow_keys)) + sorted({'v_flow_out[{},{},{},{},{},{},{}]'.format(*index) for index in flow_keys}) ) - stage_vars.extend(sorted(set('V_Capacity[{},{}]'.format(*index) for index in processes))) + stage_vars.extend(sorted({'v_capacity[{},{}]'.format(*index) for index in processes})) stage_var_sets.append(stages_fmt.format(se, '\n '.join(stage_vars))) @@ -366,7 +367,7 @@ def write_scenario_file(stochasticset, tree): %(leaves)s ; -param StageCostVariable := +param Stagecost_variable := %(stagecost)s ; @@ -551,7 +552,7 @@ def main(): sys.path.pop(0) except ImportError: - msg = 'Unable to import {}.\n\nRun this script with no arguments for ' 'more information.\n' + msg = 'Unable to import {}.\n\nRun this script with no arguments for more information.\n' SE.write(msg.format(sys.argv[1])) raise diff --git a/temoa/extensions/stochastics/legacy_files/scenariomodels.py b/temoa/extensions/stochastics/legacy_files/scenariomodels.py index 6b3893b09..45deae4ea 100644 --- a/temoa/extensions/stochastics/legacy_files/scenariomodels.py +++ b/temoa/extensions/stochastics/legacy_files/scenariomodels.py @@ -20,7 +20,7 @@ ) scenario_tree_model.StageVariables = Set(scenario_tree_model.Stages) -scenario_tree_model.StageCostVariable = Param(scenario_tree_model.Stages) +scenario_tree_model.Stagecost_variable = Param(scenario_tree_model.Stages) # scenario data can be populated in one of two ways. the first is "scenario-based", # in which a single .dat file contains all of the data for each scenario. the .dat @@ -52,7 +52,7 @@ # scenario_tree_model.ScenarioLeafNode = Param(scenario_tree_model.Scenarios, within=scenario_tree_model.Nodes) # scenario_tree_model.StageVariables = Set(scenario_tree_model.Stages) -# scenario_tree_model.StageCostVariable = Param(scenario_tree_model.Stages) +# scenario_tree_model.Stagecost_variable = Param(scenario_tree_model.Stages) ## scenario data can be populated in one of two ways. the first is "scenario-based", ## in which a single .dat file contains all of the data for each scenario. the .dat diff --git a/temoa/extensions/stochastics/options/iew2012.py b/temoa/extensions/stochastics/options/iew2012.py index f56cef7c6..2be9a8fe7 100644 --- a/temoa/extensions/stochastics/options/iew2012.py +++ b/temoa/extensions/stochastics/options/iew2012.py @@ -6,7 +6,7 @@ dotdatpath = '../data_files/iew2012.dat' stochasticset = 'time_optimize' stochastic_points = (2020, 2025, 2030, 2035) -stochastic_indices = {'Demand': 0, 'CostVariable': 0} +stochastic_indices = {'Demand': 0, 'cost_variable': 0} types = ( 'DemD_NatD_OilD', 'DemD_NatD_OilU', @@ -79,7 +79,7 @@ ('*,*,r_wheating', 1.12236), ), ), - 'CostVariable': dict( + 'cost_variable': dict( DemD_NatD_OilD=(('imp_natgas,*', 0.73351), ('imp_oil,*', 0.15309)), DemD_NatD_OilU=(('imp_natgas,*', 0.95164), ('imp_oil,*', 2.67004)), DemD_NatU_OilD=(('imp_natgas,*', 1.68052), ('imp_oil,*', 0.55464)), diff --git a/temoa/extensions/stochastics/options/utopia_coal_vs_nuc.py b/temoa/extensions/stochastics/options/utopia_coal_vs_nuc.py index 197df5373..4617a884b 100644 --- a/temoa/extensions/stochastics/options/utopia_coal_vs_nuc.py +++ b/temoa/extensions/stochastics/options/utopia_coal_vs_nuc.py @@ -5,7 +5,7 @@ modelpath = '../temoa_model/temoa_model.py' dotdatpath = '../data_files/utopia-15.dat' stochasticset = 'time_optimize' -stochastic_indices = {'Demand': 0, 'CostInvest': 1} +stochastic_indices = {'Demand': 0, 'cost_invest': 1} # CL, CA, CH = coal "[lower, average, high]" rate # _Low, _Average, _High = demand "[low, average, high]" rate @@ -45,7 +45,7 @@ CA_High=(('*,*,RH', 1.480), ('*,*,RL', 1.480), ('*,*,TX', 1.480)), CH_High=(('*,*,RH', 1.480), ('*,*,RL', 1.480), ('*,*,TX', 1.480)), ), - 'CostInvest': dict( + 'cost_invest': dict( CL_Low=( ('E01,*', 1.8), ('E21,*', 1.2), diff --git a/temoa/extensions/stochastics/stochastics_README.txt b/temoa/extensions/stochastics/stochastics_README.txt index 6ce971cf3..1792164f6 100644 --- a/temoa/extensions/stochastics/stochastics_README.txt +++ b/temoa/extensions/stochastics/stochastics_README.txt @@ -5,31 +5,31 @@ Stochastic Optimization README (Solve a stochastic run and store results into a database using config file) $ python temoa_model/temoa_stochastic.py --config=temoa_model/config_sample # Note that to invoke the stochastic run, the "--input" flag must be the path -# to ScenarioStructure.dat, and "--output" flag is the path to the target +# to ScenarioStructure.dat, and "--output" flag is the path to the target # database file, where the results will be stored. (Extensive Formulation or Deterministic Equivalent) -runef -m ../../temoa_model/ -i ./ --solver=glpk --solve >> out.txt +runef -m ../../temoa_model/ -i ./ --solver=glpk --solve >> out.txt (Progressive Hedging) -runph -m ../../temoa_model/ -i ./ --solver=ipopt --default-rho=1.0 +runph -m ../../temoa_model/ -i ./ --solver=ipopt --default-rho=1.0 (Solve a particular path in the tree as a linear program) -python ../../temoa_model/ R.dat Rs0.dat Rs0s2.dat +python ../../temoa_model/ R.dat Rs0.dat Rs0s2.dat ----------------------------- Stochastic Optimization Tools ----------------------------- - + (EVPI computation) -python test_EVPI.py +python test_EVPI.py (VSS computation) -python VSS.py +python VSS.py #(Information about how to setup a run of VSS): #Lines 246 - 249 specify the path to the folders and the solver to be used. #It is necessary to change these lines in order to properly point to the - #instance that you want to solve. The first one just points to the path of the + #instance that you want to solve. The first one just points to the path of the #temoa_stochastic.py file. The second one point to the folder of the instance #where the scenario tree structure and all the scenarios are represented. #p_model = '/home/arqueiroz/SSudan/S1_2_H/temoa_model/temoa_stochastic.py' @@ -45,14 +45,14 @@ python VSS.py #(Get info about decisions on the first stage): #On line 147 - #ef._binding_instance.S0s0s0.V_Capacity[iaux1, iaux2].fix(dV_Capacity[iaux1,iaux2]) - #it is necessary to fix the first stage decisions from the deterministic model (with - #average values) when solving the stochastic program (with fixed values) that will + #ef._binding_instance.S0s0s0.v_capacity[iaux1, iaux2].fix(dv_capacity[iaux1,iaux2]) + #it is necessary to fix the first stage decisions from the deterministic model (with + #average values) when solving the stochastic program (with fixed values) that will #be compared to the true stochastic program (without any fixed values) #Note that the left portion of the equation is the one that is fixed. As for now - #it depends on the number of stages of the problem, for the one used here there is - #a total of four stages and we need to fix .S0s0s0.V_Capacity.fix if it was 3 stages we - #would make S0s0.V_Capacity.fix + #it depends on the number of stages of the problem, for the one used here there is + #a total of four stages and we need to fix .S0s0s0.v_capacity.fix if it was 3 stages we + #would make S0s0.v_capacity.fix #Additional file for EVPI and VSS usage: #pyomo version 4.3.11388 requires the addition @@ -61,7 +61,7 @@ python VSS.py #file is: /anaconda/lib/python2.7/site-packages/pyomo/pysp (Generate Scenario Tree) -python generate_scenario_tree.py options/uc_tl_unlim.py +python generate_scenario_tree.py options/uc_tl_unlim.py #Additional files needed for generate scenario tree script: #pyomo version 4.3.11388 requires the addition #of the file scenariomodels.py within the installation @@ -70,4 +70,4 @@ python generate_scenario_tree.py options/uc_tl_unlim.py (Script for Parallel runs of runph) (to be used on Neer super computer) -qsub jobTemoa.pbs \ No newline at end of file +qsub jobTemoa.pbs diff --git a/temoa/extensions/stochastics/temoa_stochastic.py b/temoa/extensions/stochastics/temoa_stochastic.py index 6a19cde82..7abf41316 100644 --- a/temoa/extensions/stochastics/temoa_stochastic.py +++ b/temoa/extensions/stochastics/temoa_stochastic.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,10 +16,11 @@ 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 . """ + import os import sys @@ -40,7 +41,7 @@ def return_CP_and_path(p_data): # returns conditional two dictionaries, the first one is the conditional # probability of a scenario, the second one is the path to all files of a # scenario. - from collections import deque, defaultdict + from collections import defaultdict, deque # from pyomo.pysp.util.scenariomodels import scenario_tree_model from pyomo.pysp.scenariotree.tree_structure_model import CreateAbstractScenarioTreeModel @@ -173,7 +174,7 @@ def solve_ef(p_model, p_data, temoa_options=None): # options.scenario_tree_location, # stochastic_output # ) - msg = '\nStoring results from scenario {} to database.\n'.format(s.name) + msg = f'\nStoring results from scenario {s.name} to database.\n' sys.stderr.write(msg) formatted_results = pformat_results(ins, ef_result, temoa_options) @@ -196,8 +197,8 @@ def Objective_rule(M): M.StochasticPointCost = Var(M.time_optimize, within=NonNegativeReals) M.StochasticPointCostConstraint = Constraint(M.time_optimize, rule=StochasticPointObjective_rule) -del M.TotalCost -M.TotalCost = Objective(rule=Objective_rule, sense=minimize) +del M.total_cost +M.total_cost = Objective(rule=Objective_rule, sense=minimize) if __name__ == '__main__': p_model = './ReferenceModel.py' diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index 3721d09a6..e31218229 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -163,20 +163,20 @@ def _build_from_model( raise NotImplementedError('Cannot build network data from model using a MyopicIndex') dem_com = defaultdict(set) - for r, p, d in model.Demand.sparse_iterkeys(): + for r, p, d in model.demand.sparse_iterkeys(): dem_com[r, p].add(d) techs: defaultdict[tuple[Region, Period], set[EdgeTuple]] = defaultdict(set) - if model.activeFlow_rpsditvo is not None: - for r, p, _s, _d, ic, tech, v, oc in model.activeFlow_rpsditvo: + if model.active_flow_rpsditvo is not None: + for r, p, _s, _d, ic, tech, v, oc in model.active_flow_rpsditvo: techs[r, p].add(EdgeTuple(r, ic, tech, v, oc)) - if model.activeFlow_rpitvo is not None: - for r, p, ic, tech, v, oc in model.activeFlow_rpitvo: + if model.active_flow_rpitvo is not None: + for r, p, ic, tech, v, oc in model.active_flow_rpitvo: techs[r, p].add(EdgeTuple(r, ic, tech, v, oc)) linked_techs = { LinkedTechTuple(r, driver, emission, driven) - for r, driver, emission, driven in model.LinkedTechs.sparse_iterkeys() + for r, driver, emission, driven in model.linked_techs.sparse_iterkeys() } res = NetworkModelData( @@ -244,7 +244,7 @@ def _fetch_all_tech_definitions( ]: """Fetches the main block of technology efficiency and lifetime data.""" default_lifetime = TemoaModel.default_lifetime_tech - table = 'MyopicEfficiency' if myopic_index else 'Efficiency' + table = 'Myopicefficiency' if myopic_index else 'efficiency' # Check if Technology table has sector column try: @@ -263,8 +263,8 @@ def _fetch_all_tech_definitions( COALESCE(lp.lifetime, lt.lifetime, ?) AS lifetime, COALESCE(tech_dim.sector, 'Other') AS sector FROM main.{table} AS eff - LEFT JOIN main.LifetimeProcess AS lp ON eff.tech = lp.tech AND eff.vintage = lp.vintage AND eff.region = lp.region - LEFT JOIN main.LifetimeTech AS lt ON eff.tech = lt.tech AND eff.region = lt.region + LEFT JOIN main.lifetime_process AS lp ON eff.tech = lp.tech AND eff.vintage = lp.vintage AND eff.region = lp.region + LEFT JOIN main.lifetime_tech AS lt ON eff.tech = lt.tech AND eff.region = lt.region LEFT JOIN main.Technology AS tech_dim ON eff.tech = tech_dim.tech JOIN main.TimePeriod AS tp ON eff.vintage = tp.period """ @@ -274,8 +274,8 @@ def _fetch_all_tech_definitions( eff.region, eff.input_comm, eff.tech, eff.vintage, eff.output_comm, COALESCE(lp.lifetime, lt.lifetime, ?) AS lifetime FROM main.{table} AS eff - LEFT JOIN main.LifetimeProcess AS lp ON eff.tech = lp.tech AND eff.vintage = lp.vintage AND eff.region = lp.region - LEFT JOIN main.LifetimeTech AS lt ON eff.tech = lt.tech AND eff.region = lt.region + LEFT JOIN main.lifetime_process AS lp ON eff.tech = lp.tech AND eff.vintage = lp.vintage AND eff.region = lp.region + LEFT JOIN main.lifetime_tech AS lt ON eff.tech = lt.tech AND eff.region = lt.region JOIN main.TimePeriod AS tp ON eff.vintage = tp.period """ cursor = cur.execute(query, (default_lifetime,)) @@ -288,18 +288,18 @@ def _fetch_lookup_data(cur: sqlite3.Cursor) -> LookupData: try: for r, tech, v, oc in cur.execute( - 'SELECT region, tech, vintage, output_comm FROM EndOfLifeOutput' + 'SELECT region, tech, vintage, output_comm FROM end_of_life_output' ).fetchall(): lookups['eol'][(r, tech, v)].append(oc) except sqlite3.OperationalError: - logger.warning('Table EndOfLifeOutput not found, skipping.') + logger.warning('Table end_of_life_output not found, skipping.') try: lookups['construction'] = cur.execute( - 'SELECT region, input_comm, tech, vintage FROM ConstructionInput' + 'SELECT region, input_comm, tech, vintage FROM construction_input' ).fetchall() except sqlite3.OperationalError: - logger.warning('Table ConstructionInput not found, skipping.') + logger.warning('Table construction_input not found, skipping.') try: lookups['linked'] = set( @@ -314,11 +314,11 @@ def _fetch_lookup_data(cur: sqlite3.Cursor) -> LookupData: lookups['neg_cost_techs'] = { tech for (tech,) in cur.execute( - 'SELECT DISTINCT tech FROM CostVariable WHERE cost < 0' + 'SELECT DISTINCT tech FROM cost_variable WHERE cost < 0' ).fetchall() } except sqlite3.OperationalError: - logger.warning('Table CostVariable not found, skipping.') + logger.warning('Table cost_variable not found, skipping.') return lookups diff --git a/temoa/model_checking/pricing_check.py b/temoa/model_checking/pricing_check.py index a91154e0b..b1e548a56 100644 --- a/temoa/model_checking/pricing_check.py +++ b/temoa/model_checking/pricing_check.py @@ -4,7 +4,7 @@ Intent is to identify several possible errors. Note: These will need to be enhanced as this will likely generate many false positives initially. -1. Technologies that have an entry in Efficiency table that have no corresponding +1. Technologies that have an entry in efficiency table that have no corresponding (or inconsistent) fixed-cost / inv cost pairs. The primary motivation is that things without either an FC or IC have no downward pressure on activity in the model, which is regulated by cost @@ -40,11 +40,11 @@ def price_checker(model: TemoaModel) -> bool: warnings = False # flag # some sets for x-checking registered_inv_costs = { - (region, tech, vintage) for (region, tech, vintage) in model.CostInvest.sparse_iterkeys() + (region, tech, vintage) for (region, tech, vintage) in model.cost_invest.sparse_iterkeys() } efficiency_rtv = { (region, tech, vintage) - for (region, _, tech, vintage, __) in model.Efficiency.sparse_iterkeys() + for (region, _, tech, vintage, __) in model.efficiency.sparse_iterkeys() } sorted_efficiency_rtv = sorted(efficiency_rtv, key=lambda rtv: (rtv[1], rtv[0], rtv[2])) @@ -58,11 +58,11 @@ def price_checker(model: TemoaModel) -> bool: # var costs for the period = vintage year base_year_variable_cost_rtv = set() - for r, p, t, v in model.CostFixed.sparse_iterkeys(): + for r, p, t, v in model.cost_fixed.sparse_iterkeys(): fixed_costs[r, t, v].add(p) if p == v: base_year_fixed_cost_rtv.add((r, t, v)) - for r, p, t, v in model.CostVariable.sparse_iterkeys(): + for r, p, t, v in model.cost_variable.sparse_iterkeys(): var_costs[r, t, v].add(p) if p == v: base_year_variable_cost_rtv.add((r, t, v)) @@ -81,7 +81,7 @@ def price_checker(model: TemoaModel) -> bool: # Check 1 looks for missing (1a) and inconsistent (1b) fixed cost - investment cost pairings logger.debug(' Starting price check #1a') # Check 1a: Look for "missing" FC/IC (no fixed or investment cost) based on what is in the - # Efficiency set + # efficiency set techs_without_fc_or_ic = set() # pull the details... for region, tech, vintage in sorted_efficiency_rtv: @@ -130,7 +130,7 @@ def price_checker(model: TemoaModel) -> bool: err += f' ({r}, {v})\n' err += ' available (r, v):\n' for r, tt, v in comparable_fc: - err += f' ({r}, {v}): {model.CostFixed[r, v, tt, v]}\n' + err += f' ({r}, {v}): {model.cost_fixed[r, v, tt, v]}\n' if err: logger.warning(err) warnings = True @@ -156,7 +156,7 @@ def price_checker(model: TemoaModel) -> bool: err += f' ({r}, {v})\n' err += ' available (r, v):\n' for r, tt, v in compaprable_ic: - err += f' ({r}, {v}): {model.CostInvest[r, tt, v]}\n' + err += f' ({r}, {v}): {model.cost_invest[r, tt, v]}\n' if err: logger.warning(err) warnings = True @@ -209,7 +209,7 @@ def price_checker(model: TemoaModel) -> bool: # continue # get the lifetime of the tech, or default - lifetime = value(model.LifetimeProcess[region, tech, vintage]) + lifetime = value(model.lifetime_process[region, tech, vintage]) # get all applicable future periods that should be priced for this item expected_periods = {p for p in model.time_optimize if vintage <= p < vintage + lifetime} missing_fixed_costs = ( @@ -258,7 +258,7 @@ def check_tech_uncap(model: TemoaModel) -> bool: Check that the tech_uncap set members... 1. do not have fixed or invest costs 2. Either have no Var cost, or a Var cost in every year of their lifespan (similar to check #3 above) - 3. Are not in the LimitCapacity parameters + 3. Are not in the limit_capacity parameters :param M: :return: True if "clean" (no warnings), else False @@ -268,11 +268,11 @@ def check_tech_uncap(model: TemoaModel) -> bool: logger.debug('starting price check #4: uncapacitated techs') efficiency_rtv = { (region, tech, vintage) - for (region, _, tech, vintage, __) in model.Efficiency.sparse_iterkeys() + for (region, _, tech, vintage, __) in model.efficiency.sparse_iterkeys() if tech in model.tech_uncap } - fixed_cost_periods = {(r, t, v): p for r, p, t, v in model.CostFixed.sparse_iterkeys()} + fixed_cost_periods = {(r, t, v): p for r, p, t, v in model.cost_fixed.sparse_iterkeys()} rtv_with_fixed_cost = efficiency_rtv & set(fixed_cost_periods.keys()) if rtv_with_fixed_cost: logger.error( @@ -281,7 +281,7 @@ def check_tech_uncap(model: TemoaModel) -> bool: for rtv in rtv_with_fixed_cost: logger.error('%s: %s', rtv, fixed_cost_periods[rtv]) - rtv_with_invest_cost = efficiency_rtv & set(model.CostInvest.sparse_iterkeys()) + rtv_with_invest_cost = efficiency_rtv & set(model.cost_invest.sparse_iterkeys()) if rtv_with_invest_cost: logger.error( 'The following technologies are labeled as unlimited capacity, but have an INVEST cost' @@ -291,14 +291,14 @@ def check_tech_uncap(model: TemoaModel) -> bool: var_cost_periods = defaultdict(set) # by starting from the cost side, we will naturally omit anything with NO var costs at all. - for r, p, t, v in model.CostVariable.sparse_iterkeys(): + for r, p, t, v in model.cost_variable.sparse_iterkeys(): if (r, t, v) in efficiency_rtv: var_cost_periods[(r, t, v)].add(p) # use it to check for all/none var costs in viable periods all_periods = model.time_optimize bad_var_costs = False for r, t, v in var_cost_periods: - lifetime = model.LifetimeProcess[r, t, v] + lifetime = model.lifetime_process[r, t, v] expected_periods = {p for p in all_periods if v <= p < v + lifetime} missing_periods = expected_periods - var_cost_periods[r, t, v] if missing_periods: @@ -319,7 +319,7 @@ def check_tech_uncap(model: TemoaModel) -> bool: extra_periods, ) - capacity_params = (model.ExistingCapacity,) + capacity_params = (model.existing_capacity,) bad_cap_entries = False for param in capacity_params: bad_entries = {(r, t, v) for r, t, v in param.sparse_iterkeys() if t in model.tech_uncap} diff --git a/temoa/model_checking/validators.py b/temoa/model_checking/validators.py index 0277dad50..897884515 100644 --- a/temoa/model_checking/validators.py +++ b/temoa/model_checking/validators.py @@ -53,17 +53,17 @@ def validate_linked_tech(model: TemoaModel) -> bool: """ logger.debug('Starting to validate linked techs.') - base_idx = model.LinkedEmissionsTechConstraint_rpsdtve + base_idx = model.linked_emissions_tech_constraint_rpsdtve drivers = {(r, t, v, e) for r, p, s, d, t, v, e in base_idx} for r, t_driver, v, e in drivers: # get the linked tech of same region, emission - t_driven = model.LinkedTechs[r, t_driver, e] + t_driven = model.linked_techs[r, t_driver, e] # check for equality in lifetimes for vintage v - driver_lifetime = model.LifetimeProcess[r, t_driver, v] + driver_lifetime = model.lifetime_process[r, t_driver, v] try: - driven_lifetime = model.LifetimeProcess[r, t_driven, v] + driven_lifetime = model.lifetime_process[r, t_driven, v] except KeyError: logger.error( 'Linked Tech Error: Driven tech %s does not have a vintage entry %d to match driver %s', @@ -277,14 +277,14 @@ def validate_capacity_factor_process( :param v: vintage :return: """ - # devnote: CapacityFactorProcess can be a BIG table and most of these seem redundant + # devnote: capacity_factor_process can be a BIG table and most of these seem redundant # when they're already enforced by the domain of the parameter # Doesn't seem worth the compute time return all( ( r in model.regions, p in model.time_optimize, - s in model.TimeSeason[p], + s in model.time_season[p], d in model.time_of_day, t in model.tech_with_capacity, v in model.vintage_all, @@ -308,7 +308,7 @@ def validate_efficiency( ( isinstance(val, float), val > 0, - r in model.regionalIndices, + r in model.regional_indices, si in model.commodity_physical, t in model.tech_all, so in model.commodity_carrier, @@ -317,7 +317,7 @@ def validate_efficiency( ): return True print('Element Validations:') - print('region', r in model.regionalIndices) + print('region', r in model.regional_indices) print('input_commodity', si in model.commodity_physical) print('tech', t in model.tech_all) print('vintage', v in model.vintage_all) @@ -326,11 +326,11 @@ def validate_efficiency( def validate_reserve_margin(model: TemoaModel) -> None: - for r in model.PlanningReserveMargin.sparse_iterkeys(): - if all((r, p) not in model.processReservePeriods for p in model.time_optimize): + for r in model.planning_reserve_margin.sparse_iterkeys(): + if all((r, p) not in model.process_reserve_periods for p in model.time_optimize): logger.warning( 'Planning reserve margin provided but there are no reserve ' - f'technologies serving this region: {r, model.PlanningReserveMargin[r]}' + f'technologies serving this region: {r, model.planning_reserve_margin[r]}' ) diff --git a/temoa/utilities/unit_cost_explorer.py b/temoa/utilities/unit_cost_explorer.py index d650737fb..89cbabcb4 100644 --- a/temoa/utilities/unit_cost_explorer.py +++ b/temoa/utilities/unit_cost_explorer.py @@ -33,42 +33,42 @@ rptv = ('A', 2020, 'battery', 2020) # rptv model.time_future.construct([2020, 2025, 2030]) # needs to go 1 period beyond optimize horizon model.time_optimize.construct([2020, 2025]) -model.PeriodLength.construct() +model.period_length.construct() model.tech_all.construct(data=['battery']) model.regions.construct(data=['A']) -model.regionalIndices.construct(data=['A']) +model.regional_indices.construct(data=['A']) # make SETS -model.NewCapacityVar_rtv.construct(data=rtv) -model.CapacityVar_rptv.construct(data=rptv) -model.CostInvest_rtv.construct(data=rtv) -model.CostFixed_rptv.construct(data=rptv) -model.LoanLifetimeProcess_rtv.construct(data=rtv) +model.new_capacity_var_rtv.construct(data=rtv) +model.capacity_var_rptv.construct(data=rptv) +model.cost_invest_rtv.construct(data=rtv) +model.cost_fixed_rptv.construct(data=rptv) +model.loan_lifetime_process_rtv.construct(data=rtv) # M.Loan_rtv.construct(data=rtv) -# M.LoanRate_rtv.construct(data=rtv) -model.LifetimeProcess_rtv.construct(data=rtv) -model.MyopicDiscountingYear.construct(data={None: 0}) +# M.loan_rate_rtv.construct(data=rtv) +model.lifetime_process_rtv.construct(data=rtv) +model.myopic_discounting_year.construct(data={None: 0}) # M.ModelProcessLife_rptv.construct(data=rptv) # make PARAMS -model.CostInvest.construct(data={rtv: 1300}) # US_9R_8D -model.CostFixed.construct(data={rptv: 20}) # US_9R_8D -model.LoanLifetimeProcess.construct(data={rtv: 10}) -model.LoanRate.construct(data={rtv: 0.05}) -model.LoanAnnualize.construct() -model.LifetimeTech.construct(data={('A', 'battery'): 20}) -model.LifetimeProcess.construct(data={rtv: 40}) +model.cost_invest.construct(data={rtv: 1300}) # US_9R_8D +model.cost_fixed.construct(data={rptv: 20}) # US_9R_8D +model.loan_lifetime_process.construct(data={rtv: 10}) +model.loan_rate.construct(data={rtv: 0.05}) +model.loan_annualize.construct() +model.lifetime_tech.construct(data={('A', 'battery'): 20}) +model.lifetime_process.construct(data={rtv: 40}) # M.ModelProcessLife.construct(data={rptv: 20}) -model.GlobalDiscountRate.construct(data={None: 0.05}) -model.isSurvivalCurveProcess[rtv] = False +model.global_discount_rate.construct(data={None: 0.05}) +model.is_survival_curve_process[rtv] = False # make/fix VARS -model.V_NewCapacity.construct() -model.V_NewCapacity[rtv].set_value(1) +model.v_new_capacity.construct() +model.v_new_capacity[rtv].set_value(1) -model.V_Capacity.construct() -model.V_Capacity[rptv].set_value(1) +model.v_capacity.construct() +model.v_capacity[rptv].set_value(1) # run the total cost rule on our "model": tot_cost_expr = total_cost_rule(model) @@ -95,50 +95,56 @@ print('building storage level constraint...') # More SETS -model.time_season.construct(['winter', 'summer']) -model.TimeSeason.construct(data={2020: {'winter', 'summer'}, 2025: {'winter', 'summer'}}) -model.DaysPerPeriod.construct(data={None: 365}) +model.time_season_all.construct(['winter', 'summer']) +model.time_season.construct(data={2020: {'winter', 'summer'}, 2025: {'winter', 'summer'}}) +model.days_per_period.construct(data={None: 365}) tod_slices = 2 model.time_of_day.construct(data=range(1, tod_slices + 1)) model.tech_storage.construct(data=['battery']) -model.ProcessLifeFrac_rptv.construct(data=[rptv]) -model.StorageLevel_rpsdtv.construct( +model.process_life_frac_rptv.construct(data=[rptv]) +model.storage_level_rpsdtv.construct( data=[ ('A', 2020, 'winter', 1, 'battery', 2020), ] ) -model.StorageConstraints_rpsdtv.construct( +model.storage_constraints_rpsdtv.construct( data=[ ('A', 2020, 'winter', 1, 'battery', 2020), ] ) # More PARAMS -model.CapacityToActivity.construct(data={('A', 'battery'): 31.536}) -model.StorageDuration.construct(data={('A', 'battery'): 4}) +model.capacity_to_activity.construct(data={('A', 'battery'): 31.536}) +model.storage_duration.construct(data={('A', 'battery'): 4}) seasonal_fractions = {'winter': 0.4, 'summer': 0.6} -model.SegFrac.construct( +model.segment_fraction.construct( data={ (p, s, d): seasonal_fractions[s] / tod_slices for d in model.time_of_day for p in model.time_optimize - for s in model.TimeSeason[p] + for s in model.time_season[p] } ) # QA the total -print(f'quality check. Total of all SegFrac: {sum(model.SegFrac.values()):0.3f}') -model.ProcessLifeFrac.construct(data={('A', 2020, 'battery', 2020): 1.0}) +print(f'quality check. Total of all segment_fraction: {sum(model.segment_fraction.values()):0.3f}') +model.process_life_frac.construct(data={('A', 2020, 'battery', 2020): 1.0}) # More VARS -model.V_StorageLevel.construct() -model.SegFracPerSeason.construct() +model.v_storage_level.construct() +model.segment_fraction_per_season.construct() -model.isSeasonalStorage['battery'] = False +model.is_seasonal_storage['battery'] = False upper_limit = storage_energy_upper_bound_constraint(model, 'A', 2020, 'winter', 1, 'battery', 2020) print('The storage level constraint for the single period in the "super day":\n', upper_limit) # cross-check the multiplier... -mulitplier = storage_dur * model.SegFracPerSeason[2020, 'winter'] * model.DaysPerPeriod * c2a * c +mulitplier = ( + storage_dur + * model.segment_fraction_per_season[2020, 'winter'] + * model.days_per_period + * c2a + * c +) print(f'The multiplier for the storage should be: {mulitplier}') -model.StorageEnergyUpperBoundConstraint.construct() +model.storage_energy_upper_bound_constraint.construct() diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index f859e9703..24f27ca03 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -52,7 +52,7 @@ class ExpectedVals(Enum): ExpectedVals.CONSTR_COUNT: 2810, # reduced by 6 when reworking storageinit. # increased after making annualretirement derived var - # reduced 2025/07/21 after removing existing vintage V_NewCapacity indices + # reduced 2025/07/21 after removing existing vintage v_new_capacity indices # reduced 2025/07/25 by 420 after annualising demands # increased 2025/08/19 after making annual demands optional ExpectedVals.VAR_COUNT: 1960, @@ -73,10 +73,10 @@ class ExpectedVals(Enum): # reduced 3/27: unlim_cap techs now employed. # reduced by 4 in storageinit rework. # increased after making annualretirement derived var - # reduced 2025/07/21 after removing existing vintage V_NewCapacity indices + # reduced 2025/07/21 after removing existing vintage v_new_capacity indices # reduced 2025/07/25 by 200 after annualising demands # increased 2025/08/19 after making annual demands optional - ExpectedVals.VAR_COUNT: 1095, + ExpectedVals.VAR_COUNT: 1095, }, 'mediumville': { # added 2025/06/12 prior to addition of dynamic reserve margin @@ -90,7 +90,7 @@ class ExpectedVals(Enum): ExpectedVals.CONSTR_COUNT: 240, # reduced 2025/07/25 by 18 after annualising demands # increased 2025/08/19 after making annual demands optional - ExpectedVals.VAR_COUNT: 146, + ExpectedVals.VAR_COUNT: 146, }, 'seasonal_storage': { # added 2025/06/16 after addition of seasonal storage @@ -102,7 +102,7 @@ class ExpectedVals(Enum): ExpectedVals.CONSTR_COUNT: 183, # reduced 2025/07/25 by 7 after annualising demands # increased 2025/08/19 after making annual demands optional - ExpectedVals.VAR_COUNT: 91, + ExpectedVals.VAR_COUNT: 91, }, 'survival_curve': { # added 2025/06/19 after addition of survival curves @@ -112,8 +112,8 @@ class ExpectedVals(Enum): ExpectedVals.EFF_DOMAIN_SIZE: 64, ExpectedVals.EFF_INDEX_SIZE: 8, ExpectedVals.CONSTR_COUNT: 127, - # reduced 2025/07/21 after removing existing vintage V_NewCapacity indices - ExpectedVals.VAR_COUNT: 127, + # reduced 2025/07/21 after removing existing vintage v_new_capacity indices + ExpectedVals.VAR_COUNT: 127, }, 'annualised_demand': { # added 2025/06/19 after addition of survival curves @@ -123,7 +123,7 @@ class ExpectedVals(Enum): ExpectedVals.EFF_DOMAIN_SIZE: 36, ExpectedVals.EFF_INDEX_SIZE: 10, ExpectedVals.CONSTR_COUNT: 15, - # reduced 2025/07/21 after removing existing vintage V_NewCapacity indices + # reduced 2025/07/21 after removing existing vintage v_new_capacity indices ExpectedVals.VAR_COUNT: 21, }, } diff --git a/tests/test_exchange_cost_ledger.py b/tests/test_exchange_cost_ledger.py index da7f0d3f0..f13a1d846 100644 --- a/tests/test_exchange_cost_ledger.py +++ b/tests/test_exchange_cost_ledger.py @@ -33,16 +33,16 @@ # these are the necessary Temoa elements to make the ledger work data = { - 'TimeSeason': {2000: [1]}, + 'time_season': {2000: [1]}, 'time_of_day': {1}, 'tech_annual': set(), - 'LifetimeProcess': {('A-B', 't1', 2000): 30, ('B-A', 't1', 2000): 30}, - 'processInputs': {('A-B', 2000, 't1', 2000): ('c1',), ('B-A', 2000, 't1', 2000): ('c1',)}, - 'processOutputsByInput': { + 'lifetime_process': {('A-B', 't1', 2000): 30, ('B-A', 't1', 2000): 30}, + 'process_inputs': {('A-B', 2000, 't1', 2000): ('c1',), ('B-A', 2000, 't1', 2000): ('c1',)}, + 'process_outputs_by_input': { ('A-B', 2000, 't1', 2000, 'c1'): ('c1',), ('B-A', 2000, 't1', 2000, 'c1'): ('c1',), }, - 'V_FlowOut': { + 'v_flow_out': { ('A-B', 2000, 1, 1, 'c1', 't1', 2000, 'c1'): 60, ('B-A', 2000, 1, 1, 'c1', 't1', 2000, 'c1'): 40, }, diff --git a/tests/test_full_runs.py b/tests/test_full_runs.py index fff865449..f31ef6958 100644 --- a/tests/test_full_runs.py +++ b/tests/test_full_runs.py @@ -66,12 +66,12 @@ def test_against_legacy_outputs(system_test_run): # inspect some summary results assert res['Solution'][0]['Status'] == 'optimal' - assert res['Solution'][0]['Objective']['TotalCost']['Value'] == pytest.approx( + assert res['Solution'][0]['Objective']['total_cost']['Value'] == pytest.approx( expected_vals[ExpectedVals.OBJ_VALUE], 0.00001 ) # inspect a couple set sizes - efficiency_param: pyo.Param = mdl.Efficiency + efficiency_param: pyo.Param = mdl.efficiency # check the set membership assert ( len(tuple(efficiency_param.sparse_iterkeys())) == expected_vals[ExpectedVals.EFF_INDEX_SIZE] diff --git a/tests/test_network_model_data.py b/tests/test_network_model_data.py index 197503a61..9131bd91c 100644 --- a/tests/test_network_model_data.py +++ b/tests/test_network_model_data.py @@ -43,8 +43,8 @@ ('d2',), ], 'FROM main.Demand': [('R1', 2020, 'd1'), ('R1', 2020, 'd2')], - # Unique keys for Efficiency and optional tables - 'FROM main.Efficiency': [ + # Unique keys for efficiency and optional tables + 'FROM main.efficiency': [ ('R1', 's1', 't4', 2000, 'p3', 100), ('R1', 's1', 't4', 1990, 'p3', 100), ('R1', 's1', 't1', 2000, 'p1', 100), @@ -52,10 +52,10 @@ ('R1', 'p2', 't3', 2000, 'd1', 100), ('R1', 'p2', 't5', 2000, 'd2', 100), ], - 'FROM EndOfLifeOutput': [], - 'FROM ConstructionInput': [], + 'FROM end_of_life_output': [], + 'FROM construction_input': [], 'FROM main.LinkedTech': [], - 'FROM CostVariable': [], + 'FROM cost_variable': [], }, 'expected': { 'demands_count': 2, @@ -84,15 +84,15 @@ ('d2',), ], 'FROM main.Demand': [('R1', 2020, 'd1'), ('R1', 2020, 'd2')], - 'FROM main.Efficiency': [ + 'FROM main.efficiency': [ ('R1', 's1', 't4', 2000, 'p3', 100), ('R1', 'p1', 'driven', 1990, 'd2', 100), ('R1', 's1', 't1', 2000, 'd1', 100), ], - 'FROM EndOfLifeOutput': [], - 'FROM ConstructionInput': [], + 'FROM end_of_life_output': [], + 'FROM construction_input': [], 'FROM main.LinkedTech': [('R1', 't4', 'nox', 'driven')], - 'FROM CostVariable': [], + 'FROM cost_variable': [], }, 'expected': { 'demands_count': 2, @@ -121,15 +121,15 @@ ('s2',), ], 'FROM main.Demand': [('R1', 2020, 'd1'), ('R1', 2020, 'd2')], - 'FROM main.Efficiency': [ + 'FROM main.efficiency': [ ('R1', 's1', 't4', 2000, 'd2', 100), ('R1', 's2', 'driven', 1990, 'd2', 100), ('R1', 's1', 't1', 2000, 'd1', 100), ], - 'FROM EndOfLifeOutput': [], - 'FROM ConstructionInput': [], + 'FROM end_of_life_output': [], + 'FROM construction_input': [], 'FROM main.LinkedTech': [('R1', 't4', 'nox', 'driven')], - 'FROM CostVariable': [], + 'FROM cost_variable': [], }, 'expected': { 'demands_count': 2, @@ -253,7 +253,7 @@ def test_sector_handling_with_sectors() -> None: def dispatcher(query: str, *_: object) -> MagicMock: if 'sector FROM Technology' in query: return sector_check_mock - elif 'FROM main.Efficiency' in query: + elif 'FROM main.efficiency' in query: return efficiency_mock elif 'Technology WHERE retire==1' in query: m = MagicMock() @@ -283,11 +283,11 @@ def dispatcher(query: str, *_: object) -> MagicMock: m = MagicMock() m.fetchall.return_value = [('R1', 2020, 'd1')] return m - elif 'FROM EndOfLifeOutput' in query: + elif 'FROM end_of_life_output' in query: m = MagicMock() m.fetchall.return_value = [] return m - elif 'FROM ConstructionInput' in query: + elif 'FROM construction_input' in query: m = MagicMock() m.fetchall.return_value = [] return m @@ -295,7 +295,7 @@ def dispatcher(query: str, *_: object) -> MagicMock: m = MagicMock() m.fetchall.return_value = [] return m - elif 'FROM CostVariable' in query: + elif 'FROM cost_variable' in query: m = MagicMock() m.fetchall.return_value = [] return m @@ -306,7 +306,7 @@ def dispatcher(query: str, *_: object) -> MagicMock: # Build network data network_data = network_model_data._build_from_db(mock_con) - # Verify sectors are included in EfficiencyTuple + # Verify sectors are included in efficiencyTuple techs = list(network_data.available_techs[('R1', 2020)]) assert len(techs) == 2 # Fields: region, ic, tech, vintage, oc, lifetime, sector @@ -327,7 +327,7 @@ def dispatcher(query: str, *_: object) -> MagicMock: if 'sector FROM Technology' in query: # Simulate column not existing raise sqlite3.OperationalError('no such column: sector') - elif 'FROM main.Efficiency' in query: + elif 'FROM main.efficiency' in query: # Return data without sector column mock = MagicMock() mock.fetchall.return_value = [ @@ -367,11 +367,11 @@ def dispatcher(query: str, *_: object) -> MagicMock: m = MagicMock() m.fetchall.return_value = [('R1', 2020, 'd1')] return m - elif 'FROM EndOfLifeOutput' in query: + elif 'FROM end_of_life_output' in query: m = MagicMock() m.fetchall.return_value = [] return m - elif 'FROM ConstructionInput' in query: + elif 'FROM construction_input' in query: m = MagicMock() m.fetchall.return_value = [] return m @@ -379,7 +379,7 @@ def dispatcher(query: str, *_: object) -> MagicMock: m = MagicMock() m.fetchall.return_value = [] return m - elif 'FROM CostVariable' in query: + elif 'FROM cost_variable' in query: m = MagicMock() m.fetchall.return_value = [] return m diff --git a/tests/test_pricing_check.py b/tests/test_pricing_check.py index f5144c502..c9997b911 100644 --- a/tests/test_pricing_check.py +++ b/tests/test_pricing_check.py @@ -38,15 +38,15 @@ def mock_model(): model = ConcreteModel('mock') model.tech_uncap = Set(initialize=['refinery']) model.time_optimize = Set(initialize=[2000, 2010, 2020, 2030]) - model.LifetimeProcess = Param(Any, Any, Any, initialize={('CA', 'refinery', 2020): 30}) - model.Efficiency = Param( + model.lifetime_process = Param(Any, Any, Any, initialize={('CA', 'refinery', 2020): 30}) + model.efficiency = Param( Any, Any, Any, Any, Any, initialize={('CA', 0, 'refinery', 2020, 0): 1.0} ) - model.ExistingCapacity = Param(Any, Any, Any, mutable=True) - model.CostFixed = Param(Any, Any, Any, Any, mutable=True) - model.CostInvest = Param(Any, Any, Any, mutable=True) - model.CostVariable = Param(Any, Any, Any, Any, mutable=True) + model.existing_capacity = Param(Any, Any, Any, mutable=True) + model.cost_fixed = Param(Any, Any, Any, Any, mutable=True) + model.cost_invest = Param(Any, Any, Any, mutable=True) + model.cost_variable = Param(Any, Any, Any, Any, mutable=True) model.MaxCapacity = Param(Any, Any, Any, mutable=True) model.MinCapacity = Param(Any, Any, Any, mutable=True) return model @@ -61,10 +61,10 @@ def test_check_tech_uncap(mock_model): model = mock_model assert check_tech_uncap(model), 'should pass for no fixed/invest/variable costs' - model.CostVariable[('CA', 2020, 'refinery', 2020)] = 42 + model.cost_variable[('CA', 2020, 'refinery', 2020)] = 42 assert not check_tech_uncap(model), 'should fail. Has cost in 2020, but missing in 2030' # add in missing cost... - model.CostVariable[('CA', 2030, 'refinery', 2020)] = 42 + model.cost_variable[('CA', 2030, 'refinery', 2020)] = 42 assert check_tech_uncap(model), 'should pass for all periods having var cost' @@ -76,7 +76,7 @@ def test_detect_fixed_cost(mock_model): """ model = mock_model assert check_tech_uncap(model), 'should have cleared and passed again' - model.CostFixed[('CA', 2020, 'refinery', 2020)] = 42 + model.cost_fixed[('CA', 2020, 'refinery', 2020)] = 42 assert not check_tech_uncap(model), 'should fail with any fixed cost' @@ -87,5 +87,5 @@ def test_detect_invest_cost(mock_model): :return: """ model = mock_model - model.CostInvest['CA', 'refinery', 2020] = 42 + model.cost_invest['CA', 'refinery', 2020] = 42 assert not check_tech_uncap(model), 'should fail with any investment cost' diff --git a/tests/test_set_consistency.py b/tests/test_set_consistency.py index be3b1bca3..e92efbe7d 100644 --- a/tests/test_set_consistency.py +++ b/tests/test_set_consistency.py @@ -55,7 +55,7 @@ def test_set_consistency(data_name, config_file, set_file, tmp_path): overage_in_model = dict() shortage_in_model = dict() for set_name, s in model_sets.items(): - if set_name == 'CostEmission_rpe': + if set_name == 'cost_emission_rpe': pass if cached_sets.get(set_name) != s: cached_set = cached_sets.get(set_name, set()) diff --git a/tests/test_storage.py b/tests/test_storage.py index 7cdda1ed9..f80b4c10d 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -34,22 +34,22 @@ def test_storage_fraction(system_test_run): model: TemoaModel # helps with typing for some reason... data_name, results, model, _ = system_test_run - assert len(model.LimitStorageFractionConstraint_rpsdtv) > 0, ( + assert len(model.limit_storage_fraction_constraint_rpsdtv) > 0, ( 'This model does not appear to have any StorageFraction constraints to test' ) - for r, p, s, d, t, v, op in model.LimitStorageFractionConstraint_rpsdtv: + for r, p, s, d, t, v, op in model.limit_storage_fraction_constraint_rpsdtv: energy = ( - model.LimitStorageFraction[r, p, s, d, t, v, op] - * model.V_Capacity[r, p, t, v].value - * model.CapacityToActivity[r, t] - * (model.StorageDuration[r, t] / 8760) - * model.SegFracPerSeason[p, s] - * model.DaysPerPeriod - * model.ProcessLifeFrac[r, p, t, v] + model.limit_storage_fraction[r, p, s, d, t, v, op] + * model.v_capacity[r, p, t, v].value + * model.capacity_to_activity[r, t] + * (model.storage_duration[r, t] / 8760) + * model.segment_fraction_per_season[p, s] + * model.days_per_period + * model.process_life_frac[r, p, t, v] ) - assert model.V_StorageLevel[r, p, s, d, t, v].value == pytest.approx(energy, abs=1e-5), ( + assert model.v_storage_level[r, p, s, d, t, v].value == pytest.approx(energy, abs=1e-5), ( f'model fails to initialise storage state at start of season {r, p, s, d, t, v}' ) @@ -67,26 +67,26 @@ def test_state_sequencing(system_test_run): model: TemoaModel # helps with typing for some reason... data_name, results, model, _ = system_test_run - assert len(model.StorageLevel_rpsdtv) > 0, ( + assert len(model.storage_level_rpsdtv) > 0, ( 'This model does not appear to have any available storage components' ) - for r, p, s, d, t, v in model.StorageLevel_rpsdtv: + for r, p, s, d, t, v in model.storage_level_rpsdtv: charge = sum( - model.V_FlowIn[r, p, s, d, S_i, t, v, S_o].value * model.Efficiency[r, S_i, t, v, S_o] - for S_i in model.processInputs[r, p, t, v] - for S_o in model.processOutputsByInput[r, p, t, v, S_i] + model.v_flow_in[r, p, s, d, S_i, t, v, S_o].value * model.efficiency[r, S_i, t, v, S_o] + for S_i in model.process_inputs[r, p, t, v] + for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) discharge = sum( - model.V_FlowOut[r, p, s, d, S_i, t, v, S_o].value - for S_o in model.processOutputs[r, p, t, v] - for S_i in model.processInputsByOutput[r, p, t, v, S_o] + model.v_flow_out[r, p, s, d, S_i, t, v, S_o].value + for S_o in model.process_outputs[r, p, t, v] + for S_i in model.process_inputs_by_output[r, p, t, v, S_o] ) s_next, d_next = model.time_next[p, s, d] - state = model.V_StorageLevel[r, p, s, d, t, v].value - next_state = model.V_StorageLevel[r, p, s_next, d_next, t, v].value + state = model.v_storage_level[r, p, s, d, t, v].value + next_state = model.v_storage_level[r, p, s_next, d_next, t, v].value assert state + charge - discharge == pytest.approx(next_state, abs=1e-5), ( f'model fails to correctly sequence storage states {r, p, s, t, v} sequenced {s, d} to {s_next, d_next}' @@ -106,28 +106,28 @@ def test_storage_flow_balance(system_test_run): """ model: TemoaModel # helps with typing for some reason... data_name, results, model, _ = system_test_run - assert len(model.StorageLevel_rpsdtv) > 0, ( + assert len(model.storage_level_rpsdtv) > 0, ( 'This model does not appear to haveany available storage components' ) for s_tech in model.tech_storage: inflow_indices = { (r, p, s, d, i, t, v, o) - for r, p, s, d, i, t, v, o in model.FlowInStorage_rpsditvo + for r, p, s, d, i, t, v, o in model.flow_in_storage_rpsditvo if t == s_tech } outflow_indices = { (r, p, s, d, i, t, v, o) - for r, p, s, d, i, t, v, o in model.FlowVar_rpsditvo + for r, p, s, d, i, t, v, o in model.flow_var_rpsditvo if t == s_tech } # calculate the inflow and outflow. Inflow is taxed by efficiency in the model, # so we need to do that here as well inflow = sum( - model.V_FlowIn[r, p, s, d, i, t, v, o].value * model.Efficiency[r, i, t, v, o] + model.v_flow_in[r, p, s, d, i, t, v, o].value * model.efficiency[r, i, t, v, o] for (r, p, s, d, i, t, v, o) in inflow_indices ) - outflow = sum(model.V_FlowOut[idx].value for idx in outflow_indices) + outflow = sum(model.v_flow_out[idx].value for idx in outflow_indices) assert inflow == pytest.approx(outflow, abs=1e-5), ( f'total inflow and outflow of storage tech {s_tech} do not match', diff --git a/tests/testing_configs/config_annualised_demand.toml b/tests/testing_configs/config_annualised_demand.toml index c280d1d58..c4b291ace 100644 --- a/tests/testing_configs/config_annualised_demand.toml +++ b/tests/testing_configs/config_annualised_demand.toml @@ -26,22 +26,22 @@ save_lp_file = false # What seasons represent in the model # Options: # 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples +# Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. # 'representative_periods' # Each season represents a number of days, though not necessarily in any particular order. # If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in # the Technology table. # 'seasonal_timeslices' # Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# time_season_sequential table can be left empty. Seasonal storage must still be tagged. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out # in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the TimeSeasonSequential table filled. +# storage must be tagged and the time_season_sequential table filled. time_sequencing = 'representative_periods' # How contributions to the planning reserve margin are calculated @@ -51,7 +51,7 @@ time_sequencing = 'representative_periods' # capacity value = net capacity * capacity credit # 'dynamic' # Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: +# For most generators, contributions are available (derated) output in each time slice: # capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: # capacity value = flow out * reserve capacity derate @@ -71,7 +71,3 @@ weighting = "hull_expansion" # use a convex hull expansion algorithm to weight [myopic] myopic_view = 2 # number of periods seen at one iteration - - - - diff --git a/tests/testing_configs/config_emissions.toml b/tests/testing_configs/config_emissions.toml index 368abd3f1..65fc76576 100644 --- a/tests/testing_configs/config_emissions.toml +++ b/tests/testing_configs/config_emissions.toml @@ -26,22 +26,22 @@ save_lp_file = false # What seasons represent in the model # Options: # 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples +# Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. # 'representative_periods' # Each season represents a number of days, though not necessarily in any particular order. # If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in # the Technology table. # 'seasonal_timeslices' # Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# time_season_sequential table can be left empty. Seasonal storage must still be tagged. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out # in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the TimeSeasonSequential table filled. +# storage must be tagged and the time_season_sequential table filled. time_sequencing = 'seasonal_timeslices' # How contributions to the planning reserve margin are calculated @@ -51,7 +51,7 @@ time_sequencing = 'seasonal_timeslices' # capacity value = net capacity * capacity credit # 'dynamic' # Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: +# For most generators, contributions are available (derated) output in each time slice: # capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: # capacity value = flow out * reserve capacity derate @@ -69,7 +69,3 @@ weight = "integer" # currently supported: [integer, normalized] [myopic] myopic_view = 2 # number of periods seen at one iteration - - - - diff --git a/tests/testing_configs/config_link_test.toml b/tests/testing_configs/config_link_test.toml index a93fb6d88..627762a64 100644 --- a/tests/testing_configs/config_link_test.toml +++ b/tests/testing_configs/config_link_test.toml @@ -79,22 +79,22 @@ save_lp_file = false # What seasons represent in the model # Options: # 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples +# Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. # 'representative_periods' # Each season represents a number of days, though not necessarily in any particular order. # If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in # the Technology table. # 'seasonal_timeslices' # Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# time_season_sequential table can be left empty. Seasonal storage must still be tagged. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out # in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the TimeSeasonSequential table filled. +# storage must be tagged and the time_season_sequential table filled. time_sequencing = 'seasonal_timeslices' # How contributions to the planning reserve margin are calculated @@ -104,7 +104,7 @@ time_sequencing = 'seasonal_timeslices' # capacity value = net capacity * capacity credit # 'dynamic' # Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: +# For most generators, contributions are available (derated) output in each time slice: # capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: # capacity value = flow out * reserve capacity derate @@ -123,7 +123,3 @@ weight = "integer" # currently supported: [integer, normalized] [myopic] view_depth = 2 # number of periods seen/analyzed per iteration step_size = 1 # number of periods to step by (must be <= view depth) - - - - diff --git a/tests/testing_configs/config_materials.toml b/tests/testing_configs/config_materials.toml index 71f23bf7b..cc3b09df8 100644 --- a/tests/testing_configs/config_materials.toml +++ b/tests/testing_configs/config_materials.toml @@ -26,22 +26,22 @@ save_lp_file = false # What seasons represent in the model # Options: # 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples +# Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. # 'representative_periods' # Each season represents a number of days, though not necessarily in any particular order. # If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in # the Technology table. # 'seasonal_timeslices' # Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# time_season_sequential table can be left empty. Seasonal storage must still be tagged. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out # in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the TimeSeasonSequential table filled. +# storage must be tagged and the time_season_sequential table filled. time_sequencing = 'seasonal_timeslices' # How contributions to the planning reserve margin are calculated @@ -51,7 +51,7 @@ time_sequencing = 'seasonal_timeslices' # capacity value = net capacity * capacity credit # 'dynamic' # Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: +# For most generators, contributions are available (derated) output in each time slice: # capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: # capacity value = flow out * reserve capacity derate @@ -69,7 +69,3 @@ weight = "integer" # currently supported: [integer, normalized] [myopic] myopic_view = 2 # number of periods seen at one iteration - - - - diff --git a/tests/testing_configs/config_mediumville.toml b/tests/testing_configs/config_mediumville.toml index e2e9a94c9..cb9a81d91 100644 --- a/tests/testing_configs/config_mediumville.toml +++ b/tests/testing_configs/config_mediumville.toml @@ -60,22 +60,22 @@ save_lp_file = false # What seasons represent in the model # Options: # 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples +# Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. # 'representative_periods' # Each season represents a number of days, though not necessarily in any particular order. # If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in # the Technology table. # 'seasonal_timeslices' # Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# time_season_sequential table can be left empty. Seasonal storage must still be tagged. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out # in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the TimeSeasonSequential table filled. +# storage must be tagged and the time_season_sequential table filled. time_sequencing = 'seasonal_timeslices' # How contributions to the planning reserve margin are calculated @@ -85,7 +85,7 @@ time_sequencing = 'seasonal_timeslices' # capacity value = net capacity * capacity credit # 'dynamic' # Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: +# For most generators, contributions are available (derated) output in each time slice: # capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: # capacity value = flow out * reserve capacity derate @@ -103,7 +103,3 @@ weight = "integer" # currently supported: [integer, normalized] [myopic] myopic_view = 2 # number of periods seen at one iteration - - - - diff --git a/tests/testing_configs/config_seasonal_storage.toml b/tests/testing_configs/config_seasonal_storage.toml index bbd82ede2..7bcf080a2 100644 --- a/tests/testing_configs/config_seasonal_storage.toml +++ b/tests/testing_configs/config_seasonal_storage.toml @@ -26,22 +26,22 @@ save_lp_file = false # What seasons represent in the model # Options: # 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples +# Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. # 'representative_periods' # Each season represents a number of days, though not necessarily in any particular order. # If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in # the Technology table. # 'seasonal_timeslices' # Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# time_season_sequential table can be left empty. Seasonal storage must still be tagged. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out # in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the TimeSeasonSequential table filled. +# storage must be tagged and the time_season_sequential table filled. time_sequencing = 'representative_periods' # How contributions to the planning reserve margin are calculated @@ -51,7 +51,7 @@ time_sequencing = 'representative_periods' # capacity value = net capacity * capacity credit # 'dynamic' # Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: +# For most generators, contributions are available (derated) output in each time slice: # capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: # capacity value = flow out * reserve capacity derate @@ -71,7 +71,3 @@ weighting = "hull_expansion" # use a convex hull expansion algorithm to weight [myopic] myopic_view = 2 # number of periods seen at one iteration - - - - diff --git a/tests/testing_configs/config_storageville.toml b/tests/testing_configs/config_storageville.toml index 93617d301..5872f828e 100644 --- a/tests/testing_configs/config_storageville.toml +++ b/tests/testing_configs/config_storageville.toml @@ -60,22 +60,22 @@ save_lp_file = false # What seasons represent in the model # Options: # 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples +# Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. # 'representative_periods' # Each season represents a number of days, though not necessarily in any particular order. # If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in # the Technology table. # 'seasonal_timeslices' # Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# time_season_sequential table can be left empty. Seasonal storage must still be tagged. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out # in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the TimeSeasonSequential table filled. +# storage must be tagged and the time_season_sequential table filled. time_sequencing = 'seasonal_timeslices' # How contributions to the planning reserve margin are calculated @@ -85,7 +85,7 @@ time_sequencing = 'seasonal_timeslices' # capacity value = net capacity * capacity credit # 'dynamic' # Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: +# For most generators, contributions are available (derated) output in each time slice: # capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: # capacity value = flow out * reserve capacity derate @@ -103,7 +103,3 @@ weight = "integer" # currently supported: [integer, normalized] [myopic] myopic_view = 2 # number of periods seen at one iteration - - - - diff --git a/tests/testing_configs/config_survival_curve.toml b/tests/testing_configs/config_survival_curve.toml index 19cd465d3..742872d58 100644 --- a/tests/testing_configs/config_survival_curve.toml +++ b/tests/testing_configs/config_survival_curve.toml @@ -26,22 +26,22 @@ save_lp_file = false # What seasons represent in the model # Options: # 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples +# Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. # 'representative_periods' # Each season represents a number of days, though not necessarily in any particular order. # If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in # the Technology table. # 'seasonal_timeslices' # Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# time_season_sequential table can be left empty. Seasonal storage must still be tagged. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out # in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the TimeSeasonSequential table filled. +# storage must be tagged and the time_season_sequential table filled. time_sequencing = 'seasonal_timeslices' # How contributions to the planning reserve margin are calculated @@ -51,7 +51,7 @@ time_sequencing = 'seasonal_timeslices' # capacity value = net capacity * capacity credit # 'dynamic' # Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: +# For most generators, contributions are available (derated) output in each time slice: # capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: # capacity value = flow out * reserve capacity derate @@ -70,4 +70,4 @@ axis = "tech_category_activity" # use the tech activity Manager to control exp weighting = "hull_expansion" # use a convex hull expansion algorithm to weight exploration [myopic] -myopic_view = 2 # number of periods seen at one iteration \ No newline at end of file +myopic_view = 2 # number of periods seen at one iteration diff --git a/tests/testing_configs/config_test_system.toml b/tests/testing_configs/config_test_system.toml index 8bd7fa82b..278244d17 100644 --- a/tests/testing_configs/config_test_system.toml +++ b/tests/testing_configs/config_test_system.toml @@ -26,22 +26,22 @@ save_lp_file = false # What seasons represent in the model # Options: # 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples +# Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. # 'representative_periods' # Each season represents a number of days, though not necessarily in any particular order. # If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in # the Technology table. # 'seasonal_timeslices' # Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# time_season_sequential table can be left empty. Seasonal storage must still be tagged. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out # in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the TimeSeasonSequential table filled. +# storage must be tagged and the time_season_sequential table filled. time_sequencing = 'seasonal_timeslices' # How contributions to the planning reserve margin are calculated @@ -51,7 +51,7 @@ time_sequencing = 'seasonal_timeslices' # capacity value = net capacity * capacity credit # 'dynamic' # Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: +# For most generators, contributions are available (derated) output in each time slice: # capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: # capacity value = flow out * reserve capacity derate @@ -69,7 +69,3 @@ weight = "integer" # currently supported: [integer, normalized] [myopic] myopic_view = 2 # number of periods seen at one iteration - - - - diff --git a/tests/testing_configs/config_utopia.toml b/tests/testing_configs/config_utopia.toml index 7cd349d20..82a499d82 100644 --- a/tests/testing_configs/config_utopia.toml +++ b/tests/testing_configs/config_utopia.toml @@ -26,22 +26,22 @@ save_lp_file = false # What seasons represent in the model # Options: # 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples +# Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. # 'representative_periods' # Each season represents a number of days, though not necessarily in any particular order. # If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in # the Technology table. # 'seasonal_timeslices' # Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# time_season_sequential table can be left empty. Seasonal storage must still be tagged. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out # in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the TimeSeasonSequential table filled. +# storage must be tagged and the time_season_sequential table filled. time_sequencing = 'seasonal_timeslices' # How contributions to the planning reserve margin are calculated @@ -51,7 +51,7 @@ time_sequencing = 'seasonal_timeslices' # capacity value = net capacity * capacity credit # 'dynamic' # Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: +# For most generators, contributions are available (derated) output in each time slice: # capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: # capacity value = flow out * reserve capacity derate @@ -71,7 +71,3 @@ weighting = "hull_expansion" # use a convex hull expansion algorithm to weight [myopic] myopic_view = 2 # number of periods seen at one iteration - - - - diff --git a/tests/testing_configs/config_utopia_myopic.toml b/tests/testing_configs/config_utopia_myopic.toml index c59b56534..14c7947da 100644 --- a/tests/testing_configs/config_utopia_myopic.toml +++ b/tests/testing_configs/config_utopia_myopic.toml @@ -28,22 +28,22 @@ save_lp_file = false # What seasons represent in the model # Options: # 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples +# Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. # 'representative_periods' # Each season represents a number of days, though not necessarily in any particular order. # If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in # the Technology table. # 'seasonal_timeslices' # Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# time_season_sequential table can be left empty. Seasonal storage must still be tagged. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out # in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the TimeSeasonSequential table filled. +# storage must be tagged and the time_season_sequential table filled. time_sequencing = 'seasonal_timeslices' # How contributions to the planning reserve margin are calculated @@ -53,7 +53,7 @@ time_sequencing = 'seasonal_timeslices' # capacity value = net capacity * capacity credit # 'dynamic' # Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: +# For most generators, contributions are available (derated) output in each time slice: # capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: # capacity value = flow out * reserve capacity derate @@ -72,5 +72,3 @@ weight = "integer" # currently supported: [integer, normalized] [myopic] view_depth = 2 # number of periods seen/analyzed per iteration step_size = 1 # number of periods to step by - - diff --git a/tests/testing_data/US_9R_8D_legacy_set_sizes.json b/tests/testing_data/US_9R_8D_legacy_set_sizes.json index 014300fb5..caccef066 100644 --- a/tests/testing_data/US_9R_8D_legacy_set_sizes.json +++ b/tests/testing_data/US_9R_8D_legacy_set_sizes.json @@ -43,7 +43,7 @@ "tech_commercial": 0, "tech_residential": 0, "tech_PowerPlants": 0, - "SegFrac_index": 192, + "segment_fraction_index": 192, "DemandDefaultDistribution_index": 192, "DemandSpecificDistribution_index_index_0_index_0": 88128, "DemandSpecificDistribution_index_index_0": 88128, @@ -53,17 +53,17 @@ "ResourceBound_index_index_0": 24255, "ResourceBound_index": 24255, "CapacityToActivity_index": 90639, - "ExistingCapacity_index_index_0": 7160481, - "ExistingCapacity_index": 7160481, - "Efficiency_index_index_0_index_0_index_0": 1308460978440, - "Efficiency_index_index_0_index_0": 1308460978440, - "Efficiency_index_index_0": 1308460978440, - "Efficiency_index": 1308460978440, + "existing_capacity_index_index_0": 7160481, + "existing_capacity_index": 7160481, + "efficiency_index_index_0_index_0_index_0": 1308460978440, + "efficiency_index_index_0_index_0": 1308460978440, + "efficiency_index_index_0": 1308460978440, + "efficiency_index": 1308460978440, "CapacityFactor_rsdtv": 8895936, "CapacityFactor_rsdt": 1741440, - "LifetimeTech_index": 90639, + "lifetime_tech_index": 90639, "LifetimeLoanTech_index": 90639, - "LifetimeProcess_rtv": 46333, + "lifetime_process_rtv": 46333, "LifetimeLoanProcess_rtv": 42431, "TechInputSplit_index_index_0_index_0": 27141345, "TechInputSplit_index_index_0": 27141345, @@ -74,16 +74,16 @@ "TechOutputSplit_index_index_0_index_0": 30736692, "TechOutputSplit_index_index_0": 30736692, "TechOutputSplit_index": 30736692, - "RenewablePortfolioStandard_index": 63, - "CostFixed_rptv": 154120, - "CostFixedVintageDefault_rtv": 46333, - "CostInvest_rtv": 42431, - "CostVariable_rptv": 154120, - "CostVariableVintageDefault_rtv": 46333, + "renewable_portfolio_standard_index": 63, + "cost_fixed_rptv": 154120, + "cost_fixedVintageDefault_rtv": 46333, + "cost_invest_rtv": 42431, + "cost_variable_rptv": 154120, + "cost_variableVintageDefault_rtv": 46333, "DiscountRate_rtv": 31717, "Loan_rtv": 31717, "ModelProcessLife_rptv": 154120, - "ProcessLifeFrac_rptv": 154120, + "process_life_frac_rptv": 154120, "MinCapacity_index_index_0": 634473, "MinCapacity_index": 634473, "MaxCapacity_index_index_0": 634473, @@ -107,7 +107,7 @@ "GrowthRateSeed_index": 90639, "EmissionLimit_index_index_0": 158823602, "EmissionLimit_index": 158823602, - "EmissionActivity_reitvo": 1863805, + "emission_activity_reitvo": 1863805, "MinActivityGroup_index_index_0": 0, "MinActivityGroup_index": 0, "MaxActivityGroup_index_index_0": 0, @@ -121,48 +121,48 @@ "MaxNewCapacityGroup_index_index_0": 0, "MaxNewCapacityGroup_index": 0, "MinCapShare_rptg": 0, - "LinkedTechs_index_index_0": 2084697, - "LinkedTechs_index": 2084697, + "linked_techs_index_index_0": 2084697, + "linked_techs_index": 2084697, "RampUp_index": 261, "RampDown_index": 261, - "CapacityCredit_index_index_0_index_0": 54564678, - "CapacityCredit_index_index_0": 54564678, - "CapacityCredit_index": 54564678, - "StorageDuration_index": 45, + "capacity_credit_index_index_0_index_0": 54564678, + "capacity_credit_index_index_0": 54564678, + "capacity_credit_index": 54564678, + "storage_duration_index": 45, "StorageInit_rtv": 260, - "FlowVar_rpsditvo": 18920064, - "FlowVarAnnual_rpitvo": 193276, - "FlexVar_rpsditvo": 0, - "FlexVarAnnual_rpitvo": 0, - "CurtailmentVar_rpsditvo": 4855104, - "FlowInStorage_rpsditvo": 157632, - "StorageLevel_rpsdtv": 157632, - "CapacityVar_rptv": 154120, - "NewCapacityVar_rtv": 46333, - "RetiredCapacityVar_rptv": 0, - "CapacityAvailableVar_rpt": 56272, - "CapacityConstraint_rpsdtv": 16599360, - "CapacityAnnualConstraint_rptv": 67665, - "DemandConstraint_rpsdc": 607488, - "DemandActivityConstraint_rpsdtv_dem_s0d0": 1306440, - "CommodityBalanceConstraint_rpsdc": 1813440, + "flow_var_rpsditvo": 18920064, + "flow_var_annual_rpitvo": 193276, + "flex_var_rpsditvo": 0, + "flex_var_annual_rpitvo": 0, + "curtailment_var_rpsditvo": 4855104, + "flow_in_storage_rpsditvo": 157632, + "storage_level_rpsdtv": 157632, + "capacity_var_rptv": 154120, + "new_capacity_var_rtv": 46333, + "retired_capacity_var_rptv": 0, + "capacity_available_var_rpt": 56272, + "capacity_constraint_rpsdtv": 16599360, + "capacity_annual_constraint_rptv": 67665, + "demand_constraint_rpsdc": 607488, + "demand_activity_constraint_rpsdtv_dem_s0d0": 1306440, + "commodity_balance_constraint_rpsdc": 1813440, "CommodityBalanceAnnualConstraint_rpc": 13117, "ResourceConstraint_rpr": 0, - "BaseloadDiurnalConstraint_rpsdtv": 0, - "RegionalExchangeCapacityConstraint_rrptv": 3794, - "StorageConstraints_rpsdtv": 157632, + "baseload_diurnal_constraint_rpsdtv": 0, + "regional_exchange_capacity_constraint_rrptv": 3794, + "storage_constraints_rpsdtv": 157632, "StorageInitConstraint_rtv": 0, "RampConstraintDay_rpsdtv": 369600, "RampConstraintPeriod_rptv": 1925, - "ReserveMargin_rpsd": 12096, + "reserve_margin_rpsd": 12096, "EmissionLimitConstraint_rpe": 89, "GrowthRateMaxConstraint_rtv": 0, "MaxActivityConstraint_rpt": 4424, "MinActivityConstraint_rpt": 66, "MinActivityGroup_rpg": 0, "MaxActivityGroup_rpg": 0, - "MaxCapacityConstraint_rpt": 6580, - "MaxNewCapacityConstraint_rpt": 0, + "Maxcapacity_constraint_rpt": 6580, + "MaxNewcapacity_constraint_rpt": 0, "MaxCapacityGroupConstraint_rpg": 0, "MinCapacityGroupConstraint_rpg": 0, "MinNewCapacityGroupConstraint_rpg": 0, @@ -174,8 +174,8 @@ "MinNewCapacityShareConstraint_rptg": 0, "MaxNewCapacityShareConstraint_rptg": 0, "MaxResourceConstraint_rt": 9, - "MinCapacityConstraint_rpt": 0, - "MinNewCapacityConstraint_rpt": 0, + "Mincapacity_constraint_rpt": 0, + "MinNewcapacity_constraint_rpt": 0, "MinAnnualCapacityFactorConstraint_rpto": 0, "MaxAnnualCapacityFactorConstraint_rpto": 0, "TechInputSplitConstraint_rpsditv": 924480, @@ -183,6 +183,6 @@ "TechInputSplitAverageConstraint_rpitv": 63, "TechOutputSplitConstraint_rpsdtvo": 0, "TechOutputSplitAnnualConstraint_rptvo": 0, - "RenewablePortfolioStandardConstraint_rpt": 0, - "LinkedEmissionsTechConstraint_rpsdtve": 312768 -} \ No newline at end of file + "renewable_portfolio_standard_constraint_rpt": 0, + "linked_emissions_tech_constraint_rpsdtve": 312768 +} diff --git a/tests/testing_data/US_9R_8D_set_sizes.json b/tests/testing_data/US_9R_8D_set_sizes.json index 03d89d31a..15a3096be 100644 --- a/tests/testing_data/US_9R_8D_set_sizes.json +++ b/tests/testing_data/US_9R_8D_set_sizes.json @@ -45,33 +45,33 @@ "tech_residential": 0, "tech_PowerPlants": 0, "progress_marker_2_index": 1, - "SegFrac_index": 192, + "segment_fraction_index": 192, "DemandDefaultDistribution_index": 192, "DemandSpecificDistribution_index": 88128, "Demand_index": 3213, "ResourceBound_index": 24255, "CapacityToActivity_index": 90639, - "ExistingCapacity_index": 7160481, - "Efficiency_index": 1308460978440, - "CapacityFactorProcess_index": 166292352, + "existing_capacity_index": 7160481, + "efficiency_index": 1308460978440, + "capacity_factor_process_index": 166292352, "CapacityFactor_rsdt": 1741440, - "LifetimeTech_index": 90639, + "lifetime_tech_index": 90639, "LifetimeLoanTech_index": 90639, - "LifetimeProcess_rtv": 46333, + "lifetime_process_rtv": 46333, "LifetimeLoanProcess_rtv": 42431, "TechInputSplit_index": 27141345, "TechInputSplitAverage_index": 24255, "TechOutputSplit_index": 30736692, - "RenewablePortfolioStandard_index": 63, - "CostFixed_rptv": 154120, - "CostFixedVintageDefault_rtv": 46333, - "CostInvest_rtv": 42431, - "CostVariable_rptv": 154120, - "CostVariableVintageDefault_rtv": 46333, + "renewable_portfolio_standard_index": 63, + "cost_fixed_rptv": 154120, + "cost_fixedVintageDefault_rtv": 46333, + "cost_invest_rtv": 42431, + "cost_variable_rptv": 154120, + "cost_variableVintageDefault_rtv": 46333, "DiscountRate_rtv": 31717, "Loan_rtv": 31717, "ModelProcessLife_rptv": 154120, - "ProcessLifeFrac_rptv": 154120, + "process_life_frac_rptv": 154120, "MinCapacity_index": 634473, "MaxCapacity_index": 634473, "MinNewCapacity_index": 634473, @@ -84,7 +84,7 @@ "GrowthRateMax_index": 90639, "GrowthRateSeed_index": 90639, "EmissionLimit_index": 1610, - "EmissionActivity_reitvo": 1863805, + "emission_activity_reitvo": 1863805, "MinActivityGroup_index": 0, "MaxActivityGroup_index": 0, "MinCapacityGroup_index": 0, @@ -92,41 +92,41 @@ "MinNewCapacityGroup_index": 0, "MaxNewCapacityGroup_index": 0, "MinCapShare_rptg": 0, - "LinkedTechs_index": 2084697, + "linked_techs_index": 2084697, "RampUp_index": 261, "RampDown_index": 261, - "CapacityCredit_index": 54564678, - "StorageDuration_index": 45, + "capacity_credit_index": 54564678, + "storage_duration_index": 45, "StorageInit_rtv": 260, "progress_marker_3_index": 1, - "FlowVar_rpsditvo": 18920064, - "FlowVarAnnual_rpitvo": 193276, - "FlexVar_rpsditvo": 0, - "FlexVarAnnual_rpitvo": 0, - "CurtailmentVar_rpsditvo": 4855104, - "FlowInStorage_rpsditvo": 157632, - "StorageLevel_rpsdtv": 157632, - "CapacityVar_rptv": 154120, - "NewCapacityVar_rtv": 46333, - "RetiredCapacityVar_rptv": 0, - "CapacityAvailableVar_rpt": 56272, + "flow_var_rpsditvo": 18920064, + "flow_var_annual_rpitvo": 193276, + "flex_var_rpsditvo": 0, + "flex_var_annual_rpitvo": 0, + "curtailment_var_rpsditvo": 4855104, + "flow_in_storage_rpsditvo": 157632, + "storage_level_rpsdtv": 157632, + "capacity_var_rptv": 154120, + "new_capacity_var_rtv": 46333, + "retired_capacity_var_rptv": 0, + "capacity_available_var_rpt": 56272, "progress_marker_4_index": 1, - "CapacityConstraint_rpsdtv": 16599360, - "CapacityAnnualConstraint_rptv": 67665, + "capacity_constraint_rpsdtv": 16599360, + "capacity_annual_constraint_rptv": 67665, "progress_marker_5_index": 1, - "DemandConstraint_rpsdc": 607488, - "DemandActivityConstraint_rpsdtv_dem_s0d0": 1306440, - "CommodityBalanceConstraint_rpsdc": 1813440, + "demand_constraint_rpsdc": 607488, + "demand_activity_constraint_rpsdtv_dem_s0d0": 1306440, + "commodity_balance_constraint_rpsdc": 1813440, "CommodityBalanceAnnualConstraint_rpc": 13117, "ResourceConstraint_rpr": 0, - "BaseloadDiurnalConstraint_rpsdtv": 0, - "RegionalExchangeCapacityConstraint_rrptv": 3794, + "baseload_diurnal_constraint_rpsdtv": 0, + "regional_exchange_capacity_constraint_rrptv": 3794, "progress_marker_6_index": 1, - "StorageConstraints_rpsdtv": 157632, + "storage_constraints_rpsdtv": 157632, "StorageInitConstraint_rtv": 0, "RampConstraintDay_rpsdtv": 369600, "RampConstraintPeriod_rptv": 1925, - "ReserveMargin_rpsd": 12096, + "reserve_margin_rpsd": 12096, "EmissionLimitConstraint_rpe": 89, "progress_marker_7_index": 1, "GrowthRateMaxConstraint_rtv": 0, @@ -134,8 +134,8 @@ "MinActivityConstraint_rpt": 66, "MinActivityGroup_rpg": 0, "MaxActivityGroup_rpg": 0, - "MaxCapacityConstraint_rpt": 6580, - "MaxNewCapacityConstraint_rpt": 0, + "Maxcapacity_constraint_rpt": 6580, + "MaxNewcapacity_constraint_rpt": 0, "MaxCapacityGroupConstraint_rpg": 0, "MinCapacityGroupConstraint_rpg": 0, "MinNewCapacityGroupConstraint_rpg": 0, @@ -148,8 +148,8 @@ "MaxNewCapacityShareConstraint_rptg": 0, "progress_marker_8_index": 1, "MaxResourceConstraint_rt": 9, - "MinCapacityConstraint_rpt": 0, - "MinNewCapacityConstraint_rpt": 0, + "Mincapacity_constraint_rpt": 0, + "MinNewcapacity_constraint_rpt": 0, "MinAnnualCapacityFactorConstraint_rpto": 0, "MaxAnnualCapacityFactorConstraint_rpto": 0, "TechInputSplitConstraint_rpsditv": 924480, @@ -157,7 +157,7 @@ "TechInputSplitAverageConstraint_rpitv": 63, "TechOutputSplitConstraint_rpsdtvo": 0, "TechOutputSplitAnnualConstraint_rptvo": 0, - "RenewablePortfolioStandardConstraint_rpt": 0, - "LinkedEmissionsTechConstraint_rpsdtve": 312768, + "renewable_portfolio_standard_constraint_rpt": 0, + "linked_emissions_tech_constraint_rpsdtve": 312768, "progress_marker_9_index": 1 -} \ No newline at end of file +} diff --git a/tests/testing_data/annualised_demand.sql b/tests/testing_data/annualised_demand.sql index 5a263ae28..3f2c96584 100644 --- a/tests/testing_data/annualised_demand.sql +++ b/tests/testing_data/annualised_demand.sql @@ -19,7 +19,7 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -43,7 +43,7 @@ CREATE TABLE SectorLabel sector TEXT PRIMARY KEY, notes TEXT ); -CREATE TABLE CapacityCredit +CREATE TABLE capacity_credit ( region TEXT, period INTEGER @@ -56,7 +56,7 @@ CREATE TABLE CapacityCredit PRIMARY KEY (region, period, tech, vintage), CHECK (credit >= 0 AND credit <= 1) ); -CREATE TABLE CapacityFactorProcess +CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER @@ -73,7 +73,7 @@ CREATE TABLE CapacityFactorProcess PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE CapacityFactorTech +CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER @@ -124,7 +124,7 @@ INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('w','waste commodity'); INSERT INTO CommodityType VALUES('wa','waste annual commodity'); INSERT INTO CommodityType VALUES('wp','waste physical commodity'); -CREATE TABLE ConstructionInput +CREATE TABLE construction_input ( region TEXT, input_comm TEXT @@ -138,7 +138,7 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -CREATE TABLE CostEmission +CREATE TABLE cost_emission ( region TEXT, period INTEGER @@ -150,7 +150,7 @@ CREATE TABLE CostEmission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -CREATE TABLE CostFixed +CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -164,7 +164,7 @@ CREATE TABLE CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE CostInvest +CREATE TABLE cost_invest ( region TEXT, tech TEXT @@ -176,9 +176,9 @@ CREATE TABLE CostInvest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO CostInvest VALUES('region','annual',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('region','non_annual',2000,1.0,NULL,NULL); -CREATE TABLE CostVariable +INSERT INTO cost_invest VALUES('region','annual',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('region','non_annual',2000,1.0,NULL,NULL); +CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -192,8 +192,8 @@ CREATE TABLE CostVariable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostVariable VALUES('region',2000,'annual',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2000,'non_annual',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2000,'annual',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2000,'non_annual',2000,1.0,NULL,NULL); CREATE TABLE Demand ( region TEXT, @@ -223,7 +223,7 @@ CREATE TABLE DemandSpecificDistribution PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -CREATE TABLE EndOfLifeOutput +CREATE TABLE end_of_life_output ( region TEXT, tech TEXT @@ -237,7 +237,7 @@ CREATE TABLE EndOfLifeOutput notes TEXT, PRIMARY KEY (region, tech, vintage, output_comm) ); -CREATE TABLE Efficiency +CREATE TABLE efficiency ( region TEXT, input_comm TEXT @@ -253,17 +253,17 @@ CREATE TABLE Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO Efficiency VALUES('region','annual','annual',2000,'physical',1.0,NULL); -INSERT INTO Efficiency VALUES('region','annual','annual',2000,'demand',1.0,NULL); -INSERT INTO Efficiency VALUES('region','physical','annual',2000,'demand',1.0,NULL); -INSERT INTO Efficiency VALUES('region','physical','annual',2000,'annual',1.0,NULL); -INSERT INTO Efficiency VALUES('region','source','import',2000,'physical',1.0,NULL); -INSERT INTO Efficiency VALUES('region','source','import',2000,'annual',1.0,NULL); -INSERT INTO Efficiency VALUES('region','annual','non_annual',2000,'physical',1.0,NULL); -INSERT INTO Efficiency VALUES('region','annual','non_annual',2000,'demand',1.0,NULL); -INSERT INTO Efficiency VALUES('region','physical','non_annual',2000,'demand',1.0,NULL); -INSERT INTO Efficiency VALUES('region','physical','non_annual',2000,'annual',1.0,NULL); -CREATE TABLE EfficiencyVariable +INSERT INTO efficiency VALUES('region','annual','annual',2000,'physical',1.0,NULL); +INSERT INTO efficiency VALUES('region','annual','annual',2000,'demand',1.0,NULL); +INSERT INTO efficiency VALUES('region','physical','annual',2000,'demand',1.0,NULL); +INSERT INTO efficiency VALUES('region','physical','annual',2000,'annual',1.0,NULL); +INSERT INTO efficiency VALUES('region','source','import',2000,'physical',1.0,NULL); +INSERT INTO efficiency VALUES('region','source','import',2000,'annual',1.0,NULL); +INSERT INTO efficiency VALUES('region','annual','non_annual',2000,'physical',1.0,NULL); +INSERT INTO efficiency VALUES('region','annual','non_annual',2000,'demand',1.0,NULL); +INSERT INTO efficiency VALUES('region','physical','non_annual',2000,'demand',1.0,NULL); +INSERT INTO efficiency VALUES('region','physical','non_annual',2000,'annual',1.0,NULL); +CREATE TABLE efficiency_variable ( region TEXT, period INTEGER @@ -285,7 +285,7 @@ CREATE TABLE EfficiencyVariable PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -CREATE TABLE EmissionActivity +CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT @@ -303,7 +303,7 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -CREATE TABLE EmissionEmbodied +CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT @@ -317,7 +317,7 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE EmissionEndOfLife +CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT @@ -331,7 +331,7 @@ CREATE TABLE EmissionEndOfLife notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE ExistingCapacity +CREATE TABLE existing_capacity ( region TEXT, tech TEXT @@ -349,7 +349,7 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE LoanLifetimeProcess +CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT @@ -360,9 +360,9 @@ CREATE TABLE LoanLifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO LoanLifetimeProcess VALUES ('region','annual',2000,1,NULL); -INSERT INTO LoanLifetimeProcess VALUES ('region','non_annual',2000,1,NULL); -CREATE TABLE LoanRate +INSERT INTO loan_lifetime_process VALUES ('region','annual',2000,1,NULL); +INSERT INTO loan_lifetime_process VALUES ('region','non_annual',2000,1,NULL); +CREATE TABLE loan_rate ( region TEXT, tech TEXT @@ -373,7 +373,7 @@ CREATE TABLE LoanRate notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeProcess +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -384,7 +384,7 @@ CREATE TABLE LifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeTech +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT @@ -393,8 +393,8 @@ CREATE TABLE LifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO LifetimeTech VALUES ('region', 'annual', 1, NULL); -INSERT INTO LifetimeTech VALUES ('region', 'non_annual', 1, NULL); +INSERT INTO lifetime_tech VALUES ('region', 'annual', 1, NULL); +INSERT INTO lifetime_tech VALUES ('region', 'non_annual', 1, NULL); CREATE TABLE Operator ( operator TEXT PRIMARY KEY, @@ -403,7 +403,7 @@ CREATE TABLE Operator INSERT INTO Operator VALUES('e','equal to'); INSERT INTO Operator VALUES('le','less than or equal to'); INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE LimitGrowthCapacity +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, @@ -415,7 +415,7 @@ CREATE TABLE LimitGrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthCapacity +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, @@ -427,7 +427,7 @@ CREATE TABLE LimitDegrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacity +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -439,7 +439,7 @@ CREATE TABLE LimitGrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -451,7 +451,7 @@ CREATE TABLE LimitDegrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacityDelta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -463,7 +463,7 @@ CREATE TABLE LimitGrowthNewCapacityDelta notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacityDelta +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -494,7 +494,7 @@ CREATE TABLE LimitStorageLevelFraction notes TEXT, PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE LimitActivity +CREATE TABLE limit_activity ( region TEXT, period INTEGER @@ -507,9 +507,9 @@ CREATE TABLE LimitActivity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO LimitActivity VALUES('region',2000,'annual','le',0.5,NULL,NULL); -INSERT INTO LimitActivity VALUES('region',2000,'non_annual','le',0.5,NULL,NULL); -CREATE TABLE LimitActivityShare +INSERT INTO limit_activity VALUES('region',2000,'annual','le',0.5,NULL,NULL); +INSERT INTO limit_activity VALUES('region',2000,'non_annual','le',0.5,NULL,NULL); +CREATE TABLE limit_activity_share ( region TEXT, period INTEGER @@ -522,7 +522,7 @@ CREATE TABLE LimitActivityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitAnnualCapacityFactor +CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER @@ -538,7 +538,7 @@ CREATE TABLE LimitAnnualCapacityFactor PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE LimitCapacity +CREATE TABLE limit_capacity ( region TEXT, period INTEGER @@ -551,7 +551,7 @@ CREATE TABLE LimitCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitCapacityShare +CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER @@ -564,7 +564,7 @@ CREATE TABLE LimitCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitNewCapacity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER @@ -577,7 +577,7 @@ CREATE TABLE LimitNewCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitNewCapacityShare +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -590,7 +590,7 @@ CREATE TABLE LimitNewCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitResource +CREATE TABLE limit_resource ( region TEXT, tech_or_group TEXT, @@ -601,7 +601,7 @@ CREATE TABLE LimitResource notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitSeasonalCapacityFactor +CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES Region (region), @@ -617,7 +617,7 @@ CREATE TABLE LimitSeasonalCapacityFactor notes TEXT, PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE LimitTechInputSplit +CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER @@ -632,7 +632,7 @@ CREATE TABLE LimitTechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechInputSplitAnnual +CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER @@ -647,7 +647,7 @@ CREATE TABLE LimitTechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechOutputSplit +CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER @@ -662,7 +662,7 @@ CREATE TABLE LimitTechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitTechOutputSplitAnnual +CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER @@ -677,7 +677,7 @@ CREATE TABLE LimitTechOutputSplitAnnual notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitEmission +CREATE TABLE limit_emission ( region TEXT, period INTEGER @@ -834,7 +834,7 @@ CREATE TABLE OutputStorageLevel level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); -CREATE TABLE PlanningReserveMargin +CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY @@ -842,7 +842,7 @@ CREATE TABLE PlanningReserveMargin margin REAL, notes TEXT ); -CREATE TABLE RampDownHourly +CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT @@ -851,7 +851,7 @@ CREATE TABLE RampDownHourly notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUpHourly +CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT @@ -867,7 +867,7 @@ CREATE TABLE Region notes TEXT ); INSERT INTO Region VALUES('region',NULL); -CREATE TABLE ReserveCapacityDerate +CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER @@ -883,7 +883,7 @@ CREATE TABLE ReserveCapacityDerate CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE TimeSegmentFraction -( +( period INTEGER REFERENCES TimePeriod (period), season TEXT @@ -896,7 +896,7 @@ CREATE TABLE TimeSegmentFraction CHECK (segfrac >= 0 AND segfrac <= 1) ); INSERT INTO TimeSegmentFraction VALUES(2000,'S1','D1',1.0,NULL); -CREATE TABLE StorageDuration +CREATE TABLE storage_duration ( region TEXT, tech TEXT, @@ -904,7 +904,7 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE LifetimeSurvivalCurve +CREATE TABLE lifetime_survival_curve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -953,7 +953,7 @@ CREATE TABLE TimeSeason PRIMARY KEY (period, sequence, season) ); INSERT INTO TimeSeason VALUES(2000,0,'S1',NULL); -CREATE TABLE TimeSeasonSequential +CREATE TABLE time_season_sequential ( period INTEGER REFERENCES TimePeriod (period), diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 2757828a8..cd9c86349 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -19,7 +19,7 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,'Discount Rate for future costs'); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -44,7 +44,7 @@ CREATE TABLE SectorLabel sector TEXT PRIMARY KEY, notes TEXT ); -CREATE TABLE CapacityCredit +CREATE TABLE capacity_credit ( region TEXT, period INTEGER @@ -57,7 +57,7 @@ CREATE TABLE CapacityCredit PRIMARY KEY (region, period, tech, vintage), CHECK (credit >= 0 AND credit <= 1) ); -CREATE TABLE CapacityFactorProcess +CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER @@ -74,7 +74,7 @@ CREATE TABLE CapacityFactorProcess PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE CapacityFactorTech +CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER @@ -90,10 +90,10 @@ CREATE TABLE CapacityFactorTech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('TestRegion',2000,'S1','TOD1','TechCurtailment',1.0,NULL); -INSERT INTO CapacityFactorTech VALUES('TestRegion',2000,'S1','TOD2','TechCurtailment',0.5,NULL); -INSERT INTO CapacityFactorTech VALUES('TestRegion',2000,'S1','TOD1','TechOrdinary',1.0,NULL); -INSERT INTO CapacityFactorTech VALUES('TestRegion',2000,'S1','TOD2','TechOrdinary',0.5,NULL); +INSERT INTO capacity_factor_tech VALUES('TestRegion',2000,'S1','TOD1','TechCurtailment',1.0,NULL); +INSERT INTO capacity_factor_tech VALUES('TestRegion',2000,'S1','TOD2','TechCurtailment',0.5,NULL); +INSERT INTO capacity_factor_tech VALUES('TestRegion',2000,'S1','TOD1','TechOrdinary',1.0,NULL); +INSERT INTO capacity_factor_tech VALUES('TestRegion',2000,'S1','TOD2','TechOrdinary',0.5,NULL); CREATE TABLE CapacityToActivity ( region TEXT, @@ -142,7 +142,7 @@ INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); INSERT INTO CommodityType VALUES('s','source commodity'); -CREATE TABLE ConstructionInput +CREATE TABLE construction_input ( region TEXT, input_comm TEXT @@ -156,7 +156,7 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -CREATE TABLE CostEmission +CREATE TABLE cost_emission ( region TEXT, period INTEGER @@ -168,9 +168,9 @@ CREATE TABLE CostEmission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -INSERT INTO CostEmission VALUES('TestRegion',2000,'emission',0.6999999999999999556,NULL,NULL); -INSERT INTO CostEmission VALUES('TestRegion',2005,'emission',0.6999999999999999556,NULL,NULL); -CREATE TABLE CostFixed +INSERT INTO cost_emission VALUES('TestRegion',2000,'emission',0.6999999999999999556,NULL,NULL); +INSERT INTO cost_emission VALUES('TestRegion',2005,'emission',0.6999999999999999556,NULL,NULL); +CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -184,7 +184,7 @@ CREATE TABLE CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE CostInvest +CREATE TABLE cost_invest ( region TEXT, tech TEXT @@ -196,7 +196,7 @@ CREATE TABLE CostInvest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE CostVariable +CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -251,7 +251,7 @@ CREATE TABLE DemandSpecificDistribution PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -CREATE TABLE EndOfLifeOutput +CREATE TABLE end_of_life_output ( region TEXT, tech TEXT @@ -265,7 +265,7 @@ CREATE TABLE EndOfLifeOutput notes TEXT, PRIMARY KEY (region, tech, vintage, output_comm) ); -CREATE TABLE Efficiency +CREATE TABLE efficiency ( region TEXT, input_comm TEXT @@ -281,16 +281,16 @@ CREATE TABLE Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO Efficiency VALUES('TestRegion','annual_in','TechAnnual',2000,'annual_out',1.0,NULL); -INSERT INTO Efficiency VALUES('TestRegion','flex_in','TechFlex',2000,'flex_out',1.0,NULL); -INSERT INTO Efficiency VALUES('TestRegion','ordinary_in','TechOrdinary',2000,'ordinary_out',1.0,NULL); -INSERT INTO Efficiency VALUES('TestRegion','curtailment_in','TechCurtailment',2000,'curtailment_out',1.0,NULL); -INSERT INTO Efficiency VALUES('TestRegion','flex_out','TechFlexNull',2000,'flex_null',1.0,NULL); -INSERT INTO Efficiency VALUES('TestRegion','annual_flex_out','TechFlexNull',2000,'annual_flex_null',1.0,NULL); -INSERT INTO Efficiency VALUES('TestRegion','annual_flex_in','TechAnnualFlex',2000,'annual_flex_out',1.0,NULL); -INSERT INTO Efficiency VALUES('TestRegion','embodied_in','TechEmbodied',2000,'embodied_out',1.0,NULL); -INSERT INTO Efficiency VALUES('TestRegion','eol_in','TechEndOfLife',2000,'eol_out',1.0,NULL); -CREATE TABLE EfficiencyVariable +INSERT INTO efficiency VALUES('TestRegion','annual_in','TechAnnual',2000,'annual_out',1.0,NULL); +INSERT INTO efficiency VALUES('TestRegion','flex_in','TechFlex',2000,'flex_out',1.0,NULL); +INSERT INTO efficiency VALUES('TestRegion','ordinary_in','TechOrdinary',2000,'ordinary_out',1.0,NULL); +INSERT INTO efficiency VALUES('TestRegion','curtailment_in','TechCurtailment',2000,'curtailment_out',1.0,NULL); +INSERT INTO efficiency VALUES('TestRegion','flex_out','TechFlexNull',2000,'flex_null',1.0,NULL); +INSERT INTO efficiency VALUES('TestRegion','annual_flex_out','TechFlexNull',2000,'annual_flex_null',1.0,NULL); +INSERT INTO efficiency VALUES('TestRegion','annual_flex_in','TechAnnualFlex',2000,'annual_flex_out',1.0,NULL); +INSERT INTO efficiency VALUES('TestRegion','embodied_in','TechEmbodied',2000,'embodied_out',1.0,NULL); +INSERT INTO efficiency VALUES('TestRegion','eol_in','TechEndOfLife',2000,'eol_out',1.0,NULL); +CREATE TABLE efficiency_variable ( region TEXT, period INTEGER @@ -312,7 +312,7 @@ CREATE TABLE EfficiencyVariable PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -CREATE TABLE EmissionActivity +CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT @@ -330,12 +330,12 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('TestRegion','emission','annual_in','TechAnnual',2000,'annual_out',1.0,NULL,NULL); -INSERT INTO EmissionActivity VALUES('TestRegion','emission','flex_in','TechFlex',2000,'flex_out',1.0,NULL,NULL); -INSERT INTO EmissionActivity VALUES('TestRegion','emission','ordinary_in','TechOrdinary',2000,'ordinary_out',1.0,NULL,NULL); -INSERT INTO EmissionActivity VALUES('TestRegion','emission','curtailment_in','TechCurtailment',2000,'curtailment_out',1.0,NULL,NULL); -INSERT INTO EmissionActivity VALUES('TestRegion','emission','annual_flex_in','TechAnnualFlex',2000,'annual_flex_out',1.0,NULL,NULL); -CREATE TABLE EmissionEmbodied +INSERT INTO emission_activity VALUES('TestRegion','emission','annual_in','TechAnnual',2000,'annual_out',1.0,NULL,NULL); +INSERT INTO emission_activity VALUES('TestRegion','emission','flex_in','TechFlex',2000,'flex_out',1.0,NULL,NULL); +INSERT INTO emission_activity VALUES('TestRegion','emission','ordinary_in','TechOrdinary',2000,'ordinary_out',1.0,NULL,NULL); +INSERT INTO emission_activity VALUES('TestRegion','emission','curtailment_in','TechCurtailment',2000,'curtailment_out',1.0,NULL,NULL); +INSERT INTO emission_activity VALUES('TestRegion','emission','annual_flex_in','TechAnnualFlex',2000,'annual_flex_out',1.0,NULL,NULL); +CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT @@ -349,8 +349,8 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -INSERT INTO EmissionEmbodied VALUES('TestRegion','emission','TechEmbodied',2000,0.5,NULL,NULL); -CREATE TABLE EmissionEndOfLife +INSERT INTO emission_embodied VALUES('TestRegion','emission','TechEmbodied',2000,0.5,NULL,NULL); +CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT @@ -364,8 +364,8 @@ CREATE TABLE EmissionEndOfLife notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -INSERT INTO EmissionEndOfLife VALUES('TestRegion','emission','TechEndOfLife',2000,0.5,NULL,NULL); -CREATE TABLE ExistingCapacity +INSERT INTO emission_end_of_life VALUES('TestRegion','emission','TechEndOfLife',2000,0.5,NULL,NULL); +CREATE TABLE existing_capacity ( region TEXT, tech TEXT @@ -383,7 +383,7 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE LoanLifetimeProcess +CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT @@ -394,7 +394,7 @@ CREATE TABLE LoanLifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LoanRate +CREATE TABLE loan_rate ( region TEXT, tech TEXT @@ -405,7 +405,7 @@ CREATE TABLE LoanRate notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeProcess +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -416,7 +416,7 @@ CREATE TABLE LifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeTech +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT @@ -425,7 +425,7 @@ CREATE TABLE LifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO LifetimeTech VALUES('TestRegion','TechEndOfLife',5.0,NULL); +INSERT INTO lifetime_tech VALUES('TestRegion','TechEndOfLife',5.0,NULL); CREATE TABLE Operator ( operator TEXT PRIMARY KEY, @@ -434,7 +434,7 @@ CREATE TABLE Operator INSERT INTO Operator VALUES('e','equal to'); INSERT INTO Operator VALUES('le','less than or equal to'); INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE LimitGrowthCapacity +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, @@ -446,7 +446,7 @@ CREATE TABLE LimitGrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthCapacity +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, @@ -458,7 +458,7 @@ CREATE TABLE LimitDegrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacity +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -470,7 +470,7 @@ CREATE TABLE LimitGrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -482,7 +482,7 @@ CREATE TABLE LimitDegrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacityDelta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -494,7 +494,7 @@ CREATE TABLE LimitGrowthNewCapacityDelta notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacityDelta +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -525,7 +525,7 @@ CREATE TABLE LimitStorageLevelFraction notes TEXT, PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE LimitActivity +CREATE TABLE limit_activity ( region TEXT, period INTEGER @@ -538,11 +538,11 @@ CREATE TABLE LimitActivity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO LimitActivity VALUES('TestRegion',2000,'TechFlex','ge',1.0,NULL,NULL); -INSERT INTO LimitActivity VALUES('TestRegion',2000,'TechAnnualFlex','ge',1.0,NULL,NULL); -INSERT INTO LimitActivity VALUES('TestRegion',2000,'TechFlex','le',1.0,NULL,NULL); -INSERT INTO LimitActivity VALUES('TestRegion',2000,'TechAnnualFlex','le',1.0,NULL,NULL); -CREATE TABLE LimitActivityShare +INSERT INTO limit_activity VALUES('TestRegion',2000,'TechFlex','ge',1.0,NULL,NULL); +INSERT INTO limit_activity VALUES('TestRegion',2000,'TechAnnualFlex','ge',1.0,NULL,NULL); +INSERT INTO limit_activity VALUES('TestRegion',2000,'TechFlex','le',1.0,NULL,NULL); +INSERT INTO limit_activity VALUES('TestRegion',2000,'TechAnnualFlex','le',1.0,NULL,NULL); +CREATE TABLE limit_activity_share ( region TEXT, period INTEGER @@ -555,7 +555,7 @@ CREATE TABLE LimitActivityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitAnnualCapacityFactor +CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER @@ -571,7 +571,7 @@ CREATE TABLE LimitAnnualCapacityFactor PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE LimitCapacity +CREATE TABLE limit_capacity ( region TEXT, period INTEGER @@ -584,11 +584,11 @@ CREATE TABLE LimitCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO LimitCapacity VALUES('TestRegion',2000,'TechOrdinary','ge',1.0,NULL,NULL); -INSERT INTO LimitCapacity VALUES('TestRegion',2000,'TechCurtailment','ge',1.0,NULL,NULL); -INSERT INTO LimitCapacity VALUES('TestRegion',2000,'TechOrdinary','le',1.0,NULL,NULL); -INSERT INTO LimitCapacity VALUES('TestRegion',2000,'TechCurtailment','le',1.0,NULL,NULL); -CREATE TABLE LimitCapacityShare +INSERT INTO limit_capacity VALUES('TestRegion',2000,'TechOrdinary','ge',1.0,NULL,NULL); +INSERT INTO limit_capacity VALUES('TestRegion',2000,'TechCurtailment','ge',1.0,NULL,NULL); +INSERT INTO limit_capacity VALUES('TestRegion',2000,'TechOrdinary','le',1.0,NULL,NULL); +INSERT INTO limit_capacity VALUES('TestRegion',2000,'TechCurtailment','le',1.0,NULL,NULL); +CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER @@ -601,7 +601,7 @@ CREATE TABLE LimitCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitNewCapacity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER @@ -614,7 +614,7 @@ CREATE TABLE LimitNewCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitNewCapacityShare +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -627,7 +627,7 @@ CREATE TABLE LimitNewCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitResource +CREATE TABLE limit_resource ( region TEXT, tech_or_group TEXT, @@ -638,7 +638,7 @@ CREATE TABLE LimitResource notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitSeasonalCapacityFactor +CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES Region (region), @@ -654,7 +654,7 @@ CREATE TABLE LimitSeasonalCapacityFactor notes TEXT, PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE LimitTechInputSplit +CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER @@ -669,7 +669,7 @@ CREATE TABLE LimitTechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechInputSplitAnnual +CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER @@ -684,7 +684,7 @@ CREATE TABLE LimitTechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechOutputSplit +CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER @@ -699,7 +699,7 @@ CREATE TABLE LimitTechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitTechOutputSplitAnnual +CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER @@ -714,7 +714,7 @@ CREATE TABLE LimitTechOutputSplitAnnual notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitEmission +CREATE TABLE limit_emission ( region TEXT, period INTEGER @@ -871,7 +871,7 @@ CREATE TABLE OutputStorageLevel level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); -CREATE TABLE PlanningReserveMargin +CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY @@ -879,7 +879,7 @@ CREATE TABLE PlanningReserveMargin margin REAL, notes TEXT ); -CREATE TABLE RampDownHourly +CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT @@ -888,7 +888,7 @@ CREATE TABLE RampDownHourly notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUpHourly +CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT @@ -904,7 +904,7 @@ CREATE TABLE Region notes TEXT ); INSERT INTO Region VALUES('TestRegion',NULL); -CREATE TABLE ReserveCapacityDerate +CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER @@ -920,7 +920,7 @@ CREATE TABLE ReserveCapacityDerate CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE TimeSegmentFraction -( +( period INTEGER REFERENCES TimePeriod (period), season TEXT @@ -936,7 +936,7 @@ INSERT INTO TimeSegmentFraction VALUES(2000,'S1','TOD1',0.5,NULL); INSERT INTO TimeSegmentFraction VALUES(2000,'S1','TOD2',0.5,NULL); INSERT INTO TimeSegmentFraction VALUES(2005,'S1','TOD1',0.5,NULL); INSERT INTO TimeSegmentFraction VALUES(2005,'S1','TOD2',0.5,NULL); -CREATE TABLE StorageDuration +CREATE TABLE storage_duration ( region TEXT, tech TEXT, @@ -944,7 +944,7 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE LifetimeSurvivalCurve +CREATE TABLE lifetime_survival_curve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -997,7 +997,7 @@ CREATE TABLE TimeSeason ); INSERT INTO TimeSeason VALUES(2000,1,'S1',NULL); INSERT INTO TimeSeason VALUES(2005,1,'S1',NULL); -CREATE TABLE TimeSeasonSequential +CREATE TABLE time_season_sequential ( period INTEGER REFERENCES TimePeriod (period), diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index d77376460..596efc87c 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -19,7 +19,7 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,'Discount Rate for future costs'); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -47,7 +47,7 @@ CREATE TABLE SectorLabel sector TEXT PRIMARY KEY, notes TEXT ); -CREATE TABLE CapacityCredit +CREATE TABLE capacity_credit ( region TEXT, period INTEGER @@ -60,7 +60,7 @@ CREATE TABLE CapacityCredit PRIMARY KEY (region, period, tech, vintage), CHECK (credit >= 0 AND credit <= 1) ); -CREATE TABLE CapacityFactorProcess +CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER @@ -77,7 +77,7 @@ CREATE TABLE CapacityFactorProcess PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE CapacityFactorTech +CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER @@ -93,102 +93,102 @@ CREATE TABLE CapacityFactorTech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2000,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2010,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionA',2020,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2000,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2010,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO CapacityFactorTech VALUES('RegionB',2020,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'spring','overnight','SOL_PV',0.0,NULL); CREATE TABLE CapacityToActivity ( region TEXT, @@ -235,7 +235,7 @@ INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); INSERT INTO CommodityType VALUES('s','source commodity'); -CREATE TABLE ConstructionInput +CREATE TABLE construction_input ( region TEXT, input_comm TEXT @@ -249,19 +249,19 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -INSERT INTO ConstructionInput VALUES('RegionA','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionA','battery_lfp','CAR_PHEV',2000,0.1000000000000000055,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionA','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionA','battery_lfp','CAR_PHEV',2010,0.1000000000000000055,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionA','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionA','battery_lfp','CAR_PHEV',2020,0.1000000000000000055,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionB','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionB','battery_lfp','CAR_PHEV',2000,0.1000000000000000055,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionB','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionB','battery_lfp','CAR_PHEV',2010,0.1000000000000000055,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionB','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO ConstructionInput VALUES('RegionB','battery_lfp','CAR_PHEV',2020,0.1000000000000000055,NULL,NULL); -CREATE TABLE CostEmission +INSERT INTO construction_input VALUES('RegionA','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO construction_input VALUES('RegionA','battery_lfp','CAR_PHEV',2000,0.1000000000000000055,NULL,NULL); +INSERT INTO construction_input VALUES('RegionA','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO construction_input VALUES('RegionA','battery_lfp','CAR_PHEV',2010,0.1000000000000000055,NULL,NULL); +INSERT INTO construction_input VALUES('RegionA','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO construction_input VALUES('RegionA','battery_lfp','CAR_PHEV',2020,0.1000000000000000055,NULL,NULL); +INSERT INTO construction_input VALUES('RegionB','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO construction_input VALUES('RegionB','battery_lfp','CAR_PHEV',2000,0.1000000000000000055,NULL,NULL); +INSERT INTO construction_input VALUES('RegionB','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO construction_input VALUES('RegionB','battery_lfp','CAR_PHEV',2010,0.1000000000000000055,NULL,NULL); +INSERT INTO construction_input VALUES('RegionB','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO construction_input VALUES('RegionB','battery_lfp','CAR_PHEV',2020,0.1000000000000000055,NULL,NULL); +CREATE TABLE cost_emission ( region TEXT, period INTEGER @@ -273,13 +273,13 @@ CREATE TABLE CostEmission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -INSERT INTO CostEmission VALUES('RegionA',2000,'co2e',1.0,NULL,NULL); -INSERT INTO CostEmission VALUES('RegionA',2010,'co2e',1.0,NULL,NULL); -INSERT INTO CostEmission VALUES('RegionA',2020,'co2e',1.0,NULL,NULL); -INSERT INTO CostEmission VALUES('RegionB',2000,'co2e',1.0,NULL,NULL); -INSERT INTO CostEmission VALUES('RegionB',2010,'co2e',1.0,NULL,NULL); -INSERT INTO CostEmission VALUES('RegionB',2020,'co2e',1.0,NULL,NULL); -CREATE TABLE CostFixed +INSERT INTO cost_emission VALUES('RegionA',2000,'co2e',1.0,NULL,NULL); +INSERT INTO cost_emission VALUES('RegionA',2010,'co2e',1.0,NULL,NULL); +INSERT INTO cost_emission VALUES('RegionA',2020,'co2e',1.0,NULL,NULL); +INSERT INTO cost_emission VALUES('RegionB',2000,'co2e',1.0,NULL,NULL); +INSERT INTO cost_emission VALUES('RegionB',2010,'co2e',1.0,NULL,NULL); +INSERT INTO cost_emission VALUES('RegionB',2020,'co2e',1.0,NULL,NULL); +CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -293,7 +293,7 @@ CREATE TABLE CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE CostInvest +CREATE TABLE cost_invest ( region TEXT, tech TEXT @@ -305,41 +305,41 @@ CREATE TABLE CostInvest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO CostInvest VALUES('RegionA','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','CAR_PHEV',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','CAR_PHEV',2010,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','CAR_PHEV',2020,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','CAR_ICE',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','CAR_ICE',2010,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','CAR_ICE',2020,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','RECYCLE_NMC',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','RECYCLE_LFP',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','MANUFAC_NMC',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','MANUFAC_LFP',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','BATT_GRID',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','SOL_PV',2000,10.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA','GEN_DSL',2000,2.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','CAR_PHEV',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','CAR_PHEV',2010,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','CAR_PHEV',2020,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','CAR_ICE',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','CAR_ICE',2010,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','CAR_ICE',2020,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','RECYCLE_NMC',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','RECYCLE_LFP',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','MANUFAC_NMC',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','MANUFAC_LFP',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','BATT_GRID',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','GEN_DSL',2000,2.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionA-RegionB','ELEC_INTERTIE',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB-RegionA','ELEC_INTERTIE',2000,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('RegionB','SOL_PV',2000,1.0,NULL,NULL); -CREATE TABLE CostVariable +INSERT INTO cost_invest VALUES('RegionA','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','CAR_PHEV',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','CAR_PHEV',2010,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','CAR_PHEV',2020,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','CAR_ICE',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','CAR_ICE',2010,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','CAR_ICE',2020,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','RECYCLE_NMC',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','RECYCLE_LFP',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','MANUFAC_NMC',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','MANUFAC_LFP',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','BATT_GRID',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','SOL_PV',2000,10.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA','GEN_DSL',2000,2.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','CAR_PHEV',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','CAR_PHEV',2010,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','CAR_PHEV',2020,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','CAR_ICE',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','CAR_ICE',2010,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','CAR_ICE',2020,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','RECYCLE_NMC',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','RECYCLE_LFP',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','MANUFAC_NMC',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','MANUFAC_LFP',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','BATT_GRID',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','GEN_DSL',2000,2.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionA-RegionB','ELEC_INTERTIE',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB-RegionA','ELEC_INTERTIE',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('RegionB','SOL_PV',2000,1.0,NULL,NULL); +CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -353,42 +353,42 @@ CREATE TABLE CostVariable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostVariable VALUES('RegionA',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2000,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2010,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2020,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2000,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2010,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2020,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2000,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2010,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2020,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2000,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2010,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2020,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionA',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2000,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2010,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2020,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2000,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2010,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2020,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2000,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2010,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2020,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2000,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2010,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2020,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO CostVariable VALUES('RegionB',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2000,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2010,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2020,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2000,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2010,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2020,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2000,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2010,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2020,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2000,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2010,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2020,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionA',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2000,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2010,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2020,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2000,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2010,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2020,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2000,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2010,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2020,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2000,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2010,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2020,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO cost_variable VALUES('RegionB',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); CREATE TABLE Demand ( region TEXT, @@ -525,7 +525,7 @@ INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'summer','overnight INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','overnight','heating',0.1199999999999999956,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','overnight','heating',0.1600000000000000033,NULL); INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'spring','overnight','heating',0.0,NULL); -CREATE TABLE EndOfLifeOutput +CREATE TABLE end_of_life_output ( region TEXT, tech TEXT @@ -539,37 +539,37 @@ CREATE TABLE EndOfLifeOutput notes TEXT, PRIMARY KEY (region, tech, vintage, output_comm) ); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',1990,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2000,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2010,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',1990,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2000,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2010,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionA','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO EndOfLifeOutput VALUES('RegionB','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); -CREATE TABLE Efficiency +INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',1990,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',2000,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',2010,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',1990,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',2000,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',2010,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); +CREATE TABLE efficiency ( region TEXT, input_comm TEXT @@ -585,85 +585,85 @@ CREATE TABLE Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO Efficiency VALUES('RegionA','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2000000000000000111,NULL); -INSERT INTO Efficiency VALUES('RegionA','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2000000000000000111,NULL); -INSERT INTO Efficiency VALUES('RegionA','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','electricity','RECYCLE_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); -INSERT INTO Efficiency VALUES('RegionA','electricity','RECYCLE_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); -INSERT INTO Efficiency VALUES('RegionA','electricity','MANUFAC_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); -INSERT INTO Efficiency VALUES('RegionA','electricity','MANUFAC_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); -INSERT INTO Efficiency VALUES('RegionA','diesel','GEN_DSL',2000,'electricity',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','ethos','SOL_PV',2000,'electricity',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','electricity','BATT_GRID',2000,'electricity',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','diesel','FURNACE',2000,'heating',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','electricity','HEATPUMP',2000,'heating',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2000000000000000111,NULL); -INSERT INTO Efficiency VALUES('RegionB','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2000000000000000111,NULL); -INSERT INTO Efficiency VALUES('RegionB','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','electricity','RECYCLE_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); -INSERT INTO Efficiency VALUES('RegionB','electricity','RECYCLE_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); -INSERT INTO Efficiency VALUES('RegionB','electricity','MANUFAC_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); -INSERT INTO Efficiency VALUES('RegionB','electricity','MANUFAC_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); -INSERT INTO Efficiency VALUES('RegionB','diesel','GEN_DSL',2000,'electricity',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','ethos','SOL_PV',2000,'electricity',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','electricity','BATT_GRID',2000,'electricity',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','diesel','FURNACE',2000,'heating',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','electricity','HEATPUMP',2000,'heating',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionB','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); -INSERT INTO Efficiency VALUES('RegionA-RegionB','electricity','ELEC_INTERTIE',2000,'electricity',0.9000000000000000222,NULL); -INSERT INTO Efficiency VALUES('RegionB-RegionA','electricity','ELEC_INTERTIE',2000,'electricity',0.9000000000000000222,NULL); -CREATE TABLE EfficiencyVariable +INSERT INTO efficiency VALUES('RegionA','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2000000000000000111,NULL); +INSERT INTO efficiency VALUES('RegionA','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2000000000000000111,NULL); +INSERT INTO efficiency VALUES('RegionA','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','electricity','RECYCLE_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('RegionA','electricity','RECYCLE_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('RegionA','electricity','MANUFAC_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('RegionA','electricity','MANUFAC_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('RegionA','diesel','GEN_DSL',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','ethos','SOL_PV',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','electricity','BATT_GRID',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','diesel','FURNACE',2000,'heating',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','electricity','HEATPUMP',2000,'heating',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2000000000000000111,NULL); +INSERT INTO efficiency VALUES('RegionB','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2000000000000000111,NULL); +INSERT INTO efficiency VALUES('RegionB','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','electricity','RECYCLE_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('RegionB','electricity','RECYCLE_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('RegionB','electricity','MANUFAC_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('RegionB','electricity','MANUFAC_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('RegionB','diesel','GEN_DSL',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','ethos','SOL_PV',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','electricity','BATT_GRID',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','diesel','FURNACE',2000,'heating',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','electricity','HEATPUMP',2000,'heating',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionB','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('RegionA-RegionB','electricity','ELEC_INTERTIE',2000,'electricity',0.9000000000000000222,NULL); +INSERT INTO efficiency VALUES('RegionB-RegionA','electricity','ELEC_INTERTIE',2000,'electricity',0.9000000000000000222,NULL); +CREATE TABLE efficiency_variable ( region TEXT, period INTEGER @@ -685,7 +685,7 @@ CREATE TABLE EfficiencyVariable PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -CREATE TABLE EmissionActivity +CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT @@ -703,9 +703,9 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('RegionA','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); -INSERT INTO EmissionActivity VALUES('RegionB','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); -CREATE TABLE EmissionEmbodied +INSERT INTO emission_activity VALUES('RegionA','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); +INSERT INTO emission_activity VALUES('RegionB','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); +CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT @@ -719,7 +719,7 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE EmissionEndOfLife +CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT @@ -733,7 +733,7 @@ CREATE TABLE EmissionEndOfLife notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE ExistingCapacity +CREATE TABLE existing_capacity ( region TEXT, tech TEXT @@ -745,19 +745,19 @@ CREATE TABLE ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO ExistingCapacity VALUES('RegionA','CAR_BEV',1990,1.0,NULL,NULL); -INSERT INTO ExistingCapacity VALUES('RegionA','CAR_PHEV',1990,1.0,NULL,NULL); -INSERT INTO ExistingCapacity VALUES('RegionA','CAR_ICE',1990,1.0,NULL,NULL); -INSERT INTO ExistingCapacity VALUES('RegionB','CAR_BEV',1990,1.0,NULL,NULL); -INSERT INTO ExistingCapacity VALUES('RegionB','CAR_PHEV',1990,1.0,NULL,NULL); -INSERT INTO ExistingCapacity VALUES('RegionB','CAR_ICE',1990,1.0,NULL,NULL); +INSERT INTO existing_capacity VALUES('RegionA','CAR_BEV',1990,1.0,NULL,NULL); +INSERT INTO existing_capacity VALUES('RegionA','CAR_PHEV',1990,1.0,NULL,NULL); +INSERT INTO existing_capacity VALUES('RegionA','CAR_ICE',1990,1.0,NULL,NULL); +INSERT INTO existing_capacity VALUES('RegionB','CAR_BEV',1990,1.0,NULL,NULL); +INSERT INTO existing_capacity VALUES('RegionB','CAR_PHEV',1990,1.0,NULL,NULL); +INSERT INTO existing_capacity VALUES('RegionB','CAR_ICE',1990,1.0,NULL,NULL); CREATE TABLE TechGroup ( group_name TEXT PRIMARY KEY, notes TEXT ); -CREATE TABLE LoanLifetimeProcess +CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT @@ -768,7 +768,7 @@ CREATE TABLE LoanLifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LoanRate +CREATE TABLE loan_rate ( region TEXT, tech TEXT @@ -779,7 +779,7 @@ CREATE TABLE LoanRate notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeProcess +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -790,7 +790,7 @@ CREATE TABLE LifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeTech +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT @@ -799,12 +799,12 @@ CREATE TABLE LifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO LifetimeTech VALUES('RegionA','CAR_BEV',10.0,NULL); -INSERT INTO LifetimeTech VALUES('RegionA','CAR_PHEV',10.0,NULL); -INSERT INTO LifetimeTech VALUES('RegionA','CAR_ICE',10.0,NULL); -INSERT INTO LifetimeTech VALUES('RegionB','CAR_BEV',10.0,NULL); -INSERT INTO LifetimeTech VALUES('RegionB','CAR_PHEV',10.0,NULL); -INSERT INTO LifetimeTech VALUES('RegionB','CAR_ICE',10.0,NULL); +INSERT INTO lifetime_tech VALUES('RegionA','CAR_BEV',10.0,NULL); +INSERT INTO lifetime_tech VALUES('RegionA','CAR_PHEV',10.0,NULL); +INSERT INTO lifetime_tech VALUES('RegionA','CAR_ICE',10.0,NULL); +INSERT INTO lifetime_tech VALUES('RegionB','CAR_BEV',10.0,NULL); +INSERT INTO lifetime_tech VALUES('RegionB','CAR_PHEV',10.0,NULL); +INSERT INTO lifetime_tech VALUES('RegionB','CAR_ICE',10.0,NULL); CREATE TABLE Operator ( operator TEXT PRIMARY KEY, @@ -813,7 +813,7 @@ CREATE TABLE Operator INSERT INTO Operator VALUES('e','equal to'); INSERT INTO Operator VALUES('le','less than or equal to'); INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE LimitGrowthCapacity +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, @@ -825,7 +825,7 @@ CREATE TABLE LimitGrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthCapacity +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, @@ -837,7 +837,7 @@ CREATE TABLE LimitDegrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacity +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -849,7 +849,7 @@ CREATE TABLE LimitGrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -861,7 +861,7 @@ CREATE TABLE LimitDegrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacityDelta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -873,7 +873,7 @@ CREATE TABLE LimitGrowthNewCapacityDelta notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacityDelta +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -904,7 +904,7 @@ CREATE TABLE LimitStorageLevelFraction notes TEXT, PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE LimitActivity +CREATE TABLE limit_activity ( region TEXT, period INTEGER @@ -917,7 +917,7 @@ CREATE TABLE LimitActivity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitActivityShare +CREATE TABLE limit_activity_share ( region TEXT, period INTEGER @@ -930,7 +930,7 @@ CREATE TABLE LimitActivityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitAnnualCapacityFactor +CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER @@ -946,7 +946,7 @@ CREATE TABLE LimitAnnualCapacityFactor PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE LimitCapacity +CREATE TABLE limit_capacity ( region TEXT, period INTEGER @@ -959,7 +959,7 @@ CREATE TABLE LimitCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitCapacityShare +CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER @@ -972,7 +972,7 @@ CREATE TABLE LimitCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitNewCapacity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER @@ -985,7 +985,7 @@ CREATE TABLE LimitNewCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitNewCapacityShare +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -998,7 +998,7 @@ CREATE TABLE LimitNewCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitResource +CREATE TABLE limit_resource ( region TEXT, tech_or_group TEXT, @@ -1009,7 +1009,7 @@ CREATE TABLE LimitResource notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitSeasonalCapacityFactor +CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES Region (region), @@ -1025,7 +1025,7 @@ CREATE TABLE LimitSeasonalCapacityFactor notes TEXT, PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE LimitTechInputSplit +CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER @@ -1040,7 +1040,7 @@ CREATE TABLE LimitTechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechInputSplitAnnual +CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER @@ -1055,61 +1055,61 @@ CREATE TABLE LimitTechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2000,'diesel','CAR_PHEV','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2010,'diesel','CAR_PHEV','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionA',2020,'diesel','CAR_PHEV','le',0.8000000000000000444,NULL); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2000,'diesel','CAR_PHEV','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2010,'diesel','CAR_PHEV','le',0.8000000000000000444,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO LimitTechInputSplitAnnual VALUES('RegionB',2020,'diesel','CAR_PHEV','le',0.8000000000000000444,NULL); -CREATE TABLE LimitTechOutputSplit +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'diesel','CAR_PHEV','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'diesel','CAR_PHEV','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'diesel','CAR_PHEV','le',0.8000000000000000444,NULL); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'diesel','CAR_PHEV','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'diesel','CAR_PHEV','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'diesel','CAR_PHEV','le',0.8000000000000000444,NULL); +CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER @@ -1124,7 +1124,7 @@ CREATE TABLE LimitTechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitTechOutputSplitAnnual +CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER @@ -1139,7 +1139,7 @@ CREATE TABLE LimitTechOutputSplitAnnual notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitEmission +CREATE TABLE limit_emission ( region TEXT, period INTEGER @@ -1296,7 +1296,7 @@ CREATE TABLE OutputStorageLevel level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); -CREATE TABLE PlanningReserveMargin +CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY @@ -1304,7 +1304,7 @@ CREATE TABLE PlanningReserveMargin margin REAL, notes TEXT ); -CREATE TABLE RampDownHourly +CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT @@ -1313,7 +1313,7 @@ CREATE TABLE RampDownHourly notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUpHourly +CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT @@ -1330,7 +1330,7 @@ CREATE TABLE Region ); INSERT INTO Region VALUES('RegionA',NULL); INSERT INTO Region VALUES('RegionB',NULL); -CREATE TABLE ReserveCapacityDerate +CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER @@ -1346,7 +1346,7 @@ CREATE TABLE ReserveCapacityDerate CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE TimeSegmentFraction -( +( period INTEGER REFERENCES TimePeriod (period), season TEXT @@ -1406,7 +1406,7 @@ INSERT INTO TimeSegmentFraction VALUES(2020,'summer','overnight',0.0625,NULL); INSERT INTO TimeSegmentFraction VALUES(2020,'autumn','overnight',0.0625,NULL); INSERT INTO TimeSegmentFraction VALUES(2020,'winter','overnight',0.0625,NULL); INSERT INTO TimeSegmentFraction VALUES(2020,'spring','overnight',0.0625,NULL); -CREATE TABLE StorageDuration +CREATE TABLE storage_duration ( region TEXT, tech TEXT, @@ -1414,9 +1414,9 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO StorageDuration VALUES('RegionA','BATT_GRID',2.0,'2 hours energy storage'); -INSERT INTO StorageDuration VALUES('RegionB','BATT_GRID',2.0,'2 hours energy storage'); -CREATE TABLE LifetimeSurvivalCurve +INSERT INTO storage_duration VALUES('RegionA','BATT_GRID',2.0,'2 hours energy storage'); +INSERT INTO storage_duration VALUES('RegionB','BATT_GRID',2.0,'2 hours energy storage'); +CREATE TABLE lifetime_survival_curve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -1482,7 +1482,7 @@ INSERT INTO TimeSeason VALUES(2020,9,'summer',NULL); INSERT INTO TimeSeason VALUES(2020,10,'autumn',NULL); INSERT INTO TimeSeason VALUES(2020,11,'winter',NULL); INSERT INTO TimeSeason VALUES(2020,12,'spring',NULL); -CREATE TABLE TimeSeasonSequential +CREATE TABLE time_season_sequential ( period INTEGER REFERENCES TimePeriod (period), diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 9fff3b221..a0f587022 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -18,7 +18,7 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); INSERT INTO MetaDataReal VALUES('global_discount_rate',0.42000000000000004,''); CREATE TABLE OutputDualVariable ( @@ -51,7 +51,7 @@ INSERT INTO SectorLabel VALUES('transport',NULL); INSERT INTO SectorLabel VALUES('commercial',NULL); INSERT INTO SectorLabel VALUES('residential',NULL); INSERT INTO SectorLabel VALUES('industrial',NULL); -CREATE TABLE CapacityCredit +CREATE TABLE capacity_credit ( region TEXT, period INTEGER @@ -64,8 +64,8 @@ CREATE TABLE CapacityCredit PRIMARY KEY (region, period, tech, vintage), CHECK (credit >= 0 AND credit <= 1) ); -INSERT INTO CapacityCredit VALUES('A',2025,'EF',2025,0.5999999999999999778,NULL); -CREATE TABLE CapacityFactorProcess +INSERT INTO capacity_credit VALUES('A',2025,'EF',2025,0.5999999999999999778,NULL); +CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER @@ -82,9 +82,9 @@ CREATE TABLE CapacityFactorProcess PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorProcess VALUES('A',2025,'s2','d1','EFL',2025,0.8000000000000000444,NULL); -INSERT INTO CapacityFactorProcess VALUES('A',2025,'s1','d2','EFL',2025,0.9000000000000000222,NULL); -CREATE TABLE CapacityFactorTech +INSERT INTO capacity_factor_process VALUES('A',2025,'s2','d1','EFL',2025,0.8000000000000000444,NULL); +INSERT INTO capacity_factor_process VALUES('A',2025,'s1','d2','EFL',2025,0.9000000000000000222,NULL); +CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER @@ -100,8 +100,8 @@ CREATE TABLE CapacityFactorTech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('A',2025,'s1','d1','EF',0.8000000000000000444,NULL); -INSERT INTO CapacityFactorTech VALUES('B',2025,'s2','d2','bulbs',0.75,NULL); +INSERT INTO capacity_factor_tech VALUES('A',2025,'s1','d1','EF',0.8000000000000000444,NULL); +INSERT INTO capacity_factor_tech VALUES('B',2025,'s2','d2','bulbs',0.75,NULL); CREATE TABLE CapacityToActivity ( region TEXT, @@ -144,7 +144,7 @@ INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); INSERT INTO CommodityType VALUES('s','source commodity'); -CREATE TABLE ConstructionInput +CREATE TABLE construction_input ( region TEXT, input_comm TEXT @@ -158,7 +158,7 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -CREATE TABLE CostEmission +CREATE TABLE cost_emission ( region TEXT, period INTEGER @@ -170,8 +170,8 @@ CREATE TABLE CostEmission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -INSERT INTO CostEmission VALUES('A',2025,'co2',1.989999999999999992,'dollars','none'); -CREATE TABLE CostFixed +INSERT INTO cost_emission VALUES('A',2025,'co2',1.989999999999999992,'dollars','none'); +CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -185,21 +185,21 @@ CREATE TABLE CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostFixed VALUES('A',2025,'EH',2025,3.299999999999999823,'',''); -INSERT INTO CostFixed VALUES('A',2025,'EF',2025,2.0,NULL,NULL); -INSERT INTO CostFixed VALUES('A',2025,'EFL',2025,3.0,NULL,NULL); -INSERT INTO CostFixed VALUES('B',2025,'batt',2025,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('B',2025,'EF',2025,2.0,NULL,NULL); -INSERT INTO CostFixed VALUES('A',2025,'bulbs',2025,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('B',2025,'bulbs',2025,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('A',2025,'heater',2025,2.0,NULL,NULL); -INSERT INTO CostFixed VALUES('B',2025,'heater',2025,2.0,NULL,NULL); -INSERT INTO CostFixed VALUES('B',2025,'GeoThermal',2025,6.0,NULL,NULL); -INSERT INTO CostFixed VALUES('B',2025,'GeoHeater',2025,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('B',2025,'EH',2025,3.299999999999999823,NULL,NULL); -INSERT INTO CostFixed VALUES('A',2025,'GeoThermal',2025,4.0,NULL,NULL); -INSERT INTO CostFixed VALUES('A',2025,'GeoHeater',2025,4.5,NULL,NULL); -CREATE TABLE CostInvest +INSERT INTO cost_fixed VALUES('A',2025,'EH',2025,3.299999999999999823,'',''); +INSERT INTO cost_fixed VALUES('A',2025,'EF',2025,2.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('A',2025,'EFL',2025,3.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('B',2025,'batt',2025,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('B',2025,'EF',2025,2.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('A',2025,'bulbs',2025,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('B',2025,'bulbs',2025,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('A',2025,'heater',2025,2.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('B',2025,'heater',2025,2.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('B',2025,'GeoThermal',2025,6.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('B',2025,'GeoHeater',2025,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('B',2025,'EH',2025,3.299999999999999823,NULL,NULL); +INSERT INTO cost_fixed VALUES('A',2025,'GeoThermal',2025,4.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('A',2025,'GeoHeater',2025,4.5,NULL,NULL); +CREATE TABLE cost_invest ( region TEXT, tech TEXT @@ -211,21 +211,21 @@ CREATE TABLE CostInvest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO CostInvest VALUES('A','EF',2025,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('A','EH',2025,3.0,NULL,NULL); -INSERT INTO CostInvest VALUES('A','bulbs',2025,4.0,NULL,NULL); -INSERT INTO CostInvest VALUES('A','heater',2025,5.0,NULL,NULL); -INSERT INTO CostInvest VALUES('B','EF',2025,6.0,NULL,NULL); -INSERT INTO CostInvest VALUES('B','batt',2025,7.0,NULL,NULL); -INSERT INTO CostInvest VALUES('B','bulbs',2025,8.0,NULL,NULL); -INSERT INTO CostInvest VALUES('B','heater',2025,9.0,NULL,NULL); -INSERT INTO CostInvest VALUES('A','EFL',2025,2.0,NULL,NULL); -INSERT INTO CostInvest VALUES('B','GeoThermal',2025,3.0,NULL,NULL); -INSERT INTO CostInvest VALUES('B','GeoHeater',2025,4.0,NULL,NULL); -INSERT INTO CostInvest VALUES('B','EH',2025,3.299999999999999823,NULL,NULL); -INSERT INTO CostInvest VALUES('A','GeoThermal',2025,5.599999999999999645,NULL,NULL); -INSERT INTO CostInvest VALUES('A','GeoHeater',2025,4.200000000000000177,NULL,NULL); -CREATE TABLE CostVariable +INSERT INTO cost_invest VALUES('A','EF',2025,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('A','EH',2025,3.0,NULL,NULL); +INSERT INTO cost_invest VALUES('A','bulbs',2025,4.0,NULL,NULL); +INSERT INTO cost_invest VALUES('A','heater',2025,5.0,NULL,NULL); +INSERT INTO cost_invest VALUES('B','EF',2025,6.0,NULL,NULL); +INSERT INTO cost_invest VALUES('B','batt',2025,7.0,NULL,NULL); +INSERT INTO cost_invest VALUES('B','bulbs',2025,8.0,NULL,NULL); +INSERT INTO cost_invest VALUES('B','heater',2025,9.0,NULL,NULL); +INSERT INTO cost_invest VALUES('A','EFL',2025,2.0,NULL,NULL); +INSERT INTO cost_invest VALUES('B','GeoThermal',2025,3.0,NULL,NULL); +INSERT INTO cost_invest VALUES('B','GeoHeater',2025,4.0,NULL,NULL); +INSERT INTO cost_invest VALUES('B','EH',2025,3.299999999999999823,NULL,NULL); +INSERT INTO cost_invest VALUES('A','GeoThermal',2025,5.599999999999999645,NULL,NULL); +INSERT INTO cost_invest VALUES('A','GeoHeater',2025,4.200000000000000177,NULL,NULL); +CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -239,15 +239,15 @@ CREATE TABLE CostVariable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostVariable VALUES('A',2025,'EF',2025,9.0,NULL,NULL); -INSERT INTO CostVariable VALUES('A',2025,'EFL',2025,8.0,NULL,NULL); -INSERT INTO CostVariable VALUES('A',2025,'EH',2025,7.0,NULL,NULL); -INSERT INTO CostVariable VALUES('A',2025,'bulbs',2025,6.0,NULL,NULL); -INSERT INTO CostVariable VALUES('A',2025,'heater',2025,5.0,NULL,NULL); -INSERT INTO CostVariable VALUES('B',2025,'EF',2025,4.0,NULL,NULL); -INSERT INTO CostVariable VALUES('B',2025,'batt',2025,3.0,NULL,NULL); -INSERT INTO CostVariable VALUES('B',2025,'bulbs',2025,2.0,NULL,NULL); -INSERT INTO CostVariable VALUES('B',2025,'heater',2025,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('A',2025,'EF',2025,9.0,NULL,NULL); +INSERT INTO cost_variable VALUES('A',2025,'EFL',2025,8.0,NULL,NULL); +INSERT INTO cost_variable VALUES('A',2025,'EH',2025,7.0,NULL,NULL); +INSERT INTO cost_variable VALUES('A',2025,'bulbs',2025,6.0,NULL,NULL); +INSERT INTO cost_variable VALUES('A',2025,'heater',2025,5.0,NULL,NULL); +INSERT INTO cost_variable VALUES('B',2025,'EF',2025,4.0,NULL,NULL); +INSERT INTO cost_variable VALUES('B',2025,'batt',2025,3.0,NULL,NULL); +INSERT INTO cost_variable VALUES('B',2025,'bulbs',2025,2.0,NULL,NULL); +INSERT INTO cost_variable VALUES('B',2025,'heater',2025,1.0,NULL,NULL); CREATE TABLE Demand ( region TEXT, @@ -296,7 +296,7 @@ INSERT INTO DemandSpecificDistribution VALUES('A',2025,'s1','d2','RH',0.25,NULL) INSERT INTO DemandSpecificDistribution VALUES('A',2025,'s2','d2','RH',0.25,NULL); INSERT INTO DemandSpecificDistribution VALUES('B',2025,'s1','d2','RH',0.25,NULL); INSERT INTO DemandSpecificDistribution VALUES('B',2025,'s2','d2','RH',0.25,NULL); -CREATE TABLE EndOfLifeOutput +CREATE TABLE end_of_life_output ( region TEXT, tech TEXT @@ -310,7 +310,7 @@ CREATE TABLE EndOfLifeOutput notes TEXT, PRIMARY KEY (region, tech, vintage, output_comm) ); -CREATE TABLE Efficiency +CREATE TABLE efficiency ( region TEXT, input_comm TEXT @@ -326,25 +326,25 @@ CREATE TABLE Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO Efficiency VALUES('A','ELC','bulbs',2025,'RL',1.0,NULL); -INSERT INTO Efficiency VALUES('A','HYD','EH',2025,'ELC',1.0,NULL); -INSERT INTO Efficiency VALUES('A','HYD','EF',2025,'ELC',1.0,NULL); -INSERT INTO Efficiency VALUES('B','ELC','bulbs',2025,'RL',1.0,NULL); -INSERT INTO Efficiency VALUES('B','HYD','EH',2025,'ELC',1.0,NULL); -INSERT INTO Efficiency VALUES('B','ELC','batt',2025,'ELC',1.0,NULL); -INSERT INTO Efficiency VALUES('B','HYD','EF',2025,'ELC',1.0,NULL); -INSERT INTO Efficiency VALUES('A','earth','well',2025,'HYD',1.0,NULL); -INSERT INTO Efficiency VALUES('B','earth','well',2025,'HYD',1.0,NULL); -INSERT INTO Efficiency VALUES('A','earth','EFL',2025,'FusionGasFuel',1.0,NULL); -INSERT INTO Efficiency VALUES('A','FusionGasFuel','heater',2025,'RH',0.9000000000000000222,NULL); -INSERT INTO Efficiency VALUES('A-B','FusionGasFuel','FGF_pipe',2025,'FusionGasFuel',0.949999999999999956,NULL); -INSERT INTO Efficiency VALUES('B','FusionGasFuel','heater',2025,'RH',0.9000000000000000222,NULL); -INSERT INTO Efficiency VALUES('B','GeoHyd','GeoHeater',2025,'RH',0.980000000000000094,NULL); -INSERT INTO Efficiency VALUES('B','earth','GeoThermal',2025,'GeoHyd',1.0,NULL); -INSERT INTO Efficiency VALUES('B-A','FusionGasFuel','FGF_pipe',2025,'FusionGasFuel',0.949999999999999956,NULL); -INSERT INTO Efficiency VALUES('A','GeoHyd','GeoHeater',2025,'RH',0.9000000000000000222,NULL); -INSERT INTO Efficiency VALUES('A','earth','GeoThermal',2025,'GeoHyd',1.0,NULL); -CREATE TABLE EfficiencyVariable +INSERT INTO efficiency VALUES('A','ELC','bulbs',2025,'RL',1.0,NULL); +INSERT INTO efficiency VALUES('A','HYD','EH',2025,'ELC',1.0,NULL); +INSERT INTO efficiency VALUES('A','HYD','EF',2025,'ELC',1.0,NULL); +INSERT INTO efficiency VALUES('B','ELC','bulbs',2025,'RL',1.0,NULL); +INSERT INTO efficiency VALUES('B','HYD','EH',2025,'ELC',1.0,NULL); +INSERT INTO efficiency VALUES('B','ELC','batt',2025,'ELC',1.0,NULL); +INSERT INTO efficiency VALUES('B','HYD','EF',2025,'ELC',1.0,NULL); +INSERT INTO efficiency VALUES('A','earth','well',2025,'HYD',1.0,NULL); +INSERT INTO efficiency VALUES('B','earth','well',2025,'HYD',1.0,NULL); +INSERT INTO efficiency VALUES('A','earth','EFL',2025,'FusionGasFuel',1.0,NULL); +INSERT INTO efficiency VALUES('A','FusionGasFuel','heater',2025,'RH',0.9000000000000000222,NULL); +INSERT INTO efficiency VALUES('A-B','FusionGasFuel','FGF_pipe',2025,'FusionGasFuel',0.949999999999999956,NULL); +INSERT INTO efficiency VALUES('B','FusionGasFuel','heater',2025,'RH',0.9000000000000000222,NULL); +INSERT INTO efficiency VALUES('B','GeoHyd','GeoHeater',2025,'RH',0.980000000000000094,NULL); +INSERT INTO efficiency VALUES('B','earth','GeoThermal',2025,'GeoHyd',1.0,NULL); +INSERT INTO efficiency VALUES('B-A','FusionGasFuel','FGF_pipe',2025,'FusionGasFuel',0.949999999999999956,NULL); +INSERT INTO efficiency VALUES('A','GeoHyd','GeoHeater',2025,'RH',0.9000000000000000222,NULL); +INSERT INTO efficiency VALUES('A','earth','GeoThermal',2025,'GeoHyd',1.0,NULL); +CREATE TABLE efficiency_variable ( region TEXT, period INTEGER @@ -366,7 +366,7 @@ CREATE TABLE EfficiencyVariable PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -CREATE TABLE EmissionActivity +CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT @@ -384,9 +384,9 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('A','co2','HYD','EH',2025,'ELC',0.02000000000000000041,NULL,NULL); -INSERT INTO EmissionActivity VALUES('A','FusionGas','HYD','EF',2025,'ELC',-0.2000000000000000111,NULL,'needs to be negative as a driver of linked tech...don''t ask'); -CREATE TABLE EmissionEmbodied +INSERT INTO emission_activity VALUES('A','co2','HYD','EH',2025,'ELC',0.02000000000000000041,NULL,NULL); +INSERT INTO emission_activity VALUES('A','FusionGas','HYD','EF',2025,'ELC',-0.2000000000000000111,NULL,'needs to be negative as a driver of linked tech...don''t ask'); +CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT @@ -400,7 +400,7 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE EmissionEndOfLife +CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT @@ -414,7 +414,7 @@ CREATE TABLE EmissionEndOfLife notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE ExistingCapacity +CREATE TABLE existing_capacity ( region TEXT, tech TEXT @@ -426,7 +426,7 @@ CREATE TABLE ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO ExistingCapacity VALUES('A','EH',2020,200.0,'things',NULL); +INSERT INTO existing_capacity VALUES('A','EH',2020,200.0,'things',NULL); CREATE TABLE TechGroup ( group_name TEXT @@ -435,7 +435,7 @@ CREATE TABLE TechGroup ); INSERT INTO TechGroup VALUES('RPS_common',''); INSERT INTO TechGroup VALUES('A_tech_grp_1','converted from old db'); -CREATE TABLE LoanLifetimeProcess +CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT @@ -446,25 +446,25 @@ CREATE TABLE LoanLifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO LoanLifetimeProcess VALUES('A','EF',2025,57,NULL); -INSERT INTO LoanLifetimeProcess VALUES('A','EFL',2025,68,NULL); -INSERT INTO LoanLifetimeProcess VALUES('A','bulbs',2025,10,NULL); -INSERT INTO LoanLifetimeProcess VALUES('A','EH',2025,10,NULL); -INSERT INTO LoanLifetimeProcess VALUES('A','well',2025,10,NULL); -INSERT INTO LoanLifetimeProcess VALUES('A','heater',2025,10,NULL); -INSERT INTO LoanLifetimeProcess VALUES('A','GeoHeater',2025,10,NULL); -INSERT INTO LoanLifetimeProcess VALUES('A','GeoThermal',2025,10,NULL); -INSERT INTO LoanLifetimeProcess VALUES('B','EF',2025,10,NULL); -INSERT INTO LoanLifetimeProcess VALUES('B','bulbs',2025,10,NULL); -INSERT INTO LoanLifetimeProcess VALUES('B','EH',2025,10,NULL); -INSERT INTO LoanLifetimeProcess VALUES('B','batt',2025,10,NULL); -INSERT INTO LoanLifetimeProcess VALUES('B','well',2025,10,NULL); -INSERT INTO LoanLifetimeProcess VALUES('B','heater',2025,10,NULL); -INSERT INTO LoanLifetimeProcess VALUES('B','GeoHeater',2025,10,NULL); -INSERT INTO LoanLifetimeProcess VALUES('B','GeoThermal',2025,10,NULL); -INSERT INTO LoanLifetimeProcess VALUES('A-B','FGF_pipe',2025,10,NULL); -INSERT INTO LoanLifetimeProcess VALUES('B-A','FGF_pipe',2025,10,NULL); -CREATE TABLE LoanRate +INSERT INTO loan_lifetime_process VALUES('A','EF',2025,57,NULL); +INSERT INTO loan_lifetime_process VALUES('A','EFL',2025,68,NULL); +INSERT INTO loan_lifetime_process VALUES('A','bulbs',2025,10,NULL); +INSERT INTO loan_lifetime_process VALUES('A','EH',2025,10,NULL); +INSERT INTO loan_lifetime_process VALUES('A','well',2025,10,NULL); +INSERT INTO loan_lifetime_process VALUES('A','heater',2025,10,NULL); +INSERT INTO loan_lifetime_process VALUES('A','GeoHeater',2025,10,NULL); +INSERT INTO loan_lifetime_process VALUES('A','GeoThermal',2025,10,NULL); +INSERT INTO loan_lifetime_process VALUES('B','EF',2025,10,NULL); +INSERT INTO loan_lifetime_process VALUES('B','bulbs',2025,10,NULL); +INSERT INTO loan_lifetime_process VALUES('B','EH',2025,10,NULL); +INSERT INTO loan_lifetime_process VALUES('B','batt',2025,10,NULL); +INSERT INTO loan_lifetime_process VALUES('B','well',2025,10,NULL); +INSERT INTO loan_lifetime_process VALUES('B','heater',2025,10,NULL); +INSERT INTO loan_lifetime_process VALUES('B','GeoHeater',2025,10,NULL); +INSERT INTO loan_lifetime_process VALUES('B','GeoThermal',2025,10,NULL); +INSERT INTO loan_lifetime_process VALUES('A-B','FGF_pipe',2025,10,NULL); +INSERT INTO loan_lifetime_process VALUES('B-A','FGF_pipe',2025,10,NULL); +CREATE TABLE loan_rate ( region TEXT, tech TEXT @@ -475,7 +475,7 @@ CREATE TABLE LoanRate notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeProcess +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -486,8 +486,8 @@ CREATE TABLE LifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO LifetimeProcess VALUES('B','EF',2025,200.0,NULL); -CREATE TABLE LifetimeTech +INSERT INTO lifetime_process VALUES('B','EF',2025,200.0,NULL); +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT @@ -496,8 +496,8 @@ CREATE TABLE LifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO LifetimeTech VALUES('A','EH',60.0,''); -INSERT INTO LifetimeTech VALUES('B','bulbs',100.0,'super LED!'); +INSERT INTO lifetime_tech VALUES('A','EH',60.0,''); +INSERT INTO lifetime_tech VALUES('B','bulbs',100.0,'super LED!'); CREATE TABLE Operator ( operator TEXT PRIMARY KEY, @@ -506,7 +506,7 @@ CREATE TABLE Operator INSERT INTO Operator VALUES('e','equal to'); INSERT INTO Operator VALUES('le','less than or equal to'); INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE LimitGrowthCapacity +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, @@ -518,7 +518,7 @@ CREATE TABLE LimitGrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthCapacity +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, @@ -530,7 +530,7 @@ CREATE TABLE LimitDegrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacity +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -542,7 +542,7 @@ CREATE TABLE LimitGrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -554,7 +554,7 @@ CREATE TABLE LimitDegrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacityDelta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -566,7 +566,7 @@ CREATE TABLE LimitGrowthNewCapacityDelta notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacityDelta +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -597,7 +597,7 @@ CREATE TABLE LimitStorageLevelFraction notes TEXT, PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE LimitActivity +CREATE TABLE limit_activity ( region TEXT, period INTEGER @@ -610,12 +610,12 @@ CREATE TABLE LimitActivity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO LimitActivity VALUES('A',2025,'EF','ge',0.00100000000000000002,'PJ/CY','goofy units'); -INSERT INTO LimitActivity VALUES('B',2025,'EH','le',10000.0,'stuff',NULL); -INSERT INTO LimitActivity VALUES('A',2025,'EF','le',10000.0,'stuff',NULL); -INSERT INTO LimitActivity VALUES('A',2025,'A_tech_grp_1','ge',0.05000000000000000277,'',NULL); -INSERT INTO LimitActivity VALUES('A',2025,'A_tech_grp_1','le',10000.0,'',NULL); -CREATE TABLE LimitActivityShare +INSERT INTO limit_activity VALUES('A',2025,'EF','ge',0.00100000000000000002,'PJ/CY','goofy units'); +INSERT INTO limit_activity VALUES('B',2025,'EH','le',10000.0,'stuff',NULL); +INSERT INTO limit_activity VALUES('A',2025,'EF','le',10000.0,'stuff',NULL); +INSERT INTO limit_activity VALUES('A',2025,'A_tech_grp_1','ge',0.05000000000000000277,'',NULL); +INSERT INTO limit_activity VALUES('A',2025,'A_tech_grp_1','le',10000.0,'',NULL); +CREATE TABLE limit_activity_share ( region TEXT, period INTEGER @@ -628,7 +628,7 @@ CREATE TABLE LimitActivityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitAnnualCapacityFactor +CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER @@ -644,7 +644,7 @@ CREATE TABLE LimitAnnualCapacityFactor PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE LimitCapacity +CREATE TABLE limit_capacity ( region TEXT, period INTEGER @@ -657,13 +657,13 @@ CREATE TABLE LimitCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO LimitCapacity VALUES('A',2025,'EH','ge',0.1000000000000000055,'',''); -INSERT INTO LimitCapacity VALUES('B',2025,'batt','ge',0.1000000000000000055,'',''); -INSERT INTO LimitCapacity VALUES('A',2025,'EH','le',20000.0,'',''); -INSERT INTO LimitCapacity VALUES('B',2025,'EH','le',20000.0,'',''); -INSERT INTO LimitCapacity VALUES('A',2025,'A_tech_grp_1','ge',0.2000000000000000111,'',NULL); -INSERT INTO LimitCapacity VALUES('A',2025,'A_tech_grp_1','le',6000.0,'',NULL); -CREATE TABLE LimitCapacityShare +INSERT INTO limit_capacity VALUES('A',2025,'EH','ge',0.1000000000000000055,'',''); +INSERT INTO limit_capacity VALUES('B',2025,'batt','ge',0.1000000000000000055,'',''); +INSERT INTO limit_capacity VALUES('A',2025,'EH','le',20000.0,'',''); +INSERT INTO limit_capacity VALUES('B',2025,'EH','le',20000.0,'',''); +INSERT INTO limit_capacity VALUES('A',2025,'A_tech_grp_1','ge',0.2000000000000000111,'',NULL); +INSERT INTO limit_capacity VALUES('A',2025,'A_tech_grp_1','le',6000.0,'',NULL); +CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER @@ -676,7 +676,7 @@ CREATE TABLE LimitCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitNewCapacity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER @@ -689,7 +689,7 @@ CREATE TABLE LimitNewCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitNewCapacityShare +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -702,9 +702,9 @@ CREATE TABLE LimitNewCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -INSERT INTO LimitNewCapacityShare VALUES('A',2025,'RPS_common','A_tech_grp_1','ge',0.0,''); -INSERT INTO LimitNewCapacityShare VALUES('global',2025,'RPS_common','A_tech_grp_1','le',1.0,''); -CREATE TABLE LimitResource +INSERT INTO limit_new_capacity_share VALUES('A',2025,'RPS_common','A_tech_grp_1','ge',0.0,''); +INSERT INTO limit_new_capacity_share VALUES('global',2025,'RPS_common','A_tech_grp_1','le',1.0,''); +CREATE TABLE limit_resource ( region TEXT, tech_or_group TEXT, @@ -715,8 +715,8 @@ CREATE TABLE LimitResource notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -INSERT INTO LimitResource VALUES('B','EF','le',9000.0,'clumps',NULL); -CREATE TABLE LimitSeasonalCapacityFactor +INSERT INTO limit_resource VALUES('B','EF','le',9000.0,'clumps',NULL); +CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES Region (region), @@ -732,7 +732,7 @@ CREATE TABLE LimitSeasonalCapacityFactor notes TEXT, PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE LimitTechInputSplit +CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER @@ -747,8 +747,8 @@ CREATE TABLE LimitTechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -INSERT INTO LimitTechInputSplit VALUES('A',2025,'HYD','EH','ge',0.949999999999999956,'95% HYD reqt. (other not specified...)'); -CREATE TABLE LimitTechInputSplitAnnual +INSERT INTO limit_tech_input_split VALUES('A',2025,'HYD','EH','ge',0.949999999999999956,'95% HYD reqt. (other not specified...)'); +CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER @@ -763,7 +763,7 @@ CREATE TABLE LimitTechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechOutputSplit +CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER @@ -778,8 +778,8 @@ CREATE TABLE LimitTechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -INSERT INTO LimitTechOutputSplit VALUES('B',2025,'EH','ELC','ge',0.949999999999999956,'95% ELC output (there are not others, this is a min)'); -CREATE TABLE LimitTechOutputSplitAnnual +INSERT INTO limit_tech_output_split VALUES('B',2025,'EH','ELC','ge',0.949999999999999956,'95% ELC output (there are not others, this is a min)'); +CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER @@ -794,7 +794,7 @@ CREATE TABLE LimitTechOutputSplitAnnual notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitEmission +CREATE TABLE limit_emission ( region TEXT, period INTEGER @@ -808,7 +808,7 @@ CREATE TABLE LimitEmission notes TEXT, PRIMARY KEY (region, period, emis_comm, operator) ); -INSERT INTO LimitEmission VALUES('A',2025,'co2','le',10000.0,'gulps',NULL); +INSERT INTO limit_emission VALUES('A',2025,'co2','le',10000.0,'gulps',NULL); CREATE TABLE LinkedTech ( primary_region TEXT, @@ -953,7 +953,7 @@ CREATE TABLE OutputStorageLevel level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); -CREATE TABLE PlanningReserveMargin +CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY @@ -961,8 +961,8 @@ CREATE TABLE PlanningReserveMargin margin REAL, notes TEXT ); -INSERT INTO PlanningReserveMargin VALUES('A',0.05000000000000000277,NULL); -CREATE TABLE RampDownHourly +INSERT INTO planning_reserve_margin VALUES('A',0.05000000000000000277,NULL); +CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT @@ -971,9 +971,9 @@ CREATE TABLE RampDownHourly notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO RampDownHourly VALUES('A','EH',0.05000000000000000277,NULL); -INSERT INTO RampDownHourly VALUES('B','EH',0.05000000000000000277,NULL); -CREATE TABLE RampUpHourly +INSERT INTO ramp_down_hourly VALUES('A','EH',0.05000000000000000277,NULL); +INSERT INTO ramp_down_hourly VALUES('B','EH',0.05000000000000000277,NULL); +CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT @@ -982,8 +982,8 @@ CREATE TABLE RampUpHourly notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO RampUpHourly VALUES('B','EH',0.05000000000000000277,NULL); -INSERT INTO RampUpHourly VALUES('A','EH',0.05000000000000000277,NULL); +INSERT INTO ramp_up_hourly VALUES('B','EH',0.05000000000000000277,NULL); +INSERT INTO ramp_up_hourly VALUES('A','EH',0.05000000000000000277,NULL); CREATE TABLE Region ( region TEXT @@ -992,7 +992,7 @@ CREATE TABLE Region ); INSERT INTO Region VALUES('A','main region'); INSERT INTO Region VALUES('B','just a 2nd region'); -CREATE TABLE ReserveCapacityDerate +CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER @@ -1008,7 +1008,7 @@ CREATE TABLE ReserveCapacityDerate CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE TimeSegmentFraction -( +( period INTEGER REFERENCES TimePeriod (period), season TEXT @@ -1024,7 +1024,7 @@ INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d1',0.25,NULL); INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d2',0.25,NULL); INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d1',0.25,NULL); INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d2',0.25,NULL); -CREATE TABLE StorageDuration +CREATE TABLE storage_duration ( region TEXT, tech TEXT, @@ -1032,8 +1032,8 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO StorageDuration VALUES('B','batt',15.0,NULL); -CREATE TABLE LifetimeSurvivalCurve +INSERT INTO storage_duration VALUES('B','batt',15.0,NULL); +CREATE TABLE lifetime_survival_curve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -1085,7 +1085,7 @@ CREATE TABLE TimeSeason ); INSERT INTO TimeSeason VALUES(2025,1,'s1',NULL); INSERT INTO TimeSeason VALUES(2025,2,'s2',NULL); -CREATE TABLE TimeSeasonSequential +CREATE TABLE time_season_sequential ( period INTEGER REFERENCES TimePeriod (period), diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index aa5267582..7602c5d39 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -1,7 +1,7 @@ { - "AnnualCommodityBalanceConstraint_rpc": [], - "AnnualRetirementVar_rptv": [], - "BaseloadDiurnalConstraint_rpsdtv": [ + "annual_commodity_balance_constraint_rpc": [], + "annual_retirement_var_rptv": [], + "baseload_diurnal_constraint_rpsdtv": [ [ "B", 2025, @@ -67,7 +67,7 @@ 2025 ] ], - "CapacityAnnualConstraint_rptv": [ + "capacity_annual_constraint_rptv": [ [ "A", 2025, @@ -81,7 +81,7 @@ 2025 ] ], - "CapacityAvailableVar_rpt": [ + "capacity_available_var_rpt": [ [ "A-B", 2025, @@ -173,7 +173,7 @@ "well" ] ], - "CapacityConstraint_rpsdtv": [ + "capacity_constraint_rpsdtv": [ [ "A", 2025, @@ -655,7 +655,7 @@ 2025 ] ], - "CapacityFactor_rpsdt": [ + "capacity_factor_rpsdt": [ [ "A", 2025, @@ -1161,7 +1161,7 @@ "well" ] ], - "CapacityVar_rptv": [ + "capacity_var_rptv": [ [ "A", 2025, @@ -1271,7 +1271,7 @@ 2025 ] ], - "CommodityBalanceConstraint_rpsdc": [ + "commodity_balance_constraint_rpsdc": [ [ "B", 2025, @@ -1497,14 +1497,14 @@ "HYD" ] ], - "CostEmission_rpe": [ + "cost_emission_rpe": [ [ "A", 2025, "co2" ] ], - "CostFixed_rptv": [ + "cost_fixed_rptv": [ [ "A", 2025, @@ -1614,7 +1614,7 @@ 2025 ] ], - "CostInvest_rtv": [ + "cost_invest_rtv": [ [ "A", "heater", @@ -1686,7 +1686,7 @@ 2025 ] ], - "CostVariable_rptv": [ + "cost_variable_rptv": [ [ "A", 2025, @@ -1796,7 +1796,7 @@ 2025 ] ], - "CurtailmentVar_rpsditvo": [ + "curtailment_var_rpsditvo": [ [ "A", 2025, @@ -1878,7 +1878,7 @@ "ELC" ] ], - "DemandActivityConstraint_rpsdtv_dem": [ + "demand_activity_constraint_rpsdtv_dem": [ [ "B", 2025, @@ -2096,7 +2096,7 @@ "RH" ] ], - "DemandConstraint_rpc": [ + "demand_constraint_rpc": [ [ "B", 2025, @@ -2118,7 +2118,7 @@ "RL" ] ], - "EmissionActivity_reitvo": [ + "emission_activity_reitvo": [ [ "B", "FusionGas", @@ -2376,8 +2376,8 @@ "RL" ] ], - "FlexVarAnnual_rpitvo": [], - "FlexVar_rpsditvo": [ + "flex_var_annual_rpitvo": [], + "flex_var_rpsditvo": [ [ "A", 2025, @@ -2419,7 +2419,7 @@ "FusionGasFuel" ] ], - "FlowInStorage_rpsditvo": [ + "flow_in_storage_rpsditvo": [ [ "B", 2025, @@ -2461,7 +2461,7 @@ "ELC" ] ], - "FlowVarAnnual_rpitvo": [ + "flow_var_annual_rpitvo": [ [ "B", 2025, @@ -2527,7 +2527,7 @@ "RH" ] ], - "FlowVar_rpsditvo": [ + "flow_var_rpsditvo": [ [ "B", 2025, @@ -3169,7 +3169,7 @@ "HYD" ] ], - "LifetimeProcess_rtv": [ + "lifetime_process_rtv": [ [ "A", "heater", @@ -3261,7 +3261,7 @@ 2025 ] ], - "LimitActivityConstraint_rpt": [ + "limit_activity_constraint_rpt": [ [ "B", 2025, @@ -3293,9 +3293,9 @@ "ge" ] ], - "LimitActivityShareConstraint_rpgg": [], - "LimitAnnualCapacityFactorConstraint_rpto": [], - "LimitCapacityConstraint_rpt": [ + "limit_activity_share_constraint_rpgg": [], + "limit_annual_capacity_factor_constraint_rpto": [], + "limit_capacity_constraint_rpt": [ [ "B", 2025, @@ -3333,11 +3333,11 @@ "ge" ] ], - "LimitCapacityShareConstraint_rpgg": [], - "LimitDegrowthCapacityConstraint_rpt": [], - "LimitDegrowthNewCapacityConstraint_rpt": [], - "LimitDegrowthNewCapacityDeltaConstraint_rpt": [], - "LimitEmissionConstraint_rpe": [ + "limit_capacity_share_constraint_rpgg": [], + "limit_degrowth_capacity_constraint_rpt": [], + "limit_degrowth_new_capacity_constraint_rpt": [], + "limit_degrowth_new_capacity_delta_constraint_rpt": [], + "limit_emission_constraint_rpe": [ [ "A", 2025, @@ -3345,11 +3345,11 @@ "le" ] ], - "LimitGrowthCapacityConstraint_rpt": [], - "LimitGrowthNewCapacityConstraint_rpt": [], - "LimitGrowthNewCapacityDeltaConstraint_rpt": [], - "LimitNewCapacityConstraint_rpt": [], - "LimitNewCapacityShareConstraint_rpgg": [ + "limit_growth_capacity_constraint_rpt": [], + "limit_growth_new_capacity_constraint_rpt": [], + "limit_growth_new_capacity_delta_constraint_rpt": [], + "limit_new_capacity_constraint_rpt": [], + "limit_new_capacity_share_constraint_rpgg": [ [ "A", 2025, @@ -3365,18 +3365,18 @@ "le" ] ], - "LimitResourceConstraint_rt": [ + "limit_resource_constraint_rt": [ [ "B", "EF", "le" ] ], - "LimitSeasonalCapacityFactorConstraint_rpst": [], - "LimitStorageFractionConstraint_rpsdtv": [], - "LimitTechInputSplitAnnualConstraint_rpitv": [], - "LimitTechInputSplitAverageConstraint_rpitv": [], - "LimitTechInputSplitConstraint_rpsditv": [ + "limit_seasonal_capacity_factor_constraint_rpst": [], + "limit_storage_fraction_constraint_rpsdtv": [], + "limit_tech_input_split_annual_constraint_rpitv": [], + "limit_tech_input_split_average_constraint_rpitv": [], + "limit_tech_input_split_constraint_rpsditv": [ [ "A", 2025, @@ -3418,9 +3418,9 @@ "ge" ] ], - "LimitTechOutputSplitAnnualConstraint_rptvo": [], - "LimitTechOutputSplitAverageConstraint_rptvo": [], - "LimitTechOutputSplitConstraint_rpsdtvo": [ + "limit_tech_output_split_annual_constraint_rptvo": [], + "limit_tech_output_split_average_constraint_rptvo": [], + "limit_tech_output_split_constraint_rpsdtvo": [ [ "B", 2025, @@ -3462,7 +3462,7 @@ "ge" ] ], - "LinkedEmissionsTechConstraint_rpsdtve": [ + "linked_emissions_tech_constraint_rpsdtve": [ [ "A", 2025, @@ -3500,7 +3500,7 @@ "FusionGas" ] ], - "LoanLifetimeProcess_rtv": [ + "loan_lifetime_process_rtv": [ [ "A", "heater", @@ -3592,7 +3592,7 @@ 2025 ] ], - "NewCapacityVar_rtv": [ + "new_capacity_var_rtv": [ [ "A", "heater", @@ -3684,7 +3684,7 @@ 2025 ] ], - "ProcessLifeFrac_rptv": [ + "process_life_frac_rptv": [ [ "A", 2025, @@ -3794,7 +3794,7 @@ 2025 ] ], - "RampDownDayConstraint_rpsdtv": [ + "ramp_down_day_constraint_rpsdtv": [ [ "B", 2025, @@ -3860,7 +3860,7 @@ 2025 ] ], - "RampDownSeasonConstraint_rpsstv": [ + "ramp_down_season_constraint_rpsstv": [ [ "A", 2025, @@ -3894,7 +3894,7 @@ 2025 ] ], - "RampUpDayConstraint_rpsdtv": [ + "ramp_up_day_constraint_rpsdtv": [ [ "B", 2025, @@ -3960,7 +3960,7 @@ 2025 ] ], - "RampUpSeasonConstraint_rpsstv": [ + "ramp_up_season_constraint_rpsstv": [ [ "A", 2025, @@ -3994,7 +3994,7 @@ 2025 ] ], - "RegionalExchangeCapacityConstraint_rrptv": [ + "regional_exchange_capacity_constraint_rrptv": [ [ "B", "A", @@ -4010,14 +4010,14 @@ 2025 ] ], - "RenewablePortfolioStandardConstraint_rpg": [ + "renewable_portfolio_standard_constraint_rpg": [ [ "B", 2025, "RPS_common" ] ], - "ReserveMargin_rpsd": [ + "reserve_margin_rpsd": [ [ "A", 2025, @@ -4043,13 +4043,13 @@ "d2" ] ], - "ReserveMarginMethod": [ + "reserve_margin_method": [ "static" ], - "RetiredCapacityVar_rptv": [], - "SeasonalStorageLevel_rpstv": [], - "SeasonalStorageConstraints_rpsdtv": [], - "StorageConstraints_rpsdtv": [ + "retired_capacity_var_rptv": [], + "seasonal_storage_level_rpstv": [], + "seasonal_storage_constraints_rpsdtv": [], + "storage_constraints_rpsdtv": [ [ "B", 2025, @@ -4083,7 +4083,7 @@ 2025 ] ], - "StorageLevel_rpsdtv": [ + "storage_level_rpsdtv": [ [ "B", 2025, @@ -4117,7 +4117,7 @@ 2025 ] ], - "TimeNext": [], + "time_manual": [], "commodity_all": [ "FusionGas", "RH", @@ -4178,12 +4178,12 @@ "s2" ] ], - "regionalGlobalIndices": [ + "regional_global_indices": [ "B", "A", "global" ], - "regionalIndices": [ + "regional_indices": [ "B", "A", "A-B", @@ -4305,18 +4305,18 @@ "time_optimize": [ 2025 ], - "TimeSeason": [ + "time_season": [ 2025 ], - "time_season": [ + "time_season_all": [ "s1", "s2" ], - "time_season_sequential": [ + "time_season_to_sequential": [ "s1", "s2" ], - "TimeSequencing": [ + "time_sequencing": [ "seasonal_timeslices" ], "vintage_all": [ @@ -4329,4 +4329,4 @@ "vintage_optimize": [ 2025 ] -} \ No newline at end of file +} diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index 2c368a71a..3064c30c3 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -19,7 +19,7 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -60,7 +60,7 @@ CREATE TABLE SectorLabel notes TEXT ); INSERT INTO SectorLabel VALUES('electricity',NULL); -CREATE TABLE CapacityCredit +CREATE TABLE capacity_credit ( region TEXT, period INTEGER @@ -73,7 +73,7 @@ CREATE TABLE CapacityCredit PRIMARY KEY (region, period, tech, vintage), CHECK (credit >= 0 AND credit <= 1) ); -CREATE TABLE CapacityFactorProcess +CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER @@ -90,7 +90,7 @@ CREATE TABLE CapacityFactorProcess PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE CapacityFactorTech +CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER @@ -106,14 +106,14 @@ CREATE TABLE CapacityFactorTech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','a','generator',1.0,NULL); -INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','b','generator',1.0,NULL); -INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','c','generator',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('region',2000,'charge','d','generator',0.2,NULL); -INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','a','generator',0.1,NULL); -INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','b','generator',0.1,NULL); -INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','c','generator',0.01,NULL); -INSERT INTO CapacityFactorTech VALUES('region',2000,'discharge','d','generator',0.01,NULL); +INSERT INTO capacity_factor_tech VALUES('region',2000,'charge','a','generator',1.0,NULL); +INSERT INTO capacity_factor_tech VALUES('region',2000,'charge','b','generator',1.0,NULL); +INSERT INTO capacity_factor_tech VALUES('region',2000,'charge','c','generator',0.2,NULL); +INSERT INTO capacity_factor_tech VALUES('region',2000,'charge','d','generator',0.2,NULL); +INSERT INTO capacity_factor_tech VALUES('region',2000,'discharge','a','generator',0.1,NULL); +INSERT INTO capacity_factor_tech VALUES('region',2000,'discharge','b','generator',0.1,NULL); +INSERT INTO capacity_factor_tech VALUES('region',2000,'discharge','c','generator',0.01,NULL); +INSERT INTO capacity_factor_tech VALUES('region',2000,'discharge','d','generator',0.01,NULL); CREATE TABLE CapacityToActivity ( region TEXT, @@ -152,7 +152,7 @@ INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('w','waste commodity'); INSERT INTO CommodityType VALUES('wa','waste annual commodity'); INSERT INTO CommodityType VALUES('wp','waste physical commodity'); -CREATE TABLE ConstructionInput +CREATE TABLE construction_input ( region TEXT, input_comm TEXT @@ -166,7 +166,7 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -CREATE TABLE CostEmission +CREATE TABLE cost_emission ( region TEXT, period INTEGER @@ -178,7 +178,7 @@ CREATE TABLE CostEmission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -CREATE TABLE CostFixed +CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -192,7 +192,7 @@ CREATE TABLE CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE CostInvest +CREATE TABLE cost_invest ( region TEXT, tech TEXT @@ -204,11 +204,11 @@ CREATE TABLE CostInvest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO CostInvest VALUES('region','generator',2000,1000.0,'',NULL); -INSERT INTO CostInvest VALUES('region','dly_stor',2000,1.0,'',NULL); -INSERT INTO CostInvest VALUES('region','seas_stor',2000,100.0,'',NULL); -INSERT INTO CostInvest VALUES('region','demand',2000,1.0,'',NULL); -CREATE TABLE CostVariable +INSERT INTO cost_invest VALUES('region','generator',2000,1000.0,'',NULL); +INSERT INTO cost_invest VALUES('region','dly_stor',2000,1.0,'',NULL); +INSERT INTO cost_invest VALUES('region','seas_stor',2000,100.0,'',NULL); +INSERT INTO cost_invest VALUES('region','demand',2000,1.0,'',NULL); +CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -222,8 +222,8 @@ CREATE TABLE CostVariable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostVariable VALUES('region',2000,'generator',2000,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2000,'demand',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2000,'generator',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2000,'demand',2000,1.0,NULL,NULL); CREATE TABLE Demand ( region TEXT, @@ -261,7 +261,7 @@ INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','a','dem INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','b','demand',0.2,NULL); INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','c','demand',0.2,NULL); INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','d','demand',0.4,NULL); -CREATE TABLE EndOfLifeOutput +CREATE TABLE end_of_life_output ( region TEXT, tech TEXT @@ -275,7 +275,7 @@ CREATE TABLE EndOfLifeOutput notes TEXT, PRIMARY KEY (region, tech, vintage, output_comm) ); -CREATE TABLE Efficiency +CREATE TABLE efficiency ( region TEXT, input_comm TEXT @@ -291,11 +291,11 @@ CREATE TABLE Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO Efficiency VALUES('region','ethos','generator',2000,'electricity',1.0,NULL); -INSERT INTO Efficiency VALUES('region','electricity','dly_stor',2000,'electricity',1.0,NULL); -INSERT INTO Efficiency VALUES('region','electricity','seas_stor',2000,'electricity',1.0,NULL); -INSERT INTO Efficiency VALUES('region','electricity','demand',2000,'demand',1.0,NULL); -CREATE TABLE EfficiencyVariable +INSERT INTO efficiency VALUES('region','ethos','generator',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('region','electricity','dly_stor',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('region','electricity','seas_stor',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('region','electricity','demand',2000,'demand',1.0,NULL); +CREATE TABLE efficiency_variable ( region TEXT, period INTEGER @@ -317,7 +317,7 @@ CREATE TABLE EfficiencyVariable PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -CREATE TABLE EmissionActivity +CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT @@ -335,7 +335,7 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -CREATE TABLE EmissionEmbodied +CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT @@ -349,7 +349,7 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE EmissionEndOfLife +CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT @@ -363,7 +363,7 @@ CREATE TABLE EmissionEndOfLife notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE ExistingCapacity +CREATE TABLE existing_capacity ( region TEXT, tech TEXT @@ -381,7 +381,7 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE LoanLifetimeTech +CREATE TABLE Loanlifetime_tech ( region TEXT, tech TEXT @@ -390,7 +390,7 @@ CREATE TABLE LoanLifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE LoanRate +CREATE TABLE loan_rate ( region TEXT, tech TEXT @@ -401,7 +401,7 @@ CREATE TABLE LoanRate notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeProcess +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -412,7 +412,7 @@ CREATE TABLE LifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeTech +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT @@ -429,7 +429,7 @@ CREATE TABLE Operator INSERT INTO Operator VALUES('e','equal to'); INSERT INTO Operator VALUES('le','less than or equal to'); INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE LimitGrowthCapacity +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, @@ -441,7 +441,7 @@ CREATE TABLE LimitGrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthCapacity +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, @@ -453,7 +453,7 @@ CREATE TABLE LimitDegrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacity +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -465,7 +465,7 @@ CREATE TABLE LimitGrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -477,7 +477,7 @@ CREATE TABLE LimitDegrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacityDelta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -489,7 +489,7 @@ CREATE TABLE LimitGrowthNewCapacityDelta notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacityDelta +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -522,7 +522,7 @@ CREATE TABLE LimitStorageLevelFraction ); INSERT INTO LimitStorageLevelFraction VALUES('region', 2000, 'winter', 'b', 'seas_stor', 2000, 'e', 0.5, NULL); INSERT INTO LimitStorageLevelFraction VALUES('region', 2000, 'charge', 'b', 'dly_stor', 2000, 'e', 0.5, NULL); -CREATE TABLE LimitActivity +CREATE TABLE limit_activity ( region TEXT, period INTEGER @@ -535,7 +535,7 @@ CREATE TABLE LimitActivity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitActivityShare +CREATE TABLE limit_activity_share ( region TEXT, period INTEGER @@ -548,7 +548,7 @@ CREATE TABLE LimitActivityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitAnnualCapacityFactor +CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER @@ -564,7 +564,7 @@ CREATE TABLE LimitAnnualCapacityFactor PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE LimitCapacity +CREATE TABLE limit_capacity ( region TEXT, period INTEGER @@ -577,7 +577,7 @@ CREATE TABLE LimitCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitCapacityShare +CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER @@ -590,7 +590,7 @@ CREATE TABLE LimitCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitNewCapacity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER @@ -603,7 +603,7 @@ CREATE TABLE LimitNewCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitNewCapacityShare +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -616,7 +616,7 @@ CREATE TABLE LimitNewCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitResource +CREATE TABLE limit_resource ( region TEXT, tech_or_group TEXT, @@ -627,7 +627,7 @@ CREATE TABLE LimitResource notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitSeasonalCapacityFactor +CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES Region (region), @@ -643,7 +643,7 @@ CREATE TABLE LimitSeasonalCapacityFactor notes TEXT, PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE LimitTechInputSplit +CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER @@ -658,7 +658,7 @@ CREATE TABLE LimitTechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechInputSplitAnnual +CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER @@ -673,7 +673,7 @@ CREATE TABLE LimitTechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechOutputSplit +CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER @@ -688,7 +688,7 @@ CREATE TABLE LimitTechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitTechOutputSplitAnnual +CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER @@ -703,7 +703,7 @@ CREATE TABLE LimitTechOutputSplitAnnual notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitEmission +CREATE TABLE limit_emission ( region TEXT, period INTEGER @@ -860,7 +860,7 @@ CREATE TABLE OutputStorageLevel level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); -CREATE TABLE PlanningReserveMargin +CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY @@ -868,7 +868,7 @@ CREATE TABLE PlanningReserveMargin margin REAL, notes TEXT ); -CREATE TABLE RampDownHourly +CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT @@ -877,7 +877,7 @@ CREATE TABLE RampDownHourly notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUpHourly +CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT @@ -893,7 +893,7 @@ CREATE TABLE Region notes TEXT ); INSERT INTO Region VALUES('region',NULL); -CREATE TABLE ReserveCapacityDerate +CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER @@ -909,7 +909,7 @@ CREATE TABLE ReserveCapacityDerate CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE TimeSegmentFraction -( +( period INTEGER REFERENCES TimePeriod (period), season TEXT @@ -929,7 +929,7 @@ INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','a',0.125,NULL); INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','b',0.125,NULL); INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','c',0.125,NULL); INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','d',0.125,NULL); -CREATE TABLE StorageDuration +CREATE TABLE storage_duration ( region TEXT, tech TEXT, @@ -937,9 +937,9 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO StorageDuration VALUES('region','dly_stor',4.0,NULL); -INSERT INTO StorageDuration VALUES('region','seas_stor',8760.0,NULL); -CREATE TABLE LifetimeSurvivalCurve +INSERT INTO storage_duration VALUES('region','dly_stor',4.0,NULL); +INSERT INTO storage_duration VALUES('region','seas_stor',8760.0,NULL); +CREATE TABLE lifetime_survival_curve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -1078,7 +1078,7 @@ CREATE TABLE OutputCost FOREIGN KEY (vintage) REFERENCES TimePeriod (period), FOREIGN KEY (tech) REFERENCES Technology (tech) ); -CREATE TABLE TimeSeasonSequential +CREATE TABLE time_season_sequential ( period INTEGER REFERENCES TimePeriod (period), @@ -1091,18 +1091,18 @@ CREATE TABLE TimeSeasonSequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -INSERT INTO TimeSeasonSequential VALUES(2000,1,'summer','charge',152.5,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,2,'sept_w1','discharge',7,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,3,'sept_w2','charge',7,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,4,'sept_w3','discharge',7,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,5,'sept_w4','charge',7,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,6,'sept_29th','discharge',1,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,7,'sept_30th','charge',1,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,8,'winter','discharge',152.5,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,9,'apr_w1','charge',7,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,10,'apr_w2','discharge',7,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,11,'apr_w3','charge',7,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,12,'apr_w4','discharge',7,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,13,'apr_29th','charge',1,NULL); -INSERT INTO TimeSeasonSequential VALUES(2000,14,'apr_30th','discharge',1,NULL); +INSERT INTO time_season_sequential VALUES(2000,1,'summer','charge',152.5,NULL); +INSERT INTO time_season_sequential VALUES(2000,2,'sept_w1','discharge',7,NULL); +INSERT INTO time_season_sequential VALUES(2000,3,'sept_w2','charge',7,NULL); +INSERT INTO time_season_sequential VALUES(2000,4,'sept_w3','discharge',7,NULL); +INSERT INTO time_season_sequential VALUES(2000,5,'sept_w4','charge',7,NULL); +INSERT INTO time_season_sequential VALUES(2000,6,'sept_29th','discharge',1,NULL); +INSERT INTO time_season_sequential VALUES(2000,7,'sept_30th','charge',1,NULL); +INSERT INTO time_season_sequential VALUES(2000,8,'winter','discharge',152.5,NULL); +INSERT INTO time_season_sequential VALUES(2000,9,'apr_w1','charge',7,NULL); +INSERT INTO time_season_sequential VALUES(2000,10,'apr_w2','discharge',7,NULL); +INSERT INTO time_season_sequential VALUES(2000,11,'apr_w3','charge',7,NULL); +INSERT INTO time_season_sequential VALUES(2000,12,'apr_w4','discharge',7,NULL); +INSERT INTO time_season_sequential VALUES(2000,13,'apr_29th','charge',1,NULL); +INSERT INTO time_season_sequential VALUES(2000,14,'apr_30th','discharge',1,NULL); COMMIT; diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index 607f9e249..c95403a5d 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -18,7 +18,7 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); CREATE TABLE OutputDualVariable ( @@ -51,7 +51,7 @@ INSERT INTO SectorLabel VALUES('transport',NULL); INSERT INTO SectorLabel VALUES('commercial',NULL); INSERT INTO SectorLabel VALUES('residential',NULL); INSERT INTO SectorLabel VALUES('industrial',NULL); -CREATE TABLE CapacityCredit +CREATE TABLE capacity_credit ( region TEXT, period INTEGER @@ -64,7 +64,7 @@ CREATE TABLE CapacityCredit PRIMARY KEY (region, period, tech, vintage), CHECK (credit >= 0 AND credit <= 1) ); -CREATE TABLE CapacityFactorProcess +CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER @@ -81,7 +81,7 @@ CREATE TABLE CapacityFactorProcess PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE CapacityFactorTech +CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER @@ -133,7 +133,7 @@ INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); -CREATE TABLE ConstructionInput +CREATE TABLE construction_input ( region TEXT, input_comm TEXT @@ -147,7 +147,7 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -CREATE TABLE CostEmission +CREATE TABLE cost_emission ( region TEXT, period INTEGER @@ -159,8 +159,8 @@ CREATE TABLE CostEmission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -INSERT INTO CostEmission VALUES('linkville',2000,'CO2',2.0,NULL,NULL); -CREATE TABLE CostFixed +INSERT INTO cost_emission VALUES('linkville',2000,'CO2',2.0,NULL,NULL); +CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -174,7 +174,7 @@ CREATE TABLE CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE CostInvest +CREATE TABLE cost_invest ( region TEXT, tech TEXT @@ -186,9 +186,9 @@ CREATE TABLE CostInvest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO CostInvest VALUES('linkville','PLANT',2000,100.0,'',''); -INSERT INTO CostInvest VALUES('linkville','CCS',2000,50.0,'',''); -CREATE TABLE CostVariable +INSERT INTO cost_invest VALUES('linkville','PLANT',2000,100.0,'',''); +INSERT INTO cost_invest VALUES('linkville','CCS',2000,50.0,'',''); +CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -202,9 +202,9 @@ CREATE TABLE CostVariable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostVariable VALUES('linkville',2000,'PLANT',2000,10.0,NULL,NULL); -INSERT INTO CostVariable VALUES('linkville',2000,'CCS',2000,10.0,NULL,NULL); -INSERT INTO CostVariable VALUES('linkville',2000,'FAKE_SOURCE',2000,0.0,NULL,NULL); +INSERT INTO cost_variable VALUES('linkville',2000,'PLANT',2000,10.0,NULL,NULL); +INSERT INTO cost_variable VALUES('linkville',2000,'CCS',2000,10.0,NULL,NULL); +INSERT INTO cost_variable VALUES('linkville',2000,'FAKE_SOURCE',2000,0.0,NULL,NULL); CREATE TABLE Demand ( region TEXT, @@ -237,7 +237,7 @@ CREATE TABLE DemandSpecificDistribution ); INSERT INTO DemandSpecificDistribution VALUES('linkville',2000,'summer','day','ELC',0.5,''); INSERT INTO DemandSpecificDistribution VALUES('linkville',2000,'winter','day','ELC',0.5,''); -CREATE TABLE EndOfLifeOutput +CREATE TABLE end_of_life_output ( region TEXT, tech TEXT @@ -251,7 +251,7 @@ CREATE TABLE EndOfLifeOutput notes TEXT, PRIMARY KEY (region, tech, vintage, output_comm) ); -CREATE TABLE Efficiency +CREATE TABLE efficiency ( region TEXT, input_comm TEXT @@ -267,11 +267,11 @@ CREATE TABLE Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO Efficiency VALUES('linkville','ETHOS','MINE',2000,'NGA',1.0,''); -INSERT INTO Efficiency VALUES('linkville','ETHOS','CCS',2000,'CO2_CAP',1.0,'capture eff'); -INSERT INTO Efficiency VALUES('linkville','ETHOS','FAKE_SOURCE',2000,'CO2_CAP',1.0,''); -INSERT INTO Efficiency VALUES('linkville','NGA','PLANT',2000,'ELC',0.5,NULL); -CREATE TABLE EfficiencyVariable +INSERT INTO efficiency VALUES('linkville','ETHOS','MINE',2000,'NGA',1.0,''); +INSERT INTO efficiency VALUES('linkville','ETHOS','CCS',2000,'CO2_CAP',1.0,'capture eff'); +INSERT INTO efficiency VALUES('linkville','ETHOS','FAKE_SOURCE',2000,'CO2_CAP',1.0,''); +INSERT INTO efficiency VALUES('linkville','NGA','PLANT',2000,'ELC',0.5,NULL); +CREATE TABLE efficiency_variable ( region TEXT, period INTEGER @@ -293,7 +293,7 @@ CREATE TABLE EfficiencyVariable PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -CREATE TABLE EmissionActivity +CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT @@ -311,8 +311,8 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('linkville','CO2','NGA','PLANT',2000,'ELC',-3.0,'',''); -CREATE TABLE EmissionEmbodied +INSERT INTO emission_activity VALUES('linkville','CO2','NGA','PLANT',2000,'ELC',-3.0,'',''); +CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT @@ -326,7 +326,7 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE EmissionEndOfLife +CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT @@ -340,7 +340,7 @@ CREATE TABLE EmissionEndOfLife notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE ExistingCapacity +CREATE TABLE existing_capacity ( region TEXT, tech TEXT @@ -358,7 +358,7 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE LoanLifetimeProcess +CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT @@ -369,7 +369,7 @@ CREATE TABLE LoanLifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LoanRate +CREATE TABLE loan_rate ( region TEXT, tech TEXT @@ -380,7 +380,7 @@ CREATE TABLE LoanRate notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeProcess +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -391,7 +391,7 @@ CREATE TABLE LifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeTech +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT @@ -400,8 +400,8 @@ CREATE TABLE LifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO LifetimeTech VALUES('linkville','CCS',100.0,''); -INSERT INTO LifetimeTech VALUES('linkville','PLANT',100.0,''); +INSERT INTO lifetime_tech VALUES('linkville','CCS',100.0,''); +INSERT INTO lifetime_tech VALUES('linkville','PLANT',100.0,''); CREATE TABLE Operator ( operator TEXT PRIMARY KEY, @@ -410,7 +410,7 @@ CREATE TABLE Operator INSERT INTO Operator VALUES('e','equal to'); INSERT INTO Operator VALUES('le','less than or equal to'); INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE LimitGrowthCapacity +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, @@ -422,7 +422,7 @@ CREATE TABLE LimitGrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthCapacity +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, @@ -434,7 +434,7 @@ CREATE TABLE LimitDegrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacity +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -446,7 +446,7 @@ CREATE TABLE LimitGrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -458,7 +458,7 @@ CREATE TABLE LimitDegrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacityDelta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -470,7 +470,7 @@ CREATE TABLE LimitGrowthNewCapacityDelta notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacityDelta +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -501,7 +501,7 @@ CREATE TABLE LimitStorageLevelFraction notes TEXT, PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE LimitActivity +CREATE TABLE limit_activity ( region TEXT, period INTEGER @@ -514,7 +514,7 @@ CREATE TABLE LimitActivity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitActivityShare +CREATE TABLE limit_activity_share ( region TEXT, period INTEGER @@ -527,7 +527,7 @@ CREATE TABLE LimitActivityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitAnnualCapacityFactor +CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER @@ -543,7 +543,7 @@ CREATE TABLE LimitAnnualCapacityFactor PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE LimitCapacity +CREATE TABLE limit_capacity ( region TEXT, period INTEGER @@ -556,7 +556,7 @@ CREATE TABLE LimitCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitCapacityShare +CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER @@ -569,7 +569,7 @@ CREATE TABLE LimitCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitNewCapacity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER @@ -582,7 +582,7 @@ CREATE TABLE LimitNewCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitNewCapacityShare +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -595,7 +595,7 @@ CREATE TABLE LimitNewCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitResource +CREATE TABLE limit_resource ( region TEXT, tech_or_group TEXT, @@ -606,7 +606,7 @@ CREATE TABLE LimitResource notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitSeasonalCapacityFactor +CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES Region (region), @@ -622,7 +622,7 @@ CREATE TABLE LimitSeasonalCapacityFactor notes TEXT, PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE LimitTechInputSplit +CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER @@ -637,7 +637,7 @@ CREATE TABLE LimitTechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechInputSplitAnnual +CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER @@ -652,7 +652,7 @@ CREATE TABLE LimitTechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechOutputSplit +CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER @@ -667,7 +667,7 @@ CREATE TABLE LimitTechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitTechOutputSplitAnnual +CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER @@ -682,7 +682,7 @@ CREATE TABLE LimitTechOutputSplitAnnual notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitEmission +CREATE TABLE limit_emission ( region TEXT, period INTEGER @@ -840,7 +840,7 @@ CREATE TABLE OutputStorageLevel level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); -CREATE TABLE PlanningReserveMargin +CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY @@ -848,7 +848,7 @@ CREATE TABLE PlanningReserveMargin margin REAL, notes TEXT ); -CREATE TABLE RampDownHourly +CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT @@ -857,7 +857,7 @@ CREATE TABLE RampDownHourly notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUpHourly +CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT @@ -873,7 +873,7 @@ CREATE TABLE Region notes TEXT ); INSERT INTO Region VALUES('linkville',NULL); -CREATE TABLE ReserveCapacityDerate +CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER @@ -889,7 +889,7 @@ CREATE TABLE ReserveCapacityDerate CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE TimeSegmentFraction -( +( period INTEGER REFERENCES TimePeriod (period), season TEXT @@ -903,7 +903,7 @@ CREATE TABLE TimeSegmentFraction ); INSERT INTO TimeSegmentFraction VALUES(2000,'summer','day',0.5,'# S-D'); INSERT INTO TimeSegmentFraction VALUES(2000,'winter','day',0.5,'# W-D'); -CREATE TABLE StorageDuration +CREATE TABLE storage_duration ( region TEXT, tech TEXT, @@ -911,7 +911,7 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE LifetimeSurvivalCurve +CREATE TABLE lifetime_survival_curve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -962,7 +962,7 @@ CREATE TABLE TimeSeason ); INSERT INTO TimeSeason VALUES(2000,1,'summer',NULL); INSERT INTO TimeSeason VALUES(2000,2,'winter',NULL); -CREATE TABLE TimeSeasonSequential +CREATE TABLE time_season_sequential ( period INTEGER REFERENCES TimePeriod (period), diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index c9e7288f8..11aeff4d2 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -18,7 +18,7 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); CREATE TABLE OutputDualVariable ( @@ -51,7 +51,7 @@ INSERT INTO SectorLabel VALUES('transport',NULL); INSERT INTO SectorLabel VALUES('commercial',NULL); INSERT INTO SectorLabel VALUES('residential',NULL); INSERT INTO SectorLabel VALUES('industrial',NULL); -CREATE TABLE CapacityCredit +CREATE TABLE capacity_credit ( region TEXT, period INTEGER @@ -64,7 +64,7 @@ CREATE TABLE CapacityCredit PRIMARY KEY (region, period, tech, vintage), CHECK (credit >= 0 AND credit <= 1) ); -CREATE TABLE CapacityFactorProcess +CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER @@ -81,7 +81,7 @@ CREATE TABLE CapacityFactorProcess PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE CapacityFactorTech +CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER @@ -134,7 +134,7 @@ INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); INSERT INTO CommodityType VALUES('s','source commodity'); -CREATE TABLE ConstructionInput +CREATE TABLE construction_input ( region TEXT, input_comm TEXT @@ -148,7 +148,7 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -CREATE TABLE CostEmission +CREATE TABLE cost_emission ( region TEXT, period INTEGER @@ -160,7 +160,7 @@ CREATE TABLE CostEmission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -CREATE TABLE CostFixed +CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -174,9 +174,9 @@ CREATE TABLE CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostFixed VALUES('electricville',2025,'EH',2025,100.0,'',''); -INSERT INTO CostFixed VALUES('electricville',2025,'batt',2025,1.0,'',''); -CREATE TABLE CostInvest +INSERT INTO cost_fixed VALUES('electricville',2025,'EH',2025,100.0,'',''); +INSERT INTO cost_fixed VALUES('electricville',2025,'batt',2025,1.0,'',''); +CREATE TABLE cost_invest ( region TEXT, tech TEXT @@ -188,9 +188,9 @@ CREATE TABLE CostInvest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO CostInvest VALUES('electricville','EH',2025,100.0,'',''); -INSERT INTO CostInvest VALUES('electricville','batt',2025,1.0,NULL,NULL); -CREATE TABLE CostVariable +INSERT INTO cost_invest VALUES('electricville','EH',2025,100.0,'',''); +INSERT INTO cost_invest VALUES('electricville','batt',2025,1.0,NULL,NULL); +CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -204,8 +204,8 @@ CREATE TABLE CostVariable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostVariable VALUES('electricville',2025,'EH',2025,1000.0,'',''); -INSERT INTO CostVariable VALUES('electricville',2025,'batt',2025,1.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2025,'EH',2025,1000.0,'',''); +INSERT INTO cost_variable VALUES('electricville',2025,'batt',2025,1.0,'',''); CREATE TABLE Demand ( region TEXT, @@ -245,7 +245,7 @@ INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s1','d4','RL INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s1','d5','RL',0.2000000000000000111,NULL); INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s2','d4','RL',0.2000000000000000111,NULL); INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s2','d5','RL',0.07499999999999999723,NULL); -CREATE TABLE EndOfLifeOutput +CREATE TABLE end_of_life_output ( region TEXT, tech TEXT @@ -259,7 +259,7 @@ CREATE TABLE EndOfLifeOutput notes TEXT, PRIMARY KEY (region, tech, vintage, output_comm) ); -CREATE TABLE Efficiency +CREATE TABLE efficiency ( region TEXT, input_comm TEXT @@ -275,11 +275,11 @@ CREATE TABLE Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO Efficiency VALUES('electricville','HYD','EH',2025,'ELC',1.0,NULL); -INSERT INTO Efficiency VALUES('electricville','ELC','bulbs',2025,'RL',1.0,NULL); -INSERT INTO Efficiency VALUES('electricville','earth','well',2025,'HYD',1.0,'water source'); -INSERT INTO Efficiency VALUES('electricville','ELC','batt',2025,'ELC',0.75,NULL); -CREATE TABLE EfficiencyVariable +INSERT INTO efficiency VALUES('electricville','HYD','EH',2025,'ELC',1.0,NULL); +INSERT INTO efficiency VALUES('electricville','ELC','bulbs',2025,'RL',1.0,NULL); +INSERT INTO efficiency VALUES('electricville','earth','well',2025,'HYD',1.0,'water source'); +INSERT INTO efficiency VALUES('electricville','ELC','batt',2025,'ELC',0.75,NULL); +CREATE TABLE efficiency_variable ( region TEXT, period INTEGER @@ -301,7 +301,7 @@ CREATE TABLE EfficiencyVariable PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -CREATE TABLE EmissionActivity +CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT @@ -319,8 +319,8 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('electricville','co2','HYD','EH',2025,'ELC',0.02000000000000000041,NULL,NULL); -CREATE TABLE EmissionEmbodied +INSERT INTO emission_activity VALUES('electricville','co2','HYD','EH',2025,'ELC',0.02000000000000000041,NULL,NULL); +CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT @@ -334,7 +334,7 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE EmissionEndOfLife +CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT @@ -348,7 +348,7 @@ CREATE TABLE EmissionEndOfLife notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE ExistingCapacity +CREATE TABLE existing_capacity ( region TEXT, tech TEXT @@ -366,7 +366,7 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE LoanLifetimeProcess +CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT @@ -377,7 +377,7 @@ CREATE TABLE LoanLifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LoanRate +CREATE TABLE loan_rate ( region TEXT, tech TEXT @@ -388,7 +388,7 @@ CREATE TABLE LoanRate notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeProcess +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -399,7 +399,7 @@ CREATE TABLE LifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeTech +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT @@ -408,8 +408,8 @@ CREATE TABLE LifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO LifetimeTech VALUES('electricville','EH',60.0,''); -INSERT INTO LifetimeTech VALUES('electricville','bulbs',100.0,'super LED!'); +INSERT INTO lifetime_tech VALUES('electricville','EH',60.0,''); +INSERT INTO lifetime_tech VALUES('electricville','bulbs',100.0,'super LED!'); CREATE TABLE Operator ( operator TEXT PRIMARY KEY, @@ -418,7 +418,7 @@ CREATE TABLE Operator INSERT INTO Operator VALUES('e','equal to'); INSERT INTO Operator VALUES('le','less than or equal to'); INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE LimitGrowthCapacity +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, @@ -430,7 +430,7 @@ CREATE TABLE LimitGrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthCapacity +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, @@ -442,7 +442,7 @@ CREATE TABLE LimitDegrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacity +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -454,7 +454,7 @@ CREATE TABLE LimitGrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -466,7 +466,7 @@ CREATE TABLE LimitDegrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacityDelta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -478,7 +478,7 @@ CREATE TABLE LimitGrowthNewCapacityDelta notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacityDelta +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -510,7 +510,7 @@ CREATE TABLE LimitStorageLevelFraction PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); INSERT INTO LimitStorageLevelFraction VALUES('electricville',2025,'s1','d1','batt',2025,'e',0.5,NULL); -CREATE TABLE LimitActivity +CREATE TABLE limit_activity ( region TEXT, period INTEGER @@ -523,7 +523,7 @@ CREATE TABLE LimitActivity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitActivityShare +CREATE TABLE limit_activity_share ( region TEXT, period INTEGER @@ -536,7 +536,7 @@ CREATE TABLE LimitActivityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitAnnualCapacityFactor +CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER @@ -552,7 +552,7 @@ CREATE TABLE LimitAnnualCapacityFactor PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE LimitCapacity +CREATE TABLE limit_capacity ( region TEXT, period INTEGER @@ -565,11 +565,11 @@ CREATE TABLE LimitCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO LimitCapacity VALUES('electricville',2025,'EH','ge',0.1000000000000000055,'',''); -INSERT INTO LimitCapacity VALUES('electricville',2025,'batt','ge',0.1000000000000000055,'',''); -INSERT INTO LimitCapacity VALUES('electricville',2025,'EH','le',200.0,'',''); -INSERT INTO LimitCapacity VALUES('electricville',2025,'batt','le',100.0,'',''); -CREATE TABLE LimitCapacityShare +INSERT INTO limit_capacity VALUES('electricville',2025,'EH','ge',0.1000000000000000055,'',''); +INSERT INTO limit_capacity VALUES('electricville',2025,'batt','ge',0.1000000000000000055,'',''); +INSERT INTO limit_capacity VALUES('electricville',2025,'EH','le',200.0,'',''); +INSERT INTO limit_capacity VALUES('electricville',2025,'batt','le',100.0,'',''); +CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER @@ -582,7 +582,7 @@ CREATE TABLE LimitCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitNewCapacity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER @@ -595,7 +595,7 @@ CREATE TABLE LimitNewCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitNewCapacityShare +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -608,7 +608,7 @@ CREATE TABLE LimitNewCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitResource +CREATE TABLE limit_resource ( region TEXT, tech_or_group TEXT, @@ -619,7 +619,7 @@ CREATE TABLE LimitResource notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitSeasonalCapacityFactor +CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES Region (region), @@ -635,7 +635,7 @@ CREATE TABLE LimitSeasonalCapacityFactor notes TEXT, PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE LimitTechInputSplit +CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER @@ -650,7 +650,7 @@ CREATE TABLE LimitTechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechInputSplitAnnual +CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER @@ -665,7 +665,7 @@ CREATE TABLE LimitTechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechOutputSplit +CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER @@ -680,7 +680,7 @@ CREATE TABLE LimitTechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitTechOutputSplitAnnual +CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER @@ -695,7 +695,7 @@ CREATE TABLE LimitTechOutputSplitAnnual notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitEmission +CREATE TABLE limit_emission ( region TEXT, period INTEGER @@ -852,7 +852,7 @@ CREATE TABLE OutputStorageLevel level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); -CREATE TABLE PlanningReserveMargin +CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY @@ -860,7 +860,7 @@ CREATE TABLE PlanningReserveMargin margin REAL, notes TEXT ); -CREATE TABLE RampDownHourly +CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT @@ -869,7 +869,7 @@ CREATE TABLE RampDownHourly notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUpHourly +CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT @@ -885,7 +885,7 @@ CREATE TABLE Region notes TEXT ); INSERT INTO Region VALUES('electricville',NULL); -CREATE TABLE ReserveCapacityDerate +CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER @@ -901,7 +901,7 @@ CREATE TABLE ReserveCapacityDerate CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE TimeSegmentFraction -( +( period INTEGER REFERENCES TimePeriod (period), season TEXT @@ -923,7 +923,7 @@ INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d4',0.1000000000000000055,NULL INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d5',0.1000000000000000055,NULL); INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d4',0.1000000000000000055,NULL); INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d5',0.1000000000000000055,NULL); -CREATE TABLE StorageDuration +CREATE TABLE storage_duration ( region TEXT, tech TEXT, @@ -931,8 +931,8 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO StorageDuration VALUES('electricville','batt',10.0,NULL); -CREATE TABLE LifetimeSurvivalCurve +INSERT INTO storage_duration VALUES('electricville','batt',10.0,NULL); +CREATE TABLE lifetime_survival_curve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -987,7 +987,7 @@ CREATE TABLE TimeSeason ); INSERT INTO TimeSeason VALUES(2025,1,'s1',NULL); INSERT INTO TimeSeason VALUES(2025,2,'s2',NULL); -CREATE TABLE TimeSeasonSequential +CREATE TABLE time_season_sequential ( period INTEGER REFERENCES TimePeriod (period), diff --git a/tests/testing_data/survival_curve.sql b/tests/testing_data/survival_curve.sql index df443dd87..b0c6560ad 100644 --- a/tests/testing_data/survival_curve.sql +++ b/tests/testing_data/survival_curve.sql @@ -19,7 +19,7 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); CREATE TABLE OutputDualVariable ( scenario TEXT, @@ -44,7 +44,7 @@ CREATE TABLE SectorLabel sector TEXT PRIMARY KEY, notes TEXT ); -CREATE TABLE CapacityCredit +CREATE TABLE capacity_credit ( region TEXT, period INTEGER @@ -57,7 +57,7 @@ CREATE TABLE CapacityCredit PRIMARY KEY (region, period, tech, vintage), CHECK (credit >= 0 AND credit <= 1) ); -CREATE TABLE CapacityFactorProcess +CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER @@ -74,7 +74,7 @@ CREATE TABLE CapacityFactorProcess PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE CapacityFactorTech +CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER @@ -123,7 +123,7 @@ INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('w','waste commodity'); INSERT INTO CommodityType VALUES('wa','waste annual commodity'); INSERT INTO CommodityType VALUES('wp','waste physical commodity'); -CREATE TABLE ConstructionInput +CREATE TABLE construction_input ( region TEXT, input_comm TEXT @@ -137,7 +137,7 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -CREATE TABLE CostEmission +CREATE TABLE cost_emission ( region TEXT, period INTEGER @@ -149,7 +149,7 @@ CREATE TABLE CostEmission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -CREATE TABLE CostFixed +CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -163,33 +163,33 @@ CREATE TABLE CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostFixed VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO CostFixed VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); -CREATE TABLE CostInvest +INSERT INTO cost_fixed VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO cost_fixed VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); +CREATE TABLE cost_invest ( region TEXT, tech TEXT @@ -201,13 +201,13 @@ CREATE TABLE CostInvest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO CostInvest VALUES('region','tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('region','tech_future',2030,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('region','tech_future',2035,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('region','tech_future',2040,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('region','tech_future',2045,1.0,NULL,NULL); -INSERT INTO CostInvest VALUES('region','tech_future',2050,1.0,NULL,NULL); -CREATE TABLE CostVariable +INSERT INTO cost_invest VALUES('region','tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('region','tech_future',2030,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('region','tech_future',2035,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('region','tech_future',2040,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('region','tech_future',2045,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('region','tech_future',2050,1.0,NULL,NULL); +CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -221,32 +221,32 @@ CREATE TABLE CostVariable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostVariable VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO CostVariable VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); CREATE TABLE Demand ( region TEXT, @@ -281,7 +281,7 @@ CREATE TABLE DemandSpecificDistribution PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -CREATE TABLE EndOfLifeOutput +CREATE TABLE end_of_life_output ( region TEXT, tech TEXT @@ -295,7 +295,7 @@ CREATE TABLE EndOfLifeOutput notes TEXT, PRIMARY KEY (region, tech, vintage, output_comm) ); -CREATE TABLE Efficiency +CREATE TABLE efficiency ( region TEXT, input_comm TEXT @@ -311,15 +311,15 @@ CREATE TABLE Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO Efficiency VALUES('region','source','tech_ancient',1994,'demand',1.0,NULL); -INSERT INTO Efficiency VALUES('region','source','tech_old',2010,'demand',1.0,NULL); -INSERT INTO Efficiency VALUES('region','source','tech_current',2025,'demand',1.0,NULL); -INSERT INTO Efficiency VALUES('region','source','tech_future',2030,'demand',1.0,NULL); -INSERT INTO Efficiency VALUES('region','source','tech_future',2035,'demand',1.0,NULL); -INSERT INTO Efficiency VALUES('region','source','tech_future',2040,'demand',1.0,NULL); -INSERT INTO Efficiency VALUES('region','source','tech_future',2045,'demand',1.0,NULL); -INSERT INTO Efficiency VALUES('region','source','tech_future',2050,'demand',1.0,NULL); -CREATE TABLE EfficiencyVariable +INSERT INTO efficiency VALUES('region','source','tech_ancient',1994,'demand',1.0,NULL); +INSERT INTO efficiency VALUES('region','source','tech_old',2010,'demand',1.0,NULL); +INSERT INTO efficiency VALUES('region','source','tech_current',2025,'demand',1.0,NULL); +INSERT INTO efficiency VALUES('region','source','tech_future',2030,'demand',1.0,NULL); +INSERT INTO efficiency VALUES('region','source','tech_future',2035,'demand',1.0,NULL); +INSERT INTO efficiency VALUES('region','source','tech_future',2040,'demand',1.0,NULL); +INSERT INTO efficiency VALUES('region','source','tech_future',2045,'demand',1.0,NULL); +INSERT INTO efficiency VALUES('region','source','tech_future',2050,'demand',1.0,NULL); +CREATE TABLE efficiency_variable ( region TEXT, period INTEGER @@ -341,7 +341,7 @@ CREATE TABLE EfficiencyVariable PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -CREATE TABLE EmissionActivity +CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT @@ -359,7 +359,7 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -CREATE TABLE EmissionEmbodied +CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT @@ -373,7 +373,7 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE EmissionEndOfLife +CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT @@ -387,7 +387,7 @@ CREATE TABLE EmissionEndOfLife notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE ExistingCapacity +CREATE TABLE existing_capacity ( region TEXT, tech TEXT @@ -399,15 +399,15 @@ CREATE TABLE ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO ExistingCapacity VALUES('region','tech_ancient',1994,3.0,NULL,NULL); -INSERT INTO ExistingCapacity VALUES('region','tech_old',2010,0.7,NULL,NULL); +INSERT INTO existing_capacity VALUES('region','tech_ancient',1994,3.0,NULL,NULL); +INSERT INTO existing_capacity VALUES('region','tech_old',2010,0.7,NULL,NULL); CREATE TABLE TechGroup ( group_name TEXT PRIMARY KEY, notes TEXT ); -CREATE TABLE LoanLifetimeProcess +CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT @@ -418,7 +418,7 @@ CREATE TABLE LoanLifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LoanRate +CREATE TABLE loan_rate ( region TEXT, tech TEXT @@ -429,7 +429,7 @@ CREATE TABLE LoanRate notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeProcess +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -440,7 +440,7 @@ CREATE TABLE LifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeTech +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT @@ -449,10 +449,10 @@ CREATE TABLE LifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO LifetimeTech VALUES('region','tech_ancient',35.0,NULL); -INSERT INTO LifetimeTech VALUES('region','tech_old',35.0,NULL); -INSERT INTO LifetimeTech VALUES('region','tech_current',35.0,NULL); -INSERT INTO LifetimeTech VALUES('region','tech_future',35.0,NULL); +INSERT INTO lifetime_tech VALUES('region','tech_ancient',35.0,NULL); +INSERT INTO lifetime_tech VALUES('region','tech_old',35.0,NULL); +INSERT INTO lifetime_tech VALUES('region','tech_current',35.0,NULL); +INSERT INTO lifetime_tech VALUES('region','tech_future',35.0,NULL); CREATE TABLE Operator ( operator TEXT PRIMARY KEY, @@ -461,7 +461,7 @@ CREATE TABLE Operator INSERT INTO Operator VALUES('e','equal to'); INSERT INTO Operator VALUES('le','less than or equal to'); INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE LimitGrowthCapacity +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, @@ -473,7 +473,7 @@ CREATE TABLE LimitGrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthCapacity +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, @@ -485,7 +485,7 @@ CREATE TABLE LimitDegrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacity +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -497,7 +497,7 @@ CREATE TABLE LimitGrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -509,7 +509,7 @@ CREATE TABLE LimitDegrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacityDelta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -521,7 +521,7 @@ CREATE TABLE LimitGrowthNewCapacityDelta notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacityDelta +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -552,7 +552,7 @@ CREATE TABLE LimitStorageLevelFraction notes TEXT, PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE LimitActivity +CREATE TABLE limit_activity ( region TEXT, period INTEGER @@ -565,7 +565,7 @@ CREATE TABLE LimitActivity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitActivityShare +CREATE TABLE limit_activity_share ( region TEXT, period INTEGER @@ -578,7 +578,7 @@ CREATE TABLE LimitActivityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitAnnualCapacityFactor +CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER @@ -594,7 +594,7 @@ CREATE TABLE LimitAnnualCapacityFactor PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE LimitCapacity +CREATE TABLE limit_capacity ( region TEXT, period INTEGER @@ -607,7 +607,7 @@ CREATE TABLE LimitCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitCapacityShare +CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER @@ -620,7 +620,7 @@ CREATE TABLE LimitCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitNewCapacity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER @@ -633,7 +633,7 @@ CREATE TABLE LimitNewCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitNewCapacityShare +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -646,7 +646,7 @@ CREATE TABLE LimitNewCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitResource +CREATE TABLE limit_resource ( region TEXT, tech_or_group TEXT, @@ -657,7 +657,7 @@ CREATE TABLE LimitResource notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitSeasonalCapacityFactor +CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES Region (region), @@ -673,7 +673,7 @@ CREATE TABLE LimitSeasonalCapacityFactor notes TEXT, PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE LimitTechInputSplit +CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER @@ -688,7 +688,7 @@ CREATE TABLE LimitTechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechInputSplitAnnual +CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER @@ -703,7 +703,7 @@ CREATE TABLE LimitTechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechOutputSplit +CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER @@ -718,7 +718,7 @@ CREATE TABLE LimitTechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitTechOutputSplitAnnual +CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER @@ -733,7 +733,7 @@ CREATE TABLE LimitTechOutputSplitAnnual notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitEmission +CREATE TABLE limit_emission ( region TEXT, period INTEGER @@ -890,7 +890,7 @@ CREATE TABLE OutputStorageLevel level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); -CREATE TABLE PlanningReserveMargin +CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY @@ -898,7 +898,7 @@ CREATE TABLE PlanningReserveMargin margin REAL, notes TEXT ); -CREATE TABLE RampDownHourly +CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT @@ -907,7 +907,7 @@ CREATE TABLE RampDownHourly notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUpHourly +CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT @@ -923,7 +923,7 @@ CREATE TABLE Region notes TEXT ); INSERT INTO Region VALUES('region',NULL); -CREATE TABLE ReserveCapacityDerate +CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER @@ -939,7 +939,7 @@ CREATE TABLE ReserveCapacityDerate CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE TimeSegmentFraction -( +( period INTEGER REFERENCES TimePeriod (period), season TEXT @@ -957,7 +957,7 @@ INSERT INTO TimeSegmentFraction VALUES(2035,'s','d',1.0,NULL); INSERT INTO TimeSegmentFraction VALUES(2040,'s','d',1.0,NULL); INSERT INTO TimeSegmentFraction VALUES(2045,'s','d',1.0,NULL); INSERT INTO TimeSegmentFraction VALUES(2050,'s','d',1.0,NULL); -CREATE TABLE StorageDuration +CREATE TABLE storage_duration ( region TEXT, tech TEXT, @@ -965,7 +965,7 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE LifetimeSurvivalCurve +CREATE TABLE lifetime_survival_curve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -977,62 +977,62 @@ CREATE TABLE LifetimeSurvivalCurve notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO LifetimeSurvivalCurve VALUES('region',1994,'tech_ancient',1994,1,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',1999,'tech_ancient',1994,0.96999999999999992894,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2004,'tech_ancient',1994,0.88000000000000007105,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2009,'tech_ancient',1994,0.62000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2014,'tech_ancient',1994,0.27000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2019,'tech_ancient',1994,0.08,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2029,'tech_ancient',1994,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2010,'tech_old',2010,1,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2015,'tech_old',2010,0.96999999999999992894,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2020,'tech_old',2010,0.88000000000000007105,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2025,'tech_old',2010,0.62000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2030,'tech_old',2010,0.27000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_old',2010,0.08,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_old',2010,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2025,'tech_current',2025,1,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2030,'tech_current',2025,0.96999999999999992894,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_current',2025,0.88000000000000007105,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_current',2025,0.62000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_current',2025,0.27000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_current',2025,0.08,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_current',2025,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2030,'tech_future',2030,1,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_future',2030,0.96999999999999992894,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_future',2030,0.88000000000000007105,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2030,0.62000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2030,0.27000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2030,0.08,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2030,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2035,'tech_future',2035,1,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_future',2035,0.96999999999999992894,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2035,0.88000000000000007105,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2035,0.62000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2035,0.27000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2035,0.08,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2070,'tech_future',2035,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2040,'tech_future',2040,1,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2040,0.96999999999999992894,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2040,0.88000000000000007105,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2040,0.62000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2040,0.27000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2040,0.08,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2075,'tech_future',2040,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2045,'tech_future',2045,1,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2045,0.96999999999999992894,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2045,0.88000000000000007105,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2045,0.62000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2045,0.27000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2070,'tech_future',2045,0.08,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2080,'tech_future',2045,0.0,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2050,'tech_future',2050,1,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2055,'tech_future',2050,0.96999999999999992894,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2060,'tech_future',2050,0.88000000000000007105,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2065,'tech_future',2050,0.62000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2070,'tech_future',2050,0.27000000000000001776,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2075,'tech_future',2050,0.08,NULL); -INSERT INTO LifetimeSurvivalCurve VALUES('region',2085,'tech_future',2050,0.0,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',1994,'tech_ancient',1994,1,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',1999,'tech_ancient',1994,0.96999999999999992894,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2004,'tech_ancient',1994,0.88000000000000007105,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2009,'tech_ancient',1994,0.62000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2014,'tech_ancient',1994,0.27000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2019,'tech_ancient',1994,0.08,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2029,'tech_ancient',1994,0.0,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2010,'tech_old',2010,1,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2015,'tech_old',2010,0.96999999999999992894,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2020,'tech_old',2010,0.88000000000000007105,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2025,'tech_old',2010,0.62000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2030,'tech_old',2010,0.27000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2035,'tech_old',2010,0.08,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_old',2010,0.0,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2025,'tech_current',2025,1,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2030,'tech_current',2025,0.96999999999999992894,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2035,'tech_current',2025,0.88000000000000007105,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2040,'tech_current',2025,0.62000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_current',2025,0.27000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_current',2025,0.08,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2060,'tech_current',2025,0.0,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2030,'tech_future',2030,1,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2035,'tech_future',2030,0.96999999999999992894,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2040,'tech_future',2030,0.88000000000000007105,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_future',2030,0.62000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_future',2030,0.27000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2055,'tech_future',2030,0.08,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2065,'tech_future',2030,0.0,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2035,'tech_future',2035,1,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2040,'tech_future',2035,0.96999999999999992894,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_future',2035,0.88000000000000007105,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_future',2035,0.62000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2055,'tech_future',2035,0.27000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2060,'tech_future',2035,0.08,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2070,'tech_future',2035,0.0,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2040,'tech_future',2040,1,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_future',2040,0.96999999999999992894,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_future',2040,0.88000000000000007105,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2055,'tech_future',2040,0.62000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2060,'tech_future',2040,0.27000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2065,'tech_future',2040,0.08,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2075,'tech_future',2040,0.0,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_future',2045,1,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_future',2045,0.96999999999999992894,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2055,'tech_future',2045,0.88000000000000007105,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2060,'tech_future',2045,0.62000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2065,'tech_future',2045,0.27000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2070,'tech_future',2045,0.08,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2080,'tech_future',2045,0.0,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_future',2050,1,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2055,'tech_future',2050,0.96999999999999992894,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2060,'tech_future',2050,0.88000000000000007105,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2065,'tech_future',2050,0.62000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2070,'tech_future',2050,0.27000000000000001776,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2075,'tech_future',2050,0.08,NULL); +INSERT INTO lifetime_survival_curve VALUES('region',2085,'tech_future',2050,0.0,NULL); CREATE TABLE TechnologyType ( label TEXT @@ -1082,7 +1082,7 @@ INSERT INTO TimeSeason VALUES(2035,2,'s',NULL); INSERT INTO TimeSeason VALUES(2040,3,'s',NULL); INSERT INTO TimeSeason VALUES(2045,4,'s',NULL); INSERT INTO TimeSeason VALUES(2050,5,'s',NULL); -CREATE TABLE TimeSeasonSequential +CREATE TABLE time_season_sequential ( period INTEGER REFERENCES TimePeriod (period), diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 8933934ea..32f88b035 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -18,7 +18,7 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); CREATE TABLE OutputDualVariable ( @@ -53,7 +53,7 @@ INSERT INTO SectorLabel VALUES('transport',NULL); INSERT INTO SectorLabel VALUES('commercial',NULL); INSERT INTO SectorLabel VALUES('residential',NULL); INSERT INTO SectorLabel VALUES('industrial',NULL); -CREATE TABLE CapacityCredit +CREATE TABLE capacity_credit ( region TEXT, period INTEGER @@ -66,7 +66,7 @@ CREATE TABLE CapacityCredit PRIMARY KEY (region, period, tech, vintage), CHECK (credit >= 0 AND credit <= 1) ); -CREATE TABLE CapacityFactorProcess +CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER @@ -83,7 +83,7 @@ CREATE TABLE CapacityFactorProcess PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE CapacityFactorTech +CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER @@ -99,54 +99,54 @@ CREATE TABLE CapacityFactorTech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'spring','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'summer','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'fall','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'winter','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2020,'winter','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'spring','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'summer','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'fall','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'winter','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2020,'winter','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'spring','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'summer','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'fall','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'winter','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2025,'winter','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'spring','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'summer','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'fall','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'winter','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2025,'winter','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'spring','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'summer','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'fall','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'winter','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO CapacityFactorTech VALUES('R1',2030,'winter','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'spring','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'spring','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'summer','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'summer','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'fall','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'fall','night','E_SOLPV',0.0,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'winter','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO CapacityFactorTech VALUES('R2',2030,'winter','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2020,'spring','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2020,'spring','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2020,'summer','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2020,'summer','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2020,'fall','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2020,'fall','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2020,'winter','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2020,'winter','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2020,'spring','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2020,'spring','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2020,'summer','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2020,'summer','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2020,'fall','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2020,'fall','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2020,'winter','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2020,'winter','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2025,'spring','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2025,'spring','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2025,'summer','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2025,'summer','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2025,'fall','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2025,'fall','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2025,'winter','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2025,'winter','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2025,'spring','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2025,'spring','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2025,'summer','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2025,'summer','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2025,'fall','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2025,'fall','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2025,'winter','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2025,'winter','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2030,'spring','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2030,'spring','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2030,'summer','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2030,'summer','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2030,'fall','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2030,'fall','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R1',2030,'winter','day','E_SOLPV',0.5999999999999999778,''); +INSERT INTO capacity_factor_tech VALUES('R1',2030,'winter','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2030,'spring','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2030,'spring','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2030,'summer','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2030,'summer','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2030,'fall','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2030,'fall','night','E_SOLPV',0.0,''); +INSERT INTO capacity_factor_tech VALUES('R2',2030,'winter','day','E_SOLPV',0.4799999999999999823,''); +INSERT INTO capacity_factor_tech VALUES('R2',2030,'winter','night','E_SOLPV',0.0,''); CREATE TABLE CapacityToActivity ( region TEXT, @@ -223,7 +223,7 @@ INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); -CREATE TABLE ConstructionInput +CREATE TABLE construction_input ( region TEXT, input_comm TEXT @@ -237,7 +237,7 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -CREATE TABLE CostEmission +CREATE TABLE cost_emission ( region TEXT, period INTEGER @@ -249,7 +249,7 @@ CREATE TABLE CostEmission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -CREATE TABLE CostFixed +CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -263,55 +263,55 @@ CREATE TABLE CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostFixed VALUES('R1',2020,'E_NGCC',2020,30.60000000000000142,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_NGCC',2020,9.77999999999999937,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_NGCC',2025,9.77999999999999937,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2020,9.77999999999999937,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2025,9.77999999999999937,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NGCC',2030,9.77999999999999937,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2020,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_SOLPV',2025,9.099999999999999645,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2025,9.099999999999999645,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_SOLPV',2030,9.099999999999999645,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2020,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_NUCLEAR',2025,98.0999999999999801,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2025,98.0999999999999801,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_NUCLEAR',2030,98.0999999999999801,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2020,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2025,'E_BATT',2025,7.049999999999999823,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2025,7.049999999999999823,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R1',2030,'E_BATT',2030,7.049999999999999823,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2020,'E_NGCC',2020,24.48000000000000042,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_NGCC',2020,7.823999999999999844,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_NGCC',2025,7.823999999999999844,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2020,7.823999999999999844,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2025,7.823999999999999844,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NGCC',2030,7.823999999999999844,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2020,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_SOLPV',2025,7.280000000000000248,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2025,7.280000000000000248,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_SOLPV',2030,7.280000000000000248,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2020,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_NUCLEAR',2025,78.48000000000000397,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2025,78.48000000000000397,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_NUCLEAR',2030,78.48000000000000397,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2020,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2025,'E_BATT',2025,5.639999999999999681,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2025,5.639999999999999681,'$M/GWyr',''); -INSERT INTO CostFixed VALUES('R2',2030,'E_BATT',2030,5.639999999999999681,'$M/GWyr',''); -CREATE TABLE CostInvest +INSERT INTO cost_fixed VALUES('R1',2020,'E_NGCC',2020,30.60000000000000142,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2025,'E_NGCC',2020,9.77999999999999937,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2025,'E_NGCC',2025,9.77999999999999937,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_NGCC',2020,9.77999999999999937,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_NGCC',2025,9.77999999999999937,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_NGCC',2030,9.77999999999999937,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2020,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2025,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2025,'E_SOLPV',2025,9.099999999999999645,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_SOLPV',2025,9.099999999999999645,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_SOLPV',2030,9.099999999999999645,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2020,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2025,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2025,'E_NUCLEAR',2025,98.0999999999999801,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_NUCLEAR',2025,98.0999999999999801,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_NUCLEAR',2030,98.0999999999999801,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2020,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2025,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2025,'E_BATT',2025,7.049999999999999823,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_BATT',2025,7.049999999999999823,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R1',2030,'E_BATT',2030,7.049999999999999823,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2020,'E_NGCC',2020,24.48000000000000042,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2025,'E_NGCC',2020,7.823999999999999844,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2025,'E_NGCC',2025,7.823999999999999844,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_NGCC',2020,7.823999999999999844,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_NGCC',2025,7.823999999999999844,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_NGCC',2030,7.823999999999999844,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2020,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2025,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2025,'E_SOLPV',2025,7.280000000000000248,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_SOLPV',2025,7.280000000000000248,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_SOLPV',2030,7.280000000000000248,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2020,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2025,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2025,'E_NUCLEAR',2025,78.48000000000000397,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_NUCLEAR',2025,78.48000000000000397,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_NUCLEAR',2030,78.48000000000000397,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2020,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2025,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2025,'E_BATT',2025,5.639999999999999681,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_BATT',2025,5.639999999999999681,'$M/GWyr',''); +INSERT INTO cost_fixed VALUES('R2',2030,'E_BATT',2030,5.639999999999999681,'$M/GWyr',''); +CREATE TABLE cost_invest ( region TEXT, tech TEXT @@ -323,61 +323,61 @@ CREATE TABLE CostInvest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO CostInvest VALUES('R1','E_NGCC',2020,1050.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','E_NGCC',2025,1025.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','E_NGCC',2030,1000.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','E_SOLPV',2020,900.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','E_SOLPV',2025,560.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','E_SOLPV',2030,800.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','E_NUCLEAR',2020,6145.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','E_NUCLEAR',2025,6045.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','E_NUCLEAR',2030,5890.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','E_BATT',2020,1150.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','E_BATT',2025,720.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','E_BATT',2030,480.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R1','T_GSL',2020,2570.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R1','T_GSL',2025,2700.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R1','T_GSL',2030,2700.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R1','T_DSL',2020,2715.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R1','T_DSL',2025,2810.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R1','T_DSL',2030,2810.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R1','T_EV',2020,3100.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R1','T_EV',2025,3030.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R1','T_EV',2030,2925.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R1','R_EH',2020,4.099999999999999644,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_EH',2025,4.099999999999999644,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_EH',2030,4.099999999999999644,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_NGH',2020,7.599999999999999645,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_NGH',2025,7.599999999999999645,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R1','R_NGH',2030,7.599999999999999645,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R2','E_NGCC',2020,840.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','E_NGCC',2025,820.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','E_NGCC',2030,800.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','E_SOLPV',2020,720.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','E_SOLPV',2025,448.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','E_SOLPV',2030,640.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','E_NUCLEAR',2020,4916.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','E_NUCLEAR',2025,4836.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','E_NUCLEAR',2030,4712.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','E_BATT',2020,920.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','E_BATT',2025,576.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','E_BATT',2030,384.0,'$M/GW',''); -INSERT INTO CostInvest VALUES('R2','T_GSL',2020,2056.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R2','T_GSL',2025,2160.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R2','T_GSL',2030,2160.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R2','T_DSL',2020,2172.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R2','T_DSL',2025,2248.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R2','T_DSL',2030,2248.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R2','T_EV',2020,2480.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R2','T_EV',2025,2424.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R2','T_EV',2030,2340.0,'$/bvmt/yr',''); -INSERT INTO CostInvest VALUES('R2','R_EH',2020,3.279999999999999805,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R2','R_EH',2025,3.279999999999999805,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R2','R_EH',2030,3.279999999999999805,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R2','R_NGH',2020,6.080000000000000071,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R2','R_NGH',2025,6.080000000000000071,'$/PJ/yr',''); -INSERT INTO CostInvest VALUES('R2','R_NGH',2030,6.080000000000000071,'$/PJ/yr',''); -CREATE TABLE CostVariable +INSERT INTO cost_invest VALUES('R1','E_NGCC',2020,1050.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','E_NGCC',2025,1025.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','E_NGCC',2030,1000.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','E_SOLPV',2020,900.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','E_SOLPV',2025,560.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','E_SOLPV',2030,800.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','E_NUCLEAR',2020,6145.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','E_NUCLEAR',2025,6045.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','E_NUCLEAR',2030,5890.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','E_BATT',2020,1150.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','E_BATT',2025,720.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','E_BATT',2030,480.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R1','T_GSL',2020,2570.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R1','T_GSL',2025,2700.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R1','T_GSL',2030,2700.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R1','T_DSL',2020,2715.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R1','T_DSL',2025,2810.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R1','T_DSL',2030,2810.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R1','T_EV',2020,3100.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R1','T_EV',2025,3030.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R1','T_EV',2030,2925.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R1','R_EH',2020,4.099999999999999644,'$/PJ/yr',''); +INSERT INTO cost_invest VALUES('R1','R_EH',2025,4.099999999999999644,'$/PJ/yr',''); +INSERT INTO cost_invest VALUES('R1','R_EH',2030,4.099999999999999644,'$/PJ/yr',''); +INSERT INTO cost_invest VALUES('R1','R_NGH',2020,7.599999999999999645,'$/PJ/yr',''); +INSERT INTO cost_invest VALUES('R1','R_NGH',2025,7.599999999999999645,'$/PJ/yr',''); +INSERT INTO cost_invest VALUES('R1','R_NGH',2030,7.599999999999999645,'$/PJ/yr',''); +INSERT INTO cost_invest VALUES('R2','E_NGCC',2020,840.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','E_NGCC',2025,820.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','E_NGCC',2030,800.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','E_SOLPV',2020,720.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','E_SOLPV',2025,448.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','E_SOLPV',2030,640.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','E_NUCLEAR',2020,4916.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','E_NUCLEAR',2025,4836.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','E_NUCLEAR',2030,4712.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','E_BATT',2020,920.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','E_BATT',2025,576.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','E_BATT',2030,384.0,'$M/GW',''); +INSERT INTO cost_invest VALUES('R2','T_GSL',2020,2056.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R2','T_GSL',2025,2160.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R2','T_GSL',2030,2160.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R2','T_DSL',2020,2172.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R2','T_DSL',2025,2248.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R2','T_DSL',2030,2248.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R2','T_EV',2020,2480.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R2','T_EV',2025,2424.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R2','T_EV',2030,2340.0,'$/bvmt/yr',''); +INSERT INTO cost_invest VALUES('R2','R_EH',2020,3.279999999999999805,'$/PJ/yr',''); +INSERT INTO cost_invest VALUES('R2','R_EH',2025,3.279999999999999805,'$/PJ/yr',''); +INSERT INTO cost_invest VALUES('R2','R_EH',2030,3.279999999999999805,'$/PJ/yr',''); +INSERT INTO cost_invest VALUES('R2','R_NGH',2020,6.080000000000000071,'$/PJ/yr',''); +INSERT INTO cost_invest VALUES('R2','R_NGH',2025,6.080000000000000071,'$/PJ/yr',''); +INSERT INTO cost_invest VALUES('R2','R_NGH',2030,6.080000000000000071,'$/PJ/yr',''); +CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -391,60 +391,60 @@ CREATE TABLE CostVariable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostVariable VALUES('R1',2020,'S_IMPETH',2020,32.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'S_IMPETH',2020,32.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'S_IMPETH',2020,32.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2020,'S_IMPOIL',2020,20.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'S_IMPOIL',2020,20.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'S_IMPOIL',2020,20.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2020,'S_IMPNG',2020,4.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'S_IMPNG',2020,4.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'S_IMPNG',2020,4.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2020,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2020,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'E_NGCC',2025,1.699999999999999956,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2025,1.699999999999999956,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NGCC',2030,1.800000000000000044,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2020,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2025,'E_NUCLEAR',2025,0.25,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2025,0.25,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1',2030,'E_NUCLEAR',2030,0.2600000000000000088,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'E_NGCC',2025,1.360000000000000097,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2025,1.360000000000000097,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NGCC',2030,1.439999999999999947,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2020,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2025,'E_NUCLEAR',2025,0.2000000000000000111,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2025,0.2000000000000000111,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2',2030,'E_NUCLEAR',2030,0.2080000000000000183,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1-R2',2020,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1-R2',2025,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R1-R2',2030,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2-R1',2020,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2-R1',2025,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO CostVariable VALUES('R2-R1',2030,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2020,'S_IMPETH',2020,32.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2025,'S_IMPETH',2020,32.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2030,'S_IMPETH',2020,32.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2020,'S_IMPOIL',2020,20.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2025,'S_IMPOIL',2020,20.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2030,'S_IMPOIL',2020,20.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2020,'S_IMPNG',2020,4.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2025,'S_IMPNG',2020,4.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2030,'S_IMPNG',2020,4.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2020,'S_OILREF',2020,1.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2025,'S_OILREF',2020,1.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2030,'S_OILREF',2020,1.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2020,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2025,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2025,'E_NGCC',2025,1.699999999999999956,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2030,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2030,'E_NGCC',2025,1.699999999999999956,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2030,'E_NGCC',2030,1.800000000000000044,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2020,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2025,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2025,'E_NUCLEAR',2025,0.25,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2030,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2030,'E_NUCLEAR',2025,0.25,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1',2030,'E_NUCLEAR',2030,0.2600000000000000088,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2020,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2025,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2030,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2020,'S_IMPOIL',2020,16.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2025,'S_IMPOIL',2020,16.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2030,'S_IMPOIL',2020,16.0,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2020,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2025,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2030,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2020,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2025,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2030,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2020,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2025,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2025,'E_NGCC',2025,1.360000000000000097,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2030,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2030,'E_NGCC',2025,1.360000000000000097,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2030,'E_NGCC',2030,1.439999999999999947,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2020,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2025,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2025,'E_NUCLEAR',2025,0.2000000000000000111,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2030,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2030,'E_NUCLEAR',2025,0.2000000000000000111,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2',2030,'E_NUCLEAR',2030,0.2080000000000000183,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1-R2',2020,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1-R2',2025,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R1-R2',2030,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2-R1',2020,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2-R1',2025,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO cost_variable VALUES('R2-R1',2030,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); CREATE TABLE Demand ( region TEXT, @@ -533,7 +533,7 @@ INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'fall','day','RH',0.0500 INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'fall','night','RH',0.1000000000000000055,''); INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'winter','day','RH',0.2999999999999999889,''); INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'winter','night','RH',0.4000000000000000222,''); -CREATE TABLE EndOfLifeOutput +CREATE TABLE end_of_life_output ( region TEXT, tech TEXT @@ -547,7 +547,7 @@ CREATE TABLE EndOfLifeOutput notes TEXT, PRIMARY KEY (region, tech, vintage, output_comm) ); -CREATE TABLE Efficiency +CREATE TABLE efficiency ( region TEXT, input_comm TEXT @@ -563,81 +563,81 @@ CREATE TABLE Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO Efficiency VALUES('R1','ethos','S_IMPETH',2020,'ETH',1.0,''); -INSERT INTO Efficiency VALUES('R1','ethos','S_IMPOIL',2020,'OIL',1.0,''); -INSERT INTO Efficiency VALUES('R1','ethos','S_IMPNG',2020,'NG',1.0,''); -INSERT INTO Efficiency VALUES('R1','ethos','S_IMPURN',2020,'URN',1.0,''); -INSERT INTO Efficiency VALUES('R1','OIL','S_OILREF',2020,'GSL',1.0,''); -INSERT INTO Efficiency VALUES('R1','OIL','S_OILREF',2020,'DSL',1.0,''); -INSERT INTO Efficiency VALUES('R1','ETH','T_BLND',2020,'E10',1.0,''); -INSERT INTO Efficiency VALUES('R1','GSL','T_BLND',2020,'E10',1.0,''); -INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2020,'ELC',0.5500000000000000444,''); -INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2025,'ELC',0.5500000000000000444,''); -INSERT INTO Efficiency VALUES('R1','NG','E_NGCC',2030,'ELC',0.5500000000000000444,''); -INSERT INTO Efficiency VALUES('R1','SOL','E_SOLPV',2020,'ELC',1.0,''); -INSERT INTO Efficiency VALUES('R1','SOL','E_SOLPV',2025,'ELC',1.0,''); -INSERT INTO Efficiency VALUES('R1','SOL','E_SOLPV',2030,'ELC',1.0,''); -INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2015,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2020,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2025,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R1','URN','E_NUCLEAR',2030,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2020,'ELC',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2025,'ELC',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R1','ELC','E_BATT',2030,'ELC',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R1','E10','T_GSL',2020,'VMT',0.25,''); -INSERT INTO Efficiency VALUES('R1','E10','T_GSL',2025,'VMT',0.25,''); -INSERT INTO Efficiency VALUES('R1','E10','T_GSL',2030,'VMT',0.25,''); -INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2020,'VMT',0.2999999999999999889,''); -INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2025,'VMT',0.2999999999999999889,''); -INSERT INTO Efficiency VALUES('R1','DSL','T_DSL',2030,'VMT',0.2999999999999999889,''); -INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2020,'VMT',0.8900000000000000133,''); -INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2025,'VMT',0.8900000000000000133,''); -INSERT INTO Efficiency VALUES('R1','ELC','T_EV',2030,'VMT',0.8900000000000000133,''); -INSERT INTO Efficiency VALUES('R1','ELC','R_EH',2020,'RH',1.0,''); -INSERT INTO Efficiency VALUES('R1','ELC','R_EH',2025,'RH',1.0,''); -INSERT INTO Efficiency VALUES('R1','ELC','R_EH',2030,'RH',1.0,''); -INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2020,'RH',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2025,'RH',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R1','NG','R_NGH',2030,'RH',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R2','ethos','S_IMPETH',2020,'ETH',1.0,''); -INSERT INTO Efficiency VALUES('R2','ethos','S_IMPOIL',2020,'OIL',1.0,''); -INSERT INTO Efficiency VALUES('R2','ethos','S_IMPNG',2020,'NG',1.0,''); -INSERT INTO Efficiency VALUES('R2','ethos','S_IMPURN',2020,'URN',1.0,''); -INSERT INTO Efficiency VALUES('R2','OIL','S_OILREF',2020,'GSL',1.0,''); -INSERT INTO Efficiency VALUES('R2','OIL','S_OILREF',2020,'DSL',1.0,''); -INSERT INTO Efficiency VALUES('R2','ETH','T_BLND',2020,'E10',1.0,''); -INSERT INTO Efficiency VALUES('R2','GSL','T_BLND',2020,'E10',1.0,''); -INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2020,'ELC',0.5500000000000000444,''); -INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2025,'ELC',0.5500000000000000444,''); -INSERT INTO Efficiency VALUES('R2','NG','E_NGCC',2030,'ELC',0.5500000000000000444,''); -INSERT INTO Efficiency VALUES('R2','SOL','E_SOLPV',2020,'ELC',1.0,''); -INSERT INTO Efficiency VALUES('R2','SOL','E_SOLPV',2025,'ELC',1.0,''); -INSERT INTO Efficiency VALUES('R2','SOL','E_SOLPV',2030,'ELC',1.0,''); -INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2015,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2020,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2025,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R2','URN','E_NUCLEAR',2030,'ELC',0.4000000000000000222,''); -INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2020,'ELC',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2025,'ELC',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R2','ELC','E_BATT',2030,'ELC',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R2','E10','T_GSL',2020,'VMT',0.25,''); -INSERT INTO Efficiency VALUES('R2','E10','T_GSL',2025,'VMT',0.25,''); -INSERT INTO Efficiency VALUES('R2','E10','T_GSL',2030,'VMT',0.25,''); -INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2020,'VMT',0.2999999999999999889,''); -INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2025,'VMT',0.2999999999999999889,''); -INSERT INTO Efficiency VALUES('R2','DSL','T_DSL',2030,'VMT',0.2999999999999999889,''); -INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2020,'VMT',0.8900000000000000133,''); -INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2025,'VMT',0.8900000000000000133,''); -INSERT INTO Efficiency VALUES('R2','ELC','T_EV',2030,'VMT',0.8900000000000000133,''); -INSERT INTO Efficiency VALUES('R2','ELC','R_EH',2020,'RH',1.0,''); -INSERT INTO Efficiency VALUES('R2','ELC','R_EH',2025,'RH',1.0,''); -INSERT INTO Efficiency VALUES('R2','ELC','R_EH',2030,'RH',1.0,''); -INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2020,'RH',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2025,'RH',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R2','NG','R_NGH',2030,'RH',0.8499999999999999778,''); -INSERT INTO Efficiency VALUES('R1-R2','ELC','E_TRANS',2015,'ELC',0.9000000000000000222,''); -INSERT INTO Efficiency VALUES('R2-R1','ELC','E_TRANS',2015,'ELC',0.9000000000000000222,''); -CREATE TABLE EfficiencyVariable +INSERT INTO efficiency VALUES('R1','ethos','S_IMPETH',2020,'ETH',1.0,''); +INSERT INTO efficiency VALUES('R1','ethos','S_IMPOIL',2020,'OIL',1.0,''); +INSERT INTO efficiency VALUES('R1','ethos','S_IMPNG',2020,'NG',1.0,''); +INSERT INTO efficiency VALUES('R1','ethos','S_IMPURN',2020,'URN',1.0,''); +INSERT INTO efficiency VALUES('R1','OIL','S_OILREF',2020,'GSL',1.0,''); +INSERT INTO efficiency VALUES('R1','OIL','S_OILREF',2020,'DSL',1.0,''); +INSERT INTO efficiency VALUES('R1','ETH','T_BLND',2020,'E10',1.0,''); +INSERT INTO efficiency VALUES('R1','GSL','T_BLND',2020,'E10',1.0,''); +INSERT INTO efficiency VALUES('R1','NG','E_NGCC',2020,'ELC',0.5500000000000000444,''); +INSERT INTO efficiency VALUES('R1','NG','E_NGCC',2025,'ELC',0.5500000000000000444,''); +INSERT INTO efficiency VALUES('R1','NG','E_NGCC',2030,'ELC',0.5500000000000000444,''); +INSERT INTO efficiency VALUES('R1','SOL','E_SOLPV',2020,'ELC',1.0,''); +INSERT INTO efficiency VALUES('R1','SOL','E_SOLPV',2025,'ELC',1.0,''); +INSERT INTO efficiency VALUES('R1','SOL','E_SOLPV',2030,'ELC',1.0,''); +INSERT INTO efficiency VALUES('R1','URN','E_NUCLEAR',2015,'ELC',0.4000000000000000222,''); +INSERT INTO efficiency VALUES('R1','URN','E_NUCLEAR',2020,'ELC',0.4000000000000000222,''); +INSERT INTO efficiency VALUES('R1','URN','E_NUCLEAR',2025,'ELC',0.4000000000000000222,''); +INSERT INTO efficiency VALUES('R1','URN','E_NUCLEAR',2030,'ELC',0.4000000000000000222,''); +INSERT INTO efficiency VALUES('R1','ELC','E_BATT',2020,'ELC',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R1','ELC','E_BATT',2025,'ELC',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R1','ELC','E_BATT',2030,'ELC',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R1','E10','T_GSL',2020,'VMT',0.25,''); +INSERT INTO efficiency VALUES('R1','E10','T_GSL',2025,'VMT',0.25,''); +INSERT INTO efficiency VALUES('R1','E10','T_GSL',2030,'VMT',0.25,''); +INSERT INTO efficiency VALUES('R1','DSL','T_DSL',2020,'VMT',0.2999999999999999889,''); +INSERT INTO efficiency VALUES('R1','DSL','T_DSL',2025,'VMT',0.2999999999999999889,''); +INSERT INTO efficiency VALUES('R1','DSL','T_DSL',2030,'VMT',0.2999999999999999889,''); +INSERT INTO efficiency VALUES('R1','ELC','T_EV',2020,'VMT',0.8900000000000000133,''); +INSERT INTO efficiency VALUES('R1','ELC','T_EV',2025,'VMT',0.8900000000000000133,''); +INSERT INTO efficiency VALUES('R1','ELC','T_EV',2030,'VMT',0.8900000000000000133,''); +INSERT INTO efficiency VALUES('R1','ELC','R_EH',2020,'RH',1.0,''); +INSERT INTO efficiency VALUES('R1','ELC','R_EH',2025,'RH',1.0,''); +INSERT INTO efficiency VALUES('R1','ELC','R_EH',2030,'RH',1.0,''); +INSERT INTO efficiency VALUES('R1','NG','R_NGH',2020,'RH',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R1','NG','R_NGH',2025,'RH',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R1','NG','R_NGH',2030,'RH',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R2','ethos','S_IMPETH',2020,'ETH',1.0,''); +INSERT INTO efficiency VALUES('R2','ethos','S_IMPOIL',2020,'OIL',1.0,''); +INSERT INTO efficiency VALUES('R2','ethos','S_IMPNG',2020,'NG',1.0,''); +INSERT INTO efficiency VALUES('R2','ethos','S_IMPURN',2020,'URN',1.0,''); +INSERT INTO efficiency VALUES('R2','OIL','S_OILREF',2020,'GSL',1.0,''); +INSERT INTO efficiency VALUES('R2','OIL','S_OILREF',2020,'DSL',1.0,''); +INSERT INTO efficiency VALUES('R2','ETH','T_BLND',2020,'E10',1.0,''); +INSERT INTO efficiency VALUES('R2','GSL','T_BLND',2020,'E10',1.0,''); +INSERT INTO efficiency VALUES('R2','NG','E_NGCC',2020,'ELC',0.5500000000000000444,''); +INSERT INTO efficiency VALUES('R2','NG','E_NGCC',2025,'ELC',0.5500000000000000444,''); +INSERT INTO efficiency VALUES('R2','NG','E_NGCC',2030,'ELC',0.5500000000000000444,''); +INSERT INTO efficiency VALUES('R2','SOL','E_SOLPV',2020,'ELC',1.0,''); +INSERT INTO efficiency VALUES('R2','SOL','E_SOLPV',2025,'ELC',1.0,''); +INSERT INTO efficiency VALUES('R2','SOL','E_SOLPV',2030,'ELC',1.0,''); +INSERT INTO efficiency VALUES('R2','URN','E_NUCLEAR',2015,'ELC',0.4000000000000000222,''); +INSERT INTO efficiency VALUES('R2','URN','E_NUCLEAR',2020,'ELC',0.4000000000000000222,''); +INSERT INTO efficiency VALUES('R2','URN','E_NUCLEAR',2025,'ELC',0.4000000000000000222,''); +INSERT INTO efficiency VALUES('R2','URN','E_NUCLEAR',2030,'ELC',0.4000000000000000222,''); +INSERT INTO efficiency VALUES('R2','ELC','E_BATT',2020,'ELC',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R2','ELC','E_BATT',2025,'ELC',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R2','ELC','E_BATT',2030,'ELC',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R2','E10','T_GSL',2020,'VMT',0.25,''); +INSERT INTO efficiency VALUES('R2','E10','T_GSL',2025,'VMT',0.25,''); +INSERT INTO efficiency VALUES('R2','E10','T_GSL',2030,'VMT',0.25,''); +INSERT INTO efficiency VALUES('R2','DSL','T_DSL',2020,'VMT',0.2999999999999999889,''); +INSERT INTO efficiency VALUES('R2','DSL','T_DSL',2025,'VMT',0.2999999999999999889,''); +INSERT INTO efficiency VALUES('R2','DSL','T_DSL',2030,'VMT',0.2999999999999999889,''); +INSERT INTO efficiency VALUES('R2','ELC','T_EV',2020,'VMT',0.8900000000000000133,''); +INSERT INTO efficiency VALUES('R2','ELC','T_EV',2025,'VMT',0.8900000000000000133,''); +INSERT INTO efficiency VALUES('R2','ELC','T_EV',2030,'VMT',0.8900000000000000133,''); +INSERT INTO efficiency VALUES('R2','ELC','R_EH',2020,'RH',1.0,''); +INSERT INTO efficiency VALUES('R2','ELC','R_EH',2025,'RH',1.0,''); +INSERT INTO efficiency VALUES('R2','ELC','R_EH',2030,'RH',1.0,''); +INSERT INTO efficiency VALUES('R2','NG','R_NGH',2020,'RH',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R2','NG','R_NGH',2025,'RH',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R2','NG','R_NGH',2030,'RH',0.8499999999999999778,''); +INSERT INTO efficiency VALUES('R1-R2','ELC','E_TRANS',2015,'ELC',0.9000000000000000222,''); +INSERT INTO efficiency VALUES('R2-R1','ELC','E_TRANS',2015,'ELC',0.9000000000000000222,''); +CREATE TABLE efficiency_variable ( region TEXT, period INTEGER @@ -659,7 +659,7 @@ CREATE TABLE EfficiencyVariable PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -CREATE TABLE EmissionActivity +CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT @@ -677,13 +677,13 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('R1','CO2','ethos','S_IMPNG',2020,'NG',50.29999999999999005,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R1','CO2','OIL','S_OILREF',2020,'GSL',67.20000000000000284,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R1','CO2','OIL','S_OILREF',2020,'DSL',69.40000000000000569,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R2','CO2','ethos','S_IMPNG',2020,'NG',50.29999999999999005,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R2','CO2','OIL','S_OILREF',2020,'GSL',67.20000000000000284,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO EmissionActivity VALUES('R2','CO2','OIL','S_OILREF',2020,'DSL',69.40000000000000569,'kT/PJ','taken from MIT Energy Fact Sheet'); -CREATE TABLE EmissionEmbodied +INSERT INTO emission_activity VALUES('R1','CO2','ethos','S_IMPNG',2020,'NG',50.29999999999999005,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO emission_activity VALUES('R1','CO2','OIL','S_OILREF',2020,'GSL',67.20000000000000284,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO emission_activity VALUES('R1','CO2','OIL','S_OILREF',2020,'DSL',69.40000000000000569,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO emission_activity VALUES('R2','CO2','ethos','S_IMPNG',2020,'NG',50.29999999999999005,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO emission_activity VALUES('R2','CO2','OIL','S_OILREF',2020,'GSL',67.20000000000000284,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO emission_activity VALUES('R2','CO2','OIL','S_OILREF',2020,'DSL',69.40000000000000569,'kT/PJ','taken from MIT Energy Fact Sheet'); +CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT @@ -697,7 +697,7 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE EmissionEndOfLife +CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT @@ -711,7 +711,7 @@ CREATE TABLE EmissionEndOfLife notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE ExistingCapacity +CREATE TABLE existing_capacity ( region TEXT, tech TEXT @@ -723,17 +723,17 @@ CREATE TABLE ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO ExistingCapacity VALUES('R1','E_NUCLEAR',2015,0.07000000000000000667,'GW',''); -INSERT INTO ExistingCapacity VALUES('R2','E_NUCLEAR',2015,0.02999999999999999889,'GW',''); -INSERT INTO ExistingCapacity VALUES('R1-R2','E_TRANS',2015,10.0,'GW',''); -INSERT INTO ExistingCapacity VALUES('R2-R1','E_TRANS',2015,10.0,'GW',''); +INSERT INTO existing_capacity VALUES('R1','E_NUCLEAR',2015,0.07000000000000000667,'GW',''); +INSERT INTO existing_capacity VALUES('R2','E_NUCLEAR',2015,0.02999999999999999889,'GW',''); +INSERT INTO existing_capacity VALUES('R1-R2','E_TRANS',2015,10.0,'GW',''); +INSERT INTO existing_capacity VALUES('R2-R1','E_TRANS',2015,10.0,'GW',''); CREATE TABLE TechGroup ( group_name TEXT PRIMARY KEY, notes TEXT ); -CREATE TABLE LoanLifetimeProcess +CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT @@ -744,7 +744,7 @@ CREATE TABLE LoanLifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LoanRate +CREATE TABLE loan_rate ( region TEXT, tech TEXT @@ -755,7 +755,7 @@ CREATE TABLE LoanRate notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeProcess +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -766,7 +766,7 @@ CREATE TABLE LifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeTech +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT @@ -775,38 +775,38 @@ CREATE TABLE LifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO LifetimeTech VALUES('R1','S_IMPETH',100.0,''); -INSERT INTO LifetimeTech VALUES('R1','S_IMPOIL',100.0,''); -INSERT INTO LifetimeTech VALUES('R1','S_IMPNG',100.0,''); -INSERT INTO LifetimeTech VALUES('R1','S_IMPURN',100.0,''); -INSERT INTO LifetimeTech VALUES('R1','S_OILREF',100.0,''); -INSERT INTO LifetimeTech VALUES('R1','E_NGCC',30.0,''); -INSERT INTO LifetimeTech VALUES('R1','E_SOLPV',30.0,''); -INSERT INTO LifetimeTech VALUES('R1','E_BATT',20.0,''); -INSERT INTO LifetimeTech VALUES('R1','E_NUCLEAR',50.0,''); -INSERT INTO LifetimeTech VALUES('R1','T_BLND',100.0,''); -INSERT INTO LifetimeTech VALUES('R1','T_DSL',12.0,''); -INSERT INTO LifetimeTech VALUES('R1','T_GSL',12.0,''); -INSERT INTO LifetimeTech VALUES('R1','T_EV',12.0,''); -INSERT INTO LifetimeTech VALUES('R1','R_EH',20.0,''); -INSERT INTO LifetimeTech VALUES('R1','R_NGH',20.0,''); -INSERT INTO LifetimeTech VALUES('R2','S_IMPETH',100.0,''); -INSERT INTO LifetimeTech VALUES('R2','S_IMPOIL',100.0,''); -INSERT INTO LifetimeTech VALUES('R2','S_IMPNG',100.0,''); -INSERT INTO LifetimeTech VALUES('R2','S_IMPURN',100.0,''); -INSERT INTO LifetimeTech VALUES('R2','S_OILREF',100.0,''); -INSERT INTO LifetimeTech VALUES('R2','E_NGCC',30.0,''); -INSERT INTO LifetimeTech VALUES('R2','E_SOLPV',30.0,''); -INSERT INTO LifetimeTech VALUES('R2','E_BATT',20.0,''); -INSERT INTO LifetimeTech VALUES('R2','E_NUCLEAR',50.0,''); -INSERT INTO LifetimeTech VALUES('R2','T_BLND',100.0,''); -INSERT INTO LifetimeTech VALUES('R2','T_DSL',12.0,''); -INSERT INTO LifetimeTech VALUES('R2','T_GSL',12.0,''); -INSERT INTO LifetimeTech VALUES('R2','T_EV',12.0,''); -INSERT INTO LifetimeTech VALUES('R2','R_EH',20.0,''); -INSERT INTO LifetimeTech VALUES('R2','R_NGH',20.0,''); -INSERT INTO LifetimeTech VALUES('R1-R2','E_TRANS',30.0,''); -INSERT INTO LifetimeTech VALUES('R2-R1','E_TRANS',30.0,''); +INSERT INTO lifetime_tech VALUES('R1','S_IMPETH',100.0,''); +INSERT INTO lifetime_tech VALUES('R1','S_IMPOIL',100.0,''); +INSERT INTO lifetime_tech VALUES('R1','S_IMPNG',100.0,''); +INSERT INTO lifetime_tech VALUES('R1','S_IMPURN',100.0,''); +INSERT INTO lifetime_tech VALUES('R1','S_OILREF',100.0,''); +INSERT INTO lifetime_tech VALUES('R1','E_NGCC',30.0,''); +INSERT INTO lifetime_tech VALUES('R1','E_SOLPV',30.0,''); +INSERT INTO lifetime_tech VALUES('R1','E_BATT',20.0,''); +INSERT INTO lifetime_tech VALUES('R1','E_NUCLEAR',50.0,''); +INSERT INTO lifetime_tech VALUES('R1','T_BLND',100.0,''); +INSERT INTO lifetime_tech VALUES('R1','T_DSL',12.0,''); +INSERT INTO lifetime_tech VALUES('R1','T_GSL',12.0,''); +INSERT INTO lifetime_tech VALUES('R1','T_EV',12.0,''); +INSERT INTO lifetime_tech VALUES('R1','R_EH',20.0,''); +INSERT INTO lifetime_tech VALUES('R1','R_NGH',20.0,''); +INSERT INTO lifetime_tech VALUES('R2','S_IMPETH',100.0,''); +INSERT INTO lifetime_tech VALUES('R2','S_IMPOIL',100.0,''); +INSERT INTO lifetime_tech VALUES('R2','S_IMPNG',100.0,''); +INSERT INTO lifetime_tech VALUES('R2','S_IMPURN',100.0,''); +INSERT INTO lifetime_tech VALUES('R2','S_OILREF',100.0,''); +INSERT INTO lifetime_tech VALUES('R2','E_NGCC',30.0,''); +INSERT INTO lifetime_tech VALUES('R2','E_SOLPV',30.0,''); +INSERT INTO lifetime_tech VALUES('R2','E_BATT',20.0,''); +INSERT INTO lifetime_tech VALUES('R2','E_NUCLEAR',50.0,''); +INSERT INTO lifetime_tech VALUES('R2','T_BLND',100.0,''); +INSERT INTO lifetime_tech VALUES('R2','T_DSL',12.0,''); +INSERT INTO lifetime_tech VALUES('R2','T_GSL',12.0,''); +INSERT INTO lifetime_tech VALUES('R2','T_EV',12.0,''); +INSERT INTO lifetime_tech VALUES('R2','R_EH',20.0,''); +INSERT INTO lifetime_tech VALUES('R2','R_NGH',20.0,''); +INSERT INTO lifetime_tech VALUES('R1-R2','E_TRANS',30.0,''); +INSERT INTO lifetime_tech VALUES('R2-R1','E_TRANS',30.0,''); CREATE TABLE Operator ( operator TEXT PRIMARY KEY, @@ -815,7 +815,7 @@ CREATE TABLE Operator INSERT INTO Operator VALUES('e','equal to'); INSERT INTO Operator VALUES('le','less than or equal to'); INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE LimitGrowthCapacity +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, @@ -827,7 +827,7 @@ CREATE TABLE LimitGrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthCapacity +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, @@ -839,7 +839,7 @@ CREATE TABLE LimitDegrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacity +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -851,7 +851,7 @@ CREATE TABLE LimitGrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -863,7 +863,7 @@ CREATE TABLE LimitDegrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacityDelta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -875,7 +875,7 @@ CREATE TABLE LimitGrowthNewCapacityDelta notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacityDelta +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -908,7 +908,7 @@ CREATE TABLE LimitStorageLevelFraction ); INSERT INTO LimitStorageLevelFraction VALUES('R1',2025,'winter','day','E_BATT',2025,'e',0.5,''); INSERT INTO LimitStorageLevelFraction VALUES('R2',2020,'summer','day','E_BATT',2020,'e',0.5,''); -CREATE TABLE LimitActivity +CREATE TABLE limit_activity ( region TEXT, period INTEGER @@ -921,13 +921,13 @@ CREATE TABLE LimitActivity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO LimitActivity VALUES('R1',2020,'T_GSL','ge',35.0,'',''); -INSERT INTO LimitActivity VALUES('R1',2025,'T_GSL','ge',35.0,'',''); -INSERT INTO LimitActivity VALUES('R1',2030,'T_GSL','ge',35.0,'',''); -INSERT INTO LimitActivity VALUES('R2',2020,'T_GSL','ge',15.0,'',''); -INSERT INTO LimitActivity VALUES('R2',2025,'T_GSL','ge',15.0,'',''); -INSERT INTO LimitActivity VALUES('R2',2030,'T_GSL','ge',15.0,'',''); -CREATE TABLE LimitActivityShare +INSERT INTO limit_activity VALUES('R1',2020,'T_GSL','ge',35.0,'',''); +INSERT INTO limit_activity VALUES('R1',2025,'T_GSL','ge',35.0,'',''); +INSERT INTO limit_activity VALUES('R1',2030,'T_GSL','ge',35.0,'',''); +INSERT INTO limit_activity VALUES('R2',2020,'T_GSL','ge',15.0,'',''); +INSERT INTO limit_activity VALUES('R2',2025,'T_GSL','ge',15.0,'',''); +INSERT INTO limit_activity VALUES('R2',2030,'T_GSL','ge',15.0,'',''); +CREATE TABLE limit_activity_share ( region TEXT, period INTEGER @@ -940,7 +940,7 @@ CREATE TABLE LimitActivityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitAnnualCapacityFactor +CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER @@ -956,7 +956,7 @@ CREATE TABLE LimitAnnualCapacityFactor PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE LimitCapacity +CREATE TABLE limit_capacity ( region TEXT, period INTEGER @@ -969,7 +969,7 @@ CREATE TABLE LimitCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitCapacityShare +CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER @@ -982,7 +982,7 @@ CREATE TABLE LimitCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitNewCapacity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER @@ -995,7 +995,7 @@ CREATE TABLE LimitNewCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitNewCapacityShare +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -1008,7 +1008,7 @@ CREATE TABLE LimitNewCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitResource +CREATE TABLE limit_resource ( region TEXT, tech_or_group TEXT, @@ -1019,7 +1019,7 @@ CREATE TABLE LimitResource notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitSeasonalCapacityFactor +CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES Region (region), @@ -1035,7 +1035,7 @@ CREATE TABLE LimitSeasonalCapacityFactor notes TEXT, PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE LimitTechInputSplit +CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER @@ -1050,19 +1050,19 @@ CREATE TABLE LimitTechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -INSERT INTO LimitTechInputSplit VALUES('R1',2020,'GSL','T_BLND','ge',0.9000000000000000222,''); -INSERT INTO LimitTechInputSplit VALUES('R1',2020,'ETH','T_BLND','ge',0.1000000000000000055,''); -INSERT INTO LimitTechInputSplit VALUES('R1',2025,'GSL','T_BLND','ge',0.9000000000000000222,''); -INSERT INTO LimitTechInputSplit VALUES('R1',2025,'ETH','T_BLND','ge',0.1000000000000000055,''); -INSERT INTO LimitTechInputSplit VALUES('R1',2030,'GSL','T_BLND','ge',0.9000000000000000222,''); -INSERT INTO LimitTechInputSplit VALUES('R1',2030,'ETH','T_BLND','ge',0.1000000000000000055,''); -INSERT INTO LimitTechInputSplit VALUES('R2',2020,'GSL','T_BLND','ge',0.7199999999999999734,''); -INSERT INTO LimitTechInputSplit VALUES('R2',2020,'ETH','T_BLND','ge',0.08000000000000000166,''); -INSERT INTO LimitTechInputSplit VALUES('R2',2025,'GSL','T_BLND','ge',0.7199999999999999734,''); -INSERT INTO LimitTechInputSplit VALUES('R2',2025,'ETH','T_BLND','ge',0.08000000000000000166,''); -INSERT INTO LimitTechInputSplit VALUES('R2',2030,'GSL','T_BLND','ge',0.7199999999999999734,''); -INSERT INTO LimitTechInputSplit VALUES('R2',2030,'ETH','T_BLND','ge',0.08000000000000000166,''); -CREATE TABLE LimitTechInputSplitAnnual +INSERT INTO limit_tech_input_split VALUES('R1',2020,'GSL','T_BLND','ge',0.9000000000000000222,''); +INSERT INTO limit_tech_input_split VALUES('R1',2020,'ETH','T_BLND','ge',0.1000000000000000055,''); +INSERT INTO limit_tech_input_split VALUES('R1',2025,'GSL','T_BLND','ge',0.9000000000000000222,''); +INSERT INTO limit_tech_input_split VALUES('R1',2025,'ETH','T_BLND','ge',0.1000000000000000055,''); +INSERT INTO limit_tech_input_split VALUES('R1',2030,'GSL','T_BLND','ge',0.9000000000000000222,''); +INSERT INTO limit_tech_input_split VALUES('R1',2030,'ETH','T_BLND','ge',0.1000000000000000055,''); +INSERT INTO limit_tech_input_split VALUES('R2',2020,'GSL','T_BLND','ge',0.7199999999999999734,''); +INSERT INTO limit_tech_input_split VALUES('R2',2020,'ETH','T_BLND','ge',0.08000000000000000166,''); +INSERT INTO limit_tech_input_split VALUES('R2',2025,'GSL','T_BLND','ge',0.7199999999999999734,''); +INSERT INTO limit_tech_input_split VALUES('R2',2025,'ETH','T_BLND','ge',0.08000000000000000166,''); +INSERT INTO limit_tech_input_split VALUES('R2',2030,'GSL','T_BLND','ge',0.7199999999999999734,''); +INSERT INTO limit_tech_input_split VALUES('R2',2030,'ETH','T_BLND','ge',0.08000000000000000166,''); +CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER @@ -1077,7 +1077,7 @@ CREATE TABLE LimitTechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechOutputSplit +CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER @@ -1092,19 +1092,19 @@ CREATE TABLE LimitTechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -INSERT INTO LimitTechOutputSplit VALUES('R1',2020,'S_OILREF','GSL','ge',0.9000000000000000222,''); -INSERT INTO LimitTechOutputSplit VALUES('R1',2020,'S_OILREF','DSL','ge',0.1000000000000000055,''); -INSERT INTO LimitTechOutputSplit VALUES('R1',2025,'S_OILREF','GSL','ge',0.9000000000000000222,''); -INSERT INTO LimitTechOutputSplit VALUES('R1',2025,'S_OILREF','DSL','ge',0.1000000000000000055,''); -INSERT INTO LimitTechOutputSplit VALUES('R1',2030,'S_OILREF','GSL','ge',0.9000000000000000222,''); -INSERT INTO LimitTechOutputSplit VALUES('R1',2030,'S_OILREF','DSL','ge',0.1000000000000000055,''); -INSERT INTO LimitTechOutputSplit VALUES('R2',2020,'S_OILREF','GSL','ge',0.7199999999999999734,''); -INSERT INTO LimitTechOutputSplit VALUES('R2',2020,'S_OILREF','DSL','ge',0.08000000000000000166,''); -INSERT INTO LimitTechOutputSplit VALUES('R2',2025,'S_OILREF','GSL','ge',0.7199999999999999734,''); -INSERT INTO LimitTechOutputSplit VALUES('R2',2025,'S_OILREF','DSL','ge',0.08000000000000000166,''); -INSERT INTO LimitTechOutputSplit VALUES('R2',2030,'S_OILREF','GSL','ge',0.7199999999999999734,''); -INSERT INTO LimitTechOutputSplit VALUES('R2',2030,'S_OILREF','DSL','ge',0.08000000000000000166,''); -CREATE TABLE LimitTechOutputSplitAnnual +INSERT INTO limit_tech_output_split VALUES('R1',2020,'S_OILREF','GSL','ge',0.9000000000000000222,''); +INSERT INTO limit_tech_output_split VALUES('R1',2020,'S_OILREF','DSL','ge',0.1000000000000000055,''); +INSERT INTO limit_tech_output_split VALUES('R1',2025,'S_OILREF','GSL','ge',0.9000000000000000222,''); +INSERT INTO limit_tech_output_split VALUES('R1',2025,'S_OILREF','DSL','ge',0.1000000000000000055,''); +INSERT INTO limit_tech_output_split VALUES('R1',2030,'S_OILREF','GSL','ge',0.9000000000000000222,''); +INSERT INTO limit_tech_output_split VALUES('R1',2030,'S_OILREF','DSL','ge',0.1000000000000000055,''); +INSERT INTO limit_tech_output_split VALUES('R2',2020,'S_OILREF','GSL','ge',0.7199999999999999734,''); +INSERT INTO limit_tech_output_split VALUES('R2',2020,'S_OILREF','DSL','ge',0.08000000000000000166,''); +INSERT INTO limit_tech_output_split VALUES('R2',2025,'S_OILREF','GSL','ge',0.7199999999999999734,''); +INSERT INTO limit_tech_output_split VALUES('R2',2025,'S_OILREF','DSL','ge',0.08000000000000000166,''); +INSERT INTO limit_tech_output_split VALUES('R2',2030,'S_OILREF','GSL','ge',0.7199999999999999734,''); +INSERT INTO limit_tech_output_split VALUES('R2',2030,'S_OILREF','DSL','ge',0.08000000000000000166,''); +CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER @@ -1119,7 +1119,7 @@ CREATE TABLE LimitTechOutputSplitAnnual notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitEmission +CREATE TABLE limit_emission ( region TEXT, period INTEGER @@ -1133,12 +1133,12 @@ CREATE TABLE LimitEmission notes TEXT, PRIMARY KEY (region, period, emis_comm, operator) ); -INSERT INTO LimitEmission VALUES('R1',2020,'CO2','le',25000.0,'kT CO2',''); -INSERT INTO LimitEmission VALUES('R1',2025,'CO2','le',24000.0,'kT CO2',''); -INSERT INTO LimitEmission VALUES('R1',2030,'CO2','le',23000.0,'kT CO2',''); -INSERT INTO LimitEmission VALUES('global',2020,'CO2','le',37500.0,'kT CO2',''); -INSERT INTO LimitEmission VALUES('global',2025,'CO2','le',36000.0,'kT CO2',''); -INSERT INTO LimitEmission VALUES('global',2030,'CO2','le',34500.0,'kT CO2',''); +INSERT INTO limit_emission VALUES('R1',2020,'CO2','le',25000.0,'kT CO2',''); +INSERT INTO limit_emission VALUES('R1',2025,'CO2','le',24000.0,'kT CO2',''); +INSERT INTO limit_emission VALUES('R1',2030,'CO2','le',23000.0,'kT CO2',''); +INSERT INTO limit_emission VALUES('global',2020,'CO2','le',37500.0,'kT CO2',''); +INSERT INTO limit_emission VALUES('global',2025,'CO2','le',36000.0,'kT CO2',''); +INSERT INTO limit_emission VALUES('global',2030,'CO2','le',34500.0,'kT CO2',''); CREATE TABLE LinkedTech ( primary_region TEXT, @@ -1282,7 +1282,7 @@ CREATE TABLE OutputStorageLevel level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); -CREATE TABLE PlanningReserveMargin +CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY @@ -1290,7 +1290,7 @@ CREATE TABLE PlanningReserveMargin margin REAL, notes TEXT ); -CREATE TABLE RampDownHourly +CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT @@ -1299,7 +1299,7 @@ CREATE TABLE RampDownHourly notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUpHourly +CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT @@ -1316,7 +1316,7 @@ CREATE TABLE Region ); INSERT INTO Region VALUES('R1',NULL); INSERT INTO Region VALUES('R2',NULL); -CREATE TABLE ReserveCapacityDerate +CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER @@ -1332,7 +1332,7 @@ CREATE TABLE ReserveCapacityDerate CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE TimeSegmentFraction -( +( period INTEGER REFERENCES TimePeriod (period), season TEXT @@ -1368,7 +1368,7 @@ INSERT INTO TimeSegmentFraction VALUES(2030,'fall','day',0.125,'Fall - Day'); INSERT INTO TimeSegmentFraction VALUES(2030,'fall','night',0.125,'Fall - Night'); INSERT INTO TimeSegmentFraction VALUES(2030,'winter','day',0.125,'Winter - Day'); INSERT INTO TimeSegmentFraction VALUES(2030,'winter','night',0.125,'Winter - Night'); -CREATE TABLE StorageDuration +CREATE TABLE storage_duration ( region TEXT, tech TEXT, @@ -1376,9 +1376,9 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO StorageDuration VALUES('R1','E_BATT',8.0,'8-hour duration specified as fraction of a day'); -INSERT INTO StorageDuration VALUES('R2','E_BATT',8.0,'8-hour duration specified as fraction of a day'); -CREATE TABLE LifetimeSurvivalCurve +INSERT INTO storage_duration VALUES('R1','E_BATT',8.0,'8-hour duration specified as fraction of a day'); +INSERT INTO storage_duration VALUES('R2','E_BATT',8.0,'8-hour duration specified as fraction of a day'); +CREATE TABLE lifetime_survival_curve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -1442,7 +1442,7 @@ INSERT INTO TimeSeason VALUES(2030,1,'spring',NULL); INSERT INTO TimeSeason VALUES(2030,2,'summer',NULL); INSERT INTO TimeSeason VALUES(2030,3,'fall',NULL); INSERT INTO TimeSeason VALUES(2030,4,'winter',NULL); -CREATE TABLE TimeSeasonSequential +CREATE TABLE time_season_sequential ( period INTEGER REFERENCES TimePeriod (period), diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 4e03ab73a..046b78dc4 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -1,6 +1,6 @@ { - "AnnualCommodityBalanceConstraint_rpc": [], - "AnnualRetirementVar_rptv": [ + "annual_commodity_balance_constraint_rpc": [], + "annual_retirement_var_rptv": [ [ "R1", 2030, @@ -38,7 +38,7 @@ 2020 ] ], - "BaseloadDiurnalConstraint_rpsdtv": [ + "baseload_diurnal_constraint_rpsdtv": [ [ "R2", 2025, @@ -1192,8 +1192,8 @@ 2015 ] ], - "CapacityAnnualConstraint_rptv": [], - "CapacityAvailableVar_rpt": [ + "capacity_annual_constraint_rptv": [], + "capacity_available_var_rpt": [ [ "R1", 2020, @@ -1555,7 +1555,7 @@ "E_BATT" ] ], - "CapacityConstraint_rpsdtv": [ + "capacity_constraint_rpsdtv": [ [ "R2", 2025, @@ -9237,7 +9237,7 @@ 2015 ] ], - "CapacityFactor_rpsdt": [ + "capacity_factor_rpsdt": [ [ "R1", 2020, @@ -13271,7 +13271,7 @@ "T_GSL" ] ], - "CapacityVar_rptv": [ + "capacity_var_rptv": [ [ "R2", 2030, @@ -14065,7 +14065,7 @@ 2020 ] ], - "CommodityBalanceConstraint_rpsdc": [ + "commodity_balance_constraint_rpsdc": [ [ "R2", 2020, @@ -16755,8 +16755,8 @@ "ETH" ] ], - "CostEmission_rpe": [], - "CostFixed_rptv": [ + "cost_emission_rpe": [], + "cost_fixed_rptv": [ [ "R2", 2030, @@ -17550,7 +17550,7 @@ 2020 ] ], - "CostInvest_rtv": [ + "cost_invest_rtv": [ [ "R2", "E_NUCLEAR", @@ -17822,7 +17822,7 @@ 2030 ] ], - "CostVariable_rptv": [ + "cost_variable_rptv": [ [ "R2", 2030, @@ -18760,7 +18760,7 @@ 2020 ] ], - "CurtailmentVar_rpsditvo": [ + "curtailment_var_rpsditvo": [ [ "R2", 2025, @@ -19722,7 +19722,7 @@ "GSL" ] ], - "DemandActivityConstraint_rpsdtv_dem": [ + "demand_activity_constraint_rpsdtv_dem": [ [ "R2", 2030, @@ -24044,7 +24044,7 @@ "RH" ] ], - "DemandConstraint_rpc": [ + "demand_constraint_rpc": [ [ "R1", 2030, @@ -24106,7 +24106,7 @@ "RH" ] ], - "EmissionActivity_reitvo": [ + "emission_activity_reitvo": [ [ "R1", "CO2", @@ -24684,9 +24684,9 @@ "RH" ] ], - "FlexVarAnnual_rpitvo": [], - "FlexVar_rpsditvo": [], - "FlowInStorage_rpsditvo": [ + "flex_var_annual_rpitvo": [], + "flex_var_rpsditvo": [], + "flow_in_storage_rpsditvo": [ [ "R2", 2030, @@ -25648,7 +25648,7 @@ "ELC" ] ], - "FlowVarAnnual_rpitvo": [ + "flow_var_annual_rpitvo": [ [ "R1", 2030, @@ -26130,7 +26130,7 @@ "VMT" ] ], - "FlowVar_rpsditvo": [ + "flow_var_rpsditvo": [ [ "R1", 2020, @@ -39572,7 +39572,7 @@ "ELC" ] ], - "LifetimeProcess_rtv": [ + "lifetime_process_rtv": [ [ "R2", "E_NUCLEAR", @@ -39924,7 +39924,7 @@ 2020 ] ], - "LimitActivityConstraint_rpt": [ + "limit_activity_constraint_rpt": [ [ "R1", 2030, @@ -39962,14 +39962,14 @@ "ge" ] ], - "LimitActivityShareConstraint_rpgg": [], - "LimitAnnualCapacityFactorConstraint_rpto": [], - "LimitCapacityConstraint_rpt": [], - "LimitCapacityShareConstraint_rpgg": [], - "LimitDegrowthCapacityConstraint_rpt": [], - "LimitDegrowthNewCapacityConstraint_rpt": [], - "LimitDegrowthNewCapacityDeltaConstraint_rpt": [], - "LimitEmissionConstraint_rpe": [ + "limit_activity_share_constraint_rpgg": [], + "limit_annual_capacity_factor_constraint_rpto": [], + "limit_capacity_constraint_rpt": [], + "limit_capacity_share_constraint_rpgg": [], + "limit_degrowth_capacity_constraint_rpt": [], + "limit_degrowth_new_capacity_constraint_rpt": [], + "limit_degrowth_new_capacity_delta_constraint_rpt": [], + "limit_emission_constraint_rpe": [ [ "R1", 2025, @@ -40007,14 +40007,14 @@ "le" ] ], - "LimitGrowthCapacityConstraint_rpt": [], - "LimitGrowthNewCapacityConstraint_rpt": [], - "LimitGrowthNewCapacityDeltaConstraint_rpt": [], - "LimitNewCapacityConstraint_rpt": [], - "LimitNewCapacityShareConstraint_rpgg": [], - "LimitResourceConstraint_rt": [], - "LimitSeasonalCapacityFactorConstraint_rpst": [], - "LimitStorageFractionConstraint_rpsdtv": [ + "limit_growth_capacity_constraint_rpt": [], + "limit_growth_new_capacity_constraint_rpt": [], + "limit_growth_new_capacity_delta_constraint_rpt": [], + "limit_new_capacity_constraint_rpt": [], + "limit_new_capacity_share_constraint_rpgg": [], + "limit_resource_constraint_rt": [], + "limit_seasonal_capacity_factor_constraint_rpst": [], + "limit_storage_fraction_constraint_rpsdtv": [ [ "R1", 2025, @@ -40034,9 +40034,9 @@ "e" ] ], - "LimitTechInputSplitAnnualConstraint_rpitv": [], - "LimitTechInputSplitAverageConstraint_rpitv": [], - "LimitTechInputSplitConstraint_rpsditv": [ + "limit_tech_input_split_annual_constraint_rpitv": [], + "limit_tech_input_split_average_constraint_rpitv": [], + "limit_tech_input_split_constraint_rpsditv": [ [ "R2", 2020, @@ -40998,9 +40998,9 @@ "ge" ] ], - "LimitTechOutputSplitAnnualConstraint_rptvo": [], - "LimitTechOutputSplitAverageConstraint_rptvo": [], - "LimitTechOutputSplitConstraint_rpsdtvo": [ + "limit_tech_output_split_annual_constraint_rptvo": [], + "limit_tech_output_split_average_constraint_rptvo": [], + "limit_tech_output_split_constraint_rpsdtvo": [ [ "R2", 2020, @@ -41962,8 +41962,8 @@ "ge" ] ], - "LinkedEmissionsTechConstraint_rpsdtve": [], - "LoanLifetimeProcess_rtv": [ + "linked_emissions_tech_constraint_rpsdtve": [], + "loan_lifetime_process_rtv": [ [ "R2", "E_NUCLEAR", @@ -42295,7 +42295,7 @@ 2020 ] ], - "NewCapacityVar_rtv": [ + "new_capacity_var_rtv": [ [ "R2", "E_NUCLEAR", @@ -42587,7 +42587,7 @@ 2020 ] ], - "ProcessLifeFrac_rptv": [ + "process_life_frac_rptv": [ [ "R2", 2030, @@ -43525,11 +43525,11 @@ 2020 ] ], - "RampDownDayConstraint_rpsdtv": [], - "RampDownSeasonConstraint_rpsstv": [], - "RampUpDayConstraint_rpsdtv": [], - "RampUpSeasonConstraint_rpsstv": [], - "RegionalExchangeCapacityConstraint_rrptv": [ + "ramp_down_day_constraint_rpsdtv": [], + "ramp_down_season_constraint_rpsstv": [], + "ramp_up_day_constraint_rpsdtv": [], + "ramp_up_season_constraint_rpsstv": [], + "regional_exchange_capacity_constraint_rrptv": [ [ "R2", "R1", @@ -43573,15 +43573,15 @@ 2015 ] ], - "RenewablePortfolioStandardConstraint_rpg": [], - "ReserveMargin_rpsd": [], - "ReserveMarginMethod": [ + "renewable_portfolio_standard_constraint_rpg": [], + "reserve_margin_rpsd": [], + "reserve_margin_method": [ "static" ], - "RetiredCapacityVar_rptv": [], - "SeasonalStorageLevel_rpstv": [], - "SeasonalStorageConstraints_rpsdtv": [], - "StorageConstraints_rpsdtv": [ + "retired_capacity_var_rptv": [], + "seasonal_storage_level_rpstv": [], + "seasonal_storage_constraints_rpsdtv": [], + "storage_constraints_rpsdtv": [ [ "R1", 2025, @@ -44351,7 +44351,7 @@ 2030 ] ], - "StorageLevel_rpsdtv": [ + "storage_level_rpsdtv": [ [ "R1", 2025, @@ -45121,7 +45121,7 @@ 2030 ] ], - "TimeNext": [], + "time_manual": [], "commodity_all": [ "ethos", "RH", @@ -45182,12 +45182,12 @@ "le" ], "ordered_season_sequential": [], - "regionalGlobalIndices": [ + "regional_global_indices": [ "R2", "R1", "global" ], - "regionalIndices": [ + "regional_indices": [ "R2", "R1-R2", "R1", @@ -45321,19 +45321,19 @@ 2020, 2030 ], - "TimeSeason": [ + "time_season": [ 2025, 2020, 2030 ], - "time_season": [ + "time_season_all": [ "summer", "fall", "spring", "winter" ], - "time_season_sequential": [], - "TimeSequencing": [ + "time_season_to_sequential": [], + "time_sequencing": [ "seasonal_timeslices" ], "vintage_all": [ @@ -45350,4 +45350,4 @@ 2020, 2030 ] -} \ No newline at end of file +} diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index f32cc2236..6cc795edb 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -18,7 +18,7 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in LoanRate table'); +INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); CREATE TABLE OutputDualVariable ( @@ -52,7 +52,7 @@ INSERT INTO SectorLabel VALUES('transport',NULL); INSERT INTO SectorLabel VALUES('commercial',NULL); INSERT INTO SectorLabel VALUES('residential',NULL); INSERT INTO SectorLabel VALUES('industrial',NULL); -CREATE TABLE CapacityCredit +CREATE TABLE capacity_credit ( region TEXT, period INTEGER @@ -65,7 +65,7 @@ CREATE TABLE CapacityCredit PRIMARY KEY (region, period, tech, vintage), CHECK (credit >= 0 AND credit <= 1) ); -CREATE TABLE CapacityFactorProcess +CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER @@ -82,25 +82,25 @@ CREATE TABLE CapacityFactorProcess PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'inter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'winter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2000,'summer','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2000,0.2752999999999999892,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','day','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'inter','night','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','day','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'winter','night','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','day','E31',2010,0.2756000000000000116,''); -INSERT INTO CapacityFactorProcess VALUES('utopia',2010,'summer','night','E31',2010,0.2756000000000000116,''); -CREATE TABLE CapacityFactorTech +INSERT INTO capacity_factor_process VALUES('utopia',2000,'inter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2000,'inter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2000,'winter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2000,'winter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2000,'summer','day','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2000,'summer','night','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','day','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','night','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','day','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','night','E31',2000,0.2752999999999999892,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','day','E31',2010,0.2756000000000000116,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','night','E31',2010,0.2756000000000000116,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','day','E31',2010,0.2756000000000000116,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','night','E31',2010,0.2756000000000000116,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','day','E31',2010,0.2756000000000000116,''); +INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','night','E31',2010,0.2756000000000000116,''); +CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER @@ -116,96 +116,96 @@ CREATE TABLE CapacityFactorTech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'inter','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'winter','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',1990,'summer','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'inter','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'winter','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2000,'summer','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E01',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E21',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E31',0.2750000000000000222,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E51',0.1700000000000000122,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'inter','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'winter','night','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','day','E70',0.8000000000000000444,''); -INSERT INTO CapacityFactorTech VALUES('utopia',2010,'summer','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E01',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E21',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E31',0.2750000000000000222,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E51',0.1700000000000000122,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E70',0.8000000000000000444,''); +INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E70',0.8000000000000000444,''); CREATE TABLE CapacityToActivity ( region TEXT, @@ -263,7 +263,7 @@ INSERT INTO CommodityType VALUES('s','source commodity'); INSERT INTO CommodityType VALUES('p','physical commodity'); INSERT INTO CommodityType VALUES('e','emissions commodity'); INSERT INTO CommodityType VALUES('d','demand commodity'); -CREATE TABLE ConstructionInput +CREATE TABLE construction_input ( region TEXT, input_comm TEXT @@ -277,7 +277,7 @@ CREATE TABLE ConstructionInput notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -CREATE TABLE CostEmission +CREATE TABLE cost_emission ( region TEXT, period INTEGER @@ -289,7 +289,7 @@ CREATE TABLE CostEmission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -CREATE TABLE CostFixed +CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -303,89 +303,89 @@ CREATE TABLE CostFixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostFixed VALUES('utopia',1990,'E01',1960,40.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E01',1970,40.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E01',1980,40.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E01',1990,40.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E01',1970,70.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E01',1980,70.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E01',1990,70.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E01',2000,70.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E01',1980,100.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E01',1990,100.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E01',2000,100.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E01',2010,100.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E21',1990,500.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E21',1990,500.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E21',1990,500.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E21',2000,500.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E21',2000,500.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E21',2010,500.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E31',1980,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E31',1990,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E31',1980,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E31',1990,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E31',2000,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E31',1980,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E31',1990,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E31',2000,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E31',2010,75.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E51',1980,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E51',1990,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E51',1980,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E51',1990,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E51',2000,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E51',1980,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E51',1990,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E51',2000,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E51',2010,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E70',1960,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E70',1970,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E70',1980,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'E70',1990,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E70',1970,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E70',1980,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E70',1990,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'E70',2000,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E70',1980,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E70',1990,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E70',2000,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'E70',2010,30.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RHO',1970,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RHO',1980,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RHO',1990,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'RHO',1980,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'RHO',1990,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'RHO',2000,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'RHO',1990,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'RHO',2000,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'RHO',2010,1.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1980,9.46000000000000086,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'RL1',1990,9.46000000000000086,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'RL1',2000,9.46000000000000086,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'RL1',2010,9.46000000000000086,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1970,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1980,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'TXD',1990,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXD',1980,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXD',1990,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXD',2000,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'TXD',2000,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'TXD',2010,52.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'TXE',1990,100.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXE',1990,90.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXE',2000,90.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'TXE',2000,80.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'TXE',2010,80.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'TXG',1970,48.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'TXG',1980,48.0,'',''); -INSERT INTO CostFixed VALUES('utopia',1990,'TXG',1990,48.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXG',1980,48.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXG',1990,48.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2000,'TXG',2000,48.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'TXG',2000,48.0,'',''); -INSERT INTO CostFixed VALUES('utopia',2010,'TXG',2010,48.0,'',''); -CREATE TABLE CostInvest +INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1960,40.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1970,40.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1980,40.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1990,40.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E01',1970,70.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E01',1980,70.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E01',1990,70.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E01',2000,70.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E01',1980,100.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E01',1990,100.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E01',2000,100.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E01',2010,100.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E21',1990,500.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E21',1990,500.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E21',1990,500.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E21',2000,500.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E21',2000,500.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E21',2010,500.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E31',1980,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E31',1990,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E31',1980,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E31',1990,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E31',2000,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E31',1980,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E31',1990,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E31',2000,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E31',2010,75.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E51',1980,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E51',1990,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E51',1980,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E51',1990,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E51',2000,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E51',1980,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E51',1990,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E51',2000,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E51',2010,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1960,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1970,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1980,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1990,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E70',1970,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E70',1980,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E70',1990,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'E70',2000,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E70',1980,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E70',1990,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E70',2000,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'E70',2010,30.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'RHO',1970,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'RHO',1980,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'RHO',1990,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'RHO',1980,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'RHO',1990,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'RHO',2000,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'RHO',1990,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'RHO',2000,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'RHO',2010,1.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'RL1',1980,9.46000000000000086,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'RL1',1990,9.46000000000000086,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'RL1',2000,9.46000000000000086,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'RL1',2010,9.46000000000000086,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'TXD',1970,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'TXD',1980,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'TXD',1990,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXD',1980,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXD',1990,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXD',2000,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'TXD',2000,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'TXD',2010,52.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'TXE',1990,100.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXE',1990,90.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXE',2000,90.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'TXE',2000,80.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'TXE',2010,80.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'TXG',1970,48.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'TXG',1980,48.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',1990,'TXG',1990,48.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXG',1980,48.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXG',1990,48.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2000,'TXG',2000,48.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'TXG',2000,48.0,'',''); +INSERT INTO cost_fixed VALUES('utopia',2010,'TXG',2010,48.0,'',''); +CREATE TABLE cost_invest ( region TEXT, tech TEXT @@ -397,40 +397,40 @@ CREATE TABLE CostInvest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO CostInvest VALUES('utopia','E01',1990,2000.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E01',2000,1300.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E01',2010,1200.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E21',1990,5000.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E21',2000,5000.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E21',2010,5000.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E31',1990,3000.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E31',2000,3000.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E31',2010,3000.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E51',1990,900.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E51',2000,900.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E51',2010,900.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E70',1990,1000.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E70',2000,1000.0,'',''); -INSERT INTO CostInvest VALUES('utopia','E70',2010,1000.0,'',''); -INSERT INTO CostInvest VALUES('utopia','RHE',1990,90.0,'',''); -INSERT INTO CostInvest VALUES('utopia','RHE',2000,90.0,'',''); -INSERT INTO CostInvest VALUES('utopia','RHE',2010,90.0,'',''); -INSERT INTO CostInvest VALUES('utopia','RHO',1990,100.0,'',''); -INSERT INTO CostInvest VALUES('utopia','RHO',2000,100.0,'',''); -INSERT INTO CostInvest VALUES('utopia','RHO',2010,100.0,'',''); -INSERT INTO CostInvest VALUES('utopia','SRE',1990,100.0,'',''); -INSERT INTO CostInvest VALUES('utopia','SRE',2000,100.0,'',''); -INSERT INTO CostInvest VALUES('utopia','SRE',2010,100.0,'',''); -INSERT INTO CostInvest VALUES('utopia','TXD',1990,1044.0,'',''); -INSERT INTO CostInvest VALUES('utopia','TXD',2000,1044.0,'',''); -INSERT INTO CostInvest VALUES('utopia','TXD',2010,1044.0,'',''); -INSERT INTO CostInvest VALUES('utopia','TXE',1990,2000.0,'',''); -INSERT INTO CostInvest VALUES('utopia','TXE',2000,1750.0,'',''); -INSERT INTO CostInvest VALUES('utopia','TXE',2010,1500.0,'',''); -INSERT INTO CostInvest VALUES('utopia','TXG',1990,1044.0,'',''); -INSERT INTO CostInvest VALUES('utopia','TXG',2000,1044.0,'',''); -INSERT INTO CostInvest VALUES('utopia','TXG',2010,1044.0,'',''); -CREATE TABLE CostVariable +INSERT INTO cost_invest VALUES('utopia','E01',1990,2000.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E01',2000,1300.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E01',2010,1200.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E21',1990,5000.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E21',2000,5000.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E21',2010,5000.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E31',1990,3000.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E31',2000,3000.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E31',2010,3000.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E51',1990,900.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E51',2000,900.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E51',2010,900.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E70',1990,1000.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E70',2000,1000.0,'',''); +INSERT INTO cost_invest VALUES('utopia','E70',2010,1000.0,'',''); +INSERT INTO cost_invest VALUES('utopia','RHE',1990,90.0,'',''); +INSERT INTO cost_invest VALUES('utopia','RHE',2000,90.0,'',''); +INSERT INTO cost_invest VALUES('utopia','RHE',2010,90.0,'',''); +INSERT INTO cost_invest VALUES('utopia','RHO',1990,100.0,'',''); +INSERT INTO cost_invest VALUES('utopia','RHO',2000,100.0,'',''); +INSERT INTO cost_invest VALUES('utopia','RHO',2010,100.0,'',''); +INSERT INTO cost_invest VALUES('utopia','SRE',1990,100.0,'',''); +INSERT INTO cost_invest VALUES('utopia','SRE',2000,100.0,'',''); +INSERT INTO cost_invest VALUES('utopia','SRE',2010,100.0,'',''); +INSERT INTO cost_invest VALUES('utopia','TXD',1990,1044.0,'',''); +INSERT INTO cost_invest VALUES('utopia','TXD',2000,1044.0,'',''); +INSERT INTO cost_invest VALUES('utopia','TXD',2010,1044.0,'',''); +INSERT INTO cost_invest VALUES('utopia','TXE',1990,2000.0,'',''); +INSERT INTO cost_invest VALUES('utopia','TXE',2000,1750.0,'',''); +INSERT INTO cost_invest VALUES('utopia','TXE',2010,1500.0,'',''); +INSERT INTO cost_invest VALUES('utopia','TXG',1990,1044.0,'',''); +INSERT INTO cost_invest VALUES('utopia','TXG',2000,1044.0,'',''); +INSERT INTO cost_invest VALUES('utopia','TXG',2010,1044.0,'',''); +CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL @@ -444,57 +444,57 @@ CREATE TABLE CostVariable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO CostVariable VALUES('utopia',1990,'IMPDSL1',1990,10.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'IMPDSL1',1990,10.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'IMPDSL1',1990,10.0,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'IMPGSL1',1990,15.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'IMPGSL1',1990,15.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'IMPGSL1',1990,15.0,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'IMPHCO1',1990,2.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'IMPHCO1',1990,2.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'IMPHCO1',1990,2.0,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'IMPOIL1',1990,8.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'IMPOIL1',1990,8.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'IMPOIL1',1990,8.0,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'IMPURN1',1990,2.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'IMPURN1',1990,2.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'IMPURN1',1990,2.0,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1960,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1970,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1980,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E01',1990,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1970,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1980,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',1990,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E01',2000,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',1980,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',1990,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',2000,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E01',2010,0.2999999999999999889,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E21',1990,1.5,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E21',1990,1.5,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E21',1990,1.5,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E21',2000,1.5,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E21',2000,1.5,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E21',2010,1.5,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1960,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1970,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1980,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'E70',1990,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1970,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1980,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',1990,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'E70',2000,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',1980,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',1990,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',2000,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'E70',2010,0.4000000000000000222,'',''); -INSERT INTO CostVariable VALUES('utopia',1990,'SRE',1990,10.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'SRE',1990,10.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2000,'SRE',2000,10.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'SRE',1990,10.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'SRE',2000,10.0,'',''); -INSERT INTO CostVariable VALUES('utopia',2010,'SRE',2010,10.0,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'IMPDSL1',1990,10.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'IMPDSL1',1990,10.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'IMPDSL1',1990,10.0,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'IMPGSL1',1990,15.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'IMPGSL1',1990,15.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'IMPGSL1',1990,15.0,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'IMPHCO1',1990,2.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'IMPHCO1',1990,2.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'IMPHCO1',1990,2.0,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'IMPOIL1',1990,8.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'IMPOIL1',1990,8.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'IMPOIL1',1990,8.0,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'IMPURN1',1990,2.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'IMPURN1',1990,2.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'IMPURN1',1990,2.0,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'E01',1960,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'E01',1970,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'E01',1980,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'E01',1990,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'E01',1970,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'E01',1980,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'E01',1990,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'E01',2000,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'E01',1980,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'E01',1990,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'E01',2000,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'E01',2010,0.2999999999999999889,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'E21',1990,1.5,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'E21',1990,1.5,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'E21',1990,1.5,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'E21',2000,1.5,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'E21',2000,1.5,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'E21',2010,1.5,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'E70',1960,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'E70',1970,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'E70',1980,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'E70',1990,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'E70',1970,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'E70',1980,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'E70',1990,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'E70',2000,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'E70',1980,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'E70',1990,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'E70',2000,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'E70',2010,0.4000000000000000222,'',''); +INSERT INTO cost_variable VALUES('utopia',1990,'SRE',1990,10.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'SRE',1990,10.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2000,'SRE',2000,10.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'SRE',1990,10.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'SRE',2000,10.0,'',''); +INSERT INTO cost_variable VALUES('utopia',2010,'SRE',2010,10.0,'',''); CREATE TABLE Demand ( region TEXT, @@ -562,7 +562,7 @@ INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','day','RL', INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','night','RL',0.05000000000000000277,''); INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RL',0.5,''); INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RL',0.1000000000000000055,''); -CREATE TABLE EndOfLifeOutput +CREATE TABLE end_of_life_output ( region TEXT, tech TEXT @@ -576,7 +576,7 @@ CREATE TABLE EndOfLifeOutput notes TEXT, PRIMARY KEY (region, tech, vintage, output_comm) ); -CREATE TABLE Efficiency +CREATE TABLE efficiency ( region TEXT, input_comm TEXT @@ -592,71 +592,71 @@ CREATE TABLE Efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPDSL1',1990,'DSL',1.0,''); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPGSL1',1990,'GSL',1.0,''); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPHCO1',1990,'HCO',1.0,''); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,''); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,''); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,''); -INSERT INTO Efficiency VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,''); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1960,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1970,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1980,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',1990,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',2000,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HCO','E01',2010,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',1990,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2000,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','FEQ','E21',2010,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','URN','E21',1990,'ELC',0.4000000000000000222,'# 1/2.5'); -INSERT INTO Efficiency VALUES('utopia','URN','E21',2000,'ELC',0.4000000000000000222,'# 1/2.5'); -INSERT INTO Efficiency VALUES('utopia','URN','E21',2010,'ELC',0.4000000000000000222,'# 1/2.5'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',1980,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',1990,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',2000,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','HYD','E31',2010,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1960,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1970,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1980,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',1990,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',2000,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','DSL','E70',2010,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',1980,'ELC',0.7199999999999999734,'# 1/1.3889'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',1990,'ELC',0.7199999999999999734,'# 1/1.3889'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',2000,'ELC',0.7199999999999999734,'# 1/1.3889'); -INSERT INTO Efficiency VALUES('utopia','ELC','E51',2010,'ELC',0.7199999999999999734,'# 1/1.3889'); -INSERT INTO Efficiency VALUES('utopia','ELC','RHE',1990,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','RHE',2000,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','RHE',2010,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1970,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1980,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',1990,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2000,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','RHO',2010,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','RL1',1980,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','RL1',1990,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','RL1',2000,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','RL1',2010,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',1990,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2000,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO Efficiency VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','DSL','TXD',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',1990,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2000,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','ELC','TXE',2010,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO Efficiency VALUES('utopia','GSL','TXG',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -CREATE TABLE EfficiencyVariable +INSERT INTO efficiency VALUES('utopia','ethos','IMPDSL1',1990,'DSL',1.0,''); +INSERT INTO efficiency VALUES('utopia','ethos','IMPGSL1',1990,'GSL',1.0,''); +INSERT INTO efficiency VALUES('utopia','ethos','IMPHCO1',1990,'HCO',1.0,''); +INSERT INTO efficiency VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,''); +INSERT INTO efficiency VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,''); +INSERT INTO efficiency VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,''); +INSERT INTO efficiency VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,''); +INSERT INTO efficiency VALUES('utopia','HCO','E01',1960,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','HCO','E01',1970,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','HCO','E01',1980,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','HCO','E01',1990,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','HCO','E01',2000,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','HCO','E01',2010,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','FEQ','E21',1990,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','FEQ','E21',2000,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','FEQ','E21',2010,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','URN','E21',1990,'ELC',0.4000000000000000222,'# 1/2.5'); +INSERT INTO efficiency VALUES('utopia','URN','E21',2000,'ELC',0.4000000000000000222,'# 1/2.5'); +INSERT INTO efficiency VALUES('utopia','URN','E21',2010,'ELC',0.4000000000000000222,'# 1/2.5'); +INSERT INTO efficiency VALUES('utopia','HYD','E31',1980,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','HYD','E31',1990,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','HYD','E31',2000,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','HYD','E31',2010,'ELC',0.3200000000000000066,'# 1/3.125'); +INSERT INTO efficiency VALUES('utopia','DSL','E70',1960,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO efficiency VALUES('utopia','DSL','E70',1970,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO efficiency VALUES('utopia','DSL','E70',1980,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO efficiency VALUES('utopia','DSL','E70',1990,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO efficiency VALUES('utopia','DSL','E70',2000,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO efficiency VALUES('utopia','DSL','E70',2010,'ELC',0.2939999999999999836,'# 1/3.4'); +INSERT INTO efficiency VALUES('utopia','ELC','E51',1980,'ELC',0.7199999999999999734,'# 1/1.3889'); +INSERT INTO efficiency VALUES('utopia','ELC','E51',1990,'ELC',0.7199999999999999734,'# 1/1.3889'); +INSERT INTO efficiency VALUES('utopia','ELC','E51',2000,'ELC',0.7199999999999999734,'# 1/1.3889'); +INSERT INTO efficiency VALUES('utopia','ELC','E51',2010,'ELC',0.7199999999999999734,'# 1/1.3889'); +INSERT INTO efficiency VALUES('utopia','ELC','RHE',1990,'RH',1.0,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','ELC','RHE',2000,'RH',1.0,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','ELC','RHE',2010,'RH',1.0,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','DSL','RHO',1970,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','DSL','RHO',1980,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','DSL','RHO',1990,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','DSL','RHO',2000,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','DSL','RHO',2010,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','ELC','RL1',1980,'RL',1.0,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','ELC','RL1',1990,'RL',1.0,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','ELC','RL1',2000,'RL',1.0,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','ELC','RL1',2010,'RL',1.0,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','OIL','SRE',1990,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO efficiency VALUES('utopia','OIL','SRE',2000,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO efficiency VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO efficiency VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO efficiency VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO efficiency VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO efficiency VALUES('utopia','DSL','TXD',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','DSL','TXD',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','DSL','TXD',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','DSL','TXD',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','DSL','TXD',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','ELC','TXE',1990,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','ELC','TXE',2000,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','ELC','TXE',2010,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','GSL','TXG',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','GSL','TXG',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','GSL','TXG',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','GSL','TXG',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO efficiency VALUES('utopia','GSL','TXG',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +CREATE TABLE efficiency_variable ( region TEXT, period INTEGER @@ -678,7 +678,7 @@ CREATE TABLE EfficiencyVariable PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -CREATE TABLE EmissionActivity +CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT @@ -696,21 +696,21 @@ CREATE TABLE EmissionActivity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.07499999999999999723,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.07499999999999999723,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',0.0889999999999999819,'',''); -INSERT INTO EmissionActivity VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.07499999999999999723,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1970,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1980,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',1990,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',2000,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','DSL','TXD',2010,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',1970,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',1980,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',1990,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',2000,'TX',1.0,'',''); -INSERT INTO EmissionActivity VALUES('utopia','nox','GSL','TXG',2010,'TX',1.0,'',''); -CREATE TABLE EmissionEmbodied +INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.07499999999999999723,'',''); +INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.07499999999999999723,'',''); +INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',0.0889999999999999819,'',''); +INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.07499999999999999723,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',1970,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',1980,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',1990,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',2000,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',2010,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',1970,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',1980,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',1990,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',2000,'TX',1.0,'',''); +INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',2010,'TX',1.0,'',''); +CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT @@ -724,7 +724,7 @@ CREATE TABLE EmissionEmbodied notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE EmissionEndOfLife +CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT @@ -738,7 +738,7 @@ CREATE TABLE EmissionEndOfLife notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -CREATE TABLE ExistingCapacity +CREATE TABLE existing_capacity ( region TEXT, tech TEXT @@ -750,28 +750,28 @@ CREATE TABLE ExistingCapacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1960,0.1749999999999999889,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1970,0.1749999999999999889,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E01',1980,0.1499999999999999945,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E31',1980,0.1000000000000000055,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E51',1980,0.5,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1960,0.05000000000000000277,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1970,0.05000000000000000277,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','E70',1980,0.2000000000000000111,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','RHO',1970,12.5,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','RHO',1980,12.5,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','RL1',1980,5.599999999999999645,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXD',1970,0.4000000000000000222,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXD',1980,0.2000000000000000111,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXG',1970,3.100000000000000088,'',''); -INSERT INTO ExistingCapacity VALUES('utopia','TXG',1980,1.5,'',''); +INSERT INTO existing_capacity VALUES('utopia','E01',1960,0.1749999999999999889,'',''); +INSERT INTO existing_capacity VALUES('utopia','E01',1970,0.1749999999999999889,'',''); +INSERT INTO existing_capacity VALUES('utopia','E01',1980,0.1499999999999999945,'',''); +INSERT INTO existing_capacity VALUES('utopia','E31',1980,0.1000000000000000055,'',''); +INSERT INTO existing_capacity VALUES('utopia','E51',1980,0.5,'',''); +INSERT INTO existing_capacity VALUES('utopia','E70',1960,0.05000000000000000277,'',''); +INSERT INTO existing_capacity VALUES('utopia','E70',1970,0.05000000000000000277,'',''); +INSERT INTO existing_capacity VALUES('utopia','E70',1980,0.2000000000000000111,'',''); +INSERT INTO existing_capacity VALUES('utopia','RHO',1970,12.5,'',''); +INSERT INTO existing_capacity VALUES('utopia','RHO',1980,12.5,'',''); +INSERT INTO existing_capacity VALUES('utopia','RL1',1980,5.599999999999999645,'',''); +INSERT INTO existing_capacity VALUES('utopia','TXD',1970,0.4000000000000000222,'',''); +INSERT INTO existing_capacity VALUES('utopia','TXD',1980,0.2000000000000000111,'',''); +INSERT INTO existing_capacity VALUES('utopia','TXG',1970,3.100000000000000088,'',''); +INSERT INTO existing_capacity VALUES('utopia','TXG',1980,1.5,'',''); CREATE TABLE TechGroup ( group_name TEXT PRIMARY KEY, notes TEXT ); -CREATE TABLE LoanLifetimeProcess +CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT @@ -782,7 +782,7 @@ CREATE TABLE LoanLifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LoanRate +CREATE TABLE loan_rate ( region TEXT, tech TEXT @@ -793,7 +793,7 @@ CREATE TABLE LoanRate notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE LifetimeProcess +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -804,12 +804,12 @@ CREATE TABLE LifetimeProcess notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO LifetimeProcess VALUES('utopia','RL1',1980,20.0,'#forexistingcap'); -INSERT INTO LifetimeProcess VALUES('utopia','TXD',1970,30.0,'#forexistingcap'); -INSERT INTO LifetimeProcess VALUES('utopia','TXD',1980,30.0,'#forexistingcap'); -INSERT INTO LifetimeProcess VALUES('utopia','TXG',1970,30.0,'#forexistingcap'); -INSERT INTO LifetimeProcess VALUES('utopia','TXG',1980,30.0,'#forexistingcap'); -CREATE TABLE LifetimeTech +INSERT INTO lifetime_process VALUES('utopia','RL1',1980,20.0,'#forexistingcap'); +INSERT INTO lifetime_process VALUES('utopia','TXD',1970,30.0,'#forexistingcap'); +INSERT INTO lifetime_process VALUES('utopia','TXD',1980,30.0,'#forexistingcap'); +INSERT INTO lifetime_process VALUES('utopia','TXG',1970,30.0,'#forexistingcap'); +INSERT INTO lifetime_process VALUES('utopia','TXG',1980,30.0,'#forexistingcap'); +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT @@ -818,25 +818,25 @@ CREATE TABLE LifetimeTech notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO LifetimeTech VALUES('utopia','E01',40.0,''); -INSERT INTO LifetimeTech VALUES('utopia','E21',40.0,''); -INSERT INTO LifetimeTech VALUES('utopia','E31',100.0,''); -INSERT INTO LifetimeTech VALUES('utopia','E51',100.0,''); -INSERT INTO LifetimeTech VALUES('utopia','E70',40.0,''); -INSERT INTO LifetimeTech VALUES('utopia','RHE',30.0,''); -INSERT INTO LifetimeTech VALUES('utopia','RHO',30.0,''); -INSERT INTO LifetimeTech VALUES('utopia','RL1',10.0,''); -INSERT INTO LifetimeTech VALUES('utopia','SRE',50.0,''); -INSERT INTO LifetimeTech VALUES('utopia','TXD',15.0,''); -INSERT INTO LifetimeTech VALUES('utopia','TXE',15.0,''); -INSERT INTO LifetimeTech VALUES('utopia','TXG',15.0,''); -INSERT INTO LifetimeTech VALUES('utopia','IMPDSL1',1000.0,''); -INSERT INTO LifetimeTech VALUES('utopia','IMPGSL1',1000.0,''); -INSERT INTO LifetimeTech VALUES('utopia','IMPHCO1',1000.0,''); -INSERT INTO LifetimeTech VALUES('utopia','IMPOIL1',1000.0,''); -INSERT INTO LifetimeTech VALUES('utopia','IMPURN1',1000.0,''); -INSERT INTO LifetimeTech VALUES('utopia','IMPHYD',1000.0,''); -INSERT INTO LifetimeTech VALUES('utopia','IMPFEQ',1000.0,''); +INSERT INTO lifetime_tech VALUES('utopia','E01',40.0,''); +INSERT INTO lifetime_tech VALUES('utopia','E21',40.0,''); +INSERT INTO lifetime_tech VALUES('utopia','E31',100.0,''); +INSERT INTO lifetime_tech VALUES('utopia','E51',100.0,''); +INSERT INTO lifetime_tech VALUES('utopia','E70',40.0,''); +INSERT INTO lifetime_tech VALUES('utopia','RHE',30.0,''); +INSERT INTO lifetime_tech VALUES('utopia','RHO',30.0,''); +INSERT INTO lifetime_tech VALUES('utopia','RL1',10.0,''); +INSERT INTO lifetime_tech VALUES('utopia','SRE',50.0,''); +INSERT INTO lifetime_tech VALUES('utopia','TXD',15.0,''); +INSERT INTO lifetime_tech VALUES('utopia','TXE',15.0,''); +INSERT INTO lifetime_tech VALUES('utopia','TXG',15.0,''); +INSERT INTO lifetime_tech VALUES('utopia','IMPDSL1',1000.0,''); +INSERT INTO lifetime_tech VALUES('utopia','IMPGSL1',1000.0,''); +INSERT INTO lifetime_tech VALUES('utopia','IMPHCO1',1000.0,''); +INSERT INTO lifetime_tech VALUES('utopia','IMPOIL1',1000.0,''); +INSERT INTO lifetime_tech VALUES('utopia','IMPURN1',1000.0,''); +INSERT INTO lifetime_tech VALUES('utopia','IMPHYD',1000.0,''); +INSERT INTO lifetime_tech VALUES('utopia','IMPFEQ',1000.0,''); CREATE TABLE Operator ( operator TEXT PRIMARY KEY, @@ -845,7 +845,7 @@ CREATE TABLE Operator INSERT INTO Operator VALUES('e','equal to'); INSERT INTO Operator VALUES('le','less than or equal to'); INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE LimitGrowthCapacity +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, @@ -857,7 +857,7 @@ CREATE TABLE LimitGrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthCapacity +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, @@ -869,7 +869,7 @@ CREATE TABLE LimitDegrowthCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacity +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -881,7 +881,7 @@ CREATE TABLE LimitGrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, @@ -893,7 +893,7 @@ CREATE TABLE LimitDegrowthNewCapacity notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitGrowthNewCapacityDelta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -905,7 +905,7 @@ CREATE TABLE LimitGrowthNewCapacityDelta notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitDegrowthNewCapacityDelta +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, @@ -936,7 +936,7 @@ CREATE TABLE LimitStorageLevelFraction notes TEXT, PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); -CREATE TABLE LimitActivity +CREATE TABLE limit_activity ( region TEXT, period INTEGER @@ -949,7 +949,7 @@ CREATE TABLE LimitActivity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitActivityShare +CREATE TABLE limit_activity_share ( region TEXT, period INTEGER @@ -962,7 +962,7 @@ CREATE TABLE LimitActivityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitAnnualCapacityFactor +CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER @@ -978,7 +978,7 @@ CREATE TABLE LimitAnnualCapacityFactor PRIMARY KEY (region, period, tech, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE LimitCapacity +CREATE TABLE limit_capacity ( region TEXT, period INTEGER @@ -991,18 +991,18 @@ CREATE TABLE LimitCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO LimitCapacity VALUES('utopia',1990,'E31','ge',0.1300000000000000044,'',''); -INSERT INTO LimitCapacity VALUES('utopia',2000,'E31','ge',0.1300000000000000044,'',''); -INSERT INTO LimitCapacity VALUES('utopia',2010,'E31','ge',0.1300000000000000044,'',''); -INSERT INTO LimitCapacity VALUES('utopia',1990,'SRE','ge',0.1000000000000000055,'',''); -INSERT INTO LimitCapacity VALUES('utopia',1990,'E31','le',0.1300000000000000044,'',''); -INSERT INTO LimitCapacity VALUES('utopia',2000,'E31','le',0.1700000000000000122,'',''); -INSERT INTO LimitCapacity VALUES('utopia',2010,'E31','le',0.21000000000000002,'',''); -INSERT INTO LimitCapacity VALUES('utopia',1990,'RHE','le',0.0,'',''); -INSERT INTO LimitCapacity VALUES('utopia',1990,'TXD','le',0.5999999999999999778,'',''); -INSERT INTO LimitCapacity VALUES('utopia',2000,'TXD','le',1.760000000000000008,'',''); -INSERT INTO LimitCapacity VALUES('utopia',2010,'TXD','le',4.759999999999999787,'',''); -CREATE TABLE LimitCapacityShare +INSERT INTO limit_capacity VALUES('utopia',1990,'E31','ge',0.1300000000000000044,'',''); +INSERT INTO limit_capacity VALUES('utopia',2000,'E31','ge',0.1300000000000000044,'',''); +INSERT INTO limit_capacity VALUES('utopia',2010,'E31','ge',0.1300000000000000044,'',''); +INSERT INTO limit_capacity VALUES('utopia',1990,'SRE','ge',0.1000000000000000055,'',''); +INSERT INTO limit_capacity VALUES('utopia',1990,'E31','le',0.1300000000000000044,'',''); +INSERT INTO limit_capacity VALUES('utopia',2000,'E31','le',0.1700000000000000122,'',''); +INSERT INTO limit_capacity VALUES('utopia',2010,'E31','le',0.21000000000000002,'',''); +INSERT INTO limit_capacity VALUES('utopia',1990,'RHE','le',0.0,'',''); +INSERT INTO limit_capacity VALUES('utopia',1990,'TXD','le',0.5999999999999999778,'',''); +INSERT INTO limit_capacity VALUES('utopia',2000,'TXD','le',1.760000000000000008,'',''); +INSERT INTO limit_capacity VALUES('utopia',2010,'TXD','le',4.759999999999999787,'',''); +CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER @@ -1015,7 +1015,7 @@ CREATE TABLE LimitCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitNewCapacity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER @@ -1028,7 +1028,7 @@ CREATE TABLE LimitNewCapacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE LimitNewCapacityShare +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -1041,7 +1041,7 @@ CREATE TABLE LimitNewCapacityShare notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE LimitResource +CREATE TABLE limit_resource ( region TEXT, tech_or_group TEXT, @@ -1052,7 +1052,7 @@ CREATE TABLE LimitResource notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitSeasonalCapacityFactor +CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES Region (region), @@ -1068,7 +1068,7 @@ CREATE TABLE LimitSeasonalCapacityFactor notes TEXT, PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE LimitTechInputSplit +CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER @@ -1083,7 +1083,7 @@ CREATE TABLE LimitTechInputSplit notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechInputSplitAnnual +CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER @@ -1098,7 +1098,7 @@ CREATE TABLE LimitTechInputSplitAnnual notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -CREATE TABLE LimitTechOutputSplit +CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER @@ -1113,13 +1113,13 @@ CREATE TABLE LimitTechOutputSplit notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -INSERT INTO LimitTechOutputSplit VALUES('utopia',1990,'SRE','DSL','ge',0.6999999999999999556,''); -INSERT INTO LimitTechOutputSplit VALUES('utopia',2000,'SRE','DSL','ge',0.6999999999999999556,''); -INSERT INTO LimitTechOutputSplit VALUES('utopia',2010,'SRE','DSL','ge',0.6999999999999999556,''); -INSERT INTO LimitTechOutputSplit VALUES('utopia',1990,'SRE','GSL','ge',0.2999999999999999889,''); -INSERT INTO LimitTechOutputSplit VALUES('utopia',2000,'SRE','GSL','ge',0.2999999999999999889,''); -INSERT INTO LimitTechOutputSplit VALUES('utopia',2010,'SRE','GSL','ge',0.2999999999999999889,''); -CREATE TABLE LimitTechOutputSplitAnnual +INSERT INTO limit_tech_output_split VALUES('utopia',1990,'SRE','DSL','ge',0.6999999999999999556,''); +INSERT INTO limit_tech_output_split VALUES('utopia',2000,'SRE','DSL','ge',0.6999999999999999556,''); +INSERT INTO limit_tech_output_split VALUES('utopia',2010,'SRE','DSL','ge',0.6999999999999999556,''); +INSERT INTO limit_tech_output_split VALUES('utopia',1990,'SRE','GSL','ge',0.2999999999999999889,''); +INSERT INTO limit_tech_output_split VALUES('utopia',2000,'SRE','GSL','ge',0.2999999999999999889,''); +INSERT INTO limit_tech_output_split VALUES('utopia',2010,'SRE','GSL','ge',0.2999999999999999889,''); +CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER @@ -1134,7 +1134,7 @@ CREATE TABLE LimitTechOutputSplitAnnual notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE LimitEmission +CREATE TABLE limit_emission ( region TEXT, period INTEGER @@ -1291,7 +1291,7 @@ CREATE TABLE OutputStorageLevel level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); -CREATE TABLE PlanningReserveMargin +CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY @@ -1299,7 +1299,7 @@ CREATE TABLE PlanningReserveMargin margin REAL, notes TEXT ); -CREATE TABLE RampDownHourly +CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT @@ -1308,7 +1308,7 @@ CREATE TABLE RampDownHourly notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE RampUpHourly +CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT @@ -1324,7 +1324,7 @@ CREATE TABLE Region notes TEXT ); INSERT INTO Region VALUES('utopia',NULL); -CREATE TABLE ReserveCapacityDerate +CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER @@ -1340,7 +1340,7 @@ CREATE TABLE ReserveCapacityDerate CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE TimeSegmentFraction -( +( period INTEGER REFERENCES TimePeriod (period), season TEXT @@ -1370,7 +1370,7 @@ INSERT INTO TimeSegmentFraction VALUES(2010,'summer','day',0.166699999999999987, INSERT INTO TimeSegmentFraction VALUES(2010,'summer','night',0.08329999999999999905,'# S-N'); INSERT INTO TimeSegmentFraction VALUES(2010,'winter','day',0.3332999999999999852,'# W-D'); INSERT INTO TimeSegmentFraction VALUES(2010,'winter','night',0.166699999999999987,'# W-N'); -CREATE TABLE StorageDuration +CREATE TABLE storage_duration ( region TEXT, tech TEXT, @@ -1378,7 +1378,7 @@ CREATE TABLE StorageDuration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE LifetimeSurvivalCurve +CREATE TABLE lifetime_survival_curve ( region TEXT NOT NULL, period INTEGER NOT NULL, @@ -1441,7 +1441,7 @@ INSERT INTO TimeSeason VALUES(2000,3,'winter',NULL); INSERT INTO TimeSeason VALUES(2010,1,'inter',NULL); INSERT INTO TimeSeason VALUES(2010,2,'summer',NULL); INSERT INTO TimeSeason VALUES(2010,3,'winter',NULL); -CREATE TABLE TimeSeasonSequential +CREATE TABLE time_season_sequential ( period INTEGER REFERENCES TimePeriod (period), diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 17fdf0a70..583455ff8 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -1,6 +1,6 @@ { - "AnnualCommodityBalanceConstraint_rpc": [], - "AnnualRetirementVar_rptv": [ + "annual_commodity_balance_constraint_rpc": [], + "annual_retirement_var_rptv": [ [ "utopia", 2010, @@ -116,7 +116,7 @@ 1990 ] ], - "BaseloadDiurnalConstraint_rpsdtv": [ + "baseload_diurnal_constraint_rpsdtv": [ [ "utopia", 2010, @@ -1414,8 +1414,8 @@ 1990 ] ], - "CapacityAnnualConstraint_rptv": [], - "CapacityAvailableVar_rpt": [ + "capacity_annual_constraint_rptv": [], + "capacity_available_var_rpt": [ [ "utopia", 2000, @@ -1597,7 +1597,7 @@ "RHO" ] ], - "CapacityConstraint_rpsdtv": [ + "capacity_constraint_rpsdtv": [ [ "utopia", 2010, @@ -5679,7 +5679,7 @@ 2000 ] ], - "CapacityFactor_rpsdt": [ + "capacity_factor_rpsdt": [ [ "utopia", 2000, @@ -7193,7 +7193,7 @@ "RHO" ] ], - "CapacityVar_rptv": [ + "capacity_var_rptv": [ [ "utopia", 2000, @@ -7759,7 +7759,7 @@ 1990 ] ], - "CommodityBalanceConstraint_rpsdc": [ + "commodity_balance_constraint_rpsdc": [ [ "utopia", 2010, @@ -8769,8 +8769,8 @@ "GSL" ] ], - "CostEmission_rpe": [], - "CostFixed_rptv": [ + "cost_emission_rpe": [], + "cost_fixed_rptv": [ [ "utopia", 2000, @@ -9336,7 +9336,7 @@ 1990 ] ], - "CostInvest_rtv": [ + "cost_invest_rtv": [ [ "utopia", "TXD", @@ -9503,7 +9503,7 @@ 2000 ] ], - "CostVariable_rptv": [ + "cost_variable_rptv": [ [ "utopia", 2000, @@ -10195,8 +10195,8 @@ 1990 ] ], - "CurtailmentVar_rpsditvo": [], - "DemandConstraint_rpc": [ + "curtailment_var_rpsditvo": [], + "demand_constraint_rpc": [ [ "utopia", 2000, @@ -10243,7 +10243,7 @@ "RH" ] ], - "DemandActivityConstraint_rpsdtv_dem": [ + "demand_activity_constraint_rpsdtv_dem": [ [ "utopia", 2000, @@ -12405,7 +12405,7 @@ "RH" ] ], - "EmissionActivity_reitvo": [ + "emission_activity_reitvo": [ [ "utopia", "co2", @@ -13431,9 +13431,9 @@ "ELC" ] ], - "FlexVarAnnual_rpitvo": [], - "FlexVar_rpsditvo": [], - "FlowInStorage_rpsditvo": [ + "flex_var_annual_rpitvo": [], + "flex_var_rpsditvo": [], + "flow_in_storage_rpsditvo": [ [ "utopia", 2000, @@ -13975,7 +13975,7 @@ "ELC" ] ], - "FlowVarAnnual_rpitvo": [ + "flow_var_annual_rpitvo": [ [ "utopia", 2000, @@ -14297,7 +14297,7 @@ "TX" ] ], - "FlowVar_rpsditvo": [ + "flow_var_rpsditvo": [ [ "utopia", 1990, @@ -21919,7 +21919,7 @@ "RH" ] ], - "LifetimeProcess_rtv": [ + "lifetime_process_rtv": [ [ "utopia", "IMPURN1", @@ -22211,10 +22211,10 @@ 2000 ] ], - "LimitActivityConstraint_rpt": [], - "LimitActivityShareConstraint_rpgg": [], - "LimitAnnualCapacityFactorConstraint_rpto": [], - "LimitCapacityConstraint_rpt": [ + "limit_activity_constraint_rpt": [], + "limit_activity_share_constraint_rpgg": [], + "limit_annual_capacity_factor_constraint_rpto": [], + "limit_capacity_constraint_rpt": [ [ "utopia", 1990, @@ -22282,25 +22282,25 @@ "ge" ] ], - "LimitCapacityShareConstraint_rpgg": [], - "LimitDegrowthCapacityConstraint_rpt": [], - "LimitDegrowthNewCapacityConstraint_rpt": [], - "LimitDegrowthNewCapacityDeltaConstraint_rpt": [], - "LimitEmissionConstraint_rpe": [], - "LimitGrowthCapacityConstraint_rpt": [], - "LimitGrowthNewCapacityConstraint_rpt": [], - "LimitGrowthNewCapacityDeltaConstraint_rpt": [], - "LimitNewCapacityConstraint_rpt": [], - "LimitNewCapacityShareConstraint_rpgg": [], - "LimitResourceConstraint_rt": [], - "LimitSeasonalCapacityFactorConstraint_rpst": [], - "LimitStorageFractionConstraint_rpsdtv": [], - "LimitTechInputSplitAnnualConstraint_rpitv": [], - "LimitTechInputSplitAverageConstraint_rpitv": [], - "LimitTechInputSplitConstraint_rpsditv": [], - "LimitTechOutputSplitAnnualConstraint_rptvo": [], - "LimitTechOutputSplitAverageConstraint_rptvo": [], - "LimitTechOutputSplitConstraint_rpsdtvo": [ + "limit_capacity_share_constraint_rpgg": [], + "limit_degrowth_capacity_constraint_rpt": [], + "limit_degrowth_new_capacity_constraint_rpt": [], + "limit_degrowth_new_capacity_delta_constraint_rpt": [], + "limit_emission_constraint_rpe": [], + "limit_growth_capacity_constraint_rpt": [], + "limit_growth_new_capacity_constraint_rpt": [], + "limit_growth_new_capacity_delta_constraint_rpt": [], + "limit_new_capacity_constraint_rpt": [], + "limit_new_capacity_share_constraint_rpgg": [], + "limit_resource_constraint_rt": [], + "limit_seasonal_capacity_factor_constraint_rpst": [], + "limit_storage_fraction_constraint_rpsdtv": [], + "limit_tech_input_split_annual_constraint_rpitv": [], + "limit_tech_input_split_average_constraint_rpitv": [], + "limit_tech_input_split_constraint_rpsditv": [], + "limit_tech_output_split_annual_constraint_rptvo": [], + "limit_tech_output_split_average_constraint_rptvo": [], + "limit_tech_output_split_constraint_rpsdtvo": [ [ "utopia", 2010, @@ -23022,8 +23022,8 @@ "ge" ] ], - "LinkedEmissionsTechConstraint_rpsdtve": [], - "LoanLifetimeProcess_rtv": [ + "linked_emissions_tech_constraint_rpsdtve": [], + "loan_lifetime_process_rtv": [ [ "utopia", "IMPURN1", @@ -23240,7 +23240,7 @@ 2000 ] ], - "NewCapacityVar_rtv": [ + "new_capacity_var_rtv": [ [ "utopia", "TXD", @@ -23422,7 +23422,7 @@ 2000 ] ], - "ProcessLifeFrac_rptv": [ + "process_life_frac_rptv": [ [ "utopia", 2000, @@ -24114,20 +24114,20 @@ 1990 ] ], - "RampDownDayConstraint_rpsdtv": [], - "RampDownSeasonConstraint_rpsstv": [], - "RampUpDayConstraint_rpsdtv": [], - "RampUpSeasonConstraint_rpsstv": [], - "RegionalExchangeCapacityConstraint_rrptv": [], - "RenewablePortfolioStandardConstraint_rpg": [], - "ReserveMargin_rpsd": [], - "ReserveMarginMethod": [ + "ramp_down_day_constraint_rpsdtv": [], + "ramp_down_season_constraint_rpsstv": [], + "ramp_up_day_constraint_rpsdtv": [], + "ramp_up_season_constraint_rpsstv": [], + "regional_exchange_capacity_constraint_rrptv": [], + "renewable_portfolio_standard_constraint_rpg": [], + "reserve_margin_rpsd": [], + "reserve_margin_method": [ "static" ], - "RetiredCapacityVar_rptv": [], - "SeasonalStorageLevel_rpstv": [], - "SeasonalStorageConstraints_rpsdtv": [], - "StorageConstraints_rpsdtv": [ + "retired_capacity_var_rptv": [], + "seasonal_storage_level_rpstv": [], + "seasonal_storage_constraints_rpsdtv": [], + "storage_constraints_rpsdtv": [ [ "utopia", 1990, @@ -24561,7 +24561,7 @@ 2010 ] ], - "StorageLevel_rpsdtv": [ + "storage_level_rpsdtv": [ [ "utopia", 1990, @@ -24995,7 +24995,7 @@ 2010 ] ], - "TimeNext": [], + "time_manual": [], "commodity_all": [ "ethos", "RH", @@ -25058,10 +25058,10 @@ "le" ], "ordered_season_sequential": [], - "regionalGlobalIndices": [ + "regional_global_indices": [ "utopia" ], - "regionalIndices": [ + "regional_indices": [ "utopia" ], "regions": [ @@ -25210,18 +25210,18 @@ 2010, 1990 ], - "TimeSeason": [ + "time_season": [ 2000, 2010, 1990 ], - "time_season": [ + "time_season_all": [ "summer", "inter", "winter" ], - "time_season_sequential": [], - "TimeSequencing": [ + "time_season_to_sequential": [], + "time_sequencing": [ "seasonal_timeslices" ], "vintage_all": [ @@ -25242,4 +25242,4 @@ 2010, 1990 ] -} \ No newline at end of file +} From 3907dcabe949b924e6d505c55b0e0990e401f087 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 7 Nov 2025 10:40:53 -0500 Subject: [PATCH 313/587] creating new database schema --- data_files/temoa_schema_v4.sql | 1057 ++++++++++++++++++++++++++++++++ temoa/version_information.py | 32 +- 2 files changed, 1059 insertions(+), 30 deletions(-) create mode 100644 data_files/temoa_schema_v4.sql diff --git a/data_files/temoa_schema_v4.sql b/data_files/temoa_schema_v4.sql new file mode 100644 index 000000000..1af18ad09 --- /dev/null +++ b/data_files/temoa_schema_v4.sql @@ -0,0 +1,1057 @@ +PRAGMA foreign_keys= OFF; +BEGIN TRANSACTION; + +CREATE TABLE IF NOT EXISTS metadata +( + element TEXT, + value INTEGER, + notes TEXT, + PRIMARY KEY (element) +); +REPLACE INTO metadata +VALUES ('DB_MAJOR', 4, 'DB major version number'); +REPLACE INTO metadata +VALUES ('DB_MINOR', 0, 'DB minor version number'); +REPLACE INTO metadata +VALUES ('days_per_period', 365, 'count of days in each period'); + +CREATE TABLE IF NOT EXISTS metadata_real +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +REPLACE INTO metadata_real +VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); +REPLACE INTO metadata_real +VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in LoanRate table'); + +CREATE TABLE IF NOT EXISTS output_dual_variable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE IF NOT EXISTS output_objective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE IF NOT EXISTS season_label +( + season TEXT PRIMARY KEY, + notes TEXT +); +CREATE TABLE IF NOT EXISTS sector_label +( + sector TEXT PRIMARY KEY, + notes TEXT +); +CREATE TABLE IF NOT EXISTS capacity_credit +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER, + credit REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage), + CHECK (credit >= 0 AND credit <= 1) +); +CREATE TABLE IF NOT EXISTS capacity_factor_process +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS capacity_factor_tech +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS capacity_to_activity +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + c2a REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS commodity +( + name TEXT + PRIMARY KEY, + flag TEXT + REFERENCES commodity_type (label), + description TEXT +); +CREATE TABLE IF NOT EXISTS commodity_type +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO commodity_type +VALUES ('s', 'source commodity'); +REPLACE INTO commodity_type +VALUES ('a', 'annual commodity'); +REPLACE INTO commodity_type +VALUES ('p', 'physical commodity'); +REPLACE INTO commodity_type +VALUES ('d', 'demand commodity'); +REPLACE INTO commodity_type +VALUES ('e', 'emissions commodity'); +REPLACE INTO commodity_type +VALUES ('w', 'waste commodity'); +REPLACE INTO commodity_type +VALUES ('wa', 'waste annual commodity'); +REPLACE INTO commodity_type +VALUES ('wp', 'waste physical commodity'); +CREATE TABLE IF NOT EXISTS construction_input +( + region TEXT, + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS cost_emission +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT NOT NULL + REFERENCES commodity (name), + cost REAL NOT NULL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE IF NOT EXISTS cost_fixed +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES time_period (period), + tech TEXT NOT NULL + REFERENCES technology (tech), + vintage INTEGER NOT NULL + REFERENCES time_period (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS cost_invest +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS cost_variable +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES time_period (period), + tech TEXT NOT NULL + REFERENCES technology (tech), + vintage INTEGER NOT NULL + REFERENCES time_period (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS demand +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + commodity TEXT + REFERENCES commodity (name), + demand REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, commodity) +); +CREATE TABLE IF NOT EXISTS demand_specific_distribution +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + demand_name TEXT + REFERENCES commodity (name), + dsd REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), + CHECK (dsd >= 0 AND dsd <= 1) +); +CREATE TABLE IF NOT EXISTS end_of_life_output +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS efficiency +( + region TEXT, + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE IF NOT EXISTS efficiency_variable +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE IF NOT EXISTS emission_activity +( + region TEXT, + emis_comm TEXT + REFERENCES commodity (name), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS emission_embodied +( + region TEXT, + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS emission_end_of_life +( + region TEXT, + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS existing_capacity +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS tech_group +( + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE IF NOT EXISTS loan_lifetime_process +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS loan_rate +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS lifetime_process +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS lifetime_tech +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +REPLACE INTO operator VALUES('e','equal to'); +REPLACE INTO operator VALUES('le','less than or equal to'); +REPLACE INTO operator VALUES('ge','greater than or equal to'); +CREATE TABLE IF NOT EXISTS limit_growth_capacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_degrowth_capacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_growth_new_capacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_degrowth_new_capacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_growth_new_capacity_delta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_degrowth_new_capacity_delta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_storage_level_fraction +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) +); +CREATE TABLE IF NOT EXISTS limit_activity +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_activity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_annual_capacity_factor +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS limit_capacity +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_capacity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_new_capacity +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_new_capacity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_resource +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_seasonal_capacity_factor +( + region TEXT + REFERENCES region (region), + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tech TEXT + REFERENCES technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) +); +CREATE TABLE IF NOT EXISTS limit_tech_input_split +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE IF NOT EXISTS limit_tech_input_split_annual +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE IF NOT EXISTS limit_tech_output_split +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE IF NOT EXISTS limit_tech_output_split_annual +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE IF NOT EXISTS limit_emission +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE IF NOT EXISTS linked_tech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES technology (tech), + emis_comm TEXT + REFERENCES commodity (name), + driven_tech TEXT + REFERENCES technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE IF NOT EXISTS output_curtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES time_period (period), + tod TEXT + REFERENCES time_of_day (tod), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS output_net_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS output_built_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE IF NOT EXISTS output_retired_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS output_flow_in +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS output_flow_out +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS output_storage_level +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); +CREATE TABLE IF NOT EXISTS planning_reserve_margin +( + region TEXT + PRIMARY KEY + REFERENCES region (region), + margin REAL, + notes TEXT +); +CREATE TABLE IF NOT EXISTS ramp_down_hourly +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS ramp_up_hourly +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS region +( + region TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE IF NOT EXISTS reserve_capacity_derate +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS time_segment_fraction +( + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + segment_fraction REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) +); +CREATE TABLE IF NOT EXISTS storage_duration +( + region TEXT, + tech TEXT, + duration REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS lifetime_survival_curve +( + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES technology (tech), + vintage INTEGER NOT NULL + REFERENCES time_period (period), + fraction REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS technology_type +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO technology_type +VALUES ('p', 'production technology'); +REPLACE INTO technology_type +VALUES ('pb', 'baseload production technology'); +REPLACE INTO technology_type +VALUES ('ps', 'storage production technology'); +-- CREATE TABLE IF NOT EXISTS time_manual +-- ( +-- period INTEGER +-- REFERENCES time_period (period), +-- season TEXT +-- REFERENCES season_label (season), +-- tod TEXT +-- REFERENCES time_of_day (tod), +-- season_next TEXT +-- REFERENCES season_label (season), +-- tod_next TEXT +-- REFERENCES time_of_day (tod), +-- notes TEXT, +-- PRIMARY KEY (period, season, tod) +-- ); +CREATE TABLE IF NOT EXISTS time_of_day +( + sequence INTEGER UNIQUE, + tod TEXT + PRIMARY KEY +); +CREATE TABLE IF NOT EXISTS time_period +( + sequence INTEGER UNIQUE, + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES time_period_type (label) +); +CREATE TABLE IF NOT EXISTS time_season_all +( + period INTEGER + REFERENCES time_period (period), + sequence INTEGER, + season TEXT + REFERENCES season_label (season), + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +CREATE TABLE IF NOT EXISTS time_season_to_sequential +( + period INTEGER + REFERENCES time_period (period), + sequence INTEGER, + seas_seq TEXT, + season TEXT + REFERENCES season_label (season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) +); +CREATE TABLE IF NOT EXISTS time_period_type +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO time_period_type +VALUES('e', 'existing vintages'); +REPLACE INTO time_period_type +VALUES('f', 'future'); +CREATE TABLE IF NOT EXISTS output_emission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS rps_requirement +( + region TEXT NOT NULL + REFERENCES region (region), + period INTEGER NOT NULL + REFERENCES time_period (period), + tech_group TEXT NOT NULL + REFERENCES tech_group (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE IF NOT EXISTS tech_group_member +( + group_name TEXT + REFERENCES tech_group (group_name), + tech TEXT + REFERENCES technology (tech), + PRIMARY KEY (group_name, tech) +); +CREATE TABLE IF NOT EXISTS technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES technology_type (label) +); +CREATE TABLE IF NOT EXISTS output_cost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) +); +COMMIT; +PRAGMA foreign_keys = 1; diff --git a/temoa/version_information.py b/temoa/version_information.py index be8a05734..3d9d6e94d 100644 --- a/temoa/version_information.py +++ b/temoa/version_information.py @@ -1,40 +1,12 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 4/1/24 - -""" - # === INFORMATION === # current Temoa version -TEMOA_MAJOR = 3 +TEMOA_MAJOR = 4 TEMOA_MINOR = 0 # === REQUIREMENTS === # python versions are tested internally for greater than these values MIN_PYTHON_MAJOR = 3 -MIN_PYTHON_MINOR = 11 +MIN_PYTHON_MINOR = 12 # db is tested for match on major and >= on minor DB_MAJOR_VERSION = 3 From ea5d1a81fcd7f938195e3164bc0343c5933cabbf Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 7 Nov 2025 15:18:17 -0500 Subject: [PATCH 314/587] new database schema and correcting code to expect new schema --- data_files/temoa_schema_v4.sql | 24 ++++++- docs/Database Upgrade and Troubleshooting.md | 2 +- docs/source/Documentation.rst | 14 ++-- temoa/_internal/table_writer.py | 52 +++++++------- temoa/components/commodities.py | 2 +- temoa/components/operations.py | 4 +- temoa/components/time.py | 22 +++--- temoa/data_io/component_manifest.py | 70 +++++++++---------- temoa/data_io/hybrid_loader.py | 20 +++--- temoa/data_processing/database_util.py | 18 ++--- temoa/data_processing/db_to_excel.py | 8 +-- temoa/data_processing/make_output_plots.py | 6 +- temoa/extensions/get_comm_tech.py | 10 +-- .../extensions/method_of_morris/MM_README.md | 4 +- temoa/extensions/method_of_morris/morris.py | 4 +- .../method_of_morris/morris_evaluate.py | 6 +- .../MGA Design.md | 40 +++++++---- .../README.md | 18 ++--- .../example_builds/scenario_analyzer.py | 2 +- temoa/extensions/myopic/myopic_sequencer.py | 68 +++++++++--------- .../single_vector_mga/output_summary.py | 6 +- temoa/model_checking/network_model_data.py | 38 +++++----- temoa/utilities/clear_db_outputs.py | 22 +++--- temoa/utilities/db_migration_to_v3.py | 4 +- tests/test_emission_results.py | 20 +++--- tests/test_full_runs.py | 2 +- tests/test_linked_tech.py | 11 +-- tests/test_material_results.py | 2 +- tests/test_network_model_data.py | 10 +-- 29 files changed, 272 insertions(+), 237 deletions(-) diff --git a/data_files/temoa_schema_v4.sql b/data_files/temoa_schema_v4.sql index 1af18ad09..b8492044e 100644 --- a/data_files/temoa_schema_v4.sql +++ b/data_files/temoa_schema_v4.sql @@ -4,7 +4,7 @@ BEGIN TRANSACTION; CREATE TABLE IF NOT EXISTS metadata ( element TEXT, - value INTEGER, + value INT, notes TEXT, PRIMARY KEY (element) ); @@ -1053,5 +1053,27 @@ CREATE TABLE IF NOT EXISTS output_cost FOREIGN KEY (vintage) REFERENCES time_period (period), FOREIGN KEY (tech) REFERENCES technology (tech) ); + +CREATE TABLE IF NOT EXISTS time_season +( + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + season TEXT REFERENCES season_label(season), + notes TEXT, + PRIMARY KEY (period, sequence, season) +); + +CREATE TABLE IF NOT EXISTS time_season_sequential +( + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + seas_seq TEXT, + season TEXT REFERENCES season_label(season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) +); + COMMIT; PRAGMA foreign_keys = 1; diff --git a/docs/Database Upgrade and Troubleshooting.md b/docs/Database Upgrade and Troubleshooting.md index 0a47e2b92..3b11dfbfa 100644 --- a/docs/Database Upgrade and Troubleshooting.md +++ b/docs/Database Upgrade and Troubleshooting.md @@ -51,7 +51,7 @@ be slipped in to the `temoa_model.py` code anywhere in the constraint section. will limit **all** flows to an upper bound. If using this approach, the modeler should also limit any arbitrarily large demands in the demand table that may need to be revised downward in conjuction with this limit. -The `OutputFlowOut` table can then be inspected for unusually high activity. +The `output_flow_out` table can then be inspected for unusually high activity. ``` @M.Constraint(M.flow_var_rpsditvo) diff --git a/docs/source/Documentation.rst b/docs/source/Documentation.rst index 02ff833e8..f2ba0cab3 100644 --- a/docs/source/Documentation.rst +++ b/docs/source/Documentation.rst @@ -319,9 +319,9 @@ recommend that you populate input tables in the following order: **Group 2: sets used within Temoa** * Commodity: list of commodities used within the database * Technology: list of technologies used within the database - * TimePeriod: list of both past and future time periods considered in the database - * TimeSeason: seasons modeled in the database - * TimeOfDay: time of day segments modeled in the database + * time_period: list of both past and future time periods considered in the database + * time_season: seasons modeled in the database + * time_of_day: time of day segments modeled in the database **Group 3: parameters used to define processes within Temoa** @@ -750,7 +750,7 @@ Sets ":math:`\text{T}^e`",":code:`tech_existing`","string","technologies constructed in an existing (past) vintage; (:math:`{T}^e \subset T`)." ":math:`\text{T}^f`",":code:`tech_flex`","string","technologies producing excess commodity flows; (:math:`{T}^f \subset T`)" "",":code:`TechGroupName`","string","named groups for use in group constraints" - "",":code:`TechGroupMember`","(TechGroupName, tech)","Each technology belonging to each group defined above" + "",":code:`tech_group_member`","(TechGroupName, tech)","Each technology belonging to each group defined above" ":math:`\text{T}^p`",":code:`tech_production`","string","techs producing intermediate commodities" ":math:`\text{T}^{ur}`",":code:`tech_upramping`","string","electric generators with a ramp up hourly rate limit; (:math:`{T}^{ur} \subset T`)" ":math:`\text{T}^{dr}`",":code:`tech_downramping`","string","electric generators with a ramp down hourly rate limit; (:math:`{T}^{dr} \subset T`)" @@ -1278,7 +1278,7 @@ costs, which are the basis of the objective function. Costs are discounted to t first future time period in the model by default. If running a Myopic run, the discount base year can be set in the MetaData table. This is the :code:`MyopicBaseYear`. -The output in the :code:`OutputCost` table shows both discounted and non-discounted (raw) +The output in the :code:`output_cost` table shows both discounted and non-discounted (raw) values for all model costs. Of note, all loan costs are displayed as an annuity cost in the vintage year, not as a string of payments. @@ -1822,8 +1822,8 @@ portion of the electricity production counts towards the target, and there is no way to distinguish it from the useful production. Including an explicit curtailment term addresses the issue. Curtailment in the model is simply the production activity that is not used in the model and is reported as -such in the OutputCurtailment table. Note: Outputs presented in the -`OutputCurtailment` table for curtailment (the table separately includes +such in the output_curtailment table. Note: Outputs presented in the +`output_curtailment` table for curtailment (the table separately includes flex outputs) are limited by Capacity Factor. Meaning: if a tech has a capacity of 10 units, and a CF of 0.8 and a usage of 5 units, then the reported curtailment is 3 units (0.8 x 10 - 5). diff --git a/temoa/_internal/table_writer.py b/temoa/_internal/table_writer.py index 5a516bf76..42d8a7b9e 100644 --- a/temoa/_internal/table_writer.py +++ b/temoa/_internal/table_writer.py @@ -72,18 +72,18 @@ logger = getLogger(__name__) basic_output_tables = [ - 'OutputBuiltCapacity', - 'OutputCost', - 'OutputCurtailment', - 'OutputDualVariable', - 'OutputEmission', - 'OutputFlowIn', - 'OutputFlowOut', - 'OutputNetCapacity', - 'OutputObjective', - 'OutputRetiredCapacity', + 'output_built_capacity', + 'output_cost', + 'output_curtailment', + 'output_dual_variable', + 'output_emission', + 'output_flow_in', + 'output_flow_out', + 'output_net_capacity', + 'output_objective', + 'output_retired_capacity', ] -optional_output_tables = ['OutputFlowOutSummary', 'OutputMCDelta', 'OutputStorageLevel'] +optional_output_tables = ['output_flow_outSummary', 'OutputMCDelta', 'output_storage_level'] flow_summary_file_loc = Path( PROJECT_ROOT, 'temoa/extensions/modeling_to_generate_alternatives/make_flow_summary_table.sql' @@ -251,7 +251,7 @@ def write_storage_level(self, model: TemoaModel, iteration: int | None = None) - (scenario_name, sli.r, sector, sli.p, sli.s, sli.d, sli.t, sli.v, storage_level) ) - qry = f'INSERT INTO OutputStorageLevel VALUES {_marks(9)}' + qry = f'INSERT INTO output_storage_level VALUES {_marks(9)}' self.con.executemany(qry, data) self.con.commit() @@ -269,7 +269,7 @@ def _insert_objective_results( else self.config.scenario ) for obj_name, obj_value in obj_vals: - qry = 'INSERT INTO OutputObjective VALUES (?, ?, ?)' + qry = 'INSERT INTO output_objective VALUES (?, ?, ?)' data = (scenario_name, obj_name, obj_value) self.con.execute(qry, data) self.con.commit() @@ -297,7 +297,7 @@ def write_emissions(self, iteration: int | None = None) -> None: else: # embodied emissions entry = (scenario, ei.r, sector, cast(int, ei.v), ei.e, ei.t, ei.v, val) data.append(entry) - qry = f'INSERT INTO OutputEmission VALUES {_marks(8)}' + qry = f'INSERT INTO output_emission VALUES {_marks(8)}' self.con.executemany(qry, data) self.con.commit() @@ -314,7 +314,7 @@ def _insert_capacity_results(self, cap_data: CapData, iteration: int | None) -> s = self.tech_sectors.get(t) new_cap = (scenario, r, s, t, v, val) data.append(new_cap) - qry = 'INSERT INTO OutputBuiltCapacity VALUES (?, ?, ?, ?, ?, ?)' + qry = 'INSERT INTO output_built_capacity VALUES (?, ?, ?, ?, ?, ?)' self.con.executemany(qry, data) # NetCapacity @@ -331,7 +331,7 @@ def _insert_capacity_results(self, cap_data: CapData, iteration: int | None) -> val, ) data_net.append(new_net_cap) - qry = 'INSERT INTO OutputNetCapacity VALUES (?, ?, ?, ?, ?, ?, ?)' + qry = 'INSERT INTO output_net_capacity VALUES (?, ?, ?, ?, ?, ?, ?)' self.con.executemany(qry, data_net) # Retired Capacity @@ -349,7 +349,7 @@ def _insert_capacity_results(self, cap_data: CapData, iteration: int | None) -> early, ) data_ret.append(new_retired_cap) - qry = 'INSERT INTO OutputRetiredCapacity VALUES (?, ?, ?, ?, ?, ?, ?, ?)' + qry = 'INSERT INTO output_retired_capacity VALUES (?, ?, ?, ?, ?, ?, ?, ?)' self.con.executemany(qry, data_ret) self.con.commit() @@ -384,10 +384,10 @@ def write_flow_tables(self, iteration: int | None = None) -> None: flows_by_type[flow_type].append(entry) table_associations = { - FlowType.OUT: 'OutputFlowOut', - FlowType.IN: 'OutputFlowIn', - FlowType.CURTAIL: 'OutputCurtailment', - FlowType.FLEX: 'OutputCurtailment', # devnote: should flex have its own table? + FlowType.OUT: 'output_flow_out', + FlowType.IN: 'output_flow_in', + FlowType.CURTAIL: 'output_curtailment', + FlowType.FLEX: 'output_curtailment', # devnote: should flex have its own table? } for flow_type, table_name in table_associations.items(): @@ -453,7 +453,7 @@ def _insert_summary_flow_results( entry: tuple[str, str, str | None, int, str, str, int, str, float] = (*idx, flow) entries.append(entry) - qry = f'INSERT INTO OutputFlowOutSummary VALUES {_marks(9)}' + qry = f'INSERT INTO output_flow_outSummary VALUES {_marks(9)}' self.con.executemany(qry, entries) self.con.commit() @@ -575,7 +575,7 @@ def _write_cost_rows( entries: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]], iteration: int | None = None, ) -> None: - """Write the entries to the OutputCost table""" + """Write the entries to the output_cost table""" if self.tech_sectors is None: raise RuntimeError('tech sectors not available... code error') cur = self.con.cursor() @@ -604,12 +604,12 @@ def _write_cost_rows( for (r, p, t, v) in entries ] rows.sort(key=lambda r: (r[0:5])) - qry = 'INSERT INTO OutputCost VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' + qry = 'INSERT INTO output_cost VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' cur.executemany(qry, rows) self.con.commit() def write_dual_variables(self, results: SolverResults, iteration: int | None = None) -> None: - """Write the dual variables to the OutputDualVariable table""" + """Write the dual variables to the output_dual_variable table""" scenario_name = ( self.config.scenario + f'-{iteration}' if iteration is not None @@ -617,7 +617,7 @@ def write_dual_variables(self, results: SolverResults, iteration: int | None = N ) # collect the values constraint_data = results['Solution'].Constraint.items() dual_data = [(scenario_name, t[0], t[1]['Dual']) for t in constraint_data] - qry = 'INSERT INTO OutputDualVariable VALUES (?, ?, ?)' + qry = 'INSERT INTO output_dual_variable VALUES (?, ?, ?)' self.con.executemany(qry, dual_data) self.con.commit() diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index 4699598b1..99288bce5 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -695,7 +695,7 @@ def create_demands(model: TemoaModel) -> None: # devnote: DDD just clones segment_fraction. Unless we want to specify it in the database, # makes sense to just use segment_fraction directly - # Step 2: Build the demand default distribution (= segfrac) + # Step 2: Build the demand default distribution (= segment_fraction) # DDD = M.DemandDefaultDistribution # Shorter, for us lazy programmer types # unset_defaults = set(M.segment_fraction.sparse_iterkeys()) # unset_defaults.difference_update(DDD.sparse_iterkeys()) diff --git a/temoa/components/operations.py b/temoa/components/operations.py index e01579970..7221ca19c 100644 --- a/temoa/components/operations.py +++ b/temoa/components/operations.py @@ -455,7 +455,7 @@ def ramp_up_season_constraint( of sequential seasons. Same as RampUpDay but only applies to the boundary between sequential seasons, i.e., :math:`(s^{seq},d_{last})` to :math:`(s^{seq}_{next},d_{first})` and :math:`s^{seq}_{next}` is based on the TimeSequential table rather than the - TimeSeason table. + time_season table. """ d = model.time_of_day.last() @@ -528,7 +528,7 @@ def ramp_down_season_constraint( of sequential seasons. Same as RampDownDay but only applies to the boundary between sequential seasons, i.e., :math:`(s^{seq},d_{last})` to :math:`(s^{seq}_{next},d_{first})` and :math:`s^{seq}_{next}` is based on the TimeSequential table rather than the - TimeSeason table. + time_season table. """ d = model.time_of_day.last() diff --git a/temoa/components/time.py b/temoa/components/time.py index 57ebdea5a..be1e3e3a2 100644 --- a/temoa/components/time.py +++ b/temoa/components/time.py @@ -102,9 +102,9 @@ def validate_segment_fraction(model: TemoaModel) -> None: extra: set[tuple[int, str, str]] = keys.difference(expected_keys) missing: set[tuple[int, str, str]] = expected_keys.difference(keys) msg: str = ( - 'TimeSegmentFraction elements for period {} do not match TimeSeason and TimeOfDay.' + 'TimeSegmentFraction elements for period {} do not match time_season and time_of_day.' '\n\nIndices missing from TimeSegmentFraction:\n{}' - '\n\nIndices in TimeSegmentFraction missing from TimeSeason/TimeOfDay:\n{}' + '\n\nIndices in TimeSegmentFraction missing from time_season/time_of_day:\n{}' ).format(p, missing, extra) logger.error(msg) raise ValueError(msg) @@ -146,7 +146,7 @@ def validate_time_manual(model: TemoaModel) -> None: if model.time_sequencing.first() != 'manual': return - segfrac_psd: set[tuple[int, str, str]] = set(model.segment_fraction.sparse_iterkeys()) + segment_fraction_psd: set[tuple[int, str, str]] = set(model.segment_fraction.sparse_iterkeys()) time_manual_psd: set[tuple[int, str, str]] = { (p, s, d) for p, s, d, s_next, d_next in model.time_manual } @@ -154,8 +154,10 @@ def validate_time_manual(model: TemoaModel) -> None: (p, s_next, d_next) for p, s, d, s_next, d_next in model.time_manual } - missing_psd: set[tuple[int, str, str]] = segfrac_psd.difference(time_manual_psd) - missing_psd_next: set[tuple[int, str, str]] = segfrac_psd.difference(time_manual_psd_next) + missing_psd: set[tuple[int, str, str]] = segment_fraction_psd.difference(time_manual_psd) + missing_psd_next: set[tuple[int, str, str]] = segment_fraction_psd.difference( + time_manual_psd_next + ) if missing_psd or missing_psd_next: msg: str = ( 'Failed to build state sequence. ' @@ -326,7 +328,7 @@ def create_time_season_to_sequential(model: TemoaModel) -> None: if model.time_sequencing.first() in ('consecutive_days', 'seasonal_timeslices'): logger.info( 'No data in time_season_sequential. By default, assuming sequential seasons ' - 'match TimeSeason and TimeSegmentFraction.' + 'match time_season and TimeSegmentFraction.' ) for s in model.time_season_all: model.time_season_to_sequential.add(s) @@ -403,14 +405,14 @@ def create_time_season_to_sequential(model: TemoaModel) -> None: logger.warning(msg) # Check that the two tables agree on the total seasonal composition of each period - segfrac = value(model.segment_fraction_per_season[p, s]) - segfracseq = sequential[p, s] / count_total[p] - if abs(segfrac - segfracseq) >= 0.001: + segment_fraction = value(model.segment_fraction_per_season[p, s]) + segment_fraction_seq = sequential[p, s] / count_total[p] + if abs(segment_fraction - segment_fraction_seq) >= 0.001: msg = ( 'Discrepancy of total period-season composition between ' 'TimeSegmentFraction and time_season_sequential. Total fraction of each ' 'period assigned to each season should match: ' f'TimeSegmentFraction: {(p, s, value(model.segment_fraction_per_season[p, s]))}' - f', time_season_sequential: {(p, s, segfracseq)}' + f', time_season_sequential: {(p, s, segment_fraction_seq)}' ) logger.warning(msg) diff --git a/temoa/data_io/component_manifest.py b/temoa/data_io/component_manifest.py index 8665a23a3..966d6aaba 100644 --- a/temoa/data_io/component_manifest.py +++ b/temoa/data_io/component_manifest.py @@ -40,7 +40,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: # ========================================================================= LoadItem( component=model.regions, - table='Region', + table='region', columns=['region'], is_period_filtered=False, ), @@ -54,7 +54,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.tech_production, - table='Technology', + table='technology', columns=['tech'], where_clause="flag LIKE 'p%'", validator_name='viable_techs', @@ -63,7 +63,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.tech_uncap, - table='Technology', + table='technology', columns=['tech'], where_clause='unlim_cap > 0', validator_name='viable_techs', @@ -73,7 +73,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.tech_baseload, - table='Technology', + table='technology', columns=['tech'], where_clause="flag = 'pb'", validator_name='viable_techs', @@ -82,7 +82,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.tech_storage, - table='Technology', + table='technology', columns=['tech'], where_clause="flag = 'ps'", validator_name='viable_techs', @@ -91,7 +91,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.tech_seasonal_storage, - table='Technology', + table='technology', columns=['tech'], where_clause="flag = 'ps' AND seas_stor > 0", validator_name='viable_techs', @@ -100,7 +100,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.tech_reserve, - table='Technology', + table='technology', columns=['tech'], where_clause='reserve > 0', validator_name='viable_techs', @@ -109,7 +109,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.tech_curtailment, - table='Technology', + table='technology', columns=['tech'], where_clause='curtail > 0', validator_name='viable_techs', @@ -118,7 +118,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.tech_flex, - table='Technology', + table='technology', columns=['tech'], where_clause='flex > 0', validator_name='viable_techs', @@ -127,7 +127,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.tech_exchange, - table='Technology', + table='technology', columns=['tech'], where_clause='exchange > 0', validator_name='viable_techs', @@ -136,7 +136,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.tech_annual, - table='Technology', + table='technology', columns=['tech'], where_clause='annual > 0', validator_name='viable_techs', @@ -145,7 +145,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.tech_retirement, - table='Technology', + table='technology', columns=['tech'], where_clause='retire > 0', validator_name='viable_techs', @@ -154,14 +154,14 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.tech_group_names, - table='TechGroup', + table='tech_group', columns=['group_name'], is_period_filtered=False, is_table_required=False, ), LoadItem( component=model.tech_group_members, - table='TechGroupMember', + table='tech_group_member', columns=['group_name', 'tech'], custom_loader_name='_load_tech_group_members', is_period_filtered=False, @@ -169,7 +169,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.commodity_demand, - table='Commodity', + table='commodity', columns=['name'], where_clause="flag = 'd'", validator_name='viable_comms', @@ -178,14 +178,14 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.commodity_emissions, - table='Commodity', + table='commodity', columns=['name'], where_clause="flag = 'e'", is_period_filtered=False, ), LoadItem( component=model.commodity_physical, - table='Commodity', + table='commodity', columns=['name'], where_clause="flag LIKE '%p%' OR flag = 's' OR flag LIKE '%a%'", validator_name='viable_input_comms', @@ -194,7 +194,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.commodity_source, - table='Commodity', + table='commodity', columns=['name'], where_clause="flag = 's'", validator_name='viable_input_comms', @@ -203,7 +203,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.commodity_annual, - table='Commodity', + table='commodity', columns=['name'], where_clause="flag LIKE '%a%'", validator_name='viable_input_comms', @@ -212,7 +212,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.commodity_waste, - table='Commodity', + table='commodity', columns=['name'], where_clause="flag LIKE '%w%'", validator_name='viable_output_comms', @@ -221,7 +221,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.operator, - table='Operator', + table='operator', columns=['operator'], is_period_filtered=False, is_table_required=False, @@ -231,7 +231,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: # ========================================================================= LoadItem( component=model.time_of_day, - table='TimeOfDay', + table='time_of_day', columns=['tod'], is_period_filtered=False, is_table_required=False, @@ -239,7 +239,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.time_season, - table='TimeSeason', + table='time_season', columns=['period', 'season'], custom_loader_name='_load_time_season', is_period_filtered=False, # Custom loader handles myopic filtering @@ -247,15 +247,15 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.time_season_sequential, - table='time_season_sequential', + table='time_season_to_sequential', columns=['period', 'seas_seq', 'season', 'num_days'], custom_loader_name='_load_time_season_to_sequential', is_table_required=False, ), LoadItem( component=model.segment_fraction, - table='TimeSegmentFraction', - columns=['period', 'season', 'tod', 'segfrac'], + table='time_segment_fraction', + columns=['period', 'season', 'tod', 'segment_fraction'], custom_loader_name='_load_segment_fraction', is_table_required=False, ), @@ -315,7 +315,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: # ========================================================================= LoadItem( component=model.days_per_period, - table='MetaData', + table='metadata', columns=['value'], where_clause="element == 'days_per_period'", custom_loader_name='_load_days_per_period', @@ -324,7 +324,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.global_discount_rate, - table='MetaDataReal', + table='metadata_real', columns=['value'], where_clause="element = 'global_discount_rate'", custom_loader_name='_load_global_discount_rate', @@ -333,7 +333,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.default_loan_rate, - table='MetaDataReal', + table='metadata_real', columns=['value'], where_clause="element = 'default_loan_rate'", custom_loader_name='_load_default_loan_rate', @@ -371,18 +371,18 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.demand, - table='Demand', + table='demand', columns=['region', 'period', 'commodity', 'demand'], ), LoadItem( component=model.demand_specific_distribution, - table='DemandSpecificDistribution', + table='demand_specific_distribution', columns=['region', 'period', 'season', 'tod', 'demand_name', 'dsd'], is_table_required=False, ), LoadItem( component=model.capacity_to_activity, - table='CapacityToActivity', + table='capacity_to_activity', columns=['region', 'tech', 'c2a'], validator_name='viable_rt', validation_map=(0, 1), @@ -479,7 +479,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.renewable_portfolio_standard, - table='RPSRequirement', + table='rps_requirement', columns=['region', 'period', 'tech_group', 'requirement'], custom_loader_name='_load_rps_requirement', is_table_required=False, @@ -518,7 +518,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.limit_storage_fraction, - table='LimitStorageLevelFraction', + table='limit_storage_level_fraction', columns=[ 'region', 'period', @@ -692,7 +692,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.linked_techs, - table='LinkedTech', + table='linked_tech', columns=['primary_region', 'primary_tech', 'emis_comm', 'driven_tech'], validator_name='viable_rtt', validation_map=(0, 1, 3), diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index 107caa8f5..2e8774f6f 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -197,19 +197,19 @@ def create_data_dict(self, myopic_index: MyopicIndex | None = None) -> dict[str, # Load critical time sets first, as they index other components if myopic_index: raw_exist = cur.execute( - 'SELECT period FROM TimePeriod WHERE period < ? ORDER BY sequence', + 'SELECT period FROM time_period WHERE period < ? ORDER BY sequence', (myopic_index.base_year,), ).fetchall() raw_future = cur.execute( - 'SELECT period FROM TimePeriod WHERE flag = "f" AND period >= ? AND period <= ? ORDER BY sequence', + 'SELECT period FROM time_period WHERE flag = "f" AND period >= ? AND period <= ? ORDER BY sequence', (myopic_index.base_year, myopic_index.last_year), ).fetchall() else: raw_exist = cur.execute( - "SELECT period FROM TimePeriod WHERE flag = 'e' ORDER BY sequence" + "SELECT period FROM time_period WHERE flag = 'e' ORDER BY sequence" ).fetchall() raw_future = cur.execute( - "SELECT period FROM TimePeriod WHERE flag = 'f' ORDER BY sequence" + "SELECT period FROM time_period WHERE flag = 'f' ORDER BY sequence" ).fetchall() self._load_component_data(data, model.time_exist, raw_exist) self._load_component_data(data, model.time_future, raw_future) @@ -262,7 +262,7 @@ def create_data_dict(self, myopic_index: MyopicIndex | None = None) -> dict[str, ) if myopic_index: p0_result = cur.execute( - "SELECT min(period) FROM TimePeriod WHERE flag == 'f'" + "SELECT min(period) FROM time_period WHERE flag == 'f'" ).fetchone() if p0_result: data[model.myopic_discounting_year.name] = {None: int(p0_result[0])} @@ -408,7 +408,7 @@ def _source_trace(self, myopic_index: MyopicIndex | None = None) -> None: [ p for (p,) in cur.execute( - "SELECT period FROM TimePeriod WHERE flag = 'f' ORDER BY period" + "SELECT period FROM time_period WHERE flag = 'f' ORDER BY period" ) ][:-1] # drop last period ) @@ -536,7 +536,7 @@ def _load_time_season( filtered_data: Sequence[tuple[object, ...]], ) -> None: """ - Loads the indexed TimeSeason set and the simple time_season set, + Loads the indexed time_season set and the simple time_season set, with a dynamic fallback if the table is missing. """ model = TemoaModel() @@ -545,7 +545,7 @@ def _load_time_season( rows_to_load: list[tuple[object, ...]] = [] if not raw_data: - logger.warning('No TimeSeason table found. Loading a single filler season "S".') + logger.warning('No time_season table found. Loading a single filler season "S".') rows_to_load = [(p, 'S') for p in time_optimize] elif mi: valid_periods = set(time_optimize) @@ -618,11 +618,11 @@ def _load_existing_capacity( rows_to_load = [] if mi: prev_period_res = cur.execute( - 'SELECT MAX(period) FROM TimePeriod WHERE period < ?', (mi.base_year,) + 'SELECT MAX(period) FROM time_period WHERE period < ?', (mi.base_year,) ).fetchone() prev_period = prev_period_res[0] if prev_period_res else -1 rows_to_load = cur.execute( - 'SELECT region, tech, vintage, capacity FROM OutputBuiltCapacity WHERE vintage <= ? AND scenario = ? ' + 'SELECT region, tech, vintage, capacity FROM output_built_capacity WHERE vintage <= ? AND scenario = ? ' 'UNION SELECT region, tech, vintage, capacity FROM existing_capacity', (prev_period, self.config.scenario), ).fetchall() diff --git a/temoa/data_processing/database_util.py b/temoa/data_processing/database_util.py index a9fed2109..68baf7323 100644 --- a/temoa/data_processing/database_util.py +++ b/temoa/data_processing/database_util.py @@ -109,10 +109,10 @@ def read_from_dat_file(self, inp_comm: str | None, inp_tech: str | None) -> pd.D def get_time_peridos_for_flags(self, flags: list[str] | None = None) -> set[int]: """Retrieves a set of time periods, optionally filtered by flags.""" if (flags is None) or (not flags): - query = 'SELECT period FROM TimePeriod' + query = 'SELECT period FROM time_period' else: in_clause = ', '.join(f"'{flag}'" for flag in flags) - query = f'SELECT period FROM TimePeriod WHERE flag IN ({in_clause})' + query = f'SELECT period FROM time_period WHERE flag IN ({in_clause})' self.cur.execute(query) return {int(row[0]) for row in self.cur} @@ -194,7 +194,7 @@ def get_capacity_for_tech_and_period( raise ValueError('A scenario must be set for output-related queries') columns = ['tech', 'period', 'SUM(capacity)', 'region'] - query = f"SELECT {', '.join(columns)} FROM OutputNetCapacity WHERE scenario IS '{self.scenario}'" + query = f"SELECT {', '.join(columns)} FROM output_net_capacity WHERE scenario IS '{self.scenario}'" if region: query += f" AND region LIKE '{region}%'" @@ -233,11 +233,11 @@ def get_output_flow_for_period( columns: list[str] = [] table = '' if comm_type == 'input': - table = 'OutputFlowIn' + table = 'output_flow_in' if commodity is None: columns.append('input_comm') elif comm_type == 'output': - table = 'OutputFlowOut' + table = 'output_flow_out' if commodity is None: columns.append('output_comm') columns.append('tech') @@ -269,7 +269,7 @@ def get_emissions_activity_for_period(self, period: int, region: str | None) -> query = f""" SELECT E.emis_comm, E.tech, SUM(E.activity * O.flow) - FROM emission_activity E, OutputFlowOut O + FROM emission_activity E, output_flow_out O WHERE E.input_comm = O.input_comm AND E.tech = O.tech AND E.vintage = O.vintage @@ -298,12 +298,12 @@ def get_commodity_wise_input_and_output_flow( OC.capacity FROM ( SELECT region, scenario, period, input_comm, tech, vintage, output_comm, SUM(flow) AS vflow_in - FROM OutputFlowIn + FROM output_flow_in GROUP BY region, scenario, period, input_comm, tech, vintage, output_comm ) AS OF INNER JOIN ( SELECT region, scenario, period, input_comm, tech, vintage, output_comm, SUM(flow) AS vflow_out - FROM OutputFlowOut + FROM output_flow_out GROUP BY region, scenario, period, input_comm, tech, vintage, output_comm ) AS OFO ON OF.region = OFO.region AND @@ -313,7 +313,7 @@ def get_commodity_wise_input_and_output_flow( OF.input_comm = OFO.input_comm AND OF.vintage = OFO.vintage AND OF.output_comm = OFO.output_comm - INNER JOIN OutputNetCapacity OC ON + INNER JOIN output_net_capacity OC ON OF.region = OC.region AND OF.scenario = OC.scenario AND OF.tech = OC.tech AND diff --git a/temoa/data_processing/db_to_excel.py b/temoa/data_processing/db_to_excel.py index c6cbd04bf..c5e4a4c1d 100644 --- a/temoa/data_processing/db_to_excel.py +++ b/temoa/data_processing/db_to_excel.py @@ -59,7 +59,7 @@ def make_excel(ifile: str | None, ofile: Path | None, scenario: set[str]) -> Non query_capacity = """ SELECT region, tech, sector, period, SUM(capacity) as capacity - FROM OutputNetCapacity WHERE scenario = ? + FROM output_net_capacity WHERE scenario = ? GROUP BY region, tech, sector, period """ df_capacity = pd.read_sql_query(query_capacity, con, params=(scenario_name,)) @@ -88,7 +88,7 @@ def make_excel(ifile: str | None, ofile: Path | None, scenario: set[str]) -> Non query_activity = """ SELECT region, tech, sector, period, SUM(flow) as vflow_out - FROM OutputFlowOut WHERE scenario = ? + FROM output_flow_out WHERE scenario = ? GROUP BY region, tech, sector, period """ df_activity = pd.read_sql_query(query_activity, con, params=(scenario_name,)) @@ -127,7 +127,7 @@ def make_excel(ifile: str | None, ofile: Path | None, scenario: set[str]) -> Non query_emissions = """ SELECT region, tech, sector, period, emis_comm, SUM(emission) as emissions - FROM OutputEmission WHERE scenario = ? + FROM output_emission WHERE scenario = ? GROUP BY region, tech, sector, period, emis_comm """ df_emissions_raw = pd.read_sql_query(query_emissions, con, params=(scenario_name,)) @@ -164,7 +164,7 @@ def make_excel(ifile: str | None, ofile: Path | None, scenario: set[str]) -> Non query_costs = """ SELECT region, oc.tech, t.sector, vintage, d_invest + d_var + d_fixed + d_emiss as cost - FROM OutputCost oc + FROM output_cost oc JOIN Technology t ON oc.tech = t.tech WHERE scenario = ? """ diff --git a/temoa/data_processing/make_output_plots.py b/temoa/data_processing/make_output_plots.py index 7c1116d8d..706da847c 100644 --- a/temoa/data_processing/make_output_plots.py +++ b/temoa/data_processing/make_output_plots.py @@ -60,20 +60,20 @@ def extract_from_database(self, mode: int) -> None: cur = con.cursor() if mode == 1: cur.execute( - f'SELECT sector, period, tech, capacity FROM OutputNetCapacity ' + f'SELECT sector, period, tech, capacity FROM output_net_capacity ' f"WHERE scenario == '{self.scenario}' AND region LIKE '{self.region}'" ) self.capacity_output = [list(elem) for elem in cur.fetchall()] elif mode == 2: cur.execute( - f'SELECT sector, period, tech, SUM(flow) FROM OutputFlowOut ' + f'SELECT sector, period, tech, SUM(flow) FROM output_flow_out ' f"WHERE scenario == '{self.scenario}' AND region LIKE '{self.region}' " f'GROUP BY sector, period, tech' ) self.output_vflow = [list(elem) for elem in cur.fetchall()] elif mode == 3: cur.execute( - f'SELECT sector, period, emis_comm, SUM(emission) FROM OutputEmission ' + f'SELECT sector, period, emis_comm, SUM(emission) FROM output_emission ' f"WHERE scenario == '{self.scenario}' AND region LIKE '{self.region}' " f'GROUP BY sector, period, emis_comm' ) diff --git a/temoa/extensions/get_comm_tech.py b/temoa/extensions/get_comm_tech.py index bc059d81c..96522c972 100644 --- a/temoa/extensions/get_comm_tech.py +++ b/temoa/extensions/get_comm_tech.py @@ -23,12 +23,12 @@ def get_tperiods(inp_f): con.text_factory = str # this ensures data is explored with the correct UTF-8 encoding print(inp_f) - cur.execute('SELECT DISTINCT scenario FROM OutputFlowOut') + cur.execute('SELECT DISTINCT scenario FROM output_flow_outut') x = [] for row in cur: x.append(row[0]) for y in x: - cur.execute("SELECT DISTINCT period FROM OutputFlowOut WHERE scenario is '" + str(y) + "'") + cur.execute("SELECT DISTINCT period FROM output_flow_outut WHERE scenario is '" + str(y) + "'") periods_list[y] = [] for per in cur: z = per[0] @@ -56,7 +56,7 @@ def get_scenario(inp_f): con.text_factory = str # this ensures data is explored with the correct UTF-8 encoding print(inp_f) - cur.execute('SELECT DISTINCT scenario FROM OutputFlowOut') + cur.execute('SELECT DISTINCT scenario FROM output_flow_outut') for row in cur: x = row[0] scene_list[x] = x @@ -87,7 +87,7 @@ def get_comm(inp_f, db_dat): if not is_query_empty: cur.execute( - 'SELECT input_comm FROM OutputFlowOut UNION SELECT output_comm FROM OutputFlowOut' + 'SELECT input_comm FROM output_flow_outut UNION SELECT output_comm FROoutput_flow_out_out' ) for row in cur: @@ -150,7 +150,7 @@ def get_tech(inp_f, db_dat): tech_list[x] = x if not is_query_empty: - cur.execute('SELECT DISTINCT tech FROM OutputFlowOut') + cur.execute('SELECT DISTINCT tech FROM output_flow_outut') for row in cur: x = row[0] diff --git a/temoa/extensions/method_of_morris/MM_README.md b/temoa/extensions/method_of_morris/MM_README.md index 8152e43a8..c539352d4 100644 --- a/temoa/extensions/method_of_morris/MM_README.md +++ b/temoa/extensions/method_of_morris/MM_README.md @@ -21,7 +21,7 @@ which also refers to relevant studies. - It should be noted that co2 is _not_ optimized in any way, it is just the co2 emission for the optimal cost solution - Further, the code is currently hard-coded to look for _exactly_ the string `co2` in the - `OutputEmissions` table. It is highly advisable to do a "regular" run on the data to ensure + `output_emissions` table. It is highly advisable to do a "regular" run on the data to ensure that `co2` is properly represented in the commodity and output tables. - The basic sequence is: marking of input parameters (by user) and domains (through the `perturbation` @@ -42,7 +42,7 @@ relevant `config.toml` file which can then be run. 3. Observe the `morris` configuration comments in the corresponding `morris_utopia.toml` file in `my_configs`. 4. Run the config as normal. 5. MM analysis is reported on screen and in 2 csv files for the objective and `co2` in the Outputs folder -6. The DB will contain updated values (tagged by scenario name and "dash run") in `OutputObjective` and `OutputEmissions` +6. The DB will contain updated values (tagged by scenario name and "dash run") in `output_objective` and `output_emissions` _only_ which might be of secondary value to the modeler. Other output tables are _not_ updated. ### Preparing Other Databases (or modifying `morris_utopia`) diff --git a/temoa/extensions/method_of_morris/morris.py b/temoa/extensions/method_of_morris/morris.py index 52de436bd..0351a3189 100644 --- a/temoa/extensions/method_of_morris/morris.py +++ b/temoa/extensions/method_of_morris/morris.py @@ -48,11 +48,11 @@ def evaluate(param_names, param_values, data: dict, k): con = sqlite3.connect(db_file) cur = con.cursor() - cur.execute('SELECT * FROM OutputObjective') + cur.execute('SELECT * FROM output_objective') output_query = cur.fetchall() for row in output_query: Y_OF = row[-1] - cur.execute("SELECT emis_comm, SUM(emission) FROM OutputEmission WHERE emis_comm='co2'") + cur.execute("SELECT emis_comm, SUM(emission) FROM output_emissionn WHERE emis_comm='co2'") output_query = cur.fetchall() for row in output_query: Y_CumulativeCO2 = row[-1] diff --git a/temoa/extensions/method_of_morris/morris_evaluate.py b/temoa/extensions/method_of_morris/morris_evaluate.py index 03a4f2cca..0753b62e0 100644 --- a/temoa/extensions/method_of_morris/morris_evaluate.py +++ b/temoa/extensions/method_of_morris/morris_evaluate.py @@ -104,7 +104,7 @@ def evaluate(param_info, mm_sample, data, i, config: TemoaConfig, log_queue, log cur = con.cursor() scenario_name = config.scenario + f'-{i}' cur.execute( - 'SELECT total_system_cost FROM OutputObjective where scenario = ?', (scenario_name,) + 'SELECT total_system_cost FROM output_objective where scenario = ?', (scenario_name,) ) output_query = cur.fetchall() if len(output_query) > 1: @@ -114,7 +114,7 @@ def evaluate(param_info, mm_sample, data, i, config: TemoaConfig, log_queue, log else: Y_OF = output_query[0][0] cur.execute( - "SELECT SUM(emission) FROM OutputEmission WHERE emis_comm='co2' AND scenario=?", + "SELECT SUM(emission) FROM output_emission WHERE emis_comm='co2' AND scenario=?", (scenario_name,), ) output_query = cur.fetchall() @@ -122,7 +122,7 @@ def evaluate(param_info, mm_sample, data, i, config: TemoaConfig, log_queue, log Y_CumulativeCO2 = 0.0 elif len(output_query) > 1: raise RuntimeError( - 'Multiple outputs found in OutputEmissions table matching scenario name. Coding error.' + 'Multiple outputs found in output_emissions table matching scenario name. Coding error.' ) else: Y_CumulativeCO2 = output_query[0][0] diff --git a/temoa/extensions/modeling_to_generate_alternatives/MGA Design.md b/temoa/extensions/modeling_to_generate_alternatives/MGA Design.md index 07251c2c9..1acfb3b3f 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/MGA Design.md +++ b/temoa/extensions/modeling_to_generate_alternatives/MGA Design.md @@ -1,29 +1,35 @@ # MGA Design ## Terms -### MGA Axis: -- The general description of the inputs to diversify. Default now is TECH CATEGORY ACTIVITY + +### MGA Axis + +- The general description of the inputs to diversify. Default now is TECH CATEGORY ACTIVITY implying that we will try to diversify activity of each labeled tech category in `Technology` table. - **DIMENSION**: number of categories. This defines the dimensionality of the convex hull - Notions for possible Axis: - Techs: All(?) techs - Sectors: Does this make sense? - Category/Subcategory: The Fundamental idea - - A selection of `TechGroup` from data + - A selection of `tech_group` from data - Emissions: Different types - Resilience: Some combo of storage & capacity factor & such -### `Axis Vector` + +### `Axis Vector` + - Directional unit vector within the axis space - **DIMENSION** = dimensionality of the MGA Axis - This is a possible exploration direction within the MGA Axis space - `Hull Norm`: An `Axis Vector` that is normal to a facet on the convex hull - Hull Norms are generated by the convex hull routine - Must be checked for redundancy (other nearly collinear instances), especially when re-creating the hull from points + ### `Model Vector` + - A vector of coefficients or model variables or both that represent the basis of the objective function - **DIMENSION**: The total number of variables chosen within the `Vector Manager` to capture output. This is `sample dimension`. - Generated by the `Vector Manager` -- `Variable Vector`: A `Model Vector` of model variables (only) selected for analysis. +- `Variable Vector`: A `Model Vector` of model variables (only) selected for analysis. - `Coefficient Vector`: A vector of scalar multipliers of the same length as the `Variable Vector`. - `Input Vector` - A `pyomo` expression of coefficients * variables from the above. @@ -31,7 +37,8 @@ implying that we will try to diversify activity of each labeled tech category in - `Output Vector` - A vector of variables (containing solution values) from an optimization run -#### Example: +#### Example + MGA Axis of "activity" with 2 categories: {`solar`,`wind`} An `Axis Vector` might be [0.75, 0.25] @@ -43,10 +50,12 @@ A `Coefficient Vector` might be: `[0.75/2, 0.75/2, 0.25/2, 0.25/2]` An `Input Vector` would be the sum of the dot product of variables and coefficients ### Point + - The outcome of an optimization represented in Axis space - Can be used to define points on the Convex Hull (if used) ### Weighting Scheme + - The logic that determines new `axis vectors` for exploration - To be implemented by the `Vector Manager` - Options: @@ -58,19 +67,19 @@ An `Input Vector` would be the sum of the dot product of variables and coefficie built and normal vectors are employed going forward. - Random (?)?: Random unit vectors in either the `Axis Vector` dimension or `Model Vector` dimension -## Implementation: +## Implementation + - User should specify an `Axis` in the config. This will enable the selection of a `Vector Manager` - User should specify a `Weighting Scheme` in the config that is appropriate for the `Axis` chosen. This setup is only sparsely built now, but allows a framework for follow-on development - User should verify the solver config data in the `solver_options.toml` file in the MGA pkg folder in the `extensions` package. -- User should ensure that the `Axis` is supported in the appropriate data table. - - For example, if using the default, we should mark/check categories in `Technology`. - - Techs that have no category will be processed but not be part of the `Objective` function. +- User should ensure that the `Axis` is supported in the appropriate data table. + - For example, if using the default, we should mark/check categories in `Technology`. + - Techs that have no category will be processed but not be part of the `Objective` function. - If using the cvx hull algorithm, realize that `2 x |Categories|` solves are necessary to establish a hull - -## Objectives & Ideas Notes: +## Objectives & Ideas Notes - Look at near-optimal solutions that are diverse - What are metrics? @@ -78,10 +87,11 @@ package. number of runs - Flow out? Cost? Emissions? - Almost certainly capacity built. **Capacity Built is implemented** and enumerated by dash-run -number in the `OutputBuiltCapacity` table. +number in the `output_built_capacity` table. - What are reasonable aggregation schemes to capture summary values? -## What kind of diversity: +## What kind of diversity + - How are outcomes diverse from each other? - Capacity of individual techs? (likely too granular) - Capacity of groups of techs @@ -108,7 +118,7 @@ number in the `OutputBuiltCapacity` table. - How much more in one direction? ## Outputs + - Perhaps save the "weighting" index to a table for each run to make individual points reproducible to get full output? - What do MGA output summary results look like...? - diff --git a/temoa/extensions/modeling_to_generate_alternatives/README.md b/temoa/extensions/modeling_to_generate_alternatives/README.md index bdf0a73ed..39f7a8634 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/README.md +++ b/temoa/extensions/modeling_to_generate_alternatives/README.md @@ -1,32 +1,32 @@ ### Using MGA It is likely helpful to read the `MGA Design.md` file in this directory that describes some of the terms/ -analytic approach to MGA. MGA uses multi-processing to iteratively explore near-optimal solutions. +analytic approach to MGA. MGA uses multi-processing to iteratively explore near-optimal solutions. #### Outputs - The processing of results is left to the modeler and the results from runs are tagged iteratively in the Output tables in the database. -- Running MGA analysis also adds an additional `OutputFlowOutSummary` table which +- Running MGA analysis also adds an additional `output_flow_outSummary` table which summarizes flows at the period level (summarizing time of day and season) to manage the size of the output for larger models #### Setup - The Config file options - - cost_epsilon: The proportion to relax the minimal cost by to enable exploration - - iteration_limit: The max iterations to run. Note: Currently the process will run until either the + - cost_epsilon: The proportion to relax the minimal cost by to enable exploration + - iteration_limit: The max iterations to run. Note: Currently the process will run until either the iteration limit OR time limit is reached. If using hull expansion as the weighting scheme (default), realize that "the magic" of that doesn't start until the hull is built which takes 2x |categories| solves to produce. - - time_limit_hrs: Self explanatory. A backstop for long runs - - axis: The type of manager to use. Only `tech_category_activity` is currently implemented - - weighting: The type of weighting to use by the manager + - time_limit_hrs: Self explanatory. A backstop for long runs + - axis: The type of manager to use. Only `tech_category_activity` is currently implemented + - weighting: The type of weighting to use by the manager - The `MGA_solver_options.toml` file - Contains solver settings to optimize performance. These settings are used *after* the first solve, which sets the optimized cost. The "worker" solvers consume and use any options for the chosen solver from this file - - Contains the number of workers setting. Some balance must be considered between hardware resources and + - Contains the number of workers setting. Some balance must be considered between hardware resources and concurrency. Six (the current setting) seems an OK balance... - Large models consume fairly large memory footprint. It is possible to have `num_workers` + 2 models floating around either in solve, or waiting. - The number of workers should be balanced with number of cores per solve (if solver accepts that). For example, - with 6 workers and 20 threads/solve, this is a nice fit on 132 core servers, with a bit of slop. \ No newline at end of file + with 6 workers and 20 threads/solve, this is a nice fit on 132 core servers, with a bit of slop. diff --git a/temoa/extensions/monte_carlo/example_builds/scenario_analyzer.py b/temoa/extensions/monte_carlo/example_builds/scenario_analyzer.py index e1d51d3e2..9d6ba05f9 100644 --- a/temoa/extensions/monte_carlo/example_builds/scenario_analyzer.py +++ b/temoa/extensions/monte_carlo/example_builds/scenario_analyzer.py @@ -40,7 +40,7 @@ with Connection(db_path) as conn: cur = conn.cursor() obj_values = cur.execute( - f"SELECT total_system_cost FROM OutputObjective WHERE scenario LIKE '{scenario_name}-%'" + f"SELECT total_system_cost FROM output_objective WHERE scenario LIKE '{scenario_name}-%'" ).fetchall() obj_values = tuple(t[0] for t in obj_values) diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index bb1f8985d..932a278da 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -35,17 +35,17 @@ class MyopicSequencer: # Tables that are cleaned of (scenario) data before run tables_with_scenario_reference = [ - 'OutputBuiltCapacity', - 'OutputCost', - 'OutputCurtailment', - 'OutputDualVariable', - 'OutputEmission', - 'OutputFlowIn', - 'OutputFlowOut', - 'OutputNetCapacity', - 'OutputObjective', - 'OutputRetiredCapacity', - 'OutputStorageLevel', + 'output_built_capacity', + 'output_cost', + 'output_curtailment', + 'output_dual_variable', + 'output_emission', + 'output_flow_in', + 'output_flow_out', + 'output_net_capacity', + 'output_objective', + 'output_retired_capacity', + 'output_storage_level', ] tables_without_scenario_reference = [ 'Myopicefficiency', @@ -55,14 +55,14 @@ class MyopicSequencer: # note: below excludes Myopicefficiency, which is managed separately tables_with_period = [ - 'OutputCost', - 'OutputCurtailment', - 'OutputEmission', - 'OutputFlowIn', - 'OutputFlowOut', - 'OutputNetCapacity', - 'OutputRetiredCapacity', - 'OutputStorageLevel', + 'output_cost', + 'output_curtailment', + 'output_emission', + 'output_flow_in', + 'output_flow_out', + 'output_net_capacity', + 'output_retired_capacity', + 'output_storage_level', ] def __init__(self, config: TemoaConfig | None): @@ -256,22 +256,22 @@ def start(self): # prep next loop last_base_year = idx.base_year # update - # delete anything in the OutputObjective table, it is nonsensical... + # delete anything in the output_objective table, it is nonsensical... self.output_con.execute( - f'DELETE FROM OutputObjective WHERE scenario == "{self.config.scenario}"' + f'DELETE FROM output_objective WHERE scenario == "{self.config.scenario}"' ) self.output_con.commit() # 11. Compact the db... lots of writes/deletes leads to bloat self.output_con.execute('VACUUM;') - # Total system cost is, theoretically, sum of discounted costs from OutputCost table + # Total system cost is, theoretically, sum of discounted costs from output_cost table total_cost = self.output_con.execute( - f'SELECT SUM(d_invest)+SUM(d_fixed)+SUM(d_var)+SUM(d_emiss) FROM OutputCost WHERE scenario == "{self.config.scenario}"' + f'SELECT SUM(d_invest)+SUM(d_fixed)+SUM(d_var)+SUM(d_emiss) FROM output_cost WHERE scenario == "{self.config.scenario}"' ).fetchone()[0] self.output_con.execute( f"""INSERT INTO - OutputObjective(scenario, objective_name, total_system_cost) + output_objective(scenario, objective_name, total_system_cost) VALUES('{self.config.scenario}', 'total_cost', {total_cost})""" ) self.output_con.commit() @@ -308,8 +308,8 @@ def initialize_myopic_efficiency_table(self): ' LEFT JOIN main.lifetime_tech ' ' ON main.efficiency.tech = main.lifetime_tech.tech ' ' AND main.efficiency.region = main.lifetime_tech.region ' - ' JOIN TimePeriod ' - ' ON efficiency.vintage = TimePeriod.period ' + ' JOIN time_period ' + ' ON efficiency.vintage = time_period.period ' " WHERE flag = 'e'" ) @@ -322,8 +322,8 @@ def initialize_myopic_efficiency_table(self): q2 = ( "SELECT '-1', region, input_comm, tech, vintage, output_comm, efficiency " 'FROM efficiency ' - ' JOIN TimePeriod ' - ' ON efficiency.vintage = TimePeriod.period ' + ' JOIN time_period ' + ' ON efficiency.vintage = time_period.period ' " WHERE flag = 'e'" ) res = self.cursor.execute(q2).fetchall() @@ -368,15 +368,15 @@ def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: i # 1. Clean up stuff not implemented or retired by the last time period in previous step, # exempting unlim_cap techs (of course...who would forget that?) last_interval_end, flag = self.cursor.execute( - 'SELECT MAX(period), flag FROM main.TimePeriod WHERE period < ?', + 'SELECT MAX(period), flag FROM main.time_period WHERE period < ?', (myopic_index.base_year,), ).fetchone() - if flag == 'f': # the prior period should have an OutputNetCapacity entry + if flag == 'f': # the prior period should have an output_net_capacity entry # Delete anything that doesn't have capacity remaining at the end of last interval delete_qry = ( 'DELETE FROM Myopicefficiency ' 'WHERE (SELECT region, tech, vintage) ' - ' NOT IN (SELECT region, tech, vintage FROM OutputNetCapacity ' + ' NOT IN (SELECT region, tech, vintage FROM output_net_capacity ' ' WHERE period = ? AND scenario = ?) ' 'AND tech not in (SELECT tech FROM Technology where unlim_cap > 0)' ) @@ -385,7 +385,7 @@ def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: i debug_query = ( 'SELECT * FROM Myopicefficiency ' 'WHERE (SELECT region, tech, vintage) ' - ' NOT IN (SELECT region, tech, vintage FROM OutputNetCapacity ' + ' NOT IN (SELECT region, tech, vintage FROM output_net_capacity ' ' WHERE period = ? AND scenario = ?) ' 'AND tech not in (SELECT tech FROM Technology where unlim_cap > 0)' ) @@ -442,7 +442,7 @@ def characterize_run(self, future_periods: list[int] | None = None) -> None: """ if not future_periods: future_periods = self.cursor.execute( - "SELECT period FROM main.TimePeriod WHERE flag = 'f'" + "SELECT period FROM main.time_period WHERE flag = 'f'" ).fetchall() future_periods = sorted(t[0] for t in future_periods) @@ -541,7 +541,7 @@ def clear_results_after(self, period): # special case... new capacity has vintage only... self.cursor.execute( - 'DELETE FROM main.OutputBuiltCapacity WHERE main.OutputBuiltCapacity.vintage >= (?) AND scenario = (?)', + 'DELETE FROM main.output_built_capacity WHERE main.output_built_capacity.vintage >= (?) AND scenario = (?)', (period, self.config.scenario), ) self.output_con.commit() diff --git a/temoa/extensions/single_vector_mga/output_summary.py b/temoa/extensions/single_vector_mga/output_summary.py index ef54e9172..8ecb2fb8e 100644 --- a/temoa/extensions/single_vector_mga/output_summary.py +++ b/temoa/extensions/single_vector_mga/output_summary.py @@ -85,7 +85,7 @@ def poll_emission(conn: Connection, scenario: str, label: str) -> float: poll the output database of selected iteration for the given emission label total """ raw = conn.execute( - 'SELECT sum(emission) FROM main.OutputEmission WHERE scenario=? AND emis_comm=?', + 'SELECT sum(emission) FROM main.output_emissionn WHERE scenario=? AND emis_comm=?', (scenario, label), ).fetchone()[0] return raw @@ -96,7 +96,7 @@ def poll_activity(conn: Connection, scenario: str, label: str) -> float: poll the Flow Out activity for the given emission label total """ raw = conn.execute( - 'SELECT sum(flow) FROM main.OutputFlowOut WHERE scenario=? AND tech=?', + 'SELECT sum(flow) FROM main.output_flow_out WHERE scenario=? AND tech=?', (scenario, label), ).fetchone()[0] return raw @@ -107,7 +107,7 @@ def poll_capacity(conn: Connection, scenario: str, label: str) -> float: poll the built capacity for the given emission label total """ raw = conn.execute( - 'SELECT sum(capacity) FROM main.OutputBuiltCapacity WHERE scenario=? AND tech=?', + 'SELECT sum(capacity) FROM main.output_built_capacityty WHERE scenario=? AND tech=?', (scenario, label), ).fetchone()[0] return raw diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index e31218229..1c79db095 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -160,7 +160,7 @@ def _build_from_model( ) -> NetworkModelData: """Build a NetworkModelData from a TemoaModel.""" if myopic_index is not None: - raise NotImplementedError('Cannot build network data from model using a MyopicIndex') + raise NotImplementedError('Cannot build network data from model using a myopic_index') dem_com = defaultdict(set) for r, p, d in model.demand.sparse_iterkeys(): @@ -192,16 +192,16 @@ def _build_from_model( def _fetch_basic_data(cur: sqlite3.Cursor) -> BasicData: """Fetches simple, required tables and parameters from the DB.""" tech_retire = { - t[0] for t in cur.execute('SELECT tech FROM Technology WHERE retire==1').fetchall() + t[0] for t in cur.execute('SELECT tech FROM technology WHERE retire==1').fetchall() } try: tech_survival_curve = set( - cur.execute('SELECT DISTINCT region, tech, vintage FROM SurvivalCurve').fetchall() + cur.execute('SELECT DISTINCT region, tech, vintage FROM survival_curve').fetchall() ) except sqlite3.OperationalError: tech_survival_curve = set() - periods_full = sorted(p[0] for p in cur.execute('SELECT period FROM TimePeriod').fetchall()) + periods_full = sorted(p[0] for p in cur.execute('SELECT period FROM time_period').fetchall()) periods = periods_full[:-1] period_length = { periods_full[i]: periods_full[i + 1] - periods_full[i] for i in range(len(periods_full) - 1) @@ -210,18 +210,18 @@ def _fetch_basic_data(cur: sqlite3.Cursor) -> BasicData: physical_commodities = { c[0] for c in cur.execute( - "SELECT name FROM main.Commodity WHERE flag LIKE '%p%' OR flag = 's' OR flag LIKE '%a%'" + "SELECT name FROM main.commodity WHERE flag LIKE '%p%' OR flag = 's' OR flag LIKE '%a%'" ).fetchall() } waste_commodities_all = { - c[0] for c in cur.execute("SELECT name FROM Commodity WHERE flag LIKE '%w%'").fetchall() + c[0] for c in cur.execute("SELECT name FROM commodity WHERE flag LIKE '%w%'").fetchall() } source_commodities_all = { - c[0] for c in cur.execute("SELECT name FROM Commodity WHERE flag = 's'").fetchall() + c[0] for c in cur.execute("SELECT name FROM commodity WHERE flag = 's'").fetchall() } demand_commodities: defaultdict[tuple[Region, Period], set[Commodity]] = defaultdict(set) - for r, p, d in cur.execute('SELECT region, period, commodity FROM main.Demand').fetchall(): + for r, p, d in cur.execute('SELECT region, period, commodity FROM main.demand').fetchall(): demand_commodities[r, p].add(d) return BasicData( @@ -244,11 +244,11 @@ def _fetch_all_tech_definitions( ]: """Fetches the main block of technology efficiency and lifetime data.""" default_lifetime = TemoaModel.default_lifetime_tech - table = 'Myopicefficiency' if myopic_index else 'efficiency' + table = 'myopic_efficiency' if myopic_index else 'efficiency' # Check if Technology table has sector column try: - cur.execute('SELECT sector FROM Technology LIMIT 1') + cur.execute('SELECT sector FROM technology LIMIT 1') has_sector = True except sqlite3.OperationalError: has_sector = False @@ -265,8 +265,8 @@ def _fetch_all_tech_definitions( FROM main.{table} AS eff LEFT JOIN main.lifetime_process AS lp ON eff.tech = lp.tech AND eff.vintage = lp.vintage AND eff.region = lp.region LEFT JOIN main.lifetime_tech AS lt ON eff.tech = lt.tech AND eff.region = lt.region - LEFT JOIN main.Technology AS tech_dim ON eff.tech = tech_dim.tech - JOIN main.TimePeriod AS tp ON eff.vintage = tp.period + LEFT JOIN main.technology AS tech_dim ON eff.tech = tech_dim.tech + JOIN main.time_period AS tp ON eff.vintage = tp.period """ else: query = f""" @@ -276,7 +276,7 @@ def _fetch_all_tech_definitions( FROM main.{table} AS eff LEFT JOIN main.lifetime_process AS lp ON eff.tech = lp.tech AND eff.vintage = lp.vintage AND eff.region = lp.region LEFT JOIN main.lifetime_tech AS lt ON eff.tech = lt.tech AND eff.region = lt.region - JOIN main.TimePeriod AS tp ON eff.vintage = tp.period + JOIN main.time_period AS tp ON eff.vintage = tp.period """ cursor = cur.execute(query, (default_lifetime,)) return cursor.fetchall() @@ -304,11 +304,11 @@ def _fetch_lookup_data(cur: sqlite3.Cursor) -> LookupData: try: lookups['linked'] = set( cur.execute( - 'SELECT primary_region, primary_tech, emis_comm, driven_tech FROM main.LinkedTech' + 'SELECT primary_region, primary_tech, emis_comm, driven_tech FROM main.linked_tech' ).fetchall() ) except sqlite3.OperationalError: - logger.warning('Table LinkedTech not found, skipping.') + logger.warning('Table linked_tech not found, skipping.') try: lookups['neg_cost_techs'] = { @@ -431,11 +431,11 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - EdgeTuple( region=r, input_comm=cast(Commodity, tech), - tech=cast(Technology, 'EndOfLife'), + tech=cast(Technology, 'end_of_life'), vintage=v, output_comm=eol_oc, lifetime=lifetime, - sector=cast(Sector, 'Other'), + sector=cast(Sector, 'other'), ) ) res.source_commodities[r, p].add(cast(Commodity, tech)) @@ -450,13 +450,13 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - EdgeTuple( region=r, input_comm=ic, - tech=cast(Technology, 'Construction'), + tech=cast(Technology, 'construction'), vintage=v, output_comm=cast( Commodity, tech ), # commodity is kind of input to the capacity of the technology/vice versa lifetime=construction_lifetime, - sector=cast(Sector, 'Other'), + sector=cast(Sector, 'other'), ) ) res.demand_commodities[r, cast(Period, v)].add(cast(Commodity, tech)) diff --git a/temoa/utilities/clear_db_outputs.py b/temoa/utilities/clear_db_outputs.py index bc41dcf98..f04158aaf 100644 --- a/temoa/utilities/clear_db_outputs.py +++ b/temoa/utilities/clear_db_outputs.py @@ -8,18 +8,18 @@ from pathlib import Path basic_output_tables = [ - 'OutputBuiltCapacity', - 'OutputCost', - 'OutputCurtailment', - 'OutputDualVariable', - 'OutputEmission', - 'OutputFlowIn', - 'OutputFlowOut', - 'OutputNetCapacity', - 'OutputObjective', - 'OutputRetiredCapacity', + 'output_built_capacity', + 'output_cost', + 'output_curtailment', + 'output_dual_variable', + 'output_emissionn', + 'output_flow_in', + 'output_flow_out', + 'output_net_capacity', + 'output_objective', + 'output_retired_capacity', ] -optional_output_tables = ['OutputFlowOutSummary', 'MyopicEfficiency'] +optional_output_tables = ['output_flow_outSummary', 'MyopicEfficiency'] if len(sys.argv) != 2: print('this utility file expects a CLA for the path to the database to clear') diff --git a/temoa/utilities/db_migration_to_v3.py b/temoa/utilities/db_migration_to_v3.py index e1af36e37..ac0c763b0 100644 --- a/temoa/utilities/db_migration_to_v3.py +++ b/temoa/utilities/db_migration_to_v3.py @@ -101,7 +101,7 @@ ('', 'TechInputSplitAverage'), ('', 'TechOutputSplit'), ('technology_labels', 'TechnologyType'), - ('time_period_labels', 'TimePeriodType'), + ('time_period_labels', 'time_periodType'), ('SegFrac', 'TimeSegmentFraction'), ] @@ -114,7 +114,7 @@ sequence_added_tables = [ ('time_season', 'TimeSeason'), - ('time_periods', 'TimePeriod'), + ('time_periods', 'time_period'), ('time_of_day', 'TimeOfDay'), ] # fmt: on diff --git a/tests/test_emission_results.py b/tests/test_emission_results.py index dd742c6dd..58f73fa31 100644 --- a/tests/test_emission_results.py +++ b/tests/test_emission_results.py @@ -72,7 +72,7 @@ def test_emissions(solved_connection): emis = ( con.cursor() .execute( - f"SELECT SUM(emission) FROM main.OutputEmission WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied' AND period == 2000" + f"SELECT SUM(emission) FROM main.output_emissionn WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied' AND period == 2000" ) .fetchone()[0] ) @@ -96,7 +96,7 @@ def test_emissions_costs_undiscounted(solved_connection): ec = ( con.cursor() .execute( - f"SELECT SUM(emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied' AND period == 2000" + f"SELECT SUM(emiss) FROM main.output_cost WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied' AND period == 2000" ) .fetchone()[0] ) @@ -121,7 +121,7 @@ def test_emissions_costs_discounted(solved_connection): ec = ( con.cursor() .execute( - f"SELECT SUM(d_emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied' AND period == 2000" + f"SELECT SUM(d_emiss) FROM main.output_cost WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied' AND period == 2000" ) .fetchone()[0] ) @@ -146,7 +146,7 @@ def test_embodied_emissions(solved_connection): emis = ( con.cursor() .execute( - f"SELECT SUM(emission) FROM main.OutputEmission WHERE tech LIKE '{tech}' AND period == 2000" + f"SELECT SUM(emission) FROM main.output_emissionn WHERE tech LIKE '{tech}' AND period == 2000" ) .fetchone()[0] ) @@ -170,7 +170,7 @@ def test_embodied_emissions_costs_undiscounted(solved_connection): ec = ( con.cursor() .execute( - f"SELECT SUM(emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND period == 2000" + f"SELECT SUM(emiss) FROM main.output_cost WHERE tech LIKE '{tech}' AND period == 2000" ) .fetchone()[0] ) @@ -195,7 +195,7 @@ def test_embodied_emissions_costs_discounted(solved_connection): ec = ( con.cursor() .execute( - f"SELECT SUM(d_emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND period == 2000" + f"SELECT SUM(d_emiss) FROM main.output_cost WHERE tech LIKE '{tech}' AND period == 2000" ) .fetchone()[0] ) @@ -222,7 +222,7 @@ def test_endoflife_emissions(solved_connection): emis = ( con.cursor() .execute( - f"SELECT SUM(emission) FROM main.OutputEmission WHERE tech LIKE '{tech}' AND period == 2005" + f"SELECT SUM(emission) FROM main.output_emissionn WHERE tech LIKE '{tech}' AND period == 2005" ) .fetchone()[0] ) @@ -246,7 +246,7 @@ def test_endoflife_emissions_costs_undiscounted(solved_connection): ec = ( con.cursor() .execute( - f"SELECT SUM(emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND period == 2005" + f"SELECT SUM(emiss) FROM main.output_cost WHERE tech LIKE '{tech}' AND period == 2005" ) .fetchone()[0] ) @@ -271,7 +271,7 @@ def test_endoflife_emissions_costs_discounted(solved_connection): ec = ( con.cursor() .execute( - f"SELECT SUM(d_emiss) FROM main.OutputCost WHERE tech LIKE '{tech}' AND period == 2005" + f"SELECT SUM(d_emiss) FROM main.output_cost WHERE tech LIKE '{tech}' AND period == 2005" ) .fetchone()[0] ) @@ -305,7 +305,7 @@ def test_curtailment(solved_connection): curt = ( con.cursor() .execute( - f"SELECT SUM(curtailment) FROM main.OutputCurtailment WHERE tech LIKE '{tech}' AND period == 2000" + f"SELECT SUM(curtailment) FROM main.output_curtailment WHERE tech LIKE '{tech}' AND period == 2000" ) .fetchone()[0] ) diff --git a/tests/test_full_runs.py b/tests/test_full_runs.py index f31ef6958..60f5ecd34 100644 --- a/tests/test_full_runs.py +++ b/tests/test_full_runs.py @@ -110,7 +110,7 @@ def test_myopic_utopia(system_test_run): _, _, _, sequencer = system_test_run con = sqlite3.connect(sequencer.config.output_database) cur = con.cursor() - res = cur.execute('SELECT SUM(d_invest) FROM main.OutputCost').fetchone() + res = cur.execute('SELECT SUM(d_invest) FROM main.output_cost').fetchone() invest_sum = res[0] # reduced this target after storageinit rework # reduced after removing ancient 1-year shift bug from objective function diff --git a/tests/test_linked_tech.py b/tests/test_linked_tech.py index d50d6b4bf..e56af98ea 100644 --- a/tests/test_linked_tech.py +++ b/tests/test_linked_tech.py @@ -28,6 +28,7 @@ simple_linked_tech_description.jpg """ + import logging import sqlite3 from pathlib import Path @@ -56,17 +57,17 @@ def test_linked_tech(system_test_run): print(output_db_path) conn = sqlite3.connect(str(output_db_path)) co2_emiss = conn.execute( - "SELECT emission FROM OutputEmission WHERE emis_comm = 'CO2'" + "SELECT emission FROM output_emissionn WHERE emis_comm = 'CO2'" ).fetchall() assert len(co2_emiss) == 1 co2_emiss = co2_emiss[0][0] # check the total emission - assert co2_emiss == pytest.approx( - -30.0 - ), 'the linked processes should remove have an aggregate -30 units of co2 emissions' + assert co2_emiss == pytest.approx(-30.0), ( + 'the linked processes should remove have an aggregate -30 units of co2 emissions' + ) # check the flow out of captured carbon from the driven tech, which should output the captured carbon flow_out = conn.execute( - "SELECT SUM(flow) FROM OutputFlowOut WHERE tech = 'CCS' and output_comm = 'CO2_CAP'" + "SELECT SUM(flow) FROM output_flow_out WHERE tech = 'CCS' and output_comm = 'CO2_CAP'" ).fetchone()[0] assert flow_out == pytest.approx(30.0) diff --git a/tests/test_material_results.py b/tests/test_material_results.py index e16454b2f..1c00e8cf1 100644 --- a/tests/test_material_results.py +++ b/tests/test_material_results.py @@ -60,7 +60,7 @@ def test_flows(solved_connection): con, name, tech, period, flow_target = solved_connection cursor = con.cursor() row = cursor.execute( - 'SELECT SUM(flow) FROM main.OutputFlowOut WHERE tech = ? AND period = ?', + 'SELECT SUM(flow) FROM main.output_flow_out WHERE tech = ? AND period = ?', (tech, period), ).fetchone() # If the query returns no rows, row will be None. If it finds rows but the sum is NULL, row[0] will be None. diff --git a/tests/test_network_model_data.py b/tests/test_network_model_data.py index 9131bd91c..3af1ead4b 100644 --- a/tests/test_network_model_data.py +++ b/tests/test_network_model_data.py @@ -21,7 +21,7 @@ 'db_data': { 'Technology WHERE retire==1': [], 'FROM SurvivalCurve': [], - 'FROM TimePeriod': [(2020,), (2025,)], + 'FROM time_period': [(2020,), (2025,)], # Unique keys for each Commodity query 'FROM main.Commodity': [('s1',), ('p1',), ('p2',), ('p3',), ('d1',), ('d2',)], "Commodity WHERE flag LIKE '%p%'": [ @@ -72,7 +72,7 @@ 'db_data': { 'Technology WHERE retire==1': [], 'FROM SurvivalCurve': [], - 'FROM TimePeriod': [(2020,), (2025,)], + 'FROM time_period': [(2020,), (2025,)], 'FROM main.Commodity': [('s1',), ('p1',), ('p3',), ('d1',), ('d2',)], "Commodity WHERE flag LIKE '%p%'": [('s1',), ('p3',), ('d1',), ('d2',)], "Commodity WHERE flag LIKE '%w%'": [], @@ -109,7 +109,7 @@ 'db_data': { 'Technology WHERE retire==1': [], 'FROM SurvivalCurve': [], - 'FROM TimePeriod': [(2020,), (2025,)], + 'FROM time_period': [(2020,), (2025,)], 'FROM main.Commodity': [('s1',), ('p1',), ('d1',), ('d2',), ('s2',)], "Commodity WHERE flag LIKE '%p%'": [('s1',), ('d1',), ('d2',), ('s2',)], "Commodity WHERE flag LIKE '%w%'": [], @@ -263,7 +263,7 @@ def dispatcher(query: str, *_: object) -> MagicMock: m = MagicMock() m.fetchall.return_value = [] return m - elif 'FROM TimePeriod' in query: + elif 'FROM time_period' in query: m = MagicMock() m.fetchall.return_value = [(2020,), (2025,)] return m @@ -347,7 +347,7 @@ def dispatcher(query: str, *_: object) -> MagicMock: m = MagicMock() m.fetchall.return_value = [] return m - elif 'FROM TimePeriod' in query: + elif 'FROM time_period' in query: m = MagicMock() m.fetchall.return_value = [(2020,), (2025,)] return m From 344da74c630ab63e001b76dc3d81ea9127601923 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 7 Nov 2025 18:42:51 -0500 Subject: [PATCH 315/587] adding migrators for sql and sqlite files, changing db version to 4.0, fixing inconsistencies --- data_files/example_dbs/utopia.sql | 2096 +++++++++-------- data_files/my_configs/config_sample.toml | 7 +- temoa/types/model_types.py | 78 +- temoa/utilities/db_migration_v3_1_to_v4.py | 206 ++ temoa/utilities/sql_migration_v3_1_to_v4.py | 294 +++ temoa/version_information.py | 2 +- tests/test_network_model_data.py | 72 +- .../config_annualised_demand.toml | 2 +- tests/testing_configs/config_emissions.toml | 2 +- tests/testing_configs/config_link_test.toml | 4 +- tests/testing_configs/config_materials.toml | 2 +- tests/testing_configs/config_mediumville.toml | 2 +- .../config_seasonal_storage.toml | 2 +- .../testing_configs/config_storageville.toml | 2 +- .../config_survival_curve.toml | 2 +- tests/testing_configs/config_test_system.toml | 2 +- tests/testing_configs/config_utopia.toml | 2 +- .../testing_configs/config_utopia_myopic.toml | 2 +- .../US_9R_8D_legacy_set_sizes.json | 12 +- tests/testing_data/US_9R_8D_set_sizes.json | 6 +- tests/testing_data/annualised_demand.sql | 370 +-- tests/testing_data/emissions.sql | 498 ++-- tests/testing_data/materials.sql | 1372 +++++------ tests/testing_data/mediumville.sql | 438 ++-- tests/testing_data/seasonal_storage.sql | 384 +-- tests/testing_data/simple_linked_tech.sql | 382 +-- tests/testing_data/storageville.sql | 396 ++-- tests/testing_data/survival_curve.sql | 394 ++-- tests/testing_data/test_system.sql | 542 ++--- tests/testing_data/utopia.sql | 512 ++-- 30 files changed, 4301 insertions(+), 3784 deletions(-) create mode 100644 temoa/utilities/db_migration_v3_1_to_v4.py create mode 100644 temoa/utilities/sql_migration_v3_1_to_v4.py diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 6cc795edb..dc4b0f9cd 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -1,64 +1,11 @@ -PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE MetaData -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); -CREATE TABLE MetaDataReal -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); -CREATE TABLE OutputDualVariable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE SeasonLabel -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SeasonLabel VALUES('inter',NULL); -INSERT INTO SeasonLabel VALUES('summer',NULL); -INSERT INTO SeasonLabel VALUES('winter',NULL); -CREATE TABLE SectorLabel -( - sector TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SectorLabel VALUES('supply',NULL); -INSERT INTO SectorLabel VALUES('electric',NULL); -INSERT INTO SectorLabel VALUES('transport',NULL); -INSERT INTO SectorLabel VALUES('commercial',NULL); -INSERT INTO SectorLabel VALUES('residential',NULL); -INSERT INTO SectorLabel VALUES('industrial',NULL); CREATE TABLE capacity_credit ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, credit REAL, notes TEXT, @@ -69,209 +16,209 @@ CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO capacity_factor_process VALUES('utopia',2000,'inter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2000,'inter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2000,'winter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2000,'winter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2000,'summer','day','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2000,'summer','night','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','day','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','night','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','day','E31',2010,0.2756000000000000116,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','night','E31',2010,0.2756000000000000116,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','day','E31',2010,0.2756000000000000116,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','night','E31',2010,0.2756000000000000116,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','day','E31',2010,0.2756000000000000116,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','night','E31',2010,0.2756000000000000116,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'inter','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'inter','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'winter','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'winter','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'summer','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'summer','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','day','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','night','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','day','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','night','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','day','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','night','E31',2010,0.2756,''); CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E70',0.8000000000000000444,''); -CREATE TABLE CapacityToActivity +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E70',0.8,''); +CREATE TABLE capacity_to_activity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), c2a REAL, notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO CapacityToActivity VALUES('utopia','E01',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('utopia','E21',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('utopia','E31',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('utopia','E51',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('utopia','E70',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('utopia','RHE',1.0,''); -INSERT INTO CapacityToActivity VALUES('utopia','RHO',1.0,''); -INSERT INTO CapacityToActivity VALUES('utopia','RL1',1.0,''); -INSERT INTO CapacityToActivity VALUES('utopia','SRE',1.0,''); -INSERT INTO CapacityToActivity VALUES('utopia','TXD',1.0,''); -INSERT INTO CapacityToActivity VALUES('utopia','TXE',1.0,''); -INSERT INTO CapacityToActivity VALUES('utopia','TXG',1.0,''); -CREATE TABLE Commodity +INSERT INTO "capacity_to_activity" VALUES('utopia','E01',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','E21',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','E31',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','E51',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','E70',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','RHE',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','RHO',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','RL1',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','SRE',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','TXD',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','TXE',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','TXG',1.0,''); +CREATE TABLE commodity ( name TEXT PRIMARY KEY, flag TEXT - REFERENCES CommodityType (label), + REFERENCES commodity_type (label), description TEXT ); -INSERT INTO Commodity VALUES('ethos','s','# dummy commodity to supply inputs (makes graph easier to read)'); -INSERT INTO Commodity VALUES('DSL','p','# diesel'); -INSERT INTO Commodity VALUES('ELC','p','# electricity'); -INSERT INTO Commodity VALUES('FEQ','p','# fossil equivalent'); -INSERT INTO Commodity VALUES('GSL','p','# gasoline'); -INSERT INTO Commodity VALUES('HCO','p','# coal'); -INSERT INTO Commodity VALUES('HYD','p','# water'); -INSERT INTO Commodity VALUES('OIL','p','# crude oil'); -INSERT INTO Commodity VALUES('URN','p','# uranium'); -INSERT INTO Commodity VALUES('co2','e','#CO2 emissions'); -INSERT INTO Commodity VALUES('nox','e','#NOX emissions'); -INSERT INTO Commodity VALUES('RH','d','# residential heating'); -INSERT INTO Commodity VALUES('RL','d','# residential lighting'); -INSERT INTO Commodity VALUES('TX','d','# transportation'); -CREATE TABLE CommodityType +INSERT INTO "commodity" VALUES('ethos','s','# dummy commodity to supply inputs (makes graph easier to read)'); +INSERT INTO "commodity" VALUES('DSL','p','# diesel'); +INSERT INTO "commodity" VALUES('ELC','p','# electricity'); +INSERT INTO "commodity" VALUES('FEQ','p','# fossil equivalent'); +INSERT INTO "commodity" VALUES('GSL','p','# gasoline'); +INSERT INTO "commodity" VALUES('HCO','p','# coal'); +INSERT INTO "commodity" VALUES('HYD','p','# water'); +INSERT INTO "commodity" VALUES('OIL','p','# crude oil'); +INSERT INTO "commodity" VALUES('URN','p','# uranium'); +INSERT INTO "commodity" VALUES('co2','e','#CO2 emissions'); +INSERT INTO "commodity" VALUES('nox','e','#NOX emissions'); +INSERT INTO "commodity" VALUES('RH','d','# residential heating'); +INSERT INTO "commodity" VALUES('RL','d','# residential lighting'); +INSERT INTO "commodity" VALUES('TX','d','# transportation'); +CREATE TABLE commodity_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO CommodityType VALUES('w','waste commodity'); -INSERT INTO CommodityType VALUES('wa','waste annual commodity'); -INSERT INTO CommodityType VALUES('wp','waste physical commodity'); -INSERT INTO CommodityType VALUES('a','annual commodity'); -INSERT INTO CommodityType VALUES('s','source commodity'); -INSERT INTO CommodityType VALUES('p','physical commodity'); -INSERT INTO CommodityType VALUES('e','emissions commodity'); -INSERT INTO CommodityType VALUES('d','demand commodity'); +INSERT INTO "commodity_type" VALUES('w','waste commodity'); +INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); +INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); +INSERT INTO "commodity_type" VALUES('a','annual commodity'); +INSERT INTO "commodity_type" VALUES('s','source commodity'); +INSERT INTO "commodity_type" VALUES('p','physical commodity'); +INSERT INTO "commodity_type" VALUES('e','emissions commodity'); +INSERT INTO "commodity_type" VALUES('d','demand commodity'); CREATE TABLE construction_input ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -281,9 +228,9 @@ CREATE TABLE cost_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT NOT NULL - REFERENCES Commodity (name), + REFERENCES commodity (name), cost REAL NOT NULL, units TEXT, notes TEXT, @@ -293,386 +240,372 @@ CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1960,40.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1970,40.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1980,40.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1990,40.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E01',1970,70.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E01',1980,70.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E01',1990,70.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E01',2000,70.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E01',1980,100.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E01',1990,100.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E01',2000,100.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E01',2010,100.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E21',1990,500.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E21',1990,500.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E21',1990,500.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E21',2000,500.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E21',2000,500.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E21',2010,500.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E31',1980,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E31',1990,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E31',1980,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E31',1990,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E31',2000,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E31',1980,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E31',1990,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E31',2000,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E31',2010,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E51',1980,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E51',1990,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E51',1980,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E51',1990,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E51',2000,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E51',1980,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E51',1990,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E51',2000,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E51',2010,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1960,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1970,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1980,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1990,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E70',1970,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E70',1980,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E70',1990,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E70',2000,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E70',1980,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E70',1990,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E70',2000,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E70',2010,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'RHO',1970,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'RHO',1980,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'RHO',1990,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'RHO',1980,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'RHO',1990,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'RHO',2000,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'RHO',1990,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'RHO',2000,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'RHO',2010,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'RL1',1980,9.46000000000000086,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'RL1',1990,9.46000000000000086,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'RL1',2000,9.46000000000000086,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'RL1',2010,9.46000000000000086,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'TXD',1970,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'TXD',1980,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'TXD',1990,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXD',1980,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXD',1990,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXD',2000,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'TXD',2000,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'TXD',2010,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'TXE',1990,100.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXE',1990,90.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXE',2000,90.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'TXE',2000,80.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'TXE',2010,80.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'TXG',1970,48.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'TXG',1980,48.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'TXG',1990,48.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXG',1980,48.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXG',1990,48.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXG',2000,48.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'TXG',2000,48.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'TXG',2010,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1960,40.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1970,40.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1980,40.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1990,40.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',1970,70.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',1980,70.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',1990,70.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',2000,70.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',1980,100.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',1990,100.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',2000,100.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',2010,100.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E21',1990,500.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E21',1990,500.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E21',1990,500.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E21',2000,500.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E21',2000,500.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E21',2010,500.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E31',1980,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E31',1990,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E31',1980,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E31',1990,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E31',2000,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',1980,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',1990,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',2000,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',2010,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E51',1980,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E51',1990,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E51',1980,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E51',1990,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E51',2000,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',1980,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',1990,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',2000,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',2010,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1960,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1970,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1980,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1990,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',1970,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',1980,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',1990,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',2000,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',1980,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',1990,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',2000,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',2010,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'RHO',1970,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'RHO',1980,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'RHO',1990,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'RHO',1980,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'RHO',1990,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'RHO',2000,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'RHO',1990,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'RHO',2000,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'RHO',2010,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'RL1',1980,9.46,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'RL1',1990,9.46,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'RL1',2000,9.46,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'RL1',2010,9.46,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXD',1970,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXD',1980,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXD',1990,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXD',1980,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXD',1990,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXD',2000,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXD',2000,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXD',2010,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXE',1990,100.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXE',1990,90.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXE',2000,90.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXE',2000,80.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXE',2010,80.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXG',1970,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXG',1980,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXG',1990,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXG',1980,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXG',1990,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXG',2000,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXG',2000,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXG',2010,48.0,'',''); CREATE TABLE cost_invest ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO cost_invest VALUES('utopia','E01',1990,2000.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E01',2000,1300.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E01',2010,1200.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E21',1990,5000.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E21',2000,5000.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E21',2010,5000.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E31',1990,3000.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E31',2000,3000.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E31',2010,3000.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E51',1990,900.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E51',2000,900.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E51',2010,900.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E70',1990,1000.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E70',2000,1000.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E70',2010,1000.0,'',''); -INSERT INTO cost_invest VALUES('utopia','RHE',1990,90.0,'',''); -INSERT INTO cost_invest VALUES('utopia','RHE',2000,90.0,'',''); -INSERT INTO cost_invest VALUES('utopia','RHE',2010,90.0,'',''); -INSERT INTO cost_invest VALUES('utopia','RHO',1990,100.0,'',''); -INSERT INTO cost_invest VALUES('utopia','RHO',2000,100.0,'',''); -INSERT INTO cost_invest VALUES('utopia','RHO',2010,100.0,'',''); -INSERT INTO cost_invest VALUES('utopia','SRE',1990,100.0,'',''); -INSERT INTO cost_invest VALUES('utopia','SRE',2000,100.0,'',''); -INSERT INTO cost_invest VALUES('utopia','SRE',2010,100.0,'',''); -INSERT INTO cost_invest VALUES('utopia','TXD',1990,1044.0,'',''); -INSERT INTO cost_invest VALUES('utopia','TXD',2000,1044.0,'',''); -INSERT INTO cost_invest VALUES('utopia','TXD',2010,1044.0,'',''); -INSERT INTO cost_invest VALUES('utopia','TXE',1990,2000.0,'',''); -INSERT INTO cost_invest VALUES('utopia','TXE',2000,1750.0,'',''); -INSERT INTO cost_invest VALUES('utopia','TXE',2010,1500.0,'',''); -INSERT INTO cost_invest VALUES('utopia','TXG',1990,1044.0,'',''); -INSERT INTO cost_invest VALUES('utopia','TXG',2000,1044.0,'',''); -INSERT INTO cost_invest VALUES('utopia','TXG',2010,1044.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E01',1990,2000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E01',2000,1300.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E01',2010,1200.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E21',1990,5000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E21',2000,5000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E21',2010,5000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E31',1990,3000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E31',2000,3000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E31',2010,3000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E51',1990,900.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E51',2000,900.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E51',2010,900.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E70',1990,1000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E70',2000,1000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E70',2010,1000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','RHE',1990,90.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','RHE',2000,90.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','RHE',2010,90.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','RHO',1990,100.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','RHO',2000,100.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','RHO',2010,100.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','SRE',1990,100.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','SRE',2000,100.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','SRE',2010,100.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXD',1990,1044.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXD',2000,1044.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXD',2010,1044.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXE',1990,2000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXE',2000,1750.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXE',2010,1500.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXG',1990,1044.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXG',2000,1044.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXG',2010,1044.0,'',''); CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_variable VALUES('utopia',1990,'IMPDSL1',1990,10.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'IMPDSL1',1990,10.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'IMPDSL1',1990,10.0,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'IMPGSL1',1990,15.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'IMPGSL1',1990,15.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'IMPGSL1',1990,15.0,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'IMPHCO1',1990,2.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'IMPHCO1',1990,2.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'IMPHCO1',1990,2.0,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'IMPOIL1',1990,8.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'IMPOIL1',1990,8.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'IMPOIL1',1990,8.0,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'IMPURN1',1990,2.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'IMPURN1',1990,2.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'IMPURN1',1990,2.0,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'E01',1960,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'E01',1970,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'E01',1980,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'E01',1990,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'E01',1970,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'E01',1980,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'E01',1990,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'E01',2000,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'E01',1980,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'E01',1990,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'E01',2000,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'E01',2010,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'E21',1990,1.5,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'E21',1990,1.5,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'E21',1990,1.5,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'E21',2000,1.5,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'E21',2000,1.5,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'E21',2010,1.5,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'E70',1960,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'E70',1970,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'E70',1980,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'E70',1990,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'E70',1970,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'E70',1980,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'E70',1990,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'E70',2000,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'E70',1980,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'E70',1990,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'E70',2000,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'E70',2010,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'SRE',1990,10.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'SRE',1990,10.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'SRE',2000,10.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'SRE',1990,10.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'SRE',2000,10.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'SRE',2010,10.0,'',''); -CREATE TABLE Demand +INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPDSL1',1990,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPDSL1',1990,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPDSL1',1990,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPGSL1',1990,15.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPGSL1',1990,15.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPGSL1',1990,15.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPHCO1',1990,2.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPHCO1',1990,2.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPHCO1',1990,2.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPOIL1',1990,8.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPOIL1',1990,8.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPOIL1',1990,8.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPURN1',1990,2.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPURN1',1990,2.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPURN1',1990,2.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1960,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1970,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1980,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1990,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',1970,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',1980,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',1990,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',2000,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',1980,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',1990,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',2000,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',2010,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E21',1990,1.5,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E21',1990,1.5,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E21',1990,1.5,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E21',2000,1.5,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E21',2000,1.5,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E21',2010,1.5,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1960,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1970,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1980,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1990,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',1970,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',1980,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',1990,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',2000,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',1980,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',1990,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',2000,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',2010,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'SRE',1990,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'SRE',1990,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'SRE',2000,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'SRE',1990,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'SRE',2000,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'SRE',2010,10.0,'',''); +CREATE TABLE demand ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), commodity TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), demand REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO Demand VALUES('utopia',1990,'RH',25.19999999999999929,'',''); -INSERT INTO Demand VALUES('utopia',2000,'RH',37.79999999999999715,'',''); -INSERT INTO Demand VALUES('utopia',2010,'RH',56.69999999999999574,'',''); -INSERT INTO Demand VALUES('utopia',1990,'RL',5.599999999999999645,'',''); -INSERT INTO Demand VALUES('utopia',2000,'RL',8.400000000000000355,'',''); -INSERT INTO Demand VALUES('utopia',2010,'RL',12.59999999999999965,'',''); -INSERT INTO Demand VALUES('utopia',1990,'TX',5.200000000000000177,'',''); -INSERT INTO Demand VALUES('utopia',2000,'TX',7.799999999999999823,'',''); -INSERT INTO Demand VALUES('utopia',2010,'TX',11.68999999999999951,'',''); -CREATE TABLE DemandSpecificDistribution +INSERT INTO "demand" VALUES('utopia',1990,'RH',25.2,'',''); +INSERT INTO "demand" VALUES('utopia',2000,'RH',37.8,'',''); +INSERT INTO "demand" VALUES('utopia',2010,'RH',5.66999999999999957e+01,'',''); +INSERT INTO "demand" VALUES('utopia',1990,'RL',5.6,'',''); +INSERT INTO "demand" VALUES('utopia',2000,'RL',8.4,'',''); +INSERT INTO "demand" VALUES('utopia',2010,'RL',12.6,'',''); +INSERT INTO "demand" VALUES('utopia',1990,'TX',5.2,'',''); +INSERT INTO "demand" VALUES('utopia',2000,'TX',7.8,'',''); +INSERT INTO "demand" VALUES('utopia',2010,'TX',11.69,'',''); +CREATE TABLE demand_specific_distribution ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), demand_name TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), dsd REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RH',0.1199999999999999956,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RH',0.05999999999999999778,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','day','RH',0.5466999999999999638,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RH',0.2732999999999999874,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RL',0.1499999999999999945,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RL',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','day','RL',0.1499999999999999945,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','night','RL',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','day','RL',0.5,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RL',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RH',0.1199999999999999956,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RH',0.05999999999999999778,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','day','RH',0.5466999999999999638,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RH',0.2732999999999999874,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RL',0.1499999999999999945,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RL',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','day','RL',0.1499999999999999945,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','night','RL',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','day','RL',0.5,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RL',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RH',0.1199999999999999956,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RH',0.05999999999999999778,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RH',0.5466999999999999638,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RH',0.2732999999999999874,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RL',0.1499999999999999945,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RL',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','day','RL',0.1499999999999999945,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','night','RL',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RL',0.5,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RL',0.1000000000000000055,''); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','day','RH',0.12,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','night','RH',0.06,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','day','RH',0.5467,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','night','RH',0.2733,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'summer','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'summer','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','day','RL',0.5,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','night','RL',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','day','RH',0.12,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','night','RH',0.06,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','day','RH',0.5467,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','night','RH',0.2733,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'summer','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'summer','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','day','RL',0.5,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','night','RL',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','day','RH',0.12,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','night','RH',0.06,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','day','RH',0.5467,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','night','RH',0.2733,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'summer','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'summer','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','day','RL',0.5,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','night','RL',0.1,''); CREATE TABLE efficiency ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO efficiency VALUES('utopia','ethos','IMPDSL1',1990,'DSL',1.0,''); -INSERT INTO efficiency VALUES('utopia','ethos','IMPGSL1',1990,'GSL',1.0,''); -INSERT INTO efficiency VALUES('utopia','ethos','IMPHCO1',1990,'HCO',1.0,''); -INSERT INTO efficiency VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,''); -INSERT INTO efficiency VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,''); -INSERT INTO efficiency VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,''); -INSERT INTO efficiency VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,''); -INSERT INTO efficiency VALUES('utopia','HCO','E01',1960,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','HCO','E01',1970,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','HCO','E01',1980,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','HCO','E01',1990,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','HCO','E01',2000,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','HCO','E01',2010,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','FEQ','E21',1990,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','FEQ','E21',2000,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','FEQ','E21',2010,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','URN','E21',1990,'ELC',0.4000000000000000222,'# 1/2.5'); -INSERT INTO efficiency VALUES('utopia','URN','E21',2000,'ELC',0.4000000000000000222,'# 1/2.5'); -INSERT INTO efficiency VALUES('utopia','URN','E21',2010,'ELC',0.4000000000000000222,'# 1/2.5'); -INSERT INTO efficiency VALUES('utopia','HYD','E31',1980,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','HYD','E31',1990,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','HYD','E31',2000,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','HYD','E31',2010,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','DSL','E70',1960,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO efficiency VALUES('utopia','DSL','E70',1970,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO efficiency VALUES('utopia','DSL','E70',1980,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO efficiency VALUES('utopia','DSL','E70',1990,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO efficiency VALUES('utopia','DSL','E70',2000,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO efficiency VALUES('utopia','DSL','E70',2010,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO efficiency VALUES('utopia','ELC','E51',1980,'ELC',0.7199999999999999734,'# 1/1.3889'); -INSERT INTO efficiency VALUES('utopia','ELC','E51',1990,'ELC',0.7199999999999999734,'# 1/1.3889'); -INSERT INTO efficiency VALUES('utopia','ELC','E51',2000,'ELC',0.7199999999999999734,'# 1/1.3889'); -INSERT INTO efficiency VALUES('utopia','ELC','E51',2010,'ELC',0.7199999999999999734,'# 1/1.3889'); -INSERT INTO efficiency VALUES('utopia','ELC','RHE',1990,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','ELC','RHE',2000,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','ELC','RHE',2010,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','DSL','RHO',1970,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','DSL','RHO',1980,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','DSL','RHO',1990,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','DSL','RHO',2000,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','DSL','RHO',2010,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','ELC','RL1',1980,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','ELC','RL1',1990,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','ELC','RL1',2000,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','ELC','RL1',2010,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','OIL','SRE',1990,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO efficiency VALUES('utopia','OIL','SRE',2000,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO efficiency VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO efficiency VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO efficiency VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO efficiency VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO efficiency VALUES('utopia','DSL','TXD',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','DSL','TXD',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','DSL','TXD',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','DSL','TXD',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','DSL','TXD',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','ELC','TXE',1990,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','ELC','TXE',2000,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','ELC','TXE',2010,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','GSL','TXG',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','GSL','TXG',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','GSL','TXG',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','GSL','TXG',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','GSL','TXG',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPDSL1',1990,'DSL',1.0,''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPGSL1',1990,'GSL',1.0,''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPHCO1',1990,'HCO',1.0,''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,''); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1960,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1970,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1980,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1990,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',2000,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',2010,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','FEQ','E21',1990,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','FEQ','E21',2000,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','FEQ','E21',2010,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','URN','E21',1990,'ELC',0.4,'# 1/2.5'); +INSERT INTO "efficiency" VALUES('utopia','URN','E21',2000,'ELC',0.4,'# 1/2.5'); +INSERT INTO "efficiency" VALUES('utopia','URN','E21',2010,'ELC',0.4,'# 1/2.5'); +INSERT INTO "efficiency" VALUES('utopia','HYD','E31',1980,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HYD','E31',1990,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HYD','E31',2000,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HYD','E31',2010,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1960,'ELC',0.294,'# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1970,'ELC',0.294,'# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1980,'ELC',0.294,'# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1990,'ELC',0.294,'# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',2000,'ELC',0.294,'# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',2010,'ELC',0.294,'# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','ELC','E51',1980,'ELC',0.72,'# 1/1.3889'); +INSERT INTO "efficiency" VALUES('utopia','ELC','E51',1990,'ELC',0.72,'# 1/1.3889'); +INSERT INTO "efficiency" VALUES('utopia','ELC','E51',2000,'ELC',0.72,'# 1/1.3889'); +INSERT INTO "efficiency" VALUES('utopia','ELC','E51',2010,'ELC',0.72,'# 1/1.3889'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RHE',1990,'RH',1.0,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RHE',2000,'RH',1.0,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RHE',2010,'RH',1.0,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',1970,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',1980,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',1990,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',2000,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',2010,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',1980,'RL',1.0,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',1990,'RL',1.0,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',2000,'RL',1.0,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',2010,'RL',1.0,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',1990,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2000,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',1970,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',1980,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',1990,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',2000,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',2010,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','TXE',1990,'TX',0.827,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','TXE',2000,'TX',0.827,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','TXE',2010,'TX',0.827,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',1970,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',1980,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',1990,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',2000,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',2010,'TX',0.231,'# direct translation from DMD_EFF'); CREATE TABLE efficiency_variable ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), @@ -682,347 +615,332 @@ CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), activity REAL, units TEXT, notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.07499999999999999723,'',''); -INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.07499999999999999723,'',''); -INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',0.0889999999999999819,'',''); -INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.07499999999999999723,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',1970,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',1980,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',1990,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',2000,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',2010,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',1970,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',1980,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',1990,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',2000,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',2010,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.075,'',''); +INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.075,'',''); +INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',8.89999999999999819e-02,'',''); +INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.075,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1970,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1980,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1990,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',2000,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',2010,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1970,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1980,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1990,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',2000,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',2010,'TX',1.0,'',''); CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) ); CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE end_of_life_output +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); CREATE TABLE existing_capacity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, units TEXT, notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO existing_capacity VALUES('utopia','E01',1960,0.1749999999999999889,'',''); -INSERT INTO existing_capacity VALUES('utopia','E01',1970,0.1749999999999999889,'',''); -INSERT INTO existing_capacity VALUES('utopia','E01',1980,0.1499999999999999945,'',''); -INSERT INTO existing_capacity VALUES('utopia','E31',1980,0.1000000000000000055,'',''); -INSERT INTO existing_capacity VALUES('utopia','E51',1980,0.5,'',''); -INSERT INTO existing_capacity VALUES('utopia','E70',1960,0.05000000000000000277,'',''); -INSERT INTO existing_capacity VALUES('utopia','E70',1970,0.05000000000000000277,'',''); -INSERT INTO existing_capacity VALUES('utopia','E70',1980,0.2000000000000000111,'',''); -INSERT INTO existing_capacity VALUES('utopia','RHO',1970,12.5,'',''); -INSERT INTO existing_capacity VALUES('utopia','RHO',1980,12.5,'',''); -INSERT INTO existing_capacity VALUES('utopia','RL1',1980,5.599999999999999645,'',''); -INSERT INTO existing_capacity VALUES('utopia','TXD',1970,0.4000000000000000222,'',''); -INSERT INTO existing_capacity VALUES('utopia','TXD',1980,0.2000000000000000111,'',''); -INSERT INTO existing_capacity VALUES('utopia','TXG',1970,3.100000000000000088,'',''); -INSERT INTO existing_capacity VALUES('utopia','TXG',1980,1.5,'',''); -CREATE TABLE TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE loan_lifetime_process +INSERT INTO "existing_capacity" VALUES('utopia','E01',1960,0.175,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','E01',1970,0.175,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','E01',1980,0.15,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','E31',1980,0.1,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','E51',1980,0.5,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','E70',1960,0.05,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','E70',1970,0.05,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','E70',1980,0.2,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','RHO',1970,12.5,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','RHO',1980,12.5,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','RL1',1980,5.6,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','TXD',1970,0.4,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','TXD',1980,0.2,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','TXG',1970,3.1,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','TXG',1980,1.5,'',''); +CREATE TABLE lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE loan_rate +INSERT INTO "lifetime_process" VALUES('utopia','RL1',1980,20.0,'#forexistingcap'); +INSERT INTO "lifetime_process" VALUES('utopia','TXD',1970,30.0,'#forexistingcap'); +INSERT INTO "lifetime_process" VALUES('utopia','TXD',1980,30.0,'#forexistingcap'); +INSERT INTO "lifetime_process" VALUES('utopia','TXG',1970,30.0,'#forexistingcap'); +INSERT INTO "lifetime_process" VALUES('utopia','TXG',1980,30.0,'#forexistingcap'); +CREATE TABLE lifetime_survival_curve ( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - rate REAL, + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES technology (tech), + vintage INTEGER NOT NULL + REFERENCES time_period (period), + fraction REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_process -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO lifetime_process VALUES('utopia','RL1',1980,20.0,'#forexistingcap'); -INSERT INTO lifetime_process VALUES('utopia','TXD',1970,30.0,'#forexistingcap'); -INSERT INTO lifetime_process VALUES('utopia','TXD',1980,30.0,'#forexistingcap'); -INSERT INTO lifetime_process VALUES('utopia','TXG',1970,30.0,'#forexistingcap'); -INSERT INTO lifetime_process VALUES('utopia','TXG',1980,30.0,'#forexistingcap'); CREATE TABLE lifetime_tech ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO lifetime_tech VALUES('utopia','E01',40.0,''); -INSERT INTO lifetime_tech VALUES('utopia','E21',40.0,''); -INSERT INTO lifetime_tech VALUES('utopia','E31',100.0,''); -INSERT INTO lifetime_tech VALUES('utopia','E51',100.0,''); -INSERT INTO lifetime_tech VALUES('utopia','E70',40.0,''); -INSERT INTO lifetime_tech VALUES('utopia','RHE',30.0,''); -INSERT INTO lifetime_tech VALUES('utopia','RHO',30.0,''); -INSERT INTO lifetime_tech VALUES('utopia','RL1',10.0,''); -INSERT INTO lifetime_tech VALUES('utopia','SRE',50.0,''); -INSERT INTO lifetime_tech VALUES('utopia','TXD',15.0,''); -INSERT INTO lifetime_tech VALUES('utopia','TXE',15.0,''); -INSERT INTO lifetime_tech VALUES('utopia','TXG',15.0,''); -INSERT INTO lifetime_tech VALUES('utopia','IMPDSL1',1000.0,''); -INSERT INTO lifetime_tech VALUES('utopia','IMPGSL1',1000.0,''); -INSERT INTO lifetime_tech VALUES('utopia','IMPHCO1',1000.0,''); -INSERT INTO lifetime_tech VALUES('utopia','IMPOIL1',1000.0,''); -INSERT INTO lifetime_tech VALUES('utopia','IMPURN1',1000.0,''); -INSERT INTO lifetime_tech VALUES('utopia','IMPHYD',1000.0,''); -INSERT INTO lifetime_tech VALUES('utopia','IMPFEQ',1000.0,''); -CREATE TABLE Operator +INSERT INTO "lifetime_tech" VALUES('utopia','E01',40.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','E21',40.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','E31',100.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','E51',100.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','E70',40.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','RHE',30.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','RHO',30.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','RL1',10.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','SRE',50.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','TXD',15.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','TXE',15.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','TXG',15.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPDSL1',1000.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPGSL1',1000.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPHCO1',1000.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPOIL1',1000.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPURN1',1000.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPHYD',1000.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPFEQ',1000.0,''); +CREATE TABLE limit_activity ( - operator TEXT PRIMARY KEY, - notes TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO Operator VALUES('e','equal to'); -INSERT INTO Operator VALUES('le','less than or equal to'); -INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE limit_growth_capacity +CREATE TABLE limit_activity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_annual_capacity_factor +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE limit_capacity +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +INSERT INTO "limit_capacity" VALUES('utopia',1990,'E31','ge',0.13,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',2000,'E31','ge',0.13,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',2010,'E31','ge',0.13,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',1990,'SRE','ge',0.1,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',1990,'E31','le',0.13,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',2000,'E31','le',0.17,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',2010,'E31','le',2.1000000000000002e-01,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',1990,'RHE','le',0.0,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',1990,'TXD','le',0.6,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',2000,'TXD','le',1.76,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',2010,'TXD','le',4.76,'',''); +CREATE TABLE limit_capacity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_capacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity +CREATE TABLE limit_emission +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitStorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -CREATE TABLE limit_activity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -INSERT INTO limit_capacity VALUES('utopia',1990,'E31','ge',0.1300000000000000044,'',''); -INSERT INTO limit_capacity VALUES('utopia',2000,'E31','ge',0.1300000000000000044,'',''); -INSERT INTO limit_capacity VALUES('utopia',2010,'E31','ge',0.1300000000000000044,'',''); -INSERT INTO limit_capacity VALUES('utopia',1990,'SRE','ge',0.1000000000000000055,'',''); -INSERT INTO limit_capacity VALUES('utopia',1990,'E31','le',0.1300000000000000044,'',''); -INSERT INTO limit_capacity VALUES('utopia',2000,'E31','le',0.1700000000000000122,'',''); -INSERT INTO limit_capacity VALUES('utopia',2010,'E31','le',0.21000000000000002,'',''); -INSERT INTO limit_capacity VALUES('utopia',1990,'RHE','le',0.0,'',''); -INSERT INTO limit_capacity VALUES('utopia',1990,'TXD','le',0.5999999999999999778,'',''); -INSERT INTO limit_capacity VALUES('utopia',2000,'TXD','le',1.760000000000000008,'',''); -INSERT INTO limit_capacity VALUES('utopia',2010,'TXD','le',4.759999999999999787,'',''); -CREATE TABLE limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), new_cap REAL, units TEXT, notes TEXT, @@ -1032,11 +950,11 @@ CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), share REAL, notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) @@ -1046,7 +964,7 @@ CREATE TABLE limit_resource region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), cum_act REAL, units TEXT, notes TEXT, @@ -1055,30 +973,49 @@ CREATE TABLE limit_resource CREATE TABLE limit_seasonal_capacity_factor ( region TEXT - REFERENCES Region (region), + REFERENCES region (region), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), factor REAL, notes TEXT, PRIMARY KEY(region, period, season, tech, operator) ); +CREATE TABLE limit_storage_level_fraction +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) +); CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -1087,13 +1024,13 @@ CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -1102,192 +1039,278 @@ CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -INSERT INTO limit_tech_output_split VALUES('utopia',1990,'SRE','DSL','ge',0.6999999999999999556,''); -INSERT INTO limit_tech_output_split VALUES('utopia',2000,'SRE','DSL','ge',0.6999999999999999556,''); -INSERT INTO limit_tech_output_split VALUES('utopia',2010,'SRE','DSL','ge',0.6999999999999999556,''); -INSERT INTO limit_tech_output_split VALUES('utopia',1990,'SRE','GSL','ge',0.2999999999999999889,''); -INSERT INTO limit_tech_output_split VALUES('utopia',2000,'SRE','GSL','ge',0.2999999999999999889,''); -INSERT INTO limit_tech_output_split VALUES('utopia',2010,'SRE','GSL','ge',0.2999999999999999889,''); +INSERT INTO "limit_tech_output_split" VALUES('utopia',1990,'SRE','DSL','ge',0.7,''); +INSERT INTO "limit_tech_output_split" VALUES('utopia',2000,'SRE','DSL','ge',0.7,''); +INSERT INTO "limit_tech_output_split" VALUES('utopia',2010,'SRE','DSL','ge',0.7,''); +INSERT INTO "limit_tech_output_split" VALUES('utopia',1990,'SRE','GSL','ge',0.3,''); +INSERT INTO "limit_tech_output_split" VALUES('utopia',2000,'SRE','GSL','ge',0.3,''); +INSERT INTO "limit_tech_output_split" VALUES('utopia',2010,'SRE','GSL','ge',0.3,''); CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE LinkedTech +CREATE TABLE linked_tech ( primary_region TEXT, primary_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), driven_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); -CREATE TABLE OutputCurtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE OutputNetCapacity +CREATE TABLE loan_lifetime_process ( - scenario TEXT, region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + REFERENCES time_period (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE loan_rate +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE metadata +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); +INSERT INTO "metadata" VALUES('DB_MINOR',0,''); +CREATE TABLE metadata_real +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,''); +CREATE TABLE operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "operator" VALUES('e','equal to'); +INSERT INTO "operator" VALUES('le','less than or equal to'); +INSERT INTO "operator" VALUES('ge','greater than or equal to'); +CREATE TABLE output_built_capacity ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, tech, vintage) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE output_cost ( scenario TEXT, region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + sector TEXT REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) ); -CREATE TABLE OutputFlowIn +CREATE TABLE output_curtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES time_period (period), + tod TEXT + REFERENCES time_of_day (tod), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_dual_variable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE output_emission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE output_flow_in ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputFlowOut +CREATE TABLE output_flow_out ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputStorageLevel +CREATE TABLE output_net_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_objective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE output_retired_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); @@ -1295,7 +1318,7 @@ CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY - REFERENCES Region (region), + REFERENCES region (region), margin REAL, notes TEXT ); @@ -1303,7 +1326,7 @@ CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -1312,64 +1335,63 @@ CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE Region +CREATE TABLE region ( region TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO Region VALUES('utopia',NULL); +INSERT INTO "region" VALUES('utopia',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE TimeSegmentFraction +CREATE TABLE rps_requirement ( - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) -); -INSERT INTO TimeSegmentFraction VALUES(1990,'inter','day',0.166699999999999987,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(1990,'inter','night',0.08329999999999999905,'# I-N'); -INSERT INTO TimeSegmentFraction VALUES(1990,'summer','day',0.166699999999999987,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(1990,'summer','night',0.08329999999999999905,'# S-N'); -INSERT INTO TimeSegmentFraction VALUES(1990,'winter','day',0.3332999999999999852,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(1990,'winter','night',0.166699999999999987,'# W-N'); -INSERT INTO TimeSegmentFraction VALUES(2000,'inter','day',0.166699999999999987,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2000,'inter','night',0.08329999999999999905,'# I-N'); -INSERT INTO TimeSegmentFraction VALUES(2000,'summer','day',0.166699999999999987,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2000,'summer','night',0.08329999999999999905,'# S-N'); -INSERT INTO TimeSegmentFraction VALUES(2000,'winter','day',0.3332999999999999852,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2000,'winter','night',0.166699999999999987,'# W-N'); -INSERT INTO TimeSegmentFraction VALUES(2010,'inter','day',0.166699999999999987,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'inter','night',0.08329999999999999905,'# I-N'); -INSERT INTO TimeSegmentFraction VALUES(2010,'summer','day',0.166699999999999987,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'summer','night',0.08329999999999999905,'# S-N'); -INSERT INTO TimeSegmentFraction VALUES(2010,'winter','day',0.3332999999999999852,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'winter','night',0.166699999999999987,'# W-N'); + region TEXT NOT NULL + REFERENCES region (region), + period INTEGER NOT NULL + REFERENCES time_period (period), + tech_group TEXT NOT NULL + REFERENCES tech_group (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE season_label +( + season TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "season_label" VALUES('inter',NULL); +INSERT INTO "season_label" VALUES('summer',NULL); +INSERT INTO "season_label" VALUES('winter',NULL); +CREATE TABLE sector_label +( + sector TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "sector_label" VALUES('supply',NULL); +INSERT INTO "sector_label" VALUES('electric',NULL); +INSERT INTO "sector_label" VALUES('transport',NULL); +INSERT INTO "sector_label" VALUES('commercial',NULL); +INSERT INTO "sector_label" VALUES('residential',NULL); +INSERT INTO "sector_label" VALUES('industrial',NULL); CREATE TABLE storage_duration ( region TEXT, @@ -1378,181 +1400,177 @@ CREATE TABLE storage_duration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE lifetime_survival_curve +CREATE TABLE tech_group ( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE tech_group_member +( + group_name TEXT + REFERENCES tech_group (group_name), + tech TEXT + REFERENCES technology (tech), + PRIMARY KEY (group_name, tech) ); -CREATE TABLE TechnologyType +CREATE TABLE technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES technology_type (label) +); +INSERT INTO "technology" VALUES('IMPDSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported diesel'); +INSERT INTO "technology" VALUES('IMPGSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported gasoline'); +INSERT INTO "technology" VALUES('IMPHCO1','p','supply','coal','',1,0,0,0,0,0,0,0,' imported coal'); +INSERT INTO "technology" VALUES('IMPOIL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported crude oil'); +INSERT INTO "technology" VALUES('IMPURN1','p','supply','nuclear','',1,0,0,0,0,0,0,0,' imported uranium'); +INSERT INTO "technology" VALUES('IMPFEQ','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported fossil equivalent'); +INSERT INTO "technology" VALUES('IMPHYD','p','supply','hydro','',1,0,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); +INSERT INTO "technology" VALUES('E01','pb','electric','coal','',0,0,0,0,0,0,0,0,' coal power plant'); +INSERT INTO "technology" VALUES('E21','pb','electric','nuclear','',0,0,0,0,0,0,0,0,' nuclear power plant'); +INSERT INTO "technology" VALUES('E31','pb','electric','hydro','',0,0,0,0,0,0,0,0,' hydro power'); +INSERT INTO "technology" VALUES('E51','ps','electric','electric','',0,0,0,0,0,0,0,0,' electric storage'); +INSERT INTO "technology" VALUES('E70','p','electric','petroleum','',0,0,0,0,0,0,0,0,' diesel power plant'); +INSERT INTO "technology" VALUES('RHE','p','residential','electric','',0,0,0,0,0,0,0,0,' electric residential heating'); +INSERT INTO "technology" VALUES('RHO','p','residential','petroleum','',0,0,0,0,0,0,0,0,' diesel residential heating'); +INSERT INTO "technology" VALUES('RL1','p','residential','electric','',0,0,0,0,0,0,0,0,' residential lighting'); +INSERT INTO "technology" VALUES('SRE','p','supply','petroleum','',0,0,0,0,0,0,0,0,' crude oil processor'); +INSERT INTO "technology" VALUES('TXD','p','transport','petroleum','',0,0,0,0,0,0,0,0,' diesel powered vehicles'); +INSERT INTO "technology" VALUES('TXE','p','transport','electric','',0,0,0,0,0,0,0,0,' electric powered vehicles'); +INSERT INTO "technology" VALUES('TXG','p','transport','petroleum','',0,0,0,0,0,0,0,0,' gasoline powered vehicles'); +CREATE TABLE technology_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('p','production technology'); -INSERT INTO TechnologyType VALUES('pb','baseload production technology'); -INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE TimeOfDay +INSERT INTO "technology_type" VALUES('p','production technology'); +INSERT INTO "technology_type" VALUES('pb','baseload production technology'); +INSERT INTO "technology_type" VALUES('ps','storage production technology'); +CREATE TABLE time_of_day ( sequence INTEGER UNIQUE, tod TEXT PRIMARY KEY ); -INSERT INTO TimeOfDay VALUES(1,'day'); -INSERT INTO TimeOfDay VALUES(2,'night'); -CREATE TABLE TimePeriod +INSERT INTO "time_of_day" VALUES(1,'day'); +INSERT INTO "time_of_day" VALUES(2,'night'); +CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES TimePeriodType (label) + REFERENCES time_period_type (label) ); -INSERT INTO TimePeriod VALUES(1,1960,'e'); -INSERT INTO TimePeriod VALUES(2,1970,'e'); -INSERT INTO TimePeriod VALUES(3,1980,'e'); -INSERT INTO TimePeriod VALUES(4,1990,'f'); -INSERT INTO TimePeriod VALUES(5,2000,'f'); -INSERT INTO TimePeriod VALUES(6,2010,'f'); -INSERT INTO TimePeriod VALUES(7,2020,'f'); -CREATE TABLE TimeSeason +INSERT INTO "time_period" VALUES(1,1960,'e'); +INSERT INTO "time_period" VALUES(2,1970,'e'); +INSERT INTO "time_period" VALUES(3,1980,'e'); +INSERT INTO "time_period" VALUES(4,1990,'f'); +INSERT INTO "time_period" VALUES(5,2000,'f'); +INSERT INTO "time_period" VALUES(6,2010,'f'); +INSERT INTO "time_period" VALUES(7,2020,'f'); +CREATE TABLE time_period_type +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO "time_period_type" VALUES('e','existing vintages'); +INSERT INTO "time_period_type" VALUES('f','future'); +CREATE TABLE time_season +( + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + season TEXT REFERENCES season_label(season), + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +INSERT INTO "time_season" VALUES(1990,1,'inter',NULL); +INSERT INTO "time_season" VALUES(1990,2,'summer',NULL); +INSERT INTO "time_season" VALUES(1990,3,'winter',NULL); +INSERT INTO "time_season" VALUES(2000,1,'inter',NULL); +INSERT INTO "time_season" VALUES(2000,2,'summer',NULL); +INSERT INTO "time_season" VALUES(2000,3,'winter',NULL); +INSERT INTO "time_season" VALUES(2010,1,'inter',NULL); +INSERT INTO "time_season" VALUES(2010,2,'summer',NULL); +INSERT INTO "time_season" VALUES(2010,3,'winter',NULL); +CREATE TABLE time_season_all ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); -INSERT INTO TimeSeason VALUES(1990,1,'inter',NULL); -INSERT INTO TimeSeason VALUES(1990,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(1990,3,'winter',NULL); -INSERT INTO TimeSeason VALUES(2000,1,'inter',NULL); -INSERT INTO TimeSeason VALUES(2000,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(2000,3,'winter',NULL); -INSERT INTO TimeSeason VALUES(2010,1,'inter',NULL); -INSERT INTO TimeSeason VALUES(2010,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(2010,3,'winter',NULL); CREATE TABLE time_season_sequential ( - period INTEGER - REFERENCES TimePeriod (period), + period INTEGER REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES SeasonLabel (season), + season TEXT REFERENCES season_label(season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE TimePeriodType +CREATE TABLE time_season_to_sequential ( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO TimePeriodType VALUES('e','existing vintages'); -INSERT INTO TimePeriodType VALUES('f','future'); -CREATE TABLE OutputEmission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE RPSRequirement -( - region TEXT NOT NULL - REFERENCES Region (region), - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech_group TEXT NOT NULL - REFERENCES TechGroup (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE TechGroupMember -( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES Technology (tech), - PRIMARY KEY (group_name, tech) + period INTEGER + REFERENCES time_period (period), + sequence INTEGER, + seas_seq TEXT, + season TEXT + REFERENCES season_label (season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) ); -CREATE TABLE Technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) -); -INSERT INTO Technology VALUES('IMPDSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported diesel'); -INSERT INTO Technology VALUES('IMPGSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported gasoline'); -INSERT INTO Technology VALUES('IMPHCO1','p','supply','coal','',1,0,0,0,0,0,0,0,' imported coal'); -INSERT INTO Technology VALUES('IMPOIL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO Technology VALUES('IMPURN1','p','supply','nuclear','',1,0,0,0,0,0,0,0,' imported uranium'); -INSERT INTO Technology VALUES('IMPFEQ','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported fossil equivalent'); -INSERT INTO Technology VALUES('IMPHYD','p','supply','hydro','',1,0,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); -INSERT INTO Technology VALUES('E01','pb','electric','coal','',0,0,0,0,0,0,0,0,' coal power plant'); -INSERT INTO Technology VALUES('E21','pb','electric','nuclear','',0,0,0,0,0,0,0,0,' nuclear power plant'); -INSERT INTO Technology VALUES('E31','pb','electric','hydro','',0,0,0,0,0,0,0,0,' hydro power'); -INSERT INTO Technology VALUES('E51','ps','electric','electric','',0,0,0,0,0,0,0,0,' electric storage'); -INSERT INTO Technology VALUES('E70','p','electric','petroleum','',0,0,0,0,0,0,0,0,' diesel power plant'); -INSERT INTO Technology VALUES('RHE','p','residential','electric','',0,0,0,0,0,0,0,0,' electric residential heating'); -INSERT INTO Technology VALUES('RHO','p','residential','petroleum','',0,0,0,0,0,0,0,0,' diesel residential heating'); -INSERT INTO Technology VALUES('RL1','p','residential','electric','',0,0,0,0,0,0,0,0,' residential lighting'); -INSERT INTO Technology VALUES('SRE','p','supply','petroleum','',0,0,0,0,0,0,0,0,' crude oil processor'); -INSERT INTO Technology VALUES('TXD','p','transport','petroleum','',0,0,0,0,0,0,0,0,' diesel powered vehicles'); -INSERT INTO Technology VALUES('TXE','p','transport','electric','',0,0,0,0,0,0,0,0,' electric powered vehicles'); -INSERT INTO Technology VALUES('TXG','p','transport','petroleum','',0,0,0,0,0,0,0,0,' gasoline powered vehicles'); -CREATE TABLE OutputCost +CREATE TABLE time_segment_fraction ( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) -); + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + segment_fraction REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) +); +INSERT INTO "time_segment_fraction" VALUES(1990,'inter','day',0.1667,'# I-D'); +INSERT INTO "time_segment_fraction" VALUES(1990,'inter','night',0.0833,'# I-N'); +INSERT INTO "time_segment_fraction" VALUES(1990,'summer','day',0.1667,'# S-D'); +INSERT INTO "time_segment_fraction" VALUES(1990,'summer','night',0.0833,'# S-N'); +INSERT INTO "time_segment_fraction" VALUES(1990,'winter','day',0.3333,'# W-D'); +INSERT INTO "time_segment_fraction" VALUES(1990,'winter','night',0.1667,'# W-N'); +INSERT INTO "time_segment_fraction" VALUES(2000,'inter','day',0.1667,'# I-D'); +INSERT INTO "time_segment_fraction" VALUES(2000,'inter','night',0.0833,'# I-N'); +INSERT INTO "time_segment_fraction" VALUES(2000,'summer','day',0.1667,'# S-D'); +INSERT INTO "time_segment_fraction" VALUES(2000,'summer','night',0.0833,'# S-N'); +INSERT INTO "time_segment_fraction" VALUES(2000,'winter','day',0.3333,'# W-D'); +INSERT INTO "time_segment_fraction" VALUES(2000,'winter','night',0.1667,'# W-N'); +INSERT INTO "time_segment_fraction" VALUES(2010,'inter','day',0.1667,'# I-D'); +INSERT INTO "time_segment_fraction" VALUES(2010,'inter','night',0.0833,'# I-N'); +INSERT INTO "time_segment_fraction" VALUES(2010,'summer','day',0.1667,'# S-D'); +INSERT INTO "time_segment_fraction" VALUES(2010,'summer','night',0.0833,'# S-N'); +INSERT INTO "time_segment_fraction" VALUES(2010,'winter','day',0.3333,'# W-D'); +INSERT INTO "time_segment_fraction" VALUES(2010,'winter','night',0.1667,'# W-N'); COMMIT; diff --git a/data_files/my_configs/config_sample.toml b/data_files/my_configs/config_sample.toml index 204e09857..fe061efc6 100644 --- a/data_files/my_configs/config_sample.toml +++ b/data_files/my_configs/config_sample.toml @@ -85,7 +85,7 @@ save_lp_file = false # What seasons represent in the model # Options: # 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples +# Seasons are a set of days in order, with each season representing only one day. Examples # might be a model of a representative week with 7 days or a whole-year model with 365 days. # Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. # 'representative_periods' @@ -95,7 +95,7 @@ save_lp_file = false # the Technology table. # 'seasonal_timeslices' # Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the # TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. # 'manual' # The sequence of time slices is defined manually in the TimeNext table (which is commented out @@ -110,7 +110,7 @@ time_sequencing = 'seasonal_timeslices' # capacity value = net capacity * capacity credit # 'dynamic' # Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: +# For most generators, contributions are available (derated) output in each time slice: # capacity value = net capacity * reserve capacity derate * capacity factor # For storage, contributions are (derated) actual output in each time slice: # capacity value = flow out * reserve capacity derate @@ -153,4 +153,3 @@ activity_labels = [] [monte_carlo] # a path from the PROJECT ROOT to the settings file that contains the run data. run_settings = 'data_files/monte_carlo/run_settings_1.csv' - diff --git a/temoa/types/model_types.py b/temoa/types/model_types.py index 7cc5cdfe1..b9d7116e7 100644 --- a/temoa/types/model_types.py +++ b/temoa/types/model_types.py @@ -99,7 +99,7 @@ class TemoaModelProtocol(Protocol): # Geography sets regions: Set - regionalIndices: Set + regional_indices: Set # Technology sets tech_all: Set @@ -115,30 +115,30 @@ class TemoaModelProtocol(Protocol): commodity_emissions: Set # Model parameters - GlobalDiscountRate: Param - Demand: Param - Efficiency: Param - ExistingCapacity: Param - CapacityToActivity: Param + global_discount_rate: Param + demand: Param + ffficiency: Param + existing_capacity: Param + capacity_to_activity: Param # Model variables - V_FlowOut: Var - V_Capacity: Var - V_NewCapacity: Var + v_flow_out: Var + v_capacity: Var + v_new_capacity: Var # Model constraints - DemandConstraint: Constraint - CommodityBalanceConstraint: Constraint - CapacityConstraint: Constraint + demand_constraint: Constraint + commodity_balance_constraint: Constraint + capacity_constraint: Constraint # Internal data structures - processInputs: ProcessInputs - processOutputs: ProcessOutputs - activeFlow_rpsditvo: ( + process_inputs: ProcessInputs + process_outputs: ProcessOutputs + active_flow_rpsditvo: ( set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] | None ) - activeActivity_rptv: set[tuple[Region, Period, Technology, Vintage]] | None + active_activity_rptv: set[tuple[Region, Period, Technology, Vintage]] | None def __init__(self, *args: object, **kwargs: object) -> None: ... @@ -167,8 +167,8 @@ class TemoaModel(AbstractModel): # Geography sets regions: Set - regionalIndices: Set - regionalGlobalIndices: Set + regional_indices: Set + regional_global_indices: Set # Technology sets tech_all: Set @@ -190,36 +190,36 @@ class TemoaModel(AbstractModel): commodity_carrier: Set # Model parameters - GlobalDiscountRate: Param - PeriodLength: Param - SegFrac: Param - Demand: Param - Efficiency: Param - ExistingCapacity: Param - CapacityToActivity: Param - CostInvest: Param - CostFixed: Param - CostVariable: Param + global_discount_rate: Param + period_length: Param + segment_fraction: Param + demand: Param + efficiency: Param + existing_capacity: Param + capacity_to_activity: Param + cost_invest: Param + cost_fixed: Param + cost_variable: Param # Model variables - V_FlowOut: Var - V_Capacity: Var - V_NewCapacity: Var - V_RetiredCapacity: Var + v_flow_out: Var + v_capacity: Var + v_new_capacity: Var + v_retired_capacity: Var # Model constraints - DemandConstraint: Constraint - CommodityBalanceConstraint: Constraint - CapacityConstraint: Constraint + demand_constraint: Constraint + commodity_balance_constraint: Constraint + capacity_constraint: Constraint # Internal tracking dictionaries - processInputs: ProcessInputs - processOutputs: ProcessOutputs + process_inputs: ProcessInputs + process_outputs: ProcessOutputs used_techs: TechSet - activeFlow_rpsditvo: set[ + active_flow_rpsditvo: set[ tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity] ] - activeActivity_rptv: set[tuple[Region, Period, Technology, Vintage]] + active_activity_rptv: set[tuple[Region, Period, Technology, Vintage]] def __init__(self, *args: object, **kwargs: object) -> None: ... diff --git a/temoa/utilities/db_migration_v3_1_to_v4.py b/temoa/utilities/db_migration_v3_1_to_v4.py new file mode 100644 index 000000000..d7c8b25a0 --- /dev/null +++ b/temoa/utilities/db_migration_v3_1_to_v4.py @@ -0,0 +1,206 @@ +#!/usr/bin/env python3 +""" +db_migration_v3_1_to_v4.py + +Migrate a v3.1 SQLite DB to a v4 SQLite DB using deterministic mapping rules. + +Usage: + python db_migration_v3_1_to_v4.py --source old_v3_1.sqlite \ + --schema temoa_schema_v4.sql \ + --out new_v4.sqlite +""" + +from __future__ import annotations + +import argparse +import re +import sqlite3 +from pathlib import Path + +# ---------- Mapping configuration ---------- +CUSTOM_MAP: dict[str, str] = { + 'TimeSeason': 'time_season', + 'time_season': 'time_season_all', + 'TimeSeasonSequential': 'time_season_sequential', + 'time_season_sequential': 'time_season_to_sequential', + 'TimeNext': 'time_manual', + 'CommodityDStreamProcess': 'commodity_down_stream_process', + 'commodityUStreamProcess': 'commodity_up_stream_process', + 'SegFrac': 'segment_fraction', + 'segfrac': 'segment_fraction', + 'MetaDataReal': 'metadata_real', + 'MetaData': 'metadata', + 'DB_MAJOR': 'db_major', + 'DB_MINOR': 'db_minor', +} +CUSTOM_EXACT_ONLY = {'time_season', 'time_season_sequential'} +CUSTOM_KEYS_SORTED = sorted( + [k for k in CUSTOM_MAP.keys() if k not in CUSTOM_EXACT_ONLY], key=lambda k: -len(k) +) + + +def to_snake_case(s: str) -> str: + if not s: + return s + if s == s.lower() and '_' in s: + return s + x = s.replace('-', '_').replace(' ', '_') + x = re.sub(r'(.)([A-Z][a-z]+)', r'\1_\2', x) + x = re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', x) + x = re.sub(r'__+', '_', x) + return x.lower() + + +def map_token_no_cascade(token: str) -> str: + if not token: + return token + mapped_values = {v.lower() for v in CUSTOM_MAP.values()} + if token.lower() in mapped_values: + return token.lower() + if token in CUSTOM_MAP: + return CUSTOM_MAP[token].lower() + tl = token.lower() + for k, v in CUSTOM_MAP.items(): + if tl == k.lower(): + return v.lower() + if any(c.isupper() for c in token): + return to_snake_case(token) + orig = token + orig_lower = orig.lower() + replacements: list[tuple[str, str]] = [ + (k, CUSTOM_MAP[k]) for k in CUSTOM_KEYS_SORTED if k.lower() in orig_lower + ] + if replacements: + out = [] + i = 0 + length = len(orig) + while i < length: + matched = False + for key, repl in replacements: + kl = len(key) + if i + kl <= length and orig[i : i + kl].lower() == key.lower(): + out.append(repl) + i += kl + matched = True + break + if not matched: + out.append(orig[i]) + i += 1 + mapped_once = ''.join(out) + mapped_once = re.sub(r'__+', '_', mapped_once).lower() + return mapped_once + return to_snake_case(token) + + +def get_table_info(conn: sqlite3.Connection, table: str) -> list[tuple]: + try: + return conn.execute(f'PRAGMA table_info({table});').fetchall() + except sqlite3.OperationalError: + return [] + + +def migrate_direct_table( + con_old: sqlite3.Connection, con_new: sqlite3.Connection, old_table: str, new_table: str +) -> int: + old_cols = [c[1] for c in get_table_info(con_old, old_table)] + if not old_cols: + return 0 + new_cols = [c[1] for c in get_table_info(con_new, new_table)] + selectable_old_cols, insert_new_cols = [], [] + for oc in old_cols: + mapped = map_token_no_cascade(oc) + if mapped == 'seg_frac': + mapped = 'segment_fraction' + if mapped in new_cols: + selectable_old_cols.append(oc) + insert_new_cols.append(mapped) + if not selectable_old_cols: + return 0 + sel_clause = ','.join(selectable_old_cols) + rows = con_old.execute(f'SELECT {sel_clause} FROM {old_table}').fetchall() + if not rows: + return 0 + # filter out rows that are entirely NULL + filtered = [r for r in rows if any(v is not None for v in r)] + if not filtered: + return 0 + placeholders = ','.join(['?'] * len(insert_new_cols)) + q = f'INSERT OR REPLACE INTO {new_table} ({",".join(insert_new_cols)}) VALUES ({placeholders})' + con_new.executemany(q, filtered) + return len(filtered) + + +def migrate_all(args) -> None: + src = Path(args.source) + schema = Path(args.schema) + out = Path(args.out) if args.out else src.with_suffix('.v4.sqlite') + con_old = sqlite3.connect(src) + con_new = sqlite3.connect(out) + with open(schema, encoding='utf-8') as f: + sql = f.read() + con_new.executescript(sql) + con_new.execute('PRAGMA foreign_keys = 0;') + old_tables = [ + r[0] + for r in con_old.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall() + ] + new_tables = [ + r[0] + for r in con_new.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall() + ] + print('DEBUG mapping samples:') + for t in ( + 'TimeSeason', + 'time_season', + 'TimeSeasonSequential', + 'time_season_sequential', + 'SegFrac', + ): + print(f' {t} -> {map_token_no_cascade(t)}') + total = 0 + for old in old_tables: + if old.lower().startswith('sqlite_'): + continue + new = map_token_no_cascade(old) + if new not in new_tables: + candidates = [t for t in new_tables if t == new or t.startswith(new) or new in t] + if len(candidates) == 1: + new = candidates[0] + else: + print(f'SKIP (no target): {old} -> {new}; candidates={candidates}') + continue + try: + n = migrate_direct_table(con_old, con_new, old, new) + print(f'Copied {n} rows: {old} -> {new}') + total += n + except Exception as e: + print('Error:', e) + # ensure metadata version bumped + cur = con_new.cursor() + cur.execute("INSERT OR REPLACE INTO metadata VALUES ('DB_MAJOR', 4, '')") + cur.execute("INSERT OR REPLACE INTO metadata VALUES ('DB_MINOR', 0, '')") + con_new.commit() + con_new.execute('VACUUM;') + con_new.execute('PRAGMA foreign_keys = 1;') + try: + fk = con_new.execute('PRAGMA FOREIGN_KEY_CHECK;').fetchall() + if fk: + print('FK issues:', fk) + except sqlite3.OperationalError: + pass + con_old.close() + con_new.close() + print('Done; approx rows:', total, '->', out) + + +def parse_cli() -> argparse.Namespace: + p = argparse.ArgumentParser() + p.add_argument('--source', required=True) + p.add_argument('--schema', required=True) + p.add_argument('--out', required=False) + return p.parse_args() + + +if __name__ == '__main__': + args = parse_cli() + migrate_all(args) diff --git a/temoa/utilities/sql_migration_v3_1_to_v4.py b/temoa/utilities/sql_migration_v3_1_to_v4.py new file mode 100644 index 000000000..3f9fd6f75 --- /dev/null +++ b/temoa/utilities/sql_migration_v3_1_to_v4.py @@ -0,0 +1,294 @@ +#!/usr/bin/env python3 +""" +sql_migration_v_3_1_to_v4.py (Robust version) + +Converts a v3.1 SQL dump (text) into a valid v4 SQL dump. +This script: +1. Loads the v3.1 SQL dump into a temporary in-memory SQLite database. +2. Applies the v4 schema to a new in-memory SQLite database. +3. Programmatically queries data from the old in-memory DB, maps table/column + names using the defined rules (non-cascading, case-sensitive-first, etc.), + and inserts data into the new in-memory v4 DB. +4. Uses SQLite's built-in .dump functionality to generate the final v4 SQL dump. + +Usage: + python sql_migration_v3_1_to_v4.py --input v3_1.sql \ + --schema temoa_schema_v4.sql \ + --output v4.sql \ + [--debug] +""" + +from __future__ import annotations + +import argparse +import re +import sqlite3 +import sys + +# ------------------ Mapping configuration (mirror sqlite migrator) ------------------ +CUSTOM_MAP: dict[str, str] = { + 'TimeSeason': 'time_season', + 'time_season': 'time_season_all', # exact-only: only exact old token -> ..._all + 'TimeSeasonSequential': 'time_season_sequential', + 'time_season_sequential': 'time_season_to_sequential', # exact-only + 'TimeNext': 'time_manual', + 'CommodityDStreamProcess': 'commodity_down_stream_process', + 'commodityUStreamProcess': 'commodity_up_stream_process', + 'SegFrac': 'time_segment_fraction', + 'segfrac': 'segment_fraction', # canonical column name for column 'segfrac' + 'MetaDataReal': 'metadata_real', + 'MetaData': 'metadata', + 'DB_MAJOR': 'db_major', + 'DB_MINOR': 'db_minor', +} +CUSTOM_EXACT_ONLY = {'time_season', 'time_season_sequential'} +CUSTOM_KEYS_SORTED = sorted( + [k for k in CUSTOM_MAP.keys() if k not in CUSTOM_EXACT_ONLY], key=lambda k: -len(k) +) + + +# ------------------ Mapping functions (non-cascading) ------------------ +def to_snake_case(s: str) -> str: + if not s: + return s + if s == s.lower() and '_' in s: + return s + x = s.replace('-', '_').replace(' ', '_') + x = re.sub(r'(.)([A-Z][a-z]+)', r'\1_\2', x) + x = re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', x) + x = re.sub(r'__+', '_', x) + return x.lower() + + +def map_token_no_cascade(token: str) -> str: + if not token: + return token + # prevent cascading (already a mapped output) + mapped_values = {v.lower() for v in CUSTOM_MAP.values()} + if token.lower() in mapped_values: + return token.lower() + # exact case-sensitive + if token in CUSTOM_MAP: + return CUSTOM_MAP[token].lower() + # exact case-insensitive + tl = token.lower() + for k, v in CUSTOM_MAP.items(): + if tl == k.lower(): + return v.lower() + # avoid substring replacements for PascalCase + if any(c.isupper() for c in token): + return to_snake_case(token) + # substring replacements (longest-first) + orig = token + orig_lower = orig.lower() + replacements = [(k, CUSTOM_MAP[k]) for k in CUSTOM_KEYS_SORTED if k.lower() in orig_lower] + if replacements: + out = [] + i = 0 + length = len(orig) + while i < length: + matched = False + for key, repl in replacements: + kl = len(key) + if i + kl <= length and orig[i : i + kl].lower() == key.lower(): + out.append(repl) + i += kl + matched = True + break + if not matched: + out.append(orig[i]) + i += 1 + mapped_once = ''.join(out) + mapped_once = re.sub(r'__+', '_', mapped_once).lower() + return mapped_once + return to_snake_case(token) + + +def map_table_name(table: str) -> str: + return map_token_no_cascade(table) + + +def map_column_name(col: str) -> str: + mapped = map_token_no_cascade(col) + if mapped == 'seg_frac': # Ensure canonical form for this column + mapped = 'segment_fraction' + return mapped + + +def get_table_info(conn: sqlite3.Connection, table: str) -> list[tuple]: + try: + return conn.execute(f'PRAGMA table_info({table});').fetchall() + except sqlite3.OperationalError: + return [] + + +def migrate_dump_to_sqlite(args) -> None: + # --- 1. Load v3.1 SQL dump into a temporary in-memory DB --- + print(f'Loading v3.1 SQL dump from {args.input} into in-memory DB...') + con_old_in_memory = sqlite3.connect(':memory:') + try: + with open(args.input, encoding='utf-8') as f: + v3_1_sql_dump = f.read() + con_old_in_memory.executescript(v3_1_sql_dump) + print('V3.1 dump loaded.') + except Exception as e: + print(f'ERROR: Failed to load v3.1 dump: {e}') + sys.exit(1) + + # --- 2. Create new in-memory DB and apply v4 schema --- + print(f'Applying v4 schema from {args.schema} to new in-memory DB...') + con_new_in_memory = sqlite3.connect(':memory:') + try: + with open(args.schema, encoding='utf-8') as f: + v4_schema_sql = f.read() + con_new_in_memory.executescript(v4_schema_sql) + con_new_in_memory.execute('PRAGMA foreign_keys = 0;') # Temporarily disable for migration + print('V4 schema applied.') + except Exception as e: + print(f'ERROR: Failed to apply v4 schema: {e}') + sys.exit(1) + + # Get old and new table/column info + old_tables = [ + r[0] + for r in con_old_in_memory.execute( + "SELECT name FROM sqlite_master WHERE type='table'" + ).fetchall() + if not r[0].lower().startswith('sqlite_') + ] + new_db_tables = [ + r[0] + for r in con_new_in_memory.execute( + "SELECT name FROM sqlite_master WHERE type='table'" + ).fetchall() + if not r[0].lower().startswith('sqlite_') + ] + + if args.debug: + print('DEBUG Mapping samples:') + for t in ( + 'TimeSeason', + 'time_season', + 'TimeSeasonSequential', + 'time_season_sequential', + 'SegFrac', + 'segfrac', + ): + print(f' {t} -> {map_token_no_cascade(t)}') + print('\nDEBUG Old DB tables:', old_tables) + print('DEBUG New DB tables:', new_db_tables) + + # --- 3. Programmatically copy data --- + total_rows_copied = 0 + for old_table_name in old_tables: + mapped_new_table_name = map_table_name(old_table_name) + + if mapped_new_table_name not in new_db_tables: + # Tolerant fallback: if canonical target table is missing, try candidates + candidates = [ + t + for t in new_db_tables + if t.startswith(mapped_new_table_name) + or mapped_new_table_name in t + or mapped_new_table_name.replace('_', '') in t.replace('_', '') + ] + if len(candidates) == 1: + chosen_table = candidates[0] + print( + f'NOTE: Mapped target {mapped_new_table_name} not found for {old_table_name}; using candidate {chosen_table}' + ) + mapped_new_table_name = chosen_table + else: + print( + f'SKIP: No target table for {old_table_name} -> {mapped_new_table_name} (candidates: {candidates})' + ) + continue + + old_cols_info = get_table_info(con_old_in_memory, old_table_name) + new_cols_info = get_table_info(con_new_in_memory, mapped_new_table_name) + + if not old_cols_info: + if args.debug: + print(f'DEBUG: No column info for old table {old_table_name}') + continue + if not new_cols_info: + if args.debug: + print(f'DEBUG: No column info for new table {mapped_new_table_name}') + continue + + old_actual_cols = [c[1] for c in old_cols_info] + new_target_cols = [c[1] for c in new_cols_info] + + selectable_old_cols_for_query = [] # actual column names in old table to select + insert_target_cols_for_query = [] # mapped column names for new table's INSERT clause + + for oc in old_actual_cols: + mapped_oc = map_column_name(oc) + if mapped_oc in new_target_cols: + selectable_old_cols_for_query.append(oc) + insert_target_cols_for_query.append(mapped_oc) + + if not selectable_old_cols_for_query: + if args.debug: + print( + f'DEBUG: No common/mappable columns from {old_table_name} to {mapped_new_table_name}. Skipping data copy.' + ) + continue + + select_query = f'SELECT {",".join(selectable_old_cols_for_query)} FROM {old_table_name}' + rows_from_old_table = con_old_in_memory.execute(select_query).fetchall() + + if not rows_from_old_table: + if args.debug: + print(f'DEBUG: No data in {old_table_name}. Skipping.') + continue + + # Filter out rows that are entirely NULL + filtered_rows_for_insert = [r for r in rows_from_old_table if any(v is not None for v in r)] + if not filtered_rows_for_insert: + if args.debug: + print(f'DEBUG: All rows from {old_table_name} were NULL. Skipping.') + continue + + placeholders = ','.join(['?'] * len(insert_target_cols_for_query)) + insert_query = f'INSERT OR REPLACE INTO {mapped_new_table_name} ({",".join(insert_target_cols_for_query)}) VALUES ({placeholders})' + + con_new_in_memory.executemany(insert_query, filtered_rows_for_insert) + rows_copied_this_table = len(filtered_rows_for_insert) + print(f'Copied {rows_copied_this_table} rows: {old_table_name} -> {mapped_new_table_name}') + total_rows_copied += rows_copied_this_table + + # --- Final updates and dump --- + con_new_in_memory.execute("INSERT OR REPLACE INTO metadata VALUES ('DB_MAJOR', 4, '')") + con_new_in_memory.execute("INSERT OR REPLACE INTO metadata VALUES ('DB_MINOR', 0, '')") + con_new_in_memory.commit() + con_new_in_memory.execute('PRAGMA foreign_keys = 1;') # Re-enable FKs + + # Generate the v4 SQL dump + print(f'Generating v4 SQL dump to {args.output}...') + with open(args.output, 'w', encoding='utf-8') as f_out: + for line in con_new_in_memory.iterdump(): + # Add back "PRAGMA foreign_keys=OFF;" and "BEGIN TRANSACTION;" at the start if missing + # And "COMMIT;" at the end. + # It seems .iterdump() already adds PRAGMA and BEGIN/COMMIT. + f_out.write(line + '\n') + + con_old_in_memory.close() + con_new_in_memory.close() + print( + f'Conversion complete. Total rows copied: {total_rows_copied}. Output dump: {args.output}' + ) + + +def parse_cli() -> argparse.Namespace: + p = argparse.ArgumentParser() + p.add_argument('--input', '-i', required=True, help='Path to v3.1 SQL dump file') + p.add_argument('--schema', '-s', required=True, help='Path to v4 schema SQL file') + p.add_argument('--output', '-o', required=True, help='Path for output v4 SQL dump file') + p.add_argument('--debug', action='store_true', help='Enable debug output') + return p.parse_args() + + +if __name__ == '__main__': + args = parse_cli() + migrate_dump_to_sqlite(args) diff --git a/temoa/version_information.py b/temoa/version_information.py index 3d9d6e94d..74268b3a5 100644 --- a/temoa/version_information.py +++ b/temoa/version_information.py @@ -9,5 +9,5 @@ MIN_PYTHON_MINOR = 12 # db is tested for match on major and >= on minor -DB_MAJOR_VERSION = 3 +DB_MAJOR_VERSION = 4 MIN_DB_MINOR_VERSION = 0 diff --git a/tests/test_network_model_data.py b/tests/test_network_model_data.py index 3af1ead4b..8443c6003 100644 --- a/tests/test_network_model_data.py +++ b/tests/test_network_model_data.py @@ -19,12 +19,12 @@ { 'name': 'basic', 'db_data': { - 'Technology WHERE retire==1': [], + 'technology WHERE retire==1': [], 'FROM SurvivalCurve': [], 'FROM time_period': [(2020,), (2025,)], - # Unique keys for each Commodity query - 'FROM main.Commodity': [('s1',), ('p1',), ('p2',), ('p3',), ('d1',), ('d2',)], - "Commodity WHERE flag LIKE '%p%'": [ + # Unique keys for each commodity query + 'FROM main.commodity': [('s1',), ('p1',), ('p2',), ('p3',), ('d1',), ('d2',)], + "commodity WHERE flag LIKE '%p%'": [ ('s1',), ('p1',), ('p2',), @@ -32,9 +32,9 @@ ('d1',), ('d2',), ], - "Commodity WHERE flag LIKE '%w%'": [], - "Commodity WHERE flag = 's'": [('s1',)], - "Commodity WHERE flag LIKE '%p%' OR flag = 's' OR flag LIKE '%a%'": [ + "commodity WHERE flag LIKE '%w%'": [], + "commodity WHERE flag = 's'": [('s1',)], + "commodity WHERE flag LIKE '%p%' OR flag = 's' OR flag LIKE '%a%'": [ ('s1',), ('p1',), ('p2',), @@ -42,7 +42,7 @@ ('d1',), ('d2',), ], - 'FROM main.Demand': [('R1', 2020, 'd1'), ('R1', 2020, 'd2')], + 'FROM main.demand': [('R1', 2020, 'd1'), ('R1', 2020, 'd2')], # Unique keys for efficiency and optional tables 'FROM main.efficiency': [ ('R1', 's1', 't4', 2000, 'p3', 100), @@ -70,20 +70,20 @@ { 'name': 'bad linked tech', 'db_data': { - 'Technology WHERE retire==1': [], + 'technology WHERE retire==1': [], 'FROM SurvivalCurve': [], 'FROM time_period': [(2020,), (2025,)], - 'FROM main.Commodity': [('s1',), ('p1',), ('p3',), ('d1',), ('d2',)], - "Commodity WHERE flag LIKE '%p%'": [('s1',), ('p3',), ('d1',), ('d2',)], - "Commodity WHERE flag LIKE '%w%'": [], - "Commodity WHERE flag = 's'": [('s1',)], - "Commodity WHERE flag LIKE '%p%' OR flag = 's' OR flag LIKE '%a%'": [ + 'FROM main.commodity': [('s1',), ('p1',), ('p3',), ('d1',), ('d2',)], + "commodity WHERE flag LIKE '%p%'": [('s1',), ('p3',), ('d1',), ('d2',)], + "commodity WHERE flag LIKE '%w%'": [], + "commodity WHERE flag = 's'": [('s1',)], + "commodity WHERE flag LIKE '%p%' OR flag = 's' OR flag LIKE '%a%'": [ ('s1',), ('p3',), ('d1',), ('d2',), ], - 'FROM main.Demand': [('R1', 2020, 'd1'), ('R1', 2020, 'd2')], + 'FROM main.demand': [('R1', 2020, 'd1'), ('R1', 2020, 'd2')], 'FROM main.efficiency': [ ('R1', 's1', 't4', 2000, 'p3', 100), ('R1', 'p1', 'driven', 1990, 'd2', 100), @@ -107,20 +107,20 @@ { 'name': 'good linked tech', 'db_data': { - 'Technology WHERE retire==1': [], + 'technology WHERE retire==1': [], 'FROM SurvivalCurve': [], 'FROM time_period': [(2020,), (2025,)], - 'FROM main.Commodity': [('s1',), ('p1',), ('d1',), ('d2',), ('s2',)], - "Commodity WHERE flag LIKE '%p%'": [('s1',), ('d1',), ('d2',), ('s2',)], - "Commodity WHERE flag LIKE '%w%'": [], - "Commodity WHERE flag = 's'": [('s1',), ('s2',)], - "Commodity WHERE flag LIKE '%p%' OR flag = 's' OR flag LIKE '%a%'": [ + 'FROM main.commodity': [('s1',), ('p1',), ('d1',), ('d2',), ('s2',)], + "commodity WHERE flag LIKE '%p%'": [('s1',), ('d1',), ('d2',), ('s2',)], + "commodity WHERE flag LIKE '%w%'": [], + "commodity WHERE flag = 's'": [('s1',), ('s2',)], + "commodity WHERE flag LIKE '%p%' OR flag = 's' OR flag LIKE '%a%'": [ ('s1',), ('d1',), ('d2',), ('s2',), ], - 'FROM main.Demand': [('R1', 2020, 'd1'), ('R1', 2020, 'd2')], + 'FROM main.demand': [('R1', 2020, 'd1'), ('R1', 2020, 'd2')], 'FROM main.efficiency': [ ('R1', 's1', 't4', 2000, 'd2', 100), ('R1', 's2', 'driven', 1990, 'd2', 100), @@ -162,7 +162,7 @@ def mock_db_connection(request): mock_con.cursor.return_value = mock_cursor def dispatcher(query: str, *_: object) -> MagicMock: - if 'sector FROM Technology' in query: + if 'sector FROM technology' in query: raise sqlite3.OperationalError('no such column: sector') for key, data in sorted(db_data.items(), key=lambda kv: -len(kv[0])): if key in query: @@ -251,11 +251,11 @@ def test_sector_handling_with_sectors() -> None: ] def dispatcher(query: str, *_: object) -> MagicMock: - if 'sector FROM Technology' in query: + if 'sector FROM technology' in query: return sector_check_mock elif 'FROM main.efficiency' in query: return efficiency_mock - elif 'Technology WHERE retire==1' in query: + elif 'technology WHERE retire==1' in query: m = MagicMock() m.fetchall.return_value = [] return m @@ -267,19 +267,19 @@ def dispatcher(query: str, *_: object) -> MagicMock: m = MagicMock() m.fetchall.return_value = [(2020,), (2025,)] return m - elif "Commodity WHERE flag LIKE '%p%'" in query: + elif "commodity WHERE flag LIKE '%p%'" in query: m = MagicMock() m.fetchall.return_value = [('s1',), ('p1',), ('d1',)] return m - elif "Commodity WHERE flag LIKE '%w%'" in query: + elif "commodity WHERE flag LIKE '%w%'" in query: m = MagicMock() m.fetchall.return_value = [] return m - elif "Commodity WHERE flag = 's'" in query: + elif "commodity WHERE flag = 's'" in query: m = MagicMock() m.fetchall.return_value = [('s1',)] return m - elif 'FROM main.Demand' in query: + elif 'FROM main.demand' in query: m = MagicMock() m.fetchall.return_value = [('R1', 2020, 'd1')] return m @@ -324,7 +324,7 @@ def test_sector_handling_without_sectors() -> None: # Mock the sector column check to raise OperationalError (column doesn't exist) def dispatcher(query: str, *_: object) -> MagicMock: - if 'sector FROM Technology' in query: + if 'sector FROM technology' in query: # Simulate column not existing raise sqlite3.OperationalError('no such column: sector') elif 'FROM main.efficiency' in query: @@ -335,11 +335,11 @@ def dispatcher(query: str, *_: object) -> MagicMock: ('R1', 'p1', 't2', 2000, 'd1', 100), ] return mock - elif 'FROM main.Commodity' in query: + elif 'FROM main.commodity' in query: m = MagicMock() m.fetchall.return_value = [('s1',), ('p1',), ('d1',)] return m - elif 'Technology WHERE retire==1' in query: + elif 'technology WHERE retire==1' in query: m = MagicMock() m.fetchall.return_value = [] return m @@ -351,19 +351,19 @@ def dispatcher(query: str, *_: object) -> MagicMock: m = MagicMock() m.fetchall.return_value = [(2020,), (2025,)] return m - elif "Commodity WHERE flag LIKE '%p%'" in query: + elif "commodity WHERE flag LIKE '%p%'" in query: m = MagicMock() m.fetchall.return_value = [('s1',), ('p1',), ('d1',)] return m - elif "Commodity WHERE flag LIKE '%w%'" in query: + elif "commodity WHERE flag LIKE '%w%'" in query: m = MagicMock() m.fetchall.return_value = [] return m - elif "Commodity WHERE flag = 's'" in query: + elif "commodity WHERE flag = 's'" in query: m = MagicMock() m.fetchall.return_value = [('s1',)] return m - elif 'FROM main.Demand' in query: + elif 'FROM main.demand' in query: m = MagicMock() m.fetchall.return_value = [('R1', 2020, 'd1')] return m diff --git a/tests/testing_configs/config_annualised_demand.toml b/tests/testing_configs/config_annualised_demand.toml index c4b291ace..ef89e26f6 100644 --- a/tests/testing_configs/config_annualised_demand.toml +++ b/tests/testing_configs/config_annualised_demand.toml @@ -33,7 +33,7 @@ save_lp_file = false # Each season represents a number of days, though not necessarily in any particular order. # If using inter-season constraints like seasonal storage or ramp rates, the true sequence # must be defined using the time_season_sequential table. Seasonal storage must also be tagged in -# the Technology table. +# the technology table. # 'seasonal_timeslices' # Each season represents a sequential slice of the year, with one or many days represented per # season. We assume that the true sequence is the same as the TimeSeason sequence, so the diff --git a/tests/testing_configs/config_emissions.toml b/tests/testing_configs/config_emissions.toml index 65fc76576..11ab97cbb 100644 --- a/tests/testing_configs/config_emissions.toml +++ b/tests/testing_configs/config_emissions.toml @@ -33,7 +33,7 @@ save_lp_file = false # Each season represents a number of days, though not necessarily in any particular order. # If using inter-season constraints like seasonal storage or ramp rates, the true sequence # must be defined using the time_season_sequential table. Seasonal storage must also be tagged in -# the Technology table. +# the technology table. # 'seasonal_timeslices' # Each season represents a sequential slice of the year, with one or many days represented per # season. We assume that the true sequence is the same as the TimeSeason sequence, so the diff --git a/tests/testing_configs/config_link_test.toml b/tests/testing_configs/config_link_test.toml index 627762a64..2fca42dbf 100644 --- a/tests/testing_configs/config_link_test.toml +++ b/tests/testing_configs/config_link_test.toml @@ -37,7 +37,7 @@ price_check = false # Check the network connectivity for processes in the model. Strongly # recommended to ensure proper performance. Results are reported in log file -# This requires that source commodities be marked with 's' in Commodity table +# This requires that source commodities be marked with 's' in commodity table # This is required for Myopic runs source_trace = true @@ -86,7 +86,7 @@ save_lp_file = false # Each season represents a number of days, though not necessarily in any particular order. # If using inter-season constraints like seasonal storage or ramp rates, the true sequence # must be defined using the time_season_sequential table. Seasonal storage must also be tagged in -# the Technology table. +# the technology table. # 'seasonal_timeslices' # Each season represents a sequential slice of the year, with one or many days represented per # season. We assume that the true sequence is the same as the TimeSeason sequence, so the diff --git a/tests/testing_configs/config_materials.toml b/tests/testing_configs/config_materials.toml index cc3b09df8..d9ec078aa 100644 --- a/tests/testing_configs/config_materials.toml +++ b/tests/testing_configs/config_materials.toml @@ -33,7 +33,7 @@ save_lp_file = false # Each season represents a number of days, though not necessarily in any particular order. # If using inter-season constraints like seasonal storage or ramp rates, the true sequence # must be defined using the time_season_sequential table. Seasonal storage must also be tagged in -# the Technology table. +# the technology table. # 'seasonal_timeslices' # Each season represents a sequential slice of the year, with one or many days represented per # season. We assume that the true sequence is the same as the TimeSeason sequence, so the diff --git a/tests/testing_configs/config_mediumville.toml b/tests/testing_configs/config_mediumville.toml index cb9a81d91..8c5761e22 100644 --- a/tests/testing_configs/config_mediumville.toml +++ b/tests/testing_configs/config_mediumville.toml @@ -67,7 +67,7 @@ save_lp_file = false # Each season represents a number of days, though not necessarily in any particular order. # If using inter-season constraints like seasonal storage or ramp rates, the true sequence # must be defined using the time_season_sequential table. Seasonal storage must also be tagged in -# the Technology table. +# the technology table. # 'seasonal_timeslices' # Each season represents a sequential slice of the year, with one or many days represented per # season. We assume that the true sequence is the same as the TimeSeason sequence, so the diff --git a/tests/testing_configs/config_seasonal_storage.toml b/tests/testing_configs/config_seasonal_storage.toml index 7bcf080a2..c1e257690 100644 --- a/tests/testing_configs/config_seasonal_storage.toml +++ b/tests/testing_configs/config_seasonal_storage.toml @@ -33,7 +33,7 @@ save_lp_file = false # Each season represents a number of days, though not necessarily in any particular order. # If using inter-season constraints like seasonal storage or ramp rates, the true sequence # must be defined using the time_season_sequential table. Seasonal storage must also be tagged in -# the Technology table. +# the technology table. # 'seasonal_timeslices' # Each season represents a sequential slice of the year, with one or many days represented per # season. We assume that the true sequence is the same as the TimeSeason sequence, so the diff --git a/tests/testing_configs/config_storageville.toml b/tests/testing_configs/config_storageville.toml index 5872f828e..5393e8309 100644 --- a/tests/testing_configs/config_storageville.toml +++ b/tests/testing_configs/config_storageville.toml @@ -67,7 +67,7 @@ save_lp_file = false # Each season represents a number of days, though not necessarily in any particular order. # If using inter-season constraints like seasonal storage or ramp rates, the true sequence # must be defined using the time_season_sequential table. Seasonal storage must also be tagged in -# the Technology table. +# the technology table. # 'seasonal_timeslices' # Each season represents a sequential slice of the year, with one or many days represented per # season. We assume that the true sequence is the same as the TimeSeason sequence, so the diff --git a/tests/testing_configs/config_survival_curve.toml b/tests/testing_configs/config_survival_curve.toml index 742872d58..ba304efbf 100644 --- a/tests/testing_configs/config_survival_curve.toml +++ b/tests/testing_configs/config_survival_curve.toml @@ -33,7 +33,7 @@ save_lp_file = false # Each season represents a number of days, though not necessarily in any particular order. # If using inter-season constraints like seasonal storage or ramp rates, the true sequence # must be defined using the time_season_sequential table. Seasonal storage must also be tagged in -# the Technology table. +# the technology table. # 'seasonal_timeslices' # Each season represents a sequential slice of the year, with one or many days represented per # season. We assume that the true sequence is the same as the TimeSeason sequence, so the diff --git a/tests/testing_configs/config_test_system.toml b/tests/testing_configs/config_test_system.toml index 278244d17..7a13de4c5 100644 --- a/tests/testing_configs/config_test_system.toml +++ b/tests/testing_configs/config_test_system.toml @@ -33,7 +33,7 @@ save_lp_file = false # Each season represents a number of days, though not necessarily in any particular order. # If using inter-season constraints like seasonal storage or ramp rates, the true sequence # must be defined using the time_season_sequential table. Seasonal storage must also be tagged in -# the Technology table. +# the technology table. # 'seasonal_timeslices' # Each season represents a sequential slice of the year, with one or many days represented per # season. We assume that the true sequence is the same as the TimeSeason sequence, so the diff --git a/tests/testing_configs/config_utopia.toml b/tests/testing_configs/config_utopia.toml index 82a499d82..705d392d6 100644 --- a/tests/testing_configs/config_utopia.toml +++ b/tests/testing_configs/config_utopia.toml @@ -33,7 +33,7 @@ save_lp_file = false # Each season represents a number of days, though not necessarily in any particular order. # If using inter-season constraints like seasonal storage or ramp rates, the true sequence # must be defined using the time_season_sequential table. Seasonal storage must also be tagged in -# the Technology table. +# the technology table. # 'seasonal_timeslices' # Each season represents a sequential slice of the year, with one or many days represented per # season. We assume that the true sequence is the same as the TimeSeason sequence, so the diff --git a/tests/testing_configs/config_utopia_myopic.toml b/tests/testing_configs/config_utopia_myopic.toml index 14c7947da..ccb6d987b 100644 --- a/tests/testing_configs/config_utopia_myopic.toml +++ b/tests/testing_configs/config_utopia_myopic.toml @@ -35,7 +35,7 @@ save_lp_file = false # Each season represents a number of days, though not necessarily in any particular order. # If using inter-season constraints like seasonal storage or ramp rates, the true sequence # must be defined using the time_season_sequential table. Seasonal storage must also be tagged in -# the Technology table. +# the technology table. # 'seasonal_timeslices' # Each season represents a sequential slice of the year, with one or many days represented per # season. We assume that the true sequence is the same as the TimeSeason sequence, so the diff --git a/tests/testing_data/US_9R_8D_legacy_set_sizes.json b/tests/testing_data/US_9R_8D_legacy_set_sizes.json index caccef066..343ce1dda 100644 --- a/tests/testing_data/US_9R_8D_legacy_set_sizes.json +++ b/tests/testing_data/US_9R_8D_legacy_set_sizes.json @@ -44,12 +44,12 @@ "tech_residential": 0, "tech_PowerPlants": 0, "segment_fraction_index": 192, - "DemandDefaultDistribution_index": 192, - "DemandSpecificDistribution_index_index_0_index_0": 88128, - "DemandSpecificDistribution_index_index_0": 88128, - "DemandSpecificDistribution_index": 88128, - "Demand_index_index_0": 3213, - "Demand_index": 3213, + "demandDefaultDistribution_index": 192, + "demand_specific_distributionon_index_index_0_index_0": 88128, + "demand_specific_distributionon_index_index_0": 88128, + "demand_specific_distributionon_index": 88128, + "demand_index_index_0": 3213, + "demand_index": 3213, "ResourceBound_index_index_0": 24255, "ResourceBound_index": 24255, "CapacityToActivity_index": 90639, diff --git a/tests/testing_data/US_9R_8D_set_sizes.json b/tests/testing_data/US_9R_8D_set_sizes.json index 15a3096be..62b076110 100644 --- a/tests/testing_data/US_9R_8D_set_sizes.json +++ b/tests/testing_data/US_9R_8D_set_sizes.json @@ -46,9 +46,9 @@ "tech_PowerPlants": 0, "progress_marker_2_index": 1, "segment_fraction_index": 192, - "DemandDefaultDistribution_index": 192, - "DemandSpecificDistribution_index": 88128, - "Demand_index": 3213, + "demand_default_distribution_index": 192, + "demand_specific_distribution_index": 88128, + "demand_index": 3213, "ResourceBound_index": 24255, "CapacityToActivity_index": 90639, "existing_capacity_index": 7160481, diff --git a/tests/testing_data/annualised_demand.sql b/tests/testing_data/annualised_demand.sql index 3f2c96584..c51ccee3d 100644 --- a/tests/testing_data/annualised_demand.sql +++ b/tests/testing_data/annualised_demand.sql @@ -1,16 +1,16 @@ PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE MetaData +CREATE TABLE metadata ( element TEXT, value INT, notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES('days_per_period',365,'count of days in each period'); -CREATE TABLE MetaDataReal +INSERT INTO metadata VALUES('DB_MAJOR',3,'DB major version number'); +INSERT INTO metadata VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO metadata VALUES('days_per_period',365,'count of days in each period'); +CREATE TABLE metadata_real ( element TEXT, value REAL, @@ -18,9 +18,9 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -CREATE TABLE OutputDualVariable +INSERT INTO metadata_real VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +INSERT INTO metadata_real VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +CREATE TABLE output_dual_variable ( scenario TEXT, constraint_name TEXT, @@ -47,9 +47,9 @@ CREATE TABLE capacity_credit ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, credit REAL, notes TEXT, @@ -60,13 +60,13 @@ CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -77,13 +77,13 @@ CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, tech), @@ -93,46 +93,46 @@ CREATE TABLE CapacityToActivity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), c2a REAL, notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE Commodity +CREATE TABLE commodity ( name TEXT PRIMARY KEY, flag TEXT - REFERENCES CommodityType (label), + REFERENCES commodityType (label), description TEXT ); -INSERT INTO Commodity VALUES('source','s',NULL); -INSERT INTO Commodity VALUES('annual','a',NULL); -INSERT INTO Commodity VALUES('physical','p',NULL); -INSERT INTO Commodity VALUES('demand','d',NULL); -CREATE TABLE CommodityType +INSERT INTO commodity VALUES('source','s',NULL); +INSERT INTO commodity VALUES('annual','a',NULL); +INSERT INTO commodity VALUES('physical','p',NULL); +INSERT INTO commodity VALUES('demand','d',NULL); +CREATE TABLE commodityType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO CommodityType VALUES('s','source commodity'); -INSERT INTO CommodityType VALUES('a','annual commodity'); -INSERT INTO CommodityType VALUES('p','physical commodity'); -INSERT INTO CommodityType VALUES('d','demand commodity'); -INSERT INTO CommodityType VALUES('e','emissions commodity'); -INSERT INTO CommodityType VALUES('w','waste commodity'); -INSERT INTO CommodityType VALUES('wa','waste annual commodity'); -INSERT INTO CommodityType VALUES('wp','waste physical commodity'); +INSERT INTO commodityType VALUES('s','source commodity'); +INSERT INTO commodityType VALUES('a','annual commodity'); +INSERT INTO commodityType VALUES('p','physical commodity'); +INSERT INTO commodityType VALUES('d','demand commodity'); +INSERT INTO commodityType VALUES('e','emissions commodity'); +INSERT INTO commodityType VALUES('w','waste commodity'); +INSERT INTO commodityType VALUES('wa','waste annual commodity'); +INSERT INTO commodityType VALUES('wp','waste physical commodity'); CREATE TABLE construction_input ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -142,9 +142,9 @@ CREATE TABLE cost_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT NOT NULL - REFERENCES Commodity (name), + REFERENCES commodity (name), cost REAL NOT NULL, units TEXT, notes TEXT, @@ -154,11 +154,11 @@ CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -168,9 +168,9 @@ CREATE TABLE cost_invest ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -182,11 +182,11 @@ CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -194,30 +194,30 @@ CREATE TABLE cost_variable ); INSERT INTO cost_variable VALUES('region',2000,'annual',2000,1.0,NULL,NULL); INSERT INTO cost_variable VALUES('region',2000,'non_annual',2000,1.0,NULL,NULL); -CREATE TABLE Demand +CREATE TABLE demand ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), commodity TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), demand REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO Demand VALUES('region',2000,'demand',1.0,NULL,NULL); -CREATE TABLE DemandSpecificDistribution +INSERT INTO demand VALUES('region',2000,'demand',1.0,NULL,NULL); +CREATE TABLE demand_specific_distribution ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), dsd REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, demand_name), @@ -227,11 +227,11 @@ CREATE TABLE end_of_life_output ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), value REAL, units TEXT, notes TEXT, @@ -241,13 +241,13 @@ CREATE TABLE efficiency ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage, output_comm), @@ -267,19 +267,19 @@ CREATE TABLE efficiency_variable ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), @@ -289,15 +289,15 @@ CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), activity REAL, units TEXT, notes TEXT, @@ -307,11 +307,11 @@ CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -321,11 +321,11 @@ CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -335,9 +335,9 @@ CREATE TABLE existing_capacity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, units TEXT, notes TEXT, @@ -353,9 +353,9 @@ CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -366,9 +366,9 @@ CREATE TABLE loan_rate ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), rate REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -377,9 +377,9 @@ CREATE TABLE lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -388,7 +388,7 @@ CREATE TABLE lifetime_tech ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -479,15 +479,15 @@ CREATE TABLE LimitStorageLevelFraction ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), fraction REAL, @@ -498,7 +498,7 @@ CREATE TABLE limit_activity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -513,7 +513,7 @@ CREATE TABLE limit_activity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -526,11 +526,11 @@ CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, @@ -542,7 +542,7 @@ CREATE TABLE limit_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -555,7 +555,7 @@ CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -568,7 +568,7 @@ CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -581,7 +581,7 @@ CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -604,13 +604,13 @@ CREATE TABLE limit_resource CREATE TABLE limit_seasonal_capacity_factor ( region TEXT - REFERENCES Region (region), + REFERENCES region (region), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, @@ -621,11 +621,11 @@ CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -636,11 +636,11 @@ CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -651,11 +651,11 @@ CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -666,11 +666,11 @@ CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -681,9 +681,9 @@ CREATE TABLE limit_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), value REAL, @@ -695,33 +695,33 @@ CREATE TABLE LinkedTech ( primary_region TEXT, primary_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), driven_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); -CREATE TABLE OutputCurtailment +CREATE TABLE output_curtailment ( scenario TEXT, region TEXT, sector TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), curtailment REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); @@ -732,24 +732,24 @@ CREATE TABLE OutputNetCapacity sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE output_built_capacity ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, tech, vintage) ); @@ -760,11 +760,11 @@ CREATE TABLE OutputRetiredCapacity sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cap_eol REAL, cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) @@ -776,19 +776,19 @@ CREATE TABLE OutputFlowIn sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); @@ -799,38 +799,38 @@ CREATE TABLE OutputFlowOut sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputStorageLevel +CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); @@ -838,7 +838,7 @@ CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY - REFERENCES Region (region), + REFERENCES region (region), margin REAL, notes TEXT ); @@ -846,7 +846,7 @@ CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -855,27 +855,27 @@ CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE Region +CREATE TABLE region ( region TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO Region VALUES('region',NULL); +INSERT INTO region VALUES('region',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -885,7 +885,7 @@ CREATE TABLE reserve_capacity_derate CREATE TABLE TimeSegmentFraction ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT @@ -909,22 +909,22 @@ CREATE TABLE lifetime_survival_curve region TEXT NOT NULL, period INTEGER NOT NULL, tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), fraction REAL, notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE TechnologyType +CREATE TABLE technologyType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('p','production technology'); -INSERT INTO TechnologyType VALUES('pb','baseload production technology'); -INSERT INTO TechnologyType VALUES('ps','storage production technology'); +INSERT INTO technologyType VALUES('p','production technology'); +INSERT INTO technologyType VALUES('pb','baseload production technology'); +INSERT INTO technologyType VALUES('ps','storage production technology'); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -932,20 +932,20 @@ CREATE TABLE TimeOfDay PRIMARY KEY ); INSERT INTO TimeOfDay VALUES(0,'D1'); -CREATE TABLE TimePeriod +CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES TimePeriodType (label) + REFERENCES time_periodType (label) ); -INSERT INTO TimePeriod VALUES(0,2000,'f'); -INSERT INTO TimePeriod VALUES(1,2001,'f'); +INSERT INTO time_period VALUES(0,2000,'f'); +INSERT INTO time_period VALUES(1,2001,'f'); CREATE TABLE TimeSeason ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, season TEXT REFERENCES SeasonLabel (season), @@ -956,7 +956,7 @@ INSERT INTO TimeSeason VALUES(2000,0,'S1',NULL); CREATE TABLE time_season_sequential ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, season TEXT @@ -966,14 +966,14 @@ CREATE TABLE time_season_sequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE TimePeriodType +CREATE TABLE time_periodType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TimePeriodType VALUES('e','existing vintages'); -INSERT INTO TimePeriodType VALUES('f','future'); +INSERT INTO time_periodType VALUES('e','existing vintages'); +INSERT INTO time_periodType VALUES('f','future'); CREATE TABLE OutputEmission ( scenario TEXT, @@ -981,22 +981,22 @@ CREATE TABLE OutputEmission sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); CREATE TABLE RPSRequirement ( region TEXT NOT NULL - REFERENCES Region (region), + REFERENCES region (region), period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_group TEXT NOT NULL REFERENCES TechGroup (group_name), requirement REAL NOT NULL, @@ -1007,10 +1007,10 @@ CREATE TABLE TechGroupMember group_name TEXT REFERENCES TechGroup (group_name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), PRIMARY KEY (group_name, tech) ); -CREATE TABLE Technology +CREATE TABLE technology ( tech TEXT NOT NULL PRIMARY KEY, flag TEXT NOT NULL, @@ -1026,19 +1026,19 @@ CREATE TABLE Technology exchange INTEGER NOT NULL DEFAULT 0, seas_stor INTEGER NOT NULL DEFAULT 0, description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) + FOREIGN KEY (flag) REFERENCES technologyType (label) ); -INSERT INTO Technology VALUES('annual','p','energy',NULL,NULL,0,1,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('import','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('non_annual','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -CREATE TABLE OutputCost +INSERT INTO technology VALUES('annual','p','energy',NULL,NULL,0,1,0,0,0,0,0,0,NULL); +INSERT INTO technology VALUES('import','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO technology VALUES('non_annual','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +CREATE TABLE output_cost ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), d_invest REAL, d_fixed REAL, d_var REAL, @@ -1048,7 +1048,7 @@ CREATE TABLE OutputCost var REAL, emiss REAL, PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) ); COMMIT; diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index cd9c86349..fcf3137db 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -1,16 +1,16 @@ PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE MetaData +CREATE TABLE metadata ( element TEXT, value INT, notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); -CREATE TABLE MetaDataReal +INSERT INTO metadata VALUES('DB_MAJOR',3,'DB major version number'); +INSERT INTO metadata VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO metadata VALUES ('days_per_period', 365, 'count of days in each period'); +CREATE TABLE metadata_real ( element TEXT, value REAL, @@ -18,9 +18,9 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,'Discount Rate for future costs'); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); -CREATE TABLE OutputDualVariable +INSERT INTO metadata_real VALUES('global_discount_rate',0.05000000000000000277,'Discount Rate for future costs'); +INSERT INTO metadata_real VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); +CREATE TABLE output_dual_variable ( scenario TEXT, constraint_name TEXT, @@ -48,9 +48,9 @@ CREATE TABLE capacity_credit ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, credit REAL, notes TEXT, @@ -61,13 +61,13 @@ CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -78,79 +78,79 @@ CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO capacity_factor_tech VALUES('TestRegion',2000,'S1','TOD1','TechCurtailment',1.0,NULL); -INSERT INTO capacity_factor_tech VALUES('TestRegion',2000,'S1','TOD2','TechCurtailment',0.5,NULL); -INSERT INTO capacity_factor_tech VALUES('TestRegion',2000,'S1','TOD1','TechOrdinary',1.0,NULL); -INSERT INTO capacity_factor_tech VALUES('TestRegion',2000,'S1','TOD2','TechOrdinary',0.5,NULL); +INSERT INTO capacity_factor_tech VALUES('Testregion',2000,'S1','TOD1','TechCurtailment',1.0,NULL); +INSERT INTO capacity_factor_tech VALUES('Testregion',2000,'S1','TOD2','TechCurtailment',0.5,NULL); +INSERT INTO capacity_factor_tech VALUES('Testregion',2000,'S1','TOD1','TechOrdinary',1.0,NULL); +INSERT INTO capacity_factor_tech VALUES('Testregion',2000,'S1','TOD2','TechOrdinary',0.5,NULL); CREATE TABLE CapacityToActivity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), c2a REAL, notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE Commodity +CREATE TABLE commodity ( name TEXT PRIMARY KEY, flag TEXT - REFERENCES CommodityType (label), + REFERENCES commodityType (label), description TEXT ); -INSERT INTO Commodity VALUES('annual_in','s',NULL); -INSERT INTO Commodity VALUES('flex_in','s',NULL); -INSERT INTO Commodity VALUES('ordinary_in','s',NULL); -INSERT INTO Commodity VALUES('curtailment_in','s',NULL); -INSERT INTO Commodity VALUES('annual_out','d',NULL); -INSERT INTO Commodity VALUES('flex_out','p',NULL); -INSERT INTO Commodity VALUES('ordinary_out','d',NULL); -INSERT INTO Commodity VALUES('curtailment_out','d',NULL); -INSERT INTO Commodity VALUES('emission','e',NULL); -INSERT INTO Commodity VALUES('flex_null','d',NULL); -INSERT INTO Commodity VALUES('annual_flex_out','p',NULL); -INSERT INTO Commodity VALUES('annual_flex_in','s',NULL); -INSERT INTO Commodity VALUES('annual_flex_null','d',NULL); -INSERT INTO Commodity VALUES('embodied_in','s',NULL); -INSERT INTO Commodity VALUES('embodied_out','d',NULL); -INSERT INTO Commodity VALUES('eol_in','s',NULL); -INSERT INTO Commodity VALUES('eol_out','d',NULL); -CREATE TABLE CommodityType +INSERT INTO commodity VALUES('annual_in','s',NULL); +INSERT INTO commodity VALUES('flex_in','s',NULL); +INSERT INTO commodity VALUES('ordinary_in','s',NULL); +INSERT INTO commodity VALUES('curtailment_in','s',NULL); +INSERT INTO commodity VALUES('annual_out','d',NULL); +INSERT INTO commodity VALUES('flex_out','p',NULL); +INSERT INTO commodity VALUES('ordinary_out','d',NULL); +INSERT INTO commodity VALUES('curtailment_out','d',NULL); +INSERT INTO commodity VALUES('emission','e',NULL); +INSERT INTO commodity VALUES('flex_null','d',NULL); +INSERT INTO commodity VALUES('annual_flex_out','p',NULL); +INSERT INTO commodity VALUES('annual_flex_in','s',NULL); +INSERT INTO commodity VALUES('annual_flex_null','d',NULL); +INSERT INTO commodity VALUES('embodied_in','s',NULL); +INSERT INTO commodity VALUES('embodied_out','d',NULL); +INSERT INTO commodity VALUES('eol_in','s',NULL); +INSERT INTO commodity VALUES('eol_out','d',NULL); +CREATE TABLE commodityType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO CommodityType VALUES('w','waste commodity'); -INSERT INTO CommodityType VALUES('wa','waste annual commodity'); -INSERT INTO CommodityType VALUES('wp','waste physical commodity'); -INSERT INTO CommodityType VALUES('a','annual commodity'); -INSERT INTO CommodityType VALUES('p','physical commodity'); -INSERT INTO CommodityType VALUES('e','emissions commodity'); -INSERT INTO CommodityType VALUES('d','demand commodity'); -INSERT INTO CommodityType VALUES('s','source commodity'); +INSERT INTO commodityType VALUES('w','waste commodity'); +INSERT INTO commodityType VALUES('wa','waste annual commodity'); +INSERT INTO commodityType VALUES('wp','waste physical commodity'); +INSERT INTO commodityType VALUES('a','annual commodity'); +INSERT INTO commodityType VALUES('p','physical commodity'); +INSERT INTO commodityType VALUES('e','emissions commodity'); +INSERT INTO commodityType VALUES('d','demand commodity'); +INSERT INTO commodityType VALUES('s','source commodity'); CREATE TABLE construction_input ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -160,25 +160,25 @@ CREATE TABLE cost_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT NOT NULL - REFERENCES Commodity (name), + REFERENCES commodity (name), cost REAL NOT NULL, units TEXT, notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -INSERT INTO cost_emission VALUES('TestRegion',2000,'emission',0.6999999999999999556,NULL,NULL); -INSERT INTO cost_emission VALUES('TestRegion',2005,'emission',0.6999999999999999556,NULL,NULL); +INSERT INTO cost_emission VALUES('Testregion',2000,'emission',0.6999999999999999556,NULL,NULL); +INSERT INTO cost_emission VALUES('Testregion',2005,'emission',0.6999999999999999556,NULL,NULL); CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -188,9 +188,9 @@ CREATE TABLE cost_invest ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -200,52 +200,52 @@ CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE Demand +CREATE TABLE demand ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), commodity TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), demand REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO Demand VALUES('TestRegion',2000,'annual_out',1.0,NULL,NULL); -INSERT INTO Demand VALUES('TestRegion',2000,'ordinary_out',0.2999999999999999889,NULL,NULL); -INSERT INTO Demand VALUES('TestRegion',2000,'curtailment_out',0.2999999999999999889,NULL,NULL); -INSERT INTO Demand VALUES('TestRegion',2000,'flex_null',0.2999999999999999889,NULL,NULL); -INSERT INTO Demand VALUES('TestRegion',2000,'annual_flex_null',0.2999999999999999889,NULL,NULL); -INSERT INTO Demand VALUES('TestRegion',2000,'embodied_out',0.5999999999999999778,NULL,NULL); -INSERT INTO Demand VALUES('TestRegion',2000,'eol_out',0.5999999999999999778,NULL,NULL); -INSERT INTO Demand VALUES('TestRegion',2005,'ordinary_out',0.2999999999999999889,NULL,NULL); -INSERT INTO Demand VALUES('TestRegion',2005,'annual_out',1.0,NULL,NULL); -INSERT INTO Demand VALUES('TestRegion',2005,'curtailment_out',0.2999999999999999889,NULL,NULL); -INSERT INTO Demand VALUES('TestRegion',2005,'flex_null',0.2999999999999999889,NULL,NULL); -INSERT INTO Demand VALUES('TestRegion',2005,'annual_flex_null',0.2999999999999999889,NULL,NULL); -INSERT INTO Demand VALUES('TestRegion',2005,'embodied_out',0.5999999999999999778,NULL,NULL); -CREATE TABLE DemandSpecificDistribution +INSERT INTO demand VALUES('Testregion',2000,'annual_out',1.0,NULL,NULL); +INSERT INTO demand VALUES('Testregion',2000,'ordinary_out',0.2999999999999999889,NULL,NULL); +INSERT INTO demand VALUES('Testregion',2000,'curtailment_out',0.2999999999999999889,NULL,NULL); +INSERT INTO demand VALUES('Testregion',2000,'flex_null',0.2999999999999999889,NULL,NULL); +INSERT INTO demand VALUES('Testregion',2000,'annual_flex_null',0.2999999999999999889,NULL,NULL); +INSERT INTO demand VALUES('Testregion',2000,'embodied_out',0.5999999999999999778,NULL,NULL); +INSERT INTO demand VALUES('Testregion',2000,'eol_out',0.5999999999999999778,NULL,NULL); +INSERT INTO demand VALUES('Testregion',2005,'ordinary_out',0.2999999999999999889,NULL,NULL); +INSERT INTO demand VALUES('Testregion',2005,'annual_out',1.0,NULL,NULL); +INSERT INTO demand VALUES('Testregion',2005,'curtailment_out',0.2999999999999999889,NULL,NULL); +INSERT INTO demand VALUES('Testregion',2005,'flex_null',0.2999999999999999889,NULL,NULL); +INSERT INTO demand VALUES('Testregion',2005,'annual_flex_null',0.2999999999999999889,NULL,NULL); +INSERT INTO demand VALUES('Testregion',2005,'embodied_out',0.5999999999999999778,NULL,NULL); +CREATE TABLE demand_specific_distribution ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), dsd REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, demand_name), @@ -255,11 +255,11 @@ CREATE TABLE end_of_life_output ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), value REAL, units TEXT, notes TEXT, @@ -269,44 +269,44 @@ CREATE TABLE efficiency ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO efficiency VALUES('TestRegion','annual_in','TechAnnual',2000,'annual_out',1.0,NULL); -INSERT INTO efficiency VALUES('TestRegion','flex_in','TechFlex',2000,'flex_out',1.0,NULL); -INSERT INTO efficiency VALUES('TestRegion','ordinary_in','TechOrdinary',2000,'ordinary_out',1.0,NULL); -INSERT INTO efficiency VALUES('TestRegion','curtailment_in','TechCurtailment',2000,'curtailment_out',1.0,NULL); -INSERT INTO efficiency VALUES('TestRegion','flex_out','TechFlexNull',2000,'flex_null',1.0,NULL); -INSERT INTO efficiency VALUES('TestRegion','annual_flex_out','TechFlexNull',2000,'annual_flex_null',1.0,NULL); -INSERT INTO efficiency VALUES('TestRegion','annual_flex_in','TechAnnualFlex',2000,'annual_flex_out',1.0,NULL); -INSERT INTO efficiency VALUES('TestRegion','embodied_in','TechEmbodied',2000,'embodied_out',1.0,NULL); -INSERT INTO efficiency VALUES('TestRegion','eol_in','TechEndOfLife',2000,'eol_out',1.0,NULL); +INSERT INTO efficiency VALUES('Testregion','annual_in','TechAnnual',2000,'annual_out',1.0,NULL); +INSERT INTO efficiency VALUES('Testregion','flex_in','TechFlex',2000,'flex_out',1.0,NULL); +INSERT INTO efficiency VALUES('Testregion','ordinary_in','TechOrdinary',2000,'ordinary_out',1.0,NULL); +INSERT INTO efficiency VALUES('Testregion','curtailment_in','TechCurtailment',2000,'curtailment_out',1.0,NULL); +INSERT INTO efficiency VALUES('Testregion','flex_out','TechFlexNull',2000,'flex_null',1.0,NULL); +INSERT INTO efficiency VALUES('Testregion','annual_flex_out','TechFlexNull',2000,'annual_flex_null',1.0,NULL); +INSERT INTO efficiency VALUES('Testregion','annual_flex_in','TechAnnualFlex',2000,'annual_flex_out',1.0,NULL); +INSERT INTO efficiency VALUES('Testregion','embodied_in','TechEmbodied',2000,'embodied_out',1.0,NULL); +INSERT INTO efficiency VALUES('Testregion','eol_in','TechEndOfLife',2000,'eol_out',1.0,NULL); CREATE TABLE efficiency_variable ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), @@ -316,62 +316,62 @@ CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), activity REAL, units TEXT, notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO emission_activity VALUES('TestRegion','emission','annual_in','TechAnnual',2000,'annual_out',1.0,NULL,NULL); -INSERT INTO emission_activity VALUES('TestRegion','emission','flex_in','TechFlex',2000,'flex_out',1.0,NULL,NULL); -INSERT INTO emission_activity VALUES('TestRegion','emission','ordinary_in','TechOrdinary',2000,'ordinary_out',1.0,NULL,NULL); -INSERT INTO emission_activity VALUES('TestRegion','emission','curtailment_in','TechCurtailment',2000,'curtailment_out',1.0,NULL,NULL); -INSERT INTO emission_activity VALUES('TestRegion','emission','annual_flex_in','TechAnnualFlex',2000,'annual_flex_out',1.0,NULL,NULL); +INSERT INTO emission_activity VALUES('Testregion','emission','annual_in','TechAnnual',2000,'annual_out',1.0,NULL,NULL); +INSERT INTO emission_activity VALUES('Testregion','emission','flex_in','TechFlex',2000,'flex_out',1.0,NULL,NULL); +INSERT INTO emission_activity VALUES('Testregion','emission','ordinary_in','TechOrdinary',2000,'ordinary_out',1.0,NULL,NULL); +INSERT INTO emission_activity VALUES('Testregion','emission','curtailment_in','TechCurtailment',2000,'curtailment_out',1.0,NULL,NULL); +INSERT INTO emission_activity VALUES('Testregion','emission','annual_flex_in','TechAnnualFlex',2000,'annual_flex_out',1.0,NULL,NULL); CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -INSERT INTO emission_embodied VALUES('TestRegion','emission','TechEmbodied',2000,0.5,NULL,NULL); +INSERT INTO emission_embodied VALUES('Testregion','emission','TechEmbodied',2000,0.5,NULL,NULL); CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, PRIMARY KEY (region, emis_comm, tech, vintage) ); -INSERT INTO emission_end_of_life VALUES('TestRegion','emission','TechEndOfLife',2000,0.5,NULL,NULL); +INSERT INTO emission_end_of_life VALUES('Testregion','emission','TechEndOfLife',2000,0.5,NULL,NULL); CREATE TABLE existing_capacity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, units TEXT, notes TEXT, @@ -387,9 +387,9 @@ CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -398,9 +398,9 @@ CREATE TABLE loan_rate ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), rate REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -409,9 +409,9 @@ CREATE TABLE lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -420,12 +420,12 @@ CREATE TABLE lifetime_tech ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO lifetime_tech VALUES('TestRegion','TechEndOfLife',5.0,NULL); +INSERT INTO lifetime_tech VALUES('Testregion','TechEndOfLife',5.0,NULL); CREATE TABLE Operator ( operator TEXT PRIMARY KEY, @@ -510,15 +510,15 @@ CREATE TABLE LimitStorageLevelFraction ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), fraction REAL, @@ -529,7 +529,7 @@ CREATE TABLE limit_activity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -538,15 +538,15 @@ CREATE TABLE limit_activity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO limit_activity VALUES('TestRegion',2000,'TechFlex','ge',1.0,NULL,NULL); -INSERT INTO limit_activity VALUES('TestRegion',2000,'TechAnnualFlex','ge',1.0,NULL,NULL); -INSERT INTO limit_activity VALUES('TestRegion',2000,'TechFlex','le',1.0,NULL,NULL); -INSERT INTO limit_activity VALUES('TestRegion',2000,'TechAnnualFlex','le',1.0,NULL,NULL); +INSERT INTO limit_activity VALUES('Testregion',2000,'TechFlex','ge',1.0,NULL,NULL); +INSERT INTO limit_activity VALUES('Testregion',2000,'TechAnnualFlex','ge',1.0,NULL,NULL); +INSERT INTO limit_activity VALUES('Testregion',2000,'TechFlex','le',1.0,NULL,NULL); +INSERT INTO limit_activity VALUES('Testregion',2000,'TechAnnualFlex','le',1.0,NULL,NULL); CREATE TABLE limit_activity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -559,11 +559,11 @@ CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, @@ -575,7 +575,7 @@ CREATE TABLE limit_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -584,15 +584,15 @@ CREATE TABLE limit_capacity notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO limit_capacity VALUES('TestRegion',2000,'TechOrdinary','ge',1.0,NULL,NULL); -INSERT INTO limit_capacity VALUES('TestRegion',2000,'TechCurtailment','ge',1.0,NULL,NULL); -INSERT INTO limit_capacity VALUES('TestRegion',2000,'TechOrdinary','le',1.0,NULL,NULL); -INSERT INTO limit_capacity VALUES('TestRegion',2000,'TechCurtailment','le',1.0,NULL,NULL); +INSERT INTO limit_capacity VALUES('Testregion',2000,'TechOrdinary','ge',1.0,NULL,NULL); +INSERT INTO limit_capacity VALUES('Testregion',2000,'TechCurtailment','ge',1.0,NULL,NULL); +INSERT INTO limit_capacity VALUES('Testregion',2000,'TechOrdinary','le',1.0,NULL,NULL); +INSERT INTO limit_capacity VALUES('Testregion',2000,'TechCurtailment','le',1.0,NULL,NULL); CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -605,7 +605,7 @@ CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -618,7 +618,7 @@ CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -641,13 +641,13 @@ CREATE TABLE limit_resource CREATE TABLE limit_seasonal_capacity_factor ( region TEXT - REFERENCES Region (region), + REFERENCES region (region), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, @@ -658,11 +658,11 @@ CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -673,11 +673,11 @@ CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -688,11 +688,11 @@ CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -703,11 +703,11 @@ CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -718,9 +718,9 @@ CREATE TABLE limit_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), value REAL, @@ -732,33 +732,33 @@ CREATE TABLE LinkedTech ( primary_region TEXT, primary_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), driven_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); -CREATE TABLE OutputCurtailment +CREATE TABLE output_curtailment ( scenario TEXT, region TEXT, sector TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), curtailment REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); @@ -769,24 +769,24 @@ CREATE TABLE OutputNetCapacity sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE output_built_capacity ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, tech, vintage) ); @@ -797,11 +797,11 @@ CREATE TABLE OutputRetiredCapacity sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cap_eol REAL, cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) @@ -813,19 +813,19 @@ CREATE TABLE OutputFlowIn sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); @@ -836,38 +836,38 @@ CREATE TABLE OutputFlowOut sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputStorageLevel +CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); @@ -875,7 +875,7 @@ CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY - REFERENCES Region (region), + REFERENCES region (region), margin REAL, notes TEXT ); @@ -883,7 +883,7 @@ CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -892,27 +892,27 @@ CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE Region +CREATE TABLE region ( region TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO Region VALUES('TestRegion',NULL); +INSERT INTO region VALUES('Testregion',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -922,7 +922,7 @@ CREATE TABLE reserve_capacity_derate CREATE TABLE TimeSegmentFraction ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT @@ -949,22 +949,22 @@ CREATE TABLE lifetime_survival_curve region TEXT NOT NULL, period INTEGER NOT NULL, tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), fraction REAL, notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE TechnologyType +CREATE TABLE technologyType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('p','production technology'); -INSERT INTO TechnologyType VALUES('pb','baseload production technology'); -INSERT INTO TechnologyType VALUES('ps','storage production technology'); +INSERT INTO technologyType VALUES('p','production technology'); +INSERT INTO technologyType VALUES('pb','baseload production technology'); +INSERT INTO technologyType VALUES('ps','storage production technology'); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -973,22 +973,22 @@ CREATE TABLE TimeOfDay ); INSERT INTO TimeOfDay VALUES(1,'TOD1'); INSERT INTO TimeOfDay VALUES(2,'TOD2'); -CREATE TABLE TimePeriod +CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES TimePeriodType (label) + REFERENCES time_periodType (label) ); -INSERT INTO TimePeriod VALUES(1,1999,'e'); -INSERT INTO TimePeriod VALUES(2,2000,'f'); -INSERT INTO TimePeriod VALUES(3,2005,'f'); -INSERT INTO TimePeriod VALUES(4,2010,'f'); +INSERT INTO time_period VALUES(1,1999,'e'); +INSERT INTO time_period VALUES(2,2000,'f'); +INSERT INTO time_period VALUES(3,2005,'f'); +INSERT INTO time_period VALUES(4,2010,'f'); CREATE TABLE TimeSeason ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, season TEXT REFERENCES SeasonLabel (season), @@ -1000,7 +1000,7 @@ INSERT INTO TimeSeason VALUES(2005,1,'S1',NULL); CREATE TABLE time_season_sequential ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, season TEXT @@ -1010,14 +1010,14 @@ CREATE TABLE time_season_sequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE TimePeriodType +CREATE TABLE time_periodType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TimePeriodType VALUES('e','existing vintages'); -INSERT INTO TimePeriodType VALUES('f','future'); +INSERT INTO time_periodType VALUES('e','existing vintages'); +INSERT INTO time_periodType VALUES('f','future'); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1025,22 +1025,22 @@ CREATE TABLE OutputEmission sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); CREATE TABLE RPSRequirement ( region TEXT NOT NULL - REFERENCES Region (region), + REFERENCES region (region), period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_group TEXT NOT NULL REFERENCES TechGroup (group_name), requirement REAL NOT NULL, @@ -1051,10 +1051,10 @@ CREATE TABLE TechGroupMember group_name TEXT REFERENCES TechGroup (group_name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), PRIMARY KEY (group_name, tech) ); -CREATE TABLE Technology +CREATE TABLE technology ( tech TEXT NOT NULL PRIMARY KEY, flag TEXT NOT NULL, @@ -1070,24 +1070,24 @@ CREATE TABLE Technology exchange INTEGER NOT NULL DEFAULT 0, seas_stor INTEGER NOT NULL DEFAULT 0, description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) -); -INSERT INTO Technology VALUES('TechAnnual','p','energy',NULL,NULL,0,1,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('TechFlex','p','energy',NULL,NULL,0,0,0,0,0,1,0,0,NULL); -INSERT INTO Technology VALUES('TechOrdinary','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('TechCurtailment','p','energy',NULL,NULL,0,0,0,1,0,0,0,0,NULL); -INSERT INTO Technology VALUES('TechFlexNull','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('TechAnnualFlex','p','energy',NULL,NULL,0,1,0,0,0,1,0,0,NULL); -INSERT INTO Technology VALUES('TechEmbodied','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('TechEndOfLife','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -CREATE TABLE OutputCost + FOREIGN KEY (flag) REFERENCES technologyType (label) +); +INSERT INTO technology VALUES('TechAnnual','p','energy',NULL,NULL,0,1,0,0,0,0,0,0,NULL); +INSERT INTO technology VALUES('TechFlex','p','energy',NULL,NULL,0,0,0,0,0,1,0,0,NULL); +INSERT INTO technology VALUES('TechOrdinary','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO technology VALUES('TechCurtailment','p','energy',NULL,NULL,0,0,0,1,0,0,0,0,NULL); +INSERT INTO technology VALUES('TechFlexNull','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO technology VALUES('TechAnnualFlex','p','energy',NULL,NULL,0,1,0,0,0,1,0,0,NULL); +INSERT INTO technology VALUES('TechEmbodied','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO technology VALUES('TechEndOfLife','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +CREATE TABLE output_cost ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), d_invest REAL, d_fixed REAL, d_var REAL, @@ -1097,7 +1097,7 @@ CREATE TABLE OutputCost var REAL, emiss REAL, PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) ); COMMIT; diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index 596efc87c..6303a3f4d 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -1,16 +1,16 @@ PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE MetaData +CREATE TABLE metadata ( element TEXT, value INT, notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); -CREATE TABLE MetaDataReal +INSERT INTO metadata VALUES('DB_MAJOR',3,'DB major version number'); +INSERT INTO metadata VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO metadata VALUES ('days_per_period', 365, 'count of days in each period'); +CREATE TABLE metadata_real ( element TEXT, value REAL, @@ -18,9 +18,9 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,'Discount Rate for future costs'); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); -CREATE TABLE OutputDualVariable +INSERT INTO metadata_real VALUES('global_discount_rate',0.05000000000000000277,'Discount Rate for future costs'); +INSERT INTO metadata_real VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); +CREATE TABLE output_dual_variable ( scenario TEXT, constraint_name TEXT, @@ -51,9 +51,9 @@ CREATE TABLE capacity_credit ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, credit REAL, notes TEXT, @@ -64,13 +64,13 @@ CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -81,213 +81,213 @@ CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2000,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2000,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2000,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2000,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2000,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2000,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2000,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2000,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2000,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2000,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2000,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2000,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2000,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2000,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2000,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2000,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2010,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2010,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2010,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2010,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2010,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2010,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2010,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2010,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2010,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2010,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2010,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2010,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2010,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2010,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2010,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2010,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2020,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2020,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2020,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2020,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2020,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2020,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2020,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2020,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2020,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2020,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2020,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2020,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2020,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2020,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2020,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionA',2020,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2000,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2000,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2000,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2000,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2000,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2000,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2000,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2000,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2000,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2000,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2000,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2000,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2000,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2000,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2000,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2000,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2010,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2010,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2010,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2010,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2010,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2010,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2010,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2010,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2010,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2010,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2010,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2010,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2010,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2010,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2010,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2010,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2020,'summer','morning','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2020,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2020,'winter','morning','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2020,'spring','morning','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2020,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2020,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2020,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2020,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2020,'summer','evening','SOL_PV',0.1000000000000000055,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2020,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2020,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2020,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2020,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2020,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2020,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO capacity_factor_tech VALUES('regionB',2020,'spring','overnight','SOL_PV',0.0,NULL); CREATE TABLE CapacityToActivity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), c2a REAL, notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE Commodity +CREATE TABLE commodity ( name TEXT PRIMARY KEY, flag TEXT - REFERENCES CommodityType (label), + REFERENCES commodityType (label), description TEXT ); -INSERT INTO Commodity VALUES('ethos','s','import dummy source'); -INSERT INTO Commodity VALUES('electricity','p','grid electricity'); -INSERT INTO Commodity VALUES('passenger_km','d','demand for passenger km'); -INSERT INTO Commodity VALUES('battery_nmc','a','battery - lithium nickel manganese cobalt oxide'); -INSERT INTO Commodity VALUES('battery_lfp','a','battery - lithium iron phosphate'); -INSERT INTO Commodity VALUES('lithium','a','lithium'); -INSERT INTO Commodity VALUES('cobalt','a','cobalt'); -INSERT INTO Commodity VALUES('phosphorous','a','phosphorous'); -INSERT INTO Commodity VALUES('diesel','a','diesel'); -INSERT INTO Commodity VALUES('heating','d','demand for residential heating'); -INSERT INTO Commodity VALUES('nickel','a','nickel'); -INSERT INTO Commodity VALUES('used_batt_nmc','wa','used battery - lithium nickel manganese cobalt oxide'); -INSERT INTO Commodity VALUES('used_batt_lfp','wa','used battery - lithium iron phosphate'); -INSERT INTO Commodity VALUES('co2e','e','emitted co2-equivalent GHGs'); -INSERT INTO Commodity VALUES('waste_steel','w','waste steel from cars'); -CREATE TABLE CommodityType +INSERT INTO commodity VALUES('ethos','s','import dummy source'); +INSERT INTO commodity VALUES('electricity','p','grid electricity'); +INSERT INTO commodity VALUES('passenger_km','d','demand for passenger km'); +INSERT INTO commodity VALUES('battery_nmc','a','battery - lithium nickel manganese cobalt oxide'); +INSERT INTO commodity VALUES('battery_lfp','a','battery - lithium iron phosphate'); +INSERT INTO commodity VALUES('lithium','a','lithium'); +INSERT INTO commodity VALUES('cobalt','a','cobalt'); +INSERT INTO commodity VALUES('phosphorous','a','phosphorous'); +INSERT INTO commodity VALUES('diesel','a','diesel'); +INSERT INTO commodity VALUES('heating','d','demand for residential heating'); +INSERT INTO commodity VALUES('nickel','a','nickel'); +INSERT INTO commodity VALUES('used_batt_nmc','wa','used battery - lithium nickel manganese cobalt oxide'); +INSERT INTO commodity VALUES('used_batt_lfp','wa','used battery - lithium iron phosphate'); +INSERT INTO commodity VALUES('co2e','e','emitted co2-equivalent GHGs'); +INSERT INTO commodity VALUES('waste_steel','w','waste steel from cars'); +CREATE TABLE commodityType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO CommodityType VALUES('w','waste commodity'); -INSERT INTO CommodityType VALUES('wa','waste annual commodity'); -INSERT INTO CommodityType VALUES('wp','waste physical commodity'); -INSERT INTO CommodityType VALUES('a','annual commodity'); -INSERT INTO CommodityType VALUES('p','physical commodity'); -INSERT INTO CommodityType VALUES('e','emissions commodity'); -INSERT INTO CommodityType VALUES('d','demand commodity'); -INSERT INTO CommodityType VALUES('s','source commodity'); +INSERT INTO commodityType VALUES('w','waste commodity'); +INSERT INTO commodityType VALUES('wa','waste annual commodity'); +INSERT INTO commodityType VALUES('wp','waste physical commodity'); +INSERT INTO commodityType VALUES('a','annual commodity'); +INSERT INTO commodityType VALUES('p','physical commodity'); +INSERT INTO commodityType VALUES('e','emissions commodity'); +INSERT INTO commodityType VALUES('d','demand commodity'); +INSERT INTO commodityType VALUES('s','source commodity'); CREATE TABLE construction_input ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -INSERT INTO construction_input VALUES('RegionA','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO construction_input VALUES('RegionA','battery_lfp','CAR_PHEV',2000,0.1000000000000000055,NULL,NULL); -INSERT INTO construction_input VALUES('RegionA','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO construction_input VALUES('RegionA','battery_lfp','CAR_PHEV',2010,0.1000000000000000055,NULL,NULL); -INSERT INTO construction_input VALUES('RegionA','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO construction_input VALUES('RegionA','battery_lfp','CAR_PHEV',2020,0.1000000000000000055,NULL,NULL); -INSERT INTO construction_input VALUES('RegionB','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO construction_input VALUES('RegionB','battery_lfp','CAR_PHEV',2000,0.1000000000000000055,NULL,NULL); -INSERT INTO construction_input VALUES('RegionB','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO construction_input VALUES('RegionB','battery_lfp','CAR_PHEV',2010,0.1000000000000000055,NULL,NULL); -INSERT INTO construction_input VALUES('RegionB','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO construction_input VALUES('RegionB','battery_lfp','CAR_PHEV',2020,0.1000000000000000055,NULL,NULL); +INSERT INTO construction_input VALUES('regionA','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO construction_input VALUES('regionA','battery_lfp','CAR_PHEV',2000,0.1000000000000000055,NULL,NULL); +INSERT INTO construction_input VALUES('regionA','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO construction_input VALUES('regionA','battery_lfp','CAR_PHEV',2010,0.1000000000000000055,NULL,NULL); +INSERT INTO construction_input VALUES('regionA','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO construction_input VALUES('regionA','battery_lfp','CAR_PHEV',2020,0.1000000000000000055,NULL,NULL); +INSERT INTO construction_input VALUES('regionB','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO construction_input VALUES('regionB','battery_lfp','CAR_PHEV',2000,0.1000000000000000055,NULL,NULL); +INSERT INTO construction_input VALUES('regionB','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO construction_input VALUES('regionB','battery_lfp','CAR_PHEV',2010,0.1000000000000000055,NULL,NULL); +INSERT INTO construction_input VALUES('regionB','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO construction_input VALUES('regionB','battery_lfp','CAR_PHEV',2020,0.1000000000000000055,NULL,NULL); CREATE TABLE cost_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT NOT NULL - REFERENCES Commodity (name), + REFERENCES commodity (name), cost REAL NOT NULL, units TEXT, notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -INSERT INTO cost_emission VALUES('RegionA',2000,'co2e',1.0,NULL,NULL); -INSERT INTO cost_emission VALUES('RegionA',2010,'co2e',1.0,NULL,NULL); -INSERT INTO cost_emission VALUES('RegionA',2020,'co2e',1.0,NULL,NULL); -INSERT INTO cost_emission VALUES('RegionB',2000,'co2e',1.0,NULL,NULL); -INSERT INTO cost_emission VALUES('RegionB',2010,'co2e',1.0,NULL,NULL); -INSERT INTO cost_emission VALUES('RegionB',2020,'co2e',1.0,NULL,NULL); +INSERT INTO cost_emission VALUES('regionA',2000,'co2e',1.0,NULL,NULL); +INSERT INTO cost_emission VALUES('regionA',2010,'co2e',1.0,NULL,NULL); +INSERT INTO cost_emission VALUES('regionA',2020,'co2e',1.0,NULL,NULL); +INSERT INTO cost_emission VALUES('regionB',2000,'co2e',1.0,NULL,NULL); +INSERT INTO cost_emission VALUES('regionB',2010,'co2e',1.0,NULL,NULL); +INSERT INTO cost_emission VALUES('regionB',2020,'co2e',1.0,NULL,NULL); CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -297,389 +297,389 @@ CREATE TABLE cost_invest ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO cost_invest VALUES('RegionA','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','CAR_PHEV',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','CAR_PHEV',2010,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','CAR_PHEV',2020,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','CAR_ICE',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','CAR_ICE',2010,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','CAR_ICE',2020,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','RECYCLE_NMC',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','RECYCLE_LFP',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','MANUFAC_NMC',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','MANUFAC_LFP',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','BATT_GRID',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','SOL_PV',2000,10.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','GEN_DSL',2000,2.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','CAR_PHEV',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','CAR_PHEV',2010,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','CAR_PHEV',2020,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','CAR_ICE',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','CAR_ICE',2010,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','CAR_ICE',2020,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','RECYCLE_NMC',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','RECYCLE_LFP',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','MANUFAC_NMC',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','MANUFAC_LFP',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','BATT_GRID',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','GEN_DSL',2000,2.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA-RegionB','ELEC_INTERTIE',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB-RegionA','ELEC_INTERTIE',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','SOL_PV',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionA','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionA','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionA','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionA','CAR_PHEV',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionA','CAR_PHEV',2010,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionA','CAR_PHEV',2020,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionA','CAR_ICE',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionA','CAR_ICE',2010,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionA','CAR_ICE',2020,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionA','RECYCLE_NMC',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionA','RECYCLE_LFP',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionA','MANUFAC_NMC',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionA','MANUFAC_LFP',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionA','BATT_GRID',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionA','SOL_PV',2000,10.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionA','GEN_DSL',2000,2.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionB','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionB','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionB','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionB','CAR_PHEV',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionB','CAR_PHEV',2010,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionB','CAR_PHEV',2020,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionB','CAR_ICE',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionB','CAR_ICE',2010,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionB','CAR_ICE',2020,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionB','RECYCLE_NMC',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionB','RECYCLE_LFP',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionB','MANUFAC_NMC',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionB','MANUFAC_LFP',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionB','BATT_GRID',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionB','GEN_DSL',2000,2.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionA-regionB','ELEC_INTERTIE',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionB-regionA','ELEC_INTERTIE',2000,1.0,NULL,NULL); +INSERT INTO cost_invest VALUES('regionB','SOL_PV',2000,1.0,NULL,NULL); CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_variable VALUES('RegionA',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2000,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2010,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2020,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2000,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2010,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2020,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2000,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2010,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2020,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2000,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2010,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2020,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2000,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2010,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2020,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2000,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2010,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2020,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2000,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2010,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2020,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2000,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2010,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2020,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); -CREATE TABLE Demand +INSERT INTO cost_variable VALUES('regionA',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionA',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionA',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionA',2000,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionA',2010,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionA',2020,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionA',2000,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionA',2010,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionA',2020,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionA',2000,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionA',2010,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionA',2020,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionA',2000,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionA',2010,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionA',2020,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionA',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO cost_variable VALUES('regionA',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO cost_variable VALUES('regionA',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO cost_variable VALUES('regionB',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionB',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionB',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionB',2000,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionB',2010,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionB',2020,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionB',2000,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionB',2010,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionB',2020,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionB',2000,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionB',2010,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionB',2020,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionB',2000,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionB',2010,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionB',2020,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO cost_variable VALUES('regionB',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO cost_variable VALUES('regionB',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO cost_variable VALUES('regionB',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); +CREATE TABLE demand ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), commodity TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), demand REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO Demand VALUES('RegionA',2000,'passenger_km',1.0,NULL,NULL); -INSERT INTO Demand VALUES('RegionA',2010,'passenger_km',1.0,NULL,NULL); -INSERT INTO Demand VALUES('RegionA',2020,'passenger_km',1.0,NULL,NULL); -INSERT INTO Demand VALUES('RegionA',2000,'heating',1.0,NULL,NULL); -INSERT INTO Demand VALUES('RegionA',2010,'heating',1.0,NULL,NULL); -INSERT INTO Demand VALUES('RegionA',2020,'heating',1.0,NULL,NULL); -INSERT INTO Demand VALUES('RegionB',2000,'passenger_km',1.0,NULL,NULL); -INSERT INTO Demand VALUES('RegionB',2010,'passenger_km',1.0,NULL,NULL); -INSERT INTO Demand VALUES('RegionB',2020,'passenger_km',1.0,NULL,NULL); -INSERT INTO Demand VALUES('RegionB',2000,'heating',1.0,NULL,NULL); -INSERT INTO Demand VALUES('RegionB',2010,'heating',1.0,NULL,NULL); -INSERT INTO Demand VALUES('RegionB',2020,'heating',1.0,NULL,NULL); -CREATE TABLE DemandSpecificDistribution +INSERT INTO demand VALUES('regionA',2000,'passenger_km',1.0,NULL,NULL); +INSERT INTO demand VALUES('regionA',2010,'passenger_km',1.0,NULL,NULL); +INSERT INTO demand VALUES('regionA',2020,'passenger_km',1.0,NULL,NULL); +INSERT INTO demand VALUES('regionA',2000,'heating',1.0,NULL,NULL); +INSERT INTO demand VALUES('regionA',2010,'heating',1.0,NULL,NULL); +INSERT INTO demand VALUES('regionA',2020,'heating',1.0,NULL,NULL); +INSERT INTO demand VALUES('regionB',2000,'passenger_km',1.0,NULL,NULL); +INSERT INTO demand VALUES('regionB',2010,'passenger_km',1.0,NULL,NULL); +INSERT INTO demand VALUES('regionB',2020,'passenger_km',1.0,NULL,NULL); +INSERT INTO demand VALUES('regionB',2000,'heating',1.0,NULL,NULL); +INSERT INTO demand VALUES('regionB',2010,'heating',1.0,NULL,NULL); +INSERT INTO demand VALUES('regionB',2020,'heating',1.0,NULL,NULL); +CREATE TABLE demand_specific_distributionon ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), dsd REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'summer','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','morning','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','morning','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'spring','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'summer','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','afternoon','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','afternoon','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'spring','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'summer','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','evening','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','evening','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'spring','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'summer','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','overnight','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','overnight','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'spring','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'summer','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','morning','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','morning','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'spring','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'summer','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','afternoon','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','afternoon','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'spring','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'summer','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','evening','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','evening','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'spring','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'summer','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','overnight','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','overnight','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'spring','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'summer','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','morning','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','morning','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'spring','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'summer','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','afternoon','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','afternoon','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'spring','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'summer','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','evening','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','evening','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'spring','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'summer','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','overnight','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','overnight','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'spring','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'summer','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','morning','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','morning','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'spring','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'summer','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','afternoon','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','afternoon','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'spring','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'summer','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','evening','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','evening','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'spring','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'summer','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','overnight','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','overnight','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'spring','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'summer','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','morning','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','morning','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'spring','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'summer','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','afternoon','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','afternoon','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'spring','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'summer','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','evening','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','evening','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'spring','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'summer','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','overnight','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','overnight','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'spring','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'summer','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','morning','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','morning','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'spring','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'summer','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','afternoon','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','afternoon','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'spring','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'summer','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','evening','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','evening','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'spring','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'summer','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','overnight','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','overnight','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'spring','overnight','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'summer','morning','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'autumn','morning','heating',0.1199999999999999956,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'winter','morning','heating',0.1600000000000000033,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'spring','morning','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'summer','afternoon','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'autumn','afternoon','heating',0.08000000000000000166,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'winter','afternoon','heating',0.1199999999999999956,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'spring','afternoon','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'summer','evening','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'autumn','evening','heating',0.08000000000000000166,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'winter','evening','heating',0.1600000000000000033,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'spring','evening','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'summer','overnight','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'autumn','overnight','heating',0.1199999999999999956,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'winter','overnight','heating',0.1600000000000000033,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'spring','overnight','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'summer','morning','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'autumn','morning','heating',0.1199999999999999956,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'winter','morning','heating',0.1600000000000000033,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'spring','morning','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'summer','afternoon','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'autumn','afternoon','heating',0.08000000000000000166,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'winter','afternoon','heating',0.1199999999999999956,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'spring','afternoon','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'summer','evening','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'autumn','evening','heating',0.08000000000000000166,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'winter','evening','heating',0.1600000000000000033,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'spring','evening','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'summer','overnight','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'autumn','overnight','heating',0.1199999999999999956,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'winter','overnight','heating',0.1600000000000000033,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'spring','overnight','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'summer','morning','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'autumn','morning','heating',0.1199999999999999956,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'winter','morning','heating',0.1600000000000000033,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'spring','morning','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'summer','afternoon','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'autumn','afternoon','heating',0.08000000000000000166,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'winter','afternoon','heating',0.1199999999999999956,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'spring','afternoon','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'summer','evening','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'autumn','evening','heating',0.08000000000000000166,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'winter','evening','heating',0.1600000000000000033,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'spring','evening','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'summer','overnight','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'autumn','overnight','heating',0.1199999999999999956,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'winter','overnight','heating',0.1600000000000000033,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'spring','overnight','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'summer','morning','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'autumn','morning','heating',0.1199999999999999956,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'winter','morning','heating',0.1600000000000000033,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'spring','morning','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'summer','afternoon','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'autumn','afternoon','heating',0.08000000000000000166,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'winter','afternoon','heating',0.1199999999999999956,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'spring','afternoon','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'summer','evening','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'autumn','evening','heating',0.08000000000000000166,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'winter','evening','heating',0.1600000000000000033,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'spring','evening','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'summer','overnight','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'autumn','overnight','heating',0.1199999999999999956,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'winter','overnight','heating',0.1600000000000000033,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'spring','overnight','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'summer','morning','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'autumn','morning','heating',0.1199999999999999956,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'winter','morning','heating',0.1600000000000000033,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'spring','morning','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'summer','afternoon','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'autumn','afternoon','heating',0.08000000000000000166,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'winter','afternoon','heating',0.1199999999999999956,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'spring','afternoon','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'summer','evening','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'autumn','evening','heating',0.08000000000000000166,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'winter','evening','heating',0.1600000000000000033,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'spring','evening','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'summer','overnight','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'autumn','overnight','heating',0.1199999999999999956,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'winter','overnight','heating',0.1600000000000000033,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'spring','overnight','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'summer','morning','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'autumn','morning','heating',0.1199999999999999956,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'winter','morning','heating',0.1600000000000000033,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'spring','morning','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'summer','afternoon','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'autumn','afternoon','heating',0.08000000000000000166,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'winter','afternoon','heating',0.1199999999999999956,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'spring','afternoon','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'summer','evening','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'autumn','evening','heating',0.08000000000000000166,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'winter','evening','heating',0.1600000000000000033,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'spring','evening','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'summer','overnight','heating',0.0,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'autumn','overnight','heating',0.1199999999999999956,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'winter','overnight','heating',0.1600000000000000033,NULL); +INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'spring','overnight','heating',0.0,NULL); CREATE TABLE end_of_life_output ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), value REAL, units TEXT, notes TEXT, PRIMARY KEY (region, tech, vintage, output_comm) ); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',1990,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',2000,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',2010,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',1990,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',2000,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',2010,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionA','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionA','CAR_PHEV',1990,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionA','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionA','CAR_PHEV',2000,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionA','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionA','CAR_PHEV',2010,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionB','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionB','CAR_PHEV',1990,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionB','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionB','CAR_PHEV',2000,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionB','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionB','CAR_PHEV',2010,'used_batt_lfp',0.1000000000000000055,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionA','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionA','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionA','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionA','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionA','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionA','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionA','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionA','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionA','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionB','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionB','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionB','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionB','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionB','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionB','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionB','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionB','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO end_of_life_output VALUES('regionB','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); CREATE TABLE efficiency ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO efficiency VALUES('RegionA','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2000000000000000111,NULL); -INSERT INTO efficiency VALUES('RegionA','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2000000000000000111,NULL); -INSERT INTO efficiency VALUES('RegionA','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','electricity','RECYCLE_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('RegionA','electricity','RECYCLE_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('RegionA','electricity','MANUFAC_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('RegionA','electricity','MANUFAC_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('RegionA','diesel','GEN_DSL',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','ethos','SOL_PV',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','electricity','BATT_GRID',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','diesel','FURNACE',2000,'heating',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','electricity','HEATPUMP',2000,'heating',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2000000000000000111,NULL); -INSERT INTO efficiency VALUES('RegionB','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2000000000000000111,NULL); -INSERT INTO efficiency VALUES('RegionB','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','electricity','RECYCLE_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('RegionB','electricity','RECYCLE_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('RegionB','electricity','MANUFAC_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('RegionB','electricity','MANUFAC_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('RegionB','diesel','GEN_DSL',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','ethos','SOL_PV',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','electricity','BATT_GRID',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','diesel','FURNACE',2000,'heating',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','electricity','HEATPUMP',2000,'heating',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA-RegionB','electricity','ELEC_INTERTIE',2000,'electricity',0.9000000000000000222,NULL); -INSERT INTO efficiency VALUES('RegionB-RegionA','electricity','ELEC_INTERTIE',2000,'electricity',0.9000000000000000222,NULL); +INSERT INTO efficiency VALUES('regionA','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2000000000000000111,NULL); +INSERT INTO efficiency VALUES('regionA','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2000000000000000111,NULL); +INSERT INTO efficiency VALUES('regionA','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','electricity','RECYCLE_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('regionA','electricity','RECYCLE_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('regionA','electricity','MANUFAC_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('regionA','electricity','MANUFAC_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('regionA','diesel','GEN_DSL',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','ethos','SOL_PV',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','electricity','BATT_GRID',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','diesel','FURNACE',2000,'heating',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','electricity','HEATPUMP',2000,'heating',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionA','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2000000000000000111,NULL); +INSERT INTO efficiency VALUES('regionB','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2000000000000000111,NULL); +INSERT INTO efficiency VALUES('regionB','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','electricity','RECYCLE_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('regionB','electricity','RECYCLE_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('regionB','electricity','MANUFAC_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('regionB','electricity','MANUFAC_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); +INSERT INTO efficiency VALUES('regionB','diesel','GEN_DSL',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','ethos','SOL_PV',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','electricity','BATT_GRID',2000,'electricity',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','diesel','FURNACE',2000,'heating',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','electricity','HEATPUMP',2000,'heating',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionB','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); +INSERT INTO efficiency VALUES('regionA-regionB','electricity','ELEC_INTERTIE',2000,'electricity',0.9000000000000000222,NULL); +INSERT INTO efficiency VALUES('regionB-regionA','electricity','ELEC_INTERTIE',2000,'electricity',0.9000000000000000222,NULL); CREATE TABLE efficiency_variable ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), @@ -689,31 +689,31 @@ CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), activity REAL, units TEXT, notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO emission_activity VALUES('RegionA','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); -INSERT INTO emission_activity VALUES('RegionB','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); +INSERT INTO emission_activity VALUES('regionA','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); +INSERT INTO emission_activity VALUES('regionB','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -723,11 +723,11 @@ CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -737,20 +737,20 @@ CREATE TABLE existing_capacity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, units TEXT, notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO existing_capacity VALUES('RegionA','CAR_BEV',1990,1.0,NULL,NULL); -INSERT INTO existing_capacity VALUES('RegionA','CAR_PHEV',1990,1.0,NULL,NULL); -INSERT INTO existing_capacity VALUES('RegionA','CAR_ICE',1990,1.0,NULL,NULL); -INSERT INTO existing_capacity VALUES('RegionB','CAR_BEV',1990,1.0,NULL,NULL); -INSERT INTO existing_capacity VALUES('RegionB','CAR_PHEV',1990,1.0,NULL,NULL); -INSERT INTO existing_capacity VALUES('RegionB','CAR_ICE',1990,1.0,NULL,NULL); +INSERT INTO existing_capacity VALUES('regionA','CAR_BEV',1990,1.0,NULL,NULL); +INSERT INTO existing_capacity VALUES('regionA','CAR_PHEV',1990,1.0,NULL,NULL); +INSERT INTO existing_capacity VALUES('regionA','CAR_ICE',1990,1.0,NULL,NULL); +INSERT INTO existing_capacity VALUES('regionB','CAR_BEV',1990,1.0,NULL,NULL); +INSERT INTO existing_capacity VALUES('regionB','CAR_PHEV',1990,1.0,NULL,NULL); +INSERT INTO existing_capacity VALUES('regionB','CAR_ICE',1990,1.0,NULL,NULL); CREATE TABLE TechGroup ( group_name TEXT @@ -761,9 +761,9 @@ CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -772,9 +772,9 @@ CREATE TABLE loan_rate ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), rate REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -783,9 +783,9 @@ CREATE TABLE lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -794,17 +794,17 @@ CREATE TABLE lifetime_tech ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO lifetime_tech VALUES('RegionA','CAR_BEV',10.0,NULL); -INSERT INTO lifetime_tech VALUES('RegionA','CAR_PHEV',10.0,NULL); -INSERT INTO lifetime_tech VALUES('RegionA','CAR_ICE',10.0,NULL); -INSERT INTO lifetime_tech VALUES('RegionB','CAR_BEV',10.0,NULL); -INSERT INTO lifetime_tech VALUES('RegionB','CAR_PHEV',10.0,NULL); -INSERT INTO lifetime_tech VALUES('RegionB','CAR_ICE',10.0,NULL); +INSERT INTO lifetime_tech VALUES('regionA','CAR_BEV',10.0,NULL); +INSERT INTO lifetime_tech VALUES('regionA','CAR_PHEV',10.0,NULL); +INSERT INTO lifetime_tech VALUES('regionA','CAR_ICE',10.0,NULL); +INSERT INTO lifetime_tech VALUES('regionB','CAR_BEV',10.0,NULL); +INSERT INTO lifetime_tech VALUES('regionB','CAR_PHEV',10.0,NULL); +INSERT INTO lifetime_tech VALUES('regionB','CAR_ICE',10.0,NULL); CREATE TABLE Operator ( operator TEXT PRIMARY KEY, @@ -889,15 +889,15 @@ CREATE TABLE LimitStorageLevelFraction ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), fraction REAL, @@ -908,7 +908,7 @@ CREATE TABLE limit_activity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -921,7 +921,7 @@ CREATE TABLE limit_activity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -934,11 +934,11 @@ CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, @@ -950,7 +950,7 @@ CREATE TABLE limit_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -963,7 +963,7 @@ CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -976,7 +976,7 @@ CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -989,7 +989,7 @@ CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -1012,13 +1012,13 @@ CREATE TABLE limit_resource CREATE TABLE limit_seasonal_capacity_factor ( region TEXT - REFERENCES Region (region), + REFERENCES region (region), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, @@ -1029,11 +1029,11 @@ CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -1044,80 +1044,80 @@ CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'diesel','CAR_PHEV','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'diesel','CAR_PHEV','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'diesel','CAR_PHEV','le',0.8000000000000000444,NULL); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'diesel','CAR_PHEV','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'diesel','CAR_PHEV','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'diesel','CAR_PHEV','le',0.8000000000000000444,NULL); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2000,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2000,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2000,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2000,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2000,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2000,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2000,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2010,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2010,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2010,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2010,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2010,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2010,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2010,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2020,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2020,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2020,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2020,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2020,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2020,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2020,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2000,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2000,'diesel','CAR_PHEV','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2010,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2010,'diesel','CAR_PHEV','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2020,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionA',2020,'diesel','CAR_PHEV','le',0.8000000000000000444,NULL); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2000,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2000,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2000,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2000,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2000,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2000,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2000,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2010,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2010,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2010,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2010,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2010,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2010,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2010,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2020,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2020,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2020,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2020,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2020,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2020,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2020,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2000,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2000,'diesel','CAR_PHEV','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2010,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2010,'diesel','CAR_PHEV','le',0.8000000000000000444,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2020,'electricity','CAR_PHEV','le',0.2000000000000000111,''); +INSERT INTO limit_tech_input_split_annual VALUES('regionB',2020,'diesel','CAR_PHEV','le',0.8000000000000000444,NULL); CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -1128,11 +1128,11 @@ CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -1143,9 +1143,9 @@ CREATE TABLE limit_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), value REAL, @@ -1157,33 +1157,33 @@ CREATE TABLE LinkedTech ( primary_region TEXT, primary_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), driven_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); -CREATE TABLE OutputCurtailment +CREATE TABLE output_curtailment ( scenario TEXT, region TEXT, sector TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), curtailment REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); @@ -1194,24 +1194,24 @@ CREATE TABLE OutputNetCapacity sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE output_built_capacity ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, tech, vintage) ); @@ -1222,11 +1222,11 @@ CREATE TABLE OutputRetiredCapacity sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cap_eol REAL, cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) @@ -1238,19 +1238,19 @@ CREATE TABLE OutputFlowIn sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); @@ -1261,38 +1261,38 @@ CREATE TABLE OutputFlowOut sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputStorageLevel +CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); @@ -1300,7 +1300,7 @@ CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY - REFERENCES Region (region), + REFERENCES region (region), margin REAL, notes TEXT ); @@ -1308,7 +1308,7 @@ CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -1317,28 +1317,28 @@ CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE Region +CREATE TABLE region ( region TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO Region VALUES('RegionA',NULL); -INSERT INTO Region VALUES('RegionB',NULL); +INSERT INTO region VALUES('regionA',NULL); +INSERT INTO region VALUES('regionB',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -1348,7 +1348,7 @@ CREATE TABLE reserve_capacity_derate CREATE TABLE TimeSegmentFraction ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT @@ -1414,29 +1414,29 @@ CREATE TABLE storage_duration notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO storage_duration VALUES('RegionA','BATT_GRID',2.0,'2 hours energy storage'); -INSERT INTO storage_duration VALUES('RegionB','BATT_GRID',2.0,'2 hours energy storage'); +INSERT INTO storage_duration VALUES('regionA','BATT_GRID',2.0,'2 hours energy storage'); +INSERT INTO storage_duration VALUES('regionB','BATT_GRID',2.0,'2 hours energy storage'); CREATE TABLE lifetime_survival_curve ( region TEXT NOT NULL, period INTEGER NOT NULL, tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), fraction REAL, notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE TechnologyType +CREATE TABLE technologyType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('p','production technology'); -INSERT INTO TechnologyType VALUES('pb','baseload production technology'); -INSERT INTO TechnologyType VALUES('ps','storage production technology'); +INSERT INTO technologyType VALUES('p','production technology'); +INSERT INTO technologyType VALUES('pb','baseload production technology'); +INSERT INTO technologyType VALUES('ps','storage production technology'); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -1447,23 +1447,23 @@ INSERT INTO TimeOfDay VALUES(1,'morning'); INSERT INTO TimeOfDay VALUES(2,'afternoon'); INSERT INTO TimeOfDay VALUES(3,'evening'); INSERT INTO TimeOfDay VALUES(4,'overnight'); -CREATE TABLE TimePeriod +CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES TimePeriodType (label) + REFERENCES time_periodType (label) ); -INSERT INTO TimePeriod VALUES(1,1990,'e'); -INSERT INTO TimePeriod VALUES(2,2000,'f'); -INSERT INTO TimePeriod VALUES(3,2010,'f'); -INSERT INTO TimePeriod VALUES(4,2020,'f'); -INSERT INTO TimePeriod VALUES(5,2030,'f'); +INSERT INTO time_period VALUES(1,1990,'e'); +INSERT INTO time_period VALUES(2,2000,'f'); +INSERT INTO time_period VALUES(3,2010,'f'); +INSERT INTO time_period VALUES(4,2020,'f'); +INSERT INTO time_period VALUES(5,2030,'f'); CREATE TABLE TimeSeason ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, season TEXT REFERENCES SeasonLabel (season), @@ -1485,7 +1485,7 @@ INSERT INTO TimeSeason VALUES(2020,12,'spring',NULL); CREATE TABLE time_season_sequential ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, season TEXT @@ -1495,14 +1495,14 @@ CREATE TABLE time_season_sequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE TimePeriodType +CREATE TABLE time_periodType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TimePeriodType VALUES('e','existing vintages'); -INSERT INTO TimePeriodType VALUES('f','future'); +INSERT INTO time_periodType VALUES('e','existing vintages'); +INSERT INTO time_periodType VALUES('f','future'); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1510,22 +1510,22 @@ CREATE TABLE OutputEmission sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); CREATE TABLE RPSRequirement ( region TEXT NOT NULL - REFERENCES Region (region), + REFERENCES region (region), period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_group TEXT NOT NULL REFERENCES TechGroup (group_name), requirement REAL NOT NULL, @@ -1536,10 +1536,10 @@ CREATE TABLE TechGroupMember group_name TEXT REFERENCES TechGroup (group_name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), PRIMARY KEY (group_name, tech) ); -CREATE TABLE Technology +CREATE TABLE technology ( tech TEXT NOT NULL PRIMARY KEY, flag TEXT NOT NULL, @@ -1555,35 +1555,35 @@ CREATE TABLE Technology exchange INTEGER NOT NULL DEFAULT 0, seas_stor INTEGER NOT NULL DEFAULT 0, description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) -); -INSERT INTO Technology VALUES('IMPORT_LI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'lithium importer'); -INSERT INTO Technology VALUES('IMPORT_CO','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'cobalt importer'); -INSERT INTO Technology VALUES('IMPORT_P','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'phosphorous importer'); -INSERT INTO Technology VALUES('CAR_BEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - battery electric'); -INSERT INTO Technology VALUES('CAR_PHEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - plug in hybrid'); -INSERT INTO Technology VALUES('CAR_ICE','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - internal combustion'); -INSERT INTO Technology VALUES('RECYCLE_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'nmc battery recycler'); -INSERT INTO Technology VALUES('RECYCLE_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'lfp battery recycler'); -INSERT INTO Technology VALUES('MANUFAC_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'nmc battery manufacturing'); -INSERT INTO Technology VALUES('MANUFAC_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'lfp battery manufacturing'); -INSERT INTO Technology VALUES('IMPORT_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'nickel importer'); -INSERT INTO Technology VALUES('DOMESTIC_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'domestic nickel production'); -INSERT INTO Technology VALUES('GEN_DSL','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,'diesel generators'); -INSERT INTO Technology VALUES('SOL_PV','p','electricity',NULL,NULL,0,0,0,1,0,0,0,0,'solar panels'); -INSERT INTO Technology VALUES('BATT_GRID','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,0,'grid battery storage'); -INSERT INTO Technology VALUES('FURNACE','p','residential',NULL,NULL,1,0,0,0,0,0,0,0,'diesel furnace heater'); -INSERT INTO Technology VALUES('HEATPUMP','p','residential',NULL,NULL,1,0,0,0,0,0,0,0,'heat pump'); -INSERT INTO Technology VALUES('IMPORT_DSL','p','fuels',NULL,NULL,1,1,0,0,0,0,0,0,'diesel importer'); -INSERT INTO Technology VALUES('ELEC_INTERTIE','p','electricity',NULL,NULL,0,0,0,0,0,0,1,0,'dummy tech to make landfill feasible'); -CREATE TABLE OutputCost + FOREIGN KEY (flag) REFERENCES technologyType (label) +); +INSERT INTO technology VALUES('IMPORT_LI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'lithium importer'); +INSERT INTO technology VALUES('IMPORT_CO','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'cobalt importer'); +INSERT INTO technology VALUES('IMPORT_P','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'phosphorous importer'); +INSERT INTO technology VALUES('CAR_BEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - battery electric'); +INSERT INTO technology VALUES('CAR_PHEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - plug in hybrid'); +INSERT INTO technology VALUES('CAR_ICE','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - internal combustion'); +INSERT INTO technology VALUES('RECYCLE_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'nmc battery recycler'); +INSERT INTO technology VALUES('RECYCLE_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'lfp battery recycler'); +INSERT INTO technology VALUES('MANUFAC_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'nmc battery manufacturing'); +INSERT INTO technology VALUES('MANUFAC_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'lfp battery manufacturing'); +INSERT INTO technology VALUES('IMPORT_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'nickel importer'); +INSERT INTO technology VALUES('DOMESTIC_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'domestic nickel production'); +INSERT INTO technology VALUES('GEN_DSL','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,'diesel generators'); +INSERT INTO technology VALUES('SOL_PV','p','electricity',NULL,NULL,0,0,0,1,0,0,0,0,'solar panels'); +INSERT INTO technology VALUES('BATT_GRID','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,0,'grid battery storage'); +INSERT INTO technology VALUES('FURNACE','p','residential',NULL,NULL,1,0,0,0,0,0,0,0,'diesel furnace heater'); +INSERT INTO technology VALUES('HEATPUMP','p','residential',NULL,NULL,1,0,0,0,0,0,0,0,'heat pump'); +INSERT INTO technology VALUES('IMPORT_DSL','p','fuels',NULL,NULL,1,1,0,0,0,0,0,0,'diesel importer'); +INSERT INTO technology VALUES('ELEC_INTERTIE','p','electricity',NULL,NULL,0,0,0,0,0,0,1,0,'dummy tech to make landfill feasible'); +CREATE TABLE output_cost ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), d_invest REAL, d_fixed REAL, d_var REAL, @@ -1593,7 +1593,7 @@ CREATE TABLE OutputCost var REAL, emiss REAL, PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) ); COMMIT; diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index a0f587022..b47c30171 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -1,16 +1,16 @@ PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE MetaData +CREATE TABLE metadata ( element TEXT, value INT, notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); -CREATE TABLE MetaDataReal +INSERT INTO metadata VALUES('DB_MAJOR',3,'DB major version number'); +INSERT INTO metadata VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO metadata VALUES ('days_per_period', 365, 'count of days in each period'); +CREATE TABLE metadata_real ( element TEXT, value REAL, @@ -18,9 +18,9 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.42000000000000004,''); -CREATE TABLE OutputDualVariable +INSERT INTO metadata_real VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); +INSERT INTO metadata_real VALUES('global_discount_rate',0.42000000000000004,''); +CREATE TABLE output_dual_variable ( scenario TEXT, constraint_name TEXT, @@ -55,9 +55,9 @@ CREATE TABLE capacity_credit ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, credit REAL, notes TEXT, @@ -69,13 +69,13 @@ CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -88,13 +88,13 @@ CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, tech), @@ -106,53 +106,53 @@ CREATE TABLE CapacityToActivity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), c2a REAL, notes TEXT, PRIMARY KEY (region, tech) ); INSERT INTO CapacityToActivity VALUES('A','bulbs',1.0,''); INSERT INTO CapacityToActivity VALUES('B','bulbs',1.0,NULL); -CREATE TABLE Commodity +CREATE TABLE commodity ( name TEXT PRIMARY KEY, flag TEXT - REFERENCES CommodityType (label), + REFERENCES commodityType (label), description TEXT ); -INSERT INTO Commodity VALUES('ELC','p','electricity'); -INSERT INTO Commodity VALUES('HYD','p','water'); -INSERT INTO Commodity VALUES('co2','e','CO2 emissions'); -INSERT INTO Commodity VALUES('RL','d','residential lighting'); -INSERT INTO Commodity VALUES('earth','s','the source of stuff'); -INSERT INTO Commodity VALUES('RH','d','residential heat'); -INSERT INTO Commodity VALUES('FusionGas','e','mystery emission'); -INSERT INTO Commodity VALUES('FusionGasFuel','p','converted mystery gas to fuel'); -INSERT INTO Commodity VALUES('GeoHyd','p','Hot water from geo'); -CREATE TABLE CommodityType +INSERT INTO commodity VALUES('ELC','p','electricity'); +INSERT INTO commodity VALUES('HYD','p','water'); +INSERT INTO commodity VALUES('co2','e','CO2 emissions'); +INSERT INTO commodity VALUES('RL','d','residential lighting'); +INSERT INTO commodity VALUES('earth','s','the source of stuff'); +INSERT INTO commodity VALUES('RH','d','residential heat'); +INSERT INTO commodity VALUES('FusionGas','e','mystery emission'); +INSERT INTO commodity VALUES('FusionGasFuel','p','converted mystery gas to fuel'); +INSERT INTO commodity VALUES('GeoHyd','p','Hot water from geo'); +CREATE TABLE commodityType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO CommodityType VALUES('w','waste commodity'); -INSERT INTO CommodityType VALUES('wa','waste annual commodity'); -INSERT INTO CommodityType VALUES('wp','waste physical commodity'); -INSERT INTO CommodityType VALUES('a','annual commodity'); -INSERT INTO CommodityType VALUES('p','physical commodity'); -INSERT INTO CommodityType VALUES('e','emissions commodity'); -INSERT INTO CommodityType VALUES('d','demand commodity'); -INSERT INTO CommodityType VALUES('s','source commodity'); +INSERT INTO commodityType VALUES('w','waste commodity'); +INSERT INTO commodityType VALUES('wa','waste annual commodity'); +INSERT INTO commodityType VALUES('wp','waste physical commodity'); +INSERT INTO commodityType VALUES('a','annual commodity'); +INSERT INTO commodityType VALUES('p','physical commodity'); +INSERT INTO commodityType VALUES('e','emissions commodity'); +INSERT INTO commodityType VALUES('d','demand commodity'); +INSERT INTO commodityType VALUES('s','source commodity'); CREATE TABLE construction_input ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -162,9 +162,9 @@ CREATE TABLE cost_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT NOT NULL - REFERENCES Commodity (name), + REFERENCES commodity (name), cost REAL NOT NULL, units TEXT, notes TEXT, @@ -175,11 +175,11 @@ CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -203,9 +203,9 @@ CREATE TABLE cost_invest ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -229,11 +229,11 @@ CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -248,63 +248,63 @@ INSERT INTO cost_variable VALUES('B',2025,'EF',2025,4.0,NULL,NULL); INSERT INTO cost_variable VALUES('B',2025,'batt',2025,3.0,NULL,NULL); INSERT INTO cost_variable VALUES('B',2025,'bulbs',2025,2.0,NULL,NULL); INSERT INTO cost_variable VALUES('B',2025,'heater',2025,1.0,NULL,NULL); -CREATE TABLE Demand +CREATE TABLE demand ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), commodity TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), demand REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO Demand VALUES('A',2025,'RL',100.0,'',''); -INSERT INTO Demand VALUES('B',2025,'RL',100.0,NULL,NULL); -INSERT INTO Demand VALUES('A',2025,'RH',50.0,NULL,NULL); -INSERT INTO Demand VALUES('B',2025,'RH',50.0,NULL,NULL); -CREATE TABLE DemandSpecificDistribution +INSERT INTO demand VALUES('A',2025,'RL',100.0,'',''); +INSERT INTO demand VALUES('B',2025,'RL',100.0,NULL,NULL); +INSERT INTO demand VALUES('A',2025,'RH',50.0,NULL,NULL); +INSERT INTO demand VALUES('B',2025,'RH',50.0,NULL,NULL); +CREATE TABLE demand_specific_distribution ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), dsd REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('A',2025,'s1','d1','RL',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('A',2025,'s1','d2','RL',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('A',2025,'s2','d1','RL',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('A',2025,'s2','d2','RL',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('B',2025,'s1','d1','RL',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('B',2025,'s1','d2','RL',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('B',2025,'s2','d1','RL',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('B',2025,'s2','d2','RL',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('A',2025,'s1','d1','RH',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('A',2025,'s2','d1','RH',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('B',2025,'s1','d1','RH',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('B',2025,'s2','d1','RH',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('A',2025,'s1','d2','RH',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('A',2025,'s2','d2','RH',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('B',2025,'s1','d2','RH',0.25,NULL); -INSERT INTO DemandSpecificDistribution VALUES('B',2025,'s2','d2','RH',0.25,NULL); +INSERT INTO demand_specific_distribution VALUES('A',2025,'s1','d1','RL',0.25,NULL); +INSERT INTO demand_specific_distribution VALUES('A',2025,'s1','d2','RL',0.25,NULL); +INSERT INTO demand_specific_distribution VALUES('A',2025,'s2','d1','RL',0.25,NULL); +INSERT INTO demand_specific_distribution VALUES('A',2025,'s2','d2','RL',0.25,NULL); +INSERT INTO demand_specific_distribution VALUES('B',2025,'s1','d1','RL',0.25,NULL); +INSERT INTO demand_specific_distribution VALUES('B',2025,'s1','d2','RL',0.25,NULL); +INSERT INTO demand_specific_distribution VALUES('B',2025,'s2','d1','RL',0.25,NULL); +INSERT INTO demand_specific_distribution VALUES('B',2025,'s2','d2','RL',0.25,NULL); +INSERT INTO demand_specific_distribution VALUES('A',2025,'s1','d1','RH',0.25,NULL); +INSERT INTO demand_specific_distribution VALUES('A',2025,'s2','d1','RH',0.25,NULL); +INSERT INTO demand_specific_distribution VALUES('B',2025,'s1','d1','RH',0.25,NULL); +INSERT INTO demand_specific_distribution VALUES('B',2025,'s2','d1','RH',0.25,NULL); +INSERT INTO demand_specific_distribution VALUES('A',2025,'s1','d2','RH',0.25,NULL); +INSERT INTO demand_specific_distribution VALUES('A',2025,'s2','d2','RH',0.25,NULL); +INSERT INTO demand_specific_distribution VALUES('B',2025,'s1','d2','RH',0.25,NULL); +INSERT INTO demand_specific_distribution VALUES('B',2025,'s2','d2','RH',0.25,NULL); CREATE TABLE end_of_life_output ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), value REAL, units TEXT, notes TEXT, @@ -314,13 +314,13 @@ CREATE TABLE efficiency ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage, output_comm), @@ -348,19 +348,19 @@ CREATE TABLE efficiency_variable ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), @@ -370,15 +370,15 @@ CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), activity REAL, units TEXT, notes TEXT, @@ -390,11 +390,11 @@ CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -404,11 +404,11 @@ CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -418,9 +418,9 @@ CREATE TABLE existing_capacity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, units TEXT, notes TEXT, @@ -439,9 +439,9 @@ CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -468,9 +468,9 @@ CREATE TABLE loan_rate ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), rate REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -479,9 +479,9 @@ CREATE TABLE lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -491,7 +491,7 @@ CREATE TABLE lifetime_tech ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -582,15 +582,15 @@ CREATE TABLE LimitStorageLevelFraction ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), fraction REAL, @@ -601,7 +601,7 @@ CREATE TABLE limit_activity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -619,7 +619,7 @@ CREATE TABLE limit_activity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -632,11 +632,11 @@ CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, @@ -648,7 +648,7 @@ CREATE TABLE limit_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -667,7 +667,7 @@ CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -680,7 +680,7 @@ CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -693,7 +693,7 @@ CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -719,13 +719,13 @@ INSERT INTO limit_resource VALUES('B','EF','le',9000.0,'clumps',NULL); CREATE TABLE limit_seasonal_capacity_factor ( region TEXT - REFERENCES Region (region), + REFERENCES region (region), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, @@ -736,11 +736,11 @@ CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -752,11 +752,11 @@ CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -767,11 +767,11 @@ CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -783,11 +783,11 @@ CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -798,9 +798,9 @@ CREATE TABLE limit_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), value REAL, @@ -813,34 +813,34 @@ CREATE TABLE LinkedTech ( primary_region TEXT, primary_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), driven_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); INSERT INTO LinkedTech VALUES('A','EF','FusionGas','EFL',NULL); -CREATE TABLE OutputCurtailment +CREATE TABLE output_curtailment ( scenario TEXT, region TEXT, sector TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), curtailment REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); @@ -851,24 +851,24 @@ CREATE TABLE OutputNetCapacity sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE output_built_capacity ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, tech, vintage) ); @@ -879,11 +879,11 @@ CREATE TABLE OutputRetiredCapacity sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cap_eol REAL, cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) @@ -895,19 +895,19 @@ CREATE TABLE OutputFlowIn sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); @@ -918,38 +918,38 @@ CREATE TABLE OutputFlowOut sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputStorageLevel +CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); @@ -957,7 +957,7 @@ CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY - REFERENCES Region (region), + REFERENCES region (region), margin REAL, notes TEXT ); @@ -966,7 +966,7 @@ CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -977,30 +977,30 @@ CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) ); INSERT INTO ramp_up_hourly VALUES('B','EH',0.05000000000000000277,NULL); INSERT INTO ramp_up_hourly VALUES('A','EH',0.05000000000000000277,NULL); -CREATE TABLE Region +CREATE TABLE region ( region TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO Region VALUES('A','main region'); -INSERT INTO Region VALUES('B','just a 2nd region'); +INSERT INTO region VALUES('A','main region'); +INSERT INTO region VALUES('B','just a 2nd region'); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -1010,7 +1010,7 @@ CREATE TABLE reserve_capacity_derate CREATE TABLE TimeSegmentFraction ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT @@ -1038,22 +1038,22 @@ CREATE TABLE lifetime_survival_curve region TEXT NOT NULL, period INTEGER NOT NULL, tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), fraction REAL, notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE TechnologyType +CREATE TABLE technologyType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('p','production technology'); -INSERT INTO TechnologyType VALUES('pb','baseload production technology'); -INSERT INTO TechnologyType VALUES('ps','storage production technology'); +INSERT INTO technologyType VALUES('p','production technology'); +INSERT INTO technologyType VALUES('pb','baseload production technology'); +INSERT INTO technologyType VALUES('ps','storage production technology'); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -1062,21 +1062,21 @@ CREATE TABLE TimeOfDay ); INSERT INTO TimeOfDay VALUES(1,'d1'); INSERT INTO TimeOfDay VALUES(2,'d2'); -CREATE TABLE TimePeriod +CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES TimePeriodType (label) + REFERENCES time_periodType (label) ); -INSERT INTO TimePeriod VALUES(1,2020,'e'); -INSERT INTO TimePeriod VALUES(2,2025,'f'); -INSERT INTO TimePeriod VALUES(3,2030,'f'); +INSERT INTO time_period VALUES(1,2020,'e'); +INSERT INTO time_period VALUES(2,2025,'f'); +INSERT INTO time_period VALUES(3,2030,'f'); CREATE TABLE TimeSeason ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, season TEXT REFERENCES SeasonLabel (season), @@ -1088,7 +1088,7 @@ INSERT INTO TimeSeason VALUES(2025,2,'s2',NULL); CREATE TABLE time_season_sequential ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, season TEXT @@ -1098,14 +1098,14 @@ CREATE TABLE time_season_sequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE TimePeriodType +CREATE TABLE time_periodType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TimePeriodType VALUES('e','existing vintages'); -INSERT INTO TimePeriodType VALUES('f','future'); +INSERT INTO time_periodType VALUES('e','existing vintages'); +INSERT INTO time_periodType VALUES('f','future'); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1113,22 +1113,22 @@ CREATE TABLE OutputEmission sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); CREATE TABLE RPSRequirement ( region TEXT NOT NULL - REFERENCES Region (region), + REFERENCES region (region), period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_group TEXT NOT NULL REFERENCES TechGroup (group_name), requirement REAL NOT NULL, @@ -1140,13 +1140,13 @@ CREATE TABLE TechGroupMember group_name TEXT REFERENCES TechGroup (group_name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), PRIMARY KEY (group_name, tech) ); INSERT INTO TechGroupMember VALUES('RPS_common','EF'); INSERT INTO TechGroupMember VALUES('A_tech_grp_1','EH'); INSERT INTO TechGroupMember VALUES('A_tech_grp_1','EF'); -CREATE TABLE Technology +CREATE TABLE technology ( tech TEXT NOT NULL PRIMARY KEY, flag TEXT NOT NULL, @@ -1162,26 +1162,26 @@ CREATE TABLE Technology exchange INTEGER NOT NULL DEFAULT 0, seas_stor INTEGER NOT NULL DEFAULT 0, description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) -); -INSERT INTO Technology VALUES('well','p','supply','water','',0,0,0,0,0,0,0,0,'plain old water'); -INSERT INTO Technology VALUES('bulbs','p','residential','electric','',0,0,0,0,0,0,0,0,'residential lighting'); -INSERT INTO Technology VALUES('EH','pb','electric','hydro','',0,0,0,1,1,0,0,0,'hydro power electric plant'); -INSERT INTO Technology VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0,0,'big battery'); -INSERT INTO Technology VALUES('EF','p','electric','electric','',0,0,1,0,0,0,0,0,'fusion plant'); -INSERT INTO Technology VALUES('EFL','p','electric','electric','',0,0,0,0,0,1,0,0,'linked (to Fusion) producer'); -INSERT INTO Technology VALUES('heater','p','residential','electric','',0,0,0,0,0,0,0,0,'heater'); -INSERT INTO Technology VALUES('FGF_pipe','p','transport',NULL,'',0,0,0,0,0,0,1,0,'transportation line A->B'); -INSERT INTO Technology VALUES('GeoThermal','p','residential','hydro','',0,1,0,0,0,0,0,0,'geothermal hot water source'); -INSERT INTO Technology VALUES('GeoHeater','p','residential','hydro','',0,0,0,0,0,0,0,0,'geothermal heater from geo hyd'); -CREATE TABLE OutputCost + FOREIGN KEY (flag) REFERENCES technologyType (label) +); +INSERT INTO technology VALUES('well','p','supply','water','',0,0,0,0,0,0,0,0,'plain old water'); +INSERT INTO technology VALUES('bulbs','p','residential','electric','',0,0,0,0,0,0,0,0,'residential lighting'); +INSERT INTO technology VALUES('EH','pb','electric','hydro','',0,0,0,1,1,0,0,0,'hydro power electric plant'); +INSERT INTO technology VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0,0,'big battery'); +INSERT INTO technology VALUES('EF','p','electric','electric','',0,0,1,0,0,0,0,0,'fusion plant'); +INSERT INTO technology VALUES('EFL','p','electric','electric','',0,0,0,0,0,1,0,0,'linked (to Fusion) producer'); +INSERT INTO technology VALUES('heater','p','residential','electric','',0,0,0,0,0,0,0,0,'heater'); +INSERT INTO technology VALUES('FGF_pipe','p','transport',NULL,'',0,0,0,0,0,0,1,0,'transportation line A->B'); +INSERT INTO technology VALUES('GeoThermal','p','residential','hydro','',0,1,0,0,0,0,0,0,'geothermal hot water source'); +INSERT INTO technology VALUES('GeoHeater','p','residential','hydro','',0,0,0,0,0,0,0,0,'geothermal heater from geo hyd'); +CREATE TABLE output_cost ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), d_invest REAL, d_fixed REAL, d_var REAL, @@ -1191,7 +1191,7 @@ CREATE TABLE OutputCost var REAL, emiss REAL, PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) ); COMMIT; diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index 3064c30c3..1909152d1 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -1,16 +1,16 @@ PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE MetaData +CREATE TABLE metadata ( element TEXT, value INT, notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES('days_per_period',365,'count of days in each period'); -CREATE TABLE MetaDataReal +INSERT INTO metadata VALUES('DB_MAJOR',3,'DB major version number'); +INSERT INTO metadata VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO metadata VALUES('days_per_period',365,'count of days in each period'); +CREATE TABLE metadata_real ( element TEXT, value REAL, @@ -18,9 +18,9 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -CREATE TABLE OutputDualVariable +INSERT INTO metadata_real VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +INSERT INTO metadata_real VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +CREATE TABLE output_dual_variable ( scenario TEXT, constraint_name TEXT, @@ -64,9 +64,9 @@ CREATE TABLE capacity_credit ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, credit REAL, notes TEXT, @@ -77,13 +77,13 @@ CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -94,13 +94,13 @@ CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, tech), @@ -118,7 +118,7 @@ CREATE TABLE CapacityToActivity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), c2a REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -127,40 +127,40 @@ INSERT INTO CapacityToActivity VALUES('region','generator',8760.0,'MWh/MWy'); INSERT INTO CapacityToActivity VALUES('region','dly_stor',8760.0,'MWh/MWy'); INSERT INTO CapacityToActivity VALUES('region','seas_stor',8760.0,'MWh/MWy'); INSERT INTO CapacityToActivity VALUES('region','demand',8760.0,'MWh/MWy'); -CREATE TABLE Commodity +CREATE TABLE commodity ( name TEXT PRIMARY KEY, flag TEXT - REFERENCES CommodityType (label), + REFERENCES commodityType (label), description TEXT ); -INSERT INTO Commodity VALUES('ethos','s',NULL); -INSERT INTO Commodity VALUES('electricity','p',NULL); -INSERT INTO Commodity VALUES('demand','d',NULL); -CREATE TABLE CommodityType +INSERT INTO commodity VALUES('ethos','s',NULL); +INSERT INTO commodity VALUES('electricity','p',NULL); +INSERT INTO commodity VALUES('demand','d',NULL); +CREATE TABLE commodityType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO CommodityType VALUES('p','physical commodity'); -INSERT INTO CommodityType VALUES('a','annual commodity'); -INSERT INTO CommodityType VALUES('e','emissions commodity'); -INSERT INTO CommodityType VALUES('d','demand commodity'); -INSERT INTO CommodityType VALUES('s','source commodity'); -INSERT INTO CommodityType VALUES('w','waste commodity'); -INSERT INTO CommodityType VALUES('wa','waste annual commodity'); -INSERT INTO CommodityType VALUES('wp','waste physical commodity'); +INSERT INTO commodityType VALUES('p','physical commodity'); +INSERT INTO commodityType VALUES('a','annual commodity'); +INSERT INTO commodityType VALUES('e','emissions commodity'); +INSERT INTO commodityType VALUES('d','demand commodity'); +INSERT INTO commodityType VALUES('s','source commodity'); +INSERT INTO commodityType VALUES('w','waste commodity'); +INSERT INTO commodityType VALUES('wa','waste annual commodity'); +INSERT INTO commodityType VALUES('wp','waste physical commodity'); CREATE TABLE construction_input ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -170,9 +170,9 @@ CREATE TABLE cost_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT NOT NULL - REFERENCES Commodity (name), + REFERENCES commodity (name), cost REAL NOT NULL, units TEXT, notes TEXT, @@ -182,11 +182,11 @@ CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -196,9 +196,9 @@ CREATE TABLE cost_invest ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -212,11 +212,11 @@ CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -224,52 +224,52 @@ CREATE TABLE cost_variable ); INSERT INTO cost_variable VALUES('region',2000,'generator',2000,1.0,NULL,NULL); INSERT INTO cost_variable VALUES('region',2000,'demand',2000,1.0,NULL,NULL); -CREATE TABLE Demand +CREATE TABLE demand ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), commodity TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), demand REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO Demand VALUES('region',2000,'demand',8760.0,'MWh',NULL); -CREATE TABLE DemandSpecificDistribution +INSERT INTO demand VALUES('region',2000,'demand',8760.0,'MWh',NULL); +CREATE TABLE demand_specific_distribution ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), dsd REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','a','demand',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','b','demand',0.05,NULL); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','c','demand',0.05,NULL); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','d','demand',0.1,NULL); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','a','demand',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','b','demand',0.2,NULL); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','c','demand',0.2,NULL); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','d','demand',0.4,NULL); +INSERT INTO demand_specific_distribution VALUES('region',2000,'charge','a','demand',0.0,NULL); +INSERT INTO demand_specific_distribution VALUES('region',2000,'charge','b','demand',0.05,NULL); +INSERT INTO demand_specific_distribution VALUES('region',2000,'charge','c','demand',0.05,NULL); +INSERT INTO demand_specific_distribution VALUES('region',2000,'charge','d','demand',0.1,NULL); +INSERT INTO demand_specific_distribution VALUES('region',2000,'discharge','a','demand',0.0,NULL); +INSERT INTO demand_specific_distribution VALUES('region',2000,'discharge','b','demand',0.2,NULL); +INSERT INTO demand_specific_distribution VALUES('region',2000,'discharge','c','demand',0.2,NULL); +INSERT INTO demand_specific_distribution VALUES('region',2000,'discharge','d','demand',0.4,NULL); CREATE TABLE end_of_life_output ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), value REAL, units TEXT, notes TEXT, @@ -279,13 +279,13 @@ CREATE TABLE efficiency ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage, output_comm), @@ -299,19 +299,19 @@ CREATE TABLE efficiency_variable ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), @@ -321,15 +321,15 @@ CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), activity REAL, units TEXT, notes TEXT, @@ -339,11 +339,11 @@ CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -353,11 +353,11 @@ CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -367,9 +367,9 @@ CREATE TABLE existing_capacity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, units TEXT, notes TEXT, @@ -385,7 +385,7 @@ CREATE TABLE Loanlifetime_tech ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -394,9 +394,9 @@ CREATE TABLE loan_rate ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), rate REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -405,9 +405,9 @@ CREATE TABLE lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -416,7 +416,7 @@ CREATE TABLE lifetime_tech ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -505,15 +505,15 @@ CREATE TABLE LimitStorageLevelFraction ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), fraction REAL, @@ -526,7 +526,7 @@ CREATE TABLE limit_activity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -539,7 +539,7 @@ CREATE TABLE limit_activity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -552,11 +552,11 @@ CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, @@ -568,7 +568,7 @@ CREATE TABLE limit_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -581,7 +581,7 @@ CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -594,7 +594,7 @@ CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -607,7 +607,7 @@ CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -630,13 +630,13 @@ CREATE TABLE limit_resource CREATE TABLE limit_seasonal_capacity_factor ( region TEXT - REFERENCES Region (region), + REFERENCES region (region), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, @@ -647,11 +647,11 @@ CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -662,11 +662,11 @@ CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -677,11 +677,11 @@ CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -692,11 +692,11 @@ CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -707,9 +707,9 @@ CREATE TABLE limit_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), value REAL, @@ -721,33 +721,33 @@ CREATE TABLE LinkedTech ( primary_region TEXT, primary_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), driven_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); -CREATE TABLE OutputCurtailment +CREATE TABLE output_curtailment ( scenario TEXT, region TEXT, sector TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), curtailment REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); @@ -758,24 +758,24 @@ CREATE TABLE OutputNetCapacity sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE output_built_capacity ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, tech, vintage) ); @@ -786,11 +786,11 @@ CREATE TABLE OutputRetiredCapacity sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cap_eol REAL, cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) @@ -802,19 +802,19 @@ CREATE TABLE OutputFlowIn sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); @@ -825,38 +825,38 @@ CREATE TABLE OutputFlowOut sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputStorageLevel +CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); @@ -864,7 +864,7 @@ CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY - REFERENCES Region (region), + REFERENCES region (region), margin REAL, notes TEXT ); @@ -872,7 +872,7 @@ CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -881,27 +881,27 @@ CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE Region +CREATE TABLE region ( region TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO Region VALUES('region',NULL); +INSERT INTO region VALUES('region',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -911,7 +911,7 @@ CREATE TABLE reserve_capacity_derate CREATE TABLE TimeSegmentFraction ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT @@ -944,22 +944,22 @@ CREATE TABLE lifetime_survival_curve region TEXT NOT NULL, period INTEGER NOT NULL, tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), fraction REAL, notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE TechnologyType +CREATE TABLE technologyType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('p','production technology'); -INSERT INTO TechnologyType VALUES('pb','baseload production technology'); -INSERT INTO TechnologyType VALUES('ps','storage production technology'); +INSERT INTO technologyType VALUES('p','production technology'); +INSERT INTO technologyType VALUES('pb','baseload production technology'); +INSERT INTO technologyType VALUES('ps','storage production technology'); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -970,20 +970,20 @@ INSERT INTO TimeOfDay VALUES(0,'a'); INSERT INTO TimeOfDay VALUES(1,'b'); INSERT INTO TimeOfDay VALUES(2,'c'); INSERT INTO TimeOfDay VALUES(3,'d'); -CREATE TABLE TimePeriod +CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES TimePeriodType (label) + REFERENCES time_periodType (label) ); -INSERT INTO TimePeriod VALUES(0,2000,'f'); -INSERT INTO TimePeriod VALUES(1,2005,'f'); +INSERT INTO time_period VALUES(0,2000,'f'); +INSERT INTO time_period VALUES(1,2005,'f'); CREATE TABLE TimeSeason ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, season TEXT REFERENCES SeasonLabel (season), @@ -992,14 +992,14 @@ CREATE TABLE TimeSeason ); INSERT INTO TimeSeason VALUES(2000,0,'charge',NULL); INSERT INTO TimeSeason VALUES(2000,1,'discharge',NULL); -CREATE TABLE TimePeriodType +CREATE TABLE time_periodType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TimePeriodType VALUES('e','existing vintages'); -INSERT INTO TimePeriodType VALUES('f','future'); +INSERT INTO time_periodType VALUES('e','existing vintages'); +INSERT INTO time_periodType VALUES('f','future'); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1007,22 +1007,22 @@ CREATE TABLE OutputEmission sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); CREATE TABLE RPSRequirement ( region TEXT NOT NULL - REFERENCES Region (region), + REFERENCES region (region), period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_group TEXT NOT NULL REFERENCES TechGroup (group_name), requirement REAL NOT NULL, @@ -1033,10 +1033,10 @@ CREATE TABLE TechGroupMember group_name TEXT REFERENCES TechGroup (group_name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), PRIMARY KEY (group_name, tech) ); -CREATE TABLE Technology +CREATE TABLE technology ( tech TEXT NOT NULL PRIMARY KEY, flag TEXT NOT NULL, @@ -1052,20 +1052,20 @@ CREATE TABLE Technology exchange INTEGER NOT NULL DEFAULT 0, seas_stor INTEGER NOT NULL DEFAULT 0, description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) + FOREIGN KEY (flag) REFERENCES technologyType (label) ); -INSERT INTO Technology VALUES('generator','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('dly_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('seas_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,1,NULL); -INSERT INTO Technology VALUES('demand','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -CREATE TABLE OutputCost +INSERT INTO technology VALUES('generator','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO technology VALUES('dly_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO technology VALUES('seas_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,1,NULL); +INSERT INTO technology VALUES('demand','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +CREATE TABLE output_cost ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), d_invest REAL, d_fixed REAL, d_var REAL, @@ -1075,13 +1075,13 @@ CREATE TABLE OutputCost var REAL, emiss REAL, PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) ); CREATE TABLE time_season_sequential ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, season TEXT diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index c95403a5d..d685f309c 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -1,16 +1,16 @@ PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE MetaData +CREATE TABLE metadata ( element TEXT, value INT, notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); -CREATE TABLE MetaDataReal +INSERT INTO metadata VALUES('DB_MAJOR',3,'DB major version number'); +INSERT INTO metadata VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO metadata VALUES ('days_per_period', 365, 'count of days in each period'); +CREATE TABLE metadata_real ( element TEXT, value REAL, @@ -18,9 +18,9 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); -CREATE TABLE OutputDualVariable +INSERT INTO metadata_real VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); +INSERT INTO metadata_real VALUES('global_discount_rate',0.05000000000000000277,''); +CREATE TABLE output_dual_variable ( scenario TEXT, constraint_name TEXT, @@ -55,9 +55,9 @@ CREATE TABLE capacity_credit ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, credit REAL, notes TEXT, @@ -68,13 +68,13 @@ CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -85,13 +85,13 @@ CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, tech), @@ -101,47 +101,47 @@ CREATE TABLE CapacityToActivity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), c2a REAL, notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE Commodity +CREATE TABLE commodity ( name TEXT PRIMARY KEY, flag TEXT - REFERENCES CommodityType (label), + REFERENCES commodityType (label), description TEXT ); -INSERT INTO Commodity VALUES('ELC','d','electricity'); -INSERT INTO Commodity VALUES('NGA','p','natural gas'); -INSERT INTO Commodity VALUES('CO2','e','CO2 emission'); -INSERT INTO Commodity VALUES('CO2_CAP','d','captured CO2'); -INSERT INTO Commodity VALUES('ETHOS','s','source'); -CREATE TABLE CommodityType +INSERT INTO commodity VALUES('ELC','d','electricity'); +INSERT INTO commodity VALUES('NGA','p','natural gas'); +INSERT INTO commodity VALUES('CO2','e','CO2 emission'); +INSERT INTO commodity VALUES('CO2_CAP','d','captured CO2'); +INSERT INTO commodity VALUES('ETHOS','s','source'); +CREATE TABLE commodityType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO CommodityType VALUES('w','waste commodity'); -INSERT INTO CommodityType VALUES('wa','waste annual commodity'); -INSERT INTO CommodityType VALUES('wp','waste physical commodity'); -INSERT INTO CommodityType VALUES('a','annual commodity'); -INSERT INTO CommodityType VALUES('s','source commodity'); -INSERT INTO CommodityType VALUES('p','physical commodity'); -INSERT INTO CommodityType VALUES('e','emissions commodity'); -INSERT INTO CommodityType VALUES('d','demand commodity'); +INSERT INTO commodityType VALUES('w','waste commodity'); +INSERT INTO commodityType VALUES('wa','waste annual commodity'); +INSERT INTO commodityType VALUES('wp','waste physical commodity'); +INSERT INTO commodityType VALUES('a','annual commodity'); +INSERT INTO commodityType VALUES('s','source commodity'); +INSERT INTO commodityType VALUES('p','physical commodity'); +INSERT INTO commodityType VALUES('e','emissions commodity'); +INSERT INTO commodityType VALUES('d','demand commodity'); CREATE TABLE construction_input ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -151,9 +151,9 @@ CREATE TABLE cost_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT NOT NULL - REFERENCES Commodity (name), + REFERENCES commodity (name), cost REAL NOT NULL, units TEXT, notes TEXT, @@ -164,11 +164,11 @@ CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -178,9 +178,9 @@ CREATE TABLE cost_invest ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -192,11 +192,11 @@ CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -205,47 +205,47 @@ CREATE TABLE cost_variable INSERT INTO cost_variable VALUES('linkville',2000,'PLANT',2000,10.0,NULL,NULL); INSERT INTO cost_variable VALUES('linkville',2000,'CCS',2000,10.0,NULL,NULL); INSERT INTO cost_variable VALUES('linkville',2000,'FAKE_SOURCE',2000,0.0,NULL,NULL); -CREATE TABLE Demand +CREATE TABLE demand ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), commodity TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), demand REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO Demand VALUES('linkville',2000,'CO2_CAP',1000.0,NULL,NULL); -INSERT INTO Demand VALUES('linkville',2000,'ELC',10.0,NULL,NULL); -CREATE TABLE DemandSpecificDistribution +INSERT INTO demand VALUES('linkville',2000,'CO2_CAP',1000.0,NULL,NULL); +INSERT INTO demand VALUES('linkville',2000,'ELC',10.0,NULL,NULL); +CREATE TABLE demand_specific_distributionon ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), dsd REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('linkville',2000,'summer','day','ELC',0.5,''); -INSERT INTO DemandSpecificDistribution VALUES('linkville',2000,'winter','day','ELC',0.5,''); +INSERT INTO demand_specific_distributionon VALUES('linkville',2000,'summer','day','ELC',0.5,''); +INSERT INTO demand_specific_distributionon VALUES('linkville',2000,'winter','day','ELC',0.5,''); CREATE TABLE end_of_life_output ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), value REAL, units TEXT, notes TEXT, @@ -255,13 +255,13 @@ CREATE TABLE efficiency ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage, output_comm), @@ -275,19 +275,19 @@ CREATE TABLE efficiency_variable ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), @@ -297,15 +297,15 @@ CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), activity REAL, units TEXT, notes TEXT, @@ -316,11 +316,11 @@ CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -330,11 +330,11 @@ CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -344,9 +344,9 @@ CREATE TABLE existing_capacity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, units TEXT, notes TEXT, @@ -362,9 +362,9 @@ CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -373,9 +373,9 @@ CREATE TABLE loan_rate ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), rate REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -384,9 +384,9 @@ CREATE TABLE lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -395,7 +395,7 @@ CREATE TABLE lifetime_tech ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -486,15 +486,15 @@ CREATE TABLE LimitStorageLevelFraction ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), fraction REAL, @@ -505,7 +505,7 @@ CREATE TABLE limit_activity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -518,7 +518,7 @@ CREATE TABLE limit_activity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -531,11 +531,11 @@ CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, @@ -547,7 +547,7 @@ CREATE TABLE limit_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -560,7 +560,7 @@ CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -573,7 +573,7 @@ CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -586,7 +586,7 @@ CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -609,13 +609,13 @@ CREATE TABLE limit_resource CREATE TABLE limit_seasonal_capacity_factor ( region TEXT - REFERENCES Region (region), + REFERENCES region (region), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, @@ -626,11 +626,11 @@ CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -641,11 +641,11 @@ CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -656,11 +656,11 @@ CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -671,11 +671,11 @@ CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -686,9 +686,9 @@ CREATE TABLE limit_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), value REAL, @@ -700,34 +700,34 @@ CREATE TABLE LinkedTech ( primary_region TEXT, primary_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), driven_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); INSERT INTO LinkedTech VALUES('linkville','PLANT','CO2','CCS',NULL); -CREATE TABLE OutputCurtailment +CREATE TABLE output_curtailment ( scenario TEXT, region TEXT, sector TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), curtailment REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); @@ -738,24 +738,24 @@ CREATE TABLE OutputNetCapacity sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE output_built_capacity ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, tech, vintage) ); @@ -766,11 +766,11 @@ CREATE TABLE OutputRetiredCapacity sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cap_eol REAL, cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) @@ -782,19 +782,19 @@ CREATE TABLE OutputFlowIn sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); @@ -805,38 +805,38 @@ CREATE TABLE OutputFlowOut sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputStorageLevel +CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); @@ -844,7 +844,7 @@ CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY - REFERENCES Region (region), + REFERENCES region (region), margin REAL, notes TEXT ); @@ -852,7 +852,7 @@ CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -861,27 +861,27 @@ CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE Region +CREATE TABLE region ( region TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO Region VALUES('linkville',NULL); +INSERT INTO region VALUES('linkville',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -891,7 +891,7 @@ CREATE TABLE reserve_capacity_derate CREATE TABLE TimeSegmentFraction ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT @@ -916,22 +916,22 @@ CREATE TABLE lifetime_survival_curve region TEXT NOT NULL, period INTEGER NOT NULL, tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), fraction REAL, notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE TechnologyType +CREATE TABLE technologyType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('p','production technology'); -INSERT INTO TechnologyType VALUES('pb','baseload production technology'); -INSERT INTO TechnologyType VALUES('ps','storage production technology'); +INSERT INTO technologyType VALUES('p','production technology'); +INSERT INTO technologyType VALUES('pb','baseload production technology'); +INSERT INTO technologyType VALUES('ps','storage production technology'); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -939,21 +939,21 @@ CREATE TABLE TimeOfDay PRIMARY KEY ); INSERT INTO TimeOfDay VALUES(1,'day'); -CREATE TABLE TimePeriod +CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES TimePeriodType (label) + REFERENCES time_periodType (label) ); -INSERT INTO TimePeriod VALUES(0,1995,'e'); -INSERT INTO TimePeriod VALUES(1,2000,'f'); -INSERT INTO TimePeriod VALUES(2,2005,'f'); +INSERT INTO time_period VALUES(0,1995,'e'); +INSERT INTO time_period VALUES(1,2000,'f'); +INSERT INTO time_period VALUES(2,2005,'f'); CREATE TABLE TimeSeason ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, season TEXT REFERENCES SeasonLabel (season), @@ -965,7 +965,7 @@ INSERT INTO TimeSeason VALUES(2000,2,'winter',NULL); CREATE TABLE time_season_sequential ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, season TEXT @@ -975,14 +975,14 @@ CREATE TABLE time_season_sequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE TimePeriodType +CREATE TABLE time_periodType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TimePeriodType VALUES('e','existing vintages'); -INSERT INTO TimePeriodType VALUES('f','future'); +INSERT INTO time_periodType VALUES('e','existing vintages'); +INSERT INTO time_periodType VALUES('f','future'); CREATE TABLE OutputEmission ( scenario TEXT, @@ -990,22 +990,22 @@ CREATE TABLE OutputEmission sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); CREATE TABLE RPSRequirement ( region TEXT NOT NULL - REFERENCES Region (region), + REFERENCES region (region), period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_group TEXT NOT NULL REFERENCES TechGroup (group_name), requirement REAL NOT NULL, @@ -1016,10 +1016,10 @@ CREATE TABLE TechGroupMember group_name TEXT REFERENCES TechGroup (group_name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), PRIMARY KEY (group_name, tech) ); -CREATE TABLE Technology +CREATE TABLE technology ( tech TEXT NOT NULL PRIMARY KEY, flag TEXT NOT NULL, @@ -1035,20 +1035,20 @@ CREATE TABLE Technology exchange INTEGER NOT NULL DEFAULT 0, seas_stor INTEGER NOT NULL DEFAULT 0, description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) + FOREIGN KEY (flag) REFERENCES technologyType (label) ); -INSERT INTO Technology VALUES('PLANT','p','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('CCS','p','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('MINE','p','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('FAKE_SOURCE','p','supply',NULL,NULL,1,0,0,0,0,0,0,0,NULL); -CREATE TABLE OutputCost +INSERT INTO technology VALUES('PLANT','p','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO technology VALUES('CCS','p','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO technology VALUES('MINE','p','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO technology VALUES('FAKE_SOURCE','p','supply',NULL,NULL,1,0,0,0,0,0,0,0,NULL); +CREATE TABLE output_cost ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), d_invest REAL, d_fixed REAL, d_var REAL, @@ -1058,7 +1058,7 @@ CREATE TABLE OutputCost var REAL, emiss REAL, PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) ); COMMIT; diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index 11aeff4d2..befc090e0 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -1,16 +1,16 @@ PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE MetaData +CREATE TABLE metadata ( element TEXT, value INT, notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); -CREATE TABLE MetaDataReal +INSERT INTO metadata VALUES('DB_MAJOR',3,'DB major version number'); +INSERT INTO metadata VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO metadata VALUES ('days_per_period', 365, 'count of days in each period'); +CREATE TABLE metadata_real ( element TEXT, value REAL, @@ -18,9 +18,9 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); -CREATE TABLE OutputDualVariable +INSERT INTO metadata_real VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); +INSERT INTO metadata_real VALUES('global_discount_rate',0.05000000000000000277,''); +CREATE TABLE output_dual_variable ( scenario TEXT, constraint_name TEXT, @@ -55,9 +55,9 @@ CREATE TABLE capacity_credit ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, credit REAL, notes TEXT, @@ -68,13 +68,13 @@ CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -85,13 +85,13 @@ CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, tech), @@ -101,48 +101,48 @@ CREATE TABLE CapacityToActivity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), c2a REAL, notes TEXT, PRIMARY KEY (region, tech) ); INSERT INTO CapacityToActivity VALUES('electricville','bulbs',1.0,''); -CREATE TABLE Commodity +CREATE TABLE commodity ( name TEXT PRIMARY KEY, flag TEXT - REFERENCES CommodityType (label), + REFERENCES commodityType (label), description TEXT ); -INSERT INTO Commodity VALUES('ELC','p','# electricity'); -INSERT INTO Commodity VALUES('HYD','p','# water'); -INSERT INTO Commodity VALUES('co2','e','#CO2 emissions'); -INSERT INTO Commodity VALUES('RL','d','# residential lighting'); -INSERT INTO Commodity VALUES('earth','p','# the source of stuff'); -CREATE TABLE CommodityType +INSERT INTO commodity VALUES('ELC','p','# electricity'); +INSERT INTO commodity VALUES('HYD','p','# water'); +INSERT INTO commodity VALUES('co2','e','#CO2 emissions'); +INSERT INTO commodity VALUES('RL','d','# residential lighting'); +INSERT INTO commodity VALUES('earth','p','# the source of stuff'); +CREATE TABLE commodityType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO CommodityType VALUES('w','waste commodity'); -INSERT INTO CommodityType VALUES('wa','waste annual commodity'); -INSERT INTO CommodityType VALUES('wp','waste physical commodity'); -INSERT INTO CommodityType VALUES('a','annual commodity'); -INSERT INTO CommodityType VALUES('p','physical commodity'); -INSERT INTO CommodityType VALUES('e','emissions commodity'); -INSERT INTO CommodityType VALUES('d','demand commodity'); -INSERT INTO CommodityType VALUES('s','source commodity'); +INSERT INTO commodityType VALUES('w','waste commodity'); +INSERT INTO commodityType VALUES('wa','waste annual commodity'); +INSERT INTO commodityType VALUES('wp','waste physical commodity'); +INSERT INTO commodityType VALUES('a','annual commodity'); +INSERT INTO commodityType VALUES('p','physical commodity'); +INSERT INTO commodityType VALUES('e','emissions commodity'); +INSERT INTO commodityType VALUES('d','demand commodity'); +INSERT INTO commodityType VALUES('s','source commodity'); CREATE TABLE construction_input ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -152,9 +152,9 @@ CREATE TABLE cost_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT NOT NULL - REFERENCES Commodity (name), + REFERENCES commodity (name), cost REAL NOT NULL, units TEXT, notes TEXT, @@ -164,11 +164,11 @@ CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -180,9 +180,9 @@ CREATE TABLE cost_invest ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -194,11 +194,11 @@ CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -206,54 +206,54 @@ CREATE TABLE cost_variable ); INSERT INTO cost_variable VALUES('electricville',2025,'EH',2025,1000.0,'',''); INSERT INTO cost_variable VALUES('electricville',2025,'batt',2025,1.0,'',''); -CREATE TABLE Demand +CREATE TABLE demand ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), commodity TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), demand REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO Demand VALUES('electricville',2025,'RL',100.0,'',''); -CREATE TABLE DemandSpecificDistribution +INSERT INTO demand VALUES('electricville',2025,'RL',100.0,'',''); +CREATE TABLE demand_specific_distribution ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), dsd REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s1','d1','RL',0.07499999999999999723,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s1','d2','RL',0.07499999999999999723,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s1','d3','RL',0.07499999999999999723,NULL); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s2','d1','RL',0.07499999999999999723,NULL); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s2','d2','RL',0.07499999999999999723,NULL); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s2','d3','RL',0.07499999999999999723,NULL); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s1','d4','RL',0.07499999999999999723,NULL); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s1','d5','RL',0.2000000000000000111,NULL); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s2','d4','RL',0.2000000000000000111,NULL); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'s2','d5','RL',0.07499999999999999723,NULL); +INSERT INTO demand_specific_distribution VALUES('electricville',2025,'s1','d1','RL',0.07499999999999999723,''); +INSERT INTO demand_specific_distribution VALUES('electricville',2025,'s1','d2','RL',0.07499999999999999723,''); +INSERT INTO demand_specific_distribution VALUES('electricville',2025,'s1','d3','RL',0.07499999999999999723,NULL); +INSERT INTO demand_specific_distribution VALUES('electricville',2025,'s2','d1','RL',0.07499999999999999723,NULL); +INSERT INTO demand_specific_distribution VALUES('electricville',2025,'s2','d2','RL',0.07499999999999999723,NULL); +INSERT INTO demand_specific_distribution VALUES('electricville',2025,'s2','d3','RL',0.07499999999999999723,NULL); +INSERT INTO demand_specific_distribution VALUES('electricville',2025,'s1','d4','RL',0.07499999999999999723,NULL); +INSERT INTO demand_specific_distribution VALUES('electricville',2025,'s1','d5','RL',0.2000000000000000111,NULL); +INSERT INTO demand_specific_distribution VALUES('electricville',2025,'s2','d4','RL',0.2000000000000000111,NULL); +INSERT INTO demand_specific_distribution VALUES('electricville',2025,'s2','d5','RL',0.07499999999999999723,NULL); CREATE TABLE end_of_life_output ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), value REAL, units TEXT, notes TEXT, @@ -263,13 +263,13 @@ CREATE TABLE efficiency ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage, output_comm), @@ -283,19 +283,19 @@ CREATE TABLE efficiency_variable ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), @@ -305,15 +305,15 @@ CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), activity REAL, units TEXT, notes TEXT, @@ -324,11 +324,11 @@ CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -338,11 +338,11 @@ CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -352,9 +352,9 @@ CREATE TABLE existing_capacity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, units TEXT, notes TEXT, @@ -370,9 +370,9 @@ CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -381,9 +381,9 @@ CREATE TABLE loan_rate ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), rate REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -392,9 +392,9 @@ CREATE TABLE lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -403,7 +403,7 @@ CREATE TABLE lifetime_tech ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -494,15 +494,15 @@ CREATE TABLE LimitStorageLevelFraction ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), fraction REAL, @@ -514,7 +514,7 @@ CREATE TABLE limit_activity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -527,7 +527,7 @@ CREATE TABLE limit_activity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -540,11 +540,11 @@ CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, @@ -556,7 +556,7 @@ CREATE TABLE limit_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -573,7 +573,7 @@ CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -586,7 +586,7 @@ CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -599,7 +599,7 @@ CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -622,13 +622,13 @@ CREATE TABLE limit_resource CREATE TABLE limit_seasonal_capacity_factor ( region TEXT - REFERENCES Region (region), + REFERENCES region (region), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, @@ -639,11 +639,11 @@ CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -654,11 +654,11 @@ CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -669,11 +669,11 @@ CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -684,11 +684,11 @@ CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -699,9 +699,9 @@ CREATE TABLE limit_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), value REAL, @@ -713,33 +713,33 @@ CREATE TABLE LinkedTech ( primary_region TEXT, primary_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), driven_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); -CREATE TABLE OutputCurtailment +CREATE TABLE output_curtailment ( scenario TEXT, region TEXT, sector TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), curtailment REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); @@ -750,24 +750,24 @@ CREATE TABLE OutputNetCapacity sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE output_built_capacity ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, tech, vintage) ); @@ -778,11 +778,11 @@ CREATE TABLE OutputRetiredCapacity sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cap_eol REAL, cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) @@ -794,19 +794,19 @@ CREATE TABLE OutputFlowIn sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); @@ -817,38 +817,38 @@ CREATE TABLE OutputFlowOut sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputStorageLevel +CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); @@ -856,7 +856,7 @@ CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY - REFERENCES Region (region), + REFERENCES region (region), margin REAL, notes TEXT ); @@ -864,7 +864,7 @@ CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -873,27 +873,27 @@ CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE Region +CREATE TABLE region ( region TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO Region VALUES('electricville',NULL); +INSERT INTO region VALUES('electricville',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -903,7 +903,7 @@ CREATE TABLE reserve_capacity_derate CREATE TABLE TimeSegmentFraction ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT @@ -937,22 +937,22 @@ CREATE TABLE lifetime_survival_curve region TEXT NOT NULL, period INTEGER NOT NULL, tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), fraction REAL, notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE TechnologyType +CREATE TABLE technologyType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('p','production technology'); -INSERT INTO TechnologyType VALUES('pb','baseload production technology'); -INSERT INTO TechnologyType VALUES('ps','storage production technology'); +INSERT INTO technologyType VALUES('p','production technology'); +INSERT INTO technologyType VALUES('pb','baseload production technology'); +INSERT INTO technologyType VALUES('ps','storage production technology'); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -964,21 +964,21 @@ INSERT INTO TimeOfDay VALUES(2,'d2'); INSERT INTO TimeOfDay VALUES(3,'d3'); INSERT INTO TimeOfDay VALUES(4,'d4'); INSERT INTO TimeOfDay VALUES(5,'d5'); -CREATE TABLE TimePeriod +CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES TimePeriodType (label) + REFERENCES time_periodType (label) ); -INSERT INTO TimePeriod VALUES(1,2020,'e'); -INSERT INTO TimePeriod VALUES(2,2025,'f'); -INSERT INTO TimePeriod VALUES(3,2030,'f'); +INSERT INTO time_period VALUES(1,2020,'e'); +INSERT INTO time_period VALUES(2,2025,'f'); +INSERT INTO time_period VALUES(3,2030,'f'); CREATE TABLE TimeSeason ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, season TEXT REFERENCES SeasonLabel (season), @@ -990,7 +990,7 @@ INSERT INTO TimeSeason VALUES(2025,2,'s2',NULL); CREATE TABLE time_season_sequential ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, season TEXT @@ -1000,14 +1000,14 @@ CREATE TABLE time_season_sequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE TimePeriodType +CREATE TABLE time_periodType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TimePeriodType VALUES('e','existing vintages'); -INSERT INTO TimePeriodType VALUES('f','future'); +INSERT INTO time_periodType VALUES('e','existing vintages'); +INSERT INTO time_periodType VALUES('f','future'); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1015,22 +1015,22 @@ CREATE TABLE OutputEmission sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); CREATE TABLE RPSRequirement ( region TEXT NOT NULL - REFERENCES Region (region), + REFERENCES region (region), period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_group TEXT NOT NULL REFERENCES TechGroup (group_name), requirement REAL NOT NULL, @@ -1041,10 +1041,10 @@ CREATE TABLE TechGroupMember group_name TEXT REFERENCES TechGroup (group_name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), PRIMARY KEY (group_name, tech) ); -CREATE TABLE Technology +CREATE TABLE technology ( tech TEXT NOT NULL PRIMARY KEY, flag TEXT NOT NULL, @@ -1060,20 +1060,20 @@ CREATE TABLE Technology exchange INTEGER NOT NULL DEFAULT 0, seas_stor INTEGER NOT NULL DEFAULT 0, description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) + FOREIGN KEY (flag) REFERENCES technologyType (label) ); -INSERT INTO Technology VALUES('well','p','supply','water','',0,0,0,0,0,0,0,0,'plain old water'); -INSERT INTO Technology VALUES('bulbs','p','residential','electric','',0,0,0,0,0,0,0,0,' residential lighting'); -INSERT INTO Technology VALUES('EH','pb','electric','hydro','',0,0,0,0,0,0,0,0,'hydro power electric plant'); -INSERT INTO Technology VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0,0,'big battery'); -CREATE TABLE OutputCost +INSERT INTO technology VALUES('well','p','supply','water','',0,0,0,0,0,0,0,0,'plain old water'); +INSERT INTO technology VALUES('bulbs','p','residential','electric','',0,0,0,0,0,0,0,0,' residential lighting'); +INSERT INTO technology VALUES('EH','pb','electric','hydro','',0,0,0,0,0,0,0,0,'hydro power electric plant'); +INSERT INTO technology VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0,0,'big battery'); +CREATE TABLE output_cost ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), d_invest REAL, d_fixed REAL, d_var REAL, @@ -1083,7 +1083,7 @@ CREATE TABLE OutputCost var REAL, emiss REAL, PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) ); COMMIT; diff --git a/tests/testing_data/survival_curve.sql b/tests/testing_data/survival_curve.sql index b0c6560ad..5525fc022 100644 --- a/tests/testing_data/survival_curve.sql +++ b/tests/testing_data/survival_curve.sql @@ -1,16 +1,16 @@ PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE MetaData +CREATE TABLE metadata ( element TEXT, value INT, notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); -INSERT INTO MetaData VALUES('days_per_period',365,'count of days in each period'); -CREATE TABLE MetaDataReal +INSERT INTO metadata VALUES('DB_MAJOR',3,'DB major version number'); +INSERT INTO metadata VALUES('DB_MINOR',0,'DB minor version number'); +INSERT INTO metadata VALUES('days_per_period',365,'count of days in each period'); +CREATE TABLE metadata_real ( element TEXT, value REAL, @@ -18,9 +18,9 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -CREATE TABLE OutputDualVariable +INSERT INTO metadata_real VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +INSERT INTO metadata_real VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +CREATE TABLE output_dual_variable ( scenario TEXT, constraint_name TEXT, @@ -48,9 +48,9 @@ CREATE TABLE capacity_credit ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, credit REAL, notes TEXT, @@ -61,13 +61,13 @@ CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -78,13 +78,13 @@ CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, tech), @@ -94,44 +94,44 @@ CREATE TABLE CapacityToActivity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), c2a REAL, notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE Commodity +CREATE TABLE commodity ( name TEXT PRIMARY KEY, flag TEXT - REFERENCES CommodityType (label), + REFERENCES commodityType (label), description TEXT ); -INSERT INTO Commodity VALUES('source','s',NULL); -INSERT INTO Commodity VALUES('demand','d',NULL); -CREATE TABLE CommodityType +INSERT INTO commodity VALUES('source','s',NULL); +INSERT INTO commodity VALUES('demand','d',NULL); +CREATE TABLE commodityType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO CommodityType VALUES('p','physical commodity'); -INSERT INTO CommodityType VALUES('a','annual commodity'); -INSERT INTO CommodityType VALUES('e','emissions commodity'); -INSERT INTO CommodityType VALUES('d','demand commodity'); -INSERT INTO CommodityType VALUES('s','source commodity'); -INSERT INTO CommodityType VALUES('w','waste commodity'); -INSERT INTO CommodityType VALUES('wa','waste annual commodity'); -INSERT INTO CommodityType VALUES('wp','waste physical commodity'); +INSERT INTO commodityType VALUES('p','physical commodity'); +INSERT INTO commodityType VALUES('a','annual commodity'); +INSERT INTO commodityType VALUES('e','emissions commodity'); +INSERT INTO commodityType VALUES('d','demand commodity'); +INSERT INTO commodityType VALUES('s','source commodity'); +INSERT INTO commodityType VALUES('w','waste commodity'); +INSERT INTO commodityType VALUES('wa','waste annual commodity'); +INSERT INTO commodityType VALUES('wp','waste physical commodity'); CREATE TABLE construction_input ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -141,9 +141,9 @@ CREATE TABLE cost_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT NOT NULL - REFERENCES Commodity (name), + REFERENCES commodity (name), cost REAL NOT NULL, units TEXT, notes TEXT, @@ -153,11 +153,11 @@ CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -193,9 +193,9 @@ CREATE TABLE cost_invest ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -211,11 +211,11 @@ CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -247,35 +247,35 @@ INSERT INTO cost_variable VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL) INSERT INTO cost_variable VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); INSERT INTO cost_variable VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); INSERT INTO cost_variable VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); -CREATE TABLE Demand +CREATE TABLE demand ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), commodity TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), demand REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO Demand VALUES('region',2025,'demand',1.0,NULL,NULL); -INSERT INTO Demand VALUES('region',2030,'demand',1.0,NULL,NULL); -INSERT INTO Demand VALUES('region',2035,'demand',1.0,NULL,NULL); -INSERT INTO Demand VALUES('region',2040,'demand',1.0,NULL,NULL); -INSERT INTO Demand VALUES('region',2045,'demand',1.0,NULL,NULL); -INSERT INTO Demand VALUES('region',2050,'demand',1.0,NULL,NULL); -CREATE TABLE DemandSpecificDistribution +INSERT INTO demand VALUES('region',2025,'demand',1.0,NULL,NULL); +INSERT INTO demand VALUES('region',2030,'demand',1.0,NULL,NULL); +INSERT INTO demand VALUES('region',2035,'demand',1.0,NULL,NULL); +INSERT INTO demand VALUES('region',2040,'demand',1.0,NULL,NULL); +INSERT INTO demand VALUES('region',2045,'demand',1.0,NULL,NULL); +INSERT INTO demand VALUES('region',2050,'demand',1.0,NULL,NULL); +CREATE TABLE demand_specific_distributionon ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), dsd REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, demand_name), @@ -285,11 +285,11 @@ CREATE TABLE end_of_life_output ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), value REAL, units TEXT, notes TEXT, @@ -299,13 +299,13 @@ CREATE TABLE efficiency ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage, output_comm), @@ -323,19 +323,19 @@ CREATE TABLE efficiency_variable ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), @@ -345,15 +345,15 @@ CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), activity REAL, units TEXT, notes TEXT, @@ -363,11 +363,11 @@ CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -377,11 +377,11 @@ CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -391,9 +391,9 @@ CREATE TABLE existing_capacity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, units TEXT, notes TEXT, @@ -411,9 +411,9 @@ CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -422,9 +422,9 @@ CREATE TABLE loan_rate ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), rate REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -433,9 +433,9 @@ CREATE TABLE lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -444,7 +444,7 @@ CREATE TABLE lifetime_tech ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -537,15 +537,15 @@ CREATE TABLE LimitStorageLevelFraction ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), fraction REAL, @@ -556,7 +556,7 @@ CREATE TABLE limit_activity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -569,7 +569,7 @@ CREATE TABLE limit_activity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -582,11 +582,11 @@ CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, @@ -598,7 +598,7 @@ CREATE TABLE limit_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -611,7 +611,7 @@ CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -624,7 +624,7 @@ CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -637,7 +637,7 @@ CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -660,13 +660,13 @@ CREATE TABLE limit_resource CREATE TABLE limit_seasonal_capacity_factor ( region TEXT - REFERENCES Region (region), + REFERENCES region (region), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, @@ -677,11 +677,11 @@ CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -692,11 +692,11 @@ CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -707,11 +707,11 @@ CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -722,11 +722,11 @@ CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -737,9 +737,9 @@ CREATE TABLE limit_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), value REAL, @@ -751,33 +751,33 @@ CREATE TABLE LinkedTech ( primary_region TEXT, primary_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), driven_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); -CREATE TABLE OutputCurtailment +CREATE TABLE output_curtailment ( scenario TEXT, region TEXT, sector TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), curtailment REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); @@ -788,24 +788,24 @@ CREATE TABLE OutputNetCapacity sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE output_built_capacity ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, tech, vintage) ); @@ -816,11 +816,11 @@ CREATE TABLE OutputRetiredCapacity sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cap_eol REAL, cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) @@ -832,19 +832,19 @@ CREATE TABLE OutputFlowIn sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); @@ -855,38 +855,38 @@ CREATE TABLE OutputFlowOut sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputStorageLevel +CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); @@ -894,7 +894,7 @@ CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY - REFERENCES Region (region), + REFERENCES region (region), margin REAL, notes TEXT ); @@ -902,7 +902,7 @@ CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -911,27 +911,27 @@ CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE Region +CREATE TABLE region ( region TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO Region VALUES('region',NULL); +INSERT INTO region VALUES('region',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -941,7 +941,7 @@ CREATE TABLE reserve_capacity_derate CREATE TABLE TimeSegmentFraction ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT @@ -970,9 +970,9 @@ CREATE TABLE lifetime_survival_curve region TEXT NOT NULL, period INTEGER NOT NULL, tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), fraction REAL, notes TEXT, PRIMARY KEY (region, period, tech, vintage) @@ -1033,15 +1033,15 @@ INSERT INTO lifetime_survival_curve VALUES('region',2065,'tech_future',2050,0.62 INSERT INTO lifetime_survival_curve VALUES('region',2070,'tech_future',2050,0.27000000000000001776,NULL); INSERT INTO lifetime_survival_curve VALUES('region',2075,'tech_future',2050,0.08,NULL); INSERT INTO lifetime_survival_curve VALUES('region',2085,'tech_future',2050,0.0,NULL); -CREATE TABLE TechnologyType +CREATE TABLE technologyType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('p','production technology'); -INSERT INTO TechnologyType VALUES('pb','baseload production technology'); -INSERT INTO TechnologyType VALUES('ps','storage production technology'); +INSERT INTO technologyType VALUES('p','production technology'); +INSERT INTO technologyType VALUES('pb','baseload production technology'); +INSERT INTO technologyType VALUES('ps','storage production technology'); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -1049,27 +1049,27 @@ CREATE TABLE TimeOfDay PRIMARY KEY ); INSERT INTO TimeOfDay VALUES(0,'d'); -CREATE TABLE TimePeriod +CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES TimePeriodType (label) -); -INSERT INTO TimePeriod VALUES(-2,1994,'e'); -INSERT INTO TimePeriod VALUES(-1,2010,'e'); -INSERT INTO TimePeriod VALUES(0,2025,'f'); -INSERT INTO TimePeriod VALUES(1,2030,'f'); -INSERT INTO TimePeriod VALUES(2,2035,'f'); -INSERT INTO TimePeriod VALUES(3,2040,'f'); -INSERT INTO TimePeriod VALUES(4,2045,'f'); -INSERT INTO TimePeriod VALUES(5,2050,'f'); -INSERT INTO TimePeriod VALUES(6,2055,'f'); + REFERENCES time_periodType (label) +); +INSERT INTO time_period VALUES(-2,1994,'e'); +INSERT INTO time_period VALUES(-1,2010,'e'); +INSERT INTO time_period VALUES(0,2025,'f'); +INSERT INTO time_period VALUES(1,2030,'f'); +INSERT INTO time_period VALUES(2,2035,'f'); +INSERT INTO time_period VALUES(3,2040,'f'); +INSERT INTO time_period VALUES(4,2045,'f'); +INSERT INTO time_period VALUES(5,2050,'f'); +INSERT INTO time_period VALUES(6,2055,'f'); CREATE TABLE TimeSeason ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, season TEXT REFERENCES SeasonLabel (season), @@ -1085,7 +1085,7 @@ INSERT INTO TimeSeason VALUES(2050,5,'s',NULL); CREATE TABLE time_season_sequential ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, season TEXT @@ -1095,14 +1095,14 @@ CREATE TABLE time_season_sequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE TimePeriodType +CREATE TABLE time_periodType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TimePeriodType VALUES('e','existing vintages'); -INSERT INTO TimePeriodType VALUES('f','future'); +INSERT INTO time_periodType VALUES('e','existing vintages'); +INSERT INTO time_periodType VALUES('f','future'); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1110,22 +1110,22 @@ CREATE TABLE OutputEmission sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); CREATE TABLE RPSRequirement ( region TEXT NOT NULL - REFERENCES Region (region), + REFERENCES region (region), period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_group TEXT NOT NULL REFERENCES TechGroup (group_name), requirement REAL NOT NULL, @@ -1136,10 +1136,10 @@ CREATE TABLE TechGroupMember group_name TEXT REFERENCES TechGroup (group_name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), PRIMARY KEY (group_name, tech) ); -CREATE TABLE Technology +CREATE TABLE technology ( tech TEXT NOT NULL PRIMARY KEY, flag TEXT NOT NULL, @@ -1155,20 +1155,20 @@ CREATE TABLE Technology exchange INTEGER NOT NULL DEFAULT 0, seas_stor INTEGER NOT NULL DEFAULT 0, description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) + FOREIGN KEY (flag) REFERENCES technologyType (label) ); -INSERT INTO Technology VALUES('tech_ancient','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('tech_old','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('tech_current','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('tech_future','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -CREATE TABLE OutputCost +INSERT INTO technology VALUES('tech_ancient','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO technology VALUES('tech_old','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO technology VALUES('tech_current','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO technology VALUES('tech_future','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +CREATE TABLE output_cost ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), d_invest REAL, d_fixed REAL, d_var REAL, @@ -1178,7 +1178,7 @@ CREATE TABLE OutputCost var REAL, emiss REAL, PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) ); COMMIT; diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 32f88b035..0bf5a797f 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -1,16 +1,16 @@ PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE MetaData +CREATE TABLE metadata ( element TEXT, value INT, notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); -CREATE TABLE MetaDataReal +INSERT INTO metadata VALUES('DB_MAJOR',3,'DB major version number'); +INSERT INTO metadata VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO metadata VALUES ('days_per_period', 365, 'count of days in each period'); +CREATE TABLE metadata_real ( element TEXT, value REAL, @@ -18,9 +18,9 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); -CREATE TABLE OutputDualVariable +INSERT INTO metadata_real VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); +INSERT INTO metadata_real VALUES('global_discount_rate',0.05000000000000000277,''); +CREATE TABLE output_dual_variable ( scenario TEXT, constraint_name TEXT, @@ -57,9 +57,9 @@ CREATE TABLE capacity_credit ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, credit REAL, notes TEXT, @@ -70,13 +70,13 @@ CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -87,13 +87,13 @@ CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, tech), @@ -151,7 +151,7 @@ CREATE TABLE CapacityToActivity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), c2a REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -188,50 +188,50 @@ INSERT INTO CapacityToActivity VALUES('R2','R_EH',1.0,''); INSERT INTO CapacityToActivity VALUES('R2','R_NGH',1.0,''); INSERT INTO CapacityToActivity VALUES('R1-R2','E_TRANS',31.53999999999999915,''); INSERT INTO CapacityToActivity VALUES('R2-R1','E_TRANS',31.53999999999999915,''); -CREATE TABLE Commodity +CREATE TABLE commodity ( name TEXT PRIMARY KEY, flag TEXT - REFERENCES CommodityType (label), + REFERENCES commodityType (label), description TEXT ); -INSERT INTO Commodity VALUES('ethos','s','dummy commodity to supply inputs (makes graph easier to read)'); -INSERT INTO Commodity VALUES('OIL','p','crude oil'); -INSERT INTO Commodity VALUES('NG','p','natural gas'); -INSERT INTO Commodity VALUES('URN','p','uranium'); -INSERT INTO Commodity VALUES('ETH','p','ethanol'); -INSERT INTO Commodity VALUES('SOL','p','solar insolation'); -INSERT INTO Commodity VALUES('GSL','p','gasoline'); -INSERT INTO Commodity VALUES('DSL','p','diesel'); -INSERT INTO Commodity VALUES('ELC','p','electricity'); -INSERT INTO Commodity VALUES('E10','p','gasoline blend with 10% ethanol'); -INSERT INTO Commodity VALUES('VMT','d','travel demand for vehicle-miles traveled'); -INSERT INTO Commodity VALUES('RH','d','demand for residential heating'); -INSERT INTO Commodity VALUES('CO2','e','CO2 emissions commodity'); -CREATE TABLE CommodityType +INSERT INTO commodity VALUES('ethos','s','dummy commodity to supply inputs (makes graph easier to read)'); +INSERT INTO commodity VALUES('OIL','p','crude oil'); +INSERT INTO commodity VALUES('NG','p','natural gas'); +INSERT INTO commodity VALUES('URN','p','uranium'); +INSERT INTO commodity VALUES('ETH','p','ethanol'); +INSERT INTO commodity VALUES('SOL','p','solar insolation'); +INSERT INTO commodity VALUES('GSL','p','gasoline'); +INSERT INTO commodity VALUES('DSL','p','diesel'); +INSERT INTO commodity VALUES('ELC','p','electricity'); +INSERT INTO commodity VALUES('E10','p','gasoline blend with 10% ethanol'); +INSERT INTO commodity VALUES('VMT','d','travel demand for vehicle-miles traveled'); +INSERT INTO commodity VALUES('RH','d','demand for residential heating'); +INSERT INTO commodity VALUES('CO2','e','CO2 emissions commodity'); +CREATE TABLE commodityType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO CommodityType VALUES('w','waste commodity'); -INSERT INTO CommodityType VALUES('wa','waste annual commodity'); -INSERT INTO CommodityType VALUES('wp','waste physical commodity'); -INSERT INTO CommodityType VALUES('a','annual commodity'); -INSERT INTO CommodityType VALUES('s','source commodity'); -INSERT INTO CommodityType VALUES('p','physical commodity'); -INSERT INTO CommodityType VALUES('e','emissions commodity'); -INSERT INTO CommodityType VALUES('d','demand commodity'); +INSERT INTO commodityType VALUES('w','waste commodity'); +INSERT INTO commodityType VALUES('wa','waste annual commodity'); +INSERT INTO commodityType VALUES('wp','waste physical commodity'); +INSERT INTO commodityType VALUES('a','annual commodity'); +INSERT INTO commodityType VALUES('s','source commodity'); +INSERT INTO commodityType VALUES('p','physical commodity'); +INSERT INTO commodityType VALUES('e','emissions commodity'); +INSERT INTO commodityType VALUES('d','demand commodity'); CREATE TABLE construction_input ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -241,9 +241,9 @@ CREATE TABLE cost_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT NOT NULL - REFERENCES Commodity (name), + REFERENCES commodity (name), cost REAL NOT NULL, units TEXT, notes TEXT, @@ -253,11 +253,11 @@ CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -315,9 +315,9 @@ CREATE TABLE cost_invest ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -381,11 +381,11 @@ CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -445,103 +445,103 @@ INSERT INTO cost_variable VALUES('R1-R2',2030,'E_TRANS',2015,0.10000000000000000 INSERT INTO cost_variable VALUES('R2-R1',2020,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); INSERT INTO cost_variable VALUES('R2-R1',2025,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); INSERT INTO cost_variable VALUES('R2-R1',2030,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -CREATE TABLE Demand +CREATE TABLE demand ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), commodity TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), demand REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO Demand VALUES('R1',2020,'RH',30.0,'',''); -INSERT INTO Demand VALUES('R1',2025,'RH',33.0,'',''); -INSERT INTO Demand VALUES('R1',2030,'RH',36.0,'',''); -INSERT INTO Demand VALUES('R1',2020,'VMT',84.0,'',''); -INSERT INTO Demand VALUES('R1',2025,'VMT',91.0,'',''); -INSERT INTO Demand VALUES('R1',2030,'VMT',98.0,'',''); -INSERT INTO Demand VALUES('R2',2020,'RH',70.0,'',''); -INSERT INTO Demand VALUES('R2',2025,'RH',77.0,'',''); -INSERT INTO Demand VALUES('R2',2030,'RH',84.0,'',''); -INSERT INTO Demand VALUES('R2',2020,'VMT',36.0,'',''); -INSERT INTO Demand VALUES('R2',2025,'VMT',39.0,'',''); -INSERT INTO Demand VALUES('R2',2030,'VMT',42.0,'',''); -CREATE TABLE DemandSpecificDistribution +INSERT INTO demand VALUES('R1',2020,'RH',30.0,'',''); +INSERT INTO demand VALUES('R1',2025,'RH',33.0,'',''); +INSERT INTO demand VALUES('R1',2030,'RH',36.0,'',''); +INSERT INTO demand VALUES('R1',2020,'VMT',84.0,'',''); +INSERT INTO demand VALUES('R1',2025,'VMT',91.0,'',''); +INSERT INTO demand VALUES('R1',2030,'VMT',98.0,'',''); +INSERT INTO demand VALUES('R2',2020,'RH',70.0,'',''); +INSERT INTO demand VALUES('R2',2025,'RH',77.0,'',''); +INSERT INTO demand VALUES('R2',2030,'RH',84.0,'',''); +INSERT INTO demand VALUES('R2',2020,'VMT',36.0,'',''); +INSERT INTO demand VALUES('R2',2025,'VMT',39.0,'',''); +INSERT INTO demand VALUES('R2',2030,'VMT',42.0,'',''); +CREATE TABLE demand_specific_distribution ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), dsd REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'spring','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'spring','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'summer','day','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'fall','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'fall','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'winter','day','RH',0.2999999999999999889,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'winter','night','RH',0.4000000000000000222,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'spring','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'spring','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'summer','day','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'fall','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'fall','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'winter','day','RH',0.2999999999999999889,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'winter','night','RH',0.4000000000000000222,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'spring','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'spring','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'summer','day','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'fall','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'fall','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'winter','day','RH',0.2999999999999999889,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'winter','night','RH',0.4000000000000000222,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'spring','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'spring','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'summer','day','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'fall','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'fall','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'winter','day','RH',0.2999999999999999889,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'winter','night','RH',0.4000000000000000222,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'spring','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'spring','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'summer','day','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'fall','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'fall','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'winter','day','RH',0.2999999999999999889,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'winter','night','RH',0.4000000000000000222,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'spring','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'spring','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'summer','day','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'fall','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'fall','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'winter','day','RH',0.2999999999999999889,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'winter','night','RH',0.4000000000000000222,''); +INSERT INTO demand_specific_distribution VALUES('R1',2020,'spring','day','RH',0.05000000000000000277,''); +INSERT INTO demand_specific_distribution VALUES('R1',2020,'spring','night','RH',0.1000000000000000055,''); +INSERT INTO demand_specific_distribution VALUES('R1',2020,'summer','day','RH',0.0,''); +INSERT INTO demand_specific_distribution VALUES('R1',2020,'summer','night','RH',0.0,''); +INSERT INTO demand_specific_distribution VALUES('R1',2020,'fall','day','RH',0.05000000000000000277,''); +INSERT INTO demand_specific_distribution VALUES('R1',2020,'fall','night','RH',0.1000000000000000055,''); +INSERT INTO demand_specific_distribution VALUES('R1',2020,'winter','day','RH',0.2999999999999999889,''); +INSERT INTO demand_specific_distribution VALUES('R1',2020,'winter','night','RH',0.4000000000000000222,''); +INSERT INTO demand_specific_distribution VALUES('R2',2020,'spring','day','RH',0.05000000000000000277,''); +INSERT INTO demand_specific_distribution VALUES('R2',2020,'spring','night','RH',0.1000000000000000055,''); +INSERT INTO demand_specific_distribution VALUES('R2',2020,'summer','day','RH',0.0,''); +INSERT INTO demand_specific_distribution VALUES('R2',2020,'summer','night','RH',0.0,''); +INSERT INTO demand_specific_distribution VALUES('R2',2020,'fall','day','RH',0.05000000000000000277,''); +INSERT INTO demand_specific_distribution VALUES('R2',2020,'fall','night','RH',0.1000000000000000055,''); +INSERT INTO demand_specific_distribution VALUES('R2',2020,'winter','day','RH',0.2999999999999999889,''); +INSERT INTO demand_specific_distribution VALUES('R2',2020,'winter','night','RH',0.4000000000000000222,''); +INSERT INTO demand_specific_distribution VALUES('R1',2025,'spring','day','RH',0.05000000000000000277,''); +INSERT INTO demand_specific_distribution VALUES('R1',2025,'spring','night','RH',0.1000000000000000055,''); +INSERT INTO demand_specific_distribution VALUES('R1',2025,'summer','day','RH',0.0,''); +INSERT INTO demand_specific_distribution VALUES('R1',2025,'summer','night','RH',0.0,''); +INSERT INTO demand_specific_distribution VALUES('R1',2025,'fall','day','RH',0.05000000000000000277,''); +INSERT INTO demand_specific_distribution VALUES('R1',2025,'fall','night','RH',0.1000000000000000055,''); +INSERT INTO demand_specific_distribution VALUES('R1',2025,'winter','day','RH',0.2999999999999999889,''); +INSERT INTO demand_specific_distribution VALUES('R1',2025,'winter','night','RH',0.4000000000000000222,''); +INSERT INTO demand_specific_distribution VALUES('R2',2025,'spring','day','RH',0.05000000000000000277,''); +INSERT INTO demand_specific_distribution VALUES('R2',2025,'spring','night','RH',0.1000000000000000055,''); +INSERT INTO demand_specific_distribution VALUES('R2',2025,'summer','day','RH',0.0,''); +INSERT INTO demand_specific_distribution VALUES('R2',2025,'summer','night','RH',0.0,''); +INSERT INTO demand_specific_distribution VALUES('R2',2025,'fall','day','RH',0.05000000000000000277,''); +INSERT INTO demand_specific_distribution VALUES('R2',2025,'fall','night','RH',0.1000000000000000055,''); +INSERT INTO demand_specific_distribution VALUES('R2',2025,'winter','day','RH',0.2999999999999999889,''); +INSERT INTO demand_specific_distribution VALUES('R2',2025,'winter','night','RH',0.4000000000000000222,''); +INSERT INTO demand_specific_distribution VALUES('R1',2030,'spring','day','RH',0.05000000000000000277,''); +INSERT INTO demand_specific_distribution VALUES('R1',2030,'spring','night','RH',0.1000000000000000055,''); +INSERT INTO demand_specific_distribution VALUES('R1',2030,'summer','day','RH',0.0,''); +INSERT INTO demand_specific_distribution VALUES('R1',2030,'summer','night','RH',0.0,''); +INSERT INTO demand_specific_distribution VALUES('R1',2030,'fall','day','RH',0.05000000000000000277,''); +INSERT INTO demand_specific_distribution VALUES('R1',2030,'fall','night','RH',0.1000000000000000055,''); +INSERT INTO demand_specific_distribution VALUES('R1',2030,'winter','day','RH',0.2999999999999999889,''); +INSERT INTO demand_specific_distribution VALUES('R1',2030,'winter','night','RH',0.4000000000000000222,''); +INSERT INTO demand_specific_distribution VALUES('R2',2030,'spring','day','RH',0.05000000000000000277,''); +INSERT INTO demand_specific_distribution VALUES('R2',2030,'spring','night','RH',0.1000000000000000055,''); +INSERT INTO demand_specific_distribution VALUES('R2',2030,'summer','day','RH',0.0,''); +INSERT INTO demand_specific_distribution VALUES('R2',2030,'summer','night','RH',0.0,''); +INSERT INTO demand_specific_distribution VALUES('R2',2030,'fall','day','RH',0.05000000000000000277,''); +INSERT INTO demand_specific_distribution VALUES('R2',2030,'fall','night','RH',0.1000000000000000055,''); +INSERT INTO demand_specific_distribution VALUES('R2',2030,'winter','day','RH',0.2999999999999999889,''); +INSERT INTO demand_specific_distribution VALUES('R2',2030,'winter','night','RH',0.4000000000000000222,''); CREATE TABLE end_of_life_output ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), value REAL, units TEXT, notes TEXT, @@ -551,13 +551,13 @@ CREATE TABLE efficiency ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage, output_comm), @@ -641,19 +641,19 @@ CREATE TABLE efficiency_variable ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), @@ -663,15 +663,15 @@ CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), activity REAL, units TEXT, notes TEXT, @@ -687,11 +687,11 @@ CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -701,11 +701,11 @@ CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -715,9 +715,9 @@ CREATE TABLE existing_capacity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, units TEXT, notes TEXT, @@ -737,9 +737,9 @@ CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -748,9 +748,9 @@ CREATE TABLE loan_rate ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), rate REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -759,9 +759,9 @@ CREATE TABLE lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -770,7 +770,7 @@ CREATE TABLE lifetime_tech ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -891,15 +891,15 @@ CREATE TABLE LimitStorageLevelFraction ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), fraction REAL, @@ -912,7 +912,7 @@ CREATE TABLE limit_activity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -931,7 +931,7 @@ CREATE TABLE limit_activity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -944,11 +944,11 @@ CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, @@ -960,7 +960,7 @@ CREATE TABLE limit_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -973,7 +973,7 @@ CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -986,7 +986,7 @@ CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -999,7 +999,7 @@ CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -1022,13 +1022,13 @@ CREATE TABLE limit_resource CREATE TABLE limit_seasonal_capacity_factor ( region TEXT - REFERENCES Region (region), + REFERENCES region (region), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, @@ -1039,11 +1039,11 @@ CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -1066,11 +1066,11 @@ CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -1081,11 +1081,11 @@ CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -1108,11 +1108,11 @@ CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -1123,9 +1123,9 @@ CREATE TABLE limit_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), value REAL, @@ -1143,33 +1143,33 @@ CREATE TABLE LinkedTech ( primary_region TEXT, primary_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), driven_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); -CREATE TABLE OutputCurtailment +CREATE TABLE output_curtailment ( scenario TEXT, region TEXT, sector TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), curtailment REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); @@ -1180,24 +1180,24 @@ CREATE TABLE OutputNetCapacity sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE output_built_capacity ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, tech, vintage) ); @@ -1208,11 +1208,11 @@ CREATE TABLE OutputRetiredCapacity sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cap_eol REAL, cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) @@ -1224,19 +1224,19 @@ CREATE TABLE OutputFlowIn sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); @@ -1247,38 +1247,38 @@ CREATE TABLE OutputFlowOut sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputStorageLevel +CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); @@ -1286,7 +1286,7 @@ CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY - REFERENCES Region (region), + REFERENCES region (region), margin REAL, notes TEXT ); @@ -1294,7 +1294,7 @@ CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -1303,28 +1303,28 @@ CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE Region +CREATE TABLE region ( region TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO Region VALUES('R1',NULL); -INSERT INTO Region VALUES('R2',NULL); +INSERT INTO region VALUES('R1',NULL); +INSERT INTO region VALUES('R2',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -1334,7 +1334,7 @@ CREATE TABLE reserve_capacity_derate CREATE TABLE TimeSegmentFraction ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT @@ -1383,22 +1383,22 @@ CREATE TABLE lifetime_survival_curve region TEXT NOT NULL, period INTEGER NOT NULL, tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), fraction REAL, notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE TechnologyType +CREATE TABLE technologyType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('p','production technology'); -INSERT INTO TechnologyType VALUES('pb','baseload production technology'); -INSERT INTO TechnologyType VALUES('ps','storage production technology'); +INSERT INTO technologyType VALUES('p','production technology'); +INSERT INTO technologyType VALUES('pb','baseload production technology'); +INSERT INTO technologyType VALUES('ps','storage production technology'); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -1407,23 +1407,23 @@ CREATE TABLE TimeOfDay ); INSERT INTO TimeOfDay VALUES(1,'day'); INSERT INTO TimeOfDay VALUES(2,'night'); -CREATE TABLE TimePeriod +CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES TimePeriodType (label) + REFERENCES time_periodType (label) ); -INSERT INTO TimePeriod VALUES(1,2015,'e'); -INSERT INTO TimePeriod VALUES(2,2020,'f'); -INSERT INTO TimePeriod VALUES(3,2025,'f'); -INSERT INTO TimePeriod VALUES(4,2030,'f'); -INSERT INTO TimePeriod VALUES(5,2035,'f'); +INSERT INTO time_period VALUES(1,2015,'e'); +INSERT INTO time_period VALUES(2,2020,'f'); +INSERT INTO time_period VALUES(3,2025,'f'); +INSERT INTO time_period VALUES(4,2030,'f'); +INSERT INTO time_period VALUES(5,2035,'f'); CREATE TABLE TimeSeason ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, season TEXT REFERENCES SeasonLabel (season), @@ -1445,7 +1445,7 @@ INSERT INTO TimeSeason VALUES(2030,4,'winter',NULL); CREATE TABLE time_season_sequential ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, season TEXT @@ -1455,14 +1455,14 @@ CREATE TABLE time_season_sequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE TimePeriodType +CREATE TABLE time_periodType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TimePeriodType VALUES('e','existing vintages'); -INSERT INTO TimePeriodType VALUES('f','future'); +INSERT INTO time_periodType VALUES('e','existing vintages'); +INSERT INTO time_periodType VALUES('f','future'); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1470,22 +1470,22 @@ CREATE TABLE OutputEmission sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); CREATE TABLE RPSRequirement ( region TEXT NOT NULL - REFERENCES Region (region), + REFERENCES region (region), period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_group TEXT NOT NULL REFERENCES TechGroup (group_name), requirement REAL NOT NULL, @@ -1496,10 +1496,10 @@ CREATE TABLE TechGroupMember group_name TEXT REFERENCES TechGroup (group_name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), PRIMARY KEY (group_name, tech) ); -CREATE TABLE Technology +CREATE TABLE technology ( tech TEXT NOT NULL PRIMARY KEY, flag TEXT NOT NULL, @@ -1515,32 +1515,32 @@ CREATE TABLE Technology exchange INTEGER NOT NULL DEFAULT 0, seas_stor INTEGER NOT NULL DEFAULT 0, description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) -); -INSERT INTO Technology VALUES('S_IMPETH','p','supply','','',1,0,0,0,0,0,0,0,' imported ethanol'); -INSERT INTO Technology VALUES('S_IMPOIL','p','supply','','',1,0,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO Technology VALUES('S_IMPNG','p','supply','','',1,0,0,0,0,0,0,0,' imported natural gas'); -INSERT INTO Technology VALUES('S_IMPURN','p','supply','','',1,0,0,0,0,0,0,0,' imported uranium'); -INSERT INTO Technology VALUES('S_OILREF','p','supply','','',0,0,0,1,0,0,0,0,' crude oil refinery'); -INSERT INTO Technology VALUES('E_NGCC','p','electric','','',0,0,0,0,0,0,0,0,' natural gas combined-cycle'); -INSERT INTO Technology VALUES('E_SOLPV','p','electric','','',0,0,0,0,0,0,0,0,' solar photovoltaic'); -INSERT INTO Technology VALUES('E_BATT','ps','electric','','',0,0,0,0,0,0,0,0,' lithium-ion battery'); -INSERT INTO Technology VALUES('E_NUCLEAR','pb','electric','','',0,0,0,0,0,0,0,0,' nuclear power plant'); -INSERT INTO Technology VALUES('T_BLND','p','transport','','',0,0,0,0,0,0,0,0,'ethanol - gasoline blending process'); -INSERT INTO Technology VALUES('T_DSL','p','transport','','',0,0,0,0,0,0,0,0,'diesel vehicle'); -INSERT INTO Technology VALUES('T_GSL','p','transport','','',0,0,0,0,0,0,0,0,'gasoline vehicle'); -INSERT INTO Technology VALUES('T_EV','p','transport','','',0,0,0,0,0,0,0,0,'electric vehicle'); -INSERT INTO Technology VALUES('R_EH','p','residential','','',0,0,0,0,0,0,0,0,' electric residential heating'); -INSERT INTO Technology VALUES('R_NGH','p','residential','','',0,0,0,0,0,0,0,0,' natural gas residential heating'); -INSERT INTO Technology VALUES('E_TRANS','p','electric','','',0,0,0,0,0,0,1,0,'electric transmission'); -CREATE TABLE OutputCost + FOREIGN KEY (flag) REFERENCES technologyType (label) +); +INSERT INTO technology VALUES('S_IMPETH','p','supply','','',1,0,0,0,0,0,0,0,' imported ethanol'); +INSERT INTO technology VALUES('S_IMPOIL','p','supply','','',1,0,0,0,0,0,0,0,' imported crude oil'); +INSERT INTO technology VALUES('S_IMPNG','p','supply','','',1,0,0,0,0,0,0,0,' imported natural gas'); +INSERT INTO technology VALUES('S_IMPURN','p','supply','','',1,0,0,0,0,0,0,0,' imported uranium'); +INSERT INTO technology VALUES('S_OILREF','p','supply','','',0,0,0,1,0,0,0,0,' crude oil refinery'); +INSERT INTO technology VALUES('E_NGCC','p','electric','','',0,0,0,0,0,0,0,0,' natural gas combined-cycle'); +INSERT INTO technology VALUES('E_SOLPV','p','electric','','',0,0,0,0,0,0,0,0,' solar photovoltaic'); +INSERT INTO technology VALUES('E_BATT','ps','electric','','',0,0,0,0,0,0,0,0,' lithium-ion battery'); +INSERT INTO technology VALUES('E_NUCLEAR','pb','electric','','',0,0,0,0,0,0,0,0,' nuclear power plant'); +INSERT INTO technology VALUES('T_BLND','p','transport','','',0,0,0,0,0,0,0,0,'ethanol - gasoline blending process'); +INSERT INTO technology VALUES('T_DSL','p','transport','','',0,0,0,0,0,0,0,0,'diesel vehicle'); +INSERT INTO technology VALUES('T_GSL','p','transport','','',0,0,0,0,0,0,0,0,'gasoline vehicle'); +INSERT INTO technology VALUES('T_EV','p','transport','','',0,0,0,0,0,0,0,0,'electric vehicle'); +INSERT INTO technology VALUES('R_EH','p','residential','','',0,0,0,0,0,0,0,0,' electric residential heating'); +INSERT INTO technology VALUES('R_NGH','p','residential','','',0,0,0,0,0,0,0,0,' natural gas residential heating'); +INSERT INTO technology VALUES('E_TRANS','p','electric','','',0,0,0,0,0,0,1,0,'electric transmission'); +CREATE TABLE output_cost ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), d_invest REAL, d_fixed REAL, d_var REAL, @@ -1550,7 +1550,7 @@ CREATE TABLE OutputCost var REAL, emiss REAL, PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) ); COMMIT; diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 6cc795edb..4745911b7 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -1,16 +1,16 @@ PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE MetaData +CREATE TABLE metadata ( element TEXT, value INT, notes TEXT, PRIMARY KEY (element) ); -INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); -CREATE TABLE MetaDataReal +INSERT INTO metadata VALUES('DB_MAJOR',3,'DB major version number'); +INSERT INTO metadata VALUES('DB_MINOR',1,'DB minor version number'); +INSERT INTO metadata VALUES ('days_per_period', 365, 'count of days in each period'); +CREATE TABLE metadata_real ( element TEXT, value REAL, @@ -18,9 +18,9 @@ CREATE TABLE MetaDataReal PRIMARY KEY (element) ); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); -CREATE TABLE OutputDualVariable +INSERT INTO metadata_real VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); +INSERT INTO metadata_real VALUES('global_discount_rate',0.05000000000000000277,''); +CREATE TABLE output_dual_variable ( scenario TEXT, constraint_name TEXT, @@ -56,9 +56,9 @@ CREATE TABLE capacity_credit ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, credit REAL, notes TEXT, @@ -69,13 +69,13 @@ CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -104,13 +104,13 @@ CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, tech), @@ -210,7 +210,7 @@ CREATE TABLE CapacityToActivity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), c2a REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -227,51 +227,51 @@ INSERT INTO CapacityToActivity VALUES('utopia','SRE',1.0,''); INSERT INTO CapacityToActivity VALUES('utopia','TXD',1.0,''); INSERT INTO CapacityToActivity VALUES('utopia','TXE',1.0,''); INSERT INTO CapacityToActivity VALUES('utopia','TXG',1.0,''); -CREATE TABLE Commodity +CREATE TABLE commodity ( name TEXT PRIMARY KEY, flag TEXT - REFERENCES CommodityType (label), + REFERENCES commodityType (label), description TEXT ); -INSERT INTO Commodity VALUES('ethos','s','# dummy commodity to supply inputs (makes graph easier to read)'); -INSERT INTO Commodity VALUES('DSL','p','# diesel'); -INSERT INTO Commodity VALUES('ELC','p','# electricity'); -INSERT INTO Commodity VALUES('FEQ','p','# fossil equivalent'); -INSERT INTO Commodity VALUES('GSL','p','# gasoline'); -INSERT INTO Commodity VALUES('HCO','p','# coal'); -INSERT INTO Commodity VALUES('HYD','p','# water'); -INSERT INTO Commodity VALUES('OIL','p','# crude oil'); -INSERT INTO Commodity VALUES('URN','p','# uranium'); -INSERT INTO Commodity VALUES('co2','e','#CO2 emissions'); -INSERT INTO Commodity VALUES('nox','e','#NOX emissions'); -INSERT INTO Commodity VALUES('RH','d','# residential heating'); -INSERT INTO Commodity VALUES('RL','d','# residential lighting'); -INSERT INTO Commodity VALUES('TX','d','# transportation'); -CREATE TABLE CommodityType +INSERT INTO commodity VALUES('ethos','s','# dummy commodity to supply inputs (makes graph easier to read)'); +INSERT INTO commodity VALUES('DSL','p','# diesel'); +INSERT INTO commodity VALUES('ELC','p','# electricity'); +INSERT INTO commodity VALUES('FEQ','p','# fossil equivalent'); +INSERT INTO commodity VALUES('GSL','p','# gasoline'); +INSERT INTO commodity VALUES('HCO','p','# coal'); +INSERT INTO commodity VALUES('HYD','p','# water'); +INSERT INTO commodity VALUES('OIL','p','# crude oil'); +INSERT INTO commodity VALUES('URN','p','# uranium'); +INSERT INTO commodity VALUES('co2','e','#CO2 emissions'); +INSERT INTO commodity VALUES('nox','e','#NOX emissions'); +INSERT INTO commodity VALUES('RH','d','# residential heating'); +INSERT INTO commodity VALUES('RL','d','# residential lighting'); +INSERT INTO commodity VALUES('TX','d','# transportation'); +CREATE TABLE commodityType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO CommodityType VALUES('w','waste commodity'); -INSERT INTO CommodityType VALUES('wa','waste annual commodity'); -INSERT INTO CommodityType VALUES('wp','waste physical commodity'); -INSERT INTO CommodityType VALUES('a','annual commodity'); -INSERT INTO CommodityType VALUES('s','source commodity'); -INSERT INTO CommodityType VALUES('p','physical commodity'); -INSERT INTO CommodityType VALUES('e','emissions commodity'); -INSERT INTO CommodityType VALUES('d','demand commodity'); +INSERT INTO commodityType VALUES('w','waste commodity'); +INSERT INTO commodityType VALUES('wa','waste annual commodity'); +INSERT INTO commodityType VALUES('wp','waste physical commodity'); +INSERT INTO commodityType VALUES('a','annual commodity'); +INSERT INTO commodityType VALUES('s','source commodity'); +INSERT INTO commodityType VALUES('p','physical commodity'); +INSERT INTO commodityType VALUES('e','emissions commodity'); +INSERT INTO commodityType VALUES('d','demand commodity'); CREATE TABLE construction_input ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -281,9 +281,9 @@ CREATE TABLE cost_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT NOT NULL - REFERENCES Commodity (name), + REFERENCES commodity (name), cost REAL NOT NULL, units TEXT, notes TEXT, @@ -293,11 +293,11 @@ CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -389,9 +389,9 @@ CREATE TABLE cost_invest ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -434,11 +434,11 @@ CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -495,82 +495,82 @@ INSERT INTO cost_variable VALUES('utopia',2000,'SRE',2000,10.0,'',''); INSERT INTO cost_variable VALUES('utopia',2010,'SRE',1990,10.0,'',''); INSERT INTO cost_variable VALUES('utopia',2010,'SRE',2000,10.0,'',''); INSERT INTO cost_variable VALUES('utopia',2010,'SRE',2010,10.0,'',''); -CREATE TABLE Demand +CREATE TABLE demand ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), commodity TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), demand REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO Demand VALUES('utopia',1990,'RH',25.19999999999999929,'',''); -INSERT INTO Demand VALUES('utopia',2000,'RH',37.79999999999999715,'',''); -INSERT INTO Demand VALUES('utopia',2010,'RH',56.69999999999999574,'',''); -INSERT INTO Demand VALUES('utopia',1990,'RL',5.599999999999999645,'',''); -INSERT INTO Demand VALUES('utopia',2000,'RL',8.400000000000000355,'',''); -INSERT INTO Demand VALUES('utopia',2010,'RL',12.59999999999999965,'',''); -INSERT INTO Demand VALUES('utopia',1990,'TX',5.200000000000000177,'',''); -INSERT INTO Demand VALUES('utopia',2000,'TX',7.799999999999999823,'',''); -INSERT INTO Demand VALUES('utopia',2010,'TX',11.68999999999999951,'',''); -CREATE TABLE DemandSpecificDistribution +INSERT INTO demand VALUES('utopia',1990,'RH',25.19999999999999929,'',''); +INSERT INTO demand VALUES('utopia',2000,'RH',37.79999999999999715,'',''); +INSERT INTO demand VALUES('utopia',2010,'RH',56.69999999999999574,'',''); +INSERT INTO demand VALUES('utopia',1990,'RL',5.599999999999999645,'',''); +INSERT INTO demand VALUES('utopia',2000,'RL',8.400000000000000355,'',''); +INSERT INTO demand VALUES('utopia',2010,'RL',12.59999999999999965,'',''); +INSERT INTO demand VALUES('utopia',1990,'TX',5.200000000000000177,'',''); +INSERT INTO demand VALUES('utopia',2000,'TX',7.799999999999999823,'',''); +INSERT INTO demand VALUES('utopia',2010,'TX',11.68999999999999951,'',''); +CREATE TABLE demand_specific_distribution ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), demand_name TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), dsd REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RH',0.1199999999999999956,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RH',0.05999999999999999778,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','day','RH',0.5466999999999999638,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RH',0.2732999999999999874,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RL',0.1499999999999999945,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RL',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','day','RL',0.1499999999999999945,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','night','RL',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','day','RL',0.5,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RL',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RH',0.1199999999999999956,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RH',0.05999999999999999778,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','day','RH',0.5466999999999999638,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RH',0.2732999999999999874,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RL',0.1499999999999999945,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RL',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','day','RL',0.1499999999999999945,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','night','RL',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','day','RL',0.5,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RL',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RH',0.1199999999999999956,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RH',0.05999999999999999778,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RH',0.5466999999999999638,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RH',0.2732999999999999874,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RL',0.1499999999999999945,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RL',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','day','RL',0.1499999999999999945,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','night','RL',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RL',0.5,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RL',0.1000000000000000055,''); +INSERT INTO demand_specific_distribution VALUES('utopia',1990,'inter','day','RH',0.1199999999999999956,''); +INSERT INTO demand_specific_distribution VALUES('utopia',1990,'inter','night','RH',0.05999999999999999778,''); +INSERT INTO demand_specific_distribution VALUES('utopia',1990,'winter','day','RH',0.5466999999999999638,''); +INSERT INTO demand_specific_distribution VALUES('utopia',1990,'winter','night','RH',0.2732999999999999874,''); +INSERT INTO demand_specific_distribution VALUES('utopia',1990,'inter','day','RL',0.1499999999999999945,''); +INSERT INTO demand_specific_distribution VALUES('utopia',1990,'inter','night','RL',0.05000000000000000277,''); +INSERT INTO demand_specific_distribution VALUES('utopia',1990,'summer','day','RL',0.1499999999999999945,''); +INSERT INTO demand_specific_distribution VALUES('utopia',1990,'summer','night','RL',0.05000000000000000277,''); +INSERT INTO demand_specific_distribution VALUES('utopia',1990,'winter','day','RL',0.5,''); +INSERT INTO demand_specific_distribution VALUES('utopia',1990,'winter','night','RL',0.1000000000000000055,''); +INSERT INTO demand_specific_distribution VALUES('utopia',2000,'inter','day','RH',0.1199999999999999956,''); +INSERT INTO demand_specific_distribution VALUES('utopia',2000,'inter','night','RH',0.05999999999999999778,''); +INSERT INTO demand_specific_distribution VALUES('utopia',2000,'winter','day','RH',0.5466999999999999638,''); +INSERT INTO demand_specific_distribution VALUES('utopia',2000,'winter','night','RH',0.2732999999999999874,''); +INSERT INTO demand_specific_distribution VALUES('utopia',2000,'inter','day','RL',0.1499999999999999945,''); +INSERT INTO demand_specific_distribution VALUES('utopia',2000,'inter','night','RL',0.05000000000000000277,''); +INSERT INTO demand_specific_distribution VALUES('utopia',2000,'summer','day','RL',0.1499999999999999945,''); +INSERT INTO demand_specific_distribution VALUES('utopia',2000,'summer','night','RL',0.05000000000000000277,''); +INSERT INTO demand_specific_distribution VALUES('utopia',2000,'winter','day','RL',0.5,''); +INSERT INTO demand_specific_distribution VALUES('utopia',2000,'winter','night','RL',0.1000000000000000055,''); +INSERT INTO demand_specific_distribution VALUES('utopia',2010,'inter','day','RH',0.1199999999999999956,''); +INSERT INTO demand_specific_distribution VALUES('utopia',2010,'inter','night','RH',0.05999999999999999778,''); +INSERT INTO demand_specific_distribution VALUES('utopia',2010,'winter','day','RH',0.5466999999999999638,''); +INSERT INTO demand_specific_distribution VALUES('utopia',2010,'winter','night','RH',0.2732999999999999874,''); +INSERT INTO demand_specific_distribution VALUES('utopia',2010,'inter','day','RL',0.1499999999999999945,''); +INSERT INTO demand_specific_distribution VALUES('utopia',2010,'inter','night','RL',0.05000000000000000277,''); +INSERT INTO demand_specific_distribution VALUES('utopia',2010,'summer','day','RL',0.1499999999999999945,''); +INSERT INTO demand_specific_distribution VALUES('utopia',2010,'summer','night','RL',0.05000000000000000277,''); +INSERT INTO demand_specific_distribution VALUES('utopia',2010,'winter','day','RL',0.5,''); +INSERT INTO demand_specific_distribution VALUES('utopia',2010,'winter','night','RL',0.1000000000000000055,''); CREATE TABLE end_of_life_output ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), value REAL, units TEXT, notes TEXT, @@ -580,13 +580,13 @@ CREATE TABLE efficiency ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage, output_comm), @@ -660,19 +660,19 @@ CREATE TABLE efficiency_variable ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), @@ -682,15 +682,15 @@ CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), activity REAL, units TEXT, notes TEXT, @@ -714,11 +714,11 @@ CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -728,11 +728,11 @@ CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -742,9 +742,9 @@ CREATE TABLE existing_capacity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, units TEXT, notes TEXT, @@ -775,9 +775,9 @@ CREATE TABLE loan_lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -786,9 +786,9 @@ CREATE TABLE loan_rate ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), rate REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -797,9 +797,9 @@ CREATE TABLE lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) @@ -813,7 +813,7 @@ CREATE TABLE lifetime_tech ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -921,15 +921,15 @@ CREATE TABLE LimitStorageLevelFraction ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), fraction REAL, @@ -940,7 +940,7 @@ CREATE TABLE limit_activity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -953,7 +953,7 @@ CREATE TABLE limit_activity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -966,11 +966,11 @@ CREATE TABLE limit_annual_capacity_factor ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, @@ -982,7 +982,7 @@ CREATE TABLE limit_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -1006,7 +1006,7 @@ CREATE TABLE limit_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -1019,7 +1019,7 @@ CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), @@ -1032,7 +1032,7 @@ CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" @@ -1055,13 +1055,13 @@ CREATE TABLE limit_resource CREATE TABLE limit_seasonal_capacity_factor ( region TEXT - REFERENCES Region (region), + REFERENCES region (region), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, @@ -1072,11 +1072,11 @@ CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -1087,11 +1087,11 @@ CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -1102,11 +1102,11 @@ CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -1123,11 +1123,11 @@ CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), proportion REAL, @@ -1138,9 +1138,9 @@ CREATE TABLE limit_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), value REAL, @@ -1152,33 +1152,33 @@ CREATE TABLE LinkedTech ( primary_region TEXT, primary_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), driven_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); -CREATE TABLE OutputCurtailment +CREATE TABLE output_curtailment ( scenario TEXT, region TEXT, sector TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), curtailment REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); @@ -1189,24 +1189,24 @@ CREATE TABLE OutputNetCapacity sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, period, tech, vintage) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE output_built_capacity ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, tech, vintage) ); @@ -1217,11 +1217,11 @@ CREATE TABLE OutputRetiredCapacity sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cap_eol REAL, cap_early REAL, PRIMARY KEY (region, scenario, period, tech, vintage) @@ -1233,19 +1233,19 @@ CREATE TABLE OutputFlowIn sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); @@ -1256,38 +1256,38 @@ CREATE TABLE OutputFlowOut sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputStorageLevel +CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); @@ -1295,7 +1295,7 @@ CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY - REFERENCES Region (region), + REFERENCES region (region), margin REAL, notes TEXT ); @@ -1303,7 +1303,7 @@ CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -1312,27 +1312,27 @@ CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE Region +CREATE TABLE region ( region TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO Region VALUES('utopia',NULL); +INSERT INTO region VALUES('utopia',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -1342,7 +1342,7 @@ CREATE TABLE reserve_capacity_derate CREATE TABLE TimeSegmentFraction ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT @@ -1383,22 +1383,22 @@ CREATE TABLE lifetime_survival_curve region TEXT NOT NULL, period INTEGER NOT NULL, tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), fraction REAL, notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE TechnologyType +CREATE TABLE technologyType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('p','production technology'); -INSERT INTO TechnologyType VALUES('pb','baseload production technology'); -INSERT INTO TechnologyType VALUES('ps','storage production technology'); +INSERT INTO technologyType VALUES('p','production technology'); +INSERT INTO technologyType VALUES('pb','baseload production technology'); +INSERT INTO technologyType VALUES('ps','storage production technology'); CREATE TABLE TimeOfDay ( sequence INTEGER UNIQUE, @@ -1407,25 +1407,25 @@ CREATE TABLE TimeOfDay ); INSERT INTO TimeOfDay VALUES(1,'day'); INSERT INTO TimeOfDay VALUES(2,'night'); -CREATE TABLE TimePeriod +CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES TimePeriodType (label) -); -INSERT INTO TimePeriod VALUES(1,1960,'e'); -INSERT INTO TimePeriod VALUES(2,1970,'e'); -INSERT INTO TimePeriod VALUES(3,1980,'e'); -INSERT INTO TimePeriod VALUES(4,1990,'f'); -INSERT INTO TimePeriod VALUES(5,2000,'f'); -INSERT INTO TimePeriod VALUES(6,2010,'f'); -INSERT INTO TimePeriod VALUES(7,2020,'f'); + REFERENCES time_periodType (label) +); +INSERT INTO time_period VALUES(1,1960,'e'); +INSERT INTO time_period VALUES(2,1970,'e'); +INSERT INTO time_period VALUES(3,1980,'e'); +INSERT INTO time_period VALUES(4,1990,'f'); +INSERT INTO time_period VALUES(5,2000,'f'); +INSERT INTO time_period VALUES(6,2010,'f'); +INSERT INTO time_period VALUES(7,2020,'f'); CREATE TABLE TimeSeason ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, season TEXT REFERENCES SeasonLabel (season), @@ -1444,7 +1444,7 @@ INSERT INTO TimeSeason VALUES(2010,3,'winter',NULL); CREATE TABLE time_season_sequential ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, season TEXT @@ -1454,14 +1454,14 @@ CREATE TABLE time_season_sequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE TimePeriodType +CREATE TABLE time_periodType ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TimePeriodType VALUES('e','existing vintages'); -INSERT INTO TimePeriodType VALUES('f','future'); +INSERT INTO time_periodType VALUES('e','existing vintages'); +INSERT INTO time_periodType VALUES('f','future'); CREATE TABLE OutputEmission ( scenario TEXT, @@ -1469,22 +1469,22 @@ CREATE TABLE OutputEmission sector TEXT REFERENCES SectorLabel (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emission REAL, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); CREATE TABLE RPSRequirement ( region TEXT NOT NULL - REFERENCES Region (region), + REFERENCES region (region), period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_group TEXT NOT NULL REFERENCES TechGroup (group_name), requirement REAL NOT NULL, @@ -1495,10 +1495,10 @@ CREATE TABLE TechGroupMember group_name TEXT REFERENCES TechGroup (group_name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), PRIMARY KEY (group_name, tech) ); -CREATE TABLE Technology +CREATE TABLE technology ( tech TEXT NOT NULL PRIMARY KEY, flag TEXT NOT NULL, @@ -1514,35 +1514,35 @@ CREATE TABLE Technology exchange INTEGER NOT NULL DEFAULT 0, seas_stor INTEGER NOT NULL DEFAULT 0, description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) -); -INSERT INTO Technology VALUES('IMPDSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported diesel'); -INSERT INTO Technology VALUES('IMPGSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported gasoline'); -INSERT INTO Technology VALUES('IMPHCO1','p','supply','coal','',1,0,0,0,0,0,0,0,' imported coal'); -INSERT INTO Technology VALUES('IMPOIL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO Technology VALUES('IMPURN1','p','supply','nuclear','',1,0,0,0,0,0,0,0,' imported uranium'); -INSERT INTO Technology VALUES('IMPFEQ','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported fossil equivalent'); -INSERT INTO Technology VALUES('IMPHYD','p','supply','hydro','',1,0,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); -INSERT INTO Technology VALUES('E01','pb','electric','coal','',0,0,0,0,0,0,0,0,' coal power plant'); -INSERT INTO Technology VALUES('E21','pb','electric','nuclear','',0,0,0,0,0,0,0,0,' nuclear power plant'); -INSERT INTO Technology VALUES('E31','pb','electric','hydro','',0,0,0,0,0,0,0,0,' hydro power'); -INSERT INTO Technology VALUES('E51','ps','electric','electric','',0,0,0,0,0,0,0,0,' electric storage'); -INSERT INTO Technology VALUES('E70','p','electric','petroleum','',0,0,0,0,0,0,0,0,' diesel power plant'); -INSERT INTO Technology VALUES('RHE','p','residential','electric','',0,0,0,0,0,0,0,0,' electric residential heating'); -INSERT INTO Technology VALUES('RHO','p','residential','petroleum','',0,0,0,0,0,0,0,0,' diesel residential heating'); -INSERT INTO Technology VALUES('RL1','p','residential','electric','',0,0,0,0,0,0,0,0,' residential lighting'); -INSERT INTO Technology VALUES('SRE','p','supply','petroleum','',0,0,0,0,0,0,0,0,' crude oil processor'); -INSERT INTO Technology VALUES('TXD','p','transport','petroleum','',0,0,0,0,0,0,0,0,' diesel powered vehicles'); -INSERT INTO Technology VALUES('TXE','p','transport','electric','',0,0,0,0,0,0,0,0,' electric powered vehicles'); -INSERT INTO Technology VALUES('TXG','p','transport','petroleum','',0,0,0,0,0,0,0,0,' gasoline powered vehicles'); -CREATE TABLE OutputCost + FOREIGN KEY (flag) REFERENCES technologyType (label) +); +INSERT INTO technology VALUES('IMPDSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported diesel'); +INSERT INTO technology VALUES('IMPGSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported gasoline'); +INSERT INTO technology VALUES('IMPHCO1','p','supply','coal','',1,0,0,0,0,0,0,0,' imported coal'); +INSERT INTO technology VALUES('IMPOIL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported crude oil'); +INSERT INTO technology VALUES('IMPURN1','p','supply','nuclear','',1,0,0,0,0,0,0,0,' imported uranium'); +INSERT INTO technology VALUES('IMPFEQ','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported fossil equivalent'); +INSERT INTO technology VALUES('IMPHYD','p','supply','hydro','',1,0,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); +INSERT INTO technology VALUES('E01','pb','electric','coal','',0,0,0,0,0,0,0,0,' coal power plant'); +INSERT INTO technology VALUES('E21','pb','electric','nuclear','',0,0,0,0,0,0,0,0,' nuclear power plant'); +INSERT INTO technology VALUES('E31','pb','electric','hydro','',0,0,0,0,0,0,0,0,' hydro power'); +INSERT INTO technology VALUES('E51','ps','electric','electric','',0,0,0,0,0,0,0,0,' electric storage'); +INSERT INTO technology VALUES('E70','p','electric','petroleum','',0,0,0,0,0,0,0,0,' diesel power plant'); +INSERT INTO technology VALUES('RHE','p','residential','electric','',0,0,0,0,0,0,0,0,' electric residential heating'); +INSERT INTO technology VALUES('RHO','p','residential','petroleum','',0,0,0,0,0,0,0,0,' diesel residential heating'); +INSERT INTO technology VALUES('RL1','p','residential','electric','',0,0,0,0,0,0,0,0,' residential lighting'); +INSERT INTO technology VALUES('SRE','p','supply','petroleum','',0,0,0,0,0,0,0,0,' crude oil processor'); +INSERT INTO technology VALUES('TXD','p','transport','petroleum','',0,0,0,0,0,0,0,0,' diesel powered vehicles'); +INSERT INTO technology VALUES('TXE','p','transport','electric','',0,0,0,0,0,0,0,0,' electric powered vehicles'); +INSERT INTO technology VALUES('TXG','p','transport','petroleum','',0,0,0,0,0,0,0,0,' gasoline powered vehicles'); +CREATE TABLE output_cost ( scenario TEXT, region TEXT, sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), d_invest REAL, d_fixed REAL, d_var REAL, @@ -1552,7 +1552,7 @@ CREATE TABLE OutputCost var REAL, emiss REAL, PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) ); COMMIT; From 5271758d0cb9dd43865fa6c87374723c05373883 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 7 Nov 2025 19:59:15 -0500 Subject: [PATCH 316/587] WIP: updating tests to DBv4 --- data_files/example_dbs/seasonal_storage.sql | 2 +- data_files/temoa_schema_v4.sql | 33 + docs/source/Documentation.rst | 6 +- temoa/_internal/table_writer.py | 4 +- temoa/components/commodities.py | 4 +- temoa/components/flows.py | 4 +- temoa/core/model.py | 4 +- temoa/data_io/hybrid_loader.py | 6 +- temoa/extensions/get_comm_tech.py | 10 +- .../README.md | 2 +- .../extensions/myopic/make_myopic_tables.sql | 6 +- temoa/extensions/myopic/myopic table notes.md | 2 +- temoa/extensions/myopic/myopic_sequencer.py | 30 +- .../single_vector_mga/output_summary.py | 2 +- temoa/types/model_types.py | 2 +- temoa/utilities/clear_db_outputs.py | 2 +- temoa/utilities/db_migration_to_v3.py | 2 +- temoa/utilities/db_migration_v3_1_to_v4.py | 1 + temoa/utilities/run_all_v4_migrations.py | 159 ++ temoa/utilities/sql_migration_v3_1_to_v4.py | 3 +- tests/legacy_test_values.py | 4 +- tests/test_emission_results.py | 6 +- tests/test_linked_tech.py | 2 +- tests/test_network_model_data.py | 20 +- .../US_9R_8D_legacy_set_sizes.json | 6 +- tests/testing_data/annualised_demand.sql | 916 ++++---- tests/testing_data/emissions.sql | 1014 ++++----- tests/testing_data/materials.sql | 1916 ++++++++-------- tests/testing_data/mediumville.sql | 1202 +++++----- tests/testing_data/seasonal_storage.sql | 1032 ++++----- tests/testing_data/simple_linked_tech.sql | 936 ++++---- tests/testing_data/storageville.sql | 990 +++++---- tests/testing_data/survival_curve.sql | 1184 +++++----- tests/testing_data/test_system.sql | 1924 ++++++++-------- tests/testing_data/utopia.sql | 1928 +++++++++-------- 35 files changed, 6971 insertions(+), 6393 deletions(-) create mode 100644 temoa/utilities/run_all_v4_migrations.py diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql index 3064c30c3..2542862d7 100644 --- a/data_files/example_dbs/seasonal_storage.sql +++ b/data_files/example_dbs/seasonal_storage.sql @@ -381,7 +381,7 @@ CREATE TABLE TechGroup PRIMARY KEY, notes TEXT ); -CREATE TABLE Loanlifetime_tech +CREATE TABLE loan_lifetime_tech ( region TEXT, tech TEXT diff --git a/data_files/temoa_schema_v4.sql b/data_files/temoa_schema_v4.sql index b8492044e..7727e7b10 100644 --- a/data_files/temoa_schema_v4.sql +++ b/data_files/temoa_schema_v4.sql @@ -1075,5 +1075,38 @@ CREATE TABLE IF NOT EXISTS time_season_sequential CHECK (num_days > 0) ); +CREATE TABLE IF NOT EXISTS myopic_efficiency +( + base_year integer, + region text, + input_comm text, + tech text, + vintage integer, + output_comm text, + efficiency real, + lifetime integer, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (region, input_comm, tech, vintage, output_comm) +); +-- for efficient searching by rtv: +CREATE INDEX IF NOT EXISTS region_tech_vintage ON myopic_efficiency (region, tech, vintage); + +CREATE TABLE IF NOT EXISTS output_flow_out_summary +( + scenario TEXT NOT NULL, + region TEXT NOT NULL, + sector TEXT, + period INTEGER, + input_comm TEXT NOT NULL, + tech TEXT NOT NULL, + vintage INTEGER, + output_comm TEXT NOT NULL, + flow REAL NOT NULL, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) +); + COMMIT; PRAGMA foreign_keys = 1; diff --git a/docs/source/Documentation.rst b/docs/source/Documentation.rst index f2ba0cab3..9a7fc5ca0 100644 --- a/docs/source/Documentation.rst +++ b/docs/source/Documentation.rst @@ -1310,7 +1310,7 @@ loan_lifetime_process :math:`{LLP}_{r \in R, t \in T, v \in P}` **Note**: :code:`LifetimeLoanProcess` is currently not supported in the database. -Modelers should use the :code:`Loanlifetime_tech` below. +Modelers should use the :code:`loan_lifetime_tech` below. Temoa gives the modeler the ability to separate the loan lifetime from the useful life of a process. This parameter specifies the loan term associated @@ -1318,14 +1318,14 @@ with capital investment in a process, in years. If not specified, the model assigns the technology lifetime to the loan period in :code:`temoa_initialize.py`. -Loanlifetime_tech +loan_lifetime_tech ^^^^^^^^^^^^^^^^ :math:`{LLT}_{r \in R, t \in T}` Same as the :code:`loan_lifetime_process` but without the vintage index. If all vintages of a given technology are assumed to have the same loan term, then -:code:`Loanlifetime_tech` can be defined instead of :code:`loan_lifetime_process`. +:code:`loan_lifetime_tech` can be defined instead of :code:`loan_lifetime_process`. lifetime_process diff --git a/temoa/_internal/table_writer.py b/temoa/_internal/table_writer.py index 42d8a7b9e..36e7c84a8 100644 --- a/temoa/_internal/table_writer.py +++ b/temoa/_internal/table_writer.py @@ -83,7 +83,7 @@ 'output_objective', 'output_retired_capacity', ] -optional_output_tables = ['output_flow_outSummary', 'OutputMCDelta', 'output_storage_level'] +optional_output_tables = ['output_flow_out_summary', 'OutputMCDelta', 'output_storage_level'] flow_summary_file_loc = Path( PROJECT_ROOT, 'temoa/extensions/modeling_to_generate_alternatives/make_flow_summary_table.sql' @@ -453,7 +453,7 @@ def _insert_summary_flow_results( entry: tuple[str, str, str | None, int, str, str, int, str, float] = (*idx, flow) entries.append(entry) - qry = f'INSERT INTO output_flow_outSummary VALUES {_marks(9)}' + qry = f'INSERT INTO output_flow_out_summary VALUES {_marks(9)}' self.con.executemany(qry, entries) self.con.commit() diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index 99288bce5..9a22af190 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -120,7 +120,7 @@ def commodity_balance_constraint_indices( # technologies with varying output at the time slice level. indices = { (r, p, s, d, c) - for r, p, c in model.commodityBalance_rpc + for r, p, c in model.commodity_balance_rpc # r in this line includes interregional transfer combinations (not needed). if r in model.regions # this line ensures only the regions are included. and c not in model.commodity_annual @@ -138,7 +138,7 @@ def annual_commodity_balance_constraint_indices( # technologies with constant annual output. indices = { (r, p, c) - for r, p, c in model.commodityBalance_rpc + for r, p, c in model.commodity_balance_rpc # r in this line includes interregional transfer combinations (not needed). if r in model.regions # this line ensures only the regions are included. and c in model.commodity_annual diff --git a/temoa/components/flows.py b/temoa/components/flows.py index e31188216..5dded296f 100644 --- a/temoa/components/flows.py +++ b/temoa/components/flows.py @@ -98,7 +98,7 @@ def create_commodity_balance_and_flow_sets(model: TemoaModel) -> None: for flows, capacity, and storage levels will be created. Populates: - - model.commodityBalance_rpc: The master set of (r, p, c) for balance constraints. + - model.commodity_balance_rpc: The master set of (r, p, c) for balance constraints. - model.activeFlow_rpsditvo: Indices for time-sliced flows (v_flow_out). - model.activeFlow_rpitvo: Indices for annual flows (v_flow_out_annual). - model.activeFlex_rpsditvo: Indices for flexible time-sliced flows (v_flex). @@ -121,7 +121,7 @@ def create_commodity_balance_and_flow_sets(model: TemoaModel) -> None: | model.capacity_consumption_techs | model.export_regions ) - model.commodityBalance_rpc = commodity_upstream.intersection(commodity_downstream) + model.commodity_balance_rpc = commodity_upstream.intersection(commodity_downstream) # 2. Active Flow Indices (Time-Sliced) model.active_flow_rpsditvo = { diff --git a/temoa/core/model.py b/temoa/core/model.py index 6056002bf..029498f79 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -129,7 +129,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.group_region_active_flow_rpt: t.GroupRegionActiveFlowSet = ( set() # Set of valid group-region, period, tech indices ) - self.commodityBalance_rpc: t.CommodityBalancedSet = ( + self.commodity_balance_rpc: t.CommodityBalancedSet = ( set() ) # Set of valid region-period-commodity indices to balance self.commodity_down_stream_process: t.CommodityStreamProcessDict = {} # The downstream process of a commodity during a period @@ -421,7 +421,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: # Dev Note: The loan_lifetime_process table *could* be removed. There is no longer a # supporting table in the database. It is just a "passthrough" now to the - # default Loanlifetime_tech. It is already stitched in to the model, + # default loan_lifetime_tech. It is already stitched in to the model, # so will leave it for now. Table may be revived. self.loan_lifetime_process = Param( diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index 2e8774f6f..d1621f5f5 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -433,7 +433,7 @@ def _build_efficiency_dataset( if myopic_index: contents = cur.execute( 'SELECT region, input_comm, tech, vintage, output_comm, efficiency, lifetime ' - 'FROM Myopicefficiency WHERE vintage + lifetime > ?', + 'FROM myopic_efficiency WHERE vintage + lifetime > ?', (myopic_index.base_year,), ).fetchall() else: @@ -496,9 +496,9 @@ def _load_regional_global_indices( cur = self.con.cursor() regions_and_groups: set[str] = set() - if self.table_exists('Region'): + if self.table_exists('region'): regions_and_groups.update( - t[0] for t in cur.execute('SELECT region FROM main.Region').fetchall() + t[0] for t in cur.execute('SELECT region FROM main.region').fetchall() ) for table, field_name in tables_with_regional_groups.items(): diff --git a/temoa/extensions/get_comm_tech.py b/temoa/extensions/get_comm_tech.py index 96522c972..d0329dab2 100644 --- a/temoa/extensions/get_comm_tech.py +++ b/temoa/extensions/get_comm_tech.py @@ -23,12 +23,12 @@ def get_tperiods(inp_f): con.text_factory = str # this ensures data is explored with the correct UTF-8 encoding print(inp_f) - cur.execute('SELECT DISTINCT scenario FROM output_flow_outut') + cur.execute('SELECT DISTINCT scenario FROM output_flow_out') x = [] for row in cur: x.append(row[0]) for y in x: - cur.execute("SELECT DISTINCT period FROM output_flow_outut WHERE scenario is '" + str(y) + "'") + cur.execute("SELECT DISTINCT period FROM output_flow_out WHERE scenario is '" + str(y) + "'") periods_list[y] = [] for per in cur: z = per[0] @@ -56,7 +56,7 @@ def get_scenario(inp_f): con.text_factory = str # this ensures data is explored with the correct UTF-8 encoding print(inp_f) - cur.execute('SELECT DISTINCT scenario FROM output_flow_outut') + cur.execute('SELECT DISTINCT scenario FROM output_flow_out') for row in cur: x = row[0] scene_list[x] = x @@ -87,7 +87,7 @@ def get_comm(inp_f, db_dat): if not is_query_empty: cur.execute( - 'SELECT input_comm FROM output_flow_outut UNION SELECT output_comm FROoutput_flow_out_out' + 'SELECT input_comm FROM output_flow_out UNION SELECT output_comm FROM output_flow_out' ) for row in cur: @@ -150,7 +150,7 @@ def get_tech(inp_f, db_dat): tech_list[x] = x if not is_query_empty: - cur.execute('SELECT DISTINCT tech FROM output_flow_outut') + cur.execute('SELECT DISTINCT tech FROM output_flow_out') for row in cur: x = row[0] diff --git a/temoa/extensions/modeling_to_generate_alternatives/README.md b/temoa/extensions/modeling_to_generate_alternatives/README.md index 39f7a8634..7b41c71e2 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/README.md +++ b/temoa/extensions/modeling_to_generate_alternatives/README.md @@ -7,7 +7,7 @@ analytic approach to MGA. MGA uses multi-processing to iteratively explore near - The processing of results is left to the modeler and the results from runs are tagged iteratively in the Output tables in the database. -- Running MGA analysis also adds an additional `output_flow_outSummary` table which +- Running MGA analysis also adds an additional `output_flow_out_summary` table which summarizes flows at the period level (summarizing time of day and season) to manage the size of the output for larger models diff --git a/temoa/extensions/myopic/make_myopic_tables.sql b/temoa/extensions/myopic/make_myopic_tables.sql index 4f18f8241..00e88f71c 100644 --- a/temoa/extensions/myopic/make_myopic_tables.sql +++ b/temoa/extensions/myopic/make_myopic_tables.sql @@ -1,6 +1,6 @@ BEGIN; -CREATE TABLE IF NOT EXISTS Myopicefficiency +CREATE TABLE IF NOT EXISTS myopic_efficiency ( base_year integer, region text, @@ -11,11 +11,11 @@ CREATE TABLE IF NOT EXISTS Myopicefficiency efficiency real, lifetime integer, - FOREIGN KEY (tech) REFERENCES Technology (tech), + FOREIGN KEY (tech) REFERENCES technology (tech), PRIMARY KEY (region, input_comm, tech, vintage, output_comm) ); -- for efficient searching by rtv: -CREATE INDEX IF NOT EXISTS region_tech_vintage ON Myopicefficiency (region, tech, vintage); +CREATE INDEX IF NOT EXISTS region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; diff --git a/temoa/extensions/myopic/myopic table notes.md b/temoa/extensions/myopic/myopic table notes.md index bbfd9349c..42626c96f 100644 --- a/temoa/extensions/myopic/myopic table notes.md +++ b/temoa/extensions/myopic/myopic table notes.md @@ -1,7 +1,7 @@ Notes on Myopic =============== -Myopicefficiency Table +myopic_efficiency Table ---------------- - Largely similar to baseline efficiency table diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index 932a278da..cc16f6adc 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -48,11 +48,11 @@ class MyopicSequencer: 'output_storage_level', ] tables_without_scenario_reference = [ - 'Myopicefficiency', + 'myopic_efficiency', ] # Tables that may be cleaned by period during myopic run - # note: below excludes Myopicefficiency, which is managed separately + # note: below excludes myopic_efficiency, which is managed separately tables_with_period = [ 'output_cost', @@ -146,14 +146,14 @@ def start(self): # clear out the old riff-raff self.clear_old_results() - # start building the Myopicefficiency table. + # start building the myopic_efficiency table. self.initialize_myopic_efficiency_table() # start the fundamental control loop # 1. get feedback from previous instance execution (optimal/infeasible/...) # 2. decide what to do about it # 3. pull the next instance from the queue (if !empty & if needed) - # 4. Update the Myopicefficiency table (clean up history / add stuff now in visibility) + # 4. Update the myopic_efficiency table (clean up history / add stuff now in visibility) # 5. pull data for next run and filter it with source tracing # 6. build instance # 7. run checks (price check) on the model, if selected @@ -196,7 +196,7 @@ def start(self): if not self.config.silent: self.progress_mapper.report(idx, 'load') - # 4. update the Myopicefficiency table so it is ready for the upcoming data pull. + # 4. update the myopic_efficiency table so it is ready for the upcoming data pull. self.update_myopic_efficiency_table(myopic_index=idx, prev_base=last_base_year) # 5. pull the data @@ -284,11 +284,11 @@ def start(self): def initialize_myopic_efficiency_table(self): """ - create a new Myopicefficiency table and pre-load it with all existing_capacity + create a new myopic_efficiency table and pre-load it with all existing_capacity :return: """ # clear out everything from previous runs - self.cursor.execute('DELETE FROM Myopicefficiency WHERE 1') + self.cursor.execute('DELETE FROM myopic_efficiency WHERE 1') self.output_con.commit() # the -1 for base year is used to indicate "existing" for flag purposes @@ -297,7 +297,7 @@ def initialize_myopic_efficiency_table(self): # the "coalesce" is an if-else structure to pluck out the correct lifetime value, precedence left->right default_lifetime = TemoaModel.default_lifetime_tech query = ( - 'INSERT INTO Myopicefficiency ' + 'INSERT INTO myopic_efficiency ' ' SELECT -1, main.efficiency.region, input_comm, efficiency.tech, efficiency.vintage, output_comm, efficiency, ' f' coalesce(main.lifetime_process.lifetime, main.lifetime_tech.lifetime, {default_lifetime}) AS lifetime ' ' FROM main.efficiency ' @@ -331,7 +331,7 @@ def initialize_myopic_efficiency_table(self): def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: int): """ - This function adds to the Myopicefficiency table in the db with data specific + This function adds to the myopic_efficiency table in the db with data specific to the current MyopicIndex timeframe. Basically: prep it for the current iteration. :return: """ @@ -355,13 +355,13 @@ def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: i base = myopic_index.base_year last_demand_year = myopic_index.last_demand_year - logger.info('Starting update of Myopicefficiency Table retaining [%s, %s)', prev_base, base) + logger.info('Starting update of myopic_efficiency Table retaining [%s, %s)', prev_base, base) # 0. Clear any future things past the base year for housekeeping # ease with steps, depth, etc. These may have been added if we are stepping less # than the previous solve depth or if backtracking. self.cursor.execute( - 'DELETE FROM Myopicefficiency WHERE Myopicefficiency.vintage >= ?', (base,) + 'DELETE FROM myopic_efficiency WHERE myopic_efficiency.vintage >= ?', (base,) ) self.output_con.commit() @@ -374,7 +374,7 @@ def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: i if flag == 'f': # the prior period should have an output_net_capacity entry # Delete anything that doesn't have capacity remaining at the end of last interval delete_qry = ( - 'DELETE FROM Myopicefficiency ' + 'DELETE FROM myopic_efficiency ' 'WHERE (SELECT region, tech, vintage) ' ' NOT IN (SELECT region, tech, vintage FROM output_net_capacity ' ' WHERE period = ? AND scenario = ?) ' @@ -383,7 +383,7 @@ def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: i if self.debugging: debug_query = ( - 'SELECT * FROM Myopicefficiency ' + 'SELECT * FROM myopic_efficiency ' 'WHERE (SELECT region, tech, vintage) ' ' NOT IN (SELECT region, tech, vintage FROM output_net_capacity ' ' WHERE period = ? AND scenario = ?) ' @@ -403,7 +403,7 @@ def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: i # process lifetime > tech lifetime > lifetime default lifetime = TemoaModel.default_lifetime_tech query = ( - 'INSERT INTO Myopicefficiency ' + 'INSERT INTO myopic_efficiency ' f'SELECT {base}, efficiency.region, input_comm, ' ' efficiency.tech, efficiency.vintage, output_comm, efficiency, ' f' coalesce(main.lifetime_process.lifetime, main.lifetime_tech.lifetime, {lifetime}) ' @@ -427,7 +427,7 @@ def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: i f' WHERE efficiency.vintage >= {base}' f' AND efficiency.vintage <= {last_demand_year}' ).fetchall() - print('\n\n **** adding to Myopicefficiency table from newly visible techs ****') + print('\n\n **** adding to myopic_efficiency table from newly visible techs ****') for idx, t in enumerate(raw): print(idx, t) print() diff --git a/temoa/extensions/single_vector_mga/output_summary.py b/temoa/extensions/single_vector_mga/output_summary.py index 8ecb2fb8e..e4fc2441a 100644 --- a/temoa/extensions/single_vector_mga/output_summary.py +++ b/temoa/extensions/single_vector_mga/output_summary.py @@ -107,7 +107,7 @@ def poll_capacity(conn: Connection, scenario: str, label: str) -> float: poll the built capacity for the given emission label total """ raw = conn.execute( - 'SELECT sum(capacity) FROM main.output_built_capacityty WHERE scenario=? AND tech=?', + 'SELECT sum(capacity) FROM main.output_built_capacity WHERE scenario=? AND tech=?', (scenario, label), ).fetchone()[0] return raw diff --git a/temoa/types/model_types.py b/temoa/types/model_types.py index b9d7116e7..d168123cb 100644 --- a/temoa/types/model_types.py +++ b/temoa/types/model_types.py @@ -117,7 +117,7 @@ class TemoaModelProtocol(Protocol): # Model parameters global_discount_rate: Param demand: Param - ffficiency: Param + efficiency: Param existing_capacity: Param capacity_to_activity: Param diff --git a/temoa/utilities/clear_db_outputs.py b/temoa/utilities/clear_db_outputs.py index f04158aaf..d8614f141 100644 --- a/temoa/utilities/clear_db_outputs.py +++ b/temoa/utilities/clear_db_outputs.py @@ -19,7 +19,7 @@ 'output_objective', 'output_retired_capacity', ] -optional_output_tables = ['output_flow_outSummary', 'MyopicEfficiency'] +optional_output_tables = ['output_flow_out_summary', 'myopic_efficiency'] if len(sys.argv) != 2: print('this utility file expects a CLA for the path to the database to clear') diff --git a/temoa/utilities/db_migration_to_v3.py b/temoa/utilities/db_migration_to_v3.py index ac0c763b0..ec16f9dbf 100644 --- a/temoa/utilities/db_migration_to_v3.py +++ b/temoa/utilities/db_migration_to_v3.py @@ -101,7 +101,7 @@ ('', 'TechInputSplitAverage'), ('', 'TechOutputSplit'), ('technology_labels', 'TechnologyType'), - ('time_period_labels', 'time_periodType'), + ('time_period_labels', 'TimePeriodType'), ('SegFrac', 'TimeSegmentFraction'), ] diff --git a/temoa/utilities/db_migration_v3_1_to_v4.py b/temoa/utilities/db_migration_v3_1_to_v4.py index d7c8b25a0..592a74730 100644 --- a/temoa/utilities/db_migration_v3_1_to_v4.py +++ b/temoa/utilities/db_migration_v3_1_to_v4.py @@ -30,6 +30,7 @@ 'segfrac': 'segment_fraction', 'MetaDataReal': 'metadata_real', 'MetaData': 'metadata', + 'Myopicefficiency': 'myopic_efficiency', 'DB_MAJOR': 'db_major', 'DB_MINOR': 'db_minor', } diff --git a/temoa/utilities/run_all_v4_migrations.py b/temoa/utilities/run_all_v4_migrations.py new file mode 100644 index 000000000..4e65f89ed --- /dev/null +++ b/temoa/utilities/run_all_v4_migrations.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +""" +run_all_migrations.py + +Iterates over all .sql files in a specified directory, runs the v3.1 to v4 +SQL migration script on each, and overwrites the original file if successful. +Includes basic error handling to restore original files on failure. + +Usage: + python run_all_migrations.py --input_dir /path/to/your/sql_files \ + --migration_script ./sql_migration_v_3_1_to_v4.py \ + --v4_schema_path ./temoa_schema_v4.sql +""" + +from __future__ import annotations + +import argparse +import os +import shutil +import subprocess +import sys +import tempfile +from pathlib import Path + + +def run_command( + cmd: list[str], cwd: Path = None, capture_output: bool = True +) -> subprocess.CompletedProcess: + """Helper to run shell commands.""" + print(f'Executing: {" ".join(cmd)}') + result = subprocess.run(cmd, cwd=cwd, capture_output=capture_output, text=True, check=False) + if result.returncode != 0 and capture_output: + print(f'COMMAND FAILED (exit code {result.returncode}):') + print('STDOUT:\n', result.stdout) + print('STDERR:\n', result.stderr) + return result + + +def main() -> None: + parser = argparse.ArgumentParser( + description='Run SQL migration on all .sql files in a directory, overwriting originals.' + ) + parser.add_argument( + '--input_dir', + required=True, + type=Path, + help='Directory containing the .sql files to migrate.', + ) + parser.add_argument( + '--migration_script', + required=True, + type=Path, + help='Path to the sql_migration_v_3_1_to_v4.py script.', + ) + parser.add_argument( + '--v4_schema_path', + required=True, + type=Path, + help='Path to the canonical v4 schema SQL file (temoa_schema_v4.sql).', + ) + parser.add_argument( + '--dry_run', + action='store_true', + help='Perform a dry run: show which files would be processed, but do not modify.', + ) + + args = parser.parse_args() + + input_dir = args.input_dir.resolve() + migration_script = args.migration_script.resolve() + v4_schema_path = args.v4_schema_path.resolve() + + if not input_dir.is_dir(): + print(f'Error: Input directory not found at {input_dir}') + sys.exit(1) + if not migration_script.is_file(): + print(f'Error: Migration script not found at {migration_script}') + sys.exit(1) + if not v4_schema_path.is_file(): + print(f'Error: V4 schema file not found at {v4_schema_path}') + sys.exit(1) + + print(f'Scanning for .sql files in: {input_dir}') + sql_files = list(input_dir.glob('*.sql')) + + if not sql_files: + print(f'No .sql files found in {input_dir}. Exiting.') + sys.exit(0) + + if args.dry_run: + print('\n--- Dry Run ---') + print(f'The following {len(sql_files)} .sql files would be processed:') + for f in sql_files: + print(f' - {f.name}') + print('\nNo files will be modified in dry run mode.') + sys.exit(0) + + print(f'\n--- Starting Migration of {len(sql_files)} files ---') + processed_count = 0 + failed_files = [] + + for sql_file in sql_files: + print(f'\nProcessing: {sql_file.name}') + + temp_output_file = Path(tempfile.mkstemp(suffix='.sql', prefix='temp_migrated_')[1]) + original_backup_file = Path(tempfile.mkstemp(suffix='.bak', prefix='orig_backup_')[1]) + + try: + # 1. Back up original file (to restore on failure) + shutil.copy2(sql_file, original_backup_file) + + # 2. Run migration script, outputting to a temporary file + migration_cmd = [ + 'python3', + str(migration_script), + '--input', + str(sql_file), + '--schema', + str(v4_schema_path), + '--output', + str(temp_output_file), + ] + result = run_command(migration_cmd, cwd=Path.cwd()) + + if result.returncode == 0: + # 3. If successful, overwrite original file with converted content + shutil.copy2(temp_output_file, sql_file) + print(f'SUCCESS: {sql_file.name} migrated and overwritten.') + processed_count += 1 + else: + # 4. On failure, restore original file + print(f'FAILED: Migration for {sql_file.name} failed. Restoring original file.') + shutil.copy2(original_backup_file, sql_file) + failed_files.append(sql_file.name) + + except Exception as e: + print(f'CRITICAL ERROR processing {sql_file.name}: {e}. Restoring original file.') + if original_backup_file.exists(): + shutil.copy2(original_backup_file, sql_file) + failed_files.append(sql_file.name) + finally: + # Clean up temporary files + if temp_output_file.exists(): + os.remove(temp_output_file) + if original_backup_file.exists(): + os.remove(original_backup_file) + + print('\n--- Migration Summary ---') + print(f'Total files processed: {processed_count}') + if failed_files: + print(f'FAILED files: {", ".join(failed_files)}') + sys.exit(1) + else: + print('All files migrated successfully.') + sys.exit(0) + + +if __name__ == '__main__': + main() diff --git a/temoa/utilities/sql_migration_v3_1_to_v4.py b/temoa/utilities/sql_migration_v3_1_to_v4.py index 3f9fd6f75..f1d2dd838 100644 --- a/temoa/utilities/sql_migration_v3_1_to_v4.py +++ b/temoa/utilities/sql_migration_v3_1_to_v4.py @@ -34,10 +34,11 @@ 'TimeNext': 'time_manual', 'CommodityDStreamProcess': 'commodity_down_stream_process', 'commodityUStreamProcess': 'commodity_up_stream_process', - 'SegFrac': 'time_segment_fraction', + 'SegFrac': 'segment_fraction', 'segfrac': 'segment_fraction', # canonical column name for column 'segfrac' 'MetaDataReal': 'metadata_real', 'MetaData': 'metadata', + 'Myopicefficiency': 'myopic_efficiency', 'DB_MAJOR': 'db_major', 'DB_MINOR': 'db_minor', } diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index 24f27ca03..6e8006f2e 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -107,7 +107,7 @@ class ExpectedVals(Enum): 'survival_curve': { # added 2025/06/19 after addition of survival curves # reduced after changing fixed costs from MLP to PL - # increased after adding PeriodSurvivalCurve + # increased after adding Periodsurvival_curve ExpectedVals.OBJ_VALUE: 31.9423, ExpectedVals.EFF_DOMAIN_SIZE: 64, ExpectedVals.EFF_INDEX_SIZE: 8, @@ -118,7 +118,7 @@ class ExpectedVals(Enum): 'annualised_demand': { # added 2025/06/19 after addition of survival curves # reduced after changing fixed costs from MLP to PL - # increased after adding PeriodSurvivalCurve + # increased after adding Periodsurvival_curve ExpectedVals.OBJ_VALUE: 1.9524, ExpectedVals.EFF_DOMAIN_SIZE: 36, ExpectedVals.EFF_INDEX_SIZE: 10, diff --git a/tests/test_emission_results.py b/tests/test_emission_results.py index 58f73fa31..f421bea29 100644 --- a/tests/test_emission_results.py +++ b/tests/test_emission_results.py @@ -72,7 +72,7 @@ def test_emissions(solved_connection): emis = ( con.cursor() .execute( - f"SELECT SUM(emission) FROM main.output_emissionn WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied' AND period == 2000" + f"SELECT SUM(emission) FROM main.output_emission WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied' AND period == 2000" ) .fetchone()[0] ) @@ -146,7 +146,7 @@ def test_embodied_emissions(solved_connection): emis = ( con.cursor() .execute( - f"SELECT SUM(emission) FROM main.output_emissionn WHERE tech LIKE '{tech}' AND period == 2000" + f"SELECT SUM(emission) FROM main.output_emission WHERE tech LIKE '{tech}' AND period == 2000" ) .fetchone()[0] ) @@ -222,7 +222,7 @@ def test_endoflife_emissions(solved_connection): emis = ( con.cursor() .execute( - f"SELECT SUM(emission) FROM main.output_emissionn WHERE tech LIKE '{tech}' AND period == 2005" + f"SELECT SUM(emission) FROM main.output_emission WHERE tech LIKE '{tech}' AND period == 2005" ) .fetchone()[0] ) diff --git a/tests/test_linked_tech.py b/tests/test_linked_tech.py index e56af98ea..c174a05cd 100644 --- a/tests/test_linked_tech.py +++ b/tests/test_linked_tech.py @@ -57,7 +57,7 @@ def test_linked_tech(system_test_run): print(output_db_path) conn = sqlite3.connect(str(output_db_path)) co2_emiss = conn.execute( - "SELECT emission FROM output_emissionn WHERE emis_comm = 'CO2'" + "SELECT emission FROM output_emission WHERE emis_comm = 'CO2'" ).fetchall() assert len(co2_emiss) == 1 co2_emiss = co2_emiss[0][0] diff --git a/tests/test_network_model_data.py b/tests/test_network_model_data.py index 8443c6003..78140cccb 100644 --- a/tests/test_network_model_data.py +++ b/tests/test_network_model_data.py @@ -20,7 +20,7 @@ 'name': 'basic', 'db_data': { 'technology WHERE retire==1': [], - 'FROM SurvivalCurve': [], + 'FROM survival_curve': [], 'FROM time_period': [(2020,), (2025,)], # Unique keys for each commodity query 'FROM main.commodity': [('s1',), ('p1',), ('p2',), ('p3',), ('d1',), ('d2',)], @@ -54,7 +54,7 @@ ], 'FROM end_of_life_output': [], 'FROM construction_input': [], - 'FROM main.LinkedTech': [], + 'FROM main.linked_tech': [], 'FROM cost_variable': [], }, 'expected': { @@ -71,7 +71,7 @@ 'name': 'bad linked tech', 'db_data': { 'technology WHERE retire==1': [], - 'FROM SurvivalCurve': [], + 'FROM survival_curve': [], 'FROM time_period': [(2020,), (2025,)], 'FROM main.commodity': [('s1',), ('p1',), ('p3',), ('d1',), ('d2',)], "commodity WHERE flag LIKE '%p%'": [('s1',), ('p3',), ('d1',), ('d2',)], @@ -91,7 +91,7 @@ ], 'FROM end_of_life_output': [], 'FROM construction_input': [], - 'FROM main.LinkedTech': [('R1', 't4', 'nox', 'driven')], + 'FROM main.linked_tech': [('R1', 't4', 'nox', 'driven')], 'FROM cost_variable': [], }, 'expected': { @@ -108,7 +108,7 @@ 'name': 'good linked tech', 'db_data': { 'technology WHERE retire==1': [], - 'FROM SurvivalCurve': [], + 'FROM survival_curve': [], 'FROM time_period': [(2020,), (2025,)], 'FROM main.commodity': [('s1',), ('p1',), ('d1',), ('d2',), ('s2',)], "commodity WHERE flag LIKE '%p%'": [('s1',), ('d1',), ('d2',), ('s2',)], @@ -128,7 +128,7 @@ ], 'FROM end_of_life_output': [], 'FROM construction_input': [], - 'FROM main.LinkedTech': [('R1', 't4', 'nox', 'driven')], + 'FROM main.linked_tech': [('R1', 't4', 'nox', 'driven')], 'FROM cost_variable': [], }, 'expected': { @@ -259,7 +259,7 @@ def dispatcher(query: str, *_: object) -> MagicMock: m = MagicMock() m.fetchall.return_value = [] return m - elif 'FROM SurvivalCurve' in query: + elif 'FROM survival_curve' in query: m = MagicMock() m.fetchall.return_value = [] return m @@ -291,7 +291,7 @@ def dispatcher(query: str, *_: object) -> MagicMock: m = MagicMock() m.fetchall.return_value = [] return m - elif 'FROM main.LinkedTech' in query: + elif 'FROM main.linked_tech' in query: m = MagicMock() m.fetchall.return_value = [] return m @@ -343,7 +343,7 @@ def dispatcher(query: str, *_: object) -> MagicMock: m = MagicMock() m.fetchall.return_value = [] return m - elif 'FROM SurvivalCurve' in query: + elif 'FROM survival_curve' in query: m = MagicMock() m.fetchall.return_value = [] return m @@ -375,7 +375,7 @@ def dispatcher(query: str, *_: object) -> MagicMock: m = MagicMock() m.fetchall.return_value = [] return m - elif 'FROM main.LinkedTech' in query: + elif 'FROM main.linked_tech' in query: m = MagicMock() m.fetchall.return_value = [] return m diff --git a/tests/testing_data/US_9R_8D_legacy_set_sizes.json b/tests/testing_data/US_9R_8D_legacy_set_sizes.json index 343ce1dda..5f4264131 100644 --- a/tests/testing_data/US_9R_8D_legacy_set_sizes.json +++ b/tests/testing_data/US_9R_8D_legacy_set_sizes.json @@ -45,9 +45,9 @@ "tech_PowerPlants": 0, "segment_fraction_index": 192, "demandDefaultDistribution_index": 192, - "demand_specific_distributionon_index_index_0_index_0": 88128, - "demand_specific_distributionon_index_index_0": 88128, - "demand_specific_distributionon_index": 88128, + "demand_specific_distribution_index_index_0_index_0": 88128, + "demand_specific_distribution_index_index_0": 88128, + "demand_specific_distribution_index": 88128, "demand_index_index_0": 3213, "demand_index": 3213, "ResourceBound_index_index_0": 24255, diff --git a/tests/testing_data/annualised_demand.sql b/tests/testing_data/annualised_demand.sql index c51ccee3d..18477b987 100644 --- a/tests/testing_data/annualised_demand.sql +++ b/tests/testing_data/annualised_demand.sql @@ -1,48 +1,4 @@ -PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO metadata VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO metadata VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO metadata VALUES('days_per_period',365,'count of days in each period'); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO metadata_real VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO metadata_real VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE SeasonLabel -( - season TEXT PRIMARY KEY, - notes TEXT -); -CREATE TABLE SectorLabel -( - sector TEXT PRIMARY KEY, - notes TEXT -); CREATE TABLE capacity_credit ( region TEXT, @@ -62,9 +18,9 @@ CREATE TABLE capacity_factor_process period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), vintage INTEGER, @@ -79,9 +35,9 @@ CREATE TABLE capacity_factor_tech period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), factor REAL, @@ -89,7 +45,7 @@ CREATE TABLE capacity_factor_tech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE CapacityToActivity +CREATE TABLE capacity_to_activity ( region TEXT, tech TEXT @@ -103,27 +59,27 @@ CREATE TABLE commodity name TEXT PRIMARY KEY, flag TEXT - REFERENCES commodityType (label), + REFERENCES commodity_type (label), description TEXT ); -INSERT INTO commodity VALUES('source','s',NULL); -INSERT INTO commodity VALUES('annual','a',NULL); -INSERT INTO commodity VALUES('physical','p',NULL); -INSERT INTO commodity VALUES('demand','d',NULL); -CREATE TABLE commodityType +INSERT INTO "commodity" VALUES('source','s',NULL); +INSERT INTO "commodity" VALUES('annual','a',NULL); +INSERT INTO "commodity" VALUES('physical','p',NULL); +INSERT INTO "commodity" VALUES('demand','d',NULL); +CREATE TABLE commodity_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO commodityType VALUES('s','source commodity'); -INSERT INTO commodityType VALUES('a','annual commodity'); -INSERT INTO commodityType VALUES('p','physical commodity'); -INSERT INTO commodityType VALUES('d','demand commodity'); -INSERT INTO commodityType VALUES('e','emissions commodity'); -INSERT INTO commodityType VALUES('w','waste commodity'); -INSERT INTO commodityType VALUES('wa','waste annual commodity'); -INSERT INTO commodityType VALUES('wp','waste physical commodity'); +INSERT INTO "commodity_type" VALUES('s','source commodity'); +INSERT INTO "commodity_type" VALUES('a','annual commodity'); +INSERT INTO "commodity_type" VALUES('p','physical commodity'); +INSERT INTO "commodity_type" VALUES('d','demand commodity'); +INSERT INTO "commodity_type" VALUES('e','emissions commodity'); +INSERT INTO "commodity_type" VALUES('w','waste commodity'); +INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); +INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); CREATE TABLE construction_input ( region TEXT, @@ -176,8 +132,8 @@ CREATE TABLE cost_invest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO cost_invest VALUES('region','annual',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('region','non_annual',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('region','annual',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('region','non_annual',2000,1.0,NULL,NULL); CREATE TABLE cost_variable ( region TEXT NOT NULL, @@ -192,8 +148,8 @@ CREATE TABLE cost_variable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_variable VALUES('region',2000,'annual',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2000,'non_annual',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2000,'annual',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2000,'non_annual',2000,1.0,NULL,NULL); CREATE TABLE demand ( region TEXT, @@ -206,16 +162,16 @@ CREATE TABLE demand notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO demand VALUES('region',2000,'demand',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('region',2000,'demand',1.0,NULL,NULL); CREATE TABLE demand_specific_distribution ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), demand_name TEXT REFERENCES commodity (name), dsd REAL, @@ -223,20 +179,6 @@ CREATE TABLE demand_specific_distribution PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); CREATE TABLE efficiency ( region TEXT, @@ -253,25 +195,25 @@ CREATE TABLE efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO efficiency VALUES('region','annual','annual',2000,'physical',1.0,NULL); -INSERT INTO efficiency VALUES('region','annual','annual',2000,'demand',1.0,NULL); -INSERT INTO efficiency VALUES('region','physical','annual',2000,'demand',1.0,NULL); -INSERT INTO efficiency VALUES('region','physical','annual',2000,'annual',1.0,NULL); -INSERT INTO efficiency VALUES('region','source','import',2000,'physical',1.0,NULL); -INSERT INTO efficiency VALUES('region','source','import',2000,'annual',1.0,NULL); -INSERT INTO efficiency VALUES('region','annual','non_annual',2000,'physical',1.0,NULL); -INSERT INTO efficiency VALUES('region','annual','non_annual',2000,'demand',1.0,NULL); -INSERT INTO efficiency VALUES('region','physical','non_annual',2000,'demand',1.0,NULL); -INSERT INTO efficiency VALUES('region','physical','non_annual',2000,'annual',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','annual','annual',2000,'physical',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','annual','annual',2000,'demand',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','physical','annual',2000,'demand',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','physical','annual',2000,'annual',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','source','import',2000,'physical',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','source','import',2000,'annual',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','annual','non_annual',2000,'physical',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','annual','non_annual',2000,'demand',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','physical','non_annual',2000,'demand',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','physical','non_annual',2000,'annual',1.0,NULL); CREATE TABLE efficiency_variable ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -315,7 +257,7 @@ CREATE TABLE emission_embodied value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) ); CREATE TABLE emission_end_of_life ( @@ -329,7 +271,21 @@ CREATE TABLE emission_end_of_life value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE end_of_life_output +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); CREATE TABLE existing_capacity ( @@ -343,13 +299,7 @@ CREATE TABLE existing_capacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE loan_lifetime_process +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -360,156 +310,199 @@ CREATE TABLE loan_lifetime_process notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO loan_lifetime_process VALUES ('region','annual',2000,1,NULL); -INSERT INTO loan_lifetime_process VALUES ('region','non_annual',2000,1,NULL); -CREATE TABLE loan_rate +CREATE TABLE lifetime_survival_curve ( - region TEXT, - tech TEXT + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL REFERENCES technology (tech), - vintage INTEGER + vintage INTEGER NOT NULL REFERENCES time_period (period), - rate REAL, + fraction REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE lifetime_process +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), lifetime REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, tech) ); -CREATE TABLE lifetime_tech +INSERT INTO "lifetime_tech" VALUES('region','annual',1.0,NULL); +INSERT INTO "lifetime_tech" VALUES('region','non_annual',1.0,NULL); +CREATE TABLE limit_activity ( - region TEXT, - tech TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +INSERT INTO "limit_activity" VALUES('region',2000,'annual','le',0.5,NULL,NULL); +INSERT INTO "limit_activity" VALUES('region',2000,'non_annual','le',0.5,NULL,NULL); +CREATE TABLE limit_activity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_annual_capacity_factor +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator), + CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO lifetime_tech VALUES ('region', 'annual', 1, NULL); -INSERT INTO lifetime_tech VALUES ('region', 'non_annual', 1, NULL); -CREATE TABLE Operator +CREATE TABLE limit_capacity ( - operator TEXT PRIMARY KEY, - notes TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO Operator VALUES('e','equal to'); -INSERT INTO Operator VALUES('le','less than or equal to'); -INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE limit_growth_capacity +CREATE TABLE limit_capacity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_capacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity +CREATE TABLE limit_emission +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitStorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -CREATE TABLE limit_activity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, + REFERENCES operator (operator), + new_cap REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO limit_activity VALUES('region',2000,'annual','le',0.5,NULL,NULL); -INSERT INTO limit_activity VALUES('region',2000,'non_annual','le',0.5,NULL,NULL); -CREATE TABLE limit_activity_share +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -517,105 +510,56 @@ CREATE TABLE limit_activity_share sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), share REAL, notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity +CREATE TABLE limit_resource ( region TEXT, - period INTEGER - REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, + REFERENCES operator (operator), + cum_act REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) + PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_capacity_share +CREATE TABLE limit_seasonal_capacity_factor ( - region TEXT, - period INTEGER + region TEXT + REFERENCES region (region), + period INTEGER REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, + season TEXT + REFERENCES season_label (season), + tech TEXT + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE limit_new_capacity +CREATE TABLE limit_storage_level_fraction ( - region TEXT, - period INTEGER + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), - tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) + REFERENCES operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); CREATE TABLE limit_tech_input_split ( @@ -627,7 +571,7 @@ CREATE TABLE limit_tech_input_split tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -642,7 +586,7 @@ CREATE TABLE limit_tech_input_split_annual tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -657,7 +601,7 @@ CREATE TABLE limit_tech_output_split output_comm TEXT REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) @@ -672,26 +616,12 @@ CREATE TABLE limit_tech_output_split_annual output_comm TEXT REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE LinkedTech +CREATE TABLE linked_tech ( primary_region TEXT, primary_tech TEXT @@ -703,6 +633,105 @@ CREATE TABLE LinkedTech notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); +CREATE TABLE loan_lifetime_process +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +INSERT INTO "loan_lifetime_process" VALUES('region','annual',2000,1.0,NULL); +INSERT INTO "loan_lifetime_process" VALUES('region','non_annual',2000,1.0,NULL); +CREATE TABLE loan_rate +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE metadata +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); +INSERT INTO "metadata" VALUES('DB_MINOR',0,''); +CREATE TABLE metadata_real +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +CREATE TABLE myopic_efficiency +( + base_year integer, + region text, + input_comm text, + tech text, + vintage integer, + output_comm text, + efficiency real, + lifetime integer, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (region, input_comm, tech, vintage, output_comm) +); +CREATE TABLE operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "operator" VALUES('e','equal to'); +INSERT INTO "operator" VALUES('le','less than or equal to'); +INSERT INTO "operator" VALUES('ge','greater than or equal to'); +CREATE TABLE output_built_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE output_cost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) +); CREATE TABLE output_curtailment ( scenario TEXT, @@ -713,7 +742,7 @@ CREATE TABLE output_curtailment season TEXT REFERENCES time_period (period), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -725,62 +754,42 @@ CREATE TABLE output_curtailment curtailment REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputNetCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_built_capacity +CREATE TABLE output_dual_variable ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE output_emission ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), - tech TEXT + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT REFERENCES technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE OutputFlowIn +CREATE TABLE output_flow_in ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -792,18 +801,18 @@ CREATE TABLE OutputFlowIn flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputFlowOut +CREATE TABLE output_flow_out ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -815,18 +824,70 @@ CREATE TABLE OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); +CREATE TABLE output_flow_out_summary +( + scenario TEXT NOT NULL, + region TEXT NOT NULL, + sector TEXT, + period INTEGER, + input_comm TEXT NOT NULL, + tech TEXT NOT NULL, + vintage INTEGER, + output_comm TEXT NOT NULL, + flow REAL NOT NULL, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_net_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_objective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE output_retired_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), vintage INTEGER @@ -866,14 +927,14 @@ CREATE TABLE region PRIMARY KEY, notes TEXT ); -INSERT INTO region VALUES('region',NULL); +INSERT INTO "region" VALUES('region',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tech TEXT REFERENCES technology (tech), vintage INTEGER, @@ -882,20 +943,27 @@ CREATE TABLE reserve_capacity_derate PRIMARY KEY (region, period, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE TimeSegmentFraction +CREATE TABLE rps_requirement ( - period INTEGER + region TEXT NOT NULL + REFERENCES region (region), + period INTEGER NOT NULL REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) + tech_group TEXT NOT NULL + REFERENCES tech_group (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE season_label +( + season TEXT PRIMARY KEY, + notes TEXT +); +CREATE TABLE sector_label +( + sector TEXT PRIMARY KEY, + notes TEXT ); -INSERT INTO TimeSegmentFraction VALUES(2000,'S1','D1',1.0,NULL); CREATE TABLE storage_duration ( region TEXT, @@ -904,151 +972,131 @@ CREATE TABLE storage_duration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE lifetime_survival_curve +CREATE TABLE tech_group ( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE tech_group_member +( + group_name TEXT + REFERENCES tech_group (group_name), + tech TEXT REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) + PRIMARY KEY (group_name, tech) +); +CREATE TABLE technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES technology_type (label) ); -CREATE TABLE technologyType +INSERT INTO "technology" VALUES('annual','p','energy',NULL,NULL,0,1,0,0,0,0,0,0,NULL); +INSERT INTO "technology" VALUES('import','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO "technology" VALUES('non_annual','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +CREATE TABLE technology_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO technologyType VALUES('p','production technology'); -INSERT INTO technologyType VALUES('pb','baseload production technology'); -INSERT INTO technologyType VALUES('ps','storage production technology'); -CREATE TABLE TimeOfDay +INSERT INTO "technology_type" VALUES('p','production technology'); +INSERT INTO "technology_type" VALUES('pb','baseload production technology'); +INSERT INTO "technology_type" VALUES('ps','storage production technology'); +CREATE TABLE time_of_day ( sequence INTEGER UNIQUE, tod TEXT PRIMARY KEY ); -INSERT INTO TimeOfDay VALUES(0,'D1'); +INSERT INTO "time_of_day" VALUES(0,'D1'); CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES time_periodType (label) + REFERENCES time_period_type (label) ); -INSERT INTO time_period VALUES(0,2000,'f'); -INSERT INTO time_period VALUES(1,2001,'f'); -CREATE TABLE TimeSeason +INSERT INTO "time_period" VALUES(0,2000,'f'); +INSERT INTO "time_period" VALUES(1,2001,'f'); +CREATE TABLE time_period_type +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO "time_period_type" VALUES('e','existing vintages'); +INSERT INTO "time_period_type" VALUES('f','future'); +CREATE TABLE time_season +( + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + season TEXT REFERENCES season_label(season), + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +INSERT INTO "time_season" VALUES(2000,0,'S1',NULL); +CREATE TABLE time_season_all ( period INTEGER REFERENCES time_period (period), sequence INTEGER, season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); -INSERT INTO TimeSeason VALUES(2000,0,'S1',NULL); CREATE TABLE time_season_sequential ( - period INTEGER - REFERENCES time_period (period), + period INTEGER REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES SeasonLabel (season), + season TEXT REFERENCES season_label(season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE time_periodType -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO time_periodType VALUES('e','existing vintages'); -INSERT INTO time_periodType VALUES('f','future'); -CREATE TABLE OutputEmission +CREATE TABLE time_season_to_sequential ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER + period INTEGER REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) + sequence INTEGER, + seas_seq TEXT, + season TEXT + REFERENCES season_label (season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) ); -CREATE TABLE RPSRequirement +CREATE TABLE time_segment_fraction ( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL + period INTEGER REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES TechGroup (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE TechGroupMember -( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technologyType (label) -); -INSERT INTO technology VALUES('annual','p','energy',NULL,NULL,0,1,0,0,0,0,0,0,NULL); -INSERT INTO technology VALUES('import','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO technology VALUES('non_annual','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + segment_fraction REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) ); +INSERT INTO "time_segment_fraction" VALUES(2000,'S1','D1',1.0,NULL); +CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index fcf3137db..9fb49a027 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -1,49 +1,4 @@ -PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO metadata VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO metadata VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO metadata VALUES ('days_per_period', 365, 'count of days in each period'); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO metadata_real VALUES('global_discount_rate',0.05000000000000000277,'Discount Rate for future costs'); -INSERT INTO metadata_real VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE SeasonLabel -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SeasonLabel VALUES('S1',NULL); -CREATE TABLE SectorLabel -( - sector TEXT PRIMARY KEY, - notes TEXT -); CREATE TABLE capacity_credit ( region TEXT, @@ -63,9 +18,9 @@ CREATE TABLE capacity_factor_process period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), vintage INTEGER, @@ -80,9 +35,9 @@ CREATE TABLE capacity_factor_tech period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), factor REAL, @@ -90,11 +45,11 @@ CREATE TABLE capacity_factor_tech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO capacity_factor_tech VALUES('Testregion',2000,'S1','TOD1','TechCurtailment',1.0,NULL); -INSERT INTO capacity_factor_tech VALUES('Testregion',2000,'S1','TOD2','TechCurtailment',0.5,NULL); -INSERT INTO capacity_factor_tech VALUES('Testregion',2000,'S1','TOD1','TechOrdinary',1.0,NULL); -INSERT INTO capacity_factor_tech VALUES('Testregion',2000,'S1','TOD2','TechOrdinary',0.5,NULL); -CREATE TABLE CapacityToActivity +INSERT INTO "capacity_factor_tech" VALUES('Testregion',2000,'S1','TOD1','TechCurtailment',1.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('Testregion',2000,'S1','TOD2','TechCurtailment',0.5,NULL); +INSERT INTO "capacity_factor_tech" VALUES('Testregion',2000,'S1','TOD1','TechOrdinary',1.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('Testregion',2000,'S1','TOD2','TechOrdinary',0.5,NULL); +CREATE TABLE capacity_to_activity ( region TEXT, tech TEXT @@ -108,40 +63,40 @@ CREATE TABLE commodity name TEXT PRIMARY KEY, flag TEXT - REFERENCES commodityType (label), + REFERENCES commodity_type (label), description TEXT ); -INSERT INTO commodity VALUES('annual_in','s',NULL); -INSERT INTO commodity VALUES('flex_in','s',NULL); -INSERT INTO commodity VALUES('ordinary_in','s',NULL); -INSERT INTO commodity VALUES('curtailment_in','s',NULL); -INSERT INTO commodity VALUES('annual_out','d',NULL); -INSERT INTO commodity VALUES('flex_out','p',NULL); -INSERT INTO commodity VALUES('ordinary_out','d',NULL); -INSERT INTO commodity VALUES('curtailment_out','d',NULL); -INSERT INTO commodity VALUES('emission','e',NULL); -INSERT INTO commodity VALUES('flex_null','d',NULL); -INSERT INTO commodity VALUES('annual_flex_out','p',NULL); -INSERT INTO commodity VALUES('annual_flex_in','s',NULL); -INSERT INTO commodity VALUES('annual_flex_null','d',NULL); -INSERT INTO commodity VALUES('embodied_in','s',NULL); -INSERT INTO commodity VALUES('embodied_out','d',NULL); -INSERT INTO commodity VALUES('eol_in','s',NULL); -INSERT INTO commodity VALUES('eol_out','d',NULL); -CREATE TABLE commodityType +INSERT INTO "commodity" VALUES('annual_in','s',NULL); +INSERT INTO "commodity" VALUES('flex_in','s',NULL); +INSERT INTO "commodity" VALUES('ordinary_in','s',NULL); +INSERT INTO "commodity" VALUES('curtailment_in','s',NULL); +INSERT INTO "commodity" VALUES('annual_out','d',NULL); +INSERT INTO "commodity" VALUES('flex_out','p',NULL); +INSERT INTO "commodity" VALUES('ordinary_out','d',NULL); +INSERT INTO "commodity" VALUES('curtailment_out','d',NULL); +INSERT INTO "commodity" VALUES('emission','e',NULL); +INSERT INTO "commodity" VALUES('flex_null','d',NULL); +INSERT INTO "commodity" VALUES('annual_flex_out','p',NULL); +INSERT INTO "commodity" VALUES('annual_flex_in','s',NULL); +INSERT INTO "commodity" VALUES('annual_flex_null','d',NULL); +INSERT INTO "commodity" VALUES('embodied_in','s',NULL); +INSERT INTO "commodity" VALUES('embodied_out','d',NULL); +INSERT INTO "commodity" VALUES('eol_in','s',NULL); +INSERT INTO "commodity" VALUES('eol_out','d',NULL); +CREATE TABLE commodity_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO commodityType VALUES('w','waste commodity'); -INSERT INTO commodityType VALUES('wa','waste annual commodity'); -INSERT INTO commodityType VALUES('wp','waste physical commodity'); -INSERT INTO commodityType VALUES('a','annual commodity'); -INSERT INTO commodityType VALUES('p','physical commodity'); -INSERT INTO commodityType VALUES('e','emissions commodity'); -INSERT INTO commodityType VALUES('d','demand commodity'); -INSERT INTO commodityType VALUES('s','source commodity'); +INSERT INTO "commodity_type" VALUES('w','waste commodity'); +INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); +INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); +INSERT INTO "commodity_type" VALUES('a','annual commodity'); +INSERT INTO "commodity_type" VALUES('p','physical commodity'); +INSERT INTO "commodity_type" VALUES('e','emissions commodity'); +INSERT INTO "commodity_type" VALUES('d','demand commodity'); +INSERT INTO "commodity_type" VALUES('s','source commodity'); CREATE TABLE construction_input ( region TEXT, @@ -168,8 +123,8 @@ CREATE TABLE cost_emission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -INSERT INTO cost_emission VALUES('Testregion',2000,'emission',0.6999999999999999556,NULL,NULL); -INSERT INTO cost_emission VALUES('Testregion',2005,'emission',0.6999999999999999556,NULL,NULL); +INSERT INTO "cost_emission" VALUES('Testregion',2000,'emission',0.7,NULL,NULL); +INSERT INTO "cost_emission" VALUES('Testregion',2005,'emission',0.7,NULL,NULL); CREATE TABLE cost_fixed ( region TEXT NOT NULL, @@ -222,28 +177,28 @@ CREATE TABLE demand notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO demand VALUES('Testregion',2000,'annual_out',1.0,NULL,NULL); -INSERT INTO demand VALUES('Testregion',2000,'ordinary_out',0.2999999999999999889,NULL,NULL); -INSERT INTO demand VALUES('Testregion',2000,'curtailment_out',0.2999999999999999889,NULL,NULL); -INSERT INTO demand VALUES('Testregion',2000,'flex_null',0.2999999999999999889,NULL,NULL); -INSERT INTO demand VALUES('Testregion',2000,'annual_flex_null',0.2999999999999999889,NULL,NULL); -INSERT INTO demand VALUES('Testregion',2000,'embodied_out',0.5999999999999999778,NULL,NULL); -INSERT INTO demand VALUES('Testregion',2000,'eol_out',0.5999999999999999778,NULL,NULL); -INSERT INTO demand VALUES('Testregion',2005,'ordinary_out',0.2999999999999999889,NULL,NULL); -INSERT INTO demand VALUES('Testregion',2005,'annual_out',1.0,NULL,NULL); -INSERT INTO demand VALUES('Testregion',2005,'curtailment_out',0.2999999999999999889,NULL,NULL); -INSERT INTO demand VALUES('Testregion',2005,'flex_null',0.2999999999999999889,NULL,NULL); -INSERT INTO demand VALUES('Testregion',2005,'annual_flex_null',0.2999999999999999889,NULL,NULL); -INSERT INTO demand VALUES('Testregion',2005,'embodied_out',0.5999999999999999778,NULL,NULL); +INSERT INTO "demand" VALUES('Testregion',2000,'annual_out',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('Testregion',2000,'ordinary_out',0.3,NULL,NULL); +INSERT INTO "demand" VALUES('Testregion',2000,'curtailment_out',0.3,NULL,NULL); +INSERT INTO "demand" VALUES('Testregion',2000,'flex_null',0.3,NULL,NULL); +INSERT INTO "demand" VALUES('Testregion',2000,'annual_flex_null',0.3,NULL,NULL); +INSERT INTO "demand" VALUES('Testregion',2000,'embodied_out',0.6,NULL,NULL); +INSERT INTO "demand" VALUES('Testregion',2000,'eol_out',0.6,NULL,NULL); +INSERT INTO "demand" VALUES('Testregion',2005,'ordinary_out',0.3,NULL,NULL); +INSERT INTO "demand" VALUES('Testregion',2005,'annual_out',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('Testregion',2005,'curtailment_out',0.3,NULL,NULL); +INSERT INTO "demand" VALUES('Testregion',2005,'flex_null',0.3,NULL,NULL); +INSERT INTO "demand" VALUES('Testregion',2005,'annual_flex_null',0.3,NULL,NULL); +INSERT INTO "demand" VALUES('Testregion',2005,'embodied_out',0.6,NULL,NULL); CREATE TABLE demand_specific_distribution ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), demand_name TEXT REFERENCES commodity (name), dsd REAL, @@ -251,20 +206,6 @@ CREATE TABLE demand_specific_distribution PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); CREATE TABLE efficiency ( region TEXT, @@ -281,24 +222,24 @@ CREATE TABLE efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO efficiency VALUES('Testregion','annual_in','TechAnnual',2000,'annual_out',1.0,NULL); -INSERT INTO efficiency VALUES('Testregion','flex_in','TechFlex',2000,'flex_out',1.0,NULL); -INSERT INTO efficiency VALUES('Testregion','ordinary_in','TechOrdinary',2000,'ordinary_out',1.0,NULL); -INSERT INTO efficiency VALUES('Testregion','curtailment_in','TechCurtailment',2000,'curtailment_out',1.0,NULL); -INSERT INTO efficiency VALUES('Testregion','flex_out','TechFlexNull',2000,'flex_null',1.0,NULL); -INSERT INTO efficiency VALUES('Testregion','annual_flex_out','TechFlexNull',2000,'annual_flex_null',1.0,NULL); -INSERT INTO efficiency VALUES('Testregion','annual_flex_in','TechAnnualFlex',2000,'annual_flex_out',1.0,NULL); -INSERT INTO efficiency VALUES('Testregion','embodied_in','TechEmbodied',2000,'embodied_out',1.0,NULL); -INSERT INTO efficiency VALUES('Testregion','eol_in','TechEndOfLife',2000,'eol_out',1.0,NULL); +INSERT INTO "efficiency" VALUES('Testregion','annual_in','TechAnnual',2000,'annual_out',1.0,NULL); +INSERT INTO "efficiency" VALUES('Testregion','flex_in','TechFlex',2000,'flex_out',1.0,NULL); +INSERT INTO "efficiency" VALUES('Testregion','ordinary_in','TechOrdinary',2000,'ordinary_out',1.0,NULL); +INSERT INTO "efficiency" VALUES('Testregion','curtailment_in','TechCurtailment',2000,'curtailment_out',1.0,NULL); +INSERT INTO "efficiency" VALUES('Testregion','flex_out','TechFlexNull',2000,'flex_null',1.0,NULL); +INSERT INTO "efficiency" VALUES('Testregion','annual_flex_out','TechFlexNull',2000,'annual_flex_null',1.0,NULL); +INSERT INTO "efficiency" VALUES('Testregion','annual_flex_in','TechAnnualFlex',2000,'annual_flex_out',1.0,NULL); +INSERT INTO "efficiency" VALUES('Testregion','embodied_in','TechEmbodied',2000,'embodied_out',1.0,NULL); +INSERT INTO "efficiency" VALUES('Testregion','eol_in','TechEndOfLife',2000,'eol_out',1.0,NULL); CREATE TABLE efficiency_variable ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -330,11 +271,11 @@ CREATE TABLE emission_activity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO emission_activity VALUES('Testregion','emission','annual_in','TechAnnual',2000,'annual_out',1.0,NULL,NULL); -INSERT INTO emission_activity VALUES('Testregion','emission','flex_in','TechFlex',2000,'flex_out',1.0,NULL,NULL); -INSERT INTO emission_activity VALUES('Testregion','emission','ordinary_in','TechOrdinary',2000,'ordinary_out',1.0,NULL,NULL); -INSERT INTO emission_activity VALUES('Testregion','emission','curtailment_in','TechCurtailment',2000,'curtailment_out',1.0,NULL,NULL); -INSERT INTO emission_activity VALUES('Testregion','emission','annual_flex_in','TechAnnualFlex',2000,'annual_flex_out',1.0,NULL,NULL); +INSERT INTO "emission_activity" VALUES('Testregion','emission','annual_in','TechAnnual',2000,'annual_out',1.0,NULL,NULL); +INSERT INTO "emission_activity" VALUES('Testregion','emission','flex_in','TechFlex',2000,'flex_out',1.0,NULL,NULL); +INSERT INTO "emission_activity" VALUES('Testregion','emission','ordinary_in','TechOrdinary',2000,'ordinary_out',1.0,NULL,NULL); +INSERT INTO "emission_activity" VALUES('Testregion','emission','curtailment_in','TechCurtailment',2000,'curtailment_out',1.0,NULL,NULL); +INSERT INTO "emission_activity" VALUES('Testregion','emission','annual_flex_in','TechAnnualFlex',2000,'annual_flex_out',1.0,NULL,NULL); CREATE TABLE emission_embodied ( region TEXT, @@ -347,9 +288,9 @@ CREATE TABLE emission_embodied value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) ); -INSERT INTO emission_embodied VALUES('Testregion','emission','TechEmbodied',2000,0.5,NULL,NULL); +INSERT INTO "emission_embodied" VALUES('Testregion','emission','TechEmbodied',2000,0.5,NULL,NULL); CREATE TABLE emission_end_of_life ( region TEXT, @@ -362,9 +303,23 @@ CREATE TABLE emission_end_of_life value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) +); +INSERT INTO "emission_end_of_life" VALUES('Testregion','emission','TechEndOfLife',2000,0.5,NULL,NULL); +CREATE TABLE end_of_life_output +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); -INSERT INTO emission_end_of_life VALUES('Testregion','emission','TechEndOfLife',2000,0.5,NULL,NULL); CREATE TABLE existing_capacity ( region TEXT, @@ -377,13 +332,7 @@ CREATE TABLE existing_capacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE loan_lifetime_process +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -394,155 +343,204 @@ CREATE TABLE loan_lifetime_process notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE loan_rate +CREATE TABLE lifetime_survival_curve ( - region TEXT, - tech TEXT + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL REFERENCES technology (tech), - vintage INTEGER + vintage INTEGER NOT NULL REFERENCES time_period (period), - rate REAL, + fraction REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE lifetime_process +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), lifetime REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, tech) ); -CREATE TABLE lifetime_tech +INSERT INTO "lifetime_tech" VALUES('Testregion','TechEndOfLife',5.0,NULL); +CREATE TABLE limit_activity ( - region TEXT, - tech TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +INSERT INTO "limit_activity" VALUES('Testregion',2000,'TechFlex','ge',1.0,NULL,NULL); +INSERT INTO "limit_activity" VALUES('Testregion',2000,'TechAnnualFlex','ge',1.0,NULL,NULL); +INSERT INTO "limit_activity" VALUES('Testregion',2000,'TechFlex','le',1.0,NULL,NULL); +INSERT INTO "limit_activity" VALUES('Testregion',2000,'TechAnnualFlex','le',1.0,NULL,NULL); +CREATE TABLE limit_activity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_annual_capacity_factor +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator), + CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO lifetime_tech VALUES('Testregion','TechEndOfLife',5.0,NULL); -CREATE TABLE Operator +CREATE TABLE limit_capacity ( - operator TEXT PRIMARY KEY, - notes TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO Operator VALUES('e','equal to'); -INSERT INTO Operator VALUES('le','less than or equal to'); -INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE limit_growth_capacity +INSERT INTO "limit_capacity" VALUES('Testregion',2000,'TechOrdinary','ge',1.0,NULL,NULL); +INSERT INTO "limit_capacity" VALUES('Testregion',2000,'TechCurtailment','ge',1.0,NULL,NULL); +INSERT INTO "limit_capacity" VALUES('Testregion',2000,'TechOrdinary','le',1.0,NULL,NULL); +INSERT INTO "limit_capacity" VALUES('Testregion',2000,'TechCurtailment','le',1.0,NULL,NULL); +CREATE TABLE limit_capacity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_capacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity +CREATE TABLE limit_emission +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitStorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -CREATE TABLE limit_activity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, + REFERENCES operator (operator), + new_cap REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO limit_activity VALUES('Testregion',2000,'TechFlex','ge',1.0,NULL,NULL); -INSERT INTO limit_activity VALUES('Testregion',2000,'TechAnnualFlex','ge',1.0,NULL,NULL); -INSERT INTO limit_activity VALUES('Testregion',2000,'TechFlex','le',1.0,NULL,NULL); -INSERT INTO limit_activity VALUES('Testregion',2000,'TechAnnualFlex','le',1.0,NULL,NULL); -CREATE TABLE limit_activity_share +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -550,109 +548,56 @@ CREATE TABLE limit_activity_share sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), share REAL, notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity +CREATE TABLE limit_resource ( region TEXT, - period INTEGER - REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, + REFERENCES operator (operator), + cum_act REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) + PRIMARY KEY (region, tech_or_group, operator) ); -INSERT INTO limit_capacity VALUES('Testregion',2000,'TechOrdinary','ge',1.0,NULL,NULL); -INSERT INTO limit_capacity VALUES('Testregion',2000,'TechCurtailment','ge',1.0,NULL,NULL); -INSERT INTO limit_capacity VALUES('Testregion',2000,'TechOrdinary','le',1.0,NULL,NULL); -INSERT INTO limit_capacity VALUES('Testregion',2000,'TechCurtailment','le',1.0,NULL,NULL); -CREATE TABLE limit_capacity_share +CREATE TABLE limit_seasonal_capacity_factor ( - region TEXT, - period INTEGER + region TEXT + REFERENCES region (region), + period INTEGER REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, + season TEXT + REFERENCES season_label (season), + tech TEXT + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE limit_new_capacity +CREATE TABLE limit_storage_level_fraction ( - region TEXT, - period INTEGER + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), - tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) + REFERENCES operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); CREATE TABLE limit_tech_input_split ( @@ -664,7 +609,7 @@ CREATE TABLE limit_tech_input_split tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -679,7 +624,7 @@ CREATE TABLE limit_tech_input_split_annual tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -694,7 +639,7 @@ CREATE TABLE limit_tech_output_split output_comm TEXT REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) @@ -709,26 +654,12 @@ CREATE TABLE limit_tech_output_split_annual output_comm TEXT REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE LinkedTech +CREATE TABLE linked_tech ( primary_region TEXT, primary_tech TEXT @@ -740,6 +671,103 @@ CREATE TABLE LinkedTech notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); +CREATE TABLE loan_lifetime_process +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE loan_rate +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE metadata +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); +INSERT INTO "metadata" VALUES('DB_MINOR',0,''); +CREATE TABLE metadata_real +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +CREATE TABLE myopic_efficiency +( + base_year integer, + region text, + input_comm text, + tech text, + vintage integer, + output_comm text, + efficiency real, + lifetime integer, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (region, input_comm, tech, vintage, output_comm) +); +CREATE TABLE operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "operator" VALUES('e','equal to'); +INSERT INTO "operator" VALUES('le','less than or equal to'); +INSERT INTO "operator" VALUES('ge','greater than or equal to'); +CREATE TABLE output_built_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE output_cost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) +); CREATE TABLE output_curtailment ( scenario TEXT, @@ -750,7 +778,7 @@ CREATE TABLE output_curtailment season TEXT REFERENCES time_period (period), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -762,62 +790,42 @@ CREATE TABLE output_curtailment curtailment REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputNetCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_built_capacity +CREATE TABLE output_dual_variable ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE output_emission ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), - tech TEXT + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT REFERENCES technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE OutputFlowIn +CREATE TABLE output_flow_in ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -829,18 +837,18 @@ CREATE TABLE OutputFlowIn flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputFlowOut +CREATE TABLE output_flow_out ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -852,18 +860,70 @@ CREATE TABLE OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); +CREATE TABLE output_flow_out_summary +( + scenario TEXT NOT NULL, + region TEXT NOT NULL, + sector TEXT, + period INTEGER, + input_comm TEXT NOT NULL, + tech TEXT NOT NULL, + vintage INTEGER, + output_comm TEXT NOT NULL, + flow REAL NOT NULL, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_net_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_objective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE output_retired_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), vintage INTEGER @@ -903,14 +963,14 @@ CREATE TABLE region PRIMARY KEY, notes TEXT ); -INSERT INTO region VALUES('Testregion',NULL); +INSERT INTO "region" VALUES('Testregion',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tech TEXT REFERENCES technology (tech), vintage INTEGER, @@ -919,23 +979,28 @@ CREATE TABLE reserve_capacity_derate PRIMARY KEY (region, period, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE TimeSegmentFraction +CREATE TABLE rps_requirement ( - period INTEGER + region TEXT NOT NULL + REFERENCES region (region), + period INTEGER NOT NULL REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) + tech_group TEXT NOT NULL + REFERENCES tech_group (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE season_label +( + season TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "season_label" VALUES('S1',NULL); +CREATE TABLE sector_label +( + sector TEXT PRIMARY KEY, + notes TEXT ); -INSERT INTO TimeSegmentFraction VALUES(2000,'S1','TOD1',0.5,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'S1','TOD2',0.5,NULL); -INSERT INTO TimeSegmentFraction VALUES(2005,'S1','TOD1',0.5,NULL); -INSERT INTO TimeSegmentFraction VALUES(2005,'S1','TOD2',0.5,NULL); CREATE TABLE storage_duration ( region TEXT, @@ -944,160 +1009,143 @@ CREATE TABLE storage_duration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE lifetime_survival_curve +CREATE TABLE tech_group ( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE tech_group_member +( + group_name TEXT + REFERENCES tech_group (group_name), + tech TEXT REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) + PRIMARY KEY (group_name, tech) ); -CREATE TABLE technologyType +CREATE TABLE technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES technology_type (label) +); +INSERT INTO "technology" VALUES('TechAnnual','p','energy',NULL,NULL,0,1,0,0,0,0,0,0,NULL); +INSERT INTO "technology" VALUES('TechFlex','p','energy',NULL,NULL,0,0,0,0,0,1,0,0,NULL); +INSERT INTO "technology" VALUES('TechOrdinary','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO "technology" VALUES('TechCurtailment','p','energy',NULL,NULL,0,0,0,1,0,0,0,0,NULL); +INSERT INTO "technology" VALUES('TechFlexNull','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO "technology" VALUES('TechAnnualFlex','p','energy',NULL,NULL,0,1,0,0,0,1,0,0,NULL); +INSERT INTO "technology" VALUES('TechEmbodied','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO "technology" VALUES('TechEndOfLife','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +CREATE TABLE technology_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO technologyType VALUES('p','production technology'); -INSERT INTO technologyType VALUES('pb','baseload production technology'); -INSERT INTO technologyType VALUES('ps','storage production technology'); -CREATE TABLE TimeOfDay +INSERT INTO "technology_type" VALUES('p','production technology'); +INSERT INTO "technology_type" VALUES('pb','baseload production technology'); +INSERT INTO "technology_type" VALUES('ps','storage production technology'); +CREATE TABLE time_of_day ( sequence INTEGER UNIQUE, tod TEXT PRIMARY KEY ); -INSERT INTO TimeOfDay VALUES(1,'TOD1'); -INSERT INTO TimeOfDay VALUES(2,'TOD2'); +INSERT INTO "time_of_day" VALUES(1,'TOD1'); +INSERT INTO "time_of_day" VALUES(2,'TOD2'); CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES time_periodType (label) + REFERENCES time_period_type (label) +); +INSERT INTO "time_period" VALUES(1,1999,'e'); +INSERT INTO "time_period" VALUES(2,2000,'f'); +INSERT INTO "time_period" VALUES(3,2005,'f'); +INSERT INTO "time_period" VALUES(4,2010,'f'); +CREATE TABLE time_period_type +( + label TEXT + PRIMARY KEY, + description TEXT ); -INSERT INTO time_period VALUES(1,1999,'e'); -INSERT INTO time_period VALUES(2,2000,'f'); -INSERT INTO time_period VALUES(3,2005,'f'); -INSERT INTO time_period VALUES(4,2010,'f'); -CREATE TABLE TimeSeason +INSERT INTO "time_period_type" VALUES('e','existing vintages'); +INSERT INTO "time_period_type" VALUES('f','future'); +CREATE TABLE time_season +( + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + season TEXT REFERENCES season_label(season), + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +INSERT INTO "time_season" VALUES(2000,1,'S1',NULL); +INSERT INTO "time_season" VALUES(2005,1,'S1',NULL); +CREATE TABLE time_season_all ( period INTEGER REFERENCES time_period (period), sequence INTEGER, season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); -INSERT INTO TimeSeason VALUES(2000,1,'S1',NULL); -INSERT INTO TimeSeason VALUES(2005,1,'S1',NULL); CREATE TABLE time_season_sequential ( - period INTEGER - REFERENCES time_period (period), + period INTEGER REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES SeasonLabel (season), + season TEXT REFERENCES season_label(season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE time_periodType +CREATE TABLE time_season_to_sequential ( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO time_periodType VALUES('e','existing vintages'); -INSERT INTO time_periodType VALUES('f','future'); -CREATE TABLE OutputEmission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER + period INTEGER REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) + sequence INTEGER, + seas_seq TEXT, + season TEXT + REFERENCES season_label (season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) ); -CREATE TABLE RPSRequirement +CREATE TABLE time_segment_fraction ( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL + period INTEGER REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES TechGroup (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE TechGroupMember -( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technologyType (label) -); -INSERT INTO technology VALUES('TechAnnual','p','energy',NULL,NULL,0,1,0,0,0,0,0,0,NULL); -INSERT INTO technology VALUES('TechFlex','p','energy',NULL,NULL,0,0,0,0,0,1,0,0,NULL); -INSERT INTO technology VALUES('TechOrdinary','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO technology VALUES('TechCurtailment','p','energy',NULL,NULL,0,0,0,1,0,0,0,0,NULL); -INSERT INTO technology VALUES('TechFlexNull','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO technology VALUES('TechAnnualFlex','p','energy',NULL,NULL,0,1,0,0,0,1,0,0,NULL); -INSERT INTO technology VALUES('TechEmbodied','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO technology VALUES('TechEndOfLife','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + segment_fraction REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) ); +INSERT INTO "time_segment_fraction" VALUES(2000,'S1','TOD1',0.5,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'S1','TOD2',0.5,NULL); +INSERT INTO "time_segment_fraction" VALUES(2005,'S1','TOD1',0.5,NULL); +INSERT INTO "time_segment_fraction" VALUES(2005,'S1','TOD2',0.5,NULL); +CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index 6303a3f4d..16aba0eb7 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -1,52 +1,4 @@ -PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO metadata VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO metadata VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO metadata VALUES ('days_per_period', 365, 'count of days in each period'); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO metadata_real VALUES('global_discount_rate',0.05000000000000000277,'Discount Rate for future costs'); -INSERT INTO metadata_real VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE SeasonLabel -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SeasonLabel VALUES('summer',NULL); -INSERT INTO SeasonLabel VALUES('autumn',NULL); -INSERT INTO SeasonLabel VALUES('winter',NULL); -INSERT INTO SeasonLabel VALUES('spring',NULL); -CREATE TABLE SectorLabel -( - sector TEXT PRIMARY KEY, - notes TEXT -); CREATE TABLE capacity_credit ( region TEXT, @@ -66,9 +18,9 @@ CREATE TABLE capacity_factor_process period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), vintage INTEGER, @@ -83,9 +35,9 @@ CREATE TABLE capacity_factor_tech period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), factor REAL, @@ -93,103 +45,103 @@ CREATE TABLE capacity_factor_tech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO capacity_factor_tech VALUES('regionA',2000,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2000,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2000,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2000,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2000,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2000,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2000,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2000,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2000,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2000,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2000,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2000,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2000,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2000,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2000,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2000,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2010,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2010,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2010,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2010,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2010,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2010,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2010,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2010,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2010,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2010,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2010,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2010,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2010,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2010,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2010,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2010,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2020,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2020,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2020,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2020,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2020,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2020,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2020,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2020,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2020,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2020,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2020,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2020,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2020,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2020,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2020,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionA',2020,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2000,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2000,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2000,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2000,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2000,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2000,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2000,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2000,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2000,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2000,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2000,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2000,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2000,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2000,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2000,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2000,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2010,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2010,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2010,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2010,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2010,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2010,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2010,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2010,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2010,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2010,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2010,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2010,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2010,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2010,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2010,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2010,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2020,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2020,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2020,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2020,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2020,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2020,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2020,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2020,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2020,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2020,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2020,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2020,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2020,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2020,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2020,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('regionB',2020,'spring','overnight','SOL_PV',0.0,NULL); -CREATE TABLE CapacityToActivity +INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'summer','morning','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'autumn','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'winter','morning','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'spring','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'summer','afternoon','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'autumn','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'winter','afternoon','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'spring','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'summer','morning','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'autumn','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'winter','morning','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'spring','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'summer','afternoon','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'autumn','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'winter','afternoon','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'spring','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'summer','morning','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'autumn','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'winter','morning','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'spring','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'summer','afternoon','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'autumn','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'winter','afternoon','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'spring','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'summer','morning','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'autumn','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'winter','morning','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'spring','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'summer','afternoon','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'autumn','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'winter','afternoon','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'spring','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'summer','morning','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'autumn','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'winter','morning','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'spring','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'summer','afternoon','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'autumn','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'winter','afternoon','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'spring','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'summer','morning','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'autumn','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'winter','morning','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'spring','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'summer','afternoon','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'autumn','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'winter','afternoon','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'spring','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'spring','overnight','SOL_PV',0.0,NULL); +CREATE TABLE capacity_to_activity ( region TEXT, tech TEXT @@ -203,38 +155,38 @@ CREATE TABLE commodity name TEXT PRIMARY KEY, flag TEXT - REFERENCES commodityType (label), + REFERENCES commodity_type (label), description TEXT ); -INSERT INTO commodity VALUES('ethos','s','import dummy source'); -INSERT INTO commodity VALUES('electricity','p','grid electricity'); -INSERT INTO commodity VALUES('passenger_km','d','demand for passenger km'); -INSERT INTO commodity VALUES('battery_nmc','a','battery - lithium nickel manganese cobalt oxide'); -INSERT INTO commodity VALUES('battery_lfp','a','battery - lithium iron phosphate'); -INSERT INTO commodity VALUES('lithium','a','lithium'); -INSERT INTO commodity VALUES('cobalt','a','cobalt'); -INSERT INTO commodity VALUES('phosphorous','a','phosphorous'); -INSERT INTO commodity VALUES('diesel','a','diesel'); -INSERT INTO commodity VALUES('heating','d','demand for residential heating'); -INSERT INTO commodity VALUES('nickel','a','nickel'); -INSERT INTO commodity VALUES('used_batt_nmc','wa','used battery - lithium nickel manganese cobalt oxide'); -INSERT INTO commodity VALUES('used_batt_lfp','wa','used battery - lithium iron phosphate'); -INSERT INTO commodity VALUES('co2e','e','emitted co2-equivalent GHGs'); -INSERT INTO commodity VALUES('waste_steel','w','waste steel from cars'); -CREATE TABLE commodityType +INSERT INTO "commodity" VALUES('ethos','s','import dummy source'); +INSERT INTO "commodity" VALUES('electricity','p','grid electricity'); +INSERT INTO "commodity" VALUES('passenger_km','d','demand for passenger km'); +INSERT INTO "commodity" VALUES('battery_nmc','a','battery - lithium nickel manganese cobalt oxide'); +INSERT INTO "commodity" VALUES('battery_lfp','a','battery - lithium iron phosphate'); +INSERT INTO "commodity" VALUES('lithium','a','lithium'); +INSERT INTO "commodity" VALUES('cobalt','a','cobalt'); +INSERT INTO "commodity" VALUES('phosphorous','a','phosphorous'); +INSERT INTO "commodity" VALUES('diesel','a','diesel'); +INSERT INTO "commodity" VALUES('heating','d','demand for residential heating'); +INSERT INTO "commodity" VALUES('nickel','a','nickel'); +INSERT INTO "commodity" VALUES('used_batt_nmc','wa','used battery - lithium nickel manganese cobalt oxide'); +INSERT INTO "commodity" VALUES('used_batt_lfp','wa','used battery - lithium iron phosphate'); +INSERT INTO "commodity" VALUES('co2e','e','emitted co2-equivalent GHGs'); +INSERT INTO "commodity" VALUES('waste_steel','w','waste steel from cars'); +CREATE TABLE commodity_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO commodityType VALUES('w','waste commodity'); -INSERT INTO commodityType VALUES('wa','waste annual commodity'); -INSERT INTO commodityType VALUES('wp','waste physical commodity'); -INSERT INTO commodityType VALUES('a','annual commodity'); -INSERT INTO commodityType VALUES('p','physical commodity'); -INSERT INTO commodityType VALUES('e','emissions commodity'); -INSERT INTO commodityType VALUES('d','demand commodity'); -INSERT INTO commodityType VALUES('s','source commodity'); +INSERT INTO "commodity_type" VALUES('w','waste commodity'); +INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); +INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); +INSERT INTO "commodity_type" VALUES('a','annual commodity'); +INSERT INTO "commodity_type" VALUES('p','physical commodity'); +INSERT INTO "commodity_type" VALUES('e','emissions commodity'); +INSERT INTO "commodity_type" VALUES('d','demand commodity'); +INSERT INTO "commodity_type" VALUES('s','source commodity'); CREATE TABLE construction_input ( region TEXT, @@ -249,18 +201,18 @@ CREATE TABLE construction_input notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -INSERT INTO construction_input VALUES('regionA','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO construction_input VALUES('regionA','battery_lfp','CAR_PHEV',2000,0.1000000000000000055,NULL,NULL); -INSERT INTO construction_input VALUES('regionA','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO construction_input VALUES('regionA','battery_lfp','CAR_PHEV',2010,0.1000000000000000055,NULL,NULL); -INSERT INTO construction_input VALUES('regionA','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO construction_input VALUES('regionA','battery_lfp','CAR_PHEV',2020,0.1000000000000000055,NULL,NULL); -INSERT INTO construction_input VALUES('regionB','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO construction_input VALUES('regionB','battery_lfp','CAR_PHEV',2000,0.1000000000000000055,NULL,NULL); -INSERT INTO construction_input VALUES('regionB','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO construction_input VALUES('regionB','battery_lfp','CAR_PHEV',2010,0.1000000000000000055,NULL,NULL); -INSERT INTO construction_input VALUES('regionB','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO construction_input VALUES('regionB','battery_lfp','CAR_PHEV',2020,0.1000000000000000055,NULL,NULL); +INSERT INTO "construction_input" VALUES('regionA','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO "construction_input" VALUES('regionA','battery_lfp','CAR_PHEV',2000,0.1,NULL,NULL); +INSERT INTO "construction_input" VALUES('regionA','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO "construction_input" VALUES('regionA','battery_lfp','CAR_PHEV',2010,0.1,NULL,NULL); +INSERT INTO "construction_input" VALUES('regionA','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO "construction_input" VALUES('regionA','battery_lfp','CAR_PHEV',2020,0.1,NULL,NULL); +INSERT INTO "construction_input" VALUES('regionB','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO "construction_input" VALUES('regionB','battery_lfp','CAR_PHEV',2000,0.1,NULL,NULL); +INSERT INTO "construction_input" VALUES('regionB','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO "construction_input" VALUES('regionB','battery_lfp','CAR_PHEV',2010,0.1,NULL,NULL); +INSERT INTO "construction_input" VALUES('regionB','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO "construction_input" VALUES('regionB','battery_lfp','CAR_PHEV',2020,0.1,NULL,NULL); CREATE TABLE cost_emission ( region TEXT, @@ -273,12 +225,12 @@ CREATE TABLE cost_emission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -INSERT INTO cost_emission VALUES('regionA',2000,'co2e',1.0,NULL,NULL); -INSERT INTO cost_emission VALUES('regionA',2010,'co2e',1.0,NULL,NULL); -INSERT INTO cost_emission VALUES('regionA',2020,'co2e',1.0,NULL,NULL); -INSERT INTO cost_emission VALUES('regionB',2000,'co2e',1.0,NULL,NULL); -INSERT INTO cost_emission VALUES('regionB',2010,'co2e',1.0,NULL,NULL); -INSERT INTO cost_emission VALUES('regionB',2020,'co2e',1.0,NULL,NULL); +INSERT INTO "cost_emission" VALUES('regionA',2000,'co2e',1.0,NULL,NULL); +INSERT INTO "cost_emission" VALUES('regionA',2010,'co2e',1.0,NULL,NULL); +INSERT INTO "cost_emission" VALUES('regionA',2020,'co2e',1.0,NULL,NULL); +INSERT INTO "cost_emission" VALUES('regionB',2000,'co2e',1.0,NULL,NULL); +INSERT INTO "cost_emission" VALUES('regionB',2010,'co2e',1.0,NULL,NULL); +INSERT INTO "cost_emission" VALUES('regionB',2020,'co2e',1.0,NULL,NULL); CREATE TABLE cost_fixed ( region TEXT NOT NULL, @@ -305,40 +257,40 @@ CREATE TABLE cost_invest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO cost_invest VALUES('regionA','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionA','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionA','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionA','CAR_PHEV',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionA','CAR_PHEV',2010,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionA','CAR_PHEV',2020,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionA','CAR_ICE',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionA','CAR_ICE',2010,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionA','CAR_ICE',2020,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionA','RECYCLE_NMC',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionA','RECYCLE_LFP',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionA','MANUFAC_NMC',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionA','MANUFAC_LFP',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionA','BATT_GRID',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionA','SOL_PV',2000,10.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionA','GEN_DSL',2000,2.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionB','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionB','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionB','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionB','CAR_PHEV',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionB','CAR_PHEV',2010,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionB','CAR_PHEV',2020,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionB','CAR_ICE',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionB','CAR_ICE',2010,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionB','CAR_ICE',2020,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionB','RECYCLE_NMC',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionB','RECYCLE_LFP',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionB','MANUFAC_NMC',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionB','MANUFAC_LFP',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionB','BATT_GRID',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionB','GEN_DSL',2000,2.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionA-regionB','ELEC_INTERTIE',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionB-regionA','ELEC_INTERTIE',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('regionB','SOL_PV',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionA','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionA','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionA','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionA','CAR_PHEV',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionA','CAR_PHEV',2010,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionA','CAR_PHEV',2020,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionA','CAR_ICE',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionA','CAR_ICE',2010,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionA','CAR_ICE',2020,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionA','RECYCLE_NMC',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionA','RECYCLE_LFP',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionA','MANUFAC_NMC',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionA','MANUFAC_LFP',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionA','BATT_GRID',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionA','SOL_PV',2000,10.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionA','GEN_DSL',2000,2.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionB','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionB','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionB','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionB','CAR_PHEV',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionB','CAR_PHEV',2010,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionB','CAR_PHEV',2020,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionB','CAR_ICE',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionB','CAR_ICE',2010,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionB','CAR_ICE',2020,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionB','RECYCLE_NMC',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionB','RECYCLE_LFP',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionB','MANUFAC_NMC',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionB','MANUFAC_LFP',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionB','BATT_GRID',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionB','GEN_DSL',2000,2.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionA-regionB','ELEC_INTERTIE',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionB-regionA','ELEC_INTERTIE',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('regionB','SOL_PV',2000,1.0,NULL,NULL); CREATE TABLE cost_variable ( region TEXT NOT NULL, @@ -353,42 +305,42 @@ CREATE TABLE cost_variable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_variable VALUES('regionA',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionA',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionA',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionA',2000,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionA',2010,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionA',2020,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionA',2000,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionA',2010,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionA',2020,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionA',2000,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionA',2010,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionA',2020,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionA',2000,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionA',2010,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionA',2020,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionA',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO cost_variable VALUES('regionA',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO cost_variable VALUES('regionA',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO cost_variable VALUES('regionB',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionB',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionB',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionB',2000,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionB',2010,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionB',2020,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionB',2000,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionB',2010,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionB',2020,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionB',2000,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionB',2010,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionB',2020,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionB',2000,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionB',2010,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionB',2020,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO cost_variable VALUES('regionB',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO cost_variable VALUES('regionB',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO cost_variable VALUES('regionB',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionA',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionA',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionA',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionA',2000,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionA',2010,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionA',2020,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionA',2000,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionA',2010,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionA',2020,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionA',2000,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionA',2010,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionA',2020,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionA',2000,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionA',2010,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionA',2020,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionA',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionA',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionA',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionB',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionB',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionB',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionB',2000,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionB',2010,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionB',2020,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionB',2000,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionB',2010,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionB',2020,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionB',2000,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionB',2010,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionB',2020,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionB',2000,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionB',2010,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionB',2020,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionB',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionB',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO "cost_variable" VALUES('regionB',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); CREATE TABLE demand ( region TEXT, @@ -401,27 +353,27 @@ CREATE TABLE demand notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO demand VALUES('regionA',2000,'passenger_km',1.0,NULL,NULL); -INSERT INTO demand VALUES('regionA',2010,'passenger_km',1.0,NULL,NULL); -INSERT INTO demand VALUES('regionA',2020,'passenger_km',1.0,NULL,NULL); -INSERT INTO demand VALUES('regionA',2000,'heating',1.0,NULL,NULL); -INSERT INTO demand VALUES('regionA',2010,'heating',1.0,NULL,NULL); -INSERT INTO demand VALUES('regionA',2020,'heating',1.0,NULL,NULL); -INSERT INTO demand VALUES('regionB',2000,'passenger_km',1.0,NULL,NULL); -INSERT INTO demand VALUES('regionB',2010,'passenger_km',1.0,NULL,NULL); -INSERT INTO demand VALUES('regionB',2020,'passenger_km',1.0,NULL,NULL); -INSERT INTO demand VALUES('regionB',2000,'heating',1.0,NULL,NULL); -INSERT INTO demand VALUES('regionB',2010,'heating',1.0,NULL,NULL); -INSERT INTO demand VALUES('regionB',2020,'heating',1.0,NULL,NULL); -CREATE TABLE demand_specific_distributionon +INSERT INTO "demand" VALUES('regionA',2000,'passenger_km',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('regionA',2010,'passenger_km',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('regionA',2020,'passenger_km',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('regionA',2000,'heating',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('regionA',2010,'heating',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('regionA',2020,'heating',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('regionB',2000,'passenger_km',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('regionB',2010,'passenger_km',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('regionB',2020,'passenger_km',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('regionB',2000,'heating',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('regionB',2010,'heating',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('regionB',2020,'heating',1.0,NULL,NULL); +CREATE TABLE demand_specific_distribution ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), demand_name TEXT REFERENCES commodity (name), dsd REAL, @@ -429,146 +381,6 @@ CREATE TABLE demand_specific_distributionon PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'summer','morning','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'autumn','morning','heating',0.1199999999999999956,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'winter','morning','heating',0.1600000000000000033,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'spring','morning','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'summer','afternoon','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'autumn','afternoon','heating',0.08000000000000000166,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'winter','afternoon','heating',0.1199999999999999956,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'spring','afternoon','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'summer','evening','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'autumn','evening','heating',0.08000000000000000166,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'winter','evening','heating',0.1600000000000000033,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'spring','evening','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'summer','overnight','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'autumn','overnight','heating',0.1199999999999999956,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'winter','overnight','heating',0.1600000000000000033,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2000,'spring','overnight','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'summer','morning','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'autumn','morning','heating',0.1199999999999999956,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'winter','morning','heating',0.1600000000000000033,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'spring','morning','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'summer','afternoon','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'autumn','afternoon','heating',0.08000000000000000166,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'winter','afternoon','heating',0.1199999999999999956,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'spring','afternoon','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'summer','evening','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'autumn','evening','heating',0.08000000000000000166,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'winter','evening','heating',0.1600000000000000033,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'spring','evening','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'summer','overnight','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'autumn','overnight','heating',0.1199999999999999956,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'winter','overnight','heating',0.1600000000000000033,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2010,'spring','overnight','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'summer','morning','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'autumn','morning','heating',0.1199999999999999956,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'winter','morning','heating',0.1600000000000000033,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'spring','morning','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'summer','afternoon','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'autumn','afternoon','heating',0.08000000000000000166,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'winter','afternoon','heating',0.1199999999999999956,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'spring','afternoon','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'summer','evening','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'autumn','evening','heating',0.08000000000000000166,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'winter','evening','heating',0.1600000000000000033,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'spring','evening','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'summer','overnight','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'autumn','overnight','heating',0.1199999999999999956,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'winter','overnight','heating',0.1600000000000000033,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionA',2020,'spring','overnight','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'summer','morning','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'autumn','morning','heating',0.1199999999999999956,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'winter','morning','heating',0.1600000000000000033,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'spring','morning','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'summer','afternoon','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'autumn','afternoon','heating',0.08000000000000000166,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'winter','afternoon','heating',0.1199999999999999956,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'spring','afternoon','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'summer','evening','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'autumn','evening','heating',0.08000000000000000166,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'winter','evening','heating',0.1600000000000000033,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'spring','evening','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'summer','overnight','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'autumn','overnight','heating',0.1199999999999999956,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'winter','overnight','heating',0.1600000000000000033,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2000,'spring','overnight','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'summer','morning','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'autumn','morning','heating',0.1199999999999999956,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'winter','morning','heating',0.1600000000000000033,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'spring','morning','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'summer','afternoon','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'autumn','afternoon','heating',0.08000000000000000166,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'winter','afternoon','heating',0.1199999999999999956,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'spring','afternoon','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'summer','evening','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'autumn','evening','heating',0.08000000000000000166,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'winter','evening','heating',0.1600000000000000033,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'spring','evening','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'summer','overnight','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'autumn','overnight','heating',0.1199999999999999956,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'winter','overnight','heating',0.1600000000000000033,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2010,'spring','overnight','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'summer','morning','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'autumn','morning','heating',0.1199999999999999956,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'winter','morning','heating',0.1600000000000000033,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'spring','morning','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'summer','afternoon','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'autumn','afternoon','heating',0.08000000000000000166,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'winter','afternoon','heating',0.1199999999999999956,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'spring','afternoon','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'summer','evening','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'autumn','evening','heating',0.08000000000000000166,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'winter','evening','heating',0.1600000000000000033,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'spring','evening','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'summer','overnight','heating',0.0,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'autumn','overnight','heating',0.1199999999999999956,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'winter','overnight','heating',0.1600000000000000033,NULL); -INSERT INTO demand_specific_distributionon VALUES('regionB',2020,'spring','overnight','heating',0.0,NULL); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -INSERT INTO end_of_life_output VALUES('regionA','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionA','CAR_PHEV',1990,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionA','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionA','CAR_PHEV',2000,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionA','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionA','CAR_PHEV',2010,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionB','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionB','CAR_PHEV',1990,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionB','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionB','CAR_PHEV',2000,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionB','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionB','CAR_PHEV',2010,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionA','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionA','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionA','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionA','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionA','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionA','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionA','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionA','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionA','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionB','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionB','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionB','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionB','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionB','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionB','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionB','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionB','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('regionB','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); CREATE TABLE efficiency ( region TEXT, @@ -585,93 +397,93 @@ CREATE TABLE efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO efficiency VALUES('regionA','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2000000000000000111,NULL); -INSERT INTO efficiency VALUES('regionA','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2000000000000000111,NULL); -INSERT INTO efficiency VALUES('regionA','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','electricity','RECYCLE_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('regionA','electricity','RECYCLE_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('regionA','electricity','MANUFAC_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('regionA','electricity','MANUFAC_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('regionA','diesel','GEN_DSL',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','ethos','SOL_PV',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','electricity','BATT_GRID',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','diesel','FURNACE',2000,'heating',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','electricity','HEATPUMP',2000,'heating',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionA','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2000000000000000111,NULL); -INSERT INTO efficiency VALUES('regionB','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2000000000000000111,NULL); -INSERT INTO efficiency VALUES('regionB','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','electricity','RECYCLE_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('regionB','electricity','RECYCLE_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('regionB','electricity','MANUFAC_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('regionB','electricity','MANUFAC_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('regionB','diesel','GEN_DSL',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','ethos','SOL_PV',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','electricity','BATT_GRID',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','diesel','FURNACE',2000,'heating',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','electricity','HEATPUMP',2000,'heating',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionB','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('regionA-regionB','electricity','ELEC_INTERTIE',2000,'electricity',0.9000000000000000222,NULL); -INSERT INTO efficiency VALUES('regionB-regionA','electricity','ELEC_INTERTIE',2000,'electricity',0.9000000000000000222,NULL); +INSERT INTO "efficiency" VALUES('regionA','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2,NULL); +INSERT INTO "efficiency" VALUES('regionA','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2,NULL); +INSERT INTO "efficiency" VALUES('regionA','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','electricity','RECYCLE_NMC',2000,'battery_nmc',0.001,'Effectively zero'); +INSERT INTO "efficiency" VALUES('regionA','electricity','RECYCLE_LFP',2000,'battery_lfp',0.001,'Effectively zero'); +INSERT INTO "efficiency" VALUES('regionA','electricity','MANUFAC_NMC',2000,'battery_nmc',0.001,'Effectively zero'); +INSERT INTO "efficiency" VALUES('regionA','electricity','MANUFAC_LFP',2000,'battery_lfp',0.001,'Effectively zero'); +INSERT INTO "efficiency" VALUES('regionA','diesel','GEN_DSL',2000,'electricity',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','ethos','SOL_PV',2000,'electricity',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','electricity','BATT_GRID',2000,'electricity',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','diesel','FURNACE',2000,'heating',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','electricity','HEATPUMP',2000,'heating',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2,NULL); +INSERT INTO "efficiency" VALUES('regionB','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2,NULL); +INSERT INTO "efficiency" VALUES('regionB','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','electricity','RECYCLE_NMC',2000,'battery_nmc',0.001,'Effectively zero'); +INSERT INTO "efficiency" VALUES('regionB','electricity','RECYCLE_LFP',2000,'battery_lfp',0.001,'Effectively zero'); +INSERT INTO "efficiency" VALUES('regionB','electricity','MANUFAC_NMC',2000,'battery_nmc',0.001,'Effectively zero'); +INSERT INTO "efficiency" VALUES('regionB','electricity','MANUFAC_LFP',2000,'battery_lfp',0.001,'Effectively zero'); +INSERT INTO "efficiency" VALUES('regionB','diesel','GEN_DSL',2000,'electricity',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','ethos','SOL_PV',2000,'electricity',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','electricity','BATT_GRID',2000,'electricity',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','diesel','FURNACE',2000,'heating',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','electricity','HEATPUMP',2000,'heating',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionB','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('regionA-regionB','electricity','ELEC_INTERTIE',2000,'electricity',0.9,NULL); +INSERT INTO "efficiency" VALUES('regionB-regionA','electricity','ELEC_INTERTIE',2000,'electricity',0.9,NULL); CREATE TABLE efficiency_variable ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -703,8 +515,8 @@ CREATE TABLE emission_activity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO emission_activity VALUES('regionA','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); -INSERT INTO emission_activity VALUES('regionB','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); +INSERT INTO "emission_activity" VALUES('regionA','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); +INSERT INTO "emission_activity" VALUES('regionB','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); CREATE TABLE emission_embodied ( region TEXT, @@ -717,7 +529,7 @@ CREATE TABLE emission_embodied value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) ); CREATE TABLE emission_end_of_life ( @@ -731,8 +543,52 @@ CREATE TABLE emission_end_of_life value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE end_of_life_output +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); +INSERT INTO "end_of_life_output" VALUES('regionA','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionA','CAR_PHEV',1990,'used_batt_lfp',0.1,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionA','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionA','CAR_PHEV',2000,'used_batt_lfp',0.1,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionA','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionA','CAR_PHEV',2010,'used_batt_lfp',0.1,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionB','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionB','CAR_PHEV',1990,'used_batt_lfp',0.1,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionB','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionB','CAR_PHEV',2000,'used_batt_lfp',0.1,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionB','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionB','CAR_PHEV',2010,'used_batt_lfp',0.1,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionA','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionA','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionA','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionA','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionA','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionA','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionA','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionA','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionA','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionB','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionB','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionB','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionB','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionB','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionB','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionB','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionB','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('regionB','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); CREATE TABLE existing_capacity ( region TEXT, @@ -745,19 +601,13 @@ CREATE TABLE existing_capacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO existing_capacity VALUES('regionA','CAR_BEV',1990,1.0,NULL,NULL); -INSERT INTO existing_capacity VALUES('regionA','CAR_PHEV',1990,1.0,NULL,NULL); -INSERT INTO existing_capacity VALUES('regionA','CAR_ICE',1990,1.0,NULL,NULL); -INSERT INTO existing_capacity VALUES('regionB','CAR_BEV',1990,1.0,NULL,NULL); -INSERT INTO existing_capacity VALUES('regionB','CAR_PHEV',1990,1.0,NULL,NULL); -INSERT INTO existing_capacity VALUES('regionB','CAR_ICE',1990,1.0,NULL,NULL); -CREATE TABLE TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE loan_lifetime_process +INSERT INTO "existing_capacity" VALUES('regionA','CAR_BEV',1990,1.0,NULL,NULL); +INSERT INTO "existing_capacity" VALUES('regionA','CAR_PHEV',1990,1.0,NULL,NULL); +INSERT INTO "existing_capacity" VALUES('regionA','CAR_ICE',1990,1.0,NULL,NULL); +INSERT INTO "existing_capacity" VALUES('regionB','CAR_BEV',1990,1.0,NULL,NULL); +INSERT INTO "existing_capacity" VALUES('regionB','CAR_PHEV',1990,1.0,NULL,NULL); +INSERT INTO "existing_capacity" VALUES('regionB','CAR_ICE',1990,1.0,NULL,NULL); +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -768,156 +618,201 @@ CREATE TABLE loan_lifetime_process notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE loan_rate +CREATE TABLE lifetime_survival_curve ( - region TEXT, - tech TEXT + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL REFERENCES technology (tech), - vintage INTEGER + vintage INTEGER NOT NULL REFERENCES time_period (period), - rate REAL, + fraction REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE lifetime_process +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), lifetime REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, tech) ); -CREATE TABLE lifetime_tech +INSERT INTO "lifetime_tech" VALUES('regionA','CAR_BEV',10.0,NULL); +INSERT INTO "lifetime_tech" VALUES('regionA','CAR_PHEV',10.0,NULL); +INSERT INTO "lifetime_tech" VALUES('regionA','CAR_ICE',10.0,NULL); +INSERT INTO "lifetime_tech" VALUES('regionB','CAR_BEV',10.0,NULL); +INSERT INTO "lifetime_tech" VALUES('regionB','CAR_PHEV',10.0,NULL); +INSERT INTO "lifetime_tech" VALUES('regionB','CAR_ICE',10.0,NULL); +CREATE TABLE limit_activity ( - region TEXT, - tech TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE limit_activity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_annual_capacity_factor +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator), + CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO lifetime_tech VALUES('regionA','CAR_BEV',10.0,NULL); -INSERT INTO lifetime_tech VALUES('regionA','CAR_PHEV',10.0,NULL); -INSERT INTO lifetime_tech VALUES('regionA','CAR_ICE',10.0,NULL); -INSERT INTO lifetime_tech VALUES('regionB','CAR_BEV',10.0,NULL); -INSERT INTO lifetime_tech VALUES('regionB','CAR_PHEV',10.0,NULL); -INSERT INTO lifetime_tech VALUES('regionB','CAR_ICE',10.0,NULL); -CREATE TABLE Operator +CREATE TABLE limit_capacity ( - operator TEXT PRIMARY KEY, - notes TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO Operator VALUES('e','equal to'); -INSERT INTO Operator VALUES('le','less than or equal to'); -INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE limit_growth_capacity +CREATE TABLE limit_capacity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_capacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity +CREATE TABLE limit_emission +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitStorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -CREATE TABLE limit_activity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, + REFERENCES operator (operator), + new_cap REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE limit_activity_share +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -925,105 +820,56 @@ CREATE TABLE limit_activity_share sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), share REAL, notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity +CREATE TABLE limit_resource ( region TEXT, - period INTEGER - REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, + REFERENCES operator (operator), + cum_act REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) + PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_capacity_share +CREATE TABLE limit_seasonal_capacity_factor ( - region TEXT, - period INTEGER + region TEXT + REFERENCES region (region), + period INTEGER REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, + season TEXT + REFERENCES season_label (season), + tech TEXT + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE limit_new_capacity +CREATE TABLE limit_storage_level_fraction ( - region TEXT, - period INTEGER + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), - tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) + REFERENCES operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); CREATE TABLE limit_tech_input_split ( @@ -1035,7 +881,7 @@ CREATE TABLE limit_tech_input_split tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -1050,65 +896,65 @@ CREATE TABLE limit_tech_input_split_annual tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2000,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2000,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2000,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2000,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2000,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2000,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2000,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2010,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2010,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2010,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2010,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2010,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2010,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2010,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2020,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2020,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2020,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2020,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2020,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2020,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2020,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2000,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2000,'diesel','CAR_PHEV','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2010,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2010,'diesel','CAR_PHEV','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2020,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionA',2020,'diesel','CAR_PHEV','le',0.8000000000000000444,NULL); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2000,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2000,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2000,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2000,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2000,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2000,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2000,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2010,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2010,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2010,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2010,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2010,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2010,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2010,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2020,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2020,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2020,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2020,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2020,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2020,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2020,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2000,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2000,'diesel','CAR_PHEV','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2010,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2010,'diesel','CAR_PHEV','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2020,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO limit_tech_input_split_annual VALUES('regionB',2020,'diesel','CAR_PHEV','le',0.8000000000000000444,NULL); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'lithium','MANUFAC_NMC','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'nickel','MANUFAC_NMC','le',0.15,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'cobalt','MANUFAC_NMC','le',0.04,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'electricity','MANUFAC_NMC','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'lithium','MANUFAC_LFP','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'phosphorous','MANUFAC_LFP','le',0.19,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'electricity','MANUFAC_LFP','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'lithium','MANUFAC_NMC','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'nickel','MANUFAC_NMC','le',0.15,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'cobalt','MANUFAC_NMC','le',0.04,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'electricity','MANUFAC_NMC','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'lithium','MANUFAC_LFP','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'phosphorous','MANUFAC_LFP','le',0.19,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'electricity','MANUFAC_LFP','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'lithium','MANUFAC_NMC','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'nickel','MANUFAC_NMC','le',0.15,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'cobalt','MANUFAC_NMC','le',0.04,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'electricity','MANUFAC_NMC','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'lithium','MANUFAC_LFP','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'phosphorous','MANUFAC_LFP','le',0.19,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'electricity','MANUFAC_LFP','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'electricity','CAR_PHEV','le',0.2,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'diesel','CAR_PHEV','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'electricity','CAR_PHEV','le',0.2,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'diesel','CAR_PHEV','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'electricity','CAR_PHEV','le',0.2,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'diesel','CAR_PHEV','le',0.8,NULL); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'lithium','MANUFAC_NMC','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'nickel','MANUFAC_NMC','le',0.15,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'cobalt','MANUFAC_NMC','le',0.04,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'electricity','MANUFAC_NMC','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'lithium','MANUFAC_LFP','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'phosphorous','MANUFAC_LFP','le',0.19,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'electricity','MANUFAC_LFP','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'lithium','MANUFAC_NMC','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'nickel','MANUFAC_NMC','le',0.15,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'cobalt','MANUFAC_NMC','le',0.04,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'electricity','MANUFAC_NMC','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'lithium','MANUFAC_LFP','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'phosphorous','MANUFAC_LFP','le',0.19,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'electricity','MANUFAC_LFP','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'lithium','MANUFAC_NMC','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'nickel','MANUFAC_NMC','le',0.15,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'cobalt','MANUFAC_NMC','le',0.04,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'electricity','MANUFAC_NMC','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'lithium','MANUFAC_LFP','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'phosphorous','MANUFAC_LFP','le',0.19,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'electricity','MANUFAC_LFP','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'electricity','CAR_PHEV','le',0.2,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'diesel','CAR_PHEV','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'electricity','CAR_PHEV','le',0.2,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'diesel','CAR_PHEV','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'electricity','CAR_PHEV','le',0.2,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'diesel','CAR_PHEV','le',0.8,NULL); CREATE TABLE limit_tech_output_split ( region TEXT, @@ -1119,7 +965,7 @@ CREATE TABLE limit_tech_output_split output_comm TEXT REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) @@ -1134,26 +980,12 @@ CREATE TABLE limit_tech_output_split_annual output_comm TEXT REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE LinkedTech +CREATE TABLE linked_tech ( primary_region TEXT, primary_tech TEXT @@ -1165,6 +997,103 @@ CREATE TABLE LinkedTech notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); +CREATE TABLE loan_lifetime_process +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE loan_rate +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE metadata +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); +INSERT INTO "metadata" VALUES('DB_MINOR',0,''); +CREATE TABLE metadata_real +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +CREATE TABLE myopic_efficiency +( + base_year integer, + region text, + input_comm text, + tech text, + vintage integer, + output_comm text, + efficiency real, + lifetime integer, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (region, input_comm, tech, vintage, output_comm) +); +CREATE TABLE operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "operator" VALUES('e','equal to'); +INSERT INTO "operator" VALUES('le','less than or equal to'); +INSERT INTO "operator" VALUES('ge','greater than or equal to'); +CREATE TABLE output_built_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE output_cost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) +); CREATE TABLE output_curtailment ( scenario TEXT, @@ -1175,7 +1104,7 @@ CREATE TABLE output_curtailment season TEXT REFERENCES time_period (period), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -1187,62 +1116,42 @@ CREATE TABLE output_curtailment curtailment REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputNetCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_built_capacity +CREATE TABLE output_dual_variable ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE output_emission ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), - tech TEXT + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT REFERENCES technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE OutputFlowIn +CREATE TABLE output_flow_in ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -1254,18 +1163,18 @@ CREATE TABLE OutputFlowIn flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputFlowOut +CREATE TABLE output_flow_out ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -1277,18 +1186,70 @@ CREATE TABLE OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); +CREATE TABLE output_flow_out_summary +( + scenario TEXT NOT NULL, + region TEXT NOT NULL, + sector TEXT, + period INTEGER, + input_comm TEXT NOT NULL, + tech TEXT NOT NULL, + vintage INTEGER, + output_comm TEXT NOT NULL, + flow REAL NOT NULL, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_net_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_objective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE output_retired_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), vintage INTEGER @@ -1328,15 +1289,15 @@ CREATE TABLE region PRIMARY KEY, notes TEXT ); -INSERT INTO region VALUES('regionA',NULL); -INSERT INTO region VALUES('regionB',NULL); +INSERT INTO "region" VALUES('regionA',NULL); +INSERT INTO "region" VALUES('regionB',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tech TEXT REFERENCES technology (tech), vintage INTEGER, @@ -1345,67 +1306,31 @@ CREATE TABLE reserve_capacity_derate PRIMARY KEY (region, period, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE TimeSegmentFraction +CREATE TABLE rps_requirement ( - period INTEGER + region TEXT NOT NULL + REFERENCES region (region), + period INTEGER NOT NULL REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) -); -INSERT INTO TimeSegmentFraction VALUES(2000,'summer','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'autumn','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'winter','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'spring','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'summer','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'autumn','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'winter','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'spring','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'summer','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'autumn','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'winter','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'spring','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'summer','overnight',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'autumn','overnight',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'winter','overnight',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'spring','overnight',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'summer','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'autumn','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'winter','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'spring','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'summer','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'autumn','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'winter','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'spring','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'summer','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'autumn','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'winter','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'spring','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'summer','overnight',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'autumn','overnight',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'winter','overnight',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'spring','overnight',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'summer','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'autumn','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'winter','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'spring','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'summer','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'autumn','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'winter','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'spring','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'summer','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'autumn','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'winter','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'spring','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'summer','overnight',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'autumn','overnight',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'winter','overnight',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'spring','overnight',0.0625,NULL); + tech_group TEXT NOT NULL + REFERENCES tech_group (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE season_label +( + season TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "season_label" VALUES('summer',NULL); +INSERT INTO "season_label" VALUES('autumn',NULL); +INSERT INTO "season_label" VALUES('winter',NULL); +INSERT INTO "season_label" VALUES('spring',NULL); +CREATE TABLE sector_label +( + sector TEXT PRIMARY KEY, + notes TEXT +); CREATE TABLE storage_duration ( region TEXT, @@ -1414,186 +1339,213 @@ CREATE TABLE storage_duration notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO storage_duration VALUES('regionA','BATT_GRID',2.0,'2 hours energy storage'); -INSERT INTO storage_duration VALUES('regionB','BATT_GRID',2.0,'2 hours energy storage'); -CREATE TABLE lifetime_survival_curve +INSERT INTO "storage_duration" VALUES('regionA','BATT_GRID',2.0,'2 hours energy storage'); +INSERT INTO "storage_duration" VALUES('regionB','BATT_GRID',2.0,'2 hours energy storage'); +CREATE TABLE tech_group ( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE tech_group_member +( + group_name TEXT + REFERENCES tech_group (group_name), + tech TEXT REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) + PRIMARY KEY (group_name, tech) ); -CREATE TABLE technologyType +CREATE TABLE technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES technology_type (label) +); +INSERT INTO "technology" VALUES('IMPORT_LI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'lithium importer'); +INSERT INTO "technology" VALUES('IMPORT_CO','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'cobalt importer'); +INSERT INTO "technology" VALUES('IMPORT_P','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'phosphorous importer'); +INSERT INTO "technology" VALUES('CAR_BEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - battery electric'); +INSERT INTO "technology" VALUES('CAR_PHEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - plug in hybrid'); +INSERT INTO "technology" VALUES('CAR_ICE','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - internal combustion'); +INSERT INTO "technology" VALUES('RECYCLE_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'nmc battery recycler'); +INSERT INTO "technology" VALUES('RECYCLE_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'lfp battery recycler'); +INSERT INTO "technology" VALUES('MANUFAC_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'nmc battery manufacturing'); +INSERT INTO "technology" VALUES('MANUFAC_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'lfp battery manufacturing'); +INSERT INTO "technology" VALUES('IMPORT_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'nickel importer'); +INSERT INTO "technology" VALUES('DOMESTIC_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'domestic nickel production'); +INSERT INTO "technology" VALUES('GEN_DSL','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,'diesel generators'); +INSERT INTO "technology" VALUES('SOL_PV','p','electricity',NULL,NULL,0,0,0,1,0,0,0,0,'solar panels'); +INSERT INTO "technology" VALUES('BATT_GRID','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,0,'grid battery storage'); +INSERT INTO "technology" VALUES('FURNACE','p','residential',NULL,NULL,1,0,0,0,0,0,0,0,'diesel furnace heater'); +INSERT INTO "technology" VALUES('HEATPUMP','p','residential',NULL,NULL,1,0,0,0,0,0,0,0,'heat pump'); +INSERT INTO "technology" VALUES('IMPORT_DSL','p','fuels',NULL,NULL,1,1,0,0,0,0,0,0,'diesel importer'); +INSERT INTO "technology" VALUES('ELEC_INTERTIE','p','electricity',NULL,NULL,0,0,0,0,0,0,1,0,'dummy tech to make landfill feasible'); +CREATE TABLE technology_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO technologyType VALUES('p','production technology'); -INSERT INTO technologyType VALUES('pb','baseload production technology'); -INSERT INTO technologyType VALUES('ps','storage production technology'); -CREATE TABLE TimeOfDay +INSERT INTO "technology_type" VALUES('p','production technology'); +INSERT INTO "technology_type" VALUES('pb','baseload production technology'); +INSERT INTO "technology_type" VALUES('ps','storage production technology'); +CREATE TABLE time_of_day ( sequence INTEGER UNIQUE, tod TEXT PRIMARY KEY ); -INSERT INTO TimeOfDay VALUES(1,'morning'); -INSERT INTO TimeOfDay VALUES(2,'afternoon'); -INSERT INTO TimeOfDay VALUES(3,'evening'); -INSERT INTO TimeOfDay VALUES(4,'overnight'); +INSERT INTO "time_of_day" VALUES(1,'morning'); +INSERT INTO "time_of_day" VALUES(2,'afternoon'); +INSERT INTO "time_of_day" VALUES(3,'evening'); +INSERT INTO "time_of_day" VALUES(4,'overnight'); CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES time_periodType (label) + REFERENCES time_period_type (label) ); -INSERT INTO time_period VALUES(1,1990,'e'); -INSERT INTO time_period VALUES(2,2000,'f'); -INSERT INTO time_period VALUES(3,2010,'f'); -INSERT INTO time_period VALUES(4,2020,'f'); -INSERT INTO time_period VALUES(5,2030,'f'); -CREATE TABLE TimeSeason +INSERT INTO "time_period" VALUES(1,1990,'e'); +INSERT INTO "time_period" VALUES(2,2000,'f'); +INSERT INTO "time_period" VALUES(3,2010,'f'); +INSERT INTO "time_period" VALUES(4,2020,'f'); +INSERT INTO "time_period" VALUES(5,2030,'f'); +CREATE TABLE time_period_type +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO "time_period_type" VALUES('e','existing vintages'); +INSERT INTO "time_period_type" VALUES('f','future'); +CREATE TABLE time_season +( + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + season TEXT REFERENCES season_label(season), + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +INSERT INTO "time_season" VALUES(2000,1,'summer',NULL); +INSERT INTO "time_season" VALUES(2000,2,'autumn',NULL); +INSERT INTO "time_season" VALUES(2000,3,'winter',NULL); +INSERT INTO "time_season" VALUES(2000,4,'spring',NULL); +INSERT INTO "time_season" VALUES(2010,5,'summer',NULL); +INSERT INTO "time_season" VALUES(2010,6,'autumn',NULL); +INSERT INTO "time_season" VALUES(2010,7,'winter',NULL); +INSERT INTO "time_season" VALUES(2010,8,'spring',NULL); +INSERT INTO "time_season" VALUES(2020,9,'summer',NULL); +INSERT INTO "time_season" VALUES(2020,10,'autumn',NULL); +INSERT INTO "time_season" VALUES(2020,11,'winter',NULL); +INSERT INTO "time_season" VALUES(2020,12,'spring',NULL); +CREATE TABLE time_season_all ( period INTEGER REFERENCES time_period (period), sequence INTEGER, season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); -INSERT INTO TimeSeason VALUES(2000,1,'summer',NULL); -INSERT INTO TimeSeason VALUES(2000,2,'autumn',NULL); -INSERT INTO TimeSeason VALUES(2000,3,'winter',NULL); -INSERT INTO TimeSeason VALUES(2000,4,'spring',NULL); -INSERT INTO TimeSeason VALUES(2010,5,'summer',NULL); -INSERT INTO TimeSeason VALUES(2010,6,'autumn',NULL); -INSERT INTO TimeSeason VALUES(2010,7,'winter',NULL); -INSERT INTO TimeSeason VALUES(2010,8,'spring',NULL); -INSERT INTO TimeSeason VALUES(2020,9,'summer',NULL); -INSERT INTO TimeSeason VALUES(2020,10,'autumn',NULL); -INSERT INTO TimeSeason VALUES(2020,11,'winter',NULL); -INSERT INTO TimeSeason VALUES(2020,12,'spring',NULL); CREATE TABLE time_season_sequential ( - period INTEGER - REFERENCES time_period (period), + period INTEGER REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES SeasonLabel (season), + season TEXT REFERENCES season_label(season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE time_periodType -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO time_periodType VALUES('e','existing vintages'); -INSERT INTO time_periodType VALUES('f','future'); -CREATE TABLE OutputEmission +CREATE TABLE time_season_to_sequential ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER + period INTEGER REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) + sequence INTEGER, + seas_seq TEXT, + season TEXT + REFERENCES season_label (season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) ); -CREATE TABLE RPSRequirement +CREATE TABLE time_segment_fraction ( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL + period INTEGER REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES TechGroup (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE TechGroupMember -( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technologyType (label) -); -INSERT INTO technology VALUES('IMPORT_LI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'lithium importer'); -INSERT INTO technology VALUES('IMPORT_CO','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'cobalt importer'); -INSERT INTO technology VALUES('IMPORT_P','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'phosphorous importer'); -INSERT INTO technology VALUES('CAR_BEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - battery electric'); -INSERT INTO technology VALUES('CAR_PHEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - plug in hybrid'); -INSERT INTO technology VALUES('CAR_ICE','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - internal combustion'); -INSERT INTO technology VALUES('RECYCLE_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'nmc battery recycler'); -INSERT INTO technology VALUES('RECYCLE_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'lfp battery recycler'); -INSERT INTO technology VALUES('MANUFAC_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'nmc battery manufacturing'); -INSERT INTO technology VALUES('MANUFAC_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'lfp battery manufacturing'); -INSERT INTO technology VALUES('IMPORT_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'nickel importer'); -INSERT INTO technology VALUES('DOMESTIC_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'domestic nickel production'); -INSERT INTO technology VALUES('GEN_DSL','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,'diesel generators'); -INSERT INTO technology VALUES('SOL_PV','p','electricity',NULL,NULL,0,0,0,1,0,0,0,0,'solar panels'); -INSERT INTO technology VALUES('BATT_GRID','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,0,'grid battery storage'); -INSERT INTO technology VALUES('FURNACE','p','residential',NULL,NULL,1,0,0,0,0,0,0,0,'diesel furnace heater'); -INSERT INTO technology VALUES('HEATPUMP','p','residential',NULL,NULL,1,0,0,0,0,0,0,0,'heat pump'); -INSERT INTO technology VALUES('IMPORT_DSL','p','fuels',NULL,NULL,1,1,0,0,0,0,0,0,'diesel importer'); -INSERT INTO technology VALUES('ELEC_INTERTIE','p','electricity',NULL,NULL,0,0,0,0,0,0,1,0,'dummy tech to make landfill feasible'); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) -); + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + segment_fraction REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) +); +INSERT INTO "time_segment_fraction" VALUES(2000,'summer','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'autumn','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'winter','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'spring','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'summer','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'autumn','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'winter','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'spring','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'summer','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'autumn','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'winter','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'spring','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'summer','overnight',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'autumn','overnight',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'winter','overnight',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'spring','overnight',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'summer','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'autumn','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'winter','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'spring','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'summer','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'autumn','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'winter','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'spring','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'summer','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'autumn','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'winter','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'spring','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'summer','overnight',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'autumn','overnight',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'winter','overnight',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'spring','overnight',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'summer','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'autumn','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'winter','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'spring','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'summer','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'autumn','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'winter','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'spring','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'summer','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'autumn','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'winter','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'spring','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'summer','overnight',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'autumn','overnight',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'winter','overnight',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'spring','overnight',0.0625,NULL); +CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index b47c30171..0c3d0aed6 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -1,56 +1,4 @@ -PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO metadata VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO metadata VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO metadata VALUES ('days_per_period', 365, 'count of days in each period'); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO metadata_real VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); -INSERT INTO metadata_real VALUES('global_discount_rate',0.42000000000000004,''); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE SeasonLabel -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SeasonLabel VALUES('s1',NULL); -INSERT INTO SeasonLabel VALUES('s2',NULL); -CREATE TABLE SectorLabel -( - sector TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SectorLabel VALUES('supply',NULL); -INSERT INTO SectorLabel VALUES('electric',NULL); -INSERT INTO SectorLabel VALUES('transport',NULL); -INSERT INTO SectorLabel VALUES('commercial',NULL); -INSERT INTO SectorLabel VALUES('residential',NULL); -INSERT INTO SectorLabel VALUES('industrial',NULL); CREATE TABLE capacity_credit ( region TEXT, @@ -64,16 +12,16 @@ CREATE TABLE capacity_credit PRIMARY KEY (region, period, tech, vintage), CHECK (credit >= 0 AND credit <= 1) ); -INSERT INTO capacity_credit VALUES('A',2025,'EF',2025,0.5999999999999999778,NULL); +INSERT INTO "capacity_credit" VALUES('A',2025,'EF',2025,0.6,NULL); CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), vintage INTEGER, @@ -82,17 +30,17 @@ CREATE TABLE capacity_factor_process PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO capacity_factor_process VALUES('A',2025,'s2','d1','EFL',2025,0.8000000000000000444,NULL); -INSERT INTO capacity_factor_process VALUES('A',2025,'s1','d2','EFL',2025,0.9000000000000000222,NULL); +INSERT INTO "capacity_factor_process" VALUES('A',2025,'s2','d1','EFL',2025,0.8,NULL); +INSERT INTO "capacity_factor_process" VALUES('A',2025,'s1','d2','EFL',2025,0.9,NULL); CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), factor REAL, @@ -100,9 +48,9 @@ CREATE TABLE capacity_factor_tech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO capacity_factor_tech VALUES('A',2025,'s1','d1','EF',0.8000000000000000444,NULL); -INSERT INTO capacity_factor_tech VALUES('B',2025,'s2','d2','bulbs',0.75,NULL); -CREATE TABLE CapacityToActivity +INSERT INTO "capacity_factor_tech" VALUES('A',2025,'s1','d1','EF',0.8,NULL); +INSERT INTO "capacity_factor_tech" VALUES('B',2025,'s2','d2','bulbs',0.75,NULL); +CREATE TABLE capacity_to_activity ( region TEXT, tech TEXT @@ -111,39 +59,39 @@ CREATE TABLE CapacityToActivity notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO CapacityToActivity VALUES('A','bulbs',1.0,''); -INSERT INTO CapacityToActivity VALUES('B','bulbs',1.0,NULL); +INSERT INTO "capacity_to_activity" VALUES('A','bulbs',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('B','bulbs',1.0,NULL); CREATE TABLE commodity ( name TEXT PRIMARY KEY, flag TEXT - REFERENCES commodityType (label), + REFERENCES commodity_type (label), description TEXT ); -INSERT INTO commodity VALUES('ELC','p','electricity'); -INSERT INTO commodity VALUES('HYD','p','water'); -INSERT INTO commodity VALUES('co2','e','CO2 emissions'); -INSERT INTO commodity VALUES('RL','d','residential lighting'); -INSERT INTO commodity VALUES('earth','s','the source of stuff'); -INSERT INTO commodity VALUES('RH','d','residential heat'); -INSERT INTO commodity VALUES('FusionGas','e','mystery emission'); -INSERT INTO commodity VALUES('FusionGasFuel','p','converted mystery gas to fuel'); -INSERT INTO commodity VALUES('GeoHyd','p','Hot water from geo'); -CREATE TABLE commodityType +INSERT INTO "commodity" VALUES('ELC','p','electricity'); +INSERT INTO "commodity" VALUES('HYD','p','water'); +INSERT INTO "commodity" VALUES('co2','e','CO2 emissions'); +INSERT INTO "commodity" VALUES('RL','d','residential lighting'); +INSERT INTO "commodity" VALUES('earth','s','the source of stuff'); +INSERT INTO "commodity" VALUES('RH','d','residential heat'); +INSERT INTO "commodity" VALUES('FusionGas','e','mystery emission'); +INSERT INTO "commodity" VALUES('FusionGasFuel','p','converted mystery gas to fuel'); +INSERT INTO "commodity" VALUES('GeoHyd','p','Hot water from geo'); +CREATE TABLE commodity_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO commodityType VALUES('w','waste commodity'); -INSERT INTO commodityType VALUES('wa','waste annual commodity'); -INSERT INTO commodityType VALUES('wp','waste physical commodity'); -INSERT INTO commodityType VALUES('a','annual commodity'); -INSERT INTO commodityType VALUES('p','physical commodity'); -INSERT INTO commodityType VALUES('e','emissions commodity'); -INSERT INTO commodityType VALUES('d','demand commodity'); -INSERT INTO commodityType VALUES('s','source commodity'); +INSERT INTO "commodity_type" VALUES('w','waste commodity'); +INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); +INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); +INSERT INTO "commodity_type" VALUES('a','annual commodity'); +INSERT INTO "commodity_type" VALUES('p','physical commodity'); +INSERT INTO "commodity_type" VALUES('e','emissions commodity'); +INSERT INTO "commodity_type" VALUES('d','demand commodity'); +INSERT INTO "commodity_type" VALUES('s','source commodity'); CREATE TABLE construction_input ( region TEXT, @@ -170,7 +118,7 @@ CREATE TABLE cost_emission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -INSERT INTO cost_emission VALUES('A',2025,'co2',1.989999999999999992,'dollars','none'); +INSERT INTO "cost_emission" VALUES('A',2025,'co2',1.99,'dollars','none'); CREATE TABLE cost_fixed ( region TEXT NOT NULL, @@ -185,20 +133,20 @@ CREATE TABLE cost_fixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_fixed VALUES('A',2025,'EH',2025,3.299999999999999823,'',''); -INSERT INTO cost_fixed VALUES('A',2025,'EF',2025,2.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('A',2025,'EFL',2025,3.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('B',2025,'batt',2025,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('B',2025,'EF',2025,2.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('A',2025,'bulbs',2025,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('B',2025,'bulbs',2025,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('A',2025,'heater',2025,2.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('B',2025,'heater',2025,2.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('B',2025,'GeoThermal',2025,6.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('B',2025,'GeoHeater',2025,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('B',2025,'EH',2025,3.299999999999999823,NULL,NULL); -INSERT INTO cost_fixed VALUES('A',2025,'GeoThermal',2025,4.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('A',2025,'GeoHeater',2025,4.5,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('A',2025,'EH',2025,3.3,'',''); +INSERT INTO "cost_fixed" VALUES('A',2025,'EF',2025,2.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('A',2025,'EFL',2025,3.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('B',2025,'batt',2025,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('B',2025,'EF',2025,2.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('A',2025,'bulbs',2025,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('B',2025,'bulbs',2025,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('A',2025,'heater',2025,2.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('B',2025,'heater',2025,2.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('B',2025,'GeoThermal',2025,6.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('B',2025,'GeoHeater',2025,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('B',2025,'EH',2025,3.3,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('A',2025,'GeoThermal',2025,4.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('A',2025,'GeoHeater',2025,4.5,NULL,NULL); CREATE TABLE cost_invest ( region TEXT, @@ -211,20 +159,20 @@ CREATE TABLE cost_invest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO cost_invest VALUES('A','EF',2025,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('A','EH',2025,3.0,NULL,NULL); -INSERT INTO cost_invest VALUES('A','bulbs',2025,4.0,NULL,NULL); -INSERT INTO cost_invest VALUES('A','heater',2025,5.0,NULL,NULL); -INSERT INTO cost_invest VALUES('B','EF',2025,6.0,NULL,NULL); -INSERT INTO cost_invest VALUES('B','batt',2025,7.0,NULL,NULL); -INSERT INTO cost_invest VALUES('B','bulbs',2025,8.0,NULL,NULL); -INSERT INTO cost_invest VALUES('B','heater',2025,9.0,NULL,NULL); -INSERT INTO cost_invest VALUES('A','EFL',2025,2.0,NULL,NULL); -INSERT INTO cost_invest VALUES('B','GeoThermal',2025,3.0,NULL,NULL); -INSERT INTO cost_invest VALUES('B','GeoHeater',2025,4.0,NULL,NULL); -INSERT INTO cost_invest VALUES('B','EH',2025,3.299999999999999823,NULL,NULL); -INSERT INTO cost_invest VALUES('A','GeoThermal',2025,5.599999999999999645,NULL,NULL); -INSERT INTO cost_invest VALUES('A','GeoHeater',2025,4.200000000000000177,NULL,NULL); +INSERT INTO "cost_invest" VALUES('A','EF',2025,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('A','EH',2025,3.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('A','bulbs',2025,4.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('A','heater',2025,5.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('B','EF',2025,6.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('B','batt',2025,7.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('B','bulbs',2025,8.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('B','heater',2025,9.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('A','EFL',2025,2.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('B','GeoThermal',2025,3.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('B','GeoHeater',2025,4.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('B','EH',2025,3.3,NULL,NULL); +INSERT INTO "cost_invest" VALUES('A','GeoThermal',2025,5.6,NULL,NULL); +INSERT INTO "cost_invest" VALUES('A','GeoHeater',2025,4.2,NULL,NULL); CREATE TABLE cost_variable ( region TEXT NOT NULL, @@ -239,15 +187,15 @@ CREATE TABLE cost_variable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_variable VALUES('A',2025,'EF',2025,9.0,NULL,NULL); -INSERT INTO cost_variable VALUES('A',2025,'EFL',2025,8.0,NULL,NULL); -INSERT INTO cost_variable VALUES('A',2025,'EH',2025,7.0,NULL,NULL); -INSERT INTO cost_variable VALUES('A',2025,'bulbs',2025,6.0,NULL,NULL); -INSERT INTO cost_variable VALUES('A',2025,'heater',2025,5.0,NULL,NULL); -INSERT INTO cost_variable VALUES('B',2025,'EF',2025,4.0,NULL,NULL); -INSERT INTO cost_variable VALUES('B',2025,'batt',2025,3.0,NULL,NULL); -INSERT INTO cost_variable VALUES('B',2025,'bulbs',2025,2.0,NULL,NULL); -INSERT INTO cost_variable VALUES('B',2025,'heater',2025,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('A',2025,'EF',2025,9.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('A',2025,'EFL',2025,8.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('A',2025,'EH',2025,7.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('A',2025,'bulbs',2025,6.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('A',2025,'heater',2025,5.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('B',2025,'EF',2025,4.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('B',2025,'batt',2025,3.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('B',2025,'bulbs',2025,2.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('B',2025,'heater',2025,1.0,NULL,NULL); CREATE TABLE demand ( region TEXT, @@ -260,19 +208,19 @@ CREATE TABLE demand notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO demand VALUES('A',2025,'RL',100.0,'',''); -INSERT INTO demand VALUES('B',2025,'RL',100.0,NULL,NULL); -INSERT INTO demand VALUES('A',2025,'RH',50.0,NULL,NULL); -INSERT INTO demand VALUES('B',2025,'RH',50.0,NULL,NULL); +INSERT INTO "demand" VALUES('A',2025,'RL',100.0,'',''); +INSERT INTO "demand" VALUES('B',2025,'RL',100.0,NULL,NULL); +INSERT INTO "demand" VALUES('A',2025,'RH',50.0,NULL,NULL); +INSERT INTO "demand" VALUES('B',2025,'RH',50.0,NULL,NULL); CREATE TABLE demand_specific_distribution ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), demand_name TEXT REFERENCES commodity (name), dsd REAL, @@ -280,36 +228,22 @@ CREATE TABLE demand_specific_distribution PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO demand_specific_distribution VALUES('A',2025,'s1','d1','RL',0.25,NULL); -INSERT INTO demand_specific_distribution VALUES('A',2025,'s1','d2','RL',0.25,NULL); -INSERT INTO demand_specific_distribution VALUES('A',2025,'s2','d1','RL',0.25,NULL); -INSERT INTO demand_specific_distribution VALUES('A',2025,'s2','d2','RL',0.25,NULL); -INSERT INTO demand_specific_distribution VALUES('B',2025,'s1','d1','RL',0.25,NULL); -INSERT INTO demand_specific_distribution VALUES('B',2025,'s1','d2','RL',0.25,NULL); -INSERT INTO demand_specific_distribution VALUES('B',2025,'s2','d1','RL',0.25,NULL); -INSERT INTO demand_specific_distribution VALUES('B',2025,'s2','d2','RL',0.25,NULL); -INSERT INTO demand_specific_distribution VALUES('A',2025,'s1','d1','RH',0.25,NULL); -INSERT INTO demand_specific_distribution VALUES('A',2025,'s2','d1','RH',0.25,NULL); -INSERT INTO demand_specific_distribution VALUES('B',2025,'s1','d1','RH',0.25,NULL); -INSERT INTO demand_specific_distribution VALUES('B',2025,'s2','d1','RH',0.25,NULL); -INSERT INTO demand_specific_distribution VALUES('A',2025,'s1','d2','RH',0.25,NULL); -INSERT INTO demand_specific_distribution VALUES('A',2025,'s2','d2','RH',0.25,NULL); -INSERT INTO demand_specific_distribution VALUES('B',2025,'s1','d2','RH',0.25,NULL); -INSERT INTO demand_specific_distribution VALUES('B',2025,'s2','d2','RH',0.25,NULL); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); +INSERT INTO "demand_specific_distribution" VALUES('A',2025,'s1','d1','RL',0.25,NULL); +INSERT INTO "demand_specific_distribution" VALUES('A',2025,'s1','d2','RL',0.25,NULL); +INSERT INTO "demand_specific_distribution" VALUES('A',2025,'s2','d1','RL',0.25,NULL); +INSERT INTO "demand_specific_distribution" VALUES('A',2025,'s2','d2','RL',0.25,NULL); +INSERT INTO "demand_specific_distribution" VALUES('B',2025,'s1','d1','RL',0.25,NULL); +INSERT INTO "demand_specific_distribution" VALUES('B',2025,'s1','d2','RL',0.25,NULL); +INSERT INTO "demand_specific_distribution" VALUES('B',2025,'s2','d1','RL',0.25,NULL); +INSERT INTO "demand_specific_distribution" VALUES('B',2025,'s2','d2','RL',0.25,NULL); +INSERT INTO "demand_specific_distribution" VALUES('A',2025,'s1','d1','RH',0.25,NULL); +INSERT INTO "demand_specific_distribution" VALUES('A',2025,'s2','d1','RH',0.25,NULL); +INSERT INTO "demand_specific_distribution" VALUES('B',2025,'s1','d1','RH',0.25,NULL); +INSERT INTO "demand_specific_distribution" VALUES('B',2025,'s2','d1','RH',0.25,NULL); +INSERT INTO "demand_specific_distribution" VALUES('A',2025,'s1','d2','RH',0.25,NULL); +INSERT INTO "demand_specific_distribution" VALUES('A',2025,'s2','d2','RH',0.25,NULL); +INSERT INTO "demand_specific_distribution" VALUES('B',2025,'s1','d2','RH',0.25,NULL); +INSERT INTO "demand_specific_distribution" VALUES('B',2025,'s2','d2','RH',0.25,NULL); CREATE TABLE efficiency ( region TEXT, @@ -326,33 +260,33 @@ CREATE TABLE efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO efficiency VALUES('A','ELC','bulbs',2025,'RL',1.0,NULL); -INSERT INTO efficiency VALUES('A','HYD','EH',2025,'ELC',1.0,NULL); -INSERT INTO efficiency VALUES('A','HYD','EF',2025,'ELC',1.0,NULL); -INSERT INTO efficiency VALUES('B','ELC','bulbs',2025,'RL',1.0,NULL); -INSERT INTO efficiency VALUES('B','HYD','EH',2025,'ELC',1.0,NULL); -INSERT INTO efficiency VALUES('B','ELC','batt',2025,'ELC',1.0,NULL); -INSERT INTO efficiency VALUES('B','HYD','EF',2025,'ELC',1.0,NULL); -INSERT INTO efficiency VALUES('A','earth','well',2025,'HYD',1.0,NULL); -INSERT INTO efficiency VALUES('B','earth','well',2025,'HYD',1.0,NULL); -INSERT INTO efficiency VALUES('A','earth','EFL',2025,'FusionGasFuel',1.0,NULL); -INSERT INTO efficiency VALUES('A','FusionGasFuel','heater',2025,'RH',0.9000000000000000222,NULL); -INSERT INTO efficiency VALUES('A-B','FusionGasFuel','FGF_pipe',2025,'FusionGasFuel',0.949999999999999956,NULL); -INSERT INTO efficiency VALUES('B','FusionGasFuel','heater',2025,'RH',0.9000000000000000222,NULL); -INSERT INTO efficiency VALUES('B','GeoHyd','GeoHeater',2025,'RH',0.980000000000000094,NULL); -INSERT INTO efficiency VALUES('B','earth','GeoThermal',2025,'GeoHyd',1.0,NULL); -INSERT INTO efficiency VALUES('B-A','FusionGasFuel','FGF_pipe',2025,'FusionGasFuel',0.949999999999999956,NULL); -INSERT INTO efficiency VALUES('A','GeoHyd','GeoHeater',2025,'RH',0.9000000000000000222,NULL); -INSERT INTO efficiency VALUES('A','earth','GeoThermal',2025,'GeoHyd',1.0,NULL); +INSERT INTO "efficiency" VALUES('A','ELC','bulbs',2025,'RL',1.0,NULL); +INSERT INTO "efficiency" VALUES('A','HYD','EH',2025,'ELC',1.0,NULL); +INSERT INTO "efficiency" VALUES('A','HYD','EF',2025,'ELC',1.0,NULL); +INSERT INTO "efficiency" VALUES('B','ELC','bulbs',2025,'RL',1.0,NULL); +INSERT INTO "efficiency" VALUES('B','HYD','EH',2025,'ELC',1.0,NULL); +INSERT INTO "efficiency" VALUES('B','ELC','batt',2025,'ELC',1.0,NULL); +INSERT INTO "efficiency" VALUES('B','HYD','EF',2025,'ELC',1.0,NULL); +INSERT INTO "efficiency" VALUES('A','earth','well',2025,'HYD',1.0,NULL); +INSERT INTO "efficiency" VALUES('B','earth','well',2025,'HYD',1.0,NULL); +INSERT INTO "efficiency" VALUES('A','earth','EFL',2025,'FusionGasFuel',1.0,NULL); +INSERT INTO "efficiency" VALUES('A','FusionGasFuel','heater',2025,'RH',0.9,NULL); +INSERT INTO "efficiency" VALUES('A-B','FusionGasFuel','FGF_pipe',2025,'FusionGasFuel',0.95,NULL); +INSERT INTO "efficiency" VALUES('B','FusionGasFuel','heater',2025,'RH',0.9,NULL); +INSERT INTO "efficiency" VALUES('B','GeoHyd','GeoHeater',2025,'RH',9.80000000000000093e-01,NULL); +INSERT INTO "efficiency" VALUES('B','earth','GeoThermal',2025,'GeoHyd',1.0,NULL); +INSERT INTO "efficiency" VALUES('B-A','FusionGasFuel','FGF_pipe',2025,'FusionGasFuel',0.95,NULL); +INSERT INTO "efficiency" VALUES('A','GeoHyd','GeoHeater',2025,'RH',0.9,NULL); +INSERT INTO "efficiency" VALUES('A','earth','GeoThermal',2025,'GeoHyd',1.0,NULL); CREATE TABLE efficiency_variable ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -384,8 +318,8 @@ CREATE TABLE emission_activity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO emission_activity VALUES('A','co2','HYD','EH',2025,'ELC',0.02000000000000000041,NULL,NULL); -INSERT INTO emission_activity VALUES('A','FusionGas','HYD','EF',2025,'ELC',-0.2000000000000000111,NULL,'needs to be negative as a driver of linked tech...don''t ask'); +INSERT INTO "emission_activity" VALUES('A','co2','HYD','EH',2025,'ELC',0.02,NULL,NULL); +INSERT INTO "emission_activity" VALUES('A','FusionGas','HYD','EF',2025,'ELC',-0.2,NULL,'needs to be negative as a driver of linked tech...don''t ask'); CREATE TABLE emission_embodied ( region TEXT, @@ -398,7 +332,7 @@ CREATE TABLE emission_embodied value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) ); CREATE TABLE emission_end_of_life ( @@ -412,7 +346,21 @@ CREATE TABLE emission_end_of_life value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE end_of_life_output +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); CREATE TABLE existing_capacity ( @@ -426,16 +374,8 @@ CREATE TABLE existing_capacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO existing_capacity VALUES('A','EH',2020,200.0,'things',NULL); -CREATE TABLE TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -INSERT INTO TechGroup VALUES('RPS_common',''); -INSERT INTO TechGroup VALUES('A_tech_grp_1','converted from old db'); -CREATE TABLE loan_lifetime_process +INSERT INTO "existing_capacity" VALUES('A','EH',2020,200.0,'things',NULL); +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -446,176 +386,210 @@ CREATE TABLE loan_lifetime_process notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO loan_lifetime_process VALUES('A','EF',2025,57,NULL); -INSERT INTO loan_lifetime_process VALUES('A','EFL',2025,68,NULL); -INSERT INTO loan_lifetime_process VALUES('A','bulbs',2025,10,NULL); -INSERT INTO loan_lifetime_process VALUES('A','EH',2025,10,NULL); -INSERT INTO loan_lifetime_process VALUES('A','well',2025,10,NULL); -INSERT INTO loan_lifetime_process VALUES('A','heater',2025,10,NULL); -INSERT INTO loan_lifetime_process VALUES('A','GeoHeater',2025,10,NULL); -INSERT INTO loan_lifetime_process VALUES('A','GeoThermal',2025,10,NULL); -INSERT INTO loan_lifetime_process VALUES('B','EF',2025,10,NULL); -INSERT INTO loan_lifetime_process VALUES('B','bulbs',2025,10,NULL); -INSERT INTO loan_lifetime_process VALUES('B','EH',2025,10,NULL); -INSERT INTO loan_lifetime_process VALUES('B','batt',2025,10,NULL); -INSERT INTO loan_lifetime_process VALUES('B','well',2025,10,NULL); -INSERT INTO loan_lifetime_process VALUES('B','heater',2025,10,NULL); -INSERT INTO loan_lifetime_process VALUES('B','GeoHeater',2025,10,NULL); -INSERT INTO loan_lifetime_process VALUES('B','GeoThermal',2025,10,NULL); -INSERT INTO loan_lifetime_process VALUES('A-B','FGF_pipe',2025,10,NULL); -INSERT INTO loan_lifetime_process VALUES('B-A','FGF_pipe',2025,10,NULL); -CREATE TABLE loan_rate +INSERT INTO "lifetime_process" VALUES('B','EF',2025,200.0,NULL); +CREATE TABLE lifetime_survival_curve ( - region TEXT, - tech TEXT + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL REFERENCES technology (tech), - vintage INTEGER + vintage INTEGER NOT NULL REFERENCES time_period (period), - rate REAL, + fraction REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE lifetime_process +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), lifetime REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, tech) ); -INSERT INTO lifetime_process VALUES('B','EF',2025,200.0,NULL); -CREATE TABLE lifetime_tech +INSERT INTO "lifetime_tech" VALUES('A','EH',60.0,''); +INSERT INTO "lifetime_tech" VALUES('B','bulbs',100.0,'super LED!'); +CREATE TABLE limit_activity ( - region TEXT, - tech TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +INSERT INTO "limit_activity" VALUES('A',2025,'EF','ge',0.001,'PJ/CY','goofy units'); +INSERT INTO "limit_activity" VALUES('B',2025,'EH','le',10000.0,'stuff',NULL); +INSERT INTO "limit_activity" VALUES('A',2025,'EF','le',10000.0,'stuff',NULL); +INSERT INTO "limit_activity" VALUES('A',2025,'A_tech_grp_1','ge',0.05,'',NULL); +INSERT INTO "limit_activity" VALUES('A',2025,'A_tech_grp_1','le',10000.0,'',NULL); +CREATE TABLE limit_activity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_annual_capacity_factor +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator), + CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO lifetime_tech VALUES('A','EH',60.0,''); -INSERT INTO lifetime_tech VALUES('B','bulbs',100.0,'super LED!'); -CREATE TABLE Operator +CREATE TABLE limit_capacity ( - operator TEXT PRIMARY KEY, - notes TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO Operator VALUES('e','equal to'); -INSERT INTO Operator VALUES('le','less than or equal to'); -INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE limit_growth_capacity +INSERT INTO "limit_capacity" VALUES('A',2025,'EH','ge',0.1,'',''); +INSERT INTO "limit_capacity" VALUES('B',2025,'batt','ge',0.1,'',''); +INSERT INTO "limit_capacity" VALUES('A',2025,'EH','le',20000.0,'',''); +INSERT INTO "limit_capacity" VALUES('B',2025,'EH','le',20000.0,'',''); +INSERT INTO "limit_capacity" VALUES('A',2025,'A_tech_grp_1','ge',0.2,'',NULL); +INSERT INTO "limit_capacity" VALUES('A',2025,'A_tech_grp_1','le',6000.0,'',NULL); +CREATE TABLE limit_capacity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_capacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity +CREATE TABLE limit_emission +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +INSERT INTO "limit_emission" VALUES('A',2025,'co2','le',10000.0,'gulps',NULL); +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitStorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -CREATE TABLE limit_activity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, + REFERENCES operator (operator), + new_cap REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO limit_activity VALUES('A',2025,'EF','ge',0.00100000000000000002,'PJ/CY','goofy units'); -INSERT INTO limit_activity VALUES('B',2025,'EH','le',10000.0,'stuff',NULL); -INSERT INTO limit_activity VALUES('A',2025,'EF','le',10000.0,'stuff',NULL); -INSERT INTO limit_activity VALUES('A',2025,'A_tech_grp_1','ge',0.05000000000000000277,'',NULL); -INSERT INTO limit_activity VALUES('A',2025,'A_tech_grp_1','le',10000.0,'',NULL); -CREATE TABLE limit_activity_share +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -623,114 +597,59 @@ CREATE TABLE limit_activity_share sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), share REAL, notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity +INSERT INTO "limit_new_capacity_share" VALUES('A',2025,'RPS_common','A_tech_grp_1','ge',0.0,''); +INSERT INTO "limit_new_capacity_share" VALUES('global',2025,'RPS_common','A_tech_grp_1','le',1.0,''); +CREATE TABLE limit_resource ( region TEXT, - period INTEGER - REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, + REFERENCES operator (operator), + cum_act REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) + PRIMARY KEY (region, tech_or_group, operator) ); -INSERT INTO limit_capacity VALUES('A',2025,'EH','ge',0.1000000000000000055,'',''); -INSERT INTO limit_capacity VALUES('B',2025,'batt','ge',0.1000000000000000055,'',''); -INSERT INTO limit_capacity VALUES('A',2025,'EH','le',20000.0,'',''); -INSERT INTO limit_capacity VALUES('B',2025,'EH','le',20000.0,'',''); -INSERT INTO limit_capacity VALUES('A',2025,'A_tech_grp_1','ge',0.2000000000000000111,'',NULL); -INSERT INTO limit_capacity VALUES('A',2025,'A_tech_grp_1','le',6000.0,'',NULL); -CREATE TABLE limit_capacity_share +INSERT INTO "limit_resource" VALUES('B','EF','le',9000.0,'clumps',NULL); +CREATE TABLE limit_seasonal_capacity_factor ( - region TEXT, - period INTEGER + region TEXT + REFERENCES region (region), + period INTEGER REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, + season TEXT + REFERENCES season_label (season), + tech TEXT + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE limit_new_capacity +CREATE TABLE limit_storage_level_fraction ( - region TEXT, - period INTEGER + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), - tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -INSERT INTO limit_new_capacity_share VALUES('A',2025,'RPS_common','A_tech_grp_1','ge',0.0,''); -INSERT INTO limit_new_capacity_share VALUES('global',2025,'RPS_common','A_tech_grp_1','le',1.0,''); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -INSERT INTO limit_resource VALUES('B','EF','le',9000.0,'clumps',NULL); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) + REFERENCES operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); CREATE TABLE limit_tech_input_split ( @@ -742,12 +661,12 @@ CREATE TABLE limit_tech_input_split tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -INSERT INTO limit_tech_input_split VALUES('A',2025,'HYD','EH','ge',0.949999999999999956,'95% HYD reqt. (other not specified...)'); +INSERT INTO "limit_tech_input_split" VALUES('A',2025,'HYD','EH','ge',0.95,'95% HYD reqt. (other not specified...)'); CREATE TABLE limit_tech_input_split_annual ( region TEXT, @@ -758,7 +677,7 @@ CREATE TABLE limit_tech_input_split_annual tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -773,12 +692,12 @@ CREATE TABLE limit_tech_output_split output_comm TEXT REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -INSERT INTO limit_tech_output_split VALUES('B',2025,'EH','ELC','ge',0.949999999999999956,'95% ELC output (there are not others, this is a min)'); +INSERT INTO "limit_tech_output_split" VALUES('B',2025,'EH','ELC','ge',0.95,'95% ELC output (there are not others, this is a min)'); CREATE TABLE limit_tech_output_split_annual ( region TEXT, @@ -789,27 +708,12 @@ CREATE TABLE limit_tech_output_split_annual output_comm TEXT REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -INSERT INTO limit_emission VALUES('A',2025,'co2','le',10000.0,'gulps',NULL); -CREATE TABLE LinkedTech +CREATE TABLE linked_tech ( primary_region TEXT, primary_tech TEXT @@ -821,7 +725,122 @@ CREATE TABLE LinkedTech notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); -INSERT INTO LinkedTech VALUES('A','EF','FusionGas','EFL',NULL); +INSERT INTO "linked_tech" VALUES('A','EF','FusionGas','EFL',NULL); +CREATE TABLE loan_lifetime_process +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +INSERT INTO "loan_lifetime_process" VALUES('A','EF',2025,57.0,NULL); +INSERT INTO "loan_lifetime_process" VALUES('A','EFL',2025,68.0,NULL); +INSERT INTO "loan_lifetime_process" VALUES('A','bulbs',2025,10.0,NULL); +INSERT INTO "loan_lifetime_process" VALUES('A','EH',2025,10.0,NULL); +INSERT INTO "loan_lifetime_process" VALUES('A','well',2025,10.0,NULL); +INSERT INTO "loan_lifetime_process" VALUES('A','heater',2025,10.0,NULL); +INSERT INTO "loan_lifetime_process" VALUES('A','GeoHeater',2025,10.0,NULL); +INSERT INTO "loan_lifetime_process" VALUES('A','GeoThermal',2025,10.0,NULL); +INSERT INTO "loan_lifetime_process" VALUES('B','EF',2025,10.0,NULL); +INSERT INTO "loan_lifetime_process" VALUES('B','bulbs',2025,10.0,NULL); +INSERT INTO "loan_lifetime_process" VALUES('B','EH',2025,10.0,NULL); +INSERT INTO "loan_lifetime_process" VALUES('B','batt',2025,10.0,NULL); +INSERT INTO "loan_lifetime_process" VALUES('B','well',2025,10.0,NULL); +INSERT INTO "loan_lifetime_process" VALUES('B','heater',2025,10.0,NULL); +INSERT INTO "loan_lifetime_process" VALUES('B','GeoHeater',2025,10.0,NULL); +INSERT INTO "loan_lifetime_process" VALUES('B','GeoThermal',2025,10.0,NULL); +INSERT INTO "loan_lifetime_process" VALUES('A-B','FGF_pipe',2025,10.0,NULL); +INSERT INTO "loan_lifetime_process" VALUES('B-A','FGF_pipe',2025,10.0,NULL); +CREATE TABLE loan_rate +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE metadata +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); +INSERT INTO "metadata" VALUES('DB_MINOR',0,''); +CREATE TABLE metadata_real +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +INSERT INTO "metadata_real" VALUES('global_discount_rate',4.2000000000000004e-01,''); +CREATE TABLE myopic_efficiency +( + base_year integer, + region text, + input_comm text, + tech text, + vintage integer, + output_comm text, + efficiency real, + lifetime integer, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (region, input_comm, tech, vintage, output_comm) +); +CREATE TABLE operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "operator" VALUES('e','equal to'); +INSERT INTO "operator" VALUES('le','less than or equal to'); +INSERT INTO "operator" VALUES('ge','greater than or equal to'); +CREATE TABLE output_built_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE output_cost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) +); CREATE TABLE output_curtailment ( scenario TEXT, @@ -832,7 +851,7 @@ CREATE TABLE output_curtailment season TEXT REFERENCES time_period (period), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -844,62 +863,42 @@ CREATE TABLE output_curtailment curtailment REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputNetCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_built_capacity +CREATE TABLE output_dual_variable ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE output_emission ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), - tech TEXT + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT REFERENCES technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE OutputFlowIn +CREATE TABLE output_flow_in ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -911,18 +910,18 @@ CREATE TABLE OutputFlowIn flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputFlowOut +CREATE TABLE output_flow_out ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -934,18 +933,70 @@ CREATE TABLE OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); +CREATE TABLE output_flow_out_summary +( + scenario TEXT NOT NULL, + region TEXT NOT NULL, + sector TEXT, + period INTEGER, + input_comm TEXT NOT NULL, + tech TEXT NOT NULL, + vintage INTEGER, + output_comm TEXT NOT NULL, + flow REAL NOT NULL, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_net_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_objective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE output_retired_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), vintage INTEGER @@ -961,7 +1012,7 @@ CREATE TABLE planning_reserve_margin margin REAL, notes TEXT ); -INSERT INTO planning_reserve_margin VALUES('A',0.05000000000000000277,NULL); +INSERT INTO "planning_reserve_margin" VALUES('A',0.05,NULL); CREATE TABLE ramp_down_hourly ( region TEXT, @@ -971,8 +1022,8 @@ CREATE TABLE ramp_down_hourly notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO ramp_down_hourly VALUES('A','EH',0.05000000000000000277,NULL); -INSERT INTO ramp_down_hourly VALUES('B','EH',0.05000000000000000277,NULL); +INSERT INTO "ramp_down_hourly" VALUES('A','EH',0.05,NULL); +INSERT INTO "ramp_down_hourly" VALUES('B','EH',0.05,NULL); CREATE TABLE ramp_up_hourly ( region TEXT, @@ -982,23 +1033,23 @@ CREATE TABLE ramp_up_hourly notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO ramp_up_hourly VALUES('B','EH',0.05000000000000000277,NULL); -INSERT INTO ramp_up_hourly VALUES('A','EH',0.05000000000000000277,NULL); +INSERT INTO "ramp_up_hourly" VALUES('B','EH',0.05,NULL); +INSERT INTO "ramp_up_hourly" VALUES('A','EH',0.05,NULL); CREATE TABLE region ( region TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO region VALUES('A','main region'); -INSERT INTO region VALUES('B','just a 2nd region'); +INSERT INTO "region" VALUES('A','main region'); +INSERT INTO "region" VALUES('B','just a 2nd region'); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tech TEXT REFERENCES technology (tech), vintage INTEGER, @@ -1007,23 +1058,36 @@ CREATE TABLE reserve_capacity_derate PRIMARY KEY (region, period, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE TimeSegmentFraction +CREATE TABLE rps_requirement ( - period INTEGER + region TEXT NOT NULL + REFERENCES region (region), + period INTEGER NOT NULL REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) + tech_group TEXT NOT NULL + REFERENCES tech_group (group_name), + requirement REAL NOT NULL, + notes TEXT +); +INSERT INTO "rps_requirement" VALUES('B',2025,'RPS_common',0.3,NULL); +CREATE TABLE season_label +( + season TEXT PRIMARY KEY, + notes TEXT ); -INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d1',0.25,NULL); -INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d2',0.25,NULL); -INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d1',0.25,NULL); -INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d2',0.25,NULL); +INSERT INTO "season_label" VALUES('s1',NULL); +INSERT INTO "season_label" VALUES('s2',NULL); +CREATE TABLE sector_label +( + sector TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "sector_label" VALUES('supply',NULL); +INSERT INTO "sector_label" VALUES('electric',NULL); +INSERT INTO "sector_label" VALUES('transport',NULL); +INSERT INTO "sector_label" VALUES('commercial',NULL); +INSERT INTO "sector_label" VALUES('residential',NULL); +INSERT INTO "sector_label" VALUES('industrial',NULL); CREATE TABLE storage_duration ( region TEXT, @@ -1032,166 +1096,150 @@ CREATE TABLE storage_duration notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO storage_duration VALUES('B','batt',15.0,NULL); -CREATE TABLE lifetime_survival_curve +INSERT INTO "storage_duration" VALUES('B','batt',15.0,NULL); +CREATE TABLE tech_group ( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL + group_name TEXT + PRIMARY KEY, + notes TEXT +); +INSERT INTO "tech_group" VALUES('RPS_common',''); +INSERT INTO "tech_group" VALUES('A_tech_grp_1','converted from old db'); +CREATE TABLE tech_group_member +( + group_name TEXT + REFERENCES tech_group (group_name), + tech TEXT REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) + PRIMARY KEY (group_name, tech) ); -CREATE TABLE technologyType +INSERT INTO "tech_group_member" VALUES('RPS_common','EF'); +INSERT INTO "tech_group_member" VALUES('A_tech_grp_1','EH'); +INSERT INTO "tech_group_member" VALUES('A_tech_grp_1','EF'); +CREATE TABLE technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES technology_type (label) +); +INSERT INTO "technology" VALUES('well','p','supply','water','',0,0,0,0,0,0,0,0,'plain old water'); +INSERT INTO "technology" VALUES('bulbs','p','residential','electric','',0,0,0,0,0,0,0,0,'residential lighting'); +INSERT INTO "technology" VALUES('EH','pb','electric','hydro','',0,0,0,1,1,0,0,0,'hydro power electric plant'); +INSERT INTO "technology" VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0,0,'big battery'); +INSERT INTO "technology" VALUES('EF','p','electric','electric','',0,0,1,0,0,0,0,0,'fusion plant'); +INSERT INTO "technology" VALUES('EFL','p','electric','electric','',0,0,0,0,0,1,0,0,'linked (to Fusion) producer'); +INSERT INTO "technology" VALUES('heater','p','residential','electric','',0,0,0,0,0,0,0,0,'heater'); +INSERT INTO "technology" VALUES('FGF_pipe','p','transport',NULL,'',0,0,0,0,0,0,1,0,'transportation line A->B'); +INSERT INTO "technology" VALUES('GeoThermal','p','residential','hydro','',0,1,0,0,0,0,0,0,'geothermal hot water source'); +INSERT INTO "technology" VALUES('GeoHeater','p','residential','hydro','',0,0,0,0,0,0,0,0,'geothermal heater from geo hyd'); +CREATE TABLE technology_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO technologyType VALUES('p','production technology'); -INSERT INTO technologyType VALUES('pb','baseload production technology'); -INSERT INTO technologyType VALUES('ps','storage production technology'); -CREATE TABLE TimeOfDay +INSERT INTO "technology_type" VALUES('p','production technology'); +INSERT INTO "technology_type" VALUES('pb','baseload production technology'); +INSERT INTO "technology_type" VALUES('ps','storage production technology'); +CREATE TABLE time_of_day ( sequence INTEGER UNIQUE, tod TEXT PRIMARY KEY ); -INSERT INTO TimeOfDay VALUES(1,'d1'); -INSERT INTO TimeOfDay VALUES(2,'d2'); +INSERT INTO "time_of_day" VALUES(1,'d1'); +INSERT INTO "time_of_day" VALUES(2,'d2'); CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES time_periodType (label) + REFERENCES time_period_type (label) +); +INSERT INTO "time_period" VALUES(1,2020,'e'); +INSERT INTO "time_period" VALUES(2,2025,'f'); +INSERT INTO "time_period" VALUES(3,2030,'f'); +CREATE TABLE time_period_type +( + label TEXT + PRIMARY KEY, + description TEXT ); -INSERT INTO time_period VALUES(1,2020,'e'); -INSERT INTO time_period VALUES(2,2025,'f'); -INSERT INTO time_period VALUES(3,2030,'f'); -CREATE TABLE TimeSeason +INSERT INTO "time_period_type" VALUES('e','existing vintages'); +INSERT INTO "time_period_type" VALUES('f','future'); +CREATE TABLE time_season +( + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + season TEXT REFERENCES season_label(season), + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +INSERT INTO "time_season" VALUES(2025,1,'s1',NULL); +INSERT INTO "time_season" VALUES(2025,2,'s2',NULL); +CREATE TABLE time_season_all ( period INTEGER REFERENCES time_period (period), sequence INTEGER, season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); -INSERT INTO TimeSeason VALUES(2025,1,'s1',NULL); -INSERT INTO TimeSeason VALUES(2025,2,'s2',NULL); CREATE TABLE time_season_sequential ( - period INTEGER - REFERENCES time_period (period), + period INTEGER REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES SeasonLabel (season), + season TEXT REFERENCES season_label(season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE time_periodType +CREATE TABLE time_season_to_sequential ( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO time_periodType VALUES('e','existing vintages'); -INSERT INTO time_periodType VALUES('f','future'); -CREATE TABLE OutputEmission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER + period INTEGER REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) + sequence INTEGER, + seas_seq TEXT, + season TEXT + REFERENCES season_label (season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) ); -CREATE TABLE RPSRequirement +CREATE TABLE time_segment_fraction ( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL + period INTEGER REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES TechGroup (group_name), - requirement REAL NOT NULL, - notes TEXT -); -INSERT INTO RPSRequirement VALUES('B',2025,'RPS_common',0.2999999999999999889,NULL); -CREATE TABLE TechGroupMember -( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -INSERT INTO TechGroupMember VALUES('RPS_common','EF'); -INSERT INTO TechGroupMember VALUES('A_tech_grp_1','EH'); -INSERT INTO TechGroupMember VALUES('A_tech_grp_1','EF'); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technologyType (label) -); -INSERT INTO technology VALUES('well','p','supply','water','',0,0,0,0,0,0,0,0,'plain old water'); -INSERT INTO technology VALUES('bulbs','p','residential','electric','',0,0,0,0,0,0,0,0,'residential lighting'); -INSERT INTO technology VALUES('EH','pb','electric','hydro','',0,0,0,1,1,0,0,0,'hydro power electric plant'); -INSERT INTO technology VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0,0,'big battery'); -INSERT INTO technology VALUES('EF','p','electric','electric','',0,0,1,0,0,0,0,0,'fusion plant'); -INSERT INTO technology VALUES('EFL','p','electric','electric','',0,0,0,0,0,1,0,0,'linked (to Fusion) producer'); -INSERT INTO technology VALUES('heater','p','residential','electric','',0,0,0,0,0,0,0,0,'heater'); -INSERT INTO technology VALUES('FGF_pipe','p','transport',NULL,'',0,0,0,0,0,0,1,0,'transportation line A->B'); -INSERT INTO technology VALUES('GeoThermal','p','residential','hydro','',0,1,0,0,0,0,0,0,'geothermal hot water source'); -INSERT INTO technology VALUES('GeoHeater','p','residential','hydro','',0,0,0,0,0,0,0,0,'geothermal heater from geo hyd'); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + segment_fraction REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) ); +INSERT INTO "time_segment_fraction" VALUES(2025,'s2','d1',0.25,NULL); +INSERT INTO "time_segment_fraction" VALUES(2025,'s2','d2',0.25,NULL); +INSERT INTO "time_segment_fraction" VALUES(2025,'s1','d1',0.25,NULL); +INSERT INTO "time_segment_fraction" VALUES(2025,'s1','d2',0.25,NULL); +CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index 1909152d1..35ed2fcee 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -1,65 +1,4 @@ -PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO metadata VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO metadata VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO metadata VALUES('days_per_period',365,'count of days in each period'); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO metadata_real VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO metadata_real VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE SeasonLabel -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SeasonLabel VALUES('charge','non-sequential season - charging day'); -INSERT INTO SeasonLabel VALUES('discharge','non-sequential season - discharging day'); -INSERT INTO SeasonLabel VALUES('summer','sequential season - summer day'); -INSERT INTO SeasonLabel VALUES('sept_w1','sequential season - day in first week of September'); -INSERT INTO SeasonLabel VALUES('sept_w2','sequential season - day in second week of September'); -INSERT INTO SeasonLabel VALUES('sept_w3','sequential season - day in third week of September'); -INSERT INTO SeasonLabel VALUES('sept_w4','sequential season - day in fourth week of September'); -INSERT INTO SeasonLabel VALUES('sept_29th','sequential season - 29th of September'); -INSERT INTO SeasonLabel VALUES('sept_30th','sequential season - 30th of September'); -INSERT INTO SeasonLabel VALUES('winter','sequential season - winter day'); -INSERT INTO SeasonLabel VALUES('apr_w1','sequential season - day in first week of September'); -INSERT INTO SeasonLabel VALUES('apr_w2','sequential season - day in second week of September'); -INSERT INTO SeasonLabel VALUES('apr_w3','sequential season - day in third week of September'); -INSERT INTO SeasonLabel VALUES('apr_w4','sequential season - day in fourth week of September'); -INSERT INTO SeasonLabel VALUES('apr_29th','sequential season - 29th of April'); -INSERT INTO SeasonLabel VALUES('apr_30th','sequential season - 30th of April'); -CREATE TABLE SectorLabel -( - sector TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SectorLabel VALUES('electricity',NULL); CREATE TABLE capacity_credit ( region TEXT, @@ -79,9 +18,9 @@ CREATE TABLE capacity_factor_process period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), vintage INTEGER, @@ -96,9 +35,9 @@ CREATE TABLE capacity_factor_tech period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), factor REAL, @@ -106,15 +45,15 @@ CREATE TABLE capacity_factor_tech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO capacity_factor_tech VALUES('region',2000,'charge','a','generator',1.0,NULL); -INSERT INTO capacity_factor_tech VALUES('region',2000,'charge','b','generator',1.0,NULL); -INSERT INTO capacity_factor_tech VALUES('region',2000,'charge','c','generator',0.2,NULL); -INSERT INTO capacity_factor_tech VALUES('region',2000,'charge','d','generator',0.2,NULL); -INSERT INTO capacity_factor_tech VALUES('region',2000,'discharge','a','generator',0.1,NULL); -INSERT INTO capacity_factor_tech VALUES('region',2000,'discharge','b','generator',0.1,NULL); -INSERT INTO capacity_factor_tech VALUES('region',2000,'discharge','c','generator',0.01,NULL); -INSERT INTO capacity_factor_tech VALUES('region',2000,'discharge','d','generator',0.01,NULL); -CREATE TABLE CapacityToActivity +INSERT INTO "capacity_factor_tech" VALUES('region',2000,'charge','a','generator',1.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('region',2000,'charge','b','generator',1.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('region',2000,'charge','c','generator',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('region',2000,'charge','d','generator',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('region',2000,'discharge','a','generator',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('region',2000,'discharge','b','generator',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('region',2000,'discharge','c','generator',0.01,NULL); +INSERT INTO "capacity_factor_tech" VALUES('region',2000,'discharge','d','generator',0.01,NULL); +CREATE TABLE capacity_to_activity ( region TEXT, tech TEXT @@ -123,35 +62,35 @@ CREATE TABLE CapacityToActivity notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO CapacityToActivity VALUES('region','generator',8760.0,'MWh/MWy'); -INSERT INTO CapacityToActivity VALUES('region','dly_stor',8760.0,'MWh/MWy'); -INSERT INTO CapacityToActivity VALUES('region','seas_stor',8760.0,'MWh/MWy'); -INSERT INTO CapacityToActivity VALUES('region','demand',8760.0,'MWh/MWy'); +INSERT INTO "capacity_to_activity" VALUES('region','generator',8760.0,'MWh/MWy'); +INSERT INTO "capacity_to_activity" VALUES('region','dly_stor',8760.0,'MWh/MWy'); +INSERT INTO "capacity_to_activity" VALUES('region','seas_stor',8760.0,'MWh/MWy'); +INSERT INTO "capacity_to_activity" VALUES('region','demand',8760.0,'MWh/MWy'); CREATE TABLE commodity ( name TEXT PRIMARY KEY, flag TEXT - REFERENCES commodityType (label), + REFERENCES commodity_type (label), description TEXT ); -INSERT INTO commodity VALUES('ethos','s',NULL); -INSERT INTO commodity VALUES('electricity','p',NULL); -INSERT INTO commodity VALUES('demand','d',NULL); -CREATE TABLE commodityType +INSERT INTO "commodity" VALUES('ethos','s',NULL); +INSERT INTO "commodity" VALUES('electricity','p',NULL); +INSERT INTO "commodity" VALUES('demand','d',NULL); +CREATE TABLE commodity_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO commodityType VALUES('p','physical commodity'); -INSERT INTO commodityType VALUES('a','annual commodity'); -INSERT INTO commodityType VALUES('e','emissions commodity'); -INSERT INTO commodityType VALUES('d','demand commodity'); -INSERT INTO commodityType VALUES('s','source commodity'); -INSERT INTO commodityType VALUES('w','waste commodity'); -INSERT INTO commodityType VALUES('wa','waste annual commodity'); -INSERT INTO commodityType VALUES('wp','waste physical commodity'); +INSERT INTO "commodity_type" VALUES('p','physical commodity'); +INSERT INTO "commodity_type" VALUES('a','annual commodity'); +INSERT INTO "commodity_type" VALUES('e','emissions commodity'); +INSERT INTO "commodity_type" VALUES('d','demand commodity'); +INSERT INTO "commodity_type" VALUES('s','source commodity'); +INSERT INTO "commodity_type" VALUES('w','waste commodity'); +INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); +INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); CREATE TABLE construction_input ( region TEXT, @@ -204,10 +143,10 @@ CREATE TABLE cost_invest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO cost_invest VALUES('region','generator',2000,1000.0,'',NULL); -INSERT INTO cost_invest VALUES('region','dly_stor',2000,1.0,'',NULL); -INSERT INTO cost_invest VALUES('region','seas_stor',2000,100.0,'',NULL); -INSERT INTO cost_invest VALUES('region','demand',2000,1.0,'',NULL); +INSERT INTO "cost_invest" VALUES('region','generator',2000,1000.0,'',NULL); +INSERT INTO "cost_invest" VALUES('region','dly_stor',2000,1.0,'',NULL); +INSERT INTO "cost_invest" VALUES('region','seas_stor',2000,100.0,'',NULL); +INSERT INTO "cost_invest" VALUES('region','demand',2000,1.0,'',NULL); CREATE TABLE cost_variable ( region TEXT NOT NULL, @@ -222,8 +161,8 @@ CREATE TABLE cost_variable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_variable VALUES('region',2000,'generator',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2000,'demand',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2000,'generator',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2000,'demand',2000,1.0,NULL,NULL); CREATE TABLE demand ( region TEXT, @@ -236,16 +175,16 @@ CREATE TABLE demand notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO demand VALUES('region',2000,'demand',8760.0,'MWh',NULL); +INSERT INTO "demand" VALUES('region',2000,'demand',8760.0,'MWh',NULL); CREATE TABLE demand_specific_distribution ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), demand_name TEXT REFERENCES commodity (name), dsd REAL, @@ -253,28 +192,14 @@ CREATE TABLE demand_specific_distribution PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO demand_specific_distribution VALUES('region',2000,'charge','a','demand',0.0,NULL); -INSERT INTO demand_specific_distribution VALUES('region',2000,'charge','b','demand',0.05,NULL); -INSERT INTO demand_specific_distribution VALUES('region',2000,'charge','c','demand',0.05,NULL); -INSERT INTO demand_specific_distribution VALUES('region',2000,'charge','d','demand',0.1,NULL); -INSERT INTO demand_specific_distribution VALUES('region',2000,'discharge','a','demand',0.0,NULL); -INSERT INTO demand_specific_distribution VALUES('region',2000,'discharge','b','demand',0.2,NULL); -INSERT INTO demand_specific_distribution VALUES('region',2000,'discharge','c','demand',0.2,NULL); -INSERT INTO demand_specific_distribution VALUES('region',2000,'discharge','d','demand',0.4,NULL); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); +INSERT INTO "demand_specific_distribution" VALUES('region',2000,'charge','a','demand',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('region',2000,'charge','b','demand',0.05,NULL); +INSERT INTO "demand_specific_distribution" VALUES('region',2000,'charge','c','demand',0.05,NULL); +INSERT INTO "demand_specific_distribution" VALUES('region',2000,'charge','d','demand',0.1,NULL); +INSERT INTO "demand_specific_distribution" VALUES('region',2000,'discharge','a','demand',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('region',2000,'discharge','b','demand',0.2,NULL); +INSERT INTO "demand_specific_distribution" VALUES('region',2000,'discharge','c','demand',0.2,NULL); +INSERT INTO "demand_specific_distribution" VALUES('region',2000,'discharge','d','demand',0.4,NULL); CREATE TABLE efficiency ( region TEXT, @@ -291,19 +216,19 @@ CREATE TABLE efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO efficiency VALUES('region','ethos','generator',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('region','electricity','dly_stor',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('region','electricity','seas_stor',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('region','electricity','demand',2000,'demand',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','ethos','generator',2000,'electricity',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','electricity','dly_stor',2000,'electricity',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','electricity','seas_stor',2000,'electricity',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','electricity','demand',2000,'demand',1.0,NULL); CREATE TABLE efficiency_variable ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -347,7 +272,7 @@ CREATE TABLE emission_embodied value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) ); CREATE TABLE emission_end_of_life ( @@ -361,7 +286,21 @@ CREATE TABLE emission_end_of_life value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE end_of_life_output +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); CREATE TABLE existing_capacity ( @@ -375,167 +314,206 @@ CREATE TABLE existing_capacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE Loanlifetime_tech +CREATE TABLE lifetime_process ( region TEXT, tech TEXT REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), lifetime REAL, notes TEXT, - PRIMARY KEY (region, tech) + PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE loan_rate +CREATE TABLE lifetime_survival_curve ( - region TEXT, - tech TEXT + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL REFERENCES technology (tech), - vintage INTEGER + vintage INTEGER NOT NULL REFERENCES time_period (period), - rate REAL, + fraction REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE lifetime_process +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), lifetime REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, tech) ); -CREATE TABLE lifetime_tech +CREATE TABLE limit_activity ( - region TEXT, - tech TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE limit_activity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_annual_capacity_factor +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator), + CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE Operator +CREATE TABLE limit_capacity ( - operator TEXT PRIMARY KEY, - notes TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO Operator VALUES('e','equal to'); -INSERT INTO Operator VALUES('le','less than or equal to'); -INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE limit_growth_capacity +CREATE TABLE limit_capacity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_capacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity +CREATE TABLE limit_emission +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitStorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -INSERT INTO LimitStorageLevelFraction VALUES('region', 2000, 'winter', 'b', 'seas_stor', 2000, 'e', 0.5, NULL); -INSERT INTO LimitStorageLevelFraction VALUES('region', 2000, 'charge', 'b', 'dly_stor', 2000, 'e', 0.5, NULL); -CREATE TABLE limit_activity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, + REFERENCES operator (operator), + new_cap REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE limit_activity_share +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -543,106 +521,59 @@ CREATE TABLE limit_activity_share sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), share REAL, notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity +CREATE TABLE limit_resource ( region TEXT, - period INTEGER - REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, + REFERENCES operator (operator), + cum_act REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) + PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_capacity_share +CREATE TABLE limit_seasonal_capacity_factor ( - region TEXT, - period INTEGER + region TEXT + REFERENCES region (region), + period INTEGER REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, + season TEXT + REFERENCES season_label (season), + tech TEXT + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE limit_new_capacity +CREATE TABLE limit_storage_level_fraction ( - region TEXT, - period INTEGER + region TEXT, + period INTEGER REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tech TEXT + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) + REFERENCES operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); +INSERT INTO "limit_storage_level_fraction" VALUES('region',2000,'winter','b','seas_stor',2000,'e',0.5,NULL); +INSERT INTO "limit_storage_level_fraction" VALUES('region',2000,'charge','b','dly_stor',2000,'e',0.5,NULL); CREATE TABLE limit_tech_input_split ( region TEXT, @@ -653,7 +584,7 @@ CREATE TABLE limit_tech_input_split tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -668,7 +599,7 @@ CREATE TABLE limit_tech_input_split_annual tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -683,7 +614,7 @@ CREATE TABLE limit_tech_output_split output_comm TEXT REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) @@ -698,26 +629,12 @@ CREATE TABLE limit_tech_output_split_annual output_comm TEXT REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE LinkedTech +CREATE TABLE linked_tech ( primary_region TEXT, primary_tech TEXT @@ -729,6 +646,103 @@ CREATE TABLE LinkedTech notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); +CREATE TABLE loan_lifetime_process +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE loan_rate +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE metadata +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); +INSERT INTO "metadata" VALUES('DB_MINOR',0,''); +CREATE TABLE metadata_real +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +CREATE TABLE myopic_efficiency +( + base_year integer, + region text, + input_comm text, + tech text, + vintage integer, + output_comm text, + efficiency real, + lifetime integer, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (region, input_comm, tech, vintage, output_comm) +); +CREATE TABLE operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "operator" VALUES('e','equal to'); +INSERT INTO "operator" VALUES('le','less than or equal to'); +INSERT INTO "operator" VALUES('ge','greater than or equal to'); +CREATE TABLE output_built_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE output_cost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) +); CREATE TABLE output_curtailment ( scenario TEXT, @@ -739,7 +753,7 @@ CREATE TABLE output_curtailment season TEXT REFERENCES time_period (period), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -751,62 +765,42 @@ CREATE TABLE output_curtailment curtailment REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputNetCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_built_capacity +CREATE TABLE output_dual_variable ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE output_emission ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), - tech TEXT + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT REFERENCES technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE OutputFlowIn +CREATE TABLE output_flow_in ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -818,18 +812,18 @@ CREATE TABLE OutputFlowIn flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputFlowOut +CREATE TABLE output_flow_out ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -841,18 +835,70 @@ CREATE TABLE OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); +CREATE TABLE output_flow_out_summary +( + scenario TEXT NOT NULL, + region TEXT NOT NULL, + sector TEXT, + period INTEGER, + input_comm TEXT NOT NULL, + tech TEXT NOT NULL, + vintage INTEGER, + output_comm TEXT NOT NULL, + flow REAL NOT NULL, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_net_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_objective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE output_retired_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), vintage INTEGER @@ -892,14 +938,14 @@ CREATE TABLE region PRIMARY KEY, notes TEXT ); -INSERT INTO region VALUES('region',NULL); +INSERT INTO "region" VALUES('region',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tech TEXT REFERENCES technology (tech), vintage INTEGER, @@ -908,27 +954,44 @@ CREATE TABLE reserve_capacity_derate PRIMARY KEY (region, period, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE TimeSegmentFraction +CREATE TABLE rps_requirement ( - period INTEGER + region TEXT NOT NULL + REFERENCES region (region), + period INTEGER NOT NULL REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) -); -INSERT INTO TimeSegmentFraction VALUES(2000,'charge','a',0.125,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'charge','b',0.125,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'charge','c',0.125,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'charge','d',0.125,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','a',0.125,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','b',0.125,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','c',0.125,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','d',0.125,NULL); + tech_group TEXT NOT NULL + REFERENCES tech_group (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE season_label +( + season TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "season_label" VALUES('charge','non-sequential season - charging day'); +INSERT INTO "season_label" VALUES('discharge','non-sequential season - discharging day'); +INSERT INTO "season_label" VALUES('summer','sequential season - summer day'); +INSERT INTO "season_label" VALUES('sept_w1','sequential season - day in first week of September'); +INSERT INTO "season_label" VALUES('sept_w2','sequential season - day in second week of September'); +INSERT INTO "season_label" VALUES('sept_w3','sequential season - day in third week of September'); +INSERT INTO "season_label" VALUES('sept_w4','sequential season - day in fourth week of September'); +INSERT INTO "season_label" VALUES('sept_29th','sequential season - 29th of September'); +INSERT INTO "season_label" VALUES('sept_30th','sequential season - 30th of September'); +INSERT INTO "season_label" VALUES('winter','sequential season - winter day'); +INSERT INTO "season_label" VALUES('apr_w1','sequential season - day in first week of September'); +INSERT INTO "season_label" VALUES('apr_w2','sequential season - day in second week of September'); +INSERT INTO "season_label" VALUES('apr_w3','sequential season - day in third week of September'); +INSERT INTO "season_label" VALUES('apr_w4','sequential season - day in fourth week of September'); +INSERT INTO "season_label" VALUES('apr_29th','sequential season - 29th of April'); +INSERT INTO "season_label" VALUES('apr_30th','sequential season - 30th of April'); +CREATE TABLE sector_label +( + sector TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "sector_label" VALUES('electricity',NULL); CREATE TABLE storage_duration ( region TEXT, @@ -937,172 +1000,159 @@ CREATE TABLE storage_duration notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO storage_duration VALUES('region','dly_stor',4.0,NULL); -INSERT INTO storage_duration VALUES('region','seas_stor',8760.0,NULL); -CREATE TABLE lifetime_survival_curve +INSERT INTO "storage_duration" VALUES('region','dly_stor',4.0,NULL); +INSERT INTO "storage_duration" VALUES('region','seas_stor',8760.0,NULL); +CREATE TABLE tech_group ( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE tech_group_member +( + group_name TEXT + REFERENCES tech_group (group_name), + tech TEXT REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) + PRIMARY KEY (group_name, tech) +); +CREATE TABLE technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES technology_type (label) ); -CREATE TABLE technologyType +INSERT INTO "technology" VALUES('generator','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO "technology" VALUES('dly_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO "technology" VALUES('seas_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,1,NULL); +INSERT INTO "technology" VALUES('demand','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +CREATE TABLE technology_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO technologyType VALUES('p','production technology'); -INSERT INTO technologyType VALUES('pb','baseload production technology'); -INSERT INTO technologyType VALUES('ps','storage production technology'); -CREATE TABLE TimeOfDay +INSERT INTO "technology_type" VALUES('p','production technology'); +INSERT INTO "technology_type" VALUES('pb','baseload production technology'); +INSERT INTO "technology_type" VALUES('ps','storage production technology'); +CREATE TABLE time_of_day ( sequence INTEGER UNIQUE, tod TEXT PRIMARY KEY ); -INSERT INTO TimeOfDay VALUES(0,'a'); -INSERT INTO TimeOfDay VALUES(1,'b'); -INSERT INTO TimeOfDay VALUES(2,'c'); -INSERT INTO TimeOfDay VALUES(3,'d'); +INSERT INTO "time_of_day" VALUES(0,'a'); +INSERT INTO "time_of_day" VALUES(1,'b'); +INSERT INTO "time_of_day" VALUES(2,'c'); +INSERT INTO "time_of_day" VALUES(3,'d'); CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES time_periodType (label) + REFERENCES time_period_type (label) ); -INSERT INTO time_period VALUES(0,2000,'f'); -INSERT INTO time_period VALUES(1,2005,'f'); -CREATE TABLE TimeSeason -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - season TEXT - REFERENCES SeasonLabel (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); -INSERT INTO TimeSeason VALUES(2000,0,'charge',NULL); -INSERT INTO TimeSeason VALUES(2000,1,'discharge',NULL); -CREATE TABLE time_periodType +INSERT INTO "time_period" VALUES(0,2000,'f'); +INSERT INTO "time_period" VALUES(1,2005,'f'); +CREATE TABLE time_period_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO time_periodType VALUES('e','existing vintages'); -INSERT INTO time_periodType VALUES('f','future'); -CREATE TABLE OutputEmission +INSERT INTO "time_period_type" VALUES('e','existing vintages'); +INSERT INTO "time_period_type" VALUES('f','future'); +CREATE TABLE time_season ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + season TEXT REFERENCES season_label(season), + notes TEXT, + PRIMARY KEY (period, sequence, season) ); -CREATE TABLE RPSRequirement +INSERT INTO "time_season" VALUES(2000,0,'charge',NULL); +INSERT INTO "time_season" VALUES(2000,1,'discharge',NULL); +CREATE TABLE time_season_all ( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL + period INTEGER REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES TechGroup (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE TechGroupMember -( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technologyType (label) + sequence INTEGER, + season TEXT + REFERENCES season_label (season), + notes TEXT, + PRIMARY KEY (period, sequence, season) ); -INSERT INTO technology VALUES('generator','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO technology VALUES('dly_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO technology VALUES('seas_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,1,NULL); -INSERT INTO technology VALUES('demand','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -CREATE TABLE output_cost +CREATE TABLE time_season_sequential ( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + seas_seq TEXT, + season TEXT REFERENCES season_label(season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) ); -CREATE TABLE time_season_sequential +INSERT INTO "time_season_sequential" VALUES(2000,1,'summer','charge',152.5,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,2,'sept_w1','discharge',7.0,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,3,'sept_w2','charge',7.0,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,4,'sept_w3','discharge',7.0,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,5,'sept_w4','charge',7.0,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,6,'sept_29th','discharge',1.0,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,7,'sept_30th','charge',1.0,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,8,'winter','discharge',152.5,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,9,'apr_w1','charge',7.0,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,10,'apr_w2','discharge',7.0,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,11,'apr_w3','charge',7.0,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,12,'apr_w4','discharge',7.0,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,13,'apr_29th','charge',1.0,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,14,'apr_30th','discharge',1.0,NULL); +CREATE TABLE time_season_to_sequential ( period INTEGER REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -INSERT INTO time_season_sequential VALUES(2000,1,'summer','charge',152.5,NULL); -INSERT INTO time_season_sequential VALUES(2000,2,'sept_w1','discharge',7,NULL); -INSERT INTO time_season_sequential VALUES(2000,3,'sept_w2','charge',7,NULL); -INSERT INTO time_season_sequential VALUES(2000,4,'sept_w3','discharge',7,NULL); -INSERT INTO time_season_sequential VALUES(2000,5,'sept_w4','charge',7,NULL); -INSERT INTO time_season_sequential VALUES(2000,6,'sept_29th','discharge',1,NULL); -INSERT INTO time_season_sequential VALUES(2000,7,'sept_30th','charge',1,NULL); -INSERT INTO time_season_sequential VALUES(2000,8,'winter','discharge',152.5,NULL); -INSERT INTO time_season_sequential VALUES(2000,9,'apr_w1','charge',7,NULL); -INSERT INTO time_season_sequential VALUES(2000,10,'apr_w2','discharge',7,NULL); -INSERT INTO time_season_sequential VALUES(2000,11,'apr_w3','charge',7,NULL); -INSERT INTO time_season_sequential VALUES(2000,12,'apr_w4','discharge',7,NULL); -INSERT INTO time_season_sequential VALUES(2000,13,'apr_29th','charge',1,NULL); -INSERT INTO time_season_sequential VALUES(2000,14,'apr_30th','discharge',1,NULL); +CREATE TABLE time_segment_fraction +( + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + segment_fraction REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) +); +INSERT INTO "time_segment_fraction" VALUES(2000,'charge','a',0.125,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'charge','b',0.125,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'charge','c',0.125,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'charge','d',0.125,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'discharge','a',0.125,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'discharge','b',0.125,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'discharge','c',0.125,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'discharge','d',0.125,NULL); +CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index d685f309c..e5fba3d42 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -1,56 +1,4 @@ -PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO metadata VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO metadata VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO metadata VALUES ('days_per_period', 365, 'count of days in each period'); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO metadata_real VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); -INSERT INTO metadata_real VALUES('global_discount_rate',0.05000000000000000277,''); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE SeasonLabel -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SeasonLabel VALUES('summer',NULL); -INSERT INTO SeasonLabel VALUES('winter',NULL); -CREATE TABLE SectorLabel -( - sector TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SectorLabel VALUES('supply',NULL); -INSERT INTO SectorLabel VALUES('electric',NULL); -INSERT INTO SectorLabel VALUES('transport',NULL); -INSERT INTO SectorLabel VALUES('commercial',NULL); -INSERT INTO SectorLabel VALUES('residential',NULL); -INSERT INTO SectorLabel VALUES('industrial',NULL); CREATE TABLE capacity_credit ( region TEXT, @@ -70,9 +18,9 @@ CREATE TABLE capacity_factor_process period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), vintage INTEGER, @@ -87,9 +35,9 @@ CREATE TABLE capacity_factor_tech period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), factor REAL, @@ -97,7 +45,7 @@ CREATE TABLE capacity_factor_tech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE CapacityToActivity +CREATE TABLE capacity_to_activity ( region TEXT, tech TEXT @@ -111,28 +59,28 @@ CREATE TABLE commodity name TEXT PRIMARY KEY, flag TEXT - REFERENCES commodityType (label), + REFERENCES commodity_type (label), description TEXT ); -INSERT INTO commodity VALUES('ELC','d','electricity'); -INSERT INTO commodity VALUES('NGA','p','natural gas'); -INSERT INTO commodity VALUES('CO2','e','CO2 emission'); -INSERT INTO commodity VALUES('CO2_CAP','d','captured CO2'); -INSERT INTO commodity VALUES('ETHOS','s','source'); -CREATE TABLE commodityType +INSERT INTO "commodity" VALUES('ELC','d','electricity'); +INSERT INTO "commodity" VALUES('NGA','p','natural gas'); +INSERT INTO "commodity" VALUES('CO2','e','CO2 emission'); +INSERT INTO "commodity" VALUES('CO2_CAP','d','captured CO2'); +INSERT INTO "commodity" VALUES('ETHOS','s','source'); +CREATE TABLE commodity_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO commodityType VALUES('w','waste commodity'); -INSERT INTO commodityType VALUES('wa','waste annual commodity'); -INSERT INTO commodityType VALUES('wp','waste physical commodity'); -INSERT INTO commodityType VALUES('a','annual commodity'); -INSERT INTO commodityType VALUES('s','source commodity'); -INSERT INTO commodityType VALUES('p','physical commodity'); -INSERT INTO commodityType VALUES('e','emissions commodity'); -INSERT INTO commodityType VALUES('d','demand commodity'); +INSERT INTO "commodity_type" VALUES('w','waste commodity'); +INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); +INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); +INSERT INTO "commodity_type" VALUES('a','annual commodity'); +INSERT INTO "commodity_type" VALUES('s','source commodity'); +INSERT INTO "commodity_type" VALUES('p','physical commodity'); +INSERT INTO "commodity_type" VALUES('e','emissions commodity'); +INSERT INTO "commodity_type" VALUES('d','demand commodity'); CREATE TABLE construction_input ( region TEXT, @@ -159,7 +107,7 @@ CREATE TABLE cost_emission notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -INSERT INTO cost_emission VALUES('linkville',2000,'CO2',2.0,NULL,NULL); +INSERT INTO "cost_emission" VALUES('linkville',2000,'CO2',2.0,NULL,NULL); CREATE TABLE cost_fixed ( region TEXT NOT NULL, @@ -186,8 +134,8 @@ CREATE TABLE cost_invest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO cost_invest VALUES('linkville','PLANT',2000,100.0,'',''); -INSERT INTO cost_invest VALUES('linkville','CCS',2000,50.0,'',''); +INSERT INTO "cost_invest" VALUES('linkville','PLANT',2000,100.0,'',''); +INSERT INTO "cost_invest" VALUES('linkville','CCS',2000,50.0,'',''); CREATE TABLE cost_variable ( region TEXT NOT NULL, @@ -202,9 +150,9 @@ CREATE TABLE cost_variable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_variable VALUES('linkville',2000,'PLANT',2000,10.0,NULL,NULL); -INSERT INTO cost_variable VALUES('linkville',2000,'CCS',2000,10.0,NULL,NULL); -INSERT INTO cost_variable VALUES('linkville',2000,'FAKE_SOURCE',2000,0.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('linkville',2000,'PLANT',2000,10.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('linkville',2000,'CCS',2000,10.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('linkville',2000,'FAKE_SOURCE',2000,0.0,NULL,NULL); CREATE TABLE demand ( region TEXT, @@ -217,17 +165,17 @@ CREATE TABLE demand notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO demand VALUES('linkville',2000,'CO2_CAP',1000.0,NULL,NULL); -INSERT INTO demand VALUES('linkville',2000,'ELC',10.0,NULL,NULL); -CREATE TABLE demand_specific_distributionon +INSERT INTO "demand" VALUES('linkville',2000,'CO2_CAP',1000.0,NULL,NULL); +INSERT INTO "demand" VALUES('linkville',2000,'ELC',10.0,NULL,NULL); +CREATE TABLE demand_specific_distribution ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), demand_name TEXT REFERENCES commodity (name), dsd REAL, @@ -235,22 +183,6 @@ CREATE TABLE demand_specific_distributionon PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO demand_specific_distributionon VALUES('linkville',2000,'summer','day','ELC',0.5,''); -INSERT INTO demand_specific_distributionon VALUES('linkville',2000,'winter','day','ELC',0.5,''); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); CREATE TABLE efficiency ( region TEXT, @@ -267,19 +199,19 @@ CREATE TABLE efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO efficiency VALUES('linkville','ETHOS','MINE',2000,'NGA',1.0,''); -INSERT INTO efficiency VALUES('linkville','ETHOS','CCS',2000,'CO2_CAP',1.0,'capture eff'); -INSERT INTO efficiency VALUES('linkville','ETHOS','FAKE_SOURCE',2000,'CO2_CAP',1.0,''); -INSERT INTO efficiency VALUES('linkville','NGA','PLANT',2000,'ELC',0.5,NULL); +INSERT INTO "efficiency" VALUES('linkville','ETHOS','MINE',2000,'NGA',1.0,''); +INSERT INTO "efficiency" VALUES('linkville','ETHOS','CCS',2000,'CO2_CAP',1.0,'capture eff'); +INSERT INTO "efficiency" VALUES('linkville','ETHOS','FAKE_SOURCE',2000,'CO2_CAP',1.0,''); +INSERT INTO "efficiency" VALUES('linkville','NGA','PLANT',2000,'ELC',0.5,NULL); CREATE TABLE efficiency_variable ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -311,7 +243,7 @@ CREATE TABLE emission_activity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO emission_activity VALUES('linkville','CO2','NGA','PLANT',2000,'ELC',-3.0,'',''); +INSERT INTO "emission_activity" VALUES('linkville','CO2','NGA','PLANT',2000,'ELC',-3.0,'',''); CREATE TABLE emission_embodied ( region TEXT, @@ -324,7 +256,7 @@ CREATE TABLE emission_embodied value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) ); CREATE TABLE emission_end_of_life ( @@ -338,7 +270,21 @@ CREATE TABLE emission_end_of_life value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE end_of_life_output +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); CREATE TABLE existing_capacity ( @@ -352,13 +298,7 @@ CREATE TABLE existing_capacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE loan_lifetime_process +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -369,152 +309,197 @@ CREATE TABLE loan_lifetime_process notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE loan_rate +CREATE TABLE lifetime_survival_curve ( - region TEXT, - tech TEXT + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL REFERENCES technology (tech), - vintage INTEGER + vintage INTEGER NOT NULL REFERENCES time_period (period), - rate REAL, + fraction REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE lifetime_process +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), lifetime REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, tech) ); -CREATE TABLE lifetime_tech +INSERT INTO "lifetime_tech" VALUES('linkville','CCS',100.0,''); +INSERT INTO "lifetime_tech" VALUES('linkville','PLANT',100.0,''); +CREATE TABLE limit_activity ( - region TEXT, - tech TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE limit_activity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_annual_capacity_factor +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator), + CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO lifetime_tech VALUES('linkville','CCS',100.0,''); -INSERT INTO lifetime_tech VALUES('linkville','PLANT',100.0,''); -CREATE TABLE Operator +CREATE TABLE limit_capacity ( - operator TEXT PRIMARY KEY, - notes TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO Operator VALUES('e','equal to'); -INSERT INTO Operator VALUES('le','less than or equal to'); -INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE limit_growth_capacity +CREATE TABLE limit_capacity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_capacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity +CREATE TABLE limit_emission +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitStorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -CREATE TABLE limit_activity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, + REFERENCES operator (operator), + new_cap REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE limit_activity_share +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -522,105 +507,56 @@ CREATE TABLE limit_activity_share sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), share REAL, notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity +CREATE TABLE limit_resource ( region TEXT, - period INTEGER - REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, + REFERENCES operator (operator), + cum_act REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) + PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_capacity_share +CREATE TABLE limit_seasonal_capacity_factor ( - region TEXT, - period INTEGER + region TEXT + REFERENCES region (region), + period INTEGER REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, + season TEXT + REFERENCES season_label (season), + tech TEXT + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE limit_new_capacity +CREATE TABLE limit_storage_level_fraction ( - region TEXT, - period INTEGER + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), - tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) + REFERENCES operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); CREATE TABLE limit_tech_input_split ( @@ -632,7 +568,7 @@ CREATE TABLE limit_tech_input_split tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -647,7 +583,7 @@ CREATE TABLE limit_tech_input_split_annual tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -662,7 +598,7 @@ CREATE TABLE limit_tech_output_split output_comm TEXT REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) @@ -677,26 +613,12 @@ CREATE TABLE limit_tech_output_split_annual output_comm TEXT REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE LinkedTech +CREATE TABLE linked_tech ( primary_region TEXT, primary_tech TEXT @@ -708,7 +630,104 @@ CREATE TABLE LinkedTech notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); -INSERT INTO LinkedTech VALUES('linkville','PLANT','CO2','CCS',NULL); +INSERT INTO "linked_tech" VALUES('linkville','PLANT','CO2','CCS',NULL); +CREATE TABLE loan_lifetime_process +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE loan_rate +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE metadata +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); +INSERT INTO "metadata" VALUES('DB_MINOR',0,''); +CREATE TABLE metadata_real +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,''); +CREATE TABLE myopic_efficiency +( + base_year integer, + region text, + input_comm text, + tech text, + vintage integer, + output_comm text, + efficiency real, + lifetime integer, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (region, input_comm, tech, vintage, output_comm) +); +CREATE TABLE operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "operator" VALUES('e','equal to'); +INSERT INTO "operator" VALUES('le','less than or equal to'); +INSERT INTO "operator" VALUES('ge','greater than or equal to'); +CREATE TABLE output_built_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE output_cost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) +); CREATE TABLE output_curtailment ( scenario TEXT, @@ -719,7 +738,7 @@ CREATE TABLE output_curtailment season TEXT REFERENCES time_period (period), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -731,62 +750,42 @@ CREATE TABLE output_curtailment curtailment REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputNetCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_built_capacity +CREATE TABLE output_dual_variable ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE output_emission ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), - tech TEXT + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT REFERENCES technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE OutputFlowIn +CREATE TABLE output_flow_in ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -798,18 +797,18 @@ CREATE TABLE OutputFlowIn flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputFlowOut +CREATE TABLE output_flow_out ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -821,18 +820,70 @@ CREATE TABLE OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); +CREATE TABLE output_flow_out_summary +( + scenario TEXT NOT NULL, + region TEXT NOT NULL, + sector TEXT, + period INTEGER, + input_comm TEXT NOT NULL, + tech TEXT NOT NULL, + vintage INTEGER, + output_comm TEXT NOT NULL, + flow REAL NOT NULL, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_net_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_objective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE output_retired_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), vintage INTEGER @@ -872,14 +923,14 @@ CREATE TABLE region PRIMARY KEY, notes TEXT ); -INSERT INTO region VALUES('linkville',NULL); +INSERT INTO "region" VALUES('linkville',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tech TEXT REFERENCES technology (tech), vintage INTEGER, @@ -888,21 +939,35 @@ CREATE TABLE reserve_capacity_derate PRIMARY KEY (region, period, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE TimeSegmentFraction +CREATE TABLE rps_requirement ( - period INTEGER + region TEXT NOT NULL + REFERENCES region (region), + period INTEGER NOT NULL REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) + tech_group TEXT NOT NULL + REFERENCES tech_group (group_name), + requirement REAL NOT NULL, + notes TEXT ); -INSERT INTO TimeSegmentFraction VALUES(2000,'summer','day',0.5,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2000,'winter','day',0.5,'# W-D'); +CREATE TABLE season_label +( + season TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "season_label" VALUES('summer',NULL); +INSERT INTO "season_label" VALUES('winter',NULL); +CREATE TABLE sector_label +( + sector TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "sector_label" VALUES('supply',NULL); +INSERT INTO "sector_label" VALUES('electric',NULL); +INSERT INTO "sector_label" VALUES('transport',NULL); +INSERT INTO "sector_label" VALUES('commercial',NULL); +INSERT INTO "sector_label" VALUES('residential',NULL); +INSERT INTO "sector_label" VALUES('industrial',NULL); CREATE TABLE storage_duration ( region TEXT, @@ -911,154 +976,135 @@ CREATE TABLE storage_duration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE lifetime_survival_curve +CREATE TABLE tech_group ( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE tech_group_member +( + group_name TEXT + REFERENCES tech_group (group_name), + tech TEXT REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) + PRIMARY KEY (group_name, tech) +); +CREATE TABLE technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES technology_type (label) ); -CREATE TABLE technologyType +INSERT INTO "technology" VALUES('PLANT','p','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO "technology" VALUES('CCS','p','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO "technology" VALUES('MINE','p','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO "technology" VALUES('FAKE_SOURCE','p','supply',NULL,NULL,1,0,0,0,0,0,0,0,NULL); +CREATE TABLE technology_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO technologyType VALUES('p','production technology'); -INSERT INTO technologyType VALUES('pb','baseload production technology'); -INSERT INTO technologyType VALUES('ps','storage production technology'); -CREATE TABLE TimeOfDay +INSERT INTO "technology_type" VALUES('p','production technology'); +INSERT INTO "technology_type" VALUES('pb','baseload production technology'); +INSERT INTO "technology_type" VALUES('ps','storage production technology'); +CREATE TABLE time_of_day ( sequence INTEGER UNIQUE, tod TEXT PRIMARY KEY ); -INSERT INTO TimeOfDay VALUES(1,'day'); +INSERT INTO "time_of_day" VALUES(1,'day'); CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES time_periodType (label) + REFERENCES time_period_type (label) ); -INSERT INTO time_period VALUES(0,1995,'e'); -INSERT INTO time_period VALUES(1,2000,'f'); -INSERT INTO time_period VALUES(2,2005,'f'); -CREATE TABLE TimeSeason +INSERT INTO "time_period" VALUES(0,1995,'e'); +INSERT INTO "time_period" VALUES(1,2000,'f'); +INSERT INTO "time_period" VALUES(2,2005,'f'); +CREATE TABLE time_period_type +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO "time_period_type" VALUES('e','existing vintages'); +INSERT INTO "time_period_type" VALUES('f','future'); +CREATE TABLE time_season +( + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + season TEXT REFERENCES season_label(season), + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +INSERT INTO "time_season" VALUES(2000,1,'summer',NULL); +INSERT INTO "time_season" VALUES(2000,2,'winter',NULL); +CREATE TABLE time_season_all ( period INTEGER REFERENCES time_period (period), sequence INTEGER, season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); -INSERT INTO TimeSeason VALUES(2000,1,'summer',NULL); -INSERT INTO TimeSeason VALUES(2000,2,'winter',NULL); CREATE TABLE time_season_sequential ( - period INTEGER - REFERENCES time_period (period), + period INTEGER REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES SeasonLabel (season), + season TEXT REFERENCES season_label(season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE time_periodType -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO time_periodType VALUES('e','existing vintages'); -INSERT INTO time_periodType VALUES('f','future'); -CREATE TABLE OutputEmission +CREATE TABLE time_season_to_sequential ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER + period INTEGER REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) + sequence INTEGER, + seas_seq TEXT, + season TEXT + REFERENCES season_label (season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) ); -CREATE TABLE RPSRequirement +CREATE TABLE time_segment_fraction ( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL + period INTEGER REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES TechGroup (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE TechGroupMember -( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technologyType (label) -); -INSERT INTO technology VALUES('PLANT','p','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO technology VALUES('CCS','p','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO technology VALUES('MINE','p','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO technology VALUES('FAKE_SOURCE','p','supply',NULL,NULL,1,0,0,0,0,0,0,0,NULL); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + segment_fraction REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) ); +INSERT INTO "time_segment_fraction" VALUES(2000,'summer','day',0.5,'# S-D'); +INSERT INTO "time_segment_fraction" VALUES(2000,'winter','day',0.5,'# W-D'); +CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index befc090e0..3a577a81f 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -1,56 +1,4 @@ -PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO metadata VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO metadata VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO metadata VALUES ('days_per_period', 365, 'count of days in each period'); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO metadata_real VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); -INSERT INTO metadata_real VALUES('global_discount_rate',0.05000000000000000277,''); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE SeasonLabel -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SeasonLabel VALUES('s1',NULL); -INSERT INTO SeasonLabel VALUES('s2',NULL); -CREATE TABLE SectorLabel -( - sector TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SectorLabel VALUES('supply',NULL); -INSERT INTO SectorLabel VALUES('electric',NULL); -INSERT INTO SectorLabel VALUES('transport',NULL); -INSERT INTO SectorLabel VALUES('commercial',NULL); -INSERT INTO SectorLabel VALUES('residential',NULL); -INSERT INTO SectorLabel VALUES('industrial',NULL); CREATE TABLE capacity_credit ( region TEXT, @@ -70,9 +18,9 @@ CREATE TABLE capacity_factor_process period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), vintage INTEGER, @@ -87,9 +35,9 @@ CREATE TABLE capacity_factor_tech period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), factor REAL, @@ -97,7 +45,7 @@ CREATE TABLE capacity_factor_tech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE CapacityToActivity +CREATE TABLE capacity_to_activity ( region TEXT, tech TEXT @@ -106,34 +54,34 @@ CREATE TABLE CapacityToActivity notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO CapacityToActivity VALUES('electricville','bulbs',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('electricville','bulbs',1.0,''); CREATE TABLE commodity ( name TEXT PRIMARY KEY, flag TEXT - REFERENCES commodityType (label), + REFERENCES commodity_type (label), description TEXT ); -INSERT INTO commodity VALUES('ELC','p','# electricity'); -INSERT INTO commodity VALUES('HYD','p','# water'); -INSERT INTO commodity VALUES('co2','e','#CO2 emissions'); -INSERT INTO commodity VALUES('RL','d','# residential lighting'); -INSERT INTO commodity VALUES('earth','p','# the source of stuff'); -CREATE TABLE commodityType +INSERT INTO "commodity" VALUES('ELC','p','# electricity'); +INSERT INTO "commodity" VALUES('HYD','p','# water'); +INSERT INTO "commodity" VALUES('co2','e','#CO2 emissions'); +INSERT INTO "commodity" VALUES('RL','d','# residential lighting'); +INSERT INTO "commodity" VALUES('earth','p','# the source of stuff'); +CREATE TABLE commodity_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO commodityType VALUES('w','waste commodity'); -INSERT INTO commodityType VALUES('wa','waste annual commodity'); -INSERT INTO commodityType VALUES('wp','waste physical commodity'); -INSERT INTO commodityType VALUES('a','annual commodity'); -INSERT INTO commodityType VALUES('p','physical commodity'); -INSERT INTO commodityType VALUES('e','emissions commodity'); -INSERT INTO commodityType VALUES('d','demand commodity'); -INSERT INTO commodityType VALUES('s','source commodity'); +INSERT INTO "commodity_type" VALUES('w','waste commodity'); +INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); +INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); +INSERT INTO "commodity_type" VALUES('a','annual commodity'); +INSERT INTO "commodity_type" VALUES('p','physical commodity'); +INSERT INTO "commodity_type" VALUES('e','emissions commodity'); +INSERT INTO "commodity_type" VALUES('d','demand commodity'); +INSERT INTO "commodity_type" VALUES('s','source commodity'); CREATE TABLE construction_input ( region TEXT, @@ -174,8 +122,8 @@ CREATE TABLE cost_fixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_fixed VALUES('electricville',2025,'EH',2025,100.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2025,'batt',2025,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('electricville',2025,'EH',2025,100.0,'',''); +INSERT INTO "cost_fixed" VALUES('electricville',2025,'batt',2025,1.0,'',''); CREATE TABLE cost_invest ( region TEXT, @@ -188,8 +136,8 @@ CREATE TABLE cost_invest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO cost_invest VALUES('electricville','EH',2025,100.0,'',''); -INSERT INTO cost_invest VALUES('electricville','batt',2025,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('electricville','EH',2025,100.0,'',''); +INSERT INTO "cost_invest" VALUES('electricville','batt',2025,1.0,NULL,NULL); CREATE TABLE cost_variable ( region TEXT NOT NULL, @@ -204,8 +152,8 @@ CREATE TABLE cost_variable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_variable VALUES('electricville',2025,'EH',2025,1000.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2025,'batt',2025,1.0,'',''); +INSERT INTO "cost_variable" VALUES('electricville',2025,'EH',2025,1000.0,'',''); +INSERT INTO "cost_variable" VALUES('electricville',2025,'batt',2025,1.0,'',''); CREATE TABLE demand ( region TEXT, @@ -218,16 +166,16 @@ CREATE TABLE demand notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO demand VALUES('electricville',2025,'RL',100.0,'',''); +INSERT INTO "demand" VALUES('electricville',2025,'RL',100.0,'',''); CREATE TABLE demand_specific_distribution ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), demand_name TEXT REFERENCES commodity (name), dsd REAL, @@ -235,30 +183,16 @@ CREATE TABLE demand_specific_distribution PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO demand_specific_distribution VALUES('electricville',2025,'s1','d1','RL',0.07499999999999999723,''); -INSERT INTO demand_specific_distribution VALUES('electricville',2025,'s1','d2','RL',0.07499999999999999723,''); -INSERT INTO demand_specific_distribution VALUES('electricville',2025,'s1','d3','RL',0.07499999999999999723,NULL); -INSERT INTO demand_specific_distribution VALUES('electricville',2025,'s2','d1','RL',0.07499999999999999723,NULL); -INSERT INTO demand_specific_distribution VALUES('electricville',2025,'s2','d2','RL',0.07499999999999999723,NULL); -INSERT INTO demand_specific_distribution VALUES('electricville',2025,'s2','d3','RL',0.07499999999999999723,NULL); -INSERT INTO demand_specific_distribution VALUES('electricville',2025,'s1','d4','RL',0.07499999999999999723,NULL); -INSERT INTO demand_specific_distribution VALUES('electricville',2025,'s1','d5','RL',0.2000000000000000111,NULL); -INSERT INTO demand_specific_distribution VALUES('electricville',2025,'s2','d4','RL',0.2000000000000000111,NULL); -INSERT INTO demand_specific_distribution VALUES('electricville',2025,'s2','d5','RL',0.07499999999999999723,NULL); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); +INSERT INTO "demand_specific_distribution" VALUES('electricville',2025,'s1','d1','RL',0.075,''); +INSERT INTO "demand_specific_distribution" VALUES('electricville',2025,'s1','d2','RL',0.075,''); +INSERT INTO "demand_specific_distribution" VALUES('electricville',2025,'s1','d3','RL',0.075,NULL); +INSERT INTO "demand_specific_distribution" VALUES('electricville',2025,'s2','d1','RL',0.075,NULL); +INSERT INTO "demand_specific_distribution" VALUES('electricville',2025,'s2','d2','RL',0.075,NULL); +INSERT INTO "demand_specific_distribution" VALUES('electricville',2025,'s2','d3','RL',0.075,NULL); +INSERT INTO "demand_specific_distribution" VALUES('electricville',2025,'s1','d4','RL',0.075,NULL); +INSERT INTO "demand_specific_distribution" VALUES('electricville',2025,'s1','d5','RL',0.2,NULL); +INSERT INTO "demand_specific_distribution" VALUES('electricville',2025,'s2','d4','RL',0.2,NULL); +INSERT INTO "demand_specific_distribution" VALUES('electricville',2025,'s2','d5','RL',0.075,NULL); CREATE TABLE efficiency ( region TEXT, @@ -275,19 +209,19 @@ CREATE TABLE efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO efficiency VALUES('electricville','HYD','EH',2025,'ELC',1.0,NULL); -INSERT INTO efficiency VALUES('electricville','ELC','bulbs',2025,'RL',1.0,NULL); -INSERT INTO efficiency VALUES('electricville','earth','well',2025,'HYD',1.0,'water source'); -INSERT INTO efficiency VALUES('electricville','ELC','batt',2025,'ELC',0.75,NULL); +INSERT INTO "efficiency" VALUES('electricville','HYD','EH',2025,'ELC',1.0,NULL); +INSERT INTO "efficiency" VALUES('electricville','ELC','bulbs',2025,'RL',1.0,NULL); +INSERT INTO "efficiency" VALUES('electricville','earth','well',2025,'HYD',1.0,'water source'); +INSERT INTO "efficiency" VALUES('electricville','ELC','batt',2025,'ELC',0.75,NULL); CREATE TABLE efficiency_variable ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -319,7 +253,7 @@ CREATE TABLE emission_activity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO emission_activity VALUES('electricville','co2','HYD','EH',2025,'ELC',0.02000000000000000041,NULL,NULL); +INSERT INTO "emission_activity" VALUES('electricville','co2','HYD','EH',2025,'ELC',0.02,NULL,NULL); CREATE TABLE emission_embodied ( region TEXT, @@ -332,7 +266,7 @@ CREATE TABLE emission_embodied value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) ); CREATE TABLE emission_end_of_life ( @@ -346,7 +280,21 @@ CREATE TABLE emission_end_of_life value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE end_of_life_output +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); CREATE TABLE existing_capacity ( @@ -360,13 +308,7 @@ CREATE TABLE existing_capacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE loan_lifetime_process +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -377,153 +319,201 @@ CREATE TABLE loan_lifetime_process notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE loan_rate +CREATE TABLE lifetime_survival_curve ( - region TEXT, - tech TEXT + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL REFERENCES technology (tech), - vintage INTEGER + vintage INTEGER NOT NULL REFERENCES time_period (period), - rate REAL, + fraction REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE lifetime_process +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), lifetime REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, tech) ); -CREATE TABLE lifetime_tech +INSERT INTO "lifetime_tech" VALUES('electricville','EH',60.0,''); +INSERT INTO "lifetime_tech" VALUES('electricville','bulbs',100.0,'super LED!'); +CREATE TABLE limit_activity ( - region TEXT, - tech TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE limit_activity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_annual_capacity_factor +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator), + CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO lifetime_tech VALUES('electricville','EH',60.0,''); -INSERT INTO lifetime_tech VALUES('electricville','bulbs',100.0,'super LED!'); -CREATE TABLE Operator +CREATE TABLE limit_capacity ( - operator TEXT PRIMARY KEY, - notes TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO Operator VALUES('e','equal to'); -INSERT INTO Operator VALUES('le','less than or equal to'); -INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE limit_growth_capacity +INSERT INTO "limit_capacity" VALUES('electricville',2025,'EH','ge',0.1,'',''); +INSERT INTO "limit_capacity" VALUES('electricville',2025,'batt','ge',0.1,'',''); +INSERT INTO "limit_capacity" VALUES('electricville',2025,'EH','le',200.0,'',''); +INSERT INTO "limit_capacity" VALUES('electricville',2025,'batt','le',100.0,'',''); +CREATE TABLE limit_capacity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_capacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity +CREATE TABLE limit_emission +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitStorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -INSERT INTO LimitStorageLevelFraction VALUES('electricville',2025,'s1','d1','batt',2025,'e',0.5,NULL); -CREATE TABLE limit_activity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, + REFERENCES operator (operator), + new_cap REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE limit_activity_share +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -531,110 +521,58 @@ CREATE TABLE limit_activity_share sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), share REAL, notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity +CREATE TABLE limit_resource ( region TEXT, - period INTEGER - REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, + REFERENCES operator (operator), + cum_act REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) + PRIMARY KEY (region, tech_or_group, operator) ); -INSERT INTO limit_capacity VALUES('electricville',2025,'EH','ge',0.1000000000000000055,'',''); -INSERT INTO limit_capacity VALUES('electricville',2025,'batt','ge',0.1000000000000000055,'',''); -INSERT INTO limit_capacity VALUES('electricville',2025,'EH','le',200.0,'',''); -INSERT INTO limit_capacity VALUES('electricville',2025,'batt','le',100.0,'',''); -CREATE TABLE limit_capacity_share +CREATE TABLE limit_seasonal_capacity_factor ( - region TEXT, - period INTEGER + region TEXT + REFERENCES region (region), + period INTEGER REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, + season TEXT + REFERENCES season_label (season), + tech TEXT + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE limit_new_capacity +CREATE TABLE limit_storage_level_fraction ( - region TEXT, - period INTEGER + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), - tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) + REFERENCES operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); +INSERT INTO "limit_storage_level_fraction" VALUES('electricville',2025,'s1','d1','batt',2025,'e',0.5,NULL); CREATE TABLE limit_tech_input_split ( region TEXT, @@ -645,7 +583,7 @@ CREATE TABLE limit_tech_input_split tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -660,7 +598,7 @@ CREATE TABLE limit_tech_input_split_annual tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -675,7 +613,7 @@ CREATE TABLE limit_tech_output_split output_comm TEXT REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) @@ -690,26 +628,12 @@ CREATE TABLE limit_tech_output_split_annual output_comm TEXT REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE LinkedTech +CREATE TABLE linked_tech ( primary_region TEXT, primary_tech TEXT @@ -721,6 +645,103 @@ CREATE TABLE LinkedTech notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); +CREATE TABLE loan_lifetime_process +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE loan_rate +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE metadata +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); +INSERT INTO "metadata" VALUES('DB_MINOR',0,''); +CREATE TABLE metadata_real +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,''); +CREATE TABLE myopic_efficiency +( + base_year integer, + region text, + input_comm text, + tech text, + vintage integer, + output_comm text, + efficiency real, + lifetime integer, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (region, input_comm, tech, vintage, output_comm) +); +CREATE TABLE operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "operator" VALUES('e','equal to'); +INSERT INTO "operator" VALUES('le','less than or equal to'); +INSERT INTO "operator" VALUES('ge','greater than or equal to'); +CREATE TABLE output_built_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE output_cost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) +); CREATE TABLE output_curtailment ( scenario TEXT, @@ -731,7 +752,7 @@ CREATE TABLE output_curtailment season TEXT REFERENCES time_period (period), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -743,62 +764,42 @@ CREATE TABLE output_curtailment curtailment REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputNetCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_built_capacity +CREATE TABLE output_dual_variable ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE output_emission ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), - tech TEXT + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT REFERENCES technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE OutputFlowIn +CREATE TABLE output_flow_in ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -810,18 +811,18 @@ CREATE TABLE OutputFlowIn flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputFlowOut +CREATE TABLE output_flow_out ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -833,18 +834,70 @@ CREATE TABLE OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); +CREATE TABLE output_flow_out_summary +( + scenario TEXT NOT NULL, + region TEXT NOT NULL, + sector TEXT, + period INTEGER, + input_comm TEXT NOT NULL, + tech TEXT NOT NULL, + vintage INTEGER, + output_comm TEXT NOT NULL, + flow REAL NOT NULL, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_net_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_objective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE output_retired_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), vintage INTEGER @@ -884,14 +937,14 @@ CREATE TABLE region PRIMARY KEY, notes TEXT ); -INSERT INTO region VALUES('electricville',NULL); +INSERT INTO "region" VALUES('electricville',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tech TEXT REFERENCES technology (tech), vintage INTEGER, @@ -900,29 +953,35 @@ CREATE TABLE reserve_capacity_derate PRIMARY KEY (region, period, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE TimeSegmentFraction +CREATE TABLE rps_requirement ( - period INTEGER + region TEXT NOT NULL + REFERENCES region (region), + period INTEGER NOT NULL REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) -); -INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d3',0.1000000000000000055,NULL); -INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d1',0.1000000000000000055,NULL); -INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d2',0.1000000000000000055,NULL); -INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d3',0.1000000000000000055,NULL); -INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d1',0.1000000000000000055,NULL); -INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d2',0.1000000000000000055,NULL); -INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d4',0.1000000000000000055,NULL); -INSERT INTO TimeSegmentFraction VALUES(2025,'s1','d5',0.1000000000000000055,NULL); -INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d4',0.1000000000000000055,NULL); -INSERT INTO TimeSegmentFraction VALUES(2025,'s2','d5',0.1000000000000000055,NULL); + tech_group TEXT NOT NULL + REFERENCES tech_group (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE season_label +( + season TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "season_label" VALUES('s1',NULL); +INSERT INTO "season_label" VALUES('s2',NULL); +CREATE TABLE sector_label +( + sector TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "sector_label" VALUES('supply',NULL); +INSERT INTO "sector_label" VALUES('electric',NULL); +INSERT INTO "sector_label" VALUES('transport',NULL); +INSERT INTO "sector_label" VALUES('commercial',NULL); +INSERT INTO "sector_label" VALUES('residential',NULL); +INSERT INTO "sector_label" VALUES('industrial',NULL); CREATE TABLE storage_duration ( region TEXT, @@ -931,159 +990,148 @@ CREATE TABLE storage_duration notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO storage_duration VALUES('electricville','batt',10.0,NULL); -CREATE TABLE lifetime_survival_curve +INSERT INTO "storage_duration" VALUES('electricville','batt',10.0,NULL); +CREATE TABLE tech_group ( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE tech_group_member +( + group_name TEXT + REFERENCES tech_group (group_name), + tech TEXT REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) + PRIMARY KEY (group_name, tech) +); +CREATE TABLE technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES technology_type (label) ); -CREATE TABLE technologyType +INSERT INTO "technology" VALUES('well','p','supply','water','',0,0,0,0,0,0,0,0,'plain old water'); +INSERT INTO "technology" VALUES('bulbs','p','residential','electric','',0,0,0,0,0,0,0,0,' residential lighting'); +INSERT INTO "technology" VALUES('EH','pb','electric','hydro','',0,0,0,0,0,0,0,0,'hydro power electric plant'); +INSERT INTO "technology" VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0,0,'big battery'); +CREATE TABLE technology_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO technologyType VALUES('p','production technology'); -INSERT INTO technologyType VALUES('pb','baseload production technology'); -INSERT INTO technologyType VALUES('ps','storage production technology'); -CREATE TABLE TimeOfDay +INSERT INTO "technology_type" VALUES('p','production technology'); +INSERT INTO "technology_type" VALUES('pb','baseload production technology'); +INSERT INTO "technology_type" VALUES('ps','storage production technology'); +CREATE TABLE time_of_day ( sequence INTEGER UNIQUE, tod TEXT PRIMARY KEY ); -INSERT INTO TimeOfDay VALUES(1,'d1'); -INSERT INTO TimeOfDay VALUES(2,'d2'); -INSERT INTO TimeOfDay VALUES(3,'d3'); -INSERT INTO TimeOfDay VALUES(4,'d4'); -INSERT INTO TimeOfDay VALUES(5,'d5'); +INSERT INTO "time_of_day" VALUES(1,'d1'); +INSERT INTO "time_of_day" VALUES(2,'d2'); +INSERT INTO "time_of_day" VALUES(3,'d3'); +INSERT INTO "time_of_day" VALUES(4,'d4'); +INSERT INTO "time_of_day" VALUES(5,'d5'); CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES time_periodType (label) + REFERENCES time_period_type (label) +); +INSERT INTO "time_period" VALUES(1,2020,'e'); +INSERT INTO "time_period" VALUES(2,2025,'f'); +INSERT INTO "time_period" VALUES(3,2030,'f'); +CREATE TABLE time_period_type +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO "time_period_type" VALUES('e','existing vintages'); +INSERT INTO "time_period_type" VALUES('f','future'); +CREATE TABLE time_season +( + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + season TEXT REFERENCES season_label(season), + notes TEXT, + PRIMARY KEY (period, sequence, season) ); -INSERT INTO time_period VALUES(1,2020,'e'); -INSERT INTO time_period VALUES(2,2025,'f'); -INSERT INTO time_period VALUES(3,2030,'f'); -CREATE TABLE TimeSeason +INSERT INTO "time_season" VALUES(2025,1,'s1',NULL); +INSERT INTO "time_season" VALUES(2025,2,'s2',NULL); +CREATE TABLE time_season_all ( period INTEGER REFERENCES time_period (period), sequence INTEGER, season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); -INSERT INTO TimeSeason VALUES(2025,1,'s1',NULL); -INSERT INTO TimeSeason VALUES(2025,2,'s2',NULL); CREATE TABLE time_season_sequential ( - period INTEGER - REFERENCES time_period (period), + period INTEGER REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES SeasonLabel (season), + season TEXT REFERENCES season_label(season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE time_periodType +CREATE TABLE time_season_to_sequential ( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO time_periodType VALUES('e','existing vintages'); -INSERT INTO time_periodType VALUES('f','future'); -CREATE TABLE OutputEmission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER + period INTEGER REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) + sequence INTEGER, + seas_seq TEXT, + season TEXT + REFERENCES season_label (season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) ); -CREATE TABLE RPSRequirement +CREATE TABLE time_segment_fraction ( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL + period INTEGER REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES TechGroup (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE TechGroupMember -( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technologyType (label) -); -INSERT INTO technology VALUES('well','p','supply','water','',0,0,0,0,0,0,0,0,'plain old water'); -INSERT INTO technology VALUES('bulbs','p','residential','electric','',0,0,0,0,0,0,0,0,' residential lighting'); -INSERT INTO technology VALUES('EH','pb','electric','hydro','',0,0,0,0,0,0,0,0,'hydro power electric plant'); -INSERT INTO technology VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0,0,'big battery'); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) -); + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + segment_fraction REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) +); +INSERT INTO "time_segment_fraction" VALUES(2025,'s1','d3',0.1,NULL); +INSERT INTO "time_segment_fraction" VALUES(2025,'s2','d1',0.1,NULL); +INSERT INTO "time_segment_fraction" VALUES(2025,'s2','d2',0.1,NULL); +INSERT INTO "time_segment_fraction" VALUES(2025,'s2','d3',0.1,NULL); +INSERT INTO "time_segment_fraction" VALUES(2025,'s1','d1',0.1,NULL); +INSERT INTO "time_segment_fraction" VALUES(2025,'s1','d2',0.1,NULL); +INSERT INTO "time_segment_fraction" VALUES(2025,'s1','d4',0.1,NULL); +INSERT INTO "time_segment_fraction" VALUES(2025,'s1','d5',0.1,NULL); +INSERT INTO "time_segment_fraction" VALUES(2025,'s2','d4',0.1,NULL); +INSERT INTO "time_segment_fraction" VALUES(2025,'s2','d5',0.1,NULL); +CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; diff --git a/tests/testing_data/survival_curve.sql b/tests/testing_data/survival_curve.sql index 5525fc022..c907629e6 100644 --- a/tests/testing_data/survival_curve.sql +++ b/tests/testing_data/survival_curve.sql @@ -1,49 +1,4 @@ -PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO metadata VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO metadata VALUES('DB_MINOR',0,'DB minor version number'); -INSERT INTO metadata VALUES('days_per_period',365,'count of days in each period'); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO metadata_real VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO metadata_real VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE SeasonLabel -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SeasonLabel VALUES('s',NULL); -CREATE TABLE SectorLabel -( - sector TEXT PRIMARY KEY, - notes TEXT -); CREATE TABLE capacity_credit ( region TEXT, @@ -63,9 +18,9 @@ CREATE TABLE capacity_factor_process period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), vintage INTEGER, @@ -80,9 +35,9 @@ CREATE TABLE capacity_factor_tech period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), factor REAL, @@ -90,7 +45,7 @@ CREATE TABLE capacity_factor_tech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE CapacityToActivity +CREATE TABLE capacity_to_activity ( region TEXT, tech TEXT @@ -104,25 +59,25 @@ CREATE TABLE commodity name TEXT PRIMARY KEY, flag TEXT - REFERENCES commodityType (label), + REFERENCES commodity_type (label), description TEXT ); -INSERT INTO commodity VALUES('source','s',NULL); -INSERT INTO commodity VALUES('demand','d',NULL); -CREATE TABLE commodityType +INSERT INTO "commodity" VALUES('source','s',NULL); +INSERT INTO "commodity" VALUES('demand','d',NULL); +CREATE TABLE commodity_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO commodityType VALUES('p','physical commodity'); -INSERT INTO commodityType VALUES('a','annual commodity'); -INSERT INTO commodityType VALUES('e','emissions commodity'); -INSERT INTO commodityType VALUES('d','demand commodity'); -INSERT INTO commodityType VALUES('s','source commodity'); -INSERT INTO commodityType VALUES('w','waste commodity'); -INSERT INTO commodityType VALUES('wa','waste annual commodity'); -INSERT INTO commodityType VALUES('wp','waste physical commodity'); +INSERT INTO "commodity_type" VALUES('p','physical commodity'); +INSERT INTO "commodity_type" VALUES('a','annual commodity'); +INSERT INTO "commodity_type" VALUES('e','emissions commodity'); +INSERT INTO "commodity_type" VALUES('d','demand commodity'); +INSERT INTO "commodity_type" VALUES('s','source commodity'); +INSERT INTO "commodity_type" VALUES('w','waste commodity'); +INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); +INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); CREATE TABLE construction_input ( region TEXT, @@ -163,32 +118,32 @@ CREATE TABLE cost_fixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_fixed VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); CREATE TABLE cost_invest ( region TEXT, @@ -201,12 +156,12 @@ CREATE TABLE cost_invest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO cost_invest VALUES('region','tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('region','tech_future',2030,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('region','tech_future',2035,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('region','tech_future',2040,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('region','tech_future',2045,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('region','tech_future',2050,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('region','tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('region','tech_future',2030,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('region','tech_future',2035,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('region','tech_future',2040,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('region','tech_future',2045,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('region','tech_future',2050,1.0,NULL,NULL); CREATE TABLE cost_variable ( region TEXT NOT NULL, @@ -221,32 +176,32 @@ CREATE TABLE cost_variable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_variable VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); CREATE TABLE demand ( region TEXT, @@ -259,21 +214,21 @@ CREATE TABLE demand notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO demand VALUES('region',2025,'demand',1.0,NULL,NULL); -INSERT INTO demand VALUES('region',2030,'demand',1.0,NULL,NULL); -INSERT INTO demand VALUES('region',2035,'demand',1.0,NULL,NULL); -INSERT INTO demand VALUES('region',2040,'demand',1.0,NULL,NULL); -INSERT INTO demand VALUES('region',2045,'demand',1.0,NULL,NULL); -INSERT INTO demand VALUES('region',2050,'demand',1.0,NULL,NULL); -CREATE TABLE demand_specific_distributionon +INSERT INTO "demand" VALUES('region',2025,'demand',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('region',2030,'demand',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('region',2035,'demand',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('region',2040,'demand',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('region',2045,'demand',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('region',2050,'demand',1.0,NULL,NULL); +CREATE TABLE demand_specific_distribution ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), demand_name TEXT REFERENCES commodity (name), dsd REAL, @@ -281,20 +236,6 @@ CREATE TABLE demand_specific_distributionon PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); CREATE TABLE efficiency ( region TEXT, @@ -311,23 +252,23 @@ CREATE TABLE efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO efficiency VALUES('region','source','tech_ancient',1994,'demand',1.0,NULL); -INSERT INTO efficiency VALUES('region','source','tech_old',2010,'demand',1.0,NULL); -INSERT INTO efficiency VALUES('region','source','tech_current',2025,'demand',1.0,NULL); -INSERT INTO efficiency VALUES('region','source','tech_future',2030,'demand',1.0,NULL); -INSERT INTO efficiency VALUES('region','source','tech_future',2035,'demand',1.0,NULL); -INSERT INTO efficiency VALUES('region','source','tech_future',2040,'demand',1.0,NULL); -INSERT INTO efficiency VALUES('region','source','tech_future',2045,'demand',1.0,NULL); -INSERT INTO efficiency VALUES('region','source','tech_future',2050,'demand',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','source','tech_ancient',1994,'demand',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','source','tech_old',2010,'demand',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','source','tech_current',2025,'demand',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','source','tech_future',2030,'demand',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','source','tech_future',2035,'demand',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','source','tech_future',2040,'demand',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','source','tech_future',2045,'demand',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','source','tech_future',2050,'demand',1.0,NULL); CREATE TABLE efficiency_variable ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -371,7 +312,7 @@ CREATE TABLE emission_embodied value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) ); CREATE TABLE emission_end_of_life ( @@ -385,7 +326,21 @@ CREATE TABLE emission_end_of_life value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE end_of_life_output +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); CREATE TABLE existing_capacity ( @@ -399,15 +354,9 @@ CREATE TABLE existing_capacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO existing_capacity VALUES('region','tech_ancient',1994,3.0,NULL,NULL); -INSERT INTO existing_capacity VALUES('region','tech_old',2010,0.7,NULL,NULL); -CREATE TABLE TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE loan_lifetime_process +INSERT INTO "existing_capacity" VALUES('region','tech_ancient',1994,3.0,NULL,NULL); +INSERT INTO "existing_capacity" VALUES('region','tech_old',2010,0.7,NULL,NULL); +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -418,154 +367,255 @@ CREATE TABLE loan_lifetime_process notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE loan_rate +CREATE TABLE lifetime_survival_curve ( - region TEXT, - tech TEXT + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL REFERENCES technology (tech), - vintage INTEGER + vintage INTEGER NOT NULL REFERENCES time_period (period), - rate REAL, + fraction REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE lifetime_process +INSERT INTO "lifetime_survival_curve" VALUES('region',1994,'tech_ancient',1994,1.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',1999,'tech_ancient',1994,0.97,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2004,'tech_ancient',1994,8.80000000000000115e-01,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2009,'tech_ancient',1994,0.62,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2014,'tech_ancient',1994,0.27,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2019,'tech_ancient',1994,0.08,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2029,'tech_ancient',1994,0.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2010,'tech_old',2010,1.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2015,'tech_old',2010,0.97,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2020,'tech_old',2010,8.80000000000000115e-01,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2025,'tech_old',2010,0.62,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2030,'tech_old',2010,0.27,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2035,'tech_old',2010,0.08,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_old',2010,0.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2025,'tech_current',2025,1.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2030,'tech_current',2025,0.97,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2035,'tech_current',2025,8.80000000000000115e-01,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2040,'tech_current',2025,0.62,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_current',2025,0.27,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_current',2025,0.08,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2060,'tech_current',2025,0.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2030,'tech_future',2030,1.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2035,'tech_future',2030,0.97,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2040,'tech_future',2030,8.80000000000000115e-01,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_future',2030,0.62,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2030,0.27,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2030,0.08,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2065,'tech_future',2030,0.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2035,'tech_future',2035,1.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2040,'tech_future',2035,0.97,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_future',2035,8.80000000000000115e-01,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2035,0.62,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2035,0.27,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2060,'tech_future',2035,0.08,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2070,'tech_future',2035,0.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2040,'tech_future',2040,1.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_future',2040,0.97,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2040,8.80000000000000115e-01,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2040,0.62,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2060,'tech_future',2040,0.27,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2065,'tech_future',2040,0.08,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2075,'tech_future',2040,0.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_future',2045,1.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2045,0.97,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2045,8.80000000000000115e-01,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2060,'tech_future',2045,0.62,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2065,'tech_future',2045,0.27,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2070,'tech_future',2045,0.08,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2080,'tech_future',2045,0.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2050,1.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2050,0.97,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2060,'tech_future',2050,8.80000000000000115e-01,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2065,'tech_future',2050,0.62,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2070,'tech_future',2050,0.27,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2075,'tech_future',2050,0.08,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2085,'tech_future',2050,0.0,NULL); +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), lifetime REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, tech) ); -CREATE TABLE lifetime_tech +INSERT INTO "lifetime_tech" VALUES('region','tech_ancient',35.0,NULL); +INSERT INTO "lifetime_tech" VALUES('region','tech_old',35.0,NULL); +INSERT INTO "lifetime_tech" VALUES('region','tech_current',35.0,NULL); +INSERT INTO "lifetime_tech" VALUES('region','tech_future',35.0,NULL); +CREATE TABLE limit_activity ( - region TEXT, - tech TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE limit_activity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_annual_capacity_factor +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator), + CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO lifetime_tech VALUES('region','tech_ancient',35.0,NULL); -INSERT INTO lifetime_tech VALUES('region','tech_old',35.0,NULL); -INSERT INTO lifetime_tech VALUES('region','tech_current',35.0,NULL); -INSERT INTO lifetime_tech VALUES('region','tech_future',35.0,NULL); -CREATE TABLE Operator +CREATE TABLE limit_capacity ( - operator TEXT PRIMARY KEY, - notes TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO Operator VALUES('e','equal to'); -INSERT INTO Operator VALUES('le','less than or equal to'); -INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE limit_growth_capacity +CREATE TABLE limit_capacity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_capacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity +CREATE TABLE limit_emission +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitStorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -CREATE TABLE limit_activity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, + REFERENCES operator (operator), + new_cap REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE limit_activity_share +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -573,105 +623,56 @@ CREATE TABLE limit_activity_share sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), share REAL, notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity +CREATE TABLE limit_resource ( region TEXT, - period INTEGER - REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, + REFERENCES operator (operator), + cum_act REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) + PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_capacity_share +CREATE TABLE limit_seasonal_capacity_factor ( - region TEXT, - period INTEGER + region TEXT + REFERENCES region (region), + period INTEGER REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, + season TEXT + REFERENCES season_label (season), + tech TEXT + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE limit_new_capacity +CREATE TABLE limit_storage_level_fraction ( - region TEXT, - period INTEGER + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), - tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) + REFERENCES operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); CREATE TABLE limit_tech_input_split ( @@ -683,7 +684,7 @@ CREATE TABLE limit_tech_input_split tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -698,7 +699,7 @@ CREATE TABLE limit_tech_input_split_annual tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -713,7 +714,7 @@ CREATE TABLE limit_tech_output_split output_comm TEXT REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) @@ -728,26 +729,12 @@ CREATE TABLE limit_tech_output_split_annual output_comm TEXT REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE LinkedTech +CREATE TABLE linked_tech ( primary_region TEXT, primary_tech TEXT @@ -759,6 +746,103 @@ CREATE TABLE LinkedTech notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); +CREATE TABLE loan_lifetime_process +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE loan_rate +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE metadata +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); +INSERT INTO "metadata" VALUES('DB_MINOR',0,''); +CREATE TABLE metadata_real +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +CREATE TABLE myopic_efficiency +( + base_year integer, + region text, + input_comm text, + tech text, + vintage integer, + output_comm text, + efficiency real, + lifetime integer, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (region, input_comm, tech, vintage, output_comm) +); +CREATE TABLE operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "operator" VALUES('e','equal to'); +INSERT INTO "operator" VALUES('le','less than or equal to'); +INSERT INTO "operator" VALUES('ge','greater than or equal to'); +CREATE TABLE output_built_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE output_cost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) +); CREATE TABLE output_curtailment ( scenario TEXT, @@ -769,7 +853,7 @@ CREATE TABLE output_curtailment season TEXT REFERENCES time_period (period), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -781,62 +865,42 @@ CREATE TABLE output_curtailment curtailment REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputNetCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_built_capacity +CREATE TABLE output_dual_variable ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE output_emission ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), - tech TEXT + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT REFERENCES technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE OutputFlowIn +CREATE TABLE output_flow_in ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -848,18 +912,18 @@ CREATE TABLE OutputFlowIn flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputFlowOut +CREATE TABLE output_flow_out ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -871,18 +935,70 @@ CREATE TABLE OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); +CREATE TABLE output_flow_out_summary +( + scenario TEXT NOT NULL, + region TEXT NOT NULL, + sector TEXT, + period INTEGER, + input_comm TEXT NOT NULL, + tech TEXT NOT NULL, + vintage INTEGER, + output_comm TEXT NOT NULL, + flow REAL NOT NULL, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_net_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_objective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE output_retired_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), vintage INTEGER @@ -922,14 +1038,14 @@ CREATE TABLE region PRIMARY KEY, notes TEXT ); -INSERT INTO region VALUES('region',NULL); +INSERT INTO "region" VALUES('region',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tech TEXT REFERENCES technology (tech), vintage INTEGER, @@ -938,25 +1054,28 @@ CREATE TABLE reserve_capacity_derate PRIMARY KEY (region, period, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE TimeSegmentFraction +CREATE TABLE rps_requirement ( - period INTEGER + region TEXT NOT NULL + REFERENCES region (region), + period INTEGER NOT NULL REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) -); -INSERT INTO TimeSegmentFraction VALUES(2025,'s','d',1.0,NULL); -INSERT INTO TimeSegmentFraction VALUES(2030,'s','d',1.0,NULL); -INSERT INTO TimeSegmentFraction VALUES(2035,'s','d',1.0,NULL); -INSERT INTO TimeSegmentFraction VALUES(2040,'s','d',1.0,NULL); -INSERT INTO TimeSegmentFraction VALUES(2045,'s','d',1.0,NULL); -INSERT INTO TimeSegmentFraction VALUES(2050,'s','d',1.0,NULL); + tech_group TEXT NOT NULL + REFERENCES tech_group (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE season_label +( + season TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "season_label" VALUES('s',NULL); +CREATE TABLE sector_label +( + sector TEXT PRIMARY KEY, + notes TEXT +); CREATE TABLE storage_duration ( region TEXT, @@ -965,220 +1084,149 @@ CREATE TABLE storage_duration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE lifetime_survival_curve +CREATE TABLE tech_group ( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE tech_group_member +( + group_name TEXT + REFERENCES tech_group (group_name), + tech TEXT REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) + PRIMARY KEY (group_name, tech) +); +CREATE TABLE technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES technology_type (label) ); -INSERT INTO lifetime_survival_curve VALUES('region',1994,'tech_ancient',1994,1,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',1999,'tech_ancient',1994,0.96999999999999992894,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2004,'tech_ancient',1994,0.88000000000000007105,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2009,'tech_ancient',1994,0.62000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2014,'tech_ancient',1994,0.27000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2019,'tech_ancient',1994,0.08,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2029,'tech_ancient',1994,0.0,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2010,'tech_old',2010,1,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2015,'tech_old',2010,0.96999999999999992894,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2020,'tech_old',2010,0.88000000000000007105,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2025,'tech_old',2010,0.62000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2030,'tech_old',2010,0.27000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2035,'tech_old',2010,0.08,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_old',2010,0.0,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2025,'tech_current',2025,1,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2030,'tech_current',2025,0.96999999999999992894,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2035,'tech_current',2025,0.88000000000000007105,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2040,'tech_current',2025,0.62000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_current',2025,0.27000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_current',2025,0.08,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2060,'tech_current',2025,0.0,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2030,'tech_future',2030,1,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2035,'tech_future',2030,0.96999999999999992894,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2040,'tech_future',2030,0.88000000000000007105,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_future',2030,0.62000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_future',2030,0.27000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2055,'tech_future',2030,0.08,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2065,'tech_future',2030,0.0,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2035,'tech_future',2035,1,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2040,'tech_future',2035,0.96999999999999992894,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_future',2035,0.88000000000000007105,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_future',2035,0.62000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2055,'tech_future',2035,0.27000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2060,'tech_future',2035,0.08,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2070,'tech_future',2035,0.0,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2040,'tech_future',2040,1,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_future',2040,0.96999999999999992894,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_future',2040,0.88000000000000007105,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2055,'tech_future',2040,0.62000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2060,'tech_future',2040,0.27000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2065,'tech_future',2040,0.08,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2075,'tech_future',2040,0.0,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_future',2045,1,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_future',2045,0.96999999999999992894,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2055,'tech_future',2045,0.88000000000000007105,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2060,'tech_future',2045,0.62000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2065,'tech_future',2045,0.27000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2070,'tech_future',2045,0.08,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2080,'tech_future',2045,0.0,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_future',2050,1,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2055,'tech_future',2050,0.96999999999999992894,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2060,'tech_future',2050,0.88000000000000007105,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2065,'tech_future',2050,0.62000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2070,'tech_future',2050,0.27000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2075,'tech_future',2050,0.08,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2085,'tech_future',2050,0.0,NULL); -CREATE TABLE technologyType +INSERT INTO "technology" VALUES('tech_ancient','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO "technology" VALUES('tech_old','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO "technology" VALUES('tech_current','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO "technology" VALUES('tech_future','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +CREATE TABLE technology_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO technologyType VALUES('p','production technology'); -INSERT INTO technologyType VALUES('pb','baseload production technology'); -INSERT INTO technologyType VALUES('ps','storage production technology'); -CREATE TABLE TimeOfDay +INSERT INTO "technology_type" VALUES('p','production technology'); +INSERT INTO "technology_type" VALUES('pb','baseload production technology'); +INSERT INTO "technology_type" VALUES('ps','storage production technology'); +CREATE TABLE time_of_day ( sequence INTEGER UNIQUE, tod TEXT PRIMARY KEY ); -INSERT INTO TimeOfDay VALUES(0,'d'); +INSERT INTO "time_of_day" VALUES(0,'d'); CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES time_periodType (label) -); -INSERT INTO time_period VALUES(-2,1994,'e'); -INSERT INTO time_period VALUES(-1,2010,'e'); -INSERT INTO time_period VALUES(0,2025,'f'); -INSERT INTO time_period VALUES(1,2030,'f'); -INSERT INTO time_period VALUES(2,2035,'f'); -INSERT INTO time_period VALUES(3,2040,'f'); -INSERT INTO time_period VALUES(4,2045,'f'); -INSERT INTO time_period VALUES(5,2050,'f'); -INSERT INTO time_period VALUES(6,2055,'f'); -CREATE TABLE TimeSeason + REFERENCES time_period_type (label) +); +INSERT INTO "time_period" VALUES(-2,1994,'e'); +INSERT INTO "time_period" VALUES(-1,2010,'e'); +INSERT INTO "time_period" VALUES(0,2025,'f'); +INSERT INTO "time_period" VALUES(1,2030,'f'); +INSERT INTO "time_period" VALUES(2,2035,'f'); +INSERT INTO "time_period" VALUES(3,2040,'f'); +INSERT INTO "time_period" VALUES(4,2045,'f'); +INSERT INTO "time_period" VALUES(5,2050,'f'); +INSERT INTO "time_period" VALUES(6,2055,'f'); +CREATE TABLE time_period_type +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO "time_period_type" VALUES('e','existing vintages'); +INSERT INTO "time_period_type" VALUES('f','future'); +CREATE TABLE time_season +( + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + season TEXT REFERENCES season_label(season), + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +INSERT INTO "time_season" VALUES(2025,0,'s',NULL); +INSERT INTO "time_season" VALUES(2030,1,'s',NULL); +INSERT INTO "time_season" VALUES(2035,2,'s',NULL); +INSERT INTO "time_season" VALUES(2040,3,'s',NULL); +INSERT INTO "time_season" VALUES(2045,4,'s',NULL); +INSERT INTO "time_season" VALUES(2050,5,'s',NULL); +CREATE TABLE time_season_all ( period INTEGER REFERENCES time_period (period), sequence INTEGER, season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); -INSERT INTO TimeSeason VALUES(2025,0,'s',NULL); -INSERT INTO TimeSeason VALUES(2030,1,'s',NULL); -INSERT INTO TimeSeason VALUES(2035,2,'s',NULL); -INSERT INTO TimeSeason VALUES(2040,3,'s',NULL); -INSERT INTO TimeSeason VALUES(2045,4,'s',NULL); -INSERT INTO TimeSeason VALUES(2050,5,'s',NULL); CREATE TABLE time_season_sequential ( - period INTEGER - REFERENCES time_period (period), + period INTEGER REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES SeasonLabel (season), + season TEXT REFERENCES season_label(season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE time_periodType +CREATE TABLE time_season_to_sequential ( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO time_periodType VALUES('e','existing vintages'); -INSERT INTO time_periodType VALUES('f','future'); -CREATE TABLE OutputEmission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER + period INTEGER REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) + sequence INTEGER, + seas_seq TEXT, + season TEXT + REFERENCES season_label (season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) ); -CREATE TABLE RPSRequirement +CREATE TABLE time_segment_fraction ( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL + period INTEGER REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES TechGroup (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE TechGroupMember -( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technologyType (label) -); -INSERT INTO technology VALUES('tech_ancient','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO technology VALUES('tech_old','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO technology VALUES('tech_current','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO technology VALUES('tech_future','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) -); + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + segment_fraction REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) +); +INSERT INTO "time_segment_fraction" VALUES(2025,'s','d',1.0,NULL); +INSERT INTO "time_segment_fraction" VALUES(2030,'s','d',1.0,NULL); +INSERT INTO "time_segment_fraction" VALUES(2035,'s','d',1.0,NULL); +INSERT INTO "time_segment_fraction" VALUES(2040,'s','d',1.0,NULL); +INSERT INTO "time_segment_fraction" VALUES(2045,'s','d',1.0,NULL); +INSERT INTO "time_segment_fraction" VALUES(2050,'s','d',1.0,NULL); +CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 0bf5a797f..c7e9a5f50 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -1,58 +1,4 @@ -PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO metadata VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO metadata VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO metadata VALUES ('days_per_period', 365, 'count of days in each period'); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO metadata_real VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); -INSERT INTO metadata_real VALUES('global_discount_rate',0.05000000000000000277,''); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE SeasonLabel -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SeasonLabel VALUES('summer',NULL); -INSERT INTO SeasonLabel VALUES('fall',NULL); -INSERT INTO SeasonLabel VALUES('winter',NULL); -INSERT INTO SeasonLabel VALUES('spring',NULL); -CREATE TABLE SectorLabel -( - sector TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SectorLabel VALUES('supply',NULL); -INSERT INTO SectorLabel VALUES('electric',NULL); -INSERT INTO SectorLabel VALUES('transport',NULL); -INSERT INTO SectorLabel VALUES('commercial',NULL); -INSERT INTO SectorLabel VALUES('residential',NULL); -INSERT INTO SectorLabel VALUES('industrial',NULL); CREATE TABLE capacity_credit ( region TEXT, @@ -72,9 +18,9 @@ CREATE TABLE capacity_factor_process period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), vintage INTEGER, @@ -89,9 +35,9 @@ CREATE TABLE capacity_factor_tech period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), factor REAL, @@ -99,55 +45,55 @@ CREATE TABLE capacity_factor_tech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO capacity_factor_tech VALUES('R1',2020,'spring','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2020,'spring','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R1',2020,'summer','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2020,'summer','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R1',2020,'fall','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2020,'fall','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R1',2020,'winter','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2020,'winter','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2020,'spring','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2020,'spring','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2020,'summer','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2020,'summer','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2020,'fall','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2020,'fall','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2020,'winter','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2020,'winter','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R1',2025,'spring','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2025,'spring','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R1',2025,'summer','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2025,'summer','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R1',2025,'fall','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2025,'fall','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R1',2025,'winter','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2025,'winter','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2025,'spring','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2025,'spring','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2025,'summer','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2025,'summer','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2025,'fall','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2025,'fall','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2025,'winter','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2025,'winter','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R1',2030,'spring','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2030,'spring','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R1',2030,'summer','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2030,'summer','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R1',2030,'fall','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2030,'fall','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R1',2030,'winter','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2030,'winter','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2030,'spring','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2030,'spring','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2030,'summer','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2030,'summer','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2030,'fall','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2030,'fall','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2030,'winter','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2030,'winter','night','E_SOLPV',0.0,''); -CREATE TABLE CapacityToActivity +INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'spring','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'spring','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'summer','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'summer','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'fall','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'fall','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'winter','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'winter','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'spring','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'spring','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'summer','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'summer','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'fall','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'fall','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'winter','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'winter','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'spring','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'spring','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'summer','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'summer','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'fall','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'fall','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'winter','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'winter','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'spring','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'spring','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'summer','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'summer','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'fall','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'fall','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'winter','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'winter','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'spring','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'spring','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'summer','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'summer','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'fall','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'fall','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'winter','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'winter','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'spring','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'spring','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'summer','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'summer','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'fall','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'fall','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'winter','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'winter','night','E_SOLPV',0.0,''); +CREATE TABLE capacity_to_activity ( region TEXT, tech TEXT @@ -156,73 +102,73 @@ CREATE TABLE CapacityToActivity notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO CapacityToActivity VALUES('R1','S_IMPETH',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1','S_IMPOIL',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1','S_IMPNG',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1','S_IMPURN',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1','S_OILREF',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1','E_NGCC',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R1','E_SOLPV',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R1','E_BATT',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R1','E_NUCLEAR',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R1','T_BLND',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1','T_DSL',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1','T_GSL',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1','T_EV',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1','R_EH',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1','R_NGH',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','S_IMPETH',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','S_IMPOIL',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','S_IMPNG',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','S_IMPURN',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','S_OILREF',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','E_NGCC',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R2','E_SOLPV',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R2','E_BATT',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R2','E_NUCLEAR',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R2','T_BLND',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','T_DSL',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','T_GSL',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','T_EV',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','R_EH',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','R_NGH',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1-R2','E_TRANS',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R2-R1','E_TRANS',31.53999999999999915,''); +INSERT INTO "capacity_to_activity" VALUES('R1','S_IMPETH',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R1','S_IMPOIL',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R1','S_IMPNG',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R1','S_IMPURN',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R1','S_OILREF',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R1','E_NGCC',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('R1','E_SOLPV',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('R1','E_BATT',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('R1','E_NUCLEAR',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('R1','T_BLND',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R1','T_DSL',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R1','T_GSL',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R1','T_EV',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R1','R_EH',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R1','R_NGH',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R2','S_IMPETH',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R2','S_IMPOIL',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R2','S_IMPNG',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R2','S_IMPURN',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R2','S_OILREF',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R2','E_NGCC',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('R2','E_SOLPV',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('R2','E_BATT',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('R2','E_NUCLEAR',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('R2','T_BLND',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R2','T_DSL',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R2','T_GSL',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R2','T_EV',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R2','R_EH',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R2','R_NGH',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R1-R2','E_TRANS',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('R2-R1','E_TRANS',31.54,''); CREATE TABLE commodity ( name TEXT PRIMARY KEY, flag TEXT - REFERENCES commodityType (label), + REFERENCES commodity_type (label), description TEXT ); -INSERT INTO commodity VALUES('ethos','s','dummy commodity to supply inputs (makes graph easier to read)'); -INSERT INTO commodity VALUES('OIL','p','crude oil'); -INSERT INTO commodity VALUES('NG','p','natural gas'); -INSERT INTO commodity VALUES('URN','p','uranium'); -INSERT INTO commodity VALUES('ETH','p','ethanol'); -INSERT INTO commodity VALUES('SOL','p','solar insolation'); -INSERT INTO commodity VALUES('GSL','p','gasoline'); -INSERT INTO commodity VALUES('DSL','p','diesel'); -INSERT INTO commodity VALUES('ELC','p','electricity'); -INSERT INTO commodity VALUES('E10','p','gasoline blend with 10% ethanol'); -INSERT INTO commodity VALUES('VMT','d','travel demand for vehicle-miles traveled'); -INSERT INTO commodity VALUES('RH','d','demand for residential heating'); -INSERT INTO commodity VALUES('CO2','e','CO2 emissions commodity'); -CREATE TABLE commodityType +INSERT INTO "commodity" VALUES('ethos','s','dummy commodity to supply inputs (makes graph easier to read)'); +INSERT INTO "commodity" VALUES('OIL','p','crude oil'); +INSERT INTO "commodity" VALUES('NG','p','natural gas'); +INSERT INTO "commodity" VALUES('URN','p','uranium'); +INSERT INTO "commodity" VALUES('ETH','p','ethanol'); +INSERT INTO "commodity" VALUES('SOL','p','solar insolation'); +INSERT INTO "commodity" VALUES('GSL','p','gasoline'); +INSERT INTO "commodity" VALUES('DSL','p','diesel'); +INSERT INTO "commodity" VALUES('ELC','p','electricity'); +INSERT INTO "commodity" VALUES('E10','p','gasoline blend with 10% ethanol'); +INSERT INTO "commodity" VALUES('VMT','d','travel demand for vehicle-miles traveled'); +INSERT INTO "commodity" VALUES('RH','d','demand for residential heating'); +INSERT INTO "commodity" VALUES('CO2','e','CO2 emissions commodity'); +CREATE TABLE commodity_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO commodityType VALUES('w','waste commodity'); -INSERT INTO commodityType VALUES('wa','waste annual commodity'); -INSERT INTO commodityType VALUES('wp','waste physical commodity'); -INSERT INTO commodityType VALUES('a','annual commodity'); -INSERT INTO commodityType VALUES('s','source commodity'); -INSERT INTO commodityType VALUES('p','physical commodity'); -INSERT INTO commodityType VALUES('e','emissions commodity'); -INSERT INTO commodityType VALUES('d','demand commodity'); +INSERT INTO "commodity_type" VALUES('w','waste commodity'); +INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); +INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); +INSERT INTO "commodity_type" VALUES('a','annual commodity'); +INSERT INTO "commodity_type" VALUES('s','source commodity'); +INSERT INTO "commodity_type" VALUES('p','physical commodity'); +INSERT INTO "commodity_type" VALUES('e','emissions commodity'); +INSERT INTO "commodity_type" VALUES('d','demand commodity'); CREATE TABLE construction_input ( region TEXT, @@ -263,54 +209,54 @@ CREATE TABLE cost_fixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_fixed VALUES('R1',2020,'E_NGCC',2020,30.60000000000000142,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2025,'E_NGCC',2020,9.77999999999999937,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2025,'E_NGCC',2025,9.77999999999999937,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_NGCC',2020,9.77999999999999937,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_NGCC',2025,9.77999999999999937,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_NGCC',2030,9.77999999999999937,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2020,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2025,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2025,'E_SOLPV',2025,9.099999999999999645,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_SOLPV',2025,9.099999999999999645,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_SOLPV',2030,9.099999999999999645,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2020,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2025,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2025,'E_NUCLEAR',2025,98.0999999999999801,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_NUCLEAR',2025,98.0999999999999801,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_NUCLEAR',2030,98.0999999999999801,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2020,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2025,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2025,'E_BATT',2025,7.049999999999999823,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_BATT',2025,7.049999999999999823,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_BATT',2030,7.049999999999999823,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2020,'E_NGCC',2020,24.48000000000000042,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2025,'E_NGCC',2020,7.823999999999999844,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2025,'E_NGCC',2025,7.823999999999999844,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_NGCC',2020,7.823999999999999844,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_NGCC',2025,7.823999999999999844,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_NGCC',2030,7.823999999999999844,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2020,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2025,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2025,'E_SOLPV',2025,7.280000000000000248,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_SOLPV',2025,7.280000000000000248,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_SOLPV',2030,7.280000000000000248,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2020,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2025,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2025,'E_NUCLEAR',2025,78.48000000000000397,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_NUCLEAR',2025,78.48000000000000397,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_NUCLEAR',2030,78.48000000000000397,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2020,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2025,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2025,'E_BATT',2025,5.639999999999999681,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_BATT',2025,5.639999999999999681,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_BATT',2030,5.639999999999999681,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2020,'E_NGCC',2020,30.6,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2025,'E_NGCC',2020,9.78,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2025,'E_NGCC',2025,9.78,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NGCC',2020,9.78,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NGCC',2025,9.78,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NGCC',2030,9.78,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2020,'E_SOLPV',2020,10.4,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2025,'E_SOLPV',2020,10.4,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2025,'E_SOLPV',2025,9.1,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_SOLPV',2020,10.4,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_SOLPV',2025,9.1,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_SOLPV',2030,9.1,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2020,'E_NUCLEAR',2020,9.809999999999998e+01,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2025,'E_NUCLEAR',2020,9.809999999999998e+01,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2025,'E_NUCLEAR',2025,9.809999999999998e+01,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NUCLEAR',2020,9.809999999999998e+01,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NUCLEAR',2025,9.809999999999998e+01,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NUCLEAR',2030,9.809999999999998e+01,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2020,'E_BATT',2020,7.05,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2025,'E_BATT',2020,7.05,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2025,'E_BATT',2025,7.05,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_BATT',2020,7.05,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_BATT',2025,7.05,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_BATT',2030,7.05,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2020,'E_NGCC',2020,24.48,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2025,'E_NGCC',2020,7.824,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2025,'E_NGCC',2025,7.824,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NGCC',2020,7.824,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NGCC',2025,7.824,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NGCC',2030,7.824,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2020,'E_SOLPV',2020,8.32,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2025,'E_SOLPV',2020,8.32,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2025,'E_SOLPV',2025,7.28,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_SOLPV',2020,8.32,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_SOLPV',2025,7.28,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_SOLPV',2030,7.28,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2020,'E_NUCLEAR',2020,78.48,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2025,'E_NUCLEAR',2020,78.48,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2025,'E_NUCLEAR',2025,78.48,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NUCLEAR',2020,78.48,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NUCLEAR',2025,78.48,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NUCLEAR',2030,78.48,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2020,'E_BATT',2020,5.64,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2025,'E_BATT',2020,5.64,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2025,'E_BATT',2025,5.64,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_BATT',2020,5.64,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_BATT',2025,5.64,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_BATT',2030,5.64,'$M/GWyr',''); CREATE TABLE cost_invest ( region TEXT, @@ -323,60 +269,60 @@ CREATE TABLE cost_invest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO cost_invest VALUES('R1','E_NGCC',2020,1050.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','E_NGCC',2025,1025.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','E_NGCC',2030,1000.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','E_SOLPV',2020,900.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','E_SOLPV',2025,560.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','E_SOLPV',2030,800.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','E_NUCLEAR',2020,6145.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','E_NUCLEAR',2025,6045.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','E_NUCLEAR',2030,5890.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','E_BATT',2020,1150.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','E_BATT',2025,720.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','E_BATT',2030,480.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','T_GSL',2020,2570.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R1','T_GSL',2025,2700.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R1','T_GSL',2030,2700.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R1','T_DSL',2020,2715.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R1','T_DSL',2025,2810.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R1','T_DSL',2030,2810.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R1','T_EV',2020,3100.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R1','T_EV',2025,3030.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R1','T_EV',2030,2925.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R1','R_EH',2020,4.099999999999999644,'$/PJ/yr',''); -INSERT INTO cost_invest VALUES('R1','R_EH',2025,4.099999999999999644,'$/PJ/yr',''); -INSERT INTO cost_invest VALUES('R1','R_EH',2030,4.099999999999999644,'$/PJ/yr',''); -INSERT INTO cost_invest VALUES('R1','R_NGH',2020,7.599999999999999645,'$/PJ/yr',''); -INSERT INTO cost_invest VALUES('R1','R_NGH',2025,7.599999999999999645,'$/PJ/yr',''); -INSERT INTO cost_invest VALUES('R1','R_NGH',2030,7.599999999999999645,'$/PJ/yr',''); -INSERT INTO cost_invest VALUES('R2','E_NGCC',2020,840.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','E_NGCC',2025,820.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','E_NGCC',2030,800.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','E_SOLPV',2020,720.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','E_SOLPV',2025,448.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','E_SOLPV',2030,640.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','E_NUCLEAR',2020,4916.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','E_NUCLEAR',2025,4836.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','E_NUCLEAR',2030,4712.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','E_BATT',2020,920.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','E_BATT',2025,576.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','E_BATT',2030,384.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','T_GSL',2020,2056.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R2','T_GSL',2025,2160.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R2','T_GSL',2030,2160.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R2','T_DSL',2020,2172.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R2','T_DSL',2025,2248.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R2','T_DSL',2030,2248.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R2','T_EV',2020,2480.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R2','T_EV',2025,2424.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R2','T_EV',2030,2340.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R2','R_EH',2020,3.279999999999999805,'$/PJ/yr',''); -INSERT INTO cost_invest VALUES('R2','R_EH',2025,3.279999999999999805,'$/PJ/yr',''); -INSERT INTO cost_invest VALUES('R2','R_EH',2030,3.279999999999999805,'$/PJ/yr',''); -INSERT INTO cost_invest VALUES('R2','R_NGH',2020,6.080000000000000071,'$/PJ/yr',''); -INSERT INTO cost_invest VALUES('R2','R_NGH',2025,6.080000000000000071,'$/PJ/yr',''); -INSERT INTO cost_invest VALUES('R2','R_NGH',2030,6.080000000000000071,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R1','E_NGCC',2020,1050.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','E_NGCC',2025,1025.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','E_NGCC',2030,1000.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','E_SOLPV',2020,900.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','E_SOLPV',2025,560.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','E_SOLPV',2030,800.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','E_NUCLEAR',2020,6145.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','E_NUCLEAR',2025,6045.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','E_NUCLEAR',2030,5890.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','E_BATT',2020,1150.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','E_BATT',2025,720.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','E_BATT',2030,480.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','T_GSL',2020,2570.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R1','T_GSL',2025,2700.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R1','T_GSL',2030,2700.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R1','T_DSL',2020,2715.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R1','T_DSL',2025,2810.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R1','T_DSL',2030,2810.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R1','T_EV',2020,3100.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R1','T_EV',2025,3030.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R1','T_EV',2030,2925.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R1','R_EH',2020,4.1,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R1','R_EH',2025,4.1,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R1','R_EH',2030,4.1,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R1','R_NGH',2020,7.6,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R1','R_NGH',2025,7.6,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R1','R_NGH',2030,7.6,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R2','E_NGCC',2020,840.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','E_NGCC',2025,820.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','E_NGCC',2030,800.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','E_SOLPV',2020,720.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','E_SOLPV',2025,448.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','E_SOLPV',2030,640.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','E_NUCLEAR',2020,4916.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','E_NUCLEAR',2025,4836.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','E_NUCLEAR',2030,4712.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','E_BATT',2020,920.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','E_BATT',2025,576.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','E_BATT',2030,384.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','T_GSL',2020,2056.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R2','T_GSL',2025,2160.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R2','T_GSL',2030,2160.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R2','T_DSL',2020,2172.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R2','T_DSL',2025,2248.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R2','T_DSL',2030,2248.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R2','T_EV',2020,2480.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R2','T_EV',2025,2424.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R2','T_EV',2030,2340.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R2','R_EH',2020,3.28,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R2','R_EH',2025,3.28,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R2','R_EH',2030,3.28,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R2','R_NGH',2020,6.08,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R2','R_NGH',2025,6.08,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R2','R_NGH',2030,6.08,'$/PJ/yr',''); CREATE TABLE cost_variable ( region TEXT NOT NULL, @@ -391,60 +337,60 @@ CREATE TABLE cost_variable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_variable VALUES('R1',2020,'S_IMPETH',2020,32.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2025,'S_IMPETH',2020,32.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2030,'S_IMPETH',2020,32.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2020,'S_IMPOIL',2020,20.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2025,'S_IMPOIL',2020,20.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2030,'S_IMPOIL',2020,20.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2020,'S_IMPNG',2020,4.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2025,'S_IMPNG',2020,4.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2030,'S_IMPNG',2020,4.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2020,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2025,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2030,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2020,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2025,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2025,'E_NGCC',2025,1.699999999999999956,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2030,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2030,'E_NGCC',2025,1.699999999999999956,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2030,'E_NGCC',2030,1.800000000000000044,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2020,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2025,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2025,'E_NUCLEAR',2025,0.25,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2030,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2030,'E_NUCLEAR',2025,0.25,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2030,'E_NUCLEAR',2030,0.2600000000000000088,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2020,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2025,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2030,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2020,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2025,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2030,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2020,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2025,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2030,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2020,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2025,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2030,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2020,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2025,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2025,'E_NGCC',2025,1.360000000000000097,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2030,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2030,'E_NGCC',2025,1.360000000000000097,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2030,'E_NGCC',2030,1.439999999999999947,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2020,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2025,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2025,'E_NUCLEAR',2025,0.2000000000000000111,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2030,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2030,'E_NUCLEAR',2025,0.2000000000000000111,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2030,'E_NUCLEAR',2030,0.2080000000000000183,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1-R2',2020,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1-R2',2025,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1-R2',2030,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2-R1',2020,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2-R1',2025,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2-R1',2030,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2020,'S_IMPETH',2020,32.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2025,'S_IMPETH',2020,32.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2030,'S_IMPETH',2020,32.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2020,'S_IMPOIL',2020,20.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2025,'S_IMPOIL',2020,20.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2030,'S_IMPOIL',2020,20.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2020,'S_IMPNG',2020,4.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2025,'S_IMPNG',2020,4.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2030,'S_IMPNG',2020,4.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2020,'S_OILREF',2020,1.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2025,'S_OILREF',2020,1.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2030,'S_OILREF',2020,1.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2020,'E_NGCC',2020,1.6,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2025,'E_NGCC',2020,1.6,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2025,'E_NGCC',2025,1.7,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2030,'E_NGCC',2020,1.6,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2030,'E_NGCC',2025,1.7,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2030,'E_NGCC',2030,1.8,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2020,'E_NUCLEAR',2020,0.24,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2025,'E_NUCLEAR',2020,0.24,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2025,'E_NUCLEAR',2025,0.25,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2030,'E_NUCLEAR',2020,0.24,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2030,'E_NUCLEAR',2025,0.25,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2030,'E_NUCLEAR',2030,0.26,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2020,'S_IMPETH',2020,25.6,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2025,'S_IMPETH',2020,25.6,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2030,'S_IMPETH',2020,25.6,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2020,'S_IMPOIL',2020,16.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2025,'S_IMPOIL',2020,16.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2030,'S_IMPOIL',2020,16.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2020,'S_IMPNG',2020,3.2,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2025,'S_IMPNG',2020,3.2,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2030,'S_IMPNG',2020,3.2,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2020,'S_OILREF',2020,0.8,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2025,'S_OILREF',2020,0.8,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2030,'S_OILREF',2020,0.8,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2020,'E_NGCC',2020,1.28,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2025,'E_NGCC',2020,1.28,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2025,'E_NGCC',2025,1.36,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2030,'E_NGCC',2020,1.28,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2030,'E_NGCC',2025,1.36,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2030,'E_NGCC',2030,1.44,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2020,'E_NUCLEAR',2020,0.192,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2025,'E_NUCLEAR',2020,0.192,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2025,'E_NUCLEAR',2025,0.2,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2030,'E_NUCLEAR',2020,0.192,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2030,'E_NUCLEAR',2025,0.2,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2030,'E_NUCLEAR',2030,2.08000000000000018e-01,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1-R2',2020,'E_TRANS',2015,0.1,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1-R2',2025,'E_TRANS',2015,0.1,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1-R2',2030,'E_TRANS',2015,0.1,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2-R1',2020,'E_TRANS',2015,0.1,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2-R1',2025,'E_TRANS',2015,0.1,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2-R1',2030,'E_TRANS',2015,0.1,'$M/PJ',''); CREATE TABLE demand ( region TEXT, @@ -457,27 +403,27 @@ CREATE TABLE demand notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO demand VALUES('R1',2020,'RH',30.0,'',''); -INSERT INTO demand VALUES('R1',2025,'RH',33.0,'',''); -INSERT INTO demand VALUES('R1',2030,'RH',36.0,'',''); -INSERT INTO demand VALUES('R1',2020,'VMT',84.0,'',''); -INSERT INTO demand VALUES('R1',2025,'VMT',91.0,'',''); -INSERT INTO demand VALUES('R1',2030,'VMT',98.0,'',''); -INSERT INTO demand VALUES('R2',2020,'RH',70.0,'',''); -INSERT INTO demand VALUES('R2',2025,'RH',77.0,'',''); -INSERT INTO demand VALUES('R2',2030,'RH',84.0,'',''); -INSERT INTO demand VALUES('R2',2020,'VMT',36.0,'',''); -INSERT INTO demand VALUES('R2',2025,'VMT',39.0,'',''); -INSERT INTO demand VALUES('R2',2030,'VMT',42.0,'',''); +INSERT INTO "demand" VALUES('R1',2020,'RH',30.0,'',''); +INSERT INTO "demand" VALUES('R1',2025,'RH',33.0,'',''); +INSERT INTO "demand" VALUES('R1',2030,'RH',36.0,'',''); +INSERT INTO "demand" VALUES('R1',2020,'VMT',84.0,'',''); +INSERT INTO "demand" VALUES('R1',2025,'VMT',91.0,'',''); +INSERT INTO "demand" VALUES('R1',2030,'VMT',98.0,'',''); +INSERT INTO "demand" VALUES('R2',2020,'RH',70.0,'',''); +INSERT INTO "demand" VALUES('R2',2025,'RH',77.0,'',''); +INSERT INTO "demand" VALUES('R2',2030,'RH',84.0,'',''); +INSERT INTO "demand" VALUES('R2',2020,'VMT',36.0,'',''); +INSERT INTO "demand" VALUES('R2',2025,'VMT',39.0,'',''); +INSERT INTO "demand" VALUES('R2',2030,'VMT',42.0,'',''); CREATE TABLE demand_specific_distribution ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), demand_name TEXT REFERENCES commodity (name), dsd REAL, @@ -485,68 +431,54 @@ CREATE TABLE demand_specific_distribution PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO demand_specific_distribution VALUES('R1',2020,'spring','day','RH',0.05000000000000000277,''); -INSERT INTO demand_specific_distribution VALUES('R1',2020,'spring','night','RH',0.1000000000000000055,''); -INSERT INTO demand_specific_distribution VALUES('R1',2020,'summer','day','RH',0.0,''); -INSERT INTO demand_specific_distribution VALUES('R1',2020,'summer','night','RH',0.0,''); -INSERT INTO demand_specific_distribution VALUES('R1',2020,'fall','day','RH',0.05000000000000000277,''); -INSERT INTO demand_specific_distribution VALUES('R1',2020,'fall','night','RH',0.1000000000000000055,''); -INSERT INTO demand_specific_distribution VALUES('R1',2020,'winter','day','RH',0.2999999999999999889,''); -INSERT INTO demand_specific_distribution VALUES('R1',2020,'winter','night','RH',0.4000000000000000222,''); -INSERT INTO demand_specific_distribution VALUES('R2',2020,'spring','day','RH',0.05000000000000000277,''); -INSERT INTO demand_specific_distribution VALUES('R2',2020,'spring','night','RH',0.1000000000000000055,''); -INSERT INTO demand_specific_distribution VALUES('R2',2020,'summer','day','RH',0.0,''); -INSERT INTO demand_specific_distribution VALUES('R2',2020,'summer','night','RH',0.0,''); -INSERT INTO demand_specific_distribution VALUES('R2',2020,'fall','day','RH',0.05000000000000000277,''); -INSERT INTO demand_specific_distribution VALUES('R2',2020,'fall','night','RH',0.1000000000000000055,''); -INSERT INTO demand_specific_distribution VALUES('R2',2020,'winter','day','RH',0.2999999999999999889,''); -INSERT INTO demand_specific_distribution VALUES('R2',2020,'winter','night','RH',0.4000000000000000222,''); -INSERT INTO demand_specific_distribution VALUES('R1',2025,'spring','day','RH',0.05000000000000000277,''); -INSERT INTO demand_specific_distribution VALUES('R1',2025,'spring','night','RH',0.1000000000000000055,''); -INSERT INTO demand_specific_distribution VALUES('R1',2025,'summer','day','RH',0.0,''); -INSERT INTO demand_specific_distribution VALUES('R1',2025,'summer','night','RH',0.0,''); -INSERT INTO demand_specific_distribution VALUES('R1',2025,'fall','day','RH',0.05000000000000000277,''); -INSERT INTO demand_specific_distribution VALUES('R1',2025,'fall','night','RH',0.1000000000000000055,''); -INSERT INTO demand_specific_distribution VALUES('R1',2025,'winter','day','RH',0.2999999999999999889,''); -INSERT INTO demand_specific_distribution VALUES('R1',2025,'winter','night','RH',0.4000000000000000222,''); -INSERT INTO demand_specific_distribution VALUES('R2',2025,'spring','day','RH',0.05000000000000000277,''); -INSERT INTO demand_specific_distribution VALUES('R2',2025,'spring','night','RH',0.1000000000000000055,''); -INSERT INTO demand_specific_distribution VALUES('R2',2025,'summer','day','RH',0.0,''); -INSERT INTO demand_specific_distribution VALUES('R2',2025,'summer','night','RH',0.0,''); -INSERT INTO demand_specific_distribution VALUES('R2',2025,'fall','day','RH',0.05000000000000000277,''); -INSERT INTO demand_specific_distribution VALUES('R2',2025,'fall','night','RH',0.1000000000000000055,''); -INSERT INTO demand_specific_distribution VALUES('R2',2025,'winter','day','RH',0.2999999999999999889,''); -INSERT INTO demand_specific_distribution VALUES('R2',2025,'winter','night','RH',0.4000000000000000222,''); -INSERT INTO demand_specific_distribution VALUES('R1',2030,'spring','day','RH',0.05000000000000000277,''); -INSERT INTO demand_specific_distribution VALUES('R1',2030,'spring','night','RH',0.1000000000000000055,''); -INSERT INTO demand_specific_distribution VALUES('R1',2030,'summer','day','RH',0.0,''); -INSERT INTO demand_specific_distribution VALUES('R1',2030,'summer','night','RH',0.0,''); -INSERT INTO demand_specific_distribution VALUES('R1',2030,'fall','day','RH',0.05000000000000000277,''); -INSERT INTO demand_specific_distribution VALUES('R1',2030,'fall','night','RH',0.1000000000000000055,''); -INSERT INTO demand_specific_distribution VALUES('R1',2030,'winter','day','RH',0.2999999999999999889,''); -INSERT INTO demand_specific_distribution VALUES('R1',2030,'winter','night','RH',0.4000000000000000222,''); -INSERT INTO demand_specific_distribution VALUES('R2',2030,'spring','day','RH',0.05000000000000000277,''); -INSERT INTO demand_specific_distribution VALUES('R2',2030,'spring','night','RH',0.1000000000000000055,''); -INSERT INTO demand_specific_distribution VALUES('R2',2030,'summer','day','RH',0.0,''); -INSERT INTO demand_specific_distribution VALUES('R2',2030,'summer','night','RH',0.0,''); -INSERT INTO demand_specific_distribution VALUES('R2',2030,'fall','day','RH',0.05000000000000000277,''); -INSERT INTO demand_specific_distribution VALUES('R2',2030,'fall','night','RH',0.1000000000000000055,''); -INSERT INTO demand_specific_distribution VALUES('R2',2030,'winter','day','RH',0.2999999999999999889,''); -INSERT INTO demand_specific_distribution VALUES('R2',2030,'winter','night','RH',0.4000000000000000222,''); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); +INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'spring','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'spring','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'summer','day','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'summer','night','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'fall','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'fall','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'winter','day','RH',0.3,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'winter','night','RH',0.4,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'spring','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'spring','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'summer','day','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'summer','night','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'fall','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'fall','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'winter','day','RH',0.3,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'winter','night','RH',0.4,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'spring','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'spring','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'summer','day','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'summer','night','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'fall','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'fall','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'winter','day','RH',0.3,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'winter','night','RH',0.4,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'spring','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'spring','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'summer','day','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'summer','night','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'fall','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'fall','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'winter','day','RH',0.3,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'winter','night','RH',0.4,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'spring','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'spring','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'summer','day','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'summer','night','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'fall','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'fall','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'winter','day','RH',0.3,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'winter','night','RH',0.4,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'spring','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'spring','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'summer','day','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'summer','night','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'fall','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'fall','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'winter','day','RH',0.3,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'winter','night','RH',0.4,''); CREATE TABLE efficiency ( region TEXT, @@ -563,89 +495,89 @@ CREATE TABLE efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO efficiency VALUES('R1','ethos','S_IMPETH',2020,'ETH',1.0,''); -INSERT INTO efficiency VALUES('R1','ethos','S_IMPOIL',2020,'OIL',1.0,''); -INSERT INTO efficiency VALUES('R1','ethos','S_IMPNG',2020,'NG',1.0,''); -INSERT INTO efficiency VALUES('R1','ethos','S_IMPURN',2020,'URN',1.0,''); -INSERT INTO efficiency VALUES('R1','OIL','S_OILREF',2020,'GSL',1.0,''); -INSERT INTO efficiency VALUES('R1','OIL','S_OILREF',2020,'DSL',1.0,''); -INSERT INTO efficiency VALUES('R1','ETH','T_BLND',2020,'E10',1.0,''); -INSERT INTO efficiency VALUES('R1','GSL','T_BLND',2020,'E10',1.0,''); -INSERT INTO efficiency VALUES('R1','NG','E_NGCC',2020,'ELC',0.5500000000000000444,''); -INSERT INTO efficiency VALUES('R1','NG','E_NGCC',2025,'ELC',0.5500000000000000444,''); -INSERT INTO efficiency VALUES('R1','NG','E_NGCC',2030,'ELC',0.5500000000000000444,''); -INSERT INTO efficiency VALUES('R1','SOL','E_SOLPV',2020,'ELC',1.0,''); -INSERT INTO efficiency VALUES('R1','SOL','E_SOLPV',2025,'ELC',1.0,''); -INSERT INTO efficiency VALUES('R1','SOL','E_SOLPV',2030,'ELC',1.0,''); -INSERT INTO efficiency VALUES('R1','URN','E_NUCLEAR',2015,'ELC',0.4000000000000000222,''); -INSERT INTO efficiency VALUES('R1','URN','E_NUCLEAR',2020,'ELC',0.4000000000000000222,''); -INSERT INTO efficiency VALUES('R1','URN','E_NUCLEAR',2025,'ELC',0.4000000000000000222,''); -INSERT INTO efficiency VALUES('R1','URN','E_NUCLEAR',2030,'ELC',0.4000000000000000222,''); -INSERT INTO efficiency VALUES('R1','ELC','E_BATT',2020,'ELC',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R1','ELC','E_BATT',2025,'ELC',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R1','ELC','E_BATT',2030,'ELC',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R1','E10','T_GSL',2020,'VMT',0.25,''); -INSERT INTO efficiency VALUES('R1','E10','T_GSL',2025,'VMT',0.25,''); -INSERT INTO efficiency VALUES('R1','E10','T_GSL',2030,'VMT',0.25,''); -INSERT INTO efficiency VALUES('R1','DSL','T_DSL',2020,'VMT',0.2999999999999999889,''); -INSERT INTO efficiency VALUES('R1','DSL','T_DSL',2025,'VMT',0.2999999999999999889,''); -INSERT INTO efficiency VALUES('R1','DSL','T_DSL',2030,'VMT',0.2999999999999999889,''); -INSERT INTO efficiency VALUES('R1','ELC','T_EV',2020,'VMT',0.8900000000000000133,''); -INSERT INTO efficiency VALUES('R1','ELC','T_EV',2025,'VMT',0.8900000000000000133,''); -INSERT INTO efficiency VALUES('R1','ELC','T_EV',2030,'VMT',0.8900000000000000133,''); -INSERT INTO efficiency VALUES('R1','ELC','R_EH',2020,'RH',1.0,''); -INSERT INTO efficiency VALUES('R1','ELC','R_EH',2025,'RH',1.0,''); -INSERT INTO efficiency VALUES('R1','ELC','R_EH',2030,'RH',1.0,''); -INSERT INTO efficiency VALUES('R1','NG','R_NGH',2020,'RH',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R1','NG','R_NGH',2025,'RH',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R1','NG','R_NGH',2030,'RH',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R2','ethos','S_IMPETH',2020,'ETH',1.0,''); -INSERT INTO efficiency VALUES('R2','ethos','S_IMPOIL',2020,'OIL',1.0,''); -INSERT INTO efficiency VALUES('R2','ethos','S_IMPNG',2020,'NG',1.0,''); -INSERT INTO efficiency VALUES('R2','ethos','S_IMPURN',2020,'URN',1.0,''); -INSERT INTO efficiency VALUES('R2','OIL','S_OILREF',2020,'GSL',1.0,''); -INSERT INTO efficiency VALUES('R2','OIL','S_OILREF',2020,'DSL',1.0,''); -INSERT INTO efficiency VALUES('R2','ETH','T_BLND',2020,'E10',1.0,''); -INSERT INTO efficiency VALUES('R2','GSL','T_BLND',2020,'E10',1.0,''); -INSERT INTO efficiency VALUES('R2','NG','E_NGCC',2020,'ELC',0.5500000000000000444,''); -INSERT INTO efficiency VALUES('R2','NG','E_NGCC',2025,'ELC',0.5500000000000000444,''); -INSERT INTO efficiency VALUES('R2','NG','E_NGCC',2030,'ELC',0.5500000000000000444,''); -INSERT INTO efficiency VALUES('R2','SOL','E_SOLPV',2020,'ELC',1.0,''); -INSERT INTO efficiency VALUES('R2','SOL','E_SOLPV',2025,'ELC',1.0,''); -INSERT INTO efficiency VALUES('R2','SOL','E_SOLPV',2030,'ELC',1.0,''); -INSERT INTO efficiency VALUES('R2','URN','E_NUCLEAR',2015,'ELC',0.4000000000000000222,''); -INSERT INTO efficiency VALUES('R2','URN','E_NUCLEAR',2020,'ELC',0.4000000000000000222,''); -INSERT INTO efficiency VALUES('R2','URN','E_NUCLEAR',2025,'ELC',0.4000000000000000222,''); -INSERT INTO efficiency VALUES('R2','URN','E_NUCLEAR',2030,'ELC',0.4000000000000000222,''); -INSERT INTO efficiency VALUES('R2','ELC','E_BATT',2020,'ELC',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R2','ELC','E_BATT',2025,'ELC',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R2','ELC','E_BATT',2030,'ELC',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R2','E10','T_GSL',2020,'VMT',0.25,''); -INSERT INTO efficiency VALUES('R2','E10','T_GSL',2025,'VMT',0.25,''); -INSERT INTO efficiency VALUES('R2','E10','T_GSL',2030,'VMT',0.25,''); -INSERT INTO efficiency VALUES('R2','DSL','T_DSL',2020,'VMT',0.2999999999999999889,''); -INSERT INTO efficiency VALUES('R2','DSL','T_DSL',2025,'VMT',0.2999999999999999889,''); -INSERT INTO efficiency VALUES('R2','DSL','T_DSL',2030,'VMT',0.2999999999999999889,''); -INSERT INTO efficiency VALUES('R2','ELC','T_EV',2020,'VMT',0.8900000000000000133,''); -INSERT INTO efficiency VALUES('R2','ELC','T_EV',2025,'VMT',0.8900000000000000133,''); -INSERT INTO efficiency VALUES('R2','ELC','T_EV',2030,'VMT',0.8900000000000000133,''); -INSERT INTO efficiency VALUES('R2','ELC','R_EH',2020,'RH',1.0,''); -INSERT INTO efficiency VALUES('R2','ELC','R_EH',2025,'RH',1.0,''); -INSERT INTO efficiency VALUES('R2','ELC','R_EH',2030,'RH',1.0,''); -INSERT INTO efficiency VALUES('R2','NG','R_NGH',2020,'RH',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R2','NG','R_NGH',2025,'RH',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R2','NG','R_NGH',2030,'RH',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R1-R2','ELC','E_TRANS',2015,'ELC',0.9000000000000000222,''); -INSERT INTO efficiency VALUES('R2-R1','ELC','E_TRANS',2015,'ELC',0.9000000000000000222,''); +INSERT INTO "efficiency" VALUES('R1','ethos','S_IMPETH',2020,'ETH',1.0,''); +INSERT INTO "efficiency" VALUES('R1','ethos','S_IMPOIL',2020,'OIL',1.0,''); +INSERT INTO "efficiency" VALUES('R1','ethos','S_IMPNG',2020,'NG',1.0,''); +INSERT INTO "efficiency" VALUES('R1','ethos','S_IMPURN',2020,'URN',1.0,''); +INSERT INTO "efficiency" VALUES('R1','OIL','S_OILREF',2020,'GSL',1.0,''); +INSERT INTO "efficiency" VALUES('R1','OIL','S_OILREF',2020,'DSL',1.0,''); +INSERT INTO "efficiency" VALUES('R1','ETH','T_BLND',2020,'E10',1.0,''); +INSERT INTO "efficiency" VALUES('R1','GSL','T_BLND',2020,'E10',1.0,''); +INSERT INTO "efficiency" VALUES('R1','NG','E_NGCC',2020,'ELC',0.55,''); +INSERT INTO "efficiency" VALUES('R1','NG','E_NGCC',2025,'ELC',0.55,''); +INSERT INTO "efficiency" VALUES('R1','NG','E_NGCC',2030,'ELC',0.55,''); +INSERT INTO "efficiency" VALUES('R1','SOL','E_SOLPV',2020,'ELC',1.0,''); +INSERT INTO "efficiency" VALUES('R1','SOL','E_SOLPV',2025,'ELC',1.0,''); +INSERT INTO "efficiency" VALUES('R1','SOL','E_SOLPV',2030,'ELC',1.0,''); +INSERT INTO "efficiency" VALUES('R1','URN','E_NUCLEAR',2015,'ELC',0.4,''); +INSERT INTO "efficiency" VALUES('R1','URN','E_NUCLEAR',2020,'ELC',0.4,''); +INSERT INTO "efficiency" VALUES('R1','URN','E_NUCLEAR',2025,'ELC',0.4,''); +INSERT INTO "efficiency" VALUES('R1','URN','E_NUCLEAR',2030,'ELC',0.4,''); +INSERT INTO "efficiency" VALUES('R1','ELC','E_BATT',2020,'ELC',0.85,''); +INSERT INTO "efficiency" VALUES('R1','ELC','E_BATT',2025,'ELC',0.85,''); +INSERT INTO "efficiency" VALUES('R1','ELC','E_BATT',2030,'ELC',0.85,''); +INSERT INTO "efficiency" VALUES('R1','E10','T_GSL',2020,'VMT',0.25,''); +INSERT INTO "efficiency" VALUES('R1','E10','T_GSL',2025,'VMT',0.25,''); +INSERT INTO "efficiency" VALUES('R1','E10','T_GSL',2030,'VMT',0.25,''); +INSERT INTO "efficiency" VALUES('R1','DSL','T_DSL',2020,'VMT',0.3,''); +INSERT INTO "efficiency" VALUES('R1','DSL','T_DSL',2025,'VMT',0.3,''); +INSERT INTO "efficiency" VALUES('R1','DSL','T_DSL',2030,'VMT',0.3,''); +INSERT INTO "efficiency" VALUES('R1','ELC','T_EV',2020,'VMT',0.89,''); +INSERT INTO "efficiency" VALUES('R1','ELC','T_EV',2025,'VMT',0.89,''); +INSERT INTO "efficiency" VALUES('R1','ELC','T_EV',2030,'VMT',0.89,''); +INSERT INTO "efficiency" VALUES('R1','ELC','R_EH',2020,'RH',1.0,''); +INSERT INTO "efficiency" VALUES('R1','ELC','R_EH',2025,'RH',1.0,''); +INSERT INTO "efficiency" VALUES('R1','ELC','R_EH',2030,'RH',1.0,''); +INSERT INTO "efficiency" VALUES('R1','NG','R_NGH',2020,'RH',0.85,''); +INSERT INTO "efficiency" VALUES('R1','NG','R_NGH',2025,'RH',0.85,''); +INSERT INTO "efficiency" VALUES('R1','NG','R_NGH',2030,'RH',0.85,''); +INSERT INTO "efficiency" VALUES('R2','ethos','S_IMPETH',2020,'ETH',1.0,''); +INSERT INTO "efficiency" VALUES('R2','ethos','S_IMPOIL',2020,'OIL',1.0,''); +INSERT INTO "efficiency" VALUES('R2','ethos','S_IMPNG',2020,'NG',1.0,''); +INSERT INTO "efficiency" VALUES('R2','ethos','S_IMPURN',2020,'URN',1.0,''); +INSERT INTO "efficiency" VALUES('R2','OIL','S_OILREF',2020,'GSL',1.0,''); +INSERT INTO "efficiency" VALUES('R2','OIL','S_OILREF',2020,'DSL',1.0,''); +INSERT INTO "efficiency" VALUES('R2','ETH','T_BLND',2020,'E10',1.0,''); +INSERT INTO "efficiency" VALUES('R2','GSL','T_BLND',2020,'E10',1.0,''); +INSERT INTO "efficiency" VALUES('R2','NG','E_NGCC',2020,'ELC',0.55,''); +INSERT INTO "efficiency" VALUES('R2','NG','E_NGCC',2025,'ELC',0.55,''); +INSERT INTO "efficiency" VALUES('R2','NG','E_NGCC',2030,'ELC',0.55,''); +INSERT INTO "efficiency" VALUES('R2','SOL','E_SOLPV',2020,'ELC',1.0,''); +INSERT INTO "efficiency" VALUES('R2','SOL','E_SOLPV',2025,'ELC',1.0,''); +INSERT INTO "efficiency" VALUES('R2','SOL','E_SOLPV',2030,'ELC',1.0,''); +INSERT INTO "efficiency" VALUES('R2','URN','E_NUCLEAR',2015,'ELC',0.4,''); +INSERT INTO "efficiency" VALUES('R2','URN','E_NUCLEAR',2020,'ELC',0.4,''); +INSERT INTO "efficiency" VALUES('R2','URN','E_NUCLEAR',2025,'ELC',0.4,''); +INSERT INTO "efficiency" VALUES('R2','URN','E_NUCLEAR',2030,'ELC',0.4,''); +INSERT INTO "efficiency" VALUES('R2','ELC','E_BATT',2020,'ELC',0.85,''); +INSERT INTO "efficiency" VALUES('R2','ELC','E_BATT',2025,'ELC',0.85,''); +INSERT INTO "efficiency" VALUES('R2','ELC','E_BATT',2030,'ELC',0.85,''); +INSERT INTO "efficiency" VALUES('R2','E10','T_GSL',2020,'VMT',0.25,''); +INSERT INTO "efficiency" VALUES('R2','E10','T_GSL',2025,'VMT',0.25,''); +INSERT INTO "efficiency" VALUES('R2','E10','T_GSL',2030,'VMT',0.25,''); +INSERT INTO "efficiency" VALUES('R2','DSL','T_DSL',2020,'VMT',0.3,''); +INSERT INTO "efficiency" VALUES('R2','DSL','T_DSL',2025,'VMT',0.3,''); +INSERT INTO "efficiency" VALUES('R2','DSL','T_DSL',2030,'VMT',0.3,''); +INSERT INTO "efficiency" VALUES('R2','ELC','T_EV',2020,'VMT',0.89,''); +INSERT INTO "efficiency" VALUES('R2','ELC','T_EV',2025,'VMT',0.89,''); +INSERT INTO "efficiency" VALUES('R2','ELC','T_EV',2030,'VMT',0.89,''); +INSERT INTO "efficiency" VALUES('R2','ELC','R_EH',2020,'RH',1.0,''); +INSERT INTO "efficiency" VALUES('R2','ELC','R_EH',2025,'RH',1.0,''); +INSERT INTO "efficiency" VALUES('R2','ELC','R_EH',2030,'RH',1.0,''); +INSERT INTO "efficiency" VALUES('R2','NG','R_NGH',2020,'RH',0.85,''); +INSERT INTO "efficiency" VALUES('R2','NG','R_NGH',2025,'RH',0.85,''); +INSERT INTO "efficiency" VALUES('R2','NG','R_NGH',2030,'RH',0.85,''); +INSERT INTO "efficiency" VALUES('R1-R2','ELC','E_TRANS',2015,'ELC',0.9,''); +INSERT INTO "efficiency" VALUES('R2-R1','ELC','E_TRANS',2015,'ELC',0.9,''); CREATE TABLE efficiency_variable ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -677,12 +609,12 @@ CREATE TABLE emission_activity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO emission_activity VALUES('R1','CO2','ethos','S_IMPNG',2020,'NG',50.29999999999999005,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO emission_activity VALUES('R1','CO2','OIL','S_OILREF',2020,'GSL',67.20000000000000284,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO emission_activity VALUES('R1','CO2','OIL','S_OILREF',2020,'DSL',69.40000000000000569,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO emission_activity VALUES('R2','CO2','ethos','S_IMPNG',2020,'NG',50.29999999999999005,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO emission_activity VALUES('R2','CO2','OIL','S_OILREF',2020,'GSL',67.20000000000000284,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO emission_activity VALUES('R2','CO2','OIL','S_OILREF',2020,'DSL',69.40000000000000569,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO "emission_activity" VALUES('R1','CO2','ethos','S_IMPNG',2020,'NG',5.029999999999999e+01,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO "emission_activity" VALUES('R1','CO2','OIL','S_OILREF',2020,'GSL',67.2,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO "emission_activity" VALUES('R1','CO2','OIL','S_OILREF',2020,'DSL',69.4,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO "emission_activity" VALUES('R2','CO2','ethos','S_IMPNG',2020,'NG',5.029999999999999e+01,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO "emission_activity" VALUES('R2','CO2','OIL','S_OILREF',2020,'GSL',67.2,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO "emission_activity" VALUES('R2','CO2','OIL','S_OILREF',2020,'DSL',69.4,'kT/PJ','taken from MIT Energy Fact Sheet'); CREATE TABLE emission_embodied ( region TEXT, @@ -695,7 +627,7 @@ CREATE TABLE emission_embodied value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) ); CREATE TABLE emission_end_of_life ( @@ -709,7 +641,21 @@ CREATE TABLE emission_end_of_life value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE end_of_life_output +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); CREATE TABLE existing_capacity ( @@ -723,17 +669,11 @@ CREATE TABLE existing_capacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO existing_capacity VALUES('R1','E_NUCLEAR',2015,0.07000000000000000667,'GW',''); -INSERT INTO existing_capacity VALUES('R2','E_NUCLEAR',2015,0.02999999999999999889,'GW',''); -INSERT INTO existing_capacity VALUES('R1-R2','E_TRANS',2015,10.0,'GW',''); -INSERT INTO existing_capacity VALUES('R2-R1','E_TRANS',2015,10.0,'GW',''); -CREATE TABLE TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE loan_lifetime_process +INSERT INTO "existing_capacity" VALUES('R1','E_NUCLEAR',2015,0.07,'GW',''); +INSERT INTO "existing_capacity" VALUES('R2','E_NUCLEAR',2015,0.03,'GW',''); +INSERT INTO "existing_capacity" VALUES('R1-R2','E_TRANS',2015,10.0,'GW',''); +INSERT INTO "existing_capacity" VALUES('R2-R1','E_TRANS',2015,10.0,'GW',''); +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -744,190 +684,239 @@ CREATE TABLE loan_lifetime_process notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE loan_rate +CREATE TABLE lifetime_survival_curve ( - region TEXT, - tech TEXT + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL REFERENCES technology (tech), - vintage INTEGER + vintage INTEGER NOT NULL REFERENCES time_period (period), - rate REAL, + fraction REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE lifetime_process +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), lifetime REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, tech) ); -CREATE TABLE lifetime_tech +INSERT INTO "lifetime_tech" VALUES('R1','S_IMPETH',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','S_IMPOIL',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','S_IMPNG',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','S_IMPURN',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','S_OILREF',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','E_NGCC',30.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','E_SOLPV',30.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','E_BATT',20.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','E_NUCLEAR',50.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','T_BLND',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','T_DSL',12.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','T_GSL',12.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','T_EV',12.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','R_EH',20.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','R_NGH',20.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','S_IMPETH',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','S_IMPOIL',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','S_IMPNG',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','S_IMPURN',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','S_OILREF',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','E_NGCC',30.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','E_SOLPV',30.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','E_BATT',20.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','E_NUCLEAR',50.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','T_BLND',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','T_DSL',12.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','T_GSL',12.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','T_EV',12.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','R_EH',20.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','R_NGH',20.0,''); +INSERT INTO "lifetime_tech" VALUES('R1-R2','E_TRANS',30.0,''); +INSERT INTO "lifetime_tech" VALUES('R2-R1','E_TRANS',30.0,''); +CREATE TABLE limit_activity ( - region TEXT, - tech TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +INSERT INTO "limit_activity" VALUES('R1',2020,'T_GSL','ge',35.0,'',''); +INSERT INTO "limit_activity" VALUES('R1',2025,'T_GSL','ge',35.0,'',''); +INSERT INTO "limit_activity" VALUES('R1',2030,'T_GSL','ge',35.0,'',''); +INSERT INTO "limit_activity" VALUES('R2',2020,'T_GSL','ge',15.0,'',''); +INSERT INTO "limit_activity" VALUES('R2',2025,'T_GSL','ge',15.0,'',''); +INSERT INTO "limit_activity" VALUES('R2',2030,'T_GSL','ge',15.0,'',''); +CREATE TABLE limit_activity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_annual_capacity_factor +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator), + CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO lifetime_tech VALUES('R1','S_IMPETH',100.0,''); -INSERT INTO lifetime_tech VALUES('R1','S_IMPOIL',100.0,''); -INSERT INTO lifetime_tech VALUES('R1','S_IMPNG',100.0,''); -INSERT INTO lifetime_tech VALUES('R1','S_IMPURN',100.0,''); -INSERT INTO lifetime_tech VALUES('R1','S_OILREF',100.0,''); -INSERT INTO lifetime_tech VALUES('R1','E_NGCC',30.0,''); -INSERT INTO lifetime_tech VALUES('R1','E_SOLPV',30.0,''); -INSERT INTO lifetime_tech VALUES('R1','E_BATT',20.0,''); -INSERT INTO lifetime_tech VALUES('R1','E_NUCLEAR',50.0,''); -INSERT INTO lifetime_tech VALUES('R1','T_BLND',100.0,''); -INSERT INTO lifetime_tech VALUES('R1','T_DSL',12.0,''); -INSERT INTO lifetime_tech VALUES('R1','T_GSL',12.0,''); -INSERT INTO lifetime_tech VALUES('R1','T_EV',12.0,''); -INSERT INTO lifetime_tech VALUES('R1','R_EH',20.0,''); -INSERT INTO lifetime_tech VALUES('R1','R_NGH',20.0,''); -INSERT INTO lifetime_tech VALUES('R2','S_IMPETH',100.0,''); -INSERT INTO lifetime_tech VALUES('R2','S_IMPOIL',100.0,''); -INSERT INTO lifetime_tech VALUES('R2','S_IMPNG',100.0,''); -INSERT INTO lifetime_tech VALUES('R2','S_IMPURN',100.0,''); -INSERT INTO lifetime_tech VALUES('R2','S_OILREF',100.0,''); -INSERT INTO lifetime_tech VALUES('R2','E_NGCC',30.0,''); -INSERT INTO lifetime_tech VALUES('R2','E_SOLPV',30.0,''); -INSERT INTO lifetime_tech VALUES('R2','E_BATT',20.0,''); -INSERT INTO lifetime_tech VALUES('R2','E_NUCLEAR',50.0,''); -INSERT INTO lifetime_tech VALUES('R2','T_BLND',100.0,''); -INSERT INTO lifetime_tech VALUES('R2','T_DSL',12.0,''); -INSERT INTO lifetime_tech VALUES('R2','T_GSL',12.0,''); -INSERT INTO lifetime_tech VALUES('R2','T_EV',12.0,''); -INSERT INTO lifetime_tech VALUES('R2','R_EH',20.0,''); -INSERT INTO lifetime_tech VALUES('R2','R_NGH',20.0,''); -INSERT INTO lifetime_tech VALUES('R1-R2','E_TRANS',30.0,''); -INSERT INTO lifetime_tech VALUES('R2-R1','E_TRANS',30.0,''); -CREATE TABLE Operator +CREATE TABLE limit_capacity ( - operator TEXT PRIMARY KEY, - notes TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO Operator VALUES('e','equal to'); -INSERT INTO Operator VALUES('le','less than or equal to'); -INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE limit_growth_capacity +CREATE TABLE limit_capacity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_capacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity +CREATE TABLE limit_emission +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +INSERT INTO "limit_emission" VALUES('R1',2020,'CO2','le',25000.0,'kT CO2',''); +INSERT INTO "limit_emission" VALUES('R1',2025,'CO2','le',24000.0,'kT CO2',''); +INSERT INTO "limit_emission" VALUES('R1',2030,'CO2','le',23000.0,'kT CO2',''); +INSERT INTO "limit_emission" VALUES('global',2020,'CO2','le',37500.0,'kT CO2',''); +INSERT INTO "limit_emission" VALUES('global',2025,'CO2','le',36000.0,'kT CO2',''); +INSERT INTO "limit_emission" VALUES('global',2030,'CO2','le',34500.0,'kT CO2',''); +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitStorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -INSERT INTO LimitStorageLevelFraction VALUES('R1',2025,'winter','day','E_BATT',2025,'e',0.5,''); -INSERT INTO LimitStorageLevelFraction VALUES('R2',2020,'summer','day','E_BATT',2020,'e',0.5,''); -CREATE TABLE limit_activity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, + REFERENCES operator (operator), + new_cap REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO limit_activity VALUES('R1',2020,'T_GSL','ge',35.0,'',''); -INSERT INTO limit_activity VALUES('R1',2025,'T_GSL','ge',35.0,'',''); -INSERT INTO limit_activity VALUES('R1',2030,'T_GSL','ge',35.0,'',''); -INSERT INTO limit_activity VALUES('R2',2020,'T_GSL','ge',15.0,'',''); -INSERT INTO limit_activity VALUES('R2',2025,'T_GSL','ge',15.0,'',''); -INSERT INTO limit_activity VALUES('R2',2030,'T_GSL','ge',15.0,'',''); -CREATE TABLE limit_activity_share +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -935,106 +924,59 @@ CREATE TABLE limit_activity_share sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), share REAL, notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity +CREATE TABLE limit_resource ( region TEXT, - period INTEGER - REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, + REFERENCES operator (operator), + cum_act REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) + PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_capacity_share +CREATE TABLE limit_seasonal_capacity_factor ( - region TEXT, - period INTEGER + region TEXT + REFERENCES region (region), + period INTEGER REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, + season TEXT + REFERENCES season_label (season), + tech TEXT + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE limit_new_capacity +CREATE TABLE limit_storage_level_fraction ( - region TEXT, - period INTEGER + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), - tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) + REFERENCES operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); +INSERT INTO "limit_storage_level_fraction" VALUES('R1',2025,'winter','day','E_BATT',2025,'e',0.5,''); +INSERT INTO "limit_storage_level_fraction" VALUES('R2',2020,'summer','day','E_BATT',2020,'e',0.5,''); CREATE TABLE limit_tech_input_split ( region TEXT, @@ -1045,23 +987,23 @@ CREATE TABLE limit_tech_input_split tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -INSERT INTO limit_tech_input_split VALUES('R1',2020,'GSL','T_BLND','ge',0.9000000000000000222,''); -INSERT INTO limit_tech_input_split VALUES('R1',2020,'ETH','T_BLND','ge',0.1000000000000000055,''); -INSERT INTO limit_tech_input_split VALUES('R1',2025,'GSL','T_BLND','ge',0.9000000000000000222,''); -INSERT INTO limit_tech_input_split VALUES('R1',2025,'ETH','T_BLND','ge',0.1000000000000000055,''); -INSERT INTO limit_tech_input_split VALUES('R1',2030,'GSL','T_BLND','ge',0.9000000000000000222,''); -INSERT INTO limit_tech_input_split VALUES('R1',2030,'ETH','T_BLND','ge',0.1000000000000000055,''); -INSERT INTO limit_tech_input_split VALUES('R2',2020,'GSL','T_BLND','ge',0.7199999999999999734,''); -INSERT INTO limit_tech_input_split VALUES('R2',2020,'ETH','T_BLND','ge',0.08000000000000000166,''); -INSERT INTO limit_tech_input_split VALUES('R2',2025,'GSL','T_BLND','ge',0.7199999999999999734,''); -INSERT INTO limit_tech_input_split VALUES('R2',2025,'ETH','T_BLND','ge',0.08000000000000000166,''); -INSERT INTO limit_tech_input_split VALUES('R2',2030,'GSL','T_BLND','ge',0.7199999999999999734,''); -INSERT INTO limit_tech_input_split VALUES('R2',2030,'ETH','T_BLND','ge',0.08000000000000000166,''); +INSERT INTO "limit_tech_input_split" VALUES('R1',2020,'GSL','T_BLND','ge',0.9,''); +INSERT INTO "limit_tech_input_split" VALUES('R1',2020,'ETH','T_BLND','ge',0.1,''); +INSERT INTO "limit_tech_input_split" VALUES('R1',2025,'GSL','T_BLND','ge',0.9,''); +INSERT INTO "limit_tech_input_split" VALUES('R1',2025,'ETH','T_BLND','ge',0.1,''); +INSERT INTO "limit_tech_input_split" VALUES('R1',2030,'GSL','T_BLND','ge',0.9,''); +INSERT INTO "limit_tech_input_split" VALUES('R1',2030,'ETH','T_BLND','ge',0.1,''); +INSERT INTO "limit_tech_input_split" VALUES('R2',2020,'GSL','T_BLND','ge',0.72,''); +INSERT INTO "limit_tech_input_split" VALUES('R2',2020,'ETH','T_BLND','ge',0.08,''); +INSERT INTO "limit_tech_input_split" VALUES('R2',2025,'GSL','T_BLND','ge',0.72,''); +INSERT INTO "limit_tech_input_split" VALUES('R2',2025,'ETH','T_BLND','ge',0.08,''); +INSERT INTO "limit_tech_input_split" VALUES('R2',2030,'GSL','T_BLND','ge',0.72,''); +INSERT INTO "limit_tech_input_split" VALUES('R2',2030,'ETH','T_BLND','ge',0.08,''); CREATE TABLE limit_tech_input_split_annual ( region TEXT, @@ -1072,7 +1014,7 @@ CREATE TABLE limit_tech_input_split_annual tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -1087,23 +1029,23 @@ CREATE TABLE limit_tech_output_split output_comm TEXT REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -INSERT INTO limit_tech_output_split VALUES('R1',2020,'S_OILREF','GSL','ge',0.9000000000000000222,''); -INSERT INTO limit_tech_output_split VALUES('R1',2020,'S_OILREF','DSL','ge',0.1000000000000000055,''); -INSERT INTO limit_tech_output_split VALUES('R1',2025,'S_OILREF','GSL','ge',0.9000000000000000222,''); -INSERT INTO limit_tech_output_split VALUES('R1',2025,'S_OILREF','DSL','ge',0.1000000000000000055,''); -INSERT INTO limit_tech_output_split VALUES('R1',2030,'S_OILREF','GSL','ge',0.9000000000000000222,''); -INSERT INTO limit_tech_output_split VALUES('R1',2030,'S_OILREF','DSL','ge',0.1000000000000000055,''); -INSERT INTO limit_tech_output_split VALUES('R2',2020,'S_OILREF','GSL','ge',0.7199999999999999734,''); -INSERT INTO limit_tech_output_split VALUES('R2',2020,'S_OILREF','DSL','ge',0.08000000000000000166,''); -INSERT INTO limit_tech_output_split VALUES('R2',2025,'S_OILREF','GSL','ge',0.7199999999999999734,''); -INSERT INTO limit_tech_output_split VALUES('R2',2025,'S_OILREF','DSL','ge',0.08000000000000000166,''); -INSERT INTO limit_tech_output_split VALUES('R2',2030,'S_OILREF','GSL','ge',0.7199999999999999734,''); -INSERT INTO limit_tech_output_split VALUES('R2',2030,'S_OILREF','DSL','ge',0.08000000000000000166,''); +INSERT INTO "limit_tech_output_split" VALUES('R1',2020,'S_OILREF','GSL','ge',0.9,''); +INSERT INTO "limit_tech_output_split" VALUES('R1',2020,'S_OILREF','DSL','ge',0.1,''); +INSERT INTO "limit_tech_output_split" VALUES('R1',2025,'S_OILREF','GSL','ge',0.9,''); +INSERT INTO "limit_tech_output_split" VALUES('R1',2025,'S_OILREF','DSL','ge',0.1,''); +INSERT INTO "limit_tech_output_split" VALUES('R1',2030,'S_OILREF','GSL','ge',0.9,''); +INSERT INTO "limit_tech_output_split" VALUES('R1',2030,'S_OILREF','DSL','ge',0.1,''); +INSERT INTO "limit_tech_output_split" VALUES('R2',2020,'S_OILREF','GSL','ge',0.72,''); +INSERT INTO "limit_tech_output_split" VALUES('R2',2020,'S_OILREF','DSL','ge',0.08,''); +INSERT INTO "limit_tech_output_split" VALUES('R2',2025,'S_OILREF','GSL','ge',0.72,''); +INSERT INTO "limit_tech_output_split" VALUES('R2',2025,'S_OILREF','DSL','ge',0.08,''); +INSERT INTO "limit_tech_output_split" VALUES('R2',2030,'S_OILREF','GSL','ge',0.72,''); +INSERT INTO "limit_tech_output_split" VALUES('R2',2030,'S_OILREF','DSL','ge',0.08,''); CREATE TABLE limit_tech_output_split_annual ( region TEXT, @@ -1114,32 +1056,12 @@ CREATE TABLE limit_tech_output_split_annual output_comm TEXT REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -INSERT INTO limit_emission VALUES('R1',2020,'CO2','le',25000.0,'kT CO2',''); -INSERT INTO limit_emission VALUES('R1',2025,'CO2','le',24000.0,'kT CO2',''); -INSERT INTO limit_emission VALUES('R1',2030,'CO2','le',23000.0,'kT CO2',''); -INSERT INTO limit_emission VALUES('global',2020,'CO2','le',37500.0,'kT CO2',''); -INSERT INTO limit_emission VALUES('global',2025,'CO2','le',36000.0,'kT CO2',''); -INSERT INTO limit_emission VALUES('global',2030,'CO2','le',34500.0,'kT CO2',''); -CREATE TABLE LinkedTech +CREATE TABLE linked_tech ( primary_region TEXT, primary_tech TEXT @@ -1151,6 +1073,103 @@ CREATE TABLE LinkedTech notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); +CREATE TABLE loan_lifetime_process +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE loan_rate +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE metadata +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); +INSERT INTO "metadata" VALUES('DB_MINOR',0,''); +CREATE TABLE metadata_real +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,''); +CREATE TABLE myopic_efficiency +( + base_year integer, + region text, + input_comm text, + tech text, + vintage integer, + output_comm text, + efficiency real, + lifetime integer, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (region, input_comm, tech, vintage, output_comm) +); +CREATE TABLE operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "operator" VALUES('e','equal to'); +INSERT INTO "operator" VALUES('le','less than or equal to'); +INSERT INTO "operator" VALUES('ge','greater than or equal to'); +CREATE TABLE output_built_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE output_cost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) +); CREATE TABLE output_curtailment ( scenario TEXT, @@ -1161,7 +1180,7 @@ CREATE TABLE output_curtailment season TEXT REFERENCES time_period (period), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -1173,62 +1192,42 @@ CREATE TABLE output_curtailment curtailment REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputNetCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_built_capacity +CREATE TABLE output_dual_variable ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE output_emission ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), - tech TEXT + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT REFERENCES technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE OutputFlowIn +CREATE TABLE output_flow_in ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -1240,18 +1239,18 @@ CREATE TABLE OutputFlowIn flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputFlowOut +CREATE TABLE output_flow_out ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -1263,18 +1262,70 @@ CREATE TABLE OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); +CREATE TABLE output_flow_out_summary +( + scenario TEXT NOT NULL, + region TEXT NOT NULL, + sector TEXT, + period INTEGER, + input_comm TEXT NOT NULL, + tech TEXT NOT NULL, + vintage INTEGER, + output_comm TEXT NOT NULL, + flow REAL NOT NULL, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_net_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_objective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE output_retired_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), vintage INTEGER @@ -1314,15 +1365,15 @@ CREATE TABLE region PRIMARY KEY, notes TEXT ); -INSERT INTO region VALUES('R1',NULL); -INSERT INTO region VALUES('R2',NULL); +INSERT INTO "region" VALUES('R1',NULL); +INSERT INTO "region" VALUES('R2',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tech TEXT REFERENCES technology (tech), vintage INTEGER, @@ -1331,43 +1382,37 @@ CREATE TABLE reserve_capacity_derate PRIMARY KEY (region, period, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE TimeSegmentFraction +CREATE TABLE rps_requirement ( - period INTEGER + region TEXT NOT NULL + REFERENCES region (region), + period INTEGER NOT NULL REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) -); -INSERT INTO TimeSegmentFraction VALUES(2020,'spring','day',0.125,'Spring - Day'); -INSERT INTO TimeSegmentFraction VALUES(2020,'spring','night',0.125,'Spring - Night'); -INSERT INTO TimeSegmentFraction VALUES(2020,'summer','day',0.125,'Summer - Day'); -INSERT INTO TimeSegmentFraction VALUES(2020,'summer','night',0.125,'Summer - Night'); -INSERT INTO TimeSegmentFraction VALUES(2020,'fall','day',0.125,'Fall - Day'); -INSERT INTO TimeSegmentFraction VALUES(2020,'fall','night',0.125,'Fall - Night'); -INSERT INTO TimeSegmentFraction VALUES(2020,'winter','day',0.125,'Winter - Day'); -INSERT INTO TimeSegmentFraction VALUES(2020,'winter','night',0.125,'Winter - Night'); -INSERT INTO TimeSegmentFraction VALUES(2025,'spring','day',0.125,'Spring - Day'); -INSERT INTO TimeSegmentFraction VALUES(2025,'spring','night',0.125,'Spring - Night'); -INSERT INTO TimeSegmentFraction VALUES(2025,'summer','day',0.125,'Summer - Day'); -INSERT INTO TimeSegmentFraction VALUES(2025,'summer','night',0.125,'Summer - Night'); -INSERT INTO TimeSegmentFraction VALUES(2025,'fall','day',0.125,'Fall - Day'); -INSERT INTO TimeSegmentFraction VALUES(2025,'fall','night',0.125,'Fall - Night'); -INSERT INTO TimeSegmentFraction VALUES(2025,'winter','day',0.125,'Winter - Day'); -INSERT INTO TimeSegmentFraction VALUES(2025,'winter','night',0.125,'Winter - Night'); -INSERT INTO TimeSegmentFraction VALUES(2030,'spring','day',0.125,'Spring - Day'); -INSERT INTO TimeSegmentFraction VALUES(2030,'spring','night',0.125,'Spring - Night'); -INSERT INTO TimeSegmentFraction VALUES(2030,'summer','day',0.125,'Summer - Day'); -INSERT INTO TimeSegmentFraction VALUES(2030,'summer','night',0.125,'Summer - Night'); -INSERT INTO TimeSegmentFraction VALUES(2030,'fall','day',0.125,'Fall - Day'); -INSERT INTO TimeSegmentFraction VALUES(2030,'fall','night',0.125,'Fall - Night'); -INSERT INTO TimeSegmentFraction VALUES(2030,'winter','day',0.125,'Winter - Day'); -INSERT INTO TimeSegmentFraction VALUES(2030,'winter','night',0.125,'Winter - Night'); + tech_group TEXT NOT NULL + REFERENCES tech_group (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE season_label +( + season TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "season_label" VALUES('summer',NULL); +INSERT INTO "season_label" VALUES('fall',NULL); +INSERT INTO "season_label" VALUES('winter',NULL); +INSERT INTO "season_label" VALUES('spring',NULL); +CREATE TABLE sector_label +( + sector TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "sector_label" VALUES('supply',NULL); +INSERT INTO "sector_label" VALUES('electric',NULL); +INSERT INTO "sector_label" VALUES('transport',NULL); +INSERT INTO "sector_label" VALUES('commercial',NULL); +INSERT INTO "sector_label" VALUES('residential',NULL); +INSERT INTO "sector_label" VALUES('industrial',NULL); CREATE TABLE storage_duration ( region TEXT, @@ -1376,181 +1421,184 @@ CREATE TABLE storage_duration notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO storage_duration VALUES('R1','E_BATT',8.0,'8-hour duration specified as fraction of a day'); -INSERT INTO storage_duration VALUES('R2','E_BATT',8.0,'8-hour duration specified as fraction of a day'); -CREATE TABLE lifetime_survival_curve +INSERT INTO "storage_duration" VALUES('R1','E_BATT',8.0,'8-hour duration specified as fraction of a day'); +INSERT INTO "storage_duration" VALUES('R2','E_BATT',8.0,'8-hour duration specified as fraction of a day'); +CREATE TABLE tech_group ( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE tech_group_member +( + group_name TEXT + REFERENCES tech_group (group_name), + tech TEXT REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) + PRIMARY KEY (group_name, tech) ); -CREATE TABLE technologyType +CREATE TABLE technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES technology_type (label) +); +INSERT INTO "technology" VALUES('S_IMPETH','p','supply','','',1,0,0,0,0,0,0,0,' imported ethanol'); +INSERT INTO "technology" VALUES('S_IMPOIL','p','supply','','',1,0,0,0,0,0,0,0,' imported crude oil'); +INSERT INTO "technology" VALUES('S_IMPNG','p','supply','','',1,0,0,0,0,0,0,0,' imported natural gas'); +INSERT INTO "technology" VALUES('S_IMPURN','p','supply','','',1,0,0,0,0,0,0,0,' imported uranium'); +INSERT INTO "technology" VALUES('S_OILREF','p','supply','','',0,0,0,1,0,0,0,0,' crude oil refinery'); +INSERT INTO "technology" VALUES('E_NGCC','p','electric','','',0,0,0,0,0,0,0,0,' natural gas combined-cycle'); +INSERT INTO "technology" VALUES('E_SOLPV','p','electric','','',0,0,0,0,0,0,0,0,' solar photovoltaic'); +INSERT INTO "technology" VALUES('E_BATT','ps','electric','','',0,0,0,0,0,0,0,0,' lithium-ion battery'); +INSERT INTO "technology" VALUES('E_NUCLEAR','pb','electric','','',0,0,0,0,0,0,0,0,' nuclear power plant'); +INSERT INTO "technology" VALUES('T_BLND','p','transport','','',0,0,0,0,0,0,0,0,'ethanol - gasoline blending process'); +INSERT INTO "technology" VALUES('T_DSL','p','transport','','',0,0,0,0,0,0,0,0,'diesel vehicle'); +INSERT INTO "technology" VALUES('T_GSL','p','transport','','',0,0,0,0,0,0,0,0,'gasoline vehicle'); +INSERT INTO "technology" VALUES('T_EV','p','transport','','',0,0,0,0,0,0,0,0,'electric vehicle'); +INSERT INTO "technology" VALUES('R_EH','p','residential','','',0,0,0,0,0,0,0,0,' electric residential heating'); +INSERT INTO "technology" VALUES('R_NGH','p','residential','','',0,0,0,0,0,0,0,0,' natural gas residential heating'); +INSERT INTO "technology" VALUES('E_TRANS','p','electric','','',0,0,0,0,0,0,1,0,'electric transmission'); +CREATE TABLE technology_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO technologyType VALUES('p','production technology'); -INSERT INTO technologyType VALUES('pb','baseload production technology'); -INSERT INTO technologyType VALUES('ps','storage production technology'); -CREATE TABLE TimeOfDay +INSERT INTO "technology_type" VALUES('p','production technology'); +INSERT INTO "technology_type" VALUES('pb','baseload production technology'); +INSERT INTO "technology_type" VALUES('ps','storage production technology'); +CREATE TABLE time_of_day ( sequence INTEGER UNIQUE, tod TEXT PRIMARY KEY ); -INSERT INTO TimeOfDay VALUES(1,'day'); -INSERT INTO TimeOfDay VALUES(2,'night'); +INSERT INTO "time_of_day" VALUES(1,'day'); +INSERT INTO "time_of_day" VALUES(2,'night'); CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES time_periodType (label) + REFERENCES time_period_type (label) ); -INSERT INTO time_period VALUES(1,2015,'e'); -INSERT INTO time_period VALUES(2,2020,'f'); -INSERT INTO time_period VALUES(3,2025,'f'); -INSERT INTO time_period VALUES(4,2030,'f'); -INSERT INTO time_period VALUES(5,2035,'f'); -CREATE TABLE TimeSeason +INSERT INTO "time_period" VALUES(1,2015,'e'); +INSERT INTO "time_period" VALUES(2,2020,'f'); +INSERT INTO "time_period" VALUES(3,2025,'f'); +INSERT INTO "time_period" VALUES(4,2030,'f'); +INSERT INTO "time_period" VALUES(5,2035,'f'); +CREATE TABLE time_period_type +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO "time_period_type" VALUES('e','existing vintages'); +INSERT INTO "time_period_type" VALUES('f','future'); +CREATE TABLE time_season +( + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + season TEXT REFERENCES season_label(season), + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +INSERT INTO "time_season" VALUES(2020,1,'spring',NULL); +INSERT INTO "time_season" VALUES(2020,2,'summer',NULL); +INSERT INTO "time_season" VALUES(2020,3,'fall',NULL); +INSERT INTO "time_season" VALUES(2020,4,'winter',NULL); +INSERT INTO "time_season" VALUES(2025,1,'spring',NULL); +INSERT INTO "time_season" VALUES(2025,2,'summer',NULL); +INSERT INTO "time_season" VALUES(2025,3,'fall',NULL); +INSERT INTO "time_season" VALUES(2025,4,'winter',NULL); +INSERT INTO "time_season" VALUES(2030,1,'spring',NULL); +INSERT INTO "time_season" VALUES(2030,2,'summer',NULL); +INSERT INTO "time_season" VALUES(2030,3,'fall',NULL); +INSERT INTO "time_season" VALUES(2030,4,'winter',NULL); +CREATE TABLE time_season_all ( period INTEGER REFERENCES time_period (period), sequence INTEGER, season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); -INSERT INTO TimeSeason VALUES(2020,1,'spring',NULL); -INSERT INTO TimeSeason VALUES(2020,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(2020,3,'fall',NULL); -INSERT INTO TimeSeason VALUES(2020,4,'winter',NULL); -INSERT INTO TimeSeason VALUES(2025,1,'spring',NULL); -INSERT INTO TimeSeason VALUES(2025,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(2025,3,'fall',NULL); -INSERT INTO TimeSeason VALUES(2025,4,'winter',NULL); -INSERT INTO TimeSeason VALUES(2030,1,'spring',NULL); -INSERT INTO TimeSeason VALUES(2030,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(2030,3,'fall',NULL); -INSERT INTO TimeSeason VALUES(2030,4,'winter',NULL); CREATE TABLE time_season_sequential ( - period INTEGER - REFERENCES time_period (period), + period INTEGER REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES SeasonLabel (season), + season TEXT REFERENCES season_label(season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE time_periodType -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO time_periodType VALUES('e','existing vintages'); -INSERT INTO time_periodType VALUES('f','future'); -CREATE TABLE OutputEmission +CREATE TABLE time_season_to_sequential ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER + period INTEGER REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) + sequence INTEGER, + seas_seq TEXT, + season TEXT + REFERENCES season_label (season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) ); -CREATE TABLE RPSRequirement +CREATE TABLE time_segment_fraction ( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL + period INTEGER REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES TechGroup (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE TechGroupMember -( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technologyType (label) -); -INSERT INTO technology VALUES('S_IMPETH','p','supply','','',1,0,0,0,0,0,0,0,' imported ethanol'); -INSERT INTO technology VALUES('S_IMPOIL','p','supply','','',1,0,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO technology VALUES('S_IMPNG','p','supply','','',1,0,0,0,0,0,0,0,' imported natural gas'); -INSERT INTO technology VALUES('S_IMPURN','p','supply','','',1,0,0,0,0,0,0,0,' imported uranium'); -INSERT INTO technology VALUES('S_OILREF','p','supply','','',0,0,0,1,0,0,0,0,' crude oil refinery'); -INSERT INTO technology VALUES('E_NGCC','p','electric','','',0,0,0,0,0,0,0,0,' natural gas combined-cycle'); -INSERT INTO technology VALUES('E_SOLPV','p','electric','','',0,0,0,0,0,0,0,0,' solar photovoltaic'); -INSERT INTO technology VALUES('E_BATT','ps','electric','','',0,0,0,0,0,0,0,0,' lithium-ion battery'); -INSERT INTO technology VALUES('E_NUCLEAR','pb','electric','','',0,0,0,0,0,0,0,0,' nuclear power plant'); -INSERT INTO technology VALUES('T_BLND','p','transport','','',0,0,0,0,0,0,0,0,'ethanol - gasoline blending process'); -INSERT INTO technology VALUES('T_DSL','p','transport','','',0,0,0,0,0,0,0,0,'diesel vehicle'); -INSERT INTO technology VALUES('T_GSL','p','transport','','',0,0,0,0,0,0,0,0,'gasoline vehicle'); -INSERT INTO technology VALUES('T_EV','p','transport','','',0,0,0,0,0,0,0,0,'electric vehicle'); -INSERT INTO technology VALUES('R_EH','p','residential','','',0,0,0,0,0,0,0,0,' electric residential heating'); -INSERT INTO technology VALUES('R_NGH','p','residential','','',0,0,0,0,0,0,0,0,' natural gas residential heating'); -INSERT INTO technology VALUES('E_TRANS','p','electric','','',0,0,0,0,0,0,1,0,'electric transmission'); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) -); + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + segment_fraction REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) +); +INSERT INTO "time_segment_fraction" VALUES(2020,'spring','day',0.125,'Spring - Day'); +INSERT INTO "time_segment_fraction" VALUES(2020,'spring','night',0.125,'Spring - Night'); +INSERT INTO "time_segment_fraction" VALUES(2020,'summer','day',0.125,'Summer - Day'); +INSERT INTO "time_segment_fraction" VALUES(2020,'summer','night',0.125,'Summer - Night'); +INSERT INTO "time_segment_fraction" VALUES(2020,'fall','day',0.125,'Fall - Day'); +INSERT INTO "time_segment_fraction" VALUES(2020,'fall','night',0.125,'Fall - Night'); +INSERT INTO "time_segment_fraction" VALUES(2020,'winter','day',0.125,'Winter - Day'); +INSERT INTO "time_segment_fraction" VALUES(2020,'winter','night',0.125,'Winter - Night'); +INSERT INTO "time_segment_fraction" VALUES(2025,'spring','day',0.125,'Spring - Day'); +INSERT INTO "time_segment_fraction" VALUES(2025,'spring','night',0.125,'Spring - Night'); +INSERT INTO "time_segment_fraction" VALUES(2025,'summer','day',0.125,'Summer - Day'); +INSERT INTO "time_segment_fraction" VALUES(2025,'summer','night',0.125,'Summer - Night'); +INSERT INTO "time_segment_fraction" VALUES(2025,'fall','day',0.125,'Fall - Day'); +INSERT INTO "time_segment_fraction" VALUES(2025,'fall','night',0.125,'Fall - Night'); +INSERT INTO "time_segment_fraction" VALUES(2025,'winter','day',0.125,'Winter - Day'); +INSERT INTO "time_segment_fraction" VALUES(2025,'winter','night',0.125,'Winter - Night'); +INSERT INTO "time_segment_fraction" VALUES(2030,'spring','day',0.125,'Spring - Day'); +INSERT INTO "time_segment_fraction" VALUES(2030,'spring','night',0.125,'Spring - Night'); +INSERT INTO "time_segment_fraction" VALUES(2030,'summer','day',0.125,'Summer - Day'); +INSERT INTO "time_segment_fraction" VALUES(2030,'summer','night',0.125,'Summer - Night'); +INSERT INTO "time_segment_fraction" VALUES(2030,'fall','day',0.125,'Fall - Day'); +INSERT INTO "time_segment_fraction" VALUES(2030,'fall','night',0.125,'Fall - Night'); +INSERT INTO "time_segment_fraction" VALUES(2030,'winter','day',0.125,'Winter - Day'); +INSERT INTO "time_segment_fraction" VALUES(2030,'winter','night',0.125,'Winter - Night'); +CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql index 4745911b7..185852683 100644 --- a/tests/testing_data/utopia.sql +++ b/tests/testing_data/utopia.sql @@ -1,57 +1,4 @@ -PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO metadata VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO metadata VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO metadata VALUES ('days_per_period', 365, 'count of days in each period'); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO metadata_real VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); -INSERT INTO metadata_real VALUES('global_discount_rate',0.05000000000000000277,''); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE SeasonLabel -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SeasonLabel VALUES('inter',NULL); -INSERT INTO SeasonLabel VALUES('summer',NULL); -INSERT INTO SeasonLabel VALUES('winter',NULL); -CREATE TABLE SectorLabel -( - sector TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SectorLabel VALUES('supply',NULL); -INSERT INTO SectorLabel VALUES('electric',NULL); -INSERT INTO SectorLabel VALUES('transport',NULL); -INSERT INTO SectorLabel VALUES('commercial',NULL); -INSERT INTO SectorLabel VALUES('residential',NULL); -INSERT INTO SectorLabel VALUES('industrial',NULL); CREATE TABLE capacity_credit ( region TEXT, @@ -71,9 +18,9 @@ CREATE TABLE capacity_factor_process period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), vintage INTEGER, @@ -82,33 +29,33 @@ CREATE TABLE capacity_factor_process PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO capacity_factor_process VALUES('utopia',2000,'inter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2000,'inter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2000,'winter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2000,'winter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2000,'summer','day','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2000,'summer','night','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','day','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','night','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','day','E31',2010,0.2756000000000000116,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','night','E31',2010,0.2756000000000000116,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','day','E31',2010,0.2756000000000000116,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','night','E31',2010,0.2756000000000000116,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','day','E31',2010,0.2756000000000000116,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','night','E31',2010,0.2756000000000000116,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'inter','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'inter','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'winter','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'winter','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'summer','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'summer','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','day','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','night','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','day','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','night','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','day','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','night','E31',2010,0.2756,''); CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), factor REAL, @@ -116,97 +63,97 @@ CREATE TABLE capacity_factor_tech PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E70',0.8000000000000000444,''); -CREATE TABLE CapacityToActivity +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E70',0.8,''); +CREATE TABLE capacity_to_activity ( region TEXT, tech TEXT @@ -215,54 +162,54 @@ CREATE TABLE CapacityToActivity notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO CapacityToActivity VALUES('utopia','E01',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('utopia','E21',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('utopia','E31',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('utopia','E51',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('utopia','E70',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('utopia','RHE',1.0,''); -INSERT INTO CapacityToActivity VALUES('utopia','RHO',1.0,''); -INSERT INTO CapacityToActivity VALUES('utopia','RL1',1.0,''); -INSERT INTO CapacityToActivity VALUES('utopia','SRE',1.0,''); -INSERT INTO CapacityToActivity VALUES('utopia','TXD',1.0,''); -INSERT INTO CapacityToActivity VALUES('utopia','TXE',1.0,''); -INSERT INTO CapacityToActivity VALUES('utopia','TXG',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','E01',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','E21',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','E31',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','E51',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','E70',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','RHE',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','RHO',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','RL1',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','SRE',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','TXD',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','TXE',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','TXG',1.0,''); CREATE TABLE commodity ( name TEXT PRIMARY KEY, flag TEXT - REFERENCES commodityType (label), + REFERENCES commodity_type (label), description TEXT ); -INSERT INTO commodity VALUES('ethos','s','# dummy commodity to supply inputs (makes graph easier to read)'); -INSERT INTO commodity VALUES('DSL','p','# diesel'); -INSERT INTO commodity VALUES('ELC','p','# electricity'); -INSERT INTO commodity VALUES('FEQ','p','# fossil equivalent'); -INSERT INTO commodity VALUES('GSL','p','# gasoline'); -INSERT INTO commodity VALUES('HCO','p','# coal'); -INSERT INTO commodity VALUES('HYD','p','# water'); -INSERT INTO commodity VALUES('OIL','p','# crude oil'); -INSERT INTO commodity VALUES('URN','p','# uranium'); -INSERT INTO commodity VALUES('co2','e','#CO2 emissions'); -INSERT INTO commodity VALUES('nox','e','#NOX emissions'); -INSERT INTO commodity VALUES('RH','d','# residential heating'); -INSERT INTO commodity VALUES('RL','d','# residential lighting'); -INSERT INTO commodity VALUES('TX','d','# transportation'); -CREATE TABLE commodityType +INSERT INTO "commodity" VALUES('ethos','s','# dummy commodity to supply inputs (makes graph easier to read)'); +INSERT INTO "commodity" VALUES('DSL','p','# diesel'); +INSERT INTO "commodity" VALUES('ELC','p','# electricity'); +INSERT INTO "commodity" VALUES('FEQ','p','# fossil equivalent'); +INSERT INTO "commodity" VALUES('GSL','p','# gasoline'); +INSERT INTO "commodity" VALUES('HCO','p','# coal'); +INSERT INTO "commodity" VALUES('HYD','p','# water'); +INSERT INTO "commodity" VALUES('OIL','p','# crude oil'); +INSERT INTO "commodity" VALUES('URN','p','# uranium'); +INSERT INTO "commodity" VALUES('co2','e','#CO2 emissions'); +INSERT INTO "commodity" VALUES('nox','e','#NOX emissions'); +INSERT INTO "commodity" VALUES('RH','d','# residential heating'); +INSERT INTO "commodity" VALUES('RL','d','# residential lighting'); +INSERT INTO "commodity" VALUES('TX','d','# transportation'); +CREATE TABLE commodity_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO commodityType VALUES('w','waste commodity'); -INSERT INTO commodityType VALUES('wa','waste annual commodity'); -INSERT INTO commodityType VALUES('wp','waste physical commodity'); -INSERT INTO commodityType VALUES('a','annual commodity'); -INSERT INTO commodityType VALUES('s','source commodity'); -INSERT INTO commodityType VALUES('p','physical commodity'); -INSERT INTO commodityType VALUES('e','emissions commodity'); -INSERT INTO commodityType VALUES('d','demand commodity'); +INSERT INTO "commodity_type" VALUES('w','waste commodity'); +INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); +INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); +INSERT INTO "commodity_type" VALUES('a','annual commodity'); +INSERT INTO "commodity_type" VALUES('s','source commodity'); +INSERT INTO "commodity_type" VALUES('p','physical commodity'); +INSERT INTO "commodity_type" VALUES('e','emissions commodity'); +INSERT INTO "commodity_type" VALUES('d','demand commodity'); CREATE TABLE construction_input ( region TEXT, @@ -303,88 +250,88 @@ CREATE TABLE cost_fixed notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1960,40.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1970,40.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1980,40.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1990,40.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E01',1970,70.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E01',1980,70.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E01',1990,70.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E01',2000,70.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E01',1980,100.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E01',1990,100.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E01',2000,100.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E01',2010,100.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E21',1990,500.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E21',1990,500.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E21',1990,500.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E21',2000,500.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E21',2000,500.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E21',2010,500.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E31',1980,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E31',1990,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E31',1980,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E31',1990,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E31',2000,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E31',1980,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E31',1990,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E31',2000,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E31',2010,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E51',1980,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E51',1990,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E51',1980,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E51',1990,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E51',2000,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E51',1980,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E51',1990,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E51',2000,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E51',2010,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1960,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1970,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1980,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1990,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E70',1970,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E70',1980,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E70',1990,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E70',2000,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E70',1980,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E70',1990,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E70',2000,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E70',2010,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'RHO',1970,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'RHO',1980,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'RHO',1990,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'RHO',1980,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'RHO',1990,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'RHO',2000,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'RHO',1990,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'RHO',2000,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'RHO',2010,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'RL1',1980,9.46000000000000086,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'RL1',1990,9.46000000000000086,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'RL1',2000,9.46000000000000086,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'RL1',2010,9.46000000000000086,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'TXD',1970,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'TXD',1980,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'TXD',1990,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXD',1980,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXD',1990,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXD',2000,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'TXD',2000,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'TXD',2010,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'TXE',1990,100.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXE',1990,90.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXE',2000,90.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'TXE',2000,80.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'TXE',2010,80.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'TXG',1970,48.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'TXG',1980,48.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'TXG',1990,48.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXG',1980,48.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXG',1990,48.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXG',2000,48.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'TXG',2000,48.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'TXG',2010,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1960,40.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1970,40.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1980,40.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1990,40.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',1970,70.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',1980,70.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',1990,70.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',2000,70.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',1980,100.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',1990,100.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',2000,100.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',2010,100.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E21',1990,500.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E21',1990,500.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E21',1990,500.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E21',2000,500.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E21',2000,500.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E21',2010,500.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E31',1980,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E31',1990,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E31',1980,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E31',1990,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E31',2000,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',1980,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',1990,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',2000,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',2010,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E51',1980,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E51',1990,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E51',1980,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E51',1990,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E51',2000,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',1980,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',1990,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',2000,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',2010,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1960,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1970,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1980,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1990,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',1970,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',1980,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',1990,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',2000,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',1980,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',1990,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',2000,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',2010,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'RHO',1970,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'RHO',1980,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'RHO',1990,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'RHO',1980,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'RHO',1990,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'RHO',2000,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'RHO',1990,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'RHO',2000,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'RHO',2010,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'RL1',1980,9.46,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'RL1',1990,9.46,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'RL1',2000,9.46,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'RL1',2010,9.46,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXD',1970,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXD',1980,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXD',1990,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXD',1980,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXD',1990,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXD',2000,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXD',2000,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXD',2010,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXE',1990,100.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXE',1990,90.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXE',2000,90.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXE',2000,80.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXE',2010,80.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXG',1970,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXG',1980,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXG',1990,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXG',1980,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXG',1990,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXG',2000,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXG',2000,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXG',2010,48.0,'',''); CREATE TABLE cost_invest ( region TEXT, @@ -397,39 +344,39 @@ CREATE TABLE cost_invest notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO cost_invest VALUES('utopia','E01',1990,2000.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E01',2000,1300.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E01',2010,1200.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E21',1990,5000.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E21',2000,5000.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E21',2010,5000.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E31',1990,3000.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E31',2000,3000.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E31',2010,3000.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E51',1990,900.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E51',2000,900.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E51',2010,900.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E70',1990,1000.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E70',2000,1000.0,'',''); -INSERT INTO cost_invest VALUES('utopia','E70',2010,1000.0,'',''); -INSERT INTO cost_invest VALUES('utopia','RHE',1990,90.0,'',''); -INSERT INTO cost_invest VALUES('utopia','RHE',2000,90.0,'',''); -INSERT INTO cost_invest VALUES('utopia','RHE',2010,90.0,'',''); -INSERT INTO cost_invest VALUES('utopia','RHO',1990,100.0,'',''); -INSERT INTO cost_invest VALUES('utopia','RHO',2000,100.0,'',''); -INSERT INTO cost_invest VALUES('utopia','RHO',2010,100.0,'',''); -INSERT INTO cost_invest VALUES('utopia','SRE',1990,100.0,'',''); -INSERT INTO cost_invest VALUES('utopia','SRE',2000,100.0,'',''); -INSERT INTO cost_invest VALUES('utopia','SRE',2010,100.0,'',''); -INSERT INTO cost_invest VALUES('utopia','TXD',1990,1044.0,'',''); -INSERT INTO cost_invest VALUES('utopia','TXD',2000,1044.0,'',''); -INSERT INTO cost_invest VALUES('utopia','TXD',2010,1044.0,'',''); -INSERT INTO cost_invest VALUES('utopia','TXE',1990,2000.0,'',''); -INSERT INTO cost_invest VALUES('utopia','TXE',2000,1750.0,'',''); -INSERT INTO cost_invest VALUES('utopia','TXE',2010,1500.0,'',''); -INSERT INTO cost_invest VALUES('utopia','TXG',1990,1044.0,'',''); -INSERT INTO cost_invest VALUES('utopia','TXG',2000,1044.0,'',''); -INSERT INTO cost_invest VALUES('utopia','TXG',2010,1044.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E01',1990,2000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E01',2000,1300.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E01',2010,1200.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E21',1990,5000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E21',2000,5000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E21',2010,5000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E31',1990,3000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E31',2000,3000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E31',2010,3000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E51',1990,900.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E51',2000,900.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E51',2010,900.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E70',1990,1000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E70',2000,1000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E70',2010,1000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','RHE',1990,90.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','RHE',2000,90.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','RHE',2010,90.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','RHO',1990,100.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','RHO',2000,100.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','RHO',2010,100.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','SRE',1990,100.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','SRE',2000,100.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','SRE',2010,100.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXD',1990,1044.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXD',2000,1044.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXD',2010,1044.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXE',1990,2000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXE',2000,1750.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXE',2010,1500.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXG',1990,1044.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXG',2000,1044.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXG',2010,1044.0,'',''); CREATE TABLE cost_variable ( region TEXT NOT NULL, @@ -444,57 +391,57 @@ CREATE TABLE cost_variable notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_variable VALUES('utopia',1990,'IMPDSL1',1990,10.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'IMPDSL1',1990,10.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'IMPDSL1',1990,10.0,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'IMPGSL1',1990,15.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'IMPGSL1',1990,15.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'IMPGSL1',1990,15.0,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'IMPHCO1',1990,2.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'IMPHCO1',1990,2.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'IMPHCO1',1990,2.0,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'IMPOIL1',1990,8.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'IMPOIL1',1990,8.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'IMPOIL1',1990,8.0,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'IMPURN1',1990,2.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'IMPURN1',1990,2.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'IMPURN1',1990,2.0,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'E01',1960,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'E01',1970,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'E01',1980,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'E01',1990,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'E01',1970,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'E01',1980,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'E01',1990,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'E01',2000,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'E01',1980,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'E01',1990,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'E01',2000,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'E01',2010,0.2999999999999999889,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'E21',1990,1.5,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'E21',1990,1.5,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'E21',1990,1.5,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'E21',2000,1.5,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'E21',2000,1.5,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'E21',2010,1.5,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'E70',1960,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'E70',1970,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'E70',1980,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'E70',1990,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'E70',1970,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'E70',1980,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'E70',1990,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'E70',2000,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'E70',1980,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'E70',1990,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'E70',2000,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'E70',2010,0.4000000000000000222,'',''); -INSERT INTO cost_variable VALUES('utopia',1990,'SRE',1990,10.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'SRE',1990,10.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2000,'SRE',2000,10.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'SRE',1990,10.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'SRE',2000,10.0,'',''); -INSERT INTO cost_variable VALUES('utopia',2010,'SRE',2010,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPDSL1',1990,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPDSL1',1990,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPDSL1',1990,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPGSL1',1990,15.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPGSL1',1990,15.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPGSL1',1990,15.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPHCO1',1990,2.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPHCO1',1990,2.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPHCO1',1990,2.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPOIL1',1990,8.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPOIL1',1990,8.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPOIL1',1990,8.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPURN1',1990,2.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPURN1',1990,2.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPURN1',1990,2.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1960,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1970,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1980,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1990,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',1970,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',1980,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',1990,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',2000,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',1980,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',1990,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',2000,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',2010,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E21',1990,1.5,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E21',1990,1.5,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E21',1990,1.5,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E21',2000,1.5,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E21',2000,1.5,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E21',2010,1.5,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1960,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1970,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1980,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1990,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',1970,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',1980,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',1990,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',2000,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',1980,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',1990,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',2000,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',2010,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'SRE',1990,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'SRE',1990,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'SRE',2000,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'SRE',1990,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'SRE',2000,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'SRE',2010,10.0,'',''); CREATE TABLE demand ( region TEXT, @@ -507,24 +454,24 @@ CREATE TABLE demand notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO demand VALUES('utopia',1990,'RH',25.19999999999999929,'',''); -INSERT INTO demand VALUES('utopia',2000,'RH',37.79999999999999715,'',''); -INSERT INTO demand VALUES('utopia',2010,'RH',56.69999999999999574,'',''); -INSERT INTO demand VALUES('utopia',1990,'RL',5.599999999999999645,'',''); -INSERT INTO demand VALUES('utopia',2000,'RL',8.400000000000000355,'',''); -INSERT INTO demand VALUES('utopia',2010,'RL',12.59999999999999965,'',''); -INSERT INTO demand VALUES('utopia',1990,'TX',5.200000000000000177,'',''); -INSERT INTO demand VALUES('utopia',2000,'TX',7.799999999999999823,'',''); -INSERT INTO demand VALUES('utopia',2010,'TX',11.68999999999999951,'',''); +INSERT INTO "demand" VALUES('utopia',1990,'RH',25.2,'',''); +INSERT INTO "demand" VALUES('utopia',2000,'RH',37.8,'',''); +INSERT INTO "demand" VALUES('utopia',2010,'RH',5.66999999999999957e+01,'',''); +INSERT INTO "demand" VALUES('utopia',1990,'RL',5.6,'',''); +INSERT INTO "demand" VALUES('utopia',2000,'RL',8.4,'',''); +INSERT INTO "demand" VALUES('utopia',2010,'RL',12.6,'',''); +INSERT INTO "demand" VALUES('utopia',1990,'TX',5.2,'',''); +INSERT INTO "demand" VALUES('utopia',2000,'TX',7.8,'',''); +INSERT INTO "demand" VALUES('utopia',2010,'TX',11.69,'',''); CREATE TABLE demand_specific_distribution ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), demand_name TEXT REFERENCES commodity (name), dsd REAL, @@ -532,50 +479,36 @@ CREATE TABLE demand_specific_distribution PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO demand_specific_distribution VALUES('utopia',1990,'inter','day','RH',0.1199999999999999956,''); -INSERT INTO demand_specific_distribution VALUES('utopia',1990,'inter','night','RH',0.05999999999999999778,''); -INSERT INTO demand_specific_distribution VALUES('utopia',1990,'winter','day','RH',0.5466999999999999638,''); -INSERT INTO demand_specific_distribution VALUES('utopia',1990,'winter','night','RH',0.2732999999999999874,''); -INSERT INTO demand_specific_distribution VALUES('utopia',1990,'inter','day','RL',0.1499999999999999945,''); -INSERT INTO demand_specific_distribution VALUES('utopia',1990,'inter','night','RL',0.05000000000000000277,''); -INSERT INTO demand_specific_distribution VALUES('utopia',1990,'summer','day','RL',0.1499999999999999945,''); -INSERT INTO demand_specific_distribution VALUES('utopia',1990,'summer','night','RL',0.05000000000000000277,''); -INSERT INTO demand_specific_distribution VALUES('utopia',1990,'winter','day','RL',0.5,''); -INSERT INTO demand_specific_distribution VALUES('utopia',1990,'winter','night','RL',0.1000000000000000055,''); -INSERT INTO demand_specific_distribution VALUES('utopia',2000,'inter','day','RH',0.1199999999999999956,''); -INSERT INTO demand_specific_distribution VALUES('utopia',2000,'inter','night','RH',0.05999999999999999778,''); -INSERT INTO demand_specific_distribution VALUES('utopia',2000,'winter','day','RH',0.5466999999999999638,''); -INSERT INTO demand_specific_distribution VALUES('utopia',2000,'winter','night','RH',0.2732999999999999874,''); -INSERT INTO demand_specific_distribution VALUES('utopia',2000,'inter','day','RL',0.1499999999999999945,''); -INSERT INTO demand_specific_distribution VALUES('utopia',2000,'inter','night','RL',0.05000000000000000277,''); -INSERT INTO demand_specific_distribution VALUES('utopia',2000,'summer','day','RL',0.1499999999999999945,''); -INSERT INTO demand_specific_distribution VALUES('utopia',2000,'summer','night','RL',0.05000000000000000277,''); -INSERT INTO demand_specific_distribution VALUES('utopia',2000,'winter','day','RL',0.5,''); -INSERT INTO demand_specific_distribution VALUES('utopia',2000,'winter','night','RL',0.1000000000000000055,''); -INSERT INTO demand_specific_distribution VALUES('utopia',2010,'inter','day','RH',0.1199999999999999956,''); -INSERT INTO demand_specific_distribution VALUES('utopia',2010,'inter','night','RH',0.05999999999999999778,''); -INSERT INTO demand_specific_distribution VALUES('utopia',2010,'winter','day','RH',0.5466999999999999638,''); -INSERT INTO demand_specific_distribution VALUES('utopia',2010,'winter','night','RH',0.2732999999999999874,''); -INSERT INTO demand_specific_distribution VALUES('utopia',2010,'inter','day','RL',0.1499999999999999945,''); -INSERT INTO demand_specific_distribution VALUES('utopia',2010,'inter','night','RL',0.05000000000000000277,''); -INSERT INTO demand_specific_distribution VALUES('utopia',2010,'summer','day','RL',0.1499999999999999945,''); -INSERT INTO demand_specific_distribution VALUES('utopia',2010,'summer','night','RL',0.05000000000000000277,''); -INSERT INTO demand_specific_distribution VALUES('utopia',2010,'winter','day','RL',0.5,''); -INSERT INTO demand_specific_distribution VALUES('utopia',2010,'winter','night','RL',0.1000000000000000055,''); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','day','RH',0.12,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','night','RH',0.06,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','day','RH',0.5467,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','night','RH',0.2733,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'summer','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'summer','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','day','RL',0.5,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','night','RL',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','day','RH',0.12,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','night','RH',0.06,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','day','RH',0.5467,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','night','RH',0.2733,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'summer','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'summer','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','day','RL',0.5,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','night','RL',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','day','RH',0.12,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','night','RH',0.06,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','day','RH',0.5467,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','night','RH',0.2733,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'summer','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'summer','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','day','RL',0.5,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','night','RL',0.1,''); CREATE TABLE efficiency ( region TEXT, @@ -592,79 +525,79 @@ CREATE TABLE efficiency PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO efficiency VALUES('utopia','ethos','IMPDSL1',1990,'DSL',1.0,''); -INSERT INTO efficiency VALUES('utopia','ethos','IMPGSL1',1990,'GSL',1.0,''); -INSERT INTO efficiency VALUES('utopia','ethos','IMPHCO1',1990,'HCO',1.0,''); -INSERT INTO efficiency VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,''); -INSERT INTO efficiency VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,''); -INSERT INTO efficiency VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,''); -INSERT INTO efficiency VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,''); -INSERT INTO efficiency VALUES('utopia','HCO','E01',1960,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','HCO','E01',1970,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','HCO','E01',1980,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','HCO','E01',1990,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','HCO','E01',2000,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','HCO','E01',2010,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','FEQ','E21',1990,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','FEQ','E21',2000,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','FEQ','E21',2010,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','URN','E21',1990,'ELC',0.4000000000000000222,'# 1/2.5'); -INSERT INTO efficiency VALUES('utopia','URN','E21',2000,'ELC',0.4000000000000000222,'# 1/2.5'); -INSERT INTO efficiency VALUES('utopia','URN','E21',2010,'ELC',0.4000000000000000222,'# 1/2.5'); -INSERT INTO efficiency VALUES('utopia','HYD','E31',1980,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','HYD','E31',1990,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','HYD','E31',2000,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','HYD','E31',2010,'ELC',0.3200000000000000066,'# 1/3.125'); -INSERT INTO efficiency VALUES('utopia','DSL','E70',1960,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO efficiency VALUES('utopia','DSL','E70',1970,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO efficiency VALUES('utopia','DSL','E70',1980,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO efficiency VALUES('utopia','DSL','E70',1990,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO efficiency VALUES('utopia','DSL','E70',2000,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO efficiency VALUES('utopia','DSL','E70',2010,'ELC',0.2939999999999999836,'# 1/3.4'); -INSERT INTO efficiency VALUES('utopia','ELC','E51',1980,'ELC',0.7199999999999999734,'# 1/1.3889'); -INSERT INTO efficiency VALUES('utopia','ELC','E51',1990,'ELC',0.7199999999999999734,'# 1/1.3889'); -INSERT INTO efficiency VALUES('utopia','ELC','E51',2000,'ELC',0.7199999999999999734,'# 1/1.3889'); -INSERT INTO efficiency VALUES('utopia','ELC','E51',2010,'ELC',0.7199999999999999734,'# 1/1.3889'); -INSERT INTO efficiency VALUES('utopia','ELC','RHE',1990,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','ELC','RHE',2000,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','ELC','RHE',2010,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','DSL','RHO',1970,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','DSL','RHO',1980,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','DSL','RHO',1990,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','DSL','RHO',2000,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','DSL','RHO',2010,'RH',0.6999999999999999556,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','ELC','RL1',1980,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','ELC','RL1',1990,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','ELC','RL1',2000,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','ELC','RL1',2010,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','OIL','SRE',1990,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO efficiency VALUES('utopia','OIL','SRE',2000,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO efficiency VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO efficiency VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO efficiency VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO efficiency VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO efficiency VALUES('utopia','DSL','TXD',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','DSL','TXD',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','DSL','TXD',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','DSL','TXD',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','DSL','TXD',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','ELC','TXE',1990,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','ELC','TXE',2000,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','ELC','TXE',2010,'TX',0.8269999999999999574,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','GSL','TXG',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','GSL','TXG',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','GSL','TXG',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','GSL','TXG',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); -INSERT INTO efficiency VALUES('utopia','GSL','TXG',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPDSL1',1990,'DSL',1.0,''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPGSL1',1990,'GSL',1.0,''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPHCO1',1990,'HCO',1.0,''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,''); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1960,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1970,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1980,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1990,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',2000,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',2010,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','FEQ','E21',1990,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','FEQ','E21',2000,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','FEQ','E21',2010,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','URN','E21',1990,'ELC',0.4,'# 1/2.5'); +INSERT INTO "efficiency" VALUES('utopia','URN','E21',2000,'ELC',0.4,'# 1/2.5'); +INSERT INTO "efficiency" VALUES('utopia','URN','E21',2010,'ELC',0.4,'# 1/2.5'); +INSERT INTO "efficiency" VALUES('utopia','HYD','E31',1980,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HYD','E31',1990,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HYD','E31',2000,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HYD','E31',2010,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1960,'ELC',0.294,'# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1970,'ELC',0.294,'# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1980,'ELC',0.294,'# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1990,'ELC',0.294,'# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',2000,'ELC',0.294,'# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',2010,'ELC',0.294,'# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','ELC','E51',1980,'ELC',0.72,'# 1/1.3889'); +INSERT INTO "efficiency" VALUES('utopia','ELC','E51',1990,'ELC',0.72,'# 1/1.3889'); +INSERT INTO "efficiency" VALUES('utopia','ELC','E51',2000,'ELC',0.72,'# 1/1.3889'); +INSERT INTO "efficiency" VALUES('utopia','ELC','E51',2010,'ELC',0.72,'# 1/1.3889'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RHE',1990,'RH',1.0,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RHE',2000,'RH',1.0,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RHE',2010,'RH',1.0,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',1970,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',1980,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',1990,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',2000,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',2010,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',1980,'RL',1.0,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',1990,'RL',1.0,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',2000,'RL',1.0,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',2010,'RL',1.0,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',1990,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2000,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',1970,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',1980,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',1990,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',2000,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',2010,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','TXE',1990,'TX',0.827,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','TXE',2000,'TX',0.827,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','TXE',2010,'TX',0.827,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',1970,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',1980,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',1990,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',2000,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',2010,'TX',0.231,'# direct translation from DMD_EFF'); CREATE TABLE efficiency_variable ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -696,20 +629,20 @@ CREATE TABLE emission_activity notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.07499999999999999723,'',''); -INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.07499999999999999723,'',''); -INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',0.0889999999999999819,'',''); -INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.07499999999999999723,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',1970,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',1980,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',1990,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',2000,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',2010,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',1970,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',1980,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',1990,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',2000,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',2010,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.075,'',''); +INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.075,'',''); +INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',8.89999999999999819e-02,'',''); +INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.075,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1970,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1980,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1990,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',2000,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',2010,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1970,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1980,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1990,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',2000,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',2010,'TX',1.0,'',''); CREATE TABLE emission_embodied ( region TEXT, @@ -722,7 +655,7 @@ CREATE TABLE emission_embodied value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) ); CREATE TABLE emission_end_of_life ( @@ -736,7 +669,21 @@ CREATE TABLE emission_end_of_life value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE end_of_life_output +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) ); CREATE TABLE existing_capacity ( @@ -750,28 +697,22 @@ CREATE TABLE existing_capacity notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO existing_capacity VALUES('utopia','E01',1960,0.1749999999999999889,'',''); -INSERT INTO existing_capacity VALUES('utopia','E01',1970,0.1749999999999999889,'',''); -INSERT INTO existing_capacity VALUES('utopia','E01',1980,0.1499999999999999945,'',''); -INSERT INTO existing_capacity VALUES('utopia','E31',1980,0.1000000000000000055,'',''); -INSERT INTO existing_capacity VALUES('utopia','E51',1980,0.5,'',''); -INSERT INTO existing_capacity VALUES('utopia','E70',1960,0.05000000000000000277,'',''); -INSERT INTO existing_capacity VALUES('utopia','E70',1970,0.05000000000000000277,'',''); -INSERT INTO existing_capacity VALUES('utopia','E70',1980,0.2000000000000000111,'',''); -INSERT INTO existing_capacity VALUES('utopia','RHO',1970,12.5,'',''); -INSERT INTO existing_capacity VALUES('utopia','RHO',1980,12.5,'',''); -INSERT INTO existing_capacity VALUES('utopia','RL1',1980,5.599999999999999645,'',''); -INSERT INTO existing_capacity VALUES('utopia','TXD',1970,0.4000000000000000222,'',''); -INSERT INTO existing_capacity VALUES('utopia','TXD',1980,0.2000000000000000111,'',''); -INSERT INTO existing_capacity VALUES('utopia','TXG',1970,3.100000000000000088,'',''); -INSERT INTO existing_capacity VALUES('utopia','TXG',1980,1.5,'',''); -CREATE TABLE TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE loan_lifetime_process +INSERT INTO "existing_capacity" VALUES('utopia','E01',1960,0.175,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','E01',1970,0.175,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','E01',1980,0.15,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','E31',1980,0.1,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','E51',1980,0.5,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','E70',1960,0.05,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','E70',1970,0.05,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','E70',1980,0.2,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','RHO',1970,12.5,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','RHO',1980,12.5,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','RL1',1980,5.6,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','TXD',1970,0.4,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','TXD',1980,0.2,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','TXG',1970,3.1,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','TXG',1980,1.5,'',''); +CREATE TABLE lifetime_process ( region TEXT, tech TEXT @@ -782,174 +723,230 @@ CREATE TABLE loan_lifetime_process notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE loan_rate +INSERT INTO "lifetime_process" VALUES('utopia','RL1',1980,20.0,'#forexistingcap'); +INSERT INTO "lifetime_process" VALUES('utopia','TXD',1970,30.0,'#forexistingcap'); +INSERT INTO "lifetime_process" VALUES('utopia','TXD',1980,30.0,'#forexistingcap'); +INSERT INTO "lifetime_process" VALUES('utopia','TXG',1970,30.0,'#forexistingcap'); +INSERT INTO "lifetime_process" VALUES('utopia','TXG',1980,30.0,'#forexistingcap'); +CREATE TABLE lifetime_survival_curve ( - region TEXT, - tech TEXT + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL REFERENCES technology (tech), - vintage INTEGER + vintage INTEGER NOT NULL REFERENCES time_period (period), - rate REAL, + fraction REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, period, tech, vintage) ); -CREATE TABLE lifetime_process +CREATE TABLE lifetime_tech ( region TEXT, tech TEXT REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), lifetime REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, tech) ); -INSERT INTO lifetime_process VALUES('utopia','RL1',1980,20.0,'#forexistingcap'); -INSERT INTO lifetime_process VALUES('utopia','TXD',1970,30.0,'#forexistingcap'); -INSERT INTO lifetime_process VALUES('utopia','TXD',1980,30.0,'#forexistingcap'); -INSERT INTO lifetime_process VALUES('utopia','TXG',1970,30.0,'#forexistingcap'); -INSERT INTO lifetime_process VALUES('utopia','TXG',1980,30.0,'#forexistingcap'); -CREATE TABLE lifetime_tech +INSERT INTO "lifetime_tech" VALUES('utopia','E01',40.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','E21',40.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','E31',100.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','E51',100.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','E70',40.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','RHE',30.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','RHO',30.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','RL1',10.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','SRE',50.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','TXD',15.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','TXE',15.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','TXG',15.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPDSL1',1000.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPGSL1',1000.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPHCO1',1000.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPOIL1',1000.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPURN1',1000.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPHYD',1000.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPFEQ',1000.0,''); +CREATE TABLE limit_activity ( - region TEXT, - tech TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE limit_activity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_annual_capacity_factor +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator), + CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO lifetime_tech VALUES('utopia','E01',40.0,''); -INSERT INTO lifetime_tech VALUES('utopia','E21',40.0,''); -INSERT INTO lifetime_tech VALUES('utopia','E31',100.0,''); -INSERT INTO lifetime_tech VALUES('utopia','E51',100.0,''); -INSERT INTO lifetime_tech VALUES('utopia','E70',40.0,''); -INSERT INTO lifetime_tech VALUES('utopia','RHE',30.0,''); -INSERT INTO lifetime_tech VALUES('utopia','RHO',30.0,''); -INSERT INTO lifetime_tech VALUES('utopia','RL1',10.0,''); -INSERT INTO lifetime_tech VALUES('utopia','SRE',50.0,''); -INSERT INTO lifetime_tech VALUES('utopia','TXD',15.0,''); -INSERT INTO lifetime_tech VALUES('utopia','TXE',15.0,''); -INSERT INTO lifetime_tech VALUES('utopia','TXG',15.0,''); -INSERT INTO lifetime_tech VALUES('utopia','IMPDSL1',1000.0,''); -INSERT INTO lifetime_tech VALUES('utopia','IMPGSL1',1000.0,''); -INSERT INTO lifetime_tech VALUES('utopia','IMPHCO1',1000.0,''); -INSERT INTO lifetime_tech VALUES('utopia','IMPOIL1',1000.0,''); -INSERT INTO lifetime_tech VALUES('utopia','IMPURN1',1000.0,''); -INSERT INTO lifetime_tech VALUES('utopia','IMPHYD',1000.0,''); -INSERT INTO lifetime_tech VALUES('utopia','IMPFEQ',1000.0,''); -CREATE TABLE Operator +CREATE TABLE limit_capacity ( - operator TEXT PRIMARY KEY, - notes TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO Operator VALUES('e','equal to'); -INSERT INTO Operator VALUES('le','less than or equal to'); -INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE limit_growth_capacity +INSERT INTO "limit_capacity" VALUES('utopia',1990,'E31','ge',0.13,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',2000,'E31','ge',0.13,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',2010,'E31','ge',0.13,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',1990,'SRE','ge',0.1,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',1990,'E31','le',0.13,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',2000,'E31','le',0.17,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',2010,'E31','le',2.1000000000000002e-01,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',1990,'RHE','le',0.0,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',1990,'TXD','le',0.6,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',2000,'TXD','le',1.76,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',2010,'TXD','le',4.76,'',''); +CREATE TABLE limit_capacity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_capacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity +CREATE TABLE limit_emission +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitStorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -CREATE TABLE limit_activity +CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, + REFERENCES operator (operator), + new_cap REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, tech_or_group, operator) ); -CREATE TABLE limit_activity_share +CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER @@ -957,116 +954,56 @@ CREATE TABLE limit_activity_share sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), share REAL, notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) ); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity +CREATE TABLE limit_resource ( region TEXT, - period INTEGER - REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, + REFERENCES operator (operator), + cum_act REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) + PRIMARY KEY (region, tech_or_group, operator) ); -INSERT INTO limit_capacity VALUES('utopia',1990,'E31','ge',0.1300000000000000044,'',''); -INSERT INTO limit_capacity VALUES('utopia',2000,'E31','ge',0.1300000000000000044,'',''); -INSERT INTO limit_capacity VALUES('utopia',2010,'E31','ge',0.1300000000000000044,'',''); -INSERT INTO limit_capacity VALUES('utopia',1990,'SRE','ge',0.1000000000000000055,'',''); -INSERT INTO limit_capacity VALUES('utopia',1990,'E31','le',0.1300000000000000044,'',''); -INSERT INTO limit_capacity VALUES('utopia',2000,'E31','le',0.1700000000000000122,'',''); -INSERT INTO limit_capacity VALUES('utopia',2010,'E31','le',0.21000000000000002,'',''); -INSERT INTO limit_capacity VALUES('utopia',1990,'RHE','le',0.0,'',''); -INSERT INTO limit_capacity VALUES('utopia',1990,'TXD','le',0.5999999999999999778,'',''); -INSERT INTO limit_capacity VALUES('utopia',2000,'TXD','le',1.760000000000000008,'',''); -INSERT INTO limit_capacity VALUES('utopia',2010,'TXD','le',4.759999999999999787,'',''); -CREATE TABLE limit_capacity_share +CREATE TABLE limit_seasonal_capacity_factor ( - region TEXT, - period INTEGER + region TEXT + REFERENCES region (region), + period INTEGER REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, + season TEXT + REFERENCES season_label (season), + tech TEXT + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) ); -CREATE TABLE limit_new_capacity +CREATE TABLE limit_storage_level_fraction ( - region TEXT, - period INTEGER + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), - tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) + REFERENCES operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) ); CREATE TABLE limit_tech_input_split ( @@ -1078,7 +1015,7 @@ CREATE TABLE limit_tech_input_split tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -1093,7 +1030,7 @@ CREATE TABLE limit_tech_input_split_annual tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -1108,17 +1045,17 @@ CREATE TABLE limit_tech_output_split output_comm TEXT REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -INSERT INTO limit_tech_output_split VALUES('utopia',1990,'SRE','DSL','ge',0.6999999999999999556,''); -INSERT INTO limit_tech_output_split VALUES('utopia',2000,'SRE','DSL','ge',0.6999999999999999556,''); -INSERT INTO limit_tech_output_split VALUES('utopia',2010,'SRE','DSL','ge',0.6999999999999999556,''); -INSERT INTO limit_tech_output_split VALUES('utopia',1990,'SRE','GSL','ge',0.2999999999999999889,''); -INSERT INTO limit_tech_output_split VALUES('utopia',2000,'SRE','GSL','ge',0.2999999999999999889,''); -INSERT INTO limit_tech_output_split VALUES('utopia',2010,'SRE','GSL','ge',0.2999999999999999889,''); +INSERT INTO "limit_tech_output_split" VALUES('utopia',1990,'SRE','DSL','ge',0.7,''); +INSERT INTO "limit_tech_output_split" VALUES('utopia',2000,'SRE','DSL','ge',0.7,''); +INSERT INTO "limit_tech_output_split" VALUES('utopia',2010,'SRE','DSL','ge',0.7,''); +INSERT INTO "limit_tech_output_split" VALUES('utopia',1990,'SRE','GSL','ge',0.3,''); +INSERT INTO "limit_tech_output_split" VALUES('utopia',2000,'SRE','GSL','ge',0.3,''); +INSERT INTO "limit_tech_output_split" VALUES('utopia',2010,'SRE','GSL','ge',0.3,''); CREATE TABLE limit_tech_output_split_annual ( region TEXT, @@ -1129,26 +1066,12 @@ CREATE TABLE limit_tech_output_split_annual output_comm TEXT REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE LinkedTech +CREATE TABLE linked_tech ( primary_region TEXT, primary_tech TEXT @@ -1160,6 +1083,103 @@ CREATE TABLE LinkedTech notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); +CREATE TABLE loan_lifetime_process +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE loan_rate +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE metadata +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); +INSERT INTO "metadata" VALUES('DB_MINOR',0,''); +CREATE TABLE metadata_real +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,''); +CREATE TABLE myopic_efficiency +( + base_year integer, + region text, + input_comm text, + tech text, + vintage integer, + output_comm text, + efficiency real, + lifetime integer, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (region, input_comm, tech, vintage, output_comm) +); +CREATE TABLE operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "operator" VALUES('e','equal to'); +INSERT INTO "operator" VALUES('le','less than or equal to'); +INSERT INTO "operator" VALUES('ge','greater than or equal to'); +CREATE TABLE output_built_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE output_cost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) +); CREATE TABLE output_curtailment ( scenario TEXT, @@ -1170,7 +1190,7 @@ CREATE TABLE output_curtailment season TEXT REFERENCES time_period (period), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -1182,62 +1202,42 @@ CREATE TABLE output_curtailment curtailment REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputNetCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_built_capacity +CREATE TABLE output_dual_variable ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE output_emission ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), - tech TEXT + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT REFERENCES technology (tech), - vintage INTEGER + vintage INTEGER REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE OutputFlowIn +CREATE TABLE output_flow_in ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -1249,18 +1249,18 @@ CREATE TABLE OutputFlowIn flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputFlowOut +CREATE TABLE output_flow_out ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT REFERENCES commodity (name), tech TEXT @@ -1272,18 +1272,70 @@ CREATE TABLE OutputFlowOut flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); +CREATE TABLE output_flow_out_summary +( + scenario TEXT NOT NULL, + region TEXT NOT NULL, + sector TEXT, + period INTEGER, + input_comm TEXT NOT NULL, + tech TEXT NOT NULL, + vintage INTEGER, + output_comm TEXT NOT NULL, + flow REAL NOT NULL, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_net_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_objective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE output_retired_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), vintage INTEGER @@ -1323,14 +1375,14 @@ CREATE TABLE region PRIMARY KEY, notes TEXT ); -INSERT INTO region VALUES('utopia',NULL); +INSERT INTO "region" VALUES('utopia',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tech TEXT REFERENCES technology (tech), vintage INTEGER, @@ -1339,37 +1391,36 @@ CREATE TABLE reserve_capacity_derate PRIMARY KEY (region, period, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE TimeSegmentFraction +CREATE TABLE rps_requirement ( - period INTEGER + region TEXT NOT NULL + REFERENCES region (region), + period INTEGER NOT NULL REFERENCES time_period (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) -); -INSERT INTO TimeSegmentFraction VALUES(1990,'inter','day',0.166699999999999987,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(1990,'inter','night',0.08329999999999999905,'# I-N'); -INSERT INTO TimeSegmentFraction VALUES(1990,'summer','day',0.166699999999999987,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(1990,'summer','night',0.08329999999999999905,'# S-N'); -INSERT INTO TimeSegmentFraction VALUES(1990,'winter','day',0.3332999999999999852,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(1990,'winter','night',0.166699999999999987,'# W-N'); -INSERT INTO TimeSegmentFraction VALUES(2000,'inter','day',0.166699999999999987,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2000,'inter','night',0.08329999999999999905,'# I-N'); -INSERT INTO TimeSegmentFraction VALUES(2000,'summer','day',0.166699999999999987,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2000,'summer','night',0.08329999999999999905,'# S-N'); -INSERT INTO TimeSegmentFraction VALUES(2000,'winter','day',0.3332999999999999852,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2000,'winter','night',0.166699999999999987,'# W-N'); -INSERT INTO TimeSegmentFraction VALUES(2010,'inter','day',0.166699999999999987,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'inter','night',0.08329999999999999905,'# I-N'); -INSERT INTO TimeSegmentFraction VALUES(2010,'summer','day',0.166699999999999987,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'summer','night',0.08329999999999999905,'# S-N'); -INSERT INTO TimeSegmentFraction VALUES(2010,'winter','day',0.3332999999999999852,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'winter','night',0.166699999999999987,'# W-N'); + tech_group TEXT NOT NULL + REFERENCES tech_group (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE season_label +( + season TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "season_label" VALUES('inter',NULL); +INSERT INTO "season_label" VALUES('summer',NULL); +INSERT INTO "season_label" VALUES('winter',NULL); +CREATE TABLE sector_label +( + sector TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "sector_label" VALUES('supply',NULL); +INSERT INTO "sector_label" VALUES('electric',NULL); +INSERT INTO "sector_label" VALUES('transport',NULL); +INSERT INTO "sector_label" VALUES('commercial',NULL); +INSERT INTO "sector_label" VALUES('residential',NULL); +INSERT INTO "sector_label" VALUES('industrial',NULL); CREATE TABLE storage_duration ( region TEXT, @@ -1378,181 +1429,178 @@ CREATE TABLE storage_duration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE lifetime_survival_curve +CREATE TABLE tech_group ( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE tech_group_member +( + group_name TEXT + REFERENCES tech_group (group_name), + tech TEXT REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) + PRIMARY KEY (group_name, tech) ); -CREATE TABLE technologyType +CREATE TABLE technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES technology_type (label) +); +INSERT INTO "technology" VALUES('IMPDSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported diesel'); +INSERT INTO "technology" VALUES('IMPGSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported gasoline'); +INSERT INTO "technology" VALUES('IMPHCO1','p','supply','coal','',1,0,0,0,0,0,0,0,' imported coal'); +INSERT INTO "technology" VALUES('IMPOIL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported crude oil'); +INSERT INTO "technology" VALUES('IMPURN1','p','supply','nuclear','',1,0,0,0,0,0,0,0,' imported uranium'); +INSERT INTO "technology" VALUES('IMPFEQ','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported fossil equivalent'); +INSERT INTO "technology" VALUES('IMPHYD','p','supply','hydro','',1,0,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); +INSERT INTO "technology" VALUES('E01','pb','electric','coal','',0,0,0,0,0,0,0,0,' coal power plant'); +INSERT INTO "technology" VALUES('E21','pb','electric','nuclear','',0,0,0,0,0,0,0,0,' nuclear power plant'); +INSERT INTO "technology" VALUES('E31','pb','electric','hydro','',0,0,0,0,0,0,0,0,' hydro power'); +INSERT INTO "technology" VALUES('E51','ps','electric','electric','',0,0,0,0,0,0,0,0,' electric storage'); +INSERT INTO "technology" VALUES('E70','p','electric','petroleum','',0,0,0,0,0,0,0,0,' diesel power plant'); +INSERT INTO "technology" VALUES('RHE','p','residential','electric','',0,0,0,0,0,0,0,0,' electric residential heating'); +INSERT INTO "technology" VALUES('RHO','p','residential','petroleum','',0,0,0,0,0,0,0,0,' diesel residential heating'); +INSERT INTO "technology" VALUES('RL1','p','residential','electric','',0,0,0,0,0,0,0,0,' residential lighting'); +INSERT INTO "technology" VALUES('SRE','p','supply','petroleum','',0,0,0,0,0,0,0,0,' crude oil processor'); +INSERT INTO "technology" VALUES('TXD','p','transport','petroleum','',0,0,0,0,0,0,0,0,' diesel powered vehicles'); +INSERT INTO "technology" VALUES('TXE','p','transport','electric','',0,0,0,0,0,0,0,0,' electric powered vehicles'); +INSERT INTO "technology" VALUES('TXG','p','transport','petroleum','',0,0,0,0,0,0,0,0,' gasoline powered vehicles'); +CREATE TABLE technology_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO technologyType VALUES('p','production technology'); -INSERT INTO technologyType VALUES('pb','baseload production technology'); -INSERT INTO technologyType VALUES('ps','storage production technology'); -CREATE TABLE TimeOfDay +INSERT INTO "technology_type" VALUES('p','production technology'); +INSERT INTO "technology_type" VALUES('pb','baseload production technology'); +INSERT INTO "technology_type" VALUES('ps','storage production technology'); +CREATE TABLE time_of_day ( sequence INTEGER UNIQUE, tod TEXT PRIMARY KEY ); -INSERT INTO TimeOfDay VALUES(1,'day'); -INSERT INTO TimeOfDay VALUES(2,'night'); +INSERT INTO "time_of_day" VALUES(1,'day'); +INSERT INTO "time_of_day" VALUES(2,'night'); CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES time_periodType (label) + REFERENCES time_period_type (label) ); -INSERT INTO time_period VALUES(1,1960,'e'); -INSERT INTO time_period VALUES(2,1970,'e'); -INSERT INTO time_period VALUES(3,1980,'e'); -INSERT INTO time_period VALUES(4,1990,'f'); -INSERT INTO time_period VALUES(5,2000,'f'); -INSERT INTO time_period VALUES(6,2010,'f'); -INSERT INTO time_period VALUES(7,2020,'f'); -CREATE TABLE TimeSeason +INSERT INTO "time_period" VALUES(1,1960,'e'); +INSERT INTO "time_period" VALUES(2,1970,'e'); +INSERT INTO "time_period" VALUES(3,1980,'e'); +INSERT INTO "time_period" VALUES(4,1990,'f'); +INSERT INTO "time_period" VALUES(5,2000,'f'); +INSERT INTO "time_period" VALUES(6,2010,'f'); +INSERT INTO "time_period" VALUES(7,2020,'f'); +CREATE TABLE time_period_type +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO "time_period_type" VALUES('e','existing vintages'); +INSERT INTO "time_period_type" VALUES('f','future'); +CREATE TABLE time_season +( + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + season TEXT REFERENCES season_label(season), + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +INSERT INTO "time_season" VALUES(1990,1,'inter',NULL); +INSERT INTO "time_season" VALUES(1990,2,'summer',NULL); +INSERT INTO "time_season" VALUES(1990,3,'winter',NULL); +INSERT INTO "time_season" VALUES(2000,1,'inter',NULL); +INSERT INTO "time_season" VALUES(2000,2,'summer',NULL); +INSERT INTO "time_season" VALUES(2000,3,'winter',NULL); +INSERT INTO "time_season" VALUES(2010,1,'inter',NULL); +INSERT INTO "time_season" VALUES(2010,2,'summer',NULL); +INSERT INTO "time_season" VALUES(2010,3,'winter',NULL); +CREATE TABLE time_season_all ( period INTEGER REFERENCES time_period (period), sequence INTEGER, season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); -INSERT INTO TimeSeason VALUES(1990,1,'inter',NULL); -INSERT INTO TimeSeason VALUES(1990,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(1990,3,'winter',NULL); -INSERT INTO TimeSeason VALUES(2000,1,'inter',NULL); -INSERT INTO TimeSeason VALUES(2000,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(2000,3,'winter',NULL); -INSERT INTO TimeSeason VALUES(2010,1,'inter',NULL); -INSERT INTO TimeSeason VALUES(2010,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(2010,3,'winter',NULL); CREATE TABLE time_season_sequential ( - period INTEGER - REFERENCES time_period (period), + period INTEGER REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES SeasonLabel (season), + season TEXT REFERENCES season_label(season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE time_periodType -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO time_periodType VALUES('e','existing vintages'); -INSERT INTO time_periodType VALUES('f','future'); -CREATE TABLE OutputEmission +CREATE TABLE time_season_to_sequential ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER + period INTEGER REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) + sequence INTEGER, + seas_seq TEXT, + season TEXT + REFERENCES season_label (season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) ); -CREATE TABLE RPSRequirement +CREATE TABLE time_segment_fraction ( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL + period INTEGER REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES TechGroup (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE TechGroupMember -( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technologyType (label) -); -INSERT INTO technology VALUES('IMPDSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported diesel'); -INSERT INTO technology VALUES('IMPGSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported gasoline'); -INSERT INTO technology VALUES('IMPHCO1','p','supply','coal','',1,0,0,0,0,0,0,0,' imported coal'); -INSERT INTO technology VALUES('IMPOIL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO technology VALUES('IMPURN1','p','supply','nuclear','',1,0,0,0,0,0,0,0,' imported uranium'); -INSERT INTO technology VALUES('IMPFEQ','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported fossil equivalent'); -INSERT INTO technology VALUES('IMPHYD','p','supply','hydro','',1,0,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); -INSERT INTO technology VALUES('E01','pb','electric','coal','',0,0,0,0,0,0,0,0,' coal power plant'); -INSERT INTO technology VALUES('E21','pb','electric','nuclear','',0,0,0,0,0,0,0,0,' nuclear power plant'); -INSERT INTO technology VALUES('E31','pb','electric','hydro','',0,0,0,0,0,0,0,0,' hydro power'); -INSERT INTO technology VALUES('E51','ps','electric','electric','',0,0,0,0,0,0,0,0,' electric storage'); -INSERT INTO technology VALUES('E70','p','electric','petroleum','',0,0,0,0,0,0,0,0,' diesel power plant'); -INSERT INTO technology VALUES('RHE','p','residential','electric','',0,0,0,0,0,0,0,0,' electric residential heating'); -INSERT INTO technology VALUES('RHO','p','residential','petroleum','',0,0,0,0,0,0,0,0,' diesel residential heating'); -INSERT INTO technology VALUES('RL1','p','residential','electric','',0,0,0,0,0,0,0,0,' residential lighting'); -INSERT INTO technology VALUES('SRE','p','supply','petroleum','',0,0,0,0,0,0,0,0,' crude oil processor'); -INSERT INTO technology VALUES('TXD','p','transport','petroleum','',0,0,0,0,0,0,0,0,' diesel powered vehicles'); -INSERT INTO technology VALUES('TXE','p','transport','electric','',0,0,0,0,0,0,0,0,' electric powered vehicles'); -INSERT INTO technology VALUES('TXG','p','transport','petroleum','',0,0,0,0,0,0,0,0,' gasoline powered vehicles'); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) -); + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + segment_fraction REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) +); +INSERT INTO "time_segment_fraction" VALUES(1990,'inter','day',0.1667,'# I-D'); +INSERT INTO "time_segment_fraction" VALUES(1990,'inter','night',0.0833,'# I-N'); +INSERT INTO "time_segment_fraction" VALUES(1990,'summer','day',0.1667,'# S-D'); +INSERT INTO "time_segment_fraction" VALUES(1990,'summer','night',0.0833,'# S-N'); +INSERT INTO "time_segment_fraction" VALUES(1990,'winter','day',0.3333,'# W-D'); +INSERT INTO "time_segment_fraction" VALUES(1990,'winter','night',0.1667,'# W-N'); +INSERT INTO "time_segment_fraction" VALUES(2000,'inter','day',0.1667,'# I-D'); +INSERT INTO "time_segment_fraction" VALUES(2000,'inter','night',0.0833,'# I-N'); +INSERT INTO "time_segment_fraction" VALUES(2000,'summer','day',0.1667,'# S-D'); +INSERT INTO "time_segment_fraction" VALUES(2000,'summer','night',0.0833,'# S-N'); +INSERT INTO "time_segment_fraction" VALUES(2000,'winter','day',0.3333,'# W-D'); +INSERT INTO "time_segment_fraction" VALUES(2000,'winter','night',0.1667,'# W-N'); +INSERT INTO "time_segment_fraction" VALUES(2010,'inter','day',0.1667,'# I-D'); +INSERT INTO "time_segment_fraction" VALUES(2010,'inter','night',0.0833,'# I-N'); +INSERT INTO "time_segment_fraction" VALUES(2010,'summer','day',0.1667,'# S-D'); +INSERT INTO "time_segment_fraction" VALUES(2010,'summer','night',0.0833,'# S-N'); +INSERT INTO "time_segment_fraction" VALUES(2010,'winter','day',0.3333,'# W-D'); +INSERT INTO "time_segment_fraction" VALUES(2010,'winter','night',0.1667,'# W-N'); +CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; From c138e43737210dceb8927c0601ebabc46811b543 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 8 Nov 2025 10:57:29 -0500 Subject: [PATCH 317/587] tests updated for DBv4 --- docs/source/Documentation.rst | 4 ++-- temoa/components/time.py | 26 ++++++++++++------------- temoa/data_io/component_manifest.py | 4 ++-- temoa/data_io/hybrid_loader.py | 4 ++-- tests/testing_data/seasonal_storage.sql | 15 ++------------ 5 files changed, 21 insertions(+), 32 deletions(-) diff --git a/docs/source/Documentation.rst b/docs/source/Documentation.rst index 9a7fc5ca0..46f84969c 100644 --- a/docs/source/Documentation.rst +++ b/docs/source/Documentation.rst @@ -340,7 +340,7 @@ recommend that you populate input tables in the following order: * emission_activity * lifetime_tech * lifetime_process (only if LT varies by vintage; overwrites lifetime_tech) - * TimeSegmentFraction: proportion of each period represented by each time slice + * time_segment_fraction: proportion of each period represented by each time slice **Group 4: parameters used to define constraints within Temoa** * limit_activity @@ -1150,7 +1150,7 @@ DemandDefaultDistribution **Note**: The Demand Specific Distribution is currently not supported in the project. Modelers should use the DSD or rely on a "flat" distribution default -from the TimeSegmentFraction. +from the time_segment_fraction. By default, Temoa assumes that end-use demands (:ref:`Demand`) are evenly distributed throughout a year. In other words, the Demand will be apportioned diff --git a/temoa/components/time.py b/temoa/components/time.py index be1e3e3a2..77cee17cc 100644 --- a/temoa/components/time.py +++ b/temoa/components/time.py @@ -4,7 +4,7 @@ It is responsible for: - Validating the core time sets (`time_exist`, `time_future`). -- Validating the user-defined time-slice fractions (`TimeSegmentFraction`). +- Validating the user-defined time-slice fractions (`time_segment_fraction`). - Creating the sequence of time slices (`time_next`) based on the chosen sequencing method (e.g., `seasonal_timeslices`, `consecutive_days`). - Creating and validating the superimposed sequential seasons used for @@ -102,9 +102,9 @@ def validate_segment_fraction(model: TemoaModel) -> None: extra: set[tuple[int, str, str]] = keys.difference(expected_keys) missing: set[tuple[int, str, str]] = expected_keys.difference(keys) msg: str = ( - 'TimeSegmentFraction elements for period {} do not match time_season and time_of_day.' - '\n\nIndices missing from TimeSegmentFraction:\n{}' - '\n\nIndices in TimeSegmentFraction missing from time_season/time_of_day:\n{}' + 'time_segment_fraction elements for period {} do not match time_season and time_of_day.' + '\n\nIndices missing from time_segment_fraction:\n{}' + '\n\nIndices in time_segment_fraction missing from time_season/time_of_day:\n{}' ).format(p, missing, extra) logger.error(msg) raise ValueError(msg) @@ -129,7 +129,7 @@ def get_str_padding(obj: object) -> int: items: str = '\n '.join(f'{str(k):<{key_padding}} = {v}' for k, v in items_list) msg = ( - 'The values of TimeSegmentFraction do not sum to 1 for period {}. ' + 'The values of time_segment_fraction do not sum to 1 for period {}. ' 'Each item in segment_fraction represents a fraction of a year, so they must ' 'total to 1. Current values:\n {}\n\tsum = {}' ).format(p, items, total) @@ -140,7 +140,7 @@ def get_str_padding(obj: object) -> int: def validate_time_manual(model: TemoaModel) -> None: """ If using this table, check that defined states are actually valid. - TimeSegmentFraction is already compared to other tables so just compare to segment_fraction. + time_segment_fraction is already compared to other tables so just compare to segment_fraction. """ # Only check TimeNext if it is actually being used if model.time_sequencing.first() != 'manual': @@ -161,8 +161,8 @@ def validate_time_manual(model: TemoaModel) -> None: if missing_psd or missing_psd_next: msg: str = ( 'Failed to build state sequence. ' - '\nThese states from TimeSegmentFraction were not given a next state:\n{}\n' - '\nThese states from TimeSegmentFraction do not follow any state:\n{}' + '\nThese states from time_segment_fraction were not given a next state:\n{}\n' + '\nThese states from time_segment_fraction do not follow any state:\n{}' ).format(missing_psd, missing_psd_next) logger.error(msg) raise ValueError(msg) @@ -286,7 +286,7 @@ def create_time_sequence(model: TemoaModel) -> None: # Hidden feature. Define the sequence directly in the TimeManual table msg = 'Pulling time sequence from TimeNext table.' for p, s, d, s_next, d_next in model.time_manual: - model.time_manual[p, s, d] = s_next, d_next + model.time_next[p, s, d] = s_next, d_next case _: # This should have been caught in hybrid_loader msg = f"Invalid time sequencing parameter loaded '{model.time_sequencing.first()}'. Likely code error." @@ -328,7 +328,7 @@ def create_time_season_to_sequential(model: TemoaModel) -> None: if model.time_sequencing.first() in ('consecutive_days', 'seasonal_timeslices'): logger.info( 'No data in time_season_sequential. By default, assuming sequential seasons ' - 'match time_season and TimeSegmentFraction.' + 'match time_season and time_segment_fraction.' ) for s in model.time_season_all: model.time_season_to_sequential.add(s) @@ -390,7 +390,7 @@ def create_time_season_to_sequential(model: TemoaModel) -> None: if (p, s) not in model.segment_fraction_per_season: msg = ( f'Period-season index {(p, s)} that does not exist in ' - 'TimeSegmentFraction referenced in time_season_sequential .' + 'time_segment_fraction referenced in time_season_sequential .' ) logger.error(msg) raise ValueError(msg) @@ -410,9 +410,9 @@ def create_time_season_to_sequential(model: TemoaModel) -> None: if abs(segment_fraction - segment_fraction_seq) >= 0.001: msg = ( 'Discrepancy of total period-season composition between ' - 'TimeSegmentFraction and time_season_sequential. Total fraction of each ' + 'time_segment_fraction and time_season_sequential. Total fraction of each ' 'period assigned to each season should match: ' - f'TimeSegmentFraction: {(p, s, value(model.segment_fraction_per_season[p, s]))}' + f'time_segment_fraction: {(p, s, value(model.segment_fraction_per_season[p, s]))}' f', time_season_sequential: {(p, s, segment_fraction_seq)}' ) logger.warning(msg) diff --git a/temoa/data_io/component_manifest.py b/temoa/data_io/component_manifest.py index 966d6aaba..d2d6b13dc 100644 --- a/temoa/data_io/component_manifest.py +++ b/temoa/data_io/component_manifest.py @@ -247,9 +247,9 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: ), LoadItem( component=model.time_season_sequential, - table='time_season_to_sequential', + table='time_season_sequential', columns=['period', 'seas_seq', 'season', 'num_days'], - custom_loader_name='_load_time_season_to_sequential', + custom_loader_name='_load_time_season_sequential', is_table_required=False, ), LoadItem( diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index d1621f5f5..6d166a78d 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -565,7 +565,7 @@ def _load_time_season( store[period].append(season) # type: ignore[index] data[model.time_season.name] = store - def _load_time_season_to_sequential( + def _load_time_season_sequential( self, data: dict[str, object], raw_data: Sequence[tuple[object, ...]], @@ -594,7 +594,7 @@ def _load_segment_fraction( self._load_component_data(data, model.segment_fraction, filtered_data) else: logger.warning( - 'No TimeSegmentFraction table found. Generating default segment_fraction values.' + 'No time_segment_fraction table found. Generating default segment_fraction values.' ) time_optimize = data.get('time_optimize', []) fallback = [(p, 'S', 'D', 1.0) for p in time_optimize] # type: ignore[attr-defined] diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index 35ed2fcee..1ea6def23 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -1120,19 +1120,7 @@ INSERT INTO "time_season_sequential" VALUES(2000,11,'apr_w3','charge',7.0,NULL); INSERT INTO "time_season_sequential" VALUES(2000,12,'apr_w4','discharge',7.0,NULL); INSERT INTO "time_season_sequential" VALUES(2000,13,'apr_29th','charge',1.0,NULL); INSERT INTO "time_season_sequential" VALUES(2000,14,'apr_30th','discharge',1.0,NULL); -CREATE TABLE time_season_to_sequential -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT - REFERENCES season_label (season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); + CREATE TABLE time_segment_fraction ( period INTEGER @@ -1155,4 +1143,5 @@ INSERT INTO "time_segment_fraction" VALUES(2000,'discharge','b',0.125,NULL); INSERT INTO "time_segment_fraction" VALUES(2000,'discharge','c',0.125,NULL); INSERT INTO "time_segment_fraction" VALUES(2000,'discharge','d',0.125,NULL); CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); + COMMIT; From 0102cf8aac672e4fcd74f32f2f303adb07fa626c Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 8 Nov 2025 17:59:14 -0500 Subject: [PATCH 318/587] fixing inconsistencies, updating docs --- data_files/temoa_schema_v4.sql | 2 +- docs/source/Documentation.rst | 184 +++++++++--------- temoa/_internal/table_writer.py | 4 +- temoa/components/capacity.py | 2 +- temoa/components/commodities.py | 12 +- temoa/components/costs.py | 8 +- temoa/components/flows.py | 18 +- temoa/components/limits.py | 6 +- temoa/components/operations.py | 2 +- temoa/components/storage.py | 4 +- temoa/components/time.py | 2 +- temoa/core/model.py | 4 +- temoa/data_io/hybrid_loader.py | 4 +- temoa/extensions/breakeven/breakeven.py | 6 +- .../monte_carlo/make_deltas_table.sql | 4 +- temoa/extensions/myopic/myopic_sequencer.py | 4 +- temoa/extensions/stochastics/EVPI.py | 36 ++-- .../generate_scenario_tree-nonhomogenous.py | 20 +- .../stochastics/generate_scenario_tree.py | 20 +- .../legacy_files/ef_writer_script_old.py | 4 +- .../legacy_files/scenariomodels.py | 50 ++--- .../stochastics/temoa_stochastic.py | 22 +-- temoa/model_checking/validators.py | 4 +- temoa/utilities/db_migration_v3_1_to_v4.py | 8 +- temoa/utilities/run_all_v4_migrations.py | 4 +- tests/test_storage.py | 2 +- .../US_9R_8D_legacy_set_sizes.json | 4 +- tests/testing_data/US_9R_8D_set_sizes.json | 4 +- 28 files changed, 224 insertions(+), 220 deletions(-) diff --git a/data_files/temoa_schema_v4.sql b/data_files/temoa_schema_v4.sql index 7727e7b10..7290fd313 100644 --- a/data_files/temoa_schema_v4.sql +++ b/data_files/temoa_schema_v4.sql @@ -1,4 +1,4 @@ -PRAGMA foreign_keys= OFF; +PRAGMA foreign_keys = OFF; BEGIN TRANSACTION; CREATE TABLE IF NOT EXISTS metadata diff --git a/docs/source/Documentation.rst b/docs/source/Documentation.rst index 46f84969c..761218359 100644 --- a/docs/source/Documentation.rst +++ b/docs/source/Documentation.rst @@ -328,7 +328,7 @@ recommend that you populate input tables in the following order: * MetaDataReal (global_discount_rate) * MetaData (days_per_period) * Demand - * DemandSpecificDistribution + * demand_specific_distribution * efficiency * existing_capacity * CapacityFactor @@ -725,7 +725,7 @@ Sets :widths: 8, 28, 14, 50 ":math:`{}^*\text{C}`",":code:`commodity_all`","string","union of all commodity sets" - ":math:`\text{C}^s`",":code:`commodity_source`","string","input sources (not balanced by CommodityBalance_Constraint)" + ":math:`\text{C}^s`",":code:`commodity_source`","string","input sources (not balanced by CommodityBalance_constraint)" ":math:`\text{C}^d`",":code:`commodity_demand`","string","end-use demand commodities" ":math:`\text{C}^e`",":code:`commodity_emissions`","string","emission commodities (e.g. :math:`\text{CO}_\text{2}` :math:`\text{NO}_\text{x}`)" ":math:`\text{C}^p`",":code:`commodity_physical`","string","general energy forms (e.g. electricity, coal, uranium, oil)" @@ -950,14 +950,14 @@ Parameters ":math:`\text{CON}_{r,i,t,v}`","construction_input",":math:`\mathbb{R}`","Commodities consumed by creation of process capacity" ":math:`\text{DEM}_{r,p,c}`","Demand",":math:`\mathbb{R}^+_0`","End-use demands, by period" ":math:`\text{DDD}_{p,s,d}`","DemandDefaultDistribution",":math:`\mathbb{I}`","Default demand distribution (currently not supported)" - ":math:`\text{DSD}_{r,p,s,d,c}`","DemandSpecificDistribution",":math:`\mathbb{I}`","Demand-specific distribution" + ":math:`\text{DSD}_{r,p,s,d,c}`","demand_specific_distribution",":math:`\mathbb{I}`","Demand-specific distribution" ":math:`\text{EFF}_{r,i,t,v,o}`","efficiency",":math:`\mathbb{R}^+_0`","Tech- and commodity-specific efficiency" ":math:`\text{EAC}_{r,i,t,v,o,e}`","emission_activity",":math:`\mathbb{R}`","Tech-specific emissions rate" ":math:`\text{EE}_{r,t,v,e}`","emission_embodied",":math:`\mathbb{R}`","Emissions associated with the creation of capacity" ":math:`\text{EEOL}_{r,t,v,e}`","emission_end_of_life",":math:`\mathbb{R}`","Emissions associated with the retirement/end of life of capacity" ":math:`\text{EOLO}_{r,t,v,o}`","end_of_life_output",":math:`\mathbb{R}`","Commodities produced by retirement/end of life of capacity" ":math:`\text{ECAP}_{r,t,v}`","existing_capacity",":math:`\mathbb{R}^+_0`","Pre-existing capacity" - ":math:`\text{GDR}`","GlobalDiscountRate",":math:`\mathbb{R}`","Global rate used to calculate present cost" + ":math:`\text{GDR}`","global_discount_rate",":math:`\mathbb{R}`","Global rate used to calculate present cost" ":math:`\text{LTP}_{r,t,v}`","lifetime_process",":math:`\mathbb{N}`","Tech- and vintage-specific lifetime (default=lifetime_tech)" ":math:`\text{LTT}_{r,t}`","lifetime_tech",":math:`\mathbb{N}`","Tech-specific lifetime (default=40 years)" ":math:`\text{LSC}_{r,p,t,v}`","lifetime_survival_curve",":math:`\mathbb{R}^+_0`","Surviving fraction of original capacity" @@ -1132,7 +1132,7 @@ model has no incentive to build anything. This parameter specifies the end-use demands that appear at the far right edge of the system diagram. To specify the distribution of demand, look to the -:code:`DemandDefaultDistribution` (DDD) and :code:`DemandSpecificDistribution` +:code:`DemandDefaultDistribution` (DDD) and :code:`demand_specific_distribution` (DSD) parameters. As a historical note, this parameter was at one time also indexed by season and @@ -1167,7 +1167,7 @@ parameter must be specified. Like the :ref:`segment_fraction` parameter, the su DDD must be 1. -DemandSpecificDistribution +demand_specific_distribution ^^^^^^^^^^^^^^^^^^^^^^^^^^ :math:`{DSD}_{r \in R, s \in S, d \in D, c \in C^d}` @@ -1259,7 +1259,7 @@ with the exception of an investment cost. .. _GDR: -GlobalDiscountRate +global_discount_rate ^^^^^^^^^^^^^^^^^^ :math:`{GDR}` @@ -1381,7 +1381,7 @@ MaxActivity The :code:`MaxActivity` parameter is used to constrain the total activity (i.e., energy production) from a given technology in each model time period. Note that the total activity is constrained across all vintages of a technology. This parameter -is used in the :code:`MaxActivity_Constraint`. +is used in the :code:`MaxActivity_constraint`. MaxCapacity @@ -1392,7 +1392,7 @@ MaxCapacity The :code:`MaxCapacity` parameter represents an upper bound on the total installed capacity of a given technology in each model time period. Note that the total capacity is constrained across all vintages of a technology. This parameter is -used in the :code:`MaxCapacity_Constraint`. +used in the :code:`MaxCapacity_constraint`. MaxCapacitySum @@ -1404,7 +1404,7 @@ Similar to the :code:`MaxCapacity` parameter, but represents an upper bound on the total installed capacity across all model time periods. In addition, this parameter specifies the upper bound on a group of technologies specified in the :code:`tech_capacity_max` subset. This parameter is used in the -:code:`MaxCapacitySet_Constraint`. +:code:`MaxCapacitySet_constraint`. MaxResource @@ -1416,7 +1416,7 @@ MaxResource The :code:`MaxResource` parameter represents an upper bound on the cumulative amount of commodity that can be produced by region and technology over the model time -horizon. This parameter is used in :code:`MaxResource_Constraint`. Note that +horizon. This parameter is used in :code:`MaxResource_constraint`. Note that this parameter differs from :code:`ResourceBound`, which is also indexed by model time period. @@ -1429,7 +1429,7 @@ MinActivity The :code:`MinActivity` parameter represents a lower bound on the total activity (i.e., energy production) of a given technology in each model time period. Note that the total activity is constrained across all vintages of a technology. This parameter -is used in the :code:`MinActivity_Constraint`. +is used in the :code:`MinActivity_constraint`. MinCapacity @@ -1440,7 +1440,7 @@ MinCapacity The :code:`MinCapacity` parameter represents a lower bound on the total installed capacity of a given technology in each model time period. Note that the total capacity is constrained across all vintages of a technology. This parameter is -used in the :code:`MinCapacity_Constraint`. +used in the :code:`MinCapacity_constraint`. MinCapacitySum @@ -1450,7 +1450,7 @@ MinCapacitySum The :code:`MinCapacitySum` parameter represents the minimum cumulative capacity associated with technologies belonging to :code:`tech_group`. -This parameter is used in the :code:`MinActivityGroup_Constraint`. +This parameter is used in the :code:`MinActivityGroup_constraint`. MinGenGroupTarget @@ -1461,7 +1461,7 @@ MinGenGroupTarget The :code:`MinGenGroupTarget` parameter is similar to :code:`MinActivity`, but represents a minimum activity limit for a user-defined technology group (:code:`tech_groups`) rather than a single technology. This parameter is used -in the :code:`MinActivityGroup_Constraint`. +in the :code:`MinActivityGroup_constraint`. MinGenGroupWeight @@ -1472,7 +1472,7 @@ MinGenGroupWeight The :code:`MinGenGroupWeight` parameter represents a weight that is applied to each technology within each :code:`tech_group`, which determines the technology-specific activity shares that can count towards meeting the -:code:`MinActivityGroup_Constraint`. +:code:`MinActivityGroup_constraint`. MyopicBaseYear @@ -1499,7 +1499,7 @@ installed generating capacity - expressed as a share of peak load - that must be available to meet contingencies. Note that since electricity demand is often endogeous in Temoa databases, we calculate electricity production by time slice to estimate the peak electricity demand. This parameter is used in -:code:`ReserveMargin_Constraint`. +:code:`ReserveMargin_constraint`. RampDown @@ -1512,7 +1512,7 @@ ramp down rate can be specified via the :code:`RampDown` parameter. The specifie value represents the fraction of installed capacity that can be ramped down when moving from one time slice to the next. There is an equivalent :code:`RampUp` parameter, to specify ramping limits in the upward direction. This parameter is used in the -:code:`RampDownDay_Constraint` and `RampDownSeason_Constraint`. The former constrains +:code:`RampDownDay_constraint` and `RampDownSeason_constraint`. The former constrains the downward ramp rate between time-of-day slices, and the latter constrains the downward ramp rate between the last time-of-day slice in a given season and the first time-of-day slice in the next season. @@ -1528,7 +1528,7 @@ ramp up rate can be specified via the :code:`RampUp` parameter. The specified value represents the fraction of installed capacity that can be ramped up when moving from one time slice to the next. There is an equivalent :code:`RampDown` parameter, to specify ramping limits in the downward direction. This parameter is used in the -:code:`RampUpDay_Constraint` and `RampUpSeason_Constraint`. The former constrains +:code:`RampUpDay_constraint` and `RampUpSeason_constraint`. The former constrains the upward ramp rate between time-of-day slices, and the latter constrains the upward ramp rate between the last time-of-day slice in a given season and the first time-of-day slice in the next season. @@ -1543,7 +1543,7 @@ This parameter allows the modeler to specify commodity production limits per per Note that a constraint in one period does not relate to any other periods. For instance, if the modeler specifies a limit in period 1 and does not specify a limit in period 2, then the model may use as much of that resource as it would -like in period 2. This parameter is used in :code:`ResourceExtraction_Constraint`. +like in period 2. This parameter is used in :code:`ResourceExtraction_constraint`. Note that the :code:`MaxResource` parameter is similar, but constrains total cumulative resource consumption across all model time periods. @@ -1595,7 +1595,7 @@ Some technologies have a single output but have multiple input fuels. The :code:`TechInputSplit` parameter fixes the shares of commodity input to a specific technology in a given period. Note that this fixed share is maintained across all model time slices. This parameter is used in -:code:`TechInputSplit_Constraint`. +:code:`TechInputSplit_constraint`. TechInputSplitAverage @@ -1607,7 +1607,7 @@ The :code:`TechInputSplitAverage` is similar to :code:`TechInputSplit`, as they both fix input commodity shares to technologies with multiple inputs. However, :code:`TechInputSplitAverage` only fixes the average shares at the annual level, allowing the shares at the time slice level to vary. This -parameter is used in :code:`TechInputSplitAverage_Constraint`. +parameter is used in :code:`TechInputSplitAverage_constraint`. TechOutputSplit @@ -1619,7 +1619,7 @@ Some technologies have a single input fuel but have multiple outputs. The :code:`TechOutputSplit` parameter fixes the shares of commodity input to a specific technology in a given period. Note that this fixed share is maintained across all model time slices. This parameter is used in -:code:`TechOutputSplit_Constraint`. +:code:`TechOutputSplit_constraint`. \*loan_annualize @@ -1741,8 +1741,8 @@ Variables ":math:`FLXA_{r,p,i,t,v,o}`","v_flex_annual",":math:`\mathbb{R}^+_0`","The portion of commodity production from constant production techs exceeding demand" ":math:`CUR_{r,p,s,d,i,t,v,o}`","v_curtailment",":math:`\mathbb{R}^+_0`","Commodity flow out of a tech that is curtailed" ":math:`CAP_{r,t,v}`","v_capacity",":math:`\mathbb{R}^+_0`","Required tech capacity to support associated activity" - ":math:`CAPAVL_{r,p,t}`","v_capacityAvailable ByPeriodAndTech",":math:`\mathbb{R}^+_0`","Derived variable representing the capacity of technology :math:`t` available in period :math:`p`" - ":math:`SI_{r,t,v}`","V_StorageInit",":math:`\mathbb{R}^+_0`","Initial charge level associated with storage techs" + ":math:`CAPAVL_{r,p,t}`","v_capacity_available_by_period_and_tech",":math:`\mathbb{R}^+_0`","Derived variable representing the capacity of technology :math:`t` available in period :math:`p`" + ":math:`SI_{r,t,v}`","v_storage_init",":math:`\mathbb{R}^+_0`","Initial charge level associated with storage techs" ":math:`SL_{r,p,s,d,t,v}`","v_storage_level",":math:`\mathbb{R}^+_0`","Charge level each time slice associated with storage techs" ":math:`SSL_{r,p,s,t,v}`","v_seasonal_storage_level",":math:`\mathbb{R}^+_0`","Base charge level of sequential seasons for seasonal storage" ":math:`RCAP_{r,p,t,v}`","v_retired_capacity",":math:`\mathbb{R}^+_0`","Capacity retired before end of life" @@ -1757,7 +1757,7 @@ v_flow_out The most fundamental variable in the Temoa formulation is the :code:`v_flow_out` variable. It describes the commodity flow out of a process in a given time slice. To balance input and output flows in the -:code:`CommodityBalance_Constraint`, the commodity flow into a given +:code:`CommodityBalance_constraint`, the commodity flow into a given process can be calculated as :math:`\sum_{T, V, O} \textbf{FO}_{p, s, d, c, t, v, o} /EFF_{c,t,v,o}`. @@ -1791,7 +1791,7 @@ the :code:`tech_flex` set allows for the overproduction of propane and kerosene, allowing the model to fulfill the endogenous demand for gasoline. This flexible technology designation activates a slack variable (:math:`\textbf{FLX}_{r, p, s, d, i, t, v, c}`)representing -the excess production in the :code:`CommodityBalanceAnnual_Constraint`. +the excess production in the :code:`CommodityBalanceAnnual_constraint`. v_flex_annual @@ -1829,14 +1829,14 @@ capacity of 10 units, and a CF of 0.8 and a usage of 5 units, then the reported curtailment is 3 units (0.8 x 10 - 5). -v_flow_inStorage +v_flow_in_storage ^^^^^^^^^^^^^^^ :math:`FIS_{r,p,s,d,i,t,v,o}` Because the production and consumption associated with storage techs occur across different time slices, the comodity flow into a storage technologiy -cannot be discerned from :code:`v_flow_out`. Thus an explicit :math:`FlowIn` +cannot be discerned from :code:`v_flow_out`. Thus an explicit :math:`flow_in` variable is required for storage. v_capacity @@ -1859,12 +1859,12 @@ not strictly necessary, but used where the individual vintages of a technology are not warranted (e.g. in calculating the maximum or minimum total capacity allowed in a given time period). -V_StorageInit +v_storage_init ^^^^^^^^^^^^^ :math:`SI_{r,t,v}` -The :code:`V_StorageInit` variable determines the initial storage charge level +The :code:`v_storage_init` variable determines the initial storage charge level at the beginning of the first time slice within a given time period. Each vintage of each technology can have a different optimal initial value. Note that this value also determines the ending storage charge level at the end of the @@ -1885,16 +1885,16 @@ We explain the equations governing these variables the :ref:`Constraints` section. -.. _Constraints: +.. _constraints: Equations --------- There are four main equations that govern the flow of energy through the model network. The :code:`Demand_Constrant` :eq:`Demand` ensures that the supply meets -demand in every time slice. For each process, the :code:`Capacity_Constraint` :eq:`Capacity` +demand in every time slice. For each process, the :code:`Capacity_constraint` :eq:`Capacity` ensures that there is sufficient capacity to meet the optimal commodity flows across all -time slices. Between processes, the :code:`CommodityBalance_Constraint` :eq:`CommodityBalance` +time slices. Between processes, the :code:`CommodityBalance_constraint` :eq:`CommodityBalance` ensures that global commodity production across the energy system is sufficient to meet the endogenous demands for that commodity. Finally, the objective function :eq:`obj_invest` drives the model to minimize the system-wide cost of energy supply by optimizing the deployment and @@ -1906,8 +1906,8 @@ While not required, doing so improves computational performance by eliminating t season and time of day :code:`(s,d)` indices associated with these technologies. In order to ensure the model functions correctly with these simplified technologies, slightly different formulations of the capacity and commodity balance constraints -are required. See the :code:`AnnualCommodityBalance_Constraint` and -:code:`CapacityAnnual_Constraint` :eq:`CapacityAnnual` below for details. +are required. See the :code:`AnnualCommodityBalance_constraint` and +:code:`CapacityAnnual_constraint` :eq:`CapacityAnnual` below for details. The rest of this section defines each model constraint, with a rationale for existence. We use the implementation-specific names for the constraints to @@ -1922,19 +1922,19 @@ Constraints Defining Derived Decision Variables ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ These first four constraints define derived variables that are used within -the model. The :code:`Capacity_Constraint` and :code:`CapacityAnnual_Constraint` +the model. The :code:`Capacity_constraint` and :code:`CapacityAnnual_constraint` are particularly important because they define the relationship between installed capacity and allowable commodity flow. -.. autofunction:: temoa_rules.Capacity_Constraint +.. autofunction:: temoa_rules.Capacity_constraint -.. autofunction:: temoa_rules.CapacityAnnual_Constraint +.. autofunction:: temoa_rules.CapacityAnnual_constraint -.. autofunction:: temoa_rules.AdjustedCapacity_Constraint +.. autofunction:: temoa_rules.AdjustedCapacity_constraint -.. autofunction:: temoa_rules.AnnualRetirement_Constraint +.. autofunction:: temoa_rules.AnnualRetirement_constraint -.. autofunction:: temoa_rules.CapacityAvailableByPeriodAndTech_Constraint +.. autofunction:: temoa_rules.CapacityAvailableByPeriodAndTech_constraint .. _NetworkConstraints: @@ -1945,11 +1945,11 @@ Network Constraints These three constraints define the core of the Temoa model; together, they define the algebraic energy system network. -.. autofunction:: temoa_rules.Demand_Constraint +.. autofunction:: temoa_rules.demand_constraint -.. autofunction:: temoa_rules.CommodityBalance_Constraint +.. autofunction:: temoa_rules.CommodityBalance_constraint -.. autofunction:: temoa_rules.AnnualCommodityBalance_Constraint +.. autofunction:: temoa_rules.AnnualCommodityBalance_constraint Physical and Operational Constraints @@ -1958,31 +1958,31 @@ Physical and Operational Constraints These constraints fine-tune the model formulation to account for various physical and operational real-world phenomena. -.. autofunction:: temoa_rules.BaseloadDiurnal_Constraint +.. autofunction:: temoa_rules.BaseloadDiurnal_constraint -.. autofunction:: temoa_rules.DemandActivity_Constraint +.. autofunction:: temoa_rules.DemandActivity_constraint -.. autofunction:: temoa_rules.StorageEnergy_Constraint +.. autofunction:: temoa_rules.StorageEnergy_constraint -.. autofunction:: temoa_rules.SeasonalStorageEnergy_Constraint +.. autofunction:: temoa_rules.SeasonalStorageEnergy_constraint -.. autofunction:: temoa_rules.StorageEnergyUpperBound_Constraint +.. autofunction:: temoa_rules.StorageEnergyUpperBound_constraint -.. autofunction:: temoa_rules.SeasonalStorageEnergyUpperBound_Constraint +.. autofunction:: temoa_rules.SeasonalStorageEnergyUpperBound_constraint -.. autofunction:: temoa_rules.StorageChargeRate_Constraint +.. autofunction:: temoa_rules.StorageChargeRate_constraint -.. autofunction:: temoa_rules.StorageDischargeRate_Constraint +.. autofunction:: temoa_rules.StorageDischargeRate_constraint -.. autofunction:: temoa_rules.StorageThroughput_Constraint +.. autofunction:: temoa_rules.StorageThroughput_constraint -.. autofunction:: temoa_rules.RampUpDay_Constraint +.. autofunction:: temoa_rules.RampUpDay_constraint -.. autofunction:: temoa_rules.RampDownDay_Constraint +.. autofunction:: temoa_rules.RampDownDay_constraint -.. autofunction:: temoa_rules.RampUpSeason_Constraint +.. autofunction:: temoa_rules.RampUpSeason_constraint -.. autofunction:: temoa_rules.RampDownSeason_Constraint +.. autofunction:: temoa_rules.RampDownSeason_constraint .. autofunction:: temoa_rules.ReserveMarginStatic @@ -2008,45 +2008,45 @@ The constraints provided in this section are not required for proper system operation, but allow the modeler some further degree of system specification. .. commented out... not used? - .. autofunction:: temoa_rules.existing_capacity_Constraint + .. autofunction:: temoa_rules.existing_capacity_constraint -.. autofunction:: temoa_rules.limit_emission_Constraint +.. autofunction:: temoa_rules.limit_emission_constraint -.. autofunction:: temoa_rules.limit_activity_Constraint +.. autofunction:: temoa_rules.limit_activity_constraint -.. autofunction:: temoa_rules.limit_activity_share_Constraint +.. autofunction:: temoa_rules.limit_activity_share_constraint -.. _MaxCapacity_Constraint: +.. _MaxCapacity_constraint: -.. autofunction:: temoa_rules.limit_capacity_Constraint +.. autofunction:: temoa_rules.limit_capacity_constraint -.. autofunction:: temoa_rules.limit_new_capacity_Constraint +.. autofunction:: temoa_rules.limit_new_capacity_constraint -.. autofunction:: temoa_rules.limit_capacity_share_Constraint +.. autofunction:: temoa_rules.limit_capacity_share_constraint -.. autofunction:: temoa_rules.limit_new_capacity_share_Constraint +.. autofunction:: temoa_rules.limit_new_capacity_share_constraint -.. autofunction:: temoa_rules.limit_resource_Constraint +.. autofunction:: temoa_rules.limit_resource_constraint -.. _TechOutputSplit_Constraint: +.. _TechOutputSplit_constraint: -.. autofunction:: temoa_rules.limit_tech_input_split_Constraint +.. autofunction:: temoa_rules.limit_tech_input_split_constraint -.. autofunction:: temoa_rules.limit_tech_output_split_Constraint +.. autofunction:: temoa_rules.limit_tech_output_split_constraint -.. autofunction:: temoa_rules.limit_tech_input_split_annual_Constraint +.. autofunction:: temoa_rules.limit_tech_input_split_annual_constraint -.. autofunction:: temoa_rules.limit_tech_output_split_annual_Constraint +.. autofunction:: temoa_rules.limit_tech_output_split_annual_constraint -.. autofunction:: temoa_rules.limit_tech_input_splitAverage_Constraint +.. autofunction:: temoa_rules.limit_tech_input_split_average_constraint -.. autofunction:: temoa_rules.limit_tech_output_splitAverage_Constraint +.. autofunction:: temoa_rules.limit_tech_output_splitAverage_constraint -.. autofunction:: temoa_rules.limit_annual_capacity_factor_Constraint +.. autofunction:: temoa_rules.limit_annual_capacity_factor_constraint -.. autofunction:: temoa_rules.limit_seasonal_capacity_factor_Constraint +.. autofunction:: temoa_rules.limit_seasonal_capacity_factor_constraint -.. autofunction:: temoa_rules.limit_storage_fraction_Constraint +.. autofunction:: temoa_rules.limit_storage_fraction_constraint .. autofunction:: temoa_rules.limit_growth_capacity @@ -2153,7 +2153,7 @@ A simple definition of this constraint is: M.demand_constraint = Constraint( M.regions, M.time_optimize, M.time_season, M.time_of_day, M.commodity_demand, - rule=Demand_Constraint + rule=demand_constraint ) In line 1, '``M.demand_constraint =``' creates a place holder in the model object @@ -2163,7 +2163,7 @@ Pyomo-specific function that creates each individual constraint in the class. The first arguments (line 2) are the index sets of the constraint class. Line 2 is the Pyomo method of saying "for all" (:math:`\forall`). Line 3 contains the final, mandatory argument (``rule=...``) that specifies the name of the -implementation rule for the constraint, in this case ``Demand_Constraint``. +implementation rule for the constraint, in this case ``demand_constraint``. Pyomo will call this rule with each tuple in the Cartesian product of the index sets. @@ -2177,25 +2177,25 @@ is: .. code-block:: python :linenos: - def Demand_Constraint ( M, r, p, s, d, dem ): - if (r,p,s,d,dem) not in M.DemandSpecificDistribution.sparse_keys(): # If user did not specify this Demand, tell + def demand_constraint ( M, r, p, s, d, dem ): + if (r,p,s,d,dem) not in M.demand_specific_distribution.sparse_keys(): # If user did not specify this Demand, tell return Constraint.Skip # Pyomo to ignore this constraint index. supply = sum( M.v_flow_out[r, p, s, d, S_i, S_t, S_v, dem] for S_t, S_v in M.commodity_up_stream_process[r, p, dem] if S_t not in M.tech_annual - for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, dem] + for S_i in M.process_input_by_output[r, p, S_t, S_v, dem] ) supply_annual = sum( M.v_flow_out_annual[r, p, S_i, S_t, S_v, dem] for S_t, S_v in M.commodity_up_stream_process[r, p, dem] if S_t in M.tech_annual - for S_i in M.ProcessInputsByOutput[r, p, S_t, S_v, dem] + for S_i in M.process_input_by_output[r, p, S_t, S_v, dem] ) * value( M.segment_fraction[ s, d]) demand_constraintErrorCheck(supply + supply_annual, r, p, s, d, dem) - expr = supply + supply_annual == M.Demand[r, p, dem] * M.DemandSpecificDistribution[r, s, d, dem] + expr = supply + supply_annual == M.Demand[r, p, dem] * M.demand_specific_distribution[r, s, d, dem] return expr ... @@ -2244,7 +2244,7 @@ Consider a naive approach to calculating the supply:: to_sum = list() for S_t in M.tech_all: for S_v in M.vintage_all: - for S_i in ProcessInputsByOutput( p, S_t, S_v, dem ): + for S_i in process_input_by_output( p, S_t, S_v, dem ): to_sum.append( M.v_flow_out[p, s, d, S_i, S_t, S_v, dem] ) supply = sum( to_sum ) @@ -2260,7 +2260,7 @@ one:: supply = 0 for S_t in M.tech_all: for S_v in M.vintage_all: - for S_i in ProcessInputsByOutput( p, S_t, S_v, dem ): + for S_i in process_input_by_output( p, S_t, S_v, dem ): supply += M.v_flow_out[p, s, d, S_i, S_t, S_v, dem] Why is list comprehension necessary? Strictly speaking, it is not, especially @@ -2304,7 +2304,7 @@ implementation above. M.demand_constraint_rpsdc = Set( dimen=5, rule=demand_constraintIndices ) # ... - M.demand_constraint = Constraint( M.demand_constraint_rpsdc, rule=Demand_Constraint ) + M.demand_constraint = Constraint( M.demand_constraint_rpsdc, rule=demand_constraint ) As discussed above, the demand_constraint is only valid for certain @@ -2328,7 +2328,7 @@ Pyomo-enforced restriction. However, use of an index set in place of the non-sparse specification obfuscates over what indexes a constraint is defined. While it is not impossible to deduce, either from this documentation or from looking at the :code:`demand_constraintIndices` or -:code:`Demand_Constraint` implementations, the Temoa convention includes +:code:`demand_constraint` implementations, the Temoa convention includes index set names that feature the one-character representation of each set dimension. In this case, the name :code:`demand_constraint_rpsdc` implies that this set has a dimensionality of 5, and (following the :ref:`naming scheme @@ -2779,11 +2779,11 @@ Naming Conventions All constraints attached to a model should end with ``Constraint``. Similarly, the function they use to define the constraint for each index should use the same prefix and ``Constraint`` suffix, but separate them with an underscore -(e.g. ``M.somenameConstraint = Constraint( ..., rule=somename_Constraint``): +(e.g. ``M.somenameConstraint = Constraint( ..., rule=somename_constraint``): .. code-block:: python - M.capacity_constraint = Constraint( M.CapacityVar_tv, rule=Capacity_Constraint ) + M.capacity_constraint = Constraint( M.CapacityVar_tv, rule=Capacity_constraint ) When providing the implementation for a constraint rule, use a consistent naming scheme between functions and constraint definitions. For instance, we have @@ -2792,7 +2792,7 @@ already chosen ``M`` to represent the Pyomo model instance, ``t`` to represent .. code-block:: python - def Capacity_Constraint ( M, t, v ): + def Capacity_constraint ( M, t, v ): ... The complete list we have already chosen: diff --git a/temoa/_internal/table_writer.py b/temoa/_internal/table_writer.py index 36e7c84a8..48ddc55c1 100644 --- a/temoa/_internal/table_writer.py +++ b/temoa/_internal/table_writer.py @@ -83,7 +83,7 @@ 'output_objective', 'output_retired_capacity', ] -optional_output_tables = ['output_flow_out_summary', 'OutputMCDelta', 'output_storage_level'] +optional_output_tables = ['output_flow_out_summary', 'output_mc_delta', 'output_storage_level'] flow_summary_file_loc = Path( PROJECT_ROOT, 'temoa/extensions/modeling_to_generate_alternatives/make_flow_summary_table.sql' @@ -636,7 +636,7 @@ def write_tweaks(self, iteration: int, change_records: Iterable[ChangeRecord]) - change_record.new_value, ) records.append(element) - qry = 'INSERT INTO OutputMCDelta VALUES (?, ?, ?, ?, ?, ?)' + qry = 'INSERT INTO output_mc_delta VALUES (?, ?, ?, ?, ?, ?)' self.con.executemany(qry, records) self.con.commit() diff --git a/temoa/components/capacity.py b/temoa/components/capacity.py index 9738645df..69aa1d02d 100644 --- a/temoa/components/capacity.py +++ b/temoa/components/capacity.py @@ -374,7 +374,7 @@ def capacity_annual_constraint( model: TemoaModel, r: Region, p: Period, t: Technology, v: Vintage ) -> ExprLike: r""" - Similar to Capacity_Constraint, but for technologies belonging to the + Similar to Capacity_constraint, but for technologies belonging to the :code:`tech_annual` set. Technologies in the tech_annual set have constant output across different timeslices within a year, so we do not need to ensure that installed capacity is sufficient across all timeslices, thus saving diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index 9a22af190..017dce8ad 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -292,10 +292,10 @@ def commodity_balance_constraint( producing the excess commodity should be added to the :code:`tech_flex` set. This flexible technology designation will activate a slack variable (:math:`\textbf{FLX}_{r, p, s, d, i, t, v, c}`) representing - the excess production in the :code:`CommodityBalanceAnnual_Constraint`. Note + the excess production in the :code:`CommodityBalanceAnnual_constraint`. Note that the :code:`tech_flex` set is different from :code:`tech_curtailment` set; the latter is technology- rather than commodity-focused and is used in the - :code:`Capacity_Constraint` to track output that is used to produce useful + :code:`Capacity_constraint` to track output that is used to produce useful output and the amount curtailed, and to ensure that the installed capacity covers both. Alternatively, the commodity can be added to the :code:`commodity_waste` set, for which this equality constraint becomes an @@ -493,7 +493,7 @@ def annual_commodity_balance_constraint( model: TemoaModel, r: Region, p: Period, c: Commodity ) -> ExprLike: r""" - Similar to CommodityBalance_Constraint but only balances the supply and demand of the commodity + Similar to CommodityBalance_constraint but only balances the supply and demand of the commodity at the period level, summing all flows over the period but allowing imbalances at the time slice or seasonal level. Applies only to commodities in the :code:`commodity_annual` set. """ @@ -668,7 +668,7 @@ def create_demands(model: TemoaModel) -> None: 2. Find any slices not set in DemandDefaultDistribution, and set them based on the associated segment_fraction slice. 3. Validate that the DemandDefaultDistribution sums to 1. - 4. Find any per-demand DemandSpecificDistribution values not set, and set + 4. Find any per-demand demand_specific_distribution values not set, and set them from DemandDefaultDistribution. Note that this only sets a distribution for an end-use demand if the user has *not* specified _any_ anything for that end-use demand. Thus, it is up to the user to fully @@ -808,8 +808,8 @@ def get_str_padding(obj: Any) -> int: ) items = '\n '.join(fmt % (str(k), v) for k, v in items_list) msg = ( - 'The values of the DemandSpecificDistribution parameter do not ' - 'sum to 1 for {}. The DemandSpecificDistribution specifies how end-use ' + 'The values of the demand_specific_distribution parameter do not ' + 'sum to 1 for {}. The demand_specific_distribution specifies how end-use ' 'demands are distributed per time-slice (i.e., time_season, ' 'time_of_day). Within each region, period, end-use demand, then, the distribution ' 'must total to 1.\n\n Demand-specific distribution in error: ' diff --git a/temoa/components/costs.py b/temoa/components/costs.py index 362e4fd6c..b796cedc8 100644 --- a/temoa/components/costs.py +++ b/temoa/components/costs.py @@ -687,16 +687,16 @@ def create_costs(model: TemoaModel) -> None: if unspecified_fixed_prices: # CF._constructed = False for r, p, t, v in unspecified_fixed_prices: - if (r, t, v) in model.cost_fixedVintageDefault: - cost_fixed[r, p, t, v] = model.cost_fixedVintageDefault[ + if (r, t, v) in model.cost_fixed_vintage_default: + cost_fixed[r, p, t, v] = model.cost_fixed_vintage_default[ r, t, v ] # CF._constructed = True if unspecified_var_prices: # CV._constructed = False for r, p, t, v in unspecified_var_prices: - if (r, t, v) in model.cost_variableVintageDefault: - cost_variable[r, p, t, v] = model.cost_variableVintageDefault[r, t, v] + if (r, t, v) in model.cost_variable_vintage_default: + cost_variable[r, p, t, v] = model.cost_variable_vintage_default[r, t, v] # CV._constructed = True logger.debug('Created M.cost_fixed with size: %d', len(value(model.cost_fixed))) logger.debug('Created M.cost_variable with size: %d', len(value(model.cost_variable))) diff --git a/temoa/components/flows.py b/temoa/components/flows.py index 5dded296f..4ebd16511 100644 --- a/temoa/components/flows.py +++ b/temoa/components/flows.py @@ -99,15 +99,15 @@ def create_commodity_balance_and_flow_sets(model: TemoaModel) -> None: Populates: - model.commodity_balance_rpc: The master set of (r, p, c) for balance constraints. - - model.activeFlow_rpsditvo: Indices for time-sliced flows (v_flow_out). - - model.activeFlow_rpitvo: Indices for annual flows (v_flow_out_annual). - - model.activeFlex_rpsditvo: Indices for flexible time-sliced flows (v_flex). - - model.activeFlex_rpitvo: Indices for flexible annual flows (v_flex_annual). - - model.activeflow_in_storage_rpsditvo: Indices for flows into storage (v_flow_in). - - model.activeCurtailment_rpsditvo: Indices for curtailed generation (v_curtailment). - - model.activeActivity_rptv: Master set of active (r, p, t, v) processes. - - model.storageLevelIndices_rpsdtv: Indices for storage state variables (v_storage_level). - - model.seasonalStorageLevelIndices_rpstv: Indices for seasonal storage levels. + - model.active_flow_rpsditvo: Indices for time-sliced flows (v_flow_out). + - model.active_flow_rpitvo: Indices for annual flows (v_flow_out_annual). + - model.active_flex_rpsditvo: Indices for flexible time-sliced flows (v_flex). + - model.active_flex_rpitvo: Indices for flexible annual flows (v_flex_annual). + - model.active_flow_in_storage_rpsditvo: Indices for flows into storage (v_flow_in). + - model.active_curtailment_rpsditvo: Indices for curtailed generation (v_curtailment). + - model.active_activity_rptv: Master set of active (r, p, t, v) processes. + - model.storage_level_indices_rpsdtv: Indices for storage state variables (v_storage_level). + - model.seasonal_storage_level_indices_rpstv: Indices for seasonal storage levels. """ logger.debug('Creating commodity balance and active flow index sets.') # 1. Commodity Balance diff --git a/temoa/components/limits.py b/temoa/components/limits.py index a7dcae9eb..5efbafc16 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -572,7 +572,7 @@ def limit_tech_input_split_constraint( r""" Allows users to limit shares of commodity inputs to a process producing a single output. These shares can vary by model time period. See - limit_tech_output_split_Constraint for an analogous explanation. Under this constraint, + limit_tech_output_split_constraint for an analogous explanation. Under this constraint, only the technologies with variable output at the timeslice level (i.e., NOT in the :code:`tech_annual` set) are considered.""" inp = quicksum( @@ -600,7 +600,7 @@ def limit_tech_input_split_annual_constraint( r""" Allows users to limit shares of commodity inputs to a process producing a single output. These shares can vary by model time period. See - limit_tech_output_split_annual_Constraint for an analogous explanation. Under this + limit_tech_output_split_annual_constraint for an analogous explanation. Under this function, only the technologies with constant annual output (i.e., members of the :code:`tech_annual` set) are considered.""" inp = quicksum( @@ -719,7 +719,7 @@ def limit_tech_output_split_annual_constraint( model: TemoaModel, r: Region, p: Period, t: Technology, v: Vintage, o: Commodity, op: str ) -> ExprLike: r""" - This constraint operates similarly to limit_tech_output_split_Constraint. + This constraint operates similarly to limit_tech_output_split_constraint. However, under this function, only the technologies with constant annual output (i.e., members of the :code:`tech_annual` set) are considered. diff --git a/temoa/components/operations.py b/temoa/components/operations.py index 7221ca19c..cf35fe9fe 100644 --- a/temoa/components/operations.py +++ b/temoa/components/operations.py @@ -248,7 +248,7 @@ def ramp_up_day_constraint( ) -> ExprLike: r""" One of two constraints built from the ramp_up_hourly table, along with the - RampUpSeason_Constraint. RampUpDay constrains ramp rates between time slices + RampUpSeason_constraint. RampUpDay constrains ramp rates between time slices within each season and RampUpSeason constrains ramp rates between sequential seasons. If the :code:`time_sequencing` parameter is set to :code:`consecutive_days` then the RampUpSeason constraint is skipped as seasons already connect together. diff --git a/temoa/components/storage.py b/temoa/components/storage.py index c9be6c546..15316b431 100644 --- a/temoa/components/storage.py +++ b/temoa/components/storage.py @@ -90,7 +90,7 @@ def storage_energy_constraint( # We allow a non-zero daily delta only in the case of seasonal storage if model.is_seasonal_storage[t] and d == model.time_of_day.last(): - return Constraint.Skip # handled by SeasonalStorageEnergy_Constraint + return Constraint.Skip # handled by SeasonalStorageEnergy_constraint # This is the sum of all input=i sent TO storage tech t of vintage v with # output=o in p,s,d @@ -275,7 +275,7 @@ def seasonal_storage_energy_upper_bound_constraint( model: TemoaModel, r: Region, p: Period, s_seq: Season, d: TimeOfDay, t: Technology, v: Vintage ) -> ExprLike: r""" - Builds off of StorageEnergyUpperBound_Constraint. Enforces the max charge capacity + Builds off of StorageEnergyUpperBound_constraint. Enforces the max charge capacity of seasonal storage, summing the real storage level with the superimposed sequential seasonal storage level. :math:`s^*` represents the matching non-sequential season for the sequential season :math:`s^{seq}`. diff --git a/temoa/components/time.py b/temoa/components/time.py index 77cee17cc..6ff862d45 100644 --- a/temoa/components/time.py +++ b/temoa/components/time.py @@ -283,7 +283,7 @@ def create_time_sequence(model: TemoaModel) -> None: for s, d in model.time_season[p] * model.time_of_day: model.time_next[p, s, d] = loop_season_next_timeslice(model, p, s, d) case 'manual': - # Hidden feature. Define the sequence directly in the TimeManual table + # Hidden feature. Define the sequence directly in the time_manual table msg = 'Pulling time sequence from TimeNext table.' for p, s, d, s_next, d_next in model.time_manual: model.time_next[p, s, d] = s_next, d_next diff --git a/temoa/core/model.py b/temoa/core/model.py index 029498f79..536bbd256 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -819,7 +819,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: # devnote: I think this constraint is redundant # M.Retiredcapacity_constraint = Constraint( - # M.retired_capacity_var_rptv, rule=RetiredCapacity_Constraint + # M.retired_capacity_var_rptv, rule=RetiredCapacity_constraint # ) self.progress_marker_4a = BuildAction( ['Starting annual_retirement_constraint'], rule=progress_check @@ -866,7 +866,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: ) # M.ResourceExtractionConstraint = Constraint( - # M.ResourceConstraint_rpr, rule=ResourceExtraction_Constraint + # M.ResourceConstraint_rpr, rule=ResourceExtraction_constraint # ) self.baseload_diurnal_constraint_rpsdtv = Set( diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index 6d166a78d..1d354ec0b 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -557,7 +557,7 @@ def _load_time_season( data.setdefault(model.time_season_all.name, []) return - unique_seasons = sorted(list({(row[1],) for row in rows_to_load})) + unique_seasons = sorted({(row[1],) for row in rows_to_load}) self._load_component_data(data, model.time_season_all, unique_seasons) for period, season in rows_to_load: @@ -684,7 +684,7 @@ def _load_global_discount_rate( raw_data: Sequence[tuple[object, ...]], filtered_data: Sequence[tuple[object, ...]], ) -> None: - """Loads the required singleton GlobalDiscountRate.""" + """Loads the required singleton global_discount_rate.""" model = TemoaModel() if filtered_data: data[model.global_discount_rate.name] = {None: cast(float, filtered_data[0][0])} diff --git a/temoa/extensions/breakeven/breakeven.py b/temoa/extensions/breakeven/breakeven.py index 714c6f044..91a849bc9 100644 --- a/temoa/extensions/breakeven/breakeven.py +++ b/temoa/extensions/breakeven/breakeven.py @@ -79,7 +79,7 @@ def coef_IC(instance, target_tech, target_year): v = target_year P_0 = min(instance.time_optimize) P_e = instance.time_future.last() - GDR = value(instance.GlobalDiscountRate) + GDR = value(instance.global_discount_rate) MPL = instance.ModelProcessLife LLN = instance.loan_lifetime_process x = 1 + GDR # convenience variable, nothing more. @@ -104,7 +104,7 @@ def coef_FC(instance, target_tech, target_year): v = target_year P_0 = min(instance.time_optimize) P_e = instance.time_future.last() - GDR = value(instance.GlobalDiscountRate) + GDR = value(instance.global_discount_rate) MPL = instance.ModelProcessLife LLN = instance.loan_lifetime_process x = 1 + GDR # convenience variable, nothing more. @@ -171,7 +171,7 @@ def sensitivity(dat, techs): for t in techs: vintages = instance.vintage_optimize P_0 = min(instance.time_optimize) - GDR = value(instance.GlobalDiscountRate) + GDR = value(instance.global_discount_rate) MPL = instance.ModelProcessLife LLN = instance.loan_lifetime_process x = 1 + GDR # convenience variable, nothing more. diff --git a/temoa/extensions/monte_carlo/make_deltas_table.sql b/temoa/extensions/monte_carlo/make_deltas_table.sql index cb2fc304b..0e4396239 100644 --- a/temoa/extensions/monte_carlo/make_deltas_table.sql +++ b/temoa/extensions/monte_carlo/make_deltas_table.sql @@ -1,6 +1,6 @@ BEGIN; -CREATE TABLE IF NOT EXISTS OutputMCDelta +CREATE TABLE IF NOT EXISTS output_mc_delta ( scenario TEXT NOT NULL, run INT NOT NULL, @@ -11,4 +11,4 @@ CREATE TABLE IF NOT EXISTS OutputMCDelta ); -COMMIT; \ No newline at end of file +COMMIT; diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index cc16f6adc..6e7558147 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -309,7 +309,7 @@ def initialize_myopic_efficiency_table(self): ' ON main.efficiency.tech = main.lifetime_tech.tech ' ' AND main.efficiency.region = main.lifetime_tech.region ' ' JOIN time_period ' - ' ON efficiency.vintage = time_period.period ' + ' ON efficiency.vintage = main.time_period.period ' " WHERE flag = 'e'" ) @@ -378,7 +378,7 @@ def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: i 'WHERE (SELECT region, tech, vintage) ' ' NOT IN (SELECT region, tech, vintage FROM output_net_capacity ' ' WHERE period = ? AND scenario = ?) ' - 'AND tech not in (SELECT tech FROM Technology where unlim_cap > 0)' + 'AND tech not in (SELECT tech FROM main.technology where unlim_cap > 0)' ) if self.debugging: diff --git a/temoa/extensions/stochastics/EVPI.py b/temoa/extensions/stochastics/EVPI.py index 4732a337d..20dd1b247 100755 --- a/temoa/extensions/stochastics/EVPI.py +++ b/temoa/extensions/stochastics/EVPI.py @@ -86,12 +86,12 @@ def return_obj(instance): ctpTree = dict() # Child to parent dict, one to one mapping to_process = deque() - to_process.extend(sStructure.Children.keys()) + to_process.extend(sStructure.children.keys()) while to_process: node = to_process.pop() - if node in sStructure.Children: + if node in sStructure.children: # it's a parent! - new_nodes = set(sStructure.Children[node]) + new_nodes = set(sStructure.children[node]) to_process.extend(new_nodes) ctpTree.update({n: node for n in new_nodes}) @@ -104,7 +104,7 @@ def return_obj(instance): # ptcTree = dict( ptcTree ) # be slightly defensive; catch any additions # leaf_nodes = set(ctpTree.keys()) - set(ctpTree.values()) - leaf_nodes = set(sStructure.ScenarioLeafNode.values()) # Try to hack Kevin's code + leaf_nodes = set(sStructure.scenario_leaf_node.values()) # Try to hack Kevin's code scenario_nodes = dict() # Map from leafnode to 'node path' for node in leaf_nodes: # e.g.: {Rs0s0: [R, Rs0, Rs0s0]} @@ -117,22 +117,22 @@ def return_obj(instance): s.reverse() ########################################################################### - for s in sStructure.Scenarios: + for s in sStructure.scenarios: cp = 1.0 # Starting probability - for n in scenario_nodes[sStructure.ScenarioLeafNode[s]]: - cp = cp * sStructure.ConditionalProbability[n] - if not sStructure.ScenarioBasedData.value: + for n in scenario_nodes[sStructure.scenario_leaf_node[s]]: + cp = cp * sStructure.conditional_probability[n] + if not sStructure.scenario_based_data.value: s2fp_dict[s].append(n + '.dat') s2cd_dict[s] = cp - if sStructure.ScenarioBasedData.value: - for s in sStructure.Scenarios: + if sStructure.scenario_based_data.value: + for s in sStructure.scenarios: s2fp_dict[s].append(s + '.dat') # IP() model_module = __import__(tail[:-3], globals(), locals()) model = model_module.model pf_result = {'cost': list(), 'cd': list()} - for s in sStructure.Scenarios: + for s in sStructure.scenarios: pf_result['cd'].append(s2cd_dict[s]) data = DataPortal(model=model) for dat in s2fp_dict[s]: @@ -145,8 +145,8 @@ def return_obj(instance): # instance.load(results) obj_val = return_obj(instance) pf_result['cost'].append(obj_val) - sys.stdout.write('\nSolved .dat(s) {}\n'.format(s2fp_dict[s])) - sys.stdout.write(' Total cost: {}\n'.format(obj_val)) + sys.stdout.write(f'\nSolved .dat(s) {s2fp_dict[s]}\n') + sys.stdout.write(f' Total cost: {obj_val}\n') os.chdir(pwd) return pf_result @@ -205,7 +205,7 @@ def solve_ef(p_model, p_data, dummy_temoa_options=None): temoa_options.output_file = os.path.join( options.scenario_tree_location, dummy_temoa_options.output_file ) - msg = '\nStoring results from scenario {} to database.\n'.format(s.name) + msg = f'\nStoring results from scenario {s.name} to database.\n' sys.stderr.write(msg) formatted_results = pformat_results(ins, ef_result, temoa_options) @@ -226,16 +226,16 @@ def do_test(p_model, p_data, temoa_config=None): sys.stderr.write('\nSolving perfect sight mode\n') sys.stdout.write('-' * 25 + '\n') pf_result = solve_pf(p_model, this_data) - msg = 'Time: {} s\n'.format(timeit()) + msg = f'Time: {timeit()} s\n' sys.stderr.write(msg) sys.stderr.write('\nSolving extensive form\n') sys.stdout.write('-' * 25 + '\n') ef_result = solve_ef(p_model, this_data, temoa_config) - msg = '\nTime: {} s\n'.format(timeit()) - msg += 'runef objective value: {}\n'.format(ef_result) - msg += 'EVPI: {}\n'.format(compute_evpi(ef_result, pf_result)) + msg = f'\nTime: {timeit()} s\n' + msg += f'runef objective value: {ef_result}\n' + msg += f'EVPI: {compute_evpi(ef_result, pf_result)}\n' sys.stderr.write(msg) diff --git a/temoa/extensions/stochastics/generate_scenario_tree-nonhomogenous.py b/temoa/extensions/stochastics/generate_scenario_tree-nonhomogenous.py index 13814df4a..6fb568fb9 100755 --- a/temoa/extensions/stochastics/generate_scenario_tree-nonhomogenous.py +++ b/temoa/extensions/stochastics/generate_scenario_tree-nonhomogenous.py @@ -302,9 +302,9 @@ def write_scenario_file(stochasticset, tree): probability, ) = tree.get_scenario_data() - child_fmt = 'set Children[%s] :=\n %s\n\t;\n' + child_fmt = 'set children[%s] :=\n %s\n\t;\n' scenario_fmt = 'S%(i)s Rs%(i)s' - stages_fmt = 'set StageVariables[s{}] :=\n {}\n\t;' + stages_fmt = 'set stage_variables[s{}] :=\n {}\n\t;' stagecost_fmt = 's%s StochasticPointCost[%s]' leaves = '\n '.join(scenario_fmt % {'i': i} for i in scenarios) @@ -340,15 +340,15 @@ def write_scenario_file(stochasticset, tree): stage_var_sets = '\n\n'.join(stage_var_sets) structure = """\ -set Stages := +set stages := s%(stages)s ; -set Scenarios := +set scenarios := %(scenarios)s ; -set Nodes := +set nodes := %(nodes)s ; @@ -356,23 +356,23 @@ def write_scenario_file(stochasticset, tree): %(stage_var_sets)s -param NodeStage := +param node_stage := %(nodestage)s ; -param ConditionalProbability := +param conditional_probability := %(cond_prob)s ; -param ScenarioLeafNode := +param scenario_leaf_node := %(leaves)s ; -param Stagecost_variable := +param stage_cost_variable := %(stagecost)s ; -param ScenarioBasedData := False ; +param scenario_based_data := False ; """ structure %= dict( diff --git a/temoa/extensions/stochastics/generate_scenario_tree.py b/temoa/extensions/stochastics/generate_scenario_tree.py index 4c060d6c9..d9a531b38 100755 --- a/temoa/extensions/stochastics/generate_scenario_tree.py +++ b/temoa/extensions/stochastics/generate_scenario_tree.py @@ -302,9 +302,9 @@ def write_scenario_file(stochasticset, tree): probability, ) = tree.get_scenario_data() - child_fmt = 'set Children[%s] :=\n %s\n\t;\n' + child_fmt = 'set children[%s] :=\n %s\n\t;\n' scenario_fmt = 'S%(i)s Rs%(i)s' - stages_fmt = 'set StageVariables[s{}] :=\n {}\n\t;' + stages_fmt = 'set stage_variables[s{}] :=\n {}\n\t;' stagecost_fmt = 's%s StochasticPointCost[%s]' leaves = '\n '.join(scenario_fmt % {'i': i} for i in scenarios) @@ -339,15 +339,15 @@ def write_scenario_file(stochasticset, tree): stage_var_sets = '\n\n'.join(stage_var_sets) structure = """\ -set Stages := +set stages := s%(stages)s ; -set Scenarios := +set scenarios := %(scenarios)s ; -set Nodes := +set nodes := %(nodes)s ; @@ -355,23 +355,23 @@ def write_scenario_file(stochasticset, tree): %(stage_var_sets)s -param NodeStage := +param node_stage := %(nodestage)s ; -param ConditionalProbability := +param conditional_probability := %(cond_prob)s ; -param ScenarioLeafNode := +param scenario_leaf_node := %(leaves)s ; -param Stagecost_variable := +param stage_cost_variable := %(stagecost)s ; -param ScenarioBasedData := False ; +param scenario_based_data := False ; """ structure %= dict( diff --git a/temoa/extensions/stochastics/legacy_files/ef_writer_script_old.py b/temoa/extensions/stochastics/legacy_files/ef_writer_script_old.py index ffbe04d32..bf867c475 100644 --- a/temoa/extensions/stochastics/legacy_files/ef_writer_script_old.py +++ b/temoa/extensions/stochastics/legacy_files/ef_writer_script_old.py @@ -427,7 +427,7 @@ def CreateExtensiveFormInstance(options, scenario_tree): return binding_instance -class ExtensiveFormAlgorithm(object): +class ExtensiveFormAlgorithm: def __init__( self, options, @@ -514,7 +514,7 @@ def solve(self): print('Storing solution in scenario tree') self._scenario_tree.pullScenarioSolutionsFromInstances() - self._scenario_tree.snapshotSolutionFromScenarios() + self._scenario_tree.snapshotSolutionFromscenarios() # TODO # self._scenario_tree.update_variable_statistics() diff --git a/temoa/extensions/stochastics/legacy_files/scenariomodels.py b/temoa/extensions/stochastics/legacy_files/scenariomodels.py index 45deae4ea..0432aec94 100644 --- a/temoa/extensions/stochastics/legacy_files/scenariomodels.py +++ b/temoa/extensions/stochastics/legacy_files/scenariomodels.py @@ -5,22 +5,22 @@ # all set/parameter values are strings, representing the names of various entities/variables. -scenario_tree_model.Stages = Set(ordered=True) -scenario_tree_model.Nodes = Set() +scenario_tree_model.stages = Set(ordered=True) +scenario_tree_model.nodes = Set() -scenario_tree_model.NodeStage = Param(scenario_tree_model.Nodes, within=scenario_tree_model.Stages) -scenario_tree_model.Children = Set( - scenario_tree_model.Nodes, within=scenario_tree_model.Nodes, ordered=True +scenario_tree_model.node_stage = Param(scenario_tree_model.nodes, within=scenario_tree_model.stages) +scenario_tree_model.children = Set( + scenario_tree_model.nodes, within=scenario_tree_model.nodes, ordered=True ) -scenario_tree_model.ConditionalProbability = Param(scenario_tree_model.Nodes) +scenario_tree_model.conditional_probability = Param(scenario_tree_model.nodes) -scenario_tree_model.Scenarios = Set(ordered=True) -scenario_tree_model.ScenarioLeafNode = Param( - scenario_tree_model.Scenarios, within=scenario_tree_model.Nodes +scenario_tree_model.scenarios = Set(ordered=True) +scenario_tree_model.scenario_leaf_node = Param( + scenario_tree_model.scenarios, within=scenario_tree_model.nodes ) -scenario_tree_model.StageVariables = Set(scenario_tree_model.Stages) -scenario_tree_model.Stagecost_variable = Param(scenario_tree_model.Stages) +scenario_tree_model.stage_variables = Set(scenario_tree_model.stages) +scenario_tree_model.stage_cost_variable = Param(scenario_tree_model.stages) # scenario data can be populated in one of two ways. the first is "scenario-based", # in which a single .dat file contains all of the data for each scenario. the .dat @@ -29,30 +29,30 @@ # tree. the node-based method is more compact, but the scenario-based method is # often more natural when parameter data is generated via simulation. the default # is scenario-based. -scenario_tree_model.ScenarioBasedData = Param(within=Boolean, default=True, mutable=True) +scenario_tree_model.scenario_based_data = Param(within=Boolean, default=True, mutable=True) # do we bundle, and if so, how? -scenario_tree_model.Bundling = Param(within=Boolean, default=False, mutable=True) -scenario_tree_model.Bundles = Set() # bundle names -scenario_tree_model.BundleScenarios = Set(scenario_tree_model.Bundles) +scenario_tree_model.bundling = Param(within=Boolean, default=False, mutable=True) +scenario_tree_model.bundles = Set() # bundle names +scenario_tree_model.bundle_scenarios = Set(scenario_tree_model.bundles) # scenario_tree_model = AbstractModel() ## all set/parameter values are strings, representing the names of various entities/variables. -# scenario_tree_model.Stages = Set(ordered=True) -# scenario_tree_model.Nodes = Set() +# scenario_tree_model.stages = Set(ordered=True) +# scenario_tree_model.nodes = Set() -# scenario_tree_model.NodeStage = Param(scenario_tree_model.Nodes, within=scenario_tree_model.Stages) -# scenario_tree_model.Children = Set(scenario_tree_model.Nodes, within=scenario_tree_model.Nodes, ordered=True) -# scenario_tree_model.ConditionalProbability = Param(scenario_tree_model.Nodes) +# scenario_tree_model.node_stage = Param(scenario_tree_model.nodes, within=scenario_tree_model.stages) +# scenario_tree_model.children = Set(scenario_tree_model.nodes, within=scenario_tree_model.nodes, ordered=True) +# scenario_tree_model.conditional_probability = Param(scenario_tree_model.nodes) -# scenario_tree_model.Scenarios = Set(ordered=True) -# scenario_tree_model.ScenarioLeafNode = Param(scenario_tree_model.Scenarios, within=scenario_tree_model.Nodes) +# scenario_tree_model.scenarios = Set(ordered=True) +# scenario_tree_model.scenario_leaf_node = Param(scenario_tree_model.scenarios, within=scenario_tree_model.nodes) -# scenario_tree_model.StageVariables = Set(scenario_tree_model.Stages) -# scenario_tree_model.Stagecost_variable = Param(scenario_tree_model.Stages) +# scenario_tree_model.stage_variables = Set(scenario_tree_model.stages) +# scenario_tree_model.stage_cost_variable = Param(scenario_tree_model.stages) ## scenario data can be populated in one of two ways. the first is "scenario-based", ## in which a single .dat file contains all of the data for each scenario. the .dat @@ -61,4 +61,4 @@ ## tree. the node-based method is more compact, but the scenario-based method is ## often more natural when parameter data is generated via simulation. the default ## is scenario-based. -# scenario_tree_model.ScenarioBasedData = Param(within=Boolean, default=True) +# scenario_tree_model.scenario_based_data = Param(within=Boolean, default=True) diff --git a/temoa/extensions/stochastics/temoa_stochastic.py b/temoa/extensions/stochastics/temoa_stochastic.py index 7abf41316..9cb946135 100644 --- a/temoa/extensions/stochastics/temoa_stochastic.py +++ b/temoa/extensions/stochastics/temoa_stochastic.py @@ -63,12 +63,12 @@ def return_CP_and_path(p_data): ctpTree = dict() # Child to parent dict, one to one mapping to_process = deque() - to_process.extend(sStructure.Children.keys()) + to_process.extend(sStructure.children.keys()) while to_process: node = to_process.pop() - if node in sStructure.Children: + if node in sStructure.children: # it's a parent! - new_nodes = set(sStructure.Children[node]) + new_nodes = set(sStructure.children[node]) to_process.extend(new_nodes) ctpTree.update({n: node for n in new_nodes}) @@ -81,8 +81,8 @@ def return_CP_and_path(p_data): # ptcTree = dict( ptcTree ) # be slightly defensive; catch any additions # leaf_nodes = set(ctpTree.keys()) - set(ctpTree.values()) - # leaf_nodes = set(sStructure.ScenarioLeafNode.values()) # Try to hack Kevin's code - leaf_nodes = sStructure.ScenarioLeafNode.values() # Try to hack Kevin's code + # leaf_nodes = set(sStructure.scenario_leaf_node.values()) # Try to hack Kevin's code + leaf_nodes = sStructure.scenario_leaf_node.values() # Try to hack Kevin's code leaf_nodes_names = list() for n in leaf_nodes: leaf_nodes_names.append(n.value) @@ -99,16 +99,16 @@ def return_CP_and_path(p_data): s.reverse() ########################################################################### - for s in sStructure.Scenarios: + for s in sStructure.scenarios: cp = 1.0 # Starting probability - for n in scenario_nodes[value(sStructure.ScenarioLeafNode[s])]: - cp = cp * value(sStructure.ConditionalProbability[n]) - if not sStructure.ScenarioBasedData.value: + for n in scenario_nodes[value(sStructure.scenario_leaf_node[s])]: + cp = cp * value(sStructure.conditional_probability[n]) + if not sStructure.scenario_based_data.value: s2fp_dict[s].append(n + '.dat') s2cd_dict[s] = cp - if sStructure.ScenarioBasedData.value: - for s in sStructure.Scenarios: + if sStructure.scenario_based_data.value: + for s in sStructure.scenarios: s2fp_dict[s].append(s + '.dat') os.chdir(pwd) return (s2cd_dict, s2fp_dict) diff --git a/temoa/model_checking/validators.py b/temoa/model_checking/validators.py index 897884515..a6e0ad996 100644 --- a/temoa/model_checking/validators.py +++ b/temoa/model_checking/validators.py @@ -329,8 +329,8 @@ def validate_reserve_margin(model: TemoaModel) -> None: for r in model.planning_reserve_margin.sparse_iterkeys(): if all((r, p) not in model.process_reserve_periods for p in model.time_optimize): logger.warning( - 'Planning reserve margin provided but there are no reserve ' - f'technologies serving this region: {r, model.planning_reserve_margin[r]}' + 'Planning reserve margin provided but there are no reserve technologies serving this region: %s', + (r, model.planning_reserve_margin[r]), ) diff --git a/temoa/utilities/db_migration_v3_1_to_v4.py b/temoa/utilities/db_migration_v3_1_to_v4.py index 592a74730..a27fc8bae 100644 --- a/temoa/utilities/db_migration_v3_1_to_v4.py +++ b/temoa/utilities/db_migration_v3_1_to_v4.py @@ -174,8 +174,12 @@ def migrate_all(args) -> None: n = migrate_direct_table(con_old, con_new, old, new) print(f'Copied {n} rows: {old} -> {new}') total += n - except Exception as e: - print('Error:', e) + except Exception: + import traceback + + print(f'Error migrating {old} -> {new}:') + traceback.print_exc() + # ensure metadata version bumped cur = con_new.cursor() cur.execute("INSERT OR REPLACE INTO metadata VALUES ('DB_MAJOR', 4, '')") diff --git a/temoa/utilities/run_all_v4_migrations.py b/temoa/utilities/run_all_v4_migrations.py index 4e65f89ed..dbac59205 100644 --- a/temoa/utilities/run_all_v4_migrations.py +++ b/temoa/utilities/run_all_v4_migrations.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 """ -run_all_migrations.py +run_all_v4_migrations.py Iterates over all .sql files in a specified directory, runs the v3.1 to v4 SQL migration script on each, and overwrites the original file if successful. @@ -24,7 +24,7 @@ def run_command( - cmd: list[str], cwd: Path = None, capture_output: bool = True + cmd: list[str], cwd: Path | None = None, capture_output: bool = True ) -> subprocess.CompletedProcess: """Helper to run shell commands.""" print(f'Executing: {" ".join(cmd)}') diff --git a/tests/test_storage.py b/tests/test_storage.py index f80b4c10d..0a9017952 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -150,4 +150,4 @@ def test_storage_flow_balance(system_test_run): # ) # # get a built, unsolved model # model = sequencer.start() -# model.V_StorageInit['electricville', 'batt', 2025] = 0.5 +# model.v_storage_init['electricville', 'batt', 2025] = 0.5 diff --git a/tests/testing_data/US_9R_8D_legacy_set_sizes.json b/tests/testing_data/US_9R_8D_legacy_set_sizes.json index 5f4264131..cfe27e844 100644 --- a/tests/testing_data/US_9R_8D_legacy_set_sizes.json +++ b/tests/testing_data/US_9R_8D_legacy_set_sizes.json @@ -76,10 +76,10 @@ "TechOutputSplit_index": 30736692, "renewable_portfolio_standard_index": 63, "cost_fixed_rptv": 154120, - "cost_fixedVintageDefault_rtv": 46333, + "cost_fixed_vintage_default_rtv": 46333, "cost_invest_rtv": 42431, "cost_variable_rptv": 154120, - "cost_variableVintageDefault_rtv": 46333, + "cost_variable_vintage_default_rtv": 46333, "DiscountRate_rtv": 31717, "Loan_rtv": 31717, "ModelProcessLife_rptv": 154120, diff --git a/tests/testing_data/US_9R_8D_set_sizes.json b/tests/testing_data/US_9R_8D_set_sizes.json index 62b076110..29c911cbc 100644 --- a/tests/testing_data/US_9R_8D_set_sizes.json +++ b/tests/testing_data/US_9R_8D_set_sizes.json @@ -64,10 +64,10 @@ "TechOutputSplit_index": 30736692, "renewable_portfolio_standard_index": 63, "cost_fixed_rptv": 154120, - "cost_fixedVintageDefault_rtv": 46333, + "cost_fixed_vintage_default_rtv": 46333, "cost_invest_rtv": 42431, "cost_variable_rptv": 154120, - "cost_variableVintageDefault_rtv": 46333, + "cost_variable_vintage_default_rtv": 46333, "DiscountRate_rtv": 31717, "Loan_rtv": 31717, "ModelProcessLife_rptv": 154120, From 2a66b2c732699e2fd2d756415544998112108792 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 8 Nov 2025 18:04:57 -0500 Subject: [PATCH 319/587] migrating example dbs --- data_files/example_dbs/materials.sql | 2208 ++++++++++--------- data_files/example_dbs/morris_utopia.sql | 2134 +++++++++--------- data_files/example_dbs/seasonal_storage.sql | 1228 ++++++----- data_files/example_dbs/survival_curve.sql | 1380 ++++++------ data_files/example_dbs/test_system.sql | 2122 +++++++++--------- data_files/example_dbs/utopia.sql | 30 + 6 files changed, 4686 insertions(+), 4416 deletions(-) diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index 596efc87c..ccd4053e5 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -1,59 +1,11 @@ -PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE MetaData -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); -CREATE TABLE MetaDataReal -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,'Discount Rate for future costs'); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); -CREATE TABLE OutputDualVariable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE SeasonLabel -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SeasonLabel VALUES('summer',NULL); -INSERT INTO SeasonLabel VALUES('autumn',NULL); -INSERT INTO SeasonLabel VALUES('winter',NULL); -INSERT INTO SeasonLabel VALUES('spring',NULL); -CREATE TABLE SectorLabel -( - sector TEXT PRIMARY KEY, - notes TEXT -); CREATE TABLE capacity_credit ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, credit REAL, notes TEXT, @@ -64,13 +16,13 @@ CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -81,213 +33,213 @@ CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2000,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2010,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionA',2020,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2000,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2010,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'summer','morning','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'autumn','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'winter','morning','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'spring','morning','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'summer','afternoon','SOL_PV',0.2999999999999999889,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'autumn','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'winter','afternoon','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'spring','afternoon','SOL_PV',0.2000000000000000111,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'summer','evening','SOL_PV',0.1000000000000000055,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO capacity_factor_tech VALUES('RegionB',2020,'spring','overnight','SOL_PV',0.0,NULL); -CREATE TABLE CapacityToActivity +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'summer','morning','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'autumn','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'winter','morning','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'spring','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'summer','afternoon','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'autumn','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'winter','afternoon','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'spring','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'summer','morning','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'autumn','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'winter','morning','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'spring','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'summer','afternoon','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'autumn','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'winter','afternoon','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'spring','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'summer','morning','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'autumn','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'winter','morning','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'spring','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'summer','afternoon','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'autumn','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'winter','afternoon','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'spring','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'summer','morning','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'autumn','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'winter','morning','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'spring','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'summer','afternoon','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'autumn','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'winter','afternoon','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'spring','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'summer','morning','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'autumn','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'winter','morning','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'spring','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'summer','afternoon','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'autumn','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'winter','afternoon','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'spring','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'summer','morning','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'autumn','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'winter','morning','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'spring','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'summer','afternoon','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'autumn','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'winter','afternoon','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'spring','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'summer','evening','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'winter','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'spring','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'spring','overnight','SOL_PV',0.0,NULL); +CREATE TABLE capacity_to_activity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), c2a REAL, notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE Commodity +CREATE TABLE commodity ( name TEXT PRIMARY KEY, flag TEXT - REFERENCES CommodityType (label), + REFERENCES commodity_type (label), description TEXT ); -INSERT INTO Commodity VALUES('ethos','s','import dummy source'); -INSERT INTO Commodity VALUES('electricity','p','grid electricity'); -INSERT INTO Commodity VALUES('passenger_km','d','demand for passenger km'); -INSERT INTO Commodity VALUES('battery_nmc','a','battery - lithium nickel manganese cobalt oxide'); -INSERT INTO Commodity VALUES('battery_lfp','a','battery - lithium iron phosphate'); -INSERT INTO Commodity VALUES('lithium','a','lithium'); -INSERT INTO Commodity VALUES('cobalt','a','cobalt'); -INSERT INTO Commodity VALUES('phosphorous','a','phosphorous'); -INSERT INTO Commodity VALUES('diesel','a','diesel'); -INSERT INTO Commodity VALUES('heating','d','demand for residential heating'); -INSERT INTO Commodity VALUES('nickel','a','nickel'); -INSERT INTO Commodity VALUES('used_batt_nmc','wa','used battery - lithium nickel manganese cobalt oxide'); -INSERT INTO Commodity VALUES('used_batt_lfp','wa','used battery - lithium iron phosphate'); -INSERT INTO Commodity VALUES('co2e','e','emitted co2-equivalent GHGs'); -INSERT INTO Commodity VALUES('waste_steel','w','waste steel from cars'); -CREATE TABLE CommodityType +INSERT INTO "commodity" VALUES('ethos','s','import dummy source'); +INSERT INTO "commodity" VALUES('electricity','p','grid electricity'); +INSERT INTO "commodity" VALUES('passenger_km','d','demand for passenger km'); +INSERT INTO "commodity" VALUES('battery_nmc','a','battery - lithium nickel manganese cobalt oxide'); +INSERT INTO "commodity" VALUES('battery_lfp','a','battery - lithium iron phosphate'); +INSERT INTO "commodity" VALUES('lithium','a','lithium'); +INSERT INTO "commodity" VALUES('cobalt','a','cobalt'); +INSERT INTO "commodity" VALUES('phosphorous','a','phosphorous'); +INSERT INTO "commodity" VALUES('diesel','a','diesel'); +INSERT INTO "commodity" VALUES('heating','d','demand for residential heating'); +INSERT INTO "commodity" VALUES('nickel','a','nickel'); +INSERT INTO "commodity" VALUES('used_batt_nmc','wa','used battery - lithium nickel manganese cobalt oxide'); +INSERT INTO "commodity" VALUES('used_batt_lfp','wa','used battery - lithium iron phosphate'); +INSERT INTO "commodity" VALUES('co2e','e','emitted co2-equivalent GHGs'); +INSERT INTO "commodity" VALUES('waste_steel','w','waste steel from cars'); +CREATE TABLE commodity_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO CommodityType VALUES('w','waste commodity'); -INSERT INTO CommodityType VALUES('wa','waste annual commodity'); -INSERT INTO CommodityType VALUES('wp','waste physical commodity'); -INSERT INTO CommodityType VALUES('a','annual commodity'); -INSERT INTO CommodityType VALUES('p','physical commodity'); -INSERT INTO CommodityType VALUES('e','emissions commodity'); -INSERT INTO CommodityType VALUES('d','demand commodity'); -INSERT INTO CommodityType VALUES('s','source commodity'); +INSERT INTO "commodity_type" VALUES('w','waste commodity'); +INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); +INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); +INSERT INTO "commodity_type" VALUES('a','annual commodity'); +INSERT INTO "commodity_type" VALUES('p','physical commodity'); +INSERT INTO "commodity_type" VALUES('e','emissions commodity'); +INSERT INTO "commodity_type" VALUES('d','demand commodity'); +INSERT INTO "commodity_type" VALUES('s','source commodity'); CREATE TABLE construction_input ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage) ); -INSERT INTO construction_input VALUES('RegionA','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO construction_input VALUES('RegionA','battery_lfp','CAR_PHEV',2000,0.1000000000000000055,NULL,NULL); -INSERT INTO construction_input VALUES('RegionA','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO construction_input VALUES('RegionA','battery_lfp','CAR_PHEV',2010,0.1000000000000000055,NULL,NULL); -INSERT INTO construction_input VALUES('RegionA','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO construction_input VALUES('RegionA','battery_lfp','CAR_PHEV',2020,0.1000000000000000055,NULL,NULL); -INSERT INTO construction_input VALUES('RegionB','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO construction_input VALUES('RegionB','battery_lfp','CAR_PHEV',2000,0.1000000000000000055,NULL,NULL); -INSERT INTO construction_input VALUES('RegionB','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO construction_input VALUES('RegionB','battery_lfp','CAR_PHEV',2010,0.1000000000000000055,NULL,NULL); -INSERT INTO construction_input VALUES('RegionB','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO construction_input VALUES('RegionB','battery_lfp','CAR_PHEV',2020,0.1000000000000000055,NULL,NULL); +INSERT INTO "construction_input" VALUES('RegionA','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO "construction_input" VALUES('RegionA','battery_lfp','CAR_PHEV',2000,0.1,NULL,NULL); +INSERT INTO "construction_input" VALUES('RegionA','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO "construction_input" VALUES('RegionA','battery_lfp','CAR_PHEV',2010,0.1,NULL,NULL); +INSERT INTO "construction_input" VALUES('RegionA','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO "construction_input" VALUES('RegionA','battery_lfp','CAR_PHEV',2020,0.1,NULL,NULL); +INSERT INTO "construction_input" VALUES('RegionB','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO "construction_input" VALUES('RegionB','battery_lfp','CAR_PHEV',2000,0.1,NULL,NULL); +INSERT INTO "construction_input" VALUES('RegionB','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO "construction_input" VALUES('RegionB','battery_lfp','CAR_PHEV',2010,0.1,NULL,NULL); +INSERT INTO "construction_input" VALUES('RegionB','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO "construction_input" VALUES('RegionB','battery_lfp','CAR_PHEV',2020,0.1,NULL,NULL); CREATE TABLE cost_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT NOT NULL - REFERENCES Commodity (name), + REFERENCES commodity (name), cost REAL NOT NULL, units TEXT, notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -INSERT INTO cost_emission VALUES('RegionA',2000,'co2e',1.0,NULL,NULL); -INSERT INTO cost_emission VALUES('RegionA',2010,'co2e',1.0,NULL,NULL); -INSERT INTO cost_emission VALUES('RegionA',2020,'co2e',1.0,NULL,NULL); -INSERT INTO cost_emission VALUES('RegionB',2000,'co2e',1.0,NULL,NULL); -INSERT INTO cost_emission VALUES('RegionB',2010,'co2e',1.0,NULL,NULL); -INSERT INTO cost_emission VALUES('RegionB',2020,'co2e',1.0,NULL,NULL); +INSERT INTO "cost_emission" VALUES('RegionA',2000,'co2e',1.0,NULL,NULL); +INSERT INTO "cost_emission" VALUES('RegionA',2010,'co2e',1.0,NULL,NULL); +INSERT INTO "cost_emission" VALUES('RegionA',2020,'co2e',1.0,NULL,NULL); +INSERT INTO "cost_emission" VALUES('RegionB',2000,'co2e',1.0,NULL,NULL); +INSERT INTO "cost_emission" VALUES('RegionB',2010,'co2e',1.0,NULL,NULL); +INSERT INTO "cost_emission" VALUES('RegionB',2020,'co2e',1.0,NULL,NULL); CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -297,389 +249,345 @@ CREATE TABLE cost_invest ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO cost_invest VALUES('RegionA','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','CAR_PHEV',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','CAR_PHEV',2010,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','CAR_PHEV',2020,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','CAR_ICE',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','CAR_ICE',2010,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','CAR_ICE',2020,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','RECYCLE_NMC',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','RECYCLE_LFP',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','MANUFAC_NMC',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','MANUFAC_LFP',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','BATT_GRID',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','SOL_PV',2000,10.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA','GEN_DSL',2000,2.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','CAR_PHEV',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','CAR_PHEV',2010,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','CAR_PHEV',2020,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','CAR_ICE',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','CAR_ICE',2010,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','CAR_ICE',2020,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','RECYCLE_NMC',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','RECYCLE_LFP',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','MANUFAC_NMC',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','MANUFAC_LFP',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','BATT_GRID',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','GEN_DSL',2000,2.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionA-RegionB','ELEC_INTERTIE',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB-RegionA','ELEC_INTERTIE',2000,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('RegionB','SOL_PV',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionA','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionA','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionA','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionA','CAR_PHEV',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionA','CAR_PHEV',2010,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionA','CAR_PHEV',2020,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionA','CAR_ICE',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionA','CAR_ICE',2010,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionA','CAR_ICE',2020,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionA','RECYCLE_NMC',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionA','RECYCLE_LFP',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionA','MANUFAC_NMC',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionA','MANUFAC_LFP',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionA','BATT_GRID',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionA','SOL_PV',2000,10.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionA','GEN_DSL',2000,2.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionB','CAR_BEV',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionB','CAR_BEV',2010,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionB','CAR_BEV',2020,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionB','CAR_PHEV',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionB','CAR_PHEV',2010,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionB','CAR_PHEV',2020,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionB','CAR_ICE',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionB','CAR_ICE',2010,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionB','CAR_ICE',2020,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionB','RECYCLE_NMC',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionB','RECYCLE_LFP',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionB','MANUFAC_NMC',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionB','MANUFAC_LFP',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionB','BATT_GRID',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionB','GEN_DSL',2000,2.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionA-RegionB','ELEC_INTERTIE',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionB-RegionA','ELEC_INTERTIE',2000,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('RegionB','SOL_PV',2000,1.0,NULL,NULL); CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_variable VALUES('RegionA',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2000,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2010,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2020,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2000,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2010,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2020,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2000,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2010,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2020,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2000,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2010,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2020,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionA',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2000,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2010,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2020,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2000,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2010,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2020,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2000,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2010,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2020,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2000,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2010,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2020,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO cost_variable VALUES('RegionB',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); -CREATE TABLE Demand +INSERT INTO "cost_variable" VALUES('RegionA',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionA',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionA',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionA',2000,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionA',2010,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionA',2020,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionA',2000,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionA',2010,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionA',2020,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionA',2000,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionA',2010,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionA',2020,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionA',2000,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionA',2010,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionA',2020,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionA',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionA',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionA',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionB',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionB',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionB',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionB',2000,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionB',2010,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionB',2020,'IMPORT_LI',2000,2.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionB',2000,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionB',2010,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionB',2020,'IMPORT_NI',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionB',2000,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionB',2010,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionB',2020,'IMPORT_CO',2000,5.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionB',2000,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionB',2010,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionB',2020,'IMPORT_P',2000,3.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionB',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionB',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); +INSERT INTO "cost_variable" VALUES('RegionB',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); +CREATE TABLE demand ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), commodity TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), demand REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO Demand VALUES('RegionA',2000,'passenger_km',1.0,NULL,NULL); -INSERT INTO Demand VALUES('RegionA',2010,'passenger_km',1.0,NULL,NULL); -INSERT INTO Demand VALUES('RegionA',2020,'passenger_km',1.0,NULL,NULL); -INSERT INTO Demand VALUES('RegionA',2000,'heating',1.0,NULL,NULL); -INSERT INTO Demand VALUES('RegionA',2010,'heating',1.0,NULL,NULL); -INSERT INTO Demand VALUES('RegionA',2020,'heating',1.0,NULL,NULL); -INSERT INTO Demand VALUES('RegionB',2000,'passenger_km',1.0,NULL,NULL); -INSERT INTO Demand VALUES('RegionB',2010,'passenger_km',1.0,NULL,NULL); -INSERT INTO Demand VALUES('RegionB',2020,'passenger_km',1.0,NULL,NULL); -INSERT INTO Demand VALUES('RegionB',2000,'heating',1.0,NULL,NULL); -INSERT INTO Demand VALUES('RegionB',2010,'heating',1.0,NULL,NULL); -INSERT INTO Demand VALUES('RegionB',2020,'heating',1.0,NULL,NULL); -CREATE TABLE DemandSpecificDistribution +INSERT INTO "demand" VALUES('RegionA',2000,'passenger_km',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('RegionA',2010,'passenger_km',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('RegionA',2020,'passenger_km',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('RegionA',2000,'heating',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('RegionA',2010,'heating',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('RegionA',2020,'heating',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('RegionB',2000,'passenger_km',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('RegionB',2010,'passenger_km',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('RegionB',2020,'passenger_km',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('RegionB',2000,'heating',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('RegionB',2010,'heating',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('RegionB',2020,'heating',1.0,NULL,NULL); +CREATE TABLE demand_specific_distribution ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), demand_name TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), dsd REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'summer','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','morning','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','morning','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'spring','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'summer','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','afternoon','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','afternoon','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'spring','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'summer','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','evening','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','evening','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'spring','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'summer','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'autumn','overnight','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'winter','overnight','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2000,'spring','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'summer','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','morning','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','morning','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'spring','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'summer','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','afternoon','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','afternoon','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'spring','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'summer','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','evening','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','evening','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'spring','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'summer','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'autumn','overnight','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'winter','overnight','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2010,'spring','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'summer','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','morning','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','morning','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'spring','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'summer','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','afternoon','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','afternoon','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'spring','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'summer','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','evening','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','evening','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'spring','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'summer','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'autumn','overnight','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'winter','overnight','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionA',2020,'spring','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'summer','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','morning','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','morning','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'spring','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'summer','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','afternoon','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','afternoon','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'spring','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'summer','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','evening','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','evening','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'spring','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'summer','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'autumn','overnight','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'winter','overnight','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2000,'spring','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'summer','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','morning','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','morning','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'spring','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'summer','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','afternoon','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','afternoon','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'spring','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'summer','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','evening','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','evening','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'spring','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'summer','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'autumn','overnight','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'winter','overnight','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2010,'spring','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'summer','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','morning','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','morning','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'spring','morning','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'summer','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','afternoon','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','afternoon','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'spring','afternoon','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'summer','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','evening','heating',0.08000000000000000166,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','evening','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'spring','evening','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'summer','overnight','heating',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'autumn','overnight','heating',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'winter','overnight','heating',0.1600000000000000033,NULL); -INSERT INTO DemandSpecificDistribution VALUES('RegionB',2020,'spring','overnight','heating',0.0,NULL); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',1990,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',2000,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',2010,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',1990,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',2000,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',2010,'used_batt_lfp',0.1000000000000000055,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionA','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO end_of_life_output VALUES('RegionB','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'summer','morning','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'autumn','morning','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'winter','morning','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'spring','morning','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'summer','afternoon','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'autumn','afternoon','heating',0.08,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'winter','afternoon','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'spring','afternoon','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'summer','evening','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'autumn','evening','heating',0.08,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'winter','evening','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'spring','evening','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'summer','overnight','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'autumn','overnight','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'winter','overnight','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'spring','overnight','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'summer','morning','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'autumn','morning','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'winter','morning','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'spring','morning','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'summer','afternoon','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'autumn','afternoon','heating',0.08,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'winter','afternoon','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'spring','afternoon','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'summer','evening','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'autumn','evening','heating',0.08,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'winter','evening','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'spring','evening','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'summer','overnight','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'autumn','overnight','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'winter','overnight','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'spring','overnight','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'summer','morning','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'autumn','morning','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'winter','morning','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'spring','morning','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'summer','afternoon','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'autumn','afternoon','heating',0.08,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'winter','afternoon','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'spring','afternoon','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'summer','evening','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'autumn','evening','heating',0.08,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'winter','evening','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'spring','evening','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'summer','overnight','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'autumn','overnight','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'winter','overnight','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'spring','overnight','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'summer','morning','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'autumn','morning','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'winter','morning','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'spring','morning','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'summer','afternoon','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'autumn','afternoon','heating',0.08,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'winter','afternoon','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'spring','afternoon','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'summer','evening','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'autumn','evening','heating',0.08,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'winter','evening','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'spring','evening','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'summer','overnight','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'autumn','overnight','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'winter','overnight','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'spring','overnight','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'summer','morning','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'autumn','morning','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'winter','morning','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'spring','morning','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'summer','afternoon','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'autumn','afternoon','heating',0.08,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'winter','afternoon','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'spring','afternoon','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'summer','evening','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'autumn','evening','heating',0.08,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'winter','evening','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'spring','evening','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'summer','overnight','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'autumn','overnight','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'winter','overnight','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'spring','overnight','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'summer','morning','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'autumn','morning','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'winter','morning','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'spring','morning','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'summer','afternoon','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'autumn','afternoon','heating',0.08,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'winter','afternoon','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'spring','afternoon','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'summer','evening','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'autumn','evening','heating',0.08,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'winter','evening','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'spring','evening','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'summer','overnight','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'autumn','overnight','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'winter','overnight','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'spring','overnight','heating',0.0,NULL); CREATE TABLE efficiency ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO efficiency VALUES('RegionA','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2000000000000000111,NULL); -INSERT INTO efficiency VALUES('RegionA','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2000000000000000111,NULL); -INSERT INTO efficiency VALUES('RegionA','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','electricity','RECYCLE_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('RegionA','electricity','RECYCLE_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('RegionA','electricity','MANUFAC_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('RegionA','electricity','MANUFAC_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('RegionA','diesel','GEN_DSL',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','ethos','SOL_PV',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','electricity','BATT_GRID',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','diesel','FURNACE',2000,'heating',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','electricity','HEATPUMP',2000,'heating',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2000000000000000111,NULL); -INSERT INTO efficiency VALUES('RegionB','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2000000000000000111,NULL); -INSERT INTO efficiency VALUES('RegionB','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','electricity','RECYCLE_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('RegionB','electricity','RECYCLE_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('RegionB','electricity','MANUFAC_NMC',2000,'battery_nmc',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('RegionB','electricity','MANUFAC_LFP',2000,'battery_lfp',0.00100000000000000002,'Effectively zero'); -INSERT INTO efficiency VALUES('RegionB','diesel','GEN_DSL',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','ethos','SOL_PV',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','electricity','BATT_GRID',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','diesel','FURNACE',2000,'heating',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','electricity','HEATPUMP',2000,'heating',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionB','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); -INSERT INTO efficiency VALUES('RegionA-RegionB','electricity','ELEC_INTERTIE',2000,'electricity',0.9000000000000000222,NULL); -INSERT INTO efficiency VALUES('RegionB-RegionA','electricity','ELEC_INTERTIE',2000,'electricity',0.9000000000000000222,NULL); +INSERT INTO "efficiency" VALUES('RegionA','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2,NULL); +INSERT INTO "efficiency" VALUES('RegionA','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2,NULL); +INSERT INTO "efficiency" VALUES('RegionA','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','electricity','RECYCLE_NMC',2000,'battery_nmc',0.001,'Effectively zero'); +INSERT INTO "efficiency" VALUES('RegionA','electricity','RECYCLE_LFP',2000,'battery_lfp',0.001,'Effectively zero'); +INSERT INTO "efficiency" VALUES('RegionA','electricity','MANUFAC_NMC',2000,'battery_nmc',0.001,'Effectively zero'); +INSERT INTO "efficiency" VALUES('RegionA','electricity','MANUFAC_LFP',2000,'battery_lfp',0.001,'Effectively zero'); +INSERT INTO "efficiency" VALUES('RegionA','diesel','GEN_DSL',2000,'electricity',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','ethos','SOL_PV',2000,'electricity',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','electricity','BATT_GRID',2000,'electricity',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','diesel','FURNACE',2000,'heating',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','electricity','HEATPUMP',2000,'heating',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2,NULL); +INSERT INTO "efficiency" VALUES('RegionB','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2,NULL); +INSERT INTO "efficiency" VALUES('RegionB','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','electricity','RECYCLE_NMC',2000,'battery_nmc',0.001,'Effectively zero'); +INSERT INTO "efficiency" VALUES('RegionB','electricity','RECYCLE_LFP',2000,'battery_lfp',0.001,'Effectively zero'); +INSERT INTO "efficiency" VALUES('RegionB','electricity','MANUFAC_NMC',2000,'battery_nmc',0.001,'Effectively zero'); +INSERT INTO "efficiency" VALUES('RegionB','electricity','MANUFAC_LFP',2000,'battery_lfp',0.001,'Effectively zero'); +INSERT INTO "efficiency" VALUES('RegionB','diesel','GEN_DSL',2000,'electricity',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','ethos','SOL_PV',2000,'electricity',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','electricity','BATT_GRID',2000,'electricity',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','diesel','FURNACE',2000,'heating',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','electricity','HEATPUMP',2000,'heating',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionB','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); +INSERT INTO "efficiency" VALUES('RegionA-RegionB','electricity','ELEC_INTERTIE',2000,'electricity',0.9,NULL); +INSERT INTO "efficiency" VALUES('RegionB-RegionA','electricity','ELEC_INTERTIE',2000,'electricity',0.9,NULL); CREATE TABLE efficiency_variable ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), @@ -689,297 +597,312 @@ CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), activity REAL, units TEXT, notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO emission_activity VALUES('RegionA','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); -INSERT INTO emission_activity VALUES('RegionB','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); +INSERT INTO "emission_activity" VALUES('RegionA','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); +INSERT INTO "emission_activity" VALUES('RegionB','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) ); CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE end_of_life_output +( + region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, tech, vintage, output_comm) ); +INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_PHEV',1990,'used_batt_lfp',0.1,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_PHEV',2000,'used_batt_lfp',0.1,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_PHEV',2010,'used_batt_lfp',0.1,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_PHEV',1990,'used_batt_lfp',0.1,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_PHEV',2000,'used_batt_lfp',0.1,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_PHEV',2010,'used_batt_lfp',0.1,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); +INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); CREATE TABLE existing_capacity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, units TEXT, notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO existing_capacity VALUES('RegionA','CAR_BEV',1990,1.0,NULL,NULL); -INSERT INTO existing_capacity VALUES('RegionA','CAR_PHEV',1990,1.0,NULL,NULL); -INSERT INTO existing_capacity VALUES('RegionA','CAR_ICE',1990,1.0,NULL,NULL); -INSERT INTO existing_capacity VALUES('RegionB','CAR_BEV',1990,1.0,NULL,NULL); -INSERT INTO existing_capacity VALUES('RegionB','CAR_PHEV',1990,1.0,NULL,NULL); -INSERT INTO existing_capacity VALUES('RegionB','CAR_ICE',1990,1.0,NULL,NULL); -CREATE TABLE TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE loan_lifetime_process +INSERT INTO "existing_capacity" VALUES('RegionA','CAR_BEV',1990,1.0,NULL,NULL); +INSERT INTO "existing_capacity" VALUES('RegionA','CAR_PHEV',1990,1.0,NULL,NULL); +INSERT INTO "existing_capacity" VALUES('RegionA','CAR_ICE',1990,1.0,NULL,NULL); +INSERT INTO "existing_capacity" VALUES('RegionB','CAR_BEV',1990,1.0,NULL,NULL); +INSERT INTO "existing_capacity" VALUES('RegionB','CAR_PHEV',1990,1.0,NULL,NULL); +INSERT INTO "existing_capacity" VALUES('RegionB','CAR_ICE',1990,1.0,NULL,NULL); +CREATE TABLE lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE loan_rate +CREATE TABLE lifetime_survival_curve ( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - rate REAL, + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES technology (tech), + vintage INTEGER NOT NULL + REFERENCES time_period (period), + fraction REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_process -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, period, tech, vintage) ); CREATE TABLE lifetime_tech ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO lifetime_tech VALUES('RegionA','CAR_BEV',10.0,NULL); -INSERT INTO lifetime_tech VALUES('RegionA','CAR_PHEV',10.0,NULL); -INSERT INTO lifetime_tech VALUES('RegionA','CAR_ICE',10.0,NULL); -INSERT INTO lifetime_tech VALUES('RegionB','CAR_BEV',10.0,NULL); -INSERT INTO lifetime_tech VALUES('RegionB','CAR_PHEV',10.0,NULL); -INSERT INTO lifetime_tech VALUES('RegionB','CAR_ICE',10.0,NULL); -CREATE TABLE Operator +INSERT INTO "lifetime_tech" VALUES('RegionA','CAR_BEV',10.0,NULL); +INSERT INTO "lifetime_tech" VALUES('RegionA','CAR_PHEV',10.0,NULL); +INSERT INTO "lifetime_tech" VALUES('RegionA','CAR_ICE',10.0,NULL); +INSERT INTO "lifetime_tech" VALUES('RegionB','CAR_BEV',10.0,NULL); +INSERT INTO "lifetime_tech" VALUES('RegionB','CAR_PHEV',10.0,NULL); +INSERT INTO "lifetime_tech" VALUES('RegionB','CAR_ICE',10.0,NULL); +CREATE TABLE limit_activity ( - operator TEXT PRIMARY KEY, - notes TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO Operator VALUES('e','equal to'); -INSERT INTO Operator VALUES('le','less than or equal to'); -INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE limit_growth_capacity +CREATE TABLE limit_activity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_annual_capacity_factor +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE limit_capacity +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE limit_capacity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_capacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity +CREATE TABLE limit_emission +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitStorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -CREATE TABLE limit_activity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), new_cap REAL, units TEXT, notes TEXT, @@ -989,11 +912,11 @@ CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), share REAL, notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) @@ -1003,7 +926,7 @@ CREATE TABLE limit_resource region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), cum_act REAL, units TEXT, notes TEXT, @@ -1012,30 +935,49 @@ CREATE TABLE limit_resource CREATE TABLE limit_seasonal_capacity_factor ( region TEXT - REFERENCES Region (region), + REFERENCES region (region), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), factor REAL, notes TEXT, PRIMARY KEY(region, period, season, tech, operator) ); +CREATE TABLE limit_storage_level_fraction +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) +); CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -1044,82 +986,82 @@ CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2000,'diesel','CAR_PHEV','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2010,'diesel','CAR_PHEV','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionA',2020,'diesel','CAR_PHEV','le',0.8000000000000000444,NULL); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'lithium','MANUFAC_NMC','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'nickel','MANUFAC_NMC','le',0.1499999999999999945,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'cobalt','MANUFAC_NMC','le',0.04000000000000000083,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'electricity','MANUFAC_NMC','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'lithium','MANUFAC_LFP','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'phosphorous','MANUFAC_LFP','le',0.1900000000000000022,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'electricity','MANUFAC_LFP','le',0.0100000000000000002,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2000,'diesel','CAR_PHEV','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2010,'diesel','CAR_PHEV','le',0.8000000000000000444,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'electricity','CAR_PHEV','le',0.2000000000000000111,''); -INSERT INTO limit_tech_input_split_annual VALUES('RegionB',2020,'diesel','CAR_PHEV','le',0.8000000000000000444,NULL); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2000,'lithium','MANUFAC_NMC','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2000,'nickel','MANUFAC_NMC','le',0.15,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2000,'cobalt','MANUFAC_NMC','le',0.04,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2000,'electricity','MANUFAC_NMC','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2000,'lithium','MANUFAC_LFP','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2000,'phosphorous','MANUFAC_LFP','le',0.19,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2000,'electricity','MANUFAC_LFP','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2010,'lithium','MANUFAC_NMC','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2010,'nickel','MANUFAC_NMC','le',0.15,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2010,'cobalt','MANUFAC_NMC','le',0.04,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2010,'electricity','MANUFAC_NMC','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2010,'lithium','MANUFAC_LFP','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2010,'phosphorous','MANUFAC_LFP','le',0.19,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2010,'electricity','MANUFAC_LFP','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2020,'lithium','MANUFAC_NMC','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2020,'nickel','MANUFAC_NMC','le',0.15,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2020,'cobalt','MANUFAC_NMC','le',0.04,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2020,'electricity','MANUFAC_NMC','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2020,'lithium','MANUFAC_LFP','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2020,'phosphorous','MANUFAC_LFP','le',0.19,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2020,'electricity','MANUFAC_LFP','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2000,'electricity','CAR_PHEV','le',0.2,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2000,'diesel','CAR_PHEV','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2010,'electricity','CAR_PHEV','le',0.2,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2010,'diesel','CAR_PHEV','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2020,'electricity','CAR_PHEV','le',0.2,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2020,'diesel','CAR_PHEV','le',0.8,NULL); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2000,'lithium','MANUFAC_NMC','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2000,'nickel','MANUFAC_NMC','le',0.15,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2000,'cobalt','MANUFAC_NMC','le',0.04,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2000,'electricity','MANUFAC_NMC','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2000,'lithium','MANUFAC_LFP','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2000,'phosphorous','MANUFAC_LFP','le',0.19,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2000,'electricity','MANUFAC_LFP','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2010,'lithium','MANUFAC_NMC','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2010,'nickel','MANUFAC_NMC','le',0.15,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2010,'cobalt','MANUFAC_NMC','le',0.04,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2010,'electricity','MANUFAC_NMC','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2010,'lithium','MANUFAC_LFP','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2010,'phosphorous','MANUFAC_LFP','le',0.19,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2010,'electricity','MANUFAC_LFP','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2020,'lithium','MANUFAC_NMC','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2020,'nickel','MANUFAC_NMC','le',0.15,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2020,'cobalt','MANUFAC_NMC','le',0.04,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2020,'electricity','MANUFAC_NMC','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2020,'lithium','MANUFAC_LFP','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2020,'phosphorous','MANUFAC_LFP','le',0.19,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2020,'electricity','MANUFAC_LFP','le',0.01,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2000,'electricity','CAR_PHEV','le',0.2,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2000,'diesel','CAR_PHEV','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2010,'electricity','CAR_PHEV','le',0.2,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2010,'diesel','CAR_PHEV','le',0.8,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2020,'electricity','CAR_PHEV','le',0.2,''); +INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2020,'diesel','CAR_PHEV','le',0.8,NULL); CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) @@ -1128,171 +1070,286 @@ CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE LinkedTech +CREATE TABLE linked_tech ( primary_region TEXT, primary_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), driven_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); -CREATE TABLE OutputCurtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE OutputNetCapacity +CREATE TABLE loan_lifetime_process ( - scenario TEXT, region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + REFERENCES time_period (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE loan_rate +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE metadata +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); +INSERT INTO "metadata" VALUES('DB_MINOR',0,''); +CREATE TABLE metadata_real +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +CREATE TABLE myopic_efficiency +( + base_year integer, + region text, + input_comm text, + tech text, + vintage integer, + output_comm text, + efficiency real, + lifetime integer, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (region, input_comm, tech, vintage, output_comm) +); +CREATE TABLE operator +( + operator TEXT PRIMARY KEY, + notes TEXT ); -CREATE TABLE OutputBuiltCapacity +INSERT INTO "operator" VALUES('e','equal to'); +INSERT INTO "operator" VALUES('le','less than or equal to'); +INSERT INTO "operator" VALUES('ge','greater than or equal to'); +CREATE TABLE output_built_capacity ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, tech, vintage) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE output_cost ( scenario TEXT, region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + sector TEXT REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) +); +CREATE TABLE output_curtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES time_period (period), + tod TEXT + REFERENCES time_of_day (tod), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_dual_variable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE output_emission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE OutputFlowIn +CREATE TABLE output_flow_in ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputFlowOut +CREATE TABLE output_flow_out ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputStorageLevel +CREATE TABLE output_flow_out_summary +( + scenario TEXT NOT NULL, + region TEXT NOT NULL, + sector TEXT, + period INTEGER, + input_comm TEXT NOT NULL, + tech TEXT NOT NULL, + vintage INTEGER, + output_comm TEXT NOT NULL, + flow REAL NOT NULL, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_net_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_objective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE output_retired_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); @@ -1300,7 +1357,7 @@ CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY - REFERENCES Region (region), + REFERENCES region (region), margin REAL, notes TEXT ); @@ -1308,7 +1365,7 @@ CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -1317,95 +1374,59 @@ CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE Region +CREATE TABLE region ( region TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO Region VALUES('RegionA',NULL); -INSERT INTO Region VALUES('RegionB',NULL); +INSERT INTO "region" VALUES('RegionA',NULL); +INSERT INTO "region" VALUES('RegionB',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE TimeSegmentFraction +CREATE TABLE rps_requirement ( - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) -); -INSERT INTO TimeSegmentFraction VALUES(2000,'summer','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'autumn','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'winter','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'spring','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'summer','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'autumn','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'winter','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'spring','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'summer','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'autumn','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'winter','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'spring','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'summer','overnight',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'autumn','overnight',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'winter','overnight',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'spring','overnight',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'summer','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'autumn','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'winter','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'spring','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'summer','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'autumn','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'winter','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'spring','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'summer','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'autumn','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'winter','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'spring','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'summer','overnight',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'autumn','overnight',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'winter','overnight',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2010,'spring','overnight',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'summer','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'autumn','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'winter','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'spring','morning',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'summer','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'autumn','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'winter','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'spring','afternoon',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'summer','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'autumn','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'winter','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'spring','evening',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'summer','overnight',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'autumn','overnight',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'winter','overnight',0.0625,NULL); -INSERT INTO TimeSegmentFraction VALUES(2020,'spring','overnight',0.0625,NULL); + region TEXT NOT NULL + REFERENCES region (region), + period INTEGER NOT NULL + REFERENCES time_period (period), + tech_group TEXT NOT NULL + REFERENCES tech_group (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE season_label +( + season TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "season_label" VALUES('summer',NULL); +INSERT INTO "season_label" VALUES('autumn',NULL); +INSERT INTO "season_label" VALUES('winter',NULL); +INSERT INTO "season_label" VALUES('spring',NULL); +CREATE TABLE sector_label +( + sector TEXT PRIMARY KEY, + notes TEXT +); CREATE TABLE storage_duration ( region TEXT, @@ -1414,186 +1435,213 @@ CREATE TABLE storage_duration notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO storage_duration VALUES('RegionA','BATT_GRID',2.0,'2 hours energy storage'); -INSERT INTO storage_duration VALUES('RegionB','BATT_GRID',2.0,'2 hours energy storage'); -CREATE TABLE lifetime_survival_curve +INSERT INTO "storage_duration" VALUES('RegionA','BATT_GRID',2.0,'2 hours energy storage'); +INSERT INTO "storage_duration" VALUES('RegionB','BATT_GRID',2.0,'2 hours energy storage'); +CREATE TABLE tech_group ( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE tech_group_member +( + group_name TEXT + REFERENCES tech_group (group_name), + tech TEXT + REFERENCES technology (tech), + PRIMARY KEY (group_name, tech) ); -CREATE TABLE TechnologyType +CREATE TABLE technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES technology_type (label) +); +INSERT INTO "technology" VALUES('IMPORT_LI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'lithium importer'); +INSERT INTO "technology" VALUES('IMPORT_CO','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'cobalt importer'); +INSERT INTO "technology" VALUES('IMPORT_P','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'phosphorous importer'); +INSERT INTO "technology" VALUES('CAR_BEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - battery electric'); +INSERT INTO "technology" VALUES('CAR_PHEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - plug in hybrid'); +INSERT INTO "technology" VALUES('CAR_ICE','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - internal combustion'); +INSERT INTO "technology" VALUES('RECYCLE_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'nmc battery recycler'); +INSERT INTO "technology" VALUES('RECYCLE_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'lfp battery recycler'); +INSERT INTO "technology" VALUES('MANUFAC_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'nmc battery manufacturing'); +INSERT INTO "technology" VALUES('MANUFAC_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'lfp battery manufacturing'); +INSERT INTO "technology" VALUES('IMPORT_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'nickel importer'); +INSERT INTO "technology" VALUES('DOMESTIC_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'domestic nickel production'); +INSERT INTO "technology" VALUES('GEN_DSL','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,'diesel generators'); +INSERT INTO "technology" VALUES('SOL_PV','p','electricity',NULL,NULL,0,0,0,1,0,0,0,0,'solar panels'); +INSERT INTO "technology" VALUES('BATT_GRID','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,0,'grid battery storage'); +INSERT INTO "technology" VALUES('FURNACE','p','residential',NULL,NULL,1,0,0,0,0,0,0,0,'diesel furnace heater'); +INSERT INTO "technology" VALUES('HEATPUMP','p','residential',NULL,NULL,1,0,0,0,0,0,0,0,'heat pump'); +INSERT INTO "technology" VALUES('IMPORT_DSL','p','fuels',NULL,NULL,1,1,0,0,0,0,0,0,'diesel importer'); +INSERT INTO "technology" VALUES('ELEC_INTERTIE','p','electricity',NULL,NULL,0,0,0,0,0,0,1,0,'dummy tech to make landfill feasible'); +CREATE TABLE technology_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('p','production technology'); -INSERT INTO TechnologyType VALUES('pb','baseload production technology'); -INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE TimeOfDay +INSERT INTO "technology_type" VALUES('p','production technology'); +INSERT INTO "technology_type" VALUES('pb','baseload production technology'); +INSERT INTO "technology_type" VALUES('ps','storage production technology'); +CREATE TABLE time_of_day ( sequence INTEGER UNIQUE, tod TEXT PRIMARY KEY ); -INSERT INTO TimeOfDay VALUES(1,'morning'); -INSERT INTO TimeOfDay VALUES(2,'afternoon'); -INSERT INTO TimeOfDay VALUES(3,'evening'); -INSERT INTO TimeOfDay VALUES(4,'overnight'); -CREATE TABLE TimePeriod +INSERT INTO "time_of_day" VALUES(1,'morning'); +INSERT INTO "time_of_day" VALUES(2,'afternoon'); +INSERT INTO "time_of_day" VALUES(3,'evening'); +INSERT INTO "time_of_day" VALUES(4,'overnight'); +CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES TimePeriodType (label) + REFERENCES time_period_type (label) +); +INSERT INTO "time_period" VALUES(1,1990,'e'); +INSERT INTO "time_period" VALUES(2,2000,'f'); +INSERT INTO "time_period" VALUES(3,2010,'f'); +INSERT INTO "time_period" VALUES(4,2020,'f'); +INSERT INTO "time_period" VALUES(5,2030,'f'); +CREATE TABLE time_period_type +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO "time_period_type" VALUES('e','existing vintages'); +INSERT INTO "time_period_type" VALUES('f','future'); +CREATE TABLE time_season +( + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + season TEXT REFERENCES season_label(season), + notes TEXT, + PRIMARY KEY (period, sequence, season) ); -INSERT INTO TimePeriod VALUES(1,1990,'e'); -INSERT INTO TimePeriod VALUES(2,2000,'f'); -INSERT INTO TimePeriod VALUES(3,2010,'f'); -INSERT INTO TimePeriod VALUES(4,2020,'f'); -INSERT INTO TimePeriod VALUES(5,2030,'f'); -CREATE TABLE TimeSeason +INSERT INTO "time_season" VALUES(2000,1,'summer',NULL); +INSERT INTO "time_season" VALUES(2000,2,'autumn',NULL); +INSERT INTO "time_season" VALUES(2000,3,'winter',NULL); +INSERT INTO "time_season" VALUES(2000,4,'spring',NULL); +INSERT INTO "time_season" VALUES(2010,5,'summer',NULL); +INSERT INTO "time_season" VALUES(2010,6,'autumn',NULL); +INSERT INTO "time_season" VALUES(2010,7,'winter',NULL); +INSERT INTO "time_season" VALUES(2010,8,'spring',NULL); +INSERT INTO "time_season" VALUES(2020,9,'summer',NULL); +INSERT INTO "time_season" VALUES(2020,10,'autumn',NULL); +INSERT INTO "time_season" VALUES(2020,11,'winter',NULL); +INSERT INTO "time_season" VALUES(2020,12,'spring',NULL); +CREATE TABLE time_season_all ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); -INSERT INTO TimeSeason VALUES(2000,1,'summer',NULL); -INSERT INTO TimeSeason VALUES(2000,2,'autumn',NULL); -INSERT INTO TimeSeason VALUES(2000,3,'winter',NULL); -INSERT INTO TimeSeason VALUES(2000,4,'spring',NULL); -INSERT INTO TimeSeason VALUES(2010,5,'summer',NULL); -INSERT INTO TimeSeason VALUES(2010,6,'autumn',NULL); -INSERT INTO TimeSeason VALUES(2010,7,'winter',NULL); -INSERT INTO TimeSeason VALUES(2010,8,'spring',NULL); -INSERT INTO TimeSeason VALUES(2020,9,'summer',NULL); -INSERT INTO TimeSeason VALUES(2020,10,'autumn',NULL); -INSERT INTO TimeSeason VALUES(2020,11,'winter',NULL); -INSERT INTO TimeSeason VALUES(2020,12,'spring',NULL); CREATE TABLE time_season_sequential ( - period INTEGER - REFERENCES TimePeriod (period), + period INTEGER REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES SeasonLabel (season), + season TEXT REFERENCES season_label(season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE TimePeriodType +CREATE TABLE time_season_to_sequential ( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO TimePeriodType VALUES('e','existing vintages'); -INSERT INTO TimePeriodType VALUES('f','future'); -CREATE TABLE OutputEmission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE RPSRequirement -( - region TEXT NOT NULL - REFERENCES Region (region), - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech_group TEXT NOT NULL - REFERENCES TechGroup (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE TechGroupMember -( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES Technology (tech), - PRIMARY KEY (group_name, tech) + period INTEGER + REFERENCES time_period (period), + sequence INTEGER, + seas_seq TEXT, + season TEXT + REFERENCES season_label (season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) ); -CREATE TABLE Technology +CREATE TABLE time_segment_fraction ( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) -); -INSERT INTO Technology VALUES('IMPORT_LI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'lithium importer'); -INSERT INTO Technology VALUES('IMPORT_CO','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'cobalt importer'); -INSERT INTO Technology VALUES('IMPORT_P','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'phosphorous importer'); -INSERT INTO Technology VALUES('CAR_BEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - battery electric'); -INSERT INTO Technology VALUES('CAR_PHEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - plug in hybrid'); -INSERT INTO Technology VALUES('CAR_ICE','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - internal combustion'); -INSERT INTO Technology VALUES('RECYCLE_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'nmc battery recycler'); -INSERT INTO Technology VALUES('RECYCLE_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'lfp battery recycler'); -INSERT INTO Technology VALUES('MANUFAC_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'nmc battery manufacturing'); -INSERT INTO Technology VALUES('MANUFAC_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'lfp battery manufacturing'); -INSERT INTO Technology VALUES('IMPORT_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'nickel importer'); -INSERT INTO Technology VALUES('DOMESTIC_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'domestic nickel production'); -INSERT INTO Technology VALUES('GEN_DSL','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,'diesel generators'); -INSERT INTO Technology VALUES('SOL_PV','p','electricity',NULL,NULL,0,0,0,1,0,0,0,0,'solar panels'); -INSERT INTO Technology VALUES('BATT_GRID','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,0,'grid battery storage'); -INSERT INTO Technology VALUES('FURNACE','p','residential',NULL,NULL,1,0,0,0,0,0,0,0,'diesel furnace heater'); -INSERT INTO Technology VALUES('HEATPUMP','p','residential',NULL,NULL,1,0,0,0,0,0,0,0,'heat pump'); -INSERT INTO Technology VALUES('IMPORT_DSL','p','fuels',NULL,NULL,1,1,0,0,0,0,0,0,'diesel importer'); -INSERT INTO Technology VALUES('ELEC_INTERTIE','p','electricity',NULL,NULL,0,0,0,0,0,0,1,0,'dummy tech to make landfill feasible'); -CREATE TABLE OutputCost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) -); + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + segment_fraction REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) +); +INSERT INTO "time_segment_fraction" VALUES(2000,'summer','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'autumn','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'winter','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'spring','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'summer','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'autumn','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'winter','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'spring','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'summer','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'autumn','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'winter','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'spring','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'summer','overnight',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'autumn','overnight',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'winter','overnight',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'spring','overnight',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'summer','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'autumn','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'winter','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'spring','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'summer','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'autumn','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'winter','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'spring','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'summer','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'autumn','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'winter','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'spring','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'summer','overnight',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'autumn','overnight',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'winter','overnight',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2010,'spring','overnight',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'summer','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'autumn','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'winter','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'spring','morning',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'summer','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'autumn','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'winter','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'spring','afternoon',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'summer','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'autumn','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'winter','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'spring','evening',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'summer','overnight',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'autumn','overnight',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'winter','overnight',0.0625,NULL); +INSERT INTO "time_segment_fraction" VALUES(2020,'spring','overnight',0.0625,NULL); +CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index c695e6b7b..88d44f6d3 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -1,65 +1,11 @@ -PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE MetaData -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO MetaData VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); -INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); -CREATE TABLE MetaDataReal -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); -CREATE TABLE OutputDualVariable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE SeasonLabel -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SeasonLabel VALUES('inter',NULL); -INSERT INTO SeasonLabel VALUES('summer',NULL); -INSERT INTO SeasonLabel VALUES('winter',NULL); -CREATE TABLE SectorLabel -( - sector TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SectorLabel VALUES('supply',NULL); -INSERT INTO SectorLabel VALUES('electric',NULL); -INSERT INTO SectorLabel VALUES('transport',NULL); -INSERT INTO SectorLabel VALUES('commercial',NULL); -INSERT INTO SectorLabel VALUES('residential',NULL); -INSERT INTO SectorLabel VALUES('industrial',NULL); CREATE TABLE capacity_credit ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, credit REAL, notes TEXT, @@ -70,209 +16,209 @@ CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO capacity_factor_process VALUES('utopia',2000,'inter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2000,'inter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2000,'winter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2000,'winter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2000,'summer','day','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2000,'summer','night','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','day','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','night','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','day','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','night','E31',2000,0.2752999999999999892,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','day','E31',2010,0.2756000000000000116,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'inter','night','E31',2010,0.2756000000000000116,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','day','E31',2010,0.2756000000000000116,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'winter','night','E31',2010,0.2756000000000000116,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','day','E31',2010,0.2756000000000000116,''); -INSERT INTO capacity_factor_process VALUES('utopia',2010,'summer','night','E31',2010,0.2756000000000000116,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'inter','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'inter','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'winter','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'winter','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'summer','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'summer','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','day','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','night','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','day','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','night','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','day','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','night','E31',2010,0.2756,''); CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'inter','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'winter','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',1990,'summer','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'inter','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'winter','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2000,'summer','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E01',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E21',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E31',0.2750000000000000222,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E51',0.1700000000000000122,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'inter','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'winter','night','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','day','E70',0.8000000000000000444,''); -INSERT INTO capacity_factor_tech VALUES('utopia',2010,'summer','night','E70',0.8000000000000000444,''); -CREATE TABLE CapacityToActivity +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E70',0.8,''); +CREATE TABLE capacity_to_activity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), c2a REAL, notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO CapacityToActivity VALUES('utopia','E01',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('utopia','E21',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('utopia','E31',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('utopia','E51',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('utopia','E70',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('utopia','RHE',1.0,''); -INSERT INTO CapacityToActivity VALUES('utopia','RHO',1.0,''); -INSERT INTO CapacityToActivity VALUES('utopia','RL1',1.0,''); -INSERT INTO CapacityToActivity VALUES('utopia','SRE',1.0,''); -INSERT INTO CapacityToActivity VALUES('utopia','TXD',1.0,''); -INSERT INTO CapacityToActivity VALUES('utopia','TXE',1.0,''); -INSERT INTO CapacityToActivity VALUES('utopia','TXG',1.0,''); -CREATE TABLE Commodity +INSERT INTO "capacity_to_activity" VALUES('utopia','E01',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','E21',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','E31',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','E51',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','E70',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','RHE',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','RHO',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','RL1',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','SRE',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','TXD',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','TXE',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('utopia','TXG',1.0,''); +CREATE TABLE commodity ( name TEXT PRIMARY KEY, flag TEXT - REFERENCES CommodityType (label), + REFERENCES commodity_type (label), description TEXT ); -INSERT INTO Commodity VALUES('ethos','s','# dummy commodity to supply inputs (makes graph easier to read)'); -INSERT INTO Commodity VALUES('DSL','p','# diesel'); -INSERT INTO Commodity VALUES('ELC','p','# electricity'); -INSERT INTO Commodity VALUES('FEQ','p','# fossil equivalent'); -INSERT INTO Commodity VALUES('GSL','p','# gasoline'); -INSERT INTO Commodity VALUES('HCO','p','# coal'); -INSERT INTO Commodity VALUES('HYD','p','# water'); -INSERT INTO Commodity VALUES('OIL','p','# crude oil'); -INSERT INTO Commodity VALUES('URN','p','# uranium'); -INSERT INTO Commodity VALUES('co2','e','#CO2 emissions'); -INSERT INTO Commodity VALUES('nox','e','#NOX emissions'); -INSERT INTO Commodity VALUES('RH','d','# residential heating'); -INSERT INTO Commodity VALUES('RL','d','# residential lighting'); -INSERT INTO Commodity VALUES('TX','d','# transportation'); -CREATE TABLE CommodityType +INSERT INTO "commodity" VALUES('ethos','s','# dummy commodity to supply inputs (makes graph easier to read)'); +INSERT INTO "commodity" VALUES('DSL','p','# diesel'); +INSERT INTO "commodity" VALUES('ELC','p','# electricity'); +INSERT INTO "commodity" VALUES('FEQ','p','# fossil equivalent'); +INSERT INTO "commodity" VALUES('GSL','p','# gasoline'); +INSERT INTO "commodity" VALUES('HCO','p','# coal'); +INSERT INTO "commodity" VALUES('HYD','p','# water'); +INSERT INTO "commodity" VALUES('OIL','p','# crude oil'); +INSERT INTO "commodity" VALUES('URN','p','# uranium'); +INSERT INTO "commodity" VALUES('co2','e','#CO2 emissions'); +INSERT INTO "commodity" VALUES('nox','e','#NOX emissions'); +INSERT INTO "commodity" VALUES('RH','d','# residential heating'); +INSERT INTO "commodity" VALUES('RL','d','# residential lighting'); +INSERT INTO "commodity" VALUES('TX','d','# transportation'); +CREATE TABLE commodity_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO CommodityType VALUES('w','waste commodity'); -INSERT INTO CommodityType VALUES('wa','waste annual commodity'); -INSERT INTO CommodityType VALUES('wp','waste physical commodity'); -INSERT INTO CommodityType VALUES('a','annual commodity'); -INSERT INTO CommodityType VALUES('s','source commodity'); -INSERT INTO CommodityType VALUES('p','physical commodity'); -INSERT INTO CommodityType VALUES('e','emissions commodity'); -INSERT INTO CommodityType VALUES('d','demand commodity'); +INSERT INTO "commodity_type" VALUES('w','waste commodity'); +INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); +INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); +INSERT INTO "commodity_type" VALUES('a','annual commodity'); +INSERT INTO "commodity_type" VALUES('s','source commodity'); +INSERT INTO "commodity_type" VALUES('p','physical commodity'); +INSERT INTO "commodity_type" VALUES('e','emissions commodity'); +INSERT INTO "commodity_type" VALUES('d','demand commodity'); CREATE TABLE construction_input ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -282,403 +228,386 @@ CREATE TABLE cost_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT NOT NULL - REFERENCES Commodity (name), + REFERENCES commodity (name), cost REAL NOT NULL, units TEXT, notes TEXT, PRIMARY KEY (region, period, emis_comm) ); -INSERT INTO cost_emission VALUES('utopia',2000,'nox',5.0,NULL,NULL); -INSERT INTO cost_emission VALUES('utopia',2010,'co2',6.0,NULL,NULL); +INSERT INTO "cost_emission" VALUES('utopia',2000,'nox',5.0,NULL,NULL); +INSERT INTO "cost_emission" VALUES('utopia',2010,'co2',6.0,NULL,NULL); CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1960,40.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1970,40.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1980,40.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E01',1990,40.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E01',1970,70.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E01',1980,70.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E01',1990,70.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E01',2000,70.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E01',1980,100.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E01',1990,100.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E01',2000,100.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E01',2010,100.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E21',1990,500.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E21',1990,500.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E21',1990,500.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E21',2000,500.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E21',2000,500.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E21',2010,500.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E31',1980,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E31',1990,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E31',1980,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E31',1990,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E31',2000,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E31',1980,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E31',1990,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E31',2000,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E31',2010,75.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E51',1980,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E51',1990,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E51',1980,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E51',1990,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E51',2000,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E51',1980,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E51',1990,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E51',2000,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E51',2010,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1960,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1970,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1980,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'E70',1990,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E70',1970,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E70',1980,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E70',1990,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'E70',2000,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E70',1980,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E70',1990,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E70',2000,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'E70',2010,30.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'RHO',1970,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'RHO',1980,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'RHO',1990,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'RHO',1980,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'RHO',1990,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'RHO',2000,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'RHO',1990,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'RHO',2000,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'RHO',2010,1.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'RL1',1980,9.46000000000000086,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'RL1',1990,9.46000000000000086,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'RL1',2000,9.46000000000000086,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'RL1',2010,9.46000000000000086,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'TXD',1970,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'TXD',1980,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'TXD',1990,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXD',1980,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXD',1990,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXD',2000,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'TXD',2000,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'TXD',2010,52.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'TXE',1990,100.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXE',1990,90.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXE',2000,90.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'TXE',2000,80.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'TXE',2010,80.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'TXG',1970,48.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'TXG',1980,48.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',1990,'TXG',1990,48.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXG',1980,48.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXG',1990,48.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2000,'TXG',2000,48.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'TXG',2000,48.0,'',''); -INSERT INTO cost_fixed VALUES('utopia',2010,'TXG',2010,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1960,40.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1970,40.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1980,40.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1990,40.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',1970,70.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',1980,70.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',1990,70.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',2000,70.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',1980,100.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',1990,100.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',2000,100.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',2010,100.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E21',1990,500.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E21',1990,500.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E21',1990,500.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E21',2000,500.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E21',2000,500.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E21',2010,500.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E31',1980,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E31',1990,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E31',1980,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E31',1990,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E31',2000,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',1980,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',1990,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',2000,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',2010,75.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E51',1980,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E51',1990,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E51',1980,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E51',1990,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E51',2000,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',1980,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',1990,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',2000,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',2010,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1960,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1970,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1980,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1990,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',1970,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',1980,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',1990,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',2000,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',1980,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',1990,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',2000,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',2010,30.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'RHO',1970,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'RHO',1980,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'RHO',1990,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'RHO',1980,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'RHO',1990,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'RHO',2000,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'RHO',1990,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'RHO',2000,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'RHO',2010,1.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'RL1',1980,9.46,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'RL1',1990,9.46,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'RL1',2000,9.46,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'RL1',2010,9.46,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXD',1970,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXD',1980,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXD',1990,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXD',1980,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXD',1990,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXD',2000,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXD',2000,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXD',2010,52.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXE',1990,100.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXE',1990,90.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXE',2000,90.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXE',2000,80.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXE',2010,80.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXG',1970,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXG',1980,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXG',1990,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXG',1980,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXG',1990,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXG',2000,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXG',2000,48.0,'',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXG',2010,48.0,'',''); CREATE TABLE cost_invest ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, - MMAnalysis TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO cost_invest VALUES('utopia','E01',1990,2000.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','E01',2000,1300.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','E01',2010,1200.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','E21',1990,5000.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','E21',2000,5000.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','E21',2010,5000.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','E31',1990,3000.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','E31',2000,3000.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','E31',2010,3000.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','E51',1990,900.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','E51',2000,900.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','E51',2010,900.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','E70',1990,1000.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','E70',2000,1000.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','E70',2010,1000.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','RHE',1990,90.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','RHE',2000,90.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','RHE',2010,90.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','RHO',1990,100.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','RHO',2000,100.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','RHO',2010,100.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','SRE',1990,100.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','SRE',2000,100.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','SRE',2010,100.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','TXD',1990,1044.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','TXD',2000,1044.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','TXD',2010,1044.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','TXE',1990,2000.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','TXE',2000,1750.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','TXE',2010,1500.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','TXG',1990,1044.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','TXG',2000,1044.0,'','',NULL); -INSERT INTO cost_invest VALUES('utopia','TXG',2010,1044.0,'','',NULL); +INSERT INTO "cost_invest" VALUES('utopia','E01',1990,2000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E01',2000,1300.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E01',2010,1200.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E21',1990,5000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E21',2000,5000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E21',2010,5000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E31',1990,3000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E31',2000,3000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E31',2010,3000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E51',1990,900.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E51',2000,900.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E51',2010,900.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E70',1990,1000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E70',2000,1000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','E70',2010,1000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','RHE',1990,90.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','RHE',2000,90.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','RHE',2010,90.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','RHO',1990,100.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','RHO',2000,100.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','RHO',2010,100.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','SRE',1990,100.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','SRE',2000,100.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','SRE',2010,100.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXD',1990,1044.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXD',2000,1044.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXD',2010,1044.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXE',1990,2000.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXE',2000,1750.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXE',2010,1500.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXG',1990,1044.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXG',2000,1044.0,'',''); +INSERT INTO "cost_invest" VALUES('utopia','TXG',2010,1044.0,'',''); CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, - MMAnalysis TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_variable VALUES('utopia',1990,'IMPDSL1',1990,10.0,'','','OIL_COST'); -INSERT INTO cost_variable VALUES('utopia',2000,'IMPDSL1',1990,10.0,'','','OIL_COST'); -INSERT INTO cost_variable VALUES('utopia',2010,'IMPDSL1',1990,10.0,'','','OIL_COST'); -INSERT INTO cost_variable VALUES('utopia',1990,'IMPGSL1',1990,15.0,'','','OIL_COST'); -INSERT INTO cost_variable VALUES('utopia',2000,'IMPGSL1',1990,15.0,'','','OIL_COST'); -INSERT INTO cost_variable VALUES('utopia',2010,'IMPGSL1',1990,15.0,'','','OIL_COST'); -INSERT INTO cost_variable VALUES('utopia',1990,'IMPHCO1',1990,2.0,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2000,'IMPHCO1',1990,2.0,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2010,'IMPHCO1',1990,2.0,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',1990,'IMPOIL1',1990,8.0,'','','OIL_COST'); -INSERT INTO cost_variable VALUES('utopia',2000,'IMPOIL1',1990,8.0,'','','OIL_COST'); -INSERT INTO cost_variable VALUES('utopia',2010,'IMPOIL1',1990,8.0,'','','OIL_COST'); -INSERT INTO cost_variable VALUES('utopia',1990,'IMPURN1',1990,2.0,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2000,'IMPURN1',1990,2.0,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2010,'IMPURN1',1990,2.0,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',1990,'E01',1960,0.2999999999999999889,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',1990,'E01',1970,0.2999999999999999889,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',1990,'E01',1980,0.2999999999999999889,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',1990,'E01',1990,0.2999999999999999889,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2000,'E01',1970,0.2999999999999999889,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2000,'E01',1980,0.2999999999999999889,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2000,'E01',1990,0.2999999999999999889,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2000,'E01',2000,0.2999999999999999889,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2010,'E01',1980,0.2999999999999999889,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2010,'E01',1990,0.2999999999999999889,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2010,'E01',2000,0.2999999999999999889,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2010,'E01',2010,0.2999999999999999889,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',1990,'E21',1990,1.5,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2000,'E21',1990,1.5,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2010,'E21',1990,1.5,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2000,'E21',2000,1.5,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2010,'E21',2000,1.5,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2010,'E21',2010,1.5,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',1990,'E70',1960,0.4000000000000000222,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',1990,'E70',1970,0.4000000000000000222,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',1990,'E70',1980,0.4000000000000000222,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',1990,'E70',1990,0.4000000000000000222,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2000,'E70',1970,0.4000000000000000222,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2000,'E70',1980,0.4000000000000000222,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2000,'E70',1990,0.4000000000000000222,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2000,'E70',2000,0.4000000000000000222,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2010,'E70',1980,0.4000000000000000222,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2010,'E70',1990,0.4000000000000000222,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2010,'E70',2000,0.4000000000000000222,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2010,'E70',2010,0.4000000000000000222,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',1990,'SRE',1990,10.0,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2000,'SRE',1990,10.0,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2000,'SRE',2000,10.0,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2010,'SRE',1990,10.0,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2010,'SRE',2000,10.0,'','',NULL); -INSERT INTO cost_variable VALUES('utopia',2010,'SRE',2010,10.0,'','',NULL); -CREATE TABLE Demand +INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPDSL1',1990,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPDSL1',1990,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPDSL1',1990,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPGSL1',1990,15.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPGSL1',1990,15.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPGSL1',1990,15.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPHCO1',1990,2.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPHCO1',1990,2.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPHCO1',1990,2.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPOIL1',1990,8.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPOIL1',1990,8.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPOIL1',1990,8.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPURN1',1990,2.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPURN1',1990,2.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPURN1',1990,2.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1960,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1970,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1980,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1990,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',1970,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',1980,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',1990,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',2000,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',1980,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',1990,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',2000,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',2010,0.3,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E21',1990,1.5,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E21',1990,1.5,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E21',1990,1.5,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E21',2000,1.5,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E21',2000,1.5,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E21',2010,1.5,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1960,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1970,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1980,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1990,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',1970,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',1980,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',1990,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',2000,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',1980,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',1990,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',2000,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',2010,0.4,'',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'SRE',1990,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'SRE',1990,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'SRE',2000,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'SRE',1990,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'SRE',2000,10.0,'',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'SRE',2010,10.0,'',''); +CREATE TABLE demand ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), commodity TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), demand REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO Demand VALUES('utopia',1990,'RH',25.19999999999999929,'',''); -INSERT INTO Demand VALUES('utopia',2000,'RH',37.79999999999999715,'',''); -INSERT INTO Demand VALUES('utopia',2010,'RH',56.69999999999999574,'',''); -INSERT INTO Demand VALUES('utopia',1990,'RL',5.599999999999999645,'',''); -INSERT INTO Demand VALUES('utopia',2000,'RL',8.400000000000000355,'',''); -INSERT INTO Demand VALUES('utopia',2010,'RL',12.59999999999999965,'',''); -INSERT INTO Demand VALUES('utopia',1990,'TX',5.200000000000000177,'',''); -INSERT INTO Demand VALUES('utopia',2000,'TX',7.799999999999999823,'',''); -INSERT INTO Demand VALUES('utopia',2010,'TX',11.68999999999999951,'',''); -CREATE TABLE DemandSpecificDistribution +INSERT INTO "demand" VALUES('utopia',1990,'RH',25.2,'',''); +INSERT INTO "demand" VALUES('utopia',2000,'RH',37.8,'',''); +INSERT INTO "demand" VALUES('utopia',2010,'RH',5.66999999999999957e+01,'',''); +INSERT INTO "demand" VALUES('utopia',1990,'RL',5.6,'',''); +INSERT INTO "demand" VALUES('utopia',2000,'RL',8.4,'',''); +INSERT INTO "demand" VALUES('utopia',2010,'RL',12.6,'',''); +INSERT INTO "demand" VALUES('utopia',1990,'TX',5.2,'',''); +INSERT INTO "demand" VALUES('utopia',2000,'TX',7.8,'',''); +INSERT INTO "demand" VALUES('utopia',2010,'TX',11.69,'',''); +CREATE TABLE demand_specific_distribution ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), demand_name TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), dsd REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RH',0.05999999999999999778,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','day','RH',0.5466999999999999638,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RH',0.2732999999999999319,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RL',0.1499999999999999945,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','night','RL',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','day','RL',0.1499999999999999945,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'summer','night','RL',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','day','RL',0.5,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'winter','night','RL',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',1990,'inter','day','RH',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RH',0.05999999999999999778,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','day','RH',0.5466999999999999638,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RH',0.2732999999999999319,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RL',0.1499999999999999945,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','night','RL',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','day','RL',0.1499999999999999945,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'summer','night','RL',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','day','RL',0.5,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'winter','night','RL',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2000,'inter','day','RH',0.1199999999999999956,NULL); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RH',0.05999999999999999778,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RH',0.5466999999999999638,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RH',0.2732999999999999319,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RL',0.1499999999999999945,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','night','RL',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','day','RL',0.1499999999999999945,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'summer','night','RL',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','day','RL',0.5,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'winter','night','RL',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('utopia',2010,'inter','day','RH',0.1199999999999999956,NULL); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','night','RH',0.06,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','day','RH',0.5467,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','night','RH',2.73299999999999931e-01,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'summer','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'summer','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','day','RL',0.5,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','night','RL',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','day','RH',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','night','RH',0.06,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','day','RH',0.5467,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','night','RH',2.73299999999999931e-01,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'summer','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'summer','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','day','RL',0.5,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','night','RL',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','day','RH',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','night','RH',0.06,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','day','RH',0.5467,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','night','RH',2.73299999999999931e-01,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'summer','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'summer','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','day','RL',0.5,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','night','RL',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','day','RH',0.12,NULL); CREATE TABLE efficiency ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, - MMAnalysis TEXT, PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO efficiency VALUES('utopia','ethos','IMPDSL1',1990,'DSL',1.0,'',NULL); -INSERT INTO efficiency VALUES('utopia','ethos','IMPGSL1',1990,'GSL',1.0,'',NULL); -INSERT INTO efficiency VALUES('utopia','ethos','IMPHCO1',1990,'HCO',1.0,'',NULL); -INSERT INTO efficiency VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,'',NULL); -INSERT INTO efficiency VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,'',NULL); -INSERT INTO efficiency VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,'',NULL); -INSERT INTO efficiency VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,'',NULL); -INSERT INTO efficiency VALUES('utopia','HCO','E01',1960,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO efficiency VALUES('utopia','HCO','E01',1970,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO efficiency VALUES('utopia','HCO','E01',1980,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO efficiency VALUES('utopia','HCO','E01',1990,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO efficiency VALUES('utopia','HCO','E01',2000,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO efficiency VALUES('utopia','HCO','E01',2010,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO efficiency VALUES('utopia','FEQ','E21',1990,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO efficiency VALUES('utopia','FEQ','E21',2000,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO efficiency VALUES('utopia','FEQ','E21',2010,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO efficiency VALUES('utopia','URN','E21',1990,'ELC',0.4000000000000000222,'# 1/2.5',NULL); -INSERT INTO efficiency VALUES('utopia','URN','E21',2000,'ELC',0.4000000000000000222,'# 1/2.5',NULL); -INSERT INTO efficiency VALUES('utopia','URN','E21',2010,'ELC',0.4000000000000000222,'# 1/2.5',NULL); -INSERT INTO efficiency VALUES('utopia','HYD','E31',1980,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO efficiency VALUES('utopia','HYD','E31',1990,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO efficiency VALUES('utopia','HYD','E31',2000,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO efficiency VALUES('utopia','HYD','E31',2010,'ELC',0.3200000000000000066,'# 1/3.125',NULL); -INSERT INTO efficiency VALUES('utopia','DSL','E70',1960,'ELC',0.2939999999999999836,'# 1/3.4',NULL); -INSERT INTO efficiency VALUES('utopia','DSL','E70',1970,'ELC',0.2939999999999999836,'# 1/3.4',NULL); -INSERT INTO efficiency VALUES('utopia','DSL','E70',1980,'ELC',0.2939999999999999836,'# 1/3.4',NULL); -INSERT INTO efficiency VALUES('utopia','DSL','E70',1990,'ELC',0.2939999999999999836,'# 1/3.4',NULL); -INSERT INTO efficiency VALUES('utopia','DSL','E70',2000,'ELC',0.2939999999999999836,'# 1/3.4',NULL); -INSERT INTO efficiency VALUES('utopia','DSL','E70',2010,'ELC',0.2939999999999999836,'# 1/3.4',NULL); -INSERT INTO efficiency VALUES('utopia','ELC','E51',1980,'ELC',0.7199999999999999734,'# 1/1.3889',NULL); -INSERT INTO efficiency VALUES('utopia','ELC','E51',1990,'ELC',0.7199999999999999734,'# 1/1.3889',NULL); -INSERT INTO efficiency VALUES('utopia','ELC','E51',2000,'ELC',0.7199999999999999734,'# 1/1.3889',NULL); -INSERT INTO efficiency VALUES('utopia','ELC','E51',2010,'ELC',0.7199999999999999734,'# 1/1.3889',NULL); -INSERT INTO efficiency VALUES('utopia','ELC','RHE',1990,'RH',1.0,'# direct translation from DMD_EFF',NULL); -INSERT INTO efficiency VALUES('utopia','ELC','RHE',2000,'RH',1.0,'# direct translation from DMD_EFF',NULL); -INSERT INTO efficiency VALUES('utopia','ELC','RHE',2010,'RH',1.0,'# direct translation from DMD_EFF',NULL); -INSERT INTO efficiency VALUES('utopia','DSL','RHO',1970,'RH',0.6999999999999999556,'# direct translation from DMD_EFF',NULL); -INSERT INTO efficiency VALUES('utopia','DSL','RHO',1980,'RH',0.6999999999999999556,'# direct translation from DMD_EFF',NULL); -INSERT INTO efficiency VALUES('utopia','DSL','RHO',1990,'RH',0.6999999999999999556,'# direct translation from DMD_EFF',NULL); -INSERT INTO efficiency VALUES('utopia','DSL','RHO',2000,'RH',0.6999999999999999556,'# direct translation from DMD_EFF',NULL); -INSERT INTO efficiency VALUES('utopia','DSL','RHO',2010,'RH',0.6999999999999999556,'# direct translation from DMD_EFF','Res_heating_2010_eff'); -INSERT INTO efficiency VALUES('utopia','ELC','RL1',1980,'RL',1.0,'# direct translation from DMD_EFF','Res_lighting_eff'); -INSERT INTO efficiency VALUES('utopia','ELC','RL1',1990,'RL',1.0,'# direct translation from DMD_EFF','Res_lighting_eff'); -INSERT INTO efficiency VALUES('utopia','ELC','RL1',2000,'RL',1.0,'# direct translation from DMD_EFF','Res_lighting_eff'); -INSERT INTO efficiency VALUES('utopia','ELC','RL1',2010,'RL',1.0,'# direct translation from DMD_EFF','Res_lighting_eff'); -INSERT INTO efficiency VALUES('utopia','OIL','SRE',1990,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); -INSERT INTO efficiency VALUES('utopia','OIL','SRE',2000,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); -INSERT INTO efficiency VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); -INSERT INTO efficiency VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); -INSERT INTO efficiency VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); -INSERT INTO efficiency VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT',NULL); -INSERT INTO efficiency VALUES('utopia','DSL','TXD',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); -INSERT INTO efficiency VALUES('utopia','DSL','TXD',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); -INSERT INTO efficiency VALUES('utopia','DSL','TXD',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); -INSERT INTO efficiency VALUES('utopia','DSL','TXD',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); -INSERT INTO efficiency VALUES('utopia','DSL','TXD',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); -INSERT INTO efficiency VALUES('utopia','ELC','TXE',1990,'TX',0.8269999999999999574,'# direct translation from DMD_EFF',NULL); -INSERT INTO efficiency VALUES('utopia','ELC','TXE',2000,'TX',0.8269999999999999574,'# direct translation from DMD_EFF',NULL); -INSERT INTO efficiency VALUES('utopia','ELC','TXE',2010,'TX',0.8269999999999999574,'# direct translation from DMD_EFF',NULL); -INSERT INTO efficiency VALUES('utopia','GSL','TXG',1970,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); -INSERT INTO efficiency VALUES('utopia','GSL','TXG',1980,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); -INSERT INTO efficiency VALUES('utopia','GSL','TXG',1990,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); -INSERT INTO efficiency VALUES('utopia','GSL','TXG',2000,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); -INSERT INTO efficiency VALUES('utopia','GSL','TXG',2010,'TX',0.2310000000000000108,'# direct translation from DMD_EFF',NULL); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPDSL1',1990,'DSL',1.0,''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPGSL1',1990,'GSL',1.0,''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPHCO1',1990,'HCO',1.0,''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,''); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1960,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1970,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1980,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1990,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',2000,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',2010,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','FEQ','E21',1990,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','FEQ','E21',2000,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','FEQ','E21',2010,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','URN','E21',1990,'ELC',0.4,'# 1/2.5'); +INSERT INTO "efficiency" VALUES('utopia','URN','E21',2000,'ELC',0.4,'# 1/2.5'); +INSERT INTO "efficiency" VALUES('utopia','URN','E21',2010,'ELC',0.4,'# 1/2.5'); +INSERT INTO "efficiency" VALUES('utopia','HYD','E31',1980,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HYD','E31',1990,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HYD','E31',2000,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HYD','E31',2010,'ELC',0.32,'# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1960,'ELC',0.294,'# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1970,'ELC',0.294,'# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1980,'ELC',0.294,'# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1990,'ELC',0.294,'# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',2000,'ELC',0.294,'# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',2010,'ELC',0.294,'# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','ELC','E51',1980,'ELC',0.72,'# 1/1.3889'); +INSERT INTO "efficiency" VALUES('utopia','ELC','E51',1990,'ELC',0.72,'# 1/1.3889'); +INSERT INTO "efficiency" VALUES('utopia','ELC','E51',2000,'ELC',0.72,'# 1/1.3889'); +INSERT INTO "efficiency" VALUES('utopia','ELC','E51',2010,'ELC',0.72,'# 1/1.3889'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RHE',1990,'RH',1.0,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RHE',2000,'RH',1.0,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RHE',2010,'RH',1.0,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',1970,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',1980,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',1990,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',2000,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',2010,'RH',0.7,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',1980,'RL',1.0,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',1990,'RL',1.0,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',2000,'RL',1.0,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',2010,'RL',1.0,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',1990,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2000,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',1970,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',1980,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',1990,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',2000,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',2010,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','TXE',1990,'TX',0.827,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','TXE',2000,'TX',0.827,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','TXE',2010,'TX',0.827,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',1970,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',1980,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',1990,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',2000,'TX',0.231,'# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',2010,'TX',0.231,'# direct translation from DMD_EFF'); CREATE TABLE efficiency_variable ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), @@ -688,347 +617,332 @@ CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), activity REAL, units TEXT, notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.07499999999999999723,'',''); -INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.07499999999999999723,'',''); -INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',0.0889999999999999819,'',''); -INSERT INTO emission_activity VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.07499999999999999723,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',1970,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',1980,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',1990,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',2000,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','DSL','TXD',2010,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',1970,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',1980,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',1990,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',2000,'TX',1.0,'',''); -INSERT INTO emission_activity VALUES('utopia','nox','GSL','TXG',2010,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.075,'',''); +INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.075,'',''); +INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',8.89999999999999819e-02,'',''); +INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.075,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1970,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1980,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1990,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',2000,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',2010,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1970,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1980,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1990,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',2000,'TX',1.0,'',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',2010,'TX',1.0,'',''); CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) ); CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE end_of_life_output +( + region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, tech, vintage, output_comm) ); CREATE TABLE existing_capacity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, units TEXT, notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO existing_capacity VALUES('utopia','E01',1960,0.1749999999999999889,'',''); -INSERT INTO existing_capacity VALUES('utopia','E01',1970,0.1749999999999999889,'',''); -INSERT INTO existing_capacity VALUES('utopia','E01',1980,0.1499999999999999945,'',''); -INSERT INTO existing_capacity VALUES('utopia','E31',1980,0.1000000000000000055,'',''); -INSERT INTO existing_capacity VALUES('utopia','E51',1980,0.5,'',''); -INSERT INTO existing_capacity VALUES('utopia','E70',1960,0.05000000000000000277,'',''); -INSERT INTO existing_capacity VALUES('utopia','E70',1970,0.05000000000000000277,'',''); -INSERT INTO existing_capacity VALUES('utopia','E70',1980,0.2000000000000000111,'',''); -INSERT INTO existing_capacity VALUES('utopia','RHO',1970,12.5,'',''); -INSERT INTO existing_capacity VALUES('utopia','RHO',1980,12.5,'',''); -INSERT INTO existing_capacity VALUES('utopia','RL1',1980,5.599999999999999645,'',''); -INSERT INTO existing_capacity VALUES('utopia','TXD',1970,0.4000000000000000222,'',''); -INSERT INTO existing_capacity VALUES('utopia','TXD',1980,0.2000000000000000111,'',''); -INSERT INTO existing_capacity VALUES('utopia','TXG',1970,3.100000000000000088,'',''); -INSERT INTO existing_capacity VALUES('utopia','TXG',1980,1.5,'',''); -CREATE TABLE TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE loan_lifetime_process +INSERT INTO "existing_capacity" VALUES('utopia','E01',1960,0.175,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','E01',1970,0.175,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','E01',1980,0.15,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','E31',1980,0.1,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','E51',1980,0.5,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','E70',1960,0.05,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','E70',1970,0.05,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','E70',1980,0.2,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','RHO',1970,12.5,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','RHO',1980,12.5,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','RL1',1980,5.6,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','TXD',1970,0.4,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','TXD',1980,0.2,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','TXG',1970,3.1,'',''); +INSERT INTO "existing_capacity" VALUES('utopia','TXG',1980,1.5,'',''); +CREATE TABLE lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE loan_rate +INSERT INTO "lifetime_process" VALUES('utopia','RL1',1980,20.0,'#forexistingcap'); +INSERT INTO "lifetime_process" VALUES('utopia','TXD',1970,30.0,'#forexistingcap'); +INSERT INTO "lifetime_process" VALUES('utopia','TXD',1980,30.0,'#forexistingcap'); +INSERT INTO "lifetime_process" VALUES('utopia','TXG',1970,30.0,'#forexistingcap'); +INSERT INTO "lifetime_process" VALUES('utopia','TXG',1980,30.0,'#forexistingcap'); +CREATE TABLE lifetime_survival_curve ( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - rate REAL, + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES technology (tech), + vintage INTEGER NOT NULL + REFERENCES time_period (period), + fraction REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_process -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO lifetime_process VALUES('utopia','RL1',1980,20.0,'#forexistingcap'); -INSERT INTO lifetime_process VALUES('utopia','TXD',1970,30.0,'#forexistingcap'); -INSERT INTO lifetime_process VALUES('utopia','TXD',1980,30.0,'#forexistingcap'); -INSERT INTO lifetime_process VALUES('utopia','TXG',1970,30.0,'#forexistingcap'); -INSERT INTO lifetime_process VALUES('utopia','TXG',1980,30.0,'#forexistingcap'); CREATE TABLE lifetime_tech ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO lifetime_tech VALUES('utopia','E01',40.0,''); -INSERT INTO lifetime_tech VALUES('utopia','E21',40.0,''); -INSERT INTO lifetime_tech VALUES('utopia','E31',100.0,''); -INSERT INTO lifetime_tech VALUES('utopia','E51',100.0,''); -INSERT INTO lifetime_tech VALUES('utopia','E70',40.0,''); -INSERT INTO lifetime_tech VALUES('utopia','RHE',30.0,''); -INSERT INTO lifetime_tech VALUES('utopia','RHO',30.0,''); -INSERT INTO lifetime_tech VALUES('utopia','RL1',10.0,''); -INSERT INTO lifetime_tech VALUES('utopia','SRE',50.0,''); -INSERT INTO lifetime_tech VALUES('utopia','TXD',15.0,''); -INSERT INTO lifetime_tech VALUES('utopia','TXE',15.0,''); -INSERT INTO lifetime_tech VALUES('utopia','TXG',15.0,''); -INSERT INTO lifetime_tech VALUES('utopia','IMPDSL1',1000.0,''); -INSERT INTO lifetime_tech VALUES('utopia','IMPGSL1',1000.0,''); -INSERT INTO lifetime_tech VALUES('utopia','IMPHCO1',1000.0,''); -INSERT INTO lifetime_tech VALUES('utopia','IMPOIL1',1000.0,''); -INSERT INTO lifetime_tech VALUES('utopia','IMPURN1',1000.0,''); -INSERT INTO lifetime_tech VALUES('utopia','IMPHYD',1000.0,''); -INSERT INTO lifetime_tech VALUES('utopia','IMPFEQ',1000.0,''); -CREATE TABLE Operator +INSERT INTO "lifetime_tech" VALUES('utopia','E01',40.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','E21',40.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','E31',100.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','E51',100.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','E70',40.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','RHE',30.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','RHO',30.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','RL1',10.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','SRE',50.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','TXD',15.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','TXE',15.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','TXG',15.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPDSL1',1000.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPGSL1',1000.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPHCO1',1000.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPOIL1',1000.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPURN1',1000.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPHYD',1000.0,''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPFEQ',1000.0,''); +CREATE TABLE limit_activity ( - operator TEXT PRIMARY KEY, - notes TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO Operator VALUES('e','equal to'); -INSERT INTO Operator VALUES('le','less than or equal to'); -INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE limit_growth_capacity +CREATE TABLE limit_activity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_annual_capacity_factor +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE limit_capacity +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +INSERT INTO "limit_capacity" VALUES('utopia',1990,'E31','ge',0.13,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',2000,'E31','ge',0.13,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',2010,'E31','ge',0.13,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',1990,'SRE','ge',0.1,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',1990,'E31','le',0.13,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',2000,'E31','le',0.17,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',2010,'E31','le',2.1000000000000002e-01,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',1990,'RHE','le',0.0,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',1990,'TXD','le',0.6,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',2000,'TXD','le',1.76,'',''); +INSERT INTO "limit_capacity" VALUES('utopia',2010,'TXD','le',4.76,'',''); +CREATE TABLE limit_capacity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_capacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity +CREATE TABLE limit_emission +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitStorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -CREATE TABLE limit_activity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -INSERT INTO limit_capacity VALUES('utopia',1990,'E31','ge',0.1300000000000000044,'',''); -INSERT INTO limit_capacity VALUES('utopia',2000,'E31','ge',0.1300000000000000044,'',''); -INSERT INTO limit_capacity VALUES('utopia',2010,'E31','ge',0.1300000000000000044,'',''); -INSERT INTO limit_capacity VALUES('utopia',1990,'SRE','ge',0.1000000000000000055,'',''); -INSERT INTO limit_capacity VALUES('utopia',1990,'E31','le',0.1300000000000000044,'',''); -INSERT INTO limit_capacity VALUES('utopia',2000,'E31','le',0.1700000000000000122,'',''); -INSERT INTO limit_capacity VALUES('utopia',2010,'E31','le',0.21000000000000002,'',''); -INSERT INTO limit_capacity VALUES('utopia',1990,'RHE','le',0.0,'',''); -INSERT INTO limit_capacity VALUES('utopia',1990,'TXD','le',0.5999999999999999778,'',''); -INSERT INTO limit_capacity VALUES('utopia',2000,'TXD','le',1.760000000000000008,'',''); -INSERT INTO limit_capacity VALUES('utopia',2010,'TXD','le',4.759999999999999787,'',''); -CREATE TABLE limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), new_cap REAL, units TEXT, notes TEXT, @@ -1038,11 +952,11 @@ CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), share REAL, notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) @@ -1052,7 +966,7 @@ CREATE TABLE limit_resource region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), cum_act REAL, units TEXT, notes TEXT, @@ -1061,30 +975,49 @@ CREATE TABLE limit_resource CREATE TABLE limit_seasonal_capacity_factor ( region TEXT - REFERENCES Region (region), + REFERENCES region (region), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), factor REAL, notes TEXT, PRIMARY KEY(region, period, season, tech, operator) ); +CREATE TABLE limit_storage_level_fraction +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) +); CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -1093,13 +1026,13 @@ CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -1108,192 +1041,308 @@ CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -INSERT INTO limit_tech_output_split VALUES('utopia',1990,'SRE','DSL','ge',0.6999999999999999556,''); -INSERT INTO limit_tech_output_split VALUES('utopia',2000,'SRE','DSL','ge',0.6999999999999999556,''); -INSERT INTO limit_tech_output_split VALUES('utopia',2010,'SRE','DSL','ge',0.6999999999999999556,''); -INSERT INTO limit_tech_output_split VALUES('utopia',1990,'SRE','GSL','ge',0.2999999999999999889,''); -INSERT INTO limit_tech_output_split VALUES('utopia',2000,'SRE','GSL','ge',0.2999999999999999889,''); -INSERT INTO limit_tech_output_split VALUES('utopia',2010,'SRE','GSL','ge',0.2999999999999999889,''); +INSERT INTO "limit_tech_output_split" VALUES('utopia',1990,'SRE','DSL','ge',0.7,''); +INSERT INTO "limit_tech_output_split" VALUES('utopia',2000,'SRE','DSL','ge',0.7,''); +INSERT INTO "limit_tech_output_split" VALUES('utopia',2010,'SRE','DSL','ge',0.7,''); +INSERT INTO "limit_tech_output_split" VALUES('utopia',1990,'SRE','GSL','ge',0.3,''); +INSERT INTO "limit_tech_output_split" VALUES('utopia',2000,'SRE','GSL','ge',0.3,''); +INSERT INTO "limit_tech_output_split" VALUES('utopia',2010,'SRE','GSL','ge',0.3,''); CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE LinkedTech +CREATE TABLE linked_tech ( primary_region TEXT, primary_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), driven_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); -CREATE TABLE OutputCurtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE OutputNetCapacity +CREATE TABLE loan_lifetime_process ( - scenario TEXT, region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + REFERENCES time_period (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE loan_rate +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE metadata +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO "metadata" VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); +INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); +INSERT INTO "metadata" VALUES('DB_MINOR',0,''); +CREATE TABLE metadata_real +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,''); +CREATE TABLE myopic_efficiency +( + base_year integer, + region text, + input_comm text, + tech text, + vintage integer, + output_comm text, + efficiency real, + lifetime integer, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (region, input_comm, tech, vintage, output_comm) +); +CREATE TABLE operator +( + operator TEXT PRIMARY KEY, + notes TEXT ); -CREATE TABLE OutputBuiltCapacity +INSERT INTO "operator" VALUES('e','equal to'); +INSERT INTO "operator" VALUES('le','less than or equal to'); +INSERT INTO "operator" VALUES('ge','greater than or equal to'); +CREATE TABLE output_built_capacity ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, tech, vintage) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE output_cost ( scenario TEXT, region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + sector TEXT REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) ); -CREATE TABLE OutputFlowIn +CREATE TABLE output_curtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES time_period (period), + tod TEXT + REFERENCES time_of_day (tod), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_dual_variable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE output_emission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE output_flow_in ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputFlowOut +CREATE TABLE output_flow_out ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputStorageLevel +CREATE TABLE output_flow_out_summary +( + scenario TEXT NOT NULL, + region TEXT NOT NULL, + sector TEXT, + period INTEGER, + input_comm TEXT NOT NULL, + tech TEXT NOT NULL, + vintage INTEGER, + output_comm TEXT NOT NULL, + flow REAL NOT NULL, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_net_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_objective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE output_retired_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); @@ -1301,7 +1350,7 @@ CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY - REFERENCES Region (region), + REFERENCES region (region), margin REAL, notes TEXT ); @@ -1309,7 +1358,7 @@ CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -1318,64 +1367,63 @@ CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE Region +CREATE TABLE region ( region TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO Region VALUES('utopia',NULL); +INSERT INTO "region" VALUES('utopia',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE TimeSegmentFraction +CREATE TABLE rps_requirement ( - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) -); -INSERT INTO TimeSegmentFraction VALUES(1990,'inter','day',0.166699999999999987,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(1990,'inter','night',0.08329999999999999905,'# I-N'); -INSERT INTO TimeSegmentFraction VALUES(1990,'summer','day',0.166699999999999987,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(1990,'summer','night',0.08329999999999999905,'# S-N'); -INSERT INTO TimeSegmentFraction VALUES(1990,'winter','day',0.3332999999999999852,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(1990,'winter','night',0.166699999999999987,'# W-N'); -INSERT INTO TimeSegmentFraction VALUES(2000,'inter','day',0.166699999999999987,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2000,'inter','night',0.08329999999999999905,'# I-N'); -INSERT INTO TimeSegmentFraction VALUES(2000,'summer','day',0.166699999999999987,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2000,'summer','night',0.08329999999999999905,'# S-N'); -INSERT INTO TimeSegmentFraction VALUES(2000,'winter','day',0.3332999999999999852,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2000,'winter','night',0.166699999999999987,'# W-N'); -INSERT INTO TimeSegmentFraction VALUES(2010,'inter','day',0.166699999999999987,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'inter','night',0.08329999999999999905,'# I-N'); -INSERT INTO TimeSegmentFraction VALUES(2010,'summer','day',0.166699999999999987,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'summer','night',0.08329999999999999905,'# S-N'); -INSERT INTO TimeSegmentFraction VALUES(2010,'winter','day',0.3332999999999999852,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'winter','night',0.166699999999999987,'# W-N'); + region TEXT NOT NULL + REFERENCES region (region), + period INTEGER NOT NULL + REFERENCES time_period (period), + tech_group TEXT NOT NULL + REFERENCES tech_group (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE season_label +( + season TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "season_label" VALUES('inter',NULL); +INSERT INTO "season_label" VALUES('summer',NULL); +INSERT INTO "season_label" VALUES('winter',NULL); +CREATE TABLE sector_label +( + sector TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "sector_label" VALUES('supply',NULL); +INSERT INTO "sector_label" VALUES('electric',NULL); +INSERT INTO "sector_label" VALUES('transport',NULL); +INSERT INTO "sector_label" VALUES('commercial',NULL); +INSERT INTO "sector_label" VALUES('residential',NULL); +INSERT INTO "sector_label" VALUES('industrial',NULL); CREATE TABLE storage_duration ( region TEXT, @@ -1384,180 +1432,178 @@ CREATE TABLE storage_duration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE lifetime_survival_curve +CREATE TABLE tech_group ( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) + group_name TEXT + PRIMARY KEY, + notes TEXT ); -CREATE TABLE TechnologyType +CREATE TABLE tech_group_member +( + group_name TEXT + REFERENCES tech_group (group_name), + tech TEXT + REFERENCES technology (tech), + PRIMARY KEY (group_name, tech) +); +CREATE TABLE technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES technology_type (label) +); +INSERT INTO "technology" VALUES('IMPDSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported diesel'); +INSERT INTO "technology" VALUES('IMPGSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported gasoline'); +INSERT INTO "technology" VALUES('IMPHCO1','p','supply','coal','',1,0,0,0,0,0,0,0,' imported coal'); +INSERT INTO "technology" VALUES('IMPOIL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported crude oil'); +INSERT INTO "technology" VALUES('IMPURN1','p','supply','nuclear','',1,0,0,0,0,0,0,0,' imported uranium'); +INSERT INTO "technology" VALUES('IMPFEQ','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported fossil equivalent'); +INSERT INTO "technology" VALUES('IMPHYD','p','supply','','',1,0,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); +INSERT INTO "technology" VALUES('E01','pb','electric','coal','',0,0,0,1,1,0,0,0,' coal power plant'); +INSERT INTO "technology" VALUES('E21','pb','electric','nuclear','',0,0,0,1,1,0,0,0,' nuclear power plant'); +INSERT INTO "technology" VALUES('E31','pb','electric','hydro','',0,0,0,1,1,0,0,0,' hydro power'); +INSERT INTO "technology" VALUES('E51','ps','electric','electric','',0,0,0,1,0,0,0,0,' electric storage'); +INSERT INTO "technology" VALUES('E70','p','electric','petroleum','',0,0,0,1,1,0,0,0,' diesel power plant'); +INSERT INTO "technology" VALUES('RHE','p','residential','electric','',0,0,0,1,1,0,0,0,' electric residential heating'); +INSERT INTO "technology" VALUES('RHO','p','residential','petroleum','',0,0,0,1,1,0,0,0,' diesel residential heating'); +INSERT INTO "technology" VALUES('RL1','p','residential','electric','',0,0,0,1,1,0,0,0,' residential lighting'); +INSERT INTO "technology" VALUES('SRE','p','supply','petroleum','',0,0,0,1,1,0,0,0,' crude oil processor'); +INSERT INTO "technology" VALUES('TXD','p','transport','petroleum','',0,0,0,1,1,0,0,0,' diesel powered vehicles'); +INSERT INTO "technology" VALUES('TXE','p','transport','electric','',0,0,0,1,1,0,0,0,' electric powered vehicles'); +INSERT INTO "technology" VALUES('TXG','p','transport','petroleum','',0,0,0,1,1,0,0,0,' gasoline powered vehicles'); +CREATE TABLE technology_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('p','production technology'); -INSERT INTO TechnologyType VALUES('pb','baseload production technology'); -INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE TimeOfDay +INSERT INTO "technology_type" VALUES('p','production technology'); +INSERT INTO "technology_type" VALUES('pb','baseload production technology'); +INSERT INTO "technology_type" VALUES('ps','storage production technology'); +CREATE TABLE time_of_day ( sequence INTEGER UNIQUE, tod TEXT PRIMARY KEY ); -INSERT INTO TimeOfDay VALUES(1,'day'); -INSERT INTO TimeOfDay VALUES(2,'night'); -CREATE TABLE TimePeriod +INSERT INTO "time_of_day" VALUES(1,'day'); +INSERT INTO "time_of_day" VALUES(2,'night'); +CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES TimePeriodType (label) + REFERENCES time_period_type (label) +); +INSERT INTO "time_period" VALUES(1,1960,'e'); +INSERT INTO "time_period" VALUES(2,1970,'e'); +INSERT INTO "time_period" VALUES(3,1980,'e'); +INSERT INTO "time_period" VALUES(4,1990,'f'); +INSERT INTO "time_period" VALUES(5,2000,'f'); +INSERT INTO "time_period" VALUES(6,2010,'f'); +INSERT INTO "time_period" VALUES(7,2020,'f'); +CREATE TABLE time_period_type +( + label TEXT + PRIMARY KEY, + description TEXT ); -INSERT INTO TimePeriod VALUES(1,1960,'e'); -INSERT INTO TimePeriod VALUES(2,1970,'e'); -INSERT INTO TimePeriod VALUES(3,1980,'e'); -INSERT INTO TimePeriod VALUES(4,1990,'f'); -INSERT INTO TimePeriod VALUES(5,2000,'f'); -INSERT INTO TimePeriod VALUES(6,2010,'f'); -INSERT INTO TimePeriod VALUES(7,2020,'f'); -CREATE TABLE TimeSeason +INSERT INTO "time_period_type" VALUES('e','existing vintages'); +INSERT INTO "time_period_type" VALUES('f','future'); +CREATE TABLE time_season +( + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + season TEXT REFERENCES season_label(season), + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +INSERT INTO "time_season" VALUES(1990,2,'summer',NULL); +INSERT INTO "time_season" VALUES(1990,3,'winter',NULL); +INSERT INTO "time_season" VALUES(1990,1,'inter',NULL); +INSERT INTO "time_season" VALUES(2000,2,'summer',NULL); +INSERT INTO "time_season" VALUES(2000,3,'winter',NULL); +INSERT INTO "time_season" VALUES(2000,1,'inter',NULL); +INSERT INTO "time_season" VALUES(2010,2,'summer',NULL); +INSERT INTO "time_season" VALUES(2010,3,'winter',NULL); +INSERT INTO "time_season" VALUES(2010,1,'inter',NULL); +CREATE TABLE time_season_all ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); -INSERT INTO TimeSeason VALUES(1990,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(1990,3,'winter',NULL); -INSERT INTO TimeSeason VALUES(1990,1,'inter',NULL); -INSERT INTO TimeSeason VALUES(2000,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(2000,3,'winter',NULL); -INSERT INTO TimeSeason VALUES(2000,1,'inter',NULL); -INSERT INTO TimeSeason VALUES(2010,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(2010,3,'winter',NULL); -INSERT INTO TimeSeason VALUES(2010,1,'inter',NULL); CREATE TABLE time_season_sequential ( - period INTEGER - REFERENCES TimePeriod (period), + period INTEGER REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES SeasonLabel (season), + season TEXT REFERENCES season_label(season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE TimePeriodType -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO TimePeriodType VALUES('e','existing vintages'); -INSERT INTO TimePeriodType VALUES('f','future'); -CREATE TABLE OutputEmission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE RPSRequirement -( - region TEXT NOT NULL - REFERENCES Region (region), - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech_group TEXT NOT NULL - REFERENCES TechGroup (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE TechGroupMember +CREATE TABLE time_season_to_sequential ( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES Technology (tech), - PRIMARY KEY (group_name, tech) + period INTEGER + REFERENCES time_period (period), + sequence INTEGER, + seas_seq TEXT, + season TEXT + REFERENCES season_label (season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) ); -CREATE TABLE Technology +CREATE TABLE time_segment_fraction ( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) -); -INSERT INTO Technology VALUES('IMPDSL1','p','supply','petroleum','',1,0,0,0,0,0,0,' imported diesel'); -INSERT INTO Technology VALUES('IMPGSL1','p','supply','petroleum','',1,0,0,0,0,0,0,' imported gasoline'); -INSERT INTO Technology VALUES('IMPHCO1','p','supply','coal','',1,0,0,0,0,0,0,' imported coal'); -INSERT INTO Technology VALUES('IMPOIL1','p','supply','petroleum','',1,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO Technology VALUES('IMPURN1','p','supply','nuclear','',1,0,0,0,0,0,0,' imported uranium'); -INSERT INTO Technology VALUES('IMPFEQ','p','supply','petroleum','',1,0,0,0,0,0,0,' imported fossil equivalent'); -INSERT INTO Technology VALUES('IMPHYD','p','supply','','',1,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); -INSERT INTO Technology VALUES('E01','pb','electric','coal','',0,0,0,1,1,0,0,' coal power plant'); -INSERT INTO Technology VALUES('E21','pb','electric','nuclear','',0,0,0,1,1,0,0,' nuclear power plant'); -INSERT INTO Technology VALUES('E31','pb','electric','hydro','',0,0,0,1,1,0,0,' hydro power'); -INSERT INTO Technology VALUES('E51','ps','electric','electric','',0,0,0,1,0,0,0,' electric storage'); -INSERT INTO Technology VALUES('E70','p','electric','petroleum','',0,0,0,1,1,0,0,' diesel power plant'); -INSERT INTO Technology VALUES('RHE','p','residential','electric','',0,0,0,1,1,0,0,' electric residential heating'); -INSERT INTO Technology VALUES('RHO','p','residential','petroleum','',0,0,0,1,1,0,0,' diesel residential heating'); -INSERT INTO Technology VALUES('RL1','p','residential','electric','',0,0,0,1,1,0,0,' residential lighting'); -INSERT INTO Technology VALUES('SRE','p','supply','petroleum','',0,0,0,1,1,0,0,' crude oil processor'); -INSERT INTO Technology VALUES('TXD','p','transport','petroleum','',0,0,0,1,1,0,0,' diesel powered vehicles'); -INSERT INTO Technology VALUES('TXE','p','transport','electric','',0,0,0,1,1,0,0,' electric powered vehicles'); -INSERT INTO Technology VALUES('TXG','p','transport','petroleum','',0,0,0,1,1,0,0,' gasoline powered vehicles'); -CREATE TABLE OutputCost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) -); + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + segment_fraction REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) +); +INSERT INTO "time_segment_fraction" VALUES(1990,'inter','day',0.1667,'# I-D'); +INSERT INTO "time_segment_fraction" VALUES(1990,'inter','night',0.0833,'# I-N'); +INSERT INTO "time_segment_fraction" VALUES(1990,'summer','day',0.1667,'# S-D'); +INSERT INTO "time_segment_fraction" VALUES(1990,'summer','night',0.0833,'# S-N'); +INSERT INTO "time_segment_fraction" VALUES(1990,'winter','day',0.3333,'# W-D'); +INSERT INTO "time_segment_fraction" VALUES(1990,'winter','night',0.1667,'# W-N'); +INSERT INTO "time_segment_fraction" VALUES(2000,'inter','day',0.1667,'# I-D'); +INSERT INTO "time_segment_fraction" VALUES(2000,'inter','night',0.0833,'# I-N'); +INSERT INTO "time_segment_fraction" VALUES(2000,'summer','day',0.1667,'# S-D'); +INSERT INTO "time_segment_fraction" VALUES(2000,'summer','night',0.0833,'# S-N'); +INSERT INTO "time_segment_fraction" VALUES(2000,'winter','day',0.3333,'# W-D'); +INSERT INTO "time_segment_fraction" VALUES(2000,'winter','night',0.1667,'# W-N'); +INSERT INTO "time_segment_fraction" VALUES(2010,'inter','day',0.1667,'# I-D'); +INSERT INTO "time_segment_fraction" VALUES(2010,'inter','night',0.0833,'# I-N'); +INSERT INTO "time_segment_fraction" VALUES(2010,'summer','day',0.1667,'# S-D'); +INSERT INTO "time_segment_fraction" VALUES(2010,'summer','night',0.0833,'# S-N'); +INSERT INTO "time_segment_fraction" VALUES(2010,'winter','day',0.3333,'# W-D'); +INSERT INTO "time_segment_fraction" VALUES(2010,'winter','night',0.1667,'# W-N'); +CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql index 2542862d7..35ed2fcee 100644 --- a/data_files/example_dbs/seasonal_storage.sql +++ b/data_files/example_dbs/seasonal_storage.sql @@ -1,72 +1,11 @@ -PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE MetaData -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES('days_per_period',365,'count of days in each period'); -CREATE TABLE MetaDataReal -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -CREATE TABLE OutputDualVariable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE SeasonLabel -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SeasonLabel VALUES('charge','non-sequential season - charging day'); -INSERT INTO SeasonLabel VALUES('discharge','non-sequential season - discharging day'); -INSERT INTO SeasonLabel VALUES('summer','sequential season - summer day'); -INSERT INTO SeasonLabel VALUES('sept_w1','sequential season - day in first week of September'); -INSERT INTO SeasonLabel VALUES('sept_w2','sequential season - day in second week of September'); -INSERT INTO SeasonLabel VALUES('sept_w3','sequential season - day in third week of September'); -INSERT INTO SeasonLabel VALUES('sept_w4','sequential season - day in fourth week of September'); -INSERT INTO SeasonLabel VALUES('sept_29th','sequential season - 29th of September'); -INSERT INTO SeasonLabel VALUES('sept_30th','sequential season - 30th of September'); -INSERT INTO SeasonLabel VALUES('winter','sequential season - winter day'); -INSERT INTO SeasonLabel VALUES('apr_w1','sequential season - day in first week of September'); -INSERT INTO SeasonLabel VALUES('apr_w2','sequential season - day in second week of September'); -INSERT INTO SeasonLabel VALUES('apr_w3','sequential season - day in third week of September'); -INSERT INTO SeasonLabel VALUES('apr_w4','sequential season - day in fourth week of September'); -INSERT INTO SeasonLabel VALUES('apr_29th','sequential season - 29th of April'); -INSERT INTO SeasonLabel VALUES('apr_30th','sequential season - 30th of April'); -CREATE TABLE SectorLabel -( - sector TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SectorLabel VALUES('electricity',NULL); CREATE TABLE capacity_credit ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, credit REAL, notes TEXT, @@ -77,13 +16,13 @@ CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -94,73 +33,73 @@ CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO capacity_factor_tech VALUES('region',2000,'charge','a','generator',1.0,NULL); -INSERT INTO capacity_factor_tech VALUES('region',2000,'charge','b','generator',1.0,NULL); -INSERT INTO capacity_factor_tech VALUES('region',2000,'charge','c','generator',0.2,NULL); -INSERT INTO capacity_factor_tech VALUES('region',2000,'charge','d','generator',0.2,NULL); -INSERT INTO capacity_factor_tech VALUES('region',2000,'discharge','a','generator',0.1,NULL); -INSERT INTO capacity_factor_tech VALUES('region',2000,'discharge','b','generator',0.1,NULL); -INSERT INTO capacity_factor_tech VALUES('region',2000,'discharge','c','generator',0.01,NULL); -INSERT INTO capacity_factor_tech VALUES('region',2000,'discharge','d','generator',0.01,NULL); -CREATE TABLE CapacityToActivity +INSERT INTO "capacity_factor_tech" VALUES('region',2000,'charge','a','generator',1.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('region',2000,'charge','b','generator',1.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('region',2000,'charge','c','generator',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('region',2000,'charge','d','generator',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('region',2000,'discharge','a','generator',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('region',2000,'discharge','b','generator',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('region',2000,'discharge','c','generator',0.01,NULL); +INSERT INTO "capacity_factor_tech" VALUES('region',2000,'discharge','d','generator',0.01,NULL); +CREATE TABLE capacity_to_activity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), c2a REAL, notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO CapacityToActivity VALUES('region','generator',8760.0,'MWh/MWy'); -INSERT INTO CapacityToActivity VALUES('region','dly_stor',8760.0,'MWh/MWy'); -INSERT INTO CapacityToActivity VALUES('region','seas_stor',8760.0,'MWh/MWy'); -INSERT INTO CapacityToActivity VALUES('region','demand',8760.0,'MWh/MWy'); -CREATE TABLE Commodity +INSERT INTO "capacity_to_activity" VALUES('region','generator',8760.0,'MWh/MWy'); +INSERT INTO "capacity_to_activity" VALUES('region','dly_stor',8760.0,'MWh/MWy'); +INSERT INTO "capacity_to_activity" VALUES('region','seas_stor',8760.0,'MWh/MWy'); +INSERT INTO "capacity_to_activity" VALUES('region','demand',8760.0,'MWh/MWy'); +CREATE TABLE commodity ( name TEXT PRIMARY KEY, flag TEXT - REFERENCES CommodityType (label), + REFERENCES commodity_type (label), description TEXT ); -INSERT INTO Commodity VALUES('ethos','s',NULL); -INSERT INTO Commodity VALUES('electricity','p',NULL); -INSERT INTO Commodity VALUES('demand','d',NULL); -CREATE TABLE CommodityType +INSERT INTO "commodity" VALUES('ethos','s',NULL); +INSERT INTO "commodity" VALUES('electricity','p',NULL); +INSERT INTO "commodity" VALUES('demand','d',NULL); +CREATE TABLE commodity_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO CommodityType VALUES('p','physical commodity'); -INSERT INTO CommodityType VALUES('a','annual commodity'); -INSERT INTO CommodityType VALUES('e','emissions commodity'); -INSERT INTO CommodityType VALUES('d','demand commodity'); -INSERT INTO CommodityType VALUES('s','source commodity'); -INSERT INTO CommodityType VALUES('w','waste commodity'); -INSERT INTO CommodityType VALUES('wa','waste annual commodity'); -INSERT INTO CommodityType VALUES('wp','waste physical commodity'); +INSERT INTO "commodity_type" VALUES('p','physical commodity'); +INSERT INTO "commodity_type" VALUES('a','annual commodity'); +INSERT INTO "commodity_type" VALUES('e','emissions commodity'); +INSERT INTO "commodity_type" VALUES('d','demand commodity'); +INSERT INTO "commodity_type" VALUES('s','source commodity'); +INSERT INTO "commodity_type" VALUES('w','waste commodity'); +INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); +INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); CREATE TABLE construction_input ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -170,9 +109,9 @@ CREATE TABLE cost_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT NOT NULL - REFERENCES Commodity (name), + REFERENCES commodity (name), cost REAL NOT NULL, units TEXT, notes TEXT, @@ -182,11 +121,11 @@ CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, @@ -196,122 +135,108 @@ CREATE TABLE cost_invest ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO cost_invest VALUES('region','generator',2000,1000.0,'',NULL); -INSERT INTO cost_invest VALUES('region','dly_stor',2000,1.0,'',NULL); -INSERT INTO cost_invest VALUES('region','seas_stor',2000,100.0,'',NULL); -INSERT INTO cost_invest VALUES('region','demand',2000,1.0,'',NULL); +INSERT INTO "cost_invest" VALUES('region','generator',2000,1000.0,'',NULL); +INSERT INTO "cost_invest" VALUES('region','dly_stor',2000,1.0,'',NULL); +INSERT INTO "cost_invest" VALUES('region','seas_stor',2000,100.0,'',NULL); +INSERT INTO "cost_invest" VALUES('region','demand',2000,1.0,'',NULL); CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_variable VALUES('region',2000,'generator',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2000,'demand',2000,1.0,NULL,NULL); -CREATE TABLE Demand +INSERT INTO "cost_variable" VALUES('region',2000,'generator',2000,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2000,'demand',2000,1.0,NULL,NULL); +CREATE TABLE demand ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), commodity TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), demand REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO Demand VALUES('region',2000,'demand',8760.0,'MWh',NULL); -CREATE TABLE DemandSpecificDistribution +INSERT INTO "demand" VALUES('region',2000,'demand',8760.0,'MWh',NULL); +CREATE TABLE demand_specific_distribution ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), demand_name TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), dsd REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','a','demand',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','b','demand',0.05,NULL); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','c','demand',0.05,NULL); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'charge','d','demand',0.1,NULL); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','a','demand',0.0,NULL); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','b','demand',0.2,NULL); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','c','demand',0.2,NULL); -INSERT INTO DemandSpecificDistribution VALUES('region',2000,'discharge','d','demand',0.4,NULL); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); +INSERT INTO "demand_specific_distribution" VALUES('region',2000,'charge','a','demand',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('region',2000,'charge','b','demand',0.05,NULL); +INSERT INTO "demand_specific_distribution" VALUES('region',2000,'charge','c','demand',0.05,NULL); +INSERT INTO "demand_specific_distribution" VALUES('region',2000,'charge','d','demand',0.1,NULL); +INSERT INTO "demand_specific_distribution" VALUES('region',2000,'discharge','a','demand',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('region',2000,'discharge','b','demand',0.2,NULL); +INSERT INTO "demand_specific_distribution" VALUES('region',2000,'discharge','c','demand',0.2,NULL); +INSERT INTO "demand_specific_distribution" VALUES('region',2000,'discharge','d','demand',0.4,NULL); CREATE TABLE efficiency ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO efficiency VALUES('region','ethos','generator',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('region','electricity','dly_stor',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('region','electricity','seas_stor',2000,'electricity',1.0,NULL); -INSERT INTO efficiency VALUES('region','electricity','demand',2000,'demand',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','ethos','generator',2000,'electricity',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','electricity','dly_stor',2000,'electricity',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','electricity','seas_stor',2000,'electricity',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','electricity','demand',2000,'demand',1.0,NULL); CREATE TABLE efficiency_variable ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), @@ -321,15 +246,15 @@ CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), activity REAL, units TEXT, notes TEXT, @@ -339,265 +264,250 @@ CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) ); CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE end_of_life_output +( + region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, tech, vintage, output_comm) ); CREATE TABLE existing_capacity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, units TEXT, notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE loan_lifetime_tech -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE loan_rate -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); CREATE TABLE lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) ); +CREATE TABLE lifetime_survival_curve +( + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES technology (tech), + vintage INTEGER NOT NULL + REFERENCES time_period (period), + fraction REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); CREATE TABLE lifetime_tech ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE Operator +CREATE TABLE limit_activity ( - operator TEXT PRIMARY KEY, - notes TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO Operator VALUES('e','equal to'); -INSERT INTO Operator VALUES('le','less than or equal to'); -INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE limit_growth_capacity +CREATE TABLE limit_activity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_annual_capacity_factor +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE limit_capacity +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE limit_capacity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_capacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity +CREATE TABLE limit_emission +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitStorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -INSERT INTO LimitStorageLevelFraction VALUES('region', 2000, 'winter', 'b', 'seas_stor', 2000, 'e', 0.5, NULL); -INSERT INTO LimitStorageLevelFraction VALUES('region', 2000, 'charge', 'b', 'dly_stor', 2000, 'e', 0.5, NULL); -CREATE TABLE limit_activity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), new_cap REAL, units TEXT, notes TEXT, @@ -607,11 +517,11 @@ CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), share REAL, notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) @@ -621,7 +531,7 @@ CREATE TABLE limit_resource region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), cum_act REAL, units TEXT, notes TEXT, @@ -630,30 +540,51 @@ CREATE TABLE limit_resource CREATE TABLE limit_seasonal_capacity_factor ( region TEXT - REFERENCES Region (region), + REFERENCES region (region), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), factor REAL, notes TEXT, PRIMARY KEY(region, period, season, tech, operator) ); +CREATE TABLE limit_storage_level_fraction +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) +); +INSERT INTO "limit_storage_level_fraction" VALUES('region',2000,'winter','b','seas_stor',2000,'e',0.5,NULL); +INSERT INTO "limit_storage_level_fraction" VALUES('region',2000,'charge','b','dly_stor',2000,'e',0.5,NULL); CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -662,13 +593,13 @@ CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -677,13 +608,13 @@ CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) @@ -692,171 +623,286 @@ CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE LinkedTech +CREATE TABLE linked_tech ( primary_region TEXT, primary_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), driven_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); -CREATE TABLE OutputCurtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE OutputNetCapacity +CREATE TABLE loan_lifetime_process ( - scenario TEXT, region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + REFERENCES time_period (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE loan_rate +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE OutputBuiltCapacity +CREATE TABLE metadata +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); +INSERT INTO "metadata" VALUES('DB_MINOR',0,''); +CREATE TABLE metadata_real +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +CREATE TABLE myopic_efficiency +( + base_year integer, + region text, + input_comm text, + tech text, + vintage integer, + output_comm text, + efficiency real, + lifetime integer, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (region, input_comm, tech, vintage, output_comm) +); +CREATE TABLE operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "operator" VALUES('e','equal to'); +INSERT INTO "operator" VALUES('le','less than or equal to'); +INSERT INTO "operator" VALUES('ge','greater than or equal to'); +CREATE TABLE output_built_capacity ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, tech, vintage) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE output_cost ( scenario TEXT, region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + sector TEXT REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) ); -CREATE TABLE OutputFlowIn +CREATE TABLE output_curtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES time_period (period), + tod TEXT + REFERENCES time_of_day (tod), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_dual_variable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE output_emission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE output_flow_in ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputFlowOut +CREATE TABLE output_flow_out ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputStorageLevel +CREATE TABLE output_flow_out_summary +( + scenario TEXT NOT NULL, + region TEXT NOT NULL, + sector TEXT, + period INTEGER, + input_comm TEXT NOT NULL, + tech TEXT NOT NULL, + vintage INTEGER, + output_comm TEXT NOT NULL, + flow REAL NOT NULL, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_net_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_objective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE output_retired_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); @@ -864,7 +910,7 @@ CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY - REFERENCES Region (region), + REFERENCES region (region), margin REAL, notes TEXT ); @@ -872,7 +918,7 @@ CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -881,54 +927,71 @@ CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE Region +CREATE TABLE region ( region TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO Region VALUES('region',NULL); +INSERT INTO "region" VALUES('region',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE TimeSegmentFraction +CREATE TABLE rps_requirement ( - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) -); -INSERT INTO TimeSegmentFraction VALUES(2000,'charge','a',0.125,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'charge','b',0.125,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'charge','c',0.125,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'charge','d',0.125,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','a',0.125,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','b',0.125,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','c',0.125,NULL); -INSERT INTO TimeSegmentFraction VALUES(2000,'discharge','d',0.125,NULL); + region TEXT NOT NULL + REFERENCES region (region), + period INTEGER NOT NULL + REFERENCES time_period (period), + tech_group TEXT NOT NULL + REFERENCES tech_group (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE season_label +( + season TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "season_label" VALUES('charge','non-sequential season - charging day'); +INSERT INTO "season_label" VALUES('discharge','non-sequential season - discharging day'); +INSERT INTO "season_label" VALUES('summer','sequential season - summer day'); +INSERT INTO "season_label" VALUES('sept_w1','sequential season - day in first week of September'); +INSERT INTO "season_label" VALUES('sept_w2','sequential season - day in second week of September'); +INSERT INTO "season_label" VALUES('sept_w3','sequential season - day in third week of September'); +INSERT INTO "season_label" VALUES('sept_w4','sequential season - day in fourth week of September'); +INSERT INTO "season_label" VALUES('sept_29th','sequential season - 29th of September'); +INSERT INTO "season_label" VALUES('sept_30th','sequential season - 30th of September'); +INSERT INTO "season_label" VALUES('winter','sequential season - winter day'); +INSERT INTO "season_label" VALUES('apr_w1','sequential season - day in first week of September'); +INSERT INTO "season_label" VALUES('apr_w2','sequential season - day in second week of September'); +INSERT INTO "season_label" VALUES('apr_w3','sequential season - day in third week of September'); +INSERT INTO "season_label" VALUES('apr_w4','sequential season - day in fourth week of September'); +INSERT INTO "season_label" VALUES('apr_29th','sequential season - 29th of April'); +INSERT INTO "season_label" VALUES('apr_30th','sequential season - 30th of April'); +CREATE TABLE sector_label +( + sector TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "sector_label" VALUES('electricity',NULL); CREATE TABLE storage_duration ( region TEXT, @@ -937,172 +1000,159 @@ CREATE TABLE storage_duration notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO storage_duration VALUES('region','dly_stor',4.0,NULL); -INSERT INTO storage_duration VALUES('region','seas_stor',8760.0,NULL); -CREATE TABLE lifetime_survival_curve +INSERT INTO "storage_duration" VALUES('region','dly_stor',4.0,NULL); +INSERT INTO "storage_duration" VALUES('region','seas_stor',8760.0,NULL); +CREATE TABLE tech_group ( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE tech_group_member +( + group_name TEXT + REFERENCES tech_group (group_name), + tech TEXT + REFERENCES technology (tech), + PRIMARY KEY (group_name, tech) +); +CREATE TABLE technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES technology_type (label) ); -CREATE TABLE TechnologyType +INSERT INTO "technology" VALUES('generator','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO "technology" VALUES('dly_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO "technology" VALUES('seas_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,1,NULL); +INSERT INTO "technology" VALUES('demand','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +CREATE TABLE technology_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('p','production technology'); -INSERT INTO TechnologyType VALUES('pb','baseload production technology'); -INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE TimeOfDay +INSERT INTO "technology_type" VALUES('p','production technology'); +INSERT INTO "technology_type" VALUES('pb','baseload production technology'); +INSERT INTO "technology_type" VALUES('ps','storage production technology'); +CREATE TABLE time_of_day ( sequence INTEGER UNIQUE, tod TEXT PRIMARY KEY ); -INSERT INTO TimeOfDay VALUES(0,'a'); -INSERT INTO TimeOfDay VALUES(1,'b'); -INSERT INTO TimeOfDay VALUES(2,'c'); -INSERT INTO TimeOfDay VALUES(3,'d'); -CREATE TABLE TimePeriod +INSERT INTO "time_of_day" VALUES(0,'a'); +INSERT INTO "time_of_day" VALUES(1,'b'); +INSERT INTO "time_of_day" VALUES(2,'c'); +INSERT INTO "time_of_day" VALUES(3,'d'); +CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES TimePeriodType (label) -); -INSERT INTO TimePeriod VALUES(0,2000,'f'); -INSERT INTO TimePeriod VALUES(1,2005,'f'); -CREATE TABLE TimeSeason -( - period INTEGER - REFERENCES TimePeriod (period), - sequence INTEGER, - season TEXT - REFERENCES SeasonLabel (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) + REFERENCES time_period_type (label) ); -INSERT INTO TimeSeason VALUES(2000,0,'charge',NULL); -INSERT INTO TimeSeason VALUES(2000,1,'discharge',NULL); -CREATE TABLE TimePeriodType +INSERT INTO "time_period" VALUES(0,2000,'f'); +INSERT INTO "time_period" VALUES(1,2005,'f'); +CREATE TABLE time_period_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TimePeriodType VALUES('e','existing vintages'); -INSERT INTO TimePeriodType VALUES('f','future'); -CREATE TABLE OutputEmission +INSERT INTO "time_period_type" VALUES('e','existing vintages'); +INSERT INTO "time_period_type" VALUES('f','future'); +CREATE TABLE time_season ( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE RPSRequirement -( - region TEXT NOT NULL - REFERENCES Region (region), - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech_group TEXT NOT NULL - REFERENCES TechGroup (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE TechGroupMember -( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES Technology (tech), - PRIMARY KEY (group_name, tech) + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + season TEXT REFERENCES season_label(season), + notes TEXT, + PRIMARY KEY (period, sequence, season) ); -CREATE TABLE Technology +INSERT INTO "time_season" VALUES(2000,0,'charge',NULL); +INSERT INTO "time_season" VALUES(2000,1,'discharge',NULL); +CREATE TABLE time_season_all ( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) + period INTEGER + REFERENCES time_period (period), + sequence INTEGER, + season TEXT + REFERENCES season_label (season), + notes TEXT, + PRIMARY KEY (period, sequence, season) ); -INSERT INTO Technology VALUES('generator','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('dly_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('seas_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,1,NULL); -INSERT INTO Technology VALUES('demand','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -CREATE TABLE OutputCost +CREATE TABLE time_season_sequential ( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + seas_seq TEXT, + season TEXT REFERENCES season_label(season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) ); -CREATE TABLE time_season_sequential +INSERT INTO "time_season_sequential" VALUES(2000,1,'summer','charge',152.5,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,2,'sept_w1','discharge',7.0,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,3,'sept_w2','charge',7.0,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,4,'sept_w3','discharge',7.0,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,5,'sept_w4','charge',7.0,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,6,'sept_29th','discharge',1.0,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,7,'sept_30th','charge',1.0,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,8,'winter','discharge',152.5,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,9,'apr_w1','charge',7.0,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,10,'apr_w2','discharge',7.0,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,11,'apr_w3','charge',7.0,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,12,'apr_w4','discharge',7.0,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,13,'apr_29th','charge',1.0,NULL); +INSERT INTO "time_season_sequential" VALUES(2000,14,'apr_30th','discharge',1.0,NULL); +CREATE TABLE time_season_to_sequential ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -INSERT INTO time_season_sequential VALUES(2000,1,'summer','charge',152.5,NULL); -INSERT INTO time_season_sequential VALUES(2000,2,'sept_w1','discharge',7,NULL); -INSERT INTO time_season_sequential VALUES(2000,3,'sept_w2','charge',7,NULL); -INSERT INTO time_season_sequential VALUES(2000,4,'sept_w3','discharge',7,NULL); -INSERT INTO time_season_sequential VALUES(2000,5,'sept_w4','charge',7,NULL); -INSERT INTO time_season_sequential VALUES(2000,6,'sept_29th','discharge',1,NULL); -INSERT INTO time_season_sequential VALUES(2000,7,'sept_30th','charge',1,NULL); -INSERT INTO time_season_sequential VALUES(2000,8,'winter','discharge',152.5,NULL); -INSERT INTO time_season_sequential VALUES(2000,9,'apr_w1','charge',7,NULL); -INSERT INTO time_season_sequential VALUES(2000,10,'apr_w2','discharge',7,NULL); -INSERT INTO time_season_sequential VALUES(2000,11,'apr_w3','charge',7,NULL); -INSERT INTO time_season_sequential VALUES(2000,12,'apr_w4','discharge',7,NULL); -INSERT INTO time_season_sequential VALUES(2000,13,'apr_29th','charge',1,NULL); -INSERT INTO time_season_sequential VALUES(2000,14,'apr_30th','discharge',1,NULL); +CREATE TABLE time_segment_fraction +( + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + segment_fraction REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) +); +INSERT INTO "time_segment_fraction" VALUES(2000,'charge','a',0.125,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'charge','b',0.125,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'charge','c',0.125,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'charge','d',0.125,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'discharge','a',0.125,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'discharge','b',0.125,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'discharge','c',0.125,NULL); +INSERT INTO "time_segment_fraction" VALUES(2000,'discharge','d',0.125,NULL); +CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; diff --git a/data_files/example_dbs/survival_curve.sql b/data_files/example_dbs/survival_curve.sql index b0c6560ad..c907629e6 100644 --- a/data_files/example_dbs/survival_curve.sql +++ b/data_files/example_dbs/survival_curve.sql @@ -1,56 +1,11 @@ -PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE MetaData -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',0,'DB minor version number'); -INSERT INTO MetaData VALUES('days_per_period',365,'count of days in each period'); -CREATE TABLE MetaDataReal -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -CREATE TABLE OutputDualVariable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE SeasonLabel -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SeasonLabel VALUES('s',NULL); -CREATE TABLE SectorLabel -( - sector TEXT PRIMARY KEY, - notes TEXT -); CREATE TABLE capacity_credit ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, credit REAL, notes TEXT, @@ -61,13 +16,13 @@ CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -78,60 +33,60 @@ CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE CapacityToActivity +CREATE TABLE capacity_to_activity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), c2a REAL, notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE Commodity +CREATE TABLE commodity ( name TEXT PRIMARY KEY, flag TEXT - REFERENCES CommodityType (label), + REFERENCES commodity_type (label), description TEXT ); -INSERT INTO Commodity VALUES('source','s',NULL); -INSERT INTO Commodity VALUES('demand','d',NULL); -CREATE TABLE CommodityType +INSERT INTO "commodity" VALUES('source','s',NULL); +INSERT INTO "commodity" VALUES('demand','d',NULL); +CREATE TABLE commodity_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO CommodityType VALUES('p','physical commodity'); -INSERT INTO CommodityType VALUES('a','annual commodity'); -INSERT INTO CommodityType VALUES('e','emissions commodity'); -INSERT INTO CommodityType VALUES('d','demand commodity'); -INSERT INTO CommodityType VALUES('s','source commodity'); -INSERT INTO CommodityType VALUES('w','waste commodity'); -INSERT INTO CommodityType VALUES('wa','waste annual commodity'); -INSERT INTO CommodityType VALUES('wp','waste physical commodity'); +INSERT INTO "commodity_type" VALUES('p','physical commodity'); +INSERT INTO "commodity_type" VALUES('a','annual commodity'); +INSERT INTO "commodity_type" VALUES('e','emissions commodity'); +INSERT INTO "commodity_type" VALUES('d','demand commodity'); +INSERT INTO "commodity_type" VALUES('s','source commodity'); +INSERT INTO "commodity_type" VALUES('w','waste commodity'); +INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); +INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); CREATE TABLE construction_input ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -141,9 +96,9 @@ CREATE TABLE cost_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT NOT NULL - REFERENCES Commodity (name), + REFERENCES commodity (name), cost REAL NOT NULL, units TEXT, notes TEXT, @@ -153,189 +108,175 @@ CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_fixed VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO cost_fixed VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO "cost_fixed" VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); CREATE TABLE cost_invest ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO cost_invest VALUES('region','tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('region','tech_future',2030,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('region','tech_future',2035,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('region','tech_future',2040,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('region','tech_future',2045,1.0,NULL,NULL); -INSERT INTO cost_invest VALUES('region','tech_future',2050,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('region','tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('region','tech_future',2030,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('region','tech_future',2035,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('region','tech_future',2040,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('region','tech_future',2045,1.0,NULL,NULL); +INSERT INTO "cost_invest" VALUES('region','tech_future',2050,1.0,NULL,NULL); CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_variable VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); -CREATE TABLE Demand +INSERT INTO "cost_variable" VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); +INSERT INTO "cost_variable" VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); +CREATE TABLE demand ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), commodity TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), demand REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO Demand VALUES('region',2025,'demand',1.0,NULL,NULL); -INSERT INTO Demand VALUES('region',2030,'demand',1.0,NULL,NULL); -INSERT INTO Demand VALUES('region',2035,'demand',1.0,NULL,NULL); -INSERT INTO Demand VALUES('region',2040,'demand',1.0,NULL,NULL); -INSERT INTO Demand VALUES('region',2045,'demand',1.0,NULL,NULL); -INSERT INTO Demand VALUES('region',2050,'demand',1.0,NULL,NULL); -CREATE TABLE DemandSpecificDistribution +INSERT INTO "demand" VALUES('region',2025,'demand',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('region',2030,'demand',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('region',2035,'demand',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('region',2040,'demand',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('region',2045,'demand',1.0,NULL,NULL); +INSERT INTO "demand" VALUES('region',2050,'demand',1.0,NULL,NULL); +CREATE TABLE demand_specific_distribution ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), demand_name TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), dsd REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); CREATE TABLE efficiency ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO efficiency VALUES('region','source','tech_ancient',1994,'demand',1.0,NULL); -INSERT INTO efficiency VALUES('region','source','tech_old',2010,'demand',1.0,NULL); -INSERT INTO efficiency VALUES('region','source','tech_current',2025,'demand',1.0,NULL); -INSERT INTO efficiency VALUES('region','source','tech_future',2030,'demand',1.0,NULL); -INSERT INTO efficiency VALUES('region','source','tech_future',2035,'demand',1.0,NULL); -INSERT INTO efficiency VALUES('region','source','tech_future',2040,'demand',1.0,NULL); -INSERT INTO efficiency VALUES('region','source','tech_future',2045,'demand',1.0,NULL); -INSERT INTO efficiency VALUES('region','source','tech_future',2050,'demand',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','source','tech_ancient',1994,'demand',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','source','tech_old',2010,'demand',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','source','tech_current',2025,'demand',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','source','tech_future',2030,'demand',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','source','tech_future',2035,'demand',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','source','tech_future',2040,'demand',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','source','tech_future',2045,'demand',1.0,NULL); +INSERT INTO "efficiency" VALUES('region','source','tech_future',2050,'demand',1.0,NULL); CREATE TABLE efficiency_variable ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), @@ -345,15 +286,15 @@ CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), activity REAL, units TEXT, notes TEXT, @@ -363,271 +304,312 @@ CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) ); CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE end_of_life_output +( + region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, tech, vintage, output_comm) ); CREATE TABLE existing_capacity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, units TEXT, notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO existing_capacity VALUES('region','tech_ancient',1994,3.0,NULL,NULL); -INSERT INTO existing_capacity VALUES('region','tech_old',2010,0.7,NULL,NULL); -CREATE TABLE TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE loan_lifetime_process +INSERT INTO "existing_capacity" VALUES('region','tech_ancient',1994,3.0,NULL,NULL); +INSERT INTO "existing_capacity" VALUES('region','tech_old',2010,0.7,NULL,NULL); +CREATE TABLE lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE loan_rate +CREATE TABLE lifetime_survival_curve ( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - rate REAL, + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES technology (tech), + vintage INTEGER NOT NULL + REFERENCES time_period (period), + fraction REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_process -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, period, tech, vintage) ); +INSERT INTO "lifetime_survival_curve" VALUES('region',1994,'tech_ancient',1994,1.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',1999,'tech_ancient',1994,0.97,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2004,'tech_ancient',1994,8.80000000000000115e-01,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2009,'tech_ancient',1994,0.62,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2014,'tech_ancient',1994,0.27,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2019,'tech_ancient',1994,0.08,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2029,'tech_ancient',1994,0.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2010,'tech_old',2010,1.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2015,'tech_old',2010,0.97,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2020,'tech_old',2010,8.80000000000000115e-01,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2025,'tech_old',2010,0.62,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2030,'tech_old',2010,0.27,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2035,'tech_old',2010,0.08,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_old',2010,0.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2025,'tech_current',2025,1.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2030,'tech_current',2025,0.97,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2035,'tech_current',2025,8.80000000000000115e-01,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2040,'tech_current',2025,0.62,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_current',2025,0.27,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_current',2025,0.08,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2060,'tech_current',2025,0.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2030,'tech_future',2030,1.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2035,'tech_future',2030,0.97,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2040,'tech_future',2030,8.80000000000000115e-01,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_future',2030,0.62,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2030,0.27,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2030,0.08,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2065,'tech_future',2030,0.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2035,'tech_future',2035,1.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2040,'tech_future',2035,0.97,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_future',2035,8.80000000000000115e-01,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2035,0.62,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2035,0.27,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2060,'tech_future',2035,0.08,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2070,'tech_future',2035,0.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2040,'tech_future',2040,1.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_future',2040,0.97,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2040,8.80000000000000115e-01,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2040,0.62,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2060,'tech_future',2040,0.27,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2065,'tech_future',2040,0.08,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2075,'tech_future',2040,0.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_future',2045,1.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2045,0.97,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2045,8.80000000000000115e-01,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2060,'tech_future',2045,0.62,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2065,'tech_future',2045,0.27,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2070,'tech_future',2045,0.08,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2080,'tech_future',2045,0.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2050,1.0,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2050,0.97,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2060,'tech_future',2050,8.80000000000000115e-01,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2065,'tech_future',2050,0.62,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2070,'tech_future',2050,0.27,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2075,'tech_future',2050,0.08,NULL); +INSERT INTO "lifetime_survival_curve" VALUES('region',2085,'tech_future',2050,0.0,NULL); CREATE TABLE lifetime_tech ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO lifetime_tech VALUES('region','tech_ancient',35.0,NULL); -INSERT INTO lifetime_tech VALUES('region','tech_old',35.0,NULL); -INSERT INTO lifetime_tech VALUES('region','tech_current',35.0,NULL); -INSERT INTO lifetime_tech VALUES('region','tech_future',35.0,NULL); -CREATE TABLE Operator +INSERT INTO "lifetime_tech" VALUES('region','tech_ancient',35.0,NULL); +INSERT INTO "lifetime_tech" VALUES('region','tech_old',35.0,NULL); +INSERT INTO "lifetime_tech" VALUES('region','tech_current',35.0,NULL); +INSERT INTO "lifetime_tech" VALUES('region','tech_future',35.0,NULL); +CREATE TABLE limit_activity ( - operator TEXT PRIMARY KEY, - notes TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO Operator VALUES('e','equal to'); -INSERT INTO Operator VALUES('le','less than or equal to'); -INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE limit_growth_capacity +CREATE TABLE limit_activity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_annual_capacity_factor +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE limit_capacity +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE limit_capacity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_capacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity +CREATE TABLE limit_emission +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitStorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -CREATE TABLE limit_activity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), new_cap REAL, units TEXT, notes TEXT, @@ -637,11 +619,11 @@ CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), share REAL, notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) @@ -651,7 +633,7 @@ CREATE TABLE limit_resource region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), cum_act REAL, units TEXT, notes TEXT, @@ -660,30 +642,49 @@ CREATE TABLE limit_resource CREATE TABLE limit_seasonal_capacity_factor ( region TEXT - REFERENCES Region (region), + REFERENCES region (region), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), factor REAL, notes TEXT, PRIMARY KEY(region, period, season, tech, operator) ); +CREATE TABLE limit_storage_level_fraction +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) +); CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -692,13 +693,13 @@ CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -707,13 +708,13 @@ CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) @@ -722,171 +723,286 @@ CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE LinkedTech +CREATE TABLE linked_tech ( primary_region TEXT, primary_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), driven_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); -CREATE TABLE OutputCurtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE OutputNetCapacity +CREATE TABLE loan_lifetime_process ( - scenario TEXT, region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + REFERENCES time_period (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE loan_rate +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE metadata +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); +INSERT INTO "metadata" VALUES('DB_MINOR',0,''); +CREATE TABLE metadata_real +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +CREATE TABLE myopic_efficiency +( + base_year integer, + region text, + input_comm text, + tech text, + vintage integer, + output_comm text, + efficiency real, + lifetime integer, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (region, input_comm, tech, vintage, output_comm) +); +CREATE TABLE operator +( + operator TEXT PRIMARY KEY, + notes TEXT ); -CREATE TABLE OutputBuiltCapacity +INSERT INTO "operator" VALUES('e','equal to'); +INSERT INTO "operator" VALUES('le','less than or equal to'); +INSERT INTO "operator" VALUES('ge','greater than or equal to'); +CREATE TABLE output_built_capacity ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, tech, vintage) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE output_cost ( scenario TEXT, region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + sector TEXT REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) ); -CREATE TABLE OutputFlowIn +CREATE TABLE output_curtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES time_period (period), + tod TEXT + REFERENCES time_of_day (tod), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_dual_variable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE output_emission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE output_flow_in ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputFlowOut +CREATE TABLE output_flow_out ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputStorageLevel +CREATE TABLE output_flow_out_summary +( + scenario TEXT NOT NULL, + region TEXT NOT NULL, + sector TEXT, + period INTEGER, + input_comm TEXT NOT NULL, + tech TEXT NOT NULL, + vintage INTEGER, + output_comm TEXT NOT NULL, + flow REAL NOT NULL, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_net_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_objective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE output_retired_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); @@ -894,7 +1010,7 @@ CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY - REFERENCES Region (region), + REFERENCES region (region), margin REAL, notes TEXT ); @@ -902,7 +1018,7 @@ CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -911,52 +1027,55 @@ CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE Region +CREATE TABLE region ( region TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO Region VALUES('region',NULL); +INSERT INTO "region" VALUES('region',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE TimeSegmentFraction +CREATE TABLE rps_requirement ( - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) -); -INSERT INTO TimeSegmentFraction VALUES(2025,'s','d',1.0,NULL); -INSERT INTO TimeSegmentFraction VALUES(2030,'s','d',1.0,NULL); -INSERT INTO TimeSegmentFraction VALUES(2035,'s','d',1.0,NULL); -INSERT INTO TimeSegmentFraction VALUES(2040,'s','d',1.0,NULL); -INSERT INTO TimeSegmentFraction VALUES(2045,'s','d',1.0,NULL); -INSERT INTO TimeSegmentFraction VALUES(2050,'s','d',1.0,NULL); + region TEXT NOT NULL + REFERENCES region (region), + period INTEGER NOT NULL + REFERENCES time_period (period), + tech_group TEXT NOT NULL + REFERENCES tech_group (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE season_label +( + season TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "season_label" VALUES('s',NULL); +CREATE TABLE sector_label +( + sector TEXT PRIMARY KEY, + notes TEXT +); CREATE TABLE storage_duration ( region TEXT, @@ -965,220 +1084,149 @@ CREATE TABLE storage_duration notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE lifetime_survival_curve +CREATE TABLE tech_group ( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE tech_group_member +( + group_name TEXT + REFERENCES tech_group (group_name), + tech TEXT + REFERENCES technology (tech), + PRIMARY KEY (group_name, tech) ); -INSERT INTO lifetime_survival_curve VALUES('region',1994,'tech_ancient',1994,1,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',1999,'tech_ancient',1994,0.96999999999999992894,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2004,'tech_ancient',1994,0.88000000000000007105,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2009,'tech_ancient',1994,0.62000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2014,'tech_ancient',1994,0.27000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2019,'tech_ancient',1994,0.08,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2029,'tech_ancient',1994,0.0,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2010,'tech_old',2010,1,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2015,'tech_old',2010,0.96999999999999992894,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2020,'tech_old',2010,0.88000000000000007105,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2025,'tech_old',2010,0.62000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2030,'tech_old',2010,0.27000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2035,'tech_old',2010,0.08,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_old',2010,0.0,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2025,'tech_current',2025,1,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2030,'tech_current',2025,0.96999999999999992894,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2035,'tech_current',2025,0.88000000000000007105,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2040,'tech_current',2025,0.62000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_current',2025,0.27000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_current',2025,0.08,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2060,'tech_current',2025,0.0,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2030,'tech_future',2030,1,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2035,'tech_future',2030,0.96999999999999992894,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2040,'tech_future',2030,0.88000000000000007105,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_future',2030,0.62000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_future',2030,0.27000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2055,'tech_future',2030,0.08,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2065,'tech_future',2030,0.0,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2035,'tech_future',2035,1,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2040,'tech_future',2035,0.96999999999999992894,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_future',2035,0.88000000000000007105,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_future',2035,0.62000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2055,'tech_future',2035,0.27000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2060,'tech_future',2035,0.08,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2070,'tech_future',2035,0.0,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2040,'tech_future',2040,1,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_future',2040,0.96999999999999992894,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_future',2040,0.88000000000000007105,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2055,'tech_future',2040,0.62000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2060,'tech_future',2040,0.27000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2065,'tech_future',2040,0.08,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2075,'tech_future',2040,0.0,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2045,'tech_future',2045,1,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_future',2045,0.96999999999999992894,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2055,'tech_future',2045,0.88000000000000007105,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2060,'tech_future',2045,0.62000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2065,'tech_future',2045,0.27000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2070,'tech_future',2045,0.08,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2080,'tech_future',2045,0.0,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2050,'tech_future',2050,1,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2055,'tech_future',2050,0.96999999999999992894,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2060,'tech_future',2050,0.88000000000000007105,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2065,'tech_future',2050,0.62000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2070,'tech_future',2050,0.27000000000000001776,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2075,'tech_future',2050,0.08,NULL); -INSERT INTO lifetime_survival_curve VALUES('region',2085,'tech_future',2050,0.0,NULL); -CREATE TABLE TechnologyType +CREATE TABLE technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES technology_type (label) +); +INSERT INTO "technology" VALUES('tech_ancient','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO "technology" VALUES('tech_old','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO "technology" VALUES('tech_current','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +INSERT INTO "technology" VALUES('tech_future','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +CREATE TABLE technology_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('p','production technology'); -INSERT INTO TechnologyType VALUES('pb','baseload production technology'); -INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE TimeOfDay +INSERT INTO "technology_type" VALUES('p','production technology'); +INSERT INTO "technology_type" VALUES('pb','baseload production technology'); +INSERT INTO "technology_type" VALUES('ps','storage production technology'); +CREATE TABLE time_of_day ( sequence INTEGER UNIQUE, tod TEXT PRIMARY KEY ); -INSERT INTO TimeOfDay VALUES(0,'d'); -CREATE TABLE TimePeriod +INSERT INTO "time_of_day" VALUES(0,'d'); +CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES TimePeriodType (label) -); -INSERT INTO TimePeriod VALUES(-2,1994,'e'); -INSERT INTO TimePeriod VALUES(-1,2010,'e'); -INSERT INTO TimePeriod VALUES(0,2025,'f'); -INSERT INTO TimePeriod VALUES(1,2030,'f'); -INSERT INTO TimePeriod VALUES(2,2035,'f'); -INSERT INTO TimePeriod VALUES(3,2040,'f'); -INSERT INTO TimePeriod VALUES(4,2045,'f'); -INSERT INTO TimePeriod VALUES(5,2050,'f'); -INSERT INTO TimePeriod VALUES(6,2055,'f'); -CREATE TABLE TimeSeason + REFERENCES time_period_type (label) +); +INSERT INTO "time_period" VALUES(-2,1994,'e'); +INSERT INTO "time_period" VALUES(-1,2010,'e'); +INSERT INTO "time_period" VALUES(0,2025,'f'); +INSERT INTO "time_period" VALUES(1,2030,'f'); +INSERT INTO "time_period" VALUES(2,2035,'f'); +INSERT INTO "time_period" VALUES(3,2040,'f'); +INSERT INTO "time_period" VALUES(4,2045,'f'); +INSERT INTO "time_period" VALUES(5,2050,'f'); +INSERT INTO "time_period" VALUES(6,2055,'f'); +CREATE TABLE time_period_type +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO "time_period_type" VALUES('e','existing vintages'); +INSERT INTO "time_period_type" VALUES('f','future'); +CREATE TABLE time_season +( + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + season TEXT REFERENCES season_label(season), + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +INSERT INTO "time_season" VALUES(2025,0,'s',NULL); +INSERT INTO "time_season" VALUES(2030,1,'s',NULL); +INSERT INTO "time_season" VALUES(2035,2,'s',NULL); +INSERT INTO "time_season" VALUES(2040,3,'s',NULL); +INSERT INTO "time_season" VALUES(2045,4,'s',NULL); +INSERT INTO "time_season" VALUES(2050,5,'s',NULL); +CREATE TABLE time_season_all ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); -INSERT INTO TimeSeason VALUES(2025,0,'s',NULL); -INSERT INTO TimeSeason VALUES(2030,1,'s',NULL); -INSERT INTO TimeSeason VALUES(2035,2,'s',NULL); -INSERT INTO TimeSeason VALUES(2040,3,'s',NULL); -INSERT INTO TimeSeason VALUES(2045,4,'s',NULL); -INSERT INTO TimeSeason VALUES(2050,5,'s',NULL); CREATE TABLE time_season_sequential ( - period INTEGER - REFERENCES TimePeriod (period), + period INTEGER REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES SeasonLabel (season), + season TEXT REFERENCES season_label(season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE TimePeriodType +CREATE TABLE time_season_to_sequential ( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO TimePeriodType VALUES('e','existing vintages'); -INSERT INTO TimePeriodType VALUES('f','future'); -CREATE TABLE OutputEmission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE RPSRequirement -( - region TEXT NOT NULL - REFERENCES Region (region), - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech_group TEXT NOT NULL - REFERENCES TechGroup (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE TechGroupMember -( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES Technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE Technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) + period INTEGER + REFERENCES time_period (period), + sequence INTEGER, + seas_seq TEXT, + season TEXT + REFERENCES season_label (season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) ); -INSERT INTO Technology VALUES('tech_ancient','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('tech_old','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('tech_current','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO Technology VALUES('tech_future','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -CREATE TABLE OutputCost +CREATE TABLE time_segment_fraction ( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) -); + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + segment_fraction REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) +); +INSERT INTO "time_segment_fraction" VALUES(2025,'s','d',1.0,NULL); +INSERT INTO "time_segment_fraction" VALUES(2030,'s','d',1.0,NULL); +INSERT INTO "time_segment_fraction" VALUES(2035,'s','d',1.0,NULL); +INSERT INTO "time_segment_fraction" VALUES(2040,'s','d',1.0,NULL); +INSERT INTO "time_segment_fraction" VALUES(2045,'s','d',1.0,NULL); +INSERT INTO "time_segment_fraction" VALUES(2050,'s','d',1.0,NULL); +CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index 32f88b035..c7e9a5f50 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -1,65 +1,11 @@ -PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; -CREATE TABLE MetaData -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES ('days_per_period', 365, 'count of days in each period'); -CREATE TABLE MetaDataReal -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); -CREATE TABLE OutputDualVariable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE SeasonLabel -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SeasonLabel VALUES('summer',NULL); -INSERT INTO SeasonLabel VALUES('fall',NULL); -INSERT INTO SeasonLabel VALUES('winter',NULL); -INSERT INTO SeasonLabel VALUES('spring',NULL); -CREATE TABLE SectorLabel -( - sector TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SectorLabel VALUES('supply',NULL); -INSERT INTO SectorLabel VALUES('electric',NULL); -INSERT INTO SectorLabel VALUES('transport',NULL); -INSERT INTO SectorLabel VALUES('commercial',NULL); -INSERT INTO SectorLabel VALUES('residential',NULL); -INSERT INTO SectorLabel VALUES('industrial',NULL); CREATE TABLE capacity_credit ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, credit REAL, notes TEXT, @@ -70,13 +16,13 @@ CREATE TABLE capacity_factor_process ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, @@ -87,151 +33,151 @@ CREATE TABLE capacity_factor_tech ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO capacity_factor_tech VALUES('R1',2020,'spring','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2020,'spring','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R1',2020,'summer','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2020,'summer','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R1',2020,'fall','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2020,'fall','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R1',2020,'winter','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2020,'winter','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2020,'spring','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2020,'spring','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2020,'summer','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2020,'summer','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2020,'fall','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2020,'fall','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2020,'winter','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2020,'winter','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R1',2025,'spring','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2025,'spring','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R1',2025,'summer','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2025,'summer','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R1',2025,'fall','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2025,'fall','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R1',2025,'winter','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2025,'winter','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2025,'spring','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2025,'spring','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2025,'summer','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2025,'summer','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2025,'fall','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2025,'fall','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2025,'winter','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2025,'winter','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R1',2030,'spring','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2030,'spring','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R1',2030,'summer','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2030,'summer','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R1',2030,'fall','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2030,'fall','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R1',2030,'winter','day','E_SOLPV',0.5999999999999999778,''); -INSERT INTO capacity_factor_tech VALUES('R1',2030,'winter','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2030,'spring','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2030,'spring','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2030,'summer','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2030,'summer','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2030,'fall','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2030,'fall','night','E_SOLPV',0.0,''); -INSERT INTO capacity_factor_tech VALUES('R2',2030,'winter','day','E_SOLPV',0.4799999999999999823,''); -INSERT INTO capacity_factor_tech VALUES('R2',2030,'winter','night','E_SOLPV',0.0,''); -CREATE TABLE CapacityToActivity +INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'spring','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'spring','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'summer','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'summer','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'fall','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'fall','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'winter','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'winter','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'spring','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'spring','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'summer','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'summer','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'fall','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'fall','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'winter','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'winter','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'spring','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'spring','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'summer','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'summer','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'fall','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'fall','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'winter','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'winter','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'spring','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'spring','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'summer','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'summer','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'fall','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'fall','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'winter','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'winter','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'spring','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'spring','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'summer','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'summer','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'fall','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'fall','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'winter','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'winter','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'spring','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'spring','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'summer','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'summer','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'fall','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'fall','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'winter','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'winter','night','E_SOLPV',0.0,''); +CREATE TABLE capacity_to_activity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), c2a REAL, notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO CapacityToActivity VALUES('R1','S_IMPETH',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1','S_IMPOIL',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1','S_IMPNG',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1','S_IMPURN',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1','S_OILREF',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1','E_NGCC',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R1','E_SOLPV',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R1','E_BATT',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R1','E_NUCLEAR',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R1','T_BLND',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1','T_DSL',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1','T_GSL',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1','T_EV',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1','R_EH',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1','R_NGH',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','S_IMPETH',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','S_IMPOIL',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','S_IMPNG',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','S_IMPURN',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','S_OILREF',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','E_NGCC',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R2','E_SOLPV',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R2','E_BATT',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R2','E_NUCLEAR',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R2','T_BLND',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','T_DSL',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','T_GSL',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','T_EV',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','R_EH',1.0,''); -INSERT INTO CapacityToActivity VALUES('R2','R_NGH',1.0,''); -INSERT INTO CapacityToActivity VALUES('R1-R2','E_TRANS',31.53999999999999915,''); -INSERT INTO CapacityToActivity VALUES('R2-R1','E_TRANS',31.53999999999999915,''); -CREATE TABLE Commodity +INSERT INTO "capacity_to_activity" VALUES('R1','S_IMPETH',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R1','S_IMPOIL',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R1','S_IMPNG',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R1','S_IMPURN',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R1','S_OILREF',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R1','E_NGCC',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('R1','E_SOLPV',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('R1','E_BATT',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('R1','E_NUCLEAR',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('R1','T_BLND',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R1','T_DSL',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R1','T_GSL',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R1','T_EV',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R1','R_EH',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R1','R_NGH',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R2','S_IMPETH',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R2','S_IMPOIL',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R2','S_IMPNG',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R2','S_IMPURN',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R2','S_OILREF',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R2','E_NGCC',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('R2','E_SOLPV',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('R2','E_BATT',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('R2','E_NUCLEAR',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('R2','T_BLND',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R2','T_DSL',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R2','T_GSL',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R2','T_EV',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R2','R_EH',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R2','R_NGH',1.0,''); +INSERT INTO "capacity_to_activity" VALUES('R1-R2','E_TRANS',31.54,''); +INSERT INTO "capacity_to_activity" VALUES('R2-R1','E_TRANS',31.54,''); +CREATE TABLE commodity ( name TEXT PRIMARY KEY, flag TEXT - REFERENCES CommodityType (label), + REFERENCES commodity_type (label), description TEXT ); -INSERT INTO Commodity VALUES('ethos','s','dummy commodity to supply inputs (makes graph easier to read)'); -INSERT INTO Commodity VALUES('OIL','p','crude oil'); -INSERT INTO Commodity VALUES('NG','p','natural gas'); -INSERT INTO Commodity VALUES('URN','p','uranium'); -INSERT INTO Commodity VALUES('ETH','p','ethanol'); -INSERT INTO Commodity VALUES('SOL','p','solar insolation'); -INSERT INTO Commodity VALUES('GSL','p','gasoline'); -INSERT INTO Commodity VALUES('DSL','p','diesel'); -INSERT INTO Commodity VALUES('ELC','p','electricity'); -INSERT INTO Commodity VALUES('E10','p','gasoline blend with 10% ethanol'); -INSERT INTO Commodity VALUES('VMT','d','travel demand for vehicle-miles traveled'); -INSERT INTO Commodity VALUES('RH','d','demand for residential heating'); -INSERT INTO Commodity VALUES('CO2','e','CO2 emissions commodity'); -CREATE TABLE CommodityType +INSERT INTO "commodity" VALUES('ethos','s','dummy commodity to supply inputs (makes graph easier to read)'); +INSERT INTO "commodity" VALUES('OIL','p','crude oil'); +INSERT INTO "commodity" VALUES('NG','p','natural gas'); +INSERT INTO "commodity" VALUES('URN','p','uranium'); +INSERT INTO "commodity" VALUES('ETH','p','ethanol'); +INSERT INTO "commodity" VALUES('SOL','p','solar insolation'); +INSERT INTO "commodity" VALUES('GSL','p','gasoline'); +INSERT INTO "commodity" VALUES('DSL','p','diesel'); +INSERT INTO "commodity" VALUES('ELC','p','electricity'); +INSERT INTO "commodity" VALUES('E10','p','gasoline blend with 10% ethanol'); +INSERT INTO "commodity" VALUES('VMT','d','travel demand for vehicle-miles traveled'); +INSERT INTO "commodity" VALUES('RH','d','demand for residential heating'); +INSERT INTO "commodity" VALUES('CO2','e','CO2 emissions commodity'); +CREATE TABLE commodity_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO CommodityType VALUES('w','waste commodity'); -INSERT INTO CommodityType VALUES('wa','waste annual commodity'); -INSERT INTO CommodityType VALUES('wp','waste physical commodity'); -INSERT INTO CommodityType VALUES('a','annual commodity'); -INSERT INTO CommodityType VALUES('s','source commodity'); -INSERT INTO CommodityType VALUES('p','physical commodity'); -INSERT INTO CommodityType VALUES('e','emissions commodity'); -INSERT INTO CommodityType VALUES('d','demand commodity'); +INSERT INTO "commodity_type" VALUES('w','waste commodity'); +INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); +INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); +INSERT INTO "commodity_type" VALUES('a','annual commodity'); +INSERT INTO "commodity_type" VALUES('s','source commodity'); +INSERT INTO "commodity_type" VALUES('p','physical commodity'); +INSERT INTO "commodity_type" VALUES('e','emissions commodity'); +INSERT INTO "commodity_type" VALUES('d','demand commodity'); CREATE TABLE construction_input ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, @@ -241,9 +187,9 @@ CREATE TABLE cost_emission ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), emis_comm TEXT NOT NULL - REFERENCES Commodity (name), + REFERENCES commodity (name), cost REAL NOT NULL, units TEXT, notes TEXT, @@ -253,407 +199,393 @@ CREATE TABLE cost_fixed ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_fixed VALUES('R1',2020,'E_NGCC',2020,30.60000000000000142,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2025,'E_NGCC',2020,9.77999999999999937,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2025,'E_NGCC',2025,9.77999999999999937,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_NGCC',2020,9.77999999999999937,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_NGCC',2025,9.77999999999999937,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_NGCC',2030,9.77999999999999937,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2020,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2025,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2025,'E_SOLPV',2025,9.099999999999999645,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_SOLPV',2020,10.40000000000000035,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_SOLPV',2025,9.099999999999999645,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_SOLPV',2030,9.099999999999999645,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2020,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2025,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2025,'E_NUCLEAR',2025,98.0999999999999801,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_NUCLEAR',2020,98.0999999999999801,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_NUCLEAR',2025,98.0999999999999801,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_NUCLEAR',2030,98.0999999999999801,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2020,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2025,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2025,'E_BATT',2025,7.049999999999999823,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_BATT',2020,7.049999999999999823,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_BATT',2025,7.049999999999999823,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R1',2030,'E_BATT',2030,7.049999999999999823,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2020,'E_NGCC',2020,24.48000000000000042,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2025,'E_NGCC',2020,7.823999999999999844,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2025,'E_NGCC',2025,7.823999999999999844,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_NGCC',2020,7.823999999999999844,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_NGCC',2025,7.823999999999999844,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_NGCC',2030,7.823999999999999844,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2020,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2025,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2025,'E_SOLPV',2025,7.280000000000000248,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_SOLPV',2020,8.320000000000000284,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_SOLPV',2025,7.280000000000000248,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_SOLPV',2030,7.280000000000000248,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2020,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2025,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2025,'E_NUCLEAR',2025,78.48000000000000397,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_NUCLEAR',2020,78.48000000000000397,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_NUCLEAR',2025,78.48000000000000397,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_NUCLEAR',2030,78.48000000000000397,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2020,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2025,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2025,'E_BATT',2025,5.639999999999999681,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_BATT',2020,5.639999999999999681,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_BATT',2025,5.639999999999999681,'$M/GWyr',''); -INSERT INTO cost_fixed VALUES('R2',2030,'E_BATT',2030,5.639999999999999681,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2020,'E_NGCC',2020,30.6,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2025,'E_NGCC',2020,9.78,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2025,'E_NGCC',2025,9.78,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NGCC',2020,9.78,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NGCC',2025,9.78,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NGCC',2030,9.78,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2020,'E_SOLPV',2020,10.4,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2025,'E_SOLPV',2020,10.4,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2025,'E_SOLPV',2025,9.1,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_SOLPV',2020,10.4,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_SOLPV',2025,9.1,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_SOLPV',2030,9.1,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2020,'E_NUCLEAR',2020,9.809999999999998e+01,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2025,'E_NUCLEAR',2020,9.809999999999998e+01,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2025,'E_NUCLEAR',2025,9.809999999999998e+01,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NUCLEAR',2020,9.809999999999998e+01,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NUCLEAR',2025,9.809999999999998e+01,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NUCLEAR',2030,9.809999999999998e+01,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2020,'E_BATT',2020,7.05,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2025,'E_BATT',2020,7.05,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2025,'E_BATT',2025,7.05,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_BATT',2020,7.05,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_BATT',2025,7.05,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R1',2030,'E_BATT',2030,7.05,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2020,'E_NGCC',2020,24.48,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2025,'E_NGCC',2020,7.824,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2025,'E_NGCC',2025,7.824,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NGCC',2020,7.824,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NGCC',2025,7.824,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NGCC',2030,7.824,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2020,'E_SOLPV',2020,8.32,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2025,'E_SOLPV',2020,8.32,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2025,'E_SOLPV',2025,7.28,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_SOLPV',2020,8.32,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_SOLPV',2025,7.28,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_SOLPV',2030,7.28,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2020,'E_NUCLEAR',2020,78.48,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2025,'E_NUCLEAR',2020,78.48,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2025,'E_NUCLEAR',2025,78.48,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NUCLEAR',2020,78.48,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NUCLEAR',2025,78.48,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NUCLEAR',2030,78.48,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2020,'E_BATT',2020,5.64,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2025,'E_BATT',2020,5.64,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2025,'E_BATT',2025,5.64,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_BATT',2020,5.64,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_BATT',2025,5.64,'$M/GWyr',''); +INSERT INTO "cost_fixed" VALUES('R2',2030,'E_BATT',2030,5.64,'$M/GWyr',''); CREATE TABLE cost_invest ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO cost_invest VALUES('R1','E_NGCC',2020,1050.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','E_NGCC',2025,1025.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','E_NGCC',2030,1000.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','E_SOLPV',2020,900.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','E_SOLPV',2025,560.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','E_SOLPV',2030,800.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','E_NUCLEAR',2020,6145.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','E_NUCLEAR',2025,6045.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','E_NUCLEAR',2030,5890.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','E_BATT',2020,1150.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','E_BATT',2025,720.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','E_BATT',2030,480.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R1','T_GSL',2020,2570.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R1','T_GSL',2025,2700.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R1','T_GSL',2030,2700.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R1','T_DSL',2020,2715.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R1','T_DSL',2025,2810.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R1','T_DSL',2030,2810.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R1','T_EV',2020,3100.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R1','T_EV',2025,3030.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R1','T_EV',2030,2925.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R1','R_EH',2020,4.099999999999999644,'$/PJ/yr',''); -INSERT INTO cost_invest VALUES('R1','R_EH',2025,4.099999999999999644,'$/PJ/yr',''); -INSERT INTO cost_invest VALUES('R1','R_EH',2030,4.099999999999999644,'$/PJ/yr',''); -INSERT INTO cost_invest VALUES('R1','R_NGH',2020,7.599999999999999645,'$/PJ/yr',''); -INSERT INTO cost_invest VALUES('R1','R_NGH',2025,7.599999999999999645,'$/PJ/yr',''); -INSERT INTO cost_invest VALUES('R1','R_NGH',2030,7.599999999999999645,'$/PJ/yr',''); -INSERT INTO cost_invest VALUES('R2','E_NGCC',2020,840.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','E_NGCC',2025,820.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','E_NGCC',2030,800.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','E_SOLPV',2020,720.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','E_SOLPV',2025,448.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','E_SOLPV',2030,640.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','E_NUCLEAR',2020,4916.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','E_NUCLEAR',2025,4836.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','E_NUCLEAR',2030,4712.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','E_BATT',2020,920.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','E_BATT',2025,576.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','E_BATT',2030,384.0,'$M/GW',''); -INSERT INTO cost_invest VALUES('R2','T_GSL',2020,2056.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R2','T_GSL',2025,2160.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R2','T_GSL',2030,2160.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R2','T_DSL',2020,2172.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R2','T_DSL',2025,2248.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R2','T_DSL',2030,2248.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R2','T_EV',2020,2480.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R2','T_EV',2025,2424.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R2','T_EV',2030,2340.0,'$/bvmt/yr',''); -INSERT INTO cost_invest VALUES('R2','R_EH',2020,3.279999999999999805,'$/PJ/yr',''); -INSERT INTO cost_invest VALUES('R2','R_EH',2025,3.279999999999999805,'$/PJ/yr',''); -INSERT INTO cost_invest VALUES('R2','R_EH',2030,3.279999999999999805,'$/PJ/yr',''); -INSERT INTO cost_invest VALUES('R2','R_NGH',2020,6.080000000000000071,'$/PJ/yr',''); -INSERT INTO cost_invest VALUES('R2','R_NGH',2025,6.080000000000000071,'$/PJ/yr',''); -INSERT INTO cost_invest VALUES('R2','R_NGH',2030,6.080000000000000071,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R1','E_NGCC',2020,1050.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','E_NGCC',2025,1025.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','E_NGCC',2030,1000.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','E_SOLPV',2020,900.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','E_SOLPV',2025,560.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','E_SOLPV',2030,800.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','E_NUCLEAR',2020,6145.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','E_NUCLEAR',2025,6045.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','E_NUCLEAR',2030,5890.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','E_BATT',2020,1150.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','E_BATT',2025,720.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','E_BATT',2030,480.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R1','T_GSL',2020,2570.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R1','T_GSL',2025,2700.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R1','T_GSL',2030,2700.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R1','T_DSL',2020,2715.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R1','T_DSL',2025,2810.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R1','T_DSL',2030,2810.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R1','T_EV',2020,3100.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R1','T_EV',2025,3030.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R1','T_EV',2030,2925.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R1','R_EH',2020,4.1,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R1','R_EH',2025,4.1,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R1','R_EH',2030,4.1,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R1','R_NGH',2020,7.6,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R1','R_NGH',2025,7.6,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R1','R_NGH',2030,7.6,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R2','E_NGCC',2020,840.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','E_NGCC',2025,820.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','E_NGCC',2030,800.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','E_SOLPV',2020,720.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','E_SOLPV',2025,448.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','E_SOLPV',2030,640.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','E_NUCLEAR',2020,4916.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','E_NUCLEAR',2025,4836.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','E_NUCLEAR',2030,4712.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','E_BATT',2020,920.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','E_BATT',2025,576.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','E_BATT',2030,384.0,'$M/GW',''); +INSERT INTO "cost_invest" VALUES('R2','T_GSL',2020,2056.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R2','T_GSL',2025,2160.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R2','T_GSL',2030,2160.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R2','T_DSL',2020,2172.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R2','T_DSL',2025,2248.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R2','T_DSL',2030,2248.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R2','T_EV',2020,2480.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R2','T_EV',2025,2424.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R2','T_EV',2030,2340.0,'$/bvmt/yr',''); +INSERT INTO "cost_invest" VALUES('R2','R_EH',2020,3.28,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R2','R_EH',2025,3.28,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R2','R_EH',2030,3.28,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R2','R_NGH',2020,6.08,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R2','R_NGH',2025,6.08,'$/PJ/yr',''); +INSERT INTO "cost_invest" VALUES('R2','R_NGH',2030,6.08,'$/PJ/yr',''); CREATE TABLE cost_variable ( region TEXT NOT NULL, period INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT NOT NULL - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), + REFERENCES time_period (period), cost REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, tech, vintage) ); -INSERT INTO cost_variable VALUES('R1',2020,'S_IMPETH',2020,32.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2025,'S_IMPETH',2020,32.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2030,'S_IMPETH',2020,32.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2020,'S_IMPOIL',2020,20.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2025,'S_IMPOIL',2020,20.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2030,'S_IMPOIL',2020,20.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2020,'S_IMPNG',2020,4.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2025,'S_IMPNG',2020,4.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2030,'S_IMPNG',2020,4.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2020,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2025,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2030,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2020,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2025,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2025,'E_NGCC',2025,1.699999999999999956,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2030,'E_NGCC',2020,1.600000000000000088,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2030,'E_NGCC',2025,1.699999999999999956,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2030,'E_NGCC',2030,1.800000000000000044,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2020,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2025,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2025,'E_NUCLEAR',2025,0.25,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2030,'E_NUCLEAR',2020,0.2399999999999999912,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2030,'E_NUCLEAR',2025,0.25,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1',2030,'E_NUCLEAR',2030,0.2600000000000000088,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2020,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2025,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2030,'S_IMPETH',2020,25.60000000000000142,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2020,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2025,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2030,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2020,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2025,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2030,'S_IMPNG',2020,3.200000000000000177,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2020,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2025,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2030,'S_OILREF',2020,0.8000000000000000444,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2020,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2025,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2025,'E_NGCC',2025,1.360000000000000097,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2030,'E_NGCC',2020,1.280000000000000026,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2030,'E_NGCC',2025,1.360000000000000097,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2030,'E_NGCC',2030,1.439999999999999947,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2020,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2025,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2025,'E_NUCLEAR',2025,0.2000000000000000111,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2030,'E_NUCLEAR',2020,0.1920000000000000039,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2030,'E_NUCLEAR',2025,0.2000000000000000111,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2',2030,'E_NUCLEAR',2030,0.2080000000000000183,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1-R2',2020,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1-R2',2025,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R1-R2',2030,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2-R1',2020,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2-R1',2025,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -INSERT INTO cost_variable VALUES('R2-R1',2030,'E_TRANS',2015,0.1000000000000000055,'$M/PJ',''); -CREATE TABLE Demand +INSERT INTO "cost_variable" VALUES('R1',2020,'S_IMPETH',2020,32.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2025,'S_IMPETH',2020,32.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2030,'S_IMPETH',2020,32.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2020,'S_IMPOIL',2020,20.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2025,'S_IMPOIL',2020,20.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2030,'S_IMPOIL',2020,20.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2020,'S_IMPNG',2020,4.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2025,'S_IMPNG',2020,4.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2030,'S_IMPNG',2020,4.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2020,'S_OILREF',2020,1.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2025,'S_OILREF',2020,1.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2030,'S_OILREF',2020,1.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2020,'E_NGCC',2020,1.6,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2025,'E_NGCC',2020,1.6,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2025,'E_NGCC',2025,1.7,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2030,'E_NGCC',2020,1.6,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2030,'E_NGCC',2025,1.7,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2030,'E_NGCC',2030,1.8,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2020,'E_NUCLEAR',2020,0.24,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2025,'E_NUCLEAR',2020,0.24,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2025,'E_NUCLEAR',2025,0.25,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2030,'E_NUCLEAR',2020,0.24,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2030,'E_NUCLEAR',2025,0.25,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1',2030,'E_NUCLEAR',2030,0.26,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2020,'S_IMPETH',2020,25.6,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2025,'S_IMPETH',2020,25.6,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2030,'S_IMPETH',2020,25.6,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2020,'S_IMPOIL',2020,16.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2025,'S_IMPOIL',2020,16.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2030,'S_IMPOIL',2020,16.0,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2020,'S_IMPNG',2020,3.2,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2025,'S_IMPNG',2020,3.2,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2030,'S_IMPNG',2020,3.2,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2020,'S_OILREF',2020,0.8,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2025,'S_OILREF',2020,0.8,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2030,'S_OILREF',2020,0.8,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2020,'E_NGCC',2020,1.28,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2025,'E_NGCC',2020,1.28,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2025,'E_NGCC',2025,1.36,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2030,'E_NGCC',2020,1.28,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2030,'E_NGCC',2025,1.36,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2030,'E_NGCC',2030,1.44,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2020,'E_NUCLEAR',2020,0.192,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2025,'E_NUCLEAR',2020,0.192,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2025,'E_NUCLEAR',2025,0.2,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2030,'E_NUCLEAR',2020,0.192,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2030,'E_NUCLEAR',2025,0.2,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2',2030,'E_NUCLEAR',2030,2.08000000000000018e-01,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1-R2',2020,'E_TRANS',2015,0.1,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1-R2',2025,'E_TRANS',2015,0.1,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R1-R2',2030,'E_TRANS',2015,0.1,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2-R1',2020,'E_TRANS',2015,0.1,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2-R1',2025,'E_TRANS',2015,0.1,'$M/PJ',''); +INSERT INTO "cost_variable" VALUES('R2-R1',2030,'E_TRANS',2015,0.1,'$M/PJ',''); +CREATE TABLE demand ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), commodity TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), demand REAL, units TEXT, notes TEXT, PRIMARY KEY (region, period, commodity) ); -INSERT INTO Demand VALUES('R1',2020,'RH',30.0,'',''); -INSERT INTO Demand VALUES('R1',2025,'RH',33.0,'',''); -INSERT INTO Demand VALUES('R1',2030,'RH',36.0,'',''); -INSERT INTO Demand VALUES('R1',2020,'VMT',84.0,'',''); -INSERT INTO Demand VALUES('R1',2025,'VMT',91.0,'',''); -INSERT INTO Demand VALUES('R1',2030,'VMT',98.0,'',''); -INSERT INTO Demand VALUES('R2',2020,'RH',70.0,'',''); -INSERT INTO Demand VALUES('R2',2025,'RH',77.0,'',''); -INSERT INTO Demand VALUES('R2',2030,'RH',84.0,'',''); -INSERT INTO Demand VALUES('R2',2020,'VMT',36.0,'',''); -INSERT INTO Demand VALUES('R2',2025,'VMT',39.0,'',''); -INSERT INTO Demand VALUES('R2',2030,'VMT',42.0,'',''); -CREATE TABLE DemandSpecificDistribution +INSERT INTO "demand" VALUES('R1',2020,'RH',30.0,'',''); +INSERT INTO "demand" VALUES('R1',2025,'RH',33.0,'',''); +INSERT INTO "demand" VALUES('R1',2030,'RH',36.0,'',''); +INSERT INTO "demand" VALUES('R1',2020,'VMT',84.0,'',''); +INSERT INTO "demand" VALUES('R1',2025,'VMT',91.0,'',''); +INSERT INTO "demand" VALUES('R1',2030,'VMT',98.0,'',''); +INSERT INTO "demand" VALUES('R2',2020,'RH',70.0,'',''); +INSERT INTO "demand" VALUES('R2',2025,'RH',77.0,'',''); +INSERT INTO "demand" VALUES('R2',2030,'RH',84.0,'',''); +INSERT INTO "demand" VALUES('R2',2020,'VMT',36.0,'',''); +INSERT INTO "demand" VALUES('R2',2025,'VMT',39.0,'',''); +INSERT INTO "demand" VALUES('R2',2030,'VMT',42.0,'',''); +CREATE TABLE demand_specific_distribution ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), demand_name TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), dsd REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'spring','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'spring','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'summer','day','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'fall','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'fall','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'winter','day','RH',0.2999999999999999889,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2020,'winter','night','RH',0.4000000000000000222,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'spring','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'spring','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'summer','day','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'fall','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'fall','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'winter','day','RH',0.2999999999999999889,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2020,'winter','night','RH',0.4000000000000000222,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'spring','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'spring','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'summer','day','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'fall','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'fall','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'winter','day','RH',0.2999999999999999889,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2025,'winter','night','RH',0.4000000000000000222,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'spring','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'spring','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'summer','day','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'fall','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'fall','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'winter','day','RH',0.2999999999999999889,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2025,'winter','night','RH',0.4000000000000000222,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'spring','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'spring','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'summer','day','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'fall','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'fall','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'winter','day','RH',0.2999999999999999889,''); -INSERT INTO DemandSpecificDistribution VALUES('R1',2030,'winter','night','RH',0.4000000000000000222,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'spring','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'spring','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'summer','day','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'summer','night','RH',0.0,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'fall','day','RH',0.05000000000000000277,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'fall','night','RH',0.1000000000000000055,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'winter','day','RH',0.2999999999999999889,''); -INSERT INTO DemandSpecificDistribution VALUES('R2',2030,'winter','night','RH',0.4000000000000000222,''); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); +INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'spring','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'spring','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'summer','day','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'summer','night','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'fall','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'fall','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'winter','day','RH',0.3,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'winter','night','RH',0.4,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'spring','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'spring','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'summer','day','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'summer','night','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'fall','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'fall','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'winter','day','RH',0.3,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'winter','night','RH',0.4,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'spring','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'spring','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'summer','day','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'summer','night','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'fall','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'fall','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'winter','day','RH',0.3,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'winter','night','RH',0.4,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'spring','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'spring','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'summer','day','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'summer','night','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'fall','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'fall','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'winter','day','RH',0.3,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'winter','night','RH',0.4,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'spring','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'spring','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'summer','day','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'summer','night','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'fall','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'fall','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'winter','day','RH',0.3,''); +INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'winter','night','RH',0.4,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'spring','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'spring','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'summer','day','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'summer','night','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'fall','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'fall','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'winter','day','RH',0.3,''); +INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'winter','night','RH',0.4,''); CREATE TABLE efficiency ( region TEXT, input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); -INSERT INTO efficiency VALUES('R1','ethos','S_IMPETH',2020,'ETH',1.0,''); -INSERT INTO efficiency VALUES('R1','ethos','S_IMPOIL',2020,'OIL',1.0,''); -INSERT INTO efficiency VALUES('R1','ethos','S_IMPNG',2020,'NG',1.0,''); -INSERT INTO efficiency VALUES('R1','ethos','S_IMPURN',2020,'URN',1.0,''); -INSERT INTO efficiency VALUES('R1','OIL','S_OILREF',2020,'GSL',1.0,''); -INSERT INTO efficiency VALUES('R1','OIL','S_OILREF',2020,'DSL',1.0,''); -INSERT INTO efficiency VALUES('R1','ETH','T_BLND',2020,'E10',1.0,''); -INSERT INTO efficiency VALUES('R1','GSL','T_BLND',2020,'E10',1.0,''); -INSERT INTO efficiency VALUES('R1','NG','E_NGCC',2020,'ELC',0.5500000000000000444,''); -INSERT INTO efficiency VALUES('R1','NG','E_NGCC',2025,'ELC',0.5500000000000000444,''); -INSERT INTO efficiency VALUES('R1','NG','E_NGCC',2030,'ELC',0.5500000000000000444,''); -INSERT INTO efficiency VALUES('R1','SOL','E_SOLPV',2020,'ELC',1.0,''); -INSERT INTO efficiency VALUES('R1','SOL','E_SOLPV',2025,'ELC',1.0,''); -INSERT INTO efficiency VALUES('R1','SOL','E_SOLPV',2030,'ELC',1.0,''); -INSERT INTO efficiency VALUES('R1','URN','E_NUCLEAR',2015,'ELC',0.4000000000000000222,''); -INSERT INTO efficiency VALUES('R1','URN','E_NUCLEAR',2020,'ELC',0.4000000000000000222,''); -INSERT INTO efficiency VALUES('R1','URN','E_NUCLEAR',2025,'ELC',0.4000000000000000222,''); -INSERT INTO efficiency VALUES('R1','URN','E_NUCLEAR',2030,'ELC',0.4000000000000000222,''); -INSERT INTO efficiency VALUES('R1','ELC','E_BATT',2020,'ELC',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R1','ELC','E_BATT',2025,'ELC',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R1','ELC','E_BATT',2030,'ELC',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R1','E10','T_GSL',2020,'VMT',0.25,''); -INSERT INTO efficiency VALUES('R1','E10','T_GSL',2025,'VMT',0.25,''); -INSERT INTO efficiency VALUES('R1','E10','T_GSL',2030,'VMT',0.25,''); -INSERT INTO efficiency VALUES('R1','DSL','T_DSL',2020,'VMT',0.2999999999999999889,''); -INSERT INTO efficiency VALUES('R1','DSL','T_DSL',2025,'VMT',0.2999999999999999889,''); -INSERT INTO efficiency VALUES('R1','DSL','T_DSL',2030,'VMT',0.2999999999999999889,''); -INSERT INTO efficiency VALUES('R1','ELC','T_EV',2020,'VMT',0.8900000000000000133,''); -INSERT INTO efficiency VALUES('R1','ELC','T_EV',2025,'VMT',0.8900000000000000133,''); -INSERT INTO efficiency VALUES('R1','ELC','T_EV',2030,'VMT',0.8900000000000000133,''); -INSERT INTO efficiency VALUES('R1','ELC','R_EH',2020,'RH',1.0,''); -INSERT INTO efficiency VALUES('R1','ELC','R_EH',2025,'RH',1.0,''); -INSERT INTO efficiency VALUES('R1','ELC','R_EH',2030,'RH',1.0,''); -INSERT INTO efficiency VALUES('R1','NG','R_NGH',2020,'RH',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R1','NG','R_NGH',2025,'RH',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R1','NG','R_NGH',2030,'RH',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R2','ethos','S_IMPETH',2020,'ETH',1.0,''); -INSERT INTO efficiency VALUES('R2','ethos','S_IMPOIL',2020,'OIL',1.0,''); -INSERT INTO efficiency VALUES('R2','ethos','S_IMPNG',2020,'NG',1.0,''); -INSERT INTO efficiency VALUES('R2','ethos','S_IMPURN',2020,'URN',1.0,''); -INSERT INTO efficiency VALUES('R2','OIL','S_OILREF',2020,'GSL',1.0,''); -INSERT INTO efficiency VALUES('R2','OIL','S_OILREF',2020,'DSL',1.0,''); -INSERT INTO efficiency VALUES('R2','ETH','T_BLND',2020,'E10',1.0,''); -INSERT INTO efficiency VALUES('R2','GSL','T_BLND',2020,'E10',1.0,''); -INSERT INTO efficiency VALUES('R2','NG','E_NGCC',2020,'ELC',0.5500000000000000444,''); -INSERT INTO efficiency VALUES('R2','NG','E_NGCC',2025,'ELC',0.5500000000000000444,''); -INSERT INTO efficiency VALUES('R2','NG','E_NGCC',2030,'ELC',0.5500000000000000444,''); -INSERT INTO efficiency VALUES('R2','SOL','E_SOLPV',2020,'ELC',1.0,''); -INSERT INTO efficiency VALUES('R2','SOL','E_SOLPV',2025,'ELC',1.0,''); -INSERT INTO efficiency VALUES('R2','SOL','E_SOLPV',2030,'ELC',1.0,''); -INSERT INTO efficiency VALUES('R2','URN','E_NUCLEAR',2015,'ELC',0.4000000000000000222,''); -INSERT INTO efficiency VALUES('R2','URN','E_NUCLEAR',2020,'ELC',0.4000000000000000222,''); -INSERT INTO efficiency VALUES('R2','URN','E_NUCLEAR',2025,'ELC',0.4000000000000000222,''); -INSERT INTO efficiency VALUES('R2','URN','E_NUCLEAR',2030,'ELC',0.4000000000000000222,''); -INSERT INTO efficiency VALUES('R2','ELC','E_BATT',2020,'ELC',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R2','ELC','E_BATT',2025,'ELC',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R2','ELC','E_BATT',2030,'ELC',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R2','E10','T_GSL',2020,'VMT',0.25,''); -INSERT INTO efficiency VALUES('R2','E10','T_GSL',2025,'VMT',0.25,''); -INSERT INTO efficiency VALUES('R2','E10','T_GSL',2030,'VMT',0.25,''); -INSERT INTO efficiency VALUES('R2','DSL','T_DSL',2020,'VMT',0.2999999999999999889,''); -INSERT INTO efficiency VALUES('R2','DSL','T_DSL',2025,'VMT',0.2999999999999999889,''); -INSERT INTO efficiency VALUES('R2','DSL','T_DSL',2030,'VMT',0.2999999999999999889,''); -INSERT INTO efficiency VALUES('R2','ELC','T_EV',2020,'VMT',0.8900000000000000133,''); -INSERT INTO efficiency VALUES('R2','ELC','T_EV',2025,'VMT',0.8900000000000000133,''); -INSERT INTO efficiency VALUES('R2','ELC','T_EV',2030,'VMT',0.8900000000000000133,''); -INSERT INTO efficiency VALUES('R2','ELC','R_EH',2020,'RH',1.0,''); -INSERT INTO efficiency VALUES('R2','ELC','R_EH',2025,'RH',1.0,''); -INSERT INTO efficiency VALUES('R2','ELC','R_EH',2030,'RH',1.0,''); -INSERT INTO efficiency VALUES('R2','NG','R_NGH',2020,'RH',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R2','NG','R_NGH',2025,'RH',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R2','NG','R_NGH',2030,'RH',0.8499999999999999778,''); -INSERT INTO efficiency VALUES('R1-R2','ELC','E_TRANS',2015,'ELC',0.9000000000000000222,''); -INSERT INTO efficiency VALUES('R2-R1','ELC','E_TRANS',2015,'ELC',0.9000000000000000222,''); +INSERT INTO "efficiency" VALUES('R1','ethos','S_IMPETH',2020,'ETH',1.0,''); +INSERT INTO "efficiency" VALUES('R1','ethos','S_IMPOIL',2020,'OIL',1.0,''); +INSERT INTO "efficiency" VALUES('R1','ethos','S_IMPNG',2020,'NG',1.0,''); +INSERT INTO "efficiency" VALUES('R1','ethos','S_IMPURN',2020,'URN',1.0,''); +INSERT INTO "efficiency" VALUES('R1','OIL','S_OILREF',2020,'GSL',1.0,''); +INSERT INTO "efficiency" VALUES('R1','OIL','S_OILREF',2020,'DSL',1.0,''); +INSERT INTO "efficiency" VALUES('R1','ETH','T_BLND',2020,'E10',1.0,''); +INSERT INTO "efficiency" VALUES('R1','GSL','T_BLND',2020,'E10',1.0,''); +INSERT INTO "efficiency" VALUES('R1','NG','E_NGCC',2020,'ELC',0.55,''); +INSERT INTO "efficiency" VALUES('R1','NG','E_NGCC',2025,'ELC',0.55,''); +INSERT INTO "efficiency" VALUES('R1','NG','E_NGCC',2030,'ELC',0.55,''); +INSERT INTO "efficiency" VALUES('R1','SOL','E_SOLPV',2020,'ELC',1.0,''); +INSERT INTO "efficiency" VALUES('R1','SOL','E_SOLPV',2025,'ELC',1.0,''); +INSERT INTO "efficiency" VALUES('R1','SOL','E_SOLPV',2030,'ELC',1.0,''); +INSERT INTO "efficiency" VALUES('R1','URN','E_NUCLEAR',2015,'ELC',0.4,''); +INSERT INTO "efficiency" VALUES('R1','URN','E_NUCLEAR',2020,'ELC',0.4,''); +INSERT INTO "efficiency" VALUES('R1','URN','E_NUCLEAR',2025,'ELC',0.4,''); +INSERT INTO "efficiency" VALUES('R1','URN','E_NUCLEAR',2030,'ELC',0.4,''); +INSERT INTO "efficiency" VALUES('R1','ELC','E_BATT',2020,'ELC',0.85,''); +INSERT INTO "efficiency" VALUES('R1','ELC','E_BATT',2025,'ELC',0.85,''); +INSERT INTO "efficiency" VALUES('R1','ELC','E_BATT',2030,'ELC',0.85,''); +INSERT INTO "efficiency" VALUES('R1','E10','T_GSL',2020,'VMT',0.25,''); +INSERT INTO "efficiency" VALUES('R1','E10','T_GSL',2025,'VMT',0.25,''); +INSERT INTO "efficiency" VALUES('R1','E10','T_GSL',2030,'VMT',0.25,''); +INSERT INTO "efficiency" VALUES('R1','DSL','T_DSL',2020,'VMT',0.3,''); +INSERT INTO "efficiency" VALUES('R1','DSL','T_DSL',2025,'VMT',0.3,''); +INSERT INTO "efficiency" VALUES('R1','DSL','T_DSL',2030,'VMT',0.3,''); +INSERT INTO "efficiency" VALUES('R1','ELC','T_EV',2020,'VMT',0.89,''); +INSERT INTO "efficiency" VALUES('R1','ELC','T_EV',2025,'VMT',0.89,''); +INSERT INTO "efficiency" VALUES('R1','ELC','T_EV',2030,'VMT',0.89,''); +INSERT INTO "efficiency" VALUES('R1','ELC','R_EH',2020,'RH',1.0,''); +INSERT INTO "efficiency" VALUES('R1','ELC','R_EH',2025,'RH',1.0,''); +INSERT INTO "efficiency" VALUES('R1','ELC','R_EH',2030,'RH',1.0,''); +INSERT INTO "efficiency" VALUES('R1','NG','R_NGH',2020,'RH',0.85,''); +INSERT INTO "efficiency" VALUES('R1','NG','R_NGH',2025,'RH',0.85,''); +INSERT INTO "efficiency" VALUES('R1','NG','R_NGH',2030,'RH',0.85,''); +INSERT INTO "efficiency" VALUES('R2','ethos','S_IMPETH',2020,'ETH',1.0,''); +INSERT INTO "efficiency" VALUES('R2','ethos','S_IMPOIL',2020,'OIL',1.0,''); +INSERT INTO "efficiency" VALUES('R2','ethos','S_IMPNG',2020,'NG',1.0,''); +INSERT INTO "efficiency" VALUES('R2','ethos','S_IMPURN',2020,'URN',1.0,''); +INSERT INTO "efficiency" VALUES('R2','OIL','S_OILREF',2020,'GSL',1.0,''); +INSERT INTO "efficiency" VALUES('R2','OIL','S_OILREF',2020,'DSL',1.0,''); +INSERT INTO "efficiency" VALUES('R2','ETH','T_BLND',2020,'E10',1.0,''); +INSERT INTO "efficiency" VALUES('R2','GSL','T_BLND',2020,'E10',1.0,''); +INSERT INTO "efficiency" VALUES('R2','NG','E_NGCC',2020,'ELC',0.55,''); +INSERT INTO "efficiency" VALUES('R2','NG','E_NGCC',2025,'ELC',0.55,''); +INSERT INTO "efficiency" VALUES('R2','NG','E_NGCC',2030,'ELC',0.55,''); +INSERT INTO "efficiency" VALUES('R2','SOL','E_SOLPV',2020,'ELC',1.0,''); +INSERT INTO "efficiency" VALUES('R2','SOL','E_SOLPV',2025,'ELC',1.0,''); +INSERT INTO "efficiency" VALUES('R2','SOL','E_SOLPV',2030,'ELC',1.0,''); +INSERT INTO "efficiency" VALUES('R2','URN','E_NUCLEAR',2015,'ELC',0.4,''); +INSERT INTO "efficiency" VALUES('R2','URN','E_NUCLEAR',2020,'ELC',0.4,''); +INSERT INTO "efficiency" VALUES('R2','URN','E_NUCLEAR',2025,'ELC',0.4,''); +INSERT INTO "efficiency" VALUES('R2','URN','E_NUCLEAR',2030,'ELC',0.4,''); +INSERT INTO "efficiency" VALUES('R2','ELC','E_BATT',2020,'ELC',0.85,''); +INSERT INTO "efficiency" VALUES('R2','ELC','E_BATT',2025,'ELC',0.85,''); +INSERT INTO "efficiency" VALUES('R2','ELC','E_BATT',2030,'ELC',0.85,''); +INSERT INTO "efficiency" VALUES('R2','E10','T_GSL',2020,'VMT',0.25,''); +INSERT INTO "efficiency" VALUES('R2','E10','T_GSL',2025,'VMT',0.25,''); +INSERT INTO "efficiency" VALUES('R2','E10','T_GSL',2030,'VMT',0.25,''); +INSERT INTO "efficiency" VALUES('R2','DSL','T_DSL',2020,'VMT',0.3,''); +INSERT INTO "efficiency" VALUES('R2','DSL','T_DSL',2025,'VMT',0.3,''); +INSERT INTO "efficiency" VALUES('R2','DSL','T_DSL',2030,'VMT',0.3,''); +INSERT INTO "efficiency" VALUES('R2','ELC','T_EV',2020,'VMT',0.89,''); +INSERT INTO "efficiency" VALUES('R2','ELC','T_EV',2025,'VMT',0.89,''); +INSERT INTO "efficiency" VALUES('R2','ELC','T_EV',2030,'VMT',0.89,''); +INSERT INTO "efficiency" VALUES('R2','ELC','R_EH',2020,'RH',1.0,''); +INSERT INTO "efficiency" VALUES('R2','ELC','R_EH',2025,'RH',1.0,''); +INSERT INTO "efficiency" VALUES('R2','ELC','R_EH',2030,'RH',1.0,''); +INSERT INTO "efficiency" VALUES('R2','NG','R_NGH',2020,'RH',0.85,''); +INSERT INTO "efficiency" VALUES('R2','NG','R_NGH',2025,'RH',0.85,''); +INSERT INTO "efficiency" VALUES('R2','NG','R_NGH',2030,'RH',0.85,''); +INSERT INTO "efficiency" VALUES('R1-R2','ELC','E_TRANS',2015,'ELC',0.9,''); +INSERT INTO "efficiency" VALUES('R2-R1','ELC','E_TRANS',2015,'ELC',0.9,''); CREATE TABLE efficiency_variable ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), efficiency REAL, notes TEXT, PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), @@ -663,333 +595,322 @@ CREATE TABLE emission_activity ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), activity REAL, units TEXT, notes TEXT, PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) ); -INSERT INTO emission_activity VALUES('R1','CO2','ethos','S_IMPNG',2020,'NG',50.29999999999999005,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO emission_activity VALUES('R1','CO2','OIL','S_OILREF',2020,'GSL',67.20000000000000284,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO emission_activity VALUES('R1','CO2','OIL','S_OILREF',2020,'DSL',69.40000000000000569,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO emission_activity VALUES('R2','CO2','ethos','S_IMPNG',2020,'NG',50.29999999999999005,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO emission_activity VALUES('R2','CO2','OIL','S_OILREF',2020,'GSL',67.20000000000000284,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO emission_activity VALUES('R2','CO2','OIL','S_OILREF',2020,'DSL',69.40000000000000569,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO "emission_activity" VALUES('R1','CO2','ethos','S_IMPNG',2020,'NG',5.029999999999999e+01,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO "emission_activity" VALUES('R1','CO2','OIL','S_OILREF',2020,'GSL',67.2,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO "emission_activity" VALUES('R1','CO2','OIL','S_OILREF',2020,'DSL',69.4,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO "emission_activity" VALUES('R2','CO2','ethos','S_IMPNG',2020,'NG',5.029999999999999e+01,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO "emission_activity" VALUES('R2','CO2','OIL','S_OILREF',2020,'GSL',67.2,'kT/PJ','taken from MIT Energy Fact Sheet'); +INSERT INTO "emission_activity" VALUES('R2','CO2','OIL','S_OILREF',2020,'DSL',69.4,'kT/PJ','taken from MIT Energy Fact Sheet'); CREATE TABLE emission_embodied ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, emis_comm, tech, vintage) ); CREATE TABLE emission_end_of_life ( region TEXT, emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE end_of_life_output +( + region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), value REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) + PRIMARY KEY (region, tech, vintage, output_comm) ); CREATE TABLE existing_capacity ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, units TEXT, notes TEXT, PRIMARY KEY (region, tech, vintage) ); -INSERT INTO existing_capacity VALUES('R1','E_NUCLEAR',2015,0.07000000000000000667,'GW',''); -INSERT INTO existing_capacity VALUES('R2','E_NUCLEAR',2015,0.02999999999999999889,'GW',''); -INSERT INTO existing_capacity VALUES('R1-R2','E_TRANS',2015,10.0,'GW',''); -INSERT INTO existing_capacity VALUES('R2-R1','E_TRANS',2015,10.0,'GW',''); -CREATE TABLE TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE loan_lifetime_process +INSERT INTO "existing_capacity" VALUES('R1','E_NUCLEAR',2015,0.07,'GW',''); +INSERT INTO "existing_capacity" VALUES('R2','E_NUCLEAR',2015,0.03,'GW',''); +INSERT INTO "existing_capacity" VALUES('R1-R2','E_TRANS',2015,10.0,'GW',''); +INSERT INTO "existing_capacity" VALUES('R2-R1','E_TRANS',2015,10.0,'GW',''); +CREATE TABLE lifetime_process ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech, vintage) ); -CREATE TABLE loan_rate +CREATE TABLE lifetime_survival_curve ( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - rate REAL, + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES technology (tech), + vintage INTEGER NOT NULL + REFERENCES time_period (period), + fraction REAL, notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_process -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) + PRIMARY KEY (region, period, tech, vintage) ); CREATE TABLE lifetime_tech ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), lifetime REAL, notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO lifetime_tech VALUES('R1','S_IMPETH',100.0,''); -INSERT INTO lifetime_tech VALUES('R1','S_IMPOIL',100.0,''); -INSERT INTO lifetime_tech VALUES('R1','S_IMPNG',100.0,''); -INSERT INTO lifetime_tech VALUES('R1','S_IMPURN',100.0,''); -INSERT INTO lifetime_tech VALUES('R1','S_OILREF',100.0,''); -INSERT INTO lifetime_tech VALUES('R1','E_NGCC',30.0,''); -INSERT INTO lifetime_tech VALUES('R1','E_SOLPV',30.0,''); -INSERT INTO lifetime_tech VALUES('R1','E_BATT',20.0,''); -INSERT INTO lifetime_tech VALUES('R1','E_NUCLEAR',50.0,''); -INSERT INTO lifetime_tech VALUES('R1','T_BLND',100.0,''); -INSERT INTO lifetime_tech VALUES('R1','T_DSL',12.0,''); -INSERT INTO lifetime_tech VALUES('R1','T_GSL',12.0,''); -INSERT INTO lifetime_tech VALUES('R1','T_EV',12.0,''); -INSERT INTO lifetime_tech VALUES('R1','R_EH',20.0,''); -INSERT INTO lifetime_tech VALUES('R1','R_NGH',20.0,''); -INSERT INTO lifetime_tech VALUES('R2','S_IMPETH',100.0,''); -INSERT INTO lifetime_tech VALUES('R2','S_IMPOIL',100.0,''); -INSERT INTO lifetime_tech VALUES('R2','S_IMPNG',100.0,''); -INSERT INTO lifetime_tech VALUES('R2','S_IMPURN',100.0,''); -INSERT INTO lifetime_tech VALUES('R2','S_OILREF',100.0,''); -INSERT INTO lifetime_tech VALUES('R2','E_NGCC',30.0,''); -INSERT INTO lifetime_tech VALUES('R2','E_SOLPV',30.0,''); -INSERT INTO lifetime_tech VALUES('R2','E_BATT',20.0,''); -INSERT INTO lifetime_tech VALUES('R2','E_NUCLEAR',50.0,''); -INSERT INTO lifetime_tech VALUES('R2','T_BLND',100.0,''); -INSERT INTO lifetime_tech VALUES('R2','T_DSL',12.0,''); -INSERT INTO lifetime_tech VALUES('R2','T_GSL',12.0,''); -INSERT INTO lifetime_tech VALUES('R2','T_EV',12.0,''); -INSERT INTO lifetime_tech VALUES('R2','R_EH',20.0,''); -INSERT INTO lifetime_tech VALUES('R2','R_NGH',20.0,''); -INSERT INTO lifetime_tech VALUES('R1-R2','E_TRANS',30.0,''); -INSERT INTO lifetime_tech VALUES('R2-R1','E_TRANS',30.0,''); -CREATE TABLE Operator +INSERT INTO "lifetime_tech" VALUES('R1','S_IMPETH',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','S_IMPOIL',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','S_IMPNG',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','S_IMPURN',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','S_OILREF',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','E_NGCC',30.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','E_SOLPV',30.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','E_BATT',20.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','E_NUCLEAR',50.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','T_BLND',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','T_DSL',12.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','T_GSL',12.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','T_EV',12.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','R_EH',20.0,''); +INSERT INTO "lifetime_tech" VALUES('R1','R_NGH',20.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','S_IMPETH',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','S_IMPOIL',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','S_IMPNG',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','S_IMPURN',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','S_OILREF',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','E_NGCC',30.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','E_SOLPV',30.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','E_BATT',20.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','E_NUCLEAR',50.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','T_BLND',100.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','T_DSL',12.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','T_GSL',12.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','T_EV',12.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','R_EH',20.0,''); +INSERT INTO "lifetime_tech" VALUES('R2','R_NGH',20.0,''); +INSERT INTO "lifetime_tech" VALUES('R1-R2','E_TRANS',30.0,''); +INSERT INTO "lifetime_tech" VALUES('R2-R1','E_TRANS',30.0,''); +CREATE TABLE limit_activity ( - operator TEXT PRIMARY KEY, - notes TEXT + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) ); -INSERT INTO Operator VALUES('e','equal to'); -INSERT INTO Operator VALUES('le','less than or equal to'); -INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE limit_growth_capacity +INSERT INTO "limit_activity" VALUES('R1',2020,'T_GSL','ge',35.0,'',''); +INSERT INTO "limit_activity" VALUES('R1',2025,'T_GSL','ge',35.0,'',''); +INSERT INTO "limit_activity" VALUES('R1',2030,'T_GSL','ge',35.0,'',''); +INSERT INTO "limit_activity" VALUES('R2',2020,'T_GSL','ge',15.0,'',''); +INSERT INTO "limit_activity" VALUES('R2',2025,'T_GSL','ge',15.0,'',''); +INSERT INTO "limit_activity" VALUES('R2',2030,'T_GSL','ge',15.0,'',''); +CREATE TABLE limit_activity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_annual_capacity_factor +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE limit_capacity +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE limit_capacity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_degrowth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_capacity +CREATE TABLE limit_degrowth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity +CREATE TABLE limit_degrowth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity +CREATE TABLE limit_emission +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +INSERT INTO "limit_emission" VALUES('R1',2020,'CO2','le',25000.0,'kT CO2',''); +INSERT INTO "limit_emission" VALUES('R1',2025,'CO2','le',24000.0,'kT CO2',''); +INSERT INTO "limit_emission" VALUES('R1',2030,'CO2','le',23000.0,'kT CO2',''); +INSERT INTO "limit_emission" VALUES('global',2020,'CO2','le',37500.0,'kT CO2',''); +INSERT INTO "limit_emission" VALUES('global',2025,'CO2','le',36000.0,'kT CO2',''); +INSERT INTO "limit_emission" VALUES('global',2030,'CO2','le',34500.0,'kT CO2',''); +CREATE TABLE limit_growth_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_growth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE limit_degrowth_new_capacity_delta +CREATE TABLE limit_growth_new_capacity_delta ( region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), rate REAL NOT NULL DEFAULT 0, seed REAL NOT NULL DEFAULT 0, seed_units TEXT, notes TEXT, PRIMARY KEY (region, tech_or_group, operator) ); -CREATE TABLE LimitStorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -INSERT INTO LimitStorageLevelFraction VALUES('R1',2025,'winter','day','E_BATT',2025,'e',0.5,''); -INSERT INTO LimitStorageLevelFraction VALUES('R2',2020,'summer','day','E_BATT',2020,'e',0.5,''); -CREATE TABLE limit_activity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -INSERT INTO limit_activity VALUES('R1',2020,'T_GSL','ge',35.0,'',''); -INSERT INTO limit_activity VALUES('R1',2025,'T_GSL','ge',35.0,'',''); -INSERT INTO limit_activity VALUES('R1',2030,'T_GSL','ge',35.0,'',''); -INSERT INTO limit_activity VALUES('R2',2020,'T_GSL','ge',15.0,'',''); -INSERT INTO limit_activity VALUES('R2',2025,'T_GSL','ge',15.0,'',''); -INSERT INTO limit_activity VALUES('R2',2030,'T_GSL','ge',15.0,'',''); -CREATE TABLE limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); CREATE TABLE limit_new_capacity ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), new_cap REAL, units TEXT, notes TEXT, @@ -999,11 +920,11 @@ CREATE TABLE limit_new_capacity_share ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sub_group TEXT, super_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), share REAL, notes TEXT, PRIMARY KEY (region, period, sub_group, super_group, operator) @@ -1013,7 +934,7 @@ CREATE TABLE limit_resource region TEXT, tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), cum_act REAL, units TEXT, notes TEXT, @@ -1022,57 +943,78 @@ CREATE TABLE limit_resource CREATE TABLE limit_seasonal_capacity_factor ( region TEXT - REFERENCES Region (region), + REFERENCES region (region), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), factor REAL, notes TEXT, PRIMARY KEY(region, period, season, tech, operator) ); +CREATE TABLE limit_storage_level_fraction +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) +); +INSERT INTO "limit_storage_level_fraction" VALUES('R1',2025,'winter','day','E_BATT',2025,'e',0.5,''); +INSERT INTO "limit_storage_level_fraction" VALUES('R2',2020,'summer','day','E_BATT',2020,'e',0.5,''); CREATE TABLE limit_tech_input_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) ); -INSERT INTO limit_tech_input_split VALUES('R1',2020,'GSL','T_BLND','ge',0.9000000000000000222,''); -INSERT INTO limit_tech_input_split VALUES('R1',2020,'ETH','T_BLND','ge',0.1000000000000000055,''); -INSERT INTO limit_tech_input_split VALUES('R1',2025,'GSL','T_BLND','ge',0.9000000000000000222,''); -INSERT INTO limit_tech_input_split VALUES('R1',2025,'ETH','T_BLND','ge',0.1000000000000000055,''); -INSERT INTO limit_tech_input_split VALUES('R1',2030,'GSL','T_BLND','ge',0.9000000000000000222,''); -INSERT INTO limit_tech_input_split VALUES('R1',2030,'ETH','T_BLND','ge',0.1000000000000000055,''); -INSERT INTO limit_tech_input_split VALUES('R2',2020,'GSL','T_BLND','ge',0.7199999999999999734,''); -INSERT INTO limit_tech_input_split VALUES('R2',2020,'ETH','T_BLND','ge',0.08000000000000000166,''); -INSERT INTO limit_tech_input_split VALUES('R2',2025,'GSL','T_BLND','ge',0.7199999999999999734,''); -INSERT INTO limit_tech_input_split VALUES('R2',2025,'ETH','T_BLND','ge',0.08000000000000000166,''); -INSERT INTO limit_tech_input_split VALUES('R2',2030,'GSL','T_BLND','ge',0.7199999999999999734,''); -INSERT INTO limit_tech_input_split VALUES('R2',2030,'ETH','T_BLND','ge',0.08000000000000000166,''); +INSERT INTO "limit_tech_input_split" VALUES('R1',2020,'GSL','T_BLND','ge',0.9,''); +INSERT INTO "limit_tech_input_split" VALUES('R1',2020,'ETH','T_BLND','ge',0.1,''); +INSERT INTO "limit_tech_input_split" VALUES('R1',2025,'GSL','T_BLND','ge',0.9,''); +INSERT INTO "limit_tech_input_split" VALUES('R1',2025,'ETH','T_BLND','ge',0.1,''); +INSERT INTO "limit_tech_input_split" VALUES('R1',2030,'GSL','T_BLND','ge',0.9,''); +INSERT INTO "limit_tech_input_split" VALUES('R1',2030,'ETH','T_BLND','ge',0.1,''); +INSERT INTO "limit_tech_input_split" VALUES('R2',2020,'GSL','T_BLND','ge',0.72,''); +INSERT INTO "limit_tech_input_split" VALUES('R2',2020,'ETH','T_BLND','ge',0.08,''); +INSERT INTO "limit_tech_input_split" VALUES('R2',2025,'GSL','T_BLND','ge',0.72,''); +INSERT INTO "limit_tech_input_split" VALUES('R2',2025,'ETH','T_BLND','ge',0.08,''); +INSERT INTO "limit_tech_input_split" VALUES('R2',2030,'GSL','T_BLND','ge',0.72,''); +INSERT INTO "limit_tech_input_split" VALUES('R2',2030,'ETH','T_BLND','ge',0.08,''); CREATE TABLE limit_tech_input_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, input_comm, tech, operator) @@ -1081,204 +1023,313 @@ CREATE TABLE limit_tech_output_split ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -INSERT INTO limit_tech_output_split VALUES('R1',2020,'S_OILREF','GSL','ge',0.9000000000000000222,''); -INSERT INTO limit_tech_output_split VALUES('R1',2020,'S_OILREF','DSL','ge',0.1000000000000000055,''); -INSERT INTO limit_tech_output_split VALUES('R1',2025,'S_OILREF','GSL','ge',0.9000000000000000222,''); -INSERT INTO limit_tech_output_split VALUES('R1',2025,'S_OILREF','DSL','ge',0.1000000000000000055,''); -INSERT INTO limit_tech_output_split VALUES('R1',2030,'S_OILREF','GSL','ge',0.9000000000000000222,''); -INSERT INTO limit_tech_output_split VALUES('R1',2030,'S_OILREF','DSL','ge',0.1000000000000000055,''); -INSERT INTO limit_tech_output_split VALUES('R2',2020,'S_OILREF','GSL','ge',0.7199999999999999734,''); -INSERT INTO limit_tech_output_split VALUES('R2',2020,'S_OILREF','DSL','ge',0.08000000000000000166,''); -INSERT INTO limit_tech_output_split VALUES('R2',2025,'S_OILREF','GSL','ge',0.7199999999999999734,''); -INSERT INTO limit_tech_output_split VALUES('R2',2025,'S_OILREF','DSL','ge',0.08000000000000000166,''); -INSERT INTO limit_tech_output_split VALUES('R2',2030,'S_OILREF','GSL','ge',0.7199999999999999734,''); -INSERT INTO limit_tech_output_split VALUES('R2',2030,'S_OILREF','DSL','ge',0.08000000000000000166,''); +INSERT INTO "limit_tech_output_split" VALUES('R1',2020,'S_OILREF','GSL','ge',0.9,''); +INSERT INTO "limit_tech_output_split" VALUES('R1',2020,'S_OILREF','DSL','ge',0.1,''); +INSERT INTO "limit_tech_output_split" VALUES('R1',2025,'S_OILREF','GSL','ge',0.9,''); +INSERT INTO "limit_tech_output_split" VALUES('R1',2025,'S_OILREF','DSL','ge',0.1,''); +INSERT INTO "limit_tech_output_split" VALUES('R1',2030,'S_OILREF','GSL','ge',0.9,''); +INSERT INTO "limit_tech_output_split" VALUES('R1',2030,'S_OILREF','DSL','ge',0.1,''); +INSERT INTO "limit_tech_output_split" VALUES('R2',2020,'S_OILREF','GSL','ge',0.72,''); +INSERT INTO "limit_tech_output_split" VALUES('R2',2020,'S_OILREF','DSL','ge',0.08,''); +INSERT INTO "limit_tech_output_split" VALUES('R2',2025,'S_OILREF','GSL','ge',0.72,''); +INSERT INTO "limit_tech_output_split" VALUES('R2',2025,'S_OILREF','DSL','ge',0.08,''); +INSERT INTO "limit_tech_output_split" VALUES('R2',2030,'S_OILREF','GSL','ge',0.72,''); +INSERT INTO "limit_tech_output_split" VALUES('R2',2030,'S_OILREF','DSL','ge',0.08,''); CREATE TABLE limit_tech_output_split_annual ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), + REFERENCES operator (operator), proportion REAL, notes TEXT, PRIMARY KEY (region, period, tech, output_comm, operator) ); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -INSERT INTO limit_emission VALUES('R1',2020,'CO2','le',25000.0,'kT CO2',''); -INSERT INTO limit_emission VALUES('R1',2025,'CO2','le',24000.0,'kT CO2',''); -INSERT INTO limit_emission VALUES('R1',2030,'CO2','le',23000.0,'kT CO2',''); -INSERT INTO limit_emission VALUES('global',2020,'CO2','le',37500.0,'kT CO2',''); -INSERT INTO limit_emission VALUES('global',2025,'CO2','le',36000.0,'kT CO2',''); -INSERT INTO limit_emission VALUES('global',2030,'CO2','le',34500.0,'kT CO2',''); -CREATE TABLE LinkedTech +CREATE TABLE linked_tech ( primary_region TEXT, primary_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), emis_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), driven_tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), notes TEXT, PRIMARY KEY (primary_region, primary_tech, emis_comm) ); -CREATE TABLE OutputCurtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE OutputNetCapacity +CREATE TABLE loan_lifetime_process ( - scenario TEXT, region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + REFERENCES time_period (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE loan_rate +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE metadata +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); +INSERT INTO "metadata" VALUES('DB_MINOR',0,''); +CREATE TABLE metadata_real +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,''); +CREATE TABLE myopic_efficiency +( + base_year integer, + region text, + input_comm text, + tech text, + vintage integer, + output_comm text, + efficiency real, + lifetime integer, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (region, input_comm, tech, vintage, output_comm) +); +CREATE TABLE operator +( + operator TEXT PRIMARY KEY, + notes TEXT ); -CREATE TABLE OutputBuiltCapacity +INSERT INTO "operator" VALUES('e','equal to'); +INSERT INTO "operator" VALUES('le','less than or equal to'); +INSERT INTO "operator" VALUES('ge','greater than or equal to'); +CREATE TABLE output_built_capacity ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), capacity REAL, PRIMARY KEY (region, scenario, tech, vintage) ); -CREATE TABLE OutputRetiredCapacity +CREATE TABLE output_cost ( scenario TEXT, region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) + sector TEXT REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) +); +CREATE TABLE output_curtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES time_period (period), + tod TEXT + REFERENCES time_of_day (tod), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_dual_variable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE output_emission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); -CREATE TABLE OutputFlowIn +CREATE TABLE output_flow_in ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputFlowOut +CREATE TABLE output_flow_out ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), input_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), output_comm TEXT - REFERENCES Commodity (name), + REFERENCES commodity (name), flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); -CREATE TABLE OutputStorageLevel +CREATE TABLE output_flow_out_summary +( + scenario TEXT NOT NULL, + region TEXT NOT NULL, + sector TEXT, + period INTEGER, + input_comm TEXT NOT NULL, + tech TEXT NOT NULL, + vintage INTEGER, + output_comm TEXT NOT NULL, + flow REAL NOT NULL, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_net_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_objective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE output_retired_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_storage_level ( scenario TEXT, region TEXT, sector TEXT - REFERENCES SectorLabel (sector), + REFERENCES sector_label (sector), period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tod TEXT - REFERENCES TimeOfDay (tod), + REFERENCES time_of_day (tod), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), level REAL, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); @@ -1286,7 +1337,7 @@ CREATE TABLE planning_reserve_margin ( region TEXT PRIMARY KEY - REFERENCES Region (region), + REFERENCES region (region), margin REAL, notes TEXT ); @@ -1294,7 +1345,7 @@ CREATE TABLE ramp_down_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) @@ -1303,71 +1354,65 @@ CREATE TABLE ramp_up_hourly ( region TEXT, tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), rate REAL, notes TEXT, PRIMARY KEY (region, tech) ); -CREATE TABLE Region +CREATE TABLE region ( region TEXT PRIMARY KEY, notes TEXT ); -INSERT INTO Region VALUES('R1',NULL); -INSERT INTO Region VALUES('R2',NULL); +INSERT INTO "region" VALUES('R1',NULL); +INSERT INTO "region" VALUES('R2',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), tech TEXT - REFERENCES Technology (tech), + REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, PRIMARY KEY (region, period, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE TimeSegmentFraction +CREATE TABLE rps_requirement ( - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) -); -INSERT INTO TimeSegmentFraction VALUES(2020,'spring','day',0.125,'Spring - Day'); -INSERT INTO TimeSegmentFraction VALUES(2020,'spring','night',0.125,'Spring - Night'); -INSERT INTO TimeSegmentFraction VALUES(2020,'summer','day',0.125,'Summer - Day'); -INSERT INTO TimeSegmentFraction VALUES(2020,'summer','night',0.125,'Summer - Night'); -INSERT INTO TimeSegmentFraction VALUES(2020,'fall','day',0.125,'Fall - Day'); -INSERT INTO TimeSegmentFraction VALUES(2020,'fall','night',0.125,'Fall - Night'); -INSERT INTO TimeSegmentFraction VALUES(2020,'winter','day',0.125,'Winter - Day'); -INSERT INTO TimeSegmentFraction VALUES(2020,'winter','night',0.125,'Winter - Night'); -INSERT INTO TimeSegmentFraction VALUES(2025,'spring','day',0.125,'Spring - Day'); -INSERT INTO TimeSegmentFraction VALUES(2025,'spring','night',0.125,'Spring - Night'); -INSERT INTO TimeSegmentFraction VALUES(2025,'summer','day',0.125,'Summer - Day'); -INSERT INTO TimeSegmentFraction VALUES(2025,'summer','night',0.125,'Summer - Night'); -INSERT INTO TimeSegmentFraction VALUES(2025,'fall','day',0.125,'Fall - Day'); -INSERT INTO TimeSegmentFraction VALUES(2025,'fall','night',0.125,'Fall - Night'); -INSERT INTO TimeSegmentFraction VALUES(2025,'winter','day',0.125,'Winter - Day'); -INSERT INTO TimeSegmentFraction VALUES(2025,'winter','night',0.125,'Winter - Night'); -INSERT INTO TimeSegmentFraction VALUES(2030,'spring','day',0.125,'Spring - Day'); -INSERT INTO TimeSegmentFraction VALUES(2030,'spring','night',0.125,'Spring - Night'); -INSERT INTO TimeSegmentFraction VALUES(2030,'summer','day',0.125,'Summer - Day'); -INSERT INTO TimeSegmentFraction VALUES(2030,'summer','night',0.125,'Summer - Night'); -INSERT INTO TimeSegmentFraction VALUES(2030,'fall','day',0.125,'Fall - Day'); -INSERT INTO TimeSegmentFraction VALUES(2030,'fall','night',0.125,'Fall - Night'); -INSERT INTO TimeSegmentFraction VALUES(2030,'winter','day',0.125,'Winter - Day'); -INSERT INTO TimeSegmentFraction VALUES(2030,'winter','night',0.125,'Winter - Night'); + region TEXT NOT NULL + REFERENCES region (region), + period INTEGER NOT NULL + REFERENCES time_period (period), + tech_group TEXT NOT NULL + REFERENCES tech_group (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE season_label +( + season TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "season_label" VALUES('summer',NULL); +INSERT INTO "season_label" VALUES('fall',NULL); +INSERT INTO "season_label" VALUES('winter',NULL); +INSERT INTO "season_label" VALUES('spring',NULL); +CREATE TABLE sector_label +( + sector TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "sector_label" VALUES('supply',NULL); +INSERT INTO "sector_label" VALUES('electric',NULL); +INSERT INTO "sector_label" VALUES('transport',NULL); +INSERT INTO "sector_label" VALUES('commercial',NULL); +INSERT INTO "sector_label" VALUES('residential',NULL); +INSERT INTO "sector_label" VALUES('industrial',NULL); CREATE TABLE storage_duration ( region TEXT, @@ -1376,181 +1421,184 @@ CREATE TABLE storage_duration notes TEXT, PRIMARY KEY (region, tech) ); -INSERT INTO storage_duration VALUES('R1','E_BATT',8.0,'8-hour duration specified as fraction of a day'); -INSERT INTO storage_duration VALUES('R2','E_BATT',8.0,'8-hour duration specified as fraction of a day'); -CREATE TABLE lifetime_survival_curve +INSERT INTO "storage_duration" VALUES('R1','E_BATT',8.0,'8-hour duration specified as fraction of a day'); +INSERT INTO "storage_duration" VALUES('R2','E_BATT',8.0,'8-hour duration specified as fraction of a day'); +CREATE TABLE tech_group ( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE tech_group_member +( + group_name TEXT + REFERENCES tech_group (group_name), + tech TEXT + REFERENCES technology (tech), + PRIMARY KEY (group_name, tech) ); -CREATE TABLE TechnologyType +CREATE TABLE technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES technology_type (label) +); +INSERT INTO "technology" VALUES('S_IMPETH','p','supply','','',1,0,0,0,0,0,0,0,' imported ethanol'); +INSERT INTO "technology" VALUES('S_IMPOIL','p','supply','','',1,0,0,0,0,0,0,0,' imported crude oil'); +INSERT INTO "technology" VALUES('S_IMPNG','p','supply','','',1,0,0,0,0,0,0,0,' imported natural gas'); +INSERT INTO "technology" VALUES('S_IMPURN','p','supply','','',1,0,0,0,0,0,0,0,' imported uranium'); +INSERT INTO "technology" VALUES('S_OILREF','p','supply','','',0,0,0,1,0,0,0,0,' crude oil refinery'); +INSERT INTO "technology" VALUES('E_NGCC','p','electric','','',0,0,0,0,0,0,0,0,' natural gas combined-cycle'); +INSERT INTO "technology" VALUES('E_SOLPV','p','electric','','',0,0,0,0,0,0,0,0,' solar photovoltaic'); +INSERT INTO "technology" VALUES('E_BATT','ps','electric','','',0,0,0,0,0,0,0,0,' lithium-ion battery'); +INSERT INTO "technology" VALUES('E_NUCLEAR','pb','electric','','',0,0,0,0,0,0,0,0,' nuclear power plant'); +INSERT INTO "technology" VALUES('T_BLND','p','transport','','',0,0,0,0,0,0,0,0,'ethanol - gasoline blending process'); +INSERT INTO "technology" VALUES('T_DSL','p','transport','','',0,0,0,0,0,0,0,0,'diesel vehicle'); +INSERT INTO "technology" VALUES('T_GSL','p','transport','','',0,0,0,0,0,0,0,0,'gasoline vehicle'); +INSERT INTO "technology" VALUES('T_EV','p','transport','','',0,0,0,0,0,0,0,0,'electric vehicle'); +INSERT INTO "technology" VALUES('R_EH','p','residential','','',0,0,0,0,0,0,0,0,' electric residential heating'); +INSERT INTO "technology" VALUES('R_NGH','p','residential','','',0,0,0,0,0,0,0,0,' natural gas residential heating'); +INSERT INTO "technology" VALUES('E_TRANS','p','electric','','',0,0,0,0,0,0,1,0,'electric transmission'); +CREATE TABLE technology_type ( label TEXT PRIMARY KEY, description TEXT ); -INSERT INTO TechnologyType VALUES('p','production technology'); -INSERT INTO TechnologyType VALUES('pb','baseload production technology'); -INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE TimeOfDay +INSERT INTO "technology_type" VALUES('p','production technology'); +INSERT INTO "technology_type" VALUES('pb','baseload production technology'); +INSERT INTO "technology_type" VALUES('ps','storage production technology'); +CREATE TABLE time_of_day ( sequence INTEGER UNIQUE, tod TEXT PRIMARY KEY ); -INSERT INTO TimeOfDay VALUES(1,'day'); -INSERT INTO TimeOfDay VALUES(2,'night'); -CREATE TABLE TimePeriod +INSERT INTO "time_of_day" VALUES(1,'day'); +INSERT INTO "time_of_day" VALUES(2,'night'); +CREATE TABLE time_period ( sequence INTEGER UNIQUE, period INTEGER PRIMARY KEY, flag TEXT - REFERENCES TimePeriodType (label) + REFERENCES time_period_type (label) +); +INSERT INTO "time_period" VALUES(1,2015,'e'); +INSERT INTO "time_period" VALUES(2,2020,'f'); +INSERT INTO "time_period" VALUES(3,2025,'f'); +INSERT INTO "time_period" VALUES(4,2030,'f'); +INSERT INTO "time_period" VALUES(5,2035,'f'); +CREATE TABLE time_period_type +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO "time_period_type" VALUES('e','existing vintages'); +INSERT INTO "time_period_type" VALUES('f','future'); +CREATE TABLE time_season +( + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + season TEXT REFERENCES season_label(season), + notes TEXT, + PRIMARY KEY (period, sequence, season) ); -INSERT INTO TimePeriod VALUES(1,2015,'e'); -INSERT INTO TimePeriod VALUES(2,2020,'f'); -INSERT INTO TimePeriod VALUES(3,2025,'f'); -INSERT INTO TimePeriod VALUES(4,2030,'f'); -INSERT INTO TimePeriod VALUES(5,2035,'f'); -CREATE TABLE TimeSeason +INSERT INTO "time_season" VALUES(2020,1,'spring',NULL); +INSERT INTO "time_season" VALUES(2020,2,'summer',NULL); +INSERT INTO "time_season" VALUES(2020,3,'fall',NULL); +INSERT INTO "time_season" VALUES(2020,4,'winter',NULL); +INSERT INTO "time_season" VALUES(2025,1,'spring',NULL); +INSERT INTO "time_season" VALUES(2025,2,'summer',NULL); +INSERT INTO "time_season" VALUES(2025,3,'fall',NULL); +INSERT INTO "time_season" VALUES(2025,4,'winter',NULL); +INSERT INTO "time_season" VALUES(2030,1,'spring',NULL); +INSERT INTO "time_season" VALUES(2030,2,'summer',NULL); +INSERT INTO "time_season" VALUES(2030,3,'fall',NULL); +INSERT INTO "time_season" VALUES(2030,4,'winter',NULL); +CREATE TABLE time_season_all ( period INTEGER - REFERENCES TimePeriod (period), + REFERENCES time_period (period), sequence INTEGER, season TEXT - REFERENCES SeasonLabel (season), + REFERENCES season_label (season), notes TEXT, PRIMARY KEY (period, sequence, season) ); -INSERT INTO TimeSeason VALUES(2020,1,'spring',NULL); -INSERT INTO TimeSeason VALUES(2020,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(2020,3,'fall',NULL); -INSERT INTO TimeSeason VALUES(2020,4,'winter',NULL); -INSERT INTO TimeSeason VALUES(2025,1,'spring',NULL); -INSERT INTO TimeSeason VALUES(2025,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(2025,3,'fall',NULL); -INSERT INTO TimeSeason VALUES(2025,4,'winter',NULL); -INSERT INTO TimeSeason VALUES(2030,1,'spring',NULL); -INSERT INTO TimeSeason VALUES(2030,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(2030,3,'fall',NULL); -INSERT INTO TimeSeason VALUES(2030,4,'winter',NULL); CREATE TABLE time_season_sequential ( - period INTEGER - REFERENCES TimePeriod (period), + period INTEGER REFERENCES time_period (period), sequence INTEGER, seas_seq TEXT, - season TEXT - REFERENCES SeasonLabel (season), + season TEXT REFERENCES season_label(season), num_days REAL NOT NULL, notes TEXT, PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE TimePeriodType +CREATE TABLE time_season_to_sequential ( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO TimePeriodType VALUES('e','existing vintages'); -INSERT INTO TimePeriodType VALUES('f','future'); -CREATE TABLE OutputEmission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE RPSRequirement -( - region TEXT NOT NULL - REFERENCES Region (region), - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech_group TEXT NOT NULL - REFERENCES TechGroup (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE TechGroupMember -( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES Technology (tech), - PRIMARY KEY (group_name, tech) + period INTEGER + REFERENCES time_period (period), + sequence INTEGER, + seas_seq TEXT, + season TEXT + REFERENCES season_label (season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) ); -CREATE TABLE Technology +CREATE TABLE time_segment_fraction ( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) -); -INSERT INTO Technology VALUES('S_IMPETH','p','supply','','',1,0,0,0,0,0,0,0,' imported ethanol'); -INSERT INTO Technology VALUES('S_IMPOIL','p','supply','','',1,0,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO Technology VALUES('S_IMPNG','p','supply','','',1,0,0,0,0,0,0,0,' imported natural gas'); -INSERT INTO Technology VALUES('S_IMPURN','p','supply','','',1,0,0,0,0,0,0,0,' imported uranium'); -INSERT INTO Technology VALUES('S_OILREF','p','supply','','',0,0,0,1,0,0,0,0,' crude oil refinery'); -INSERT INTO Technology VALUES('E_NGCC','p','electric','','',0,0,0,0,0,0,0,0,' natural gas combined-cycle'); -INSERT INTO Technology VALUES('E_SOLPV','p','electric','','',0,0,0,0,0,0,0,0,' solar photovoltaic'); -INSERT INTO Technology VALUES('E_BATT','ps','electric','','',0,0,0,0,0,0,0,0,' lithium-ion battery'); -INSERT INTO Technology VALUES('E_NUCLEAR','pb','electric','','',0,0,0,0,0,0,0,0,' nuclear power plant'); -INSERT INTO Technology VALUES('T_BLND','p','transport','','',0,0,0,0,0,0,0,0,'ethanol - gasoline blending process'); -INSERT INTO Technology VALUES('T_DSL','p','transport','','',0,0,0,0,0,0,0,0,'diesel vehicle'); -INSERT INTO Technology VALUES('T_GSL','p','transport','','',0,0,0,0,0,0,0,0,'gasoline vehicle'); -INSERT INTO Technology VALUES('T_EV','p','transport','','',0,0,0,0,0,0,0,0,'electric vehicle'); -INSERT INTO Technology VALUES('R_EH','p','residential','','',0,0,0,0,0,0,0,0,' electric residential heating'); -INSERT INTO Technology VALUES('R_NGH','p','residential','','',0,0,0,0,0,0,0,0,' natural gas residential heating'); -INSERT INTO Technology VALUES('E_TRANS','p','electric','','',0,0,0,0,0,0,1,0,'electric transmission'); -CREATE TABLE OutputCost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) -); + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + segment_fraction REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) +); +INSERT INTO "time_segment_fraction" VALUES(2020,'spring','day',0.125,'Spring - Day'); +INSERT INTO "time_segment_fraction" VALUES(2020,'spring','night',0.125,'Spring - Night'); +INSERT INTO "time_segment_fraction" VALUES(2020,'summer','day',0.125,'Summer - Day'); +INSERT INTO "time_segment_fraction" VALUES(2020,'summer','night',0.125,'Summer - Night'); +INSERT INTO "time_segment_fraction" VALUES(2020,'fall','day',0.125,'Fall - Day'); +INSERT INTO "time_segment_fraction" VALUES(2020,'fall','night',0.125,'Fall - Night'); +INSERT INTO "time_segment_fraction" VALUES(2020,'winter','day',0.125,'Winter - Day'); +INSERT INTO "time_segment_fraction" VALUES(2020,'winter','night',0.125,'Winter - Night'); +INSERT INTO "time_segment_fraction" VALUES(2025,'spring','day',0.125,'Spring - Day'); +INSERT INTO "time_segment_fraction" VALUES(2025,'spring','night',0.125,'Spring - Night'); +INSERT INTO "time_segment_fraction" VALUES(2025,'summer','day',0.125,'Summer - Day'); +INSERT INTO "time_segment_fraction" VALUES(2025,'summer','night',0.125,'Summer - Night'); +INSERT INTO "time_segment_fraction" VALUES(2025,'fall','day',0.125,'Fall - Day'); +INSERT INTO "time_segment_fraction" VALUES(2025,'fall','night',0.125,'Fall - Night'); +INSERT INTO "time_segment_fraction" VALUES(2025,'winter','day',0.125,'Winter - Day'); +INSERT INTO "time_segment_fraction" VALUES(2025,'winter','night',0.125,'Winter - Night'); +INSERT INTO "time_segment_fraction" VALUES(2030,'spring','day',0.125,'Spring - Day'); +INSERT INTO "time_segment_fraction" VALUES(2030,'spring','night',0.125,'Spring - Night'); +INSERT INTO "time_segment_fraction" VALUES(2030,'summer','day',0.125,'Summer - Day'); +INSERT INTO "time_segment_fraction" VALUES(2030,'summer','night',0.125,'Summer - Night'); +INSERT INTO "time_segment_fraction" VALUES(2030,'fall','day',0.125,'Fall - Day'); +INSERT INTO "time_segment_fraction" VALUES(2030,'fall','night',0.125,'Fall - Night'); +INSERT INTO "time_segment_fraction" VALUES(2030,'winter','day',0.125,'Winter - Day'); +INSERT INTO "time_segment_fraction" VALUES(2030,'winter','night',0.125,'Winter - Night'); +CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index dc4b0f9cd..185852683 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -1125,6 +1125,20 @@ CREATE TABLE metadata_real ); INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,''); +CREATE TABLE myopic_efficiency +( + base_year integer, + region text, + input_comm text, + tech text, + vintage integer, + output_comm text, + efficiency real, + lifetime integer, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (region, input_comm, tech, vintage, output_comm) +); CREATE TABLE operator ( operator TEXT PRIMARY KEY, @@ -1258,6 +1272,21 @@ CREATE TABLE output_flow_out flow REAL, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); +CREATE TABLE output_flow_out_summary +( + scenario TEXT NOT NULL, + region TEXT NOT NULL, + sector TEXT, + period INTEGER, + input_comm TEXT NOT NULL, + tech TEXT NOT NULL, + vintage INTEGER, + output_comm TEXT NOT NULL, + flow REAL NOT NULL, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) +); CREATE TABLE output_net_capacity ( scenario TEXT, @@ -1573,4 +1602,5 @@ INSERT INTO "time_segment_fraction" VALUES(2010,'summer','day',0.1667,'# S-D'); INSERT INTO "time_segment_fraction" VALUES(2010,'summer','night',0.0833,'# S-N'); INSERT INTO "time_segment_fraction" VALUES(2010,'winter','day',0.3333,'# W-D'); INSERT INTO "time_segment_fraction" VALUES(2010,'winter','night',0.1667,'# W-N'); +CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; From 83e7e4bd96d559535a6798330ed69f8936c0874f Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Mon, 10 Nov 2025 08:33:11 -0500 Subject: [PATCH 320/587] changing cycles detected warning to info --- temoa/model_checking/commodity_graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temoa/model_checking/commodity_graph.py b/temoa/model_checking/commodity_graph.py index 17c1eb716..3ef086d8e 100644 --- a/temoa/model_checking/commodity_graph.py +++ b/temoa/model_checking/commodity_graph.py @@ -306,6 +306,6 @@ def visualize_graph( if len(cycle) < 2: continue cycle_str = ' -> '.join(cycle) + f' -> {cycle[0]}' - logger.warning('Cycle detected: %s', cycle_str) + logger.info('Cycle detected: %s', cycle_str) except nx.NetworkXError as e: logger.warning('NetworkXError during cycle detection: %s', e, exc_info=True) From 263a784082fb817a1f066d27f79552a9d6ff8e38 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Mon, 10 Nov 2025 08:19:13 -0500 Subject: [PATCH 321/587] minor polish --- data_files/temoa_schema_v4.sql | 2 +- temoa/components/time.py | 7 ++++--- temoa/data_io/hybrid_loader.py | 7 ++++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/data_files/temoa_schema_v4.sql b/data_files/temoa_schema_v4.sql index 7290fd313..5cbdb446f 100644 --- a/data_files/temoa_schema_v4.sql +++ b/data_files/temoa_schema_v4.sql @@ -1109,4 +1109,4 @@ CREATE TABLE IF NOT EXISTS output_flow_out_summary ); COMMIT; -PRAGMA foreign_keys = 1; +PRAGMA foreign_keys = ON; diff --git a/temoa/components/time.py b/temoa/components/time.py index 6ff862d45..364e35b11 100644 --- a/temoa/components/time.py +++ b/temoa/components/time.py @@ -139,8 +139,9 @@ def get_str_padding(obj: object) -> int: def validate_time_manual(model: TemoaModel) -> None: """ - If using this table, check that defined states are actually valid. - time_segment_fraction is already compared to other tables so just compare to segment_fraction. + If using the manual sequencing table, check that all defined states are valid. + segment_fraction keys are already validated, so we compare time_manual against those. + """ # Only check TimeNext if it is actually being used if model.time_sequencing.first() != 'manual': @@ -284,7 +285,7 @@ def create_time_sequence(model: TemoaModel) -> None: model.time_next[p, s, d] = loop_season_next_timeslice(model, p, s, d) case 'manual': # Hidden feature. Define the sequence directly in the time_manual table - msg = 'Pulling time sequence from TimeNext table.' + msg = 'Pulling time sequence from time_manual table.' for p, s, d, s_next, d_next in model.time_manual: model.time_next[p, s, d] = s_next, d_next case _: diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index 1d354ec0b..7b4bd1ec9 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -536,8 +536,9 @@ def _load_time_season( filtered_data: Sequence[tuple[object, ...]], ) -> None: """ - Loads the indexed time_season set and the simple time_season set, - with a dynamic fallback if the table is missing. + Loads time_season_all (simple set of all seasons) and time_season + (indexed set mapping periods to seasons), with a dynamic fallback + if the table is missing. """ model = TemoaModel() mi = self.myopic_index @@ -594,7 +595,7 @@ def _load_segment_fraction( self._load_component_data(data, model.segment_fraction, filtered_data) else: logger.warning( - 'No time_segment_fraction table found. Generating default segment_fraction values.' + 'No segment_fraction table found. Generating default segment_fraction values.' ) time_optimize = data.get('time_optimize', []) fallback = [(p, 'S', 'D', 1.0) for p in time_optimize] # type: ignore[attr-defined] From 0aa1e0a50fdd069592f5eedd1301fb9099bd7dfc Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Mon, 10 Nov 2025 14:34:50 -0500 Subject: [PATCH 322/587] reworking definitions to for pip install compatibility --- definitions.py | 22 ---------- temoa/_internal/run_actions.py | 44 ++----------------- temoa/_internal/table_writer.py | 9 ++-- temoa/cli.py | 2 - temoa/extensions/method_of_morris/morris.py | 8 ++-- .../method_of_morris/morris_sequencer.py | 37 ++-------------- .../mga_sequencer.py | 36 +++------------ .../tech_activity_vector_manager.py | 34 ++------------ .../example_builds/scenario_analyzer.py | 31 +------------ .../example_builds/scenario_maker.py | 29 +----------- temoa/extensions/monte_carlo/mc_run.py | 33 ++------------ temoa/extensions/monte_carlo/mc_sequencer.py | 34 +++----------- temoa/extensions/myopic/myopic_sequencer.py | 6 +-- tests/conftest.py | 19 ++++---- tests/test_linked_tech.py | 28 +----------- tests/test_material_results.py | 13 +++--- tests/test_model.py | 7 ++- tests/test_set_consistency.py | 3 +- .../utilities/capture_set_sizes_for_cache.py | 31 ++----------- .../utilities/capture_set_values_for_cache.py | 39 +++------------- 20 files changed, 73 insertions(+), 392 deletions(-) delete mode 100644 definitions.py diff --git a/definitions.py b/definitions.py deleted file mode 100644 index 908b109a4..000000000 --- a/definitions.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -top-level folder to provide project-wide definitions & references -""" - -import os -from pathlib import Path - -PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) - -OUTPUT_PATH: Path | None = None - - -def get_OUTPUT_PATH() -> Path: - if OUTPUT_PATH is None: - raise RuntimeError('Output path not yet defined') - # Use cast to help mypy understand the type - return OUTPUT_PATH - - -def set_OUTPUT_PATH(path: Path) -> None: - global OUTPUT_PATH - OUTPUT_PATH = path diff --git a/temoa/_internal/run_actions.py b/temoa/_internal/run_actions.py index 9815495e1..a11b3ff32 100644 --- a/temoa/_internal/run_actions.py +++ b/temoa/_internal/run_actions.py @@ -1,32 +1,7 @@ """ Basic-level atomic functions that can be used by a sequencer, as needed - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 11/15/23 - -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . """ -import os import sqlite3 import sys from logging import getLogger @@ -46,7 +21,6 @@ ) from pyomo.opt import SolverResults -import definitions from temoa._internal.table_writer import TableWriter from temoa.core.config import TemoaConfig from temoa.core.model import TemoaModel @@ -157,21 +131,9 @@ def build_instance( if not silent: try: # Check for warnings in log file to notify user. Ugly but it works - log_file = os.path.join(definitions.get_OUTPUT_PATH(), 'log.log') - with open(log_file) as f: - warnings_found = any( - '| WARNING |' in line or '| ERROR |' in line or '| CRITICAL |' in line - for line in f - ) - if warnings_found: - sys.stderr.write( - '\r[%8.2f] Instance created with warnings. Check log file.\n' - % (time() - hack) - ) - else: - sys.stderr.write( - '\r[%8.2f] Instance created. \n' % (time() - hack) - ) # needs spaces to clear previous line + sys.stderr.write( + '\r[%8.2f] Instance created. \n' % (time() - hack) + ) # needs spaces to clear previous line sys.stderr.flush() except Exception: sys.stderr.write( diff --git a/temoa/_internal/table_writer.py b/temoa/_internal/table_writer.py index 48ddc55c1..98a49cbd8 100644 --- a/temoa/_internal/table_writer.py +++ b/temoa/_internal/table_writer.py @@ -6,6 +6,7 @@ import sys from collections import defaultdict from collections.abc import Iterable +from importlib import resources from logging import getLogger from pathlib import Path from typing import TYPE_CHECKING, cast @@ -13,7 +14,6 @@ from pyomo.core import value from pyomo.opt import SolverResults -from definitions import PROJECT_ROOT from temoa._internal.data_brick import DataBrick from temoa._internal.exchange_tech_cost_ledger import CostType from temoa._internal.table_data_puller import ( @@ -85,10 +85,11 @@ ] optional_output_tables = ['output_flow_out_summary', 'output_mc_delta', 'output_storage_level'] -flow_summary_file_loc = Path( - PROJECT_ROOT, 'temoa/extensions/modeling_to_generate_alternatives/make_flow_summary_table.sql' +flow_summary_file_loc = ( + resources.files('temoa.extensions.modeling_to_generate_alternatives') + / 'make_flow_summary_table.sql' ) -mc_tweaks_file_loc = Path(PROJECT_ROOT, 'temoa/extensions/monte_carlo/make_deltas_table.sql') +mc_tweaks_file_loc = resources.files('temoa.extensions.monte_carlo') / 'make_deltas_table.sql' class TableWriter: diff --git a/temoa/cli.py b/temoa/cli.py index a69456e0f..79036b8fb 100644 --- a/temoa/cli.py +++ b/temoa/cli.py @@ -8,7 +8,6 @@ from rich.logging import RichHandler from rich.text import Text -from definitions import set_OUTPUT_PATH from temoa._internal.temoa_sequencer import TemoaSequencer from temoa.core.config import TemoaConfig from temoa.core.modes import TemoaMode @@ -87,7 +86,6 @@ def _setup_sequencer( # Pass the silent flag to the logging setup _setup_logging(final_output_path, debug=debug, silent=silent) - set_OUTPUT_PATH(final_output_path) config = TemoaConfig.build_config( config_file=config_file, output_path=final_output_path, silent=silent ) diff --git a/temoa/extensions/method_of_morris/morris.py b/temoa/extensions/method_of_morris/morris.py index 0351a3189..e82f116bb 100644 --- a/temoa/extensions/method_of_morris/morris.py +++ b/temoa/extensions/method_of_morris/morris.py @@ -1,10 +1,10 @@ # from __future__ import division import time +from importlib import resources from pathlib import Path from pyomo.dataportal import DataPortal -from definitions import PROJECT_ROOT from temoa._internal import run_actions from temoa._internal.table_writer import TableWriter from temoa.core.config import TemoaConfig @@ -63,11 +63,11 @@ def evaluate(param_names, param_values, data: dict, k): return Morris_Objectives -morris_root = Path(PROJECT_ROOT, 'temoa/extensions/method_of_morris') +morris_root = Path(__file__).parent perturbation_coefficient = 0.2 # minus plus 10% of the baseline values param_file = morris_root / 'm_params.txt' -db_file = Path(PROJECT_ROOT, 'data_files/untracked_data/morris/morris_utopia.sqlite') -config_path = Path(PROJECT_ROOT, 'data_files/untracked_data/morris/morris_utopia.toml') +db_file = resources.files('data_files.untracked_data.morris') / 'morris_utopia.sqlite' +config_path = resources.files('data_files.untracked_data.morris') / 'morris_utopia.toml' with sqlite3.connect(db_file) as con: with open(param_file, 'w') as file: param_names = {} diff --git a/temoa/extensions/method_of_morris/morris_sequencer.py b/temoa/extensions/method_of_morris/morris_sequencer.py index 9f41f98fe..53b9026e4 100644 --- a/temoa/extensions/method_of_morris/morris_sequencer.py +++ b/temoa/extensions/method_of_morris/morris_sequencer.py @@ -1,35 +1,6 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - -This code is modified from original work on Method of Morris framework -by Hadi Eshragi. Original morris.py file can be located in the energysystem -branch - -Modified/Refactored by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 5/30/24 - An event sequencer to control the flow of a Method of Morris calculation. This code uses multiprocessing via the joblib library - """ import csv @@ -39,6 +10,7 @@ import sys import tomllib from logging.handlers import QueueListener +from importlib import resources from pathlib import Path from joblib import Parallel, delayed @@ -47,7 +19,6 @@ from SALib.sample.morris import sample from SALib.util import compute_groups_matrix, read_param_file -from definitions import PROJECT_ROOT, get_OUTPUT_PATH from temoa._internal.table_writer import TableWriter from temoa.core.config import TemoaConfig from temoa.data_io.hybrid_loader import HybridLoader @@ -55,8 +26,8 @@ logger = logging.getLogger(__name__) -solver_options_file = Path( - PROJECT_ROOT, 'temoa/extensions/method_of_morris/morris_solver_options.toml' +solver_options_file = ( + resources.files('temoa.extensions.method_of_morris') / 'morris_solver_options.toml' ) @@ -98,7 +69,7 @@ def __init__(self, config: TemoaConfig): # output handling self.verbose = False # for troubleshooting - self.mm_output_folder = get_OUTPUT_PATH() / 'MM_outputs' + self.mm_output_folder = self.config.output_path / 'MM_outputs' self.mm_output_folder.mkdir(exist_ok=True) self.param_file: Path = self.mm_output_folder / 'params.csv' diff --git a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py index bda3cf224..104691e76 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py +++ b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py @@ -1,30 +1,5 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 4/15/24 - -The purpose of this module is to perform top-level control over an MGA model run +Performs top-level control over an MGA model run """ import logging @@ -35,6 +10,7 @@ from datetime import datetime from logging import getLogger from multiprocessing import Queue +from importlib import resources from pathlib import Path from queue import Empty @@ -43,7 +19,6 @@ from pyomo.dataportal import DataPortal from pyomo.opt import check_optimal_termination -from definitions import PROJECT_ROOT, get_OUTPUT_PATH from temoa._internal.run_actions import build_instance from temoa._internal.table_writer import TableWriter from temoa.components.costs import total_cost_rule @@ -58,8 +33,8 @@ logger = getLogger(__name__) -solver_options_path = Path( - PROJECT_ROOT, 'temoa/extensions/modeling_to_generate_alternatives/MGA_solver_options.toml' +solver_options_path = ( + resources.files('temoa.extensions.modeling_to_generate_alternatives') / 'MGA_solver_options.toml' ) @@ -208,6 +183,7 @@ def start(self): con=self.con, optimal_cost=tot_cost, cost_relaxation=self.cost_epsilon, + config=self.config, ) # 5. Set up the Workers @@ -224,7 +200,7 @@ def start(self): 'solver_options': self.worker_solver_options, } # construct path for the solver logs - s_path = Path(get_OUTPUT_PATH(), 'solver_logs') + s_path = self.config.output_path / 'solver_logs' if not s_path.exists(): s_path.mkdir() for _ in range(num_workers): diff --git a/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py b/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py index 0828dc3a7..8e28f7a75 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py +++ b/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py @@ -1,31 +1,3 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 4/16/24 - -""" - import queue import sqlite3 from collections import defaultdict @@ -38,7 +10,7 @@ from matplotlib import pyplot as plt from pyomo.core import Expression, Objective, Var, quicksum, value -from definitions import get_OUTPUT_PATH +from temoa.core.config import TemoaConfig from temoa.core.model import TemoaModel from temoa.extensions.modeling_to_generate_alternatives.hull import Hull from temoa.extensions.modeling_to_generate_alternatives.mga_constants import MgaWeighting @@ -73,12 +45,14 @@ def __init__( weighting: MgaWeighting, optimal_cost: float, cost_relaxation: float, + config: TemoaConfig, ): self.completed_solves = 0 self.conn = conn self.base_model = base_model self.optimal_cost = optimal_cost self.cost_relaxation = cost_relaxation + self.config = config self.generation_index = 1 # index of how many models generated to couple inputs-outputs # {category : [technology, ...]} @@ -362,7 +336,7 @@ def tracker(self): self.perf_data.update({len(self.hull_points): volume}) def finalize_tracker(self): - fout = Path(get_OUTPUT_PATH(), 'hull_performance.png') + fout = self.config.output_path / 'hull_performance.png' pts = sorted(self.perf_data.keys()) y = [self.perf_data[pt] for pt in pts] plt.plot(pts, y) diff --git a/temoa/extensions/monte_carlo/example_builds/scenario_analyzer.py b/temoa/extensions/monte_carlo/example_builds/scenario_analyzer.py index 9d6ba05f9..03f87a80e 100644 --- a/temoa/extensions/monte_carlo/example_builds/scenario_analyzer.py +++ b/temoa/extensions/monte_carlo/example_builds/scenario_analyzer.py @@ -1,42 +1,15 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 11/11/24 - Simple analyzer--example only - """ from math import sqrt from pathlib import Path from sqlite3 import Connection +from importlib import resources from matplotlib import pyplot as plt -from definitions import PROJECT_ROOT - scenario_name = 'Purple Onion' # must match config file -db_path = Path(PROJECT_ROOT, 'data_files/example_dbs/utopia.sqlite') +db_path = resources.files('data_files.example_dbs') / 'utopia.sqlite' with Connection(db_path) as conn: cur = conn.cursor() obj_values = cur.execute( diff --git a/temoa/extensions/monte_carlo/example_builds/scenario_maker.py b/temoa/extensions/monte_carlo/example_builds/scenario_maker.py index 0768b3fd5..e79b915fc 100644 --- a/temoa/extensions/monte_carlo/example_builds/scenario_maker.py +++ b/temoa/extensions/monte_carlo/example_builds/scenario_maker.py @@ -1,28 +1,4 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 11/11/24 This file is intended to be a simple EXAMPLE for testing mainly of how one might make a set of runs for a Monte Carlo simulation. @@ -45,10 +21,9 @@ from pathlib import Path import matplotlib.pyplot as plt +from importlib import resources import numpy as np -from definitions import PROJECT_ROOT - # distro for the related cost vars # multivariate norm generator: @@ -69,7 +44,7 @@ nuc_dev = np.random.binomial(n=1, p=0.20, size=num_runs) * -0.4 # put it together... -file_loc = Path(PROJECT_ROOT) / 'data_files/monte_carlo/run_settings_2.csv' +file_loc = resources.files('data_files.monte_carlo') / 'run_settings_2.csv' with open(file_loc, 'w') as f: f.write('run,param,index,mod,value,notes\n') for run_idx in range(num_runs): diff --git a/temoa/extensions/monte_carlo/mc_run.py b/temoa/extensions/monte_carlo/mc_run.py index 537bea1fd..a57ba3c9f 100644 --- a/temoa/extensions/monte_carlo/mc_run.py +++ b/temoa/extensions/monte_carlo/mc_run.py @@ -1,28 +1,4 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 11/9/24 """ @@ -34,7 +10,6 @@ from pyomo.dataportal import DataPortal -from definitions import PROJECT_ROOT from temoa.core.config import TemoaConfig from temoa.core.model import TemoaModel from temoa.data_io.hybrid_loader import HybridLoader @@ -222,14 +197,14 @@ def __init__(self, config: TemoaConfig, data_store: dict): self.config = config self.data_store = data_store self.tweak_factory = TweakFactory(data_store) - self.settings_file = PROJECT_ROOT / Path(self.config.monte_carlo_inputs['run_settings']) + self.settings_file = Path(self.config.monte_carlo_inputs['run_settings']) def prescreen_input_file(self): """ read the input csv file and screen common errors :return: True if file passes, false otherwise with log entries """ - with open(self.settings_file, 'r') as f: + with open(self.settings_file) as f: header = f.readline().strip() assert header == 'run,param,index,mod,value,notes', ( 'header should be: run,param,index,mod,value,notes' @@ -252,7 +227,7 @@ def _next_row_generator(self) -> Generator[tuple[int, str], None, None]: A generator to read lines from thr run settings file :return: """ - with open(self.settings_file, 'r') as f: + with open(self.settings_file) as f: # burn header f.readline() idx = 2 @@ -314,7 +289,7 @@ def element_locator(data_store: dict, param: str, target_index: tuple) -> list[t matches = [ k for k in raw_indices - if all((k[idx] == target_index[idx] for idx in non_wildcard_locs)) + if all(k[idx] == target_index[idx] for idx in non_wildcard_locs) ] return matches diff --git a/temoa/extensions/monte_carlo/mc_sequencer.py b/temoa/extensions/monte_carlo/mc_sequencer.py index 44945f68d..59112ed76 100644 --- a/temoa/extensions/monte_carlo/mc_sequencer.py +++ b/temoa/extensions/monte_carlo/mc_sequencer.py @@ -1,31 +1,7 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 11/9/24 A sequencer for Monte Carlo Runs -. + """ import logging @@ -36,11 +12,11 @@ from datetime import datetime from logging import getLogger from multiprocessing import Queue +from importlib import resources from pathlib import Path from pyomo.dataportal import DataPortal -from definitions import PROJECT_ROOT, get_OUTPUT_PATH from temoa._internal.data_brick import DataBrick from temoa._internal.table_writer import TableWriter from temoa.core.config import TemoaConfig @@ -50,7 +26,9 @@ logger = getLogger(__name__) -solver_options_path = Path(PROJECT_ROOT, 'temoa/extensions/monte_carlo/MC_solver_options.toml') +solver_options_path = ( + resources.files('temoa.extensions.monte_carlo') / 'MC_solver_options.toml' +) class MCSequencer: @@ -130,7 +108,7 @@ def start(self): 'solver_options': self.worker_solver_options, } # construct path for the solver logs - s_path = Path(get_OUTPUT_PATH(), 'solver_logs') + s_path = self.config.output_path / 'solver_logs' if not s_path.exists(): s_path.mkdir() for i in range(num_workers): diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index 6e7558147..ec05813ee 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -7,10 +7,10 @@ import sqlite3 import sys from collections import deque +from importlib import resources from pathlib import Path from sqlite3 import Connection -import definitions from temoa._internal import run_actions from temoa._internal.table_writer import TableWriter from temoa.core.config import TemoaConfig @@ -23,9 +23,7 @@ logger = logging.getLogger(__name__) -table_script_file = Path( - definitions.PROJECT_ROOT, 'temoa/extensions/myopic', 'make_myopic_tables.sql' -) +table_script_file = resources.files('temoa.extensions.myopic') / 'make_myopic_tables.sql' class MyopicSequencer: diff --git a/tests/conftest.py b/tests/conftest.py index dbc332e3e..0e405a521 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7,7 +7,6 @@ import pytest from pyomo.opt import SolverResults -from definitions import PROJECT_ROOT, set_OUTPUT_PATH from temoa._internal.temoa_sequencer import TemoaSequencer from temoa.core.config import TemoaConfig from temoa.core.model import TemoaModel @@ -15,14 +14,14 @@ logger = logging.getLogger(__name__) # set the target folder for output from testing -output_path = os.path.join(PROJECT_ROOT, 'tests', 'testing_log') -if not os.path.exists(output_path): - os.mkdir(output_path) +output_path = Path(__file__).parent / 'testing_log' +if not output_path.exists(): + output_path.mkdir() # set up logger in conftest.py so that it is properly anchored in the test folder. filename = 'testing.log' logging.basicConfig( - filename=os.path.join(output_path, filename), + filename=output_path / filename, filemode='w', format='%(asctime)s | %(module)s | %(levelname)s | %(message)s', datefmt='%d-%b-%y %H:%M:%S', @@ -36,8 +35,8 @@ def refresh_databases() -> None: """make new databases from source for testing... removes possibility of contamination by earlier runs""" - data_output_path = Path(PROJECT_ROOT, 'tests', 'testing_outputs') - data_source_path = Path(PROJECT_ROOT, 'tests', 'testing_data') + data_output_path = Path(__file__).parent / 'testing_outputs' + data_source_path = Path(__file__).parent / 'testing_data' databases = ( ('utopia.sql', 'utopia.sqlite'), ('utopia.sql', 'myo_utopia.sqlite'), @@ -66,7 +65,7 @@ def refresh_databases() -> None: @pytest.fixture() def system_test_run( - request, tmp_path + request: Any, tmp_path: Path ) -> tuple[Any, SolverResults | None, TemoaModel | None, TemoaSequencer]: """ spin up the model, solve it, and hand over the model and result for inspection @@ -74,9 +73,7 @@ def system_test_run( data_name = request.param['name'] logger.info('Setting up and solving: %s', data_name) filename = request.param['filename'] - config_file = Path(PROJECT_ROOT, 'tests', 'testing_configs', filename) - - set_OUTPUT_PATH(tmp_path) + config_file = Path(__file__).parent / 'testing_configs' / filename config = TemoaConfig.build_config( config_file=config_file, diff --git a/tests/test_linked_tech.py b/tests/test_linked_tech.py index c174a05cd..cfa66240b 100644 --- a/tests/test_linked_tech.py +++ b/tests/test_linked_tech.py @@ -1,28 +1,4 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 6/22/24 A quick test on Linked Tech. The scenario is described in an image in the testing_data folder: simple_linked_tech_description.jpg @@ -35,8 +11,6 @@ import pytest -from definitions import PROJECT_ROOT - logger = logging.getLogger(__name__) config_files = [ {'name': 'link', 'filename': 'config_link_test.toml'}, @@ -53,7 +27,7 @@ def test_linked_tech(system_test_run): """Check a few known values. See the note above in header regarding scenario reference""" data_name, res, mdl, _ = system_test_run # test emission of CO2 - output_db_path = Path(PROJECT_ROOT, 'tests', 'testing_outputs', 'simple_linked_tech.sqlite') + output_db_path = Path(__file__).parent / 'testing_outputs' / 'simple_linked_tech.sqlite' print(output_db_path) conn = sqlite3.connect(str(output_db_path)) co2_emiss = conn.execute( diff --git a/tests/test_material_results.py b/tests/test_material_results.py index 1c00e8cf1..c292ac57b 100644 --- a/tests/test_material_results.py +++ b/tests/test_material_results.py @@ -1,10 +1,11 @@ import logging import sqlite3 +from collections.abc import Generator from pathlib import Path +from typing import Any import pytest -from definitions import PROJECT_ROOT from temoa._internal.temoa_sequencer import TemoaSequencer from temoa.core.config import TemoaConfig @@ -12,14 +13,16 @@ @pytest.fixture(scope='module') -def solved_connection(request, tmp_path_factory): +def solved_connection( + request: Any, tmp_path_factory: Any +) -> Generator[tuple[sqlite3.Connection, str, str, int, float], None, None]: """ spin up the model, solve it, and hand over a connection to the results db """ data_name = 'materials' logger.info('Setting up and solving: %s', data_name) filename = 'config_materials.toml' - config_file = Path(PROJECT_ROOT, 'tests', 'testing_configs', filename) + config_file = Path(__file__).parent / 'testing_configs' / filename tmp_path = tmp_path_factory.mktemp('data') config = TemoaConfig.build_config(config_file=config_file, output_path=tmp_path, silent=True) sequencer = TemoaSequencer(config=config) @@ -51,9 +54,9 @@ def solved_connection(request, tmp_path_factory): 'solved_connection', argvalues=flow_tests, indirect=True, - ids=[t['name'] for t in flow_tests], + ids=[str(t['name']) for t in flow_tests], ) -def test_flows(solved_connection): +def test_flows(solved_connection: tuple[sqlite3.Connection, str, str, int, float]) -> None: """ Test that the emissions from each technology archetype are correct, and check total emissions """ diff --git a/tests/test_model.py b/tests/test_model.py index 35cfaf6fc..5692333d6 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -5,20 +5,19 @@ import pathlib import pickle -from definitions import PROJECT_ROOT from temoa._internal.temoa_sequencer import TemoaSequencer from temoa.core.config import TemoaConfig from temoa.core.modes import TemoaMode -def test_serialization(): +def test_serialization() -> None: """ Test to ensure the model pickles properly. This is used when employing mpi4py which requires that jobs passed are pickle-able. """ config_filename = 'config_utopia.toml' - config_file_path = pathlib.Path(PROJECT_ROOT, 'tests', 'testing_configs', config_filename) - output_path = pathlib.Path(PROJECT_ROOT, 'tests', 'testing_outputs') + config_file_path = pathlib.Path(__file__).parent / 'testing_configs' / config_filename + output_path = pathlib.Path(__file__).parent / 'testing_outputs' config = TemoaConfig.build_config( config_file=config_file_path, output_path=output_path, silent=True diff --git a/tests/test_set_consistency.py b/tests/test_set_consistency.py index e92efbe7d..52444914b 100644 --- a/tests/test_set_consistency.py +++ b/tests/test_set_consistency.py @@ -9,7 +9,6 @@ import pytest from pyomo import environ as pyo -from definitions import PROJECT_ROOT from temoa._internal.temoa_sequencer import TemoaSequencer from temoa.core.config import TemoaConfig from temoa.core.modes import TemoaMode @@ -44,7 +43,7 @@ def test_set_consistency(data_name, config_file, set_file, tmp_path): model_sets = {k: set(v) for k, v in model_sets.items()} # retrieve the cache and convert the set values from list -> set (json can't store sets) - cache_file = pathlib.Path(PROJECT_ROOT, 'tests', 'testing_data', set_file) + cache_file = pathlib.Path(__file__).parent / 'testing_data' / set_file with open(cache_file) as src: cached_sets = json.load(src) cached_sets = { diff --git a/tests/utilities/capture_set_sizes_for_cache.py b/tests/utilities/capture_set_sizes_for_cache.py index 900d4536c..cfe0ad465 100644 --- a/tests/utilities/capture_set_sizes_for_cache.py +++ b/tests/utilities/capture_set_sizes_for_cache.py @@ -1,29 +1,5 @@ """ Utility to capture the set sizes for inspection/comparison - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 11/14/23 - -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . """ import json @@ -33,7 +9,6 @@ import pyomo.environ as pyo -from definitions import PROJECT_ROOT from temoa._internal.temoa_sequencer import TemoaSequencer logger = logging.getLogger(__name__) @@ -47,11 +22,11 @@ t = input('Type "Y" to continue, any other key to exit now.') if t not in {'y', 'Y'}: sys.exit(0) -output_file = Path(PROJECT_ROOT, 'tests', 'testing_data', 'US_9R_8D_set_sizes.json') -config_file = Path(PROJECT_ROOT, 'tests', 'utilities', 'config_US_9R_8D.toml') +output_file = Path(__file__).parent.parent / 'testing_data' / 'US_9R_8D_set_sizes.json' +config_file = Path(__file__).parent / 'config_US_9R_8D.toml' options = {'silent': True, 'debug': True} sequencer = TemoaSequencer( - config_file=config_file, output_path=Path(PROJECT_ROOT, 'tests', 'testing_log'), **options + config_file=config_file, output_path=Path(__file__).parent.parent / 'testing_log', **options ) instance = sequencer.start() diff --git a/tests/utilities/capture_set_values_for_cache.py b/tests/utilities/capture_set_values_for_cache.py index 36926f080..c7991bed0 100644 --- a/tests/utilities/capture_set_values_for_cache.py +++ b/tests/utilities/capture_set_values_for_cache.py @@ -2,30 +2,6 @@ Quick utility to capture set values from a pyomo model to enable later comparison. This file should not need to be run again unless model schema changes - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 8/26/23 - -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . """ import json @@ -34,7 +10,6 @@ import pyomo.environ as pyo -from definitions import PROJECT_ROOT from temoa._internal.temoa_sequencer import TemoaSequencer from tests.conftest import refresh_databases @@ -52,20 +27,20 @@ if t not in {'y', 'Y'}: sys.exit(0) -output_path = Path(PROJECT_ROOT, 'tests', 'testing_log') # capture the log here +output_path = Path(__file__).parent.parent / 'testing_log' # capture the log here scenarios = [ { - 'output_file': Path(PROJECT_ROOT, 'tests', 'testing_data', 'utopia_sets.json'), - 'config_file': Path(PROJECT_ROOT, 'tests', 'utilities', 'config_utopia.toml'), + 'output_file': Path(__file__).parent.parent / 'testing_data' / 'utopia_sets.json', + 'config_file': Path(__file__).parent / 'config_utopia.toml', }, { - 'output_file': Path(PROJECT_ROOT, 'tests', 'testing_data', 'test_system_sets.json'), - 'config_file': Path(PROJECT_ROOT, 'tests', 'utilities', 'config_test_system.toml'), + 'output_file': Path(__file__).parent.parent / 'testing_data' / 'test_system_sets.json', + 'config_file': Path(__file__).parent / 'config_test_system.toml', }, { - 'output_file': Path(PROJECT_ROOT, 'tests', 'testing_data', 'mediumville_sets.json'), - 'config_file': Path(PROJECT_ROOT, 'tests', 'utilities', 'config_mediumville.toml'), + 'output_file': Path(__file__).parent.parent / 'testing_data' / 'mediumville_sets.json', + 'config_file': Path(__file__).parent / 'config_mediumville.toml', }, ] # make new copies of the DB's from source... From da6341d471ce4d4b5228a9acfeee21956f969462 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 11 Nov 2025 14:47:35 -0500 Subject: [PATCH 323/587] fixing possible traversable to path mapping issues --- temoa/_internal/table_writer.py | 35 +++++-------------- temoa/extensions/method_of_morris/morris.py | 9 +++-- .../method_of_morris/morris_sequencer.py | 5 +-- .../mga_sequencer.py | 5 +-- .../example_builds/scenario_analyzer.py | 4 +-- .../example_builds/scenario_maker.py | 3 +- temoa/extensions/monte_carlo/mc_sequencer.py | 5 +-- temoa/extensions/myopic/myopic_sequencer.py | 3 +- .../utilities/capture_set_sizes_for_cache.py | 13 ++++--- .../utilities/capture_set_values_for_cache.py | 8 +++-- 10 files changed, 42 insertions(+), 48 deletions(-) diff --git a/temoa/_internal/table_writer.py b/temoa/_internal/table_writer.py index 98a49cbd8..d58d0ad3b 100644 --- a/temoa/_internal/table_writer.py +++ b/temoa/_internal/table_writer.py @@ -2,6 +2,8 @@ tool for writing outputs to database tables """ +from __future__ import annotations + import sqlite3 import sys from collections import defaultdict @@ -39,30 +41,6 @@ pass """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 2/9/24 Note: This file borrows heavily from the legacy pformat_results.py, and is somewhat of a restructure of that code to accommodate the run modes more cleanly @@ -653,13 +631,16 @@ def make_mc_tweaks_table(self) -> None: # make the table for monte carlo tweaks, if needed... self.execute_script(mc_tweaks_file_loc) - def execute_script(self, script_file: str | Path) -> None: + def execute_script(self, script_file: str | Path | resources.abc.Traversable) -> None: """ A utility to execute a sql script on the current db connection :return: """ - with open(script_file) as table_script: - sql_commands = table_script.read() + if isinstance(script_file, resources.abc.Traversable): + sql_commands = script_file.read_text() + else: + with open(script_file) as table_script: + sql_commands = table_script.read() logger.debug('Executing sql from file: %s ', script_file) self.con.executescript(sql_commands) diff --git a/temoa/extensions/method_of_morris/morris.py b/temoa/extensions/method_of_morris/morris.py index e82f116bb..e8116ca34 100644 --- a/temoa/extensions/method_of_morris/morris.py +++ b/temoa/extensions/method_of_morris/morris.py @@ -66,9 +66,12 @@ def evaluate(param_names, param_values, data: dict, k): morris_root = Path(__file__).parent perturbation_coefficient = 0.2 # minus plus 10% of the baseline values param_file = morris_root / 'm_params.txt' -db_file = resources.files('data_files.untracked_data.morris') / 'morris_utopia.sqlite' -config_path = resources.files('data_files.untracked_data.morris') / 'morris_utopia.toml' -with sqlite3.connect(db_file) as con: + +db_resource = resources.files('data_files.untracked_data.morris') / 'morris_utopia.sqlite' +config_resource = resources.files('data_files.untracked_data.morris') / 'morris_utopia.toml' +with resources.as_file(db_resource) as db_file, \ + resources.as_file(config_resource) as config_path, \ + sqlite3.connect(str(db_file)) as con: with open(param_file, 'w') as file: param_names = {} cur = con.cursor() diff --git a/temoa/extensions/method_of_morris/morris_sequencer.py b/temoa/extensions/method_of_morris/morris_sequencer.py index 53b9026e4..c788028c8 100644 --- a/temoa/extensions/method_of_morris/morris_sequencer.py +++ b/temoa/extensions/method_of_morris/morris_sequencer.py @@ -58,8 +58,9 @@ def __init__(self, config: TemoaConfig): # read in the options try: - with open(solver_options_file, 'rb') as f: - all_options = tomllib.load(f) + with resources.as_file(solver_options_file) as path: + with open(path, 'rb') as f: + all_options = tomllib.load(f) s_options = all_options.get(self.config.solver_name, {}) logger.info('Using solver options: %s', s_options) diff --git a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py index 104691e76..2b9e49a40 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py +++ b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py @@ -63,8 +63,9 @@ def __init__(self, config: TemoaConfig): # read in the options try: - with open(solver_options_path, 'rb') as f: - all_options = tomllib.load(f) + with resources.as_file(solver_options_path) as path: + with open(path, 'rb') as f: + all_options = tomllib.load(f) s_options = all_options.get(self.config.solver_name, {}) logger.info('Using solver options: %s', s_options) diff --git a/temoa/extensions/monte_carlo/example_builds/scenario_analyzer.py b/temoa/extensions/monte_carlo/example_builds/scenario_analyzer.py index 03f87a80e..ba55b0fb2 100644 --- a/temoa/extensions/monte_carlo/example_builds/scenario_analyzer.py +++ b/temoa/extensions/monte_carlo/example_builds/scenario_analyzer.py @@ -9,8 +9,8 @@ from matplotlib import pyplot as plt scenario_name = 'Purple Onion' # must match config file -db_path = resources.files('data_files.example_dbs') / 'utopia.sqlite' -with Connection(db_path) as conn: +db_resource = resources.files('data_files.example_dbs') / 'utopia.sqlite' +with resources.as_file(db_resource) as db_path, Connection(str(db_path)) as conn: cur = conn.cursor() obj_values = cur.execute( f"SELECT total_system_cost FROM output_objective WHERE scenario LIKE '{scenario_name}-%'" diff --git a/temoa/extensions/monte_carlo/example_builds/scenario_maker.py b/temoa/extensions/monte_carlo/example_builds/scenario_maker.py index e79b915fc..7f6217771 100644 --- a/temoa/extensions/monte_carlo/example_builds/scenario_maker.py +++ b/temoa/extensions/monte_carlo/example_builds/scenario_maker.py @@ -21,7 +21,6 @@ from pathlib import Path import matplotlib.pyplot as plt -from importlib import resources import numpy as np # distro for the related cost vars @@ -44,7 +43,7 @@ nuc_dev = np.random.binomial(n=1, p=0.20, size=num_runs) * -0.4 # put it together... -file_loc = resources.files('data_files.monte_carlo') / 'run_settings_2.csv' +file_loc = Path.cwd() / 'run_settings_2.csv' with open(file_loc, 'w') as f: f.write('run,param,index,mod,value,notes\n') for run_idx in range(num_runs): diff --git a/temoa/extensions/monte_carlo/mc_sequencer.py b/temoa/extensions/monte_carlo/mc_sequencer.py index 59112ed76..e59851790 100644 --- a/temoa/extensions/monte_carlo/mc_sequencer.py +++ b/temoa/extensions/monte_carlo/mc_sequencer.py @@ -41,8 +41,9 @@ def __init__(self, config: TemoaConfig): # read in the options try: - with open(solver_options_path, 'rb') as f: - all_options = tomllib.load(f) + with resources.as_file(solver_options_path) as path: + with open(path, 'rb') as f: + all_options = tomllib.load(f) s_options = all_options.get(self.config.solver_name, {}) logger.info('Using solver options: %s', s_options) diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index ec05813ee..c0877bf26 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -139,7 +139,8 @@ def start(self): self.characterize_run() # create the Myopic Output tables, if they don't already exist. - self.execute_script(table_script_file) + with resources.as_file(table_script_file) as script_path: + self.execute_script(script_path) # clear out the old riff-raff self.clear_old_results() diff --git a/tests/utilities/capture_set_sizes_for_cache.py b/tests/utilities/capture_set_sizes_for_cache.py index cfe0ad465..83620f4d5 100644 --- a/tests/utilities/capture_set_sizes_for_cache.py +++ b/tests/utilities/capture_set_sizes_for_cache.py @@ -10,6 +10,7 @@ import pyomo.environ as pyo from temoa._internal.temoa_sequencer import TemoaSequencer +from temoa.core.config import TemoaConfig logger = logging.getLogger(__name__) @@ -23,12 +24,14 @@ if t not in {'y', 'Y'}: sys.exit(0) output_file = Path(__file__).parent.parent / 'testing_data' / 'US_9R_8D_set_sizes.json' -config_file = Path(__file__).parent / 'config_US_9R_8D.toml' -options = {'silent': True, 'debug': True} -sequencer = TemoaSequencer( - config_file=config_file, output_path=Path(__file__).parent.parent / 'testing_log', **options +config_file_path = Path(__file__).parent / 'config_US_9R_8D.toml' +output_path = Path(__file__).parent.parent / 'testing_log' +options = {'silent': True} +config = TemoaConfig.build_config( + config_file=config_file_path, output_path=output_path, silent=options['silent'] ) -instance = sequencer.start() +sequencer = TemoaSequencer(config=config) +instance = sequencer.build_model() # catch the built model model_sets = instance.component_map(ctype=pyo.Set) sets_dict = {k: len(v) for k, v in model_sets.items() if '_index' not in k} diff --git a/tests/utilities/capture_set_values_for_cache.py b/tests/utilities/capture_set_values_for_cache.py index c7991bed0..3a018206d 100644 --- a/tests/utilities/capture_set_values_for_cache.py +++ b/tests/utilities/capture_set_values_for_cache.py @@ -11,6 +11,7 @@ import pyomo.environ as pyo from temoa._internal.temoa_sequencer import TemoaSequencer +from temoa.core.config import TemoaConfig from tests.conftest import refresh_databases print( @@ -47,9 +48,12 @@ refresh_databases() for scenario in scenarios: - ts = TemoaSequencer(config_file=scenario['config_file'], output_path=output_path) + config = TemoaConfig.build_config( + config_file=scenario['config_file'], output_path=output_path, silent=True + ) + ts = TemoaSequencer(config=config) - built_instance = ts.start() # catch the built model + built_instance = ts.build_model() # catch the built model model_sets = built_instance.component_map(ctype=pyo.Set) sets_dict = {k: list(v) for k, v in model_sets.items()} From f841abaf04410f5a5b1927e09736437557de52c2 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 11 Nov 2025 16:18:06 -0500 Subject: [PATCH 324/587] adding defences for paht creation before use in testing logs --- tests/utilities/capture_set_sizes_for_cache.py | 2 ++ tests/utilities/capture_set_values_for_cache.py | 1 + 2 files changed, 3 insertions(+) diff --git a/tests/utilities/capture_set_sizes_for_cache.py b/tests/utilities/capture_set_sizes_for_cache.py index 83620f4d5..1536ff453 100644 --- a/tests/utilities/capture_set_sizes_for_cache.py +++ b/tests/utilities/capture_set_sizes_for_cache.py @@ -26,6 +26,8 @@ output_file = Path(__file__).parent.parent / 'testing_data' / 'US_9R_8D_set_sizes.json' config_file_path = Path(__file__).parent / 'config_US_9R_8D.toml' output_path = Path(__file__).parent.parent / 'testing_log' +output_path.mkdir(parents=True, exist_ok=True) + options = {'silent': True} config = TemoaConfig.build_config( config_file=config_file_path, output_path=output_path, silent=options['silent'] diff --git a/tests/utilities/capture_set_values_for_cache.py b/tests/utilities/capture_set_values_for_cache.py index 3a018206d..3c5eed984 100644 --- a/tests/utilities/capture_set_values_for_cache.py +++ b/tests/utilities/capture_set_values_for_cache.py @@ -29,6 +29,7 @@ sys.exit(0) output_path = Path(__file__).parent.parent / 'testing_log' # capture the log here +output_path.mkdir(parents=True, exist_ok=True) scenarios = [ { From 8923f7a3ce06436c6b1f3d1888e56b32629c40f7 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 12 Nov 2025 11:15:51 -0500 Subject: [PATCH 325/587] adding unstable branch to ci --- .github/workflows/ci.yml | 4 +++- FEATURE_BRANCH.md | 25 ------------------------- 2 files changed, 3 insertions(+), 26 deletions(-) delete mode 100644 FEATURE_BRANCH.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e24e9f3d1..89cf12a51 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,6 +9,7 @@ on: "ci_testing", "1.0.0-dev-operator", "temoa_davey_code", + "unstable", ] pull_request: branches: @@ -18,6 +19,7 @@ on: "ci_testing", "1.0.0-dev-operator", "temoa_davey_code", + "unstable", ] jobs: @@ -26,7 +28,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.12"] + python-version: ["3.12", "3.13"] steps: - uses: actions/checkout@v5 diff --git a/FEATURE_BRANCH.md b/FEATURE_BRANCH.md deleted file mode 100644 index 4cce535fc..000000000 --- a/FEATURE_BRANCH.md +++ /dev/null @@ -1,25 +0,0 @@ -# Library Reorganization Feature Branch - -## Overview - -Major refactoring to make TEMOA pip-installable with clean library API. - -## Current Phase - -[ ] Phase 1: Foundation -[ ] Phase 2: CLI Separation -[ ] Phase 3: Data & Configuration -[ ] Phase 4: Extensions & Testing -[ ] Phase 5: Documentation & Release - -## Testing Status - -- [ ] Core model tests pass -- [ ] CLI tests pass -- [ ] Extension tests pass -- [ ] Integration tests pass - -## Known Issues - -- [ ] Import path changes may break existing code -- [ ] Need to update CI/CD configuration From 3c0615ebe8df2529305de1277cbfb4984c3f425c Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 13 Nov 2025 12:25:18 -0500 Subject: [PATCH 326/587] adding readthedocs file --- .gitignore | 1 + .readthedocs.yaml | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 .readthedocs.yaml diff --git a/.gitignore b/.gitignore index 052fcc0b5..47190a980 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ !CHANGELOG.md !CONTRIBUTING.md !.pre-commit-config.yaml +!.readthedocs.yaml !.coderabbit.yaml !CITATION.cff diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 000000000..8fd13ec63 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,22 @@ +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the OS, Python version, and other tools you might need +build: + os: ubuntu-24.04 + tools: + python: "3.13" + +# Build documentation in the "docs/" directory with Sphinx +sphinx: + configuration: docs/source/conf.py + +python: + install: + - method: pip + path: . + extra_requirements: + - docs From a8b0df41ec01a8d6b441adb3ba15107c617810e6 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 13 Nov 2025 13:16:22 -0500 Subject: [PATCH 327/587] adding database migrators to the cli --- data_files/temoa_schema_v3_1.sql | 4 +- pyproject.toml | 8 + temoa/cli.py | 201 ++++- temoa/db_schema/temoa_schema_v3.sql | 919 ++++++++++++++++++++ temoa/db_schema/temoa_schema_v3_1.sql | 1057 +++++++++++++++++++++++ temoa/db_schema/temoa_schema_v4.sql | 1112 +++++++++++++++++++++++++ tests/test_cli.py | 268 +++++- 7 files changed, 3559 insertions(+), 10 deletions(-) create mode 100644 temoa/db_schema/temoa_schema_v3.sql create mode 100644 temoa/db_schema/temoa_schema_v3_1.sql create mode 100644 temoa/db_schema/temoa_schema_v4.sql diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index 7626b3791..b91d03ce5 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -873,7 +873,7 @@ CREATE TABLE IF NOT EXISTS ReserveCapacityDerate CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE IF NOT EXISTS TimeSegmentFraction -( +( period INTEGER REFERENCES TimePeriod (period), season TEXT @@ -1054,4 +1054,4 @@ CREATE TABLE IF NOT EXISTS OutputCost FOREIGN KEY (tech) REFERENCES Technology (tech) ); COMMIT; -PRAGMA FOREIGN_KEYS = 1; \ No newline at end of file +PRAGMA FOREIGN_KEYS = 1; diff --git a/pyproject.toml b/pyproject.toml index 5a7e4d548..398ba8561 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,6 +69,14 @@ solver = [ requires = ["hatchling"] build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +include = [ + "temoa", +] +package-data = { "temoa" = ["db_schema/*.sql"] } + + [tool.ruff] line-length = 100 indent-width = 4 diff --git a/temoa/cli.py b/temoa/cli.py index 79036b8fb..417934207 100644 --- a/temoa/cli.py +++ b/temoa/cli.py @@ -1,5 +1,7 @@ +import argparse import logging -from datetime import datetime +from datetime import datetime, timezone +from importlib import resources from pathlib import Path from typing import Annotated @@ -11,6 +13,7 @@ from temoa._internal.temoa_sequencer import TemoaSequencer from temoa.core.config import TemoaConfig from temoa.core.modes import TemoaMode +from temoa.utilities import db_migration_v3_1_to_v4, sql_migration_v3_1_to_v4 from temoa.version_information import TEMOA_MAJOR, TEMOA_MINOR # ============================================================================= @@ -106,7 +109,6 @@ def _version_callback(value: bool) -> None: def _cite_callback(value: bool) -> None: if value: citation_text = Text() - citation_text.append('[bold]How to Cite Temoa:[/bold]\n\n', style='bold') citation_text.append( 'If you use Temoa in your research, please cite the following publication:\n\n' ) @@ -128,6 +130,34 @@ def _cite_callback(value: bool) -> None: raise typer.Exit() +def get_default_schema() -> Path: + """Get the default path to the v4 schema file, handling both installed and development cases.""" + try: + schema_path = resources.files('temoa.db_schema') / 'temoa_schema_v4.sql' + + if not schema_path.is_file(): + raise FileNotFoundError( + f'Schema file not found at expected resource path: {schema_path}' + ) + return Path(str(schema_path)) # Convert Traversable to concrete Path + except Exception as e: + logger.exception('Failed to load schema from resources') + # The fallback for development needs to reflect the current repository structure + # assuming `cli.py` is in `temoa/` and `db_schema/` is a sibling of `cli.py` within `temoa/`. + fallback_path = Path(__file__).parent / 'db_schema' / 'temoa_schema_v4.sql' + if fallback_path.is_file(): + logger.warning( + 'Using fallback schema path: %s. ' + 'This might indicate an issue with package installation or resource setup.', + fallback_path, + ) + return fallback_path + else: + raise FileNotFoundError( + f'Schema file not found using resource system or fallback at {fallback_path}' + ) from e + + app = typer.Typer( name='temoa', help='The Temoa Project: Tools for Energy Model Optimization and Analysis.', @@ -158,7 +188,7 @@ def validate( typer.Option('--output', '-o', help='Directory to save validation log.'), ] = None, silent: Annotated[ - bool, typer.Option('--silent', '-s', help='Suppress informational output on success.') + bool, typer.Option('--silent', '-q', help='Suppress informational output on success.') ] = False, debug: Annotated[ bool, typer.Option('--debug', '-d', help='Enable debug-level logging.') @@ -212,7 +242,7 @@ def run( silent: Annotated[ bool, typer.Option( - '--silent', '-s', help='Silent run. No interactive prompts or INFO logs on console.' + '--silent', '-q', help='Silent run. No interactive prompts or INFO logs on console.' ), ] = False, debug: Annotated[ @@ -255,6 +285,169 @@ def run( raise typer.Exit(code=1) from e +@app.command() +def migrate( + input_path: Annotated[ + Path, + typer.Argument( + help='Path to input file to migrate (SQL dump or SQLite DB).', + exists=True, + resolve_path=True, + ), + ], + output_path: Annotated[ + Path | None, + typer.Option( + '--output', + '-o', + help='Output path for the migrated file. If not provided, a default name ' + '(e.g., input_v4.sql or input_v4.sqlite) will be used in a writable location.', + ), + ] = None, + schema_path: Annotated[ + Path | None, + typer.Option('--schema', '-s', help='Path to v4 schema SQL file.'), + ] = None, + migration_type: Annotated[ + str | None, + typer.Option( + '--type', + help='Migration type: "sql" for SQL dump to SQLite dump, "db" for SQLite DB in-place migration, if omitted, infers from input extension.', + ), + ] = None, + silent: Annotated[ + bool, typer.Option('--silent', '-q', help='Suppress informational output on success.') + ] = False, + debug: Annotated[bool, typer.Option('--debug', '-d', help='Enable debug output.')] = False, +) -> None: + """ + Migrate a single Temoa database file (SQL dump or SQLite DB) from v3.1 to v4 format. + """ + if schema_path is None: + schema_path = get_default_schema() + if not schema_path.is_file(): + rich.print(f'[red]Error: Schema file {schema_path} does not exist or is not a file.[/red]') + raise typer.Exit(1) + + # Validate that input_path is a file, not a directory + if not input_path.is_file(): + rich.print(f'[red]Error: Input path must be a file, not a directory: {input_path}[/red]') + raise typer.Exit(1) + + ext = input_path.suffix.lower() + + # Determine the effective output directory and file + effective_output_dir: Path + final_output_file: Path + + if output_path: + # If explicit output_path is provided, its parent is the desired directory + effective_output_dir = output_path.parent + # Ensure the explicitly provided output_path parent exists + try: + effective_output_dir.mkdir(parents=True, exist_ok=True) + except OSError as e: + rich.print( + f'[red]Error: Could not create output directory "{effective_output_dir}": {e}[/red]' + ) + raise typer.Exit(1) from e + final_output_file = effective_output_dir / output_path.name + else: + # Try to use the input file's directory + input_dir = input_path.parent + if _is_writable(input_dir): + effective_output_dir = input_dir + else: + # Fallback to current working directory if input_dir is not writable + current_dir = Path.cwd() + if _is_writable(current_dir): + effective_output_dir = current_dir + if not silent: + rich.print( + f'[yellow]Warning: Input directory "{input_dir}" is not writable. ' + f'Saving output to current directory: "{current_dir}"[/yellow]' + ) + else: + rich.print( + f'[red]Error: Neither input directory "{input_dir}" ' + f'nor current working directory "{current_dir}" are writable. ' + 'Please specify a writable output path with --output.[/red]' + ) + raise typer.Exit(1) + + # Ensure the chosen output directory exists + try: + effective_output_dir.mkdir(parents=True, exist_ok=True) + except OSError as e: + rich.print( + f'[red]Error: Could not create auto-generated output directory "{effective_output_dir}": {e}[/red]' + ) + raise typer.Exit(1) from e + + # For auto-output, derive filename from input_path, place in effective_output_dir + # Determine output file extension based on migration type + if migration_type == 'db' or (migration_type is None and ext in ['.db', '.sqlite']): + # If migrating to DB, output should be .sqlite + final_output_file = effective_output_dir / (input_path.stem + '_v4.sqlite') + else: + # Default to .sql if migrating SQL dump or type 'auto' for .sql input + final_output_file = effective_output_dir / (input_path.stem + '_v4.sql') + + # --- Execute the migration based on type --- + if migration_type == 'sql' or (migration_type is None and ext == '.sql'): + # SQL dump to SQL dump migration + args_namespace = argparse.Namespace( + input=str(input_path), + schema=str(schema_path), + output=str(final_output_file), + debug=debug, + ) + try: + sql_migration_v3_1_to_v4.migrate_dump_to_sqlite(args_namespace) + if not silent: + rich.print(f'[green]SQL dump migration completed: {final_output_file}[/green]') + except Exception as e: + logger.exception('SQL dump migration failed for %s', input_path) + rich.print( + f'[red]SQL dump migration failed for {input_path} -> {final_output_file}: {e}[/red]' + ) + raise typer.Exit(1) from e + elif migration_type == 'db' or (migration_type is None and ext in ['.db', '.sqlite']): + # SQLite DB to SQLite DB migration + args_namespace = argparse.Namespace( + source=str(input_path), + schema=str(schema_path), + out=str(final_output_file), + ) + try: + db_migration_v3_1_to_v4.migrate_all(args_namespace) + if not silent: + rich.print(f'[green]Database migration completed: {final_output_file}[/green]') + except Exception as e: + logger.exception('Database migration failed for %s', input_path) + rich.print( + f'[red]Database migration failed for {input_path} -> {final_output_file}: {e}[/red]' + ) + raise typer.Exit(1) from e + else: + rich.print( + f'[red]Error: Cannot determine migration type for {input_path}. ' + 'Use --type sql, --type db, or ensure file has a .sql, .db, or .sqlite extension.[/red]' + ) + raise typer.Exit(1) + + +def _is_writable(path: Path) -> bool: + """Check if a path is writable.""" + try: + test_file = path / f'.temoa_write_test_{datetime.now(timezone.utc).timestamp()}' + test_file.touch() + test_file.unlink() # Clean up + return True + except OSError: + return False + + # ============================================================================= # Global Options # ============================================================================= diff --git a/temoa/db_schema/temoa_schema_v3.sql b/temoa/db_schema/temoa_schema_v3.sql new file mode 100644 index 000000000..3d0d66faf --- /dev/null +++ b/temoa/db_schema/temoa_schema_v3.sql @@ -0,0 +1,919 @@ +PRAGMA foreign_keys= OFF; +BEGIN TRANSACTION; + +CREATE TABLE IF NOT EXISTS MetaData +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +REPLACE INTO MetaData +VALUES ('myopic_base_year', 2000, 'Base Year for Myopic Analysis'); +REPLACE INTO MetaData +VALUES ('DB_MAJOR', 3, 'DB major version number'); +REPLACE INTO MetaData +VALUES ('DB_MINOR', 0, 'DB minor version number'); + +CREATE TABLE IF NOT EXISTS MetaDataReal +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +REPLACE INTO MetaDataReal +VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); +REPLACE INTO MetaDataReal +VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in LoanRate table'); + +CREATE TABLE IF NOT EXISTS OutputDualVariable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE IF NOT EXISTS OutputObjective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE IF NOT EXISTS SectorLabel +( + sector TEXT, + PRIMARY KEY (sector) +); + +CREATE TABLE IF NOT EXISTS CapacityCredit +( + region TEXT, + period INTEGER, + tech TEXT, + vintage INTEGER, + credit REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage), + CHECK (credit >= 0 AND credit <= 1) +); +CREATE TABLE IF NOT EXISTS CapacityFactorProcess +( + region TEXT, + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, season, tod, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS CapacityFactorTech +( + region TEXT, + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + factor REAL, + notes TEXT, + PRIMARY KEY (region, season, tod, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS CapacityToActivity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + c2a REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS Commodity +( + name TEXT + PRIMARY KEY, + flag TEXT + REFERENCES CommodityType (label), + description TEXT +); +CREATE TABLE IF NOT EXISTS CommodityType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO CommodityType +VALUES ('p', 'physical commodity'); +REPLACE INTO CommodityType +VALUES ('e', 'emissions commodity'); +REPLACE INTO CommodityType +VALUES ('d', 'demand commodity'); +REPLACE INTO CommodityType +VALUES ('s', 'source commodity'); + +CREATE TABLE IF NOT EXISTS CostEmission +( + region TEXT + REFERENCES Region (region), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT NOT NULL + REFERENCES Commodity (name), + cost REAL NOT NULL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE IF NOT EXISTS CostFixed +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS CostInvest +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS CostVariable +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS Demand +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + commodity TEXT + REFERENCES Commodity (name), + demand REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, commodity) +); +CREATE TABLE IF NOT EXISTS DemandSpecificDistribution +( + region TEXT, + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + demand_name TEXT + REFERENCES Commodity (name), + dds REAL, + dds_notes TEXT, + PRIMARY KEY (region, season, tod, demand_name), + CHECK (dds >= 0 AND dds <= 1) +); +CREATE TABLE IF NOT EXISTS LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS Efficiency +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE IF NOT EXISTS EmissionActivity +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS ExistingCapacity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS TechGroup +( + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE IF NOT EXISTS GrowthRateMax +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS GrowthRateSeed +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + seed REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS LoanLifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS LifetimeProcess +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS LifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE IF NOT EXISTS MaxActivity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + max_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE IF NOT EXISTS MaxCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + max_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE IF NOT EXISTS MaxResource +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + max_res REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS MinActivity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + min_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE IF NOT EXISTS MaxCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + max_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE IF NOT EXISTS MinCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + min_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE IF NOT EXISTS MinCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + min_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE IF NOT EXISTS OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputFlowOut +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS PlanningReserveMargin +( + region TEXT + PRIMARY KEY + REFERENCES Region (region), + margin REAL +); +CREATE TABLE IF NOT EXISTS RampDown +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS RampUp +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS Region +( + region TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE IF NOT EXISTS TimeSegmentFraction +( + season TEXT + REFERENCES TimeSeason (season), + tod TEXT + REFERENCES TimeOfDay (tod), + segfrac REAL, + notes TEXT, + PRIMARY KEY (season, tod), + CHECK (segfrac >= 0 AND segfrac <= 1) +); +CREATE TABLE IF NOT EXISTS StorageDuration +( + region TEXT, + tech TEXT, + duration REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS StorageInit +( + tech TEXT + PRIMARY KEY, + value REAL, + notes TEXT +); +CREATE TABLE IF NOT EXISTS TechnologyType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO TechnologyType +VALUES ('r', 'resource technology'); +REPLACE INTO TechnologyType +VALUES ('p', 'production technology'); +REPLACE INTO TechnologyType +VALUES ('pb', 'baseload production technology'); +REPLACE INTO TechnologyType +VALUES ('ps', 'storage production technology'); + +CREATE TABLE IF NOT EXISTS TechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE IF NOT EXISTS TechInputSplitAverage +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech) +); +CREATE TABLE IF NOT EXISTS TechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm) +); +CREATE TABLE IF NOT EXISTS TimeOfDay +( + sequence INTEGER UNIQUE, + tod TEXT + PRIMARY KEY +); +CREATE TABLE IF NOT EXISTS TimePeriod +( + sequence INTEGER UNIQUE, + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES TimePeriodType (label) +); +CREATE TABLE IF NOT EXISTS TimeSeason +( + sequence INTEGER UNIQUE, + season TEXT + PRIMARY KEY +); +CREATE TABLE IF NOT EXISTS TimePeriodType +( + label TEXT + PRIMARY KEY, + description TEXT +); +CREATE TABLE IF NOT EXISTS MaxActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE IF NOT EXISTS MaxCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE IF NOT EXISTS MaxAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + factor REAL, + source TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS MaxNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + max_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE IF NOT EXISTS MaxNewCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + max_new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE IF NOT EXISTS MaxNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE IF NOT EXISTS MinActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE IF NOT EXISTS MinAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + factor REAL, + source TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS MinCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + min_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE IF NOT EXISTS MinNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + min_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech) +); +CREATE TABLE IF NOT EXISTS MinNewCapacityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + min_new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE IF NOT EXISTS MinNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + group_name TEXT + REFERENCES TechGroup (group_name), + max_proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, group_name) +); +CREATE TABLE IF NOT EXISTS OutputEmission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS MinActivityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + min_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); +CREATE TABLE IF NOT EXISTS EmissionLimit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE IF NOT EXISTS MaxActivityGroup +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + group_name TEXT + REFERENCES TechGroup (group_name), + max_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, group_name) +); + +CREATE TABLE RPSRequirement +( + region TEXT NOT NULL + REFERENCES Region (region), + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech_group TEXT NOT NULL + REFERENCES TechGroup (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE TechGroupMember +( + group_name TEXT + REFERENCES TechGroup (group_name), + tech TEXT + REFERENCES Technology (tech), + PRIMARY KEY (group_name, tech) +); +CREATE TABLE IF NOT EXISTS Technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + variable INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES TechnologyType (label) +); +CREATE TABLE IF NOT EXISTS OutputCost +( + scenario TEXT, + region TEXT, + period INTEGER, + tech TEXT, + vintage INTEGER, + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES TimePeriod (period), + FOREIGN KEY (tech) REFERENCES Technology (tech) +); +COMMIT; +PRAGMA FOREIGN_KEYS = 1; diff --git a/temoa/db_schema/temoa_schema_v3_1.sql b/temoa/db_schema/temoa_schema_v3_1.sql new file mode 100644 index 000000000..b91d03ce5 --- /dev/null +++ b/temoa/db_schema/temoa_schema_v3_1.sql @@ -0,0 +1,1057 @@ +PRAGMA foreign_keys= OFF; +BEGIN TRANSACTION; + +CREATE TABLE IF NOT EXISTS MetaData +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +REPLACE INTO MetaData +VALUES ('DB_MAJOR', 3, 'DB major version number'); +REPLACE INTO MetaData +VALUES ('DB_MINOR', 1, 'DB minor version number'); +REPLACE INTO MetaData +VALUES ('days_per_period', 365, 'count of days in each period'); + +CREATE TABLE IF NOT EXISTS MetaDataReal +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +REPLACE INTO MetaDataReal +VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); +REPLACE INTO MetaDataReal +VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in LoanRate table'); + +CREATE TABLE IF NOT EXISTS OutputDualVariable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE IF NOT EXISTS OutputObjective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE IF NOT EXISTS SeasonLabel +( + season TEXT PRIMARY KEY, + notes TEXT +); +CREATE TABLE IF NOT EXISTS SectorLabel +( + sector TEXT PRIMARY KEY, + notes TEXT +); +CREATE TABLE IF NOT EXISTS CapacityCredit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + credit REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage), + CHECK (credit >= 0 AND credit <= 1) +); +CREATE TABLE IF NOT EXISTS CapacityFactorProcess +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS CapacityFactorTech +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS CapacityToActivity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + c2a REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS Commodity +( + name TEXT + PRIMARY KEY, + flag TEXT + REFERENCES CommodityType (label), + description TEXT +); +CREATE TABLE IF NOT EXISTS CommodityType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO CommodityType +VALUES ('s', 'source commodity'); +REPLACE INTO CommodityType +VALUES ('a', 'annual commodity'); +REPLACE INTO CommodityType +VALUES ('p', 'physical commodity'); +REPLACE INTO CommodityType +VALUES ('d', 'demand commodity'); +REPLACE INTO CommodityType +VALUES ('e', 'emissions commodity'); +REPLACE INTO CommodityType +VALUES ('w', 'waste commodity'); +REPLACE INTO CommodityType +VALUES ('wa', 'waste annual commodity'); +REPLACE INTO CommodityType +VALUES ('wp', 'waste physical commodity'); +CREATE TABLE IF NOT EXISTS ConstructionInput +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS CostEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT NOT NULL + REFERENCES Commodity (name), + cost REAL NOT NULL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE IF NOT EXISTS CostFixed +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS CostInvest +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS CostVariable +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS Demand +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + commodity TEXT + REFERENCES Commodity (name), + demand REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, commodity) +); +CREATE TABLE IF NOT EXISTS DemandSpecificDistribution +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tod TEXT + REFERENCES TimeOfDay (tod), + demand_name TEXT + REFERENCES Commodity (name), + dsd REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), + CHECK (dsd >= 0 AND dsd <= 1) +); +CREATE TABLE IF NOT EXISTS EndOfLifeOutput +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS Efficiency +( + region TEXT, + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE IF NOT EXISTS EfficiencyVariable +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE IF NOT EXISTS EmissionActivity +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS EmissionEmbodied +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS EmissionEndOfLife +( + region TEXT, + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS ExistingCapacity +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS TechGroup +( + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE IF NOT EXISTS LoanLifetimeProcess +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS LoanRate +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS LifetimeProcess +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS LifetimeTech +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS Operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +REPLACE INTO Operator VALUES('e','equal to'); +REPLACE INTO Operator VALUES('le','less than or equal to'); +REPLACE INTO Operator VALUES('ge','greater than or equal to'); +CREATE TABLE IF NOT EXISTS LimitGrowthCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitDegrowthCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitGrowthNewCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitDegrowthNewCapacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitGrowthNewCapacityDelta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitDegrowthNewCapacityDelta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitStorageLevelFraction +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) +); +CREATE TABLE IF NOT EXISTS LimitActivity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitActivityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitAnnualCapacityFactor +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS LimitCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitNewCapacity +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitNewCapacityShare +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitResource +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS LimitSeasonalCapacityFactor +( + region TEXT + REFERENCES Region (region), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) +); +CREATE TABLE IF NOT EXISTS LimitTechInputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE IF NOT EXISTS LimitTechInputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE IF NOT EXISTS LimitTechOutputSplit +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE IF NOT EXISTS LimitTechOutputSplitAnnual +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + output_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE IF NOT EXISTS LimitEmission +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES Operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE IF NOT EXISTS LinkedTech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES Technology (tech), + emis_comm TEXT + REFERENCES Commodity (name), + driven_tech TEXT + REFERENCES Technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE IF NOT EXISTS OutputCurtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES TimePeriod (period), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputNetCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputBuiltCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputRetiredCapacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS OutputFlowIn +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputFlowOut +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tod TEXT + REFERENCES TimeOfDay (tod), + input_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + output_comm TEXT + REFERENCES Commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS OutputStorageLevel +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tod TEXT + REFERENCES TimeOfDay (tod), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); +CREATE TABLE IF NOT EXISTS PlanningReserveMargin +( + region TEXT + PRIMARY KEY + REFERENCES Region (region), + margin REAL, + notes TEXT +); +CREATE TABLE IF NOT EXISTS RampDownHourly +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS RampUpHourly +( + region TEXT, + tech TEXT + REFERENCES Technology (tech), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS Region +( + region TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE IF NOT EXISTS ReserveCapacityDerate +( + region TEXT, + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS TimeSegmentFraction +( + period INTEGER + REFERENCES TimePeriod (period), + season TEXT + REFERENCES SeasonLabel (season), + tod TEXT + REFERENCES TimeOfDay (tod), + segfrac REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segfrac >= 0 AND segfrac <= 1) +); +CREATE TABLE IF NOT EXISTS StorageDuration +( + region TEXT, + tech TEXT, + duration REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS LifetimeSurvivalCurve +( + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES Technology (tech), + vintage INTEGER NOT NULL + REFERENCES TimePeriod (period), + fraction REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS TechnologyType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO TechnologyType +VALUES ('p', 'production technology'); +REPLACE INTO TechnologyType +VALUES ('pb', 'baseload production technology'); +REPLACE INTO TechnologyType +VALUES ('ps', 'storage production technology'); +-- CREATE TABLE IF NOT EXISTS TimeNext +-- ( +-- period INTEGER +-- REFERENCES TimePeriod (period), +-- season TEXT +-- REFERENCES SeasonLabel (season), +-- tod TEXT +-- REFERENCES TimeOfDay (tod), +-- season_next TEXT +-- REFERENCES SeasonLabel (season), +-- tod_next TEXT +-- REFERENCES TimeOfDay (tod), +-- notes TEXT, +-- PRIMARY KEY (period, season, tod) +-- ); +CREATE TABLE IF NOT EXISTS TimeOfDay +( + sequence INTEGER UNIQUE, + tod TEXT + PRIMARY KEY +); +CREATE TABLE IF NOT EXISTS TimePeriod +( + sequence INTEGER UNIQUE, + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES TimePeriodType (label) +); +CREATE TABLE IF NOT EXISTS TimeSeason +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + season TEXT + REFERENCES SeasonLabel (season), + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +CREATE TABLE IF NOT EXISTS TimeSeasonSequential +( + period INTEGER + REFERENCES TimePeriod (period), + sequence INTEGER, + seas_seq TEXT, + season TEXT + REFERENCES SeasonLabel (season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) +); +CREATE TABLE IF NOT EXISTS TimePeriodType +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO TimePeriodType +VALUES('e', 'existing vintages'); +REPLACE INTO TimePeriodType +VALUES('f', 'future'); +CREATE TABLE IF NOT EXISTS OutputEmission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES SectorLabel (sector), + period INTEGER + REFERENCES TimePeriod (period), + emis_comm TEXT + REFERENCES Commodity (name), + tech TEXT + REFERENCES Technology (tech), + vintage INTEGER + REFERENCES TimePeriod (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS RPSRequirement +( + region TEXT NOT NULL + REFERENCES Region (region), + period INTEGER NOT NULL + REFERENCES TimePeriod (period), + tech_group TEXT NOT NULL + REFERENCES TechGroup (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE IF NOT EXISTS TechGroupMember +( + group_name TEXT + REFERENCES TechGroup (group_name), + tech TEXT + REFERENCES Technology (tech), + PRIMARY KEY (group_name, tech) +); +CREATE TABLE IF NOT EXISTS Technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES TechnologyType (label) +); +CREATE TABLE IF NOT EXISTS OutputCost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES SectorLabel (sector), + period INTEGER REFERENCES TimePeriod (period), + tech TEXT REFERENCES Technology (tech), + vintage INTEGER REFERENCES TimePeriod (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES TimePeriod (period), + FOREIGN KEY (tech) REFERENCES Technology (tech) +); +COMMIT; +PRAGMA FOREIGN_KEYS = 1; diff --git a/temoa/db_schema/temoa_schema_v4.sql b/temoa/db_schema/temoa_schema_v4.sql new file mode 100644 index 000000000..5cbdb446f --- /dev/null +++ b/temoa/db_schema/temoa_schema_v4.sql @@ -0,0 +1,1112 @@ +PRAGMA foreign_keys = OFF; +BEGIN TRANSACTION; + +CREATE TABLE IF NOT EXISTS metadata +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +REPLACE INTO metadata +VALUES ('DB_MAJOR', 4, 'DB major version number'); +REPLACE INTO metadata +VALUES ('DB_MINOR', 0, 'DB minor version number'); +REPLACE INTO metadata +VALUES ('days_per_period', 365, 'count of days in each period'); + +CREATE TABLE IF NOT EXISTS metadata_real +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +REPLACE INTO metadata_real +VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); +REPLACE INTO metadata_real +VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in LoanRate table'); + +CREATE TABLE IF NOT EXISTS output_dual_variable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE IF NOT EXISTS output_objective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE IF NOT EXISTS season_label +( + season TEXT PRIMARY KEY, + notes TEXT +); +CREATE TABLE IF NOT EXISTS sector_label +( + sector TEXT PRIMARY KEY, + notes TEXT +); +CREATE TABLE IF NOT EXISTS capacity_credit +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER, + credit REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage), + CHECK (credit >= 0 AND credit <= 1) +); +CREATE TABLE IF NOT EXISTS capacity_factor_process +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS capacity_factor_tech +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS capacity_to_activity +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + c2a REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS commodity +( + name TEXT + PRIMARY KEY, + flag TEXT + REFERENCES commodity_type (label), + description TEXT +); +CREATE TABLE IF NOT EXISTS commodity_type +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO commodity_type +VALUES ('s', 'source commodity'); +REPLACE INTO commodity_type +VALUES ('a', 'annual commodity'); +REPLACE INTO commodity_type +VALUES ('p', 'physical commodity'); +REPLACE INTO commodity_type +VALUES ('d', 'demand commodity'); +REPLACE INTO commodity_type +VALUES ('e', 'emissions commodity'); +REPLACE INTO commodity_type +VALUES ('w', 'waste commodity'); +REPLACE INTO commodity_type +VALUES ('wa', 'waste annual commodity'); +REPLACE INTO commodity_type +VALUES ('wp', 'waste physical commodity'); +CREATE TABLE IF NOT EXISTS construction_input +( + region TEXT, + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS cost_emission +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT NOT NULL + REFERENCES commodity (name), + cost REAL NOT NULL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE IF NOT EXISTS cost_fixed +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES time_period (period), + tech TEXT NOT NULL + REFERENCES technology (tech), + vintage INTEGER NOT NULL + REFERENCES time_period (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS cost_invest +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS cost_variable +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES time_period (period), + tech TEXT NOT NULL + REFERENCES technology (tech), + vintage INTEGER NOT NULL + REFERENCES time_period (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS demand +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + commodity TEXT + REFERENCES commodity (name), + demand REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, commodity) +); +CREATE TABLE IF NOT EXISTS demand_specific_distribution +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + demand_name TEXT + REFERENCES commodity (name), + dsd REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), + CHECK (dsd >= 0 AND dsd <= 1) +); +CREATE TABLE IF NOT EXISTS end_of_life_output +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS efficiency +( + region TEXT, + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE IF NOT EXISTS efficiency_variable +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE IF NOT EXISTS emission_activity +( + region TEXT, + emis_comm TEXT + REFERENCES commodity (name), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS emission_embodied +( + region TEXT, + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS emission_end_of_life +( + region TEXT, + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS existing_capacity +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS tech_group +( + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE IF NOT EXISTS loan_lifetime_process +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS loan_rate +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS lifetime_process +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE IF NOT EXISTS lifetime_tech +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + lifetime REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +REPLACE INTO operator VALUES('e','equal to'); +REPLACE INTO operator VALUES('le','less than or equal to'); +REPLACE INTO operator VALUES('ge','greater than or equal to'); +CREATE TABLE IF NOT EXISTS limit_growth_capacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_degrowth_capacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_growth_new_capacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_degrowth_new_capacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_growth_new_capacity_delta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_degrowth_new_capacity_delta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_storage_level_fraction +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) +); +CREATE TABLE IF NOT EXISTS limit_activity +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_activity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_annual_capacity_factor +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS limit_capacity +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_capacity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_new_capacity +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_new_capacity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_resource +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE IF NOT EXISTS limit_seasonal_capacity_factor +( + region TEXT + REFERENCES region (region), + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tech TEXT + REFERENCES technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) +); +CREATE TABLE IF NOT EXISTS limit_tech_input_split +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE IF NOT EXISTS limit_tech_input_split_annual +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE IF NOT EXISTS limit_tech_output_split +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE IF NOT EXISTS limit_tech_output_split_annual +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE IF NOT EXISTS limit_emission +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE IF NOT EXISTS linked_tech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES technology (tech), + emis_comm TEXT + REFERENCES commodity (name), + driven_tech TEXT + REFERENCES technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE IF NOT EXISTS output_curtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES time_period (period), + tod TEXT + REFERENCES time_of_day (tod), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + curtailment REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS output_net_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS output_built_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE IF NOT EXISTS output_retired_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + cap_eol REAL, + cap_early REAL, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS output_flow_in +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS output_flow_out +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + flow REAL, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE IF NOT EXISTS output_storage_level +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + level REAL, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); +CREATE TABLE IF NOT EXISTS planning_reserve_margin +( + region TEXT + PRIMARY KEY + REFERENCES region (region), + margin REAL, + notes TEXT +); +CREATE TABLE IF NOT EXISTS ramp_down_hourly +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS ramp_up_hourly +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS region +( + region TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE IF NOT EXISTS reserve_capacity_derate +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE IF NOT EXISTS time_segment_fraction +( + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + segment_fraction REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) +); +CREATE TABLE IF NOT EXISTS storage_duration +( + region TEXT, + tech TEXT, + duration REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE IF NOT EXISTS lifetime_survival_curve +( + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES technology (tech), + vintage INTEGER NOT NULL + REFERENCES time_period (period), + fraction REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE IF NOT EXISTS technology_type +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO technology_type +VALUES ('p', 'production technology'); +REPLACE INTO technology_type +VALUES ('pb', 'baseload production technology'); +REPLACE INTO technology_type +VALUES ('ps', 'storage production technology'); +-- CREATE TABLE IF NOT EXISTS time_manual +-- ( +-- period INTEGER +-- REFERENCES time_period (period), +-- season TEXT +-- REFERENCES season_label (season), +-- tod TEXT +-- REFERENCES time_of_day (tod), +-- season_next TEXT +-- REFERENCES season_label (season), +-- tod_next TEXT +-- REFERENCES time_of_day (tod), +-- notes TEXT, +-- PRIMARY KEY (period, season, tod) +-- ); +CREATE TABLE IF NOT EXISTS time_of_day +( + sequence INTEGER UNIQUE, + tod TEXT + PRIMARY KEY +); +CREATE TABLE IF NOT EXISTS time_period +( + sequence INTEGER UNIQUE, + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES time_period_type (label) +); +CREATE TABLE IF NOT EXISTS time_season_all +( + period INTEGER + REFERENCES time_period (period), + sequence INTEGER, + season TEXT + REFERENCES season_label (season), + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +CREATE TABLE IF NOT EXISTS time_season_to_sequential +( + period INTEGER + REFERENCES time_period (period), + sequence INTEGER, + seas_seq TEXT, + season TEXT + REFERENCES season_label (season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) +); +CREATE TABLE IF NOT EXISTS time_period_type +( + label TEXT + PRIMARY KEY, + description TEXT +); +REPLACE INTO time_period_type +VALUES('e', 'existing vintages'); +REPLACE INTO time_period_type +VALUES('f', 'future'); +CREATE TABLE IF NOT EXISTS output_emission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + emission REAL, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE IF NOT EXISTS rps_requirement +( + region TEXT NOT NULL + REFERENCES region (region), + period INTEGER NOT NULL + REFERENCES time_period (period), + tech_group TEXT NOT NULL + REFERENCES tech_group (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE IF NOT EXISTS tech_group_member +( + group_name TEXT + REFERENCES tech_group (group_name), + tech TEXT + REFERENCES technology (tech), + PRIMARY KEY (group_name, tech) +); +CREATE TABLE IF NOT EXISTS technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES technology_type (label) +); +CREATE TABLE IF NOT EXISTS output_cost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) +); + +CREATE TABLE IF NOT EXISTS time_season +( + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + season TEXT REFERENCES season_label(season), + notes TEXT, + PRIMARY KEY (period, sequence, season) +); + +CREATE TABLE IF NOT EXISTS time_season_sequential +( + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + seas_seq TEXT, + season TEXT REFERENCES season_label(season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) +); + +CREATE TABLE IF NOT EXISTS myopic_efficiency +( + base_year integer, + region text, + input_comm text, + tech text, + vintage integer, + output_comm text, + efficiency real, + lifetime integer, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (region, input_comm, tech, vintage, output_comm) +); +-- for efficient searching by rtv: +CREATE INDEX IF NOT EXISTS region_tech_vintage ON myopic_efficiency (region, tech, vintage); + +CREATE TABLE IF NOT EXISTS output_flow_out_summary +( + scenario TEXT NOT NULL, + region TEXT NOT NULL, + sector TEXT, + period INTEGER, + input_comm TEXT NOT NULL, + tech TEXT NOT NULL, + vintage INTEGER, + output_comm TEXT NOT NULL, + flow REAL NOT NULL, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) +); + +COMMIT; +PRAGMA foreign_keys = ON; diff --git a/tests/test_cli.py b/tests/test_cli.py index 1075bf794..ba97d1e9a 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,8 +1,9 @@ +import shutil from pathlib import Path from typer.testing import CliRunner -from temoa.cli import app +from temoa.cli import _is_writable, app runner = CliRunner() @@ -37,11 +38,12 @@ def test_cli_run_command_success_silent(tmp_path): """Test a successful silent run of the `temoa run` command.""" db_path = Path(__file__).parent / 'testing_outputs' / 'utopia.sqlite' test_config_path = create_test_config(tmp_path, db_path) + # --output is explicitly given, so it should use tmp_path args = ['run', str(test_config_path), '--output', str(tmp_path), '--silent'] result = runner.invoke(app, args) assert result.exit_code == 0, f'CLI crashed with error: {result.exception}' - assert 'Temoa run completed successfully' not in result.stdout + assert 'Temoa run completed successfully' not in result.stdout # Silent run assert (tmp_path / 'temoa-run.log').exists() @@ -49,11 +51,12 @@ def test_cli_run_build_only_silent(tmp_path): """Test the `temoa run --build-only --silent` flags.""" db_path = Path(__file__).parent / 'testing_outputs' / 'utopia.sqlite' test_config_path = create_test_config(tmp_path, db_path) + # --output is explicitly given, so it should use tmp_path args = ['run', str(test_config_path), '--output', str(tmp_path), '--build-only', '--silent'] result = runner.invoke(app, args) assert result.exit_code == 0, f'CLI crashed with error: {result.exception}' - assert 'Model built successfully' not in result.stdout + assert 'Model built successfully' not in result.stdout # Silent run assert (tmp_path / 'temoa-run.log').exists() @@ -113,4 +116,261 @@ def test_cli_run_missing_config(): assert result.exit_code != 0 # Check that the error mentions the missing file (more robust than exact string match) assert 'non_existent_file.toml' in result.stderr - assert 'does not' in result.stderr and 'exist' in result.stderr + + +# ============================================================================= +# Tests for the `migrate` command +# ============================================================================= + + +def test_cli_migrate_help(): + """Test the `temoa migrate --help` command.""" + result = runner.invoke(app, ['migrate', '--help']) + assert result.exit_code == 0 + assert 'migrate' in result.stdout + assert 'Migrate a single Temoa database file' in result.stdout + + +def test_cli_migrate_sql_file(tmp_path): + """Test migrating a SQL file with explicit --output.""" + # Ensure input file is available in the test environment (e.g., copied from data_files) + input_file_src = Path(__file__).parent.parent / 'data_files' / 'temoa_basics_0.sql' + input_file = tmp_path / 'test_input.sql' + shutil.copy2(input_file_src, input_file) + + output_file = tmp_path / 'migrated_explicit.sql' + args = ['migrate', str(input_file), '--output', str(output_file)] + result = runner.invoke(app, args) + + assert result.exit_code == 0, f'Migration failed: {result.exception}\n{result.stderr}' + assert 'SQL dump migration completed' in result.stdout + assert output_file.exists() + + +def test_cli_migrate_rejects_directory_input(tmp_path): + """Test that the migrate command rejects a directory as input.""" + dummy_dir = tmp_path / 'my_dummy_dir' + dummy_dir.mkdir() + args = ['migrate', str(dummy_dir)] + result = runner.invoke(app, args) + + assert result.exit_code != 0 + assert 'Error: Input path must be a file, not a directory:' in result.stdout + assert str(dummy_dir) in result.stdout + + +def test_cli_migrate_sql_file_auto_output_writable_input_dir(tmp_path): + """ + Test migrating a SQL file without --output, + where the input directory is writable. + Output should be next to input with _v4.sql suffix. + """ + src_file = Path(__file__).parent.parent / 'data_files' / 'temoa_basics_0.sql' + input_file = tmp_path / src_file.name # Input file in writable tmp_path + shutil.copy2(src_file, input_file) + + args = ['migrate', str(input_file)] + result = runner.invoke(app, args) + + assert result.exit_code == 0, ( + f'Migration failed: {result.exception}\n{result.stderr}\n{result.stdout}' + ) + assert 'SQL dump migration completed' in result.stdout + expected_output = input_file.with_stem(input_file.stem + '_v4').with_suffix( + '.sql' + ) # Explicit .sql suffix + assert expected_output.exists() + + +def test_cli_migrate_sql_file_auto_output_non_writable_input_dir_fallback_cwd( + tmp_path, monkeypatch +): + """ + Test migrating a SQL file without --output, + where the input directory is NOT writable. + Output should fall back to current working directory (mocked as tmp_path) + and have a _v4.sql suffix. + """ + non_writable_mock_parent = tmp_path / 'mock_non_writable_input_parent' + non_writable_mock_parent.mkdir() + + src_file = Path(__file__).parent.parent / 'data_files' / 'temoa_basics_0.sql' + input_file = non_writable_mock_parent / src_file.name + shutil.copy2(src_file, input_file) + + def mock_is_writable(path: Path) -> bool: + if path == non_writable_mock_parent: + return False + if path == tmp_path: # CWD for the test runner is tmp_path + return True + return _is_writable(path) + + monkeypatch.setattr('temoa.cli._is_writable', mock_is_writable) + monkeypatch.setattr( + Path, + 'cwd', + classmethod(lambda cls: tmp_path), + ) # Ensure CWD is tmp_path for logging + + args = ['migrate', str(input_file)] + result = runner.invoke(app, args, catch_exceptions=False) + + assert result.exit_code == 0, ( + f'Migration failed: {result.exception}\n{result.stderr}\n{result.stdout}' + ) + assert 'SQL dump migration completed' in result.stdout + assert 'Warning: Input directory' in result.stdout + assert str(non_writable_mock_parent) in result.stdout + assert 'is not writable.' in result.stdout + assert 'Saving output to current directory:' in result.stdout + assert str(tmp_path) in result.stdout + + expected_output_in_cwd = tmp_path / (input_file.stem + '_v4.sql') + assert expected_output_in_cwd.exists() + assert not (non_writable_mock_parent / (input_file.stem + '_v4.sql')).exists() + + +def test_cli_migrate_sql_file_auto_output_no_writable_location(tmp_path, monkeypatch): + """ + Test migrating a SQL file without --output, + where neither the input directory nor the CWD are writable. + Should exit with an error. + """ + non_writable_mock_parent = tmp_path / 'mock_non_writable_input_parent_no_cwd' + non_writable_mock_parent.mkdir() + + src_file = Path(__file__).parent.parent / 'data_files' / 'temoa_basics_0.sql' + input_file = non_writable_mock_parent / src_file.name + shutil.copy2(src_file, input_file) + + # Mock _is_writable to return False for both the input directory and the CWD (tmp_path) + def mock_is_writable_always_false(_path: Path) -> bool: + return False + + monkeypatch.setattr('temoa.cli._is_writable', mock_is_writable_always_false) + + args = ['migrate', str(input_file)] + result = runner.invoke(app, args, catch_exceptions=False) + + assert result.exit_code != 0, 'Migration should fail with a non-zero exit code' + assert 'Error: Neither input directory' in result.stdout + assert 'nor current working directory' in result.stdout + assert 'are writable.' in result.stdout + assert not ( + tmp_path / (input_file.stem + '_v4' + input_file.suffix) + ).exists() # No output created + + +def test_cli_migrate_invalid_file(): + """Test migrating a non-existent file.""" + args = ['migrate', 'non_existent.sql'] + result = runner.invoke(app, args) + + assert result.exit_code != 0 + # Typer handles file existence check, so error is in stderr + assert 'does not exist' in result.stderr or 'does not exist' in str(result.exception) + + +def test_cli_migrate_unknown_type(tmp_path): + """Test migrating a file with unknown extension.""" + unknown_file = tmp_path / 'unknown.txt' + unknown_file.write_text('dummy') + args = ['migrate', str(unknown_file)] + result = runner.invoke(app, args) + + assert result.exit_code != 0 + assert 'Cannot determine migration type' in result.stdout + + +def test_cli_migrate_override_type(tmp_path): + """Test migrating with explicit type override.""" + input_file_src = Path(__file__).parent.parent / 'data_files' / 'temoa_basics_0.sql' + input_file = tmp_path / 'test_input_override.sql' + shutil.copy2(input_file_src, input_file) + + output_file = tmp_path / 'migrated_override.sql' + args = ['migrate', str(input_file), '--output', str(output_file), '--type', 'sql'] + result = runner.invoke(app, args) + + assert result.exit_code == 0 + assert 'SQL dump migration completed' in result.stdout + assert output_file.exists() + + +def test_cli_migrate_sql_file_silent(tmp_path): + """Test migrating a SQL file with --silent flag.""" + input_file_src = Path(__file__).parent.parent / 'data_files' / 'temoa_basics_0.sql' + input_file = tmp_path / 'test_input_silent.sql' + shutil.copy2(input_file_src, input_file) + + output_file = tmp_path / 'migrated_silent.sql' + args = ['migrate', str(input_file), '--output', str(output_file), '--silent'] # Use --silent + result = runner.invoke(app, args) + + assert result.exit_code == 0, f'Migration failed: {result.exception}\n{result.stderr}' + # In silent mode, success messages should NOT be in stdout + assert 'SQL dump migration completed' not in result.stdout + assert output_file.exists() + + +def test_cli_migrate_db_file_silent(tmp_path): + """Test migrating a DB file with --silent flag.""" + import sqlite3 # Ensure sqlite3 is imported for this test if not already at top level + + input_file = tmp_path / 'test_v3_1_silent.sqlite' + conn = sqlite3.connect(input_file) + conn.execute('CREATE TABLE MetaData (name TEXT, value TEXT)') + conn.execute("INSERT INTO MetaData VALUES ('DB_MAJOR', '3')") + conn.commit() + conn.close() + + output_file = tmp_path / 'migrated_silent.sqlite' + args = ['migrate', str(input_file), '--output', str(output_file), '--silent'] # Use --silent + result = runner.invoke(app, args) + + assert result.exit_code == 0, f'Migration failed: {result.exception}\n{result.stderr}' + # In silent mode, success messages should NOT be in stdout + assert 'Database migration completed' not in result.stdout + assert output_file.exists() + + +def test_cli_migrate_sql_file_auto_output_non_writable_input_dir_fallback_cwd_silent( + tmp_path, monkeypatch +): + """ + Test migrating a SQL file with --silent, where input dir is not writable. + Output should fall back to CWD, and the warning should NOT be printed. + """ + non_writable_mock_parent = tmp_path / 'mock_non_writable_input_parent_silent' + non_writable_mock_parent.mkdir() + + src_file = Path(__file__).parent.parent / 'data_files' / 'temoa_basics_0.sql' + input_file = non_writable_mock_parent / src_file.name + shutil.copy2(src_file, input_file) + + def mock_is_writable(path: Path) -> bool: + if path == non_writable_mock_parent: + return False + if path == tmp_path: + return True + return _is_writable(path) + + monkeypatch.setattr('temoa.cli._is_writable', mock_is_writable) + monkeypatch.setattr( + Path, + 'cwd', + classmethod(lambda cls: tmp_path), + ) + + args = ['migrate', str(input_file), '--silent'] # Use --silent here + result = runner.invoke(app, args, catch_exceptions=False) + + assert result.exit_code == 0, ( + f'Migration failed: {result.exception}\n{result.stderr}\n{result.stdout}' + ) + assert 'SQL dump migration completed' not in result.stdout # Should be silent + assert 'Warning: Input directory' not in result.stdout # Warning should be silent + + expected_output_in_cwd = tmp_path / (input_file.stem + '_v4.sql') + assert expected_output_in_cwd.exists() + assert not (non_writable_mock_parent / (input_file.stem + '_v4.sql')).exists() From 53defd4cb704e06fc694b7d3734e5ccf059015a9 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 13 Nov 2025 17:54:25 -0500 Subject: [PATCH 328/587] adding a tutorial command to the cli --- pyproject.toml | 5 +- requirements-dev.txt | 2 + requirements.txt | 2 + temoa/cli.py | 162 +++++++++++++++++++++++ temoa/tutorial_assets/config_sample.toml | 154 +++++++++++++++++++++ temoa/tutorial_assets/utopia.sqlite | Bin 0 -> 1028096 bytes uv.lock | 13 +- 7 files changed, 335 insertions(+), 3 deletions(-) create mode 100644 temoa/tutorial_assets/config_sample.toml create mode 100644 temoa/tutorial_assets/utopia.sqlite diff --git a/pyproject.toml b/pyproject.toml index 398ba8561..6814e538e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "temoa" -version = "4.0.0a1" +version = "4.0.0a1.dev20251113" description = "Tools for Energy Model Optimization and Analysis" readme = "README.md" requires-python = ">=3.12" @@ -30,6 +30,7 @@ dependencies = [ "scipy>=1.14.1", "typer>=0.20.0", "rich>=14.2.0", + "tomlkit>=0.12.0", ] @@ -74,7 +75,7 @@ build-backend = "hatchling.build" include = [ "temoa", ] -package-data = { "temoa" = ["db_schema/*.sql"] } +package-data = { "temoa" = ["db_schema/*.sql", "tutorial_assets/*"] } [tool.ruff] diff --git a/requirements-dev.txt b/requirements-dev.txt index f86d17a9a..99a973a88 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -172,6 +172,8 @@ sphinxcontrib-serializinghtml==2.0.0 # sphinx tabulate==0.9.0 # via temoa (pyproject.toml) +tomlkit==0.13.3 + # via temoa (pyproject.toml) typer==0.20.0 # via temoa (pyproject.toml) typing-extensions==4.15.0 diff --git a/requirements.txt b/requirements.txt index 4fe33fddb..2b660981f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -102,6 +102,8 @@ six==1.17.0 # via python-dateutil tabulate==0.9.0 # via temoa (pyproject.toml) +tomlkit==0.13.3 + # via temoa (pyproject.toml) typer==0.20.0 # via temoa (pyproject.toml) typing-extensions==4.15.0 diff --git a/temoa/cli.py b/temoa/cli.py index 417934207..fc4feaf78 100644 --- a/temoa/cli.py +++ b/temoa/cli.py @@ -1,11 +1,13 @@ import argparse import logging +import shutil from datetime import datetime, timezone from importlib import resources from pathlib import Path from typing import Annotated import rich +import tomlkit import typer from rich.logging import RichHandler from rich.text import Text @@ -437,6 +439,166 @@ def migrate( raise typer.Exit(1) +def _copy_tutorial_resources(target_config: Path, target_database: Path) -> None: + """ + Copy tutorial resource files directly to target locations. + + Args: + target_config: Path where configuration file should be copied + target_database: Path where database file should be copied + """ + try: + # Try to copy resources directly from the package using resources.files() + base = resources.files('temoa') / 'tutorial_assets' + config_resource = base / 'config_sample.toml' + db_resource = base / 'utopia.sqlite' + + # Copy configuration file + with config_resource.open('rb') as source: + with open(target_config, 'wb') as target: + shutil.copyfileobj(source, target) + + # Copy database file + with db_resource.open('rb') as source: + with open(target_database, 'wb') as target: + shutil.copyfileobj(source, target) + + except (ModuleNotFoundError, FileNotFoundError, AttributeError) as e: + logger.exception('Failed to load tutorial resources from package') + # Fallback to development paths (for development environments) + fallback_config = Path(__file__).parent / 'tutorial_assets' / 'config_sample.toml' + fallback_database = Path(__file__).parent / 'tutorial_assets' / 'utopia.sqlite' + + if not fallback_config.exists() or not fallback_database.exists(): + raise FileNotFoundError( + f'Tutorial resources not found. Tried package resources and fallback paths:\n' + f'Config: {fallback_config}\n' + f'Database: {fallback_database}' + ) from e + + # Copy files using fallback paths + shutil.copy2(fallback_config, target_config) + shutil.copy2(fallback_database, target_database) + + +def _update_toml_database_paths(config_path: Path, new_database_name: str) -> None: + """ + Update database paths in a TOML configuration file using tomlkit. + + Args: + config_path: Path to the configuration file + new_database_name: Base name for the new database (without extension) + """ + try: + # Load TOML document with tomlkit + with open(config_path, 'rb') as f: + doc = tomlkit.load(f) + + # Update database paths safely + if 'input_database' in doc: + doc['input_database'] = f'{new_database_name}.sqlite' + + if 'output_database' in doc: + doc['output_database'] = f'{new_database_name}.sqlite' + + # Write back with tomlkit + with open(config_path, 'w', encoding='utf-8') as f: + tomlkit.dump(doc, f) + + except Exception as _e: + logger.warning('Failed to update TOML configuration %s', config_path) + raise + + +@app.command() +def tutorial( + config_name: Annotated[ + str, typer.Argument(help='Name for the tutorial configuration file (without extension).') + ] = 'tutorial_config', + database_name: Annotated[ + str, typer.Argument(help='Name for the tutorial database file (without extension).') + ] = 'tutorial_database', + force: Annotated[ + bool, typer.Option('--force', '-f', help='Overwrite existing files without prompting.') + ] = False, + verbose: Annotated[ + bool, + typer.Option('--verbose', '-v', help='Show detailed information about the tutorial setup.'), + ] = False, +) -> None: + """ + Create tutorial configuration and database files in the current directory with guidance. + + This command creates: + - A configuration file (.toml) + - A sample database (.sqlite) + + Both files will be configured to work together for running your first Temoa model. + """ + current_dir = Path.cwd() + + target_config = current_dir / f'{config_name}.toml' + target_database = current_dir / f'{database_name}.sqlite' + + # Check for existing files and handle conflicts + existing_files = [] + if target_config.exists(): + existing_files.append(str(target_config)) + if target_database.exists(): + existing_files.append(str(target_database)) + + if existing_files and not force: + rich.print('[yellow]Tutorial files already exist:[/yellow]') + for file in existing_files: + rich.print(f' - {file}') + + try: + typer.confirm('Do you want to overwrite these files?', abort=True) + except typer.Abort: + rich.print('[yellow]Tutorial setup cancelled.[/yellow]') + raise typer.Exit() from None + + try: + # Copy tutorial resources directly to target locations + if verbose: + rich.print('Copying tutorial resources...') + _copy_tutorial_resources(target_config, target_database) + + # Update database paths using tomlkit (preserves formatting/comments) + if verbose: + rich.print('Updating database paths in configuration...') + + _update_toml_database_paths(target_config, database_name) + + if verbose: + rich.print('\n[bold green]āœ… Tutorial files created successfully![/bold green]') + + rich.print('\n[bold]Tutorial Setup Complete![/bold]') + rich.print(f'Configuration file: [cyan]{target_config.name}[/cyan]') + rich.print(f'Database file: [cyan]{target_database.name}[/cyan]') + + rich.print('\n[bold]Next Steps:[/bold]') + rich.print(f'1. Review the configuration: [cyan]{target_config.name}[/cyan]') + rich.print('2. Run your first model:') + rich.print(f' [green]uv run temoa run {target_config.name}[/green]') + rich.print(' or') + rich.print(f' [green]python -m temoa run {target_config.name}[/green]') + rich.print( + f'\nTo learn more about the configuration options, see the comments in [cyan]{target_config.name}[/cyan]' + ) + + if verbose: + rich.print( + f"\n[dim]The configuration file points to your local '{database_name}.sqlite' database.[/dim]" + ) + rich.print("[dim]Results will be saved in the 'output_files' directory.[/dim]") + + except Exception as e: + logger.exception('Failed to create tutorial files') + rich.print(f'\n[bold red]āŒ Failed to create tutorial files:[/bold red] {e}') + raise typer.Exit(1) from e + + def _is_writable(path: Path) -> bool: """Check if a path is writable.""" try: diff --git a/temoa/tutorial_assets/config_sample.toml b/temoa/tutorial_assets/config_sample.toml new file mode 100644 index 000000000..6fae53b0b --- /dev/null +++ b/temoa/tutorial_assets/config_sample.toml @@ -0,0 +1,154 @@ +# ---------------------------------------------------------- +# Configuration file for a Temoa Run +# Allows specification of run type and associated parameters +# ---------------------------------------------------------- +# +# For toml format info see: https://toml.io/en/ +# - comments may be added with hash +# - do NOT comment out table names in brackets like: [] + +# Scenario Name (Mandatory) +# This scenario name is used to label results within the output .sqlite file +# (cannot contain "-" dash) +scenario = "zulu" + +# Scenario Mode (Mandatory) +# See documentation for explanations. A standard single run is "perfect_foresight" +# mode must be one of (case-insensitive): +# [perfect_foresight, MGA, myopic, method_of_morris, build_only, check, monte_carlo] +scenario_mode = "perfect_foresight" + +# Input database (Mandatory) +input_database = "data_files/example_dbs/utopia.sqlite" + +# Output file (Mandatory) +# The output file must be an existing .sqlite file +# For Perfect Foresight, the user may target the same input file or a separate / +# copied sqlite file in a different location. Myopic, MGA require that input_database = output_database +output_database = "data_files/example_dbs/utopia.sqlite" + +# ------------------------------------ +# DATABASE CONFIGURATION +# ------------------------------------ + +# See the documentation section on Data Quality for notes on the features below + +# Check the pricing structure for common errors, which are reported in the log file +# Strongly recommended +price_check = true + +# Check the network connectivity for processes in the model. Strongly +# recommended to ensure proper performance. Results are reported in log file +# This requires that source commodities be marked with 's' in Commodity table +# This is required for Myopic runs +source_trace = true + +# Produce HTML files for Commodity Networks. Requires source_trace above +plot_commodity_network = true + +# ------------------------------------ +# SOLVER +# Solver Selection +# ------------------------------------ + +# use the NEOS server to solve. (Currently NOT supported) +neos = false + +# solver (Mandatory) +# Depending on what client machine has installed. +# [cbc, appsi_highs, gurobi, cplex, ...] +solver_name = "cbc" + +# ------------------------------------ +# OUTPUTS +# select desired output products/files +# ------------------------------------ + +# generate an Excel file in the output_files folder +save_excel = true + +# save the duals in the output Database (may slow execution slightly?) +save_duals = true + +# save storage levels by time slice (may be a large amount of data) +save_storage_levels = true + +# save a copy of the pyomo-generated lp file(s) to the outputs folder (maybe a large file(s)!) +save_lp_file = false + +# ------------------------------------ +# MODEL PARAMETERS +# these are specific to each model +# ------------------------------------ + +# What seasons represent in the model +# Options: +# 'consecutive_days' +# Seasons are a set of days in order, with each season representing only one day. Examples +# might be a model of a representative week with 7 days or a whole-year model with 365 days. +# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. +# 'representative_periods' +# Each season represents a number of days, though not necessarily in any particular order. +# If using inter-season constraints like seasonal storage or ramp rates, the true sequence +# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in +# the Technology table. +# 'seasonal_timeslices' +# Each season represents a sequential slice of the year, with one or many days represented per +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out +# in the schema). This is an advanced feature and not recommended for most users. Seasonal +# storage must be tagged and the TimeSeasonSequential table filled. +time_sequencing = 'seasonal_timeslices' + +# How contributions to the planning reserve margin are calculated +# Options: +# 'static' +# Traditional planning reserve formulation. Contributions are independent of hourly availability: +# capacity value = net capacity * capacity credit +# 'dynamic' +# Contributions are available output including a capacity derate factor (e.g., forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = net capacity * reserve capacity derate * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * reserve capacity derate +reserve_margin = 'dynamic' + +# --------------------------------------------------- +# MODE OPTIONS +# options below are mode-specific and will be ignored +# if the run is not executed in that mode. +# --------------------------------------------------- +[MGA] +# see notes on these in the extensions/modeling_to_generate_alternatives folder readme.txt +cost_epsilon = 0.03 # proportional relaxation on optimal cost (ex: 0.05 = bound at 105% of original optimal cost) +iteration_limit = 55 # max iterations to perform +time_limit_hrs = 1 # max time +axis = "tech_category_activity" # use the tech activity Manager to control exploration based on categories in Tech +weighting = "hull_expansion" # use a convex hull expansion algorithm to weight exploration + +[myopic] +view_depth = 2 # number of periods seen/analyzed per iteration +step_size = 1 # number of periods to step by (must be <= view depth) + +[morris] +perturbation = 0.10 # amount to perturb marked parameters (ex: 0.10 -> +/- 10%) +levels = 8 # number of levels in param grid (must be even number) +trajectories = 10 # number of Morris trajectories to generate/explore +seed = false # random seed for use in generation/analysis for repeatable results. false=system derived +cores = 0 # number of CPU cores to use. 0 (default) = cpu count +# Note: Problem size (in general) is (Groups + 1) * trajectories see the SALib Dox +# Groups = number of unique labels used in MM analysis columns in DB + +[SVMGA] +cost_epsilon = 0.05 +# labels from appropriate tables in database. It is recommended to only use one of the lists below and leave +# the others blank +emission_labels = ['co2', 'nox'] +capacity_labels = ['TXD', 'TXG'] +activity_labels = [] + +[monte_carlo] +# a path from the PROJECT ROOT to the settings file that contains the run data. +run_settings = 'data_files/monte_carlo/run_settings_1.csv' diff --git a/temoa/tutorial_assets/utopia.sqlite b/temoa/tutorial_assets/utopia.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..1e3008d3b12e57f9f96e039101fc6e74d63e5a79 GIT binary patch literal 1028096 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%0D($0`3W0UyS8bh8o3IfHaTJcRqf)H zE2{{Ms+}>76(~;91f+gc=SwPP?m0~-Ft2vTv=l(FkYH%Kf8zH0hK$M+Hn8?r=}RA1 z_^J7MU8el{P6|MxMan+BI2Y2Z*yJD3_+r90YI%-~ad3_a2Tstr3`9yG9iZ zVk?6jfzh?=^JSXCF#y>zpZw+sOs@SIFy6g*e~ZB6+QSXvxXfKKyvfNsMg;=HYmaDv zK*Sv>0KBNYTj*KPnZEfJ?zO3U}RHhklU3c^R%&OJLbJF}i%p1|bV zBPlW0bLBxw5FhjUoWmZtNFy-2c7rd@No*oOC4t$sQLx#zeNp@n7D%Pw4Ij11+*!ZZ ze_kUn!gj?l?)o7Rim@S4j9pM0bTGp56EK3<=DT(;s6!k7H?pTYAAs~C{Mq2d*Rr;E zeiD1Mv;E7qDLVebp2ydm^HOYY(ly(l635{Au{1aQ|?F&H z2#lhAM-}u=6Hkir1ZL45Va-$n-33gMppDL7>#rhw8eNT^g*?pIq8YtZ7OJj$k*Ok02HyjyYvX3}oSk&G-nHk1S=;x&?%#Szb~3@GqnphjRO?RpBR z56GX7$3Zy)6KQv|ET1PpYWi!(3G>=aK2IYskM<}IWs%MEGU%9W|7!5L%Uh4q35=wx zpB$ESePAl>A%iSXIg-#gC`Vu@?RJFHzi|~BXTZCmc>)t@w*njaXq+FL)d5VTU5`LM zpZjJAGGE_5FyHpoxfKM)(XREeiDJGQ1;_${VYEkPUFuEvG*|pWDNkS^?P14eZidQ3 z{$f&ru#vRW?_=c22^%z%BmTYk0)dfqHH=s~GyW^R9N{Br$K+CC7#lI~Mi&T7q@4vY zcQ1Az1u(rSOr>2TG*0liPe(DFl&*|B z0@~@)8@4n4@&pFcu0ai%5eG8J|LG^+-@fFPsw%>!(oPA2U2HdPd>I)j=*Tz-ImMUDOB2gJewzcGVNGtAXBt)B?a=AhSTs<9r1fZ z!l%=Y65vW5i@<+pQAJ=t?VMv_7+cJtu;-4!t@{Ozsvqsv`A3(DEK8qu&=BNZMhC@~52>cZN> znXS%z{kuFljWVcCgrtW6Krn{@9qD@K>Pse=LWAZp>O8(c{of+|6#V`l>i<2N*D_-> zr=)k$d;dnJ+oraqo=;t!IzG8IIXgKl*($L$@myk9qGkMl@mcY!;wQ#_jJ*)MI@UV+ zWAwS`F#4Up&5>s!gCoa=H&K=c{|;*4pau?V;GhN$SOd8t42)ef7U}Czpc3yT6=7KH znlRvugVz9f&{JfiV&@t_7GpT|6N8>2Op0CNl$rU8IAtc_dYjJcHq~8vVy@^lE0zkt z5{TFAiZCno$hykvpz@cKi!d;DRiaJS1r;^_ouO9b17qi&HQxiCcLIaOtUad}VPx#A zMw#qb)mS*x0S3A(`-u$!H4k7tHcSHZ!)oZ?Y?zOI!C~=2X1&4tNfkwy6}xrk z&4wDr4);NYB8-ZipD(vA%-8yS|KnnWeg4KqzF3`cF$Vzpb&6huaj}OF#Z^3Kfv!u* z7hz!Rx8R{$5G_T1Ur0rf4U4N`0w{`A6=70L55QqCfW5DI1fqFR*d6#|+DpIQsS%hM zySXraj)oIQRcGP%|4sg7$Q3Jf0z+eGFD`9R$UserkL{XVtuET}*jSCg;Mh$D9L~$2 zXxw>0U~KGRirku+Hxa>*-=LKv6DR}sgv2x_?h4=}__Ys})85oe}>nit{QMCy#Y%j<0uEWW55XkKL%q!z<;k) zAY%Mt zGb1yOegW{v^v~&K>1pXp(ydebQfuiK0LP}fr4CDOPcBYQOJ0^dIT=fQmUtpDB5_(G z68|jzTzpczZ~R#LtAN$9f5)zkb&l1Fejc3}9T)8uZ5Y`~?*_apa&e?hL=CSCKT3Ze z&^EL$v^MlaXk4g!=*ZyD!R5gRgTst30Dc>o7r29d0kE0+v-*a5uR2gYNexjkeg3hF zCXIu|pJl`GNyb<9Ib8N?um?3wWzKTAd9;i-w-@Dh|KxP=q%ei#EWHJ~&7GN#s}{GY?k+c<|Yt${n< z8yvonWV=RKkmL78?N*saq^xkbd)sc6X-8wF!zn#r7E4%GB44^l`6mZkI@=Gqw5Fy` z?hFYdEo7o(UJ5rWHQ2~IKFFn&s7~Jj#oCm1(%J`e1b*V597KQL;k%(+7VL#N?piu| zRBMVLPIMqYAi zayKY{Kg|a8l}yxr%ETEzdAhV`*M;*S)dB9Zdu34kx5ftDr!-P$A@)`K_vDD17uvvIR%eZ1L?GZ3@J5&rZ<3Ff322z2Zlv~K(3NTT~Y&r=r?p+7ik(hmQ^6N1;qY`A${> zrAN&2KU{x-kFD>ATozPK{78eG@?^=r#BpKirIjd88iCo`3bP@nhSJstwX~G>K17j# zR?#=493_{SR$dYHQCSMhCASIY$}Wdm$7YEDo^r46H74woSA}S0EjR0POw?V*G;0az zatVT*+E5y)9pq#N0D$Y_O)TLy##;^qwhc~>#Vma!)Gm@@*c~sGnbT67sYiG+mN2_Y zGIme~D4|2!C@5o~Cu51o8~xH!i6aI~XmM1IMw#-PsUmlT%6x}12aO=iH6|W^77r@N zmi0jQf$n0%34Oz~tat%7|~j0tS3NId4a$)WgQHX(gAO+;%+ z8Eh;M#H7Kw7q2)Ul9S6H@z53yHV3VX(48*K4`hor~xniQW?0( zv|ntEA~X>yVk-J!LMk>ZqK9*cv*z|;Q8q5qLI{I4}9$K1K0&|%;J zMs0N%=Gz$9uwR@5^?x5_uaaGteKI>P+bNsPe4d#}?*QnLIU@aIdU5)`^rh+c^gDnb zrJkhI|E{T8$@R%6lGh}=BpW7vNGwe}Kz|QVNYsgMj=vtiJAP@rLp%_BFZO6`SWKhS z|BcaC=yw4IL|aD{+5vbXGB$F0q)zzD@U!7@;WNWWgnkUY8G0ZzG?WWv=pBL22PXti zr?&)d4!lag5^!Ol6}>6oUG?AU5cMP~;#;NFf64z7s4EL3`2CA=t5BYE0J!ZU(=4`D zW0f?E=c}>GGz(?50}!!<*e>q&PY-sX{3elDVn-$XWq=tW$xCpK$vMvH@9&f){>f?J zQ0qJ39CPP5r!S>V@IlQzH>haH(1 z0CMi~OH2<-`G*l`t!*+Xv_wrm&ka&qGd0-ZDTYLta=%|DjC?F{b?F|3N0odKji|tq#$H5X_YI#xYo{Ln}D|?Fb*#5@?frQv>e? zlDZU@mI4lNxyCqSYi)?+=KhZ!a@d<#0yF53m?gMvyoHv)RBL;)=G0W^oG;dpi_&|f zl*fFr=2`AZqNpm5(V~sa^-z6s4m5prMmK@7` z3c|V?m32U=0~XsxF152KV~KNRmM3FI3^4C4X>DL$>U?kUNeh1LQ!iSHa5dymVO(^?hW>|8*HuQkr=6={C%lO(4dubfk_-Ai)2p1VX z(pr#V>17x=Sqf8vPaA6JiTvn;oEsILJ}OInlJm~UG#{c%8~B?K=A0Tj9*6s5&Mn~_ zf6RdzW{b~=)VC~pa5ds!AR6i)i6v#>!)A%FnmP`7ymg5*nLmB6F%3p-#8hR8Ao4lL zT-3viuwc#ME!1Ev=X|4rkQ;r;)ovlFttvPWfhWL9Jz%3PHxWNN23(t7}I zO`n}^Om6~sHFZboLi)bw{^Z)^^yJ87r)1s4ro=0WTN39bn#8xo=TSBX{|;*4pau?V z;GhN$YT%#-4r<__2D~-kP!i&w5to;QJ;l7EEVZ>=Ba++WsihKDd2XXR}yrjUx((`fqc&nV8${zPe&ATWU_!EU!k7@%^+?CaX zTojvnP>qNs_C|x32$MO?p|-O=#WWb@ao=l9dr|8-6m9Z3$Xt{={8Ag%@{Kn&vXzB? zso_m5mCw~Ibu5yb@iruxY4p@=CN<`4TH1*wYhF96k}XRxk_SAAk%_$Pi Date: Fri, 14 Nov 2025 14:16:20 -0500 Subject: [PATCH 329/587] adding main.py to temoa root to make cli invocation consistent --- temoa/__main__.py | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 temoa/__main__.py diff --git a/temoa/__main__.py b/temoa/__main__.py new file mode 100644 index 000000000..610b96473 --- /dev/null +++ b/temoa/__main__.py @@ -0,0 +1,4 @@ +from .cli import app + +if __name__ == '__main__': + app() From aa63e71c9420787f1384c1dad508c0575946ca43 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 14 Nov 2025 15:57:59 -0500 Subject: [PATCH 330/587] updated readme --- README.md | 427 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 281 insertions(+), 146 deletions(-) diff --git a/README.md b/README.md index ca3c01f69..0b9c25f16 100644 --- a/README.md +++ b/README.md @@ -1,246 +1,381 @@ -# Getting Started with TEMOA Version 4.0.0a1 +# TEMOA Version 4.0.0a1 + +[![CI](https://github.com/TemoaProject/temoa/actions/workflows/ci.yml/badge.svg?branch=unstable)](https://github.com/TemoaProject/temoa/actions/workflows/ci.yml) +[![Documentation Status](https://readthedocs.org/projects/temoa/badge/?version=latest)](https://temoa.readthedocs.io/en/latest/?badge=latest) +[![Python 3.12+](https://img.shields.io/badge/python-3.12%2B-blue)](https://pyreadiness.org/3.12/) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![Type Checked with mypy](https://img.shields.io/badge/type--checked-mypy-blue?style=flat-square&logo=python)](https://img.shields.io/badge/type--checked-mypy-blue?style=flat-square&logo=python) +[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) +[![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv) ## Overview TEMOA (Tools for Energy Model Optimization and Analysis) is a sophisticated energy systems optimization framework that supports various modeling approaches including perfect foresight, myopic planning, uncertainty analysis, and alternative generation. -### Package Structure +## Quick Start -The main subdirectories in the project are: +### Using uv (Recommended) -1. **`temoa/`** - Main package directory - - **`temoa.core`** - Public API for end users (TemoaModel, TemoaConfig, TemoaMode) - - **`temoa._internal`** - Private implementation modules (not for public use) - - **`temoa.data_processing`** - Post-processing and output utilities - - **`temoa.extensions`** - Optional extensions for different modeling approaches - - **`temoa.utilities`** - Helper scripts and database utilities - - **`temoa.model_checking`** - Model validation and integrity checking +The fastest way to get started with Temoa: -2. **`data_files/`** - Input data files and configuration examples -3. **`tests/`** - Comprehensive test suite -4. **`docs/`** - Documentation source files -5. **`notebooks/`** - Jupyter notebooks for analysis and examples +```bash +# Install uv if you haven't already +curl -LsSf https://astral.sh/uv/install.sh | sh -### Installation +``` -TEMOA can be installed as a pip package: +Bleeding-edge nightly development installation: ```bash +uv add temoa --default-index https://pypi.temoaproject.org/simple/ --index https://pypi.org/simple/ + +# or + +pip install --index-url https://temoaproject.github.io/temoa-nightlies/simple/ temoa --extra-index-url https://pypi.org/simple/ + +``` + +Or clone the repository and install in development mode: + +```bash + +# Clone and setup development environment +git clone https://github.com/TemoaProject/temoa.git +cd temoa +uv sync --all-extras --dev + +# Run your first model +uv run temoa tutorial my_first_model +uv run temoa run my_first_model_config.toml +``` + +### Standard Installation + +```bash +# Install from PyPI (not yet available) +pip install temoa + +# Or install from source pip install -e . ``` -Or using the provided requirements file: +### Get Started in 30 Seconds ```bash -pip install -r requirements.txt +# Create tutorial files +temoa tutorial quick_start + +# Run the model +temoa run quick_start_config.toml ``` -## Guide to Setup +## Package Structure + +The Temoa package is organized into clear modules: + +- **`temoa.core`** - Public API for end users (TemoaModel, TemoaConfig, TemoaMode) +- **`temoa.cli`** - Command-line interface and utilities +- **`temoa.components`** - Model components and constraints +- **`temoa.data_io`** - Data loading and validation +- **`temoa.extensions`** - Optional extensions for different modeling approaches + - `modeling_to_generate_alternatives` - MGA analysis + - `method_of_morris` - Sensitivity analysis + - `monte_carlo` - Uncertainty quantification + - `myopic` - Sequential decision making +- **`temoa.model_checking`** - Model validation and integrity checking +- **`temoa.data_processing`** - Output analysis and visualization +- **`temoa.utilities`** - Helper scripts and migration tools + +## Installation & Setup -1. Obtain a current copy of Python from the python.org website. The model has been tested with 3.11 and 3.12. It will -fail (raise error) on earlier versions. -2. A `requirements.txt` file has been included to allow for use of `pip` to populate a virtual environment. In order to use that the steps are: +### Development Installation -- Ensure you have a copy of python 3.11/3.12 installed on your machine ([python.org](https://www.python.org)) -- Make and activate a virtual environment using the `venv` package: +For users who want to contribute or modify Temoa should install in development mode using `uv`: +```bash +# Clone repository +git clone https://github.com/TemoaProject/temoa.git +cd temoa + +# Setup development environment with uv +uv sync --all-extras --dev + +# Install pre-commit hooks +uv run pre-commit install + +# Run tests +uv run pytest + +# Run type checking +uv run mypy +``` + +## Command Line Interface + +Temoa provides a modern, user-friendly CLI built with Typer: + +### Basic Commands + +**Run a model:** + +```bash +temoa run config.toml +temoa run config.toml --output results/ +temoa run config.toml --build-only # Build without solving +``` + +**Validate configuration:** + +```bash +temoa validate config.toml +temoa validate config.toml --debug +``` + +**Database migration:** + +```bash +temoa migrate old_database.sql --output new_database.sql +temoa migrate old_database.db --type db +temoa migrate old_database.sqlite --output migrated_v4.sqlite ``` -python3.11 -m venv venv -source venv/bin/activate # for linux/osx, windows activation command may differ + +**Generate tutorial files:** + +```bash +temoa tutorial # Creates tutorial_config.toml and tutorial_database.sqlite +temoa tutorial my_model my_db # Custom names ``` -- Verify that you have a prepended indicator on your cursor that you are in the virtual environment (see below) -- After activating the venv, use `pip` *within* the venv to install everything. Most IDEs have automated tools to -help set up and associate this venv with the project. It is also possible from the command line: +### Global Options +```bash +temoa --version # Show version information +temoa --how-to-cite # Show citation information +temoa --help # Full help ``` -(venv) $ pip install -r requirements.txt + +### Using with uv + +When working with the source code, use `uv run` to ensure you're using the correct dependencies: + +```bash +uv run temoa run config.toml # Run with project dependencies +uv run temoa validate config.toml # Validate configuration +uv run temoa tutorial my_first_model # Create tutorial files ``` -- For Conda users, an environment.yml file is provided that is not currently fully tested. Additional installs may -be required. +## Programmatic Usage -3. **Usage as a Library**: Import and use TEMOA programmatically: +You can use Temoa as a Python library: ```python import temoa +from pathlib import Path from temoa import TemoaModel, TemoaConfig, TemoaMode # Create configuration config = TemoaConfig( scenario="my_scenario", scenario_mode=TemoaMode.PERFECT_FORESIGHT, - input_database="path/to/input.db", - output_database="path/to/output.db", - output_path="path/to/output", - solver_name="gurobi" + input_database=Path("path/to/input.db"), + output_database=Path("path/to/output.db"), + output_path=Path("path/to/output"), + solver_name="cbc" ) # Build and solve model -model = TemoaModel() -# ... (additional usage) +model = TemoaModel(config) +result = model.run() # Equivalent to: temoa run config.toml + +# Check if run was successful +if result: + print("Model solved successfully!") +else: + print("Model failed to solve") ``` -4. **Command Line Usage**: Use the main entry point: +## Database Setup + +### Quick Setup with Tutorial + +The fastest way to get started: ```bash -python -m temoa --config data_files/my_configs/config_sample.toml +temoa tutorial ``` -## Database Setup +This creates: -- Several sample database files in Version 3 format are provided in SQL format for learning/testing. These are provided in the -`data_files/example_dbs` folder. In order to use them, they must be converted into sqlite database files. This can -be done from the command line using the sqlite3 engine to convert them. sqlite3 is packaged with Python and should be -available. If not, most configuration managers should be able to install it. The command to make the `.sqlite` file -is (for Utopia as an example): +- `tutorial_config.toml` - Configuration file with example settings +- `tutorial_database.sqlite` - Sample database for learning -``` -(venv) $ sqlite3 utopia.sqlite < utopia.sql -``` - -- Converting legacy db's to Version 3 can be done with the included database migration tool. Users who use this -tool are advised to carefully review the console outputs during conversion to ensure accuracy and check the -converted database carefully. The migration tool will build an empty new Version 3 database and move data from -the old database, preserving the legacy database in place. The command can be run from the top level of the -project and needs pointers to the target database and the Version 3 schema file. A typical execution from top level -should look like: +**Migration from older versions:** ```bash -python -m temoa.utilities.db_migration_to_v3 --source data_files/.sqlite --schema data_files/temoa_schema_v3.sql -``` +# Migrate from v3.1 to v4 +temoa migrate old_database_v3.1.sql --output new_database_v4.sql -- Users may also create a blank full or minimal version of the database from the two schema files in the `data_files` -directory as described above using the `sqlite3` command. The "minimal" version excludes some of the group -parameters and is recommended as a starting point for entry-level models. It can be upgraded to the full set of -tables by executing the full schema SQL command on the resulting database later, which will add the missing tables. +# or for SQLite databases +temoa migrate old_database_v4.sqlite --output new_database_v4.sqlite +``` -## Config Files +## Configuration Files -- A configuration (config) file is required to run the model. The `sample_config.toml` is provided as a reference -and has all parameters in it. It can be copied/renamed, etc. -- Notes on Config Options: +A configuration file is required to run the model. The tutorial command creates a complete example: -| Field | Notes | -|------------------------|------------------------------------------------------------------------------------------------------------| -| Scenario Name | A name used in output tables for results (cannot contain dash '-' symbol) | -| Temoa Mode | The execution mode. See note below on currently supported modes | -| Input/Output DB | The source (and optionally diffent) output database. Note for myopic, MGA input must be same as output | -| Price Checking | Run the "price checker" on the built model to look for costing deficiencies and log them | -| Source Tracing | Check the integrity of the commodity flow network in every region-period combination. Required for Myopic | -| Plot Commodity Network | Produce HTML (viewable in any browser) displays of the networks built (see note at bottom) | -| Solver | The exact name of the solver executable to call | -| Save Excel | Save core output data to excel files. Needed if user intends to use the graphviz post-processing modules | -| Save LP | Save the created LP model files | -| Save Duals | Save the values of the Dual Variables in the Output Tables. (Only supported by some solvers) | -| Mode Specific Settings | See the README files within mode folders for up-to-date values | +```toml +scenario = "tutorial" +scenario_mode = "perfect_foresight" +input_database = "tutorial_database.sqlite" +output_database = "tutorial_database.sqlite" +solver_name = "cbc" +``` -## Currently Supported Modes +### Configuration Options -### Check +| Field | Notes | +|-------|-------| +| Scenario Name | Name used in output tables (cannot contain '-' symbol) | +| Temoa Mode | Execution mode (PERFECT_FORESIGHT, MYOPIC, MGA, etc.) | +| Input/Output DB | Source and output database paths | +| Price Checking | Run pricing analysis on built model | +| Source Tracing | Verify commodity flow network integrity | +| Plot Network | Generate HTML network visualizations | +| Solver | Solver executable name (cbc, gurobi, cplex, etc.) | +| Save Excel | Export core output to Excel files | +| Save LP | Save LP model files for external solving | -Build the model and run the numerous checks on it. Results will be in the log file. No solve is attempted. -Note: The LP file for the model can be saved with this option and solved later/independently by selecting -the ``save_lp_file`` option in the config. +## Supported Modes ### Perfect Foresight -All-in-one run that solves the entire model at once. It is possible to run this without source tracing, which will -use raw data in the model without checking the integrity of the underlying network. It is highly advised to use -source tracing for most accurate results. +Solves the entire model at once. Most common mode for optimization. ### Myopic -Solve the model sequentially through iterative solves based on Myopic settings. Source tracing is required to -accommodate build/no-build decisions made per iteration to ensure follow-on models are well built. +Sequential solving through iterative builds. Required for stepwise decision analysis. ### MGA (Modeling to Generate Alternatives) -An iterative solving process to explore near cost-optimal solutions. See the documentation on this mode. +Explores near cost-optimal solutions for robustness analysis. ### SVMGA (Single Vector MGA) -A sequence of 2 model solves that establishes a base optimal cost, then relaxes the cost then minimizes an -alternate unweighted objective function comprised of variables associated with labels selected in lists in the -config file. +Two-solve process focusing on specific variables in the objective. ### Method of Morris -A limited sensitivity analysis of user-selected variables using a Method of Morris approach. See the documentation -on this mode. +Limited sensitivity analysis of user-selected variables. ### Build Only -Mostly for test/troubleshooting. This builds/returns an un-solved model. +Builds model without solving. Useful for validation and troubleshooting. -Several other options are possible to pass to the main execution command including changing the logging level to -`debug` or running silent (no console feedback) which may be best for server runs. Also, redirecting the output -products is possible. To see available options invoke the `main.py` file with the `-h` flag: +## Typical Workflow -```bash -python -m temoa --help -``` +1. **Setup**: Create configuration and database files: -## Typical Run + ```bash + temoa tutorial my_project + ``` -1. Prepare a database (or copy of one) as described above. Runs will fill the output tables and overwrite any data with the -same scenario name. -2. Perepare a config file with paths to the database(s) relative to the top of the project, as in the example -3. Run the model using the module entry point: +2. **Configure**: Edit the configuration file to match your scenario -```bash -python -m temoa --config data_files/my_configs/config_sample.toml -``` +3. **Validate**: Check configuration before running: -4. Review the config display and accept -5. Review the log file and output products which are automatically placed in a time-stamped folder in `output_files`, -unless user has redirected output -6. Review the data in the Output tables + ```bash + temoa validate my_project_config.toml + ``` -## Testing +4. **Run**: Execute the model: -Users who wish to exercise the `pytest` based test in the test folder can do so from the command line or any IDE. -Note that many of the tests perform solves on small models using the freely available `cbc` solver, which is -required to run the testing suite. + ```bash + temoa run my_project_config.toml + ``` -The tests should all run and pass (several are currently skipped and reflect in-process work). Tests should normally -be run from the top level of the `tests folder`. If `pytest` is installed it will locate tests within the folder and -run/report them. Note the dot '.' below indicating current folder: +5. **Review**: Check results in `output_files/YYYY-MM-DD_HHMMSS/` -```bash -python -m pytest tests/ -``` +6. **Iterate**: Modify configuration and run again + +## Advanced Features + +### Extensions + +Temoa includes optional extensions for advanced analysis: + +- **Monte Carlo**: Uncertainty quantification +- **Stochastic Programming**: Scenario-based optimization +- **Method of Morris**: Sensitivity analysis + +### Data Processing + +- Excel output generation +- Graphviz network visualization +- Interactive network diagrams + +### Model Validation -Several of the packages used may currently generate warnings during this testing process, but the tests should all PASS -with the exception of skipped tests. +- Built-in validation checks +- Commodity flow verification +- Price consistency analysis -## Documentation and Additional Information +### Solver Dependencies -The full Temoa documentation can be built by following the build README file in the Documentation folder. +TEMOA requires at least one optimization solver: -## Hot Fix for Network Plots on Windows Machines +- **Free**: [CBC](https://github.com/coin-or/Cbc) + - Requires separate installation (see [CBC documentation](https://github.com/coin-or/Cbc)) + - Required for tutorial and testing -Users wishing to utilize the feature to make the html network plots of the energy network using the -`plot_commodity_network` option in the config file who are working on Windows Operating System may need to make a -"hot fix" to the library code. See note here: +- **Commercial**: Gurobi, CPLEX, or Xpress + - Requires separate license and installation + - See individual solver documentation -The `gravis` library which nicely makes these plots appears to currently be non-maintained and a 1-line fix is -likely needed to avoid error on Windows machines: +## Troubleshooting -1. Within the `venv` that contains project dependencies, navigate to the `gravis` folder -2. Open the file `gravis/_internal/plotting/data_structures.py` and edit line 120 to include the encoding flag: +### Solver Issues - `with open(filepath, 'w', encoding='utf-8') as file_handle:` +If you encounter solver errors: -## Hot Fix for Graphviz +```bash +# For commercial solvers (Gurobi, CPLEX) +pip install ".[solver]" # Include specific solver packages + +# For free solver +temoa run config.toml --debug # Get detailed error information +``` + +## Documentation & Support + +- **Full Documentation**: Built by following docs/README.md +- **API Reference**: See `temoa.core` module for public API +- **GitHub Issues**: Report bugs and request features +- **Tutorials**: Run `temoa tutorial` for guided examples -Users wishing to utilize the `graphviz` package to visualize results as described in the `README.md` file -in the `data_processing` package/folder may need to re-install `graphviz` using another delivery means -other than `pip`. The current `requirements.txt` will attempt to install `graphviz`, but according to -their project page, this needs to be done with another configuration manager like `apt` or `homebrew`. +## Code Style & Quality -Mac users wishing to use `graphviz` should re-install using `homebrew` with the command: +For contributors: -`brew install graphviz` +- **Ruff**: Code formatting and linting +- **mypy**: Type checking +- **pytest**: Testing framework +- **Pre-commit**: Automated quality checks + +See CONTRIBUTING.md for detailed development guidelines. + +## Citation + +If you use Temoa in your research, please cite: + +```bibtex +@article{hunter2013modeling, + title={Modeling for insight using Tools for Energy Model Optimization and Analysis (Temoa)}, + journal={Energy Economics}, + volume={40}, + pages={339--349}, + year={2013}, + doi={10.1016/j.eneco.2013.07.014} +} +``` -(Any Windows users who have tips/info on this are asked to submit a PR to this file to update this section.) +Or use: `temoa --how-to-cite` From 8d834c0bdbf87cc87ec9a3c0bace93d621c7a863 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Mon, 17 Nov 2025 09:59:20 -0500 Subject: [PATCH 331/587] fixing readme inconsistency --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0b9c25f16..a7873e06b 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,8 @@ curl -LsSf https://astral.sh/uv/install.sh | sh Bleeding-edge nightly development installation: +In a directory initialized with uv (e.g., `uv init .`) run: + ```bash uv add temoa --default-index https://pypi.temoaproject.org/simple/ --index https://pypi.org/simple/ @@ -46,7 +48,7 @@ uv sync --all-extras --dev # Run your first model uv run temoa tutorial my_first_model -uv run temoa run my_first_model_config.toml +uv run temoa run my_first_model.toml ``` ### Standard Installation @@ -66,7 +68,7 @@ pip install -e . temoa tutorial quick_start # Run the model -temoa run quick_start_config.toml +temoa run quick_start.toml ``` ## Package Structure From cf1e5ea276d039442df37e890573e83623d67a25 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sun, 16 Nov 2025 20:19:25 -0500 Subject: [PATCH 332/587] adding typing to tests --- .github/workflows/ci.yml | 2 +- pyproject.toml | 8 +- tests/legacy_test_values.py | 23 ---- tests/test_cli.py | 45 ++++--- tests/test_element_checker.py | 40 ++---- tests/test_emission_results.py | 62 ++++++--- tests/test_exchange_cost_ledger.py | 81 ++++++----- tests/test_full_runs.py | 40 ++---- tests/test_hull.py | 54 ++------ tests/test_linked_tech.py | 8 +- tests/test_mc_run.py | 70 ++++------ tests/test_myopic_sequencer.py | 34 +---- tests/test_network_model_data.py | 34 +++-- tests/test_pricing_check.py | 49 +++---- tests/test_set_consistency.py | 4 +- tests/test_source_check.py | 202 ++++++++++++++++------------ tests/test_storage.py | 27 ++-- tests/test_table_writer.py | 140 +++++++++---------- tests/test_tech_activity_vectors.py | 29 +--- tests/test_temoa_sequencer.py | 17 ++- tests/test_validators.py | 59 ++++---- tests/utilities/namespace_mock.py | 31 +---- 22 files changed, 469 insertions(+), 590 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 89cf12a51..d0df95f29 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -74,4 +74,4 @@ jobs: run: uv sync --locked --all-extras --dev - name: Run mypy - run: uv run mypy --config-file=pyproject.toml temoa/ + run: uv run mypy --config-file=pyproject.toml . diff --git a/pyproject.toml b/pyproject.toml index 6814e538e..74ffa9ae4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,6 @@ authors = [ { name = "TemoaProject Team", email = "info@temoaproject.org" } ] - dependencies = [ "pyomo>=6.8.0", "matplotlib==3.9.2", @@ -96,6 +95,7 @@ select = [ "I", # isort "B", # flake8-bugbear "N", # flake8-naming + "G004" # logging-f-string ] ignore = [ "E501", # line too long temporarily ignored @@ -126,7 +126,7 @@ python_version = "3.12" mypy_path = "stubs" # Exclude specific directories from type checking will try to add them back gradually -exclude = "(?x)(^tests/|^temoa/extensions/|^temoa/utilities/)" +exclude = "(?x)(^temoa/extensions/|^temoa/utilities/|^stubs/)" # Strict typing for our own code disallow_untyped_defs = true @@ -169,6 +169,10 @@ check_untyped_defs = true module = "temoa.types.*" disallow_any_explicit = false +# More lenient settings for test files to accommodate pytest decorators and test-specific patterns +[[tool.mypy.overrides]] +module = "tests.*" +disallow_any_decorated = false [project.urls] diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index 6e8006f2e..b4a355a9a 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -2,29 +2,6 @@ a container for test values from legacy code (Python 3.7 / Pyomo 5.5) captured for continuity/development testing -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 6/27/23 - -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . """ from enum import Enum diff --git a/tests/test_cli.py b/tests/test_cli.py index ba97d1e9a..d3a894c5e 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,6 +1,7 @@ import shutil from pathlib import Path +import pytest from typer.testing import CliRunner from temoa.cli import _is_writable, app @@ -27,14 +28,14 @@ def create_test_config(tmp_path: Path, db_path: Path) -> Path: return test_config_path -def test_cli_version(): +def test_cli_version() -> None: """Test the `temoa --version` command.""" result = runner.invoke(app, ['--version']) assert result.exit_code == 0 assert 'Temoa Version' in result.stdout -def test_cli_run_command_success_silent(tmp_path): +def test_cli_run_command_success_silent(tmp_path: Path) -> None: """Test a successful silent run of the `temoa run` command.""" db_path = Path(__file__).parent / 'testing_outputs' / 'utopia.sqlite' test_config_path = create_test_config(tmp_path, db_path) @@ -47,7 +48,7 @@ def test_cli_run_command_success_silent(tmp_path): assert (tmp_path / 'temoa-run.log').exists() -def test_cli_run_build_only_silent(tmp_path): +def test_cli_run_build_only_silent(tmp_path: Path) -> None: """Test the `temoa run --build-only --silent` flags.""" db_path = Path(__file__).parent / 'testing_outputs' / 'utopia.sqlite' test_config_path = create_test_config(tmp_path, db_path) @@ -65,7 +66,7 @@ def test_cli_run_build_only_silent(tmp_path): # ============================================================================= -def test_cli_validate_success_verbose(tmp_path): +def test_cli_validate_success_verbose(tmp_path: Path) -> None: """Test a successful verbose run of the `temoa validate` command.""" db_path = Path(__file__).parent / 'testing_outputs' / 'utopia.sqlite' test_config_path = create_test_config(tmp_path, db_path) @@ -77,7 +78,7 @@ def test_cli_validate_success_verbose(tmp_path): assert (tmp_path / 'temoa-run.log').exists() -def test_cli_validate_success_silent(tmp_path): +def test_cli_validate_success_silent(tmp_path: Path) -> None: """Test a successful silent run of the `temoa validate` command.""" db_path = Path(__file__).parent / 'testing_outputs' / 'utopia.sqlite' test_config_path = create_test_config(tmp_path, db_path) @@ -89,7 +90,7 @@ def test_cli_validate_success_silent(tmp_path): assert (tmp_path / 'temoa-run.log').exists() -def test_cli_validate_failure_on_invalid_db(tmp_path): +def test_cli_validate_failure_on_invalid_db(tmp_path: Path) -> None: """Test a failing run of `temoa validate` with an invalid database.""" # Create a file that is not a valid Temoa database (an empty file). # This will cause the version check inside the sequencer to fail. @@ -108,7 +109,7 @@ def test_cli_validate_failure_on_invalid_db(tmp_path): assert (tmp_path / 'temoa-run.log').exists() -def test_cli_run_missing_config(): +def test_cli_run_missing_config() -> None: """Test graceful failure for a missing config file.""" args = ['run', 'non_existent_file.toml'] result = runner.invoke(app, args) @@ -123,7 +124,7 @@ def test_cli_run_missing_config(): # ============================================================================= -def test_cli_migrate_help(): +def test_cli_migrate_help() -> None: """Test the `temoa migrate --help` command.""" result = runner.invoke(app, ['migrate', '--help']) assert result.exit_code == 0 @@ -131,7 +132,7 @@ def test_cli_migrate_help(): assert 'Migrate a single Temoa database file' in result.stdout -def test_cli_migrate_sql_file(tmp_path): +def test_cli_migrate_sql_file(tmp_path: Path) -> None: """Test migrating a SQL file with explicit --output.""" # Ensure input file is available in the test environment (e.g., copied from data_files) input_file_src = Path(__file__).parent.parent / 'data_files' / 'temoa_basics_0.sql' @@ -147,7 +148,7 @@ def test_cli_migrate_sql_file(tmp_path): assert output_file.exists() -def test_cli_migrate_rejects_directory_input(tmp_path): +def test_cli_migrate_rejects_directory_input(tmp_path: Path) -> None: """Test that the migrate command rejects a directory as input.""" dummy_dir = tmp_path / 'my_dummy_dir' dummy_dir.mkdir() @@ -159,7 +160,7 @@ def test_cli_migrate_rejects_directory_input(tmp_path): assert str(dummy_dir) in result.stdout -def test_cli_migrate_sql_file_auto_output_writable_input_dir(tmp_path): +def test_cli_migrate_sql_file_auto_output_writable_input_dir(tmp_path: Path) -> None: """ Test migrating a SQL file without --output, where the input directory is writable. @@ -183,8 +184,8 @@ def test_cli_migrate_sql_file_auto_output_writable_input_dir(tmp_path): def test_cli_migrate_sql_file_auto_output_non_writable_input_dir_fallback_cwd( - tmp_path, monkeypatch -): + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: """ Test migrating a SQL file without --output, where the input directory is NOT writable. @@ -230,7 +231,9 @@ def mock_is_writable(path: Path) -> bool: assert not (non_writable_mock_parent / (input_file.stem + '_v4.sql')).exists() -def test_cli_migrate_sql_file_auto_output_no_writable_location(tmp_path, monkeypatch): +def test_cli_migrate_sql_file_auto_output_no_writable_location( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: """ Test migrating a SQL file without --output, where neither the input directory nor the CWD are writable. @@ -261,7 +264,7 @@ def mock_is_writable_always_false(_path: Path) -> bool: ).exists() # No output created -def test_cli_migrate_invalid_file(): +def test_cli_migrate_invalid_file() -> None: """Test migrating a non-existent file.""" args = ['migrate', 'non_existent.sql'] result = runner.invoke(app, args) @@ -271,7 +274,7 @@ def test_cli_migrate_invalid_file(): assert 'does not exist' in result.stderr or 'does not exist' in str(result.exception) -def test_cli_migrate_unknown_type(tmp_path): +def test_cli_migrate_unknown_type(tmp_path: Path) -> None: """Test migrating a file with unknown extension.""" unknown_file = tmp_path / 'unknown.txt' unknown_file.write_text('dummy') @@ -282,7 +285,7 @@ def test_cli_migrate_unknown_type(tmp_path): assert 'Cannot determine migration type' in result.stdout -def test_cli_migrate_override_type(tmp_path): +def test_cli_migrate_override_type(tmp_path: Path) -> None: """Test migrating with explicit type override.""" input_file_src = Path(__file__).parent.parent / 'data_files' / 'temoa_basics_0.sql' input_file = tmp_path / 'test_input_override.sql' @@ -297,7 +300,7 @@ def test_cli_migrate_override_type(tmp_path): assert output_file.exists() -def test_cli_migrate_sql_file_silent(tmp_path): +def test_cli_migrate_sql_file_silent(tmp_path: Path) -> None: """Test migrating a SQL file with --silent flag.""" input_file_src = Path(__file__).parent.parent / 'data_files' / 'temoa_basics_0.sql' input_file = tmp_path / 'test_input_silent.sql' @@ -313,7 +316,7 @@ def test_cli_migrate_sql_file_silent(tmp_path): assert output_file.exists() -def test_cli_migrate_db_file_silent(tmp_path): +def test_cli_migrate_db_file_silent(tmp_path: Path) -> None: """Test migrating a DB file with --silent flag.""" import sqlite3 # Ensure sqlite3 is imported for this test if not already at top level @@ -335,8 +338,8 @@ def test_cli_migrate_db_file_silent(tmp_path): def test_cli_migrate_sql_file_auto_output_non_writable_input_dir_fallback_cwd_silent( - tmp_path, monkeypatch -): + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: """ Test migrating a SQL file with --silent, where input dir is not writable. Output should fall back to CWD, and the warning should NOT be printed. diff --git a/tests/test_element_checker.py b/tests/test_element_checker.py index a7b54e8ee..5e43ed2ed 100644 --- a/tests/test_element_checker.py +++ b/tests/test_element_checker.py @@ -1,36 +1,12 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 4/25/24 - -""" +from typing import Any import pytest from temoa.model_checking.element_checker import ViableSet, filter_elements -params = [ +ParamType = dict[str, Any] +ElementType = tuple[Any, ...] | str | int +params: list[ParamType] = [ { 'name': 'group 1', 'filt': ViableSet( @@ -131,8 +107,8 @@ ] -@pytest.mark.parametrize('data', params, ids=(param['name'] for param in params)) -def test_filter_elements(data): +@pytest.mark.parametrize('data', params, ids=[param['name'] for param in params]) +def test_filter_elements(data: ParamType) -> None: # use the 'tester' elements against the filter to ensure we get expected results assert ( filter_elements( @@ -142,9 +118,9 @@ def test_filter_elements(data): ) -def test_dimension_measurement(): +def test_dimension_measurement() -> None: """quick test to ensure we are getting the correct dimension esp. when elements are not tuple""" - elements = [(1, 2), (3, 4)] + elements: list[ElementType] = [(1, 2), (3, 4)] assert ViableSet(elements).dim == 2 elements = ['dog', 'pig', 'uncle bob'] diff --git a/tests/test_emission_results.py b/tests/test_emission_results.py index f421bea29..04daebab6 100644 --- a/tests/test_emission_results.py +++ b/tests/test_emission_results.py @@ -5,7 +5,9 @@ import logging import sqlite3 +from collections.abc import Generator from pathlib import Path +from typing import TypedDict, cast import pytest @@ -15,14 +17,26 @@ logger = logging.getLogger(__name__) +type SolvedConnection = tuple[sqlite3.Connection, str, str, float] + + +# Define a TypedDict for the test parameters to provide better type hints +class TechTestParams(TypedDict): + name: str + tech: str + target: float + @pytest.fixture(scope='module') -def solved_connection(request, tmp_path_factory): +def solved_connection( + request: pytest.FixtureRequest, tmp_path_factory: pytest.TempPathFactory +) -> Generator[SolvedConnection, None, None]: """ Spins up the model, solves it, and hands over a connection to the results db. This fixture is now updated to use the refactored TemoaSequencer API. """ - logger.info(f'Setting up and solving for test case: {request.param["name"]}') + param = cast(TechTestParams, request.param) + logger.info('Setting up and solving for test case: %s', param['name']) config_file = Path(__file__).parent / 'testing_configs' / 'config_emissions.toml' tmp_path = tmp_path_factory.mktemp('data') @@ -35,13 +49,13 @@ def solved_connection(request, tmp_path_factory): con = sqlite3.connect(sequencer.config.output_database) try: - yield con, request.param['name'], request.param['tech'], request.param['target'] + yield con, param['name'], param['tech'], param['target'] finally: con.close() # List of tech archetypes to test and their correct emission value -emissions_tests = [ +emissions_tests: list[TechTestParams] = [ {'name': 'ordinary archetype', 'tech': 'TechOrdinary', 'target': 0.3}, {'name': 'curtailment archetype', 'tech': 'TechCurtailment', 'target': 0.3}, {'name': 'annual archetype', 'tech': 'TechAnnual', 'target': 1.0}, @@ -49,10 +63,10 @@ def solved_connection(request, tmp_path_factory): {'name': 'annual flex archetype', 'tech': 'TechAnnualFlex', 'target': 1.0}, {'name': 'total', 'tech': '%', 'target': 3.6}, ] -embodied_tests = [ +embodied_tests: list[TechTestParams] = [ {'name': 'embodied archetype', 'tech': 'TechEmbodied', 'target': 0.3}, ] -eol_tests = [ +eol_tests: list[TechTestParams] = [ {'name': 'end of life archetype', 'tech': 'TechEndOfLife', 'target': 0.3}, ] @@ -64,7 +78,7 @@ def solved_connection(request, tmp_path_factory): indirect=True, ids=[t['name'] for t in emissions_tests], ) -def test_emissions(solved_connection): +def test_emissions(solved_connection: SolvedConnection) -> None: """ Test that the emissions from each technology archetype are correct, and check total emissions """ @@ -88,7 +102,9 @@ def test_emissions(solved_connection): indirect=True, ids=[t['name'] for t in emissions_tests], ) -def test_emissions_costs_undiscounted(solved_connection): +def test_emissions_costs_undiscounted( + solved_connection: SolvedConnection, +) -> None: """ Test that the undiscounted emission costs from each technology archetype are correct """ @@ -113,7 +129,9 @@ def test_emissions_costs_undiscounted(solved_connection): indirect=True, ids=[t['name'] for t in emissions_tests], ) -def test_emissions_costs_discounted(solved_connection): +def test_emissions_costs_discounted( + solved_connection: SolvedConnection, +) -> None: """ Test that the discounted emission costs from each technology archetype are correct """ @@ -138,7 +156,7 @@ def test_emissions_costs_discounted(solved_connection): indirect=True, ids=[t['name'] for t in embodied_tests], ) -def test_embodied_emissions(solved_connection): +def test_embodied_emissions(solved_connection: SolvedConnection) -> None: """ Test that the embodied emissions from each technology archetype are correct, and check total emissions """ @@ -162,7 +180,9 @@ def test_embodied_emissions(solved_connection): indirect=True, ids=[t['name'] for t in embodied_tests], ) -def test_embodied_emissions_costs_undiscounted(solved_connection): +def test_embodied_emissions_costs_undiscounted( + solved_connection: SolvedConnection, +) -> None: """ Test that the undiscounted embodied emission costs from each technology archetype are correct """ @@ -187,7 +207,9 @@ def test_embodied_emissions_costs_undiscounted(solved_connection): indirect=True, ids=[t['name'] for t in embodied_tests], ) -def test_embodied_emissions_costs_discounted(solved_connection): +def test_embodied_emissions_costs_discounted( + solved_connection: SolvedConnection, +) -> None: """ Test that discounted embodied emission costs from each technology archetype are correct """ @@ -214,7 +236,7 @@ def test_embodied_emissions_costs_discounted(solved_connection): indirect=True, ids=[t['name'] for t in eol_tests], ) -def test_endoflife_emissions(solved_connection): +def test_endoflife_emissions(solved_connection: SolvedConnection) -> None: """ Test that the end of life emissions from each technology archetype are correct, and check total emissions """ @@ -238,7 +260,9 @@ def test_endoflife_emissions(solved_connection): indirect=True, ids=[t['name'] for t in eol_tests], ) -def test_endoflife_emissions_costs_undiscounted(solved_connection): +def test_endoflife_emissions_costs_undiscounted( + solved_connection: SolvedConnection, +) -> None: """ Test that the undiscounted end of life emission costs from each technology archetype are correct """ @@ -263,7 +287,9 @@ def test_endoflife_emissions_costs_undiscounted(solved_connection): indirect=True, ids=[t['name'] for t in eol_tests], ) -def test_endoflife_emissions_costs_discounted(solved_connection): +def test_endoflife_emissions_costs_discounted( + solved_connection: SolvedConnection, +) -> None: """ Test that discounted end of life emission costs from each technology archetype are correct """ @@ -285,7 +311,7 @@ def test_endoflife_emissions_costs_discounted(solved_connection): # Curtailment # List of tech archetypes to test and their correct curtailment value -curtailment_tests = [ +curtailment_tests: list[TechTestParams] = [ {'name': 'curtailment archetype', 'tech': 'TechCurtailment', 'target': 0.45}, {'name': 'flex archetype', 'tech': 'TechFlex', 'target': 0.7}, {'name': 'annual flex archetype', 'tech': 'TechAnnualFlex', 'target': 0.7}, @@ -299,9 +325,9 @@ def test_endoflife_emissions_costs_discounted(solved_connection): indirect=True, ids=[t['name'] for t in curtailment_tests], ) -def test_curtailment(solved_connection): +def test_curtailment(solved_connection: SolvedConnection) -> None: con, name, tech, curt_target = solved_connection - print(name, tech, curt_target) + logger.info('Curtailment test: %s %s target=%s', name, tech, curt_target) curt = ( con.cursor() .execute( diff --git a/tests/test_exchange_cost_ledger.py b/tests/test_exchange_cost_ledger.py index f13a1d846..17f062fff 100644 --- a/tests/test_exchange_cost_ledger.py +++ b/tests/test_exchange_cost_ledger.py @@ -1,36 +1,20 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 3/3/24 - -""" +from typing import Any, cast import pytest from temoa._internal.exchange_tech_cost_ledger import CostType, ExchangeTechCostLedger +from temoa.types.core_types import Period, Region, Technology, Vintage from tests.utilities.namespace_mock import Namespace +# Module-level typed constants +TEST_REGION_A = cast(Region, 'A') +TEST_REGION_B = cast(Region, 'B') +TEST_REGION_AB = cast(Region, 'A-B') +TEST_PERIOD_1 = cast(Period, 1) +TEST_PERIOD_2000 = cast(Period, 2000) +TEST_TECH_T1 = cast(Technology, 't1') +TEST_VINTAGE_2000 = cast(Vintage, 2000) + # these are the necessary Temoa elements to make the ledger work data = { 'time_season': {2000: [1]}, @@ -50,20 +34,27 @@ @pytest.fixture -def fake_model(): +def fake_model() -> Namespace: """make a fake Temoa Model from data""" fake_model = Namespace(**data) return fake_model -def test_add_cost_record(fake_model): +def test_add_cost_record(fake_model: Namespace) -> None: """test adding a record to the ledger""" ledger = ExchangeTechCostLedger(fake_model) - ledger.add_cost_record('A-B', 1, 't1', 2000, 1.99, CostType.FIXED) + ledger.add_cost_record( + TEST_REGION_AB, + TEST_PERIOD_1, + TEST_TECH_T1, + TEST_VINTAGE_2000, + 1.99, + CostType.FIXED, + ) assert len(ledger.cost_records) == 1, 'should have 1 entry in the ledger' -params = [ +params: list[dict[str, Any]] = [ { 'name': 'no usage splitting', 'records': [ @@ -91,7 +82,7 @@ def test_add_cost_record(fake_model): @pytest.mark.parametrize('costs', argvalues=params, ids=[d['name'] for d in params]) -def test_cost_allocation(fake_model, costs): +def test_cost_allocation(fake_model: Namespace, costs: dict[str, Any]) -> None: """Test the accurate""" ledger = ExchangeTechCostLedger(fake_model) for record in costs['records']: @@ -99,11 +90,23 @@ def test_cost_allocation(fake_model, costs): assert len(ledger.cost_records[CostType.FIXED]) == costs['cost_entries'] # test for ratio... - ratio = ledger.get_use_ratio('A', 'B', 2000, 't1', 2000) + ratio = ledger.get_use_ratio( + TEST_REGION_A, + TEST_REGION_B, + TEST_PERIOD_2000, + TEST_TECH_T1, + TEST_VINTAGE_2000, + ) assert ratio == pytest.approx(costs['B_ratio']), ( 'B should get 60% of cost as it receives 60% of flow' ) - ratio = ledger.get_use_ratio('B', 'A', 2000, 't1', 2000) + ratio = ledger.get_use_ratio( + TEST_REGION_B, + TEST_REGION_A, + TEST_PERIOD_2000, + TEST_TECH_T1, + TEST_VINTAGE_2000, + ) assert ratio == pytest.approx(costs['A_ratio']), ( 'A should get 40% of cost as it receives 40% of flow' ) @@ -111,5 +114,11 @@ def test_cost_allocation(fake_model, costs): # test the outpt cost entries... entries = ledger.get_entries() assert len(entries) == 2, 'should produce 2 entries for A, B' - assert entries['A', 2000, 't1', 2000][CostType.FIXED] == costs['A_cost'], "costs didn't match" - assert entries['B', 2000, 't1', 2000][CostType.FIXED] == costs['B_cost'], "costs didn't match" + assert ( + entries[TEST_REGION_A, TEST_PERIOD_2000, TEST_TECH_T1, TEST_VINTAGE_2000][CostType.FIXED] + == costs['A_cost'] + ), "costs didn't match" + assert ( + entries[TEST_REGION_B, TEST_PERIOD_2000, TEST_TECH_T1, TEST_VINTAGE_2000][CostType.FIXED] + == costs['B_cost'] + ), "costs didn't match" diff --git a/tests/test_full_runs.py b/tests/test_full_runs.py index 60f5ecd34..e4476ad4b 100644 --- a/tests/test_full_runs.py +++ b/tests/test_full_runs.py @@ -1,29 +1,5 @@ """ Test a couple full-runs to match objective function value and some internals - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 6/27/23 - -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . """ import logging @@ -32,8 +8,11 @@ import pyomo.environ as pyo import pytest from pyomo.core import Constraint, Var +from pyomo.opt import SolverResults # from src.temoa_model.temoa_model import temoa_create_model +from temoa._internal.temoa_sequencer import TemoaSequencer +from temoa.core.model import TemoaModel from tests.legacy_test_values import ExpectedVals, test_vals logger = logging.getLogger(__name__) @@ -56,15 +35,20 @@ indirect=True, ids=[d['name'] for d in legacy_config_files], ) -def test_against_legacy_outputs(system_test_run): +def test_against_legacy_outputs( + system_test_run: tuple[str, SolverResults | None, TemoaModel | None, TemoaSequencer], +) -> None: """ This test compares tests of legacy models to captured test results """ data_name, res, mdl, _ = system_test_run logger.info('Starting output test on scenario: %s', data_name) + assert res is not None, f'No solver results for {data_name}' + assert mdl is not None, f'No model for {data_name}' expected_vals = test_vals.get(data_name) # a dictionary of expected results + assert expected_vals is not None, f'No expected values for {data_name}' - # inspect some summary results + # Inspect some summary results assert res['Solution'][0]['Status'] == 'optimal' assert res['Solution'][0]['Objective']['total_cost']['Value'] == pytest.approx( expected_vals[ExpectedVals.OBJ_VALUE], 0.00001 @@ -99,7 +83,9 @@ def test_against_legacy_outputs(system_test_run): @pytest.mark.parametrize( 'system_test_run', argvalues=myopic_files, indirect=True, ids=[d['name'] for d in myopic_files] ) -def test_myopic_utopia(system_test_run): +def test_myopic_utopia( + system_test_run: tuple[str, SolverResults | None, TemoaModel | None, TemoaSequencer], +) -> None: """ Some cursory tests to ensure Myopic is running... This is a very weak/simple test It mostly just ensures that the mode runs correctly and only checks 1 output. Much diff --git a/tests/test_hull.py b/tests/test_hull.py index e90f8b0e9..624b1abcf 100644 --- a/tests/test_hull.py +++ b/tests/test_hull.py @@ -1,30 +1,3 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 4/18/24 - -""" import numpy as np import pytest @@ -33,29 +6,25 @@ pts = np.array([[2, 2], [2, 4], [4, 2]]) r""" |\ - <-- | \ --> (to be viewed at a slightly upward angle. :/ ) + <-- | \ --> (to be viewed at a slightly upward angle. :/ ) | \ |___\ | v -A simple right triangle to start with +A simple right triangle to start with - should have 3 norms from 3 equations as a starter """ -def test_hull(): +def test_hull() -> None: """Basic build test, just see if it can be built and it rejects bad dimension inputs""" - hull = Hull(pts) - assert hull.cv_hull - with pytest.raises(ValueError): + hull = Hull(pts) # noqa F841 + with pytest.raises(ValueError, match='Insufficient points to make hull'): # transposed, the points(2) are insufficient for the dimensionality (3) - hull2 = Hull(pts.T) - print( - hull2.all_points - ) # should never get here... just to prevent warning on unused var 'hull' + hull2 = Hull(pts.T) # noqa F841 -def test_add_point(): +def test_add_point() -> None: """ test adding point to the triangle to make a square and that by doing so we get 2 new normals @@ -74,17 +43,18 @@ def test_add_point(): assert count == 5, '5 faces were available and should have been added to the available vecs' -def test_get_vector(): +def test_get_vector() -> None: """Test iteration through the 3 vectors available""" hull = Hull(pts) for _ in range(3): v = hull.get_norm() + assert v is not None assert np.linalg.norm(v) == pytest.approx(1.0) # should be no more... assert hull.get_norm() is None -def test_is_new_direction(): +def test_is_new_direction() -> None: """Test the linear algebra used to see if a new vector is different from an existing vector""" hull = Hull(pts) # make a new highly similar direction to the [-1, 0] normal @@ -93,7 +63,7 @@ def test_is_new_direction(): assert not hull.is_new_direction(sim_vec), 'this should be rejected as a new direction' -def test_valid_directions_available(): +def test_valid_directions_available() -> None: hull = Hull(pts) assert hull.norms_available == 3, '3 basic normals are available' hull.add_point(np.array([4, 4])) @@ -102,7 +72,7 @@ def test_valid_directions_available(): assert hull.norms_available == 5, '5 should be available' -def test_get_vectors(): +def test_get_vectors() -> None: hull = Hull(pts) vecs = hull.get_all_norms() assert len(vecs) == 3 diff --git a/tests/test_linked_tech.py b/tests/test_linked_tech.py index cfa66240b..20887baf0 100644 --- a/tests/test_linked_tech.py +++ b/tests/test_linked_tech.py @@ -10,6 +10,10 @@ from pathlib import Path import pytest +from pyomo.opt import SolverResults + +from temoa._internal.temoa_sequencer import TemoaSequencer +from temoa.core.model import TemoaModel logger = logging.getLogger(__name__) config_files = [ @@ -23,7 +27,9 @@ indirect=True, ids=[d['name'] for d in config_files], ) -def test_linked_tech(system_test_run): +def test_linked_tech( + system_test_run: tuple[str, SolverResults | None, TemoaModel | None, TemoaSequencer], +) -> None: """Check a few known values. See the note above in header regarding scenario reference""" data_name, res, mdl, _ = system_test_run # test emission of CO2 diff --git a/tests/test_mc_run.py b/tests/test_mc_run.py index 69da7e445..3fefacf4a 100644 --- a/tests/test_mc_run.py +++ b/tests/test_mc_run.py @@ -1,37 +1,10 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 11/9/24 - -""" import pytest -from temoa.extensions.monte_carlo.mc_run import TweakFactory, RowData +from temoa.extensions.monte_carlo.mc_run import RowData, TweakFactory @pytest.fixture(scope='module') -def tweak_factory(): +def tweak_factory() -> TweakFactory: tweak_factory = TweakFactory( data_store={'dog': {(1, 2): 3.0, (5, 6): 4.0}, 'cat': {('a', 'b'): 7.0, ('c', 'd'): 8.0}} ) @@ -39,35 +12,46 @@ def tweak_factory(): good_params = [ - ('1,dog,1|2,a,1.0,some good notes', RowData(1, 'dog', '1|2', 'a', 1.0, 'some good notes'), 1), - ( + pytest.param( + '1,dog,1|2,a,1.0,some good notes', + RowData(1, 'dog', '1|2', 'a', 1.0, 'some good notes'), + 1, + id='good_param_0', + ), + pytest.param( '1 , dog, 1|2 , a , 1.0,', RowData(1, 'dog', '1|2', 'a', 1.0, ''), 1, + id='good_param_1_strip_spaces', ), # we should be able to strip lead/trail spaces - ('22,cat,c|d/e/f|9/10,r,2,', RowData(22, 'cat', 'c|d/e/f|9/10', 'r', 2.0, ''), 6), + pytest.param( + '22,cat,c|d/e/f|9/10,r,2,', + RowData(22, 'cat', 'c|d/e/f|9/10', 'r', 2.0, ''), + 6, + id='good_param_2', + ), ] + fail_examples = [ - ('z,dog,1|2,a,1.0,'), # has 'z' for run, non integer - ('1,dog,1||2,a,1.0,'), # has empty index location - ('2,dog,5|6,x,2.0,'), # has 'x' not in r/s/a - ('3,pig,4|5|7,r,2.0,'), # no pig in data source + pytest.param('z,dog,1|2,a,1.0,', id='non-int run label'), # has 'z' for run, non integer + pytest.param('1,dog,1||2,a,1.0,', id='empty index'), # has empty index location + pytest.param('2,dog,5|6,x,2.0,', id='non r/s/a'), # has 'x' not in r/s/a + pytest.param('3,pig,4|5|7,r,2.0,', id='no-match param'), # no pig in data source ] -ids = ['non-int run label', 'empty index', 'non r/s/a', 'no-match param'] -@pytest.mark.parametrize('row, expected,_', good_params, ids=range(len(good_params))) -def test__row_parser(row, expected, _, tweak_factory): +@pytest.mark.parametrize(('row', 'expected', '_'), good_params) +def test__row_parser(row: str, expected: RowData, _: object, tweak_factory: TweakFactory) -> None: assert tweak_factory.row_parser(0, row=row) == expected -@pytest.mark.parametrize('row', fail_examples, ids=ids) -def test__row_parser_fail(row, tweak_factory): +@pytest.mark.parametrize('row', fail_examples) +def test__row_parser_fail(row: str, tweak_factory: TweakFactory) -> None: with pytest.raises(ValueError): tweak_factory.row_parser(0, row=row) -@pytest.mark.parametrize('row, _, num_tweaks', good_params, ids=range(len(good_params))) -def test_make_tweaks(row, _, num_tweaks, tweak_factory): +@pytest.mark.parametrize(('row', '_', 'num_tweaks'), good_params) +def test_make_tweaks(row: str, _: object, num_tweaks: int, tweak_factory: TweakFactory) -> None: _, tweaks = tweak_factory.make_tweaks(0, row=row) assert len(tweaks) == num_tweaks diff --git a/tests/test_myopic_sequencer.py b/tests/test_myopic_sequencer.py index d3a1be206..1c28eb01e 100644 --- a/tests/test_myopic_sequencer.py +++ b/tests/test_myopic_sequencer.py @@ -1,30 +1,4 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 1/20/24 - -""" +from typing import Any import pytest @@ -58,8 +32,8 @@ """ -@pytest.mark.parametrize('param', params, ids=[t['name'] for t in params]) -def test_characterize_run(param): +@pytest.mark.parametrize('param', params, ids=lambda p: p['name']) +def test_characterize_run(param: dict[str, Any]) -> None: """ Test the slicing up of the future periods into myopic indices """ @@ -70,7 +44,7 @@ def test_characterize_run(param): ms.characterize_run(future_periods=list(range(5))) assert len(ms.instance_queue) == param['expected_steps'], ( - 'number of myopic iterations does not match expected ' 'number of iterations' + 'number of myopic iterations does not match expected number of iterations' ) # pop the last myopic index from the queue and inspect it. Should be same for both cases diff --git a/tests/test_network_model_data.py b/tests/test_network_model_data.py index 78140cccb..337d91773 100644 --- a/tests/test_network_model_data.py +++ b/tests/test_network_model_data.py @@ -1,10 +1,19 @@ import sqlite3 +from typing import TypedDict, cast from unittest.mock import MagicMock import pytest from temoa.model_checking import network_model_data from temoa.model_checking.commodity_network import CommodityNetwork +from temoa.types.core_types import Period, Region + + +class ScenarioType(TypedDict): + name: str + db_data: dict[str, object] + expected: dict[str, object] + # ============================================================================== # Test Scenarios @@ -14,7 +23,7 @@ # This makes the mock robust against changes in the order of execution, # ensuring backwards compatibility with older versions of the code. # ============================================================================== -test_scenarios = [ +test_scenarios: list[ScenarioType] = [ # Scenario 1: A basic network with several orphan technologies. { 'name': 'basic', @@ -147,7 +156,7 @@ # Fixtures # ============================================================================== @pytest.fixture -def mock_db_connection(request): +def mock_db_connection(request: pytest.FixtureRequest) -> tuple[MagicMock, dict[str, object]]: """ A robust mock of a database connection. @@ -182,7 +191,9 @@ def dispatcher(query: str, *_: object) -> MagicMock: @pytest.mark.parametrize( 'mock_db_connection', test_scenarios, indirect=True, ids=[d['name'] for d in test_scenarios] ) -def test_network_build_and_analysis(mock_db_connection) -> None: +def test_network_build_and_analysis( + mock_db_connection: tuple[MagicMock, dict[str, object]], +) -> None: """Tests both data model construction and network analysis in one go.""" conn, expected = mock_db_connection @@ -193,10 +204,15 @@ def test_network_build_and_analysis(mock_db_connection) -> None: assert ( sum(len(s) for s in network_data.demand_commodities.values()) == expected['demands_count'] ) - assert len(network_data.available_techs[('R1', 2020)]) == expected['techs_count'] + assert ( + len(network_data.available_techs[(cast(Region, 'R1'), cast(Period, 2020))]) + == expected['techs_count'] + ) # --- 3. Perform network analysis --- - cn = CommodityNetwork(region='R1', period=2020, model_data=network_data) + cn = CommodityNetwork( + region=cast(Region, 'R1'), period=cast(Period, 2020), model_data=network_data + ) cn.analyze_network() # --- 4. Test analysis results --- @@ -213,7 +229,7 @@ def test_network_build_and_analysis(mock_db_connection) -> None: @pytest.mark.parametrize('mock_db_connection', [test_scenarios[0]], indirect=True) -def test_clone(mock_db_connection): +def test_clone(mock_db_connection: tuple[MagicMock, dict[str, object]]) -> None: """Verifies that the clone() method creates a deep enough copy.""" conn, _ = mock_db_connection network_data = network_model_data._build_from_db(conn) @@ -225,7 +241,7 @@ def test_clone(mock_db_connection): 'Data should be identical after cloning' ) - clone.available_techs.pop(('R1', 2020)) + clone.available_techs.pop((cast(Region, 'R1'), cast(Period, 2020))) assert network_data.available_techs != clone.available_techs, ( 'Modifying clone should not affect original' ) @@ -307,7 +323,7 @@ def dispatcher(query: str, *_: object) -> MagicMock: network_data = network_model_data._build_from_db(mock_con) # Verify sectors are included in efficiencyTuple - techs = list(network_data.available_techs[('R1', 2020)]) + techs = list(network_data.available_techs[(cast(Region, 'R1'), cast(Period, 2020))]) assert len(techs) == 2 # Fields: region, ic, tech, vintage, oc, lifetime, sector assert all(len(tech) == 7 for tech in techs) @@ -391,7 +407,7 @@ def dispatcher(query: str, *_: object) -> MagicMock: network_data = network_model_data._build_from_db(mock_con) # Verify sectors default to None - techs = list(network_data.available_techs[('R1', 2020)]) + techs = list(network_data.available_techs[(cast(Region, 'R1'), cast(Period, 2020))]) assert len(techs) == 2 # Fields: region, ic, tech, vintage, oc, lifetime, sector (sector None here) assert all(len(tech) == 7 for tech in techs) diff --git a/tests/test_pricing_check.py b/tests/test_pricing_check.py index c9997b911..8b02dd3a1 100644 --- a/tests/test_pricing_check.py +++ b/tests/test_pricing_check.py @@ -1,39 +1,14 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 2/2/24 - -""" +from typing import cast import pytest from pyomo.environ import Any, ConcreteModel, Param, Set +from temoa.core.model import TemoaModel from temoa.model_checking.pricing_check import check_tech_uncap @pytest.fixture -def mock_model(): +def mock_model() -> ConcreteModel: """let's see how tough this is to work with...""" model = ConcreteModel('mock') model.tech_uncap = Set(initialize=['refinery']) @@ -52,13 +27,15 @@ def mock_model(): return model -def test_check_tech_uncap(mock_model): +def test_check_tech_uncap( + mock_model: ConcreteModel, +) -> None: """ test the fault checking for unlimited capacity techs :param mock_model: :return: """ - model = mock_model + model = cast(TemoaModel, mock_model) assert check_tech_uncap(model), 'should pass for no fixed/invest/variable costs' model.cost_variable[('CA', 2020, 'refinery', 2020)] = 42 @@ -68,24 +45,28 @@ def test_check_tech_uncap(mock_model): assert check_tech_uncap(model), 'should pass for all periods having var cost' -def test_detect_fixed_cost(mock_model): +def test_detect_fixed_cost( + mock_model: ConcreteModel, +) -> None: """ test the fault checking for unlimited capacity techs :param mock_model: :return: """ - model = mock_model + model = cast(TemoaModel, mock_model) assert check_tech_uncap(model), 'should have cleared and passed again' model.cost_fixed[('CA', 2020, 'refinery', 2020)] = 42 assert not check_tech_uncap(model), 'should fail with any fixed cost' -def test_detect_invest_cost(mock_model): +def test_detect_invest_cost( + mock_model: ConcreteModel, +) -> None: """ test the fault checking for unlimited capacity techs :param mock_model: :return: """ - model = mock_model + model = cast(TemoaModel, mock_model) model.cost_invest['CA', 'refinery', 2020] = 42 assert not check_tech_uncap(model), 'should fail with any investment cost' diff --git a/tests/test_set_consistency.py b/tests/test_set_consistency.py index 52444914b..532016e1f 100644 --- a/tests/test_set_consistency.py +++ b/tests/test_set_consistency.py @@ -26,7 +26,9 @@ @pytest.mark.parametrize( argnames='data_name config_file set_file'.split(), argvalues=params, ids=[t[0] for t in params] ) -def test_set_consistency(data_name, config_file, set_file, tmp_path): +def test_set_consistency( + data_name: str, config_file: str, set_file: str, tmp_path: pathlib.Path +) -> None: """ test the set membership of the utopia model against cached values to ensure consistency """ diff --git a/tests/test_source_check.py b/tests/test_source_check.py index ad6a34c85..8ca0f914f 100644 --- a/tests/test_source_check.py +++ b/tests/test_source_check.py @@ -7,6 +7,7 @@ """ from collections import defaultdict +from typing import TypedDict, cast from unittest.mock import MagicMock import pytest @@ -14,58 +15,64 @@ # Assuming the refactored code is in this location from temoa.model_checking.commodity_network import CommodityNetwork from temoa.model_checking.network_model_data import EdgeTuple +from temoa.types.core_types import Commodity, Period, Region, Technology, Vintage -# --- Test Case Definitions --- -# Each tuple contains: -# 1. test_id (str): A descriptive name for the test case. -# 2. start_nodes (set): Demand commodities to start the backward trace from. -# 3. end_nodes (set): Source commodities that validate a path. -# 4. connections (dict): The network structure {output: {(input, tech)}}. -# 5. expected_good (set): The connections that should be fully valid. -# 6. expected_demand_orphans (set): Connections reachable from demand but not a source. -# 7. expected_other_orphans (set): Connections not reachable from demand at all. -TEST_CASES = [ +class CaseType(TypedDict): + test_id: str # Descriptive name for the test case + start_nodes: set[str] # Demand commodities to start the backward trace from + end_nodes: set[str] # Source commodities that validate a path + connections: dict[str, set[tuple[str, str]]] # The network structure {output: {(input, tech)}}. + expected_good: set[tuple[str, str, str]] # The connections that should be fully valid + expected_demand_orphans: set[ + tuple[str, str, str] + ] # Connections reachable from demand but not a source + expected_other_orphans: set[ + tuple[str, str, str] + ] # Connections not reachable from demand at all + + +TEST_CASES: list[CaseType] = [ # s = source commodity, p = physical commodity, d = demand, t = tech # Test 1: A simple, valid, linear chain from source to demand. # s1 -> t1 -> p1 -> t2 -> d1 - ( - 'simple_linear_chain', - {'d1'}, - {'s1'}, - {'d1': {('p1', 't2')}, 'p1': {('s1', 't1')}}, - {('s1', 't1', 'p1'), ('p1', 't2', 'd1')}, - set(), - set(), - ), + { + 'test_id': 'simple_linear_chain', + 'start_nodes': {'d1'}, + 'end_nodes': {'s1'}, + 'connections': {'d1': {('p1', 't2')}, 'p1': {('s1', 't1')}}, + 'expected_good': {('s1', 't1', 'p1'), ('p1', 't2', 'd1')}, + 'expected_demand_orphans': set(), + 'expected_other_orphans': set(), + }, # Test 2: One valid chain and one orphaned branch feeding into the same demand. # s1 -> t1 -> p1 -> t2 -> d1 # / # p2 -> t3 - - ( - 'one_good_one_orphan_branch', - {'d1'}, - {'s1'}, - {'d1': {('p1', 't2'), ('p2', 't3')}, 'p1': {('s1', 't1')}}, - {('s1', 't1', 'p1'), ('p1', 't2', 'd1')}, - {('p2', 't3', 'd1')}, - set(), - ), + { + 'test_id': 'one_good_one_orphan_branch', + 'start_nodes': {'d1'}, + 'end_nodes': {'s1'}, + 'connections': {'d1': {('p1', 't2'), ('p2', 't3')}, 'p1': {('s1', 't1')}}, + 'expected_good': {('s1', 't1', 'p1'), ('p1', 't2', 'd1')}, + 'expected_demand_orphans': {('p2', 't3', 'd1')}, + 'expected_other_orphans': set(), + }, # Test 3: Multiple valid paths from one intermediate commodity, plus an orphan branch. # - t4 - # / \ # s1 -> t1 -> p1 -> t2 -> d1 # / # p2 -> t3 - - ( - 'multiple_paths_from_one_source', - {'d1'}, - {'s1'}, - {'d1': {('p1', 't2'), ('p2', 't3'), ('p1', 't4')}, 'p1': {('s1', 't1')}}, - {('s1', 't1', 'p1'), ('p1', 't2', 'd1'), ('p1', 't4', 'd1')}, - {('p2', 't3', 'd1')}, - set(), - ), + { + 'test_id': 'multiple_paths_from_one_source', + 'start_nodes': {'d1'}, + 'end_nodes': {'s1'}, + 'connections': {'d1': {('p1', 't2'), ('p2', 't3'), ('p1', 't4')}, 'p1': {('s1', 't1')}}, + 'expected_good': {('s1', 't1', 'p1'), ('p1', 't2', 'd1'), ('p1', 't4', 'd1')}, + 'expected_demand_orphans': {('p2', 't3', 'd1')}, + 'expected_other_orphans': set(), + }, # Test 4: Two independent, valid supply chains for two different demands. # - t4 - # / \ @@ -74,19 +81,24 @@ # p2 -> t3 - # # s2 -> t5 -> d2 - ( - 'multiple_demands_and_sources', - {'d1', 'd2'}, - {'s1', 's2'}, - { + { + 'test_id': 'multiple_demands_and_sources', + 'start_nodes': {'d1', 'd2'}, + 'end_nodes': {'s1', 's2'}, + 'connections': { 'd1': {('p1', 't2'), ('p2', 't3'), ('p1', 't4')}, 'p1': {('s1', 't1')}, 'd2': {('s2', 't5')}, }, - {('s1', 't1', 'p1'), ('p1', 't2', 'd1'), ('p1', 't4', 'd1'), ('s2', 't5', 'd2')}, - {('p2', 't3', 'd1')}, - set(), - ), + 'expected_good': { + ('s1', 't1', 'p1'), + ('p1', 't2', 'd1'), + ('p1', 't4', 'd1'), + ('s2', 't5', 'd2'), + }, + 'expected_demand_orphans': {('p2', 't3', 'd1')}, + 'expected_other_orphans': set(), + }, # Test 5: One demand is valid, the other is completely orphaned (no path to any source). # - t4 - # / \ @@ -95,59 +107,64 @@ # p2 -> t3 - # # p3 -> t5 -> d2 - ( - 'one_demand_is_fully_orphaned', - {'d1', 'd2'}, - {'s1'}, - { + { + 'test_id': 'one_demand_is_fully_orphaned', + 'start_nodes': {'d1', 'd2'}, + 'end_nodes': {'s1'}, + 'connections': { 'd1': {('p1', 't2'), ('p2', 't3'), ('p1', 't4')}, 'p1': {('s1', 't1')}, 'd2': {('p3', 't5')}, }, - {('s1', 't1', 'p1'), ('p1', 't2', 'd1'), ('p1', 't4', 'd1')}, - {('p2', 't3', 'd1'), ('p3', 't5', 'd2')}, - set(), - ), + 'expected_good': {('s1', 't1', 'p1'), ('p1', 't2', 'd1'), ('p1', 't4', 'd1')}, + 'expected_demand_orphans': {('p2', 't3', 'd1'), ('p3', 't5', 'd2')}, + 'expected_other_orphans': set(), + }, # Test 6: A valid network that includes a loop (e.g., storage technology). # - t4 - # \ / # s1 -> t1 -> p1 -> t2 -> d1 # / # p2 -> t3 - - ( - 'network_with_a_loop', - {'d1'}, - {'s1', 's2'}, - { + { + 'test_id': 'network_with_a_loop', + 'start_nodes': {'d1'}, + 'end_nodes': {'s1', 's2'}, + 'connections': { 'd1': {('p1', 't2'), ('p2', 't3'), ('p1', 't4')}, 'p1': {('s1', 't1'), ('p1', 't4')}, # t4 loops on p1 }, - {('s1', 't1', 'p1'), ('p1', 't2', 'd1'), ('p1', 't4', 'd1'), ('p1', 't4', 'p1')}, - {('p2', 't3', 'd1')}, - set(), - ), + 'expected_good': { + ('s1', 't1', 'p1'), + ('p1', 't2', 'd1'), + ('p1', 't4', 'd1'), + ('p1', 't4', 'p1'), + }, + 'expected_demand_orphans': {('p2', 't3', 'd1')}, + 'expected_other_orphans': set(), + }, # Test 7: No source nodes are defined, so no connections can be "good". # s1 -> t1 -> p1 -> t2 -> d1 # s2 -> t5 -> d2 - ( - 'no_source_nodes_defined', - {'d1', 'd2'}, - set(), # No sources - { + { + 'test_id': 'no_source_nodes_defined', + 'start_nodes': {'d1', 'd2'}, + 'end_nodes': set(), # No sources + 'connections': { 'd1': {('p1', 't2'), ('p2', 't3'), ('p1', 't4')}, 'p1': {('s1', 't1')}, 'd2': {('s2', 't5')}, }, - set(), # No good connections are possible - { + 'expected_good': set(), # No good connections are possible + 'expected_demand_orphans': { ('p1', 't2', 'd1'), ('p2', 't3', 'd1'), ('p1', 't4', 'd1'), ('s1', 't1', 'p1'), ('s2', 't5', 'd2'), }, - set(), - ), + 'expected_other_orphans': set(), + }, ] @@ -161,25 +178,36 @@ 'expected_demand_orphans', 'expected_other_orphans', ), - TEST_CASES, - ids=[case[0] for case in TEST_CASES], + [ + ( + case['test_id'], + case['start_nodes'], + case['end_nodes'], + case['connections'], + case['expected_good'], + case['expected_demand_orphans'], + case['expected_other_orphans'], + ) + for case in TEST_CASES + ], + ids=[case['test_id'] for case in TEST_CASES], ) def test_network_analysis( - test_id, - start_nodes, - end_nodes, - connections, - expected_good, - expected_demand_orphans, - expected_other_orphans, -): + test_id: str, + start_nodes: set[str], + end_nodes: set[str], + connections: dict[Commodity, set[tuple[Commodity, Technology]]], + expected_good: set[tuple[str, str, str]], + expected_demand_orphans: set[tuple[str, str, str]], + expected_other_orphans: set[tuple[str, str, str]], +) -> None: """ Tests the CommodityNetwork analysis logic against various topologies. """ # 1. Setup mock model data for the test case mock_model_data = MagicMock() - region = 'test_region' - period = 2025 + region = cast(Region, 'test_region') + period = cast(Period, 2025) # The mock needs to return the correct data for the (region, period) key mock_model_data.demand_commodities = defaultdict(set, {(region, period): start_nodes}) @@ -189,7 +217,9 @@ def test_network_analysis( # Convert the connections dict into a set of Tech namedtuples available_techs = { - EdgeTuple(input_comm=ic, output_comm=oc, tech=tech, vintage=period, region=region) + EdgeTuple( + input_comm=ic, output_comm=oc, tech=tech, vintage=cast(Vintage, period), region=region + ) for oc, links in connections.items() for ic, tech in links } diff --git a/tests/test_storage.py b/tests/test_storage.py index 0a9017952..b27a458b5 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -1,13 +1,10 @@ """ The intent of this file is to test the storage relationships in the model -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 12/29/23 """ import logging +from typing import Any import pytest @@ -27,7 +24,7 @@ indirect=True, ids=[d['name'] for d in storage_config_files], ) -def test_storage_fraction(system_test_run): +def test_storage_fraction(system_test_run: tuple[str, Any, TemoaModel, Any]) -> None: """ Level at the start of the time slice should equal the forced fraction """ @@ -41,7 +38,7 @@ def test_storage_fraction(system_test_run): for r, p, s, d, t, v, op in model.limit_storage_fraction_constraint_rpsdtv: energy = ( model.limit_storage_fraction[r, p, s, d, t, v, op] - * model.v_capacity[r, p, t, v].value + * model.v_capacity[r, p, t, v].value # type: ignore [attr-defined] # I can't figure out how to get mypy to see value through the pyomo stubs * model.capacity_to_activity[r, t] * (model.storage_duration[r, t] / 8760) * model.segment_fraction_per_season[p, s] @@ -49,7 +46,7 @@ def test_storage_fraction(system_test_run): * model.process_life_frac[r, p, t, v] ) - assert model.v_storage_level[r, p, s, d, t, v].value == pytest.approx(energy, abs=1e-5), ( + assert model.v_storage_level[r, p, s, d, t, v].value == pytest.approx(energy, abs=1e-5), ( # type: ignore [attr-defined] # I can't figure out how to get mypy to see value through the pyomo stubs f'model fails to initialise storage state at start of season {r, p, s, d, t, v}' ) @@ -60,7 +57,7 @@ def test_storage_fraction(system_test_run): indirect=True, ids=[d['name'] for d in storage_config_files], ) -def test_state_sequencing(system_test_run): +def test_state_sequencing(system_test_run: tuple[str, Any, TemoaModel, Any]) -> None: """ Make sure that everything is looping properly """ @@ -73,20 +70,20 @@ def test_state_sequencing(system_test_run): for r, p, s, d, t, v in model.storage_level_rpsdtv: charge = sum( - model.v_flow_in[r, p, s, d, S_i, t, v, S_o].value * model.efficiency[r, S_i, t, v, S_o] + model.v_flow_in[r, p, s, d, S_i, t, v, S_o].value * model.efficiency[r, S_i, t, v, S_o] # type: ignore [attr-defined] # I can't figure out how to get mypy to see value through the pyomo stubs for S_i in model.process_inputs[r, p, t, v] for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) discharge = sum( - model.v_flow_out[r, p, s, d, S_i, t, v, S_o].value + model.v_flow_out[r, p, s, d, S_i, t, v, S_o].value # type: ignore [attr-defined] # I can't figure out how to get mypy to see value through the pyomo stubs for S_o in model.process_outputs[r, p, t, v] for S_i in model.process_inputs_by_output[r, p, t, v, S_o] ) s_next, d_next = model.time_next[p, s, d] - state = model.v_storage_level[r, p, s, d, t, v].value - next_state = model.v_storage_level[r, p, s_next, d_next, t, v].value + state = model.v_storage_level[r, p, s, d, t, v].value # type: ignore [attr-defined] # I can't figure out how to get mypy to see value through the pyomo stubs + next_state = model.v_storage_level[r, p, s_next, d_next, t, v].value # type: ignore [attr-defined] # I can't figure out how to get mypy to see value through the pyomo stubs assert state + charge - discharge == pytest.approx(next_state, abs=1e-5), ( f'model fails to correctly sequence storage states {r, p, s, t, v} sequenced {s, d} to {s_next, d_next}' @@ -99,7 +96,7 @@ def test_state_sequencing(system_test_run): indirect=True, ids=[d['name'] for d in storage_config_files], ) -def test_storage_flow_balance(system_test_run): +def test_storage_flow_balance(system_test_run: tuple[str, Any, TemoaModel, Any]) -> None: """ Test the balance of all inflows vs. all outflows. Note: inflows are taxed by efficiency, so that is replicated here @@ -124,10 +121,10 @@ def test_storage_flow_balance(system_test_run): # calculate the inflow and outflow. Inflow is taxed by efficiency in the model, # so we need to do that here as well inflow = sum( - model.v_flow_in[r, p, s, d, i, t, v, o].value * model.efficiency[r, i, t, v, o] + model.v_flow_in[r, p, s, d, i, t, v, o].value * model.efficiency[r, i, t, v, o] # type: ignore [attr-defined] # I can't figure out how to get mypy to see value through the pyomo stubs for (r, p, s, d, i, t, v, o) in inflow_indices ) - outflow = sum(model.v_flow_out[idx].value for idx in outflow_indices) + outflow = sum(model.v_flow_out[idx].value for idx in outflow_indices) # type: ignore [attr-defined] # I can't figure out how to get mypy to see value through the pyomo stubs assert inflow == pytest.approx(outflow, abs=1e-5), ( f'total inflow and outflow of storage tech {s_tech} do not match', diff --git a/tests/test_table_writer.py b/tests/test_table_writer.py index 7f44996a9..3f30d2e1f 100644 --- a/tests/test_table_writer.py +++ b/tests/test_table_writer.py @@ -1,102 +1,104 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling +from typing import TypedDict -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +import pytest -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 . +from temoa._internal.table_data_puller import loan_costs -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 3/1/24 +class LoanCostInput(TypedDict): + capacity: float + invest_cost: float + loan_life: float + loan_rate: float + global_discount_rate: float + process_life: int + p_0: int + vintage: int + p_e: int -""" -import pytest +class LoanCostTestCase(TypedDict): + ID: str + input: LoanCostInput + expected_model_cost: float + expected_undiscounted_cost: float -from temoa._internal.table_data_puller import loan_costs -params = [ +params: list[LoanCostTestCase] = [ { 'ID': 'near-zero GDR', - 'capacity': 100_000, # units - 'invest_cost': 1, # $/unit of capacity - 'loan_life': 40, - 'loan_rate': 0.10, - 'global_discount_rate': 0.000000000001, - 'process_life': 40, - 'p_0': 2020, # the "myopic base year" to which all prices are discounted - 'vintage': 2020, # the vintage of the new 'tech' - 'p_e': 2100, # last year in the myopic view - 'model_cost': 409037.66, - 'undiscounted_cost': 409037.66, + 'input': { + 'capacity': 100_000.0, # units + 'invest_cost': 1.0, # $/unit of capacity + 'loan_life': 40.0, + 'loan_rate': 0.10, + 'global_discount_rate': 0.000000000001, + 'process_life': 40, + 'p_0': 2020, # the "myopic base year" to which all prices are discounted + 'vintage': 2020, # the vintage of the new 'tech' + 'p_e': 2100, # last year in the myopic view + }, + 'expected_model_cost': 409037.66, + 'expected_undiscounted_cost': 409037.66, }, { 'ID': 'shortened term', - 'capacity': 100_000, - 'invest_cost': 1, - 'loan_life': 40, - 'loan_rate': 0.08, - 'global_discount_rate': 0.05, - 'process_life': 50, - 'p_0': 2020, - 'vintage': 2030, - 'p_e': 2035, - 'model_cost': 20950.20952, # reduced after fixing 1 year shift obj function bug - 'undiscounted_cost': 33544.06, + 'input': { + 'capacity': 100_000.0, + 'invest_cost': 1.0, + 'loan_life': 40.0, + 'loan_rate': 0.08, + 'global_discount_rate': 0.05, + 'process_life': 50, + 'p_0': 2020, + 'vintage': 2030, + 'p_e': 2035, + }, + 'expected_model_cost': 20950.20952, + 'expected_undiscounted_cost': 33544.06, }, ] -params_with_zero_GDR = [ +params_with_zero_gdr: list[LoanCostTestCase] = [ { 'ID': 'actual zero GDR', - 'capacity': 100_000, # units - 'invest_cost': 1, # $/unit of capacity - 'loan_life': 40, - 'loan_rate': 0.10, - 'global_discount_rate': 0, - 'process_life': 40, - 'p_0': 2020, # the "myopic base year" to which all prices are discounted - 'vintage': 2020, # the vintage of the new 'tech' - 'p_e': 2100, # last year in the myopic view - 'model_cost': 409037.657, - 'undiscounted_cost': 409037.657, + 'input': { + 'capacity': 100_000.0, # units + 'invest_cost': 1.0, # $/unit of capacity + 'loan_life': 40.0, + 'loan_rate': 0.10, + 'global_discount_rate': 0, + 'process_life': 40, + 'p_0': 2020, # the "myopic base year" to which all prices are discounted + 'vintage': 2020, # the vintage of the new 'tech' + 'p_e': 2100, # last year in the myopic view + }, + 'expected_model_cost': 409037.657, + 'expected_undiscounted_cost': 409037.657, } ] -@pytest.mark.parametrize('param', params, ids=(param['ID'] for param in params)) -def test_loan_costs(param): +@pytest.mark.parametrize('test_case', params, ids=[p['ID'] for p in params]) +def test_loan_costs(test_case: LoanCostTestCase) -> None: """ Test the loan cost calculations """ # we will test with a 1% error to accommodate the approximation of GDR=0 - model_cost, undiscounted_cost = loan_costs(**param) - assert model_cost == pytest.approx(param['model_cost'], rel=0.01) - assert undiscounted_cost == pytest.approx(param['undiscounted_cost'], rel=0.01) + model_cost, undiscounted_cost = loan_costs(**test_case['input']) + assert model_cost == pytest.approx(test_case['expected_model_cost'], rel=0.01) + assert undiscounted_cost == pytest.approx(test_case['expected_undiscounted_cost'], rel=0.01) @pytest.mark.parametrize( - 'param', params_with_zero_GDR, ids=(param['ID'] for param in params_with_zero_GDR) + 'test_case', + params_with_zero_gdr, + ids=[p['ID'] for p in params_with_zero_gdr], ) -def test_loan_costs_with_zero_GDR(param): +def test_loan_costs_with_zero_gdr(test_case: LoanCostTestCase) -> None: """ Test the formula with zero for GDR to make sure it is handled correctly. The formula risks division by zero if this is not correct. """ - model_cost, undiscounted_cost = loan_costs(**param) - assert model_cost == pytest.approx(param['model_cost'], abs=0.01) - assert undiscounted_cost == pytest.approx(param['undiscounted_cost'], abs=0.01) + model_cost, undiscounted_cost = loan_costs(**test_case['input']) + assert model_cost == pytest.approx(test_case['expected_model_cost'], abs=0.01) + assert undiscounted_cost == pytest.approx(test_case['expected_undiscounted_cost'], abs=0.01) diff --git a/tests/test_tech_activity_vectors.py b/tests/test_tech_activity_vectors.py index 258cc4bfa..85da17e0d 100644 --- a/tests/test_tech_activity_vectors.py +++ b/tests/test_tech_activity_vectors.py @@ -1,30 +1,3 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 4/16/24 - -""" import pytest from temoa.extensions.modeling_to_generate_alternatives.tech_activity_vector_manager import ( @@ -32,7 +5,7 @@ ) -def test__vector_engine(): +def test__vector_engine() -> None: """ Make sure the basis generation algorithm is accurate. In this test case, there are unequal number of members per category and differing variables per member. We should come up with diff --git a/tests/test_temoa_sequencer.py b/tests/test_temoa_sequencer.py index 6a5b38b90..334df5686 100644 --- a/tests/test_temoa_sequencer.py +++ b/tests/test_temoa_sequencer.py @@ -1,4 +1,5 @@ from pathlib import Path +from typing import Any import pytest from pyomo.environ import ConcreteModel @@ -22,8 +23,13 @@ ] -@pytest.mark.parametrize('run_data', run_params, ids=lambda p: p['name']) -def test_sequencer_start(run_data, tmp_path): +def id_func(p: dict[str, Any]) -> str: + return p['name'] + + +# Suppress mypy error for pytest.mark.parametrize by using a more specific ignore +@pytest.mark.parametrize('run_data', run_params, ids=id_func) +def test_sequencer_start(run_data: dict[str, Any], tmp_path: Path) -> None: """ Tests the main `start()` method for various run modes. """ @@ -42,13 +48,12 @@ def test_sequencer_start(run_data, tmp_path): mode_override=run_data['mode'], ) - # Step 3: Call the `start()` method and assert it returns None on success. + # Step 3: Call the `start()` method. # Any failure will raise an exception, which pytest will catch. - result = sequencer.start() - assert result is None, 'sequencer.start() should return None on success' + sequencer.start() -def test_sequencer_build_model(tmp_path): +def test_sequencer_build_model(tmp_path: Path) -> None: """ Tests the dedicated `build_model()` method for the BUILD_ONLY mode. """ diff --git a/tests/test_validators.py b/tests/test_validators.py index 9e41e8eac..1adfc8af8 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -1,44 +1,23 @@ """ Tests for the validators for regions, linked regions, and region groups - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 9/28/23 - -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - """ +from typing import cast + import pyomo.environ as pyo import pytest +from temoa.core.model import TemoaModel from temoa.model_checking.validators import ( linked_region_check, no_slash_or_pipe, region_check, region_group_check, ) +from temoa.types.core_types import Region -def test_region_check(): +def test_region_check() -> None: """ Test good region names """ @@ -50,12 +29,14 @@ def test_region_check(): ' R12', # leading spaces 'global', # illegal for individual region } - assert all(region_check(None, region=r) for r in good_names) + assert all(region_check(cast(TemoaModel, None), region=cast(Region, r)) for r in good_names) for bad_name in bad_names: - assert not region_check(None, region=bad_name), f'This should fail {bad_name}' + assert not region_check(cast(TemoaModel, None), region=cast(Region, bad_name)), ( + f'This should fail {bad_name}' + ) -def test_linked_region_check(): +def test_linked_region_check() -> None: """ Test legal pairings for linked regions """ @@ -72,12 +53,14 @@ def test_linked_region_check(): 'AZ - Mexico', # bad spacing 'AZ-R2-Mexico', # triples not allowed } - assert all(linked_region_check(m, region_pair=rp) for rp in good_names) + assert all(linked_region_check(cast(TemoaModel, m), region_pair=rp) for rp in good_names) for bad_name in bad_names: - assert not linked_region_check(m, region_pair=bad_name), f'This should fail {bad_name}' + assert not linked_region_check(cast(TemoaModel, m), region_pair=bad_name), ( + f'This should fail {bad_name}' + ) -def test_region_group_check(): +def test_region_group_check() -> None: """ Test legal multi-region groupings """ @@ -92,9 +75,13 @@ def test_region_group_check(): 'Region3', # singleton not in m.R } for name in good_names: - assert region_group_check(m, name), f'This name should have been good: {name}' + assert region_group_check(cast(TemoaModel, m), rg=name), ( + f'This name should have been good: {name}' + ) for name in bad_names: - assert not region_group_check(m, name), f'This name should have failed: {name}' + assert not region_group_check(cast(TemoaModel, m), rg=name), ( + f'This name should have failed: {name}' + ) params = [ @@ -107,5 +94,5 @@ def test_region_group_check(): @pytest.mark.parametrize('value, expected', params) -def test_no_slash(value, expected): - assert no_slash_or_pipe(model=None, element=value) == expected +def test_no_slash(value: str | int, *, expected: bool) -> None: + assert no_slash_or_pipe(model=cast(TemoaModel, None), element=value) == expected diff --git a/tests/utilities/namespace_mock.py b/tests/utilities/namespace_mock.py index 5ba0c69d7..062afc5da 100644 --- a/tests/utilities/namespace_mock.py +++ b/tests/utilities/namespace_mock.py @@ -1,32 +1,3 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 4/1/24 - -""" - - class Namespace: - def __init__(self, **kwargs): + def __init__(self, **kwargs: object) -> None: self.__dict__.update(kwargs) From 0a59b0d0c81c1a3838a22e9c9231292a4e7c56ab Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 13 Nov 2025 10:13:42 -0500 Subject: [PATCH 333/587] adding ci scripts to deploy changes in the unstable --- .github/scripts/deploy_nightly_pypi.py | 256 +++++++++++++++++++++++++ .github/workflows/deploy-nightly.yml | 132 +++++++++++++ 2 files changed, 388 insertions(+) create mode 100644 .github/scripts/deploy_nightly_pypi.py create mode 100644 .github/workflows/deploy-nightly.yml diff --git a/.github/scripts/deploy_nightly_pypi.py b/.github/scripts/deploy_nightly_pypi.py new file mode 100644 index 000000000..816f22af1 --- /dev/null +++ b/.github/scripts/deploy_nightly_pypi.py @@ -0,0 +1,256 @@ +import os +import shutil # Added for cleanup +import subprocess +from datetime import datetime, timezone +from typing import Any + +import boto3 +import tomli +import tomli_w +from botocore.exceptions import ClientError + +# --- Configuration (from environment variables) --- +# Secrets +R2_ACCOUNT_ID = os.environ['R2_ACCOUNT_ID'] +R2_ACCESS_KEY_ID = os.environ['R2_ACCESS_KEY_ID'] +R2_SECRET_ACCESS_KEY = os.environ['R2_SECRET_ACCESS_KEY'] +NIGHTLIES_GH_TOKEN = os.environ['NIGHTLIES_GH_TOKEN'] +# Variables +R2_BUCKET_NAME = os.environ['R2_BUCKET_NAME'] +R2_PACKAGES_PUBLIC_URL = os.environ['R2_PACKAGES_PUBLIC_URL'] +GH_PAGES_INDEX_BASE_URL = os.environ['GH_PAGES_INDEX_BASE_URL'] +GH_PAGES_REPO = os.environ['GH_PAGES_REPO'] +GH_PAGES_BRANCH = os.environ['GH_PAGES_BRANCH'] +SOURCE_COMMIT_SHA = os.environ.get('SOURCE_COMMIT_SHA', 'N/A') # Passed from workflow + +# --- Constants --- +TEMPORARY_OUTPUT_DIR = '/tmp/gh_pages_output' # Temporary dir for dumb-pypi output +NIGHTLIES_REPO_CLONE_DIR = '/tmp/nightlies_repo_clone' # Temporary dir for cloning gh-pages repo +UPLOADED_PACKAGE_LIST_FILE = os.path.join(TEMPORARY_OUTPUT_DIR, 'uploaded_package_list.txt') + + +# --- Boto3 S3 Client for R2 --- +s3_client = boto3.client( + 's3', + endpoint_url=f'https://{R2_ACCOUNT_ID}.r2.cloudflarestorage.com', + aws_access_key_id=R2_ACCESS_KEY_ID, + aws_secret_access_key=R2_SECRET_ACCESS_KEY, +) + + +def run_command( + command: list[str], + cwd: str | None = None, + check: bool = True, + mask_values: list[str] | None = None, +) -> str: + """Helper to run shell commands.""" + + def _redact(text: str) -> str: + if not mask_values: + return text + redacted = text + for secret in mask_values: + if secret: + redacted = redacted.replace(secret, '***') + return redacted + + print(f'Running command: {" ".join(_redact(part) for part in command)}') + result = subprocess.run(command, cwd=cwd, capture_output=True, text=True, check=check) + if result.stdout: + print(_redact(result.stdout)) + if result.stderr and check: + print(_redact(result.stderr)) + return result.stdout.strip() + + +def get_current_temoa_version() -> str: + """Reads the base version from pyproject.toml.""" + with open('pyproject.toml', 'rb') as f: + data = tomli.load(f) + return data['project']['version'] + + +def generate_nightly_version(base_version: str) -> str: + """Generates a PEP 440 compliant nightly version string.""" + today = datetime.now(timezone.utc).strftime('%Y%m%d') + return f'{base_version}.dev{today}' + + +def upload_packages_to_r2(dist_dir: str) -> None: + """Uploads built packages from dist_dir to R2 and lists filenames.""" + os.makedirs(os.path.dirname(UPLOADED_PACKAGE_LIST_FILE), exist_ok=True) + uploaded_filenames = [] + for filename in os.listdir(dist_dir): + file_path = os.path.join(dist_dir, filename) + if os.path.isfile(file_path): + print(f'Uploading {filename} to R2 bucket {R2_BUCKET_NAME}...') + try: + s3_client.upload_file( + file_path, + R2_BUCKET_NAME, + filename, + ExtraArgs={'ContentType': 'application/octet-stream'}, + ) + print(f'Successfully uploaded {filename}') + uploaded_filenames.append(filename) + except ClientError as e: + print(f'āŒ ERROR uploading {filename} to R2: {e}') + raise + + with open(UPLOADED_PACKAGE_LIST_FILE, 'w') as f: + for fname in uploaded_filenames: + f.write(f'{fname}\n') + print(f'Generated {UPLOADED_PACKAGE_LIST_FILE} with {len(uploaded_filenames)} files.') + + +def deploy_dumb_pypi_index(nightly_version: str) -> None: + """Generates dumb-pypi index and pushes to GitHub Pages.""" + print(f'Generating dumb-pypi index in {TEMPORARY_OUTPUT_DIR}...') + run_command(['mkdir', '-p', TEMPORARY_OUTPUT_DIR]) + + # Run dumb-pypi (this will use the dumb-pypi executable found in uv env) + run_command( + [ + 'dumb-pypi', + '--package-list', + UPLOADED_PACKAGE_LIST_FILE, + '--packages-url', + R2_PACKAGES_PUBLIC_URL, + '--output-dir', + os.path.join(TEMPORARY_OUTPUT_DIR, 'simple/'), + ] + ) + print('dumb-pypi index generated.') + + print(f'Cloning {GH_PAGES_REPO} to {NIGHTLIES_REPO_CLONE_DIR}...') + run_command( + [ + 'git', + 'clone', + f'https://x-access-token:{NIGHTLIES_GH_TOKEN}@github.com/{GH_PAGES_REPO}.git', + NIGHTLIES_REPO_CLONE_DIR, + ], + mask_values=[NIGHTLIES_GH_TOKEN], + ) + + run_command( + ['git', 'config', 'user.name', os.environ.get('GITHUB_ACTOR', 'github-actions[bot]')], + cwd=NIGHTLIES_REPO_CLONE_DIR, + ) # Use GITHUB_ACTOR if available + run_command( + ['git', 'config', 'user.email', 'github-actions[bot]@users.noreply.github.com'], + cwd=NIGHTLIES_REPO_CLONE_DIR, + ) + + # Ensure the target branch exists or create it as orphan + # Check if branch exists by trying to switch without creating + try: + run_command(['git', 'checkout', GH_PAGES_BRANCH], cwd=NIGHTLIES_REPO_CLONE_DIR) + except subprocess.CalledProcessError: + try: + run_command( + ['git', 'checkout', '--track', f'origin/{GH_PAGES_BRANCH}'], + cwd=NIGHTLIES_REPO_CLONE_DIR, + ) + except subprocess.CalledProcessError: + run_command( + ['git', 'checkout', '--orphan', GH_PAGES_BRANCH], cwd=NIGHTLIES_REPO_CLONE_DIR + ) + + # Clean existing content (except .git) + # Use shutil.rmtree for directories and os.remove for files + for item in os.listdir(NIGHTLIES_REPO_CLONE_DIR): + if item == '.git': + continue + item_path = os.path.join(NIGHTLIES_REPO_CLONE_DIR, item) + if os.path.isfile(item_path): + os.remove(item_path) + elif os.path.isdir(item_path): + shutil.rmtree(item_path) # Use shutil for robust directory deletion + + print( + f'Copying generated index from {TEMPORARY_OUTPUT_DIR}/simple/ to {NIGHTLIES_REPO_CLONE_DIR}...' + ) + for item in os.listdir(os.path.join(TEMPORARY_OUTPUT_DIR, 'simple')): + src_path = os.path.join(TEMPORARY_OUTPUT_DIR, 'simple', item) + dest_path = os.path.join(NIGHTLIES_REPO_CLONE_DIR, item) + if os.path.isfile(src_path): + shutil.copy2(src_path, dest_path) + elif os.path.isdir(src_path): + shutil.copytree(src_path, dest_path) + + run_command(['git', 'add', '.'], cwd=NIGHTLIES_REPO_CLONE_DIR) + + commit_message = ( + f'Automated nightly deploy of Temoa {nightly_version} (source commit: {SOURCE_COMMIT_SHA})' + ) + + try: + run_command(['git', 'commit', '-m', commit_message], cwd=NIGHTLIES_REPO_CLONE_DIR) + print('Committing changes...') + run_command( + ['git', 'push', 'origin', GH_PAGES_BRANCH], + cwd=NIGHTLIES_REPO_CLONE_DIR, + mask_values=[NIGHTLIES_GH_TOKEN], + ) + print('āœ… Nightly index pushed to GitHub Pages.') + except subprocess.CalledProcessError as e: + if 'nothing to commit' in e.stderr: + print('No changes to commit for GitHub Pages index.') + else: + print(f'āŒ ERROR committing/pushing to GitHub Pages: {e}') + raise + + print(f'Nightly build index updated on GitHub Pages: {GH_PAGES_INDEX_BASE_URL}simple/') + + +def main() -> None: + """Main execution function for nightly PyPI deployment.""" + print('Starting Temoa nightly PyPI deployment process...') + + # 1. Determine version + base_version = get_current_temoa_version() + nightly_version = generate_nightly_version(base_version) + print(f'Nightly version to deploy: {nightly_version}') + + # 2. Store original pyproject.toml data for restoration + + original_pyproject_data: dict[str, Any] + with open('pyproject.toml', 'rb') as f: + original_pyproject_data = tomli.load(f) + + # Use try-finally to guarantee restoration + try: + # 3. Create a copy to modify for the build version + modified_data = original_pyproject_data.copy() + modified_data['project']['version'] = nightly_version + + with open('pyproject.toml', 'wb') as f: + tomli_w.dump(modified_data, f) + print(f'Temporarily updated pyproject.toml version to {nightly_version}') + + # 4. Build sdist and wheel + dist_dir = 'dist' + run_command(['uv', 'build', '--sdist', '--wheel']) # Using uv build + print('sdist and wheel built.') + + # 5. Upload packages to R2 + upload_packages_to_r2(dist_dir) + print('Packages uploaded to R2.') + + # 6. Generate dumb-pypi index and push to GitHub Pages + deploy_dumb_pypi_index(nightly_version) + print('dumb-pypi index deployed.') + + finally: + # 7. Restore original pyproject.toml unconditionally + with open('pyproject.toml', 'wb') as f: + tomli_w.dump(original_pyproject_data, f) + print('Restored original pyproject.toml.') + + print('āœ… Temoa nightly PyPI deployment complete.') + + +if __name__ == '__main__': + main() diff --git a/.github/workflows/deploy-nightly.yml b/.github/workflows/deploy-nightly.yml new file mode 100644 index 000000000..b9924484b --- /dev/null +++ b/.github/workflows/deploy-nightly.yml @@ -0,0 +1,132 @@ +# .github/workflows/deploy-nightly.yml +name: Deploy Temoa Nightlies + +on: + workflow_dispatch: + inputs: + reason: + description: "Reason for manual trigger (e.g., hotfix, test)" + required: false + default: "Manual deploy" + schedule: + - cron: "0 0 * * *" # Every day at 00:00 UTC + +jobs: + check_for_changes_and_test: + runs-on: ubuntu-latest + outputs: + should_deploy: ${{ steps.check_changes.outputs.should_deploy }} + unstable_branch_sha: ${{ steps.get_unstable_sha.outputs.sha }} + + env: + NIGHTLIES_GH_TOKEN: ${{ secrets.NIGHTLIES_GH_TOKEN }} + GH_PAGES_REPO: ${{ vars.GH_PAGES_REPO }} + GH_PAGES_BRANCH: ${{ vars.GH_PAGES_BRANCH }} + SOURCE_BRANCH_FOR_NIGHTLIES: unstable + + steps: + - name: Checkout the source branch for nightlies (unstable) + uses: actions/checkout@v4 + with: + ref: ${{ env.SOURCE_BRANCH_FOR_NIGHTLIES }} + fetch-depth: 0 + + - name: Get SHA of the unstable branch + id: get_unstable_sha + run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" + + - name: Fetch last deployed SHA from nightlies repo + id: get_last_deployed + run: | + git clone "https://x-access-token:${{ env.NIGHTLIES_GH_TOKEN }}@github.com/${{ env.GH_PAGES_REPO }}.git" /tmp/nightlies_repo_check + cd /tmp/nightlies_repo_check + git checkout ${{ env.GH_PAGES_BRANCH }} || git checkout --orphan ${{ env.GH_PAGES_BRANCH }} + LAST_DEPLOYED_SHA=$(git log -1 --pretty=format:%H || echo "") + + echo "LAST_DEPLOYED_SHA=$LAST_DEPLOYED_SHA" >> "$GITHUB_OUTPUT" + echo "Current source branch (${{ env.SOURCE_BRANCH_FOR_NIGHTLIES }} HEAD): ${{ steps.get_unstable_sha.outputs.sha }}" + + - name: Determine if deployment is needed + id: check_changes + run: | + CURRENT_SOURCE_SHA="${{ steps.get_unstable_sha.outputs.sha }}" + LAST_DEPLOYED_SHA="${{ steps.get_last_deployed.outputs.LAST_DEPLOYED_SHA }}" + + SHOULD_DEPLOY="false" + + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + echo "Triggered manually, attempting deployment." + SHOULD_DEPLOY="true" + elif [[ "$CURRENT_SOURCE_SHA" != "$LAST_DEPLOYED_SHA" ]]; then + echo "Changes detected on source branch (${{ env.SOURCE_BRANCH_FOR_NIGHTLIES }} HEAD: $CURRENT_SOURCE_SHA, last deployed: $LAST_DEPLOYED_SHA). Attempting deployment." + SHOULD_DEPLOY="true" + else + echo "No new changes on source branch since last deployment ($CURRENT_SOURCE_SHA == $LAST_DEPLOYED_SHA). Skipping deployment." + fi + + echo "should_deploy=$SHOULD_DEPLOY" >> "$GITHUB_OUTPUT" + + - name: Install uv + uses: astral-sh/setup-uv@v6 + with: + version: "0.9.6" + python-version: "3.12" + enable-cache: true + + - name: Install the project (with all extras for comprehensive testing) + run: uv sync --locked --all-extras --dev + + - name: Install CBC solver + run: | + sudo apt-get update + sudo apt-get install -y coinor-cbc + + - name: Run tests + env: + CI: 1 + run: uv run pytest tests + + - name: Run type check (mypy) + run: uv run mypy --config-file=pyproject.toml temoa/ + + deploy_nightly_artifacts: + needs: check_for_changes_and_test + if: success() && needs.check_for_changes_and_test.outputs.should_deploy == 'true' + runs-on: ubuntu-latest + + permissions: + contents: write + + env: + R2_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_R2_ACCOUNT_ID }} + R2_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }} + R2_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }} + NIGHTLIES_GH_TOKEN: ${{ secrets.NIGHTLIES_GH_TOKEN }} + + R2_BUCKET_NAME: ${{ vars.R2_BUCKET_NAME }} + R2_PACKAGES_PUBLIC_URL: ${{ vars.R2_PACKAGES_PUBLIC_URL }} + GH_PAGES_INDEX_BASE_URL: ${{ vars.GH_PAGES_INDEX_BASE_URL }} + GH_PAGES_REPO: ${{ vars.GH_PAGES_REPO }} + GH_PAGES_BRANCH: ${{ vars.GH_PAGES_BRANCH }} + SOURCE_COMMIT_SHA: ${{ needs.check_for_changes_and_test.outputs.unstable_branch_sha }} + SOURCE_BRANCH_FOR_NIGHTLIES: unstable # Also define here for the checkout action + + steps: + - name: Checkout the source branch for nightlies (unstable) + uses: actions/checkout@v4 + with: + ref: ${{ env.SOURCE_BRANCH_FOR_NIGHTLIES }} + fetch-depth: 0 + + - name: Install uv and project dependencies for deployment script + uses: astral-sh/setup-uv@v6 + with: + version: "0.9.6" + python-version: "3.12" + enable-cache: true + + - name: Install deploy script specific dependencies (boto3, dumb-pypi, tomli_w) + run: uv pip install boto3 dumb-pypi tomli tomli_w + + - name: Run Python Deployment Script + run: uv run python .github/scripts/deploy_nightly_pypi.py From 0275980ff2c8b8a3ff39f5da5411fe419204e397 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Mon, 17 Nov 2025 14:10:18 -0500 Subject: [PATCH 334/587] swapping from tomli to tomlkit --- .github/scripts/deploy_nightly_pypi.py | 26 ++++++++++++++------------ .github/workflows/deploy-nightly.yml | 4 ++-- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/.github/scripts/deploy_nightly_pypi.py b/.github/scripts/deploy_nightly_pypi.py index 816f22af1..e02f0fa9e 100644 --- a/.github/scripts/deploy_nightly_pypi.py +++ b/.github/scripts/deploy_nightly_pypi.py @@ -1,12 +1,12 @@ +import copy import os -import shutil # Added for cleanup +import shutil import subprocess from datetime import datetime, timezone from typing import Any import boto3 -import tomli -import tomli_w +import tomlkit from botocore.exceptions import ClientError # --- Configuration (from environment variables) --- @@ -66,8 +66,8 @@ def _redact(text: str) -> str: def get_current_temoa_version() -> str: """Reads the base version from pyproject.toml.""" - with open('pyproject.toml', 'rb') as f: - data = tomli.load(f) + with open('pyproject.toml') as f: + data = tomlkit.parse(f.read()) return data['project']['version'] @@ -119,6 +119,8 @@ def deploy_dumb_pypi_index(nightly_version: str) -> None: R2_PACKAGES_PUBLIC_URL, '--output-dir', os.path.join(TEMPORARY_OUTPUT_DIR, 'simple/'), + '--title', + 'Temoa Nightly PyPI Index', ] ) print('dumb-pypi index generated.') @@ -217,17 +219,17 @@ def main() -> None: # 2. Store original pyproject.toml data for restoration original_pyproject_data: dict[str, Any] - with open('pyproject.toml', 'rb') as f: - original_pyproject_data = tomli.load(f) + with open('pyproject.toml') as f: + original_pyproject_data = tomlkit.parse(f.read()) # Use try-finally to guarantee restoration try: # 3. Create a copy to modify for the build version - modified_data = original_pyproject_data.copy() + modified_data = copy.deepcopy(original_pyproject_data) modified_data['project']['version'] = nightly_version - with open('pyproject.toml', 'wb') as f: - tomli_w.dump(modified_data, f) + with open('pyproject.toml', 'w') as f: + f.write(tomlkit.dumps(modified_data)) print(f'Temporarily updated pyproject.toml version to {nightly_version}') # 4. Build sdist and wheel @@ -245,8 +247,8 @@ def main() -> None: finally: # 7. Restore original pyproject.toml unconditionally - with open('pyproject.toml', 'wb') as f: - tomli_w.dump(original_pyproject_data, f) + with open('pyproject.toml', 'w') as f: + f.write(tomlkit.dumps(original_pyproject_data)) print('Restored original pyproject.toml.') print('āœ… Temoa nightly PyPI deployment complete.') diff --git a/.github/workflows/deploy-nightly.yml b/.github/workflows/deploy-nightly.yml index b9924484b..239e7e5d7 100644 --- a/.github/workflows/deploy-nightly.yml +++ b/.github/workflows/deploy-nightly.yml @@ -125,8 +125,8 @@ jobs: python-version: "3.12" enable-cache: true - - name: Install deploy script specific dependencies (boto3, dumb-pypi, tomli_w) - run: uv pip install boto3 dumb-pypi tomli tomli_w + - name: Install deploy script specific dependencies (boto3, dumb-pypi, tomlkit) + run: uv pip install boto3 dumb-pypi tomlkit - name: Run Python Deployment Script run: uv run python .github/scripts/deploy_nightly_pypi.py From 93f5bea72cf0d6ce1c5c64a7e9076b8e4af0a180 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Mon, 17 Nov 2025 15:58:41 -0500 Subject: [PATCH 335/587] checking if solver in path and helpful messaging --- temoa/cli.py | 20 +++++- temoa/core/config.py | 56 +++++++++------ tests/test_cli.py | 166 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 218 insertions(+), 24 deletions(-) diff --git a/temoa/cli.py b/temoa/cli.py index fc4feaf78..b530225a7 100644 --- a/temoa/cli.py +++ b/temoa/cli.py @@ -13,7 +13,7 @@ from rich.text import Text from temoa._internal.temoa_sequencer import TemoaSequencer -from temoa.core.config import TemoaConfig +from temoa.core.config import SOLVER_DOC_LINKS, TemoaConfig from temoa.core.modes import TemoaMode from temoa.utilities import db_migration_v3_1_to_v4, sql_migration_v3_1_to_v4 from temoa.version_information import TEMOA_MAJOR, TEMOA_MINOR @@ -98,6 +98,14 @@ def _setup_sequencer( return sequencer, final_output_path +def _check_cbc_availability() -> bool: + """ + Checks if the CBC solver is available in the system's PATH. + Returns True if found, False otherwise. + """ + return shutil.which('cbc') is not None + + # ============================================================================= # Callbacks and Typer App Setup # ============================================================================= @@ -593,6 +601,16 @@ def tutorial( ) rich.print("[dim]Results will be saved in the 'output_files' directory.[/dim]") + if not _check_cbc_availability(): + cbc_doc_link = SOLVER_DOC_LINKS.get('cbc') + rich.print('\n[bold yellow]āš ļø Important: CBC Solver Not Found[/bold yellow]') + rich.print( + 'The default tutorial configuration uses the [bold]CBC[/bold] solver, ' + "which was not found in your system's PATH.\n" + 'To run the tutorial model successfully, please install CBC. ' + f'Refer to this link for installation guidance: [link={cbc_doc_link}]{cbc_doc_link}[/link]\n' + ) + except Exception as e: logger.exception('Failed to create tutorial files') rich.print(f'\n[bold red]āŒ Failed to create tutorial files:[/bold red] {e}') diff --git a/temoa/core/config.py b/temoa/core/config.py index 72dff879c..c54e22ad7 100644 --- a/temoa/core/config.py +++ b/temoa/core/config.py @@ -1,24 +1,4 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 expanding this from an archive may not have -received this license file. If not, see . -""" - +import shutil import sys import tomllib from logging import getLogger @@ -29,6 +9,20 @@ logger = getLogger(__name__) +class SolverNotAvailableError(Exception): + """Raised when a required solver executable cannot be found in the system's PATH.""" + + +# Dictionary to store installation documentation links for common solvers +SOLVER_DOC_LINKS = { + 'cbc': 'https://github.com/coin-or/Cbc#download (refer to temoa documentation for specific OS steps)', + 'gurobi': 'https://www.gurobi.com/downloads/ (requires license and installation)', + 'cplex': 'https://www.ibm.com/products/ilog-cplex-optimization-studio (requires license and installation)', + 'highs': 'https://ergo-code.github.io/HiGHS/dev/installation/ (refer to documentation for specific OS steps)', + 'glpk': 'https://www.gnu.org/software/glpk/', +} + + class TemoaConfig: """ The overall configuration for a Temoa Scenario @@ -118,6 +112,26 @@ def __init__( raise NotImplementedError('Neos is currently not supported.') self.solver_name = solver_name + + if self.solver_name: + solver_executable = shutil.which(self.solver_name) + if solver_executable is None: + error_message = ( + f"The specified solver '{self.solver_name}' was not found in your system's PATH.\n" + 'Please ensure the solver is installed and its executable is accessible.\n' + ) + if self.solver_name.lower() in SOLVER_DOC_LINKS: + error_message += f'For installation instructions, refer to: {SOLVER_DOC_LINKS[self.solver_name.lower()]}\n' + else: + error_message += "Refer to the solver's official documentation for installation instructions." + raise SolverNotAvailableError(error_message) + else: + logger.info('Using solver: %s found at %s', self.solver_name, solver_executable) + else: + logger.warning( + 'No solver name specified in the configuration. This may lead to errors if a solver is required.' + ) + self.save_excel = save_excel self.save_duals = save_duals self.save_storage_levels = save_storage_levels diff --git a/tests/test_cli.py b/tests/test_cli.py index d3a894c5e..c0cfaaca1 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,4 +1,6 @@ +import re import shutil +import sqlite3 from pathlib import Path import pytest @@ -28,6 +30,27 @@ def create_test_config(tmp_path: Path, db_path: Path) -> Path: return test_config_path +def create_config_with_solver(tmp_path: Path, db_path: Path, solver_name: str) -> Path: + """ + Creates a test config file that points to a specific solver. + """ + test_config_path = create_test_config(tmp_path, db_path) + config_content = test_config_path.read_text() + if re.search(r'^\s*solver_name\s*=', config_content, re.MULTILINE): + config_content = re.sub( + r'^\s*solver_name\s*=\s*".*?"', + f'solver_name = "{solver_name}"', + config_content, + flags=re.MULTILINE, + ) + else: + # Add to the end if not found + config_content += f'\nsolver_name = "{solver_name}"\n' + + test_config_path.write_text(config_content) + return test_config_path + + def test_cli_version() -> None: """Test the `temoa --version` command.""" result = runner.invoke(app, ['--version']) @@ -318,8 +341,6 @@ def test_cli_migrate_sql_file_silent(tmp_path: Path) -> None: def test_cli_migrate_db_file_silent(tmp_path: Path) -> None: """Test migrating a DB file with --silent flag.""" - import sqlite3 # Ensure sqlite3 is imported for this test if not already at top level - input_file = tmp_path / 'test_v3_1_silent.sqlite' conn = sqlite3.connect(input_file) conn.execute('CREATE TABLE MetaData (name TEXT, value TEXT)') @@ -377,3 +398,144 @@ def mock_is_writable(path: Path) -> bool: expected_output_in_cwd = tmp_path / (input_file.stem + '_v4.sql') assert expected_output_in_cwd.exists() assert not (non_writable_mock_parent / (input_file.stem + '_v4.sql')).exists() + + +# ============================================================================= +# Tests for Solver Checks +# ============================================================================= + + +def test_cli_tutorial_warns_if_cbc_missing(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: + """ + Test that the tutorial command warns if CBC is not found. + """ + # Ensure fallback tutorial_assets exists so _copy_tutorial_resources() works via fallback. + fallback_assets = Path(__file__).parent.parent / 'temoa' / 'tutorial_assets' + if not fallback_assets.exists(): + pytest.skip("Skipping tutorial tests as 'temoa/tutorial_assets' directory not found.") + + # Mock shutil.which to simulate CBC not being found + def mock_which_no_cbc(cmd: str) -> None | str: + if cmd == 'cbc': + return None + return shutil.which(cmd) + + monkeypatch.setattr(shutil, 'which', mock_which_no_cbc) + monkeypatch.setattr('temoa.cli._check_cbc_availability', lambda: False) + + # Run the tutorial command in tmp_path as CWD + monkeypatch.chdir(tmp_path) + + result = runner.invoke( + app, + ['tutorial', 'test_config', 'test_db', '--force'], + catch_exceptions=False, + ) + + assert result.exit_code == 0, ( + f'Tutorial command failed: {result.exception}\n{result.stderr}\n{result.stdout}' + ) + assert 'Tutorial Setup Complete!' in result.stdout + assert 'Important: CBC Solver Not Found' in result.stdout + assert 'The default tutorial configuration uses the CBC solver' in result.stdout + + # Just assert that the known URL is present, ignoring line breaks / extra text + assert 'https://github.com/coin-or/Cbc#download' in result.stdout + + # Files should be created in the current working directory (= tmp_path) + assert (tmp_path / 'test_config.toml').exists() + assert (tmp_path / 'test_db.sqlite').exists() + + +def test_cli_tutorial_no_warn_if_cbc_present( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + """ + Test that the tutorial command does NOT warn if CBC is found. + """ + fallback_assets = Path(__file__).parent.parent / 'temoa' / 'tutorial_assets' + if not fallback_assets.exists(): + pytest.skip("Skipping tutorial tests as 'temoa/tutorial_assets' directory not found.") + + # Mock shutil.which to simulate CBC being found + def mock_which_with_cbc(cmd: str) -> str | None: + if cmd == 'cbc': + return '/usr/local/bin/cbc' + return shutil.which(cmd) + + monkeypatch.setattr(shutil, 'which', mock_which_with_cbc) + monkeypatch.setattr('temoa.cli._check_cbc_availability', lambda: True) + + # Run in tmp_path so tutorial files are created there + monkeypatch.chdir(tmp_path) + + result = runner.invoke( + app, + ['tutorial', 'test_config', 'test_db', '--force'], + catch_exceptions=False, + ) + + assert result.exit_code == 0, ( + f'Tutorial command failed: {result.exception}\n{result.stderr}\n{result.stdout}' + ) + assert 'Tutorial Setup Complete!' in result.stdout + assert 'Important: CBC Solver Not Found' not in result.stdout + + assert (tmp_path / 'test_config.toml').exists() + assert (tmp_path / 'test_db.sqlite').exists() + + +def test_cli_validate_fails_if_solver_missing( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + """ + Test that the validate command fails with SolverNotAvailableError if the configured solver is missing. + """ + db_path = Path(__file__).parent / 'testing_outputs' / 'utopia.sqlite' + test_config_path = create_config_with_solver(tmp_path, db_path, 'nonexistent_solver') + + # Mock shutil.which to always return None for any solver check + monkeypatch.setattr(shutil, 'which', lambda _: None) + + args = ['validate', str(test_config_path), '--output', str(tmp_path)] + result = runner.invoke(app, args, catch_exceptions=False) + + assert result.exit_code != 0, ( + f'Validate should have failed: {result.exception}\n{result.stderr}\n{result.stdout}' + ) + assert isinstance(result.exception, SystemExit) + assert result.exception.code == 1 + assert 'āŒ Validation failed:' in result.stdout + assert 'nonexistent_solver' in result.stdout + # Use the more robust phrase for checking installation instructions + assert ( + 'Please ensure the solver is installed and its executable is accessible.' in result.stdout + ) + assert (tmp_path / 'temoa-run.log').exists() + + +def test_cli_run_fails_if_solver_missing(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: + """ + Test that the run command fails with SolverNotAvailableError if the configured solver is missing. + """ + db_path = Path(__file__).parent / 'testing_outputs' / 'utopia.sqlite' + test_config_path = create_config_with_solver(tmp_path, db_path, 'another_nonexistent_solver') + + # Mock shutil.which to always return None for any solver check + monkeypatch.setattr(shutil, 'which', lambda _: None) + + args = ['run', str(test_config_path), '--output', str(tmp_path)] + result = runner.invoke(app, args, catch_exceptions=False) + + assert result.exit_code != 0, ( + f'Run should have failed: {result.exception}\n{result.stderr}\n{result.stdout}' + ) + assert isinstance(result.exception, SystemExit) + assert result.exception.code == 1 + assert 'āŒ An error occurred:' in result.stdout + assert 'another_nonexistent_solver' in result.stdout + # Use the more robust phrase for checking installation instructions + assert ( + 'Please ensure the solver is installed and its executable is accessible.' in result.stdout + ) + assert (tmp_path / 'temoa-run.log').exists() From 0ac88a3ade2dede0f9e68b6bd23572ced594d039 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 18 Nov 2025 09:56:39 -0500 Subject: [PATCH 336/587] moved check to build_config for earlier catch --- temoa/core/config.py | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/temoa/core/config.py b/temoa/core/config.py index c54e22ad7..fb962a0bc 100644 --- a/temoa/core/config.py +++ b/temoa/core/config.py @@ -110,28 +110,8 @@ def __init__( self.neos = neos if self.neos: raise NotImplementedError('Neos is currently not supported.') - self.solver_name = solver_name - if self.solver_name: - solver_executable = shutil.which(self.solver_name) - if solver_executable is None: - error_message = ( - f"The specified solver '{self.solver_name}' was not found in your system's PATH.\n" - 'Please ensure the solver is installed and its executable is accessible.\n' - ) - if self.solver_name.lower() in SOLVER_DOC_LINKS: - error_message += f'For installation instructions, refer to: {SOLVER_DOC_LINKS[self.solver_name.lower()]}\n' - else: - error_message += "Refer to the solver's official documentation for installation instructions." - raise SolverNotAvailableError(error_message) - else: - logger.info('Using solver: %s found at %s', self.solver_name, solver_executable) - else: - logger.warning( - 'No solver name specified in the configuration. This may lead to errors if a solver is required.' - ) - self.save_excel = save_excel self.save_duals = save_duals self.save_storage_levels = save_storage_levels @@ -178,6 +158,23 @@ def build_config(config_file: Path, output_path: Path, silent: bool = False) -> with open(config_file, 'rb') as f: data = tomllib.load(f) + if 'solver_name' in data: + solver_executable = shutil.which(data['solver_name']) + if solver_executable is None: + error_message = ( + f"The specified solver '{data['solver_name']}' was not found in your system's PATH.\n" + 'Please ensure the solver is installed and its executable is accessible.\n' + ) + if data['solver_name'].lower() in SOLVER_DOC_LINKS: + error_message += f'For installation instructions, refer to: {SOLVER_DOC_LINKS[data["solver_name"].lower()]}\n' + else: + error_message += "Refer to the solver's official documentation for installation instructions." + raise SolverNotAvailableError(error_message) + else: + logger.info('Using solver: %s found at %s', data['solver_name'], solver_executable) + else: + raise SolverNotAvailableError('No solver name specified in the configuration.') + tc = TemoaConfig(output_path=output_path, config_file=config_file, silent=silent, **data) logger.info('Scenario Name: %s', tc.scenario) logger.info('Data source: %s', tc.input_database) From fe2974f6f9e052f06df33cd1e22c937f3ae4edff Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 20 Nov 2025 12:56:41 -0500 Subject: [PATCH 337/587] feat: Enable package type checking by adding `py.typed` and updating `pyproject.toml`. --- pyproject.toml | 2 +- temoa/py.typed | 0 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 temoa/py.typed diff --git a/pyproject.toml b/pyproject.toml index 74ffa9ae4..5b94544cf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,7 +74,7 @@ build-backend = "hatchling.build" include = [ "temoa", ] -package-data = { "temoa" = ["db_schema/*.sql", "tutorial_assets/*"] } +package-data = { "temoa" = ["db_schema/*.sql", "tutorial_assets/*", "py.typed"] } [tool.ruff] diff --git a/temoa/py.typed b/temoa/py.typed new file mode 100644 index 000000000..e69de29bb From 668ab95f42be5d9ff776131c429990fab05b5bd8 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 20 Nov 2025 22:08:20 -0500 Subject: [PATCH 338/587] chore: enable UP (pyupgrade) linting rules in pyproject.toml --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 5b94544cf..e7606bd0d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -95,7 +95,8 @@ select = [ "I", # isort "B", # flake8-bugbear "N", # flake8-naming - "G004" # logging-f-string + "G004", # logging-f-string + "UP", # pyupgrade ] ignore = [ "E501", # line too long temporarily ignored From b17ee841e1ee45fb4cd63260be7d81b714066562 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 20 Nov 2025 22:10:39 -0500 Subject: [PATCH 339/587] refactor: apply auto-fixable pyupgrade modernizations (UP017, UP032, UP038) - Convert timezone.utc to datetime.UTC (UP017) - Convert .format() calls to f-strings (UP032) - Use X | Y instead of isinstance(x, (X, Y)) (UP038) --- .github/scripts/deploy_nightly_pypi.py | 4 ++-- temoa/cli.py | 4 ++-- temoa/components/technology.py | 8 ++++---- temoa/components/time.py | 20 ++++++++++---------- temoa/data_processing/make_graphviz.py | 8 ++++---- temoa/model_checking/network_model_data.py | 2 +- temoa/utilities/graph_utils.py | 2 +- 7 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.github/scripts/deploy_nightly_pypi.py b/.github/scripts/deploy_nightly_pypi.py index e02f0fa9e..509250cf1 100644 --- a/.github/scripts/deploy_nightly_pypi.py +++ b/.github/scripts/deploy_nightly_pypi.py @@ -2,7 +2,7 @@ import os import shutil import subprocess -from datetime import datetime, timezone +from datetime import UTC, datetime from typing import Any import boto3 @@ -73,7 +73,7 @@ def get_current_temoa_version() -> str: def generate_nightly_version(base_version: str) -> str: """Generates a PEP 440 compliant nightly version string.""" - today = datetime.now(timezone.utc).strftime('%Y%m%d') + today = datetime.now(UTC).strftime('%Y%m%d') return f'{base_version}.dev{today}' diff --git a/temoa/cli.py b/temoa/cli.py index b530225a7..09d465806 100644 --- a/temoa/cli.py +++ b/temoa/cli.py @@ -1,7 +1,7 @@ import argparse import logging import shutil -from datetime import datetime, timezone +from datetime import UTC, datetime from importlib import resources from pathlib import Path from typing import Annotated @@ -620,7 +620,7 @@ def tutorial( def _is_writable(path: Path) -> bool: """Check if a path is writable.""" try: - test_file = path / f'.temoa_write_test_{datetime.now(timezone.utc).timestamp()}' + test_file = path / f'.temoa_write_test_{datetime.now(UTC).timestamp()}' test_file.touch() test_file.unlink() # Clean up return True diff --git a/temoa/components/technology.py b/temoa/components/technology.py index 7c8f7833e..aa9d15a61 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -265,9 +265,9 @@ def create_survival_curve(model: TemoaModel) -> None: lsc_prev = value(model.lifetime_survival_curve[r, p_prev, t, v]) if lsc - lsc_prev > 0.0001: msg = ( - 'lifetime_survival_curve fraction increases going forward in time from {} to {}. ' + f'lifetime_survival_curve fraction increases going forward in time from {(r, p_prev, t, v)} to {(r, p, t, v)}. ' 'This is not allowed.' - ).format((r, p_prev, t, v), (r, p, t, v)) + ) logger.error(msg) raise ValueError(msg) @@ -323,8 +323,8 @@ def create_survival_curve(model: TemoaModel) -> None: msg = ( 'For the purposes of investment cost accounting, lifetime_survival_curve must be defined ' 'for each individual year. Gaps between defined years will be filled by linear interpolation. ' - 'Otherwise, these individual years can be defined manually. Interpolated processes: {}' - ).format([rtv for rtv in rtv_interpolated]) + f'Otherwise, these individual years can be defined manually. Interpolated processes: {[rtv for rtv in rtv_interpolated]}' + ) logger.info(msg) diff --git a/temoa/components/time.py b/temoa/components/time.py index 364e35b11..8e8c05de9 100644 --- a/temoa/components/time.py +++ b/temoa/components/time.py @@ -102,10 +102,10 @@ def validate_segment_fraction(model: TemoaModel) -> None: extra: set[tuple[int, str, str]] = keys.difference(expected_keys) missing: set[tuple[int, str, str]] = expected_keys.difference(keys) msg: str = ( - 'time_segment_fraction elements for period {} do not match time_season and time_of_day.' - '\n\nIndices missing from time_segment_fraction:\n{}' - '\n\nIndices in time_segment_fraction missing from time_season/time_of_day:\n{}' - ).format(p, missing, extra) + f'time_segment_fraction elements for period {p} do not match time_season and time_of_day.' + f'\n\nIndices missing from time_segment_fraction:\n{missing}' + f'\n\nIndices in time_segment_fraction missing from time_season/time_of_day:\n{extra}' + ) logger.error(msg) raise ValueError(msg) @@ -129,10 +129,10 @@ def get_str_padding(obj: object) -> int: items: str = '\n '.join(f'{str(k):<{key_padding}} = {v}' for k, v in items_list) msg = ( - 'The values of time_segment_fraction do not sum to 1 for period {}. ' + f'The values of time_segment_fraction do not sum to 1 for period {p}. ' 'Each item in segment_fraction represents a fraction of a year, so they must ' - 'total to 1. Current values:\n {}\n\tsum = {}' - ).format(p, items, total) + f'total to 1. Current values:\n {items}\n\tsum = {total}' + ) logger.error(msg) raise Exception(msg) @@ -162,9 +162,9 @@ def validate_time_manual(model: TemoaModel) -> None: if missing_psd or missing_psd_next: msg: str = ( 'Failed to build state sequence. ' - '\nThese states from time_segment_fraction were not given a next state:\n{}\n' - '\nThese states from time_segment_fraction do not follow any state:\n{}' - ).format(missing_psd, missing_psd_next) + f'\nThese states from time_segment_fraction were not given a next state:\n{missing_psd}\n' + f'\nThese states from time_segment_fraction do not follow any state:\n{missing_psd_next}' + ) logger.error(msg) raise ValueError(msg) diff --git a/temoa/data_processing/make_graphviz.py b/temoa/data_processing/make_graphviz.py index 3f4ff8730..8c1cd5d45 100644 --- a/temoa/data_processing/make_graphviz.py +++ b/temoa/data_processing/make_graphviz.py @@ -269,9 +269,9 @@ def create_tech_results_diagrams( if row['input_comm'] != 'ethos': enodes.add((row['input_comm'], enode_attr_fmt % (row['input_comm'], period))) - iedges.add((row['input_comm'], vnode, 'label="%.2f"' % row['flow_in'])) + iedges.add((row['input_comm'], vnode, 'label="{:.2f}"'.format(row['flow_in']))) enodes.add((row['output_comm'], enode_attr_fmt % (row['output_comm'], period))) - oedges.add((vnode, row['output_comm'], 'label="%.2f"' % row['flow_out'])) + oedges.add((vnode, row['output_comm'], 'label="{:.2f}"'.format(row['flow_out']))) output_path = output_name + '.' + output_format if vnodes: @@ -340,7 +340,7 @@ def create_commodity_partial_results( t = flow_in.iloc[i]['tech'] f = flow_in.iloc[i]['flow'] enodes.add((t, node_attr_fmt % (t, period))) - eedges.add((comm, t, 'label="%.2f"' % f)) + eedges.add((comm, t, f'label="{f:.2f}"')) for t in output_total - otechs: dnodes.add((t, '')) dedges.add((comm, t, '')) @@ -348,7 +348,7 @@ def create_commodity_partial_results( t = flow_out.iloc[i]['tech'] f = flow_out.iloc[i]['flow'] enodes.add((t, node_attr_fmt % (t, period))) - eedges.add((t, comm, 'label="%.2f"' % f)) + eedges.add((t, comm, f'label="{f:.2f}"')) for t in input_total - itechs: dnodes.add((t, '')) dedges.add((t, comm, '')) diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index 1c79db095..681320016 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -146,7 +146,7 @@ def build(data: ModelBlock | DbConnection, *args: object, **kwargs: object) -> N def _get_builder(data: ModelBlock | DbConnection) -> Callable[..., NetworkModelData]: """Selects the appropriate builder function based on the input data type.""" - if isinstance(data, (TemoaModel, ConcreteModel)): + if isinstance(data, TemoaModel | ConcreteModel): return _build_from_model if isinstance(data, sqlite3.Connection): return _build_from_db diff --git a/temoa/utilities/graph_utils.py b/temoa/utilities/graph_utils.py index 4975270fb..611b6c712 100644 --- a/temoa/utilities/graph_utils.py +++ b/temoa/utilities/graph_utils.py @@ -39,7 +39,7 @@ GraphType = TypeVar('GraphType', nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph) -def convert_graph_to_json( +def convert_graph_to_json[GraphType: (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)]( nx_graph: GraphType, override_node_properties: dict[str, Any] | None, override_edge_properties: dict[str, Any] | None, From 68c4e4ecbfd2d011bb13128d84fe78895573e391 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 20 Nov 2025 22:11:56 -0500 Subject: [PATCH 340/587] refactor: convert Optional[X] to X | None syntax (UP045) - Updated all type aliases in set_types.py to use modern union syntax - Removed Optional import as it's no longer needed - Added noqa comment for intentional printf-style format in commodities.py --- temoa/components/commodities.py | 2 +- temoa/types/set_types.py | 67 +++++++++++++++------------------ 2 files changed, 32 insertions(+), 37 deletions(-) diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index 017dce8ad..8d7b4f723 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -800,7 +800,7 @@ def get_str_padding(obj: Any) -> int: key_padding = max(map(get_str_padding, keys)) - fmt = '%%-%ds = %%s' % key_padding + fmt = '%%-%ds = %%s' % key_padding # noqa: UP031 # Works out to something like "%-25s = %s" items_list: list[tuple[Any, Any]] = sorted( diff --git a/temoa/types/set_types.py b/temoa/types/set_types.py index ad2b73e9d..df1d1df4d 100644 --- a/temoa/types/set_types.py +++ b/temoa/types/set_types.py @@ -1,41 +1,36 @@ -""" -Set types for Temoa energy model. +"""Type aliases for Temoa set types.""" -This module contains set type definitions used for sparse indexing -and various collections in the Temoa model. -""" - -from typing import Optional - -from .core_types import Commodity, Period, Region, Season, Technology, TimeOfDay, Vintage +from temoa.types.core_types import ( + Commodity, + Period, + Region, + Season, + Technology, + TimeOfDay, + Vintage, +) # Set types for sparse indexing -ActiveFlowSet = Optional[ - set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] -] -ActiveFlowAnnualSet = Optional[ - set[tuple[Region, Period, Commodity, Technology, Vintage, Commodity]] -] -ActiveFlexSet = Optional[ - set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] -] -ActiveFlexAnnualSet = Optional[ - set[tuple[Region, Period, Commodity, Technology, Vintage, Commodity]] -] -ActiveFlowInStorageSet = Optional[ - set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] -] -ActiveCurtailmentSet = Optional[ - set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] -] -ActiveActivitySet = Optional[set[tuple[Region, Period, Technology, Vintage]]] -StorageLevelIndicesSet = Optional[ - set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]] -] -SeasonalStorageLevelIndicesSet = Optional[set[tuple[Region, Period, Season, Technology, Vintage]]] -NewCapacitySet = Optional[set[tuple[Region, Technology, Vintage]]] -ActiveCapacityAvailableSet = Optional[set[tuple[Region, Period, Technology]]] -ActiveCapacityAvailableVintageSet = Optional[set[tuple[Region, Period, Technology, Vintage]]] -GroupRegionActiveFlowSet = Optional[set[tuple[Region, Period, Technology]]] +ActiveFlowSet = ( + set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] | None +) +ActiveFlowAnnualSet = set[tuple[Region, Period, Commodity, Technology, Vintage, Commodity]] | None +ActiveFlexSet = ( + set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] | None +) +ActiveFlexAnnualSet = set[tuple[Region, Period, Commodity, Technology, Vintage, Commodity]] | None +ActiveFlowInStorageSet = ( + set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] | None +) +ActiveCurtailmentSet = ( + set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] | None +) +ActiveActivitySet = set[tuple[Region, Period, Technology, Vintage]] | None +StorageLevelIndicesSet = set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]] | None +SeasonalStorageLevelIndicesSet = set[tuple[Region, Period, Season, Technology, Vintage]] | None +NewCapacitySet = set[tuple[Region, Technology, Vintage]] | None +ActiveCapacityAvailableSet = set[tuple[Region, Period, Technology]] | None +ActiveCapacityAvailableVintageSet = set[tuple[Region, Period, Technology, Vintage]] | None +GroupRegionActiveFlowSet = set[tuple[Region, Period, Technology]] | None CommodityBalancedSet = set[tuple[Region, Period, Commodity]] From 9e29f7b59a99bc902a85a668f97c087a7f179365 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 18 Nov 2025 17:53:29 -0500 Subject: [PATCH 341/587] docs: adding markdown support and using pyproject.toml for project info in docs --- docs/automake.sh | 21 --------------------- docs/source/conf.py | 35 +++++++++++++++++++++++++---------- pyproject.toml | 1 + requirements-dev.txt | 21 +++++++++++++++++---- uv.lock | 37 ++++++++++++++++++++++++++++++++++--- 5 files changed, 77 insertions(+), 38 deletions(-) diff --git a/docs/automake.sh b/docs/automake.sh index 3384cb2ad..87d3af9a0 100755 --- a/docs/automake.sh +++ b/docs/automake.sh @@ -1,27 +1,6 @@ #!/bin/bash -# Tools for Energy Model Optimization and Analysis (Temoa): -# An open source framework for energy systems optimization modeling -# -# Copyright (C) 2015, NC State University -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# 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 -# received this license file. If not, see . - - - set -e # Only for ls and inotifywait (to make sure files exist) ... # files to watch diff --git a/docs/source/conf.py b/docs/source/conf.py index 8c897df11..af224d437 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -2,7 +2,10 @@ import os import sys import time -from typing import Any +from pathlib import Path +from typing import Any, cast + +import tomlkit # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -15,16 +18,26 @@ sys.path.insert(1, os.path.abspath('../../temoa/temoa_model')) -# -- Project information ----------------------------------------------------- +# -- Project information from pyproject.toml --------------------------------- + +# Read version and metadata from pyproject.toml for single source of truth +pyproject_path = Path(__file__).parent.parent.parent / 'pyproject.toml' +with open(pyproject_path) as f: + pyproject_data = tomlkit.load(f) +project_metadata = cast(dict[str, Any], pyproject_data['project']) project = 'Tools for Energy Model Optimization and Analysis (Temoa)' -copyright = '2020, NC State University' -author = 'Joe DeCarolis, Kevin Hunter' +author = ', '.join( + author['name'] for author in cast(list[dict[str, Any]], project_metadata.get('authors', [])) +) +copyright = f'2011-{time.strftime("%Y")}, NC State University' # The short X.Y version -version = '3.0' +version = cast(str, project_metadata['version']).rsplit('.', 1)[ + 0 +] # '4.0.0a1.dev20251113' -> '4.0.0a1' # The full version, including alpha/beta/rc tags -release = time.strftime('%F', time.gmtime()) +release = cast(str, project_metadata['version']) # -- General configuration --------------------------------------------------- @@ -45,6 +58,7 @@ 'sphinx.ext.mathjax', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode', + 'myst_parser', # Enable Markdown support ] # Add any paths that contain templates here, relative to this directory. @@ -53,10 +67,11 @@ bibtex_bibfiles = ['References.bib'] # The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] -source_suffix = '.rst' +# Support both reStructuredText and Markdown +source_suffix = { + '.rst': 'restructuredtext', + '.md': 'markdown', +} # The master toctree document. master_doc = 'index' diff --git a/pyproject.toml b/pyproject.toml index 5b94544cf..fece4e4b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,6 +55,7 @@ docs = [ "sphinxcontrib-htmlhelp>=2.1.0", "sphinxcontrib-serializinghtml>=2.0.0", "sphinxcontrib-bibtex>=2.6.2", + "myst-parser>=2.0.0", ] plotting = [ diff --git a/requirements-dev.txt b/requirements-dev.txt index 99a973a88..daa1b24c4 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -20,6 +20,7 @@ dill==0.4.0 # via multiprocess docutils==0.21.2 # via + # myst-parser # pybtex-docutils # sphinx # sphinx-rtd-theme @@ -41,15 +42,20 @@ imagesize==1.4.1 iniconfig==2.1.0 # via pytest jinja2==3.1.6 - # via sphinx + # via + # myst-parser + # sphinx joblib==1.5.1 # via temoa (pyproject.toml) kiwisolver==1.4.8 # via matplotlib latexcodec==3.0.1 # via pybtex -markdown-it-py==4.0.0 - # via rich +markdown-it-py==3.0.0 + # via + # mdit-py-plugins + # myst-parser + # rich markupsafe==3.0.2 # via jinja2 matplotlib==3.9.2 @@ -57,10 +63,14 @@ matplotlib==3.9.2 # temoa (pyproject.toml) # salib # seaborn +mdit-py-plugins==0.5.0 + # via myst-parser mdurl==0.1.2 # via markdown-it-py multiprocess==0.70.18 # via salib +myst-parser==4.0.1 + # via temoa (pyproject.toml) networkx==3.5 # via temoa (pyproject.toml) numpy==2.3.1 @@ -118,7 +128,9 @@ python-dateutil==2.9.0.post0 pytz==2025.2 # via pandas pyyaml==6.0.2 - # via pybtex + # via + # myst-parser + # pybtex requests==2.32.4 # via sphinx rich==14.2.0 @@ -145,6 +157,7 @@ snowballstemmer==3.0.1 sphinx==8.2.3 # via # temoa (pyproject.toml) + # myst-parser # sphinx-rtd-theme # sphinxcontrib-bibtex # sphinxcontrib-jquery diff --git a/uv.lock b/uv.lock index 43d7a8050..8d6f99744 100644 --- a/uv.lock +++ b/uv.lock @@ -442,14 +442,14 @@ wheels = [ [[package]] name = "markdown-it-py" -version = "4.0.0" +version = "3.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mdurl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, + { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, ] [[package]] @@ -526,6 +526,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/01/8a/760f7fce66b39f447ad160800619d0bd5d0936d2b4633587116534a4afe0/matplotlib-3.9.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5816b1e1fe8c192cbc013f8f3e3368ac56fbecf02fb41b8f8559303f24c5015e", size = 9093770, upload-time = "2024-08-13T01:45:15.562Z" }, ] +[[package]] +name = "mdit-py-plugins" +version = "0.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b2/fd/a756d36c0bfba5f6e39a1cdbdbfdd448dc02692467d83816dff4592a1ebc/mdit_py_plugins-0.5.0.tar.gz", hash = "sha256:f4918cb50119f50446560513a8e311d574ff6aaed72606ddae6d35716fe809c6", size = 44655, upload-time = "2025-08-11T07:25:49.083Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/86/dd6e5db36df29e76c7a7699123569a4a18c1623ce68d826ed96c62643cae/mdit_py_plugins-0.5.0-py3-none-any.whl", hash = "sha256:07a08422fc1936a5d26d146759e9155ea466e842f5ab2f7d2266dd084c8dab1f", size = 57205, upload-time = "2025-08-11T07:25:47.597Z" }, +] + [[package]] name = "mdurl" version = "0.1.2" @@ -587,6 +599,23 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, ] +[[package]] +name = "myst-parser" +version = "4.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docutils" }, + { name = "jinja2" }, + { name = "markdown-it-py" }, + { name = "mdit-py-plugins" }, + { name = "pyyaml" }, + { name = "sphinx" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/a5/9626ba4f73555b3735ad86247a8077d4603aa8628537687c839ab08bfe44/myst_parser-4.0.1.tar.gz", hash = "sha256:5cfea715e4f3574138aecbf7d54132296bfd72bb614d31168f48c477a830a7c4", size = 93985, upload-time = "2025-02-12T10:53:03.833Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/df/76d0321c3797b54b60fef9ec3bd6f4cfd124b9e422182156a1dd418722cf/myst_parser-4.0.1-py3-none-any.whl", hash = "sha256:9134e88959ec3b5780aedf8a99680ea242869d012e8821db3126d427edc9c95d", size = 84579, upload-time = "2025-02-12T10:53:02.078Z" }, +] + [[package]] name = "networkx" version = "3.5" @@ -1332,6 +1361,7 @@ dependencies = [ [package.optional-dependencies] docs = [ + { name = "myst-parser" }, { name = "sphinx" }, { name = "sphinx-rtd-theme" }, { name = "sphinxcontrib-bibtex" }, @@ -1367,6 +1397,7 @@ requires-dist = [ { name = "joblib" }, { name = "matplotlib", specifier = "==3.9.2" }, { name = "matplotlib", marker = "extra == 'plotting'", specifier = ">=3.9.2" }, + { name = "myst-parser", marker = "extra == 'docs'", specifier = ">=2.0.0" }, { name = "networkx", specifier = ">=3.3" }, { name = "numpy", specifier = ">=2.1.0" }, { name = "openpyxl", specifier = ">=3.1.5" }, From 88ccbfebc750c840db2946853935b4309e88cec4 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 18 Nov 2025 17:55:09 -0500 Subject: [PATCH 342/587] docs: splitting up the documentation.rst file and updating contents to be in line with source code --- docs/source/Documentation.rst | 3005 +----------------- docs/source/computational_implementation.rst | 865 +++++ docs/source/mathematical_formulation.rst | 1503 +++++++++ docs/source/preface.rst | 101 + docs/source/quick_start.rst | 358 +++ docs/source/visualization.rst | 112 + 6 files changed, 2951 insertions(+), 2993 deletions(-) create mode 100644 docs/source/computational_implementation.rst create mode 100644 docs/source/mathematical_formulation.rst create mode 100644 docs/source/preface.rst create mode 100644 docs/source/quick_start.rst create mode 100644 docs/source/visualization.rst diff --git a/docs/source/Documentation.rst b/docs/source/Documentation.rst index 761218359..82f047787 100644 --- a/docs/source/Documentation.rst +++ b/docs/source/Documentation.rst @@ -1,3020 +1,38 @@ - ======= Preface ======= - -This manual, in both `PDF`_ and `HTML`_ form, is the official documentation of -Tools for Energy Model Optimization and Analysis (Temoa). It describes all -functionality of the Temoa model, and provides a mathematical description of -the implemented equations. - -Besides this documentation, there are a couple other sources for Temoa-oriented -information. The most interactive is the `mailing list`_, and we encourage any -and all questions related to energy system modeling. Publications are good -introductory resources, but are not guaranteed to be the most up-to-date as -information and implementations evolve quickly. As with many software-oriented -projects, even before this manual, `the code is the most definitive resource`. -That said, please let us know (via the `mailing list`_, or other avenue) of any -discrepancies you find, and we will fix it as soon as possible. - -What is Temoa? --------------- - -Temoa is an energy system optimization model (ESOM). Briefly, ESOMs optimize the -installation and utilization of energy technology capacity over a user-defined -time horizon. Optimal decisions are driven by an objective function that minimizes -the cost of energy supply. Conceptually, one may think of an ESOM as a "left-to-right" -network graph, with a set of energy sources on the lefthand side of the graph that -are transformed into consumable energy commodities by a set of energy technologies, -which are ultimately used to meet demands on the righthand side of the network graph. -[#esom_definition]_ - -Key features of the core Temoa model include: - - * Flexible time slicing by season and time-of-day - * Variable length model time periods - * Technology vintaging - * Separate technology loan periods and lifetimes - * Global and technology-specific discount rates - * Capability to perform stochastic optimization - * Capability to perform modeling-to-generate alternatives (MGA) - - -Temoa design features include: - - * Source code licensed under GPLv2, available through Github [#open_source_realities]_ - * Open source software stack - * Part of a rich Python ecosystem - * Data stored in a relational database system (sqlite) - * Ability to utilize multi-core and compute cluster environments - -The word 'Temoa' is actually an acronym for "Tools for Energy Model Optimization -and Analysis," currently composed of four (major) pieces of infrastructure: - - * The mathematical model - * The implemented model (code) - * Surrounding tools - * An online presence - -Each of these pieces is fundamental to creating a transparent and usable model -with a community oriented around collaboration. - - -Why Temoa? ----------- - -In short, because we believe that ESOM-based analyses should be repeatable by -independent third parties. The only way to make this happen is to -have a freely available model, and to create an ecosystem of freely shared data -and model inputs. - -For a longer explanation, please see :cite:`Hunter_etal_2013` (available from -the `project website `_. In summary, -ESOM-based analyses are (1) impossible to validate, (2) complex enough as to be -non-repeatable without electronic access to **exact** versions of code *and* data -input, and (3) often do a poor job addressing uncertainty. We believe that -ESOM-based analyses should be completely open, independently reproducible, -electronically available, and address uncertainty about the future. - - -Temoa Origin and Pronunciation ------------------------------- - -While we use 'Temoa' as an acronym, it is an actual word in the Nahuatl (Aztec) -language, meaning "to seek something." - -.. Figure:: images/temoa_definition.* - :align: center - :figclass: center - :figwidth: 50% - -One pronounces the word 'Temoa' as "teh", "moe", "uh". Though TEMOA is an acronym -for 'Tools for Energy Model Optimization and Analysis', we generally use 'Temoa' -as a proper noun, and so forgo the need for all-caps. - - -Bug Reporting -------------- - -Temoa strives for correctness. Unfortunately, as an energy system model and software -project there are plenty of levels and avenues for error. If you spot a bug, -inconsistency, or general "that could be improved", we want to hear about it. - -If you are a software developer-type, feel free to open an issue on our `GitHub -Issue tracker`_\ . If you would rather not create a GitHub account, feel free -to let us know the issue on our `mailing list`_\ . - +.. include:: preface.rst =========== Quick Start =========== - -Installing Software Elements ----------------------------- - -Temoa is implemented in `Pyomo `_, which is in turn -written in `Python `_. Consequently, Temoa will run on -Linux, Mac, Windows, or any operating system that Pyomo supports. There are -several open source software elements required to run Temoa. The easiest way to -install these elements is to create a conda environment in which to run the -model. Creating a customized environment (or virtual environment) ensures that the latest version of -Temoa is compatible with the required software elements. Currently, users have a choice -between using Pythons :code:`pip` installation tool to set up a virtual environment or use -:code:`anaconda` as described below: - -**Anaconda**: To begin, you need to -have conda installed either via `miniconda -`_ or -`anaconda `_. -Next, download the `environment.yml -`_ file -from our `Github repo `__, and place it in -a new directory named ā€˜temoa-py3.’ Create this new directory in a location where -you wish to store the environment. On a MAc, the anaconda environment files are -stored in the following location by default: :code:`/opt/anaconda/envs` -Navigate to this directory and execute the following from the command line: - -.. parsed-literal:: - $ conda env create - -Then activate the environment as follows: - -.. parsed-literal:: - $ conda activate temoa-py3 - -For additional guidance, `This YouTube tutorial ` -walks through the creation of the Temoa environment. It is slightly dated with the -release of Version 3 of Temoa, but is still informative on how to set up. -More information on virtual environments can be found -`here `_. -This new conda environment contains several elements, including Python 3, a -compatible version of Pyomo, matplotlib, numpy, scipy. - -**Pip**: For those who prefer to use Python's :code:`pip` installation tool, instructions -are included in the top level README.md file - -Solvers -------- - -A few notes for on the choice of solvers. Different solvers -have widely varying solution times. If you plan to run Temoa with large datasets -and/or conduct uncertainty analysis, you may want to consider installing -commercial linear solvers such as `CPLEX -`_ or `Gurobi -`_. Both offer free academic licenses. - -For smaller models, Temoa has been tested with both the `CBC `_ -solver and the more recently released `HiGHS `_ solver. -Each of the respective websites contains installation instructions for the individual -solvers. For those wishing to run the internal tests on Temoa, the :code:`CBC` solver -is required. - -There are three ways to run the model, each of which is detailed below. Note that -the example commands utilize 'temoa_utopia', a commonly used test case for ESOMs. - -Obtaining Temoa ---------------- - -Now that you have functioning environment, you need to obtain the source code -for Temoa. There are a couple of options for obtaining and running Temoa from -GitHub. If you want to simply run the model, you can download Temoa from GitHub -as a zip file. Navigate to our `Github repo `__, -and click the green ā€˜clone or download’ button near the top-right corner. Select -ā€˜Download ZIP,’ and you can download the entire Temoa :code:`main` (our main branch) -to your local machine. The second option creates a local copy of the model source -code in our GitHub repository. This is a two step process: first install git and -then ā€˜clone’ the repository. Under Linux, git can be installed through the default -package manager. Git for Windows and Mac can be downloaded from the `Git website -`_. To clone the Temoa repository, navigate to -the directory where you want the model to reside and type the following from the -prompt: - -.. parsed-literal:: - $ git clone https://github.com/TemoaProject/temoa/ - -Note that cloning the repository will supply the latest version of the code, and -allow you to archive changes to the code and data in your own local git -repository. - -A few basic input data files are included in the :code:`temoa/data_files`` folder. -Additional Temoa-compatible datasets are available in `this separate GitHub -repo `_. - -The installation procedures above are meant to be generic and should work across -different platforms. Nonetheless, system-specific ambiguities and unexpected -conditions inevitably arise. Please use the `Temoa forum -`_ to ask for help. - -Running Temoa -------------- -Temoa should always be run from the top-level from the top-level -:code:`temoa` directory. - -To run the model, a configuration (ā€˜config’) file is needed. An -example config file called :code:`config_sample.toml` resides within the -:code:`data_files/my_configs` folder. Running the model with a config file allows -the user to (1) use a sqlite -database for storing input and output data, (2) create a formatted Excel output -file, (2) specify the solver to use, (3) return the log file produced during -model execution, (4) return the lp file utilized by the solver, and (5) to -execute several of the modeling extensions. - -.. parsed-literal:: - $ python temoa_model/ --config=data_files/my_configs/config_sample.toml - -**For general help, use --help:** - -.. parsed-literal:: - $ **python main.py --help** - usage: main.py [-h] [--config CONFIG_FILE] [-b] [-s] [-d] [-o OUTPUT_PATH] [--how_to_cite] [-v] - - options: - -h, --help show this help message and exit - --config CONFIG_FILE Path to file containing configuration information. - -b, --build_only Build and return an unsolved TemoaModel instance. - -s, --silent Silent run. No prompts. - -d, --debug Set logging level to DEBUG to see debugging output in log file. - -o OUTPUT_PATH, --output_path OUTPUT_PATH - Set the path for log and program outputs to an existing directory. Default is time-stamped folder in output_files. - --how_to_cite Show citation information for publishing purposes. - -v, --version Show current Temoa version - -.. - dated references, preserved as comment here: - - To supplement this documentation, we have also created a - `YouTube video tutorial ` that explains - how to run Temoa from the command line. There is also an option to run - `Temoa on the cloud `, which - is explained in `this video tutorial `. - -==================================== -Database Construction -==================================== - -Input datasets in Temoa can be constructed either as text files or relational -databases. Input text files are referred to as 'DAT' files and follow a specific -format. Take a look at the example DAT files in the :code:`temoa/data_files` -directory. - -While DAT files work fine for small datasets, relational databases are preferred -for larger datasets. To first order, you can think of a database as a collection -of tables, where a 'primary key' within each table defines a unique entry (i.e., -row) within the table. In addition, a 'foreign key' defines a table element drawn -from another table. Foreign keys enforce the defined relationships between -different sets and parameters. - -Temoa uses `sqlite`_, a widely used, self-contained database -system. Building a database first requires constructing a sql file, which is -simply a text file that defines the structure of different database tables and -includes the input data. The snippet below is from the technology table used to -define the 'temoa_utopia' dataset: - -**NOTE**: *As of Version 3, the below table format is dated, but still shows the general structure of -the SQL files used to create the database.* - -.. parsed-literal:: - CREATE TABLE technologies ( - tech text primary key, - flag text, - sector text, - tech_desc text, - tech_category text, - FOREIGN KEY(flag) REFERENCES technology_labels(tech_labels), - FOREIGN KEY(sector) REFERENCES sector_labels(sector)); - INSERT INTO "technologies" VALUES('IMPDSL1','r','supply',' imported diesel','petroleum'); - INSERT INTO "technologies" VALUES('IMPGSL1','r','supply',' imported gasoline','petroleum'); - INSERT INTO "technologies" VALUES('IMPHCO1','r','supply',' imported coal','coal'); - -The first line creates the table. **Lines 2-6** define the columns within this table. -Note that the the technology ('tech') name defines the primary key. Therefore, the -same technology name cannot be entered twice; each technology name must be unique. -**Lines 7-8** define foreign keys within the table. For example, each technology -should be specified with a label (e.g., 'r' for 'resource'). Those labels must -come from the 'technology_labels' table. Likewise, the sector name must be defined -in the 'sector_labels' table. This enforcement of names across tables using -foreign keys helps immediately catch typos. (As you can imagine, typos happen in -plain text files and Excel when defining thousands of rows of data.) Another big -advantage of using databases is that the model run outputs are stored in -separate database output tables. The outputs by model run are indexed by a scenario name, -which makes it possible to perform thousands of runs, programatically store all -the results, and execute arbitrary queries that instantaneously return the requested -data. - -Because some database table elements serve as foreign keys in other tables, we -recommend that you populate input tables in the following order: - -**Group 1: labels used for internal database processing** - * CommodityType: Need to identify which type of commodity. Do NOT change these abbreviations. - * TechnologyType: Need to identify which type of technology. Do NOT change these abbreviations. Categorizing - and sub-categorizing can be done in the Technology table itself. - * TimePeriodType: Used to distinguish which time periods are simply used to specify pre-existing - vintages and which represent future optimization periods. - * SeasonLabel: Unordered unique labels defining seasons in the model. - - -**Group 2: sets used within Temoa** - * Commodity: list of commodities used within the database - * Technology: list of technologies used within the database - * time_period: list of both past and future time periods considered in the database - * time_season: seasons modeled in the database - * time_of_day: time of day segments modeled in the database - - -**Group 3: parameters used to define processes within Temoa** - * MetaDataReal (global_discount_rate) - * MetaData (days_per_period) - * Demand - * demand_specific_distribution - * efficiency - * existing_capacity - * CapacityFactor - * capacity_factor_process (only if CF varies by vintage; overwrites CapacityFactor) - * CapacityToActivity - * cost_fixed - * cost_invest - * cost_variable - * emission_activity - * lifetime_tech - * lifetime_process (only if LT varies by vintage; overwrites lifetime_tech) - * time_segment_fraction: proportion of each period represented by each time slice - -**Group 4: parameters used to define constraints within Temoa** - * limit_activity - * limit_capacity - * limit_emission - * limit_growth_capacity - * limit_new_capacity - * limit_resource - * limit_tech_input_split - * limit_tech_output_split - -For help getting started, take a look at how :code:`data_files/temoa_utopia.sql` is -constructed. Use :code:`data_files/temoa_schema.sql` (a database file with the requisite -structure but no data added) to begin building your own database file. We recommend -leaving the database structure intact, and simply adding data to the schema file, or -constructing an empty database from the schema file and then using a database editor -to import data. -Once the sql file is complete, you can convert it into a binary sqlite file by -installing sqlite3 and executing the following command: - -.. parsed-literal:: - $ sqlite3 my_database.sqlite < my_database.sql - -Now you can specify this database as the source for both input and output data -in the config file. - -============ -Data Quality -============ - -In addition to numerous internal checks, Temoa (optionally) employs two quality checks on -data read in from the database. The outputs (actions and warnings) generated by these processes -are reported in the log file for the run. - -Both of the checks below can be run to QA data by running the model in `CHECK` mode and inspecting -the log file. During `CHECK` mode runs, no solve is attempted on the model. - -Price Checking --------------- -The "price checker" reviews cost data in the 3 cost tables and considers technology lifetime. It -screens for possible inconsistencies that would corrupt output quality. Larger models may have -well over 100K cost entries and an overlooked investment cost for a particular vintage tech in -a particular region could easily be overlooked. Price checks performed/reported: - -1. **Missing Costs (Check 0)**: This check looks for technologies that have no fixed/invest/variable - costs at all. Other checks are more discriminating, so this check is only reported when Temoa is run - in `debug` mode by using the `-d` flag on the run command. -2. **Missing Fixed/Investment Costs (Check 1a)**: This check identifies technologies that are *not* - flagged as `uncapacitated` with neither a fixed or investment cost associated. These *might* be - problematic for solve because the model minimizes cost, so capacity in these technologies would be - free. `uncapacitated` technologies have no capacity measure, so fixed/investment costs are prohibited - for them and that is checked elsewhere. -3. **Inconsistent Fixed/Investment Cost (Check 1b)**: This check looks for inconsistent application - of fixed or base costs in the "base" or vintage year across all vintages and regions. So, if a tech has - a fixed cost in some particular region and vintage year, but not in all, it will be flagged as a likely - omission. -4. **Inconsistent Fixed & Variable Costs (Check 2)**: This check identifies techs that have - inconsistencies in the application of fixed - variable costs. Techs that have *any* fixed cost for - a particular [region, tech, vintage] process, but do not have entries that match the variable cost - entries for the same process are flagged, and vice-versa. This would hopefully identify an - accidental omission of some of the fixed/var costs for processes that have at least 1 entry for either. -5. **Lifetime Costing (Check 3)**: This check identifies costs that fall short or are missing - during the process's lifetime. If a process has a variable cost in *any* year during the lifetime, but - not all years, it is flagged. Same for fixed cost. -6. **Uncapacitated Tech Costs**: Any technology flagged as `uncapacitated` will trigger warnings here - if it has any fixed/invest costs. - -Source Tracing --------------- - -Temoa works backwards from demands to identify chains of technologies required to meet the demand. -Source Tracing is designed to ensure that this backward tracing from demands describes a proper -commodity network without gaps that might allow intermediate commodities to be treated as a free -"source" commodity. Further description of possible network problems is included in the -`commodity network notes.md` file in the `docs` folder. - -Source Tracing pre-builds the entire commodity network in each region-period contained in the -data and analyzes it for "orphans" which likely represent gaps in the network that would lead -to erroneous output data. The operation is enabled by tagging foundational commodities for which -there are no predecessors as "source" commodities in the `Commodity` database table with an `s` tag. -Orphans (or chains of orphans) on either the demand or supply side are reported and *suppressed* in -the data to prevent network corruption. - -Note that the myopic mode *requires* the use of Source Tracing to ensure accuracy as some orphans -may be produced by endogenous decisions in myopic runs. - -Commodity Network Visualization -------------------------------- -The output of the Source Tracing operation can be visualized by enabling the commodity network plots -in the config file. This will add a set of region-period specific html files to the Outputs folder. -These files *should* be open-able in any web browser. (See the note in the main `README.md` for trouble -with Windows OS systems). - -.. Figure:: images/utopia_commodity_network.png - :align: center - :figclass: center - :figwidth: 60% - - An example of the Commodity Network for Utopia (interactive view in web browser by opening - the generated html file) - -The color legend for Commodity Networks is as follows: - -* Green dot: Source Commodity -* Orange dot: Demand Commodity -* Violet dot: Intermediate Commodity -* Black arc: Technology -* Blue arc: Linked Technology (the driven tech, *not* the driver) -* Yellow arc: Supply-Side Orphan (shown, but suppressed when model built) -* Red arc: Demand-Side Orphan (shown, but suppressed when model built) -* Green arc: Any Tech with a Negative Variable Cost +.. include:: quick_start.rst ============= Visualization ============= -Network Diagrams ----------------- - -Since Temoa model consists of an energy network in which technologies are connected -by the flow of energy commodities, a directed network graph represents an excellent way -to visualize a given energy system representation in a Temoa-compatible input database. -Temoa utilizes an open source graphics package called `Graphviz`_ to create a series of -data-specific and interactive energy-system maps. Currently, the output graphs consist of -a full energy system map as well as capacity and activity results per model time period. -In addition, users can create subgraphs focused on a particular commodity or technology. - -There are a couple ways to utilize Graphviz. The first way is to use the version embedded -in the :code:`Network_diagrams.ipynb` jupyter notebook available in the :code:`data_processing` -folder. This `YouTube video tutorial ` walks through the process -of using the jupyter notebook. - -The second way is to use graphviz from the command line. To do so, navigate to the -:code:`data_processing` folder, where the graphviz script resides. To review all of the -graphviz options, use the :code:`--help` flag: - -.. parsed-literal:: - $ python make_graphviz.py --help - -The most basic way to use graphviz is to view the full energy system map: - -.. parsed-literal:: - $ python make_graphviz.py -i ../data_files/temoa_utopia.sqlite - -In the command above, note that we have to point the Graphviz module to the -:code:`temoa_utopia` database file, which resides in the :code:`data_files` -directory. The resultant system map will look like this: - -.. Figure:: images/simple_model.* - :align: center - :figclass: center - :figwidth: 60% - - This is a map of the simple 'Utopia' system, which we often use for testing - purposes. The map shows the possible commodity flows through the system, - providing a comprehensive overview of the system. Creating the simple system - map is useful for debugging purposes in order to make sure that technologies - are linked together properly via commodity flows. - -It is also possible to create a system map showing the optimal installed capacity -and technology flows in a particular model time period. These results are associated -with a specific model run stored in the model database. To view the results, include -the scenario flag (:code:`-s`) and a specific model year (:code:`-y`). - -Note that when Graphiz runs, it creates a folder within the :code:`data_processing` -folder. The folder itself is assigned the name of the database file, with -:code:`input_graphviz` appended to the end. This descriptor changes if using Graphviz -to visualize output graphics. Within this Graphviz-generated folder are two files. The -graphics file (default: svg) is a viewable image of the network. The dot file is the -input file to Graphviz that is created programmatically. Note that the dot files provide -another means to debug the model and create an archive of visualizations for auditing -purposes. In addition, we have taken care to make these intermediate files well-formatted. - -.. parsed-literal:: - $ python make_graphviz.py -i ../data_files/temoa_utopia.sqlite -s test_run -y 1990 - -.. figure:: images/global_results.* - :align: center - :figclass: center - :figwidth: 60% - - This graph shows the optimal installed capacity and commodity flows from the - 'utopia' test system in 2010. - -The output can also be fine-tuned to show results associated with a specific -commodity or technology. For example: - -.. parsed-literal:: - $ python make_graphviz.py -i ../data_files/temoa_utopia.sqlite -s test_run -y 2010 -b E31 - -.. figure:: images/techvintage_results.* - :align: center - :figclass: center - :figwidth: 60% - - In this case, the graph shows the commodity flow in and out of - technology 'E31' in 2010, which is from the 'test_run' scenario drawn from the - 'temoa_utopia' database. - -Output Graphs -------------- - -Temoa can also be used to generate output graphs using `matplotlib `. -From the command line, navigate to the :code:`data_processing` folder and execute the following command: - -.. parsed-literal:: - $ python make_output_plots.py --help - -The command above will specify all of the flags required to created a stacked bar -or line plot. For example, consider the following command: - -.. parsed-literal:: - $ python make_output_plots.py -i ../data_files/temoa_utopia.sqlite -s test_run -p capacity -c electric --super - -Here is the result: - -.. figure:: images/output_flow_example.* - :align: center - :figclass: center - :figwidth: 60% - - This stacked bar plot represents the activity (i.e., output commodity flow) - associated with each technology in the electric sector from the 'test_run' - scenario drawn from the 'temoa_utopia' database. Because the :code:`super` - flag was specified, technologies are grouped together based on user-specified - categories in the :code:`tech_category`` column of the :code:`technologies` - table of the database. - +.. include:: visualization.rst ===================== The Math Behind Temoa ===================== - To understand this section, the reader will need at least a cursory - understanding of mathematical optimization. We omit here that introduction, - and instead refer the reader to `various`_ `available`_ `online`_ `sources`_. - Temoa is formulated as an algebraic model that requires information organized - into sets, parameters, variables, and equation - definitions. - -The heart of Temoa is a technology explicit energy system optimization model. -It is an algebraic network of linked processes -- where each process is defined -by a set of engineering characteristics (e.g. capital cost, efficiency, capacity -factor, emission rates) -- that transform raw energy sources into end-use -demands. The model objective function minimizes the present-value cost of -energy supply by optimizing installed capacity and its utilization over time. - -.. _simple_system: - -.. figure:: images/simple_system2.* - :align: center - :width: 100% - :alt: A simple energy system, with energy sources on the left and energy - sinks (end-use demands) on the right. - :figclass: align-center - :figwidth: 70% - - A common visualization of energy system models is a directed network graph, - with energy sources on the left and end-use demands on the right. The - modeler must specify the end-use demands to be met, the technologies defined - within the system (rectangles), and the inputs and outputs of each (red and green - arrows). The circles represent distinct energy carriers that connect - technologies within the energy system network. - -The most fundamental tenet of the model is the understanding of energy flow, -treating all processes as black boxes that take inputs and produce outputs. -Specifically, Temoa does not care about the inner workings of a process, only -its global input and output characteristics. In this vein, the above graphic -can be broken down into process-specific elements. For example, the coal power -plant takes as input coal and produces electricity, and is subject to various -costs (e.g. variable costs) and constraints (e.g. efficiency) along the way. - -.. figure:: images/coal_process.png - :align: center - :figclass: center - :figwidth: 60% - - -The modeler defines the processes and engineering characteristics through a -combination of sets and parameters, described in the next few sections. Temoa then -utilizes these parameters, along with the associated technology-specific decision -variables for capacity and activity, to create the objective function and -constraints that are used during the optimization process. - -.. _Sets: - - -Conventions ------------ - - * In the mathematical notation, we use CAPITALIZATION to denote a container, - like a set, indexed variable, or indexed parameter. Sets use only a single - letter, so we use the lower case to represent an item from the set. For - example, :math:`T` represents the set of all technologies and :math:`t` - represents a single item from :math:`T`. - - * Variables are named V\_VarName within the code to aid readability. However, - in the documentation where there is benefit of italics and other font - manipulations, we elide the 'V\_' prefix. - - * In all equations, we **bold** variables to distinguish them from parameters. - Take, for example, this excerpt from the Temoa default objective function: - - .. math:: - C_{variable} = \sum_{r, p, s, d, i, t, v, o \in \Theta_{VC}} \left ( - {VC}_{r, p, t, v} - \cdot R_p - \cdot \textbf{FO}_{r, p, s, d, i, t, v, o} - \right ) - - Note that :math:`C_{variable}` is not bold, as it is a temporary variable - used for clarity while constructing the objective function. It is not a - structural variable and the solver never sees it. - - * Where appropriate, we put the variable on the right side of the coefficient. - In other words, this is not a preferred form of the previous equation: - - .. math:: - - C_{variable} = \sum_{r, p, s, d, i, t, v, o \in \Theta_{VC}} \left ( - \textbf{FO}_{r, p, s, d, i, t, v, o} - \cdot {VC}_{r, p, t, v} - \cdot R_p - \right ) - - * We generally put the limiting or defining aspect of an equation on the right - hand side of the relational operator, and the aspect being limited or defined - on the left hand side. For example, equation :eq:`Capacity` defines Temoa's - mathematical understanding of a process capacity (:math:`\textbf{CAP}`) in - terms of that process' activity (:math:`\textbf{ACT}`): - - .. math:: - - \left ( - \text{CFP}_{r, t, v} - \cdot \text{C2A}_{r, t} - \cdot \text{SEG}_{s, d} - \right ) - \cdot \textbf{CAP}_{r, t, v} - = - \sum_{I, O} \textbf{FO}_{r, p, s, d,i, t, v, o} - + - \sum_{I, O} \textbf{CUR}_{r, p, s, d, i, t, v, o} - - \\ - \forall \{r, p, s, d, t, v\} \in \Theta_{\text{FO}} - - * We use the word 'slice' to refer to the tuple of season and time of day - :math:`\{s,d\}`. Note that these time slices are user-defined, and can - represent time ranging large blocks of time (e.g., winter-night) to every - hour in a given season. - - * We use the word 'process' to refer to the tuple of technology and vintage - (:math:`\{t,v\}`). For example, solar PV (technology) installed in 2030 - (vintage). - - - * Mathematical notation: - - * We use the symbol :math:`\mathbb{I}` to represent the unit interval ([0, - 1]). - - * We use the symbol :math:`\mathbb{Z}` to represent "the set of all - integers." - - * We use the symbol :math:`\mathbb{N}` to represent natural numbers (i.e., - integers greater than zero: 1, 2, 3, :math:`\ldots`). - - * We use the symbol :math:`\mathbb{R}` to denote the set of real numbers, and - :math:`\mathbb{R}^+_0` to denote non-negative real numbers. - - -Sets ----- - -.. _table_set: - -.. csv-table:: List of all Temoa sets with which a modeler might interact. The - asterisked (\*) elements are automatically derived by the model and - are not user-specifiable. - :header: "Set","Temoa Name","Data Type","Short Description" - :widths: 8, 28, 14, 50 - - ":math:`{}^*\text{C}`",":code:`commodity_all`","string","union of all commodity sets" - ":math:`\text{C}^s`",":code:`commodity_source`","string","input sources (not balanced by CommodityBalance_constraint)" - ":math:`\text{C}^d`",":code:`commodity_demand`","string","end-use demand commodities" - ":math:`\text{C}^e`",":code:`commodity_emissions`","string","emission commodities (e.g. :math:`\text{CO}_\text{2}` :math:`\text{NO}_\text{x}`)" - ":math:`\text{C}^p`",":code:`commodity_physical`","string","general energy forms (e.g. electricity, coal, uranium, oil)" - ":math:`\text{C}^a`",":code:`commodity_annual`","string","same as commodity physical but flows are only balanced over each period (:math:`\text{C}^a \subset \text{C}^p`)" - ":math:`\text{C}^w`",":code:`commodity_waste`","string","production can be greater than consumption. can be physical, annual, or neither (not balanced)" - ":math:`{}^*\text{C}^c`",":code:`commodity_carrier`","string","physical energy carriers and end-use demands (:math:`\text{C}_p \cup \text{C}_d`)" - ":math:`\text{I}`",,"string","alias of :math:`\text{C}^p`; used in documentation only to mean ""input""" - ":math:`\text{O}`",,"string","alias of :math:`\text{C}^c`; used in documentation only to mean ""output""" - ":math:`\text{P}^e`",":code:`time_existing`",":math:`\mathbb{Z}`","model periods before optimization begins" - ":math:`\text{P}^f`",":code:`time_future`",":math:`\mathbb{Z}`","model time scale of interest; the last year is not optimized" - ":math:`{}^*\text{P}^o`",":code:`time_optimize`",":math:`\mathbb{Z}`","model time periods to optimize; (:math:`\text{P}^f - \text{max}(\text{P}^f)`)" - ":math:`\text{R}`",":code:`regions`","string","distinct geographical regions" - ":math:`{}^*\text{V}`",":code:`vintage_all`",":math:`\mathbb{Z}`","possible tech vintages; (:math:`\text{P}^e \cup \text{P}^o`)" - ":math:`\text{S}`",":code:`time_season`","string","seasonal divisions (e.g. winter, summer)" - ":math:`\text{D}`",":code:`time_of_day`","string","time-of-day divisions (e.g. morning)" - ":math:`{}^*\text{T}`",":code:`tech_all`","string","all technologies to be modeled; (:math:`{T}^r \cup {T}^p`)" - ":math:`\text{T}^u`",":code:`tech_unlim_cap`","string","technologies that have no bound on capacity, and can have variable costs only (imports, taxes, etc.); (:math:`{T}^u \subset (T - T^{res})`)" - ":math:`\text{T}^a`",":code:`tech_annual`","string","technologies that produce constant annual output; (:math:`{T}^a \subset T`)" - ":math:`\text{T}^b`",":code:`tech_baseload`","string","baseload electric generators; (:math:`{T}^b \subset T`)" - ":math:`\text{T}^c`",":code:`tech_curtailment`","string","technologies with curtailable output and no upstream cost; (:math:`{T}^c \subset (T - T^{res})`)" - ":math:`\text{T}^x`",":code:`tech_exchange`","string","technologies used for interregional commodity flow; (:math:`{T}^x \subset T`). See Note 1 below on capacity and cost application for `tech_exchange`" - ":math:`\text{T}^e`",":code:`tech_existing`","string","technologies constructed in an existing (past) vintage; (:math:`{T}^e \subset T`)." - ":math:`\text{T}^f`",":code:`tech_flex`","string","technologies producing excess commodity flows; (:math:`{T}^f \subset T`)" - "",":code:`TechGroupName`","string","named groups for use in group constraints" - "",":code:`tech_group_member`","(TechGroupName, tech)","Each technology belonging to each group defined above" - ":math:`\text{T}^p`",":code:`tech_production`","string","techs producing intermediate commodities" - ":math:`\text{T}^{ur}`",":code:`tech_upramping`","string","electric generators with a ramp up hourly rate limit; (:math:`{T}^{ur} \subset T`)" - ":math:`\text{T}^{dr}`",":code:`tech_downramping`","string","electric generators with a ramp down hourly rate limit; (:math:`{T}^{dr} \subset T`)" - ":math:`\text{T}^{res}`",":code:`tech_reserve`","string","electric generators contributing to the reserve margin requirement; (:math:`{T}^res \subset T`)" - ":math:`\text{T}^{ret}`",":code:`tech_retirement`","string","technologies allowed to retire before end of life; (:math:`{T}^{ret} \subset (T - T^{u})`)" - ":math:`\text{T}^s`",":code:`tech_storage`","string","all storage technologies; (:math:`{T}^s \subset T`)" - ":math:`\text{T}^{ss}`",":code:`tech_seasonal_storage`","string","seasonal storage technologies; (:math:`{T}^{ss} \subset T^s`)" - -Note 1: Temoa sets Capacity for Exchange Technologies to be equal in both directions on the link automatically. -Costs are apportioned as follows: If both directions of the link have a cost parameter, costs are accrued to -each region region directly based on flow *to* that region. If only 1 element of the link holds a populated cost value, -then that cost divided between the 2 regions automatically based on use, where each region is "billed" according -to use as a receiver. - -Temoa uses two different set notation styles, one for code representation and -one that utilizes standard algebraic notation. For brevity, the mathematical -representation uses capital letters to denote sets, and lower case letters to -represent items within sets. For example, :math:`T` represents the set of all -technologies and :math:`t` represents an item within :math:`T`. - -The code representation is more verbose than the algebraic version, using full -words. This documentation presents them in an italicized font. The same -example of all technologies is represented in the code as :code:`tech_all`. -:ref:`Table 1 ` lists all of the Temoa sets, with both sets of notation. - -There are four basic set "groups" within Temoa: periods, sub-annual "time slices", -technologies, and energy commodities. The technology-related sets contain all the -possible energy technologies that the model may build and the commodities sets -contain all the input and output forms of energy that technologies consume and -produce. The period and time slice sets merit a slightly longer discussion. - -Temoa's conceptual model of *time* is broken up into three levels, and energy supply -and demand is balanced at each of these levels: - - * **Periods** - consecutive blocks of years, marked by the first year in the - period. For example, a two-period model might consist of :math:`\text{P}^f = - \{2010, 2015, 2025\}`, representing the two periods of years from beginning 2010 - through 2014 end, and from beginning 2015 through 2024 end. Note the that last period element - \(2025\) does not represent a new time period, but rather defines the end of the second time - period and therefore the planning horizon. - - * **Seasonal** - Each year may have multiple seasons. In a conventional time-sliced - model, the seasons may typically represent the four seasons: winter, spring summer, - and fall. However, the seasonal slices can represent any amount of time at the - sub-period scale. For example, in a database with representative days, the seasonal - slices can be used as generic containers to represent blocks of days. The type of - seasonal representation in use should be defined in the config file. - - * **Daily** - Within a season, a given day can be further subdivided into different - time segments. Less detailed databases may include larger blocks of time, such as morning, - afternoon, and night. In a database with representative days, each daily segment can - be used to represent every hour of the day. - - -There are two specifiable period sets: :code:`time_exist` (:math:`\text{P}^e`) -and :code:`time_future` (:math:`\text{P}^f`). The :code:`time_exist` set -contains periods before :code:`time_future`. Its primary purpose is to specify -the vintages for capacity that exist prior to the model optimization. -The :code:`time_future` set contains the future periods that the model will -optimize. As this set must contain only integers, Temoa interprets the elements -to be the boundaries of each period of interest. Thus, this is an ordered set -and Temoa uses its elements to automatically calculate the length of each -optimization period; modelers may exploit this to create variable period lengths -within a given input database. Temoa "names" each optimization period by the first -year, and makes them easily accessible via the :code:`time_optimize` set. This final -"period" set is not user-specifiable, but is an exact duplicate of -:code:`time_future`, less the largest element. In the above example, since -:math:`\text{P}^f = \{2010, 2015, 2025\}`, :code:`time_optimize` does not -contain 2025: :math:`\text{P}^o =\{2010, 2015\}`. - -One final note on periods: rather than optimizing each year within a period -individually, Temoa makes the simplifying assumption that each time period contains -:math:`n` copies of a single, representative year. Temoa optimizes capacity -and activity for just this characteristic year within each time period, assuming -the results for different years in the same time period are identical. The Temoa -objective function, however, accounts for the total cost across all years in all -model time periods. Figure 3.3 gives a graphical explanation of the annual -delineation. - -.. _FigureObjectiveComparison: - -.. figure:: images/ObjectiveUsageVsCostComparison.png - :align: center - :width: 100% - :alt: Energy use same each year; time-value of annual costs reduced each year - :figclass: align-center - :figwidth: 60% - - The left graph is of energy, while the right graph is of the annual costs. - The energy used in a period by a process is the same for all - years (with exception for those processes that cease their useful life - mid-period). However, even though the costs incurred will be the same, the - time-value of money changes due to the discount-rate. As the fixed costs of - a process are tied to the length of its useful life, those processes that do - not fall on a period boundary require unique time-value multipliers in the - objective function. - -As noted above, Temoa allows the modeler to subdivide each year into a set of time -slices, comprised of a season and a time of day. Unlike :code:`time_future`, there -is no restriction on what labels the modeler may assign to the :code:`time_season` -and :code:`time_of_day` set elements. - - -A Word on Index Ordering -^^^^^^^^^^^^^^^^^^^^^^^^ - -The ordering of the indices is consistent throughout the model to promote an -intuitive "left-to-right" description of each parameter, variable, and -constraint set. For example, Temoa's output commodity flow variable -:math:`FO_{r,p,s,d,i,t,v,o}` may be described as "in region (:math:`r`), -in period (:math:`p`) during season (:math:`s`) at time of day (:math:`d`), -the flow of input commodity (:math:`i`) to technology (:math:`t`) of vintage -(:math:`v`) generates an output commodity flow (:math:`o`) of -:math:`FO_{r,p,s,d,i,t,v,o}`." For any indexed parameter or variable within -Temoa, our intent is to enable a mental model of a simple left-to-right, arrow-box-arrow -mnemonic to describe the "input :math:`\rightarrow` process -:math:`\rightarrow` output" flow of energy. And while not all variables, parameters, -or constraints have 8 indices, the 8-index order mentioned here (r, p, s, d, i, t, v, o) -is the canonical ordering. If you note any case where, for example, d comes before s, -that is an oversight. In general, if there is an index ordering that does not follow -this rubric, we view that as a bug. - - -Deviations from Standard Mathematical Notation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Temoa deviates from standard mathematical notation and set understanding in two -ways. The first is that Temoa places a restriction on the *time* set elements. -Specifically, while most optimization programs treat set elements as arbitrary -labels, Temoa assumes that all elements of the :code:`time_existing` and -:code:`time_future` sets are integers. Further, these sets are assumed to be -ordered, such that the minimum element is "naught". For example, if -:math:`\text{P}^f = \{2015, 2020, 2030\}`, then :math:`P_0 = 2015`. In -other words, the capital :math:`\text{P}` with the naught subscript indicates -the first element in the :code:`time_future` set. We will explain the reason -for this notation shortly. - -The second set of deviations revolves around the use of the Theta superset -(:math:`\Theta`). The Temoa code makes heavy use of sparse sets, for both -correctness and efficient use of computational resources. For brevity, and -to avoid discussion of implementation details, we do not enumerate their -logical creation here. Instead, we rely on the readers general understanding of -the context. For example, in the sparse creation of the constraints of the -Demand constraint class (explained in :ref:`NetworkConstraints` and -:ref:`constraint-anatomy`), we state simply that the constraint is instantiated -"for all the :math:`\{p, s, d, dem\}` tuples in -:math:`\Theta_{\text{demand}}`". This means that the constraint is only defined -for the exact indices for which the modeler specified end-use demands via the -Demand parameter in the input data file. - -Summations also occur in a sparse manner. For example, let's take another look at -the :code:`Capacity` :eq:`Capacity` Constraint: - -.. math:: - - \left ( - \text{CFP}_{r, s, d, t, v} - \cdot \text{C2A}_{r, t} - \cdot \text{SEG}_{s, d} - \right ) - \cdot \textbf{CAP}_{r, t, v} - = - \sum_{I, O} \textbf{FO}_{r, p, s, d,i, t, v, o} - + - \sum_{I, O} \textbf{CUR}_{r, p, s, d, i, t, v, o} - - \\ - \forall \{p, s, d, t, v\} \in \Theta_{\text{Capacity}} - -It defines the Capacity variable for every valid combination of :math:`\{p, v\}`, -and includes the sum over all inputs and outputs of the FlowOut variable. A -naive implementation of this equation might include nonsensical items in each -summation, such as an input of vehicle miles traveled to an oil refinery or an -output of sunlight from nuclear generating capacity. However, in this context, -summing over the inputs and outputs (:math:`i` and :math:`o`) implicitly -includes only the valid combinations of :math:`\{p, s, d, i, t, v, o\}`. - - -Parameters ----------- - -.. _table_parameter: - -.. csv-table:: List of Temoa parameters with which a modeler might interact. - The asterisked (\*) parameters specified at the end of the table - are automatically derived by the model and are not user-specifiable. - :header: "Parameter","Temoa Name","Domain","Short Description" - :widths: 14, 27, 10, 49 - - ":math:`\text{CC}_{r,p,t,v}`","capacity_credit",":math:`\mathbb{I}`","Process-specific capacity credit" - ":math:`\text{CFT}_{r,s,d,t}`","capacity_factor_tech",":math:`\mathbb{I}`","Technology-specific capacity factor" - ":math:`\text{CFP}_{r,s,d,t,v}`","capacity_factor_process",":math:`\mathbb{I}`","Process-specific capacity factor" - ":math:`\text{C2A}_{r,t,v}`","CapacityToActivity",":math:`\mathbb{R}^+_0`","Converts from capacity to activity units" - ":math:`\text{CF}_{r,p,t,v}`","cost_fixed",":math:`\mathbb{R}`","Fixed operations \& maintenance cost" - ":math:`\text{CI}_{r,t,v}`","cost_invest",":math:`\mathbb{R}`","Tech-specific investment cost" - ":math:`\text{CV}_{r,p,t,v}`","cost_variable",":math:`\mathbb{R}`","Variable operations \& maintenance cost" - ":math:`\text{CON}_{r,i,t,v}`","construction_input",":math:`\mathbb{R}`","Commodities consumed by creation of process capacity" - ":math:`\text{DEM}_{r,p,c}`","Demand",":math:`\mathbb{R}^+_0`","End-use demands, by period" - ":math:`\text{DDD}_{p,s,d}`","DemandDefaultDistribution",":math:`\mathbb{I}`","Default demand distribution (currently not supported)" - ":math:`\text{DSD}_{r,p,s,d,c}`","demand_specific_distribution",":math:`\mathbb{I}`","Demand-specific distribution" - ":math:`\text{EFF}_{r,i,t,v,o}`","efficiency",":math:`\mathbb{R}^+_0`","Tech- and commodity-specific efficiency" - ":math:`\text{EAC}_{r,i,t,v,o,e}`","emission_activity",":math:`\mathbb{R}`","Tech-specific emissions rate" - ":math:`\text{EE}_{r,t,v,e}`","emission_embodied",":math:`\mathbb{R}`","Emissions associated with the creation of capacity" - ":math:`\text{EEOL}_{r,t,v,e}`","emission_end_of_life",":math:`\mathbb{R}`","Emissions associated with the retirement/end of life of capacity" - ":math:`\text{EOLO}_{r,t,v,o}`","end_of_life_output",":math:`\mathbb{R}`","Commodities produced by retirement/end of life of capacity" - ":math:`\text{ECAP}_{r,t,v}`","existing_capacity",":math:`\mathbb{R}^+_0`","Pre-existing capacity" - ":math:`\text{GDR}`","global_discount_rate",":math:`\mathbb{R}`","Global rate used to calculate present cost" - ":math:`\text{LTP}_{r,t,v}`","lifetime_process",":math:`\mathbb{N}`","Tech- and vintage-specific lifetime (default=lifetime_tech)" - ":math:`\text{LTT}_{r,t}`","lifetime_tech",":math:`\mathbb{N}`","Tech-specific lifetime (default=40 years)" - ":math:`\text{LSC}_{r,p,t,v}`","lifetime_survival_curve",":math:`\mathbb{R}^+_0`","Surviving fraction of original capacity" - ":math:`\text{LIT}_{r,t,e,t}`","linked_techs","text","Dummy techs used to convert CO2 emissions to physical commodity" - ":math:`\text{LLP}_{r,t,v}`","loan_lifetime_process",":math:`\mathbb{N}`","Process-specific loan term (default=lifetime_process)" - ":math:`\text{LR}_{r,t,v}`","loan_rate",":math:`\mathbb{R}`","Process-specific interest rate on investment cost" - ":math:`\text{LE}_{r,p,e}`","limit_emission",":math:`\mathbb{R}^+_0`","Limit emissions by region and period" - ":math:`\text{LA}_{r,p,t}`","limit_activity",":math:`\mathbb{R}^+_0`","Limit tech-specific activity by region and period" - ":math:`\text{LC}_{r,p,t}`","limit_capacity",":math:`\mathbb{R}^+_0`","Limit tech-specific capacity by period" - ":math:`\text{LR}_{r,t}`","limit_resource",":math:`\mathbb{R}^+_0`","Limit resource production by tech across time periods" - ":math:`\text{LSF}_{r,p,s,d,t,v}`","LimitStorageLevelFraction",":math:`\mathbb{R}^+_0`","Limit storage level in any time slice" - ":math:`\text{MDY}`","myopic_discounting_year",":math:`\mathbb{N}`","Objective function NPV year when running myopically" - ":math:`\text{PRM}_{r}`","planning_reserve_margin",":math:`\mathbb{I}`","Margin used to ensure sufficient generating capacity" - ":math:`\text{RDH}_{r,t}`","ramp_down_hourly",":math:`\mathbb{R}`","Hourly rate at which generation techs can ramp output down" - ":math:`\text{RUH}_{r,t}`","ramp_up_hourly",":math:`\mathbb{R}`","Hourly rate at which generation techs can ramp output up" - ":math:`\text{SD}_{r,t}`","storage_duration",":math:`\mathbb{N}`","Storage duration per technology, specified in hours" - ":math:`\text{SEG}_{s,d}`","segment_fraction",":math:`\mathbb{I}`","Fraction of year represented by each (s, d) tuple" - ":math:`\text{TIS}_{r,i,t}`","TechInputSplit",":math:`\mathbb{I}`","Technology input fuel ratio at time slice level" - ":math:`\text{TISA}_{r,i,t}`","TechInputSplitAnnual",":math:`\mathbb{I}`","Average annual technology input fuel ratio" - ":math:`\text{TOS}_{r,t,o}`","TechOutputSplit",":math:`\mathbb{I}`","Technology output fuel ratio at time slice level" - ":math:`\text{TISA}_{r,i,t}`","TechOutputSplitAnnual",":math:`\mathbb{I}`","Average annual technology output fuel ratio" - ":math:`{}^*\text{LA}_{t,v}`","loan_annualize",":math:`\mathbb{R}^+_0`","Loan amortization by tech and vintage; based on :math:`DR_t`" - ":math:`{}^*\text{MPL}_{p,t,v}`","ModelProcessLife",":math:`\mathbb{N}`","Smaller of remaining model horizon or process tech life" - ":math:`{}^*\text{PLF}_{r,p,t,v}`","process_life_frac",":math:`\mathbb{I}`","Fraction of available process capacity by region and period " - ":math:`{}^*\text{LEN}_p`","PeriodLength",":math:`\mathbb{N}`","Number of years in period :math:`p`" - - -.. _influential_efficiency: - -efficiency -^^^^^^^^^^ - -:math:`{EFF}_{r \in R, i \in C_p, t \in T, v \in V, o \in C_c}` - -We present the efficiency (:math:`EFF`) parameter first as it is one of the most -critical model parameters. Beyond defining the conversion efficiency of each -process, Temoa also utilizes the indices to understand the valid input -:math:`\rightarrow` process :math:`\rightarrow` output paths for energy. For -instance, if a modeler does not specify an efficiency for a 2020 vintage coal -power plant, then Temoa will recognize any mention of a 2020 vintage coal power -plant elsewhere as an error. Generally, if a process is not specified in the -efficiency table,\ [#efficiency_table]_ Temoa assumes it is not a valid process -and will provide the user a warning with pointed debugging information. - - -.. _capacity_factor_tech: - -capacity_credit -^^^^^^^^^^^^^^ - -:math:`{CC}_{r \in R, p \in P, t \in T, v \in V}` - -The capacity credit represents the fraction of total installed capacity of -a process that can be relied upon during the time slice in which peak -electricity demand occurs. This parameter is used in the :math:`ReserveMargin` -constraint. - -capacity_factor_tech -^^^^^^^^^^^^^^^^^^ - -:math:`{CFT}_{r \in R, s \in S, d \in D, t \in T}` - -Temoa indexes the :code:`capacity_factor_tech` parameter by season, time-of-day, -and technology. - -capacity_factor_process -^^^^^^^^^^^^^^^^^^^^^ - -:math:`{CFP}_{r \in R, s \in S, d \in D, t \in T, v \in V}` - -In addition to :ref:`capacity_factor_tech`, there may be cases where different -vintages of the same technology have different capacity factors. For example, -newer vintages of wind turbines may have higher capacity factors. So, -:code:`capacity_factor_process` allows users to specify the capacity factor by -season, time-of-day, technology, and vintage. - - -CapacityToActivity -^^^^^^^^^^^^^^^^^^ - -:math:`{C2A}_{r \in R, t \in T}` - -Capacity and Activity are inherently two different units of measure. Capacity -represents the maximum flow of energy per time (:math:`\frac{energy}{time}`), -while Activity is a measure of total energy actually produced. However, there are -times when one needs to compare the two, and this parameter makes those -comparisons more natural. For example, a capacity of 1 GW for one year works -out to an activity of - -.. math:: - - {1 GW} \cdot {8,760 \tfrac{hr}{yr}} \cdot {3,600 \tfrac{sec}{hr}} \cdot - {10^{-6} \tfrac{P}{G}} = {31.536 \tfrac{PJ}{yr}} - -.. centered:: - or - -.. math:: - - {1 GW} \cdot {8,760 \tfrac{hr}{yr}} \cdot {10^{-3} \tfrac{T}{G}} = {8.75 TWh} - -When comparing one capacity to another, the comparison is easy, unit wise. -However, when one *needs* to compare capacity and activity, how does one -reconcile the units? One way to think about the utility of this parameter is in -the context of the question: "How much activity would this capacity create, if -used 100% of the time?" - - -cost_fixed -^^^^^^^^^ - -:math:`{CF}_{r \in R, p \in P, t \in T, v \in V}` - -The :code:`cost_fixed` parameter specifies the fixed cost associated with any -process. Fixed costs are those that must be paid, regardless of how much the -process is utilized. For instance, if the model decides to build a nuclear -power plant, even if it decides not utilize the plant, the model must pay the -fixed costs. These costs are in addition to the capital cost, so once the -capital is paid off, these costs are still incurred every year the process -exists. - -Temoa's default objective function assumes the modeler has specified this -parameter in units of currency per unit capacity (:math:`\tfrac{Dollars}{Unit -Cap}`). - - -cost_invest -^^^^^^^^^^ - -:math:`{CI}_{r \in R, t \in T, v \in P}` - -The :code:`cost_invest` parameter specifies the process-specific investment cost. -Unlike the :code:`cost_fixed` and :code:`cost_variable` parameters, -:code:`cost_invest` only applies to vintages of technologies within the model -optimization horizon (:math:`\text{P}^o`). Like :code:`cost_fixed`, -:code:`cost_invest` is specified in units of cost per unit of capacity and is -only used in the default objective function (:math:`\tfrac{Dollars}{Unit Cap}`). - - -cost_variable -^^^^^^^^^^^^ - -:math:`{CV}_{r \in R, p \in P,t \in T,v \in V}` - -The :code:`cost_variable` parameter represents the cost of a process-specific unit -of activity. Thus the incurred variable costs are proportional to the activity -of the process. - - -construction_input -^^^^^^^^^^^^^^^^^ - -:math:`{CON}_{r \in R, i \in C^p,t \in T \setminus T^u,v \in V}` - -The :code:`construction_input` parameter allows the modeller to attach commodity -input flows to the production of new capacity, in units of activity per unit -capacity. Assumes that capacity is produced evenly over years in its vintage -period. - - -.. _Demand: - -Demand -^^^^^^ - -:math:`{DEM}_{r \in r, p \in P, c \in C^d}` - -The :code:`Demand` parameter allows the modeler to define the total end-use -demand levels for all periods. In combination with the :code:`efficiency` -parameter, this parameter is the most important because without it, the rest of -model has no incentive to build anything. This parameter specifies the end-use -demands that appear at the far right edge of the system diagram. - -To specify the distribution of demand, look to the -:code:`DemandDefaultDistribution` (DDD) and :code:`demand_specific_distribution` -(DSD) parameters. - -As a historical note, this parameter was at one time also indexed by season and -time of day, allowing modelers to specify exact demands for every time slice. -However, while extremely flexible, this proved too tedious to maintain for any -data set of appreciable size. Thus, we implemented the DDD and DSD parameters. - - -.. _DDD: - -DemandDefaultDistribution -^^^^^^^^^^^^^^^^^^^^^^^^^ - -:math:`{DDD}_{s \in S, d \in D}` - -**Note**: The Demand Specific Distribution is currently not supported in -the project. Modelers should use the DSD or rely on a "flat" distribution default -from the time_segment_fraction. - -By default, Temoa assumes that end-use demands (:ref:`Demand`) are evenly -distributed throughout a year. In other words, the Demand will be apportioned -by the :code:`segment_fraction` parameter via: - -.. math:: - - \text{EndUseDemand}_{s, d, c} = {segment_fraction}_{s, d} \cdot {Demand}_{p, c} - -Temoa enables this default action by automatically setting DDD equivalent to -:code:`segment_fraction` for all seasons and times of day. If a modeler would like a -different default demand distribution, the indices and values of the DDD -parameter must be specified. Like the :ref:`segment_fraction` parameter, the sum of -DDD must be 1. - - -demand_specific_distribution -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:math:`{DSD}_{r \in R, s \in S, d \in D, c \in C^d}` - -If there is an end-use demand that varies over the course of a day or across -seasons -- for example, heating or cooling in the summer or winter -- the -modeler may specify the fraction of annual demand occurring in each time slice. -Like :ref:`segment_fraction` and :ref:`DDD`, the sum of DSD for each :math:`c` must be 1. -If the modeler does not define DSD for a season, time of day, and demand -commodity, Temoa automatically populates this parameter according to DDD. -It is this parameter that is actually multiplied by the :code:`Demand` parameter -in the Demand constraint. - - -emission_activity -^^^^^^^^^^^^^^^^ - -:math:`{EAC}_{e \in C_e,\{r,i,t,v,o\} \in \Theta_{\text{efficiency}}}` - -Temoa currently has two methods for enabling a process to produce an output: the -:code:`efficiency` parameter, and the :code:`emission_activity` parameter. Where -the :code:`efficiency` parameter defines the amount of output energy a process -produces per unit of input, the :code:`emission_activity` parameter allows for -secondary outputs. As the name suggests, this parameter was originally intended -to account for emissions per unit activity, but it more accurately describes -*parallel* activity. It is restricted to emissions accounting (by the -:math:`e \in C^e` set restriction). - - -emission_embodied -^^^^^^^^^^^^^^^^ - -:math:`{EE}_{r \in R,t \in T \setminus T^u, v \in V,e \in C_e}` - -Like the emission_activity parameter, but attaches emission outputs to the creation -of capacity instead of activity flows. Assumes that capacity is produced evenly -over each year in the deployment vintage. - - -emission_end_of_life -^^^^^^^^^^^^^^^^^ - -:math:`{EEOL}_{r \in R,t \in T \setminus T^u, v \in V,e \in C_e}` - -Like emission_embodied, but attaches emissions to the retirement/end of life of -capacity rather than production of capacity. Assumes that retirement or end of -life occur evenly over years in that period. - - -end_of_life_output -^^^^^^^^^^^^^^^ - -:math:`{EOLO}_{r \in R,t \in T \setminus T^u, v \in V,o \in C_p}` - -Like construction_input, but attaches flows to the retirement/end of life of -capacity rather than production of capacity. Assumes that retirement or end of -life occur evenly over years in that period. - - -.. limit_emission -.. ^^^^^^^^^^^^^ - -.. :math:`{LE}_{r \in R, p \in P, e \in C^e}` - -.. The :code:`EmissionLimit` parameter ensures that Temoa finds a solution that -.. fits within the modeler-specified limit of emission :math:`e` in time period -.. :math:`p`. - - -existing_capacity -^^^^^^^^^^^^^^^^ - -:math:`{ECAP}_{r \in R, t \in T, v \in \text{P}^e}` - -The :code:`existing_capacity` parameter defines the capacity installed prior to the -beginning of :code:`time_optimize`. Note that processes with existing capacity -require all of the engineering-economic characteristics of a standard process, -with the exception of an investment cost. - -RetiredCapacity -^^^^^^^^^^^^^^^^ - -:math:`{ECAP}_{r \in R, t \in T, v \in \text{P}^e}` - -The :code:`existing_capacity` parameter defines the capacity installed prior to the -beginning of :code:`time_optimize`. Note that processes with existing capacity -require all of the engineering-economic characteristics of a standard process, -with the exception of an investment cost. - -.. _GDR: - -global_discount_rate -^^^^^^^^^^^^^^^^^^ - -:math:`{GDR}` - -The :code:`GDR` parameter represents the global discount rate used to convert -cash flows in future model time periods into a present value. The future value -(FV) of a sum of currency is related to the net present value (NPV) via the -formula: - -.. math:: - - \text{FV} = \text{NPV} \cdot {(1 + GDR)^n} - -where :math:`n` is in years. This parameter is used to calculate all discounted -costs, which are the basis of the objective function. Costs are discounted to the -first future time period in the model by default. If running a Myopic run, the -discount base year can be set in the MetaData table. This is the :code:`MyopicBaseYear`. - -The output in the :code:`output_cost` table shows both discounted and non-discounted (raw) -values for all model costs. Of note, all loan costs are displayed as an annuity cost in -the vintage year, not as a string of payments. - -The Global Discount Rate is entered in the MetaDataReal table in the database. - -GrowthRateMax -^^^^^^^^^^^^^ - -:math:`{GRM}_{r \in R, t \in T}` - -The :code:`GRM` parameter defines the maximum annual rate at which the capacity of -a given technology can grow. Note that the growth rate is not defined by vintage, -but rather across all vintages of a given technology. - - -GrowthRateSeed -^^^^^^^^^^^^^^ - -:math:`{GRS}_{r \in R, t \in T}` - -The :code:`GRS` parameter defines the maximum capacity of a given technology when -first installed in a given time period. The growth rate is applied to this initial -capacity seed in subsequent time periods. - - -loan_lifetime_process -^^^^^^^^^^^^^^^^^^^ - -:math:`{LLP}_{r \in R, t \in T, v \in P}` - -**Note**: :code:`LifetimeLoanProcess` is currently not supported in the database. -Modelers should use the :code:`loan_lifetime_tech` below. - -Temoa gives the modeler the ability to separate the loan lifetime from the -useful life of a process. This parameter specifies the loan term associated -with capital investment in a process, in years. If not specified, the model -assigns the technology lifetime to the loan period in :code:`temoa_initialize.py`. - - -loan_lifetime_tech -^^^^^^^^^^^^^^^^ - -:math:`{LLT}_{r \in R, t \in T}` - -Same as the :code:`loan_lifetime_process` but without the vintage index. If all -vintages of a given technology are assumed to have the same loan term, then -:code:`loan_lifetime_tech` can be defined instead of :code:`loan_lifetime_process`. - - -lifetime_process -^^^^^^^^^^^^^^^ - -:math:`{LTP}_{r \in R, t \in T, v \in P}` - -This parameter specifies the total useful life of a given process in years. - - -lifetime_tech -^^^^^^^^^^^^ - -:math:`{LTT}_{r \in R, t \in T}` - -Similar to lifetime_process, this parameter specifies the total useful life of a -given technology in years. If all vintages of a given technology have the same -lifetime, then :code:`LifeTimeTech` can be used instead of :code:`LifeTimeProcess`. - - -linked_techs -^^^^^^^^^^^ - -:math:`{LIT}_{r \in R, t \in T, e \in C^e, t \in T}` - -In power-to-gas pathways, :math:`CO2` is an input to some processes, including -synthetic natural gas production and liquid fuel production via Fischer-Tropsch. -Within the model, :math:`CO2` must be converted from an emissions commodity to a -physical commodity that can be included in the :code:`efficiency` table. The -:code:`linked_techs` parameter specifies the dummy technology used to convert an -emissions commodity to a physical commodity. Note that the first :code:`t` -represents the primary upstream technology linked to the dummy linked technology, -which is represented by the second :code:`t` index. - - -loan_rate -^^^^^^^^ - -:math:`{LR}_{r \in r, t \in T, v \in V}` - -The interest rate used for loans supporting investment costs. The default -loan rate is accessible in the MetaDataReals table in the database. - - -.. _ParamMaxCapacity: - - -MaxActivity -^^^^^^^^^^^ - -:math:`{MAA}_{r \in R, p \in P, t \in T}` - -The :code:`MaxActivity` parameter is used to constrain the total activity (i.e., -energy production) from a given technology in each model time period. Note that the -total activity is constrained across all vintages of a technology. This parameter -is used in the :code:`MaxActivity_constraint`. - - -MaxCapacity -^^^^^^^^^^^ - -:math:`{MAC}_{r \in R, p \in P, t \in T}` - -The :code:`MaxCapacity` parameter represents an upper bound on the total installed -capacity of a given technology in each model time period. Note that the total -capacity is constrained across all vintages of a technology. This parameter is -used in the :code:`MaxCapacity_constraint`. - - -MaxCapacitySum -^^^^^^^^^^^^^^ - -:math:`{MCS}_{t \in T}` - -Similar to the :code:`MaxCapacity` parameter, but represents an upper bound on -the total installed capacity across all model time periods. In addition, -this parameter specifies the upper bound on a group of technologies specified -in the :code:`tech_capacity_max` subset. This parameter is used in the -:code:`MaxCapacitySet_constraint`. - - -MaxResource -^^^^^^^^^^^ - -:math:`{MAR}_{r \in R, t \in T}` - -**Note**: The MaxResource parameter/constraint is currently not supported in the model. - -The :code:`MaxResource` parameter represents an upper bound on the cumulative -amount of commodity that can be produced by region and technology over the model time -horizon. This parameter is used in :code:`MaxResource_constraint`. Note that -this parameter differs from :code:`ResourceBound`, which is also indexed by -model time period. - - -MinActivity -^^^^^^^^^^^ - -:math:`{MIA}_{r \in R, p \in P, t \in T}` - -The :code:`MinActivity` parameter represents a lower bound on the total activity (i.e., -energy production) of a given technology in each model time period. Note that the -total activity is constrained across all vintages of a technology. This parameter -is used in the :code:`MinActivity_constraint`. - - -MinCapacity -^^^^^^^^^^^ - -:math:`{MIC}_{r \in R, p \in P,t \in T}` - -The :code:`MinCapacity` parameter represents a lower bound on the total installed -capacity of a given technology in each model time period. Note that the total -capacity is constrained across all vintages of a technology. This parameter is -used in the :code:`MinCapacity_constraint`. - - -MinCapacitySum -^^^^^^^^^^^^^^ - -:math:`{MCS}_{t \in T}` - -The :code:`MinCapacitySum` parameter represents the minimum cumulative -capacity associated with technologies belonging to :code:`tech_group`. -This parameter is used in the :code:`MinActivityGroup_constraint`. - - -MinGenGroupTarget -^^^^^^^^^^^^^^^^^ - -:math:`{MGT}_{r \in R}` - -The :code:`MinGenGroupTarget` parameter is similar to :code:`MinActivity`, but -represents a minimum activity limit for a user-defined technology group -(:code:`tech_groups`) rather than a single technology. This parameter is used -in the :code:`MinActivityGroup_constraint`. - - -MinGenGroupWeight -^^^^^^^^^^^^^^^^^ - -:math:`{MGW}_{r \in R, t \in T}` - -The :code:`MinGenGroupWeight` parameter represents a weight that is applied -to each technology within each :code:`tech_group`, which determines the -technology-specific activity shares that can count towards meeting the -:code:`MinActivityGroup_constraint`. - - -MyopicBaseYear -^^^^^^^^^^^^^^ - -:math:`MBY` - -Temoa is typically run in "perfect foresight" mode, where all decision variables -in all time periods are solved simultaneously. However, it is also possible to -solve the model myopically, whereby the model solves a subset of time periods -in sequence. The :code:`MyopicBaseYear` parameter specifies the base year to which -all future costs are discounted. This parameter is located in the :code:`MetaData` -table in the database. - - -planning_reserve_margin -^^^^^^^^^^^^^^^^^^^^^ - -:math:`{PRM}_{r \in R}` - -The :code:`planning_reserve_margin` parameter specifies that capacity reserve margin -in the electric sector by region. The capacity reserve margin represents the -installed generating capacity - expressed as a share of peak load - that must be -available to meet contingencies. Note that since electricity demand is often -endogeous in Temoa databases, we calculate electricity production by time slice -to estimate the peak electricity demand. This parameter is used in -:code:`ReserveMargin_constraint`. - - -RampDown -^^^^^^^^ - -:math:`{RMD}_{r \in R, t \in T}` - -To account for the limited ramping capability of some thermal generators, a -ramp down rate can be specified via the :code:`RampDown` parameter. The specified -value represents the fraction of installed capacity that can be ramped down when moving -from one time slice to the next. There is an equivalent :code:`RampUp` parameter, to -specify ramping limits in the upward direction. This parameter is used in the -:code:`RampDownDay_constraint` and `RampDownSeason_constraint`. The former constrains -the downward ramp rate between time-of-day slices, and the latter constrains the downward -ramp rate between the last time-of-day slice in a given season and the first time-of-day -slice in the next season. - - -RampUp -^^^^^^ - -:math:`{RMU}_{r \in R, t \in T}` - -To account for the limited ramping capability of some thermal generators, a -ramp up rate can be specified via the :code:`RampUp` parameter. The specified -value represents the fraction of installed capacity that can be ramped up when moving -from one time slice to the next. There is an equivalent :code:`RampDown` parameter, to -specify ramping limits in the downward direction. This parameter is used in the -:code:`RampUpDay_constraint` and `RampUpSeason_constraint`. The former constrains -the upward ramp rate between time-of-day slices, and the latter constrains the upward -ramp rate between the last time-of-day slice in a given season and the first time-of-day -slice in the next season. - - -ResourceBound -^^^^^^^^^^^^^ - -:math:`{RSC}_{r \in R, p \in P, c \in C_p}` - -This parameter allows the modeler to specify commodity production limits per period. -Note that a constraint in one period does not relate to any other periods. For -instance, if the modeler specifies a limit in period 1 and does not specify a -limit in period 2, then the model may use as much of that resource as it would -like in period 2. This parameter is used in :code:`ResourceExtraction_constraint`. -Note that the :code:`MaxResource` parameter is similar, but constrains total -cumulative resource consumption across all model time periods. - - -.. _segment_fraction: - -segment_fraction -^^^^^^^ - -:math:`{SEG}_{s \in S,d \in D}` - -The :code:`segment_fraction` parameter specifies the fraction of the year represented by -each combination of season and time of day. The sum of all combinations within -:code:`segment_fraction` must be 1, representing 100% of a year. - - -storage_duration -^^^^^^^^^^^^^^^ - -:math:`{SD}_{r \in R, t \in T^{S}}` - -The :code:`storage_duration` parameter represents the number of hours over which -storage can discharge if it starts at full charge and produces maximum output -until empty. The parameter value defaults to 4 hours if not specified by the user. - - -StorageInit -^^^^^^^^^^^ - -:math:`{SI}_{r \in R, t \in T^{S}, v \in P}` - -The :code:`StorageInit` parameter determines the initial charge level associated -with each storage technology. The value should be expressed as a fraction between -0 and 1. - -Note 1: that this is an optional parameter and should only be used if the -user wishes to set the initial charge rather than allowing the model to optimize it. - -Note 2: This initialization is currently *not supported*. Values in the StorageInit -table will be ignored and a log warning will be generated. - - -TechInputSplit -^^^^^^^^^^^^^^ - -:math:`{TIS}_{r \in R, p \in P, i \in C_p, t \in T}` - -Some technologies have a single output but have multiple input fuels. The -:code:`TechInputSplit` parameter fixes the shares of commodity input to a -specific technology in a given period. Note that this fixed share is maintained -across all model time slices. This parameter is used in -:code:`TechInputSplit_constraint`. - - -TechInputSplitAverage -^^^^^^^^^^^^^^^^^^^^^ - -:math:`{TISA}_{r \in R, p \in P, i \in C_p, t \in T}` - -The :code:`TechInputSplitAverage` is similar to :code:`TechInputSplit`, as -they both fix input commodity shares to technologies with multiple inputs. -However, :code:`TechInputSplitAverage` only fixes the average shares at the -annual level, allowing the shares at the time slice level to vary. This -parameter is used in :code:`TechInputSplitAverage_constraint`. - - -TechOutputSplit -^^^^^^^^^^^^^^^ - -:math:`{TOS}_{t \in T, o \in C_c}` - -Some technologies have a single input fuel but have multiple outputs. The -:code:`TechOutputSplit` parameter fixes the shares of commodity input to a -specific technology in a given period. Note that this fixed share is maintained -across all model time slices. This parameter is used in -:code:`TechOutputSplit_constraint`. - - -\*loan_annualize -^^^^^^^^^^^^^^^ - -:math:`{LA}_{r \in R, t \in T, v \in P}` - -This is a model-calculated parameter based on the process-specific loan length -(its indices are the same as the :code:`LifetimeLoan` parameter), and -process-specific discount rate (the :code:`DiscountRate` parameter). It is -calculated via the formula: - -.. math:: - - LA_{t,v} = \frac{DR_{r,t,v}}{1 - (1 + DR_{r,t,v})^{{}^- LLN_{r,t,v}}} - - \forall \{t, v\} \in \Theta_\text{cost_invest} - - -ModelProcessLife -^^^^^^^^^^^^^^^^ - -:math:`{MPL}_{r \in R, p \in P, t \in T, v \in P}` - -The :code:`ModelProcessLife` parameter is internally-derived by the model calcuated in -:code:`ParamModelProcessLife_rule` and which makes use of the :code:`lifetime_process` -parameter. For a given technology vintage in a given model time period, it returns the -lesser of the period length and the remaining process lifetime. This parameter is used -to sum the annual :code:`fixed_costs` and :code:`variable_costs` across all years within -a given time period. - - -\*PeriodLength -^^^^^^^^^^^^^^ - -:math:`{LEN}_{p \in P}` - -Given that the modeler may specify arbitrary time period boundaries, this -parameter specifies the number of years contained in each period. The final year -is the largest element in :code:`time_future` which is specifically not included -in the list of periods in :code:`time_optimize` (:math:`\text{P}^o`). The length -calculation for each period then exploits the fact that the ``time`` sets are -ordered: - -.. math:: - - \text{LET boundaries} & = \text{sorted}(\text{P}^f) \\ - \text{LET I(p)} & = \text{index of p in boundaries} \\ - & \therefore \\ - {LEN}_p & = \text{boundaries}[ I(p) + 1 ] - p - - \forall p \in P - -The first line creates a sorted array of the period boundaries, called -*boundaries*. The second line defines a function `I` that finds the index of -period :math:`p` in boundaries. The third line then defines the length of period -:math:`p` to be the number of years between period :math:`p` and the next -period. For example, if :math:`\text{P}^f = \{2015, 2020, 2030, 2045\}`, -then *boundaries* would be :code:`[2015, 2020, 2030, 2045]`. For 2020, I(2020) -would return 2. Similarly, boundaries[ 3 ] = 2030. Then, - -.. math:: - {LEN}_{2020} & = \text{boundaries}[I(2020) + 1] - (2020) \\ - & = \text{boundaries} [2 + 1] - 2020 \\ - & = \text{boundaries} [3] - 2020 \\ - & = 2030 - 2020 \\ - & = 10 - -Note that LEN is only defined for elements in :math:`\text{P}^o`, and is -specifically not defined for the final element in :math:`\text{P}^f`. - - -\*process_life_frac -^^^^^^^^^^^^^^^^^ - -:math:`{PLF}_{r \in R, p \in P,t \in T,v \in P}` - -The modeler may specify a useful lifetime of a process such that the process -will be decommissioned part way through a period. Rather than attempt to -delineate each year within that final period, Temoa averages the total output -of the process over the entire period but limits the available capacity and -output of the decommissioning process by the ratio of how long through the -period the process is active. This parameter is that ratio, formally defined -as: - -.. math:: - - PLF_{p,t,v} = \frac{v + LTP_{t,v} - p}{LEN_p} - - \\ - \forall \{p,t,v\} & \in \Theta_\text{Activity by PTV} | \\ - v + LTP_{t,v} & \notin P, \\ - v + LTP_{t,v} & \le max(F), \\ - p & = max(P | p < v + LTP_{t,v}) - -Note that this parameter is defined over the same indices as -:code:`cost_variable` -- the active periods for each process :math:`\{p, t, -v\}`. As an example, if a model has :math:`P = \{2010, 2012, -2020, 2030\}`, and a process :math:`\{t, v\} = \{car, 2010\}` has a useful -lifetime of 5 years, then this parameter would include only the first two -activity indices for the process. Namely, :math:`p \in \{2010, 2012\}` as -:math:`\{p, t, v\} \in \{\{2010, car, 2010\}, \{2012, car, -2010\}\}`. The values would be :math:`{TLF}_{2010, car, 2010} = 1`, and -:math:`{TLF}_{2012, car, 2010} = \frac{3}{8}`. - - -Variables ---------- - -.. _table_variable: -.. csv-table:: Temoa's Main Variables - :header: "Variable","Temoa Name","Domain","Short Description" - :widths: 18, 22, 10, 50 - - ":math:`FO_{r,p,s,d,i,t,v,o}`","v_flow_out",":math:`\mathbb{R}^+_0`","Commodity flow by time slice out of a tech based on a given input" - ":math:`FOA_{r,p,s,d,i,t,v,o}`","v_flow_out_annual",":math:`\mathbb{R}^+_0`","Annual commodity flow out of a tech based on a given input" - ":math:`FIS_{r,p,s,d,i,t,v,o}`","v_flow_in",":math:`\mathbb{R}^+_0`","Commodity flow into a storage tech to produce a given output" - ":math:`FLX_{r,p,s,d,i,t,v,o}`","v_flex",":math:`\mathbb{R}^+_0`","The portion of commodity production exceeding demand" - ":math:`FLXA_{r,p,i,t,v,o}`","v_flex_annual",":math:`\mathbb{R}^+_0`","The portion of commodity production from constant production techs exceeding demand" - ":math:`CUR_{r,p,s,d,i,t,v,o}`","v_curtailment",":math:`\mathbb{R}^+_0`","Commodity flow out of a tech that is curtailed" - ":math:`CAP_{r,t,v}`","v_capacity",":math:`\mathbb{R}^+_0`","Required tech capacity to support associated activity" - ":math:`CAPAVL_{r,p,t}`","v_capacity_available_by_period_and_tech",":math:`\mathbb{R}^+_0`","Derived variable representing the capacity of technology :math:`t` available in period :math:`p`" - ":math:`SI_{r,t,v}`","v_storage_init",":math:`\mathbb{R}^+_0`","Initial charge level associated with storage techs" - ":math:`SL_{r,p,s,d,t,v}`","v_storage_level",":math:`\mathbb{R}^+_0`","Charge level each time slice associated with storage techs" - ":math:`SSL_{r,p,s,t,v}`","v_seasonal_storage_level",":math:`\mathbb{R}^+_0`","Base charge level of sequential seasons for seasonal storage" - ":math:`RCAP_{r,p,t,v}`","v_retired_capacity",":math:`\mathbb{R}^+_0`","Capacity retired before end of life" - ":math:`ART_{r,p,t,v}`","v_annual_retirement",":math:`\mathbb{R}^+_0`","Annualised capacity retiring or reaching end of life" - ":math:`NCAP_{r,t,v}`","v_new_capacity",":math:`\mathbb{R}^+_0`","New deployed capacity" - -v_flow_out -^^^^^^^^^ - -:math:`FO_{r,p,s,d,i,t,v,o}` - -The most fundamental variable in the Temoa formulation is the -:code:`v_flow_out` variable. It describes the commodity flow out of a -process in a given time slice. To balance input and output flows in the -:code:`CommodityBalance_constraint`, the commodity flow into a given -process can be calculated as -:math:`\sum_{T, V, O} \textbf{FO}_{p, s, d, c, t, v, o} -/EFF_{c,t,v,o}`. - -v_flow_out_annual -^^^^^^^^^^^^^^^ - -:math:`FOA_{r,p,i,t,v,o}` - -Similar to :code:`v_flow_out`, but used for technologies that are members -of the :code:`tech_annual` set, whose output does not vary across seasons -and times-of-day. Eliminating the :code:`s,d` indices for these technologies -improves computational performance. - - -v_flex -^^^^^^ - -:math:`FLX_{r,p,s,d,i,t,v,o}` - -In some cases, the overproduction of a commodity may be required, such -that supply exceeds the endogenous demand. Refineries represent a -common example, where the share of different refined products are governed -by TechOutputSplit, but total production is driven by a particular commodity. -For example, gasoline production may be artificially constrained in order to -ensure the appropriate balance for lower demand fuels such as propane or -kerosene. Instead, we allow overproduction, i.e., production exceeding -endogenous demand, for commodities produced by technologies belonging to -the :code:`tech_flex` set. In the example above, adding the refinery to -the :code:`tech_flex` set allows for the overproduction of propane and -kerosene, allowing the model to fulfill the endogenous demand -for gasoline. This flexible technology designation activates a slack -variable (:math:`\textbf{FLX}_{r, p, s, d, i, t, v, c}`)representing -the excess production in the :code:`CommodityBalanceAnnual_constraint`. - - -v_flex_annual -^^^^^^^^^^^^ - -:math:`FLXA_{r,p,i,t,v,o}` - -Similar to :code:`v_flex`, but used for technologies that are members -of the :code:`tech_flex` set, whose output does not vary across seasons -and times-of-day. Eliminating the :code:`s,d` indices for these technologies -improves computational performance. - - -v_curtailment -^^^^^^^^^^^^^ - -:math:`CUR_{r,p,s,d,i,t,v,o}` - -The :code:`v_curtailment` variable is an accounting tool to help calculate -the unused production capacity of technologies annotated in the Technology -database table as curtailable technologies belonging to the -:code:`tech_curtailment` set. -Renewables such as wind and solar are often placed in this set. While we -used to simply formulate the :code:`Capacity` and :code:`CommodityBalance` -constraints as inequalities that implicitly allowed for curtailment, this -simpler approach does not work with renewable targets because the curtailed -portion of the electricity production counts towards the target, and there is -no way to distinguish it from the useful production. Including an explicit -curtailment term addresses the issue. Curtailment in the model is simply -the production activity that is not used in the model and is reported as -such in the output_curtailment table. Note: Outputs presented in the -`output_curtailment` table for curtailment (the table separately includes -flex outputs) are limited by Capacity Factor. Meaning: if a tech has a -capacity of 10 units, and a CF of 0.8 and a usage of 5 units, then the reported -curtailment is 3 units (0.8 x 10 - 5). - - -v_flow_in_storage -^^^^^^^^^^^^^^^ - -:math:`FIS_{r,p,s,d,i,t,v,o}` - -Because the production and consumption associated with storage techs occur -across different time slices, the comodity flow into a storage technologiy -cannot be discerned from :code:`v_flow_out`. Thus an explicit :math:`flow_in` -variable is required for storage. - -v_capacity -^^^^^^^^^^ - -:math:`CAP_{r,t,v}` - -The :code:`v_capacity` variable determines the required capacity of all processes -across the user-defined system. It is indexed for each process (t,v), and Temoa -constrains the capacity variable to be able to meet the total commodity flow out -of that process in all time slices in which it is active :eq:`Capacity`. - -v_capacity_available_by_period_and_tech -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:math:`CAPAVL_{r,p,t}` - -:code:`CapacityAvailableByPeriodAndTech` is a convenience variable that is -not strictly necessary, but used where the individual vintages of a technology -are not warranted (e.g. in calculating the maximum or minimum total capacity -allowed in a given time period). - -v_storage_init -^^^^^^^^^^^^^ - -:math:`SI_{r,t,v}` - -The :code:`v_storage_init` variable determines the initial storage charge level -at the beginning of the first time slice within a given time period. Each vintage -of each technology can have a different optimal initial value. Note that -this value also determines the ending storage charge level at the end of the -last time slice within each model time period. - -v_storage_level -^^^^^^^^^^^^^^ - -:math:`SL_{r,p,s,d,t,v}` - -The :code:`v_storage_level` variable tracks the storage charge level across ordered -time slices and is critical to ensure that storage charge and dispatch is constrained -by the energy available in the storage units. - - - -We explain the equations governing these variables the :ref:`Constraints` -section. - - -.. _constraints: - -Equations ---------- - -There are four main equations that govern the flow of energy through the model -network. The :code:`Demand_Constrant` :eq:`Demand` ensures that the supply meets -demand in every time slice. For each process, the :code:`Capacity_constraint` :eq:`Capacity` -ensures that there is sufficient capacity to meet the optimal commodity flows across all -time slices. Between processes, the :code:`CommodityBalance_constraint` :eq:`CommodityBalance` -ensures that global commodity production across the energy system is sufficient to meet the -endogenous demands for that commodity. Finally, the objective function :eq:`obj_invest` drives -the model to minimize the system-wide cost of energy supply by optimizing the deployment and -utilization of energy technologies across the system. - -One additional point regarding the model formulation. Technologies that -produce constant annual output can be placed in the :code:`tech_annual` set. -While not required, doing so improves computational performance by eliminating the -season and time of day :code:`(s,d)` indices associated with these technologies. -In order to ensure the model functions correctly with these simplified technologies, -slightly different formulations of the capacity and commodity balance constraints -are required. See the :code:`AnnualCommodityBalance_constraint` and -:code:`CapacityAnnual_constraint` :eq:`CapacityAnnual` below for details. - -The rest of this section defines each model constraint, with a rationale for -existence. We use the implementation-specific names for the constraints to -highlight the organization of the functions within the actual code. Note that -the definitions below are pulled directly from the docstrings embedded in -:code:`temoa_rules.py`. - - -.. _DecisionVariables: - -Constraints Defining Derived Decision Variables -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -These first four constraints define derived variables that are used within -the model. The :code:`Capacity_constraint` and :code:`CapacityAnnual_constraint` -are particularly important because they define the relationship between installed -capacity and allowable commodity flow. - -.. autofunction:: temoa_rules.Capacity_constraint - -.. autofunction:: temoa_rules.CapacityAnnual_constraint - -.. autofunction:: temoa_rules.AdjustedCapacity_constraint - -.. autofunction:: temoa_rules.AnnualRetirement_constraint - -.. autofunction:: temoa_rules.CapacityAvailableByPeriodAndTech_constraint - - -.. _NetworkConstraints: - -Network Constraints -^^^^^^^^^^^^^^^^^^^ - -These three constraints define the core of the Temoa model; together, they -define the algebraic energy system network. - -.. autofunction:: temoa_rules.demand_constraint - -.. autofunction:: temoa_rules.CommodityBalance_constraint - -.. autofunction:: temoa_rules.AnnualCommodityBalance_constraint - - -Physical and Operational Constraints -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -These constraints fine-tune the model formulation to account for -various physical and operational real-world phenomena. - -.. autofunction:: temoa_rules.BaseloadDiurnal_constraint - -.. autofunction:: temoa_rules.DemandActivity_constraint - -.. autofunction:: temoa_rules.StorageEnergy_constraint - -.. autofunction:: temoa_rules.SeasonalStorageEnergy_constraint - -.. autofunction:: temoa_rules.StorageEnergyUpperBound_constraint - -.. autofunction:: temoa_rules.SeasonalStorageEnergyUpperBound_constraint - -.. autofunction:: temoa_rules.StorageChargeRate_constraint - -.. autofunction:: temoa_rules.StorageDischargeRate_constraint - -.. autofunction:: temoa_rules.StorageThroughput_constraint - -.. autofunction:: temoa_rules.RampUpDay_constraint - -.. autofunction:: temoa_rules.RampDownDay_constraint - -.. autofunction:: temoa_rules.RampUpSeason_constraint - -.. autofunction:: temoa_rules.RampDownSeason_constraint - -.. autofunction:: temoa_rules.ReserveMarginStatic - -.. autofunction:: temoa_rules.ReserveMarginDynamic - - -Objective Function -^^^^^^^^^^^^^^^^^^ - -.. autofunction:: temoa_rules.annuity_to_pv - -.. autofunction:: temoa_rules.pv_to_annuity - -.. autofunction:: temoa_rules.fv_to_pv - -.. autofunction:: temoa_rules.total_cost_rule - - -User-Specific Constraints -^^^^^^^^^^^^^^^^^^^^^^^^^ - -The constraints provided in this section are not required for proper system -operation, but allow the modeler some further degree of system specification. - -.. commented out... not used? - .. autofunction:: temoa_rules.existing_capacity_constraint - -.. autofunction:: temoa_rules.limit_emission_constraint - -.. autofunction:: temoa_rules.limit_activity_constraint - -.. autofunction:: temoa_rules.limit_activity_share_constraint - -.. _MaxCapacity_constraint: - -.. autofunction:: temoa_rules.limit_capacity_constraint - -.. autofunction:: temoa_rules.limit_new_capacity_constraint - -.. autofunction:: temoa_rules.limit_capacity_share_constraint - -.. autofunction:: temoa_rules.limit_new_capacity_share_constraint - -.. autofunction:: temoa_rules.limit_resource_constraint - -.. _TechOutputSplit_constraint: - -.. autofunction:: temoa_rules.limit_tech_input_split_constraint - -.. autofunction:: temoa_rules.limit_tech_output_split_constraint - -.. autofunction:: temoa_rules.limit_tech_input_split_annual_constraint - -.. autofunction:: temoa_rules.limit_tech_output_split_annual_constraint - -.. autofunction:: temoa_rules.limit_tech_input_split_average_constraint - -.. autofunction:: temoa_rules.limit_tech_output_splitAverage_constraint - -.. autofunction:: temoa_rules.limit_annual_capacity_factor_constraint - -.. autofunction:: temoa_rules.limit_seasonal_capacity_factor_constraint - -.. autofunction:: temoa_rules.limit_storage_fraction_constraint - -.. autofunction:: temoa_rules.limit_growth_capacity - -.. autofunction:: temoa_rules.limit_growth_new_capacity - -.. autofunction:: temoa_rules.limit_growth_new_capacity_delta - - - -General Caveats ---------------- - -Temoa does not currently provide an easy avenue to track multiple concurrent -energy flows through a process. Consider a cogeneration plant. Where a -conventional power plant might simply emit excess heat as exhaust, a -cogeneration plant harnesses some or all of that heat for heating purposes, -either very close to the plant, or generally as hot water for district heating. -Temoa's flow variables can track both flows through a process, but each flow -will have its own efficiency from the efficiency parameter. This implies that -to produce 1 unit of electricity will require :math:`\frac{1}{elc eff}` units of -input. At the same time, to produce 1 unit of heat will require units of input -energy, and to produce both output units of heat and energy, both flows must be -active, and the desired activity will be double-counted by Temoa. - -To model a parallel output device (c.f., a cogeneration plant), the modeler must -currently set up the process with the :code:`TechInputSplit` and -:code:`TechOutputSplit` parameters, appropriately adding each flow to the -efficiency parameter and accounting for the overall process efficiency through -all flows. - - +.. include:: mathematical_formulation.rst ====================================== The Temoa Computational Implementation ====================================== -We have implemented Temoa within an algebraic modeling environment (AME). AMEs -provide both a convenient way to describe mathematical optimization models -for a computational context, and allow for abstract model\ [#abstract_model]_ -formulations :cite:`Kallrath_2004`. In contrast to describing a model in a -formal computer programming language like C or Java, AMEs generally have syntax -that directly translates to standard mathematical notation. Consequently, -models written in AMEs are more easily understood by a wider variety of researchers. -Further, by allowing abstract formulations, a model written with an AME may be -used with many different input data sets. - -Three well-known and popular algebraic modeling environments are the General -Algebraic Modeling System (GAMS) :cite:`Brooke_Rosenthal_2003`, AMPL -:cite:`Fourer_etal_1987`, and GNU MathProg :cite:`Makhorin_2000`. All three -environments provide concise syntax that closely resembles standard (paper) -notation. We decided to implement Temoa within an AME called -Python Optimization Modeling Objects (Pyomo). - -Pyomo provides similar functionality to GAMS, AMPL, and MathProg, but is open -source and written in the Python scripting language. This has two general -consequences of which to be aware: - - * Python is a scripting language; in general, scripts are an order of - magnitude slower than an equivalent compiled program. - * Pyomo provides similar functionality, but because of its Python heritage, is - **much** more verbose than GAMS, AMPL, or MathProg. - -It is our view that the speed penalty of Python as compared to compiled -languages is inconsequential in the face of other large resource bottle necks, -so we omit any discussion of it as an issue. However, the "boiler-plate" code -(verbosity) overhead requires some discussion. We discuss this in the -:ref:`Anatomy of a Constraint `. - - -.. _constraint-anatomy: - -Anatomy of a Constraint ------------------------ - -To help explain the Pyomo implementation, we discuss a single constraint in -detail. Consider the :code:`Demand` :eq:`Demand` constraint: - -.. math:: - \sum_{I, T, V} \textbf{FO}_{r, p, s, d, i, t, v, dem} + - SEG_{s,d} \cdot \sum_{I, T^{a}, V} \textbf{FOA}_{r, p, i, t, v, dem} - \ge - {DEM}_{r, p, dem} \cdot {DSD}_{r, s, d, dem} - - \\ - \forall \{r, p, s, d, dem\} \in \Theta_{\text{Demand}} - -Implementing this with Pyomo requires two pieces, and optionally a third: - - #. a constraint definition (in ``temoa_model.py``), - #. the constraint implementation (in ``temoa_rules.py``), and - #. (optional) sparse constraint index creation (in ``temoa_initialize.py``). - -We discuss first a straightforward implementation of this constraint, that -specifies the sets over which the constraint is defined. We will follow it with -the actual implementation which utilizes a more computationally efficient but -less transparent constraint index definition (the optional step 3). - -A simple definition of this constraint is: - -.. topic:: in ``temoa_model.py`` - - .. code-block:: python - :linenos: - - M.demand_constraint = Constraint( - M.regions, M.time_optimize, M.time_season, M.time_of_day, M.commodity_demand, - rule=demand_constraint - ) - -In line 1, '``M.demand_constraint =``' creates a place holder in the model object -``M``, called 'demand_constraint'. Like a variable, this is the name through -which Pyomo will reference this class of constraints. ``Constraint(...)`` is a -Pyomo-specific function that creates each individual constraint in the class. -The first arguments (line 2) are the index sets of the constraint class. Line 2 -is the Pyomo method of saying "for all" (:math:`\forall`). Line 3 contains the -final, mandatory argument (``rule=...``) that specifies the name of the -implementation rule for the constraint, in this case ``demand_constraint``. -Pyomo will call this rule with each tuple in the Cartesian product of the index -sets. - -An associated implementation of this constraint based on the definition above -is: - -.. topic:: temoa_rules.py - - ... - - .. code-block:: python - :linenos: - - def demand_constraint ( M, r, p, s, d, dem ): - if (r,p,s,d,dem) not in M.demand_specific_distribution.sparse_keys(): # If user did not specify this Demand, tell - return Constraint.Skip # Pyomo to ignore this constraint index. - - supply = sum( - M.v_flow_out[r, p, s, d, S_i, S_t, S_v, dem] - for S_t, S_v in M.commodity_up_stream_process[r, p, dem] if S_t not in M.tech_annual - for S_i in M.process_input_by_output[r, p, S_t, S_v, dem] - ) - - supply_annual = sum( - M.v_flow_out_annual[r, p, S_i, S_t, S_v, dem] - for S_t, S_v in M.commodity_up_stream_process[r, p, dem] if S_t in M.tech_annual - for S_i in M.process_input_by_output[r, p, S_t, S_v, dem] - ) * value( M.segment_fraction[ s, d]) - - demand_constraintErrorCheck(supply + supply_annual, r, p, s, d, dem) - - expr = supply + supply_annual == M.Demand[r, p, dem] * M.demand_specific_distribution[r, s, d, dem] - return expr - - ... - -The Python boiler-plate code to create the rule is on line 1. It begins with -:code:`def`, followed by the rule name (matching the :code:`rule=...` argument -in the constraint definition in ``temoa_model``), followed by the argument list. -The argument list will always start with the model (Temoa convention shortens -this to just :code:`M`) followed by local variable names in which to store the -index set elements passed by Pyomo. Note that the ordering is the same as -specified in the constraint definition. Thus the first item after :code:`M` -will be an item from :code:`region`, the second from :code:`time_optimize`, -the third from :code:`time_season`, fourth from :code:`time_of_day`, and the -fifth from :code:`commodity_demand`. Though one could choose :code:`a`, :code:`b`, -:code:`c`, :code:`d`, and :code:`e` (or any naming scheme), we chose :code:`p`, :code:`s`, -:code:`d`, and :code:`dem` as part of a :ref:`naming scheme -` to aid in mnemonic understanding. Consequently, the rule -signature (Line 1) is another place to look to discover what indices define a -constraint. - -Lines 2 and 3 are an indication that this constraint is implemented in a -non-sparse manner. That is, Pyomo does not inherently know the valid indices -for a given model parameter or equation. In ``temoa_model``, the constraint definition -listed five index sets, so Pyomo will naively call this function for every -possible combination of tuple :math:`\{r, p, s, d, dem\}`. However, as there -may be slices for which a demand does not exist (e.g., the winter season might -have no cooling demand), there is no need to create a constraint for any tuple -involving 'winter' and 'cooling'. Indeed, an attempt to access a demand for -which the modeler has not specified a value results in a Pyomo error, so it is -necessary to ignore any tuple for which no Demand exists. - -Lines 5 through 11 represent two *source-lines* that we split over several lines for -clarity. These lines implement the summations of the demand commodity ``dem`` -produced by demand technologies with both variable and constant output across the -year, summed over all relevant technologies, vintages, and the inputs. The -:code:`supply` and :code:`supply_annual` are local variables used in the expression -(:code:`expr`) shown below. Note that the sum is performed with sparse indices, which -are returned from dictionaries created in :code:`temoa_initialize.py`. - -Lines 5 through 11 also showcase a very common idiom in Python: -list-comprehension. List comprehension is a concise and efficient syntax to -create lists. As opposed to building a list element-by-element with for-loops, -list comprehension can convert many statements into a single operation. -Consider a naive approach to calculating the supply:: - - to_sum = list() - for S_t in M.tech_all: - for S_v in M.vintage_all: - for S_i in process_input_by_output( p, S_t, S_v, dem ): - to_sum.append( M.v_flow_out[p, s, d, S_i, S_t, S_v, dem] ) - supply = sum( to_sum ) - -This implementation creates an extra list (:code:`to_sum`), then builds the list -element by element with :code:`.append()`, before finally calculating the summation. -This means that the Python interpreter must iterate through the elements of the -summation, not once, but twice. - -A less naive approach would replace the :code:`.append()` call with the -:code:`+=` operator, reducing the number of iterations through the elements to -one:: - - supply = 0 - for S_t in M.tech_all: - for S_v in M.vintage_all: - for S_i in process_input_by_output( p, S_t, S_v, dem ): - supply += M.v_flow_out[p, s, d, S_i, S_t, S_v, dem] - -Why is list comprehension necessary? Strictly speaking, it is not, especially -in light of this last example, which may read more familiar to those comfortable -with C, Fortran, or Java. However, due to quirks of both Python and Pyomo, -list-comprehension is preferred both syntactically as "the Pythonic" way, and as -the more efficient route for many list manipulations. (It also *may* seem -slightly more familiar to those used to a more mainstream algebraic modeling -language.) - -With the correct model variables summed and stored in the ``supply`` and -``supply_annual`` variables, Line 17 calls a function defined in -:code:`temoa_initialize.py` that checks to make sure there is technology -that can supply each demand commodity ``dem`` in each :math:`\{r, p, s, d\}`. - -If no process supplies the demand, then it quits computation immediately rather -than completing a potentially lengthy model generation and waiting for the -solver to recognize the infeasibility of the model. Further, the function -lists potential ways for the modeler to correct the problem. This is one of the -benefits of Temoa: we've incorporated error handling in several places to -try and capture the most common user errors. This capability is subtle, but in -practice extremely useful while building and debugging a model. - -Line 19 creates the actual inequality comparison. This line is superfluous, but -we leave it in the code as a reminder that inequality operators (i.e. :code:`<=` -and :code:`>=`) with a Pyomo object (like supply) generate a Pyomo *expression -object*, not a boolean True or False as one might expect.\ [#return_expression]_ -It is this expression object that must be returned to Pyomo, as on Line 20. - -In the above implementation, the constraint is called for every tuple in the -Cartesian product of the indices, and the constraint must then decide whether -each tuple is valid. The below implementation differs from the one above -because it only calls the constraint rule for the valid tuples within the -Cartesian product, which is computationally more efficient than the simpler -implementation above. - -.. topic:: in ``temoa_model.py`` (actual implementation) - - .. code-block:: python - :linenos: - - M.demand_constraint_rpsdc = Set( dimen=5, rule=demand_constraintIndices ) - # ... - M.demand_constraint = Constraint( M.demand_constraint_rpsdc, rule=demand_constraint ) - - -As discussed above, the demand_constraint is only valid for certain -:math:`\{r, p, s, d, dem\}` tuples. Since the modeler can specify the demand -distribution per commodity (necessary to model demands like heating, that do not -apply in all time slices), Temoa must ascertain the valid tuples. We have -implemented this logic in the function :code:`demand_constraintIndices` in -``temoa_initialize.py``. Thus, Line 1 tells Pyomo to instantiate -:code:`demand_constraint_rpsdc` as a Set of 5-length tuples indices -(:code:`dimen=5`), and populate it with what Temoa's rule -:code:`demand_constraintIndices` returns. We omit here an explanation of the -implementation of the :code:`demand_constraintIndices` function, stating merely -that it returns the exact indices over which the demand_constraint must to be -created. With the sparse set :code:`demand_constraint_rpsdc` created, we can now -can use it in place of the five sets specified in the non-sparse -implementation. Pyomo will now call the constraint implementation rule the -minimum number of times. - -On the choice of the :code:`_rpsdc` suffix for the index set name, there is no -Pyomo-enforced restriction. However, use of an index set in place of the -non-sparse specification obfuscates over what indexes a constraint is defined. -While it is not impossible to deduce, either from this documentation -or from looking at the :code:`demand_constraintIndices` or -:code:`demand_constraint` implementations, the Temoa convention includes -index set names that feature the one-character representation of each set dimension. -In this case, the name :code:`demand_constraint_rpsdc` implies that this set has a -dimensionality of 5, and (following the :ref:`naming scheme -`) the first index of each tuple will be an element of -:code:`region`, the second an element of :code:`time_optimize`, the third -an element of :code:`time_season`, fourth an element of :code:`time_of_day`, -and fifth a commodity. From the contextual information that this is the -Demand constraint, one can assume that the ``c`` represents an element from -:code:`commodity_demand`. - - - - - -A Word on Verbosity -------------------- - -Implementing this same constraint in AMPL, GAMS, or MathProg would require only -a single source-line (in a single file). Using MathProg as an example, it might -look like: - -.. code-block:: ampl - - s.t. demand_constraint{(p, s, d, dem) in sDemand_psd_dem} : - sum{(p, s, d, Si, St, Sv, dem) in sFlowVar_psditvo} - v_flow_out[p, s, d, Si, St, Sv, dem] - = - pDemand[p, s, d, dem]; - -While the syntax is not a direct translation, the indices of the constraint -(``p``, ``s``, ``d``, and ``dem``) are clear, and by inference, so are the -indices of summation (``i``, ``t``, ``v``) and operand (``v_flow_out``). This -one-line definition creates an inequality for each period, season, time of day, -and demand, ensuring that total output meets each demand in each time slice -- -almost exactly as we have formulated the demand constraint :eq:`Demand`. In -contrast, Temoa's implementation in Pyomo takes 47 source-lines (the code -discussed above does not include the function documentation). While some of the -verbosity is inherent to working with a general purpose scripting language, and -most of it is our formatting for clarity, the absolute minimum number of lines a -Pyomo constraint can be is 2 lines, and that likely will be even less readable. - -So why use Python and Pyomo if they are so verbose? In short, for four -reasons: - - * Temoa has the full power of Python, and has access to a rich ecosystem of - tools (e.g. numpy, matplotlib) that are not as cleanly available to other - AMLs. For instance, there is minimal capability in MathProg to error check a - model before a solve, and providing interactive feedback like what Temoa's - demand_constraintErrorCheck function does is difficult, if not impossible. - While a subtle addition, specific and directed error messages are an - effective measure to reduce the learning curve for new modelers. - - * Python has a vibrant community. Whereas mathematical optimization has a - small community, its open-source segment even smaller, and the energy modeling segment - significantly smaller than that, the Python community is huge, and - encompasses many disciplines. This means that where a developer may struggle - to find an answer, implementation, or workaround to a problem with a more - standard AML, Python will likely enable a community-suggested solution. - - * Powerful documentation tools. One of the available toolsets in the Python - world is documentation generators that *dynamically* introspect Python code. - While it is possible to inline and block comment with more traditional AMLs, - the integration with Python that many documentation generators have is much - more powerful. Temoa uses this capability to embed user-oriented - documentation literally in the code, and almost every constraint has a block - comment. Having both the documentation and implementation in one place helps - reduce the mental friction and discrepancies often involved in maintaining - multiple sources of model authority. - - * AMLs are not as concise as thought. - -This last point is somewhat esoteric, but consider the MathProg implementation -of the Demand constraint in contrast with the last line of the Pyomo version:: - - expr = (supply = M.Demand[p, s, d, dem]) - -While the MathProg version indeed translates more directly to standard notation, -consider that standard notation itself needs extensive surrounding text to -explain the significance of an equation. *Why* does the equation compare the -sum of a subset of FlowOut to Demand? In Temoa's implementation, a high-level -understanding of what a constraint does requires only the last line of code: -"Supply must meet demand." - - -Project Structure ------------------ - -The Temoa model code is split into several packages: - -1. ``temoa_model`` contains the mathematical model and supporting code to perform basic runs - - * ``temoa_model.py`` - contains the overall model definition, defining the - various sets, parameters, variables, and equations of the Temoa model. - Peruse this file for a high-level overview of the model. It references rule - implementations in the ``temoa_rules.py`` file for implementations. Of note, - the ``TemoaModel`` class needs to remain serializable by Python's ``pickle`` - module, so there are no functions/lambdas within the class. This is enforced by - one of the project tests. - - * ``temoa_rules.py`` - mainly contains the rule implementations. That is, this - file implements the objective function, internal parameters, and constraint - logic. Where ``temoa_model`` provides the high-level overview, this file - provides the actual equation implementations. - - * ``temoa_initialize.py`` - contains the code used to initialize the model, - including sparse matrix indexing and checks on parameter and constraint - specifications. - - * ``temoa_sequencer.py`` - contains the code required to run the execution sequence - during the model run. This module may pass control to other extensions as reqd. - - * ``run_actions.py`` - contains actions needed to build/solve the model in the course - of a run - - * ``hybrid_loader.py`` - contains the interface to load model data from a sqlite - database and, when requested, interface with the source-tracing code to QA data. - - - * ``table_writer.py`` - formats the results returned by the model; includes - outputting results to the shell, storing them in a database, and if requested, - calling 'db_to_excel.py' to create the Excel file outputs. - -2. ``data_processing`` - contains modules to process output results - -3. ``extensions`` - contains sub packages to execute alternative solve modes - - * ``myopic`` - contains a separate sequencer and support files to run the model - in myopic mode, which is configurable via the config file. - - * ``stochastic`` - contains the PySP required alterations to the - deterministic model for use in a stochastic model. Specifically, Temoa - only needs one additional constraint class in order to partition the - calculation of the objective function per period. - - * ``modeling_to_generate_alternatives`` - contains modules to execute an "MGA" - series of runs on the model via multiprocessing. MGA is configured via the - config file and the additional files in this package. - - * ``method_of_morris`` - contains modules to execute basic sensitivity analysis - using method of morris techniques and is described more fully in the ``readme`` - in that package. - -If you are working with a Temoa Git repository, these packages/files are in the -``temoa/`` subdirectory. - - -The Bleeding Edge ------------------ - -The Temoa Project uses the Git source code management system, and the services -of Github.com. If you are inclined to work with the bleeding edge of the Temoa -Project code base, then take a look at the Temoa repository. To acquire a -copy, make sure you have Git installed on your local machine, then execute this -command to clone the repository: - -.. code:: - - $ git clone git://github.com/TemoaProject/temoa.git - Cloning into 'temoa'... - remote: Counting objects: 2386, done. - remote: Compressing objects: 100% (910/910), done. - remote: Total 2386 (delta 1552), reused 2280 (delta 1446) - Receiving objects: 100% (2386/2386), 2.79 MiB | 1.82 MiB/s, done. - Resolving deltas: 100% (1552/1552), done. - -You will now have a new subdirectory called ``temoa``, that contains the entire -Temoa Project code and archive history. Note that Git is a *distributed* source -code management tool. This means that by cloning the Temoa repository, you have -your own copy to which you are welcome (and encouraged!) to alter and make -commits to. It will not affect the source repository. - -Though this is not a Git manual, we recognize that many readers of this manual -may not be software developers, so we offer a few quick pointers to using Git -effectively. - -If you want to see the log of commits, use the command git log: - -.. code:: - - $ git log -1 - commit b5bddea7312c34c5c44fe5cce2830cbf5b9f0f3b - Date: Thu Jul 5 03:23:11 2012 -0400 - - Update two APIs - - * I had updated the internal global variables to use the _psditvo - naming scheme, and had forgotten to make the changes to _graphviz.py - * Coopr also updated their API with the new .sparse_* methods. - -You can also explore the various development branches in the repository: - -.. code:: - - $ ls - data_files stochastic temoa_model create_archive.sh README.txt - - $ git branch -a - * energysystem - remotes/origin/HEAD -> origin/energysystem - remotes/origin/energysystem - remotes/origin/exp_electric_load_duration_reorg - remotes/origin/exp_electricity_sector - remotes/origin/exp_energysystem_flow_based - remotes/origin/exp_energysystem_match_markal - remotes/origin/exp_energysystem_test_framework - remotes/origin/misc_scripts - remotes/origin/old_energysystem_coopr2 - remotes/origin/temoaproject.org - - $ git checkout exp_energysystem_match_markal - Branch exp_energysystem_match_markal set up to track remote branch - exp_energysystem_match_markal from origin. - Switched to a new branch 'exp_energysystem_match_markal' - - $ ls - temoa_model create_archive.sh utopia-markal-20.dat - compare_with_utopia-15.py README.txt - compare_with_utopia-20.py utopia-markal-15.dat - -To view exactly what changes you have made since the most recent commit to the -repository use the ``diff`` command to ``git``: - -.. code:: - - $ git diff - diff --git a/temoa_model/temoa_lib.py b/temoa_model/temoa_lib.py - index 4ff9b30..0ba15b0 100644 - --- a/temoa_model/temoa_lib.py - +++ b/temoa_model/temoa_lib.py - @@ -246,7 +246,7 @@ def InitializeProcessParameters ( M ): - if l_vin in M.vintage_exist: - if l_process not in l_exist_indices: - msg = ('Warning: %s has a specified efficiency, but does not ' - - 'have any existing install base (existing_capacity)\n.') - + 'have any existing install base (existing_capacity).\n') - SE.write( msg % str(l_process) ) - continue - if 0 == M.existing_capacity[ l_process ]: - [ ... ] - -For a crash course on git, here is a handy `quick start guide`_. - - -====================== -Temoa Code Style Guide -====================== - -It is an open question in programming circles whether code formatting actually -matters. The Temoa Project developers believe that it does for these main -reasons: - - * Consistently-formatted code reduces the cognitive work required to understand - the structure and intent of a code base. Specifically, we believe that - before code is to be executed, it is to be understood by other humans. The - fact that it makes the computer do something useful is a (happy) coincidence. - * Consistently-formatted code helps identify `code smell`_\ . - * Consistently-formatted code helps one to spot code bugs and typos more - easily. - -Note, however, that this is a style `guide`, not a strict ruleset. There will -also be corner cases to which a style guide does not apply, and in these cases, -the judgment of what to do is left to the implementers and maintainers of the -code base. To this end, the Python project has a well-written treatise in `PEP -8`_\ : - - **A Foolish Consistency is the Hobgoblin of Little Minds** - - One of Guido's key insights is that code is read much more often than it is - written. The guidelines provided here are intended to improve the - readability of code and make it consistent across the wide spectrum of Python - code. As PEP 20 says, "Readability counts". - - A style guide is about consistency. Consistency with this style guide is - important. Consistency within a project is more important. Consistency - within one module or function is most important. - - But most importantly: know when to be inconsistent -- sometimes the style - guide just doesn't apply. When in doubt, use your best judgment. Look at - other examples and decide what looks best. And don't hesitate to ask! - - Two good reasons to break a particular rule: - - 1. When applying the rule would make the code less readable, even for - someone who is used to reading code that follows the rules. - 2. To be consistent with surrounding code that also breaks it (maybe for - historic reasons) -- although this is also an opportunity to clean up - someone else's mess (in true XP style). - -Ruff Formatting ---------------- - -The project has shifted to using Ruff (`ruff`_) as a formatter / linter. Commits to -the project should use Ruff to format any changed code. Ruff relies on -settings in the :code:`pyproject.toml` file. Contributors should be able -to apply ruff to any changed files with the command :code:`ruff format `. -If there is *specific* need to disable Ruff for a particular table or equation, -contributors can sparingly turn off Ruff formatting for sections of code using -comments. (See the Ruff documentation.) - -Indentation: Tabs and Spaces ----------------------------- - -The project is standardized to using spaces for indentation in accordance with -PEP-8 standards. Ruff will convert tabs to spaces. - - -End of Line Whitespace ----------------------- - -Remove it. Many editors have plugins or builtin functionality that will take -care of this automatically when the file is saved. - - -Maximum Line Length -------------------- - -(Similar to `PEP 8`_\ ) Limit all lines to a maximum of 100 characters. - -Historically, 80 characters was the width (in monospace characters) that a -terminal had to display output. With the advent of graphical user interfaces -with variable font-sizes, this technological limit no longer exists. While -80 characters remains an excellent metric of what constitutes a "long line" most -modern wide-screen displays can comfortably show side-by-side difference files with -100 characters per side, and 100 characters better accommodates some long equations. A -long line in this sense is one that is not as transparent as to its intent as it -could be. **Ruff will enforce 100 character line length**, in accordance with the settings -in the ``pyproject.toml`` file - -Slightly adapted from `PEP 8`_\ : - - The preferred way of wrapping long lines is by using Python's implied line - continuation inside parentheses, brackets and braces. Long lines can be - broken over multiple lines by wrapping expressions in parentheses. These - should be used in preference to using a backslash for line continuation. - Make sure to indent the continued line appropriately. The preferred place to - break around a binary operator is after the operator, not before it. Some - examples: - - .. code-block:: python - - class Rectangle ( Blob ): - - def __init__ ( self, width, height, - color='black', emphasis=None, highlight=0 ): - if ( width == 0 and height == 0 and - color == 'red' and emphasis == 'strong' or - highlight > 100 ): - raise ValueError("sorry, you lose") - if width == 0 and height == 0 and (color == 'red' or - emphasis is None): - raise ValueError("I don't think so -- values are {}, {}".format( - (width, height) )) - Blob.__init__( self, width, height, - color, emphasis, highlight ) - - -Blank Lines ------------ - - * Separate logical sections within a single function with a single blank line. - * Separate function and method definitions with two blank lines. - * Separate class definitions with three blank lines. - - -Encodings ---------- - -Following `PEP 3120`, all code files should use UTF-8 encoding. - -.. commented out - Punctuation and Spacing - ----------------------- - - Always put spaces after code punctuation, like equivalence tests, assignments, - and index lookups. - - .. code-block:: python - - a=b # bad - a = b # good - - a==b # bad - a == b # good - - a[b] = c # bad - a[ b ] = c # good - - # exception: if there is more than one index - a[ b, c ] = d # acceptable, but not preferred - a[b, c] = d # good, preferred - - # exception: if using a string literal, don't include a space: - a[ 'x' ] == d # bad - a['x'] == d # good - - When defining a function or method, put a single space on either side of each - parenthesis: - - .. code-block:: python - - def someFunction(a, b, c): # bad - pass - - def someFunction ( a, b, c ): # good - pass - - - Vertical Alignment - ------------------ - - *Where appropriate*, vertically align sections of the code. - - .. code-block:: python - - # bad - M.someVariable = Var( M.someIndex, domain=NonNegativeIntegers ) - M.otherVariable = Var( M.otherIndex, domain=NonNegativeReals ) - - # good - M.someVariable = Var( M.someIndex, domain=NonNegativeIntegers ) - M.otherVariable = Var( M.otherIndex, domain=NonNegativeReals ) - - - Single, Double, and Triple Quotes - --------------------------------- - - Python has four delimiters to mark a string literal in the code: ``"``, ``'``, - ``"""``, and |'''|. Use each as appropriate. One should rarely need to escape - a quote within a string literal, because one can merely alternate use of the - single, double or triple quotes: - - .. code-block:: python - - a = "She said, \"Do not do that!\"" # bad - a = 'She said, "Do not do that!"' # good - - b = "She said, \"Don't do that!\"" # bad - b = 'She said, "Don\'t do that!"' # bad - b = """She said, "Don't do that!\"""" # bad - b = '''She said, "Don't do that!"''' # good - - -.. _naming_conventions: - -Naming Conventions ------------------- - -All constraints attached to a model should end with ``Constraint``. Similarly, -the function they use to define the constraint for each index should use the -same prefix and ``Constraint`` suffix, but separate them with an underscore -(e.g. ``M.somenameConstraint = Constraint( ..., rule=somename_constraint``): - -.. code-block:: python - - M.capacity_constraint = Constraint( M.CapacityVar_tv, rule=Capacity_constraint ) - -When providing the implementation for a constraint rule, use a consistent naming -scheme between functions and constraint definitions. For instance, we have -already chosen ``M`` to represent the Pyomo model instance, ``t`` to represent -*technology*, and ``v`` to represent *vintage*: - -.. code-block:: python - - def Capacity_constraint ( M, t, v ): - ... - -The complete list we have already chosen: - - * :math:`p` to represent a period item from :math:`time\_optimize` - * :math:`s` to represent a season item from :math:`time\_season` - * :math:`d` to represent a time of day item from :math:`time\_of\_day` - * :math:`i` to represent an input to a process, an item from - :math:`commodity\_physical` - * :math:`t` to represent a technology from :math:`tech\_all` - * :math:`v` to represent a vintage from :math:`vintage\_all` - * :math:`o` to represent an output of a process, an item from - :math:`commodity\_carrier` - -Note also the order of presentation, even in this list. In order to reduce the -number mental "question marks" one might have while discovering Temoa, we -attempt to rigidly reference a mental model of "left to right". Just as the -entire energy system that Temoa optimizes may be thought of as a left-to-right -graph, so too are the individual processes. As mentioned above in `A Word on Index -Ordering`_: - - For any indexed parameter or variable within Temoa, our intent is to enable a - mental model of a left-to-right arrow-box-arrow as a simple mnemonic to - describe the "input :math:`\rightarrow` process :math:`\rightarrow` output" - flow of energy. And while not all variables, parameters, or constraints have - 7 indices, the 7-index order mentioned here (p, s, d, i, t, v, o) is the - canonical ordering. If you note any case where, for example, d comes before - s, that is an oversight. - - -In-line Implementation Conventions ----------------------------------- - -Wherever possible, implement the algorithm in a way that is *pedagogically* -sound or reads like an English sentence. Consider this snippet: - -.. code-block:: python - - if ( a > 5 and a < 10 ): - doSomething() - -In English, one might translate this snippet as "If a is greater than 5 and less -then 10, do something." However, a semantically stronger implementation might -be: - -.. code-block:: python - - if ( 5 < a and a < 10 ): - doSomething() - -This reads closer to the more familiar mathematical notation of ``5 < a < 10`` -and translates to English as "If a is between 5 and 10, do something." The -semantic meaning that ``a`` should be *between* 5 and 10 is more readily -apparent from just the visual placement between 5 and 10, and is easier for the -"next person" to understand (who may very well be you in six months!). - -Consider the reverse case: - -.. code-block:: python - - if ( a < 5 or a > 10 ): - doSomething() - -On the number line, this says that a must fall before 5 or beyond 10. But the -intent might more easily be understood if altered as above: - -.. code-block:: python - - if not ( 5 < a and a < 10 ): - doSomething() - -This last snippet now makes clear the core question that a should ``not`` fall -between 5 and 10. - -Consider another snippet: - -.. code-block:: python - - acounter = scounter + 1 - -This method of increasing or incrementing a variable is one that many -mathematicians-turned-programmers prefer, but is more prone to error. For -example, is that an intentional use of ``acounter`` or ``scounter``? Assuming -as written that it's incorrect, a better paradigm uses the += operator: - -.. code-block:: python - - acounter += 1 - -This performs the same operation, but makes clear that the ``acounter`` variable -is to be incremented by one, rather than be set to one greater than ``scounter``. - -The same argument can be made for the related operators: - -.. code-block:: python - - >>> a, b, c = 10, 3, 2 - - >>> a += 5; a # same as a = a + 5 - 15 - >>> a -= b; a # same as a = a - b - 12 - >>> a /= b; a # same as a = a / b - 4 - >>> a *= c; a # same as a = a * c - 8 - >>> a **= c; a # same as a = a ** c - 64 - - -Miscellaneous Style Conventions -------------------------------- - - * (Same as `PEP 8`_\ ) Do not use spaces around the assignment operator (``=``) - when used to indicate a default argument or keyword parameter: - - .. code-block:: python - - def complex ( real, imag = 0.0 ): # bad - return magic(r = real, i = imag) # bad - - def complex ( real, imag=0.0 ): # good - return magic( r=real, i=imag ) # good - - * (Same as `PEP 8`_\ ) Do not use spaces immediately before the open - parenthesis that starts the argument list of a function call: - - .. code-block:: python - - a = b.calc () # bad - a = b.calc ( c ) # bad - a = b.calc( c ) # good - - * (Same as `PEP 8`_\ ) Do not use spaces immediately before the open - bracket that starts an indexing or slicing: - - .. code-block:: python - - a = b ['key'] # bad - a = b [a, b] # bad - a = b['key'] # good - a = b[a, b] # good - - -Patches and Commits to the Repository -------------------------------------- - -In terms of code quality and maintaining a legible "audit trail," every patch -should meet a basic standard of quality: - - * Every commit to the repository must include an appropriate summary message - about the accompanying code changes. Include enough context that one reading - the patch need not also inspect the code to get a high-level understanding of - the changes. For example, "Fixed broken algorithm" does not convey much - information. A more appropriate and complete summary message might be:: - - Fixed broken storage algorithm - - The previous implementation erroneously assumed that only the energy - flow out of a storage device mattered. However, Temoa needs to know the - energy flow in to all devices so that it can appropriately calculate the - inter-process commodity balance. - - License: GPLv2 - - If there is any external information that would be helpful, such as a bug - report, include a "clickable" link to it, such that one reading the patch as - via an email or online, can immediately view the external information. - - Specifically, commit messages should follow the form:: - - A subject line of 50 characters or less - [ an empty line ] - 1. http://any.com/ - 2. http://relevant.org/some/path/ - 3. http://urls.edu/~some/other/path/ - 4. https://github.com/blog/926-shiny-new-commit-styles - 5. https://help.github.com/articles/github-flavored-markdown - [ another empty line ] - Any amount and format of text, such that it conforms to a line-width of - 72 characters[4]. Bonus points for being aware of the Github Markdown - syntax[5]. - - License: GPLv2 - - * Ensure that each commit contains no more than one *logical* change to the - code base. This is very important for later auditing. If you have not - developed in a logical manner (like many of us don't), :code:`git add -p` is - a very helpful tool. - - * If you are not a core maintainer of the project, all commits must also - include a specific reference to the license under which you are giving your - code to the project. Note that Temoa will not accept any patches that - are not licensed under GPLv2. A line like this at the end of your commit - will suffice:: - - ... the last line of the commit message. - - License: GPLv2 - - This indicates that you retain all rights to any intellectual property your - (set of) commit(s) creates, but that you license it to the Temoa Project - under the terms of the GNU Public License, version 2. If - the Temoa Project incorporates your commit, then Temoa may not relicense - your (set of) patch(es), other than to increase the version number of the - GPL license. In short, the intellectual property remains yours, and the - Temoa Project would be but a licensee using your code similarly under the - terms of GPLv2. - - Executing licensing in this manner -- rather than requesting IP assignment -- - ensures that no one group of code contributers may unilaterally change the - license of Temoa, unless **all** contributers agree in writing in a - publicly archived forum (such as the `Temoa Forum`_). - - * When you are ready to submit your (set of) patch(es) to the Temoa Project, - we will utilize GitHub's `Pull Request`_ mechanism. - +.. include:: computational_implementation.rst .. rubric:: Footnotes .. [#open_source_realities] The two main goals behind Temoa are transparency and - repeatability, hence the GPLv2 license. Unfortunately, there are some harsh + repeatability, hence the MIT license. Unfortunately, there are some harsh realities in the current climate of energy modeling, so this license is not a guarantee of openness. This documentation touches on the issues involved in the final section. @@ -3053,10 +71,10 @@ should meet a basic standard of quality: .. _Temoa model: http://temoaproject.org/download/temoa.py .. _temoaproject.org: http://temoaproject.org/ .. _example data sets: http://temoaproject.org/download/example_data_sets.zip -.. _mailing list: https://groups.google.com/forum/#!forum/temoa-project -.. _Temoa Forum: https://groups.google.com/forum/#!forum/temoa-project +.. _mailing list: https://groups.google.com/forum/\#\!forum/temoa-project +.. _Temoa Forum: https://groups.google.com/forum/\#\!forum/temoa-project .. _various: http://xlinux.nist.gov/dads/HTML/optimization.html -.. _available: http://www.stanford.edu/~boyd/cvxbook/ +.. _available: http://www.stanford.edu/\~boyd/cvxbook/ .. _online: https://en.wikipedia.org/wiki/Optimization_problem .. _sources: https://en.wikipedia.org/wiki/Mathematical_optimization .. _GAMS: http://www.gams.com/ @@ -3068,8 +86,8 @@ should meet a basic standard of quality: .. _code smell: https://en.wikipedia.org/wiki/Code_smell .. _PEP 8: http://www.python.org/dev/peps/pep-0008/ .. _PEP 3120: http://www.python.org/dev/peps/pep-3120/ -.. _list comprehension: http://docs.python.org/tutorial/datastructures.html#list-comprehensions -.. _lambda function: http://docs.python.org/tutorial/controlflow.html#lambda-forms +.. _list comprehension: http://docs.python.org/tutorial/datastructures.html\#list-comprehensions +.. _lambda function: http://docs.python.org/tutorial/controlflow.html\#lambda-forms .. _generally accepted relative rates: http://www.forecasts.org/inflation.htm .. _Pull Request: https://help.github.com/articles/using-pull-requests .. _quick start guide: http://rogerdudler.github.io/git-guide/ @@ -3078,3 +96,4 @@ should meet a basic standard of quality: .. _ruff: https://docs.astral.sh/ruff/ .. bibliography:: References.bib +.. _GitHub Issues: https://github.com/TemoaProject/temoa/issues diff --git a/docs/source/computational_implementation.rst b/docs/source/computational_implementation.rst new file mode 100644 index 000000000..549a805f6 --- /dev/null +++ b/docs/source/computational_implementation.rst @@ -0,0 +1,865 @@ +The Temoa Computational Implementation +====================================== + +We have implemented Temoa within an algebraic modeling environment (AME). AMEs +provide both a convenient way to describe mathematical optimization models +for a computational context, and allow for abstract model\ [#abstract_model]_ +formulations :cite:`Kallrath_2004`. In contrast to describing a model in a +formal computer programming language like C or Java, AMEs generally have syntax +that directly translates to standard mathematical notation. Consequently, +models written in AMEs are more easily understood by a wider variety of researchers. +Further, by allowing abstract formulations, a model written with an AME may be +used with many different input data sets. + +Three well-known and popular algebraic modeling environments are the General +Algebraic Modeling System (GAMS) :cite:`Brooke_Rosenthal_2003`, AMPL +:cite:`Fourer_etal_1987`, and GNU MathProg :cite:`Makhorin_2000`. All three +environments provide concise syntax that closely resembles standard (paper) +notation. We decided to implement Temoa within an AME called +Python Optimization Modeling Objects (Pyomo). + +Pyomo provides similar functionality to GAMS, AMPL, and MathProg, but is open +source and written in the Python scripting language. This has two general +consequences of which to be aware: + + * Python is a scripting language; in general, scripts are an order of + magnitude slower than an equivalent compiled program. + * Pyomo provides similar functionality, but because of its Python heritage, is + **much** more verbose than GAMS, AMPL, or MathProg. + +It is our view that the speed penalty of Python as compared to compiled +languages is inconsequential in the face of other large resource bottle necks, +so we omit any discussion of it as an issue. However, the "boiler-plate" code +(verbosity) overhead requires some discussion. We discuss this in the +:ref:`Anatomy of a Constraint `. + + +.. _constraint-anatomy: + +Anatomy of a Constraint +----------------------- + +To help explain the Pyomo implementation, we discuss a single constraint in +detail. Consider the :code:`Demand` :eq:`Demand` constraint: + +.. math:: + \sum_{I, T, V} \textbf{FO}_{r, p, s, d, i, t, v, dem} + + SEG_{s,d} \cdot \sum_{I, T^{a}, V} \textbf{FOA}_{r, p, i, t, v, dem} + \ge + {DEM}_{r, p, dem} \cdot {DSD}_{r, s, d, dem} + + \\ + \forall \{r, p, s, d, dem\} \in \Theta_{\text{Demand}} + +Implementing this with Pyomo requires two pieces, and optionally a third: + + #. a constraint definition (in ``temoa/core/model.py``), + #. the constraint implementation (in ``temoa/components/``), and + #. (optional) sparse constraint index creation (in ``temoa/components/technology.py``). + +We discuss first a straightforward implementation of this constraint, that +specifies the sets over which the constraint is defined. We will follow it with +the actual implementation which utilizes a more computationally efficient but +less transparent constraint index definition (the optional step 3). + +A simple definition of this constraint is: + +.. topic:: in ``temoa/core/model.py`` + + .. code-block:: python + :linenos: + + M.demand_constraint = Constraint( + M.regions, M.time_optimize, M.time_season, M.time_of_day, M.commodity_demand, + rule=demand_constraint + ) + +In line 1, '``M.demand_constraint =``' creates a place holder in the model object +``M``, called 'demand_constraint'. Like a variable, this is the name through +which Pyomo will reference this class of constraints. ``Constraint(...)`` is a +Pyomo-specific function that creates each individual constraint in the class. +The first arguments (line 2) are the index sets of the constraint class. Line 2 +is the Pyomo method of saying "for all" (:math:`\forall`). Line 3 contains the +final, mandatory argument (``rule=...``) that specifies the name of the +implementation rule for the constraint, in this case ``demand_constraint``. +Pyomo will call this rule with each tuple in the Cartesian product of the index +sets. + +An associated implementation of this constraint based on the definition above +is: + +.. topic:: temoa/components/ + + ... + + .. code-block:: python + :linenos: + + def demand_constraint ( M, r, p, s, d, dem ): + if (r,p,s,d,dem) not in M.demand_specific_distribution.sparse_keys(): # If user did not specify this Demand, tell + return Constraint.Skip # Pyomo to ignore this constraint index. + + supply = sum( + M.v_flow_out[r, p, s, d, S_i, S_t, S_v, dem] + for S_t, S_v in M.commodity_up_stream_process[r, p, dem] if S_t not in M.tech_annual + for S_i in M.process_input_by_output[r, p, S_t, S_v, dem] + ) + + supply_annual = sum( + M.v_flow_out_annual[r, p, S_i, S_t, S_v, dem] + for S_t, S_v in M.commodity_up_stream_process[r, p, dem] if S_t in M.tech_annual + for S_i in M.process_input_by_output[r, p, S_t, S_v, dem] + ) * value( M.segment_fraction[ s, d]) + + demand_constraintErrorCheck(supply + supply_annual, r, p, s, d, dem) + + expr = supply + supply_annual == M.Demand[r, p, dem] * M.demand_specific_distribution[r, s, d, dem] + return expr + + ... + +The Python boiler-plate code to create the rule is on line 1. It begins with +:code:`def`, followed by the rule name (matching the :code:`rule=...` argument +in the constraint definition in ``temoa.core.model``), followed by the argument list. +The argument list will always start with the model (Temoa convention shortens +this to just :code:`M`) followed by local variable names in which to store the +index set elements passed by Pyomo. Note that the ordering is the same as +specified in the constraint definition. Thus the first item after :code:`M` +will be an item from :code:`region`, the second from :code:`time_optimize`, +the third from :code:`time_season`, fourth from :code:`time_of_day`, and the +fifth from :code:`commodity_demand`. Though one could choose :code:`a`, :code:`b`, +:code:`c`, :code:`d`, and :code:`e` (or any naming scheme), we chose :code:`p`, :code:`s`, +:code:`d`, and :code:`dem` as part of a :ref:`naming scheme +` to aid in mnemonic understanding. Consequently, the rule +signature (Line 1) is another place to look to discover what indices define a +constraint. + +Lines 2 and 3 are an indication that this constraint is implemented in a +non-sparse manner. That is, Pyomo does not inherently know the valid indices +for a given model parameter or equation. In ``temoa.core.model``, the constraint definition +listed five index sets, so Pyomo will naively call this function for every +possible combination of tuple :math:`\{r, p, s, d, dem\}`. However, as there +may be slices for which a demand does not exist (e.g., the winter season might +have no cooling demand), there is no need to create a constraint for any tuple +involving 'winter' and 'cooling'. Indeed, an attempt to access a demand for +which the modeler has not specified a value results in a Pyomo error, so it is +necessary to ignore any tuple for which no Demand exists. + +Lines 5 through 11 represent two *source-lines* that we split over several lines for +clarity. These lines implement the summations of the demand commodity ``dem`` +produced by demand technologies with both variable and constant output across the +year, summed over all relevant technologies, vintages, and the inputs. The +:code:`supply` and :code:`supply_annual` are local variables used in the expression +(:code:`expr`) shown below. Note that the sum is performed with sparse indices, which +are returned from dictionaries created in :code:`temoa/components/technology.py`. + +Lines 5 through 11 also showcase a very common idiom in Python: +list-comprehension. List comprehension is a concise and efficient syntax to +create lists. As opposed to building a list element-by-element with for-loops, +list comprehension can convert many statements into a single operation. +Consider a naive approach to calculating the supply:: + + to_sum = list() + for S_t in M.tech_all: + for S_v in M.vintage_all: + for S_i in process_input_by_output( p, S_t, S_v, dem ): + to_sum.append( M.v_flow_out[p, s, d, S_i, S_t, S_v, dem] ) + supply = sum( to_sum ) + +This implementation creates an extra list (:code:`to_sum`), then builds the list +element by element with :code:`.append()`, before finally calculating the summation. +This means that the Python interpreter must iterate through the elements of the +summation, not once, but twice. + +A less naive approach would replace the :code:`.append()` call with the +:code:`+=` operator, reducing the number of iterations through the elements to +one:: + + supply = 0 + for S_t in M.tech_all: + for S_v in M.vintage_all: + for S_i in process_input_by_output( p, S_t, S_v, dem ): + supply += M.v_flow_out[p, s, d, S_i, S_t, S_v, dem] + +Why is list comprehension necessary? Strictly speaking, it is not, especially +in light of this last example, which may read more familiar to those comfortable +with C, Fortran, or Java. However, due to quirks of both Python and Pyomo, +list-comprehension is preferred both syntactically as "the Pythonic" way, and as +the more efficient route for many list manipulations. (It also *may* seem +slightly more familiar to those used to a more mainstream algebraic modeling +language.) + +With the correct model variables summed and stored in the ``supply`` and +``supply_annual`` variables, Line 17 calls a function defined in +:code:`temoa/components/technology.py` that checks to make sure there is technology +that can supply each demand commodity ``dem`` in each :math:`\{r, p, s, d\}`. + +If no process supplies the demand, then it quits computation immediately rather +than completing a potentially lengthy model generation and waiting for the +solver to recognize the infeasibility of the model. Further, the function +lists potential ways for the modeler to correct the problem. This is one of the +benefits of Temoa: we've incorporated error handling in several places to +try and capture the most common user errors. This capability is subtle, but in +practice extremely useful while building and debugging a model. + +Line 19 creates the actual inequality comparison. This line is superfluous, but +we leave it in the code as a reminder that inequality operators (i.e. :code:`<=` +and :code:`>=`) with a Pyomo object (like supply) generate a Pyomo *expression +object*, not a boolean True or False as one might expect.\ [#return_expression]_ +It is this expression object that must be returned to Pyomo, as on Line 20. + +In the above implementation, the constraint is called for every tuple in the +Cartesian product of the indices, and the constraint must then decide whether +each tuple is valid. The below implementation differs from the one above +because it only calls the constraint rule for the valid tuples within the +Cartesian product, which is computationally more efficient than the simpler +implementation above. + +.. topic:: in ``temoa/core/model.py`` (actual implementation) + + .. code-block:: python + :linenos: + + M.demand_constraint_rpsdc = Set( dimen=5, rule=demand_constraint_indices ) + # ... + M.demand_constraint = Constraint( M.demand_constraint_rpsdc, rule=demand_constraint ) + + +As discussed above, the demand_constraint is only valid for certain +:math:`\{r, p, s, d, dem\}` tuples. Since the modeler can specify the demand +distribution per commodity (necessary to model demands like heating, that do not +apply in all time slices), Temoa must ascertain the valid tuples. We have +implemented this logic in the function :code:`demand_constraint_indices` in +``temoa/components/technology.py``. Thus, Line 1 tells Pyomo to instantiate +:code:`demand_constraint_rpsdc` as a Set of 5-length tuples indices +(:code:`dimen=5`), and populate it with what Temoa's rule +:code:`demand_constraint_indices` returns. We omit here an explanation of the +implementation of the :code:`demand_constraint_indices` function, stating merely +that it returns the exact indices over which the demand_constraint must to be +created. With the sparse set :code:`demand_constraint_rpsdc` created, we can now +can use it in place of the five sets specified in the non-sparse +implementation. Pyomo will now call the constraint implementation rule the +minimum number of times. + +On the choice of the :code:`_rpsdc` suffix for the index set name, there is no +Pyomo-enforced restriction. However, use of an index set in place of the +non-sparse specification obfuscates over what indexes a constraint is defined. +While it is not impossible to deduce, either from this documentation +or from looking at the :code:`demand_constraint_indices` or +:code:`demand_constraint` implementations, the Temoa convention includes +index set names that feature the one-character representation of each set dimension. +In this case, the name :code:`demand_constraint_rpsdc` implies that this set has a +dimensionality of 5, and (following the :ref:`naming scheme +`) the first index of each tuple will be an element of +:code:`region`, the second an element of :code:`time_optimize`, the third +an element of :code:`time_season`, fourth an element of :code:`time_of_day`, +and fifth a commodity. From the contextual information that this is the +Demand constraint, one can assume that the ``c`` represents an element from +:code:`commodity_demand`. + + + + + +A Word on Verbosity +------------------- + +Implementing this same constraint in AMPL, GAMS, or MathProg would require only +a single source-line (in a single file). Using MathProg as an example, it might +look like: + +.. code-block:: ampl + + s.t. demand_constraint{(p, s, d, dem) in sDemand_psd_dem} : + sum{(p, s, d, Si, St, Sv, dem) in sFlowVar_psditvo} + v_flow_out[p, s, d, Si, St, Sv, dem] + = + pDemand[p, s, d, dem]; + +While the syntax is not a direct translation, the indices of the constraint +(``p``, ``s``, ``d``, and ``dem``) are clear, and by inference, so are the +indices of summation (``i``, ``t``, ``v``) and operand (``v_flow_out``). This +one-line definition creates an inequality for each period, season, time of day, +and demand, ensuring that total output meets each demand in each time slice -- +almost exactly as we have formulated the demand constraint :eq:`Demand`. In +contrast, Temoa's implementation in Pyomo takes 47 source-lines (the code +discussed above does not include the function documentation). While some of the +verbosity is inherent to working with a general purpose scripting language, and +most of it is our formatting for clarity, the absolute minimum number of lines a +Pyomo constraint can be is 2 lines, and that likely will be even less readable. + +So why use Python and Pyomo if they are so verbose? In short, for four +reasons: + + * Temoa has the full power of Python, and has access to a rich ecosystem of + tools (e.g. numpy, matplotlib) that are not as cleanly available to other + AMLs. For instance, there is minimal capability in MathProg to error check a + model before a solve, and providing interactive feedback like what Temoa's + demand_constraintErrorCheck function does is difficult, if not impossible. + While a subtle addition, specific and directed error messages are an + effective measure to reduce the learning curve for new modelers. + + * Python has a vibrant community. Whereas mathematical optimization has a + small community, its open-source segment even smaller, and the energy modeling segment + significantly smaller than that, the Python community is huge, and + encompasses many disciplines. This means that where a developer may struggle + to find an answer, implementation, or workaround to a problem with a more + standard AML, Python will likely enable a community-suggested solution. + + * Powerful documentation tools. One of the available toolsets in the Python + world is documentation generators that *dynamically* introspect Python code. + While it is possible to inline and block comment with more traditional AMLs, + the integration with Python that many documentation generators have is much + more powerful. Temoa uses this capability to embed user-oriented + documentation literally in the code, and almost every constraint has a block + comment. Having both the documentation and implementation in one place helps + reduce the mental friction and discrepancies often involved in maintaining + multiple sources of model authority. + + * AMLs are not as concise as thought. + +This last point is somewhat esoteric, but consider the MathProg implementation +of the Demand constraint in contrast with the last line of the Pyomo version:: + + expr = (supply = M.Demand[p, s, d, dem]) + +While the MathProg version indeed translates more directly to standard notation, +consider that standard notation itself needs extensive surrounding text to +explain the significance of an equation. *Why* does the equation compare the +sum of a subset of FlowOut to Demand? In Temoa's implementation, a high-level +understanding of what a constraint does requires only the last line of code: +"Supply must meet demand." + + +Project Structure +----------------- + +The Temoa model code is organized into clear, purpose-driven packages: + +**Core Packages:** + +* ``temoa.core`` - Public API for end users + + * ``model.py`` - Contains the ``TemoaModel`` class, the main entry point for building + and solving energy system models. This class coordinates all model components. + + * ``config.py`` - Contains ``TemoaConfig`` and ``TemoaMode`` for model configuration + and execution mode selection (perfect foresight, myopic, MGA, etc.). + +* ``temoa.cli`` - Command-line interface + + * Provides the ``temoa`` command with subcommands for running models, validating + configurations, migrating databases, and generating tutorial files. + +* ``temoa.components`` - Model components and constraints + + * ``costs.py`` - Objective function implementation (total system cost minimization) + * ``flows.py`` - Commodity flow balance constraints + * ``capacity.py`` - Capacity and activity constraints + * ``emissions.py`` - Emission accounting and constraints + * ``reserves.py`` - Reserve margin requirements + * ``limits.py`` - Various limit constraints (capacity, activity, emissions, etc.) + * ``storage.py`` - Energy storage constraints + * ``ramping.py`` - Ramping constraints for generators + * Additional constraint modules for specific features + +* ``temoa.data_io`` - Data loading and validation + + * ``hybrid_loader.py`` - Main data loading engine using manifest-driven architecture + * ``component_manifest.py`` - Declarative specification of all data components + * ``loader_manifest.py`` - Data structure definitions for the loader + * Database interface and validation logic + +* ``temoa.model_checking`` - Model validation and integrity checking + + * Price checking for cost data consistency + * Source tracing for commodity network validation + * Network visualization tools + +* ``temoa.data_processing`` - Output analysis and visualization + + * ``db_to_excel.py`` - Excel output generation (āš ļø untested in v4.0) + * ``make_graphviz.py`` - Network diagram generation (āš ļø untested in v4.0) + * Result processing utilities + +* ``temoa.extensions`` - Optional extensions for advanced analysis + + * ``modeling_to_generate_alternatives`` - MGA analysis for exploring near-optimal solutions (āš ļø untested in v4.0) + * ``method_of_morris`` - Sensitivity analysis (āš ļø untested in v4.0) + * ``monte_carlo`` - Uncertainty quantification (āš ļø untested in v4.0) + * ``myopic`` - Sequential decision making with limited foresight + * ``single_vector_mga`` - Focused MGA on specific variables (āš ļø untested in v4.0) + * ``stochastics`` - Stochastic programming capabilities (āš ļø untested in v4.0) + +* ``temoa._internal`` - Internal utilities (not part of public API) + + * ``table_writer.py`` - Database output formatting + * ``table_data_puller.py`` - Result extraction utilities + * Other internal helper modules + +If you are working with a Temoa Git repository, these packages are in the +``temoa/`` subdirectory. For detailed architecture documentation, see the +README.md file in the repository root. + + +The Bleeding Edge +----------------- + +The Temoa Project uses the Git source code management system, and the services +of Github.com. If you are inclined to work with the bleeding edge of the Temoa +Project code base, then take a look at the Temoa repository. To acquire a +copy, make sure you have Git installed on your local machine, then execute this +command to clone the repository: + +.. code:: + + $ git clone git://github.com/TemoaProject/temoa.git + Cloning into 'temoa'... + remote: Counting objects: 2386, done. + remote: Compressing objects: 100% (910/910), done. + remote: Total 2386 (delta 1552), reused 2280 (delta 1446) + Receiving objects: 100% (2386/2386), 2.79 MiB | 1.82 MiB/s, done. + Resolving deltas: 100% (1552/1552), done. + +You will now have a new subdirectory called ``temoa``, that contains the entire +Temoa Project code and archive history. Note that Git is a *distributed* source +code management tool. This means that by cloning the Temoa repository, you have +your own copy to which you are welcome (and encouraged!) to alter and make +commits to. It will not affect the source repository. + +Though this is not a Git manual, we recognize that many readers of this manual +may not be software developers, so we offer a few quick pointers to using Git +effectively. + +If you want to see the log of commits, use the command git log: + +.. code:: + + $ git log -1 + commit b5bddea7312c34c5c44fe5cce2830cbf5b9f0f3b + Date: Thu Jul 5 03:23:11 2012 -0400 + + Update two APIs + + * I had updated the internal global variables to use the _psditvo + naming scheme, and had forgotten to make the changes to _graphviz.py + * Coopr also updated their API with the new .sparse_* methods. + +You can also explore the various development branches in the repository: + +.. code:: + + $ ls + data_files stochastic temoa_model create_archive.sh README.txt + + $ git branch -a + * energysystem + remotes/origin/HEAD -> origin/energysystem + remotes/origin/energysystem + remotes/origin/exp_electric_load_duration_reorg + remotes/origin/exp_electricity_sector + remotes/origin/exp_energysystem_flow_based + remotes/origin/exp_energysystem_match_markal + remotes/origin/exp_energysystem_test_framework + remotes/origin/misc_scripts + remotes/origin/old_energysystem_coopr2 + remotes/origin/temoaproject.org + + $ git checkout exp_energysystem_match_markal + Branch exp_energysystem_match_markal set up to track remote branch + exp_energysystem_match_markal from origin. + Switched to a new branch 'exp_energysystem_match_markal' + + $ ls + temoa_model create_archive.sh utopia-markal-20.dat + compare_with_utopia-15.py README.txt + compare_with_utopia-20.py utopia-markal-15.dat + +To view exactly what changes you have made since the most recent commit to the +repository use the ``diff`` command to ``git``: + +.. code:: + + $ git diff + diff --git a/temoa_model/temoa_lib.py b/temoa_model/temoa_lib.py + index 4ff9b30..0ba15b0 100644 + --- a/temoa_model/temoa_lib.py + +++ b/temoa_model/temoa_lib.py + @@ -246,7 +246,7 @@ def InitializeProcessParameters ( M ): + if l_vin in M.vintage_exist: + if l_process not in l_exist_indices: + msg = ('Warning: %s has a specified efficiency, but does not ' + - 'have any existing install base (existing_capacity)\n.') + + 'have any existing install base (existing_capacity).\n') + SE.write( msg % str(l_process) ) + continue + if 0 == M.existing_capacity[ l_process ]: + [ ... ] + +For a crash course on git, here is a handy `quick start guide`_. + + +====================== +Temoa Code Style Guide +====================== + +It is an open question in programming circles whether code formatting actually +matters. The Temoa Project developers believe that it does for these main +reasons: + + * Consistently-formatted code reduces the cognitive work required to understand + the structure and intent of a code base. Specifically, we believe that + before code is to be executed, it is to be understood by other humans. The + fact that it makes the computer do something useful is a (happy) coincidence. + * Consistently-formatted code helps identify `code smell`_\ . + * Consistently-formatted code helps one to spot code bugs and typos more + easily. + +Note, however, that this is a style `guide`, not a strict ruleset. There will +also be corner cases to which a style guide does not apply, and in these cases, +the judgment of what to do is left to the implementers and maintainers of the +code base. To this end, the Python project has a well-written treatise in `PEP +8`_\ : + + **A Foolish Consistency is the Hobgoblin of Little Minds** + + One of Guido's key insights is that code is read much more often than it is + written. The guidelines provided here are intended to improve the + readability of code and make it consistent across the wide spectrum of Python + code. As PEP 20 says, "Readability counts". + + A style guide is about consistency. Consistency with this style guide is + important. Consistency within a project is more important. Consistency + within one module or function is most important. + + But most importantly: know when to be inconsistent -- sometimes the style + guide just doesn't apply. When in doubt, use your best judgment. Look at + other examples and decide what looks best. And don't hesitate to ask! + + Two good reasons to break a particular rule: + + 1. When applying the rule would make the code less readable, even for + someone who is used to reading code that follows the rules. + 2. To be consistent with surrounding code that also breaks it (maybe for + historic reasons) -- although this is also an opportunity to clean up + someone else's mess (in true XP style). + +Ruff Formatting +--------------- + +The project has shifted to using Ruff (`ruff`_) as a formatter / linter. Commits to +the project should use Ruff to format any changed code. Ruff relies on +settings in the :code:`pyproject.toml` file. Contributors should be able +to apply ruff to any changed files with the command :code:`ruff format `. +If there is *specific* need to disable Ruff for a particular table or equation, +contributors can sparingly turn off Ruff formatting for sections of code using +comments. (See the Ruff documentation.) + +Indentation: Tabs and Spaces +---------------------------- + +The project is standardized to using spaces for indentation in accordance with +PEP-8 standards. Ruff will convert tabs to spaces. + + +End of Line Whitespace +---------------------- + +Remove it. Many editors have plugins or builtin functionality that will take +care of this automatically when the file is saved. + + +Maximum Line Length +------------------- + +(Similar to `PEP 8`_\ ) Limit all lines to a maximum of 100 characters. + +Historically, 80 characters was the width (in monospace characters) that a +terminal had to display output. With the advent of graphical user interfaces +with variable font-sizes, this technological limit no longer exists. While +80 characters remains an excellent metric of what constitutes a "long line" most +modern wide-screen displays can comfortably show side-by-side difference files with +100 characters per side, and 100 characters better accommodates some long equations. A +long line in this sense is one that is not as transparent as to its intent as it +could be. **Ruff will enforce 100 character line length**, in accordance with the settings +in the ``pyproject.toml`` file + +Slightly adapted from `PEP 8`_\ : + + The preferred way of wrapping long lines is by using Python's implied line + continuation inside parentheses, brackets and braces. Long lines can be + broken over multiple lines by wrapping expressions in parentheses. These + should be used in preference to using a backslash for line continuation. + Make sure to indent the continued line appropriately. The preferred place to + break around a binary operator is after the operator, not before it. Some + examples: + + .. code-block:: python + + class Rectangle ( Blob ): + + def __init__ ( self, width, height, + color='black', emphasis=None, highlight=0 ): + if ( width == 0 and height == 0 and + color == 'red' and emphasis == 'strong' or + highlight > 100 ): + raise ValueError("sorry, you lose") + if width == 0 and height == 0 and (color == 'red' or + emphasis is None): + raise ValueError("I don't think so -- values are {}, {}".format( + (width, height) )) + Blob.__init__( self, width, height, + color, emphasis, highlight ) + + +Blank Lines +----------- + + * Separate logical sections within a single function with a single blank line. + * Separate function and method definitions with two blank lines. + * Separate class definitions with three blank lines. + + +Encodings +--------- + +Following `PEP 3120`, all code files should use UTF-8 encoding. + +.. _naming_conventions: + +Naming Conventions +------------------ + +All constraints attached to a model should end with ``constraint``. Similarly, +the function they use to define the constraint for each index should use the +same prefix and ``constraint`` suffix, but separate them with an underscore +(e.g. ``M.somename_constraint = Constraint( ..., rule=somename_constraint``): + +.. code-block:: python + + M.capacity_constraint = Constraint( M.CapacityVar_tv, rule=Capacity_constraint ) + +When providing the implementation for a constraint rule, use a consistent naming +scheme between functions and constraint definitions. For instance, we have +already chosen ``model`` to represent the Pyomo model instance, ``t`` to represent +*technology*, and ``v`` to represent *vintage*: + +.. code-block:: python + + def capacity_constraint ( model: TemoaModel, t: Technology, v: Vintage ): + ... + +The complete list we have already chosen: + + * :math:`p` to represent a period item from :math:`time\_optimize` + * :math:`s` to represent a season item from :math:`time\_season` + * :math:`d` to represent a time of day item from :math:`time\_of\_day` + * :math:`i` to represent an input to a process, an item from + :math:`commodity\_physical` + * :math:`t` to represent a technology from :math:`tech\_all` + * :math:`v` to represent a vintage from :math:`vintage\_all` + * :math:`o` to represent an output of a process, an item from + :math:`commodity\_carrier` + +Note also the order of presentation, even in this list. In order to reduce the +number mental "question marks" one might have while discovering Temoa, we +attempt to rigidly reference a mental model of "left to right". Just as the +entire energy system that Temoa optimizes may be thought of as a left-to-right +graph, so too are the individual processes. As mentioned above in `A Word on Index +Ordering`_: + + For any indexed parameter or variable within Temoa, our intent is to enable a + mental model of a left-to-right arrow-box-arrow as a simple mnemonic to + describe the "input :math:`\rightarrow` process :math:`\rightarrow` output" + flow of energy. And while not all variables, parameters, or constraints have + 7 indices, the 7-index order mentioned here (p, s, d, i, t, v, o) is the + canonical ordering. If you note any case where, for example, d comes before + s, that is an oversight. + + +In-line Implementation Conventions +---------------------------------- + +Wherever possible, implement the algorithm in a way that is *pedagogically* +sound or reads like an English sentence. Consider this snippet: + +.. code-block:: python + + if ( a > 5 and a < 10 ): + doSomething() + +In English, one might translate this snippet as "If a is greater than 5 and less +then 10, do something." However, a semantically stronger implementation might +be: + +.. code-block:: python + + if ( 5 < a and a < 10 ): + doSomething() + +This reads closer to the more familiar mathematical notation of ``5 < a < 10`` +and translates to English as "If a is between 5 and 10, do something." The +semantic meaning that ``a`` should be *between* 5 and 10 is more readily +apparent from just the visual placement between 5 and 10, and is easier for the +"next person" to understand (who may very well be you in six months!). + +Consider the reverse case: + +.. code-block:: python + + if ( a < 5 or a > 10 ): + doSomething() + +On the number line, this says that a must fall before 5 or beyond 10. But the +intent might more easily be understood if altered as above: + +.. code-block:: python + + if not ( 5 < a and a < 10 ): + doSomething() + +This last snippet now makes clear the core question that a should ``not`` fall +between 5 and 10. + +Consider another snippet: + +.. code-block:: python + + acounter = scounter + 1 + +This method of increasing or incrementing a variable is one that many +mathematicians-turned-programmers prefer, but is more prone to error. For +example, is that an intentional use of ``acounter`` or ``scounter``? Assuming +as written that it's incorrect, a better paradigm uses the += operator: + +.. code-block:: python + + acounter += 1 + +This performs the same operation, but makes clear that the ``acounter`` variable +is to be incremented by one, rather than be set to one greater than ``scounter``. + +The same argument can be made for the related operators: + +.. code-block:: python + + >>> a, b, c = 10, 3, 2 + + >>> a += 5; a # same as a = a + 5 + 15 + >>> a -= b; a # same as a = a - b + 12 + >>> a /= b; a # same as a = a / b + 4 + >>> a *= c; a # same as a = a * c + 8 + >>> a **= c; a # same as a = a ** c + 64 + + +Miscellaneous Style Conventions +------------------------------- + + * (Same as `PEP 8`_\ ) Do not use spaces around the assignment operator (``=``) + when used to indicate a default argument or keyword parameter: + + .. code-block:: python + + def complex ( real, imag = 0.0 ): # bad + return magic(r = real, i = imag) # bad + + def complex ( real, imag=0.0 ): # good + return magic( r=real, i=imag ) # good + + * (Same as `PEP 8`_\ ) Do not use spaces immediately before the open + parenthesis that starts the argument list of a function call: + + .. code-block:: python + + a = b.calc () # bad + a = b.calc ( c ) # bad + a = b.calc( c ) # good + + * (Same as `PEP 8`_\ ) Do not use spaces immediately before the open + bracket that starts an indexing or slicing: + + .. code-block:: python + + a = b ['key'] # bad + a = b [a, b] # bad + a = b['key'] # good + a = b[a, b] # good + + +Patches and Commits to the Repository +------------------------------------- + +In terms of code quality and maintaining a legible "audit trail," every patch +should meet a basic standard of quality: + + * Every commit to the repository must include an appropriate summary message + about the accompanying code changes. Include enough context that one reading + the patch need not also inspect the code to get a high-level understanding of + the changes. For example, "Fixed broken algorithm" does not convey much + information. A more appropriate and complete summary message might be:: + + Fixed broken storage algorithm + + The previous implementation erroneously assumed that only the energy + flow out of a storage device mattered. However, Temoa needs to know the + energy flow in to all devices so that it can appropriately calculate the + inter-process commodity balance. + + License: MIT + + If there is any external information that would be helpful, such as a bug + report, include a "clickable" link to it, such that one reading the patch as + via an email or online, can immediately view the external information. + + Specifically, commit messages should follow the form:: + + A subject line of 50 characters or less + [ an empty line ] + 1. http://any.com/ + 2. http://relevant.org/some/path/ + 3. http://urls.edu/~some/other/path/ + 4. https://github.com/blog/926-shiny-new-commit-styles + 5. https://help.github.com/articles/github-flavored-markdown + [ another empty line ] + Any amount and format of text, such that it conforms to a line-width of + 72 characters[4]. Bonus points for being aware of the Github Markdown + syntax[5]. + + License: MIT + + * Ensure that each commit contains no more than one *logical* change to the + code base. This is very important for later auditing. If you have not + developed in a logical manner (like many of us don't), :code:`git add -p` is + a very helpful tool. + + * If you are not a core maintainer of the project, all commits must also + include a specific reference to the license under which you are giving your + code to the project. Note that Temoa will not accept any patches that + are not licensed under MIT. A line like this at the end of your commit + will suffice:: + + ... the last line of the commit message. + + License: MIT + + This indicates that you retain all rights to any intellectual property your + (set of) commit(s) creates, but that you license it to the Temoa Project + under the terms of the GNU Public License, version 2. If + the Temoa Project incorporates your commit, then Temoa may not relicense + your (set of) patch(es), other than to increase the version number of the + GPL license. In short, the intellectual property remains yours, and the + Temoa Project would be but a licensee using your code similarly under the + terms of MIT. + + Executing licensing in this manner -- rather than requesting IP assignment -- + ensures that no one group of code contributers may unilaterally change the + license of Temoa, unless **all** contributers agree in writing in a + publicly archived forum (such as the `Temoa Forum`_). + + * When you are ready to submit your (set of) patch(es) to the Temoa Project, + we will utilize GitHub's `Pull Request`_ mechanism. diff --git a/docs/source/mathematical_formulation.rst b/docs/source/mathematical_formulation.rst new file mode 100644 index 000000000..5c11cfb08 --- /dev/null +++ b/docs/source/mathematical_formulation.rst @@ -0,0 +1,1503 @@ + +To understand this section, the reader will need at least a cursory +understanding of mathematical optimization. We omit here that introduction, +and instead refer the reader to `various`_ `available`_ `online`_ `sources`_. +Temoa is formulated as an algebraic model that requires information organized +into sets, parameters, variables, and equation +definitions. + +The heart of Temoa is a technology explicit energy system optimization model. +It is an algebraic network of linked processes -- where each process is defined +by a set of engineering characteristics (e.g. capital cost, efficiency, capacity +factor, emission rates) -- that transform raw energy sources into end-use +demands. The model objective function minimizes the present-value cost of +energy supply by optimizing installed capacity and its utilization over time. + +.. _simple_system: + +.. figure:: images/simple_system2.* + :align: center + :width: 100% + :alt: A simple energy system, with energy sources on the left and energy + sinks (end-use demands) on the right. + :figclass: align-center + :figwidth: 70% + + A common visualization of energy system models is a directed network graph, + with energy sources on the left and end-use demands on the right. The + modeler must specify the end-use demands to be met, the technologies defined + within the system (rectangles), and the inputs and outputs of each (red and green + arrows). The circles represent distinct energy carriers that connect + technologies within the energy system network. + +The most fundamental tenet of the model is the understanding of energy flow, +treating all processes as black boxes that take inputs and produce outputs. +Specifically, Temoa does not care about the inner workings of a process, only +its global input and output characteristics. In this vein, the above graphic +can be broken down into process-specific elements. For example, the coal power +plant takes as input coal and produces electricity, and is subject to various +costs (e.g. variable costs) and constraints (e.g. efficiency) along the way. + +.. figure:: images/coal_process.png + :align: center + :figclass: center + :figwidth: 60% + + +The modeler defines the processes and engineering characteristics through a +combination of sets and parameters, described in the next few sections. Temoa then +utilizes these parameters, along with the associated technology-specific decision +variables for capacity and activity, to create the objective function and +constraints that are used during the optimization process. + +.. _Sets: + + +Conventions +----------- + + * In the mathematical notation, we use CAPITALIZATION to denote a container, + like a set, indexed variable, or indexed parameter. Sets use only a single + letter, so we use the lower case to represent an item from the set. For + example, :math:`T` represents the set of all technologies and :math:`t` + represents a single item from :math:`T`. + + * Variables are named V\_VarName within the code to aid readability. However, + in the documentation where there is benefit of italics and other font + manipulations, we elide the 'V\_' prefix. + + * In all equations, we **bold** variables to distinguish them from parameters. + Take, for example, this excerpt from the Temoa default objective function: + + .. math:: + C_{variable} = \sum_{r, p, s, d, i, t, v, o \in \Theta_{VC}} \left ( + {VC}_{r, p, t, v} + \cdot R_p + \cdot \textbf{FO}_{r, p, s, d, i, t, v, o} + \right ) + + Note that :math:`C_{variable}` is not bold, as it is a temporary variable + used for clarity while constructing the objective function. It is not a + structural variable and the solver never sees it. + + * Where appropriate, we put the variable on the right side of the coefficient. + In other words, this is not a preferred form of the previous equation: + + .. math:: + + C_{variable} = \sum_{r, p, s, d, i, t, v, o \in \Theta_{VC}} \left ( + \textbf{FO}_{r, p, s, d, i, t, v, o} + \cdot {VC}_{r, p, t, v} + \cdot R_p + \right ) + + * We generally put the limiting or defining aspect of an equation on the right + hand side of the relational operator, and the aspect being limited or defined + on the left hand side. For example, equation :eq:`Capacity` defines Temoa's + mathematical understanding of a process capacity (:math:`\textbf{CAP}`) in + terms of that process' activity (:math:`\textbf{ACT}`): + + .. math:: + + \left ( + \text{CFP}_{r, t, v} + \cdot \text{C2A}_{r, t} + \cdot \text{SEG}_{s, d} + \right ) + \cdot \textbf{CAP}_{r, t, v} + = + \sum_{I, O} \textbf{FO}_{r, p, s, d,i, t, v, o} + + + \sum_{I, O} \textbf{CUR}_{r, p, s, d, i, t, v, o} + + \\ + \forall \{r, p, s, d, t, v\} \in \Theta_{\text{FO}} + + * We use the word 'slice' to refer to the tuple of season and time of day + :math:`\{s,d\}`. Note that these time slices are user-defined, and can + represent time ranging large blocks of time (e.g., winter-night) to every + hour in a given season. + + * We use the word 'process' to refer to the tuple of technology and vintage + (:math:`\{t,v\}`). For example, solar PV (technology) installed in 2030 + (vintage). + + + * Mathematical notation: + + * We use the symbol :math:`\mathbb{I}` to represent the unit interval ([0, + 1]). + + * We use the symbol :math:`\mathbb{Z}` to represent "the set of all + integers." + + * We use the symbol :math:`\mathbb{N}` to represent natural numbers (i.e., + integers greater than zero: 1, 2, 3, :math:`\ldots`). + + * We use the symbol :math:`\mathbb{R}` to denote the set of real numbers, and + :math:`\mathbb{R}^+_0` to denote non-negative real numbers. + + +Sets +---- + +.. _table_set: + +.. csv-table:: List of all Temoa sets with which a modeler might interact. The + asterisked (\*) elements are automatically derived by the model and + are not user-specifiable. + :header: "Set","Temoa Name","Data Type","Short Description" + :widths: 8, 28, 14, 50 + + ":math:`{}^*\text{C}`",":code:`commodity_all`","string","union of all commodity sets" + ":math:`\text{C}^s`",":code:`commodity_source`","string","input sources (not balanced by CommodityBalance_constraint)" + ":math:`\text{C}^d`",":code:`commodity_demand`","string","end-use demand commodities" + ":math:`\text{C}^e`",":code:`commodity_emissions`","string","emission commodities (e.g. :math:`\text{CO}_\text{2}` :math:`\text{NO}_\text{x}`)" + ":math:`\text{C}^p`",":code:`commodity_physical`","string","general energy forms (e.g. electricity, coal, uranium, oil)" + ":math:`\text{C}^a`",":code:`commodity_annual`","string","same as commodity physical but flows are only balanced over each period (:math:`\text{C}^a \subset \text{C}^p`)" + ":math:`\text{C}^w`",":code:`commodity_waste`","string","production can be greater than consumption. can be physical, annual, or neither (not balanced)" + ":math:`{}^*\text{C}^c`",":code:`commodity_carrier`","string","physical energy carriers and end-use demands (:math:`\text{C}_p \cup \text{C}_d`)" + ":math:`\text{I}`",,"string","alias of :math:`\text{C}^p`; used in documentation only to mean ""input""" + ":math:`\text{O}`",,"string","alias of :math:`\text{C}^c`; used in documentation only to mean ""output""" + ":math:`\text{P}^e`",":code:`time_existing`",":math:`\mathbb{Z}`","model periods before optimization begins" + ":math:`\text{P}^f`",":code:`time_future`",":math:`\mathbb{Z}`","model time scale of interest; the last year is not optimized" + ":math:`{}^*\text{P}^o`",":code:`time_optimize`",":math:`\mathbb{Z}`","model time periods to optimize; (:math:`\text{P}^f - \text{max}(\text{P}^f)`)" + ":math:`\text{R}`",":code:`regions`","string","distinct geographical regions" + ":math:`{}^*\text{V}`",":code:`vintage_all`",":math:`\mathbb{Z}`","possible tech vintages; (:math:`\text{P}^e \cup \text{P}^o`)" + ":math:`\text{S}`",":code:`time_season`","string","seasonal divisions (e.g. winter, summer)" + ":math:`\text{D}`",":code:`time_of_day`","string","time-of-day divisions (e.g. morning)" + ":math:`{}^*\text{T}`",":code:`tech_all`","string","all technologies to be modeled; (:math:`{T}^r \cup {T}^p`)" + ":math:`\text{T}^u`",":code:`tech_unlim_cap`","string","technologies that have no bound on capacity, and can have variable costs only (imports, taxes, etc.); (:math:`{T}^u \subset (T - T^{res})`)" + ":math:`\text{T}^a`",":code:`tech_annual`","string","technologies that produce constant annual output; (:math:`{T}^a \subset T`)" + ":math:`\text{T}^b`",":code:`tech_baseload`","string","baseload electric generators; (:math:`{T}^b \subset T`)" + ":math:`\text{T}^c`",":code:`tech_curtailment`","string","technologies with curtailable output and no upstream cost; (:math:`{T}^c \subset (T - T^{res})`)" + ":math:`\text{T}^x`",":code:`tech_exchange`","string","technologies used for interregional commodity flow; (:math:`{T}^x \subset T`). See Note 1 below on capacity and cost application for `tech_exchange`" + ":math:`\text{T}^e`",":code:`tech_existing`","string","technologies constructed in an existing (past) vintage; (:math:`{T}^e \subset T`)." + ":math:`\text{T}^f`",":code:`tech_flex`","string","technologies producing excess commodity flows; (:math:`{T}^f \subset T`)" + "",":code:`tech_group_names`","string","named groups for use in group constraints" + "",":code:`tech_group_members`","(tech_group_names, tech)","Each technology belonging to each group defined above" + ":math:`\text{T}^p`",":code:`tech_production`","string","techs producing intermediate commodities" + ":math:`\text{T}^{ur}`",":code:`tech_upramping`","string","electric generators with a ramp up hourly rate limit; (:math:`{T}^{ur} \subset T`)" + ":math:`\text{T}^{dr}`",":code:`tech_downramping`","string","electric generators with a ramp down hourly rate limit; (:math:`{T}^{dr} \subset T`)" + ":math:`\text{T}^{res}`",":code:`tech_reserve`","string","electric generators contributing to the reserve margin requirement; (:math:`{T}^res \subset T`)" + ":math:`\text{T}^{ret}`",":code:`tech_retirement`","string","technologies allowed to retire before end of life; (:math:`{T}^{ret} \subset (T - T^{u})`)" + ":math:`\text{T}^s`",":code:`tech_storage`","string","all storage technologies; (:math:`{T}^s \subset T`)" + ":math:`\text{T}^{ss}`",":code:`tech_seasonal_storage`","string","seasonal storage technologies; (:math:`{T}^{ss} \subset T^s`)" + +Note 1: Temoa sets Capacity for Exchange Technologies to be equal in both directions on the link automatically. +Costs are apportioned as follows: If both directions of the link have a cost parameter, costs are accrued to +each region region directly based on flow *to* that region. If only 1 element of the link holds a populated cost value, +then that cost divided between the 2 regions automatically based on use, where each region is "billed" according +to use as a receiver. + +Temoa uses two different set notation styles, one for code representation and +one that utilizes standard algebraic notation. For brevity, the mathematical +representation uses capital letters to denote sets, and lower case letters to +represent items within sets. For example, :math:`T` represents the set of all +technologies and :math:`t` represents an item within :math:`T`. + +The code representation is more verbose than the algebraic version, using full +words. This documentation presents them in an italicized font. The same +example of all technologies is represented in the code as :code:`tech_all`. +:ref:`Table 1 ` lists all of the Temoa sets, with both sets of notation. + +There are four basic set "groups" within Temoa: periods, sub-annual "time slices", +technologies, and energy commodities. The technology-related sets contain all the +possible energy technologies that the model may build and the commodities sets +contain all the input and output forms of energy that technologies consume and +produce. The period and time slice sets merit a slightly longer discussion. + +Temoa's conceptual model of *time* is broken up into three levels, and energy supply +and demand is balanced at each of these levels: + + * **Periods** - consecutive blocks of years, marked by the first year in the + period. For example, a two-period model might consist of :math:`\text{P}^f = + \{2010, 2015, 2025\}`, representing the two periods of years from beginning 2010 + through 2014 end, and from beginning 2015 through 2024 end. Note the that last period element + \(2025\) does not represent a new time period, but rather defines the end of the second time + period and therefore the planning horizon. + + * **Seasonal** - Each year may have multiple seasons. In a conventional time-sliced + model, the seasons may typically represent the four seasons: winter, spring summer, + and fall. However, the seasonal slices can represent any amount of time at the + sub-period scale. For example, in a database with representative days, the seasonal + slices can be used as generic containers to represent blocks of days. The type of + seasonal representation in use should be defined in the config file. + + * **Daily** - Within a season, a given day can be further subdivided into different + time segments. Less detailed databases may include larger blocks of time, such as morning, + afternoon, and night. In a database with representative days, each daily segment can + be used to represent every hour of the day. + + +There are two specifiable period sets: :code:`time_exist` (:math:`\text{P}^e`) +and :code:`time_future` (:math:`\text{P}^f`). The :code:`time_exist` set +contains periods before :code:`time_future`. Its primary purpose is to specify +the vintages for capacity that exist prior to the model optimization. +The :code:`time_future` set contains the future periods that the model will +optimize. As this set must contain only integers, Temoa interprets the elements +to be the boundaries of each period of interest. Thus, this is an ordered set +and Temoa uses its elements to automatically calculate the length of each +optimization period; modelers may exploit this to create variable period lengths +within a given input database. Temoa "names" each optimization period by the first +year, and makes them easily accessible via the :code:`time_optimize` set. This final +"period" set is not user-specifiable, but is an exact duplicate of +:code:`time_future`, less the largest element. In the above example, since +:math:`\text{P}^f = \{2010, 2015, 2025\}`, :code:`time_optimize` does not +contain 2025: :math:`\text{P}^o =\{2010, 2015\}`. + +One final note on periods: rather than optimizing each year within a period +individually, Temoa makes the simplifying assumption that each time period contains +:math:`n` copies of a single, representative year. Temoa optimizes capacity +and activity for just this characteristic year within each time period, assuming +the results for different years in the same time period are identical. The Temoa +objective function, however, accounts for the total cost across all years in all +model time periods. Figure 3.3 gives a graphical explanation of the annual +delineation. + +.. _FigureObjectiveComparison: + +.. figure:: images/ObjectiveUsageVsCostComparison.png + :align: center + :width: 100% + :alt: Energy use same each year; time-value of annual costs reduced each year + :figclass: align-center + :figwidth: 60% + + The left graph is of energy, while the right graph is of the annual costs. + The energy used in a period by a process is the same for all + years (with exception for those processes that cease their useful life + mid-period). However, even though the costs incurred will be the same, the + time-value of money changes due to the discount-rate. As the fixed costs of + a process are tied to the length of its useful life, those processes that do + not fall on a period boundary require unique time-value multipliers in the + objective function. + +As noted above, Temoa allows the modeler to subdivide each year into a set of time +slices, comprised of a season and a time of day. Unlike :code:`time_future`, there +is no restriction on what labels the modeler may assign to the :code:`time_season` +and :code:`time_of_day` set elements. + + +A Word on Index Ordering +^^^^^^^^^^^^^^^^^^^^^^^^ + +The ordering of the indices is consistent throughout the model to promote an +intuitive "left-to-right" description of each parameter, variable, and +constraint set. For example, Temoa's output commodity flow variable +:math:`FO_{r,p,s,d,i,t,v,o}` may be described as "in region (:math:`r`), +in period (:math:`p`) during season (:math:`s`) at time of day (:math:`d`), +the flow of input commodity (:math:`i`) to technology (:math:`t`) of vintage +(:math:`v`) generates an output commodity flow (:math:`o`) of +:math:`FO_{r,p,s,d,i,t,v,o}`." For any indexed parameter or variable within +Temoa, our intent is to enable a mental model of a simple left-to-right, arrow-box-arrow +mnemonic to describe the "input :math:`\rightarrow` process +:math:`\rightarrow` output" flow of energy. And while not all variables, parameters, +or constraints have 8 indices, the 8-index order mentioned here (r, p, s, d, i, t, v, o) +is the canonical ordering. If you note any case where, for example, d comes before s, +that is an oversight. In general, if there is an index ordering that does not follow +this rubric, we view that as a bug. + + +Deviations from Standard Mathematical Notation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Temoa deviates from standard mathematical notation and set understanding in two +ways. The first is that Temoa places a restriction on the *time* set elements. +Specifically, while most optimization programs treat set elements as arbitrary +labels, Temoa assumes that all elements of the :code:`time_existing` and +:code:`time_future` sets are integers. Further, these sets are assumed to be +ordered, such that the minimum element is "naught". For example, if +:math:`\text{P}^f = \{2015, 2020, 2030\}`, then :math:`P_0 = 2015`. In +other words, the capital :math:`\text{P}` with the naught subscript indicates +the first element in the :code:`time_future` set. We will explain the reason +for this notation shortly. + +The second set of deviations revolves around the use of the Theta superset +(:math:`\Theta`). The Temoa code makes heavy use of sparse sets, for both +correctness and efficient use of computational resources. For brevity, and +to avoid discussion of implementation details, we do not enumerate their +logical creation here. Instead, we rely on the readers general understanding of +the context. For example, in the sparse creation of the constraints of the +Demand constraint class (explained in :ref:`NetworkConstraints` and +:ref:`constraint-anatomy`), we state simply that the constraint is instantiated +"for all the :math:`\{p, s, d, dem\}` tuples in +:math:`\Theta_{\text{demand}}`". This means that the constraint is only defined +for the exact indices for which the modeler specified end-use demands via the +Demand parameter in the input data file. + +Summations also occur in a sparse manner. For example, let's take another look at +the :code:`Capacity` :eq:`Capacity` Constraint: + +.. math:: + + \left ( + \text{CFP}_{r, s, d, t, v} + \cdot \text{C2A}_{r, t} + \cdot \text{SEG}_{s, d} + \right ) + \cdot \textbf{CAP}_{r, t, v} + = + \sum_{I, O} \textbf{FO}_{r, p, s, d,i, t, v, o} + + + \sum_{I, O} \textbf{CUR}_{r, p, s, d, i, t, v, o} + + \\ + \forall \{p, s, d, t, v\} \in \Theta_{\text{Capacity}} + +It defines the Capacity variable for every valid combination of :math:`\{p, v\}`, +and includes the sum over all inputs and outputs of the FlowOut variable. A +naive implementation of this equation might include nonsensical items in each +summation, such as an input of vehicle miles traveled to an oil refinery or an +output of sunlight from nuclear generating capacity. However, in this context, +summing over the inputs and outputs (:math:`i` and :math:`o`) implicitly +includes only the valid combinations of :math:`\{p, s, d, i, t, v, o\}`. + + +Parameters +---------- + +.. _table_parameter: + +.. csv-table:: List of Temoa parameters with which a modeler might interact. + The asterisked (\*) parameters specified at the end of the table + are automatically derived by the model and are not user-specifiable. + :header: "Parameter","Temoa Name","Domain","Short Description" + :widths: 14, 27, 10, 49 + + ":math:`\text{CC}_{r,p,t,v}`","capacity_credit",":math:`\mathbb{I}`","Process-specific capacity credit" + ":math:`\text{CFT}_{r,s,d,t}`","capacity_factor_tech",":math:`\mathbb{I}`","Technology-specific capacity factor" + ":math:`\text{CFP}_{r,s,d,t,v}`","capacity_factor_process",":math:`\mathbb{I}`","Process-specific capacity factor" + ":math:`\text{C2A}_{r,t,v}`","capacity_to_activity",":math:`\mathbb{R}^+_0`","Converts from capacity to activity units" + ":math:`\text{CF}_{r,p,t,v}`","cost_fixed",":math:`\mathbb{R}`","Fixed operations \& maintenance cost" + ":math:`\text{CI}_{r,t,v}`","cost_invest",":math:`\mathbb{R}`","Tech-specific investment cost" + ":math:`\text{CV}_{r,p,t,v}`","cost_variable",":math:`\mathbb{R}`","Variable operations \& maintenance cost" + ":math:`\text{CON}_{r,i,t,v}`","construction_input",":math:`\mathbb{R}`","Commodities consumed by creation of process capacity" + ":math:`\text{DEM}_{r,p,c}`","demand",":math:`\mathbb{R}^+_0`","End-use demands, by period" + ":math:`\text{DDD}_{p,s,d}`","demand_default_distribution",":math:`\mathbb{I}`","Default demand distribution (currently not supported)" + ":math:`\text{DSD}_{r,p,s,d,c}`","demand_specific_distribution",":math:`\mathbb{I}`","Demand-specific distribution" + ":math:`\text{EFF}_{r,i,t,v,o}`","efficiency",":math:`\mathbb{R}^+_0`","Tech- and commodity-specific efficiency" + ":math:`\text{EAC}_{r,i,t,v,o,e}`","emission_activity",":math:`\mathbb{R}`","Tech-specific emissions rate" + ":math:`\text{EE}_{r,t,v,e}`","emission_embodied",":math:`\mathbb{R}`","Emissions associated with the creation of capacity" + ":math:`\text{EEOL}_{r,t,v,e}`","emission_end_of_life",":math:`\mathbb{R}`","Emissions associated with the retirement/end of life of capacity" + ":math:`\text{EOLO}_{r,t,v,o}`","end_of_life_output",":math:`\mathbb{R}`","Commodities produced by retirement/end of life of capacity" + ":math:`\text{ECAP}_{r,t,v}`","existing_capacity",":math:`\mathbb{R}^+_0`","Pre-existing capacity" + ":math:`\text{GDR}`","global_discount_rate",":math:`\mathbb{R}`","Global rate used to calculate present cost" + ":math:`\text{LTP}_{r,t,v}`","lifetime_process",":math:`\mathbb{N}`","Tech- and vintage-specific lifetime (default=lifetime_tech)" + ":math:`\text{LTT}_{r,t}`","lifetime_tech",":math:`\mathbb{N}`","Tech-specific lifetime (default=40 years)" + ":math:`\text{LSC}_{r,p,t,v}`","lifetime_survival_curve",":math:`\mathbb{R}^+_0`","Surviving fraction of original capacity" + ":math:`\text{LIT}_{r,t,e,t}`","linked_techs","text","Dummy techs used to convert CO2 emissions to physical commodity" + ":math:`\text{LLP}_{r,t,v}`","loan_lifetime_process",":math:`\mathbb{N}`","Process-specific loan term (default=lifetime_process)" + ":math:`\text{LR}_{r,t,v}`","loan_rate",":math:`\mathbb{R}`","Process-specific interest rate on investment cost" + ":math:`\text{LE}_{r,p,e}`","limit_emission",":math:`\mathbb{R}^+_0`","Limit emissions by region and period" + ":math:`\text{LA}_{r,p,t}`","limit_activity",":math:`\mathbb{R}^+_0`","Limit tech-specific activity by region and period" + ":math:`\text{LC}_{r,p,t}`","limit_capacity",":math:`\mathbb{R}^+_0`","Limit tech-specific capacity by period" + ":math:`\text{LR}_{r,t}`","limit_resource",":math:`\mathbb{R}^+_0`","Limit resource production by tech across time periods" + ":math:`\text{LSF}_{r,p,s,d,t,v}`","limit_storage_level_fraction",":math:`\mathbb{R}^+_0`","Limit storage level in any time slice" + ":math:`\text{MDY}`","myopic_discounting_year",":math:`\mathbb{N}`","Objective function NPV year when running myopically" + ":math:`\text{PRM}_{r}`","planning_reserve_margin",":math:`\mathbb{I}`","Margin used to ensure sufficient generating capacity" + ":math:`\text{RDH}_{r,t}`","ramp_down_hourly",":math:`\mathbb{R}`","Hourly rate at which generation techs can ramp output down" + ":math:`\text{RUH}_{r,t}`","ramp_up_hourly",":math:`\mathbb{R}`","Hourly rate at which generation techs can ramp output up" + ":math:`\text{SD}_{r,t}`","storage_duration",":math:`\mathbb{N}`","Storage duration per technology, specified in hours" + ":math:`\text{SEG}_{s,d}`","segment_fraction",":math:`\mathbb{I}`","Fraction of year represented by each (s, d) tuple" + ":math:`\text{TIS}_{r,i,t}`","tech_input_split",":math:`\mathbb{I}`","Technology input fuel ratio at time slice level" + ":math:`\text{TISA}_{r,i,t}`","tech_input_split_annual",":math:`\mathbb{I}`","Average annual technology input fuel ratio" + ":math:`\text{TOS}_{r,t,o}`","tech_output_split",":math:`\mathbb{I}`","Technology output fuel ratio at time slice level" + ":math:`\text{TISA}_{r,i,t}`","tech_output_split_annual",":math:`\mathbb{I}`","Average annual technology output fuel ratio" + ":math:`{}^*\text{LA}_{t,v}`","loan_annualize",":math:`\mathbb{R}^+_0`","Loan amortization by tech and vintage; based on :math:`DR_t`" + ":math:`{}^*\text{MPL}_{p,t,v}`","model_process_life",":math:`\mathbb{N}`","Smaller of remaining model horizon or process tech life" + ":math:`{}^*\text{PLF}_{r,p,t,v}`","process_life_frac",":math:`\mathbb{I}`","Fraction of available process capacity by region and period " + ":math:`{}^*\text{LEN}_p`","period_length",":math:`\mathbb{N}`","Number of years in period :math:`p`" + + +.. _influential_efficiency: + +efficiency +^^^^^^^^^^ + +:math:`{EFF}_{r \in R, i \in C_p, t \in T, v \in V, o \in C_c}` + +We present the efficiency (:math:`EFF`) parameter first as it is one of the most +critical model parameters. Beyond defining the conversion efficiency of each +process, Temoa also utilizes the indices to understand the valid input +:math:`\rightarrow` process :math:`\rightarrow` output paths for energy. For +instance, if a modeler does not specify an efficiency for a 2020 vintage coal +power plant, then Temoa will recognize any mention of a 2020 vintage coal power +plant elsewhere as an error. Generally, if a process is not specified in the +efficiency table,\ [#efficiency_table]_ Temoa assumes it is not a valid process +and will provide the user a warning with pointed debugging information. + + +.. _capacity_factor_tech: + +capacity_credit +^^^^^^^^^^^^^^ + +:math:`{CC}_{r \in R, p \in P, t \in T, v \in V}` + +The capacity credit represents the fraction of total installed capacity of +a process that can be relied upon during the time slice in which peak +electricity demand occurs. This parameter is used in the :math:`reserve_margin` +constraint. + +capacity_factor_tech +^^^^^^^^^^^^^^^^^^ + +:math:`{CFT}_{r \in R, s \in S, d \in D, t \in T}` + +Temoa indexes the :code:`capacity_factor_tech` parameter by season, time-of-day, +and technology. + +capacity_factor_process +^^^^^^^^^^^^^^^^^^^^^ + +:math:`{CFP}_{r \in R, s \in S, d \in D, t \in T, v \in V}` + +In addition to :ref:`capacity_factor_tech`, there may be cases where different +vintages of the same technology have different capacity factors. For example, +newer vintages of wind turbines may have higher capacity factors. So, +:code:`capacity_factor_process` allows users to specify the capacity factor by +season, time-of-day, technology, and vintage. + + +capacity_to_activity +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:math:`{C2A}_{r \in R, t \in T}` + +Capacity and Activity are inherently two different units of measure. Capacity +represents the maximum flow of energy per time (:math:`\frac{energy}{time}`), +while Activity is a measure of total energy actually produced. However, there are +times when one needs to compare the two, and this parameter makes those +comparisons more natural. For example, a capacity of 1 GW for one year works +out to an activity of + +.. math:: + + {1 GW} \cdot {8,760 \tfrac{hr}{yr}} \cdot {3,600 \tfrac{sec}{hr}} \cdot + {10^{-6} \tfrac{P}{G}} = {31.536 \tfrac{PJ}{yr}} + +.. centered:: + or + +.. math:: + + {1 GW} \cdot {8,760 \tfrac{hr}{yr}} \cdot {10^{-3} \tfrac{T}{G}} = {8.75 TWh} + +When comparing one capacity to another, the comparison is easy, unit wise. +However, when one *needs* to compare capacity and activity, how does one +reconcile the units? One way to think about the utility of this parameter is in +the context of the question: "How much activity would this capacity create, if +used 100% of the time?" + + +cost_fixed +^^^^^^^^^ + +:math:`{CF}_{r \in R, p \in P, t \in T, v \in V}` + +The :code:`cost_fixed` parameter specifies the fixed cost associated with any +process. Fixed costs are those that must be paid, regardless of how much the +process is utilized. For instance, if the model decides to build a nuclear +power plant, even if it decides not utilize the plant, the model must pay the +fixed costs. These costs are in addition to the capital cost, so once the +capital is paid off, these costs are still incurred every year the process +exists. + +Temoa's default objective function assumes the modeler has specified this +parameter in units of currency per unit capacity (:math:`\tfrac{Dollars}{Unit +Cap}`). + + +cost_invest +^^^^^^^^^^ + +:math:`{CI}_{r \in R, t \in T, v \in P}` + +The :code:`cost_invest` parameter specifies the process-specific investment cost. +Unlike the :code:`cost_fixed` and :code:`cost_variable` parameters, +:code:`cost_invest` only applies to vintages of technologies within the model +optimization horizon (:math:`\text{P}^o`). Like :code:`cost_fixed`, +:code:`cost_invest` is specified in units of cost per unit of capacity and is +only used in the default objective function (:math:`\tfrac{Dollars}{Unit Cap}`). + + +cost_variable +^^^^^^^^^^^^ + +:math:`{CV}_{r \in R, p \in P,t \in T,v \in V}` + +The :code:`cost_variable` parameter represents the cost of a process-specific unit +of activity. Thus the incurred variable costs are proportional to the activity +of the process. + + +construction_input +^^^^^^^^^^^^^^^^^ + +:math:`{CON}_{r \in R, i \in C^p,t \in T \setminus T^u,v \in V}` + +The :code:`construction_input` parameter allows the modeller to attach commodity +input flows to the production of new capacity, in units of activity per unit +capacity. Assumes that capacity is produced evenly over years in its vintage +period. + + +.. _demand: + +demand +^^^^^^ + +:math:`{DEM}_{r \in R, p \in P, c \in C^d}` + +The :code:`demand` parameter allows the modeler to define the total end-use +demand levels for all periods. In combination with the :code:`efficiency` +parameter, this parameter is the most important because without it, the rest of +model has no incentive to build anything. This parameter specifies the end-use +demands that appear at the far right edge of the system diagram. + +To specify the distribution of demand, look to the +:code:`demand_default_distribution` (DDD) and :code:`demand_specific_distribution` +(DSD) parameters. + +As a historical note, this parameter was at one time also indexed by season and +time of day, allowing modelers to specify exact demands for every time slice. +However, while extremely flexible, this proved too tedious to maintain for any +data set of appreciable size. Thus, we implemented the DDD and DSD parameters. + + +.. _DDD: + +demand_default_distribution +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:math:`{DDD}_{s \in S, d \in D}` + +**Note**: The Demand Specific Distribution is currently not supported in +the project. Modelers should use the DSD or rely on a "flat" distribution default +from the time_segment_fraction. + +By default, Temoa assumes that end-use demands (:ref:`Demand`) are evenly +distributed throughout a year. In other words, the Demand will be apportioned +by the :code:`segment_fraction` parameter via: + +.. math:: + + \text{EndUseDemand}_{s, d, c} = {segment_fraction}_{s, d} \cdot {Demand}_{p, c} + +Temoa enables this default action by automatically setting DDD equivalent to +:code:`segment_fraction` for all seasons and times of day. If a modeler would like a +different default demand distribution, the indices and values of the DDD +parameter must be specified. Like the :ref:`segment_fraction` parameter, the sum of +DDD must be 1. + + +demand_specific_distribution +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:math:`{DSD}_{r \in R, s \in S, d \in D, c \in C^d}` + +If there is an end-use demand that varies over the course of a day or across +seasons -- for example, heating or cooling in the summer or winter -- the +modeler may specify the fraction of annual demand occurring in each time slice. +Like :ref:`segment_fraction` and :ref:`DDD`, the sum of DSD for each :math:`c` must be 1. +If the modeler does not define DSD for a season, time of day, and demand +commodity, Temoa automatically populates this parameter according to DDD. +It is this parameter that is actually multiplied by the :code:`Demand` parameter +in the Demand constraint. + + +emission_activity +^^^^^^^^^^^^^^^^ + +:math:`{EAC}_{e \in C_e,\{r,i,t,v,o\} \in \Theta_{\text{efficiency}}}` + +Temoa currently has two methods for enabling a process to produce an output: the +:code:`efficiency` parameter, and the :code:`emission_activity` parameter. Where +the :code:`efficiency` parameter defines the amount of output energy a process +produces per unit of input, the :code:`emission_activity` parameter allows for +secondary outputs. As the name suggests, this parameter was originally intended +to account for emissions per unit activity, but it more accurately describes +*parallel* activity. It is restricted to emissions accounting (by the +:math:`e \in C^e` set restriction). + + +emission_embodied +^^^^^^^^^^^^^^^^ + +:math:`{EE}_{r \in R,t \in T \setminus T^u, v \in V,e \in C_e}` + +Like the emission_activity parameter, but attaches emission outputs to the creation +of capacity instead of activity flows. Assumes that capacity is produced evenly +over each year in the deployment vintage. + + +emission_end_of_life +^^^^^^^^^^^^^^^^^ + +:math:`{EEOL}_{r \in R,t \in T \setminus T^u, v \in V,e \in C_e}` + +Like emission_embodied, but attaches emissions to the retirement/end of life of +capacity rather than production of capacity. Assumes that retirement or end of +life occur evenly over years in that period. + + +end_of_life_output +^^^^^^^^^^^^^^^ + +:math:`{EOLO}_{r \in R,t \in T \setminus T^u, v \in V,o \in C_p}` + +Like construction_input, but attaches flows to the retirement/end of life of +capacity rather than production of capacity. Assumes that retirement or end of +life occur evenly over years in that period. + + +.. limit_emission +.. ^^^^^^^^^^^^^ + +.. :math:`{LE}_{r \in R, p \in P, e \in C^e}` + +.. The :code:`emission_limit` parameter ensures that Temoa finds a solution that +.. fits within the modeler-specified limit of emission :math:`e` in time period +.. :math:`p`. + + +existing_capacity +^^^^^^^^^^^^^^^^ + +:math:`{ECAP}_{r \in R, t \in T, v \in \text{P}^e}` + +The :code:`existing_capacity` parameter defines the capacity installed prior to the +beginning of :code:`time_optimize`. Note that processes with existing capacity +require all of the engineering-economic characteristics of a standard process, +with the exception of an investment cost. + +retired_capacity +^^^^^^^^^^^^^^^^ + +:math:`{ECAP}_{r \in R, t \in T, v \in \text{P}^e}` + +The :code:`existing_capacity` parameter defines the capacity installed prior to the +beginning of :code:`time_optimize`. Note that processes with existing capacity +require all of the engineering-economic characteristics of a standard process, +with the exception of an investment cost. + +.. _GDR: + +global_discount_rate +^^^^^^^^^^^^^^^^^^ + +:math:`{GDR}` + +The :code:`GDR` parameter represents the global discount rate used to convert +cash flows in future model time periods into a present value. The future value +(FV) of a sum of currency is related to the net present value (NPV) via the +formula: + +.. math:: + + \text{FV} = \text{NPV} \cdot {(1 + GDR)^n} + +where :math:`n` is in years. This parameter is used to calculate all discounted +costs, which are the basis of the objective function. Costs are discounted to the +first future time period in the model by default. If running a Myopic run, the +discount base year can be set in the metadata table. This is the :code:`myopic_base_year`. + +The output in the :code:`output_cost` table shows both discounted and non-discounted (raw) +values for all model costs. Of note, all loan costs are displayed as an annuity cost in +the vintage year, not as a string of payments. + +The Global Discount Rate is entered in the metadata_real table in the database. + +growth_rate_max +^^^^^^^^^^^^^ + +:math:`{GRM}_{r \in R, t \in T}` + +The :code:`GRM` parameter defines the maximum annual rate at which the capacity of +a given technology can grow. Note that the growth rate is not defined by vintage, +but rather across all vintages of a given technology. + + +growth_rate_seed +^^^^^^^^^^^^^^ + +:math:`{GRS}_{r \in R, t \in T}` + +The :code:`GRS` parameter defines the maximum capacity of a given technology when +first installed in a given time period. The growth rate is applied to this initial +capacity seed in subsequent time periods. + + +loan_lifetime_process +^^^^^^^^^^^^^^^^^^^ + +:math:`{LLP}_{r \in R, t \in T, v \in P}` + +**Note**: :code:`LifetimeLoanProcess` is currently not supported in the database. +Modelers should use the :code:`loan_lifetime_tech` below. + +Temoa gives the modeler the ability to separate the loan lifetime from the +useful life of a process. This parameter specifies the loan term associated +with capital investment in a process, in years. If not specified, the model +assigns the technology lifetime to the loan period in :code:`temoa/components/technology.py`. + + +loan_lifetime_tech +^^^^^^^^^^^^^^^^ + +:math:`{LLT}_{r \in R, t \in T}` + +Same as the :code:`loan_lifetime_process` but without the vintage index. If all +vintages of a given technology are assumed to have the same loan term, then +:code:`loan_lifetime_tech` can be defined instead of :code:`loan_lifetime_process`. + + +lifetime_process +^^^^^^^^^^^^^^^ + +:math:`{LTP}_{r \in R, t \in T, v \in P}` + +This parameter specifies the total useful life of a given process in years. + + +lifetime_tech +^^^^^^^^^^^^ + +:math:`{LTT}_{r \in R, t \in T}` + +Similar to lifetime_process, this parameter specifies the total useful life of a +given technology in years. If all vintages of a given technology have the same +lifetime, then :code:`LifeTimeTech` can be used instead of :code:`LifeTimeProcess`. + + +linked_techs +^^^^^^^^^^^ + +:math:`{LIT}_{r \in R, t \in T, e \in C^e, t \in T}` + +In power-to-gas pathways, :math:`CO2` is an input to some processes, including +synthetic natural gas production and liquid fuel production via Fischer-Tropsch. +Within the model, :math:`CO2` must be converted from an emissions commodity to a +physical commodity that can be included in the :code:`efficiency` table. The +:code:`linked_techs` parameter specifies the dummy technology used to convert an +emissions commodity to a physical commodity. Note that the first :code:`t` +represents the primary upstream technology linked to the dummy linked technology, +which is represented by the second :code:`t` index. + + +loan_rate +^^^^^^^^ + +:math:`{LR}_{r \in r, t \in T, v \in V}` + +The interest rate used for loans supporting investment costs. The default +loan rate is accessible in the metadata_real table in the database. + + +.. _ParamMaxCapacity: + + +max_activity +^^^^^^^^^^^ + +:math:`{MAA}_{r \in R, p \in P, t \in T}` + +The :code:`max_activity` parameter is used to constrain the total activity (i.e., +energy production) from a given technology in each model time period. Note that the +total activity is constrained across all vintages of a technology. This parameter +is used in the :code:`max_activity_constraint`. + + +max_capacity +^^^^^^^^^^^ + +:math:`{MAC}_{r \in R, p \in P, t \in T}` + +The :code:`max_capacity` parameter represents an upper bound on the total installed +capacity of a given technology in each model time period. Note that the total +capacity is constrained across all vintages of a technology. This parameter is +used in the :code:`max_capacity_constraint`. + + +max_capacity_sum +^^^^^^^^^^^^^^ + +:math:`{MCS}_{t \in T}` + +Similar to the :code:`max_capacity` parameter, but represents an upper bound on +the total installed capacity across all model time periods. In addition, +this parameter specifies the upper bound on a group of technologies specified +in the :code:`tech_capacity_max` subset. This parameter is used in the +:code:`MaxCapacitySet_constraint`. + + +max_resource +^^^^^^^^^^^ + +:math:`{MAR}_{r \in R, t \in T}` + +**Note**: The max_resource parameter/constraint is currently not supported in the model. + +The :code:`max_resource` parameter represents an upper bound on the cumulative +amount of commodity that can be produced by region and technology over the model time +horizon. This parameter is used in :code:`max_resource_constraint`. Note that +this parameter differs from :code:`resource_bound`, which is also indexed by +model time period. + + +min_activity +^^^^^^^^^^^ + +:math:`{MIA}_{r \in R, p \in P, t \in T}` + +The :code:`min_activity` parameter represents a lower bound on the total activity (i.e., +energy production) of a given technology in each model time period. Note that the +total activity is constrained across all vintages of a technology. This parameter +is used in the :code:`min_activity_constraint`. + + +min_capacity +^^^^^^^^^^^ + +:math:`{MIC}_{r \in R, p \in P,t \in T}` + +The :code:`min_capacity` parameter represents a lower bound on the total installed +capacity of a given technology in each model time period. Note that the total +capacity is constrained across all vintages of a technology. This parameter is +used in the :code:`min_capacity_constraint`. + + +min_capacity_sum +^^^^^^^^^^^^^^ + +:math:`{MCS}_{t \in T}` + +The :code:`min_capacity_sum` parameter represents the minimum cumulative +capacity associated with technologies belonging to :code:`tech_group`. +This parameter is used in the :code:`min_activityGroup_constraint`. + + +min_gen_group_target +^^^^^^^^^^^^^^^^^ + +:math:`{MGT}_{r \in R}` + +The :code:`min_gen_group_target` parameter is similar to :code:`min_activity`, but +represents a minimum activity limit for a user-defined technology group +(:code:`tech_groups`) rather than a single technology. This parameter is used +in the :code:`min_activityGroup_constraint`. + + +min_gen_group_weight +^^^^^^^^^^^^^^^^^ + +:math:`{MGW}_{r \in R, t \in T}` + +The :code:`min_gen_group_weight` parameter represents a weight that is applied +to each technology within each :code:`tech_group`, which determines the +technology-specific activity shares that can count towards meeting the +:code:`min_activityGroup_constraint`. + + +myopic_base_year +^^^^^^^^^^^^^^ + +:math:`MBY` + +Temoa is typically run in "perfect foresight" mode, where all decision variables +in all time periods are solved simultaneously. However, it is also possible to +solve the model myopically, whereby the model solves a subset of time periods +in sequence. The :code:`myopic_base_year` parameter specifies the base year to which +all future costs are discounted. This parameter is located in the :code:`metadata` +table in the database. + + +planning_reserve_margin +^^^^^^^^^^^^^^^^^^^^^ + +:math:`{PRM}_{r \in R}` + +The :code:`planning_reserve_margin` parameter specifies that capacity reserve margin +in the electric sector by region. The capacity reserve margin represents the +installed generating capacity - expressed as a share of peak load - that must be +available to meet contingencies. Note that since electricity demand is often +endogeous in Temoa databases, we calculate electricity production by time slice +to estimate the peak electricity demand. This parameter is used in +:code:`ReserveMargin_constraint`. + + +ramp_down +^^^^^^^^ + +:math:`{RMD}_{r \in R, t \in T}` + +To account for the limited ramping capability of some thermal generators, a +ramp down rate can be specified via the :code:`ramp_down` parameter. The specified +value represents the fraction of installed capacity that can be ramped down when moving +from one time slice to the next. There is an equivalent :code:`ramp_up` parameter, to +specify ramping limits in the upward direction. This parameter is used in the +:code:`ramp_downDay_constraint` and `ramp_downSeason_constraint`. The former constrains +the downward ramp rate between time-of-day slices, and the latter constrains the downward +ramp rate between the last time-of-day slice in a given season and the first time-of-day +slice in the next season. + + +ramp_up +^^^^^^ + +:math:`{RMU}_{r \in R, t \in T}` + +To account for the limited ramping capability of some thermal generators, a +ramp up rate can be specified via the :code:`ramp_up` parameter. The specified +value represents the fraction of installed capacity that can be ramped up when moving +from one time slice to the next. There is an equivalent :code:`ramp_down` parameter, to +specify ramping limits in the downward direction. This parameter is used in the +:code:`ramp_upDay_constraint` and `ramp_upSeason_constraint`. The former constrains +the upward ramp rate between time-of-day slices, and the latter constrains the upward +ramp rate between the last time-of-day slice in a given season and the first time-of-day +slice in the next season. + + +resource_bound +^^^^^^^^^^^^^ + +:math:`{RSC}_{r \in R, p \in P, c \in C_p}` + +This parameter allows the modeler to specify commodity production limits per period. +Note that a constraint in one period does not relate to any other periods. For +instance, if the modeler specifies a limit in period 1 and does not specify a +limit in period 2, then the model may use as much of that resource as it would +like in period 2. This parameter is used in :code:`ResourceExtraction_constraint`. +Note that the :code:`max_resource` parameter is similar, but constrains total +cumulative resource consumption across all model time periods. + + +.. _segment_fraction: + +segment_fraction +^^^^^^^ + +:math:`{SEG}_{s \in S,d \in D}` + +The :code:`segment_fraction` parameter specifies the fraction of the year represented by +each combination of season and time of day. The sum of all combinations within +:code:`segment_fraction` must be 1, representing 100% of a year. + + +storage_duration +^^^^^^^^^^^^^^^ + +:math:`{SD}_{r \in R, t \in T^{S}}` + +The :code:`storage_duration` parameter represents the number of hours over which +storage can discharge if it starts at full charge and produces maximum output +until empty. The parameter value defaults to 4 hours if not specified by the user. + + +storage_init +^^^^^^^^^^^ + +:math:`{SI}_{r \in R, t \in T^{S}, v \in P}` + +The :code:`storage_init` parameter determines the initial charge level associated +with each storage technology. The value should be expressed as a fraction between +0 and 1. + +Note 1: that this is an optional parameter and should only be used if the +user wishes to set the initial charge rather than allowing the model to optimize it. + +Note 2: This initialization is currently *not supported*. Values in the storage_init +table will be ignored and a log warning will be generated. + + +tech_input_split +^^^^^^^^^^^^^^^^^^^^^^^ + +:math:`{TIS}_{r \in R, p \in P, i \in C_p, t \in T}` + +Some technologies have a single output but have multiple input fuels. The +:code:`tech_input_split` parameter fixes the shares of commodity input to a +specific technology in a given period. Note that this fixed share is maintained +across all model time slices. This parameter is used in +:code:`TechInputSplit_constraint`. + + +tech_input_split_average +^^^^^^^^^^^^^^^^^^^^^ + +:math:`{TISA}_{r \in R, p \in P, i \in C_p, t \in T}` + +The :code:`tech_input_split_average` is similar to :code:`tech_input_split`, as +they both fix input commodity shares to technologies with multiple inputs. +However, :code:`tech_input_split_average` only fixes the average shares at the +annual level, allowing the shares at the time slice level to vary. This +parameter is used in :code:`TechInputSplitAverage_constraint`. + + +tech_output_split +^^^^^^^^^^^^^^^ + +:math:`{TOS}_{t \in T, o \in C_c}` + +Some technologies have a single input fuel but have multiple outputs. The +:code:`tech_output_split` parameter fixes the shares of commodity input to a +specific technology in a given period. Note that this fixed share is maintained +across all model time slices. This parameter is used in +:code:`TechOutputSplit_constraint`. + + +\*loan_annualize +^^^^^^^^^^^^^^^ + +:math:`{LA}_{r \in R, t \in T, v \in P}` + +This is a model-calculated parameter based on the process-specific loan length +(its indices are the same as the :code:`LifetimeLoan` parameter), and +process-specific discount rate (the :code:`DiscountRate` parameter). It is +calculated via the formula: + +.. math:: + + LA_{t,v} = \frac{DR_{r,t,v}}{1 - (1 + DR_{r,t,v})^{{}^- LLN_{r,t,v}}} + + \forall \{t, v\} \in \Theta_\text{cost_invest} + + +model_process_life +^^^^^^^^^^^^^^^^ + +:math:`{MPL}_{r \in R, p \in P, t \in T, v \in P}` + +The :code:`model_process_life` parameter is internally-derived by the model calcuated in +:code:`ParamModelProcessLife_rule` and which makes use of the :code:`lifetime_process` +parameter. For a given technology vintage in a given model time period, it returns the +lesser of the period length and the remaining process lifetime. This parameter is used +to sum the annual :code:`fixed_costs` and :code:`variable_costs` across all years within +a given time period. + + +\*period_length +^^^^^^^^^^^^^^ + +:math:`{LEN}_{p \in P}` + +Given that the modeler may specify arbitrary time period boundaries, this +parameter specifies the number of years contained in each period. The final year +is the largest element in :code:`time_future` which is specifically not included +in the list of periods in :code:`time_optimize` (:math:`\text{P}^o`). The length +calculation for each period then exploits the fact that the ``time`` sets are +ordered: + +.. math:: + + \text{LET boundaries} & = \text{sorted}(\text{P}^f) \\ + \text{LET I(p)} & = \text{index of p in boundaries} \\ + & \therefore \\ + {LEN}_p & = \text{boundaries}[ I(p) + 1 ] - p + + \forall p \in P + +The first line creates a sorted array of the period boundaries, called +*boundaries*. The second line defines a function `I` that finds the index of +period :math:`p` in boundaries. The third line then defines the length of period +:math:`p` to be the number of years between period :math:`p` and the next +period. For example, if :math:`\text{P}^f = \{2015, 2020, 2030, 2045\}`, +then *boundaries* would be :code:`[2015, 2020, 2030, 2045]`. For 2020, I(2020) +would return 2. Similarly, boundaries[ 3 ] = 2030. Then, + +.. math:: + {LEN}_{2020} & = \text{boundaries}[I(2020) + 1] - (2020) \\ + & = \text{boundaries} [2 + 1] - 2020 \\ + & = \text{boundaries} [3] - 2020 \\ + & = 2030 - 2020 \\ + & = 10 + +Note that LEN is only defined for elements in :math:`\text{P}^o`, and is +specifically not defined for the final element in :math:`\text{P}^f`. + + +\*process_life_frac +^^^^^^^^^^^^^^^^^ + +:math:`{PLF}_{r \in R, p \in P,t \in T,v \in P}` + +The modeler may specify a useful lifetime of a process such that the process +will be decommissioned part way through a period. Rather than attempt to +delineate each year within that final period, Temoa averages the total output +of the process over the entire period but limits the available capacity and +output of the decommissioning process by the ratio of how long through the +period the process is active. This parameter is that ratio, formally defined +as: + +.. math:: + + PLF_{p,t,v} = \frac{v + LTP_{t,v} - p}{LEN_p} + + \\ + \forall \{p,t,v\} & \in \Theta_\text{Activity by PTV} | \\ + v + LTP_{t,v} & \notin P, \\ + v + LTP_{t,v} & \le max(F), \\ + p & = max(P | p < v + LTP_{t,v}) + +Note that this parameter is defined over the same indices as +:code:`cost_variable` -- the active periods for each process :math:`\{p, t, +v\}`. As an example, if a model has :math:`P = \{2010, 2012, +2020, 2030\}`, and a process :math:`\{t, v\} = \{car, 2010\}` has a useful +lifetime of 5 years, then this parameter would include only the first two +activity indices for the process. Namely, :math:`p \in \{2010, 2012\}` as +:math:`\{p, t, v\} \in \{\{2010, car, 2010\}, \{2012, car, +2010\}\}`. The values would be :math:`{TLF}_{2010, car, 2010} = 1`, and +:math:`{TLF}_{2012, car, 2010} = \frac{3}{8}`. + + +Variables +--------- + +.. _table_variable: +.. csv-table:: Temoa's Main Variables + :header: "Variable","Temoa Name","Domain","Short Description" + :widths: 18, 22, 10, 50 + + ":math:`FO_{r,p,s,d,i,t,v,o}`","v_flow_out",":math:`\mathbb{R}^+_0`","Commodity flow by time slice out of a tech based on a given input" + ":math:`FOA_{r,p,s,d,i,t,v,o}`","v_flow_out_annual",":math:`\mathbb{R}^+_0`","Annual commodity flow out of a tech based on a given input" + ":math:`FIS_{r,p,s,d,i,t,v,o}`","v_flow_in",":math:`\mathbb{R}^+_0`","Commodity flow into a storage tech to produce a given output" + ":math:`FLX_{r,p,s,d,i,t,v,o}`","v_flex",":math:`\mathbb{R}^+_0`","The portion of commodity production exceeding demand" + ":math:`FLXA_{r,p,i,t,v,o}`","v_flex_annual",":math:`\mathbb{R}^+_0`","The portion of commodity production from constant production techs exceeding demand" + ":math:`CUR_{r,p,s,d,i,t,v,o}`","v_curtailment",":math:`\mathbb{R}^+_0`","Commodity flow out of a tech that is curtailed" + ":math:`CAP_{r,t,v}`","v_capacity",":math:`\mathbb{R}^+_0`","Required tech capacity to support associated activity" + ":math:`CAPAVL_{r,p,t}`","v_capacity_available_by_period_and_tech",":math:`\mathbb{R}^+_0`","Derived variable representing the capacity of technology :math:`t` available in period :math:`p`" + ":math:`SI_{r,t,v}`","v_storage_init",":math:`\mathbb{R}^+_0`","Initial charge level associated with storage techs" + ":math:`SL_{r,p,s,d,t,v}`","v_storage_level",":math:`\mathbb{R}^+_0`","Charge level each time slice associated with storage techs" + ":math:`SSL_{r,p,s,t,v}`","v_seasonal_storage_level",":math:`\mathbb{R}^+_0`","Base charge level of sequential seasons for seasonal storage" + ":math:`RCAP_{r,p,t,v}`","v_retired_capacity",":math:`\mathbb{R}^+_0`","Capacity retired before end of life" + ":math:`ART_{r,p,t,v}`","v_annual_retirement",":math:`\mathbb{R}^+_0`","Annualised capacity retiring or reaching end of life" + ":math:`NCAP_{r,t,v}`","v_new_capacity",":math:`\mathbb{R}^+_0`","New deployed capacity" + +v_flow_out +^^^^^^^^^ + +:math:`FO_{r,p,s,d,i,t,v,o}` + +The most fundamental variable in the Temoa formulation is the +:code:`v_flow_out` variable. It describes the commodity flow out of a +process in a given time slice. To balance input and output flows in the +:code:`CommodityBalance_constraint`, the commodity flow into a given +process can be calculated as +:math:`\sum_{T, V, O} \textbf{FO}_{p, s, d, c, t, v, o} +/EFF_{c,t,v,o}`. + +v_flow_out_annual +^^^^^^^^^^^^^^^ + +:math:`FOA_{r,p,i,t,v,o}` + +Similar to :code:`v_flow_out`, but used for technologies that are members +of the :code:`tech_annual` set, whose output does not vary across seasons +and times-of-day. Eliminating the :code:`s,d` indices for these technologies +improves computational performance. + + +v_flex +^^^^^^ + +:math:`FLX_{r,p,s,d,i,t,v,o}` + +In some cases, the overproduction of a commodity may be required, such +that supply exceeds the endogenous demand. Refineries represent a +common example, where the share of different refined products are governed +by tech_output_split, but total production is driven by a particular commodity. +For example, gasoline production may be artificially constrained in order to +ensure the appropriate balance for lower demand fuels such as propane or +kerosene. Instead, we allow overproduction, i.e., production exceeding +endogenous demand, for commodities produced by technologies belonging to +the :code:`tech_flex` set. In the example above, adding the refinery to +the :code:`tech_flex` set allows for the overproduction of propane and +kerosene, allowing the model to fulfill the endogenous demand +for gasoline. This flexible technology designation activates a slack +variable (:math:`\textbf{FLX}_{r, p, s, d, i, t, v, c}`)representing +the excess production in the :code:`CommodityBalanceAnnual_constraint`. + + +v_flex_annual +^^^^^^^^^^^^ + +:math:`FLXA_{r,p,i,t,v,o}` + +Similar to :code:`v_flex`, but used for technologies that are members +of the :code:`tech_flex` set, whose output does not vary across seasons +and times-of-day. Eliminating the :code:`s,d` indices for these technologies +improves computational performance. + + +v_curtailment +^^^^^^^^^^^^^ + +:math:`CUR_{r,p,s,d,i,t,v,o}` + +The :code:`v_curtailment` variable is an accounting tool to help calculate +the unused production capacity of technologies annotated in the Technology +database table as curtailable technologies belonging to the +:code:`tech_curtailment` set. +Renewables such as wind and solar are often placed in this set. While we +used to simply formulate the :code:`Capacity` and :code:`CommodityBalance` +constraints as inequalities that implicitly allowed for curtailment, this +simpler approach does not work with renewable targets because the curtailed +portion of the electricity production counts towards the target, and there is +no way to distinguish it from the useful production. Including an explicit +curtailment term addresses the issue. Curtailment in the model is simply +the production activity that is not used in the model and is reported as +such in the output_curtailment table. Note: Outputs presented in the +`output_curtailment` table for curtailment (the table separately includes +flex outputs) are limited by Capacity Factor. Meaning: if a tech has a +capacity of 10 units, and a CF of 0.8 and a usage of 5 units, then the reported +curtailment is 3 units (0.8 x 10 - 5). + + +v_flow_in_storage +^^^^^^^^^^^^^^^ + +:math:`FIS_{r,p,s,d,i,t,v,o}` + +Because the production and consumption associated with storage techs occur +across different time slices, the comodity flow into a storage technologiy +cannot be discerned from :code:`v_flow_out`. Thus an explicit :math:`flow_in` +variable is required for storage. + +v_capacity +^^^^^^^^^^ + +:math:`CAP_{r,t,v}` + +The :code:`v_capacity` variable determines the required capacity of all processes +across the user-defined system. It is indexed for each process (t,v), and Temoa +constrains the capacity variable to be able to meet the total commodity flow out +of that process in all time slices in which it is active :eq:`Capacity`. + +v_capacity_available_by_period_and_tech +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:math:`CAPAVL_{r,p,t}` + +:code:`CapacityAvailableByPeriodAndTech` is a convenience variable that is +not strictly necessary, but used where the individual vintages of a technology +are not warranted (e.g. in calculating the maximum or minimum total capacity +allowed in a given time period). + +v_storage_init +^^^^^^^^^^^^^ + +:math:`SI_{r,t,v}` + +The :code:`v_storage_init` variable determines the initial storage charge level +at the beginning of the first time slice within a given time period. Each vintage +of each technology can have a different optimal initial value. Note that +this value also determines the ending storage charge level at the end of the +last time slice within each model time period. + +v_storage_level +^^^^^^^^^^^^^^ + +:math:`SL_{r,p,s,d,t,v}` + +The :code:`v_storage_level` variable tracks the storage charge level across ordered +time slices and is critical to ensure that storage charge and dispatch is constrained +by the energy available in the storage units. + + + +We explain the equations governing these variables the :ref:`Constraints` +section. + + +.. _constraints: + +Equations +--------- + +There are four main equations that govern the flow of energy through the model +network. The :code:`Demand_Constrant` :eq:`Demand` ensures that the supply meets +demand in every time slice. For each process, the :code:`Capacity_constraint` :eq:`Capacity` +ensures that there is sufficient capacity to meet the optimal commodity flows across all +time slices. Between processes, the :code:`CommodityBalance_constraint` :eq:`CommodityBalance` +ensures that global commodity production across the energy system is sufficient to meet the +endogenous demands for that commodity. Finally, the objective function :eq:`obj_invest` drives +the model to minimize the system-wide cost of energy supply by optimizing the deployment and +utilization of energy technologies across the system. + +One additional point regarding the model formulation. Technologies that +produce constant annual output can be placed in the :code:`tech_annual` set. +While not required, doing so improves computational performance by eliminating the +season and time of day :code:`(s,d)` indices associated with these technologies. +In order to ensure the model functions correctly with these simplified technologies, +slightly different formulations of the capacity and commodity balance constraints +are required. See the :code:`AnnualCommodityBalance_constraint` and +:code:`CapacityAnnual_constraint` :eq:`CapacityAnnual` below for details. + +The rest of this section defines each model constraint, with a rationale for +existence. We use the implementation-specific names for the constraints to +highlight the organization of the functions within the actual code. Note that +the definitions below are pulled directly from the docstrings embedded in +:code:`temoa/components/`. + + +.. _DecisionVariables: + +Constraints Defining Derived Decision Variables +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +These first four constraints define derived variables that are used within +the model. The :code:`Capacity_constraint` and :code:`CapacityAnnual_constraint` +are particularly important because they define the relationship between installed +capacity and allowable commodity flow. + +.. autofunction:: temoa.components.capacity.capacity_constraint + +.. autofunction:: temoa.components.capacity.capacity_annual_constraint + +.. autofunction:: temoa.components.capacity.adjusted_capacity_constraint + +.. autofunction:: temoa.components.capacity.annual_retirement_constraint + +.. autofunction:: temoa.components.capacity.capacity_available_by_period_and_tech_constraint + + +.. _NetworkConstraints: + +Network Constraints +^^^^^^^^^^^^^^^^^^^ + +These three constraints define the core of the Temoa model; together, they +define the algebraic energy system network. + +.. autofunction:: temoa.components.commodities.demand_constraint + +.. autofunction:: temoa.components.commodities.commodity_balance_constraint + +.. autofunction:: temoa.components.commodities.annual_commodity_balance_constraint + + +Physical and Operational Constraints +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +These constraints fine-tune the model formulation to account for +various physical and operational real-world phenomena. + +.. autofunction:: temoa.components.operations.baseload_diurnal_constraint + +.. autofunction:: temoa.components.commodities.demand_activity_constraint + +.. autofunction:: temoa.components.storage.storage_energy_constraint + +.. autofunction:: temoa.components.storage.seasonal_storage_energy_constraint + +.. autofunction:: temoa.components.storage.storage_energy_upper_bound_constraint + +.. autofunction:: temoa.components.storage.seasonal_storage_energy_upper_bound_constraint + +.. autofunction:: temoa.components.storage.storage_charge_rate_constraint + +.. autofunction:: temoa.components.storage.storage_discharge_rate_constraint + +.. autofunction:: temoa.components.storage.storage_throughput_constraint + +.. autofunction:: temoa.components.operations.ramp_up_day_constraint + +.. autofunction:: temoa.components.operations.ramp_down_day_constraint + +.. autofunction:: temoa.components.operations.ramp_up_season_constraint + +.. autofunction:: temoa.components.operations.ramp_down_season_constraint + +.. autofunction:: temoa.components.reserves.reserve_margin_static + +.. autofunction:: temoa.components.reserves.reserve_margin_dynamic + + +Objective Function +^^^^^^^^^^^^^^^^^^ + +.. autofunction:: temoa.components.costs.annuity_to_pv + +.. autofunction:: temoa.components.costs.pv_to_annuity + +.. autofunction:: temoa.components.costs.fv_to_pv + +.. autofunction:: temoa.components.costs.total_cost_rule + + +User-Specific Constraints +^^^^^^^^^^^^^^^^^^^^^^^^^ + +The constraints provided in this section are not required for proper system +operation, but allow the modeler some further degree of system specification. + +.. commented out... not used? + .. autofunction:: temoa.components.capacity.existing_capacity_constraint + +.. autofunction:: temoa.components.limits.limit_emission_constraint + +.. autofunction:: temoa.components.limits.limit_activity_constraint + +.. autofunction:: temoa.components.limits.limit_activity_share_constraint + +.. _max_capacity_constraint: + +.. autofunction:: temoa.components.limits.limit_capacity_constraint + +.. autofunction:: temoa.components.limits.limit_new_capacity_constraint + +.. autofunction:: temoa.components.limits.limit_capacity_share_constraint + +.. autofunction:: temoa.components.limits.limit_new_capacity_share_constraint + +.. autofunction:: temoa.components.limits.limit_resource_constraint + +.. _TechOutputSplit_constraint: + +.. autofunction:: temoa.components.limits.limit_tech_input_split_constraint + +.. autofunction:: temoa.components.limits.limit_tech_output_split_constraint + +.. autofunction:: temoa.components.limits.limit_tech_input_split_annual_constraint + +.. autofunction:: temoa.components.limits.limit_tech_output_split_annual_constraint + +.. autofunction:: temoa.components.limits.limit_tech_input_split_average_constraint + +.. autofunction:: temoa.components.limits.limit_tech_output_split_average_constraint + +.. autofunction:: temoa.components.limits.limit_annual_capacity_factor_constraint + +.. autofunction:: temoa.components.limits.limit_seasonal_capacity_factor_constraint + +.. autofunction:: temoa.components.storage.limit_storage_fraction_constraint + +.. autofunction:: temoa.components.limits.limit_growth_capacity + +.. autofunction:: temoa.components.limits.limit_growth_new_capacity + +.. autofunction:: temoa.components.limits.limit_growth_new_capacity_delta + + + +General Caveats +--------------- + +Temoa does not currently provide an easy avenue to track multiple concurrent +energy flows through a process. Consider a cogeneration plant. Where a +conventional power plant might simply emit excess heat as exhaust, a +cogeneration plant harnesses some or all of that heat for heating purposes, +either very close to the plant, or generally as hot water for district heating. +Temoa's flow variables can track both flows through a process, but each flow +will have its own efficiency from the efficiency parameter. This implies that +to produce 1 unit of electricity will require :math:`\frac{1}{elc eff}` units of +input. At the same time, to produce 1 unit of heat will require units of input +energy, and to produce both output units of heat and energy, both flows must be +active, and the desired activity will be double-counted by Temoa. + +To model a parallel output device (c.f., a cogeneration plant), the modeler must +currently set up the process with the :code:`tech_input_split` and +:code:`tech_output_split` parameters, appropriately adding each flow to the +efficiency parameter and accounting for the overall process efficiency through +all flows. diff --git a/docs/source/preface.rst b/docs/source/preface.rst new file mode 100644 index 000000000..093f81a73 --- /dev/null +++ b/docs/source/preface.rst @@ -0,0 +1,101 @@ + + +This manual, in both `PDF`_ and `HTML`_ form, is the official documentation of +Tools for Energy Model Optimization and Analysis (Temoa). It describes all +functionality of the Temoa model, and provides a mathematical description of +the implemented equations. + +Besides this documentation, there are a couple other sources for Temoa-oriented +information. For questions, bug reports, or feature requests, please use our +`GitHub Issues`_. Publications are good introductory resources, but are not +guaranteed to be the most up-to-date as information and implementations evolve +quickly. As with many software-oriented projects, even before this manual, +`the code is the most definitive resource`. That said, please let us know +(via `GitHub Issues`_) of any discrepancies you find, and we will fix it as +soon as possible. + +What is Temoa? +-------------- + +Temoa is an energy system optimization model (ESOM). Briefly, ESOMs optimize the +installation and utilization of energy technology capacity over a user-defined +time horizon. Optimal decisions are driven by an objective function that minimizes +the cost of energy supply. Conceptually, one may think of an ESOM as a "left-to-right" +network graph, with a set of energy sources on the lefthand side of the graph that +are transformed into consumable energy commodities by a set of energy technologies, +which are ultimately used to meet demands on the righthand side of the network graph. +[#esom_definition]_ + +Key features of the core Temoa model include: + + * Flexible time slicing by season and time-of-day + * Variable length model time periods + * Technology vintaging + * Separate technology loan periods and lifetimes + * Global and technology-specific discount rates + * Capability to perform stochastic optimization + * Capability to perform modeling-to-generate alternatives (MGA) + + +Temoa design features include: + + * Source code licensed under MIT, available through Github [#open_source_realities]_ + * Open source software stack + * Part of a rich Python ecosystem + * Data stored in a relational database system (sqlite) + * Ability to utilize multi-core and compute cluster environments + +The word 'Temoa' is actually an acronym for "Tools for Energy Model Optimization +and Analysis," currently composed of four (major) pieces of infrastructure: + + * The mathematical model + * The implemented model (code) + * Surrounding tools + * An online presence + +Each of these pieces is fundamental to creating a transparent and usable model +with a community oriented around collaboration. + + +Why Temoa? +---------- + +In short, because we believe that ESOM-based analyses should be repeatable by +independent third parties. The only way to make this happen is to +have a freely available model, and to create an ecosystem of freely shared data +and model inputs. + +For a longer explanation, please see :cite:`Hunter_etal_2013`. In summary, +ESOM-based analyses are (1) impossible to validate, (2) complex enough as to be +non-repeatable without electronic access to **exact** versions of code *and* data +input, and (3) often do a poor job addressing uncertainty. We believe that +ESOM-based analyses should be completely open, independently reproducible, +electronically available, and address uncertainty about the future. + + +Temoa Origin and Pronunciation +------------------------------ + +While we use 'Temoa' as an acronym, it is an actual word in the Nahuatl (Aztec) +language, meaning "to seek something." + +.. Figure:: images/temoa_definition.* + :align: center + :figclass: center + :figwidth: 50% + +One pronounces the word 'Temoa' as "teh", "moe", "uh". Though TEMOA is an acronym +for 'Tools for Energy Model Optimization and Analysis', we generally use 'Temoa' +as a proper noun, and so forgo the need for all-caps. + + +Bug Reporting +------------- + +Temoa strives for correctness. Unfortunately, as an energy system model and software +project there are plenty of levels and avenues for error. If you spot a bug, +inconsistency, or general "that could be improved", we want to hear about it. + +If you are a software developer-type, feel free to open an issue on our `GitHub +Issue tracker`_\ . If you would rather not create a GitHub account, feel free +to let us know the issue on our `mailing list`_\ . diff --git a/docs/source/quick_start.rst b/docs/source/quick_start.rst new file mode 100644 index 000000000..a7f7ba6d1 --- /dev/null +++ b/docs/source/quick_start.rst @@ -0,0 +1,358 @@ + + +Installing Software Elements +---------------------------- + +Temoa is implemented in `Pyomo `_, which is in turn +written in `Python `_. Consequently, Temoa will run on +Linux, Mac, Windows, or any operating system that Pyomo supports. There are +several open source software elements required to run Temoa. + +**Using pip (Recommended for most users)**: + +The standard way to install Temoa: + +.. parsed-literal:: + # Install from PyPI (when 4.0 is released) + $ pip install temoa + + # Or install from nightlies (alpha/development versions) + $ pip install --index-url https://temoaproject.github.io/temoa-nightlies/simple/ temoa --extra-index-url https://pypi.org/simple/ + + # Get started + $ temoa tutorial my_first_model + $ temoa run my_first_model.toml + +**Using uv (Alternative)**: + +For faster dependency resolution: + +.. parsed-literal:: + # Install uv + $ curl -LsSf https://astral.sh/uv/install.sh | sh + + # Install Temoa from nightlies + $ uv pip install --index-url https://temoaproject.github.io/temoa-nightlies/simple/ temoa --extra-index-url https://pypi.org/simple/ + + # Get started + $ temoa tutorial my_first_model + $ temoa run my_first_model.toml + +**For Contributors (Development Installation)**: + +If you want to contribute to Temoa or modify the code: + +.. parsed-literal:: + # Clone the repository + $ git clone https://github.com/TemoaProject/temoa.git + $ cd temoa + + # Install in development mode with uv (recommended) + $ uv sync --all-extras --dev + + # Or with pip + $ pip install -e ".[docs,plotting]" + +For detailed contribution guidelines, see CONTRIBUTING.md in the repository. + +Solvers +------- + +A few notes for on the choice of solvers. Different solvers +have widely varying solution times. If you plan to run Temoa with large datasets +and/or conduct uncertainty analysis, you may want to consider installing +commercial linear solvers such as `CPLEX +`_ or `Gurobi +`_. Both offer free academic licenses. + +For smaller models, Temoa has been tested with both the `CBC `_ +solver and the more recently released `HiGHS `_ solver. +Each of the respective websites contains installation instructions for the individual +solvers. For those wishing to run the internal tests on Temoa, the :code:`CBC` solver +is required. + +There are three ways to run the model, each of which is detailed below. Note that +the example commands utilize 'temoa_utopia', a commonly used test case for ESOMs. + +Obtaining Temoa +--------------- + +Now that you have functioning environment, you need to obtain the source code +for Temoa. There are a couple of options for obtaining and running Temoa from +GitHub. If you want to simply run the model, you can download Temoa from GitHub +as a zip file. Navigate to our `Github repo `__, +and click the green ā€˜clone or download’ button near the top-right corner. Select +ā€˜Download ZIP,’ and you can download the entire Temoa :code:`main` (our main branch) +to your local machine. The second option creates a local copy of the model source +code in our GitHub repository. This is a two step process: first install git and +then ā€˜clone’ the repository. Under Linux, git can be installed through the default +package manager. Git for Windows and Mac can be downloaded from the `Git website +`_. To clone the Temoa repository, navigate to +the directory where you want the model to reside and type the following from the +prompt: + +.. parsed-literal:: + $ git clone https://github.com/TemoaProject/temoa/ + +Note that cloning the repository will supply the latest version of the code, and +allow you to archive changes to the code and data in your own local git +repository. + +A few basic input data files are included in the :code:`temoa/data_files`` folder. +Additional Temoa-compatible datasets are available in `this separate GitHub +repo `_. + +The installation procedures above are meant to be generic and should work across +different platforms. Nonetheless, system-specific ambiguities and unexpected +conditions inevitably arise. Please use the `Temoa forum +`_ to ask for help. + +Running Temoa +------------- +Temoa should always be run from the top-level from the top-level +:code:`temoa` directory. + +To run the model, a configuration (ā€˜config’) file is needed. An +example config file called :code:`config_sample.toml` resides within the +:code:`data_files/my_configs` folder. Running the model with a config file allows +the user to (1) use a sqlite +database for storing input and output data, (2) create a formatted Excel output +file, (2) specify the solver to use, (3) return the log file produced during +model execution, (4) return the lp file utilized by the solver, and (5) to +execute several of the modeling extensions. + +.. parsed-literal:: + $ temoa run config.toml + +**For general help, use --help:** + +.. parsed-literal:: + $ **temoa --help** + usage: temoa [-h] [--version] [--how-to-cite] COMMAND ... + + Tools for Energy Model Optimization and Analysis (Temoa) + + options: + -h, --help show this help message and exit + --version Show version information + --how-to-cite Show citation information + + commands: + COMMAND + run Run a Temoa model + validate Validate a configuration file + migrate Migrate a database to the latest schema + tutorial Create tutorial files + +.. + dated references, preserved as comment here: + + To supplement this documentation, we have also created a + `YouTube video tutorial ` that explains + how to run Temoa from the command line. There is also an option to run + `Temoa on the cloud `, which + is explained in `this video tutorial `. + +==================================== +Database Construction +==================================== + +Input datasets in Temoa can be constructed either as text files or relational +databases. Input text files are referred to as 'DAT' files and follow a specific +format. Take a look at the example DAT files in the :code:`temoa/data_files` +directory. + +While DAT files work fine for small datasets, relational databases are preferred +for larger datasets. To first order, you can think of a database as a collection +of tables, where a 'primary key' within each table defines a unique entry (i.e., +row) within the table. In addition, a 'foreign key' defines a table element drawn +from another table. Foreign keys enforce the defined relationships between +different sets and parameters. + +Temoa uses `sqlite`_, a widely used, self-contained database +system. Building a database first requires constructing a sql file, which is +simply a text file that defines the structure of different database tables and +includes the input data. The snippet below is from the technology table used to +define the 'temoa_utopia' dataset: + +**NOTE**: *As of Version 3, the below table format is dated, but still shows the general structure of +the SQL files used to create the database.* + +.. parsed-literal:: + CREATE TABLE technologies ( + tech text primary key, + flag text, + sector text, + tech_desc text, + tech_category text, + FOREIGN KEY(flag) REFERENCES technology_labels(tech_labels), + FOREIGN KEY(sector) REFERENCES sector_labels(sector)); + INSERT INTO "technologies" VALUES('IMPDSL1','r','supply',' imported diesel','petroleum'); + INSERT INTO "technologies" VALUES('IMPGSL1','r','supply',' imported gasoline','petroleum'); + INSERT INTO "technologies" VALUES('IMPHCO1','r','supply',' imported coal','coal'); + +The first line creates the table. **Lines 2-6** define the columns within this table. +Note that the the technology ('tech') name defines the primary key. Therefore, the +same technology name cannot be entered twice; each technology name must be unique. +**Lines 7-8** define foreign keys within the table. For example, each technology +should be specified with a label (e.g., 'r' for 'resource'). Those labels must +come from the 'technology_labels' table. Likewise, the sector name must be defined +in the 'sector_labels' table. This enforcement of names across tables using +foreign keys helps immediately catch typos. (As you can imagine, typos happen in +plain text files and Excel when defining thousands of rows of data.) Another big +advantage of using databases is that the model run outputs are stored in +separate database output tables. The outputs by model run are indexed by a scenario name, +which makes it possible to perform thousands of runs, programatically store all +the results, and execute arbitrary queries that instantaneously return the requested +data. + +Because some database table elements serve as foreign keys in other tables, we +recommend that you populate input tables in the following order: + +**Group 1: labels used for internal database processing** + * commodity_type: Need to identify which type of commodity. Do NOT change these abbreviations. + * technology_type: Need to identify which type of technology. Do NOT change these abbreviations. Categorizing + and sub-categorizing can be done in the Technology table itself. + * time_period_type: Used to distinguish which time periods are simply used to specify pre-existing + vintages and which represent future optimization periods. + * season_label: Unordered unique labels defining seasons in the model. + + +**Group 2: sets used within Temoa** + * Commodity: list of commodities used within the database + * Technology: list of technologies used within the database + * time_period: list of both past and future time periods considered in the database + * time_season: seasons modeled in the database + * time_of_day: time of day segments modeled in the database + + +**Group 3: parameters used to define processes within Temoa** + * metadata_real (global_discount_rate) + * metadata (days_per_period) + * Demand + * demand_specific_distribution + * efficiency + * existing_capacity + * capacity_factor + * capacity_factor_process (only if CF varies by vintage; overwrites capacity_factor) + * capacity_to_activity + * cost_fixed + * cost_invest + * cost_variable + * emission_activity + * lifetime_tech + * lifetime_process (only if LT varies by vintage; overwrites lifetime_tech) + * time_segment_fraction: proportion of each period represented by each time slice + +**Group 4: parameters used to define constraints within Temoa** + * limit_activity + * limit_capacity + * limit_emission + * limit_growth_capacity + * limit_new_capacity + * limit_resource + * limit_tech_input_split + * limit_tech_output_split + +For help getting started, take a look at how :code:`data_files/temoa_utopia.sql` is +constructed. Use :code:`data_files/temoa_schema.sql` (a database file with the requisite +structure but no data added) to begin building your own database file. We recommend +leaving the database structure intact, and simply adding data to the schema file, or +constructing an empty database from the schema file and then using a database editor +to import data. +Once the sql file is complete, you can convert it into a binary sqlite file by +installing sqlite3 and executing the following command: + +.. parsed-literal:: + $ sqlite3 my_database.sqlite < my_database.sql + +Now you can specify this database as the source for both input and output data +in the config file. + +============ +Data Quality +============ + +In addition to numerous internal checks, Temoa (optionally) employs two quality checks on +data read in from the database. The outputs (actions and warnings) generated by these processes +are reported in the log file for the run. + +Both of the checks below can be run to QA data by running the model in `CHECK` mode and inspecting +the log file. During `CHECK` mode runs, no solve is attempted on the model. + +Price Checking +-------------- +The "price checker" reviews cost data in the 3 cost tables and considers technology lifetime. It +screens for possible inconsistencies that would corrupt output quality. Larger models may have +well over 100K cost entries and an overlooked investment cost for a particular vintage tech in +a particular region could easily be overlooked. Price checks performed/reported: + +1. **Missing Costs (Check 0)**: This check looks for technologies that have no fixed/invest/variable + costs at all. Other checks are more discriminating, so this check is only reported when Temoa is run + in `debug` mode by using the `-d` flag on the run command. +2. **Missing Fixed/Investment Costs (Check 1a)**: This check identifies technologies that are *not* + flagged as `uncapacitated` with neither a fixed or investment cost associated. These *might* be + problematic for solve because the model minimizes cost, so capacity in these technologies would be + free. `uncapacitated` technologies have no capacity measure, so fixed/investment costs are prohibited + for them and that is checked elsewhere. +3. **Inconsistent Fixed/Investment Cost (Check 1b)**: This check looks for inconsistent application + of fixed or base costs in the "base" or vintage year across all vintages and regions. So, if a tech has + a fixed cost in some particular region and vintage year, but not in all, it will be flagged as a likely + omission. +4. **Inconsistent Fixed & Variable Costs (Check 2)**: This check identifies techs that have + inconsistencies in the application of fixed - variable costs. Techs that have *any* fixed cost for + a particular [region, tech, vintage] process, but do not have entries that match the variable cost + entries for the same process are flagged, and vice-versa. This would hopefully identify an + accidental omission of some of the fixed/var costs for processes that have at least 1 entry for either. +5. **Lifetime Costing (Check 3)**: This check identifies costs that fall short or are missing + during the process's lifetime. If a process has a variable cost in *any* year during the lifetime, but + not all years, it is flagged. Same for fixed cost. +6. **Uncapacitated Tech Costs**: Any technology flagged as `uncapacitated` will trigger warnings here + if it has any fixed/invest costs. + +Source Tracing +-------------- + +Temoa works backwards from demands to identify chains of technologies required to meet the demand. +Source Tracing is designed to ensure that this backward tracing from demands describes a proper +commodity network without gaps that might allow intermediate commodities to be treated as a free +"source" commodity. Further description of possible network problems is included in the +`commodity network notes.md` file in the `docs` folder. + +Source Tracing pre-builds the entire commodity network in each region-period contained in the +data and analyzes it for "orphans" which likely represent gaps in the network that would lead +to erroneous output data. The operation is enabled by tagging foundational commodities for which +there are no predecessors as "source" commodities in the `Commodity` database table with an `s` tag. +Orphans (or chains of orphans) on either the demand or supply side are reported and *suppressed* in +the data to prevent network corruption. + +Note that the myopic mode *requires* the use of Source Tracing to ensure accuracy as some orphans +may be produced by endogenous decisions in myopic runs. + +Commodity Network Visualization +------------------------------- +The output of the Source Tracing operation can be visualized by enabling the commodity network plots +in the config file. This will add a set of region-period specific html files to the Outputs folder. +These files *should* be open-able in any web browser. (See the note in the main `README.md` for trouble +with Windows OS systems). + +.. Figure:: images/utopia_commodity_network.png + :align: center + :figclass: center + :figwidth: 60% + + An example of the Commodity Network for Utopia (interactive view in web browser by opening + the generated html file) + +The color legend for Commodity Networks is as follows: + +* Green dot: Source Commodity +* Orange dot: Demand Commodity +* Violet dot: Intermediate Commodity +* Black arc: Technology +* Blue arc: Linked Technology (the driven tech, *not* the driver) +* Yellow arc: Supply-Side Orphan (shown, but suppressed when model built) +* Red arc: Demand-Side Orphan (shown, but suppressed when model built) +* Green arc: Any Tech with a Negative Variable Cost + +============= diff --git a/docs/source/visualization.rst b/docs/source/visualization.rst new file mode 100644 index 000000000..dad14f652 --- /dev/null +++ b/docs/source/visualization.rst @@ -0,0 +1,112 @@ +Network Diagrams +---------------- + +.. warning:: + The graphviz visualization tools have not been fully tested with Temoa v4.0. + They may require updates. Please report any issues on + `GitHub Issues `_. + +Since Temoa model consists of an energy network in which technologies are connected +by the flow of energy commodities, a directed network graph represents an excellent way +to visualize a given energy system representation in a Temoa-compatible input database. +Temoa utilizes an open source graphics package called `Graphviz`_ to create a series of +data-specific and interactive energy-system maps. Currently, the output graphs consist of +a full energy system map as well as capacity and activity results per model time period. +In addition, users can create subgraphs focused on a particular commodity or technology. + + +To use graphviz from the command line, navigate to the :code:`data_processing` folder, +where the graphviz script resides. To review all of the graphviz options, use the +:code:`--help` flag: + +.. parsed-literal:: + $ python make_graphviz.py --help + +The most basic way to use graphviz is to view the full energy system map: + +.. parsed-literal:: + $ python make_graphviz.py -i ../data_files/temoa_utopia.sqlite + +In the command above, note that we have to point the Graphviz module to the +:code:`temoa_utopia` database file, which resides in the :code:`data_files` +directory. The resultant system map will look like this: + +.. Figure:: images/simple_model.* + :align: center + :figclass: center + :figwidth: 60% + + This is a map of the simple 'Utopia' system, which we often use for testing + purposes. The map shows the possible commodity flows through the system, + providing a comprehensive overview of the system. Creating the simple system + map is useful for debugging purposes in order to make sure that technologies + are linked together properly via commodity flows. + +It is also possible to create a system map showing the optimal installed capacity +and technology flows in a particular model time period. These results are associated +with a specific model run stored in the model database. To view the results, include +the scenario flag (:code:`-s`) and a specific model year (:code:`-y`). + +Note that when Graphiz runs, it creates a folder within the :code:`data_processing` +folder. The folder itself is assigned the name of the database file, with +:code:`input_graphviz` appended to the end. This descriptor changes if using Graphviz +to visualize output graphics. Within this Graphviz-generated folder are two files. The +graphics file (default: svg) is a viewable image of the network. The dot file is the +input file to Graphviz that is created programmatically. Note that the dot files provide +another means to debug the model and create an archive of visualizations for auditing +purposes. In addition, we have taken care to make these intermediate files well-formatted. + +.. parsed-literal:: + $ python make_graphviz.py -i ../data_files/temoa_utopia.sqlite -s test_run -y 1990 + +.. figure:: images/global_results.* + :align: center + :figclass: center + :figwidth: 60% + + This graph shows the optimal installed capacity and commodity flows from the + 'utopia' test system in 2010. + +The output can also be fine-tuned to show results associated with a specific +commodity or technology. For example: + +.. parsed-literal:: + $ python make_graphviz.py -i ../data_files/temoa_utopia.sqlite -s test_run -y 2010 -b E31 + +.. figure:: images/techvintage_results.* + :align: center + :figclass: center + :figwidth: 60% + + In this case, the graph shows the commodity flow in and out of + technology 'E31' in 2010, which is from the 'test_run' scenario drawn from the + 'temoa_utopia' database. + +Output Graphs +------------- + +Temoa can also be used to generate output graphs using `matplotlib `. +From the command line, navigate to the :code:`data_processing` folder and execute the following command: + +.. parsed-literal:: + $ python make_output_plots.py --help + +The command above will specify all of the flags required to created a stacked bar +or line plot. For example, consider the following command: + +.. parsed-literal:: + $ python make_output_plots.py -i ../data_files/temoa_utopia.sqlite -s test_run -p capacity -c electric --super + +Here is the result: + +.. figure:: images/output_flow_example.* + :align: center + :figclass: center + :figwidth: 60% + + This stacked bar plot represents the activity (i.e., output commodity flow) + associated with each technology in the electric sector from the 'test_run' + scenario drawn from the 'temoa_utopia' database. Because the :code:`super` + flag was specified, technologies are grouped together based on user-specified + categories in the :code:`tech_category`` column of the :code:`technologies` + table of the database. From 0ba8167ec1451c49fa7d2a82a299436b8a93e51a Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 18 Nov 2025 17:57:52 -0500 Subject: [PATCH 343/587] docs: updating readmes --- docs/README.md | 107 +++++++++++++++++++++++++++----- temoa/data_processing/README.md | 75 +++++++++++++++------- 2 files changed, 143 insertions(+), 39 deletions(-) diff --git a/docs/README.md b/docs/README.md index 94c59c64d..c79050ad6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,31 +1,104 @@ -This directory contains the source files necessary to generate the Temoa documentation in [ReST](https://en.wikipedia.org/wiki/ReStructuredText) format. +# Temoa Documentation -## Required Software +This directory contains the source files for generating the Temoa documentation in [ReStructuredText](https://en.wikipedia.org/wiki/ReStructuredText) format. -The required software elements to produce the documentation are included in the Temoa [environment file](https://github.com/TemoaProject/temoa/blob/energysystem/environment.yml). +## Building the Documentation -The only additional software element required is LaTex. On a Mac, [MacTeX](https://www.tug.org/mactex/mactex-download.html) is a good option, and must be installed manually. [MiKTeX](https://miktex.org/download) is also available across platforms and is installed manually. On a Windows machine, MikTeX can also be installed through `conda` with the following command: +### Prerequisites -```$ conda install -c conda-forge miktex``` +The documentation build requires Sphinx and related packages. These are included in the `docs` extra dependency group. -## Producing documentation -The Temoa documentation draws from a couple of sources: (1) the static descriptions of model elements included in [Documentation.rst](source//Documentation.rst), and (2) the doc strings -embedded in [temoa_rules.py](../temoa_model/temoa_rules.py) that document the objective function and constraints. Sphinx retrieves these doc strings and generates LaTeX-formatted equations in the "Equations" section of the documentation. +### Setup +Install the documentation dependencies using uv (recommended): -From this folder, execute the following to generate the html documentation: +```bash +cd /path/to/temoa +uv sync --extra docs +``` -```$ make html``` +Or using pip: -To generate the PDF documentation, from the same folder, execute the following: +```bash +pip install -e ".[docs]" +``` -```$ make latexpdf``` +### Generating HTML Documentation -Sometimes this automatic PDF generation fails. If that is the case, navigate to `/tmp/TemoaDocumentationBuild/` and manually generate the pdf: +From the `docs` directory, execute: -```$ pdflatex toolsforenergymodeloptimizationandanalysistemoa.pdf``` +```bash +uv run sphinx-build source _build/html +``` -## In Windows -With the Temoa virtual environment active and the current directory set to the Temoa root directory (see README in root dir), build the documentation with Sphinx: +Or from the repository root: -```python -m sphinx docs/source docs/_build/html`` \ No newline at end of file +```bash +uv run sphinx-build docs/source docs/_build/html +``` + +The generated HTML files will be in `docs/_build/html/`. Open `index.html` in your browser to view the documentation. + +### Generating PDF Documentation + +To generate PDF documentation, you'll need LaTeX installed on your system: +- **macOS**: [MacTeX](https://www.tug.org/mactex/mactex-download.html) +- **Windows/Linux**: [MiKTeX](https://miktex.org/download) + +Then run: + +```bash +uv run sphinx-build -b latexpdf source _build/latex +``` + +The PDF will be generated in `docs/_build/latex/`. + +If automatic PDF generation fails, navigate to the build directory and manually generate the PDF: + +```bash +cd docs/_build/latex +pdflatex toolsforenergymodeloptimizationandanalysistemoa.tex +``` + +## Documentation Structure + +The Temoa documentation draws from two main sources: + +1. **Static descriptions** - Model elements and concepts described in `source/Documentation.rst` +2. **Code docstrings** - Objective function and constraint documentation from module docstrings in: + - `temoa/components/costs.py` - Objective function + - `temoa/components/*.py` - Constraint implementations + +Sphinx retrieves these docstrings and generates LaTeX-formatted equations in the "Equations" section of the documentation. + +## Checking for Issues + +### Link Checking + +To check for broken links in the documentation: + +```bash +uv run sphinx-build -b linkcheck source _build/linkcheck +``` + +Review the output in `docs/_build/linkcheck/output.txt`. + +### Build Warnings + +To treat warnings as errors (useful for CI): + +```bash +uv run sphinx-build -W -b html source _build/html +``` + +## Contributing to Documentation + +When contributing to the documentation: + +1. Follow ReStructuredText formatting guidelines +2. Ensure all code examples are tested and working +3. Build the documentation locally to check for warnings +4. Run the link checker to verify external links +5. Update docstrings in code when changing model equations + +See [CONTRIBUTING.md](../CONTRIBUTING.md) for general contribution guidelines. diff --git a/temoa/data_processing/README.md b/temoa/data_processing/README.md index eda947288..dd3006e70 100644 --- a/temoa/data_processing/README.md +++ b/temoa/data_processing/README.md @@ -1,36 +1,67 @@ # Overview -This folder contains files used to manage Temoa input/output data. Included files are: +This folder contains files used to manage Temoa output data processing and visualization. + +> **āš ļø Note:** These tools have not been fully tested with Temoa v4.0. They may require updates or fixes. Please report any issues on [GitHub Issues](https://github.com/TemoaProject/temoa/issues). + +## Available Tools + +### 1. `db_to_excel.py` + +**Status:** āš ļø Untested in v4.0 -1. `db_to_excel.py/` Python script that queries database output tables to create an Excel file containing scenario-specific results. -2. `make_graphviz.py/` -Python script that creates a Graphviz diagram for the database. -The most basic way to use graphviz is to view the full energy system map: -```$ python make_graphviz.py -i temoa_utopia.sqlite``` Other options include a capacitated -flow graph for a specific period: ```-i ../../data_files/utopia.sqlite -r utopia -s -c -y 2010``` -note how this input file passes a relative link up to the data_files directory, assuming standard location in the project +**Usage:** +```bash +uv run python temoa/data_processing/db_to_excel.py -i path/to/database.sqlite -s scenario_name +``` + +### 2. `make_graphviz.py` + +**Status:** āš ļø Untested in v4.0 + +Python script that creates Graphviz diagrams for visualizing the energy system network. + +**Basic usage** - View the full energy system map: +```bash +uv run python temoa/data_processing/make_graphviz.py -i data_files/temoa_utopia.sqlite +``` -3. `Network_diagrams.ipynb/` -Notebook to interactively view network diagrams for a user-specified database. -Create and activate the Temoa environment, as follows: +**Advanced usage** - Capacitated flow graph for a specific period: +```bash +uv run python temoa/data_processing/make_graphviz.py \ + -i data_files/temoa_utopia.sqlite \ + -r utopia \ + -s scenario_name \ + -c \ + -y 2010 +``` - ```$ conda env create``` +**Options:** +- `-i` : Input database file path +- `-r` : Region name +- `-s` : Scenario name +- `-c` : Include capacity information +- `-y` : Specific year to visualize - ```$ source activate temoa-py3``` +For all available options: +```bash +uv run python temoa/data_processing/make_graphviz.py --help +``` - Once the Temoa environment is created and activated, enable the following extensions from the command line. - This will need to be done only once, before using notebooks within the Temoa environment. +## Output Files - ```(temoa-py3) $ jupyter nbextension enable init_cell/main``` +The scripts generate output files in the current directory or a specified output location. Graphviz creates both: +- **SVG/PNG files** - Viewable images of the network +- **DOT files** - Source files for Graphviz (useful for debugging and archiving) - ```(temoa-py3) $ jupyter nbextension enable hide_input/main``` +## Environment Setup - Once these extensions are enabled, navigate to the `temoa/data_processing/` folder and then open notebooks as follows. +These tools are included in the main Temoa installation. If you're working from the repository: - ```(temoa-py3) $ jupyter notebook``` +```bash +uv sync --all-extras +``` - Navigate to the `Network_diagrams.ipynb/` file and select technology/commodity options to interactively view their network diagrams. - The notebook also includes an interactive technology/commodity lookup tool. - The "Toggle selected cell input display" button (below and to the right of the Help menu) can be used to view hidden code cells. +This ensures all required dependencies (pandas, graphviz, xlsxwriter, etc.) are installed. From 56074e28cdc237a0c92d2d29734ef83c22ea62a5 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 18 Nov 2025 18:03:08 -0500 Subject: [PATCH 344/587] docs: fixing remnant naming inconsistencies --- docs/Database Upgrade and Troubleshooting.md | 2 +- temoa/components/operations.py | 20 ++++++++++---------- temoa/components/time.py | 11 +++++++---- temoa/core/model.py | 9 +++++---- temoa/utilities/capacity_analyzer.py | 7 +++---- tests/test_pricing_check.py | 4 ++-- tests/test_storage.py | 2 +- 7 files changed, 29 insertions(+), 26 deletions(-) diff --git a/docs/Database Upgrade and Troubleshooting.md b/docs/Database Upgrade and Troubleshooting.md index 3b11dfbfa..142f416dd 100644 --- a/docs/Database Upgrade and Troubleshooting.md +++ b/docs/Database Upgrade and Troubleshooting.md @@ -78,5 +78,5 @@ WHERE base.tech IS NULL; easily by commenting out the read-in process for parameter data in `hybrid_loader.py`. It should be possible to search for the table name and then just comment out the entire block that reads in that table. Much easier than manipulating the database. -Consideration for excluding MinActivity, MaxActivity, EmissionLimit, etc. is +Consideration for excluding min_activity, max_activity, EmissionLimit, etc. is suggested. diff --git a/temoa/components/operations.py b/temoa/components/operations.py index cf35fe9fe..103ef5ed9 100644 --- a/temoa/components/operations.py +++ b/temoa/components/operations.py @@ -248,10 +248,10 @@ def ramp_up_day_constraint( ) -> ExprLike: r""" One of two constraints built from the ramp_up_hourly table, along with the - RampUpSeason_constraint. RampUpDay constrains ramp rates between time slices - within each season and RampUpSeason constrains ramp rates between sequential + ramp_upSeason_constraint. ramp_upDay constrains ramp rates between time slices + within each season and ramp_upSeason constrains ramp rates between sequential seasons. If the :code:`time_sequencing` parameter is set to :code:`consecutive_days` - then the RampUpSeason constraint is skipped as seasons already connect together. + then the ramp_upSeason constraint is skipped as seasons already connect together. The ramp rate constraint is utilized to limit the rate of electricity generation increase and decrease between two adjacent time slices in order to account for @@ -266,7 +266,7 @@ def ramp_up_day_constraint( is the beginning of the same season, :math:`(s,d_{first})` .. math:: - :label: RampUpDay + :label: ramp_upDay \frac{ \sum_{I,O} \mathbf{FO}_{r,p,s_{next},d_{next},i,t,v,o} @@ -282,7 +282,7 @@ def ramp_up_day_constraint( \leq R_{r,t} \cdot \Delta H_{r,p,s,d,s_{next},d_{next}} \cdot CAP_{r,p,t,v} \cdot C2A_{r,t} \\ - \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampUpDay}} + \forall \{r, p, s, d, t, v\} \in \Theta_{\text{ramp_upDay}} \\ \text{where: } \Delta H_{r,p,s,d,s_{next},d_{next}} = \frac{24}{2} \left ( \frac{SEG_{r,p,s,d}}{\sum_{D} SEG_{r,p,s,d'}} + @@ -363,11 +363,11 @@ def ramp_down_day_constraint( ) -> ExprLike: r""" - Similar to the :code`RampUpDay` constraint, we use the :code:`RampDownDay` + Similar to the :code`ramp_upDay` constraint, we use the :code:`ramp_downDay` constraint to limit ramp down rates between any two adjacent time slices. .. math:: - :label: RampDownDay + :label: ramp_downDay \frac{ \sum_{I,O} \mathbf{FO}_{r,p,s,d,i,t,v,o} @@ -383,7 +383,7 @@ def ramp_down_day_constraint( \leq R_{r,t} \cdot \Delta H_{r,p,s,d,s_{next},d_{next}} \cdot CAP_{r,p,t,v} \cdot C2A_{r,t} \\ - \forall \{r, p, s, d, t, v\} \in \Theta_{\text{RampDownDay}} + \forall \{r, p, s, d, t, v\} \in \Theta_{\text{ramp_downDay}} """ s_next, d_next = model.time_next[p, s, d] @@ -452,7 +452,7 @@ def ramp_up_season_constraint( ) -> ExprLike: r""" Constrains the ramp up rate of activity between time slices at the boundary - of sequential seasons. Same as RampUpDay but only applies to the boundary + of sequential seasons. Same as ramp_upDay but only applies to the boundary between sequential seasons, i.e., :math:`(s^{seq},d_{last})` to :math:`(s^{seq}_{next},d_{first})` and :math:`s^{seq}_{next}` is based on the TimeSequential table rather than the time_season table. @@ -525,7 +525,7 @@ def ramp_down_season_constraint( ) -> ExprLike: r""" Constrains the ramp down rate of activity between time slices at the boundary - of sequential seasons. Same as RampDownDay but only applies to the boundary + of sequential seasons. Same as ramp_downDay but only applies to the boundary between sequential seasons, i.e., :math:`(s^{seq},d_{last})` to :math:`(s^{seq}_{next},d_{first})` and :math:`s^{seq}_{next}` is based on the TimeSequential table rather than the time_season table. diff --git a/temoa/components/time.py b/temoa/components/time.py index 364e35b11..69b9d40f7 100644 --- a/temoa/components/time.py +++ b/temoa/components/time.py @@ -344,7 +344,7 @@ def create_time_season_to_sequential(model: TemoaModel) -> None: msg = ( f'No data in time_season_sequential but time_sequencing parameter set to {model.time_sequencing.first()} ' 'and inter-season features used. time_season_sequential must be filled for this type of time ' - 'sequencing if seasonal storage or inter-season constraints like RampUp/RampDown are used. Check ' + 'sequencing if seasonal storage or inter-season constraints like ramp_up/ramp_down are used. Check ' 'the config file.' ) logger.error(msg) @@ -381,9 +381,12 @@ def create_time_season_to_sequential(model: TemoaModel) -> None: count_total[p] = sum(sequential[p, s] for _p, s in sequential if _p == p) if abs(count_total[p] - value(model.days_per_period)) >= 0.001: logger.warning( - f'Sum of num_days in time_season_sequential ({count_total[p]}) ' - f'for period {p} does not sum to days_per_period ({value(model.days_per_period)}) ' - 'from the MetaData table.' + 'Sum of num_days in time_season_sequential (%s) ' + 'for period %s does not sum to days_per_period (%s) ' + 'from the MetaData table.', + count_total[p], + p, + value(model.days_per_period), ) # Check that seasons using in storage seasons are actual seasons diff --git a/temoa/core/model.py b/temoa/core/model.py index 536bbd256..b8ff83898 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -79,8 +79,9 @@ def create_sparse_dicts(model: 'TemoaModel') -> None: if unused_techs: for tech in sorted(unused_techs): logger.warning( - f"Notice: '{tech}' is specified as a technology but is not " - 'utilized in the efficiency parameter.' + "Notice: '%s' is specified as a technology but is not " + 'utilized in the efficiency parameter.', + tech, ) logger.debug('Completed creation of SparseDicts') @@ -261,7 +262,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: # Note: Storage techs cannot (currently) be retired due to linkage to initialization # process, which is currently incapable of reducing initializations on retirements. # Note2: I think this has been fixed but I can't tell what the problem was. Suspect - # it was the old StorageInit constraint + # it was the old storage_init constraint self.tech_retirement = Set(within=self.tech_with_capacity) # - M.tech_storage) self.validate_techs = BuildAction(rule=validate_tech_sets) @@ -343,7 +344,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: # limit_resource IS implemented but sums cumulatively for a technology rather than # resource commodity # M.ResourceConstraint_rpr = Set(within=M.regions * M.time_optimize * M.commodity_physical) - # M.ResourceBound = Param(M.ResourceConstraint_rpr) + # M.resource_bound = Param(M.ResourceConstraint_rpr) # Define technology performance parameters self.capacity_to_activity = Param(self.regional_indices, self.tech_all, default=1) diff --git a/temoa/utilities/capacity_analyzer.py b/temoa/utilities/capacity_analyzer.py index e708833bd..81e77c018 100644 --- a/temoa/utilities/capacity_analyzer.py +++ b/temoa/utilities/capacity_analyzer.py @@ -1,6 +1,6 @@ """ Quick utility script to analyze the distribution of capacities within a scenario database -Note: this uses the MaxCapacity table for analysis, which depending on if/how that table +Note: this uses the max_capacity table for analysis, which depending on if/how that table is populated will influence the utility of using this method """ @@ -8,9 +8,8 @@ import os.path import sqlite3 -from matplotlib import pyplot as plt - from definitions import PROJECT_ROOT +from matplotlib import pyplot as plt # Written by: J. F. Hyink # jeff@westernspark.us @@ -27,7 +26,7 @@ try: con = sqlite3.connect(source_db_file) cur = con.cursor() - cur.execute('SELECT max_cap FROM MaxCapacity') + cur.execute('SELECT max_cap FROM max_capacity') for row in cur: res.append(row) diff --git a/tests/test_pricing_check.py b/tests/test_pricing_check.py index 8b02dd3a1..3e936e552 100644 --- a/tests/test_pricing_check.py +++ b/tests/test_pricing_check.py @@ -22,8 +22,8 @@ def mock_model() -> ConcreteModel: model.cost_fixed = Param(Any, Any, Any, Any, mutable=True) model.cost_invest = Param(Any, Any, Any, mutable=True) model.cost_variable = Param(Any, Any, Any, Any, mutable=True) - model.MaxCapacity = Param(Any, Any, Any, mutable=True) - model.MinCapacity = Param(Any, Any, Any, mutable=True) + model.max_capacity = Param(Any, Any, Any, mutable=True) + model.min_capacity = Param(Any, Any, Any, mutable=True) return model diff --git a/tests/test_storage.py b/tests/test_storage.py index b27a458b5..68328c790 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -132,7 +132,7 @@ def test_storage_flow_balance(system_test_run: tuple[str, Any, TemoaModel, Any]) ) -# devnote: the StorageInit constraint was reworked into LimitStorageLevelFraction +# devnote: the storage_init constraint was reworked into LimitStorageLevelFraction # @pytest.mark.skip('not ready for primetime') # def test_hard_initialization(): # filename = 'config_storageville.toml' From 2dfde625e12c70e7e2ddad83c34a100cbc6e8cfd Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 18 Nov 2025 18:26:17 -0500 Subject: [PATCH 345/587] docs: fixing inconsistencies --- docs/source/computational_implementation.rst | 4 ++-- docs/source/mathematical_formulation.rst | 4 ++-- docs/source/preface.rst | 2 +- docs/source/quick_start.rst | 6 ++---- temoa/components/operations.py | 20 ++++++++++---------- temoa/data_processing/README.md | 6 ++++++ 6 files changed, 23 insertions(+), 19 deletions(-) diff --git a/docs/source/computational_implementation.rst b/docs/source/computational_implementation.rst index 549a805f6..28b370e6f 100644 --- a/docs/source/computational_implementation.rst +++ b/docs/source/computational_implementation.rst @@ -849,10 +849,10 @@ should meet a basic standard of quality: This indicates that you retain all rights to any intellectual property your (set of) commit(s) creates, but that you license it to the Temoa Project - under the terms of the GNU Public License, version 2. If + under the terms of the MIT license. If the Temoa Project incorporates your commit, then Temoa may not relicense your (set of) patch(es), other than to increase the version number of the - GPL license. In short, the intellectual property remains yours, and the + MIT license. In short, the intellectual property remains yours, and the Temoa Project would be but a licensee using your code similarly under the terms of MIT. diff --git a/docs/source/mathematical_formulation.rst b/docs/source/mathematical_formulation.rst index 5c11cfb08..e8f834e22 100644 --- a/docs/source/mathematical_formulation.rst +++ b/docs/source/mathematical_formulation.rst @@ -937,7 +937,7 @@ ramp down rate can be specified via the :code:`ramp_down` parameter. The specifi value represents the fraction of installed capacity that can be ramped down when moving from one time slice to the next. There is an equivalent :code:`ramp_up` parameter, to specify ramping limits in the upward direction. This parameter is used in the -:code:`ramp_downDay_constraint` and `ramp_downSeason_constraint`. The former constrains +:code:`ramp_down_day_constraint` and `ramp_down_season_constraint`. The former constrains the downward ramp rate between time-of-day slices, and the latter constrains the downward ramp rate between the last time-of-day slice in a given season and the first time-of-day slice in the next season. @@ -953,7 +953,7 @@ ramp up rate can be specified via the :code:`ramp_up` parameter. The specified value represents the fraction of installed capacity that can be ramped up when moving from one time slice to the next. There is an equivalent :code:`ramp_down` parameter, to specify ramping limits in the downward direction. This parameter is used in the -:code:`ramp_upDay_constraint` and `ramp_upSeason_constraint`. The former constrains +:code:`ramp_up_day_constraint` and `ramp_up_season_constraint`. The former constrains the upward ramp rate between time-of-day slices, and the latter constrains the upward ramp rate between the last time-of-day slice in a given season and the first time-of-day slice in the next season. diff --git a/docs/source/preface.rst b/docs/source/preface.rst index 093f81a73..ae9c79fc6 100644 --- a/docs/source/preface.rst +++ b/docs/source/preface.rst @@ -79,7 +79,7 @@ Temoa Origin and Pronunciation While we use 'Temoa' as an acronym, it is an actual word in the Nahuatl (Aztec) language, meaning "to seek something." -.. Figure:: images/temoa_definition.* +.. figure:: images/temoa_definition.* :align: center :figclass: center :figwidth: 50% diff --git a/docs/source/quick_start.rst b/docs/source/quick_start.rst index a7f7ba6d1..83f8c0085 100644 --- a/docs/source/quick_start.rst +++ b/docs/source/quick_start.rst @@ -104,13 +104,11 @@ repo `_. The installation procedures above are meant to be generic and should work across different platforms. Nonetheless, system-specific ambiguities and unexpected -conditions inevitably arise. Please use the `Temoa forum -`_ to ask for help. +conditions inevitably arise. Please use +`GitHub Issues `_ to ask for help. Running Temoa ------------- -Temoa should always be run from the top-level from the top-level -:code:`temoa` directory. To run the model, a configuration (ā€˜config’) file is needed. An example config file called :code:`config_sample.toml` resides within the diff --git a/temoa/components/operations.py b/temoa/components/operations.py index 103ef5ed9..bfb9bcc49 100644 --- a/temoa/components/operations.py +++ b/temoa/components/operations.py @@ -248,10 +248,10 @@ def ramp_up_day_constraint( ) -> ExprLike: r""" One of two constraints built from the ramp_up_hourly table, along with the - ramp_upSeason_constraint. ramp_upDay constrains ramp rates between time slices - within each season and ramp_upSeason constrains ramp rates between sequential + ramp_up_season_constraint. ramp_up_day constrains ramp rates between time slices + within each season and ramp_up_season constrains ramp rates between sequential seasons. If the :code:`time_sequencing` parameter is set to :code:`consecutive_days` - then the ramp_upSeason constraint is skipped as seasons already connect together. + then the ramp_up_season constraint is skipped as seasons already connect together. The ramp rate constraint is utilized to limit the rate of electricity generation increase and decrease between two adjacent time slices in order to account for @@ -266,7 +266,7 @@ def ramp_up_day_constraint( is the beginning of the same season, :math:`(s,d_{first})` .. math:: - :label: ramp_upDay + :label: ramp_up_day \frac{ \sum_{I,O} \mathbf{FO}_{r,p,s_{next},d_{next},i,t,v,o} @@ -282,7 +282,7 @@ def ramp_up_day_constraint( \leq R_{r,t} \cdot \Delta H_{r,p,s,d,s_{next},d_{next}} \cdot CAP_{r,p,t,v} \cdot C2A_{r,t} \\ - \forall \{r, p, s, d, t, v\} \in \Theta_{\text{ramp_upDay}} + \forall \{r, p, s, d, t, v\} \in \Theta_{\text{ramp_up_day}} \\ \text{where: } \Delta H_{r,p,s,d,s_{next},d_{next}} = \frac{24}{2} \left ( \frac{SEG_{r,p,s,d}}{\sum_{D} SEG_{r,p,s,d'}} + @@ -363,11 +363,11 @@ def ramp_down_day_constraint( ) -> ExprLike: r""" - Similar to the :code`ramp_upDay` constraint, we use the :code:`ramp_downDay` + Similar to the :code`ramp_up_day` constraint, we use the :code:`ramp_down_day` constraint to limit ramp down rates between any two adjacent time slices. .. math:: - :label: ramp_downDay + :label: ramp_down_day \frac{ \sum_{I,O} \mathbf{FO}_{r,p,s,d,i,t,v,o} @@ -383,7 +383,7 @@ def ramp_down_day_constraint( \leq R_{r,t} \cdot \Delta H_{r,p,s,d,s_{next},d_{next}} \cdot CAP_{r,p,t,v} \cdot C2A_{r,t} \\ - \forall \{r, p, s, d, t, v\} \in \Theta_{\text{ramp_downDay}} + \forall \{r, p, s, d, t, v\} \in \Theta_{\text{ramp_down_day}} """ s_next, d_next = model.time_next[p, s, d] @@ -452,7 +452,7 @@ def ramp_up_season_constraint( ) -> ExprLike: r""" Constrains the ramp up rate of activity between time slices at the boundary - of sequential seasons. Same as ramp_upDay but only applies to the boundary + of sequential seasons. Same as ramp_up_day but only applies to the boundary between sequential seasons, i.e., :math:`(s^{seq},d_{last})` to :math:`(s^{seq}_{next},d_{first})` and :math:`s^{seq}_{next}` is based on the TimeSequential table rather than the time_season table. @@ -525,7 +525,7 @@ def ramp_down_season_constraint( ) -> ExprLike: r""" Constrains the ramp down rate of activity between time slices at the boundary - of sequential seasons. Same as ramp_downDay but only applies to the boundary + of sequential seasons. Same as ramp_down_day but only applies to the boundary between sequential seasons, i.e., :math:`(s^{seq},d_{last})` to :math:`(s^{seq}_{next},d_{first})` and :math:`s^{seq}_{next}` is based on the TimeSequential table rather than the time_season table. diff --git a/temoa/data_processing/README.md b/temoa/data_processing/README.md index dd3006e70..4388d7e19 100644 --- a/temoa/data_processing/README.md +++ b/temoa/data_processing/README.md @@ -13,6 +13,7 @@ This folder contains files used to manage Temoa output data processing and visua Python script that queries database output tables to create an Excel file containing scenario-specific results. **Usage:** + ```bash uv run python temoa/data_processing/db_to_excel.py -i path/to/database.sqlite -s scenario_name ``` @@ -24,11 +25,13 @@ uv run python temoa/data_processing/db_to_excel.py -i path/to/database.sqlite -s Python script that creates Graphviz diagrams for visualizing the energy system network. **Basic usage** - View the full energy system map: + ```bash uv run python temoa/data_processing/make_graphviz.py -i data_files/temoa_utopia.sqlite ``` **Advanced usage** - Capacitated flow graph for a specific period: + ```bash uv run python temoa/data_processing/make_graphviz.py \ -i data_files/temoa_utopia.sqlite \ @@ -39,6 +42,7 @@ uv run python temoa/data_processing/make_graphviz.py \ ``` **Options:** + - `-i` : Input database file path - `-r` : Region name - `-s` : Scenario name @@ -46,6 +50,7 @@ uv run python temoa/data_processing/make_graphviz.py \ - `-y` : Specific year to visualize For all available options: + ```bash uv run python temoa/data_processing/make_graphviz.py --help ``` @@ -53,6 +58,7 @@ uv run python temoa/data_processing/make_graphviz.py --help ## Output Files The scripts generate output files in the current directory or a specified output location. Graphviz creates both: + - **SVG/PNG files** - Viewable images of the network - **DOT files** - Source files for Graphviz (useful for debugging and archiving) From 5e582c2f6090c6b0e28eb10353dfe03b57495792 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 19 Nov 2025 09:26:13 -0500 Subject: [PATCH 346/587] docs: fixing sphinx warnings and polishing --- docs/source/conf.py | 9 +- docs/source/mathematical_formulation.rst | 114 +++++++++++------------ docs/source/preface.rst | 7 ++ docs/source/quick_start.rst | 70 +++++--------- docs/source/visualization.rst | 8 +- 5 files changed, 100 insertions(+), 108 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index af224d437..4557621d0 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -37,7 +37,7 @@ 0 ] # '4.0.0a1.dev20251113' -> '4.0.0a1' # The full version, including alpha/beta/rc tags -release = cast(str, project_metadata['version']) +release = str(project_metadata['version']) # -- General configuration --------------------------------------------------- @@ -91,6 +91,13 @@ # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' +# Suppress warnings for duplicate labels and objects (intentional due to file inclusion and autodoc) +suppress_warnings = [ + 'ref.duplicate', # Duplicate labels between included RST files + 'autosummary', # Autodoc duplicate object descriptions + 'ref.footnote', # Unreferenced footnotes +] + # -- Options for HTML output ------------------------------------------------- diff --git a/docs/source/mathematical_formulation.rst b/docs/source/mathematical_formulation.rst index e8f834e22..eb9e984bf 100644 --- a/docs/source/mathematical_formulation.rst +++ b/docs/source/mathematical_formulation.rst @@ -105,9 +105,9 @@ Conventions \cdot \text{SEG}_{s, d} \right ) \cdot \textbf{CAP}_{r, t, v} - = + = \sum_{I, O} \textbf{FO}_{r, p, s, d,i, t, v, o} - + + + \sum_{I, O} \textbf{CUR}_{r, p, s, d, i, t, v, o} \\ @@ -337,9 +337,9 @@ the :code:`Capacity` :eq:`Capacity` Constraint: \cdot \text{SEG}_{s, d} \right ) \cdot \textbf{CAP}_{r, t, v} - = + = \sum_{I, O} \textbf{FO}_{r, p, s, d,i, t, v, o} - + + + \sum_{I, O} \textbf{CUR}_{r, p, s, d, i, t, v, o} \\ @@ -431,7 +431,7 @@ and will provide the user a warning with pointed debugging information. .. _capacity_factor_tech: capacity_credit -^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^ :math:`{CC}_{r \in R, p \in P, t \in T, v \in V}` @@ -441,7 +441,7 @@ electricity demand occurs. This parameter is used in the :math:`reserve_margin` constraint. capacity_factor_tech -^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^ :math:`{CFT}_{r \in R, s \in S, d \in D, t \in T}` @@ -449,7 +449,7 @@ Temoa indexes the :code:`capacity_factor_tech` parameter by season, time-of-day, and technology. capacity_factor_process -^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^ :math:`{CFP}_{r \in R, s \in S, d \in D, t \in T, v \in V}` @@ -492,7 +492,7 @@ used 100% of the time?" cost_fixed -^^^^^^^^^ +^^^^^^^^^^ :math:`{CF}_{r \in R, p \in P, t \in T, v \in V}` @@ -510,7 +510,7 @@ Cap}`). cost_invest -^^^^^^^^^^ +^^^^^^^^^^^ :math:`{CI}_{r \in R, t \in T, v \in P}` @@ -523,7 +523,7 @@ only used in the default objective function (:math:`\tfrac{Dollars}{Unit Cap}`). cost_variable -^^^^^^^^^^^^ +^^^^^^^^^^^^^ :math:`{CV}_{r \in R, p \in P,t \in T,v \in V}` @@ -533,7 +533,7 @@ of the process. construction_input -^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^ :math:`{CON}_{r \in R, i \in C^p,t \in T \setminus T^u,v \in V}` @@ -593,7 +593,7 @@ DDD must be 1. demand_specific_distribution -^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :math:`{DSD}_{r \in R, s \in S, d \in D, c \in C^d}` @@ -608,7 +608,7 @@ in the Demand constraint. emission_activity -^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^ :math:`{EAC}_{e \in C_e,\{r,i,t,v,o\} \in \Theta_{\text{efficiency}}}` @@ -623,7 +623,7 @@ to account for emissions per unit activity, but it more accurately describes emission_embodied -^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^ :math:`{EE}_{r \in R,t \in T \setminus T^u, v \in V,e \in C_e}` @@ -633,7 +633,7 @@ over each year in the deployment vintage. emission_end_of_life -^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^ :math:`{EEOL}_{r \in R,t \in T \setminus T^u, v \in V,e \in C_e}` @@ -643,7 +643,7 @@ life occur evenly over years in that period. end_of_life_output -^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^ :math:`{EOLO}_{r \in R,t \in T \setminus T^u, v \in V,o \in C_p}` @@ -663,7 +663,7 @@ life occur evenly over years in that period. existing_capacity -^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^ :math:`{ECAP}_{r \in R, t \in T, v \in \text{P}^e}` @@ -685,7 +685,7 @@ with the exception of an investment cost. .. _GDR: global_discount_rate -^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^ :math:`{GDR}` @@ -710,7 +710,7 @@ the vintage year, not as a string of payments. The Global Discount Rate is entered in the metadata_real table in the database. growth_rate_max -^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^ :math:`{GRM}_{r \in R, t \in T}` @@ -720,7 +720,7 @@ but rather across all vintages of a given technology. growth_rate_seed -^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^ :math:`{GRS}_{r \in R, t \in T}` @@ -730,7 +730,7 @@ capacity seed in subsequent time periods. loan_lifetime_process -^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^ :math:`{LLP}_{r \in R, t \in T, v \in P}` @@ -744,7 +744,7 @@ assigns the technology lifetime to the loan period in :code:`temoa/components/te loan_lifetime_tech -^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^ :math:`{LLT}_{r \in R, t \in T}` @@ -754,7 +754,7 @@ vintages of a given technology are assumed to have the same loan term, then lifetime_process -^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^ :math:`{LTP}_{r \in R, t \in T, v \in P}` @@ -762,7 +762,7 @@ This parameter specifies the total useful life of a given process in years. lifetime_tech -^^^^^^^^^^^^ +^^^^^^^^^^^^^ :math:`{LTT}_{r \in R, t \in T}` @@ -772,7 +772,7 @@ lifetime, then :code:`LifeTimeTech` can be used instead of :code:`LifeTimeProces linked_techs -^^^^^^^^^^^ +^^^^^^^^^^^^ :math:`{LIT}_{r \in R, t \in T, e \in C^e, t \in T}` @@ -787,7 +787,7 @@ which is represented by the second :code:`t` index. loan_rate -^^^^^^^^ +^^^^^^^^^ :math:`{LR}_{r \in r, t \in T, v \in V}` @@ -799,7 +799,7 @@ loan rate is accessible in the metadata_real table in the database. max_activity -^^^^^^^^^^^ +^^^^^^^^^^^^ :math:`{MAA}_{r \in R, p \in P, t \in T}` @@ -810,7 +810,7 @@ is used in the :code:`max_activity_constraint`. max_capacity -^^^^^^^^^^^ +^^^^^^^^^^^^ :math:`{MAC}_{r \in R, p \in P, t \in T}` @@ -821,7 +821,7 @@ used in the :code:`max_capacity_constraint`. max_capacity_sum -^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^ :math:`{MCS}_{t \in T}` @@ -833,7 +833,7 @@ in the :code:`tech_capacity_max` subset. This parameter is used in the max_resource -^^^^^^^^^^^ +^^^^^^^^^^^^ :math:`{MAR}_{r \in R, t \in T}` @@ -847,7 +847,7 @@ model time period. min_activity -^^^^^^^^^^^ +^^^^^^^^^^^^ :math:`{MIA}_{r \in R, p \in P, t \in T}` @@ -858,7 +858,7 @@ is used in the :code:`min_activity_constraint`. min_capacity -^^^^^^^^^^^ +^^^^^^^^^^^^ :math:`{MIC}_{r \in R, p \in P,t \in T}` @@ -869,7 +869,7 @@ used in the :code:`min_capacity_constraint`. min_capacity_sum -^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^ :math:`{MCS}_{t \in T}` @@ -879,7 +879,7 @@ This parameter is used in the :code:`min_activityGroup_constraint`. min_gen_group_target -^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^ :math:`{MGT}_{r \in R}` @@ -890,7 +890,7 @@ in the :code:`min_activityGroup_constraint`. min_gen_group_weight -^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^ :math:`{MGW}_{r \in R, t \in T}` @@ -901,7 +901,7 @@ technology-specific activity shares that can count towards meeting the myopic_base_year -^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^ :math:`MBY` @@ -914,7 +914,7 @@ table in the database. planning_reserve_margin -^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^ :math:`{PRM}_{r \in R}` @@ -928,7 +928,7 @@ to estimate the peak electricity demand. This parameter is used in ramp_down -^^^^^^^^ +^^^^^^^^^ :math:`{RMD}_{r \in R, t \in T}` @@ -944,7 +944,7 @@ slice in the next season. ramp_up -^^^^^^ +^^^^^^^ :math:`{RMU}_{r \in R, t \in T}` @@ -960,7 +960,7 @@ slice in the next season. resource_bound -^^^^^^^^^^^^^ +^^^^^^^^^^^^^^ :math:`{RSC}_{r \in R, p \in P, c \in C_p}` @@ -976,7 +976,7 @@ cumulative resource consumption across all model time periods. .. _segment_fraction: segment_fraction -^^^^^^^ +^^^^^^^^^^^^^^^^ :math:`{SEG}_{s \in S,d \in D}` @@ -986,7 +986,7 @@ each combination of season and time of day. The sum of all combinations within storage_duration -^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^ :math:`{SD}_{r \in R, t \in T^{S}}` @@ -996,7 +996,7 @@ until empty. The parameter value defaults to 4 hours if not specified by the use storage_init -^^^^^^^^^^^ +^^^^^^^^^^^^ :math:`{SI}_{r \in R, t \in T^{S}, v \in P}` @@ -1024,7 +1024,7 @@ across all model time slices. This parameter is used in tech_input_split_average -^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^ :math:`{TISA}_{r \in R, p \in P, i \in C_p, t \in T}` @@ -1036,7 +1036,7 @@ parameter is used in :code:`TechInputSplitAverage_constraint`. tech_output_split -^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^ :math:`{TOS}_{t \in T, o \in C_c}` @@ -1048,7 +1048,7 @@ across all model time slices. This parameter is used in \*loan_annualize -^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^ :math:`{LA}_{r \in R, t \in T, v \in P}` @@ -1065,11 +1065,11 @@ calculated via the formula: model_process_life -^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^ :math:`{MPL}_{r \in R, p \in P, t \in T, v \in P}` -The :code:`model_process_life` parameter is internally-derived by the model calcuated in +The :code:`model_process_life` parameter is internally-derived by the model calculated in :code:`ParamModelProcessLife_rule` and which makes use of the :code:`lifetime_process` parameter. For a given technology vintage in a given model time period, it returns the lesser of the period length and the remaining process lifetime. This parameter is used @@ -1078,7 +1078,7 @@ a given time period. \*period_length -^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^ :math:`{LEN}_{p \in P}` @@ -1118,7 +1118,7 @@ specifically not defined for the final element in :math:`\text{P}^f`. \*process_life_frac -^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^ :math:`{PLF}_{r \in R, p \in P,t \in T,v \in P}` @@ -1175,7 +1175,7 @@ Variables ":math:`NCAP_{r,t,v}`","v_new_capacity",":math:`\mathbb{R}^+_0`","New deployed capacity" v_flow_out -^^^^^^^^^ +^^^^^^^^^^ :math:`FO_{r,p,s,d,i,t,v,o}` @@ -1188,7 +1188,7 @@ process can be calculated as /EFF_{c,t,v,o}`. v_flow_out_annual -^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^ :math:`FOA_{r,p,i,t,v,o}` @@ -1220,7 +1220,7 @@ the excess production in the :code:`CommodityBalanceAnnual_constraint`. v_flex_annual -^^^^^^^^^^^^ +^^^^^^^^^^^^^ :math:`FLXA_{r,p,i,t,v,o}` @@ -1255,7 +1255,7 @@ curtailment is 3 units (0.8 x 10 - 5). v_flow_in_storage -^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^ :math:`FIS_{r,p,s,d,i,t,v,o}` @@ -1275,7 +1275,7 @@ constrains the capacity variable to be able to meet the total commodity flow out of that process in all time slices in which it is active :eq:`Capacity`. v_capacity_available_by_period_and_tech -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :math:`CAPAVL_{r,p,t}` @@ -1285,7 +1285,7 @@ are not warranted (e.g. in calculating the maximum or minimum total capacity allowed in a given time period). v_storage_init -^^^^^^^^^^^^^ +^^^^^^^^^^^^^^ :math:`SI_{r,t,v}` @@ -1296,7 +1296,7 @@ this value also determines the ending storage charge level at the end of the last time slice within each model time period. v_storage_level -^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^ :math:`SL_{r,p,s,d,t,v}` diff --git a/docs/source/preface.rst b/docs/source/preface.rst index ae9c79fc6..210d46c21 100644 --- a/docs/source/preface.rst +++ b/docs/source/preface.rst @@ -99,3 +99,10 @@ inconsistency, or general "that could be improved", we want to hear about it. If you are a software developer-type, feel free to open an issue on our `GitHub Issue tracker`_\ . If you would rather not create a GitHub account, feel free to let us know the issue on our `mailing list`_\ . + +.. _PDF: https://temoacloud.com/wp-content/uploads/2020/02/toolsforenergymodeloptimizationandanalysistemoa.pdf +.. _HTML: http://temoaproject.org/docs/ +.. _GitHub Issues: https://github.com/TemoaProject/temoa/issues +.. _GitHub Issue tracker: https://github.com/TemoaProject/temoa/issues +.. _mailing list: https://groups.google.com/forum/#!forum/temoa-project + diff --git a/docs/source/quick_start.rst b/docs/source/quick_start.rst index 83f8c0085..f7c2d185b 100644 --- a/docs/source/quick_start.rst +++ b/docs/source/quick_start.rst @@ -8,10 +8,18 @@ written in `Python `_. Consequently, Temoa will run on Linux, Mac, Windows, or any operating system that Pyomo supports. There are several open source software elements required to run Temoa. -**Using pip (Recommended for most users)**: +**Using pip**: The standard way to install Temoa: +First, it is highly recommended to use a Python virtual environment to manage dependencies: + +.. parsed-literal:: + $ python -m venv temoa_env + $ source temoa_env/bin/activate + +Then, install Temoa: + .. parsed-literal:: # Install from PyPI (when 4.0 is released) $ pip install temoa @@ -20,8 +28,8 @@ The standard way to install Temoa: $ pip install --index-url https://temoaproject.github.io/temoa-nightlies/simple/ temoa --extra-index-url https://pypi.org/simple/ # Get started - $ temoa tutorial my_first_model - $ temoa run my_first_model.toml + $ python -m temoa tutorial my_first_model + $ python -m temoa run my_first_model.toml **Using uv (Alternative)**: @@ -31,12 +39,17 @@ For faster dependency resolution: # Install uv $ curl -LsSf https://astral.sh/uv/install.sh | sh - # Install Temoa from nightlies - $ uv pip install --index-url https://temoaproject.github.io/temoa-nightlies/simple/ temoa --extra-index-url https://pypi.org/simple/ + # Create a uv initialized virtual environment + $ uv init + $ cd + + + # add Temoa from nightlies to pyproject.toml + $ uv add temoa --default-index https://pypi.temoaproject.org/simple --index https://pypi.org/simple # Get started - $ temoa tutorial my_first_model - $ temoa run my_first_model.toml + $ uv run temoa tutorial my_first_model + $ uv run temoa run my_first_model.toml **For Contributors (Development Installation)**: @@ -50,9 +63,6 @@ If you want to contribute to Temoa or modify the code: # Install in development mode with uv (recommended) $ uv sync --all-extras --dev - # Or with pip - $ pip install -e ".[docs,plotting]" - For detailed contribution guidelines, see CONTRIBUTING.md in the repository. Solvers @@ -71,41 +81,6 @@ Each of the respective websites contains installation instructions for the indiv solvers. For those wishing to run the internal tests on Temoa, the :code:`CBC` solver is required. -There are three ways to run the model, each of which is detailed below. Note that -the example commands utilize 'temoa_utopia', a commonly used test case for ESOMs. - -Obtaining Temoa ---------------- - -Now that you have functioning environment, you need to obtain the source code -for Temoa. There are a couple of options for obtaining and running Temoa from -GitHub. If you want to simply run the model, you can download Temoa from GitHub -as a zip file. Navigate to our `Github repo `__, -and click the green ā€˜clone or download’ button near the top-right corner. Select -ā€˜Download ZIP,’ and you can download the entire Temoa :code:`main` (our main branch) -to your local machine. The second option creates a local copy of the model source -code in our GitHub repository. This is a two step process: first install git and -then ā€˜clone’ the repository. Under Linux, git can be installed through the default -package manager. Git for Windows and Mac can be downloaded from the `Git website -`_. To clone the Temoa repository, navigate to -the directory where you want the model to reside and type the following from the -prompt: - -.. parsed-literal:: - $ git clone https://github.com/TemoaProject/temoa/ - -Note that cloning the repository will supply the latest version of the code, and -allow you to archive changes to the code and data in your own local git -repository. - -A few basic input data files are included in the :code:`temoa/data_files`` folder. -Additional Temoa-compatible datasets are available in `this separate GitHub -repo `_. - -The installation procedures above are meant to be generic and should work across -different platforms. Nonetheless, system-specific ambiguities and unexpected -conditions inevitably arise. Please use -`GitHub Issues `_ to ask for help. Running Temoa ------------- @@ -329,12 +304,13 @@ may be produced by endogenous decisions in myopic runs. Commodity Network Visualization ------------------------------- + The output of the Source Tracing operation can be visualized by enabling the commodity network plots in the config file. This will add a set of region-period specific html files to the Outputs folder. These files *should* be open-able in any web browser. (See the note in the main `README.md` for trouble with Windows OS systems). -.. Figure:: images/utopia_commodity_network.png +.. figure:: images/utopia_commodity_network.png :align: center :figclass: center :figwidth: 60% @@ -353,4 +329,4 @@ The color legend for Commodity Networks is as follows: * Red arc: Demand-Side Orphan (shown, but suppressed when model built) * Green arc: Any Tech with a Negative Variable Cost -============= +.. _sqlite: https://www.sqlite.org/ diff --git a/docs/source/visualization.rst b/docs/source/visualization.rst index dad14f652..b4dbebc87 100644 --- a/docs/source/visualization.rst +++ b/docs/source/visualization.rst @@ -31,7 +31,7 @@ In the command above, note that we have to point the Graphviz module to the :code:`temoa_utopia` database file, which resides in the :code:`data_files` directory. The resultant system map will look like this: -.. Figure:: images/simple_model.* +.. figure:: images/simple_model.* :align: center :figclass: center :figwidth: 60% @@ -85,7 +85,7 @@ commodity or technology. For example: Output Graphs ------------- -Temoa can also be used to generate output graphs using `matplotlib `. +Temoa can also be used to generate output graphs using `matplotlib `_. From the command line, navigate to the :code:`data_processing` folder and execute the following command: .. parsed-literal:: @@ -108,5 +108,7 @@ Here is the result: associated with each technology in the electric sector from the 'test_run' scenario drawn from the 'temoa_utopia' database. Because the :code:`super` flag was specified, technologies are grouped together based on user-specified - categories in the :code:`tech_category`` column of the :code:`technologies` + categories in the :code:`tech_category` column of the :code:`technologies` table of the database. + +.. _Graphviz: http://www.graphviz.org/ From 8d9cc2a632ddd09fb4cfdd4e3303f4c6c3a0c126 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 20 Nov 2025 22:20:31 -0500 Subject: [PATCH 347/587] chore: enable TC (type-checking) linting rules in pyproject.toml --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 9c3174096..316a19da1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -96,7 +96,8 @@ select = [ "I", # isort "B", # flake8-bugbear "N", # flake8-naming - "G004", # logging-f-string + "G004",, # logging-f-string + "TC", # flake8-type-checking "UP", # pyupgrade ] ignore = [ From 7c4efe00380c013efa0bb22815c481385a569e1b Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 20 Nov 2025 22:20:59 -0500 Subject: [PATCH 348/587] refactor: move type-only imports into TYPE_CHECKING blocks (TC001, TC003) - Moved 239 type-only imports into TYPE_CHECKING blocks - Added TYPE_CHECKING imports where needed - Quoted type expressions in cast() calls for forward references - Optimizes runtime import overhead --- temoa/_internal/exchange_tech_cost_ledger.py | 12 +++--- temoa/_internal/table_data_puller.py | 22 +++++------ temoa/_internal/table_writer.py | 20 +++++----- temoa/_internal/temoa_sequencer.py | 5 ++- temoa/components/capacity.py | 2 +- temoa/components/commodities.py | 20 +++++----- temoa/components/costs.py | 6 +-- temoa/components/emissions.py | 4 +- temoa/components/flows.py | 26 ++++++------- temoa/components/geography.py | 16 ++++---- temoa/components/limits.py | 8 ++-- temoa/components/operations.py | 4 +- temoa/components/reserves.py | 2 +- temoa/components/storage.py | 2 +- temoa/components/technology.py | 8 ++-- temoa/components/utils.py | 4 +- temoa/core/model.py | 7 +++- temoa/data_io/hybrid_loader.py | 12 +++--- temoa/data_processing/make_output_plots.py | 10 +++-- temoa/model_checking/commodity_graph.py | 16 ++++---- temoa/model_checking/network_model_data.py | 40 ++++++++++---------- temoa/model_checking/validators.py | 4 +- temoa/utilities/graph_utils.py | 8 ++-- temoa/utilities/set_spitter.py | 3 +- temoa/utilities/visualizer.py | 8 ++-- tests/test_emission_results.py | 2 +- tests/test_exchange_cost_ledger.py | 20 +++++----- tests/test_full_runs.py | 5 ++- tests/test_network_model_data.py | 16 ++++---- tests/test_pricing_check.py | 12 +++--- tests/test_source_check.py | 6 +-- tests/test_validators.py | 22 ++++++----- 32 files changed, 188 insertions(+), 164 deletions(-) diff --git a/temoa/_internal/exchange_tech_cost_ledger.py b/temoa/_internal/exchange_tech_cost_ledger.py index 83ce1b1e9..c19b5bf31 100644 --- a/temoa/_internal/exchange_tech_cost_ledger.py +++ b/temoa/_internal/exchange_tech_cost_ledger.py @@ -14,10 +14,10 @@ from pyomo.common.numeric_types import value -from temoa.core.model import TemoaModel -from temoa.types.core_types import Period, Region, Technology, Vintage if TYPE_CHECKING: + from temoa.types.core_types import Period, Region, Technology, Vintage + from temoa.core.model import TemoaModel from tests.utilities.namespace_mock import Namespace @@ -54,7 +54,7 @@ def add_cost_record( add a cost associated with an exchange tech :return: """ - r1, r2 = (cast(Region, r) for r in link.split('-')) + r1, r2 = (cast('Region', r) for r in link.split('-')) if not r1 and r2: raise ValueError(f'problem splitting region-region: {link}') # add to the "seen" records for appropriate cost type @@ -74,10 +74,10 @@ def get_use_ratio( """ # Cast to TemoaModel for type checking - at runtime this will be either TemoaModel or Namespace # Both have the same attributes, but mypy doesn't know about Namespace's dynamic attributes - model = cast(TemoaModel, self.model) + model = cast('TemoaModel', self.model) # need to temporarily reconstitute the names - rr1 = cast(Region, '-'.join([exporter, importer])) - rr2 = cast(Region, '-'.join([importer, exporter])) + rr1 = cast('Region', '-'.join([exporter, importer])) + rr2 = cast('Region', '-'.join([importer, exporter])) if any( ( period >= vintage + value(model.lifetime_process[rr1, tech, vintage]), diff --git a/temoa/_internal/table_data_puller.py b/temoa/_internal/table_data_puller.py index b78ac7e8d..23b45310e 100644 --- a/temoa/_internal/table_data_puller.py +++ b/temoa/_internal/table_data_puller.py @@ -184,7 +184,7 @@ def poll_flow_results(model: TemoaModel, epsilon: float = 1e-5) -> dict[FI, dict ) for s in model.time_season[v]: for d in model.time_of_day: - fi = FI(r, v, s, d, i, t, v, cast(Commodity, 'construction_input')) + fi = FI(r, v, s, d, i, t, v, cast('Commodity', 'construction_input')) flow = annual * value(model.segment_fraction[v, s, d]) if abs(flow) < epsilon: continue @@ -200,7 +200,7 @@ def poll_flow_results(model: TemoaModel, epsilon: float = 1e-5) -> dict[FI, dict ) for s in model.time_season[p]: for d in model.time_of_day: - fi = FI(r, p, s, d, cast(Commodity, 'end_of_life_output'), t, v, o) + fi = FI(r, p, s, d, cast('Commodity', 'end_of_life_output'), t, v, o) flow = annual * value(model.segment_fraction[p, s, d]) if abs(flow) < epsilon: continue @@ -349,7 +349,7 @@ def poll_cost_results( ) else: # The period `p` for an investment cost is its vintage `v`. - key = (cast(Region, r), cast(Period, v), cast(Technology, t), cast(Vintage, v)) + key = (cast('Region', r), cast('Period', v), cast('Technology', t), cast('Vintage', v)) entries[key].update( {CostType.D_INVEST: model_loan_cost, CostType.INVEST: undiscounted_cost} ) @@ -660,28 +660,28 @@ def poll_emissions( flows[ei] = 0.0 continue # screen to see if there is an associated cost - cost_index = (ei.r, cast(Period, ei.v), ei.e) + cost_index = (ei.r, cast('Period', ei.v), ei.e) if cost_index not in model.cost_emission: continue undiscounted_emiss_cost = ( embodied_flows[ei] - * model.cost_emission[ei.r, cast(Period, ei.v), ei.e] + * model.cost_emission[ei.r, cast('Period', ei.v), ei.e] * model.period_length[ - cast(Period, ei.v) + cast('Period', ei.v) ] # treat as fixed cost distributed over construction period ) discounted_emiss_cost = costs.fixed_or_variable_cost( cap_or_flow=embodied_flows[ei], - cost_factor=value(model.cost_emission[ei.r, cast(Period, ei.v), ei.e]), + cost_factor=value(model.cost_emission[ei.r, cast('Period', ei.v), ei.e]), cost_years=model.period_length[ - cast(Period, ei.v) + cast('Period', ei.v) ], # treat as fixed cost distributed over construction period global_discount_rate=global_discount_rate, p_0=p_0_true, - p=cast(Period, ei.v), + p=cast('Period', ei.v), ) - ud_costs[ei.r, cast(Period, ei.v), ei.t, ei.v] += float(value(undiscounted_emiss_cost)) - d_costs[ei.r, cast(Period, ei.v), ei.t, ei.v] += float(value(discounted_emiss_cost)) + ud_costs[ei.r, cast('Period', ei.v), ei.t, ei.v] += float(value(undiscounted_emiss_cost)) + d_costs[ei.r, cast('Period', ei.v), ei.t, ei.v] += float(value(discounted_emiss_cost)) ########################### # End of life Emissions diff --git a/temoa/_internal/table_writer.py b/temoa/_internal/table_writer.py index d58d0ad3b..0408b1f31 100644 --- a/temoa/_internal/table_writer.py +++ b/temoa/_internal/table_writer.py @@ -7,16 +7,12 @@ import sqlite3 import sys from collections import defaultdict -from collections.abc import Iterable from importlib import resources from logging import getLogger -from pathlib import Path from typing import TYPE_CHECKING, cast from pyomo.core import value -from pyomo.opt import SolverResults -from temoa._internal.data_brick import DataBrick from temoa._internal.exchange_tech_cost_ledger import CostType from temoa._internal.table_data_puller import ( EI, @@ -31,13 +27,17 @@ poll_objective, poll_storage_level_results, ) -from temoa.core.config import TemoaConfig -from temoa.core.model import TemoaModel from temoa.core.modes import TemoaMode -from temoa.extensions.monte_carlo.mc_run import ChangeRecord -from temoa.types.core_types import Period, Region, Technology, Vintage if TYPE_CHECKING: + from temoa._internal.data_brick import DataBrick + from temoa.extensions.monte_carlo.mc_run import ChangeRecord + from pyomo.opt import SolverResults + from temoa.types.core_types import Period, Region, Technology, Vintage + from temoa.core.model import TemoaModel + from temoa.core.config import TemoaConfig + from pathlib import Path + from collections.abc import Iterable pass """ @@ -272,9 +272,9 @@ def write_emissions(self, iteration: int | None = None) -> None: if abs(val) < self.epsilon: continue if hasattr(ei, 'p'): # emissions from flows - entry = (scenario, ei.r, sector, cast(int, ei.p), ei.e, ei.t, ei.v, val) + entry = (scenario, ei.r, sector, cast('int', ei.p), ei.e, ei.t, ei.v, val) else: # embodied emissions - entry = (scenario, ei.r, sector, cast(int, ei.v), ei.e, ei.t, ei.v, val) + entry = (scenario, ei.r, sector, cast('int', ei.v), ei.e, ei.t, ei.v, val) data.append(entry) qry = f'INSERT INTO output_emission VALUES {_marks(8)}' self.con.executemany(qry, data) diff --git a/temoa/_internal/temoa_sequencer.py b/temoa/_internal/temoa_sequencer.py index 6e8bf991b..d35c6254c 100644 --- a/temoa/_internal/temoa_sequencer.py +++ b/temoa/_internal/temoa_sequencer.py @@ -9,7 +9,6 @@ import sqlite3 from logging import getLogger -import pyomo.opt from temoa._internal.run_actions import ( build_instance, @@ -35,6 +34,10 @@ MIN_PYTHON_MAJOR, MIN_PYTHON_MINOR, ) +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + import pyomo.opt logger = getLogger(__name__) diff --git a/temoa/components/capacity.py b/temoa/components/capacity.py index 69aa1d02d..3506cfc35 100644 --- a/temoa/components/capacity.py +++ b/temoa/components/capacity.py @@ -18,9 +18,9 @@ from deprecated import deprecated from pyomo.environ import value -from temoa.types import ExprLike if TYPE_CHECKING: + from temoa.types import ExprLike from temoa.core.model import TemoaModel from temoa.types import ( Period, diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index 8d7b4f723..cb363772e 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -18,12 +18,12 @@ from pyomo.environ import value -from temoa.types.core_types import Season, Technology, TimeOfDay, Vintage if TYPE_CHECKING: + from ..types import Commodity, ExprLike, Period, Region + from temoa.types.core_types import Season, Technology, TimeOfDay, Vintage from temoa.core.model import TemoaModel -from ..types import Commodity, ExprLike, Period, Region from .utils import get_variable_efficiency logger = getLogger(name=__name__) @@ -445,14 +445,14 @@ def commodity_balance_constraint( if (r, p, c) in model.export_regions: consumed += sum( model.v_flow_out[r + '-' + reg, p, s, d, c, s_t, s_v, S_o] - / get_variable_efficiency(model, cast(Region, r + '-' + reg), p, s, d, c, s_t, s_v, S_o) + / get_variable_efficiency(model, cast('Region', r + '-' + reg), p, s, d, c, s_t, s_v, S_o) for reg, s_t, s_v, S_o in model.export_regions[r, p, c] if s_t not in model.tech_annual ) consumed += sum( value(model.segment_fraction[p, s, d]) * model.v_flow_out_annual[r + '-' + reg, p, c, s_t, s_v, S_o] - / get_variable_efficiency(model, cast(Region, r + '-' + reg), p, s, d, c, s_t, s_v, S_o) + / get_variable_efficiency(model, cast('Region', r + '-' + reg), p, s, d, c, s_t, s_v, S_o) for reg, s_t, s_v, S_o in model.export_regions[r, p, c] if s_t in model.tech_annual ) @@ -588,9 +588,9 @@ def annual_commodity_balance_constraint( # export of commodity c from region r to other regions if (r, p, c) in model.export_regions: consumed += sum( - model.v_flow_out[cast(Region, r + '-' + s_r), p, s_s, s_d, c, s_t, s_v, s_o] + model.v_flow_out[cast('Region', r + '-' + s_r), p, s_s, s_d, c, s_t, s_v, s_o] / get_variable_efficiency( - model, cast(Region, r + '-' + s_r), p, s_s, s_d, c, s_t, s_v, s_o + model, cast('Region', r + '-' + s_r), p, s_s, s_d, c, s_t, s_v, s_o ) for s_s in model.time_season[p] for s_d in model.time_of_day @@ -598,8 +598,8 @@ def annual_commodity_balance_constraint( if s_t not in model.tech_annual ) consumed += sum( - model.v_flow_out_annual[cast(Region, r + '-' + s_r), p, c, s_t, s_v, s_o] - / model.efficiency[cast(Region, r + '-' + s_r), c, s_t, s_v, s_o] + model.v_flow_out_annual[cast('Region', r + '-' + s_r), p, c, s_t, s_v, s_o] + / model.efficiency[cast('Region', r + '-' + s_r), c, s_t, s_v, s_o] for s_r, s_t, s_v, s_o in model.export_regions[r, p, c] if s_t in model.tech_annual ) @@ -607,14 +607,14 @@ def annual_commodity_balance_constraint( # import of commodity c from other regions into region r if (r, p, c) in model.import_regions: produced += sum( - model.v_flow_out[cast(Region, s_r + '-' + r), p, s_s, S_d, s_i, s_t, s_v, c] + model.v_flow_out[cast('Region', s_r + '-' + r), p, s_s, S_d, s_i, s_t, s_v, c] for s_s in model.time_season[p] for S_d in model.time_of_day for s_r, s_t, s_v, s_i in model.import_regions[r, p, c] if s_t not in model.tech_annual ) produced += sum( - model.v_flow_out_annual[cast(Region, s_r + '-' + r), p, s_i, s_t, s_v, c] + model.v_flow_out_annual[cast('Region', s_r + '-' + r), p, s_i, s_t, s_v, c] for s_r, s_t, s_v, s_i in model.import_regions[r, p, c] if s_t in model.tech_annual ) diff --git a/temoa/components/costs.py b/temoa/components/costs.py index b796cedc8..2810b8ea8 100644 --- a/temoa/components/costs.py +++ b/temoa/components/costs.py @@ -16,13 +16,13 @@ from typing import TYPE_CHECKING, Any from deprecated import deprecated -from pyomo.core import Expression, Var -from pyomo.core.base.component import ComponentData from pyomo.environ import quicksum, value -from temoa.types.core_types import Period, Region, Technology, Vintage if TYPE_CHECKING: + from pyomo.core import Expression, Var + from temoa.types.core_types import Period, Region, Technology, Vintage + from pyomo.core.base.component import ComponentData from temoa.core.model import TemoaModel from logging import getLogger diff --git a/temoa/components/emissions.py b/temoa/components/emissions.py index 414624514..552420e98 100644 --- a/temoa/components/emissions.py +++ b/temoa/components/emissions.py @@ -16,10 +16,10 @@ from pyomo.core import quicksum from pyomo.environ import value -from temoa.types import ExprLike -from temoa.types.core_types import Commodity, Period, Region, Season, Technology, TimeOfDay, Vintage if TYPE_CHECKING: + from temoa.types import ExprLike + from temoa.types.core_types import Commodity, Period, Region, Season, Technology, TimeOfDay, Vintage from temoa.core.model import TemoaModel diff --git a/temoa/components/flows.py b/temoa/components/flows.py index 4ebd16511..32015ee46 100644 --- a/temoa/components/flows.py +++ b/temoa/components/flows.py @@ -14,23 +14,23 @@ from logging import getLogger from typing import TYPE_CHECKING -from temoa.types.core_types import ( - Commodity, - Period, - Region, - Season, - Technology, - TimeOfDay, - Vintage, -) if TYPE_CHECKING: + from temoa.types.core_types import ( + Commodity, + Period, + Region, + Season, + Technology, + TimeOfDay, + Vintage, + ) + from temoa.types import ( + ActiveFlexAnnualSet, + ActiveFlowAnnualSet, + ) from temoa.core.model import TemoaModel -from temoa.types import ( - ActiveFlexAnnualSet, - ActiveFlowAnnualSet, -) logger = getLogger(__name__) diff --git a/temoa/components/geography.py b/temoa/components/geography.py index c105e8850..45134e4f6 100644 --- a/temoa/components/geography.py +++ b/temoa/components/geography.py @@ -12,7 +12,6 @@ from __future__ import annotations -from collections.abc import Iterable from logging import getLogger from typing import TYPE_CHECKING, cast @@ -20,10 +19,11 @@ from pyomo.environ import value if TYPE_CHECKING: + from temoa.types import ExprLike, Period, Region, Technology, Vintage + from collections.abc import Iterable from temoa.core.model import TemoaModel # Import type annotations -from temoa.types import ExprLike, Period, Region, Technology, Vintage logger = getLogger(name=__name__) @@ -37,7 +37,7 @@ def gather_group_regions(model: TemoaModel, region: Region) -> Iterable[Region]: if region == 'global': regions = list(model.regions) elif '+' in region: - regions = [cast(Region, r) for r in region.split('+')] + regions = [cast('Region', r) for r in region.split('+')] else: regions = [region] return regions @@ -59,7 +59,7 @@ def create_regional_indices(model: TemoaModel) -> list[Region]: if r_i == r_j: regional_indices.add(r_i) else: - regional_indices.add(cast(Region, r_i + '-' + r_j)) + regional_indices.add(cast('Region', r_i + '-' + r_j)) # dev note: Sorting these passed them to pyomo in an ordered container and prevents warnings return sorted(regional_indices) @@ -72,8 +72,8 @@ def regional_global_initialized_indices(model: TemoaModel) -> set[Region]: for n in range(1, len(model.regions) + 1): regional_perms = permutations(model.regions, n) for i in regional_perms: - indices.add(cast(Region, '+'.join(i))) - indices.add(cast(Region, 'global')) + indices.add(cast('Region', '+'.join(i))) + indices.add(cast('Region', 'global')) indices = indices.union(model.regional_indices) return indices @@ -138,8 +138,8 @@ def create_geography_sets(model: TemoaModel) -> None: raise ValueError(msg) region_from_str, region_to_str = r.split('-', 1) - region_from = cast(Region, region_from_str) - region_to = cast(Region, region_to_str) + region_from = cast('Region', region_from_str) + region_to = cast('Region', region_to_str) lifetime: float = value(model.lifetime_process[r, t, v]) for p in model.time_optimize: diff --git a/temoa/components/limits.py b/temoa/components/limits.py index 5efbafc16..01e85f96f 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -21,10 +21,10 @@ import temoa.components.geography as geography import temoa.components.technology as technology from temoa.components.utils import Operator, get_variable_efficiency, operator_expression -from temoa.types import ExprLike, Period, Region, Technology, Vintage -from temoa.types.core_types import Commodity, Season, TimeOfDay if TYPE_CHECKING: + from temoa.types import ExprLike, Period, Region, Technology, Vintage + from temoa.types.core_types import Commodity, Season, TimeOfDay from temoa.core.model import TemoaModel logger = getLogger(__name__) @@ -419,7 +419,7 @@ def limit_new_capacity_share_constraint( model.v_new_capacity[_r, _t, p] for _t in sub_group for _r in regions - if (_r, _t, cast(Vintage, p)) in model.process_periods + if (_r, _t, cast('Vintage', p)) in model.process_periods ) super_group = technology.gather_group_techs(model, g2) @@ -427,7 +427,7 @@ def limit_new_capacity_share_constraint( model.v_new_capacity[_r, _t, p] for _t in super_group for _r in regions - if (_r, _t, cast(Vintage, p)) in model.process_periods + if (_r, _t, cast('Vintage', p)) in model.process_periods ) share_lim = value(model.limit_new_capacity_share[r, p, g1, g2, op]) diff --git a/temoa/components/operations.py b/temoa/components/operations.py index bfb9bcc49..68c2aff73 100644 --- a/temoa/components/operations.py +++ b/temoa/components/operations.py @@ -17,10 +17,10 @@ from pyomo.environ import Constraint, value -from temoa.types import ExprLike -from temoa.types.core_types import Period, Region, Season, Technology, TimeOfDay, Vintage if TYPE_CHECKING: + from temoa.types import ExprLike + from temoa.types.core_types import Period, Region, Season, Technology, TimeOfDay, Vintage from temoa.core.model import TemoaModel logger = getLogger(__name__) diff --git a/temoa/components/reserves.py b/temoa/components/reserves.py index f27d87989..53ed95498 100644 --- a/temoa/components/reserves.py +++ b/temoa/components/reserves.py @@ -15,11 +15,11 @@ from pyomo.environ import Constraint, value -from temoa.types.core_types import Period, Region, Season, TimeOfDay from .utils import get_variable_efficiency if TYPE_CHECKING: + from temoa.types.core_types import Period, Region, Season, TimeOfDay from temoa.core.model import TemoaModel from temoa.types import ExprLike diff --git a/temoa/components/storage.py b/temoa/components/storage.py index 15316b431..7265e4ee9 100644 --- a/temoa/components/storage.py +++ b/temoa/components/storage.py @@ -17,10 +17,10 @@ from pyomo.environ import Constraint, value -from ..types import ExprLike, Period, Region, Season, Technology, TimeOfDay, Vintage from .utils import Operator, get_variable_efficiency, operator_expression if TYPE_CHECKING: + from ..types import ExprLike, Period, Region, Season, Technology, TimeOfDay, Vintage from temoa.core.model import TemoaModel diff --git a/temoa/components/technology.py b/temoa/components/technology.py index aa9d15a61..2fd431385 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -12,15 +12,15 @@ from __future__ import annotations -from collections.abc import Iterable from logging import getLogger from typing import TYPE_CHECKING, cast from pyomo.environ import value if TYPE_CHECKING: + from temoa.types import Period, Region, Technology, Vintage + from collections.abc import Iterable from temoa.core.model import TemoaModel -from temoa.types import Period, Region, Technology, Vintage logger = getLogger(__name__) @@ -33,7 +33,7 @@ def gather_group_techs(model: TemoaModel, t_or_g: Technology) -> Iterable[Techno if t_or_g in model.tech_group_names: return model.tech_group_members[t_or_g] elif '+' in t_or_g: - return [cast(Technology, tech) for tech in t_or_g.split('+')] + return [cast('Technology', tech) for tech in t_or_g.split('+')] else: return (t_or_g,) @@ -272,7 +272,7 @@ def create_survival_curve(model: TemoaModel) -> None: raise ValueError(msg) if p - p_prev > 1: - _between_periods = [cast(Period, _p) for _p in range(p_prev + 1, p, 1)] + _between_periods = [cast('Period', _p) for _p in range(p_prev + 1, p, 1)] for _p in _between_periods: x = (_p - p_prev) / (p - p_prev) lsc_x = lsc_prev + x * (lsc - lsc_prev) diff --git a/temoa/components/utils.py b/temoa/components/utils.py index 1f6a383a5..000e098bc 100644 --- a/temoa/components/utils.py +++ b/temoa/components/utils.py @@ -12,12 +12,12 @@ from logging import getLogger from typing import TYPE_CHECKING -from pyomo.core import Expression from pyomo.environ import value -from temoa.types import ExprLike if TYPE_CHECKING: + from temoa.types import ExprLike + from pyomo.core import Expression from temoa.core.model import TemoaModel from temoa.types import ( Commodity, diff --git a/temoa/core/model.py b/temoa/core/model.py index b8ff83898..5580e355f 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -22,7 +22,6 @@ minimize, ) -from temoa import types as t from temoa.components import ( capacity, commodities, @@ -47,7 +46,11 @@ validate_reserve_margin, validate_tech_sets, ) -from temoa.types.core_types import Technology +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from temoa.types.core_types import Technology + from temoa import types as t logger = logging.getLogger(__name__) diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index 7b4bd1ec9..ee5e44bc4 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -340,7 +340,7 @@ def _filter_data( if validator is None: return values - typed_values = cast(Sequence[tuple[ValidationPrimitive, ...]], values) + typed_values = cast('Sequence[tuple[ValidationPrimitive, ...]]', values) return element_checker.filter_elements( values=typed_values, validation=validator, value_locations=item.validation_map ) @@ -542,7 +542,7 @@ def _load_time_season( """ model = TemoaModel() mi = self.myopic_index - time_optimize = cast(list[int], data.get('time_optimize', [])) + time_optimize = cast('list[int]', data.get('time_optimize', [])) rows_to_load: list[tuple[object, ...]] = [] if not raw_data: @@ -647,7 +647,7 @@ def _load_cost_invest( model = TemoaModel() base_year = self.myopic_index.base_year if self.myopic_index else None data_to_load = [ - row for row in filtered_data if base_year is None or cast(int, row[2]) >= base_year + row for row in filtered_data if base_year is None or cast('int', row[2]) >= base_year ] self._load_component_data(data, model.cost_invest, data_to_load) @@ -674,7 +674,7 @@ def _load_days_per_period( model = TemoaModel() days = 365 if filtered_data: - days = cast(int, filtered_data[0][0]) + days = cast('int', filtered_data[0][0]) else: logger.info('No value for days_per_period found. Assuming 365 days per period.') data[model.days_per_period.name] = {None: days} @@ -688,7 +688,7 @@ def _load_global_discount_rate( """Loads the required singleton global_discount_rate.""" model = TemoaModel() if filtered_data: - data[model.global_discount_rate.name] = {None: cast(float, filtered_data[0][0])} + data[model.global_discount_rate.name] = {None: cast('float', filtered_data[0][0])} else: raise ValueError( "Missing required parameter: 'global_discount_rate' not found in MetaDataReal table." @@ -703,7 +703,7 @@ def _load_default_loan_rate( """Loads the optional singleton default_loan_rate.""" model = TemoaModel() if filtered_data: - data[model.default_loan_rate.name] = {None: cast(float, filtered_data[0][0])} + data[model.default_loan_rate.name] = {None: cast('float', filtered_data[0][0])} # --- Operational Constraints and Parameters --- def _load_efficiency( diff --git a/temoa/data_processing/make_output_plots.py b/temoa/data_processing/make_output_plots.py index 706da847c..d964f3a18 100644 --- a/temoa/data_processing/make_output_plots.py +++ b/temoa/data_processing/make_output_plots.py @@ -4,14 +4,16 @@ import sqlite3 import sys from collections.abc import Callable -from typing import cast +from typing import cast, TYPE_CHECKING import matplotlib from matplotlib import cm as cmx from matplotlib import colors from matplotlib import pyplot as plt -from matplotlib.figure import Figure -from matplotlib.legend import Legend + +if TYPE_CHECKING: + from matplotlib.figure import Figure + from matplotlib.legend import Legend matplotlib.use('Agg') @@ -241,7 +243,7 @@ def wrapper(index: int | float) -> Color: # library's type stubs, but matplotlib's to_rgba function correctly # handles scalar inputs at runtime. This is a known limitation of the stubs. rgba_value = scalar_map.to_rgba(index) # type: ignore[arg-type] - return cast(Color, rgba_value) + return cast('Color', rgba_value) return wrapper diff --git a/temoa/model_checking/commodity_graph.py b/temoa/model_checking/commodity_graph.py index 3ef086d8e..e451d9485 100644 --- a/temoa/model_checking/commodity_graph.py +++ b/temoa/model_checking/commodity_graph.py @@ -2,20 +2,22 @@ import logging from collections import defaultdict -from collections.abc import Iterable -from typing import Any, cast +from typing import Any, cast, TYPE_CHECKING import networkx as nx -from temoa.core.config import TemoaConfig -from temoa.model_checking.network_model_data import EdgeTuple, NetworkModelData -from temoa.types.core_types import Commodity, Period, Region, Sector, Technology from temoa.utilities.graph_utils import ( calculate_initial_positions, calculate_tech_graph_positions, ) from temoa.utilities.visualizer import make_nx_graph, nx_to_vis +if TYPE_CHECKING: + from temoa.core.config import TemoaConfig + from temoa.model_checking.network_model_data import EdgeTuple, NetworkModelData + from temoa.types.core_types import Commodity, Period, Region, Sector, Technology + from collections.abc import Iterable + logger = logging.getLogger(__name__) @@ -47,7 +49,7 @@ def generate_technology_graph( # Pass 2: Create a single, correctly styled node for each unique technology. for tech_name, info in tech_info.items(): - pos_attrs = tech_positions.get(cast(Technology, tech_name)) or {} + pos_attrs = tech_positions.get(cast('Technology', tech_name)) or {} sector = info['sector'] color_obj: dict[str, str] = {} @@ -290,7 +292,7 @@ def visualize_graph( output_filename=output_file, html_title=f'Network Graphs - {region} {period}', sectors=unique_sectors, - color_legend_map=cast(dict[str, str], sector_colors), + color_legend_map=cast('dict[str, str]', sector_colors), style_legend_map=style_legend_map, show_browser=False, ) diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index 681320016..2c3d8b66d 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -10,19 +10,21 @@ import logging import sqlite3 from collections import defaultdict -from collections.abc import Callable from dataclasses import dataclass, field from itertools import chain -from typing import NamedTuple, Self, TypedDict, cast, overload +from typing import NamedTuple, Self, TypedDict, cast, overload, TYPE_CHECKING import deprecated from pyomo.core.base import ConcreteModel from temoa.core.model import TemoaModel -from temoa.extensions.myopic.myopic_index import MyopicIndex -from temoa.types import Commodity, Period, Region, Sector, Technology, Vintage from temoa.types.core_types import ParameterValue +if TYPE_CHECKING: + from temoa.types import Commodity, Period, Region, Sector, Technology, Vintage + from temoa.extensions.myopic.myopic_index import MyopicIndex + from collections.abc import Callable + # --- Type Definitions --- class EdgeTuple(NamedTuple): @@ -359,10 +361,10 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - living_techs.add(tech) if '-' in r and r.count('-') == 1: # Inter-regional transfer - r1, r2 = (cast(Region, reg) for reg in r.split('-', 1)) + r1, r2 = (cast('Region', reg) for reg in r.split('-', 1)) source_comm, dest_comm = ( - cast(Commodity, f'{ic} ({r1})'), - cast(Commodity, f'{oc} ({r2})'), + cast('Commodity', f'{ic} ({r1})'), + cast('Commodity', f'{oc} ({r2})'), ) res.available_techs[r2, p].add( EdgeTuple( @@ -430,37 +432,37 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - res.available_techs[r, p].add( EdgeTuple( region=r, - input_comm=cast(Commodity, tech), - tech=cast(Technology, 'end_of_life'), + input_comm=cast('Commodity', tech), + tech=cast('Technology', 'end_of_life'), vintage=v, output_comm=eol_oc, lifetime=lifetime, - sector=cast(Sector, 'other'), + sector=cast('Sector', 'other'), ) ) - res.source_commodities[r, p].add(cast(Commodity, tech)) - res.capacity_commodities.add(cast(Commodity, tech)) + res.source_commodities[r, p].add(cast('Commodity', tech)) + res.capacity_commodities.add(cast('Commodity', tech)) if eol_oc in basic_data['waste_commodities_all']: res.waste_commodities[r, p].add(eol_oc) # --- 3. Process Construction --- for r, ic, tech, v in lookup_data['construction']: - construction_lifetime = basic_data['period_length'].get(cast(Period, v), cast(Period, 1)) - res.available_techs[r, cast(Period, v)].add( + construction_lifetime = basic_data['period_length'].get(cast('Period', v), cast('Period', 1)) + res.available_techs[r, cast('Period', v)].add( EdgeTuple( region=r, input_comm=ic, - tech=cast(Technology, 'construction'), + tech=cast('Technology', 'construction'), vintage=v, output_comm=cast( - Commodity, tech + 'Commodity', tech ), # commodity is kind of input to the capacity of the technology/vice versa lifetime=construction_lifetime, - sector=cast(Sector, 'other'), + sector=cast('Sector', 'other'), ) ) - res.demand_commodities[r, cast(Period, v)].add(cast(Commodity, tech)) - res.capacity_commodities.add(cast(Commodity, tech)) + res.demand_commodities[r, cast('Period', v)].add(cast('Commodity', tech)) + res.capacity_commodities.add(cast('Commodity', tech)) living_techs.add(tech) # --- 4. Process Linked Techs and Other Metadata --- diff --git a/temoa/model_checking/validators.py b/temoa/model_checking/validators.py index a6e0ad996..83d9d88c3 100644 --- a/temoa/model_checking/validators.py +++ b/temoa/model_checking/validators.py @@ -10,12 +10,12 @@ from typing import TYPE_CHECKING import deprecated -from pyomo.core import Set from pyomo.environ import NonNegativeReals -from temoa.types.core_types import Commodity, Period, Region, Season, Technology, TimeOfDay, Vintage if TYPE_CHECKING: + from temoa.types.core_types import Commodity, Period, Region, Season, Technology, TimeOfDay, Vintage + from pyomo.core import Set from temoa.core.model import TemoaModel logger = getLogger(__name__) diff --git a/temoa/utilities/graph_utils.py b/temoa/utilities/graph_utils.py index 611b6c712..4dd1ad0c9 100644 --- a/temoa/utilities/graph_utils.py +++ b/temoa/utilities/graph_utils.py @@ -14,18 +14,18 @@ import math import random import uuid -from collections.abc import Iterable, Sequence from typing import TYPE_CHECKING, Any, TypeVar, cast import networkx as nx -from temoa.model_checking.network_model_data import EdgeTuple -from temoa.types.core_types import Commodity, Sector, Technology logger = logging.getLogger(__name__) if TYPE_CHECKING: + from temoa.types.core_types import Commodity, Sector, Technology + from temoa.model_checking.network_model_data import EdgeTuple + from collections.abc import Iterable, Sequence GraphType = TypeVar( 'GraphType', nx.Graph[Commodity | Technology | str], @@ -158,7 +158,7 @@ def calculate_initial_positions( positions: dict[str, dict[str, Any]] = {} # Prepare to lay out the remaining (non-fixed) nodes: all layers except 1 - nodes_to_place = {cast(Commodity, n) for n, layer in node_layer_map.items() if layer != 1} + nodes_to_place = {cast('Commodity', n) for n, layer in node_layer_map.items() if layer != 1} if not nodes_to_place: return positions diff --git a/temoa/utilities/set_spitter.py b/temoa/utilities/set_spitter.py index 879fdc9ee..618af5a89 100644 --- a/temoa/utilities/set_spitter.py +++ b/temoa/utilities/set_spitter.py @@ -5,9 +5,8 @@ from typing import TYPE_CHECKING import pyomo.environ as pyo +from temoa.core.model import TemoaModel -if TYPE_CHECKING: - from temoa.core.model import TemoaModel def spit_sets(model: TemoaModel, index_sets: bool = False) -> None: diff --git a/temoa/utilities/visualizer.py b/temoa/utilities/visualizer.py index a30d10a49..8fe69ff43 100644 --- a/temoa/utilities/visualizer.py +++ b/temoa/utilities/visualizer.py @@ -17,18 +17,20 @@ import logging import uuid from collections import defaultdict -from collections.abc import Iterable, Sequence from pathlib import Path -from typing import Any +from typing import Any, TYPE_CHECKING import networkx as nx -from temoa.types.core_types import Commodity, Sector, Technology from temoa.utilities.graph_utils import ( GraphType, convert_graph_to_json, ) +if TYPE_CHECKING: + from temoa.types.core_types import Commodity, Sector, Technology + from collections.abc import Iterable, Sequence + logger = logging.getLogger(__name__) diff --git a/tests/test_emission_results.py b/tests/test_emission_results.py index 04daebab6..b90a3f7ed 100644 --- a/tests/test_emission_results.py +++ b/tests/test_emission_results.py @@ -35,7 +35,7 @@ def solved_connection( Spins up the model, solves it, and hands over a connection to the results db. This fixture is now updated to use the refactored TemoaSequencer API. """ - param = cast(TechTestParams, request.param) + param = cast('TechTestParams', request.param) logger.info('Setting up and solving for test case: %s', param['name']) config_file = Path(__file__).parent / 'testing_configs' / 'config_emissions.toml' diff --git a/tests/test_exchange_cost_ledger.py b/tests/test_exchange_cost_ledger.py index 17f062fff..218b0ce09 100644 --- a/tests/test_exchange_cost_ledger.py +++ b/tests/test_exchange_cost_ledger.py @@ -1,19 +1,21 @@ -from typing import Any, cast +from typing import Any, cast, TYPE_CHECKING import pytest from temoa._internal.exchange_tech_cost_ledger import CostType, ExchangeTechCostLedger -from temoa.types.core_types import Period, Region, Technology, Vintage from tests.utilities.namespace_mock import Namespace +if TYPE_CHECKING: + from temoa.types.core_types import Period, Region, Technology, Vintage + # Module-level typed constants -TEST_REGION_A = cast(Region, 'A') -TEST_REGION_B = cast(Region, 'B') -TEST_REGION_AB = cast(Region, 'A-B') -TEST_PERIOD_1 = cast(Period, 1) -TEST_PERIOD_2000 = cast(Period, 2000) -TEST_TECH_T1 = cast(Technology, 't1') -TEST_VINTAGE_2000 = cast(Vintage, 2000) +TEST_REGION_A = cast('Region', 'A') +TEST_REGION_B = cast('Region', 'B') +TEST_REGION_AB = cast('Region', 'A-B') +TEST_PERIOD_1 = cast('Period', 1) +TEST_PERIOD_2000 = cast('Period', 2000) +TEST_TECH_T1 = cast('Technology', 't1') +TEST_VINTAGE_2000 = cast('Vintage', 2000) # these are the necessary Temoa elements to make the ledger work data = { diff --git a/tests/test_full_runs.py b/tests/test_full_runs.py index e4476ad4b..023234324 100644 --- a/tests/test_full_runs.py +++ b/tests/test_full_runs.py @@ -5,7 +5,6 @@ import logging import sqlite3 -import pyomo.environ as pyo import pytest from pyomo.core import Constraint, Var from pyomo.opt import SolverResults @@ -14,6 +13,10 @@ from temoa._internal.temoa_sequencer import TemoaSequencer from temoa.core.model import TemoaModel from tests.legacy_test_values import ExpectedVals, test_vals +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + import pyomo.environ as pyo logger = logging.getLogger(__name__) # list of test scenarios for which we have captured results in legacy_test_values.py diff --git a/tests/test_network_model_data.py b/tests/test_network_model_data.py index 337d91773..2903ce0b3 100644 --- a/tests/test_network_model_data.py +++ b/tests/test_network_model_data.py @@ -1,12 +1,14 @@ import sqlite3 -from typing import TypedDict, cast +from typing import TypedDict, cast, TYPE_CHECKING from unittest.mock import MagicMock import pytest from temoa.model_checking import network_model_data from temoa.model_checking.commodity_network import CommodityNetwork -from temoa.types.core_types import Period, Region + +if TYPE_CHECKING: + from temoa.types.core_types import Period, Region class ScenarioType(TypedDict): @@ -205,13 +207,13 @@ def test_network_build_and_analysis( sum(len(s) for s in network_data.demand_commodities.values()) == expected['demands_count'] ) assert ( - len(network_data.available_techs[(cast(Region, 'R1'), cast(Period, 2020))]) + len(network_data.available_techs[(cast('Region', 'R1'), cast('Period', 2020))]) == expected['techs_count'] ) # --- 3. Perform network analysis --- cn = CommodityNetwork( - region=cast(Region, 'R1'), period=cast(Period, 2020), model_data=network_data + region=cast('Region', 'R1'), period=cast('Period', 2020), model_data=network_data ) cn.analyze_network() @@ -241,7 +243,7 @@ def test_clone(mock_db_connection: tuple[MagicMock, dict[str, object]]) -> None: 'Data should be identical after cloning' ) - clone.available_techs.pop((cast(Region, 'R1'), cast(Period, 2020))) + clone.available_techs.pop((cast('Region', 'R1'), cast('Period', 2020))) assert network_data.available_techs != clone.available_techs, ( 'Modifying clone should not affect original' ) @@ -323,7 +325,7 @@ def dispatcher(query: str, *_: object) -> MagicMock: network_data = network_model_data._build_from_db(mock_con) # Verify sectors are included in efficiencyTuple - techs = list(network_data.available_techs[(cast(Region, 'R1'), cast(Period, 2020))]) + techs = list(network_data.available_techs[(cast('Region', 'R1'), cast('Period', 2020))]) assert len(techs) == 2 # Fields: region, ic, tech, vintage, oc, lifetime, sector assert all(len(tech) == 7 for tech in techs) @@ -407,7 +409,7 @@ def dispatcher(query: str, *_: object) -> MagicMock: network_data = network_model_data._build_from_db(mock_con) # Verify sectors default to None - techs = list(network_data.available_techs[(cast(Region, 'R1'), cast(Period, 2020))]) + techs = list(network_data.available_techs[(cast('Region', 'R1'), cast('Period', 2020))]) assert len(techs) == 2 # Fields: region, ic, tech, vintage, oc, lifetime, sector (sector None here) assert all(len(tech) == 7 for tech in techs) diff --git a/tests/test_pricing_check.py b/tests/test_pricing_check.py index 3e936e552..27058e639 100644 --- a/tests/test_pricing_check.py +++ b/tests/test_pricing_check.py @@ -1,11 +1,13 @@ -from typing import cast +from typing import cast, TYPE_CHECKING import pytest from pyomo.environ import Any, ConcreteModel, Param, Set -from temoa.core.model import TemoaModel from temoa.model_checking.pricing_check import check_tech_uncap +if TYPE_CHECKING: + from temoa.core.model import TemoaModel + @pytest.fixture def mock_model() -> ConcreteModel: @@ -35,7 +37,7 @@ def test_check_tech_uncap( :param mock_model: :return: """ - model = cast(TemoaModel, mock_model) + model = cast('TemoaModel', mock_model) assert check_tech_uncap(model), 'should pass for no fixed/invest/variable costs' model.cost_variable[('CA', 2020, 'refinery', 2020)] = 42 @@ -53,7 +55,7 @@ def test_detect_fixed_cost( :param mock_model: :return: """ - model = cast(TemoaModel, mock_model) + model = cast('TemoaModel', mock_model) assert check_tech_uncap(model), 'should have cleared and passed again' model.cost_fixed[('CA', 2020, 'refinery', 2020)] = 42 assert not check_tech_uncap(model), 'should fail with any fixed cost' @@ -67,6 +69,6 @@ def test_detect_invest_cost( :param mock_model: :return: """ - model = cast(TemoaModel, mock_model) + model = cast('TemoaModel', mock_model) model.cost_invest['CA', 'refinery', 2020] = 42 assert not check_tech_uncap(model), 'should fail with any investment cost' diff --git a/tests/test_source_check.py b/tests/test_source_check.py index 8ca0f914f..5650da40a 100644 --- a/tests/test_source_check.py +++ b/tests/test_source_check.py @@ -206,8 +206,8 @@ def test_network_analysis( """ # 1. Setup mock model data for the test case mock_model_data = MagicMock() - region = cast(Region, 'test_region') - period = cast(Period, 2025) + region = cast('Region', 'test_region') + period = cast('Period', 2025) # The mock needs to return the correct data for the (region, period) key mock_model_data.demand_commodities = defaultdict(set, {(region, period): start_nodes}) @@ -218,7 +218,7 @@ def test_network_analysis( # Convert the connections dict into a set of Tech namedtuples available_techs = { EdgeTuple( - input_comm=ic, output_comm=oc, tech=tech, vintage=cast(Vintage, period), region=region + input_comm=ic, output_comm=oc, tech=tech, vintage=cast('Vintage', period), region=region ) for oc, links in connections.items() for ic, tech in links diff --git a/tests/test_validators.py b/tests/test_validators.py index 1adfc8af8..110b32d2f 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -2,19 +2,21 @@ Tests for the validators for regions, linked regions, and region groups """ -from typing import cast +from typing import cast, TYPE_CHECKING import pyomo.environ as pyo import pytest -from temoa.core.model import TemoaModel from temoa.model_checking.validators import ( linked_region_check, no_slash_or_pipe, region_check, region_group_check, ) -from temoa.types.core_types import Region + +if TYPE_CHECKING: + from temoa.core.model import TemoaModel + from temoa.types.core_types import Region def test_region_check() -> None: @@ -29,9 +31,9 @@ def test_region_check() -> None: ' R12', # leading spaces 'global', # illegal for individual region } - assert all(region_check(cast(TemoaModel, None), region=cast(Region, r)) for r in good_names) + assert all(region_check(cast('TemoaModel', None), region=cast('Region', r)) for r in good_names) for bad_name in bad_names: - assert not region_check(cast(TemoaModel, None), region=cast(Region, bad_name)), ( + assert not region_check(cast('TemoaModel', None), region=cast('Region', bad_name)), ( f'This should fail {bad_name}' ) @@ -53,9 +55,9 @@ def test_linked_region_check() -> None: 'AZ - Mexico', # bad spacing 'AZ-R2-Mexico', # triples not allowed } - assert all(linked_region_check(cast(TemoaModel, m), region_pair=rp) for rp in good_names) + assert all(linked_region_check(cast('TemoaModel', m), region_pair=rp) for rp in good_names) for bad_name in bad_names: - assert not linked_region_check(cast(TemoaModel, m), region_pair=bad_name), ( + assert not linked_region_check(cast('TemoaModel', m), region_pair=bad_name), ( f'This should fail {bad_name}' ) @@ -75,11 +77,11 @@ def test_region_group_check() -> None: 'Region3', # singleton not in m.R } for name in good_names: - assert region_group_check(cast(TemoaModel, m), rg=name), ( + assert region_group_check(cast('TemoaModel', m), rg=name), ( f'This name should have been good: {name}' ) for name in bad_names: - assert not region_group_check(cast(TemoaModel, m), rg=name), ( + assert not region_group_check(cast('TemoaModel', m), rg=name), ( f'This name should have failed: {name}' ) @@ -95,4 +97,4 @@ def test_region_group_check() -> None: @pytest.mark.parametrize('value, expected', params) def test_no_slash(value: str | int, *, expected: bool) -> None: - assert no_slash_or_pipe(model=cast(TemoaModel, None), element=value) == expected + assert no_slash_or_pipe(model=cast('TemoaModel', None), element=value) == expected From db84b73f7d571200fee34789db1c57a09df5dc96 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 20 Nov 2025 22:31:59 -0500 Subject: [PATCH 349/587] refactor: use __future__ annotations instead of quoted type expressions - Added 'from __future__ import annotations' to 12 files - Removed manual quotes from cast() type expressions - Enables PEP 563 postponed evaluation of annotations - Cleaner and more maintainable than manual quoting --- temoa/_internal/exchange_tech_cost_ledger.py | 3 ++- temoa/_internal/table_data_puller.py | 10 +++++++--- temoa/components/commodities.py | 3 ++- temoa/components/geography.py | 3 ++- temoa/components/limits.py | 3 ++- temoa/components/technology.py | 3 ++- temoa/data_io/hybrid_loader.py | 12 ++++++++---- temoa/data_processing/make_output_plots.py | 2 ++ temoa/model_checking/commodity_graph.py | 3 ++- temoa/model_checking/network_model_data.py | 3 ++- temoa/utilities/graph_utils.py | 3 ++- 11 files changed, 33 insertions(+), 15 deletions(-) diff --git a/temoa/_internal/exchange_tech_cost_ledger.py b/temoa/_internal/exchange_tech_cost_ledger.py index c19b5bf31..a93ebfe39 100644 --- a/temoa/_internal/exchange_tech_cost_ledger.py +++ b/temoa/_internal/exchange_tech_cost_ledger.py @@ -16,7 +16,8 @@ if TYPE_CHECKING: - from temoa.types.core_types import Period, Region, Technology, Vintage + from temoa.types.core_types import Region + from temoa.types.core_types import Period, Technology, Vintage from temoa.core.model import TemoaModel from tests.utilities.namespace_mock import Namespace diff --git a/temoa/_internal/table_data_puller.py b/temoa/_internal/table_data_puller.py index 23b45310e..27e467ab8 100644 --- a/temoa/_internal/table_data_puller.py +++ b/temoa/_internal/table_data_puller.py @@ -5,11 +5,13 @@ by Workers who shouldn't interact with DB). Dev Note: In future, if transition away from sqlite, this could all be refactored to perform tasks within workers, but concurrent access to sqlite is a no-go """ +from __future__ import annotations + import functools import logging from collections import defaultdict -from typing import cast +from typing import cast, TYPE_CHECKING from pyomo.common.numeric_types import value from pyomo.core import Objective @@ -17,10 +19,12 @@ from temoa._internal.exchange_tech_cost_ledger import CostType, ExchangeTechCostLedger from temoa.components import costs from temoa.components.utils import get_variable_efficiency -from temoa.core.model import TemoaModel -from temoa.types.core_types import Commodity, Period, Region, Technology, Vintage from temoa.types.model_types import EI, FI, SLI, CapData, FlowType +if TYPE_CHECKING: + from temoa.types.core_types import Commodity, Period, Region, Technology, Vintage + from temoa.core.model import TemoaModel + logger = logging.getLogger(__name__) diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index cb363772e..3a950b80b 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -20,7 +20,8 @@ if TYPE_CHECKING: - from ..types import Commodity, ExprLike, Period, Region + from ..types import Region + from ..types import Commodity, ExprLike, Period from temoa.types.core_types import Season, Technology, TimeOfDay, Vintage from temoa.core.model import TemoaModel diff --git a/temoa/components/geography.py b/temoa/components/geography.py index 45134e4f6..39d5902be 100644 --- a/temoa/components/geography.py +++ b/temoa/components/geography.py @@ -19,7 +19,8 @@ from pyomo.environ import value if TYPE_CHECKING: - from temoa.types import ExprLike, Period, Region, Technology, Vintage + from temoa.types import Region + from temoa.types import ExprLike, Period, Technology, Vintage from collections.abc import Iterable from temoa.core.model import TemoaModel diff --git a/temoa/components/limits.py b/temoa/components/limits.py index 01e85f96f..87dc373e8 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -23,7 +23,8 @@ from temoa.components.utils import Operator, get_variable_efficiency, operator_expression if TYPE_CHECKING: - from temoa.types import ExprLike, Period, Region, Technology, Vintage + from temoa.types import Vintage + from temoa.types import ExprLike, Period, Region, Technology from temoa.types.core_types import Commodity, Season, TimeOfDay from temoa.core.model import TemoaModel diff --git a/temoa/components/technology.py b/temoa/components/technology.py index 2fd431385..e1f8c87c1 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -18,7 +18,8 @@ from pyomo.environ import value if TYPE_CHECKING: - from temoa.types import Period, Region, Technology, Vintage + from temoa.types import Period, Technology + from temoa.types import Region, Vintage from collections.abc import Iterable from temoa.core.model import TemoaModel diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index ee5e44bc4..9bb62362f 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -1,3 +1,5 @@ +from __future__ import annotations + # temoa/data_io/hybrid_loader.py """ Defines the main data loading engine for the Temoa model. @@ -21,24 +23,26 @@ import time from collections import defaultdict -from collections.abc import Sequence from logging import getLogger from sqlite3 import Connection, Cursor, OperationalError -from typing import cast +from typing import cast, TYPE_CHECKING from pyomo.core import Param, Set from pyomo.dataportal import DataPortal -from temoa.core.config import TemoaConfig from temoa.core.model import TemoaModel from temoa.core.modes import TemoaMode from temoa.data_io.component_manifest import build_manifest -from temoa.data_io.loader_manifest import LoadItem from temoa.extensions.myopic.myopic_index import MyopicIndex from temoa.model_checking import element_checker, network_model_data from temoa.model_checking.commodity_network_manager import CommodityNetworkManager from temoa.model_checking.element_checker import ValidationPrimitive, ViableSet +if TYPE_CHECKING: + from temoa.core.config import TemoaConfig + from temoa.data_io.loader_manifest import LoadItem + from collections.abc import Sequence + logger = getLogger(__name__) # A manifest of tables that may contain region groups, used by a custom loader. diff --git a/temoa/data_processing/make_output_plots.py b/temoa/data_processing/make_output_plots.py index d964f3a18..bd1d057ac 100644 --- a/temoa/data_processing/make_output_plots.py +++ b/temoa/data_processing/make_output_plots.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import argparse import os import random diff --git a/temoa/model_checking/commodity_graph.py b/temoa/model_checking/commodity_graph.py index e451d9485..a14f1f939 100644 --- a/temoa/model_checking/commodity_graph.py +++ b/temoa/model_checking/commodity_graph.py @@ -13,9 +13,10 @@ from temoa.utilities.visualizer import make_nx_graph, nx_to_vis if TYPE_CHECKING: + from temoa.types.core_types import Technology from temoa.core.config import TemoaConfig from temoa.model_checking.network_model_data import EdgeTuple, NetworkModelData - from temoa.types.core_types import Commodity, Period, Region, Sector, Technology + from temoa.types.core_types import Commodity, Period, Region, Sector from collections.abc import Iterable logger = logging.getLogger(__name__) diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index 2c3d8b66d..e81b11913 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -21,7 +21,8 @@ from temoa.types.core_types import ParameterValue if TYPE_CHECKING: - from temoa.types import Commodity, Period, Region, Sector, Technology, Vintage + from temoa.types import Commodity, Period, Region, Sector, Technology + from temoa.types import Vintage from temoa.extensions.myopic.myopic_index import MyopicIndex from collections.abc import Callable diff --git a/temoa/utilities/graph_utils.py b/temoa/utilities/graph_utils.py index 4dd1ad0c9..0351e424c 100644 --- a/temoa/utilities/graph_utils.py +++ b/temoa/utilities/graph_utils.py @@ -23,7 +23,8 @@ if TYPE_CHECKING: - from temoa.types.core_types import Commodity, Sector, Technology + from temoa.types.core_types import Commodity + from temoa.types.core_types import Sector, Technology from temoa.model_checking.network_model_data import EdgeTuple from collections.abc import Iterable, Sequence GraphType = TypeVar( From 02d751e59f38bfb7d61eb382fb1f4f61ebe56b23 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 22 Nov 2025 10:33:53 -0500 Subject: [PATCH 350/587] fixing linting conflicts --- docs/source/conf.py | 12 ++++++------ pyproject.toml | 2 +- temoa/_internal/exchange_tech_cost_ledger.py | 4 +--- temoa/_internal/table_data_puller.py | 6 +++--- temoa/_internal/table_writer.py | 13 ++++++++----- temoa/_internal/temoa_sequencer.py | 3 +-- temoa/components/capacity.py | 3 +-- temoa/components/commodities.py | 15 +++++++++------ temoa/components/costs.py | 4 ++-- temoa/components/emissions.py | 13 ++++++++++--- temoa/components/flows.py | 11 +++++------ temoa/components/geography.py | 4 ++-- temoa/components/limits.py | 5 ++--- temoa/components/operations.py | 3 +-- temoa/components/reserves.py | 3 +-- temoa/components/storage.py | 3 ++- temoa/components/technology.py | 4 ++-- temoa/components/utils.py | 4 ++-- temoa/core/model.py | 4 ++-- temoa/data_io/hybrid_loader.py | 9 +++++---- temoa/data_processing/make_output_plots.py | 2 +- temoa/model_checking/commodity_graph.py | 8 ++++---- temoa/model_checking/network_model_data.py | 12 +++++++----- temoa/model_checking/validators.py | 12 ++++++++++-- temoa/utilities/graph_utils.py | 8 ++++---- temoa/utilities/set_spitter.py | 4 +--- temoa/utilities/visualizer.py | 5 +++-- tests/test_exchange_cost_ledger.py | 2 +- tests/test_full_runs.py | 2 +- tests/test_network_model_data.py | 2 +- tests/test_pricing_check.py | 2 +- tests/test_validators.py | 2 +- 32 files changed, 101 insertions(+), 85 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 4557621d0..7f55219dd 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -25,15 +25,15 @@ with open(pyproject_path) as f: pyproject_data = tomlkit.load(f) -project_metadata = cast(dict[str, Any], pyproject_data['project']) +project_metadata = cast('dict[str, Any]', pyproject_data['project']) project = 'Tools for Energy Model Optimization and Analysis (Temoa)' author = ', '.join( - author['name'] for author in cast(list[dict[str, Any]], project_metadata.get('authors', [])) + author['name'] for author in cast('list[dict[str, Any]]', project_metadata.get('authors', [])) ) copyright = f'2011-{time.strftime("%Y")}, NC State University' # The short X.Y version -version = cast(str, project_metadata['version']).rsplit('.', 1)[ +version = cast('str', project_metadata['version']).rsplit('.', 1)[ 0 ] # '4.0.0a1.dev20251113' -> '4.0.0a1' # The full version, including alpha/beta/rc tags @@ -93,9 +93,9 @@ # Suppress warnings for duplicate labels and objects (intentional due to file inclusion and autodoc) suppress_warnings = [ - 'ref.duplicate', # Duplicate labels between included RST files - 'autosummary', # Autodoc duplicate object descriptions - 'ref.footnote', # Unreferenced footnotes + 'ref.duplicate', # Duplicate labels between included RST files + 'autosummary', # Autodoc duplicate object descriptions + 'ref.footnote', # Unreferenced footnotes ] diff --git a/pyproject.toml b/pyproject.toml index 316a19da1..6312f4614 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -96,7 +96,7 @@ select = [ "I", # isort "B", # flake8-bugbear "N", # flake8-naming - "G004",, # logging-f-string + "G004", # logging-f-string "TC", # flake8-type-checking "UP", # pyupgrade ] diff --git a/temoa/_internal/exchange_tech_cost_ledger.py b/temoa/_internal/exchange_tech_cost_ledger.py index a93ebfe39..3edaa6c62 100644 --- a/temoa/_internal/exchange_tech_cost_ledger.py +++ b/temoa/_internal/exchange_tech_cost_ledger.py @@ -14,11 +14,9 @@ from pyomo.common.numeric_types import value - if TYPE_CHECKING: - from temoa.types.core_types import Region - from temoa.types.core_types import Period, Technology, Vintage from temoa.core.model import TemoaModel + from temoa.types.core_types import Period, Region, Technology, Vintage from tests.utilities.namespace_mock import Namespace diff --git a/temoa/_internal/table_data_puller.py b/temoa/_internal/table_data_puller.py index 27e467ab8..f9cc97a78 100644 --- a/temoa/_internal/table_data_puller.py +++ b/temoa/_internal/table_data_puller.py @@ -5,13 +5,13 @@ by Workers who shouldn't interact with DB). Dev Note: In future, if transition away from sqlite, this could all be refactored to perform tasks within workers, but concurrent access to sqlite is a no-go """ -from __future__ import annotations +from __future__ import annotations import functools import logging from collections import defaultdict -from typing import cast, TYPE_CHECKING +from typing import TYPE_CHECKING, cast from pyomo.common.numeric_types import value from pyomo.core import Objective @@ -22,8 +22,8 @@ from temoa.types.model_types import EI, FI, SLI, CapData, FlowType if TYPE_CHECKING: - from temoa.types.core_types import Commodity, Period, Region, Technology, Vintage from temoa.core.model import TemoaModel + from temoa.types.core_types import Commodity, Period, Region, Technology, Vintage logger = logging.getLogger(__name__) diff --git a/temoa/_internal/table_writer.py b/temoa/_internal/table_writer.py index 0408b1f31..ed9171d98 100644 --- a/temoa/_internal/table_writer.py +++ b/temoa/_internal/table_writer.py @@ -30,14 +30,17 @@ from temoa.core.modes import TemoaMode if TYPE_CHECKING: + from collections.abc import Iterable + from pathlib import Path + + from pyomo.opt import SolverResults + from temoa._internal.data_brick import DataBrick + from temoa.core.config import TemoaConfig + from temoa.core.model import TemoaModel from temoa.extensions.monte_carlo.mc_run import ChangeRecord - from pyomo.opt import SolverResults from temoa.types.core_types import Period, Region, Technology, Vintage - from temoa.core.model import TemoaModel - from temoa.core.config import TemoaConfig - from pathlib import Path - from collections.abc import Iterable + pass """ diff --git a/temoa/_internal/temoa_sequencer.py b/temoa/_internal/temoa_sequencer.py index d35c6254c..6eb5924a2 100644 --- a/temoa/_internal/temoa_sequencer.py +++ b/temoa/_internal/temoa_sequencer.py @@ -8,7 +8,7 @@ import sqlite3 from logging import getLogger - +from typing import TYPE_CHECKING from temoa._internal.run_actions import ( build_instance, @@ -34,7 +34,6 @@ MIN_PYTHON_MAJOR, MIN_PYTHON_MINOR, ) -from typing import TYPE_CHECKING if TYPE_CHECKING: import pyomo.opt diff --git a/temoa/components/capacity.py b/temoa/components/capacity.py index 3506cfc35..ff495f9e0 100644 --- a/temoa/components/capacity.py +++ b/temoa/components/capacity.py @@ -18,11 +18,10 @@ from deprecated import deprecated from pyomo.environ import value - if TYPE_CHECKING: - from temoa.types import ExprLike from temoa.core.model import TemoaModel from temoa.types import ( + ExprLike, Period, Region, Season, diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index 3a950b80b..bb65126eb 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -18,12 +18,11 @@ from pyomo.environ import value - if TYPE_CHECKING: - from ..types import Region - from ..types import Commodity, ExprLike, Period - from temoa.types.core_types import Season, Technology, TimeOfDay, Vintage from temoa.core.model import TemoaModel + from temoa.types.core_types import Season, Technology, TimeOfDay, Vintage + + from ..types import Commodity, ExprLike, Period, Region from .utils import get_variable_efficiency @@ -446,14 +445,18 @@ def commodity_balance_constraint( if (r, p, c) in model.export_regions: consumed += sum( model.v_flow_out[r + '-' + reg, p, s, d, c, s_t, s_v, S_o] - / get_variable_efficiency(model, cast('Region', r + '-' + reg), p, s, d, c, s_t, s_v, S_o) + / get_variable_efficiency( + model, cast('Region', r + '-' + reg), p, s, d, c, s_t, s_v, S_o + ) for reg, s_t, s_v, S_o in model.export_regions[r, p, c] if s_t not in model.tech_annual ) consumed += sum( value(model.segment_fraction[p, s, d]) * model.v_flow_out_annual[r + '-' + reg, p, c, s_t, s_v, S_o] - / get_variable_efficiency(model, cast('Region', r + '-' + reg), p, s, d, c, s_t, s_v, S_o) + / get_variable_efficiency( + model, cast('Region', r + '-' + reg), p, s, d, c, s_t, s_v, S_o + ) for reg, s_t, s_v, S_o in model.export_regions[r, p, c] if s_t in model.tech_annual ) diff --git a/temoa/components/costs.py b/temoa/components/costs.py index 2810b8ea8..30bf455c1 100644 --- a/temoa/components/costs.py +++ b/temoa/components/costs.py @@ -18,12 +18,12 @@ from deprecated import deprecated from pyomo.environ import quicksum, value - if TYPE_CHECKING: from pyomo.core import Expression, Var - from temoa.types.core_types import Period, Region, Technology, Vintage from pyomo.core.base.component import ComponentData + from temoa.core.model import TemoaModel + from temoa.types.core_types import Period, Region, Technology, Vintage from logging import getLogger diff --git a/temoa/components/emissions.py b/temoa/components/emissions.py index 552420e98..03e9a9c45 100644 --- a/temoa/components/emissions.py +++ b/temoa/components/emissions.py @@ -16,11 +16,18 @@ from pyomo.core import quicksum from pyomo.environ import value - if TYPE_CHECKING: - from temoa.types import ExprLike - from temoa.types.core_types import Commodity, Period, Region, Season, Technology, TimeOfDay, Vintage from temoa.core.model import TemoaModel + from temoa.types import ExprLike + from temoa.types.core_types import ( + Commodity, + Period, + Region, + Season, + Technology, + TimeOfDay, + Vintage, + ) # ============================================================================ diff --git a/temoa/components/flows.py b/temoa/components/flows.py index 32015ee46..e9443ee4c 100644 --- a/temoa/components/flows.py +++ b/temoa/components/flows.py @@ -14,8 +14,12 @@ from logging import getLogger from typing import TYPE_CHECKING - if TYPE_CHECKING: + from temoa.core.model import TemoaModel + from temoa.types import ( + ActiveFlexAnnualSet, + ActiveFlowAnnualSet, + ) from temoa.types.core_types import ( Commodity, Period, @@ -25,11 +29,6 @@ TimeOfDay, Vintage, ) - from temoa.types import ( - ActiveFlexAnnualSet, - ActiveFlowAnnualSet, - ) - from temoa.core.model import TemoaModel logger = getLogger(__name__) diff --git a/temoa/components/geography.py b/temoa/components/geography.py index 39d5902be..ffad4e9bd 100644 --- a/temoa/components/geography.py +++ b/temoa/components/geography.py @@ -19,10 +19,10 @@ from pyomo.environ import value if TYPE_CHECKING: - from temoa.types import Region - from temoa.types import ExprLike, Period, Technology, Vintage from collections.abc import Iterable + from temoa.core.model import TemoaModel + from temoa.types import ExprLike, Period, Region, Technology, Vintage # Import type annotations diff --git a/temoa/components/limits.py b/temoa/components/limits.py index 87dc373e8..d9cc3c8d3 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -23,10 +23,9 @@ from temoa.components.utils import Operator, get_variable_efficiency, operator_expression if TYPE_CHECKING: - from temoa.types import Vintage - from temoa.types import ExprLike, Period, Region, Technology - from temoa.types.core_types import Commodity, Season, TimeOfDay from temoa.core.model import TemoaModel + from temoa.types import ExprLike, Period, Region, Technology, Vintage + from temoa.types.core_types import Commodity, Season, TimeOfDay logger = getLogger(__name__) diff --git a/temoa/components/operations.py b/temoa/components/operations.py index 68c2aff73..95fdd8edf 100644 --- a/temoa/components/operations.py +++ b/temoa/components/operations.py @@ -17,11 +17,10 @@ from pyomo.environ import Constraint, value - if TYPE_CHECKING: + from temoa.core.model import TemoaModel from temoa.types import ExprLike from temoa.types.core_types import Period, Region, Season, Technology, TimeOfDay, Vintage - from temoa.core.model import TemoaModel logger = getLogger(__name__) diff --git a/temoa/components/reserves.py b/temoa/components/reserves.py index 53ed95498..da3b0dbeb 100644 --- a/temoa/components/reserves.py +++ b/temoa/components/reserves.py @@ -15,13 +15,12 @@ from pyomo.environ import Constraint, value - from .utils import get_variable_efficiency if TYPE_CHECKING: - from temoa.types.core_types import Period, Region, Season, TimeOfDay from temoa.core.model import TemoaModel from temoa.types import ExprLike + from temoa.types.core_types import Period, Region, Season, TimeOfDay logger = getLogger(__name__) diff --git a/temoa/components/storage.py b/temoa/components/storage.py index 7265e4ee9..974f28bad 100644 --- a/temoa/components/storage.py +++ b/temoa/components/storage.py @@ -20,9 +20,10 @@ from .utils import Operator, get_variable_efficiency, operator_expression if TYPE_CHECKING: - from ..types import ExprLike, Period, Region, Season, Technology, TimeOfDay, Vintage from temoa.core.model import TemoaModel + from ..types import ExprLike, Period, Region, Season, Technology, TimeOfDay, Vintage + # ============================================================================ # PYOMO INDEX SET FUNCTIONS diff --git a/temoa/components/technology.py b/temoa/components/technology.py index e1f8c87c1..7f765746a 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -18,10 +18,10 @@ from pyomo.environ import value if TYPE_CHECKING: - from temoa.types import Period, Technology - from temoa.types import Region, Vintage from collections.abc import Iterable + from temoa.core.model import TemoaModel + from temoa.types import Period, Region, Technology, Vintage logger = getLogger(__name__) diff --git a/temoa/components/utils.py b/temoa/components/utils.py index 000e098bc..c558bf23b 100644 --- a/temoa/components/utils.py +++ b/temoa/components/utils.py @@ -14,13 +14,13 @@ from pyomo.environ import value - if TYPE_CHECKING: - from temoa.types import ExprLike from pyomo.core import Expression + from temoa.core.model import TemoaModel from temoa.types import ( Commodity, + ExprLike, Period, Region, Season, diff --git a/temoa/core/model.py b/temoa/core/model.py index 5580e355f..2c7a0b55e 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -9,6 +9,7 @@ """ import logging +from typing import TYPE_CHECKING from pyomo.core import BuildCheck, Set, Var from pyomo.environ import ( @@ -46,11 +47,10 @@ validate_reserve_margin, validate_tech_sets, ) -from typing import TYPE_CHECKING if TYPE_CHECKING: - from temoa.types.core_types import Technology from temoa import types as t + from temoa.types.core_types import Technology logger = logging.getLogger(__name__) diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index 9bb62362f..fae368e55 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -1,5 +1,3 @@ -from __future__ import annotations - # temoa/data_io/hybrid_loader.py """ Defines the main data loading engine for the Temoa model. @@ -21,11 +19,13 @@ `HybridLoader` class. """ +from __future__ import annotations + import time from collections import defaultdict from logging import getLogger from sqlite3 import Connection, Cursor, OperationalError -from typing import cast, TYPE_CHECKING +from typing import TYPE_CHECKING, cast from pyomo.core import Param, Set from pyomo.dataportal import DataPortal @@ -39,9 +39,10 @@ from temoa.model_checking.element_checker import ValidationPrimitive, ViableSet if TYPE_CHECKING: + from collections.abc import Sequence + from temoa.core.config import TemoaConfig from temoa.data_io.loader_manifest import LoadItem - from collections.abc import Sequence logger = getLogger(__name__) diff --git a/temoa/data_processing/make_output_plots.py b/temoa/data_processing/make_output_plots.py index bd1d057ac..a1d4fa8ac 100644 --- a/temoa/data_processing/make_output_plots.py +++ b/temoa/data_processing/make_output_plots.py @@ -6,7 +6,7 @@ import sqlite3 import sys from collections.abc import Callable -from typing import cast, TYPE_CHECKING +from typing import TYPE_CHECKING, cast import matplotlib from matplotlib import cm as cmx diff --git a/temoa/model_checking/commodity_graph.py b/temoa/model_checking/commodity_graph.py index a14f1f939..3c70c246b 100644 --- a/temoa/model_checking/commodity_graph.py +++ b/temoa/model_checking/commodity_graph.py @@ -2,7 +2,7 @@ import logging from collections import defaultdict -from typing import Any, cast, TYPE_CHECKING +from typing import TYPE_CHECKING, Any, cast import networkx as nx @@ -13,11 +13,11 @@ from temoa.utilities.visualizer import make_nx_graph, nx_to_vis if TYPE_CHECKING: - from temoa.types.core_types import Technology + from collections.abc import Iterable + from temoa.core.config import TemoaConfig from temoa.model_checking.network_model_data import EdgeTuple, NetworkModelData - from temoa.types.core_types import Commodity, Period, Region, Sector - from collections.abc import Iterable + from temoa.types.core_types import Commodity, Period, Region, Sector, Technology logger = logging.getLogger(__name__) diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index e81b11913..c4a6288ae 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -12,7 +12,7 @@ from collections import defaultdict from dataclasses import dataclass, field from itertools import chain -from typing import NamedTuple, Self, TypedDict, cast, overload, TYPE_CHECKING +from typing import TYPE_CHECKING, NamedTuple, Self, TypedDict, cast, overload import deprecated from pyomo.core.base import ConcreteModel @@ -21,11 +21,11 @@ from temoa.types.core_types import ParameterValue if TYPE_CHECKING: - from temoa.types import Commodity, Period, Region, Sector, Technology - from temoa.types import Vintage - from temoa.extensions.myopic.myopic_index import MyopicIndex from collections.abc import Callable + from temoa.extensions.myopic.myopic_index import MyopicIndex + from temoa.types import Commodity, Period, Region, Sector, Technology, Vintage + # --- Type Definitions --- class EdgeTuple(NamedTuple): @@ -448,7 +448,9 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - # --- 3. Process Construction --- for r, ic, tech, v in lookup_data['construction']: - construction_lifetime = basic_data['period_length'].get(cast('Period', v), cast('Period', 1)) + construction_lifetime = basic_data['period_length'].get( + cast('Period', v), cast('Period', 1) + ) res.available_techs[r, cast('Period', v)].add( EdgeTuple( region=r, diff --git a/temoa/model_checking/validators.py b/temoa/model_checking/validators.py index 83d9d88c3..aa8a262c0 100644 --- a/temoa/model_checking/validators.py +++ b/temoa/model_checking/validators.py @@ -12,11 +12,19 @@ import deprecated from pyomo.environ import NonNegativeReals - if TYPE_CHECKING: - from temoa.types.core_types import Commodity, Period, Region, Season, Technology, TimeOfDay, Vintage from pyomo.core import Set + from temoa.core.model import TemoaModel + from temoa.types.core_types import ( + Commodity, + Period, + Region, + Season, + Technology, + TimeOfDay, + Vintage, + ) logger = getLogger(__name__) diff --git a/temoa/utilities/graph_utils.py b/temoa/utilities/graph_utils.py index 0351e424c..a1541f0af 100644 --- a/temoa/utilities/graph_utils.py +++ b/temoa/utilities/graph_utils.py @@ -18,15 +18,15 @@ import networkx as nx - logger = logging.getLogger(__name__) if TYPE_CHECKING: - from temoa.types.core_types import Commodity - from temoa.types.core_types import Sector, Technology - from temoa.model_checking.network_model_data import EdgeTuple from collections.abc import Iterable, Sequence + + from temoa.model_checking.network_model_data import EdgeTuple + from temoa.types.core_types import Commodity, Sector, Technology + GraphType = TypeVar( 'GraphType', nx.Graph[Commodity | Technology | str], diff --git a/temoa/utilities/set_spitter.py b/temoa/utilities/set_spitter.py index 618af5a89..dbaaca05e 100644 --- a/temoa/utilities/set_spitter.py +++ b/temoa/utilities/set_spitter.py @@ -2,11 +2,9 @@ Quick utility to spit out the set members of a pyomo model """ -from typing import TYPE_CHECKING - import pyomo.environ as pyo -from temoa.core.model import TemoaModel +from temoa.core.model import TemoaModel def spit_sets(model: TemoaModel, index_sets: bool = False) -> None: diff --git a/temoa/utilities/visualizer.py b/temoa/utilities/visualizer.py index 8fe69ff43..eba8846bd 100644 --- a/temoa/utilities/visualizer.py +++ b/temoa/utilities/visualizer.py @@ -18,7 +18,7 @@ import uuid from collections import defaultdict from pathlib import Path -from typing import Any, TYPE_CHECKING +from typing import TYPE_CHECKING, Any import networkx as nx @@ -28,9 +28,10 @@ ) if TYPE_CHECKING: - from temoa.types.core_types import Commodity, Sector, Technology from collections.abc import Iterable, Sequence + from temoa.types.core_types import Commodity, Sector, Technology + logger = logging.getLogger(__name__) diff --git a/tests/test_exchange_cost_ledger.py b/tests/test_exchange_cost_ledger.py index 218b0ce09..1bee47806 100644 --- a/tests/test_exchange_cost_ledger.py +++ b/tests/test_exchange_cost_ledger.py @@ -1,4 +1,4 @@ -from typing import Any, cast, TYPE_CHECKING +from typing import TYPE_CHECKING, Any, cast import pytest diff --git a/tests/test_full_runs.py b/tests/test_full_runs.py index 023234324..d8ac886f2 100644 --- a/tests/test_full_runs.py +++ b/tests/test_full_runs.py @@ -4,6 +4,7 @@ import logging import sqlite3 +from typing import TYPE_CHECKING import pytest from pyomo.core import Constraint, Var @@ -13,7 +14,6 @@ from temoa._internal.temoa_sequencer import TemoaSequencer from temoa.core.model import TemoaModel from tests.legacy_test_values import ExpectedVals, test_vals -from typing import TYPE_CHECKING if TYPE_CHECKING: import pyomo.environ as pyo diff --git a/tests/test_network_model_data.py b/tests/test_network_model_data.py index 2903ce0b3..f9ed609b9 100644 --- a/tests/test_network_model_data.py +++ b/tests/test_network_model_data.py @@ -1,5 +1,5 @@ import sqlite3 -from typing import TypedDict, cast, TYPE_CHECKING +from typing import TYPE_CHECKING, TypedDict, cast from unittest.mock import MagicMock import pytest diff --git a/tests/test_pricing_check.py b/tests/test_pricing_check.py index 27058e639..95aa9a97f 100644 --- a/tests/test_pricing_check.py +++ b/tests/test_pricing_check.py @@ -1,4 +1,4 @@ -from typing import cast, TYPE_CHECKING +from typing import TYPE_CHECKING, cast import pytest from pyomo.environ import Any, ConcreteModel, Param, Set diff --git a/tests/test_validators.py b/tests/test_validators.py index 110b32d2f..a3a3d9c34 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -2,7 +2,7 @@ Tests for the validators for regions, linked regions, and region groups """ -from typing import cast, TYPE_CHECKING +from typing import TYPE_CHECKING, cast import pyomo.environ as pyo import pytest From d5880e59ef966c98f0db520301ed8357b91cda13 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 20 Nov 2025 22:35:19 -0500 Subject: [PATCH 351/587] chore: enable C4 (comprehensions) linting rules in pyproject.toml --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 6312f4614..5829bea56 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -96,9 +96,10 @@ select = [ "I", # isort "B", # flake8-bugbear "N", # flake8-naming - "G004", # logging-f-string + "G004",, # logging-f-string "TC", # flake8-type-checking "UP", # pyupgrade + "C4", # flake8-comprehensions ] ignore = [ "E501", # line too long temporarily ignored From bfdf41f35cc2738471b61ba03fa422e89087c41b Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 20 Nov 2025 22:35:48 -0500 Subject: [PATCH 352/587] refactor: simplify collection constructors and comprehensions (C4) - Replace dict() calls with literal {} syntax (C408) - Remove unnecessary nested list() or sorted() calls (C414) - Simplify unnecessary list comprehensions (C416) - 18 violations fixed across 6 files --- pyproject.toml | 2 +- temoa/components/technology.py | 2 +- temoa/data_io/hybrid_loader.py | 6 +- temoa/data_processing/graphviz_util.py | 40 +++++----- temoa/data_processing/make_graphviz.py | 80 +++++++++---------- temoa/data_processing/make_output_plots.py | 6 +- .../commodity_network_manager.py | 2 +- temoa/utilities/db_migration_to_v3.py | 2 +- temoa/utilities/db_migration_v3_to_v3_1.py | 4 +- tests/test_set_consistency.py | 4 +- 10 files changed, 74 insertions(+), 74 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 5829bea56..8b9054e60 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -96,7 +96,7 @@ select = [ "I", # isort "B", # flake8-bugbear "N", # flake8-naming - "G004",, # logging-f-string + "G004", # logging-f-string "TC", # flake8-type-checking "UP", # pyupgrade "C4", # flake8-comprehensions diff --git a/temoa/components/technology.py b/temoa/components/technology.py index 7f765746a..579151a78 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -324,7 +324,7 @@ def create_survival_curve(model: TemoaModel) -> None: msg = ( 'For the purposes of investment cost accounting, lifetime_survival_curve must be defined ' 'for each individual year. Gaps between defined years will be filled by linear interpolation. ' - f'Otherwise, these individual years can be defined manually. Interpolated processes: {[rtv for rtv in rtv_interpolated]}' + f'Otherwise, these individual years can be defined manually. Interpolated processes: {list(rtv_interpolated)}' ) logger.info(msg) diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index fae368e55..672bfc9e3 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -639,7 +639,7 @@ def _load_existing_capacity( self._load_component_data(data, model.existing_capacity, rows_to_load) if rows_to_load: - tech_exist_data = sorted(list({(row[1],) for row in rows_to_load})) + tech_exist_data = sorted({(row[1],) for row in rows_to_load}) self._load_component_data(data, model.tech_exist, tech_exist_data) def _load_cost_invest( @@ -753,7 +753,7 @@ def _load_ramping_down( model = TemoaModel() self._load_component_data(data, model.ramp_down_hourly, filtered_data) if filtered_data: - tech_data = sorted(list({(row[1],) for row in filtered_data})) + tech_data = sorted({(row[1],) for row in filtered_data}) tech_filtered = self._filter_data( tech_data, self.manifest_map[model.tech_downramping.name], use_raw_data=False ) @@ -769,7 +769,7 @@ def _load_ramping_up( model = TemoaModel() self._load_component_data(data, model.ramp_up_hourly, filtered_data) if filtered_data: - tech_data = sorted(list({(row[1],) for row in filtered_data})) + tech_data = sorted({(row[1],) for row in filtered_data}) tech_filtered = self._filter_data( tech_data, self.manifest_map[model.tech_upramping.name], use_raw_data=False ) diff --git a/temoa/data_processing/graphviz_util.py b/temoa/data_processing/graphviz_util.py index 478c00eb3..999c8b617 100644 --- a/temoa/data_processing/graphviz_util.py +++ b/temoa/data_processing/graphviz_util.py @@ -124,27 +124,27 @@ def process_input(args: list[str]) -> dict[str, Any]: def get_color_config(grey_flag: bool) -> dict[str, str | tuple[str, ...]]: """Return a dictionary of color configurations for the graph.""" grey_flag = not (grey_flag) - kwargs: dict[str, str | tuple[str, ...]] = dict( - tech_color='darkseagreen' if grey_flag else 'black', - commodity_color='lightsteelblue' if grey_flag else 'black', - unused_color='powderblue' if grey_flag else 'gray75', - arrowheadout_color='forestgreen' if grey_flag else 'black', - arrowheadin_color='firebrick' if grey_flag else 'black', - usedfont_color='black', - unusedfont_color='chocolate' if grey_flag else 'gray75', - menu_color='hotpink', - home_color='gray75', - font_color='black' if grey_flag else 'white', - fill_color='lightsteelblue' if grey_flag else 'white', + kwargs: dict[str, str | tuple[str, ...]] = { + 'tech_color': 'darkseagreen' if grey_flag else 'black', + 'commodity_color': 'lightsteelblue' if grey_flag else 'black', + 'unused_color': 'powderblue' if grey_flag else 'gray75', + 'arrowheadout_color': 'forestgreen' if grey_flag else 'black', + 'arrowheadin_color': 'firebrick' if grey_flag else 'black', + 'usedfont_color': 'black', + 'unusedfont_color': 'chocolate' if grey_flag else 'gray75', + 'menu_color': 'hotpink', + 'home_color': 'gray75', + 'font_color': 'black' if grey_flag else 'white', + 'fill_color': 'lightsteelblue' if grey_flag else 'white', # MODELDETAILED, - md_tech_color='hotpink', - sb_incom_color='lightsteelblue' if grey_flag else 'black', - sb_outcom_color='lawngreen' if grey_flag else 'black', - sb_vpbackg_color='lightgrey', - sb_vp_color='white', - sb_arrow_color='forestgreen' if grey_flag else 'black', + 'md_tech_color': 'hotpink', + 'sb_incom_color': 'lightsteelblue' if grey_flag else 'black', + 'sb_outcom_color': 'lawngreen' if grey_flag else 'black', + 'sb_vpbackg_color': 'lightgrey', + 'sb_vp_color': 'white', + 'sb_arrow_color': 'forestgreen' if grey_flag else 'black', # SUBGRAPH 1 ARROW COLORS - color_list=( + 'color_list': ( ( 'red', 'orange', @@ -163,7 +163,7 @@ def get_color_config(grey_flag: bool) -> dict[str, str | tuple[str, ...]]: if grey_flag else ('black', 'black') ), - ) + } return kwargs diff --git a/temoa/data_processing/make_graphviz.py b/temoa/data_processing/make_graphviz.py index 8c1cd5d45..e609dcd85 100644 --- a/temoa/data_processing/make_graphviz.py +++ b/temoa/data_processing/make_graphviz.py @@ -204,20 +204,20 @@ def create_main_results_diagram( demissions = {(ee, '') for ee in commodity_emissions if ee not in usede} self.__log__('CreateMainResultsDiagram: creating diagrams') - args = dict( - period=period, - splinevar=self.colors['splinevar'], - dtechs=create_text_nodes(dtechs, indent=2), - etechs=create_text_nodes(etechs, indent=2), - xnodes=create_text_nodes(xnodes, indent=2), - dcarriers=create_text_nodes(dcarriers, indent=2), - ecarriers=create_text_nodes(ecarriers, indent=2), - demissions=create_text_nodes(demissions, indent=2), - eemissions=create_text_nodes(eemissions, indent=2), - dflows=create_text_edges(dflows, indent=2), - eflowsi=create_text_edges(eflowsi, indent=3), - eflowso=create_text_edges(eflowso, indent=3), - ) + args = { + 'period': period, + 'splinevar': self.colors['splinevar'], + 'dtechs': create_text_nodes(dtechs, indent=2), + 'etechs': create_text_nodes(etechs, indent=2), + 'xnodes': create_text_nodes(xnodes, indent=2), + 'dcarriers': create_text_nodes(dcarriers, indent=2), + 'ecarriers': create_text_nodes(ecarriers, indent=2), + 'demissions': create_text_nodes(demissions, indent=2), + 'eemissions': create_text_nodes(eemissions, indent=2), + 'dflows': create_text_edges(dflows, indent=2), + 'eflowsi': create_text_edges(eflowsi, indent=3), + 'eflowso': create_text_edges(eflowso, indent=3), + } output_path = output_name + '.' + output_format self.__generate_graph__(results_dot_fmt, args, output_name, output_format) @@ -276,16 +276,16 @@ def create_tech_results_diagrams( output_path = output_name + '.' + output_format if vnodes: self.__log__('CreateTechResultsDiagrams: creating diagrams') - args: dict[str, Any] = dict( - cluster_vintage_url='#', - total_cap=total_cap, - inp_technology=tech, - period=period, - vnodes=create_text_nodes(vnodes, indent=2), - enodes=create_text_nodes(enodes, indent=2), - iedges=create_text_edges(iedges, indent=2), - oedges=create_text_edges(oedges, indent=2), - ) + args: dict[str, Any] = { + 'cluster_vintage_url': '#', + 'total_cap': total_cap, + 'inp_technology': tech, + 'period': period, + 'vnodes': create_text_nodes(vnodes, indent=2), + 'enodes': create_text_nodes(enodes, indent=2), + 'iedges': create_text_edges(iedges, indent=2), + 'oedges': create_text_edges(oedges, indent=2), + } self.__generate_graph__(tech_results_dot_fmt, args, output_name, output_format) else: self.__log__('CreateTechResultsDiagrams: nothing to create') @@ -354,15 +354,15 @@ def create_commodity_partial_results( dedges.add((t, comm, '')) self.__log__('CreateCommodityPartialResults: creating diagrams') - args = dict( - inp_commodity=comm, - period=period, - resource_node=create_text_nodes(rcnode), - used_nodes=create_text_nodes(enodes, indent=2), - unused_nodes=create_text_nodes(dnodes, indent=2), - used_edges=create_text_edges(eedges, indent=2), - unused_edges=create_text_edges(dedges, indent=2), - ) + args = { + 'inp_commodity': comm, + 'period': period, + 'resource_node': create_text_nodes(rcnode), + 'used_nodes': create_text_nodes(enodes, indent=2), + 'unused_nodes': create_text_nodes(dnodes, indent=2), + 'used_edges': create_text_edges(eedges, indent=2), + 'unused_edges': create_text_edges(dedges, indent=2), + } output_path = output_name + '.' + output_format self.__generate_graph__(commodity_dot_fmt, args, output_name, output_format) self.__log__('CreateCommodityPartialResults: graph generated, returning') @@ -431,13 +431,13 @@ def create_complete_input_graph( self.__log__('createCompleteInputGraph: creating diagrams') - args = dict( - enodes=''.join(f'"{x}";\n\t\t' for x in nodes), - tnodes=''.join(f'"{x}";\n\t\t' for x in tech), - iedges=''.join(f'{x};\n\t\t' for x in to_tech), - oedges=''.join(f'{x};\n\t\t' for x in from_tech), - snodes=';'.join(f'"{x}"' for x in ltech), - ) + args = { + 'enodes': ''.join(f'"{x}";\n\t\t' for x in nodes), + 'tnodes': ''.join(f'"{x}";\n\t\t' for x in tech), + 'iedges': ''.join(f'{x};\n\t\t' for x in to_tech), + 'oedges': ''.join(f'{x};\n\t\t' for x in from_tech), + 'snodes': ';'.join(f'"{x}"' for x in ltech), + } output_path = output_name + '.' + output_format self.__generate_graph__(quick_run_dot_fmt, args, output_name, output_format) self.__log__('createCompleteInputGraph: graph generated, returning') diff --git a/temoa/data_processing/make_output_plots.py b/temoa/data_processing/make_output_plots.py index a1d4fa8ac..810d75338 100644 --- a/temoa/data_processing/make_output_plots.py +++ b/temoa/data_processing/make_output_plots.py @@ -105,7 +105,7 @@ def get_sectors(self, plot_type: int) -> list[str]: for row in data: sectors.add(str(row[0])) - res = sorted(list(sectors)) + res = sorted(sectors) res.insert(0, 'all') return res @@ -132,8 +132,8 @@ def process_data( periods_set.add(int(row[1])) techs_set.add(str(row[2])) - periods = sorted(list(periods_set)) - techs = sorted(list(techs_set)) + periods = sorted(periods_set) + techs = sorted(techs_set) output_values: PlotData = {} for tech in techs: diff --git a/temoa/model_checking/commodity_network_manager.py b/temoa/model_checking/commodity_network_manager.py index 11d065492..d93f73f3e 100644 --- a/temoa/model_checking/commodity_network_manager.py +++ b/temoa/model_checking/commodity_network_manager.py @@ -116,7 +116,7 @@ def analyze_network(self) -> bool: """ self.filtered_data = self.orig_data.clone() # Identify regions to analyze (excluding exchange pseudo-regions) - self.regions = set(sorted({r for (r, p) in self.orig_data.available_techs if '-' not in r})) + self.regions = set({r for (r, p) in self.orig_data.available_techs if '-' not in r}) for region in self.regions: logger.info('Starting network analysis for region %s', region) diff --git a/temoa/utilities/db_migration_to_v3.py b/temoa/utilities/db_migration_to_v3.py index ec16f9dbf..13996598f 100644 --- a/temoa/utilities/db_migration_to_v3.py +++ b/temoa/utilities/db_migration_to_v3.py @@ -355,7 +355,7 @@ # need to convert null -> 0 for unlim_cap to match new schema that does not allow null new_data = [] for row in data: - new_row = [t for t in row] + new_row = list(row) if new_row[4] is None: new_row[4] = 0 new_data.append(tuple(new_row)) diff --git a/temoa/utilities/db_migration_v3_to_v3_1.py b/temoa/utilities/db_migration_v3_to_v3_1.py index 8c7fc4fe7..c7458de4d 100644 --- a/temoa/utilities/db_migration_v3_to_v3_1.py +++ b/temoa/utilities/db_migration_v3_to_v3_1.py @@ -234,7 +234,7 @@ def column_check(old_name: str, new_name: str) -> bool: time_all = sorted(time_all)[0:-1] # Exclude horizon end # get lifetimes. Major headache but needs to be done -lifetime_process = dict() +lifetime_process = {} data = cur.execute('SELECT region, tech, vintage FROM Efficiency').fetchall() for rtv in data: lifetime_process[rtv] = TemoaModel.default_lifetime_tech @@ -283,7 +283,7 @@ def column_check(old_name: str, new_name: str) -> bool: for r, t, v in data[['region','tech','vintage']] ] elif 'tech' in cols: - periods = dict() + periods = {} for r, t in data[['region','tech']].drop_duplicates().values: periods[r, t] = [ p for p in time_optimize diff --git a/tests/test_set_consistency.py b/tests/test_set_consistency.py index 532016e1f..c9167fef9 100644 --- a/tests/test_set_consistency.py +++ b/tests/test_set_consistency.py @@ -53,8 +53,8 @@ def test_set_consistency( } # compare sets where they exist in the model. - overage_in_model = dict() - shortage_in_model = dict() + overage_in_model = {} + shortage_in_model = {} for set_name, s in model_sets.items(): if set_name == 'cost_emission_rpe': pass From fe9756f885ebfd32252189d4ab1187d8a1cf5299 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 22 Nov 2025 10:50:44 -0500 Subject: [PATCH 353/587] fixing remaining G004 logger warnings as well --- temoa/_internal/temoa_sequencer.py | 4 ++-- temoa/components/technology.py | 30 ++++++++++++++++----------- temoa/model_checking/pricing_check.py | 7 +++++-- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/temoa/_internal/temoa_sequencer.py b/temoa/_internal/temoa_sequencer.py index 6eb5924a2..553e76304 100644 --- a/temoa/_internal/temoa_sequencer.py +++ b/temoa/_internal/temoa_sequencer.py @@ -62,7 +62,7 @@ def __init__( if mode_override and mode_override != self.config.scenario_mode: self.temoa_mode = mode_override self.config.scenario_mode = mode_override - logger.info(f'Temoa Mode overridden by caller to: {self.temoa_mode}') + logger.info('Temoa Mode overridden by caller to: %s', self.temoa_mode) # for results catching for perfect_foresight or testing self.pf_results: pyomo.opt.SolverResults | None = None @@ -131,7 +131,7 @@ def start(self) -> None: self._run_preliminary_checks() # The mode is now definitively set, so we can proceed. - logger.info(f'Executing scenario in mode: {self.temoa_mode}') + logger.info('Executing scenario in mode: %s', self.temoa_mode) # Select execution path based on mode match self.temoa_mode: diff --git a/temoa/components/technology.py b/temoa/components/technology.py index 579151a78..af51ad1c4 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -153,27 +153,33 @@ def populate_core_dictionaries(model: TemoaModel) -> None: if v in model.vintage_exist: if process not in exist_indices and t not in model.tech_uncap: logger.warning( - f'Warning: {process} has a specified efficiency, but does not ' - f'have any existing install base (existing_capacity).' + 'Warning: %s has a specified efficiency, but does not ' + 'have any existing install base (existing_capacity).', + process, ) continue if t not in model.tech_uncap and model.existing_capacity[process] == 0: logger.warning( - f'Notice: Unnecessary specification of existing_capacity for {process}. ' - f'Declaring a capacity of zero may be omitted.' + 'Notice: Unnecessary specification of existing_capacity for %s. ' + 'Declaring a capacity of zero may be omitted.', + process, ) continue if v + lifetime <= first_period: logger.info( - f'{process} specified as existing_capacity, but its ' - f'lifetime ({lifetime} years) does not extend past the ' - f'beginning of time_future ({first_period}).' + '%s specified as existing_capacity, but its ' + 'lifetime (%s years) does not extend past the ' + 'beginning of time_future (%s).', + process, + lifetime, + first_period, ) if model.efficiency[r, i, t, v, o] == 0: logger.info( - f'Notice: Unnecessary specification of efficiency for {(r, i, t, v, o)}. ' - f'Specifying an efficiency of zero may be omitted.' + 'Notice: Unnecessary specification of efficiency for %s. ' + 'Specifying an efficiency of zero may be omitted.', + (r, i, t, v, o), ) continue @@ -321,12 +327,12 @@ def create_survival_curve(model: TemoaModel) -> None: model.survival_curve_periods[r, t, v].update(between_periods) if rtv_interpolated: - msg = ( + logger.info( 'For the purposes of investment cost accounting, lifetime_survival_curve must be defined ' 'for each individual year. Gaps between defined years will be filled by linear interpolation. ' - f'Otherwise, these individual years can be defined manually. Interpolated processes: {list(rtv_interpolated)}' + 'Otherwise, these individual years can be defined manually. Interpolated processes: %s', + list(rtv_interpolated), ) - logger.info(msg) def check_efficiency_indices(model: TemoaModel) -> None: diff --git a/temoa/model_checking/pricing_check.py b/temoa/model_checking/pricing_check.py index b1e548a56..a6d0c0abb 100644 --- a/temoa/model_checking/pricing_check.py +++ b/temoa/model_checking/pricing_check.py @@ -98,8 +98,11 @@ def price_checker(model: TemoaModel) -> bool: if not any((has_fc, has_ic)): logger.warning( - f'Check 1a (detail): tech with capacity {tech} of vintage {vintage} in region {region} does not ' - f'have a Fixed Cost or Investment Cost component' + 'Check 1a (detail): tech with capacity %s of vintage %s in region %s does not ' + 'have a Fixed Cost or Investment Cost component', + tech, + vintage, + region, ) techs_without_fc_or_ic.add(tech) warnings = True From 355a2bca895bc799f07ba1c966daf7a38e22cf8d Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 22 Nov 2025 11:34:02 -0500 Subject: [PATCH 354/587] fixing linter issues --- temoa/_internal/run_actions.py | 32 ++ temoa/core/config.py | 3 + temoa/data_processing/graphviz_formats.py | 287 ------------------ temoa/data_processing/graphviz_util.py | 241 --------------- temoa/model_checking/commodity_graph.py | 123 +++++++- .../database_util.py | 0 temoa/utilities/graphviz_formats.py | 287 ++++++++++++++++++ .../graphviz_generator.py} | 163 +++++++--- temoa/utilities/graphviz_util.py | 126 ++++++++ 9 files changed, 698 insertions(+), 564 deletions(-) delete mode 100644 temoa/data_processing/graphviz_formats.py delete mode 100644 temoa/data_processing/graphviz_util.py rename temoa/{data_processing => utilities}/database_util.py (100%) create mode 100644 temoa/utilities/graphviz_formats.py rename temoa/{data_processing/make_graphviz.py => utilities/graphviz_generator.py} (84%) create mode 100644 temoa/utilities/graphviz_util.py diff --git a/temoa/_internal/run_actions.py b/temoa/_internal/run_actions.py index a11b3ff32..c646dbd7a 100644 --- a/temoa/_internal/run_actions.py +++ b/temoa/_internal/run_actions.py @@ -361,4 +361,36 @@ def handle_results( # normal (non-MGA) run will have a total_cost as the OBJ: if hasattr(instance, 'total_cost'): logger.info('total_cost value: %0.2f', value(instance.total_cost)) + + if config.graphviz_output: + try: + from temoa.utilities.graphviz_generator import GraphvizDiagramGenerator + + logger.info('Generating Graphviz plots...') + # Determine output directory (same as other outputs) + out_dir = str(config.output_path) + + # Initialize generator + graph_gen = GraphvizDiagramGenerator( + db_file=str(config.output_database), + scenario=config.scenario, + out_dir=out_dir, + verbose=0, # Less verbose for integrated run + ) + graph_gen.connect() + + # Get periods from the model instance + periods = sorted(instance.time_optimize) + + for period in periods: + # Generate main results diagram for the period + # We pass None for region to generate for all/default + graph_gen.create_main_results_diagram(period=period, region=None) + + graph_gen.close() + logger.info('Graphviz plots generated in %s', graph_gen.out_dir) + + except Exception as e: + logger.error('Failed to generate Graphviz plots: %s', e, exc_info=True) + return diff --git a/temoa/core/config.py b/temoa/core/config.py index fb962a0bc..3ad005fac 100644 --- a/temoa/core/config.py +++ b/temoa/core/config.py @@ -54,6 +54,7 @@ def __init__( price_check: bool = True, source_trace: bool = False, plot_commodity_network: bool = False, + graphviz_output: bool = False, ): if '-' in scenario: raise ValueError( @@ -134,6 +135,7 @@ def __init__( 'Both are required to produce plots.' ) self.plot_commodity_network = plot_commodity_network and self.source_trace + self.graphviz_output = graphviz_output # warn if output db != input db if self.input_database.suffix == self.output_database.suffix: # they are both .db/.sqlite @@ -198,6 +200,7 @@ def __repr__(self) -> str: msg += '{:>{}s}: {}\n'.format('Price check', width, self.price_check) msg += '{:>{}s}: {}\n'.format('Source trace', width, self.source_trace) msg += '{:>{}s}: {}\n'.format('Commodity network plots', width, self.plot_commodity_network) + msg += '{:>{}s}: {}\n'.format('Graphviz output', width, self.graphviz_output) msg += spacer msg += '{:>{}s}: {}\n'.format('Selected solver', width, self.solver_name) diff --git a/temoa/data_processing/graphviz_formats.py b/temoa/data_processing/graphviz_formats.py deleted file mode 100644 index a517e1bba..000000000 --- a/temoa/data_processing/graphviz_formats.py +++ /dev/null @@ -1,287 +0,0 @@ -# SVG Formats - -results_dot_fmt = """\ -strict digraph model { - label = "Results for %(period)s" - - rankdir = "LR" ; - smoothtype = "power_dist" ; - splines = "%(splinevar)s" ; - - node [ style="filled" ] ; - edge [ arrowhead="vee" ] ; - - subgraph unused_techs { - node [ - color = "%(unused_color)s", - fontcolor = "%(unusedfont_color)s", - shape = "box", - fontcolor = "%(font_color)s" - ] ; - - %(dtechs)s - } - - subgraph unused_energy_carriers { - node [ - color = "%(unused_color)s", - fontcolor = "%(unusedfont_color)s", - shape = "circle", - fillcolor = "%(fill_color)s" - ] ; - - %(dcarriers)s - } - - subgraph unused_emissions { - node [ - color = "%(unused_color)s", - fontcolor = "%(unusedfont_color)s", - shape = "circle", - fillcolor = "%(fill_color)s" - ] - - %(demissions)s - } - - subgraph in_use_techs { - node [ - color = "%(tech_color)s", - fontcolor = "%(usedfont_color)s", - shape = "box", - fontcolor = "%(font_color)s" - ] ; - - %(etechs)s - } - - subgraph in_use_energy_carriers { - node [ - color = "%(commodity_color)s", - fontcolor = "%(usedfont_color)s", - shape = "circle", - fillcolor = "%(fill_color)s" - ] ; - - %(ecarriers)s - } - - subgraph in_use_emissions { - node [ - color = "%(commodity_color)s", - fontcolor = "%(usedfont_color)s", - shape = "circle", - fillcolor = "%(fill_color)s" - ] ; - - %(eemissions)s - } - - subgraph unused_flows { - edge [ color="%(unused_color)s" ] - - %(dflows)s - } - - subgraph in_use_flows { - subgraph inputs { - edge [ color="%(arrowheadin_color)s" ] ; - - %(eflowsi)s - } - - subgraph outputs { - edge [ color="%(arrowheadout_color)s" ] ; - - %(eflowso)s - } - } - - {rank = same; %(xnodes)s} -} -""" - - -tech_results_dot_fmt = """\ -strict digraph model { - label = "Results for %(inp_technology)s in %(period)s" ; - - compound = "True" ; - concentrate = "True"; - rankdir = "LR" ; - splines = "%(splinevar)s" ; - - node [ style="filled" ] ; - edge [ arrowhead="vee" ] ; - - subgraph cluster_vintages { - label = "Vintages\\nCapacity: %(total_cap).2f" ; - - href = "%(cluster_vintage_url)s" ; - style = "filled" - color = "%(sb_vpbackg_color)s" - - node [ color="%(sb_vp_color)s", shape="box", fontcolor="%(usedfont_color)s" ] ; - - %(vnodes)s - } - - subgraph energy_carriers { - node [ - color = "%(commodity_color)s", - fontcolor = "%(usedfont_color)s", - shape = "circle", - fillcolor = "%(fill_color)s" - ] ; - - %(enodes)s - } - - subgraph inputs { - edge [ color="%(arrowheadin_color)s" ] ; - - %(iedges)s - } - - subgraph outputs { - edge [ color="%(arrowheadout_color)s" ] ; - - %(oedges)s - } -} -""" - -slice_dot_fmt = """\ -strict digraph model { - label = "Activity split of process %(inp_technology)s, %(vintage)s in year %(period)s" ; - - compound = "True" ; - concentrate = "True"; - rankdir = "LR" ; - splines = "%(splinevar)s" ; - - node [ style="filled" ] ; - edge [ arrowhead="vee" ] ; - - subgraph cluster_slices { - label = "%(vintage)s Capacity: %(total_cap).2f" ; - - color = "%(vintage_cluster_color)s" ; - rank = "same" ; - style = "filled" ; - - node [ color="%(vintage_color)s", shape="box", fontcolor="%(usedfont_color)s" ] ; - - %(snodes)s - } - - subgraph energy_carriers { - node [ - color = "%(commodity_color)s", - fontcolor = "%(usedfont_color)s", - shape = "circle", - fillcolor = "%(fill_color)s" - ] ; - - %(enodes)s - } - - subgraph inputs { - edge [ color="%(input_color)s" ] ; - - %(iedges)s - } - - subgraph outputs { - edge [ color="%(output_color)s" ] ; - - %(oedges)s - } -} -""" - -commodity_dot_fmt = """\ -strict digraph result_commodity_%(inp_commodity)s { - label = "%(inp_commodity)s - %(period)s" ; - - compound = "True" ; - concentrate = "True" ; - rankdir = "LR" ; - splines = "True" ; - - node [ shape="box", style="filled", fontcolor="%(font_color)s" ] ; - edge [ - arrowhead = "vee", - fontsize = "8", - label = " ", - labelfloat = "False", - labelfontcolor = "lightgreen" - len = "2", - weight = "0.5", - ] ; - - %(resource_node)s - - subgraph used_techs { - node [ color="%(tech_color)s" ] ; - - %(used_nodes)s - } - - subgraph used_techs { - node [ color="%(unused_color)s" ] ; - - %(unused_nodes)s - } - - subgraph in_use_flows { - edge [ color="%(sb_arrow_color)s" ] ; - - %(used_edges)s - } - - subgraph unused_flows { - edge [ color="%(unused_color)s" ] ; - - %(unused_edges)s - } -} -""" - -quick_run_dot_fmt = """\ -strict digraph model { - rankdir = "LR" ; - - // Default node and edge attributes - node [ style="filled" ] ; - edge [ arrowhead="vee", labelfontcolor="lightgreen" ] ; - - // Define individual nodes - subgraph techs { - node [ color="%(tech_color)s", shape="box", fontcolor="%(font_color)s" ] ; - - %(tnodes)s - } - - subgraph energy_carriers { - node [ color="%(commodity_color)s", shape="circle", fillcolor="%(fill_color)s" ] ; - - %(enodes)s - } - - // Define edges and any specific edge attributes - subgraph inputs { - edge [ color="%(arrowheadin_color)s" ] ; - - %(iedges)s - } - - subgraph outputs { - edge [ color="%(arrowheadout_color)s" ] ; - - %(oedges)s - } - - {rank = same; %(snodes)s} -} -""" diff --git a/temoa/data_processing/graphviz_util.py b/temoa/data_processing/graphviz_util.py deleted file mode 100644 index 999c8b617..000000000 --- a/temoa/data_processing/graphviz_util.py +++ /dev/null @@ -1,241 +0,0 @@ -import argparse -from collections.abc import Callable, Iterable, Sequence, Sized -from typing import Any - - -def process_input(args: list[str]) -> dict[str, Any]: - """Parse command line arguments.""" - parser = argparse.ArgumentParser(description='Generate Output Plot') - parser.add_argument( - '-i', - '--input', - action='store', - dest='ifile', - help='Input Database Filename ', - required=True, - ) - parser.add_argument( - '-f', - '--format', - action='store', - dest='image_format', - help='Graphviz output format (Default: svg)', - default='svg', - ) - parser.add_argument( - '-c', - '--show_capacity', - action='store_true', - dest='show_capacity', - help='Whether capacity shows up in subgraphs (Default: not shown)', - default=False, - ) - parser.add_argument( - '-v', - '--splinevar', - action='store_true', - dest='splinevar', - help='Whether subgraph edges to be straight or curved (Default: Straight)', - default=False, - ) - parser.add_argument( - '-t', - '--graph_type', - action='store', - dest='graph_type', - help='Type of subgraph (Default: separate_vintages)', - choices=['separate_vintages', 'explicit_vintages'], - default='separate_vintages', - ) - parser.add_argument( - '-g', - '--gray', - action='store_true', - dest='grey_flag', - help='If specified, generates graph in graycale', - default=False, - ) - parser.add_argument( - '-n', - '--name', - action='store', - dest='quick_name', - help='Specify the extension you wish to give your quick run', - ) - parser.add_argument( - '-o', - '--output', - action='store', - dest='res_dir', - help='Optional output file path (to dump the images folder)', - default='./', - ) - - group1 = parser.add_mutually_exclusive_group() - group1.add_argument( - '-b', - '--technology', - action='store', - dest='inp_technology', - help='Technology for which graph to be generated', - ) - group1.add_argument( - '-a', - '--commodity', - action='store', - dest='inp_commodity', - help='Commodity for which graph to be generated', - ) - - parser.add_argument( - '-s', - '--scenario', - action='store', - dest='scenario_name', - help='Model run scenario name', - default=None, - ) - parser.add_argument( - '-y', - '--year', - action='store', - dest='period', - type=int, - help='The period for which the graph is to be generated (Used only for output plots)', - ) - parser.add_argument( - '-r', - '--region', - action='store', - dest='region', - help='The region for which the graph is to be generated', - default=None, - ) - - options = parser.parse_args(args) - - if bool(options.scenario_name) ^ bool(options.period): - parser.print_help() - raise ValueError('Scenario and input year must both be present or not present together') - - return vars(options) - - -def get_color_config(grey_flag: bool) -> dict[str, str | tuple[str, ...]]: - """Return a dictionary of color configurations for the graph.""" - grey_flag = not (grey_flag) - kwargs: dict[str, str | tuple[str, ...]] = { - 'tech_color': 'darkseagreen' if grey_flag else 'black', - 'commodity_color': 'lightsteelblue' if grey_flag else 'black', - 'unused_color': 'powderblue' if grey_flag else 'gray75', - 'arrowheadout_color': 'forestgreen' if grey_flag else 'black', - 'arrowheadin_color': 'firebrick' if grey_flag else 'black', - 'usedfont_color': 'black', - 'unusedfont_color': 'chocolate' if grey_flag else 'gray75', - 'menu_color': 'hotpink', - 'home_color': 'gray75', - 'font_color': 'black' if grey_flag else 'white', - 'fill_color': 'lightsteelblue' if grey_flag else 'white', - # MODELDETAILED, - 'md_tech_color': 'hotpink', - 'sb_incom_color': 'lightsteelblue' if grey_flag else 'black', - 'sb_outcom_color': 'lawngreen' if grey_flag else 'black', - 'sb_vpbackg_color': 'lightgrey', - 'sb_vp_color': 'white', - 'sb_arrow_color': 'forestgreen' if grey_flag else 'black', - # SUBGRAPH 1 ARROW COLORS - 'color_list': ( - ( - 'red', - 'orange', - 'gold', - 'green', - 'blue', - 'purple', - 'hotpink', - 'cyan', - 'burlywood', - 'coral', - 'limegreen', - 'black', - 'brown', - ) - if grey_flag - else ('black', 'black') - ), - } - return kwargs - - -def _get_len(key: int) -> Callable[[Sequence[Sized]], int]: - """Return a function that gets the length of an item at a specific index in a sequence.""" - - def wrapped(obj: Sequence[Sized]) -> int: - return len(obj[key]) - - return wrapped - - -def create_text_nodes(nodes: Iterable[tuple[str, str]], indent: int = 1) -> str: - """ - Return a set of text nodes in Graphviz DOT format, optimally padded for - easier reading and debugging. - - Args: - nodes: iterable of (id, attribute) node tuples - e.g. [(node1, attr1), (node2, attr2), ...] - indent: integer, number of tabs with which to indent all Dot node lines - """ - if not nodes: - return '// no nodes in this section' - - # Step 1: for alignment, get max item length in node list - # The `+ 2` accounts for the two extra quotes that will be added. - maxl = max(map(_get_len(0), nodes), default=0) + 2 - - # Step 2: prepare a text format based on max node size that pads all - # lines with attributes - nfmt_attr = f'{{0:<{maxl}}} [ {{1}} ] ;' # node text format - nfmt_noa = '{0} ;' - - # Step 3: create each node, and place string representation in a set to - # guarantee uniqueness - q = '"%s"' # enforce quoting for all nodes - gviz = {nfmt_attr.format(q % n, a) for n, a in nodes if a} - gviz.update(nfmt_noa.format(q % n) for n, a in nodes if not a) - - # Step 4: return a sorted version of nodes, as a single string - indent_str = '\n' + '\t' * indent - return indent_str.join(sorted(gviz)) - - -def create_text_edges(edges: Iterable[tuple[str, str, str]], indent: int = 1) -> str: - """ - Return a set of text edge definitions in Graphviz DOT format, optimally - padded for easier reading and debugging. - - Args: - edges: iterable of (from, to, attribute) edge tuples - e.g. [(inp1, tech1, attr1), (inp2, tech2, attr2), ...] - indent: integer, number of tabs with which to indent all Dot edge lines - """ - if not edges: - return '// no edges in this section' - - # Step 1: for alignment, get max length of items on left and right side of - # graph operator token ('->'). The `+ 2` accounts for the two extra quotes. - maxl = max(map(_get_len(0), edges), default=0) + 2 - maxr = max(map(_get_len(1), edges), default=0) + 2 - - # Step 2: prepare format to be "\n\tinp+PADDING -> out+PADDING [..." - efmt_attr = f'{{0:<{maxl}}} -> {{1:<{maxr}}} [ {{2}} ] ;' # with attributes - efmt_noa = f'{{0:<{maxl}}} -> {{1}} ;' # no attributes - - # Step 3: add each edge to a set (to guarantee unique entries only) - q = '"%s"' # enforce quoting for all tokens - gviz = {efmt_attr.format(q % i, q % t, a) for i, t, a in edges if a} - gviz.update(efmt_noa.format(q % i, q % t) for i, t, a in edges if not a) - - # Step 4: return a sorted version of the edges, as a single string - indent_str = '\n' + '\t' * indent - return indent_str.join(sorted(gviz)) diff --git a/temoa/model_checking/commodity_graph.py b/temoa/model_checking/commodity_graph.py index 3c70c246b..615aa1290 100644 --- a/temoa/model_checking/commodity_graph.py +++ b/temoa/model_checking/commodity_graph.py @@ -10,10 +10,17 @@ calculate_initial_positions, calculate_tech_graph_positions, ) +from temoa.utilities.graphviz_formats import results_dot_fmt +from temoa.utilities.graphviz_util import ( + create_text_edges, + create_text_nodes, + get_color_config, +) from temoa.utilities.visualizer import make_nx_graph, nx_to_vis if TYPE_CHECKING: from collections.abc import Iterable + from pathlib import Path from temoa.core.config import TemoaConfig from temoa.model_checking.network_model_data import EdgeTuple, NetworkModelData @@ -231,6 +238,114 @@ def generate_commodity_graph( return dg, sector_colors +logger = logging.getLogger(__name__) + + +def generate_graphviz_files( + period: Period, + region: Region, + network_data: NetworkModelData, + all_techs: Iterable[EdgeTuple], + sector_colors: dict[Sector, str], + output_dir: Path, +) -> None: + """ + Generates Graphviz .dot and .svg files matching the legacy format. + """ + import subprocess + + # Prepare data structures for Graphviz + # We need to categorize techs, commodities, and flows. + + # Sets to hold unique strings for Graphviz + etechs: set[tuple[str, str]] = set() # Used techs + dtechs: set[tuple[str, str]] = ( + set() + ) # Unused techs (we might not have this info easily, maybe skip or infer) + ecarriers: set[tuple[str, str]] = set() # Used carriers + dcarriers: set[tuple[str, str]] = set() # Unused carriers + eemissions: set[tuple[str, str]] = set() # Used emissions + demissions: set[tuple[str, str]] = set() # Unused emissions + eflowsi: set[tuple[str, str, str]] = set() # Input flows (Comm -> Tech) + eflowso: set[tuple[str, str, str]] = set() # Output flows (Tech -> Comm) + dflows: set[tuple[str, str, str]] = set() # Unused flows + xnodes: set[tuple[str, str]] = set() # Ethos nodes? + + # Helper to format attributes + def get_tech_attr(tech: str, cap: float = 0.0) -> str: + # We might not have capacity info here easily without querying DB or passing it in. + # For now, we'll just show the label. + return f'label="{tech}"' + + def get_comm_attr(comm: str) -> str: + return f'label="{comm}"' + + def get_flow_attr(flow: float = 0.0) -> str: + return f'label="{flow:.2f}"' if flow > 0 else '' + + # Iterate over all active technologies/edges + used_techs = set() + used_comms = set() + + for edge in all_techs: + tech = edge.tech + ic = edge.input_comm + oc = edge.output_comm + + used_techs.add(tech) + + # Input Flow: Comm -> Tech + if ic != 'ethos': + used_comms.add(ic) + ecarriers.add((ic, get_comm_attr(ic))) + eflowsi.add((ic, tech, '')) # No flow value for now + + # Output Flow: Tech -> Comm + if oc != 'ethos': + used_comms.add(oc) + ecarriers.add((oc, get_comm_attr(oc))) + eflowso.add((tech, oc, '')) # No flow value for now + + # Tech Node + etechs.add((tech, get_tech_attr(tech))) + + # Generate the DOT content + colors = get_color_config(False) # Default to color + + args = { + 'period': period, + 'splinevar': 'true', # Default + 'dtechs': create_text_nodes(dtechs, indent=2), + 'etechs': create_text_nodes(etechs, indent=2), + 'xnodes': create_text_nodes(xnodes, indent=2), + 'dcarriers': create_text_nodes(dcarriers, indent=2), + 'ecarriers': create_text_nodes(ecarriers, indent=2), + 'demissions': create_text_nodes(demissions, indent=2), + 'eemissions': create_text_nodes(eemissions, indent=2), + 'dflows': create_text_edges(dflows, indent=2), + 'eflowsi': create_text_edges(eflowsi, indent=3), + 'eflowso': create_text_edges(eflowso, indent=3), + **colors, + } + + dot_content = results_dot_fmt.format(**args) + + output_name = output_dir / f'results_{region}_{period}' + dot_file = output_name.with_suffix('.dot') + svg_file = output_name.with_suffix('.svg') + + with open(dot_file, 'w') as f: + f.write(dot_content) + + try: + subprocess.call(['dot', '-Tsvg', f'-o{svg_file}', str(dot_file)]) + logger.info('Generated Graphviz plot: %s', svg_file) + except FileNotFoundError: + logger.error("Graphviz 'dot' command not found. Please install Graphviz.") + except Exception as e: + logger.error('Failed to run Graphviz: %s', e) + + def visualize_graph( region: Region, period: Period, @@ -303,7 +418,13 @@ def visualize_graph( else: logger.error('Failed to generate network graphs') - # 7. Perform cycle detection on the commodity graph + # 7. Generate Graphviz output if requested + if config.graphviz_output: + generate_graphviz_files( + period, region, network_data, all_techs_for_period, sector_colors, config.output_path + ) + + # 8. Perform cycle detection on the commodity graph try: for cycle in nx.simple_cycles(G=commodity_graph): if len(cycle) < 2: diff --git a/temoa/data_processing/database_util.py b/temoa/utilities/database_util.py similarity index 100% rename from temoa/data_processing/database_util.py rename to temoa/utilities/database_util.py diff --git a/temoa/utilities/graphviz_formats.py b/temoa/utilities/graphviz_formats.py new file mode 100644 index 000000000..a14f8dd50 --- /dev/null +++ b/temoa/utilities/graphviz_formats.py @@ -0,0 +1,287 @@ +# SVG Formats + +results_dot_fmt = """\ +strict digraph model {{ + label = "Results for {period}" + + rankdir = "LR" ; + smoothtype = "power_dist" ; + splines = "{splinevar}" ; + + node [ style="filled" ] ; + edge [ arrowhead="vee" ] ; + + subgraph unused_techs {{ + node [ + color = "{unused_color}", + fontcolor = "{unusedfont_color}", + shape = "box", + fontcolor = "{font_color}" + ] ; + + {dtechs} + }} + + subgraph unused_energy_carriers {{ + node [ + color = "{unused_color}", + fontcolor = "{unusedfont_color}", + shape = "circle", + fillcolor = "{fill_color}" + ] ; + + {dcarriers} + }} + + subgraph unused_emissions {{ + node [ + color = "{unused_color}", + fontcolor = "{unusedfont_color}", + shape = "circle", + fillcolor = "{fill_color}" + ] + + {demissions} + }} + + subgraph in_use_techs {{ + node [ + color = "{tech_color}", + fontcolor = "{usedfont_color}", + shape = "box", + fontcolor = "{font_color}" + ] ; + + {etechs} + }} + + subgraph in_use_energy_carriers {{ + node [ + color = "{commodity_color}", + fontcolor = "{usedfont_color}", + shape = "circle", + fillcolor = "{fill_color}" + ] ; + + {ecarriers} + }} + + subgraph in_use_emissions {{ + node [ + color = "{commodity_color}", + fontcolor = "{usedfont_color}", + shape = "circle", + fillcolor = "{fill_color}" + ] ; + + {eemissions} + }} + + subgraph unused_flows {{ + edge [ color="{unused_color}" ] + + {dflows} + }} + + subgraph in_use_flows {{ + subgraph inputs {{ + edge [ color="{arrowheadin_color}" ] ; + + {eflowsi} + }} + + subgraph outputs {{ + edge [ color="{arrowheadout_color}" ] ; + + {eflowso} + }} + }} + + {{rank = same; {xnodes}}} +}} +""" + + +tech_results_dot_fmt = """\ +strict digraph model {{ + label = "Results for {inp_technology} in {period}" ; + + compound = "True" ; + concentrate = "True"; + rankdir = "LR" ; + splines = "{splinevar}" ; + + node [ style="filled" ] ; + edge [ arrowhead="vee" ] ; + + subgraph cluster_vintages {{ + label = "Vintages\\nCapacity: {total_cap:.2f}" ; + + href = "{cluster_vintage_url}" ; + style = "filled" + color = "{sb_vpbackg_color}" + + node [ color="{sb_vp_color}", shape="box", fontcolor="{usedfont_color}" ] ; + + {vnodes} + }} + + subgraph energy_carriers {{ + node [ + color = "{commodity_color}", + fontcolor = "{usedfont_color}", + shape = "circle", + fillcolor = "{fill_color}" + ] ; + + {enodes} + }} + + subgraph inputs {{ + edge [ color="{arrowheadin_color}" ] ; + + {iedges} + }} + + subgraph outputs {{ + edge [ color="{arrowheadout_color}" ] ; + + {oedges} + }} +}} +""" + +slice_dot_fmt = """\ +strict digraph model {{ + label = "Activity split of process {inp_technology}, {vintage} in year {period}" ; + + compound = "True" ; + concentrate = "True"; + rankdir = "LR" ; + splines = "{splinevar}" ; + + node [ style="filled" ] ; + edge [ arrowhead="vee" ] ; + + subgraph cluster_slices {{ + label = "{vintage} Capacity: {total_cap:.2f}" ; + + color = "{vintage_cluster_color}" ; + rank = "same" ; + style = "filled" ; + + node [ color="{vintage_color}", shape="box", fontcolor="{usedfont_color}" ] ; + + {snodes} + }} + + subgraph energy_carriers {{ + node [ + color = "{commodity_color}", + fontcolor = "{usedfont_color}", + shape = "circle", + fillcolor = "{fill_color}" + ] ; + + {enodes} + }} + + subgraph inputs {{ + edge [ color="{input_color}" ] ; + + {iedges} + }} + + subgraph outputs {{ + edge [ color="{output_color}" ] ; + + {oedges} + }} +}} +""" + +commodity_dot_fmt = """\ +strict digraph result_commodity_{inp_commodity} {{ + label = "{inp_commodity} - {period}" ; + + compound = "True" ; + concentrate = "True" ; + rankdir = "LR" ; + splines = "True" ; + + node [ shape="box", style="filled", fontcolor="{font_color}" ] ; + edge [ + arrowhead = "vee", + fontsize = "8", + label = " ", + labelfloat = "False", + labelfontcolor = "lightgreen" + len = "2", + weight = "0.5", + ] ; + + {resource_node} + + subgraph used_techs {{ + node [ color="{tech_color}" ] ; + + {used_nodes} + }} + + subgraph used_techs {{ + node [ color="{unused_color}" ] ; + + {unused_nodes} + }} + + subgraph in_use_flows {{ + edge [ color="{sb_arrow_color}" ] ; + + {used_edges} + }} + + subgraph unused_flows {{ + edge [ color="{unused_color}" ] ; + + {unused_edges} + }} +}} +""" + +quick_run_dot_fmt = """\ +strict digraph model {{ + rankdir = "LR" ; + + // Default node and edge attributes + node [ style="filled" ] ; + edge [ arrowhead="vee", labelfontcolor="lightgreen" ] ; + + // Define individual nodes + subgraph techs {{ + node [ color="{tech_color}", shape="box", fontcolor="{font_color}" ] ; + + {tnodes} + }} + + subgraph energy_carriers {{ + node [ color="{commodity_color}", shape="circle", fillcolor="{fill_color}" ] ; + + {enodes} + }} + + // Define edges and any specific edge attributes + subgraph inputs {{ + edge [ color="{arrowheadin_color}" ] ; + + {iedges} + }} + + subgraph outputs {{ + edge [ color="{arrowheadout_color}" ] ; + + {oedges} + }} + + {{rank = same; {snodes}}} +}} +""" diff --git a/temoa/data_processing/make_graphviz.py b/temoa/utilities/graphviz_generator.py similarity index 84% rename from temoa/data_processing/make_graphviz.py rename to temoa/utilities/graphviz_generator.py index e609dcd85..eb328a3d7 100644 --- a/temoa/data_processing/make_graphviz.py +++ b/temoa/utilities/graphviz_generator.py @@ -1,16 +1,139 @@ +import argparse import os -import sys from subprocess import call from typing import Any, TextIO -from .database_util import DatabaseUtil -from .graphviz_formats import ( +from temoa.utilities.graphviz_formats import ( commodity_dot_fmt, quick_run_dot_fmt, results_dot_fmt, tech_results_dot_fmt, ) -from .graphviz_util import create_text_edges, create_text_nodes, get_color_config, process_input +from temoa.utilities.graphviz_util import ( + create_text_edges, + create_text_nodes, + get_color_config, +) + +from .database_util import DatabaseUtil + + +def process_input(args: list[str]) -> dict[str, Any]: + """Parse command line arguments.""" + parser = argparse.ArgumentParser(description='Generate Output Plot') + parser.add_argument( + '-i', + '--input', + action='store', + dest='ifile', + help='Input Database Filename ', + required=True, + ) + parser.add_argument( + '-f', + '--format', + action='store', + dest='image_format', + help='Graphviz output format (Default: svg)', + default='svg', + ) + parser.add_argument( + '-c', + '--show_capacity', + action='store_true', + dest='show_capacity', + help='Whether capacity shows up in subgraphs (Default: not shown)', + default=False, + ) + parser.add_argument( + '-v', + '--splinevar', + action='store_true', + dest='splinevar', + help='Whether subgraph edges to be straight or curved (Default: Straight)', + default=False, + ) + parser.add_argument( + '-t', + '--graph_type', + action='store', + dest='graph_type', + help='Type of subgraph (Default: separate_vintages)', + choices=['separate_vintages', 'explicit_vintages'], + default='separate_vintages', + ) + parser.add_argument( + '-g', + '--gray', + action='store_true', + dest='grey_flag', + help='If specified, generates graph in graycale', + default=False, + ) + parser.add_argument( + '-n', + '--name', + action='store', + dest='quick_name', + help='Specify the extension you wish to give your quick run', + ) + parser.add_argument( + '-o', + '--output', + action='store', + dest='res_dir', + help='Optional output file path (to dump the images folder)', + default='./', + ) + + group1 = parser.add_mutually_exclusive_group() + group1.add_argument( + '-b', + '--technology', + action='store', + dest='inp_technology', + help='Technology for which graph to be generated', + ) + group1.add_argument( + '-a', + '--commodity', + action='store', + dest='inp_commodity', + help='Commodity for which graph to be generated', + ) + + parser.add_argument( + '-s', + '--scenario', + action='store', + dest='scenario_name', + help='Model run scenario name', + default=None, + ) + parser.add_argument( + '-y', + '--year', + action='store', + dest='period', + type=int, + help='The period for which the graph is to be generated (Used only for output plots)', + ) + parser.add_argument( + '-r', + '--region', + action='store', + dest='region', + help='The region for which the graph is to be generated', + default=None, + ) + + options = parser.parse_args(args) + + if bool(options.scenario_name) ^ bool(options.period): + parser.print_help() + raise ValueError('Scenario and input year must both be present or not present together') + + return vars(options) class GraphvizDiagramGenerator: @@ -82,7 +205,7 @@ def __generate_graph__( """Generate a graph from a DOT format string.""" dot_args.update(self.colors) with open(output_name + '.dot', 'w') as f: - f.write(dot_format % dot_args) + f.write(dot_format.format(**dot_args)) cmd = ( 'dot', f'-T{output_format}', @@ -442,33 +565,3 @@ def create_complete_input_graph( self.__generate_graph__(quick_run_dot_fmt, args, output_name, output_format) self.__log__('createCompleteInputGraph: graph generated, returning') return self.out_dir, output_path - - -if __name__ == '__main__': - cli_input = process_input(sys.argv[1:]) - graph_gen = GraphvizDiagramGenerator( - cli_input['ifile'], - cli_input['scenario_name'], - cli_input['region'], - out_dir=cli_input['res_dir'], - ) - graph_gen.connect() - graph_gen.set_graphic_options( - grey_flag=cli_input['grey_flag'], splinevar=cli_input['splinevar'] - ) - if cli_input['scenario_name'] is None: - result = graph_gen.create_complete_input_graph( - cli_input['region'], cli_input['inp_technology'], cli_input['inp_commodity'] - ) - elif cli_input['inp_technology'] is None and cli_input['inp_commodity'] is None: - result = graph_gen.create_main_results_diagram(cli_input['period'], cli_input['region']) - elif cli_input['inp_commodity'] is None: - result = graph_gen.create_tech_results_diagrams( - cli_input['period'], cli_input['region'], cli_input['inp_technology'] - ) - else: # 'inp_technology' is None - result = graph_gen.create_commodity_partial_results( - cli_input['period'], cli_input['region'], cli_input['inp_commodity'] - ) - graph_gen.close() - print(f'Check graph generated at {result[1]} and all results at {result[0]}') diff --git a/temoa/utilities/graphviz_util.py b/temoa/utilities/graphviz_util.py new file mode 100644 index 000000000..2619cd583 --- /dev/null +++ b/temoa/utilities/graphviz_util.py @@ -0,0 +1,126 @@ +from collections.abc import Callable, Iterable, Sequence, Sized + + +def get_color_config(grey_flag: bool) -> dict[str, str | tuple[str, ...]]: + """Return a dictionary of color configurations for the graph.""" + + is_colored = not grey_flag + kwargs: dict[str, str | tuple[str, ...]] = { + 'tech_color': 'darkseagreen' if is_colored else 'black', + 'commodity_color': 'lightsteelblue' if is_colored else 'black', + 'unused_color': 'powderblue' if is_colored else 'gray75', + 'arrowheadout_color': 'forestgreen' if is_colored else 'black', + 'arrowheadin_color': 'firebrick' if is_colored else 'black', + 'usedfont_color': 'black', + 'unusedfont_color': 'chocolate' if is_colored else 'gray75', + 'menu_color': 'hotpink', + 'home_color': 'gray75', + 'font_color': 'black' if is_colored else 'white', + 'fill_color': 'lightsteelblue' if is_colored else 'white', + # MODELDETAILED, + 'md_tech_color': 'hotpink', + 'sb_incom_color': 'lightsteelblue' if is_colored else 'black', + 'sb_outcom_color': 'lawngreen' if is_colored else 'black', + 'sb_vpbackg_color': 'lightgrey', + 'sb_vp_color': 'white', + 'sb_arrow_color': 'forestgreen' if is_colored else 'black', + # SUBGRAPH 1 ARROW COLORS + 'color_list': ( + ( + 'red', + 'orange', + 'gold', + 'green', + 'blue', + 'purple', + 'hotpink', + 'cyan', + 'burlywood', + 'coral', + 'limegreen', + 'black', + 'brown', + ) + if is_colored + else ('black', 'black') + ), + } + return kwargs + + +def _get_len(key: int) -> Callable[[Sequence[Sized]], int]: + """Return a function that gets the length of an item at a specific index in a sequence.""" + + def wrapped(obj: Sequence[Sized]) -> int: + return len(obj[key]) + + return wrapped + + +def create_text_nodes(nodes: Iterable[tuple[str, str]], indent: int = 1) -> str: + """ + Return a set of text nodes in Graphviz DOT format, optimally padded for + easier reading and debugging. + + Args: + nodes: iterable of (id, attribute) node tuples + e.g. [(node1, attr1), (node2, attr2), ...] + indent: integer, number of tabs with which to indent all Dot node lines + """ + # Convert to list to avoid consuming iterable multiple times if it's an iterator + nodes_list = list(nodes) + if not nodes_list: + return '// no nodes in this section' + + # Step 1: for alignment, get max item length in node list + # The `+ 2` accounts for the two extra quotes that will be added. + maxl = max(map(_get_len(0), nodes_list), default=0) + 2 + + # Step 2: prepare a text format based on max node size that pads all + # lines with attributes + nfmt_attr = f'{{0:<{maxl}}} [ {{1}} ] ;' # node text format + nfmt_noa = '{0} ;' + + # Step 3: create each node, and place string representation in a set to + # guarantee uniqueness + q = '"%s"' # enforce quoting for all nodes + gviz = {nfmt_attr.format(q % n, a) for n, a in nodes_list if a} + gviz.update(nfmt_noa.format(q % n) for n, a in nodes_list if not a) + + # Step 4: return a sorted version of nodes, as a single string + indent_str = '\n' + '\t' * indent + return indent_str.join(sorted(gviz)) + + +def create_text_edges(edges: Iterable[tuple[str, str, str]], indent: int = 1) -> str: + """ + Return a set of text edge definitions in Graphviz DOT format, optimally + padded for easier reading and debugging. + + Args: + edges: iterable of (from, to, attribute) edge tuples + e.g. [(inp1, tech1, attr1), (inp2, tech2, attr2), ...] + indent: integer, number of tabs with which to indent all Dot edge lines + """ + # Convert to list + edges_list = list(edges) + if not edges_list: + return '// no edges in this section' + + # Step 1: for alignment, get max length of items on left and right side of + # graph operator token ('->'). The `+ 2` accounts for the two extra quotes. + maxl = max(map(_get_len(0), edges_list), default=0) + 2 + maxr = max(map(_get_len(1), edges_list), default=0) + 2 + + # Step 2: prepare format to be "\n\tinp+PADDING -> out+PADDING [..." + efmt_attr = f'{{0:<{maxl}}} -> {{1:<{maxr}}} [ {{2}} ] ;' # with attributes + efmt_noa = f'{{0:<{maxl}}} -> {{1}} ;' # no attributes + + # Step 3: add each edge to a set (to guarantee unique entries only) + q = '"%s"' # enforce quoting for all tokens + gviz = {efmt_attr.format(q % i, q % t, a) for i, t, a in edges_list if a} + gviz.update(efmt_noa.format(q % i, q % t) for i, t, a in edges_list if not a) + + # Step 4: return a sorted version of the edges, as a single string + indent_str = '\n' + '\t' * indent + return indent_str.join(sorted(gviz)) From cdd48b58a6dff906174153e45f556fcabe415d68 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 21 Nov 2025 12:11:35 -0500 Subject: [PATCH 355/587] tests for graphviz integration --- tests/test_graphviz_integration.py | 116 ++++++++++++++++++++ tests/testing_configs/config_utopia_gv.toml | 78 +++++++++++++ 2 files changed, 194 insertions(+) create mode 100644 tests/test_graphviz_integration.py create mode 100644 tests/testing_configs/config_utopia_gv.toml diff --git a/tests/test_graphviz_integration.py b/tests/test_graphviz_integration.py new file mode 100644 index 000000000..c3492818e --- /dev/null +++ b/tests/test_graphviz_integration.py @@ -0,0 +1,116 @@ +from __future__ import annotations + +import shutil +import tempfile +import unittest +from pathlib import Path +from typing import cast +from unittest.mock import MagicMock, patch + +from temoa.core.config import TemoaConfig +from temoa.model_checking.commodity_graph import generate_graphviz_files, visualize_graph +from temoa.model_checking.network_model_data import NetworkModelData +from temoa.types.core_types import Commodity, Period, Region, Sector, Technology, Vintage +from temoa.utilities.graph_utils import EdgeTuple + + +class TestGraphvizIntegration(unittest.TestCase): + def setUp(self) -> None: # noqa: N802 + # Create a unique temp output directory per test run + self._tmp_dir = Path(tempfile.mkdtemp(prefix='temoa_test_output_')) + + self.config = MagicMock(spec=TemoaConfig) + self.config.plot_commodity_network = True + self.config.graphviz_output = True + self.config.output_path = self._tmp_dir + + self.network_data = MagicMock(spec=NetworkModelData) + + self.network_data.available_techs = { + (cast(Region, 'region'), cast(Period, '2020')): {('tech1', 'v1')} + } + self.network_data.source_commodities = { + (cast(Region, 'region'), cast(Period, '2020')): {'coal'} + } + self.network_data.demand_commodities = { + (cast(Region, 'region'), cast(Period, '2020')): {'electricity'} + } + + self.edge_tuple = EdgeTuple( + region=cast(Region, 'region'), + tech=cast(Technology, 'tech1'), + vintage=cast(Vintage, 'v1'), + input_comm=cast(Commodity, 'coal'), + output_comm=cast(Commodity, 'electricity'), + sector=cast(Sector, 'electric'), + ) + + def tearDown(self) -> None: # noqa: N802 + shutil.rmtree(self._tmp_dir, ignore_errors=True) + + @patch('temoa.model_checking.commodity_graph.generate_commodity_graph') + @patch('temoa.model_checking.commodity_graph.generate_technology_graph') + @patch('temoa.model_checking.commodity_graph.nx_to_vis') + @patch('temoa.model_checking.commodity_graph.generate_graphviz_files') + def test_visualize_graph_calls_graphviz( + self, + mock_gen_gv: MagicMock, + mock_nx_vis: MagicMock, + mock_gen_tech: MagicMock, + mock_gen_comm: MagicMock, + ) -> None: + mock_gen_comm.return_value = (MagicMock(), {}) + mock_gen_tech.return_value = MagicMock() + mock_nx_vis.return_value = 'path/to/graph.html' + + visualize_graph( + region=cast(Region, 'region'), + period=cast(Period, '2020'), + network_data=self.network_data, + demand_orphans=[], + other_orphans=[], + driven_techs=[self.edge_tuple], + config=self.config, + ) + + mock_gen_gv.assert_called_once() + args, _ = mock_gen_gv.call_args + self.assertEqual(args[0], '2020') + self.assertEqual(args[1], 'region') + # Check that output path is passed correctly + self.assertEqual(args[5], self.config.output_path) + + @patch('subprocess.call') + def test_generate_graphviz_files_creates_dot_file(self, mock_subprocess: MagicMock) -> None: + with tempfile.TemporaryDirectory(prefix='temoa_test_output_') as tmp_output_dir_str: + output_dir = Path(tmp_output_dir_str) + + sector_colors = {cast(Sector, 'electric'): 'blue'} + all_techs = [self.edge_tuple] + + generate_graphviz_files( + period=cast(Period, '2020'), + region=cast(Region, 'region'), + network_data=self.network_data, + all_techs=all_techs, + sector_colors=sector_colors, + output_dir=output_dir, + ) + + dot_file = output_dir / 'results_region_2020.dot' + self.assertTrue(dot_file.exists()) + + with open(dot_file) as f: + content = f.read() + self.assertIn('label = "Results for 2020"', content) + self.assertIn('label="tech1"', content) + self.assertIn('label="coal"', content) + self.assertIn('label="electricity"', content) + + # Verify subprocess call + svg_file = output_dir / 'results_region_2020.svg' + mock_subprocess.assert_called_with(['dot', '-Tsvg', f'-o{svg_file}', str(dot_file)]) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/testing_configs/config_utopia_gv.toml b/tests/testing_configs/config_utopia_gv.toml new file mode 100644 index 000000000..d4c9b7444 --- /dev/null +++ b/tests/testing_configs/config_utopia_gv.toml @@ -0,0 +1,78 @@ +# this config is used for testing in test_full_runs.py +scenario = "test run" +scenario_mode = "perfect_foresight" + +input_database = "tests/testing_outputs/utopia.sqlite" +output_database = "tests/testing_outputs/utopia.sqlite" +neos = false + +# solver +solver_name = "cbc" + +# generate an excel file in the output_files folder +save_excel = false + +# save the duals in the output .sqlite database +save_duals = false + +# save a copy of the pyomo-generated lp file to the outputs folder (may be large file!) +save_lp_file = false + +# ------------------------------------ +# MODEL PARAMETERS +# these are specific to each model +# ------------------------------------ + +# What seasons represent in the model +# Options: +# 'consecutive_days' +# Seasons are a set of days in order, with each season representing only one day. Examples +# might be a model of a representative week with 7 days or a whole-year model with 365 days. +# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. +# 'representative_periods' +# Each season represents a number of days, though not necessarily in any particular order. +# If using inter-season constraints like seasonal storage or ramp rates, the true sequence +# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in +# the technology table. +# 'seasonal_timeslices' +# Each season represents a sequential slice of the year, with one or many days represented per +# season. We assume that the true sequence is the same as the TimeSeason sequence, so the +# time_season_sequential table can be left empty. Seasonal storage must still be tagged. +# 'manual' +# The sequence of time slices is defined manually in the TimeNext table (which is commented out +# in the schema). This is an advanced feature and not recommended for most users. Seasonal +# storage must be tagged and the time_season_sequential table filled. +time_sequencing = 'seasonal_timeslices' + +# How contributions to the planning reserve margin are calculated +# Options: +# 'static' +# Traditional planning reserve formulation. Contributions are independent of hourly availability: +# capacity value = net capacity * capacity credit +# 'dynamic' +# Contributions are available output including a capacity derate factor (e.g., forced outage rate). +# For most generators, contributions are available (derated) output in each time slice: +# capacity value = net capacity * reserve capacity derate * capacity factor +# For storage, contributions are (derated) actual output in each time slice: +# capacity value = flow out * reserve capacity derate +reserve_margin = 'static' + +# --------------------------------------------------- +# OUTPUT OPTIONS +# --------------------------------------------------- +graphviz_output = true + +# --------------------------------------------------- +# MODE OPTIONS +# options below are mode-specific and will be ignored +# if the run is not executed in that mode. +# --------------------------------------------------- +[MGA] +cost_epsilon = 0.03 # 3% relaxation on optimal cost +iteration_limit = 15 # max iterations to perform +time_limit_hrs = 1 # max time +axis = "tech_category_activity" # use the tech activity Manager to control exploration based on categories in Tech +weighting = "hull_expansion" # use a convex hull expansion algorithm to weight exploration + +[myopic] +myopic_view = 2 # number of periods seen at one iteration From b480ff9d4f02f9c7d8296065893ea131937e6e7b Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 21 Nov 2025 12:12:06 -0500 Subject: [PATCH 356/587] updating CI to install graphviz --- .github/workflows/ci.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d0df95f29..8c0261903 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,6 +48,11 @@ jobs: sudo apt-get update sudo apt-get install -y coinor-cbc + - name: Install Graphviz + run: | + sudo apt-get update + sudo apt-get install -y graphviz + - name: Run tests env: CI: 1 From a8dd5cb680ce49a5b4427af775c93025fca0dcff Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 21 Nov 2025 12:12:19 -0500 Subject: [PATCH 357/587] updating docs --- docs/source/Documentation.rst | 106 +++- .../static/Network_Graph_utopia_1990.html | 55 ++ docs/source/default/static/graph_script.js | 260 +++++++++ docs/source/default/static/graph_styles.css | 29 + .../Network_Graph_utopia_1990.html | 55 ++ .../images/graphviz_examples/results1990.svg | 533 ++++++++++++++++++ docs/source/quick_start.rst | 27 +- temoa/data_processing/README.md | 56 +- 8 files changed, 1039 insertions(+), 82 deletions(-) create mode 100644 docs/source/default/static/Network_Graph_utopia_1990.html create mode 100644 docs/source/default/static/graph_script.js create mode 100644 docs/source/default/static/graph_styles.css create mode 100644 docs/source/images/graphviz_examples/Network_Graph_utopia_1990.html create mode 100644 docs/source/images/graphviz_examples/results1990.svg diff --git a/docs/source/Documentation.rst b/docs/source/Documentation.rst index 82f047787..b83e1bd2f 100644 --- a/docs/source/Documentation.rst +++ b/docs/source/Documentation.rst @@ -15,7 +15,111 @@ Quick Start Visualization ============= -.. include:: visualization.rst +Network Diagrams +---------------- + +Since the Temoa model consists of an energy network in which technologies are connected +by the flow of energy commodities, a directed network graph represents an excellent way +to visualize a given energy system representation in a Temoa-compatible input database. + +Temoa provides two types of network visualizations: + +1. **Interactive HTML Network Graphs** - Dynamic, explorable visualizations showing commodity flows and technology connections +2. **Graphviz Diagrams** - Static SVG/DOT format diagrams showing the energy system structure + +Generating Network Visualizations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The easiest way to generate these diagrams is to enable visualization options in your +configuration TOML file. Add the following to your config file: + +.. parsed-literal:: + # Enable interactive HTML network graphs (requires source_trace = true) + source_trace = true + plot_commodity_network = true + + # Enable Graphviz static diagrams + graphviz_output = true + +When these options are enabled, Temoa will automatically generate visualization files +in the output directory during model execution. + +**Interactive Network Graphs** will be created as HTML files (one per time period) that +you can open in a web browser. These provide an interactive view where you can: + +- Pan and zoom the network +- Click on nodes to see details +- Toggle between commodity-centric and technology-centric views +- Filter by sector using color-coded legends + +**Graphviz Diagrams** will be created as both ``.dot`` (source) and ``.svg`` (rendered) +files in a subdirectory within your output folder. These provide static visualizations +showing: + +- Full energy system maps +- Capacity and activity results per model time period +- Technology interconnections via commodity flows + +Example Visualizations +~~~~~~~~~~~~~~~~~~~~~~ + +**Interactive Network Graph** + +The interactive HTML network graphs provide dynamic exploration with pan, zoom, and filtering capabilities: + +.. raw:: html + + + +*Interactive network graph for the 'utopia' test system in 1990. You can pan, zoom, click nodes for details, and toggle between commodity-centric and technology-centric views. These files are automatically generated when* ``source_trace = true`` *and* ``plot_commodity_network = true`` *are set in the configuration file.* + +**Static Graphviz Diagram** + +Graphviz also generates static SVG diagrams showing the energy system structure: + +.. figure:: images/graphviz_examples/results1990.svg + :align: center + :figclass: center + :width: 100% + + Static Graphviz diagram showing the optimal installed capacity and commodity flows + for the 'utopia' test system in 1990. Technologies are shown as boxes, + commodities as circles, with arrows indicating energy flows. These diagrams + are automatically generated when ``graphviz_output = true`` is set in the + configuration file. + +Output Graphs +------------- + +.. warning:: + The ``make_output_plots.py`` script has not been fully tested with Temoa v4.0 + and is currently unsupported. Use at your own risk and please report any issues + on `GitHub Issues`_. + +Temoa can also be used to generate output graphs using `matplotlib `_. +From the command line, navigate to the :code:`data_processing` folder and execute the +following command: + +.. parsed-literal:: + $ uv run python temoa/data_processing/make_output_plots.py --help + +The command above will specify all of the flags required to create a stacked bar +or line plot. For example, consider the following command: + +.. parsed-literal:: + $ uv run python temoa/data_processing/make_output_plots.py -i data_files/temoa_utopia.sqlite -s test_run -p capacity -c electric --super + +.. figure:: images/output_flow_example.* + :align: center + :figclass: center + :figwidth: 60% + + This stacked bar plot represents the activity (i.e., output commodity flow) + associated with each technology in the electric sector from the 'test_run' + scenario drawn from the 'temoa_utopia' database. Because the :code:`super` + flag was specified, technologies are grouped together based on user-specified + categories in the :code:`tech_category` column of the :code:`technologies` + table of the database. ===================== The Math Behind Temoa diff --git a/docs/source/default/static/Network_Graph_utopia_1990.html b/docs/source/default/static/Network_Graph_utopia_1990.html new file mode 100644 index 000000000..243036757 --- /dev/null +++ b/docs/source/default/static/Network_Graph_utopia_1990.html @@ -0,0 +1,55 @@ + + + + + + + Network Graphs - utopia 1990 + + + + + +
+
+

Configuration & Legend

+ +
+
+
+

Style Legend

+
+
+
+

Sector Legend

+
+
+ Show Advanced Physics Controls + +
+
+
+ +
+
+ Filter Sectors: +
+
+ + + +
+
+ Tip: Double-click a node to isolate. Single-click to select. Use 'Reset View' to clear. +
+
+ + + + + + + diff --git a/docs/source/default/static/graph_script.js b/docs/source/default/static/graph_script.js new file mode 100644 index 000000000..78e77b915 --- /dev/null +++ b/docs/source/default/static/graph_script.js @@ -0,0 +1,260 @@ +document.addEventListener('DOMContentLoaded', function () { + // --- Master Datasets (Read embedded JSON safely) --- + let data = null; + const dataEl = document.getElementById('graph-data'); + if (dataEl && dataEl.textContent) { + try { + data = JSON.parse(dataEl.textContent); + } catch (e) { + console.error('Failed to parse graph data JSON:', e); + } + } + + // If data failed to load, stop immediately to prevent further errors. + if (!data) { + console.error('Could not find or parse GRAPH_DATA. Halting script.'); + return; + } + + const { + nodes_json_primary: allNodesPrimary, + edges_json_primary: allEdgesPrimary, + nodes_json_secondary: allNodesSecondary, + edges_json_secondary: allEdgesSecondary, + options_json_str: optionsRaw, + sectors_json_str: allSectors, + color_legend_json_str: colorLegendData, + style_legend_json_str: styleLegendData, + primary_view_name: primaryViewName, + secondary_view_name: secondaryViewName, + } = data; + const optionsObject = (typeof optionsRaw === 'string') ? JSON.parse(optionsRaw) : optionsRaw; + // --- State --- + let currentView = 'primary'; + let primaryViewPositions = null; + let secondaryViewPositions = null; + + // --- DOM Elements --- + const configWrapper = document.getElementById('config-panel-wrapper'); + const configHeader = document.querySelector('.config-panel-header'); + const configToggleButton = document.querySelector('.config-toggle-btn'); + const advancedControlsToggle = document.getElementById('advanced-controls-toggle'); + const visConfigContainer = document.getElementById('vis-config-container'); + const searchInput = document.getElementById('search-input'); + const resetButton = document.getElementById('reset-view-btn'); + const sectorTogglesContainer = document.getElementById('sector-toggles'); + const viewToggleButton = document.getElementById('view-toggle-btn'); + const graphContainer = document.getElementById('mynetwork'); + + // --- Config Panel Toggle --- + if (optionsObject.configure && optionsObject.configure.enabled) { + optionsObject.configure.container = visConfigContainer; + configHeader.addEventListener('click', () => { + const isCollapsed = configWrapper.classList.toggle('collapsed'); + configToggleButton.setAttribute('aria-expanded', !isCollapsed); + }); + advancedControlsToggle.addEventListener('click', function(e) { + e.preventDefault(); + const isHidden = visConfigContainer.style.display === 'none'; + visConfigContainer.style.display = isHidden ? 'block' : 'none'; + this.textContent = isHidden ? 'Hide Advanced Physics Controls' : 'Show Advanced Physics Controls'; + }); + } + + // --- Vis.js Network Initialization --- + const nodes = new vis.DataSet(allNodesPrimary); + const edges = new vis.DataSet(allEdgesPrimary); + const network = new vis.Network(graphContainer, { nodes, edges }, optionsObject); + + // --- Core Functions --- + function applyPositions(positions) { + if (!positions) return; + const updates = Object.keys(positions).map(nodeId => ({ + id: nodeId, x: positions[nodeId].x, y: positions[nodeId].y, + })); + if (updates.length > 0) nodes.update(updates); + } + + function switchView() { + if (currentView === 'primary') { + primaryViewPositions = network.getPositions(); + } else { + secondaryViewPositions = network.getPositions(); + } + nodes.clear(); edges.clear(); + + if (currentView === 'primary') { + nodes.add(allNodesSecondary); edges.add(allEdgesSecondary); + currentView = 'secondary'; + viewToggleButton.textContent = `Switch to ${primaryViewName}`; + viewToggleButton.setAttribute('aria-pressed', 'true'); + applyPositions(secondaryViewPositions); + } else { + nodes.add(allNodesPrimary); edges.add(allEdgesPrimary); + currentView = 'primary'; + viewToggleButton.textContent = `Switch to ${secondaryViewName}`; + viewToggleButton.setAttribute('aria-pressed', 'false'); + applyPositions(primaryViewPositions); + } + applyAllFilters(); + network.fit(); + } + + function applyAllFilters() { + // Preserve current positions so filtering doesn't reset layout + const currentPositions = network.getPositions(); + const checkedSectors = new Set(Array.from(sectorTogglesContainer.querySelectorAll('input:checked')).map(c => c.value)); + const searchQuery = searchInput.value; + let regex = null; + if (searchQuery) { + try { regex = new RegExp(searchQuery, 'i'); } catch (e) { console.error("Invalid Regex:", e); return; } + } + const activeNodesData = (currentView === 'primary') ? allNodesPrimary : allNodesSecondary; + const activeEdgesData = (currentView === 'primary') ? allEdgesPrimary : allEdgesSecondary; + const sectorFilteredNodes = activeNodesData.filter(node => { + let match = node.group === null || node.group === undefined || checkedSectors.has(node.group); + if (currentView === 'primary' && node.alwaysVisible === true) { + match = true; + } + return match; + }); + let visibleNodes, visibleEdges; + if (regex) { + const seedNodes = sectorFilteredNodes.filter(node => regex.test(node.label || node.id)); + const seedNodeIds = new Set(seedNodes.map(n => n.id)); + const nodesToShowIds = new Set(seedNodeIds); + activeEdgesData.forEach(edge => { + if (seedNodeIds.has(edge.from)) nodesToShowIds.add(edge.to); + if (seedNodeIds.has(edge.to)) nodesToShowIds.add(edge.from); + }); + visibleNodes = activeNodesData.filter(node => nodesToShowIds.has(node.id)); + visibleEdges = activeEdgesData.filter(edge => nodesToShowIds.has(edge.from) && nodesToShowIds.has(edge.to)); + } else { + visibleNodes = sectorFilteredNodes; + const visibleNodeIds = new Set(visibleNodes.map(n => n.id)); + visibleEdges = activeEdgesData.filter(edge => visibleNodeIds.has(edge.from) && visibleNodeIds.has(edge.to)); + } + nodes.clear(); edges.clear(); + nodes.add(visibleNodes); edges.add(visibleEdges); + applyPositions(currentPositions); + } + + function createStyleLegend() { + const container = document.getElementById('style-legend-container'); + if (!container || !styleLegendData || styleLegendData.length === 0) return; + styleLegendData.forEach(itemData => { + const item = document.createElement('div'); + item.className = 'legend-item'; + const swatch = document.createElement('div'); + swatch.className = 'legend-color-swatch'; + if (itemData.borderColor) swatch.style.borderColor = itemData.borderColor; + if (itemData.borderWidth) swatch.style.borderWidth = itemData.borderWidth + 'px'; + const label = document.createElement('span'); + label.className = 'legend-label'; + label.textContent = itemData.label; + item.append(swatch, label); + container.appendChild(item); + }); + } + + function createSectorLegend() { + const container = document.getElementById('legend-container'); + if (!container || !colorLegendData || Object.keys(colorLegendData).length === 0) return; + Object.keys(colorLegendData).sort().forEach(key => { + const item = document.createElement('div'); + item.className = 'legend-item'; + const swatch = document.createElement('div'); + swatch.className = 'legend-color-swatch'; + swatch.style.backgroundColor = colorLegendData[key]; + const label = document.createElement('span'); + label.className = 'legend-label'; + label.textContent = key; + item.append(swatch, label); + container.appendChild(item); + }); + } + + function createSectorToggles() { + if (!allSectors || allSectors.length === 0) { + sectorTogglesContainer.style.display = 'none'; + return; + } + allSectors.forEach(sector => { + const item = document.createElement('div'); + item.className = 'sector-toggle-item'; + const checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + checkbox.id = `toggle-${sector}`; + checkbox.value = sector; + checkbox.checked = true; + checkbox.addEventListener('change', applyAllFilters); + const swatch = document.createElement('div'); + swatch.className = 'toggle-color-swatch'; + swatch.style.backgroundColor = colorLegendData[sector] || '#ccc'; + const label = document.createElement('label'); + label.htmlFor = checkbox.id; + label.textContent = sector; + item.append(swatch, checkbox, label); + item.addEventListener('click', e => { + if (e.target.tagName === 'INPUT') return; + e.preventDefault(); + checkbox.checked = !checkbox.checked; + checkbox.dispatchEvent(new Event('change', { bubbles: true })); + }); + sectorTogglesContainer.appendChild(item); + }); + } + + function resetView() { + searchInput.value = ""; + primaryViewPositions = null; + secondaryViewPositions = null; + if (currentView !== 'primary') { + switchView(); // This will switch back to primary and apply null positions + } else { + // If already on primary, just reload the original data + nodes.clear(); edges.clear(); + nodes.add(allNodesPrimary); edges.add(allEdgesPrimary); + applyPositions(primaryViewPositions); // Apply null to reset + network.fit(); + } + sectorTogglesContainer.querySelectorAll('input[type=checkbox]').forEach(c => c.checked = true); + applyAllFilters(); + } + + function showNeighborhood(nodeId) { + const activeNodes = (currentView === 'primary') ? allNodesPrimary : allNodesSecondary; + const activeEdges = (currentView === 'primary') ? allEdgesPrimary : allEdgesSecondary; + searchInput.value = ""; + const nodesToShow = new Set([nodeId]); + activeEdges.forEach(edge => { + if (edge.from === nodeId) nodesToShow.add(edge.to); + else if (edge.to === nodeId) nodesToShow.add(edge.from); + }); + const filteredNodes = activeNodes.filter(node => nodesToShow.has(node.id)); + const filteredEdges = activeEdges.filter(edge => nodesToShow.has(edge.from) && nodesToShow.has(edge.to)); + nodes.clear(); edges.clear(); + nodes.add(filteredNodes); + edges.add(filteredEdges); + network.fit(); + } + + // --- Event Listeners & Initial Setup --- + if (allNodesSecondary && allNodesSecondary.length > 0) { + viewToggleButton.textContent = `Switch to ${secondaryViewName}`; + viewToggleButton.addEventListener('click', switchView); + } else { + document.getElementById('view-toggle-panel').style.display = 'none'; + } + resetButton.addEventListener('click', resetView); + searchInput.addEventListener('input', applyAllFilters); + network.on("doubleClick", params => { + if (params.nodes.length > 0) { + showNeighborhood(params.nodes[0]); + } + }); + + createStyleLegend(); + createSectorLegend(); + createSectorToggles(); +}); diff --git a/docs/source/default/static/graph_styles.css b/docs/source/default/static/graph_styles.css new file mode 100644 index 000000000..0402c090e --- /dev/null +++ b/docs/source/default/static/graph_styles.css @@ -0,0 +1,29 @@ +body, html { + margin: 0; padding: 0; width: 100%; height: 100%; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + background-color: #f4f6f8; display: flex; flex-direction: column; overflow: hidden; +} +.config-panel-wrapper { width: 100%; background-color: #ffffff; box-shadow: 0 2px 4px rgba(0,0,0,0.1); z-index: 10; flex-shrink: 0; } +.config-panel-header { display: flex; justify-content: space-between; align-items: center; padding: 10px 15px; border-bottom: 1px solid #e0e0e0; cursor: pointer; background-color: #f9f9f9; } +.config-panel-header h3 { margin: 0; font-size: 16px; font-weight: 600; } +.config-toggle-btn::after { content: '\25BC'; display: inline-block; transition: transform 0.2s ease-in-out; } +.collapsed .config-toggle-btn::after { transform: rotate(-90deg); } +#config-container-content { max-height: 40vh; overflow-y: auto; padding: 15px; box-sizing: border-box; background-color: #ffffff; transition: max-height 0.3s ease-in-out, padding 0.3s ease-in-out; } +.collapsed #config-container-content { max-height: 0; padding-top: 0; padding-bottom: 0; overflow: hidden; } +#mynetwork { width: 100%; flex-grow: 1; min-height: 0; } +.filter-panel { display: flex; align-items: center; gap: 10px; padding: 8px 15px; background-color: #e9ecef; border-bottom: 1px solid #dee2e6; } +.filter-panel input[type=text] { flex-grow: 1; padding: 6px 8px; border: 1px solid #ced4da; border-radius: 4px; } +.filter-panel button { padding: 6px 12px; border-radius: 4px; border: 1px solid #6c757d; background-color: #6c757d; color: white; cursor: pointer; } +.info-panel { padding: 8px 15px; background-color: #f8f9fa; font-size: 13px; text-align: center; border-bottom: 1px solid #dee2e6; } +.sector-toggles { padding: 10px 15px; background-color: #f8f9fa; border-bottom: 1px solid #dee2e6; display: flex; flex-wrap: wrap; gap: 10px; align-items: center; } +.sector-toggles-title { font-weight: 600; } +.sector-toggle-item { display: flex; align-items: center; gap: 8px; padding: 5px 10px; border: 1px solid #ccc; border-radius: 16px; background-color: #fff; cursor: pointer; user-select: none; } +.toggle-color-swatch { width: 14px; height: 14px; border-radius: 50%; } +.legend-section { margin-bottom: 15px; } +.legend-section h4 { margin-top: 0; margin-bottom: 10px; font-size: 14px; font-weight: 600; } +.legend-container { display: flex; flex-wrap: wrap; gap: 15px; } +.legend-item { display: flex; align-items: center; margin-bottom: 6px; } +.legend-color-swatch { width: 18px; height: 18px; margin-right: 8px; flex-shrink: 0; border: 1px solid #ccc; background-color: #f0f0f0; box-sizing: border-box; } +.legend-label { font-size: 13px; } +#advanced-controls-toggle { font-size: 12px; color: #007bff; cursor: pointer; text-decoration: none; margin-top: 15px; display: block; } +.view-toggle-panel { padding: 8px 15px; background-color: #343a40; color: white; display: flex; justify-content: center; align-items: center; } +.view-toggle-panel button { font-size: 14px; font-weight: 600; padding: 8px 16px; border-radius: 5px; border: 1px solid #6c757d; background-color: #495057; color: white; cursor: pointer; } diff --git a/docs/source/images/graphviz_examples/Network_Graph_utopia_1990.html b/docs/source/images/graphviz_examples/Network_Graph_utopia_1990.html new file mode 100644 index 000000000..243036757 --- /dev/null +++ b/docs/source/images/graphviz_examples/Network_Graph_utopia_1990.html @@ -0,0 +1,55 @@ + + + + + + + Network Graphs - utopia 1990 + + + + + +
+
+

Configuration & Legend

+ +
+
+
+

Style Legend

+
+
+
+

Sector Legend

+
+
+ Show Advanced Physics Controls + +
+
+
+ +
+
+ Filter Sectors: +
+
+ + + +
+
+ Tip: Double-click a node to isolate. Single-click to select. Use 'Reset View' to clear. +
+
+ + + + + + + diff --git a/docs/source/images/graphviz_examples/results1990.svg b/docs/source/images/graphviz_examples/results1990.svg new file mode 100644 index 000000000..ba1615a8a --- /dev/null +++ b/docs/source/images/graphviz_examples/results1990.svg @@ -0,0 +1,533 @@ + + + + + + +model + +Results for 1990 + + +E21 + +E21 + + + +ELC + + +ELC + + + + + +E21->ELC + + + + + +IMPDSL1 + + +IMPDSL1 +Capacity: 99999.00 + + + + + +DSL + + +DSL + + + + + +IMPDSL1->DSL + + +38.60 + + + +co2 + +co2 + + + +IMPDSL1->co2 + + +2.89 + + + +IMPFEQ + +IMPFEQ + + + +FEQ + +FEQ + + + +IMPFEQ->FEQ + + + + + +IMPGSL1 + + +IMPGSL1 +Capacity: 99999.00 + + + + + +GSL + + +GSL + + + + + +IMPGSL1->GSL + + +19.91 + + + +IMPGSL1->co2 + + +1.49 + + + +IMPHCO1 + + +IMPHCO1 +Capacity: 99999.00 + + + + + +HCO + + +HCO + + + + + +IMPHCO1->HCO + + +14.70 + + + +IMPHCO1->co2 + + +1.31 + + + +IMPHYD + + +IMPHYD +Capacity: 99999.00 + + + + + +HYD + + +HYD + + + + + +IMPHYD->HYD + + +3.52 + + + +IMPOIL1 + +IMPOIL1 + + + +OIL + +OIL + + + +IMPOIL1->OIL + + + + + +IMPURN1 + +IMPURN1 + + + +URN + +URN + + + +IMPURN1->URN + + + + + +RHE + +RHE + + + +RH + + +RH + + + + + +RHE->RH + + + + + +TXE + +TXE + + + +TX + + +TX + + + + + +TXE->TX + + + + + +FEQ->E21 + + + + + +SRE + + +SRE +Capacity: 0.10 + + + + + +OIL->SRE + + + + + +URN->E21 + + + + + +E01 + + +E01 +Capacity: 0.50 + + + + + +E01->ELC + + +4.70 + + + +E31 + + +E31 +Capacity: 0.13 + + + + + +E31->ELC + + +1.13 + + + +E51 + + +E51 +Capacity: 0.50 + + + + + +E51->ELC + + +0.59 + + + +E70 + + +E70 +Capacity: 0.30 + + + + + +E70->ELC + + + + + +RHO + + +RHO +Capacity: 41.33 + + + + + +RHO->RH + + +25.20 + + + +RL1 + + +RL1 +Capacity: 8.40 + + + + + +RL + + +RL + + + + + +RL1->RL + + +5.60 + + + +SRE->DSL + + + + + +SRE->GSL + + + + + +TXD + + +TXD +Capacity: 0.60 + + + + + +TXD->TX + + +0.60 + + + +nox + +nox + + + +TXD->nox + + +0.60 + + + +TXG + + +TXG +Capacity: 4.60 + + + + + +TXG->TX + + +4.60 + + + +TXG->nox + + +4.60 + + + +DSL->E70 + + + + + +DSL->RHO + + +36.00 + + + +DSL->TXD + + +2.60 + + + +ELC->RHE + + + + + +ELC->TXE + + + + + +ELC->E51 + + +0.82 + + + +ELC->RL1 + + +5.60 + + + +GSL->TXG + + +19.91 + + + +HCO->E01 + + +14.70 + + + +HYD->E31 + + +3.52 + + + diff --git a/docs/source/quick_start.rst b/docs/source/quick_start.rst index f7c2d185b..9dcbc398c 100644 --- a/docs/source/quick_start.rst +++ b/docs/source/quick_start.rst @@ -302,31 +302,6 @@ the data to prevent network corruption. Note that the myopic mode *requires* the use of Source Tracing to ensure accuracy as some orphans may be produced by endogenous decisions in myopic runs. -Commodity Network Visualization -------------------------------- - -The output of the Source Tracing operation can be visualized by enabling the commodity network plots -in the config file. This will add a set of region-period specific html files to the Outputs folder. -These files *should* be open-able in any web browser. (See the note in the main `README.md` for trouble -with Windows OS systems). - -.. figure:: images/utopia_commodity_network.png - :align: center - :figclass: center - :figwidth: 60% - - An example of the Commodity Network for Utopia (interactive view in web browser by opening - the generated html file) - -The color legend for Commodity Networks is as follows: - -* Green dot: Source Commodity -* Orange dot: Demand Commodity -* Violet dot: Intermediate Commodity -* Black arc: Technology -* Blue arc: Linked Technology (the driven tech, *not* the driver) -* Yellow arc: Supply-Side Orphan (shown, but suppressed when model built) -* Red arc: Demand-Side Orphan (shown, but suppressed when model built) -* Green arc: Any Tech with a Negative Variable Cost .. _sqlite: https://www.sqlite.org/ + diff --git a/temoa/data_processing/README.md b/temoa/data_processing/README.md index 4388d7e19..11634db7d 100644 --- a/temoa/data_processing/README.md +++ b/temoa/data_processing/README.md @@ -1,7 +1,6 @@ # Overview -This folder contains files used to manage Temoa output data processing and visualization. - +This folder contains files used to manage Temoa output data processing > **āš ļø Note:** These tools have not been fully tested with Temoa v4.0. They may require updates or fixes. Please report any issues on [GitHub Issues](https://github.com/TemoaProject/temoa/issues). ## Available Tools @@ -18,56 +17,3 @@ Python script that queries database output tables to create an Excel file contai uv run python temoa/data_processing/db_to_excel.py -i path/to/database.sqlite -s scenario_name ``` -### 2. `make_graphviz.py` - -**Status:** āš ļø Untested in v4.0 - -Python script that creates Graphviz diagrams for visualizing the energy system network. - -**Basic usage** - View the full energy system map: - -```bash -uv run python temoa/data_processing/make_graphviz.py -i data_files/temoa_utopia.sqlite -``` - -**Advanced usage** - Capacitated flow graph for a specific period: - -```bash -uv run python temoa/data_processing/make_graphviz.py \ - -i data_files/temoa_utopia.sqlite \ - -r utopia \ - -s scenario_name \ - -c \ - -y 2010 -``` - -**Options:** - -- `-i` : Input database file path -- `-r` : Region name -- `-s` : Scenario name -- `-c` : Include capacity information -- `-y` : Specific year to visualize - -For all available options: - -```bash -uv run python temoa/data_processing/make_graphviz.py --help -``` - -## Output Files - -The scripts generate output files in the current directory or a specified output location. Graphviz creates both: - -- **SVG/PNG files** - Viewable images of the network -- **DOT files** - Source files for Graphviz (useful for debugging and archiving) - -## Environment Setup - -These tools are included in the main Temoa installation. If you're working from the repository: - -```bash -uv sync --all-extras -``` - -This ensures all required dependencies (pandas, graphviz, xlsxwriter, etc.) are installed. From 0e9d23721df0b31dc4078ab1ad2eb0947612645f Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 22 Nov 2025 12:12:08 -0500 Subject: [PATCH 358/587] fixing merge conflicts --- .github/workflows/ci.yml | 4 +- temoa/model_checking/commodity_graph.py | 121 ------------------------ temoa/utilities/graphviz_generator.py | 4 +- temoa/utilities/graphviz_util.py | 6 +- tests/test_full_runs.py | 40 ++++++++ tests/test_graphviz_integration.py | 116 ----------------------- 6 files changed, 46 insertions(+), 245 deletions(-) delete mode 100644 tests/test_graphviz_integration.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8c0261903..8faac9d88 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,9 +49,7 @@ jobs: sudo apt-get install -y coinor-cbc - name: Install Graphviz - run: | - sudo apt-get update - sudo apt-get install -y graphviz + run: sudo apt-get install -y graphviz - name: Run tests env: diff --git a/temoa/model_checking/commodity_graph.py b/temoa/model_checking/commodity_graph.py index 615aa1290..0a2e30a06 100644 --- a/temoa/model_checking/commodity_graph.py +++ b/temoa/model_checking/commodity_graph.py @@ -10,17 +10,10 @@ calculate_initial_positions, calculate_tech_graph_positions, ) -from temoa.utilities.graphviz_formats import results_dot_fmt -from temoa.utilities.graphviz_util import ( - create_text_edges, - create_text_nodes, - get_color_config, -) from temoa.utilities.visualizer import make_nx_graph, nx_to_vis if TYPE_CHECKING: from collections.abc import Iterable - from pathlib import Path from temoa.core.config import TemoaConfig from temoa.model_checking.network_model_data import EdgeTuple, NetworkModelData @@ -238,114 +231,6 @@ def generate_commodity_graph( return dg, sector_colors -logger = logging.getLogger(__name__) - - -def generate_graphviz_files( - period: Period, - region: Region, - network_data: NetworkModelData, - all_techs: Iterable[EdgeTuple], - sector_colors: dict[Sector, str], - output_dir: Path, -) -> None: - """ - Generates Graphviz .dot and .svg files matching the legacy format. - """ - import subprocess - - # Prepare data structures for Graphviz - # We need to categorize techs, commodities, and flows. - - # Sets to hold unique strings for Graphviz - etechs: set[tuple[str, str]] = set() # Used techs - dtechs: set[tuple[str, str]] = ( - set() - ) # Unused techs (we might not have this info easily, maybe skip or infer) - ecarriers: set[tuple[str, str]] = set() # Used carriers - dcarriers: set[tuple[str, str]] = set() # Unused carriers - eemissions: set[tuple[str, str]] = set() # Used emissions - demissions: set[tuple[str, str]] = set() # Unused emissions - eflowsi: set[tuple[str, str, str]] = set() # Input flows (Comm -> Tech) - eflowso: set[tuple[str, str, str]] = set() # Output flows (Tech -> Comm) - dflows: set[tuple[str, str, str]] = set() # Unused flows - xnodes: set[tuple[str, str]] = set() # Ethos nodes? - - # Helper to format attributes - def get_tech_attr(tech: str, cap: float = 0.0) -> str: - # We might not have capacity info here easily without querying DB or passing it in. - # For now, we'll just show the label. - return f'label="{tech}"' - - def get_comm_attr(comm: str) -> str: - return f'label="{comm}"' - - def get_flow_attr(flow: float = 0.0) -> str: - return f'label="{flow:.2f}"' if flow > 0 else '' - - # Iterate over all active technologies/edges - used_techs = set() - used_comms = set() - - for edge in all_techs: - tech = edge.tech - ic = edge.input_comm - oc = edge.output_comm - - used_techs.add(tech) - - # Input Flow: Comm -> Tech - if ic != 'ethos': - used_comms.add(ic) - ecarriers.add((ic, get_comm_attr(ic))) - eflowsi.add((ic, tech, '')) # No flow value for now - - # Output Flow: Tech -> Comm - if oc != 'ethos': - used_comms.add(oc) - ecarriers.add((oc, get_comm_attr(oc))) - eflowso.add((tech, oc, '')) # No flow value for now - - # Tech Node - etechs.add((tech, get_tech_attr(tech))) - - # Generate the DOT content - colors = get_color_config(False) # Default to color - - args = { - 'period': period, - 'splinevar': 'true', # Default - 'dtechs': create_text_nodes(dtechs, indent=2), - 'etechs': create_text_nodes(etechs, indent=2), - 'xnodes': create_text_nodes(xnodes, indent=2), - 'dcarriers': create_text_nodes(dcarriers, indent=2), - 'ecarriers': create_text_nodes(ecarriers, indent=2), - 'demissions': create_text_nodes(demissions, indent=2), - 'eemissions': create_text_nodes(eemissions, indent=2), - 'dflows': create_text_edges(dflows, indent=2), - 'eflowsi': create_text_edges(eflowsi, indent=3), - 'eflowso': create_text_edges(eflowso, indent=3), - **colors, - } - - dot_content = results_dot_fmt.format(**args) - - output_name = output_dir / f'results_{region}_{period}' - dot_file = output_name.with_suffix('.dot') - svg_file = output_name.with_suffix('.svg') - - with open(dot_file, 'w') as f: - f.write(dot_content) - - try: - subprocess.call(['dot', '-Tsvg', f'-o{svg_file}', str(dot_file)]) - logger.info('Generated Graphviz plot: %s', svg_file) - except FileNotFoundError: - logger.error("Graphviz 'dot' command not found. Please install Graphviz.") - except Exception as e: - logger.error('Failed to run Graphviz: %s', e) - - def visualize_graph( region: Region, period: Period, @@ -418,12 +303,6 @@ def visualize_graph( else: logger.error('Failed to generate network graphs') - # 7. Generate Graphviz output if requested - if config.graphviz_output: - generate_graphviz_files( - period, region, network_data, all_techs_for_period, sector_colors, config.output_path - ) - # 8. Perform cycle detection on the commodity graph try: for cycle in nx.simple_cycles(G=commodity_graph): diff --git a/temoa/utilities/graphviz_generator.py b/temoa/utilities/graphviz_generator.py index eb328a3d7..eb8de5b8f 100644 --- a/temoa/utilities/graphviz_generator.py +++ b/temoa/utilities/graphviz_generator.py @@ -129,7 +129,7 @@ def process_input(args: list[str]) -> dict[str, Any]: options = parser.parse_args(args) - if bool(options.scenario_name) ^ bool(options.period): + if (options.scenario_name is not None) ^ (options.period is not None): parser.print_help() raise ValueError('Scenario and input year must both be present or not present together') @@ -220,7 +220,7 @@ def set_graphic_options( """Set graphic options for the diagrams.""" if grey_flag is not None: self.grey_flag = grey_flag - self.colors.update(get_color_config(self.grey_flag)) + self.colors.update(get_color_config(grey_flag=self.grey_flag)) if splinevar is not None: self.colors['splinevar'] = 'spline' if splinevar else 'line' self.__log__( diff --git a/temoa/utilities/graphviz_util.py b/temoa/utilities/graphviz_util.py index 2619cd583..31a320feb 100644 --- a/temoa/utilities/graphviz_util.py +++ b/temoa/utilities/graphviz_util.py @@ -1,7 +1,7 @@ from collections.abc import Callable, Iterable, Sequence, Sized -def get_color_config(grey_flag: bool) -> dict[str, str | tuple[str, ...]]: +def get_color_config(*, grey_flag: bool) -> dict[str, str | tuple[str, ...]]: """Return a dictionary of color configurations for the graph.""" is_colored = not grey_flag @@ -70,7 +70,7 @@ def create_text_nodes(nodes: Iterable[tuple[str, str]], indent: int = 1) -> str: # Convert to list to avoid consuming iterable multiple times if it's an iterator nodes_list = list(nodes) if not nodes_list: - return '// no nodes in this section' + return '// no nodes in this section\n' # Step 1: for alignment, get max item length in node list # The `+ 2` accounts for the two extra quotes that will be added. @@ -105,7 +105,7 @@ def create_text_edges(edges: Iterable[tuple[str, str, str]], indent: int = 1) -> # Convert to list edges_list = list(edges) if not edges_list: - return '// no edges in this section' + return '// no edges in this section\n' # Step 1: for alignment, get max length of items on left and right side of # graph operator token ('->'). The `+ 2` accounts for the two extra quotes. diff --git a/tests/test_full_runs.py b/tests/test_full_runs.py index d8ac886f2..19e3c740c 100644 --- a/tests/test_full_runs.py +++ b/tests/test_full_runs.py @@ -4,6 +4,7 @@ import logging import sqlite3 +from pathlib import Path from typing import TYPE_CHECKING import pytest @@ -12,6 +13,7 @@ # from src.temoa_model.temoa_model import temoa_create_model from temoa._internal.temoa_sequencer import TemoaSequencer +from temoa.core.config import TemoaConfig from temoa.core.model import TemoaModel from tests.legacy_test_values import ExpectedVals, test_vals @@ -106,3 +108,41 @@ def test_myopic_utopia( # increased after rework of inter-season sequencing assert invest_sum == pytest.approx(11004.8335), 'sum of investment costs did not match expected' con.close() + + +def test_graphviz_integration(tmp_path: Path) -> None: + """ + Test that graphviz diagrams are generated during a full run when enabled. + """ + # Use utopia config as a base + config_file = Path(__file__).parent / 'testing_configs' / 'config_utopia.toml' + + # Build config with graphviz output enabled + config = TemoaConfig.build_config( + config_file=config_file, + output_path=tmp_path, + silent=True, + ) + + # Enable graphviz output + config.graphviz_output = True + + # Run the sequencer + sequencer = TemoaSequencer(config=config) + sequencer.start() + + # The graphviz generator creates a subdirectory like: {db_name}_{scenario}_graphviz + # Find any directory matching the pattern *_graphviz + graphviz_dirs = list(tmp_path.glob('*_graphviz')) + assert len(graphviz_dirs) > 0, 'Graphviz output directory should be created' + + graphviz_dir = graphviz_dirs[0] + assert graphviz_dir.is_dir(), 'Graphviz output should be a directory' + + # Check that at least some output files were generated (DOT or SVG files) + output_files = list(graphviz_dir.rglob('*.svg')) + list(graphviz_dir.rglob('*.dot')) + assert len(output_files) > 0, 'At least one diagram file should be generated' + + # Check that the files are not empty + for output_file in output_files: + assert output_file.stat().st_size > 0, f'{output_file.name} should not be empty' diff --git a/tests/test_graphviz_integration.py b/tests/test_graphviz_integration.py deleted file mode 100644 index c3492818e..000000000 --- a/tests/test_graphviz_integration.py +++ /dev/null @@ -1,116 +0,0 @@ -from __future__ import annotations - -import shutil -import tempfile -import unittest -from pathlib import Path -from typing import cast -from unittest.mock import MagicMock, patch - -from temoa.core.config import TemoaConfig -from temoa.model_checking.commodity_graph import generate_graphviz_files, visualize_graph -from temoa.model_checking.network_model_data import NetworkModelData -from temoa.types.core_types import Commodity, Period, Region, Sector, Technology, Vintage -from temoa.utilities.graph_utils import EdgeTuple - - -class TestGraphvizIntegration(unittest.TestCase): - def setUp(self) -> None: # noqa: N802 - # Create a unique temp output directory per test run - self._tmp_dir = Path(tempfile.mkdtemp(prefix='temoa_test_output_')) - - self.config = MagicMock(spec=TemoaConfig) - self.config.plot_commodity_network = True - self.config.graphviz_output = True - self.config.output_path = self._tmp_dir - - self.network_data = MagicMock(spec=NetworkModelData) - - self.network_data.available_techs = { - (cast(Region, 'region'), cast(Period, '2020')): {('tech1', 'v1')} - } - self.network_data.source_commodities = { - (cast(Region, 'region'), cast(Period, '2020')): {'coal'} - } - self.network_data.demand_commodities = { - (cast(Region, 'region'), cast(Period, '2020')): {'electricity'} - } - - self.edge_tuple = EdgeTuple( - region=cast(Region, 'region'), - tech=cast(Technology, 'tech1'), - vintage=cast(Vintage, 'v1'), - input_comm=cast(Commodity, 'coal'), - output_comm=cast(Commodity, 'electricity'), - sector=cast(Sector, 'electric'), - ) - - def tearDown(self) -> None: # noqa: N802 - shutil.rmtree(self._tmp_dir, ignore_errors=True) - - @patch('temoa.model_checking.commodity_graph.generate_commodity_graph') - @patch('temoa.model_checking.commodity_graph.generate_technology_graph') - @patch('temoa.model_checking.commodity_graph.nx_to_vis') - @patch('temoa.model_checking.commodity_graph.generate_graphviz_files') - def test_visualize_graph_calls_graphviz( - self, - mock_gen_gv: MagicMock, - mock_nx_vis: MagicMock, - mock_gen_tech: MagicMock, - mock_gen_comm: MagicMock, - ) -> None: - mock_gen_comm.return_value = (MagicMock(), {}) - mock_gen_tech.return_value = MagicMock() - mock_nx_vis.return_value = 'path/to/graph.html' - - visualize_graph( - region=cast(Region, 'region'), - period=cast(Period, '2020'), - network_data=self.network_data, - demand_orphans=[], - other_orphans=[], - driven_techs=[self.edge_tuple], - config=self.config, - ) - - mock_gen_gv.assert_called_once() - args, _ = mock_gen_gv.call_args - self.assertEqual(args[0], '2020') - self.assertEqual(args[1], 'region') - # Check that output path is passed correctly - self.assertEqual(args[5], self.config.output_path) - - @patch('subprocess.call') - def test_generate_graphviz_files_creates_dot_file(self, mock_subprocess: MagicMock) -> None: - with tempfile.TemporaryDirectory(prefix='temoa_test_output_') as tmp_output_dir_str: - output_dir = Path(tmp_output_dir_str) - - sector_colors = {cast(Sector, 'electric'): 'blue'} - all_techs = [self.edge_tuple] - - generate_graphviz_files( - period=cast(Period, '2020'), - region=cast(Region, 'region'), - network_data=self.network_data, - all_techs=all_techs, - sector_colors=sector_colors, - output_dir=output_dir, - ) - - dot_file = output_dir / 'results_region_2020.dot' - self.assertTrue(dot_file.exists()) - - with open(dot_file) as f: - content = f.read() - self.assertIn('label = "Results for 2020"', content) - self.assertIn('label="tech1"', content) - self.assertIn('label="coal"', content) - self.assertIn('label="electricity"', content) - - # Verify subprocess call - svg_file = output_dir / 'results_region_2020.svg' - mock_subprocess.assert_called_with(['dot', '-Tsvg', f'-o{svg_file}', str(dot_file)]) - - -if __name__ == '__main__': - unittest.main() From f228f0b042b46496024aab202cbda62050b80d45 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 22 Nov 2025 17:57:38 -0500 Subject: [PATCH 359/587] fixing E501 line too long linting issues in _internal --- temoa/_internal/data_brick.py | 12 ++++++---- temoa/_internal/exchange_tech_cost_ledger.py | 10 ++++---- temoa/_internal/run_actions.py | 19 ++++++++++------ temoa/_internal/table_data_puller.py | 20 +++++++++------- temoa/_internal/table_writer.py | 24 +++++++++++++------- temoa/_internal/temoa_sequencer.py | 9 +++++--- 6 files changed, 59 insertions(+), 35 deletions(-) diff --git a/temoa/_internal/data_brick.py b/temoa/_internal/data_brick.py index 735576179..a83544bee 100644 --- a/temoa/_internal/data_brick.py +++ b/temoa/_internal/data_brick.py @@ -1,8 +1,9 @@ """ -Objective of this module is to build a lightweight container to hold a selection of model results from a -Worker process with the intent to send this back via multiprocessing queue in lieu of sending the entire -model back (which is giant and slow). It will probably be a "superset" of data elements required to report -for MC and MGA right now, and maybe others +Objective of this module is to build a lightweight container to hold a selection of model results +from a Worker process with the intent to send this back via multiprocessing queue in lieu of +sending the entire +model back (which is giant and slow). It will probably be a "superset" of data elements required +to report for MC and MGA right now, and maybe others """ @@ -21,7 +22,8 @@ class DataBrick: """ - A utility container for bundling assorted data structures for solved models done by Worker objects. + A utility container for bundling assorted data structures for solved models done by Worker + objects. """ def __init__( diff --git a/temoa/_internal/exchange_tech_cost_ledger.py b/temoa/_internal/exchange_tech_cost_ledger.py index 3edaa6c62..cf90257eb 100644 --- a/temoa/_internal/exchange_tech_cost_ledger.py +++ b/temoa/_internal/exchange_tech_cost_ledger.py @@ -1,8 +1,8 @@ """ The purpose of this module is to provide a ledger for all costs for exchange techs. The main reason -for the need is that in many cases, the costs need to be apportioned by use ratio so it is helpful to -separately gather all of the costs and then use a usage ratio to generate entries when asked for +for the need is that in many cases, the costs need to be apportioned by use ratio so it is helpful +to separately gather all of the costs and then use a usage ratio to generate entries when asked for """ @@ -71,7 +71,8 @@ def get_use_ratio( :param vintage: :return: the proportion to assign to the IMPORTER, or 0.5 if no usage """ - # Cast to TemoaModel for type checking - at runtime this will be either TemoaModel or Namespace + # Cast to TemoaModel for type checking - at runtime this will be either TemoaModel or + # Namespace # Both have the same attributes, but mypy doesn't know about Namespace's dynamic attributes model = cast('TemoaModel', self.model) # need to temporarily reconstitute the names @@ -130,7 +131,8 @@ def get_entries( region_costs: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]] = ( defaultdict(dict) ) - # iterate through each region pairing, pull the cost records and decide if/how to split each one + # iterate through each region pairing, pull the cost records and decide if/how to split + # each one for cost_type in self.cost_records: # make a copy, this will be destructive operation records = self.cost_records[cost_type].copy() diff --git a/temoa/_internal/run_actions.py b/temoa/_internal/run_actions.py index c646dbd7a..ecca3dc98 100644 --- a/temoa/_internal/run_actions.py +++ b/temoa/_internal/run_actions.py @@ -75,10 +75,12 @@ def check_database_version(config: TemoaConfig, db_major_reqd: int, min_db_minor db_minor = db_minor[0] if db_minor else -1 except sqlite3.OperationalError: logger.error( - 'Database does not appear to have MetaData table with required versioning info. See schema for v3+.' + 'Database does not appear to have MetaData table with required versioning info. ' + 'See schema for v3+.' ) sys.stderr.write( - 'Database does not appear to have MetaData table with required. Is this version 3+ compatible?\n' + 'Database does not appear to have MetaData table with required. Is this version ' + '3+ compatible?\n' 'If required, see dox on using the database migrator to move to v3.' ) db_major, db_minor = -1, -1 @@ -88,7 +90,8 @@ def check_database_version(config: TemoaConfig, db_major_reqd: int, min_db_minor good_version = db_major == db_major_reqd and db_minor >= min_db_minor if not good_version: logger.error( - 'Database %s version %d.%d does not match the major version %d and have at least minor version %d', + 'Database %s version %d.%d does not match the major version %d and have at least ' + 'minor version %d', str(name), db_major, db_minor, @@ -242,9 +245,10 @@ def solve_instance( elif solver_name == 'appsi_highs': pass - # dev note: The handling of suffixes is pretty weak. As of today 4/4/2024, highspy crashes if - # the keyword suffixes is passed in (regardless if there are any requested). CBC only - # supports some. Perhaps in the future, this will be easier. For now, we need a different + # dev note: The handling of suffixes is pretty weak. As of today 4/4/2024, highspy + # crashes if the keyword suffixes is passed in (regardless if there are any + # requested). CBC only supports some. Perhaps in the future, this will be + # easier. For now, we need a different # solve command for highspy and no suffixes because it works so well. if solver_suffixes: solver_suffixes_set = set(solver_suffixes) @@ -301,7 +305,8 @@ def check_solve_status(result: SolverResults) -> tuple[bool, str]: """ Check the status of the solve. :param result: the results object returned by the solver - :return: tuple of status boolean (True='optimal', others False), and string message if not optimal + :return: tuple of status boolean (True='optimal', others False), and string message if not + optimal """ soln = result['Solution'] diff --git a/temoa/_internal/table_data_puller.py b/temoa/_internal/table_data_puller.py index f9cc97a78..afa06f9e1 100644 --- a/temoa/_internal/table_data_puller.py +++ b/temoa/_internal/table_data_puller.py @@ -1,9 +1,10 @@ """ -A companion module to the table writer to hold some data-pulling functions and small utilities and separate them -from the writing process for organization and to isolate the DB access in the writer such that -these functions can be called on a model instance without any DB interactions. (Intended to support use -by Workers who shouldn't interact with DB). Dev Note: In future, if transition away from sqlite, this -could all be refactored to perform tasks within workers, but concurrent access to sqlite is a no-go +A companion module to the table writer to hold some data-pulling functions and small utilities and +separate them from the writing process for organization and to isolate the DB access in the writer +such that these functions can be called on a model instance without any DB interactions. (Intended +to support use by Workers who shouldn't interact with DB). Dev Note: In future, if transition +away from sqlite, this could all be refactored to perform tasks within workers, but concurrent +access to sqlite is a no-go """ from __future__ import annotations @@ -76,7 +77,8 @@ def poll_capacity_results(model: TemoaModel, epsilon: float = 1e-5) -> CapData: for r, t, v in model.retirement_periods: lifetime = value(model.lifetime_process[r, t, v]) for p in model.retirement_periods[r, t, v]: - # We want to output period retirement, not annual retirement, so multiply by PeriodLength + # We want to output period retirement, not annual retirement, so multiply by + # PeriodLength eol = value(model.period_length[p]) * value(model.v_annual_retirement[r, p, t, v]) early = 0 if t in model.tech_retirement and v < p <= v + lifetime - value(model.period_length[p]): @@ -277,7 +279,8 @@ def poll_cost_results( """ Poll a solved model for all cost results :param M: Solved Model - :param p_0: a base year for discounting of loans, typically only used in MYOPIC. If none, first optimization year used + :param p_0: a base year for discounting of loans, typically only used in MYOPIC. If none, + first optimization year used :param epsilon: epsilon (default 1e-5) :return: tuple of cost_dict, exchange_cost_dict (for exchange techs) """ @@ -568,7 +571,8 @@ def poll_emissions( :return: cost_dict, flow_dict """ - # UPDATE: older versions brought forward had some accounting errors here for flex/curtailed emissions + # UPDATE: older versions brought forward had some accounting errors here for flex/curtailed + # emissions # see the note on emissions in the Cost function in temoa_rules p_0_true: Period if p_0 is None: diff --git a/temoa/_internal/table_writer.py b/temoa/_internal/table_writer.py index ed9171d98..e8e012188 100644 --- a/temoa/_internal/table_writer.py +++ b/temoa/_internal/table_writer.py @@ -45,7 +45,8 @@ """ -Note: This file borrows heavily from the legacy pformat_results.py, and is somewhat of a restructure of that code +Note: This file borrows heavily from the legacy pformat_results.py, and is somewhat of a + restructure of that code to accommodate the run modes more cleanly """ @@ -97,10 +98,13 @@ def write_results( ) -> None: """ Write results to output database - :param iteration: An interation count for repeated runs, to be passed to tables that support it - :param results_with_duals: if provided, this will trigger the writing of dual variables, pulled from the SolverResults + :param iteration: An interation count for repeated runs, to be passed to tables that + support it + :param results_with_duals: if provided, this will trigger the writing of dual variables, + pulled from the SolverResults :param M: the model - :param append: append whatever is already in the tables. If False (default), clear existing tables by scenario name + :param append: append whatever is already in the tables. If False (default), clear + existing tables by scenario name :return: """ if not append: @@ -198,7 +202,8 @@ def clear_scenario(self) -> None: def clear_iterative_runs(self) -> None: """ clear runs that are iterative extensions to the scenario name - Ex: scenario = 'Red Monkey" ... will clear "Red Monkey-1, Red Monkey-2, Red Monkey-3, Red Monkey-4' + Ex: scenario = 'Red Monkey" ... will clear "Red Monkey-1, Red Monkey-2, Red Monkey-3, + Red Monkey-4' :return: None """ target = self.config.scenario + '-%' # the dash followed by wildcard for anything after @@ -381,7 +386,8 @@ def write_flow_tables(self, iteration: int | None = None) -> None: def write_summary_flow(self, model: TemoaModel, iteration: int | None = None) -> None: """ This is normally called from MGA (other?) - iterative solves where capturing the annual summary of flow out is desired vs. flows by season, tod for + iterative solves where capturing the annual summary of flow out is desired vs. flows by + season, tod for single instances :param iteration: the number of the sequential iteration :param M: The solved model @@ -500,7 +506,8 @@ def check_flow_balance(self, model: TemoaModel) -> bool: elif flows[fi][FlowType.IN] == 0 and abs(deltas[fi]) > 0.02: all_good = False logger.warning( - 'Flow balance check failed for index: %s, delta: %0.2f. Flows happening with 0 input', + 'Flow balance check failed for index: %s, delta: %0.2f. Flows happening with ' + '0 input', fi, deltas[fi], ) @@ -526,7 +533,8 @@ def write_costs( """ # P_0 is usually the first optimization year, but if running myopic, we could assign it via - # table entry. Perhaps in future it is just always the first optimization year of the 1st iter. + # table entry. Perhaps in future it is just always the first optimization year of the + # 1st iter. if self.config.scenario_mode == TemoaMode.MYOPIC: p_0 = model.myopic_discounting_year else: diff --git a/temoa/_internal/temoa_sequencer.py b/temoa/_internal/temoa_sequencer.py index 553e76304..ad28f2377 100644 --- a/temoa/_internal/temoa_sequencer.py +++ b/temoa/_internal/temoa_sequencer.py @@ -139,7 +139,8 @@ def start(self) -> None: # The `start` method's contract is to run to completion, not return a model. # Raise an error to guide the developer to the correct API. raise RuntimeError( - "For BUILD_ONLY mode, please use the 'build_model()' method instead of 'start()'." + "For BUILD_ONLY mode, please use the 'build_model()' method instead of " + "'start()'." ) case TemoaMode.CHECK: @@ -155,7 +156,8 @@ def start(self) -> None: case TemoaMode.MGA: if self.config.solver_name == 'appsi_highs': raise ValueError( - 'MGA mode is not compatible with the HiGHS solver due to a multiprocessing issue.' + 'MGA mode is not compatible with the HiGHS solver due to a multiprocessing ' + 'issue.' ) mga_sequencer = MgaSequencer(config=self.config) mga_sequencer.start() @@ -228,7 +230,8 @@ def _run_monte_carlo(self) -> None: """Encapsulated logic for the MONTE_CARLO mode.""" if self.config.solver_name == 'appsi_highs': raise ValueError( - 'Monte Carlo mode is not compatible with the HiGHS solver due to a multiprocessing issue.' + 'Monte Carlo mode is not compatible with the HiGHS solver due to a multiprocessing ' + 'issue.' ) # Disable features not typically used in Monte Carlo runs to reduce noise/overhead From 6a2833e483b4c525b725132a7b0ca376a195a776 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 22 Nov 2025 17:58:00 -0500 Subject: [PATCH 360/587] fixing E501 line too long linting issues in components --- temoa/components/capacity.py | 25 ++++++----- temoa/components/commodities.py | 30 ++++++++----- temoa/components/costs.py | 66 ++++++++++++++++------------ temoa/components/geography.py | 5 ++- temoa/components/limits.py | 77 ++++++++++++++++++++------------- temoa/components/operations.py | 21 ++++++--- temoa/components/reserves.py | 24 +++++++--- temoa/components/storage.py | 9 ++-- temoa/components/technology.py | 29 ++++++++----- temoa/components/time.py | 30 ++++++++----- 10 files changed, 199 insertions(+), 117 deletions(-) diff --git a/temoa/components/capacity.py b/temoa/components/capacity.py index ff495f9e0..790bd4adf 100644 --- a/temoa/components/capacity.py +++ b/temoa/components/capacity.py @@ -65,8 +65,9 @@ def check_capacity_factor_process(model: TemoaModel) -> None: model.is_capacity_factor_process[r, p, t, v] = True if count < num_seg: logger.info( - 'Some but not all processes were set in capacity_factor_process (%i out of a possible %i) for: %s' - ' Missing values will default to capacity_factor_tech value or 1 if that is not set either.', + 'Some but not all processes were set in capacity_factor_process (%i out of a ' + 'possible %i) for: %s Missing values will default to capacity_factor_tech ' + 'value or 1 if that is not set either.', count, num_seg, (r, p, t, v), @@ -118,7 +119,8 @@ def get_default_capacity_factor( model: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage ) -> float: """ - This initializer is used to fill the capacity_factor_process from the capacity_factor_tech where needed. + This initializer is used to fill the capacity_factor_process from the capacity_factor_tech + where needed. Priority: 1. As specified in data input (this function not called) @@ -290,7 +292,8 @@ def annual_retirement_constraint( \frac{1}{\text{LEN}_p} \cdot \left( \frac{\text{LSC}_{r,p,t,v}}{\text{PLF}_{r,p,t,v}} \cdot \textbf{CAP}_{r,p,t,v} - - \frac{\text{LSC}_{r,p_{next},t,v}}{\text{PLF}_{r,p_{next},t,v}} \cdot \textbf{CAP}_{r,p_{next},t,v} + - \frac{\text{LSC}_{r,p_{next},t,v}}{\text{PLF}_{r,p_{next},t,v}} \cdot + \textbf{CAP}_{r,p_{next},t,v} \right) & \text{otherwise} \\ \end{cases} @@ -329,7 +332,8 @@ def annual_retirement_constraint( p_next = model.time_future.next(p) if p == model.time_optimize.last() or p_next == v + value(model.lifetime_process[r, t, v]): - # No v_capacity or v_retired_capacity for next period so just continue down the survival curve + # No v_capacity or v_retired_capacity for next period so just continue down the + # survival curve cap_end = ( cap_begin * value(model.lifetime_survival_curve[r, p_next, t, v]) @@ -496,13 +500,13 @@ def adjusted_capacity_constraint( :figclass: align-center :figwidth: 50% - For processes reaching end of life mid-period, the process life fraction adjustment is applied, - distributing the effective capacity over the whole period. + For processes reaching end of life mid-period, the process life fraction adjustment is + applied, distributing the effective capacity over the whole period. For processes using survival curves, the yearly survival curve :math:`\text{LSC}_{r,p,t,v}` is averaged over the period to get the effective remaining capacity for that period Because this - implicitly handles mid-period end of life, :math:`\text{PLF}_{r,p,t,v}` is used to account for both - phenomena. + implicitly handles mid-period end of life, :math:`\text{PLF}_{r,p,t,v}` is used to account for + both phenomena. .. figure:: images/adjusted_capacity_sc.* :align: center @@ -594,7 +598,8 @@ def create_capacity_and_retirement_sets(model: TemoaModel) -> None: processes that produce commodity `o` at end-of-life. - model.new_capacity_rtv: set of (r, t, v) for new capacity investments. - model.active_capacity_available_rpt: set of (r, p, t) where capacity is active. - - model.active_capacity_available_rptv: set of (r, p, t, v) where vintage capacity is active. + - model.active_capacity_available_rptv: set of (r, p, t, v) where vintage capacity is + active. """ logger.debug('Creating capacity, retirement, and construction/EOL sets.') diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index bb65126eb..a80ed4e83 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -225,9 +225,11 @@ def demand_activity_constraint( .. math:: :label: DemandActivity - DEM_{r, p, s, d, dem} \cdot \sum_{I} \textbf{FO}_{r, p, s_0, d_0, i, t \not \in T^{a}, v, dem} + DEM_{r, p, s, d, dem} \cdot \sum_{I} + \textbf{FO}_{r, p, s_0, d_0, i, t \not \in T^{a}, v, dem} = - DEM_{r, p, s_0, d_0, dem} \cdot \sum_{I} \textbf{FO}_{r, p, s, d, i, t \not \in T^{a}, v, dem} + DEM_{r, p, s_0, d_0, dem} \cdot \sum_{I} + \textbf{FO}_{r, p, s, d, i, t \not \in T^{a}, v, dem} \\ \forall \{r, p, s, d, t, v, dem, s_0, d_0\} \in \Theta_{\text{DemandActivity}} @@ -316,7 +318,8 @@ def commodity_balance_constraint( Finally, for annual commodities, AnnualCommodityBalance is used which balances the sum of flows over each year. - *process outputs + imports + end of life outputs = process inputs + construction inputs + exports + flex waste* + *process outputs + imports + end of life outputs = process inputs + construction inputs + + exports + flex waste* .. math:: :label: CommodityBalance @@ -324,26 +327,33 @@ def commodity_balance_constraint( \begin{aligned} &\sum_{I, t \notin T^a, V} \mathbf{FO}_{r, p, s, d, i, t, v, c} && \text{(processes outputting commodity)} \\ - &+ SEG_{s,d} \cdot \sum_{I, t \in T^a, V} \frac{\mathbf{FOA}_{r, p, i, t, v, c}}{EFF_{r, i, t, v, c}} + &+ SEG_{s,d} \cdot \sum_{I, t \in T^a, V} + \frac{\mathbf{FOA}_{r, p, i, t, v, c}}{EFF_{r, i, t, v, c}} && \text{(annual processes outputting commodity)} \\ - &+ \sum_{\text{reg} \neq r, I, t \in T^x, V} \mathbf{FIM}_{r - \text{reg}, p, s, d, i, t, v, c} + &+ \sum_{\text{reg} \neq r, I, t \in T^x, V} + \mathbf{FIM}_{r - \text{reg}, p, s, d, i, t, v, c} && \text{(inter-regional imports of commodity)} \\ - &+ SEG_{s,d} \sum_{T, V} \left ( EOLO_{r, t, v, c} \cdot \textbf{ART}_{r, p, t, v} \right ) + &+ SEG_{s,d} \sum_{T, V} \left ( EOLO_{r, t, v, c} \cdot \textbf{ART}_{r, p, t, v} + \right ) && \text{(end-of-life outputs of commodity)} \\ &\begin{cases} &= \text{if } c \notin C^w \\ &\geq \text{if } c \in C^w \end{cases} \\ &\sum_{t \in T^s, V, O} \mathbf{FIS}_{r, p, s, d, c, t, v, o} && \text{(commodity stored)} \\ - &+ \sum_{t \notin T^s, V, O} \frac{\mathbf{FO}_{r, p, s, d, c, t, v, o}}{EFF_{r, c, t, v, o}} + &+ \sum_{t \notin T^s, V, O} + \frac{\mathbf{FO}_{r, p, s, d, c, t, v, o}}{EFF_{r, c, t, v, o}} && \text{(commodity consumed by processes)} \\ - &+ SEG_{s,d} \cdot \sum_{t \in T^a, V, O} \frac{\mathbf{FOA}_{r, p, c, t, v, o}}{EFF_{r, c, t, v, o}} + &+ SEG_{s,d} \cdot \sum_{t \in T^a, V, O} + \frac{\mathbf{FOA}_{r, p, c, t, v, o}}{EFF_{r, c, t, v, o}} && \text{(commodity consumed by annual processes)} \\ - &+ \sum_{\text{reg} \neq r, t \in T^x, V, O} \mathbf{FEX}_{r - \text{reg}, p, s, d, c, t, v, o} + &+ \sum_{\text{reg} \neq r, t \in T^x, V, O} + \mathbf{FEX}_{r - \text{reg}, p, s, d, c, t, v, o} && \text{(inter-regional exports of commodity)} \\ &+ \sum_{I, t \in T^f, V} \mathbf{FLX}_{r, p, s, d, i, t, v, c} && \text{(flex wastes of commodity)} \\ - &+ SEG_{s,d} \cdot \sum_{T, V} \left ( CON_{r, c, t, v} \cdot \frac{\textbf{NCAP}_{r, t, v}}{LEN_p} \right ) + &+ SEG_{s,d} \cdot \sum_{T, V} \left ( CON_{r, c, t, v} \cdot + \frac{\textbf{NCAP}_{r, t, v}}{LEN_p} \right ) && \text{(consumed annually by construction inputs)} \end{aligned} diff --git a/temoa/components/costs.py b/temoa/components/costs.py index 30bf455c1..a4647e64c 100644 --- a/temoa/components/costs.py +++ b/temoa/components/costs.py @@ -142,8 +142,8 @@ def loan_cost( vintage: int, ) -> float | Expression: """ - function to calculate the loan cost. It can be used with fixed values to produce a hard number or - pyomo variables/params to make a pyomo Expression + function to calculate the loan cost. It can be used with fixed values to produce a hard number + or pyomo variables/params to make a pyomo Expression :param capacity: The capacity to use to calculate cost :param invest_cost: the cost/capacity :param loan_annualize: parameter @@ -408,8 +408,10 @@ def period_cost_rule(model: TemoaModel, p: int) -> float | Expression: # result with processInput # ================= Emissions and Flex and Curtailment ================= - # Flex flows are deducted from v_flow_out, so it is NOT NEEDED to tax them again. (See commodity balance constr) - # Curtailment does not draw any inputs, so it seems logical that curtailed flows not be taxed either + # Flex flows are deducted from v_flow_out, so it is NOT NEEDED to tax them again. (See + # commodity balance constr) + # Curtailment does not draw any inputs, so it seems logical that curtailed flows not be taxed + # either # Earlier versions of this code had accounting for flex & curtailment that have been removed. base = [ @@ -446,7 +448,8 @@ def period_cost_rule(model: TemoaModel, p: int) -> float | Expression: # 2. flex emissions -- removed (double counting, flex wastes are SUBTRACTIVE from flowout) - # 3. curtailment emissions -- removed (curtailment is no-flow, for accounting only, so no emissions) + # 3. curtailment emissions -- removed (curtailment is no-flow, for accounting only, so no + # emissions) # 4. annual emissions var_annual_emissions = quicksum( @@ -463,7 +466,8 @@ def period_cost_rule(model: TemoaModel, p: int) -> float | Expression: if t not in model.tech_flex ) - # 5. flex annual emissions -- removed (double counting, flex wastes are SUBTRACTIVE from flowout) + # 5. flex annual emissions -- removed (double counting, flex wastes are SUBTRACTIVE from + # flowout) # 6. embodied - treated as a fixed cost distributed over the deployment period (vintage) embodied_emissions = quicksum( @@ -472,9 +476,9 @@ def period_cost_rule(model: TemoaModel, p: int) -> float | Expression: * value(model.emission_embodied[r, e, t, v]) / value(model.period_length[p]), cost_factor=value(model.cost_emission[r, p, e]), - cost_years=value( - model.period_length[v] - ), # We assume the embodied emissions are emitted in the same year as the capacity is installed. + cost_years=value(model.period_length[v]), + # We assume the embodied emissions are emitted in the same year as the capacity is + # installed. global_discount_rate=global_discount_rate, p_0=p_0, p=p, @@ -490,9 +494,9 @@ def period_cost_rule(model: TemoaModel, p: int) -> float | Expression: cap_or_flow=model.v_annual_retirement[r, p, t, v] * value(model.emission_end_of_life[r, e, t, v]), cost_factor=value(model.cost_emission[r, p, e]), - cost_years=value( - model.period_length[p] - ), # We assume the embodied emissions are emitted in the same year as the capacity is installed. + cost_years=value(model.period_length[p]), + # We assume the embodied emissions are emitted in the same year as the capacity is + # installed. global_discount_rate=global_discount_rate, p_0=p_0, p=p, @@ -546,32 +550,38 @@ def total_cost_rule(model: TemoaModel) -> Expression: Note that capital costs (:math:`{CI}_{r,t,v}`) are handled in several steps. - 1. Each capital cost is amortized using the loan rate (i.e., technology-specific discount rate) and loan period. + 1. Each capital cost is amortized using the loan rate (i.e., technology-specific discount + rate) and loan period. - 2. The annual stream of payments is converted into a lump sum using the global discount rate and loan period. + 2. The annual stream of payments is converted into a lump sum using the global discount + rate and loan period. 3. The new lump sum is amortized at the global discount rate over the process lifetime. 4. Loan payments beyond the model time horizon are removed and the lump sum recalculated. - 5. Finally, the lump sum is discounted back to the beginning of the horizon (:math:`P_0`) using the global discount rate. + 5. Finally, the lump sum is discounted back to the beginning of the horizon (:math:`P_0`) + using the global discount rate. Steps 3 and 4 serve to correctly balance the cost-benefit of technologies whose useful lives - would extend beyond the planning horizon. While an explicit salvage term is not included, this approach properly - captures the capital costs incurred within the model time horizon, accounting for process-specific loan rates - and periods. - - In the case of processes using survival curves, steps 3 and 4 do not reamortise costs uniformly over the process lifetime. - Instead, costs are amortised over the life of the process in proportion to the survival fraction in each year. - Note that, for this calculation, a survival curve :math:`{LSC}_{r,y,t,v}` must be defined out to the year in which the - surviving fraction is zero, even if that extends beyond the planning horizon. It must also be defined for each integer - year between model periods and, if not, these gaps will be filled by linear interpolation ahead of this calculation. + would extend beyond the planning horizon. While an explicit salvage term is not included, this + approach properly captures the capital costs incurred within the model time horizon, accounting + for process-specific loan rates and periods. + + In the case of processes using survival curves, steps 3 and 4 do not reamortise costs uniformly + over the process lifetime. Instead, costs are amortised over the life of the process in + proportion to the survival fraction in each year. Note that, for this calculation, a survival + curve :math:`{LSC}_{r,y,t,v}` must be defined out to the year in which the surviving fraction + is zero, even if that extends beyond the planning horizon. It must also be defined for each + integer year between model periods and, if not, these gaps will be filled by linear + interpolation ahead of this calculation. .. math:: :label: obj_invest_survival_curve \begin{aligned} - C_{loans,LSC} =& \sum_{r, t, v \in \Theta_{CI}} CI_{r, t, v} \cdot \textbf{NCAP}_{r, t, v} + C_{loans,LSC} =& \sum_{r, t, v \in \Theta_{CI}} CI_{r, t, v} \cdot + \textbf{NCAP}_{r, t, v} && \text{(overnight capital cost)} \\ &\cdot \frac{A}{P}(i=\text{LR}_{r,t,v}, N=\text{LLP}_{r,t,v}) && \text{(overnight cost amortised into annual loan payments)} \\ @@ -603,7 +613,8 @@ def total_cost_rule(model: TemoaModel) -> Expression: :label: annual_fixed_variable_emission \begin{aligned} - C_{fixed} =& \sum_{r, p, t, v \in \Theta_{CF}} CF_{r, p, t, v} \cdot \textbf{CAP}_{r, p, t, v} + C_{fixed} =& \sum_{r, p, t, v \in \Theta_{CF}} CF_{r, p, t, v} \cdot + \textbf{CAP}_{r, p, t, v} && \text{(annual fixed cost)} \\ \\ C_{variable} =& \sum_{r, p, t \notin T^a, v \in \Theta_{CV}} @@ -617,7 +628,8 @@ def total_cost_rule(model: TemoaModel) -> Expression: & \text{where } t \in T^a \\ &+\\ C_{emissions} =& \sum_{r, p, e \in \Theta_{CE}} CE_{r, p, e} - \cdot EAC_{r, i, t, v, o, e} \cdot \sum_{S, D, I, O} \mathbf{FO}_{r, p, s, d, i, t, v, o} + \cdot EAC_{r, i, t, v, o, e} \cdot \sum_{S, D, I, O} + \mathbf{FO}_{r, p, s, d, i, t, v, o} && \text{(annual emission cost on flow)} \\ & \text{where } t \notin T^a \\ &+\\ diff --git a/temoa/components/geography.py b/temoa/components/geography.py index ffad4e9bd..96538c409 100644 --- a/temoa/components/geography.py +++ b/temoa/components/geography.py @@ -134,7 +134,10 @@ def create_geography_sets(model: TemoaModel) -> None: continue if '-' not in r: - msg = f"Exchange technology {t} has an invalid region '{r}'. Must be 'region_from-region_to'." + msg = ( + f"Exchange technology {t} has an invalid region '{r}'. Must be " + "'region_from-region_to'." + ) logger.error(msg) raise ValueError(msg) diff --git a/temoa/components/limits.py b/temoa/components/limits.py index d9cc3c8d3..386705a51 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -51,7 +51,8 @@ def limit_tech_input_split_constraint_indices( if len(ann_indices) > 0: msg = ( 'Warning: Annual technologies included in limit_tech_input_split table. ' - 'Use limit_tech_input_split_annual table instead or these constraints will be ignored: {}' + 'Use limit_tech_input_split_annual table instead or these constraints will ' + 'be ignored: {}' ) logger.warning(msg.format(ann_indices)) @@ -100,7 +101,8 @@ def limit_tech_output_split_constraint_indices( if len(ann_indices) > 0: msg = ( 'Warning: Annual technologies included in limit_tech_output_split table. ' - 'Use limit_tech_output_split_annual table instead or these constraints will be ignored: {}' + 'Use limit_tech_output_split_annual table instead or these constraints will ' + 'be ignored: {}' ) logger.warning(msg.format(ann_indices)) @@ -253,10 +255,10 @@ def limit_resource_constraint(model: TemoaModel, r: Region, t: Technology, op: s \le LR_{r, t} \forall \{r, t\} \in \Theta_{\text{limit_resource}}""" - # dev note: this constraint is a misnomer. It is actually a "global activity constraint on a tech" - # regardless of whatever "resources" are consumed. - # dev note: this would generally be applied to a "dummy import" technology to restrict something like - # oil/mineral extraction across all model periods. Looks fine to me. + # dev note: this constraint is a misnomer. It is actually a "global activity constraint on a + # tech" regardless of whatever "resources" are consumed. + # dev note: this would generally be applied to a "dummy import" technology to restrict + # something like oil/mineral extraction across all model periods. Looks fine to me. regions = geography.gather_group_regions(model, r) techs = technology.gather_group_techs(model, t) @@ -302,9 +304,11 @@ def limit_activity_share_constraint( .. math:: :label: Limit Activity Share - \sum_{R_g \subseteq R,\ S,\ D,\ I,\ T^{g_1} \subseteq T,\ V,\ O} \mathbf{FO}_{r,p,s,d,i,t,v,o} + \sum_{R_g \subseteq R,\ S,\ D,\ I,\ T^{g_1} \subseteq T,\ V,\ O} + \mathbf{FO}_{r,p,s,d,i,t,v,o} \leq LAS_{r,p,g_1,g_2} \cdot - \sum_{R_g \subseteq R,\ S,\ D,\ I,\ T^{g_2} \subseteq T,\ V,\ O} \mathbf{FO}_{r,p,s,d,i,t,v,o} + \sum_{R_g \subseteq R,\ S,\ D,\ I,\ T^{g_2} \subseteq T,\ V,\ O} + \mathbf{FO}_{r,p,s,d,i,t,v,o} \qquad \forall \{r, p, g_1, g_2\} \in \Theta_{\text{limit_activity_share}} """ @@ -450,15 +454,18 @@ def limit_annual_capacity_factor_constraint( .. math:: :label: limit_annual_capacity_factor - \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMACF_{r, p, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} + \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMACF_{r, p, t} \cdot + \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} \forall \{r, p, t \notin T^{a}, o\} \in \Theta_{\text{limit_annual_capacity_factor}} - \\\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \ge LIMACF_{r, p, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} + \\\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \ge LIMACF_{r, p, t} \cdot + \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} \forall \{r, p, t \in T^{a}, o\} \in \Theta_{\text{limit_annual_capacity_factor}} """ - # r can be an individual region (r='US'), or a combination of regions separated by plus (r='Mexico+US+Canada'), or 'global'. + # r can be an individual region (r='US'), or a combination of regions separated by plus + # (r='Mexico+US+Canada'), or 'global'. # if r == 'global', the constraint is system-wide regions = geography.gather_group_regions(model, r) # we need to screen here because it is possible that the restriction extends beyond the @@ -509,15 +516,19 @@ def limit_seasonal_capacity_factor_constraint( .. math:: :label: Limit Seasonal Capacity Factor - \sum_{D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMSCF_{r, p, s, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} + \sum_{D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMSCF_{r, p, s, t} \cdot + \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} \forall \{r, p, t \notin T^{a}, o\} \in \Theta_{\text{limit_seasonal_capacity_factor}} - \\\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \cdot \sum_{D} SEG_{s,d} \le LIMSCF_{r, p, s, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} + \\\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \cdot \sum_{D} SEG_{s,d} + \le LIMSCF_{r, p, s, t} \cdot + \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} \forall \{r, p, t \in T^{a}, o\} \in \Theta_{\text{limit_seasonal_capacity_factor}} """ - # r can be an individual region (r='US'), or a combination of regions separated by plus (r='Mexico+US+Canada'), or 'global'. + # r can be an individual region (r='US'), or a combination of regions separated by plus + # (r='Mexico+US+Canada'), or 'global'. # if r == 'global', the constraint is system-wide regions = geography.gather_group_regions(model, r) # we need to screen here because it is possible that the restriction extends beyond the @@ -728,9 +739,11 @@ def limit_tech_output_split_annual_constraint( \sum_{I, T^{a}} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} \geq - TOS_{r, p, t, o} \cdot \sum_{I, O, T^{a}} \textbf{FOA}_{r, p, s, d, i, t \in T^{a}, v, o} + TOS_{r, p, t, o} \cdot + \sum_{I, O, T^{a}} \textbf{FOA}_{r, p, s, d, i, t \in T^{a}, v, o} - \forall \{r, p, t \in T^{a}, v, o\} \in \Theta_{\text{limit_tech_output_split_annual}}""" + \forall \{r, p, t \in T^{a}, v, o\} \in + \Theta_{\text{limit_tech_output_split_annual}}""" out = quicksum( model.v_flow_out_annual[r, p, S_i, t, v, o] for S_i in model.process_inputs_by_output[r, p, t, v, o] @@ -812,17 +825,19 @@ def limit_emission_constraint( """ emission_limit = value(model.limit_emission[r, p, e, op]) - # 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. + # 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 regions = geography.gather_group_regions(model, r) # ================= Emissions and Flex and Curtailment ================= - # Flex flows are deducted from v_flow_out, so it is NOT NEEDED to tax them again. (See commodity balance constr) - # Curtailment does not draw any inputs, so it seems logical that curtailed flows not be taxed either + # Flex flows are deducted from v_flow_out, so it is NOT NEEDED to tax them again. + # (See commodity balance constr) + # Curtailment does not draw any inputs, so it seems logical that curtailed flows not be taxed + # either process_emissions = quicksum( model.v_flow_out[reg, p, S_s, S_d, S_i, S_t, S_v, S_o] @@ -867,7 +882,8 @@ def limit_emission_constraint( process_emissions + process_emissions_annual + embodied_emissions + retirement_emissions # + emissions_flex # NO! flex is subtracted from flowout, already accounted by flowout # + emissions_curtail # NO! curtailed flows are not actual flows, just an accounting tool - # + emissions_flex_annual # NO! flexannual is subtracted from flowoutannual, already accounted + # + emissions_flex_annual # NO! flexannual is subtracted from flowoutannual, already + # accounted ) expr = operator_expression(lhs, Operator(op), emission_limit) @@ -1151,7 +1167,8 @@ def limit_growth_new_capacity_delta( \begin{aligned}\text{Growth:}\\ &\mathbf{NCAP}_{r,t,v_i} - \mathbf{NCAP}_{r,t,v_{i-1}} - \leq S_{r,t} + (1+R_{r,t}) \cdot (\mathbf{NCAP}_{r,t,v_{i-1}} - \mathbf{NCAP}_{r,t,v_{i-2}}) + \leq S_{r,t} + (1+R_{r,t}) \cdot + (\mathbf{NCAP}_{r,t,v_{i-1}} - \mathbf{NCAP}_{r,t,v_{i-2}}) \end{aligned} \text{ where } v_i=p @@ -1188,8 +1205,8 @@ def limit_growth_new_capacity_delta( if len(periods) == 0: if p == model.time_optimize.first(): msg = ( - 'Tried to set {}rowthNewCapacityDelta constraint {} but there are no periods where this ' - 'technology can be built in this region. Constraint skipped.' + 'Tried to set {}rowthNewCapacityDelta constraint {} but there are no periods where ' + 'this technology can be built in this region. Constraint skipped.' ).format('Deg' if degrowth else 'G', (r, t)) logger.warning(msg) return Constraint.Skip @@ -1210,9 +1227,9 @@ def limit_growth_new_capacity_delta( ] if gaps: msg = ( - 'Constructing {}rowthNewCapacityDelta constraint {} and there are period gaps in which' - 'new capacity cannot be built in this region ({}). New capacity in these periods ' - 'will be treated as zero which may cause infeasibility or other problems.' + 'Constructing {}rowthNewCapacityDelta constraint {} and there are period gaps in ' + 'which new capacity cannot be built in this region ({}). New capacity in these ' + 'periods will be treated as zero which may cause infeasibility or other problems.' ).format('Deg' if degrowth else 'G', (r, t), gaps) logger.warning(msg) @@ -1329,8 +1346,8 @@ def limit_new_capacity_constraint( ) -> ExprLike: r""" The limit_new_capacity constraint sets a limit on the newly installed capacity of a - given technology or group in a given year. Note that the indices for these constraints are region, - period and tech. + given technology or group in a given year. Note that the indices for these constraints are + region, period and tech. .. math:: :label: limit_new_capacity diff --git a/temoa/components/operations.py b/temoa/components/operations.py index 95fdd8edf..a202aea36 100644 --- a/temoa/components/operations.py +++ b/temoa/components/operations.py @@ -292,7 +292,8 @@ def ramp_up_day_constraint( - :math:`SEG_{r,p,s,d}` is the fraction of the period in time slice :math:`(s,d)` - :math:`DPP` is the number of days in each period - :math:`R_{r,t}` is the ramp rate per hour - - :math:`\Delta H_{r,p,s,d,s_{next},d_{next}}` is the number of elapsed hours between midpoints of time slices + - :math:`\Delta H_{r,p,s,d,s_{next},d_{next}}` is the number of elapsed hours between midpoints + of time slices - :math:`CAP \cdot C2A` gives the maximum hourly change in activity """ @@ -336,7 +337,8 @@ def ramp_up_day_constraint( if ramp_fraction >= 1: msg = ( - 'Warning: Hourly ramp up rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' + 'Warning: Hourly ramp up rate ({}, {}) is too large to be constraining from ' + '({}, {}, {}) to ({}, {}, {}). ' f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' ) logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) @@ -425,7 +427,8 @@ def ramp_down_day_constraint( if ramp_fraction >= 1: msg = ( - 'Warning: Hourly ramp down rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' + 'Warning: Hourly ramp down rate ({}, {}) is too large to be constraining from ' + '({}, {}, {}) to ({}, {}, {}). ' f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' ) logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) @@ -452,7 +455,8 @@ def ramp_up_season_constraint( r""" Constrains the ramp up rate of activity between time slices at the boundary of sequential seasons. Same as ramp_up_day but only applies to the boundary - between sequential seasons, i.e., :math:`(s^{seq},d_{last})` to :math:`(s^{seq}_{next},d_{first})` + between sequential seasons, i.e., :math:`(s^{seq},d_{last})` to + :math:`(s^{seq}_{next},d_{first})` and :math:`s^{seq}_{next}` is based on the TimeSequential table rather than the time_season table. """ @@ -498,7 +502,8 @@ def ramp_up_season_constraint( if ramp_fraction >= 1: msg = ( - 'Warning: Hourly ramp up rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' + 'Warning: Hourly ramp up rate ({}, {}) is too large to be constraining from ' + '({}, {}, {}) to ({}, {}, {}). ' f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' ) logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) @@ -525,7 +530,8 @@ def ramp_down_season_constraint( r""" Constrains the ramp down rate of activity between time slices at the boundary of sequential seasons. Same as ramp_down_day but only applies to the boundary - between sequential seasons, i.e., :math:`(s^{seq},d_{last})` to :math:`(s^{seq}_{next},d_{first})` + between sequential seasons, i.e., :math:`(s^{seq},d_{last})` to + :math:`(s^{seq}_{next},d_{first})` and :math:`s^{seq}_{next}` is based on the TimeSequential table rather than the time_season table. """ @@ -571,7 +577,8 @@ def ramp_down_season_constraint( if ramp_fraction >= 1: msg = ( - 'Warning: Hourly ramp down rate ({}, {}) is too large to be constraining from ({}, {}, {}) to ({}, {}, {}). ' + 'Warning: Hourly ramp down rate ({}, {}) is too large to be constraining from ' + '({}, {}, {}) to ({}, {}, {}). ' f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' ) logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) diff --git a/temoa/components/reserves.py b/temoa/components/reserves.py index da3b0dbeb..bc82625b7 100644 --- a/temoa/components/reserves.py +++ b/temoa/components/reserves.py @@ -180,16 +180,23 @@ def reserve_margin_static( .. math:: :label: reserve_margin_static - &\sum_{t \in T^{res} \setminus T^{x}} {CC_{t,r} \cdot \textbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*} \cdot C2A_{r,t} }\\ - &+ \sum_{t \in T^{res} \cap T^{x}} {CC_{t,r_i-r} \cdot \textbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*} \cdot C2A_{r_i-r,t} }\\ - &- \sum_{t \in T^{res} \cap T^{x}} {CC_{t,r-r_i} \cdot \textbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*} \cdot C2A_{r-r_i,t} }\\ - &\geq \left [ \sum_{ t \in T^{res} \setminus T^{x},V,I,O } \textbf{FO}_{r, p, s, d, i, t, v, o}\right.\\ + &\sum_{t \in T^{res} \setminus T^{x}} {CC_{t,r} \cdot \textbf{CAPAVL}_{p,t} \cdot + SEG_{s^*,d^*} \cdot C2A_{r,t} }\\ + &+ \sum_{t \in T^{res} \cap T^{x}} {CC_{t,r_i-r} \cdot \textbf{CAPAVL}_{p,t} \cdot + SEG_{s^*,d^*} \cdot C2A_{r_i-r,t} }\\ + &- \sum_{t \in T^{res} \cap T^{x}} {CC_{t,r-r_i} \cdot \textbf{CAPAVL}_{p,t} \cdot + SEG_{s^*,d^*} \cdot C2A_{r-r_i,t} }\\ + &\geq \left [ \sum_{ t \in T^{res} \setminus T^{x},V,I,O } + \textbf{FO}_{r, p, s, d, i, t, v, o}\right.\\ &+ \sum_{ t \in T^{res} \cap T^{x},V,I,O } \textbf{FO}_{r_i-r, p, s, d, i, t, v, o}\\ &- \sum_{ t \in T^{res} \cap T^{x},V,I,O } \textbf{FI}_{r-r_i, p, s, d, i, t, v, o}\\ - &- \left.\sum_{ t \in T^{res} \cap T^{s},V,I,O } \textbf{FI}_{r, p, s, d, i, t, v, o} \right] \cdot (1 + PRM_r)\\ + &- \left.\sum_{ t \in T^{res} \cap T^{s},V,I,O } \textbf{FI}_{r, p, s, d, i, t, v, o} + \right] + \cdot (1 + PRM_r)\\ \\ - &\qquad\qquad\forall \{r, p, s, d\} \in \Theta_{\text{ReserveMargin}} \text{and} \forall r_i \in R + &\qquad\qquad\forall \{r, p, s, d\} \in \Theta_{\text{ReserveMargin}} \text{and} \forall + r_i \in R """ if (not model.tech_reserve) or ( (r, p) not in model.process_reserve_periods @@ -255,7 +262,10 @@ def reserve_margin_constraint( case 'dynamic': available = reserve_margin_dynamic(model, r, p, s, d) case _: - msg = f"Invalid reserve margin parameter '{model.reserve_margin_method.first()}'. Check the config file." + msg = ( + f"Invalid reserve margin parameter '{model.reserve_margin_method.first()}'. " + 'Check the config file.' + ) logger.error(msg) raise ValueError(msg) diff --git a/temoa/components/storage.py b/temoa/components/storage.py index 974f28bad..bad3b2cd5 100644 --- a/temoa/components/storage.py +++ b/temoa/components/storage.py @@ -188,7 +188,8 @@ def seasonal_storage_energy_constraint( s_seq_next: Season = model.time_next_sequential[p, s_seq] s_next: Season = model.sequential_to_season[p, s_seq_next] - # Flows and StorageLevel are normalised to the number of days in the non-sequential season, so must + # Flows and StorageLevel are normalised to the number of days in the non-sequential season, + # so must # be adjusted to the number of days in the sequential season days_adjust = value(model.time_season_sequential[p, s_seq, s]) / ( value(model.segment_fraction_per_season[p, s]) * value(model.days_per_period) @@ -335,13 +336,15 @@ def seasonal_storage_energy_upper_bound_constraint( * (value(model.storage_duration[r, t]) / (24 * value(model.days_per_period))) ) - # Flows and StorageLevel are normalised to the number of days in the non-sequential season, so must + # Flows and StorageLevel are normalised to the number of days in the non-sequential season, + # so must # be adjusted to the number of days in the sequential season days_adjust = value(model.time_season_sequential[p, s_seq, s]) / ( value(model.segment_fraction_per_season[p, s]) * value(model.days_per_period) ) - # v_storage_level tracks the running cumulative delta in the non-sequential season, so must be adjusted + # v_storage_level tracks the running cumulative delta in the non-sequential season, + # so must be adjusted # to the size of the sequential season running_day_delta = model.v_storage_level[r, p, s, d, t, v] * days_adjust diff --git a/temoa/components/technology.py b/temoa/components/technology.py index af51ad1c4..49c16c4fc 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -78,7 +78,8 @@ def get_default_survival( def get_default_process_lifetime(model: TemoaModel, r: Region, t: Technology, v: Vintage) -> int: """ - This initializer used to initialize the lifetime_process parameter from lifetime_tech where needed + This initializer used to initialize the lifetime_process parameter from lifetime_tech where + needed Priority: 1. Specified in lifetime_process data (provided as a fill and would not call this function) @@ -272,7 +273,8 @@ def create_survival_curve(model: TemoaModel) -> None: lsc_prev = value(model.lifetime_survival_curve[r, p_prev, t, v]) if lsc - lsc_prev > 0.0001: msg = ( - f'lifetime_survival_curve fraction increases going forward in time from {(r, p_prev, t, v)} to {(r, p, t, v)}. ' + f'lifetime_survival_curve fraction increases going forward in time from ' + f'{(r, p_prev, t, v)} to {(r, p, t, v)}. ' 'This is not allowed.' ) logger.error(msg) @@ -297,17 +299,19 @@ def create_survival_curve(model: TemoaModel) -> None: # Make sure the lifetime for this process aligns with survival curve end if value(model.lifetime_process[r, t, v]) < p - v: msg = ( - f'The lifetime_process parameter for process ({r, t, v}) with survival curve ' - f'does not extend beyond the end of that survival curve in {p}. To agree with ' + f'The lifetime_process parameter for process ({r, t, v}) with survival ' + f'curve does not extend beyond the end of that survival curve in {p}. To ' + 'agree with ' f'the survival curve, set lifetime_process[{r, t, v}] >= {p - v}' ) logger.error(msg) raise ValueError(msg) elif value(model.lifetime_process[r, t, v]) != p - v: msg = ( - f'The lifetime_process parameter for process ({r, t, v}) with survival curve ' - f'does match the end of that survival curve in {p}. This will waste compute. ' - 'To agree with the survival curve and suppress this warning, set ' + f'The lifetime_process parameter for process ({r, t, v}) with survival ' + 'curve ' + f'does match the end of that survival curve in {p}. This will waste ' + 'compute. To agree with the survival curve and suppress this warning, set ' f'lifetime_process[{r, t, v}] = {p - v}' ) logger.warning(msg) @@ -328,9 +332,10 @@ def create_survival_curve(model: TemoaModel) -> None: if rtv_interpolated: logger.info( - 'For the purposes of investment cost accounting, lifetime_survival_curve must be defined ' - 'for each individual year. Gaps between defined years will be filled by linear interpolation. ' - 'Otherwise, these individual years can be defined manually. Interpolated processes: %s', + 'For the purposes of investment cost accounting, lifetime_survival_curve must be ' + 'defined for each individual year. Gaps between defined years will be filled by ' + 'linear interpolation. Otherwise, these individual years can be defined manually. ' + 'Interpolated processes: %s', list(rtv_interpolated), ) @@ -426,8 +431,8 @@ def check_efficiency_variable(model: TemoaModel) -> None: model.is_efficiency_variable[r, p, i, t, v, o] = True if count < num_seg: logger.info( - 'Some but not all efficiency_variable values were set (%i out of a possible %i) for: %s' - ' Missing values will default to value set in efficiency table.', + 'Some but not all efficiency_variable values were set (%i out of a possible ' + '%i) for: %s Missing values will default to value set in efficiency table.', count, num_seg, (r, p, i, t, v, o), diff --git a/temoa/components/time.py b/temoa/components/time.py index c8fd23ffb..6df7e5239 100644 --- a/temoa/components/time.py +++ b/temoa/components/time.py @@ -102,9 +102,11 @@ def validate_segment_fraction(model: TemoaModel) -> None: extra: set[tuple[int, str, str]] = keys.difference(expected_keys) missing: set[tuple[int, str, str]] = expected_keys.difference(keys) msg: str = ( - f'time_segment_fraction elements for period {p} do not match time_season and time_of_day.' + f'time_segment_fraction elements for period {p} do not match time_season and ' + 'time_of_day.' f'\n\nIndices missing from time_segment_fraction:\n{missing}' - f'\n\nIndices in time_segment_fraction missing from time_season/time_of_day:\n{extra}' + f'\n\nIndices in time_segment_fraction missing from time_season/time_of_day:\n' + f'{extra}' ) logger.error(msg) raise ValueError(msg) @@ -162,8 +164,10 @@ def validate_time_manual(model: TemoaModel) -> None: if missing_psd or missing_psd_next: msg: str = ( 'Failed to build state sequence. ' - f'\nThese states from time_segment_fraction were not given a next state:\n{missing_psd}\n' - f'\nThese states from time_segment_fraction do not follow any state:\n{missing_psd_next}' + f'\nThese states from time_segment_fraction were not given a next state:\n' + f'{missing_psd}\n' + f'\nThese states from time_segment_fraction do not follow any state:\n' + f'{missing_psd_next}' ) logger.error(msg) raise ValueError(msg) @@ -290,7 +294,10 @@ def create_time_sequence(model: TemoaModel) -> None: model.time_next[p, s, d] = s_next, d_next case _: # This should have been caught in hybrid_loader - msg = f"Invalid time sequencing parameter loaded '{model.time_sequencing.first()}'. Likely code error." + msg = ( + f"Invalid time sequencing parameter loaded '{model.time_sequencing.first()}'. " + 'Likely code error.' + ) logger.error(msg) raise ValueError(msg) @@ -342,9 +349,11 @@ def create_time_season_to_sequential(model: TemoaModel) -> None: else: msg = ( - f'No data in time_season_sequential but time_sequencing parameter set to {model.time_sequencing.first()} ' - 'and inter-season features used. time_season_sequential must be filled for this type of time ' - 'sequencing if seasonal storage or inter-season constraints like ramp_up/ramp_down are used. Check ' + f'No data in time_season_sequential but time_sequencing parameter set to ' + f'{model.time_sequencing.first()} and inter-season features used. ' + 'time_season_sequential must be filled for this type of time sequencing if ' + 'seasonal storage or inter-season constraints like ramp_up/ramp_down are used. ' + 'Check ' 'the config file.' ) logger.error(msg) @@ -360,8 +369,9 @@ def create_time_season_to_sequential(model: TemoaModel) -> None: and abs(num_days - prev_n) >= 0.001 ): msg = ( - 'time_sequencing set to consecutive_days but two consecutive seasons do not represent the same ' - f'number of days. This discontinuity will lead to bad model behaviour: {p, s}, days: {num_days}. ' + 'time_sequencing set to consecutive_days but two consecutive seasons do not ' + 'represent the same number of days. This discontinuity will lead to bad model ' + f'behaviour: {p, s}, days: {num_days}. ' f'Previous number of days: {prev_n}. Check the config file for more information.' ) logger.error(msg) From fbd82b4cb304efd619b5990e2205ab021c7b29c3 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 22 Nov 2025 17:58:11 -0500 Subject: [PATCH 361/587] fixing E501 line too long linting issues in core --- temoa/core/config.py | 26 +++++++++++++++++------ temoa/core/model.py | 49 +++++++++++++++++++++++++++++--------------- 2 files changed, 53 insertions(+), 22 deletions(-) diff --git a/temoa/core/config.py b/temoa/core/config.py index 3ad005fac..c06d5439a 100644 --- a/temoa/core/config.py +++ b/temoa/core/config.py @@ -15,10 +15,19 @@ class SolverNotAvailableError(Exception): # Dictionary to store installation documentation links for common solvers SOLVER_DOC_LINKS = { - 'cbc': 'https://github.com/coin-or/Cbc#download (refer to temoa documentation for specific OS steps)', + 'cbc': ( + 'https://github.com/coin-or/Cbc#download ' + '(refer to temoa documentation for specific OS steps)' + ), 'gurobi': 'https://www.gurobi.com/downloads/ (requires license and installation)', - 'cplex': 'https://www.ibm.com/products/ilog-cplex-optimization-studio (requires license and installation)', - 'highs': 'https://ergo-code.github.io/HiGHS/dev/installation/ (refer to documentation for specific OS steps)', + 'cplex': ( + 'https://www.ibm.com/products/ilog-cplex-optimization-studio ' + '(requires license and installation)' + ), + 'highs': ( + 'https://ergo-code.github.io/HiGHS/dev/installation/ ' + '(refer to documentation for specific OS steps)' + ), 'glpk': 'https://www.gnu.org/software/glpk/', } @@ -164,13 +173,18 @@ def build_config(config_file: Path, output_path: Path, silent: bool = False) -> solver_executable = shutil.which(data['solver_name']) if solver_executable is None: error_message = ( - f"The specified solver '{data['solver_name']}' was not found in your system's PATH.\n" + f"The specified solver '{data['solver_name']}' was not found in your system's " + 'PATH.\n' 'Please ensure the solver is installed and its executable is accessible.\n' ) if data['solver_name'].lower() in SOLVER_DOC_LINKS: - error_message += f'For installation instructions, refer to: {SOLVER_DOC_LINKS[data["solver_name"].lower()]}\n' + link = SOLVER_DOC_LINKS[data['solver_name'].lower()] + error_message += f'For installation instructions, refer to: {link}\n' else: - error_message += "Refer to the solver's official documentation for installation instructions." + error_message += ( + "Refer to the solver's official documentation for " + 'installation instructions.' + ) raise SolverNotAvailableError(error_message) else: logger.info('Using solver: %s found at %s', data['solver_name'], solver_executable) diff --git a/temoa/core/model.py b/temoa/core/model.py index 2c7a0b55e..1f8fc9b14 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -122,7 +122,9 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.active_activity_rptv: t.ActiveActivitySet = set() self.storage_level_indices_rpsdtv: t.StorageLevelIndicesSet = set() self.seasonal_storage_level_indices_rpstv: t.SeasonalStorageLevelIndicesSet = set() - """currently available (within lifespan) (r, p, t, v) tuples (from model.process_vintages)""" + """ + currently available (within lifespan) (r, p, t, v) tuples (from model.process_vintages) + """ self.active_regions_for_tech: t.ActiveRegionsForTechDict = {} """currently available regions by period and tech {(p, t) : r}""" @@ -136,18 +138,24 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.commodity_balance_rpc: t.CommodityBalancedSet = ( set() ) # Set of valid region-period-commodity indices to balance - self.commodity_down_stream_process: t.CommodityStreamProcessDict = {} # The downstream process of a commodity during a period - self.commodity_up_stream_process: t.CommodityStreamProcessDict = {} # The upstream process of a commodity during a period - self.capacity_consumption_techs: t.CapacityConsumptionTechsDict = {} # New capacity consuming a commodity during a period [r,p,c] -> t - self.retirement_production_processes: t.RetirementProductionProcessesDict = {} # Retired capacity producing a commodity during a period [r,p,c] -> t,v + # The downstream process of a commodity during a period + self.commodity_down_stream_process: t.CommodityStreamProcessDict = {} + # The upstream process of a commodity during a period + self.commodity_up_stream_process: t.CommodityStreamProcessDict = {} + # New capacity consuming a commodity during a period [r,p,c] -> t + self.capacity_consumption_techs: t.CapacityConsumptionTechsDict = {} + # Retired capacity producing a commodity during a period [r,p,c] -> t,v + self.retirement_production_processes: t.RetirementProductionProcessesDict = {} self.process_inputs_by_output: t.ProcessInputsByOutputDict = {} self.process_outputs_by_input: t.ProcessOutputsByInputDict = {} self.process_techs: t.ProcessTechsDict = {} self.process_reserve_periods: t.ProcessReservePeriodsDict = {} self.process_periods: t.ProcessPeriodsDict = {} # {(r, t, v): set(p)} - self.retirement_periods: t.RetirementPeriodsDict = {} # {(r, t, v): set(p)} periods in which a process can economically or naturally retire + # {(r, t, v): set(p)} periods in which a process can economically or naturally retire + self.retirement_periods: t.RetirementPeriodsDict = {} self.process_vintages: t.ProcessVintagesDict = {} - self.survival_curve_periods: t.SurvivalCurvePeriodsDict = {} # {(r, t, v): set(p)} periods for which the process has a defined survival fraction + # {(r, t, v): set(p)} periods for which the process has a defined survival fraction + self.survival_curve_periods: t.SurvivalCurvePeriodsDict = {} """current available (within lifespan) vintages {(r, p, t) : set(v)}""" self.baseload_vintages: t.BaseloadVintagesDict = {} @@ -164,19 +172,26 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.import_regions: t.ImportRegionsDict = {} # These establish time sequencing - self.time_next: t.TimeNextDict = {} # {(p, s, d): (s_next, d_next)} sequence of following time slices - self.time_next_sequential: t.TimeNextSequentialDict = {} # {(p, s_seq): (s_seq_next)} next virtual storage season - self.sequential_to_season: t.SequentialToSeasonDict = {} # {(p, s_seq): (s)} season matching this virtual storage season + # {(p, s, d): (s_next, d_next)} sequence of following time slices + self.time_next: t.TimeNextDict = {} + # {(p, s_seq): (s_seq_next)} next virtual storage season + self.time_next_sequential: t.TimeNextSequentialDict = {} + # {(p, s_seq): (s)} season matching this virtual storage season + self.sequential_to_season: t.SequentialToSeasonDict = {} ################################################ # Switching Sets # # (to avoid slow searches in initialisation) # ################################################ - self.is_efficiency_variable: t.EfficiencyVariableDict = {} # {(r, p, i, t, v, o): bool} which efficiencies have variable indexing - self.is_capacity_factor_process: t.CapacityFactorProcessDict = {} # {(r, p, t, v): bool} which capacity factors have have period-vintage indexing - self.is_seasonal_storage: t.SeasonalStorageDict = {} # {t: bool} whether a storage tech is seasonal storage - self.is_survival_curve_process: t.SurvivalCurveProcessDict = {} # {(r, t, v): bool} whether a process uses survival curves. + # {(r, p, i, t, v, o): bool} which efficiencies have variable indexing + self.is_efficiency_variable: t.EfficiencyVariableDict = {} + # {(r, p, t, v): bool} which capacity factors have have period-vintage indexing + self.is_capacity_factor_process: t.CapacityFactorProcessDict = {} + # {t: bool} whether a storage tech is seasonal storage + self.is_seasonal_storage: t.SeasonalStorageDict = {} + # {(r, t, v): bool} whether a process uses survival curves. + self.is_survival_curve_process: t.SurvivalCurveProcessDict = {} ################################################ # Model Sets # @@ -510,9 +525,11 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.time_of_day, self.tech_with_capacity, self.vintage_all, - # validate=validate_capacity_factor_process, # opting for a quicker validation, just 0->1 + # validate=validate_capacity_factor_process, + # opting for a quicker validation, just 0->1 validate=validate_0to1, - default=capacity.get_default_capacity_factor, # slow but only called if a value is missing + # slow but only called if a value is missing + default=capacity.get_default_capacity_factor, ) self.capacity_constraint_rpsdtv = Set( From 0bc1aa783d344165b37d1acc0c14ea1073fc9dd9 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 22 Nov 2025 17:58:32 -0500 Subject: [PATCH 362/587] fixing E501 line too long linting issues in data io and processing --- temoa/data_io/hybrid_loader.py | 40 +++++++++++++++------- temoa/data_processing/db_query.py | 3 +- temoa/data_processing/make_output_plots.py | 2 +- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index 672bfc9e3..de0c6c733 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -206,7 +206,8 @@ def create_data_dict(self, myopic_index: MyopicIndex | None = None) -> dict[str, (myopic_index.base_year,), ).fetchall() raw_future = cur.execute( - 'SELECT period FROM time_period WHERE flag = "f" AND period >= ? AND period <= ? ORDER BY sequence', + 'SELECT period FROM time_period WHERE flag = "f" AND period >= ? AND period <= ? ' + 'ORDER BY sequence', (myopic_index.base_year, myopic_index.last_year), ).fetchall() else: @@ -319,7 +320,8 @@ def _fetch_data( except OperationalError as e: if not item.is_table_required: logger.info( - 'Could not load optional component %s, likely due to older schema. Skipping. Error: %s', + 'Could not load optional component %s, likely due to older schema. Skipping. ' + 'Error: %s', item.component.name, e, ) @@ -378,7 +380,8 @@ def _load_component_data( if len(values[0]) == 1: if len(values) > 1: logger.warning( - "Component '%s' appears to be a scalar Param but has multiple values. Using only the first value.", + "Component '%s' appears to be a scalar Param but has multiple values. " + 'Using only the first value.', component.name, ) data[component.name] = {None: values[0][0]} @@ -443,7 +446,8 @@ def _build_efficiency_dataset( ).fetchall() else: contents = cur.execute( - 'SELECT region, input_comm, tech, vintage, output_comm, efficiency, NULL FROM main.efficiency' + 'SELECT region, input_comm, tech, vintage, output_comm, efficiency, NULL FROM ' + 'main.efficiency' ).fetchall() if use_raw_data: @@ -628,7 +632,8 @@ def _load_existing_capacity( ).fetchone() prev_period = prev_period_res[0] if prev_period_res else -1 rows_to_load = cur.execute( - 'SELECT region, tech, vintage, capacity FROM output_built_capacity WHERE vintage <= ? AND scenario = ? ' + 'SELECT region, tech, vintage, capacity FROM output_built_capacity WHERE ' + 'vintage <= ? AND scenario = ? ' 'UNION SELECT region, tech, vintage, capacity FROM existing_capacity', (prev_period, self.config.scenario), ).fetchall() @@ -696,7 +701,8 @@ def _load_global_discount_rate( data[model.global_discount_rate.name] = {None: cast('float', filtered_data[0][0])} else: raise ValueError( - "Missing required parameter: 'global_discount_rate' not found in MetaDataReal table." + "Missing required parameter: 'global_discount_rate' not found in MetaDataReal " + 'table.' ) def _load_default_loan_rate( @@ -737,7 +743,8 @@ def _load_linked_techs( p_tech, d_tech = entry[1], entry[3] if p_tech in valid_techs or d_tech in valid_techs: msg = ( - 'A LinkedTech entry %s was invalidated, but one of its component technologies ' + 'A LinkedTech entry %s was invalidated, but one of its component ' + 'technologies ' 'remains viable. This could lead to incorrect model behavior.' ) logger.error(msg, entry) @@ -786,7 +793,8 @@ def _load_rps_requirement( self._load_component_data(data, model.renewable_portfolio_standard, filtered_data) if filtered_data: logger.warning( - 'The renewable_portfolio_standard constraint is deprecated. Use limit_activity_share instead. ' + 'The renewable_portfolio_standard constraint is deprecated. Use ' + 'limit_activity_share instead. ' 'The constraint has been applied but this feature may be removed in the future.' ) @@ -894,16 +902,24 @@ def load_param_idx_sets(self, data: dict[str, object]) -> dict[str, object]: model.demand.name: model.demand_constraint_rpc.name, model.limit_emission.name: model.limit_emission_constraint_rpe.name, model.limit_activity.name: model.limit_activity_constraint_rpt.name, - model.limit_seasonal_capacity_factor.name: model.limit_seasonal_capacity_factor_constraint_rpst.name, + model.limit_seasonal_capacity_factor.name: ( + model.limit_seasonal_capacity_factor_constraint_rpst.name + ), model.limit_activity_share.name: model.limit_activity_share_constraint_rpgg.name, - model.limit_annual_capacity_factor.name: model.limit_annual_capacity_factor_constraint_rpto.name, + model.limit_annual_capacity_factor.name: ( + model.limit_annual_capacity_factor_constraint_rpto.name + ), model.limit_capacity.name: model.limit_capacity_constraint_rpt.name, model.limit_capacity_share.name: model.limit_capacity_share_constraint_rpgg.name, model.limit_new_capacity.name: model.limit_new_capacity_constraint_rpt.name, - model.limit_new_capacity_share.name: model.limit_new_capacity_share_constraint_rpgg.name, + model.limit_new_capacity_share.name: ( + model.limit_new_capacity_share_constraint_rpgg.name + ), model.limit_resource.name: model.limit_resource_constraint_rt.name, model.limit_storage_fraction.name: model.limit_storage_fraction_constraint_rpsdtv.name, - model.renewable_portfolio_standard.name: model.renewable_portfolio_standard_constraint_rpg.name, + model.renewable_portfolio_standard.name: ( + model.renewable_portfolio_standard_constraint_rpg.name + ), } res: dict[str, object] = {} diff --git a/temoa/data_processing/db_query.py b/temoa/data_processing/db_query.py index 7db428b0c..2a001daad 100644 --- a/temoa/data_processing/db_query.py +++ b/temoa/data_processing/db_query.py @@ -1,4 +1,5 @@ -# Dev Note: This module is unused and appears to be just a query executor. Retained for now. 12JUN2024 +# Dev Note: This module is unused and appears to be just a query executor. Retained for now. +# 12JUN2024 """ A command-line utility for sending a direct SQL query to a Temoa database. diff --git a/temoa/data_processing/make_output_plots.py b/temoa/data_processing/make_output_plots.py index 810d75338..a48ebc18c 100644 --- a/temoa/data_processing/make_output_plots.py +++ b/temoa/data_processing/make_output_plots.py @@ -233,7 +233,7 @@ def generate_plot_for_emissions( self.make_line_plot(output_values.copy(), 'Emissions', title) return relative_path - # --------------------------- Plot Generation related functions -------------------------------------- + # --------------------------- Plot Generation related functions ------------------------------ def get_cmap(self, size: int) -> ColorMapFunc: """Returns a function that maps an index to a distinct RGB color.""" From 231d53722c64d24a768d75211651cd185fa902e6 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 22 Nov 2025 17:58:56 -0500 Subject: [PATCH 363/587] fixing E501 line too long linting issues in utilities --- temoa/utilities/database_util.py | 21 +++++++++++++---- temoa/utilities/db_migration_to_v3.py | 18 ++++++++------ temoa/utilities/db_migration_v3_to_v3_1.py | 26 ++++++++++++++++----- temoa/utilities/graphviz_generator.py | 5 +++- temoa/utilities/sql_migration_v3_1_to_v4.py | 14 +++++++---- temoa/utilities/visualizer.py | 3 ++- 6 files changed, 63 insertions(+), 24 deletions(-) diff --git a/temoa/utilities/database_util.py b/temoa/utilities/database_util.py index 68baf7323..b49002dec 100644 --- a/temoa/utilities/database_util.py +++ b/temoa/utilities/database_util.py @@ -138,7 +138,10 @@ def get_commodities_and_tech( inp_comm_sql = 'NOT NULL' inp_tech_sql = 'NOT NULL' - where_clause = f'(input_comm IS {inp_comm_sql} OR output_comm IS {inp_comm_sql} OR tech IS {inp_tech_sql})' + where_clause = ( + f'(input_comm IS {inp_comm_sql} OR output_comm IS {inp_comm_sql} OR tech IS ' + f'{inp_tech_sql})' + ) if region: where_clause = f"region LIKE '%{region}%' AND {where_clause}" @@ -194,7 +197,10 @@ def get_capacity_for_tech_and_period( raise ValueError('A scenario must be set for output-related queries') columns = ['tech', 'period', 'SUM(capacity)', 'region'] - query = f"SELECT {', '.join(columns)} FROM output_net_capacity WHERE scenario IS '{self.scenario}'" + query = ( + f'SELECT {", ".join(columns)} FROM output_net_capacity WHERE scenario IS ' + f"'{self.scenario}'" + ) if region: query += f" AND region LIKE '{region}%'" @@ -242,7 +248,10 @@ def get_output_flow_for_period( columns.append('output_comm') columns.append('tech') - query = f"SELECT DISTINCT {', '.join(columns)}, SUM(flow) AS flow FROM {table} WHERE scenario IS '{self.scenario}'" + query = ( + f'SELECT DISTINCT {", ".join(columns)}, SUM(flow) AS flow FROM {table} WHERE ' + f"scenario IS '{self.scenario}'" + ) if region: query += f" AND region LIKE '{region}%'" @@ -297,12 +306,14 @@ def get_commodity_wise_input_and_output_flow( SUM(OFO.vflow_out) AS vflow_out, OC.capacity FROM ( - SELECT region, scenario, period, input_comm, tech, vintage, output_comm, SUM(flow) AS vflow_in + SELECT region, scenario, period, input_comm, tech, vintage, output_comm, + SUM(flow) AS vflow_in FROM output_flow_in GROUP BY region, scenario, period, input_comm, tech, vintage, output_comm ) AS OF INNER JOIN ( - SELECT region, scenario, period, input_comm, tech, vintage, output_comm, SUM(flow) AS vflow_out + SELECT region, scenario, period, input_comm, tech, vintage, output_comm, + SUM(flow) AS vflow_out FROM output_flow_out GROUP BY region, scenario, period, input_comm, tech, vintage, output_comm ) AS OFO ON diff --git a/temoa/utilities/db_migration_to_v3.py b/temoa/utilities/db_migration_to_v3.py index 13996598f..32d49b245 100644 --- a/temoa/utilities/db_migration_to_v3.py +++ b/temoa/utilities/db_migration_to_v3.py @@ -171,11 +171,13 @@ # quick check for expected number of fields... if len(data[0]) != 5: print( - f'\nWARNING: unexpected number of fields in table: {old_name}. Was expecting 5: region, period, group, value, notes' + f'\nWARNING: unexpected number of fields in table: {old_name}. Was expecting 5: ' + 'region, period, group, value, notes' ) print( - '\nIt is possible that the older table you have was not indexed by REGION, which might be common' - 'for old datasets. If so, that cannot be moved automatically. You will need to do it manually.' + '\nIt is possible that the older table you have was not indexed by REGION, which might ' + 'be common for old datasets. If so, that cannot be moved automatically. You will ' + 'need to do it manually.' ) print(f'\n *** IGNORING TABLE: {old_name} in transfer!! ***\n') continue @@ -211,7 +213,8 @@ # More complicated stuff.... fixing the groups print( - '\n --- comparing RPS groups to a common set to see if they can be combined into 1 (except global) ---' + '\n --- comparing RPS groups to a common set to see if they can be combined into 1 ' + '(except global) ---' ) groups: dict[str, set[str]] = defaultdict(set) @@ -239,7 +242,8 @@ techs_common &= not common ^ techs if not techs_common: print( - 'combining RPS techs failed. Some regions are not same. Must be done manually.' + 'combining RPS techs failed. Some regions are not same. Must be done ' + 'manually.' ) if techs_common: @@ -299,8 +303,8 @@ skip_tech_groups = True if not skip_tech_groups: # ------- FIX TABLES THAT USED TO USE tech_groups ----------- - # We'll do this by modifying the group names similar to above (smashing the region-name together to match - # the newly renamed groups + # We'll do this by modifying the group names similar to above (smashing the region-name + # together to match the newly renamed groups tables_using_groups = [ 'MaxActivityGroup', 'MaxActivityShare', diff --git a/temoa/utilities/db_migration_v3_to_v3_1.py b/temoa/utilities/db_migration_v3_to_v3_1.py index c7458de4d..e3d9729e7 100644 --- a/temoa/utilities/db_migration_v3_to_v3_1.py +++ b/temoa/utilities/db_migration_v3_to_v3_1.py @@ -68,7 +68,8 @@ def column_check(old_name: str, new_name: str) -> bool: missing = [c for c in new_columns if c not in old_columns and c not in ('period', 'notes')] if len(missing) > 0: msg = ( - f'Columns of {new_name} in the new database missing from {old_name} in old database. Try adding or renaming the column in the old database:' + f'Columns of {new_name} in the new database missing from {old_name} in old database. ' + 'Try adding or renaming the column in the old database:' f'\n{missing}\n' ) print(msg) @@ -182,7 +183,9 @@ def column_check(old_name: str, new_name: str) -> bool: print('No data for: ' + old_name) continue - new_cols: list[str] = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] + new_cols: list[str] = [ + c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall() + ] op_index = new_cols.index('operator') data = [(*row[0:op_index], operator, *row[op_index:len(new_cols)-1]) for row in data] @@ -291,7 +294,8 @@ def column_check(old_name: str, new_name: str) -> bool: v <= p < v+lifetime_process[r, t, v] for v in [ t[0] for t in con_old.execute( - f'SELECT vintage FROM Efficiency WHERE region == "{r}" AND tech == "{t}"' + f'SELECT vintage FROM Efficiency WHERE region == "{r}" AND ' + f'tech == "{t}"' ).fetchall() ] ) @@ -342,7 +346,9 @@ def column_check(old_name: str, new_name: str) -> bool: "WHERE (region, period, demand_name) " "NOT IN (SELECT region, period, commodity FROM Demand)" ) - print(f"{n_del} extraneous rows removed from DemandSpecificDistribution after adding period index") + print( + f"{n_del} extraneous rows removed from DemandSpecificDistribution after adding period index" + ) # TimeSeason unique seasons to SeasonLabel con_new.execute("INSERT OR REPLACE INTO SeasonLabel(season) SELECT DISTINCT season FROM TimeSeason") @@ -363,7 +369,12 @@ def column_check(old_name: str, new_name: str) -> bool: else: new_data = [] for row in data: - vints = [v[0] for v in con_old.execute(f'SELECT vintage FROM Efficiency WHERE region=="{row[0]}" AND tech="{row[1]}"').fetchall()] + vints = [ + v[0] + for v in con_old.execute( + f'SELECT vintage FROM Efficiency WHERE region=="{row[0]}" AND tech="{row[1]}"' + ).fetchall() + ] for v in vints: new_data.append((row[0], row[1], v, row[2], row[3])) query = 'INSERT OR REPLACE INTO LoanLifetimeProcess VALUES (?,?,?,?,?)' @@ -372,7 +383,10 @@ def column_check(old_name: str, new_name: str) -> bool: # Warn about incompatible changes -print('\n --- The following transfers were impossible due to incompatible changes. Transfer manually. ---') +print( + '\n --- The following transfers were impossible due to incompatible changes. Transfer ' + 'manually. ---' +) for old_name, new_name in no_transfer.items(): print(f'{old_name} to {new_name}') diff --git a/temoa/utilities/graphviz_generator.py b/temoa/utilities/graphviz_generator.py index eb8de5b8f..07a0568b4 100644 --- a/temoa/utilities/graphviz_generator.py +++ b/temoa/utilities/graphviz_generator.py @@ -261,7 +261,10 @@ def create_main_results_diagram( self.__log__('CreateMainResultsDiagram: database fetched successfully') - tech_attr_fmt = 'label="%s\\nCapacity: %.2f", href="#", onclick="loadNextGraphvizGraph(\'results\', \'%s\', \'%s\')"' + tech_attr_fmt = ( + 'label="%s\\nCapacity: %.2f", href="#", ' + "onclick=\"loadNextGraphvizGraph('results', '%s', '%s')\"" + ) commodity_fmt = "href=\"#\", onclick=\"loadNextGraphvizGraph('results', '%s', '%s')\"" flow_fmt = 'label="%.2f"' epsilon = 0.005 diff --git a/temoa/utilities/sql_migration_v3_1_to_v4.py b/temoa/utilities/sql_migration_v3_1_to_v4.py index f1d2dd838..817562454 100644 --- a/temoa/utilities/sql_migration_v3_1_to_v4.py +++ b/temoa/utilities/sql_migration_v3_1_to_v4.py @@ -196,12 +196,14 @@ def migrate_dump_to_sqlite(args) -> None: if len(candidates) == 1: chosen_table = candidates[0] print( - f'NOTE: Mapped target {mapped_new_table_name} not found for {old_table_name}; using candidate {chosen_table}' + f'NOTE: Mapped target {mapped_new_table_name} not found for {old_table_name}; ' + f'using candidate {chosen_table}' ) mapped_new_table_name = chosen_table else: print( - f'SKIP: No target table for {old_table_name} -> {mapped_new_table_name} (candidates: {candidates})' + f'SKIP: No target table for {old_table_name} -> {mapped_new_table_name} ' + f'(candidates: {candidates})' ) continue @@ -232,7 +234,8 @@ def migrate_dump_to_sqlite(args) -> None: if not selectable_old_cols_for_query: if args.debug: print( - f'DEBUG: No common/mappable columns from {old_table_name} to {mapped_new_table_name}. Skipping data copy.' + f'DEBUG: No common/mappable columns from {old_table_name} to ' + f'{mapped_new_table_name}. Skipping data copy.' ) continue @@ -252,7 +255,10 @@ def migrate_dump_to_sqlite(args) -> None: continue placeholders = ','.join(['?'] * len(insert_target_cols_for_query)) - insert_query = f'INSERT OR REPLACE INTO {mapped_new_table_name} ({",".join(insert_target_cols_for_query)}) VALUES ({placeholders})' + insert_query = ( + f'INSERT OR REPLACE INTO {mapped_new_table_name} ' + f'({",".join(insert_target_cols_for_query)}) VALUES ({placeholders})' + ) con_new_in_memory.executemany(insert_query, filtered_rows_for_insert) rows_copied_this_table = len(filtered_rows_for_insert) diff --git a/temoa/utilities/visualizer.py b/temoa/utilities/visualizer.py index eba8846bd..9dc04369c 100644 --- a/temoa/utilities/visualizer.py +++ b/temoa/utilities/visualizer.py @@ -227,7 +227,8 @@ def nx_to_vis( js_template = (template_dir / 'graph_script.js').read_text(encoding='utf-8') except FileNotFoundError: logger.exception( - "Template files not found. Ensure the 'network_vis_templates' directory exists next to visualizer.py." + "Template files not found. Ensure the 'network_vis_templates' directory exists next to " + 'visualizer.py.' ) return None From 6c4c925f8a37d714bc23d9273f88e60806394061 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 22 Nov 2025 17:59:25 -0500 Subject: [PATCH 364/587] fixing E501 line too long linting issues in extensions --- temoa/extensions/breakeven/breakeven.py | 38 +++++++++----- temoa/extensions/get_comm_tech.py | 28 +++++++---- temoa/extensions/method_of_morris/morris.py | 10 ++-- .../method_of_morris/morris_evaluate.py | 7 +-- .../method_of_morris/morris_sequencer.py | 28 +++++++---- .../modeling_to_generate_alternatives/hull.py | 18 ++++--- .../mga_sequencer.py | 6 ++- .../tech_activity_vector_manager.py | 9 ++-- .../example_builds/scenario_maker.py | 18 ++++--- temoa/extensions/monte_carlo/mc_run.py | 20 +++++--- temoa/extensions/monte_carlo/mc_sequencer.py | 6 ++- temoa/extensions/monte_carlo/mc_worker.py | 7 +-- .../myopic/myopic_progress_mapper.py | 5 +- temoa/extensions/myopic/myopic_sequencer.py | 49 ++++++++++++------- .../single_vector_mga/sv_mga_sequencer.py | 14 ++++-- temoa/extensions/stochastics/VSS.py | 29 ++++++++--- 16 files changed, 192 insertions(+), 100 deletions(-) diff --git a/temoa/extensions/breakeven/breakeven.py b/temoa/extensions/breakeven/breakeven.py index 91a849bc9..c021899ed 100644 --- a/temoa/extensions/breakeven/breakeven.py +++ b/temoa/extensions/breakeven/breakeven.py @@ -244,7 +244,8 @@ def sensitivity(dat, techs): lrc = instance.lrc[instance.v_capacity[t, v]] urc = instance.urc[instance.v_capacity[t, v]] - # print("{:>s}\t{:>g}\t{:>.0f}\t{:>.0f}\t{:>.0f}\t{:>.3f}\t{:>.1f}\t{:>.1f}\t{:>.0f}\t{:>.0f}\t{:>.3f}".format() + # print("{:>s}\t{:>g}\t{:>.0f}\t{:>.0f}\t{:>.0f}\t{:>.3f}\t{:>.1f}\t{:>.1f}\t{:>.0f}\t" + # "{:>.0f}\t{:>.3f}".format() print( '{:>10s}\t{:>7g}\t{:>6.0f}\t{:>4.0f}\t{:>6.0f}\t{:>5.3f}\t{:>7.1f}\t{:>7.1f}\t{:>5.0f}\t{:>3.0f}\t{:>5.3f}'.format( t, @@ -423,16 +424,19 @@ def sensitivity_api(instance, techs, algorithm=None): ) ) - msg += '{:>10s}\t{:>7g}\t{:>6.0f}\t{:>4.0f}\t{:>6.0f}\t{:>5.3f}\t{:>7.1f}\t{:>5.0f}\t{:>5.3f}'.format( - t, - v, - clb_s[t, v], - coef_CAP[t, v], - cub_s[t, v], - scal_CAP[t, v], - bic_s[t][vintages.index(v)], - value(instance.cost_invest[t, v]), - cap_s[t][vintages.index(v)], + msg += ( + '{:>10s}\t{:>7g}\t{:>6.0f}\t{:>4.0f}\t{:>6.0f}\t{:>5.3f}\t{:>7.1f}\t{:>5.0f}\t' + '{:>5.3f}'.format( + t, + v, + clb_s[t, v], + coef_CAP[t, v], + cub_s[t, v], + scal_CAP[t, v], + bic_s[t][vintages.index(v)], + value(instance.cost_invest[t, v]), + cap_s[t][vintages.index(v)], + ) ) msg += '\n' @@ -1009,7 +1013,13 @@ def explore_Cost_marginal(dat): # for p in instance.time_optimize: # for s in instance.time_season: # for tod in instance.time_of_day: - # print(p, s, tod, instance.dual[instance.demand_constraint[p,s,tod,c]], instance.slack[instance.demand_constraint[p,s,tod,c]]) + # print( + # p, + # s, + # tod, + # instance.dual[instance.demand_constraint[p, s, tod, c]], + # instance.slack[instance.demand_constraint[p, s, tod, c]], + # ) def plot_breakeven(years, bic, ic): @@ -1109,4 +1119,6 @@ def return_range(bs): sen_range('ECOALIGCCS', 2020, scales, ['reference.dat']) # do_sensitivity_new() # do_sensitivity_old() - # explore_Cost_marginal(['/afs/unity.ncsu.edu/users/b/bli6/TEMOA_NC/sql20170417/results/R/NCreference.R.dat']) + # explore_Cost_marginal( + # ['/afs/unity.ncsu.edu/users/b/bli6/TEMOA_NC/sql20170417/results/R/NCreference.R.dat'] + # ) diff --git a/temoa/extensions/get_comm_tech.py b/temoa/extensions/get_comm_tech.py index d0329dab2..57e370ee9 100644 --- a/temoa/extensions/get_comm_tech.py +++ b/temoa/extensions/get_comm_tech.py @@ -19,7 +19,8 @@ def get_tperiods(inp_f): periods_set = set() con = sqlite3.connect(inp_f) - cur = con.cursor() # a database cursor is a control structure that enables traversal over the records in a database + cur = con.cursor() # a database cursor is a control structure that enables traversal over + # the records in a database con.text_factory = str # this ensures data is explored with the correct UTF-8 encoding print(inp_f) @@ -28,7 +29,9 @@ def get_tperiods(inp_f): for row in cur: x.append(row[0]) for y in x: - cur.execute("SELECT DISTINCT period FROM output_flow_out WHERE scenario is '" + str(y) + "'") + cur.execute( + "SELECT DISTINCT period FROM output_flow_out WHERE scenario is '" + str(y) + "'" + ) periods_list[y] = [] for per in cur: z = per[0] @@ -52,7 +55,8 @@ def get_scenario(inp_f): scene_set = set() con = sqlite3.connect(inp_f) - cur = con.cursor() # a database cursor is a control structure that enables traversal over the records in a database + cur = con.cursor() # a database cursor is a control structure that enables traversal over + # the records in a database con.text_factory = str # this ensures data is explored with the correct UTF-8 encoding print(inp_f) @@ -73,7 +77,8 @@ def get_comm(inp_f, db_dat): if not db_dat: con = sqlite3.connect(inp_f) - cur = con.cursor() # a database cursor is a control structure that enables traversal over the records in a database + cur = con.cursor() # a database cursor is a control structure that enables traversal over + # the records in a database con.text_factory = str # this ensures data is explored with the correct UTF-8 encoding print(inp_f) @@ -87,7 +92,8 @@ def get_comm(inp_f, db_dat): if not is_query_empty: cur.execute( - 'SELECT input_comm FROM output_flow_out UNION SELECT output_comm FROM output_flow_out' + 'SELECT input_comm FROM output_flow_out UNION SELECT output_comm FROM ' + 'output_flow_out' ) for row in cur: @@ -105,7 +111,8 @@ def get_comm(inp_f, db_dat): if eff_flag is False and re.search( r'^\s*param\s+efficiency\s*[:][=]', line, flags=re.I ): - # Search for the line param efficiency := (The script recognizes the commodities specified in this section) + # Search for the line param efficiency := (The script recognizes the + # commodities specified in this section) eff_flag = True elif eff_flag: line = re.sub('[#].*$', ' ', line) @@ -138,7 +145,8 @@ def get_tech(inp_f, db_dat): if not db_dat: con = sqlite3.connect(inp_f) - cur = con.cursor() # a database cursor is a control structure that enables traversal over the records in a database + cur = con.cursor() # a database cursor is a control structure that enables traversal over + # the records in a database con.text_factory = str # this ensures data is explored with the correct UTF-8 encoding print(inp_f) @@ -166,7 +174,8 @@ def get_tech(inp_f, db_dat): if eff_flag is False and re.search( r'^\s*param\s+efficiency\s*[:][=]', line, flags=re.I ): - # Search for the line param efficiency := (The script recognizes the commodities specified in this section) + # Search for the line param efficiency := (The script recognizes the + # commodities specified in this section) eff_flag = True elif eff_flag: line = re.sub('[#].*$', ' ', line) @@ -208,7 +217,8 @@ def is_db_overwritten(db_file, inp_dat_file): for elem in cur: is_db_empty = True # True for non-empty db file break - # This file could be schema with populated results from previous run. Or it could be a normal db file. + # This file could be schema with populated results from previous run. Or it could be a normal + # db file. if is_db_empty: cur.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='input_file';") does_input_file_table_exist = False diff --git a/temoa/extensions/method_of_morris/morris.py b/temoa/extensions/method_of_morris/morris.py index e8116ca34..51318c976 100644 --- a/temoa/extensions/method_of_morris/morris.py +++ b/temoa/extensions/method_of_morris/morris.py @@ -76,7 +76,8 @@ def evaluate(param_names, param_values, data: dict, k): param_names = {} cur = con.cursor() cur.execute( - 'SELECT region, period, tech, vintage, cost, MMAnalysis FROM cost_variable WHERE MMAnalysis is not NULL' + 'SELECT region, period, tech, vintage, cost, MMAnalysis FROM cost_variable WHERE ' + 'MMAnalysis is not NULL' ) output_query = cur.fetchall() g1 = len(output_query) @@ -97,7 +98,8 @@ def evaluate(param_names, param_values, data: dict, k): file.write('\n') cur.execute( - 'SELECT region, tech, vintage, cost, MMAnalysis FROM cost_invest WHERE MMAnalysis is not NULL' + 'SELECT region, tech, vintage, cost, MMAnalysis FROM cost_invest WHERE MMAnalysis is ' + 'not NULL' ) output_query = cur.fetchall() g2 = len(output_query) @@ -112,8 +114,10 @@ def evaluate(param_names, param_values, data: dict, k): file.write(' ') file.write(output_query[i][-1]) file.write('\n') + cur.execute( - 'SELECT DISTINCT region, input_comm, tech, vintage, output_comm, efficiency, MMAnalysis FROM efficiency WHERE MMAnalysis is not NULL' + 'SELECT DISTINCT region, input_comm, tech, vintage, output_comm, efficiency, ' + 'MMAnalysis FROM efficiency WHERE MMAnalysis is not NULL' ) output_query = cur.fetchall() g3 = len(output_query) diff --git a/temoa/extensions/method_of_morris/morris_evaluate.py b/temoa/extensions/method_of_morris/morris_evaluate.py index 0753b62e0..6a00d3bb3 100644 --- a/temoa/extensions/method_of_morris/morris_evaluate.py +++ b/temoa/extensions/method_of_morris/morris_evaluate.py @@ -24,8 +24,8 @@ https://westernspark.us Created on: 6/2/24 -This module contains the core "evaluation" function for Method Of Morris. It needs to be isolated (outside -of class) to enable parallelization. +This module contains the core "evaluation" function for Method Of Morris. It needs to be isolated +(outside of class) to enable parallelization. """ import logging @@ -122,7 +122,8 @@ def evaluate(param_info, mm_sample, data, i, config: TemoaConfig, log_queue, log Y_CumulativeCO2 = 0.0 elif len(output_query) > 1: raise RuntimeError( - 'Multiple outputs found in output_emissions table matching scenario name. Coding error.' + 'Multiple outputs found in output_emissions table matching scenario name. Coding ' + 'error.' ) else: Y_CumulativeCO2 = output_query[0][0] diff --git a/temoa/extensions/method_of_morris/morris_sequencer.py b/temoa/extensions/method_of_morris/morris_sequencer.py index c788028c8..6ddacf8fe 100644 --- a/temoa/extensions/method_of_morris/morris_sequencer.py +++ b/temoa/extensions/method_of_morris/morris_sequencer.py @@ -1,6 +1,6 @@ """ -An event sequencer to control the flow of a Method of Morris calculation. This code uses multiprocessing via -the joblib library +An event sequencer to control the flow of a Method of Morris calculation. This code uses +multiprocessing via the joblib library """ import csv @@ -51,7 +51,8 @@ def __init__(self, config: TemoaConfig): config.save_excel = False if config.price_check: logger.warning( - 'Price check is disabled during Morris runs. If you wish to check costs, run "CHECK" on model before MM' + 'Price check is disabled during Morris runs. If you wish to check costs, run ' + '"CHECK" on model before MM' ) config.price_check = False self.config = config @@ -105,7 +106,8 @@ def __init__(self, config: TemoaConfig): logger.warning( 'No value received for trajectories, using default: %d', self.trajectories ) - # Note: Problem size (in general) is (Groups + 1) * trajectories see the SALib Dox (which aren't super) + # Note: Problem size (in general) is (Groups + 1) * trajectories see the SALib Dox (which + # aren't super) seed = config.morris_inputs.get('seed') self.seed = seed if seed else None @@ -119,14 +121,17 @@ def __init__(self, config: TemoaConfig): logger.info('Morris number of cores: %d', self.num_cores) logger.info('Initialized Morris Sequencer') logger.info( - 'Currently, MM only logs ERROR level messages during model build, which is done repeatedly.' - ' If there are issues building the model, run Temoa in CHECK separately to get more detail on the model.' + 'Currently, MM only logs ERROR level messages during model build, which is done ' + 'repeatedly.' + ' If there are issues building the model, run Temoa in CHECK separately to get more ' + 'detail on the model.' ) def start(self): """ run the sequence of steps to do a MM analysis - 0. clear any prior results with this scenario name. this sequencer appends the DB, so start fresh + 0. clear any prior results with this scenario name. this sequencer appends the DB, so + start fresh 1. gather the parameters from items marked in the DB 2. build a data portal as a basis 3. use SALib to construct the sample @@ -139,7 +144,8 @@ def start(self): tw = TableWriter(config=self.config) tw.clear_scenario() - # 1. Gather param info from the DB and construct the param file, which will be basis of the 'problem' + # 1. Gather param info from the DB and construct the param file, which will be basis of + # the 'problem' param_names = self.gather_parameters() # 2. Use the loader to get raw access to the model's data (dictionary) @@ -270,7 +276,8 @@ def gather_parameters(self): with open(self.param_file, 'w') as f: v_idx = 4 # index of variable to perturb raw = cur.execute( - 'SELECT region, period, tech, vintage, cost, MMAnalysis FROM cost_variable WHERE MMAnalysis IS NOT NULL' + 'SELECT region, period, tech, vintage, cost, MMAnalysis FROM cost_variable WHERE ' + 'MMAnalysis IS NOT NULL' ).fetchall() g1 = len(raw) for i in range(0, len(raw)): @@ -289,7 +296,8 @@ def gather_parameters(self): v_idx = 3 raw = cur.execute( - 'SELECT region, tech, vintage, cost, MMAnalysis FROM cost_invest WHERE MMAnalysis IS NOT NULL' + 'SELECT region, tech, vintage, cost, MMAnalysis FROM cost_invest WHERE MMAnalysis ' + 'IS NOT NULL' ).fetchall() g2 = len(raw) for i in range(0, len(raw)): diff --git a/temoa/extensions/modeling_to_generate_alternatives/hull.py b/temoa/extensions/modeling_to_generate_alternatives/hull.py index d2eaa1ae4..888d7d663 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/hull.py +++ b/temoa/extensions/modeling_to_generate_alternatives/hull.py @@ -94,20 +94,22 @@ def update(self): return try: self.cv_hull = ConvexHull(self.all_points, qhull_options='Q12 QJ') - # Q12: Allow "wide" facets, which seems to happen with large disparity in scale in model - # QJ: option to "joggle" inputs if errors arise from singularities, etc. This seems to slow things down - # a moderate amount. - # Dev Note: After significant experiments with building new each time or allowing "incremental" - # additions to the hull, it appears more ROBUST to just rebuild. More frequent - # abnormal exits when trying to use incremental, and time difference is negligible - # for this few pts. + # Q12: Allow "wide" facets, which seems to happen with large disparity in scale in + # model + # QJ: option to "joggle" inputs if errors arise from singularities, etc. This seems + # to slow things down a moderate amount. + # Dev Note: After significant experiments with building new each time or allowing + # "incremental" additions to the hull, it appears more ROBUST to just + # rebuild. More frequent abnormal exits when trying to use incremental, and + # time difference is negligible for this few pts. self.good_points = self.cv_hull.points logger.info('Hull updated') self.volume = self.cv_hull.volume except scipy.spatial._qhull.QhullError as e: logger.error( 'Attempt at hull construction from basis vectors failed.' - '\nMay be non-recoverable. Possibly try a set of random vectors to initialize the Hull.' + '\nMay be non-recoverable. Possibly try a set of random vectors to initialize the ' + 'Hull.' ) logger.error(e) raise RuntimeError('Hull construction from vectors failed. See log file') diff --git a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py index 2b9e49a40..64821c521 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py +++ b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py @@ -34,7 +34,8 @@ logger = getLogger(__name__) solver_options_path = ( - resources.files('temoa.extensions.modeling_to_generate_alternatives') / 'MGA_solver_options.toml' + resources.files('temoa.extensions.modeling_to_generate_alternatives') + / 'MGA_solver_options.toml' ) @@ -335,7 +336,8 @@ def process_solve_results(self, instance: TemoaModel): # get the instance number from the model name, if provided if '-' not in instance.name: raise ValueError( - 'Instance name does not appear to contain a -idx value. The manager should be tagging/updating this' + 'Instance name does not appear to contain a -idx value. The manager should be ' + 'tagging/updating this' ) idx = int(instance.name.split('-')[-1]) if idx in self.seen_instance_indices: diff --git a/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py b/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py index 8e28f7a75..14426721f 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py +++ b/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py @@ -219,7 +219,8 @@ def group_members(self, group) -> list[str]: # noinspection PyTypeChecker def _make_basis_objective_vector(self, M: TemoaModel) -> Iterable[Expression] | None: - """generator for basis vectors which will be the coefficients in the obj expression in the basis solves""" + """generator for basis vectors which will be the coefficients in the obj expression in the + basis solves""" if self.basis_coefficients.empty(): return None try: @@ -262,7 +263,8 @@ def _next_objective_vector(self, M: TemoaModel) -> Expression | None: return quicksum(c * v for v, c in zip(obj_vars, coeffs, strict=False)) def var_vector(self, M: TemoaModel) -> list[Var]: - """Produce a properly sequenced array of variables from the current model for use in obj vector""" + """Produce a properly sequenced array of variables from the current model for use in obj + vector""" res = [] for cat in self.category_mapping: for tech in self.category_mapping[cat]: @@ -299,7 +301,8 @@ def input_vectors_available(self) -> int: @staticmethod def _generate_basis_coefficients(category_mapping: dict, technology_size: dict) -> Queue: - # Sequentially build the coefficient vector in the order of the categories and associated techs + # Sequentially build the coefficient vector in the order of the categories and associated + # techs q = Queue() for selected_cat in category_mapping: res = [] diff --git a/temoa/extensions/monte_carlo/example_builds/scenario_maker.py b/temoa/extensions/monte_carlo/example_builds/scenario_maker.py index 7f6217771..d89556daf 100644 --- a/temoa/extensions/monte_carlo/example_builds/scenario_maker.py +++ b/temoa/extensions/monte_carlo/example_builds/scenario_maker.py @@ -6,12 +6,14 @@ This scenario is based on Utopia with the following random variables: Cost of Imported Oil will have a normal distribution of *relative changes* applied in all periods -Residential Heating (RH) will have a similar distribution, with some negative correlation (seems logical that -there is some hidden price sensitivity, even though RH could be satisfied from electricity as well.) +Residential Heating (RH) will have a similar distribution, with some negative correlation (seems +logical that there is some hidden price sensitivity, even though RH could be satisfied from +electricity as well.) -Additionally, we will assume there is an independent 20% chance that the govt will subsidize new nuclear -power by: - (a) subsidizing the cost of any Investment Cost by 40%, in the out-years of 2000, 2010 (but not 1990) +Additionally, we will assume there is an independent 20% chance that the govt will subsidize new +nuclear power by: + (a) subsidizing the cost of any Investment Cost by 40%, in the out-years of 2000, 2010 (but not + 1990) (b) paying all fixed costs in the same years. Let's make a set of 500 runs and explore output @@ -48,13 +50,15 @@ f.write('run,param,index,mod,value,notes\n') for run_idx in range(num_runs): f.write( - f'{run_idx + 1},cost_variable,*|*|IMPOIL1|*,r,{price_devs[run_idx, 0]},oil relative change\n' + f'{run_idx + 1},cost_variable,*|*|IMPOIL1|*,r,{price_devs[run_idx, 0]},oil relative ' + 'change\n' ) f.write( f'{run_idx + 1},Demand,*|*|RH,r,{price_devs[run_idx, 1]},res heat relative change\n' ) f.write( - f'{run_idx + 1},cost_invest,*|E21|2000/2010,r,{nuc_dev[run_idx]},nuclear invest relative discount\n' + f'{run_idx + 1},cost_invest,*|E21|2000/2010,r,{nuc_dev[run_idx]},nuclear invest ' + 'relative discount\n' ) if nuc_dev[run_idx] < 0: f.write(f'{run_idx + 1},cost_fixed,*|*|E21|2000/2010,s,0.0,nuclear op cost covered\n') diff --git a/temoa/extensions/monte_carlo/mc_run.py b/temoa/extensions/monte_carlo/mc_run.py index a57ba3c9f..c52784e34 100644 --- a/temoa/extensions/monte_carlo/mc_run.py +++ b/temoa/extensions/monte_carlo/mc_run.py @@ -42,7 +42,10 @@ def __init__(self, param_name: str, indices: tuple, adjustment: str, value: floa self.value = value def __repr__(self): - return f'' + return ( + f'' + ) class TweakFactory: @@ -114,7 +117,8 @@ def row_parser(self, row_number: int, row: str) -> RowData: # check length if len(tokens) != 6: raise ValueError( - f'Incorrect number of tokens for row {row_number}. Did you omit notes / trailing comma for no notes or have a comma in your note?' + f'Error parsing line {row_number}. Did you omit notes / trailing comma for no ' + 'notes or have a comma in your note?' ) # convert the run number try: @@ -132,14 +136,16 @@ def row_parser(self, row_number: int, row: str) -> RowData: if rd.param_name not in self.val_data: # the param name should be a key value in the data dictionary raise ValueError( - f'param_name at index: {row_number} is either invalid or not represented in the input dataset' + f'param_name at index: {row_number} is either invalid or not represented in the ' + 'input dataset' ) if rd.adjustment not in {'r', 'a', 's'}: raise ValueError(f'adjustment at index {row_number} must be either r/a/s') # check for no "empty" indices in the index if '||' in rd.indices: raise ValueError( - f'indices at index {row_number} cannot contain empty marker: ||. Did you mean to put in wildcard "*"?' + f'indices at index {row_number} cannot contain empty marker: ||. Did you mean to ' + 'put in wildcard "*"?' ) return rd @@ -283,7 +289,8 @@ def element_locator(data_store: dict, param: str, target_index: tuple) -> list[t first_index = tuple(param_data.keys())[0] if len(target_index) != len(first_index): raise ValueError( - f'length of search index {target_index} for parameter {param} does not match data ex: {first_index}' + f'length of search index {target_index} for parameter {param} does not match data ' + f'ex: {first_index}' ) raw_indices = param_data.keys() matches = [ @@ -343,7 +350,8 @@ def run_generator(self) -> Generator[MCRun, None, None]: for tweak in failed_tweaks: logger.warning('Failed tweak: %s', tweak) - # skip the creation of the run if no tweaks were successful (it would just be the baseline run...) + # skip the creation of the run if no tweaks were successful (it would just be the + # baseline run...) if not good_tweaks: logger.warning(f'Aborting run: {run}. No good tweaks found') continue diff --git a/temoa/extensions/monte_carlo/mc_sequencer.py b/temoa/extensions/monte_carlo/mc_sequencer.py index e59851790..4cb0768cb 100644 --- a/temoa/extensions/monte_carlo/mc_sequencer.py +++ b/temoa/extensions/monte_carlo/mc_sequencer.py @@ -97,7 +97,8 @@ def start(self): num_workers = self.num_workers work_queue: Queue[tuple[str, DataPortal] | str] = Queue( num_workers + 1 - ) # must be able to hold all shutdowns at once (could be changed later to not lock on insertion...) + ) # must be able to hold all shutdowns at once (could be changed later to not lock on + # insertion...) result_queue: Queue[DataBrick | str] = Queue( num_workers + 1 ) # must be able to hold a shutdown signal from all workers at once! @@ -265,7 +266,8 @@ def process_solve_results(self, brick: DataBrick): # get the instance number from the model name, if provided if '-' not in brick.name: raise ValueError( - 'Instance name does not appear to contain a -idx value. The manager should be tagging/updating this' + 'Instance name does not appear to contain a -idx value. The manager should be ' + 'tagging/updating this' ) idx = int(brick.name.split('-')[-1]) if idx in self.seen_instance_indices: diff --git a/temoa/extensions/monte_carlo/mc_worker.py b/temoa/extensions/monte_carlo/mc_worker.py index e4f6d458f..622271ea7 100644 --- a/temoa/extensions/monte_carlo/mc_worker.py +++ b/temoa/extensions/monte_carlo/mc_worker.py @@ -28,8 +28,9 @@ dev note: This class is derived from the original Worker class in MGA extension, but is just different enough -that it is a separate class. In future, it may make sense to re-combine these. RN, this worker will -ingest DataPortal objects to make new models. The MGA will (in future) likely just take in new obj functions +that it is a separate class. In future, it may make sense to re-combine these. RN, this worker +will ingest DataPortal objects to make new models. The MGA will (in future) likely just take in +new obj functions """ @@ -61,7 +62,7 @@ def __init__( solver_log_path: Path | None = None, **kwargs, ): - super(MCWorker, self).__init__(daemon=True) + super().__init__(daemon=True) self.worker_number = MCWorker.worker_idx MCWorker.worker_idx += 1 self.dp_queue: Queue[DataPortal | str] = dp_queue diff --git a/temoa/extensions/myopic/myopic_progress_mapper.py b/temoa/extensions/myopic/myopic_progress_mapper.py index 485095627..9cc2b5fe9 100644 --- a/temoa/extensions/myopic/myopic_progress_mapper.py +++ b/temoa/extensions/myopic/myopic_progress_mapper.py @@ -72,7 +72,10 @@ def draw_header(self): def timestamp(self) -> str: delta = datetime.now() - self.hack - return f'{int(delta.total_seconds()//3600):02d}:{int(delta.total_seconds()%3600//60):02d}:{int(delta.total_seconds())%60:02d} ' + return ( + f'Elapsed: {int(delta.total_seconds()//3600):02d}:' + f'{int(delta.total_seconds()%3600//60):02d}:{int(delta.total_seconds())%60:02d} ' + ) def report(self, mi: MyopicIndex, status): if status not in {'load', 'solve', 'report', 'check'}: diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index c0877bf26..f4c5d943c 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -122,10 +122,13 @@ def get_connection(self) -> Connection: logger.info('Connected to database: %s', input_file) else: msg = ( - 'Myopic Mode processing only supports a single database (i.e. input_file = output_db).\n' + 'Myopic Mode processing only supports a single database (i.e. input_file = ' + 'output_db).\n' 'This is due to the linkage between input and output and the use of Myopic tables\n' - 'in the database to orchestrate the run. Either reset both input and output to point\n' - 'to the same db or make a copy to preserve the original and point both input/output\n' + 'in the database to orchestrate the run. Either reset both input and output to ' + 'point\n' + 'to the same db or make a copy to preserve the original and point both ' + 'input/output\n' 'to the copy.' ) sys.stderr.write(msg) @@ -178,10 +181,11 @@ def start(self): if new_start_idx < 0: logger.error('Failed myopic iteration. Cannot back up any further.') raise RuntimeError( - 'Myopic iteration failed during attempt to back up recursively before start of optimization ' - 'period.' + 'Myopic iteration failed during attempt to back up recursively before ' + 'start of optimization period.' ) - # roll back the start year by making a new index, increase the depth, keep the same last year + # roll back the start year by making a new index, increase the depth, keep the + # same last year base_year = self.optimization_periods[new_start_idx] idx = MyopicIndex( base_year=base_year, @@ -241,7 +245,8 @@ def start(self): logger.info('Completed myopic iteration on %s', idx) # 9, 10. Update the output tables... - # first, clear any possible previous results that overlap, we might have been backtracking... + # first, clear any possible previous results that overlap, we might have been + # backtracking... self.clear_results_after(idx.base_year) # add the new results... if not self.config.silent: @@ -266,7 +271,8 @@ def start(self): # Total system cost is, theoretically, sum of discounted costs from output_cost table total_cost = self.output_con.execute( - f'SELECT SUM(d_invest)+SUM(d_fixed)+SUM(d_var)+SUM(d_emiss) FROM output_cost WHERE scenario == "{self.config.scenario}"' + 'SELECT SUM(d_invest)+SUM(d_fixed)+SUM(d_var)+SUM(d_emiss) FROM output_cost ' + f'WHERE scenario == "{self.config.scenario}"' ).fetchone()[0] self.output_con.execute( f"""INSERT INTO @@ -293,12 +299,15 @@ def initialize_myopic_efficiency_table(self): # the -1 for base year is used to indicate "existing" for flag purposes # we will just use the "existing" flag in the orig db to set this up and capture # all values in those vintages as "existing" - # the "coalesce" is an if-else structure to pluck out the correct lifetime value, precedence left->right + # the "coalesce" is an if-else structure to pluck out the correct lifetime value, + # precedence left->right default_lifetime = TemoaModel.default_lifetime_tech query = ( 'INSERT INTO myopic_efficiency ' - ' SELECT -1, main.efficiency.region, input_comm, efficiency.tech, efficiency.vintage, output_comm, efficiency, ' - f' coalesce(main.lifetime_process.lifetime, main.lifetime_tech.lifetime, {default_lifetime}) AS lifetime ' + ' SELECT -1, main.efficiency.region, input_comm, efficiency.tech, ' + 'efficiency.vintage, output_comm, efficiency, ' + f' coalesce(main.lifetime_process.lifetime, main.lifetime_tech.lifetime, ' + f'{default_lifetime}) AS lifetime ' ' FROM main.efficiency ' ' LEFT JOIN main.lifetime_process ' ' ON main.efficiency.tech = lifetime_process.tech ' @@ -354,7 +363,9 @@ def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: i base = myopic_index.base_year last_demand_year = myopic_index.last_demand_year - logger.info('Starting update of myopic_efficiency Table retaining [%s, %s)', prev_base, base) + logger.info( + 'Starting update of myopic_efficiency Table retaining [%s, %s)', prev_base, base + ) # 0. Clear any future things past the base year for housekeeping # ease with steps, depth, etc. These may have been added if we are stepping less @@ -398,15 +409,15 @@ def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: i self.output_con.commit() # 2. Add the new stuff now visible - # dev note: the `coalesce()` command is a nested if-else. The first hit wins, so it is priority: - # process lifetime > tech lifetime > lifetime default + # dev note: the `coalesce()` command is a nested if-else. The first hit wins, so it is + # priority: process lifetime > tech lifetime > lifetime default lifetime = TemoaModel.default_lifetime_tech query = ( 'INSERT INTO myopic_efficiency ' f'SELECT {base}, efficiency.region, input_comm, ' ' efficiency.tech, efficiency.vintage, output_comm, efficiency, ' - f' coalesce(main.lifetime_process.lifetime, main.lifetime_tech.lifetime, {lifetime}) ' - f' AS lifetime ' + f' coalesce(main.lifetime_process.lifetime, main.lifetime_tech.lifetime, ' + f'{lifetime}) AS lifetime ' ' FROM main.efficiency ' ' LEFT JOIN main.lifetime_process ' ' ON main.efficiency.tech = lifetime_process.tech ' @@ -419,7 +430,8 @@ def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: i f' AND efficiency.vintage <= {last_demand_year}' ) if self.debugging: - # note: the debug query below omits the lifetime computation for brevity, but is very useful without... + # note: the debug query below omits the lifetime computation for brevity, but is very + # useful without... raw = self.cursor.execute( f'SELECT {base}, region, input_comm, tech, vintage, output_comm, efficiency ' 'FROM efficiency ' @@ -540,7 +552,8 @@ def clear_results_after(self, period): # special case... new capacity has vintage only... self.cursor.execute( - 'DELETE FROM main.output_built_capacity WHERE main.output_built_capacity.vintage >= (?) AND scenario = (?)', + 'DELETE FROM main.output_built_capacity WHERE ' + 'main.output_built_capacity.vintage >= (?) AND scenario = (?)', (period, self.config.scenario), ) self.output_con.commit() diff --git a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py index 2511a1735..864186a0c 100644 --- a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py +++ b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py @@ -151,7 +151,10 @@ def start(self): # check for an empty objective if isinstance(new_obj, int): # no variables found - msg = 'Construction of the alternative OBJ in SVMGA failed to locate any variables. Exiting' + msg = ( + 'Construction of the alternative OBJ in SVMGA failed to locate any variables. ' + 'Exiting' + ) logger.error(msg) print(msg) sys.exit(1) @@ -242,9 +245,12 @@ def construct_obj( categories_used += 1 if categories_used > 1: msg = ( - 'Warning: Using labels in multiple categories during SVMGA may lead to odd results.\n' - 'The catagories are not specifically designed to work together, but rather add flexibility.\n' - 'The new OBJ function will be an *unweighted* sum of everything found, so outputs in \n' + 'Warning: Using labels in multiple categories during SVMGA may lead to odd ' + 'results.\n' + 'The catagories are not specifically designed to work together, but rather add ' + 'flexibility.\n' + 'The new OBJ function will be an *unweighted* sum of everything found, so outputs ' + 'in \n' 'differing categories with vastly different scale may have odd interactions.' ) diff --git a/temoa/extensions/stochastics/VSS.py b/temoa/extensions/stochastics/VSS.py index a5d0f6fa4..09589eece 100755 --- a/temoa/extensions/stochastics/VSS.py +++ b/temoa/extensions/stochastics/VSS.py @@ -93,7 +93,13 @@ def my_ef_writer(scenario_tree): V_Activity_ptv = rows['V_ActivityByPeriodAndProcess'] V_Activity_pt = OrderedDict() for row in V_Activity_ptv: - key = (row[0], row[1], row[2], row[3], row[4]) # (Stage, Node, var_name, p, t) + key = ( + row[0], + row[1], + row[2], + row[3], + row[4], + ) # (Stage, Node, var_name, p, t) if key not in V_Activity_pt: V_Activity_pt[key] = float(row[6]) else: @@ -146,7 +152,9 @@ def solve_ef_fix(ef_options, avg_instance): time_fut = avg_instance.time_future.data() techs = avg_instance.tech_all.data() - dv_capacity = avg_instance.v_capacity.get_values() # Getting dec vars that matters to be fixed + dv_capacity = ( + avg_instance.v_capacity.get_values() + ) # Getting dec vars that matters to be fixed # dV_HydroStorage = avg_instance.V_HydroStorage.get_values() # Storing techs and future time periods in vector for easy access @@ -156,11 +164,13 @@ def solve_ef_fix(ef_options, avg_instance): vtime_fut[k] = iaux k = k + 1 - # Fixing Capacity values for first stage at the ef instance with values from the deterministic instance + # Fixing Capacity values for first stage at the ef instance with values from + # the deterministic instance for iaux1, iaux2 in dv_capacity: if iaux2 == vtime_fut[0]: ef._binding_instance.S0s0s0.v_capacity[iaux1, iaux2].fix(dv_capacity[iaux1, iaux2]) - # ef._binding_instance.S0.v_capacity[iaux1, iaux2].fix(3) #just for checking if fixing at one scen also fix in the other - ok for now + # ef._binding_instance.S0.v_capacity[iaux1, iaux2].fix(3) + # just for checking if fixing at one scen also fix in the other - ok for now # Fixing Hydro Storage values for first stage # for iaux1 , iaux2 in dV_HydroStorage: @@ -227,7 +237,9 @@ def return_obj(instance): dm_result['cost'].append(obj_val) # Writting to the Shell - sys.stdout.write('\nSolved deterministic model with uncertainty at average valures \n') + sys.stdout.write( + '\nSolved deterministic model with uncertainty at average valures \n' + ) sys.stdout.write(f' Total cost: {obj_val}\n') os.chdir(pwd) return instance # Returning instance solved, values will be used later @@ -248,9 +260,10 @@ def runECIU(): def runVSS(): - # This is the main function. It calls 1) Extensive Form 2)Deterministic LP 3)Fixed Extensive Form - # After results of 1) and 3) are obtained it computes the VSS - # As input, this function requires the path of the stochastic folder and temoa_stochastic.py file + # This is the main function. It calls 1) Extensive Form 2)Deterministic LP + # 3)Fixed Extensive Form. After results of 1) and 3) are obtained it computes the VSS + # As input, this function requires the path of the stochastic folder and + # temoa_stochastic.py file # It assumes that an instance named ReferenceModel.dat is located inside the stochastic folder import sys From d9442b603f9188cfdf8890871f2adae674f601ec Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 22 Nov 2025 17:59:57 -0500 Subject: [PATCH 365/587] fixing E501 line too long linting issues in model_checking --- temoa/model_checking/commodity_network.py | 15 ++++++++---- temoa/model_checking/network_model_data.py | 6 +++-- temoa/model_checking/pricing_check.py | 18 +++++++++++---- temoa/model_checking/validators.py | 27 +++++++++++++++------- 4 files changed, 46 insertions(+), 20 deletions(-) diff --git a/temoa/model_checking/commodity_network.py b/temoa/model_checking/commodity_network.py index b21d65bc1..10a4ca9b6 100644 --- a/temoa/model_checking/commodity_network.py +++ b/temoa/model_checking/commodity_network.py @@ -153,7 +153,8 @@ def prescreen_linked_tech(self) -> None: self.viable_linked_tech.add((driver, driven)) elif driver_exists and not driven_exists: logger.info( - 'No driven linked tech for driver %s in region %s, period %s. Driver REMOVED.', + 'No driven linked tech for driver %s in region %s, period %s. Driver ' + 'REMOVED.', driver, self.region, self.period, @@ -161,7 +162,8 @@ def prescreen_linked_tech(self) -> None: self.remove_tech_by_name(driver) elif not driver_exists and driven_exists: logger.warning( - 'Driven linked tech %s has no active driver in region %s, period %s. Driven tech REMOVED.', + 'Driven linked tech %s has no active driver in region %s, period %s. ' + 'Driven tech REMOVED.', driven, self.region, self.period, @@ -207,7 +209,8 @@ def analyze_network(self) -> None: for driver, driven in sour_links: logger.warning( - 'Both members of link (%s, %s) are not valid. Removing both in region %s, period %s.', + 'Both members of link (%s, %s) are not valid. Removing both in region %s, ' + 'period %s.', driver, driven, self.region, @@ -279,7 +282,8 @@ def _log_orphans(self) -> None: """Helper to log discovered orphaned processes.""" if self.other_orphans: logger.info( - "Source tracing revealed %s 'other' (non-demand) orphaned processes in region %s, period %s.", + "Source tracing revealed %s 'other' (non-demand) orphaned processes in region %s, " + 'period %s.', len(self.other_orphans), self.region, self.period, @@ -289,7 +293,8 @@ def _log_orphans(self) -> None: if self.demand_orphans: logger.info( - 'Source tracing revealed %s demand-side orphaned processes in region %s, period %s.', + 'Source tracing revealed %s demand-side orphaned processes in region %s, ' + 'period %s.', len(self.demand_orphans), self.region, self.period, diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index c4a6288ae..62ed54e3f 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -266,7 +266,8 @@ def _fetch_all_tech_definitions( COALESCE(lp.lifetime, lt.lifetime, ?) AS lifetime, COALESCE(tech_dim.sector, 'Other') AS sector FROM main.{table} AS eff - LEFT JOIN main.lifetime_process AS lp ON eff.tech = lp.tech AND eff.vintage = lp.vintage AND eff.region = lp.region + LEFT JOIN main.lifetime_process AS lp ON eff.tech = lp.tech AND eff.vintage = lp.vintage + AND eff.region = lp.region LEFT JOIN main.lifetime_tech AS lt ON eff.tech = lt.tech AND eff.region = lt.region LEFT JOIN main.technology AS tech_dim ON eff.tech = tech_dim.tech JOIN main.time_period AS tp ON eff.vintage = tp.period @@ -277,7 +278,8 @@ def _fetch_all_tech_definitions( eff.region, eff.input_comm, eff.tech, eff.vintage, eff.output_comm, COALESCE(lp.lifetime, lt.lifetime, ?) AS lifetime FROM main.{table} AS eff - LEFT JOIN main.lifetime_process AS lp ON eff.tech = lp.tech AND eff.vintage = lp.vintage AND eff.region = lp.region + LEFT JOIN main.lifetime_process AS lp ON eff.tech = lp.tech AND eff.vintage = lp.vintage + AND eff.region = lp.region LEFT JOIN main.lifetime_tech AS lt ON eff.tech = lt.tech AND eff.region = lt.region JOIN main.time_period AS tp ON eff.vintage = tp.period """ diff --git a/temoa/model_checking/pricing_check.py b/temoa/model_checking/pricing_check.py index a6d0c0abb..a7027f4ea 100644 --- a/temoa/model_checking/pricing_check.py +++ b/temoa/model_checking/pricing_check.py @@ -180,7 +180,8 @@ def price_checker(model: TemoaModel) -> bool: if missing_fixed_costs: logger.warning( 'Check 2: The following have registered variable costs in ' - 'the periods listed and at least 1 fixed cost, but not fixed & var in all periods: %s', + 'the periods listed and at least 1 fixed cost, but not fixed & var in all periods: ' + '%s', missing_fixed_costs, ) warnings = True @@ -260,7 +261,8 @@ def check_tech_uncap(model: TemoaModel) -> bool: """ Check that the tech_uncap set members... 1. do not have fixed or invest costs - 2. Either have no Var cost, or a Var cost in every year of their lifespan (similar to check #3 above) + 2. Either have no Var cost, or a Var cost in every year of their lifespan (similar to check #3 + above) 3. Are not in the limit_capacity parameters :param M: @@ -279,7 +281,9 @@ def check_tech_uncap(model: TemoaModel) -> bool: rtv_with_fixed_cost = efficiency_rtv & set(fixed_cost_periods.keys()) if rtv_with_fixed_cost: logger.error( - 'The following technologies are labeled as unlimited capacity, but have a FIXED cost in periods' + 'The following technologies are labeled as unlimited capacity, but have a FIXED cost ' + 'in ' + 'periods' ) for rtv in rtv_with_fixed_cost: logger.error('%s: %s', rtv, fixed_cost_periods[rtv]) @@ -306,7 +310,9 @@ def check_tech_uncap(model: TemoaModel) -> bool: missing_periods = expected_periods - var_cost_periods[r, t, v] if missing_periods: logger.warning( - 'Unlimited capacity tech %s has some Variable costs, but is missing cost in periods: %s', + 'Unlimited capacity tech %s has some Variable costs, but is missing cost in ' + 'periods: ' + '%s', t, missing_periods, ) @@ -314,7 +320,9 @@ def check_tech_uncap(model: TemoaModel) -> bool: extra_periods = var_cost_periods[r, t, v] - expected_periods if extra_periods: logger.warning( - 'Unlimited capacity region-tech-vintage %s-%s-%s has some variable costs outside of its ' + 'Unlimited capacity region-tech-vintage %s-%s-%s has some variable costs outside ' + 'of ' + 'its ' 'lifespan: %s', r, t, diff --git a/temoa/model_checking/validators.py b/temoa/model_checking/validators.py index aa8a262c0..d94406dd4 100644 --- a/temoa/model_checking/validators.py +++ b/temoa/model_checking/validators.py @@ -48,12 +48,14 @@ def validate_linked_tech(model: TemoaModel) -> bool: """ A validation that for all the linked techs, they have the same lifetime in each possible vintage - The Constraint that this check supports is indexed by a set that fundamentally expands the (r, t, e) + The Constraint that this check supports is indexed by a set that fundamentally expands the + (r, t, e) index of the LinkedTech data table (where t==driver tech) to include valid vintages. The implication is that there is a driven tech in the same region, of the same vintage, with the same lifetime as the driver tech. We should check that. - We can filter the index down to (r, t_driver, v, e) and then query the lifetime of the driver and driven + We can filter the index down to (r, t_driver, v, e) and then query the lifetime of the driver + and driven to ensure they are the same :param M: @@ -74,7 +76,8 @@ def validate_linked_tech(model: TemoaModel) -> bool: driven_lifetime = model.lifetime_process[r, t_driven, v] except KeyError: logger.error( - 'Linked Tech Error: Driven tech %s does not have a vintage entry %d to match driver %s', + 'Linked Tech Error: Driven tech %s does not have a vintage entry %d to match ' + 'driver %s', t_driven, v, t_driver, @@ -83,7 +86,8 @@ def validate_linked_tech(model: TemoaModel) -> bool: return False if driven_lifetime != driver_lifetime: logger.error( - 'Linked Tech Error: Driven tech %s has lifetime %d in vintage %d while driver tech %s has lifetime %d', + 'Linked Tech Error: Driven tech %s has lifetime %d in vintage %d while driver ' + 'tech %s has lifetime %d', t_driven, driven_lifetime, v, @@ -178,8 +182,10 @@ def tech_groups_set_check(model: TemoaModel, rg: str, g: str, t: str) -> bool: # TODO: Several of these param checkers below are not in use because the params cannot -# accept new values for the indexing sets that aren't in an already-constructed set. Now that we are -# making the GlobalRegionalIndices, we can probably come back and employ them instead of using +# accept new values for the indexing sets that aren't in an already-constructed set. Now +# that we are +# making the GlobalRegionalIndices, we can probably come back and employ them instead of +# using # the buildAction approach @@ -337,7 +343,9 @@ def validate_reserve_margin(model: TemoaModel) -> None: for r in model.planning_reserve_margin.sparse_iterkeys(): if all((r, p) not in model.process_reserve_periods for p in model.time_optimize): logger.warning( - 'Planning reserve margin provided but there are no reserve technologies serving this region: %s', + 'Planning reserve margin provided but there are no reserve technologies serving ' + 'this ' + 'region: %s', (r, model.planning_reserve_margin[r]), ) @@ -364,7 +372,10 @@ def validate_tech_sets(model: TemoaModel) -> None: def check_no_intersection(set_one: Set, set_two: Set) -> bool: violations = set_one & set_two if violations: - msg = f'The following are in both {set_one} and {set_two}, which is not permitted:\n{list(violations)}' + msg = ( + f'The following are in both {set_one} and {set_two}, which is not permitted:\n' + f'{list(violations)}' + ) logger.error(msg) return False return True From 1660d4cfb44fbf1327b0e13ac998410ec9656c05 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 22 Nov 2025 18:00:12 -0500 Subject: [PATCH 366/587] fixing E501 line too long linting issues in types --- temoa/types/validation_types.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/temoa/types/validation_types.py b/temoa/types/validation_types.py index 3db057dc0..029bca15e 100644 --- a/temoa/types/validation_types.py +++ b/temoa/types/validation_types.py @@ -40,7 +40,8 @@ class ValidationError: severity: The severity level of the validation issue message: Human-readable description of the issue location: Optional location information (e.g., file, line, component) - context: Optional additional context about the issue (e.g., {'variable': 'x', 'expected': 10, 'actual': 5}) + context: Optional additional context about the issue + (e.g., {'variable': 'x', 'expected': 10, 'actual': 5}) """ severity: ValidationSeverity From 02c9ef9d7566e8d5a929bf7ade80ddd5af443f3c Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 22 Nov 2025 18:00:28 -0500 Subject: [PATCH 367/587] fixing E501 line too long linting issues in cli --- temoa/cli.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/temoa/cli.py b/temoa/cli.py index 09d465806..8971ae8fa 100644 --- a/temoa/cli.py +++ b/temoa/cli.py @@ -125,7 +125,8 @@ def _cite_callback(value: bool) -> None: citation_text.append( """Hunter, K., Sreepathi, S., & DeCarolis, J. F. (2013). """ - """Modeling for insight using Tools for Energy Model Optimization and Analysis (Temoa). """ + """Modeling for insight using Tools for Energy Model Optimization and Analysis """ + """(Temoa). """ """Energy Economics, 40, 339-349. """ """https://doi.org/10.1016/j.eneco.2013.07.014""", style='italic', @@ -153,7 +154,8 @@ def get_default_schema() -> Path: except Exception as e: logger.exception('Failed to load schema from resources') # The fallback for development needs to reflect the current repository structure - # assuming `cli.py` is in `temoa/` and `db_schema/` is a sibling of `cli.py` within `temoa/`. + # assuming `cli.py` is in `temoa/` and `db_schema/` is a sibling of `cli.py` within + # `temoa/`. fallback_path = Path(__file__).parent / 'db_schema' / 'temoa_schema_v4.sql' if fallback_path.is_file(): logger.warning( @@ -322,7 +324,8 @@ def migrate( str | None, typer.Option( '--type', - help='Migration type: "sql" for SQL dump to SQLite dump, "db" for SQLite DB in-place migration, if omitted, infers from input extension.', + help='Migration type: "sql" for SQL dump to SQLite dump, "db" for SQLite DB in-place ' + 'migration, if omitted, infers from input extension.', ), ] = None, silent: Annotated[ @@ -390,7 +393,8 @@ def migrate( effective_output_dir.mkdir(parents=True, exist_ok=True) except OSError as e: rich.print( - f'[red]Error: Could not create auto-generated output directory "{effective_output_dir}": {e}[/red]' + f'[red]Error: Could not create auto-generated output directory ' + f'"{effective_output_dir}": {e}[/red]' ) raise typer.Exit(1) from e @@ -592,12 +596,14 @@ def tutorial( rich.print(' or') rich.print(f' [green]python -m temoa run {target_config.name}[/green]') rich.print( - f'\nTo learn more about the configuration options, see the comments in [cyan]{target_config.name}[/cyan]' + f'\nTo learn more about the configuration options, see the comments in ' + f'[cyan]{target_config.name}[/cyan]' ) if verbose: rich.print( - f"\n[dim]The configuration file points to your local '{database_name}.sqlite' database.[/dim]" + f"\n[dim]The configuration file points to your local '{database_name}.sqlite' " + 'database.[/dim]' ) rich.print("[dim]Results will be saved in the 'output_files' directory.[/dim]") @@ -608,7 +614,8 @@ def tutorial( 'The default tutorial configuration uses the [bold]CBC[/bold] solver, ' "which was not found in your system's PATH.\n" 'To run the tutorial model successfully, please install CBC. ' - f'Refer to this link for installation guidance: [link={cbc_doc_link}]{cbc_doc_link}[/link]\n' + f'Refer to this link for installation guidance: ' + f'[link={cbc_doc_link}]{cbc_doc_link}[/link]\n' ) except Exception as e: From a1ba8eff3e3c4c3674a62d3150f764cfa54a7db2 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 22 Nov 2025 18:00:45 -0500 Subject: [PATCH 368/587] fixing E501 line too long linting issues in ci script --- .github/scripts/deploy_nightly_pypi.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/scripts/deploy_nightly_pypi.py b/.github/scripts/deploy_nightly_pypi.py index 509250cf1..25efb1a8a 100644 --- a/.github/scripts/deploy_nightly_pypi.py +++ b/.github/scripts/deploy_nightly_pypi.py @@ -172,7 +172,8 @@ def deploy_dumb_pypi_index(nightly_version: str) -> None: shutil.rmtree(item_path) # Use shutil for robust directory deletion print( - f'Copying generated index from {TEMPORARY_OUTPUT_DIR}/simple/ to {NIGHTLIES_REPO_CLONE_DIR}...' + f'Copying generated index from {TEMPORARY_OUTPUT_DIR}/simple/ to ' + f'{NIGHTLIES_REPO_CLONE_DIR}...' ) for item in os.listdir(os.path.join(TEMPORARY_OUTPUT_DIR, 'simple')): src_path = os.path.join(TEMPORARY_OUTPUT_DIR, 'simple', item) From c15135df6b3cef8773debe5f598f8097eefdecdf Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 22 Nov 2025 18:01:02 -0500 Subject: [PATCH 369/587] fixing E501 line too long linting issues in tests --- tests/conftest.py | 5 +++- tests/test_cli.py | 6 ++-- tests/test_emission_results.py | 30 ++++++++++++------- tests/test_full_runs.py | 3 +- tests/test_linked_tech.py | 3 +- tests/test_material_results.py | 3 +- tests/test_set_consistency.py | 3 +- tests/test_storage.py | 3 +- tests/test_tech_activity_vectors.py | 3 +- .../utilities/capture_set_sizes_for_cache.py | 7 +++-- 10 files changed, 44 insertions(+), 22 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 0e405a521..1041c686d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -34,7 +34,10 @@ def refresh_databases() -> None: - """make new databases from source for testing... removes possibility of contamination by earlier runs""" + """ + make new databases from source for testing... removes possibility of contamination by earlier + runs + """ data_output_path = Path(__file__).parent / 'testing_outputs' data_source_path = Path(__file__).parent / 'testing_data' databases = ( diff --git a/tests/test_cli.py b/tests/test_cli.py index c0cfaaca1..b1823fb17 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -489,7 +489,8 @@ def test_cli_validate_fails_if_solver_missing( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: """ - Test that the validate command fails with SolverNotAvailableError if the configured solver is missing. + Test that the validate command fails with SolverNotAvailableError if the configured solver is + missing. """ db_path = Path(__file__).parent / 'testing_outputs' / 'utopia.sqlite' test_config_path = create_config_with_solver(tmp_path, db_path, 'nonexistent_solver') @@ -516,7 +517,8 @@ def test_cli_validate_fails_if_solver_missing( def test_cli_run_fails_if_solver_missing(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: """ - Test that the run command fails with SolverNotAvailableError if the configured solver is missing. + Test that the run command fails with SolverNotAvailableError if the configured solver is + missing. """ db_path = Path(__file__).parent / 'testing_outputs' / 'utopia.sqlite' test_config_path = create_config_with_solver(tmp_path, db_path, 'another_nonexistent_solver') diff --git a/tests/test_emission_results.py b/tests/test_emission_results.py index b90a3f7ed..7cd0d8e3a 100644 --- a/tests/test_emission_results.py +++ b/tests/test_emission_results.py @@ -86,7 +86,8 @@ def test_emissions(solved_connection: SolvedConnection) -> None: emis = ( con.cursor() .execute( - f"SELECT SUM(emission) FROM main.output_emission WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied' AND period == 2000" + f"SELECT SUM(emission) FROM main.output_emission WHERE tech LIKE '{tech}' AND " + f"tech != 'TechEmbodied' AND period == 2000" ) .fetchone()[0] ) @@ -112,7 +113,8 @@ def test_emissions_costs_undiscounted( ec = ( con.cursor() .execute( - f"SELECT SUM(emiss) FROM main.output_cost WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied' AND period == 2000" + f"SELECT SUM(emiss) FROM main.output_cost WHERE tech LIKE '{tech}' AND " + f"tech != 'TechEmbodied' AND period == 2000" ) .fetchone()[0] ) @@ -139,7 +141,8 @@ def test_emissions_costs_discounted( ec = ( con.cursor() .execute( - f"SELECT SUM(d_emiss) FROM main.output_cost WHERE tech LIKE '{tech}' AND tech != 'TechEmbodied' AND period == 2000" + f"SELECT SUM(d_emiss) FROM main.output_cost WHERE tech LIKE '{tech}' AND " + f"tech != 'TechEmbodied' AND period == 2000" ) .fetchone()[0] ) @@ -158,13 +161,15 @@ def test_emissions_costs_discounted( ) def test_embodied_emissions(solved_connection: SolvedConnection) -> None: """ - Test that the embodied emissions from each technology archetype are correct, and check total emissions + Test that the embodied emissions from each technology archetype are correct, and check total + emissions """ con, name, tech, emis_target = solved_connection emis = ( con.cursor() .execute( - f"SELECT SUM(emission) FROM main.output_emission WHERE tech LIKE '{tech}' AND period == 2000" + f"SELECT SUM(emission) FROM main.output_emission WHERE tech LIKE '{tech}' AND " + f'period == 2000' ) .fetchone()[0] ) @@ -196,7 +201,8 @@ def test_embodied_emissions_costs_undiscounted( ) cost_target = 0.7 * emis_target # emission cost x embodied emissions assert ec == pytest.approx(cost_target), ( - f'{name} undiscounted embodied emission costs were incorrect. Should be {cost_target}, got {ec}' + f'{name} undiscounted embodied emission costs were incorrect. Should be {cost_target}, ' + f'got {ec}' ) @@ -238,13 +244,15 @@ def test_embodied_emissions_costs_discounted( ) def test_endoflife_emissions(solved_connection: SolvedConnection) -> None: """ - Test that the end of life emissions from each technology archetype are correct, and check total emissions + Test that the end of life emissions from each technology archetype are correct, and check total + emissions """ con, name, tech, emis_target = solved_connection emis = ( con.cursor() .execute( - f"SELECT SUM(emission) FROM main.output_emission WHERE tech LIKE '{tech}' AND period == 2005" + f"SELECT SUM(emission) FROM main.output_emission WHERE tech LIKE '{tech}' AND " + f'period == 2005' ) .fetchone()[0] ) @@ -276,7 +284,8 @@ def test_endoflife_emissions_costs_undiscounted( ) cost_target = 0.7 * emis_target # emission cost x end of life emissions assert ec == pytest.approx(cost_target), ( - f'{name} undiscounted end of life emission costs were incorrect. Should be {cost_target}, got {ec}' + f'{name} undiscounted end of life emission costs were incorrect. Should be {cost_target}, ' + f'got {ec}' ) @@ -331,7 +340,8 @@ def test_curtailment(solved_connection: SolvedConnection) -> None: curt = ( con.cursor() .execute( - f"SELECT SUM(curtailment) FROM main.output_curtailment WHERE tech LIKE '{tech}' AND period == 2000" + f"SELECT SUM(curtailment) FROM main.output_curtailment WHERE tech LIKE '{tech}' AND " + f'period == 2000' ) .fetchone()[0] ) diff --git a/tests/test_full_runs.py b/tests/test_full_runs.py index 19e3c740c..f4e424b5f 100644 --- a/tests/test_full_runs.py +++ b/tests/test_full_runs.py @@ -66,7 +66,8 @@ def test_against_legacy_outputs( len(tuple(efficiency_param.sparse_iterkeys())) == expected_vals[ExpectedVals.EFF_INDEX_SIZE] ), 'should match legacy numbers' - # check the size of the domain. NOTE: The build of the domain here may be "expensive" for large models + # check the size of the domain. NOTE: The build of the domain here may be "expensive" for + # large models assert ( len(efficiency_param.index_set().domain) == expected_vals[ExpectedVals.EFF_DOMAIN_SIZE] ), 'should match legacy numbers' diff --git a/tests/test_linked_tech.py b/tests/test_linked_tech.py index 20887baf0..d2850a31a 100644 --- a/tests/test_linked_tech.py +++ b/tests/test_linked_tech.py @@ -46,7 +46,8 @@ def test_linked_tech( 'the linked processes should remove have an aggregate -30 units of co2 emissions' ) - # check the flow out of captured carbon from the driven tech, which should output the captured carbon + # check the flow out of captured carbon from the driven tech, which should output the captured + # carbon flow_out = conn.execute( "SELECT SUM(flow) FROM output_flow_out WHERE tech = 'CCS' and output_comm = 'CO2_CAP'" ).fetchone()[0] diff --git a/tests/test_material_results.py b/tests/test_material_results.py index c292ac57b..aec11b752 100644 --- a/tests/test_material_results.py +++ b/tests/test_material_results.py @@ -66,7 +66,8 @@ def test_flows(solved_connection: tuple[sqlite3.Connection, str, str, int, float 'SELECT SUM(flow) FROM main.output_flow_out WHERE tech = ? AND period = ?', (tech, period), ).fetchone() - # If the query returns no rows, row will be None. If it finds rows but the sum is NULL, row[0] will be None. + # If the query returns no rows, row will be None. If it finds rows but the sum is NULL, row[0] + # will be None. flow = row[0] if row and row[0] is not None else 0.0 assert flow == pytest.approx( diff --git a/tests/test_set_consistency.py b/tests/test_set_consistency.py index c9167fef9..23906ca4d 100644 --- a/tests/test_set_consistency.py +++ b/tests/test_set_consistency.py @@ -63,7 +63,8 @@ def test_set_consistency( overage_in_model[set_name] = s - cached_set shortage_in_model[set_name] = cached_set - s missing_in_model = cached_sets.keys() - model_sets.keys() - # drop any set that has "_index" in the name as they are no longer reported by newer version of pyomo + # drop any set that has "_index" in the name as they are no longer reported by newer version of + # pyomo missing_in_model = {s for s in missing_in_model if '_index' not in s and '_domain' not in s} if overage_in_model: diff --git a/tests/test_storage.py b/tests/test_storage.py index 68328c790..7704e3353 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -86,7 +86,8 @@ def test_state_sequencing(system_test_run: tuple[str, Any, TemoaModel, Any]) -> next_state = model.v_storage_level[r, p, s_next, d_next, t, v].value # type: ignore [attr-defined] # I can't figure out how to get mypy to see value through the pyomo stubs assert state + charge - discharge == pytest.approx(next_state, abs=1e-5), ( - f'model fails to correctly sequence storage states {r, p, s, t, v} sequenced {s, d} to {s_next, d_next}' + f'model fails to correctly sequence storage states {r, p, s, t, v} sequenced {s, d} ' + f'to {s_next, d_next}' ) diff --git a/tests/test_tech_activity_vectors.py b/tests/test_tech_activity_vectors.py index 85da17e0d..7eedd7cc0 100644 --- a/tests/test_tech_activity_vectors.py +++ b/tests/test_tech_activity_vectors.py @@ -20,7 +20,8 @@ def test__vector_engine() -> None: } var_map = {'dog': ['red', 'blue'], 'pig': ['yellow', 'green'], 'cat': ['blue', 'gold']} tech_sizes = {k: len(v) for k, v in var_map.items()} - # below is just to show the mapping back to variables.... test just want the coefficients from res_values + # below is just to show the mapping back to variables.... test just want the coefficients from + # res_values # res = [ # {'red': 0.25, 'blue': 0.25, 'yellow': 0.25, 'green': 0.25}, # {'red': -0.25, 'blue': -0.25, 'yellow': -0.25, 'green': -0.25}, diff --git a/tests/utilities/capture_set_sizes_for_cache.py b/tests/utilities/capture_set_sizes_for_cache.py index 1536ff453..817e7648f 100644 --- a/tests/utilities/capture_set_sizes_for_cache.py +++ b/tests/utilities/capture_set_sizes_for_cache.py @@ -15,9 +15,10 @@ logger = logging.getLogger(__name__) print( - 'WARNING: Continuing to execute this file will update the cached values for the set sizes for US_9R model in ' - 'the testing_data folder from the sqlite databases in the same folder. This should only need to be done if the ' - 'schema or model have changed and that database has been updated.' + 'WARNING: Continuing to execute this file will update the cached values for the set sizes ' + 'for US_9R model in the testing_data folder from the sqlite databases in the same folder. ' + 'This should only need to be done if the schema or model have changed and that database has ' + 'been updated.' ) t = input('Type "Y" to continue, any other key to exit now.') From f25476580b48acfa04d7cd3752e96767b2715658 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 22 Nov 2025 18:02:27 -0500 Subject: [PATCH 370/587] adding back E501 restruction for everything but legacy files --- pyproject.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8b9054e60..dbdeffbf1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -101,13 +101,13 @@ select = [ "UP", # pyupgrade "C4", # flake8-comprehensions ] -ignore = [ - "E501", # line too long temporarily ignored -] [tool.ruff.lint.pep8-naming] ignore-names = ["MGA", "SVMGA"] # Allow these names to violate naming conventions +[tool.ruff.lint.per-file-ignores] +"temoa/extensions/stochastics/legacy_files/**/*.py" = ["E501"] + [tool.pytest.ini_options] testpaths = [ From 458ea63b3723c0838d6bbf6fc3f6be2ca620591f Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 22 Nov 2025 18:39:25 -0500 Subject: [PATCH 371/587] standardizing string quote style with ruff autofix --- pyproject.toml | 6 + temoa/utilities/db_migration_to_v3.py | 118 ++++----- temoa/utilities/db_migration_v3_to_v3_1.py | 280 ++++++++++----------- 3 files changed, 205 insertions(+), 199 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index dbdeffbf1..7b6df8443 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -100,6 +100,12 @@ select = [ "TC", # flake8-type-checking "UP", # pyupgrade "C4", # flake8-comprehensions + "Q", # flake8-quotes +] + +ignore = [ + "Q000", # the formatter deals with this + "Q003" # the formatter deals with this ] [tool.ruff.lint.pep8-naming] diff --git a/temoa/utilities/db_migration_to_v3.py b/temoa/utilities/db_migration_to_v3.py index 32d49b245..19c7999eb 100644 --- a/temoa/utilities/db_migration_to_v3.py +++ b/temoa/utilities/db_migration_to_v3.py @@ -51,71 +51,71 @@ # table mapping for DIRECT transfers # fmt: off direct_transfer_tables = [ - ('', 'CapacityCredit'), - ('', 'CapacityFactorProcess'), - ('', 'CapacityFactorTech'), - ('', 'CapacityToActivity'), - ('commodities', 'Commodity'), - ('commodity_labels', 'CommodityType'), - ('CostEmissions', 'CostEmission'), - ('', 'CostFixed'), - ('', 'CostInvest'), - ('', 'CostVariable'), - ('', 'Demand'), - ('', 'DemandSpecificDistribution'), - ('', 'Efficiency'), - ('', 'EmissionActivity'), - ('', 'EmissionLimit'), - ('', 'ExistingCapacity'), - ('', 'GrowthRateMax'), - ('', 'GrowthRateSeed'), - ('', 'LifetimeProcess'), - ('', 'LifetimeTech'), - ('LinkedTechs', 'LinkedTech'), - ('LifetimeLoanTech', 'LoanLifetimeTech'), - ('DiscountRate', 'LoanRate'), - ('', 'MaxActivity'), - ('', 'MaxActivityShare'), - ('', 'MaxAnnualCapacityFactor'), - ('', 'MaxCapacity'), - ('', 'MaxCapacityShare'), - ('', 'MaxNewCapacity'), - ('', 'MaxNewCapacityGroup'), - ('', 'MaxNewCapacityShare'), - ('', 'MaxResource'), - ('', 'MinActivity'), - ('', 'MinActivityShare'), - ('', 'MinAnnualCapacityFactor'), - ('', 'MinCapacity'), - ('', 'MinCapacityShare'), - ('', 'MinNewCapacity'), - ('', 'MinNewCapacityGroup'), - ('', 'MinNewCapacityShare'), - ('', 'PlanningReserveMargin'), - ('', 'RampDown'), - ('', 'RampUp'), - ('regions', 'Region'), - ('sector_labels', 'SectorLabel'), - ('', 'StorageDuration'), - ('', 'TechInputSplit'), - ('', 'TechInputSplitAverage'), - ('', 'TechOutputSplit'), - ('technology_labels', 'TechnologyType'), - ('time_period_labels', 'TimePeriodType'), - ('SegFrac', 'TimeSegmentFraction'), + ("", "CapacityCredit"), + ("", "CapacityFactorProcess"), + ("", "CapacityFactorTech"), + ("", "CapacityToActivity"), + ("commodities", "Commodity"), + ("commodity_labels", "CommodityType"), + ("CostEmissions", "CostEmission"), + ("", "CostFixed"), + ("", "CostInvest"), + ("", "CostVariable"), + ("", "Demand"), + ("", "DemandSpecificDistribution"), + ("", "Efficiency"), + ("", "EmissionActivity"), + ("", "EmissionLimit"), + ("", "ExistingCapacity"), + ("", "GrowthRateMax"), + ("", "GrowthRateSeed"), + ("", "LifetimeProcess"), + ("", "LifetimeTech"), + ("LinkedTechs", "LinkedTech"), + ("LifetimeLoanTech", "LoanLifetimeTech"), + ("DiscountRate", "LoanRate"), + ("", "MaxActivity"), + ("", "MaxActivityShare"), + ("", "MaxAnnualCapacityFactor"), + ("", "MaxCapacity"), + ("", "MaxCapacityShare"), + ("", "MaxNewCapacity"), + ("", "MaxNewCapacityGroup"), + ("", "MaxNewCapacityShare"), + ("", "MaxResource"), + ("", "MinActivity"), + ("", "MinActivityShare"), + ("", "MinAnnualCapacityFactor"), + ("", "MinCapacity"), + ("", "MinCapacityShare"), + ("", "MinNewCapacity"), + ("", "MinNewCapacityGroup"), + ("", "MinNewCapacityShare"), + ("", "PlanningReserveMargin"), + ("", "RampDown"), + ("", "RampUp"), + ("regions", "Region"), + ("sector_labels", "SectorLabel"), + ("", "StorageDuration"), + ("", "TechInputSplit"), + ("", "TechInputSplitAverage"), + ("", "TechOutputSplit"), + ("technology_labels", "TechnologyType"), + ("time_period_labels", "TimePeriodType"), + ("SegFrac", "TimeSegmentFraction"), ] units_added_tables = [ - ('', 'MaxActivityGroup'), - ('', 'MaxCapacityGroup'), - ('', 'MinCapacityGroup'), - ('', 'MinActivityGroup'), + ("", "MaxActivityGroup"), + ("", "MaxCapacityGroup"), + ("", "MinCapacityGroup"), + ("", "MinActivityGroup"), ] sequence_added_tables = [ - ('time_season', 'TimeSeason'), - ('time_periods', 'time_period'), - ('time_of_day', 'TimeOfDay'), + ("time_season", "TimeSeason"), + ("time_periods", "time_period"), + ("time_of_day", "TimeOfDay"), ] # fmt: on diff --git a/temoa/utilities/db_migration_v3_to_v3_1.py b/temoa/utilities/db_migration_v3_to_v3_1.py index e3d9729e7..63e7b7a8a 100644 --- a/temoa/utilities/db_migration_v3_to_v3_1.py +++ b/temoa/utilities/db_migration_v3_to_v3_1.py @@ -80,83 +80,83 @@ def column_check(old_name: str, new_name: str) -> bool: # table mapping for DIRECT transfers # fmt: off direct_transfer_tables = [ - ('', 'CapacityCredit'), - ('', 'CapacityToActivity'), - ('', 'Commodity'), - ('', 'CommodityType'), - ('', 'CostEmission'), - ('', 'CostFixed'), - ('', 'CostInvest'), - ('', 'CostVariable'), - ('', 'Demand'), - ('', 'Efficiency'), - ('', 'EmissionActivity'), - ('', 'ExistingCapacity'), - ('', 'LifetimeProcess'), - ('', 'LifetimeTech'), - ('', 'LinkedTech'), - ('', 'LoanRate'), - ('', 'MetaData'), - ('', 'MetaDataReal'), - ('', 'PlanningReserveMargin'), - ('RampDown', 'RampDownHourly'), - ('RampUp', 'RampUpHourly'), - ('', 'Region'), - ('', 'RPSRequirement'), - ('', 'SectorLabel'), - ('', 'StorageDuration'), - ('', 'TechGroup'), - ('', 'TechGroupMember'), - ('', 'Technology'), - ('', 'TechnologyType'), - ('', 'TimeOfDay'), - ('', 'TimePeriod'), - ('', 'TimePeriodType'), + ("", "CapacityCredit"), + ("", "CapacityToActivity"), + ("", "Commodity"), + ("", "CommodityType"), + ("", "CostEmission"), + ("", "CostFixed"), + ("", "CostInvest"), + ("", "CostVariable"), + ("", "Demand"), + ("", "Efficiency"), + ("", "EmissionActivity"), + ("", "ExistingCapacity"), + ("", "LifetimeProcess"), + ("", "LifetimeTech"), + ("", "LinkedTech"), + ("", "LoanRate"), + ("", "MetaData"), + ("", "MetaDataReal"), + ("", "PlanningReserveMargin"), + ("RampDown", "RampDownHourly"), + ("RampUp", "RampUpHourly"), + ("", "Region"), + ("", "RPSRequirement"), + ("", "SectorLabel"), + ("", "StorageDuration"), + ("", "TechGroup"), + ("", "TechGroupMember"), + ("", "Technology"), + ("", "TechnologyType"), + ("", "TimeOfDay"), + ("", "TimePeriod"), + ("", "TimePeriodType"), ] period_added_tables = [ - ('', 'CapacityFactorProcess'), - ('', 'CapacityFactorTech'), - ('', 'DemandSpecificDistribution'), - ('', 'TimeSeason'), - ('', 'TimeSegmentFraction'), + ("", "CapacityFactorProcess"), + ("", "CapacityFactorTech"), + ("", "DemandSpecificDistribution"), + ("", "TimeSeason"), + ("", "TimeSegmentFraction"), ] operator_added_tables = { - 'EmissionLimit': ('LimitEmission', 'le'), - 'TechOutputSplit': ('LimitTechOutputSplit', 'ge'), - 'TechInputSplitAnnual': ('LimitTechInputSplitAnnual', 'ge'), - 'TechInputSplitAverage': ('LimitTechInputSplitAnnual', 'ge'), - 'TechInputSplit': ('LimitTechInputSplit', 'ge'), - 'MinNewCapacityShare': ('LimitNewCapacityShare', 'ge'), - 'MinNewCapacityGroupShare': ('LimitNewCapacityShare', 'ge'), - 'MinNewCapacityGroup': ('LimitNewCapacity', 'ge'), - 'MinNewCapacity': ('LimitNewCapacity', 'ge'), - 'MinCapacityShare': ('LimitCapacityShare', 'ge'), - 'MinCapacityGroup': ('LimitCapacity', 'ge'), - 'MinCapacity': ('LimitCapacity', 'ge'), - 'MinAnnualCapacityFactor': ('LimitAnnualCapacityFactor', 'ge'), - 'MinActivityShare': ('LimitActivityShare', 'ge'), - 'MinActivityGroup': ('LimitActivity', 'ge'), - 'MinActivity': ('LimitActivity', 'ge'), - 'MaxNewCapacityShare': ('LimitNewCapacityShare', 'le'), - 'MaxNewCapacityGroupShare': ('LimitNewCapacityShare', 'le'), - 'MaxNewCapacityGroup': ('LimitNewCapacity', 'le'), - 'MaxNewCapacity': ('LimitNewCapacity', 'le'), - 'MaxCapacityShare': ('LimitCapacityShare', 'le'), - 'MaxCapacityGroup': ('LimitCapacity', 'le'), - 'MaxCapacity': ('LimitCapacity', 'le'), - 'MaxAnnualCapacityFactor': ('LimitAnnualCapacityFactor', 'le'), - 'MaxActivityShare': ('LimitActivityShare', 'le'), - 'MaxActivityGroup': ('LimitActivity', 'le'), - 'MaxActivity': ('LimitActivity', 'le'), - 'MaxResource': ('LimitResource', 'le'), + "EmissionLimit": ("LimitEmission", "le"), + "TechOutputSplit": ("LimitTechOutputSplit", "ge"), + "TechInputSplitAnnual": ("LimitTechInputSplitAnnual", "ge"), + "TechInputSplitAverage": ("LimitTechInputSplitAnnual", "ge"), + "TechInputSplit": ("LimitTechInputSplit", "ge"), + "MinNewCapacityShare": ("LimitNewCapacityShare", "ge"), + "MinNewCapacityGroupShare": ("LimitNewCapacityShare", "ge"), + "MinNewCapacityGroup": ("LimitNewCapacity", "ge"), + "MinNewCapacity": ("LimitNewCapacity", "ge"), + "MinCapacityShare": ("LimitCapacityShare", "ge"), + "MinCapacityGroup": ("LimitCapacity", "ge"), + "MinCapacity": ("LimitCapacity", "ge"), + "MinAnnualCapacityFactor": ("LimitAnnualCapacityFactor", "ge"), + "MinActivityShare": ("LimitActivityShare", "ge"), + "MinActivityGroup": ("LimitActivity", "ge"), + "MinActivity": ("LimitActivity", "ge"), + "MaxNewCapacityShare": ("LimitNewCapacityShare", "le"), + "MaxNewCapacityGroupShare": ("LimitNewCapacityShare", "le"), + "MaxNewCapacityGroup": ("LimitNewCapacity", "le"), + "MaxNewCapacity": ("LimitNewCapacity", "le"), + "MaxCapacityShare": ("LimitCapacityShare", "le"), + "MaxCapacityGroup": ("LimitCapacity", "le"), + "MaxCapacity": ("LimitCapacity", "le"), + "MaxAnnualCapacityFactor": ("LimitAnnualCapacityFactor", "le"), + "MaxActivityShare": ("LimitActivityShare", "le"), + "MaxActivityGroup": ("LimitActivity", "le"), + "MaxActivity": ("LimitActivity", "le"), + "MaxResource": ("LimitResource", "le"), } no_transfer = { - 'MinSeasonalActivity': 'LimitSeasonalCapacityFactor', - 'MaxSeasonalActivity': 'LimitSeasonalCapacityFactor', - 'StorageInit': 'LimitStorageLevelFraction', + "MinSeasonalActivity": "LimitSeasonalCapacityFactor", + "MaxSeasonalActivity": "LimitSeasonalCapacityFactor", + "StorageInit": "LimitStorageLevelFraction", } @@ -170,82 +170,82 @@ def column_check(old_name: str, new_name: str) -> bool: # Collapse Max/Min constraint tables -print('\n --- Collapsing Max/Min tables and adding operators ---') +print("\n --- Collapsing Max/Min tables and adding operators ---") for old_name, (new_name, operator) in operator_added_tables.items(): try: - data = con_old.execute(f'SELECT * FROM {old_name}').fetchall() + data = con_old.execute(f"SELECT * FROM {old_name}").fetchall() except sqlite3.OperationalError: - print('TABLE NOT FOUND: ' + old_name) + print("TABLE NOT FOUND: " + old_name) continue if not data: - print('No data for: ' + old_name) + print("No data for: " + old_name) continue new_cols: list[str] = [ - c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall() + c[1] for c in con_new.execute(f"PRAGMA table_info({new_name});").fetchall() ] - op_index = new_cols.index('operator') + op_index = new_cols.index("operator") data = [(*row[0:op_index], operator, *row[op_index:len(new_cols)-1]) for row in data] # construct the query with correct number of placeholders num_placeholders = len(data[0]) - placeholders = ','.join(['?' for _ in range(num_placeholders)]) - query = f'INSERT OR REPLACE INTO {new_name} VALUES ({placeholders})' + placeholders = ",".join(["?" for _ in range(num_placeholders)]) + query = f"INSERT OR REPLACE INTO {new_name} VALUES ({placeholders})" con_new.executemany(query, data) - print(f'Transfered {len(data)} rows from {old_name} to {new_name}') + print(f"Transfered {len(data)} rows from {old_name} to {new_name}") # It wasn't active anyway... can't be bothered # StorageInit -> LimitStorageLevelFraction # execute the direct transfers -print('\n --- Executing direct transfers ---') +print("\n --- Executing direct transfers ---") for old_name, new_name in direct_transfer_tables: - if old_name == '': + if old_name == "": old_name = new_name try: - con_old.execute(f'SELECT * FROM {old_name}').fetchone() + con_old.execute(f"SELECT * FROM {old_name}").fetchone() except sqlite3.OperationalError: - print('TABLE NOT FOUND: ' + old_name) + print("TABLE NOT FOUND: " + old_name) continue - old_columns = [c[1] for c in con_old.execute(f'PRAGMA table_info({old_name});').fetchall()] - new_columns = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] + old_columns = [c[1] for c in con_old.execute(f"PRAGMA table_info({old_name});").fetchall()] + new_columns = [c[1] for c in con_new.execute(f"PRAGMA table_info({new_name});").fetchall()] cols = [c for c in new_columns if c in old_columns] data = con_old.execute(f'SELECT {str(cols)[1:-1].replace("'","")} FROM {old_name}').fetchall() if not data: - print('No data for: ' + old_name) + print("No data for: " + old_name) continue # construct the query with correct number of placeholders num_placeholders = len(data[0]) - placeholders = ','.join(['?' for _ in range(num_placeholders)]) + placeholders = ",".join(["?" for _ in range(num_placeholders)]) query = ( - 'INSERT OR REPLACE INTO ' - f'{new_name}{tuple(c for c in cols) if len(cols)>1 else f'({cols[0]})'} ' - f'VALUES ({placeholders})' + "INSERT OR REPLACE INTO " + f"{new_name}{tuple(c for c in cols) if len(cols)>1 else f'({cols[0]})'} " + f"VALUES ({placeholders})" ) con_new.executemany(query, data) - print(f'Transfered {len(data)} rows from {old_name} to {new_name}') + print(f"Transfered {len(data)} rows from {old_name} to {new_name}") time_all = [ - p[0] for p in cur.execute('SELECT period FROM TimePeriod').fetchall() + p[0] for p in cur.execute("SELECT period FROM TimePeriod").fetchall() ] time_all = sorted(time_all)[0:-1] # Exclude horizon end # get lifetimes. Major headache but needs to be done lifetime_process = {} -data = cur.execute('SELECT region, tech, vintage FROM Efficiency').fetchall() +data = cur.execute("SELECT region, tech, vintage FROM Efficiency").fetchall() for rtv in data: lifetime_process[rtv] = TemoaModel.default_lifetime_tech -data = cur.execute('SELECT region, tech, lifetime FROM LifetimeTech').fetchall() +data = cur.execute("SELECT region, tech, lifetime FROM LifetimeTech").fetchall() for rtl in data: for v in time_all: lifetime_process[*rtl[0:2], v] = rtl[2] -data = cur.execute('SELECT region, tech, vintage, lifetime FROM LifetimeProcess').fetchall() +data = cur.execute("SELECT region, tech, vintage, lifetime FROM LifetimeProcess").fetchall() for rtvl in data: lifetime_process[rtvl[0:3]] = rtvl[3] @@ -256,38 +256,38 @@ def column_check(old_name: str, new_name: str) -> bool: time_optimize = sorted(time_optimize)[0:-1] # Exclude horizon end # add period indexing to seasonal tables -print('\n --- Adding period index to some tables ---') +print("\n --- Adding period index to some tables ---") for old_name, new_name in period_added_tables: - if old_name == '': + if old_name == "": old_name = new_name try: - con_old.execute(f'SELECT * FROM {old_name}').fetchone() + con_old.execute(f"SELECT * FROM {old_name}").fetchone() except sqlite3.OperationalError: - print('TABLE NOT FOUND: ' + old_name) + print("TABLE NOT FOUND: " + old_name) continue - old_columns = [c[1] for c in con_old.execute(f'PRAGMA table_info({old_name});').fetchall()] - new_columns = [c[1] for c in con_new.execute(f'PRAGMA table_info({new_name});').fetchall()] + old_columns = [c[1] for c in con_old.execute(f"PRAGMA table_info({old_name});").fetchall()] + new_columns = [c[1] for c in con_new.execute(f"PRAGMA table_info({new_name});").fetchall()] cols = [c for c in new_columns if c in old_columns] data = pd.read_sql_query(f'SELECT {str(cols)[1:-1].replace("'","")} FROM {old_name}', con_old) if len(data) == 0: - print('No data for: ' + old_name) + print("No data for: " + old_name) continue # This insanity collects the viable periods for each table - if 'vintage' in cols: - data['periods'] = [ + if "vintage" in cols: + data["periods"] = [ ( p for p in time_optimize if v <= p < v+lifetime_process[r, t, v] ) - for r, t, v in data[['region','tech','vintage']] + for r, t, v in data[["region","tech","vintage"]] ] - elif 'tech' in cols: + elif "tech" in cols: periods = {} - for r, t in data[['region','tech']].drop_duplicates().values: + for r, t in data[["region","tech"]].drop_duplicates().values: periods[r, t] = [ p for p in time_optimize if any( @@ -300,41 +300,41 @@ def column_check(old_name: str, new_name: str) -> bool: ] ) ] - data['periods'] = [ + data["periods"] = [ periods[r, t] - for (r, t) in data[['region','tech']].values + for (r, t) in data[["region","tech"]].values ] else: - data['periods'] = [time_optimize for i in data.index] + data["periods"] = [time_optimize for i in data.index] data_new = [] for p in time_optimize: for _idx, row in data.iterrows(): - if p not in row['periods']: + if p not in row["periods"]: continue - if old_name[0:5] == 'TimeS': # horrible but covers TimeSeason and TimeSegmentFraction + if old_name[0:5] == "TimeS": # horrible but covers TimeSeason and TimeSegmentFraction data_new.append((p, *row.iloc[0:-1])) else: data_new.append((row.iloc[0], p, *row.iloc[1:-1])) - if old_name[0:5] == 'TimeS': # horrible but covers TimeSeason and TimeSegmentFraction - cols = ['period',*cols] + if old_name[0:5] == "TimeS": # horrible but covers TimeSeason and TimeSegmentFraction + cols = ["period",*cols] else: - cols = [cols[0],'period',*cols[1::]] + cols = [cols[0],"period",*cols[1::]] # construct the query with correct number of placeholders num_placeholders = len(data_new[0]) - placeholders = ','.join(['?' for _ in range(num_placeholders)]) + placeholders = ",".join(["?" for _ in range(num_placeholders)]) query = ( - 'INSERT OR REPLACE INTO ' - f'{new_name}{tuple(c for c in cols) if len(cols)>1 else f'({cols[0]})'} ' - f'VALUES ({placeholders})' + "INSERT OR REPLACE INTO " + f"{new_name}{tuple(c for c in cols) if len(cols)>1 else f'({cols[0]})'} " + f"VALUES ({placeholders})" ) con_new.executemany(query, data_new) - print(f'Transfered {len(data_new)} rows from {old_name} to {new_name}') + print(f"Transfered {len(data_new)} rows from {old_name} to {new_name}") -print('\n --- Making some final changes ---') +print("\n --- Making some final changes ---") n_del = len(con_new.execute( "SELECT * FROM DemandSpecificDistribution " "WHERE (region, period, demand_name) " @@ -352,20 +352,20 @@ def column_check(old_name: str, new_name: str) -> bool: # TimeSeason unique seasons to SeasonLabel con_new.execute("INSERT OR REPLACE INTO SeasonLabel(season) SELECT DISTINCT season FROM TimeSeason") -print('Filled SeasonLabel') +print("Filled SeasonLabel") # Removal of tech_resource con_new.execute("UPDATE Technology SET flag='p' WHERE flag=='r';") -print('Converted all resource techs to production techs.') +print("Converted all resource techs to production techs.") # LoanLifetimeTech -> LoanLifetimeProcess try: - data = con_old.execute('SELECT region, tech, lifetime, notes FROM LoanLifetimeTech').fetchall() + data = con_old.execute("SELECT region, tech, lifetime, notes FROM LoanLifetimeTech").fetchall() except sqlite3.OperationalError: - print('TABLE NOT FOUND: LoanLifetimeTech') + print("TABLE NOT FOUND: LoanLifetimeTech") if not data: - print('No data for: LoanLifetimeTech') + print("No data for: LoanLifetimeTech") else: new_data = [] for row in data: @@ -377,21 +377,21 @@ def column_check(old_name: str, new_name: str) -> bool: ] for v in vints: new_data.append((row[0], row[1], v, row[2], row[3])) - query = 'INSERT OR REPLACE INTO LoanLifetimeProcess VALUES (?,?,?,?,?)' + query = "INSERT OR REPLACE INTO LoanLifetimeProcess VALUES (?,?,?,?,?)" con_new.executemany(query, new_data) - print(f'Transfered {len(new_data)} rows from LifetimeLoanTech to LifetimeLoanProcess') + print(f"Transfered {len(new_data)} rows from LifetimeLoanTech to LifetimeLoanProcess") # Warn about incompatible changes print( - '\n --- The following transfers were impossible due to incompatible changes. Transfer ' - 'manually. ---' + "\n --- The following transfers were impossible due to incompatible changes. Transfer " + "manually. ---" ) for old_name, new_name in no_transfer.items(): - print(f'{old_name} to {new_name}') + print(f"{old_name} to {new_name}") -print('\n --- Updating MetaData ---') +print("\n --- Updating MetaData ---") cur.execute("DELETE FROM MetaData WHERE element == 'myopic_base_year'") print( "myopic_base_year removed from MetaData. This parameter is no longer used. " \ @@ -402,25 +402,25 @@ def column_check(old_name: str, new_name: str) -> bool: -print('\n --- Validating foreign keys ---') +print("\n --- Validating foreign keys ---") con_new.commit() -con_new.execute('VACUUM;') -con_new.execute('PRAGMA FOREIGN_KEYS=1;') +con_new.execute("VACUUM;") +con_new.execute("PRAGMA FOREIGN_KEYS=1;") try: - data = con_new.execute('PRAGMA FOREIGN_KEY_CHECK;').fetchall() + data = con_new.execute("PRAGMA FOREIGN_KEY_CHECK;").fetchall() if not data: - print('No Foreign Key Failures. (Good news!)') + print("No Foreign Key Failures. (Good news!)") else: - print('\nFK check fails (MUST BE FIXED):') - print('(Table, Row ID, Reference Table, (fkid) )') + print("\nFK check fails (MUST BE FIXED):") + print("(Table, Row ID, Reference Table, (fkid) )") for row in data: print(row) except sqlite3.OperationalError as e: - print('Foreign Key Check FAILED on new DB. Something may be wrong with schema.') + print("Foreign Key Check FAILED on new DB. Something may be wrong with schema.") print(e) -print('\nFinished! Check your database for any missing data.' - ' If there was a mismatch of table names, something may have been lost.') +print("\nFinished! Check your database for any missing data." + " If there was a mismatch of table names, something may have been lost.") con_new.close() con_old.close() From 1fbb1f1c7944c8fd1efb62081ee1f67b63ef00fd Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 25 Nov 2025 17:43:30 -0500 Subject: [PATCH 372/587] adding macos to ci testing and correcting some tests to pass on macos --- .github/workflows/ci.yml | 20 +++++++++++++++++--- tests/test_cli.py | 29 ++++++++++++++++++----------- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8faac9d88..059b464f8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,9 +25,10 @@ on: jobs: test: name: setup and test - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} strategy: matrix: + os: [ubuntu-latest, macos-latest] python-version: ["3.12", "3.13"] steps: @@ -43,14 +44,27 @@ jobs: - name: Install the project run: uv sync --locked --all-extras --dev - - name: Install CBC solver + - name: Install CBC solver (Ubuntu) + if: runner.os == 'Linux' run: | sudo apt-get update sudo apt-get install -y coinor-cbc - - name: Install Graphviz + - name: Install CBC solver (macOS) + if: runner.os == 'macOS' + run: | + brew tap coin-or-tools/coinor + brew install coin-or-tools/coinor/cbc + echo "/opt/homebrew/opt/cbc/bin" >> $GITHUB_PATH + + - name: Install Graphviz (Ubuntu) + if: runner.os == 'Linux' run: sudo apt-get install -y graphviz + - name: Install Graphviz (macOS) + if: runner.os == 'macOS' + run: brew install graphviz + - name: Run tests env: CI: 1 diff --git a/tests/test_cli.py b/tests/test_cli.py index b1823fb17..7b279492b 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -179,8 +179,11 @@ def test_cli_migrate_rejects_directory_input(tmp_path: Path) -> None: result = runner.invoke(app, args) assert result.exit_code != 0 - assert 'Error: Input path must be a file, not a directory:' in result.stdout - assert str(dummy_dir) in result.stdout + # Normalize whitespace to handle platform-specific line breaks from rich.print() + normalized_output = ' '.join(result.stdout.split()) + assert 'Error: Input path must be a file, not a directory:' in normalized_output + # Check for the directory name in the original output (paths may be split across lines) + assert 'my_dummy_dir' in result.stdout def test_cli_migrate_sql_file_auto_output_writable_input_dir(tmp_path: Path) -> None: @@ -242,12 +245,14 @@ def mock_is_writable(path: Path) -> bool: assert result.exit_code == 0, ( f'Migration failed: {result.exception}\n{result.stderr}\n{result.stdout}' ) - assert 'SQL dump migration completed' in result.stdout - assert 'Warning: Input directory' in result.stdout - assert str(non_writable_mock_parent) in result.stdout - assert 'is not writable.' in result.stdout - assert 'Saving output to current directory:' in result.stdout - assert str(tmp_path) in result.stdout + # Normalize whitespace to handle platform-specific line breaks from rich.print() + normalized_output = ' '.join(result.stdout.split()) + assert 'SQL dump migration completed' in normalized_output + assert 'Warning: Input directory' in normalized_output + assert str(non_writable_mock_parent) in normalized_output + assert 'is not writable.' in normalized_output + assert 'Saving output to current directory:' in normalized_output + assert str(tmp_path) in normalized_output expected_output_in_cwd = tmp_path / (input_file.stem + '_v4.sql') assert expected_output_in_cwd.exists() @@ -279,9 +284,11 @@ def mock_is_writable_always_false(_path: Path) -> bool: result = runner.invoke(app, args, catch_exceptions=False) assert result.exit_code != 0, 'Migration should fail with a non-zero exit code' - assert 'Error: Neither input directory' in result.stdout - assert 'nor current working directory' in result.stdout - assert 'are writable.' in result.stdout + # Normalize whitespace to handle platform-specific line breaks from rich.print() + normalized_output = ' '.join(result.stdout.split()) + assert 'Error: Neither input directory' in normalized_output + assert 'nor current working directory' in normalized_output + assert 'are writable.' in normalized_output assert not ( tmp_path / (input_file.stem + '_v4' + input_file.suffix) ).exists() # No output created From d7856a0773e2811caaa03a9ad2cd85bf3b51a2ca Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 26 Nov 2025 11:49:52 -0500 Subject: [PATCH 373/587] fix: fixing eager path checking causing python solvers that are not in path to be unusable --- temoa/core/config.py | 55 ++++++++++++++++++++++++++++++++++++-------- tests/test_cli.py | 8 ++----- 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/temoa/core/config.py b/temoa/core/config.py index c06d5439a..077e86a68 100644 --- a/temoa/core/config.py +++ b/temoa/core/config.py @@ -24,10 +24,7 @@ class SolverNotAvailableError(Exception): 'https://www.ibm.com/products/ilog-cplex-optimization-studio ' '(requires license and installation)' ), - 'highs': ( - 'https://ergo-code.github.io/HiGHS/dev/installation/ ' - '(refer to documentation for specific OS steps)' - ), + 'highs': ('Did you mean to use appsi_highs? '), 'glpk': 'https://www.gnu.org/software/glpk/', } @@ -157,6 +154,45 @@ def __init__( if not self.silent: sys.stderr.write('Warning: ' + msg) + @staticmethod + def _check_solver_availability(solver_name: str) -> tuple[bool, str | None]: + """ + Check if a solver is available, supporting both Python-based and system executable solvers. + + Args: + solver_name: Name of the solver to check + + Returns: + Tuple of (is_available, location_or_message) + """ + # First, try to check if it's available through Pyomo (works for Python-based solvers) + try: + import pyomo.environ as pyo + + solver = pyo.SolverFactory(solver_name) + if solver.available(): + # For Python-based solvers like appsi_highs + if solver_name.startswith('appsi_'): + return True, 'available via Pyomo (Python package)' + # For other solvers, try to get the executable path + try: + exec_path = solver.executable() + return True, exec_path.name if hasattr(exec_path, 'name') else str(exec_path) + except Exception as e: + logger.debug('Could not get executable path for %s: %s', solver_name, e) + return True, 'available via Pyomo' + + except Exception as e: + logger.debug('Could not check solver availability for %s: %s', solver_name, e) + pass + + # Fallback: check if it's a system executable + solver_executable = shutil.which(solver_name) + if solver_executable is not None: + return True, solver_executable + + return False, None + @staticmethod def build_config(config_file: Path, output_path: Path, silent: bool = False) -> 'TemoaConfig': """ @@ -170,12 +206,11 @@ def build_config(config_file: Path, output_path: Path, silent: bool = False) -> data = tomllib.load(f) if 'solver_name' in data: - solver_executable = shutil.which(data['solver_name']) - if solver_executable is None: + is_available, location = TemoaConfig._check_solver_availability(data['solver_name']) + if not is_available: error_message = ( - f"The specified solver '{data['solver_name']}' was not found in your system's " - 'PATH.\n' - 'Please ensure the solver is installed and its executable is accessible.\n' + f"The specified solver '{data['solver_name']}' was not found.\n" + 'Please ensure the solver is installed and accessible.\n' ) if data['solver_name'].lower() in SOLVER_DOC_LINKS: link = SOLVER_DOC_LINKS[data['solver_name'].lower()] @@ -187,7 +222,7 @@ def build_config(config_file: Path, output_path: Path, silent: bool = False) -> ) raise SolverNotAvailableError(error_message) else: - logger.info('Using solver: %s found at %s', data['solver_name'], solver_executable) + logger.info('Using solver: %s (%s)', data['solver_name'], location) else: raise SolverNotAvailableError('No solver name specified in the configuration.') diff --git a/tests/test_cli.py b/tests/test_cli.py index 7b279492b..249003a2b 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -516,9 +516,7 @@ def test_cli_validate_fails_if_solver_missing( assert 'āŒ Validation failed:' in result.stdout assert 'nonexistent_solver' in result.stdout # Use the more robust phrase for checking installation instructions - assert ( - 'Please ensure the solver is installed and its executable is accessible.' in result.stdout - ) + assert 'Please ensure the solver is installed and accessible.' in result.stdout assert (tmp_path / 'temoa-run.log').exists() @@ -544,7 +542,5 @@ def test_cli_run_fails_if_solver_missing(tmp_path: Path, monkeypatch: pytest.Mon assert 'āŒ An error occurred:' in result.stdout assert 'another_nonexistent_solver' in result.stdout # Use the more robust phrase for checking installation instructions - assert ( - 'Please ensure the solver is installed and its executable is accessible.' in result.stdout - ) + assert 'Please ensure the solver is installed and accessible.' in result.stdout assert (tmp_path / 'temoa-run.log').exists() From 1bf0e5111a8ea3377be8fdb7ef5f0005915be212 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 26 Nov 2025 12:12:55 -0500 Subject: [PATCH 374/587] fix: Fixing multiprocessing issues that prevented highs solver from being usable for MGA and MC --- temoa/_internal/temoa_sequencer.py | 10 --- .../worker.py | 66 +++++++------------ temoa/extensions/monte_carlo/mc_worker.py | 42 ++++-------- .../testing_configs/config_utopia_myopic.toml | 2 +- 4 files changed, 38 insertions(+), 82 deletions(-) diff --git a/temoa/_internal/temoa_sequencer.py b/temoa/_internal/temoa_sequencer.py index ad28f2377..81accbf56 100644 --- a/temoa/_internal/temoa_sequencer.py +++ b/temoa/_internal/temoa_sequencer.py @@ -154,11 +154,6 @@ def start(self) -> None: myopic_sequencer.start() case TemoaMode.MGA: - if self.config.solver_name == 'appsi_highs': - raise ValueError( - 'MGA mode is not compatible with the HiGHS solver due to a multiprocessing ' - 'issue.' - ) mga_sequencer = MgaSequencer(config=self.config) mga_sequencer.start() @@ -228,11 +223,6 @@ def _run_perfect_foresight(self) -> None: def _run_monte_carlo(self) -> None: """Encapsulated logic for the MONTE_CARLO mode.""" - if self.config.solver_name == 'appsi_highs': - raise ValueError( - 'Monte Carlo mode is not compatible with the HiGHS solver due to a multiprocessing ' - 'issue.' - ) # Disable features not typically used in Monte Carlo runs to reduce noise/overhead if self.config.plot_commodity_network: diff --git a/temoa/extensions/modeling_to_generate_alternatives/worker.py b/temoa/extensions/modeling_to_generate_alternatives/worker.py index 1c1ba999c..62dd458c6 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/worker.py +++ b/temoa/extensions/modeling_to_generate_alternatives/worker.py @@ -1,31 +1,5 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 5/5/24 - Class to contain Workers that execute solves in separate processes - """ import logging.handlers @@ -33,10 +7,12 @@ from logging import getLogger from multiprocessing import Process, Queue from pathlib import Path +from typing import TYPE_CHECKING from pyomo.opt import SolverFactory, SolverResults, check_optimal_termination -from temoa.core.model import TemoaModel +if TYPE_CHECKING: + from temoa.core.model import TemoaModel verbose = False # for T/S or monitoring... @@ -48,36 +24,42 @@ def __init__( self, model_queue: Queue, results_queue: Queue, - log_root_name, - log_queue, - log_level, + log_root_name: str, + log_queue: Queue, + log_level: int = logging.INFO, + solver_name: str = 'appsi_highs', + solver_options: dict | None = None, solver_log_path: Path | None = None, - **kwargs, ): - super(Worker, self).__init__(daemon=True) + super().__init__(daemon=True) self.worker_number = Worker.worker_idx Worker.worker_idx += 1 self.model_queue: Queue = model_queue self.results_queue: Queue = results_queue - self.solver_name = kwargs['solver_name'] - self.solver_options = kwargs['solver_options'] - self.opt = SolverFactory(self.solver_name, options=self.solver_options) self.log_queue = log_queue - self.log_level = log_level - self.root_logger_name = log_root_name + self.solver_name = solver_name + self.solver_options = solver_options or {} self.solver_log_path = solver_log_path + self.opt = None # Initialize in run() + + self.log_root_name = log_root_name + self.log_level = log_level self.solve_count = 0 def run(self): - logger = getLogger('.'.join((self.root_logger_name, 'worker', str(self.worker_number)))) - logger.setLevel(self.log_level) - logger.propagate = ( - False # not propagating up the chain fixes issue on TRACE where we were getting dupes. - ) + logger = getLogger('.'.join((self.log_root_name, 'worker', str(self.worker_number)))) + logger.propagate = False # prevent duplicate logs + # add a handler that pushes to the queue handler = logging.handlers.QueueHandler(self.log_queue) + logger.setLevel(self.log_level) logger.addHandler(handler) logger.info('Worker %d spun up', self.worker_number) + # Initialize the solver here in the child process to avoid pickling issues + # Note: We do not set the options here because appsi_highs does not accept options in + # __init__. We can set them later via self.opt.options + self.opt = SolverFactory(self.solver_name) + # update the solver options to pass in a log location while True: if self.solver_log_path: diff --git a/temoa/extensions/monte_carlo/mc_worker.py b/temoa/extensions/monte_carlo/mc_worker.py index 622271ea7..67072cd7f 100644 --- a/temoa/extensions/monte_carlo/mc_worker.py +++ b/temoa/extensions/monte_carlo/mc_worker.py @@ -1,28 +1,4 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 5/5/24 Class to contain Workers that execute solves in separate processes @@ -39,13 +15,16 @@ from logging import getLogger from multiprocessing import Process, Queue from pathlib import Path +from typing import TYPE_CHECKING -from pyomo.dataportal import DataPortal from pyomo.opt import SolverFactory, SolverResults, check_optimal_termination from temoa._internal.data_brick import DataBrick, data_brick_factory from temoa.core.model import TemoaModel +if TYPE_CHECKING: + from pyomo.dataportal import DataPortal + verbose = False # for T/S or monitoring... @@ -56,9 +35,9 @@ def __init__( self, dp_queue: Queue, results_queue: Queue, - log_root_name, - log_queue, - log_level, + log_root_name: str, + log_queue: Queue, + log_level: int = logging.INFO, solver_log_path: Path | None = None, **kwargs, ): @@ -69,7 +48,7 @@ def __init__( self.results_queue: Queue[DataBrick | str] = results_queue self.solver_name = kwargs['solver_name'] self.solver_options = kwargs['solver_options'] - self.opt = SolverFactory(self.solver_name, options=self.solver_options) + self.opt = None # Initialize in run() self.log_queue = log_queue self.log_level = log_level self.root_logger_name = log_root_name @@ -86,6 +65,11 @@ def run(self): logger.addHandler(handler) logger.info('Worker %d spun up', self.worker_number) + # Initialize the solver here in the child process to avoid pickling issues + # Note: We do not set the options here because appsi_highs does not accept options in + # __init__. We can set them later via self.opt.options + self.opt = SolverFactory(self.solver_name) + # update the solver options to pass in a log location while True: if self.solver_log_path: diff --git a/tests/testing_configs/config_utopia_myopic.toml b/tests/testing_configs/config_utopia_myopic.toml index ccb6d987b..e5f0f1fe8 100644 --- a/tests/testing_configs/config_utopia_myopic.toml +++ b/tests/testing_configs/config_utopia_myopic.toml @@ -9,7 +9,7 @@ output_database = "tests/testing_outputs/myo_utopia.sqlite" neos = false # solver -solver_name = "cbc" +solver_name = "appsi_highs" # generate an excel file in the output_files folder save_excel = true From a95db8f2a75d51bfc3987d68368293ae8f747412 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 26 Nov 2025 14:38:52 -0500 Subject: [PATCH 375/587] changing tests to use highs instead of cbc --- tests/test_cli.py | 85 ------------------- tests/test_full_runs.py | 15 +++- .../config_annualised_demand.toml | 2 +- tests/testing_configs/config_emissions.toml | 2 +- tests/testing_configs/config_link_test.toml | 2 +- tests/testing_configs/config_materials.toml | 2 +- tests/testing_configs/config_mediumville.toml | 2 +- .../config_seasonal_storage.toml | 2 +- .../testing_configs/config_storageville.toml | 2 +- .../config_survival_curve.toml | 2 +- tests/testing_configs/config_test_system.toml | 2 +- tests/testing_configs/config_utopia.toml | 2 +- tests/testing_configs/config_utopia_gv.toml | 2 +- tests/utilities/config_US_9R_8D.toml | 6 +- tests/utilities/config_mediumville.toml | 6 +- tests/utilities/config_test_system.toml | 6 +- tests/utilities/config_utopia.toml | 6 +- 17 files changed, 26 insertions(+), 120 deletions(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index 249003a2b..3b85716b6 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -407,91 +407,6 @@ def mock_is_writable(path: Path) -> bool: assert not (non_writable_mock_parent / (input_file.stem + '_v4.sql')).exists() -# ============================================================================= -# Tests for Solver Checks -# ============================================================================= - - -def test_cli_tutorial_warns_if_cbc_missing(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: - """ - Test that the tutorial command warns if CBC is not found. - """ - # Ensure fallback tutorial_assets exists so _copy_tutorial_resources() works via fallback. - fallback_assets = Path(__file__).parent.parent / 'temoa' / 'tutorial_assets' - if not fallback_assets.exists(): - pytest.skip("Skipping tutorial tests as 'temoa/tutorial_assets' directory not found.") - - # Mock shutil.which to simulate CBC not being found - def mock_which_no_cbc(cmd: str) -> None | str: - if cmd == 'cbc': - return None - return shutil.which(cmd) - - monkeypatch.setattr(shutil, 'which', mock_which_no_cbc) - monkeypatch.setattr('temoa.cli._check_cbc_availability', lambda: False) - - # Run the tutorial command in tmp_path as CWD - monkeypatch.chdir(tmp_path) - - result = runner.invoke( - app, - ['tutorial', 'test_config', 'test_db', '--force'], - catch_exceptions=False, - ) - - assert result.exit_code == 0, ( - f'Tutorial command failed: {result.exception}\n{result.stderr}\n{result.stdout}' - ) - assert 'Tutorial Setup Complete!' in result.stdout - assert 'Important: CBC Solver Not Found' in result.stdout - assert 'The default tutorial configuration uses the CBC solver' in result.stdout - - # Just assert that the known URL is present, ignoring line breaks / extra text - assert 'https://github.com/coin-or/Cbc#download' in result.stdout - - # Files should be created in the current working directory (= tmp_path) - assert (tmp_path / 'test_config.toml').exists() - assert (tmp_path / 'test_db.sqlite').exists() - - -def test_cli_tutorial_no_warn_if_cbc_present( - tmp_path: Path, monkeypatch: pytest.MonkeyPatch -) -> None: - """ - Test that the tutorial command does NOT warn if CBC is found. - """ - fallback_assets = Path(__file__).parent.parent / 'temoa' / 'tutorial_assets' - if not fallback_assets.exists(): - pytest.skip("Skipping tutorial tests as 'temoa/tutorial_assets' directory not found.") - - # Mock shutil.which to simulate CBC being found - def mock_which_with_cbc(cmd: str) -> str | None: - if cmd == 'cbc': - return '/usr/local/bin/cbc' - return shutil.which(cmd) - - monkeypatch.setattr(shutil, 'which', mock_which_with_cbc) - monkeypatch.setattr('temoa.cli._check_cbc_availability', lambda: True) - - # Run in tmp_path so tutorial files are created there - monkeypatch.chdir(tmp_path) - - result = runner.invoke( - app, - ['tutorial', 'test_config', 'test_db', '--force'], - catch_exceptions=False, - ) - - assert result.exit_code == 0, ( - f'Tutorial command failed: {result.exception}\n{result.stderr}\n{result.stdout}' - ) - assert 'Tutorial Setup Complete!' in result.stdout - assert 'Important: CBC Solver Not Found' not in result.stdout - - assert (tmp_path / 'test_config.toml').exists() - assert (tmp_path / 'test_db.sqlite').exists() - - def test_cli_validate_fails_if_solver_missing( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: diff --git a/tests/test_full_runs.py b/tests/test_full_runs.py index f4e424b5f..029df9962 100644 --- a/tests/test_full_runs.py +++ b/tests/test_full_runs.py @@ -54,10 +54,17 @@ def test_against_legacy_outputs( assert expected_vals is not None, f'No expected values for {data_name}' # Inspect some summary results - assert res['Solution'][0]['Status'] == 'optimal' - assert res['Solution'][0]['Objective']['total_cost']['Value'] == pytest.approx( - expected_vals[ExpectedVals.OBJ_VALUE], 0.00001 - ) + # Use check_optimal_termination instead of checking raw status string + # Different solvers report status differently (e.g., HiGHS reports 'unknown' but is optimal) + from pyomo.environ import check_optimal_termination + + assert check_optimal_termination(res), f'Solver did not terminate optimally for {data_name}' + # Get objective value from the model instance instead of results object + # HiGHS doesn't populate the results object the same way as CBC + from pyomo.environ import value + + obj_value = value(mdl.total_cost) + assert obj_value == pytest.approx(expected_vals[ExpectedVals.OBJ_VALUE], 0.00001) # inspect a couple set sizes efficiency_param: pyo.Param = mdl.efficiency diff --git a/tests/testing_configs/config_annualised_demand.toml b/tests/testing_configs/config_annualised_demand.toml index ef89e26f6..9506d7b11 100644 --- a/tests/testing_configs/config_annualised_demand.toml +++ b/tests/testing_configs/config_annualised_demand.toml @@ -7,7 +7,7 @@ output_database = "tests/testing_outputs/annualised_demand.sqlite" neos = false # solver -solver_name = "cbc" +solver_name = "appsi_highs" # generate an excel file in the output_files folder save_excel = false diff --git a/tests/testing_configs/config_emissions.toml b/tests/testing_configs/config_emissions.toml index 11ab97cbb..c131806cf 100644 --- a/tests/testing_configs/config_emissions.toml +++ b/tests/testing_configs/config_emissions.toml @@ -7,7 +7,7 @@ output_database = "tests/testing_outputs/emissions.sqlite" neos = false # solver -solver_name = "cbc" +solver_name = "appsi_highs" # generate an excel file in the output_files folder save_excel = false diff --git a/tests/testing_configs/config_link_test.toml b/tests/testing_configs/config_link_test.toml index 2fca42dbf..0a3783179 100644 --- a/tests/testing_configs/config_link_test.toml +++ b/tests/testing_configs/config_link_test.toml @@ -55,7 +55,7 @@ neos = false # solver (Mandatory) # Depending on what client machine has installed. # [cbc, appsi_highs, gurobi, cplex, ...] -solver_name = "cbc" +solver_name = "appsi_highs" # ------------------------------------ # OUTPUTS diff --git a/tests/testing_configs/config_materials.toml b/tests/testing_configs/config_materials.toml index d9ec078aa..b70404fea 100644 --- a/tests/testing_configs/config_materials.toml +++ b/tests/testing_configs/config_materials.toml @@ -7,7 +7,7 @@ output_database = "tests/testing_outputs/materials.sqlite" neos = false # solver -solver_name = "cbc" +solver_name = "appsi_highs" # generate an excel file in the output_files folder save_excel = false diff --git a/tests/testing_configs/config_mediumville.toml b/tests/testing_configs/config_mediumville.toml index 8c5761e22..0376832ec 100644 --- a/tests/testing_configs/config_mediumville.toml +++ b/tests/testing_configs/config_mediumville.toml @@ -36,7 +36,7 @@ output_database = "tests/testing_outputs/mediumville.sqlite" neos = false # solver -solver_name = "cbc" +solver_name = "appsi_highs" # ------------------------------------ # OUTPUTS diff --git a/tests/testing_configs/config_seasonal_storage.toml b/tests/testing_configs/config_seasonal_storage.toml index c1e257690..fa7fac063 100644 --- a/tests/testing_configs/config_seasonal_storage.toml +++ b/tests/testing_configs/config_seasonal_storage.toml @@ -7,7 +7,7 @@ output_database = "tests/testing_outputs/seasonal_storage.sqlite" neos = false # solver -solver_name = "cbc" +solver_name = "appsi_highs" # generate an excel file in the output_files folder save_excel = false diff --git a/tests/testing_configs/config_storageville.toml b/tests/testing_configs/config_storageville.toml index 5393e8309..fe96195f6 100644 --- a/tests/testing_configs/config_storageville.toml +++ b/tests/testing_configs/config_storageville.toml @@ -36,7 +36,7 @@ output_database = "tests/testing_outputs/storageville.sqlite" neos = false # solver -solver_name = "cbc" +solver_name = "appsi_highs" # ------------------------------------ # OUTPUTS diff --git a/tests/testing_configs/config_survival_curve.toml b/tests/testing_configs/config_survival_curve.toml index ba304efbf..c59abb9c6 100644 --- a/tests/testing_configs/config_survival_curve.toml +++ b/tests/testing_configs/config_survival_curve.toml @@ -7,7 +7,7 @@ output_database = "tests/testing_outputs/survival_curve.sqlite" neos = false # solver -solver_name = "cbc" +solver_name = "appsi_highs" # generate an excel file in the output_files folder save_excel = false diff --git a/tests/testing_configs/config_test_system.toml b/tests/testing_configs/config_test_system.toml index 7a13de4c5..d65c627f1 100644 --- a/tests/testing_configs/config_test_system.toml +++ b/tests/testing_configs/config_test_system.toml @@ -7,7 +7,7 @@ output_database = "tests/testing_outputs/test_system.sqlite" neos = false # solver -solver_name = "cbc" +solver_name = "appsi_highs" # generate an excel file in the output_files folder save_excel = false diff --git a/tests/testing_configs/config_utopia.toml b/tests/testing_configs/config_utopia.toml index 705d392d6..90ba74908 100644 --- a/tests/testing_configs/config_utopia.toml +++ b/tests/testing_configs/config_utopia.toml @@ -7,7 +7,7 @@ output_database = "tests/testing_outputs/utopia.sqlite" neos = false # solver -solver_name = "cbc" +solver_name = "appsi_highs" # generate an excel file in the output_files folder save_excel = false diff --git a/tests/testing_configs/config_utopia_gv.toml b/tests/testing_configs/config_utopia_gv.toml index d4c9b7444..54e048673 100644 --- a/tests/testing_configs/config_utopia_gv.toml +++ b/tests/testing_configs/config_utopia_gv.toml @@ -7,7 +7,7 @@ output_database = "tests/testing_outputs/utopia.sqlite" neos = false # solver -solver_name = "cbc" +solver_name = "appsi_highs" # generate an excel file in the output_files folder save_excel = false diff --git a/tests/utilities/config_US_9R_8D.toml b/tests/utilities/config_US_9R_8D.toml index 586ae1e5d..93c87051a 100644 --- a/tests/utilities/config_US_9R_8D.toml +++ b/tests/utilities/config_US_9R_8D.toml @@ -7,7 +7,7 @@ output_database = "../testing_outputs/US_9R_8D.sqlite" neos = false # solver -solver_name = "cbc" +solver_name = "appsi_highs" # generate an excel file in the output_files folder save_excel = false @@ -30,7 +30,3 @@ weight = "integer" # currently supported: [integer, normalized] [myopic] myopic_view = 2 # number of periods seen at one iteration - - - - diff --git a/tests/utilities/config_mediumville.toml b/tests/utilities/config_mediumville.toml index accac040a..5a0c0582f 100644 --- a/tests/utilities/config_mediumville.toml +++ b/tests/utilities/config_mediumville.toml @@ -36,7 +36,7 @@ output_database = "../testing_outputs/mediumville.sqlite" neos = false # solver -solver_name = "cbc" +solver_name = "appsi_highs" # ------------------------------------ # OUTPUTS @@ -64,7 +64,3 @@ weight = "integer" # currently supported: [integer, normalized] [myopic] myopic_view = 2 # number of periods seen at one iteration - - - - diff --git a/tests/utilities/config_test_system.toml b/tests/utilities/config_test_system.toml index bab80ff0a..50ff7737a 100644 --- a/tests/utilities/config_test_system.toml +++ b/tests/utilities/config_test_system.toml @@ -7,7 +7,7 @@ output_database = "../testing_outputs/test_system.sqlite" neos = false # solver -solver_name = "cbc" +solver_name = "appsi_highs" # generate an excel file in the output_files folder save_excel = false @@ -30,7 +30,3 @@ weight = "integer" # currently supported: [integer, normalized] [myopic] myopic_view = 2 # number of periods seen at one iteration - - - - diff --git a/tests/utilities/config_utopia.toml b/tests/utilities/config_utopia.toml index c5bcf4b90..c4db1213e 100644 --- a/tests/utilities/config_utopia.toml +++ b/tests/utilities/config_utopia.toml @@ -7,7 +7,7 @@ output_database = "../testing_outputs/utopia.sqlite" neos = false # solver -solver_name = "cbc" +solver_name = "appsi_highs" # generate an excel file in the output_files folder save_excel = false @@ -30,7 +30,3 @@ weight = "integer" # currently supported: [integer, normalized] [myopic] myopic_view = 2 # number of periods seen at one iteration - - - - From 767153686206a15ed2d68241b9ed69149e7f0a70 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 26 Nov 2025 14:42:21 -0500 Subject: [PATCH 376/587] changing cli and tutorial to use highs --- temoa/cli.py | 21 +-------------------- temoa/tutorial_assets/config_sample.toml | 7 +++++-- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/temoa/cli.py b/temoa/cli.py index 8971ae8fa..b8a573962 100644 --- a/temoa/cli.py +++ b/temoa/cli.py @@ -13,7 +13,7 @@ from rich.text import Text from temoa._internal.temoa_sequencer import TemoaSequencer -from temoa.core.config import SOLVER_DOC_LINKS, TemoaConfig +from temoa.core.config import TemoaConfig from temoa.core.modes import TemoaMode from temoa.utilities import db_migration_v3_1_to_v4, sql_migration_v3_1_to_v4 from temoa.version_information import TEMOA_MAJOR, TEMOA_MINOR @@ -98,14 +98,6 @@ def _setup_sequencer( return sequencer, final_output_path -def _check_cbc_availability() -> bool: - """ - Checks if the CBC solver is available in the system's PATH. - Returns True if found, False otherwise. - """ - return shutil.which('cbc') is not None - - # ============================================================================= # Callbacks and Typer App Setup # ============================================================================= @@ -607,17 +599,6 @@ def tutorial( ) rich.print("[dim]Results will be saved in the 'output_files' directory.[/dim]") - if not _check_cbc_availability(): - cbc_doc_link = SOLVER_DOC_LINKS.get('cbc') - rich.print('\n[bold yellow]āš ļø Important: CBC Solver Not Found[/bold yellow]') - rich.print( - 'The default tutorial configuration uses the [bold]CBC[/bold] solver, ' - "which was not found in your system's PATH.\n" - 'To run the tutorial model successfully, please install CBC. ' - f'Refer to this link for installation guidance: ' - f'[link={cbc_doc_link}]{cbc_doc_link}[/link]\n' - ) - except Exception as e: logger.exception('Failed to create tutorial files') rich.print(f'\n[bold red]āŒ Failed to create tutorial files:[/bold red] {e}') diff --git a/temoa/tutorial_assets/config_sample.toml b/temoa/tutorial_assets/config_sample.toml index 6fae53b0b..f36348e2c 100644 --- a/temoa/tutorial_assets/config_sample.toml +++ b/temoa/tutorial_assets/config_sample.toml @@ -56,8 +56,8 @@ neos = false # solver (Mandatory) # Depending on what client machine has installed. -# [cbc, appsi_highs, gurobi, cplex, ...] -solver_name = "cbc" +# [appsi_highs, cbc, gurobi, cplex, ...] +solver_name = "appsi_highs" # ------------------------------------ # OUTPUTS @@ -76,6 +76,9 @@ save_storage_levels = true # save a copy of the pyomo-generated lp file(s) to the outputs folder (maybe a large file(s)!) save_lp_file = false +# graphviz dot file and svg for network visualization (requires graphviz to be installed separately) +graphviz_output = false + # ------------------------------------ # MODEL PARAMETERS # these are specific to each model From 14d5adc32cef4daf85eae76e91c663856b3fd912 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 26 Nov 2025 14:43:54 -0500 Subject: [PATCH 377/587] updating CI to not install cbc --- .github/workflows/ci.yml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 059b464f8..a794319b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,19 +44,6 @@ jobs: - name: Install the project run: uv sync --locked --all-extras --dev - - name: Install CBC solver (Ubuntu) - if: runner.os == 'Linux' - run: | - sudo apt-get update - sudo apt-get install -y coinor-cbc - - - name: Install CBC solver (macOS) - if: runner.os == 'macOS' - run: | - brew tap coin-or-tools/coinor - brew install coin-or-tools/coinor/cbc - echo "/opt/homebrew/opt/cbc/bin" >> $GITHUB_PATH - - name: Install Graphviz (Ubuntu) if: runner.os == 'Linux' run: sudo apt-get install -y graphviz From a349102b9da96f0c35d2edc0992407a88b455a8b Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 26 Nov 2025 14:44:26 -0500 Subject: [PATCH 378/587] updating docs to refer to highs as default instead of cbc --- README.md | 12 ++++++++---- data_files/my_configs/config_sample.toml | 2 +- docs/source/quick_start.rst | 8 ++------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index a7873e06b..12f35dd09 100644 --- a/README.md +++ b/README.md @@ -182,7 +182,7 @@ config = TemoaConfig( input_database=Path("path/to/input.db"), output_database=Path("path/to/output.db"), output_path=Path("path/to/output"), - solver_name="cbc" + solver_name="appsi_highs" ) # Build and solve model @@ -230,7 +230,7 @@ scenario = "tutorial" scenario_mode = "perfect_foresight" input_database = "tutorial_database.sqlite" output_database = "tutorial_database.sqlite" -solver_name = "cbc" +solver_name = "appsi_highs" ``` ### Configuration Options @@ -243,7 +243,7 @@ solver_name = "cbc" | Price Checking | Run pricing analysis on built model | | Source Tracing | Verify commodity flow network integrity | | Plot Network | Generate HTML network visualizations | -| Solver | Solver executable name (cbc, gurobi, cplex, etc.) | +| Solver | Solver executable name (appsi_highs, cbc, gurobi, cplex, etc.) | | Save Excel | Export core output to Excel files | | Save LP | Save LP model files for external solving | @@ -325,9 +325,13 @@ Temoa includes optional extensions for advanced analysis: TEMOA requires at least one optimization solver: +- **Free**: [HiGHS](https://ergo-code.github.io/HiGHS/) + - Included via the `highspy` Python package (automatically installed with Temoa) + - Default solver for tutorial and testing + - **Free**: [CBC](https://github.com/coin-or/Cbc) - Requires separate installation (see [CBC documentation](https://github.com/coin-or/Cbc)) - - Required for tutorial and testing + - Alternative free solver option - **Commercial**: Gurobi, CPLEX, or Xpress - Requires separate license and installation diff --git a/data_files/my_configs/config_sample.toml b/data_files/my_configs/config_sample.toml index fe061efc6..063a7a8ba 100644 --- a/data_files/my_configs/config_sample.toml +++ b/data_files/my_configs/config_sample.toml @@ -58,7 +58,7 @@ neos = false # solver (Mandatory) # Depending on what client machine has installed. # [cbc, appsi_highs, gurobi, cplex, ...] -solver_name = "cbc" +solver_name = "appsi_highs" # ------------------------------------ # OUTPUTS diff --git a/docs/source/quick_start.rst b/docs/source/quick_start.rst index 9dcbc398c..d639f0bc0 100644 --- a/docs/source/quick_start.rst +++ b/docs/source/quick_start.rst @@ -75,11 +75,8 @@ commercial linear solvers such as `CPLEX `_ or `Gurobi `_. Both offer free academic licenses. -For smaller models, Temoa has been tested with both the `CBC `_ -solver and the more recently released `HiGHS `_ solver. -Each of the respective websites contains installation instructions for the individual -solvers. For those wishing to run the internal tests on Temoa, the :code:`CBC` solver -is required. +For smaller models, Temoa has been tested with the `HiGHS `_ +solver. HiGHS is automatically available when you install Temoa and requires no additional setup. Running Temoa @@ -304,4 +301,3 @@ may be produced by endogenous decisions in myopic runs. .. _sqlite: https://www.sqlite.org/ - From f1f186f10751f2d73fe0db418303e93afc63ebbd Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Wed, 26 Nov 2025 15:03:50 -0500 Subject: [PATCH 379/587] making the check solver status function more solver agnostic --- temoa/_internal/run_actions.py | 46 ++++++++++++++++++++++++++++++---- tests/test_full_runs.py | 12 ++++++--- 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/temoa/_internal/run_actions.py b/temoa/_internal/run_actions.py index ecca3dc98..f914856a7 100644 --- a/temoa/_internal/run_actions.py +++ b/temoa/_internal/run_actions.py @@ -303,18 +303,54 @@ def solve_instance( def check_solve_status(result: SolverResults) -> tuple[bool, str]: """ - Check the status of the solve. + Check the status of the solve in a solver-agnostic way. + Handles both legacy solver results and APPSI solver results. + :param result: the results object returned by the solver :return: tuple of status boolean (True='optimal', others False), and string message if not optimal """ - soln = result['Solution'] + # Use check_optimal_termination for solver-agnostic checking + # Different solvers report status differently (e.g., HiGHS reports 'unknown' but is optimal) + is_optimal = check_optimal_termination(result) + + # Safely extract termination condition for logging (works for both legacy and APPSI solvers) + termination_condition = 'unknown' + if hasattr(result, 'solver') and hasattr(result.solver, 'termination_condition'): + termination_condition = result.solver.termination_condition + elif hasattr(result, 'termination_condition'): + # Some APPSI solvers expose this directly + termination_condition = result.termination_condition + + logger.info('Solver termination condition: %s (optimal: %s)', termination_condition, is_optimal) - logger.info('The solver reported status as: %s', soln.Status) - if check_optimal_termination(result): + if is_optimal: return True, '' else: - return False, f'{soln.Status} was returned from solve' + # Safely extract status for error message + status_msg = 'unknown status' + + # Try legacy solver result format first + if hasattr(result, '__getitem__'): + try: + soln = result.get('Solution') if hasattr(result, 'get') else result['Solution'] + if soln and hasattr(soln, 'Status'): + status_msg = str(soln.Status) + except (KeyError, TypeError, AttributeError): + pass + + # Try APPSI result format + if status_msg == 'unknown status': + for attr in ['status', 'problem_status', 'solver_status']: + if hasattr(result, attr): + status_msg = str(getattr(result, attr)) + break + + # Final fallback + if status_msg == 'unknown status': + status_msg = str(result) if result else 'no solution returned' + + return False, f'{status_msg} was returned from solve' def handle_results( diff --git a/tests/test_full_runs.py b/tests/test_full_runs.py index 029df9962..4228696e3 100644 --- a/tests/test_full_runs.py +++ b/tests/test_full_runs.py @@ -9,6 +9,7 @@ import pytest from pyomo.core import Constraint, Var +from pyomo.environ import check_optimal_termination, value from pyomo.opt import SolverResults # from src.temoa_model.temoa_model import temoa_create_model @@ -48,21 +49,24 @@ def test_against_legacy_outputs( """ data_name, res, mdl, _ = system_test_run logger.info('Starting output test on scenario: %s', data_name) + + # Defensive checks for test fixture results assert res is not None, f'No solver results for {data_name}' + assert isinstance(res, SolverResults), ( + f'Expected SolverResults object for {data_name}, got {type(res)}' + ) assert mdl is not None, f'No model for {data_name}' + expected_vals = test_vals.get(data_name) # a dictionary of expected results assert expected_vals is not None, f'No expected values for {data_name}' # Inspect some summary results # Use check_optimal_termination instead of checking raw status string # Different solvers report status differently (e.g., HiGHS reports 'unknown' but is optimal) - from pyomo.environ import check_optimal_termination - assert check_optimal_termination(res), f'Solver did not terminate optimally for {data_name}' + # Get objective value from the model instance instead of results object # HiGHS doesn't populate the results object the same way as CBC - from pyomo.environ import value - obj_value = value(mdl.total_cost) assert obj_value == pytest.approx(expected_vals[ExpectedVals.OBJ_VALUE], 0.00001) From 7b8c2d418127f5f83cfc16c21260b166f18d5c6d Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 27 Nov 2025 17:21:39 -0500 Subject: [PATCH 380/587] windows in ci for testing --- .github/workflows/ci.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a794319b9..577b42cec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-latest] + os: [ubuntu-latest, macos-latest, windows-latest] python-version: ["3.12", "3.13"] steps: @@ -52,6 +52,10 @@ jobs: if: runner.os == 'macOS' run: brew install graphviz + - name: Install Graphviz (Windows) + if: runner.os == 'Windows' + run: choco install graphviz -y + - name: Run tests env: CI: 1 From 6401ee60859ad02c2863121536c90ed5a1b7e6bc Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Mon, 1 Dec 2025 12:46:33 -0500 Subject: [PATCH 381/587] polishing versioning --- docs/source/conf.py | 15 ++++++++------- pyproject.toml | 5 ++++- temoa/__about__.py | 24 ++++++++++++++++++++++++ temoa/__init__.py | 7 ++----- temoa/_internal/temoa_sequencer.py | 12 ++++++------ temoa/cli.py | 4 ++-- temoa/version_information.py | 13 ------------- uv.lock | 1 - 8 files changed, 46 insertions(+), 35 deletions(-) create mode 100644 temoa/__about__.py delete mode 100644 temoa/version_information.py diff --git a/docs/source/conf.py b/docs/source/conf.py index 7f55219dd..38de5dc7e 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -17,10 +17,12 @@ # this addition provided direct abbreviated link to the modules in the model sys.path.insert(1, os.path.abspath('../../temoa/temoa_model')) +# Import version from source (after sys.path setup) +from temoa.__about__ import __version__ # -- Project information from pyproject.toml --------------------------------- -# Read version and metadata from pyproject.toml for single source of truth +# Read metadata from pyproject.toml pyproject_path = Path(__file__).parent.parent.parent / 'pyproject.toml' with open(pyproject_path) as f: pyproject_data = tomlkit.load(f) @@ -32,12 +34,11 @@ ) copyright = f'2011-{time.strftime("%Y")}, NC State University' -# The short X.Y version -version = cast('str', project_metadata['version']).rsplit('.', 1)[ - 0 -] # '4.0.0a1.dev20251113' -> '4.0.0a1' -# The full version, including alpha/beta/rc tags -release = str(project_metadata['version']) + +# The short version +version = __version__.rsplit('.', 1)[0] +# The full version +release = __version__ # -- General configuration --------------------------------------------------- diff --git a/pyproject.toml b/pyproject.toml index 7b6df8443..a22140dd1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "temoa" -version = "4.0.0a1.dev20251113" +dynamic = ["version"] description = "Tools for Energy Model Optimization and Analysis" readme = "README.md" requires-python = ">=3.12" @@ -78,6 +78,9 @@ include = [ package-data = { "temoa" = ["db_schema/*.sql", "tutorial_assets/*", "py.typed"] } +[tool.hatch.version] +path = "temoa/__about__.py" + [tool.ruff] line-length = 100 indent-width = 4 diff --git a/temoa/__about__.py b/temoa/__about__.py new file mode 100644 index 000000000..a8b1a2f07 --- /dev/null +++ b/temoa/__about__.py @@ -0,0 +1,24 @@ +import re + +__version__ = '4.0.0a1.dev20251201' + +# Parse the version string to get major and minor versions +# We use a regex to be robust against versions like "4.1a1" or "4.0.0.dev1" +_match = re.match(r'^(\d+)\.(\d+)', __version__) +if not _match: + raise ValueError( + f"Could not parse major/minor version from '{__version__}'. " + "Expected format 'X.Y...' where X and Y are integers." + ) + +TEMOA_MAJOR = int(_match.group(1)) +TEMOA_MINOR = int(_match.group(2)) + +# === REQUIREMENTS === +# python versions are tested internally for greater than these values +MIN_PYTHON_MAJOR = 3 +MIN_PYTHON_MINOR = 12 + +# db is tested for match on major and >= on minor +DB_MAJOR_VERSION = 4 +MIN_DB_MINOR_VERSION = 0 diff --git a/temoa/__init__.py b/temoa/__init__.py index 1c54ccc0b..67ef283bd 100644 --- a/temoa/__init__.py +++ b/temoa/__init__.py @@ -8,6 +8,8 @@ # Core API - public interface # Internal modules - for backward compatibility +# Version information +from temoa.__about__ import TEMOA_MAJOR, TEMOA_MINOR, __version__ from temoa._internal.data_brick import DataBrick, data_brick_factory from temoa._internal.exchange_tech_cost_ledger import CostType, ExchangeTechCostLedger from temoa._internal.run_actions import ( @@ -30,11 +32,6 @@ from temoa.core.modes import TemoaMode from temoa.data_io.hybrid_loader import HybridLoader -# Version information -from temoa.version_information import TEMOA_MAJOR, TEMOA_MINOR - -__version__ = '4.0.0a1' - # Maintain backward compatibility for common imports __all__ = [ # Core API diff --git a/temoa/_internal/temoa_sequencer.py b/temoa/_internal/temoa_sequencer.py index 81accbf56..673f7ebdc 100644 --- a/temoa/_internal/temoa_sequencer.py +++ b/temoa/_internal/temoa_sequencer.py @@ -10,6 +10,12 @@ from logging import getLogger from typing import TYPE_CHECKING +from temoa.__about__ import ( + DB_MAJOR_VERSION, + MIN_DB_MINOR_VERSION, + MIN_PYTHON_MAJOR, + MIN_PYTHON_MINOR, +) from temoa._internal.run_actions import ( build_instance, check_database_version, @@ -28,12 +34,6 @@ from temoa.extensions.myopic.myopic_sequencer import MyopicSequencer from temoa.extensions.single_vector_mga.sv_mga_sequencer import SvMgaSequencer from temoa.model_checking.pricing_check import price_checker -from temoa.version_information import ( - DB_MAJOR_VERSION, - MIN_DB_MINOR_VERSION, - MIN_PYTHON_MAJOR, - MIN_PYTHON_MINOR, -) if TYPE_CHECKING: import pyomo.opt diff --git a/temoa/cli.py b/temoa/cli.py index b8a573962..59415cf11 100644 --- a/temoa/cli.py +++ b/temoa/cli.py @@ -12,11 +12,11 @@ from rich.logging import RichHandler from rich.text import Text +from temoa.__about__ import __version__ from temoa._internal.temoa_sequencer import TemoaSequencer from temoa.core.config import TemoaConfig from temoa.core.modes import TemoaMode from temoa.utilities import db_migration_v3_1_to_v4, sql_migration_v3_1_to_v4 -from temoa.version_information import TEMOA_MAJOR, TEMOA_MINOR # ============================================================================= # Logging & Helper Setup @@ -103,7 +103,7 @@ def _setup_sequencer( # ============================================================================= def _version_callback(value: bool) -> None: if value: - version = f'{TEMOA_MAJOR}.{TEMOA_MINOR}' + version = __version__ rich.print(f'Temoa Version: [bold green]{version}[/bold green]') raise typer.Exit() diff --git a/temoa/version_information.py b/temoa/version_information.py deleted file mode 100644 index 74268b3a5..000000000 --- a/temoa/version_information.py +++ /dev/null @@ -1,13 +0,0 @@ -# === INFORMATION === -# current Temoa version -TEMOA_MAJOR = 4 -TEMOA_MINOR = 0 - -# === REQUIREMENTS === -# python versions are tested internally for greater than these values -MIN_PYTHON_MAJOR = 3 -MIN_PYTHON_MINOR = 12 - -# db is tested for match on major and >= on minor -DB_MAJOR_VERSION = 4 -MIN_DB_MINOR_VERSION = 0 diff --git a/uv.lock b/uv.lock index 8d6f99744..921f47649 100644 --- a/uv.lock +++ b/uv.lock @@ -1334,7 +1334,6 @@ wheels = [ [[package]] name = "temoa" -version = "4.0.0a1.dev20251113" source = { editable = "." } dependencies = [ { name = "deprecated" }, From 1c430bbdef04e08e223c9d9d91d0da29e8a66f34 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 5 Dec 2025 16:11:01 -0500 Subject: [PATCH 382/587] adding gitattributes to make line endings consistent between windows and posix --- .gitattributes | 25 +++++++++++++++++++++++++ .gitignore | 1 + 2 files changed, 26 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..b229c8eed --- /dev/null +++ b/.gitattributes @@ -0,0 +1,25 @@ +# Auto-detect text files and normalize them to LF on checkin. +# Force LF on checkout for all text files to avoid Windows CRLF issues. +* text=auto eol=lf + +# Explicitly force LF for text files, redundant but explicit +*.toml text eol=lf +*.txt text eol=lf +*.md text eol=lf +*.rst text eol=lf +*.py text eol=lf +*.json text eol=lf +*.yaml text eol=lf +*.yml text eol=lf +*.sh text eol=lf + +# Explicitly declare binary files to avoid accidental corruption +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.ico binary +*.pdf binary +*.sqlite binary +*.db binary +*.pyc binary diff --git a/.gitignore b/.gitignore index 47190a980..0df0d6485 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ # unignore files !.gitignore +!.gitattributes !README.md !pyproject.toml !uv.lock From 7d00b976642f64f11aaad6964054609ccd908aec Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 11 Dec 2025 14:00:59 -0500 Subject: [PATCH 383/587] chore: pre-commit update --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 78d1311f3..8e69cea87 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ repos: - repo: https://github.com/astral-sh/uv-pre-commit # uv version. - rev: 0.9.3 + rev: 0.9.17 hooks: # Dependency management - id: uv-lock @@ -40,14 +40,14 @@ repos: args: ["--maxkb=1024"] - id: debug-statements - repo: https://github.com/asottile/pyupgrade - rev: v3.21.0 + rev: v3.21.2 hooks: - id: pyupgrade args: ["--py312-plus"] # Python Linting & Formatting with Ruff - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: "v0.14.1" + rev: "v0.14.8" hooks: - id: ruff name: ruff (linter) From 46ecf8b8a769a5460aabf13bd0bcfad15dfebe2b Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 11 Dec 2025 14:01:35 -0500 Subject: [PATCH 384/587] ref: refactoring table_writer to have dynamic column handling and more descriptive naming --- temoa/_internal/table_writer.py | 931 +++++++++++++++++--------------- 1 file changed, 496 insertions(+), 435 deletions(-) diff --git a/temoa/_internal/table_writer.py b/temoa/_internal/table_writer.py index e8e012188..d77b0f613 100644 --- a/temoa/_internal/table_writer.py +++ b/temoa/_internal/table_writer.py @@ -9,7 +9,7 @@ from collections import defaultdict from importlib import resources from logging import getLogger -from typing import TYPE_CHECKING, cast +from typing import TYPE_CHECKING, Any from pyomo.core import value @@ -19,7 +19,6 @@ FI, CapData, FlowType, - _marks, poll_capacity_results, poll_cost_results, poll_emissions, @@ -32,6 +31,7 @@ if TYPE_CHECKING: from collections.abc import Iterable from pathlib import Path + from types import TracebackType from pyomo.opt import SolverResults @@ -41,19 +41,10 @@ from temoa.extensions.monte_carlo.mc_run import ChangeRecord from temoa.types.core_types import Period, Region, Technology, Vintage - pass - -""" - -Note: This file borrows heavily from the legacy pformat_results.py, and is somewhat of a - restructure of that code - to accommodate the run modes more cleanly - -""" - logger = getLogger(__name__) -basic_output_tables = [ +# Basic tables that are always cleared on run +BASIC_OUTPUT_TABLES = [ 'output_built_capacity', 'output_cost', 'output_curtailment', @@ -65,29 +56,152 @@ 'output_objective', 'output_retired_capacity', ] -optional_output_tables = ['output_flow_out_summary', 'output_mc_delta', 'output_storage_level'] -flow_summary_file_loc = ( +OPTIONAL_OUTPUT_TABLES = [ + 'output_flow_out_summary', + 'output_mc_delta', + 'output_storage_level', +] + +FLOW_SUMMARY_FILE_LOC = ( resources.files('temoa.extensions.modeling_to_generate_alternatives') / 'make_flow_summary_table.sql' ) -mc_tweaks_file_loc = resources.files('temoa.extensions.monte_carlo') / 'make_deltas_table.sql' +MC_TWEAKS_FILE_LOC = resources.files('temoa.extensions.monte_carlo') / 'make_deltas_table.sql' class TableWriter: + con: sqlite3.Connection | None + def __init__(self, config: TemoaConfig, epsilon: float = 1e-5) -> None: self.config = config self.epsilon = epsilon self.tech_sectors: dict[str, str] | None = None self.flow_register: dict[FI, dict[FlowType, float]] = {} self.emission_register: dict[EI, float] | None = None + self.con = None + + # Cache for table columns to avoid repeated PRAGMA calls + self._table_columns_cache: dict[str, set[str]] = {} + try: self.con = sqlite3.connect(config.output_database) - except sqlite3.OperationalError as e: - logger.error('Failed to connect to output database: %s', config.output_database) - logger.error(e) + self.con.execute('PRAGMA foreign_keys = OFF') + except sqlite3.OperationalError as _: + logger.exception('Failed to connect to output database: %s', config.output_database) sys.exit(-1) + @property + def connection(self) -> sqlite3.Connection: + """ + Returns the active database connection. + Raises RuntimeError if the connection is closed or not initialized. + This serves as a central type guard for Mypy. + """ + if self.con is None: + raise RuntimeError('Database connection is closed') + return self.con + + def __enter__(self) -> TableWriter: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> None: + self.close() + + def close(self) -> None: + """Explicitly close the database connection.""" + if self.con: + try: + self.con.close() + except (sqlite3.Error, OSError) as e: + logger.warning('Error closing database connection: %s', e) + finally: + self.con = None + + def _validate_foreign_keys(self) -> None: + """ + Re-enables foreign keys, runs a check, and logs any violations. + This is essentially a "soft" integrity check that won't crash the write process + but will alert the user to data consistency issues. + """ + if self.con is None: + return + + try: + # Re-enable foreign keys to check for violations + self.connection.execute('PRAGMA foreign_keys = ON') + + # Check for violations + cursor = self.connection.execute('PRAGMA foreign_key_check') + violations = cursor.fetchall() + + if violations: + logger.error('Foreign key constraint violations found in output database:') + for violation in violations: + # violation tuple: (table, rowid, parent, fkid) + table_name = violation[0] + row_id = violation[1] + parent_table = violation[2] + logger.error( + " Table '%s' (row %s) violates FK to parent '%s'", + table_name, + row_id, + parent_table, + ) + except sqlite3.Error as _: + logger.exception('Error during foreign key validation') + + def _get_table_columns(self, table_name: str) -> set[str]: + """Returns a set of column names for the given table.""" + if table_name not in self._table_columns_cache: + cursor = self.connection.execute(f'PRAGMA table_info({table_name})') + # row[1] is the column name in sqlite PRAGMA table_info + columns = {row[1] for row in cursor.fetchall()} + self._table_columns_cache[table_name] = columns + return self._table_columns_cache[table_name] + + def _bulk_insert(self, table_name: str, records: list[dict[str, Any]]) -> None: + """ + Dynamically inserts records into a table. + + 1. Checks the DB schema to see which columns exist. + 2. Filters the input dictionary to match existing columns. + 3. Handles the optional 'units' column automatically. + """ + if not records: + return + + valid_columns = self._get_table_columns(table_name) + + # Determine the columns we will actually write to based on the first record + # and the valid schema columns. + data_keys = set(records[0].keys()) + + # Intersection: keys present in data AND present in database table + target_columns = list(data_keys.intersection(valid_columns)) + target_columns.sort() # Sort to ensure consistent order + + if not target_columns: + logger.warning('No matching columns found for table %s. Skipping insert.', table_name) + return + + # Prepare SQL statement + cols_str = ', '.join(target_columns) + placeholders = ', '.join(['?'] * len(target_columns)) + query = f'INSERT INTO {table_name} ({cols_str}) VALUES ({placeholders})' + + # Prepare values tuple generator + rows_to_insert = [] + for rec in records: + rows_to_insert.append(tuple(rec[col] for col in target_columns)) + + self.connection.executemany(query, rows_to_insert) + def write_results( self, model: TemoaModel, @@ -96,425 +210,385 @@ def write_results( append: bool = False, iteration: int | None = None, ) -> None: - """ - Write results to output database - :param iteration: An interation count for repeated runs, to be passed to tables that - support it - :param results_with_duals: if provided, this will trigger the writing of dual variables, - pulled from the SolverResults - :param M: the model - :param append: append whatever is already in the tables. If False (default), clear - existing tables by scenario name - :return: - """ - if not append: - self.clear_scenario() - if not self.tech_sectors: - self._set_tech_sectors() - self.write_objective(model, iteration=iteration) - self.write_capacity_tables(model, iteration=iteration) - # analyze the emissions to get the costs and flows - if self.config.scenario_mode == TemoaMode.MYOPIC: - p_0 = model.myopic_discounting_year - else: - p_0 = None # min year will be used in poll - e_costs, e_flows = poll_emissions(model=model, p_0=value(p_0)) - - self.emission_register = e_flows - self.write_emissions(iteration=iteration) - self.write_costs(model, emission_entries=e_costs, iteration=iteration) - self.flow_register = self.calculate_flows(model) - self.check_flow_balance(model) - self.write_flow_tables(iteration=iteration) - if results_with_duals: # write the duals - self.write_dual_variables(results_with_duals, iteration=iteration) - if save_storage_levels: - self.write_storage_level(model, iteration=iteration) - # catch-all - self.con.commit() - self.con.execute('VACUUM') + try: + if not append: + self.clear_scenario() + + if not self.tech_sectors: + self._set_tech_sectors() + + self.write_objective(model, iteration=iteration) + self.write_capacity_tables(model, iteration=iteration) + + # Poll and Write Emissions + if self.config.scenario_mode == TemoaMode.MYOPIC: + p_0 = model.myopic_discounting_year + else: + p_0 = None + + e_costs, e_flows = poll_emissions(model=model, p_0=value(p_0)) + self.emission_register = e_flows + self.write_emissions(iteration=iteration) + + # Costs and Flows + self.write_costs(model, emission_entries=e_costs, iteration=iteration) + + self.flow_register = self.calculate_flows(model) + self.check_flow_balance(model) + self.write_flow_tables(iteration=iteration) + + if results_with_duals: + self.write_dual_variables(results_with_duals, iteration=iteration) + + if save_storage_levels: + self.write_storage_level(model, iteration=iteration) + + finally: + self._validate_foreign_keys() + self.connection.commit() def write_mm_results(self, model: TemoaModel, iteration: int) -> None: - """ - tailored writer function for Method of Morris which: - (a) appends data (so scenario needs to be cleared elsewhere - (b) requires an iteration number to separate results - (c) only writes to MM required tables (obj, emissions right now) - :param M: solved model - :param iteration: an iteration index for scenario labeling - :return: - """ - if not self.tech_sectors: - self._set_tech_sectors() - self.write_objective(model, iteration=iteration) - # analyze the emissions to get the costs and flows - e_costs, e_flows = poll_emissions(model=model) - self.emission_register = e_flows - self.write_emissions(iteration=iteration) - self.con.commit() - self.con.execute('VACUUM') + try: + if not self.tech_sectors: + self._set_tech_sectors() + self.write_objective(model, iteration=iteration) + _e_costs, e_flows = poll_emissions(model=model) + self.emission_register = e_flows + self.write_emissions(iteration=iteration) + finally: + self._validate_foreign_keys() + self.connection.commit() def write_mc_results(self, brick: DataBrick, iteration: int) -> None: - """ - tailored write function to capture appropriate monte carlo results - :param M: solve model - :param iteration: iteration number - :return: - """ - if not self.tech_sectors: - self._set_tech_sectors() - # analyze the emissions to get the costs and flows - e_costs, e_flows = brick.emission_cost_data, brick.emission_flows - self.emission_register = e_flows - self.write_emissions(iteration=iteration) - - # the rest can be directly inserted from the data_brick - self._insert_capacity_results(brick.capacity_data, iteration=iteration) - self._insert_summary_flow_results(flow_data=brick.flow_data, iteration=iteration) - self._insert_cost_results( - regular_entries=brick.cost_data, - exchange_entries=brick.exchange_cost_data, - emission_entries=e_costs, - iteration=iteration, - ) - self._insert_objective_results(brick.obj_data, iteration=iteration) - self.con.commit() - self.con.execute('VACUUM') + try: + if not self.tech_sectors: + self._set_tech_sectors() + + e_costs, e_flows = brick.emission_cost_data, brick.emission_flows + self.emission_register = e_flows + self.write_emissions(iteration=iteration) + + self._insert_capacity_results(brick.capacity_data, iteration=iteration) + self._insert_summary_flow_results(flow_data=brick.flow_data, iteration=iteration) + self._insert_cost_results( + regular_entries=brick.cost_data, + exchange_entries=brick.exchange_cost_data, + emission_entries=e_costs, + iteration=iteration, + ) + self._insert_objective_results(brick.obj_data, iteration=iteration) + finally: + self._validate_foreign_keys() + self.connection.commit() def _set_tech_sectors(self) -> None: - """pull the sector info and fill the mapping""" qry = 'SELECT tech, sector FROM Technology' - data = self.con.execute(qry).fetchall() + data = self.connection.execute(qry).fetchall() self.tech_sectors = dict(data) + def _get_scenario_name(self, iteration: int | None) -> str: + if iteration is not None: + return f'{self.config.scenario}-{iteration}' + return self.config.scenario + def clear_scenario(self) -> None: - cur = self.con.cursor() - for table in basic_output_tables: + cur = self.connection.cursor() + for table in BASIC_OUTPUT_TABLES: cur.execute(f'DELETE FROM {table} WHERE scenario == ?', (self.config.scenario,)) - for table in optional_output_tables: + for table in OPTIONAL_OUTPUT_TABLES: try: cur.execute(f'DELETE FROM {table} WHERE scenario == ?', (self.config.scenario,)) except sqlite3.OperationalError: pass - self.con.commit() + self.connection.commit() self.clear_iterative_runs() def clear_iterative_runs(self) -> None: - """ - clear runs that are iterative extensions to the scenario name - Ex: scenario = 'Red Monkey" ... will clear "Red Monkey-1, Red Monkey-2, Red Monkey-3, - Red Monkey-4' - :return: None - """ - target = self.config.scenario + '-%' # the dash followed by wildcard for anything after - cur = self.con.cursor() - for table in basic_output_tables: - cur.execute(f'DELETE FROM {table} WHERE scenario like ?', (target,)) - self.con.commit() - for table in optional_output_tables: + target = self.config.scenario + '-%' + cur = self.connection.cursor() + tables = BASIC_OUTPUT_TABLES + OPTIONAL_OUTPUT_TABLES + for table in tables: try: cur.execute(f'DELETE FROM {table} WHERE scenario like ?', (target,)) except sqlite3.OperationalError: pass - self.con.commit() + self.connection.commit() + + # ------------------------------------------------------------------------- + # WRITE IMPLEMENTATIONS + # ------------------------------------------------------------------------- def write_storage_level(self, model: TemoaModel, iteration: int | None = None) -> None: - """Write the storage level table to the DB""" + if self.tech_sectors is None: + raise RuntimeError('tech sectors not available... code error') storage_levels = poll_storage_level_results(model=model) + scenario = self._get_scenario_name(iteration) - scenario_name = ( - self.config.scenario + f'-{iteration}' - if iteration is not None - else self.config.scenario - ) - - data = [] - for sli, storage_level in storage_levels.items(): - if self.tech_sectors is None: - raise RuntimeError('tech sectors not available... code error') - sector = self.tech_sectors[sli.t] - data.append( - (scenario_name, sli.r, sector, sli.p, sli.s, sli.d, sli.t, sli.v, storage_level) + records = [] + for sli, val in storage_levels.items(): + records.append( + { + 'scenario': scenario, + 'region': sli.r, + 'sector': self.tech_sectors.get(sli.t), + 'period': sli.p, + 'season': sli.s, + 'tod': sli.d, + 'tech': sli.t, + 'vintage': sli.v, + 'level': val, + 'units': None, + } ) - qry = f'INSERT INTO output_storage_level VALUES {_marks(9)}' - self.con.executemany(qry, data) - self.con.commit() + self._bulk_insert('output_storage_level', records) + self.connection.commit() def write_objective(self, model: TemoaModel, iteration: int | None = None) -> None: - """Write the value of all ACTIVE objectives to the DB""" obj_vals = poll_objective(model=model) self._insert_objective_results(obj_vals, iteration=iteration) def _insert_objective_results( self, obj_vals: list[tuple[str, float]], iteration: int | None ) -> None: - scenario_name = ( - self.config.scenario + f'-{iteration}' - if iteration is not None - else self.config.scenario - ) - for obj_name, obj_value in obj_vals: - qry = 'INSERT INTO output_objective VALUES (?, ?, ?)' - data = (scenario_name, obj_name, obj_value) - self.con.execute(qry, data) - self.con.commit() + scenario = self._get_scenario_name(iteration) + records = [ + { + 'scenario': scenario, + 'objective_name': obj_name, + 'total_system_cost': obj_value, + } + for obj_name, obj_value in obj_vals + ] + self._bulk_insert('output_objective', records) + self.connection.commit() def write_emissions(self, iteration: int | None = None) -> None: - """Write the emission table to the DB""" - if self.tech_sectors is None: - raise RuntimeError('tech sectors not available... code error') - if self.emission_register is None: - raise RuntimeError('emission register not available... code error') - - data = [] - scenario = ( - self.config.scenario + f'-{iteration}' - if iteration is not None - else self.config.scenario - ) - for ei in self.emission_register: - sector = self.tech_sectors[ei.t] - val = self.emission_register[ei] + if self.tech_sectors is None or self.emission_register is None: + raise RuntimeError('Dependencies missing (tech_sectors or emission_register)') + + scenario = self._get_scenario_name(iteration) + records = [] + + for ei, val in self.emission_register.items(): if abs(val) < self.epsilon: continue + + row = { + 'scenario': scenario, + 'region': ei.r, + 'sector': self.tech_sectors.get(ei.t), + 'emission': val, + 'emis_comm': ei.e, + 'tech': ei.t, + 'vintage': ei.v, + 'units': None, + } + if hasattr(ei, 'p'): # emissions from flows - entry = (scenario, ei.r, sector, cast('int', ei.p), ei.e, ei.t, ei.v, val) - else: # embodied emissions - entry = (scenario, ei.r, sector, cast('int', ei.v), ei.e, ei.t, ei.v, val) - data.append(entry) - qry = f'INSERT INTO output_emission VALUES {_marks(8)}' - self.con.executemany(qry, data) - self.con.commit() + row['period'] = ei.p + else: # embodied emissions (use vintage as period) + row['period'] = ei.v + + records.append(row) + + self._bulk_insert('output_emission', records) + self.connection.commit() + + def write_capacity_tables(self, model: TemoaModel, iteration: int | None = None) -> None: + cap_data = poll_capacity_results(model=model) + self._insert_capacity_results(cap_data=cap_data, iteration=iteration) def _insert_capacity_results(self, cap_data: CapData, iteration: int | None) -> None: - if not self.tech_sectors: + if self.tech_sectors is None: raise RuntimeError('tech sectors not available... code error') - scenario = self.config.scenario - if iteration is not None: - scenario = scenario + f'-{iteration}' - # Built Capacity - data: list[tuple[str, str, str | None, str, int, float]] = [] + scenario = self._get_scenario_name(iteration) + + # 1. Built Capacity + built_recs = [] for r, t, v, val in cap_data.built: - s = self.tech_sectors.get(t) - new_cap = (scenario, r, s, t, v, val) - data.append(new_cap) - qry = 'INSERT INTO output_built_capacity VALUES (?, ?, ?, ?, ?, ?)' - self.con.executemany(qry, data) - - # NetCapacity - data_net: list[tuple[str, str, str | None, int, str, int, float]] = [] + built_recs.append( + { + 'scenario': scenario, + 'region': r, + 'sector': self.tech_sectors.get(t), + 'tech': t, + 'vintage': v, + 'capacity': val, + 'units': None, + } + ) + self._bulk_insert('output_built_capacity', built_recs) + + # 2. Net Capacity + net_recs = [] for r, p, t, v, val in cap_data.net: - s = self.tech_sectors.get(t) - new_net_cap: tuple[str, str, str | None, int, str, int, float] = ( - scenario, - r, - s, - p, - t, - v, - val, + net_recs.append( + { + 'scenario': scenario, + 'region': r, + 'sector': self.tech_sectors.get(t), + 'period': p, + 'tech': t, + 'vintage': v, + 'capacity': val, + 'units': None, + } ) - data_net.append(new_net_cap) - qry = 'INSERT INTO output_net_capacity VALUES (?, ?, ?, ?, ?, ?, ?)' - self.con.executemany(qry, data_net) + self._bulk_insert('output_net_capacity', net_recs) - # Retired Capacity - data_ret: list[tuple[str, str, str | None, int, str, int, float, float]] = [] + # 3. Retired Capacity + ret_recs = [] for r, p, t, v, eol, early in cap_data.retired: - s = self.tech_sectors.get(t) - new_retired_cap: tuple[str, str, str | None, int, str, int, float, float] = ( - scenario, - r, - s, - p, - t, - v, - eol, - early, + ret_recs.append( + { + 'scenario': scenario, + 'region': r, + 'sector': self.tech_sectors.get(t), + 'period': p, + 'tech': t, + 'vintage': v, + 'cap_eol': eol, + 'cap_early': early, + 'units': None, + } ) - data_ret.append(new_retired_cap) - qry = 'INSERT INTO output_retired_capacity VALUES (?, ?, ?, ?, ?, ?, ?, ?)' - self.con.executemany(qry, data_ret) - self.con.commit() + self._bulk_insert('output_retired_capacity', ret_recs) - def write_capacity_tables(self, model: TemoaModel, iteration: int | None = None) -> None: - """Write the capacity tables to the DB""" - cap_data = poll_capacity_results(model=model) - self._insert_capacity_results(cap_data=cap_data, iteration=iteration) + self.connection.commit() def write_flow_tables(self, iteration: int | None = None) -> None: - """Write the flow tables""" - if not self.tech_sectors: - raise RuntimeError('tech sectors not available... code error') - if not self.flow_register: - raise RuntimeError('flow_register not available... code error') - # sort the flows - flows_by_type: dict[ - FlowType, list[tuple[str, str, str | None, int, str, str, str, str, int, str, float]] - ] = defaultdict(list) - scenario = ( - self.config.scenario + f'-{iteration}' - if iteration is not None - else self.config.scenario - ) + if not self.tech_sectors or not self.flow_register: + raise RuntimeError('Dependencies missing (tech_sectors or flow_register)') - for fi in self.flow_register: - sector = self.tech_sectors.get(fi.t) - for flow_type in self.flow_register[fi]: - val = self.flow_register[fi][flow_type] - if abs(val) < self.epsilon: - continue - entry = (scenario, fi.r, sector, fi.p, fi.s, fi.d, fi.i, fi.t, fi.v, fi.o, val) - flows_by_type[flow_type].append(entry) + scenario = self._get_scenario_name(iteration) - table_associations = { + # Structure to hold list of dicts for each table type + table_data: defaultdict[str, list[dict[str, Any]]] = defaultdict(list) + + map_flow_to_table = { FlowType.OUT: 'output_flow_out', FlowType.IN: 'output_flow_in', FlowType.CURTAIL: 'output_curtailment', - FlowType.FLEX: 'output_curtailment', # devnote: should flex have its own table? + FlowType.FLEX: 'output_curtailment', } - for flow_type, table_name in table_associations.items(): - qry = f'INSERT INTO {table_name} VALUES {_marks(11)}' - self.con.executemany(qry, flows_by_type[flow_type]) + for fi, flows in self.flow_register.items(): + sector = self.tech_sectors.get(fi.t) + + for flow_type, val in flows.items(): + if abs(val) < self.epsilon: + continue + + table_name = map_flow_to_table.get(flow_type) + if not table_name: + continue - self.con.commit() + row: dict[str, Any] = { + 'scenario': scenario, + 'region': fi.r, + 'sector': sector, + 'period': fi.p, + 'season': fi.s, + 'tod': fi.d, + 'input_comm': fi.i, + 'tech': fi.t, + 'vintage': fi.v, + 'output_comm': fi.o, + 'units': None, + } + + # Assign value to correct column name based on table/type + if table_name == 'output_curtailment': + row['curtailment'] = val + else: + row['flow'] = val + + table_data[table_name].append(row) + + for table_name, records in table_data.items(): + self._bulk_insert(table_name, records) + + self.connection.commit() def write_summary_flow(self, model: TemoaModel, iteration: int | None = None) -> None: - """ - This is normally called from MGA (other?) - iterative solves where capturing the annual summary of flow out is desired vs. flows by - season, tod for - single instances - :param iteration: the number of the sequential iteration - :param M: The solved model - :return: None - """ flow_data = self.calculate_flows(model=model) self._insert_summary_flow_results(flow_data=flow_data, iteration=iteration) def _insert_summary_flow_results( self, flow_data: dict[FI, dict[FlowType, float]], iteration: int | None ) -> None: - if not self.tech_sectors: + if self.tech_sectors is None: raise RuntimeError('tech sectors not available... code error') + scenario = self._get_scenario_name(iteration) self.flow_register = flow_data - if isinstance(iteration, int): - scenario = self.config.scenario + f'-{iteration}' - elif iteration is None: - scenario = self.config.scenario - else: - raise ValueError(f'Illegal (non integer) value received for iteration: {iteration}') - # iterate through all elements of the flow register, look for output flows only, - # and gather the total by index (region, period, input_comm, tech, vintage, output_comm) - # this is summing across season, tod - output_flows: dict[tuple[str, str, str | None, int, str, str, int, str], float] = ( + # Aggregate flows (sum across seasons/time of day) + output_flows: defaultdict[tuple[str, Period, str, Technology, Vintage, str], float] = ( defaultdict(float) ) - for fi in self.flow_register: - sector = self.tech_sectors.get(fi.t) - # get the output flow for this index, if it exists... - flow_out_value = self.flow_register[fi].get(FlowType.OUT, None) - if flow_out_value: - idx: tuple[str, str, str | None, int, str, str, int, str] = ( - scenario, - fi.r, - sector, - fi.p, - fi.i, - fi.t, - fi.v, - fi.o, - ) - output_flows[idx] += flow_out_value - - # convert to entries, if the sum is non-negligible - entries: list[tuple[str, str, str | None, int, str, str, int, str, float]] = [] - for idx, flow in output_flows.items(): - if abs(flow) < self.epsilon: - continue - entry: tuple[str, str, str | None, int, str, str, int, str, float] = (*idx, flow) - entries.append(entry) - qry = f'INSERT INTO output_flow_out_summary VALUES {_marks(9)}' - self.con.executemany(qry, entries) + for fi, flows in self.flow_register.items(): + val = flows.get(FlowType.OUT) + if val: + key = (fi.r, fi.p, fi.i, fi.t, fi.v, fi.o) + output_flows[key] += val - self.con.commit() + records = [] + for (r, p, i, t, v, o), val in output_flows.items(): + if abs(val) < self.epsilon: + continue + records.append( + { + 'scenario': scenario, + 'region': r, + 'sector': self.tech_sectors.get(t), + 'period': p, + 'input_comm': i, + 'tech': t, + 'vintage': v, + 'output_comm': o, + 'flow': val, + 'units': None, + } + ) - # @staticmethod - # def poll_summary_flow_results( M:TemoaModel) -> dict: - # flow_data = self.calculate_flows(M) + self._bulk_insert('output_flow_out_summary', records) + self.connection.commit() def check_flow_balance(self, model: TemoaModel) -> bool: - """ - An easy sanity check to ensure that the flow tables are balanced, except for storage - and construction/end of life flows - """ + """Sanity check to ensure that the flow tables are balanced.""" flows = self.flow_register all_good = True - deltas = defaultdict(float) - for fi in flows: + + for fi, flow_vals in flows.items(): if fi.t in model.tech_storage: continue - if fi.i == 'end_of_life_output': - continue - if fi.o == 'construction_input': + if fi.i == 'end_of_life_output' or fi.o == 'construction_input': continue - # some conveniences for the players... - fin = flows[fi][FlowType.IN] - fout = flows[fi][FlowType.OUT] - fcurt = flows[fi][FlowType.CURTAIL] - fflex = flows[fi][FlowType.FLEX] - flost = flows[fi][FlowType.LOST] - # some identifiers - tech = fi.t - flex_tech = fi.t in model.tech_flex - annual_tech = fi.t in model.tech_annual - - # ----- flow balance equation ----- - deltas[fi] = fin - fout - flost - fflex - # dev note: in constraint, flex is taken out of flow_out, but in output processing, - # we are treating flow out as "net of flex" so this is not double-counting - - if ( - flows[fi][FlowType.IN] != 0 and abs(deltas[fi] / flows[fi][FlowType.IN]) > 0.02 - ): # 2% of input is missing / surplus - all_good = False - logger.warning( - 'Flow balance check failed for index: %s, delta: %0.2f', fi, deltas[fi] - ) - logger.info( - 'Tech: %s, Flex: %s, Annual: %s', - tech, - flex_tech, - annual_tech, - ) - logger.info( - 'IN: %0.6f, OUT: %0.6f, LOST: %0.6f, CURT: %0.6f, FLEX: %0.6f', - fin, - fout, - flost, - fcurt, - fflex, - ) - elif flows[fi][FlowType.IN] == 0 and abs(deltas[fi]) > 0.02: + fin = flow_vals.get(FlowType.IN, 0) + fout = flow_vals.get(FlowType.OUT, 0) + flost = flow_vals.get(FlowType.LOST, 0) + fflex = flow_vals.get(FlowType.FLEX, 0) + + delta = fin - fout - flost - fflex + + # Check logic + if fin != 0: + if abs(delta / fin) > 0.02: + all_good = False + logger.warning('Flow imbalance > 2%% for %s: delta=%.2f', fi, delta) + elif abs(delta) > 0.02: all_good = False - logger.warning( - 'Flow balance check failed for index: %s, delta: %0.2f. Flows happening with ' - '0 input', - fi, - deltas[fi], - ) + logger.warning('Flow imbalance (zero input) for %s: delta=%.2f', fi, delta) + return all_good def calculate_flows(self, model: TemoaModel) -> dict[FI, dict[FlowType, float]]: - """Gather all flows by Flow Index and Type""" return poll_flow_results(model, self.epsilon) def write_costs( @@ -524,25 +598,12 @@ def write_costs( | None = None, iteration: int | None = None, ) -> None: - """ - Gather the cost data vars - :param iteration: tag for iteration in scenario name - :param emission_entries: cost dictionary for emissions - :param M: the Temoa Model - :return: dictionary of results of format variable name -> {idx: value} - """ - - # P_0 is usually the first optimization year, but if running myopic, we could assign it via - # table entry. Perhaps in future it is just always the first optimization year of the - # 1st iter. if self.config.scenario_mode == TemoaMode.MYOPIC: p_0 = model.myopic_discounting_year else: p_0 = min(model.time_optimize) entries, exchange_entries = poll_cost_results(model, value(p_0), self.epsilon) - - # write to table self._insert_cost_results(entries, exchange_entries, emission_entries, iteration) def _insert_cost_results( @@ -553,106 +614,106 @@ def _insert_cost_results( | None, iteration: int | None, ) -> None: - # add the emission costs to the same row data, if provided if emission_entries: - for k in emission_entries: - regular_entries[k].update(emission_entries[k]) - self._write_cost_rows(regular_entries, iteration=iteration) - self._write_cost_rows(exchange_entries, iteration=iteration) + # Create a copy to avoid mutating the input + regular_entries = dict(regular_entries) + + for k, v in emission_entries.items(): + if k in regular_entries: + regular_entries[k].update(v) + else: + regular_entries[k] = v + + self._write_cost_rows(regular_entries, iteration) + self._write_cost_rows(exchange_entries, iteration) def _write_cost_rows( self, entries: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]], iteration: int | None = None, ) -> None: - """Write the entries to the output_cost table""" if self.tech_sectors is None: raise RuntimeError('tech sectors not available... code error') - cur = self.con.cursor() - scenario_name = ( - self.config.scenario + f'-{iteration}' - if iteration is not None - else self.config.scenario - ) - rows = [ - ( - scenario_name, - r, - self.tech_sectors[t], - p, - t, - v, - entries[r, p, t, v].get(CostType.D_INVEST, 0), - entries[r, p, t, v].get(CostType.D_FIXED, 0), - entries[r, p, t, v].get(CostType.D_VARIABLE, 0), - entries[r, p, t, v].get(CostType.D_EMISS, 0), - entries[r, p, t, v].get(CostType.INVEST, 0), - entries[r, p, t, v].get(CostType.FIXED, 0), - entries[r, p, t, v].get(CostType.VARIABLE, 0), - entries[r, p, t, v].get(CostType.EMISS, 0), + + scenario = self._get_scenario_name(iteration) + records = [] + + sorted_keys = sorted(entries.keys()) + + for r, p, t, v in sorted_keys: + costs = entries[(r, p, t, v)] + records.append( + { + 'scenario': scenario, + 'region': r, + 'sector': self.tech_sectors.get(t), + 'period': p, + 'tech': t, + 'vintage': v, + 'd_invest': costs.get(CostType.D_INVEST, 0), + 'd_fixed': costs.get(CostType.D_FIXED, 0), + 'd_var': costs.get(CostType.D_VARIABLE, 0), + 'd_emiss': costs.get(CostType.D_EMISS, 0), + 'invest': costs.get(CostType.INVEST, 0), + 'fixed': costs.get(CostType.FIXED, 0), + 'var': costs.get(CostType.VARIABLE, 0), + 'emiss': costs.get(CostType.EMISS, 0), + 'units': None, + } ) - for (r, p, t, v) in entries - ] - rows.sort(key=lambda r: (r[0:5])) - qry = 'INSERT INTO output_cost VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' - cur.executemany(qry, rows) - self.con.commit() + + self._bulk_insert('output_cost', records) + self.connection.commit() def write_dual_variables(self, results: SolverResults, iteration: int | None = None) -> None: - """Write the dual variables to the output_dual_variable table""" - scenario_name = ( - self.config.scenario + f'-{iteration}' - if iteration is not None - else self.config.scenario - ) # collect the values + scenario = self._get_scenario_name(iteration) constraint_data = results['Solution'].Constraint.items() - dual_data = [(scenario_name, t[0], t[1]['Dual']) for t in constraint_data] - qry = 'INSERT INTO output_dual_variable VALUES (?, ?, ?)' - self.con.executemany(qry, dual_data) - self.con.commit() - # MONTE CARLO stuff + records = [ + { + 'scenario': scenario, + 'constraint_name': name, + 'dual': data['Dual'], + } + for name, data in constraint_data + ] + self._bulk_insert('output_dual_variable', records) + self.connection.commit() def write_tweaks(self, iteration: int, change_records: Iterable[ChangeRecord]) -> None: - scenario = f'{self.config.scenario}-{iteration}' + scenario = self._get_scenario_name(iteration) records = [] - for change_record in change_records: - element = ( - scenario, - iteration, - change_record.param_name, - str(change_record.param_index).replace("'", ''), - change_record.old_value, - change_record.new_value, - ) - records.append(element) - qry = 'INSERT INTO output_mc_delta VALUES (?, ?, ?, ?, ?, ?)' - self.con.executemany(qry, records) - self.con.commit() - def __del__(self) -> None: - if self.con: - self.con.close() - - def make_summary_flow_table(self) -> None: - # make the additional output table, if needed... - self.execute_script(flow_summary_file_loc) + for cr in change_records: + records.append( + { + 'scenario': scenario, + 'iteration': iteration, + 'param_name': cr.param_name, + 'param_index': str(cr.param_index).replace("'", ''), + 'old_value': cr.old_value, + 'new_value': cr.new_value, + } + ) - def make_mc_tweaks_table(self) -> None: - # make the table for monte carlo tweaks, if needed... - self.execute_script(mc_tweaks_file_loc) + self._bulk_insert('output_mc_delta', records) + self.connection.commit() def execute_script(self, script_file: str | Path | resources.abc.Traversable) -> None: - """ - A utility to execute a sql script on the current db connection - :return: - """ if isinstance(script_file, resources.abc.Traversable): sql_commands = script_file.read_text() else: with open(script_file) as table_script: sql_commands = table_script.read() - logger.debug('Executing sql from file: %s ', script_file) - self.con.executescript(sql_commands) - self.con.commit() + self.connection.executescript(sql_commands) + self.connection.commit() + + def make_summary_flow_table(self) -> None: + self.execute_script(FLOW_SUMMARY_FILE_LOC) + + def make_mc_tweaks_table(self) -> None: + self.execute_script(MC_TWEAKS_FILE_LOC) + + def __del__(self) -> None: + self.close() From c4a43cf1ae204736abad64b0a963f1cb29a52b33 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 16 Dec 2025 14:09:08 -0500 Subject: [PATCH 385/587] adding Pint to core dependencies --- pyproject.toml | 1 + requirements-dev.txt | 14 +++++++++++++- requirements.txt | 14 +++++++++++++- uv.lock | 41 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a22140dd1..e9625bc9d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,6 +30,7 @@ dependencies = [ "typer>=0.20.0", "rich>=14.2.0", "tomlkit>=0.12.0", + "pint>=0.25.2", ] diff --git a/requirements-dev.txt b/requirements-dev.txt index daa1b24c4..6f7cc6a5a 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -27,6 +27,10 @@ docutils==0.21.2 # sphinxcontrib-bibtex et-xmlfile==2.0.0 # via openpyxl +flexcache==0.3 + # via pint +flexparser==0.4 + # via pint fonttools==4.59.0 # via matplotlib graphviz==0.21 @@ -98,6 +102,10 @@ pandas==2.3.1 # seaborn pillow==11.3.0 # via matplotlib +pint==0.25.2 + # via temoa (pyproject.toml) +platformdirs==4.5.1 + # via pint pluggy==1.6.0 # via pytest ply==3.11 @@ -190,7 +198,11 @@ tomlkit==0.13.3 typer==0.20.0 # via temoa (pyproject.toml) typing-extensions==4.15.0 - # via typer + # via + # flexcache + # flexparser + # pint + # typer tzdata==2025.2 # via pandas urllib3==2.5.0 diff --git a/requirements.txt b/requirements.txt index 2b660981f..8d0fdddc6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,6 +12,10 @@ dill==0.4.0 # via multiprocess et-xmlfile==2.0.0 # via openpyxl +flexcache==0.3 + # via pint +flexparser==0.4 + # via pint fonttools==4.59.0 # via matplotlib graphviz==0.21 @@ -61,6 +65,10 @@ pandas==2.3.1 # seaborn pillow==11.3.0 # via matplotlib +pint==0.25.2 + # via temoa (pyproject.toml) +platformdirs==4.5.1 + # via pint pluggy==1.6.0 # via pytest ply==3.11 @@ -107,7 +115,11 @@ tomlkit==0.13.3 typer==0.20.0 # via temoa (pyproject.toml) typing-extensions==4.15.0 - # via typer + # via + # flexcache + # flexparser + # pint + # typer tzdata==2025.2 # via pandas wrapt==1.17.2 diff --git a/uv.lock b/uv.lock index 921f47649..b33d1785c 100644 --- a/uv.lock +++ b/uv.lock @@ -243,6 +243,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215, upload-time = "2025-03-14T07:11:39.145Z" }, ] +[[package]] +name = "flexcache" +version = "0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/b0/8a21e330561c65653d010ef112bf38f60890051d244ede197ddaa08e50c1/flexcache-0.3.tar.gz", hash = "sha256:18743bd5a0621bfe2cf8d519e4c3bfdf57a269c15d1ced3fb4b64e0ff4600656", size = 15816, upload-time = "2024-03-09T03:21:07.555Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/cd/c883e1a7c447479d6e13985565080e3fea88ab5a107c21684c813dba1875/flexcache-0.3-py3-none-any.whl", hash = "sha256:d43c9fea82336af6e0115e308d9d33a185390b8346a017564611f1466dcd2e32", size = 13263, upload-time = "2024-03-09T03:21:05.635Z" }, +] + +[[package]] +name = "flexparser" +version = "0.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/82/99/b4de7e39e8eaf8207ba1a8fa2241dd98b2ba72ae6e16960d8351736d8702/flexparser-0.4.tar.gz", hash = "sha256:266d98905595be2ccc5da964fe0a2c3526fbbffdc45b65b3146d75db992ef6b2", size = 31799, upload-time = "2024-11-07T02:00:56.249Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/5e/3be305568fe5f34448807976dc82fc151d76c3e0e03958f34770286278c1/flexparser-0.4-py3-none-any.whl", hash = "sha256:3738b456192dcb3e15620f324c447721023c0293f6af9955b481e91d00179846", size = 27625, upload-time = "2024-11-07T02:00:54.523Z" }, +] + [[package]] name = "fonttools" version = "4.59.0" @@ -818,6 +842,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/89/c7/5572fa4a3f45740eaab6ae86fcdf7195b55beac1371ac8c619d880cfe948/pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa", size = 2512835, upload-time = "2025-07-01T09:15:50.399Z" }, ] +[[package]] +name = "pint" +version = "0.25.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "flexcache" }, + { name = "flexparser" }, + { name = "platformdirs" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5f/74/bc3f671997158aef171194c3c4041e549946f4784b8690baa0626a0a164b/pint-0.25.2.tar.gz", hash = "sha256:85a45d1da8fe9c9f7477fed8aef59ad2b939af3d6611507e1a9cbdacdcd3450a", size = 254467, upload-time = "2025-11-06T22:08:09.184Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/88/550d41e81e6d43335603a960cd9c75c1d88f9cf01bc9d4ee8e86290aba7d/pint-0.25.2-py3-none-any.whl", hash = "sha256:ca35ab1d8eeeb6f7d9942b3cb5f34ca42b61cdd5fb3eae79531553dcca04dda7", size = 306762, upload-time = "2025-11-06T22:08:07.745Z" }, +] + [[package]] name = "platformdirs" version = "4.3.8" @@ -1345,6 +1384,7 @@ dependencies = [ { name = "numpy" }, { name = "openpyxl" }, { name = "pandas" }, + { name = "pint" }, { name = "pydoe" }, { name = "pyomo" }, { name = "pytest" }, @@ -1401,6 +1441,7 @@ requires-dist = [ { name = "numpy", specifier = ">=2.1.0" }, { name = "openpyxl", specifier = ">=3.1.5" }, { name = "pandas", specifier = ">=2.2.2" }, + { name = "pint", specifier = ">=0.25.2" }, { name = "pydoe", specifier = ">=0.3.8" }, { name = "pyomo", specifier = ">=6.8.0" }, { name = "pytest", specifier = ">=8.3.2" }, From 147fdbf6f61ff533e8289dc72458913335a328c2 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 16 Dec 2025 14:09:47 -0500 Subject: [PATCH 386/587] feat: adding unit checking module Co-authored-by: Jeff-ws --- .../model_checking/unit_checking/__init__.py | 22 + temoa/model_checking/unit_checking/common.py | 172 ++++++ .../unit_checking/entry_checker.py | 76 +++ .../unit_checking/relations_checker.py | 522 ++++++++++++++++++ .../model_checking/unit_checking/screener.py | 320 +++++++++++ .../unit_checking/table_checker.py | 116 ++++ .../unit_checking/temoa_units.txt | 15 + .../unit_checking/unit_propagator.py | 334 +++++++++++ 8 files changed, 1577 insertions(+) create mode 100644 temoa/model_checking/unit_checking/__init__.py create mode 100644 temoa/model_checking/unit_checking/common.py create mode 100644 temoa/model_checking/unit_checking/entry_checker.py create mode 100644 temoa/model_checking/unit_checking/relations_checker.py create mode 100644 temoa/model_checking/unit_checking/screener.py create mode 100644 temoa/model_checking/unit_checking/table_checker.py create mode 100644 temoa/model_checking/unit_checking/temoa_units.txt create mode 100644 temoa/model_checking/unit_checking/unit_propagator.py diff --git a/temoa/model_checking/unit_checking/__init__.py b/temoa/model_checking/unit_checking/__init__.py new file mode 100644 index 000000000..0db3c443f --- /dev/null +++ b/temoa/model_checking/unit_checking/__init__.py @@ -0,0 +1,22 @@ +from importlib import resources as importlib_resources + +from pint import UnitRegistry +from pint.errors import DefinitionSyntaxError + +# UnitRegistry is generic but doesn't require type args at instantiation +ureg: UnitRegistry = UnitRegistry() # type: ignore[type-arg] + +# Load custom unit definitions from the package resources +_resource_path = 'temoa.model_checking.unit_checking/temoa_units.txt' +try: + data = importlib_resources.files('temoa.model_checking.unit_checking').joinpath( + 'temoa_units.txt' + ) + # Ensure we have a real filesystem path (handles zipped resources too) + with importlib_resources.as_file(data) as path: + ureg.load_definitions(path) +except (FileNotFoundError, OSError, DefinitionSyntaxError) as exc: + raise RuntimeError( + f'Failed to load custom Temoa unit definitions from {_resource_path!r}. ' + 'This may indicate a broken installation or missing resource file.' + ) from exc diff --git a/temoa/model_checking/unit_checking/common.py b/temoa/model_checking/unit_checking/common.py new file mode 100644 index 000000000..f4c024a99 --- /dev/null +++ b/temoa/model_checking/unit_checking/common.py @@ -0,0 +1,172 @@ +""" +common elements used within Unit Checking +""" + +from collections.abc import Sequence +from dataclasses import dataclass +from enum import Enum +from typing import NamedTuple + +input_tables_with_units = [ + 'capacity_to_activity', + 'commodity', + 'construction_input', + 'cost_emission', + 'cost_fixed', + 'cost_invest', + 'cost_variable', + 'demand', + 'efficiency', + 'emission_activity', + 'emission_embodied', + 'emission_end_of_life', + 'end_of_life_output', + 'existing_capacity', + 'lifetime_process', + 'lifetime_tech', + 'loan_lifetime_process', + 'limit_activity', + 'limit_capacity', + # Growth/degrowth tables use 'seed_units' column, not 'units' - handle separately + # 'limit_degrowth_capacity', + # 'limit_degrowth_new_capacity', + # 'limit_degrowth_new_capacity_delta', + 'limit_emission', + # 'limit_growth_capacity', + # 'limit_growth_new_capacity', + # 'limit_growth_new_capacity_delta', + 'limit_new_capacity', + 'limit_resource', +] + +output_tables_with_units = [ + 'output_built_capacity', + 'output_cost', + 'output_curtailment', + 'output_emission', + 'output_flow_in', + 'output_flow_out', + 'output_net_capacity', + 'output_retired_capacity', + 'output_storage_level', +] + +# Combined list for backward compatibility +tables_with_units = input_tables_with_units + output_tables_with_units + +ratio_capture_tables = { + 'efficiency', + # 'emission_activity', # Not using ratio format in v4 + 'cost_emission', + 'cost_fixed', + 'cost_invest', + 'cost_variable', +} +"""Tables that require ratio capture in form "units / (other units)" """ + +commodity_based_tables = [ + 'demand', +] + +# Group tables Not Yet Implemented... would need to gather by group name and tech, etc. +activity_based_tables = [ + 'limit_activity', + # 'limit_activity' with groups - NYI +] +"""Tables that should have units equivalent to the commodity's native units""" + +# dev note: The "grouped" functions below are not yet implemented / future work. +# They are (to date) seldom used. Implementing would require grouping by group name, +# ensuring all techs in group are same... +capacity_based_tables = [ + 'existing_capacity', + 'limit_capacity', + 'limit_new_capacity', + # Group-based capacity limits - NYI +] +"""Tables that require conversion via capacity_to_activity to reach the native units""" + +period_based_tables = [ + 'lifetime_process', + 'lifetime_tech', + 'loan_lifetime_process', +] +"""Tables that align to the time period, presumably 'years'""" + + +# we need to delineate whether the units are commodity-referenced or tech-referenced +# and if they are "capacity based" so... +# format: (table_name, commodity field name (None if 'tech' based), +# capacity-based, period-based ) +class CostTableData(NamedTuple): + """A named tuple for the cost tables + important properties""" + + table_name: str + commodity_reference: str | None + capacity_based: bool + period_based: bool + + +cost_based_tables = [ + CostTableData( + table_name='cost_invest', commodity_reference=None, capacity_based=True, period_based=False + ), + CostTableData( + table_name='cost_emission', + commodity_reference='emis_comm', + capacity_based=False, + period_based=False, + ), + CostTableData( + table_name='cost_fixed', commodity_reference=None, capacity_based=True, period_based=True + ), + CostTableData( + table_name='cost_variable', + commodity_reference=None, + capacity_based=False, + period_based=False, + ), +] +"""Tables that have cost units and their properties""" + + +class RelationType(Enum): + ACTIVITY = 1 + CAPACITY = 2 + COMMODITY = 3 + + +@dataclass(frozen=True) +class UnitsFormat: + format: str + groups: int + + +# any gathering of letters and allowed symbols which are "*" and "_" +# with end lead/trail spaces trimmed +# We include numbers here for cases where there is an exponent in the units like "meter^2" +# the units *may* be parenthesized arbitrarily. See the unit tests for examples. +SINGLE_ELEMENT = UnitsFormat(format=r'^\s*([A-Za-z0-9\*\^\_\s\/\(\)]+?)\s*$', groups=1) + +# any fractional expression using the same pattern above with the denominator +# IN PARENTHESES this modification of above REQUIRES a parenthetical expression +# after the slash to isolate the denominator. see the unit tests for examples. +RATIO_ELEMENT = UnitsFormat( + format=r'^\s*([A-Za-z0-9\*\/\^\_\s]+?)\s*\/\s*\(\s*([A-Za-z0-9\*\^\/\(\)\_\s]+?)\s*\)\s*$', + groups=2, +) +"""Format for a units ratio. re will return the first group as the numerator +and the second as the denominator""" + +ACCEPTABLE_CHARACTERS = r'^\s*([A-Za-z0-9\*\^\_\s\/\(\)]+?)\s*$' + + +def consolidate_lines(line_nums: Sequence[int]) -> str: + """A little sand wedge function to prevent lists of many line numbers + and maxing at 5 or 5 + 'more'""" + listed_lines = ( + ', '.join(str(t) for t in line_nums) + if len(line_nums) < 5 + else f'{", ".join(str(t) for t in line_nums[:5])}, ... +{len(line_nums) - 5} more' + ) + return listed_lines diff --git a/temoa/model_checking/unit_checking/entry_checker.py b/temoa/model_checking/unit_checking/entry_checker.py new file mode 100644 index 000000000..effe07cb2 --- /dev/null +++ b/temoa/model_checking/unit_checking/entry_checker.py @@ -0,0 +1,76 @@ +""" +module to check all units entries in database for... + (1) existence :) + (2) general format (e.g. as a singleton or a ratio expression like Lumens / (Watt)) + (3) membership in units registry + +""" + +import logging +import re +import sqlite3 +from collections import defaultdict + +from pint import UndefinedUnitError, Unit + +from temoa.model_checking.unit_checking import ureg +from temoa.model_checking.unit_checking.common import ( + UnitsFormat, +) + +logger = logging.getLogger(__name__) + + +def validate_units_format( + expr: str, unit_format: UnitsFormat +) -> tuple[bool, tuple[str, ...] | None]: + """ + validate against the format + return boolean for validity and tuple of elements if valid + """ + if not expr: + return False, None + elements = re.search(unit_format.format, expr) + if elements: + return True, tuple(elements.groups()) + return False, None + + +def validate_units_expression(expr: str) -> tuple[bool, Unit | None]: + """ + validate an entry against the units registry + :param expr: the expression to validate + :return: tuple of the validity and the converted expression + """ + try: + units = ureg.parse_units(expr) + return True, units + except UndefinedUnitError: + return False, None + + +def gather_from_table(conn: sqlite3.Connection, table: str) -> dict[str, list[int]]: + """gather all unique "units" entries from a table and collect the row indices""" + + res = defaultdict(list) + with conn: + cur = conn.cursor() + + try: + cur.execute(f'SELECT units FROM {table}') + except sqlite3.OperationalError as exc: + # e.g. "no such column: units" for a table that hasn't been upgraded + logger.error( + 'Table %s does not contain a "units" column required for units checking: %s', + table, + exc, + ) + # Let the caller decide how to treat this (e.g., mark Check 2 as failed) + return {} + + for idx, result in enumerate(cur.fetchall(), start=1): + # note: this will put in "blank" entries which is OK, we want to mark blank rows too + entry = result[0] + res[entry].append(idx) + + return res diff --git a/temoa/model_checking/unit_checking/relations_checker.py b/temoa/model_checking/unit_checking/relations_checker.py new file mode 100644 index 000000000..522c2087b --- /dev/null +++ b/temoa/model_checking/unit_checking/relations_checker.py @@ -0,0 +1,522 @@ +""" +A systematic check of expected relationships between tables to ensure units are consistent + +""" + +import dataclasses +import logging +import sqlite3 +from collections import defaultdict +from collections.abc import Iterable + +from pint.registry import Unit + +from temoa.model_checking.unit_checking import ureg +from temoa.model_checking.unit_checking.common import ( + RATIO_ELEMENT, + SINGLE_ELEMENT, + CostTableData, + RelationType, + activity_based_tables, + capacity_based_tables, + commodity_based_tables, + consolidate_lines, +) +from temoa.model_checking.unit_checking.entry_checker import ( + validate_units_expression, + validate_units_format, +) + +logger = logging.getLogger(__name__) + + +def make_commodity_lut(conn: sqlite3.Connection) -> dict[str, Unit]: + """Get a dictionary of the units for each commodity entry""" + res: dict[str, Unit] = {} + cursor = conn.cursor() + query = 'SELECT name, units FROM commodity' + cursor.execute(query) + rows = cursor.fetchall() + for comm, units in rows: + valid, group = validate_units_format(units, SINGLE_ELEMENT) + if valid and group is not None: + valid, unit_obj = validate_units_expression(group[0]) + if valid and unit_obj is not None: + res[comm] = unit_obj + return res + + +def make_c2a_lut(conn: sqlite3.Connection) -> dict[str, Unit]: + """Get a dictionary of the units for each capacity to activity entry""" + res: dict[str, Unit] = {} + cursor = conn.cursor() + query = 'SELECT tech, units FROM capacity_to_activity' + cursor.execute(query) + rows = cursor.fetchall() + for tech, units in rows: + valid, group = validate_units_format(units, SINGLE_ELEMENT) + if valid and group is not None: + valid, unit_obj = validate_units_expression(group[0]) + if valid and unit_obj is not None: + res[tech] = unit_obj + return res + + +@dataclasses.dataclass(frozen=True) +class IOUnits: + input_units: Unit + output_units: Unit + + +def check_efficiency_table( + conn: sqlite3.Connection, comm_units: dict[str, Unit] +) -> tuple[dict[str, IOUnits], list[str]]: + """ + Check the technology units for Efficiency table entries + + Returns a dictionary of technology : IOUnits and a list of error messages + + """ + + query = 'SELECT tech, input_comm, output_comm, units FROM efficiency' + rows = conn.execute(query).fetchall() + res: dict[str, IOUnits] = {} + error_msgs = [] + invalid_rows = [] + for idx, (tech, ic, oc, units) in enumerate(rows, start=1): + input_units: Unit | None = None + output_units: Unit | None = None + valid, located_units = validate_units_format(units, RATIO_ELEMENT) + if valid and located_units is not None and len(located_units) >= 2: + valid, output_units = validate_units_expression(located_units[0]) + if valid and located_units is not None and len(located_units) >= 2: + valid, input_units = validate_units_expression(located_units[1]) + if not valid or input_units is None or output_units is None: + invalid_rows.append(idx) + # we give up early. The specifics of why this failed should be evident in earlier tests + continue + + # check that our tech matches the units of the connected commodities + expected_input = comm_units.get(ic) + expected_output = comm_units.get(oc) + if expected_input is None or expected_output is None: + invalid_rows.append(idx) + logger.warning( + 'Missing commodity units for input_comm=%s or output_comm=%s in efficiency row %d', + ic, + oc, + idx, + ) + continue + + invalid_input_flag = input_units != expected_input + invalid_output_flag = output_units != expected_output + if invalid_input_flag or invalid_output_flag: + logger.warning( + 'Efficiency units conflict with associated commodity for Technology %s near row %d', + tech, + idx, + ) + msg = ( + f'\n Expected: {f"{ic} [{expected_input}]":^25} ----> ' + f'{tech:^20} ----> {f"{oc} [{expected_output}]": ^25}' + ) + if invalid_input_flag: + msg += f'\n Invalid input units: {input_units}' + if invalid_output_flag: + msg += f'\n Invalid output units: {output_units}' + error_msgs.append(msg) + + # check that the output of this technology is consistent in units with + # other instances of same tech + if tech in res: + if res[tech].output_units != output_units: + logger.warning( + 'Efficiency units conflict with same-name tech for Technology %s near row %d', + tech, + idx, + ) + msg = ( + f'\n Found: {f"{ic} [{input_units}]":^25} ----> ' + f'{tech:^20} ----> {f"{oc} [{output_units}]": ^25}' + ) + msg += f'\n Conflicting output units: {res[tech].output_units} vs {output_units}' + error_msgs.append(msg) + + else: + res[tech] = IOUnits(input_units, output_units) + + # we gather all non-processed rows in one statement here due to size of table + # vs. individual reporting + if invalid_rows: + listed_lines = consolidate_lines(invalid_rows) + line_error_msg = f'Non-processed rows (see earlier tests): {listed_lines}' + error_msgs.append(line_error_msg) + + return res, error_msgs + + +def _column_exists(conn: sqlite3.Connection, table: str, column: str) -> bool: + """Check if a column exists in a table.""" + try: + cursor = conn.execute(f'PRAGMA table_info({table})') + columns = [row[1] for row in cursor.fetchall()] + return column in columns + except sqlite3.Error: + return False + + +def check_inter_table_relations( + conn: sqlite3.Connection, + table_name: str, + tech_lut: dict[str, IOUnits], + comm_lut: dict[str, Unit], + relation_type: RelationType, +) -> list[str]: + """Check the tech and units in the given table vs. baseline (expected) values for the tech. + + Fixed: Made SQL queries more robust to handle: + - Missing columns (e.g., 'region' may not exist in all tables) + - Missing tables (e.g., some databases may not have all limit tables) + - Schema variations between v3.1 and v4.0 + """ + # Validate table_name against known safe tables + valid_tables = activity_based_tables + capacity_based_tables + commodity_based_tables + if table_name not in valid_tables: + raise ValueError(f'Invalid table name: {table_name}') + + grouped_errors: defaultdict[str, list[int]] = defaultdict(list) + + # Build query based on relation type, with robustness checks + match relation_type: + case RelationType.CAPACITY: + # Check if required tables and columns exist + has_c2a = _column_exists(conn, 'capacity_to_activity', 'tech') + has_region = _column_exists(conn, table_name, 'region') + + # Some tables use 'tech_or_group' instead of 'tech' (e.g., limit tables) + tech_column = 'tech' if _column_exists(conn, table_name, 'tech') else 'tech_or_group' + + if has_c2a: + # Use LEFT JOIN to handle missing matches gracefully + join_condition = f'{table_name}.{tech_column} = ca.tech' + if has_region: + join_condition += f' AND {table_name}.region = ca.region' + + query = ( + f'SELECT {table_name}.{tech_column}, {table_name}.units, ca.units ' + f'FROM {table_name} ' + f'LEFT JOIN capacity_to_activity ca ON {join_condition}' + ) + else: + # Fallback: no C2A table available, just check the table itself + query = f'SELECT {tech_column}, units, NULL FROM {table_name}' + logger.warning( + 'capacity_to_activity table not available for %s, skipping C2A verification', + table_name, + ) + case RelationType.ACTIVITY: + # Activity tables may also have tech_or_group + tech_column = 'tech' if _column_exists(conn, table_name, 'tech') else 'tech_or_group' + query = f'SELECT {tech_column}, units, NULL FROM {table_name}' + case RelationType.COMMODITY: + query = f'SELECT commodity, units, NULL FROM {table_name}' + case _: + raise ValueError(f'Unexpected relation type: {relation_type}') + + try: + rows = conn.execute(query).fetchall() + except sqlite3.OperationalError as _: + # Log the error but don't fail the entire check + logger.exception('failed to process query: %s when processing table %s', query, table_name) + msg = ( + f'Failed to process table {table_name} due to SQL error. ' + f'This may indicate missing columns or incompatible schema. ' + f'See log for details.' + ) + return [msg] + + # process the rows + for idx, (tech_or_comm, table_units, c2a_units) in enumerate(rows, start=1): + expected_units = None + match relation_type: + case RelationType.CAPACITY: + io_units = tech_lut.get(tech_or_comm) + if not io_units: + grouped_errors[ + f'Unprocessed row (missing reference for tech ' + f'"{tech_or_comm}" --see earlier tests)' + ].append(idx) + continue + expected_units = io_units.output_units + case RelationType.ACTIVITY: + io_units = tech_lut.get(tech_or_comm) + if not io_units: + grouped_errors[ + f'Unprocessed row (missing reference for tech ' + f'"{tech_or_comm}" --see earlier tests)' + ].append(idx) + continue + expected_units = io_units.output_units + case RelationType.COMMODITY: + expected_units = comm_lut.get(tech_or_comm) + case _: + raise ValueError(f'Unexpected relation type: {relation_type}') + if not expected_units: + entity = 'commodity' if relation_type is RelationType.COMMODITY else 'tech' + grouped_errors[ + f'Unprocessed row (missing reference for {entity} "{tech_or_comm}"' + ].append(idx) + + continue + + # validate the units in the table... + entry_format_valid, units_data = validate_units_format(table_units, SINGLE_ELEMENT) + if entry_format_valid and units_data is not None and len(units_data) >= 1: + _is_valid, valid_table_units = validate_units_expression(units_data[0]) + else: + valid_table_units = None + + # validate the c2a units, if needed + if c2a_units: + c2a_valid, units_data = validate_units_format(c2a_units, SINGLE_ELEMENT) + if c2a_valid and units_data is not None and len(units_data) >= 1: + # further ensure the conversion is valid and retain the appropriate units object + _is_valid, valid_c2a_units = validate_units_expression(units_data[0]) + if not valid_c2a_units: + grouped_errors[ + f'Invalid units or unit format for c2a table: {c2a_units}' + ].append(idx) + continue + else: + grouped_errors[f'Invalid units or unit format for c2a table: {c2a_units}'].append( + idx + ) + continue + else: + valid_c2a_units = None + + if not valid_table_units: + grouped_errors[f'Invalid units or unit format: {table_units}'].append(idx) + continue + + # if we have valid c2a units, combine them to get the units of activity + if valid_c2a_units: + res_units = valid_table_units * (valid_c2a_units * ureg.year) + else: + res_units = valid_table_units + + # check that the res_units match the expectation from the tech + if expected_units != res_units: + label = f'Units do not match expectation for tech/comm: {tech_or_comm}' + conversions = [] + if valid_c2a_units: + conversions.append(f'C2A Factor: {valid_c2a_units}') + conversions.append(f'Nominal Period: {ureg.year}') + detail = _ding_label( + table_entry=table_units, + focus=f'Converted Measure: {valid_table_units}', + conversions=conversions, + result=res_units, + expectation=expected_units, + ) + msg = label + detail + '\n' + grouped_errors[msg].append(idx) + + # gather into list format + res = [] + for msg, line_nums in grouped_errors.items(): + res.append(f'{msg} at rows: {consolidate_lines(line_nums)}') + + return res + + +def _ding_label( + table_entry: str, + focus: str, + result: Unit | None, + expectation: Unit | None, + conversions: list[str] | None = None, +) -> str: + """Make a standardized 'ding' label to use in error reporting""" + res = [''] + res.append(f'| Table Entry: {table_entry}') + res.append(f'| Focused Portion: {focus}') + if conversions: + for conversion in conversions: + res.append(f'| Conversion: {conversion}') + res.append(f'| Result: {result}') + res.append(f'| Expectation: {expectation}') + return '\n '.join(res) + + +def check_cost_tables( + conn: sqlite3.Connection, + cost_tables: Iterable[CostTableData], + tech_lut: dict[str, IOUnits], + c2a_lut: dict[str, Unit], + commodity_lut: dict[str, Unit], +) -> list[str]: + """ + Check all cost tables for (a) alignment of units to tech output (the denominator) + and (b) 100% commonality in the cost units (numerator) + Note: we'll *assume* the first passing entry in the first table establishes + the common cost units and check for consistency + """ + common_cost_unit = None # Expectation: MUSD. Something with a prefix and currency dimension + error_msgs = [] + for ct in cost_tables: + table_grouped_errors = defaultdict(list) + if ct.commodity_reference and ct.capacity_based: + raise ValueError( + f'Table that is "capacity based" {ct.table_name} flagged as ' + 'having commodity field--expecting tech field. Check data.' + ) + query = ( + f'SELECT {ct.commodity_reference if ct.commodity_reference else "tech"}, ' + f'units FROM {ct.table_name}' + ) + try: + rows = conn.execute(query).fetchall() + except sqlite3.OperationalError: + logger.exception( + 'failed to process query: %s when processing table %s', query, ct.table_name + ) + msg = f'Failed to process table {ct.table_name}. See log for failed query.' + error_msgs.append(msg) + continue + for idx, (tech, raw_units_expression) in enumerate(rows, start=1): + # convert to pint expression + cost_units, measure_units = None, None + # screen for empty/missing raw inputs + if not raw_units_expression: + label = f'{ct.table_name}: Unprocessed row (missing units): {raw_units_expression}' + table_grouped_errors[label].append(idx) + continue + valid, elements = validate_units_format(raw_units_expression, RATIO_ELEMENT) + if valid and elements is not None and len(elements) >= 2: + cost_valid, cost_units = validate_units_expression(elements[0]) + units_valid, measure_units = validate_units_expression(elements[1]) + else: + cost_valid, units_valid = False, False + if not (cost_valid and units_valid): + label = ( + f'{ct.table_name}: Unprocessed row ' + f'(invalid units--see earlier tests): {raw_units_expression}' + ) + table_grouped_errors[label].append(idx) + continue + + # Test 1: Look for cost commonality + # extract the cost units + if not cost_units: + label = ( + f'{ct.table_name}: Unprocessed row ' + f'(missing cost units): {raw_units_expression}' + ) + table_grouped_errors[label].append(idx) + continue + + # Get cost unit object + # cost_units is already a pint Unit object from validate_units_expression(elements[0]) + cost_unit_obj = cost_units + + # Check for currency dimension + if '[currency]' not in cost_unit_obj.dimensionality: + label = ( + f'{ct.table_name}: Cost units must have currency dimension. ' + f'Found: {cost_unit_obj}' + ) + table_grouped_errors[label].append(idx) + continue + + # Initialize common_cost_unit on first valid row + if common_cost_unit is None: + common_cost_unit = cost_unit_obj + # No need to continue here, as we still need to check measure units + else: + # Validate subsequent rows against the established common unit + if cost_unit_obj != common_cost_unit: + # Try to see if they're equivalent but differently expressed + try: + # Attempt conversion to check if they're compatible + (1.0 * cost_unit_obj).to(common_cost_unit) + except (ValueError, AttributeError, TypeError) as e: + # Not compatible - this is an error + label = ( + f'{ct.table_name}: Inconsistent cost units: {cost_unit_obj} ' + f'does not match common cost unit {common_cost_unit}. Error: {e}' + ) + table_grouped_errors[label].append(idx) + continue + # If compatible but not strictly equal, we still flag it as non-standard + label = ( + f'{ct.table_name}: Non-standard cost found ' + f'(expected common cost units of {common_cost_unit}) got ' + f'{cost_unit_obj}' + ) + table_grouped_errors[label].append(idx) + + # Test 2: Check the units of measure to ensure alignment with the + # tech's output units. Find the referenced commodity units from the tech + # or commodity depending on table structure... + expected_measure_units: Unit | None = None + if ct.commodity_reference: + expected_measure_units = commodity_lut.get(tech) + if not expected_measure_units: + label = f'{ct.table_name}: Unprocessed row (unknown commodity: {tech}) ' + table_grouped_errors[label].append(idx) + continue + else: + tech_io = tech_lut.get(tech) + if tech_io: + # If capacity-based, we need to multiply by C2A and nominal period + if ct.capacity_based: + c2a_unit = c2a_lut.get(tech) + if c2a_unit: + expected_measure_units = tech_io.output_units * c2a_unit * ureg.year + else: + label = ( + f'{ct.table_name}: Unprocessed row (missing C2A for tech: {tech}) ' + ) + table_grouped_errors[label].append(idx) + continue + else: + expected_measure_units = tech_io.output_units + else: + label = f'{ct.table_name}: Unprocessed row (unknown tech: {tech}) ' + table_grouped_errors[label].append(idx) + continue + + # Now adjust for period-based if needed + if ct.period_based and expected_measure_units is not None: + expected_measure_units = expected_measure_units / ureg.year + + # Handle case where both are None (could indicate data issue) + if measure_units is None and expected_measure_units is None: + label = f'{ct.table_name}: Unable to determine measure units for tech/comm: {tech}' + table_grouped_errors[label].append(idx) + continue + + # Check if measure_units matches expected + matched = ( + measure_units == expected_measure_units + if (measure_units and expected_measure_units) + else False + ) + + if not matched: + label = f'{ct.table_name}: Non-matching measure unit for tech/comm: {tech}' + # Simplified detail without c2a_units/oring_measure_units + detail = ( + f'\n Table entry: {raw_units_expression}' + f'\n Expected: {expected_measure_units}' + f'\n Found: {measure_units}' + ) + label += detail + + table_grouped_errors[label].append(idx) + + for label, listed_lines in table_grouped_errors.items(): + error_msgs.append(f'{label} at rows: {consolidate_lines(listed_lines)}\n') + return error_msgs diff --git a/temoa/model_checking/unit_checking/screener.py b/temoa/model_checking/unit_checking/screener.py new file mode 100644 index 000000000..9f8d6a49a --- /dev/null +++ b/temoa/model_checking/unit_checking/screener.py @@ -0,0 +1,320 @@ +""" +The main executable to screen for units +""" + +import logging +import sqlite3 +from pathlib import Path +from typing import Any + +from temoa.model_checking.unit_checking.common import ( + RelationType, + activity_based_tables, + capacity_based_tables, + commodity_based_tables, + cost_based_tables, + input_tables_with_units, +) +from temoa.model_checking.unit_checking.relations_checker import ( + check_cost_tables, + check_efficiency_table, + check_inter_table_relations, + make_c2a_lut, + make_commodity_lut, +) +from temoa.model_checking.unit_checking.table_checker import check_table + +logger = logging.getLogger(__name__) + + +def _check_db_version(conn: sqlite3.Connection, report_entries: list[str]) -> tuple[bool, int, int]: + """ + Check the database version and return success/failure indicator and version info + :param conn: sqlite3 database connection + :param report_entries: list to append report messages to + :return: tuple of (success_indicator, major_version, minor_version) + """ + msg = '======== Units Check 1 (DB Version): Started ========' + report_entries.extend((msg, '\n')) + logger.info(msg) + + data = conn.execute('SELECT element, value FROM metadata').fetchall() + meta_data = dict(data) + major = int(meta_data.get('DB_MAJOR', 0)) + minor = int(meta_data.get('DB_MINOR', 0)) + + if major >= 4: + msg = 'Units Check 1 (DB Version): Passed' + report_entries.extend((msg, '\n')) + logger.info(msg) + return True, major, minor + else: + msg = 'Units Check 1 (DB Version): Failed. DB must be v4.0 or greater for units checking' + report_entries.extend((msg, '\n')) + logger.warning(msg) + return False, major, minor + + +def _check_units_entries(conn: sqlite3.Connection, report_entries: list[str]) -> bool: + """ + Check units entries in all tables and return success/failure indicator + :param conn: sqlite3 database connection + :param report_entries: list to append report messages to + :return: True if all units entries are valid, False otherwise + """ + report_entries.append('\n') + msg = '======== Units Check 2 (Units Entries in Tables): Started ========' + logger.info(msg) + report_entries.extend((msg, '\n')) + + tables_to_check = input_tables_with_units.copy() + + errors_test2 = False + for table in tables_to_check: + _, table_errors = check_table(conn, table) + if table_errors: + errors_test2 = True + for error in table_errors: + logger.info('%s: %s', table, error) + report_entries.extend((f'{table}: {error}', '\n')) + + if not errors_test2: + msg = 'Units Check 2 (Units Entries in Tables): Passed' + logger.info(msg) + report_entries.extend((msg, '\n')) + + report_entries.append('\n') + return not errors_test2 + + +def _check_efficiency_table( + conn: sqlite3.Connection, report_entries: list[str], comm_units: dict[str, Any] +) -> tuple[dict[str, Any], bool]: + """ + Check efficiency table and return tech_io_lut and success/failure indicator + :param conn: sqlite3 database connection + :param report_entries: list to append report messages to + :param comm_units: commodity units lookup table + :return: tuple of (tech_io_lut, success_indicator) + """ + report_entries.append('\n') + msg = '======== Units Check 3 (Tech I/O via Efficiency Table): Started ========' + report_entries.extend((msg, '\n')) + logger.info(msg) + + tech_io_lut, efficiency_errors = check_efficiency_table(conn, comm_units=comm_units) + + if efficiency_errors: + report_entries.append('Efficiency: \n') + for error in efficiency_errors: + report_entries.append(error) + report_entries.append('\n') + logger.warning('Unit conflicts found in Efficiency table. See report.') + return tech_io_lut, False + else: + msg = 'Units Check 3 (Efficiency): Passed' + report_entries.extend((msg, '\n')) + logger.info(msg) + return tech_io_lut, True + + +def _check_related_tables( + conn: sqlite3.Connection, + report_entries: list[str], + tech_io_lut: dict[str, Any], + comm_units: dict[str, Any], +) -> bool: + """ + Check related tables and return success/failure indicator + :param conn: sqlite3 database connection + :param report_entries: list to append report messages to + :param tech_io_lut: technology I/O units lookup table + :param comm_units: commodity units lookup table + :return: True if all related tables are valid, False otherwise + """ + report_entries.append('\n') + msg = '======== Units Check 4 (Related Tables): Started ========' + report_entries.extend((msg, '\n')) + logger.info(msg) + + errors_test4 = False + + # Activity-based + for table in activity_based_tables: + activity_errors = check_inter_table_relations( + conn=conn, + table_name=table, + tech_lut=tech_io_lut, + comm_lut=comm_units, + relation_type=RelationType.ACTIVITY, + ) + if activity_errors: + errors_test4 = True + report_entries.append(f'{table}: \n') + for error in activity_errors: + report_entries.append(error) + report_entries.append('\n') + logger.info('%s: %s', table, error) + + # Capacity-based + for table in capacity_based_tables: + capacity_errors = check_inter_table_relations( + conn=conn, + table_name=table, + tech_lut=tech_io_lut, + comm_lut=comm_units, + relation_type=RelationType.CAPACITY, + ) + if capacity_errors: + errors_test4 = True + report_entries.append(f'{table}: \n') + for error in capacity_errors: + report_entries.append(error) + report_entries.append('\n') + logger.info('%s: %s', table, error) + + # Commodity-based + for table in commodity_based_tables: + commodity_errors = check_inter_table_relations( + conn=conn, + table_name=table, + tech_lut=tech_io_lut, + comm_lut=comm_units, + relation_type=RelationType.COMMODITY, + ) + if commodity_errors: + errors_test4 = True + report_entries.append(f'{table}: \n') + for error in commodity_errors: + report_entries.append(error) + report_entries.append('\n') + logger.info('%s: %s', table, error) + + if not errors_test4: + msg = 'Units Check 4: (Related Tables): Passed' + logger.info(msg) + report_entries.extend((msg, '\n')) + + report_entries.append('\n') + return not errors_test4 + + +def _check_cost_tables( + conn: sqlite3.Connection, + report_entries: list[str], + tech_io_lut: dict[str, Any], + c2a_units: dict[str, Any], + comm_units: dict[str, Any], +) -> bool: + """ + Check cost tables and return success/failure indicator + :param conn: sqlite3 database connection + :param report_entries: list to append report messages to + :param tech_io_lut: technology I/O units lookup table + :param c2a_units: capacity to activity units lookup table + :param comm_units: commodity units lookup table + :return: True if all cost tables are valid, False otherwise + """ + msg = '======== Units Check 5 (Cost Tables): Started ========' + logger.info(msg) + report_entries.extend((msg, '\n')) + + errors = check_cost_tables( + conn, + cost_tables=cost_based_tables, + tech_lut=tech_io_lut, + c2a_lut=c2a_units, + commodity_lut=comm_units, + ) + + if errors: + for error in errors: + logger.info('Cost Tables: %s', error) + report_entries.extend(('Cost Tables: ', error, '\n')) + + return False + else: + msg = 'Units Check 5 (Cost Tables): Passed' + logger.info(msg) + report_entries.extend((msg, '\n')) + + return True + + +def screen(*db_paths: Path, report_dir: Path | None = None) -> bool: + """ + Run series of units screens on the database + :param db_paths: the abs path(S) to the database(s) + :param report_dir: directory to write the report to. If None, no report is written + :return: indicator of whether all checks passed "cleanly" or not + """ + all_clear = True + report_entries = [] + + for db_path in db_paths: + if not db_path.is_file(): + raise FileNotFoundError(f'Database file not found: {db_path}') + initialization_msg = f'\n======== Units Check on DB: {db_path}: Started ========\n\n' + report_entries.append(initialization_msg) + logger.info('Starting Units Check on DB: %s', db_path) + + with sqlite3.connect(db_path) as conn: + # test 1: DB version + db_version_ok, _major_version, _minor_version = _check_db_version(conn, report_entries) + if not db_version_ok: + # we are non-viable, write the (very short) report and return + if report_dir: + _write_report(report_dir, report_entries) + return False + + # test 2: Units in tables + comm_units = make_commodity_lut(conn) + c2a_units = make_c2a_lut(conn) + + units_entries_ok = _check_units_entries(conn, report_entries) + if not units_entries_ok: + all_clear = False + + # test 3: efficiency table + tech_io_lut, efficiency_ok = _check_efficiency_table(conn, report_entries, comm_units) + if not efficiency_ok: + all_clear = False + + # test 4: related tables + related_tables_ok = _check_related_tables(conn, report_entries, tech_io_lut, comm_units) + if not related_tables_ok: + all_clear = False + + # test 5: Cost-Based Tables + cost_tables_ok = _check_cost_tables( + conn, report_entries, tech_io_lut, c2a_units, comm_units + ) + if not cost_tables_ok: + all_clear = False + + # wrap it up + if report_dir: + _write_report(report_dir, report_entries) + logger.info('Finished Units Check') + return all_clear + + +def _write_report(report_dir: Path, report_entries: list[str]) -> None: + """write out a report if the path is specified""" + import datetime + + timestamp = datetime.datetime.now(datetime.UTC).strftime('%Y-%m-%d_%H%M%S') + report_dir.mkdir(parents=True, exist_ok=True) + report_file_path = report_dir / f'units_check_{timestamp}.txt' + with open(report_file_path, 'w', encoding='utf-8') as report_file: + report_file.writelines(report_entries) + + +if __name__ == '__main__': + import sys + + if len(sys.argv) > 1: + db_path = Path(sys.argv[1]) + screen(db_path, report_dir=Path('temp')) + else: + print('Usage: python screener.py ') diff --git a/temoa/model_checking/unit_checking/table_checker.py b/temoa/model_checking/unit_checking/table_checker.py new file mode 100644 index 000000000..182a9ac21 --- /dev/null +++ b/temoa/model_checking/unit_checking/table_checker.py @@ -0,0 +1,116 @@ +""" +functions to check tables within a database for units compliance +""" + +import logging +import re +import sqlite3 +from typing import cast + +from pint.registry import Unit + +from temoa.model_checking.unit_checking import ureg +from temoa.model_checking.unit_checking.common import ( + ACCEPTABLE_CHARACTERS, + RATIO_ELEMENT, + SINGLE_ELEMENT, + capacity_based_tables, + consolidate_lines, + ratio_capture_tables, +) +from temoa.model_checking.unit_checking.entry_checker import ( + gather_from_table, + validate_units_expression, + validate_units_format, +) + +logger = logging.getLogger(__name__) + + +def check_table(conn: sqlite3.Connection, table_name: str) -> tuple[dict[str, Unit], list[str]]: + """ + Check all entries in a table for format and registry compliance + This "first pass" gathers common entries for efficiency""" + errors = [] + res = {} + format_type = RATIO_ELEMENT if table_name in ratio_capture_tables else SINGLE_ELEMENT + + # this function gathers all unique entries by row number for efficiency in larger tables + entries = gather_from_table(conn, table_name) + for expr, line_nums in entries.items(): + # mark the blanks + if not expr: + listed_lines = consolidate_lines(line_nums) + errors.append(f'Blank units entry found at rows: {listed_lines}') + continue + + # check characters + valid_chars = re.search(ACCEPTABLE_CHARACTERS, expr) + if not valid_chars: + listed_lines = consolidate_lines(line_nums) + errors.append( + f'Invalid character(s): {expr if expr else ""} ' + f'[only letters, digits, underscore and "*, /, ^, ()" operators allowed] ' + f'at rows: {listed_lines} ' + ) + continue + + # Check format + valid_format, elements = validate_units_format(expr, format_type) + if not valid_format: + listed_lines = consolidate_lines(line_nums) + if format_type == RATIO_ELEMENT: + msg = ( + f'Format violation at rows. {listed_lines}: {expr}. ' + f'Check illegal chars/operators and that denominator is isolated ' + f'in parentheses.' + ) + else: + msg = ( + f'Format violation at rows. {listed_lines}: {expr}. ' + f'Check for illegal characters or operators.' + ) + errors.append(msg) + continue + elif elements is None: + listed_lines = consolidate_lines(line_nums) + errors.append(f'No units found for expression: {expr} at rows: {listed_lines}') + continue + + # Check registry compliance + converted_units = [] + for element in elements: + if element: + success, unit_obj = validate_units_expression(element) + if not success or unit_obj is None: + listed_lines = consolidate_lines(line_nums) + errors.append( + f'Registry violation (UNK units): {element} at rows: {listed_lines}' + ) + else: + # Capacity table validation: check for inappropriate time dimensions + if table_name in capacity_based_tables and format_type == SINGLE_ELEMENT: + unit_dimensionality = unit_obj.dimensionality + time_exponent = unit_dimensionality.get('[time]', 0) + + if float(cast('float', time_exponent)) > -3: # cast needed to satisfy mypy + listed_lines = consolidate_lines(line_nums) + errors.append( + f'Energy units (not capacity) in capacity table: {element} ' + f'at rows: {listed_lines}. ' + f'Expected power units (e.g., GW, MW, kW), not energy units. ' + f'Remove time component: use {unit_obj / ureg.year} instead?' + ) + converted_units.append(unit_obj) + + # assemble a reference of item: units-relationship if we have a valid entry + if len(converted_units) == format_type.groups: + if format_type == SINGLE_ELEMENT: + ref = {expr: converted_units[0]} + res.update(ref) + elif format_type == RATIO_ELEMENT: + ref = {expr: converted_units[0] / converted_units[1]} + res.update(ref) + else: + raise ValueError(f'Unknown units format: {format_type}') + return res, errors diff --git a/temoa/model_checking/unit_checking/temoa_units.txt b/temoa/model_checking/unit_checking/temoa_units.txt new file mode 100644 index 000000000..a84099cee --- /dev/null +++ b/temoa/model_checking/unit_checking/temoa_units.txt @@ -0,0 +1,15 @@ +# a few additions needed to for completeness in Temoa model +# the units here AUGMENT the default units in pint. See pint's documentation for more info. + +passenger = [person] +seat = [object] +vehicle = [object] + +# see pint's notes about currency and conversion before getting ideas about currency conversions. ;) +# it would be OK to add other currencies here in addition to USD. + +dollar = [currency] = USD +euro = [currency] = EUR + +# Temoa uses ethos as an original source, so we add it here as an "empty" base class unit +ethos = [empty] diff --git a/temoa/model_checking/unit_checking/unit_propagator.py b/temoa/model_checking/unit_checking/unit_propagator.py new file mode 100644 index 000000000..69df296c1 --- /dev/null +++ b/temoa/model_checking/unit_checking/unit_propagator.py @@ -0,0 +1,334 @@ +""" +Unit Propagator - derives units for output tables from input table definitions. + +This module provides the UnitPropagator class which builds lookup tables from +input data and provides unit derivation methods for populating output tables. + +All methods should return None gracefully when units cannot be determined, ensuring +backward compatibility with databases that lack unit information. +""" + +import logging +import re +import sqlite3 +from typing import TYPE_CHECKING + +from temoa.model_checking.unit_checking.relations_checker import ( + IOUnits, + check_efficiency_table, + make_c2a_lut, + make_commodity_lut, +) + +if TYPE_CHECKING: + from pint import Unit + +logger = logging.getLogger(__name__) + + +class UnitPropagator: + """ + Provides unit derivation for output table writing. + + Builds lookup tables once at initialization from input tables and provides + simple getter methods for each output table type. All methods should return None + if units cannot be determined, ensuring graceful fallback for databases + without unit information. + + Usage: + propagator = UnitPropagator(conn) + flow_units = propagator.get_flow_out_units('electricity') # e.g., 'PJ' + cap_units = propagator.get_capacity_units('E_NUCLEAR') # e.g., 'GW' + """ + + def __init__(self, conn: sqlite3.Connection) -> None: + """ + Initialize the propagator by building lookup tables from input data. + + Args: + conn: SQLite connection to the database with input tables. + """ + self._conn = conn + self._commodity_units: dict[str, Unit] | None = None + self._tech_io_units: dict[str, IOUnits] | None = None + self._c2a_units: dict[str, Unit] | None = None + self._capacity_units: dict[str, str] | None = None + self._cost_unit: str | None = None + self._storage_tech_commodities: dict[str, str] | None = None + + # Build all lookups, handling failures gracefully + self._build_lookups() + + def _build_lookups(self) -> None: + """Build all lookup tables, logging warnings on failure.""" + try: + self._commodity_units = make_commodity_lut(self._conn) + except (sqlite3.Error, KeyError) as e: + logger.debug('Could not build commodity units lookup: %s', e) + self._commodity_units = {} + + try: + if self._commodity_units: + tech_result = check_efficiency_table(self._conn, self._commodity_units) + self._tech_io_units = tech_result[0] + else: + self._tech_io_units = {} + except (sqlite3.Error, KeyError) as e: + logger.debug('Could not build tech I/O units lookup: %s', e) + self._tech_io_units = {} + + try: + self._c2a_units = make_c2a_lut(self._conn) + except (sqlite3.Error, KeyError) as e: + logger.debug('Could not build C2A units lookup: %s', e) + self._c2a_units = {} + + try: + self._capacity_units = self._build_capacity_lut() + except (sqlite3.Error, KeyError) as e: + logger.debug('Could not build capacity units lookup: %s', e) + self._capacity_units = {} + + try: + self._cost_unit = self._derive_common_cost_unit() + except (sqlite3.Error, KeyError) as e: + logger.debug('Could not derive common cost unit: %s', e) + self._cost_unit = None + + try: + self._storage_tech_commodities = self._build_storage_commodity_lut() + except (sqlite3.Error, KeyError) as e: + logger.debug('Could not build storage commodity lookup: %s', e) + self._storage_tech_commodities = {} + + def _build_capacity_lut(self) -> dict[str, str]: + """ + Build lookup of tech -> capacity units. + + Sources (in order of precedence): + 1. existing_capacity table (direct unit definition) + 2. cost_invest table (derived from denominator, e.g. Mdollar/GW -> GW) + + Returns: + Dictionary mapping technology name to capacity unit string. + """ + result: dict[str, str] = {} + + # 1. Check existing_capacity + try: + query = 'SELECT tech, units FROM existing_capacity WHERE units IS NOT NULL' + rows = self._conn.execute(query).fetchall() + for tech, units in rows: + if units and tech not in result: + result[tech] = units + except sqlite3.OperationalError: + pass + + # 2. Check cost_invest for new technologies + try: + query = 'SELECT tech, units FROM cost_invest WHERE units IS NOT NULL' + rows = self._conn.execute(query).fetchall() + for tech, units in rows: + if tech not in result and units: + cap_unit = self._extract_capacity_unit(units) + if cap_unit: + result[tech] = cap_unit + except sqlite3.OperationalError: + pass + + return result + + @staticmethod + def _extract_capacity_unit(unit_str: str) -> str | None: + """ + Scavenge for a capacity unit within a complex unit string. + + Handles complex composite units like 'Mdollar / (PJ^2 / GW)' by extracting + the known power unit (GW, MW, kW, etc.). + """ + # Prioritize finding standard power units + # Use word boundaries to avoid partial matches (e.g. GWh matching GW) + patterns = [ + r'\bGW\b', + r'\bMW\b', + r'\bkW\b', + r'\bTW\b', + r'\bgigawatt\b', + r'\bmegawatt\b', + r'\bkilowatt\b', + ] + for pat in patterns: + match = re.search(pat, unit_str) + if match: + return match.group(0) + return None + + def _derive_common_cost_unit(self) -> str | None: + """ + Derive the common cost unit from cost input tables. + + Extracts the currency portion (numerator) from the first valid cost + table entry. + + Returns: + Common cost unit string (e.g., 'Mdollar') or None. + """ + cost_tables = ['cost_invest', 'cost_fixed', 'cost_variable', 'cost_emission'] + for table in cost_tables: + try: + query = f'SELECT units FROM {table} WHERE units IS NOT NULL LIMIT 1' + row = self._conn.execute(query).fetchone() + if row and row[0]: + units_str = row[0] + # Extract numerator from ratio format "MUSD / (GW)" + # Use regex to safely split at the main division " / (" + # This handles cases like "kWh/day / (GW)" where numerator has slashes + parts = re.split(r'\s*/\s*\(', units_str, maxsplit=1) + if len(parts) > 1: + return parts[0].strip() + + # Fallback for simple ratios without parentheses or if strict format not used + if '/' in units_str: + return units_str.split('/', 1)[0].strip() + return units_str + except sqlite3.OperationalError as e: + logger.debug('Cost table %s not found or query failed: %s', table, e) + continue + return None + + def _build_storage_commodity_lut(self) -> dict[str, str]: + """ + Build lookup of storage tech -> output commodity from efficiency table. + + Returns: + Dictionary mapping storage technology to its output commodity. + """ + result: dict[str, str] = {} + try: + # Get storage technologies from storage_duration table + query = """ + SELECT DISTINCT e.tech, e.output_comm + FROM efficiency e + LEFT JOIN technology t ON e.tech = t.tech + LEFT JOIN storage_duration sd ON e.tech = sd.tech + WHERE t.flag = 'ps' + """ + rows = self._conn.execute(query).fetchall() + for tech, output_comm in rows: + if tech not in result: + result[tech] = output_comm + except sqlite3.OperationalError: + pass + return result + + def get_flow_out_units(self, output_comm: str) -> str | None: + """ + Get units for output flow based on output commodity. + + Args: + output_comm: Output commodity name. + + Returns: + Unit string or None if not available. + """ + if not self._commodity_units: + return None + unit = self._commodity_units.get(output_comm) + return f'{unit:~}' if unit else None + + def get_flow_in_units(self, input_comm: str) -> str | None: + """ + Get units for input flow based on input commodity. + + Args: + input_comm: Input commodity name. + + Returns: + Unit string or None if not available. + """ + if not self._commodity_units: + return None + unit = self._commodity_units.get(input_comm) + return f'{unit:~}' if unit else None + + def get_curtailment_units(self, output_comm: str) -> str | None: + """ + Get units for curtailment based on output commodity. + + Args: + output_comm: Output commodity name. + + Returns: + Unit string or None if not available. + """ + return self.get_flow_out_units(output_comm) + + def get_capacity_units(self, tech: str) -> str | None: + """ + Get capacity units for a technology. + + Args: + tech: Technology name. + + Returns: + Unit string or None if not available. + """ + if not self._capacity_units: + return None + return self._capacity_units.get(tech) + + def get_emission_units(self, emis_comm: str) -> str | None: + """ + Get units for emissions based on emission commodity. + + Args: + emis_comm: Emission commodity name. + + Returns: + Unit string or None if not available. + """ + if not self._commodity_units: + return None + unit = self._commodity_units.get(emis_comm) + return f'{unit:~}' if unit else None + + def get_cost_units(self) -> str | None: + """ + Get common cost units for cost output. + + Returns: + Common cost unit string (e.g., 'Mdollar') or None. + """ + return self._cost_unit + + def get_storage_units(self, tech: str) -> str | None: + """ + Get storage level units for a storage technology. + + Storage levels are in the units of the stored commodity. + + Args: + tech: Storage technology name. + + Returns: + Unit string or None if not available. + """ + if not self._storage_tech_commodities or not self._commodity_units: + return None + commodity = self._storage_tech_commodities.get(tech) + if commodity: + unit = self._commodity_units.get(commodity) + return f'{unit:~}' if unit else None + return None + + @property + def has_unit_data(self) -> bool: + """ + Check if any unit information is available. + + Returns: + True if at least one lookup has data, False otherwise. + """ + return bool( + self._commodity_units or self._capacity_units or self._cost_unit or self._tech_io_units + ) From f797ffc94fc5e780531ab30b2585e0cb5d8d530d Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 16 Dec 2025 14:10:43 -0500 Subject: [PATCH 387/587] updating temoa v4 schema with units --- data_files/temoa_schema_v4.sql | 17 +- temoa/db_schema/temoa_schema_v4.sql | 17 +- tests/testing_data/utopia.sql | 1606 --------------------------- 3 files changed, 32 insertions(+), 1608 deletions(-) delete mode 100644 tests/testing_data/utopia.sql diff --git a/data_files/temoa_schema_v4.sql b/data_files/temoa_schema_v4.sql index 5cbdb446f..bfb48c554 100644 --- a/data_files/temoa_schema_v4.sql +++ b/data_files/temoa_schema_v4.sql @@ -103,6 +103,7 @@ CREATE TABLE IF NOT EXISTS capacity_to_activity tech TEXT REFERENCES technology (tech), c2a REAL, + units TEXT, notes TEXT, PRIMARY KEY (region, tech) ); @@ -112,7 +113,8 @@ CREATE TABLE IF NOT EXISTS commodity PRIMARY KEY, flag TEXT REFERENCES commodity_type (label), - description TEXT + description TEXT, + units TEXT ); CREATE TABLE IF NOT EXISTS commodity_type ( @@ -256,6 +258,7 @@ CREATE TABLE IF NOT EXISTS efficiency output_comm TEXT REFERENCES commodity (name), efficiency REAL, + units TEXT, notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) @@ -354,6 +357,7 @@ CREATE TABLE IF NOT EXISTS loan_lifetime_process vintage INTEGER REFERENCES time_period (period), lifetime REAL, + units TEXT, notes TEXT, PRIMARY KEY (region, tech, vintage) ); @@ -376,6 +380,7 @@ CREATE TABLE IF NOT EXISTS lifetime_process vintage INTEGER REFERENCES time_period (period), lifetime REAL, + units TEXT, notes TEXT, PRIMARY KEY (region, tech, vintage) ); @@ -385,6 +390,7 @@ CREATE TABLE IF NOT EXISTS lifetime_tech tech TEXT REFERENCES technology (tech), lifetime REAL, + units TEXT, notes TEXT, PRIMARY KEY (region, tech) ); @@ -714,6 +720,7 @@ CREATE TABLE IF NOT EXISTS output_curtailment output_comm TEXT REFERENCES commodity (name), curtailment REAL, + units TEXT, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); CREATE TABLE IF NOT EXISTS output_net_capacity @@ -729,6 +736,7 @@ CREATE TABLE IF NOT EXISTS output_net_capacity vintage INTEGER REFERENCES time_period (period), capacity REAL, + units TEXT, PRIMARY KEY (region, scenario, period, tech, vintage) ); CREATE TABLE IF NOT EXISTS output_built_capacity @@ -742,6 +750,7 @@ CREATE TABLE IF NOT EXISTS output_built_capacity vintage INTEGER REFERENCES time_period (period), capacity REAL, + units TEXT, PRIMARY KEY (region, scenario, tech, vintage) ); CREATE TABLE IF NOT EXISTS output_retired_capacity @@ -758,6 +767,7 @@ CREATE TABLE IF NOT EXISTS output_retired_capacity REFERENCES time_period (period), cap_eol REAL, cap_early REAL, + units TEXT, PRIMARY KEY (region, scenario, period, tech, vintage) ); CREATE TABLE IF NOT EXISTS output_flow_in @@ -781,6 +791,7 @@ CREATE TABLE IF NOT EXISTS output_flow_in output_comm TEXT REFERENCES commodity (name), flow REAL, + units TEXT, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); CREATE TABLE IF NOT EXISTS output_flow_out @@ -804,6 +815,7 @@ CREATE TABLE IF NOT EXISTS output_flow_out output_comm TEXT REFERENCES commodity (name), flow REAL, + units TEXT, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); CREATE TABLE IF NOT EXISTS output_storage_level @@ -823,6 +835,7 @@ CREATE TABLE IF NOT EXISTS output_storage_level vintage INTEGER REFERENCES time_period (period), level REAL, + units TEXT, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); CREATE TABLE IF NOT EXISTS planning_reserve_margin @@ -994,6 +1007,7 @@ CREATE TABLE IF NOT EXISTS output_emission vintage INTEGER REFERENCES time_period (period), emission REAL, + units TEXT, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); CREATE TABLE IF NOT EXISTS rps_requirement @@ -1049,6 +1063,7 @@ CREATE TABLE IF NOT EXISTS output_cost fixed REAL, var REAL, emiss REAL, + units TEXT, PRIMARY KEY (scenario, region, period, tech, vintage), FOREIGN KEY (vintage) REFERENCES time_period (period), FOREIGN KEY (tech) REFERENCES technology (tech) diff --git a/temoa/db_schema/temoa_schema_v4.sql b/temoa/db_schema/temoa_schema_v4.sql index 5cbdb446f..bfb48c554 100644 --- a/temoa/db_schema/temoa_schema_v4.sql +++ b/temoa/db_schema/temoa_schema_v4.sql @@ -103,6 +103,7 @@ CREATE TABLE IF NOT EXISTS capacity_to_activity tech TEXT REFERENCES technology (tech), c2a REAL, + units TEXT, notes TEXT, PRIMARY KEY (region, tech) ); @@ -112,7 +113,8 @@ CREATE TABLE IF NOT EXISTS commodity PRIMARY KEY, flag TEXT REFERENCES commodity_type (label), - description TEXT + description TEXT, + units TEXT ); CREATE TABLE IF NOT EXISTS commodity_type ( @@ -256,6 +258,7 @@ CREATE TABLE IF NOT EXISTS efficiency output_comm TEXT REFERENCES commodity (name), efficiency REAL, + units TEXT, notes TEXT, PRIMARY KEY (region, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) @@ -354,6 +357,7 @@ CREATE TABLE IF NOT EXISTS loan_lifetime_process vintage INTEGER REFERENCES time_period (period), lifetime REAL, + units TEXT, notes TEXT, PRIMARY KEY (region, tech, vintage) ); @@ -376,6 +380,7 @@ CREATE TABLE IF NOT EXISTS lifetime_process vintage INTEGER REFERENCES time_period (period), lifetime REAL, + units TEXT, notes TEXT, PRIMARY KEY (region, tech, vintage) ); @@ -385,6 +390,7 @@ CREATE TABLE IF NOT EXISTS lifetime_tech tech TEXT REFERENCES technology (tech), lifetime REAL, + units TEXT, notes TEXT, PRIMARY KEY (region, tech) ); @@ -714,6 +720,7 @@ CREATE TABLE IF NOT EXISTS output_curtailment output_comm TEXT REFERENCES commodity (name), curtailment REAL, + units TEXT, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); CREATE TABLE IF NOT EXISTS output_net_capacity @@ -729,6 +736,7 @@ CREATE TABLE IF NOT EXISTS output_net_capacity vintage INTEGER REFERENCES time_period (period), capacity REAL, + units TEXT, PRIMARY KEY (region, scenario, period, tech, vintage) ); CREATE TABLE IF NOT EXISTS output_built_capacity @@ -742,6 +750,7 @@ CREATE TABLE IF NOT EXISTS output_built_capacity vintage INTEGER REFERENCES time_period (period), capacity REAL, + units TEXT, PRIMARY KEY (region, scenario, tech, vintage) ); CREATE TABLE IF NOT EXISTS output_retired_capacity @@ -758,6 +767,7 @@ CREATE TABLE IF NOT EXISTS output_retired_capacity REFERENCES time_period (period), cap_eol REAL, cap_early REAL, + units TEXT, PRIMARY KEY (region, scenario, period, tech, vintage) ); CREATE TABLE IF NOT EXISTS output_flow_in @@ -781,6 +791,7 @@ CREATE TABLE IF NOT EXISTS output_flow_in output_comm TEXT REFERENCES commodity (name), flow REAL, + units TEXT, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); CREATE TABLE IF NOT EXISTS output_flow_out @@ -804,6 +815,7 @@ CREATE TABLE IF NOT EXISTS output_flow_out output_comm TEXT REFERENCES commodity (name), flow REAL, + units TEXT, PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) ); CREATE TABLE IF NOT EXISTS output_storage_level @@ -823,6 +835,7 @@ CREATE TABLE IF NOT EXISTS output_storage_level vintage INTEGER REFERENCES time_period (period), level REAL, + units TEXT, PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) ); CREATE TABLE IF NOT EXISTS planning_reserve_margin @@ -994,6 +1007,7 @@ CREATE TABLE IF NOT EXISTS output_emission vintage INTEGER REFERENCES time_period (period), emission REAL, + units TEXT, PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) ); CREATE TABLE IF NOT EXISTS rps_requirement @@ -1049,6 +1063,7 @@ CREATE TABLE IF NOT EXISTS output_cost fixed REAL, var REAL, emiss REAL, + units TEXT, PRIMARY KEY (scenario, region, period, tech, vintage), FOREIGN KEY (vintage) REFERENCES time_period (period), FOREIGN KEY (tech) REFERENCES technology (tech) diff --git a/tests/testing_data/utopia.sql b/tests/testing_data/utopia.sql deleted file mode 100644 index 185852683..000000000 --- a/tests/testing_data/utopia.sql +++ /dev/null @@ -1,1606 +0,0 @@ -BEGIN TRANSACTION; -CREATE TABLE capacity_credit -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -CREATE TABLE capacity_factor_process -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'inter','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'inter','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'winter','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'winter','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'summer','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'summer','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','day','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','night','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','day','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','night','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','day','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','night','E31',2010,0.2756,''); -CREATE TABLE capacity_factor_tech -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E70',0.8,''); -CREATE TABLE capacity_to_activity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "capacity_to_activity" VALUES('utopia','E01',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','E21',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','E31',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','E51',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','E70',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','RHE',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','RHO',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','RL1',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','SRE',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','TXD',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','TXE',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','TXG',1.0,''); -CREATE TABLE commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES commodity_type (label), - description TEXT -); -INSERT INTO "commodity" VALUES('ethos','s','# dummy commodity to supply inputs (makes graph easier to read)'); -INSERT INTO "commodity" VALUES('DSL','p','# diesel'); -INSERT INTO "commodity" VALUES('ELC','p','# electricity'); -INSERT INTO "commodity" VALUES('FEQ','p','# fossil equivalent'); -INSERT INTO "commodity" VALUES('GSL','p','# gasoline'); -INSERT INTO "commodity" VALUES('HCO','p','# coal'); -INSERT INTO "commodity" VALUES('HYD','p','# water'); -INSERT INTO "commodity" VALUES('OIL','p','# crude oil'); -INSERT INTO "commodity" VALUES('URN','p','# uranium'); -INSERT INTO "commodity" VALUES('co2','e','#CO2 emissions'); -INSERT INTO "commodity" VALUES('nox','e','#NOX emissions'); -INSERT INTO "commodity" VALUES('RH','d','# residential heating'); -INSERT INTO "commodity" VALUES('RL','d','# residential lighting'); -INSERT INTO "commodity" VALUES('TX','d','# transportation'); -CREATE TABLE commodity_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "commodity_type" VALUES('w','waste commodity'); -INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); -INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); -INSERT INTO "commodity_type" VALUES('a','annual commodity'); -INSERT INTO "commodity_type" VALUES('s','source commodity'); -INSERT INTO "commodity_type" VALUES('p','physical commodity'); -INSERT INTO "commodity_type" VALUES('e','emissions commodity'); -INSERT INTO "commodity_type" VALUES('d','demand commodity'); -CREATE TABLE construction_input -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage) -); -CREATE TABLE cost_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT NOT NULL - REFERENCES commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE cost_fixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1960,40.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1970,40.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1980,40.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1990,40.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',1970,70.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',1980,70.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',1990,70.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',2000,70.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',1980,100.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',1990,100.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',2000,100.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',2010,100.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E21',1990,500.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E21',1990,500.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E21',1990,500.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E21',2000,500.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E21',2000,500.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E21',2010,500.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E31',1980,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E31',1990,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E31',1980,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E31',1990,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E31',2000,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',1980,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',1990,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',2000,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',2010,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E51',1980,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E51',1990,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E51',1980,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E51',1990,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E51',2000,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',1980,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',1990,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',2000,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',2010,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1960,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1970,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1980,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1990,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',1970,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',1980,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',1990,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',2000,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',1980,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',1990,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',2000,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',2010,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'RHO',1970,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'RHO',1980,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'RHO',1990,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'RHO',1980,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'RHO',1990,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'RHO',2000,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'RHO',1990,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'RHO',2000,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'RHO',2010,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'RL1',1980,9.46,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'RL1',1990,9.46,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'RL1',2000,9.46,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'RL1',2010,9.46,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXD',1970,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXD',1980,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXD',1990,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXD',1980,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXD',1990,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXD',2000,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXD',2000,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXD',2010,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXE',1990,100.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXE',1990,90.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXE',2000,90.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXE',2000,80.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXE',2010,80.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXG',1970,48.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXG',1980,48.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXG',1990,48.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXG',1980,48.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXG',1990,48.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXG',2000,48.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXG',2000,48.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXG',2010,48.0,'',''); -CREATE TABLE cost_invest -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "cost_invest" VALUES('utopia','E01',1990,2000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E01',2000,1300.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E01',2010,1200.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E21',1990,5000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E21',2000,5000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E21',2010,5000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E31',1990,3000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E31',2000,3000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E31',2010,3000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E51',1990,900.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E51',2000,900.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E51',2010,900.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E70',1990,1000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E70',2000,1000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E70',2010,1000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','RHE',1990,90.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','RHE',2000,90.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','RHE',2010,90.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','RHO',1990,100.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','RHO',2000,100.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','RHO',2010,100.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','SRE',1990,100.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','SRE',2000,100.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','SRE',2010,100.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXD',1990,1044.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXD',2000,1044.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXD',2010,1044.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXE',1990,2000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXE',2000,1750.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXE',2010,1500.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXG',1990,1044.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXG',2000,1044.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXG',2010,1044.0,'',''); -CREATE TABLE cost_variable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPDSL1',1990,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPDSL1',1990,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPDSL1',1990,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPGSL1',1990,15.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPGSL1',1990,15.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPGSL1',1990,15.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPHCO1',1990,2.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPHCO1',1990,2.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPHCO1',1990,2.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPOIL1',1990,8.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPOIL1',1990,8.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPOIL1',1990,8.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPURN1',1990,2.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPURN1',1990,2.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPURN1',1990,2.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1960,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1970,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1980,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1990,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',1970,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',1980,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',1990,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',2000,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',1980,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',1990,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',2000,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',2010,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E21',1990,1.5,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E21',1990,1.5,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E21',1990,1.5,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E21',2000,1.5,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E21',2000,1.5,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E21',2010,1.5,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1960,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1970,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1980,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1990,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',1970,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',1980,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',1990,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',2000,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',1980,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',1990,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',2000,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',2010,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'SRE',1990,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'SRE',1990,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'SRE',2000,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'SRE',1990,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'SRE',2000,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'SRE',2010,10.0,'',''); -CREATE TABLE demand -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - commodity TEXT - REFERENCES commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -INSERT INTO "demand" VALUES('utopia',1990,'RH',25.2,'',''); -INSERT INTO "demand" VALUES('utopia',2000,'RH',37.8,'',''); -INSERT INTO "demand" VALUES('utopia',2010,'RH',5.66999999999999957e+01,'',''); -INSERT INTO "demand" VALUES('utopia',1990,'RL',5.6,'',''); -INSERT INTO "demand" VALUES('utopia',2000,'RL',8.4,'',''); -INSERT INTO "demand" VALUES('utopia',2010,'RL',12.6,'',''); -INSERT INTO "demand" VALUES('utopia',1990,'TX',5.2,'',''); -INSERT INTO "demand" VALUES('utopia',2000,'TX',7.8,'',''); -INSERT INTO "demand" VALUES('utopia',2010,'TX',11.69,'',''); -CREATE TABLE demand_specific_distribution -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - demand_name TEXT - REFERENCES commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','day','RH',0.12,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','night','RH',0.06,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','day','RH',0.5467,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','night','RH',0.2733,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'summer','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'summer','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','day','RL',0.5,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','night','RL',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','day','RH',0.12,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','night','RH',0.06,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','day','RH',0.5467,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','night','RH',0.2733,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'summer','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'summer','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','day','RL',0.5,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','night','RL',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','day','RH',0.12,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','night','RH',0.06,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','day','RH',0.5467,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','night','RH',0.2733,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'summer','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'summer','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','day','RL',0.5,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','night','RL',0.1,''); -CREATE TABLE efficiency -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -INSERT INTO "efficiency" VALUES('utopia','ethos','IMPDSL1',1990,'DSL',1.0,''); -INSERT INTO "efficiency" VALUES('utopia','ethos','IMPGSL1',1990,'GSL',1.0,''); -INSERT INTO "efficiency" VALUES('utopia','ethos','IMPHCO1',1990,'HCO',1.0,''); -INSERT INTO "efficiency" VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,''); -INSERT INTO "efficiency" VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,''); -INSERT INTO "efficiency" VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,''); -INSERT INTO "efficiency" VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,''); -INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1960,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1970,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1980,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1990,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HCO','E01',2000,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HCO','E01',2010,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','FEQ','E21',1990,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','FEQ','E21',2000,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','FEQ','E21',2010,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','URN','E21',1990,'ELC',0.4,'# 1/2.5'); -INSERT INTO "efficiency" VALUES('utopia','URN','E21',2000,'ELC',0.4,'# 1/2.5'); -INSERT INTO "efficiency" VALUES('utopia','URN','E21',2010,'ELC',0.4,'# 1/2.5'); -INSERT INTO "efficiency" VALUES('utopia','HYD','E31',1980,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HYD','E31',1990,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HYD','E31',2000,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HYD','E31',2010,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1960,'ELC',0.294,'# 1/3.4'); -INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1970,'ELC',0.294,'# 1/3.4'); -INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1980,'ELC',0.294,'# 1/3.4'); -INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1990,'ELC',0.294,'# 1/3.4'); -INSERT INTO "efficiency" VALUES('utopia','DSL','E70',2000,'ELC',0.294,'# 1/3.4'); -INSERT INTO "efficiency" VALUES('utopia','DSL','E70',2010,'ELC',0.294,'# 1/3.4'); -INSERT INTO "efficiency" VALUES('utopia','ELC','E51',1980,'ELC',0.72,'# 1/1.3889'); -INSERT INTO "efficiency" VALUES('utopia','ELC','E51',1990,'ELC',0.72,'# 1/1.3889'); -INSERT INTO "efficiency" VALUES('utopia','ELC','E51',2000,'ELC',0.72,'# 1/1.3889'); -INSERT INTO "efficiency" VALUES('utopia','ELC','E51',2010,'ELC',0.72,'# 1/1.3889'); -INSERT INTO "efficiency" VALUES('utopia','ELC','RHE',1990,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','RHE',2000,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','RHE',2010,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',1970,'RH',0.7,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',1980,'RH',0.7,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',1990,'RH',0.7,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',2000,'RH',0.7,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',2010,'RH',0.7,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',1980,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',1990,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',2000,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',2010,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',1990,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2000,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',1970,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',1980,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',1990,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',2000,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',2010,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','TXE',1990,'TX',0.827,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','TXE',2000,'TX',0.827,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','TXE',2010,'TX',0.827,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',1970,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',1980,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',1990,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',2000,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',2010,'TX',0.231,'# direct translation from DMD_EFF'); -CREATE TABLE efficiency_variable -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE emission_activity -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.075,'',''); -INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.075,'',''); -INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',8.89999999999999819e-02,'',''); -INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.075,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1970,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1980,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1990,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',2000,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',2010,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1970,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1980,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1990,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',2000,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',2010,'TX',1.0,'',''); -CREATE TABLE emission_embodied -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE emission_end_of_life -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -CREATE TABLE existing_capacity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "existing_capacity" VALUES('utopia','E01',1960,0.175,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','E01',1970,0.175,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','E01',1980,0.15,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','E31',1980,0.1,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','E51',1980,0.5,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','E70',1960,0.05,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','E70',1970,0.05,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','E70',1980,0.2,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','RHO',1970,12.5,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','RHO',1980,12.5,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','RL1',1980,5.6,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','TXD',1970,0.4,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','TXD',1980,0.2,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','TXG',1970,3.1,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','TXG',1980,1.5,'',''); -CREATE TABLE lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "lifetime_process" VALUES('utopia','RL1',1980,20.0,'#forexistingcap'); -INSERT INTO "lifetime_process" VALUES('utopia','TXD',1970,30.0,'#forexistingcap'); -INSERT INTO "lifetime_process" VALUES('utopia','TXD',1980,30.0,'#forexistingcap'); -INSERT INTO "lifetime_process" VALUES('utopia','TXG',1970,30.0,'#forexistingcap'); -INSERT INTO "lifetime_process" VALUES('utopia','TXG',1980,30.0,'#forexistingcap'); -CREATE TABLE lifetime_survival_curve -( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE lifetime_tech -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "lifetime_tech" VALUES('utopia','E01',40.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','E21',40.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','E31',100.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','E51',100.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','E70',40.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','RHE',30.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','RHO',30.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','RL1',10.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','SRE',50.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','TXD',15.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','TXE',15.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','TXG',15.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','IMPDSL1',1000.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','IMPGSL1',1000.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','IMPHCO1',1000.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','IMPOIL1',1000.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','IMPURN1',1000.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','IMPHYD',1000.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','IMPFEQ',1000.0,''); -CREATE TABLE limit_activity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -INSERT INTO "limit_capacity" VALUES('utopia',1990,'E31','ge',0.13,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',2000,'E31','ge',0.13,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',2010,'E31','ge',0.13,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',1990,'SRE','ge',0.1,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',1990,'E31','le',0.13,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',2000,'E31','le',0.17,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',2010,'E31','le',2.1000000000000002e-01,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',1990,'RHE','le',0.0,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',1990,'TXD','le',0.6,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',2000,'TXD','le',1.76,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',2010,'TXD','le',4.76,'',''); -CREATE TABLE limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_degrowth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE limit_growth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) -); -CREATE TABLE limit_storage_level_fraction -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -CREATE TABLE limit_tech_input_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_input_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_output_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -INSERT INTO "limit_tech_output_split" VALUES('utopia',1990,'SRE','DSL','ge',0.7,''); -INSERT INTO "limit_tech_output_split" VALUES('utopia',2000,'SRE','DSL','ge',0.7,''); -INSERT INTO "limit_tech_output_split" VALUES('utopia',2010,'SRE','DSL','ge',0.7,''); -INSERT INTO "limit_tech_output_split" VALUES('utopia',1990,'SRE','GSL','ge',0.3,''); -INSERT INTO "limit_tech_output_split" VALUES('utopia',2000,'SRE','GSL','ge',0.3,''); -INSERT INTO "limit_tech_output_split" VALUES('utopia',2010,'SRE','GSL','ge',0.3,''); -CREATE TABLE limit_tech_output_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE linked_tech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES technology (tech), - emis_comm TEXT - REFERENCES commodity (name), - driven_tech TEXT - REFERENCES technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -CREATE TABLE loan_lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE loan_rate -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); -INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); -INSERT INTO "metadata" VALUES('DB_MINOR',0,''); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,''); -CREATE TABLE myopic_efficiency -( - base_year integer, - region text, - input_comm text, - tech text, - vintage integer, - output_comm text, - efficiency real, - lifetime integer, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (region, input_comm, tech, vintage, output_comm) -); -CREATE TABLE operator -( - operator TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "operator" VALUES('e','equal to'); -INSERT INTO "operator" VALUES('le','less than or equal to'); -INSERT INTO "operator" VALUES('ge','greater than or equal to'); -CREATE TABLE output_built_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES sector_label (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) -); -CREATE TABLE output_curtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_period (period), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE output_emission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE output_flow_in -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out_summary -( - scenario TEXT NOT NULL, - region TEXT NOT NULL, - sector TEXT, - period INTEGER, - input_comm TEXT NOT NULL, - tech TEXT NOT NULL, - vintage INTEGER, - output_comm TEXT NOT NULL, - flow REAL NOT NULL, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_net_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_objective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE output_retired_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_storage_level -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE planning_reserve_margin -( - region TEXT - PRIMARY KEY - REFERENCES region (region), - margin REAL, - notes TEXT -); -CREATE TABLE ramp_down_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE ramp_up_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -INSERT INTO "region" VALUES('utopia',NULL); -CREATE TABLE reserve_capacity_derate -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE rps_requirement -( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL - REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES tech_group (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE season_label -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "season_label" VALUES('inter',NULL); -INSERT INTO "season_label" VALUES('summer',NULL); -INSERT INTO "season_label" VALUES('winter',NULL); -CREATE TABLE sector_label -( - sector TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "sector_label" VALUES('supply',NULL); -INSERT INTO "sector_label" VALUES('electric',NULL); -INSERT INTO "sector_label" VALUES('transport',NULL); -INSERT INTO "sector_label" VALUES('commercial',NULL); -INSERT INTO "sector_label" VALUES('residential',NULL); -INSERT INTO "sector_label" VALUES('industrial',NULL); -CREATE TABLE storage_duration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE tech_group -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE tech_group_member -( - group_name TEXT - REFERENCES tech_group (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technology_type (label) -); -INSERT INTO "technology" VALUES('IMPDSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported diesel'); -INSERT INTO "technology" VALUES('IMPGSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported gasoline'); -INSERT INTO "technology" VALUES('IMPHCO1','p','supply','coal','',1,0,0,0,0,0,0,0,' imported coal'); -INSERT INTO "technology" VALUES('IMPOIL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO "technology" VALUES('IMPURN1','p','supply','nuclear','',1,0,0,0,0,0,0,0,' imported uranium'); -INSERT INTO "technology" VALUES('IMPFEQ','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported fossil equivalent'); -INSERT INTO "technology" VALUES('IMPHYD','p','supply','hydro','',1,0,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); -INSERT INTO "technology" VALUES('E01','pb','electric','coal','',0,0,0,0,0,0,0,0,' coal power plant'); -INSERT INTO "technology" VALUES('E21','pb','electric','nuclear','',0,0,0,0,0,0,0,0,' nuclear power plant'); -INSERT INTO "technology" VALUES('E31','pb','electric','hydro','',0,0,0,0,0,0,0,0,' hydro power'); -INSERT INTO "technology" VALUES('E51','ps','electric','electric','',0,0,0,0,0,0,0,0,' electric storage'); -INSERT INTO "technology" VALUES('E70','p','electric','petroleum','',0,0,0,0,0,0,0,0,' diesel power plant'); -INSERT INTO "technology" VALUES('RHE','p','residential','electric','',0,0,0,0,0,0,0,0,' electric residential heating'); -INSERT INTO "technology" VALUES('RHO','p','residential','petroleum','',0,0,0,0,0,0,0,0,' diesel residential heating'); -INSERT INTO "technology" VALUES('RL1','p','residential','electric','',0,0,0,0,0,0,0,0,' residential lighting'); -INSERT INTO "technology" VALUES('SRE','p','supply','petroleum','',0,0,0,0,0,0,0,0,' crude oil processor'); -INSERT INTO "technology" VALUES('TXD','p','transport','petroleum','',0,0,0,0,0,0,0,0,' diesel powered vehicles'); -INSERT INTO "technology" VALUES('TXE','p','transport','electric','',0,0,0,0,0,0,0,0,' electric powered vehicles'); -INSERT INTO "technology" VALUES('TXG','p','transport','petroleum','',0,0,0,0,0,0,0,0,' gasoline powered vehicles'); -CREATE TABLE technology_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "technology_type" VALUES('p','production technology'); -INSERT INTO "technology_type" VALUES('pb','baseload production technology'); -INSERT INTO "technology_type" VALUES('ps','storage production technology'); -CREATE TABLE time_of_day -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY -); -INSERT INTO "time_of_day" VALUES(1,'day'); -INSERT INTO "time_of_day" VALUES(2,'night'); -CREATE TABLE time_period -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES time_period_type (label) -); -INSERT INTO "time_period" VALUES(1,1960,'e'); -INSERT INTO "time_period" VALUES(2,1970,'e'); -INSERT INTO "time_period" VALUES(3,1980,'e'); -INSERT INTO "time_period" VALUES(4,1990,'f'); -INSERT INTO "time_period" VALUES(5,2000,'f'); -INSERT INTO "time_period" VALUES(6,2010,'f'); -INSERT INTO "time_period" VALUES(7,2020,'f'); -CREATE TABLE time_period_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "time_period_type" VALUES('e','existing vintages'); -INSERT INTO "time_period_type" VALUES('f','future'); -CREATE TABLE time_season -( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - season TEXT REFERENCES season_label(season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); -INSERT INTO "time_season" VALUES(1990,1,'inter',NULL); -INSERT INTO "time_season" VALUES(1990,2,'summer',NULL); -INSERT INTO "time_season" VALUES(1990,3,'winter',NULL); -INSERT INTO "time_season" VALUES(2000,1,'inter',NULL); -INSERT INTO "time_season" VALUES(2000,2,'summer',NULL); -INSERT INTO "time_season" VALUES(2000,3,'winter',NULL); -INSERT INTO "time_season" VALUES(2010,1,'inter',NULL); -INSERT INTO "time_season" VALUES(2010,2,'summer',NULL); -INSERT INTO "time_season" VALUES(2010,3,'winter',NULL); -CREATE TABLE time_season_all -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - season TEXT - REFERENCES season_label (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); -CREATE TABLE time_season_sequential -( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT REFERENCES season_label(season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); -CREATE TABLE time_season_to_sequential -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT - REFERENCES season_label (season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); -CREATE TABLE time_segment_fraction -( - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - segment_fraction REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); -INSERT INTO "time_segment_fraction" VALUES(1990,'inter','day',0.1667,'# I-D'); -INSERT INTO "time_segment_fraction" VALUES(1990,'inter','night',0.0833,'# I-N'); -INSERT INTO "time_segment_fraction" VALUES(1990,'summer','day',0.1667,'# S-D'); -INSERT INTO "time_segment_fraction" VALUES(1990,'summer','night',0.0833,'# S-N'); -INSERT INTO "time_segment_fraction" VALUES(1990,'winter','day',0.3333,'# W-D'); -INSERT INTO "time_segment_fraction" VALUES(1990,'winter','night',0.1667,'# W-N'); -INSERT INTO "time_segment_fraction" VALUES(2000,'inter','day',0.1667,'# I-D'); -INSERT INTO "time_segment_fraction" VALUES(2000,'inter','night',0.0833,'# I-N'); -INSERT INTO "time_segment_fraction" VALUES(2000,'summer','day',0.1667,'# S-D'); -INSERT INTO "time_segment_fraction" VALUES(2000,'summer','night',0.0833,'# S-N'); -INSERT INTO "time_segment_fraction" VALUES(2000,'winter','day',0.3333,'# W-D'); -INSERT INTO "time_segment_fraction" VALUES(2000,'winter','night',0.1667,'# W-N'); -INSERT INTO "time_segment_fraction" VALUES(2010,'inter','day',0.1667,'# I-D'); -INSERT INTO "time_segment_fraction" VALUES(2010,'inter','night',0.0833,'# I-N'); -INSERT INTO "time_segment_fraction" VALUES(2010,'summer','day',0.1667,'# S-D'); -INSERT INTO "time_segment_fraction" VALUES(2010,'summer','night',0.0833,'# S-N'); -INSERT INTO "time_segment_fraction" VALUES(2010,'winter','day',0.3333,'# W-D'); -INSERT INTO "time_segment_fraction" VALUES(2010,'winter','night',0.1667,'# W-N'); -CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); -COMMIT; From ebae876d873c45c5416d99156e1cd0e7f8b09e0d Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 16 Dec 2025 14:11:10 -0500 Subject: [PATCH 388/587] adding unit checking to sequencer --- temoa/_internal/temoa_sequencer.py | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/temoa/_internal/temoa_sequencer.py b/temoa/_internal/temoa_sequencer.py index 673f7ebdc..3eee5b29b 100644 --- a/temoa/_internal/temoa_sequencer.py +++ b/temoa/_internal/temoa_sequencer.py @@ -69,9 +69,30 @@ def __init__( self.pf_solved_instance: TemoaModel | None = None def _run_preliminary_checks(self) -> None: - """Runs pre-flight checks and raises an error if any fail.""" - checks_ok = True - checks_ok &= check_python_version(MIN_PYTHON_MAJOR, MIN_PYTHON_MINOR) + """Runs pre-flight system checks and (optionally) a non-fatal units check. + + Raises an error if Python or database version checks fail; unit-check + failures are logged but do not abort the run. + """ + # Unit checking - runs on database before model build + if self.config.check_units: + from temoa.model_checking.unit_checking.screener import screen + + logger.info('Running units consistency check on input database...') + report_dir = self.config.output_path / 'unit_check_reports' + success = screen(self.config.input_database, report_dir=report_dir) + + if not success: + logger.warning( + 'Units check found errors. See detailed report at: %s', + report_dir, + ) + logger.warning('Continuing with model build despite unit check warnings...') + else: + logger.info('Units check completed successfully - no errors found.') + + # System checks (Python version, database version) + checks_ok = check_python_version(MIN_PYTHON_MAJOR, MIN_PYTHON_MINOR) checks_ok &= check_database_version( self.config, db_major_reqd=DB_MAJOR_VERSION, min_db_minor=MIN_DB_MINOR_VERSION ) From afef24c6bf120b1e20a44f33506a3958d185b758 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 16 Dec 2025 14:11:38 -0500 Subject: [PATCH 389/587] adding unit checking to cli --- temoa/cli.py | 153 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 139 insertions(+), 14 deletions(-) diff --git a/temoa/cli.py b/temoa/cli.py index 59415cf11..21d8beafb 100644 --- a/temoa/cli.py +++ b/temoa/cli.py @@ -289,6 +289,110 @@ def run( raise typer.Exit(code=1) from e +@app.command('check-units') +def check_units( + database: Annotated[ + Path, + typer.Argument( + help='Path to the Temoa database file to check.', + exists=True, + file_okay=True, + dir_okay=False, + readable=True, + resolve_path=True, + ), + ], + output_dir: Annotated[ + Path | None, + typer.Option( + '--output', + '-o', + help='Directory to save the unit check report. ' + 'Defaults to current directory/unit_check_reports.', + ), + ] = None, + silent: Annotated[ + bool, + typer.Option('--silent', '-q', help='Suppress informational output.'), + ] = False, +) -> None: + """ + Check units consistency in a Temoa database. + + Validates that units are properly defined and consistent across all tables + in the database. Generates a detailed report of any issues found. + + The unit checker verifies: + - Units format and registry compliance + - Technology input/output unit alignment + - Commodity unit consistency + - Cost table unit alignment + """ + from temoa.model_checking.unit_checking.screener import screen + + if not silent: + rich.print(f'Checking units in database: [cyan]{database}[/cyan]') + + # Determine output directory + if output_dir is None: + output_dir = Path.cwd() / 'unit_check_reports' + else: + output_dir = output_dir.resolve() + + # Create output directory if it doesn't exist + try: + output_dir.mkdir(parents=True, exist_ok=True) + except OSError as e: + rich.print(f'[red]Error: Could not create output directory: {e}[/red]') + raise typer.Exit(1) from e + + # Run the unit checker + try: + all_clear = screen(database, report_dir=output_dir) + + if all_clear: + if not silent: + rich.print('\n[bold green]āœ… All unit checks passed![/bold green]') + rich.print('No unit inconsistencies found in the database.') + else: + # Find the most recent report + reports = sorted(output_dir.glob('units_check_*.txt'), reverse=True) + if reports: + report_file = reports[0] + if not silent: + rich.print('\n[bold yellow]⚠ Unit check found issues.[/bold yellow]') + rich.print(f'Detailed report saved to: [cyan]{report_file}[/cyan]') + # Brief summary of the report + if not silent: + rich.print('\n[bold]Report Summary:[/bold]') + shown = 0 + with open(report_file, encoding='utf-8') as f: + for idx, line in enumerate(f): + if idx >= 40: + break + if shown > 0 and line.strip() == '': + break + if line.strip(): + rich.print(f' {line.rstrip()}') + shown += 1 + else: + if not silent: + rich.print( + '\n[yellow]Unit check completed but no report was generated.[/yellow]' + ) + + except FileNotFoundError as e: + rich.print(f'[red]Error: Database file not found: {e}[/red]') + raise typer.Exit(1) from e + except Exception as e: + logger.exception('Unit check failed') + rich.print(f'\n[bold red]āŒ Unit check failed:[/bold red] {e}') + raise typer.Exit(1) from e + + if not all_clear: + raise typer.Exit(1) + + @app.command() def migrate( input_path: Annotated[ @@ -447,42 +551,63 @@ def _copy_tutorial_resources(target_config: Path, target_database: Path) -> None """ Copy tutorial resource files directly to target locations. + The database is generated from the SQL source file to ensure it uses + the latest schema with unit-compliant data (single source of truth). + Args: target_config: Path where configuration file should be copied - target_database: Path where database file should be copied + target_database: Path where database file should be created """ + import sqlite3 + try: - # Try to copy resources directly from the package using resources.files() + # Try to load resources from the package using resources.files() base = resources.files('temoa') / 'tutorial_assets' config_resource = base / 'config_sample.toml' - db_resource = base / 'utopia.sqlite' + sql_resource = base / 'utopia.sql' # Copy configuration file with config_resource.open('rb') as source: with open(target_config, 'wb') as target: shutil.copyfileobj(source, target) - # Copy database file - with db_resource.open('rb') as source: - with open(target_database, 'wb') as target: - shutil.copyfileobj(source, target) + # Delete existing database if it exists (required for overwrite to work) + if target_database.exists(): + target_database.unlink() + + # Generate database from SQL source (single source of truth) + sql_content = sql_resource.read_text(encoding='utf-8') + with sqlite3.connect(target_database) as conn: + conn.executescript(sql_content) except (ModuleNotFoundError, FileNotFoundError, AttributeError) as e: logger.exception('Failed to load tutorial resources from package') # Fallback to development paths (for development environments) fallback_config = Path(__file__).parent / 'tutorial_assets' / 'config_sample.toml' - fallback_database = Path(__file__).parent / 'tutorial_assets' / 'utopia.sqlite' + fallback_sql = Path(__file__).parent / 'tutorial_assets' / 'utopia.sql' - if not fallback_config.exists() or not fallback_database.exists(): + if not fallback_config.exists(): raise FileNotFoundError( - f'Tutorial resources not found. Tried package resources and fallback paths:\n' - f'Config: {fallback_config}\n' - f'Database: {fallback_database}' + f'Tutorial config not found. Tried package resources and fallback path:\n' + f'Config: {fallback_config}' ) from e - # Copy files using fallback paths + if not fallback_sql.exists(): + raise FileNotFoundError( + f'Tutorial SQL source not found. Tried package resources and fallback path:\n' + f'SQL: {fallback_sql}' + ) from e + + # Copy config file using fallback path shutil.copy2(fallback_config, target_config) - shutil.copy2(fallback_database, target_database) + + # Delete existing database if it exists (required for overwrite to work) + if target_database.exists(): + target_database.unlink() + + # Generate database from SQL source + with sqlite3.connect(target_database) as conn: + conn.executescript(fallback_sql.read_text(encoding='utf-8')) def _update_toml_database_paths(config_path: Path, new_database_name: str) -> None: From 4bc9a436d3f00ec4ecd522b8b2d2afc094052132 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 16 Dec 2025 14:13:03 -0500 Subject: [PATCH 390/587] adding unit checking to temoa config --- temoa/core/config.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/temoa/core/config.py b/temoa/core/config.py index 077e86a68..2098b234b 100644 --- a/temoa/core/config.py +++ b/temoa/core/config.py @@ -59,6 +59,7 @@ def __init__( stream_output: bool = False, price_check: bool = True, source_trace: bool = False, + check_units: bool = False, plot_commodity_network: bool = False, graphviz_output: bool = False, ): @@ -135,6 +136,7 @@ def __init__( self.stream_output = stream_output self.price_check = price_check self.source_trace = source_trace + self.check_units = check_units if plot_commodity_network and not self.source_trace: logger.warning( 'Commodity Network plotting was selected, but Source Trace was not selected. ' @@ -248,6 +250,7 @@ def __repr__(self) -> str: msg += spacer msg += '{:>{}s}: {}\n'.format('Price check', width, self.price_check) msg += '{:>{}s}: {}\n'.format('Source trace', width, self.source_trace) + msg += '{:>{}s}: {}\n'.format('Unit checking', width, self.check_units) msg += '{:>{}s}: {}\n'.format('Commodity network plots', width, self.plot_commodity_network) msg += '{:>{}s}: {}\n'.format('Graphviz output', width, self.graphviz_output) From a3e47428986ebd1402e54eed6e5a606589d43e0d Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 16 Dec 2025 14:13:35 -0500 Subject: [PATCH 391/587] adding unit complieant tutorial db --- temoa/tutorial_assets/config_sample.toml | 5 + temoa/tutorial_assets/utopia.sql | 1621 ++++++++++++++++++++++ temoa/tutorial_assets/utopia.sqlite | Bin 1028096 -> 0 bytes 3 files changed, 1626 insertions(+) create mode 100644 temoa/tutorial_assets/utopia.sql delete mode 100644 temoa/tutorial_assets/utopia.sqlite diff --git a/temoa/tutorial_assets/config_sample.toml b/temoa/tutorial_assets/config_sample.toml index f36348e2c..daa88be75 100644 --- a/temoa/tutorial_assets/config_sample.toml +++ b/temoa/tutorial_assets/config_sample.toml @@ -46,6 +46,11 @@ source_trace = true # Produce HTML files for Commodity Networks. Requires source_trace above plot_commodity_network = true +# Check units consistency in the database +# Validates that units are properly formatted and consistent across related tables +# Recommended for production runs after units are populated in the database +check_units = true + # ------------------------------------ # SOLVER # Solver Selection diff --git a/temoa/tutorial_assets/utopia.sql b/temoa/tutorial_assets/utopia.sql new file mode 100644 index 000000000..41fe6dba8 --- /dev/null +++ b/temoa/tutorial_assets/utopia.sql @@ -0,0 +1,1621 @@ +BEGIN TRANSACTION; +CREATE TABLE capacity_credit +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER, + credit REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage), + CHECK (credit >= 0 AND credit <= 1) +); +CREATE TABLE capacity_factor_process +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'inter','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'inter','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'winter','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'winter','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'summer','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'summer','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','day','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','night','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','day','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','night','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','day','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','night','E31',2010,0.2756,''); +CREATE TABLE capacity_factor_tech +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, tech), + CHECK (factor >= 0 AND factor <= 1) +); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E70',0.8,''); +CREATE TABLE capacity_to_activity +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + c2a REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech) +); +INSERT INTO "capacity_to_activity" VALUES('utopia','E01',31.54,'PJ / (GW * year)',''); +INSERT INTO "capacity_to_activity" VALUES('utopia','E21',31.54,'PJ / (GW * year)',''); +INSERT INTO "capacity_to_activity" VALUES('utopia','E31',31.54,'PJ / (GW * year)',''); +INSERT INTO "capacity_to_activity" VALUES('utopia','E51',31.54,'PJ / (GW * year)',''); +INSERT INTO "capacity_to_activity" VALUES('utopia','E70',31.54,'PJ / (GW * year)',''); +INSERT INTO "capacity_to_activity" VALUES('utopia','RHE',1.0,'PJ / (GW * year)',''); +INSERT INTO "capacity_to_activity" VALUES('utopia','RHO',1.0,'PJ / (GW * year)',''); +INSERT INTO "capacity_to_activity" VALUES('utopia','RL1',1.0,'PJ / (GW * year)',''); +INSERT INTO "capacity_to_activity" VALUES('utopia','SRE',1.0,'PJ / (GW * year)',''); +INSERT INTO "capacity_to_activity" VALUES('utopia','TXD',1.0,'PJ / (GW * year)',''); +INSERT INTO "capacity_to_activity" VALUES('utopia','TXE',1.0,'PJ / (GW * year)',''); +INSERT INTO "capacity_to_activity" VALUES('utopia','TXG',1.0,'PJ / (GW * year)',''); +CREATE TABLE commodity +( + name TEXT + PRIMARY KEY, + flag TEXT + REFERENCES commodity_type (label), + description TEXT, + units TEXT +); +INSERT INTO "commodity" VALUES('ethos','s','# dummy commodity to supply inputs','PJ'); +INSERT INTO "commodity" VALUES('DSL','p','# diesel','PJ'); +INSERT INTO "commodity" VALUES('ELC','p','# electricity','PJ'); +INSERT INTO "commodity" VALUES('FEQ','p','# fossil equivalent','PJ'); +INSERT INTO "commodity" VALUES('GSL','p','# gasoline','PJ'); +INSERT INTO "commodity" VALUES('HCO','p','# coal','PJ'); +INSERT INTO "commodity" VALUES('HYD','p','# water','PJ'); +INSERT INTO "commodity" VALUES('OIL','p','# crude oil','PJ'); +INSERT INTO "commodity" VALUES('URN','p','# uranium','PJ'); +INSERT INTO "commodity" VALUES('co2','e','#CO2 emissions','Mt'); +INSERT INTO "commodity" VALUES('nox','e','#NOX emissions','Mt'); +INSERT INTO "commodity" VALUES('RH','d','# residential heating','PJ'); +INSERT INTO "commodity" VALUES('RL','d','# residential lighting','PJ'); +INSERT INTO "commodity" VALUES('TX','d','# transportation','PJ'); +CREATE TABLE commodity_type +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO "commodity_type" VALUES('w','waste commodity'); +INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); +INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); +INSERT INTO "commodity_type" VALUES('a','annual commodity'); +INSERT INTO "commodity_type" VALUES('s','source commodity'); +INSERT INTO "commodity_type" VALUES('p','physical commodity'); +INSERT INTO "commodity_type" VALUES('e','emissions commodity'); +INSERT INTO "commodity_type" VALUES('d','demand commodity'); +CREATE TABLE construction_input +( + region TEXT, + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage) +); +CREATE TABLE cost_emission +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT NOT NULL + REFERENCES commodity (name), + cost REAL NOT NULL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm) +); +CREATE TABLE cost_fixed +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES time_period (period), + tech TEXT NOT NULL + REFERENCES technology (tech), + vintage INTEGER NOT NULL + REFERENCES time_period (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1960,40.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1970,40.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1980,40.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1990,40.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',1970,70.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',1980,70.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',1990,70.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',2000,70.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',1980,100.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',1990,100.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',2000,100.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',2010,100.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E21',1990,500.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E21',1990,500.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E21',1990,500.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E21',2000,500.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E21',2000,500.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E21',2010,500.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E31',1980,75.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E31',1990,75.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E31',1980,75.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E31',1990,75.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E31',2000,75.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',1980,75.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',1990,75.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',2000,75.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',2010,75.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E51',1980,30.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E51',1990,30.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E51',1980,30.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E51',1990,30.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E51',2000,30.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',1980,30.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',1990,30.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',2000,30.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',2010,30.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1960,30.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1970,30.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1980,30.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1990,30.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',1970,30.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',1980,30.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',1990,30.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',2000,30.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',1980,30.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',1990,30.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',2000,30.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',2010,30.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'RHO',1970,1.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'RHO',1980,1.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'RHO',1990,1.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'RHO',1980,1.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'RHO',1990,1.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'RHO',2000,1.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'RHO',1990,1.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'RHO',2000,1.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'RHO',2010,1.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'RL1',1980,9.46,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'RL1',1990,9.46,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'RL1',2000,9.46,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'RL1',2010,9.46,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXD',1970,52.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXD',1980,52.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXD',1990,52.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXD',1980,52.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXD',1990,52.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXD',2000,52.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXD',2000,52.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXD',2010,52.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXE',1990,100.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXE',1990,90.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXE',2000,90.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXE',2000,80.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXE',2010,80.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXG',1970,48.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXG',1980,48.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXG',1990,48.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXG',1980,48.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXG',1990,48.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXG',2000,48.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXG',2000,48.0,'Mdollar / (PJ^2 / GW / year)',''); +INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXG',2010,48.0,'Mdollar / (PJ^2 / GW / year)',''); +CREATE TABLE cost_invest +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +INSERT INTO "cost_invest" VALUES('utopia','E01',1990,2000.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','E01',2000,1300.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','E01',2010,1200.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','E21',1990,5000.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','E21',2000,5000.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','E21',2010,5000.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','E31',1990,3000.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','E31',2000,3000.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','E31',2010,3000.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','E51',1990,900.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','E51',2000,900.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','E51',2010,900.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','E70',1990,1000.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','E70',2000,1000.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','E70',2010,1000.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','RHE',1990,90.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','RHE',2000,90.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','RHE',2010,90.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','RHO',1990,100.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','RHO',2000,100.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','RHO',2010,100.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','SRE',1990,100.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','SRE',2000,100.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','SRE',2010,100.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','TXD',1990,1044.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','TXD',2000,1044.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','TXD',2010,1044.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','TXE',1990,2000.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','TXE',2000,1750.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','TXE',2010,1500.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','TXG',1990,1044.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','TXG',2000,1044.0,'Mdollar / (PJ^2 / GW)',''); +INSERT INTO "cost_invest" VALUES('utopia','TXG',2010,1044.0,'Mdollar / (PJ^2 / GW)',''); +CREATE TABLE cost_variable +( + region TEXT NOT NULL, + period INTEGER NOT NULL + REFERENCES time_period (period), + tech TEXT NOT NULL + REFERENCES technology (tech), + vintage INTEGER NOT NULL + REFERENCES time_period (period), + cost REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPDSL1',1990,10.0,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPDSL1',1990,10.0,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPDSL1',1990,10.0,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPGSL1',1990,15.0,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPGSL1',1990,15.0,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPGSL1',1990,15.0,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPHCO1',1990,2.0,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPHCO1',1990,2.0,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPHCO1',1990,2.0,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPOIL1',1990,8.0,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPOIL1',1990,8.0,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPOIL1',1990,8.0,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPURN1',1990,2.0,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPURN1',1990,2.0,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPURN1',1990,2.0,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1960,0.3,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1970,0.3,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1980,0.3,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1990,0.3,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',1970,0.3,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',1980,0.3,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',1990,0.3,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',2000,0.3,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',1980,0.3,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',1990,0.3,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',2000,0.3,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',2010,0.3,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E21',1990,1.5,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E21',1990,1.5,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E21',1990,1.5,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E21',2000,1.5,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E21',2000,1.5,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E21',2010,1.5,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1960,0.4,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1970,0.4,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1980,0.4,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1990,0.4,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',1970,0.4,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',1980,0.4,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',1990,0.4,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',2000,0.4,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',1980,0.4,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',1990,0.4,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',2000,0.4,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',2010,0.4,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',1990,'SRE',1990,10.0,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'SRE',1990,10.0,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2000,'SRE',2000,10.0,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'SRE',1990,10.0,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'SRE',2000,10.0,'Mdollar / (PJ)',''); +INSERT INTO "cost_variable" VALUES('utopia',2010,'SRE',2010,10.0,'Mdollar / (PJ)',''); +CREATE TABLE demand +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + commodity TEXT + REFERENCES commodity (name), + demand REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, commodity) +); +INSERT INTO "demand" VALUES('utopia',1990,'RH',25.2,'PJ',''); +INSERT INTO "demand" VALUES('utopia',2000,'RH',37.8,'PJ',''); +INSERT INTO "demand" VALUES('utopia',2010,'RH',5.669999999999999574e+01,'PJ',''); +INSERT INTO "demand" VALUES('utopia',1990,'RL',5.6,'PJ',''); +INSERT INTO "demand" VALUES('utopia',2000,'RL',8.4,'PJ',''); +INSERT INTO "demand" VALUES('utopia',2010,'RL',12.6,'PJ',''); +INSERT INTO "demand" VALUES('utopia',1990,'TX',5.2,'PJ',''); +INSERT INTO "demand" VALUES('utopia',2000,'TX',7.8,'PJ',''); +INSERT INTO "demand" VALUES('utopia',2010,'TX',11.69,'PJ',''); +CREATE TABLE demand_specific_distribution +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + demand_name TEXT + REFERENCES commodity (name), + dsd REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, demand_name), + CHECK (dsd >= 0 AND dsd <= 1) +); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','day','RH',0.12,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','night','RH',0.06,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','day','RH',0.5467,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','night','RH',0.2733,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'summer','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'summer','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','day','RL',0.5,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','night','RL',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','day','RH',0.12,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','night','RH',0.06,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','day','RH',0.5467,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','night','RH',0.2733,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'summer','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'summer','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','day','RL',0.5,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','night','RL',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','day','RH',0.12,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','night','RH',0.06,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','day','RH',0.5467,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','night','RH',0.2733,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'summer','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'summer','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','day','RL',0.5,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','night','RL',0.1,''); +CREATE TABLE efficiency +( + region TEXT, + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + efficiency REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPDSL1',1990,'DSL',1.0,'PJ / (PJ)',''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPGSL1',1990,'GSL',1.0,'PJ / (PJ)',''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPHCO1',1990,'HCO',1.0,'PJ / (PJ)',''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,'PJ / (PJ)',''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,'PJ / (PJ)',''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,'PJ / (PJ)',''); +INSERT INTO "efficiency" VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,'PJ / (PJ)',''); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1960,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1970,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1980,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1990,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',2000,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HCO','E01',2010,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','FEQ','E21',1990,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','FEQ','E21',2000,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','FEQ','E21',2010,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','URN','E21',1990,'ELC',0.4,'PJ / (PJ)','# 1/2.5'); +INSERT INTO "efficiency" VALUES('utopia','URN','E21',2000,'ELC',0.4,'PJ / (PJ)','# 1/2.5'); +INSERT INTO "efficiency" VALUES('utopia','URN','E21',2010,'ELC',0.4,'PJ / (PJ)','# 1/2.5'); +INSERT INTO "efficiency" VALUES('utopia','HYD','E31',1980,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HYD','E31',1990,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HYD','E31',2000,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','HYD','E31',2010,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1960,'ELC',0.294,'PJ / (PJ)','# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1970,'ELC',0.294,'PJ / (PJ)','# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1980,'ELC',0.294,'PJ / (PJ)','# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1990,'ELC',0.294,'PJ / (PJ)','# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',2000,'ELC',0.294,'PJ / (PJ)','# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','DSL','E70',2010,'ELC',0.294,'PJ / (PJ)','# 1/3.4'); +INSERT INTO "efficiency" VALUES('utopia','ELC','E51',1980,'ELC',0.72,'PJ / (PJ)','# 1/1.3889'); +INSERT INTO "efficiency" VALUES('utopia','ELC','E51',1990,'ELC',0.72,'PJ / (PJ)','# 1/1.3889'); +INSERT INTO "efficiency" VALUES('utopia','ELC','E51',2000,'ELC',0.72,'PJ / (PJ)','# 1/1.3889'); +INSERT INTO "efficiency" VALUES('utopia','ELC','E51',2010,'ELC',0.72,'PJ / (PJ)','# 1/1.3889'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RHE',1990,'RH',1.0,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RHE',2000,'RH',1.0,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RHE',2010,'RH',1.0,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',1970,'RH',0.7,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',1980,'RH',0.7,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',1990,'RH',0.7,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',2000,'RH',0.7,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',2010,'RH',0.7,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',1980,'RL',1.0,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',1990,'RL',1.0,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',2000,'RL',1.0,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',2010,'RL',1.0,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',1990,'DSL',1.0,'PJ / (PJ)','# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2000,'DSL',1.0,'PJ / (PJ)','# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'PJ / (PJ)','# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'PJ / (PJ)','# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'PJ / (PJ)','# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'PJ / (PJ)','# direct translation from PRC_INP2, PRC_OUT'); +INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',1970,'TX',0.231,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',1980,'TX',0.231,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',1990,'TX',0.231,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',2000,'TX',0.231,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',2010,'TX',0.231,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','TXE',1990,'TX',0.827,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','TXE',2000,'TX',0.827,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','ELC','TXE',2010,'TX',0.827,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',1970,'TX',0.231,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',1980,'TX',0.231,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',1990,'TX',0.231,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',2000,'TX',0.231,'PJ / (PJ)','# direct translation from DMD_EFF'); +INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',2010,'TX',0.231,'PJ / (PJ)','# direct translation from DMD_EFF'); +CREATE TABLE efficiency_variable +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + efficiency REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + CHECK (efficiency > 0) +); +CREATE TABLE emission_activity +( + region TEXT, + emis_comm TEXT + REFERENCES commodity (name), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) +); +INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.075,'Mt / (PJ)',''); +INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.075,'Mt / (PJ)',''); +INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',8.9e-02,'Mt / (PJ)',''); +INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.075,'Mt / (PJ)',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1970,'TX',1.0,'Mt / (PJ)',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1980,'TX',1.0,'Mt / (PJ)',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1990,'TX',1.0,'Mt / (PJ)',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',2000,'TX',1.0,'Mt / (PJ)',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',2010,'TX',1.0,'Mt / (PJ)',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1970,'TX',1.0,'Mt / (PJ)',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1980,'TX',1.0,'Mt / (PJ)',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1990,'TX',1.0,'Mt / (PJ)',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',2000,'TX',1.0,'Mt / (PJ)',''); +INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',2010,'TX',1.0,'Mt / (PJ)',''); +CREATE TABLE emission_embodied +( + region TEXT, + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE emission_end_of_life +( + region TEXT, + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, emis_comm, tech, vintage) +); +CREATE TABLE end_of_life_output +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage, output_comm) +); +CREATE TABLE existing_capacity +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +INSERT INTO "existing_capacity" VALUES('utopia','E01',1960,0.175,'GW',''); +INSERT INTO "existing_capacity" VALUES('utopia','E01',1970,0.175,'GW',''); +INSERT INTO "existing_capacity" VALUES('utopia','E01',1980,0.15,'GW',''); +INSERT INTO "existing_capacity" VALUES('utopia','E31',1980,0.1,'GW',''); +INSERT INTO "existing_capacity" VALUES('utopia','E51',1980,0.5,'GW',''); +INSERT INTO "existing_capacity" VALUES('utopia','E70',1960,0.05,'GW',''); +INSERT INTO "existing_capacity" VALUES('utopia','E70',1970,0.05,'GW',''); +INSERT INTO "existing_capacity" VALUES('utopia','E70',1980,0.2,'GW',''); +INSERT INTO "existing_capacity" VALUES('utopia','RHO',1970,12.5,'GW',''); +INSERT INTO "existing_capacity" VALUES('utopia','RHO',1980,12.5,'GW',''); +INSERT INTO "existing_capacity" VALUES('utopia','RL1',1980,5.6,'GW',''); +INSERT INTO "existing_capacity" VALUES('utopia','TXD',1970,0.4,'GW',''); +INSERT INTO "existing_capacity" VALUES('utopia','TXD',1980,0.2,'GW',''); +INSERT INTO "existing_capacity" VALUES('utopia','TXG',1970,3.1,'GW',''); +INSERT INTO "existing_capacity" VALUES('utopia','TXG',1980,1.5,'GW',''); +CREATE TABLE lifetime_process +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + lifetime REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +INSERT INTO "lifetime_process" VALUES('utopia','RL1',1980,20.0,'year','#forexistingcap'); +INSERT INTO "lifetime_process" VALUES('utopia','TXD',1970,30.0,'year','#forexistingcap'); +INSERT INTO "lifetime_process" VALUES('utopia','TXD',1980,30.0,'year','#forexistingcap'); +INSERT INTO "lifetime_process" VALUES('utopia','TXG',1970,30.0,'year','#forexistingcap'); +INSERT INTO "lifetime_process" VALUES('utopia','TXG',1980,30.0,'year','#forexistingcap'); +CREATE TABLE lifetime_survival_curve +( + region TEXT NOT NULL, + period INTEGER NOT NULL, + tech TEXT NOT NULL + REFERENCES technology (tech), + vintage INTEGER NOT NULL + REFERENCES time_period (period), + fraction REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, vintage) +); +CREATE TABLE lifetime_tech +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + lifetime REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech) +); +INSERT INTO "lifetime_tech" VALUES('utopia','E01',40.0,'year',''); +INSERT INTO "lifetime_tech" VALUES('utopia','E21',40.0,'year',''); +INSERT INTO "lifetime_tech" VALUES('utopia','E31',100.0,'year',''); +INSERT INTO "lifetime_tech" VALUES('utopia','E51',100.0,'year',''); +INSERT INTO "lifetime_tech" VALUES('utopia','E70',40.0,'year',''); +INSERT INTO "lifetime_tech" VALUES('utopia','RHE',30.0,'year',''); +INSERT INTO "lifetime_tech" VALUES('utopia','RHO',30.0,'year',''); +INSERT INTO "lifetime_tech" VALUES('utopia','RL1',10.0,'year',''); +INSERT INTO "lifetime_tech" VALUES('utopia','SRE',50.0,'year',''); +INSERT INTO "lifetime_tech" VALUES('utopia','TXD',15.0,'year',''); +INSERT INTO "lifetime_tech" VALUES('utopia','TXE',15.0,'year',''); +INSERT INTO "lifetime_tech" VALUES('utopia','TXG',15.0,'year',''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPDSL1',1000.0,'year',''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPGSL1',1000.0,'year',''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPHCO1',1000.0,'year',''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPOIL1',1000.0,'year',''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPURN1',1000.0,'year',''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPHYD',1000.0,'year',''); +INSERT INTO "lifetime_tech" VALUES('utopia','IMPFEQ',1000.0,'year',''); +CREATE TABLE limit_activity +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + activity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE limit_activity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_annual_capacity_factor +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE limit_capacity +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + capacity REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +INSERT INTO "limit_capacity" VALUES('utopia',1990,'E31','ge',0.13,'GW',''); +INSERT INTO "limit_capacity" VALUES('utopia',2000,'E31','ge',0.13,'GW',''); +INSERT INTO "limit_capacity" VALUES('utopia',2010,'E31','ge',0.13,'GW',''); +INSERT INTO "limit_capacity" VALUES('utopia',1990,'SRE','ge',0.1,'GW',''); +INSERT INTO "limit_capacity" VALUES('utopia',1990,'E31','le',0.13,'GW',''); +INSERT INTO "limit_capacity" VALUES('utopia',2000,'E31','le',0.17,'GW',''); +INSERT INTO "limit_capacity" VALUES('utopia',2010,'E31','le',2.1e-01,'GW',''); +INSERT INTO "limit_capacity" VALUES('utopia',1990,'RHE','le',0.0,'GW',''); +INSERT INTO "limit_capacity" VALUES('utopia',1990,'TXD','le',0.6,'GW',''); +INSERT INTO "limit_capacity" VALUES('utopia',2000,'TXD','le',1.76,'GW',''); +INSERT INTO "limit_capacity" VALUES('utopia',2010,'TXD','le',4.76,'GW',''); +CREATE TABLE limit_capacity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_degrowth_capacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE limit_degrowth_new_capacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE limit_degrowth_new_capacity_delta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE limit_emission +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + value REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, emis_comm, operator) +); +CREATE TABLE limit_growth_capacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE limit_growth_new_capacity +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE limit_growth_new_capacity_delta +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + rate REAL NOT NULL DEFAULT 0, + seed REAL NOT NULL DEFAULT 0, + seed_units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE limit_new_capacity +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + new_cap REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, period, tech_or_group, operator) +); +CREATE TABLE limit_new_capacity_share +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + sub_group TEXT, + super_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + share REAL, + notes TEXT, + PRIMARY KEY (region, period, sub_group, super_group, operator) +); +CREATE TABLE limit_resource +( + region TEXT, + tech_or_group TEXT, + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + cum_act REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech_or_group, operator) +); +CREATE TABLE limit_seasonal_capacity_factor +( + region TEXT + REFERENCES region (region), + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tech TEXT + REFERENCES technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + factor REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tech, operator) +); +CREATE TABLE limit_storage_level_fraction +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + fraction REAL, + notes TEXT, + PRIMARY KEY(region, period, season, tod, tech, vintage, operator) +); +CREATE TABLE limit_tech_input_split +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE limit_tech_input_split_annual +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, input_comm, tech, operator) +); +CREATE TABLE limit_tech_output_split +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +INSERT INTO "limit_tech_output_split" VALUES('utopia',1990,'SRE','DSL','ge',0.7,''); +INSERT INTO "limit_tech_output_split" VALUES('utopia',2000,'SRE','DSL','ge',0.7,''); +INSERT INTO "limit_tech_output_split" VALUES('utopia',2010,'SRE','DSL','ge',0.7,''); +INSERT INTO "limit_tech_output_split" VALUES('utopia',1990,'SRE','GSL','ge',0.3,''); +INSERT INTO "limit_tech_output_split" VALUES('utopia',2000,'SRE','GSL','ge',0.3,''); +INSERT INTO "limit_tech_output_split" VALUES('utopia',2010,'SRE','GSL','ge',0.3,''); +CREATE TABLE limit_tech_output_split_annual +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + output_comm TEXT + REFERENCES commodity (name), + operator TEXT NOT NULL DEFAULT "le" + REFERENCES operator (operator), + proportion REAL, + notes TEXT, + PRIMARY KEY (region, period, tech, output_comm, operator) +); +CREATE TABLE linked_tech +( + primary_region TEXT, + primary_tech TEXT + REFERENCES technology (tech), + emis_comm TEXT + REFERENCES commodity (name), + driven_tech TEXT + REFERENCES technology (tech), + notes TEXT, + PRIMARY KEY (primary_region, primary_tech, emis_comm) +); +CREATE TABLE loan_lifetime_process +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + lifetime REAL, + units TEXT, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE loan_rate +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech, vintage) +); +CREATE TABLE metadata +( + element TEXT, + value INT, + notes TEXT, + PRIMARY KEY (element) +); +INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); +INSERT INTO "metadata" VALUES('DB_MINOR',0,''); +CREATE TABLE metadata_real +( + element TEXT, + value REAL, + notes TEXT, + + PRIMARY KEY (element) +); +INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,''); +CREATE TABLE myopic_efficiency +( + base_year integer, + region text, + input_comm text, + tech text, + vintage integer, + output_comm text, + efficiency real, + lifetime integer, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (region, input_comm, tech, vintage, output_comm) +); +CREATE TABLE operator +( + operator TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "operator" VALUES('e','equal to'); +INSERT INTO "operator" VALUES('le','less than or equal to'); +INSERT INTO "operator" VALUES('ge','greater than or equal to'); +CREATE TABLE output_built_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + units TEXT, + PRIMARY KEY (region, scenario, tech, vintage) +); +CREATE TABLE output_cost +( + scenario TEXT, + region TEXT, + sector TEXT REFERENCES sector_label (sector), + period INTEGER REFERENCES time_period (period), + tech TEXT REFERENCES technology (tech), + vintage INTEGER REFERENCES time_period (period), + d_invest REAL, + d_fixed REAL, + d_var REAL, + d_emiss REAL, + invest REAL, + fixed REAL, + var REAL, + emiss REAL, + units TEXT, + PRIMARY KEY (scenario, region, period, tech, vintage), + FOREIGN KEY (vintage) REFERENCES time_period (period), + FOREIGN KEY (tech) REFERENCES technology (tech) +); +CREATE TABLE output_curtailment +( + scenario TEXT, + region TEXT, + sector TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES time_period (period), + tod TEXT + REFERENCES time_of_day (tod), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + curtailment REAL, + units TEXT, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_dual_variable +( + scenario TEXT, + constraint_name TEXT, + dual REAL, + PRIMARY KEY (constraint_name, scenario) +); +CREATE TABLE output_emission +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + emis_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + emission REAL, + units TEXT, + PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) +); +CREATE TABLE output_flow_in +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + flow REAL, + units TEXT, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_flow_out +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + flow REAL, + units TEXT, + PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_flow_out_summary +( + scenario TEXT NOT NULL, + region TEXT NOT NULL, + sector TEXT, + period INTEGER, + input_comm TEXT NOT NULL, + tech TEXT NOT NULL, + vintage INTEGER, + output_comm TEXT NOT NULL, + flow REAL NOT NULL, + + FOREIGN KEY (tech) REFERENCES technology (tech), + PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) +); +CREATE TABLE output_net_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + capacity REAL, + units TEXT, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_objective +( + scenario TEXT, + objective_name TEXT, + total_system_cost REAL +); +CREATE TABLE output_retired_capacity +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + cap_eol REAL, + cap_early REAL, + units TEXT, + PRIMARY KEY (region, scenario, period, tech, vintage) +); +CREATE TABLE output_storage_level +( + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + level REAL, + units TEXT, + PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) +); +CREATE TABLE planning_reserve_margin +( + region TEXT + PRIMARY KEY + REFERENCES region (region), + margin REAL, + notes TEXT +); +CREATE TABLE ramp_down_hourly +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE ramp_up_hourly +( + region TEXT, + tech TEXT + REFERENCES technology (tech), + rate REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE region +( + region TEXT + PRIMARY KEY, + notes TEXT +); +INSERT INTO "region" VALUES('utopia',NULL); +CREATE TABLE reserve_capacity_derate +( + region TEXT, + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER, + factor REAL, + notes TEXT, + PRIMARY KEY (region, period, season, tech, vintage), + CHECK (factor >= 0 AND factor <= 1) +); +CREATE TABLE rps_requirement +( + region TEXT NOT NULL + REFERENCES region (region), + period INTEGER NOT NULL + REFERENCES time_period (period), + tech_group TEXT NOT NULL + REFERENCES tech_group (group_name), + requirement REAL NOT NULL, + notes TEXT +); +CREATE TABLE season_label +( + season TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "season_label" VALUES('inter',NULL); +INSERT INTO "season_label" VALUES('summer',NULL); +INSERT INTO "season_label" VALUES('winter',NULL); +CREATE TABLE sector_label +( + sector TEXT PRIMARY KEY, + notes TEXT +); +INSERT INTO "sector_label" VALUES('supply',NULL); +INSERT INTO "sector_label" VALUES('electric',NULL); +INSERT INTO "sector_label" VALUES('transport',NULL); +INSERT INTO "sector_label" VALUES('commercial',NULL); +INSERT INTO "sector_label" VALUES('residential',NULL); +INSERT INTO "sector_label" VALUES('industrial',NULL); +CREATE TABLE storage_duration +( + region TEXT, + tech TEXT, + duration REAL, + notes TEXT, + PRIMARY KEY (region, tech) +); +CREATE TABLE tech_group +( + group_name TEXT + PRIMARY KEY, + notes TEXT +); +CREATE TABLE tech_group_member +( + group_name TEXT + REFERENCES tech_group (group_name), + tech TEXT + REFERENCES technology (tech), + PRIMARY KEY (group_name, tech) +); +CREATE TABLE technology +( + tech TEXT NOT NULL PRIMARY KEY, + flag TEXT NOT NULL, + sector TEXT, + category TEXT, + sub_category TEXT, + unlim_cap INTEGER NOT NULL DEFAULT 0, + annual INTEGER NOT NULL DEFAULT 0, + reserve INTEGER NOT NULL DEFAULT 0, + curtail INTEGER NOT NULL DEFAULT 0, + retire INTEGER NOT NULL DEFAULT 0, + flex INTEGER NOT NULL DEFAULT 0, + exchange INTEGER NOT NULL DEFAULT 0, + seas_stor INTEGER NOT NULL DEFAULT 0, + description TEXT, + FOREIGN KEY (flag) REFERENCES technology_type (label) +); +INSERT INTO "technology" VALUES('IMPDSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported diesel'); +INSERT INTO "technology" VALUES('IMPGSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported gasoline'); +INSERT INTO "technology" VALUES('IMPHCO1','p','supply','coal','',1,0,0,0,0,0,0,0,' imported coal'); +INSERT INTO "technology" VALUES('IMPOIL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported crude oil'); +INSERT INTO "technology" VALUES('IMPURN1','p','supply','nuclear','',1,0,0,0,0,0,0,0,' imported uranium'); +INSERT INTO "technology" VALUES('IMPFEQ','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported fossil equivalent'); +INSERT INTO "technology" VALUES('IMPHYD','p','supply','hydro','',1,0,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); +INSERT INTO "technology" VALUES('E01','pb','electric','coal','',0,0,0,0,0,0,0,0,' coal power plant'); +INSERT INTO "technology" VALUES('E21','pb','electric','nuclear','',0,0,0,0,0,0,0,0,' nuclear power plant'); +INSERT INTO "technology" VALUES('E31','pb','electric','hydro','',0,0,0,0,0,0,0,0,' hydro power'); +INSERT INTO "technology" VALUES('E51','ps','electric','electric','',0,0,0,0,0,0,0,0,' electric storage'); +INSERT INTO "technology" VALUES('E70','p','electric','petroleum','',0,0,0,0,0,0,0,0,' diesel power plant'); +INSERT INTO "technology" VALUES('RHE','p','residential','electric','',0,0,0,0,0,0,0,0,' electric residential heating'); +INSERT INTO "technology" VALUES('RHO','p','residential','petroleum','',0,0,0,0,0,0,0,0,' diesel residential heating'); +INSERT INTO "technology" VALUES('RL1','p','residential','electric','',0,0,0,0,0,0,0,0,' residential lighting'); +INSERT INTO "technology" VALUES('SRE','p','supply','petroleum','',0,0,0,0,0,0,0,0,' crude oil processor'); +INSERT INTO "technology" VALUES('TXD','p','transport','petroleum','',0,0,0,0,0,0,0,0,' diesel powered vehicles'); +INSERT INTO "technology" VALUES('TXE','p','transport','electric','',0,0,0,0,0,0,0,0,' electric powered vehicles'); +INSERT INTO "technology" VALUES('TXG','p','transport','petroleum','',0,0,0,0,0,0,0,0,' gasoline powered vehicles'); +CREATE TABLE technology_type +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO "technology_type" VALUES('p','production technology'); +INSERT INTO "technology_type" VALUES('pb','baseload production technology'); +INSERT INTO "technology_type" VALUES('ps','storage production technology'); +CREATE TABLE time_of_day +( + sequence INTEGER UNIQUE, + tod TEXT + PRIMARY KEY +); +INSERT INTO "time_of_day" VALUES(1,'day'); +INSERT INTO "time_of_day" VALUES(2,'night'); +CREATE TABLE time_period +( + sequence INTEGER UNIQUE, + period INTEGER + PRIMARY KEY, + flag TEXT + REFERENCES time_period_type (label) +); +INSERT INTO "time_period" VALUES(1,1960,'e'); +INSERT INTO "time_period" VALUES(2,1970,'e'); +INSERT INTO "time_period" VALUES(3,1980,'e'); +INSERT INTO "time_period" VALUES(4,1990,'f'); +INSERT INTO "time_period" VALUES(5,2000,'f'); +INSERT INTO "time_period" VALUES(6,2010,'f'); +INSERT INTO "time_period" VALUES(7,2020,'f'); +CREATE TABLE time_period_type +( + label TEXT + PRIMARY KEY, + description TEXT +); +INSERT INTO "time_period_type" VALUES('e','existing vintages'); +INSERT INTO "time_period_type" VALUES('f','future'); +CREATE TABLE time_season +( + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + season TEXT REFERENCES season_label(season), + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +INSERT INTO "time_season" VALUES(1990,1,'inter',NULL); +INSERT INTO "time_season" VALUES(1990,2,'summer',NULL); +INSERT INTO "time_season" VALUES(1990,3,'winter',NULL); +INSERT INTO "time_season" VALUES(2000,1,'inter',NULL); +INSERT INTO "time_season" VALUES(2000,2,'summer',NULL); +INSERT INTO "time_season" VALUES(2000,3,'winter',NULL); +INSERT INTO "time_season" VALUES(2010,1,'inter',NULL); +INSERT INTO "time_season" VALUES(2010,2,'summer',NULL); +INSERT INTO "time_season" VALUES(2010,3,'winter',NULL); +CREATE TABLE time_season_all +( + period INTEGER + REFERENCES time_period (period), + sequence INTEGER, + season TEXT + REFERENCES season_label (season), + notes TEXT, + PRIMARY KEY (period, sequence, season) +); +CREATE TABLE time_season_sequential +( + period INTEGER REFERENCES time_period (period), + sequence INTEGER, + seas_seq TEXT, + season TEXT REFERENCES season_label(season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) +); +CREATE TABLE time_season_to_sequential +( + period INTEGER + REFERENCES time_period (period), + sequence INTEGER, + seas_seq TEXT, + season TEXT + REFERENCES season_label (season), + num_days REAL NOT NULL, + notes TEXT, + PRIMARY KEY (period, sequence, seas_seq, season), + CHECK (num_days > 0) +); +CREATE TABLE time_segment_fraction +( + period INTEGER + REFERENCES time_period (period), + season TEXT + REFERENCES season_label (season), + tod TEXT + REFERENCES time_of_day (tod), + segment_fraction REAL, + notes TEXT, + PRIMARY KEY (period, season, tod), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) +); +INSERT INTO "time_segment_fraction" VALUES(1990,'inter','day',0.1667,'# I-D'); +INSERT INTO "time_segment_fraction" VALUES(1990,'inter','night',0.0833,'# I-N'); +INSERT INTO "time_segment_fraction" VALUES(1990,'summer','day',0.1667,'# S-D'); +INSERT INTO "time_segment_fraction" VALUES(1990,'summer','night',0.0833,'# S-N'); +INSERT INTO "time_segment_fraction" VALUES(1990,'winter','day',0.3333,'# W-D'); +INSERT INTO "time_segment_fraction" VALUES(1990,'winter','night',0.1667,'# W-N'); +INSERT INTO "time_segment_fraction" VALUES(2000,'inter','day',0.1667,'# I-D'); +INSERT INTO "time_segment_fraction" VALUES(2000,'inter','night',0.0833,'# I-N'); +INSERT INTO "time_segment_fraction" VALUES(2000,'summer','day',0.1667,'# S-D'); +INSERT INTO "time_segment_fraction" VALUES(2000,'summer','night',0.0833,'# S-N'); +INSERT INTO "time_segment_fraction" VALUES(2000,'winter','day',0.3333,'# W-D'); +INSERT INTO "time_segment_fraction" VALUES(2000,'winter','night',0.1667,'# W-N'); +INSERT INTO "time_segment_fraction" VALUES(2010,'inter','day',0.1667,'# I-D'); +INSERT INTO "time_segment_fraction" VALUES(2010,'inter','night',0.0833,'# I-N'); +INSERT INTO "time_segment_fraction" VALUES(2010,'summer','day',0.1667,'# S-D'); +INSERT INTO "time_segment_fraction" VALUES(2010,'summer','night',0.0833,'# S-N'); +INSERT INTO "time_segment_fraction" VALUES(2010,'winter','day',0.3333,'# W-D'); +INSERT INTO "time_segment_fraction" VALUES(2010,'winter','night',0.1667,'# W-N'); +CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); +COMMIT; diff --git a/temoa/tutorial_assets/utopia.sqlite b/temoa/tutorial_assets/utopia.sqlite deleted file mode 100644 index 1e3008d3b12e57f9f96e039101fc6e74d63e5a79..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1028096 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%0D($0`3W0UyS8bh8o3IfHaTJcRqf)H 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 Date: Tue, 16 Dec 2025 14:14:15 -0500 Subject: [PATCH 392/587] adding unit propagation to table writer --- temoa/_internal/table_writer.py | 69 +++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/temoa/_internal/table_writer.py b/temoa/_internal/table_writer.py index d77b0f613..42fa140a2 100644 --- a/temoa/_internal/table_writer.py +++ b/temoa/_internal/table_writer.py @@ -39,6 +39,7 @@ from temoa.core.config import TemoaConfig from temoa.core.model import TemoaModel from temoa.extensions.monte_carlo.mc_run import ChangeRecord + from temoa.model_checking.unit_checking.unit_propagator import UnitPropagator from temoa.types.core_types import Period, Region, Technology, Vintage logger = getLogger(__name__) @@ -91,6 +92,9 @@ def __init__(self, config: TemoaConfig, epsilon: float = 1e-5) -> None: logger.exception('Failed to connect to output database: %s', config.output_database) sys.exit(-1) + # Unit propagator for populating units in output tables (lazy init) + self._unit_propagator: UnitPropagator | None = None + @property def connection(self) -> sqlite3.Connection: """ @@ -123,6 +127,28 @@ def close(self) -> None: finally: self.con = None + @property + def unit_propagator(self) -> UnitPropagator | None: + """ + Lazily initialize and return the unit propagator. + + Returns None if initialization fails, ensuring graceful fallback + for databases without unit information. + """ + if self._unit_propagator is None: + try: + from temoa.model_checking.unit_checking.unit_propagator import ( + UnitPropagator, + ) + + self._unit_propagator = UnitPropagator(self.connection) + if not self._unit_propagator.has_unit_data: + logger.debug('No unit data available in database') + except (ImportError, sqlite3.Error, RuntimeError) as e: + logger.debug('Could not initialize unit propagator: %s', e, exc_info=True) + # Leave as None - units will be None in output + return self._unit_propagator + def _validate_foreign_keys(self) -> None: """ Re-enables foreign keys, runs a check, and logs any violations. @@ -324,6 +350,7 @@ def write_storage_level(self, model: TemoaModel, iteration: int | None = None) - storage_levels = poll_storage_level_results(model=model) scenario = self._get_scenario_name(iteration) + unit_prop = self.unit_propagator records = [] for sli, val in storage_levels.items(): @@ -338,7 +365,7 @@ def write_storage_level(self, model: TemoaModel, iteration: int | None = None) - 'tech': sli.t, 'vintage': sli.v, 'level': val, - 'units': None, + 'units': unit_prop.get_storage_units(sli.t) if unit_prop else None, } ) @@ -369,6 +396,7 @@ def write_emissions(self, iteration: int | None = None) -> None: raise RuntimeError('Dependencies missing (tech_sectors or emission_register)') scenario = self._get_scenario_name(iteration) + unit_prop = self.unit_propagator records = [] for ei, val in self.emission_register.items(): @@ -383,7 +411,7 @@ def write_emissions(self, iteration: int | None = None) -> None: 'emis_comm': ei.e, 'tech': ei.t, 'vintage': ei.v, - 'units': None, + 'units': unit_prop.get_emission_units(ei.e) if unit_prop else None, } if hasattr(ei, 'p'): # emissions from flows @@ -405,6 +433,7 @@ def _insert_capacity_results(self, cap_data: CapData, iteration: int | None) -> raise RuntimeError('tech sectors not available... code error') scenario = self._get_scenario_name(iteration) + unit_prop = self.unit_propagator # 1. Built Capacity built_recs = [] @@ -417,7 +446,7 @@ def _insert_capacity_results(self, cap_data: CapData, iteration: int | None) -> 'tech': t, 'vintage': v, 'capacity': val, - 'units': None, + 'units': unit_prop.get_capacity_units(t) if unit_prop else None, } ) self._bulk_insert('output_built_capacity', built_recs) @@ -434,7 +463,7 @@ def _insert_capacity_results(self, cap_data: CapData, iteration: int | None) -> 'tech': t, 'vintage': v, 'capacity': val, - 'units': None, + 'units': unit_prop.get_capacity_units(t) if unit_prop else None, } ) self._bulk_insert('output_net_capacity', net_recs) @@ -452,7 +481,7 @@ def _insert_capacity_results(self, cap_data: CapData, iteration: int | None) -> 'vintage': v, 'cap_eol': eol, 'cap_early': early, - 'units': None, + 'units': unit_prop.get_capacity_units(t) if unit_prop else None, } ) self._bulk_insert('output_retired_capacity', ret_recs) @@ -497,7 +526,7 @@ def write_flow_tables(self, iteration: int | None = None) -> None: 'tech': fi.t, 'vintage': fi.v, 'output_comm': fi.o, - 'units': None, + 'units': self._get_flow_units(flow_type, fi.i, fi.o), } # Assign value to correct column name based on table/type @@ -513,6 +542,31 @@ def write_flow_tables(self, iteration: int | None = None) -> None: self.connection.commit() + def _get_flow_units(self, flow_type: FlowType, input_comm: str, output_comm: str) -> str | None: + """ + Get units for flow based on flow type. + + For output flows and curtailment, uses the output commodity units. + For input flows, uses the input commodity units. + + Args: + flow_type: Type of flow (IN, OUT, CURTAIL, FLEX). + input_comm: Input commodity name. + output_comm: Output commodity name. + + Returns: + Unit string or None if not available. + """ + unit_prop = self.unit_propagator + if not unit_prop: + return None + + if flow_type == FlowType.IN: + return unit_prop.get_flow_in_units(input_comm) + else: + # OUT, CURTAIL, FLEX all use output commodity units + return unit_prop.get_flow_out_units(output_comm) + def write_summary_flow(self, model: TemoaModel, iteration: int | None = None) -> None: flow_data = self.calculate_flows(model=model) self._insert_summary_flow_results(flow_data=flow_data, iteration=iteration) @@ -636,6 +690,7 @@ def _write_cost_rows( raise RuntimeError('tech sectors not available... code error') scenario = self._get_scenario_name(iteration) + unit_prop = self.unit_propagator records = [] sorted_keys = sorted(entries.keys()) @@ -658,7 +713,7 @@ def _write_cost_rows( 'fixed': costs.get(CostType.FIXED, 0), 'var': costs.get(CostType.VARIABLE, 0), 'emiss': costs.get(CostType.EMISS, 0), - 'units': None, + 'units': unit_prop.get_cost_units() if unit_prop else None, } ) From 290d58dde1476a8368bbd0371d6bdb4444faafc1 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 16 Dec 2025 14:14:59 -0500 Subject: [PATCH 393/587] tests: adding tests for unit checking, integration, and propagation --- tests/conftest.py | 154 ++++++++++++++-- tests/test_unit_checking.py | 100 +++++++++++ tests/test_unit_checking_integration.py | 97 +++++++++++ tests/test_unit_propagation.py | 223 ++++++++++++++++++++++++ tests/test_unit_scavenging.py | 56 ++++++ tests/testing_outputs/.gitignore | 7 +- 6 files changed, 617 insertions(+), 20 deletions(-) create mode 100644 tests/test_unit_checking.py create mode 100644 tests/test_unit_checking_integration.py create mode 100644 tests/test_unit_propagation.py create mode 100644 tests/test_unit_scavenging.py diff --git a/tests/conftest.py b/tests/conftest.py index 1041c686d..34f4de3ea 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,6 +5,7 @@ from typing import Any import pytest +from _pytest.config import Config from pyomo.opt import SolverResults from temoa._internal.temoa_sequencer import TemoaSequencer @@ -40,30 +41,151 @@ def refresh_databases() -> None: """ data_output_path = Path(__file__).parent / 'testing_outputs' data_source_path = Path(__file__).parent / 'testing_data' - databases = ( - ('utopia.sql', 'utopia.sqlite'), - ('utopia.sql', 'myo_utopia.sqlite'), - ('test_system.sql', 'test_system.sqlite'), - ('storageville.sql', 'storageville.sqlite'), - ('mediumville.sql', 'mediumville.sqlite'), - ('emissions.sql', 'emissions.sqlite'), - ('materials.sql', 'materials.sqlite'), - ('simple_linked_tech.sql', 'simple_linked_tech.sqlite'), - ('seasonal_storage.sql', 'seasonal_storage.sqlite'), - ('survival_curve.sql', 'survival_curve.sqlite'), - ('annualised_demand.sql', 'annualised_demand.sqlite'), - ) - for src, db in databases: + # utopia.sql is in tutorial_assets (single source of truth for unit-compliant data) + tutorial_assets_path = Path(__file__).parent.parent / 'temoa' / 'tutorial_assets' + + # Map source files to their locations + # (source_dir, source_file, output_file) + databases = [ + # Utopia uses the tutorial_assets source (unit-compliant) + (tutorial_assets_path, 'utopia.sql', 'utopia.sqlite'), + (tutorial_assets_path, 'utopia.sql', 'myo_utopia.sqlite'), + # Other test databases use testing_data + (data_source_path, 'test_system.sql', 'test_system.sqlite'), + (data_source_path, 'storageville.sql', 'storageville.sqlite'), + (data_source_path, 'mediumville.sql', 'mediumville.sqlite'), + (data_source_path, 'emissions.sql', 'emissions.sqlite'), + (data_source_path, 'materials.sql', 'materials.sqlite'), + (data_source_path, 'simple_linked_tech.sql', 'simple_linked_tech.sqlite'), + (data_source_path, 'seasonal_storage.sql', 'seasonal_storage.sqlite'), + (data_source_path, 'survival_curve.sql', 'survival_curve.sqlite'), + (data_source_path, 'annualised_demand.sql', 'annualised_demand.sqlite'), + ] + for source_dir, src, db in databases: if Path.exists(data_output_path / db): os.remove(data_output_path / db) # make a new one and fill it con = sqlite3.connect(data_output_path / db) - with open(data_source_path / src) as script: + with open(source_dir / src) as script: con.executescript(script.read()) con.close() -refresh_databases() +def create_unit_test_db_from_sql( + source_sql_path: Path, output_db_path: Path, modifications: list[tuple[str, tuple[Any, ...]]] +) -> None: + """Create a unit test database from SQL source with specific modifications. + + Args: + source_sql_path: Path to the source SQL file + output_db_path: Path where the database should be created + modifications: List of (sql, params) tuples to apply after creation + """ + if output_db_path.exists(): + output_db_path.unlink() + + # Generate database from SQL source and apply modifications + with sqlite3.connect(output_db_path) as conn: + # Execute the SQL source to create the database + conn.executescript(source_sql_path.read_text(encoding='utf-8')) + + # Apply modifications + for sql, params in modifications: + conn.execute(sql, params) + conn.commit() + + +def create_unit_test_dbs() -> None: + """Create unit test databases from SQL source for unit checking tests. + + Generates databases from the single SQL source of truth (tutorial_assets/utopia.sql), + applying modifications for each test case. + """ + test_output_dir = Path(__file__).parent / 'testing_outputs' + test_output_dir.mkdir(exist_ok=True) + + # Source SQL file path (single source of truth) + source_sql = Path(__file__).parent.parent / 'temoa' / 'tutorial_assets' / 'utopia.sql' + + if not source_sql.exists(): + raise FileNotFoundError( + f'Source SQL not found at: {source_sql}. Please ensure the Utopia tutorial SQL exists.' + ) + + # Define unit test variations with their modifications + unit_test_variations = [ + # 1. Valid database (baseline) - no modifications + ('utopia_valid_units.sqlite', []), + # 2. Invalid currency (no currency dimension in cost table) + ( + 'utopia_invalid_currency.sqlite', + [ + ("UPDATE cost_invest SET units = 'PJ / (GW)' WHERE ROWID = 1", ()), + ], + ), + # 3. Energy units in capacity table (GWh instead of GW) + ( + 'utopia_energy_in_capacity.sqlite', + [ + ("UPDATE existing_capacity SET units = 'GWh' WHERE ROWID = 1", ()), + ], + ), + # 4. Missing parentheses in ratio format + ( + 'utopia_missing_parentheses.sqlite', + [ + ("UPDATE efficiency SET units = 'PJ / Mt' WHERE ROWID = 1", ()), + ], + ), + # 5. Unknown/unregistered units + ( + 'utopia_unknown_units.sqlite', + [ + ("UPDATE commodity SET units = 'catfood' WHERE name = 'co2'", ()), + ], + ), + # 6. Mismatched tech output units + ( + 'utopia_mismatched_outputs.sqlite', + [ + ( + """ + UPDATE efficiency + SET units = 'GJ / (Mt)' + WHERE tech = 'E01' AND output_comm = 'ELC' AND ROWID = + (SELECT MIN(ROWID) FROM efficiency WHERE tech = 'E01') + """, + (), + ), + ], + ), + # 7. Composite currency with nonsensical dimensions + ( + 'utopia_bad_composite_currency.sqlite', + [ + ("UPDATE cost_invest SET units = 'dollar * meter' WHERE ROWID = 1", ()), + ], + ), + ] + + for db_name, modifications in unit_test_variations: + output_path = test_output_dir / db_name + create_unit_test_db_from_sql(source_sql, output_path, modifications) + logger.info('Created unit test DB: %s', db_name) + + +def pytest_configure(config: Config) -> None: # noqa: ARG001 + """Setup test databases before test collection.""" + refresh_databases() + try: + create_unit_test_dbs() + except FileNotFoundError as e: + # Source DB not available; unit tests will be skipped via pytestmark + logger.warning( + 'Unit test databases not created: source SQL not found. ' + 'Unit checking tests will be skipped.' + ) + logger.debug('DB creation skipped due to: %s', e) @pytest.fixture() diff --git a/tests/test_unit_checking.py b/tests/test_unit_checking.py new file mode 100644 index 000000000..4426c09d1 --- /dev/null +++ b/tests/test_unit_checking.py @@ -0,0 +1,100 @@ +""" +Unit checking module tests for Temoa v4 + +Tests for the unit checking validation using pint library + +""" + +import pytest + +from temoa.model_checking.unit_checking import ureg +from temoa.model_checking.unit_checking.common import RATIO_ELEMENT, SINGLE_ELEMENT, UnitsFormat +from temoa.model_checking.unit_checking.entry_checker import ( + validate_units_expression, + validate_units_format, +) + +cases = [ + ('PJ', SINGLE_ELEMENT, True), + (' kWh', SINGLE_ELEMENT, True), + ('dog_food ', SINGLE_ELEMENT, True), + (' G * tonne', SINGLE_ELEMENT, True), + ('Mt.steel ', SINGLE_ELEMENT, False), # period not allowed + ('PJ / day', SINGLE_ELEMENT, True), # SINGLE_ELEMENT regex allows slashes + ('PJ / (kT)', RATIO_ELEMENT, True), + ('(PJ) / (kT)', RATIO_ELEMENT, False), # numerator with parens doesn't match RATIO regex + ('PJ / kT', RATIO_ELEMENT, False), # no parens on denom + ( + 'kWh/day/(cycle)', + RATIO_ELEMENT, + True, + ), # matches: numerator has slash (allowed), denom in parens + ('(kWh/day)/(cycle)', RATIO_ELEMENT, False), # numerator parens not in RATIO regex +] + + +@pytest.mark.parametrize( + ('entry', 'units_format', 'expected'), + cases, + ids=[f'{t[0]} -> {"valid" if t[2] else "invalid"}' for t in cases], +) +def test_format_validation(entry: str, units_format: UnitsFormat, expected: bool) -> None: + """Test the regex matching for unit format + Note: The unit values here are NOT tested within the Units Registry + This test is solely to test the regex to grab the units, esp the ratio units""" + is_valid, _ = validate_units_format(expr=entry, unit_format=units_format) + assert is_valid is expected + + +# Test cases: (expression, (is_valid, unit_object)) +# These test actual unit registry validation +expression_cases = [ + ('kg', True, ureg.kg), + ('kg/m^3', True, ureg('kg/(meter*meter*meter)')), + ('m/s', True, ureg('m/s')), + ('dog_food', False, None), + ('ethos', True, ureg.ethos), + ('passenger', True, ureg.passenger), + ('seat', True, ureg.seat), + ('dollar', True, ureg.dollar), + ('dollars', True, ureg.dollar), + ('USD', True, ureg.dollar), + ('EUR', True, ureg.euro), + ('kWh', True, ureg.kWh), +] + + +@pytest.mark.parametrize( + ('expr', 'is_valid', 'expected_unit'), + expression_cases, + ids=[f'{t[0]} -> {"valid" if t[1] else "invalid"}' for t in expression_cases], +) +def test_validate_units_expression(expr: str, is_valid: bool, expected_unit: object) -> None: + """ + Test the validate_units_expression function against various unit expressions. + """ + valid, result_unit = validate_units_expression(expr) + assert valid == is_valid + if is_valid: + assert result_unit == expected_unit + else: + assert result_unit is None + + +# Time dimension exponents: power units have [time]^-3, energy units have [time]^-2 +time_dimension_cases = [('kW', -3), ('kWh', -2), ('PJ', -2), ('PJ/h', -3)] + + +@pytest.mark.parametrize( + ('expr', 'location'), + time_dimension_cases, + ids=[t[0] for t in time_dimension_cases], +) +def test_time_dimension_locator(expr: str, location: int) -> None: + valid, test_value = validate_units_expression(expr) + assert valid, f'Expression {expr} should be valid' + assert test_value is not None, f'Expected unit object for {expr}' + found = test_value.dimensionality.get('[time]') + assert found == location, ( + f'time dimension not found at expected location for units: {test_value}' + ) diff --git a/tests/test_unit_checking_integration.py b/tests/test_unit_checking_integration.py new file mode 100644 index 000000000..b7baeeeed --- /dev/null +++ b/tests/test_unit_checking_integration.py @@ -0,0 +1,97 @@ +""" +Integration tests for unit checking using pre-built test databases. + +Uses Utopia database variants with specific unit errors to test the unit checker. +Test databases are created by create_unit_test_dbs() in tests/conftest.py during +pytest setup. +""" + +import shutil +from pathlib import Path + +import pytest + +from temoa.model_checking.unit_checking.screener import screen + +# Test database paths +TEST_DB_DIR = Path(__file__).parent / 'testing_outputs' + +# Module-level skip condition - all tests require the test databases +DBS_PRESENT = (TEST_DB_DIR / 'utopia_valid_units.sqlite').exists() + +pytestmark = pytest.mark.skipif( + not DBS_PRESENT, + reason='Test databases not created. Ensure conftest.py setup completed successfully.', +) + + +def test_valid_units_pass_check() -> None: + """Test that properly configured Utopia database passes all checks. + + This includes verifying that valid composite units with currency dimensions + (e.g., 'Mdollar / (PJ^2 / GW)') are accepted. + """ + db_path = TEST_DB_DIR / 'utopia_valid_units.sqlite' + + result = screen(db_path) + + assert result is True, 'Valid Utopia database should pass all unit checks' + + +def test_invalid_currency_units_detected() -> None: + """Test that cost units without currency dimension are detected""" + db_path = TEST_DB_DIR / 'utopia_invalid_currency.sqlite' + report_dir = TEST_DB_DIR / 'reports' + + try: + result = screen(db_path, report_dir=report_dir) + finally: + if report_dir.exists(): + shutil.rmtree(report_dir) + + assert result is False, 'Should detect missing currency dimension in cost table' + + +def test_energy_units_in_capacity_table_detected() -> None: + """Test that energy units (GWh) in capacity tables are detected""" + db_path = TEST_DB_DIR / 'utopia_energy_in_capacity.sqlite' + + result = screen(db_path) + + assert result is False, 'Should detect energy units (GWh) in capacity table' + + +def test_missing_ratio_parentheses_detected() -> None: + """Test that missing parentheses in ratio format are detected""" + db_path = TEST_DB_DIR / 'utopia_missing_parentheses.sqlite' + + result = screen(db_path) + + assert result is False, 'Should detect missing parentheses in ratio format' + + +def test_unknown_units_detected() -> None: + """Test that unregistered units are detected""" + db_path = TEST_DB_DIR / 'utopia_unknown_units.sqlite' + + result = screen(db_path) + + assert result is False, 'Should detect unregistered units' + + +def test_mismatched_tech_output_units_detected() -> None: + """Test that technologies with mismatched output units are detected""" + db_path = TEST_DB_DIR / 'utopia_mismatched_outputs.sqlite' + + result = screen(db_path) + + assert result is False, 'Should detect mismatched output units for same tech' + + +def test_bad_composite_currency_rejected() -> None: + """Test that nonsensical currency composites (dollar*meter) are caught""" + db_path = TEST_DB_DIR / 'utopia_bad_composite_currency.sqlite' + + result = screen(db_path) + + assert result is False, 'Should reject nonsensical currency composite (dollar*meter)' diff --git a/tests/test_unit_propagation.py b/tests/test_unit_propagation.py new file mode 100644 index 000000000..aec882f19 --- /dev/null +++ b/tests/test_unit_propagation.py @@ -0,0 +1,223 @@ +""" +Tests for the UnitPropagator class. + +Tests unit derivation from input tables for output table population. +""" + +import sqlite3 +from collections.abc import Generator +from pathlib import Path + +import pytest + +from temoa.model_checking.unit_checking.unit_propagator import UnitPropagator + +# Use the utopia_valid_units database which has proper units +TEST_DB_DIR = Path(__file__).parent / 'testing_outputs' +VALID_UNITS_DB = TEST_DB_DIR / 'utopia_valid_units.sqlite' + +# Skip if test database doesn't exist +pytestmark = pytest.mark.skipif( + not VALID_UNITS_DB.exists(), + reason='Test database not created. Ensure conftest.py setup completed.', +) + + +@pytest.fixture +def propagator() -> Generator[UnitPropagator, None, None]: + """Create a UnitPropagator from the valid units database.""" + with sqlite3.connect(VALID_UNITS_DB) as conn: + yield UnitPropagator(conn) + + +def test_propagator_has_unit_data(propagator: UnitPropagator) -> None: + """Verify propagator detects available unit data.""" + assert propagator.has_unit_data is True + + +def test_get_flow_out_units(propagator: UnitPropagator) -> None: + """Test flow out units derived from commodity table.""" + # ELC is a commodity in Utopia with units + units = propagator.get_flow_out_units('ELC') + assert units is not None + assert 'joule' in units.lower() or 'pj' in units.lower() + + +def test_get_flow_in_units(propagator: UnitPropagator) -> None: + """Test flow in units derived from commodity table.""" + units = propagator.get_flow_in_units('DSL') + assert units is not None + + +def test_get_capacity_units(propagator: UnitPropagator) -> None: + """Test capacity units derived from existing_capacity table.""" + units = propagator.get_capacity_units('E01') + assert units == 'GW' + + +def test_get_cost_units(propagator: UnitPropagator) -> None: + """Test cost units derived from cost tables.""" + units = propagator.get_cost_units() + # Should be currency-based + assert units is not None + assert 'dollar' in units.lower() or 'usd' in units.lower() + + +def test_missing_commodity_returns_none(propagator: UnitPropagator) -> None: + """Test that missing commodities return None gracefully.""" + units = propagator.get_flow_out_units('NONEXISTENT_COMMODITY') + assert units is None + + +def test_missing_tech_capacity_returns_none(propagator: UnitPropagator) -> None: + """Test that missing tech returns None for capacity units.""" + units = propagator.get_capacity_units('NONEXISTENT_TECH') + assert units is None + + +def test_empty_database_graceful_fallback() -> None: + """Test that an empty/minimal database doesn't crash the propagator.""" + # Create in-memory database with minimal schema - use context manager to avoid leaks + with sqlite3.connect(':memory:') as conn: + conn.execute('CREATE TABLE commodity (name TEXT, flag TEXT, description TEXT, units TEXT)') + conn.execute('CREATE TABLE metadata (element TEXT, value INT)') + conn.execute("INSERT INTO metadata VALUES ('DB_MAJOR', 4)") + conn.commit() + + propagator = UnitPropagator(conn) + + # Should not crash, just return None/empty + assert propagator.get_flow_out_units('anything') is None + assert propagator.get_capacity_units('anything') is None + assert propagator.get_cost_units() is None + + +# --------------------------------------------------------------------------- +# Integration test for end-to-end unit propagation +# --------------------------------------------------------------------------- + + +@pytest.fixture(scope='module') +def solved_db_with_units(tmp_path_factory: pytest.TempPathFactory) -> Path: + """ + Run a model solve using utopia_valid_units database and return path to results. + + This fixture creates a copy of the valid units database, runs a full model + solve, and returns the path for verification. + """ + import shutil + + from temoa._internal.temoa_sequencer import TemoaSequencer + from temoa.core.config import TemoaConfig + + # Skip if source database or solver doesn't exist + if not VALID_UNITS_DB.exists(): + pytest.skip('Valid units database not available') + + is_available, _location = TemoaConfig._check_solver_availability('appsi_highs') + if not is_available: + pytest.skip('Solver appsi_highs not available') + + # Create working directory and copy database + tmp_dir = tmp_path_factory.mktemp('unit_propagation') + working_db = tmp_dir / 'utopia_propagation_test.sqlite' + shutil.copy(VALID_UNITS_DB, working_db) + + # Create a config file that points to the correct database + # Use as_posix() to ensure forward slashes, avoiding escape sequence issues on Windows in TOML + config_content = ( + f'scenario = "unit_test"\n' + f'scenario_mode = "perfect_foresight"\n' + f'input_database = "{working_db.as_posix()}"\n' + f'output_database = "{working_db.as_posix()}"\n' + f'solver_name = "appsi_highs"\n' + f'save_excel = false\n' + f'save_duals = false\n' + f'time_sequencing = "seasonal_timeslices"\n' + ) + config_file = tmp_dir / 'config_unit_propagation.toml' + config_file.write_text(config_content) + + # Build config from our temporary config file + config = TemoaConfig.build_config( + config_file=config_file, + output_path=tmp_dir, + silent=True, + ) + + # Run the model + sequencer = TemoaSequencer(config=config) + sequencer.start() + + return working_db + + +def test_units_propagated_to_output_flow_tables(solved_db_with_units: Path) -> None: + """Verify that output flow tables have units populated.""" + with sqlite3.connect(solved_db_with_units) as conn: + # Check output_flow_out + row = conn.execute( + 'SELECT COUNT(*), SUM(CASE WHEN units IS NOT NULL THEN 1 ELSE 0 END)' + ' FROM output_flow_out' + ).fetchone() + total, with_units = row + assert total > 0 + assert with_units > 0, 'No units populated in output_flow_out' + sample = conn.execute( + 'SELECT output_comm, units FROM output_flow_out WHERE units IS NOT NULL LIMIT 1' + ).fetchone() + assert sample is not None + + # Check output_curtailment (same logic) + row = conn.execute( + 'SELECT COUNT(*), SUM(CASE WHEN units IS NOT NULL THEN 1 ELSE 0 END)' + ' FROM output_curtailment' + ).fetchone() + if row[0] > 0: + assert row[1] > 0, 'No units populated in output_curtailment' + + # Check output_flow_in + row = conn.execute( + 'SELECT COUNT(*), SUM(CASE WHEN units IS NOT NULL THEN 1 ELSE 0 END)' + ' FROM output_flow_in' + ).fetchone() + if row[0] > 0: + assert row[1] > 0, 'No units populated in output_flow_in' + + +def test_units_propagated_to_capacity_tables(solved_db_with_units: Path) -> None: + """Verify that capacity output tables have units populated.""" + with sqlite3.connect(solved_db_with_units) as conn: + for table in ['output_built_capacity', 'output_net_capacity']: + row = conn.execute( + f'SELECT COUNT(*), SUM(CASE WHEN units IS NOT NULL THEN 1 ELSE 0 END) FROM {table}' + ).fetchone() + total, with_units = row + + if total > 0: # Some tables may be empty depending on model + assert with_units > 0, f'No units populated in {table}' + # Check for GW (standard capacity unit in Utopia) + sample = conn.execute( + f'SELECT tech, units FROM {table} WHERE units IS NOT NULL LIMIT 1' + ).fetchone() + assert sample is not None + assert sample[1] == 'GW', f'Expected GW, got {sample[1]} in {table}' + + +def test_units_propagated_to_cost_table(solved_db_with_units: Path) -> None: + """Verify that output_cost table has units populated.""" + with sqlite3.connect(solved_db_with_units) as conn: + row = conn.execute( + 'SELECT COUNT(*), SUM(CASE WHEN units IS NOT NULL THEN 1 ELSE 0 END) FROM output_cost' + ).fetchone() + total, with_units = row + assert total > 0 + assert with_units > 0, 'No units populated in output_cost' + + sample = conn.execute( + 'SELECT units FROM output_cost WHERE units IS NOT NULL LIMIT 1' + ).fetchone() + assert sample is not None + # Utopia uses 'Mdollar', but simplified check for non-empty string is good baseline + units = sample[0].lower() + assert ('dollar' in units) or ('usd' in units) or ('euro' in units) or ('eur' in units) diff --git a/tests/test_unit_scavenging.py b/tests/test_unit_scavenging.py new file mode 100644 index 000000000..36a523d2b --- /dev/null +++ b/tests/test_unit_scavenging.py @@ -0,0 +1,56 @@ +from temoa.model_checking.unit_checking.unit_propagator import UnitPropagator + +extract_capacity_unit_func = UnitPropagator._extract_capacity_unit + + +def test_extract_simple() -> None: + """Test extracting a simple capacity unit.""" + assert extract_capacity_unit_func('Mdollar/GW') == 'GW' + + +def test_extract_complex_utopia() -> None: + """Test extracting from a complex unit string like 'Mdollar / (PJ^2 / GW)'.""" + assert extract_capacity_unit_func('Mdollar / (PJ^2 / GW)') == 'GW' + + +def test_extract_complex_fixed() -> None: + """Test extracting from a complex unit string with a time component.""" + assert extract_capacity_unit_func('Mdollar / (PJ^2 / GW / year)') == 'GW' + + +def test_extract_MW() -> None: # noqa: N802 + """Test extracting 'MW' as a capacity unit.""" + assert extract_capacity_unit_func('Mdollar / (MW)') == 'MW' + + +def test_extract_kW() -> None: # noqa: N802 + """Test extracting 'kW' as a capacity unit.""" + assert extract_capacity_unit_func('Mdollar / (kW)') == 'kW' + + +def test_extract_gigawatt() -> None: + """Test extracting 'gigawatt' as a capacity unit.""" + assert extract_capacity_unit_func('Mdollar / (gigawatt)') == 'gigawatt' + + +def test_extract_megawatt() -> None: + """Test extracting 'megawatt' as a capacity unit.""" + assert extract_capacity_unit_func('Mdollar / (megawatt)') == 'megawatt' + + +def test_extract_kilowatt() -> None: + """Test extracting 'kilowatt' as a capacity unit.""" + assert extract_capacity_unit_func('Mdollar / (kilowatt)') == 'kilowatt' + + +def test_extract_ignores_energy() -> None: + """Test that energy units like 'GWh' are ignored.""" + assert extract_capacity_unit_func('GWh') is None + + +def test_extract_none() -> None: + """Test cases where no capacity unit can be extracted.""" + assert extract_capacity_unit_func('Mdollar/PJ') is None + assert extract_capacity_unit_func('Mdollar/kg') is None + assert extract_capacity_unit_func('Mdollar') is None + assert extract_capacity_unit_func('SomethingElse') is None diff --git a/tests/testing_outputs/.gitignore b/tests/testing_outputs/.gitignore index 39fbe462d..4cfa99f77 100644 --- a/tests/testing_outputs/.gitignore +++ b/tests/testing_outputs/.gitignore @@ -1,5 +1,4 @@ -# ignore the databases here. They are just used to catch output +/* -*.sqlite -*.dat -*.xlsx \ No newline at end of file + +!README.txt From 7ea06c2c18687be109955f1232e86ce57bae57b6 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 16 Dec 2025 14:15:25 -0500 Subject: [PATCH 394/587] docs: adding unit checking to docs --- data_files/my_configs/config_sample.toml | 5 + docs/source/index.rst | 1 + docs/source/unit_checking.rst | 427 +++++++++++++++++++++++ 3 files changed, 433 insertions(+) create mode 100644 docs/source/unit_checking.rst diff --git a/data_files/my_configs/config_sample.toml b/data_files/my_configs/config_sample.toml index 063a7a8ba..0174f9ec5 100644 --- a/data_files/my_configs/config_sample.toml +++ b/data_files/my_configs/config_sample.toml @@ -47,6 +47,11 @@ source_trace = true # Produce HTML files for Commodity Networks. Requires source_trace above plot_commodity_network = true +# Check units consistency in the database +# Validates that units are properly formatted and consistent across related tables +# Recommended for production runs after units are populated in the database +check_units = false + # ------------------------------------ # SOLVER # Solver Selection diff --git a/docs/source/index.rst b/docs/source/index.rst index 777d8885c..aeecc2a53 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -4,3 +4,4 @@ Temoa Project Documentation .. toctree:: Documentation + unit_checking diff --git a/docs/source/unit_checking.rst b/docs/source/unit_checking.rst new file mode 100644 index 000000000..c158168f2 --- /dev/null +++ b/docs/source/unit_checking.rst @@ -0,0 +1,427 @@ +.. _unit_checking: + +Units Checking +============== + +The Temoa v4.0 database schema includes comprehensive units checking capabilities to ensure consistency +and accuracy throughout the model. Unit checking validates that all units are properly formatted, +dimensionally consistent, and align correctly across related tables. + +.. important:: + The units expressed and checked via ``pint`` do not "follow the values" through the mathematics + of the model. Unit checking is a **pre-processing validation layer** used to support documentation + and catch input errors. **The units are not used in the model calculations themselves.** + +Unit Propagation to Outputs +--------------------------- + +Starting with v4.0, units defined in input tables are **automatically propagated** to output tables +when model results are written. This provides traceability of units from inputs through results. + +**How It Works**: + +- ``output_flow_out`` / ``output_flow_in``: Units from ``commodity.units`` for the output/input commodity +- ``output_built_capacity`` / ``output_net_capacity`` / ``output_retired_capacity``: Units from ``existing_capacity.units`` +- ``output_emission``: Units from ``commodity.units`` for the emission commodity +- ``output_cost``: Common currency unit extracted from cost input tables +- ``output_storage_level``: Units from the stored commodity + +**Backward Compatibility**: + +- Databases without unit data in input tables will write ``NULL`` units to outputs +- Databases with older schemas (no ``units`` column on output tables) continue to work normally +- Unit propagation is automatic and requires no configuration + +Overview +-------- + +The unit checking system uses the Python package ``pint`` to perform unit validation and dimensional +analysis. This leverages pint's built-in unit registry to validate units with varying prefixes +(e.g., PJ, TJ, GJ) and enables future extensions. + +The basis for most unit comparisons comes from: + +- **commodity table**: Defines native units for each commodity (energy network nodes) +- **efficiency table**: Infers technology units via input/output ratios +- **capacity_to_activity table**: Provides conversion factors for capacity-based measures + +Enabling Unit Checking +----------------------- + +Via Configuration File +~~~~~~~~~~~~~~~~~~~~~~ + +Add to your ``config.toml``: + +.. code-block:: toml + + [model_checks] + check_units = true + +Via CLI +~~~~~~~ + +Standalone unit checking for any database: + +.. code-block:: bash + + # Basic usage + temoa check-units path/to/database.sqlite + + # Custom output directory + temoa check-units database.sqlite --output ./reports + + # Silent mode (for scripting) + temoa check-units database.sqlite --silent + +How It Works +------------ + +The unit checker performs five sequential tests: + +1. **Database Version Check**: Ensures database is v4.0+ (checks ``metadata`` table) +2. **Units Entry Validation**: Checks for illegal characters, proper formatting, registry membership +3. **Technology I/O Alignment**: Validates ``efficiency`` table units match commodities +4. **Related Tables**: Checks tables referencing technologies for unit consistency +5. **Cost Tables**: Validates cost units and dimensional alignment + +Expressing Units +---------------- + +Format Requirements +~~~~~~~~~~~~~~~~~~~ + +.. warning:: + **CRITICAL**: The unit checker uses regex parsing with strict format requirements! + +Units in **efficiency** and **cost** tables MUST use ratio format: + +.. code-block:: text + + Numerator / (Denominator) + + āœ… CORRECT: PJ / (PJ) + āœ… CORRECT: Mdollar / (PJ^2 / GW) + āŒ WRONG: PJ/PJ (no parentheses) + āŒ WRONG: Mdollar * GW / (PJ^2) (denominator incomplete) + +The denominator **MUST be fully enclosed in parentheses**. The regex only captures content +within ``( )`` after the ``/``. + +Other tables should use plain entries: + +.. code-block:: text + + āœ… PJ + āœ… petajoules + āœ… GW + āœ… Mt / (GW) (if ratio needed) + +Custom Units Registry +~~~~~~~~~~~~~~~~~~~~~ + +Temoa extends pint's default registry with domain-specific units: + +- ``dollar`` (or ``USD``) +- ``euro`` (or ``EUR``) +- ``passenger`` +- ``seat`` (for passenger-miles, seat-miles) +- ``ethos`` (dimensionless source commodity) + +Common Footguns and Pitfalls +----------------------------- + +1. Missing Parentheses in Ratios +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Problem**: Forgetting to parenthesize the denominator + +.. code-block:: text + + āŒ cost_invest units: "Mdollar / PJ^2 / GW" + + Error: RATIO_ELEMENT regex doesn't match, only "PJ^2" captured + +**Solution**: Always use parentheses + +.. code-block:: text + + āœ… cost_invest units: "Mdollar / (PJ^2 / GW)" + +2. Capacity vs Energy Units +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Problem**: Using energy units (GW*year, kWh) in capacity tables + +.. code-block:: text + + āŒ existing_capacity units: "GW * year" + + Error: Energy units (not capacity) in capacity table + +**Solution**: Use power units (negative time dimension) + +.. code-block:: text + + āœ… existing_capacity units: "GW" ([time]^-3 = power) + āŒ existing_capacity units: "GWh" ([time]^-2 = energy) + +**Physics**: +- Capacity = Power (W, kW, MW, GW) → ``[time]^-3`` +- Energy = Power Ɨ Time (Wh, kWh) → ``[time]^-2`` + +3. Cost Table Units and C2A +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Problem**: Not accounting for capacity_to_activity conversion + +For capacity-based costs, the expected denominator is: + +.. math:: + + \text{expected_measure} = \text{output_units} \times \text{C2A} \times \text{year} + +**Example**: +- Output commodity: ``ELC`` = ``PJ`` +- C2A: ``PJ / (GW * year)`` +- Expected: ``PJ * [PJ/(GW*year)] * year`` = ``PJ^2/GW`` + +.. code-block:: text + + āœ… cost_invest: "Mdollar / (PJ^2 / GW)" + āœ… cost_fixed: "Mdollar / (PJ^2 / GW / year)" (adds /year for period-based) + +4. period_based Flag +~~~~~~~~~~~~~~~~~~~~ + +**Problem**: Misunderstanding period_based vs capacity_based + +These flags are **orthogonal**: + +- ``capacity_based``: Multiply expected units by C2A +- ``period_based``: Divide expected units by year + +``cost_fixed`` is **BOTH** capacity_based AND period_based! + +.. csv-table:: + :header: "Table", "capacity_based", "period_based", "Units Example" + + "cost_invest", "True", "False", "Mdollar / (PJ^2 / GW)" + "cost_fixed", "True", "True", "Mdollar / (PJ^2 / GW / year)" + "cost_variable", "False", "False", "Mdollar / (PJ)" + "cost_emission", "False", "False", "Mdollar / (Mt)" + +5. Schema Variations: tech vs tech_or_group +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Problem**: v4.0 limit tables use ``tech_or_group`` not ``tech`` + +The unit checker automatically detects which column exists, but be aware: + +.. code-block:: sql + + -- v3.1 schema + SELECT tech, units FROM limit_capacity... + + -- v4.0 schema + SELECT tech_or_group, units FROM limit_capacity... + +Tables affected: ``limit_activity``, ``limit_capacity``, ``limit_new_capacity`` + +6. Technology Output Uniformity +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Problem**: Same technology with multiple output commodities using different units + +.. warning:: + All instances of a technology MUST produce output in the **same units**, even if + output commodities differ! + +**Why**: Constraints span regions and output commodities, requiring a single unit of measure. + +.. code-block:: text + + āŒ WRONG: + tech E01, output ELC: PJ + tech E01, output HEAT: GJ (different units!) + + āœ… CORRECT: + tech E01, output ELC: PJ + tech E01, output HEAT: PJ (same units) + +Testing and Troubleshooting +---------------------------- + +Testing Units Manually +~~~~~~~~~~~~~~~~~~~~~~~ + +Test unit validity outside the model: + +.. code-block:: python + + from temoa.model_checking.unit_checking import ureg + + # Check if units exist in registry + print('PJ' in ureg) # True + print('catfood' in ureg) # False + + # Parse and check units + u = ureg('Mdollar / (PJ^2 / GW)') + print(u.dimensionality) # {[currency]: 1, [time]: 1, ...} + + # Check currency dimension (for cost tables) + print('[currency]' in u.dimensionality) # True + +Common Error Messages +~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: text + + "Units lack currency dimension" + → Cost table units don't contain currency (dollar/euro) + + "Energy units (not capacity) in capacity table" + → Using energy units (kWh, GWh, etc.) instead of capacity units (GW, MW) + + "Non-matching measure unit" + → Units don't match expected format after accounting for C2A/period + + "failed to process query: no such column: tech" + → Using old SQL queries on v4.0 schema (should auto-fix now) + +Reading Unit Check Reports +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Reports are saved to ``output_path/unit_check_reports/units_check_TIMESTAMP.txt``: + +.. code-block:: text + + ======== Units Check 1 (DB Version): Started ======== + Units Check 1 (DB Version): Passed + + ======== Units Check 2 (Units Entries in Tables): Started ======== + existing_capacity: Energy units (not capacity) in capacity table: GW*year at rows: 1, 2, 3 + + ======== Units Check 3 (Tech I/O via Efficiency Table): Started ======== + Efficiency units conflict with associated commodity for Technology E01 near row 1 + + ======== Units Check 4 (Related Tables): Started ======== + limit_capacity: Non-standard units for tech E01 (expected GW) got: MW at rows: 5, 6 + + ======== Units Check 5 (Cost Tables): Started ======== + cost_invest: Non-matching measure unit for tech/comm: E01 + Table entry: Mdollar / (PJ) + Expected: petajoule ** 2 / gigawatt + Found: petajoule at rows: 1, 2, 3 + +Each check section shows: +- Which table/tech has issues +- What was expected vs what was found +- Row numbers for easy correction + +Tables Checked +-------------- + +v4.0 Schema Coverage +~~~~~~~~~~~~~~~~~~~~ + +.. csv-table:: + :header: "Table", "Has Units", "Check 2", "Check 3", "Check 4", "Check 5" + :widths: 25, 12, 10, 12, 15, 10 + + "capacity_to_activity", "āœ“", "āœ“", "", "(used)", "(used)" + "commodity", "āœ“", "āœ“", "āœ“", "", "" + "construction_input", "āœ“", "āœ“", "", "", "" + "cost_emission", "āœ“", "āœ“", "", "", "āœ“" + "cost_fixed", "āœ“", "āœ“", "", "", "āœ“" + "cost_invest", "āœ“", "āœ“", "", "", "āœ“" + "cost_variable", "āœ“", "āœ“", "", "", "āœ“" + "demand", "āœ“", "āœ“", "", "āœ“", "" + "efficiency", "āœ“", "āœ“", "āœ“", "", "" + "emission_activity", "āœ“", "āœ“", "", "", "" + "emission_embodied", "āœ“", "āœ“", "", "", "" + "emission_end_of_life", "āœ“", "āœ“", "", "", "" + "end_of_life_output", "āœ“", "āœ“", "", "", "" + "existing_capacity", "āœ“", "āœ“", "", "āœ“", "" + "lifetime_process", "āœ“", "āœ“", "", "", "" + "lifetime_tech", "āœ“", "āœ“", "", "", "" + "loan_lifetime_process", "āœ“", "āœ“", "", "", "" + "limit_activity", "āœ“", "āœ“", "", "āœ“", "" + "limit_capacity", "āœ“", "āœ“", "", "āœ“", "" + "limit_emission", "āœ“", "āœ“", "", "", "" + "limit_new_capacity", "āœ“", "āœ“", "", "āœ“", "" + "limit_resource", "āœ“", "āœ“", "", "", "" + +**Check Legend**: +- Check 2: Standard validation (format, characters, registry) +- Check 3: Technology I/O alignment via Efficiency table +- Check 4: Related tables consistency +- Check 5: Cost tables validation + +Best Practices +-------------- + +1. **Start with commodities**: Define commodity units first, then build tech efficiency ratios +2. **Use standard prefixes**: Stick to k, M, G, T prefixes (kilo, mega, giga, tera) +3. **Be consistent**: Use the same unit style across your database (e.g., always "PJ" not mix of "PJ"/"petajoule") +4. **Test early**: Run unit checker on partial databases during development +5. **Document assumptions**: Use notes fields to explain unusual unit choices +6. **Reference implementation**: See ``temoa/tutorial_assets/utopia.sqlite`` for a fully compliant example + +Quick Reference +--------------- + +Common Unit Patterns +~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: text + + # Energy commodities + commodity units: PJ, TJ, GJ, MWh + + # Capacity + existing_capacity units: GW, MW, kW + + # Efficiency (energy tech) + efficiency units: PJ / (PJ) (dimensionless) + efficiency units: PJ / (Mt) (energy from mass) + + # C2A conversion + capacity_to_activity units: PJ / (GW * year) + + # Costs (capacity-based tech with PJ output, PJ/(GW*year) C2A) + cost_invest units: Mdollar / (PJ^2 / GW) + cost_fixed units: Mdollar / (PJ^2 / GW / year) + cost_variable units: Mdollar / (PJ) + + # Emissions + emission_activity units: Mt / (PJ) + emission_embodied units: Mt / (GW) + +Dimension Reference +~~~~~~~~~~~~~~~~~~~ + +Pint tracks seven base dimensions: + +- ``[length]``: meter, km, mile +- ``[mass]``: kg, tonne, Mt +- ``[time]``: second, year +- ``[current]``: ampere +- ``[temperature]``: kelvin +- ``[substance]``: mole +- ``[luminosity]``: candela +- ``[currency]``: dollar, euro (Temoa extension) + +Derived dimensions: + +- Energy: ``[length]^2 * [mass] / [time]^2`` (joule, kWh) +- Power: ``[length]^2 * [mass] / [time]^3`` (watt, GW) +- Force: ``[length] * [mass] / [time]^2`` (newton) + +See Also +-------- + +- :ref:`database_schema` - v4.0 schema reference +- :ref:`configuration` - Configuration file format +- ``temoa/model_checking/unit_checking/`` - Source code +- ``tests/test_unit_checking.py`` - Unit tests with examples From 9c74dcdb766a9474307f1858b9e60398a9477ed2 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 18 Dec 2025 11:14:22 -0500 Subject: [PATCH 395/587] removing time_season_all and time_season_to_sequential tables from schema --- data_files/temoa_schema_v4.sql | 23 ----------------------- temoa/db_schema/temoa_schema_v4.sql | 23 ----------------------- 2 files changed, 46 deletions(-) diff --git a/data_files/temoa_schema_v4.sql b/data_files/temoa_schema_v4.sql index bfb48c554..8efedde67 100644 --- a/data_files/temoa_schema_v4.sql +++ b/data_files/temoa_schema_v4.sql @@ -959,29 +959,6 @@ CREATE TABLE IF NOT EXISTS time_period flag TEXT REFERENCES time_period_type (label) ); -CREATE TABLE IF NOT EXISTS time_season_all -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - season TEXT - REFERENCES season_label (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); -CREATE TABLE IF NOT EXISTS time_season_to_sequential -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT - REFERENCES season_label (season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); CREATE TABLE IF NOT EXISTS time_period_type ( label TEXT diff --git a/temoa/db_schema/temoa_schema_v4.sql b/temoa/db_schema/temoa_schema_v4.sql index bfb48c554..8efedde67 100644 --- a/temoa/db_schema/temoa_schema_v4.sql +++ b/temoa/db_schema/temoa_schema_v4.sql @@ -959,29 +959,6 @@ CREATE TABLE IF NOT EXISTS time_period flag TEXT REFERENCES time_period_type (label) ); -CREATE TABLE IF NOT EXISTS time_season_all -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - season TEXT - REFERENCES season_label (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); -CREATE TABLE IF NOT EXISTS time_season_to_sequential -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT - REFERENCES season_label (season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); CREATE TABLE IF NOT EXISTS time_period_type ( label TEXT From bc54f3bfe6b13ca3d1386c05eec0eee38615310f Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 18 Dec 2025 11:15:19 -0500 Subject: [PATCH 396/587] updating migrators for schema change --- temoa/utilities/db_migration_v3_1_to_v4.py | 4 ++-- temoa/utilities/sql_migration_v3_1_to_v4.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/temoa/utilities/db_migration_v3_1_to_v4.py b/temoa/utilities/db_migration_v3_1_to_v4.py index a27fc8bae..55e6e2e67 100644 --- a/temoa/utilities/db_migration_v3_1_to_v4.py +++ b/temoa/utilities/db_migration_v3_1_to_v4.py @@ -20,9 +20,9 @@ # ---------- Mapping configuration ---------- CUSTOM_MAP: dict[str, str] = { 'TimeSeason': 'time_season', - 'time_season': 'time_season_all', + 'time_season': 'time_season', 'TimeSeasonSequential': 'time_season_sequential', - 'time_season_sequential': 'time_season_to_sequential', + 'time_season_sequential': 'time_season_sequential', 'TimeNext': 'time_manual', 'CommodityDStreamProcess': 'commodity_down_stream_process', 'commodityUStreamProcess': 'commodity_up_stream_process', diff --git a/temoa/utilities/sql_migration_v3_1_to_v4.py b/temoa/utilities/sql_migration_v3_1_to_v4.py index 817562454..f888d28e6 100644 --- a/temoa/utilities/sql_migration_v3_1_to_v4.py +++ b/temoa/utilities/sql_migration_v3_1_to_v4.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 """ -sql_migration_v_3_1_to_v4.py (Robust version) +sql_migration_v_3_1_to_v4.py Converts a v3.1 SQL dump (text) into a valid v4 SQL dump. This script: @@ -28,14 +28,14 @@ # ------------------ Mapping configuration (mirror sqlite migrator) ------------------ CUSTOM_MAP: dict[str, str] = { 'TimeSeason': 'time_season', - 'time_season': 'time_season_all', # exact-only: only exact old token -> ..._all + 'time_season': 'time_season', 'TimeSeasonSequential': 'time_season_sequential', - 'time_season_sequential': 'time_season_to_sequential', # exact-only + 'time_season_sequential': 'time_season_sequential', 'TimeNext': 'time_manual', 'CommodityDStreamProcess': 'commodity_down_stream_process', 'commodityUStreamProcess': 'commodity_up_stream_process', 'SegFrac': 'segment_fraction', - 'segfrac': 'segment_fraction', # canonical column name for column 'segfrac' + 'segfrac': 'segment_fraction', 'MetaDataReal': 'metadata_real', 'MetaData': 'metadata', 'Myopicefficiency': 'myopic_efficiency', From 2ebdc4904c26ab141ab9da67dcc366707fa58fde Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 18 Dec 2025 11:15:48 -0500 Subject: [PATCH 397/587] removing time_season_all and time_season_to_sequential tables from example and testing databases --- data_files/example_dbs/materials.sql | 25 ++------------------- data_files/example_dbs/morris_utopia.sql | 25 ++------------------- data_files/example_dbs/seasonal_storage.sql | 25 ++------------------- data_files/example_dbs/survival_curve.sql | 25 ++------------------- data_files/example_dbs/test_system.sql | 25 ++------------------- data_files/example_dbs/utopia.sql | 25 ++------------------- tests/testing_data/annualised_demand.sql | 25 ++------------------- tests/testing_data/emissions.sql | 25 ++------------------- tests/testing_data/materials.sql | 25 ++------------------- tests/testing_data/mediumville.sql | 25 ++------------------- tests/testing_data/seasonal_storage.sql | 11 +-------- tests/testing_data/simple_linked_tech.sql | 25 ++------------------- tests/testing_data/storageville.sql | 25 ++------------------- tests/testing_data/survival_curve.sql | 25 ++------------------- tests/testing_data/test_system.sql | 25 ++------------------- 15 files changed, 29 insertions(+), 332 deletions(-) diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index ccd4053e5..19d8a03b5 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -1548,16 +1548,7 @@ INSERT INTO "time_season" VALUES(2020,9,'summer',NULL); INSERT INTO "time_season" VALUES(2020,10,'autumn',NULL); INSERT INTO "time_season" VALUES(2020,11,'winter',NULL); INSERT INTO "time_season" VALUES(2020,12,'spring',NULL); -CREATE TABLE time_season_all -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - season TEXT - REFERENCES season_label (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); + CREATE TABLE time_season_sequential ( period INTEGER REFERENCES time_period (period), @@ -1569,19 +1560,7 @@ CREATE TABLE time_season_sequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE time_season_to_sequential -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT - REFERENCES season_label (season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); + CREATE TABLE time_segment_fraction ( period INTEGER diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index 88d44f6d3..0ec374ed2 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -1540,16 +1540,7 @@ INSERT INTO "time_season" VALUES(2000,1,'inter',NULL); INSERT INTO "time_season" VALUES(2010,2,'summer',NULL); INSERT INTO "time_season" VALUES(2010,3,'winter',NULL); INSERT INTO "time_season" VALUES(2010,1,'inter',NULL); -CREATE TABLE time_season_all -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - season TEXT - REFERENCES season_label (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); + CREATE TABLE time_season_sequential ( period INTEGER REFERENCES time_period (period), @@ -1561,19 +1552,7 @@ CREATE TABLE time_season_sequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE time_season_to_sequential -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT - REFERENCES season_label (season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); + CREATE TABLE time_segment_fraction ( period INTEGER diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql index 35ed2fcee..5bd5b3710 100644 --- a/data_files/example_dbs/seasonal_storage.sql +++ b/data_files/example_dbs/seasonal_storage.sql @@ -1085,16 +1085,7 @@ CREATE TABLE time_season ); INSERT INTO "time_season" VALUES(2000,0,'charge',NULL); INSERT INTO "time_season" VALUES(2000,1,'discharge',NULL); -CREATE TABLE time_season_all -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - season TEXT - REFERENCES season_label (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); + CREATE TABLE time_season_sequential ( period INTEGER REFERENCES time_period (period), @@ -1120,19 +1111,7 @@ INSERT INTO "time_season_sequential" VALUES(2000,11,'apr_w3','charge',7.0,NULL); INSERT INTO "time_season_sequential" VALUES(2000,12,'apr_w4','discharge',7.0,NULL); INSERT INTO "time_season_sequential" VALUES(2000,13,'apr_29th','charge',1.0,NULL); INSERT INTO "time_season_sequential" VALUES(2000,14,'apr_30th','discharge',1.0,NULL); -CREATE TABLE time_season_to_sequential -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT - REFERENCES season_label (season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); + CREATE TABLE time_segment_fraction ( period INTEGER diff --git a/data_files/example_dbs/survival_curve.sql b/data_files/example_dbs/survival_curve.sql index c907629e6..ea6055117 100644 --- a/data_files/example_dbs/survival_curve.sql +++ b/data_files/example_dbs/survival_curve.sql @@ -1175,16 +1175,7 @@ INSERT INTO "time_season" VALUES(2035,2,'s',NULL); INSERT INTO "time_season" VALUES(2040,3,'s',NULL); INSERT INTO "time_season" VALUES(2045,4,'s',NULL); INSERT INTO "time_season" VALUES(2050,5,'s',NULL); -CREATE TABLE time_season_all -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - season TEXT - REFERENCES season_label (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); + CREATE TABLE time_season_sequential ( period INTEGER REFERENCES time_period (period), @@ -1196,19 +1187,7 @@ CREATE TABLE time_season_sequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE time_season_to_sequential -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT - REFERENCES season_label (season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); + CREATE TABLE time_segment_fraction ( period INTEGER diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index c7e9a5f50..89b181fc9 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -1529,16 +1529,7 @@ INSERT INTO "time_season" VALUES(2030,1,'spring',NULL); INSERT INTO "time_season" VALUES(2030,2,'summer',NULL); INSERT INTO "time_season" VALUES(2030,3,'fall',NULL); INSERT INTO "time_season" VALUES(2030,4,'winter',NULL); -CREATE TABLE time_season_all -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - season TEXT - REFERENCES season_label (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); + CREATE TABLE time_season_sequential ( period INTEGER REFERENCES time_period (period), @@ -1550,19 +1541,7 @@ CREATE TABLE time_season_sequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE time_season_to_sequential -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT - REFERENCES season_label (season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); + CREATE TABLE time_segment_fraction ( period INTEGER diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 185852683..72ab60a18 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -1537,16 +1537,7 @@ INSERT INTO "time_season" VALUES(2000,3,'winter',NULL); INSERT INTO "time_season" VALUES(2010,1,'inter',NULL); INSERT INTO "time_season" VALUES(2010,2,'summer',NULL); INSERT INTO "time_season" VALUES(2010,3,'winter',NULL); -CREATE TABLE time_season_all -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - season TEXT - REFERENCES season_label (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); + CREATE TABLE time_season_sequential ( period INTEGER REFERENCES time_period (period), @@ -1558,19 +1549,7 @@ CREATE TABLE time_season_sequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE time_season_to_sequential -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT - REFERENCES season_label (season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); + CREATE TABLE time_segment_fraction ( period INTEGER diff --git a/tests/testing_data/annualised_demand.sql b/tests/testing_data/annualised_demand.sql index 18477b987..aa6947474 100644 --- a/tests/testing_data/annualised_demand.sql +++ b/tests/testing_data/annualised_demand.sql @@ -1050,16 +1050,7 @@ CREATE TABLE time_season PRIMARY KEY (period, sequence, season) ); INSERT INTO "time_season" VALUES(2000,0,'S1',NULL); -CREATE TABLE time_season_all -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - season TEXT - REFERENCES season_label (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); + CREATE TABLE time_season_sequential ( period INTEGER REFERENCES time_period (period), @@ -1071,19 +1062,7 @@ CREATE TABLE time_season_sequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE time_season_to_sequential -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT - REFERENCES season_label (season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); + CREATE TABLE time_segment_fraction ( period INTEGER diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 9fb49a027..3e3355efe 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -1096,16 +1096,7 @@ CREATE TABLE time_season ); INSERT INTO "time_season" VALUES(2000,1,'S1',NULL); INSERT INTO "time_season" VALUES(2005,1,'S1',NULL); -CREATE TABLE time_season_all -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - season TEXT - REFERENCES season_label (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); + CREATE TABLE time_season_sequential ( period INTEGER REFERENCES time_period (period), @@ -1117,19 +1108,7 @@ CREATE TABLE time_season_sequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE time_season_to_sequential -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT - REFERENCES season_label (season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); + CREATE TABLE time_segment_fraction ( period INTEGER diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index 16aba0eb7..f32e898d9 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -1452,16 +1452,7 @@ INSERT INTO "time_season" VALUES(2020,9,'summer',NULL); INSERT INTO "time_season" VALUES(2020,10,'autumn',NULL); INSERT INTO "time_season" VALUES(2020,11,'winter',NULL); INSERT INTO "time_season" VALUES(2020,12,'spring',NULL); -CREATE TABLE time_season_all -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - season TEXT - REFERENCES season_label (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); + CREATE TABLE time_season_sequential ( period INTEGER REFERENCES time_period (period), @@ -1473,19 +1464,7 @@ CREATE TABLE time_season_sequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE time_season_to_sequential -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT - REFERENCES season_label (season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); + CREATE TABLE time_segment_fraction ( period INTEGER diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 0c3d0aed6..6a1cd6ca7 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -1190,16 +1190,7 @@ CREATE TABLE time_season ); INSERT INTO "time_season" VALUES(2025,1,'s1',NULL); INSERT INTO "time_season" VALUES(2025,2,'s2',NULL); -CREATE TABLE time_season_all -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - season TEXT - REFERENCES season_label (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); + CREATE TABLE time_season_sequential ( period INTEGER REFERENCES time_period (period), @@ -1211,19 +1202,7 @@ CREATE TABLE time_season_sequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE time_season_to_sequential -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT - REFERENCES season_label (season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); + CREATE TABLE time_segment_fraction ( period INTEGER diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index 1ea6def23..990abbd29 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -1085,16 +1085,7 @@ CREATE TABLE time_season ); INSERT INTO "time_season" VALUES(2000,0,'charge',NULL); INSERT INTO "time_season" VALUES(2000,1,'discharge',NULL); -CREATE TABLE time_season_all -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - season TEXT - REFERENCES season_label (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); + CREATE TABLE time_season_sequential ( period INTEGER REFERENCES time_period (period), diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index e5fba3d42..bf28bd18e 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -1057,16 +1057,7 @@ CREATE TABLE time_season ); INSERT INTO "time_season" VALUES(2000,1,'summer',NULL); INSERT INTO "time_season" VALUES(2000,2,'winter',NULL); -CREATE TABLE time_season_all -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - season TEXT - REFERENCES season_label (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); + CREATE TABLE time_season_sequential ( period INTEGER REFERENCES time_period (period), @@ -1078,19 +1069,7 @@ CREATE TABLE time_season_sequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE time_season_to_sequential -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT - REFERENCES season_label (season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); + CREATE TABLE time_segment_fraction ( period INTEGER diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index 3a577a81f..127982bff 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -1076,16 +1076,7 @@ CREATE TABLE time_season ); INSERT INTO "time_season" VALUES(2025,1,'s1',NULL); INSERT INTO "time_season" VALUES(2025,2,'s2',NULL); -CREATE TABLE time_season_all -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - season TEXT - REFERENCES season_label (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); + CREATE TABLE time_season_sequential ( period INTEGER REFERENCES time_period (period), @@ -1097,19 +1088,7 @@ CREATE TABLE time_season_sequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE time_season_to_sequential -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT - REFERENCES season_label (season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); + CREATE TABLE time_segment_fraction ( period INTEGER diff --git a/tests/testing_data/survival_curve.sql b/tests/testing_data/survival_curve.sql index c907629e6..ea6055117 100644 --- a/tests/testing_data/survival_curve.sql +++ b/tests/testing_data/survival_curve.sql @@ -1175,16 +1175,7 @@ INSERT INTO "time_season" VALUES(2035,2,'s',NULL); INSERT INTO "time_season" VALUES(2040,3,'s',NULL); INSERT INTO "time_season" VALUES(2045,4,'s',NULL); INSERT INTO "time_season" VALUES(2050,5,'s',NULL); -CREATE TABLE time_season_all -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - season TEXT - REFERENCES season_label (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); + CREATE TABLE time_season_sequential ( period INTEGER REFERENCES time_period (period), @@ -1196,19 +1187,7 @@ CREATE TABLE time_season_sequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE time_season_to_sequential -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT - REFERENCES season_label (season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); + CREATE TABLE time_segment_fraction ( period INTEGER diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index c7e9a5f50..89b181fc9 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -1529,16 +1529,7 @@ INSERT INTO "time_season" VALUES(2030,1,'spring',NULL); INSERT INTO "time_season" VALUES(2030,2,'summer',NULL); INSERT INTO "time_season" VALUES(2030,3,'fall',NULL); INSERT INTO "time_season" VALUES(2030,4,'winter',NULL); -CREATE TABLE time_season_all -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - season TEXT - REFERENCES season_label (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); + CREATE TABLE time_season_sequential ( period INTEGER REFERENCES time_period (period), @@ -1550,19 +1541,7 @@ CREATE TABLE time_season_sequential PRIMARY KEY (period, sequence, seas_seq, season), CHECK (num_days > 0) ); -CREATE TABLE time_season_to_sequential -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT - REFERENCES season_label (season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); + CREATE TABLE time_segment_fraction ( period INTEGER From 8b39a164ac0a7f7faf4691a176239219429782b2 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sun, 14 Dec 2025 20:51:50 -0500 Subject: [PATCH 398/587] removing stale pydoe dependency --- pyproject.toml | 1 - requirements-dev.txt | 4 ---- requirements.txt | 4 ---- uv.lock | 12 ------------ 4 files changed, 21 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e9625bc9d..fb7053823 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,6 @@ dependencies = [ "numpy>=2.1.0", "joblib", "salib>=1.5.1", - "pydoe>=0.3.8", "graphviz>=0.20.3", "seaborn>=0.13.2", "tabulate>=0.9.0", diff --git a/requirements-dev.txt b/requirements-dev.txt index 6f7cc6a5a..5ad2eccf7 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -84,7 +84,6 @@ numpy==2.3.1 # highspy # matplotlib # pandas - # pydoe # salib # scipy # seaborn @@ -116,8 +115,6 @@ pybtex==0.25.1 # sphinxcontrib-bibtex pybtex-docutils==1.0.3 # via sphinxcontrib-bibtex -pydoe==0.3.8 - # via temoa (pyproject.toml) pygments==2.19.2 # via # pytest @@ -152,7 +149,6 @@ salib==1.5.1 scipy==1.16.0 # via # temoa (pyproject.toml) - # pydoe # salib seaborn==0.13.2 # via temoa (pyproject.toml) diff --git a/requirements.txt b/requirements.txt index 8d0fdddc6..d016fb62a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -48,7 +48,6 @@ numpy==2.3.1 # highspy # matplotlib # pandas - # pydoe # salib # scipy # seaborn @@ -73,8 +72,6 @@ pluggy==1.6.0 # via pytest ply==3.11 # via pyomo -pydoe==0.3.8 - # via temoa (pyproject.toml) pygments==2.19.2 # via # pytest @@ -100,7 +97,6 @@ salib==1.5.1 scipy==1.16.0 # via # temoa (pyproject.toml) - # pydoe # salib seaborn==0.13.2 # via temoa (pyproject.toml) diff --git a/uv.lock b/uv.lock index b33d1785c..1d5f3eee6 100644 --- a/uv.lock +++ b/uv.lock @@ -926,16 +926,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/11/b1/ce1f4596211efb5410e178a803f08e59b20bedb66837dcf41e21c54f9ec1/pybtex_docutils-1.0.3-py3-none-any.whl", hash = "sha256:8fd290d2ae48e32fcb54d86b0efb8d573198653c7e2447d5bec5847095f430b9", size = 6385, upload-time = "2023-08-22T06:43:20.513Z" }, ] -[[package]] -name = "pydoe" -version = "0.3.8" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, - { name = "scipy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bc/ac/91fe4c039e2744466621343d3b8af4a485193ed0aab53af5b1db03be0989/pyDOE-0.3.8.zip", hash = "sha256:cbd6f14ae26d3c9f736013205f53ea1191add4567033c3ee77b7dd356566c4b6", size = 22283, upload-time = "2015-07-13T20:56:28.603Z" } - [[package]] name = "pygments" version = "2.19.2" @@ -1385,7 +1375,6 @@ dependencies = [ { name = "openpyxl" }, { name = "pandas" }, { name = "pint" }, - { name = "pydoe" }, { name = "pyomo" }, { name = "pytest" }, { name = "rich" }, @@ -1442,7 +1431,6 @@ requires-dist = [ { name = "openpyxl", specifier = ">=3.1.5" }, { name = "pandas", specifier = ">=2.2.2" }, { name = "pint", specifier = ">=0.25.2" }, - { name = "pydoe", specifier = ">=0.3.8" }, { name = "pyomo", specifier = ">=6.8.0" }, { name = "pytest", specifier = ">=8.3.2" }, { name = "rich", specifier = ">=14.2.0" }, From e637077e04c3b860ff0189481290114aba9594b6 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sun, 7 Dec 2025 11:00:45 -0500 Subject: [PATCH 399/587] logging refactor with context manager for operation timing --- temoa/_internal/run_actions.py | 348 ++++++++++++++------------------- temoa/cli.py | 1 + 2 files changed, 153 insertions(+), 196 deletions(-) diff --git a/temoa/_internal/run_actions.py b/temoa/_internal/run_actions.py index f914856a7..0fece7419 100644 --- a/temoa/_internal/run_actions.py +++ b/temoa/_internal/run_actions.py @@ -3,11 +3,12 @@ """ import sqlite3 -import sys +from collections.abc import Generator, Iterable +from contextlib import contextmanager from logging import getLogger from pathlib import Path from sys import version_info -from time import time +from time import perf_counter from pyomo.environ import ( Constraint, @@ -29,6 +30,25 @@ logger = getLogger(__name__) +@contextmanager +def task_timer(action_name: str, *, silent: bool = False) -> Generator[None, None, None]: + """ + Context manager to time blocks of code using the standard logger. + """ + if not silent: + logger.info('Started: %s', action_name) + + start_time = perf_counter() + + try: + yield + finally: + duration = perf_counter() - start_time + if not silent: + # sample output: [10:30:35] INFO Finished: Creating model instance (Time taken: 0.07s) + logger.info('Finished: %s (Time taken: %.2fs)', action_name, duration) + + def check_python_version(min_major: int, min_minor: int) -> bool: if (min_major, min_minor) >= version_info: logger.error( @@ -50,38 +70,33 @@ def check_database_version(config: TemoaConfig, db_major_reqd: int, min_db_minor :param min_db_minor: the required minimum minor version (GTE test) :return: T/F """ - input_conn, input_path = sqlite3.connect(config.input_database), config.input_database - if config.input_database == config.output_database: - output_conn = None - else: - output_conn = sqlite3.connect(config.output_database) - cons = [ - (input_conn, input_path), - ] - if output_conn is not None: - cons.append((output_conn, config.output_database)) + db_paths = [config.input_database] + if config.input_database != config.output_database: + db_paths.append(config.output_database) + # check for correct version all_good = True - for con, name in cons: + for name in db_paths: + con = sqlite3.connect(name) try: - db_major = con.execute( - "SELECT value from MetaData where element = 'DB_MAJOR'" + db_major_row = con.execute( + "SELECT value from metadata where element = 'DB_MAJOR'" ).fetchone() - db_minor = con.execute( - "SELECT value from MetaData where element = 'DB_MINOR'" + db_minor_row = con.execute( + "SELECT value from metadata where element = 'DB_MINOR'" ).fetchone() - db_major = db_major[0] if db_major else -1 - db_minor = db_minor[0] if db_minor else -1 + db_major = int(db_major_row[0]) if db_major_row else -1 + db_minor = int(db_minor_row[0]) if db_minor_row else -1 except sqlite3.OperationalError: logger.error( - 'Database does not appear to have MetaData table with required versioning info. ' - 'See schema for v3+.' - ) - sys.stderr.write( - 'Database does not appear to have MetaData table with required. Is this version ' - '3+ compatible?\n' - 'If required, see dox on using the database migrator to move to v3.' + 'Database %s does not appear to have metadata table. Is this v%d.%d+ compatible?' + 'If required, see docs on using the database migrator to move to v%d.%d.', + str(name), + db_major_reqd, + min_db_minor, + db_major_reqd, + min_db_minor, ) db_major, db_minor = -1, -1 finally: @@ -90,8 +105,8 @@ def check_database_version(config: TemoaConfig, db_major_reqd: int, min_db_minor good_version = db_major == db_major_reqd and db_minor >= min_db_minor if not good_version: logger.error( - 'Database %s version %d.%d does not match the major version %d and have at least ' - 'minor version %d', + 'Database %s version %d.%d does not match the major version %d and have ' + 'at least minor version %d', str(name), db_major, db_minor, @@ -125,38 +140,18 @@ def build_instance( # self.model.rc = Suffix(direction=Suffix.IMPORT) # self.model.slack = Suffix(direction=Suffix.IMPORT) - hack = time() - if not silent: - sys.stderr.write('[ ] Creating model instance.') - sys.stderr.flush() - logger.info('Started creating model instance from data') - instance = model.create_instance(loaded_portal, name=model_name) - if not silent: - try: - # Check for warnings in log file to notify user. Ugly but it works - sys.stderr.write( - '\r[%8.2f] Instance created. \n' % (time() - hack) - ) # needs spaces to clear previous line - sys.stderr.flush() - except Exception: - sys.stderr.write( - '\r[%8.2f] Instance created. \n' % (time() - hack) - ) # needs spaces to clear previous line - sys.stderr.flush() - logger.info('Finished creating model instance from data') + with task_timer('Creating model instance', silent=silent): + instance = model.create_instance(loaded_portal, name=model_name) # save LP if requested if keep_lp_file and lp_path is not None: save_lp(instance, lp_path) # gather some stats... - c_count = 0 - v_count = 0 - for constraint in instance.component_objects(ctype=Constraint): - c_count += len(constraint) - for var in instance.component_objects(ctype=Var): - v_count += len(var) - logger.info('model built... Variables: %d, Constraints: %d', v_count, c_count) + c_count = sum(len(c) for c in instance.component_objects(ctype=Constraint)) + v_count = sum(len(v) for v in instance.component_objects(ctype=Var)) + + logger.info('Model built... Variables: %d, Constraints: %d', v_count, c_count) return instance @@ -168,17 +163,16 @@ def save_lp(instance: TemoaModel, lp_path: Path) -> None: if not lp_path: logger.warning('Requested "keep LP file", but no path is provided...skipped') else: - if not Path.is_dir(lp_path): - Path.mkdir(lp_path) + lp_path.mkdir(parents=True, exist_ok=True) filename = lp_path / 'model.lp' - instance.write(filename, format='lp', io_options={'symbolic_solver_labels': True}) + instance.write(str(filename), format='lp', io_options={'symbolic_solver_labels': True}) def solve_instance( instance: TemoaModel, solver_name: str, silent: bool = False, - solver_suffixes: list[str] | None = None, + solver_suffixes: Iterable[str] | None = None, ) -> tuple[TemoaModel, SolverResults]: """ Solve the instance and return a loaded instance @@ -194,6 +188,7 @@ def solve_instance( if not solver_name: logger.error('No solver specified in solve sequence') raise TypeError('Error occurred during solve, see log') + optimizer = SolverFactory(solver_name) if isinstance(optimizer, UnknownSolver): logger.error( @@ -203,100 +198,78 @@ def solve_instance( ) raise TypeError('Failed to make Solver instance. See log.') - hack = time() - if not silent: - sys.stderr.write('[ ] Solving.') - sys.stderr.flush() - - logger.info( - 'Starting the solve process using %s solver on model %s', solver_name, instance.name - ) if solver_name == 'neos': raise NotImplementedError('Neos based solve is not currently supported') - else: - if solver_name == 'cbc': - pass - # dev note: I think these options are outdated. Getting decent results without them... - # preserved for now. - # Solver options. Reference: - # https://genxproject.github.io/GenX/dev/solver_configuration/ - # optimizer.options["dualTolerance"] = 1e-6 - # optimizer.options["primalTolerance"] = 1e-6 - # optimizer.options["zeroTolerance"] = 1e-12 - # optimizer.options["crossover"] = 'off' - - elif solver_name == 'cplex': - # Note: these parameter values are taken to be the same as those in PyPSA - # (see: https://pypsa-eur.readthedocs.io/en/latest/configuration.html) - optimizer.options['lpmethod'] = 4 # barrier - optimizer.options['solutiontype'] = 2 # non basic solution, ie no crossover - optimizer.options['barrier convergetol'] = 1.0e-5 - optimizer.options['feasopt tolerance'] = 1.0e-6 - - elif solver_name == 'gurobi': - # Note: these parameter values are taken to be the same as those in PyPSA (see: https://pypsa-eur.readthedocs.io/en/latest/configuration.html) - optimizer.options['Method'] = 2 # barrier - optimizer.options['Crossover'] = 0 # non basic solution, ie no crossover - optimizer.options['BarConvTol'] = 1.0e-5 - optimizer.options['FeasibilityTol'] = 1.0e-6 - # optimizer.options["BarOrder"] = 0 # if solve times seem unusually long, try 0 or 1 - - elif solver_name == 'appsi_highs': - pass + # Solver Configuration + if solver_name == 'cbc': + pass + + elif solver_name == 'cplex': + # Note: these parameter values are taken to be the same as those in PyPSA + # (see: https://pypsa-eur.readthedocs.io/en/latest/configuration.html) + optimizer.options['lpmethod'] = 4 # barrier + optimizer.options['solutiontype'] = 2 # non basic solution, ie no crossover + optimizer.options['barrier convergetol'] = 1.0e-5 + optimizer.options['feasopt tolerance'] = 1.0e-6 + + elif solver_name == 'gurobi': + # Note: these parameter values are taken to be the same as those in PyPSA (see: https://pypsa-eur.readthedocs.io/en/latest/configuration.html) + optimizer.options['Method'] = 2 # barrier + optimizer.options['Crossover'] = 0 # non basic solution, ie no crossover + optimizer.options['BarConvTol'] = 1.0e-5 + optimizer.options['FeasibilityTol'] = 1.0e-6 + # optimizer.options["BarOrder"] = 0 # if solve times seem unusually long, try 0 or 1 + + elif solver_name == 'appsi_highs': + pass + + # Suffix Handling + solver_suffixes_list: list[str] = [] + if solver_suffixes: + solver_suffixes_set = set(solver_suffixes) + legit_suffixes = {'dual', 'slack', 'rc'} + bad_apples = solver_suffixes_set - legit_suffixes + solver_suffixes_set &= legit_suffixes + if bad_apples: + logger.warning( + 'Solver suffix %s is not in pyomo standards (see pyomo dox). Removed', + bad_apples, + ) + solver_suffixes_list = list(solver_suffixes_set) - # dev note: The handling of suffixes is pretty weak. As of today 4/4/2024, highspy - # crashes if the keyword suffixes is passed in (regardless if there are any - # requested). CBC only supports some. Perhaps in the future, this will be - # easier. For now, we need a different - # solve command for highspy and no suffixes because it works so well. - if solver_suffixes: - solver_suffixes_set = set(solver_suffixes) - legit_suffixes = {'dual', 'slack', 'rc'} - bad_apples = solver_suffixes_set - legit_suffixes - solver_suffixes_set &= legit_suffixes - if bad_apples: - logger.warning( - 'Solver suffix %s is not in pyomo standards (see pyomo dox). Removed', - bad_apples, - ) - # convert back to list... - solver_suffixes = list(solver_suffixes_set) - else: - solver_suffixes = [] - result: SolverResults | None = None + result: SolverResults | None = None + + with task_timer(f'Solving model {instance.name}', silent=silent): try: - # currently, the highs solver call will puke if the suffixes are passed, so we need to - # differentiate... + # currently, the highs solver call will puke if the suffixes are passed if solver_name == 'appsi_highs': result = optimizer.solve(instance) else: - result = optimizer.solve(instance, suffixes=solver_suffixes) + result = optimizer.solve(instance, suffixes=solver_suffixes_list) except RuntimeError as error: - logger.error('Solver failed to solve and returned an error: %s', error) + logger.exception('Solver failed to solve and returned an error: %s', error) logger.error( 'This may be due to asking for suffixes (duals) for an incompatible solver. ' "Try de-selecting 'save_duals' in the config. (see note in run_actions.py code)" ) if result: + try: + _ok, status_msg = check_solve_status(result) + except Exception: + status_msg = '' logger.error( - 'Solver reported termination condition (if any): %s', result['Solution'].Status + 'Solver reported termination/status (if any): %s', + status_msg, ) - sys.stderr.write('solver failure. See log file.') - sys.exit(-1) + raise RuntimeError('Solver failure. See log file.') from error - if check_optimal_termination(result): - if solver_suffixes: - instance.solutions.store_to( - result - ) # this is needed to capture the duals/suffixes from the Solutions obj + if check_optimal_termination(result): + if solver_suffixes_list: + # Needed to capture the duals/suffixes from the Solutions obj + instance.solutions.store_to(result) - logger.info('Solve process complete') - logger.debug('Solver results: \n %s', result.solver) - - if not silent: - sys.stderr.write('\r[%8.2f] Model solved.\n' % (time() - hack)) - sys.stderr.flush() + logger.debug('Solver results: \n %s', result.solver) return instance, result @@ -311,10 +284,9 @@ def check_solve_status(result: SolverResults) -> tuple[bool, str]: optimal """ # Use check_optimal_termination for solver-agnostic checking - # Different solvers report status differently (e.g., HiGHS reports 'unknown' but is optimal) is_optimal = check_optimal_termination(result) - # Safely extract termination condition for logging (works for both legacy and APPSI solvers) + # Safely extract termination condition for logging termination_condition = 'unknown' if hasattr(result, 'solver') and hasattr(result.solver, 'termination_condition'): termination_condition = result.solver.termination_condition @@ -322,35 +294,39 @@ def check_solve_status(result: SolverResults) -> tuple[bool, str]: # Some APPSI solvers expose this directly termination_condition = result.termination_condition - logger.info('Solver termination condition: %s (optimal: %s)', termination_condition, is_optimal) + logger.info( + 'Solver termination condition: %s (optimal: %s)', + termination_condition, + is_optimal, + ) if is_optimal: return True, '' - else: - # Safely extract status for error message - status_msg = 'unknown status' - # Try legacy solver result format first - if hasattr(result, '__getitem__'): - try: - soln = result.get('Solution') if hasattr(result, 'get') else result['Solution'] - if soln and hasattr(soln, 'Status'): - status_msg = str(soln.Status) - except (KeyError, TypeError, AttributeError): - pass + # Safely extract status for error message + status_msg = 'unknown status' + + # Try legacy solver result format first + if hasattr(result, '__getitem__'): + try: + soln = result.get('Solution') if hasattr(result, 'get') else result['Solution'] + if soln and hasattr(soln, 'Status'): + status_msg = str(soln.Status) + except (KeyError, TypeError, AttributeError): + pass - # Try APPSI result format - if status_msg == 'unknown status': - for attr in ['status', 'problem_status', 'solver_status']: - if hasattr(result, attr): - status_msg = str(getattr(result, attr)) - break + # Try APPSI result format + if status_msg == 'unknown status': + for attr in ['status', 'problem_status', 'solver_status']: + if hasattr(result, attr): + status_msg = str(getattr(result, attr)) + break - # Final fallback - if status_msg == 'unknown status': - status_msg = str(result) if result else 'no solution returned' + # Final fallback + if status_msg == 'unknown status': + status_msg = str(result) if result else 'no solution returned' - return False, f'{status_msg} was returned from solve' + return False, f'{status_msg} was returned from solve' def handle_results( @@ -360,48 +336,27 @@ def handle_results( append: bool = False, iteration: int | None = None, ) -> None: - hack = time() - if not config.silent: - msg = '[ ] Calculating reporting variables and formatting results.' - # yield 'Calculating reporting variables and formatting results.' - sys.stderr.write(msg) - sys.stderr.flush() - - table_writer = TableWriter(config=config) - if config.save_duals: + with task_timer('Processing results', silent=config.silent): + table_writer = TableWriter(config=config) table_writer.write_results( model=instance, - results_with_duals=results, + results_with_duals=results if config.save_duals else None, save_storage_levels=config.save_storage_levels, append=append, iteration=iteration, ) - else: - table_writer.write_results( - model=instance, - append=append, - save_storage_levels=config.save_storage_levels, - iteration=iteration, - ) - - if not config.silent: - sys.stderr.write( - '\r[%8.2f] Results processed. \n' % (time() - hack) - ) - sys.stderr.flush() if config.save_excel: scenario_name = ( - config.scenario + f'-{iteration}' if iteration is not None else config.scenario + f'{config.scenario}-{iteration}' if iteration is not None else config.scenario ) - temp_scenario = set() - temp_scenario.add(scenario_name) + temp_scenario = {scenario_name} excel_filename = config.output_path / scenario_name make_excel(str(config.output_database), excel_filename, temp_scenario) # normal (non-MGA) run will have a total_cost as the OBJ: if hasattr(instance, 'total_cost'): - logger.info('total_cost value: %0.2f', value(instance.total_cost)) + logger.info('Total Cost value: %0.2f', value(instance.total_cost)) if config.graphviz_output: try: @@ -420,18 +375,19 @@ def handle_results( ) graph_gen.connect() - # Get periods from the model instance - periods = sorted(instance.time_optimize) - - for period in periods: - # Generate main results diagram for the period - # We pass None for region to generate for all/default - graph_gen.create_main_results_diagram(period=period, region=None) - - graph_gen.close() + try: + # Get periods from the model instance + periods = sorted(instance.time_optimize) + + for period in periods: + # Generate main results diagram for the period + # We pass None for region to generate for all/default + graph_gen.create_main_results_diagram(period=period, region=None) + except Exception as e: + logger.error('Failed to generate Graphviz plots: %s', e, exc_info=True) + finally: + graph_gen.close() logger.info('Graphviz plots generated in %s', graph_gen.out_dir) except Exception as e: logger.error('Failed to generate Graphviz plots: %s', e, exc_info=True) - - return diff --git a/temoa/cli.py b/temoa/cli.py index 21d8beafb..45aea3a34 100644 --- a/temoa/cli.py +++ b/temoa/cli.py @@ -50,6 +50,7 @@ def _setup_logging(output_path: Path, debug: bool = False, silent: bool = False) level=console_level, rich_tracebacks=True, show_path=False, + show_time=True, log_time_format='[%X]', ) From 44ba20a7654226b2525d5fc2a1fe1d48bdbf92c6 Mon Sep 17 00:00:00 2001 From: Anil Radhakrishnan Date: Mon, 24 Nov 2025 12:27:42 -0500 Subject: [PATCH 400/587] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 86 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 50 +++++++++++++ .github/ISSUE_TEMPLATE/question.md | 41 +++++++++++ 3 files changed, 177 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/question.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..79a94c47e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,86 @@ +--- +name: Bug report +about: Report a reproducible bug or unexpected behavior. +title: "[Bug]: Clear and concise description of the bug" +labels: bug, needs-triage +assignees: '' + +--- + +## Bug Description + +Clearly and concisely describe the bug you've encountered. What is the unexpected behavior? What did you expect to happen instead? + +## Steps to Reproduce + +Provide a clear, step-by-step procedure to reproduce the bug. This is crucial for us to understand and fix the issue. + +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error '....' + +## Code or Configuration Example + +If the bug involves code or configuration, please provide a minimal, reproducible example that demonstrates the issue. This should be the smallest amount of code/config necessary to trigger the bug. + +```python +# Example of bug-inducing code (if relevant) +import my_library + +# Setup or initialization +config = { + "setting_a": "value", + "setting_b": 123 +} +processor = my_library.Processor(**config) + +# Action that triggers the bug +try: + processor.process_data(invalid_data) +except Exception as e: + print(f"Error: {e}") +``` + +## Error Message / Stack Trace + +If an error message or stack trace was produced, please include it here. Use code blocks for better readability. + +```text +# Example Error Message/Stack Trace +Traceback (most recent call last): + File "", line 7, in + processor.process_data(invalid_data) + File "/path/to/my_library/processor.py", line 42, in process_data + raise ValueError("Invalid data provided") +ValueError: Invalid data provided +``` + +## Screenshots / Videos + +If applicable, add screenshots to help explain the problem. You can drag and drop images directly into the issue description. + +## Expected Behavior + +Describe what you expected to happen when following the reproduction steps. + +## Actual Behavior + +Describe what actually happened, including any unexpected output or results. + +## Environment + +Please provide details about your environment. This helps us reproduce the issue. + +* **Operating System:** +* **Python Version:** +* **Project Version:** +* **Relevant Dependencies:** + +## Checklist + +* [ ] I have searched existing issues to ensure this bug hasn't already been reported. +* [ ] I have provided clear steps to reproduce the bug. +* [ ] I have provided a minimal, reproducible code example (if applicable). +* [ ] I have included any relevant error messages or stack traces. +* [ ] I have described the expected and actual behavior. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..c6162169c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,50 @@ +--- +name: Feature request +about: Suggest an idea for a new feature or enhancement. +title: "[Feature]: Concise title for your feature request" +labels: enhancement, needs-triage +assignees: '' + +--- + +## Feature Request + +Clearly and concisely describe the new feature or enhancement you are requesting. + +## Problem Statement + +What problem does this new feature or enhancement solve? Why is it needed? Describe the current limitations or pain points that this feature would address. + +## Proposed Solution (optional) + +Describe your proposed solution or how you envision this feature working. Be as specific as possible. Consider: + +* **User Interface/API Changes:** How would a user interact with this new feature? +* **Configuration:** Would new configuration options be needed? +* **Examples of Usage:** Provide a hypothetical example of how this feature would be used. +## Benefits + +What are the benefits of implementing this feature? How would it improve the project for users? + +* (e.g., "It would simplify X workflow for users.") +* (e.g., "It would enable Y functionality that is currently impossible.") +* (e.g., "It would improve performance by Z% in certain scenarios.") + +## Alternatives Considered + +Have you considered any alternative approaches or workarounds for the problem you're trying to solve? If so, why do you think this feature request is a better solution? + +## Additional Context + +Add any other context, links, or information about the feature request here. This could include: + +* Similar features in other projects. +* Relevant research papers or articles. +* Any potential challenges or considerations for implementation. + +## Checklist + +* [ ] I have searched existing issues to ensure this feature hasn't already been requested. +* [ ] I have clearly described the problem this feature solves. +* [ ] I have provided a detailed proposed solution (optional). +* [ ] I have explained the benefits of this feature. diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 000000000..817c6d7fe --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,41 @@ +--- +name: Question +about: Questions about the usage or working of a feature +title: "[Question]: Your concise question title here" +labels: needs-triage, question +assignees: '' + +--- + +## Question +Clearly and concisely state your question here. What are you trying to understand or achieve? + +## Context +Provide any relevant background information or context that might help us understand your question better. For example: + +* **What are you trying to do?** (e.g., "I'm trying to integrate X with Y," "I'm trying to achieve Z functionality.") +* **Why is this question important to you?** (e.g., "This is blocking my progress on feature A," "I'm trying to decide between two approaches.") +* **What steps have you already taken to find an answer?** (e.g., "I've checked the documentation for X," "I've searched existing issues for similar topics," "I've tried searching on Stack Overflow.") + +## Details & Examples + +If applicable, provide specific details, code snippets, or examples that illustrate your question. This is especially helpful for questions related to: + +* **Usage:** How are you currently trying to use the project? +* **Configuration:** What relevant configuration are you using? +* **Code:** If your question involves code, please provide a minimal, reproducible example. + +## Environment + +Please provide details about your environment. This helps us reproduce issues or understand potential incompatibilities. + +* **Operating System:** +* **Python Version:** +* **Project Version:** +* **Relevant Dependencies:** + +## Checklist + +* [ ] I have checked the [documentation](https://docs.temoaproject.org/en/latest/) for an answer. +* [ ] I have searched existing issues to ensure my question hasn't already been asked. +* [ ] I have provided as much detail as possible to help answer my question. From 3753005dddad509decfe6edb30bcc0d07709b873 Mon Sep 17 00:00:00 2001 From: Joe DeCarolis Date: Mon, 29 Dec 2025 09:28:07 -0500 Subject: [PATCH 401/587] Update preface and quick start guide --- docs/source/preface.rst | 113 ++++++++++++++++++++---------------- docs/source/quick_start.rst | 105 +++++++++++++++++---------------- 2 files changed, 116 insertions(+), 102 deletions(-) diff --git a/docs/source/preface.rst b/docs/source/preface.rst index 210d46c21..3ae144383 100644 --- a/docs/source/preface.rst +++ b/docs/source/preface.rst @@ -16,61 +16,76 @@ soon as possible. What is Temoa? -------------- +Temoa is an energy system optimization model (ESOM) developed over many years +to support transparent, data-driven analysis of energy systems. ESOMs +serve as an important planning tool because they allow users to examine energy +futures using a self-consistent framework for evaluation. Temoa is implemented +as a linear program that minimizes the total cost of energy supply by optimizing +the installation and operation of energy technologies over a user-defined +planning horizon. Energy supply must meet end-use demands subject to physical +and technical constraints governing system operation, along with user-defined +policy scenarios. + +The energy system on which Temoa and other ESOMs operate can be visualized as +a directed graph. Primary energy sources represent the points of origin, which +are transformed by a network of energy conversion and delivery technologies, and +ultimately produce consumable energy commodities that satisfy end-use demands. +[#esom_definition]_. Temoa provides tools to explicitly represent this network, +visualize system structure, and trace energy flows through time. + +A defining strength of Temoa is its flexible treatment of time. Users may +define arbitrary model periods of varying length and represent intra-period +operations using seasonal and time-of-day slices, full chronological hours, or +representative days. Capacity expansion can be solved under perfect foresight +or using a rolling-horizon. In addition, Temoa supports technology +vintaging, separate loan periods and physical lifetimes, and both global and +technology-specific discount rates. Beyond deterministic optimization, Temoa +supports stochastic optimization as well as modeling-to-generate alternatives +(MGA) to explore near-optimal solution spaces. All of Temoa's features were +driven by specific analytic needs over a decade of model development and +policy-focused application. + +Temoa is implemented within an open-source software stack and is released under +the MIT license, with source code available on GitHub [#open_source_realities]_. +The model is written in Python and seamlessly integrates with the broader Python +ecosystem. Input data are stored in a relational SQLite database, enabling +transparency, reproducibility, and easy modification. The model maintains a +strict distinction between source code and the input data on which it operates. +The model can be executed on single machines, multi-core systems, or +high-performance computing environments. + +The name Temoa (Tools for Energy Model Optimization and Analysis) reflects the +project's broader scope. The platform comprises four interrelated components: +the underlying mathematical formulation, its software implementation, a suite +of supporting tools for data management, analysis, and visualization, and an +online presence that supports documentation, dissemination, and community +engagement. Together, these elements are designed to foster collaboration, +extensibility, and trust in energy system modeling results. -Temoa is an energy system optimization model (ESOM). Briefly, ESOMs optimize the -installation and utilization of energy technology capacity over a user-defined -time horizon. Optimal decisions are driven by an objective function that minimizes -the cost of energy supply. Conceptually, one may think of an ESOM as a "left-to-right" -network graph, with a set of energy sources on the lefthand side of the graph that -are transformed into consumable energy commodities by a set of energy technologies, -which are ultimately used to meet demands on the righthand side of the network graph. -[#esom_definition]_ - -Key features of the core Temoa model include: - - * Flexible time slicing by season and time-of-day - * Variable length model time periods - * Technology vintaging - * Separate technology loan periods and lifetimes - * Global and technology-specific discount rates - * Capability to perform stochastic optimization - * Capability to perform modeling-to-generate alternatives (MGA) - - -Temoa design features include: - - * Source code licensed under MIT, available through Github [#open_source_realities]_ - * Open source software stack - * Part of a rich Python ecosystem - * Data stored in a relational database system (sqlite) - * Ability to utilize multi-core and compute cluster environments - -The word 'Temoa' is actually an acronym for "Tools for Energy Model Optimization -and Analysis," currently composed of four (major) pieces of infrastructure: - - * The mathematical model - * The implemented model (code) - * Surrounding tools - * An online presence - -Each of these pieces is fundamental to creating a transparent and usable model -with a community oriented around collaboration. Why Temoa? ---------- +In 2009, when the idea for Temoa was born, most options for energy systems +modeling were geared towards government institutions that could afford the +expensive commercial software licenses. Closed source code and data also +meant that it was impossible for third parties to verify published model +results, even though those results were being used to inform public policy +decisions involving significant transfers of wealth and direct consequences for +people's lives. In addition, models were typically used to run a limited number +of scenarios that did not address the true underlying uncertainty about the +future. + +Today's vibrant open source energy modeling community did not exist at +that time. We were motivated to build Temoa around three high-level objectives: +(1) make the model code and data open source to enable third party replication +of results, (2) use an open source software stack to minimize the barriers to +entry in energy modeling, and (3) build a toolkit to evaluate future uncertainty +in different ways, depending on the question at hand. + +Temoa remains one of the most fully-featured, open source energy system models +focused on projecting changes across the whole energy system. -In short, because we believe that ESOM-based analyses should be repeatable by -independent third parties. The only way to make this happen is to -have a freely available model, and to create an ecosystem of freely shared data -and model inputs. - -For a longer explanation, please see :cite:`Hunter_etal_2013`. In summary, -ESOM-based analyses are (1) impossible to validate, (2) complex enough as to be -non-repeatable without electronic access to **exact** versions of code *and* data -input, and (3) often do a poor job addressing uncertainty. We believe that -ESOM-based analyses should be completely open, independently reproducible, -electronically available, and address uncertainty about the future. Temoa Origin and Pronunciation diff --git a/docs/source/quick_start.rst b/docs/source/quick_start.rst index d639f0bc0..8a9429995 100644 --- a/docs/source/quick_start.rst +++ b/docs/source/quick_start.rst @@ -82,14 +82,13 @@ solver. HiGHS is automatically available when you install Temoa and requires no Running Temoa ------------- -To run the model, a configuration (ā€˜config’) file is needed. An +To run the model, a configuration (``config``) file is needed. An example config file called :code:`config_sample.toml` resides within the :code:`data_files/my_configs` folder. Running the model with a config file allows -the user to (1) use a sqlite -database for storing input and output data, (2) create a formatted Excel output -file, (2) specify the solver to use, (3) return the log file produced during -model execution, (4) return the lp file utilized by the solver, and (5) to -execute several of the modeling extensions. +the user to (1) use a sqlite database for storing input and output data, (2) +create a formatted Excel output file, (2) specify the solver to use, (3) return +the log file produced during model execution, (4) return the lp file utilized by +the solver, and (5) to execute several of the modeling extensions. .. parsed-literal:: $ temoa run config.toml @@ -127,53 +126,53 @@ execute several of the modeling extensions. Database Construction ==================================== -Input datasets in Temoa can be constructed either as text files or relational -databases. Input text files are referred to as 'DAT' files and follow a specific -format. Take a look at the example DAT files in the :code:`temoa/data_files` -directory. - -While DAT files work fine for small datasets, relational databases are preferred -for larger datasets. To first order, you can think of a database as a collection -of tables, where a 'primary key' within each table defines a unique entry (i.e., -row) within the table. In addition, a 'foreign key' defines a table element drawn -from another table. Foreign keys enforce the defined relationships between -different sets and parameters. +Input datasets in Temoa are stored in a relational database management system. +For those unfamiliar with databases, you can think of them as collections of +tables. Within each table, a 'primary key' uniquely identifies each row. A +'foreign key' is a column in one table that references the primary key of +another table, thereby establishing relationships between tables and ensuring +data consistency across the database. Temoa uses `sqlite`_, a widely used, self-contained database system. Building a database first requires constructing a sql file, which is simply a text file that defines the structure of different database tables and -includes the input data. The snippet below is from the technology table used to -define the 'temoa_utopia' dataset: - -**NOTE**: *As of Version 3, the below table format is dated, but still shows the general structure of -the SQL files used to create the database.* +includes the input data. The snippet below is from the ``time_period`` table +used to define the ``test_system`` dataset: .. parsed-literal:: - CREATE TABLE technologies ( - tech text primary key, - flag text, - sector text, - tech_desc text, - tech_category text, - FOREIGN KEY(flag) REFERENCES technology_labels(tech_labels), - FOREIGN KEY(sector) REFERENCES sector_labels(sector)); - INSERT INTO "technologies" VALUES('IMPDSL1','r','supply',' imported diesel','petroleum'); - INSERT INTO "technologies" VALUES('IMPGSL1','r','supply',' imported gasoline','petroleum'); - INSERT INTO "technologies" VALUES('IMPHCO1','r','supply',' imported coal','coal'); - -The first line creates the table. **Lines 2-6** define the columns within this table. -Note that the the technology ('tech') name defines the primary key. Therefore, the -same technology name cannot be entered twice; each technology name must be unique. -**Lines 7-8** define foreign keys within the table. For example, each technology -should be specified with a label (e.g., 'r' for 'resource'). Those labels must -come from the 'technology_labels' table. Likewise, the sector name must be defined -in the 'sector_labels' table. This enforcement of names across tables using -foreign keys helps immediately catch typos. (As you can imagine, typos happen in -plain text files and Excel when defining thousands of rows of data.) Another big -advantage of using databases is that the model run outputs are stored in -separate database output tables. The outputs by model run are indexed by a scenario name, -which makes it possible to perform thousands of runs, programatically store all -the results, and execute arbitrary queries that instantaneously return the requested + 1 CREATE TABLE time_period + 2 ( + 3 sequence INTEGER UNIQUE, + 4 period INTEGER + 5 PRIMARY KEY, + 6 flag TEXT + 7 REFERENCES time_period_type (label) + 8 ); + 9 INSERT INTO "time_period" VALUES(1,2015,'e'); + 10 INSERT INTO "time_period" VALUES(2,2020,'f'); + 11 INSERT INTO "time_period" VALUES(3,2025,'f'); + 12 INSERT INTO "time_period" VALUES(4,2030,'f'); + 13 INSERT INTO "time_period" VALUES(5,2035,'f'); + +The first line creates the table. **Lines 3-7** define the columns within this +table. Note that ``period`` is the primary key. Therefore, the same time period +cannot be entered twice; each name must be unique. **Line 7**, which helps +define the ``flag`` column, declares a foreign key reference to the ``label`` +column of the ``time_period_type`` table. As a result, if the user tries to +enter a label in this table that does not exist in the ``time_period_type`` +table, it will fail with an error. This foreign key reference ensures that the +modeler doesn't accidently type the wrong label in this table. For context, +there are two basic types of time periods in Temoa, ``e``, which defines +pre-existing periods, and ``f``, which defines future time periods that are to +be optimized. + +This enforcement of names across tables using foreign keys helps immediately +catch typos. As you can imagine, typos happen in plain text files and Excel when +defining thousands of rows of data. Another big advantage of using databases is +that the model run outputs are stored in separate database output tables. The +outputs by model run are indexed by a scenario name, which makes it possible to +perform thousands of runs, programatically store all the results, and execute +arbitrary queries that instantaneously return the requested data. Because some database table elements serve as foreign keys in other tables, we @@ -224,12 +223,12 @@ recommend that you populate input tables in the following order: * limit_tech_input_split * limit_tech_output_split -For help getting started, take a look at how :code:`data_files/temoa_utopia.sql` is -constructed. Use :code:`data_files/temoa_schema.sql` (a database file with the requisite -structure but no data added) to begin building your own database file. We recommend -leaving the database structure intact, and simply adding data to the schema file, or -constructing an empty database from the schema file and then using a database editor -to import data. +For help getting started, take a look at how ``data_files/example_dbs/utopia.sql`` +is constructed. To begin building your own database file, use +``data_files/temoa_schema_v4.sql``, which is a database file with the requisite +structure but no data added. We recommend leaving the database structure intact, +and simply adding data to the schema file, or constructing an empty database +from the schema file and then using a script or database editor to import data. Once the sql file is complete, you can convert it into a binary sqlite file by installing sqlite3 and executing the following command: From b284706d6b6120cc0d2e7733be3956aa68399eca Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 1 Jan 2026 09:27:51 -0500 Subject: [PATCH 402/587] docs: adding mapping between code elements and database tables Co-authored-by: jdecarolis --- docs/source/db_model_comparison.rst | 319 +++++++++++++++++++++++ docs/source/mathematical_formulation.rst | 3 + 2 files changed, 322 insertions(+) create mode 100644 docs/source/db_model_comparison.rst diff --git a/docs/source/db_model_comparison.rst b/docs/source/db_model_comparison.rst new file mode 100644 index 000000000..1b6d06f4a --- /dev/null +++ b/docs/source/db_model_comparison.rst @@ -0,0 +1,319 @@ +Database Tables vs Model Sets/Parameters Comparison +====================================================== + +Direct Mappings: Sets +--------------------- + +Time-Related Sets +^^^^^^^^^^^^^^^^^ + +.. csv-table:: + :header: "Set", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + ":math:`\text{P}^e`", "time_period", "time_exist", "model periods before optimization begins; partitioned by period type flag" + ":math:`\text{P}^f`", "time_period", "time_future", "model time scale of interest; the last year is not optimized; partitioned by period type flag" + ":math:`{}^*\text{P}^o`", "time_period", "time_optimize", "model time periods to optimize; (:math:`\text{P}^f - \text{max}(\text{P}^f)`); partitioned by period type flag" + ":math:`{}^*\text{V}`", "time_period", "vintage_exist, vintage_optimize, vintage_all", "possible tech vintages; (:math:`\text{P}^e \cup \text{P}^o`); same data, used for vintage tracking" + ":math:`\text{D}`", "time_of_day", "time_of_day", "time-of-day divisions (e.g. morning); direct mapping" + ":math:`\text{S}`", "season_label", "time_season_all, time_season", "seasonal divisions (e.g. winter, summer); direct mapping" + "", "time_season", "time_season", "seasons by period" + "", "time_season_sequential", "time_season_to_sequential, ordered_season_sequential", "sequential season ordering" + +Geography Sets +^^^^^^^^^^^^^^ + +.. csv-table:: + :header: "Set", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + ":math:`\text{R}`", "region", "regions", "distinct geographical regions; direct mapping" + "", "region", "regional_indices", "derived with exchange logic" + "", "region", "regional_global_indices", "regional groups" + +Technology Sets +^^^^^^^^^^^^^^^ + +.. csv-table:: + :header: "Set", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + ":math:`{}^*\text{T}`", "technology", "tech_all", "all technologies to be modeled; (:math:`{T}^r \cup {T}^p`); all technologies" + ":math:`\text{T}^p`", "technology", "tech_production", "techs producing intermediate commodities" + ":math:`\text{T}^b`", "technology (flag='pb')", "tech_baseload", "baseload electric generators; (:math:`{T}^b \subset T`); filtered by flag" + ":math:`\text{T}^s`", "technology (flag='ps')", "tech_storage", "all storage technologies; (:math:`{T}^s \subset T`); filtered by flag" + ":math:`\text{T}^a`", "technology (annual=1)", "tech_annual", "technologies that produce constant annual output; (:math:`{T}^a \subset T`); filtered by annual flag" + ":math:`\text{T}^{res}`", "technology (reserve=1)", "tech_reserve", "electric generators contributing to the reserve margin requirement; (:math:`{T}^{res} \subset T`); filtered by reserve flag" + ":math:`\text{T}^c`", "technology (curtail=1)", "tech_curtailment", "technologies with curtailable output and no upstream cost; (:math:`{T}^c \subset (T - T^{res})`); filtered by curtail flag" + ":math:`\text{T}^f`", "technology (flex=1)", "tech_flex", "technologies producing excess commodity flows; (:math:`{T}^f \subset T`); filtered by flex flag" + ":math:`\text{T}^x`", "technology (exchange=1)", "tech_exchange", "technologies used for interregional commodity flow; (:math:`{T}^x \subset T`); filtered by exchange flag" + ":math:`\text{T}^{ret}`", "technology (retire=1)", "tech_retirement", "technologies allowed to retire before end of life; (:math:`{T}^{ret} \subset (T - T^{u})`); filtered by retire flag" + ":math:`\text{T}^u`", "technology (unlim_cap=1)", "tech_uncap", "technologies that have no bound on capacity; (:math:`{T}^u \subset (T - T^{res})`); filtered by unlim_cap flag" + ":math:`\text{T}^{ss}`", "technology (seas_stor=1)", "tech_seasonal_storage", "seasonal storage technologies; (:math:`{T}^{ss} \subset T^s`); filtered by seas_stor flag" + "", "tech_group", "tech_group_names", "named groups for use in group constraints; group names" + "", "tech_group_member", "tech_group_members", "each technology belonging to each group; group membership" + ":math:`\text{T}^e`", "existing_capacity", "tech_exist", "technologies constructed in an existing (past) vintage; (:math:`{T}^e \subset T`); derived from existing_capacity table" + +Commodity Sets +^^^^^^^^^^^^^^ + +.. csv-table:: + :header: "Set", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + ":math:`\text{C}^d`", "commodity (flag='d')", "commodity_demand", "end-use demand commodities; filtered by flag" + ":math:`\text{C}^e`", "commodity (flag='e')", "commodity_emissions", "emission commodities (e.g. :math:`\text{CO}_\text{2}` :math:`\text{NO}_\text{x}`); filtered by flag" + ":math:`\text{C}^p`", "commodity (flag='p')", "commodity_physical", "general energy forms (e.g. electricity, coal, uranium, oil); filtered by flag" + ":math:`\text{C}^w`", "commodity (flag='w','wa','wp')", "commodity_waste", "production can be greater than consumption; can be physical, annual, or neither (not balanced); filtered by waste flags" + ":math:`\text{C}^a`", "commodity (flag='a')", "commodity_annual", "same as commodity physical but flows are only balanced over each period (:math:`\text{C}^a \subset \text{C}^p`); filtered by flag" + ":math:`\text{C}^s`", "commodity (flag='s')", "commodity_source", "input sources (not balanced by CommodityBalance_constraint); filtered by flag" + ":math:`{}^*\text{C}^c`", "", "commodity_carrier", "physical energy carriers and end-use demands (:math:`\text{C}_p \cup \text{C}_d`); union of physical, demand, and waste commodities" + ":math:`{}^*\text{C}`", "", "commodity_all", "union of all commodity sets; union of carrier and emissions commodities" + +Other Sets +^^^^^^^^^^ + +.. csv-table:: + :header: "Set", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + "", "operator", "operator", "constraint operators" + + +Direct Mappings: Parameters +---------------------------- + +Time-Related Parameters +^^^^^^^^^^^^^^^^^^^^^^^ + +.. csv-table:: + :header: "Parameter", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + "", "metadata_real (global_discount_rate)", "global_discount_rate", "global rate used to calculate present cost; global discount rate" + ":math:`\text{SEG}_{s,d}`", "time_segment_fraction", "segment_fraction", "fraction of year represented by each (s, d) tuple; time slice fractions" + "", "metadata (days_per_period)", "days_per_period", "days per period" + "", "", "segment_fraction_per_season", "computed from segment fractions" + "", "time_season_sequential", "time_season_sequential", "sequential season ordering (mutable)" + +Capacity & Existing Infrastructure Parameters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. csv-table:: + :header: "Parameter", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + ":math:`\text{ECAP}_{r,t,v}`", "existing_capacity", "existing_capacity", "pre-existing capacity; direct mapping" + ":math:`\text{C2A}_{r,t,v}`", "capacity_to_activity", "capacity_to_activity", "converts from capacity to activity units; direct mapping" + ":math:`\text{CFT}_{r,s,d,t}`", "capacity_factor_tech", "capacity_factor_tech", "technology-specific capacity factor; tech-level capacity factors" + ":math:`\text{CFP}_{r,s,d,t,v}`", "capacity_factor_process", "capacity_factor_process", "process-specific capacity factor; process-level capacity factors" + ":math:`\text{CC}_{r,p,t,v}`", "capacity_credit", "capacity_credit", "process-specific capacity credit; reserve capacity credit" + +Cost Parameters +^^^^^^^^^^^^^^^ + +.. csv-table:: + :header: "Parameter", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + ":math:`\text{CF}_{r,p,t,v}`", "cost_fixed", "cost_fixed", "fixed operations & maintenance cost; fixed O&M costs" + ":math:`\text{CI}_{r,t,v}`", "cost_invest", "cost_invest", "tech-specific investment cost; investment costs" + ":math:`\text{CV}_{r,p,t,v}`", "cost_variable", "cost_variable", "variable operations & maintenance cost; variable O&M costs" + "", "cost_emission", "cost_emission", "emission costs" + ":math:`\text{LR}_{r,t,v}`", "loan_rate", "loan_rate", "process-specific interest rate on investment cost; technology-specific loan rates" + "", "metadata_real (default_loan_rate)", "default_loan_rate", "default loan rate" + ":math:`\text{GDR}`", "metadata_real (global_discount_rate)", "global_discount_rate", "global rate used to calculate present cost; global discount rate" + +Efficiency & Performance Parameters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. csv-table:: + :header: "Parameter", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + ":math:`\text{EFF}_{r,i,t,v,o}`", "efficiency", "efficiency", "tech- and commodity-specific efficiency; base efficiency" + "", "efficiency_variable", "efficiency_variable", "time-varying efficiency" + ":math:`\text{LTT}_{r,t}`", "lifetime_tech", "lifetime_tech", "tech-specific lifetime (default=40 years); technology lifetime" + ":math:`\text{LTP}_{r,t,v}`", "lifetime_process", "lifetime_process", "tech- and vintage-specific lifetime (default=lifetime_tech); process-specific lifetime" + ":math:`\text{LSC}_{r,p,t,v}`", "lifetime_survival_curve", "lifetime_survival_curve", "surviving fraction of original capacity; survival curve fractions" + ":math:`\text{LLP}_{r,t,v}`", "loan_lifetime_process", "loan_lifetime_process", "process-specific loan term (default=lifetime_process); loan lifetime" + +Demand Parameters +^^^^^^^^^^^^^^^^^ + +.. csv-table:: + :header: "Parameter", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + ":math:`\text{DEM}_{r,p,c}`", "demand", "demand", "end-use demands, by period; demand by region-period-commodity" + ":math:`\text{DSD}_{r,p,s,d,c}`", "demand_specific_distribution", "demand_specific_distribution", "demand-specific distribution; demand time distribution" + +Emission Parameters +^^^^^^^^^^^^^^^^^^^ + +.. csv-table:: + :header: "Parameter", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + ":math:`\text{EAC}_{r,i,t,v,o,e}`", "emission_activity", "emission_activity", "tech-specific emissions rate; activity-based emissions" + ":math:`\text{EE}_{r,t,v,e}`", "emission_embodied", "emission_embodied", "emissions associated with the creation of capacity; embodied emissions" + ":math:`\text{EEOL}_{r,t,v,e}`", "emission_end_of_life", "emission_end_of_life", "emissions associated with the retirement/end of life of capacity; end-of-life emissions" + +Limit & Constraint Parameters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. csv-table:: + :header: "Parameter", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + ":math:`\text{LC}_{r,p,t}`", "limit_capacity", "limit_capacity", "limit tech-specific capacity by period; capacity limits" + "", "limit_new_capacity", "limit_new_capacity", "new capacity limits" + ":math:`\text{LA}_{r,p,t}`", "limit_activity", "limit_activity", "limit tech-specific activity by region and period; activity limits" + ":math:`\text{LE}_{r,p,e}`", "limit_emission", "limit_emission", "limit emissions by region and period; emission limits" + ":math:`\text{LR}_{r,t}`", "limit_resource", "limit_resource", "limit resource production by tech across time periods; resource extraction limits" + "", "limit_growth_capacity", "limit_growth_capacity", "capacity growth rate" + "", "limit_degrowth_capacity", "limit_degrowth_capacity", "capacity degrowth rate" + "", "limit_growth_new_capacity", "limit_growth_new_capacity", "new capacity growth rate" + "", "limit_degrowth_new_capacity", "limit_degrowth_new_capacity", "new capacity degrowth rate" + "", "limit_growth_new_capacity_delta", "limit_growth_new_capacity_delta", "new capacity growth delta" + "", "limit_degrowth_new_capacity_delta", "limit_degrowth_new_capacity_delta", "new capacity degrowth delta" + "", "limit_annual_capacity_factor", "limit_annual_capacity_factor", "annual capacity factor limits" + "", "limit_seasonal_capacity_factor", "limit_seasonal_capacity_factor", "seasonal capacity factor limits" + "", "limit_capacity_share", "limit_capacity_share", "capacity share limits" + "", "limit_activity_share", "limit_activity_share", "activity share limits" + "", "limit_new_capacity_share", "limit_new_capacity_share", "new capacity share limits" + ":math:`\text{TIS}_{r,i,t}`", "limit_tech_input_split", "limit_tech_input_split", "technology input fuel ratio at time slice level; tech input split constraints" + ":math:`\text{TISA}_{r,i,t}`", "limit_tech_input_split_annual", "limit_tech_input_split_annual", "average annual technology input fuel ratio; annual tech input splits" + ":math:`\text{TOS}_{r,t,o}`", "limit_tech_output_split", "limit_tech_output_split", "technology output fuel ratio at time slice level; tech output split constraints" + ":math:`\text{TISA}_{r,i,t}`", "limit_tech_output_split_annual", "limit_tech_output_split_annual", "average annual technology output fuel ratio; annual tech output splits" + ":math:`\text{LSF}_{r,p,s,d,t,v}`", "limit_storage_level_fraction", "limit_storage_fraction", "limit storage level in any time slice; storage level fraction limits" + +Storage Parameters +^^^^^^^^^^^^^^^^^^ + +.. csv-table:: + :header: "Parameter", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + ":math:`\text{SD}_{r,t}`", "storage_duration", "storage_duration", "storage duration per technology, specified in hours; storage duration in hours" + +Operations Parameters +^^^^^^^^^^^^^^^^^^^^^ + +.. csv-table:: + :header: "Parameter", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + ":math:`\text{RUH}_{r,t}`", "ramp_up_hourly", "ramp_up_hourly", "hourly rate at which generation techs can ramp output up; hourly ramp-up rates" + ":math:`\text{RDH}_{r,t}`", "ramp_down_hourly", "ramp_down_hourly", "hourly rate at which generation techs can ramp output down; hourly ramp-down rates" + +Reserve Margin Parameters +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. csv-table:: + :header: "Parameter", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + ":math:`\text{PRM}_{r}`", "planning_reserve_margin", "planning_reserve_margin", "margin used to ensure sufficient generating capacity; planning reserve margin" + "", "reserve_capacity_derate", "reserve_capacity_derate", "reserve capacity derate" + +Policy Parameters +^^^^^^^^^^^^^^^^^ + +.. csv-table:: + :header: "Parameter", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + "", "rps_requirement", "renewable_portfolio_standard", "RPS requirements" + ":math:`\text{LIT}_{r,t,e,t}`", "linked_tech", "linked_techs", "dummy techs used to convert CO2 emissions to physical commodity; linked technology specs" + +Construction & End-of-Life Parameters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. csv-table:: + :header: "Parameter", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + ":math:`\text{CON}_{r,i,t,v}`", "construction_input", "construction_input", "commodities consumed by creation of process capacity; construction input requirements" + ":math:`\text{EOLO}_{r,t,v,o}`", "end_of_life_output", "end_of_life_output", "commodities produced by retirement/end of life of capacity; end-of-life outputs" + +Computed Parameters (Model-Derived) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. csv-table:: + :header: "Parameter", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + ":math:`{}^*\text{LEN}_p`", "", "period_length", "number of years in period :math:`p`; computed from time periods" + "", "", "segment_fraction_per_season", "computed from segment fractions" + ":math:`{}^*\text{LA}_{t,v}`", "", "loan_annualize", "loan amortization by tech and vintage; based on :math:`DR_t`; computed from loan rate and lifetime" + ":math:`{}^*\text{PLF}_{r,p,t,v}`", "", "process_life_frac", "fraction of available process capacity by region and period; computed process life fraction" + + +Output Tables (Not in Model Input) +----------------------------------- + +These tables store optimization results and are not part of model input: + +- output_dual_variable +- output_objective +- output_curtailment +- output_net_capacity +- output_built_capacity +- output_retired_capacity +- output_flow_in +- output_flow_out +- output_flow_out_summary +- output_storage_level +- output_emission +- output_cost + + +Model-Only Elements (Not Directly from Database) +------------------------------------------------- + +Derived Sets +^^^^^^^^^^^^ + +.. csv-table:: + :header: "Set", "Model Element", "Notes" + :widths: 15, 25, 60 + + "", "tech_with_capacity", "technologies eligible for capacitization; computed as tech_all - tech_uncap" + "", "tech_or_group", "technologies or groups combined; union of tech_group_names | tech_all" + ":math:`{}^*\text{C}^c`", "commodity_carrier", "physical energy carriers and end-use demands; union of physical, demand, and waste commodities" + ":math:`{}^*\text{C}`", "commodity_all", "union of all commodity sets; union of carrier and emissions commodities" + ":math:`\text{T}^e`", "tech_exist", "technologies with existing capacity; derived from existing_capacity table" + +Internal Data Structures (Not Formal Model Elements) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +These are dictionaries and sets used internally during model construction: + +- process_inputs, process_outputs, process_loans +- active_flow_rpsditvo, active_flow_rpitvo +- Various vintage and operational tracking dictionaries +- Time sequencing dictionaries (time_next, time_next_sequential) + + +Database Tables Without Direct Model Mapping +--------------------------------------------- + +.. csv-table:: + :header: "Database Table", "Purpose", "Notes" + :widths: 30, 30, 40 + + "myopic_efficiency", "Myopic mode efficiency", "alternative efficiency for myopic optimization" + "time_manual", "Manual time sequencing", "hidden feature, rarely used" + "sector_label", "Sectoral classification", "used in output tables only" + + +Summary Statistics +------------------ + +- **Database Tables**: 73 total (63 input, 10 output) +- **Model Sets**: 101 total (37 core sets, 64 constraint index sets) +- **Model Parameters**: 60 total +- **Direct Mappings**: ~55 database tables map to model elements +- **Output-Only Tables**: 10 tables +- **Model-Derived Elements**: ~20 sets/parameters computed from database data diff --git a/docs/source/mathematical_formulation.rst b/docs/source/mathematical_formulation.rst index eb9e984bf..b0ac043e9 100644 --- a/docs/source/mathematical_formulation.rst +++ b/docs/source/mathematical_formulation.rst @@ -141,6 +141,9 @@ Conventions Sets ---- +.. include:: db_model_comparison.rst + + .. _table_set: .. csv-table:: List of all Temoa sets with which a modeler might interact. The From 2ce5dcda5bff5063a8039b6150e16460ba49ac66 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 18 Dec 2025 15:58:44 -0500 Subject: [PATCH 403/587] deduplicating testing databases by separating central schema from modifications --- temoa/tutorial_assets/utopia.sql | 2 +- tests/conftest.py | 124 +- .../config_annualised_demand.toml | 68 +- tests/testing_configs/config_emissions.toml | 60 +- tests/testing_configs/config_link_test.toml | 112 +- tests/testing_configs/config_materials.toml | 60 +- tests/testing_configs/config_mediumville.toml | 94 +- .../config_seasonal_storage.toml | 68 +- .../testing_configs/config_storageville.toml | 94 +- .../config_survival_curve.toml | 68 +- tests/testing_configs/config_test_system.toml | 60 +- tests/testing_configs/config_utopia.toml | 68 +- tests/testing_configs/config_utopia_gv.toml | 72 +- .../testing_configs/config_utopia_myopic.toml | 64 +- tests/testing_data/annualised_demand.sql | 1136 +-------- tests/testing_data/emissions.sql | 1234 +--------- tests/testing_data/materials.sql | 2034 ++++------------ tests/testing_data/mediumville.sql | 1422 ++--------- tests/testing_data/seasonal_storage.sql | 1249 +--------- tests/testing_data/simple_linked_tech.sql | 1152 +-------- tests/testing_data/storageville.sql | 1206 +--------- tests/testing_data/survival_curve.sql | 1396 ++--------- tests/testing_data/test_system.sql | 2140 +++++------------ tests/testing_data/utopia_data.sql | 559 +++++ 24 files changed, 2557 insertions(+), 11985 deletions(-) create mode 100644 tests/testing_data/utopia_data.sql diff --git a/temoa/tutorial_assets/utopia.sql b/temoa/tutorial_assets/utopia.sql index 41fe6dba8..24138883c 100644 --- a/temoa/tutorial_assets/utopia.sql +++ b/temoa/tutorial_assets/utopia.sql @@ -458,7 +458,7 @@ CREATE TABLE demand ); INSERT INTO "demand" VALUES('utopia',1990,'RH',25.2,'PJ',''); INSERT INTO "demand" VALUES('utopia',2000,'RH',37.8,'PJ',''); -INSERT INTO "demand" VALUES('utopia',2010,'RH',5.669999999999999574e+01,'PJ',''); +INSERT INTO "demand" VALUES('utopia',2010,'RH',56.7,'PJ',''); INSERT INTO "demand" VALUES('utopia',1990,'RL',5.6,'PJ',''); INSERT INTO "demand" VALUES('utopia',2000,'RL',8.4,'PJ',''); INSERT INTO "demand" VALUES('utopia',2010,'RL',12.6,'PJ',''); diff --git a/tests/conftest.py b/tests/conftest.py index 34f4de3ea..8b46ad776 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,4 @@ import logging -import os import sqlite3 from pathlib import Path from typing import Any @@ -34,83 +33,77 @@ logging.getLogger('pyutilib').setLevel(logging.WARNING) +# Central paths +TEST_DATA_PATH = Path(__file__).parent / 'testing_data' +TEST_OUTPUT_PATH = Path(__file__).parent / 'testing_outputs' +SCHEMA_PATH = Path(__file__).parent.parent / 'temoa' / 'db_schema' / 'temoa_schema_v4.sql' + + +def _build_test_db( + db_file: Path, + data_scripts: list[Path], + modifications: list[tuple[str, tuple[Any, ...]]] | None = None, +) -> None: + """Helper to build a test database from central schema + data scripts + mods.""" + if db_file.exists(): + db_file.unlink() + + with sqlite3.connect(db_file) as con: + con.execute('PRAGMA foreign_keys = OFF') + # 1. Load central schema + con.executescript(SCHEMA_PATH.read_text(encoding='utf-8')) + # Force FK OFF again as schema file might turn it on at the end + con.execute('PRAGMA foreign_keys = OFF') + + # 2. Load data scripts + for script_path in data_scripts: + with open(script_path) as f: + con.executescript(f.read()) + + # 3. Apply modifications + if modifications: + for sql, params in modifications: + con.execute(sql, params) + + # 4. Turn foreign keys back on + con.execute('PRAGMA foreign_keys = ON') + con.commit() + + def refresh_databases() -> None: """ make new databases from source for testing... removes possibility of contamination by earlier runs """ - data_output_path = Path(__file__).parent / 'testing_outputs' - data_source_path = Path(__file__).parent / 'testing_data' - # utopia.sql is in tutorial_assets (single source of truth for unit-compliant data) - tutorial_assets_path = Path(__file__).parent.parent / 'temoa' / 'tutorial_assets' - # Map source files to their locations - # (source_dir, source_file, output_file) databases = [ - # Utopia uses the tutorial_assets source (unit-compliant) - (tutorial_assets_path, 'utopia.sql', 'utopia.sqlite'), - (tutorial_assets_path, 'utopia.sql', 'myo_utopia.sqlite'), - # Other test databases use testing_data - (data_source_path, 'test_system.sql', 'test_system.sqlite'), - (data_source_path, 'storageville.sql', 'storageville.sqlite'), - (data_source_path, 'mediumville.sql', 'mediumville.sqlite'), - (data_source_path, 'emissions.sql', 'emissions.sqlite'), - (data_source_path, 'materials.sql', 'materials.sqlite'), - (data_source_path, 'simple_linked_tech.sql', 'simple_linked_tech.sqlite'), - (data_source_path, 'seasonal_storage.sql', 'seasonal_storage.sqlite'), - (data_source_path, 'survival_curve.sql', 'survival_curve.sqlite'), - (data_source_path, 'annualised_demand.sql', 'annualised_demand.sqlite'), + # Utopia uses the unit-compliant data-only script + ('utopia_data.sql', 'utopia.sqlite'), + ('utopia_data.sql', 'myo_utopia.sqlite'), + # Other test databases + ('test_system.sql', 'test_system.sqlite'), + ('mediumville.sql', 'mediumville.sqlite'), + ('seasonal_storage.sql', 'seasonal_storage.sqlite'), + ('survival_curve.sql', 'survival_curve.sqlite'), + ('annualised_demand.sql', 'annualised_demand.sqlite'), + # Feature tests (separate for temporal consistency) + ('emissions.sql', 'emissions.sqlite'), + ('materials.sql', 'materials.sqlite'), + ('simple_linked_tech.sql', 'simple_linked_tech.sqlite'), + ('storageville.sql', 'storageville.sqlite'), ] - for source_dir, src, db in databases: - if Path.exists(data_output_path / db): - os.remove(data_output_path / db) - # make a new one and fill it - con = sqlite3.connect(data_output_path / db) - with open(source_dir / src) as script: - con.executescript(script.read()) - con.close() - - -def create_unit_test_db_from_sql( - source_sql_path: Path, output_db_path: Path, modifications: list[tuple[str, tuple[Any, ...]]] -) -> None: - """Create a unit test database from SQL source with specific modifications. - - Args: - source_sql_path: Path to the source SQL file - output_db_path: Path where the database should be created - modifications: List of (sql, params) tuples to apply after creation - """ - if output_db_path.exists(): - output_db_path.unlink() - - # Generate database from SQL source and apply modifications - with sqlite3.connect(output_db_path) as conn: - # Execute the SQL source to create the database - conn.executescript(source_sql_path.read_text(encoding='utf-8')) - # Apply modifications - for sql, params in modifications: - conn.execute(sql, params) - conn.commit() + for src, db in databases: + _build_test_db(TEST_OUTPUT_PATH / db, [TEST_DATA_PATH / src]) def create_unit_test_dbs() -> None: """Create unit test databases from SQL source for unit checking tests. - Generates databases from the single SQL source of truth (tutorial_assets/utopia.sql), + Generates databases from the single SQL source of truth (utopia_data.sql), applying modifications for each test case. """ - test_output_dir = Path(__file__).parent / 'testing_outputs' - test_output_dir.mkdir(exist_ok=True) - - # Source SQL file path (single source of truth) - source_sql = Path(__file__).parent.parent / 'temoa' / 'tutorial_assets' / 'utopia.sql' - - if not source_sql.exists(): - raise FileNotFoundError( - f'Source SQL not found at: {source_sql}. Please ensure the Utopia tutorial SQL exists.' - ) + TEST_OUTPUT_PATH.mkdir(exist_ok=True) # Define unit test variations with their modifications unit_test_variations = [ @@ -169,8 +162,11 @@ def create_unit_test_dbs() -> None: ] for db_name, modifications in unit_test_variations: - output_path = test_output_dir / db_name - create_unit_test_db_from_sql(source_sql, output_path, modifications) + _build_test_db( + TEST_OUTPUT_PATH / db_name, + [TEST_DATA_PATH / 'utopia_data.sql'], + modifications, + ) logger.info('Created unit test DB: %s', db_name) diff --git a/tests/testing_configs/config_annualised_demand.toml b/tests/testing_configs/config_annualised_demand.toml index 9506d7b11..3e6393fe5 100644 --- a/tests/testing_configs/config_annualised_demand.toml +++ b/tests/testing_configs/config_annualised_demand.toml @@ -1,73 +1,21 @@ -# this config is used for testing in test_full_runs.py scenario = "test run" scenario_mode = "perfect_foresight" - input_database = "tests/testing_outputs/annualised_demand.sqlite" output_database = "tests/testing_outputs/annualised_demand.sqlite" neos = false - -# solver solver_name = "appsi_highs" - -# generate an excel file in the output_files folder save_excel = false - -# save the duals in the output .sqlite database save_duals = false - -# save a copy of the pyomo-generated lp file to the outputs folder (may be large file!) save_lp_file = false +time_sequencing = "representative_periods" +reserve_margin = "static" -# ------------------------------------ -# MODEL PARAMETERS -# these are specific to each model -# ------------------------------------ - -# What seasons represent in the model -# Options: -# 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples -# might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. -# 'representative_periods' -# Each season represents a number of days, though not necessarily in any particular order. -# If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in -# the technology table. -# 'seasonal_timeslices' -# Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# time_season_sequential table can be left empty. Seasonal storage must still be tagged. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out -# in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the time_season_sequential table filled. -time_sequencing = 'representative_periods' - -# How contributions to the planning reserve margin are calculated -# Options: -# 'static' -# Traditional planning reserve formulation. Contributions are independent of hourly availability: -# capacity value = net capacity * capacity credit -# 'dynamic' -# Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = net capacity * reserve capacity derate * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * reserve capacity derate -reserve_margin = 'static' - -# --------------------------------------------------- -# MODE OPTIONS -# options below are mode-specific and will be ignored -# if the run is not executed in that mode. -# --------------------------------------------------- [MGA] -cost_epsilon = 0.03 # 3% relaxation on optimal cost -iteration_limit = 15 # max iterations to perform -time_limit_hrs = 1 # max time -axis = "tech_category_activity" # use the tech activity Manager to control exploration based on categories in Tech -weighting = "hull_expansion" # use a convex hull expansion algorithm to weight exploration +cost_epsilon = 0.03 +iteration_limit = 15 +time_limit_hrs = 1 +axis = "tech_category_activity" +weighting = "hull_expansion" [myopic] -myopic_view = 2 # number of periods seen at one iteration +myopic_view = 2 diff --git a/tests/testing_configs/config_emissions.toml b/tests/testing_configs/config_emissions.toml index c131806cf..f06f424da 100644 --- a/tests/testing_configs/config_emissions.toml +++ b/tests/testing_configs/config_emissions.toml @@ -1,71 +1,19 @@ -# this config is used for testing in test_full_runs.py scenario = "test run" scenario_mode = "perfect_foresight" - input_database = "tests/testing_outputs/emissions.sqlite" output_database = "tests/testing_outputs/emissions.sqlite" neos = false - -# solver solver_name = "appsi_highs" - -# generate an excel file in the output_files folder save_excel = false - -# save the duals in the output .sqlite database save_duals = false - -# save a copy of the pyomo-generated lp file to the outputs folder (may be large file!) save_lp_file = false +time_sequencing = "seasonal_timeslices" +reserve_margin = "static" -# ------------------------------------ -# MODEL PARAMETERS -# these are specific to each model -# ------------------------------------ - -# What seasons represent in the model -# Options: -# 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples -# might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. -# 'representative_periods' -# Each season represents a number of days, though not necessarily in any particular order. -# If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in -# the technology table. -# 'seasonal_timeslices' -# Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# time_season_sequential table can be left empty. Seasonal storage must still be tagged. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out -# in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the time_season_sequential table filled. -time_sequencing = 'seasonal_timeslices' - -# How contributions to the planning reserve margin are calculated -# Options: -# 'static' -# Traditional planning reserve formulation. Contributions are independent of hourly availability: -# capacity value = net capacity * capacity credit -# 'dynamic' -# Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = net capacity * reserve capacity derate * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * reserve capacity derate -reserve_margin = 'static' - -# --------------------------------------------------- -# MODE OPTIONS -# options below are mode-specific and will be ignored -# if the run is not executed in that mode. -# --------------------------------------------------- [MGA] slack = 0.1 iterations = 4 -weight = "integer" # currently supported: [integer, normalized] +weight = "integer" [myopic] -myopic_view = 2 # number of periods seen at one iteration +myopic_view = 2 diff --git a/tests/testing_configs/config_link_test.toml b/tests/testing_configs/config_link_test.toml index 0a3783179..ff8bab418 100644 --- a/tests/testing_configs/config_link_test.toml +++ b/tests/testing_configs/config_link_test.toml @@ -1,125 +1,23 @@ -# ---------------------------------------------------------- -# Configuration file for a Temoa Run -# Allows specification of run type and associated parameters -# ---------------------------------------------------------- -# -# For toml format info see: https://toml.io/en/ -# - comments may be added with hash -# - do NOT comment out table names in brackets like: [
] - -# Scenario Name (Mandatory) -# This scenario name is used to label results within the output .sqlite file scenario = "test_linked_tech" - -# Scenaio Mode (Mandatory) -# See documentation for explanations. A standard single run is "perfect_foresight" -# mode must be one of (case-insensitive): -# [perfect_foresight, MGA, myopic, method_of_morris, build_only, check] scenario_mode = "perfect_foresight" - -# Input database (Mandatory) input_database = "tests/testing_outputs/simple_linked_tech.sqlite" - -# Output file (Mandatory) -# The output file must be an existing .sqlite file -# For Pefrect Foresight, the user may target the same input file or a separate / -# copied sqlite file in a different location. Myopic requires that input_database = output_database output_database = "tests/testing_outputs/simple_linked_tech.sqlite" - -# ------------------------------------ -# DATA / MODEL CHECKS -# To check data / cost integrity -# ------------------------------------ - -# Check the pricing structure for common errors, which are reported in the log file -# Strongly recommended price_check = false - -# Check the network connectivity for processes in the model. Strongly -# recommended to ensure proper performance. Results are reported in log file -# This requires that source commodities be marked with 's' in commodity table -# This is required for Myopic runs source_trace = true - -# Produce HTML files for Commodity Networks. Requires source_trace above plot_commodity_network = false - -# ------------------------------------ -# SOLVER -# Solver Selection -# ------------------------------------ - -# use the NEOS server to solve. (Currently NOT supported) neos = false - -# solver (Mandatory) -# Depending on what client machine has installed. -# [cbc, appsi_highs, gurobi, cplex, ...] solver_name = "appsi_highs" - -# ------------------------------------ -# OUTPUTS -# select desired output products/files -# ------------------------------------ - -# generate an Excel file in the output_files folder save_excel = false - -# save the duals in the output Database (may slow execution slightly?) save_duals = false - -# save a copy of the pyomo-generated lp file(s) to the outputs folder (maybe a large file(s)!) save_lp_file = false +time_sequencing = "seasonal_timeslices" +reserve_margin = "static" -# ------------------------------------ -# MODEL PARAMETERS -# these are specific to each model -# ------------------------------------ - -# What seasons represent in the model -# Options: -# 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples -# might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. -# 'representative_periods' -# Each season represents a number of days, though not necessarily in any particular order. -# If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in -# the technology table. -# 'seasonal_timeslices' -# Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# time_season_sequential table can be left empty. Seasonal storage must still be tagged. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out -# in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the time_season_sequential table filled. -time_sequencing = 'seasonal_timeslices' - -# How contributions to the planning reserve margin are calculated -# Options: -# 'static' -# Traditional planning reserve formulation. Contributions are independent of hourly availability: -# capacity value = net capacity * capacity credit -# 'dynamic' -# Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = net capacity * reserve capacity derate * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * reserve capacity derate -reserve_margin = 'static' - -# --------------------------------------------------- -# MODE OPTIONS -# options below are mode-specific and will be ignored -# if the run is not executed in that mode. -# --------------------------------------------------- [MGA] slack = 0.1 iterations = 4 -weight = "integer" # currently supported: [integer, normalized] +weight = "integer" [myopic] -view_depth = 2 # number of periods seen/analyzed per iteration -step_size = 1 # number of periods to step by (must be <= view depth) +view_depth = 2 +step_size = 1 diff --git a/tests/testing_configs/config_materials.toml b/tests/testing_configs/config_materials.toml index b70404fea..81bb00f00 100644 --- a/tests/testing_configs/config_materials.toml +++ b/tests/testing_configs/config_materials.toml @@ -1,71 +1,19 @@ -# this config is used for testing in test_full_runs.py scenario = "test run" scenario_mode = "perfect_foresight" - input_database = "tests/testing_outputs/materials.sqlite" output_database = "tests/testing_outputs/materials.sqlite" neos = false - -# solver solver_name = "appsi_highs" - -# generate an excel file in the output_files folder save_excel = false - -# save the duals in the output .sqlite database save_duals = false - -# save a copy of the pyomo-generated lp file to the outputs folder (may be large file!) save_lp_file = false +time_sequencing = "seasonal_timeslices" +reserve_margin = "static" -# ------------------------------------ -# MODEL PARAMETERS -# these are specific to each model -# ------------------------------------ - -# What seasons represent in the model -# Options: -# 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples -# might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. -# 'representative_periods' -# Each season represents a number of days, though not necessarily in any particular order. -# If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in -# the technology table. -# 'seasonal_timeslices' -# Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# time_season_sequential table can be left empty. Seasonal storage must still be tagged. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out -# in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the time_season_sequential table filled. -time_sequencing = 'seasonal_timeslices' - -# How contributions to the planning reserve margin are calculated -# Options: -# 'static' -# Traditional planning reserve formulation. Contributions are independent of hourly availability: -# capacity value = net capacity * capacity credit -# 'dynamic' -# Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = net capacity * reserve capacity derate * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * reserve capacity derate -reserve_margin = 'static' - -# --------------------------------------------------- -# MODE OPTIONS -# options below are mode-specific and will be ignored -# if the run is not executed in that mode. -# --------------------------------------------------- [MGA] slack = 0.1 iterations = 4 -weight = "integer" # currently supported: [integer, normalized] +weight = "integer" [myopic] -myopic_view = 2 # number of periods seen at one iteration +myopic_view = 2 diff --git a/tests/testing_configs/config_mediumville.toml b/tests/testing_configs/config_mediumville.toml index 0376832ec..53f1b935d 100644 --- a/tests/testing_configs/config_mediumville.toml +++ b/tests/testing_configs/config_mediumville.toml @@ -1,105 +1,19 @@ -# ---------------------------------------------------------- -# Configuration file for a Temoa Run -# Allows specification of run type and associated parameters -# -# For toml format info see: https://toml.io/en/ -# - comments may be added with hash -# - do NOT comment out table names in brackets like: [
] - -# Scenario Name (Mandatory) -# This scenario name is used to label results within the output .sqlite file scenario = "testing" - -# Scenaio Mode (Mandatory) -# See documentation for explanations. A standard single run is "perfect foresight" -# mode must be one of (case-insensitive): -# [perfect_foresight, MGA, myopic, method_of_morris, build_only] scenario_mode = "perfect_foresight" - -# Input file (Mandatory) -# Input can be a .sqlite or .dat file -# Both relative path and absolute path are accepted input_database = "tests/testing_outputs/mediumville.sqlite" - -# Output file (Mandatory) -# The output file must be an existing .sqlite file -# the user may target the same input file or a separate / -# copied sqlite file in a different location output_database = "tests/testing_outputs/mediumville.sqlite" - -# ------------------------------------ -# SOLVER -# Solver Selection -# ------------------------------------ - -# use the NEOS server to solve neos = false - -# solver solver_name = "appsi_highs" - -# ------------------------------------ -# OUTPUTS -# select desired output products/files -# ------------------------------------ - -# generate an Excel file in the output_files folder save_excel = false - -# save the duals in the output .sqlite database save_duals = false - -# save a copy of the pyomo-generated lp file to the outputs folder (may be large file!) save_lp_file = false +time_sequencing = "seasonal_timeslices" +reserve_margin = "static" -# ------------------------------------ -# MODEL PARAMETERS -# these are specific to each model -# ------------------------------------ - -# What seasons represent in the model -# Options: -# 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples -# might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. -# 'representative_periods' -# Each season represents a number of days, though not necessarily in any particular order. -# If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in -# the technology table. -# 'seasonal_timeslices' -# Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# time_season_sequential table can be left empty. Seasonal storage must still be tagged. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out -# in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the time_season_sequential table filled. -time_sequencing = 'seasonal_timeslices' - -# How contributions to the planning reserve margin are calculated -# Options: -# 'static' -# Traditional planning reserve formulation. Contributions are independent of hourly availability: -# capacity value = net capacity * capacity credit -# 'dynamic' -# Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = net capacity * reserve capacity derate * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * reserve capacity derate -reserve_margin = 'static' - -# --------------------------------------------------- -# MODE OPTIONS -# options below are mode-specific and will be ignored -# if the run is not executed in that mode. -# --------------------------------------------------- [MGA] slack = 0.1 iterations = 4 -weight = "integer" # currently supported: [integer, normalized] +weight = "integer" [myopic] -myopic_view = 2 # number of periods seen at one iteration +myopic_view = 2 diff --git a/tests/testing_configs/config_seasonal_storage.toml b/tests/testing_configs/config_seasonal_storage.toml index fa7fac063..760a7b88e 100644 --- a/tests/testing_configs/config_seasonal_storage.toml +++ b/tests/testing_configs/config_seasonal_storage.toml @@ -1,73 +1,21 @@ -# this config is used for testing in test_full_runs.py scenario = "test run" scenario_mode = "perfect_foresight" - input_database = "tests/testing_outputs/seasonal_storage.sqlite" output_database = "tests/testing_outputs/seasonal_storage.sqlite" neos = false - -# solver solver_name = "appsi_highs" - -# generate an excel file in the output_files folder save_excel = false - -# save the duals in the output .sqlite database save_duals = false - -# save a copy of the pyomo-generated lp file to the outputs folder (may be large file!) save_lp_file = false +time_sequencing = "representative_periods" +reserve_margin = "static" -# ------------------------------------ -# MODEL PARAMETERS -# these are specific to each model -# ------------------------------------ - -# What seasons represent in the model -# Options: -# 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples -# might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. -# 'representative_periods' -# Each season represents a number of days, though not necessarily in any particular order. -# If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in -# the technology table. -# 'seasonal_timeslices' -# Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# time_season_sequential table can be left empty. Seasonal storage must still be tagged. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out -# in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the time_season_sequential table filled. -time_sequencing = 'representative_periods' - -# How contributions to the planning reserve margin are calculated -# Options: -# 'static' -# Traditional planning reserve formulation. Contributions are independent of hourly availability: -# capacity value = net capacity * capacity credit -# 'dynamic' -# Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = net capacity * reserve capacity derate * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * reserve capacity derate -reserve_margin = 'static' - -# --------------------------------------------------- -# MODE OPTIONS -# options below are mode-specific and will be ignored -# if the run is not executed in that mode. -# --------------------------------------------------- [MGA] -cost_epsilon = 0.03 # 3% relaxation on optimal cost -iteration_limit = 15 # max iterations to perform -time_limit_hrs = 1 # max time -axis = "tech_category_activity" # use the tech activity Manager to control exploration based on categories in Tech -weighting = "hull_expansion" # use a convex hull expansion algorithm to weight exploration +cost_epsilon = 0.03 +iteration_limit = 15 +time_limit_hrs = 1 +axis = "tech_category_activity" +weighting = "hull_expansion" [myopic] -myopic_view = 2 # number of periods seen at one iteration +myopic_view = 2 diff --git a/tests/testing_configs/config_storageville.toml b/tests/testing_configs/config_storageville.toml index fe96195f6..df73dad14 100644 --- a/tests/testing_configs/config_storageville.toml +++ b/tests/testing_configs/config_storageville.toml @@ -1,105 +1,19 @@ -# ---------------------------------------------------------- -# Configuration file for a Temoa Run -# Allows specification of run type and associated parameters -# -# For toml format info see: https://toml.io/en/ -# - comments may be added with hash -# - do NOT comment out table names in brackets like: [
] - -# Scenario Name (Mandatory) -# This scenario name is used to label results within the output .sqlite file scenario = "storage testing" - -# Scenaio Mode (Mandatory) -# See documentation for explanations. A standard single run is "perfect foresight" -# mode must be one of (case-insensitive): -# [perfect_foresight, MGA, myopic, method_of_morris, build_only] scenario_mode = "perfect_foresight" - -# Input file (Mandatory) -# Input can be a .sqlite or .dat file -# Both relative path and absolute path are accepted input_database = "tests/testing_outputs/storageville.sqlite" - -# Output file (Mandatory) -# The output file must be an existing .sqlite file -# the user may target the same input file or a separate / -# copied sqlite file in a different location output_database = "tests/testing_outputs/storageville.sqlite" - -# ------------------------------------ -# SOLVER -# Solver Selection -# ------------------------------------ - -# use the NEOS server to solve neos = false - -# solver solver_name = "appsi_highs" - -# ------------------------------------ -# OUTPUTS -# select desired output products/files -# ------------------------------------ - -# generate an Excel file in the output_files folder save_excel = false - -# save the duals in the output .sqlite database save_duals = false - -# save a copy of the pyomo-generated lp file to the outputs folder (may be large file!) save_lp_file = false +time_sequencing = "seasonal_timeslices" +reserve_margin = "static" -# ------------------------------------ -# MODEL PARAMETERS -# these are specific to each model -# ------------------------------------ - -# What seasons represent in the model -# Options: -# 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples -# might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. -# 'representative_periods' -# Each season represents a number of days, though not necessarily in any particular order. -# If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in -# the technology table. -# 'seasonal_timeslices' -# Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# time_season_sequential table can be left empty. Seasonal storage must still be tagged. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out -# in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the time_season_sequential table filled. -time_sequencing = 'seasonal_timeslices' - -# How contributions to the planning reserve margin are calculated -# Options: -# 'static' -# Traditional planning reserve formulation. Contributions are independent of hourly availability: -# capacity value = net capacity * capacity credit -# 'dynamic' -# Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = net capacity * reserve capacity derate * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * reserve capacity derate -reserve_margin = 'static' - -# --------------------------------------------------- -# MODE OPTIONS -# options below are mode-specific and will be ignored -# if the run is not executed in that mode. -# --------------------------------------------------- [MGA] slack = 0.1 iterations = 4 -weight = "integer" # currently supported: [integer, normalized] +weight = "integer" [myopic] -myopic_view = 2 # number of periods seen at one iteration +myopic_view = 2 diff --git a/tests/testing_configs/config_survival_curve.toml b/tests/testing_configs/config_survival_curve.toml index c59abb9c6..2c1d051e2 100644 --- a/tests/testing_configs/config_survival_curve.toml +++ b/tests/testing_configs/config_survival_curve.toml @@ -1,73 +1,21 @@ -# this config is used for testing in test_full_runs.py scenario = "test run" scenario_mode = "perfect_foresight" - input_database = "tests/testing_outputs/survival_curve.sqlite" output_database = "tests/testing_outputs/survival_curve.sqlite" neos = false - -# solver solver_name = "appsi_highs" - -# generate an excel file in the output_files folder save_excel = false - -# save the duals in the output .sqlite database save_duals = false - -# save a copy of the pyomo-generated lp file to the outputs folder (may be large file!) save_lp_file = false +time_sequencing = "seasonal_timeslices" +reserve_margin = "static" -# ------------------------------------ -# MODEL PARAMETERS -# these are specific to each model -# ------------------------------------ - -# What seasons represent in the model -# Options: -# 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples -# might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. -# 'representative_periods' -# Each season represents a number of days, though not necessarily in any particular order. -# If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in -# the technology table. -# 'seasonal_timeslices' -# Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# time_season_sequential table can be left empty. Seasonal storage must still be tagged. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out -# in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the time_season_sequential table filled. -time_sequencing = 'seasonal_timeslices' - -# How contributions to the planning reserve margin are calculated -# Options: -# 'static' -# Traditional planning reserve formulation. Contributions are independent of hourly availability: -# capacity value = net capacity * capacity credit -# 'dynamic' -# Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = net capacity * reserve capacity derate * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * reserve capacity derate -reserve_margin = 'static' - -# --------------------------------------------------- -# MODE OPTIONS -# options below are mode-specific and will be ignored -# if the run is not executed in that mode. -# --------------------------------------------------- [MGA] -cost_epsilon = 0.03 # 3% relaxation on optimal cost -iteration_limit = 15 # max iterations to perform -time_limit_hrs = 1 # max time -axis = "tech_category_activity" # use the tech activity Manager to control exploration based on categories in Tech -weighting = "hull_expansion" # use a convex hull expansion algorithm to weight exploration +cost_epsilon = 0.03 +iteration_limit = 15 +time_limit_hrs = 1 +axis = "tech_category_activity" +weighting = "hull_expansion" [myopic] -myopic_view = 2 # number of periods seen at one iteration +myopic_view = 2 diff --git a/tests/testing_configs/config_test_system.toml b/tests/testing_configs/config_test_system.toml index d65c627f1..b776c317d 100644 --- a/tests/testing_configs/config_test_system.toml +++ b/tests/testing_configs/config_test_system.toml @@ -1,71 +1,19 @@ -# this config is used for testing in test_full_runs.py scenario = "test run" scenario_mode = "perfect_foresight" - input_database = "tests/testing_outputs/test_system.sqlite" output_database = "tests/testing_outputs/test_system.sqlite" neos = false - -# solver solver_name = "appsi_highs" - -# generate an excel file in the output_files folder save_excel = false - -# save the duals in the output .sqlite database save_duals = false - -# save a copy of the pyomo-generated lp file to the outputs folder (may be large file!) save_lp_file = false +time_sequencing = "seasonal_timeslices" +reserve_margin = "static" -# ------------------------------------ -# MODEL PARAMETERS -# these are specific to each model -# ------------------------------------ - -# What seasons represent in the model -# Options: -# 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples -# might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. -# 'representative_periods' -# Each season represents a number of days, though not necessarily in any particular order. -# If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in -# the technology table. -# 'seasonal_timeslices' -# Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# time_season_sequential table can be left empty. Seasonal storage must still be tagged. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out -# in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the time_season_sequential table filled. -time_sequencing = 'seasonal_timeslices' - -# How contributions to the planning reserve margin are calculated -# Options: -# 'static' -# Traditional planning reserve formulation. Contributions are independent of hourly availability: -# capacity value = net capacity * capacity credit -# 'dynamic' -# Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = net capacity * reserve capacity derate * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * reserve capacity derate -reserve_margin = 'static' - -# --------------------------------------------------- -# MODE OPTIONS -# options below are mode-specific and will be ignored -# if the run is not executed in that mode. -# --------------------------------------------------- [MGA] slack = 0.1 iterations = 4 -weight = "integer" # currently supported: [integer, normalized] +weight = "integer" [myopic] -myopic_view = 2 # number of periods seen at one iteration +myopic_view = 2 diff --git a/tests/testing_configs/config_utopia.toml b/tests/testing_configs/config_utopia.toml index 90ba74908..e13262f29 100644 --- a/tests/testing_configs/config_utopia.toml +++ b/tests/testing_configs/config_utopia.toml @@ -1,73 +1,21 @@ -# this config is used for testing in test_full_runs.py scenario = "test run" scenario_mode = "perfect_foresight" - input_database = "tests/testing_outputs/utopia.sqlite" output_database = "tests/testing_outputs/utopia.sqlite" neos = false - -# solver solver_name = "appsi_highs" - -# generate an excel file in the output_files folder save_excel = false - -# save the duals in the output .sqlite database save_duals = false - -# save a copy of the pyomo-generated lp file to the outputs folder (may be large file!) save_lp_file = false +time_sequencing = "seasonal_timeslices" +reserve_margin = "static" -# ------------------------------------ -# MODEL PARAMETERS -# these are specific to each model -# ------------------------------------ - -# What seasons represent in the model -# Options: -# 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples -# might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. -# 'representative_periods' -# Each season represents a number of days, though not necessarily in any particular order. -# If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in -# the technology table. -# 'seasonal_timeslices' -# Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# time_season_sequential table can be left empty. Seasonal storage must still be tagged. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out -# in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the time_season_sequential table filled. -time_sequencing = 'seasonal_timeslices' - -# How contributions to the planning reserve margin are calculated -# Options: -# 'static' -# Traditional planning reserve formulation. Contributions are independent of hourly availability: -# capacity value = net capacity * capacity credit -# 'dynamic' -# Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = net capacity * reserve capacity derate * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * reserve capacity derate -reserve_margin = 'static' - -# --------------------------------------------------- -# MODE OPTIONS -# options below are mode-specific and will be ignored -# if the run is not executed in that mode. -# --------------------------------------------------- [MGA] -cost_epsilon = 0.03 # 3% relaxation on optimal cost -iteration_limit = 15 # max iterations to perform -time_limit_hrs = 1 # max time -axis = "tech_category_activity" # use the tech activity Manager to control exploration based on categories in Tech -weighting = "hull_expansion" # use a convex hull expansion algorithm to weight exploration +cost_epsilon = 0.03 +iteration_limit = 15 +time_limit_hrs = 1 +axis = "tech_category_activity" +weighting = "hull_expansion" [myopic] -myopic_view = 2 # number of periods seen at one iteration +myopic_view = 2 diff --git a/tests/testing_configs/config_utopia_gv.toml b/tests/testing_configs/config_utopia_gv.toml index 54e048673..4112427de 100644 --- a/tests/testing_configs/config_utopia_gv.toml +++ b/tests/testing_configs/config_utopia_gv.toml @@ -1,78 +1,22 @@ -# this config is used for testing in test_full_runs.py scenario = "test run" scenario_mode = "perfect_foresight" - input_database = "tests/testing_outputs/utopia.sqlite" output_database = "tests/testing_outputs/utopia.sqlite" neos = false - -# solver solver_name = "appsi_highs" - -# generate an excel file in the output_files folder save_excel = false - -# save the duals in the output .sqlite database save_duals = false - -# save a copy of the pyomo-generated lp file to the outputs folder (may be large file!) save_lp_file = false - -# ------------------------------------ -# MODEL PARAMETERS -# these are specific to each model -# ------------------------------------ - -# What seasons represent in the model -# Options: -# 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples -# might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. -# 'representative_periods' -# Each season represents a number of days, though not necessarily in any particular order. -# If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in -# the technology table. -# 'seasonal_timeslices' -# Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# time_season_sequential table can be left empty. Seasonal storage must still be tagged. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out -# in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the time_season_sequential table filled. -time_sequencing = 'seasonal_timeslices' - -# How contributions to the planning reserve margin are calculated -# Options: -# 'static' -# Traditional planning reserve formulation. Contributions are independent of hourly availability: -# capacity value = net capacity * capacity credit -# 'dynamic' -# Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = net capacity * reserve capacity derate * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * reserve capacity derate -reserve_margin = 'static' - -# --------------------------------------------------- -# OUTPUT OPTIONS -# --------------------------------------------------- +time_sequencing = "seasonal_timeslices" +reserve_margin = "static" graphviz_output = true -# --------------------------------------------------- -# MODE OPTIONS -# options below are mode-specific and will be ignored -# if the run is not executed in that mode. -# --------------------------------------------------- [MGA] -cost_epsilon = 0.03 # 3% relaxation on optimal cost -iteration_limit = 15 # max iterations to perform -time_limit_hrs = 1 # max time -axis = "tech_category_activity" # use the tech activity Manager to control exploration based on categories in Tech -weighting = "hull_expansion" # use a convex hull expansion algorithm to weight exploration +cost_epsilon = 0.03 +iteration_limit = 15 +time_limit_hrs = 1 +axis = "tech_category_activity" +weighting = "hull_expansion" [myopic] -myopic_view = 2 # number of periods seen at one iteration +myopic_view = 2 diff --git a/tests/testing_configs/config_utopia_myopic.toml b/tests/testing_configs/config_utopia_myopic.toml index e5f0f1fe8..bbfff7863 100644 --- a/tests/testing_configs/config_utopia_myopic.toml +++ b/tests/testing_configs/config_utopia_myopic.toml @@ -1,74 +1,20 @@ -# this config is used for testing in test_full_runs.py scenario = "test myopic" scenario_mode = "myopic" - -# note that myopic currently only supports input = output. Test code will be responsible -# for making a fresh copy (if desired) and moving it to the output folder input_database = "tests/testing_outputs/myo_utopia.sqlite" output_database = "tests/testing_outputs/myo_utopia.sqlite" neos = false - -# solver solver_name = "appsi_highs" - -# generate an excel file in the output_files folder save_excel = true - -# save the duals in the output .sqlite database save_duals = true - -# save a copy of the pyomo-generated lp file to the outputs folder (may be large file!) save_lp_file = false +time_sequencing = "seasonal_timeslices" +reserve_margin = "static" -# ------------------------------------ -# MODEL PARAMETERS -# these are specific to each model -# ------------------------------------ - -# What seasons represent in the model -# Options: -# 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples -# might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the time_season_sequential table can be left empty. -# 'representative_periods' -# Each season represents a number of days, though not necessarily in any particular order. -# If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the time_season_sequential table. Seasonal storage must also be tagged in -# the technology table. -# 'seasonal_timeslices' -# Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# time_season_sequential table can be left empty. Seasonal storage must still be tagged. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out -# in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the time_season_sequential table filled. -time_sequencing = 'seasonal_timeslices' - -# How contributions to the planning reserve margin are calculated -# Options: -# 'static' -# Traditional planning reserve formulation. Contributions are independent of hourly availability: -# capacity value = net capacity * capacity credit -# 'dynamic' -# Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = net capacity * reserve capacity derate * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * reserve capacity derate -reserve_margin = 'static' - -# --------------------------------------------------- -# MODE OPTIONS -# options below are mode-specific and will be ignored -# if the run is not executed in that mode. -# --------------------------------------------------- [MGA] slack = 0.1 iterations = 4 -weight = "integer" # currently supported: [integer, normalized] +weight = "integer" [myopic] -view_depth = 2 # number of periods seen/analyzed per iteration -step_size = 1 # number of periods to step by +view_depth = 2 +step_size = 1 diff --git a/tests/testing_data/annualised_demand.sql b/tests/testing_data/annualised_demand.sql index aa6947474..a69b0e57a 100644 --- a/tests/testing_data/annualised_demand.sql +++ b/tests/testing_data/annualised_demand.sql @@ -1,1081 +1,55 @@ -BEGIN TRANSACTION; -CREATE TABLE capacity_credit -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -CREATE TABLE capacity_factor_process -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE capacity_factor_tech -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE capacity_to_activity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES commodity_type (label), - description TEXT -); -INSERT INTO "commodity" VALUES('source','s',NULL); -INSERT INTO "commodity" VALUES('annual','a',NULL); -INSERT INTO "commodity" VALUES('physical','p',NULL); -INSERT INTO "commodity" VALUES('demand','d',NULL); -CREATE TABLE commodity_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "commodity_type" VALUES('s','source commodity'); -INSERT INTO "commodity_type" VALUES('a','annual commodity'); -INSERT INTO "commodity_type" VALUES('p','physical commodity'); -INSERT INTO "commodity_type" VALUES('d','demand commodity'); -INSERT INTO "commodity_type" VALUES('e','emissions commodity'); -INSERT INTO "commodity_type" VALUES('w','waste commodity'); -INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); -INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); -CREATE TABLE construction_input -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage) -); -CREATE TABLE cost_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT NOT NULL - REFERENCES commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE cost_fixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE cost_invest -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "cost_invest" VALUES('region','annual',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('region','non_annual',2000,1.0,NULL,NULL); -CREATE TABLE cost_variable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_variable" VALUES('region',2000,'annual',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2000,'non_annual',2000,1.0,NULL,NULL); -CREATE TABLE demand -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - commodity TEXT - REFERENCES commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -INSERT INTO "demand" VALUES('region',2000,'demand',1.0,NULL,NULL); -CREATE TABLE demand_specific_distribution -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - demand_name TEXT - REFERENCES commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -CREATE TABLE efficiency -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -INSERT INTO "efficiency" VALUES('region','annual','annual',2000,'physical',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','annual','annual',2000,'demand',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','physical','annual',2000,'demand',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','physical','annual',2000,'annual',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','source','import',2000,'physical',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','source','import',2000,'annual',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','annual','non_annual',2000,'physical',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','annual','non_annual',2000,'demand',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','physical','non_annual',2000,'demand',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','physical','non_annual',2000,'annual',1.0,NULL); -CREATE TABLE efficiency_variable -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE emission_activity -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -CREATE TABLE emission_embodied -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE emission_end_of_life -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -CREATE TABLE existing_capacity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_survival_curve -( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE lifetime_tech -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "lifetime_tech" VALUES('region','annual',1.0,NULL); -INSERT INTO "lifetime_tech" VALUES('region','non_annual',1.0,NULL); -CREATE TABLE limit_activity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -INSERT INTO "limit_activity" VALUES('region',2000,'annual','le',0.5,NULL,NULL); -INSERT INTO "limit_activity" VALUES('region',2000,'non_annual','le',0.5,NULL,NULL); -CREATE TABLE limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_degrowth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE limit_growth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) -); -CREATE TABLE limit_storage_level_fraction -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -CREATE TABLE limit_tech_input_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_input_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_output_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE limit_tech_output_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE linked_tech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES technology (tech), - emis_comm TEXT - REFERENCES commodity (name), - driven_tech TEXT - REFERENCES technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -CREATE TABLE loan_lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "loan_lifetime_process" VALUES('region','annual',2000,1.0,NULL); -INSERT INTO "loan_lifetime_process" VALUES('region','non_annual',2000,1.0,NULL); -CREATE TABLE loan_rate -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); -INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); -INSERT INTO "metadata" VALUES('DB_MINOR',0,''); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -CREATE TABLE myopic_efficiency -( - base_year integer, - region text, - input_comm text, - tech text, - vintage integer, - output_comm text, - efficiency real, - lifetime integer, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (region, input_comm, tech, vintage, output_comm) -); -CREATE TABLE operator -( - operator TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "operator" VALUES('e','equal to'); -INSERT INTO "operator" VALUES('le','less than or equal to'); -INSERT INTO "operator" VALUES('ge','greater than or equal to'); -CREATE TABLE output_built_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES sector_label (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) -); -CREATE TABLE output_curtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_period (period), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE output_emission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE output_flow_in -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out_summary -( - scenario TEXT NOT NULL, - region TEXT NOT NULL, - sector TEXT, - period INTEGER, - input_comm TEXT NOT NULL, - tech TEXT NOT NULL, - vintage INTEGER, - output_comm TEXT NOT NULL, - flow REAL NOT NULL, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_net_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_objective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE output_retired_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_storage_level -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE planning_reserve_margin -( - region TEXT - PRIMARY KEY - REFERENCES region (region), - margin REAL, - notes TEXT -); -CREATE TABLE ramp_down_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE ramp_up_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -INSERT INTO "region" VALUES('region',NULL); -CREATE TABLE reserve_capacity_derate -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE rps_requirement -( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL - REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES tech_group (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE season_label -( - season TEXT PRIMARY KEY, - notes TEXT -); -CREATE TABLE sector_label -( - sector TEXT PRIMARY KEY, - notes TEXT -); -CREATE TABLE storage_duration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE tech_group -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE tech_group_member -( - group_name TEXT - REFERENCES tech_group (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technology_type (label) -); -INSERT INTO "technology" VALUES('annual','p','energy',NULL,NULL,0,1,0,0,0,0,0,0,NULL); -INSERT INTO "technology" VALUES('import','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO "technology" VALUES('non_annual','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -CREATE TABLE technology_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "technology_type" VALUES('p','production technology'); -INSERT INTO "technology_type" VALUES('pb','baseload production technology'); -INSERT INTO "technology_type" VALUES('ps','storage production technology'); -CREATE TABLE time_of_day -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY -); -INSERT INTO "time_of_day" VALUES(0,'D1'); -CREATE TABLE time_period -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES time_period_type (label) -); -INSERT INTO "time_period" VALUES(0,2000,'f'); -INSERT INTO "time_period" VALUES(1,2001,'f'); -CREATE TABLE time_period_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "time_period_type" VALUES('e','existing vintages'); -INSERT INTO "time_period_type" VALUES('f','future'); -CREATE TABLE time_season -( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - season TEXT REFERENCES season_label(season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); -INSERT INTO "time_season" VALUES(2000,0,'S1',NULL); - -CREATE TABLE time_season_sequential -( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT REFERENCES season_label(season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); - -CREATE TABLE time_segment_fraction -( - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - segment_fraction REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); -INSERT INTO "time_segment_fraction" VALUES(2000,'S1','D1',1.0,NULL); -CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); -COMMIT; +REPLACE INTO "commodity" VALUES('source', 's', NULL, NULL); +REPLACE INTO "commodity" VALUES('annual', 'a', NULL, NULL); +REPLACE INTO "commodity" VALUES('physical', 'p', NULL, NULL); +REPLACE INTO "commodity" VALUES('demand', 'd', NULL, NULL); +REPLACE INTO "commodity_type" VALUES('s','source commodity'); +REPLACE INTO "commodity_type" VALUES('a','annual commodity'); +REPLACE INTO "commodity_type" VALUES('p','physical commodity'); +REPLACE INTO "commodity_type" VALUES('d','demand commodity'); +REPLACE INTO "commodity_type" VALUES('e','emissions commodity'); +REPLACE INTO "commodity_type" VALUES('w','waste commodity'); +REPLACE INTO "commodity_type" VALUES('wa','waste annual commodity'); +REPLACE INTO "commodity_type" VALUES('wp','waste physical commodity'); +REPLACE INTO "cost_invest" VALUES('region','annual',2000,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('region','non_annual',2000,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2000,'annual',2000,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2000,'non_annual',2000,1.0,NULL,NULL); +REPLACE INTO "demand" VALUES('region',2000,'demand',1.0,NULL,NULL); +REPLACE INTO "efficiency" VALUES('region', 'annual', 'annual', 2000, 'physical', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('region', 'annual', 'annual', 2000, 'demand', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('region', 'physical', 'annual', 2000, 'demand', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('region', 'physical', 'annual', 2000, 'annual', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('region', 'source', 'import', 2000, 'physical', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('region', 'source', 'import', 2000, 'annual', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('region', 'annual', 'non_annual', 2000, 'physical', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('region', 'annual', 'non_annual', 2000, 'demand', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('region', 'physical', 'non_annual', 2000, 'demand', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('region', 'physical', 'non_annual', 2000, 'annual', 1.0, NULL, NULL); +REPLACE INTO "lifetime_tech" VALUES('region', 'annual', 1.0, NULL, NULL); +REPLACE INTO "lifetime_tech" VALUES('region', 'non_annual', 1.0, NULL, NULL); +REPLACE INTO "limit_activity" VALUES('region',2000,'annual','le',0.5,NULL,NULL); +REPLACE INTO "limit_activity" VALUES('region',2000,'non_annual','le',0.5,NULL,NULL); +REPLACE INTO "loan_lifetime_process" VALUES('region', 'annual', 2000, 1.0, NULL, NULL); +REPLACE INTO "loan_lifetime_process" VALUES('region', 'non_annual', 2000, 1.0, NULL, NULL); +REPLACE INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +REPLACE INTO "metadata" VALUES('DB_MAJOR',4,''); +REPLACE INTO "metadata" VALUES('DB_MINOR',0,''); +REPLACE INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +REPLACE INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +REPLACE INTO "operator" VALUES('e','equal to'); +REPLACE INTO "operator" VALUES('le','less than or equal to'); +REPLACE INTO "operator" VALUES('ge','greater than or equal to'); +REPLACE INTO "region" VALUES('region',NULL); +REPLACE INTO "technology" VALUES('annual','p','energy',NULL,NULL,0,1,0,0,0,0,0,0,NULL); +REPLACE INTO "technology" VALUES('import','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +REPLACE INTO "technology" VALUES('non_annual','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +REPLACE INTO "technology_type" VALUES('p','production technology'); +REPLACE INTO "technology_type" VALUES('pb','baseload production technology'); +REPLACE INTO "technology_type" VALUES('ps','storage production technology'); +REPLACE INTO "time_of_day" VALUES(0,'D1'); +REPLACE INTO "time_period" VALUES(0,2000,'f'); +REPLACE INTO "time_period" VALUES(1,2001,'f'); +REPLACE INTO "time_period_type" VALUES('e','existing vintages'); +REPLACE INTO "time_period_type" VALUES('f','future'); +REPLACE INTO "time_season" VALUES(2000,0,'S1',NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'S1','D1',1.0,NULL); diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 3e3355efe..25faaf3e3 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -1,1130 +1,104 @@ -BEGIN TRANSACTION; -CREATE TABLE capacity_credit -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -CREATE TABLE capacity_factor_process -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE capacity_factor_tech -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -INSERT INTO "capacity_factor_tech" VALUES('Testregion',2000,'S1','TOD1','TechCurtailment',1.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('Testregion',2000,'S1','TOD2','TechCurtailment',0.5,NULL); -INSERT INTO "capacity_factor_tech" VALUES('Testregion',2000,'S1','TOD1','TechOrdinary',1.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('Testregion',2000,'S1','TOD2','TechOrdinary',0.5,NULL); -CREATE TABLE capacity_to_activity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES commodity_type (label), - description TEXT -); -INSERT INTO "commodity" VALUES('annual_in','s',NULL); -INSERT INTO "commodity" VALUES('flex_in','s',NULL); -INSERT INTO "commodity" VALUES('ordinary_in','s',NULL); -INSERT INTO "commodity" VALUES('curtailment_in','s',NULL); -INSERT INTO "commodity" VALUES('annual_out','d',NULL); -INSERT INTO "commodity" VALUES('flex_out','p',NULL); -INSERT INTO "commodity" VALUES('ordinary_out','d',NULL); -INSERT INTO "commodity" VALUES('curtailment_out','d',NULL); -INSERT INTO "commodity" VALUES('emission','e',NULL); -INSERT INTO "commodity" VALUES('flex_null','d',NULL); -INSERT INTO "commodity" VALUES('annual_flex_out','p',NULL); -INSERT INTO "commodity" VALUES('annual_flex_in','s',NULL); -INSERT INTO "commodity" VALUES('annual_flex_null','d',NULL); -INSERT INTO "commodity" VALUES('embodied_in','s',NULL); -INSERT INTO "commodity" VALUES('embodied_out','d',NULL); -INSERT INTO "commodity" VALUES('eol_in','s',NULL); -INSERT INTO "commodity" VALUES('eol_out','d',NULL); -CREATE TABLE commodity_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "commodity_type" VALUES('w','waste commodity'); -INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); -INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); -INSERT INTO "commodity_type" VALUES('a','annual commodity'); -INSERT INTO "commodity_type" VALUES('p','physical commodity'); -INSERT INTO "commodity_type" VALUES('e','emissions commodity'); -INSERT INTO "commodity_type" VALUES('d','demand commodity'); -INSERT INTO "commodity_type" VALUES('s','source commodity'); -CREATE TABLE construction_input -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage) -); -CREATE TABLE cost_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT NOT NULL - REFERENCES commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -INSERT INTO "cost_emission" VALUES('Testregion',2000,'emission',0.7,NULL,NULL); -INSERT INTO "cost_emission" VALUES('Testregion',2005,'emission',0.7,NULL,NULL); -CREATE TABLE cost_fixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE cost_invest -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE cost_variable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE demand -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - commodity TEXT - REFERENCES commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -INSERT INTO "demand" VALUES('Testregion',2000,'annual_out',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('Testregion',2000,'ordinary_out',0.3,NULL,NULL); -INSERT INTO "demand" VALUES('Testregion',2000,'curtailment_out',0.3,NULL,NULL); -INSERT INTO "demand" VALUES('Testregion',2000,'flex_null',0.3,NULL,NULL); -INSERT INTO "demand" VALUES('Testregion',2000,'annual_flex_null',0.3,NULL,NULL); -INSERT INTO "demand" VALUES('Testregion',2000,'embodied_out',0.6,NULL,NULL); -INSERT INTO "demand" VALUES('Testregion',2000,'eol_out',0.6,NULL,NULL); -INSERT INTO "demand" VALUES('Testregion',2005,'ordinary_out',0.3,NULL,NULL); -INSERT INTO "demand" VALUES('Testregion',2005,'annual_out',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('Testregion',2005,'curtailment_out',0.3,NULL,NULL); -INSERT INTO "demand" VALUES('Testregion',2005,'flex_null',0.3,NULL,NULL); -INSERT INTO "demand" VALUES('Testregion',2005,'annual_flex_null',0.3,NULL,NULL); -INSERT INTO "demand" VALUES('Testregion',2005,'embodied_out',0.6,NULL,NULL); -CREATE TABLE demand_specific_distribution -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - demand_name TEXT - REFERENCES commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -CREATE TABLE efficiency -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -INSERT INTO "efficiency" VALUES('Testregion','annual_in','TechAnnual',2000,'annual_out',1.0,NULL); -INSERT INTO "efficiency" VALUES('Testregion','flex_in','TechFlex',2000,'flex_out',1.0,NULL); -INSERT INTO "efficiency" VALUES('Testregion','ordinary_in','TechOrdinary',2000,'ordinary_out',1.0,NULL); -INSERT INTO "efficiency" VALUES('Testregion','curtailment_in','TechCurtailment',2000,'curtailment_out',1.0,NULL); -INSERT INTO "efficiency" VALUES('Testregion','flex_out','TechFlexNull',2000,'flex_null',1.0,NULL); -INSERT INTO "efficiency" VALUES('Testregion','annual_flex_out','TechFlexNull',2000,'annual_flex_null',1.0,NULL); -INSERT INTO "efficiency" VALUES('Testregion','annual_flex_in','TechAnnualFlex',2000,'annual_flex_out',1.0,NULL); -INSERT INTO "efficiency" VALUES('Testregion','embodied_in','TechEmbodied',2000,'embodied_out',1.0,NULL); -INSERT INTO "efficiency" VALUES('Testregion','eol_in','TechEndOfLife',2000,'eol_out',1.0,NULL); -CREATE TABLE efficiency_variable -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE emission_activity -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -INSERT INTO "emission_activity" VALUES('Testregion','emission','annual_in','TechAnnual',2000,'annual_out',1.0,NULL,NULL); -INSERT INTO "emission_activity" VALUES('Testregion','emission','flex_in','TechFlex',2000,'flex_out',1.0,NULL,NULL); -INSERT INTO "emission_activity" VALUES('Testregion','emission','ordinary_in','TechOrdinary',2000,'ordinary_out',1.0,NULL,NULL); -INSERT INTO "emission_activity" VALUES('Testregion','emission','curtailment_in','TechCurtailment',2000,'curtailment_out',1.0,NULL,NULL); -INSERT INTO "emission_activity" VALUES('Testregion','emission','annual_flex_in','TechAnnualFlex',2000,'annual_flex_out',1.0,NULL,NULL); -CREATE TABLE emission_embodied -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -INSERT INTO "emission_embodied" VALUES('Testregion','emission','TechEmbodied',2000,0.5,NULL,NULL); -CREATE TABLE emission_end_of_life -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -INSERT INTO "emission_end_of_life" VALUES('Testregion','emission','TechEndOfLife',2000,0.5,NULL,NULL); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -CREATE TABLE existing_capacity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_survival_curve -( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE lifetime_tech -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "lifetime_tech" VALUES('Testregion','TechEndOfLife',5.0,NULL); -CREATE TABLE limit_activity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -INSERT INTO "limit_activity" VALUES('Testregion',2000,'TechFlex','ge',1.0,NULL,NULL); -INSERT INTO "limit_activity" VALUES('Testregion',2000,'TechAnnualFlex','ge',1.0,NULL,NULL); -INSERT INTO "limit_activity" VALUES('Testregion',2000,'TechFlex','le',1.0,NULL,NULL); -INSERT INTO "limit_activity" VALUES('Testregion',2000,'TechAnnualFlex','le',1.0,NULL,NULL); -CREATE TABLE limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -INSERT INTO "limit_capacity" VALUES('Testregion',2000,'TechOrdinary','ge',1.0,NULL,NULL); -INSERT INTO "limit_capacity" VALUES('Testregion',2000,'TechCurtailment','ge',1.0,NULL,NULL); -INSERT INTO "limit_capacity" VALUES('Testregion',2000,'TechOrdinary','le',1.0,NULL,NULL); -INSERT INTO "limit_capacity" VALUES('Testregion',2000,'TechCurtailment','le',1.0,NULL,NULL); -CREATE TABLE limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_degrowth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE limit_growth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) -); -CREATE TABLE limit_storage_level_fraction -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -CREATE TABLE limit_tech_input_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_input_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_output_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE limit_tech_output_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE linked_tech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES technology (tech), - emis_comm TEXT - REFERENCES commodity (name), - driven_tech TEXT - REFERENCES technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -CREATE TABLE loan_lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE loan_rate -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); -INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); -INSERT INTO "metadata" VALUES('DB_MINOR',0,''); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -CREATE TABLE myopic_efficiency -( - base_year integer, - region text, - input_comm text, - tech text, - vintage integer, - output_comm text, - efficiency real, - lifetime integer, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (region, input_comm, tech, vintage, output_comm) -); -CREATE TABLE operator -( - operator TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "operator" VALUES('e','equal to'); -INSERT INTO "operator" VALUES('le','less than or equal to'); -INSERT INTO "operator" VALUES('ge','greater than or equal to'); -CREATE TABLE output_built_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES sector_label (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) -); -CREATE TABLE output_curtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_period (period), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE output_emission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE output_flow_in -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out_summary -( - scenario TEXT NOT NULL, - region TEXT NOT NULL, - sector TEXT, - period INTEGER, - input_comm TEXT NOT NULL, - tech TEXT NOT NULL, - vintage INTEGER, - output_comm TEXT NOT NULL, - flow REAL NOT NULL, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_net_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_objective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE output_retired_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_storage_level -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE planning_reserve_margin -( - region TEXT - PRIMARY KEY - REFERENCES region (region), - margin REAL, - notes TEXT -); -CREATE TABLE ramp_down_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE ramp_up_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -INSERT INTO "region" VALUES('Testregion',NULL); -CREATE TABLE reserve_capacity_derate -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE rps_requirement -( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL - REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES tech_group (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE season_label -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "season_label" VALUES('S1',NULL); -CREATE TABLE sector_label -( - sector TEXT PRIMARY KEY, - notes TEXT -); -CREATE TABLE storage_duration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE tech_group -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE tech_group_member -( - group_name TEXT - REFERENCES tech_group (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technology_type (label) -); -INSERT INTO "technology" VALUES('TechAnnual','p','energy',NULL,NULL,0,1,0,0,0,0,0,0,NULL); -INSERT INTO "technology" VALUES('TechFlex','p','energy',NULL,NULL,0,0,0,0,0,1,0,0,NULL); -INSERT INTO "technology" VALUES('TechOrdinary','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO "technology" VALUES('TechCurtailment','p','energy',NULL,NULL,0,0,0,1,0,0,0,0,NULL); -INSERT INTO "technology" VALUES('TechFlexNull','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO "technology" VALUES('TechAnnualFlex','p','energy',NULL,NULL,0,1,0,0,0,1,0,0,NULL); -INSERT INTO "technology" VALUES('TechEmbodied','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO "technology" VALUES('TechEndOfLife','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -CREATE TABLE technology_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "technology_type" VALUES('p','production technology'); -INSERT INTO "technology_type" VALUES('pb','baseload production technology'); -INSERT INTO "technology_type" VALUES('ps','storage production technology'); -CREATE TABLE time_of_day -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY -); -INSERT INTO "time_of_day" VALUES(1,'TOD1'); -INSERT INTO "time_of_day" VALUES(2,'TOD2'); -CREATE TABLE time_period -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES time_period_type (label) -); -INSERT INTO "time_period" VALUES(1,1999,'e'); -INSERT INTO "time_period" VALUES(2,2000,'f'); -INSERT INTO "time_period" VALUES(3,2005,'f'); -INSERT INTO "time_period" VALUES(4,2010,'f'); -CREATE TABLE time_period_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "time_period_type" VALUES('e','existing vintages'); -INSERT INTO "time_period_type" VALUES('f','future'); -CREATE TABLE time_season -( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - season TEXT REFERENCES season_label(season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); -INSERT INTO "time_season" VALUES(2000,1,'S1',NULL); -INSERT INTO "time_season" VALUES(2005,1,'S1',NULL); - -CREATE TABLE time_season_sequential -( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT REFERENCES season_label(season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); - -CREATE TABLE time_segment_fraction -( - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - segment_fraction REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); -INSERT INTO "time_segment_fraction" VALUES(2000,'S1','TOD1',0.5,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'S1','TOD2',0.5,NULL); -INSERT INTO "time_segment_fraction" VALUES(2005,'S1','TOD1',0.5,NULL); -INSERT INTO "time_segment_fraction" VALUES(2005,'S1','TOD2',0.5,NULL); -CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); -COMMIT; +REPLACE INTO "capacity_factor_tech" VALUES('Testregion',2000,'S1','TOD1','TechCurtailment',1.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('Testregion',2000,'S1','TOD2','TechCurtailment',0.5,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('Testregion',2000,'S1','TOD1','TechOrdinary',1.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('Testregion',2000,'S1','TOD2','TechOrdinary',0.5,NULL); +REPLACE INTO "commodity" VALUES('annual_in', 's', NULL, NULL); +REPLACE INTO "commodity" VALUES('flex_in', 's', NULL, NULL); +REPLACE INTO "commodity" VALUES('ordinary_in', 's', NULL, NULL); +REPLACE INTO "commodity" VALUES('curtailment_in', 's', NULL, NULL); +REPLACE INTO "commodity" VALUES('annual_out', 'd', NULL, NULL); +REPLACE INTO "commodity" VALUES('flex_out', 'p', NULL, NULL); +REPLACE INTO "commodity" VALUES('ordinary_out', 'd', NULL, NULL); +REPLACE INTO "commodity" VALUES('curtailment_out', 'd', NULL, NULL); +REPLACE INTO "commodity" VALUES('emission', 'e', NULL, NULL); +REPLACE INTO "commodity" VALUES('flex_null', 'd', NULL, NULL); +REPLACE INTO "commodity" VALUES('annual_flex_out', 'p', NULL, NULL); +REPLACE INTO "commodity" VALUES('annual_flex_in', 's', NULL, NULL); +REPLACE INTO "commodity" VALUES('annual_flex_null', 'd', NULL, NULL); +REPLACE INTO "commodity" VALUES('embodied_in', 's', NULL, NULL); +REPLACE INTO "commodity" VALUES('embodied_out', 'd', NULL, NULL); +REPLACE INTO "commodity" VALUES('eol_in', 's', NULL, NULL); +REPLACE INTO "commodity" VALUES('eol_out', 'd', NULL, NULL); +REPLACE INTO "commodity_type" VALUES('w','waste commodity'); +REPLACE INTO "commodity_type" VALUES('wa','waste annual commodity'); +REPLACE INTO "commodity_type" VALUES('wp','waste physical commodity'); +REPLACE INTO "commodity_type" VALUES('a','annual commodity'); +REPLACE INTO "commodity_type" VALUES('p','physical commodity'); +REPLACE INTO "commodity_type" VALUES('e','emissions commodity'); +REPLACE INTO "commodity_type" VALUES('d','demand commodity'); +REPLACE INTO "commodity_type" VALUES('s','source commodity'); +REPLACE INTO "cost_emission" VALUES('Testregion',2000,'emission',0.7,NULL,NULL); +REPLACE INTO "cost_emission" VALUES('Testregion',2005,'emission',0.7,NULL,NULL); +REPLACE INTO "demand" VALUES('Testregion',2000,'annual_out',1.0,NULL,NULL); +REPLACE INTO "demand" VALUES('Testregion',2000,'ordinary_out',0.3,NULL,NULL); +REPLACE INTO "demand" VALUES('Testregion',2000,'curtailment_out',0.3,NULL,NULL); +REPLACE INTO "demand" VALUES('Testregion',2000,'flex_null',0.3,NULL,NULL); +REPLACE INTO "demand" VALUES('Testregion',2000,'annual_flex_null',0.3,NULL,NULL); +REPLACE INTO "demand" VALUES('Testregion',2000,'embodied_out',0.6,NULL,NULL); +REPLACE INTO "demand" VALUES('Testregion',2000,'eol_out',0.6,NULL,NULL); +REPLACE INTO "demand" VALUES('Testregion',2005,'ordinary_out',0.3,NULL,NULL); +REPLACE INTO "demand" VALUES('Testregion',2005,'annual_out',1.0,NULL,NULL); +REPLACE INTO "demand" VALUES('Testregion',2005,'curtailment_out',0.3,NULL,NULL); +REPLACE INTO "demand" VALUES('Testregion',2005,'flex_null',0.3,NULL,NULL); +REPLACE INTO "demand" VALUES('Testregion',2005,'annual_flex_null',0.3,NULL,NULL); +REPLACE INTO "demand" VALUES('Testregion',2005,'embodied_out',0.6,NULL,NULL); +REPLACE INTO "efficiency" VALUES('Testregion', 'annual_in', 'TechAnnual', 2000, 'annual_out', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('Testregion', 'flex_in', 'TechFlex', 2000, 'flex_out', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('Testregion', 'ordinary_in', 'TechOrdinary', 2000, 'ordinary_out', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('Testregion', 'curtailment_in', 'TechCurtailment', 2000, 'curtailment_out', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('Testregion', 'flex_out', 'TechFlexNull', 2000, 'flex_null', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('Testregion', 'annual_flex_out', 'TechFlexNull', 2000, 'annual_flex_null', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('Testregion', 'annual_flex_in', 'TechAnnualFlex', 2000, 'annual_flex_out', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('Testregion', 'embodied_in', 'TechEmbodied', 2000, 'embodied_out', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('Testregion', 'eol_in', 'TechEndOfLife', 2000, 'eol_out', 1.0, NULL, NULL); +REPLACE INTO "emission_activity" VALUES('Testregion','emission','annual_in','TechAnnual',2000,'annual_out',1.0,NULL,NULL); +REPLACE INTO "emission_activity" VALUES('Testregion','emission','flex_in','TechFlex',2000,'flex_out',1.0,NULL,NULL); +REPLACE INTO "emission_activity" VALUES('Testregion','emission','ordinary_in','TechOrdinary',2000,'ordinary_out',1.0,NULL,NULL); +REPLACE INTO "emission_activity" VALUES('Testregion','emission','curtailment_in','TechCurtailment',2000,'curtailment_out',1.0,NULL,NULL); +REPLACE INTO "emission_activity" VALUES('Testregion','emission','annual_flex_in','TechAnnualFlex',2000,'annual_flex_out',1.0,NULL,NULL); +REPLACE INTO "emission_embodied" VALUES('Testregion','emission','TechEmbodied',2000,0.5,NULL,NULL); +REPLACE INTO "emission_end_of_life" VALUES('Testregion','emission','TechEndOfLife',2000,0.5,NULL,NULL); +REPLACE INTO "lifetime_tech" VALUES('Testregion', 'TechEndOfLife', 5.0, NULL, NULL); +REPLACE INTO "limit_activity" VALUES('Testregion',2000,'TechFlex','ge',1.0,NULL,NULL); +REPLACE INTO "limit_activity" VALUES('Testregion',2000,'TechAnnualFlex','ge',1.0,NULL,NULL); +REPLACE INTO "limit_activity" VALUES('Testregion',2000,'TechFlex','le',1.0,NULL,NULL); +REPLACE INTO "limit_activity" VALUES('Testregion',2000,'TechAnnualFlex','le',1.0,NULL,NULL); +REPLACE INTO "limit_capacity" VALUES('Testregion',2000,'TechOrdinary','ge',1.0,NULL,NULL); +REPLACE INTO "limit_capacity" VALUES('Testregion',2000,'TechCurtailment','ge',1.0,NULL,NULL); +REPLACE INTO "limit_capacity" VALUES('Testregion',2000,'TechOrdinary','le',1.0,NULL,NULL); +REPLACE INTO "limit_capacity" VALUES('Testregion',2000,'TechCurtailment','le',1.0,NULL,NULL); +REPLACE INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +REPLACE INTO "metadata" VALUES('DB_MAJOR',4,''); +REPLACE INTO "metadata" VALUES('DB_MINOR',0,''); +REPLACE INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +REPLACE INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +REPLACE INTO "operator" VALUES('e','equal to'); +REPLACE INTO "operator" VALUES('le','less than or equal to'); +REPLACE INTO "operator" VALUES('ge','greater than or equal to'); +REPLACE INTO "region" VALUES('Testregion',NULL); +REPLACE INTO "season_label" VALUES('S1',NULL); +REPLACE INTO "technology" VALUES('TechAnnual','p','energy',NULL,NULL,0,1,0,0,0,0,0,0,NULL); +REPLACE INTO "technology" VALUES('TechFlex','p','energy',NULL,NULL,0,0,0,0,0,1,0,0,NULL); +REPLACE INTO "technology" VALUES('TechOrdinary','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +REPLACE INTO "technology" VALUES('TechCurtailment','p','energy',NULL,NULL,0,0,0,1,0,0,0,0,NULL); +REPLACE INTO "technology" VALUES('TechFlexNull','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +REPLACE INTO "technology" VALUES('TechAnnualFlex','p','energy',NULL,NULL,0,1,0,0,0,1,0,0,NULL); +REPLACE INTO "technology" VALUES('TechEmbodied','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +REPLACE INTO "technology" VALUES('TechEndOfLife','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +REPLACE INTO "technology_type" VALUES('p','production technology'); +REPLACE INTO "technology_type" VALUES('pb','baseload production technology'); +REPLACE INTO "technology_type" VALUES('ps','storage production technology'); +REPLACE INTO "time_of_day" VALUES(1,'TOD1'); +REPLACE INTO "time_of_day" VALUES(2,'TOD2'); +REPLACE INTO "time_period" VALUES(1,1999,'e'); +REPLACE INTO "time_period" VALUES(2,2000,'f'); +REPLACE INTO "time_period" VALUES(3,2005,'f'); +REPLACE INTO "time_period" VALUES(4,2010,'f'); +REPLACE INTO "time_period_type" VALUES('e','existing vintages'); +REPLACE INTO "time_period_type" VALUES('f','future'); +REPLACE INTO "time_season" VALUES(2000,1,'S1',NULL); +REPLACE INTO "time_season" VALUES(2005,1,'S1',NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'S1','TOD1',0.5,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'S1','TOD2',0.5,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2005,'S1','TOD1',0.5,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2005,'S1','TOD2',0.5,NULL); diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index f32e898d9..abf2c3c0f 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -1,1530 +1,504 @@ -BEGIN TRANSACTION; -CREATE TABLE capacity_credit -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -CREATE TABLE capacity_factor_process -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE capacity_factor_tech -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'summer','morning','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'autumn','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'winter','morning','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'spring','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'summer','afternoon','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'autumn','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'winter','afternoon','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'spring','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'summer','evening','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2000,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'summer','morning','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'autumn','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'winter','morning','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'spring','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'summer','afternoon','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'autumn','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'winter','afternoon','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'spring','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'summer','evening','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2010,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'summer','morning','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'autumn','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'winter','morning','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'spring','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'summer','afternoon','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'autumn','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'winter','afternoon','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'spring','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'summer','evening','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionA',2020,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'summer','morning','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'autumn','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'winter','morning','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'spring','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'summer','afternoon','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'autumn','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'winter','afternoon','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'spring','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'summer','evening','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2000,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'summer','morning','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'autumn','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'winter','morning','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'spring','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'summer','afternoon','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'autumn','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'winter','afternoon','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'spring','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'summer','evening','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2010,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'summer','morning','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'autumn','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'winter','morning','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'spring','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'summer','afternoon','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'autumn','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'winter','afternoon','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'spring','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'summer','evening','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('regionB',2020,'spring','overnight','SOL_PV',0.0,NULL); -CREATE TABLE capacity_to_activity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES commodity_type (label), - description TEXT -); -INSERT INTO "commodity" VALUES('ethos','s','import dummy source'); -INSERT INTO "commodity" VALUES('electricity','p','grid electricity'); -INSERT INTO "commodity" VALUES('passenger_km','d','demand for passenger km'); -INSERT INTO "commodity" VALUES('battery_nmc','a','battery - lithium nickel manganese cobalt oxide'); -INSERT INTO "commodity" VALUES('battery_lfp','a','battery - lithium iron phosphate'); -INSERT INTO "commodity" VALUES('lithium','a','lithium'); -INSERT INTO "commodity" VALUES('cobalt','a','cobalt'); -INSERT INTO "commodity" VALUES('phosphorous','a','phosphorous'); -INSERT INTO "commodity" VALUES('diesel','a','diesel'); -INSERT INTO "commodity" VALUES('heating','d','demand for residential heating'); -INSERT INTO "commodity" VALUES('nickel','a','nickel'); -INSERT INTO "commodity" VALUES('used_batt_nmc','wa','used battery - lithium nickel manganese cobalt oxide'); -INSERT INTO "commodity" VALUES('used_batt_lfp','wa','used battery - lithium iron phosphate'); -INSERT INTO "commodity" VALUES('co2e','e','emitted co2-equivalent GHGs'); -INSERT INTO "commodity" VALUES('waste_steel','w','waste steel from cars'); -CREATE TABLE commodity_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "commodity_type" VALUES('w','waste commodity'); -INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); -INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); -INSERT INTO "commodity_type" VALUES('a','annual commodity'); -INSERT INTO "commodity_type" VALUES('p','physical commodity'); -INSERT INTO "commodity_type" VALUES('e','emissions commodity'); -INSERT INTO "commodity_type" VALUES('d','demand commodity'); -INSERT INTO "commodity_type" VALUES('s','source commodity'); -CREATE TABLE construction_input -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage) -); -INSERT INTO "construction_input" VALUES('regionA','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO "construction_input" VALUES('regionA','battery_lfp','CAR_PHEV',2000,0.1,NULL,NULL); -INSERT INTO "construction_input" VALUES('regionA','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO "construction_input" VALUES('regionA','battery_lfp','CAR_PHEV',2010,0.1,NULL,NULL); -INSERT INTO "construction_input" VALUES('regionA','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO "construction_input" VALUES('regionA','battery_lfp','CAR_PHEV',2020,0.1,NULL,NULL); -INSERT INTO "construction_input" VALUES('regionB','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO "construction_input" VALUES('regionB','battery_lfp','CAR_PHEV',2000,0.1,NULL,NULL); -INSERT INTO "construction_input" VALUES('regionB','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO "construction_input" VALUES('regionB','battery_lfp','CAR_PHEV',2010,0.1,NULL,NULL); -INSERT INTO "construction_input" VALUES('regionB','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO "construction_input" VALUES('regionB','battery_lfp','CAR_PHEV',2020,0.1,NULL,NULL); -CREATE TABLE cost_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT NOT NULL - REFERENCES commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -INSERT INTO "cost_emission" VALUES('regionA',2000,'co2e',1.0,NULL,NULL); -INSERT INTO "cost_emission" VALUES('regionA',2010,'co2e',1.0,NULL,NULL); -INSERT INTO "cost_emission" VALUES('regionA',2020,'co2e',1.0,NULL,NULL); -INSERT INTO "cost_emission" VALUES('regionB',2000,'co2e',1.0,NULL,NULL); -INSERT INTO "cost_emission" VALUES('regionB',2010,'co2e',1.0,NULL,NULL); -INSERT INTO "cost_emission" VALUES('regionB',2020,'co2e',1.0,NULL,NULL); -CREATE TABLE cost_fixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE cost_invest -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "cost_invest" VALUES('regionA','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionA','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionA','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionA','CAR_PHEV',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionA','CAR_PHEV',2010,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionA','CAR_PHEV',2020,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionA','CAR_ICE',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionA','CAR_ICE',2010,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionA','CAR_ICE',2020,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionA','RECYCLE_NMC',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionA','RECYCLE_LFP',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionA','MANUFAC_NMC',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionA','MANUFAC_LFP',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionA','BATT_GRID',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionA','SOL_PV',2000,10.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionA','GEN_DSL',2000,2.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionB','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionB','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionB','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionB','CAR_PHEV',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionB','CAR_PHEV',2010,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionB','CAR_PHEV',2020,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionB','CAR_ICE',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionB','CAR_ICE',2010,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionB','CAR_ICE',2020,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionB','RECYCLE_NMC',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionB','RECYCLE_LFP',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionB','MANUFAC_NMC',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionB','MANUFAC_LFP',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionB','BATT_GRID',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionB','GEN_DSL',2000,2.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionA-regionB','ELEC_INTERTIE',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionB-regionA','ELEC_INTERTIE',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('regionB','SOL_PV',2000,1.0,NULL,NULL); -CREATE TABLE cost_variable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_variable" VALUES('regionA',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionA',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionA',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionA',2000,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionA',2010,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionA',2020,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionA',2000,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionA',2010,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionA',2020,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionA',2000,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionA',2010,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionA',2020,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionA',2000,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionA',2010,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionA',2020,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionA',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionA',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionA',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionB',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionB',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionB',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionB',2000,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionB',2010,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionB',2020,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionB',2000,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionB',2010,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionB',2020,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionB',2000,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionB',2010,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionB',2020,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionB',2000,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionB',2010,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionB',2020,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionB',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionB',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO "cost_variable" VALUES('regionB',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); -CREATE TABLE demand -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - commodity TEXT - REFERENCES commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -INSERT INTO "demand" VALUES('regionA',2000,'passenger_km',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('regionA',2010,'passenger_km',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('regionA',2020,'passenger_km',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('regionA',2000,'heating',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('regionA',2010,'heating',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('regionA',2020,'heating',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('regionB',2000,'passenger_km',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('regionB',2010,'passenger_km',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('regionB',2020,'passenger_km',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('regionB',2000,'heating',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('regionB',2010,'heating',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('regionB',2020,'heating',1.0,NULL,NULL); -CREATE TABLE demand_specific_distribution -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - demand_name TEXT - REFERENCES commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -CREATE TABLE efficiency -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -INSERT INTO "efficiency" VALUES('regionA','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2,NULL); -INSERT INTO "efficiency" VALUES('regionA','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2,NULL); -INSERT INTO "efficiency" VALUES('regionA','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','electricity','RECYCLE_NMC',2000,'battery_nmc',0.001,'Effectively zero'); -INSERT INTO "efficiency" VALUES('regionA','electricity','RECYCLE_LFP',2000,'battery_lfp',0.001,'Effectively zero'); -INSERT INTO "efficiency" VALUES('regionA','electricity','MANUFAC_NMC',2000,'battery_nmc',0.001,'Effectively zero'); -INSERT INTO "efficiency" VALUES('regionA','electricity','MANUFAC_LFP',2000,'battery_lfp',0.001,'Effectively zero'); -INSERT INTO "efficiency" VALUES('regionA','diesel','GEN_DSL',2000,'electricity',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','ethos','SOL_PV',2000,'electricity',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','electricity','BATT_GRID',2000,'electricity',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','diesel','FURNACE',2000,'heating',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','electricity','HEATPUMP',2000,'heating',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2,NULL); -INSERT INTO "efficiency" VALUES('regionB','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2,NULL); -INSERT INTO "efficiency" VALUES('regionB','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','electricity','RECYCLE_NMC',2000,'battery_nmc',0.001,'Effectively zero'); -INSERT INTO "efficiency" VALUES('regionB','electricity','RECYCLE_LFP',2000,'battery_lfp',0.001,'Effectively zero'); -INSERT INTO "efficiency" VALUES('regionB','electricity','MANUFAC_NMC',2000,'battery_nmc',0.001,'Effectively zero'); -INSERT INTO "efficiency" VALUES('regionB','electricity','MANUFAC_LFP',2000,'battery_lfp',0.001,'Effectively zero'); -INSERT INTO "efficiency" VALUES('regionB','diesel','GEN_DSL',2000,'electricity',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','ethos','SOL_PV',2000,'electricity',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','electricity','BATT_GRID',2000,'electricity',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','diesel','FURNACE',2000,'heating',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','electricity','HEATPUMP',2000,'heating',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionB','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('regionA-regionB','electricity','ELEC_INTERTIE',2000,'electricity',0.9,NULL); -INSERT INTO "efficiency" VALUES('regionB-regionA','electricity','ELEC_INTERTIE',2000,'electricity',0.9,NULL); -CREATE TABLE efficiency_variable -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE emission_activity -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -INSERT INTO "emission_activity" VALUES('regionA','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); -INSERT INTO "emission_activity" VALUES('regionB','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); -CREATE TABLE emission_embodied -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE emission_end_of_life -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -INSERT INTO "end_of_life_output" VALUES('regionA','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionA','CAR_PHEV',1990,'used_batt_lfp',0.1,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionA','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionA','CAR_PHEV',2000,'used_batt_lfp',0.1,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionA','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionA','CAR_PHEV',2010,'used_batt_lfp',0.1,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionB','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionB','CAR_PHEV',1990,'used_batt_lfp',0.1,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionB','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionB','CAR_PHEV',2000,'used_batt_lfp',0.1,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionB','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionB','CAR_PHEV',2010,'used_batt_lfp',0.1,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionA','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionA','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionA','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionA','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionA','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionA','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionA','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionA','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionA','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionB','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionB','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionB','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionB','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionB','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionB','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionB','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionB','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('regionB','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); -CREATE TABLE existing_capacity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "existing_capacity" VALUES('regionA','CAR_BEV',1990,1.0,NULL,NULL); -INSERT INTO "existing_capacity" VALUES('regionA','CAR_PHEV',1990,1.0,NULL,NULL); -INSERT INTO "existing_capacity" VALUES('regionA','CAR_ICE',1990,1.0,NULL,NULL); -INSERT INTO "existing_capacity" VALUES('regionB','CAR_BEV',1990,1.0,NULL,NULL); -INSERT INTO "existing_capacity" VALUES('regionB','CAR_PHEV',1990,1.0,NULL,NULL); -INSERT INTO "existing_capacity" VALUES('regionB','CAR_ICE',1990,1.0,NULL,NULL); -CREATE TABLE lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_survival_curve -( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE lifetime_tech -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "lifetime_tech" VALUES('regionA','CAR_BEV',10.0,NULL); -INSERT INTO "lifetime_tech" VALUES('regionA','CAR_PHEV',10.0,NULL); -INSERT INTO "lifetime_tech" VALUES('regionA','CAR_ICE',10.0,NULL); -INSERT INTO "lifetime_tech" VALUES('regionB','CAR_BEV',10.0,NULL); -INSERT INTO "lifetime_tech" VALUES('regionB','CAR_PHEV',10.0,NULL); -INSERT INTO "lifetime_tech" VALUES('regionB','CAR_ICE',10.0,NULL); -CREATE TABLE limit_activity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_degrowth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE limit_growth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) -); -CREATE TABLE limit_storage_level_fraction -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -CREATE TABLE limit_tech_input_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_input_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'lithium','MANUFAC_NMC','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'nickel','MANUFAC_NMC','le',0.15,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'cobalt','MANUFAC_NMC','le',0.04,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'electricity','MANUFAC_NMC','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'lithium','MANUFAC_LFP','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'phosphorous','MANUFAC_LFP','le',0.19,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'electricity','MANUFAC_LFP','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'lithium','MANUFAC_NMC','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'nickel','MANUFAC_NMC','le',0.15,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'cobalt','MANUFAC_NMC','le',0.04,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'electricity','MANUFAC_NMC','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'lithium','MANUFAC_LFP','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'phosphorous','MANUFAC_LFP','le',0.19,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'electricity','MANUFAC_LFP','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'lithium','MANUFAC_NMC','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'nickel','MANUFAC_NMC','le',0.15,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'cobalt','MANUFAC_NMC','le',0.04,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'electricity','MANUFAC_NMC','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'lithium','MANUFAC_LFP','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'phosphorous','MANUFAC_LFP','le',0.19,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'electricity','MANUFAC_LFP','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'electricity','CAR_PHEV','le',0.2,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'diesel','CAR_PHEV','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'electricity','CAR_PHEV','le',0.2,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'diesel','CAR_PHEV','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'electricity','CAR_PHEV','le',0.2,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'diesel','CAR_PHEV','le',0.8,NULL); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'lithium','MANUFAC_NMC','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'nickel','MANUFAC_NMC','le',0.15,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'cobalt','MANUFAC_NMC','le',0.04,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'electricity','MANUFAC_NMC','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'lithium','MANUFAC_LFP','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'phosphorous','MANUFAC_LFP','le',0.19,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'electricity','MANUFAC_LFP','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'lithium','MANUFAC_NMC','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'nickel','MANUFAC_NMC','le',0.15,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'cobalt','MANUFAC_NMC','le',0.04,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'electricity','MANUFAC_NMC','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'lithium','MANUFAC_LFP','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'phosphorous','MANUFAC_LFP','le',0.19,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'electricity','MANUFAC_LFP','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'lithium','MANUFAC_NMC','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'nickel','MANUFAC_NMC','le',0.15,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'cobalt','MANUFAC_NMC','le',0.04,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'electricity','MANUFAC_NMC','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'lithium','MANUFAC_LFP','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'phosphorous','MANUFAC_LFP','le',0.19,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'electricity','MANUFAC_LFP','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'electricity','CAR_PHEV','le',0.2,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'diesel','CAR_PHEV','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'electricity','CAR_PHEV','le',0.2,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'diesel','CAR_PHEV','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'electricity','CAR_PHEV','le',0.2,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'diesel','CAR_PHEV','le',0.8,NULL); -CREATE TABLE limit_tech_output_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE limit_tech_output_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE linked_tech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES technology (tech), - emis_comm TEXT - REFERENCES commodity (name), - driven_tech TEXT - REFERENCES technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -CREATE TABLE loan_lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE loan_rate -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); -INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); -INSERT INTO "metadata" VALUES('DB_MINOR',0,''); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -CREATE TABLE myopic_efficiency -( - base_year integer, - region text, - input_comm text, - tech text, - vintage integer, - output_comm text, - efficiency real, - lifetime integer, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (region, input_comm, tech, vintage, output_comm) -); -CREATE TABLE operator -( - operator TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "operator" VALUES('e','equal to'); -INSERT INTO "operator" VALUES('le','less than or equal to'); -INSERT INTO "operator" VALUES('ge','greater than or equal to'); -CREATE TABLE output_built_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES sector_label (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) -); -CREATE TABLE output_curtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_period (period), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE output_emission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE output_flow_in -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out_summary -( - scenario TEXT NOT NULL, - region TEXT NOT NULL, - sector TEXT, - period INTEGER, - input_comm TEXT NOT NULL, - tech TEXT NOT NULL, - vintage INTEGER, - output_comm TEXT NOT NULL, - flow REAL NOT NULL, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_net_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_objective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE output_retired_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_storage_level -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE planning_reserve_margin -( - region TEXT - PRIMARY KEY - REFERENCES region (region), - margin REAL, - notes TEXT -); -CREATE TABLE ramp_down_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE ramp_up_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -INSERT INTO "region" VALUES('regionA',NULL); -INSERT INTO "region" VALUES('regionB',NULL); -CREATE TABLE reserve_capacity_derate -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE rps_requirement -( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL - REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES tech_group (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE season_label -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "season_label" VALUES('summer',NULL); -INSERT INTO "season_label" VALUES('autumn',NULL); -INSERT INTO "season_label" VALUES('winter',NULL); -INSERT INTO "season_label" VALUES('spring',NULL); -CREATE TABLE sector_label -( - sector TEXT PRIMARY KEY, - notes TEXT -); -CREATE TABLE storage_duration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "storage_duration" VALUES('regionA','BATT_GRID',2.0,'2 hours energy storage'); -INSERT INTO "storage_duration" VALUES('regionB','BATT_GRID',2.0,'2 hours energy storage'); -CREATE TABLE tech_group -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE tech_group_member -( - group_name TEXT - REFERENCES tech_group (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technology_type (label) -); -INSERT INTO "technology" VALUES('IMPORT_LI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'lithium importer'); -INSERT INTO "technology" VALUES('IMPORT_CO','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'cobalt importer'); -INSERT INTO "technology" VALUES('IMPORT_P','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'phosphorous importer'); -INSERT INTO "technology" VALUES('CAR_BEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - battery electric'); -INSERT INTO "technology" VALUES('CAR_PHEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - plug in hybrid'); -INSERT INTO "technology" VALUES('CAR_ICE','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - internal combustion'); -INSERT INTO "technology" VALUES('RECYCLE_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'nmc battery recycler'); -INSERT INTO "technology" VALUES('RECYCLE_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'lfp battery recycler'); -INSERT INTO "technology" VALUES('MANUFAC_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'nmc battery manufacturing'); -INSERT INTO "technology" VALUES('MANUFAC_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'lfp battery manufacturing'); -INSERT INTO "technology" VALUES('IMPORT_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'nickel importer'); -INSERT INTO "technology" VALUES('DOMESTIC_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'domestic nickel production'); -INSERT INTO "technology" VALUES('GEN_DSL','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,'diesel generators'); -INSERT INTO "technology" VALUES('SOL_PV','p','electricity',NULL,NULL,0,0,0,1,0,0,0,0,'solar panels'); -INSERT INTO "technology" VALUES('BATT_GRID','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,0,'grid battery storage'); -INSERT INTO "technology" VALUES('FURNACE','p','residential',NULL,NULL,1,0,0,0,0,0,0,0,'diesel furnace heater'); -INSERT INTO "technology" VALUES('HEATPUMP','p','residential',NULL,NULL,1,0,0,0,0,0,0,0,'heat pump'); -INSERT INTO "technology" VALUES('IMPORT_DSL','p','fuels',NULL,NULL,1,1,0,0,0,0,0,0,'diesel importer'); -INSERT INTO "technology" VALUES('ELEC_INTERTIE','p','electricity',NULL,NULL,0,0,0,0,0,0,1,0,'dummy tech to make landfill feasible'); -CREATE TABLE technology_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "technology_type" VALUES('p','production technology'); -INSERT INTO "technology_type" VALUES('pb','baseload production technology'); -INSERT INTO "technology_type" VALUES('ps','storage production technology'); -CREATE TABLE time_of_day -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY -); -INSERT INTO "time_of_day" VALUES(1,'morning'); -INSERT INTO "time_of_day" VALUES(2,'afternoon'); -INSERT INTO "time_of_day" VALUES(3,'evening'); -INSERT INTO "time_of_day" VALUES(4,'overnight'); -CREATE TABLE time_period -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES time_period_type (label) -); -INSERT INTO "time_period" VALUES(1,1990,'e'); -INSERT INTO "time_period" VALUES(2,2000,'f'); -INSERT INTO "time_period" VALUES(3,2010,'f'); -INSERT INTO "time_period" VALUES(4,2020,'f'); -INSERT INTO "time_period" VALUES(5,2030,'f'); -CREATE TABLE time_period_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "time_period_type" VALUES('e','existing vintages'); -INSERT INTO "time_period_type" VALUES('f','future'); -CREATE TABLE time_season -( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - season TEXT REFERENCES season_label(season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); -INSERT INTO "time_season" VALUES(2000,1,'summer',NULL); -INSERT INTO "time_season" VALUES(2000,2,'autumn',NULL); -INSERT INTO "time_season" VALUES(2000,3,'winter',NULL); -INSERT INTO "time_season" VALUES(2000,4,'spring',NULL); -INSERT INTO "time_season" VALUES(2010,5,'summer',NULL); -INSERT INTO "time_season" VALUES(2010,6,'autumn',NULL); -INSERT INTO "time_season" VALUES(2010,7,'winter',NULL); -INSERT INTO "time_season" VALUES(2010,8,'spring',NULL); -INSERT INTO "time_season" VALUES(2020,9,'summer',NULL); -INSERT INTO "time_season" VALUES(2020,10,'autumn',NULL); -INSERT INTO "time_season" VALUES(2020,11,'winter',NULL); -INSERT INTO "time_season" VALUES(2020,12,'spring',NULL); - -CREATE TABLE time_season_sequential -( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT REFERENCES season_label(season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); - -CREATE TABLE time_segment_fraction -( - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - segment_fraction REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); -INSERT INTO "time_segment_fraction" VALUES(2000,'summer','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'autumn','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'winter','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'spring','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'summer','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'autumn','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'winter','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'spring','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'summer','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'autumn','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'winter','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'spring','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'summer','overnight',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'autumn','overnight',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'winter','overnight',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'spring','overnight',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'summer','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'autumn','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'winter','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'spring','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'summer','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'autumn','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'winter','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'spring','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'summer','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'autumn','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'winter','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'spring','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'summer','overnight',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'autumn','overnight',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'winter','overnight',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'spring','overnight',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'summer','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'autumn','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'winter','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'spring','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'summer','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'autumn','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'winter','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'spring','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'summer','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'autumn','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'winter','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'spring','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'summer','overnight',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'autumn','overnight',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'winter','overnight',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'spring','overnight',0.0625,NULL); -CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); -COMMIT; +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'summer','morning','SOL_PV',0.3,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'autumn','morning','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'winter','morning','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'spring','morning','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'summer','afternoon','SOL_PV',0.3,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'autumn','afternoon','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'winter','afternoon','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'spring','afternoon','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'summer','evening','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'autumn','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'winter','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'spring','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'summer','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'autumn','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'winter','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'spring','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'summer','morning','SOL_PV',0.3,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'autumn','morning','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'winter','morning','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'spring','morning','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'summer','afternoon','SOL_PV',0.3,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'autumn','afternoon','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'winter','afternoon','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'spring','afternoon','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'summer','evening','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'autumn','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'winter','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'spring','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'summer','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'autumn','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'winter','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'spring','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'summer','morning','SOL_PV',0.3,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'autumn','morning','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'winter','morning','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'spring','morning','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'summer','afternoon','SOL_PV',0.3,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'autumn','afternoon','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'winter','afternoon','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'spring','afternoon','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'summer','evening','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'autumn','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'winter','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'spring','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'summer','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'autumn','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'winter','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'spring','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'summer','morning','SOL_PV',0.3,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'autumn','morning','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'winter','morning','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'spring','morning','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'summer','afternoon','SOL_PV',0.3,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'autumn','afternoon','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'winter','afternoon','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'spring','afternoon','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'summer','evening','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'autumn','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'winter','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'spring','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'summer','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'autumn','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'winter','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'spring','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'summer','morning','SOL_PV',0.3,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'autumn','morning','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'winter','morning','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'spring','morning','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'summer','afternoon','SOL_PV',0.3,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'autumn','afternoon','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'winter','afternoon','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'spring','afternoon','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'summer','evening','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'autumn','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'winter','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'spring','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'summer','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'autumn','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'winter','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'spring','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'summer','morning','SOL_PV',0.3,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'autumn','morning','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'winter','morning','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'spring','morning','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'summer','afternoon','SOL_PV',0.3,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'autumn','afternoon','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'winter','afternoon','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'spring','afternoon','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'summer','evening','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'autumn','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'winter','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'spring','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'summer','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'autumn','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'winter','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'spring','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "commodity" VALUES('ethos', 's', 'import dummy source', NULL); +REPLACE INTO "commodity" VALUES('electricity', 'p', 'grid electricity', NULL); +REPLACE INTO "commodity" VALUES('passenger_km', 'd', 'demand for passenger km', NULL); +REPLACE INTO "commodity" VALUES('battery_nmc', 'a', 'battery - lithium nickel manganese cobalt oxide', NULL); +REPLACE INTO "commodity" VALUES('battery_lfp', 'a', 'battery - lithium iron phosphate', NULL); +REPLACE INTO "commodity" VALUES('lithium', 'a', 'lithium', NULL); +REPLACE INTO "commodity" VALUES('cobalt', 'a', 'cobalt', NULL); +REPLACE INTO "commodity" VALUES('phosphorous', 'a', 'phosphorous', NULL); +REPLACE INTO "commodity" VALUES('diesel', 'a', 'diesel', NULL); +REPLACE INTO "commodity" VALUES('heating', 'd', 'demand for residential heating', NULL); +REPLACE INTO "commodity" VALUES('nickel', 'a', 'nickel', NULL); +REPLACE INTO "commodity" VALUES('used_batt_nmc', 'wa', 'used battery - lithium nickel manganese cobalt oxide', NULL); +REPLACE INTO "commodity" VALUES('used_batt_lfp', 'wa', 'used battery - lithium iron phosphate', NULL); +REPLACE INTO "commodity" VALUES('co2e', 'e', 'emitted co2-equivalent GHGs', NULL); +REPLACE INTO "commodity" VALUES('waste_steel', 'w', 'waste steel from cars', NULL); +REPLACE INTO "commodity_type" VALUES('w','waste commodity'); +REPLACE INTO "commodity_type" VALUES('wa','waste annual commodity'); +REPLACE INTO "commodity_type" VALUES('wp','waste physical commodity'); +REPLACE INTO "commodity_type" VALUES('a','annual commodity'); +REPLACE INTO "commodity_type" VALUES('p','physical commodity'); +REPLACE INTO "commodity_type" VALUES('e','emissions commodity'); +REPLACE INTO "commodity_type" VALUES('d','demand commodity'); +REPLACE INTO "commodity_type" VALUES('s','source commodity'); +REPLACE INTO "construction_input" VALUES('regionA','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); +REPLACE INTO "construction_input" VALUES('regionA','battery_lfp','CAR_PHEV',2000,0.1,NULL,NULL); +REPLACE INTO "construction_input" VALUES('regionA','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); +REPLACE INTO "construction_input" VALUES('regionA','battery_lfp','CAR_PHEV',2010,0.1,NULL,NULL); +REPLACE INTO "construction_input" VALUES('regionA','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); +REPLACE INTO "construction_input" VALUES('regionA','battery_lfp','CAR_PHEV',2020,0.1,NULL,NULL); +REPLACE INTO "construction_input" VALUES('regionB','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); +REPLACE INTO "construction_input" VALUES('regionB','battery_lfp','CAR_PHEV',2000,0.1,NULL,NULL); +REPLACE INTO "construction_input" VALUES('regionB','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); +REPLACE INTO "construction_input" VALUES('regionB','battery_lfp','CAR_PHEV',2010,0.1,NULL,NULL); +REPLACE INTO "construction_input" VALUES('regionB','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); +REPLACE INTO "construction_input" VALUES('regionB','battery_lfp','CAR_PHEV',2020,0.1,NULL,NULL); +REPLACE INTO "cost_emission" VALUES('regionA',2000,'co2e',1.0,NULL,NULL); +REPLACE INTO "cost_emission" VALUES('regionA',2010,'co2e',1.0,NULL,NULL); +REPLACE INTO "cost_emission" VALUES('regionA',2020,'co2e',1.0,NULL,NULL); +REPLACE INTO "cost_emission" VALUES('regionB',2000,'co2e',1.0,NULL,NULL); +REPLACE INTO "cost_emission" VALUES('regionB',2010,'co2e',1.0,NULL,NULL); +REPLACE INTO "cost_emission" VALUES('regionB',2020,'co2e',1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionA','CAR_BEV',2000,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionA','CAR_BEV',2010,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionA','CAR_BEV',2020,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionA','CAR_PHEV',2000,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionA','CAR_PHEV',2010,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionA','CAR_PHEV',2020,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionA','CAR_ICE',2000,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionA','CAR_ICE',2010,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionA','CAR_ICE',2020,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionA','RECYCLE_NMC',2000,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionA','RECYCLE_LFP',2000,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionA','MANUFAC_NMC',2000,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionA','MANUFAC_LFP',2000,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionA','BATT_GRID',2000,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionA','SOL_PV',2000,10.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionA','GEN_DSL',2000,2.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionB','CAR_BEV',2000,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionB','CAR_BEV',2010,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionB','CAR_BEV',2020,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionB','CAR_PHEV',2000,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionB','CAR_PHEV',2010,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionB','CAR_PHEV',2020,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionB','CAR_ICE',2000,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionB','CAR_ICE',2010,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionB','CAR_ICE',2020,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionB','RECYCLE_NMC',2000,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionB','RECYCLE_LFP',2000,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionB','MANUFAC_NMC',2000,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionB','MANUFAC_LFP',2000,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionB','BATT_GRID',2000,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionB','GEN_DSL',2000,2.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionA-regionB','ELEC_INTERTIE',2000,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionB-regionA','ELEC_INTERTIE',2000,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('regionB','SOL_PV',2000,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionA',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionA',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionA',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionA',2000,'IMPORT_LI',2000,2.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionA',2010,'IMPORT_LI',2000,2.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionA',2020,'IMPORT_LI',2000,2.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionA',2000,'IMPORT_NI',2000,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionA',2010,'IMPORT_NI',2000,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionA',2020,'IMPORT_NI',2000,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionA',2000,'IMPORT_CO',2000,5.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionA',2010,'IMPORT_CO',2000,5.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionA',2020,'IMPORT_CO',2000,5.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionA',2000,'IMPORT_P',2000,3.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionA',2010,'IMPORT_P',2000,3.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionA',2020,'IMPORT_P',2000,3.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionA',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionA',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionA',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionB',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionB',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionB',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionB',2000,'IMPORT_LI',2000,2.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionB',2010,'IMPORT_LI',2000,2.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionB',2020,'IMPORT_LI',2000,2.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionB',2000,'IMPORT_NI',2000,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionB',2010,'IMPORT_NI',2000,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionB',2020,'IMPORT_NI',2000,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionB',2000,'IMPORT_CO',2000,5.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionB',2010,'IMPORT_CO',2000,5.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionB',2020,'IMPORT_CO',2000,5.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionB',2000,'IMPORT_P',2000,3.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionB',2010,'IMPORT_P',2000,3.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionB',2020,'IMPORT_P',2000,3.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionB',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionB',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('regionB',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); +REPLACE INTO "demand" VALUES('regionA',2000,'passenger_km',1.0,NULL,NULL); +REPLACE INTO "demand" VALUES('regionA',2010,'passenger_km',1.0,NULL,NULL); +REPLACE INTO "demand" VALUES('regionA',2020,'passenger_km',1.0,NULL,NULL); +REPLACE INTO "demand" VALUES('regionA',2000,'heating',1.0,NULL,NULL); +REPLACE INTO "demand" VALUES('regionA',2010,'heating',1.0,NULL,NULL); +REPLACE INTO "demand" VALUES('regionA',2020,'heating',1.0,NULL,NULL); +REPLACE INTO "demand" VALUES('regionB',2000,'passenger_km',1.0,NULL,NULL); +REPLACE INTO "demand" VALUES('regionB',2010,'passenger_km',1.0,NULL,NULL); +REPLACE INTO "demand" VALUES('regionB',2020,'passenger_km',1.0,NULL,NULL); +REPLACE INTO "demand" VALUES('regionB',2000,'heating',1.0,NULL,NULL); +REPLACE INTO "demand" VALUES('regionB',2010,'heating',1.0,NULL,NULL); +REPLACE INTO "demand" VALUES('regionB',2020,'heating',1.0,NULL,NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'ethos', 'DOMESTIC_NI', 2000, 'nickel', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'ethos', 'IMPORT_LI', 2000, 'lithium', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'ethos', 'IMPORT_NI', 2000, 'nickel', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'ethos', 'IMPORT_CO', 2000, 'cobalt', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'ethos', 'IMPORT_P', 2000, 'phosphorous', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'used_batt_nmc', 'RECYCLE_NMC', 2000, 'battery_nmc', 0.2, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'used_batt_lfp', 'RECYCLE_LFP', 2000, 'battery_lfp', 0.2, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'lithium', 'MANUFAC_NMC', 2000, 'battery_nmc', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'nickel', 'MANUFAC_NMC', 2000, 'battery_nmc', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'cobalt', 'MANUFAC_NMC', 2000, 'battery_nmc', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'lithium', 'MANUFAC_LFP', 2000, 'battery_lfp', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'phosphorous', 'MANUFAC_LFP', 2000, 'battery_lfp', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'electricity', 'RECYCLE_NMC', 2000, 'battery_nmc', 0.001, NULL, 'Effectively zero'); +REPLACE INTO "efficiency" VALUES('regionA', 'electricity', 'RECYCLE_LFP', 2000, 'battery_lfp', 0.001, NULL, 'Effectively zero'); +REPLACE INTO "efficiency" VALUES('regionA', 'electricity', 'MANUFAC_NMC', 2000, 'battery_nmc', 0.001, NULL, 'Effectively zero'); +REPLACE INTO "efficiency" VALUES('regionA', 'electricity', 'MANUFAC_LFP', 2000, 'battery_lfp', 0.001, NULL, 'Effectively zero'); +REPLACE INTO "efficiency" VALUES('regionA', 'diesel', 'GEN_DSL', 2000, 'electricity', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'ethos', 'SOL_PV', 2000, 'electricity', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'electricity', 'BATT_GRID', 2000, 'electricity', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'ethos', 'IMPORT_DSL', 2000, 'diesel', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'diesel', 'FURNACE', 2000, 'heating', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'electricity', 'HEATPUMP', 2000, 'heating', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'electricity', 'CAR_BEV', 1990, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'electricity', 'CAR_PHEV', 1990, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'diesel', 'CAR_PHEV', 1990, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'diesel', 'CAR_ICE', 1990, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'electricity', 'CAR_BEV', 2000, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'electricity', 'CAR_PHEV', 2000, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'diesel', 'CAR_PHEV', 2000, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'diesel', 'CAR_ICE', 2000, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'electricity', 'CAR_BEV', 2010, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'electricity', 'CAR_PHEV', 2010, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'diesel', 'CAR_PHEV', 2010, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'diesel', 'CAR_ICE', 2010, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'electricity', 'CAR_BEV', 2020, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'electricity', 'CAR_PHEV', 2020, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'diesel', 'CAR_PHEV', 2020, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA', 'diesel', 'CAR_ICE', 2020, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'ethos', 'DOMESTIC_NI', 2000, 'nickel', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'ethos', 'IMPORT_LI', 2000, 'lithium', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'ethos', 'IMPORT_NI', 2000, 'nickel', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'ethos', 'IMPORT_CO', 2000, 'cobalt', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'ethos', 'IMPORT_P', 2000, 'phosphorous', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'used_batt_nmc', 'RECYCLE_NMC', 2000, 'battery_nmc', 0.2, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'used_batt_lfp', 'RECYCLE_LFP', 2000, 'battery_lfp', 0.2, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'lithium', 'MANUFAC_NMC', 2000, 'battery_nmc', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'nickel', 'MANUFAC_NMC', 2000, 'battery_nmc', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'cobalt', 'MANUFAC_NMC', 2000, 'battery_nmc', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'lithium', 'MANUFAC_LFP', 2000, 'battery_lfp', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'phosphorous', 'MANUFAC_LFP', 2000, 'battery_lfp', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'electricity', 'RECYCLE_NMC', 2000, 'battery_nmc', 0.001, NULL, 'Effectively zero'); +REPLACE INTO "efficiency" VALUES('regionB', 'electricity', 'RECYCLE_LFP', 2000, 'battery_lfp', 0.001, NULL, 'Effectively zero'); +REPLACE INTO "efficiency" VALUES('regionB', 'electricity', 'MANUFAC_NMC', 2000, 'battery_nmc', 0.001, NULL, 'Effectively zero'); +REPLACE INTO "efficiency" VALUES('regionB', 'electricity', 'MANUFAC_LFP', 2000, 'battery_lfp', 0.001, NULL, 'Effectively zero'); +REPLACE INTO "efficiency" VALUES('regionB', 'diesel', 'GEN_DSL', 2000, 'electricity', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'ethos', 'SOL_PV', 2000, 'electricity', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'electricity', 'BATT_GRID', 2000, 'electricity', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'ethos', 'IMPORT_DSL', 2000, 'diesel', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'diesel', 'FURNACE', 2000, 'heating', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'electricity', 'HEATPUMP', 2000, 'heating', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'electricity', 'CAR_BEV', 1990, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'electricity', 'CAR_PHEV', 1990, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'diesel', 'CAR_PHEV', 1990, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'diesel', 'CAR_ICE', 1990, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'electricity', 'CAR_BEV', 2000, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'electricity', 'CAR_PHEV', 2000, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'diesel', 'CAR_PHEV', 2000, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'diesel', 'CAR_ICE', 2000, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'electricity', 'CAR_BEV', 2010, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'electricity', 'CAR_PHEV', 2010, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'diesel', 'CAR_PHEV', 2010, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'diesel', 'CAR_ICE', 2010, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'electricity', 'CAR_BEV', 2020, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'electricity', 'CAR_PHEV', 2020, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'diesel', 'CAR_PHEV', 2020, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB', 'diesel', 'CAR_ICE', 2020, 'passenger_km', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionA-regionB', 'electricity', 'ELEC_INTERTIE', 2000, 'electricity', 0.9, NULL, NULL); +REPLACE INTO "efficiency" VALUES('regionB-regionA', 'electricity', 'ELEC_INTERTIE', 2000, 'electricity', 0.9, NULL, NULL); +REPLACE INTO "emission_activity" VALUES('regionA','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); +REPLACE INTO "emission_activity" VALUES('regionB','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); +REPLACE INTO "end_of_life_output" VALUES('regionA','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionA','CAR_PHEV',1990,'used_batt_lfp',0.1,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionA','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionA','CAR_PHEV',2000,'used_batt_lfp',0.1,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionA','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionA','CAR_PHEV',2010,'used_batt_lfp',0.1,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionB','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionB','CAR_PHEV',1990,'used_batt_lfp',0.1,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionB','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionB','CAR_PHEV',2000,'used_batt_lfp',0.1,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionB','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionB','CAR_PHEV',2010,'used_batt_lfp',0.1,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionA','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionA','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionA','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionA','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionA','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionA','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionA','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionA','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionA','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionB','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionB','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionB','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionB','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionB','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionB','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionB','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionB','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); +REPLACE INTO "end_of_life_output" VALUES('regionB','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); +REPLACE INTO "existing_capacity" VALUES('regionA','CAR_BEV',1990,1.0,NULL,NULL); +REPLACE INTO "existing_capacity" VALUES('regionA','CAR_PHEV',1990,1.0,NULL,NULL); +REPLACE INTO "existing_capacity" VALUES('regionA','CAR_ICE',1990,1.0,NULL,NULL); +REPLACE INTO "existing_capacity" VALUES('regionB','CAR_BEV',1990,1.0,NULL,NULL); +REPLACE INTO "existing_capacity" VALUES('regionB','CAR_PHEV',1990,1.0,NULL,NULL); +REPLACE INTO "existing_capacity" VALUES('regionB','CAR_ICE',1990,1.0,NULL,NULL); +REPLACE INTO "lifetime_tech" VALUES('regionA', 'CAR_BEV', 10.0, NULL, NULL); +REPLACE INTO "lifetime_tech" VALUES('regionA', 'CAR_PHEV', 10.0, NULL, NULL); +REPLACE INTO "lifetime_tech" VALUES('regionA', 'CAR_ICE', 10.0, NULL, NULL); +REPLACE INTO "lifetime_tech" VALUES('regionB', 'CAR_BEV', 10.0, NULL, NULL); +REPLACE INTO "lifetime_tech" VALUES('regionB', 'CAR_PHEV', 10.0, NULL, NULL); +REPLACE INTO "lifetime_tech" VALUES('regionB', 'CAR_ICE', 10.0, NULL, NULL); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'lithium','MANUFAC_NMC','le',0.8,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'nickel','MANUFAC_NMC','le',0.15,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'cobalt','MANUFAC_NMC','le',0.04,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'electricity','MANUFAC_NMC','le',0.01,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'lithium','MANUFAC_LFP','le',0.8,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'phosphorous','MANUFAC_LFP','le',0.19,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'electricity','MANUFAC_LFP','le',0.01,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'lithium','MANUFAC_NMC','le',0.8,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'nickel','MANUFAC_NMC','le',0.15,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'cobalt','MANUFAC_NMC','le',0.04,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'electricity','MANUFAC_NMC','le',0.01,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'lithium','MANUFAC_LFP','le',0.8,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'phosphorous','MANUFAC_LFP','le',0.19,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'electricity','MANUFAC_LFP','le',0.01,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'lithium','MANUFAC_NMC','le',0.8,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'nickel','MANUFAC_NMC','le',0.15,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'cobalt','MANUFAC_NMC','le',0.04,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'electricity','MANUFAC_NMC','le',0.01,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'lithium','MANUFAC_LFP','le',0.8,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'phosphorous','MANUFAC_LFP','le',0.19,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'electricity','MANUFAC_LFP','le',0.01,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'electricity','CAR_PHEV','le',0.2,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2000,'diesel','CAR_PHEV','le',0.8,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'electricity','CAR_PHEV','le',0.2,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2010,'diesel','CAR_PHEV','le',0.8,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'electricity','CAR_PHEV','le',0.2,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionA',2020,'diesel','CAR_PHEV','le',0.8,NULL); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'lithium','MANUFAC_NMC','le',0.8,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'nickel','MANUFAC_NMC','le',0.15,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'cobalt','MANUFAC_NMC','le',0.04,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'electricity','MANUFAC_NMC','le',0.01,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'lithium','MANUFAC_LFP','le',0.8,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'phosphorous','MANUFAC_LFP','le',0.19,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'electricity','MANUFAC_LFP','le',0.01,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'lithium','MANUFAC_NMC','le',0.8,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'nickel','MANUFAC_NMC','le',0.15,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'cobalt','MANUFAC_NMC','le',0.04,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'electricity','MANUFAC_NMC','le',0.01,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'lithium','MANUFAC_LFP','le',0.8,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'phosphorous','MANUFAC_LFP','le',0.19,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'electricity','MANUFAC_LFP','le',0.01,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'lithium','MANUFAC_NMC','le',0.8,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'nickel','MANUFAC_NMC','le',0.15,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'cobalt','MANUFAC_NMC','le',0.04,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'electricity','MANUFAC_NMC','le',0.01,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'lithium','MANUFAC_LFP','le',0.8,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'phosphorous','MANUFAC_LFP','le',0.19,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'electricity','MANUFAC_LFP','le',0.01,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'electricity','CAR_PHEV','le',0.2,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2000,'diesel','CAR_PHEV','le',0.8,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'electricity','CAR_PHEV','le',0.2,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'diesel','CAR_PHEV','le',0.8,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'electricity','CAR_PHEV','le',0.2,''); +REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'diesel','CAR_PHEV','le',0.8,NULL); +REPLACE INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +REPLACE INTO "metadata" VALUES('DB_MAJOR',4,''); +REPLACE INTO "metadata" VALUES('DB_MINOR',0,''); +REPLACE INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +REPLACE INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +REPLACE INTO "operator" VALUES('e','equal to'); +REPLACE INTO "operator" VALUES('le','less than or equal to'); +REPLACE INTO "operator" VALUES('ge','greater than or equal to'); +REPLACE INTO "region" VALUES('regionA',NULL); +REPLACE INTO "region" VALUES('regionB',NULL); +REPLACE INTO "season_label" VALUES('summer',NULL); +REPLACE INTO "season_label" VALUES('autumn',NULL); +REPLACE INTO "season_label" VALUES('winter',NULL); +REPLACE INTO "season_label" VALUES('spring',NULL); +REPLACE INTO "storage_duration" VALUES('regionA','BATT_GRID',2.0,'2 hours energy storage'); +REPLACE INTO "storage_duration" VALUES('regionB','BATT_GRID',2.0,'2 hours energy storage'); +REPLACE INTO "technology" VALUES('IMPORT_LI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'lithium importer'); +REPLACE INTO "technology" VALUES('IMPORT_CO','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'cobalt importer'); +REPLACE INTO "technology" VALUES('IMPORT_P','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'phosphorous importer'); +REPLACE INTO "technology" VALUES('CAR_BEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - battery electric'); +REPLACE INTO "technology" VALUES('CAR_PHEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - plug in hybrid'); +REPLACE INTO "technology" VALUES('CAR_ICE','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - internal combustion'); +REPLACE INTO "technology" VALUES('RECYCLE_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'nmc battery recycler'); +REPLACE INTO "technology" VALUES('RECYCLE_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'lfp battery recycler'); +REPLACE INTO "technology" VALUES('MANUFAC_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'nmc battery manufacturing'); +REPLACE INTO "technology" VALUES('MANUFAC_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'lfp battery manufacturing'); +REPLACE INTO "technology" VALUES('IMPORT_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'nickel importer'); +REPLACE INTO "technology" VALUES('DOMESTIC_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'domestic nickel production'); +REPLACE INTO "technology" VALUES('GEN_DSL','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,'diesel generators'); +REPLACE INTO "technology" VALUES('SOL_PV','p','electricity',NULL,NULL,0,0,0,1,0,0,0,0,'solar panels'); +REPLACE INTO "technology" VALUES('BATT_GRID','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,0,'grid battery storage'); +REPLACE INTO "technology" VALUES('FURNACE','p','residential',NULL,NULL,1,0,0,0,0,0,0,0,'diesel furnace heater'); +REPLACE INTO "technology" VALUES('HEATPUMP','p','residential',NULL,NULL,1,0,0,0,0,0,0,0,'heat pump'); +REPLACE INTO "technology" VALUES('IMPORT_DSL','p','fuels',NULL,NULL,1,1,0,0,0,0,0,0,'diesel importer'); +REPLACE INTO "technology" VALUES('ELEC_INTERTIE','p','electricity',NULL,NULL,0,0,0,0,0,0,1,0,'dummy tech to make landfill feasible'); +REPLACE INTO "technology_type" VALUES('p','production technology'); +REPLACE INTO "technology_type" VALUES('pb','baseload production technology'); +REPLACE INTO "technology_type" VALUES('ps','storage production technology'); +REPLACE INTO "time_of_day" VALUES(1,'morning'); +REPLACE INTO "time_of_day" VALUES(2,'afternoon'); +REPLACE INTO "time_of_day" VALUES(3,'evening'); +REPLACE INTO "time_of_day" VALUES(4,'overnight'); +REPLACE INTO "time_period" VALUES(1,1990,'e'); +REPLACE INTO "time_period" VALUES(2,2000,'f'); +REPLACE INTO "time_period" VALUES(3,2010,'f'); +REPLACE INTO "time_period" VALUES(4,2020,'f'); +REPLACE INTO "time_period" VALUES(5,2030,'f'); +REPLACE INTO "time_period_type" VALUES('e','existing vintages'); +REPLACE INTO "time_period_type" VALUES('f','future'); +REPLACE INTO "time_season" VALUES(2000,1,'summer',NULL); +REPLACE INTO "time_season" VALUES(2000,2,'autumn',NULL); +REPLACE INTO "time_season" VALUES(2000,3,'winter',NULL); +REPLACE INTO "time_season" VALUES(2000,4,'spring',NULL); +REPLACE INTO "time_season" VALUES(2010,5,'summer',NULL); +REPLACE INTO "time_season" VALUES(2010,6,'autumn',NULL); +REPLACE INTO "time_season" VALUES(2010,7,'winter',NULL); +REPLACE INTO "time_season" VALUES(2010,8,'spring',NULL); +REPLACE INTO "time_season" VALUES(2020,9,'summer',NULL); +REPLACE INTO "time_season" VALUES(2020,10,'autumn',NULL); +REPLACE INTO "time_season" VALUES(2020,11,'winter',NULL); +REPLACE INTO "time_season" VALUES(2020,12,'spring',NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'summer','morning',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'autumn','morning',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'winter','morning',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'spring','morning',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'summer','afternoon',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'autumn','afternoon',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'winter','afternoon',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'spring','afternoon',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'summer','evening',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'autumn','evening',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'winter','evening',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'spring','evening',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'summer','overnight',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'autumn','overnight',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'winter','overnight',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'spring','overnight',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2010,'summer','morning',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2010,'autumn','morning',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2010,'winter','morning',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2010,'spring','morning',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2010,'summer','afternoon',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2010,'autumn','afternoon',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2010,'winter','afternoon',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2010,'spring','afternoon',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2010,'summer','evening',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2010,'autumn','evening',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2010,'winter','evening',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2010,'spring','evening',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2010,'summer','overnight',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2010,'autumn','overnight',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2010,'winter','overnight',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2010,'spring','overnight',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2020,'summer','morning',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2020,'autumn','morning',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2020,'winter','morning',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2020,'spring','morning',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2020,'summer','afternoon',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2020,'autumn','afternoon',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2020,'winter','afternoon',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2020,'spring','afternoon',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2020,'summer','evening',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2020,'autumn','evening',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2020,'winter','evening',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2020,'spring','evening',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2020,'summer','overnight',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2020,'autumn','overnight',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2020,'winter','overnight',0.0625,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2020,'spring','overnight',0.0625,NULL); diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index 6a1cd6ca7..dcd0f59bd 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -1,1224 +1,198 @@ -BEGIN TRANSACTION; -CREATE TABLE capacity_credit -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -INSERT INTO "capacity_credit" VALUES('A',2025,'EF',2025,0.6,NULL); -CREATE TABLE capacity_factor_process -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -INSERT INTO "capacity_factor_process" VALUES('A',2025,'s2','d1','EFL',2025,0.8,NULL); -INSERT INTO "capacity_factor_process" VALUES('A',2025,'s1','d2','EFL',2025,0.9,NULL); -CREATE TABLE capacity_factor_tech -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -INSERT INTO "capacity_factor_tech" VALUES('A',2025,'s1','d1','EF',0.8,NULL); -INSERT INTO "capacity_factor_tech" VALUES('B',2025,'s2','d2','bulbs',0.75,NULL); -CREATE TABLE capacity_to_activity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "capacity_to_activity" VALUES('A','bulbs',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('B','bulbs',1.0,NULL); -CREATE TABLE commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES commodity_type (label), - description TEXT -); -INSERT INTO "commodity" VALUES('ELC','p','electricity'); -INSERT INTO "commodity" VALUES('HYD','p','water'); -INSERT INTO "commodity" VALUES('co2','e','CO2 emissions'); -INSERT INTO "commodity" VALUES('RL','d','residential lighting'); -INSERT INTO "commodity" VALUES('earth','s','the source of stuff'); -INSERT INTO "commodity" VALUES('RH','d','residential heat'); -INSERT INTO "commodity" VALUES('FusionGas','e','mystery emission'); -INSERT INTO "commodity" VALUES('FusionGasFuel','p','converted mystery gas to fuel'); -INSERT INTO "commodity" VALUES('GeoHyd','p','Hot water from geo'); -CREATE TABLE commodity_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "commodity_type" VALUES('w','waste commodity'); -INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); -INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); -INSERT INTO "commodity_type" VALUES('a','annual commodity'); -INSERT INTO "commodity_type" VALUES('p','physical commodity'); -INSERT INTO "commodity_type" VALUES('e','emissions commodity'); -INSERT INTO "commodity_type" VALUES('d','demand commodity'); -INSERT INTO "commodity_type" VALUES('s','source commodity'); -CREATE TABLE construction_input -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage) -); -CREATE TABLE cost_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT NOT NULL - REFERENCES commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -INSERT INTO "cost_emission" VALUES('A',2025,'co2',1.99,'dollars','none'); -CREATE TABLE cost_fixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_fixed" VALUES('A',2025,'EH',2025,3.3,'',''); -INSERT INTO "cost_fixed" VALUES('A',2025,'EF',2025,2.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('A',2025,'EFL',2025,3.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('B',2025,'batt',2025,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('B',2025,'EF',2025,2.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('A',2025,'bulbs',2025,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('B',2025,'bulbs',2025,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('A',2025,'heater',2025,2.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('B',2025,'heater',2025,2.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('B',2025,'GeoThermal',2025,6.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('B',2025,'GeoHeater',2025,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('B',2025,'EH',2025,3.3,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('A',2025,'GeoThermal',2025,4.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('A',2025,'GeoHeater',2025,4.5,NULL,NULL); -CREATE TABLE cost_invest -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "cost_invest" VALUES('A','EF',2025,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('A','EH',2025,3.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('A','bulbs',2025,4.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('A','heater',2025,5.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('B','EF',2025,6.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('B','batt',2025,7.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('B','bulbs',2025,8.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('B','heater',2025,9.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('A','EFL',2025,2.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('B','GeoThermal',2025,3.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('B','GeoHeater',2025,4.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('B','EH',2025,3.3,NULL,NULL); -INSERT INTO "cost_invest" VALUES('A','GeoThermal',2025,5.6,NULL,NULL); -INSERT INTO "cost_invest" VALUES('A','GeoHeater',2025,4.2,NULL,NULL); -CREATE TABLE cost_variable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_variable" VALUES('A',2025,'EF',2025,9.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('A',2025,'EFL',2025,8.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('A',2025,'EH',2025,7.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('A',2025,'bulbs',2025,6.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('A',2025,'heater',2025,5.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('B',2025,'EF',2025,4.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('B',2025,'batt',2025,3.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('B',2025,'bulbs',2025,2.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('B',2025,'heater',2025,1.0,NULL,NULL); -CREATE TABLE demand -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - commodity TEXT - REFERENCES commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -INSERT INTO "demand" VALUES('A',2025,'RL',100.0,'',''); -INSERT INTO "demand" VALUES('B',2025,'RL',100.0,NULL,NULL); -INSERT INTO "demand" VALUES('A',2025,'RH',50.0,NULL,NULL); -INSERT INTO "demand" VALUES('B',2025,'RH',50.0,NULL,NULL); -CREATE TABLE demand_specific_distribution -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - demand_name TEXT - REFERENCES commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -INSERT INTO "demand_specific_distribution" VALUES('A',2025,'s1','d1','RL',0.25,NULL); -INSERT INTO "demand_specific_distribution" VALUES('A',2025,'s1','d2','RL',0.25,NULL); -INSERT INTO "demand_specific_distribution" VALUES('A',2025,'s2','d1','RL',0.25,NULL); -INSERT INTO "demand_specific_distribution" VALUES('A',2025,'s2','d2','RL',0.25,NULL); -INSERT INTO "demand_specific_distribution" VALUES('B',2025,'s1','d1','RL',0.25,NULL); -INSERT INTO "demand_specific_distribution" VALUES('B',2025,'s1','d2','RL',0.25,NULL); -INSERT INTO "demand_specific_distribution" VALUES('B',2025,'s2','d1','RL',0.25,NULL); -INSERT INTO "demand_specific_distribution" VALUES('B',2025,'s2','d2','RL',0.25,NULL); -INSERT INTO "demand_specific_distribution" VALUES('A',2025,'s1','d1','RH',0.25,NULL); -INSERT INTO "demand_specific_distribution" VALUES('A',2025,'s2','d1','RH',0.25,NULL); -INSERT INTO "demand_specific_distribution" VALUES('B',2025,'s1','d1','RH',0.25,NULL); -INSERT INTO "demand_specific_distribution" VALUES('B',2025,'s2','d1','RH',0.25,NULL); -INSERT INTO "demand_specific_distribution" VALUES('A',2025,'s1','d2','RH',0.25,NULL); -INSERT INTO "demand_specific_distribution" VALUES('A',2025,'s2','d2','RH',0.25,NULL); -INSERT INTO "demand_specific_distribution" VALUES('B',2025,'s1','d2','RH',0.25,NULL); -INSERT INTO "demand_specific_distribution" VALUES('B',2025,'s2','d2','RH',0.25,NULL); -CREATE TABLE efficiency -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -INSERT INTO "efficiency" VALUES('A','ELC','bulbs',2025,'RL',1.0,NULL); -INSERT INTO "efficiency" VALUES('A','HYD','EH',2025,'ELC',1.0,NULL); -INSERT INTO "efficiency" VALUES('A','HYD','EF',2025,'ELC',1.0,NULL); -INSERT INTO "efficiency" VALUES('B','ELC','bulbs',2025,'RL',1.0,NULL); -INSERT INTO "efficiency" VALUES('B','HYD','EH',2025,'ELC',1.0,NULL); -INSERT INTO "efficiency" VALUES('B','ELC','batt',2025,'ELC',1.0,NULL); -INSERT INTO "efficiency" VALUES('B','HYD','EF',2025,'ELC',1.0,NULL); -INSERT INTO "efficiency" VALUES('A','earth','well',2025,'HYD',1.0,NULL); -INSERT INTO "efficiency" VALUES('B','earth','well',2025,'HYD',1.0,NULL); -INSERT INTO "efficiency" VALUES('A','earth','EFL',2025,'FusionGasFuel',1.0,NULL); -INSERT INTO "efficiency" VALUES('A','FusionGasFuel','heater',2025,'RH',0.9,NULL); -INSERT INTO "efficiency" VALUES('A-B','FusionGasFuel','FGF_pipe',2025,'FusionGasFuel',0.95,NULL); -INSERT INTO "efficiency" VALUES('B','FusionGasFuel','heater',2025,'RH',0.9,NULL); -INSERT INTO "efficiency" VALUES('B','GeoHyd','GeoHeater',2025,'RH',9.80000000000000093e-01,NULL); -INSERT INTO "efficiency" VALUES('B','earth','GeoThermal',2025,'GeoHyd',1.0,NULL); -INSERT INTO "efficiency" VALUES('B-A','FusionGasFuel','FGF_pipe',2025,'FusionGasFuel',0.95,NULL); -INSERT INTO "efficiency" VALUES('A','GeoHyd','GeoHeater',2025,'RH',0.9,NULL); -INSERT INTO "efficiency" VALUES('A','earth','GeoThermal',2025,'GeoHyd',1.0,NULL); -CREATE TABLE efficiency_variable -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE emission_activity -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -INSERT INTO "emission_activity" VALUES('A','co2','HYD','EH',2025,'ELC',0.02,NULL,NULL); -INSERT INTO "emission_activity" VALUES('A','FusionGas','HYD','EF',2025,'ELC',-0.2,NULL,'needs to be negative as a driver of linked tech...don''t ask'); -CREATE TABLE emission_embodied -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE emission_end_of_life -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -CREATE TABLE existing_capacity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "existing_capacity" VALUES('A','EH',2020,200.0,'things',NULL); -CREATE TABLE lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "lifetime_process" VALUES('B','EF',2025,200.0,NULL); -CREATE TABLE lifetime_survival_curve -( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE lifetime_tech -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "lifetime_tech" VALUES('A','EH',60.0,''); -INSERT INTO "lifetime_tech" VALUES('B','bulbs',100.0,'super LED!'); -CREATE TABLE limit_activity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -INSERT INTO "limit_activity" VALUES('A',2025,'EF','ge',0.001,'PJ/CY','goofy units'); -INSERT INTO "limit_activity" VALUES('B',2025,'EH','le',10000.0,'stuff',NULL); -INSERT INTO "limit_activity" VALUES('A',2025,'EF','le',10000.0,'stuff',NULL); -INSERT INTO "limit_activity" VALUES('A',2025,'A_tech_grp_1','ge',0.05,'',NULL); -INSERT INTO "limit_activity" VALUES('A',2025,'A_tech_grp_1','le',10000.0,'',NULL); -CREATE TABLE limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -INSERT INTO "limit_capacity" VALUES('A',2025,'EH','ge',0.1,'',''); -INSERT INTO "limit_capacity" VALUES('B',2025,'batt','ge',0.1,'',''); -INSERT INTO "limit_capacity" VALUES('A',2025,'EH','le',20000.0,'',''); -INSERT INTO "limit_capacity" VALUES('B',2025,'EH','le',20000.0,'',''); -INSERT INTO "limit_capacity" VALUES('A',2025,'A_tech_grp_1','ge',0.2,'',NULL); -INSERT INTO "limit_capacity" VALUES('A',2025,'A_tech_grp_1','le',6000.0,'',NULL); -CREATE TABLE limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_degrowth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -INSERT INTO "limit_emission" VALUES('A',2025,'co2','le',10000.0,'gulps',NULL); -CREATE TABLE limit_growth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -INSERT INTO "limit_new_capacity_share" VALUES('A',2025,'RPS_common','A_tech_grp_1','ge',0.0,''); -INSERT INTO "limit_new_capacity_share" VALUES('global',2025,'RPS_common','A_tech_grp_1','le',1.0,''); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -INSERT INTO "limit_resource" VALUES('B','EF','le',9000.0,'clumps',NULL); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) -); -CREATE TABLE limit_storage_level_fraction -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -CREATE TABLE limit_tech_input_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -INSERT INTO "limit_tech_input_split" VALUES('A',2025,'HYD','EH','ge',0.95,'95% HYD reqt. (other not specified...)'); -CREATE TABLE limit_tech_input_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_output_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -INSERT INTO "limit_tech_output_split" VALUES('B',2025,'EH','ELC','ge',0.95,'95% ELC output (there are not others, this is a min)'); -CREATE TABLE limit_tech_output_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE linked_tech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES technology (tech), - emis_comm TEXT - REFERENCES commodity (name), - driven_tech TEXT - REFERENCES technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -INSERT INTO "linked_tech" VALUES('A','EF','FusionGas','EFL',NULL); -CREATE TABLE loan_lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "loan_lifetime_process" VALUES('A','EF',2025,57.0,NULL); -INSERT INTO "loan_lifetime_process" VALUES('A','EFL',2025,68.0,NULL); -INSERT INTO "loan_lifetime_process" VALUES('A','bulbs',2025,10.0,NULL); -INSERT INTO "loan_lifetime_process" VALUES('A','EH',2025,10.0,NULL); -INSERT INTO "loan_lifetime_process" VALUES('A','well',2025,10.0,NULL); -INSERT INTO "loan_lifetime_process" VALUES('A','heater',2025,10.0,NULL); -INSERT INTO "loan_lifetime_process" VALUES('A','GeoHeater',2025,10.0,NULL); -INSERT INTO "loan_lifetime_process" VALUES('A','GeoThermal',2025,10.0,NULL); -INSERT INTO "loan_lifetime_process" VALUES('B','EF',2025,10.0,NULL); -INSERT INTO "loan_lifetime_process" VALUES('B','bulbs',2025,10.0,NULL); -INSERT INTO "loan_lifetime_process" VALUES('B','EH',2025,10.0,NULL); -INSERT INTO "loan_lifetime_process" VALUES('B','batt',2025,10.0,NULL); -INSERT INTO "loan_lifetime_process" VALUES('B','well',2025,10.0,NULL); -INSERT INTO "loan_lifetime_process" VALUES('B','heater',2025,10.0,NULL); -INSERT INTO "loan_lifetime_process" VALUES('B','GeoHeater',2025,10.0,NULL); -INSERT INTO "loan_lifetime_process" VALUES('B','GeoThermal',2025,10.0,NULL); -INSERT INTO "loan_lifetime_process" VALUES('A-B','FGF_pipe',2025,10.0,NULL); -INSERT INTO "loan_lifetime_process" VALUES('B-A','FGF_pipe',2025,10.0,NULL); -CREATE TABLE loan_rate -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); -INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); -INSERT INTO "metadata" VALUES('DB_MINOR',0,''); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -INSERT INTO "metadata_real" VALUES('global_discount_rate',4.2000000000000004e-01,''); -CREATE TABLE myopic_efficiency -( - base_year integer, - region text, - input_comm text, - tech text, - vintage integer, - output_comm text, - efficiency real, - lifetime integer, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (region, input_comm, tech, vintage, output_comm) -); -CREATE TABLE operator -( - operator TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "operator" VALUES('e','equal to'); -INSERT INTO "operator" VALUES('le','less than or equal to'); -INSERT INTO "operator" VALUES('ge','greater than or equal to'); -CREATE TABLE output_built_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES sector_label (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) -); -CREATE TABLE output_curtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_period (period), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE output_emission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE output_flow_in -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out_summary -( - scenario TEXT NOT NULL, - region TEXT NOT NULL, - sector TEXT, - period INTEGER, - input_comm TEXT NOT NULL, - tech TEXT NOT NULL, - vintage INTEGER, - output_comm TEXT NOT NULL, - flow REAL NOT NULL, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_net_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_objective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE output_retired_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_storage_level -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE planning_reserve_margin -( - region TEXT - PRIMARY KEY - REFERENCES region (region), - margin REAL, - notes TEXT -); -INSERT INTO "planning_reserve_margin" VALUES('A',0.05,NULL); -CREATE TABLE ramp_down_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "ramp_down_hourly" VALUES('A','EH',0.05,NULL); -INSERT INTO "ramp_down_hourly" VALUES('B','EH',0.05,NULL); -CREATE TABLE ramp_up_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "ramp_up_hourly" VALUES('B','EH',0.05,NULL); -INSERT INTO "ramp_up_hourly" VALUES('A','EH',0.05,NULL); -CREATE TABLE region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -INSERT INTO "region" VALUES('A','main region'); -INSERT INTO "region" VALUES('B','just a 2nd region'); -CREATE TABLE reserve_capacity_derate -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE rps_requirement -( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL - REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES tech_group (group_name), - requirement REAL NOT NULL, - notes TEXT -); -INSERT INTO "rps_requirement" VALUES('B',2025,'RPS_common',0.3,NULL); -CREATE TABLE season_label -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "season_label" VALUES('s1',NULL); -INSERT INTO "season_label" VALUES('s2',NULL); -CREATE TABLE sector_label -( - sector TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "sector_label" VALUES('supply',NULL); -INSERT INTO "sector_label" VALUES('electric',NULL); -INSERT INTO "sector_label" VALUES('transport',NULL); -INSERT INTO "sector_label" VALUES('commercial',NULL); -INSERT INTO "sector_label" VALUES('residential',NULL); -INSERT INTO "sector_label" VALUES('industrial',NULL); -CREATE TABLE storage_duration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "storage_duration" VALUES('B','batt',15.0,NULL); -CREATE TABLE tech_group -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -INSERT INTO "tech_group" VALUES('RPS_common',''); -INSERT INTO "tech_group" VALUES('A_tech_grp_1','converted from old db'); -CREATE TABLE tech_group_member -( - group_name TEXT - REFERENCES tech_group (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -INSERT INTO "tech_group_member" VALUES('RPS_common','EF'); -INSERT INTO "tech_group_member" VALUES('A_tech_grp_1','EH'); -INSERT INTO "tech_group_member" VALUES('A_tech_grp_1','EF'); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technology_type (label) -); -INSERT INTO "technology" VALUES('well','p','supply','water','',0,0,0,0,0,0,0,0,'plain old water'); -INSERT INTO "technology" VALUES('bulbs','p','residential','electric','',0,0,0,0,0,0,0,0,'residential lighting'); -INSERT INTO "technology" VALUES('EH','pb','electric','hydro','',0,0,0,1,1,0,0,0,'hydro power electric plant'); -INSERT INTO "technology" VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0,0,'big battery'); -INSERT INTO "technology" VALUES('EF','p','electric','electric','',0,0,1,0,0,0,0,0,'fusion plant'); -INSERT INTO "technology" VALUES('EFL','p','electric','electric','',0,0,0,0,0,1,0,0,'linked (to Fusion) producer'); -INSERT INTO "technology" VALUES('heater','p','residential','electric','',0,0,0,0,0,0,0,0,'heater'); -INSERT INTO "technology" VALUES('FGF_pipe','p','transport',NULL,'',0,0,0,0,0,0,1,0,'transportation line A->B'); -INSERT INTO "technology" VALUES('GeoThermal','p','residential','hydro','',0,1,0,0,0,0,0,0,'geothermal hot water source'); -INSERT INTO "technology" VALUES('GeoHeater','p','residential','hydro','',0,0,0,0,0,0,0,0,'geothermal heater from geo hyd'); -CREATE TABLE technology_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "technology_type" VALUES('p','production technology'); -INSERT INTO "technology_type" VALUES('pb','baseload production technology'); -INSERT INTO "technology_type" VALUES('ps','storage production technology'); -CREATE TABLE time_of_day -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY -); -INSERT INTO "time_of_day" VALUES(1,'d1'); -INSERT INTO "time_of_day" VALUES(2,'d2'); -CREATE TABLE time_period -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES time_period_type (label) -); -INSERT INTO "time_period" VALUES(1,2020,'e'); -INSERT INTO "time_period" VALUES(2,2025,'f'); -INSERT INTO "time_period" VALUES(3,2030,'f'); -CREATE TABLE time_period_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "time_period_type" VALUES('e','existing vintages'); -INSERT INTO "time_period_type" VALUES('f','future'); -CREATE TABLE time_season -( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - season TEXT REFERENCES season_label(season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); -INSERT INTO "time_season" VALUES(2025,1,'s1',NULL); -INSERT INTO "time_season" VALUES(2025,2,'s2',NULL); - -CREATE TABLE time_season_sequential -( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT REFERENCES season_label(season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); - -CREATE TABLE time_segment_fraction -( - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - segment_fraction REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); -INSERT INTO "time_segment_fraction" VALUES(2025,'s2','d1',0.25,NULL); -INSERT INTO "time_segment_fraction" VALUES(2025,'s2','d2',0.25,NULL); -INSERT INTO "time_segment_fraction" VALUES(2025,'s1','d1',0.25,NULL); -INSERT INTO "time_segment_fraction" VALUES(2025,'s1','d2',0.25,NULL); -CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); -COMMIT; +REPLACE INTO "capacity_credit" VALUES('A',2025,'EF',2025,0.6,NULL); +REPLACE INTO "capacity_factor_process" VALUES('A',2025,'s2','d1','EFL',2025,0.8,NULL); +REPLACE INTO "capacity_factor_process" VALUES('A',2025,'s1','d2','EFL',2025,0.9,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('A',2025,'s1','d1','EF',0.8,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('B',2025,'s2','d2','bulbs',0.75,NULL); +REPLACE INTO "capacity_to_activity" VALUES('A', 'bulbs', 1.0, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('B', 'bulbs', 1.0, NULL, NULL); +REPLACE INTO "commodity" VALUES('ELC', 'p', 'electricity', NULL); +REPLACE INTO "commodity" VALUES('HYD', 'p', 'water', NULL); +REPLACE INTO "commodity" VALUES('co2', 'e', 'CO2 emissions', NULL); +REPLACE INTO "commodity" VALUES('RL', 'd', 'residential lighting', NULL); +REPLACE INTO "commodity" VALUES('earth', 's', 'the source of stuff', NULL); +REPLACE INTO "commodity" VALUES('RH', 'd', 'residential heat', NULL); +REPLACE INTO "commodity" VALUES('FusionGas', 'e', 'mystery emission', NULL); +REPLACE INTO "commodity" VALUES('FusionGasFuel', 'p', 'converted mystery gas to fuel', NULL); +REPLACE INTO "commodity" VALUES('GeoHyd', 'p', 'Hot water from geo', NULL); +REPLACE INTO "commodity_type" VALUES('w','waste commodity'); +REPLACE INTO "commodity_type" VALUES('wa','waste annual commodity'); +REPLACE INTO "commodity_type" VALUES('wp','waste physical commodity'); +REPLACE INTO "commodity_type" VALUES('a','annual commodity'); +REPLACE INTO "commodity_type" VALUES('p','physical commodity'); +REPLACE INTO "commodity_type" VALUES('e','emissions commodity'); +REPLACE INTO "commodity_type" VALUES('d','demand commodity'); +REPLACE INTO "commodity_type" VALUES('s','source commodity'); +REPLACE INTO "cost_emission" VALUES('A',2025,'co2',1.99,'dollars','none'); +REPLACE INTO "cost_fixed" VALUES('A',2025,'EH',2025,3.3,'',''); +REPLACE INTO "cost_fixed" VALUES('A',2025,'EF',2025,2.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('A',2025,'EFL',2025,3.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('B',2025,'batt',2025,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('B',2025,'EF',2025,2.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('A',2025,'bulbs',2025,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('B',2025,'bulbs',2025,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('A',2025,'heater',2025,2.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('B',2025,'heater',2025,2.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('B',2025,'GeoThermal',2025,6.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('B',2025,'GeoHeater',2025,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('B',2025,'EH',2025,3.3,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('A',2025,'GeoThermal',2025,4.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('A',2025,'GeoHeater',2025,4.5,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('A','EF',2025,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('A','EH',2025,3.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('A','bulbs',2025,4.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('A','heater',2025,5.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('B','EF',2025,6.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('B','batt',2025,7.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('B','bulbs',2025,8.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('B','heater',2025,9.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('A','EFL',2025,2.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('B','GeoThermal',2025,3.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('B','GeoHeater',2025,4.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('B','EH',2025,3.3,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('A','GeoThermal',2025,5.6,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('A','GeoHeater',2025,4.2,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('A',2025,'EF',2025,9.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('A',2025,'EFL',2025,8.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('A',2025,'EH',2025,7.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('A',2025,'bulbs',2025,6.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('A',2025,'heater',2025,5.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('B',2025,'EF',2025,4.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('B',2025,'batt',2025,3.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('B',2025,'bulbs',2025,2.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('B',2025,'heater',2025,1.0,NULL,NULL); +REPLACE INTO "demand" VALUES('A',2025,'RL',100.0,'',''); +REPLACE INTO "demand" VALUES('B',2025,'RL',100.0,NULL,NULL); +REPLACE INTO "demand" VALUES('A',2025,'RH',50.0,NULL,NULL); +REPLACE INTO "demand" VALUES('B',2025,'RH',50.0,NULL,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('A',2025,'s1','d1','RL',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('A',2025,'s1','d2','RL',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('A',2025,'s2','d1','RL',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('A',2025,'s2','d2','RL',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('B',2025,'s1','d1','RL',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('B',2025,'s1','d2','RL',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('B',2025,'s2','d1','RL',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('B',2025,'s2','d2','RL',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('A',2025,'s1','d1','RH',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('A',2025,'s2','d1','RH',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('B',2025,'s1','d1','RH',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('B',2025,'s2','d1','RH',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('A',2025,'s1','d2','RH',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('A',2025,'s2','d2','RH',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('B',2025,'s1','d2','RH',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('B',2025,'s2','d2','RH',0.25,NULL); +REPLACE INTO "efficiency" VALUES('A', 'ELC', 'bulbs', 2025, 'RL', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('A', 'HYD', 'EH', 2025, 'ELC', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('A', 'HYD', 'EF', 2025, 'ELC', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('B', 'ELC', 'bulbs', 2025, 'RL', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('B', 'HYD', 'EH', 2025, 'ELC', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('B', 'ELC', 'batt', 2025, 'ELC', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('B', 'HYD', 'EF', 2025, 'ELC', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('A', 'earth', 'well', 2025, 'HYD', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('B', 'earth', 'well', 2025, 'HYD', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('A', 'earth', 'EFL', 2025, 'FusionGasFuel', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('A', 'FusionGasFuel', 'heater', 2025, 'RH', 0.9, NULL, NULL); +REPLACE INTO "efficiency" VALUES('A-B', 'FusionGasFuel', 'FGF_pipe', 2025, 'FusionGasFuel', 0.95, NULL, NULL); +REPLACE INTO "efficiency" VALUES('B', 'FusionGasFuel', 'heater', 2025, 'RH', 0.9, NULL, NULL); +REPLACE INTO "efficiency" VALUES('B', 'GeoHyd', 'GeoHeater', 2025, 'RH', 9.80000000000000093e-01, NULL, NULL); +REPLACE INTO "efficiency" VALUES('B', 'earth', 'GeoThermal', 2025, 'GeoHyd', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('B-A', 'FusionGasFuel', 'FGF_pipe', 2025, 'FusionGasFuel', 0.95, NULL, NULL); +REPLACE INTO "efficiency" VALUES('A', 'GeoHyd', 'GeoHeater', 2025, 'RH', 0.9, NULL, NULL); +REPLACE INTO "efficiency" VALUES('A', 'earth', 'GeoThermal', 2025, 'GeoHyd', 1.0, NULL, NULL); +REPLACE INTO "emission_activity" VALUES('A','co2','HYD','EH',2025,'ELC',0.02,NULL,NULL); +REPLACE INTO "emission_activity" VALUES('A','FusionGas','HYD','EF',2025,'ELC',-0.2,NULL,'emission_activity specifies emission activity coefficients (not efficiency values), negative coefficients represent emissions removal/capture, this coupling is essential for the linked tech constraint that converts CO2 from emissions commodity to physical commodity input.'); +REPLACE INTO "existing_capacity" VALUES('A','EH',2020,200.0,'things',NULL); +REPLACE INTO "lifetime_process" VALUES('B', 'EF', 2025, 200.0, NULL, NULL); +REPLACE INTO "lifetime_tech" VALUES('A', 'EH', 60.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('B', 'bulbs', 100.0, NULL, 'super LED!'); +REPLACE INTO "limit_activity" VALUES('A',2025,'EF','ge',0.001,'PJ/CY','goofy units'); +REPLACE INTO "limit_activity" VALUES('B',2025,'EH','le',10000.0,'stuff',NULL); +REPLACE INTO "limit_activity" VALUES('A',2025,'EF','le',10000.0,'stuff',NULL); +REPLACE INTO "limit_activity" VALUES('A',2025,'A_tech_grp_1','ge',0.05,'',NULL); +REPLACE INTO "limit_activity" VALUES('A',2025,'A_tech_grp_1','le',10000.0,'',NULL); +REPLACE INTO "limit_capacity" VALUES('A',2025,'EH','ge',0.1,'',''); +REPLACE INTO "limit_capacity" VALUES('B',2025,'batt','ge',0.1,'',''); +REPLACE INTO "limit_capacity" VALUES('A',2025,'EH','le',20000.0,'',''); +REPLACE INTO "limit_capacity" VALUES('B',2025,'EH','le',20000.0,'',''); +REPLACE INTO "limit_capacity" VALUES('A',2025,'A_tech_grp_1','ge',0.2,'',NULL); +REPLACE INTO "limit_capacity" VALUES('A',2025,'A_tech_grp_1','le',6000.0,'',NULL); +REPLACE INTO "limit_emission" VALUES('A',2025,'co2','le',10000.0,'gulps',NULL); +REPLACE INTO "limit_new_capacity_share" VALUES('A',2025,'RPS_common','A_tech_grp_1','ge',0.0,''); +REPLACE INTO "limit_new_capacity_share" VALUES('global',2025,'RPS_common','A_tech_grp_1','le',1.0,''); +REPLACE INTO "limit_resource" VALUES('B','EF','le',9000.0,'clumps',NULL); +REPLACE INTO "limit_tech_input_split" VALUES('A',2025,'HYD','EH','ge',0.95,'95% HYD reqt. (other not specified...)'); +REPLACE INTO "limit_tech_output_split" VALUES('B',2025,'EH','ELC','ge',0.95,'95% ELC output (there are not others, this is a min)'); +REPLACE INTO "linked_tech" VALUES('A','EF','FusionGas','EFL',NULL); +REPLACE INTO "loan_lifetime_process" VALUES('A', 'EF', 2025, 57.0, NULL, NULL); +REPLACE INTO "loan_lifetime_process" VALUES('A', 'EFL', 2025, 68.0, NULL, NULL); +REPLACE INTO "loan_lifetime_process" VALUES('A', 'bulbs', 2025, 10.0, NULL, NULL); +REPLACE INTO "loan_lifetime_process" VALUES('A', 'EH', 2025, 10.0, NULL, NULL); +REPLACE INTO "loan_lifetime_process" VALUES('A', 'well', 2025, 10.0, NULL, NULL); +REPLACE INTO "loan_lifetime_process" VALUES('A', 'heater', 2025, 10.0, NULL, NULL); +REPLACE INTO "loan_lifetime_process" VALUES('A', 'GeoHeater', 2025, 10.0, NULL, NULL); +REPLACE INTO "loan_lifetime_process" VALUES('A', 'GeoThermal', 2025, 10.0, NULL, NULL); +REPLACE INTO "loan_lifetime_process" VALUES('B', 'EF', 2025, 10.0, NULL, NULL); +REPLACE INTO "loan_lifetime_process" VALUES('B', 'bulbs', 2025, 10.0, NULL, NULL); +REPLACE INTO "loan_lifetime_process" VALUES('B', 'EH', 2025, 10.0, NULL, NULL); +REPLACE INTO "loan_lifetime_process" VALUES('B', 'batt', 2025, 10.0, NULL, NULL); +REPLACE INTO "loan_lifetime_process" VALUES('B', 'well', 2025, 10.0, NULL, NULL); +REPLACE INTO "loan_lifetime_process" VALUES('B', 'heater', 2025, 10.0, NULL, NULL); +REPLACE INTO "loan_lifetime_process" VALUES('B', 'GeoHeater', 2025, 10.0, NULL, NULL); +REPLACE INTO "loan_lifetime_process" VALUES('B', 'GeoThermal', 2025, 10.0, NULL, NULL); +REPLACE INTO "loan_lifetime_process" VALUES('A-B', 'FGF_pipe', 2025, 10.0, NULL, NULL); +REPLACE INTO "loan_lifetime_process" VALUES('B-A', 'FGF_pipe', 2025, 10.0, NULL, NULL); +REPLACE INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +REPLACE INTO "metadata" VALUES('DB_MAJOR',4,''); +REPLACE INTO "metadata" VALUES('DB_MINOR',0,''); +REPLACE INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +REPLACE INTO "metadata_real" VALUES('global_discount_rate',4.2000000000000004e-01,''); +REPLACE INTO "operator" VALUES('e','equal to'); +REPLACE INTO "operator" VALUES('le','less than or equal to'); +REPLACE INTO "operator" VALUES('ge','greater than or equal to'); +REPLACE INTO "planning_reserve_margin" VALUES('A',0.05,NULL); +REPLACE INTO "ramp_down_hourly" VALUES('A','EH',0.05,NULL); +REPLACE INTO "ramp_down_hourly" VALUES('B','EH',0.05,NULL); +REPLACE INTO "ramp_up_hourly" VALUES('B','EH',0.05,NULL); +REPLACE INTO "ramp_up_hourly" VALUES('A','EH',0.05,NULL); +REPLACE INTO "region" VALUES('A','main region'); +REPLACE INTO "region" VALUES('B','just a 2nd region'); +REPLACE INTO "rps_requirement" VALUES('B',2025,'RPS_common',0.3,NULL); +REPLACE INTO "season_label" VALUES('s1',NULL); +REPLACE INTO "season_label" VALUES('s2',NULL); +REPLACE INTO "sector_label" VALUES('supply',NULL); +REPLACE INTO "sector_label" VALUES('electric',NULL); +REPLACE INTO "sector_label" VALUES('transport',NULL); +REPLACE INTO "sector_label" VALUES('commercial',NULL); +REPLACE INTO "sector_label" VALUES('residential',NULL); +REPLACE INTO "sector_label" VALUES('industrial',NULL); +REPLACE INTO "storage_duration" VALUES('B','batt',15.0,NULL); +REPLACE INTO "tech_group" VALUES('RPS_common',''); +REPLACE INTO "tech_group" VALUES('A_tech_grp_1','converted from old db'); +REPLACE INTO "tech_group_member" VALUES('RPS_common','EF'); +REPLACE INTO "tech_group_member" VALUES('A_tech_grp_1','EH'); +REPLACE INTO "tech_group_member" VALUES('A_tech_grp_1','EF'); +REPLACE INTO "technology" VALUES('well','p','supply','water','',0,0,0,0,0,0,0,0,'plain old water'); +REPLACE INTO "technology" VALUES('bulbs','p','residential','electric','',0,0,0,0,0,0,0,0,'residential lighting'); +REPLACE INTO "technology" VALUES('EH','pb','electric','hydro','',0,0,0,1,1,0,0,0,'hydro power electric plant'); +REPLACE INTO "technology" VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0,0,'big battery'); +REPLACE INTO "technology" VALUES('EF','p','electric','electric','',0,0,1,0,0,0,0,0,'fusion plant'); +REPLACE INTO "technology" VALUES('EFL','p','electric','electric','',0,0,0,0,0,1,0,0,'linked (to Fusion) producer'); +REPLACE INTO "technology" VALUES('heater','p','residential','electric','',0,0,0,0,0,0,0,0,'heater'); +REPLACE INTO "technology" VALUES('FGF_pipe','p','transport',NULL,'',0,0,0,0,0,0,1,0,'transportation line A->B'); +REPLACE INTO "technology" VALUES('GeoThermal','p','residential','hydro','',0,1,0,0,0,0,0,0,'geothermal hot water source'); +REPLACE INTO "technology" VALUES('GeoHeater','p','residential','hydro','',0,0,0,0,0,0,0,0,'geothermal heater from geo hyd'); +REPLACE INTO "technology_type" VALUES('p','production technology'); +REPLACE INTO "technology_type" VALUES('pb','baseload production technology'); +REPLACE INTO "technology_type" VALUES('ps','storage production technology'); +REPLACE INTO "time_of_day" VALUES(1,'d1'); +REPLACE INTO "time_of_day" VALUES(2,'d2'); +REPLACE INTO "time_period" VALUES(1,2020,'e'); +REPLACE INTO "time_period" VALUES(2,2025,'f'); +REPLACE INTO "time_period" VALUES(3,2030,'f'); +REPLACE INTO "time_period_type" VALUES('e','existing vintages'); +REPLACE INTO "time_period_type" VALUES('f','future'); +REPLACE INTO "time_season" VALUES(2025,1,'s1',NULL); +REPLACE INTO "time_season" VALUES(2025,2,'s2',NULL); +REPLACE INTO "time_segment_fraction" VALUES(2025,'s2','d1',0.25,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2025,'s2','d2',0.25,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2025,'s1','d1',0.25,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2025,'s1','d2',0.25,NULL); diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index 990abbd29..70d88e5ac 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -1,1138 +1,111 @@ -BEGIN TRANSACTION; -CREATE TABLE capacity_credit -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -CREATE TABLE capacity_factor_process -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE capacity_factor_tech -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -INSERT INTO "capacity_factor_tech" VALUES('region',2000,'charge','a','generator',1.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('region',2000,'charge','b','generator',1.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('region',2000,'charge','c','generator',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('region',2000,'charge','d','generator',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('region',2000,'discharge','a','generator',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('region',2000,'discharge','b','generator',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('region',2000,'discharge','c','generator',0.01,NULL); -INSERT INTO "capacity_factor_tech" VALUES('region',2000,'discharge','d','generator',0.01,NULL); -CREATE TABLE capacity_to_activity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "capacity_to_activity" VALUES('region','generator',8760.0,'MWh/MWy'); -INSERT INTO "capacity_to_activity" VALUES('region','dly_stor',8760.0,'MWh/MWy'); -INSERT INTO "capacity_to_activity" VALUES('region','seas_stor',8760.0,'MWh/MWy'); -INSERT INTO "capacity_to_activity" VALUES('region','demand',8760.0,'MWh/MWy'); -CREATE TABLE commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES commodity_type (label), - description TEXT -); -INSERT INTO "commodity" VALUES('ethos','s',NULL); -INSERT INTO "commodity" VALUES('electricity','p',NULL); -INSERT INTO "commodity" VALUES('demand','d',NULL); -CREATE TABLE commodity_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "commodity_type" VALUES('p','physical commodity'); -INSERT INTO "commodity_type" VALUES('a','annual commodity'); -INSERT INTO "commodity_type" VALUES('e','emissions commodity'); -INSERT INTO "commodity_type" VALUES('d','demand commodity'); -INSERT INTO "commodity_type" VALUES('s','source commodity'); -INSERT INTO "commodity_type" VALUES('w','waste commodity'); -INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); -INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); -CREATE TABLE construction_input -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage) -); -CREATE TABLE cost_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT NOT NULL - REFERENCES commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE cost_fixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE cost_invest -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "cost_invest" VALUES('region','generator',2000,1000.0,'',NULL); -INSERT INTO "cost_invest" VALUES('region','dly_stor',2000,1.0,'',NULL); -INSERT INTO "cost_invest" VALUES('region','seas_stor',2000,100.0,'',NULL); -INSERT INTO "cost_invest" VALUES('region','demand',2000,1.0,'',NULL); -CREATE TABLE cost_variable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_variable" VALUES('region',2000,'generator',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2000,'demand',2000,1.0,NULL,NULL); -CREATE TABLE demand -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - commodity TEXT - REFERENCES commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -INSERT INTO "demand" VALUES('region',2000,'demand',8760.0,'MWh',NULL); -CREATE TABLE demand_specific_distribution -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - demand_name TEXT - REFERENCES commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -INSERT INTO "demand_specific_distribution" VALUES('region',2000,'charge','a','demand',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('region',2000,'charge','b','demand',0.05,NULL); -INSERT INTO "demand_specific_distribution" VALUES('region',2000,'charge','c','demand',0.05,NULL); -INSERT INTO "demand_specific_distribution" VALUES('region',2000,'charge','d','demand',0.1,NULL); -INSERT INTO "demand_specific_distribution" VALUES('region',2000,'discharge','a','demand',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('region',2000,'discharge','b','demand',0.2,NULL); -INSERT INTO "demand_specific_distribution" VALUES('region',2000,'discharge','c','demand',0.2,NULL); -INSERT INTO "demand_specific_distribution" VALUES('region',2000,'discharge','d','demand',0.4,NULL); -CREATE TABLE efficiency -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -INSERT INTO "efficiency" VALUES('region','ethos','generator',2000,'electricity',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','electricity','dly_stor',2000,'electricity',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','electricity','seas_stor',2000,'electricity',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','electricity','demand',2000,'demand',1.0,NULL); -CREATE TABLE efficiency_variable -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE emission_activity -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -CREATE TABLE emission_embodied -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE emission_end_of_life -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -CREATE TABLE existing_capacity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_survival_curve -( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE lifetime_tech -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE limit_activity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_degrowth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE limit_growth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) -); -CREATE TABLE limit_storage_level_fraction -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -INSERT INTO "limit_storage_level_fraction" VALUES('region',2000,'winter','b','seas_stor',2000,'e',0.5,NULL); -INSERT INTO "limit_storage_level_fraction" VALUES('region',2000,'charge','b','dly_stor',2000,'e',0.5,NULL); -CREATE TABLE limit_tech_input_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_input_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_output_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE limit_tech_output_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE linked_tech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES technology (tech), - emis_comm TEXT - REFERENCES commodity (name), - driven_tech TEXT - REFERENCES technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -CREATE TABLE loan_lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE loan_rate -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); -INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); -INSERT INTO "metadata" VALUES('DB_MINOR',0,''); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -CREATE TABLE myopic_efficiency -( - base_year integer, - region text, - input_comm text, - tech text, - vintage integer, - output_comm text, - efficiency real, - lifetime integer, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (region, input_comm, tech, vintage, output_comm) -); -CREATE TABLE operator -( - operator TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "operator" VALUES('e','equal to'); -INSERT INTO "operator" VALUES('le','less than or equal to'); -INSERT INTO "operator" VALUES('ge','greater than or equal to'); -CREATE TABLE output_built_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES sector_label (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) -); -CREATE TABLE output_curtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_period (period), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE output_emission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE output_flow_in -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out_summary -( - scenario TEXT NOT NULL, - region TEXT NOT NULL, - sector TEXT, - period INTEGER, - input_comm TEXT NOT NULL, - tech TEXT NOT NULL, - vintage INTEGER, - output_comm TEXT NOT NULL, - flow REAL NOT NULL, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_net_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_objective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE output_retired_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_storage_level -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE planning_reserve_margin -( - region TEXT - PRIMARY KEY - REFERENCES region (region), - margin REAL, - notes TEXT -); -CREATE TABLE ramp_down_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE ramp_up_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -INSERT INTO "region" VALUES('region',NULL); -CREATE TABLE reserve_capacity_derate -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE rps_requirement -( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL - REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES tech_group (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE season_label -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "season_label" VALUES('charge','non-sequential season - charging day'); -INSERT INTO "season_label" VALUES('discharge','non-sequential season - discharging day'); -INSERT INTO "season_label" VALUES('summer','sequential season - summer day'); -INSERT INTO "season_label" VALUES('sept_w1','sequential season - day in first week of September'); -INSERT INTO "season_label" VALUES('sept_w2','sequential season - day in second week of September'); -INSERT INTO "season_label" VALUES('sept_w3','sequential season - day in third week of September'); -INSERT INTO "season_label" VALUES('sept_w4','sequential season - day in fourth week of September'); -INSERT INTO "season_label" VALUES('sept_29th','sequential season - 29th of September'); -INSERT INTO "season_label" VALUES('sept_30th','sequential season - 30th of September'); -INSERT INTO "season_label" VALUES('winter','sequential season - winter day'); -INSERT INTO "season_label" VALUES('apr_w1','sequential season - day in first week of September'); -INSERT INTO "season_label" VALUES('apr_w2','sequential season - day in second week of September'); -INSERT INTO "season_label" VALUES('apr_w3','sequential season - day in third week of September'); -INSERT INTO "season_label" VALUES('apr_w4','sequential season - day in fourth week of September'); -INSERT INTO "season_label" VALUES('apr_29th','sequential season - 29th of April'); -INSERT INTO "season_label" VALUES('apr_30th','sequential season - 30th of April'); -CREATE TABLE sector_label -( - sector TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "sector_label" VALUES('electricity',NULL); -CREATE TABLE storage_duration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "storage_duration" VALUES('region','dly_stor',4.0,NULL); -INSERT INTO "storage_duration" VALUES('region','seas_stor',8760.0,NULL); -CREATE TABLE tech_group -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE tech_group_member -( - group_name TEXT - REFERENCES tech_group (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technology_type (label) -); -INSERT INTO "technology" VALUES('generator','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO "technology" VALUES('dly_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO "technology" VALUES('seas_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,1,NULL); -INSERT INTO "technology" VALUES('demand','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -CREATE TABLE technology_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "technology_type" VALUES('p','production technology'); -INSERT INTO "technology_type" VALUES('pb','baseload production technology'); -INSERT INTO "technology_type" VALUES('ps','storage production technology'); -CREATE TABLE time_of_day -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY -); -INSERT INTO "time_of_day" VALUES(0,'a'); -INSERT INTO "time_of_day" VALUES(1,'b'); -INSERT INTO "time_of_day" VALUES(2,'c'); -INSERT INTO "time_of_day" VALUES(3,'d'); -CREATE TABLE time_period -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES time_period_type (label) -); -INSERT INTO "time_period" VALUES(0,2000,'f'); -INSERT INTO "time_period" VALUES(1,2005,'f'); -CREATE TABLE time_period_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "time_period_type" VALUES('e','existing vintages'); -INSERT INTO "time_period_type" VALUES('f','future'); -CREATE TABLE time_season -( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - season TEXT REFERENCES season_label(season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); -INSERT INTO "time_season" VALUES(2000,0,'charge',NULL); -INSERT INTO "time_season" VALUES(2000,1,'discharge',NULL); - -CREATE TABLE time_season_sequential -( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT REFERENCES season_label(season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); -INSERT INTO "time_season_sequential" VALUES(2000,1,'summer','charge',152.5,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,2,'sept_w1','discharge',7.0,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,3,'sept_w2','charge',7.0,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,4,'sept_w3','discharge',7.0,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,5,'sept_w4','charge',7.0,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,6,'sept_29th','discharge',1.0,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,7,'sept_30th','charge',1.0,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,8,'winter','discharge',152.5,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,9,'apr_w1','charge',7.0,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,10,'apr_w2','discharge',7.0,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,11,'apr_w3','charge',7.0,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,12,'apr_w4','discharge',7.0,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,13,'apr_29th','charge',1.0,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,14,'apr_30th','discharge',1.0,NULL); - -CREATE TABLE time_segment_fraction -( - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - segment_fraction REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); -INSERT INTO "time_segment_fraction" VALUES(2000,'charge','a',0.125,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'charge','b',0.125,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'charge','c',0.125,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'charge','d',0.125,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'discharge','a',0.125,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'discharge','b',0.125,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'discharge','c',0.125,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'discharge','d',0.125,NULL); -CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); - -COMMIT; +REPLACE INTO "capacity_factor_tech" VALUES('region',2000,'charge','a','generator',1.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('region',2000,'charge','b','generator',1.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('region',2000,'charge','c','generator',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('region',2000,'charge','d','generator',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('region',2000,'discharge','a','generator',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('region',2000,'discharge','b','generator',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('region',2000,'discharge','c','generator',0.01,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('region',2000,'discharge','d','generator',0.01,NULL); +REPLACE INTO "capacity_to_activity" VALUES('region', 'generator', 8760.0, NULL, 'MWh/MWy'); +REPLACE INTO "capacity_to_activity" VALUES('region', 'dly_stor', 8760.0, NULL, 'MWh/MWy'); +REPLACE INTO "capacity_to_activity" VALUES('region', 'seas_stor', 8760.0, NULL, 'MWh/MWy'); +REPLACE INTO "capacity_to_activity" VALUES('region', 'demand', 8760.0, NULL, 'MWh/MWy'); +REPLACE INTO "commodity" VALUES('ethos', 's', NULL, NULL); +REPLACE INTO "commodity" VALUES('electricity', 'p', NULL, NULL); +REPLACE INTO "commodity" VALUES('demand', 'd', NULL, NULL); +REPLACE INTO "commodity_type" VALUES('p','physical commodity'); +REPLACE INTO "commodity_type" VALUES('a','annual commodity'); +REPLACE INTO "commodity_type" VALUES('e','emissions commodity'); +REPLACE INTO "commodity_type" VALUES('d','demand commodity'); +REPLACE INTO "commodity_type" VALUES('s','source commodity'); +REPLACE INTO "commodity_type" VALUES('w','waste commodity'); +REPLACE INTO "commodity_type" VALUES('wa','waste annual commodity'); +REPLACE INTO "commodity_type" VALUES('wp','waste physical commodity'); +REPLACE INTO "cost_invest" VALUES('region','generator',2000,1000.0,'',NULL); +REPLACE INTO "cost_invest" VALUES('region','dly_stor',2000,1.0,'',NULL); +REPLACE INTO "cost_invest" VALUES('region','seas_stor',2000,100.0,'',NULL); +REPLACE INTO "cost_invest" VALUES('region','demand',2000,1.0,'',NULL); +REPLACE INTO "cost_variable" VALUES('region',2000,'generator',2000,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2000,'demand',2000,1.0,NULL,NULL); +REPLACE INTO "demand" VALUES('region',2000,'demand',8760.0,'MWh',NULL); +REPLACE INTO "demand_specific_distribution" VALUES('region',2000,'charge','a','demand',0.0,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('region',2000,'charge','b','demand',0.05,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('region',2000,'charge','c','demand',0.05,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('region',2000,'charge','d','demand',0.1,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('region',2000,'discharge','a','demand',0.0,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('region',2000,'discharge','b','demand',0.2,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('region',2000,'discharge','c','demand',0.2,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('region',2000,'discharge','d','demand',0.4,NULL); +REPLACE INTO "efficiency" VALUES('region', 'ethos', 'generator', 2000, 'electricity', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('region', 'electricity', 'dly_stor', 2000, 'electricity', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('region', 'electricity', 'seas_stor', 2000, 'electricity', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('region', 'electricity', 'demand', 2000, 'demand', 1.0, NULL, NULL); +REPLACE INTO "limit_storage_level_fraction" VALUES('region',2000,'winter','b','seas_stor',2000,'e',0.5,NULL); +REPLACE INTO "limit_storage_level_fraction" VALUES('region',2000,'charge','b','dly_stor',2000,'e',0.5,NULL); +REPLACE INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +REPLACE INTO "metadata" VALUES('DB_MAJOR',4,''); +REPLACE INTO "metadata" VALUES('DB_MINOR',0,''); +REPLACE INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +REPLACE INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +REPLACE INTO "operator" VALUES('e','equal to'); +REPLACE INTO "operator" VALUES('le','less than or equal to'); +REPLACE INTO "operator" VALUES('ge','greater than or equal to'); +REPLACE INTO "region" VALUES('region',NULL); +REPLACE INTO "season_label" VALUES('charge','non-sequential season - charging day'); +REPLACE INTO "season_label" VALUES('discharge','non-sequential season - discharging day'); +REPLACE INTO "season_label" VALUES('summer','sequential season - summer day'); +REPLACE INTO "season_label" VALUES('sept_w1','sequential season - day in first week of September'); +REPLACE INTO "season_label" VALUES('sept_w2','sequential season - day in second week of September'); +REPLACE INTO "season_label" VALUES('sept_w3','sequential season - day in third week of September'); +REPLACE INTO "season_label" VALUES('sept_w4','sequential season - day in fourth week of September'); +REPLACE INTO "season_label" VALUES('sept_29th','sequential season - 29th of September'); +REPLACE INTO "season_label" VALUES('sept_30th','sequential season - 30th of September'); +REPLACE INTO "season_label" VALUES('winter','sequential season - winter day'); +REPLACE INTO "season_label" VALUES('apr_w1','sequential season - day in first week of September'); +REPLACE INTO "season_label" VALUES('apr_w2','sequential season - day in second week of September'); +REPLACE INTO "season_label" VALUES('apr_w3','sequential season - day in third week of September'); +REPLACE INTO "season_label" VALUES('apr_w4','sequential season - day in fourth week of September'); +REPLACE INTO "season_label" VALUES('apr_29th','sequential season - 29th of April'); +REPLACE INTO "season_label" VALUES('apr_30th','sequential season - 30th of April'); +REPLACE INTO "sector_label" VALUES('electricity',NULL); +REPLACE INTO "storage_duration" VALUES('region','dly_stor',4.0,NULL); +REPLACE INTO "storage_duration" VALUES('region','seas_stor',8760.0,NULL); +REPLACE INTO "technology" VALUES('generator','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +REPLACE INTO "technology" VALUES('dly_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +REPLACE INTO "technology" VALUES('seas_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,1,NULL); +REPLACE INTO "technology" VALUES('demand','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +REPLACE INTO "technology_type" VALUES('p','production technology'); +REPLACE INTO "technology_type" VALUES('pb','baseload production technology'); +REPLACE INTO "technology_type" VALUES('ps','storage production technology'); +REPLACE INTO "time_of_day" VALUES(0,'a'); +REPLACE INTO "time_of_day" VALUES(1,'b'); +REPLACE INTO "time_of_day" VALUES(2,'c'); +REPLACE INTO "time_of_day" VALUES(3,'d'); +REPLACE INTO "time_period" VALUES(0,2000,'f'); +REPLACE INTO "time_period" VALUES(1,2005,'f'); +REPLACE INTO "time_period_type" VALUES('e','existing vintages'); +REPLACE INTO "time_period_type" VALUES('f','future'); +REPLACE INTO "time_season" VALUES(2000,0,'charge',NULL); +REPLACE INTO "time_season" VALUES(2000,1,'discharge',NULL); +REPLACE INTO "time_season_sequential" VALUES(2000,1,'summer','charge',152.5,NULL); +REPLACE INTO "time_season_sequential" VALUES(2000,2,'sept_w1','discharge',7.0,NULL); +REPLACE INTO "time_season_sequential" VALUES(2000,3,'sept_w2','charge',7.0,NULL); +REPLACE INTO "time_season_sequential" VALUES(2000,4,'sept_w3','discharge',7.0,NULL); +REPLACE INTO "time_season_sequential" VALUES(2000,5,'sept_w4','charge',7.0,NULL); +REPLACE INTO "time_season_sequential" VALUES(2000,6,'sept_29th','discharge',1.0,NULL); +REPLACE INTO "time_season_sequential" VALUES(2000,7,'sept_30th','charge',1.0,NULL); +REPLACE INTO "time_season_sequential" VALUES(2000,8,'winter','discharge',152.5,NULL); +REPLACE INTO "time_season_sequential" VALUES(2000,9,'apr_w1','charge',7.0,NULL); +REPLACE INTO "time_season_sequential" VALUES(2000,10,'apr_w2','discharge',7.0,NULL); +REPLACE INTO "time_season_sequential" VALUES(2000,11,'apr_w3','charge',7.0,NULL); +REPLACE INTO "time_season_sequential" VALUES(2000,12,'apr_w4','discharge',7.0,NULL); +REPLACE INTO "time_season_sequential" VALUES(2000,13,'apr_29th','charge',1.0,NULL); +REPLACE INTO "time_season_sequential" VALUES(2000,14,'apr_30th','discharge',1.0,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'charge','a',0.125,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'charge','b',0.125,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'charge','c',0.125,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'charge','d',0.125,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'discharge','a',0.125,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'discharge','b',0.125,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'discharge','c',0.125,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'discharge','d',0.125,NULL); diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index bf28bd18e..359f62cea 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -1,1089 +1,63 @@ -BEGIN TRANSACTION; -CREATE TABLE capacity_credit -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -CREATE TABLE capacity_factor_process -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE capacity_factor_tech -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE capacity_to_activity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES commodity_type (label), - description TEXT -); -INSERT INTO "commodity" VALUES('ELC','d','electricity'); -INSERT INTO "commodity" VALUES('NGA','p','natural gas'); -INSERT INTO "commodity" VALUES('CO2','e','CO2 emission'); -INSERT INTO "commodity" VALUES('CO2_CAP','d','captured CO2'); -INSERT INTO "commodity" VALUES('ETHOS','s','source'); -CREATE TABLE commodity_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "commodity_type" VALUES('w','waste commodity'); -INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); -INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); -INSERT INTO "commodity_type" VALUES('a','annual commodity'); -INSERT INTO "commodity_type" VALUES('s','source commodity'); -INSERT INTO "commodity_type" VALUES('p','physical commodity'); -INSERT INTO "commodity_type" VALUES('e','emissions commodity'); -INSERT INTO "commodity_type" VALUES('d','demand commodity'); -CREATE TABLE construction_input -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage) -); -CREATE TABLE cost_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT NOT NULL - REFERENCES commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -INSERT INTO "cost_emission" VALUES('linkville',2000,'CO2',2.0,NULL,NULL); -CREATE TABLE cost_fixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE cost_invest -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "cost_invest" VALUES('linkville','PLANT',2000,100.0,'',''); -INSERT INTO "cost_invest" VALUES('linkville','CCS',2000,50.0,'',''); -CREATE TABLE cost_variable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_variable" VALUES('linkville',2000,'PLANT',2000,10.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('linkville',2000,'CCS',2000,10.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('linkville',2000,'FAKE_SOURCE',2000,0.0,NULL,NULL); -CREATE TABLE demand -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - commodity TEXT - REFERENCES commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -INSERT INTO "demand" VALUES('linkville',2000,'CO2_CAP',1000.0,NULL,NULL); -INSERT INTO "demand" VALUES('linkville',2000,'ELC',10.0,NULL,NULL); -CREATE TABLE demand_specific_distribution -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - demand_name TEXT - REFERENCES commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -CREATE TABLE efficiency -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -INSERT INTO "efficiency" VALUES('linkville','ETHOS','MINE',2000,'NGA',1.0,''); -INSERT INTO "efficiency" VALUES('linkville','ETHOS','CCS',2000,'CO2_CAP',1.0,'capture eff'); -INSERT INTO "efficiency" VALUES('linkville','ETHOS','FAKE_SOURCE',2000,'CO2_CAP',1.0,''); -INSERT INTO "efficiency" VALUES('linkville','NGA','PLANT',2000,'ELC',0.5,NULL); -CREATE TABLE efficiency_variable -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE emission_activity -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -INSERT INTO "emission_activity" VALUES('linkville','CO2','NGA','PLANT',2000,'ELC',-3.0,'',''); -CREATE TABLE emission_embodied -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE emission_end_of_life -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -CREATE TABLE existing_capacity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_survival_curve -( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE lifetime_tech -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "lifetime_tech" VALUES('linkville','CCS',100.0,''); -INSERT INTO "lifetime_tech" VALUES('linkville','PLANT',100.0,''); -CREATE TABLE limit_activity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_degrowth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE limit_growth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) -); -CREATE TABLE limit_storage_level_fraction -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -CREATE TABLE limit_tech_input_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_input_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_output_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE limit_tech_output_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE linked_tech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES technology (tech), - emis_comm TEXT - REFERENCES commodity (name), - driven_tech TEXT - REFERENCES technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -INSERT INTO "linked_tech" VALUES('linkville','PLANT','CO2','CCS',NULL); -CREATE TABLE loan_lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE loan_rate -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); -INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); -INSERT INTO "metadata" VALUES('DB_MINOR',0,''); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,''); -CREATE TABLE myopic_efficiency -( - base_year integer, - region text, - input_comm text, - tech text, - vintage integer, - output_comm text, - efficiency real, - lifetime integer, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (region, input_comm, tech, vintage, output_comm) -); -CREATE TABLE operator -( - operator TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "operator" VALUES('e','equal to'); -INSERT INTO "operator" VALUES('le','less than or equal to'); -INSERT INTO "operator" VALUES('ge','greater than or equal to'); -CREATE TABLE output_built_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES sector_label (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) -); -CREATE TABLE output_curtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_period (period), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE output_emission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE output_flow_in -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out_summary -( - scenario TEXT NOT NULL, - region TEXT NOT NULL, - sector TEXT, - period INTEGER, - input_comm TEXT NOT NULL, - tech TEXT NOT NULL, - vintage INTEGER, - output_comm TEXT NOT NULL, - flow REAL NOT NULL, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_net_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_objective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE output_retired_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_storage_level -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE planning_reserve_margin -( - region TEXT - PRIMARY KEY - REFERENCES region (region), - margin REAL, - notes TEXT -); -CREATE TABLE ramp_down_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE ramp_up_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -INSERT INTO "region" VALUES('linkville',NULL); -CREATE TABLE reserve_capacity_derate -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE rps_requirement -( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL - REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES tech_group (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE season_label -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "season_label" VALUES('summer',NULL); -INSERT INTO "season_label" VALUES('winter',NULL); -CREATE TABLE sector_label -( - sector TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "sector_label" VALUES('supply',NULL); -INSERT INTO "sector_label" VALUES('electric',NULL); -INSERT INTO "sector_label" VALUES('transport',NULL); -INSERT INTO "sector_label" VALUES('commercial',NULL); -INSERT INTO "sector_label" VALUES('residential',NULL); -INSERT INTO "sector_label" VALUES('industrial',NULL); -CREATE TABLE storage_duration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE tech_group -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE tech_group_member -( - group_name TEXT - REFERENCES tech_group (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technology_type (label) -); -INSERT INTO "technology" VALUES('PLANT','p','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO "technology" VALUES('CCS','p','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO "technology" VALUES('MINE','p','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO "technology" VALUES('FAKE_SOURCE','p','supply',NULL,NULL,1,0,0,0,0,0,0,0,NULL); -CREATE TABLE technology_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "technology_type" VALUES('p','production technology'); -INSERT INTO "technology_type" VALUES('pb','baseload production technology'); -INSERT INTO "technology_type" VALUES('ps','storage production technology'); -CREATE TABLE time_of_day -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY -); -INSERT INTO "time_of_day" VALUES(1,'day'); -CREATE TABLE time_period -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES time_period_type (label) -); -INSERT INTO "time_period" VALUES(0,1995,'e'); -INSERT INTO "time_period" VALUES(1,2000,'f'); -INSERT INTO "time_period" VALUES(2,2005,'f'); -CREATE TABLE time_period_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "time_period_type" VALUES('e','existing vintages'); -INSERT INTO "time_period_type" VALUES('f','future'); -CREATE TABLE time_season -( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - season TEXT REFERENCES season_label(season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); -INSERT INTO "time_season" VALUES(2000,1,'summer',NULL); -INSERT INTO "time_season" VALUES(2000,2,'winter',NULL); - -CREATE TABLE time_season_sequential -( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT REFERENCES season_label(season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); - -CREATE TABLE time_segment_fraction -( - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - segment_fraction REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); -INSERT INTO "time_segment_fraction" VALUES(2000,'summer','day',0.5,'# S-D'); -INSERT INTO "time_segment_fraction" VALUES(2000,'winter','day',0.5,'# W-D'); -CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); -COMMIT; +REPLACE INTO "commodity" VALUES('ELC', 'd', 'electricity', NULL); +REPLACE INTO "commodity" VALUES('NGA', 'p', 'natural gas', NULL); +REPLACE INTO "commodity" VALUES('CO2', 'e', 'CO2 emission', NULL); +REPLACE INTO "commodity" VALUES('CO2_CAP', 'd', 'captured CO2', NULL); +REPLACE INTO "commodity" VALUES('ETHOS', 's', 'source', NULL); +REPLACE INTO "commodity_type" VALUES('w','waste commodity'); +REPLACE INTO "commodity_type" VALUES('wa','waste annual commodity'); +REPLACE INTO "commodity_type" VALUES('wp','waste physical commodity'); +REPLACE INTO "commodity_type" VALUES('a','annual commodity'); +REPLACE INTO "commodity_type" VALUES('s','source commodity'); +REPLACE INTO "commodity_type" VALUES('p','physical commodity'); +REPLACE INTO "commodity_type" VALUES('e','emissions commodity'); +REPLACE INTO "commodity_type" VALUES('d','demand commodity'); +REPLACE INTO "cost_emission" VALUES('linkville',2000,'CO2',2.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('linkville','PLANT',2000,100.0,'',''); +REPLACE INTO "cost_invest" VALUES('linkville','CCS',2000,50.0,'',''); +REPLACE INTO "cost_variable" VALUES('linkville',2000,'PLANT',2000,10.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('linkville',2000,'CCS',2000,10.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('linkville',2000,'FAKE_SOURCE',2000,0.0,NULL,NULL); +REPLACE INTO "demand" VALUES('linkville',2000,'CO2_CAP',1000.0,NULL,NULL); +REPLACE INTO "demand" VALUES('linkville',2000,'ELC',10.0,NULL,NULL); +REPLACE INTO "efficiency" VALUES('linkville', 'ETHOS', 'MINE', 2000, 'NGA', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('linkville', 'ETHOS', 'CCS', 2000, 'CO2_CAP', 1.0, NULL, 'capture eff'); +REPLACE INTO "efficiency" VALUES('linkville', 'ETHOS', 'FAKE_SOURCE', 2000, 'CO2_CAP', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('linkville', 'NGA', 'PLANT', 2000, 'ELC', 0.5, NULL, NULL); +REPLACE INTO "emission_activity" VALUES('linkville','CO2','NGA','PLANT',2000,'ELC',-3.0,'',''); +REPLACE INTO "lifetime_tech" VALUES('linkville', 'CCS', 100.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('linkville', 'PLANT', 100.0, NULL, ''); +REPLACE INTO "linked_tech" VALUES('linkville','PLANT','CO2','CCS',NULL); +REPLACE INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +REPLACE INTO "metadata" VALUES('DB_MAJOR',4,''); +REPLACE INTO "metadata" VALUES('DB_MINOR',0,''); +REPLACE INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +REPLACE INTO "metadata_real" VALUES('global_discount_rate',0.05,''); +REPLACE INTO "operator" VALUES('e','equal to'); +REPLACE INTO "operator" VALUES('le','less than or equal to'); +REPLACE INTO "operator" VALUES('ge','greater than or equal to'); +REPLACE INTO "region" VALUES('linkville',NULL); +REPLACE INTO "season_label" VALUES('summer',NULL); +REPLACE INTO "season_label" VALUES('winter',NULL); +REPLACE INTO "sector_label" VALUES('supply',NULL); +REPLACE INTO "sector_label" VALUES('electric',NULL); +REPLACE INTO "sector_label" VALUES('transport',NULL); +REPLACE INTO "sector_label" VALUES('commercial',NULL); +REPLACE INTO "sector_label" VALUES('residential',NULL); +REPLACE INTO "sector_label" VALUES('industrial',NULL); +REPLACE INTO "technology" VALUES('PLANT','p','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +REPLACE INTO "technology" VALUES('CCS','p','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +REPLACE INTO "technology" VALUES('MINE','p','supply',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +REPLACE INTO "technology" VALUES('FAKE_SOURCE','p','supply',NULL,NULL,1,0,0,0,0,0,0,0,NULL); +REPLACE INTO "technology_type" VALUES('p','production technology'); +REPLACE INTO "technology_type" VALUES('pb','baseload production technology'); +REPLACE INTO "technology_type" VALUES('ps','storage production technology'); +REPLACE INTO "time_of_day" VALUES(1,'day'); +REPLACE INTO "time_period" VALUES(0,1995,'e'); +REPLACE INTO "time_period" VALUES(1,2000,'f'); +REPLACE INTO "time_period" VALUES(2,2005,'f'); +REPLACE INTO "time_period_type" VALUES('e','existing vintages'); +REPLACE INTO "time_period_type" VALUES('f','future'); +REPLACE INTO "time_season" VALUES(2000,1,'summer',NULL); +REPLACE INTO "time_season" VALUES(2000,2,'winter',NULL); +REPLACE INTO "time_segment_fraction" VALUES(2000,'summer','day',0.5,'# S-D'); +REPLACE INTO "time_segment_fraction" VALUES(2000,'winter','day',0.5,'# W-D'); diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index 127982bff..a592e10d7 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -1,1116 +1,90 @@ -BEGIN TRANSACTION; -CREATE TABLE capacity_credit -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -CREATE TABLE capacity_factor_process -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE capacity_factor_tech -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE capacity_to_activity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "capacity_to_activity" VALUES('electricville','bulbs',1.0,''); -CREATE TABLE commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES commodity_type (label), - description TEXT -); -INSERT INTO "commodity" VALUES('ELC','p','# electricity'); -INSERT INTO "commodity" VALUES('HYD','p','# water'); -INSERT INTO "commodity" VALUES('co2','e','#CO2 emissions'); -INSERT INTO "commodity" VALUES('RL','d','# residential lighting'); -INSERT INTO "commodity" VALUES('earth','p','# the source of stuff'); -CREATE TABLE commodity_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "commodity_type" VALUES('w','waste commodity'); -INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); -INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); -INSERT INTO "commodity_type" VALUES('a','annual commodity'); -INSERT INTO "commodity_type" VALUES('p','physical commodity'); -INSERT INTO "commodity_type" VALUES('e','emissions commodity'); -INSERT INTO "commodity_type" VALUES('d','demand commodity'); -INSERT INTO "commodity_type" VALUES('s','source commodity'); -CREATE TABLE construction_input -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage) -); -CREATE TABLE cost_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT NOT NULL - REFERENCES commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE cost_fixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_fixed" VALUES('electricville',2025,'EH',2025,100.0,'',''); -INSERT INTO "cost_fixed" VALUES('electricville',2025,'batt',2025,1.0,'',''); -CREATE TABLE cost_invest -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "cost_invest" VALUES('electricville','EH',2025,100.0,'',''); -INSERT INTO "cost_invest" VALUES('electricville','batt',2025,1.0,NULL,NULL); -CREATE TABLE cost_variable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_variable" VALUES('electricville',2025,'EH',2025,1000.0,'',''); -INSERT INTO "cost_variable" VALUES('electricville',2025,'batt',2025,1.0,'',''); -CREATE TABLE demand -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - commodity TEXT - REFERENCES commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -INSERT INTO "demand" VALUES('electricville',2025,'RL',100.0,'',''); -CREATE TABLE demand_specific_distribution -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - demand_name TEXT - REFERENCES commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -INSERT INTO "demand_specific_distribution" VALUES('electricville',2025,'s1','d1','RL',0.075,''); -INSERT INTO "demand_specific_distribution" VALUES('electricville',2025,'s1','d2','RL',0.075,''); -INSERT INTO "demand_specific_distribution" VALUES('electricville',2025,'s1','d3','RL',0.075,NULL); -INSERT INTO "demand_specific_distribution" VALUES('electricville',2025,'s2','d1','RL',0.075,NULL); -INSERT INTO "demand_specific_distribution" VALUES('electricville',2025,'s2','d2','RL',0.075,NULL); -INSERT INTO "demand_specific_distribution" VALUES('electricville',2025,'s2','d3','RL',0.075,NULL); -INSERT INTO "demand_specific_distribution" VALUES('electricville',2025,'s1','d4','RL',0.075,NULL); -INSERT INTO "demand_specific_distribution" VALUES('electricville',2025,'s1','d5','RL',0.2,NULL); -INSERT INTO "demand_specific_distribution" VALUES('electricville',2025,'s2','d4','RL',0.2,NULL); -INSERT INTO "demand_specific_distribution" VALUES('electricville',2025,'s2','d5','RL',0.075,NULL); -CREATE TABLE efficiency -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -INSERT INTO "efficiency" VALUES('electricville','HYD','EH',2025,'ELC',1.0,NULL); -INSERT INTO "efficiency" VALUES('electricville','ELC','bulbs',2025,'RL',1.0,NULL); -INSERT INTO "efficiency" VALUES('electricville','earth','well',2025,'HYD',1.0,'water source'); -INSERT INTO "efficiency" VALUES('electricville','ELC','batt',2025,'ELC',0.75,NULL); -CREATE TABLE efficiency_variable -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE emission_activity -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -INSERT INTO "emission_activity" VALUES('electricville','co2','HYD','EH',2025,'ELC',0.02,NULL,NULL); -CREATE TABLE emission_embodied -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE emission_end_of_life -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -CREATE TABLE existing_capacity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_survival_curve -( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE lifetime_tech -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "lifetime_tech" VALUES('electricville','EH',60.0,''); -INSERT INTO "lifetime_tech" VALUES('electricville','bulbs',100.0,'super LED!'); -CREATE TABLE limit_activity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -INSERT INTO "limit_capacity" VALUES('electricville',2025,'EH','ge',0.1,'',''); -INSERT INTO "limit_capacity" VALUES('electricville',2025,'batt','ge',0.1,'',''); -INSERT INTO "limit_capacity" VALUES('electricville',2025,'EH','le',200.0,'',''); -INSERT INTO "limit_capacity" VALUES('electricville',2025,'batt','le',100.0,'',''); -CREATE TABLE limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_degrowth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE limit_growth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) -); -CREATE TABLE limit_storage_level_fraction -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -INSERT INTO "limit_storage_level_fraction" VALUES('electricville',2025,'s1','d1','batt',2025,'e',0.5,NULL); -CREATE TABLE limit_tech_input_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_input_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_output_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE limit_tech_output_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE linked_tech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES technology (tech), - emis_comm TEXT - REFERENCES commodity (name), - driven_tech TEXT - REFERENCES technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -CREATE TABLE loan_lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE loan_rate -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); -INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); -INSERT INTO "metadata" VALUES('DB_MINOR',0,''); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,''); -CREATE TABLE myopic_efficiency -( - base_year integer, - region text, - input_comm text, - tech text, - vintage integer, - output_comm text, - efficiency real, - lifetime integer, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (region, input_comm, tech, vintage, output_comm) -); -CREATE TABLE operator -( - operator TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "operator" VALUES('e','equal to'); -INSERT INTO "operator" VALUES('le','less than or equal to'); -INSERT INTO "operator" VALUES('ge','greater than or equal to'); -CREATE TABLE output_built_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES sector_label (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) -); -CREATE TABLE output_curtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_period (period), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE output_emission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE output_flow_in -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out_summary -( - scenario TEXT NOT NULL, - region TEXT NOT NULL, - sector TEXT, - period INTEGER, - input_comm TEXT NOT NULL, - tech TEXT NOT NULL, - vintage INTEGER, - output_comm TEXT NOT NULL, - flow REAL NOT NULL, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_net_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_objective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE output_retired_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_storage_level -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE planning_reserve_margin -( - region TEXT - PRIMARY KEY - REFERENCES region (region), - margin REAL, - notes TEXT -); -CREATE TABLE ramp_down_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE ramp_up_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -INSERT INTO "region" VALUES('electricville',NULL); -CREATE TABLE reserve_capacity_derate -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE rps_requirement -( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL - REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES tech_group (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE season_label -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "season_label" VALUES('s1',NULL); -INSERT INTO "season_label" VALUES('s2',NULL); -CREATE TABLE sector_label -( - sector TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "sector_label" VALUES('supply',NULL); -INSERT INTO "sector_label" VALUES('electric',NULL); -INSERT INTO "sector_label" VALUES('transport',NULL); -INSERT INTO "sector_label" VALUES('commercial',NULL); -INSERT INTO "sector_label" VALUES('residential',NULL); -INSERT INTO "sector_label" VALUES('industrial',NULL); -CREATE TABLE storage_duration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "storage_duration" VALUES('electricville','batt',10.0,NULL); -CREATE TABLE tech_group -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE tech_group_member -( - group_name TEXT - REFERENCES tech_group (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technology_type (label) -); -INSERT INTO "technology" VALUES('well','p','supply','water','',0,0,0,0,0,0,0,0,'plain old water'); -INSERT INTO "technology" VALUES('bulbs','p','residential','electric','',0,0,0,0,0,0,0,0,' residential lighting'); -INSERT INTO "technology" VALUES('EH','pb','electric','hydro','',0,0,0,0,0,0,0,0,'hydro power electric plant'); -INSERT INTO "technology" VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0,0,'big battery'); -CREATE TABLE technology_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "technology_type" VALUES('p','production technology'); -INSERT INTO "technology_type" VALUES('pb','baseload production technology'); -INSERT INTO "technology_type" VALUES('ps','storage production technology'); -CREATE TABLE time_of_day -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY -); -INSERT INTO "time_of_day" VALUES(1,'d1'); -INSERT INTO "time_of_day" VALUES(2,'d2'); -INSERT INTO "time_of_day" VALUES(3,'d3'); -INSERT INTO "time_of_day" VALUES(4,'d4'); -INSERT INTO "time_of_day" VALUES(5,'d5'); -CREATE TABLE time_period -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES time_period_type (label) -); -INSERT INTO "time_period" VALUES(1,2020,'e'); -INSERT INTO "time_period" VALUES(2,2025,'f'); -INSERT INTO "time_period" VALUES(3,2030,'f'); -CREATE TABLE time_period_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "time_period_type" VALUES('e','existing vintages'); -INSERT INTO "time_period_type" VALUES('f','future'); -CREATE TABLE time_season -( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - season TEXT REFERENCES season_label(season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); -INSERT INTO "time_season" VALUES(2025,1,'s1',NULL); -INSERT INTO "time_season" VALUES(2025,2,'s2',NULL); - -CREATE TABLE time_season_sequential -( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT REFERENCES season_label(season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); - -CREATE TABLE time_segment_fraction -( - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - segment_fraction REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); -INSERT INTO "time_segment_fraction" VALUES(2025,'s1','d3',0.1,NULL); -INSERT INTO "time_segment_fraction" VALUES(2025,'s2','d1',0.1,NULL); -INSERT INTO "time_segment_fraction" VALUES(2025,'s2','d2',0.1,NULL); -INSERT INTO "time_segment_fraction" VALUES(2025,'s2','d3',0.1,NULL); -INSERT INTO "time_segment_fraction" VALUES(2025,'s1','d1',0.1,NULL); -INSERT INTO "time_segment_fraction" VALUES(2025,'s1','d2',0.1,NULL); -INSERT INTO "time_segment_fraction" VALUES(2025,'s1','d4',0.1,NULL); -INSERT INTO "time_segment_fraction" VALUES(2025,'s1','d5',0.1,NULL); -INSERT INTO "time_segment_fraction" VALUES(2025,'s2','d4',0.1,NULL); -INSERT INTO "time_segment_fraction" VALUES(2025,'s2','d5',0.1,NULL); -CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); -COMMIT; +REPLACE INTO "capacity_to_activity" VALUES('electricville', 'bulbs', 1.0, NULL, ''); +REPLACE INTO "commodity" VALUES('ELC', 'p', '# electricity', NULL); +REPLACE INTO "commodity" VALUES('HYD', 'p', '# water', NULL); +REPLACE INTO "commodity" VALUES('co2', 'e', '#CO2 emissions', NULL); +REPLACE INTO "commodity" VALUES('RL', 'd', '# residential lighting', NULL); +REPLACE INTO "commodity" VALUES('earth', 'p', '# the source of stuff', NULL); +REPLACE INTO "commodity_type" VALUES('w','waste commodity'); +REPLACE INTO "commodity_type" VALUES('wa','waste annual commodity'); +REPLACE INTO "commodity_type" VALUES('wp','waste physical commodity'); +REPLACE INTO "commodity_type" VALUES('a','annual commodity'); +REPLACE INTO "commodity_type" VALUES('p','physical commodity'); +REPLACE INTO "commodity_type" VALUES('e','emissions commodity'); +REPLACE INTO "commodity_type" VALUES('d','demand commodity'); +REPLACE INTO "commodity_type" VALUES('s','source commodity'); +REPLACE INTO "cost_fixed" VALUES('electricville',2025,'EH',2025,100.0,'',''); +REPLACE INTO "cost_fixed" VALUES('electricville',2025,'batt',2025,1.0,'',''); +REPLACE INTO "cost_invest" VALUES('electricville','EH',2025,100.0,'',''); +REPLACE INTO "cost_invest" VALUES('electricville','batt',2025,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('electricville',2025,'EH',2025,1000.0,'',''); +REPLACE INTO "cost_variable" VALUES('electricville',2025,'batt',2025,1.0,'',''); +REPLACE INTO "demand" VALUES('electricville',2025,'RL',100.0,'',''); +REPLACE INTO "demand_specific_distribution" VALUES('electricville',2025,'s1','d1','RL',0.075,''); +REPLACE INTO "demand_specific_distribution" VALUES('electricville',2025,'s1','d2','RL',0.075,''); +REPLACE INTO "demand_specific_distribution" VALUES('electricville',2025,'s1','d3','RL',0.075,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('electricville',2025,'s2','d1','RL',0.075,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('electricville',2025,'s2','d2','RL',0.075,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('electricville',2025,'s2','d3','RL',0.075,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('electricville',2025,'s1','d4','RL',0.075,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('electricville',2025,'s1','d5','RL',0.2,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('electricville',2025,'s2','d4','RL',0.2,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('electricville',2025,'s2','d5','RL',0.075,NULL); +REPLACE INTO "efficiency" VALUES('electricville', 'HYD', 'EH', 2025, 'ELC', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('electricville', 'ELC', 'bulbs', 2025, 'RL', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('electricville', 'earth', 'well', 2025, 'HYD', 1.0, NULL, 'water source'); +REPLACE INTO "efficiency" VALUES('electricville', 'ELC', 'batt', 2025, 'ELC', 0.75, NULL, NULL); +REPLACE INTO "emission_activity" VALUES('electricville','co2','HYD','EH',2025,'ELC',0.02,NULL,NULL); +REPLACE INTO "lifetime_tech" VALUES('electricville', 'EH', 60.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('electricville', 'bulbs', 100.0, NULL, 'super LED!'); +REPLACE INTO "limit_capacity" VALUES('electricville',2025,'EH','ge',0.1,'',''); +REPLACE INTO "limit_capacity" VALUES('electricville',2025,'batt','ge',0.1,'',''); +REPLACE INTO "limit_capacity" VALUES('electricville',2025,'EH','le',200.0,'',''); +REPLACE INTO "limit_capacity" VALUES('electricville',2025,'batt','le',100.0,'',''); +REPLACE INTO "limit_storage_level_fraction" VALUES('electricville',2025,'s1','d1','batt',2025,'e',0.5,NULL); +REPLACE INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +REPLACE INTO "metadata" VALUES('DB_MAJOR',4,''); +REPLACE INTO "metadata" VALUES('DB_MINOR',0,''); +REPLACE INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +REPLACE INTO "metadata_real" VALUES('global_discount_rate',0.05,''); +REPLACE INTO "operator" VALUES('e','equal to'); +REPLACE INTO "operator" VALUES('le','less than or equal to'); +REPLACE INTO "operator" VALUES('ge','greater than or equal to'); +REPLACE INTO "region" VALUES('electricville',NULL); +REPLACE INTO "season_label" VALUES('s1',NULL); +REPLACE INTO "season_label" VALUES('s2',NULL); +REPLACE INTO "sector_label" VALUES('supply',NULL); +REPLACE INTO "sector_label" VALUES('electric',NULL); +REPLACE INTO "sector_label" VALUES('transport',NULL); +REPLACE INTO "sector_label" VALUES('commercial',NULL); +REPLACE INTO "sector_label" VALUES('residential',NULL); +REPLACE INTO "sector_label" VALUES('industrial',NULL); +REPLACE INTO "storage_duration" VALUES('electricville','batt',10.0,NULL); +REPLACE INTO "technology" VALUES('well','p','supply','water','',0,0,0,0,0,0,0,0,'plain old water'); +REPLACE INTO "technology" VALUES('bulbs','p','residential','electric','',0,0,0,0,0,0,0,0,' residential lighting'); +REPLACE INTO "technology" VALUES('EH','pb','electric','hydro','',0,0,0,0,0,0,0,0,'hydro power electric plant'); +REPLACE INTO "technology" VALUES('batt','ps','electric','electric','',0,0,0,0,0,0,0,0,'big battery'); +REPLACE INTO "technology_type" VALUES('p','production technology'); +REPLACE INTO "technology_type" VALUES('pb','baseload production technology'); +REPLACE INTO "technology_type" VALUES('ps','storage production technology'); +REPLACE INTO "time_of_day" VALUES(1,'d1'); +REPLACE INTO "time_of_day" VALUES(2,'d2'); +REPLACE INTO "time_of_day" VALUES(3,'d3'); +REPLACE INTO "time_of_day" VALUES(4,'d4'); +REPLACE INTO "time_of_day" VALUES(5,'d5'); +REPLACE INTO "time_period" VALUES(1,2020,'e'); +REPLACE INTO "time_period" VALUES(2,2025,'f'); +REPLACE INTO "time_period" VALUES(3,2030,'f'); +REPLACE INTO "time_period_type" VALUES('e','existing vintages'); +REPLACE INTO "time_period_type" VALUES('f','future'); +REPLACE INTO "time_season" VALUES(2025,1,'s1',NULL); +REPLACE INTO "time_season" VALUES(2025,2,'s2',NULL); +REPLACE INTO "time_segment_fraction" VALUES(2025,'s1','d3',0.1,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2025,'s2','d1',0.1,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2025,'s2','d2',0.1,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2025,'s2','d3',0.1,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2025,'s1','d1',0.1,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2025,'s1','d2',0.1,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2025,'s1','d4',0.1,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2025,'s1','d5',0.1,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2025,'s2','d4',0.1,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2025,'s2','d5',0.1,NULL); diff --git a/tests/testing_data/survival_curve.sql b/tests/testing_data/survival_curve.sql index ea6055117..de16ef19d 100644 --- a/tests/testing_data/survival_curve.sql +++ b/tests/testing_data/survival_curve.sql @@ -1,1211 +1,185 @@ -BEGIN TRANSACTION; -CREATE TABLE capacity_credit -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -CREATE TABLE capacity_factor_process -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE capacity_factor_tech -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE capacity_to_activity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES commodity_type (label), - description TEXT -); -INSERT INTO "commodity" VALUES('source','s',NULL); -INSERT INTO "commodity" VALUES('demand','d',NULL); -CREATE TABLE commodity_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "commodity_type" VALUES('p','physical commodity'); -INSERT INTO "commodity_type" VALUES('a','annual commodity'); -INSERT INTO "commodity_type" VALUES('e','emissions commodity'); -INSERT INTO "commodity_type" VALUES('d','demand commodity'); -INSERT INTO "commodity_type" VALUES('s','source commodity'); -INSERT INTO "commodity_type" VALUES('w','waste commodity'); -INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); -INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); -CREATE TABLE construction_input -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage) -); -CREATE TABLE cost_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT NOT NULL - REFERENCES commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE cost_fixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_fixed" VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); -CREATE TABLE cost_invest -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "cost_invest" VALUES('region','tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('region','tech_future',2030,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('region','tech_future',2035,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('region','tech_future',2040,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('region','tech_future',2045,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('region','tech_future',2050,1.0,NULL,NULL); -CREATE TABLE cost_variable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_variable" VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); -CREATE TABLE demand -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - commodity TEXT - REFERENCES commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -INSERT INTO "demand" VALUES('region',2025,'demand',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('region',2030,'demand',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('region',2035,'demand',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('region',2040,'demand',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('region',2045,'demand',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('region',2050,'demand',1.0,NULL,NULL); -CREATE TABLE demand_specific_distribution -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - demand_name TEXT - REFERENCES commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -CREATE TABLE efficiency -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -INSERT INTO "efficiency" VALUES('region','source','tech_ancient',1994,'demand',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','source','tech_old',2010,'demand',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','source','tech_current',2025,'demand',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','source','tech_future',2030,'demand',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','source','tech_future',2035,'demand',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','source','tech_future',2040,'demand',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','source','tech_future',2045,'demand',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','source','tech_future',2050,'demand',1.0,NULL); -CREATE TABLE efficiency_variable -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE emission_activity -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -CREATE TABLE emission_embodied -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE emission_end_of_life -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -CREATE TABLE existing_capacity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "existing_capacity" VALUES('region','tech_ancient',1994,3.0,NULL,NULL); -INSERT INTO "existing_capacity" VALUES('region','tech_old',2010,0.7,NULL,NULL); -CREATE TABLE lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_survival_curve -( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "lifetime_survival_curve" VALUES('region',1994,'tech_ancient',1994,1.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',1999,'tech_ancient',1994,0.97,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2004,'tech_ancient',1994,8.80000000000000115e-01,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2009,'tech_ancient',1994,0.62,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2014,'tech_ancient',1994,0.27,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2019,'tech_ancient',1994,0.08,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2029,'tech_ancient',1994,0.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2010,'tech_old',2010,1.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2015,'tech_old',2010,0.97,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2020,'tech_old',2010,8.80000000000000115e-01,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2025,'tech_old',2010,0.62,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2030,'tech_old',2010,0.27,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2035,'tech_old',2010,0.08,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_old',2010,0.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2025,'tech_current',2025,1.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2030,'tech_current',2025,0.97,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2035,'tech_current',2025,8.80000000000000115e-01,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2040,'tech_current',2025,0.62,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_current',2025,0.27,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_current',2025,0.08,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2060,'tech_current',2025,0.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2030,'tech_future',2030,1.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2035,'tech_future',2030,0.97,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2040,'tech_future',2030,8.80000000000000115e-01,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_future',2030,0.62,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2030,0.27,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2030,0.08,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2065,'tech_future',2030,0.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2035,'tech_future',2035,1.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2040,'tech_future',2035,0.97,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_future',2035,8.80000000000000115e-01,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2035,0.62,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2035,0.27,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2060,'tech_future',2035,0.08,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2070,'tech_future',2035,0.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2040,'tech_future',2040,1.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_future',2040,0.97,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2040,8.80000000000000115e-01,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2040,0.62,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2060,'tech_future',2040,0.27,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2065,'tech_future',2040,0.08,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2075,'tech_future',2040,0.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_future',2045,1.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2045,0.97,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2045,8.80000000000000115e-01,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2060,'tech_future',2045,0.62,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2065,'tech_future',2045,0.27,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2070,'tech_future',2045,0.08,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2080,'tech_future',2045,0.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2050,1.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2050,0.97,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2060,'tech_future',2050,8.80000000000000115e-01,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2065,'tech_future',2050,0.62,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2070,'tech_future',2050,0.27,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2075,'tech_future',2050,0.08,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2085,'tech_future',2050,0.0,NULL); -CREATE TABLE lifetime_tech -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "lifetime_tech" VALUES('region','tech_ancient',35.0,NULL); -INSERT INTO "lifetime_tech" VALUES('region','tech_old',35.0,NULL); -INSERT INTO "lifetime_tech" VALUES('region','tech_current',35.0,NULL); -INSERT INTO "lifetime_tech" VALUES('region','tech_future',35.0,NULL); -CREATE TABLE limit_activity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_degrowth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE limit_growth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) -); -CREATE TABLE limit_storage_level_fraction -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -CREATE TABLE limit_tech_input_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_input_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_output_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE limit_tech_output_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE linked_tech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES technology (tech), - emis_comm TEXT - REFERENCES commodity (name), - driven_tech TEXT - REFERENCES technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -CREATE TABLE loan_lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE loan_rate -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); -INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); -INSERT INTO "metadata" VALUES('DB_MINOR',0,''); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -CREATE TABLE myopic_efficiency -( - base_year integer, - region text, - input_comm text, - tech text, - vintage integer, - output_comm text, - efficiency real, - lifetime integer, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (region, input_comm, tech, vintage, output_comm) -); -CREATE TABLE operator -( - operator TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "operator" VALUES('e','equal to'); -INSERT INTO "operator" VALUES('le','less than or equal to'); -INSERT INTO "operator" VALUES('ge','greater than or equal to'); -CREATE TABLE output_built_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES sector_label (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) -); -CREATE TABLE output_curtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_period (period), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE output_emission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE output_flow_in -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out_summary -( - scenario TEXT NOT NULL, - region TEXT NOT NULL, - sector TEXT, - period INTEGER, - input_comm TEXT NOT NULL, - tech TEXT NOT NULL, - vintage INTEGER, - output_comm TEXT NOT NULL, - flow REAL NOT NULL, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_net_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_objective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE output_retired_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_storage_level -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE planning_reserve_margin -( - region TEXT - PRIMARY KEY - REFERENCES region (region), - margin REAL, - notes TEXT -); -CREATE TABLE ramp_down_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE ramp_up_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -INSERT INTO "region" VALUES('region',NULL); -CREATE TABLE reserve_capacity_derate -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE rps_requirement -( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL - REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES tech_group (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE season_label -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "season_label" VALUES('s',NULL); -CREATE TABLE sector_label -( - sector TEXT PRIMARY KEY, - notes TEXT -); -CREATE TABLE storage_duration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE tech_group -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE tech_group_member -( - group_name TEXT - REFERENCES tech_group (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technology_type (label) -); -INSERT INTO "technology" VALUES('tech_ancient','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO "technology" VALUES('tech_old','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO "technology" VALUES('tech_current','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO "technology" VALUES('tech_future','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -CREATE TABLE technology_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "technology_type" VALUES('p','production technology'); -INSERT INTO "technology_type" VALUES('pb','baseload production technology'); -INSERT INTO "technology_type" VALUES('ps','storage production technology'); -CREATE TABLE time_of_day -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY -); -INSERT INTO "time_of_day" VALUES(0,'d'); -CREATE TABLE time_period -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES time_period_type (label) -); -INSERT INTO "time_period" VALUES(-2,1994,'e'); -INSERT INTO "time_period" VALUES(-1,2010,'e'); -INSERT INTO "time_period" VALUES(0,2025,'f'); -INSERT INTO "time_period" VALUES(1,2030,'f'); -INSERT INTO "time_period" VALUES(2,2035,'f'); -INSERT INTO "time_period" VALUES(3,2040,'f'); -INSERT INTO "time_period" VALUES(4,2045,'f'); -INSERT INTO "time_period" VALUES(5,2050,'f'); -INSERT INTO "time_period" VALUES(6,2055,'f'); -CREATE TABLE time_period_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "time_period_type" VALUES('e','existing vintages'); -INSERT INTO "time_period_type" VALUES('f','future'); -CREATE TABLE time_season -( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - season TEXT REFERENCES season_label(season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); -INSERT INTO "time_season" VALUES(2025,0,'s',NULL); -INSERT INTO "time_season" VALUES(2030,1,'s',NULL); -INSERT INTO "time_season" VALUES(2035,2,'s',NULL); -INSERT INTO "time_season" VALUES(2040,3,'s',NULL); -INSERT INTO "time_season" VALUES(2045,4,'s',NULL); -INSERT INTO "time_season" VALUES(2050,5,'s',NULL); - -CREATE TABLE time_season_sequential -( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT REFERENCES season_label(season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); - -CREATE TABLE time_segment_fraction -( - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - segment_fraction REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); -INSERT INTO "time_segment_fraction" VALUES(2025,'s','d',1.0,NULL); -INSERT INTO "time_segment_fraction" VALUES(2030,'s','d',1.0,NULL); -INSERT INTO "time_segment_fraction" VALUES(2035,'s','d',1.0,NULL); -INSERT INTO "time_segment_fraction" VALUES(2040,'s','d',1.0,NULL); -INSERT INTO "time_segment_fraction" VALUES(2045,'s','d',1.0,NULL); -INSERT INTO "time_segment_fraction" VALUES(2050,'s','d',1.0,NULL); -CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); -COMMIT; +REPLACE INTO "commodity" VALUES('source', 's', NULL, NULL); +REPLACE INTO "commodity" VALUES('demand', 'd', NULL, NULL); +REPLACE INTO "commodity_type" VALUES('p','physical commodity'); +REPLACE INTO "commodity_type" VALUES('a','annual commodity'); +REPLACE INTO "commodity_type" VALUES('e','emissions commodity'); +REPLACE INTO "commodity_type" VALUES('d','demand commodity'); +REPLACE INTO "commodity_type" VALUES('s','source commodity'); +REPLACE INTO "commodity_type" VALUES('w','waste commodity'); +REPLACE INTO "commodity_type" VALUES('wa','waste annual commodity'); +REPLACE INTO "commodity_type" VALUES('wp','waste physical commodity'); +REPLACE INTO "cost_fixed" VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); +REPLACE INTO "cost_fixed" VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('region','tech_current',2025,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('region','tech_future',2030,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('region','tech_future',2035,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('region','tech_future',2040,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('region','tech_future',2045,1.0,NULL,NULL); +REPLACE INTO "cost_invest" VALUES('region','tech_future',2050,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); +REPLACE INTO "cost_variable" VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); +REPLACE INTO "demand" VALUES('region',2025,'demand',1.0,NULL,NULL); +REPLACE INTO "demand" VALUES('region',2030,'demand',1.0,NULL,NULL); +REPLACE INTO "demand" VALUES('region',2035,'demand',1.0,NULL,NULL); +REPLACE INTO "demand" VALUES('region',2040,'demand',1.0,NULL,NULL); +REPLACE INTO "demand" VALUES('region',2045,'demand',1.0,NULL,NULL); +REPLACE INTO "demand" VALUES('region',2050,'demand',1.0,NULL,NULL); +REPLACE INTO "efficiency" VALUES('region', 'source', 'tech_ancient', 1994, 'demand', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('region', 'source', 'tech_old', 2010, 'demand', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('region', 'source', 'tech_current', 2025, 'demand', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('region', 'source', 'tech_future', 2030, 'demand', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('region', 'source', 'tech_future', 2035, 'demand', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('region', 'source', 'tech_future', 2040, 'demand', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('region', 'source', 'tech_future', 2045, 'demand', 1.0, NULL, NULL); +REPLACE INTO "efficiency" VALUES('region', 'source', 'tech_future', 2050, 'demand', 1.0, NULL, NULL); +REPLACE INTO "existing_capacity" VALUES('region','tech_ancient',1994,3.0,NULL,NULL); +REPLACE INTO "existing_capacity" VALUES('region','tech_old',2010,0.7,NULL,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',1994,'tech_ancient',1994,1.0,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',1999,'tech_ancient',1994,0.97,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2004,'tech_ancient',1994,8.80000000000000115e-01,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2009,'tech_ancient',1994,0.62,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2014,'tech_ancient',1994,0.27,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2019,'tech_ancient',1994,0.08,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2029,'tech_ancient',1994,0.0,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2010,'tech_old',2010,1.0,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2015,'tech_old',2010,0.97,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2020,'tech_old',2010,8.80000000000000115e-01,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2025,'tech_old',2010,0.62,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2030,'tech_old',2010,0.27,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2035,'tech_old',2010,0.08,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2045,'tech_old',2010,0.0,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2025,'tech_current',2025,1.0,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2030,'tech_current',2025,0.97,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2035,'tech_current',2025,8.80000000000000115e-01,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2040,'tech_current',2025,0.62,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2045,'tech_current',2025,0.27,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2050,'tech_current',2025,0.08,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2060,'tech_current',2025,0.0,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2030,'tech_future',2030,1.0,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2035,'tech_future',2030,0.97,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2040,'tech_future',2030,8.80000000000000115e-01,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2045,'tech_future',2030,0.62,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2030,0.27,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2030,0.08,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2065,'tech_future',2030,0.0,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2035,'tech_future',2035,1.0,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2040,'tech_future',2035,0.97,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2045,'tech_future',2035,8.80000000000000115e-01,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2035,0.62,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2035,0.27,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2060,'tech_future',2035,0.08,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2070,'tech_future',2035,0.0,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2040,'tech_future',2040,1.0,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2045,'tech_future',2040,0.97,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2040,8.80000000000000115e-01,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2040,0.62,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2060,'tech_future',2040,0.27,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2065,'tech_future',2040,0.08,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2075,'tech_future',2040,0.0,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2045,'tech_future',2045,1.0,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2045,0.97,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2045,8.80000000000000115e-01,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2060,'tech_future',2045,0.62,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2065,'tech_future',2045,0.27,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2070,'tech_future',2045,0.08,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2080,'tech_future',2045,0.0,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2050,1.0,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2050,0.97,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2060,'tech_future',2050,8.80000000000000115e-01,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2065,'tech_future',2050,0.62,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2070,'tech_future',2050,0.27,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2075,'tech_future',2050,0.08,NULL); +REPLACE INTO "lifetime_survival_curve" VALUES('region',2085,'tech_future',2050,0.0,NULL); +REPLACE INTO "lifetime_tech" VALUES('region', 'tech_ancient', 35.0, NULL, NULL); +REPLACE INTO "lifetime_tech" VALUES('region', 'tech_old', 35.0, NULL, NULL); +REPLACE INTO "lifetime_tech" VALUES('region', 'tech_current', 35.0, NULL, NULL); +REPLACE INTO "lifetime_tech" VALUES('region', 'tech_future', 35.0, NULL, NULL); +REPLACE INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +REPLACE INTO "metadata" VALUES('DB_MAJOR',4,''); +REPLACE INTO "metadata" VALUES('DB_MINOR',0,''); +REPLACE INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); +REPLACE INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +REPLACE INTO "operator" VALUES('e','equal to'); +REPLACE INTO "operator" VALUES('le','less than or equal to'); +REPLACE INTO "operator" VALUES('ge','greater than or equal to'); +REPLACE INTO "region" VALUES('region',NULL); +REPLACE INTO "season_label" VALUES('s',NULL); +REPLACE INTO "technology" VALUES('tech_ancient','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +REPLACE INTO "technology" VALUES('tech_old','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +REPLACE INTO "technology" VALUES('tech_current','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +REPLACE INTO "technology" VALUES('tech_future','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); +REPLACE INTO "technology_type" VALUES('p','production technology'); +REPLACE INTO "technology_type" VALUES('pb','baseload production technology'); +REPLACE INTO "technology_type" VALUES('ps','storage production technology'); +REPLACE INTO "time_of_day" VALUES(0,'d'); +REPLACE INTO "time_period" VALUES(-2,1994,'e'); +REPLACE INTO "time_period" VALUES(-1,2010,'e'); +REPLACE INTO "time_period" VALUES(0,2025,'f'); +REPLACE INTO "time_period" VALUES(1,2030,'f'); +REPLACE INTO "time_period" VALUES(2,2035,'f'); +REPLACE INTO "time_period" VALUES(3,2040,'f'); +REPLACE INTO "time_period" VALUES(4,2045,'f'); +REPLACE INTO "time_period" VALUES(5,2050,'f'); +REPLACE INTO "time_period" VALUES(6,2055,'f'); +REPLACE INTO "time_period_type" VALUES('e','existing vintages'); +REPLACE INTO "time_period_type" VALUES('f','future'); +REPLACE INTO "time_season" VALUES(2025,0,'s',NULL); +REPLACE INTO "time_season" VALUES(2030,1,'s',NULL); +REPLACE INTO "time_season" VALUES(2035,2,'s',NULL); +REPLACE INTO "time_season" VALUES(2040,3,'s',NULL); +REPLACE INTO "time_season" VALUES(2045,4,'s',NULL); +REPLACE INTO "time_season" VALUES(2050,5,'s',NULL); +REPLACE INTO "time_segment_fraction" VALUES(2025,'s','d',1.0,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2030,'s','d',1.0,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2035,'s','d',1.0,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2040,'s','d',1.0,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2045,'s','d',1.0,NULL); +REPLACE INTO "time_segment_fraction" VALUES(2050,'s','d',1.0,NULL); diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 89b181fc9..fff350f17 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -1,1583 +1,557 @@ -BEGIN TRANSACTION; -CREATE TABLE capacity_credit -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -CREATE TABLE capacity_factor_process -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE capacity_factor_tech -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'spring','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'spring','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'summer','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'summer','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'fall','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'fall','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'winter','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'winter','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'spring','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'spring','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'summer','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'summer','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'fall','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'fall','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'winter','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'winter','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'spring','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'spring','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'summer','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'summer','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'fall','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'fall','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'winter','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'winter','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'spring','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'spring','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'summer','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'summer','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'fall','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'fall','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'winter','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'winter','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'spring','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'spring','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'summer','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'summer','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'fall','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'fall','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'winter','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'winter','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'spring','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'spring','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'summer','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'summer','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'fall','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'fall','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'winter','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'winter','night','E_SOLPV',0.0,''); -CREATE TABLE capacity_to_activity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "capacity_to_activity" VALUES('R1','S_IMPETH',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R1','S_IMPOIL',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R1','S_IMPNG',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R1','S_IMPURN',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R1','S_OILREF',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R1','E_NGCC',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('R1','E_SOLPV',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('R1','E_BATT',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('R1','E_NUCLEAR',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('R1','T_BLND',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R1','T_DSL',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R1','T_GSL',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R1','T_EV',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R1','R_EH',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R1','R_NGH',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R2','S_IMPETH',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R2','S_IMPOIL',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R2','S_IMPNG',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R2','S_IMPURN',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R2','S_OILREF',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R2','E_NGCC',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('R2','E_SOLPV',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('R2','E_BATT',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('R2','E_NUCLEAR',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('R2','T_BLND',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R2','T_DSL',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R2','T_GSL',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R2','T_EV',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R2','R_EH',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R2','R_NGH',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R1-R2','E_TRANS',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('R2-R1','E_TRANS',31.54,''); -CREATE TABLE commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES commodity_type (label), - description TEXT -); -INSERT INTO "commodity" VALUES('ethos','s','dummy commodity to supply inputs (makes graph easier to read)'); -INSERT INTO "commodity" VALUES('OIL','p','crude oil'); -INSERT INTO "commodity" VALUES('NG','p','natural gas'); -INSERT INTO "commodity" VALUES('URN','p','uranium'); -INSERT INTO "commodity" VALUES('ETH','p','ethanol'); -INSERT INTO "commodity" VALUES('SOL','p','solar insolation'); -INSERT INTO "commodity" VALUES('GSL','p','gasoline'); -INSERT INTO "commodity" VALUES('DSL','p','diesel'); -INSERT INTO "commodity" VALUES('ELC','p','electricity'); -INSERT INTO "commodity" VALUES('E10','p','gasoline blend with 10% ethanol'); -INSERT INTO "commodity" VALUES('VMT','d','travel demand for vehicle-miles traveled'); -INSERT INTO "commodity" VALUES('RH','d','demand for residential heating'); -INSERT INTO "commodity" VALUES('CO2','e','CO2 emissions commodity'); -CREATE TABLE commodity_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "commodity_type" VALUES('w','waste commodity'); -INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); -INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); -INSERT INTO "commodity_type" VALUES('a','annual commodity'); -INSERT INTO "commodity_type" VALUES('s','source commodity'); -INSERT INTO "commodity_type" VALUES('p','physical commodity'); -INSERT INTO "commodity_type" VALUES('e','emissions commodity'); -INSERT INTO "commodity_type" VALUES('d','demand commodity'); -CREATE TABLE construction_input -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage) -); -CREATE TABLE cost_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT NOT NULL - REFERENCES commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE cost_fixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_fixed" VALUES('R1',2020,'E_NGCC',2020,30.6,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2025,'E_NGCC',2020,9.78,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2025,'E_NGCC',2025,9.78,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NGCC',2020,9.78,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NGCC',2025,9.78,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NGCC',2030,9.78,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2020,'E_SOLPV',2020,10.4,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2025,'E_SOLPV',2020,10.4,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2025,'E_SOLPV',2025,9.1,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_SOLPV',2020,10.4,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_SOLPV',2025,9.1,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_SOLPV',2030,9.1,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2020,'E_NUCLEAR',2020,9.809999999999998e+01,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2025,'E_NUCLEAR',2020,9.809999999999998e+01,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2025,'E_NUCLEAR',2025,9.809999999999998e+01,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NUCLEAR',2020,9.809999999999998e+01,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NUCLEAR',2025,9.809999999999998e+01,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NUCLEAR',2030,9.809999999999998e+01,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2020,'E_BATT',2020,7.05,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2025,'E_BATT',2020,7.05,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2025,'E_BATT',2025,7.05,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_BATT',2020,7.05,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_BATT',2025,7.05,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_BATT',2030,7.05,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2020,'E_NGCC',2020,24.48,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2025,'E_NGCC',2020,7.824,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2025,'E_NGCC',2025,7.824,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NGCC',2020,7.824,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NGCC',2025,7.824,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NGCC',2030,7.824,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2020,'E_SOLPV',2020,8.32,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2025,'E_SOLPV',2020,8.32,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2025,'E_SOLPV',2025,7.28,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_SOLPV',2020,8.32,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_SOLPV',2025,7.28,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_SOLPV',2030,7.28,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2020,'E_NUCLEAR',2020,78.48,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2025,'E_NUCLEAR',2020,78.48,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2025,'E_NUCLEAR',2025,78.48,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NUCLEAR',2020,78.48,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NUCLEAR',2025,78.48,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NUCLEAR',2030,78.48,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2020,'E_BATT',2020,5.64,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2025,'E_BATT',2020,5.64,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2025,'E_BATT',2025,5.64,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_BATT',2020,5.64,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_BATT',2025,5.64,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_BATT',2030,5.64,'$M/GWyr',''); -CREATE TABLE cost_invest -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "cost_invest" VALUES('R1','E_NGCC',2020,1050.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','E_NGCC',2025,1025.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','E_NGCC',2030,1000.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','E_SOLPV',2020,900.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','E_SOLPV',2025,560.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','E_SOLPV',2030,800.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','E_NUCLEAR',2020,6145.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','E_NUCLEAR',2025,6045.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','E_NUCLEAR',2030,5890.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','E_BATT',2020,1150.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','E_BATT',2025,720.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','E_BATT',2030,480.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','T_GSL',2020,2570.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R1','T_GSL',2025,2700.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R1','T_GSL',2030,2700.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R1','T_DSL',2020,2715.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R1','T_DSL',2025,2810.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R1','T_DSL',2030,2810.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R1','T_EV',2020,3100.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R1','T_EV',2025,3030.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R1','T_EV',2030,2925.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R1','R_EH',2020,4.1,'$/PJ/yr',''); -INSERT INTO "cost_invest" VALUES('R1','R_EH',2025,4.1,'$/PJ/yr',''); -INSERT INTO "cost_invest" VALUES('R1','R_EH',2030,4.1,'$/PJ/yr',''); -INSERT INTO "cost_invest" VALUES('R1','R_NGH',2020,7.6,'$/PJ/yr',''); -INSERT INTO "cost_invest" VALUES('R1','R_NGH',2025,7.6,'$/PJ/yr',''); -INSERT INTO "cost_invest" VALUES('R1','R_NGH',2030,7.6,'$/PJ/yr',''); -INSERT INTO "cost_invest" VALUES('R2','E_NGCC',2020,840.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','E_NGCC',2025,820.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','E_NGCC',2030,800.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','E_SOLPV',2020,720.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','E_SOLPV',2025,448.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','E_SOLPV',2030,640.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','E_NUCLEAR',2020,4916.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','E_NUCLEAR',2025,4836.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','E_NUCLEAR',2030,4712.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','E_BATT',2020,920.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','E_BATT',2025,576.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','E_BATT',2030,384.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','T_GSL',2020,2056.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R2','T_GSL',2025,2160.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R2','T_GSL',2030,2160.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R2','T_DSL',2020,2172.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R2','T_DSL',2025,2248.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R2','T_DSL',2030,2248.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R2','T_EV',2020,2480.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R2','T_EV',2025,2424.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R2','T_EV',2030,2340.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R2','R_EH',2020,3.28,'$/PJ/yr',''); -INSERT INTO "cost_invest" VALUES('R2','R_EH',2025,3.28,'$/PJ/yr',''); -INSERT INTO "cost_invest" VALUES('R2','R_EH',2030,3.28,'$/PJ/yr',''); -INSERT INTO "cost_invest" VALUES('R2','R_NGH',2020,6.08,'$/PJ/yr',''); -INSERT INTO "cost_invest" VALUES('R2','R_NGH',2025,6.08,'$/PJ/yr',''); -INSERT INTO "cost_invest" VALUES('R2','R_NGH',2030,6.08,'$/PJ/yr',''); -CREATE TABLE cost_variable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_variable" VALUES('R1',2020,'S_IMPETH',2020,32.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2025,'S_IMPETH',2020,32.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2030,'S_IMPETH',2020,32.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2020,'S_IMPOIL',2020,20.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2025,'S_IMPOIL',2020,20.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2030,'S_IMPOIL',2020,20.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2020,'S_IMPNG',2020,4.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2025,'S_IMPNG',2020,4.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2030,'S_IMPNG',2020,4.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2020,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2025,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2030,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2020,'E_NGCC',2020,1.6,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2025,'E_NGCC',2020,1.6,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2025,'E_NGCC',2025,1.7,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2030,'E_NGCC',2020,1.6,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2030,'E_NGCC',2025,1.7,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2030,'E_NGCC',2030,1.8,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2020,'E_NUCLEAR',2020,0.24,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2025,'E_NUCLEAR',2020,0.24,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2025,'E_NUCLEAR',2025,0.25,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2030,'E_NUCLEAR',2020,0.24,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2030,'E_NUCLEAR',2025,0.25,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2030,'E_NUCLEAR',2030,0.26,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2020,'S_IMPETH',2020,25.6,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2025,'S_IMPETH',2020,25.6,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2030,'S_IMPETH',2020,25.6,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2020,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2025,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2030,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2020,'S_IMPNG',2020,3.2,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2025,'S_IMPNG',2020,3.2,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2030,'S_IMPNG',2020,3.2,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2020,'S_OILREF',2020,0.8,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2025,'S_OILREF',2020,0.8,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2030,'S_OILREF',2020,0.8,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2020,'E_NGCC',2020,1.28,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2025,'E_NGCC',2020,1.28,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2025,'E_NGCC',2025,1.36,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2030,'E_NGCC',2020,1.28,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2030,'E_NGCC',2025,1.36,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2030,'E_NGCC',2030,1.44,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2020,'E_NUCLEAR',2020,0.192,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2025,'E_NUCLEAR',2020,0.192,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2025,'E_NUCLEAR',2025,0.2,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2030,'E_NUCLEAR',2020,0.192,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2030,'E_NUCLEAR',2025,0.2,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2030,'E_NUCLEAR',2030,2.08000000000000018e-01,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1-R2',2020,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1-R2',2025,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1-R2',2030,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2-R1',2020,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2-R1',2025,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2-R1',2030,'E_TRANS',2015,0.1,'$M/PJ',''); -CREATE TABLE demand -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - commodity TEXT - REFERENCES commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -INSERT INTO "demand" VALUES('R1',2020,'RH',30.0,'',''); -INSERT INTO "demand" VALUES('R1',2025,'RH',33.0,'',''); -INSERT INTO "demand" VALUES('R1',2030,'RH',36.0,'',''); -INSERT INTO "demand" VALUES('R1',2020,'VMT',84.0,'',''); -INSERT INTO "demand" VALUES('R1',2025,'VMT',91.0,'',''); -INSERT INTO "demand" VALUES('R1',2030,'VMT',98.0,'',''); -INSERT INTO "demand" VALUES('R2',2020,'RH',70.0,'',''); -INSERT INTO "demand" VALUES('R2',2025,'RH',77.0,'',''); -INSERT INTO "demand" VALUES('R2',2030,'RH',84.0,'',''); -INSERT INTO "demand" VALUES('R2',2020,'VMT',36.0,'',''); -INSERT INTO "demand" VALUES('R2',2025,'VMT',39.0,'',''); -INSERT INTO "demand" VALUES('R2',2030,'VMT',42.0,'',''); -CREATE TABLE demand_specific_distribution -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - demand_name TEXT - REFERENCES commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'spring','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'spring','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'summer','day','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'summer','night','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'fall','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'fall','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'winter','day','RH',0.3,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'winter','night','RH',0.4,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'spring','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'spring','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'summer','day','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'summer','night','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'fall','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'fall','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'winter','day','RH',0.3,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'winter','night','RH',0.4,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'spring','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'spring','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'summer','day','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'summer','night','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'fall','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'fall','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'winter','day','RH',0.3,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'winter','night','RH',0.4,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'spring','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'spring','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'summer','day','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'summer','night','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'fall','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'fall','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'winter','day','RH',0.3,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'winter','night','RH',0.4,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'spring','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'spring','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'summer','day','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'summer','night','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'fall','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'fall','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'winter','day','RH',0.3,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'winter','night','RH',0.4,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'spring','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'spring','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'summer','day','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'summer','night','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'fall','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'fall','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'winter','day','RH',0.3,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'winter','night','RH',0.4,''); -CREATE TABLE efficiency -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -INSERT INTO "efficiency" VALUES('R1','ethos','S_IMPETH',2020,'ETH',1.0,''); -INSERT INTO "efficiency" VALUES('R1','ethos','S_IMPOIL',2020,'OIL',1.0,''); -INSERT INTO "efficiency" VALUES('R1','ethos','S_IMPNG',2020,'NG',1.0,''); -INSERT INTO "efficiency" VALUES('R1','ethos','S_IMPURN',2020,'URN',1.0,''); -INSERT INTO "efficiency" VALUES('R1','OIL','S_OILREF',2020,'GSL',1.0,''); -INSERT INTO "efficiency" VALUES('R1','OIL','S_OILREF',2020,'DSL',1.0,''); -INSERT INTO "efficiency" VALUES('R1','ETH','T_BLND',2020,'E10',1.0,''); -INSERT INTO "efficiency" VALUES('R1','GSL','T_BLND',2020,'E10',1.0,''); -INSERT INTO "efficiency" VALUES('R1','NG','E_NGCC',2020,'ELC',0.55,''); -INSERT INTO "efficiency" VALUES('R1','NG','E_NGCC',2025,'ELC',0.55,''); -INSERT INTO "efficiency" VALUES('R1','NG','E_NGCC',2030,'ELC',0.55,''); -INSERT INTO "efficiency" VALUES('R1','SOL','E_SOLPV',2020,'ELC',1.0,''); -INSERT INTO "efficiency" VALUES('R1','SOL','E_SOLPV',2025,'ELC',1.0,''); -INSERT INTO "efficiency" VALUES('R1','SOL','E_SOLPV',2030,'ELC',1.0,''); -INSERT INTO "efficiency" VALUES('R1','URN','E_NUCLEAR',2015,'ELC',0.4,''); -INSERT INTO "efficiency" VALUES('R1','URN','E_NUCLEAR',2020,'ELC',0.4,''); -INSERT INTO "efficiency" VALUES('R1','URN','E_NUCLEAR',2025,'ELC',0.4,''); -INSERT INTO "efficiency" VALUES('R1','URN','E_NUCLEAR',2030,'ELC',0.4,''); -INSERT INTO "efficiency" VALUES('R1','ELC','E_BATT',2020,'ELC',0.85,''); -INSERT INTO "efficiency" VALUES('R1','ELC','E_BATT',2025,'ELC',0.85,''); -INSERT INTO "efficiency" VALUES('R1','ELC','E_BATT',2030,'ELC',0.85,''); -INSERT INTO "efficiency" VALUES('R1','E10','T_GSL',2020,'VMT',0.25,''); -INSERT INTO "efficiency" VALUES('R1','E10','T_GSL',2025,'VMT',0.25,''); -INSERT INTO "efficiency" VALUES('R1','E10','T_GSL',2030,'VMT',0.25,''); -INSERT INTO "efficiency" VALUES('R1','DSL','T_DSL',2020,'VMT',0.3,''); -INSERT INTO "efficiency" VALUES('R1','DSL','T_DSL',2025,'VMT',0.3,''); -INSERT INTO "efficiency" VALUES('R1','DSL','T_DSL',2030,'VMT',0.3,''); -INSERT INTO "efficiency" VALUES('R1','ELC','T_EV',2020,'VMT',0.89,''); -INSERT INTO "efficiency" VALUES('R1','ELC','T_EV',2025,'VMT',0.89,''); -INSERT INTO "efficiency" VALUES('R1','ELC','T_EV',2030,'VMT',0.89,''); -INSERT INTO "efficiency" VALUES('R1','ELC','R_EH',2020,'RH',1.0,''); -INSERT INTO "efficiency" VALUES('R1','ELC','R_EH',2025,'RH',1.0,''); -INSERT INTO "efficiency" VALUES('R1','ELC','R_EH',2030,'RH',1.0,''); -INSERT INTO "efficiency" VALUES('R1','NG','R_NGH',2020,'RH',0.85,''); -INSERT INTO "efficiency" VALUES('R1','NG','R_NGH',2025,'RH',0.85,''); -INSERT INTO "efficiency" VALUES('R1','NG','R_NGH',2030,'RH',0.85,''); -INSERT INTO "efficiency" VALUES('R2','ethos','S_IMPETH',2020,'ETH',1.0,''); -INSERT INTO "efficiency" VALUES('R2','ethos','S_IMPOIL',2020,'OIL',1.0,''); -INSERT INTO "efficiency" VALUES('R2','ethos','S_IMPNG',2020,'NG',1.0,''); -INSERT INTO "efficiency" VALUES('R2','ethos','S_IMPURN',2020,'URN',1.0,''); -INSERT INTO "efficiency" VALUES('R2','OIL','S_OILREF',2020,'GSL',1.0,''); -INSERT INTO "efficiency" VALUES('R2','OIL','S_OILREF',2020,'DSL',1.0,''); -INSERT INTO "efficiency" VALUES('R2','ETH','T_BLND',2020,'E10',1.0,''); -INSERT INTO "efficiency" VALUES('R2','GSL','T_BLND',2020,'E10',1.0,''); -INSERT INTO "efficiency" VALUES('R2','NG','E_NGCC',2020,'ELC',0.55,''); -INSERT INTO "efficiency" VALUES('R2','NG','E_NGCC',2025,'ELC',0.55,''); -INSERT INTO "efficiency" VALUES('R2','NG','E_NGCC',2030,'ELC',0.55,''); -INSERT INTO "efficiency" VALUES('R2','SOL','E_SOLPV',2020,'ELC',1.0,''); -INSERT INTO "efficiency" VALUES('R2','SOL','E_SOLPV',2025,'ELC',1.0,''); -INSERT INTO "efficiency" VALUES('R2','SOL','E_SOLPV',2030,'ELC',1.0,''); -INSERT INTO "efficiency" VALUES('R2','URN','E_NUCLEAR',2015,'ELC',0.4,''); -INSERT INTO "efficiency" VALUES('R2','URN','E_NUCLEAR',2020,'ELC',0.4,''); -INSERT INTO "efficiency" VALUES('R2','URN','E_NUCLEAR',2025,'ELC',0.4,''); -INSERT INTO "efficiency" VALUES('R2','URN','E_NUCLEAR',2030,'ELC',0.4,''); -INSERT INTO "efficiency" VALUES('R2','ELC','E_BATT',2020,'ELC',0.85,''); -INSERT INTO "efficiency" VALUES('R2','ELC','E_BATT',2025,'ELC',0.85,''); -INSERT INTO "efficiency" VALUES('R2','ELC','E_BATT',2030,'ELC',0.85,''); -INSERT INTO "efficiency" VALUES('R2','E10','T_GSL',2020,'VMT',0.25,''); -INSERT INTO "efficiency" VALUES('R2','E10','T_GSL',2025,'VMT',0.25,''); -INSERT INTO "efficiency" VALUES('R2','E10','T_GSL',2030,'VMT',0.25,''); -INSERT INTO "efficiency" VALUES('R2','DSL','T_DSL',2020,'VMT',0.3,''); -INSERT INTO "efficiency" VALUES('R2','DSL','T_DSL',2025,'VMT',0.3,''); -INSERT INTO "efficiency" VALUES('R2','DSL','T_DSL',2030,'VMT',0.3,''); -INSERT INTO "efficiency" VALUES('R2','ELC','T_EV',2020,'VMT',0.89,''); -INSERT INTO "efficiency" VALUES('R2','ELC','T_EV',2025,'VMT',0.89,''); -INSERT INTO "efficiency" VALUES('R2','ELC','T_EV',2030,'VMT',0.89,''); -INSERT INTO "efficiency" VALUES('R2','ELC','R_EH',2020,'RH',1.0,''); -INSERT INTO "efficiency" VALUES('R2','ELC','R_EH',2025,'RH',1.0,''); -INSERT INTO "efficiency" VALUES('R2','ELC','R_EH',2030,'RH',1.0,''); -INSERT INTO "efficiency" VALUES('R2','NG','R_NGH',2020,'RH',0.85,''); -INSERT INTO "efficiency" VALUES('R2','NG','R_NGH',2025,'RH',0.85,''); -INSERT INTO "efficiency" VALUES('R2','NG','R_NGH',2030,'RH',0.85,''); -INSERT INTO "efficiency" VALUES('R1-R2','ELC','E_TRANS',2015,'ELC',0.9,''); -INSERT INTO "efficiency" VALUES('R2-R1','ELC','E_TRANS',2015,'ELC',0.9,''); -CREATE TABLE efficiency_variable -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE emission_activity -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -INSERT INTO "emission_activity" VALUES('R1','CO2','ethos','S_IMPNG',2020,'NG',5.029999999999999e+01,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO "emission_activity" VALUES('R1','CO2','OIL','S_OILREF',2020,'GSL',67.2,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO "emission_activity" VALUES('R1','CO2','OIL','S_OILREF',2020,'DSL',69.4,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO "emission_activity" VALUES('R2','CO2','ethos','S_IMPNG',2020,'NG',5.029999999999999e+01,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO "emission_activity" VALUES('R2','CO2','OIL','S_OILREF',2020,'GSL',67.2,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO "emission_activity" VALUES('R2','CO2','OIL','S_OILREF',2020,'DSL',69.4,'kT/PJ','taken from MIT Energy Fact Sheet'); -CREATE TABLE emission_embodied -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE emission_end_of_life -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -CREATE TABLE existing_capacity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "existing_capacity" VALUES('R1','E_NUCLEAR',2015,0.07,'GW',''); -INSERT INTO "existing_capacity" VALUES('R2','E_NUCLEAR',2015,0.03,'GW',''); -INSERT INTO "existing_capacity" VALUES('R1-R2','E_TRANS',2015,10.0,'GW',''); -INSERT INTO "existing_capacity" VALUES('R2-R1','E_TRANS',2015,10.0,'GW',''); -CREATE TABLE lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_survival_curve -( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE lifetime_tech -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "lifetime_tech" VALUES('R1','S_IMPETH',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','S_IMPOIL',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','S_IMPNG',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','S_IMPURN',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','S_OILREF',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','E_NGCC',30.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','E_SOLPV',30.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','E_BATT',20.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','E_NUCLEAR',50.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','T_BLND',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','T_DSL',12.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','T_GSL',12.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','T_EV',12.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','R_EH',20.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','R_NGH',20.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','S_IMPETH',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','S_IMPOIL',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','S_IMPNG',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','S_IMPURN',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','S_OILREF',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','E_NGCC',30.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','E_SOLPV',30.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','E_BATT',20.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','E_NUCLEAR',50.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','T_BLND',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','T_DSL',12.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','T_GSL',12.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','T_EV',12.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','R_EH',20.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','R_NGH',20.0,''); -INSERT INTO "lifetime_tech" VALUES('R1-R2','E_TRANS',30.0,''); -INSERT INTO "lifetime_tech" VALUES('R2-R1','E_TRANS',30.0,''); -CREATE TABLE limit_activity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -INSERT INTO "limit_activity" VALUES('R1',2020,'T_GSL','ge',35.0,'',''); -INSERT INTO "limit_activity" VALUES('R1',2025,'T_GSL','ge',35.0,'',''); -INSERT INTO "limit_activity" VALUES('R1',2030,'T_GSL','ge',35.0,'',''); -INSERT INTO "limit_activity" VALUES('R2',2020,'T_GSL','ge',15.0,'',''); -INSERT INTO "limit_activity" VALUES('R2',2025,'T_GSL','ge',15.0,'',''); -INSERT INTO "limit_activity" VALUES('R2',2030,'T_GSL','ge',15.0,'',''); -CREATE TABLE limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_degrowth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -INSERT INTO "limit_emission" VALUES('R1',2020,'CO2','le',25000.0,'kT CO2',''); -INSERT INTO "limit_emission" VALUES('R1',2025,'CO2','le',24000.0,'kT CO2',''); -INSERT INTO "limit_emission" VALUES('R1',2030,'CO2','le',23000.0,'kT CO2',''); -INSERT INTO "limit_emission" VALUES('global',2020,'CO2','le',37500.0,'kT CO2',''); -INSERT INTO "limit_emission" VALUES('global',2025,'CO2','le',36000.0,'kT CO2',''); -INSERT INTO "limit_emission" VALUES('global',2030,'CO2','le',34500.0,'kT CO2',''); -CREATE TABLE limit_growth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) -); -CREATE TABLE limit_storage_level_fraction -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -INSERT INTO "limit_storage_level_fraction" VALUES('R1',2025,'winter','day','E_BATT',2025,'e',0.5,''); -INSERT INTO "limit_storage_level_fraction" VALUES('R2',2020,'summer','day','E_BATT',2020,'e',0.5,''); -CREATE TABLE limit_tech_input_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -INSERT INTO "limit_tech_input_split" VALUES('R1',2020,'GSL','T_BLND','ge',0.9,''); -INSERT INTO "limit_tech_input_split" VALUES('R1',2020,'ETH','T_BLND','ge',0.1,''); -INSERT INTO "limit_tech_input_split" VALUES('R1',2025,'GSL','T_BLND','ge',0.9,''); -INSERT INTO "limit_tech_input_split" VALUES('R1',2025,'ETH','T_BLND','ge',0.1,''); -INSERT INTO "limit_tech_input_split" VALUES('R1',2030,'GSL','T_BLND','ge',0.9,''); -INSERT INTO "limit_tech_input_split" VALUES('R1',2030,'ETH','T_BLND','ge',0.1,''); -INSERT INTO "limit_tech_input_split" VALUES('R2',2020,'GSL','T_BLND','ge',0.72,''); -INSERT INTO "limit_tech_input_split" VALUES('R2',2020,'ETH','T_BLND','ge',0.08,''); -INSERT INTO "limit_tech_input_split" VALUES('R2',2025,'GSL','T_BLND','ge',0.72,''); -INSERT INTO "limit_tech_input_split" VALUES('R2',2025,'ETH','T_BLND','ge',0.08,''); -INSERT INTO "limit_tech_input_split" VALUES('R2',2030,'GSL','T_BLND','ge',0.72,''); -INSERT INTO "limit_tech_input_split" VALUES('R2',2030,'ETH','T_BLND','ge',0.08,''); -CREATE TABLE limit_tech_input_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_output_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -INSERT INTO "limit_tech_output_split" VALUES('R1',2020,'S_OILREF','GSL','ge',0.9,''); -INSERT INTO "limit_tech_output_split" VALUES('R1',2020,'S_OILREF','DSL','ge',0.1,''); -INSERT INTO "limit_tech_output_split" VALUES('R1',2025,'S_OILREF','GSL','ge',0.9,''); -INSERT INTO "limit_tech_output_split" VALUES('R1',2025,'S_OILREF','DSL','ge',0.1,''); -INSERT INTO "limit_tech_output_split" VALUES('R1',2030,'S_OILREF','GSL','ge',0.9,''); -INSERT INTO "limit_tech_output_split" VALUES('R1',2030,'S_OILREF','DSL','ge',0.1,''); -INSERT INTO "limit_tech_output_split" VALUES('R2',2020,'S_OILREF','GSL','ge',0.72,''); -INSERT INTO "limit_tech_output_split" VALUES('R2',2020,'S_OILREF','DSL','ge',0.08,''); -INSERT INTO "limit_tech_output_split" VALUES('R2',2025,'S_OILREF','GSL','ge',0.72,''); -INSERT INTO "limit_tech_output_split" VALUES('R2',2025,'S_OILREF','DSL','ge',0.08,''); -INSERT INTO "limit_tech_output_split" VALUES('R2',2030,'S_OILREF','GSL','ge',0.72,''); -INSERT INTO "limit_tech_output_split" VALUES('R2',2030,'S_OILREF','DSL','ge',0.08,''); -CREATE TABLE limit_tech_output_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE linked_tech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES technology (tech), - emis_comm TEXT - REFERENCES commodity (name), - driven_tech TEXT - REFERENCES technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -CREATE TABLE loan_lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE loan_rate -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); -INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); -INSERT INTO "metadata" VALUES('DB_MINOR',0,''); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,''); -CREATE TABLE myopic_efficiency -( - base_year integer, - region text, - input_comm text, - tech text, - vintage integer, - output_comm text, - efficiency real, - lifetime integer, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (region, input_comm, tech, vintage, output_comm) -); -CREATE TABLE operator -( - operator TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "operator" VALUES('e','equal to'); -INSERT INTO "operator" VALUES('le','less than or equal to'); -INSERT INTO "operator" VALUES('ge','greater than or equal to'); -CREATE TABLE output_built_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES sector_label (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) -); -CREATE TABLE output_curtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_period (period), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE output_emission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE output_flow_in -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out_summary -( - scenario TEXT NOT NULL, - region TEXT NOT NULL, - sector TEXT, - period INTEGER, - input_comm TEXT NOT NULL, - tech TEXT NOT NULL, - vintage INTEGER, - output_comm TEXT NOT NULL, - flow REAL NOT NULL, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_net_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_objective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE output_retired_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_storage_level -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE planning_reserve_margin -( - region TEXT - PRIMARY KEY - REFERENCES region (region), - margin REAL, - notes TEXT -); -CREATE TABLE ramp_down_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE ramp_up_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -INSERT INTO "region" VALUES('R1',NULL); -INSERT INTO "region" VALUES('R2',NULL); -CREATE TABLE reserve_capacity_derate -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE rps_requirement -( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL - REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES tech_group (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE season_label -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "season_label" VALUES('summer',NULL); -INSERT INTO "season_label" VALUES('fall',NULL); -INSERT INTO "season_label" VALUES('winter',NULL); -INSERT INTO "season_label" VALUES('spring',NULL); -CREATE TABLE sector_label -( - sector TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "sector_label" VALUES('supply',NULL); -INSERT INTO "sector_label" VALUES('electric',NULL); -INSERT INTO "sector_label" VALUES('transport',NULL); -INSERT INTO "sector_label" VALUES('commercial',NULL); -INSERT INTO "sector_label" VALUES('residential',NULL); -INSERT INTO "sector_label" VALUES('industrial',NULL); -CREATE TABLE storage_duration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "storage_duration" VALUES('R1','E_BATT',8.0,'8-hour duration specified as fraction of a day'); -INSERT INTO "storage_duration" VALUES('R2','E_BATT',8.0,'8-hour duration specified as fraction of a day'); -CREATE TABLE tech_group -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE tech_group_member -( - group_name TEXT - REFERENCES tech_group (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technology_type (label) -); -INSERT INTO "technology" VALUES('S_IMPETH','p','supply','','',1,0,0,0,0,0,0,0,' imported ethanol'); -INSERT INTO "technology" VALUES('S_IMPOIL','p','supply','','',1,0,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO "technology" VALUES('S_IMPNG','p','supply','','',1,0,0,0,0,0,0,0,' imported natural gas'); -INSERT INTO "technology" VALUES('S_IMPURN','p','supply','','',1,0,0,0,0,0,0,0,' imported uranium'); -INSERT INTO "technology" VALUES('S_OILREF','p','supply','','',0,0,0,1,0,0,0,0,' crude oil refinery'); -INSERT INTO "technology" VALUES('E_NGCC','p','electric','','',0,0,0,0,0,0,0,0,' natural gas combined-cycle'); -INSERT INTO "technology" VALUES('E_SOLPV','p','electric','','',0,0,0,0,0,0,0,0,' solar photovoltaic'); -INSERT INTO "technology" VALUES('E_BATT','ps','electric','','',0,0,0,0,0,0,0,0,' lithium-ion battery'); -INSERT INTO "technology" VALUES('E_NUCLEAR','pb','electric','','',0,0,0,0,0,0,0,0,' nuclear power plant'); -INSERT INTO "technology" VALUES('T_BLND','p','transport','','',0,0,0,0,0,0,0,0,'ethanol - gasoline blending process'); -INSERT INTO "technology" VALUES('T_DSL','p','transport','','',0,0,0,0,0,0,0,0,'diesel vehicle'); -INSERT INTO "technology" VALUES('T_GSL','p','transport','','',0,0,0,0,0,0,0,0,'gasoline vehicle'); -INSERT INTO "technology" VALUES('T_EV','p','transport','','',0,0,0,0,0,0,0,0,'electric vehicle'); -INSERT INTO "technology" VALUES('R_EH','p','residential','','',0,0,0,0,0,0,0,0,' electric residential heating'); -INSERT INTO "technology" VALUES('R_NGH','p','residential','','',0,0,0,0,0,0,0,0,' natural gas residential heating'); -INSERT INTO "technology" VALUES('E_TRANS','p','electric','','',0,0,0,0,0,0,1,0,'electric transmission'); -CREATE TABLE technology_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "technology_type" VALUES('p','production technology'); -INSERT INTO "technology_type" VALUES('pb','baseload production technology'); -INSERT INTO "technology_type" VALUES('ps','storage production technology'); -CREATE TABLE time_of_day -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY -); -INSERT INTO "time_of_day" VALUES(1,'day'); -INSERT INTO "time_of_day" VALUES(2,'night'); -CREATE TABLE time_period -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES time_period_type (label) -); -INSERT INTO "time_period" VALUES(1,2015,'e'); -INSERT INTO "time_period" VALUES(2,2020,'f'); -INSERT INTO "time_period" VALUES(3,2025,'f'); -INSERT INTO "time_period" VALUES(4,2030,'f'); -INSERT INTO "time_period" VALUES(5,2035,'f'); -CREATE TABLE time_period_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "time_period_type" VALUES('e','existing vintages'); -INSERT INTO "time_period_type" VALUES('f','future'); -CREATE TABLE time_season -( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - season TEXT REFERENCES season_label(season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); -INSERT INTO "time_season" VALUES(2020,1,'spring',NULL); -INSERT INTO "time_season" VALUES(2020,2,'summer',NULL); -INSERT INTO "time_season" VALUES(2020,3,'fall',NULL); -INSERT INTO "time_season" VALUES(2020,4,'winter',NULL); -INSERT INTO "time_season" VALUES(2025,1,'spring',NULL); -INSERT INTO "time_season" VALUES(2025,2,'summer',NULL); -INSERT INTO "time_season" VALUES(2025,3,'fall',NULL); -INSERT INTO "time_season" VALUES(2025,4,'winter',NULL); -INSERT INTO "time_season" VALUES(2030,1,'spring',NULL); -INSERT INTO "time_season" VALUES(2030,2,'summer',NULL); -INSERT INTO "time_season" VALUES(2030,3,'fall',NULL); -INSERT INTO "time_season" VALUES(2030,4,'winter',NULL); - -CREATE TABLE time_season_sequential -( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT REFERENCES season_label(season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); - -CREATE TABLE time_segment_fraction -( - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - segment_fraction REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); -INSERT INTO "time_segment_fraction" VALUES(2020,'spring','day',0.125,'Spring - Day'); -INSERT INTO "time_segment_fraction" VALUES(2020,'spring','night',0.125,'Spring - Night'); -INSERT INTO "time_segment_fraction" VALUES(2020,'summer','day',0.125,'Summer - Day'); -INSERT INTO "time_segment_fraction" VALUES(2020,'summer','night',0.125,'Summer - Night'); -INSERT INTO "time_segment_fraction" VALUES(2020,'fall','day',0.125,'Fall - Day'); -INSERT INTO "time_segment_fraction" VALUES(2020,'fall','night',0.125,'Fall - Night'); -INSERT INTO "time_segment_fraction" VALUES(2020,'winter','day',0.125,'Winter - Day'); -INSERT INTO "time_segment_fraction" VALUES(2020,'winter','night',0.125,'Winter - Night'); -INSERT INTO "time_segment_fraction" VALUES(2025,'spring','day',0.125,'Spring - Day'); -INSERT INTO "time_segment_fraction" VALUES(2025,'spring','night',0.125,'Spring - Night'); -INSERT INTO "time_segment_fraction" VALUES(2025,'summer','day',0.125,'Summer - Day'); -INSERT INTO "time_segment_fraction" VALUES(2025,'summer','night',0.125,'Summer - Night'); -INSERT INTO "time_segment_fraction" VALUES(2025,'fall','day',0.125,'Fall - Day'); -INSERT INTO "time_segment_fraction" VALUES(2025,'fall','night',0.125,'Fall - Night'); -INSERT INTO "time_segment_fraction" VALUES(2025,'winter','day',0.125,'Winter - Day'); -INSERT INTO "time_segment_fraction" VALUES(2025,'winter','night',0.125,'Winter - Night'); -INSERT INTO "time_segment_fraction" VALUES(2030,'spring','day',0.125,'Spring - Day'); -INSERT INTO "time_segment_fraction" VALUES(2030,'spring','night',0.125,'Spring - Night'); -INSERT INTO "time_segment_fraction" VALUES(2030,'summer','day',0.125,'Summer - Day'); -INSERT INTO "time_segment_fraction" VALUES(2030,'summer','night',0.125,'Summer - Night'); -INSERT INTO "time_segment_fraction" VALUES(2030,'fall','day',0.125,'Fall - Day'); -INSERT INTO "time_segment_fraction" VALUES(2030,'fall','night',0.125,'Fall - Night'); -INSERT INTO "time_segment_fraction" VALUES(2030,'winter','day',0.125,'Winter - Day'); -INSERT INTO "time_segment_fraction" VALUES(2030,'winter','night',0.125,'Winter - Night'); -CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); -COMMIT; +REPLACE INTO "capacity_factor_tech" VALUES('R1',2020,'spring','day','E_SOLPV',0.6,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1',2020,'spring','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1',2020,'summer','day','E_SOLPV',0.6,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1',2020,'summer','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1',2020,'fall','day','E_SOLPV',0.6,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1',2020,'fall','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1',2020,'winter','day','E_SOLPV',0.6,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1',2020,'winter','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2020,'spring','day','E_SOLPV',0.48,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2020,'spring','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2020,'summer','day','E_SOLPV',0.48,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2020,'summer','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2020,'fall','day','E_SOLPV',0.48,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2020,'fall','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2020,'winter','day','E_SOLPV',0.48,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2020,'winter','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1',2025,'spring','day','E_SOLPV',0.6,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1',2025,'spring','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1',2025,'summer','day','E_SOLPV',0.6,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1',2025,'summer','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1',2025,'fall','day','E_SOLPV',0.6,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1',2025,'fall','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1',2025,'winter','day','E_SOLPV',0.6,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1',2025,'winter','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2025,'spring','day','E_SOLPV',0.48,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2025,'spring','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2025,'summer','day','E_SOLPV',0.48,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2025,'summer','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2025,'fall','day','E_SOLPV',0.48,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2025,'fall','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2025,'winter','day','E_SOLPV',0.48,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2025,'winter','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1',2030,'spring','day','E_SOLPV',0.6,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1',2030,'spring','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1',2030,'summer','day','E_SOLPV',0.6,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1',2030,'summer','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1',2030,'fall','day','E_SOLPV',0.6,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1',2030,'fall','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1',2030,'winter','day','E_SOLPV',0.6,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1',2030,'winter','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2030,'spring','day','E_SOLPV',0.48,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2030,'spring','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2030,'summer','day','E_SOLPV',0.48,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2030,'summer','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2030,'fall','day','E_SOLPV',0.48,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2030,'fall','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2030,'winter','day','E_SOLPV',0.48,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2',2030,'winter','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_to_activity" VALUES('R1', 'S_IMPETH', 1.0, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R1', 'S_IMPOIL', 1.0, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R1', 'S_IMPNG', 1.0, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R1', 'S_IMPURN', 1.0, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R1', 'S_OILREF', 1.0, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R1', 'E_NGCC', 31.54, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R1', 'E_SOLPV', 31.54, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R1', 'E_BATT', 31.54, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R1', 'E_NUCLEAR', 31.54, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R1', 'T_BLND', 1.0, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R1', 'T_DSL', 1.0, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R1', 'T_GSL', 1.0, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R1', 'T_EV', 1.0, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R1', 'R_EH', 1.0, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R1', 'R_NGH', 1.0, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R2', 'S_IMPETH', 1.0, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R2', 'S_IMPOIL', 1.0, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R2', 'S_IMPNG', 1.0, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R2', 'S_IMPURN', 1.0, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R2', 'S_OILREF', 1.0, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R2', 'E_NGCC', 31.54, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R2', 'E_SOLPV', 31.54, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R2', 'E_BATT', 31.54, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R2', 'E_NUCLEAR', 31.54, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R2', 'T_BLND', 1.0, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R2', 'T_DSL', 1.0, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R2', 'T_GSL', 1.0, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R2', 'T_EV', 1.0, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R2', 'R_EH', 1.0, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R2', 'R_NGH', 1.0, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R1-R2', 'E_TRANS', 31.54, NULL, ''); +REPLACE INTO "capacity_to_activity" VALUES('R2-R1', 'E_TRANS', 31.54, NULL, ''); +REPLACE INTO "commodity" VALUES('ethos', 's', 'dummy commodity to supply inputs (makes graph easier to read)', NULL); +REPLACE INTO "commodity" VALUES('OIL', 'p', 'crude oil', NULL); +REPLACE INTO "commodity" VALUES('NG', 'p', 'natural gas', NULL); +REPLACE INTO "commodity" VALUES('URN', 'p', 'uranium', NULL); +REPLACE INTO "commodity" VALUES('ETH', 'p', 'ethanol', NULL); +REPLACE INTO "commodity" VALUES('SOL', 'p', 'solar insolation', NULL); +REPLACE INTO "commodity" VALUES('GSL', 'p', 'gasoline', NULL); +REPLACE INTO "commodity" VALUES('DSL', 'p', 'diesel', NULL); +REPLACE INTO "commodity" VALUES('ELC', 'p', 'electricity', NULL); +REPLACE INTO "commodity" VALUES('E10', 'p', 'gasoline blend with 10% ethanol', NULL); +REPLACE INTO "commodity" VALUES('VMT', 'd', 'travel demand for vehicle-miles traveled', NULL); +REPLACE INTO "commodity" VALUES('RH', 'd', 'demand for residential heating', NULL); +REPLACE INTO "commodity" VALUES('CO2', 'e', 'CO2 emissions commodity', NULL); +REPLACE INTO "commodity_type" VALUES('w','waste commodity'); +REPLACE INTO "commodity_type" VALUES('wa','waste annual commodity'); +REPLACE INTO "commodity_type" VALUES('wp','waste physical commodity'); +REPLACE INTO "commodity_type" VALUES('a','annual commodity'); +REPLACE INTO "commodity_type" VALUES('s','source commodity'); +REPLACE INTO "commodity_type" VALUES('p','physical commodity'); +REPLACE INTO "commodity_type" VALUES('e','emissions commodity'); +REPLACE INTO "commodity_type" VALUES('d','demand commodity'); +REPLACE INTO "cost_fixed" VALUES('R1',2020,'E_NGCC',2020,30.6,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R1',2025,'E_NGCC',2020,9.78,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R1',2025,'E_NGCC',2025,9.78,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R1',2030,'E_NGCC',2020,9.78,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R1',2030,'E_NGCC',2025,9.78,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R1',2030,'E_NGCC',2030,9.78,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R1',2020,'E_SOLPV',2020,10.4,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R1',2025,'E_SOLPV',2020,10.4,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R1',2025,'E_SOLPV',2025,9.1,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R1',2030,'E_SOLPV',2020,10.4,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R1',2030,'E_SOLPV',2025,9.1,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R1',2030,'E_SOLPV',2030,9.1,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R1',2020,'E_NUCLEAR',2020,9.809999999999998e+01,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R1',2025,'E_NUCLEAR',2020,9.809999999999998e+01,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R1',2025,'E_NUCLEAR',2025,9.809999999999998e+01,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R1',2030,'E_NUCLEAR',2020,9.809999999999998e+01,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R1',2030,'E_NUCLEAR',2025,9.809999999999998e+01,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R1',2030,'E_NUCLEAR',2030,9.809999999999998e+01,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R1',2020,'E_BATT',2020,7.05,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R1',2025,'E_BATT',2020,7.05,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R1',2025,'E_BATT',2025,7.05,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R1',2030,'E_BATT',2020,7.05,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R1',2030,'E_BATT',2025,7.05,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R1',2030,'E_BATT',2030,7.05,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2020,'E_NGCC',2020,24.48,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2025,'E_NGCC',2020,7.824,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2025,'E_NGCC',2025,7.824,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2030,'E_NGCC',2020,7.824,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2030,'E_NGCC',2025,7.824,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2030,'E_NGCC',2030,7.824,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2020,'E_SOLPV',2020,8.32,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2025,'E_SOLPV',2020,8.32,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2025,'E_SOLPV',2025,7.28,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2030,'E_SOLPV',2020,8.32,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2030,'E_SOLPV',2025,7.28,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2030,'E_SOLPV',2030,7.28,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2020,'E_NUCLEAR',2020,78.48,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2025,'E_NUCLEAR',2020,78.48,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2025,'E_NUCLEAR',2025,78.48,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2030,'E_NUCLEAR',2020,78.48,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2030,'E_NUCLEAR',2025,78.48,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2030,'E_NUCLEAR',2030,78.48,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2020,'E_BATT',2020,5.64,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2025,'E_BATT',2020,5.64,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2025,'E_BATT',2025,5.64,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2030,'E_BATT',2020,5.64,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2030,'E_BATT',2025,5.64,'$M/GWyr',''); +REPLACE INTO "cost_fixed" VALUES('R2',2030,'E_BATT',2030,5.64,'$M/GWyr',''); +REPLACE INTO "cost_invest" VALUES('R1','E_NGCC',2020,1050.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R1','E_NGCC',2025,1025.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R1','E_NGCC',2030,1000.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R1','E_SOLPV',2020,900.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R1','E_SOLPV',2025,560.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R1','E_SOLPV',2030,800.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R1','E_NUCLEAR',2020,6145.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R1','E_NUCLEAR',2025,6045.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R1','E_NUCLEAR',2030,5890.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R1','E_BATT',2020,1150.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R1','E_BATT',2025,720.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R1','E_BATT',2030,480.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R1','T_GSL',2020,2570.0,'$/bvmt/yr',''); +REPLACE INTO "cost_invest" VALUES('R1','T_GSL',2025,2700.0,'$/bvmt/yr',''); +REPLACE INTO "cost_invest" VALUES('R1','T_GSL',2030,2700.0,'$/bvmt/yr',''); +REPLACE INTO "cost_invest" VALUES('R1','T_DSL',2020,2715.0,'$/bvmt/yr',''); +REPLACE INTO "cost_invest" VALUES('R1','T_DSL',2025,2810.0,'$/bvmt/yr',''); +REPLACE INTO "cost_invest" VALUES('R1','T_DSL',2030,2810.0,'$/bvmt/yr',''); +REPLACE INTO "cost_invest" VALUES('R1','T_EV',2020,3100.0,'$/bvmt/yr',''); +REPLACE INTO "cost_invest" VALUES('R1','T_EV',2025,3030.0,'$/bvmt/yr',''); +REPLACE INTO "cost_invest" VALUES('R1','T_EV',2030,2925.0,'$/bvmt/yr',''); +REPLACE INTO "cost_invest" VALUES('R1','R_EH',2020,4.1,'$/PJ/yr',''); +REPLACE INTO "cost_invest" VALUES('R1','R_EH',2025,4.1,'$/PJ/yr',''); +REPLACE INTO "cost_invest" VALUES('R1','R_EH',2030,4.1,'$/PJ/yr',''); +REPLACE INTO "cost_invest" VALUES('R1','R_NGH',2020,7.6,'$/PJ/yr',''); +REPLACE INTO "cost_invest" VALUES('R1','R_NGH',2025,7.6,'$/PJ/yr',''); +REPLACE INTO "cost_invest" VALUES('R1','R_NGH',2030,7.6,'$/PJ/yr',''); +REPLACE INTO "cost_invest" VALUES('R2','E_NGCC',2020,840.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R2','E_NGCC',2025,820.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R2','E_NGCC',2030,800.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R2','E_SOLPV',2020,720.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R2','E_SOLPV',2025,448.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R2','E_SOLPV',2030,640.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R2','E_NUCLEAR',2020,4916.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R2','E_NUCLEAR',2025,4836.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R2','E_NUCLEAR',2030,4712.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R2','E_BATT',2020,920.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R2','E_BATT',2025,576.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R2','E_BATT',2030,384.0,'$M/GW',''); +REPLACE INTO "cost_invest" VALUES('R2','T_GSL',2020,2056.0,'$/bvmt/yr',''); +REPLACE INTO "cost_invest" VALUES('R2','T_GSL',2025,2160.0,'$/bvmt/yr',''); +REPLACE INTO "cost_invest" VALUES('R2','T_GSL',2030,2160.0,'$/bvmt/yr',''); +REPLACE INTO "cost_invest" VALUES('R2','T_DSL',2020,2172.0,'$/bvmt/yr',''); +REPLACE INTO "cost_invest" VALUES('R2','T_DSL',2025,2248.0,'$/bvmt/yr',''); +REPLACE INTO "cost_invest" VALUES('R2','T_DSL',2030,2248.0,'$/bvmt/yr',''); +REPLACE INTO "cost_invest" VALUES('R2','T_EV',2020,2480.0,'$/bvmt/yr',''); +REPLACE INTO "cost_invest" VALUES('R2','T_EV',2025,2424.0,'$/bvmt/yr',''); +REPLACE INTO "cost_invest" VALUES('R2','T_EV',2030,2340.0,'$/bvmt/yr',''); +REPLACE INTO "cost_invest" VALUES('R2','R_EH',2020,3.28,'$/PJ/yr',''); +REPLACE INTO "cost_invest" VALUES('R2','R_EH',2025,3.28,'$/PJ/yr',''); +REPLACE INTO "cost_invest" VALUES('R2','R_EH',2030,3.28,'$/PJ/yr',''); +REPLACE INTO "cost_invest" VALUES('R2','R_NGH',2020,6.08,'$/PJ/yr',''); +REPLACE INTO "cost_invest" VALUES('R2','R_NGH',2025,6.08,'$/PJ/yr',''); +REPLACE INTO "cost_invest" VALUES('R2','R_NGH',2030,6.08,'$/PJ/yr',''); +REPLACE INTO "cost_variable" VALUES('R1',2020,'S_IMPETH',2020,32.0,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1',2025,'S_IMPETH',2020,32.0,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1',2030,'S_IMPETH',2020,32.0,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1',2020,'S_IMPOIL',2020,20.0,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1',2025,'S_IMPOIL',2020,20.0,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1',2030,'S_IMPOIL',2020,20.0,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1',2020,'S_IMPNG',2020,4.0,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1',2025,'S_IMPNG',2020,4.0,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1',2030,'S_IMPNG',2020,4.0,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1',2020,'S_OILREF',2020,1.0,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1',2025,'S_OILREF',2020,1.0,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1',2030,'S_OILREF',2020,1.0,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1',2020,'E_NGCC',2020,1.6,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1',2025,'E_NGCC',2020,1.6,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1',2025,'E_NGCC',2025,1.7,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1',2030,'E_NGCC',2020,1.6,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1',2030,'E_NGCC',2025,1.7,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1',2030,'E_NGCC',2030,1.8,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1',2020,'E_NUCLEAR',2020,0.24,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1',2025,'E_NUCLEAR',2020,0.24,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1',2025,'E_NUCLEAR',2025,0.25,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1',2030,'E_NUCLEAR',2020,0.24,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1',2030,'E_NUCLEAR',2025,0.25,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1',2030,'E_NUCLEAR',2030,0.26,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2020,'S_IMPETH',2020,25.6,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2025,'S_IMPETH',2020,25.6,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2030,'S_IMPETH',2020,25.6,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2020,'S_IMPOIL',2020,16.0,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2025,'S_IMPOIL',2020,16.0,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2030,'S_IMPOIL',2020,16.0,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2020,'S_IMPNG',2020,3.2,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2025,'S_IMPNG',2020,3.2,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2030,'S_IMPNG',2020,3.2,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2020,'S_OILREF',2020,0.8,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2025,'S_OILREF',2020,0.8,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2030,'S_OILREF',2020,0.8,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2020,'E_NGCC',2020,1.28,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2025,'E_NGCC',2020,1.28,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2025,'E_NGCC',2025,1.36,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2030,'E_NGCC',2020,1.28,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2030,'E_NGCC',2025,1.36,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2030,'E_NGCC',2030,1.44,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2020,'E_NUCLEAR',2020,0.192,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2025,'E_NUCLEAR',2020,0.192,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2025,'E_NUCLEAR',2025,0.2,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2030,'E_NUCLEAR',2020,0.192,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2030,'E_NUCLEAR',2025,0.2,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2',2030,'E_NUCLEAR',2030,2.08000000000000018e-01,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1-R2',2020,'E_TRANS',2015,0.1,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1-R2',2025,'E_TRANS',2015,0.1,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R1-R2',2030,'E_TRANS',2015,0.1,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2-R1',2020,'E_TRANS',2015,0.1,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2-R1',2025,'E_TRANS',2015,0.1,'$M/PJ',''); +REPLACE INTO "cost_variable" VALUES('R2-R1',2030,'E_TRANS',2015,0.1,'$M/PJ',''); +REPLACE INTO "demand" VALUES('R1',2020,'RH',30.0,'',''); +REPLACE INTO "demand" VALUES('R1',2025,'RH',33.0,'',''); +REPLACE INTO "demand" VALUES('R1',2030,'RH',36.0,'',''); +REPLACE INTO "demand" VALUES('R1',2020,'VMT',84.0,'',''); +REPLACE INTO "demand" VALUES('R1',2025,'VMT',91.0,'',''); +REPLACE INTO "demand" VALUES('R1',2030,'VMT',98.0,'',''); +REPLACE INTO "demand" VALUES('R2',2020,'RH',70.0,'',''); +REPLACE INTO "demand" VALUES('R2',2025,'RH',77.0,'',''); +REPLACE INTO "demand" VALUES('R2',2030,'RH',84.0,'',''); +REPLACE INTO "demand" VALUES('R2',2020,'VMT',36.0,'',''); +REPLACE INTO "demand" VALUES('R2',2025,'VMT',39.0,'',''); +REPLACE INTO "demand" VALUES('R2',2030,'VMT',42.0,'',''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2020,'spring','day','RH',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2020,'spring','night','RH',0.1,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2020,'summer','day','RH',0.0,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2020,'summer','night','RH',0.0,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2020,'fall','day','RH',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2020,'fall','night','RH',0.1,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2020,'winter','day','RH',0.3,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2020,'winter','night','RH',0.4,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2020,'spring','day','RH',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2020,'spring','night','RH',0.1,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2020,'summer','day','RH',0.0,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2020,'summer','night','RH',0.0,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2020,'fall','day','RH',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2020,'fall','night','RH',0.1,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2020,'winter','day','RH',0.3,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2020,'winter','night','RH',0.4,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2025,'spring','day','RH',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2025,'spring','night','RH',0.1,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2025,'summer','day','RH',0.0,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2025,'summer','night','RH',0.0,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2025,'fall','day','RH',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2025,'fall','night','RH',0.1,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2025,'winter','day','RH',0.3,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2025,'winter','night','RH',0.4,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2025,'spring','day','RH',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2025,'spring','night','RH',0.1,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2025,'summer','day','RH',0.0,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2025,'summer','night','RH',0.0,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2025,'fall','day','RH',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2025,'fall','night','RH',0.1,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2025,'winter','day','RH',0.3,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2025,'winter','night','RH',0.4,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2030,'spring','day','RH',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2030,'spring','night','RH',0.1,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2030,'summer','day','RH',0.0,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2030,'summer','night','RH',0.0,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2030,'fall','day','RH',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2030,'fall','night','RH',0.1,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2030,'winter','day','RH',0.3,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1',2030,'winter','night','RH',0.4,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2030,'spring','day','RH',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2030,'spring','night','RH',0.1,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2030,'summer','day','RH',0.0,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2030,'summer','night','RH',0.0,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2030,'fall','day','RH',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2030,'fall','night','RH',0.1,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2030,'winter','day','RH',0.3,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2',2030,'winter','night','RH',0.4,''); +REPLACE INTO "efficiency" VALUES('R1', 'ethos', 'S_IMPETH', 2020, 'ETH', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'ethos', 'S_IMPOIL', 2020, 'OIL', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'ethos', 'S_IMPNG', 2020, 'NG', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'ethos', 'S_IMPURN', 2020, 'URN', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'OIL', 'S_OILREF', 2020, 'GSL', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'OIL', 'S_OILREF', 2020, 'DSL', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'ETH', 'T_BLND', 2020, 'E10', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'GSL', 'T_BLND', 2020, 'E10', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'NG', 'E_NGCC', 2020, 'ELC', 0.55, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'NG', 'E_NGCC', 2025, 'ELC', 0.55, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'NG', 'E_NGCC', 2030, 'ELC', 0.55, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'SOL', 'E_SOLPV', 2020, 'ELC', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'SOL', 'E_SOLPV', 2025, 'ELC', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'SOL', 'E_SOLPV', 2030, 'ELC', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'URN', 'E_NUCLEAR', 2015, 'ELC', 0.4, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'URN', 'E_NUCLEAR', 2020, 'ELC', 0.4, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'URN', 'E_NUCLEAR', 2025, 'ELC', 0.4, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'URN', 'E_NUCLEAR', 2030, 'ELC', 0.4, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'ELC', 'E_BATT', 2020, 'ELC', 0.85, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'ELC', 'E_BATT', 2025, 'ELC', 0.85, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'ELC', 'E_BATT', 2030, 'ELC', 0.85, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'E10', 'T_GSL', 2020, 'VMT', 0.25, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'E10', 'T_GSL', 2025, 'VMT', 0.25, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'E10', 'T_GSL', 2030, 'VMT', 0.25, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'DSL', 'T_DSL', 2020, 'VMT', 0.3, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'DSL', 'T_DSL', 2025, 'VMT', 0.3, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'DSL', 'T_DSL', 2030, 'VMT', 0.3, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'ELC', 'T_EV', 2020, 'VMT', 0.89, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'ELC', 'T_EV', 2025, 'VMT', 0.89, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'ELC', 'T_EV', 2030, 'VMT', 0.89, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'ELC', 'R_EH', 2020, 'RH', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'ELC', 'R_EH', 2025, 'RH', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'ELC', 'R_EH', 2030, 'RH', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'NG', 'R_NGH', 2020, 'RH', 0.85, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'NG', 'R_NGH', 2025, 'RH', 0.85, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1', 'NG', 'R_NGH', 2030, 'RH', 0.85, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'ethos', 'S_IMPETH', 2020, 'ETH', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'ethos', 'S_IMPOIL', 2020, 'OIL', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'ethos', 'S_IMPNG', 2020, 'NG', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'ethos', 'S_IMPURN', 2020, 'URN', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'OIL', 'S_OILREF', 2020, 'GSL', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'OIL', 'S_OILREF', 2020, 'DSL', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'ETH', 'T_BLND', 2020, 'E10', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'GSL', 'T_BLND', 2020, 'E10', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'NG', 'E_NGCC', 2020, 'ELC', 0.55, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'NG', 'E_NGCC', 2025, 'ELC', 0.55, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'NG', 'E_NGCC', 2030, 'ELC', 0.55, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'SOL', 'E_SOLPV', 2020, 'ELC', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'SOL', 'E_SOLPV', 2025, 'ELC', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'SOL', 'E_SOLPV', 2030, 'ELC', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'URN', 'E_NUCLEAR', 2015, 'ELC', 0.4, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'URN', 'E_NUCLEAR', 2020, 'ELC', 0.4, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'URN', 'E_NUCLEAR', 2025, 'ELC', 0.4, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'URN', 'E_NUCLEAR', 2030, 'ELC', 0.4, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'ELC', 'E_BATT', 2020, 'ELC', 0.85, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'ELC', 'E_BATT', 2025, 'ELC', 0.85, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'ELC', 'E_BATT', 2030, 'ELC', 0.85, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'E10', 'T_GSL', 2020, 'VMT', 0.25, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'E10', 'T_GSL', 2025, 'VMT', 0.25, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'E10', 'T_GSL', 2030, 'VMT', 0.25, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'DSL', 'T_DSL', 2020, 'VMT', 0.3, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'DSL', 'T_DSL', 2025, 'VMT', 0.3, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'DSL', 'T_DSL', 2030, 'VMT', 0.3, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'ELC', 'T_EV', 2020, 'VMT', 0.89, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'ELC', 'T_EV', 2025, 'VMT', 0.89, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'ELC', 'T_EV', 2030, 'VMT', 0.89, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'ELC', 'R_EH', 2020, 'RH', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'ELC', 'R_EH', 2025, 'RH', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'ELC', 'R_EH', 2030, 'RH', 1.0, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'NG', 'R_NGH', 2020, 'RH', 0.85, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'NG', 'R_NGH', 2025, 'RH', 0.85, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2', 'NG', 'R_NGH', 2030, 'RH', 0.85, NULL, ''); +REPLACE INTO "efficiency" VALUES('R1-R2', 'ELC', 'E_TRANS', 2015, 'ELC', 0.9, NULL, ''); +REPLACE INTO "efficiency" VALUES('R2-R1', 'ELC', 'E_TRANS', 2015, 'ELC', 0.9, NULL, ''); +REPLACE INTO "emission_activity" VALUES('R1','CO2','ethos','S_IMPNG',2020,'NG',5.029999999999999e+01,'kT/PJ','taken from MIT Energy Fact Sheet'); +REPLACE INTO "emission_activity" VALUES('R1','CO2','OIL','S_OILREF',2020,'GSL',67.2,'kT/PJ','taken from MIT Energy Fact Sheet'); +REPLACE INTO "emission_activity" VALUES('R1','CO2','OIL','S_OILREF',2020,'DSL',69.4,'kT/PJ','taken from MIT Energy Fact Sheet'); +REPLACE INTO "emission_activity" VALUES('R2','CO2','ethos','S_IMPNG',2020,'NG',5.029999999999999e+01,'kT/PJ','taken from MIT Energy Fact Sheet'); +REPLACE INTO "emission_activity" VALUES('R2','CO2','OIL','S_OILREF',2020,'GSL',67.2,'kT/PJ','taken from MIT Energy Fact Sheet'); +REPLACE INTO "emission_activity" VALUES('R2','CO2','OIL','S_OILREF',2020,'DSL',69.4,'kT/PJ','taken from MIT Energy Fact Sheet'); +REPLACE INTO "existing_capacity" VALUES('R1','E_NUCLEAR',2015,0.07,'GW',''); +REPLACE INTO "existing_capacity" VALUES('R2','E_NUCLEAR',2015,0.03,'GW',''); +REPLACE INTO "existing_capacity" VALUES('R1-R2','E_TRANS',2015,10.0,'GW',''); +REPLACE INTO "existing_capacity" VALUES('R2-R1','E_TRANS',2015,10.0,'GW',''); +REPLACE INTO "lifetime_tech" VALUES('R1', 'S_IMPETH', 100.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R1', 'S_IMPOIL', 100.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R1', 'S_IMPNG', 100.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R1', 'S_IMPURN', 100.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R1', 'S_OILREF', 100.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R1', 'E_NGCC', 30.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R1', 'E_SOLPV', 30.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R1', 'E_BATT', 20.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R1', 'E_NUCLEAR', 50.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R1', 'T_BLND', 100.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R1', 'T_DSL', 12.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R1', 'T_GSL', 12.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R1', 'T_EV', 12.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R1', 'R_EH', 20.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R1', 'R_NGH', 20.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R2', 'S_IMPETH', 100.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R2', 'S_IMPOIL', 100.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R2', 'S_IMPNG', 100.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R2', 'S_IMPURN', 100.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R2', 'S_OILREF', 100.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R2', 'E_NGCC', 30.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R2', 'E_SOLPV', 30.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R2', 'E_BATT', 20.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R2', 'E_NUCLEAR', 50.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R2', 'T_BLND', 100.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R2', 'T_DSL', 12.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R2', 'T_GSL', 12.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R2', 'T_EV', 12.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R2', 'R_EH', 20.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R2', 'R_NGH', 20.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R1-R2', 'E_TRANS', 30.0, NULL, ''); +REPLACE INTO "lifetime_tech" VALUES('R2-R1', 'E_TRANS', 30.0, NULL, ''); +REPLACE INTO "limit_activity" VALUES('R1',2020,'T_GSL','ge',35.0,'',''); +REPLACE INTO "limit_activity" VALUES('R1',2025,'T_GSL','ge',35.0,'',''); +REPLACE INTO "limit_activity" VALUES('R1',2030,'T_GSL','ge',35.0,'',''); +REPLACE INTO "limit_activity" VALUES('R2',2020,'T_GSL','ge',15.0,'',''); +REPLACE INTO "limit_activity" VALUES('R2',2025,'T_GSL','ge',15.0,'',''); +REPLACE INTO "limit_activity" VALUES('R2',2030,'T_GSL','ge',15.0,'',''); +REPLACE INTO "limit_emission" VALUES('R1',2020,'CO2','le',25000.0,'kT CO2',''); +REPLACE INTO "limit_emission" VALUES('R1',2025,'CO2','le',24000.0,'kT CO2',''); +REPLACE INTO "limit_emission" VALUES('R1',2030,'CO2','le',23000.0,'kT CO2',''); +REPLACE INTO "limit_emission" VALUES('global',2020,'CO2','le',37500.0,'kT CO2',''); +REPLACE INTO "limit_emission" VALUES('global',2025,'CO2','le',36000.0,'kT CO2',''); +REPLACE INTO "limit_emission" VALUES('global',2030,'CO2','le',34500.0,'kT CO2',''); +REPLACE INTO "limit_storage_level_fraction" VALUES('R1',2025,'winter','day','E_BATT',2025,'e',0.5,''); +REPLACE INTO "limit_storage_level_fraction" VALUES('R2',2020,'summer','day','E_BATT',2020,'e',0.5,''); +REPLACE INTO "limit_tech_input_split" VALUES('R1',2020,'GSL','T_BLND','ge',0.9,''); +REPLACE INTO "limit_tech_input_split" VALUES('R1',2020,'ETH','T_BLND','ge',0.1,''); +REPLACE INTO "limit_tech_input_split" VALUES('R1',2025,'GSL','T_BLND','ge',0.9,''); +REPLACE INTO "limit_tech_input_split" VALUES('R1',2025,'ETH','T_BLND','ge',0.1,''); +REPLACE INTO "limit_tech_input_split" VALUES('R1',2030,'GSL','T_BLND','ge',0.9,''); +REPLACE INTO "limit_tech_input_split" VALUES('R1',2030,'ETH','T_BLND','ge',0.1,''); +REPLACE INTO "limit_tech_input_split" VALUES('R2',2020,'GSL','T_BLND','ge',0.72,''); +REPLACE INTO "limit_tech_input_split" VALUES('R2',2020,'ETH','T_BLND','ge',0.08,''); +REPLACE INTO "limit_tech_input_split" VALUES('R2',2025,'GSL','T_BLND','ge',0.72,''); +REPLACE INTO "limit_tech_input_split" VALUES('R2',2025,'ETH','T_BLND','ge',0.08,''); +REPLACE INTO "limit_tech_input_split" VALUES('R2',2030,'GSL','T_BLND','ge',0.72,''); +REPLACE INTO "limit_tech_input_split" VALUES('R2',2030,'ETH','T_BLND','ge',0.08,''); +REPLACE INTO "limit_tech_output_split" VALUES('R1',2020,'S_OILREF','GSL','ge',0.9,''); +REPLACE INTO "limit_tech_output_split" VALUES('R1',2020,'S_OILREF','DSL','ge',0.1,''); +REPLACE INTO "limit_tech_output_split" VALUES('R1',2025,'S_OILREF','GSL','ge',0.9,''); +REPLACE INTO "limit_tech_output_split" VALUES('R1',2025,'S_OILREF','DSL','ge',0.1,''); +REPLACE INTO "limit_tech_output_split" VALUES('R1',2030,'S_OILREF','GSL','ge',0.9,''); +REPLACE INTO "limit_tech_output_split" VALUES('R1',2030,'S_OILREF','DSL','ge',0.1,''); +REPLACE INTO "limit_tech_output_split" VALUES('R2',2020,'S_OILREF','GSL','ge',0.72,''); +REPLACE INTO "limit_tech_output_split" VALUES('R2',2020,'S_OILREF','DSL','ge',0.08,''); +REPLACE INTO "limit_tech_output_split" VALUES('R2',2025,'S_OILREF','GSL','ge',0.72,''); +REPLACE INTO "limit_tech_output_split" VALUES('R2',2025,'S_OILREF','DSL','ge',0.08,''); +REPLACE INTO "limit_tech_output_split" VALUES('R2',2030,'S_OILREF','GSL','ge',0.72,''); +REPLACE INTO "limit_tech_output_split" VALUES('R2',2030,'S_OILREF','DSL','ge',0.08,''); +REPLACE INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +REPLACE INTO "metadata" VALUES('DB_MAJOR',4,''); +REPLACE INTO "metadata" VALUES('DB_MINOR',0,''); +REPLACE INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +REPLACE INTO "metadata_real" VALUES('global_discount_rate',0.05,''); +REPLACE INTO "operator" VALUES('e','equal to'); +REPLACE INTO "operator" VALUES('le','less than or equal to'); +REPLACE INTO "operator" VALUES('ge','greater than or equal to'); +REPLACE INTO "region" VALUES('R1',NULL); +REPLACE INTO "region" VALUES('R2',NULL); +REPLACE INTO "season_label" VALUES('summer',NULL); +REPLACE INTO "season_label" VALUES('fall',NULL); +REPLACE INTO "season_label" VALUES('winter',NULL); +REPLACE INTO "season_label" VALUES('spring',NULL); +REPLACE INTO "sector_label" VALUES('supply',NULL); +REPLACE INTO "sector_label" VALUES('electric',NULL); +REPLACE INTO "sector_label" VALUES('transport',NULL); +REPLACE INTO "sector_label" VALUES('commercial',NULL); +REPLACE INTO "sector_label" VALUES('residential',NULL); +REPLACE INTO "sector_label" VALUES('industrial',NULL); +REPLACE INTO "storage_duration" VALUES('R1','E_BATT',8.0,'8-hour duration specified as fraction of a day'); +REPLACE INTO "storage_duration" VALUES('R2','E_BATT',8.0,'8-hour duration specified as fraction of a day'); +REPLACE INTO "technology" VALUES('S_IMPETH','p','supply','','',1,0,0,0,0,0,0,0,' imported ethanol'); +REPLACE INTO "technology" VALUES('S_IMPOIL','p','supply','','',1,0,0,0,0,0,0,0,' imported crude oil'); +REPLACE INTO "technology" VALUES('S_IMPNG','p','supply','','',1,0,0,0,0,0,0,0,' imported natural gas'); +REPLACE INTO "technology" VALUES('S_IMPURN','p','supply','','',1,0,0,0,0,0,0,0,' imported uranium'); +REPLACE INTO "technology" VALUES('S_OILREF','p','supply','','',0,0,0,1,0,0,0,0,' crude oil refinery'); +REPLACE INTO "technology" VALUES('E_NGCC','p','electric','','',0,0,0,0,0,0,0,0,' natural gas combined-cycle'); +REPLACE INTO "technology" VALUES('E_SOLPV','p','electric','','',0,0,0,0,0,0,0,0,' solar photovoltaic'); +REPLACE INTO "technology" VALUES('E_BATT','ps','electric','','',0,0,0,0,0,0,0,0,' lithium-ion battery'); +REPLACE INTO "technology" VALUES('E_NUCLEAR','pb','electric','','',0,0,0,0,0,0,0,0,' nuclear power plant'); +REPLACE INTO "technology" VALUES('T_BLND','p','transport','','',0,0,0,0,0,0,0,0,'ethanol - gasoline blending process'); +REPLACE INTO "technology" VALUES('T_DSL','p','transport','','',0,0,0,0,0,0,0,0,'diesel vehicle'); +REPLACE INTO "technology" VALUES('T_GSL','p','transport','','',0,0,0,0,0,0,0,0,'gasoline vehicle'); +REPLACE INTO "technology" VALUES('T_EV','p','transport','','',0,0,0,0,0,0,0,0,'electric vehicle'); +REPLACE INTO "technology" VALUES('R_EH','p','residential','','',0,0,0,0,0,0,0,0,' electric residential heating'); +REPLACE INTO "technology" VALUES('R_NGH','p','residential','','',0,0,0,0,0,0,0,0,' natural gas residential heating'); +REPLACE INTO "technology" VALUES('E_TRANS','p','electric','','',0,0,0,0,0,0,1,0,'electric transmission'); +REPLACE INTO "technology_type" VALUES('p','production technology'); +REPLACE INTO "technology_type" VALUES('pb','baseload production technology'); +REPLACE INTO "technology_type" VALUES('ps','storage production technology'); +REPLACE INTO "time_of_day" VALUES(1,'day'); +REPLACE INTO "time_of_day" VALUES(2,'night'); +REPLACE INTO "time_period" VALUES(1,2015,'e'); +REPLACE INTO "time_period" VALUES(2,2020,'f'); +REPLACE INTO "time_period" VALUES(3,2025,'f'); +REPLACE INTO "time_period" VALUES(4,2030,'f'); +REPLACE INTO "time_period" VALUES(5,2035,'f'); +REPLACE INTO "time_period_type" VALUES('e','existing vintages'); +REPLACE INTO "time_period_type" VALUES('f','future'); +REPLACE INTO "time_season" VALUES(2020,1,'spring',NULL); +REPLACE INTO "time_season" VALUES(2020,2,'summer',NULL); +REPLACE INTO "time_season" VALUES(2020,3,'fall',NULL); +REPLACE INTO "time_season" VALUES(2020,4,'winter',NULL); +REPLACE INTO "time_season" VALUES(2025,1,'spring',NULL); +REPLACE INTO "time_season" VALUES(2025,2,'summer',NULL); +REPLACE INTO "time_season" VALUES(2025,3,'fall',NULL); +REPLACE INTO "time_season" VALUES(2025,4,'winter',NULL); +REPLACE INTO "time_season" VALUES(2030,1,'spring',NULL); +REPLACE INTO "time_season" VALUES(2030,2,'summer',NULL); +REPLACE INTO "time_season" VALUES(2030,3,'fall',NULL); +REPLACE INTO "time_season" VALUES(2030,4,'winter',NULL); +REPLACE INTO "time_segment_fraction" VALUES(2020,'spring','day',0.125,'Spring - Day'); +REPLACE INTO "time_segment_fraction" VALUES(2020,'spring','night',0.125,'Spring - Night'); +REPLACE INTO "time_segment_fraction" VALUES(2020,'summer','day',0.125,'Summer - Day'); +REPLACE INTO "time_segment_fraction" VALUES(2020,'summer','night',0.125,'Summer - Night'); +REPLACE INTO "time_segment_fraction" VALUES(2020,'fall','day',0.125,'Fall - Day'); +REPLACE INTO "time_segment_fraction" VALUES(2020,'fall','night',0.125,'Fall - Night'); +REPLACE INTO "time_segment_fraction" VALUES(2020,'winter','day',0.125,'Winter - Day'); +REPLACE INTO "time_segment_fraction" VALUES(2020,'winter','night',0.125,'Winter - Night'); +REPLACE INTO "time_segment_fraction" VALUES(2025,'spring','day',0.125,'Spring - Day'); +REPLACE INTO "time_segment_fraction" VALUES(2025,'spring','night',0.125,'Spring - Night'); +REPLACE INTO "time_segment_fraction" VALUES(2025,'summer','day',0.125,'Summer - Day'); +REPLACE INTO "time_segment_fraction" VALUES(2025,'summer','night',0.125,'Summer - Night'); +REPLACE INTO "time_segment_fraction" VALUES(2025,'fall','day',0.125,'Fall - Day'); +REPLACE INTO "time_segment_fraction" VALUES(2025,'fall','night',0.125,'Fall - Night'); +REPLACE INTO "time_segment_fraction" VALUES(2025,'winter','day',0.125,'Winter - Day'); +REPLACE INTO "time_segment_fraction" VALUES(2025,'winter','night',0.125,'Winter - Night'); +REPLACE INTO "time_segment_fraction" VALUES(2030,'spring','day',0.125,'Spring - Day'); +REPLACE INTO "time_segment_fraction" VALUES(2030,'spring','night',0.125,'Spring - Night'); +REPLACE INTO "time_segment_fraction" VALUES(2030,'summer','day',0.125,'Summer - Day'); +REPLACE INTO "time_segment_fraction" VALUES(2030,'summer','night',0.125,'Summer - Night'); +REPLACE INTO "time_segment_fraction" VALUES(2030,'fall','day',0.125,'Fall - Day'); +REPLACE INTO "time_segment_fraction" VALUES(2030,'fall','night',0.125,'Fall - Night'); +REPLACE INTO "time_segment_fraction" VALUES(2030,'winter','day',0.125,'Winter - Day'); +REPLACE INTO "time_segment_fraction" VALUES(2030,'winter','night',0.125,'Winter - Night'); diff --git a/tests/testing_data/utopia_data.sql b/tests/testing_data/utopia_data.sql new file mode 100644 index 000000000..8e99da42a --- /dev/null +++ b/tests/testing_data/utopia_data.sql @@ -0,0 +1,559 @@ +REPLACE INTO "capacity_factor_process" VALUES('utopia',2000,'inter','day','E31',2000,0.2753,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia',2000,'inter','night','E31',2000,0.2753,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia',2000,'winter','day','E31',2000,0.2753,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia',2000,'winter','night','E31',2000,0.2753,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia',2000,'summer','day','E31',2000,0.2753,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia',2000,'summer','night','E31',2000,0.2753,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'inter','day','E31',2000,0.2753,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'inter','night','E31',2000,0.2753,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'winter','day','E31',2000,0.2753,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'winter','night','E31',2000,0.2753,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'summer','day','E31',2000,0.2753,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'summer','night','E31',2000,0.2753,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'inter','day','E31',2010,0.2756,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'inter','night','E31',2010,0.2756,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'winter','day','E31',2010,0.2756,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'winter','night','E31',2010,0.2756,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'summer','day','E31',2010,0.2756,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'summer','night','E31',2010,0.2756,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E70',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E70',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E70',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E70',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E70',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E70',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E70',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E70',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E70',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E70',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E70',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E70',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E70',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E70',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E70',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E70',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E70',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E70',0.8,''); +REPLACE INTO "capacity_to_activity" VALUES('utopia','E01',31.54,'PJ / (GW * year)',''); +REPLACE INTO "capacity_to_activity" VALUES('utopia','E21',31.54,'PJ / (GW * year)',''); +REPLACE INTO "capacity_to_activity" VALUES('utopia','E31',31.54,'PJ / (GW * year)',''); +REPLACE INTO "capacity_to_activity" VALUES('utopia','E51',31.54,'PJ / (GW * year)',''); +REPLACE INTO "capacity_to_activity" VALUES('utopia','E70',31.54,'PJ / (GW * year)',''); +REPLACE INTO "capacity_to_activity" VALUES('utopia','RHE',1.0,'PJ / (GW * year)',''); +REPLACE INTO "capacity_to_activity" VALUES('utopia','RHO',1.0,'PJ / (GW * year)',''); +REPLACE INTO "capacity_to_activity" VALUES('utopia','RL1',1.0,'PJ / (GW * year)',''); +REPLACE INTO "capacity_to_activity" VALUES('utopia','SRE',1.0,'PJ / (GW * year)',''); +REPLACE INTO "capacity_to_activity" VALUES('utopia','TXD',1.0,'PJ / (GW * year)',''); +REPLACE INTO "capacity_to_activity" VALUES('utopia','TXE',1.0,'PJ / (GW * year)',''); +REPLACE INTO "capacity_to_activity" VALUES('utopia','TXG',1.0,'PJ / (GW * year)',''); +REPLACE INTO "commodity" VALUES('ethos','s','# dummy commodity to supply inputs','PJ'); +REPLACE INTO "commodity" VALUES('DSL','p','# diesel','PJ'); +REPLACE INTO "commodity" VALUES('ELC','p','# electricity','PJ'); +REPLACE INTO "commodity" VALUES('FEQ','p','# fossil equivalent','PJ'); +REPLACE INTO "commodity" VALUES('GSL','p','# gasoline','PJ'); +REPLACE INTO "commodity" VALUES('HCO','p','# coal','PJ'); +REPLACE INTO "commodity" VALUES('HYD','p','# water','PJ'); +REPLACE INTO "commodity" VALUES('OIL','p','# crude oil','PJ'); +REPLACE INTO "commodity" VALUES('URN','p','# uranium','PJ'); +REPLACE INTO "commodity" VALUES('co2','e','#CO2 emissions','Mt'); +REPLACE INTO "commodity" VALUES('nox','e','#NOX emissions','Mt'); +REPLACE INTO "commodity" VALUES('RH','d','# residential heating','PJ'); +REPLACE INTO "commodity" VALUES('RL','d','# residential lighting','PJ'); +REPLACE INTO "commodity" VALUES('TX','d','# transportation','PJ'); +REPLACE INTO "commodity_type" VALUES('w','waste commodity'); +REPLACE INTO "commodity_type" VALUES('wa','waste annual commodity'); +REPLACE INTO "commodity_type" VALUES('wp','waste physical commodity'); +REPLACE INTO "commodity_type" VALUES('a','annual commodity'); +REPLACE INTO "commodity_type" VALUES('s','source commodity'); +REPLACE INTO "commodity_type" VALUES('p','physical commodity'); +REPLACE INTO "commodity_type" VALUES('e','emissions commodity'); +REPLACE INTO "commodity_type" VALUES('d','demand commodity'); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'E01',1960,40.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'E01',1970,40.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'E01',1980,40.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'E01',1990,40.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'E01',1970,70.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'E01',1980,70.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'E01',1990,70.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'E01',2000,70.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'E01',1980,100.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'E01',1990,100.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'E01',2000,100.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'E01',2010,100.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'E21',1990,500.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'E21',1990,500.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'E21',1990,500.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'E21',2000,500.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'E21',2000,500.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'E21',2010,500.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'E31',1980,75.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'E31',1990,75.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'E31',1980,75.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'E31',1990,75.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'E31',2000,75.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'E31',1980,75.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'E31',1990,75.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'E31',2000,75.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'E31',2010,75.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'E51',1980,30.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'E51',1990,30.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'E51',1980,30.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'E51',1990,30.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'E51',2000,30.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'E51',1980,30.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'E51',1990,30.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'E51',2000,30.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'E51',2010,30.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'E70',1960,30.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'E70',1970,30.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'E70',1980,30.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'E70',1990,30.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'E70',1970,30.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'E70',1980,30.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'E70',1990,30.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'E70',2000,30.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'E70',1980,30.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'E70',1990,30.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'E70',2000,30.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'E70',2010,30.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'RHO',1970,1.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'RHO',1980,1.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'RHO',1990,1.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'RHO',1980,1.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'RHO',1990,1.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'RHO',2000,1.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'RHO',1990,1.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'RHO',2000,1.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'RHO',2010,1.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'RL1',1980,9.46,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'RL1',1990,9.46,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'RL1',2000,9.46,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'RL1',2010,9.46,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'TXD',1970,52.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'TXD',1980,52.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'TXD',1990,52.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'TXD',1980,52.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'TXD',1990,52.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'TXD',2000,52.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'TXD',2000,52.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'TXD',2010,52.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'TXE',1990,100.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'TXE',1990,90.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'TXE',2000,90.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'TXE',2000,80.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'TXE',2010,80.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'TXG',1970,48.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'TXG',1980,48.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',1990,'TXG',1990,48.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'TXG',1980,48.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'TXG',1990,48.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2000,'TXG',2000,48.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'TXG',2000,48.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_fixed" VALUES('utopia',2010,'TXG',2010,48.0,'Mdollar / (PJ^2 / GW / year)',''); +REPLACE INTO "cost_invest" VALUES('utopia','E01',1990,2000.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','E01',2000,1300.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','E01',2010,1200.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','E21',1990,5000.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','E21',2000,5000.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','E21',2010,5000.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','E31',1990,3000.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','E31',2000,3000.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','E31',2010,3000.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','E51',1990,900.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','E51',2000,900.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','E51',2010,900.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','E70',1990,1000.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','E70',2000,1000.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','E70',2010,1000.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','RHE',1990,90.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','RHE',2000,90.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','RHE',2010,90.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','RHO',1990,100.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','RHO',2000,100.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','RHO',2010,100.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','SRE',1990,100.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','SRE',2000,100.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','SRE',2010,100.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','TXD',1990,1044.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','TXD',2000,1044.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','TXD',2010,1044.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','TXE',1990,2000.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','TXE',2000,1750.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','TXE',2010,1500.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','TXG',1990,1044.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','TXG',2000,1044.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_invest" VALUES('utopia','TXG',2010,1044.0,'Mdollar / (PJ^2 / GW)',''); +REPLACE INTO "cost_variable" VALUES('utopia',1990,'IMPDSL1',1990,10.0,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2000,'IMPDSL1',1990,10.0,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2010,'IMPDSL1',1990,10.0,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',1990,'IMPGSL1',1990,15.0,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2000,'IMPGSL1',1990,15.0,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2010,'IMPGSL1',1990,15.0,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',1990,'IMPHCO1',1990,2.0,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2000,'IMPHCO1',1990,2.0,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2010,'IMPHCO1',1990,2.0,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',1990,'IMPOIL1',1990,8.0,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2000,'IMPOIL1',1990,8.0,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2010,'IMPOIL1',1990,8.0,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',1990,'IMPURN1',1990,2.0,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2000,'IMPURN1',1990,2.0,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2010,'IMPURN1',1990,2.0,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',1990,'E01',1960,0.3,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',1990,'E01',1970,0.3,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',1990,'E01',1980,0.3,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',1990,'E01',1990,0.3,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2000,'E01',1970,0.3,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2000,'E01',1980,0.3,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2000,'E01',1990,0.3,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2000,'E01',2000,0.3,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2010,'E01',1980,0.3,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2010,'E01',1990,0.3,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2010,'E01',2000,0.3,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2010,'E01',2010,0.3,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',1990,'E21',1990,1.5,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2000,'E21',1990,1.5,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2010,'E21',1990,1.5,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2000,'E21',2000,1.5,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2010,'E21',2000,1.5,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2010,'E21',2010,1.5,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',1990,'E70',1960,0.4,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',1990,'E70',1970,0.4,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',1990,'E70',1980,0.4,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',1990,'E70',1990,0.4,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2000,'E70',1970,0.4,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2000,'E70',1980,0.4,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2000,'E70',1990,0.4,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2000,'E70',2000,0.4,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2010,'E70',1980,0.4,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2010,'E70',1990,0.4,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2010,'E70',2000,0.4,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2010,'E70',2010,0.4,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',1990,'SRE',1990,10.0,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2000,'SRE',1990,10.0,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2000,'SRE',2000,10.0,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2010,'SRE',1990,10.0,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2010,'SRE',2000,10.0,'Mdollar / (PJ)',''); +REPLACE INTO "cost_variable" VALUES('utopia',2010,'SRE',2010,10.0,'Mdollar / (PJ)',''); +REPLACE INTO "demand" VALUES('utopia',1990,'RH',25.2,'PJ',''); +REPLACE INTO "demand" VALUES('utopia',2000,'RH',37.8,'PJ',''); +REPLACE INTO "demand" VALUES('utopia',2010,'RH',56.7,'PJ',''); +REPLACE INTO "demand" VALUES('utopia',1990,'RL',5.6,'PJ',''); +REPLACE INTO "demand" VALUES('utopia',2000,'RL',8.4,'PJ',''); +REPLACE INTO "demand" VALUES('utopia',2010,'RL',12.6,'PJ',''); +REPLACE INTO "demand" VALUES('utopia',1990,'TX',5.2,'PJ',''); +REPLACE INTO "demand" VALUES('utopia',2000,'TX',7.8,'PJ',''); +REPLACE INTO "demand" VALUES('utopia',2010,'TX',11.69,'PJ',''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','day','RH',0.12,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','night','RH',0.06,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','day','RH',0.5467,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','night','RH',0.2733,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','day','RL',0.15,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','night','RL',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',1990,'summer','day','RL',0.15,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',1990,'summer','night','RL',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','day','RL',0.5,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','night','RL',0.1,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','day','RH',0.12,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','night','RH',0.06,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','day','RH',0.5467,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','night','RH',0.2733,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','day','RL',0.15,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','night','RL',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',2000,'summer','day','RL',0.15,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',2000,'summer','night','RL',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','day','RL',0.5,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','night','RL',0.1,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','day','RH',0.12,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','night','RH',0.06,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','day','RH',0.5467,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','night','RH',0.2733,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','day','RL',0.15,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','night','RL',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',2010,'summer','day','RL',0.15,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',2010,'summer','night','RL',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','day','RL',0.5,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','night','RL',0.1,''); +REPLACE INTO "efficiency" VALUES('utopia','ethos','IMPDSL1',1990,'DSL',1.0,'PJ / (PJ)',''); +REPLACE INTO "efficiency" VALUES('utopia','ethos','IMPGSL1',1990,'GSL',1.0,'PJ / (PJ)',''); +REPLACE INTO "efficiency" VALUES('utopia','ethos','IMPHCO1',1990,'HCO',1.0,'PJ / (PJ)',''); +REPLACE INTO "efficiency" VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,'PJ / (PJ)',''); +REPLACE INTO "efficiency" VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,'PJ / (PJ)',''); +REPLACE INTO "efficiency" VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,'PJ / (PJ)',''); +REPLACE INTO "efficiency" VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,'PJ / (PJ)',''); +REPLACE INTO "efficiency" VALUES('utopia','HCO','E01',1960,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +REPLACE INTO "efficiency" VALUES('utopia','HCO','E01',1970,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +REPLACE INTO "efficiency" VALUES('utopia','HCO','E01',1980,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +REPLACE INTO "efficiency" VALUES('utopia','HCO','E01',1990,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +REPLACE INTO "efficiency" VALUES('utopia','HCO','E01',2000,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +REPLACE INTO "efficiency" VALUES('utopia','HCO','E01',2010,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +REPLACE INTO "efficiency" VALUES('utopia','FEQ','E21',1990,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +REPLACE INTO "efficiency" VALUES('utopia','FEQ','E21',2000,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +REPLACE INTO "efficiency" VALUES('utopia','FEQ','E21',2010,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +REPLACE INTO "efficiency" VALUES('utopia','URN','E21',1990,'ELC',0.4,'PJ / (PJ)','# 1/2.5'); +REPLACE INTO "efficiency" VALUES('utopia','URN','E21',2000,'ELC',0.4,'PJ / (PJ)','# 1/2.5'); +REPLACE INTO "efficiency" VALUES('utopia','URN','E21',2010,'ELC',0.4,'PJ / (PJ)','# 1/2.5'); +REPLACE INTO "efficiency" VALUES('utopia','HYD','E31',1980,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +REPLACE INTO "efficiency" VALUES('utopia','HYD','E31',1990,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +REPLACE INTO "efficiency" VALUES('utopia','HYD','E31',2000,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +REPLACE INTO "efficiency" VALUES('utopia','HYD','E31',2010,'ELC',0.32,'PJ / (PJ)','# 1/3.125'); +REPLACE INTO "efficiency" VALUES('utopia','DSL','E70',1960,'ELC',0.294,'PJ / (PJ)','# 1/3.4'); +REPLACE INTO "efficiency" VALUES('utopia','DSL','E70',1970,'ELC',0.294,'PJ / (PJ)','# 1/3.4'); +REPLACE INTO "efficiency" VALUES('utopia','DSL','E70',1980,'ELC',0.294,'PJ / (PJ)','# 1/3.4'); +REPLACE INTO "efficiency" VALUES('utopia','DSL','E70',1990,'ELC',0.294,'PJ / (PJ)','# 1/3.4'); +REPLACE INTO "efficiency" VALUES('utopia','DSL','E70',2000,'ELC',0.294,'PJ / (PJ)','# 1/3.4'); +REPLACE INTO "efficiency" VALUES('utopia','DSL','E70',2010,'ELC',0.294,'PJ / (PJ)','# 1/3.4'); +REPLACE INTO "efficiency" VALUES('utopia','ELC','E51',1980,'ELC',0.72,'PJ / (PJ)','# 1/1.3889'); +REPLACE INTO "efficiency" VALUES('utopia','ELC','E51',1990,'ELC',0.72,'PJ / (PJ)','# 1/1.3889'); +REPLACE INTO "efficiency" VALUES('utopia','ELC','E51',2000,'ELC',0.72,'PJ / (PJ)','# 1/1.3889'); +REPLACE INTO "efficiency" VALUES('utopia','ELC','E51',2010,'ELC',0.72,'PJ / (PJ)','# 1/1.3889'); +REPLACE INTO "efficiency" VALUES('utopia','ELC','RHE',1990,'RH',1.0,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','ELC','RHE',2000,'RH',1.0,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','ELC','RHE',2010,'RH',1.0,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','DSL','RHO',1970,'RH',0.7,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','DSL','RHO',1980,'RH',0.7,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','DSL','RHO',1990,'RH',0.7,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','DSL','RHO',2000,'RH',0.7,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','DSL','RHO',2010,'RH',0.7,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','ELC','RL1',1980,'RL',1.0,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','ELC','RL1',1990,'RL',1.0,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','ELC','RL1',2000,'RL',1.0,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','ELC','RL1',2010,'RL',1.0,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','OIL','SRE',1990,'DSL',1.0,'PJ / (PJ)','# direct translation from PRC_INP2, PRC_OUT'); +REPLACE INTO "efficiency" VALUES('utopia','OIL','SRE',2000,'DSL',1.0,'PJ / (PJ)','# direct translation from PRC_INP2, PRC_OUT'); +REPLACE INTO "efficiency" VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'PJ / (PJ)','# direct translation from PRC_INP2, PRC_OUT'); +REPLACE INTO "efficiency" VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'PJ / (PJ)','# direct translation from PRC_INP2, PRC_OUT'); +REPLACE INTO "efficiency" VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'PJ / (PJ)','# direct translation from PRC_INP2, PRC_OUT'); +REPLACE INTO "efficiency" VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'PJ / (PJ)','# direct translation from PRC_INP2, PRC_OUT'); +REPLACE INTO "efficiency" VALUES('utopia','DSL','TXD',1970,'TX',0.231,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','DSL','TXD',1980,'TX',0.231,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','DSL','TXD',1990,'TX',0.231,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','DSL','TXD',2000,'TX',0.231,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','DSL','TXD',2010,'TX',0.231,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','ELC','TXE',1990,'TX',0.827,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','ELC','TXE',2000,'TX',0.827,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','ELC','TXE',2010,'TX',0.827,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','GSL','TXG',1970,'TX',0.231,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','GSL','TXG',1980,'TX',0.231,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','GSL','TXG',1990,'TX',0.231,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','GSL','TXG',2000,'TX',0.231,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "efficiency" VALUES('utopia','GSL','TXG',2010,'TX',0.231,'PJ / (PJ)','# direct translation from DMD_EFF'); +REPLACE INTO "emission_activity" VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.075,'Mt / (PJ)',''); +REPLACE INTO "emission_activity" VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.075,'Mt / (PJ)',''); +REPLACE INTO "emission_activity" VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',8.9e-02,'Mt / (PJ)',''); +REPLACE INTO "emission_activity" VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.075,'Mt / (PJ)',''); +REPLACE INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1970,'TX',1.0,'Mt / (PJ)',''); +REPLACE INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1980,'TX',1.0,'Mt / (PJ)',''); +REPLACE INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1990,'TX',1.0,'Mt / (PJ)',''); +REPLACE INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',2000,'TX',1.0,'Mt / (PJ)',''); +REPLACE INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',2010,'TX',1.0,'Mt / (PJ)',''); +REPLACE INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1970,'TX',1.0,'Mt / (PJ)',''); +REPLACE INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1980,'TX',1.0,'Mt / (PJ)',''); +REPLACE INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1990,'TX',1.0,'Mt / (PJ)',''); +REPLACE INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',2000,'TX',1.0,'Mt / (PJ)',''); +REPLACE INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',2010,'TX',1.0,'Mt / (PJ)',''); +REPLACE INTO "existing_capacity" VALUES('utopia','E01',1960,0.175,'GW',''); +REPLACE INTO "existing_capacity" VALUES('utopia','E01',1970,0.175,'GW',''); +REPLACE INTO "existing_capacity" VALUES('utopia','E01',1980,0.15,'GW',''); +REPLACE INTO "existing_capacity" VALUES('utopia','E31',1980,0.1,'GW',''); +REPLACE INTO "existing_capacity" VALUES('utopia','E51',1980,0.5,'GW',''); +REPLACE INTO "existing_capacity" VALUES('utopia','E70',1960,0.05,'GW',''); +REPLACE INTO "existing_capacity" VALUES('utopia','E70',1970,0.05,'GW',''); +REPLACE INTO "existing_capacity" VALUES('utopia','E70',1980,0.2,'GW',''); +REPLACE INTO "existing_capacity" VALUES('utopia','RHO',1970,12.5,'GW',''); +REPLACE INTO "existing_capacity" VALUES('utopia','RHO',1980,12.5,'GW',''); +REPLACE INTO "existing_capacity" VALUES('utopia','RL1',1980,5.6,'GW',''); +REPLACE INTO "existing_capacity" VALUES('utopia','TXD',1970,0.4,'GW',''); +REPLACE INTO "existing_capacity" VALUES('utopia','TXD',1980,0.2,'GW',''); +REPLACE INTO "existing_capacity" VALUES('utopia','TXG',1970,3.1,'GW',''); +REPLACE INTO "existing_capacity" VALUES('utopia','TXG',1980,1.5,'GW',''); +REPLACE INTO "lifetime_process" VALUES('utopia','RL1',1980,20.0,'year','#forexistingcap'); +REPLACE INTO "lifetime_process" VALUES('utopia','TXD',1970,30.0,'year','#forexistingcap'); +REPLACE INTO "lifetime_process" VALUES('utopia','TXD',1980,30.0,'year','#forexistingcap'); +REPLACE INTO "lifetime_process" VALUES('utopia','TXG',1970,30.0,'year','#forexistingcap'); +REPLACE INTO "lifetime_process" VALUES('utopia','TXG',1980,30.0,'year','#forexistingcap'); +REPLACE INTO "lifetime_tech" VALUES('utopia','E01',40.0,'year',''); +REPLACE INTO "lifetime_tech" VALUES('utopia','E21',40.0,'year',''); +REPLACE INTO "lifetime_tech" VALUES('utopia','E31',100.0,'year',''); +REPLACE INTO "lifetime_tech" VALUES('utopia','E51',100.0,'year',''); +REPLACE INTO "lifetime_tech" VALUES('utopia','E70',40.0,'year',''); +REPLACE INTO "lifetime_tech" VALUES('utopia','RHE',30.0,'year',''); +REPLACE INTO "lifetime_tech" VALUES('utopia','RHO',30.0,'year',''); +REPLACE INTO "lifetime_tech" VALUES('utopia','RL1',10.0,'year',''); +REPLACE INTO "lifetime_tech" VALUES('utopia','SRE',50.0,'year',''); +REPLACE INTO "lifetime_tech" VALUES('utopia','TXD',15.0,'year',''); +REPLACE INTO "lifetime_tech" VALUES('utopia','TXE',15.0,'year',''); +REPLACE INTO "lifetime_tech" VALUES('utopia','TXG',15.0,'year',''); +REPLACE INTO "lifetime_tech" VALUES('utopia','IMPDSL1',1000.0,'year',''); +REPLACE INTO "lifetime_tech" VALUES('utopia','IMPGSL1',1000.0,'year',''); +REPLACE INTO "lifetime_tech" VALUES('utopia','IMPHCO1',1000.0,'year',''); +REPLACE INTO "lifetime_tech" VALUES('utopia','IMPOIL1',1000.0,'year',''); +REPLACE INTO "lifetime_tech" VALUES('utopia','IMPURN1',1000.0,'year',''); +REPLACE INTO "lifetime_tech" VALUES('utopia','IMPHYD',1000.0,'year',''); +REPLACE INTO "lifetime_tech" VALUES('utopia','IMPFEQ',1000.0,'year',''); +REPLACE INTO "limit_capacity" VALUES('utopia',1990,'E31','ge',0.13,'GW',''); +REPLACE INTO "limit_capacity" VALUES('utopia',2000,'E31','ge',0.13,'GW',''); +REPLACE INTO "limit_capacity" VALUES('utopia',2010,'E31','ge',0.13,'GW',''); +REPLACE INTO "limit_capacity" VALUES('utopia',1990,'SRE','ge',0.1,'GW',''); +REPLACE INTO "limit_capacity" VALUES('utopia',1990,'E31','le',0.13,'GW',''); +REPLACE INTO "limit_capacity" VALUES('utopia',2000,'E31','le',0.17,'GW',''); +REPLACE INTO "limit_capacity" VALUES('utopia',2010,'E31','le',2.1e-01,'GW',''); +REPLACE INTO "limit_capacity" VALUES('utopia',1990,'RHE','le',0.0,'GW',''); +REPLACE INTO "limit_capacity" VALUES('utopia',1990,'TXD','le',0.6,'GW',''); +REPLACE INTO "limit_capacity" VALUES('utopia',2000,'TXD','le',1.76,'GW',''); +REPLACE INTO "limit_capacity" VALUES('utopia',2010,'TXD','le',4.76,'GW',''); +REPLACE INTO "limit_tech_output_split" VALUES('utopia',1990,'SRE','DSL','ge',0.7,''); +REPLACE INTO "limit_tech_output_split" VALUES('utopia',2000,'SRE','DSL','ge',0.7,''); +REPLACE INTO "limit_tech_output_split" VALUES('utopia',2010,'SRE','DSL','ge',0.7,''); +REPLACE INTO "limit_tech_output_split" VALUES('utopia',1990,'SRE','GSL','ge',0.3,''); +REPLACE INTO "limit_tech_output_split" VALUES('utopia',2000,'SRE','GSL','ge',0.3,''); +REPLACE INTO "limit_tech_output_split" VALUES('utopia',2010,'SRE','GSL','ge',0.3,''); +REPLACE INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +REPLACE INTO "metadata" VALUES('DB_MAJOR',4,''); +REPLACE INTO "metadata" VALUES('DB_MINOR',0,''); +REPLACE INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); +REPLACE INTO "metadata_real" VALUES('global_discount_rate',0.05,''); +REPLACE INTO "operator" VALUES('e','equal to'); +REPLACE INTO "operator" VALUES('le','less than or equal to'); +REPLACE INTO "operator" VALUES('ge','greater than or equal to'); +REPLACE INTO "region" VALUES('utopia',NULL); +REPLACE INTO "season_label" VALUES('inter',NULL); +REPLACE INTO "season_label" VALUES('summer',NULL); +REPLACE INTO "season_label" VALUES('winter',NULL); +REPLACE INTO "sector_label" VALUES('supply',NULL); +REPLACE INTO "sector_label" VALUES('electric',NULL); +REPLACE INTO "sector_label" VALUES('transport',NULL); +REPLACE INTO "sector_label" VALUES('commercial',NULL); +REPLACE INTO "sector_label" VALUES('residential',NULL); +REPLACE INTO "sector_label" VALUES('industrial',NULL); +REPLACE INTO "technology" VALUES('IMPDSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported diesel'); +REPLACE INTO "technology" VALUES('IMPGSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported gasoline'); +REPLACE INTO "technology" VALUES('IMPHCO1','p','supply','coal','',1,0,0,0,0,0,0,0,' imported coal'); +REPLACE INTO "technology" VALUES('IMPOIL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported crude oil'); +REPLACE INTO "technology" VALUES('IMPURN1','p','supply','nuclear','',1,0,0,0,0,0,0,0,' imported uranium'); +REPLACE INTO "technology" VALUES('IMPFEQ','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported fossil equivalent'); +REPLACE INTO "technology" VALUES('IMPHYD','p','supply','hydro','',1,0,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); +REPLACE INTO "technology" VALUES('E01','pb','electric','coal','',0,0,0,0,0,0,0,0,' coal power plant'); +REPLACE INTO "technology" VALUES('E21','pb','electric','nuclear','',0,0,0,0,0,0,0,0,' nuclear power plant'); +REPLACE INTO "technology" VALUES('E31','pb','electric','hydro','',0,0,0,0,0,0,0,0,' hydro power'); +REPLACE INTO "technology" VALUES('E51','ps','electric','electric','',0,0,0,0,0,0,0,0,' electric storage'); +REPLACE INTO "technology" VALUES('E70','p','electric','petroleum','',0,0,0,0,0,0,0,0,' diesel power plant'); +REPLACE INTO "technology" VALUES('RHE','p','residential','electric','',0,0,0,0,0,0,0,0,' electric residential heating'); +REPLACE INTO "technology" VALUES('RHO','p','residential','petroleum','',0,0,0,0,0,0,0,0,' diesel residential heating'); +REPLACE INTO "technology" VALUES('RL1','p','residential','electric','',0,0,0,0,0,0,0,0,' residential lighting'); +REPLACE INTO "technology" VALUES('SRE','p','supply','petroleum','',0,0,0,0,0,0,0,0,' crude oil processor'); +REPLACE INTO "technology" VALUES('TXD','p','transport','petroleum','',0,0,0,0,0,0,0,0,' diesel powered vehicles'); +REPLACE INTO "technology" VALUES('TXE','p','transport','electric','',0,0,0,0,0,0,0,0,' electric powered vehicles'); +REPLACE INTO "technology" VALUES('TXG','p','transport','petroleum','',0,0,0,0,0,0,0,0,' gasoline powered vehicles'); +REPLACE INTO "technology_type" VALUES('p','production technology'); +REPLACE INTO "technology_type" VALUES('pb','baseload production technology'); +REPLACE INTO "technology_type" VALUES('ps','storage production technology'); +REPLACE INTO "time_of_day" VALUES(1,'day'); +REPLACE INTO "time_of_day" VALUES(2,'night'); +REPLACE INTO "time_period" VALUES(1,1960,'e'); +REPLACE INTO "time_period" VALUES(2,1970,'e'); +REPLACE INTO "time_period" VALUES(3,1980,'e'); +REPLACE INTO "time_period" VALUES(4,1990,'f'); +REPLACE INTO "time_period" VALUES(5,2000,'f'); +REPLACE INTO "time_period" VALUES(6,2010,'f'); +REPLACE INTO "time_period" VALUES(7,2020,'f'); +REPLACE INTO "time_period_type" VALUES('e','existing vintages'); +REPLACE INTO "time_period_type" VALUES('f','future'); +REPLACE INTO "time_season" VALUES(1990,1,'inter',NULL); +REPLACE INTO "time_season" VALUES(1990,2,'summer',NULL); +REPLACE INTO "time_season" VALUES(1990,3,'winter',NULL); +REPLACE INTO "time_season" VALUES(2000,1,'inter',NULL); +REPLACE INTO "time_season" VALUES(2000,2,'summer',NULL); +REPLACE INTO "time_season" VALUES(2000,3,'winter',NULL); +REPLACE INTO "time_season" VALUES(2010,1,'inter',NULL); +REPLACE INTO "time_season" VALUES(2010,2,'summer',NULL); +REPLACE INTO "time_season" VALUES(2010,3,'winter',NULL); +REPLACE INTO "time_segment_fraction" VALUES(1990,'inter','day',0.1667,'# I-D'); +REPLACE INTO "time_segment_fraction" VALUES(1990,'inter','night',0.0833,'# I-N'); +REPLACE INTO "time_segment_fraction" VALUES(1990,'summer','day',0.1667,'# S-D'); +REPLACE INTO "time_segment_fraction" VALUES(1990,'summer','night',0.0833,'# S-N'); +REPLACE INTO "time_segment_fraction" VALUES(1990,'winter','day',0.3333,'# W-D'); +REPLACE INTO "time_segment_fraction" VALUES(1990,'winter','night',0.1667,'# W-N'); +REPLACE INTO "time_segment_fraction" VALUES(2000,'inter','day',0.1667,'# I-D'); +REPLACE INTO "time_segment_fraction" VALUES(2000,'inter','night',0.0833,'# I-N'); +REPLACE INTO "time_segment_fraction" VALUES(2000,'summer','day',0.1667,'# S-D'); +REPLACE INTO "time_segment_fraction" VALUES(2000,'summer','night',0.0833,'# S-N'); +REPLACE INTO "time_segment_fraction" VALUES(2000,'winter','day',0.3333,'# W-D'); +REPLACE INTO "time_segment_fraction" VALUES(2000,'winter','night',0.1667,'# W-N'); +REPLACE INTO "time_segment_fraction" VALUES(2010,'inter','day',0.1667,'# I-D'); +REPLACE INTO "time_segment_fraction" VALUES(2010,'inter','night',0.0833,'# I-N'); +REPLACE INTO "time_segment_fraction" VALUES(2010,'summer','day',0.1667,'# S-D'); +REPLACE INTO "time_segment_fraction" VALUES(2010,'summer','night',0.0833,'# S-N'); +REPLACE INTO "time_segment_fraction" VALUES(2010,'winter','day',0.3333,'# W-D'); +REPLACE INTO "time_segment_fraction" VALUES(2010,'winter','night',0.1667,'# W-N'); From 48d339b724bffc0b5e914e6b167574fb17a76c6b Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Mon, 5 Jan 2026 11:15:47 -0500 Subject: [PATCH 404/587] docs: fixing regressions in pdf documentation building and correcting latex errors --- docs/Makefile | 24 +- docs/README.md | 6 +- docs/source/Documentation.rst | 2 +- docs/source/computational_implementation.rst | 14 +- .../images/graphviz_examples/results1990.pdf | Bin 0 -> 15064 bytes docs/source/images/results1990.pdf | Bin 0 -> 15064 bytes docs/source/images/results1990.svg | 533 ++++++++++++++++++ docs/source/mathematical_formulation.rst | 2 +- docs/source/quick_start.rst | 2 +- docs/source/unit_checking.rst | 92 +-- temoa/components/limits.py | 36 +- temoa/components/operations.py | 4 +- temoa/components/storage.py | 8 +- 13 files changed, 633 insertions(+), 90 deletions(-) create mode 100644 docs/source/images/graphviz_examples/results1990.pdf create mode 100644 docs/source/images/results1990.pdf create mode 100644 docs/source/images/results1990.svg diff --git a/docs/Makefile b/docs/Makefile index 465f6c0ef..9c9aa31ef 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -5,9 +5,7 @@ SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = -BUILDDIR = build -# The below doesn't seem to work properly.... changed to 'build' directory (above) within the docs folder -# BUILDDIR = /tmp/TemoaDocumentationBuild +BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 @@ -108,9 +106,22 @@ latex: latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex \ - LATEXOPTS='-interaction=nonstopmode -file-line-error -halt-on-error' \ - all-pdf + @if command -v latexmk > /dev/null 2>&1; then \ + $(MAKE) -C $(BUILDDIR)/latex \ + LATEXOPTS='-interaction=nonstopmode -file-line-error -halt-on-error' \ + all-pdf; \ + else \ + echo "latexmk not found, falling back to manual pdflatex..."; \ + $(MAKE) -C $(BUILDDIR)/latex \ + PDFLATEX="pdflatex -interaction=nonstopmode -file-line-error -halt-on-error" \ + LATEXMKOPTS="" \ + all-pdf || true; \ + echo "Running pdflatex again for references..."; \ + $(MAKE) -C $(BUILDDIR)/latex \ + PDFLATEX="pdflatex -interaction=nonstopmode -file-line-error -halt-on-error" \ + LATEXMKOPTS="" \ + all-pdf; \ + fi @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: @@ -156,4 +167,3 @@ doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." - diff --git a/docs/README.md b/docs/README.md index c79050ad6..63b9c8c3d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -41,14 +41,14 @@ The generated HTML files will be in `docs/_build/html/`. Open `index.html` in yo ### Generating PDF Documentation -To generate PDF documentation, you'll need LaTeX installed on your system: +To generate PDF documentation, you'll need LaTeX installed. latexmk is recommended for automatic PDF generation: - **macOS**: [MacTeX](https://www.tug.org/mactex/mactex-download.html) -- **Windows/Linux**: [MiKTeX](https://miktex.org/download) +- **Windows/Linux**: [MiKTeX](https://miktex.org/download) or TeX Live Then run: ```bash -uv run sphinx-build -b latexpdf source _build/latex +uv run make latexpdf ``` The PDF will be generated in `docs/_build/latex/`. diff --git a/docs/source/Documentation.rst b/docs/source/Documentation.rst index b83e1bd2f..2955e90f7 100644 --- a/docs/source/Documentation.rst +++ b/docs/source/Documentation.rst @@ -77,7 +77,7 @@ The interactive HTML network graphs provide dynamic exploration with pan, zoom, Graphviz also generates static SVG diagrams showing the energy system structure: -.. figure:: images/graphviz_examples/results1990.svg +.. figure:: images/results1990.* :align: center :figclass: center :width: 100% diff --git a/docs/source/computational_implementation.rst b/docs/source/computational_implementation.rst index 28b370e6f..8bd0185ae 100644 --- a/docs/source/computational_implementation.rst +++ b/docs/source/computational_implementation.rst @@ -378,18 +378,18 @@ The Temoa model code is organized into clear, purpose-driven packages: * ``temoa.data_processing`` - Output analysis and visualization - * ``db_to_excel.py`` - Excel output generation (āš ļø untested in v4.0) - * ``make_graphviz.py`` - Network diagram generation (āš ļø untested in v4.0) + * ``db_to_excel.py`` - Excel output generation ([!] untested in v4.0) + * ``make_graphviz.py`` - Network diagram generation ([!] untested in v4.0) * Result processing utilities * ``temoa.extensions`` - Optional extensions for advanced analysis - * ``modeling_to_generate_alternatives`` - MGA analysis for exploring near-optimal solutions (āš ļø untested in v4.0) - * ``method_of_morris`` - Sensitivity analysis (āš ļø untested in v4.0) - * ``monte_carlo`` - Uncertainty quantification (āš ļø untested in v4.0) + * ``modeling_to_generate_alternatives`` - MGA analysis for exploring near-optimal solutions ([!] untested in v4.0) + * ``method_of_morris`` - Sensitivity analysis ([!] untested in v4.0) + * ``monte_carlo`` - Uncertainty quantification ([!] untested in v4.0) * ``myopic`` - Sequential decision making with limited foresight - * ``single_vector_mga`` - Focused MGA on specific variables (āš ļø untested in v4.0) - * ``stochastics`` - Stochastic programming capabilities (āš ļø untested in v4.0) + * ``single_vector_mga`` - Focused MGA on specific variables ([!] untested in v4.0) + * ``stochastics`` - Stochastic programming capabilities ([!] untested in v4.0) * ``temoa._internal`` - Internal utilities (not part of public API) diff --git a/docs/source/images/graphviz_examples/results1990.pdf b/docs/source/images/graphviz_examples/results1990.pdf new file mode 100644 index 0000000000000000000000000000000000000000..02d6839b886149f732eaaec96c83031404882066 GIT binary patch literal 15064 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 fLjUcv + + + + + +model + +Results for 1990 + + +E21 + +E21 + + + +ELC + + +ELC + + + + + +E21->ELC + + + + + +IMPDSL1 + + +IMPDSL1 +Capacity: 99999.00 + + + + + +DSL + + +DSL + + + + + +IMPDSL1->DSL + + +38.60 + + + +co2 + +co2 + + + +IMPDSL1->co2 + + +2.89 + + + +IMPFEQ + +IMPFEQ + + + +FEQ + +FEQ + + + +IMPFEQ->FEQ + + + + + +IMPGSL1 + + +IMPGSL1 +Capacity: 99999.00 + + + + + +GSL + + +GSL + + + + + +IMPGSL1->GSL + + +19.91 + + + +IMPGSL1->co2 + + +1.49 + + + +IMPHCO1 + + +IMPHCO1 +Capacity: 99999.00 + + + + + +HCO + + +HCO + + + + + +IMPHCO1->HCO + + +14.70 + + + +IMPHCO1->co2 + + +1.31 + + + +IMPHYD + + +IMPHYD +Capacity: 99999.00 + + + + + +HYD + + +HYD + + + + + +IMPHYD->HYD + + +3.52 + + + +IMPOIL1 + +IMPOIL1 + + + +OIL + +OIL + + + +IMPOIL1->OIL + + + + + +IMPURN1 + +IMPURN1 + + + +URN + +URN + + + +IMPURN1->URN + + + + + +RHE + +RHE + + + +RH + + +RH + + + + + +RHE->RH + + + + + +TXE + +TXE + + + +TX + + +TX + + + + + +TXE->TX + + + + + +FEQ->E21 + + + + + +SRE + + +SRE +Capacity: 0.10 + + + + + +OIL->SRE + + + + + +URN->E21 + + + + + +E01 + + +E01 +Capacity: 0.50 + + + + + +E01->ELC + + +4.70 + + + +E31 + + +E31 +Capacity: 0.13 + + + + + +E31->ELC + + +1.13 + + + +E51 + + +E51 +Capacity: 0.50 + + + + + +E51->ELC + + +0.59 + + + +E70 + + +E70 +Capacity: 0.30 + + + + + +E70->ELC + + + + + +RHO + + +RHO +Capacity: 41.33 + + + + + +RHO->RH + + +25.20 + + + +RL1 + + +RL1 +Capacity: 8.40 + + + + + +RL + + +RL + + + + + +RL1->RL + + +5.60 + + + +SRE->DSL + + + + + +SRE->GSL + + + + + +TXD + + +TXD +Capacity: 0.60 + + + + + +TXD->TX + + +0.60 + + + +nox + +nox + + + +TXD->nox + + +0.60 + + + +TXG + + +TXG +Capacity: 4.60 + + + + + +TXG->TX + + +4.60 + + + +TXG->nox + + +4.60 + + + +DSL->E70 + + + + + +DSL->RHO + + +36.00 + + + +DSL->TXD + + +2.60 + + + +ELC->RHE + + + + + +ELC->TXE + + + + + +ELC->E51 + + +0.82 + + + +ELC->RL1 + + +5.60 + + + +GSL->TXG + + +19.91 + + + +HCO->E01 + + +14.70 + + + +HYD->E31 + + +3.52 + + + diff --git a/docs/source/mathematical_formulation.rst b/docs/source/mathematical_formulation.rst index b0ac043e9..76c8bce9e 100644 --- a/docs/source/mathematical_formulation.rst +++ b/docs/source/mathematical_formulation.rst @@ -1064,7 +1064,7 @@ calculated via the formula: LA_{t,v} = \frac{DR_{r,t,v}}{1 - (1 + DR_{r,t,v})^{{}^- LLN_{r,t,v}}} - \forall \{t, v\} \in \Theta_\text{cost_invest} + \forall \{t, v\} \in \Theta_{\text{cost\_invest}} model_process_life diff --git a/docs/source/quick_start.rst b/docs/source/quick_start.rst index 8a9429995..d19f75dc9 100644 --- a/docs/source/quick_start.rst +++ b/docs/source/quick_start.rst @@ -164,7 +164,7 @@ table, it will fail with an error. This foreign key reference ensures that the modeler doesn't accidently type the wrong label in this table. For context, there are two basic types of time periods in Temoa, ``e``, which defines pre-existing periods, and ``f``, which defines future time periods that are to -be optimized. +be optimized. This enforcement of names across tables using foreign keys helps immediately catch typos. As you can imagine, typos happen in plain text files and Excel when diff --git a/docs/source/unit_checking.rst b/docs/source/unit_checking.rst index c158168f2..9818fdce4 100644 --- a/docs/source/unit_checking.rst +++ b/docs/source/unit_checking.rst @@ -100,10 +100,10 @@ Units in **efficiency** and **cost** tables MUST use ratio format: Numerator / (Denominator) - āœ… CORRECT: PJ / (PJ) - āœ… CORRECT: Mdollar / (PJ^2 / GW) - āŒ WRONG: PJ/PJ (no parentheses) - āŒ WRONG: Mdollar * GW / (PJ^2) (denominator incomplete) + [V] CORRECT: PJ / (PJ) + [V] CORRECT: Mdollar / (PJ^2 / GW) + [X] WRONG: PJ/PJ (no parentheses) + [X] WRONG: Mdollar * GW / (PJ^2) (denominator incomplete) The denominator **MUST be fully enclosed in parentheses**. The regex only captures content within ``( )`` after the ``/``. @@ -112,10 +112,10 @@ Other tables should use plain entries: .. code-block:: text - āœ… PJ - āœ… petajoules - āœ… GW - āœ… Mt / (GW) (if ratio needed) + [V] PJ + [V] petajoules + [V] GW + [V] Mt / (GW) (if ratio needed) Custom Units Registry ~~~~~~~~~~~~~~~~~~~~~ @@ -138,7 +138,7 @@ Common Footguns and Pitfalls .. code-block:: text - āŒ cost_invest units: "Mdollar / PJ^2 / GW" + [X] cost_invest units: "Mdollar / PJ^2 / GW" Error: RATIO_ELEMENT regex doesn't match, only "PJ^2" captured @@ -146,7 +146,7 @@ Common Footguns and Pitfalls .. code-block:: text - āœ… cost_invest units: "Mdollar / (PJ^2 / GW)" + [V] cost_invest units: "Mdollar / (PJ^2 / GW)" 2. Capacity vs Energy Units ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -155,7 +155,7 @@ Common Footguns and Pitfalls .. code-block:: text - āŒ existing_capacity units: "GW * year" + [X] existing_capacity units: "GW * year" Error: Energy units (not capacity) in capacity table @@ -163,12 +163,12 @@ Common Footguns and Pitfalls .. code-block:: text - āœ… existing_capacity units: "GW" ([time]^-3 = power) - āŒ existing_capacity units: "GWh" ([time]^-2 = energy) + [V] existing_capacity units: "GW" ([time]^-3 = power) + [X] existing_capacity units: "GWh" ([time]^-2 = energy) **Physics**: -- Capacity = Power (W, kW, MW, GW) → ``[time]^-3`` -- Energy = Power Ɨ Time (Wh, kWh) → ``[time]^-2`` +- Capacity = Power (W, kW, MW, GW) -> ``[time]^-3`` +- Energy = Power Ɨ Time (Wh, kWh) -> ``[time]^-2`` 3. Cost Table Units and C2A ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -179,7 +179,7 @@ For capacity-based costs, the expected denominator is: .. math:: - \text{expected_measure} = \text{output_units} \times \text{C2A} \times \text{year} + \text{expected\_measure} = \text{output\_units} \times \text{C2A} \times \text{year} **Example**: - Output commodity: ``ELC`` = ``PJ`` @@ -188,8 +188,8 @@ For capacity-based costs, the expected denominator is: .. code-block:: text - āœ… cost_invest: "Mdollar / (PJ^2 / GW)" - āœ… cost_fixed: "Mdollar / (PJ^2 / GW / year)" (adds /year for period-based) + [V] cost_invest: "Mdollar / (PJ^2 / GW)" + [V] cost_fixed: "Mdollar / (PJ^2 / GW / year)" (adds /year for period-based) 4. period_based Flag ~~~~~~~~~~~~~~~~~~~~ @@ -241,11 +241,11 @@ Tables affected: ``limit_activity``, ``limit_capacity``, ``limit_new_capacity`` .. code-block:: text - āŒ WRONG: + [X] WRONG: tech E01, output ELC: PJ tech E01, output HEAT: GJ (different units!) - āœ… CORRECT: + [V] CORRECT: tech E01, output ELC: PJ tech E01, output HEAT: PJ (same units) @@ -278,16 +278,16 @@ Common Error Messages .. code-block:: text "Units lack currency dimension" - → Cost table units don't contain currency (dollar/euro) + -> Cost table units don't contain currency (dollar/euro) "Energy units (not capacity) in capacity table" - → Using energy units (kWh, GWh, etc.) instead of capacity units (GW, MW) + -> Using energy units (kWh, GWh, etc.) instead of capacity units (GW, MW) "Non-matching measure unit" - → Units don't match expected format after accounting for C2A/period + -> Units don't match expected format after accounting for C2A/period "failed to process query: no such column: tech" - → Using old SQL queries on v4.0 schema (should auto-fix now) + -> Using old SQL queries on v4.0 schema (should auto-fix now) Reading Unit Check Reports ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -329,28 +329,28 @@ v4.0 Schema Coverage :header: "Table", "Has Units", "Check 2", "Check 3", "Check 4", "Check 5" :widths: 25, 12, 10, 12, 15, 10 - "capacity_to_activity", "āœ“", "āœ“", "", "(used)", "(used)" - "commodity", "āœ“", "āœ“", "āœ“", "", "" - "construction_input", "āœ“", "āœ“", "", "", "" - "cost_emission", "āœ“", "āœ“", "", "", "āœ“" - "cost_fixed", "āœ“", "āœ“", "", "", "āœ“" - "cost_invest", "āœ“", "āœ“", "", "", "āœ“" - "cost_variable", "āœ“", "āœ“", "", "", "āœ“" - "demand", "āœ“", "āœ“", "", "āœ“", "" - "efficiency", "āœ“", "āœ“", "āœ“", "", "" - "emission_activity", "āœ“", "āœ“", "", "", "" - "emission_embodied", "āœ“", "āœ“", "", "", "" - "emission_end_of_life", "āœ“", "āœ“", "", "", "" - "end_of_life_output", "āœ“", "āœ“", "", "", "" - "existing_capacity", "āœ“", "āœ“", "", "āœ“", "" - "lifetime_process", "āœ“", "āœ“", "", "", "" - "lifetime_tech", "āœ“", "āœ“", "", "", "" - "loan_lifetime_process", "āœ“", "āœ“", "", "", "" - "limit_activity", "āœ“", "āœ“", "", "āœ“", "" - "limit_capacity", "āœ“", "āœ“", "", "āœ“", "" - "limit_emission", "āœ“", "āœ“", "", "", "" - "limit_new_capacity", "āœ“", "āœ“", "", "āœ“", "" - "limit_resource", "āœ“", "āœ“", "", "", "" + "capacity_to_activity", "[V]", "[V]", "", "(used)", "(used)" + "commodity", "[V]", "[V]", "[V]", "", "" + "construction_input", "[V]", "[V]", "", "", "" + "cost_emission", "[V]", "[V]", "", "", "[V]" + "cost_fixed", "[V]", "[V]", "", "", "[V]" + "cost_invest", "[V]", "[V]", "", "", "[V]" + "cost_variable", "[V]", "[V]", "", "", "[V]" + "demand", "[V]", "[V]", "", "[V]", "" + "efficiency", "[V]", "[V]", "[V]", "", "" + "emission_activity", "[V]", "[V]", "", "", "" + "emission_embodied", "[V]", "[V]", "", "", "" + "emission_end_of_life", "[V]", "[V]", "", "", "" + "end_of_life_output", "[V]", "[V]", "", "", "" + "existing_capacity", "[V]", "[V]", "", "[V]", "" + "lifetime_process", "[V]", "[V]", "", "", "" + "lifetime_tech", "[V]", "[V]", "", "", "" + "loan_lifetime_process", "[V]", "[V]", "", "", "" + "limit_activity", "[V]", "[V]", "", "[V]", "" + "limit_capacity", "[V]", "[V]", "", "[V]", "" + "limit_emission", "[V]", "[V]", "", "", "" + "limit_new_capacity", "[V]", "[V]", "", "[V]", "" + "limit_resource", "[V]", "[V]", "", "", "" **Check Legend**: - Check 2: Standard validation (format, characters, registry) diff --git a/temoa/components/limits.py b/temoa/components/limits.py index 386705a51..baa4b0428 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -254,7 +254,7 @@ def limit_resource_constraint(model: TemoaModel, r: Region, t: Technology, op: s \le LR_{r, t} - \forall \{r, t\} \in \Theta_{\text{limit_resource}}""" + \forall \{r, t\} \in \Theta_{\text{limit\_resource}}""" # dev note: this constraint is a misnomer. It is actually a "global activity constraint on a # tech" regardless of whatever "resources" are consumed. # dev note: this would generally be applied to a "dummy import" technology to restrict @@ -310,7 +310,7 @@ def limit_activity_share_constraint( \sum_{R_g \subseteq R,\ S,\ D,\ I,\ T^{g_2} \subseteq T,\ V,\ O} \mathbf{FO}_{r,p,s,d,i,t,v,o} - \qquad \forall \{r, p, g_1, g_2\} \in \Theta_{\text{limit_activity_share}} + \qquad \forall \{r, p, g_1, g_2\} \in \Theta_{\text{limit\_activity\_share}} """ regions = geography.gather_group_regions(model, r) @@ -457,12 +457,12 @@ def limit_annual_capacity_factor_constraint( \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMACF_{r, p, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} - \forall \{r, p, t \notin T^{a}, o\} \in \Theta_{\text{limit_annual_capacity_factor}} + \forall \{r, p, t \notin T^{a}, o\} \in \Theta_{\text{limit\_annual\_capacity\_factor}} \\\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \ge LIMACF_{r, p, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} - \forall \{r, p, t \in T^{a}, o\} \in \Theta_{\text{limit_annual_capacity_factor}} + \forall \{r, p, t \in T^{a}, o\} \in \Theta_{\text{limit\_annual\_capacity\_factor}} """ # r can be an individual region (r='US'), or a combination of regions separated by plus # (r='Mexico+US+Canada'), or 'global'. @@ -519,13 +519,13 @@ def limit_seasonal_capacity_factor_constraint( \sum_{D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMSCF_{r, p, s, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} - \forall \{r, p, t \notin T^{a}, o\} \in \Theta_{\text{limit_seasonal_capacity_factor}} + \forall \{r, p, t \notin T^{a}, o\} \in \Theta_{\text{limit\_seasonal\_capacity\_factor}} \\\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \cdot \sum_{D} SEG_{s,d} \le LIMSCF_{r, p, s, t} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} - \forall \{r, p, t \in T^{a}, o\} \in \Theta_{\text{limit_seasonal_capacity_factor}} + \forall \{r, p, t \in T^{a}, o\} \in \Theta_{\text{limit\_seasonal\_capacity\_factor}} """ # r can be an individual region (r='US'), or a combination of regions separated by plus # (r='Mexico+US+Canada'), or 'global'. @@ -708,7 +708,7 @@ def limit_tech_output_split_constraint( \geq TOS_{r, p, t, o} \cdot \sum_{I, O, t \not \in T^{a}} \textbf{FO}_{r, p, s, d, i, t, v, o} - \forall \{r, p, s, d, t, v, o\} \in \Theta_{\text{limit_tech_output_split}}""" + \forall \{r, p, s, d, t, v, o\} \in \Theta_{\text{limit\_tech\_output\_split}}""" out = quicksum( model.v_flow_out[r, p, s, d, S_i, t, v, o] for S_i in model.process_inputs_by_output[r, p, t, v, o] @@ -743,7 +743,7 @@ def limit_tech_output_split_annual_constraint( \sum_{I, O, T^{a}} \textbf{FOA}_{r, p, s, d, i, t \in T^{a}, v, o} \forall \{r, p, t \in T^{a}, v, o\} \in - \Theta_{\text{limit_tech_output_split_annual}}""" + \Theta_{\text{limit\_tech\_output\_split\_annual}}""" out = quicksum( model.v_flow_out_annual[r, p, S_i, t, v, o] for S_i in model.process_inputs_by_output[r, p, t, v, o] @@ -820,7 +820,7 @@ def limit_emission_constraint( ELM_{r, p, e} \\ - & \forall \{r, p, e\} \in \Theta_{\text{limit_emission}} + & \forall \{r, p, e\} \in \Theta_{\text{limit\_emission}} """ emission_limit = value(model.limit_emission[r, p, e, op]) @@ -932,7 +932,7 @@ def limit_growth_capacity( \leq S_{r,t} + (1+R_{r,t}) \cdot \mathbf{CAPAVL}_{r,p_{prev},t} \end{aligned} - \qquad \forall \{r, p, t\} \in \Theta_{\text{limit_growth_capacity}} + \qquad \forall \{r, p, t\} \in \Theta_{\text{limit\_growth\_capacity}} \begin{aligned}\text{Degrowth:}\\ @@ -940,7 +940,7 @@ def limit_growth_capacity( \leq S_{r,t} + (1+R_{r,t}) \cdot \mathbf{CAPAVL}_{r,p,t} \end{aligned} - \qquad \forall \{r, p, t\} \in \Theta_{\text{limit_degrowth_capacity}} + \qquad \forall \{r, p, t\} \in \Theta_{\text{limit\_degrowth\_capacity}} """ regions = geography.gather_group_regions(model, r) @@ -1053,7 +1053,7 @@ def limit_growth_new_capacity( \text{ where } v=p \end{aligned} - \qquad \forall \{r, p, t\} \in \Theta_{\text{limit_growth_capacity}} + \qquad \forall \{r, p, t\} \in \Theta_{\text{limit\_growth\_capacity}} \begin{aligned}\text{Degrowth:}\\ &\mathbf{NCAP}_{r,t,v_{prev}} @@ -1061,7 +1061,7 @@ def limit_growth_new_capacity( \text{ where } v=p \end{aligned} - \qquad \forall \{r, p, t\} \in \Theta_{\text{limit_degrowth_capacity}} + \qquad \forall \{r, p, t\} \in \Theta_{\text{limit\_degrowth\_capacity}} """ regions = geography.gather_group_regions(model, r) @@ -1173,7 +1173,7 @@ def limit_growth_new_capacity_delta( \text{ where } v_i=p - \qquad \forall \{r, p, t\} \in \Theta_{\text{limit_growth_capacityDelta}} + \qquad \forall \{r, p, t\} \in \Theta_{\text{limit\_growth\_capacityDelta}} \begin{aligned}\text{Degrowth:}\\ &\mathbf{NCAP}_{r,t,v_{i-1}} - \mathbf{NCAP}_{r,t,v_{i-2}} @@ -1182,7 +1182,7 @@ def limit_growth_new_capacity_delta( \text{ where } v_i=p - \qquad \forall \{r, p, t\} \in \Theta_{\text{limit_degrowth_capacityDelta}} + \qquad \forall \{r, p, t\} \in \Theta_{\text{limit\_degrowth\_capacityDelta}} """ regions = geography.gather_group_regions(model, r) @@ -1298,11 +1298,11 @@ def limit_activity_constraint( \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} - \forall \{r, p, t \notin T^{a}\} \in \Theta_{\text{limit_activity}} + \forall \{r, p, t \notin T^{a}\} \in \Theta_{\text{limit\_activity}} +\sum_{I,V,O} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} - \forall \{r, p, t \in T^{a}\} \in \Theta_{\text{limit_activity}} + \forall \{r, p, t \in T^{a}\} \in \Theta_{\text{limit\_activity}} \le LA_{r, p, t} """ @@ -1378,7 +1378,7 @@ def limit_capacity_constraint( \textbf{CAPAVL}_{r, p, t} \le LC_{r, p, t} - \forall \{r, p, t\} \in \Theta_{\text{limit_capacity}}""" + \forall \{r, p, t\} \in \Theta_{\text{limit\_capacity}}""" regions = geography.gather_group_regions(model, r) techs = technology.gather_group_techs(model, t) cap_lim = value(model.limit_capacity[r, p, t, op]) diff --git a/temoa/components/operations.py b/temoa/components/operations.py index a202aea36..ee11f26c8 100644 --- a/temoa/components/operations.py +++ b/temoa/components/operations.py @@ -281,7 +281,7 @@ def ramp_up_day_constraint( \leq R_{r,t} \cdot \Delta H_{r,p,s,d,s_{next},d_{next}} \cdot CAP_{r,p,t,v} \cdot C2A_{r,t} \\ - \forall \{r, p, s, d, t, v\} \in \Theta_{\text{ramp_up_day}} + \forall \{r, p, s, d, t, v\} \in \Theta_{\text{ramp\_up\_day}} \\ \text{where: } \Delta H_{r,p,s,d,s_{next},d_{next}} = \frac{24}{2} \left ( \frac{SEG_{r,p,s,d}}{\sum_{D} SEG_{r,p,s,d'}} + @@ -384,7 +384,7 @@ def ramp_down_day_constraint( \leq R_{r,t} \cdot \Delta H_{r,p,s,d,s_{next},d_{next}} \cdot CAP_{r,p,t,v} \cdot C2A_{r,t} \\ - \forall \{r, p, s, d, t, v\} \in \Theta_{\text{ramp_down_day}} + \forall \{r, p, s, d, t, v\} \in \Theta_{\text{ramp\_down\_day}} """ s_next, d_next = model.time_next[p, s, d] diff --git a/temoa/components/storage.py b/temoa/components/storage.py index bad3b2cd5..6171db723 100644 --- a/temoa/components/storage.py +++ b/temoa/components/storage.py @@ -503,13 +503,13 @@ def limit_storage_fraction_constraint( :label: limit_storage_fraction \textbf{SF}_{r,p,s,d,t,v} \le - \ SF_{r,p,s,d,t,v} + SF_{r,p,s,d,t,v} \cdot - \textbf{CAP}_{r,p,t,v} \cdot C2A_{r,t} \cdot \frac {SD_{r,t}}{(24 \cdot DPP hrs/yr} - \cdot \sum_{d} SEG_{s,d} \cdot M.days_per_period days/yr \cdot MPL_{r,p,t,v} + \textbf{CAP}_{r,p,t,v} \cdot \text{C2A}_{r,t} \cdot \frac {SD_{r,t}}{24 \cdot \text{DPP}} + \cdot \sum_{d} \text{SEG}_{s,d} \cdot \text{days\_per\_period} \cdot \text{MPL}_{r,p,t,v} \\ - \forall \{r, p, s, d, t, v\} \in \Theta_{\text{limit_storage_fraction}} + \forall \{r, p, s, d, t, v\} \in \Theta_{\text{limit\_storage\_fraction}} """ energy_limit = ( From ded5d59c5eca5d229e0add6fe52b95eee4f8c699 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 6 Jan 2026 11:14:20 -0500 Subject: [PATCH 405/587] fix monte carlo to work on multiprocessing with highs and add full integration tests --- temoa/_internal/table_writer.py | 8 +-- temoa/extensions/monte_carlo/mc_sequencer.py | 40 +++++++++--- temoa/extensions/monte_carlo/mc_worker.py | 65 +++++++++++++------- tests/conftest.py | 1 + tests/test_full_runs.py | 43 +++++++++++++ tests/testing_configs/config_utopia_mc.toml | 16 +++++ tests/testing_data/mc_settings_utopia.csv | 3 + 7 files changed, 141 insertions(+), 35 deletions(-) create mode 100644 tests/testing_configs/config_utopia_mc.toml create mode 100644 tests/testing_data/mc_settings_utopia.csv diff --git a/temoa/_internal/table_writer.py b/temoa/_internal/table_writer.py index 42fa140a2..c671abcc1 100644 --- a/temoa/_internal/table_writer.py +++ b/temoa/_internal/table_writer.py @@ -743,11 +743,11 @@ def write_tweaks(self, iteration: int, change_records: Iterable[ChangeRecord]) - records.append( { 'scenario': scenario, - 'iteration': iteration, - 'param_name': cr.param_name, + 'run': iteration, + 'param': cr.param_name, 'param_index': str(cr.param_index).replace("'", ''), - 'old_value': cr.old_value, - 'new_value': cr.new_value, + 'old_val': cr.old_value, + 'new_val': cr.new_value, } ) diff --git a/temoa/extensions/monte_carlo/mc_sequencer.py b/temoa/extensions/monte_carlo/mc_sequencer.py index 4cb0768cb..b3e61d237 100644 --- a/temoa/extensions/monte_carlo/mc_sequencer.py +++ b/temoa/extensions/monte_carlo/mc_sequencer.py @@ -39,16 +39,34 @@ class MCSequencer: def __init__(self, config: TemoaConfig): self.config = config + # determine the path to the solver options file + custom_path = self.config.monte_carlo_inputs.get('solver_options') + if custom_path: + options_file_path = Path(custom_path) + # if the path is relative, make it relative to the config file location if possible + if not options_file_path.is_absolute() and self.config.config_file: + options_file_path = self.config.config_file.parent / options_file_path + logger.info('Using custom Monte Carlo solver options from: %s', options_file_path) + else: + options_file_path = None + # read in the options try: - with resources.as_file(solver_options_path) as path: - with open(path, 'rb') as f: + if options_file_path: + with open(options_file_path, 'rb') as f: all_options = tomllib.load(f) + else: + with resources.as_file(solver_options_path) as path: + with open(path, 'rb') as f: + all_options = tomllib.load(f) s_options = all_options.get(self.config.solver_name, {}) logger.info('Using solver options: %s', s_options) except FileNotFoundError: - logger.warning('Unable to find solver options toml file. Using default options.') + if options_file_path: + logger.error('Unable to find custom solver options file at: %s', options_file_path) + else: + logger.warning('Unable to find default solver options toml file.') s_options = {} all_options = {} @@ -84,7 +102,7 @@ def start(self): # 1. Load data with sqlite3.connect(self.config.input_database) as con: hybrid_loader = HybridLoader(db_connection=con, config=self.config) - data_store = hybrid_loader.create_data_dict(myopic_index=None) + data_store = hybrid_loader.create_data_dict(myopic_index=None) mc_run = MCRunFactory(config=self.config, data_store=data_store) # 2. Screen the input file @@ -94,15 +112,18 @@ def start(self): run_gen = mc_run.run_generator() # 4. Set up the workers + import multiprocessing + ctx = multiprocessing.get_context('spawn') + num_workers = self.num_workers - work_queue: Queue[tuple[str, DataPortal] | str] = Queue( + work_queue: Queue[tuple[str, DataPortal] | str] = ctx.Queue( num_workers + 1 ) # must be able to hold all shutdowns at once (could be changed later to not lock on # insertion...) - result_queue: Queue[DataBrick | str] = Queue( + result_queue: Queue[DataBrick | str] = ctx.Queue( num_workers + 1 ) # must be able to hold a shutdown signal from all workers at once! - log_queue = Queue() + log_queue = ctx.Queue() # make workers workers = [] kwargs = { @@ -123,8 +144,9 @@ def start(self): solver_log_path=s_path, **kwargs, ) - w.start() - workers.append(w) + p = ctx.Process(target=w.run, daemon=True) + p.start() + workers.append(p) # workers now running and waiting for jobs... # 6. Start the iterative solve process and let the manager run the show diff --git a/temoa/extensions/monte_carlo/mc_worker.py b/temoa/extensions/monte_carlo/mc_worker.py index 67072cd7f..4b19b0617 100644 --- a/temoa/extensions/monte_carlo/mc_worker.py +++ b/temoa/extensions/monte_carlo/mc_worker.py @@ -28,7 +28,7 @@ verbose = False # for T/S or monitoring... -class MCWorker(Process): +class MCWorker: worker_idx = 1 def __init__( @@ -41,7 +41,6 @@ def __init__( solver_log_path: Path | None = None, **kwargs, ): - super().__init__(daemon=True) self.worker_number = MCWorker.worker_idx MCWorker.worker_idx += 1 self.dp_queue: Queue[DataPortal | str] = dp_queue @@ -70,34 +69,19 @@ def run(self): # __init__. We can set them later via self.opt.options self.opt = SolverFactory(self.solver_name) - # update the solver options to pass in a log location while True: - if self.solver_log_path: - # add the solver log path to options, if one is provided - log_location = Path( - self.solver_log_path, - f'solver_log_{str(self.worker_number)}_{self.solve_count}.log', - ) - log_location = str(log_location) - match self.solver_name: - case 'gurobi': - self.solver_options.update({'LogFile': log_location}) - # case 'appsi_highs': - # self.solver_options.update({'log_file': log_location}) - case _: - pass - - self.opt.options = self.solver_options - # wait for a DataPortal object to show up, then get to work tic = datetime.now() data = self.dp_queue.get() toc = datetime.now() + + # log data pull logger.debug( 'Worker %d waited for and pulled a DataPortal from work queue in %0.2f seconds', self.worker_number, (toc - tic).total_seconds(), ) + if data == 'ZEBRA': # shutdown signal if verbose: print(f'worker {self.worker_number} got shutdown signal') @@ -105,13 +89,43 @@ def run(self): self.results_queue.put('COYOTE') break name, dp = data + + # update the solver options + self.opt.options = self.solver_options + if self.solver_name.startswith('appsi_'): + for k, v in self.solver_options.items(): + try: + setattr(self.opt.config, k, v) + except (ValueError, AttributeError): + # Key not defined in ConfigDict, skip it + pass + + # Handle solver log path for appsi + if self.solver_log_path: + log_location = ( + self.solver_log_path + / f'solver_log_{self.worker_number}_{self.solve_count}.log' + ) + try: + setattr(self.opt.config, 'log_file', str(log_location)) + except (ValueError, AttributeError): + pass + abstract_model = TemoaModel() model: TemoaModel = abstract_model.create_instance(data=dp) model.name = name # set the name from the input tic = datetime.now() try: self.solve_count += 1 - res: SolverResults | None = self.opt.solve(model) + if self.solver_name.startswith('appsi_'): + # For appsi, we can set tee on the config + try: + self.opt.config.tee = True + except (ValueError, AttributeError): + pass + res: SolverResults | None = self.opt.solve(model) + else: + res: SolverResults | None = self.opt.solve(model, tee=True) except Exception as e: if verbose: @@ -122,6 +136,11 @@ def run(self): model.name, e, ) + # Try to get more info if it's a known solver error + if hasattr(self.opt, 'results') and self.opt.results: + logger.warning( + 'Solver results status: %s', self.opt.results.solver.termination_condition + ) res = None toc = datetime.now() @@ -141,7 +160,9 @@ def run(self): else: status = res['Solver'].termination_condition logger.info( - 'Worker %d did not solve. Results status: %s', self.worker_number, status + 'Worker %d did not solve. Results status: %s', + self.worker_number, + status, ) except AttributeError: pass diff --git a/tests/conftest.py b/tests/conftest.py index 8b46ad776..002a85237 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -80,6 +80,7 @@ def refresh_databases() -> None: # Utopia uses the unit-compliant data-only script ('utopia_data.sql', 'utopia.sqlite'), ('utopia_data.sql', 'myo_utopia.sqlite'), + ('utopia_data.sql', 'utopia_mc.sqlite'), # Other test databases ('test_system.sql', 'test_system.sqlite'), ('mediumville.sql', 'mediumville.sqlite'), diff --git a/tests/test_full_runs.py b/tests/test_full_runs.py index 4228696e3..a70e711d8 100644 --- a/tests/test_full_runs.py +++ b/tests/test_full_runs.py @@ -33,6 +33,7 @@ ] myopic_files = [{'name': 'myopic utopia', 'filename': 'config_utopia_myopic.toml'}] +mc_files = [{'name': 'utopia mc', 'filename': 'config_utopia_mc.toml'}] @pytest.mark.parametrize( @@ -158,3 +159,45 @@ def test_graphviz_integration(tmp_path: Path) -> None: # Check that the files are not empty for output_file in output_files: assert output_file.stat().st_size > 0, f'{output_file.name} should not be empty' + + +@pytest.mark.parametrize( + 'system_test_run', argvalues=mc_files, indirect=True, ids=[d['name'] for d in mc_files] +) +def test_mc_utopia( + system_test_run: tuple[str, SolverResults | None, TemoaModel | None, TemoaSequencer], +) -> None: + """ + Test Monte Carlo run logic and output database contents + """ + data_name, _, _, sequencer = system_test_run + + # Connect to the output database + con = sqlite3.connect(sequencer.config.output_database) + cur = con.cursor() + + # 1. Check output_mc_delta table + res = cur.execute('SELECT run, param, old_val, new_val FROM main.output_mc_delta').fetchall() + assert len(res) == 2, 'Should have 2 tweaks recorded' + + # Tweak 1: cost_invest, utopia|TXD|2010, a, -44.0 + # The old value for TXD cost_invest in 2010 in Utopia is 1044.0 + # New value should be 1000.0 + assert res[0][0] == 1 + assert res[0][1] == 'cost_invest' + assert res[0][3] == pytest.approx(1000.0) + + # Tweak 2: demand, utopia|2010|RH, r, 0.1 + # Old value for RH demand in 2010 in Utopia is approx 56.7 + # New value should be approx 62.37 + assert res[1][0] == 2 + assert res[1][1] == 'demand' + assert res[1][3] == pytest.approx(56.7 * 1.1, rel=1e-3) + + # 2. Check output_objective table + res = cur.execute('SELECT scenario FROM main.output_objective').fetchall() + scenarios = [r[0] for r in res] + assert 'utopia_mc-1' in scenarios + assert 'utopia_mc-2' in scenarios + + con.close() diff --git a/tests/testing_configs/config_utopia_mc.toml b/tests/testing_configs/config_utopia_mc.toml new file mode 100644 index 000000000..acd9cd0cc --- /dev/null +++ b/tests/testing_configs/config_utopia_mc.toml @@ -0,0 +1,16 @@ +# MC config for testing in test_full_runs.py +scenario = "utopia_mc" +scenario_mode = "monte_carlo" + +input_database = "tests/testing_outputs/utopia_mc.sqlite" +output_database = "tests/testing_outputs/utopia_mc.sqlite" +neos = false + +# solver +solver_name = "appsi_highs" + +time_sequencing = 'seasonal_timeslices' +reserve_margin = 'static' + +[monte_carlo] +run_settings = "tests/testing_data/mc_settings_utopia.csv" diff --git a/tests/testing_data/mc_settings_utopia.csv b/tests/testing_data/mc_settings_utopia.csv new file mode 100644 index 000000000..f4b6b6ebb --- /dev/null +++ b/tests/testing_data/mc_settings_utopia.csv @@ -0,0 +1,3 @@ +run,param,index,mod,value,notes +1,cost_invest,utopia|TXD|2010,a,-44.0,reduce invest cost to 1000 +2,demand,utopia|2010|RH,r,0.1,increase demand by 10% From 9e8014ebe69b21aead3ab777398798a3458006d7 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 6 Jan 2026 11:46:48 -0500 Subject: [PATCH 406/587] docs: documenting monte carlo functionality --- docs/source/computational_implementation.rst | 2 +- docs/source/index.rst | 1 + docs/source/monte_carlo.rst | 124 +++++++++++++++++++ 3 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 docs/source/monte_carlo.rst diff --git a/docs/source/computational_implementation.rst b/docs/source/computational_implementation.rst index 8bd0185ae..8f2b22d37 100644 --- a/docs/source/computational_implementation.rst +++ b/docs/source/computational_implementation.rst @@ -386,7 +386,7 @@ The Temoa model code is organized into clear, purpose-driven packages: * ``modeling_to_generate_alternatives`` - MGA analysis for exploring near-optimal solutions ([!] untested in v4.0) * ``method_of_morris`` - Sensitivity analysis ([!] untested in v4.0) - * ``monte_carlo`` - Uncertainty quantification ([!] untested in v4.0) + * ``monte_carlo`` - :doc:`monte_carlo` (Uncertainty quantification) * ``myopic`` - Sequential decision making with limited foresight * ``single_vector_mga`` - Focused MGA on specific variables ([!] untested in v4.0) * ``stochastics`` - Stochastic programming capabilities ([!] untested in v4.0) diff --git a/docs/source/index.rst b/docs/source/index.rst index aeecc2a53..3099d0940 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -4,4 +4,5 @@ Temoa Project Documentation .. toctree:: Documentation + monte_carlo unit_checking diff --git a/docs/source/monte_carlo.rst b/docs/source/monte_carlo.rst new file mode 100644 index 000000000..1a4bc9d29 --- /dev/null +++ b/docs/source/monte_carlo.rst @@ -0,0 +1,124 @@ +Monte Carlo Uncertainty Quantification +======================================== + +Temoa provides a Monte Carlo simulation framework that allows users to perform +probabilistic analysis by executing multiple model runs with varying input parameters. +This feature is useful for characterizing the distribution of outcomes under +uncertainty or performing sensitivity analysis. + +Overall Framework +----------------- + +The Monte Carlo extension in Temoa is designed to: + +* Execute an arbitrary number of structured runs. +* Provide a clean interface to specify parameter deviations for each run. +* Support multiple deviations (tweaks) per individual run. +* Record all parameter adjustments in the output database for verification. +* Utilize parallel processing to speed up the execution of multiple runs. + +Configuration +------------- + +To enable Monte Carlo mode, set the ``scenario_mode`` to ``"monte_carlo"`` in +your configuration TOML file and provide the path to the run settings file +under a ``[monte_carlo]`` section: + +.. code-block:: toml + + scenario_mode = "monte_carlo" + + [monte_carlo] + run_settings = "path/to/mc_settings.csv" + solver_options = "mc_solver_options.toml" # Optional + +Settings +~~~~~~~~ + +* **run_settings**: Path to the CSV file containing the parameter deviations. +* **solver_options** (Optional): Path to a TOML file containing worker counts and solver-specific options. If not provided, Temoa uses the default options file in ``temoa/extensions/monte_carlo/MC_solver_options.toml``. + +Input File Format +----------------- + +The Monte Carlo settings are defined in a CSV file. The file must contain a header +and follow this structure: + +.. code-block:: none + + run,param,index,mod,value,notes + 1,cost_invest,utopia|TXD|2010,a,-44.0,reduce invest cost to 1000 + 2,demand,utopia|2010|RH,r,0.1,increase demand by 10% + 2,cost_fixed,utopia|TXD|2010|2010,s,15.0,set fixed cost to 15.0 + +Columns +~~~~~~~ + +* **run**: An integer representing the run index. Multiple lines with the same run index will be applied to the same model instance. +* **param**: The name of the Temoa parameter to adjust (e.g., ``cost_invest``, ``demand``). +* **index**: The index of the parameter, using the pipe (``|``) character as a separator. +* **mod**: The adjustment type (see below). +* **value**: The numeric value used for the adjustment. +* **notes**: A free-text field for user notes. + +Adjustment Types +~~~~~~~~~~~~~~~~ + +The ``mod`` column supports three types of adjustments: + +* **a (Absolute Change)**: Adds the ``value`` to the baseline parameter value. + Formula: :math:`new\_value = old\_value + value` +* **r (Relative Change)**: Adjusts the baseline value by a percentage. + Formula: :math:`new\_value = old\_value \times (1 + value)` +* **s (Substitution)**: Replaces the baseline value with the provided ``value``. + Formula: :math:`new\_value = value` + +Advanced Indexing +~~~~~~~~~~~~~~~~~ + +* **Wildcards**: You can use an asterisk (``*``) as a wildcard in any position of the ``index`` to apply the adjustment to all matching elements. + Example: ``utopia|*|2010`` would match all regions for the given tech/commodity in 2010. +* **Multi-tokens**: You can specify multiple identifiers for a single index position by separating them with a forward slash (``/``). This will create a Cartesian product of all specified combinations. + Example: ``utopia/usa|TXD|2010`` would apply the tweak to both ``utopia|TXD|2010`` and ``usa|TXD|2010``. + +Parallel Execution +------------------ + +Monte Carlo runs are executed in parallel to maximize performance. The number of +worker processes and solver-specific options for these workers are controlled +by a configuration file. + +By default, Temoa uses the ``MC_solver_options.toml`` file located in the +``temoa/extensions/monte_carlo/`` directory. However, you can provide your own +file by specifying the ``solver_options`` path in your configuration TOML. + +.. tip:: + The default configuration uses 11 worker processes. If you provide a custom + ``solver_options`` file, you can adjust the ``num_workers`` setting and add + solver-specific parameters (e.g., threads, tolerances) for each solver. + +Outputs +------- + +The results of each Monte Carlo run are stored in the output database specified +in your configuration. + +Model Scenarios +~~~~~~~~~~~~~~~ + +Each run is saved under a unique scenario name in the output tables, following +the format: ``-``. For example, if your base scenario +is ``utopia_mc``, the results for the first run will be labeled ``utopia_mc-1``. + +Tweak Log Table +~~~~~~~~~~~~~~~ + +The specific adjustments made for each run are recorded in the ``output_mc_delta`` +table. This table contains the following columns: + +* **scenario**: The unique scenario name for the run. +* **run**: The run index. +* **param**: The parameter that was adjusted. +* **param_index**: The specific index that was tweaked. +* **old_val**: The original value from the baseline data. +* **new_val**: The new value after the adjustment was applied. From 952072f437a057b64b0bffaf833e218b2da8aaab Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Mon, 1 Dec 2025 10:00:46 -0500 Subject: [PATCH 407/587] switching license to MIT --- .gitignore | 2 +- LICENSE | 21 ++ LICENSE.txt | 280 ------------------ pyproject.toml | 2 +- temoa/core/modes.py | 25 -- temoa/extensions/method_of_morris/__init__.py | 27 -- .../method_of_morris/morris_evaluate.py | 25 -- .../__init__.py | 27 -- .../modeling_to_generate_alternatives/hull.py | 25 -- .../manager_factory.py | 28 -- .../mga_constants.py | 27 -- .../vector_manager.py | 25 -- temoa/extensions/myopic/__init__.py | 27 -- temoa/extensions/myopic/myopic_index.py | 32 +- .../myopic/myopic_progress_mapper.py | 28 -- .../extensions/single_vector_mga/__init__.py | 27 -- .../single_vector_mga/output_summary.py | 25 -- .../single_vector_mga/sv_mga_sequencer.py | 24 -- .../generate_scenario_tree-nonhomogenous.py | 22 +- .../stochastics/generate_scenario_tree.py | 22 +- .../stochastics/temoa_stochastic.py | 20 -- 21 files changed, 27 insertions(+), 714 deletions(-) create mode 100644 LICENSE delete mode 100644 LICENSE.txt diff --git a/.gitignore b/.gitignore index 0df0d6485..010ef5405 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,7 @@ !pyproject.toml !uv.lock !requirements*.txt -!LICENSE.txt +!LICENSE !CHANGELOG.md !CONTRIBUTING.md !.pre-commit-config.yaml diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..9db61c127 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2015-2025 TemoaProject Team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index 6c5b18cf1..000000000 --- a/LICENSE.txt +++ /dev/null @@ -1,280 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS diff --git a/pyproject.toml b/pyproject.toml index fb7053823..c72751e04 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ dynamic = ["version"] description = "Tools for Energy Model Optimization and Analysis" readme = "README.md" requires-python = ">=3.12" -license = { file = "LICENSE.txt" } +license = "MIT" authors = [ { name = "TemoaProject Team", email = "info@temoaproject.org" } ] diff --git a/temoa/core/modes.py b/temoa/core/modes.py index dcd510cf6..870dbcba4 100644 --- a/temoa/core/modes.py +++ b/temoa/core/modes.py @@ -1,30 +1,5 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 11/28/23 - The possible operating modes for a scenario - """ from enum import Enum, unique diff --git a/temoa/extensions/method_of_morris/__init__.py b/temoa/extensions/method_of_morris/__init__.py index 3e289969b..e69de29bb 100644 --- a/temoa/extensions/method_of_morris/__init__.py +++ b/temoa/extensions/method_of_morris/__init__.py @@ -1,27 +0,0 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 6/3/24 - -""" diff --git a/temoa/extensions/method_of_morris/morris_evaluate.py b/temoa/extensions/method_of_morris/morris_evaluate.py index 6a00d3bb3..89a96271e 100644 --- a/temoa/extensions/method_of_morris/morris_evaluate.py +++ b/temoa/extensions/method_of_morris/morris_evaluate.py @@ -1,29 +1,4 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 6/2/24 - This module contains the core "evaluation" function for Method Of Morris. It needs to be isolated (outside of class) to enable parallelization. """ diff --git a/temoa/extensions/modeling_to_generate_alternatives/__init__.py b/temoa/extensions/modeling_to_generate_alternatives/__init__.py index f79bdd36f..e69de29bb 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/__init__.py +++ b/temoa/extensions/modeling_to_generate_alternatives/__init__.py @@ -1,27 +0,0 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 4/9/24 - -""" diff --git a/temoa/extensions/modeling_to_generate_alternatives/hull.py b/temoa/extensions/modeling_to_generate_alternatives/hull.py index 888d7d663..e4ecd5e41 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/hull.py +++ b/temoa/extensions/modeling_to_generate_alternatives/hull.py @@ -1,29 +1,4 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 4/17/24 - A thin wrapper on Scipy's ConvexHull to make it more manageable """ from logging import getLogger diff --git a/temoa/extensions/modeling_to_generate_alternatives/manager_factory.py b/temoa/extensions/modeling_to_generate_alternatives/manager_factory.py index 2fe260bd7..84a69fa64 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/manager_factory.py +++ b/temoa/extensions/modeling_to_generate_alternatives/manager_factory.py @@ -1,31 +1,3 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 4/16/24 - -""" - import sqlite3 from temoa.core.model import TemoaModel diff --git a/temoa/extensions/modeling_to_generate_alternatives/mga_constants.py b/temoa/extensions/modeling_to_generate_alternatives/mga_constants.py index 973f8f07e..f5b2ed1e6 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/mga_constants.py +++ b/temoa/extensions/modeling_to_generate_alternatives/mga_constants.py @@ -1,30 +1,3 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 4/16/24 - -""" import enum from enum import Enum diff --git a/temoa/extensions/modeling_to_generate_alternatives/vector_manager.py b/temoa/extensions/modeling_to_generate_alternatives/vector_manager.py index 2a761e9f4..37da4c4ca 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/vector_manager.py +++ b/temoa/extensions/modeling_to_generate_alternatives/vector_manager.py @@ -1,29 +1,4 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 4/15/24 - An ABC to serve as a framework for future Vector Managers """ diff --git a/temoa/extensions/myopic/__init__.py b/temoa/extensions/myopic/__init__.py index af2433005..e69de29bb 100644 --- a/temoa/extensions/myopic/__init__.py +++ b/temoa/extensions/myopic/__init__.py @@ -1,27 +0,0 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 1/17/24 - -""" diff --git a/temoa/extensions/myopic/myopic_index.py b/temoa/extensions/myopic/myopic_index.py index 580197eb8..c72ca2c26 100644 --- a/temoa/extensions/myopic/myopic_index.py +++ b/temoa/extensions/myopic/myopic_index.py @@ -2,34 +2,6 @@ A simple frozen data structure to hold instance info on myopic runs """ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 1/18/24 - -""" - from dataclasses import dataclass @@ -78,10 +50,10 @@ def __post_init__(self): The model generally expects one extra period after the last period to be optimized for the purpose of setting the last optimization interval length. So, when parsing out the "middle years" in myopic mode -we need to stop gathering demands in the 2nd year when we have a 3 year +we need to stop gathering demands in the 2nd year when we have a 3 year view depth. -If the myopic view depth is 1 period, and therefore, the step can +If the myopic view depth is 1 period, and therefore, the step can only be 1 period, then: FY = LDY (we just need data that FY period) SY = FY + 1 period (we are going to step 1 period) diff --git a/temoa/extensions/myopic/myopic_progress_mapper.py b/temoa/extensions/myopic/myopic_progress_mapper.py index 9cc2b5fe9..0d38e3135 100644 --- a/temoa/extensions/myopic/myopic_progress_mapper.py +++ b/temoa/extensions/myopic/myopic_progress_mapper.py @@ -6,34 +6,6 @@ from temoa.extensions.myopic.myopic_index import MyopicIndex -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 1/22/24 - -""" - class MyopicProgressMapper: def __init__(self, sorted_future_years: list): diff --git a/temoa/extensions/single_vector_mga/__init__.py b/temoa/extensions/single_vector_mga/__init__.py index 5cd29424f..e69de29bb 100644 --- a/temoa/extensions/single_vector_mga/__init__.py +++ b/temoa/extensions/single_vector_mga/__init__.py @@ -1,27 +0,0 @@ -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 6/25/24 - -""" diff --git a/temoa/extensions/single_vector_mga/output_summary.py b/temoa/extensions/single_vector_mga/output_summary.py index e4fc2441a..0c5cf778c 100644 --- a/temoa/extensions/single_vector_mga/output_summary.py +++ b/temoa/extensions/single_vector_mga/output_summary.py @@ -1,29 +1,4 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 6/26/24 - A tabular summation of the results from an SVMGA run """ diff --git a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py index 864186a0c..1ca5ee123 100644 --- a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py +++ b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py @@ -1,28 +1,4 @@ """ -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . - - -Written by: J. F. Hyink -jeff@westernspark.us -https://westernspark.us -Created on: 6/25/24 Single-Vector MGA is a 2-stage solve process to look at an alternative solution with a relaxed cost The "single vector" distinguishes it from "regular" MGA in that this only uses 1 extra solve to look diff --git a/temoa/extensions/stochastics/generate_scenario_tree-nonhomogenous.py b/temoa/extensions/stochastics/generate_scenario_tree-nonhomogenous.py index 6fb568fb9..33302c118 100755 --- a/temoa/extensions/stochastics/generate_scenario_tree-nonhomogenous.py +++ b/temoa/extensions/stochastics/generate_scenario_tree-nonhomogenous.py @@ -1,25 +1,5 @@ -#!/usr/bin/env pyomo_python +#!/usr/bin/env python -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . -""" import os import sys diff --git a/temoa/extensions/stochastics/generate_scenario_tree.py b/temoa/extensions/stochastics/generate_scenario_tree.py index d9a531b38..f2f781d6f 100755 --- a/temoa/extensions/stochastics/generate_scenario_tree.py +++ b/temoa/extensions/stochastics/generate_scenario_tree.py @@ -1,25 +1,5 @@ -#!/usr/bin/env pyomo_python +#!/usr/bin/env python -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . -""" import os import sys diff --git a/temoa/extensions/stochastics/temoa_stochastic.py b/temoa/extensions/stochastics/temoa_stochastic.py index 9cb946135..bf3c06ae9 100644 --- a/temoa/extensions/stochastics/temoa_stochastic.py +++ b/temoa/extensions/stochastics/temoa_stochastic.py @@ -1,25 +1,5 @@ #!/usr/bin/env python -""" -Tools for Energy Model Optimization and Analysis (Temoa): -An open source framework for energy systems optimization modeling - -Copyright (C) 2015, NC State University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 -received this license file. If not, see . -""" import os import sys From 2caa1137a176bd69e3fb8e1e2aacac78af47c33a Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 8 Jan 2026 14:04:19 -0500 Subject: [PATCH 408/587] adding mpi-sppy as core dependency --- pyproject.toml | 1 + requirements-dev.txt | 8 +++++++- requirements.txt | 8 +++++++- uv.lock | 16 ++++++++++++++++ 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c72751e04..e54ec9ef4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,6 +30,7 @@ dependencies = [ "rich>=14.2.0", "tomlkit>=0.12.0", "pint>=0.25.2", + "mpi-sppy>=0.12.1", ] diff --git a/requirements-dev.txt b/requirements-dev.txt index 5ad2eccf7..069d18cde 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -71,6 +71,8 @@ mdit-py-plugins==0.5.0 # via myst-parser mdurl==0.1.2 # via markdown-it-py +mpi-sppy==0.12.1 + # via temoa (pyproject.toml) multiprocess==0.70.18 # via salib myst-parser==4.0.1 @@ -83,6 +85,7 @@ numpy==2.3.1 # contourpy # highspy # matplotlib + # mpi-sppy # pandas # salib # scipy @@ -121,7 +124,9 @@ pygments==2.19.2 # rich # sphinx pyomo==6.9.2 - # via temoa (pyproject.toml) + # via + # temoa (pyproject.toml) + # mpi-sppy pyparsing==3.2.3 # via matplotlib pytest==8.4.1 @@ -149,6 +154,7 @@ salib==1.5.1 scipy==1.16.0 # via # temoa (pyproject.toml) + # mpi-sppy # salib seaborn==0.13.2 # via temoa (pyproject.toml) diff --git a/requirements.txt b/requirements.txt index d016fb62a..ebf917c83 100644 --- a/requirements.txt +++ b/requirements.txt @@ -37,6 +37,8 @@ matplotlib==3.9.2 # seaborn mdurl==0.1.2 # via markdown-it-py +mpi-sppy==0.12.1 + # via temoa (pyproject.toml) multiprocess==0.70.18 # via salib networkx==3.5 @@ -47,6 +49,7 @@ numpy==2.3.1 # contourpy # highspy # matplotlib + # mpi-sppy # pandas # salib # scipy @@ -77,7 +80,9 @@ pygments==2.19.2 # pytest # rich pyomo==6.9.2 - # via temoa (pyproject.toml) + # via + # temoa (pyproject.toml) + # mpi-sppy pyparsing==3.2.3 # via matplotlib pytest==8.4.1 @@ -97,6 +102,7 @@ salib==1.5.1 scipy==1.16.0 # via # temoa (pyproject.toml) + # mpi-sppy # salib seaborn==0.13.2 # via temoa (pyproject.toml) diff --git a/uv.lock b/uv.lock index 1d5f3eee6..948edf7e5 100644 --- a/uv.lock +++ b/uv.lock @@ -571,6 +571,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, ] +[[package]] +name = "mpi-sppy" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "pyomo" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a5/d2/1df67d240fb6f9b07d550fc6d8477a74dd220e17f24fce6ccac9d5316ad2/mpi-sppy-0.12.1.tar.gz", hash = "sha256:c405b88f3ab69c67dd564789cf156c0cfb704a9eb74d0645f29a1058c19bed27", size = 246281, upload-time = "2024-01-11T16:41:08.311Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a6/29/5d104b54a67d088f0df34801dcc891c702da6dcbb0a1764708a0488f800d/mpi_sppy-0.12.1-py3-none-any.whl", hash = "sha256:0fdf71087f4c5cd9ae22f93ff9ec1feb724ae6bc8e12f9a194154b97dddc750e", size = 310166, upload-time = "2024-01-11T16:41:06.816Z" }, +] + [[package]] name = "multiprocess" version = "0.70.18" @@ -1370,6 +1384,7 @@ dependencies = [ { name = "highspy" }, { name = "joblib" }, { name = "matplotlib" }, + { name = "mpi-sppy" }, { name = "networkx" }, { name = "numpy" }, { name = "openpyxl" }, @@ -1425,6 +1440,7 @@ requires-dist = [ { name = "joblib" }, { name = "matplotlib", specifier = "==3.9.2" }, { name = "matplotlib", marker = "extra == 'plotting'", specifier = ">=3.9.2" }, + { name = "mpi-sppy", specifier = ">=0.12.1" }, { name = "myst-parser", marker = "extra == 'docs'", specifier = ">=2.0.0" }, { name = "networkx", specifier = ">=3.3" }, { name = "numpy", specifier = ">=2.1.0" }, From 500fe66e2926eb4e01a03e6c72645bb134ee0583 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 8 Jan 2026 14:07:33 -0500 Subject: [PATCH 409/587] feat: implementing basic stochastics for temoa using mpi-sppy --- .../stochastics/scenario_creator.py | 130 ++++++++++++++++++ .../stochastics/stochastic_config.py | 88 ++++++++++++ .../stochastics/stochastic_sequencer.py | 94 +++++++++++++ 3 files changed, 312 insertions(+) create mode 100644 temoa/extensions/stochastics/scenario_creator.py create mode 100644 temoa/extensions/stochastics/stochastic_config.py create mode 100644 temoa/extensions/stochastics/stochastic_sequencer.py diff --git a/temoa/extensions/stochastics/scenario_creator.py b/temoa/extensions/stochastics/scenario_creator.py new file mode 100644 index 000000000..9055d8c2e --- /dev/null +++ b/temoa/extensions/stochastics/scenario_creator.py @@ -0,0 +1,130 @@ +import logging +import sqlite3 +from typing import TYPE_CHECKING, Any + +import pyomo.environ as pyo +from mpisppy.utils.sputils import attach_root_node + +from temoa._internal.run_actions import build_instance +from temoa.components.costs import period_cost_rule +from temoa.data_io.hybrid_loader import HybridLoader + +if TYPE_CHECKING: + from temoa.core.config import TemoaConfig + from temoa.extensions.stochastics.stochastic_config import StochasticConfig + +logger = logging.getLogger(__name__) + + +def scenario_creator(scenario_name: str, **kwargs: Any) -> pyo.ConcreteModel: + """ + Creator for mpi-sppy scenarios. + + Args: + scenario_name (str): Name of the scenario to create. + **kwargs: Must contain 'temoa_config' and 'stoch_config'. + """ + if 'temoa_config' not in kwargs or 'stoch_config' not in kwargs: + raise ValueError("scenario_creator requires 'temoa_config' and 'stoch_config' in kwargs") + + temoa_config: TemoaConfig = kwargs['temoa_config'] + stoch_config: StochasticConfig = kwargs['stoch_config'] + + # 1. Load base data + try: + with sqlite3.connect(temoa_config.input_database) as con: + hybrid_loader = HybridLoader(db_connection=con, config=temoa_config) + data_dict = hybrid_loader.create_data_dict(myopic_index=None) + + # Build a map of table -> index columns from the manifest + # For each LoadItem, the index columns are all but the last one (which is the value) + table_index_map = {} + for item in hybrid_loader.manifest: + if item.table not in table_index_map and item.columns: + table_index_map[item.table] = item.columns[:-1] + except Exception as e: + logger.exception('Failed to connect to database %s', temoa_config.input_database) + raise RuntimeError(f'Failed to connect to database {temoa_config.input_database}') from e + + # 2. Apply perturbations for this scenario + for p in stoch_config.perturbations: + if p.scenario != scenario_name: + continue + + target_param = data_dict.get(p.table) + if target_param is None: + logger.warning( + 'Table %s not found in data_dict for scenario %s', p.table, scenario_name + ) + continue + + # target_param is {(idx...): value} + # We need to find entries matching p.filter + index_cols = table_index_map.get(p.table) + if index_cols is None: + logger.warning( + 'Table %s not found in manifest; cannot map indices for scenario %s', + p.table, + scenario_name, + ) + continue + + for idx_tuple, current_val in list(target_param.items()): + # Map index tuple to names based on table manifest + index_map = dict(zip(index_cols, idx_tuple, strict=True)) + + # Check if filter matches + match = True + for filter_key, filter_val in p.filter.items(): + if index_map.get(filter_key) != filter_val: + match = False + break + + if match: + if p.action == 'multiply': + target_param[idx_tuple] = current_val * p.value + elif p.action == 'add': + target_param[idx_tuple] = current_val + p.value + elif p.action == 'set': + target_param[idx_tuple] = p.value + + # 3. Build instance + data_portal = HybridLoader.data_portal_from_data(data_dict) + instance = build_instance(data_portal, silent=True) + + # 4. Attach root node (Stage 1) + periods = sorted(instance.time_optimize) + first_period = periods[0] + + prob = stoch_config.scenarios.get(scenario_name) + if prob is None: + logger.warning( + "Scenario '%s' not found in stochastic config probabilities; defaulting to 1.0", + scenario_name, + ) + prob = 1.0 + instance._mpisppy_probability = prob + + # First stage variables: v_new_capacity[*, *, first_period] + first_stage_vars = [] + for r, t, p in instance.v_new_capacity: + if p == first_period: + first_stage_vars.append(instance.v_new_capacity[r, t, p]) + + if not first_stage_vars: + logger.error( + 'No first-stage variables (v_new_capacity for period %s) found for scenario %s. ' + 'Stochastic optimization requires at least one first-stage decision.', + first_period, + scenario_name, + ) + raise ValueError(f'No first-stage variables found for scenario {scenario_name}') + + # First stage cost: PeriodCost[first_period] + # We can use the period_cost_rule directly + first_stage_cost_expr = period_cost_rule(instance, first_period) + + # Attach root node + attach_root_node(instance, first_stage_cost_expr, first_stage_vars) + + return instance diff --git a/temoa/extensions/stochastics/stochastic_config.py b/temoa/extensions/stochastics/stochastic_config.py new file mode 100644 index 000000000..fb69ceeca --- /dev/null +++ b/temoa/extensions/stochastics/stochastic_config.py @@ -0,0 +1,88 @@ +import logging +import tomllib +from dataclasses import dataclass, field +from pathlib import Path +from typing import Any + +logger = logging.getLogger(__name__) + + +@dataclass +class Perturbation: + scenario: str + table: str + filter: dict[str, Any] + action: str # 'multiply', 'add', 'set' + value: float + + def __post_init__(self) -> None: + allowed_actions = {'multiply', 'add', 'set'} + if self.action not in allowed_actions: + raise ValueError( + f"Invalid perturbation action '{self.action}'; must be one of {allowed_actions}" + ) + + +@dataclass +class StochasticConfig: + scenarios: dict[str, float] # scenario_name -> probability + perturbations: list[Perturbation] = field(default_factory=list) + solver_options: dict[str, Any] = field(default_factory=dict) + + + @classmethod + def from_toml(cls, path: Path) -> 'StochasticConfig': + with open(path, 'rb') as f: + data = tomllib.load(f) + + scenarios_raw = data.get('scenarios', {}) + scenarios = {} + for name, val in scenarios_raw.items(): + if isinstance(val, dict): + scenarios[name] = float(val.get('probability', 1.0)) + else: + scenarios[name] = float(val) + + # Validate probability distribution + if scenarios: + total_prob = sum(scenarios.values()) + if not (0.99 <= total_prob <= 1.01): + logger.warning( + 'Stochastic scenario probabilities sum to %s; usually they should sum to ~1.0', + total_prob, + ) + + perturbations_data = data.get('perturbations', []) + perturbations = [] + for i, p in enumerate(perturbations_data): + try: + scenario_name = p['scenario'] + if scenario_name not in scenarios: + raise ValueError( + f'Perturbation at index {i} references nonexistent scenario: ' + f"'{scenario_name}'. Available scenarios: {list(scenarios.keys())}" + ) + + perturbations.append( + Perturbation( + scenario=scenario_name, + table=p['table'], + filter=p['filter'], + action=p.get('action', 'set'), + value=p['value'], + ) + ) + except KeyError as e: + raise ValueError(f'Perturbation at index {i} is missing required field: {e}') from e + + solver_options = data.get('solver_options', {}) + + # Validate at least one scenario exists + if not scenarios: + raise ValueError('Stochastic configuration must define at least one scenario') + + return cls( + scenarios=scenarios, + perturbations=perturbations, + solver_options=solver_options, + ) diff --git a/temoa/extensions/stochastics/stochastic_sequencer.py b/temoa/extensions/stochastics/stochastic_sequencer.py new file mode 100644 index 000000000..1ff7d7727 --- /dev/null +++ b/temoa/extensions/stochastics/stochastic_sequencer.py @@ -0,0 +1,94 @@ +import logging +from typing import Any + +import pyomo.environ as pyo + +from temoa.core.config import TemoaConfig +from temoa.extensions.stochastics.stochastic_config import StochasticConfig + +logger = logging.getLogger(__name__) + + +class StochasticSequencer: + """ + Orchestrates a stochastic run using mpi-sppy. + """ + + def __init__(self, config: TemoaConfig) -> None: + self.config = config + self.objective_value: float | None = None + if not self.config.stochastic_config: + raise ValueError("Stochastic mode requires a 'stochastic_config' in the TOML.") + + sc_path = self.config.stochastic_config + if not sc_path.exists(): + raise ValueError(f'Stochastic config file not found: {sc_path}') + if not sc_path.is_file(): + raise ValueError(f'Stochastic config path is not a file: {sc_path}') + + try: + self.stoch_config = StochasticConfig.from_toml(sc_path) + except Exception as e: + logger.exception('Failed to load stochastic config from %s', sc_path) + raise ValueError(f'Error parsing stochastic config {sc_path}') from e + + def start(self) -> None: + """ + Execute the stochastic run. + """ + try: + from mpisppy.opt.ef import ExtensiveForm + except ImportError as e: + logger.exception('mpi-sppy is not installed. Please install it to use stochastic mode.') + raise RuntimeError('mpi-sppy not found') from e + + from temoa.extensions.stochastics.scenario_creator import scenario_creator + + # Merge solver options from stoch_config + solver_options = self.stoch_config.solver_options.get(self.config.solver_name, {}) + + options = { + 'solver': self.config.solver_name, + } + + if not self.stoch_config.scenarios: + raise ValueError( + 'No scenarios found in stoch_config.scenarios; provide at least one scenario ' + 'before constructing the ExtensiveForm' + ) + + # For now, we only support Extensive Form (EF) + # We need to provide a list of scenario names to mpi-sppy + all_scenario_names = list(self.stoch_config.scenarios.keys()) + + scenario_creator_kwargs = { + 'temoa_config': self.config, + 'stoch_config': self.stoch_config, + } + + logger.info('Starting mpi-sppy Extensive Form (EF) solver...') + + ef = ExtensiveForm( + options, + all_scenario_names, + scenario_creator, + scenario_creator_kwargs=scenario_creator_kwargs, + ) + + results = ef.solve_extensive_form(solver_options=solver_options) + + # Check for optimal termination before accessing objective + if not pyo.check_optimal_termination(results): + termination = 'unknown' + if hasattr(results, 'solver'): + termination = getattr(results.solver, 'termination_condition', 'unknown') + + logger.error('Stochastic solve failed with termination condition: %s', termination) + raise RuntimeError(f'Stochastic solve failed: {termination}') + + obj_val = ef.get_objective_value() + self.objective_value = obj_val + logger.info('Stochastic Expected Value: %s', obj_val) + + # TODO: Integrate with TableWriter to save results to database + # This might require a modified handle_results or a new one for stochastics From a94788b7768210953b8f515f3fb8f6fbb0c6a621 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 8 Jan 2026 14:07:59 -0500 Subject: [PATCH 410/587] interfacing stochastics implementation with configuration and modeling pipeline --- temoa/_internal/temoa_sequencer.py | 6 ++++++ temoa/core/config.py | 17 +++++++++++++++++ temoa/core/modes.py | 1 + 3 files changed, 24 insertions(+) diff --git a/temoa/_internal/temoa_sequencer.py b/temoa/_internal/temoa_sequencer.py index 3eee5b29b..0faf201bd 100644 --- a/temoa/_internal/temoa_sequencer.py +++ b/temoa/_internal/temoa_sequencer.py @@ -33,6 +33,7 @@ from temoa.extensions.monte_carlo.mc_sequencer import MCSequencer from temoa.extensions.myopic.myopic_sequencer import MyopicSequencer from temoa.extensions.single_vector_mga.sv_mga_sequencer import SvMgaSequencer +from temoa.extensions.stochastics.stochastic_sequencer import StochasticSequencer from temoa.model_checking.pricing_check import price_checker if TYPE_CHECKING: @@ -67,6 +68,7 @@ def __init__( # for results catching for perfect_foresight or testing self.pf_results: pyomo.opt.SolverResults | None = None self.pf_solved_instance: TemoaModel | None = None + self.stochastic_sequencer: StochasticSequencer | None = None def _run_preliminary_checks(self) -> None: """Runs pre-flight system checks and (optionally) a non-fatal units check. @@ -189,6 +191,10 @@ def start(self) -> None: case TemoaMode.MONTE_CARLO: self._run_monte_carlo() + case TemoaMode.STOCHASTIC: + self.stochastic_sequencer = StochasticSequencer(config=self.config) + self.stochastic_sequencer.start() + case _: raise NotImplementedError( f"The scenario mode '{self.temoa_mode}' is not yet implemented." diff --git a/temoa/core/config.py b/temoa/core/config.py index 2098b234b..6441fb5c0 100644 --- a/temoa/core/config.py +++ b/temoa/core/config.py @@ -54,6 +54,7 @@ def __init__( myopic: dict[str, object] | None = None, morris: dict[str, object] | None = None, monte_carlo: dict[str, object] | None = None, + stochastic_config: Path | None = None, config_file: Path | None = None, silent: bool = False, stream_output: bool = False, @@ -144,6 +145,7 @@ def __init__( ) self.plot_commodity_network = plot_commodity_network and self.source_trace self.graphviz_output = graphviz_output + self.stochastic_config = stochastic_config # warn if output db != input db if self.input_database.suffix == self.output_database.suffix: # they are both .db/.sqlite @@ -228,6 +230,21 @@ def build_config(config_file: Path, output_path: Path, silent: bool = False) -> else: raise SolverNotAvailableError('No solver name specified in the configuration.') + if 'stochastic' in data: + stoch_data = data.pop('stochastic') + if 'stochastic_config' in stoch_data: + # Resolve relative to config file Path + sc = config_file.parent / stoch_data['stochastic_config'] + data['stochastic_config'] = sc + + # Pop other sections that are not top-level arguments in __init__ + for section in ['execution', 'model', 'pricing', 'monte_carlo_tweaks']: + if section in data: + data.pop(section) + + if 'output_path' in data: + data.pop('output_path') + tc = TemoaConfig(output_path=output_path, config_file=config_file, silent=silent, **data) logger.info('Scenario Name: %s', tc.scenario) logger.info('Data source: %s', tc.input_database) diff --git a/temoa/core/modes.py b/temoa/core/modes.py index 870dbcba4..5d55d4e3a 100644 --- a/temoa/core/modes.py +++ b/temoa/core/modes.py @@ -17,3 +17,4 @@ class TemoaMode(Enum): CHECK = 6 # build and run price check, source trace it SVMGA = 7 # single-vector MGA MONTE_CARLO = 8 # MC optimization + STOCHASTIC = 9 # Stochastic optimization From 7c9f8135811a8b82a3e869fcb823be2f82e2a7fb Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 8 Jan 2026 14:08:20 -0500 Subject: [PATCH 411/587] adding tests for stochastic modelling --- tests/conftest.py | 4 +++- tests/test_full_runs.py | 24 ++++++++++++++++++- .../config_utopia_stochastic.toml | 12 ++++++++++ .../utopia_stochastic_config.toml | 19 +++++++++++++++ 4 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 tests/testing_configs/config_utopia_stochastic.toml create mode 100644 tests/testing_data/utopia_stochastic_config.toml diff --git a/tests/conftest.py b/tests/conftest.py index 002a85237..1d942ed9e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -92,10 +92,12 @@ def refresh_databases() -> None: ('materials.sql', 'materials.sqlite'), ('simple_linked_tech.sql', 'simple_linked_tech.sqlite'), ('storageville.sql', 'storageville.sqlite'), + (None, 'utopia_stochastic.sqlite'), ] for src, db in databases: - _build_test_db(TEST_OUTPUT_PATH / db, [TEST_DATA_PATH / src]) + src_scripts = [TEST_DATA_PATH / src] if src else [] + _build_test_db(TEST_OUTPUT_PATH / db, src_scripts) def create_unit_test_dbs() -> None: diff --git a/tests/test_full_runs.py b/tests/test_full_runs.py index a70e711d8..9cb39cec7 100644 --- a/tests/test_full_runs.py +++ b/tests/test_full_runs.py @@ -5,7 +5,7 @@ import logging import sqlite3 from pathlib import Path -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any import pytest from pyomo.core import Constraint, Var @@ -34,6 +34,7 @@ myopic_files = [{'name': 'myopic utopia', 'filename': 'config_utopia_myopic.toml'}] mc_files = [{'name': 'utopia mc', 'filename': 'config_utopia_mc.toml'}] +stochastic_files = [{'name': 'stochastic utopia', 'filename': 'config_utopia_stochastic.toml'}] @pytest.mark.parametrize( @@ -123,6 +124,27 @@ def test_myopic_utopia( con.close() +@pytest.mark.parametrize( + 'system_test_run', + argvalues=stochastic_files, + indirect=True, + ids=[d['name'] for d in stochastic_files], +) +def test_stochastic_utopia( + system_test_run: tuple[str, Any, Any, TemoaSequencer], +) -> None: + """ + Test the stochastic integration for the utopia model. + """ + _, _, _, sequencer = system_test_run + + # Stochastic Expected Value for current utopia configuration + expected_obj = 34389.9878 + + assert sequencer.stochastic_sequencer is not None + assert sequencer.stochastic_sequencer.objective_value == pytest.approx(expected_obj, rel=1e-5) + + def test_graphviz_integration(tmp_path: Path) -> None: """ Test that graphviz diagrams are generated during a full run when enabled. diff --git a/tests/testing_configs/config_utopia_stochastic.toml b/tests/testing_configs/config_utopia_stochastic.toml new file mode 100644 index 000000000..78fa81a9a --- /dev/null +++ b/tests/testing_configs/config_utopia_stochastic.toml @@ -0,0 +1,12 @@ +# Temoa configuration for utopia stochastic run +scenario = "utopia_stochastic" +scenario_mode = "stochastic" +input_database = "tests/testing_outputs/utopia.sqlite" +output_database = "tests/testing_outputs/utopia_stochastic.sqlite" +output_path = "tests/testing_outputs/utopia_stochastic" +solver_name = "appsi_highs" +time_sequencing = "seasonal_timeslices" +save_duals = false + +[stochastic] +stochastic_config = "../testing_data/utopia_stochastic_config.toml" diff --git a/tests/testing_data/utopia_stochastic_config.toml b/tests/testing_data/utopia_stochastic_config.toml new file mode 100644 index 000000000..a3b05f554 --- /dev/null +++ b/tests/testing_data/utopia_stochastic_config.toml @@ -0,0 +1,19 @@ +[scenarios] +low_coal = { probability = 0.5 } +high_coal = { probability = 0.5 } + +[[perturbations]] +scenario = "low_coal" +table = "cost_variable" +column = "cost" +filter = { tech = "IMPHCO1" } +action = "multiply" +value = 0.5 + +[[perturbations]] +scenario = "high_coal" +table = "cost_variable" +column = "cost" +filter = { tech = "IMPHCO1" } +action = "multiply" +value = 1.5 From 5cca55edbe1f1fb2233a674119a387f83394fbca Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 8 Jan 2026 14:08:53 -0500 Subject: [PATCH 412/587] docs: documenting stochastics implementation --- docs/source/computational_implementation.rst | 2 +- docs/source/index.rst | 1 + docs/source/stochastics.rst | 107 +++++++++++++++++++ 3 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 docs/source/stochastics.rst diff --git a/docs/source/computational_implementation.rst b/docs/source/computational_implementation.rst index 8f2b22d37..80d294a32 100644 --- a/docs/source/computational_implementation.rst +++ b/docs/source/computational_implementation.rst @@ -389,7 +389,7 @@ The Temoa model code is organized into clear, purpose-driven packages: * ``monte_carlo`` - :doc:`monte_carlo` (Uncertainty quantification) * ``myopic`` - Sequential decision making with limited foresight * ``single_vector_mga`` - Focused MGA on specific variables ([!] untested in v4.0) - * ``stochastics`` - Stochastic programming capabilities ([!] untested in v4.0) + * ``stochastics`` - :doc:`stochastics` (Stochastic programming capabilities) * ``temoa._internal`` - Internal utilities (not part of public API) diff --git a/docs/source/index.rst b/docs/source/index.rst index 3099d0940..5e0bde765 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -6,3 +6,4 @@ Temoa Project Documentation Documentation monte_carlo unit_checking + stochastics diff --git a/docs/source/stochastics.rst b/docs/source/stochastics.rst new file mode 100644 index 000000000..6f01ab88e --- /dev/null +++ b/docs/source/stochastics.rst @@ -0,0 +1,107 @@ + +.. _stochastics: + +Stochastic Programming +====================== + +The Stochastics extension in Temoa v4 provides support for stochastic programming using the `mpi-sppy `_ library. This allows for decision-making under uncertainty by considering multiple scenarios simultaneously and finding an optimal "first-stage" decision that minimizes the expected cost over all scenarios. + +Stochastic programming is particularly useful for modeling uncertainties in future costs, demands, or resource availability. + +Dependencies +------------ + +The stochastics extension requires the ``mpi-sppy`` package. You can install it using ``uv``: + +.. code-block:: bash + + uv add mpi-sppy + +Or using ``pip``: + +.. code-block:: bash + + pip install mpi-sppy + +Configuration +------------- + +To run Temoa in stochastic mode, you need to modify your main configuration TOML file and provide an additional stochastic configuration file. + +Main Configuration TOML +~~~~~~~~~~~~~~~~~~~~~~~ + +Set the ``scenario_mode`` to ``"stochastic"`` and add a ``[stochastic]`` section: + +.. code-block:: toml + + scenario_mode = "stochastic" + + # ... other standard options ... + + [stochastic] + # Path to the stochastic configuration file, relative to this file + stochastic_config = "stochastic_config.toml" + +Stochastic Configuration TOML +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The stochastic configuration file defines the scenarios, their probabilities, and the data perturbations associated with each scenario. + +.. code-block:: toml + + # Define the scenarios + [scenarios] + # Each key is a scenario name, and the value is its probability + # Probabilities must sum to 1.0 + low_cost = 0.5 + high_cost = 0.5 + + # Define perturbations for a specific scenario + [[perturbations]] + scenario = "low_cost" + table = "cost_variable" + # Filter specifies which rows in the table to perturb + filter = { tech = "IMPHCO1" } + # Action can be "multiply", "add", or "set" (defaults to "set") + action = "multiply" + value = 0.5 + + [[perturbations]] + scenario = "high_cost" + table = "cost_variable" + filter = { tech = "IMPHCO1" } + action = "multiply" + value = 1.5 + +Perturbation Options +^^^^^^^^^^^^^^^^^^^^ + +Currently, the following fields are required for each perturbation: + +* **scenario**: The name of the scenario to which this perturbation applies. +* **table**: The Temoa parameter (database table) to perturb (e.g., ``cost_variable``, ``demand``, ``capacity_factor_process``). +* **filter**: A dictionary of column-value pairs used to identify specific rows. Since the extension uses the dynamic manifest from ``HybridLoader``, any column belonging to the table's index can be used for filtering. +* **action**: The operation to perform. Supported values: + * ``multiply``: Multiply the base value by ``value``. + * ``add``: Add ``value`` to the base value. + * ``set``: Replace the base value with ``value``. +* **value**: The numeric value used in the perturbation action. + +How it Works +------------ + +When running in stochastic mode, Temoa: + +1. Loads the base data from the input database. +2. Identifies the "first-stage" variables. In the current implementation, all decisions in the first time period are considered first-stage. +3. Orchestrates multiple scenario runs using the ``mpi-sppy`` Extensive Form (EF) solver. +4. For each scenario, the ``scenario_creator`` applies the specified perturbations to the base data and builds a Pyomo model instance. +5. The EF solver binds the first-stage variables across all scenarios (non-anticipativity constraints) and optimizes the total expected cost. +6. The terminal output reports the Stochastic Expected Value. + +Limitations +----------- + +* **Two-Stage Only**: While ``mpi-sppy`` supports multi-stage stochastic programming, the current Temoa integration is tailored for two-stage problems where the first time period constitutes the first stage. +* **Result Persistence**: Currently, only the expected objective value and summary logs are produced. Detailed per-scenario result persistence to the database is under development. From 03f34d369c8254e6cf2e7c76eaa8bc5aedf82c7b Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 8 Jan 2026 14:09:13 -0500 Subject: [PATCH 413/587] removing legacy stochastics code --- temoa/extensions/README.txt | 6 - temoa/extensions/stochastics/EVPI.py | 261 ------ temoa/extensions/stochastics/README.txt | 3 - .../extensions/stochastics/ReferenceModel.py | 1 - temoa/extensions/stochastics/VSS.py | 326 -------- .../generate_scenario_tree-nonhomogenous.py | 613 -------------- .../stochastics/generate_scenario_tree.py | 623 -------------- temoa/extensions/stochastics/jobTemoa.pbs | 61 -- .../legacy_files/ef_writer_script_old.py | 759 ------------------ .../legacy_files/scenariomodels.py | 64 -- .../extensions/stochastics/options/README.txt | 67 -- .../stochastics/options/__init__.py | 0 .../options/iew2012-nonhomogenized-markov.py | 101 --- .../extensions/stochastics/options/iew2012.py | 92 --- .../stochastics/options/utopia_coal_vs_nuc.py | 86 -- .../stochastics/stochastics_README.txt | 73 -- .../stochastics/temoa_stochastic.py | 189 ----- 17 files changed, 3325 deletions(-) delete mode 100644 temoa/extensions/README.txt delete mode 100755 temoa/extensions/stochastics/EVPI.py delete mode 100644 temoa/extensions/stochastics/README.txt delete mode 120000 temoa/extensions/stochastics/ReferenceModel.py delete mode 100755 temoa/extensions/stochastics/VSS.py delete mode 100755 temoa/extensions/stochastics/generate_scenario_tree-nonhomogenous.py delete mode 100755 temoa/extensions/stochastics/generate_scenario_tree.py delete mode 100644 temoa/extensions/stochastics/jobTemoa.pbs delete mode 100644 temoa/extensions/stochastics/legacy_files/ef_writer_script_old.py delete mode 100644 temoa/extensions/stochastics/legacy_files/scenariomodels.py delete mode 100644 temoa/extensions/stochastics/options/README.txt delete mode 100644 temoa/extensions/stochastics/options/__init__.py delete mode 100644 temoa/extensions/stochastics/options/iew2012-nonhomogenized-markov.py delete mode 100644 temoa/extensions/stochastics/options/iew2012.py delete mode 100644 temoa/extensions/stochastics/options/utopia_coal_vs_nuc.py delete mode 100644 temoa/extensions/stochastics/stochastics_README.txt delete mode 100644 temoa/extensions/stochastics/temoa_stochastic.py diff --git a/temoa/extensions/README.txt b/temoa/extensions/README.txt deleted file mode 100644 index 20d60b8f6..000000000 --- a/temoa/extensions/README.txt +++ /dev/null @@ -1,6 +0,0 @@ -Note that most of the "extensions" in this folder are legacy work that are currently not maintained. -Most need to be reworked and made compatible with the version 3 model and database structure. They are retained -for now as valuable work-product for future development. - -Working: -Myopic mode. This should be accessed via normal run and appropriate config file \ No newline at end of file diff --git a/temoa/extensions/stochastics/EVPI.py b/temoa/extensions/stochastics/EVPI.py deleted file mode 100755 index 20dd1b247..000000000 --- a/temoa/extensions/stochastics/EVPI.py +++ /dev/null @@ -1,261 +0,0 @@ -# This version is compatible with Pyomo 5.2 - -import os -import sys - -from pyomo.environ import * -from pyomo.opt import SolverFactory -from pyomo.pysp.ef import create_ef_instance -from pyomo.pysp.scenariotree.manager import ScenarioTreeManagerClientSerial - - -# To see detailed information about options -# for name in options.keys(): -# print(options.about(name)) - -# To see a more compact display of options -# options.display() - -# options.model_location = \ -# os.path.join(farmer_example_dir, 'models') -# options.scenario_tree_location = \ -# os.path.join(farmer_example_dir, 'scenariodata') - - -class DummyTemoaConfig: - pass - - -def compute_evpi(ef_result, pf_result): - pf = 0 - for i in range(0, len(pf_result['cost'])): - pf += pf_result['cd'][i] * pf_result['cost'][i] - return ef_result - pf - - -def solve_pf(p_model, p_data): - """ - solve_pf(p_model, p_data) -> dict() - Solves the model in perfect sight mode. - p_model -> string, the path to the model file. - p_data -> string, the path to the directory of data for the stochastic - model, where ScenarioStructure.dat should resides. - Returns a dictionary including the value of objective function for each - scenario and its conditional probability. - """ - - def return_obj(instance): - from pyomo.core import Objective - - obj = instance.component_objects(Objective, active=True) - obj_values = list() - for o in obj: - # See section 18.6.3 in Pyomo online doc - # https://taizilongxu.gitbooks.io/stackoverflow-about-python/content/59/README.html - method_obj = getattr(instance, str(o)) - obj_values.append(method_obj()) - # Assuming there is only one objective function - return obj_values[0] - - # Out-of-date for Pyomo 4.1 - # obj = instance.active_components(Objective) - # objs = obj.items()[0] - # obj_name, obj_value = objs[0], value(objs[1]()) - # return obj_value - - import sys - import os - from collections import deque, defaultdict - from pyomo.pysp.util.scenariomodels import scenario_tree_model - - (head, tail) = os.path.split(p_model) - sys.path.insert(0, head) - pwd = os.getcwd() - os.chdir(p_data) - - s2fp_dict = defaultdict(deque) # Scenario to 'file path' dictionary, .dat not included - s2cd_dict = defaultdict(float) # Scenario to conditonal density mapping - sStructure = scenario_tree_model.create_instance(filename='ScenarioStructure.dat') - - # The following code is borrowed from Kevin's temoa_lib.py - ########################################################################### - # Step 1: find the root node. PySP doesn't make this very easy ... - - # a child -> parent mapping, because every child has only one parent, but - # not vice-versa - ctpTree = dict() # Child to parent dict, one to one mapping - - to_process = deque() - to_process.extend(sStructure.children.keys()) - while to_process: - node = to_process.pop() - if node in sStructure.children: - # it's a parent! - new_nodes = set(sStructure.children[node]) - to_process.extend(new_nodes) - ctpTree.update({n: node for n in new_nodes}) - - # parents - children - root_node = (set(ctpTree.values()) - set(ctpTree.keys())).pop() - - # ptcTree = defaultdict( list ) # Parent to child node, one to multiple mapping - # for c, p in ctpTree.iteritems(): - # ptcTree[ p ].append( c ) - # ptcTree = dict( ptcTree ) # be slightly defensive; catch any additions - - # leaf_nodes = set(ctpTree.keys()) - set(ctpTree.values()) - leaf_nodes = set(sStructure.scenario_leaf_node.values()) # Try to hack Kevin's code - - scenario_nodes = dict() # Map from leafnode to 'node path' - for node in leaf_nodes: # e.g.: {Rs0s0: [R, Rs0, Rs0s0]} - s = deque() - scenario_nodes[node] = s - while node in ctpTree: - s.append(node) - node = ctpTree[node] - s.append(node) - s.reverse() - ########################################################################### - - for s in sStructure.scenarios: - cp = 1.0 # Starting probability - for n in scenario_nodes[sStructure.scenario_leaf_node[s]]: - cp = cp * sStructure.conditional_probability[n] - if not sStructure.scenario_based_data.value: - s2fp_dict[s].append(n + '.dat') - s2cd_dict[s] = cp - - if sStructure.scenario_based_data.value: - for s in sStructure.scenarios: - s2fp_dict[s].append(s + '.dat') - # IP() - model_module = __import__(tail[:-3], globals(), locals()) - model = model_module.model - pf_result = {'cost': list(), 'cd': list()} - for s in sStructure.scenarios: - pf_result['cd'].append(s2cd_dict[s]) - data = DataPortal(model=model) - for dat in s2fp_dict[s]: - data.load(filename=dat) - instance = model.create_instance(data) - optimizer = SolverFactory('cplex') - results = optimizer.solve(instance) - - instance.solutions.load_from(results) - # instance.load(results) - obj_val = return_obj(instance) - pf_result['cost'].append(obj_val) - sys.stdout.write(f'\nSolved .dat(s) {s2fp_dict[s]}\n') - sys.stdout.write(f' Total cost: {obj_val}\n') - os.chdir(pwd) - return pf_result - - -def solve_ef(p_model, p_data, dummy_temoa_options=None): - """ - solve_ef(p_model, p_data) -> objective value of the extensive form - Solves the model in stochastic mode. - p_model -> string, the path to the model file (ReferenceModel.py). - p_data -> string, the path to the directory of data for the stochastic - mdoel, where ScenarioStructure.dat should resides. - Returns a float point number of the value of objective function for the - stochastic program model. - """ - - options = ScenarioTreeManagerClientSerial.register_options() - - if os.path.basename(p_model) == 'ReferenceModel.py': - options.model_location = os.path.dirname(p_model) - else: - sys.stderr.write('\nModel file should be ReferenceModel.py. Exiting...\n') - sys.exit(1) - options.scenario_tree_location = p_data - - # using the 'with' block will automatically call - # manager.close() and gracefully shutdown - with ScenarioTreeManagerClientSerial(options) as manager: - manager.initialize() - - ef_instance = create_ef_instance(manager.scenario_tree, verbose_output=options.verbose) - - ef_instance.dual = Suffix(direction=Suffix.IMPORT) - - with SolverFactory('cplex') as opt: - ef_result = opt.solve(ef_instance) - - # Write to database - if dummy_temoa_options: - sys.path.append(options.model_location) - from pformat_results import pformat_results - from temoa_config import TemoaConfig - - temoa_options = TemoaConfig() - temoa_options.config = dummy_temoa_options.config - temoa_options.save_lp_file = dummy_temoa_options.save_lp_file - temoa_options.saveTEXTFILE = dummy_temoa_options.saveTEXTFILE - temoa_options.path_to_data = dummy_temoa_options.path_to_data - temoa_options.save_excel = dummy_temoa_options.save_excel - ef_result.solution.Status = 'feasible' # Assume it is feasible - for s in manager.scenario_tree.scenarios: - ins = s._instance - temoa_options.scenario = s.name - temoa_options.dot_dat = [ - os.path.join(options.scenario_tree_location, s.name + '.dat') - ] - temoa_options.output_file = os.path.join( - options.scenario_tree_location, dummy_temoa_options.output_file - ) - msg = f'\nStoring results from scenario {s.name} to database.\n' - sys.stderr.write(msg) - formatted_results = pformat_results(ins, ef_result, temoa_options) - - ef_instance.solutions.store_to(ef_result) - ef_obj = value(ef_instance.EF_EXPECTED_COST.values()[0]) - return ef_obj - - -def do_test(p_model, p_data, temoa_config=None): - from time import time - - t0 = time() - timeit = lambda: time() - t0 - - if not isinstance(p_data, list): - p_data = [p_data] - for this_data in p_data: - sys.stderr.write('\nSolving perfect sight mode\n') - sys.stdout.write('-' * 25 + '\n') - pf_result = solve_pf(p_model, this_data) - msg = f'Time: {timeit()} s\n' - sys.stderr.write(msg) - - sys.stderr.write('\nSolving extensive form\n') - sys.stdout.write('-' * 25 + '\n') - ef_result = solve_ef(p_model, this_data, temoa_config) - - msg = f'\nTime: {timeit()} s\n' - msg += f'runef objective value: {ef_result}\n' - msg += f'EVPI: {compute_evpi(ef_result, pf_result)}\n' - sys.stderr.write(msg) - - -if __name__ == '__main__': - # p_model = "/afs/unity.ncsu.edu/users/b/bli6/temoa/temoa_model" - # p_data = [ - # "/afs/unity.ncsu.edu/users/b/bli6/TEMOA_stochastic/NC/noIGCC-CP", - # "/afs/unity.ncsu.edu/users/b/bli6/TEMOA_stochastic/NC/noIGCC-noCP", - # "/afs/unity.ncsu.edu/users/b/bli6/TEMOA_stochastic/NC/IGCC-CP", - # "/afs/unity.ncsu.edu/users/b/bli6/TEMOA_stochastic/NC/IGCC-noCP", - # ] - # dummy_temoa_options = DummyTemoaConfig() - # dummy_temoa_options.config = None - # dummy_temoa_options.keepPyomoLP = False - # dummy_temoa_options.saveTEXTFILE = False - # dummy_temoa_options.path_to_data = None - # dummy_temoa_options.saveEXCEL = False - # dummy_temoa_options.output = "NCreference.db" - # do_test(p_model, p_data, dummy_temoa_options) - - p_model = '/mnt/disk2/nspatank/SS_2_H/For_Jeff/temoa_ssudan/temoa_model/ReferenceModel.py' - p_data = '/mnt/disk2/nspatank/SS_2_H/For_Jeff/temoa_ssudan/tools/S_Sudan' - do_test(p_model, p_data) diff --git a/temoa/extensions/stochastics/README.txt b/temoa/extensions/stochastics/README.txt deleted file mode 100644 index 339003393..000000000 --- a/temoa/extensions/stochastics/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -This extension is currently NOT maintained and is retained as a framework for possible future use. - -1 JUN 2024 \ No newline at end of file diff --git a/temoa/extensions/stochastics/ReferenceModel.py b/temoa/extensions/stochastics/ReferenceModel.py deleted file mode 120000 index 3e640644e..000000000 --- a/temoa/extensions/stochastics/ReferenceModel.py +++ /dev/null @@ -1 +0,0 @@ -temoa_stochastic.py \ No newline at end of file diff --git a/temoa/extensions/stochastics/VSS.py b/temoa/extensions/stochastics/VSS.py deleted file mode 100755 index 09589eece..000000000 --- a/temoa/extensions/stochastics/VSS.py +++ /dev/null @@ -1,326 +0,0 @@ -# Script to determine the value of the stochastic solution using Temoa -from pyomo.core import DataPortal -from pyomo.opt import SolverFactory -from pyomo.pysp.ef_vss import * -from pyomo.pysp.ef_writer_script_old import * - - -def organize_csv(): - # This function was imported from the EVPI script - from collections import OrderedDict - from csv import reader, writer - - rows = list() - tech = list() - node = list() - empty_row = [''] * 7 - with open('V_ActivityByPeriodAndTech.csv', 'rb') as f: - csv_reader = reader(f, dialect='excel') - for row in csv_reader: - rows.append(row + ['']) - - organized_rows = OrderedDict() - for row in rows: - this_tech = row[4] - if row[1] not in node: - node.append(row[1]) - if this_tech not in tech: - tech.append(this_tech) - organized_rows[this_tech] = [row] - else: - organized_rows[this_tech].append(row) - - for this_tech in tech: - for i in range(0, len(organized_rows[this_tech])): - if organized_rows[this_tech][i][1] != node[i]: - organized_rows[this_tech].insert(i, empty_row) - - # tech.sort() - with open('V_ActivityByPeriodAndTech_org.csv', 'wb') as f: - csv_writer = writer(f, dialect='excel') - for this_tech in organized_rows: - row = list() - for i in organized_rows[this_tech]: - row += i - csv_writer.writerow(row) - - -def my_ef_writer(scenario_tree): - # This function was imported from the EVPI script - from collections import OrderedDict - from csv import writer - - rows = dict() # Key is the variable's name - for stage in scenario_tree._stages: - stage_name = stage._name - for tree_node in stage._tree_nodes: - tree_node_name = tree_node._name - for var_id in sorted(tree_node._variable_ids): - var_name, index = tree_node._variable_ids[var_id] - row = [str(stage_name), str(tree_node_name), str(var_name)] - if isinstance(index, str): - row += [index] - else: - for i in index: - row += [str(i)] - row += [str(tree_node._solution[var_id])] - if var_name not in rows: - rows[var_name] = [row] - else: - rows[var_name].append(row) - - stage_cost_vardata = tree_node._cost_variable_datas[0][0] - obj = str(stage_cost_vardata.parent_component().name) - row = [ - str(stage_name), - str(tree_node_name), - str(obj), - str(stage_cost_vardata.index()), - str(stage_cost_vardata()), - ] - if obj not in rows: - rows[obj] = [row] - else: - rows[obj].append(row) - - for ofile in rows.keys(): - with open(ofile + '.csv', 'wb') as f: - csv_writer = writer(f, dialect='excel') - csv_writer.writerows(rows[ofile]) - - # To calculate V_Activity[p,t] - if 'V_ActivityByPeriodAndProcess' in rows: - V_Activity_ptv = rows['V_ActivityByPeriodAndProcess'] - V_Activity_pt = OrderedDict() - for row in V_Activity_ptv: - key = ( - row[0], - row[1], - row[2], - row[3], - row[4], - ) # (Stage, Node, var_name, p, t) - if key not in V_Activity_pt: - V_Activity_pt[key] = float(row[6]) - else: - V_Activity_pt[key] += float(row[6]) - - with open('V_ActivityByPeriodAndTech.csv', 'wb') as f: - csv_writer = writer(f, dialect='excel') - for key in V_Activity_pt.keys(): - row = list(key) + [V_Activity_pt[key]] - csv_writer.writerow(row) - - -def solve_ef(ef_options): - # This function solves a stochastic optimization problem via extensive form - # This function was imported from the EVPI script - import os - import sys - - sif = ScenarioTreeInstanceFactory( - ef_options.model_directory, ef_options.instance_directory, ef_options.verbose - ) - scenario_tree = GenerateScenarioTreeForEF(ef_options, sif) - ef = EFAlgorithmBuilder(ef_options, scenario_tree) - f = open(os.devnull, 'w') - sys.stdout = f - ef.solve() - # ef.save_solution() # This line saves the results into two csv files - sys.stdout = sys.__stdout__ - f.close() - sys.stderr.write('\nrunef output suppressed\n') - my_ef_writer(ef._scenario_tree) - root_node = ef._scenario_tree._stages[0]._tree_nodes[0] - # II() - return root_node.computeExpectedNodeCost() - - -def solve_ef_fix(ef_options, avg_instance): - # This function solves a stochastic optimization problem via extensive form - # where first stage decision variables are fixed at the optimal values from - # the deterministic model called here avg_instance - - import os - import sys - - sif = ScenarioTreeInstanceFactory( - ef_options.model_directory, ef_options.instance_directory, ef_options.verbose - ) - scenario_tree = GenerateScenarioTreeForEF(ef_options, sif) - ef = EFAlgorithmBuilder(ef_options, scenario_tree) - - time_fut = avg_instance.time_future.data() - techs = avg_instance.tech_all.data() - dv_capacity = ( - avg_instance.v_capacity.get_values() - ) # Getting dec vars that matters to be fixed - # dV_HydroStorage = avg_instance.V_HydroStorage.get_values() - - # Storing techs and future time periods in vector for easy access - vtime_fut = [0] * len(time_fut) - k = 0 - for iaux in time_fut: - vtime_fut[k] = iaux - k = k + 1 - - # Fixing Capacity values for first stage at the ef instance with values from - # the deterministic instance - for iaux1, iaux2 in dv_capacity: - if iaux2 == vtime_fut[0]: - ef._binding_instance.S0s0s0.v_capacity[iaux1, iaux2].fix(dv_capacity[iaux1, iaux2]) - # ef._binding_instance.S0.v_capacity[iaux1, iaux2].fix(3) - # just for checking if fixing at one scen also fix in the other - ok for now - - # Fixing Hydro Storage values for first stage - # for iaux1 , iaux2 in dV_HydroStorage: - # if iaux2 == vtime_fut[0]: - # ef._binding_instance.S0s0.V_HydroStorage[iaux1, iaux2].fix(dV_HydroStorage[iaux1,iaux2]) - - f = open(os.devnull, 'w') - sys.stdout = f - ef.solve() - # ef.save_solution() # This line saves the results into two csv files - sys.stdout = sys.__stdout__ - f.close() - sys.stderr.write('\nrunef output suppressed\n') - my_ef_writer(ef._scenario_tree) - root_node = ef._scenario_tree._stages[0]._tree_nodes[0] - return root_node.computeExpectedNodeCost() - - -def solve_dm(p_model, p_data, opt_solver): - # This function solves a deterministic model with the inputs for - # uncertainty values represented by their average values at each stage - # We assume the ReferenceModel.dat as the average problem properly represented - # inside the stochastic folder - - def return_obj(instance): - from pyomo.core import Objective - - obj = instance.component_objects(Objective, active=True) - obj_values = list() - for o in obj: - # See section 18.6.3 in Pyomo online doc - method_obj = getattr(instance, str(o)) - obj_values.append(method_obj()) - # Assuming there is only one objective function - return obj_values[0] - - import os - import sys - - (head, tail) = os.path.split(p_model) - sys.path.insert(0, head) - pwd = os.getcwd() - os.chdir(p_data) - - model_module = __import__(tail[:-3], globals(), locals()) - model = model_module.model - dm_result = {'cost': list(), 'flowin': list(), 'flowout': list(), 'capacity': list()} - - data = DataPortal(model=model) - - dat = 'AverageModel.dat' # Loading the model from the data file - data.load(filename=dat) - - instance = model.create_instance( - data - ) # Defining the model instance with the data from .dat file - optimizer = SolverFactory(opt_solver) # Defining the optimization solver - results = optimizer.solve(instance) # Solving the optimization model - - instance.solutions.load_from(results) # Saving solutions in memory - - # Getting objective function values - obj_val = return_obj(instance) - dm_result['cost'].append(obj_val) - - # Writting to the Shell - sys.stdout.write( - '\nSolved deterministic model with uncertainty at average valures \n' - ) - sys.stdout.write(f' Total cost: {obj_val}\n') - os.chdir(pwd) - return instance # Returning instance solved, values will be used later - - -def runEVPI(): - # EVPI_value = test_twotechs_vss_base() - EVPI_value = test_sudan_VSS() - return EVPI_value - - -def runECIU(): - import os - - # folder_string = "stochastic/twotechs_vss_base/" - folder_string = 'stochastic/utopia_vss/' - os.system('python temoa_model/ --eciu ' + folder_string) - - -def runVSS(): - # This is the main function. It calls 1) Extensive Form 2)Deterministic LP - # 3)Fixed Extensive Form. After results of 1) and 3) are obtained it computes the VSS - # As input, this function requires the path of the stochastic folder and - # temoa_stochastic.py file - # It assumes that an instance named ReferenceModel.dat is located inside the stochastic folder - - import sys - from time import time - - sys.stderr.write('\nFinding the Value of the Stochastic Solution using Temoa\n') - - p_model = '/home/arqueiroz/SSudan/S1_2_H/temoa_model/temoa_stochastic.py' - p_data = '/home/arqueiroz/SSudan/S1_2_H/stochastic/S_Sudan_original_stoch_cap_cost_11' - optsolver = 'cplex' - - # --------------------- - # Solving the deterministic model with average values - # --------------------- - sys.stderr.write('\nSolving perfect sight with uncertainty at average values\n') - dm_instance = solve_dm( - p_model, p_data, optsolver - ) # Here we have all the information with respect to objfunc and decvars - - zdm_result = dm_instance.total_cost.value - # --------------------- - # Solving the extensive model for the recoursive problem - # --------------------- - ef_args = ['-m', p_model, '-i', p_data, '--solver', optsolver, '--solve'] - ef_option_parser = construct_ef_writer_options_parser('runef [options]') - start_time = time() - (ef_options, args) = ef_option_parser.parse_args(args=ef_args) - - # II() - sys.stderr.write('\nSolving extensive form\n') - ef_result = solve_ef(ef_options) - - msg = f'\nrunef time: {time() - start_time} s\n' - msg += f'runef objective value: {ef_result}\n' - sys.stderr.write(msg) - - # --------------------- - # Solving the extensive model fixing variables for stage 1 - # --------------------- - ef_result_fixed = solve_ef_fix(ef_options, dm_instance) - - # Compute the value of the stochastic solution (vss = z_eev - z_rp) - return ef_result, ef_result_fixed, zdm_result - - -if __name__ == '__main__': - vZrp, vZeev, vZdm = runVSS() - print('---------------------------------------------------------') - print('---------------------------------------------------------') - vEVPI = runEVPI() - print('---------------------------------------------------------') - print('---------------------------------------------------------') - # runECIU() - print('---------------------------------------------------------') - print('---------------------------------------------------------') - print('Zrp = ', vZrp) - print('Zeev = ', vZeev) - print('Zdm = ', vZdm) - print('EVPI = ', vEVPI) - print('VSS = ', vZeev - vZrp) diff --git a/temoa/extensions/stochastics/generate_scenario_tree-nonhomogenous.py b/temoa/extensions/stochastics/generate_scenario_tree-nonhomogenous.py deleted file mode 100755 index 33302c118..000000000 --- a/temoa/extensions/stochastics/generate_scenario_tree-nonhomogenous.py +++ /dev/null @@ -1,613 +0,0 @@ -#!/usr/bin/env python - - -import os -import sys -from io import StringIO -from pprint import pformat -from shutil import copy as copyfile -from shutil import rmtree - -from pyomo.core.base.sets import _SetContainer, _SetProduct - -SE = sys.stderr -instance = None - -node_count = 0 -stringify = lambda x: ', '.join(str(i) for i in x) - - -class Storage: - __slots__ = ('value', 'rate') # this saves a noticeable amount of memory - - def __str__(self): - return pformat(self.__dict__, indent=2) - - __repr__ = __str__ - - -class Param: - # will be common to all Parameters, so no sense in storing it N times - stochasticset = None - - # this saves a noticeable amount of memory, and mild decrease in time - __slots__ = ('items', 'name', 'spoint', 'param', 'my_keys', 'model_keys', 'skeys') - - def __init__(self, **kwargs): - # At the point someone is using this class, they probably know what - # they're doing, so intentionally die at this point if any of these - # items are not passed. They're all mandatory. - name = kwargs.pop('param') # parameter in question to modify - spoint = kwargs.pop('spoint') # stochastic point at which to do it - rates = kwargs.pop('rates') # how much to vary the parameter - pidx = int(kwargs.pop('stochastic_index')) - - param = getattr(instance, name) # intentionally die if not found. - - indices = tuple() - pindex = param.index() - - if isinstance(pindex, _SetProduct): - indices = param.sparse_keys() - skeys = lambda: (' '.join(str(i) for i in k) for k in self.model_keys) - - keys = param.sparse_keys() - f = lambda x: x[pidx] == spoint - r = lambda x: tuple(x[0:pidx] + x[pidx + 1 :]) - # reduce keys to remove stochastic parameter - - elif isinstance(pindex, _SetContainer): - # this is under sparse keys - indices = (param._index.name,) - skeys = lambda: (' '.join(str(i) for i in self.model_keys)) - - keys = param.sparse_keys() - f = lambda x: x[pidx] == spoint - r = lambda x: tuple(x[0:pidx] + x[pidx + 1 :]) - - # we filter out the spoint because it's inherently known by TreeNode, - # which "owns" /this/ Param - model_keys = filter(f, keys) - my_keys = map(r, model_keys) - - items = dict() - - for actual, mine in zip(model_keys, my_keys): - rate = 1 - for pattern, r in rates: - keys = pattern.split(',') - match = True - for p, t in zip(keys, mine): # "pattern", "test" - if '*' == p: - continue - if t != p: - match = False - break - if match: - rate = r - break - - items[mine] = Storage() - try: - items[mine].value = param[actual] # pulled from model - except ValueError: - items[mine].value = 0 - items[mine].rate = rate - - self.items = items - self.name = name - self.spoint = spoint - self.param = param - self.my_keys = my_keys # these keys are linked -- in the same - self.model_keys = model_keys # order -- for zip()-ability - self.skeys = skeys # for later, string keys - - def __iter__(self): - return self.items.__iter__() - - def __getitem__(self, i): - try: - return self.items[i] - except: - # it's likely the element did not exist, which hopefully means 0? - class _tmp: - rate = 0 - value = 0 - - return _tmp() - - def __str__(self): - x = '; '.join(f'({self[i].value}, {self[i].rate})' for i in self) - return f'Param({self.name}): {x}' - - __repr__ = __str__ - - def as_ampl(self, comment=''): - pindex = self.param.index() - if comment: - comment = '# Decision: %s\n\n' % str(comment) - - keys = self.skeys() - if isinstance(keys, str): - keys = [keys] - - # Together, these functions return the length of a printed version of - # a number, in characters. They are used to make columns of data line up - # so one may have an easier time getting an overall sense of a data file. - def get_int_padding(v): - return len(str(int(v))) - - def get_str_padding(index): - def anonymous_function(obj): - val = obj[index] - return len(str(val)) - - return anonymous_function - - keys = tuple(tuple(i.split()) for i in keys) - vals = tuple(self[i].value for i in self.my_keys) - int_padding = max(map(get_int_padding, vals)) - str_padding = [max(map(get_str_padding(i), keys)) for i in range(len(keys[0]))] - str_format = ' %-{}s' * len(self.model_keys[0]) - str_format = str_format.format(*str_padding) - - format = '\n%%s %%%ds%%s' % int_padding - # works out to something like '\n %s %8d%-6s' - # index { val } - - data = StringIO() - data.write(comment + 'param %s :=' % self.name) - for actual_key, this_key in sorted(zip(self.model_keys, self.my_keys)): - v = self[this_key].value - int_part = str(int(abs(v))) - if int_part != str(abs(v)): - dec_part = str(abs(v))[len(int_part) :] - else: - dec_part = '' - - if v < 0: - int_part = '-%d' % int_part - index = str_format % tuple(actual_key) - data.write(format % (index, int_part, dec_part)) - data.write('\n\t;\n') - - # return comment + data - return data.getvalue() - - -class TreeNode: - __slots__ = ('name', 'parent', 'spoint', 'prob', 'params', 'bname', 'children') - - def __init__(self, *args, **kwargs): - # At the point someone is using this class, they probably know what - # they're doing, so intentionally die at this point if any of these - # items are not passed. They're all mandatory. - self.name = kwargs.pop('name') # name of /this/ node - self.parent = kwargs.pop('parent') - self.spoint = kwargs.pop('spoint') # stochastic point of node - self.prob = kwargs.pop('prob') # conditional probability of node - bname = kwargs.pop('filebase') # file name minus extension - types = kwargs.pop('types') # names of decisions - rates = kwargs.pop('rates') # rates at which to vary - sindices = kwargs.pop('stochastic_indices') - - params = rates.keys() - myparams = dict() - if self.name != 'HedgingStrategy': - for key, decisions in rates.items(): - paramkwargs = { - 'param': key, - 'rates': (), - 'spoint': self.spoint, - 'stochastic_index': sindices[key], - } - decision = f'{self.parent}{self.name}' - paramkwargs.update({'rates': decisions[decision]}) - - myparams[key] = Param(**paramkwargs) - - self.params = myparams - self.bname = bname - self.children = [] - - def addChild(self, node): - self.children.append(node) - - def __repr__(self): - x = self.name - if isinstance(self.name, tuple): - x = ', '.join(x) - return f'{self.spoint}({x}): ' + ', '.join(str(i) for i in self.params.values()) - - def __str__(self, indent=' ', space=''): - x = ''.join(i.__str__(indent, space + indent) for i in self.children) - - return space + repr(self) + '\n' + x - - def write_dat_files(self): - global node_count - - # Step 1: Write my own file, if necessary - if self.name != 'HedgingStrategy': - params = self.params.values() - data = params[0].as_ampl(self.name) - if len(params) > 1: - data += '\n' + '\n'.join(p.as_ampl() for p in params[1:]) - else: - data = '# Decision: HedgingStrategy (no change from R.dat)\n' - - with open(self.bname + '.dat', 'w') as f: - f.write(data) - - node_count += 1 - inform('\b' * (len(str(node_count - 1)) + 1) + str(node_count) + ' ') - - # Step 2: Tell my children to write their files - for c in self.children: - for p in self.params: - cp = c.params[p] - for key in self.params[p]: - cp[key].value = self.params[p][key].value * cp[key].rate - c.write_dat_files() - - def get_scenario_data(self): - nodes = [self.bname] - nodestage = [(self.bname, 's' + str(self.spoint))] - probability = [(self.bname, self.prob)] - scenarios = [] - children = [] - - if not self.children: - scenarios = [self.bname[2:]] - else: - children = [(self.bname, [c.bname for c in self.children])] - - for child in self.children: - s, n, ns, c, p = child.get_scenario_data() - scenarios += s - nodes += n - nodestage += ns - children += c - probability += p - - return scenarios, nodes, nodestage, children, probability - - -def write_scenario_file(stochasticset, tree): - ( - scenarios, - nodes, - nodestage, - children, - probability, - ) = tree.get_scenario_data() - - child_fmt = 'set children[%s] :=\n %s\n\t;\n' - scenario_fmt = 'S%(i)s Rs%(i)s' - stages_fmt = 'set stage_variables[s{}] :=\n {}\n\t;' - stagecost_fmt = 's%s StochasticPointCost[%s]' - - leaves = '\n '.join(scenario_fmt % {'i': i} for i in scenarios) - nodes = '\n '.join(nodes) - nodestage = '\n '.join(' '.join(ns) for ns in nodestage) - scenarios = 'S%s' % '\n S'.join(scenarios) - stagecost = '\n '.join(stagecost_fmt % (s, s) for s in stochasticset) - stages = '\n s'.join(str(se) for se in stochasticset) - - probability = '\n '.join(' '.join(str(i) for i in p) for p in probability) - children = '\n'.join(child_fmt % (c[0], '\n '.join(c[1])) for c in children) - - # XXX: Temporary and absolute hack, that currently only works for Temoa - # models. The short of it is that this script was written prior to Temoa's - # implementation with sparse sets, so now we have to ensure that only the - # sparse sets are used: - - stage_var_sets = list() - for se in stochasticset: # se = "stochastic element" - flow_keys = [index for index in instance.v_flow_out.keys() if index[0] == se] - processes = [(t, v) for p, s, d, i, t, v, o in flow_keys if v == se] - - stage_vars = list() - stage_vars.extend( - sorted('v_flow_in[{},{},{},{},{},{},{}]'.format(*index) for index in flow_keys) - ) - stage_vars.extend( - sorted('v_flow_out[{},{},{},{},{},{},{}]'.format(*index) for index in flow_keys) - ) - stage_vars.extend(sorted('v_capacity[{},{}]'.format(*index) for index in processes)) - - stage_var_sets.append(stages_fmt.format(se, '\n '.join(stage_vars))) - stage_var_sets = '\n\n'.join(stage_var_sets) - - structure = """\ -set stages := - s%(stages)s - ; - -set scenarios := - %(scenarios)s - ; - -set nodes := - %(nodes)s - ; - -%(children_sets)s - -%(stage_var_sets)s - -param node_stage := - %(nodestage)s - ; - -param conditional_probability := - %(cond_prob)s - ; - -param scenario_leaf_node := - %(leaves)s - ; - -param stage_cost_variable := - %(stagecost)s - ; - -param scenario_based_data := False ; -""" - - structure %= dict( - stages=stages, - scenarios=scenarios, - nodes=nodes, - children_sets=children, - stage_var_sets=stage_var_sets, - nodestage=nodestage, - cond_prob=probability, - leaves=leaves, - stagecost=stagecost, - ) - - with open('ScenarioStructure.dat', 'w') as f: - f.write(structure) - - -def _create_tree(stochasticset, spoints, **kwargs): - name = kwargs.get('name') - bname = kwargs.get('bname') - parent = kwargs.get('parent') - prob = kwargs.get('prob') - cprob = kwargs.get('cprob') - - spoint = stochasticset.pop() # stochastic point, use of pop implies ordering - treekwargs = dict( - spoint=spoint, - name=name, - parent=parent, - types=kwargs.get('types'), - rates=kwargs.get('rates'), - filebase=bname, - prob=prob, - stochastic_indices=kwargs.get('stochastic_indices'), - ) - - node = TreeNode(**treekwargs) - global node_count - node_count += 1 - inform('\b' * (len(str(node_count - 1)) + 1) + str(node_count) + ' ') - - if spoint not in spoints: - kwargs.update( - name='HedgingStrategy', - parent=name, - bname='%ss0' % bname, - prob=1, - ) - node.addChild(_create_tree(stochasticset[:], spoints, **kwargs)) - elif stochasticset: - decisions = enumerate(cprob[name]) - bname = '%ss%%d' % bname # the format for the basename of the file - for enum, (d, prob) in decisions: - kwargs.update( - name=d, - parent=name, - bname=bname % enum, - prob=prob, - ) - node.addChild(_create_tree(stochasticset[:], spoints, **kwargs)) - - return node - - -def create_tree(stochasticset, spoints, opts): - types = opts.types - rates = opts.rates - cprob = opts.conditional_probability - - stochasticset.reverse() - spoints.sort() - spoints.reverse() - - kwargs = dict( - name='HedgingStrategy', - parent='', - bname='R', - types=types, - rates=rates, - cprob=cprob, - stochastic_indices=opts.stochastic_indices, - prob=1, # conditional probability, but root guaranteed to occur - ) - return _create_tree(stochasticset, spoints, **kwargs) - - -def inform(x): - global verbose - if verbose: - SE.write(x) - SE.flush() - - -def setup_directory(dname, force): - if os.path.exists(dname): - if os.path.isdir(dname): - files = os.listdir(dname) - if files and not force: - msg = ( - 'Not empty: {}\n\nIf you want to use this directory anyway, ' - "set 'force = True' in the options.py file." - ) - raise Warning(msg.format(dname)) - - # would be potentially useful to put this into a thread to speed up - # the process. like 'mv somedir to_del; rm -rf to_del &' - rmtree(dname) - os.mkdir(dname) - else: - msg = 'Error - already exists: {}' - raise NameError(msg.format(dname)) - else: - os.mkdir(dname) - - -def test_model_parameters(M, opts): - try: - getattr(M, opts.stochasticset) - except: - msg = ( - 'Whoops! The stochastic set is not available from the model. ' - 'Did you perhaps typo the name?\n' - ' Model name: {}\n' - ' Stochastic name: {}' - ) - raise ValueError(msg.format(M.name, opts.stochasticset)) - - try: - for pname in opts.rates: - param = getattr(M, pname) - except: - msg = ( - 'Whoops! Parameter not available from the model. Have you ' - 'perhaps typoed the name?\n' - ' Model name: {}\n' - ' Parameter name: {}' - ) - raise ValueError(msg.format(M.name, pname)) - - -def usage(): - SE.write( - """ -synopsis: pyomo_python {0} - -Example: pyomo_python {0} options/utopia_coal_vs_nuc.py - -For information about the options_to_import.py file, please see -options/README.txt -""".format(sys.argv[0]) - ) - - raise SystemExit - - -def main(): - from os import getcwd - from time import clock - - if len(sys.argv) < 2: - usage() - module_name = sys.argv[1][:-3].replace('/', '.') # remove the '.py' - - try: - __import__(module_name) - opts = sys.modules[module_name] - - except ImportError: - msg = 'Unable to import {}.\n\nRun this script with no arguments for more information.\n' - SE.write(msg.format(sys.argv[1])) - raise - - try: - opts.dirname - except AttributeError: - opts.dirname = module_name.split('.')[-1] - - global verbose - verbose = opts.verbose - - cwd = getcwd() - - begin = clock() - duration = lambda: clock() - begin - - inform('[ ] Setting up working directory (%s)' % opts.dirname) - setup_directory(opts.dirname, opts.force) - inform('\r[%6.2f\n' % duration()) - - inform('[ ] Import model definition (%s)' % opts.modelpath) - mp = opts.modelpath - modelbase = os.path.basename(mp)[:-3] - modeldir = os.path.abspath(os.path.dirname(mp)) - - sys.path.insert(0, modeldir) - _temp = __import__(modelbase, globals(), locals(), ('model',)) - M = _temp.model - del _temp - sys.path.pop(0) - - test_model_parameters(M, opts) - - inform('\r[%6.2f\n' % duration()) - - inform('[ ] Create concrete instance (%s)' % opts.dotdatpath) - ins = M.create(opts.dotdatpath) - inform('\r[%6.2f\n' % duration()) - - global instance - instance = ins - - inform('[ ] Collecting stochastic points from model (%s)' % M.name) - all_spoints = sorted(getattr(ins, opts.stochasticset).value) - try: - spoints = list(opts.stochastic_points) - except AttributeError: - spoints = all_spoints - - inform('\r[%6.2f\n' % duration()) - - # used for friendlier error checking - Param.stochasticset = opts.stochasticset - - os.chdir(opts.dirname) - inform('[ ] Building tree: ') - tree = create_tree(all_spoints[:], spoints[:], opts) # give an intentional copy - inform('\r[%6.2f\n' % duration()) - - global node_count - node_count = 0 - - inform('[ ] Writing scenario "dot dat" files: ') - tree.write_dat_files() - write_scenario_file(all_spoints, tree) - inform('\r[%6.2f] Writing scenario "dot dat" files\n' % duration()) - - os.chdir(cwd) - inform('[ ] Copying ReferenceModel.dat as scenario tree root') - copyfile(opts.dotdatpath, '%s/ReferenceModel.dat' % opts.dirname) - copyfile(opts.dotdatpath, '%s/R.dat' % opts.dirname) - inform('\r[%6.2f\n' % duration()) - - -if '__main__' == __name__: - try: - main() - except Exception as e: - if '--debug' in sys.argv: - raise - - msg = ( - '\n\nIf you need more verbose (potentially helpful) information ' - 'about this error, you can run this program again, and add the' - ' "--debug" command line flag.\n' - ) - msg = '\n\n' + str(e) + msg - SE.write(msg) diff --git a/temoa/extensions/stochastics/generate_scenario_tree.py b/temoa/extensions/stochastics/generate_scenario_tree.py deleted file mode 100755 index f2f781d6f..000000000 --- a/temoa/extensions/stochastics/generate_scenario_tree.py +++ /dev/null @@ -1,623 +0,0 @@ -#!/usr/bin/env python - - -import os -import sys -from io import StringIO -from pprint import pformat -from shutil import copy as copyfile -from shutil import rmtree - -from pyomo.core.base.sets import SimpleSet, _SetProduct - -SE = sys.stderr -instance = None - -node_count = 0 -stringify = lambda x: ', '.join(str(i) for i in x) - - -class Storage: - __slots__ = ('value', 'rate') # this saves a noticeable amount of memory - - def __str__(self): - return pformat(self.__dict__, indent=2) - - __repr__ = __str__ - - -class Param: - # will be common to all Parameters, so no sense in storing it N times - stochasticset = None - - # this saves a noticeable amount of memory, and mild decrease in time - __slots__ = ('items', 'name', 'spoint', 'param', 'my_keys', 'model_keys', 'skeys') - - def __init__(self, **kwargs): - # At the point someone is using this class, they probably know what - # they're doing, so intentionally die at this point if any of these - # items are not passed. They're all mandatory. - name = kwargs.pop('param') # parameter in question to modify - spoint = kwargs.pop('spoint') # stochastic point at which to do it - rates = kwargs.pop('rates') # how much to vary the parameter - pidx = int(kwargs.pop('stochastic_index')) - - param = getattr(instance, name) # intentionally die if not found. - - indices = tuple() - pindex = param.index_set() - - if isinstance(pindex, _SetProduct): - getname = lambda x: x.name - indices = [getname(i) for i in pindex.set_tuple] - skeys = lambda: (' '.join(str(i) for i in k) for k in self.model_keys) - - keys = param.keys() - f = lambda x: x[pidx] == spoint - r = lambda x: tuple(x[0:pidx] + x[pidx + 1 :]) - # reduce keys to remove stochastic parameter - - elif isinstance(pindex, SimpleSet): - # this is under sparse keys - indices = (param._index.name,) - skeys = lambda: (' '.join(str(i) for i in self.model_keys)) - - keys = param.keys() - f = lambda x: x[pidx] == spoint - r = lambda x: tuple(x[0:pidx] + x[pidx + 1 :]) - - # we filter out the spoint because it's inherently known by TreeNode, - # which "owns" /this/ Param - model_keys = filter(f, keys) - my_keys = map(r, model_keys) - - items = dict() - - for actual, mine in zip(model_keys, my_keys): - rate = 1 - - for pattern, r in rates: - keys = pattern.split(',') - match = True - for p, t in zip(keys, mine): # "pattern", "test" - if '*' == p: - continue - if t != p: - match = False - break - if match: - rate = r - break - - items[mine] = Storage() - try: - items[mine].value = param[actual] # pulled from model - except ValueError: - items[mine].value = 0 - items[mine].rate = rate - - self.items = items - self.name = name - self.spoint = spoint - self.param = param - self.my_keys = my_keys # these keys are linked -- in the same - self.model_keys = model_keys # order -- for zip()-ability - self.skeys = skeys # for later, string keys - - def __iter__(self): - return self.items.__iter__() - - def __getitem__(self, i): - try: - return self.items[i] - except: - # it's likely the element did not exist, which hopefully means 0? - class _tmp: - rate = 0 - value = 0 - - return _tmp() - - def __str__(self): - x = '; '.join(f'({self[i].value}, {self[i].rate})' for i in self) - return f'Param({self.name}): {x}' - - __repr__ = __str__ - - def as_ampl(self, comment=''): - pindex = self.param.index_set() - if comment: - comment = '# Decision: %s\n\n' % str(comment) - - keys = self.skeys() - if isinstance(keys, str): - keys = [keys] - - # Together, these functions return the length of a printed version of a - # number, in characters. They are used to make columns of data line up so - # one may have an easier time getting an overall sense of a data file. - def get_int_padding(v): - return len(str(int(v))) - - def get_str_padding(index): - def anonymous_function(obj): - val = obj[index] - return len(str(val)) - - return anonymous_function - - keys = tuple(tuple(i.split()) for i in keys) - vals = tuple(self[i].value for i in self.my_keys) - int_padding = max(map(get_int_padding, vals)) - str_padding = [max(map(get_str_padding(i), keys)) for i in range(len(keys[0]))] - str_format = ' %-{}s' * len(self.model_keys[0]) - str_format = str_format.format(*str_padding) - - format = '\n%%s %%%ds%%s' % int_padding - # works out to something like '\n %s %8d%-6s' - # index { val } - - data = StringIO() - data.write(comment + 'param %s :=' % self.name) - for actual_key, this_key in sorted(zip(self.model_keys, self.my_keys)): - v = self[this_key].value - int_part = str(int(abs(v))) - if int_part != str(abs(v)): - dec_part = str(abs(v))[len(int_part) :] - else: - dec_part = '' - - if v < 0: - int_part = '-%d' % int_part - index = str_format % tuple(actual_key) - data.write(format % (index, int_part, dec_part)) - data.write('\n\t;\n') - - # return comment + data - return data.getvalue() - - -class TreeNode: - __slots__ = ('name', 'spoint', 'prob', 'params', 'bname', 'children') - - def __init__(self, *args, **kwargs): - # At the point someone is using this class, they probably know what - # they're doing, so intentionally die at this point if any of these - # items are not passed. They're all mandatory. - self.name = kwargs.pop('name') # name of /this/ node - self.spoint = kwargs.pop('spoint') # stochastic point of node - self.prob = kwargs.pop('prob') # conditional probability of node - bname = kwargs.pop('filebase') # file name minus extension - types = kwargs.pop('types') # names of decisions - rates = kwargs.pop('rates') # rates at which to vary - sindices = kwargs.pop('stochastic_indices') - - params = rates.keys() - myparams = dict() - for key, decisions in rates.items(): - paramkwargs = { - 'param': key, - 'rates': (), - 'spoint': self.spoint, - 'stochastic_index': sindices[key], - } - if self.prob < 1: - paramkwargs.update({'rates': decisions[self.name]}) - - myparams[key] = Param(**paramkwargs) - - self.params = myparams - self.bname = bname - self.children = [] - - def addChild(self, node): - self.children.append(node) - - def __repr__(self): - x = self.name - if isinstance(self.name, tuple): - x = ', '.join(x) - return f'{self.spoint}({x}): ' + ', '.join(str(i) for i in self.params.values()) - - def __str__(self, indent=' ', space=''): - x = ''.join(i.__str__(indent, space + indent) for i in self.children) - - return space + repr(self) + '\n' + x - - def write_dat_files(self): - global node_count - - # Step 1: Write my own file, if necessary - if self.prob < 1: - params = self.params.values() - data = params[0].as_ampl(self.name) - if len(params) > 1: - data += '\n' + '\n'.join(p.as_ampl() for p in params[1:]) - else: - data = '# Decision: HedgingStrategy (no change from R.dat)\n' - - with open(self.bname + '.dat', 'w') as f: - f.write(data) - - node_count += 1 - inform('\b' * (len(str(node_count - 1)) + 1) + str(node_count) + ' ') - - # Step 2: Tell my children to write their files - for c in self.children: - for p in self.params: - cp = c.params[p] - for key in self.params[p]: - cp[key].value = self.params[p][key].value * cp[key].rate - c.write_dat_files() - - def get_scenario_data(self): - nodes = [self.bname] - nodestage = [(self.bname, 's' + str(self.spoint))] - probability = [(self.bname, self.prob)] - scenarios = [] - children = [] - - if not self.children: - scenarios = [self.bname[2:]] - else: - children = [(self.bname, [c.bname for c in self.children])] - - for child in self.children: - s, n, ns, c, p = child.get_scenario_data() - scenarios += s - nodes += n - nodestage += ns - children += c - probability += p - - return scenarios, nodes, nodestage, children, probability - - -def write_scenario_file(stochasticset, tree): - ( - scenarios, - nodes, - nodestage, - children, - probability, - ) = tree.get_scenario_data() - - child_fmt = 'set children[%s] :=\n %s\n\t;\n' - scenario_fmt = 'S%(i)s Rs%(i)s' - stages_fmt = 'set stage_variables[s{}] :=\n {}\n\t;' - stagecost_fmt = 's%s StochasticPointCost[%s]' - - leaves = '\n '.join(scenario_fmt % {'i': i} for i in scenarios) - nodes = '\n '.join(nodes) - nodestage = '\n '.join(' '.join(ns) for ns in nodestage) - scenarios = 'S%s' % '\n S'.join(scenarios) - stagecost = '\n '.join(stagecost_fmt % (s, s) for s in stochasticset) - stages = '\n s'.join(str(se) for se in stochasticset) - - probability = '\n '.join(' '.join(str(i) for i in p) for p in probability) - children = '\n'.join(child_fmt % (c[0], '\n '.join(c[1])) for c in children) - - # XXX: Absolute hack, that currently only works for Temoa models. I have - # not yet thought about how to make this generic. Can it be done? - - stage_var_sets = list() - for se in stochasticset: # se = "stochastic element" - flow_keys = [index for index in instance.v_flow_out.keys() if index[0] == se] - processes = [(t, v) for p, s, d, i, t, v, o in flow_keys if v == se] - - stage_vars = list() - stage_vars.extend( - sorted({'v_flow_in[{},{},{},{},{},{},{}]'.format(*index) for index in flow_keys}) - ) - stage_vars.extend( - sorted({'v_flow_out[{},{},{},{},{},{},{}]'.format(*index) for index in flow_keys}) - ) - stage_vars.extend(sorted({'v_capacity[{},{}]'.format(*index) for index in processes})) - - stage_var_sets.append(stages_fmt.format(se, '\n '.join(stage_vars))) - - stage_var_sets = '\n\n'.join(stage_var_sets) - - structure = """\ -set stages := - s%(stages)s - ; - -set scenarios := - %(scenarios)s - ; - -set nodes := - %(nodes)s - ; - -%(children_sets)s - -%(stage_var_sets)s - -param node_stage := - %(nodestage)s - ; - -param conditional_probability := - %(cond_prob)s - ; - -param scenario_leaf_node := - %(leaves)s - ; - -param stage_cost_variable := - %(stagecost)s - ; - -param scenario_based_data := False ; -""" - - structure %= dict( - stages=stages, - scenarios=scenarios, - nodes=nodes, - children_sets=children, - stage_var_sets=stage_var_sets, - nodestage=nodestage, - cond_prob=probability, - leaves=leaves, - stagecost=stagecost, - ) - - with open('ScenarioStructure.dat', 'w') as f: - f.write(structure) - - -def _create_tree(stochasticset, spoints, **kwargs): - name = kwargs.get('name') - bname = kwargs.get('bname') - prob = kwargs.get('prob') - cprob = kwargs.get('cprob') - decision_list = kwargs.get('decisions') - - try: - spoint = stochasticset.pop() # stochastic point, use of pop implies ordering - except: - SE.write( - '\nError: mismatch in specified stochastic set. Does ' - 'stochastic_points match the dat file?' - ) - raise - - treekwargs = dict( - spoint=spoint, - name=name, - types=kwargs.get('types'), - rates=kwargs.get('rates'), - filebase=bname, - prob=prob, - stochastic_indices=kwargs.get('stochastic_indices'), - ) - - node = TreeNode(**treekwargs) - global node_count - node_count += 1 - inform('\b' * (len(str(node_count - 1)) + 1) + str(node_count) + ' ') - - if spoint not in spoints: - kwargs.update( - name='HedgingStrategy', - bname='%ss0' % bname, - prob=1, - ) - node.addChild(_create_tree(stochasticset[:], spoints, **kwargs)) - elif stochasticset: - decisions = enumerate(decision_list) - bname = '%ss%%d' % bname # the format for the basename of the file - for enum, d in decisions: - kwargs.update( - name=d, - bname=bname % enum, - prob=cprob[d], - ) - node.addChild(_create_tree(stochasticset[:], spoints, **kwargs)) - - return node - - -def create_tree(stochasticset, spoints, opts): - types = opts.types - rates = opts.rates - cprob = opts.conditional_probability - - stochasticset.reverse() - spoints.sort() - spoints.reverse() - - kwargs = dict( - name='Root', - bname='R', - types=types, - rates=rates, - cprob=cprob, - decisions=types, - stochastic_indices=opts.stochastic_indices, - prob=1, # conditional probability, but root guaranteed to occur - ) - return _create_tree(stochasticset, spoints, **kwargs) - - -def inform(x): - global verbose - if verbose: - SE.write(x) - SE.flush() - - -def setup_directory(dname, force): - if os.path.exists(dname): - if os.path.isdir(dname): - files = os.listdir(dname) - if files and not force: - msg = ( - 'Not empty: {}\n\nIf you want to use this directory anyway, ' - "set 'force = True' in the options.py file." - ) - raise Warning(msg.format(dname)) - - # would be potentially useful to put this into a thread to speed up - # the process. like 'mv somedir to_del; rm -rf to_del &' - rmtree(dname) - os.mkdir(dname) - else: - msg = 'Error - already exists: {}' - raise NameError(msg.format(dname)) - else: - os.mkdir(dname) - - -def test_model_parameters(M, opts): - try: - getattr(M, opts.stochasticset) - except: - msg = ( - 'Whoops! The stochastic set is not available from the model. ' - 'Did you perhaps typo the name?\n' - ' Model name: {}\n' - ' Stochastic name: {}' - ) - raise ValueError(msg.format(M.name, opts.stochasticset)) - - try: - for pname in opts.rates: - param = getattr(M, pname) - except: - msg = ( - 'Whoops! Parameter not available from the model. Have you ' - 'perhaps typoed the name?\n' - ' Model name: {}\n' - ' Parameter name: {}' - ) - raise ValueError(msg.format(M.name, pname)) - - -def usage(): - SE.write( - """ -synopsis: pyomo_python {0} - -Example: pyomo_python {0} options/utopia_coal_vs_nuc.py - -For information about the options_to_import.py file, please see -options/README.txt -""".format(sys.argv[0]) - ) - - raise SystemExit - - -def main(): - from os import getcwd - from os.path import abspath, basename, dirname - from time import clock - - if len(sys.argv) < 2: - usage() - module_name = sys.argv[1][:-3].replace('/', '.') # remove the '.py' - - mbase = basename(module_name)[:-3] - mdir = abspath(dirname(module_name)) - sys.path.insert(0, mdir) - - try: - __import__(module_name) - opts = sys.modules[module_name] - sys.path.pop(0) - - except ImportError: - msg = 'Unable to import {}.\n\nRun this script with no arguments for more information.\n' - SE.write(msg.format(sys.argv[1])) - raise - - try: - opts.dirname - except AttributeError: - opts.dirname = module_name.split('.')[-1] - - global verbose - verbose = opts.verbose - - cwd = getcwd() - - begin = clock() - duration = lambda: clock() - begin - - inform('[ ] Setting up working directory (%s)' % opts.dirname) - setup_directory(opts.dirname, opts.force) - inform('\r[%6.2f\n' % duration()) - - inform('[ ] Import model definition (%s)' % opts.modelpath) - mp = opts.modelpath - modelbase = basename(mp)[:-3] - modeldir = abspath(dirname(mp)) - - sys.path.insert(0, modeldir) - _temp = __import__(modelbase, globals(), locals(), ('model',)) - M = _temp.model - del _temp - sys.path.pop(0) - - test_model_parameters(M, opts) - - inform('\r[%6.2f\n' % duration()) - - inform('[ ] Create concrete instance (%s)' % opts.dotdatpath) - ins = M.create(opts.dotdatpath) - inform('\r[%6.2f\n' % duration()) - - global instance - instance = ins - - inform('[ ] Collecting stochastic points from model (%s)' % M.name) - all_spoints = sorted(getattr(ins, opts.stochasticset).value) - try: - spoints = list(opts.stochastic_points) - except AttributeError: - spoints = all_spoints - - inform('\r[%6.2f\n' % duration()) - - # used for friendlier error checking - Param.stochasticset = opts.stochasticset - - os.chdir(opts.dirname) - inform('[ ] Building tree: ') - tree = create_tree(all_spoints[:], spoints[:], opts) # give an intentional copy - inform('\r[%6.2f\n' % duration()) - - global node_count - node_count = 0 - - inform('[ ] Writing scenario "dot dat" files: ') - tree.write_dat_files() - write_scenario_file(all_spoints, tree) - inform('\r[%6.2f] Writing scenario "dot dat" files\n' % duration()) - - os.chdir(cwd) - inform('[ ] Copying ReferenceModel.dat as scenario tree root') - copyfile(opts.dotdatpath, '%s/ReferenceModel.dat' % opts.dirname) - copyfile(opts.dotdatpath, '%s/R.dat' % opts.dirname) - inform('\r[%6.2f\n' % duration()) - - -if '__main__' == __name__: - try: - main() - except Exception as e: - if '--debug' in sys.argv: - raise - - msg = ( - '\n\nIf you need more verbose (potentially helpful) information ' - 'about this error, you can run this program again, and add the' - ' "--debug" command line flag.\n' - ) - msg = '\n\n' + str(e) + msg - SE.write(msg) diff --git a/temoa/extensions/stochastics/jobTemoa.pbs b/temoa/extensions/stochastics/jobTemoa.pbs deleted file mode 100644 index dfd5907c0..000000000 --- a/temoa/extensions/stochastics/jobTemoa.pbs +++ /dev/null @@ -1,61 +0,0 @@ -#! /bin/bash - -# This is a simple job submission script that can be adapted for your needs. -# At the very least, change the name of the program (line 10), -# number of nodes requested (line 16) and -# wallclock time requested (line 19) and -# your program arguments (line 48) - -# Name of the program (used to produce standard output and error logs - Eg. test.o### ) -#PBS -N test -# Combine both error and output logs -#PBS -j oe - -# Change nodes as desired below -# ppn refers to processes per node which is usually equal to number of cores (32 in our case) -#PBS -l nodes=2:ppn=32 - -# Wall clock time limit in hh:mm:ss format -#PBS -l walltime=72:00:00 - -# Available queues are short (5 min), low, medium and high priority. -# medium is appropriate for most users -#PBS -q long - -# If you wish to export environment variables, use both lines below -#PBS -V -# Just note that HYDRA_HOST_FILE shouldn't be set in this environment -unset HYDRA_HOST_FILE - -# If you wish to receive email, update email and -# remove first '#' from line below -# #PBS -M username@ncsu.edu - # a mail is sent when the job is aborted by the batch system. - # b mail is sent when the job begins execution. - # e mail is sent when the job terminates. -#PBS -m abe - -# Change to the program's directory -cd /home/arqueiroz/temoa/stochastic/usdatabase_64n -echo "Directory: $PBS_O_WORKDIR" -date -echo "Number of nodes is ${PBS_NUM_NODES}" -echo "Number of cores is ${PBS_NP}" -# If you wish to print the nodes on which your program ran, uncomment line below -# cat $PBS_NODEFILE - -# TODO: Replace cpi with your program and arguments -#mpiexec -n $PBS_NP -machinefile $PBS_NODEFILE ./cpi -export PYRO_NS_PORT=9096 -#mpiexec -n $PBS_NP -machinefile $PBS_NODEFILE \ -#-np 1 /home/arqueiroz/anaconda2/bin/pyomo_ns : \ -#-np 1 /home/arqueiroz/anaconda2/bin/dispatch_srvr : \ -#-np 3 /home/arqueiroz/anaconda2/bin/phsolverserver : \ -#-np 1 /home/arqueiroz/anaconda2/bin/runph --solver=cplex --solver-manager=phpyro --shutdown-pyro -m models -i scenariodata --default-rho=1.0 -mpiexec -np 1 /home/arqueiroz/anaconda2/bin/pyomo_ns -n localhost : -np 1 /home/arqueiroz/anaconda2/bin/dispatch_srvr localhost : -np 3 /home/arqueiroz/anaconda2/bin/phsolverserver : -np 1 /home/arqueiroz/anaconda2/bin/runph --solver=cplex --solver-manager=phpyro --shutdown-pyro --traceback -m ../../temoa_model/ -i ./ --default-rho=1 - -# mpiexec can detect number of available cores by default -# So above is equivalent to line below. But use the detailed version above, as that -# explicitly identifies number of cores etc. -# mpiexec ./cpi - diff --git a/temoa/extensions/stochastics/legacy_files/ef_writer_script_old.py b/temoa/extensions/stochastics/legacy_files/ef_writer_script_old.py deleted file mode 100644 index bf867c475..000000000 --- a/temoa/extensions/stochastics/legacy_files/ef_writer_script_old.py +++ /dev/null @@ -1,759 +0,0 @@ -# _________________________________________________________________________ -# -# Pyomo: Python Optimization Modeling Objects -# Copyright (c) 2014 Sandia Corporation. -# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, -# the U.S. Government retains certain rights in this software. -# This software is distributed under the BSD License. -# _________________________________________________________________________ - -import os -import random -import sys -import time -from optparse import OptionParser, OptionGroup - -import pyutilib.misc -from pyomo.core.base import maximize, minimize -from pyomo.opt.base import SolverFactory, PersistentSolver, ProblemFormat -from pyomo.opt.base.solvers import UnknownSolver -from pyomo.opt.parallel import SolverManagerFactory -from pyomo.pysp.ef import write_ef, create_ef_instance -from pyomo.pysp.scenariotree.instance_factory import ScenarioTreeInstanceFactory -from pyomo.pysp.solutionwriter import ISolutionWriterExtension -from pyomo.pysp.util.misc import launch_command -from pyomo.util import pyomo_command -from pyomo.util.plugin import ExtensionPoint -from pyutilib.pyro import shutdown_pyro_components - - -# -# utility method to construct an option parser for ef writer arguments -# - - -def construct_ef_writer_options_parser(usage_string): - solver_list = SolverFactory.services() - solver_list = sorted(filter(lambda x: '_' != x[0], solver_list)) - solver_help = ( - 'Specify the solver with which to solve the extensive form. The ' - 'following solver types are currently supported: %s; Default: cplex' - ) - solver_help %= ', '.join(solver_list) - - parser = OptionParser() - parser.usage = usage_string - - inputOpts = OptionGroup(parser, 'Input Options') - scenarioTreeOpts = OptionGroup(parser, 'Scenario Tree Options') - efOpts = OptionGroup(parser, 'EF Options') - ccOpts = OptionGroup(parser, 'Chance Constraint Options') - solverOpts = OptionGroup(parser, 'Solver Options') - outputOpts = OptionGroup(parser, 'Output Options') - otherOpts = OptionGroup(parser, 'Other Options') - parser.add_option_group(inputOpts) - parser.add_option_group(scenarioTreeOpts) - parser.add_option_group(efOpts) - parser.add_option_group(ccOpts) - parser.add_option_group(solverOpts) - parser.add_option_group(outputOpts) - parser.add_option_group(otherOpts) - - inputOpts.add_option( - '-i', - '--instance-directory', - help='The directory in which all instance (reference and scenario) definitions are stored. This option is required if no callback is found in the model file.', - action='store', - dest='instance_directory', - type='string', - default=None, - ) - inputOpts.add_option( - '-m', - '--model-directory', - help='The directory in which all model (reference and scenario) definitions are stored. Default is ".".', - action='store', - dest='model_directory', - type='string', - default='.', - ) - - def objective_sense_callback(option, opt_str, value, parser): - if value in ('min', 'minimize', minimize): - parser.values.objective_sense = minimize - elif value in ('max', 'maximize', maximize): - parser.values.objective_sense = maximize - else: - parser.values.objective_sense = None - - inputOpts.add_option( - '-o', - '--objective-sense-stage-based', - help='The objective sense to use for the auto-generated scenario instance objective, which is equal to the ' - 'sum of the scenario-tree stage costs. Default is None, indicating an Objective has been declared on the ' - 'reference model.', - action='callback', - dest='objective_sense', - type='choice', - choices=[maximize, 'max', 'maximize', minimize, 'min', 'minimize', None], - default=None, - callback=objective_sense_callback, - ) - - scenarioTreeOpts.add_option( - '--scenario-tree-seed', - help='The random seed associated with manipulation operations on the scenario tree (e.g., down-sampling). Default is None, indicating unassigned.', - action='store', - dest='scenario_tree_random_seed', - type='int', - default=random.getrandbits(100), - ) - scenarioTreeOpts.add_option( - '--scenario-tree-downsample-fraction', - help='The proportion of the scenarios in the scenario tree that are actually used. Specific scenarios are selected at random. Default is 1.0, indicating no down-sampling.', - action='store', - dest='scenario_tree_downsample_fraction', - type='float', - default=1.0, - ) - - efOpts.add_option( - '--cvar-weight', - help='The weight associated with the CVaR term in the risk-weighted objective formulation. Default is 1.0. If the weight is 0, then *only* a non-weighted CVaR cost will appear in the EF objective - the expected cost component will be dropped.', - action='store', - dest='cvar_weight', - type='float', - default=1.0, - ) - efOpts.add_option( - '--generate-weighted-cvar', - help='Add a weighted CVaR term to the primary objective', - action='store_true', - dest='generate_weighted_cvar', - default=False, - ) - efOpts.add_option( - '--risk-alpha', - help='The probability threshold associated with cvar (or any future) risk-oriented performance metrics. Default is 0.95.', - action='store', - dest='risk_alpha', - type='float', - default=0.95, - ) - - ccOpts.add_option( - '--cc-alpha', - help='The probability threshold associated with a chance constraint. The RHS will be one minus this value. Default is 0.', - action='store', - dest='cc_alpha', - type='float', - default=0.0, - ) - - ccOpts.add_option( - '--cc-indicator-var', - help='The name of the binary variable to be used to construct a chance constraint. Default is None, which indicates no chance constraint.', - action='store', - dest='cc_indicator_var', - type='string', - default=None, - ) - - solverOpts.add_option( - '--mipgap', - help='Specifies the mipgap for the EF solve.', - action='store', - dest='mipgap', - type='float', - default=None, - ) - solverOpts.add_option( - '--solve', - help='Following write of the extensive form model, solve it.', - action='store_true', - dest='solve_ef', - default=False, - ) - solverOpts.add_option( - '--solver', - help=solver_help, - action='store', - dest='solver_type', - type='string', - default='cplex', - ) - solverOpts.add_option( - '--solver-io', - help='The type of IO used to execute the solver. Different solvers support different types of IO, but the following are common options: lp - generate LP files, nl - generate NL files, python - direct Python interface, os - generate OSiL XML files.', - action='store', - dest='solver_io', - default=None, - ) - solverOpts.add_option( - '--solver-manager', - help='The type of solver manager used to coordinate scenario sub-problem solves. Default is serial.', - action='store', - dest='solver_manager_type', - type='string', - default='serial', - ) - solverOpts.add_option( - '--pyro-host', - help='The hostname to bind on when searching for a Pyro nameserver.', - action='store', - dest='pyro_host', - default=None, - ) - solverOpts.add_option( - '--pyro-port', - help='The port to bind on when searching for a Pyro nameserver.', - action='store', - dest='pyro_port', - type='int', - default=None, - ) - solverOpts.add_option( - '--solver-options', - help='Solver options for the extensive form problem.', - action='append', - dest='solver_options', - type='string', - default=[], - ) - solverOpts.add_option( - '--disable-warmstarts', - help='Disable warm-starts of EF solves. Default is False.', - action='store_true', - dest='disable_warmstarts', - default=False, - ) - solverOpts.add_option( - '--shutdown-pyro', - help='Shut down all Pyro-related components associated with the Pyro solver manager (if specified), including the dispatch server, name server, and any mip servers. Default is False.', - action='store_true', - dest='shutdown_pyro', - default=False, - ) - solverOpts.add_option( - '--shutdown-pyro-workers', - help='Shut down PH solver servers on exit, leaving dispatcher and nameserver running. Default is False.', - action='store_true', - dest='shutdown_pyro_workers', - default=False, - ) - - outputOpts.add_option( - '--output-file', - help="The name of the extensive form output file (currently only LP and NL file formats are supported). If the option name does not end in '.lp' or '.nl', then the output format will be determined by the value of the --solver-io option, and the appropriate ending suffix will be added to the name. Default is 'efout'.", - action='store', - dest='output_file', - type='string', - default='efout', - ) - outputOpts.add_option( - '--symbolic-solver-labels', - help='When interfacing with the solver, use symbol names derived from the model. For example, "my_special_variable[1_2_3]" instead of "v1". Useful for debugging. When using the ASL interface (--solver-io=nl), generates corresponding .row (constraints) and .col (variables) files. The ordering in these files provides a mapping from ASL index to symbolic model names.', - action='store_true', - dest='symbolic_solver_labels', - default=False, - ) - outputOpts.add_option( - '--output-solver-log', - help='Output solver log during the extensive form solve.', - action='store_true', - dest='output_solver_log', - default=False, - ) - outputOpts.add_option( - '--solution-writer', - help='The plugin invoked to write the scenario tree solution. Defaults to the empty list.', - action='append', - dest='solution_writer', - type='string', - default=[], - ) - outputOpts.add_option( - '--verbose', - help='Generate verbose output, beyond the usual status output. Default is False.', - action='store_true', - dest='verbose', - default=False, - ) - outputOpts.add_option( - '--output-times', - help='Output timing statistics for various EF components', - action='store_true', - dest='output_times', - default=False, - ) - outputOpts.add_option( - '--output-instance-construction-time', - help='Output timing statistics for instance construction (client-side only when using PHPyro', - action='store_true', - dest='output_instance_construction_time', - default=False, - ) - otherOpts.add_option( - '--disable-gc', - help='Disable the python garbage collecter. Default is False.', - action='store_true', - dest='disable_gc', - default=False, - ) - otherOpts.add_option( - '-k', - '--keep-solver-files', - help='Retain temporary input and output files for solve.', - action='store_true', - dest='keep_solver_files', - default=False, - ) - otherOpts.add_option( - '--profile', - help='Enable profiling of Python code. The value of this option is the number of functions that are summarized.', - action='store', - dest='profile', - type='int', - default=0, - ) - otherOpts.add_option( - '--traceback', - help='When an exception is thrown, show the entire call stack. Ignored if profiling is enabled. Default is False.', - action='store_true', - dest='traceback', - default=False, - ) - otherOpts.add_option( - '--compile-scenario-instances', - help='Replace all linear constraints on scenario instances with a more memory efficient sparse matrix representation. Default is False.', - action='store_true', - dest='compile_scenario_instances', - default=False, - ) - - return parser - - -def EF_DefaultOptions(): - parser = construct_ef_writer_options_parser('') - options, _ = parser.parse_args(['']) - return options - - -def GenerateScenarioTreeForEF(options, scenario_instance_factory, include_scenarios=None): - try: - scenario_tree = scenario_instance_factory.generate_scenario_tree( - include_scenarios=include_scenarios, - downsample_fraction=options.scenario_tree_downsample_fraction, - random_seed=options.scenario_tree_random_seed, - ) - - # - # print the input tree for validation/information purposes. - # - if options.verbose: - scenario_tree.pprint() - - # - # validate the tree prior to doing anything serious - # - if not scenario_tree.validate(): - raise RuntimeError('Scenario tree is invalid') - else: - if options.verbose: - print('Scenario tree is valid!') - - start_time = time.time() - - print('Constructing scenario tree instances') - instance_dictionary = scenario_instance_factory.construct_instances_for_scenario_tree( - scenario_tree, - output_instance_construction_time=options.output_instance_construction_time, - compile_scenario_instances=options.compile_scenario_instances, - ) - - if options.verbose or options.output_times: - print('Time to construct scenario instances=%.2f seconds' % (time.time() - start_time)) - - print('Linking instances into scenario tree') - start_time = time.time() - - # with the scenario instances now available, link the - # referenced objects directly into the scenario tree. - scenario_tree.linkInInstances( - instance_dictionary, objective_sense=options.objective_sense, create_variable_ids=True - ) - - if options.output_times: - print( - 'Time link scenario tree with instances=%.2f seconds' % (time.time() - start_time) - ) - - except: - if scenario_instance_factory is not None: - scenario_instance_factory.close() - print('Failed to initialize model and/or scenario tree data') - raise - - return scenario_tree - - -def CreateExtensiveFormInstance(options, scenario_tree): - start_time = time.time() - print('Creating extensive form instance') - - # then validate the associated parameters. - generate_weighted_cvar = False - cvar_weight = None - risk_alpha = None - if options.generate_weighted_cvar is True: - generate_weighted_cvar = True - cvar_weight = options.cvar_weight - risk_alpha = options.risk_alpha - - binding_instance = create_ef_instance( - scenario_tree, - verbose_output=options.verbose, - generate_weighted_cvar=generate_weighted_cvar, - cvar_weight=cvar_weight, - risk_alpha=risk_alpha, - cc_indicator_var_name=options.cc_indicator_var, - cc_alpha=options.cc_alpha, - ) - - if options.verbose or options.output_times: - print('Time to construct extensive form instance=%.2f seconds' % (time.time() - start_time)) - - return binding_instance - - -class ExtensiveFormAlgorithm: - def __init__( - self, - options, - binding_instance, - scenario_tree, - solver_manager, - solver, - solution_plugins=None, - ): - self._options = options - self._binding_instance = binding_instance - self._scenario_tree = scenario_tree - self._solver_manager = solver_manager - self._solver = solver - self._solution_plugins = solution_plugins - - def write(self): - start_time = time.time() - - output_filename = os.path.expanduser(self._options.output_file) - suf = os.path.splitext(output_filename)[1] - if suf not in ['.nl', '.lp']: - if self._solver.problem_format() == ProblemFormat.cpxlp: - output_filename += '.lp' - elif self._solver.problem_format() == ProblemFormat.nl: - output_filename += '.nl' - else: - raise ValueError( - 'Could not determine output file format. ' - 'No recognized ending suffix was provided ' - 'and no format was indicated was by the ' - '--solver-io option.' - ) - - start_time = time.time() - if self._options.verbose: - print('Starting to write extensive form') - - symbol_map = write_ef( - self._binding_instance, output_filename, self._options.symbolic_solver_labels - ) - - print('Extensive form written to file=' + output_filename) - if self._options.verbose or self._options.output_times: - print('Time to write output file=%.2f seconds' % (time.time() - start_time)) - - return output_filename, symbol_map - - def solve(self): - start_time = time.time() - print('Queuing extensive form solve') - - if isinstance(self._solver, PersistentSolver): - self._solver.compile_instance( - self._binding_instance, symbolic_solver_labels=self._options.symbolic_solver_labels - ) - - solve_kwds = {} - solve_kwds['load_solutions'] = False - if self._options.keep_solver_files: - solve_kwds['keepfiles'] = True - if self._options.symbolic_solver_labels: - solve_kwds['symbolic_solver_labels'] = True - if self._options.output_solver_log: - solve_kwds['tee'] = True - - if (not self._options.disable_warmstarts) and (self._solver.warm_start_capable()): - action_handle = self._solver_manager.queue( - self._binding_instance, opt=self._solver, warmstart=True, **solve_kwds - ) - else: - action_handle = self._solver_manager.queue( - self._binding_instance, opt=self._solver, **solve_kwds - ) - print('Waiting for extensive form solve') - results = self._solver_manager.wait_for(action_handle) - - if len(results.solution) == 0: - results.write() - raise RuntimeError('Solve failed; no solutions generated') - - print('Done with extensive form solve - loading results') - self._binding_instance.solutions.load_from(results) - - print('Storing solution in scenario tree') - self._scenario_tree.pullScenarioSolutionsFromInstances() - self._scenario_tree.snapshotSolutionFromscenarios() - # TODO - # self._scenario_tree.update_variable_statistics() - - if self._options.verbose or self._options.output_times: - print( - 'Time to solve and load results for the ' - 'extensive form=%.2f seconds' % (time.time() - start_time) - ) - - # print *the* metric of interest. - root_node = self._scenario_tree._stages[0]._tree_nodes[0] - print('') - print( - '********************************' - '********************************' - '*******************************' - ) - print( - '>>>THE EXPECTED SUM OF THE STAGE COST VARIABLES=' - + str(root_node.computeExpectedNodeCost()) - + '<<<' - ) - print( - '********************************' - '********************************' - '*******************************' - ) - - # handle output of solution from the scenario tree. - print('') - print('Extensive form solution:') - self._scenario_tree.pprintSolution() - print('') - print('Extensive form costs:') - self._scenario_tree.pprintCosts() - - def save_solution(self, label='ef'): - if self._solution_plugins is not None: - for plugin in self._solution_plugins: - plugin.write(self._scenario_tree, label) - - -def EFAlgorithmBuilder(options, scenario_tree): - solution_writer_plugins = ExtensionPoint(ISolutionWriterExtension) - for plugin in solution_writer_plugins: - plugin.disable() - - solution_plugins = [] - if len(options.solution_writer) > 0: - for this_extension in options.solution_writer: - if this_extension in sys.modules: - print( - 'User-defined EF solution writer module=' - + this_extension - + ' already imported - skipping' - ) - else: - print( - 'Trying to import user-defined EF ' 'solution writer module=' + this_extension - ) - # make sure "." is in the PATH. - original_path = list(sys.path) - sys.path.insert(0, '.') - pyutilib.misc.import_file(this_extension) - print('Module successfully loaded') - sys.path[:] = original_path # restore to what it was - - # now that we're sure the module is loaded, re-enable this - # specific plugin. recall that all plugins are disabled - # by default in phinit.py, for various reasons. if we want - # them to be picked up, we need to enable them explicitly. - import inspect - - module_to_find = this_extension - if module_to_find.rfind('.py'): - module_to_find = module_to_find.rstrip('.py') - if module_to_find.find('/') != -1: - module_to_find = module_to_find.split('/')[-1] - - for name, obj in inspect.getmembers(sys.modules[module_to_find], inspect.isclass): - import pyomo.util - - # the second condition gets around goofyness related to issubclass returning - # True when the obj is the same as the test class. - if issubclass(obj, pyomo.util.plugin.SingletonPlugin) and name != 'SingletonPlugin': - for plugin in solution_writer_plugins(all=True): - if isinstance(plugin, obj): - plugin.enable() - solution_plugins.append(plugin) - - ef_solver = SolverFactory(options.solver_type, solver_io=options.solver_io) - if isinstance(ef_solver, UnknownSolver): - raise ValueError( - 'Failed to create solver of type=' - + options.solver_type - + ' for use in extensive form solve' - ) - if len(options.worker_solver_options) > 0: - print('Initializing ef solver with options=' + str(options.worker_solver_options)) - ef_solver.set_options(''.join(options.worker_solver_options)) - if options.mipgap is not None: - if (options.mipgap < 0.0) or (options.mipgap > 1.0): - raise ValueError( - 'Value of the mipgap parameter for the EF ' - 'solve must be on the unit interval; ' - 'value specified=' + str(options.mipgap) - ) - ef_solver.options.mipgap = float(options.mipgap) - - ef_solver_manager = SolverManagerFactory( - options.solver_manager_type, host=options.pyro_host, port=options.pyro_port - ) - if ef_solver_manager is None: - raise ValueError( - 'Failed to create solver manager of type=' - + options.solver_type - + ' for use in extensive form solve' - ) - - binding_instance = CreateExtensiveFormInstance(options, scenario_tree) - - ef = ExtensiveFormAlgorithm( - options, - binding_instance, - scenario_tree, - ef_solver_manager, - ef_solver, - solution_plugins=solution_plugins, - ) - - return ef - - -def run_ef(options, ef): - if options.solve_ef: - retval = ef.solve() - ef.save_solution() - else: - retval = ef.write() - - return retval - - -def exec_runef(options): - import pyomo.solvers.plugins.smanager.phpyro - import pyomo.solvers.plugins.smanager.pyro - - start_time = time.time() - - if options.verbose: - print('Importing model and scenario tree files') - - scenario_instance_factory = ScenarioTreeInstanceFactory( - options.model_directory, options.instance_directory, options.verbose - ) - - if options.output_times: - print( - 'Time to import model and scenario tree structure files=%.2f seconds' - % (time.time() - start_time) - ) - - ef = None - try: - scenario_tree = GenerateScenarioTreeForEF(options, scenario_instance_factory) - - ef = EFAlgorithmBuilder(options, scenario_tree) - - run_ef(options, ef) - - finally: - if ef is not None: - if ef._solver_manager is not None: - if isinstance( - ef._solver_manager, pyomo.solvers.plugins.smanager.phpyro.SolverManager_PHPyro - ): - ef._solver_manager.release_servers(shutdown=option.shutdown_pyro_workers) - if isinstance( - ef._solver_manager, pyomo.solvers.plugins.smanager.pyro.SolverManager_Pyro - ): - if options.shutdown_pyro_workers: - ef._solver_manager.shutdown_workers() - ef._solver_manager.deactivate() - if ef._solver is not None: - ef._solver.deactivate() - - if ( - isinstance( - ef._solver_manager, pyomo.solvers.plugins.smanager.pyro.SolverManager_Pyro - ) - or isinstance( - ef._solver_manager, pyomo.solvers.plugins.smanager.phpyro.SolverManager_PHPyro - ) - ) and (options.shutdown_pyro): - print('Shutting down Pyro solver components') - shutdown_pyro_components( - host=options.pyro_host, port=options.pyro_port, num_retries=0 - ) - - if scenario_instance_factory is not None: - scenario_instance_factory.close() - - print('') - print('Total EF execution time=%.2f seconds' % (time.time() - start_time)) - print('') - - return 0 - - -def main(args=None): - # - # Top-level command that executes the runef command - # - - # - # Import plugins - # - - # - # Parse command-line options. - # - try: - options_parser = construct_ef_writer_options_parser('runef [options]') - (options, args) = options_parser.parse_args(args=args) - except SystemExit as _exc: - # the parser throws a system exit if "-h" is specified - # - catch it to exit gracefully. - return _exc.code - - return launch_command( - exec_runef, - options, - error_label='runef: ', - disable_gc=options.disable_gc, - profile_count=options.profile, - traceback=options.traceback, - ) - - -@pyomo_command('runef', 'Convert a SP tfo extensive form and optimize') -def EF_main(args=None): - return main(args=args) diff --git a/temoa/extensions/stochastics/legacy_files/scenariomodels.py b/temoa/extensions/stochastics/legacy_files/scenariomodels.py deleted file mode 100644 index 0432aec94..000000000 --- a/temoa/extensions/stochastics/legacy_files/scenariomodels.py +++ /dev/null @@ -1,64 +0,0 @@ -# grab the pyomo modeling components. -from pyomo.environ import * - -scenario_tree_model = AbstractModel() - -# all set/parameter values are strings, representing the names of various entities/variables. - -scenario_tree_model.stages = Set(ordered=True) -scenario_tree_model.nodes = Set() - -scenario_tree_model.node_stage = Param(scenario_tree_model.nodes, within=scenario_tree_model.stages) -scenario_tree_model.children = Set( - scenario_tree_model.nodes, within=scenario_tree_model.nodes, ordered=True -) -scenario_tree_model.conditional_probability = Param(scenario_tree_model.nodes) - -scenario_tree_model.scenarios = Set(ordered=True) -scenario_tree_model.scenario_leaf_node = Param( - scenario_tree_model.scenarios, within=scenario_tree_model.nodes -) - -scenario_tree_model.stage_variables = Set(scenario_tree_model.stages) -scenario_tree_model.stage_cost_variable = Param(scenario_tree_model.stages) - -# scenario data can be populated in one of two ways. the first is "scenario-based", -# in which a single .dat file contains all of the data for each scenario. the .dat -# file prefix must correspond to the scenario name. the second is "node-based", -# in which a single .dat file contains only the data for each node in the scenario -# tree. the node-based method is more compact, but the scenario-based method is -# often more natural when parameter data is generated via simulation. the default -# is scenario-based. -scenario_tree_model.scenario_based_data = Param(within=Boolean, default=True, mutable=True) - -# do we bundle, and if so, how? -scenario_tree_model.bundling = Param(within=Boolean, default=False, mutable=True) -scenario_tree_model.bundles = Set() # bundle names -scenario_tree_model.bundle_scenarios = Set(scenario_tree_model.bundles) - - -# scenario_tree_model = AbstractModel() - -## all set/parameter values are strings, representing the names of various entities/variables. - -# scenario_tree_model.stages = Set(ordered=True) -# scenario_tree_model.nodes = Set() - -# scenario_tree_model.node_stage = Param(scenario_tree_model.nodes, within=scenario_tree_model.stages) -# scenario_tree_model.children = Set(scenario_tree_model.nodes, within=scenario_tree_model.nodes, ordered=True) -# scenario_tree_model.conditional_probability = Param(scenario_tree_model.nodes) - -# scenario_tree_model.scenarios = Set(ordered=True) -# scenario_tree_model.scenario_leaf_node = Param(scenario_tree_model.scenarios, within=scenario_tree_model.nodes) - -# scenario_tree_model.stage_variables = Set(scenario_tree_model.stages) -# scenario_tree_model.stage_cost_variable = Param(scenario_tree_model.stages) - -## scenario data can be populated in one of two ways. the first is "scenario-based", -## in which a single .dat file contains all of the data for each scenario. the .dat -## file prefix must correspond to the scenario name. the second is "node-based", -## in which a single .dat file contains only the data for each node in the scenario -## tree. the node-based method is more compact, but the scenario-based method is -## often more natural when parameter data is generated via simulation. the default -## is scenario-based. -# scenario_tree_model.scenario_based_data = Param(within=Boolean, default=True) diff --git a/temoa/extensions/stochastics/options/README.txt b/temoa/extensions/stochastics/options/README.txt deleted file mode 100644 index 91452d716..000000000 --- a/temoa/extensions/stochastics/options/README.txt +++ /dev/null @@ -1,67 +0,0 @@ -Stochastic Temoa Tree Generation Options Files -============================================== - -The options.py files in this directory describe stochastic trees as implemented -by the generate_scenario_tree.py script in the parent directory. These files -serve as a command line input to that script, specifying various items necessary -to create a generic scenario tree stucture and input dot dat files. - -The options.py files in this directory will generally be imported via the -generate_scenario_tree.py script in the parent directory. The script then -expects to be able to access the below items via the imported file. - -If any of the below is not clear, the other files in this directory can serve as -examples. If you do not have the files, the Temoa repository contains them all -at http://svn.temoaproject.org/trac/. Check "Browse Source". At the time of -this writing, the files are located in - -branches/stochastic/options/ - -Elements an options.py Should Specify -===================================== - -(str) dirname (optional) - This directory will be where all output files are placed. If not specified, - the name of the options file will be used as the default. - -(bool) verbose - Should the script give information about it's progress? - -(bool) force - If the dirname already exists, remove it before proceeding? - -(path) modelpath - Relative or absolute path of where to find the model - -(path) dotdatpath - Relative or absolute path of where to find the base LP dat file. - -(str) stochasticset - Within the model, the name of the stochastic set that indexes the parameters - to be rate-modified. - -(tuple) stochastic_points - Within the model, specifically /which/ items in the stochastic set are the - stochastic ones? For the parameters specified in types and rates, the ones - indexed by these points will be modified. Note that for useful output, this - item, if specified, needs at least two stochastic points, and the first one - will have a conditional probability of 1. - -(dict) stochastic_indices - For each parameter to modify, the numerical order of its stochastic index. - This is a 0-based, numerical specification. - -(tuple of strings) types - Each item in this tuple is the name of a decision branch from a node. However - many items specified here, are the number of branches each node in the event - tree will have. - -(dict) conditional_probability - This dict specifies the conditional probability of each branch. - -(dict of dicts of tuples) rates - This is a two-level dict that specifies each parameter to modify, and for each - branch in types, what to multiply against each index. Indices can be - explicitly spelled-out, or specified in a group via an asterisk. - ------ \ No newline at end of file diff --git a/temoa/extensions/stochastics/options/__init__.py b/temoa/extensions/stochastics/options/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/temoa/extensions/stochastics/options/iew2012-nonhomogenized-markov.py b/temoa/extensions/stochastics/options/iew2012-nonhomogenized-markov.py deleted file mode 100644 index 3fdfd16c8..000000000 --- a/temoa/extensions/stochastics/options/iew2012-nonhomogenized-markov.py +++ /dev/null @@ -1,101 +0,0 @@ -verbose = True -force = True - -dirname = 'temoa_island_markoved' -modelpath = '../temoa_model.py' -dotdatpath = '../data_files/iew2012.dat' -stochasticset = 'time_optimize' -stochastic_points = (2020, 2025, 2030, 2035) -stochastic_indices = {'CostMarginal': 0} -types = ( - 'DDD', - 'DDU', - 'DUD', - 'DUU', - 'UDD', - 'UDU', - 'UUU', -) - -conditional_probability = dict( - HedgingStrategy=( - ('DDD', 13.0 / 57), - ('DDU', 1.0 / 57), - ('DUD', 12.0 / 57), - ('DUU', 14.0 / 57), - ('UDD', 3.0 / 57), - ('UDU', 2.0 / 57), - ('UUU', 12.0 / 57), - ), - DDD=( - ('DDD', 8.0 / 13), - ('DDU', 1.0 / 13), - ('DUD', 1.0 / 13), - ('DUU', 2.0 / 13), - ('UDD', 1.0 / 13), - ), - DDU=(('DDD', 1),), - DUD=(('DDD', 4.0 / 12), ('DUD', 7.0 / 12), ('DUU', 1.0 / 12)), - DUU=(('DUD', 3.0 / 14), ('DUU', 10.0 / 14), ('UUU', 1.0 / 14)), - UDD=(('UDD', 2.0 / 3), ('UUU', 1.0 / 3)), - UDU=(('UDU', 1),), - UUU=(('DUU', 1.0 / 12), ('UDU', 1.0 / 12), ('UUU', 10.0 / 12)), -) - -rates = { - 'CostMarginal': dict( - HedgingStrategyDDD=( - ('imp_coal', 1.06637), - ('imp_natgas,*', 0.88132), - ('imp_oil,*', 1.05582), - ), - HedgingStrategyDDU=( - ('imp_coal', 1.06637), - ('imp_natgas,*', 0.88132), - ('imp_oil,*', 1.05582), - ), - HedgingStrategyDUD=( - ('imp_coal', 1.06637), - ('imp_natgas,*', 0.88132), - ('imp_oil,*', 1.05582), - ), - HedgingStrategyDUU=( - ('imp_coal', 1.06637), - ('imp_natgas,*', 0.88132), - ('imp_oil,*', 1.05582), - ), - HedgingStrategyUDD=( - ('imp_coal', 1.06637), - ('imp_natgas,*', 0.88132), - ('imp_oil,*', 1.05582), - ), - HedgingStrategyUDU=( - ('imp_coal', 1.06637), - ('imp_natgas,*', 0.88132), - ('imp_oil,*', 1.05582), - ), - HedgingStrategyUUU=( - ('imp_coal', 1.06637), - ('imp_natgas,*', 0.88132), - ('imp_oil,*', 1.05582), - ), - DDDDDD=(('imp_coal,*', 0.95886), ('imp_natgas,*', 0.93415), ('imp_oil,*', 0.91485)), - DDDDDU=(('imp_coal,*', 0.94783), ('imp_natgas,*', 0.93143), ('imp_oil,*', 1.01982)), - DDDDUD=(('imp_coal,*', 0.95210), ('imp_natgas,*', 1.00764), ('imp_oil,*', 0.99502)), - DDDDUU=(('imp_coal,*', 0.95412), ('imp_natgas,*', 1.02703), ('imp_oil,*', 1.00843)), - DDDUDD=(('imp_coal,*', 1.03169), ('imp_natgas,*', 0.97375), ('imp_oil,*', 0.98145)), - DDUDDD=(('imp_coal,*', 0.95059), ('imp_natgas,*', 0.97436), ('imp_oil,*', 0.97492)), - DUDDDD=(('imp_coal,*', 0.95935), ('imp_natgas,*', 0.98153), ('imp_oil,*', 0.92444)), - DUDDUD=(('imp_coal,*', 0.96920), ('imp_natgas,*', 1.03930), ('imp_oil,*', 0.98458)), - DUDDUU=(('imp_coal,*', 0.97144), ('imp_natgas,*', 1.06985), ('imp_oil,*', 1.00170)), - DUUDUD=(('imp_coal,*', 0.96475), ('imp_natgas,*', 1.03622), ('imp_oil,*', 0.98506)), - DUUDUU=(('imp_coal,*', 0.97600), ('imp_natgas,*', 1.11657), ('imp_oil,*', 1.09607)), - DUUUUU=(('imp_coal,*', 1.01655), ('imp_natgas,*', 1.16025), ('imp_oil,*', 1.15942)), - UDDUDD=(('imp_coal,*', 1.05568), ('imp_natgas,*', 0.98233), ('imp_oil,*', 0.98602)), - UDDUUU=(('imp_coal,*', 1.07542), ('imp_natgas,*', 1.01397), ('imp_oil,*', 1.00729)), - UDUUDU=(('imp_coal,*', 1.06637), ('imp_natgas,*', 0.88132), ('imp_oil,*', 1.05582)), - UUUDUU=(('imp_coal,*', 0.98426), ('imp_natgas,*', 1.20240), ('imp_oil,*', 1.18666)), - UUUUDU=(('imp_coal,*', 1.08067), ('imp_natgas,*', 0.92897), ('imp_oil,*', 1.04542)), - UUUUUU=(('imp_coal,*', 1.10292), ('imp_natgas,*', 1.14894), ('imp_oil,*', 1.13962)), - ) -} diff --git a/temoa/extensions/stochastics/options/iew2012.py b/temoa/extensions/stochastics/options/iew2012.py deleted file mode 100644 index 2be9a8fe7..000000000 --- a/temoa/extensions/stochastics/options/iew2012.py +++ /dev/null @@ -1,92 +0,0 @@ -verbose = True -force = True - -dirname = 'temoa_island' -modelpath = '../temoa_model/temoa_model.py' -dotdatpath = '../data_files/iew2012.dat' -stochasticset = 'time_optimize' -stochastic_points = (2020, 2025, 2030, 2035) -stochastic_indices = {'Demand': 0, 'cost_variable': 0} -types = ( - 'DemD_NatD_OilD', - 'DemD_NatD_OilU', - 'DemD_NatU_OilD', - 'DemD_NatU_OilU', - 'DemU_NatD_OilD', - 'DemU_NatD_OilU', - 'DemU_NatU_OilD', - 'DemU_NatU_OilU', -) -conditional_probability = dict( - DemD_NatD_OilD=0.0952, - DemD_NatD_OilU=0.0238, - DemD_NatU_OilD=0.0952, - DemD_NatU_OilU=0.1429, - DemU_NatD_OilD=0.1429, - DemU_NatD_OilU=0.1667, - DemU_NatU_OilD=0.0952, - DemU_NatU_OilU=0.2381, -) - -rates = { - 'Demand': dict( - DemD_NatD_OilD=( - ('*,*,r_cooling', 0.95937), - ('*,*,r_heating', 0.95937), - ('*,*,r_lighting', 0.95937), - ('*,*,r_wheating', 0.95937), - ), - DemD_NatD_OilU=( - ('*,*,r_cooling', 0.78503), - ('*,*,r_heating', 0.78503), - ('*,*,r_lighting', 0.78503), - ('*,*,r_wheating', 0.78503), - ), - DemD_NatU_OilD=( - ('*,*,r_cooling', 0.92841), - ('*,*,r_heating', 0.92841), - ('*,*,r_lighting', 0.92841), - ('*,*,r_wheating', 0.92841), - ), - DemD_NatU_OilU=( - ('*,*,r_cooling', 0.90791), - ('*,*,r_heating', 0.90791), - ('*,*,r_lighting', 0.90791), - ('*,*,r_wheating', 0.90791), - ), - DemU_NatD_OilD=( - ('*,*,r_cooling', 1.18282), - ('*,*,r_heating', 1.18282), - ('*,*,r_lighting', 1.18282), - ('*,*,r_wheating', 1.18282), - ), - DemU_NatD_OilU=( - ('*,*,r_cooling', 1.20957), - ('*,*,r_heating', 1.20957), - ('*,*,r_lighting', 1.20957), - ('*,*,r_wheating', 1.20957), - ), - DemU_NatU_OilD=( - ('*,*,r_cooling', 1.20281), - ('*,*,r_heating', 1.20281), - ('*,*,r_lighting', 1.20281), - ('*,*,r_wheating', 1.20281), - ), - DemU_NatU_OilU=( - ('*,*,r_cooling', 1.12236), - ('*,*,r_heating', 1.12236), - ('*,*,r_lighting', 1.12236), - ('*,*,r_wheating', 1.12236), - ), - ), - 'cost_variable': dict( - DemD_NatD_OilD=(('imp_natgas,*', 0.73351), ('imp_oil,*', 0.15309)), - DemD_NatD_OilU=(('imp_natgas,*', 0.95164), ('imp_oil,*', 2.67004)), - DemD_NatU_OilD=(('imp_natgas,*', 1.68052), ('imp_oil,*', 0.55464)), - DemD_NatU_OilU=(('imp_natgas,*', 1.40218), ('imp_oil,*', 4.45265)), - DemU_NatD_OilD=(('imp_natgas,*', 0.74707), ('imp_oil,*', 0.62440)), - DemU_NatD_OilU=(('imp_natgas,*', 0.75098), ('imp_oil,*', 2.11862)), - DemU_NatU_OilD=(('imp_natgas,*', 1.37597), ('imp_oil,*', 0.66387)), - DemU_NatU_OilU=(('imp_natgas,*', 1.45544), ('imp_oil,*', 2.34730)), - ), -} diff --git a/temoa/extensions/stochastics/options/utopia_coal_vs_nuc.py b/temoa/extensions/stochastics/options/utopia_coal_vs_nuc.py deleted file mode 100644 index 4617a884b..000000000 --- a/temoa/extensions/stochastics/options/utopia_coal_vs_nuc.py +++ /dev/null @@ -1,86 +0,0 @@ -verbose = True -force = True - -dirname = 'utopia_demand' -modelpath = '../temoa_model/temoa_model.py' -dotdatpath = '../data_files/utopia-15.dat' -stochasticset = 'time_optimize' -stochastic_indices = {'Demand': 0, 'cost_invest': 1} - -# CL, CA, CH = coal "[lower, average, high]" rate -# _Low, _Average, _High = demand "[low, average, high]" rate -types = ( - 'CL_Low', - 'CL_Average', - 'CL_High', - 'CA_Low', - 'CA_Average', - 'CA_High', - 'CH_Low', - 'CH_Average', - 'CH_High', -) - -# for this toy problem, all branches are equally likely, so 1/9 -conditional_probability = dict( - CL_Low=1.0 / 9, - CA_Low=1.0 / 9, - CH_Low=1.0 / 9, - CL_Average=1.0 / 9, - CA_Average=1.0 / 9, - CH_Average=1.0 / 9, - CL_High=1.0 / 9, - CA_High=1.0 / 9, - CH_High=1.0 / 9, -) -rates = { - 'Demand': dict( - CL_Low=(('*,*,RH', 0.951), ('*,*,RL', 0.951), ('*,*,TX', 0.951)), - CA_Low=(('*,*,RH', 0.951), ('*,*,RL', 0.951), ('*,*,TX', 0.951)), - CH_Low=(('*,*,RH', 0.951), ('*,*,RL', 0.951), ('*,*,TX', 0.951)), - CL_Average=(('*,*,RH', 1.105), ('*,*,RL', 1.105), ('*,*,TX', 1.105)), - CA_Average=(('*,*,RH', 1.105), ('*,*,RL', 1.105), ('*,*,TX', 1.105)), - CH_Average=(('*,*,RH', 1.105), ('*,*,RL', 1.105), ('*,*,TX', 1.105)), - CL_High=(('*,*,RH', 1.480), ('*,*,RL', 1.480), ('*,*,TX', 1.480)), - CA_High=(('*,*,RH', 1.480), ('*,*,RL', 1.480), ('*,*,TX', 1.480)), - CH_High=(('*,*,RH', 1.480), ('*,*,RL', 1.480), ('*,*,TX', 1.480)), - ), - 'cost_invest': dict( - CL_Low=( - ('E01,*', 1.8), - ('E21,*', 1.2), - ), - CL_Average=( - ('E01,*', 1.8), - ('E21,*', 1.2), - ), - CL_High=( - ('E01,*', 1.8), - ('E21,*', 1.2), - ), - CA_Low=( - ('E01,*', 2.0), - ('E21,*', 0.7), - ), - CA_Average=( - ('E01,*', 2.0), - ('E21,*', 0.7), - ), - CA_High=( - ('E01,*', 2.0), - ('E21,*', 0.7), - ), - CH_Low=( - ('E01,*', 2.2), - ('E21,*', 0.2), - ), - CH_Average=( - ('E01,*', 2.2), - ('E21,*', 0.2), - ), - CH_High=( - ('E01,*', 2.2), - ('E21,*', 0.2), - ), - ), -} diff --git a/temoa/extensions/stochastics/stochastics_README.txt b/temoa/extensions/stochastics/stochastics_README.txt deleted file mode 100644 index 1792164f6..000000000 --- a/temoa/extensions/stochastics/stochastics_README.txt +++ /dev/null @@ -1,73 +0,0 @@ ------------------------------- -Stochastic Optimization README ------------------------------- - -(Solve a stochastic run and store results into a database using config file) -$ python temoa_model/temoa_stochastic.py --config=temoa_model/config_sample -# Note that to invoke the stochastic run, the "--input" flag must be the path -# to ScenarioStructure.dat, and "--output" flag is the path to the target -# database file, where the results will be stored. - -(Extensive Formulation or Deterministic Equivalent) -runef -m ../../temoa_model/ -i ./ --solver=glpk --solve >> out.txt - -(Progressive Hedging) -runph -m ../../temoa_model/ -i ./ --solver=ipopt --default-rho=1.0 - -(Solve a particular path in the tree as a linear program) -python ../../temoa_model/ R.dat Rs0.dat Rs0s2.dat - ------------------------------ -Stochastic Optimization Tools ------------------------------ - -(EVPI computation) -python test_EVPI.py - -(VSS computation) -python VSS.py - #(Information about how to setup a run of VSS): - #Lines 246 - 249 specify the path to the folders and the solver to be used. - #It is necessary to change these lines in order to properly point to the - #instance that you want to solve. The first one just points to the path of the - #temoa_stochastic.py file. The second one point to the folder of the instance - #where the scenario tree structure and all the scenarios are represented. - #p_model = '/home/arqueiroz/SSudan/S1_2_H/temoa_model/temoa_stochastic.py' - #p_data = '/home/arqueiroz/SSudan/S1_2_H/stochastic/S_Sudan_original_stoch_cap_cost_11' - #optsolver = 'cplex' - - #(Deterministic file with average values): - #Inside the stochastic folder where you want to run the VSS script it is necessary to - #manually create an input file to represent the uncertainty with average values. This - #file will be used to run the deterministic instance where we store information about the - #decisions on the first stage. - #The name of the input file is defined on line 195 - - #(Get info about decisions on the first stage): - #On line 147 - #ef._binding_instance.S0s0s0.v_capacity[iaux1, iaux2].fix(dv_capacity[iaux1,iaux2]) - #it is necessary to fix the first stage decisions from the deterministic model (with - #average values) when solving the stochastic program (with fixed values) that will - #be compared to the true stochastic program (without any fixed values) - #Note that the left portion of the equation is the one that is fixed. As for now - #it depends on the number of stages of the problem, for the one used here there is - #a total of four stages and we need to fix .S0s0s0.v_capacity.fix if it was 3 stages we - #would make S0s0.v_capacity.fix - - #Additional file for EVPI and VSS usage: - #pyomo version 4.3.11388 requires the addition - #of the file ef_writer_script_old.py within the installation - #of pyomo under anaconda. The correct path to add the - #file is: /anaconda/lib/python2.7/site-packages/pyomo/pysp - -(Generate Scenario Tree) -python generate_scenario_tree.py options/uc_tl_unlim.py - #Additional files needed for generate scenario tree script: - #pyomo version 4.3.11388 requires the addition - #of the file scenariomodels.py within the installation - #of pyomo under anaconda. The correct path to add the - #file is: /anaconda/lib/python2.7/site-packages/pyomo/pysp/util - - -(Script for Parallel runs of runph) (to be used on Neer super computer) -qsub jobTemoa.pbs diff --git a/temoa/extensions/stochastics/temoa_stochastic.py b/temoa/extensions/stochastics/temoa_stochastic.py deleted file mode 100644 index bf3c06ae9..000000000 --- a/temoa/extensions/stochastics/temoa_stochastic.py +++ /dev/null @@ -1,189 +0,0 @@ -#!/usr/bin/env python - - -import os -import sys - -from pformat_results import pformat_results -from pyomo.core.kernel.numvalue import value -from pyomo.environ import * -from pyomo.opt import SolverFactory -from pyomo.pysp.ef import create_ef_instance -from pyomo.pysp.scenariotree.manager import ScenarioTreeManagerClientSerial -from temoa_model import TemoaModel -from temoa_rules import PeriodCost_rule -from temoa_run import parse_args - - -def return_CP_and_path(p_data): - # return_CP_and_path(p_data) -> dict(), dict() - # This function reads the path to the instance directory (p_data) and - # returns conditional two dictionaries, the first one is the conditional - # probability of a scenario, the second one is the path to all files of a - # scenario. - from collections import defaultdict, deque - - # from pyomo.pysp.util.scenariomodels import scenario_tree_model - from pyomo.pysp.scenariotree.tree_structure_model import CreateAbstractScenarioTreeModel - - pwd = os.getcwd() - os.chdir(p_data) - - s2fp_dict = defaultdict(deque) # Scenario to 'file path' dictionary, .dat not included - s2cd_dict = defaultdict(float) # Scenario to conditonal density mapping - # sStructure = scenario_tree_model.create_instance( filename='ScenarioStructure.dat' ) - sStructure = CreateAbstractScenarioTreeModel().create_instance(filename='ScenarioStructure.dat') - - # The following code is borrowed from Kevin's temoa_lib.py - ########################################################################### - # Step 1: find the root node. PySP doesn't make this very easy ... - - # a child -> parent mapping, because every child has only one parent, but - # not vice-versa - ctpTree = dict() # Child to parent dict, one to one mapping - - to_process = deque() - to_process.extend(sStructure.children.keys()) - while to_process: - node = to_process.pop() - if node in sStructure.children: - # it's a parent! - new_nodes = set(sStructure.children[node]) - to_process.extend(new_nodes) - ctpTree.update({n: node for n in new_nodes}) - - # parents - children - root_node = (set(ctpTree.values()) - set(ctpTree.keys())).pop() - - # ptcTree = defaultdict( list ) # Parent to child node, one to multiple mapping - # for c, p in ctpTree.items(): - # ptcTree[ p ].append( c ) - # ptcTree = dict( ptcTree ) # be slightly defensive; catch any additions - - # leaf_nodes = set(ctpTree.keys()) - set(ctpTree.values()) - # leaf_nodes = set(sStructure.scenario_leaf_node.values()) # Try to hack Kevin's code - leaf_nodes = sStructure.scenario_leaf_node.values() # Try to hack Kevin's code - leaf_nodes_names = list() - for n in leaf_nodes: - leaf_nodes_names.append(n.value) - leaf_nodes_names = set(leaf_nodes_names) - - scenario_nodes = dict() # Map from leafnode to 'node path' - for node in leaf_nodes_names: # e.g.: {Rs0s0: [R, Rs0, Rs0s0]} - s = deque() - scenario_nodes[node] = s - while node in ctpTree: - s.append(node) - node = ctpTree[node] - s.append(node) - s.reverse() - ########################################################################### - - for s in sStructure.scenarios: - cp = 1.0 # Starting probability - for n in scenario_nodes[value(sStructure.scenario_leaf_node[s])]: - cp = cp * value(sStructure.conditional_probability[n]) - if not sStructure.scenario_based_data.value: - s2fp_dict[s].append(n + '.dat') - s2cd_dict[s] = cp - - if sStructure.scenario_based_data.value: - for s in sStructure.scenarios: - s2fp_dict[s].append(s + '.dat') - os.chdir(pwd) - return (s2cd_dict, s2fp_dict) - - -def solve_ef(p_model, p_data, temoa_options=None): - """ - solve_ef(p_model, p_data) -> objective value of the extensive form - Solves the model in stochastic mode. - p_model -> string, the path to the model file (ReferenceModel.py). - p_data -> string, the path to the directory of data for the stochastic - mdoel, where ScenarioStructure.dat should resides. - Returns a float point number of the value of objective function for the - stochastic program model. - """ - - options = ScenarioTreeManagerClientSerial.register_options() - - if os.path.basename(p_model) == 'ReferenceModel.py': - options.model_location = os.path.dirname(p_model) - else: - sys.stderr.write('\nModel file should be ReferenceModel.py. Exiting...\n') - sys.exit(1) - options.scenario_tree_location = p_data - - # using the 'with' block will automatically call - # manager.close() and gracefully shutdown - with ScenarioTreeManagerClientSerial(options) as manager: - manager.initialize() - - ef_instance = create_ef_instance(manager.scenario_tree, verbose_output=options.verbose) - - ef_instance.dual = Suffix(direction=Suffix.IMPORT) - - with SolverFactory(temoa_options.solver_name) as opt: - ef_result = opt.solve(ef_instance) - - # Write to database - if hasattr(temoa_options, 'output'): - sys.path.append(options.model_location) - - # from temoa_config import TemoaConfig - # temoa_options = TemoaConfig() - # temoa_options.config = temoa_options.config - # temoa_options.keepPyomoLP = temoa_options.keepPyomoLP - # temoa_options.saveTEXTFILE = temoa_options.saveTEXTFILE - # temoa_options.path_to_data = temoa_options.path_to_data - # temoa_options.saveEXCEL = temoa_options.saveEXCEL - ef_result.solution.Status = 'feasible' # Assume it is feasible - # Maybe there is a better solution using manager, but now it is a - # kludge to use return_CP_and_path() function - s2cd_dict, s2fp_dict = return_CP_and_path(p_data) - stochastic_run = temoa_options.scenario # Name of stochastic run - for s in manager.scenario_tree.scenarios: - ins = s._instance - temoa_options.scenario = '.'.join([stochastic_run, s.name]) - temoa_options.dot_dat = list() - for fname in s2fp_dict[s.name]: - temoa_options.dot_dat.append( - os.path.join(options.scenario_tree_location, fname) - ) - # temoa_options.output = os.path.join( - # options.scenario_tree_location, - # stochastic_output - # ) - msg = f'\nStoring results from scenario {s.name} to database.\n' - sys.stderr.write(msg) - formatted_results = pformat_results(ins, ef_result, temoa_options) - - ef_instance.solutions.store_to(ef_result) - ef_obj = value(ef_instance.EF_EXPECTED_COST.values()[0]) - return ef_obj - - -def StochasticPointObjective_rule(M, p): - expr = M.StochasticPointCost[p] == PeriodCost_rule(M, p) - return expr - - -def Objective_rule(M): - return sum(M.StochasticPointCost[pp] for pp in M.time_optimize) - - -M = model = TemoaModel('TEMOA Stochastic') - -M.StochasticPointCost = Var(M.time_optimize, within=NonNegativeReals) -M.StochasticPointCostConstraint = Constraint(M.time_optimize, rule=StochasticPointObjective_rule) - -del M.total_cost -M.total_cost = Objective(rule=Objective_rule, sense=minimize) - -if __name__ == '__main__': - p_model = './ReferenceModel.py' - temoa_options, config_flag = parse_args() - p_dot_dat = temoa_options.dot_dat[0] # must be ScenarioStructure.dat - p_data = os.path.dirname(p_dot_dat) - print(p_model, p_data) - print(solve_ef(p_model, p_data, temoa_options)) From 4e6116365a1f78534279510f623c02d73edbc806 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 8 Jan 2026 16:10:52 -0500 Subject: [PATCH 414/587] update docs and readme with pypi info --- README.md | 64 ++++++++++++------------------------- docs/source/quick_start.rst | 13 ++++---- 2 files changed, 27 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 12f35dd09..a7a563673 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ -# TEMOA Version 4.0.0a1 +# TEMOA +[![PyPI](https://img.shields.io/pypi/v/temoa?label=pypi%20package)](https://pypi.org/project/temoa/) [![CI](https://github.com/TemoaProject/temoa/actions/workflows/ci.yml/badge.svg?branch=unstable)](https://github.com/TemoaProject/temoa/actions/workflows/ci.yml) [![Documentation Status](https://readthedocs.org/projects/temoa/badge/?version=latest)](https://temoa.readthedocs.io/en/latest/?badge=latest) [![Python 3.12+](https://img.shields.io/badge/python-3.12%2B-blue)](https://pyreadiness.org/3.12/) @@ -14,57 +15,28 @@ TEMOA (Tools for Energy Model Optimization and Analysis) is a sophisticated ener ## Quick Start -### Using uv (Recommended) - -The fastest way to get started with Temoa: - -```bash -# Install uv if you haven't already -curl -LsSf https://astral.sh/uv/install.sh | sh - -``` - -Bleeding-edge nightly development installation: - -In a directory initialized with uv (e.g., `uv init .`) run: +### Standard Installation ```bash -uv add temoa --default-index https://pypi.temoaproject.org/simple/ --index https://pypi.org/simple/ - -# or - -pip install --index-url https://temoaproject.github.io/temoa-nightlies/simple/ temoa --extra-index-url https://pypi.org/simple/ - -``` - -Or clone the repository and install in development mode: +# Install from PyPI in a virtual environment +python -m venv .venv -```bash +# Activate virtual environment +# On Linux/Mac: +source .venv/bin/activate +# On Windows: +.venv\Scripts\activate -# Clone and setup development environment -git clone https://github.com/TemoaProject/temoa.git -cd temoa -uv sync --all-extras --dev - -# Run your first model -uv run temoa tutorial my_first_model -uv run temoa run my_first_model.toml -``` - -### Standard Installation - -```bash -# Install from PyPI (not yet available) +# Install temoa pip install temoa - -# Or install from source -pip install -e . ``` ### Get Started in 30 Seconds +In a virtual env with temoa installed, run: + ```bash -# Create tutorial files +# Create tutorial files in the current directory temoa tutorial quick_start # Run the model @@ -92,7 +64,13 @@ The Temoa package is organized into clear modules: ### Development Installation -For users who want to contribute or modify Temoa should install in development mode using `uv`: +For users who want to contribute to or modify Temoa should install in development mode using `uv`: + +```bash +# Install uv if you haven't already +curl -LsSf https://astral.sh/uv/install.sh | sh + +``` ```bash # Clone repository diff --git a/docs/source/quick_start.rst b/docs/source/quick_start.rst index d19f75dc9..a1ead6fdf 100644 --- a/docs/source/quick_start.rst +++ b/docs/source/quick_start.rst @@ -21,12 +21,9 @@ First, it is highly recommended to use a Python virtual environment to manage de Then, install Temoa: .. parsed-literal:: - # Install from PyPI (when 4.0 is released) + # Install from PyPI $ pip install temoa - # Or install from nightlies (alpha/development versions) - $ pip install --index-url https://temoaproject.github.io/temoa-nightlies/simple/ temoa --extra-index-url https://pypi.org/simple/ - # Get started $ python -m temoa tutorial my_first_model $ python -m temoa run my_first_model.toml @@ -43,9 +40,8 @@ For faster dependency resolution: $ uv init $ cd - - # add Temoa from nightlies to pyproject.toml - $ uv add temoa --default-index https://pypi.temoaproject.org/simple --index https://pypi.org/simple + # add Temoa from PyPI to pyproject.toml + $ uv add temoa # Get started $ uv run temoa tutorial my_first_model @@ -63,6 +59,9 @@ If you want to contribute to Temoa or modify the code: # Install in development mode with uv (recommended) $ uv sync --all-extras --dev + # Install pre-commit hooks + $ uv run pre-commit install + For detailed contribution guidelines, see CONTRIBUTING.md in the repository. Solvers From 274ca23d5d838e27588844bdaa62e7ad4c3fd32c Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 9 Jan 2026 12:34:35 -0500 Subject: [PATCH 415/587] adding sphinx mermaid plugin for docs --- pyproject.toml | 1 + requirements-dev.txt | 4 ++++ uv.lock | 15 +++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index e54ec9ef4..d0704126c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,6 +57,7 @@ docs = [ "sphinxcontrib-serializinghtml>=2.0.0", "sphinxcontrib-bibtex>=2.6.2", "myst-parser>=2.0.0", + "sphinxcontrib-mermaid>=1.2.3", ] plotting = [ diff --git a/requirements-dev.txt b/requirements-dev.txt index 069d18cde..e845fadf9 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -141,6 +141,7 @@ pyyaml==6.0.2 # via # myst-parser # pybtex + # sphinxcontrib-mermaid requests==2.32.4 # via sphinx rich==14.2.0 @@ -171,6 +172,7 @@ sphinx==8.2.3 # sphinx-rtd-theme # sphinxcontrib-bibtex # sphinxcontrib-jquery + # sphinxcontrib-mermaid sphinx-rtd-theme==3.0.2 # via temoa (pyproject.toml) sphinxcontrib-applehelp==2.0.0 @@ -187,6 +189,8 @@ sphinxcontrib-jquery==4.1 # via sphinx-rtd-theme sphinxcontrib-jsmath==1.0.1 # via sphinx +sphinxcontrib-mermaid==1.2.3 + # via temoa (pyproject.toml) sphinxcontrib-qthelp==2.0.0 # via sphinx sphinxcontrib-serializinghtml==2.0.0 diff --git a/uv.lock b/uv.lock index 948edf7e5..dbce91d1b 100644 --- a/uv.lock +++ b/uv.lock @@ -1348,6 +1348,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071, upload-time = "2019-01-21T16:10:14.333Z" }, ] +[[package]] +name = "sphinxcontrib-mermaid" +version = "1.2.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, + { name = "sphinx" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f5/49/c6ddfe709a4ab76ac6e5a00e696f73626b2c189dc1e1965a361ec102e6cc/sphinxcontrib_mermaid-1.2.3.tar.gz", hash = "sha256:358699d0ec924ef679b41873d9edd97d0773446daf9760c75e18dc0adfd91371", size = 18885, upload-time = "2025-11-26T04:18:32.43Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/39/8b54299ffa00e597d3b0b4d042241a0a0b22cb429ad007ccfb9c1745b4d1/sphinxcontrib_mermaid-1.2.3-py3-none-any.whl", hash = "sha256:5be782b27026bef97bfb15ccb2f7868b674a1afc0982b54cb149702cfc25aa02", size = 13413, upload-time = "2025-11-26T04:18:31.269Z" }, +] + [[package]] name = "sphinxcontrib-qthelp" version = "2.0.0" @@ -1409,6 +1422,7 @@ docs = [ { name = "sphinx-rtd-theme" }, { name = "sphinxcontrib-bibtex" }, { name = "sphinxcontrib-htmlhelp" }, + { name = "sphinxcontrib-mermaid" }, { name = "sphinxcontrib-serializinghtml" }, ] plotting = [ @@ -1458,6 +1472,7 @@ requires-dist = [ { name = "sphinx-rtd-theme", marker = "extra == 'docs'", specifier = ">=2.0.0" }, { name = "sphinxcontrib-bibtex", marker = "extra == 'docs'", specifier = ">=2.6.2" }, { name = "sphinxcontrib-htmlhelp", marker = "extra == 'docs'", specifier = ">=2.1.0" }, + { name = "sphinxcontrib-mermaid", marker = "extra == 'docs'", specifier = ">=1.2.3" }, { name = "sphinxcontrib-serializinghtml", marker = "extra == 'docs'", specifier = ">=2.0.0" }, { name = "tabulate", specifier = ">=0.9.0" }, { name = "tomlkit", specifier = ">=0.12.0" }, From a8c067007cf91a8f2dc32e61231c8844f879bbc3 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 9 Jan 2026 12:35:11 -0500 Subject: [PATCH 416/587] adding mermaid diagram for showing temoa execution flow --- docs/source/computational_implementation.rst | 80 ++++++++++++++++++++ docs/source/conf.py | 10 +++ 2 files changed, 90 insertions(+) diff --git a/docs/source/computational_implementation.rst b/docs/source/computational_implementation.rst index 80d294a32..f0c4c180e 100644 --- a/docs/source/computational_implementation.rst +++ b/docs/source/computational_implementation.rst @@ -331,6 +331,86 @@ understanding of what a constraint does requires only the last line of code: "Supply must meet demand." +Execution Flow +-------------- + +The Temoa execution flow is designed to be modular and consistent across different modeling modes. It begins with the Command Line Interface (CLI), which parses user input and sets up the execution environment. The following sequence diagram illustrates the execution flow of a Temoa run, from the initial command-line invocation to the final processing of results. + +.. mermaid:: + :alt: Temoa Execution Flow + :zoom: + + sequenceDiagram + participant User + participant CLI as temoa/cli.py + participant Config as TemoaConfig + participant Sequencer as TemoaSequencer + participant HL as HybridLoader + participant Model as TemoaModel Instance + participant RA as run_actions.py + participant DB as Database + + rect rgb(220,230,250) + Note over CLI: User invokes CLI (run/validate) + User->>CLI: temoa run/validate config.toml + end + + rect rgb(230,250,220) + Note over CLI: Environment Setup + CLI->>CLI: _create_output_folder() + CLI->>CLI: _setup_logging() + CLI->>Config: build_config(config_file, output_path, silent) + Config-->>CLI: TemoaConfig instance + end + + rect rgb(250,240,220) + Note over CLI,Sequencer: Sequencer Initialization + CLI->>Sequencer: TemoaSequencer(config, mode_override?) + Sequencer-->>CLI: Ready + end + + rect rgb(240,220,250) + Note over Sequencer: Model Building & Execution + alt build-only / validate + CLI->>Sequencer: build_model() + Sequencer->>Sequencer: _run_preliminary_checks() + Sequencer->>RA: check_database_version() + Sequencer->>HL: HybridLoader(db_con, config) + HL->>HL: load_data_portal() + Sequencer->>RA: build_instance(data_portal) + RA-->>Sequencer: TemoaModel instance + Sequencer-->>CLI: TemoaModel instance + else full run (e.g., perfect_foresight) + CLI->>Sequencer: start() + Sequencer->>Sequencer: _run_preliminary_checks() + Sequencer->>Sequencer: _run_perfect_foresight() + Sequencer->>HL: HybridLoader(db_con, config) + HL->>HL: load_data_portal() + Sequencer->>RA: build_instance(data_portal) + RA-->>Sequencer: instance + Sequencer->>RA: solve_instance(instance, solver_name) + RA->>RA: check_solve_status(results) + Sequencer->>RA: handle_results(instance, results, config) + RA->>DB: Persist results + Sequencer-->>CLI: Success / Error + end + end + + rect rgb(220,250,240) + CLI->>User: report log path and output folder + end + +The execution flow involves several key stages: + +1. **CLI Entry**: The user interacts with :file:`temoa/cli.py` to initiate a run or validation. +2. **Environment Setup**: The CLI creates a timestamped output directory, initializes logging, and uses :class:`TemoaConfig` to parse the provided TOML configuration file. This includes checking for the availability of the specified optimization solver. +3. **Sequencing**: A :class:`TemoaSequencer` is created. This object is the main coordinator, selecting the appropriate execution path based on the modeling mode (e.g., Perfect Foresight, Myopic, MGA). +4. **Data Loading**: The sequencer uses a :class:`HybridLoader` to pull data from the SQLite database. This data is organized into a Pyomo :class:`DataPortal`. +5. **Model Construction**: Using the :class:`DataPortal`, Temoa constructs a :class:`TemoaModel` instance. This stage builds all the mathematical sets, parameters, variables, and constraints. +6. **Solving**: The model instance is passed to :func:`solve_instance`, which invokes the chosen solver (like HiGHS, CBC, or Gurobi). +7. **Result Processing**: After the solver completes, :func:`handle_results` extracts the solution, checks for optimality, and persists the results back to the database. It also generates any requested auxiliary outputs like Excel files or network plots. + + Project Structure ----------------- diff --git a/docs/source/conf.py b/docs/source/conf.py index 38de5dc7e..6010d5010 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -60,6 +60,7 @@ 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode', 'myst_parser', # Enable Markdown support + 'sphinxcontrib.mermaid', # Enable Mermaid diagrams ] # Add any paths that contain templates here, relative to this directory. @@ -141,3 +142,12 @@ def setup(app: Any) -> None: html_theme = 'sphinx_rtd_theme' html_logo = 'images/Temoa_logo_color_small.png' latex_logo = 'images/TemoaLogo_grayscale.png' + + +myst_enable_extensions = ['amsmath', 'colon_fence', 'dollarmath', 'html_image'] +myst_fence_as_directive = ['mermaid'] + +mermaid_d3_zoom = True +mermaid_fullscreen = True +mermaid_include_elk = True +mermaid_include_mindmap = True From ca0cc4fb3c0650b475adf3997755aa1a53bc0768 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 9 Jan 2026 12:42:54 -0500 Subject: [PATCH 417/587] adding entity relationship diagram for v4 schema --- docs/source/database_schema.mmd | 875 ++++++++++++++++++++++++++++++++ docs/source/quick_start.rst | 11 +- 2 files changed, 884 insertions(+), 2 deletions(-) create mode 100644 docs/source/database_schema.mmd diff --git a/docs/source/database_schema.mmd b/docs/source/database_schema.mmd new file mode 100644 index 000000000..0bc047252 --- /dev/null +++ b/docs/source/database_schema.mmd @@ -0,0 +1,875 @@ +erDiagram +capacity_credit { + INTEGER period PK + TEXT region PK + TEXT tech PK + INTEGER vintage PK + REAL credit + TEXT notes +} +technology { + TEXT tech PK + INTEGER annual + TEXT category + INTEGER curtail + TEXT description + INTEGER exchange + TEXT flag + INTEGER flex + INTEGER reserve + INTEGER retire + INTEGER seas_stor + TEXT sector + TEXT sub_category + INTEGER unlim_cap +} +technology_type { + TEXT label PK + TEXT description +} +time_period { + INTEGER period PK + TEXT flag + INTEGER sequence +} +time_period_type { + TEXT label PK + TEXT description +} +capacity_factor_process { + INTEGER period PK + TEXT region PK + TEXT season PK + TEXT tech PK + TEXT tod PK + INTEGER vintage PK + REAL factor + TEXT notes +} +time_of_day { + TEXT tod PK + INTEGER sequence +} +season_label { + TEXT season PK + TEXT notes +} +capacity_factor_tech { + INTEGER period PK + TEXT region PK + TEXT season PK + TEXT tech PK + TEXT tod PK + REAL factor + TEXT notes +} +capacity_to_activity { + TEXT region PK + TEXT tech PK + REAL c2a + TEXT notes +} +commodity { + TEXT name PK + TEXT description + TEXT flag +} +commodity_type { + TEXT label PK + TEXT description +} +construction_input { + TEXT input_comm PK + TEXT region PK + TEXT tech PK + INTEGER vintage PK + TEXT notes + TEXT units + REAL value +} +cost_emission { + TEXT emis_comm PK + INTEGER period PK + TEXT region PK + REAL cost + TEXT notes + TEXT units +} +cost_fixed { + INTEGER period PK + TEXT region PK + TEXT tech PK + INTEGER vintage PK + REAL cost + TEXT notes + TEXT units +} +cost_invest { + TEXT region PK + TEXT tech PK + INTEGER vintage PK + REAL cost + TEXT notes + TEXT units +} +cost_variable { + INTEGER period PK + TEXT region PK + TEXT tech PK + INTEGER vintage PK + REAL cost + TEXT notes + TEXT units +} +demand { + TEXT commodity PK + INTEGER period PK + TEXT region PK + REAL demand + TEXT notes + TEXT units +} +demand_specific_distribution { + TEXT demand_name PK + INTEGER period PK + TEXT region PK + TEXT season PK + TEXT tod PK + REAL dsd + TEXT notes +} +efficiency { + TEXT input_comm PK + TEXT output_comm PK + TEXT region PK + TEXT tech PK + INTEGER vintage PK + REAL efficiency + TEXT notes +} +efficiency_variable { + TEXT input_comm PK + TEXT output_comm PK + INTEGER period PK + TEXT region PK + TEXT season PK + TEXT tech PK + TEXT tod PK + INTEGER vintage PK + REAL efficiency + TEXT notes +} +emission_activity { + TEXT emis_comm PK + TEXT input_comm PK + TEXT output_comm PK + TEXT region PK + TEXT tech PK + INTEGER vintage PK + REAL activity + TEXT notes + TEXT units +} +emission_embodied { + TEXT emis_comm PK + TEXT region PK + TEXT tech PK + INTEGER vintage PK + TEXT notes + TEXT units + REAL value +} +emission_end_of_life { + TEXT emis_comm PK + TEXT region PK + TEXT tech PK + INTEGER vintage PK + TEXT notes + TEXT units + REAL value +} +end_of_life_output { + TEXT output_comm PK + TEXT region PK + TEXT tech PK + INTEGER vintage PK + TEXT notes + TEXT units + REAL value +} +existing_capacity { + TEXT region PK + TEXT tech PK + INTEGER vintage PK + REAL capacity + TEXT notes + TEXT units +} +lifetime_process { + TEXT region PK + TEXT tech PK + INTEGER vintage PK + REAL lifetime + TEXT notes +} +lifetime_survival_curve { + INTEGER period PK + TEXT region PK + TEXT tech PK + INTEGER vintage PK + REAL fraction + TEXT notes +} +lifetime_tech { + TEXT region PK + TEXT tech PK + REAL lifetime + TEXT notes +} +limit_activity { + TEXT operator PK + INTEGER period PK + TEXT region PK + TEXT tech_or_group PK + REAL activity + TEXT notes + TEXT units +} +operator { + TEXT operator PK + TEXT notes +} +limit_activity_share { + TEXT operator PK + INTEGER period PK + TEXT region PK + TEXT sub_group PK + TEXT super_group PK + TEXT notes + REAL share +} +limit_annual_capacity_factor { + TEXT operator PK + TEXT output_comm PK + INTEGER period PK + TEXT region PK + TEXT tech PK + REAL factor + TEXT notes +} +limit_capacity { + TEXT operator PK + INTEGER period PK + TEXT region PK + TEXT tech_or_group PK + REAL capacity + TEXT notes + TEXT units +} +limit_capacity_share { + TEXT operator PK + INTEGER period PK + TEXT region PK + TEXT sub_group PK + TEXT super_group PK + TEXT notes + REAL share +} +limit_degrowth_capacity { + TEXT operator PK + TEXT region PK + TEXT tech_or_group PK + TEXT notes + REAL rate + REAL seed + TEXT seed_units +} +limit_degrowth_new_capacity { + TEXT operator PK + TEXT region PK + TEXT tech_or_group PK + TEXT notes + REAL rate + REAL seed + TEXT seed_units +} +limit_degrowth_new_capacity_delta { + TEXT operator PK + TEXT region PK + TEXT tech_or_group PK + TEXT notes + REAL rate + REAL seed + TEXT seed_units +} +limit_emission { + TEXT emis_comm PK + TEXT operator PK + INTEGER period PK + TEXT region PK + TEXT notes + TEXT units + REAL value +} +limit_growth_capacity { + TEXT operator PK + TEXT region PK + TEXT tech_or_group PK + TEXT notes + REAL rate + REAL seed + TEXT seed_units +} +limit_growth_new_capacity { + TEXT operator PK + TEXT region PK + TEXT tech_or_group PK + TEXT notes + REAL rate + REAL seed + TEXT seed_units +} +limit_growth_new_capacity_delta { + TEXT operator PK + TEXT region PK + TEXT tech_or_group PK + TEXT notes + REAL rate + REAL seed + TEXT seed_units +} +limit_new_capacity { + TEXT operator PK + INTEGER period PK + TEXT region PK + TEXT tech_or_group PK + REAL new_cap + TEXT notes + TEXT units +} +limit_new_capacity_share { + TEXT operator PK + INTEGER period PK + TEXT region PK + TEXT sub_group PK + TEXT super_group PK + TEXT notes + REAL share +} +limit_resource { + TEXT operator PK + TEXT region PK + TEXT tech_or_group PK + REAL cum_act + TEXT notes + TEXT units +} +limit_seasonal_capacity_factor { + TEXT operator PK + INTEGER period PK + TEXT region PK + TEXT season PK + TEXT tech PK + REAL factor + TEXT notes +} +region { + TEXT region PK + TEXT notes +} +limit_storage_level_fraction { + TEXT operator PK + INTEGER period PK + TEXT region PK + TEXT season PK + TEXT tech PK + TEXT tod PK + INTEGER vintage PK + REAL fraction + TEXT notes +} +limit_tech_input_split { + TEXT input_comm PK + TEXT operator PK + INTEGER period PK + TEXT region PK + TEXT tech PK + TEXT notes + REAL proportion +} +limit_tech_input_split_annual { + TEXT input_comm PK + TEXT operator PK + INTEGER period PK + TEXT region PK + TEXT tech PK + TEXT notes + REAL proportion +} +limit_tech_output_split { + TEXT operator PK + TEXT output_comm PK + INTEGER period PK + TEXT region PK + TEXT tech PK + TEXT notes + REAL proportion +} +limit_tech_output_split_annual { + TEXT operator PK + TEXT output_comm PK + INTEGER period PK + TEXT region PK + TEXT tech PK + TEXT notes + REAL proportion +} +linked_tech { + TEXT emis_comm PK + TEXT primary_region PK + TEXT primary_tech PK + TEXT driven_tech + TEXT notes +} +loan_lifetime_process { + TEXT region PK + TEXT tech PK + INTEGER vintage PK + REAL lifetime + TEXT notes +} +loan_rate { + TEXT region PK + TEXT tech PK + INTEGER vintage PK + TEXT notes + REAL rate +} +metadata { + TEXT element PK + TEXT notes + INTEGER value +} +metadata_real { + TEXT element PK + TEXT notes + REAL value +} +myopic_efficiency { + TEXT input_comm PK + TEXT output_comm PK + TEXT region PK + TEXT tech PK + INTEGER vintage PK + INTEGER base_year + REAL efficiency + INTEGER lifetime +} +output_built_capacity { + TEXT region PK + TEXT scenario PK + TEXT tech PK + INTEGER vintage PK + REAL capacity + TEXT sector +} +sector_label { + TEXT sector PK + TEXT notes +} +output_cost { + INTEGER period PK + TEXT region PK + TEXT scenario PK + TEXT tech PK + INTEGER vintage PK + REAL d_emiss + REAL d_fixed + REAL d_invest + REAL d_var + REAL emiss + REAL fixed + REAL invest + TEXT sector + REAL var +} +output_curtailment { + TEXT input_comm PK + TEXT output_comm PK + INTEGER period PK + TEXT region PK + TEXT scenario PK + TEXT season PK + TEXT tech PK + TEXT tod PK + INTEGER vintage PK + REAL curtailment + TEXT sector +} +output_dual_variable { + TEXT constraint_name PK + TEXT scenario PK + REAL dual +} +output_emission { + TEXT emis_comm PK + INTEGER period PK + TEXT region PK + TEXT scenario PK + TEXT tech PK + INTEGER vintage PK + REAL emission + TEXT sector +} +output_flow_in { + TEXT input_comm PK + TEXT output_comm PK + INTEGER period PK + TEXT region PK + TEXT scenario PK + TEXT season PK + TEXT tech PK + TEXT tod PK + INTEGER vintage PK + REAL flow + TEXT sector +} +output_flow_out { + TEXT input_comm PK + TEXT output_comm PK + INTEGER period PK + TEXT region PK + TEXT scenario PK + TEXT season PK + TEXT tech PK + TEXT tod PK + INTEGER vintage PK + REAL flow + TEXT sector +} +output_flow_out_summary { + TEXT input_comm PK + TEXT output_comm PK + INTEGER period PK + TEXT region PK + TEXT scenario PK + TEXT tech PK + INTEGER vintage PK + REAL flow + TEXT sector +} +output_net_capacity { + INTEGER period PK + TEXT region PK + TEXT scenario PK + TEXT tech PK + INTEGER vintage PK + REAL capacity + TEXT sector +} +output_objective { + TEXT objective_name + TEXT scenario + REAL total_system_cost +} +output_retired_capacity { + INTEGER period PK + TEXT region PK + TEXT scenario PK + TEXT tech PK + INTEGER vintage PK + REAL cap_early + REAL cap_eol + TEXT sector +} +output_storage_level { + INTEGER period PK + TEXT region PK + TEXT scenario PK + TEXT season PK + TEXT tech PK + TEXT tod PK + INTEGER vintage PK + REAL level + TEXT sector +} +planning_reserve_margin { + TEXT region PK + REAL margin + TEXT notes +} +ramp_down_hourly { + TEXT region PK + TEXT tech PK + TEXT notes + REAL rate +} +ramp_up_hourly { + TEXT region PK + TEXT tech PK + TEXT notes + REAL rate +} +reserve_capacity_derate { + INTEGER period PK + TEXT region PK + TEXT season PK + TEXT tech PK + INTEGER vintage PK + REAL factor + TEXT notes +} +rps_requirement { + TEXT notes + INTEGER period + TEXT region + REAL requirement + TEXT tech_group +} +tech_group { + TEXT group_name PK + TEXT notes +} +storage_duration { + TEXT region PK + TEXT tech PK + REAL duration + TEXT notes +} +tech_group_member { + TEXT group_name PK + TEXT tech PK +} +time_season { + INTEGER period PK + TEXT season PK + INTEGER sequence PK + TEXT notes +} +time_season_all { + INTEGER period PK + TEXT season PK + INTEGER sequence PK + TEXT notes +} +time_season_sequential { + INTEGER period PK + TEXT seas_seq PK + TEXT season PK + INTEGER sequence PK + TEXT notes + REAL num_days +} +time_season_to_sequential { + INTEGER period PK + TEXT seas_seq PK + TEXT season PK + INTEGER sequence PK + TEXT notes + REAL num_days +} +time_segment_fraction { + INTEGER period PK + TEXT season PK + TEXT tod PK + TEXT notes + REAL segment_fraction +} +technology one or zero--0+ capacity_credit : has +time_period one or zero--0+ capacity_credit : has +technology_type 1--0+ technology : has +time_period_type one or zero--0+ time_period : has +technology one or zero--0+ capacity_factor_process : has +time_of_day one or zero--0+ capacity_factor_process : has +time_period one or zero--0+ capacity_factor_process : has +season_label one or zero--0+ capacity_factor_process : has +season_label one or zero--0+ capacity_factor_tech : has +time_period one or zero--0+ capacity_factor_tech : has +time_of_day one or zero--0+ capacity_factor_tech : has +technology one or zero--0+ capacity_factor_tech : has +technology one or zero--0+ capacity_to_activity : has +commodity_type one or zero--0+ commodity : has +time_period one or zero--0+ construction_input : has +commodity one or zero--0+ construction_input : has +technology one or zero--0+ construction_input : has +time_period one or zero--0+ cost_emission : has +commodity 1--0+ cost_emission : has +time_period 1--0+ cost_fixed : has +technology 1--0+ cost_fixed : has +time_period 1--0+ cost_fixed : has +technology one or zero--0+ cost_invest : has +time_period one or zero--0+ cost_invest : has +time_period 1--0+ cost_variable : has +time_period 1--0+ cost_variable : has +technology 1--0+ cost_variable : has +time_period one or zero--0+ demand : has +commodity one or zero--0+ demand : has +time_period one or zero--0+ demand_specific_distribution : has +season_label one or zero--0+ demand_specific_distribution : has +time_of_day one or zero--0+ demand_specific_distribution : has +commodity one or zero--0+ demand_specific_distribution : has +commodity one or zero--0+ efficiency : has +technology one or zero--0+ efficiency : has +time_period one or zero--0+ efficiency : has +commodity one or zero--0+ efficiency : has +time_period one or zero--0+ efficiency_variable : has +season_label one or zero--0+ efficiency_variable : has +time_of_day one or zero--0+ efficiency_variable : has +commodity one or zero--0+ efficiency_variable : has +technology one or zero--0+ efficiency_variable : has +time_period one or zero--0+ efficiency_variable : has +commodity one or zero--0+ efficiency_variable : has +commodity one or zero--0+ emission_activity : has +commodity one or zero--0+ emission_activity : has +technology one or zero--0+ emission_activity : has +time_period one or zero--0+ emission_activity : has +commodity one or zero--0+ emission_activity : has +commodity one or zero--0+ emission_embodied : has +technology one or zero--0+ emission_embodied : has +time_period one or zero--0+ emission_embodied : has +time_period one or zero--0+ emission_end_of_life : has +commodity one or zero--0+ emission_end_of_life : has +technology one or zero--0+ emission_end_of_life : has +technology one or zero--0+ end_of_life_output : has +commodity one or zero--0+ end_of_life_output : has +time_period one or zero--0+ end_of_life_output : has +time_period one or zero--0+ existing_capacity : has +technology one or zero--0+ existing_capacity : has +technology one or zero--0+ lifetime_process : has +time_period one or zero--0+ lifetime_process : has +time_period 1--0+ lifetime_survival_curve : has +technology 1--0+ lifetime_survival_curve : has +technology one or zero--0+ lifetime_tech : has +time_period one or zero--0+ limit_activity : has +operator 1--0+ limit_activity : has +time_period one or zero--0+ limit_activity_share : has +operator 1--0+ limit_activity_share : has +operator 1--0+ limit_annual_capacity_factor : has +time_period one or zero--0+ limit_annual_capacity_factor : has +technology one or zero--0+ limit_annual_capacity_factor : has +commodity one or zero--0+ limit_annual_capacity_factor : has +operator 1--0+ limit_capacity : has +time_period one or zero--0+ limit_capacity : has +time_period one or zero--0+ limit_capacity_share : has +operator 1--0+ limit_capacity_share : has +operator 1--0+ limit_degrowth_capacity : has +operator 1--0+ limit_degrowth_new_capacity : has +operator 1--0+ limit_degrowth_new_capacity_delta : has +commodity one or zero--0+ limit_emission : has +operator 1--0+ limit_emission : has +time_period one or zero--0+ limit_emission : has +operator 1--0+ limit_growth_capacity : has +operator 1--0+ limit_growth_new_capacity : has +operator 1--0+ limit_growth_new_capacity_delta : has +time_period one or zero--0+ limit_new_capacity : has +operator 1--0+ limit_new_capacity : has +operator 1--0+ limit_new_capacity_share : has +time_period one or zero--0+ limit_new_capacity_share : has +operator 1--0+ limit_resource : has +region one or zero--0+ limit_seasonal_capacity_factor : has +time_period one or zero--0+ limit_seasonal_capacity_factor : has +season_label one or zero--0+ limit_seasonal_capacity_factor : has +technology one or zero--0+ limit_seasonal_capacity_factor : has +operator 1--0+ limit_seasonal_capacity_factor : has +time_of_day one or zero--0+ limit_storage_level_fraction : has +technology one or zero--0+ limit_storage_level_fraction : has +time_period one or zero--0+ limit_storage_level_fraction : has +operator 1--0+ limit_storage_level_fraction : has +time_period one or zero--0+ limit_storage_level_fraction : has +season_label one or zero--0+ limit_storage_level_fraction : has +technology one or zero--0+ limit_tech_input_split : has +operator 1--0+ limit_tech_input_split : has +time_period one or zero--0+ limit_tech_input_split : has +commodity one or zero--0+ limit_tech_input_split : has +technology one or zero--0+ limit_tech_input_split_annual : has +operator 1--0+ limit_tech_input_split_annual : has +time_period one or zero--0+ limit_tech_input_split_annual : has +commodity one or zero--0+ limit_tech_input_split_annual : has +commodity one or zero--0+ limit_tech_output_split : has +operator 1--0+ limit_tech_output_split : has +time_period one or zero--0+ limit_tech_output_split : has +technology one or zero--0+ limit_tech_output_split : has +commodity one or zero--0+ limit_tech_output_split_annual : has +operator 1--0+ limit_tech_output_split_annual : has +time_period one or zero--0+ limit_tech_output_split_annual : has +technology one or zero--0+ limit_tech_output_split_annual : has +commodity one or zero--0+ linked_tech : has +technology one or zero--0+ linked_tech : has +technology one or zero--0+ linked_tech : has +technology one or zero--0+ loan_lifetime_process : has +time_period one or zero--0+ loan_lifetime_process : has +technology one or zero--0+ loan_rate : has +time_period one or zero--0+ loan_rate : has +technology one or zero--0+ myopic_efficiency : has +sector_label one or zero--0+ output_built_capacity : has +technology one or zero--0+ output_built_capacity : has +time_period one or zero--0+ output_built_capacity : has +time_period one or zero--0+ output_cost : has +sector_label one or zero--0+ output_cost : has +time_period one or zero--0+ output_cost : has +technology one or zero--0+ output_cost : has +time_of_day one or zero--0+ output_curtailment : has +commodity one or zero--0+ output_curtailment : has +technology one or zero--0+ output_curtailment : has +time_period one or zero--0+ output_curtailment : has +commodity one or zero--0+ output_curtailment : has +time_period one or zero--0+ output_curtailment : has +time_period one or zero--0+ output_curtailment : has +sector_label one or zero--0+ output_emission : has +time_period one or zero--0+ output_emission : has +commodity one or zero--0+ output_emission : has +technology one or zero--0+ output_emission : has +time_period one or zero--0+ output_emission : has +sector_label one or zero--0+ output_flow_in : has +time_period one or zero--0+ output_flow_in : has +season_label one or zero--0+ output_flow_in : has +time_of_day one or zero--0+ output_flow_in : has +commodity one or zero--0+ output_flow_in : has +technology one or zero--0+ output_flow_in : has +time_period one or zero--0+ output_flow_in : has +commodity one or zero--0+ output_flow_in : has +technology one or zero--0+ output_flow_out : has +time_period one or zero--0+ output_flow_out : has +commodity one or zero--0+ output_flow_out : has +sector_label one or zero--0+ output_flow_out : has +time_period one or zero--0+ output_flow_out : has +season_label one or zero--0+ output_flow_out : has +time_of_day one or zero--0+ output_flow_out : has +commodity one or zero--0+ output_flow_out : has +technology 1--0+ output_flow_out_summary : has +technology one or zero--0+ output_net_capacity : has +time_period one or zero--0+ output_net_capacity : has +sector_label one or zero--0+ output_net_capacity : has +time_period one or zero--0+ output_net_capacity : has +technology one or zero--0+ output_retired_capacity : has +time_period one or zero--0+ output_retired_capacity : has +sector_label one or zero--0+ output_retired_capacity : has +time_period one or zero--0+ output_retired_capacity : has +technology one or zero--0+ output_storage_level : has +time_period one or zero--0+ output_storage_level : has +sector_label one or zero--0+ output_storage_level : has +time_period one or zero--0+ output_storage_level : has +season_label one or zero--0+ output_storage_level : has +time_of_day one or zero--0+ output_storage_level : has +region one or zero--1 planning_reserve_margin : has +technology one or zero--0+ ramp_down_hourly : has +technology one or zero--0+ ramp_up_hourly : has +technology one or zero--0+ reserve_capacity_derate : has +time_period one or zero--0+ reserve_capacity_derate : has +season_label one or zero--0+ reserve_capacity_derate : has +time_period 1--0+ rps_requirement : has +tech_group 1--0+ rps_requirement : has +region 1--0+ rps_requirement : has +tech_group one or zero--0+ tech_group_member : has +technology one or zero--0+ tech_group_member : has +time_period one or zero--0+ time_season : has +season_label one or zero--0+ time_season : has +season_label one or zero--0+ time_season_all : has +time_period one or zero--0+ time_season_all : has +time_period one or zero--0+ time_season_sequential : has +season_label one or zero--0+ time_season_sequential : has +season_label one or zero--0+ time_season_to_sequential : has +time_period one or zero--0+ time_season_to_sequential : has +time_period one or zero--0+ time_segment_fraction : has +season_label one or zero--0+ time_segment_fraction : has +time_of_day one or zero--0+ time_segment_fraction : has diff --git a/docs/source/quick_start.rst b/docs/source/quick_start.rst index a1ead6fdf..9f7250762 100644 --- a/docs/source/quick_start.rst +++ b/docs/source/quick_start.rst @@ -121,9 +121,9 @@ the solver, and (5) to execute several of the modeling extensions. `Temoa on the cloud `, which is explained in `this video tutorial `. -==================================== +===================== Database Construction -==================================== +===================== Input datasets in Temoa are stored in a relational database management system. For those unfamiliar with databases, you can think of them as collections of @@ -132,6 +132,13 @@ tables. Within each table, a 'primary key' uniquely identifies each row. A another table, thereby establishing relationships between tables and ensuring data consistency across the database. +The following Entity-Relationship (ER) diagram provides a visual overview of the +Temoa v4 database schema and the relationships between its various tables: + +.. mermaid:: database_schema.mmd + :alt: Temoa Database Schema ER Diagram + :align: center + Temoa uses `sqlite`_, a widely used, self-contained database system. Building a database first requires constructing a sql file, which is simply a text file that defines the structure of different database tables and From 9ab789d1e90b3b9471a39087f26ebf782c49f7b4 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 15 Jan 2026 13:37:36 -0500 Subject: [PATCH 418/587] docs: switching from rtd to book theme and changing logo --- docs/source/assets/logo.pdf | Bin 0 -> 5481 bytes docs/source/assets/logo.svg | 51 +++++++++++++++ docs/source/assets/logo_bottom_text.pdf | Bin 0 -> 7202 bytes docs/source/assets/logo_bottom_text.svg | 75 ++++++++++++++++++++++ docs/source/conf.py | 36 ++++------- pyproject.toml | 2 +- requirements-dev.txt | 27 +++++--- uv.lock | 80 ++++++++++++++++++------ 8 files changed, 219 insertions(+), 52 deletions(-) create mode 100644 docs/source/assets/logo.pdf create mode 100644 docs/source/assets/logo.svg create mode 100644 docs/source/assets/logo_bottom_text.pdf create mode 100644 docs/source/assets/logo_bottom_text.svg diff --git a/docs/source/assets/logo.pdf b/docs/source/assets/logo.pdf new file mode 100644 index 0000000000000000000000000000000000000000..dacbdd101d496bdd4a38c67ded7aebce7dfb43ae GIT binary patch literal 5481 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 literal 0 HcmV?d00001 diff --git a/docs/source/assets/logo.svg b/docs/source/assets/logo.svg new file mode 100644 index 000000000..e1159b091 --- /dev/null +++ b/docs/source/assets/logo.svg @@ -0,0 +1,51 @@ + + + + + + + + + + + diff --git a/docs/source/assets/logo_bottom_text.pdf b/docs/source/assets/logo_bottom_text.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c55b0ee7f5c19cc6707315f182e5713be3adaa83 GIT binary patch literal 7202 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 + + + + + + + + + + + + + + + + + diff --git a/docs/source/conf.py b/docs/source/conf.py index 6010d5010..43934d0da 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -61,6 +61,7 @@ 'sphinx.ext.viewcode', 'myst_parser', # Enable Markdown support 'sphinxcontrib.mermaid', # Enable Mermaid diagrams + 'sphinx.ext.imgconverter', # Support SVG to PDF conversion for LaTeX ] # Add any paths that contain templates here, relative to this directory. @@ -119,30 +120,17 @@ html_static_path = ['default/static'] -# this stylesheet eliminates fixed width and is located in the _static directory -def setup(app: Any) -> None: - app.add_css_file('my_theme.css') - - -# Custom sidebar templates, must be a dictionary that maps document names -# to template names. -# -# The default sidebars (for documents that don't match any pattern) are -# defined by theme itself. Builtin themes are using these templates by -# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', -# 'searchbox.html']``. -# -# html_sidebars = {} -# import sphinx_rtd_theme - -# extensions = [ -# "sphinx_rtd_theme" -# ] - -html_theme = 'sphinx_rtd_theme' -html_logo = 'images/Temoa_logo_color_small.png' -latex_logo = 'images/TemoaLogo_grayscale.png' - +html_theme = 'sphinx_book_theme' +html_theme_options = { + 'repository_url': 'https://github.com/TemoaProject/temoa', + 'use_repository_button': True, + 'use_issues_button': True, + 'use_edit_page_button': True, + 'path_to_docs': 'docs/source', + 'show_navbar_depth': 2, +} +latex_logo = 'assets/logo_bottom_text.pdf' +html_logo = 'assets/logo_bottom_text.svg' myst_enable_extensions = ['amsmath', 'colon_fence', 'dollarmath', 'html_image'] myst_fence_as_directive = ['mermaid'] diff --git a/pyproject.toml b/pyproject.toml index d0704126c..e9fc108ca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,7 +52,7 @@ dev = [ [project.optional-dependencies] docs = [ "sphinx>=7.4.7", - "sphinx-rtd-theme>=2.0.0", + "sphinx-book-theme>=1.1.3", "sphinxcontrib-htmlhelp>=2.1.0", "sphinxcontrib-serializinghtml>=2.0.0", "sphinxcontrib-bibtex>=2.6.2", diff --git a/requirements-dev.txt b/requirements-dev.txt index e845fadf9..71efc37c9 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,9 +1,15 @@ # This file was autogenerated by uv via the following command: # uv pip compile pyproject.toml --all-extras -o requirements-dev.txt +accessible-pygments==0.0.5 + # via pydata-sphinx-theme alabaster==1.0.0 # via sphinx babel==2.17.0 - # via sphinx + # via + # pydata-sphinx-theme + # sphinx +beautifulsoup4==4.14.3 + # via pydata-sphinx-theme certifi==2025.7.14 # via requests charset-normalizer==3.4.2 @@ -22,8 +28,8 @@ docutils==0.21.2 # via # myst-parser # pybtex-docutils + # pydata-sphinx-theme # sphinx - # sphinx-rtd-theme # sphinxcontrib-bibtex et-xmlfile==2.0.0 # via openpyxl @@ -95,6 +101,7 @@ openpyxl==3.1.5 packaging==25.0 # via # matplotlib + # pydata-sphinx-theme # pytest # sphinx pandas==2.3.1 @@ -118,8 +125,12 @@ pybtex==0.25.1 # sphinxcontrib-bibtex pybtex-docutils==1.0.3 # via sphinxcontrib-bibtex +pydata-sphinx-theme==0.15.4 + # via sphinx-book-theme pygments==2.19.2 # via + # accessible-pygments + # pydata-sphinx-theme # pytest # rich # sphinx @@ -165,15 +176,17 @@ six==1.17.0 # via python-dateutil snowballstemmer==3.0.1 # via sphinx +soupsieve==2.8.1 + # via beautifulsoup4 sphinx==8.2.3 # via # temoa (pyproject.toml) # myst-parser - # sphinx-rtd-theme + # pydata-sphinx-theme + # sphinx-book-theme # sphinxcontrib-bibtex - # sphinxcontrib-jquery # sphinxcontrib-mermaid -sphinx-rtd-theme==3.0.2 +sphinx-book-theme==1.1.4 # via temoa (pyproject.toml) sphinxcontrib-applehelp==2.0.0 # via sphinx @@ -185,8 +198,6 @@ sphinxcontrib-htmlhelp==2.1.0 # via # temoa (pyproject.toml) # sphinx -sphinxcontrib-jquery==4.1 - # via sphinx-rtd-theme sphinxcontrib-jsmath==1.0.1 # via sphinx sphinxcontrib-mermaid==1.2.3 @@ -205,9 +216,11 @@ typer==0.20.0 # via temoa (pyproject.toml) typing-extensions==4.15.0 # via + # beautifulsoup4 # flexcache # flexparser # pint + # pydata-sphinx-theme # typer tzdata==2025.2 # via pandas diff --git a/uv.lock b/uv.lock index dbce91d1b..5930c5dc1 100644 --- a/uv.lock +++ b/uv.lock @@ -2,6 +2,18 @@ version = 1 revision = 3 requires-python = ">=3.12" +[[package]] +name = "accessible-pygments" +version = "0.0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/c1/bbac6a50d02774f91572938964c582fff4270eee73ab822a4aeea4d8b11b/accessible_pygments-0.0.5.tar.gz", hash = "sha256:40918d3e6a2b619ad424cb91e556bd3bd8865443d9f22f1dcdf79e33c8046872", size = 1377899, upload-time = "2024-05-10T11:23:10.216Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/3f/95338030883d8c8b91223b4e21744b04d11b161a3ef117295d8241f50ab4/accessible_pygments-0.0.5-py3-none-any.whl", hash = "sha256:88ae3211e68a1d0b011504b2ffc1691feafce124b845bd072ab6f9f66f34d4b7", size = 1395903, upload-time = "2024-05-10T11:23:08.421Z" }, +] + [[package]] name = "alabaster" version = "1.0.0" @@ -20,6 +32,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, ] +[[package]] +name = "beautifulsoup4" +version = "4.14.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737, upload-time = "2025-11-30T15:08:26.084Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721, upload-time = "2025-11-30T15:08:24.087Z" }, +] + [[package]] name = "certifi" version = "2025.7.14" @@ -940,6 +965,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/11/b1/ce1f4596211efb5410e178a803f08e59b20bedb66837dcf41e21c54f9ec1/pybtex_docutils-1.0.3-py3-none-any.whl", hash = "sha256:8fd290d2ae48e32fcb54d86b0efb8d573198653c7e2447d5bec5847095f430b9", size = 6385, upload-time = "2023-08-22T06:43:20.513Z" }, ] +[[package]] +name = "pydata-sphinx-theme" +version = "0.15.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "accessible-pygments" }, + { name = "babel" }, + { name = "beautifulsoup4" }, + { name = "docutils" }, + { name = "packaging" }, + { name = "pygments" }, + { name = "sphinx" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/67/ea/3ab478cccacc2e8ef69892c42c44ae547bae089f356c4b47caf61730958d/pydata_sphinx_theme-0.15.4.tar.gz", hash = "sha256:7762ec0ac59df3acecf49fd2f889e1b4565dbce8b88b2e29ee06fdd90645a06d", size = 2400673, upload-time = "2024-06-25T19:28:45.041Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/d3/c622950d87a2ffd1654208733b5bd1c5645930014abed8f4c0d74863988b/pydata_sphinx_theme-0.15.4-py3-none-any.whl", hash = "sha256:2136ad0e9500d0949f96167e63f3e298620040aea8f9c74621959eda5d4cf8e6", size = 4640157, upload-time = "2024-06-25T19:28:42.383Z" }, +] + [[package]] name = "pygments" version = "2.19.2" @@ -1243,6 +1287,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c8/78/3565d011c61f5a43488987ee32b6f3f656e7f107ac2782dd57bdd7d91d9a/snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064", size = 103274, upload-time = "2025-05-09T16:34:50.371Z" }, ] +[[package]] +name = "soupsieve" +version = "2.8.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/89/23/adf3796d740536d63a6fbda113d07e60c734b6ed5d3058d1e47fc0495e47/soupsieve-2.8.1.tar.gz", hash = "sha256:4cf733bc50fa805f5df4b8ef4740fc0e0fa6218cf3006269afd3f9d6d80fd350", size = 117856, upload-time = "2025-12-18T13:50:34.655Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/f3/b67d6ea49ca9154453b6d70b34ea22f3996b9fa55da105a79d8732227adc/soupsieve-2.8.1-py3-none-any.whl", hash = "sha256:a11fe2a6f3d76ab3cf2de04eb339c1be5b506a8a47f2ceb6d139803177f85434", size = 36710, upload-time = "2025-12-18T13:50:33.267Z" }, +] + [[package]] name = "sphinx" version = "8.2.3" @@ -1272,17 +1325,16 @@ wheels = [ ] [[package]] -name = "sphinx-rtd-theme" -version = "3.0.2" +name = "sphinx-book-theme" +version = "1.1.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "docutils" }, + { name = "pydata-sphinx-theme" }, { name = "sphinx" }, - { name = "sphinxcontrib-jquery" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/91/44/c97faec644d29a5ceddd3020ae2edffa69e7d00054a8c7a6021e82f20335/sphinx_rtd_theme-3.0.2.tar.gz", hash = "sha256:b7457bc25dda723b20b086a670b9953c859eab60a2a03ee8eb2bb23e176e5f85", size = 7620463, upload-time = "2024-11-13T11:06:04.545Z" } +sdist = { url = "https://files.pythonhosted.org/packages/45/19/d002ed96bdc7738c15847c730e1e88282d738263deac705d5713b4d8fa94/sphinx_book_theme-1.1.4.tar.gz", hash = "sha256:73efe28af871d0a89bd05856d300e61edce0d5b2fbb7984e84454be0fedfe9ed", size = 439188, upload-time = "2025-02-20T16:32:32.581Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/85/77/46e3bac77b82b4df5bb5b61f2de98637724f246b4966cfc34bc5895d852a/sphinx_rtd_theme-3.0.2-py2.py3-none-any.whl", hash = "sha256:422ccc750c3a3a311de4ae327e82affdaf59eb695ba4936538552f3b00f4ee13", size = 7655561, upload-time = "2024-11-13T11:06:02.094Z" }, + { url = "https://files.pythonhosted.org/packages/51/9e/c41d68be04eef5b6202b468e0f90faf0c469f3a03353f2a218fd78279710/sphinx_book_theme-1.1.4-py3-none-any.whl", hash = "sha256:843b3f5c8684640f4a2d01abd298beb66452d1b2394cd9ef5be5ebd5640ea0e1", size = 433952, upload-time = "2025-02-20T16:32:31.009Z" }, ] [[package]] @@ -1327,18 +1379,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705, upload-time = "2024-07-29T01:09:36.407Z" }, ] -[[package]] -name = "sphinxcontrib-jquery" -version = "4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/de/f3/aa67467e051df70a6330fe7770894b3e4f09436dea6881ae0b4f3d87cad8/sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a", size = 122331, upload-time = "2023-03-14T15:01:01.944Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/85/749bd22d1a68db7291c89e2ebca53f4306c3f205853cf31e9de279034c3c/sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae", size = 121104, upload-time = "2023-03-14T15:01:00.356Z" }, -] - [[package]] name = "sphinxcontrib-jsmath" version = "1.0.1" @@ -1419,7 +1459,7 @@ dependencies = [ docs = [ { name = "myst-parser" }, { name = "sphinx" }, - { name = "sphinx-rtd-theme" }, + { name = "sphinx-book-theme" }, { name = "sphinxcontrib-bibtex" }, { name = "sphinxcontrib-htmlhelp" }, { name = "sphinxcontrib-mermaid" }, @@ -1469,7 +1509,7 @@ requires-dist = [ { name = "seaborn", specifier = ">=0.13.2" }, { name = "seaborn", marker = "extra == 'plotting'", specifier = ">=0.13.2" }, { name = "sphinx", marker = "extra == 'docs'", specifier = ">=7.4.7" }, - { name = "sphinx-rtd-theme", marker = "extra == 'docs'", specifier = ">=2.0.0" }, + { name = "sphinx-book-theme", marker = "extra == 'docs'", specifier = ">=1.1.3" }, { name = "sphinxcontrib-bibtex", marker = "extra == 'docs'", specifier = ">=2.6.2" }, { name = "sphinxcontrib-htmlhelp", marker = "extra == 'docs'", specifier = ">=2.1.0" }, { name = "sphinxcontrib-mermaid", marker = "extra == 'docs'", specifier = ">=1.2.3" }, From 8f6871a8e739360680edf49d7d33f38e31bf2f9b Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 23 Jan 2026 13:18:19 -0500 Subject: [PATCH 419/587] chore: updating packages to latest compatible versions, making filter warnings less strict on dependencies --- pyproject.toml | 19 +- requirements-dev.txt | 2 +- uv.lock | 1622 +++++++++++++++++++++++++----------------- 3 files changed, 967 insertions(+), 676 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e9fc108ca..2810d00dd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ authors = [ dependencies = [ "pyomo>=6.8.0", - "matplotlib==3.9.2", + "matplotlib>=3.9.2", "pandas>=2.2.2", "numpy>=2.1.0", "joblib", @@ -65,7 +65,7 @@ plotting = [ "seaborn>=0.13.2", ] solver = [ - "gurobipy>=12.0.3,<13", + "gurobipy>=12.0.3", ] [build-system] @@ -125,12 +125,15 @@ testpaths = [ "tests", ] filterwarnings = [ - # Raise all warnings as errors except for the ones we specifically ignore - "error::DeprecationWarning", - "error::FutureWarning", - "error::RuntimeWarning", - "error::UserWarning", - + # Treat warnings from temoa and tests as errors + "error::DeprecationWarning:temoa.*", + "error::FutureWarning:temoa.*", + "error::RuntimeWarning:temoa.*", + "error::UserWarning:temoa.*", + "error::DeprecationWarning:tests.*", + "error::FutureWarning:tests.*", + "error::RuntimeWarning:tests.*", + "error::UserWarning:tests.*", ] [tool.mypy] diff --git a/requirements-dev.txt b/requirements-dev.txt index 71efc37c9..8a0497d63 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -41,7 +41,7 @@ fonttools==4.59.0 # via matplotlib graphviz==0.21 # via temoa (pyproject.toml) -gurobipy==12.0.3 +gurobipy==13.0.1 # via temoa (pyproject.toml) highspy==1.11.0 # via temoa (pyproject.toml) diff --git a/uv.lock b/uv.lock index 5930c5dc1..03000af98 100644 --- a/uv.lock +++ b/uv.lock @@ -1,6 +1,14 @@ version = 1 revision = 3 requires-python = ">=3.12" +resolution-markers = [ + "python_full_version >= '3.14' and sys_platform == 'win32'", + "python_full_version >= '3.14' and sys_platform == 'emscripten'", + "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version < '3.14' and sys_platform == 'win32'", + "python_full_version < '3.14' and sys_platform == 'emscripten'", + "python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", +] [[package]] name = "accessible-pygments" @@ -47,67 +55,89 @@ wheels = [ [[package]] name = "certifi" -version = "2025.7.14" +version = "2026.1.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b3/76/52c535bcebe74590f296d6c77c86dabf761c41980e1347a2422e4aa2ae41/certifi-2025.7.14.tar.gz", hash = "sha256:8ea99dbdfaaf2ba2f9bac77b9249ef62ec5218e7c2b2e903378ed5fccf765995", size = 163981, upload-time = "2025-07-14T03:29:28.449Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4f/52/34c6cf5bb9285074dc3531c437b3919e825d976fde097a7a73f79e726d03/certifi-2025.7.14-py3-none-any.whl", hash = "sha256:6b31f564a415d79ee77df69d757bb49a5bb53bd9f756cbbe24394ffd6fc1f4b2", size = 162722, upload-time = "2025-07-14T03:29:26.863Z" }, + { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, ] [[package]] name = "cfgv" -version = "3.4.0" +version = "3.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114, upload-time = "2023-08-12T20:38:17.776Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249, upload-time = "2023-08-12T20:38:16.269Z" }, + { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, ] [[package]] name = "charset-normalizer" -version = "3.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload-time = "2025-05-02T08:32:33.712Z" }, - { url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload-time = "2025-05-02T08:32:35.768Z" }, - { url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload-time = "2025-05-02T08:32:37.284Z" }, - { url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload-time = "2025-05-02T08:32:38.803Z" }, - { url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload-time = "2025-05-02T08:32:40.251Z" }, - { url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload-time = "2025-05-02T08:32:41.705Z" }, - { url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload-time = "2025-05-02T08:32:43.709Z" }, - { url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload-time = "2025-05-02T08:32:46.197Z" }, - { url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload-time = "2025-05-02T08:32:48.105Z" }, - { url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload-time = "2025-05-02T08:32:49.719Z" }, - { url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload-time = "2025-05-02T08:32:51.404Z" }, - { url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload-time = "2025-05-02T08:32:53.079Z" }, - { url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload-time = "2025-05-02T08:32:54.573Z" }, - { url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload-time = "2025-05-02T08:32:56.363Z" }, - { url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload-time = "2025-05-02T08:32:58.551Z" }, - { url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload-time = "2025-05-02T08:33:00.342Z" }, - { url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload-time = "2025-05-02T08:33:02.081Z" }, - { url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload-time = "2025-05-02T08:33:04.063Z" }, - { url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload-time = "2025-05-02T08:33:06.418Z" }, - { url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload-time = "2025-05-02T08:33:08.183Z" }, - { url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload-time = "2025-05-02T08:33:09.986Z" }, - { url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload-time = "2025-05-02T08:33:11.814Z" }, - { url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload-time = "2025-05-02T08:33:13.707Z" }, - { url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload-time = "2025-05-02T08:33:15.458Z" }, - { url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload-time = "2025-05-02T08:33:17.06Z" }, - { url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload-time = "2025-05-02T08:33:18.753Z" }, - { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" }, + { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" }, + { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" }, + { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" }, + { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" }, + { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" }, + { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" }, + { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" }, + { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" }, + { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" }, + { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" }, + { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" }, + { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" }, + { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" }, + { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" }, + { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" }, + { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" }, + { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" }, + { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" }, + { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" }, + { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" }, + { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" }, + { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" }, + { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" }, + { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" }, + { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" }, + { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" }, + { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" }, + { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" }, + { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" }, + { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" }, + { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" }, + { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" }, + { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" }, + { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" }, + { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" }, + { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" }, + { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" }, + { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, ] [[package]] name = "click" -version = "8.3.0" +version = "8.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/46/61/de6cd827efad202d7057d93e0fed9294b96952e188f7384832791c7b2254/click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4", size = 276943, upload-time = "2025-09-18T17:32:23.696Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/db/d3/9dcc0f5797f070ec8edf30fbadfb200e71d9db6b84d211e3b2085a7589a0/click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc", size = 107295, upload-time = "2025-09-18T17:32:22.42Z" }, + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, ] [[package]] @@ -121,85 +151,142 @@ wheels = [ [[package]] name = "contourpy" -version = "1.3.2" +version = "1.3.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130, upload-time = "2025-04-15T17:47:53.79Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/34/f7/44785876384eff370c251d58fd65f6ad7f39adce4a093c934d4a67a7c6b6/contourpy-1.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4caf2bcd2969402bf77edc4cb6034c7dd7c0803213b3523f111eb7460a51b8d2", size = 271580, upload-time = "2025-04-15T17:37:03.105Z" }, - { url = "https://files.pythonhosted.org/packages/93/3b/0004767622a9826ea3d95f0e9d98cd8729015768075d61f9fea8eeca42a8/contourpy-1.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:82199cb78276249796419fe36b7386bd8d2cc3f28b3bc19fe2454fe2e26c4c15", size = 255530, upload-time = "2025-04-15T17:37:07.026Z" }, - { url = "https://files.pythonhosted.org/packages/e7/bb/7bd49e1f4fa805772d9fd130e0d375554ebc771ed7172f48dfcd4ca61549/contourpy-1.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:106fab697af11456fcba3e352ad50effe493a90f893fca6c2ca5c033820cea92", size = 307688, upload-time = "2025-04-15T17:37:11.481Z" }, - { url = "https://files.pythonhosted.org/packages/fc/97/e1d5dbbfa170725ef78357a9a0edc996b09ae4af170927ba8ce977e60a5f/contourpy-1.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d14f12932a8d620e307f715857107b1d1845cc44fdb5da2bc8e850f5ceba9f87", size = 347331, upload-time = "2025-04-15T17:37:18.212Z" }, - { url = "https://files.pythonhosted.org/packages/6f/66/e69e6e904f5ecf6901be3dd16e7e54d41b6ec6ae3405a535286d4418ffb4/contourpy-1.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:532fd26e715560721bb0d5fc7610fce279b3699b018600ab999d1be895b09415", size = 318963, upload-time = "2025-04-15T17:37:22.76Z" }, - { url = "https://files.pythonhosted.org/packages/a8/32/b8a1c8965e4f72482ff2d1ac2cd670ce0b542f203c8e1d34e7c3e6925da7/contourpy-1.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b383144cf2d2c29f01a1e8170f50dacf0eac02d64139dcd709a8ac4eb3cfe", size = 323681, upload-time = "2025-04-15T17:37:33.001Z" }, - { url = "https://files.pythonhosted.org/packages/30/c6/12a7e6811d08757c7162a541ca4c5c6a34c0f4e98ef2b338791093518e40/contourpy-1.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c49f73e61f1f774650a55d221803b101d966ca0c5a2d6d5e4320ec3997489441", size = 1308674, upload-time = "2025-04-15T17:37:48.64Z" }, - { url = "https://files.pythonhosted.org/packages/2a/8a/bebe5a3f68b484d3a2b8ffaf84704b3e343ef1addea528132ef148e22b3b/contourpy-1.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3d80b2c0300583228ac98d0a927a1ba6a2ba6b8a742463c564f1d419ee5b211e", size = 1380480, upload-time = "2025-04-15T17:38:06.7Z" }, - { url = "https://files.pythonhosted.org/packages/34/db/fcd325f19b5978fb509a7d55e06d99f5f856294c1991097534360b307cf1/contourpy-1.3.2-cp312-cp312-win32.whl", hash = "sha256:90df94c89a91b7362e1142cbee7568f86514412ab8a2c0d0fca72d7e91b62912", size = 178489, upload-time = "2025-04-15T17:38:10.338Z" }, - { url = "https://files.pythonhosted.org/packages/01/c8/fadd0b92ffa7b5eb5949bf340a63a4a496a6930a6c37a7ba0f12acb076d6/contourpy-1.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:8c942a01d9163e2e5cfb05cb66110121b8d07ad438a17f9e766317bcb62abf73", size = 223042, upload-time = "2025-04-15T17:38:14.239Z" }, - { url = "https://files.pythonhosted.org/packages/2e/61/5673f7e364b31e4e7ef6f61a4b5121c5f170f941895912f773d95270f3a2/contourpy-1.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:de39db2604ae755316cb5967728f4bea92685884b1e767b7c24e983ef5f771cb", size = 271630, upload-time = "2025-04-15T17:38:19.142Z" }, - { url = "https://files.pythonhosted.org/packages/ff/66/a40badddd1223822c95798c55292844b7e871e50f6bfd9f158cb25e0bd39/contourpy-1.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3f9e896f447c5c8618f1edb2bafa9a4030f22a575ec418ad70611450720b5b08", size = 255670, upload-time = "2025-04-15T17:38:23.688Z" }, - { url = "https://files.pythonhosted.org/packages/1e/c7/cf9fdee8200805c9bc3b148f49cb9482a4e3ea2719e772602a425c9b09f8/contourpy-1.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71e2bd4a1c4188f5c2b8d274da78faab884b59df20df63c34f74aa1813c4427c", size = 306694, upload-time = "2025-04-15T17:38:28.238Z" }, - { url = "https://files.pythonhosted.org/packages/dd/e7/ccb9bec80e1ba121efbffad7f38021021cda5be87532ec16fd96533bb2e0/contourpy-1.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de425af81b6cea33101ae95ece1f696af39446db9682a0b56daaa48cfc29f38f", size = 345986, upload-time = "2025-04-15T17:38:33.502Z" }, - { url = "https://files.pythonhosted.org/packages/dc/49/ca13bb2da90391fa4219fdb23b078d6065ada886658ac7818e5441448b78/contourpy-1.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:977e98a0e0480d3fe292246417239d2d45435904afd6d7332d8455981c408b85", size = 318060, upload-time = "2025-04-15T17:38:38.672Z" }, - { url = "https://files.pythonhosted.org/packages/c8/65/5245ce8c548a8422236c13ffcdcdada6a2a812c361e9e0c70548bb40b661/contourpy-1.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:434f0adf84911c924519d2b08fc10491dd282b20bdd3fa8f60fd816ea0b48841", size = 322747, upload-time = "2025-04-15T17:38:43.712Z" }, - { url = "https://files.pythonhosted.org/packages/72/30/669b8eb48e0a01c660ead3752a25b44fdb2e5ebc13a55782f639170772f9/contourpy-1.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c66c4906cdbc50e9cba65978823e6e00b45682eb09adbb78c9775b74eb222422", size = 1308895, upload-time = "2025-04-15T17:39:00.224Z" }, - { url = "https://files.pythonhosted.org/packages/05/5a/b569f4250decee6e8d54498be7bdf29021a4c256e77fe8138c8319ef8eb3/contourpy-1.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8b7fc0cd78ba2f4695fd0a6ad81a19e7e3ab825c31b577f384aa9d7817dc3bef", size = 1379098, upload-time = "2025-04-15T17:43:29.649Z" }, - { url = "https://files.pythonhosted.org/packages/19/ba/b227c3886d120e60e41b28740ac3617b2f2b971b9f601c835661194579f1/contourpy-1.3.2-cp313-cp313-win32.whl", hash = "sha256:15ce6ab60957ca74cff444fe66d9045c1fd3e92c8936894ebd1f3eef2fff075f", size = 178535, upload-time = "2025-04-15T17:44:44.532Z" }, - { url = "https://files.pythonhosted.org/packages/12/6e/2fed56cd47ca739b43e892707ae9a13790a486a3173be063681ca67d2262/contourpy-1.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e1578f7eafce927b168752ed7e22646dad6cd9bca673c60bff55889fa236ebf9", size = 223096, upload-time = "2025-04-15T17:44:48.194Z" }, - { url = "https://files.pythonhosted.org/packages/54/4c/e76fe2a03014a7c767d79ea35c86a747e9325537a8b7627e0e5b3ba266b4/contourpy-1.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0475b1f6604896bc7c53bb070e355e9321e1bc0d381735421a2d2068ec56531f", size = 285090, upload-time = "2025-04-15T17:43:34.084Z" }, - { url = "https://files.pythonhosted.org/packages/7b/e2/5aba47debd55d668e00baf9651b721e7733975dc9fc27264a62b0dd26eb8/contourpy-1.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c85bb486e9be652314bb5b9e2e3b0d1b2e643d5eec4992c0fbe8ac71775da739", size = 268643, upload-time = "2025-04-15T17:43:38.626Z" }, - { url = "https://files.pythonhosted.org/packages/a1/37/cd45f1f051fe6230f751cc5cdd2728bb3a203f5619510ef11e732109593c/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:745b57db7758f3ffc05a10254edd3182a2a83402a89c00957a8e8a22f5582823", size = 310443, upload-time = "2025-04-15T17:43:44.522Z" }, - { url = "https://files.pythonhosted.org/packages/8b/a2/36ea6140c306c9ff6dd38e3bcec80b3b018474ef4d17eb68ceecd26675f4/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:970e9173dbd7eba9b4e01aab19215a48ee5dd3f43cef736eebde064a171f89a5", size = 349865, upload-time = "2025-04-15T17:43:49.545Z" }, - { url = "https://files.pythonhosted.org/packages/95/b7/2fc76bc539693180488f7b6cc518da7acbbb9e3b931fd9280504128bf956/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6c4639a9c22230276b7bffb6a850dfc8258a2521305e1faefe804d006b2e532", size = 321162, upload-time = "2025-04-15T17:43:54.203Z" }, - { url = "https://files.pythonhosted.org/packages/f4/10/76d4f778458b0aa83f96e59d65ece72a060bacb20cfbee46cf6cd5ceba41/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc829960f34ba36aad4302e78eabf3ef16a3a100863f0d4eeddf30e8a485a03b", size = 327355, upload-time = "2025-04-15T17:44:01.025Z" }, - { url = "https://files.pythonhosted.org/packages/43/a3/10cf483ea683f9f8ab096c24bad3cce20e0d1dd9a4baa0e2093c1c962d9d/contourpy-1.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d32530b534e986374fc19eaa77fcb87e8a99e5431499949b828312bdcd20ac52", size = 1307935, upload-time = "2025-04-15T17:44:17.322Z" }, - { url = "https://files.pythonhosted.org/packages/78/73/69dd9a024444489e22d86108e7b913f3528f56cfc312b5c5727a44188471/contourpy-1.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e298e7e70cf4eb179cc1077be1c725b5fd131ebc81181bf0c03525c8abc297fd", size = 1372168, upload-time = "2025-04-15T17:44:33.43Z" }, - { url = "https://files.pythonhosted.org/packages/0f/1b/96d586ccf1b1a9d2004dd519b25fbf104a11589abfd05484ff12199cca21/contourpy-1.3.2-cp313-cp313t-win32.whl", hash = "sha256:d0e589ae0d55204991450bb5c23f571c64fe43adaa53f93fc902a84c96f52fe1", size = 189550, upload-time = "2025-04-15T17:44:37.092Z" }, - { url = "https://files.pythonhosted.org/packages/b0/e6/6000d0094e8a5e32ad62591c8609e269febb6e4db83a1c75ff8868b42731/contourpy-1.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:78e9253c3de756b3f6a5174d024c4835acd59eb3f8e2ca13e775dbffe1558f69", size = 238214, upload-time = "2025-04-15T17:44:40.827Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/45/adfee365d9ea3d853550b2e735f9d66366701c65db7855cd07621732ccfc/contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb", size = 293419, upload-time = "2025-07-26T12:01:21.16Z" }, + { url = "https://files.pythonhosted.org/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6", size = 273979, upload-time = "2025-07-26T12:01:22.448Z" }, + { url = "https://files.pythonhosted.org/packages/d4/1c/a12359b9b2ca3a845e8f7f9ac08bdf776114eb931392fcad91743e2ea17b/contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7", size = 332653, upload-time = "2025-07-26T12:01:24.155Z" }, + { url = "https://files.pythonhosted.org/packages/63/12/897aeebfb475b7748ea67b61e045accdfcf0d971f8a588b67108ed7f5512/contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8", size = 379536, upload-time = "2025-07-26T12:01:25.91Z" }, + { url = "https://files.pythonhosted.org/packages/43/8a/a8c584b82deb248930ce069e71576fc09bd7174bbd35183b7943fb1064fd/contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea", size = 384397, upload-time = "2025-07-26T12:01:27.152Z" }, + { url = "https://files.pythonhosted.org/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1", size = 362601, upload-time = "2025-07-26T12:01:28.808Z" }, + { url = "https://files.pythonhosted.org/packages/05/0a/a3fe3be3ee2dceb3e615ebb4df97ae6f3828aa915d3e10549ce016302bd1/contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7", size = 1331288, upload-time = "2025-07-26T12:01:31.198Z" }, + { url = "https://files.pythonhosted.org/packages/33/1d/acad9bd4e97f13f3e2b18a3977fe1b4a37ecf3d38d815333980c6c72e963/contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411", size = 1403386, upload-time = "2025-07-26T12:01:33.947Z" }, + { url = "https://files.pythonhosted.org/packages/cf/8f/5847f44a7fddf859704217a99a23a4f6417b10e5ab1256a179264561540e/contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69", size = 185018, upload-time = "2025-07-26T12:01:35.64Z" }, + { url = "https://files.pythonhosted.org/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b", size = 226567, upload-time = "2025-07-26T12:01:36.804Z" }, + { url = "https://files.pythonhosted.org/packages/d1/e2/f05240d2c39a1ed228d8328a78b6f44cd695f7ef47beb3e684cf93604f86/contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc", size = 193655, upload-time = "2025-07-26T12:01:37.999Z" }, + { url = "https://files.pythonhosted.org/packages/68/35/0167aad910bbdb9599272bd96d01a9ec6852f36b9455cf2ca67bd4cc2d23/contourpy-1.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:177fb367556747a686509d6fef71d221a4b198a3905fe824430e5ea0fda54eb5", size = 293257, upload-time = "2025-07-26T12:01:39.367Z" }, + { url = "https://files.pythonhosted.org/packages/96/e4/7adcd9c8362745b2210728f209bfbcf7d91ba868a2c5f40d8b58f54c509b/contourpy-1.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d002b6f00d73d69333dac9d0b8d5e84d9724ff9ef044fd63c5986e62b7c9e1b1", size = 274034, upload-time = "2025-07-26T12:01:40.645Z" }, + { url = "https://files.pythonhosted.org/packages/73/23/90e31ceeed1de63058a02cb04b12f2de4b40e3bef5e082a7c18d9c8ae281/contourpy-1.3.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:348ac1f5d4f1d66d3322420f01d42e43122f43616e0f194fc1c9f5d830c5b286", size = 334672, upload-time = "2025-07-26T12:01:41.942Z" }, + { url = "https://files.pythonhosted.org/packages/ed/93/b43d8acbe67392e659e1d984700e79eb67e2acb2bd7f62012b583a7f1b55/contourpy-1.3.3-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:655456777ff65c2c548b7c454af9c6f33f16c8884f11083244b5819cc214f1b5", size = 381234, upload-time = "2025-07-26T12:01:43.499Z" }, + { url = "https://files.pythonhosted.org/packages/46/3b/bec82a3ea06f66711520f75a40c8fc0b113b2a75edb36aa633eb11c4f50f/contourpy-1.3.3-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:644a6853d15b2512d67881586bd03f462c7ab755db95f16f14d7e238f2852c67", size = 385169, upload-time = "2025-07-26T12:01:45.219Z" }, + { url = "https://files.pythonhosted.org/packages/4b/32/e0f13a1c5b0f8572d0ec6ae2f6c677b7991fafd95da523159c19eff0696a/contourpy-1.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4debd64f124ca62069f313a9cb86656ff087786016d76927ae2cf37846b006c9", size = 362859, upload-time = "2025-07-26T12:01:46.519Z" }, + { url = "https://files.pythonhosted.org/packages/33/71/e2a7945b7de4e58af42d708a219f3b2f4cff7386e6b6ab0a0fa0033c49a9/contourpy-1.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a15459b0f4615b00bbd1e91f1b9e19b7e63aea7483d03d804186f278c0af2659", size = 1332062, upload-time = "2025-07-26T12:01:48.964Z" }, + { url = "https://files.pythonhosted.org/packages/12/fc/4e87ac754220ccc0e807284f88e943d6d43b43843614f0a8afa469801db0/contourpy-1.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca0fdcd73925568ca027e0b17ab07aad764be4706d0a925b89227e447d9737b7", size = 1403932, upload-time = "2025-07-26T12:01:51.979Z" }, + { url = "https://files.pythonhosted.org/packages/a6/2e/adc197a37443f934594112222ac1aa7dc9a98faf9c3842884df9a9d8751d/contourpy-1.3.3-cp313-cp313-win32.whl", hash = "sha256:b20c7c9a3bf701366556e1b1984ed2d0cedf999903c51311417cf5f591d8c78d", size = 185024, upload-time = "2025-07-26T12:01:53.245Z" }, + { url = "https://files.pythonhosted.org/packages/18/0b/0098c214843213759692cc638fce7de5c289200a830e5035d1791d7a2338/contourpy-1.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:1cadd8b8969f060ba45ed7c1b714fe69185812ab43bd6b86a9123fe8f99c3263", size = 226578, upload-time = "2025-07-26T12:01:54.422Z" }, + { url = "https://files.pythonhosted.org/packages/8a/9a/2f6024a0c5995243cd63afdeb3651c984f0d2bc727fd98066d40e141ad73/contourpy-1.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:fd914713266421b7536de2bfa8181aa8c699432b6763a0ea64195ebe28bff6a9", size = 193524, upload-time = "2025-07-26T12:01:55.73Z" }, + { url = "https://files.pythonhosted.org/packages/c0/b3/f8a1a86bd3298513f500e5b1f5fd92b69896449f6cab6a146a5d52715479/contourpy-1.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:88df9880d507169449d434c293467418b9f6cbe82edd19284aa0409e7fdb933d", size = 306730, upload-time = "2025-07-26T12:01:57.051Z" }, + { url = "https://files.pythonhosted.org/packages/3f/11/4780db94ae62fc0c2053909b65dc3246bd7cecfc4f8a20d957ad43aa4ad8/contourpy-1.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d06bb1f751ba5d417047db62bca3c8fde202b8c11fb50742ab3ab962c81e8216", size = 287897, upload-time = "2025-07-26T12:01:58.663Z" }, + { url = "https://files.pythonhosted.org/packages/ae/15/e59f5f3ffdd6f3d4daa3e47114c53daabcb18574a26c21f03dc9e4e42ff0/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4e6b05a45525357e382909a4c1600444e2a45b4795163d3b22669285591c1ae", size = 326751, upload-time = "2025-07-26T12:02:00.343Z" }, + { url = "https://files.pythonhosted.org/packages/0f/81/03b45cfad088e4770b1dcf72ea78d3802d04200009fb364d18a493857210/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ab3074b48c4e2cf1a960e6bbeb7f04566bf36b1861d5c9d4d8ac04b82e38ba20", size = 375486, upload-time = "2025-07-26T12:02:02.128Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ba/49923366492ffbdd4486e970d421b289a670ae8cf539c1ea9a09822b371a/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c3d53c796f8647d6deb1abe867daeb66dcc8a97e8455efa729516b997b8ed99", size = 388106, upload-time = "2025-07-26T12:02:03.615Z" }, + { url = "https://files.pythonhosted.org/packages/9f/52/5b00ea89525f8f143651f9f03a0df371d3cbd2fccd21ca9b768c7a6500c2/contourpy-1.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50ed930df7289ff2a8d7afeb9603f8289e5704755c7e5c3bbd929c90c817164b", size = 352548, upload-time = "2025-07-26T12:02:05.165Z" }, + { url = "https://files.pythonhosted.org/packages/32/1d/a209ec1a3a3452d490f6b14dd92e72280c99ae3d1e73da74f8277d4ee08f/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4feffb6537d64b84877da813a5c30f1422ea5739566abf0bd18065ac040e120a", size = 1322297, upload-time = "2025-07-26T12:02:07.379Z" }, + { url = "https://files.pythonhosted.org/packages/bc/9e/46f0e8ebdd884ca0e8877e46a3f4e633f6c9c8c4f3f6e72be3fe075994aa/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2b7e9480ffe2b0cd2e787e4df64270e3a0440d9db8dc823312e2c940c167df7e", size = 1391023, upload-time = "2025-07-26T12:02:10.171Z" }, + { url = "https://files.pythonhosted.org/packages/b9/70/f308384a3ae9cd2209e0849f33c913f658d3326900d0ff5d378d6a1422d2/contourpy-1.3.3-cp313-cp313t-win32.whl", hash = "sha256:283edd842a01e3dcd435b1c5116798d661378d83d36d337b8dde1d16a5fc9ba3", size = 196157, upload-time = "2025-07-26T12:02:11.488Z" }, + { url = "https://files.pythonhosted.org/packages/b2/dd/880f890a6663b84d9e34a6f88cded89d78f0091e0045a284427cb6b18521/contourpy-1.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:87acf5963fc2b34825e5b6b048f40e3635dd547f590b04d2ab317c2619ef7ae8", size = 240570, upload-time = "2025-07-26T12:02:12.754Z" }, + { url = "https://files.pythonhosted.org/packages/80/99/2adc7d8ffead633234817ef8e9a87115c8a11927a94478f6bb3d3f4d4f7d/contourpy-1.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:3c30273eb2a55024ff31ba7d052dde990d7d8e5450f4bbb6e913558b3d6c2301", size = 199713, upload-time = "2025-07-26T12:02:14.4Z" }, + { url = "https://files.pythonhosted.org/packages/72/8b/4546f3ab60f78c514ffb7d01a0bd743f90de36f0019d1be84d0a708a580a/contourpy-1.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fde6c716d51c04b1c25d0b90364d0be954624a0ee9d60e23e850e8d48353d07a", size = 292189, upload-time = "2025-07-26T12:02:16.095Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e1/3542a9cb596cadd76fcef413f19c79216e002623158befe6daa03dbfa88c/contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cbedb772ed74ff5be440fa8eee9bd49f64f6e3fc09436d9c7d8f1c287b121d77", size = 273251, upload-time = "2025-07-26T12:02:17.524Z" }, + { url = "https://files.pythonhosted.org/packages/b1/71/f93e1e9471d189f79d0ce2497007731c1e6bf9ef6d1d61b911430c3db4e5/contourpy-1.3.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22e9b1bd7a9b1d652cd77388465dc358dafcd2e217d35552424aa4f996f524f5", size = 335810, upload-time = "2025-07-26T12:02:18.9Z" }, + { url = "https://files.pythonhosted.org/packages/91/f9/e35f4c1c93f9275d4e38681a80506b5510e9327350c51f8d4a5a724d178c/contourpy-1.3.3-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a22738912262aa3e254e4f3cb079a95a67132fc5a063890e224393596902f5a4", size = 382871, upload-time = "2025-07-26T12:02:20.418Z" }, + { url = "https://files.pythonhosted.org/packages/b5/71/47b512f936f66a0a900d81c396a7e60d73419868fba959c61efed7a8ab46/contourpy-1.3.3-cp314-cp314-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:afe5a512f31ee6bd7d0dda52ec9864c984ca3d66664444f2d72e0dc4eb832e36", size = 386264, upload-time = "2025-07-26T12:02:21.916Z" }, + { url = "https://files.pythonhosted.org/packages/04/5f/9ff93450ba96b09c7c2b3f81c94de31c89f92292f1380261bd7195bea4ea/contourpy-1.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f64836de09927cba6f79dcd00fdd7d5329f3fccc633468507079c829ca4db4e3", size = 363819, upload-time = "2025-07-26T12:02:23.759Z" }, + { url = "https://files.pythonhosted.org/packages/3e/a6/0b185d4cc480ee494945cde102cb0149ae830b5fa17bf855b95f2e70ad13/contourpy-1.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1fd43c3be4c8e5fd6e4f2baeae35ae18176cf2e5cced681cca908addf1cdd53b", size = 1333650, upload-time = "2025-07-26T12:02:26.181Z" }, + { url = "https://files.pythonhosted.org/packages/43/d7/afdc95580ca56f30fbcd3060250f66cedbde69b4547028863abd8aa3b47e/contourpy-1.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6afc576f7b33cf00996e5c1102dc2a8f7cc89e39c0b55df93a0b78c1bd992b36", size = 1404833, upload-time = "2025-07-26T12:02:28.782Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e2/366af18a6d386f41132a48f033cbd2102e9b0cf6345d35ff0826cd984566/contourpy-1.3.3-cp314-cp314-win32.whl", hash = "sha256:66c8a43a4f7b8df8b71ee1840e4211a3c8d93b214b213f590e18a1beca458f7d", size = 189692, upload-time = "2025-07-26T12:02:30.128Z" }, + { url = "https://files.pythonhosted.org/packages/7d/c2/57f54b03d0f22d4044b8afb9ca0e184f8b1afd57b4f735c2fa70883dc601/contourpy-1.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:cf9022ef053f2694e31d630feaacb21ea24224be1c3ad0520b13d844274614fd", size = 232424, upload-time = "2025-07-26T12:02:31.395Z" }, + { url = "https://files.pythonhosted.org/packages/18/79/a9416650df9b525737ab521aa181ccc42d56016d2123ddcb7b58e926a42c/contourpy-1.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:95b181891b4c71de4bb404c6621e7e2390745f887f2a026b2d99e92c17892339", size = 198300, upload-time = "2025-07-26T12:02:32.956Z" }, + { url = "https://files.pythonhosted.org/packages/1f/42/38c159a7d0f2b7b9c04c64ab317042bb6952b713ba875c1681529a2932fe/contourpy-1.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:33c82d0138c0a062380332c861387650c82e4cf1747aaa6938b9b6516762e772", size = 306769, upload-time = "2025-07-26T12:02:34.2Z" }, + { url = "https://files.pythonhosted.org/packages/c3/6c/26a8205f24bca10974e77460de68d3d7c63e282e23782f1239f226fcae6f/contourpy-1.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ea37e7b45949df430fe649e5de8351c423430046a2af20b1c1961cae3afcda77", size = 287892, upload-time = "2025-07-26T12:02:35.807Z" }, + { url = "https://files.pythonhosted.org/packages/66/06/8a475c8ab718ebfd7925661747dbb3c3ee9c82ac834ccb3570be49d129f4/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d304906ecc71672e9c89e87c4675dc5c2645e1f4269a5063b99b0bb29f232d13", size = 326748, upload-time = "2025-07-26T12:02:37.193Z" }, + { url = "https://files.pythonhosted.org/packages/b4/a3/c5ca9f010a44c223f098fccd8b158bb1cb287378a31ac141f04730dc49be/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca658cd1a680a5c9ea96dc61cdbae1e85c8f25849843aa799dfd3cb370ad4fbe", size = 375554, upload-time = "2025-07-26T12:02:38.894Z" }, + { url = "https://files.pythonhosted.org/packages/80/5b/68bd33ae63fac658a4145088c1e894405e07584a316738710b636c6d0333/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ab2fd90904c503739a75b7c8c5c01160130ba67944a7b77bbf36ef8054576e7f", size = 388118, upload-time = "2025-07-26T12:02:40.642Z" }, + { url = "https://files.pythonhosted.org/packages/40/52/4c285a6435940ae25d7410a6c36bda5145839bc3f0beb20c707cda18b9d2/contourpy-1.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7301b89040075c30e5768810bc96a8e8d78085b47d8be6e4c3f5a0b4ed478a0", size = 352555, upload-time = "2025-07-26T12:02:42.25Z" }, + { url = "https://files.pythonhosted.org/packages/24/ee/3e81e1dd174f5c7fefe50e85d0892de05ca4e26ef1c9a59c2a57e43b865a/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2a2a8b627d5cc6b7c41a4beff6c5ad5eb848c88255fda4a8745f7e901b32d8e4", size = 1322295, upload-time = "2025-07-26T12:02:44.668Z" }, + { url = "https://files.pythonhosted.org/packages/3c/b2/6d913d4d04e14379de429057cd169e5e00f6c2af3bb13e1710bcbdb5da12/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fd6ec6be509c787f1caf6b247f0b1ca598bef13f4ddeaa126b7658215529ba0f", size = 1391027, upload-time = "2025-07-26T12:02:47.09Z" }, + { url = "https://files.pythonhosted.org/packages/93/8a/68a4ec5c55a2971213d29a9374913f7e9f18581945a7a31d1a39b5d2dfe5/contourpy-1.3.3-cp314-cp314t-win32.whl", hash = "sha256:e74a9a0f5e3fff48fb5a7f2fd2b9b70a3fe014a67522f79b7cca4c0c7e43c9ae", size = 202428, upload-time = "2025-07-26T12:02:48.691Z" }, + { url = "https://files.pythonhosted.org/packages/fa/96/fd9f641ffedc4fa3ace923af73b9d07e869496c9cc7a459103e6e978992f/contourpy-1.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:13b68d6a62db8eafaebb8039218921399baf6e47bf85006fd8529f2a08ef33fc", size = 250331, upload-time = "2025-07-26T12:02:50.137Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8c/469afb6465b853afff216f9528ffda78a915ff880ed58813ba4faf4ba0b6/contourpy-1.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:b7448cb5a725bb1e35ce88771b86fba35ef418952474492cf7c764059933ff8b", size = 203831, upload-time = "2025-07-26T12:02:51.449Z" }, ] [[package]] name = "coverage" -version = "7.9.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/04/b7/c0465ca253df10a9e8dae0692a4ae6e9726d245390aaef92360e1d6d3832/coverage-7.9.2.tar.gz", hash = "sha256:997024fa51e3290264ffd7492ec97d0690293ccd2b45a6cd7d82d945a4a80c8b", size = 813556, upload-time = "2025-07-03T10:54:15.101Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/53/d7/7deefc6fd4f0f1d4c58051f4004e366afc9e7ab60217ac393f247a1de70a/coverage-7.9.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ae9eb07f1cfacd9cfe8eaee6f4ff4b8a289a668c39c165cd0c8548484920ffc0", size = 212344, upload-time = "2025-07-03T10:53:09.3Z" }, - { url = "https://files.pythonhosted.org/packages/95/0c/ee03c95d32be4d519e6a02e601267769ce2e9a91fc8faa1b540e3626c680/coverage-7.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9ce85551f9a1119f02adc46d3014b5ee3f765deac166acf20dbb851ceb79b6f3", size = 212580, upload-time = "2025-07-03T10:53:11.52Z" }, - { url = "https://files.pythonhosted.org/packages/8b/9f/826fa4b544b27620086211b87a52ca67592622e1f3af9e0a62c87aea153a/coverage-7.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8f6389ac977c5fb322e0e38885fbbf901743f79d47f50db706e7644dcdcb6e1", size = 246383, upload-time = "2025-07-03T10:53:13.134Z" }, - { url = "https://files.pythonhosted.org/packages/7f/b3/4477aafe2a546427b58b9c540665feff874f4db651f4d3cb21b308b3a6d2/coverage-7.9.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff0d9eae8cdfcd58fe7893b88993723583a6ce4dfbfd9f29e001922544f95615", size = 243400, upload-time = "2025-07-03T10:53:14.614Z" }, - { url = "https://files.pythonhosted.org/packages/f8/c2/efffa43778490c226d9d434827702f2dfbc8041d79101a795f11cbb2cf1e/coverage-7.9.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fae939811e14e53ed8a9818dad51d434a41ee09df9305663735f2e2d2d7d959b", size = 245591, upload-time = "2025-07-03T10:53:15.872Z" }, - { url = "https://files.pythonhosted.org/packages/c6/e7/a59888e882c9a5f0192d8627a30ae57910d5d449c80229b55e7643c078c4/coverage-7.9.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:31991156251ec202c798501e0a42bbdf2169dcb0f137b1f5c0f4267f3fc68ef9", size = 245402, upload-time = "2025-07-03T10:53:17.124Z" }, - { url = "https://files.pythonhosted.org/packages/92/a5/72fcd653ae3d214927edc100ce67440ed8a0a1e3576b8d5e6d066ed239db/coverage-7.9.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d0d67963f9cbfc7c7f96d4ac74ed60ecbebd2ea6eeb51887af0f8dce205e545f", size = 243583, upload-time = "2025-07-03T10:53:18.781Z" }, - { url = "https://files.pythonhosted.org/packages/5c/f5/84e70e4df28f4a131d580d7d510aa1ffd95037293da66fd20d446090a13b/coverage-7.9.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:49b752a2858b10580969ec6af6f090a9a440a64a301ac1528d7ca5f7ed497f4d", size = 244815, upload-time = "2025-07-03T10:53:20.168Z" }, - { url = "https://files.pythonhosted.org/packages/39/e7/d73d7cbdbd09fdcf4642655ae843ad403d9cbda55d725721965f3580a314/coverage-7.9.2-cp312-cp312-win32.whl", hash = "sha256:88d7598b8ee130f32f8a43198ee02edd16d7f77692fa056cb779616bbea1b355", size = 214719, upload-time = "2025-07-03T10:53:21.521Z" }, - { url = "https://files.pythonhosted.org/packages/9f/d6/7486dcc3474e2e6ad26a2af2db7e7c162ccd889c4c68fa14ea8ec189c9e9/coverage-7.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:9dfb070f830739ee49d7c83e4941cc767e503e4394fdecb3b54bfdac1d7662c0", size = 215509, upload-time = "2025-07-03T10:53:22.853Z" }, - { url = "https://files.pythonhosted.org/packages/b7/34/0439f1ae2593b0346164d907cdf96a529b40b7721a45fdcf8b03c95fcd90/coverage-7.9.2-cp312-cp312-win_arm64.whl", hash = "sha256:4e2c058aef613e79df00e86b6d42a641c877211384ce5bd07585ed7ba71ab31b", size = 213910, upload-time = "2025-07-03T10:53:24.472Z" }, - { url = "https://files.pythonhosted.org/packages/94/9d/7a8edf7acbcaa5e5c489a646226bed9591ee1c5e6a84733c0140e9ce1ae1/coverage-7.9.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:985abe7f242e0d7bba228ab01070fde1d6c8fa12f142e43debe9ed1dde686038", size = 212367, upload-time = "2025-07-03T10:53:25.811Z" }, - { url = "https://files.pythonhosted.org/packages/e8/9e/5cd6f130150712301f7e40fb5865c1bc27b97689ec57297e568d972eec3c/coverage-7.9.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82c3939264a76d44fde7f213924021ed31f55ef28111a19649fec90c0f109e6d", size = 212632, upload-time = "2025-07-03T10:53:27.075Z" }, - { url = "https://files.pythonhosted.org/packages/a8/de/6287a2c2036f9fd991c61cefa8c64e57390e30c894ad3aa52fac4c1e14a8/coverage-7.9.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae5d563e970dbe04382f736ec214ef48103d1b875967c89d83c6e3f21706d5b3", size = 245793, upload-time = "2025-07-03T10:53:28.408Z" }, - { url = "https://files.pythonhosted.org/packages/06/cc/9b5a9961d8160e3cb0b558c71f8051fe08aa2dd4b502ee937225da564ed1/coverage-7.9.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdd612e59baed2a93c8843c9a7cb902260f181370f1d772f4842987535071d14", size = 243006, upload-time = "2025-07-03T10:53:29.754Z" }, - { url = "https://files.pythonhosted.org/packages/49/d9/4616b787d9f597d6443f5588619c1c9f659e1f5fc9eebf63699eb6d34b78/coverage-7.9.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:256ea87cb2a1ed992bcdfc349d8042dcea1b80436f4ddf6e246d6bee4b5d73b6", size = 244990, upload-time = "2025-07-03T10:53:31.098Z" }, - { url = "https://files.pythonhosted.org/packages/48/83/801cdc10f137b2d02b005a761661649ffa60eb173dcdaeb77f571e4dc192/coverage-7.9.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f44ae036b63c8ea432f610534a2668b0c3aee810e7037ab9d8ff6883de480f5b", size = 245157, upload-time = "2025-07-03T10:53:32.717Z" }, - { url = "https://files.pythonhosted.org/packages/c8/a4/41911ed7e9d3ceb0ffb019e7635468df7499f5cc3edca5f7dfc078e9c5ec/coverage-7.9.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:82d76ad87c932935417a19b10cfe7abb15fd3f923cfe47dbdaa74ef4e503752d", size = 243128, upload-time = "2025-07-03T10:53:34.009Z" }, - { url = "https://files.pythonhosted.org/packages/10/41/344543b71d31ac9cb00a664d5d0c9ef134a0fe87cb7d8430003b20fa0b7d/coverage-7.9.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:619317bb86de4193debc712b9e59d5cffd91dc1d178627ab2a77b9870deb2868", size = 244511, upload-time = "2025-07-03T10:53:35.434Z" }, - { url = "https://files.pythonhosted.org/packages/d5/81/3b68c77e4812105e2a060f6946ba9e6f898ddcdc0d2bfc8b4b152a9ae522/coverage-7.9.2-cp313-cp313-win32.whl", hash = "sha256:0a07757de9feb1dfafd16ab651e0f628fd7ce551604d1bf23e47e1ddca93f08a", size = 214765, upload-time = "2025-07-03T10:53:36.787Z" }, - { url = "https://files.pythonhosted.org/packages/06/a2/7fac400f6a346bb1a4004eb2a76fbff0e242cd48926a2ce37a22a6a1d917/coverage-7.9.2-cp313-cp313-win_amd64.whl", hash = "sha256:115db3d1f4d3f35f5bb021e270edd85011934ff97c8797216b62f461dd69374b", size = 215536, upload-time = "2025-07-03T10:53:38.188Z" }, - { url = "https://files.pythonhosted.org/packages/08/47/2c6c215452b4f90d87017e61ea0fd9e0486bb734cb515e3de56e2c32075f/coverage-7.9.2-cp313-cp313-win_arm64.whl", hash = "sha256:48f82f889c80af8b2a7bb6e158d95a3fbec6a3453a1004d04e4f3b5945a02694", size = 213943, upload-time = "2025-07-03T10:53:39.492Z" }, - { url = "https://files.pythonhosted.org/packages/a3/46/e211e942b22d6af5e0f323faa8a9bc7c447a1cf1923b64c47523f36ed488/coverage-7.9.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:55a28954545f9d2f96870b40f6c3386a59ba8ed50caf2d949676dac3ecab99f5", size = 213088, upload-time = "2025-07-03T10:53:40.874Z" }, - { url = "https://files.pythonhosted.org/packages/d2/2f/762551f97e124442eccd907bf8b0de54348635b8866a73567eb4e6417acf/coverage-7.9.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cdef6504637731a63c133bb2e6f0f0214e2748495ec15fe42d1e219d1b133f0b", size = 213298, upload-time = "2025-07-03T10:53:42.218Z" }, - { url = "https://files.pythonhosted.org/packages/7a/b7/76d2d132b7baf7360ed69be0bcab968f151fa31abe6d067f0384439d9edb/coverage-7.9.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bcd5ebe66c7a97273d5d2ddd4ad0ed2e706b39630ed4b53e713d360626c3dbb3", size = 256541, upload-time = "2025-07-03T10:53:43.823Z" }, - { url = "https://files.pythonhosted.org/packages/a0/17/392b219837d7ad47d8e5974ce5f8dc3deb9f99a53b3bd4d123602f960c81/coverage-7.9.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9303aed20872d7a3c9cb39c5d2b9bdbe44e3a9a1aecb52920f7e7495410dfab8", size = 252761, upload-time = "2025-07-03T10:53:45.19Z" }, - { url = "https://files.pythonhosted.org/packages/d5/77/4256d3577fe1b0daa8d3836a1ebe68eaa07dd2cbaf20cf5ab1115d6949d4/coverage-7.9.2-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc18ea9e417a04d1920a9a76fe9ebd2f43ca505b81994598482f938d5c315f46", size = 254917, upload-time = "2025-07-03T10:53:46.931Z" }, - { url = "https://files.pythonhosted.org/packages/53/99/fc1a008eef1805e1ddb123cf17af864743354479ea5129a8f838c433cc2c/coverage-7.9.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6406cff19880aaaadc932152242523e892faff224da29e241ce2fca329866584", size = 256147, upload-time = "2025-07-03T10:53:48.289Z" }, - { url = "https://files.pythonhosted.org/packages/92/c0/f63bf667e18b7f88c2bdb3160870e277c4874ced87e21426128d70aa741f/coverage-7.9.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2d0d4f6ecdf37fcc19c88fec3e2277d5dee740fb51ffdd69b9579b8c31e4232e", size = 254261, upload-time = "2025-07-03T10:53:49.99Z" }, - { url = "https://files.pythonhosted.org/packages/8c/32/37dd1c42ce3016ff8ec9e4b607650d2e34845c0585d3518b2a93b4830c1a/coverage-7.9.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c33624f50cf8de418ab2b4d6ca9eda96dc45b2c4231336bac91454520e8d1fac", size = 255099, upload-time = "2025-07-03T10:53:51.354Z" }, - { url = "https://files.pythonhosted.org/packages/da/2e/af6b86f7c95441ce82f035b3affe1cd147f727bbd92f563be35e2d585683/coverage-7.9.2-cp313-cp313t-win32.whl", hash = "sha256:1df6b76e737c6a92210eebcb2390af59a141f9e9430210595251fbaf02d46926", size = 215440, upload-time = "2025-07-03T10:53:52.808Z" }, - { url = "https://files.pythonhosted.org/packages/4d/bb/8a785d91b308867f6b2e36e41c569b367c00b70c17f54b13ac29bcd2d8c8/coverage-7.9.2-cp313-cp313t-win_amd64.whl", hash = "sha256:f5fd54310b92741ebe00d9c0d1d7b2b27463952c022da6d47c175d246a98d1bd", size = 216537, upload-time = "2025-07-03T10:53:54.273Z" }, - { url = "https://files.pythonhosted.org/packages/1d/a0/a6bffb5e0f41a47279fd45a8f3155bf193f77990ae1c30f9c224b61cacb0/coverage-7.9.2-cp313-cp313t-win_arm64.whl", hash = "sha256:c48c2375287108c887ee87d13b4070a381c6537d30e8487b24ec721bf2a781cb", size = 214398, upload-time = "2025-07-03T10:53:56.715Z" }, - { url = "https://files.pythonhosted.org/packages/3c/38/bbe2e63902847cf79036ecc75550d0698af31c91c7575352eb25190d0fb3/coverage-7.9.2-py3-none-any.whl", hash = "sha256:e425cd5b00f6fc0ed7cdbd766c70be8baab4b7839e4d4fe5fac48581dd968ea4", size = 204005, upload-time = "2025-07-03T10:54:13.491Z" }, +version = "7.13.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/23/f9/e92df5e07f3fc8d4c7f9a0f146ef75446bf870351cd37b788cf5897f8079/coverage-7.13.1.tar.gz", hash = "sha256:b7593fe7eb5feaa3fbb461ac79aac9f9fc0387a5ca8080b0c6fe2ca27b091afd", size = 825862, upload-time = "2025-12-28T15:42:56.969Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/8a/87af46cccdfa78f53db747b09f5f9a21d5fc38d796834adac09b30a8ce74/coverage-7.13.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6f34591000f06e62085b1865c9bc5f7858df748834662a51edadfd2c3bfe0dd3", size = 218927, upload-time = "2025-12-28T15:40:52.814Z" }, + { url = "https://files.pythonhosted.org/packages/82/a8/6e22fdc67242a4a5a153f9438d05944553121c8f4ba70cb072af4c41362e/coverage-7.13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b67e47c5595b9224599016e333f5ec25392597a89d5744658f837d204e16c63e", size = 219288, upload-time = "2025-12-28T15:40:54.262Z" }, + { url = "https://files.pythonhosted.org/packages/d0/0a/853a76e03b0f7c4375e2ca025df45c918beb367f3e20a0a8e91967f6e96c/coverage-7.13.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3e7b8bd70c48ffb28461ebe092c2345536fb18bbbf19d287c8913699735f505c", size = 250786, upload-time = "2025-12-28T15:40:56.059Z" }, + { url = "https://files.pythonhosted.org/packages/ea/b4/694159c15c52b9f7ec7adf49d50e5f8ee71d3e9ef38adb4445d13dd56c20/coverage-7.13.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c223d078112e90dc0e5c4e35b98b9584164bea9fbbd221c0b21c5241f6d51b62", size = 253543, upload-time = "2025-12-28T15:40:57.585Z" }, + { url = "https://files.pythonhosted.org/packages/96/b2/7f1f0437a5c855f87e17cf5d0dc35920b6440ff2b58b1ba9788c059c26c8/coverage-7.13.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:794f7c05af0763b1bbd1b9e6eff0e52ad068be3b12cd96c87de037b01390c968", size = 254635, upload-time = "2025-12-28T15:40:59.443Z" }, + { url = "https://files.pythonhosted.org/packages/e9/d1/73c3fdb8d7d3bddd9473c9c6a2e0682f09fc3dfbcb9c3f36412a7368bcab/coverage-7.13.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0642eae483cc8c2902e4af7298bf886d605e80f26382124cddc3967c2a3df09e", size = 251202, upload-time = "2025-12-28T15:41:01.328Z" }, + { url = "https://files.pythonhosted.org/packages/66/3c/f0edf75dcc152f145d5598329e864bbbe04ab78660fe3e8e395f9fff010f/coverage-7.13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9f5e772ed5fef25b3de9f2008fe67b92d46831bd2bc5bdc5dd6bfd06b83b316f", size = 252566, upload-time = "2025-12-28T15:41:03.319Z" }, + { url = "https://files.pythonhosted.org/packages/17/b3/e64206d3c5f7dcbceafd14941345a754d3dbc78a823a6ed526e23b9cdaab/coverage-7.13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:45980ea19277dc0a579e432aef6a504fe098ef3a9032ead15e446eb0f1191aee", size = 250711, upload-time = "2025-12-28T15:41:06.411Z" }, + { url = "https://files.pythonhosted.org/packages/dc/ad/28a3eb970a8ef5b479ee7f0c484a19c34e277479a5b70269dc652b730733/coverage-7.13.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e4f18eca6028ffa62adbd185a8f1e1dd242f2e68164dba5c2b74a5204850b4cf", size = 250278, upload-time = "2025-12-28T15:41:08.285Z" }, + { url = "https://files.pythonhosted.org/packages/54/e3/c8f0f1a93133e3e1291ca76cbb63565bd4b5c5df63b141f539d747fff348/coverage-7.13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f8dca5590fec7a89ed6826fce625595279e586ead52e9e958d3237821fbc750c", size = 252154, upload-time = "2025-12-28T15:41:09.969Z" }, + { url = "https://files.pythonhosted.org/packages/d0/bf/9939c5d6859c380e405b19e736321f1c7d402728792f4c752ad1adcce005/coverage-7.13.1-cp312-cp312-win32.whl", hash = "sha256:ff86d4e85188bba72cfb876df3e11fa243439882c55957184af44a35bd5880b7", size = 221487, upload-time = "2025-12-28T15:41:11.468Z" }, + { url = "https://files.pythonhosted.org/packages/fa/dc/7282856a407c621c2aad74021680a01b23010bb8ebf427cf5eacda2e876f/coverage-7.13.1-cp312-cp312-win_amd64.whl", hash = "sha256:16cc1da46c04fb0fb128b4dc430b78fa2aba8a6c0c9f8eb391fd5103409a6ac6", size = 222299, upload-time = "2025-12-28T15:41:13.386Z" }, + { url = "https://files.pythonhosted.org/packages/10/79/176a11203412c350b3e9578620013af35bcdb79b651eb976f4a4b32044fa/coverage-7.13.1-cp312-cp312-win_arm64.whl", hash = "sha256:8d9bc218650022a768f3775dd7fdac1886437325d8d295d923ebcfef4892ad5c", size = 220941, upload-time = "2025-12-28T15:41:14.975Z" }, + { url = "https://files.pythonhosted.org/packages/a3/a4/e98e689347a1ff1a7f67932ab535cef82eb5e78f32a9e4132e114bbb3a0a/coverage-7.13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:cb237bfd0ef4d5eb6a19e29f9e528ac67ac3be932ea6b44fb6cc09b9f3ecff78", size = 218951, upload-time = "2025-12-28T15:41:16.653Z" }, + { url = "https://files.pythonhosted.org/packages/32/33/7cbfe2bdc6e2f03d6b240d23dc45fdaf3fd270aaf2d640be77b7f16989ab/coverage-7.13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1dcb645d7e34dcbcc96cd7c132b1fc55c39263ca62eb961c064eb3928997363b", size = 219325, upload-time = "2025-12-28T15:41:18.609Z" }, + { url = "https://files.pythonhosted.org/packages/59/f6/efdabdb4929487baeb7cb2a9f7dac457d9356f6ad1b255be283d58b16316/coverage-7.13.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3d42df8201e00384736f0df9be2ced39324c3907607d17d50d50116c989d84cd", size = 250309, upload-time = "2025-12-28T15:41:20.629Z" }, + { url = "https://files.pythonhosted.org/packages/12/da/91a52516e9d5aea87d32d1523f9cdcf7a35a3b298e6be05d6509ba3cfab2/coverage-7.13.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fa3edde1aa8807de1d05934982416cb3ec46d1d4d91e280bcce7cca01c507992", size = 252907, upload-time = "2025-12-28T15:41:22.257Z" }, + { url = "https://files.pythonhosted.org/packages/75/38/f1ea837e3dc1231e086db1638947e00d264e7e8c41aa8ecacf6e1e0c05f4/coverage-7.13.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9edd0e01a343766add6817bc448408858ba6b489039eaaa2018474e4001651a4", size = 254148, upload-time = "2025-12-28T15:41:23.87Z" }, + { url = "https://files.pythonhosted.org/packages/7f/43/f4f16b881aaa34954ba446318dea6b9ed5405dd725dd8daac2358eda869a/coverage-7.13.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:985b7836931d033570b94c94713c6dba5f9d3ff26045f72c3e5dbc5fe3361e5a", size = 250515, upload-time = "2025-12-28T15:41:25.437Z" }, + { url = "https://files.pythonhosted.org/packages/84/34/8cba7f00078bd468ea914134e0144263194ce849ec3baad187ffb6203d1c/coverage-7.13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ffed1e4980889765c84a5d1a566159e363b71d6b6fbaf0bebc9d3c30bc016766", size = 252292, upload-time = "2025-12-28T15:41:28.459Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a4/cffac66c7652d84ee4ac52d3ccb94c015687d3b513f9db04bfcac2ac800d/coverage-7.13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8842af7f175078456b8b17f1b73a0d16a65dcbdc653ecefeb00a56b3c8c298c4", size = 250242, upload-time = "2025-12-28T15:41:30.02Z" }, + { url = "https://files.pythonhosted.org/packages/f4/78/9a64d462263dde416f3c0067efade7b52b52796f489b1037a95b0dc389c9/coverage-7.13.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:ccd7a6fca48ca9c131d9b0a2972a581e28b13416fc313fb98b6d24a03ce9a398", size = 250068, upload-time = "2025-12-28T15:41:32.007Z" }, + { url = "https://files.pythonhosted.org/packages/69/c8/a8994f5fece06db7c4a97c8fc1973684e178599b42e66280dded0524ef00/coverage-7.13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0403f647055de2609be776965108447deb8e384fe4a553c119e3ff6bfbab4784", size = 251846, upload-time = "2025-12-28T15:41:33.946Z" }, + { url = "https://files.pythonhosted.org/packages/cc/f7/91fa73c4b80305c86598a2d4e54ba22df6bf7d0d97500944af7ef155d9f7/coverage-7.13.1-cp313-cp313-win32.whl", hash = "sha256:549d195116a1ba1e1ae2f5ca143f9777800f6636eab917d4f02b5310d6d73461", size = 221512, upload-time = "2025-12-28T15:41:35.519Z" }, + { url = "https://files.pythonhosted.org/packages/45/0b/0768b4231d5a044da8f75e097a8714ae1041246bb765d6b5563bab456735/coverage-7.13.1-cp313-cp313-win_amd64.whl", hash = "sha256:5899d28b5276f536fcf840b18b61a9fce23cc3aec1d114c44c07fe94ebeaa500", size = 222321, upload-time = "2025-12-28T15:41:37.371Z" }, + { url = "https://files.pythonhosted.org/packages/9b/b8/bdcb7253b7e85157282450262008f1366aa04663f3e3e4c30436f596c3e2/coverage-7.13.1-cp313-cp313-win_arm64.whl", hash = "sha256:868a2fae76dfb06e87291bcbd4dcbcc778a8500510b618d50496e520bd94d9b9", size = 220949, upload-time = "2025-12-28T15:41:39.553Z" }, + { url = "https://files.pythonhosted.org/packages/70/52/f2be52cc445ff75ea8397948c96c1b4ee14f7f9086ea62fc929c5ae7b717/coverage-7.13.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:67170979de0dacac3f3097d02b0ad188d8edcea44ccc44aaa0550af49150c7dc", size = 219643, upload-time = "2025-12-28T15:41:41.567Z" }, + { url = "https://files.pythonhosted.org/packages/47/79/c85e378eaa239e2edec0c5523f71542c7793fe3340954eafb0bc3904d32d/coverage-7.13.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f80e2bb21bfab56ed7405c2d79d34b5dc0bc96c2c1d2a067b643a09fb756c43a", size = 219997, upload-time = "2025-12-28T15:41:43.418Z" }, + { url = "https://files.pythonhosted.org/packages/fe/9b/b1ade8bfb653c0bbce2d6d6e90cc6c254cbb99b7248531cc76253cb4da6d/coverage-7.13.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f83351e0f7dcdb14d7326c3d8d8c4e915fa685cbfdc6281f9470d97a04e9dfe4", size = 261296, upload-time = "2025-12-28T15:41:45.207Z" }, + { url = "https://files.pythonhosted.org/packages/1f/af/ebf91e3e1a2473d523e87e87fd8581e0aa08741b96265730e2d79ce78d8d/coverage-7.13.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bb3f6562e89bad0110afbe64e485aac2462efdce6232cdec7862a095dc3412f6", size = 263363, upload-time = "2025-12-28T15:41:47.163Z" }, + { url = "https://files.pythonhosted.org/packages/c4/8b/fb2423526d446596624ac7fde12ea4262e66f86f5120114c3cfd0bb2befa/coverage-7.13.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77545b5dcda13b70f872c3b5974ac64c21d05e65b1590b441c8560115dc3a0d1", size = 265783, upload-time = "2025-12-28T15:41:49.03Z" }, + { url = "https://files.pythonhosted.org/packages/9b/26/ef2adb1e22674913b89f0fe7490ecadcef4a71fa96f5ced90c60ec358789/coverage-7.13.1-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a4d240d260a1aed814790bbe1f10a5ff31ce6c21bc78f0da4a1e8268d6c80dbd", size = 260508, upload-time = "2025-12-28T15:41:51.035Z" }, + { url = "https://files.pythonhosted.org/packages/ce/7d/f0f59b3404caf662e7b5346247883887687c074ce67ba453ea08c612b1d5/coverage-7.13.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d2287ac9360dec3837bfdad969963a5d073a09a85d898bd86bea82aa8876ef3c", size = 263357, upload-time = "2025-12-28T15:41:52.631Z" }, + { url = "https://files.pythonhosted.org/packages/1a/b1/29896492b0b1a047604d35d6fa804f12818fa30cdad660763a5f3159e158/coverage-7.13.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:0d2c11f3ea4db66b5cbded23b20185c35066892c67d80ec4be4bab257b9ad1e0", size = 260978, upload-time = "2025-12-28T15:41:54.589Z" }, + { url = "https://files.pythonhosted.org/packages/48/f2/971de1238a62e6f0a4128d37adadc8bb882ee96afbe03ff1570291754629/coverage-7.13.1-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:3fc6a169517ca0d7ca6846c3c5392ef2b9e38896f61d615cb75b9e7134d4ee1e", size = 259877, upload-time = "2025-12-28T15:41:56.263Z" }, + { url = "https://files.pythonhosted.org/packages/6a/fc/0474efcbb590ff8628830e9aaec5f1831594874360e3251f1fdec31d07a3/coverage-7.13.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d10a2ed46386e850bb3de503a54f9fe8192e5917fcbb143bfef653a9355e9a53", size = 262069, upload-time = "2025-12-28T15:41:58.093Z" }, + { url = "https://files.pythonhosted.org/packages/88/4f/3c159b7953db37a7b44c0eab8a95c37d1aa4257c47b4602c04022d5cb975/coverage-7.13.1-cp313-cp313t-win32.whl", hash = "sha256:75a6f4aa904301dab8022397a22c0039edc1f51e90b83dbd4464b8a38dc87842", size = 222184, upload-time = "2025-12-28T15:41:59.763Z" }, + { url = "https://files.pythonhosted.org/packages/58/a5/6b57d28f81417f9335774f20679d9d13b9a8fb90cd6160957aa3b54a2379/coverage-7.13.1-cp313-cp313t-win_amd64.whl", hash = "sha256:309ef5706e95e62578cda256b97f5e097916a2c26247c287bbe74794e7150df2", size = 223250, upload-time = "2025-12-28T15:42:01.52Z" }, + { url = "https://files.pythonhosted.org/packages/81/7c/160796f3b035acfbb58be80e02e484548595aa67e16a6345e7910ace0a38/coverage-7.13.1-cp313-cp313t-win_arm64.whl", hash = "sha256:92f980729e79b5d16d221038dbf2e8f9a9136afa072f9d5d6ed4cb984b126a09", size = 221521, upload-time = "2025-12-28T15:42:03.275Z" }, + { url = "https://files.pythonhosted.org/packages/aa/8e/ba0e597560c6563fc0adb902fda6526df5d4aa73bb10adf0574d03bd2206/coverage-7.13.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:97ab3647280d458a1f9adb85244e81587505a43c0c7cff851f5116cd2814b894", size = 218996, upload-time = "2025-12-28T15:42:04.978Z" }, + { url = "https://files.pythonhosted.org/packages/6b/8e/764c6e116f4221dc7aa26c4061181ff92edb9c799adae6433d18eeba7a14/coverage-7.13.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8f572d989142e0908e6acf57ad1b9b86989ff057c006d13b76c146ec6a20216a", size = 219326, upload-time = "2025-12-28T15:42:06.691Z" }, + { url = "https://files.pythonhosted.org/packages/4f/a6/6130dc6d8da28cdcbb0f2bf8865aeca9b157622f7c0031e48c6cf9a0e591/coverage-7.13.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d72140ccf8a147e94274024ff6fd8fb7811354cf7ef88b1f0a988ebaa5bc774f", size = 250374, upload-time = "2025-12-28T15:42:08.786Z" }, + { url = "https://files.pythonhosted.org/packages/82/2b/783ded568f7cd6b677762f780ad338bf4b4750205860c17c25f7c708995e/coverage-7.13.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d3c9f051b028810f5a87c88e5d6e9af3c0ff32ef62763bf15d29f740453ca909", size = 252882, upload-time = "2025-12-28T15:42:10.515Z" }, + { url = "https://files.pythonhosted.org/packages/cd/b2/9808766d082e6a4d59eb0cc881a57fc1600eb2c5882813eefff8254f71b5/coverage-7.13.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f398ba4df52d30b1763f62eed9de5620dcde96e6f491f4c62686736b155aa6e4", size = 254218, upload-time = "2025-12-28T15:42:12.208Z" }, + { url = "https://files.pythonhosted.org/packages/44/ea/52a985bb447c871cb4d2e376e401116520991b597c85afdde1ea9ef54f2c/coverage-7.13.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:132718176cc723026d201e347f800cd1a9e4b62ccd3f82476950834dad501c75", size = 250391, upload-time = "2025-12-28T15:42:14.21Z" }, + { url = "https://files.pythonhosted.org/packages/7f/1d/125b36cc12310718873cfc8209ecfbc1008f14f4f5fa0662aa608e579353/coverage-7.13.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9e549d642426e3579b3f4b92d0431543b012dcb6e825c91619d4e93b7363c3f9", size = 252239, upload-time = "2025-12-28T15:42:16.292Z" }, + { url = "https://files.pythonhosted.org/packages/6a/16/10c1c164950cade470107f9f14bbac8485f8fb8515f515fca53d337e4a7f/coverage-7.13.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:90480b2134999301eea795b3a9dbf606c6fbab1b489150c501da84a959442465", size = 250196, upload-time = "2025-12-28T15:42:18.54Z" }, + { url = "https://files.pythonhosted.org/packages/2a/c6/cd860fac08780c6fd659732f6ced1b40b79c35977c1356344e44d72ba6c4/coverage-7.13.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e825dbb7f84dfa24663dd75835e7257f8882629fc11f03ecf77d84a75134b864", size = 250008, upload-time = "2025-12-28T15:42:20.365Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/a8c58d3d38f82a5711e1e0a67268362af48e1a03df27c03072ac30feefcf/coverage-7.13.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:623dcc6d7a7ba450bbdbeedbaa0c42b329bdae16491af2282f12a7e809be7eb9", size = 251671, upload-time = "2025-12-28T15:42:22.114Z" }, + { url = "https://files.pythonhosted.org/packages/f0/bc/fd4c1da651d037a1e3d53e8cb3f8182f4b53271ffa9a95a2e211bacc0349/coverage-7.13.1-cp314-cp314-win32.whl", hash = "sha256:6e73ebb44dca5f708dc871fe0b90cf4cff1a13f9956f747cc87b535a840386f5", size = 221777, upload-time = "2025-12-28T15:42:23.919Z" }, + { url = "https://files.pythonhosted.org/packages/4b/50/71acabdc8948464c17e90b5ffd92358579bd0910732c2a1c9537d7536aa6/coverage-7.13.1-cp314-cp314-win_amd64.whl", hash = "sha256:be753b225d159feb397bd0bf91ae86f689bad0da09d3b301478cd39b878ab31a", size = 222592, upload-time = "2025-12-28T15:42:25.619Z" }, + { url = "https://files.pythonhosted.org/packages/f7/c8/a6fb943081bb0cc926499c7907731a6dc9efc2cbdc76d738c0ab752f1a32/coverage-7.13.1-cp314-cp314-win_arm64.whl", hash = "sha256:228b90f613b25ba0019361e4ab81520b343b622fc657daf7e501c4ed6a2366c0", size = 221169, upload-time = "2025-12-28T15:42:27.629Z" }, + { url = "https://files.pythonhosted.org/packages/16/61/d5b7a0a0e0e40d62e59bc8c7aa1afbd86280d82728ba97f0673b746b78e2/coverage-7.13.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:60cfb538fe9ef86e5b2ab0ca8fc8d62524777f6c611dcaf76dc16fbe9b8e698a", size = 219730, upload-time = "2025-12-28T15:42:29.306Z" }, + { url = "https://files.pythonhosted.org/packages/a3/2c/8881326445fd071bb49514d1ce97d18a46a980712b51fee84f9ab42845b4/coverage-7.13.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:57dfc8048c72ba48a8c45e188d811e5efd7e49b387effc8fb17e97936dde5bf6", size = 220001, upload-time = "2025-12-28T15:42:31.319Z" }, + { url = "https://files.pythonhosted.org/packages/b5/d7/50de63af51dfa3a7f91cc37ad8fcc1e244b734232fbc8b9ab0f3c834a5cd/coverage-7.13.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3f2f725aa3e909b3c5fdb8192490bdd8e1495e85906af74fe6e34a2a77ba0673", size = 261370, upload-time = "2025-12-28T15:42:32.992Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2c/d31722f0ec918fd7453b2758312729f645978d212b410cd0f7c2aed88a94/coverage-7.13.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ee68b21909686eeb21dfcba2c3b81fee70dcf38b140dcd5aa70680995fa3aa5", size = 263485, upload-time = "2025-12-28T15:42:34.759Z" }, + { url = "https://files.pythonhosted.org/packages/fa/7a/2c114fa5c5fc08ba0777e4aec4c97e0b4a1afcb69c75f1f54cff78b073ab/coverage-7.13.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:724b1b270cb13ea2e6503476e34541a0b1f62280bc997eab443f87790202033d", size = 265890, upload-time = "2025-12-28T15:42:36.517Z" }, + { url = "https://files.pythonhosted.org/packages/65/d9/f0794aa1c74ceabc780fe17f6c338456bbc4e96bd950f2e969f48ac6fb20/coverage-7.13.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:916abf1ac5cf7eb16bc540a5bf75c71c43a676f5c52fcb9fe75a2bd75fb944e8", size = 260445, upload-time = "2025-12-28T15:42:38.646Z" }, + { url = "https://files.pythonhosted.org/packages/49/23/184b22a00d9bb97488863ced9454068c79e413cb23f472da6cbddc6cfc52/coverage-7.13.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:776483fd35b58d8afe3acbd9988d5de592ab6da2d2a865edfdbc9fdb43e7c486", size = 263357, upload-time = "2025-12-28T15:42:40.788Z" }, + { url = "https://files.pythonhosted.org/packages/7d/bd/58af54c0c9199ea4190284f389005779d7daf7bf3ce40dcd2d2b2f96da69/coverage-7.13.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b6f3b96617e9852703f5b633ea01315ca45c77e879584f283c44127f0f1ec564", size = 260959, upload-time = "2025-12-28T15:42:42.808Z" }, + { url = "https://files.pythonhosted.org/packages/4b/2a/6839294e8f78a4891bf1df79d69c536880ba2f970d0ff09e7513d6e352e9/coverage-7.13.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:bd63e7b74661fed317212fab774e2a648bc4bb09b35f25474f8e3325d2945cd7", size = 259792, upload-time = "2025-12-28T15:42:44.818Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c3/528674d4623283310ad676c5af7414b9850ab6d55c2300e8aa4b945ec554/coverage-7.13.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:933082f161bbb3e9f90d00990dc956120f608cdbcaeea15c4d897f56ef4fe416", size = 262123, upload-time = "2025-12-28T15:42:47.108Z" }, + { url = "https://files.pythonhosted.org/packages/06/c5/8c0515692fb4c73ac379d8dc09b18eaf0214ecb76ea6e62467ba7a1556ff/coverage-7.13.1-cp314-cp314t-win32.whl", hash = "sha256:18be793c4c87de2965e1c0f060f03d9e5aff66cfeae8e1dbe6e5b88056ec153f", size = 222562, upload-time = "2025-12-28T15:42:49.144Z" }, + { url = "https://files.pythonhosted.org/packages/05/0e/c0a0c4678cb30dac735811db529b321d7e1c9120b79bd728d4f4d6b010e9/coverage-7.13.1-cp314-cp314t-win_amd64.whl", hash = "sha256:0e42e0ec0cd3e0d851cb3c91f770c9301f48647cb2877cb78f74bdaa07639a79", size = 223670, upload-time = "2025-12-28T15:42:51.218Z" }, + { url = "https://files.pythonhosted.org/packages/f5/5f/b177aa0011f354abf03a8f30a85032686d290fdeed4222b27d36b4372a50/coverage-7.13.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eaecf47ef10c72ece9a2a92118257da87e460e113b83cc0d2905cbbe931792b4", size = 221707, upload-time = "2025-12-28T15:42:53.034Z" }, + { url = "https://files.pythonhosted.org/packages/cc/48/d9f421cb8da5afaa1a64570d9989e00fb7955e6acddc5a12979f7666ef60/coverage-7.13.1-py3-none-any.whl", hash = "sha256:2016745cb3ba554469d02819d78958b571792bb68e31302610e898f80dd3a573", size = 210722, upload-time = "2025-12-28T15:42:54.901Z" }, ] [[package]] @@ -225,29 +312,29 @@ wheels = [ [[package]] name = "dill" -version = "0.4.0" +version = "0.4.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/12/80/630b4b88364e9a8c8c5797f4602d0f76ef820909ee32f0bacb9f90654042/dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", size = 186976, upload-time = "2025-04-16T00:41:48.867Z" } +sdist = { url = "https://files.pythonhosted.org/packages/81/e1/56027a71e31b02ddc53c7d65b01e68edf64dea2932122fe7746a516f75d5/dill-0.4.1.tar.gz", hash = "sha256:423092df4182177d4d8ba8290c8a5b640c66ab35ec7da59ccfa00f6fa3eea5fa", size = 187315, upload-time = "2026-01-19T02:36:56.85Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668, upload-time = "2025-04-16T00:41:47.671Z" }, + { url = "https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl", hash = "sha256:1e1ce33e978ae97fcfcff5638477032b801c46c7c65cf717f95fbc2248f79a9d", size = 120019, upload-time = "2026-01-19T02:36:55.663Z" }, ] [[package]] name = "distlib" -version = "0.3.9" +version = "0.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0d/dd/1bec4c5ddb504ca60fc29472f3d27e8d4da1257a854e1d96742f15c1d02d/distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403", size = 613923, upload-time = "2024-10-09T18:35:47.551Z" } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/91/a1/cf2472db20f7ce4a6be1253a81cfdf85ad9c7885ffbed7047fb72c24cf87/distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", size = 468973, upload-time = "2024-10-09T18:35:44.272Z" }, + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, ] [[package]] name = "docutils" -version = "0.21.2" +version = "0.22.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444, upload-time = "2024-04-23T18:57:18.24Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/b6/03bb70946330e88ffec97aefd3ea75ba575cb2e762061e0e62a213befee8/docutils-0.22.4.tar.gz", hash = "sha256:4db53b1fde9abecbb74d91230d32ab626d94f6badfc575d6db9194a49df29968", size = 2291750, upload-time = "2025-12-18T19:00:26.443Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408, upload-time = "2024-04-23T18:57:14.835Z" }, + { url = "https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl", hash = "sha256:d0013f540772d1420576855455d050a2180186c91c15779301ac2ccb3eeb68de", size = 633196, upload-time = "2025-12-18T19:00:18.077Z" }, ] [[package]] @@ -261,11 +348,11 @@ wheels = [ [[package]] name = "filelock" -version = "3.18.0" +version = "3.20.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0a/10/c23352565a6544bdc5353e0b15fc1c563352101f30e24bf500207a54df9a/filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2", size = 18075, upload-time = "2025-03-14T07:11:40.47Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/65/ce7f1b70157833bf3cb851b556a37d4547ceafc158aa9b34b36782f23696/filelock-3.20.3.tar.gz", hash = "sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1", size = 19485, upload-time = "2026-01-09T17:55:05.421Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215, upload-time = "2025-03-14T07:11:39.145Z" }, + { url = "https://files.pythonhosted.org/packages/b5/36/7fb70f04bf00bc646cd5bb45aa9eddb15e19437a28b8fb2b4a5249fac770/filelock-3.20.3-py3-none-any.whl", hash = "sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1", size = 16701, upload-time = "2026-01-09T17:55:04.334Z" }, ] [[package]] @@ -294,27 +381,43 @@ wheels = [ [[package]] name = "fonttools" -version = "4.59.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/27/ec3c723bfdf86f34c5c82bf6305df3e0f0d8ea798d2d3a7cb0c0a866d286/fonttools-4.59.0.tar.gz", hash = "sha256:be392ec3529e2f57faa28709d60723a763904f71a2b63aabe14fee6648fe3b14", size = 3532521, upload-time = "2025-07-16T12:04:54.613Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/77/b1c8af22f4265e951cd2e5535dbef8859efcef4fb8dee742d368c967cddb/fonttools-4.59.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f9b3a78f69dcbd803cf2fb3f972779875b244c1115481dfbdd567b2c22b31f6b", size = 2767562, upload-time = "2025-07-16T12:04:06.895Z" }, - { url = "https://files.pythonhosted.org/packages/ff/5a/aeb975699588176bb357e8b398dfd27e5d3a2230d92b81ab8cbb6187358d/fonttools-4.59.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:57bb7e26928573ee7c6504f54c05860d867fd35e675769f3ce01b52af38d48e2", size = 2335168, upload-time = "2025-07-16T12:04:08.695Z" }, - { url = "https://files.pythonhosted.org/packages/54/97/c6101a7e60ae138c4ef75b22434373a0da50a707dad523dd19a4889315bf/fonttools-4.59.0-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4536f2695fe5c1ffb528d84a35a7d3967e5558d2af58b4775e7ab1449d65767b", size = 4909850, upload-time = "2025-07-16T12:04:10.761Z" }, - { url = "https://files.pythonhosted.org/packages/bd/6c/fa4d18d641054f7bff878cbea14aa9433f292b9057cb1700d8e91a4d5f4f/fonttools-4.59.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:885bde7d26e5b40e15c47bd5def48b38cbd50830a65f98122a8fb90962af7cd1", size = 4955131, upload-time = "2025-07-16T12:04:12.846Z" }, - { url = "https://files.pythonhosted.org/packages/20/5c/331947fc1377deb928a69bde49f9003364f5115e5cbe351eea99e39412a2/fonttools-4.59.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6801aeddb6acb2c42eafa45bc1cb98ba236871ae6f33f31e984670b749a8e58e", size = 4899667, upload-time = "2025-07-16T12:04:14.558Z" }, - { url = "https://files.pythonhosted.org/packages/8a/46/b66469dfa26b8ff0baa7654b2cc7851206c6d57fe3abdabbaab22079a119/fonttools-4.59.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:31003b6a10f70742a63126b80863ab48175fb8272a18ca0846c0482968f0588e", size = 5051349, upload-time = "2025-07-16T12:04:16.388Z" }, - { url = "https://files.pythonhosted.org/packages/2e/05/ebfb6b1f3a4328ab69787d106a7d92ccde77ce66e98659df0f9e3f28d93d/fonttools-4.59.0-cp312-cp312-win32.whl", hash = "sha256:fbce6dae41b692a5973d0f2158f782b9ad05babc2c2019a970a1094a23909b1b", size = 2201315, upload-time = "2025-07-16T12:04:18.557Z" }, - { url = "https://files.pythonhosted.org/packages/09/45/d2bdc9ea20bbadec1016fd0db45696d573d7a26d95ab5174ffcb6d74340b/fonttools-4.59.0-cp312-cp312-win_amd64.whl", hash = "sha256:332bfe685d1ac58ca8d62b8d6c71c2e52a6c64bc218dc8f7825c9ea51385aa01", size = 2249408, upload-time = "2025-07-16T12:04:20.489Z" }, - { url = "https://files.pythonhosted.org/packages/f3/bb/390990e7c457d377b00890d9f96a3ca13ae2517efafb6609c1756e213ba4/fonttools-4.59.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:78813b49d749e1bb4db1c57f2d4d7e6db22c253cb0a86ad819f5dc197710d4b2", size = 2758704, upload-time = "2025-07-16T12:04:22.217Z" }, - { url = "https://files.pythonhosted.org/packages/df/6f/d730d9fcc9b410a11597092bd2eb9ca53e5438c6cb90e4b3047ce1b723e9/fonttools-4.59.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:401b1941ce37e78b8fd119b419b617277c65ae9417742a63282257434fd68ea2", size = 2330764, upload-time = "2025-07-16T12:04:23.985Z" }, - { url = "https://files.pythonhosted.org/packages/75/b4/b96bb66f6f8cc4669de44a158099b249c8159231d254ab6b092909388be5/fonttools-4.59.0-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:efd7e6660674e234e29937bc1481dceb7e0336bfae75b856b4fb272b5093c5d4", size = 4890699, upload-time = "2025-07-16T12:04:25.664Z" }, - { url = "https://files.pythonhosted.org/packages/b5/57/7969af50b26408be12baa317c6147588db5b38af2759e6df94554dbc5fdb/fonttools-4.59.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51ab1ff33c19e336c02dee1e9fd1abd974a4ca3d8f7eef2a104d0816a241ce97", size = 4952934, upload-time = "2025-07-16T12:04:27.733Z" }, - { url = "https://files.pythonhosted.org/packages/d6/e2/dd968053b6cf1f46c904f5bd409b22341477c017d8201619a265e50762d3/fonttools-4.59.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a9bf8adc9e1f3012edc8f09b08336272aec0c55bc677422273e21280db748f7c", size = 4892319, upload-time = "2025-07-16T12:04:30.074Z" }, - { url = "https://files.pythonhosted.org/packages/6b/95/a59810d8eda09129f83467a4e58f84205dc6994ebaeb9815406363e07250/fonttools-4.59.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:37e01c6ec0c98599778c2e688350d624fa4770fbd6144551bd5e032f1199171c", size = 5034753, upload-time = "2025-07-16T12:04:32.292Z" }, - { url = "https://files.pythonhosted.org/packages/a5/84/51a69ee89ff8d1fea0c6997e946657e25a3f08513de8435fe124929f3eef/fonttools-4.59.0-cp313-cp313-win32.whl", hash = "sha256:70d6b3ceaa9cc5a6ac52884f3b3d9544e8e231e95b23f138bdb78e6d4dc0eae3", size = 2199688, upload-time = "2025-07-16T12:04:34.444Z" }, - { url = "https://files.pythonhosted.org/packages/a0/ee/f626cd372932d828508137a79b85167fdcf3adab2e3bed433f295c596c6a/fonttools-4.59.0-cp313-cp313-win_amd64.whl", hash = "sha256:26731739daa23b872643f0e4072d5939960237d540c35c14e6a06d47d71ca8fe", size = 2248560, upload-time = "2025-07-16T12:04:36.034Z" }, - { url = "https://files.pythonhosted.org/packages/d0/9c/df0ef2c51845a13043e5088f7bb988ca6cd5bb82d5d4203d6a158aa58cf2/fonttools-4.59.0-py3-none-any.whl", hash = "sha256:241313683afd3baacb32a6bd124d0bce7404bc5280e12e291bae1b9bba28711d", size = 1128050, upload-time = "2025-07-16T12:04:52.687Z" }, +version = "4.61.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/ca/cf17b88a8df95691275a3d77dc0a5ad9907f328ae53acbe6795da1b2f5ed/fonttools-4.61.1.tar.gz", hash = "sha256:6675329885c44657f826ef01d9e4fb33b9158e9d93c537d84ad8399539bc6f69", size = 3565756, upload-time = "2025-12-12T17:31:24.246Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/16/7decaa24a1bd3a70c607b2e29f0adc6159f36a7e40eaba59846414765fd4/fonttools-4.61.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f3cb4a569029b9f291f88aafc927dd53683757e640081ca8c412781ea144565e", size = 2851593, upload-time = "2025-12-12T17:30:04.225Z" }, + { url = "https://files.pythonhosted.org/packages/94/98/3c4cb97c64713a8cf499b3245c3bf9a2b8fd16a3e375feff2aed78f96259/fonttools-4.61.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41a7170d042e8c0024703ed13b71893519a1a6d6e18e933e3ec7507a2c26a4b2", size = 2400231, upload-time = "2025-12-12T17:30:06.47Z" }, + { url = "https://files.pythonhosted.org/packages/b7/37/82dbef0f6342eb01f54bca073ac1498433d6ce71e50c3c3282b655733b31/fonttools-4.61.1-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:10d88e55330e092940584774ee5e8a6971b01fc2f4d3466a1d6c158230880796", size = 4954103, upload-time = "2025-12-12T17:30:08.432Z" }, + { url = "https://files.pythonhosted.org/packages/6c/44/f3aeac0fa98e7ad527f479e161aca6c3a1e47bb6996b053d45226fe37bf2/fonttools-4.61.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:15acc09befd16a0fb8a8f62bc147e1a82817542d72184acca9ce6e0aeda9fa6d", size = 5004295, upload-time = "2025-12-12T17:30:10.56Z" }, + { url = "https://files.pythonhosted.org/packages/14/e8/7424ced75473983b964d09f6747fa09f054a6d656f60e9ac9324cf40c743/fonttools-4.61.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e6bcdf33aec38d16508ce61fd81838f24c83c90a1d1b8c68982857038673d6b8", size = 4944109, upload-time = "2025-12-12T17:30:12.874Z" }, + { url = "https://files.pythonhosted.org/packages/c8/8b/6391b257fa3d0b553d73e778f953a2f0154292a7a7a085e2374b111e5410/fonttools-4.61.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5fade934607a523614726119164ff621e8c30e8fa1ffffbbd358662056ba69f0", size = 5093598, upload-time = "2025-12-12T17:30:15.79Z" }, + { url = "https://files.pythonhosted.org/packages/d9/71/fd2ea96cdc512d92da5678a1c98c267ddd4d8c5130b76d0f7a80f9a9fde8/fonttools-4.61.1-cp312-cp312-win32.whl", hash = "sha256:75da8f28eff26defba42c52986de97b22106cb8f26515b7c22443ebc9c2d3261", size = 2269060, upload-time = "2025-12-12T17:30:18.058Z" }, + { url = "https://files.pythonhosted.org/packages/80/3b/a3e81b71aed5a688e89dfe0e2694b26b78c7d7f39a5ffd8a7d75f54a12a8/fonttools-4.61.1-cp312-cp312-win_amd64.whl", hash = "sha256:497c31ce314219888c0e2fce5ad9178ca83fe5230b01a5006726cdf3ac9f24d9", size = 2319078, upload-time = "2025-12-12T17:30:22.862Z" }, + { url = "https://files.pythonhosted.org/packages/4b/cf/00ba28b0990982530addb8dc3e9e6f2fa9cb5c20df2abdda7baa755e8fe1/fonttools-4.61.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c56c488ab471628ff3bfa80964372fc13504ece601e0d97a78ee74126b2045c", size = 2846454, upload-time = "2025-12-12T17:30:24.938Z" }, + { url = "https://files.pythonhosted.org/packages/5a/ca/468c9a8446a2103ae645d14fee3f610567b7042aba85031c1c65e3ef7471/fonttools-4.61.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dc492779501fa723b04d0ab1f5be046797fee17d27700476edc7ee9ae535a61e", size = 2398191, upload-time = "2025-12-12T17:30:27.343Z" }, + { url = "https://files.pythonhosted.org/packages/a3/4b/d67eedaed19def5967fade3297fed8161b25ba94699efc124b14fb68cdbc/fonttools-4.61.1-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:64102ca87e84261419c3747a0d20f396eb024bdbeb04c2bfb37e2891f5fadcb5", size = 4928410, upload-time = "2025-12-12T17:30:29.771Z" }, + { url = "https://files.pythonhosted.org/packages/b0/8d/6fb3494dfe61a46258cd93d979cf4725ded4eb46c2a4ca35e4490d84daea/fonttools-4.61.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c1b526c8d3f615a7b1867f38a9410849c8f4aef078535742198e942fba0e9bd", size = 4984460, upload-time = "2025-12-12T17:30:32.073Z" }, + { url = "https://files.pythonhosted.org/packages/f7/f1/a47f1d30b3dc00d75e7af762652d4cbc3dff5c2697a0dbd5203c81afd9c3/fonttools-4.61.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:41ed4b5ec103bd306bb68f81dc166e77409e5209443e5773cb4ed837bcc9b0d3", size = 4925800, upload-time = "2025-12-12T17:30:34.339Z" }, + { url = "https://files.pythonhosted.org/packages/a7/01/e6ae64a0981076e8a66906fab01539799546181e32a37a0257b77e4aa88b/fonttools-4.61.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b501c862d4901792adaec7c25b1ecc749e2662543f68bb194c42ba18d6eec98d", size = 5067859, upload-time = "2025-12-12T17:30:36.593Z" }, + { url = "https://files.pythonhosted.org/packages/73/aa/28e40b8d6809a9b5075350a86779163f074d2b617c15d22343fce81918db/fonttools-4.61.1-cp313-cp313-win32.whl", hash = "sha256:4d7092bb38c53bbc78e9255a59158b150bcdc115a1e3b3ce0b5f267dc35dd63c", size = 2267821, upload-time = "2025-12-12T17:30:38.478Z" }, + { url = "https://files.pythonhosted.org/packages/1a/59/453c06d1d83dc0951b69ef692d6b9f1846680342927df54e9a1ca91c6f90/fonttools-4.61.1-cp313-cp313-win_amd64.whl", hash = "sha256:21e7c8d76f62ab13c9472ccf74515ca5b9a761d1bde3265152a6dc58700d895b", size = 2318169, upload-time = "2025-12-12T17:30:40.951Z" }, + { url = "https://files.pythonhosted.org/packages/32/8f/4e7bf82c0cbb738d3c2206c920ca34ca74ef9dabde779030145d28665104/fonttools-4.61.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fff4f534200a04b4a36e7ae3cb74493afe807b517a09e99cb4faa89a34ed6ecd", size = 2846094, upload-time = "2025-12-12T17:30:43.511Z" }, + { url = "https://files.pythonhosted.org/packages/71/09/d44e45d0a4f3a651f23a1e9d42de43bc643cce2971b19e784cc67d823676/fonttools-4.61.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d9203500f7c63545b4ce3799319fe4d9feb1a1b89b28d3cb5abd11b9dd64147e", size = 2396589, upload-time = "2025-12-12T17:30:45.681Z" }, + { url = "https://files.pythonhosted.org/packages/89/18/58c64cafcf8eb677a99ef593121f719e6dcbdb7d1c594ae5a10d4997ca8a/fonttools-4.61.1-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fa646ecec9528bef693415c79a86e733c70a4965dd938e9a226b0fc64c9d2e6c", size = 4877892, upload-time = "2025-12-12T17:30:47.709Z" }, + { url = "https://files.pythonhosted.org/packages/8a/ec/9e6b38c7ba1e09eb51db849d5450f4c05b7e78481f662c3b79dbde6f3d04/fonttools-4.61.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:11f35ad7805edba3aac1a3710d104592df59f4b957e30108ae0ba6c10b11dd75", size = 4972884, upload-time = "2025-12-12T17:30:49.656Z" }, + { url = "https://files.pythonhosted.org/packages/5e/87/b5339da8e0256734ba0dbbf5b6cdebb1dd79b01dc8c270989b7bcd465541/fonttools-4.61.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b931ae8f62db78861b0ff1ac017851764602288575d65b8e8ff1963fed419063", size = 4924405, upload-time = "2025-12-12T17:30:51.735Z" }, + { url = "https://files.pythonhosted.org/packages/0b/47/e3409f1e1e69c073a3a6fd8cb886eb18c0bae0ee13db2c8d5e7f8495e8b7/fonttools-4.61.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b148b56f5de675ee16d45e769e69f87623a4944f7443850bf9a9376e628a89d2", size = 5035553, upload-time = "2025-12-12T17:30:54.823Z" }, + { url = "https://files.pythonhosted.org/packages/bf/b6/1f6600161b1073a984294c6c031e1a56ebf95b6164249eecf30012bb2e38/fonttools-4.61.1-cp314-cp314-win32.whl", hash = "sha256:9b666a475a65f4e839d3d10473fad6d47e0a9db14a2f4a224029c5bfde58ad2c", size = 2271915, upload-time = "2025-12-12T17:30:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/52/7b/91e7b01e37cc8eb0e1f770d08305b3655e4f002fc160fb82b3390eabacf5/fonttools-4.61.1-cp314-cp314-win_amd64.whl", hash = "sha256:4f5686e1fe5fce75d82d93c47a438a25bf0d1319d2843a926f741140b2b16e0c", size = 2323487, upload-time = "2025-12-12T17:30:59.804Z" }, + { url = "https://files.pythonhosted.org/packages/39/5c/908ad78e46c61c3e3ed70c3b58ff82ab48437faf84ec84f109592cabbd9f/fonttools-4.61.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:e76ce097e3c57c4bcb67c5aa24a0ecdbd9f74ea9219997a707a4061fbe2707aa", size = 2929571, upload-time = "2025-12-12T17:31:02.574Z" }, + { url = "https://files.pythonhosted.org/packages/bd/41/975804132c6dea64cdbfbaa59f3518a21c137a10cccf962805b301ac6ab2/fonttools-4.61.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:9cfef3ab326780c04d6646f68d4b4742aae222e8b8ea1d627c74e38afcbc9d91", size = 2435317, upload-time = "2025-12-12T17:31:04.974Z" }, + { url = "https://files.pythonhosted.org/packages/b0/5a/aef2a0a8daf1ebaae4cfd83f84186d4a72ee08fd6a8451289fcd03ffa8a4/fonttools-4.61.1-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a75c301f96db737e1c5ed5fd7d77d9c34466de16095a266509e13da09751bd19", size = 4882124, upload-time = "2025-12-12T17:31:07.456Z" }, + { url = "https://files.pythonhosted.org/packages/80/33/d6db3485b645b81cea538c9d1c9219d5805f0877fda18777add4671c5240/fonttools-4.61.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:91669ccac46bbc1d09e9273546181919064e8df73488ea087dcac3e2968df9ba", size = 5100391, upload-time = "2025-12-12T17:31:09.732Z" }, + { url = "https://files.pythonhosted.org/packages/6c/d6/675ba631454043c75fcf76f0ca5463eac8eb0666ea1d7badae5fea001155/fonttools-4.61.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c33ab3ca9d3ccd581d58e989d67554e42d8d4ded94ab3ade3508455fe70e65f7", size = 4978800, upload-time = "2025-12-12T17:31:11.681Z" }, + { url = "https://files.pythonhosted.org/packages/7f/33/d3ec753d547a8d2bdaedd390d4a814e8d5b45a093d558f025c6b990b554c/fonttools-4.61.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:664c5a68ec406f6b1547946683008576ef8b38275608e1cee6c061828171c118", size = 5006426, upload-time = "2025-12-12T17:31:13.764Z" }, + { url = "https://files.pythonhosted.org/packages/b4/40/cc11f378b561a67bea850ab50063366a0d1dd3f6d0a30ce0f874b0ad5664/fonttools-4.61.1-cp314-cp314t-win32.whl", hash = "sha256:aed04cabe26f30c1647ef0e8fbb207516fd40fe9472e9439695f5c6998e60ac5", size = 2335377, upload-time = "2025-12-12T17:31:16.49Z" }, + { url = "https://files.pythonhosted.org/packages/e4/ff/c9a2b66b39f8628531ea58b320d66d951267c98c6a38684daa8f50fb02f8/fonttools-4.61.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2180f14c141d2f0f3da43f3a81bc8aa4684860f6b0e6f9e165a4831f24e6a23b", size = 2400613, upload-time = "2025-12-12T17:31:18.769Z" }, + { url = "https://files.pythonhosted.org/packages/c7/4e/ce75a57ff3aebf6fc1f4e9d508b8e5810618a33d900ad6c19eb30b290b97/fonttools-4.61.1-py3-none-any.whl", hash = "sha256:17d2bf5d541add43822bcf0c43d7d847b160c9bb01d15d5007d84e2217aaa371", size = 1148996, upload-time = "2025-12-12T17:31:21.03Z" }, ] [[package]] @@ -328,17 +431,25 @@ wheels = [ [[package]] name = "gurobipy" -version = "12.0.3" +version = "13.0.1" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6f/bb/b3784497115c64c2bd122cc9d411f167026d4ec42a26b1ff3c43a779275d/gurobipy-12.0.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:020f23277f630e079eac114385eabd1bd9fb4ac22f8796ed5ba6d915ce4f141b", size = 12222234, upload-time = "2025-07-15T07:19:24.64Z" }, - { url = "https://files.pythonhosted.org/packages/18/ea/c065984de5287c99fd30ee8d700fd78f83692e992471f9667ab5d36612b9/gurobipy-12.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:72bbf544bc05060bb93909b79715ace4c0f416198f7622a985cabb9e8e99aa1c", size = 62583866, upload-time = "2025-07-15T07:20:17.576Z" }, - { url = "https://files.pythonhosted.org/packages/9b/8b/2b9f26e4e19a258229b8a8ffc377ca372cc2059a22a0a7c67572efe308d8/gurobipy-12.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b3f971caf270f671b6ffcf5b937b3c0430a5264b0f01529dc8681d61c221f215", size = 14268480, upload-time = "2025-07-15T07:20:26.898Z" }, - { url = "https://files.pythonhosted.org/packages/26/0f/3544a323635f37cdfe1e011d2903b7ef94ba18e10224fa1419f64d0c1968/gurobipy-12.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:af18fd03d5dc3f6e5f590c372ad288b8430a6d88a5b5e66cfcd8432f86ee8650", size = 11121565, upload-time = "2025-07-15T07:20:34.576Z" }, - { url = "https://files.pythonhosted.org/packages/5e/95/f0e5b5cf85298f42482cf4e53d8114c45bb962f55195d531fe4e62b5afa1/gurobipy-12.0.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a8552e47673cb6f1fd351edf8fcad86b02f832cbfb57d90ef21e0397e96d138e", size = 12183439, upload-time = "2025-07-15T07:20:44.224Z" }, - { url = "https://files.pythonhosted.org/packages/61/6e/aea725b4143faa4eb6878414a91fa74e7871aba0ab9453803a9eeef781c2/gurobipy-12.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:be05c074141c8a126c8aaeccc41795ab091a666eabb39ca1ff98a74bde81e663", size = 62583451, upload-time = "2025-07-15T07:21:38.825Z" }, - { url = "https://files.pythonhosted.org/packages/75/47/7b9c63ce2cd85d796403b91a6d211d5c8baac7b694edd94e2151f365d6a9/gurobipy-12.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:79a333766e27fef7902ceeefbcf0279a1ca393a27a72ea62f8e301b21aa17d59", size = 14271076, upload-time = "2025-07-15T07:21:55.102Z" }, - { url = "https://files.pythonhosted.org/packages/2a/93/b10cd6112c05675fed5c817fd7933c9d4ba3a7039e42cba844a9ac09242a/gurobipy-12.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:e0f9ed55077e622021369bb9df2ca3b00c86b678792a3b1556cc59f67348fab0", size = 11111414, upload-time = "2025-07-15T07:22:05.079Z" }, + { url = "https://files.pythonhosted.org/packages/c1/5f/7cc9a23fac538e200ec0985cce6abce5f5dcc1187e63e21167b5d5bbefca/gurobipy-13.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:850f553795a5f11439dd2844e6afcbab380db191d7dbb5bb6f4e6b19e1fde637", size = 15963915, upload-time = "2026-01-21T10:36:36.074Z" }, + { url = "https://files.pythonhosted.org/packages/85/9b/9363877895a78258f24a883b137fae83e5cc5e33ed3768618f8ae2aa8da3/gurobipy-13.0.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8848329014960a640c57136bf2adc6a75dc73716f50729ca6c86d68b9f0b6b2", size = 14843835, upload-time = "2026-01-21T10:36:49.236Z" }, + { url = "https://files.pythonhosted.org/packages/87/05/2fc774d1df58f5e9f798d90e39ca15cf6f0f94635669e6a83c97901e0d1f/gurobipy-13.0.1-cp312-cp312-manylinux_2_26_aarch64.whl", hash = "sha256:c0a4232009a133e4a69375f3ce547c66dc31269afc86f6d5d794137d2331b84f", size = 87192977, upload-time = "2026-01-21T10:38:08.088Z" }, + { url = "https://files.pythonhosted.org/packages/8d/c7/c106367b5209ab5500df8feed64d596276d7e78fe7ab3b918ac938ce580b/gurobipy-13.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:a77a8fa0937b274382dd3b436ab1aada3730d4270fb819b22614725dac927d9c", size = 11222551, upload-time = "2026-01-21T10:38:23.295Z" }, + { url = "https://files.pythonhosted.org/packages/b3/32/75c9df1755b20422155674b8d189ca62cf6d069b7c9de1f8e5348e3bdd29/gurobipy-13.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8fc13ccec3ebd66e2aee9d62e22854bb33d27336d12ae6465a9d02fe8371d0b7", size = 15953428, upload-time = "2026-01-21T10:38:39.935Z" }, + { url = "https://files.pythonhosted.org/packages/10/b2/b829bf5ad5f0f241bbdcbeca2fccc0655452ed7c7e55787f446d6e773142/gurobipy-13.0.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c159bac8c7eb2f4acc81579ba3f5860326fb2ca3a9d77f60f14d0686009b4687", size = 14844652, upload-time = "2026-01-21T10:38:52.84Z" }, + { url = "https://files.pythonhosted.org/packages/2e/8d/cbf532a8c373ee47d46f300a18498a478de69929cb93e1e3dd40ceb45e15/gurobipy-13.0.1-cp313-cp313-manylinux_2_26_aarch64.whl", hash = "sha256:42f1dfb2c6e72b0a0199caaa05b38fdb02dc949ef1a25eb4e789fc5ea52d938e", size = 87197330, upload-time = "2026-01-21T10:40:07.251Z" }, + { url = "https://files.pythonhosted.org/packages/de/98/ae44df62a7bc1f4b78770713f00014557e520a268544640e90fa63cc50f2/gurobipy-13.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:532794c3204163315225f7b84776df4aa1b9b68e612596221d928066bf36b1a7", size = 11216528, upload-time = "2026-01-21T10:40:20.473Z" }, + { url = "https://files.pythonhosted.org/packages/18/4d/3ce4f83b5631bbda7f59321453341e8b7ecf927dffb569084178248a8c0a/gurobipy-13.0.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:402cad299b4f4b37460ca8342e315b252ff2e7086a6bc99ca2d35f79c6173d5c", size = 15821573, upload-time = "2026-01-21T10:40:37.459Z" }, + { url = "https://files.pythonhosted.org/packages/1e/5d/f8bc51c76f80f133cb57be3c6fa8f664cb2308a498a0f0d0b6081c554c56/gurobipy-13.0.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5944820a3278b964f0c48b1ab083a2cc4999f47b99068595574177c0f8973826", size = 14743643, upload-time = "2026-01-21T10:40:53.101Z" }, + { url = "https://files.pythonhosted.org/packages/26/53/515e60ee42248d22242c4d0774ae504e775cef26fea9ffd8a174459bb2e6/gurobipy-13.0.1-cp314-cp314-manylinux_2_26_aarch64.whl", hash = "sha256:a8700e549c2667aa235034a6149af16a2138ba7c1f9ecd15b55754704ab6ceaf", size = 87125439, upload-time = "2026-01-21T10:42:07.665Z" }, + { url = "https://files.pythonhosted.org/packages/55/cc/96058a65f18ba427ed5d148065b1e3c44fdffaf4125e81f1b5d2cd1fd192/gurobipy-13.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:d7374de3d602364480de330847c0c642ccf05d13edde431fda7061b092add1e4", size = 11437728, upload-time = "2026-01-21T10:43:56.314Z" }, + { url = "https://files.pythonhosted.org/packages/eb/73/dfed3c9c9727f825457f15bc2fc606204a96df81c7a6182b23b298de2ae5/gurobipy-13.0.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:e9de59083600c7a4b52e3ea48d126ece9c491326138e16e8523c9d81e8519656", size = 16136707, upload-time = "2026-01-21T10:42:21.097Z" }, + { url = "https://files.pythonhosted.org/packages/9f/6b/56939031627076c2df54685e652a5a7a41b56112c0aa67fb2bcc8f8d5190/gurobipy-13.0.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f7e556a4e7dd077a53fa6a683805e409ce66bae33b9b2af2122e81432d32b02a", size = 14738383, upload-time = "2026-01-21T10:42:34.24Z" }, + { url = "https://files.pythonhosted.org/packages/d9/67/c8e65fef49bbbfd0f526d90713b49e61c7df8f4e302df4868efe5544e98d/gurobipy-13.0.1-cp314-cp314t-manylinux_2_26_aarch64.whl", hash = "sha256:81405565946d7e212890884c7569e0af4183178d67dfcadaec861b16172012eb", size = 87122127, upload-time = "2026-01-21T10:43:36.176Z" }, + { url = "https://files.pythonhosted.org/packages/9d/6b/b5a10633dc2bf62c8e15c0f114e064b68a7cc0b147f800d630d02830b09d/gurobipy-13.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:70348777693ed8b7348fe43db4444151d49ab7dec7d46b959fb98c2c1e557028", size = 11879457, upload-time = "2026-01-21T10:43:48.059Z" }, ] [[package]] @@ -374,20 +485,20 @@ wheels = [ [[package]] name = "identify" -version = "2.6.12" +version = "2.6.16" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/88/d193a27416618628a5eea64e3223acd800b40749a96ffb322a9b55a49ed1/identify-2.6.12.tar.gz", hash = "sha256:d8de45749f1efb108badef65ee8386f0f7bb19a7f26185f74de6367bffbaf0e6", size = 99254, upload-time = "2025-05-23T20:37:53.3Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/8d/e8b97e6bd3fb6fb271346f7981362f1e04d6a7463abd0de79e1fda17c067/identify-2.6.16.tar.gz", hash = "sha256:846857203b5511bbe94d5a352a48ef2359532bc8f6727b5544077a0dcfb24980", size = 99360, upload-time = "2026-01-12T18:58:58.201Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/cd/18f8da995b658420625f7ef13f037be53ae04ec5ad33f9b718240dcfd48c/identify-2.6.12-py2.py3-none-any.whl", hash = "sha256:ad9672d5a72e0d2ff7c5c8809b62dfa60458626352fb0eb7b55e69bdc45334a2", size = 99145, upload-time = "2025-05-23T20:37:51.495Z" }, + { url = "https://files.pythonhosted.org/packages/b8/58/40fbbcefeda82364720eba5cf2270f98496bdfa19ea75b4cccae79c698e6/identify-2.6.16-py2.py3-none-any.whl", hash = "sha256:391ee4d77741d994189522896270b787aed8670389bfd60f326d677d64a6dfb0", size = 99202, upload-time = "2026-01-12T18:58:56.627Z" }, ] [[package]] name = "idna" -version = "3.10" +version = "3.11" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, ] [[package]] @@ -401,11 +512,11 @@ wheels = [ [[package]] name = "iniconfig" -version = "2.1.0" +version = "2.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, ] [[package]] @@ -422,62 +533,83 @@ wheels = [ [[package]] name = "joblib" -version = "1.5.2" +version = "1.5.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/5d/447af5ea094b9e4c4054f82e223ada074c552335b9b4b2d14bd9b35a67c4/joblib-1.5.2.tar.gz", hash = "sha256:3faa5c39054b2f03ca547da9b2f52fde67c06240c31853f306aea97f13647b55", size = 331077, upload-time = "2025-08-27T12:15:46.575Z" } +sdist = { url = "https://files.pythonhosted.org/packages/41/f2/d34e8b3a08a9cc79a50b2208a93dce981fe615b64d5a4d4abee421d898df/joblib-1.5.3.tar.gz", hash = "sha256:8561a3269e6801106863fd0d6d84bb737be9e7631e33aaed3fb9ce5953688da3", size = 331603, upload-time = "2025-12-15T08:41:46.427Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/e8/685f47e0d754320684db4425a0967f7d3fa70126bffd76110b7009a0090f/joblib-1.5.2-py3-none-any.whl", hash = "sha256:4e1f0bdbb987e6d843c70cf43714cb276623def372df3c22fe5266b2670bc241", size = 308396, upload-time = "2025-08-27T12:15:45.188Z" }, + { url = "https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713", size = 309071, upload-time = "2025-12-15T08:41:44.973Z" }, ] [[package]] name = "kiwisolver" -version = "1.4.8" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/82/59/7c91426a8ac292e1cdd53a63b6d9439abd573c875c3f92c146767dd33faf/kiwisolver-1.4.8.tar.gz", hash = "sha256:23d5f023bdc8c7e54eb65f03ca5d5bb25b601eac4d7f1a042888a1f45237987e", size = 97538, upload-time = "2024-12-24T18:30:51.519Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/aa/cea685c4ab647f349c3bc92d2daf7ae34c8e8cf405a6dcd3a497f58a2ac3/kiwisolver-1.4.8-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d6af5e8815fd02997cb6ad9bbed0ee1e60014438ee1a5c2444c96f87b8843502", size = 124152, upload-time = "2024-12-24T18:29:16.85Z" }, - { url = "https://files.pythonhosted.org/packages/c5/0b/8db6d2e2452d60d5ebc4ce4b204feeb16176a851fd42462f66ade6808084/kiwisolver-1.4.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bade438f86e21d91e0cf5dd7c0ed00cda0f77c8c1616bd83f9fc157fa6760d31", size = 66555, upload-time = "2024-12-24T18:29:19.146Z" }, - { url = "https://files.pythonhosted.org/packages/60/26/d6a0db6785dd35d3ba5bf2b2df0aedc5af089962c6eb2cbf67a15b81369e/kiwisolver-1.4.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b83dc6769ddbc57613280118fb4ce3cd08899cc3369f7d0e0fab518a7cf37fdb", size = 65067, upload-time = "2024-12-24T18:29:20.096Z" }, - { url = "https://files.pythonhosted.org/packages/c9/ed/1d97f7e3561e09757a196231edccc1bcf59d55ddccefa2afc9c615abd8e0/kiwisolver-1.4.8-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:111793b232842991be367ed828076b03d96202c19221b5ebab421ce8bcad016f", size = 1378443, upload-time = "2024-12-24T18:29:22.843Z" }, - { url = "https://files.pythonhosted.org/packages/29/61/39d30b99954e6b46f760e6289c12fede2ab96a254c443639052d1b573fbc/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:257af1622860e51b1a9d0ce387bf5c2c4f36a90594cb9514f55b074bcc787cfc", size = 1472728, upload-time = "2024-12-24T18:29:24.463Z" }, - { url = "https://files.pythonhosted.org/packages/0c/3e/804163b932f7603ef256e4a715e5843a9600802bb23a68b4e08c8c0ff61d/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69b5637c3f316cab1ec1c9a12b8c5f4750a4c4b71af9157645bf32830e39c03a", size = 1478388, upload-time = "2024-12-24T18:29:25.776Z" }, - { url = "https://files.pythonhosted.org/packages/8a/9e/60eaa75169a154700be74f875a4d9961b11ba048bef315fbe89cb6999056/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:782bb86f245ec18009890e7cb8d13a5ef54dcf2ebe18ed65f795e635a96a1c6a", size = 1413849, upload-time = "2024-12-24T18:29:27.202Z" }, - { url = "https://files.pythonhosted.org/packages/bc/b3/9458adb9472e61a998c8c4d95cfdfec91c73c53a375b30b1428310f923e4/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc978a80a0db3a66d25767b03688f1147a69e6237175c0f4ffffaaedf744055a", size = 1475533, upload-time = "2024-12-24T18:29:28.638Z" }, - { url = "https://files.pythonhosted.org/packages/e4/7a/0a42d9571e35798de80aef4bb43a9b672aa7f8e58643d7bd1950398ffb0a/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:36dbbfd34838500a31f52c9786990d00150860e46cd5041386f217101350f0d3", size = 2268898, upload-time = "2024-12-24T18:29:30.368Z" }, - { url = "https://files.pythonhosted.org/packages/d9/07/1255dc8d80271400126ed8db35a1795b1a2c098ac3a72645075d06fe5c5d/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:eaa973f1e05131de5ff3569bbba7f5fd07ea0595d3870ed4a526d486fe57fa1b", size = 2425605, upload-time = "2024-12-24T18:29:33.151Z" }, - { url = "https://files.pythonhosted.org/packages/84/df/5a3b4cf13780ef6f6942df67b138b03b7e79e9f1f08f57c49957d5867f6e/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a66f60f8d0c87ab7f59b6fb80e642ebb29fec354a4dfad687ca4092ae69d04f4", size = 2375801, upload-time = "2024-12-24T18:29:34.584Z" }, - { url = "https://files.pythonhosted.org/packages/8f/10/2348d068e8b0f635c8c86892788dac7a6b5c0cb12356620ab575775aad89/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:858416b7fb777a53f0c59ca08190ce24e9abbd3cffa18886a5781b8e3e26f65d", size = 2520077, upload-time = "2024-12-24T18:29:36.138Z" }, - { url = "https://files.pythonhosted.org/packages/32/d8/014b89fee5d4dce157d814303b0fce4d31385a2af4c41fed194b173b81ac/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:085940635c62697391baafaaeabdf3dd7a6c3643577dde337f4d66eba021b2b8", size = 2338410, upload-time = "2024-12-24T18:29:39.991Z" }, - { url = "https://files.pythonhosted.org/packages/bd/72/dfff0cc97f2a0776e1c9eb5bef1ddfd45f46246c6533b0191887a427bca5/kiwisolver-1.4.8-cp312-cp312-win_amd64.whl", hash = "sha256:01c3d31902c7db5fb6182832713d3b4122ad9317c2c5877d0539227d96bb2e50", size = 71853, upload-time = "2024-12-24T18:29:42.006Z" }, - { url = "https://files.pythonhosted.org/packages/dc/85/220d13d914485c0948a00f0b9eb419efaf6da81b7d72e88ce2391f7aed8d/kiwisolver-1.4.8-cp312-cp312-win_arm64.whl", hash = "sha256:a3c44cb68861de93f0c4a8175fbaa691f0aa22550c331fefef02b618a9dcb476", size = 65424, upload-time = "2024-12-24T18:29:44.38Z" }, - { url = "https://files.pythonhosted.org/packages/79/b3/e62464a652f4f8cd9006e13d07abad844a47df1e6537f73ddfbf1bc997ec/kiwisolver-1.4.8-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1c8ceb754339793c24aee1c9fb2485b5b1f5bb1c2c214ff13368431e51fc9a09", size = 124156, upload-time = "2024-12-24T18:29:45.368Z" }, - { url = "https://files.pythonhosted.org/packages/8d/2d/f13d06998b546a2ad4f48607a146e045bbe48030774de29f90bdc573df15/kiwisolver-1.4.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a62808ac74b5e55a04a408cda6156f986cefbcf0ada13572696b507cc92fa1", size = 66555, upload-time = "2024-12-24T18:29:46.37Z" }, - { url = "https://files.pythonhosted.org/packages/59/e3/b8bd14b0a54998a9fd1e8da591c60998dc003618cb19a3f94cb233ec1511/kiwisolver-1.4.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:68269e60ee4929893aad82666821aaacbd455284124817af45c11e50a4b42e3c", size = 65071, upload-time = "2024-12-24T18:29:47.333Z" }, - { url = "https://files.pythonhosted.org/packages/f0/1c/6c86f6d85ffe4d0ce04228d976f00674f1df5dc893bf2dd4f1928748f187/kiwisolver-1.4.8-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34d142fba9c464bc3bbfeff15c96eab0e7310343d6aefb62a79d51421fcc5f1b", size = 1378053, upload-time = "2024-12-24T18:29:49.636Z" }, - { url = "https://files.pythonhosted.org/packages/4e/b9/1c6e9f6dcb103ac5cf87cb695845f5fa71379021500153566d8a8a9fc291/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc373e0eef45b59197de815b1b28ef89ae3955e7722cc9710fb91cd77b7f47", size = 1472278, upload-time = "2024-12-24T18:29:51.164Z" }, - { url = "https://files.pythonhosted.org/packages/ee/81/aca1eb176de671f8bda479b11acdc42c132b61a2ac861c883907dde6debb/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77e6f57a20b9bd4e1e2cedda4d0b986ebd0216236f0106e55c28aea3d3d69b16", size = 1478139, upload-time = "2024-12-24T18:29:52.594Z" }, - { url = "https://files.pythonhosted.org/packages/49/f4/e081522473671c97b2687d380e9e4c26f748a86363ce5af48b4a28e48d06/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08e77738ed7538f036cd1170cbed942ef749137b1311fa2bbe2a7fda2f6bf3cc", size = 1413517, upload-time = "2024-12-24T18:29:53.941Z" }, - { url = "https://files.pythonhosted.org/packages/8f/e9/6a7d025d8da8c4931522922cd706105aa32b3291d1add8c5427cdcd66e63/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5ce1e481a74b44dd5e92ff03ea0cb371ae7a0268318e202be06c8f04f4f1246", size = 1474952, upload-time = "2024-12-24T18:29:56.523Z" }, - { url = "https://files.pythonhosted.org/packages/82/13/13fa685ae167bee5d94b415991c4fc7bb0a1b6ebea6e753a87044b209678/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fc2ace710ba7c1dfd1a3b42530b62b9ceed115f19a1656adefce7b1782a37794", size = 2269132, upload-time = "2024-12-24T18:29:57.989Z" }, - { url = "https://files.pythonhosted.org/packages/ef/92/bb7c9395489b99a6cb41d502d3686bac692586db2045adc19e45ee64ed23/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:3452046c37c7692bd52b0e752b87954ef86ee2224e624ef7ce6cb21e8c41cc1b", size = 2425997, upload-time = "2024-12-24T18:29:59.393Z" }, - { url = "https://files.pythonhosted.org/packages/ed/12/87f0e9271e2b63d35d0d8524954145837dd1a6c15b62a2d8c1ebe0f182b4/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7e9a60b50fe8b2ec6f448fe8d81b07e40141bfced7f896309df271a0b92f80f3", size = 2376060, upload-time = "2024-12-24T18:30:01.338Z" }, - { url = "https://files.pythonhosted.org/packages/02/6e/c8af39288edbce8bf0fa35dee427b082758a4b71e9c91ef18fa667782138/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:918139571133f366e8362fa4a297aeba86c7816b7ecf0bc79168080e2bd79957", size = 2520471, upload-time = "2024-12-24T18:30:04.574Z" }, - { url = "https://files.pythonhosted.org/packages/13/78/df381bc7b26e535c91469f77f16adcd073beb3e2dd25042efd064af82323/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e063ef9f89885a1d68dd8b2e18f5ead48653176d10a0e324e3b0030e3a69adeb", size = 2338793, upload-time = "2024-12-24T18:30:06.25Z" }, - { url = "https://files.pythonhosted.org/packages/d0/dc/c1abe38c37c071d0fc71c9a474fd0b9ede05d42f5a458d584619cfd2371a/kiwisolver-1.4.8-cp313-cp313-win_amd64.whl", hash = "sha256:a17b7c4f5b2c51bb68ed379defd608a03954a1845dfed7cc0117f1cc8a9b7fd2", size = 71855, upload-time = "2024-12-24T18:30:07.535Z" }, - { url = "https://files.pythonhosted.org/packages/a0/b6/21529d595b126ac298fdd90b705d87d4c5693de60023e0efcb4f387ed99e/kiwisolver-1.4.8-cp313-cp313-win_arm64.whl", hash = "sha256:3cd3bc628b25f74aedc6d374d5babf0166a92ff1317f46267f12d2ed54bc1d30", size = 65430, upload-time = "2024-12-24T18:30:08.504Z" }, - { url = "https://files.pythonhosted.org/packages/34/bd/b89380b7298e3af9b39f49334e3e2a4af0e04819789f04b43d560516c0c8/kiwisolver-1.4.8-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:370fd2df41660ed4e26b8c9d6bbcad668fbe2560462cba151a721d49e5b6628c", size = 126294, upload-time = "2024-12-24T18:30:09.508Z" }, - { url = "https://files.pythonhosted.org/packages/83/41/5857dc72e5e4148eaac5aa76e0703e594e4465f8ab7ec0fc60e3a9bb8fea/kiwisolver-1.4.8-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:84a2f830d42707de1d191b9490ac186bf7997a9495d4e9072210a1296345f7dc", size = 67736, upload-time = "2024-12-24T18:30:11.039Z" }, - { url = "https://files.pythonhosted.org/packages/e1/d1/be059b8db56ac270489fb0b3297fd1e53d195ba76e9bbb30e5401fa6b759/kiwisolver-1.4.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7a3ad337add5148cf51ce0b55642dc551c0b9d6248458a757f98796ca7348712", size = 66194, upload-time = "2024-12-24T18:30:14.886Z" }, - { url = "https://files.pythonhosted.org/packages/e1/83/4b73975f149819eb7dcf9299ed467eba068ecb16439a98990dcb12e63fdd/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7506488470f41169b86d8c9aeff587293f530a23a23a49d6bc64dab66bedc71e", size = 1465942, upload-time = "2024-12-24T18:30:18.927Z" }, - { url = "https://files.pythonhosted.org/packages/c7/2c/30a5cdde5102958e602c07466bce058b9d7cb48734aa7a4327261ac8e002/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f0121b07b356a22fb0414cec4666bbe36fd6d0d759db3d37228f496ed67c880", size = 1595341, upload-time = "2024-12-24T18:30:22.102Z" }, - { url = "https://files.pythonhosted.org/packages/ff/9b/1e71db1c000385aa069704f5990574b8244cce854ecd83119c19e83c9586/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d6d6bd87df62c27d4185de7c511c6248040afae67028a8a22012b010bc7ad062", size = 1598455, upload-time = "2024-12-24T18:30:24.947Z" }, - { url = "https://files.pythonhosted.org/packages/85/92/c8fec52ddf06231b31cbb779af77e99b8253cd96bd135250b9498144c78b/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:291331973c64bb9cce50bbe871fb2e675c4331dab4f31abe89f175ad7679a4d7", size = 1522138, upload-time = "2024-12-24T18:30:26.286Z" }, - { url = "https://files.pythonhosted.org/packages/0b/51/9eb7e2cd07a15d8bdd976f6190c0164f92ce1904e5c0c79198c4972926b7/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:893f5525bb92d3d735878ec00f781b2de998333659507d29ea4466208df37bed", size = 1582857, upload-time = "2024-12-24T18:30:28.86Z" }, - { url = "https://files.pythonhosted.org/packages/0f/95/c5a00387a5405e68ba32cc64af65ce881a39b98d73cc394b24143bebc5b8/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b47a465040146981dc9db8647981b8cb96366fbc8d452b031e4f8fdffec3f26d", size = 2293129, upload-time = "2024-12-24T18:30:30.34Z" }, - { url = "https://files.pythonhosted.org/packages/44/83/eeb7af7d706b8347548313fa3a3a15931f404533cc54fe01f39e830dd231/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:99cea8b9dd34ff80c521aef46a1dddb0dcc0283cf18bde6d756f1e6f31772165", size = 2421538, upload-time = "2024-12-24T18:30:33.334Z" }, - { url = "https://files.pythonhosted.org/packages/05/f9/27e94c1b3eb29e6933b6986ffc5fa1177d2cd1f0c8efc5f02c91c9ac61de/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:151dffc4865e5fe6dafce5480fab84f950d14566c480c08a53c663a0020504b6", size = 2390661, upload-time = "2024-12-24T18:30:34.939Z" }, - { url = "https://files.pythonhosted.org/packages/d9/d4/3c9735faa36ac591a4afcc2980d2691000506050b7a7e80bcfe44048daa7/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:577facaa411c10421314598b50413aa1ebcf5126f704f1e5d72d7e4e9f020d90", size = 2546710, upload-time = "2024-12-24T18:30:37.281Z" }, - { url = "https://files.pythonhosted.org/packages/4c/fa/be89a49c640930180657482a74970cdcf6f7072c8d2471e1babe17a222dc/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:be4816dc51c8a471749d664161b434912eee82f2ea66bd7628bd14583a833e85", size = 2349213, upload-time = "2024-12-24T18:30:40.019Z" }, +version = "1.4.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564, upload-time = "2025-08-10T21:27:49.279Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/c9/13573a747838aeb1c76e3267620daa054f4152444d1f3d1a2324b78255b5/kiwisolver-1.4.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ac5a486ac389dddcc5bef4f365b6ae3ffff2c433324fb38dd35e3fab7c957999", size = 123686, upload-time = "2025-08-10T21:26:10.034Z" }, + { url = "https://files.pythonhosted.org/packages/51/ea/2ecf727927f103ffd1739271ca19c424d0e65ea473fbaeea1c014aea93f6/kiwisolver-1.4.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2ba92255faa7309d06fe44c3a4a97efe1c8d640c2a79a5ef728b685762a6fd2", size = 66460, upload-time = "2025-08-10T21:26:11.083Z" }, + { url = "https://files.pythonhosted.org/packages/5b/5a/51f5464373ce2aeb5194508298a508b6f21d3867f499556263c64c621914/kiwisolver-1.4.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a2899935e724dd1074cb568ce7ac0dce28b2cd6ab539c8e001a8578eb106d14", size = 64952, upload-time = "2025-08-10T21:26:12.058Z" }, + { url = "https://files.pythonhosted.org/packages/70/90/6d240beb0f24b74371762873e9b7f499f1e02166a2d9c5801f4dbf8fa12e/kiwisolver-1.4.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f6008a4919fdbc0b0097089f67a1eb55d950ed7e90ce2cc3e640abadd2757a04", size = 1474756, upload-time = "2025-08-10T21:26:13.096Z" }, + { url = "https://files.pythonhosted.org/packages/12/42/f36816eaf465220f683fb711efdd1bbf7a7005a2473d0e4ed421389bd26c/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:67bb8b474b4181770f926f7b7d2f8c0248cbcb78b660fdd41a47054b28d2a752", size = 1276404, upload-time = "2025-08-10T21:26:14.457Z" }, + { url = "https://files.pythonhosted.org/packages/2e/64/bc2de94800adc830c476dce44e9b40fd0809cddeef1fde9fcf0f73da301f/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2327a4a30d3ee07d2fbe2e7933e8a37c591663b96ce42a00bc67461a87d7df77", size = 1294410, upload-time = "2025-08-10T21:26:15.73Z" }, + { url = "https://files.pythonhosted.org/packages/5f/42/2dc82330a70aa8e55b6d395b11018045e58d0bb00834502bf11509f79091/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7a08b491ec91b1d5053ac177afe5290adacf1f0f6307d771ccac5de30592d198", size = 1343631, upload-time = "2025-08-10T21:26:17.045Z" }, + { url = "https://files.pythonhosted.org/packages/22/fd/f4c67a6ed1aab149ec5a8a401c323cee7a1cbe364381bb6c9c0d564e0e20/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d8fc5c867c22b828001b6a38d2eaeb88160bf5783c6cb4a5e440efc981ce286d", size = 2224963, upload-time = "2025-08-10T21:26:18.737Z" }, + { url = "https://files.pythonhosted.org/packages/45/aa/76720bd4cb3713314677d9ec94dcc21ced3f1baf4830adde5bb9b2430a5f/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3b3115b2581ea35bb6d1f24a4c90af37e5d9b49dcff267eeed14c3893c5b86ab", size = 2321295, upload-time = "2025-08-10T21:26:20.11Z" }, + { url = "https://files.pythonhosted.org/packages/80/19/d3ec0d9ab711242f56ae0dc2fc5d70e298bb4a1f9dfab44c027668c673a1/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:858e4c22fb075920b96a291928cb7dea5644e94c0ee4fcd5af7e865655e4ccf2", size = 2487987, upload-time = "2025-08-10T21:26:21.49Z" }, + { url = "https://files.pythonhosted.org/packages/39/e9/61e4813b2c97e86b6fdbd4dd824bf72d28bcd8d4849b8084a357bc0dd64d/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ed0fecd28cc62c54b262e3736f8bb2512d8dcfdc2bcf08be5f47f96bf405b145", size = 2291817, upload-time = "2025-08-10T21:26:22.812Z" }, + { url = "https://files.pythonhosted.org/packages/a0/41/85d82b0291db7504da3c2defe35c9a8a5c9803a730f297bd823d11d5fb77/kiwisolver-1.4.9-cp312-cp312-win_amd64.whl", hash = "sha256:f68208a520c3d86ea51acf688a3e3002615a7f0238002cccc17affecc86a8a54", size = 73895, upload-time = "2025-08-10T21:26:24.37Z" }, + { url = "https://files.pythonhosted.org/packages/e2/92/5f3068cf15ee5cb624a0c7596e67e2a0bb2adee33f71c379054a491d07da/kiwisolver-1.4.9-cp312-cp312-win_arm64.whl", hash = "sha256:2c1a4f57df73965f3f14df20b80ee29e6a7930a57d2d9e8491a25f676e197c60", size = 64992, upload-time = "2025-08-10T21:26:25.732Z" }, + { url = "https://files.pythonhosted.org/packages/31/c1/c2686cda909742ab66c7388e9a1a8521a59eb89f8bcfbee28fc980d07e24/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5d0432ccf1c7ab14f9949eec60c5d1f924f17c037e9f8b33352fa05799359b8", size = 123681, upload-time = "2025-08-10T21:26:26.725Z" }, + { url = "https://files.pythonhosted.org/packages/ca/f0/f44f50c9f5b1a1860261092e3bc91ecdc9acda848a8b8c6abfda4a24dd5c/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efb3a45b35622bb6c16dbfab491a8f5a391fe0e9d45ef32f4df85658232ca0e2", size = 66464, upload-time = "2025-08-10T21:26:27.733Z" }, + { url = "https://files.pythonhosted.org/packages/2d/7a/9d90a151f558e29c3936b8a47ac770235f436f2120aca41a6d5f3d62ae8d/kiwisolver-1.4.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a12cf6398e8a0a001a059747a1cbf24705e18fe413bc22de7b3d15c67cffe3f", size = 64961, upload-time = "2025-08-10T21:26:28.729Z" }, + { url = "https://files.pythonhosted.org/packages/e9/e9/f218a2cb3a9ffbe324ca29a9e399fa2d2866d7f348ec3a88df87fc248fc5/kiwisolver-1.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b67e6efbf68e077dd71d1a6b37e43e1a99d0bff1a3d51867d45ee8908b931098", size = 1474607, upload-time = "2025-08-10T21:26:29.798Z" }, + { url = "https://files.pythonhosted.org/packages/d9/28/aac26d4c882f14de59041636292bc838db8961373825df23b8eeb807e198/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5656aa670507437af0207645273ccdfee4f14bacd7f7c67a4306d0dcaeaf6eed", size = 1276546, upload-time = "2025-08-10T21:26:31.401Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ad/8bfc1c93d4cc565e5069162f610ba2f48ff39b7de4b5b8d93f69f30c4bed/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bfc08add558155345129c7803b3671cf195e6a56e7a12f3dde7c57d9b417f525", size = 1294482, upload-time = "2025-08-10T21:26:32.721Z" }, + { url = "https://files.pythonhosted.org/packages/da/f1/6aca55ff798901d8ce403206d00e033191f63d82dd708a186e0ed2067e9c/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:40092754720b174e6ccf9e845d0d8c7d8e12c3d71e7fc35f55f3813e96376f78", size = 1343720, upload-time = "2025-08-10T21:26:34.032Z" }, + { url = "https://files.pythonhosted.org/packages/d1/91/eed031876c595c81d90d0f6fc681ece250e14bf6998c3d7c419466b523b7/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:497d05f29a1300d14e02e6441cf0f5ee81c1ff5a304b0d9fb77423974684e08b", size = 2224907, upload-time = "2025-08-10T21:26:35.824Z" }, + { url = "https://files.pythonhosted.org/packages/e9/ec/4d1925f2e49617b9cca9c34bfa11adefad49d00db038e692a559454dfb2e/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdd1a81a1860476eb41ac4bc1e07b3f07259e6d55bbf739b79c8aaedcf512799", size = 2321334, upload-time = "2025-08-10T21:26:37.534Z" }, + { url = "https://files.pythonhosted.org/packages/43/cb/450cd4499356f68802750c6ddc18647b8ea01ffa28f50d20598e0befe6e9/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e6b93f13371d341afee3be9f7c5964e3fe61d5fa30f6a30eb49856935dfe4fc3", size = 2488313, upload-time = "2025-08-10T21:26:39.191Z" }, + { url = "https://files.pythonhosted.org/packages/71/67/fc76242bd99f885651128a5d4fa6083e5524694b7c88b489b1b55fdc491d/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d75aa530ccfaa593da12834b86a0724f58bff12706659baa9227c2ccaa06264c", size = 2291970, upload-time = "2025-08-10T21:26:40.828Z" }, + { url = "https://files.pythonhosted.org/packages/75/bd/f1a5d894000941739f2ae1b65a32892349423ad49c2e6d0771d0bad3fae4/kiwisolver-1.4.9-cp313-cp313-win_amd64.whl", hash = "sha256:dd0a578400839256df88c16abddf9ba14813ec5f21362e1fe65022e00c883d4d", size = 73894, upload-time = "2025-08-10T21:26:42.33Z" }, + { url = "https://files.pythonhosted.org/packages/95/38/dce480814d25b99a391abbddadc78f7c117c6da34be68ca8b02d5848b424/kiwisolver-1.4.9-cp313-cp313-win_arm64.whl", hash = "sha256:d4188e73af84ca82468f09cadc5ac4db578109e52acb4518d8154698d3a87ca2", size = 64995, upload-time = "2025-08-10T21:26:43.889Z" }, + { url = "https://files.pythonhosted.org/packages/e2/37/7d218ce5d92dadc5ebdd9070d903e0c7cf7edfe03f179433ac4d13ce659c/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:5a0f2724dfd4e3b3ac5a82436a8e6fd16baa7d507117e4279b660fe8ca38a3a1", size = 126510, upload-time = "2025-08-10T21:26:44.915Z" }, + { url = "https://files.pythonhosted.org/packages/23/b0/e85a2b48233daef4b648fb657ebbb6f8367696a2d9548a00b4ee0eb67803/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1b11d6a633e4ed84fc0ddafd4ebfd8ea49b3f25082c04ad12b8315c11d504dc1", size = 67903, upload-time = "2025-08-10T21:26:45.934Z" }, + { url = "https://files.pythonhosted.org/packages/44/98/f2425bc0113ad7de24da6bb4dae1343476e95e1d738be7c04d31a5d037fd/kiwisolver-1.4.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61874cdb0a36016354853593cffc38e56fc9ca5aa97d2c05d3dcf6922cd55a11", size = 66402, upload-time = "2025-08-10T21:26:47.101Z" }, + { url = "https://files.pythonhosted.org/packages/98/d8/594657886df9f34c4177cc353cc28ca7e6e5eb562d37ccc233bff43bbe2a/kiwisolver-1.4.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:60c439763a969a6af93b4881db0eed8fadf93ee98e18cbc35bc8da868d0c4f0c", size = 1582135, upload-time = "2025-08-10T21:26:48.665Z" }, + { url = "https://files.pythonhosted.org/packages/5c/c6/38a115b7170f8b306fc929e166340c24958347308ea3012c2b44e7e295db/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92a2f997387a1b79a75e7803aa7ded2cfbe2823852ccf1ba3bcf613b62ae3197", size = 1389409, upload-time = "2025-08-10T21:26:50.335Z" }, + { url = "https://files.pythonhosted.org/packages/bf/3b/e04883dace81f24a568bcee6eb3001da4ba05114afa622ec9b6fafdc1f5e/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31d512c812daea6d8b3be3b2bfcbeb091dbb09177706569bcfc6240dcf8b41c", size = 1401763, upload-time = "2025-08-10T21:26:51.867Z" }, + { url = "https://files.pythonhosted.org/packages/9f/80/20ace48e33408947af49d7d15c341eaee69e4e0304aab4b7660e234d6288/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:52a15b0f35dad39862d376df10c5230155243a2c1a436e39eb55623ccbd68185", size = 1453643, upload-time = "2025-08-10T21:26:53.592Z" }, + { url = "https://files.pythonhosted.org/packages/64/31/6ce4380a4cd1f515bdda976a1e90e547ccd47b67a1546d63884463c92ca9/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a30fd6fdef1430fd9e1ba7b3398b5ee4e2887783917a687d86ba69985fb08748", size = 2330818, upload-time = "2025-08-10T21:26:55.051Z" }, + { url = "https://files.pythonhosted.org/packages/fa/e9/3f3fcba3bcc7432c795b82646306e822f3fd74df0ee81f0fa067a1f95668/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cc9617b46837c6468197b5945e196ee9ca43057bb7d9d1ae688101e4e1dddf64", size = 2419963, upload-time = "2025-08-10T21:26:56.421Z" }, + { url = "https://files.pythonhosted.org/packages/99/43/7320c50e4133575c66e9f7dadead35ab22d7c012a3b09bb35647792b2a6d/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:0ab74e19f6a2b027ea4f845a78827969af45ce790e6cb3e1ebab71bdf9f215ff", size = 2594639, upload-time = "2025-08-10T21:26:57.882Z" }, + { url = "https://files.pythonhosted.org/packages/65/d6/17ae4a270d4a987ef8a385b906d2bdfc9fce502d6dc0d3aea865b47f548c/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dba5ee5d3981160c28d5490f0d1b7ed730c22470ff7f6cc26cfcfaacb9896a07", size = 2391741, upload-time = "2025-08-10T21:26:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/2a/8f/8f6f491d595a9e5912971f3f863d81baddccc8a4d0c3749d6a0dd9ffc9df/kiwisolver-1.4.9-cp313-cp313t-win_arm64.whl", hash = "sha256:0749fd8f4218ad2e851e11cc4dc05c7cbc0cbc4267bdfdb31782e65aace4ee9c", size = 68646, upload-time = "2025-08-10T21:27:00.52Z" }, + { url = "https://files.pythonhosted.org/packages/6b/32/6cc0fbc9c54d06c2969faa9c1d29f5751a2e51809dd55c69055e62d9b426/kiwisolver-1.4.9-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9928fe1eb816d11ae170885a74d074f57af3a0d65777ca47e9aeb854a1fba386", size = 123806, upload-time = "2025-08-10T21:27:01.537Z" }, + { url = "https://files.pythonhosted.org/packages/b2/dd/2bfb1d4a4823d92e8cbb420fe024b8d2167f72079b3bb941207c42570bdf/kiwisolver-1.4.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d0005b053977e7b43388ddec89fa567f43d4f6d5c2c0affe57de5ebf290dc552", size = 66605, upload-time = "2025-08-10T21:27:03.335Z" }, + { url = "https://files.pythonhosted.org/packages/f7/69/00aafdb4e4509c2ca6064646cba9cd4b37933898f426756adb2cb92ebbed/kiwisolver-1.4.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2635d352d67458b66fd0667c14cb1d4145e9560d503219034a18a87e971ce4f3", size = 64925, upload-time = "2025-08-10T21:27:04.339Z" }, + { url = "https://files.pythonhosted.org/packages/43/dc/51acc6791aa14e5cb6d8a2e28cefb0dc2886d8862795449d021334c0df20/kiwisolver-1.4.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:767c23ad1c58c9e827b649a9ab7809fd5fd9db266a9cf02b0e926ddc2c680d58", size = 1472414, upload-time = "2025-08-10T21:27:05.437Z" }, + { url = "https://files.pythonhosted.org/packages/3d/bb/93fa64a81db304ac8a246f834d5094fae4b13baf53c839d6bb6e81177129/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72d0eb9fba308b8311685c2268cf7d0a0639a6cd027d8128659f72bdd8a024b4", size = 1281272, upload-time = "2025-08-10T21:27:07.063Z" }, + { url = "https://files.pythonhosted.org/packages/70/e6/6df102916960fb8d05069d4bd92d6d9a8202d5a3e2444494e7cd50f65b7a/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f68e4f3eeca8fb22cc3d731f9715a13b652795ef657a13df1ad0c7dc0e9731df", size = 1298578, upload-time = "2025-08-10T21:27:08.452Z" }, + { url = "https://files.pythonhosted.org/packages/7c/47/e142aaa612f5343736b087864dbaebc53ea8831453fb47e7521fa8658f30/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d84cd4061ae292d8ac367b2c3fa3aad11cb8625a95d135fe93f286f914f3f5a6", size = 1345607, upload-time = "2025-08-10T21:27:10.125Z" }, + { url = "https://files.pythonhosted.org/packages/54/89/d641a746194a0f4d1a3670fb900d0dbaa786fb98341056814bc3f058fa52/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a60ea74330b91bd22a29638940d115df9dc00af5035a9a2a6ad9399ffb4ceca5", size = 2230150, upload-time = "2025-08-10T21:27:11.484Z" }, + { url = "https://files.pythonhosted.org/packages/aa/6b/5ee1207198febdf16ac11f78c5ae40861b809cbe0e6d2a8d5b0b3044b199/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ce6a3a4e106cf35c2d9c4fa17c05ce0b180db622736845d4315519397a77beaf", size = 2325979, upload-time = "2025-08-10T21:27:12.917Z" }, + { url = "https://files.pythonhosted.org/packages/fc/ff/b269eefd90f4ae14dcc74973d5a0f6d28d3b9bb1afd8c0340513afe6b39a/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:77937e5e2a38a7b48eef0585114fe7930346993a88060d0bf886086d2aa49ef5", size = 2491456, upload-time = "2025-08-10T21:27:14.353Z" }, + { url = "https://files.pythonhosted.org/packages/fc/d4/10303190bd4d30de547534601e259a4fbf014eed94aae3e5521129215086/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:24c175051354f4a28c5d6a31c93906dc653e2bf234e8a4bbfb964892078898ce", size = 2294621, upload-time = "2025-08-10T21:27:15.808Z" }, + { url = "https://files.pythonhosted.org/packages/28/e0/a9a90416fce5c0be25742729c2ea52105d62eda6c4be4d803c2a7be1fa50/kiwisolver-1.4.9-cp314-cp314-win_amd64.whl", hash = "sha256:0763515d4df10edf6d06a3c19734e2566368980d21ebec439f33f9eb936c07b7", size = 75417, upload-time = "2025-08-10T21:27:17.436Z" }, + { url = "https://files.pythonhosted.org/packages/1f/10/6949958215b7a9a264299a7db195564e87900f709db9245e4ebdd3c70779/kiwisolver-1.4.9-cp314-cp314-win_arm64.whl", hash = "sha256:0e4e2bf29574a6a7b7f6cb5fa69293b9f96c928949ac4a53ba3f525dffb87f9c", size = 66582, upload-time = "2025-08-10T21:27:18.436Z" }, + { url = "https://files.pythonhosted.org/packages/ec/79/60e53067903d3bc5469b369fe0dfc6b3482e2133e85dae9daa9527535991/kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d976bbb382b202f71c67f77b0ac11244021cfa3f7dfd9e562eefcea2df711548", size = 126514, upload-time = "2025-08-10T21:27:19.465Z" }, + { url = "https://files.pythonhosted.org/packages/25/d1/4843d3e8d46b072c12a38c97c57fab4608d36e13fe47d47ee96b4d61ba6f/kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2489e4e5d7ef9a1c300a5e0196e43d9c739f066ef23270607d45aba368b91f2d", size = 67905, upload-time = "2025-08-10T21:27:20.51Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ae/29ffcbd239aea8b93108de1278271ae764dfc0d803a5693914975f200596/kiwisolver-1.4.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e2ea9f7ab7fbf18fffb1b5434ce7c69a07582f7acc7717720f1d69f3e806f90c", size = 66399, upload-time = "2025-08-10T21:27:21.496Z" }, + { url = "https://files.pythonhosted.org/packages/a1/ae/d7ba902aa604152c2ceba5d352d7b62106bedbccc8e95c3934d94472bfa3/kiwisolver-1.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b34e51affded8faee0dfdb705416153819d8ea9250bbbf7ea1b249bdeb5f1122", size = 1582197, upload-time = "2025-08-10T21:27:22.604Z" }, + { url = "https://files.pythonhosted.org/packages/f2/41/27c70d427eddb8bc7e4f16420a20fefc6f480312122a59a959fdfe0445ad/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8aacd3d4b33b772542b2e01beb50187536967b514b00003bdda7589722d2a64", size = 1390125, upload-time = "2025-08-10T21:27:24.036Z" }, + { url = "https://files.pythonhosted.org/packages/41/42/b3799a12bafc76d962ad69083f8b43b12bf4fe78b097b12e105d75c9b8f1/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7cf974dd4e35fa315563ac99d6287a1024e4dc2077b8a7d7cd3d2fb65d283134", size = 1402612, upload-time = "2025-08-10T21:27:25.773Z" }, + { url = "https://files.pythonhosted.org/packages/d2/b5/a210ea073ea1cfaca1bb5c55a62307d8252f531beb364e18aa1e0888b5a0/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:85bd218b5ecfbee8c8a82e121802dcb519a86044c9c3b2e4aef02fa05c6da370", size = 1453990, upload-time = "2025-08-10T21:27:27.089Z" }, + { url = "https://files.pythonhosted.org/packages/5f/ce/a829eb8c033e977d7ea03ed32fb3c1781b4fa0433fbadfff29e39c676f32/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0856e241c2d3df4efef7c04a1e46b1936b6120c9bcf36dd216e3acd84bc4fb21", size = 2331601, upload-time = "2025-08-10T21:27:29.343Z" }, + { url = "https://files.pythonhosted.org/packages/e0/4b/b5e97eb142eb9cd0072dacfcdcd31b1c66dc7352b0f7c7255d339c0edf00/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9af39d6551f97d31a4deebeac6f45b156f9755ddc59c07b402c148f5dbb6482a", size = 2422041, upload-time = "2025-08-10T21:27:30.754Z" }, + { url = "https://files.pythonhosted.org/packages/40/be/8eb4cd53e1b85ba4edc3a9321666f12b83113a178845593307a3e7891f44/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:bb4ae2b57fc1d8cbd1cf7b1d9913803681ffa903e7488012be5b76dedf49297f", size = 2594897, upload-time = "2025-08-10T21:27:32.803Z" }, + { url = "https://files.pythonhosted.org/packages/99/dd/841e9a66c4715477ea0abc78da039832fbb09dac5c35c58dc4c41a407b8a/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:aedff62918805fb62d43a4aa2ecd4482c380dc76cd31bd7c8878588a61bd0369", size = 2391835, upload-time = "2025-08-10T21:27:34.23Z" }, + { url = "https://files.pythonhosted.org/packages/0c/28/4b2e5c47a0da96896fdfdb006340ade064afa1e63675d01ea5ac222b6d52/kiwisolver-1.4.9-cp314-cp314t-win_amd64.whl", hash = "sha256:1fa333e8b2ce4d9660f2cda9c0e1b6bafcfb2457a9d259faa82289e73ec24891", size = 79988, upload-time = "2025-08-10T21:27:35.587Z" }, + { url = "https://files.pythonhosted.org/packages/80/be/3578e8afd18c88cdf9cb4cffde75a96d2be38c5a903f1ed0ceec061bd09e/kiwisolver-1.4.9-cp314-cp314t-win_arm64.whl", hash = "sha256:4a48a2ce79d65d363597ef7b567ce3d14d68783d2b2263d98db3d9477805ba32", size = 70260, upload-time = "2025-08-10T21:27:36.606Z" }, ] [[package]] @@ -489,59 +621,136 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b5/40/23569737873cc9637fd488606347e9dd92b9fa37ba4fcda1f98ee5219a97/latexcodec-3.0.1-py3-none-any.whl", hash = "sha256:a9eb8200bff693f0437a69581f7579eb6bca25c4193515c09900ce76451e452e", size = 18532, upload-time = "2025-06-17T18:47:30.726Z" }, ] +[[package]] +name = "librt" +version = "0.7.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/24/5f3646ff414285e0f7708fa4e946b9bf538345a41d1c375c439467721a5e/librt-0.7.8.tar.gz", hash = "sha256:1a4ede613941d9c3470b0368be851df6bb78ab218635512d0370b27a277a0862", size = 148323, upload-time = "2026-01-14T12:56:16.876Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/04/79d8fcb43cae376c7adbab7b2b9f65e48432c9eced62ac96703bcc16e09b/librt-0.7.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9b6943885b2d49c48d0cff23b16be830ba46b0152d98f62de49e735c6e655a63", size = 57472, upload-time = "2026-01-14T12:55:08.528Z" }, + { url = "https://files.pythonhosted.org/packages/b4/ba/60b96e93043d3d659da91752689023a73981336446ae82078cddf706249e/librt-0.7.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:46ef1f4b9b6cc364b11eea0ecc0897314447a66029ee1e55859acb3dd8757c93", size = 58986, upload-time = "2026-01-14T12:55:09.466Z" }, + { url = "https://files.pythonhosted.org/packages/7c/26/5215e4cdcc26e7be7eee21955a7e13cbf1f6d7d7311461a6014544596fac/librt-0.7.8-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:907ad09cfab21e3c86e8f1f87858f7049d1097f77196959c033612f532b4e592", size = 168422, upload-time = "2026-01-14T12:55:10.499Z" }, + { url = "https://files.pythonhosted.org/packages/0f/84/e8d1bc86fa0159bfc24f3d798d92cafd3897e84c7fea7fe61b3220915d76/librt-0.7.8-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2991b6c3775383752b3ca0204842743256f3ad3deeb1d0adc227d56b78a9a850", size = 177478, upload-time = "2026-01-14T12:55:11.577Z" }, + { url = "https://files.pythonhosted.org/packages/57/11/d0268c4b94717a18aa91df1100e767b010f87b7ae444dafaa5a2d80f33a6/librt-0.7.8-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03679b9856932b8c8f674e87aa3c55ea11c9274301f76ae8dc4d281bda55cf62", size = 192439, upload-time = "2026-01-14T12:55:12.7Z" }, + { url = "https://files.pythonhosted.org/packages/8d/56/1e8e833b95fe684f80f8894ae4d8b7d36acc9203e60478fcae599120a975/librt-0.7.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3968762fec1b2ad34ce57458b6de25dbb4142713e9ca6279a0d352fa4e9f452b", size = 191483, upload-time = "2026-01-14T12:55:13.838Z" }, + { url = "https://files.pythonhosted.org/packages/17/48/f11cf28a2cb6c31f282009e2208312aa84a5ee2732859f7856ee306176d5/librt-0.7.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:bb7a7807523a31f03061288cc4ffc065d684c39db7644c676b47d89553c0d714", size = 185376, upload-time = "2026-01-14T12:55:15.017Z" }, + { url = "https://files.pythonhosted.org/packages/b8/6a/d7c116c6da561b9155b184354a60a3d5cdbf08fc7f3678d09c95679d13d9/librt-0.7.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad64a14b1e56e702e19b24aae108f18ad1bf7777f3af5fcd39f87d0c5a814449", size = 206234, upload-time = "2026-01-14T12:55:16.571Z" }, + { url = "https://files.pythonhosted.org/packages/61/de/1975200bb0285fc921c5981d9978ce6ce11ae6d797df815add94a5a848a3/librt-0.7.8-cp312-cp312-win32.whl", hash = "sha256:0241a6ed65e6666236ea78203a73d800dbed896cf12ae25d026d75dc1fcd1dac", size = 44057, upload-time = "2026-01-14T12:55:18.077Z" }, + { url = "https://files.pythonhosted.org/packages/8e/cd/724f2d0b3461426730d4877754b65d39f06a41ac9d0a92d5c6840f72b9ae/librt-0.7.8-cp312-cp312-win_amd64.whl", hash = "sha256:6db5faf064b5bab9675c32a873436b31e01d66ca6984c6f7f92621656033a708", size = 50293, upload-time = "2026-01-14T12:55:19.179Z" }, + { url = "https://files.pythonhosted.org/packages/bd/cf/7e899acd9ee5727ad8160fdcc9994954e79fab371c66535c60e13b968ffc/librt-0.7.8-cp312-cp312-win_arm64.whl", hash = "sha256:57175aa93f804d2c08d2edb7213e09276bd49097611aefc37e3fa38d1fb99ad0", size = 43574, upload-time = "2026-01-14T12:55:20.185Z" }, + { url = "https://files.pythonhosted.org/packages/a1/fe/b1f9de2829cf7fc7649c1dcd202cfd873837c5cc2fc9e526b0e7f716c3d2/librt-0.7.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4c3995abbbb60b3c129490fa985dfe6cac11d88fc3c36eeb4fb1449efbbb04fc", size = 57500, upload-time = "2026-01-14T12:55:21.219Z" }, + { url = "https://files.pythonhosted.org/packages/eb/d4/4a60fbe2e53b825f5d9a77325071d61cd8af8506255067bf0c8527530745/librt-0.7.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:44e0c2cbc9bebd074cf2cdbe472ca185e824be4e74b1c63a8e934cea674bebf2", size = 59019, upload-time = "2026-01-14T12:55:22.256Z" }, + { url = "https://files.pythonhosted.org/packages/6a/37/61ff80341ba5159afa524445f2d984c30e2821f31f7c73cf166dcafa5564/librt-0.7.8-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4d2f1e492cae964b3463a03dc77a7fe8742f7855d7258c7643f0ee32b6651dd3", size = 169015, upload-time = "2026-01-14T12:55:23.24Z" }, + { url = "https://files.pythonhosted.org/packages/1c/86/13d4f2d6a93f181ebf2fc953868826653ede494559da8268023fe567fca3/librt-0.7.8-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:451e7ffcef8f785831fdb791bd69211f47e95dc4c6ddff68e589058806f044c6", size = 178161, upload-time = "2026-01-14T12:55:24.826Z" }, + { url = "https://files.pythonhosted.org/packages/88/26/e24ef01305954fc4d771f1f09f3dd682f9eb610e1bec188ffb719374d26e/librt-0.7.8-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3469e1af9f1380e093ae06bedcbdd11e407ac0b303a56bbe9afb1d6824d4982d", size = 193015, upload-time = "2026-01-14T12:55:26.04Z" }, + { url = "https://files.pythonhosted.org/packages/88/a0/92b6bd060e720d7a31ed474d046a69bd55334ec05e9c446d228c4b806ae3/librt-0.7.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f11b300027ce19a34f6d24ebb0a25fd0e24a9d53353225a5c1e6cadbf2916b2e", size = 192038, upload-time = "2026-01-14T12:55:27.208Z" }, + { url = "https://files.pythonhosted.org/packages/06/bb/6f4c650253704279c3a214dad188101d1b5ea23be0606628bc6739456624/librt-0.7.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4adc73614f0d3c97874f02f2c7fd2a27854e7e24ad532ea6b965459c5b757eca", size = 186006, upload-time = "2026-01-14T12:55:28.594Z" }, + { url = "https://files.pythonhosted.org/packages/dc/00/1c409618248d43240cadf45f3efb866837fa77e9a12a71481912135eb481/librt-0.7.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:60c299e555f87e4c01b2eca085dfccda1dde87f5a604bb45c2906b8305819a93", size = 206888, upload-time = "2026-01-14T12:55:30.214Z" }, + { url = "https://files.pythonhosted.org/packages/d9/83/b2cfe8e76ff5c1c77f8a53da3d5de62d04b5ebf7cf913e37f8bca43b5d07/librt-0.7.8-cp313-cp313-win32.whl", hash = "sha256:b09c52ed43a461994716082ee7d87618096851319bf695d57ec123f2ab708951", size = 44126, upload-time = "2026-01-14T12:55:31.44Z" }, + { url = "https://files.pythonhosted.org/packages/a9/0b/c59d45de56a51bd2d3a401fc63449c0ac163e4ef7f523ea8b0c0dee86ec5/librt-0.7.8-cp313-cp313-win_amd64.whl", hash = "sha256:f8f4a901a3fa28969d6e4519deceab56c55a09d691ea7b12ca830e2fa3461e34", size = 50262, upload-time = "2026-01-14T12:55:33.01Z" }, + { url = "https://files.pythonhosted.org/packages/fc/b9/973455cec0a1ec592395250c474164c4a58ebf3e0651ee920fef1a2623f1/librt-0.7.8-cp313-cp313-win_arm64.whl", hash = "sha256:43d4e71b50763fcdcf64725ac680d8cfa1706c928b844794a7aa0fa9ac8e5f09", size = 43600, upload-time = "2026-01-14T12:55:34.054Z" }, + { url = "https://files.pythonhosted.org/packages/1a/73/fa8814c6ce2d49c3827829cadaa1589b0bf4391660bd4510899393a23ebc/librt-0.7.8-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:be927c3c94c74b05128089a955fba86501c3b544d1d300282cc1b4bd370cb418", size = 57049, upload-time = "2026-01-14T12:55:35.056Z" }, + { url = "https://files.pythonhosted.org/packages/53/fe/f6c70956da23ea235fd2e3cc16f4f0b4ebdfd72252b02d1164dd58b4e6c3/librt-0.7.8-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7b0803e9008c62a7ef79058233db7ff6f37a9933b8f2573c05b07ddafa226611", size = 58689, upload-time = "2026-01-14T12:55:36.078Z" }, + { url = "https://files.pythonhosted.org/packages/1f/4d/7a2481444ac5fba63050d9abe823e6bc16896f575bfc9c1e5068d516cdce/librt-0.7.8-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:79feb4d00b2a4e0e05c9c56df707934f41fcb5fe53fd9efb7549068d0495b758", size = 166808, upload-time = "2026-01-14T12:55:37.595Z" }, + { url = "https://files.pythonhosted.org/packages/ac/3c/10901d9e18639f8953f57c8986796cfbf4c1c514844a41c9197cf87cb707/librt-0.7.8-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b9122094e3f24aa759c38f46bd8863433820654927370250f460ae75488b66ea", size = 175614, upload-time = "2026-01-14T12:55:38.756Z" }, + { url = "https://files.pythonhosted.org/packages/db/01/5cbdde0951a5090a80e5ba44e6357d375048123c572a23eecfb9326993a7/librt-0.7.8-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7e03bea66af33c95ce3addf87a9bf1fcad8d33e757bc479957ddbc0e4f7207ac", size = 189955, upload-time = "2026-01-14T12:55:39.939Z" }, + { url = "https://files.pythonhosted.org/packages/6a/b4/e80528d2f4b7eaf1d437fcbd6fc6ba4cbeb3e2a0cb9ed5a79f47c7318706/librt-0.7.8-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f1ade7f31675db00b514b98f9ab9a7698c7282dad4be7492589109471852d398", size = 189370, upload-time = "2026-01-14T12:55:41.057Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ab/938368f8ce31a9787ecd4becb1e795954782e4312095daf8fd22420227c8/librt-0.7.8-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a14229ac62adcf1b90a15992f1ab9c69ae8b99ffb23cb64a90878a6e8a2f5b81", size = 183224, upload-time = "2026-01-14T12:55:42.328Z" }, + { url = "https://files.pythonhosted.org/packages/3c/10/559c310e7a6e4014ac44867d359ef8238465fb499e7eb31b6bfe3e3f86f5/librt-0.7.8-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5bcaaf624fd24e6a0cb14beac37677f90793a96864c67c064a91458611446e83", size = 203541, upload-time = "2026-01-14T12:55:43.501Z" }, + { url = "https://files.pythonhosted.org/packages/f8/db/a0db7acdb6290c215f343835c6efda5b491bb05c3ddc675af558f50fdba3/librt-0.7.8-cp314-cp314-win32.whl", hash = "sha256:7aa7d5457b6c542ecaed79cec4ad98534373c9757383973e638ccced0f11f46d", size = 40657, upload-time = "2026-01-14T12:55:44.668Z" }, + { url = "https://files.pythonhosted.org/packages/72/e0/4f9bdc2a98a798511e81edcd6b54fe82767a715e05d1921115ac70717f6f/librt-0.7.8-cp314-cp314-win_amd64.whl", hash = "sha256:3d1322800771bee4a91f3b4bd4e49abc7d35e65166821086e5afd1e6c0d9be44", size = 46835, upload-time = "2026-01-14T12:55:45.655Z" }, + { url = "https://files.pythonhosted.org/packages/f9/3d/59c6402e3dec2719655a41ad027a7371f8e2334aa794ed11533ad5f34969/librt-0.7.8-cp314-cp314-win_arm64.whl", hash = "sha256:5363427bc6a8c3b1719f8f3845ea53553d301382928a86e8fab7984426949bce", size = 39885, upload-time = "2026-01-14T12:55:47.138Z" }, + { url = "https://files.pythonhosted.org/packages/4e/9c/2481d80950b83085fb14ba3c595db56330d21bbc7d88a19f20165f3538db/librt-0.7.8-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:ca916919793a77e4a98d4a1701e345d337ce53be4a16620f063191f7322ac80f", size = 59161, upload-time = "2026-01-14T12:55:48.45Z" }, + { url = "https://files.pythonhosted.org/packages/96/79/108df2cfc4e672336765d54e3ff887294c1cc36ea4335c73588875775527/librt-0.7.8-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:54feb7b4f2f6706bb82325e836a01be805770443e2400f706e824e91f6441dde", size = 61008, upload-time = "2026-01-14T12:55:49.527Z" }, + { url = "https://files.pythonhosted.org/packages/46/f2/30179898f9994a5637459d6e169b6abdc982012c0a4b2d4c26f50c06f911/librt-0.7.8-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:39a4c76fee41007070f872b648cc2f711f9abf9a13d0c7162478043377b52c8e", size = 187199, upload-time = "2026-01-14T12:55:50.587Z" }, + { url = "https://files.pythonhosted.org/packages/b4/da/f7563db55cebdc884f518ba3791ad033becc25ff68eb70902b1747dc0d70/librt-0.7.8-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac9c8a458245c7de80bc1b9765b177055efff5803f08e548dd4bb9ab9a8d789b", size = 198317, upload-time = "2026-01-14T12:55:51.991Z" }, + { url = "https://files.pythonhosted.org/packages/b3/6c/4289acf076ad371471fa86718c30ae353e690d3de6167f7db36f429272f1/librt-0.7.8-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:95b67aa7eff150f075fda09d11f6bfb26edffd300f6ab1666759547581e8f666", size = 210334, upload-time = "2026-01-14T12:55:53.682Z" }, + { url = "https://files.pythonhosted.org/packages/4a/7f/377521ac25b78ac0a5ff44127a0360ee6d5ddd3ce7327949876a30533daa/librt-0.7.8-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:535929b6eff670c593c34ff435d5440c3096f20fa72d63444608a5aef64dd581", size = 211031, upload-time = "2026-01-14T12:55:54.827Z" }, + { url = "https://files.pythonhosted.org/packages/c5/b1/e1e96c3e20b23d00cf90f4aad48f0deb4cdfec2f0ed8380d0d85acf98bbf/librt-0.7.8-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:63937bd0f4d1cb56653dc7ae900d6c52c41f0015e25aaf9902481ee79943b33a", size = 204581, upload-time = "2026-01-14T12:55:56.811Z" }, + { url = "https://files.pythonhosted.org/packages/43/71/0f5d010e92ed9747e14bef35e91b6580533510f1e36a8a09eb79ee70b2f0/librt-0.7.8-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cf243da9e42d914036fd362ac3fa77d80a41cadcd11ad789b1b5eec4daaf67ca", size = 224731, upload-time = "2026-01-14T12:55:58.175Z" }, + { url = "https://files.pythonhosted.org/packages/22/f0/07fb6ab5c39a4ca9af3e37554f9d42f25c464829254d72e4ebbd81da351c/librt-0.7.8-cp314-cp314t-win32.whl", hash = "sha256:171ca3a0a06c643bd0a2f62a8944e1902c94aa8e5da4db1ea9a8daf872685365", size = 41173, upload-time = "2026-01-14T12:55:59.315Z" }, + { url = "https://files.pythonhosted.org/packages/24/d4/7e4be20993dc6a782639625bd2f97f3c66125c7aa80c82426956811cfccf/librt-0.7.8-cp314-cp314t-win_amd64.whl", hash = "sha256:445b7304145e24c60288a2f172b5ce2ca35c0f81605f5299f3fa567e189d2e32", size = 47668, upload-time = "2026-01-14T12:56:00.261Z" }, + { url = "https://files.pythonhosted.org/packages/fc/85/69f92b2a7b3c0f88ffe107c86b952b397004b5b8ea5a81da3d9c04c04422/librt-0.7.8-cp314-cp314t-win_arm64.whl", hash = "sha256:8766ece9de08527deabcd7cb1b4f1a967a385d26e33e536d6d8913db6ef74f06", size = 40550, upload-time = "2026-01-14T12:56:01.542Z" }, +] + [[package]] name = "markdown-it-py" -version = "3.0.0" +version = "4.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mdurl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, ] [[package]] name = "markupsafe" -version = "3.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, - { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, - { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, - { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, - { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, - { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, - { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, - { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, - { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, - { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, - { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, - { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, - { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, - { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, - { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, - { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, - { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, - { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, - { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, - { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, - { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, - { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, - { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, - { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, - { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, - { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, - { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, - { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, - { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, ] [[package]] name = "matplotlib" -version = "3.9.2" +version = "3.10.8" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "contourpy" }, @@ -554,25 +763,43 @@ dependencies = [ { name = "pyparsing" }, { name = "python-dateutil" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9e/d8/3d7f706c69e024d4287c1110d74f7dabac91d9843b99eadc90de9efc8869/matplotlib-3.9.2.tar.gz", hash = "sha256:96ab43906269ca64a6366934106fa01534454a69e471b7bf3d79083981aaab92", size = 36088381, upload-time = "2024-08-13T01:45:36.875Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/82/de/54f7f38ce6de79cb77d513bb3eaa4e0b1031e9fd6022214f47943fa53a88/matplotlib-3.9.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ac43031375a65c3196bee99f6001e7fa5bdfb00ddf43379d3c0609bdca042df9", size = 7892511, upload-time = "2024-08-13T01:44:46.59Z" }, - { url = "https://files.pythonhosted.org/packages/35/3e/5713b84a02b24b2a4bd4d6673bfc03017e6654e1d8793ece783b7ed4d484/matplotlib-3.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:be0fc24a5e4531ae4d8e858a1a548c1fe33b176bb13eff7f9d0d38ce5112a27d", size = 7769370, upload-time = "2024-08-13T01:44:48.084Z" }, - { url = "https://files.pythonhosted.org/packages/5b/bd/c404502aa1824456d2862dd6b9b0c1917761a51a32f7f83ff8cf94b6d117/matplotlib-3.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf81de2926c2db243c9b2cbc3917619a0fc85796c6ba4e58f541df814bbf83c7", size = 8193260, upload-time = "2024-08-13T01:44:49.663Z" }, - { url = "https://files.pythonhosted.org/packages/27/75/de5b9cd67648051cae40039da0c8cbc497a0d99acb1a1f3d087cd66d27b7/matplotlib-3.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6ee45bc4245533111ced13f1f2cace1e7f89d1c793390392a80c139d6cf0e6c", size = 8306310, upload-time = "2024-08-13T01:44:51.329Z" }, - { url = "https://files.pythonhosted.org/packages/de/e3/2976e4e54d7ee76eaf54b7639fdc10a223d05c2bdded7045233e9871e469/matplotlib-3.9.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:306c8dfc73239f0e72ac50e5a9cf19cc4e8e331dd0c54f5e69ca8758550f1e1e", size = 9086717, upload-time = "2024-08-13T01:44:53.772Z" }, - { url = "https://files.pythonhosted.org/packages/d2/92/c2b9464a0562feb6ae780bdc152364810862e07ef5e6affa2b7686028db2/matplotlib-3.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:5413401594cfaff0052f9d8b1aafc6d305b4bd7c4331dccd18f561ff7e1d3bd3", size = 7832805, upload-time = "2024-08-13T01:44:55.947Z" }, - { url = "https://files.pythonhosted.org/packages/5c/7f/8932eac316b32f464b8f9069f151294dcd892c8fbde61fe8bcd7ba7f7f7e/matplotlib-3.9.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:18128cc08f0d3cfff10b76baa2f296fc28c4607368a8402de61bb3f2eb33c7d9", size = 7893012, upload-time = "2024-08-13T01:44:57.63Z" }, - { url = "https://files.pythonhosted.org/packages/90/89/9db9db3dd0ff3e2c49e452236dfe29e60b5586a88f8928ca1d153d0da8b5/matplotlib-3.9.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4876d7d40219e8ae8bb70f9263bcbe5714415acfdf781086601211335e24f8aa", size = 7769810, upload-time = "2024-08-13T01:44:59.652Z" }, - { url = "https://files.pythonhosted.org/packages/67/26/d2661cdc2e1410b8929c5f12dfd521e4528abfed1b3c3d5a28ac48258b43/matplotlib-3.9.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d9f07a80deab4bb0b82858a9e9ad53d1382fd122be8cde11080f4e7dfedb38b", size = 8193779, upload-time = "2024-08-13T01:45:01.453Z" }, - { url = "https://files.pythonhosted.org/packages/95/70/4839eaa672bf4eacc98ebc8d23633e02b6daf39e294e7433c4ab11a689be/matplotlib-3.9.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7c0410f181a531ec4e93bbc27692f2c71a15c2da16766f5ba9761e7ae518413", size = 8306260, upload-time = "2024-08-13T01:45:03.107Z" }, - { url = "https://files.pythonhosted.org/packages/88/62/7b263b2cb2724b45d3a4f9c8c6137696cc3ef037d44383fb01ac2a9555c2/matplotlib-3.9.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:909645cce2dc28b735674ce0931a4ac94e12f5b13f6bb0b5a5e65e7cea2c192b", size = 9086073, upload-time = "2024-08-13T01:45:04.757Z" }, - { url = "https://files.pythonhosted.org/packages/b0/6d/3572fe243c74112fef120f0bc86f5edd21f49b60e8322fc7f6a01fe945dd/matplotlib-3.9.2-cp313-cp313-win_amd64.whl", hash = "sha256:f32c7410c7f246838a77d6d1eff0c0f87f3cb0e7c4247aebea71a6d5a68cab49", size = 7833041, upload-time = "2024-08-13T01:45:07.406Z" }, - { url = "https://files.pythonhosted.org/packages/03/8f/9d505be3eb2f40ec731674fb6b47d10cc3147bbd6a9ea7a08c8da55415c6/matplotlib-3.9.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:37e51dd1c2db16ede9cfd7b5cabdfc818b2c6397c83f8b10e0e797501c963a03", size = 7933657, upload-time = "2024-08-13T01:45:08.967Z" }, - { url = "https://files.pythonhosted.org/packages/5d/68/44b458b9794bcff2a66921f8c9a8110a50a0bb099bd5f7cabb428a1dc765/matplotlib-3.9.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b82c5045cebcecd8496a4d694d43f9cc84aeeb49fe2133e036b207abe73f4d30", size = 7799276, upload-time = "2024-08-13T01:45:10.607Z" }, - { url = "https://files.pythonhosted.org/packages/47/79/8486d4ddcaaf676314b5fb58e8fe19d1a6210a443a7c31fa72d4215fcb87/matplotlib-3.9.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f053c40f94bc51bc03832a41b4f153d83f2062d88c72b5e79997072594e97e51", size = 8221027, upload-time = "2024-08-13T01:45:12.204Z" }, - { url = "https://files.pythonhosted.org/packages/56/62/72a472181578c3d035dcda0d0fa2e259ba2c4cb91132588a348bb705b70d/matplotlib-3.9.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbe196377a8248972f5cede786d4c5508ed5f5ca4a1e09b44bda889958b33f8c", size = 8329097, upload-time = "2024-08-13T01:45:13.877Z" }, - { url = "https://files.pythonhosted.org/packages/01/8a/760f7fce66b39f447ad160800619d0bd5d0936d2b4633587116534a4afe0/matplotlib-3.9.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5816b1e1fe8c192cbc013f8f3e3368ac56fbecf02fb41b8f8559303f24c5015e", size = 9093770, upload-time = "2024-08-13T01:45:15.562Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/8a/76/d3c6e3a13fe484ebe7718d14e269c9569c4eb0020a968a327acb3b9a8fe6/matplotlib-3.10.8.tar.gz", hash = "sha256:2299372c19d56bcd35cf05a2738308758d32b9eaed2371898d8f5bd33f084aa3", size = 34806269, upload-time = "2025-12-10T22:56:51.155Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/67/f997cdcbb514012eb0d10cd2b4b332667997fb5ebe26b8d41d04962fa0e6/matplotlib-3.10.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:64fcc24778ca0404ce0cb7b6b77ae1f4c7231cdd60e6778f999ee05cbd581b9a", size = 8260453, upload-time = "2025-12-10T22:55:30.709Z" }, + { url = "https://files.pythonhosted.org/packages/7e/65/07d5f5c7f7c994f12c768708bd2e17a4f01a2b0f44a1c9eccad872433e2e/matplotlib-3.10.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b9a5ca4ac220a0cdd1ba6bcba3608547117d30468fefce49bb26f55c1a3d5c58", size = 8148321, upload-time = "2025-12-10T22:55:33.265Z" }, + { url = "https://files.pythonhosted.org/packages/3e/f3/c5195b1ae57ef85339fd7285dfb603b22c8b4e79114bae5f4f0fcf688677/matplotlib-3.10.8-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3ab4aabc72de4ff77b3ec33a6d78a68227bf1123465887f9905ba79184a1cc04", size = 8716944, upload-time = "2025-12-10T22:55:34.922Z" }, + { url = "https://files.pythonhosted.org/packages/00/f9/7638f5cc82ec8a7aa005de48622eecc3ed7c9854b96ba15bd76b7fd27574/matplotlib-3.10.8-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:24d50994d8c5816ddc35411e50a86ab05f575e2530c02752e02538122613371f", size = 9550099, upload-time = "2025-12-10T22:55:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/57/61/78cd5920d35b29fd2a0fe894de8adf672ff52939d2e9b43cb83cd5ce1bc7/matplotlib-3.10.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:99eefd13c0dc3b3c1b4d561c1169e65fe47aab7b8158754d7c084088e2329466", size = 9613040, upload-time = "2025-12-10T22:55:38.715Z" }, + { url = "https://files.pythonhosted.org/packages/30/4e/c10f171b6e2f44d9e3a2b96efa38b1677439d79c99357600a62cc1e9594e/matplotlib-3.10.8-cp312-cp312-win_amd64.whl", hash = "sha256:dd80ecb295460a5d9d260df63c43f4afbdd832d725a531f008dad1664f458adf", size = 8142717, upload-time = "2025-12-10T22:55:41.103Z" }, + { url = "https://files.pythonhosted.org/packages/f1/76/934db220026b5fef85f45d51a738b91dea7d70207581063cd9bd8fafcf74/matplotlib-3.10.8-cp312-cp312-win_arm64.whl", hash = "sha256:3c624e43ed56313651bc18a47f838b60d7b8032ed348911c54906b130b20071b", size = 8012751, upload-time = "2025-12-10T22:55:42.684Z" }, + { url = "https://files.pythonhosted.org/packages/3d/b9/15fd5541ef4f5b9a17eefd379356cf12175fe577424e7b1d80676516031a/matplotlib-3.10.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3f2e409836d7f5ac2f1c013110a4d50b9f7edc26328c108915f9075d7d7a91b6", size = 8261076, upload-time = "2025-12-10T22:55:44.648Z" }, + { url = "https://files.pythonhosted.org/packages/8d/a0/2ba3473c1b66b9c74dc7107c67e9008cb1782edbe896d4c899d39ae9cf78/matplotlib-3.10.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56271f3dac49a88d7fca5060f004d9d22b865f743a12a23b1e937a0be4818ee1", size = 8148794, upload-time = "2025-12-10T22:55:46.252Z" }, + { url = "https://files.pythonhosted.org/packages/75/97/a471f1c3eb1fd6f6c24a31a5858f443891d5127e63a7788678d14e249aea/matplotlib-3.10.8-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a0a7f52498f72f13d4a25ea70f35f4cb60642b466cbb0a9be951b5bc3f45a486", size = 8718474, upload-time = "2025-12-10T22:55:47.864Z" }, + { url = "https://files.pythonhosted.org/packages/01/be/cd478f4b66f48256f42927d0acbcd63a26a893136456cd079c0cc24fbabf/matplotlib-3.10.8-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:646d95230efb9ca614a7a594d4fcacde0ac61d25e37dd51710b36477594963ce", size = 9549637, upload-time = "2025-12-10T22:55:50.048Z" }, + { url = "https://files.pythonhosted.org/packages/5d/7c/8dc289776eae5109e268c4fb92baf870678dc048a25d4ac903683b86d5bf/matplotlib-3.10.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f89c151aab2e2e23cb3fe0acad1e8b82841fd265379c4cecd0f3fcb34c15e0f6", size = 9613678, upload-time = "2025-12-10T22:55:52.21Z" }, + { url = "https://files.pythonhosted.org/packages/64/40/37612487cc8a437d4dd261b32ca21fe2d79510fe74af74e1f42becb1bdb8/matplotlib-3.10.8-cp313-cp313-win_amd64.whl", hash = "sha256:e8ea3e2d4066083e264e75c829078f9e149fa119d27e19acd503de65e0b13149", size = 8142686, upload-time = "2025-12-10T22:55:54.253Z" }, + { url = "https://files.pythonhosted.org/packages/66/52/8d8a8730e968185514680c2a6625943f70269509c3dcfc0dcf7d75928cb8/matplotlib-3.10.8-cp313-cp313-win_arm64.whl", hash = "sha256:c108a1d6fa78a50646029cb6d49808ff0fc1330fda87fa6f6250c6b5369b6645", size = 8012917, upload-time = "2025-12-10T22:55:56.268Z" }, + { url = "https://files.pythonhosted.org/packages/b5/27/51fe26e1062f298af5ef66343d8ef460e090a27fea73036c76c35821df04/matplotlib-3.10.8-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ad3d9833a64cf48cc4300f2b406c3d0f4f4724a91c0bd5640678a6ba7c102077", size = 8305679, upload-time = "2025-12-10T22:55:57.856Z" }, + { url = "https://files.pythonhosted.org/packages/2c/1e/4de865bc591ac8e3062e835f42dd7fe7a93168d519557837f0e37513f629/matplotlib-3.10.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:eb3823f11823deade26ce3b9f40dcb4a213da7a670013929f31d5f5ed1055b22", size = 8198336, upload-time = "2025-12-10T22:55:59.371Z" }, + { url = "https://files.pythonhosted.org/packages/c6/cb/2f7b6e75fb4dce87ef91f60cac4f6e34f4c145ab036a22318ec837971300/matplotlib-3.10.8-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d9050fee89a89ed57b4fb2c1bfac9a3d0c57a0d55aed95949eedbc42070fea39", size = 8731653, upload-time = "2025-12-10T22:56:01.032Z" }, + { url = "https://files.pythonhosted.org/packages/46/b3/bd9c57d6ba670a37ab31fb87ec3e8691b947134b201f881665b28cc039ff/matplotlib-3.10.8-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b44d07310e404ba95f8c25aa5536f154c0a8ec473303535949e52eb71d0a1565", size = 9561356, upload-time = "2025-12-10T22:56:02.95Z" }, + { url = "https://files.pythonhosted.org/packages/c0/3d/8b94a481456dfc9dfe6e39e93b5ab376e50998cddfd23f4ae3b431708f16/matplotlib-3.10.8-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0a33deb84c15ede243aead39f77e990469fff93ad1521163305095b77b72ce4a", size = 9614000, upload-time = "2025-12-10T22:56:05.411Z" }, + { url = "https://files.pythonhosted.org/packages/bd/cd/bc06149fe5585ba800b189a6a654a75f1f127e8aab02fd2be10df7fa500c/matplotlib-3.10.8-cp313-cp313t-win_amd64.whl", hash = "sha256:3a48a78d2786784cc2413e57397981fb45c79e968d99656706018d6e62e57958", size = 8220043, upload-time = "2025-12-10T22:56:07.551Z" }, + { url = "https://files.pythonhosted.org/packages/e3/de/b22cf255abec916562cc04eef457c13e58a1990048de0c0c3604d082355e/matplotlib-3.10.8-cp313-cp313t-win_arm64.whl", hash = "sha256:15d30132718972c2c074cd14638c7f4592bd98719e2308bccea40e0538bc0cb5", size = 8062075, upload-time = "2025-12-10T22:56:09.178Z" }, + { url = "https://files.pythonhosted.org/packages/3c/43/9c0ff7a2f11615e516c3b058e1e6e8f9614ddeca53faca06da267c48345d/matplotlib-3.10.8-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b53285e65d4fa4c86399979e956235deb900be5baa7fc1218ea67fbfaeaadd6f", size = 8262481, upload-time = "2025-12-10T22:56:10.885Z" }, + { url = "https://files.pythonhosted.org/packages/6f/ca/e8ae28649fcdf039fda5ef554b40a95f50592a3c47e6f7270c9561c12b07/matplotlib-3.10.8-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:32f8dce744be5569bebe789e46727946041199030db8aeb2954d26013a0eb26b", size = 8151473, upload-time = "2025-12-10T22:56:12.377Z" }, + { url = "https://files.pythonhosted.org/packages/f1/6f/009d129ae70b75e88cbe7e503a12a4c0670e08ed748a902c2568909e9eb5/matplotlib-3.10.8-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4cf267add95b1c88300d96ca837833d4112756045364f5c734a2276038dae27d", size = 9553896, upload-time = "2025-12-10T22:56:14.432Z" }, + { url = "https://files.pythonhosted.org/packages/f5/26/4221a741eb97967bc1fd5e4c52b9aa5a91b2f4ec05b59f6def4d820f9df9/matplotlib-3.10.8-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2cf5bd12cecf46908f286d7838b2abc6c91cda506c0445b8223a7c19a00df008", size = 9824193, upload-time = "2025-12-10T22:56:16.29Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f3/3abf75f38605772cf48a9daf5821cd4f563472f38b4b828c6fba6fa6d06e/matplotlib-3.10.8-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:41703cc95688f2516b480f7f339d8851a6035f18e100ee6a32bc0b8536a12a9c", size = 9615444, upload-time = "2025-12-10T22:56:18.155Z" }, + { url = "https://files.pythonhosted.org/packages/93/a5/de89ac80f10b8dc615807ee1133cd99ac74082581196d4d9590bea10690d/matplotlib-3.10.8-cp314-cp314-win_amd64.whl", hash = "sha256:83d282364ea9f3e52363da262ce32a09dfe241e4080dcedda3c0db059d3c1f11", size = 8272719, upload-time = "2025-12-10T22:56:20.366Z" }, + { url = "https://files.pythonhosted.org/packages/69/ce/b006495c19ccc0a137b48083168a37bd056392dee02f87dba0472f2797fe/matplotlib-3.10.8-cp314-cp314-win_arm64.whl", hash = "sha256:2c1998e92cd5999e295a731bcb2911c75f597d937341f3030cc24ef2733d78a8", size = 8144205, upload-time = "2025-12-10T22:56:22.239Z" }, + { url = "https://files.pythonhosted.org/packages/68/d9/b31116a3a855bd313c6fcdb7226926d59b041f26061c6c5b1be66a08c826/matplotlib-3.10.8-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:b5a2b97dbdc7d4f353ebf343744f1d1f1cca8aa8bfddb4262fcf4306c3761d50", size = 8305785, upload-time = "2025-12-10T22:56:24.218Z" }, + { url = "https://files.pythonhosted.org/packages/1e/90/6effe8103f0272685767ba5f094f453784057072f49b393e3ea178fe70a5/matplotlib-3.10.8-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3f5c3e4da343bba819f0234186b9004faba952cc420fbc522dc4e103c1985908", size = 8198361, upload-time = "2025-12-10T22:56:26.787Z" }, + { url = "https://files.pythonhosted.org/packages/d7/65/a73188711bea603615fc0baecca1061429ac16940e2385433cc778a9d8e7/matplotlib-3.10.8-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f62550b9a30afde8c1c3ae450e5eb547d579dd69b25c2fc7a1c67f934c1717a", size = 9561357, upload-time = "2025-12-10T22:56:28.953Z" }, + { url = "https://files.pythonhosted.org/packages/f4/3d/b5c5d5d5be8ce63292567f0e2c43dde9953d3ed86ac2de0a72e93c8f07a1/matplotlib-3.10.8-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:495672de149445ec1b772ff2c9ede9b769e3cb4f0d0aa7fa730d7f59e2d4e1c1", size = 9823610, upload-time = "2025-12-10T22:56:31.455Z" }, + { url = "https://files.pythonhosted.org/packages/4d/4b/e7beb6bbd49f6bae727a12b270a2654d13c397576d25bd6786e47033300f/matplotlib-3.10.8-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:595ba4d8fe983b88f0eec8c26a241e16d6376fe1979086232f481f8f3f67494c", size = 9614011, upload-time = "2025-12-10T22:56:33.85Z" }, + { url = "https://files.pythonhosted.org/packages/7c/e6/76f2813d31f032e65f6f797e3f2f6e4aab95b65015924b1c51370395c28a/matplotlib-3.10.8-cp314-cp314t-win_amd64.whl", hash = "sha256:25d380fe8b1dc32cf8f0b1b448470a77afb195438bafdf1d858bfb876f3edf7b", size = 8362801, upload-time = "2025-12-10T22:56:36.107Z" }, + { url = "https://files.pythonhosted.org/packages/5d/49/d651878698a0b67f23aa28e17f45a6d6dd3d3f933fa29087fa4ce5947b5a/matplotlib-3.10.8-cp314-cp314t-win_arm64.whl", hash = "sha256:113bb52413ea508ce954a02c10ffd0d565f9c3bc7f2eddc27dfe1731e71c7b5f", size = 8192560, upload-time = "2025-12-10T22:56:38.008Z" }, ] [[package]] @@ -612,45 +839,52 @@ wheels = [ [[package]] name = "multiprocess" -version = "0.70.18" +version = "0.70.19" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "dill" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/fd/2ae3826f5be24c6ed87266bc4e59c46ea5b059a103f3d7e7eb76a52aeecb/multiprocess-0.70.18.tar.gz", hash = "sha256:f9597128e6b3e67b23956da07cf3d2e5cba79e2f4e0fba8d7903636663ec6d0d", size = 1798503, upload-time = "2025-04-17T03:11:27.742Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/f2/e783ac7f2aeeed14e9e12801f22529cc7e6b7ab80928d6dcce4e9f00922d/multiprocess-0.70.19.tar.gz", hash = "sha256:952021e0e6c55a4a9fe4cd787895b86e239a40e76802a789d6305398d3975897", size = 2079989, upload-time = "2026-01-19T06:47:39.744Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/d8/0cba6cf51a1a31f20471fbc823a716170c73012ddc4fb85d706630ed6e8f/multiprocess-0.70.18-py310-none-any.whl", hash = "sha256:60c194974c31784019c1f459d984e8f33ee48f10fcf42c309ba97b30d9bd53ea", size = 134948, upload-time = "2025-04-17T03:11:20.223Z" }, - { url = "https://files.pythonhosted.org/packages/4b/88/9039f2fed1012ef584751d4ceff9ab4a51e5ae264898f0b7cbf44340a859/multiprocess-0.70.18-py311-none-any.whl", hash = "sha256:5aa6eef98e691281b3ad923be2832bf1c55dd2c859acd73e5ec53a66aae06a1d", size = 144462, upload-time = "2025-04-17T03:11:21.657Z" }, - { url = "https://files.pythonhosted.org/packages/bf/b6/5f922792be93b82ec6b5f270bbb1ef031fd0622847070bbcf9da816502cc/multiprocess-0.70.18-py312-none-any.whl", hash = "sha256:9b78f8e5024b573730bfb654783a13800c2c0f2dfc0c25e70b40d184d64adaa2", size = 150287, upload-time = "2025-04-17T03:11:22.69Z" }, - { url = "https://files.pythonhosted.org/packages/ee/25/7d7e78e750bc1aecfaf0efbf826c69a791d2eeaf29cf20cba93ff4cced78/multiprocess-0.70.18-py313-none-any.whl", hash = "sha256:871743755f43ef57d7910a38433cfe41319e72be1bbd90b79c7a5ac523eb9334", size = 151917, upload-time = "2025-04-17T03:11:24.044Z" }, - { url = "https://files.pythonhosted.org/packages/3b/c3/ca84c19bd14cdfc21c388fdcebf08b86a7a470ebc9f5c3c084fc2dbc50f7/multiprocess-0.70.18-py38-none-any.whl", hash = "sha256:dbf705e52a154fe5e90fb17b38f02556169557c2dd8bb084f2e06c2784d8279b", size = 132636, upload-time = "2025-04-17T03:11:24.936Z" }, - { url = "https://files.pythonhosted.org/packages/6c/28/dd72947e59a6a8c856448a5e74da6201cb5502ddff644fbc790e4bd40b9a/multiprocess-0.70.18-py39-none-any.whl", hash = "sha256:e78ca805a72b1b810c690b6b4cc32579eba34f403094bbbae962b7b5bf9dfcb8", size = 133478, upload-time = "2025-04-17T03:11:26.253Z" }, + { url = "https://files.pythonhosted.org/packages/e3/45/8004d1e6b9185c1a444d6b55ac5682acf9d98035e54386d967366035a03a/multiprocess-0.70.19-py310-none-any.whl", hash = "sha256:97404393419dcb2a8385910864eedf47a3cadf82c66345b44f036420eb0b5d87", size = 134948, upload-time = "2026-01-19T06:47:32.325Z" }, + { url = "https://files.pythonhosted.org/packages/86/c2/dec9722dc3474c164a0b6bcd9a7ed7da542c98af8cabce05374abab35edd/multiprocess-0.70.19-py311-none-any.whl", hash = "sha256:928851ae7973aea4ce0eaf330bbdafb2e01398a91518d5c8818802845564f45c", size = 144457, upload-time = "2026-01-19T06:47:33.711Z" }, + { url = "https://files.pythonhosted.org/packages/71/70/38998b950a97ea279e6bd657575d22d1a2047256caf707d9a10fbce4f065/multiprocess-0.70.19-py312-none-any.whl", hash = "sha256:3a56c0e85dd5025161bac5ce138dcac1e49174c7d8e74596537e729fd5c53c28", size = 150281, upload-time = "2026-01-19T06:47:35.037Z" }, + { url = "https://files.pythonhosted.org/packages/7f/74/d2c27e03cb84251dfe7249b8e82923643c6d48fa4883b9476b025e7dc7eb/multiprocess-0.70.19-py313-none-any.whl", hash = "sha256:8d5eb4ec5017ba2fab4e34a747c6d2c2b6fecfe9e7236e77988db91580ada952", size = 156414, upload-time = "2026-01-19T06:47:35.915Z" }, + { url = "https://files.pythonhosted.org/packages/a0/61/af9115673a5870fd885247e2f1b68c4f1197737da315b520a91c757a861a/multiprocess-0.70.19-py314-none-any.whl", hash = "sha256:e8cc7fbdff15c0613f0a1f1f8744bef961b0a164c0ca29bdff53e9d2d93c5e5f", size = 160318, upload-time = "2026-01-19T06:47:37.497Z" }, + { url = "https://files.pythonhosted.org/packages/7e/82/69e539c4c2027f1e1697e09aaa2449243085a0edf81ae2c6341e84d769b6/multiprocess-0.70.19-py39-none-any.whl", hash = "sha256:0d4b4397ed669d371c81dcd1ef33fd384a44d6c3de1bd0ca7ac06d837720d3c5", size = 133477, upload-time = "2026-01-19T06:47:38.619Z" }, ] [[package]] name = "mypy" -version = "1.17.0" +version = "1.19.1" source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "librt", marker = "platform_python_implementation != 'PyPy'" }, { name = "mypy-extensions" }, { name = "pathspec" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1e/e3/034322d5a779685218ed69286c32faa505247f1f096251ef66c8fd203b08/mypy-1.17.0.tar.gz", hash = "sha256:e5d7ccc08ba089c06e2f5629c660388ef1fee708444f1dee0b9203fa031dee03", size = 3352114, upload-time = "2025-07-14T20:34:30.181Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/12/e9/e6824ed620bbf51d3bf4d6cbbe4953e83eaf31a448d1b3cfb3620ccb641c/mypy-1.17.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f986f1cab8dbec39ba6e0eaa42d4d3ac6686516a5d3dccd64be095db05ebc6bb", size = 11086395, upload-time = "2025-07-14T20:34:11.452Z" }, - { url = "https://files.pythonhosted.org/packages/ba/51/a4afd1ae279707953be175d303f04a5a7bd7e28dc62463ad29c1c857927e/mypy-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:51e455a54d199dd6e931cd7ea987d061c2afbaf0960f7f66deef47c90d1b304d", size = 10120052, upload-time = "2025-07-14T20:33:09.897Z" }, - { url = "https://files.pythonhosted.org/packages/8a/71/19adfeac926ba8205f1d1466d0d360d07b46486bf64360c54cb5a2bd86a8/mypy-1.17.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3204d773bab5ff4ebbd1f8efa11b498027cd57017c003ae970f310e5b96be8d8", size = 11861806, upload-time = "2025-07-14T20:32:16.028Z" }, - { url = "https://files.pythonhosted.org/packages/0b/64/d6120eca3835baf7179e6797a0b61d6c47e0bc2324b1f6819d8428d5b9ba/mypy-1.17.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1051df7ec0886fa246a530ae917c473491e9a0ba6938cfd0ec2abc1076495c3e", size = 12744371, upload-time = "2025-07-14T20:33:33.503Z" }, - { url = "https://files.pythonhosted.org/packages/1f/dc/56f53b5255a166f5bd0f137eed960e5065f2744509dfe69474ff0ba772a5/mypy-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f773c6d14dcc108a5b141b4456b0871df638eb411a89cd1c0c001fc4a9d08fc8", size = 12914558, upload-time = "2025-07-14T20:33:56.961Z" }, - { url = "https://files.pythonhosted.org/packages/69/ac/070bad311171badc9add2910e7f89271695a25c136de24bbafc7eded56d5/mypy-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:1619a485fd0e9c959b943c7b519ed26b712de3002d7de43154a489a2d0fd817d", size = 9585447, upload-time = "2025-07-14T20:32:20.594Z" }, - { url = "https://files.pythonhosted.org/packages/be/7b/5f8ab461369b9e62157072156935cec9d272196556bdc7c2ff5f4c7c0f9b/mypy-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c41aa59211e49d717d92b3bb1238c06d387c9325d3122085113c79118bebb06", size = 11070019, upload-time = "2025-07-14T20:32:07.99Z" }, - { url = "https://files.pythonhosted.org/packages/9c/f8/c49c9e5a2ac0badcc54beb24e774d2499748302c9568f7f09e8730e953fa/mypy-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e69db1fb65b3114f98c753e3930a00514f5b68794ba80590eb02090d54a5d4a", size = 10114457, upload-time = "2025-07-14T20:33:47.285Z" }, - { url = "https://files.pythonhosted.org/packages/89/0c/fb3f9c939ad9beed3e328008b3fb90b20fda2cddc0f7e4c20dbefefc3b33/mypy-1.17.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:03ba330b76710f83d6ac500053f7727270b6b8553b0423348ffb3af6f2f7b889", size = 11857838, upload-time = "2025-07-14T20:33:14.462Z" }, - { url = "https://files.pythonhosted.org/packages/4c/66/85607ab5137d65e4f54d9797b77d5a038ef34f714929cf8ad30b03f628df/mypy-1.17.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:037bc0f0b124ce46bfde955c647f3e395c6174476a968c0f22c95a8d2f589bba", size = 12731358, upload-time = "2025-07-14T20:32:25.579Z" }, - { url = "https://files.pythonhosted.org/packages/73/d0/341dbbfb35ce53d01f8f2969facbb66486cee9804048bf6c01b048127501/mypy-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c38876106cb6132259683632b287238858bd58de267d80defb6f418e9ee50658", size = 12917480, upload-time = "2025-07-14T20:34:21.868Z" }, - { url = "https://files.pythonhosted.org/packages/64/63/70c8b7dbfc520089ac48d01367a97e8acd734f65bd07813081f508a8c94c/mypy-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:d30ba01c0f151998f367506fab31c2ac4527e6a7b2690107c7a7f9e3cb419a9c", size = 9589666, upload-time = "2025-07-14T20:34:16.841Z" }, - { url = "https://files.pythonhosted.org/packages/e3/fc/ee058cc4316f219078464555873e99d170bde1d9569abd833300dbeb484a/mypy-1.17.0-py3-none-any.whl", hash = "sha256:15d9d0018237ab058e5de3d8fce61b6fa72cc59cc78fd91f1b474bce12abf496", size = 2283195, upload-time = "2025-07-14T20:31:54.753Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/f5/db/4efed9504bc01309ab9c2da7e352cc223569f05478012b5d9ece38fd44d2/mypy-1.19.1.tar.gz", hash = "sha256:19d88bb05303fe63f71dd2c6270daca27cb9401c4ca8255fe50d1d920e0eb9ba", size = 3582404, upload-time = "2025-12-15T05:03:48.42Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/06/8a/19bfae96f6615aa8a0604915512e0289b1fad33d5909bf7244f02935d33a/mypy-1.19.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a8174a03289288c1f6c46d55cef02379b478bfbc8e358e02047487cad44c6ca1", size = 13206053, upload-time = "2025-12-15T05:03:46.622Z" }, + { url = "https://files.pythonhosted.org/packages/a5/34/3e63879ab041602154ba2a9f99817bb0c85c4df19a23a1443c8986e4d565/mypy-1.19.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffcebe56eb09ff0c0885e750036a095e23793ba6c2e894e7e63f6d89ad51f22e", size = 12219134, upload-time = "2025-12-15T05:03:24.367Z" }, + { url = "https://files.pythonhosted.org/packages/89/cc/2db6f0e95366b630364e09845672dbee0cbf0bbe753a204b29a944967cd9/mypy-1.19.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b64d987153888790bcdb03a6473d321820597ab8dd9243b27a92153c4fa50fd2", size = 12731616, upload-time = "2025-12-15T05:02:44.725Z" }, + { url = "https://files.pythonhosted.org/packages/00/be/dd56c1fd4807bc1eba1cf18b2a850d0de7bacb55e158755eb79f77c41f8e/mypy-1.19.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c35d298c2c4bba75feb2195655dfea8124d855dfd7343bf8b8c055421eaf0cf8", size = 13620847, upload-time = "2025-12-15T05:03:39.633Z" }, + { url = "https://files.pythonhosted.org/packages/6d/42/332951aae42b79329f743bf1da088cd75d8d4d9acc18fbcbd84f26c1af4e/mypy-1.19.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:34c81968774648ab5ac09c29a375fdede03ba253f8f8287847bd480782f73a6a", size = 13834976, upload-time = "2025-12-15T05:03:08.786Z" }, + { url = "https://files.pythonhosted.org/packages/6f/63/e7493e5f90e1e085c562bb06e2eb32cae27c5057b9653348d38b47daaecc/mypy-1.19.1-cp312-cp312-win_amd64.whl", hash = "sha256:b10e7c2cd7870ba4ad9b2d8a6102eb5ffc1f16ca35e3de6bfa390c1113029d13", size = 10118104, upload-time = "2025-12-15T05:03:10.834Z" }, + { url = "https://files.pythonhosted.org/packages/de/9f/a6abae693f7a0c697dbb435aac52e958dc8da44e92e08ba88d2e42326176/mypy-1.19.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e3157c7594ff2ef1634ee058aafc56a82db665c9438fd41b390f3bde1ab12250", size = 13201927, upload-time = "2025-12-15T05:02:29.138Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a4/45c35ccf6e1c65afc23a069f50e2c66f46bd3798cbe0d680c12d12935caa/mypy-1.19.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdb12f69bcc02700c2b47e070238f42cb87f18c0bc1fc4cdb4fb2bc5fd7a3b8b", size = 12206730, upload-time = "2025-12-15T05:03:01.325Z" }, + { url = "https://files.pythonhosted.org/packages/05/bb/cdcf89678e26b187650512620eec8368fded4cfd99cfcb431e4cdfd19dec/mypy-1.19.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f859fb09d9583a985be9a493d5cfc5515b56b08f7447759a0c5deaf68d80506e", size = 12724581, upload-time = "2025-12-15T05:03:20.087Z" }, + { url = "https://files.pythonhosted.org/packages/d1/32/dd260d52babf67bad8e6770f8e1102021877ce0edea106e72df5626bb0ec/mypy-1.19.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9a6538e0415310aad77cb94004ca6482330fece18036b5f360b62c45814c4ef", size = 13616252, upload-time = "2025-12-15T05:02:49.036Z" }, + { url = "https://files.pythonhosted.org/packages/71/d0/5e60a9d2e3bd48432ae2b454b7ef2b62a960ab51292b1eda2a95edd78198/mypy-1.19.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:da4869fc5e7f62a88f3fe0b5c919d1d9f7ea3cef92d3689de2823fd27e40aa75", size = 13840848, upload-time = "2025-12-15T05:02:55.95Z" }, + { url = "https://files.pythonhosted.org/packages/98/76/d32051fa65ecf6cc8c6610956473abdc9b4c43301107476ac03559507843/mypy-1.19.1-cp313-cp313-win_amd64.whl", hash = "sha256:016f2246209095e8eda7538944daa1d60e1e8134d98983b9fc1e92c1fc0cb8dd", size = 10135510, upload-time = "2025-12-15T05:02:58.438Z" }, + { url = "https://files.pythonhosted.org/packages/de/eb/b83e75f4c820c4247a58580ef86fcd35165028f191e7e1ba57128c52782d/mypy-1.19.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06e6170bd5836770e8104c8fdd58e5e725cfeb309f0a6c681a811f557e97eac1", size = 13199744, upload-time = "2025-12-15T05:03:30.823Z" }, + { url = "https://files.pythonhosted.org/packages/94/28/52785ab7bfa165f87fcbb61547a93f98bb20e7f82f90f165a1f69bce7b3d/mypy-1.19.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:804bd67b8054a85447c8954215a906d6eff9cabeabe493fb6334b24f4bfff718", size = 12215815, upload-time = "2025-12-15T05:02:42.323Z" }, + { url = "https://files.pythonhosted.org/packages/0a/c6/bdd60774a0dbfb05122e3e925f2e9e846c009e479dcec4821dad881f5b52/mypy-1.19.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21761006a7f497cb0d4de3d8ef4ca70532256688b0523eee02baf9eec895e27b", size = 12740047, upload-time = "2025-12-15T05:03:33.168Z" }, + { url = "https://files.pythonhosted.org/packages/32/2a/66ba933fe6c76bd40d1fe916a83f04fed253152f451a877520b3c4a5e41e/mypy-1.19.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28902ee51f12e0f19e1e16fbe2f8f06b6637f482c459dd393efddd0ec7f82045", size = 13601998, upload-time = "2025-12-15T05:03:13.056Z" }, + { url = "https://files.pythonhosted.org/packages/e3/da/5055c63e377c5c2418760411fd6a63ee2b96cf95397259038756c042574f/mypy-1.19.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:481daf36a4c443332e2ae9c137dfee878fcea781a2e3f895d54bd3002a900957", size = 13807476, upload-time = "2025-12-15T05:03:17.977Z" }, + { url = "https://files.pythonhosted.org/packages/cd/09/4ebd873390a063176f06b0dbf1f7783dd87bd120eae7727fa4ae4179b685/mypy-1.19.1-cp314-cp314-win_amd64.whl", hash = "sha256:8bb5c6f6d043655e055be9b542aa5f3bdd30e4f3589163e85f93f3640060509f", size = 10281872, upload-time = "2025-12-15T05:03:05.549Z" }, + { url = "https://files.pythonhosted.org/packages/8d/f4/4ce9a05ce5ded1de3ec1c1d96cf9f9504a04e54ce0ed55cfa38619a32b8d/mypy-1.19.1-py3-none-any.whl", hash = "sha256:f1235f5ea01b7db5468d53ece6aaddf1ad0b88d9e7462b86ef96fe04995d7247", size = 2471239, upload-time = "2025-12-15T05:03:07.248Z" }, ] [[package]] @@ -664,7 +898,7 @@ wheels = [ [[package]] name = "myst-parser" -version = "4.0.1" +version = "5.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "docutils" }, @@ -674,68 +908,88 @@ dependencies = [ { name = "pyyaml" }, { name = "sphinx" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/66/a5/9626ba4f73555b3735ad86247a8077d4603aa8628537687c839ab08bfe44/myst_parser-4.0.1.tar.gz", hash = "sha256:5cfea715e4f3574138aecbf7d54132296bfd72bb614d31168f48c477a830a7c4", size = 93985, upload-time = "2025-02-12T10:53:03.833Z" } +sdist = { url = "https://files.pythonhosted.org/packages/33/fa/7b45eef11b7971f0beb29d27b7bfe0d747d063aa29e170d9edd004733c8a/myst_parser-5.0.0.tar.gz", hash = "sha256:f6f231452c56e8baa662cc352c548158f6a16fcbd6e3800fc594978002b94f3a", size = 98535, upload-time = "2026-01-15T09:08:18.036Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/df/76d0321c3797b54b60fef9ec3bd6f4cfd124b9e422182156a1dd418722cf/myst_parser-4.0.1-py3-none-any.whl", hash = "sha256:9134e88959ec3b5780aedf8a99680ea242869d012e8821db3126d427edc9c95d", size = 84579, upload-time = "2025-02-12T10:53:02.078Z" }, + { url = "https://files.pythonhosted.org/packages/d3/ac/686789b9145413f1a61878c407210e41bfdb097976864e0913078b24098c/myst_parser-5.0.0-py3-none-any.whl", hash = "sha256:ab31e516024918296e169139072b81592336f2fef55b8986aa31c9f04b5f7211", size = 84533, upload-time = "2026-01-15T09:08:16.788Z" }, ] [[package]] name = "networkx" -version = "3.5" +version = "3.6.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6c/4f/ccdb8ad3a38e583f214547fd2f7ff1fc160c43a75af88e6aec213404b96a/networkx-3.5.tar.gz", hash = "sha256:d4c6f9cf81f52d69230866796b82afbccdec3db7ae4fbd1b65ea750feed50037", size = 2471065, upload-time = "2025-05-29T11:35:07.804Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/51/63fe664f3908c97be9d2e4f1158eb633317598cfa6e1fc14af5383f17512/networkx-3.6.1.tar.gz", hash = "sha256:26b7c357accc0c8cde558ad486283728b65b6a95d85ee1cd66bafab4c8168509", size = 2517025, upload-time = "2025-12-08T17:02:39.908Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/8d/776adee7bbf76365fdd7f2552710282c79a4ead5d2a46408c9043a2b70ba/networkx-3.5-py3-none-any.whl", hash = "sha256:0030d386a9a06dee3565298b4a734b68589749a544acbb6c412dc9e2489ec6ec", size = 2034406, upload-time = "2025-05-29T11:35:04.961Z" }, + { url = "https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl", hash = "sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762", size = 2068504, upload-time = "2025-12-08T17:02:38.159Z" }, ] [[package]] name = "nodeenv" -version = "1.9.1" +version = "1.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, ] [[package]] name = "numpy" -version = "2.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2e/19/d7c972dfe90a353dbd3efbbe1d14a5951de80c99c9dc1b93cd998d51dc0f/numpy-2.3.1.tar.gz", hash = "sha256:1ec9ae20a4226da374362cca3c62cd753faf2f951440b0e3b98e93c235441d2b", size = 20390372, upload-time = "2025-06-21T12:28:33.469Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/56/71ad5022e2f63cfe0ca93559403d0edef14aea70a841d640bd13cdba578e/numpy-2.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2959d8f268f3d8ee402b04a9ec4bb7604555aeacf78b360dc4ec27f1d508177d", size = 20896664, upload-time = "2025-06-21T12:15:30.845Z" }, - { url = "https://files.pythonhosted.org/packages/25/65/2db52ba049813670f7f987cc5db6dac9be7cd95e923cc6832b3d32d87cef/numpy-2.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:762e0c0c6b56bdedfef9a8e1d4538556438288c4276901ea008ae44091954e29", size = 14131078, upload-time = "2025-06-21T12:15:52.23Z" }, - { url = "https://files.pythonhosted.org/packages/57/dd/28fa3c17b0e751047ac928c1e1b6990238faad76e9b147e585b573d9d1bd/numpy-2.3.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:867ef172a0976aaa1f1d1b63cf2090de8b636a7674607d514505fb7276ab08fc", size = 5112554, upload-time = "2025-06-21T12:16:01.434Z" }, - { url = "https://files.pythonhosted.org/packages/c9/fc/84ea0cba8e760c4644b708b6819d91784c290288c27aca916115e3311d17/numpy-2.3.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:4e602e1b8682c2b833af89ba641ad4176053aaa50f5cacda1a27004352dde943", size = 6646560, upload-time = "2025-06-21T12:16:11.895Z" }, - { url = "https://files.pythonhosted.org/packages/61/b2/512b0c2ddec985ad1e496b0bd853eeb572315c0f07cd6997473ced8f15e2/numpy-2.3.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:8e333040d069eba1652fb08962ec5b76af7f2c7bce1df7e1418c8055cf776f25", size = 14260638, upload-time = "2025-06-21T12:16:32.611Z" }, - { url = "https://files.pythonhosted.org/packages/6e/45/c51cb248e679a6c6ab14b7a8e3ead3f4a3fe7425fc7a6f98b3f147bec532/numpy-2.3.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e7cbf5a5eafd8d230a3ce356d892512185230e4781a361229bd902ff403bc660", size = 16632729, upload-time = "2025-06-21T12:16:57.439Z" }, - { url = "https://files.pythonhosted.org/packages/e4/ff/feb4be2e5c09a3da161b412019caf47183099cbea1132fd98061808c2df2/numpy-2.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5f1b8f26d1086835f442286c1d9b64bb3974b0b1e41bb105358fd07d20872952", size = 15565330, upload-time = "2025-06-21T12:17:20.638Z" }, - { url = "https://files.pythonhosted.org/packages/bc/6d/ceafe87587101e9ab0d370e4f6e5f3f3a85b9a697f2318738e5e7e176ce3/numpy-2.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ee8340cb48c9b7a5899d1149eece41ca535513a9698098edbade2a8e7a84da77", size = 18361734, upload-time = "2025-06-21T12:17:47.938Z" }, - { url = "https://files.pythonhosted.org/packages/2b/19/0fb49a3ea088be691f040c9bf1817e4669a339d6e98579f91859b902c636/numpy-2.3.1-cp312-cp312-win32.whl", hash = "sha256:e772dda20a6002ef7061713dc1e2585bc1b534e7909b2030b5a46dae8ff077ab", size = 6320411, upload-time = "2025-06-21T12:17:58.475Z" }, - { url = "https://files.pythonhosted.org/packages/b1/3e/e28f4c1dd9e042eb57a3eb652f200225e311b608632bc727ae378623d4f8/numpy-2.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:cfecc7822543abdea6de08758091da655ea2210b8ffa1faf116b940693d3df76", size = 12734973, upload-time = "2025-06-21T12:18:17.601Z" }, - { url = "https://files.pythonhosted.org/packages/04/a8/8a5e9079dc722acf53522b8f8842e79541ea81835e9b5483388701421073/numpy-2.3.1-cp312-cp312-win_arm64.whl", hash = "sha256:7be91b2239af2658653c5bb6f1b8bccafaf08226a258caf78ce44710a0160d30", size = 10191491, upload-time = "2025-06-21T12:18:33.585Z" }, - { url = "https://files.pythonhosted.org/packages/d4/bd/35ad97006d8abff8631293f8ea6adf07b0108ce6fec68da3c3fcca1197f2/numpy-2.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:25a1992b0a3fdcdaec9f552ef10d8103186f5397ab45e2d25f8ac51b1a6b97e8", size = 20889381, upload-time = "2025-06-21T12:19:04.103Z" }, - { url = "https://files.pythonhosted.org/packages/f1/4f/df5923874d8095b6062495b39729178eef4a922119cee32a12ee1bd4664c/numpy-2.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7dea630156d39b02a63c18f508f85010230409db5b2927ba59c8ba4ab3e8272e", size = 14152726, upload-time = "2025-06-21T12:19:25.599Z" }, - { url = "https://files.pythonhosted.org/packages/8c/0f/a1f269b125806212a876f7efb049b06c6f8772cf0121139f97774cd95626/numpy-2.3.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:bada6058dd886061f10ea15f230ccf7dfff40572e99fef440a4a857c8728c9c0", size = 5105145, upload-time = "2025-06-21T12:19:34.782Z" }, - { url = "https://files.pythonhosted.org/packages/6d/63/a7f7fd5f375b0361682f6ffbf686787e82b7bbd561268e4f30afad2bb3c0/numpy-2.3.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:a894f3816eb17b29e4783e5873f92faf55b710c2519e5c351767c51f79d8526d", size = 6639409, upload-time = "2025-06-21T12:19:45.228Z" }, - { url = "https://files.pythonhosted.org/packages/bf/0d/1854a4121af895aab383f4aa233748f1df4671ef331d898e32426756a8a6/numpy-2.3.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:18703df6c4a4fee55fd3d6e5a253d01c5d33a295409b03fda0c86b3ca2ff41a1", size = 14257630, upload-time = "2025-06-21T12:20:06.544Z" }, - { url = "https://files.pythonhosted.org/packages/50/30/af1b277b443f2fb08acf1c55ce9d68ee540043f158630d62cef012750f9f/numpy-2.3.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:5902660491bd7a48b2ec16c23ccb9124b8abfd9583c5fdfa123fe6b421e03de1", size = 16627546, upload-time = "2025-06-21T12:20:31.002Z" }, - { url = "https://files.pythonhosted.org/packages/6e/ec/3b68220c277e463095342d254c61be8144c31208db18d3fd8ef02712bcd6/numpy-2.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:36890eb9e9d2081137bd78d29050ba63b8dab95dff7912eadf1185e80074b2a0", size = 15562538, upload-time = "2025-06-21T12:20:54.322Z" }, - { url = "https://files.pythonhosted.org/packages/77/2b/4014f2bcc4404484021c74d4c5ee8eb3de7e3f7ac75f06672f8dcf85140a/numpy-2.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a780033466159c2270531e2b8ac063704592a0bc62ec4a1b991c7c40705eb0e8", size = 18360327, upload-time = "2025-06-21T12:21:21.053Z" }, - { url = "https://files.pythonhosted.org/packages/40/8d/2ddd6c9b30fcf920837b8672f6c65590c7d92e43084c25fc65edc22e93ca/numpy-2.3.1-cp313-cp313-win32.whl", hash = "sha256:39bff12c076812595c3a306f22bfe49919c5513aa1e0e70fac756a0be7c2a2b8", size = 6312330, upload-time = "2025-06-21T12:25:07.447Z" }, - { url = "https://files.pythonhosted.org/packages/dd/c8/beaba449925988d415efccb45bf977ff8327a02f655090627318f6398c7b/numpy-2.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d5ee6eec45f08ce507a6570e06f2f879b374a552087a4179ea7838edbcbfa42", size = 12731565, upload-time = "2025-06-21T12:25:26.444Z" }, - { url = "https://files.pythonhosted.org/packages/0b/c3/5c0c575d7ec78c1126998071f58facfc124006635da75b090805e642c62e/numpy-2.3.1-cp313-cp313-win_arm64.whl", hash = "sha256:0c4d9e0a8368db90f93bd192bfa771ace63137c3488d198ee21dfb8e7771916e", size = 10190262, upload-time = "2025-06-21T12:25:42.196Z" }, - { url = "https://files.pythonhosted.org/packages/ea/19/a029cd335cf72f79d2644dcfc22d90f09caa86265cbbde3b5702ccef6890/numpy-2.3.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:b0b5397374f32ec0649dd98c652a1798192042e715df918c20672c62fb52d4b8", size = 20987593, upload-time = "2025-06-21T12:21:51.664Z" }, - { url = "https://files.pythonhosted.org/packages/25/91/8ea8894406209107d9ce19b66314194675d31761fe2cb3c84fe2eeae2f37/numpy-2.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c5bdf2015ccfcee8253fb8be695516ac4457c743473a43290fd36eba6a1777eb", size = 14300523, upload-time = "2025-06-21T12:22:13.583Z" }, - { url = "https://files.pythonhosted.org/packages/a6/7f/06187b0066eefc9e7ce77d5f2ddb4e314a55220ad62dd0bfc9f2c44bac14/numpy-2.3.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d70f20df7f08b90a2062c1f07737dd340adccf2068d0f1b9b3d56e2038979fee", size = 5227993, upload-time = "2025-06-21T12:22:22.53Z" }, - { url = "https://files.pythonhosted.org/packages/e8/ec/a926c293c605fa75e9cfb09f1e4840098ed46d2edaa6e2152ee35dc01ed3/numpy-2.3.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:2fb86b7e58f9ac50e1e9dd1290154107e47d1eef23a0ae9145ded06ea606f992", size = 6736652, upload-time = "2025-06-21T12:22:33.629Z" }, - { url = "https://files.pythonhosted.org/packages/e3/62/d68e52fb6fde5586650d4c0ce0b05ff3a48ad4df4ffd1b8866479d1d671d/numpy-2.3.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:23ab05b2d241f76cb883ce8b9a93a680752fbfcbd51c50eff0b88b979e471d8c", size = 14331561, upload-time = "2025-06-21T12:22:55.056Z" }, - { url = "https://files.pythonhosted.org/packages/fc/ec/b74d3f2430960044bdad6900d9f5edc2dc0fb8bf5a0be0f65287bf2cbe27/numpy-2.3.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:ce2ce9e5de4703a673e705183f64fd5da5bf36e7beddcb63a25ee2286e71ca48", size = 16693349, upload-time = "2025-06-21T12:23:20.53Z" }, - { url = "https://files.pythonhosted.org/packages/0d/15/def96774b9d7eb198ddadfcbd20281b20ebb510580419197e225f5c55c3e/numpy-2.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c4913079974eeb5c16ccfd2b1f09354b8fed7e0d6f2cab933104a09a6419b1ee", size = 15642053, upload-time = "2025-06-21T12:23:43.697Z" }, - { url = "https://files.pythonhosted.org/packages/2b/57/c3203974762a759540c6ae71d0ea2341c1fa41d84e4971a8e76d7141678a/numpy-2.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:010ce9b4f00d5c036053ca684c77441f2f2c934fd23bee058b4d6f196efd8280", size = 18434184, upload-time = "2025-06-21T12:24:10.708Z" }, - { url = "https://files.pythonhosted.org/packages/22/8a/ccdf201457ed8ac6245187850aff4ca56a79edbea4829f4e9f14d46fa9a5/numpy-2.3.1-cp313-cp313t-win32.whl", hash = "sha256:6269b9edfe32912584ec496d91b00b6d34282ca1d07eb10e82dfc780907d6c2e", size = 6440678, upload-time = "2025-06-21T12:24:21.596Z" }, - { url = "https://files.pythonhosted.org/packages/f1/7e/7f431d8bd8eb7e03d79294aed238b1b0b174b3148570d03a8a8a8f6a0da9/numpy-2.3.1-cp313-cp313t-win_amd64.whl", hash = "sha256:2a809637460e88a113e186e87f228d74ae2852a2e0c44de275263376f17b5bdc", size = 12870697, upload-time = "2025-06-21T12:24:40.644Z" }, - { url = "https://files.pythonhosted.org/packages/d4/ca/af82bf0fad4c3e573c6930ed743b5308492ff19917c7caaf2f9b6f9e2e98/numpy-2.3.1-cp313-cp313t-win_arm64.whl", hash = "sha256:eccb9a159db9aed60800187bc47a6d3451553f0e1b08b068d8b277ddfbb9b244", size = 10260376, upload-time = "2025-06-21T12:24:56.884Z" }, +version = "2.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/62/ae72ff66c0f1fd959925b4c11f8c2dea61f47f6acaea75a08512cdfe3fed/numpy-2.4.1.tar.gz", hash = "sha256:a1ceafc5042451a858231588a104093474c6a5c57dcc724841f5c888d237d690", size = 20721320, upload-time = "2026-01-10T06:44:59.619Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/7f/ec53e32bf10c813604edf07a3682616bd931d026fcde7b6d13195dfb684a/numpy-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d3703409aac693fa82c0aee023a1ae06a6e9d065dba10f5e8e80f642f1e9d0a2", size = 16656888, upload-time = "2026-01-10T06:42:40.913Z" }, + { url = "https://files.pythonhosted.org/packages/b8/e0/1f9585d7dae8f14864e948fd7fa86c6cb72dee2676ca2748e63b1c5acfe0/numpy-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7211b95ca365519d3596a1d8688a95874cc94219d417504d9ecb2df99fa7bfa8", size = 12373956, upload-time = "2026-01-10T06:42:43.091Z" }, + { url = "https://files.pythonhosted.org/packages/8e/43/9762e88909ff2326f5e7536fa8cb3c49fb03a7d92705f23e6e7f553d9cb3/numpy-2.4.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:5adf01965456a664fc727ed69cc71848f28d063217c63e1a0e200a118d5eec9a", size = 5202567, upload-time = "2026-01-10T06:42:45.107Z" }, + { url = "https://files.pythonhosted.org/packages/4b/ee/34b7930eb61e79feb4478800a4b95b46566969d837546aa7c034c742ef98/numpy-2.4.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:26f0bcd9c79a00e339565b303badc74d3ea2bd6d52191eeca5f95936cad107d0", size = 6549459, upload-time = "2026-01-10T06:42:48.152Z" }, + { url = "https://files.pythonhosted.org/packages/79/e3/5f115fae982565771be994867c89bcd8d7208dbfe9469185497d70de5ddf/numpy-2.4.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0093e85df2960d7e4049664b26afc58b03236e967fb942354deef3208857a04c", size = 14404859, upload-time = "2026-01-10T06:42:49.947Z" }, + { url = "https://files.pythonhosted.org/packages/d9/7d/9c8a781c88933725445a859cac5d01b5871588a15969ee6aeb618ba99eee/numpy-2.4.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7ad270f438cbdd402c364980317fb6b117d9ec5e226fff5b4148dd9aa9fc6e02", size = 16371419, upload-time = "2026-01-10T06:42:52.409Z" }, + { url = "https://files.pythonhosted.org/packages/a6/d2/8aa084818554543f17cf4162c42f162acbd3bb42688aefdba6628a859f77/numpy-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:297c72b1b98100c2e8f873d5d35fb551fce7040ade83d67dd51d38c8d42a2162", size = 16182131, upload-time = "2026-01-10T06:42:54.694Z" }, + { url = "https://files.pythonhosted.org/packages/60/db/0425216684297c58a8df35f3284ef56ec4a043e6d283f8a59c53562caf1b/numpy-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cf6470d91d34bf669f61d515499859fa7a4c2f7c36434afb70e82df7217933f9", size = 18295342, upload-time = "2026-01-10T06:42:56.991Z" }, + { url = "https://files.pythonhosted.org/packages/31/4c/14cb9d86240bd8c386c881bafbe43f001284b7cce3bc01623ac9475da163/numpy-2.4.1-cp312-cp312-win32.whl", hash = "sha256:b6bcf39112e956594b3331316d90c90c90fb961e39696bda97b89462f5f3943f", size = 5959015, upload-time = "2026-01-10T06:42:59.631Z" }, + { url = "https://files.pythonhosted.org/packages/51/cf/52a703dbeb0c65807540d29699fef5fda073434ff61846a564d5c296420f/numpy-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:e1a27bb1b2dee45a2a53f5ca6ff2d1a7f135287883a1689e930d44d1ff296c87", size = 12310730, upload-time = "2026-01-10T06:43:01.627Z" }, + { url = "https://files.pythonhosted.org/packages/69/80/a828b2d0ade5e74a9fe0f4e0a17c30fdc26232ad2bc8c9f8b3197cf7cf18/numpy-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:0e6e8f9d9ecf95399982019c01223dc130542960a12edfa8edd1122dfa66a8a8", size = 10312166, upload-time = "2026-01-10T06:43:03.673Z" }, + { url = "https://files.pythonhosted.org/packages/04/68/732d4b7811c00775f3bd522a21e8dd5a23f77eb11acdeb663e4a4ebf0ef4/numpy-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d797454e37570cfd61143b73b8debd623c3c0952959adb817dd310a483d58a1b", size = 16652495, upload-time = "2026-01-10T06:43:06.283Z" }, + { url = "https://files.pythonhosted.org/packages/20/ca/857722353421a27f1465652b2c66813eeeccea9d76d5f7b74b99f298e60e/numpy-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82c55962006156aeef1629b953fd359064aa47e4d82cfc8e67f0918f7da3344f", size = 12368657, upload-time = "2026-01-10T06:43:09.094Z" }, + { url = "https://files.pythonhosted.org/packages/81/0d/2377c917513449cc6240031a79d30eb9a163d32a91e79e0da47c43f2c0c8/numpy-2.4.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:71abbea030f2cfc3092a0ff9f8c8fdefdc5e0bf7d9d9c99663538bb0ecdac0b9", size = 5197256, upload-time = "2026-01-10T06:43:13.634Z" }, + { url = "https://files.pythonhosted.org/packages/17/39/569452228de3f5de9064ac75137082c6214be1f5c532016549a7923ab4b5/numpy-2.4.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:5b55aa56165b17aaf15520beb9cbd33c9039810e0d9643dd4379e44294c7303e", size = 6545212, upload-time = "2026-01-10T06:43:15.661Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a4/77333f4d1e4dac4395385482557aeecf4826e6ff517e32ca48e1dafbe42a/numpy-2.4.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0faba4a331195bfa96f93dd9dfaa10b2c7aa8cda3a02b7fd635e588fe821bf5", size = 14402871, upload-time = "2026-01-10T06:43:17.324Z" }, + { url = "https://files.pythonhosted.org/packages/ba/87/d341e519956273b39d8d47969dd1eaa1af740615394fe67d06f1efa68773/numpy-2.4.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e3087f53e2b4428766b54932644d148613c5a595150533ae7f00dab2f319a8", size = 16359305, upload-time = "2026-01-10T06:43:19.376Z" }, + { url = "https://files.pythonhosted.org/packages/32/91/789132c6666288eaa20ae8066bb99eba1939362e8f1a534949a215246e97/numpy-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:49e792ec351315e16da54b543db06ca8a86985ab682602d90c60ef4ff4db2a9c", size = 16181909, upload-time = "2026-01-10T06:43:21.808Z" }, + { url = "https://files.pythonhosted.org/packages/cf/b8/090b8bd27b82a844bb22ff8fdf7935cb1980b48d6e439ae116f53cdc2143/numpy-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:79e9e06c4c2379db47f3f6fc7a8652e7498251789bf8ff5bd43bf478ef314ca2", size = 18284380, upload-time = "2026-01-10T06:43:23.957Z" }, + { url = "https://files.pythonhosted.org/packages/67/78/722b62bd31842ff029412271556a1a27a98f45359dea78b1548a3a9996aa/numpy-2.4.1-cp313-cp313-win32.whl", hash = "sha256:3d1a100e48cb266090a031397863ff8a30050ceefd798f686ff92c67a486753d", size = 5957089, upload-time = "2026-01-10T06:43:27.535Z" }, + { url = "https://files.pythonhosted.org/packages/da/a6/cf32198b0b6e18d4fbfa9a21a992a7fca535b9bb2b0cdd217d4a3445b5ca/numpy-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:92a0e65272fd60bfa0d9278e0484c2f52fe03b97aedc02b357f33fe752c52ffb", size = 12307230, upload-time = "2026-01-10T06:43:29.298Z" }, + { url = "https://files.pythonhosted.org/packages/44/6c/534d692bfb7d0afe30611320c5fb713659dcb5104d7cc182aff2aea092f5/numpy-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:20d4649c773f66cc2fc36f663e091f57c3b7655f936a4c681b4250855d1da8f5", size = 10313125, upload-time = "2026-01-10T06:43:31.782Z" }, + { url = "https://files.pythonhosted.org/packages/da/a1/354583ac5c4caa566de6ddfbc42744409b515039e085fab6e0ff942e0df5/numpy-2.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f93bc6892fe7b0663e5ffa83b61aab510aacffd58c16e012bb9352d489d90cb7", size = 12496156, upload-time = "2026-01-10T06:43:34.237Z" }, + { url = "https://files.pythonhosted.org/packages/51/b0/42807c6e8cce58c00127b1dc24d365305189991f2a7917aa694a109c8d7d/numpy-2.4.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:178de8f87948163d98a4c9ab5bee4ce6519ca918926ec8df195af582de28544d", size = 5324663, upload-time = "2026-01-10T06:43:36.211Z" }, + { url = "https://files.pythonhosted.org/packages/fe/55/7a621694010d92375ed82f312b2f28017694ed784775269115323e37f5e2/numpy-2.4.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:98b35775e03ab7f868908b524fc0a84d38932d8daf7b7e1c3c3a1b6c7a2c9f15", size = 6645224, upload-time = "2026-01-10T06:43:37.884Z" }, + { url = "https://files.pythonhosted.org/packages/50/96/9fa8635ed9d7c847d87e30c834f7109fac5e88549d79ef3324ab5c20919f/numpy-2.4.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:941c2a93313d030f219f3a71fd3d91a728b82979a5e8034eb2e60d394a2b83f9", size = 14462352, upload-time = "2026-01-10T06:43:39.479Z" }, + { url = "https://files.pythonhosted.org/packages/03/d1/8cf62d8bb2062da4fb82dd5d49e47c923f9c0738032f054e0a75342faba7/numpy-2.4.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:529050522e983e00a6c1c6b67411083630de8b57f65e853d7b03d9281b8694d2", size = 16407279, upload-time = "2026-01-10T06:43:41.93Z" }, + { url = "https://files.pythonhosted.org/packages/86/1c/95c86e17c6b0b31ce6ef219da00f71113b220bcb14938c8d9a05cee0ff53/numpy-2.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2302dc0224c1cbc49bb94f7064f3f923a971bfae45c33870dcbff63a2a550505", size = 16248316, upload-time = "2026-01-10T06:43:44.121Z" }, + { url = "https://files.pythonhosted.org/packages/30/b4/e7f5ff8697274c9d0fa82398b6a372a27e5cef069b37df6355ccb1f1db1a/numpy-2.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:9171a42fcad32dcf3fa86f0a4faa5e9f8facefdb276f54b8b390d90447cff4e2", size = 18329884, upload-time = "2026-01-10T06:43:46.613Z" }, + { url = "https://files.pythonhosted.org/packages/37/a4/b073f3e9d77f9aec8debe8ca7f9f6a09e888ad1ba7488f0c3b36a94c03ac/numpy-2.4.1-cp313-cp313t-win32.whl", hash = "sha256:382ad67d99ef49024f11d1ce5dcb5ad8432446e4246a4b014418ba3a1175a1f4", size = 6081138, upload-time = "2026-01-10T06:43:48.854Z" }, + { url = "https://files.pythonhosted.org/packages/16/16/af42337b53844e67752a092481ab869c0523bc95c4e5c98e4dac4e9581ac/numpy-2.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:62fea415f83ad8fdb6c20840578e5fbaf5ddd65e0ec6c3c47eda0f69da172510", size = 12447478, upload-time = "2026-01-10T06:43:50.476Z" }, + { url = "https://files.pythonhosted.org/packages/6c/f8/fa85b2eac68ec631d0b631abc448552cb17d39afd17ec53dcbcc3537681a/numpy-2.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:a7870e8c5fc11aef57d6fea4b4085e537a3a60ad2cdd14322ed531fdca68d261", size = 10382981, upload-time = "2026-01-10T06:43:52.575Z" }, + { url = "https://files.pythonhosted.org/packages/1b/a7/ef08d25698e0e4b4efbad8d55251d20fe2a15f6d9aa7c9b30cd03c165e6f/numpy-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:3869ea1ee1a1edc16c29bbe3a2f2a4e515cc3a44d43903ad41e0cacdbaf733dc", size = 16652046, upload-time = "2026-01-10T06:43:54.797Z" }, + { url = "https://files.pythonhosted.org/packages/8f/39/e378b3e3ca13477e5ac70293ec027c438d1927f18637e396fe90b1addd72/numpy-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e867df947d427cdd7a60e3e271729090b0f0df80f5f10ab7dd436f40811699c3", size = 12378858, upload-time = "2026-01-10T06:43:57.099Z" }, + { url = "https://files.pythonhosted.org/packages/c3/74/7ec6154f0006910ed1fdbb7591cf4432307033102b8a22041599935f8969/numpy-2.4.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:e3bd2cb07841166420d2fa7146c96ce00cb3410664cbc1a6be028e456c4ee220", size = 5207417, upload-time = "2026-01-10T06:43:59.037Z" }, + { url = "https://files.pythonhosted.org/packages/f7/b7/053ac11820d84e42f8feea5cb81cc4fcd1091499b45b1ed8c7415b1bf831/numpy-2.4.1-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:f0a90aba7d521e6954670550e561a4cb925713bd944445dbe9e729b71f6cabee", size = 6542643, upload-time = "2026-01-10T06:44:01.852Z" }, + { url = "https://files.pythonhosted.org/packages/c0/c4/2e7908915c0e32ca636b92e4e4a3bdec4cb1e7eb0f8aedf1ed3c68a0d8cd/numpy-2.4.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d558123217a83b2d1ba316b986e9248a1ed1971ad495963d555ccd75dcb1556", size = 14418963, upload-time = "2026-01-10T06:44:04.047Z" }, + { url = "https://files.pythonhosted.org/packages/eb/c0/3ed5083d94e7ffd7c404e54619c088e11f2e1939a9544f5397f4adb1b8ba/numpy-2.4.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2f44de05659b67d20499cbc96d49f2650769afcb398b79b324bb6e297bfe3844", size = 16363811, upload-time = "2026-01-10T06:44:06.207Z" }, + { url = "https://files.pythonhosted.org/packages/0e/68/42b66f1852bf525050a67315a4fb94586ab7e9eaa541b1bef530fab0c5dd/numpy-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:69e7419c9012c4aaf695109564e3387f1259f001b4326dfa55907b098af082d3", size = 16197643, upload-time = "2026-01-10T06:44:08.33Z" }, + { url = "https://files.pythonhosted.org/packages/d2/40/e8714fc933d85f82c6bfc7b998a0649ad9769a32f3494ba86598aaf18a48/numpy-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2ffd257026eb1b34352e749d7cc1678b5eeec3e329ad8c9965a797e08ccba205", size = 18289601, upload-time = "2026-01-10T06:44:10.841Z" }, + { url = "https://files.pythonhosted.org/packages/80/9a/0d44b468cad50315127e884802351723daca7cf1c98d102929468c81d439/numpy-2.4.1-cp314-cp314-win32.whl", hash = "sha256:727c6c3275ddefa0dc078524a85e064c057b4f4e71ca5ca29a19163c607be745", size = 6005722, upload-time = "2026-01-10T06:44:13.332Z" }, + { url = "https://files.pythonhosted.org/packages/7e/bb/c6513edcce5a831810e2dddc0d3452ce84d208af92405a0c2e58fd8e7881/numpy-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:7d5d7999df434a038d75a748275cd6c0094b0ecdb0837342b332a82defc4dc4d", size = 12438590, upload-time = "2026-01-10T06:44:15.006Z" }, + { url = "https://files.pythonhosted.org/packages/e9/da/a598d5cb260780cf4d255102deba35c1d072dc028c4547832f45dd3323a8/numpy-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:ce9ce141a505053b3c7bce3216071f3bf5c182b8b28930f14cd24d43932cd2df", size = 10596180, upload-time = "2026-01-10T06:44:17.386Z" }, + { url = "https://files.pythonhosted.org/packages/de/bc/ea3f2c96fcb382311827231f911723aeff596364eb6e1b6d1d91128aa29b/numpy-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:4e53170557d37ae404bf8d542ca5b7c629d6efa1117dac6a83e394142ea0a43f", size = 12498774, upload-time = "2026-01-10T06:44:19.467Z" }, + { url = "https://files.pythonhosted.org/packages/aa/ab/ef9d939fe4a812648c7a712610b2ca6140b0853c5efea361301006c02ae5/numpy-2.4.1-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:a73044b752f5d34d4232f25f18160a1cc418ea4507f5f11e299d8ac36875f8a0", size = 5327274, upload-time = "2026-01-10T06:44:23.189Z" }, + { url = "https://files.pythonhosted.org/packages/bd/31/d381368e2a95c3b08b8cf7faac6004849e960f4a042d920337f71cef0cae/numpy-2.4.1-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:fb1461c99de4d040666ca0444057b06541e5642f800b71c56e6ea92d6a853a0c", size = 6648306, upload-time = "2026-01-10T06:44:25.012Z" }, + { url = "https://files.pythonhosted.org/packages/c8/e5/0989b44ade47430be6323d05c23207636d67d7362a1796ccbccac6773dd2/numpy-2.4.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:423797bdab2eeefbe608d7c1ec7b2b4fd3c58d51460f1ee26c7500a1d9c9ee93", size = 14464653, upload-time = "2026-01-10T06:44:26.706Z" }, + { url = "https://files.pythonhosted.org/packages/10/a7/cfbe475c35371cae1358e61f20c5f075badc18c4797ab4354140e1d283cf/numpy-2.4.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:52b5f61bdb323b566b528899cc7db2ba5d1015bda7ea811a8bcf3c89c331fa42", size = 16405144, upload-time = "2026-01-10T06:44:29.378Z" }, + { url = "https://files.pythonhosted.org/packages/f8/a3/0c63fe66b534888fa5177cc7cef061541064dbe2b4b60dcc60ffaf0d2157/numpy-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42d7dd5fa36d16d52a84f821eb96031836fd405ee6955dd732f2023724d0aa01", size = 16247425, upload-time = "2026-01-10T06:44:31.721Z" }, + { url = "https://files.pythonhosted.org/packages/6b/2b/55d980cfa2c93bd40ff4c290bf824d792bd41d2fe3487b07707559071760/numpy-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e7b6b5e28bbd47b7532698e5db2fe1db693d84b58c254e4389d99a27bb9b8f6b", size = 18330053, upload-time = "2026-01-10T06:44:34.617Z" }, + { url = "https://files.pythonhosted.org/packages/23/12/8b5fc6b9c487a09a7957188e0943c9ff08432c65e34567cabc1623b03a51/numpy-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:5de60946f14ebe15e713a6f22850c2372fa72f4ff9a432ab44aa90edcadaa65a", size = 6152482, upload-time = "2026-01-10T06:44:36.798Z" }, + { url = "https://files.pythonhosted.org/packages/00/a5/9f8ca5856b8940492fc24fbe13c1bc34d65ddf4079097cf9e53164d094e1/numpy-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:8f085da926c0d491ffff3096f91078cc97ea67e7e6b65e490bc8dcda65663be2", size = 12627117, upload-time = "2026-01-10T06:44:38.828Z" }, + { url = "https://files.pythonhosted.org/packages/ad/0d/eca3d962f9eef265f01a8e0d20085c6dd1f443cbffc11b6dede81fd82356/numpy-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:6436cffb4f2bf26c974344439439c95e152c9a527013f26b3577be6c2ca64295", size = 10667121, upload-time = "2026-01-10T06:44:41.644Z" }, ] [[package]] @@ -752,133 +1006,154 @@ wheels = [ [[package]] name = "packaging" -version = "25.0" +version = "26.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, + { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" }, ] [[package]] name = "pandas" -version = "2.3.1" +version = "3.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, { name = "python-dateutil" }, - { name = "pytz" }, - { name = "tzdata" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d1/6f/75aa71f8a14267117adeeed5d21b204770189c0a0025acbdc03c337b28fc/pandas-2.3.1.tar.gz", hash = "sha256:0a95b9ac964fe83ce317827f80304d37388ea77616b1425f0ae41c9d2d0d7bb2", size = 4487493, upload-time = "2025-07-07T19:20:04.079Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/46/de/b8445e0f5d217a99fe0eeb2f4988070908979bec3587c0633e5428ab596c/pandas-2.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:689968e841136f9e542020698ee1c4fbe9caa2ed2213ae2388dc7b81721510d3", size = 11588172, upload-time = "2025-07-07T19:18:52.054Z" }, - { url = "https://files.pythonhosted.org/packages/1e/e0/801cdb3564e65a5ac041ab99ea6f1d802a6c325bb6e58c79c06a3f1cd010/pandas-2.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:025e92411c16cbe5bb2a4abc99732a6b132f439b8aab23a59fa593eb00704232", size = 10717365, upload-time = "2025-07-07T19:18:54.785Z" }, - { url = "https://files.pythonhosted.org/packages/51/a5/c76a8311833c24ae61a376dbf360eb1b1c9247a5d9c1e8b356563b31b80c/pandas-2.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b7ff55f31c4fcb3e316e8f7fa194566b286d6ac430afec0d461163312c5841e", size = 11280411, upload-time = "2025-07-07T19:18:57.045Z" }, - { url = "https://files.pythonhosted.org/packages/da/01/e383018feba0a1ead6cf5fe8728e5d767fee02f06a3d800e82c489e5daaf/pandas-2.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7dcb79bf373a47d2a40cf7232928eb7540155abbc460925c2c96d2d30b006eb4", size = 11988013, upload-time = "2025-07-07T19:18:59.771Z" }, - { url = "https://files.pythonhosted.org/packages/5b/14/cec7760d7c9507f11c97d64f29022e12a6cc4fc03ac694535e89f88ad2ec/pandas-2.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:56a342b231e8862c96bdb6ab97170e203ce511f4d0429589c8ede1ee8ece48b8", size = 12767210, upload-time = "2025-07-07T19:19:02.944Z" }, - { url = "https://files.pythonhosted.org/packages/50/b9/6e2d2c6728ed29fb3d4d4d302504fb66f1a543e37eb2e43f352a86365cdf/pandas-2.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ca7ed14832bce68baef331f4d7f294411bed8efd032f8109d690df45e00c4679", size = 13440571, upload-time = "2025-07-07T19:19:06.82Z" }, - { url = "https://files.pythonhosted.org/packages/80/a5/3a92893e7399a691bad7664d977cb5e7c81cf666c81f89ea76ba2bff483d/pandas-2.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:ac942bfd0aca577bef61f2bc8da8147c4ef6879965ef883d8e8d5d2dc3e744b8", size = 10987601, upload-time = "2025-07-07T19:19:09.589Z" }, - { url = "https://files.pythonhosted.org/packages/32/ed/ff0a67a2c5505e1854e6715586ac6693dd860fbf52ef9f81edee200266e7/pandas-2.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9026bd4a80108fac2239294a15ef9003c4ee191a0f64b90f170b40cfb7cf2d22", size = 11531393, upload-time = "2025-07-07T19:19:12.245Z" }, - { url = "https://files.pythonhosted.org/packages/c7/db/d8f24a7cc9fb0972adab0cc80b6817e8bef888cfd0024eeb5a21c0bb5c4a/pandas-2.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6de8547d4fdb12421e2d047a2c446c623ff4c11f47fddb6b9169eb98ffba485a", size = 10668750, upload-time = "2025-07-07T19:19:14.612Z" }, - { url = "https://files.pythonhosted.org/packages/0f/b0/80f6ec783313f1e2356b28b4fd8d2148c378370045da918c73145e6aab50/pandas-2.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:782647ddc63c83133b2506912cc6b108140a38a37292102aaa19c81c83db2928", size = 11342004, upload-time = "2025-07-07T19:19:16.857Z" }, - { url = "https://files.pythonhosted.org/packages/e9/e2/20a317688435470872885e7fc8f95109ae9683dec7c50be29b56911515a5/pandas-2.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ba6aff74075311fc88504b1db890187a3cd0f887a5b10f5525f8e2ef55bfdb9", size = 12050869, upload-time = "2025-07-07T19:19:19.265Z" }, - { url = "https://files.pythonhosted.org/packages/55/79/20d746b0a96c67203a5bee5fb4e00ac49c3e8009a39e1f78de264ecc5729/pandas-2.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e5635178b387bd2ba4ac040f82bc2ef6e6b500483975c4ebacd34bec945fda12", size = 12750218, upload-time = "2025-07-07T19:19:21.547Z" }, - { url = "https://files.pythonhosted.org/packages/7c/0f/145c8b41e48dbf03dd18fdd7f24f8ba95b8254a97a3379048378f33e7838/pandas-2.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6f3bf5ec947526106399a9e1d26d40ee2b259c66422efdf4de63c848492d91bb", size = 13416763, upload-time = "2025-07-07T19:19:23.939Z" }, - { url = "https://files.pythonhosted.org/packages/b2/c0/54415af59db5cdd86a3d3bf79863e8cc3fa9ed265f0745254061ac09d5f2/pandas-2.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:1c78cf43c8fde236342a1cb2c34bcff89564a7bfed7e474ed2fffa6aed03a956", size = 10987482, upload-time = "2025-07-07T19:19:42.699Z" }, - { url = "https://files.pythonhosted.org/packages/48/64/2fd2e400073a1230e13b8cd604c9bc95d9e3b962e5d44088ead2e8f0cfec/pandas-2.3.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8dfc17328e8da77be3cf9f47509e5637ba8f137148ed0e9b5241e1baf526e20a", size = 12029159, upload-time = "2025-07-07T19:19:26.362Z" }, - { url = "https://files.pythonhosted.org/packages/d8/0a/d84fd79b0293b7ef88c760d7dca69828d867c89b6d9bc52d6a27e4d87316/pandas-2.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:ec6c851509364c59a5344458ab935e6451b31b818be467eb24b0fe89bd05b6b9", size = 11393287, upload-time = "2025-07-07T19:19:29.157Z" }, - { url = "https://files.pythonhosted.org/packages/50/ae/ff885d2b6e88f3c7520bb74ba319268b42f05d7e583b5dded9837da2723f/pandas-2.3.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:911580460fc4884d9b05254b38a6bfadddfcc6aaef856fb5859e7ca202e45275", size = 11309381, upload-time = "2025-07-07T19:19:31.436Z" }, - { url = "https://files.pythonhosted.org/packages/85/86/1fa345fc17caf5d7780d2699985c03dbe186c68fee00b526813939062bb0/pandas-2.3.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f4d6feeba91744872a600e6edbbd5b033005b431d5ae8379abee5bcfa479fab", size = 11883998, upload-time = "2025-07-07T19:19:34.267Z" }, - { url = "https://files.pythonhosted.org/packages/81/aa/e58541a49b5e6310d89474333e994ee57fea97c8aaa8fc7f00b873059bbf/pandas-2.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:fe37e757f462d31a9cd7580236a82f353f5713a80e059a29753cf938c6775d96", size = 12704705, upload-time = "2025-07-07T19:19:36.856Z" }, - { url = "https://files.pythonhosted.org/packages/d5/f9/07086f5b0f2a19872554abeea7658200824f5835c58a106fa8f2ae96a46c/pandas-2.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5db9637dbc24b631ff3707269ae4559bce4b7fd75c1c4d7e13f40edc42df4444", size = 13189044, upload-time = "2025-07-07T19:19:39.999Z" }, + { name = "tzdata", marker = "sys_platform == 'emscripten' or sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/da/b1dc0481ab8d55d0f46e343cfe67d4551a0e14fcee52bd38ca1bd73258d8/pandas-3.0.0.tar.gz", hash = "sha256:0facf7e87d38f721f0af46fe70d97373a37701b1c09f7ed7aeeb292ade5c050f", size = 4633005, upload-time = "2026-01-21T15:52:04.726Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/38/db33686f4b5fa64d7af40d96361f6a4615b8c6c8f1b3d334eee46ae6160e/pandas-3.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9803b31f5039b3c3b10cc858c5e40054adb4b29b4d81cb2fd789f4121c8efbcd", size = 10334013, upload-time = "2026-01-21T15:50:34.771Z" }, + { url = "https://files.pythonhosted.org/packages/a5/7b/9254310594e9774906bacdd4e732415e1f86ab7dbb4b377ef9ede58cd8ec/pandas-3.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:14c2a4099cd38a1d18ff108168ea417909b2dea3bd1ebff2ccf28ddb6a74d740", size = 9874154, upload-time = "2026-01-21T15:50:36.67Z" }, + { url = "https://files.pythonhosted.org/packages/63/d4/726c5a67a13bc66643e66d2e9ff115cead482a44fc56991d0c4014f15aaf/pandas-3.0.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d257699b9a9960e6125686098d5714ac59d05222bef7a5e6af7a7fd87c650801", size = 10384433, upload-time = "2026-01-21T15:50:39.132Z" }, + { url = "https://files.pythonhosted.org/packages/bf/2e/9211f09bedb04f9832122942de8b051804b31a39cfbad199a819bb88d9f3/pandas-3.0.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:69780c98f286076dcafca38d8b8eee1676adf220199c0a39f0ecbf976b68151a", size = 10864519, upload-time = "2026-01-21T15:50:41.043Z" }, + { url = "https://files.pythonhosted.org/packages/00/8d/50858522cdc46ac88b9afdc3015e298959a70a08cd21e008a44e9520180c/pandas-3.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4a66384f017240f3858a4c8a7cf21b0591c3ac885cddb7758a589f0f71e87ebb", size = 11394124, upload-time = "2026-01-21T15:50:43.377Z" }, + { url = "https://files.pythonhosted.org/packages/86/3f/83b2577db02503cd93d8e95b0f794ad9d4be0ba7cb6c8bcdcac964a34a42/pandas-3.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be8c515c9bc33989d97b89db66ea0cececb0f6e3c2a87fcc8b69443a6923e95f", size = 11920444, upload-time = "2026-01-21T15:50:45.932Z" }, + { url = "https://files.pythonhosted.org/packages/64/2d/4f8a2f192ed12c90a0aab47f5557ece0e56b0370c49de9454a09de7381b2/pandas-3.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:a453aad8c4f4e9f166436994a33884442ea62aa8b27d007311e87521b97246e1", size = 9730970, upload-time = "2026-01-21T15:50:47.962Z" }, + { url = "https://files.pythonhosted.org/packages/d4/64/ff571be435cf1e643ca98d0945d76732c0b4e9c37191a89c8550b105eed1/pandas-3.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:da768007b5a33057f6d9053563d6b74dd6d029c337d93c6d0d22a763a5c2ecc0", size = 9041950, upload-time = "2026-01-21T15:50:50.422Z" }, + { url = "https://files.pythonhosted.org/packages/6f/fa/7f0ac4ca8877c57537aaff2a842f8760e630d8e824b730eb2e859ffe96ca/pandas-3.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b78d646249b9a2bc191040988c7bb524c92fa8534fb0898a0741d7e6f2ffafa6", size = 10307129, upload-time = "2026-01-21T15:50:52.877Z" }, + { url = "https://files.pythonhosted.org/packages/6f/11/28a221815dcea4c0c9414dfc845e34a84a6a7dabc6da3194498ed5ba4361/pandas-3.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bc9cba7b355cb4162442a88ce495e01cb605f17ac1e27d6596ac963504e0305f", size = 9850201, upload-time = "2026-01-21T15:50:54.807Z" }, + { url = "https://files.pythonhosted.org/packages/ba/da/53bbc8c5363b7e5bd10f9ae59ab250fc7a382ea6ba08e4d06d8694370354/pandas-3.0.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c9a1a149aed3b6c9bf246033ff91e1b02d529546c5d6fb6b74a28fea0cf4c70", size = 10354031, upload-time = "2026-01-21T15:50:57.463Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a3/51e02ebc2a14974170d51e2410dfdab58870ea9bcd37cda15bd553d24dc4/pandas-3.0.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:95683af6175d884ee89471842acfca29172a85031fccdabc35e50c0984470a0e", size = 10861165, upload-time = "2026-01-21T15:50:59.32Z" }, + { url = "https://files.pythonhosted.org/packages/a5/fe/05a51e3cac11d161472b8297bd41723ea98013384dd6d76d115ce3482f9b/pandas-3.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1fbbb5a7288719e36b76b4f18d46ede46e7f916b6c8d9915b756b0a6c3f792b3", size = 11359359, upload-time = "2026-01-21T15:51:02.014Z" }, + { url = "https://files.pythonhosted.org/packages/ee/56/ba620583225f9b85a4d3e69c01df3e3870659cc525f67929b60e9f21dcd1/pandas-3.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8e8b9808590fa364416b49b2a35c1f4cf2785a6c156935879e57f826df22038e", size = 11912907, upload-time = "2026-01-21T15:51:05.175Z" }, + { url = "https://files.pythonhosted.org/packages/c9/8c/c6638d9f67e45e07656b3826405c5cc5f57f6fd07c8b2572ade328c86e22/pandas-3.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:98212a38a709feb90ae658cb6227ea3657c22ba8157d4b8f913cd4c950de5e7e", size = 9732138, upload-time = "2026-01-21T15:51:07.569Z" }, + { url = "https://files.pythonhosted.org/packages/7b/bf/bd1335c3bf1770b6d8fed2799993b11c4971af93bb1b729b9ebbc02ca2ec/pandas-3.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:177d9df10b3f43b70307a149d7ec49a1229a653f907aa60a48f1877d0e6be3be", size = 9033568, upload-time = "2026-01-21T15:51:09.484Z" }, + { url = "https://files.pythonhosted.org/packages/8e/c6/f5e2171914d5e29b9171d495344097d54e3ffe41d2d85d8115baba4dc483/pandas-3.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2713810ad3806767b89ad3b7b69ba153e1c6ff6d9c20f9c2140379b2a98b6c98", size = 10741936, upload-time = "2026-01-21T15:51:11.693Z" }, + { url = "https://files.pythonhosted.org/packages/51/88/9a0164f99510a1acb9f548691f022c756c2314aad0d8330a24616c14c462/pandas-3.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:15d59f885ee5011daf8335dff47dcb8a912a27b4ad7826dc6cbe809fd145d327", size = 10393884, upload-time = "2026-01-21T15:51:14.197Z" }, + { url = "https://files.pythonhosted.org/packages/e0/53/b34d78084d88d8ae2b848591229da8826d1e65aacf00b3abe34023467648/pandas-3.0.0-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:24e6547fb64d2c92665dd2adbfa4e85fa4fd70a9c070e7cfb03b629a0bbab5eb", size = 10310740, upload-time = "2026-01-21T15:51:16.093Z" }, + { url = "https://files.pythonhosted.org/packages/5b/d3/bee792e7c3d6930b74468d990604325701412e55d7aaf47460a22311d1a5/pandas-3.0.0-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:48ee04b90e2505c693d3f8e8f524dab8cb8aaf7ddcab52c92afa535e717c4812", size = 10700014, upload-time = "2026-01-21T15:51:18.818Z" }, + { url = "https://files.pythonhosted.org/packages/55/db/2570bc40fb13aaed1cbc3fbd725c3a60ee162477982123c3adc8971e7ac1/pandas-3.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:66f72fb172959af42a459e27a8d8d2c7e311ff4c1f7db6deb3b643dbc382ae08", size = 11323737, upload-time = "2026-01-21T15:51:20.784Z" }, + { url = "https://files.pythonhosted.org/packages/bc/2e/297ac7f21c8181b62a4cccebad0a70caf679adf3ae5e83cb676194c8acc3/pandas-3.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4a4a400ca18230976724a5066f20878af785f36c6756e498e94c2a5e5d57779c", size = 11771558, upload-time = "2026-01-21T15:51:22.977Z" }, + { url = "https://files.pythonhosted.org/packages/0a/46/e1c6876d71c14332be70239acce9ad435975a80541086e5ffba2f249bcf6/pandas-3.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:940eebffe55528074341a5a36515f3e4c5e25e958ebbc764c9502cfc35ba3faa", size = 10473771, upload-time = "2026-01-21T15:51:25.285Z" }, + { url = "https://files.pythonhosted.org/packages/c0/db/0270ad9d13c344b7a36fa77f5f8344a46501abf413803e885d22864d10bf/pandas-3.0.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:597c08fb9fef0edf1e4fa2f9828dd27f3d78f9b8c9b4a748d435ffc55732310b", size = 10312075, upload-time = "2026-01-21T15:51:28.5Z" }, + { url = "https://files.pythonhosted.org/packages/09/9f/c176f5e9717f7c91becfe0f55a52ae445d3f7326b4a2cf355978c51b7913/pandas-3.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:447b2d68ac5edcbf94655fe909113a6dba6ef09ad7f9f60c80477825b6c489fe", size = 9900213, upload-time = "2026-01-21T15:51:30.955Z" }, + { url = "https://files.pythonhosted.org/packages/d9/e7/63ad4cc10b257b143e0a5ebb04304ad806b4e1a61c5da25f55896d2ca0f4/pandas-3.0.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:debb95c77ff3ed3ba0d9aa20c3a2f19165cc7956362f9873fce1ba0a53819d70", size = 10428768, upload-time = "2026-01-21T15:51:33.018Z" }, + { url = "https://files.pythonhosted.org/packages/9e/0e/4e4c2d8210f20149fd2248ef3fff26623604922bd564d915f935a06dd63d/pandas-3.0.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fedabf175e7cd82b69b74c30adbaa616de301291a5231138d7242596fc296a8d", size = 10882954, upload-time = "2026-01-21T15:51:35.287Z" }, + { url = "https://files.pythonhosted.org/packages/c6/60/c9de8ac906ba1f4d2250f8a951abe5135b404227a55858a75ad26f84db47/pandas-3.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:412d1a89aab46889f3033a386912efcdfa0f1131c5705ff5b668dda88305e986", size = 11430293, upload-time = "2026-01-21T15:51:37.57Z" }, + { url = "https://files.pythonhosted.org/packages/a1/69/806e6637c70920e5787a6d6896fd707f8134c2c55cd761e7249a97b7dc5a/pandas-3.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e979d22316f9350c516479dd3a92252be2937a9531ed3a26ec324198a99cdd49", size = 11952452, upload-time = "2026-01-21T15:51:39.618Z" }, + { url = "https://files.pythonhosted.org/packages/cb/de/918621e46af55164c400ab0ef389c9d969ab85a43d59ad1207d4ddbe30a5/pandas-3.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:083b11415b9970b6e7888800c43c82e81a06cd6b06755d84804444f0007d6bb7", size = 9851081, upload-time = "2026-01-21T15:51:41.758Z" }, + { url = "https://files.pythonhosted.org/packages/91/a1/3562a18dd0bd8c73344bfa26ff90c53c72f827df119d6d6b1dacc84d13e3/pandas-3.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:5db1e62cb99e739fa78a28047e861b256d17f88463c76b8dafc7c1338086dca8", size = 9174610, upload-time = "2026-01-21T15:51:44.312Z" }, + { url = "https://files.pythonhosted.org/packages/ce/26/430d91257eaf366f1737d7a1c158677caaf6267f338ec74e3a1ec444111c/pandas-3.0.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:697b8f7d346c68274b1b93a170a70974cdc7d7354429894d5927c1effdcccd73", size = 10761999, upload-time = "2026-01-21T15:51:46.899Z" }, + { url = "https://files.pythonhosted.org/packages/ec/1a/954eb47736c2b7f7fe6a9d56b0cb6987773c00faa3c6451a43db4beb3254/pandas-3.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8cb3120f0d9467ed95e77f67a75e030b67545bcfa08964e349252d674171def2", size = 10410279, upload-time = "2026-01-21T15:51:48.89Z" }, + { url = "https://files.pythonhosted.org/packages/20/fc/b96f3a5a28b250cd1b366eb0108df2501c0f38314a00847242abab71bb3a/pandas-3.0.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:33fd3e6baa72899746b820c31e4b9688c8e1b7864d7aec2de7ab5035c285277a", size = 10330198, upload-time = "2026-01-21T15:51:51.015Z" }, + { url = "https://files.pythonhosted.org/packages/90/b3/d0e2952f103b4fbef1ef22d0c2e314e74fc9064b51cee30890b5e3286ee6/pandas-3.0.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8942e333dc67ceda1095227ad0febb05a3b36535e520154085db632c40ad084", size = 10728513, upload-time = "2026-01-21T15:51:53.387Z" }, + { url = "https://files.pythonhosted.org/packages/76/81/832894f286df828993dc5fd61c63b231b0fb73377e99f6c6c369174cf97e/pandas-3.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:783ac35c4d0fe0effdb0d67161859078618b1b6587a1af15928137525217a721", size = 11345550, upload-time = "2026-01-21T15:51:55.329Z" }, + { url = "https://files.pythonhosted.org/packages/34/a0/ed160a00fb4f37d806406bc0a79a8b62fe67f29d00950f8d16203ff3409b/pandas-3.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:125eb901e233f155b268bbef9abd9afb5819db74f0e677e89a61b246228c71ac", size = 11799386, upload-time = "2026-01-21T15:51:57.457Z" }, + { url = "https://files.pythonhosted.org/packages/36/c8/2ac00d7255252c5e3cf61b35ca92ca25704b0188f7454ca4aec08a33cece/pandas-3.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b86d113b6c109df3ce0ad5abbc259fe86a1bd4adfd4a31a89da42f84f65509bb", size = 10873041, upload-time = "2026-01-21T15:52:00.034Z" }, + { url = "https://files.pythonhosted.org/packages/e6/3f/a80ac00acbc6b35166b42850e98a4f466e2c0d9c64054161ba9620f95680/pandas-3.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:1c39eab3ad38f2d7a249095f0a3d8f8c22cc0f847e98ccf5bbe732b272e2d9fa", size = 9441003, upload-time = "2026-01-21T15:52:02.281Z" }, ] [[package]] name = "pandas-stubs" -version = "2.3.2.250926" +version = "2.3.3.260113" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, { name = "types-pytz" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1b/3b/32be58a125db39d0b5f62cc93795f32b5bb2915bd5c4a46f0e35171985e2/pandas_stubs-2.3.2.250926.tar.gz", hash = "sha256:c64b9932760ceefb96a3222b953e6a251321a9832a28548be6506df473a66406", size = 102147, upload-time = "2025-09-26T19:50:39.522Z" } +sdist = { url = "https://files.pythonhosted.org/packages/92/5d/be23854a73fda69f1dbdda7bc10fbd6f930bd1fa87aaec389f00c901c1e8/pandas_stubs-2.3.3.260113.tar.gz", hash = "sha256:076e3724bcaa73de78932b012ec64b3010463d377fa63116f4e6850643d93800", size = 116131, upload-time = "2026-01-13T22:30:16.704Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/40/96/1e4a035eaf4dce9610aac6e43026d0c6baa05773daf6d21e635a4fe19e21/pandas_stubs-2.3.2.250926-py3-none-any.whl", hash = "sha256:81121818453dcfe00f45c852f4dceee043640b813830f6e7bd084a4ef7ff7270", size = 159995, upload-time = "2025-09-26T19:50:38.241Z" }, + { url = "https://files.pythonhosted.org/packages/d1/c6/df1fe324248424f77b89371116dab5243db7f052c32cc9fe7442ad9c5f75/pandas_stubs-2.3.3.260113-py3-none-any.whl", hash = "sha256:ec070b5c576e1badf12544ae50385872f0631fc35d99d00dc598c2954ec564d3", size = 168246, upload-time = "2026-01-13T22:30:15.244Z" }, ] [[package]] name = "pathspec" -version = "0.12.1" +version = "1.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/b2/bb8e495d5262bfec41ab5cb18f522f1012933347fb5d9e62452d446baca2/pathspec-1.0.3.tar.gz", hash = "sha256:bac5cf97ae2c2876e2d25ebb15078eb04d76e4b98921ee31c6f85ade8b59444d", size = 130841, upload-time = "2026-01-09T15:46:46.009Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, + { url = "https://files.pythonhosted.org/packages/32/2b/121e912bd60eebd623f873fd090de0e84f322972ab25a7f9044c056804ed/pathspec-1.0.3-py3-none-any.whl", hash = "sha256:e80767021c1cc524aa3fb14bedda9c34406591343cc42797b386ce7b9354fb6c", size = 55021, upload-time = "2026-01-09T15:46:44.652Z" }, ] [[package]] name = "pillow" -version = "11.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/d0d6dea55cd152ce3d6767bb38a8fc10e33796ba4ba210cbab9354b6d238/pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523", size = 47113069, upload-time = "2025-07-01T09:16:30.666Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/40/fe/1bc9b3ee13f68487a99ac9529968035cca2f0a51ec36892060edcc51d06a/pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4", size = 5278800, upload-time = "2025-07-01T09:14:17.648Z" }, - { url = "https://files.pythonhosted.org/packages/2c/32/7e2ac19b5713657384cec55f89065fb306b06af008cfd87e572035b27119/pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69", size = 4686296, upload-time = "2025-07-01T09:14:19.828Z" }, - { url = "https://files.pythonhosted.org/packages/8e/1e/b9e12bbe6e4c2220effebc09ea0923a07a6da1e1f1bfbc8d7d29a01ce32b/pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d", size = 5871726, upload-time = "2025-07-03T13:10:04.448Z" }, - { url = "https://files.pythonhosted.org/packages/8d/33/e9200d2bd7ba00dc3ddb78df1198a6e80d7669cce6c2bdbeb2530a74ec58/pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6", size = 7644652, upload-time = "2025-07-03T13:10:10.391Z" }, - { url = "https://files.pythonhosted.org/packages/41/f1/6f2427a26fc683e00d985bc391bdd76d8dd4e92fac33d841127eb8fb2313/pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7", size = 5977787, upload-time = "2025-07-01T09:14:21.63Z" }, - { url = "https://files.pythonhosted.org/packages/e4/c9/06dd4a38974e24f932ff5f98ea3c546ce3f8c995d3f0985f8e5ba48bba19/pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024", size = 6645236, upload-time = "2025-07-01T09:14:23.321Z" }, - { url = "https://files.pythonhosted.org/packages/40/e7/848f69fb79843b3d91241bad658e9c14f39a32f71a301bcd1d139416d1be/pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809", size = 6086950, upload-time = "2025-07-01T09:14:25.237Z" }, - { url = "https://files.pythonhosted.org/packages/0b/1a/7cff92e695a2a29ac1958c2a0fe4c0b2393b60aac13b04a4fe2735cad52d/pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d", size = 6723358, upload-time = "2025-07-01T09:14:27.053Z" }, - { url = "https://files.pythonhosted.org/packages/26/7d/73699ad77895f69edff76b0f332acc3d497f22f5d75e5360f78cbcaff248/pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149", size = 6275079, upload-time = "2025-07-01T09:14:30.104Z" }, - { url = "https://files.pythonhosted.org/packages/8c/ce/e7dfc873bdd9828f3b6e5c2bbb74e47a98ec23cc5c74fc4e54462f0d9204/pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d", size = 6986324, upload-time = "2025-07-01T09:14:31.899Z" }, - { url = "https://files.pythonhosted.org/packages/16/8f/b13447d1bf0b1f7467ce7d86f6e6edf66c0ad7cf44cf5c87a37f9bed9936/pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542", size = 2423067, upload-time = "2025-07-01T09:14:33.709Z" }, - { url = "https://files.pythonhosted.org/packages/1e/93/0952f2ed8db3a5a4c7a11f91965d6184ebc8cd7cbb7941a260d5f018cd2d/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd", size = 2128328, upload-time = "2025-07-01T09:14:35.276Z" }, - { url = "https://files.pythonhosted.org/packages/4b/e8/100c3d114b1a0bf4042f27e0f87d2f25e857e838034e98ca98fe7b8c0a9c/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8", size = 2170652, upload-time = "2025-07-01T09:14:37.203Z" }, - { url = "https://files.pythonhosted.org/packages/aa/86/3f758a28a6e381758545f7cdb4942e1cb79abd271bea932998fc0db93cb6/pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f", size = 2227443, upload-time = "2025-07-01T09:14:39.344Z" }, - { url = "https://files.pythonhosted.org/packages/01/f4/91d5b3ffa718df2f53b0dc109877993e511f4fd055d7e9508682e8aba092/pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c", size = 5278474, upload-time = "2025-07-01T09:14:41.843Z" }, - { url = "https://files.pythonhosted.org/packages/f9/0e/37d7d3eca6c879fbd9dba21268427dffda1ab00d4eb05b32923d4fbe3b12/pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd", size = 4686038, upload-time = "2025-07-01T09:14:44.008Z" }, - { url = "https://files.pythonhosted.org/packages/ff/b0/3426e5c7f6565e752d81221af9d3676fdbb4f352317ceafd42899aaf5d8a/pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e", size = 5864407, upload-time = "2025-07-03T13:10:15.628Z" }, - { url = "https://files.pythonhosted.org/packages/fc/c1/c6c423134229f2a221ee53f838d4be9d82bab86f7e2f8e75e47b6bf6cd77/pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1", size = 7639094, upload-time = "2025-07-03T13:10:21.857Z" }, - { url = "https://files.pythonhosted.org/packages/ba/c9/09e6746630fe6372c67c648ff9deae52a2bc20897d51fa293571977ceb5d/pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805", size = 5973503, upload-time = "2025-07-01T09:14:45.698Z" }, - { url = "https://files.pythonhosted.org/packages/d5/1c/a2a29649c0b1983d3ef57ee87a66487fdeb45132df66ab30dd37f7dbe162/pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8", size = 6642574, upload-time = "2025-07-01T09:14:47.415Z" }, - { url = "https://files.pythonhosted.org/packages/36/de/d5cc31cc4b055b6c6fd990e3e7f0f8aaf36229a2698501bcb0cdf67c7146/pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2", size = 6084060, upload-time = "2025-07-01T09:14:49.636Z" }, - { url = "https://files.pythonhosted.org/packages/d5/ea/502d938cbaeec836ac28a9b730193716f0114c41325db428e6b280513f09/pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b", size = 6721407, upload-time = "2025-07-01T09:14:51.962Z" }, - { url = "https://files.pythonhosted.org/packages/45/9c/9c5e2a73f125f6cbc59cc7087c8f2d649a7ae453f83bd0362ff7c9e2aee2/pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3", size = 6273841, upload-time = "2025-07-01T09:14:54.142Z" }, - { url = "https://files.pythonhosted.org/packages/23/85/397c73524e0cd212067e0c969aa245b01d50183439550d24d9f55781b776/pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51", size = 6978450, upload-time = "2025-07-01T09:14:56.436Z" }, - { url = "https://files.pythonhosted.org/packages/17/d2/622f4547f69cd173955194b78e4d19ca4935a1b0f03a302d655c9f6aae65/pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580", size = 2423055, upload-time = "2025-07-01T09:14:58.072Z" }, - { url = "https://files.pythonhosted.org/packages/dd/80/a8a2ac21dda2e82480852978416cfacd439a4b490a501a288ecf4fe2532d/pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e", size = 5281110, upload-time = "2025-07-01T09:14:59.79Z" }, - { url = "https://files.pythonhosted.org/packages/44/d6/b79754ca790f315918732e18f82a8146d33bcd7f4494380457ea89eb883d/pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d", size = 4689547, upload-time = "2025-07-01T09:15:01.648Z" }, - { url = "https://files.pythonhosted.org/packages/49/20/716b8717d331150cb00f7fdd78169c01e8e0c219732a78b0e59b6bdb2fd6/pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced", size = 5901554, upload-time = "2025-07-03T13:10:27.018Z" }, - { url = "https://files.pythonhosted.org/packages/74/cf/a9f3a2514a65bb071075063a96f0a5cf949c2f2fce683c15ccc83b1c1cab/pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c", size = 7669132, upload-time = "2025-07-03T13:10:33.01Z" }, - { url = "https://files.pythonhosted.org/packages/98/3c/da78805cbdbee9cb43efe8261dd7cc0b4b93f2ac79b676c03159e9db2187/pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8", size = 6005001, upload-time = "2025-07-01T09:15:03.365Z" }, - { url = "https://files.pythonhosted.org/packages/6c/fa/ce044b91faecf30e635321351bba32bab5a7e034c60187fe9698191aef4f/pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59", size = 6668814, upload-time = "2025-07-01T09:15:05.655Z" }, - { url = "https://files.pythonhosted.org/packages/7b/51/90f9291406d09bf93686434f9183aba27b831c10c87746ff49f127ee80cb/pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe", size = 6113124, upload-time = "2025-07-01T09:15:07.358Z" }, - { url = "https://files.pythonhosted.org/packages/cd/5a/6fec59b1dfb619234f7636d4157d11fb4e196caeee220232a8d2ec48488d/pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c", size = 6747186, upload-time = "2025-07-01T09:15:09.317Z" }, - { url = "https://files.pythonhosted.org/packages/49/6b/00187a044f98255225f172de653941e61da37104a9ea60e4f6887717e2b5/pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788", size = 6277546, upload-time = "2025-07-01T09:15:11.311Z" }, - { url = "https://files.pythonhosted.org/packages/e8/5c/6caaba7e261c0d75bab23be79f1d06b5ad2a2ae49f028ccec801b0e853d6/pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31", size = 6985102, upload-time = "2025-07-01T09:15:13.164Z" }, - { url = "https://files.pythonhosted.org/packages/f3/7e/b623008460c09a0cb38263c93b828c666493caee2eb34ff67f778b87e58c/pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e", size = 2424803, upload-time = "2025-07-01T09:15:15.695Z" }, - { url = "https://files.pythonhosted.org/packages/73/f4/04905af42837292ed86cb1b1dabe03dce1edc008ef14c473c5c7e1443c5d/pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12", size = 5278520, upload-time = "2025-07-01T09:15:17.429Z" }, - { url = "https://files.pythonhosted.org/packages/41/b0/33d79e377a336247df6348a54e6d2a2b85d644ca202555e3faa0cf811ecc/pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a", size = 4686116, upload-time = "2025-07-01T09:15:19.423Z" }, - { url = "https://files.pythonhosted.org/packages/49/2d/ed8bc0ab219ae8768f529597d9509d184fe8a6c4741a6864fea334d25f3f/pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632", size = 5864597, upload-time = "2025-07-03T13:10:38.404Z" }, - { url = "https://files.pythonhosted.org/packages/b5/3d/b932bb4225c80b58dfadaca9d42d08d0b7064d2d1791b6a237f87f661834/pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673", size = 7638246, upload-time = "2025-07-03T13:10:44.987Z" }, - { url = "https://files.pythonhosted.org/packages/09/b5/0487044b7c096f1b48f0d7ad416472c02e0e4bf6919541b111efd3cae690/pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027", size = 5973336, upload-time = "2025-07-01T09:15:21.237Z" }, - { url = "https://files.pythonhosted.org/packages/a8/2d/524f9318f6cbfcc79fbc004801ea6b607ec3f843977652fdee4857a7568b/pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77", size = 6642699, upload-time = "2025-07-01T09:15:23.186Z" }, - { url = "https://files.pythonhosted.org/packages/6f/d2/a9a4f280c6aefedce1e8f615baaa5474e0701d86dd6f1dede66726462bbd/pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874", size = 6083789, upload-time = "2025-07-01T09:15:25.1Z" }, - { url = "https://files.pythonhosted.org/packages/fe/54/86b0cd9dbb683a9d5e960b66c7379e821a19be4ac5810e2e5a715c09a0c0/pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a", size = 6720386, upload-time = "2025-07-01T09:15:27.378Z" }, - { url = "https://files.pythonhosted.org/packages/e7/95/88efcaf384c3588e24259c4203b909cbe3e3c2d887af9e938c2022c9dd48/pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214", size = 6370911, upload-time = "2025-07-01T09:15:29.294Z" }, - { url = "https://files.pythonhosted.org/packages/2e/cc/934e5820850ec5eb107e7b1a72dd278140731c669f396110ebc326f2a503/pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635", size = 7117383, upload-time = "2025-07-01T09:15:31.128Z" }, - { url = "https://files.pythonhosted.org/packages/d6/e9/9c0a616a71da2a5d163aa37405e8aced9a906d574b4a214bede134e731bc/pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6", size = 2511385, upload-time = "2025-07-01T09:15:33.328Z" }, - { url = "https://files.pythonhosted.org/packages/1a/33/c88376898aff369658b225262cd4f2659b13e8178e7534df9e6e1fa289f6/pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae", size = 5281129, upload-time = "2025-07-01T09:15:35.194Z" }, - { url = "https://files.pythonhosted.org/packages/1f/70/d376247fb36f1844b42910911c83a02d5544ebd2a8bad9efcc0f707ea774/pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653", size = 4689580, upload-time = "2025-07-01T09:15:37.114Z" }, - { url = "https://files.pythonhosted.org/packages/eb/1c/537e930496149fbac69efd2fc4329035bbe2e5475b4165439e3be9cb183b/pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6", size = 5902860, upload-time = "2025-07-03T13:10:50.248Z" }, - { url = "https://files.pythonhosted.org/packages/bd/57/80f53264954dcefeebcf9dae6e3eb1daea1b488f0be8b8fef12f79a3eb10/pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36", size = 7670694, upload-time = "2025-07-03T13:10:56.432Z" }, - { url = "https://files.pythonhosted.org/packages/70/ff/4727d3b71a8578b4587d9c276e90efad2d6fe0335fd76742a6da08132e8c/pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b", size = 6005888, upload-time = "2025-07-01T09:15:39.436Z" }, - { url = "https://files.pythonhosted.org/packages/05/ae/716592277934f85d3be51d7256f3636672d7b1abfafdc42cf3f8cbd4b4c8/pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477", size = 6670330, upload-time = "2025-07-01T09:15:41.269Z" }, - { url = "https://files.pythonhosted.org/packages/e7/bb/7fe6cddcc8827b01b1a9766f5fdeb7418680744f9082035bdbabecf1d57f/pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50", size = 6114089, upload-time = "2025-07-01T09:15:43.13Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f5/06bfaa444c8e80f1a8e4bff98da9c83b37b5be3b1deaa43d27a0db37ef84/pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b", size = 6748206, upload-time = "2025-07-01T09:15:44.937Z" }, - { url = "https://files.pythonhosted.org/packages/f0/77/bc6f92a3e8e6e46c0ca78abfffec0037845800ea38c73483760362804c41/pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12", size = 6377370, upload-time = "2025-07-01T09:15:46.673Z" }, - { url = "https://files.pythonhosted.org/packages/4a/82/3a721f7d69dca802befb8af08b7c79ebcab461007ce1c18bd91a5d5896f9/pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db", size = 7121500, upload-time = "2025-07-01T09:15:48.512Z" }, - { url = "https://files.pythonhosted.org/packages/89/c7/5572fa4a3f45740eaab6ae86fcdf7195b55beac1371ac8c619d880cfe948/pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa", size = 2512835, upload-time = "2025-07-01T09:15:50.399Z" }, +version = "12.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/02/d52c733a2452ef1ffcc123b68e6606d07276b0e358db70eabad7e40042b7/pillow-12.1.0.tar.gz", hash = "sha256:5c5ae0a06e9ea030ab786b0251b32c7e4ce10e58d983c0d5c56029455180b5b9", size = 46977283, upload-time = "2026-01-02T09:13:29.892Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/31/dc53fe21a2f2996e1b7d92bf671cdb157079385183ef7c1ae08b485db510/pillow-12.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a332ac4ccb84b6dde65dbace8431f3af08874bf9770719d32a635c4ef411b18b", size = 5262642, upload-time = "2026-01-02T09:11:10.138Z" }, + { url = "https://files.pythonhosted.org/packages/ab/c1/10e45ac9cc79419cedf5121b42dcca5a50ad2b601fa080f58c22fb27626e/pillow-12.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:907bfa8a9cb790748a9aa4513e37c88c59660da3bcfffbd24a7d9e6abf224551", size = 4657464, upload-time = "2026-01-02T09:11:12.319Z" }, + { url = "https://files.pythonhosted.org/packages/ad/26/7b82c0ab7ef40ebede7a97c72d473bda5950f609f8e0c77b04af574a0ddb/pillow-12.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:efdc140e7b63b8f739d09a99033aa430accce485ff78e6d311973a67b6bf3208", size = 6234878, upload-time = "2026-01-02T09:11:14.096Z" }, + { url = "https://files.pythonhosted.org/packages/76/25/27abc9792615b5e886ca9411ba6637b675f1b77af3104710ac7353fe5605/pillow-12.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bef9768cab184e7ae6e559c032e95ba8d07b3023c289f79a2bd36e8bf85605a5", size = 8044868, upload-time = "2026-01-02T09:11:15.903Z" }, + { url = "https://files.pythonhosted.org/packages/0a/ea/f200a4c36d836100e7bc738fc48cd963d3ba6372ebc8298a889e0cfc3359/pillow-12.1.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:742aea052cf5ab5034a53c3846165bc3ce88d7c38e954120db0ab867ca242661", size = 6349468, upload-time = "2026-01-02T09:11:17.631Z" }, + { url = "https://files.pythonhosted.org/packages/11/8f/48d0b77ab2200374c66d344459b8958c86693be99526450e7aee714e03e4/pillow-12.1.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a6dfc2af5b082b635af6e08e0d1f9f1c4e04d17d4e2ca0ef96131e85eda6eb17", size = 7041518, upload-time = "2026-01-02T09:11:19.389Z" }, + { url = "https://files.pythonhosted.org/packages/1d/23/c281182eb986b5d31f0a76d2a2c8cd41722d6fb8ed07521e802f9bba52de/pillow-12.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:609e89d9f90b581c8d16358c9087df76024cf058fa693dd3e1e1620823f39670", size = 6462829, upload-time = "2026-01-02T09:11:21.28Z" }, + { url = "https://files.pythonhosted.org/packages/25/ef/7018273e0faac099d7b00982abdcc39142ae6f3bd9ceb06de09779c4a9d6/pillow-12.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:43b4899cfd091a9693a1278c4982f3e50f7fb7cff5153b05174b4afc9593b616", size = 7166756, upload-time = "2026-01-02T09:11:23.559Z" }, + { url = "https://files.pythonhosted.org/packages/8f/c8/993d4b7ab2e341fe02ceef9576afcf5830cdec640be2ac5bee1820d693d4/pillow-12.1.0-cp312-cp312-win32.whl", hash = "sha256:aa0c9cc0b82b14766a99fbe6084409972266e82f459821cd26997a488a7261a7", size = 6328770, upload-time = "2026-01-02T09:11:25.661Z" }, + { url = "https://files.pythonhosted.org/packages/a7/87/90b358775a3f02765d87655237229ba64a997b87efa8ccaca7dd3e36e7a7/pillow-12.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:d70534cea9e7966169ad29a903b99fc507e932069a881d0965a1a84bb57f6c6d", size = 7033406, upload-time = "2026-01-02T09:11:27.474Z" }, + { url = "https://files.pythonhosted.org/packages/5d/cf/881b457eccacac9e5b2ddd97d5071fb6d668307c57cbf4e3b5278e06e536/pillow-12.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:65b80c1ee7e14a87d6a068dd3b0aea268ffcabfe0498d38661b00c5b4b22e74c", size = 2452612, upload-time = "2026-01-02T09:11:29.309Z" }, + { url = "https://files.pythonhosted.org/packages/dd/c7/2530a4aa28248623e9d7f27316b42e27c32ec410f695929696f2e0e4a778/pillow-12.1.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:7b5dd7cbae20285cdb597b10eb5a2c13aa9de6cde9bb64a3c1317427b1db1ae1", size = 4062543, upload-time = "2026-01-02T09:11:31.566Z" }, + { url = "https://files.pythonhosted.org/packages/8f/1f/40b8eae823dc1519b87d53c30ed9ef085506b05281d313031755c1705f73/pillow-12.1.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:29a4cef9cb672363926f0470afc516dbf7305a14d8c54f7abbb5c199cd8f8179", size = 4138373, upload-time = "2026-01-02T09:11:33.367Z" }, + { url = "https://files.pythonhosted.org/packages/d4/77/6fa60634cf06e52139fd0e89e5bbf055e8166c691c42fb162818b7fda31d/pillow-12.1.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:681088909d7e8fa9e31b9799aaa59ba5234c58e5e4f1951b4c4d1082a2e980e0", size = 3601241, upload-time = "2026-01-02T09:11:35.011Z" }, + { url = "https://files.pythonhosted.org/packages/4f/bf/28ab865de622e14b747f0cd7877510848252d950e43002e224fb1c9ababf/pillow-12.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:983976c2ab753166dc66d36af6e8ec15bb511e4a25856e2227e5f7e00a160587", size = 5262410, upload-time = "2026-01-02T09:11:36.682Z" }, + { url = "https://files.pythonhosted.org/packages/1c/34/583420a1b55e715937a85bd48c5c0991598247a1fd2eb5423188e765ea02/pillow-12.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:db44d5c160a90df2d24a24760bbd37607d53da0b34fb546c4c232af7192298ac", size = 4657312, upload-time = "2026-01-02T09:11:38.535Z" }, + { url = "https://files.pythonhosted.org/packages/1d/fd/f5a0896839762885b3376ff04878f86ab2b097c2f9a9cdccf4eda8ba8dc0/pillow-12.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6b7a9d1db5dad90e2991645874f708e87d9a3c370c243c2d7684d28f7e133e6b", size = 6232605, upload-time = "2026-01-02T09:11:40.602Z" }, + { url = "https://files.pythonhosted.org/packages/98/aa/938a09d127ac1e70e6ed467bd03834350b33ef646b31edb7452d5de43792/pillow-12.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6258f3260986990ba2fa8a874f8b6e808cf5abb51a94015ca3dc3c68aa4f30ea", size = 8041617, upload-time = "2026-01-02T09:11:42.721Z" }, + { url = "https://files.pythonhosted.org/packages/17/e8/538b24cb426ac0186e03f80f78bc8dc7246c667f58b540bdd57c71c9f79d/pillow-12.1.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e115c15e3bc727b1ca3e641a909f77f8ca72a64fff150f666fcc85e57701c26c", size = 6346509, upload-time = "2026-01-02T09:11:44.955Z" }, + { url = "https://files.pythonhosted.org/packages/01/9a/632e58ec89a32738cabfd9ec418f0e9898a2b4719afc581f07c04a05e3c9/pillow-12.1.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6741e6f3074a35e47c77b23a4e4f2d90db3ed905cb1c5e6e0d49bff2045632bc", size = 7038117, upload-time = "2026-01-02T09:11:46.736Z" }, + { url = "https://files.pythonhosted.org/packages/c7/a2/d40308cf86eada842ca1f3ffa45d0ca0df7e4ab33c83f81e73f5eaed136d/pillow-12.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:935b9d1aed48fcfb3f838caac506f38e29621b44ccc4f8a64d575cb1b2a88644", size = 6460151, upload-time = "2026-01-02T09:11:48.625Z" }, + { url = "https://files.pythonhosted.org/packages/f1/88/f5b058ad6453a085c5266660a1417bdad590199da1b32fb4efcff9d33b05/pillow-12.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5fee4c04aad8932da9f8f710af2c1a15a83582cfb884152a9caa79d4efcdbf9c", size = 7164534, upload-time = "2026-01-02T09:11:50.445Z" }, + { url = "https://files.pythonhosted.org/packages/19/ce/c17334caea1db789163b5d855a5735e47995b0b5dc8745e9a3605d5f24c0/pillow-12.1.0-cp313-cp313-win32.whl", hash = "sha256:a786bf667724d84aa29b5db1c61b7bfdde380202aaca12c3461afd6b71743171", size = 6332551, upload-time = "2026-01-02T09:11:52.234Z" }, + { url = "https://files.pythonhosted.org/packages/e5/07/74a9d941fa45c90a0d9465098fe1ec85de3e2afbdc15cc4766622d516056/pillow-12.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:461f9dfdafa394c59cd6d818bdfdbab4028b83b02caadaff0ffd433faf4c9a7a", size = 7040087, upload-time = "2026-01-02T09:11:54.822Z" }, + { url = "https://files.pythonhosted.org/packages/88/09/c99950c075a0e9053d8e880595926302575bc742b1b47fe1bbcc8d388d50/pillow-12.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:9212d6b86917a2300669511ed094a9406888362e085f2431a7da985a6b124f45", size = 2452470, upload-time = "2026-01-02T09:11:56.522Z" }, + { url = "https://files.pythonhosted.org/packages/b5/ba/970b7d85ba01f348dee4d65412476321d40ee04dcb51cd3735b9dc94eb58/pillow-12.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:00162e9ca6d22b7c3ee8e61faa3c3253cd19b6a37f126cad04f2f88b306f557d", size = 5264816, upload-time = "2026-01-02T09:11:58.227Z" }, + { url = "https://files.pythonhosted.org/packages/10/60/650f2fb55fdba7a510d836202aa52f0baac633e50ab1cf18415d332188fb/pillow-12.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7d6daa89a00b58c37cb1747ec9fb7ac3bc5ffd5949f5888657dfddde6d1312e0", size = 4660472, upload-time = "2026-01-02T09:12:00.798Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/5273a99478956a099d533c4f46cbaa19fd69d606624f4334b85e50987a08/pillow-12.1.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e2479c7f02f9d505682dc47df8c0ea1fc5e264c4d1629a5d63fe3e2334b89554", size = 6268974, upload-time = "2026-01-02T09:12:02.572Z" }, + { url = "https://files.pythonhosted.org/packages/b4/26/0bf714bc2e73d5267887d47931d53c4ceeceea6978148ed2ab2a4e6463c4/pillow-12.1.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f188d580bd870cda1e15183790d1cc2fa78f666e76077d103edf048eed9c356e", size = 8073070, upload-time = "2026-01-02T09:12:04.75Z" }, + { url = "https://files.pythonhosted.org/packages/43/cf/1ea826200de111a9d65724c54f927f3111dc5ae297f294b370a670c17786/pillow-12.1.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0fde7ec5538ab5095cc02df38ee99b0443ff0e1c847a045554cf5f9af1f4aa82", size = 6380176, upload-time = "2026-01-02T09:12:06.626Z" }, + { url = "https://files.pythonhosted.org/packages/03/e0/7938dd2b2013373fd85d96e0f38d62b7a5a262af21ac274250c7ca7847c9/pillow-12.1.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0ed07dca4a8464bada6139ab38f5382f83e5f111698caf3191cb8dbf27d908b4", size = 7067061, upload-time = "2026-01-02T09:12:08.624Z" }, + { url = "https://files.pythonhosted.org/packages/86/ad/a2aa97d37272a929a98437a8c0ac37b3cf012f4f8721e1bd5154699b2518/pillow-12.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f45bd71d1fa5e5749587613037b172e0b3b23159d1c00ef2fc920da6f470e6f0", size = 6491824, upload-time = "2026-01-02T09:12:10.488Z" }, + { url = "https://files.pythonhosted.org/packages/a4/44/80e46611b288d51b115826f136fb3465653c28f491068a72d3da49b54cd4/pillow-12.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:277518bf4fe74aa91489e1b20577473b19ee70fb97c374aa50830b279f25841b", size = 7190911, upload-time = "2026-01-02T09:12:12.772Z" }, + { url = "https://files.pythonhosted.org/packages/86/77/eacc62356b4cf81abe99ff9dbc7402750044aed02cfd6a503f7c6fc11f3e/pillow-12.1.0-cp313-cp313t-win32.whl", hash = "sha256:7315f9137087c4e0ee73a761b163fc9aa3b19f5f606a7fc08d83fd3e4379af65", size = 6336445, upload-time = "2026-01-02T09:12:14.775Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3c/57d81d0b74d218706dafccb87a87ea44262c43eef98eb3b164fd000e0491/pillow-12.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:0ddedfaa8b5f0b4ffbc2fa87b556dc59f6bb4ecb14a53b33f9189713ae8053c0", size = 7045354, upload-time = "2026-01-02T09:12:16.599Z" }, + { url = "https://files.pythonhosted.org/packages/ac/82/8b9b97bba2e3576a340f93b044a3a3a09841170ab4c1eb0d5c93469fd32f/pillow-12.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:80941e6d573197a0c28f394753de529bb436b1ca990ed6e765cf42426abc39f8", size = 2454547, upload-time = "2026-01-02T09:12:18.704Z" }, + { url = "https://files.pythonhosted.org/packages/8c/87/bdf971d8bbcf80a348cc3bacfcb239f5882100fe80534b0ce67a784181d8/pillow-12.1.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:5cb7bc1966d031aec37ddb9dcf15c2da5b2e9f7cc3ca7c54473a20a927e1eb91", size = 4062533, upload-time = "2026-01-02T09:12:20.791Z" }, + { url = "https://files.pythonhosted.org/packages/ff/4f/5eb37a681c68d605eb7034c004875c81f86ec9ef51f5be4a63eadd58859a/pillow-12.1.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:97e9993d5ed946aba26baf9c1e8cf18adbab584b99f452ee72f7ee8acb882796", size = 4138546, upload-time = "2026-01-02T09:12:23.664Z" }, + { url = "https://files.pythonhosted.org/packages/11/6d/19a95acb2edbace40dcd582d077b991646b7083c41b98da4ed7555b59733/pillow-12.1.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:414b9a78e14ffeb98128863314e62c3f24b8a86081066625700b7985b3f529bd", size = 3601163, upload-time = "2026-01-02T09:12:26.338Z" }, + { url = "https://files.pythonhosted.org/packages/fc/36/2b8138e51cb42e4cc39c3297713455548be855a50558c3ac2beebdc251dd/pillow-12.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e6bdb408f7c9dd2a5ff2b14a3b0bb6d4deb29fb9961e6eb3ae2031ae9a5cec13", size = 5266086, upload-time = "2026-01-02T09:12:28.782Z" }, + { url = "https://files.pythonhosted.org/packages/53/4b/649056e4d22e1caa90816bf99cef0884aed607ed38075bd75f091a607a38/pillow-12.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3413c2ae377550f5487991d444428f1a8ae92784aac79caa8b1e3b89b175f77e", size = 4657344, upload-time = "2026-01-02T09:12:31.117Z" }, + { url = "https://files.pythonhosted.org/packages/6c/6b/c5742cea0f1ade0cd61485dc3d81f05261fc2276f537fbdc00802de56779/pillow-12.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e5dcbe95016e88437ecf33544ba5db21ef1b8dd6e1b434a2cb2a3d605299e643", size = 6232114, upload-time = "2026-01-02T09:12:32.936Z" }, + { url = "https://files.pythonhosted.org/packages/bf/8f/9f521268ce22d63991601aafd3d48d5ff7280a246a1ef62d626d67b44064/pillow-12.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d0a7735df32ccbcc98b98a1ac785cc4b19b580be1bdf0aeb5c03223220ea09d5", size = 8042708, upload-time = "2026-01-02T09:12:34.78Z" }, + { url = "https://files.pythonhosted.org/packages/1a/eb/257f38542893f021502a1bbe0c2e883c90b5cff26cc33b1584a841a06d30/pillow-12.1.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c27407a2d1b96774cbc4a7594129cc027339fd800cd081e44497722ea1179de", size = 6347762, upload-time = "2026-01-02T09:12:36.748Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5a/8ba375025701c09b309e8d5163c5a4ce0102fa86bbf8800eb0d7ac87bc51/pillow-12.1.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15c794d74303828eaa957ff8070846d0efe8c630901a1c753fdc63850e19ecd9", size = 7039265, upload-time = "2026-01-02T09:12:39.082Z" }, + { url = "https://files.pythonhosted.org/packages/cf/dc/cf5e4cdb3db533f539e88a7bbf9f190c64ab8a08a9bc7a4ccf55067872e4/pillow-12.1.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c990547452ee2800d8506c4150280757f88532f3de2a58e3022e9b179107862a", size = 6462341, upload-time = "2026-01-02T09:12:40.946Z" }, + { url = "https://files.pythonhosted.org/packages/d0/47/0291a25ac9550677e22eda48510cfc4fa4b2ef0396448b7fbdc0a6946309/pillow-12.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b63e13dd27da389ed9475b3d28510f0f954bca0041e8e551b2a4eb1eab56a39a", size = 7165395, upload-time = "2026-01-02T09:12:42.706Z" }, + { url = "https://files.pythonhosted.org/packages/4f/4c/e005a59393ec4d9416be06e6b45820403bb946a778e39ecec62f5b2b991e/pillow-12.1.0-cp314-cp314-win32.whl", hash = "sha256:1a949604f73eb07a8adab38c4fe50791f9919344398bdc8ac6b307f755fc7030", size = 6431413, upload-time = "2026-01-02T09:12:44.944Z" }, + { url = "https://files.pythonhosted.org/packages/1c/af/f23697f587ac5f9095d67e31b81c95c0249cd461a9798a061ed6709b09b5/pillow-12.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:4f9f6a650743f0ddee5593ac9e954ba1bdbc5e150bc066586d4f26127853ab94", size = 7176779, upload-time = "2026-01-02T09:12:46.727Z" }, + { url = "https://files.pythonhosted.org/packages/b3/36/6a51abf8599232f3e9afbd16d52829376a68909fe14efe29084445db4b73/pillow-12.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:808b99604f7873c800c4840f55ff389936ef1948e4e87645eaf3fccbc8477ac4", size = 2543105, upload-time = "2026-01-02T09:12:49.243Z" }, + { url = "https://files.pythonhosted.org/packages/82/54/2e1dd20c8749ff225080d6ba465a0cab4387f5db0d1c5fb1439e2d99923f/pillow-12.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bc11908616c8a283cf7d664f77411a5ed2a02009b0097ff8abbba5e79128ccf2", size = 5268571, upload-time = "2026-01-02T09:12:51.11Z" }, + { url = "https://files.pythonhosted.org/packages/57/61/571163a5ef86ec0cf30d265ac2a70ae6fc9e28413d1dc94fa37fae6bda89/pillow-12.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:896866d2d436563fa2a43a9d72f417874f16b5545955c54a64941e87c1376c61", size = 4660426, upload-time = "2026-01-02T09:12:52.865Z" }, + { url = "https://files.pythonhosted.org/packages/5e/e1/53ee5163f794aef1bf84243f755ee6897a92c708505350dd1923f4afec48/pillow-12.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8e178e3e99d3c0ea8fc64b88447f7cac8ccf058af422a6cedc690d0eadd98c51", size = 6269908, upload-time = "2026-01-02T09:12:54.884Z" }, + { url = "https://files.pythonhosted.org/packages/bc/0b/b4b4106ff0ee1afa1dc599fde6ab230417f800279745124f6c50bcffed8e/pillow-12.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:079af2fb0c599c2ec144ba2c02766d1b55498e373b3ac64687e43849fbbef5bc", size = 8074733, upload-time = "2026-01-02T09:12:56.802Z" }, + { url = "https://files.pythonhosted.org/packages/19/9f/80b411cbac4a732439e629a26ad3ef11907a8c7fc5377b7602f04f6fe4e7/pillow-12.1.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bdec5e43377761c5dbca620efb69a77f6855c5a379e32ac5b158f54c84212b14", size = 6381431, upload-time = "2026-01-02T09:12:58.823Z" }, + { url = "https://files.pythonhosted.org/packages/8f/b7/d65c45db463b66ecb6abc17c6ba6917a911202a07662247e1355ce1789e7/pillow-12.1.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:565c986f4b45c020f5421a4cea13ef294dde9509a8577f29b2fc5edc7587fff8", size = 7068529, upload-time = "2026-01-02T09:13:00.885Z" }, + { url = "https://files.pythonhosted.org/packages/50/96/dfd4cd726b4a45ae6e3c669fc9e49deb2241312605d33aba50499e9d9bd1/pillow-12.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:43aca0a55ce1eefc0aefa6253661cb54571857b1a7b2964bd8a1e3ef4b729924", size = 6492981, upload-time = "2026-01-02T09:13:03.314Z" }, + { url = "https://files.pythonhosted.org/packages/4d/1c/b5dc52cf713ae46033359c5ca920444f18a6359ce1020dd3e9c553ea5bc6/pillow-12.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0deedf2ea233722476b3a81e8cdfbad786f7adbed5d848469fa59fe52396e4ef", size = 7191878, upload-time = "2026-01-02T09:13:05.276Z" }, + { url = "https://files.pythonhosted.org/packages/53/26/c4188248bd5edaf543864fe4834aebe9c9cb4968b6f573ce014cc42d0720/pillow-12.1.0-cp314-cp314t-win32.whl", hash = "sha256:b17fbdbe01c196e7e159aacb889e091f28e61020a8abeac07b68079b6e626988", size = 6438703, upload-time = "2026-01-02T09:13:07.491Z" }, + { url = "https://files.pythonhosted.org/packages/b8/0e/69ed296de8ea05cb03ee139cee600f424ca166e632567b2d66727f08c7ed/pillow-12.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27b9baecb428899db6c0de572d6d305cfaf38ca1596b5c0542a5182e3e74e8c6", size = 7182927, upload-time = "2026-01-02T09:13:09.841Z" }, + { url = "https://files.pythonhosted.org/packages/fc/f5/68334c015eed9b5cff77814258717dec591ded209ab5b6fb70e2ae873d1d/pillow-12.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:f61333d817698bdcdd0f9d7793e365ac3d2a21c1f1eb02b32ad6aefb8d8ea831", size = 2545104, upload-time = "2026-01-02T09:13:12.068Z" }, ] [[package]] @@ -898,11 +1173,11 @@ wheels = [ [[package]] name = "platformdirs" -version = "4.3.8" +version = "4.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/8b/3c73abc9c759ecd3f1f7ceff6685840859e8070c4d947c93fae71f6a0bf2/platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc", size = 21362, upload-time = "2025-05-07T22:47:42.121Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/39/979e8e21520d4e47a0bbe349e2713c0aac6f3d853d0e5b34d76206c439aa/platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4", size = 18567, upload-time = "2025-05-07T22:47:40.376Z" }, + { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, ] [[package]] @@ -925,7 +1200,7 @@ wheels = [ [[package]] name = "pre-commit" -version = "4.2.0" +version = "4.5.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cfgv" }, @@ -934,9 +1209,9 @@ dependencies = [ { name = "pyyaml" }, { name = "virtualenv" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/08/39/679ca9b26c7bb2999ff122d50faa301e49af82ca9c066ec061cfbc0c6784/pre_commit-4.2.0.tar.gz", hash = "sha256:601283b9757afd87d40c4c4a9b2b5de9637a8ea02eaff7adc2d0fb4e04841146", size = 193424, upload-time = "2025-03-18T21:35:20.987Z" } +sdist = { url = "https://files.pythonhosted.org/packages/40/f1/6d86a29246dfd2e9b6237f0b5823717f60cad94d47ddc26afa916d21f525/pre_commit-4.5.1.tar.gz", hash = "sha256:eb545fcff725875197837263e977ea257a402056661f09dae08e4b149b030a61", size = 198232, upload-time = "2025-12-16T21:14:33.552Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/74/a88bf1b1efeae488a0c0b7bdf71429c313722d1fc0f377537fbe554e6180/pre_commit-4.2.0-py2.py3-none-any.whl", hash = "sha256:a009ca7205f1eb497d10b845e52c838a98b6cdd2102a6c8e4540e94ee75c58bd", size = 220707, upload-time = "2025-03-18T21:35:19.343Z" }, + { url = "https://files.pythonhosted.org/packages/5d/19/fd3ef348460c80af7bb4669ea7926651d1f95c23ff2df18b9d24bab4f3fa/pre_commit-4.5.1-py2.py3-none-any.whl", hash = "sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77", size = 226437, upload-time = "2025-12-16T21:14:32.409Z" }, ] [[package]] @@ -1023,16 +1298,16 @@ wheels = [ [[package]] name = "pyparsing" -version = "3.2.3" +version = "3.3.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bb/22/f1129e69d94ffff626bdb5c835506b3a5b4f3d070f17ea295e12c2c6f60f/pyparsing-3.2.3.tar.gz", hash = "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be", size = 1088608, upload-time = "2025-03-25T05:01:28.114Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/05/e7/df2285f3d08fee213f2d041540fa4fc9ca6c2d44cf36d3a035bf2a8d2bcc/pyparsing-3.2.3-py3-none-any.whl", hash = "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf", size = 111120, upload-time = "2025-03-25T05:01:24.908Z" }, + { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, ] [[package]] name = "pytest" -version = "8.4.1" +version = "9.0.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, @@ -1041,23 +1316,23 @@ dependencies = [ { name = "pluggy" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/08/ba/45911d754e8eba3d5a841a5ce61a65a685ff1798421ac054f85aa8747dfb/pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c", size = 1517714, upload-time = "2025-06-18T05:48:06.109Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/29/16/c8a903f4c4dffe7a12843191437d7cd8e32751d5de349d45d3fe69544e87/pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7", size = 365474, upload-time = "2025-06-18T05:48:03.955Z" }, + { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" }, ] [[package]] name = "pytest-cov" -version = "6.2.1" +version = "7.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "coverage" }, { name = "pluggy" }, { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/18/99/668cade231f434aaa59bbfbf49469068d2ddd945000621d3d165d2e7dd7b/pytest_cov-6.2.1.tar.gz", hash = "sha256:25cc6cc0a5358204b8108ecedc51a9b57b34cc6b8c967cc2c01a4e00d8a67da2", size = 69432, upload-time = "2025-06-12T10:47:47.684Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/16/4ea354101abb1287856baa4af2732be351c7bee728065aed451b678153fd/pytest_cov-6.2.1-py3-none-any.whl", hash = "sha256:f5bc4c23f42f1cdd23c70b1dab1bbaef4fc505ba950d53e0081d0730dd7e86d5", size = 24644, upload-time = "2025-06-12T10:47:45.932Z" }, + { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" }, ] [[package]] @@ -1072,44 +1347,55 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, ] -[[package]] -name = "pytz" -version = "2025.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, -] - [[package]] name = "pyyaml" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, - { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, - { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, - { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, - { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, - { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, - { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, - { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, - { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, - { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, - { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, - { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, - { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, - { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, - { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, - { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, ] [[package]] name = "requests" -version = "2.32.4" +version = "2.32.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, @@ -1117,9 +1403,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, ] [[package]] @@ -1136,37 +1422,38 @@ wheels = [ ] [[package]] -name = "roman-numerals-py" -version = "3.1.0" +name = "roman-numerals" +version = "4.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/76/48fd56d17c5bdbdf65609abbc67288728a98ed4c02919428d4f52d23b24b/roman_numerals_py-3.1.0.tar.gz", hash = "sha256:be4bf804f083a4ce001b5eb7e3c0862479d10f94c936f6c4e5f250aa5ff5bd2d", size = 9017, upload-time = "2025-02-22T07:34:54.333Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/f9/41dc953bbeb056c17d5f7a519f50fdf010bd0553be2d630bc69d1e022703/roman_numerals-4.1.0.tar.gz", hash = "sha256:1af8b147eb1405d5839e78aeb93131690495fe9da5c91856cb33ad55a7f1e5b2", size = 9077, upload-time = "2025-12-17T18:25:34.381Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/53/97/d2cbbaa10c9b826af0e10fdf836e1bf344d9f0abb873ebc34d1f49642d3f/roman_numerals_py-3.1.0-py3-none-any.whl", hash = "sha256:9da2ad2fb670bcf24e81070ceb3be72f6c11c440d73bd579fbeca1e9f330954c", size = 7742, upload-time = "2025-02-22T07:34:52.422Z" }, + { url = "https://files.pythonhosted.org/packages/04/54/6f679c435d28e0a568d8e8a7c0a93a09010818634c3c3907fc98d8983770/roman_numerals-4.1.0-py3-none-any.whl", hash = "sha256:647ba99caddc2cc1e55a51e4360689115551bf4476d90e8162cf8c345fe233c7", size = 7676, upload-time = "2025-12-17T18:25:33.098Z" }, ] [[package]] name = "ruff" -version = "0.12.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c3/2a/43955b530c49684d3c38fcda18c43caf91e99204c2a065552528e0552d4f/ruff-0.12.3.tar.gz", hash = "sha256:f1b5a4b6668fd7b7ea3697d8d98857390b40c1320a63a178eee6be0899ea2d77", size = 4459341, upload-time = "2025-07-11T13:21:16.086Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/fd/b44c5115539de0d598d75232a1cc7201430b6891808df111b8b0506aae43/ruff-0.12.3-py3-none-linux_armv6l.whl", hash = "sha256:47552138f7206454eaf0c4fe827e546e9ddac62c2a3d2585ca54d29a890137a2", size = 10430499, upload-time = "2025-07-11T13:20:26.321Z" }, - { url = "https://files.pythonhosted.org/packages/43/c5/9eba4f337970d7f639a37077be067e4ec80a2ad359e4cc6c5b56805cbc66/ruff-0.12.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:0a9153b000c6fe169bb307f5bd1b691221c4286c133407b8827c406a55282041", size = 11213413, upload-time = "2025-07-11T13:20:30.017Z" }, - { url = "https://files.pythonhosted.org/packages/e2/2c/fac3016236cf1fe0bdc8e5de4f24c76ce53c6dd9b5f350d902549b7719b2/ruff-0.12.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fa6b24600cf3b750e48ddb6057e901dd5b9aa426e316addb2a1af185a7509882", size = 10586941, upload-time = "2025-07-11T13:20:33.046Z" }, - { url = "https://files.pythonhosted.org/packages/c5/0f/41fec224e9dfa49a139f0b402ad6f5d53696ba1800e0f77b279d55210ca9/ruff-0.12.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2506961bf6ead54887ba3562604d69cb430f59b42133d36976421bc8bd45901", size = 10783001, upload-time = "2025-07-11T13:20:35.534Z" }, - { url = "https://files.pythonhosted.org/packages/0d/ca/dd64a9ce56d9ed6cad109606ac014860b1c217c883e93bf61536400ba107/ruff-0.12.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c4faaff1f90cea9d3033cbbcdf1acf5d7fb11d8180758feb31337391691f3df0", size = 10269641, upload-time = "2025-07-11T13:20:38.459Z" }, - { url = "https://files.pythonhosted.org/packages/63/5c/2be545034c6bd5ce5bb740ced3e7014d7916f4c445974be11d2a406d5088/ruff-0.12.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40dced4a79d7c264389de1c59467d5d5cefd79e7e06d1dfa2c75497b5269a5a6", size = 11875059, upload-time = "2025-07-11T13:20:41.517Z" }, - { url = "https://files.pythonhosted.org/packages/8e/d4/a74ef1e801ceb5855e9527dae105eaff136afcb9cc4d2056d44feb0e4792/ruff-0.12.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:0262d50ba2767ed0fe212aa7e62112a1dcbfd46b858c5bf7bbd11f326998bafc", size = 12658890, upload-time = "2025-07-11T13:20:44.442Z" }, - { url = "https://files.pythonhosted.org/packages/13/c8/1057916416de02e6d7c9bcd550868a49b72df94e3cca0aeb77457dcd9644/ruff-0.12.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12371aec33e1a3758597c5c631bae9a5286f3c963bdfb4d17acdd2d395406687", size = 12232008, upload-time = "2025-07-11T13:20:47.374Z" }, - { url = "https://files.pythonhosted.org/packages/f5/59/4f7c130cc25220392051fadfe15f63ed70001487eca21d1796db46cbcc04/ruff-0.12.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:560f13b6baa49785665276c963edc363f8ad4b4fc910a883e2625bdb14a83a9e", size = 11499096, upload-time = "2025-07-11T13:20:50.348Z" }, - { url = "https://files.pythonhosted.org/packages/d4/01/a0ad24a5d2ed6be03a312e30d32d4e3904bfdbc1cdbe63c47be9d0e82c79/ruff-0.12.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:023040a3499f6f974ae9091bcdd0385dd9e9eb4942f231c23c57708147b06311", size = 11688307, upload-time = "2025-07-11T13:20:52.945Z" }, - { url = "https://files.pythonhosted.org/packages/93/72/08f9e826085b1f57c9a0226e48acb27643ff19b61516a34c6cab9d6ff3fa/ruff-0.12.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:883d844967bffff5ab28bba1a4d246c1a1b2933f48cb9840f3fdc5111c603b07", size = 10661020, upload-time = "2025-07-11T13:20:55.799Z" }, - { url = "https://files.pythonhosted.org/packages/80/a0/68da1250d12893466c78e54b4a0ff381370a33d848804bb51279367fc688/ruff-0.12.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:2120d3aa855ff385e0e562fdee14d564c9675edbe41625c87eeab744a7830d12", size = 10246300, upload-time = "2025-07-11T13:20:58.222Z" }, - { url = "https://files.pythonhosted.org/packages/6a/22/5f0093d556403e04b6fd0984fc0fb32fbb6f6ce116828fd54306a946f444/ruff-0.12.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6b16647cbb470eaf4750d27dddc6ebf7758b918887b56d39e9c22cce2049082b", size = 11263119, upload-time = "2025-07-11T13:21:01.503Z" }, - { url = "https://files.pythonhosted.org/packages/92/c9/f4c0b69bdaffb9968ba40dd5fa7df354ae0c73d01f988601d8fac0c639b1/ruff-0.12.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e1417051edb436230023575b149e8ff843a324557fe0a265863b7602df86722f", size = 11746990, upload-time = "2025-07-11T13:21:04.524Z" }, - { url = "https://files.pythonhosted.org/packages/fe/84/7cc7bd73924ee6be4724be0db5414a4a2ed82d06b30827342315a1be9e9c/ruff-0.12.3-py3-none-win32.whl", hash = "sha256:dfd45e6e926deb6409d0616078a666ebce93e55e07f0fb0228d4b2608b2c248d", size = 10589263, upload-time = "2025-07-11T13:21:07.148Z" }, - { url = "https://files.pythonhosted.org/packages/07/87/c070f5f027bd81f3efee7d14cb4d84067ecf67a3a8efb43aadfc72aa79a6/ruff-0.12.3-py3-none-win_amd64.whl", hash = "sha256:a946cf1e7ba3209bdef039eb97647f1c77f6f540e5845ec9c114d3af8df873e7", size = 11695072, upload-time = "2025-07-11T13:21:11.004Z" }, - { url = "https://files.pythonhosted.org/packages/e0/30/f3eaf6563c637b6e66238ed6535f6775480db973c836336e4122161986fc/ruff-0.12.3-py3-none-win_arm64.whl", hash = "sha256:5f9c7c9c8f84c2d7f27e93674d27136fbf489720251544c4da7fb3d742e011b1", size = 10805855, upload-time = "2025-07-11T13:21:13.547Z" }, +version = "0.14.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/06/f71e3a86b2df0dfa2d2f72195941cd09b44f87711cb7fa5193732cb9a5fc/ruff-0.14.14.tar.gz", hash = "sha256:2d0f819c9a90205f3a867dbbd0be083bee9912e170fd7d9704cc8ae45824896b", size = 4515732, upload-time = "2026-01-22T22:30:17.527Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/89/20a12e97bc6b9f9f68343952da08a8099c57237aef953a56b82711d55edd/ruff-0.14.14-py3-none-linux_armv6l.whl", hash = "sha256:7cfe36b56e8489dee8fbc777c61959f60ec0f1f11817e8f2415f429552846aed", size = 10467650, upload-time = "2026-01-22T22:30:08.578Z" }, + { url = "https://files.pythonhosted.org/packages/a3/b1/c5de3fd2d5a831fcae21beda5e3589c0ba67eec8202e992388e4b17a6040/ruff-0.14.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6006a0082336e7920b9573ef8a7f52eec837add1265cc74e04ea8a4368cd704c", size = 10883245, upload-time = "2026-01-22T22:30:04.155Z" }, + { url = "https://files.pythonhosted.org/packages/b8/7c/3c1db59a10e7490f8f6f8559d1db8636cbb13dccebf18686f4e3c9d7c772/ruff-0.14.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:026c1d25996818f0bf498636686199d9bd0d9d6341c9c2c3b62e2a0198b758de", size = 10231273, upload-time = "2026-01-22T22:30:34.642Z" }, + { url = "https://files.pythonhosted.org/packages/a1/6e/5e0e0d9674be0f8581d1f5e0f0a04761203affce3232c1a1189d0e3b4dad/ruff-0.14.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f666445819d31210b71e0a6d1c01e24447a20b85458eea25a25fe8142210ae0e", size = 10585753, upload-time = "2026-01-22T22:30:31.781Z" }, + { url = "https://files.pythonhosted.org/packages/23/09/754ab09f46ff1884d422dc26d59ba18b4e5d355be147721bb2518aa2a014/ruff-0.14.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c0f18b922c6d2ff9a5e6c3ee16259adc513ca775bcf82c67ebab7cbd9da5bc8", size = 10286052, upload-time = "2026-01-22T22:30:24.827Z" }, + { url = "https://files.pythonhosted.org/packages/c8/cc/e71f88dd2a12afb5f50733851729d6b571a7c3a35bfdb16c3035132675a0/ruff-0.14.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1629e67489c2dea43e8658c3dba659edbfd87361624b4040d1df04c9740ae906", size = 11043637, upload-time = "2026-01-22T22:30:13.239Z" }, + { url = "https://files.pythonhosted.org/packages/67/b2/397245026352494497dac935d7f00f1468c03a23a0c5db6ad8fc49ca3fb2/ruff-0.14.14-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:27493a2131ea0f899057d49d303e4292b2cae2bb57253c1ed1f256fbcd1da480", size = 12194761, upload-time = "2026-01-22T22:30:22.542Z" }, + { url = "https://files.pythonhosted.org/packages/5b/06/06ef271459f778323112c51b7587ce85230785cd64e91772034ddb88f200/ruff-0.14.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ff589aab3f5b539e35db38425da31a57521efd1e4ad1ae08fc34dbe30bd7df", size = 12005701, upload-time = "2026-01-22T22:30:20.499Z" }, + { url = "https://files.pythonhosted.org/packages/41/d6/99364514541cf811ccc5ac44362f88df66373e9fec1b9d1c4cc830593fe7/ruff-0.14.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc12d74eef0f29f51775f5b755913eb523546b88e2d733e1d701fe65144e89b", size = 11282455, upload-time = "2026-01-22T22:29:59.679Z" }, + { url = "https://files.pythonhosted.org/packages/ca/71/37daa46f89475f8582b7762ecd2722492df26421714a33e72ccc9a84d7a5/ruff-0.14.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb8481604b7a9e75eff53772496201690ce2687067e038b3cc31aaf16aa0b974", size = 11215882, upload-time = "2026-01-22T22:29:57.032Z" }, + { url = "https://files.pythonhosted.org/packages/2c/10/a31f86169ec91c0705e618443ee74ede0bdd94da0a57b28e72db68b2dbac/ruff-0.14.14-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:14649acb1cf7b5d2d283ebd2f58d56b75836ed8c6f329664fa91cdea19e76e66", size = 11180549, upload-time = "2026-01-22T22:30:27.175Z" }, + { url = "https://files.pythonhosted.org/packages/fd/1e/c723f20536b5163adf79bdd10c5f093414293cdf567eed9bdb7b83940f3f/ruff-0.14.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8058d2145566510790eab4e2fad186002e288dec5e0d343a92fe7b0bc1b3e13", size = 10543416, upload-time = "2026-01-22T22:30:01.964Z" }, + { url = "https://files.pythonhosted.org/packages/3e/34/8a84cea7e42c2d94ba5bde1d7a4fae164d6318f13f933d92da6d7c2041ff/ruff-0.14.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e651e977a79e4c758eb807f0481d673a67ffe53cfa92209781dfa3a996cf8412", size = 10285491, upload-time = "2026-01-22T22:30:29.51Z" }, + { url = "https://files.pythonhosted.org/packages/55/ef/b7c5ea0be82518906c978e365e56a77f8de7678c8bb6651ccfbdc178c29f/ruff-0.14.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cc8b22da8d9d6fdd844a68ae937e2a0adf9b16514e9a97cc60355e2d4b219fc3", size = 10733525, upload-time = "2026-01-22T22:30:06.499Z" }, + { url = "https://files.pythonhosted.org/packages/6a/5b/aaf1dfbcc53a2811f6cc0a1759de24e4b03e02ba8762daabd9b6bd8c59e3/ruff-0.14.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:16bc890fb4cc9781bb05beb5ab4cd51be9e7cb376bf1dd3580512b24eb3fda2b", size = 11315626, upload-time = "2026-01-22T22:30:36.848Z" }, + { url = "https://files.pythonhosted.org/packages/2c/aa/9f89c719c467dfaf8ad799b9bae0df494513fb21d31a6059cb5870e57e74/ruff-0.14.14-py3-none-win32.whl", hash = "sha256:b530c191970b143375b6a68e6f743800b2b786bbcf03a7965b06c4bf04568167", size = 10502442, upload-time = "2026-01-22T22:30:38.93Z" }, + { url = "https://files.pythonhosted.org/packages/87/44/90fa543014c45560cae1fffc63ea059fb3575ee6e1cb654562197e5d16fb/ruff-0.14.14-py3-none-win_amd64.whl", hash = "sha256:3dde1435e6b6fe5b66506c1dff67a421d0b7f6488d466f651c07f4cab3bf20fd", size = 11630486, upload-time = "2026-01-22T22:30:10.852Z" }, + { url = "https://files.pythonhosted.org/packages/9e/6a/40fee331a52339926a92e17ae748827270b288a35ef4a15c9c8f2ec54715/ruff-0.14.14-py3-none-win_arm64.whl", hash = "sha256:56e6981a98b13a32236a72a8da421d7839221fa308b223b9283312312e5ac76c", size = 10920448, upload-time = "2026-01-22T22:30:15.417Z" }, ] [[package]] @@ -1187,63 +1474,63 @@ wheels = [ [[package]] name = "scipy" -version = "1.16.3" +version = "1.17.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0a/ca/d8ace4f98322d01abcd52d381134344bf7b431eba7ed8b42bdea5a3c2ac9/scipy-1.16.3.tar.gz", hash = "sha256:01e87659402762f43bd2fee13370553a17ada367d42e7487800bf2916535aecb", size = 30597883, upload-time = "2025-10-28T17:38:54.068Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/40/41/5bf55c3f386b1643812f3a5674edf74b26184378ef0f3e7c7a09a7e2ca7f/scipy-1.16.3-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:81fc5827606858cf71446a5e98715ba0e11f0dbc83d71c7409d05486592a45d6", size = 36659043, upload-time = "2025-10-28T17:32:40.285Z" }, - { url = "https://files.pythonhosted.org/packages/1e/0f/65582071948cfc45d43e9870bf7ca5f0e0684e165d7c9ef4e50d783073eb/scipy-1.16.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:c97176013d404c7346bf57874eaac5187d969293bf40497140b0a2b2b7482e07", size = 28898986, upload-time = "2025-10-28T17:32:45.325Z" }, - { url = "https://files.pythonhosted.org/packages/96/5e/36bf3f0ac298187d1ceadde9051177d6a4fe4d507e8f59067dc9dd39e650/scipy-1.16.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:2b71d93c8a9936046866acebc915e2af2e292b883ed6e2cbe5c34beb094b82d9", size = 20889814, upload-time = "2025-10-28T17:32:49.277Z" }, - { url = "https://files.pythonhosted.org/packages/80/35/178d9d0c35394d5d5211bbff7ac4f2986c5488b59506fef9e1de13ea28d3/scipy-1.16.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3d4a07a8e785d80289dfe66b7c27d8634a773020742ec7187b85ccc4b0e7b686", size = 23565795, upload-time = "2025-10-28T17:32:53.337Z" }, - { url = "https://files.pythonhosted.org/packages/fa/46/d1146ff536d034d02f83c8afc3c4bab2eddb634624d6529a8512f3afc9da/scipy-1.16.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0553371015692a898e1aa858fed67a3576c34edefa6b7ebdb4e9dde49ce5c203", size = 33349476, upload-time = "2025-10-28T17:32:58.353Z" }, - { url = "https://files.pythonhosted.org/packages/79/2e/415119c9ab3e62249e18c2b082c07aff907a273741b3f8160414b0e9193c/scipy-1.16.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:72d1717fd3b5e6ec747327ce9bda32d5463f472c9dce9f54499e81fbd50245a1", size = 35676692, upload-time = "2025-10-28T17:33:03.88Z" }, - { url = "https://files.pythonhosted.org/packages/27/82/df26e44da78bf8d2aeaf7566082260cfa15955a5a6e96e6a29935b64132f/scipy-1.16.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1fb2472e72e24d1530debe6ae078db70fb1605350c88a3d14bc401d6306dbffe", size = 36019345, upload-time = "2025-10-28T17:33:09.773Z" }, - { url = "https://files.pythonhosted.org/packages/82/31/006cbb4b648ba379a95c87262c2855cd0d09453e500937f78b30f02fa1cd/scipy-1.16.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c5192722cffe15f9329a3948c4b1db789fbb1f05c97899187dcf009b283aea70", size = 38678975, upload-time = "2025-10-28T17:33:15.809Z" }, - { url = "https://files.pythonhosted.org/packages/c2/7f/acbd28c97e990b421af7d6d6cd416358c9c293fc958b8529e0bd5d2a2a19/scipy-1.16.3-cp312-cp312-win_amd64.whl", hash = "sha256:56edc65510d1331dae01ef9b658d428e33ed48b4f77b1d51caf479a0253f96dc", size = 38555926, upload-time = "2025-10-28T17:33:21.388Z" }, - { url = "https://files.pythonhosted.org/packages/ce/69/c5c7807fd007dad4f48e0a5f2153038dc96e8725d3345b9ee31b2b7bed46/scipy-1.16.3-cp312-cp312-win_arm64.whl", hash = "sha256:a8a26c78ef223d3e30920ef759e25625a0ecdd0d60e5a8818b7513c3e5384cf2", size = 25463014, upload-time = "2025-10-28T17:33:25.975Z" }, - { url = "https://files.pythonhosted.org/packages/72/f1/57e8327ab1508272029e27eeef34f2302ffc156b69e7e233e906c2a5c379/scipy-1.16.3-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:d2ec56337675e61b312179a1ad124f5f570c00f920cc75e1000025451b88241c", size = 36617856, upload-time = "2025-10-28T17:33:31.375Z" }, - { url = "https://files.pythonhosted.org/packages/44/13/7e63cfba8a7452eb756306aa2fd9b37a29a323b672b964b4fdeded9a3f21/scipy-1.16.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:16b8bc35a4cc24db80a0ec836a9286d0e31b2503cb2fd7ff7fb0e0374a97081d", size = 28874306, upload-time = "2025-10-28T17:33:36.516Z" }, - { url = "https://files.pythonhosted.org/packages/15/65/3a9400efd0228a176e6ec3454b1fa998fbbb5a8defa1672c3f65706987db/scipy-1.16.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:5803c5fadd29de0cf27fa08ccbfe7a9e5d741bf63e4ab1085437266f12460ff9", size = 20865371, upload-time = "2025-10-28T17:33:42.094Z" }, - { url = "https://files.pythonhosted.org/packages/33/d7/eda09adf009a9fb81827194d4dd02d2e4bc752cef16737cc4ef065234031/scipy-1.16.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:b81c27fc41954319a943d43b20e07c40bdcd3ff7cf013f4fb86286faefe546c4", size = 23524877, upload-time = "2025-10-28T17:33:48.483Z" }, - { url = "https://files.pythonhosted.org/packages/7d/6b/3f911e1ebc364cb81320223a3422aab7d26c9c7973109a9cd0f27c64c6c0/scipy-1.16.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0c3b4dd3d9b08dbce0f3440032c52e9e2ab9f96ade2d3943313dfe51a7056959", size = 33342103, upload-time = "2025-10-28T17:33:56.495Z" }, - { url = "https://files.pythonhosted.org/packages/21/f6/4bfb5695d8941e5c570a04d9fcd0d36bce7511b7d78e6e75c8f9791f82d0/scipy-1.16.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7dc1360c06535ea6116a2220f760ae572db9f661aba2d88074fe30ec2aa1ff88", size = 35697297, upload-time = "2025-10-28T17:34:04.722Z" }, - { url = "https://files.pythonhosted.org/packages/04/e1/6496dadbc80d8d896ff72511ecfe2316b50313bfc3ebf07a3f580f08bd8c/scipy-1.16.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:663b8d66a8748051c3ee9c96465fb417509315b99c71550fda2591d7dd634234", size = 36021756, upload-time = "2025-10-28T17:34:13.482Z" }, - { url = "https://files.pythonhosted.org/packages/fe/bd/a8c7799e0136b987bda3e1b23d155bcb31aec68a4a472554df5f0937eef7/scipy-1.16.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eab43fae33a0c39006a88096cd7b4f4ef545ea0447d250d5ac18202d40b6611d", size = 38696566, upload-time = "2025-10-28T17:34:22.384Z" }, - { url = "https://files.pythonhosted.org/packages/cd/01/1204382461fcbfeb05b6161b594f4007e78b6eba9b375382f79153172b4d/scipy-1.16.3-cp313-cp313-win_amd64.whl", hash = "sha256:062246acacbe9f8210de8e751b16fc37458213f124bef161a5a02c7a39284304", size = 38529877, upload-time = "2025-10-28T17:35:51.076Z" }, - { url = "https://files.pythonhosted.org/packages/7f/14/9d9fbcaa1260a94f4bb5b64ba9213ceb5d03cd88841fe9fd1ffd47a45b73/scipy-1.16.3-cp313-cp313-win_arm64.whl", hash = "sha256:50a3dbf286dbc7d84f176f9a1574c705f277cb6565069f88f60db9eafdbe3ee2", size = 25455366, upload-time = "2025-10-28T17:35:59.014Z" }, - { url = "https://files.pythonhosted.org/packages/e2/a3/9ec205bd49f42d45d77f1730dbad9ccf146244c1647605cf834b3a8c4f36/scipy-1.16.3-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:fb4b29f4cf8cc5a8d628bc8d8e26d12d7278cd1f219f22698a378c3d67db5e4b", size = 37027931, upload-time = "2025-10-28T17:34:31.451Z" }, - { url = "https://files.pythonhosted.org/packages/25/06/ca9fd1f3a4589cbd825b1447e5db3a8ebb969c1eaf22c8579bd286f51b6d/scipy-1.16.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:8d09d72dc92742988b0e7750bddb8060b0c7079606c0d24a8cc8e9c9c11f9079", size = 29400081, upload-time = "2025-10-28T17:34:39.087Z" }, - { url = "https://files.pythonhosted.org/packages/6a/56/933e68210d92657d93fb0e381683bc0e53a965048d7358ff5fbf9e6a1b17/scipy-1.16.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:03192a35e661470197556de24e7cb1330d84b35b94ead65c46ad6f16f6b28f2a", size = 21391244, upload-time = "2025-10-28T17:34:45.234Z" }, - { url = "https://files.pythonhosted.org/packages/a8/7e/779845db03dc1418e215726329674b40576879b91814568757ff0014ad65/scipy-1.16.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:57d01cb6f85e34f0946b33caa66e892aae072b64b034183f3d87c4025802a119", size = 23929753, upload-time = "2025-10-28T17:34:51.793Z" }, - { url = "https://files.pythonhosted.org/packages/4c/4b/f756cf8161d5365dcdef9e5f460ab226c068211030a175d2fc7f3f41ca64/scipy-1.16.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:96491a6a54e995f00a28a3c3badfff58fd093bf26cd5fb34a2188c8c756a3a2c", size = 33496912, upload-time = "2025-10-28T17:34:59.8Z" }, - { url = "https://files.pythonhosted.org/packages/09/b5/222b1e49a58668f23839ca1542a6322bb095ab8d6590d4f71723869a6c2c/scipy-1.16.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cd13e354df9938598af2be05822c323e97132d5e6306b83a3b4ee6724c6e522e", size = 35802371, upload-time = "2025-10-28T17:35:08.173Z" }, - { url = "https://files.pythonhosted.org/packages/c1/8d/5964ef68bb31829bde27611f8c9deeac13764589fe74a75390242b64ca44/scipy-1.16.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:63d3cdacb8a824a295191a723ee5e4ea7768ca5ca5f2838532d9f2e2b3ce2135", size = 36190477, upload-time = "2025-10-28T17:35:16.7Z" }, - { url = "https://files.pythonhosted.org/packages/ab/f2/b31d75cb9b5fa4dd39a0a931ee9b33e7f6f36f23be5ef560bf72e0f92f32/scipy-1.16.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e7efa2681ea410b10dde31a52b18b0154d66f2485328830e45fdf183af5aefc6", size = 38796678, upload-time = "2025-10-28T17:35:26.354Z" }, - { url = "https://files.pythonhosted.org/packages/b4/1e/b3723d8ff64ab548c38d87055483714fefe6ee20e0189b62352b5e015bb1/scipy-1.16.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2d1ae2cf0c350e7705168ff2429962a89ad90c2d49d1dd300686d8b2a5af22fc", size = 38640178, upload-time = "2025-10-28T17:35:35.304Z" }, - { url = "https://files.pythonhosted.org/packages/8e/f3/d854ff38789aca9b0cc23008d607ced9de4f7ab14fa1ca4329f86b3758ca/scipy-1.16.3-cp313-cp313t-win_arm64.whl", hash = "sha256:0c623a54f7b79dd88ef56da19bc2873afec9673a48f3b85b18e4d402bdd29a5a", size = 25803246, upload-time = "2025-10-28T17:35:42.155Z" }, - { url = "https://files.pythonhosted.org/packages/99/f6/99b10fd70f2d864c1e29a28bbcaa0c6340f9d8518396542d9ea3b4aaae15/scipy-1.16.3-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:875555ce62743e1d54f06cdf22c1e0bc47b91130ac40fe5d783b6dfa114beeb6", size = 36606469, upload-time = "2025-10-28T17:36:08.741Z" }, - { url = "https://files.pythonhosted.org/packages/4d/74/043b54f2319f48ea940dd025779fa28ee360e6b95acb7cd188fad4391c6b/scipy-1.16.3-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:bb61878c18a470021fb515a843dc7a76961a8daceaaaa8bad1332f1bf4b54657", size = 28872043, upload-time = "2025-10-28T17:36:16.599Z" }, - { url = "https://files.pythonhosted.org/packages/4d/e1/24b7e50cc1c4ee6ffbcb1f27fe9f4c8b40e7911675f6d2d20955f41c6348/scipy-1.16.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:f2622206f5559784fa5c4b53a950c3c7c1cf3e84ca1b9c4b6c03f062f289ca26", size = 20862952, upload-time = "2025-10-28T17:36:22.966Z" }, - { url = "https://files.pythonhosted.org/packages/dd/3a/3e8c01a4d742b730df368e063787c6808597ccb38636ed821d10b39ca51b/scipy-1.16.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:7f68154688c515cdb541a31ef8eb66d8cd1050605be9dcd74199cbd22ac739bc", size = 23508512, upload-time = "2025-10-28T17:36:29.731Z" }, - { url = "https://files.pythonhosted.org/packages/1f/60/c45a12b98ad591536bfe5330cb3cfe1850d7570259303563b1721564d458/scipy-1.16.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3c820ddb80029fe9f43d61b81d8b488d3ef8ca010d15122b152db77dc94c22", size = 33413639, upload-time = "2025-10-28T17:36:37.982Z" }, - { url = "https://files.pythonhosted.org/packages/71/bc/35957d88645476307e4839712642896689df442f3e53b0fa016ecf8a3357/scipy-1.16.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d3837938ae715fc0fe3c39c0202de3a8853aff22ca66781ddc2ade7554b7e2cc", size = 35704729, upload-time = "2025-10-28T17:36:46.547Z" }, - { url = "https://files.pythonhosted.org/packages/3b/15/89105e659041b1ca11c386e9995aefacd513a78493656e57789f9d9eab61/scipy-1.16.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:aadd23f98f9cb069b3bd64ddc900c4d277778242e961751f77a8cb5c4b946fb0", size = 36086251, upload-time = "2025-10-28T17:36:55.161Z" }, - { url = "https://files.pythonhosted.org/packages/1a/87/c0ea673ac9c6cc50b3da2196d860273bc7389aa69b64efa8493bdd25b093/scipy-1.16.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b7c5f1bda1354d6a19bc6af73a649f8285ca63ac6b52e64e658a5a11d4d69800", size = 38716681, upload-time = "2025-10-28T17:37:04.1Z" }, - { url = "https://files.pythonhosted.org/packages/91/06/837893227b043fb9b0d13e4bd7586982d8136cb249ffb3492930dab905b8/scipy-1.16.3-cp314-cp314-win_amd64.whl", hash = "sha256:e5d42a9472e7579e473879a1990327830493a7047506d58d73fc429b84c1d49d", size = 39358423, upload-time = "2025-10-28T17:38:20.005Z" }, - { url = "https://files.pythonhosted.org/packages/95/03/28bce0355e4d34a7c034727505a02d19548549e190bedd13a721e35380b7/scipy-1.16.3-cp314-cp314-win_arm64.whl", hash = "sha256:6020470b9d00245926f2d5bb93b119ca0340f0d564eb6fbaad843eaebf9d690f", size = 26135027, upload-time = "2025-10-28T17:38:24.966Z" }, - { url = "https://files.pythonhosted.org/packages/b2/6f/69f1e2b682efe9de8fe9f91040f0cd32f13cfccba690512ba4c582b0bc29/scipy-1.16.3-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:e1d27cbcb4602680a49d787d90664fa4974063ac9d4134813332a8c53dbe667c", size = 37028379, upload-time = "2025-10-28T17:37:14.061Z" }, - { url = "https://files.pythonhosted.org/packages/7c/2d/e826f31624a5ebbab1cd93d30fd74349914753076ed0593e1d56a98c4fb4/scipy-1.16.3-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:9b9c9c07b6d56a35777a1b4cc8966118fb16cfd8daf6743867d17d36cfad2d40", size = 29400052, upload-time = "2025-10-28T17:37:21.709Z" }, - { url = "https://files.pythonhosted.org/packages/69/27/d24feb80155f41fd1f156bf144e7e049b4e2b9dd06261a242905e3bc7a03/scipy-1.16.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:3a4c460301fb2cffb7f88528f30b3127742cff583603aa7dc964a52c463b385d", size = 21391183, upload-time = "2025-10-28T17:37:29.559Z" }, - { url = "https://files.pythonhosted.org/packages/f8/d3/1b229e433074c5738a24277eca520a2319aac7465eea7310ea6ae0e98ae2/scipy-1.16.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:f667a4542cc8917af1db06366d3f78a5c8e83badd56409f94d1eac8d8d9133fa", size = 23930174, upload-time = "2025-10-28T17:37:36.306Z" }, - { url = "https://files.pythonhosted.org/packages/16/9d/d9e148b0ec680c0f042581a2be79a28a7ab66c0c4946697f9e7553ead337/scipy-1.16.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f379b54b77a597aa7ee5e697df0d66903e41b9c85a6dd7946159e356319158e8", size = 33497852, upload-time = "2025-10-28T17:37:42.228Z" }, - { url = "https://files.pythonhosted.org/packages/2f/22/4e5f7561e4f98b7bea63cf3fd7934bff1e3182e9f1626b089a679914d5c8/scipy-1.16.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4aff59800a3b7f786b70bfd6ab551001cb553244988d7d6b8299cb1ea653b353", size = 35798595, upload-time = "2025-10-28T17:37:48.102Z" }, - { url = "https://files.pythonhosted.org/packages/83/42/6644d714c179429fc7196857866f219fef25238319b650bb32dde7bf7a48/scipy-1.16.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:da7763f55885045036fabcebd80144b757d3db06ab0861415d1c3b7c69042146", size = 36186269, upload-time = "2025-10-28T17:37:53.72Z" }, - { url = "https://files.pythonhosted.org/packages/ac/70/64b4d7ca92f9cf2e6fc6aaa2eecf80bb9b6b985043a9583f32f8177ea122/scipy-1.16.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ffa6eea95283b2b8079b821dc11f50a17d0571c92b43e2b5b12764dc5f9b285d", size = 38802779, upload-time = "2025-10-28T17:37:59.393Z" }, - { url = "https://files.pythonhosted.org/packages/61/82/8d0e39f62764cce5ffd5284131e109f07cf8955aef9ab8ed4e3aa5e30539/scipy-1.16.3-cp314-cp314t-win_amd64.whl", hash = "sha256:d9f48cafc7ce94cf9b15c6bffdc443a81a27bf7075cf2dcd5c8b40f85d10c4e7", size = 39471128, upload-time = "2025-10-28T17:38:05.259Z" }, - { url = "https://files.pythonhosted.org/packages/64/47/a494741db7280eae6dc033510c319e34d42dd41b7ac0c7ead39354d1a2b5/scipy-1.16.3-cp314-cp314t-win_arm64.whl", hash = "sha256:21d9d6b197227a12dcbf9633320a4e34c6b0e51c57268df255a0942983bac562", size = 26464127, upload-time = "2025-10-28T17:38:11.34Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/56/3e/9cca699f3486ce6bc12ff46dc2031f1ec8eb9ccc9a320fdaf925f1417426/scipy-1.17.0.tar.gz", hash = "sha256:2591060c8e648d8b96439e111ac41fd8342fdeff1876be2e19dea3fe8930454e", size = 30396830, upload-time = "2026-01-10T21:34:23.009Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/11/7241a63e73ba5a516f1930ac8d5b44cbbfabd35ac73a2d08ca206df007c4/scipy-1.17.0-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:0d5018a57c24cb1dd828bcf51d7b10e65986d549f52ef5adb6b4d1ded3e32a57", size = 31364580, upload-time = "2026-01-10T21:25:25.717Z" }, + { url = "https://files.pythonhosted.org/packages/ed/1d/5057f812d4f6adc91a20a2d6f2ebcdb517fdbc87ae3acc5633c9b97c8ba5/scipy-1.17.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:88c22af9e5d5a4f9e027e26772cc7b5922fab8bcc839edb3ae33de404feebd9e", size = 27969012, upload-time = "2026-01-10T21:25:30.921Z" }, + { url = "https://files.pythonhosted.org/packages/e3/21/f6ec556c1e3b6ec4e088da667d9987bb77cc3ab3026511f427dc8451187d/scipy-1.17.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:f3cd947f20fe17013d401b64e857c6b2da83cae567adbb75b9dcba865abc66d8", size = 20140691, upload-time = "2026-01-10T21:25:34.802Z" }, + { url = "https://files.pythonhosted.org/packages/7a/fe/5e5ad04784964ba964a96f16c8d4676aa1b51357199014dce58ab7ec5670/scipy-1.17.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:e8c0b331c2c1f531eb51f1b4fc9ba709521a712cce58f1aa627bc007421a5306", size = 22463015, upload-time = "2026-01-10T21:25:39.277Z" }, + { url = "https://files.pythonhosted.org/packages/4a/69/7c347e857224fcaf32a34a05183b9d8a7aca25f8f2d10b8a698b8388561a/scipy-1.17.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5194c445d0a1c7a6c1a4a4681b6b7c71baad98ff66d96b949097e7513c9d6742", size = 32724197, upload-time = "2026-01-10T21:25:44.084Z" }, + { url = "https://files.pythonhosted.org/packages/d1/fe/66d73b76d378ba8cc2fe605920c0c75092e3a65ae746e1e767d9d020a75a/scipy-1.17.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9eeb9b5f5997f75507814ed9d298ab23f62cf79f5a3ef90031b1ee2506abdb5b", size = 35009148, upload-time = "2026-01-10T21:25:50.591Z" }, + { url = "https://files.pythonhosted.org/packages/af/07/07dec27d9dc41c18d8c43c69e9e413431d20c53a0339c388bcf72f353c4b/scipy-1.17.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:40052543f7bbe921df4408f46003d6f01c6af109b9e2c8a66dd1cf6cf57f7d5d", size = 34798766, upload-time = "2026-01-10T21:25:59.41Z" }, + { url = "https://files.pythonhosted.org/packages/81/61/0470810c8a093cdacd4ba7504b8a218fd49ca070d79eca23a615f5d9a0b0/scipy-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0cf46c8013fec9d3694dc572f0b54100c28405d55d3e2cb15e2895b25057996e", size = 37405953, upload-time = "2026-01-10T21:26:07.75Z" }, + { url = "https://files.pythonhosted.org/packages/92/ce/672ed546f96d5d41ae78c4b9b02006cedd0b3d6f2bf5bb76ea455c320c28/scipy-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:0937a0b0d8d593a198cededd4c439a0ea216a3f36653901ea1f3e4be949056f8", size = 36328121, upload-time = "2026-01-10T21:26:16.509Z" }, + { url = "https://files.pythonhosted.org/packages/9d/21/38165845392cae67b61843a52c6455d47d0cc2a40dd495c89f4362944654/scipy-1.17.0-cp312-cp312-win_arm64.whl", hash = "sha256:f603d8a5518c7426414d1d8f82e253e454471de682ce5e39c29adb0df1efb86b", size = 24314368, upload-time = "2026-01-10T21:26:23.087Z" }, + { url = "https://files.pythonhosted.org/packages/0c/51/3468fdfd49387ddefee1636f5cf6d03ce603b75205bf439bbf0e62069bfd/scipy-1.17.0-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:65ec32f3d32dfc48c72df4291345dae4f048749bc8d5203ee0a3f347f96c5ce6", size = 31344101, upload-time = "2026-01-10T21:26:30.25Z" }, + { url = "https://files.pythonhosted.org/packages/b2/9a/9406aec58268d437636069419e6977af953d1e246df941d42d3720b7277b/scipy-1.17.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:1f9586a58039d7229ce77b52f8472c972448cded5736eaf102d5658bbac4c269", size = 27950385, upload-time = "2026-01-10T21:26:36.801Z" }, + { url = "https://files.pythonhosted.org/packages/4f/98/e7342709e17afdfd1b26b56ae499ef4939b45a23a00e471dfb5375eea205/scipy-1.17.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:9fad7d3578c877d606b1150135c2639e9de9cecd3705caa37b66862977cc3e72", size = 20122115, upload-time = "2026-01-10T21:26:42.107Z" }, + { url = "https://files.pythonhosted.org/packages/fd/0e/9eeeb5357a64fd157cbe0302c213517c541cc16b8486d82de251f3c68ede/scipy-1.17.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:423ca1f6584fc03936972b5f7c06961670dbba9f234e71676a7c7ccf938a0d61", size = 22442402, upload-time = "2026-01-10T21:26:48.029Z" }, + { url = "https://files.pythonhosted.org/packages/c9/10/be13397a0e434f98e0c79552b2b584ae5bb1c8b2be95db421533bbca5369/scipy-1.17.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fe508b5690e9eaaa9467fc047f833af58f1152ae51a0d0aed67aa5801f4dd7d6", size = 32696338, upload-time = "2026-01-10T21:26:55.521Z" }, + { url = "https://files.pythonhosted.org/packages/63/1e/12fbf2a3bb240161651c94bb5cdd0eae5d4e8cc6eaeceb74ab07b12a753d/scipy-1.17.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6680f2dfd4f6182e7d6db161344537da644d1cf85cf293f015c60a17ecf08752", size = 34977201, upload-time = "2026-01-10T21:27:03.501Z" }, + { url = "https://files.pythonhosted.org/packages/19/5b/1a63923e23ccd20bd32156d7dd708af5bbde410daa993aa2500c847ab2d2/scipy-1.17.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eec3842ec9ac9de5917899b277428886042a93db0b227ebbe3a333b64ec7643d", size = 34777384, upload-time = "2026-01-10T21:27:11.423Z" }, + { url = "https://files.pythonhosted.org/packages/39/22/b5da95d74edcf81e540e467202a988c50fef41bd2011f46e05f72ba07df6/scipy-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d7425fcafbc09a03731e1bc05581f5fad988e48c6a861f441b7ab729a49a55ea", size = 37379586, upload-time = "2026-01-10T21:27:20.171Z" }, + { url = "https://files.pythonhosted.org/packages/b9/b6/8ac583d6da79e7b9e520579f03007cb006f063642afd6b2eeb16b890bf93/scipy-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:87b411e42b425b84777718cc41516b8a7e0795abfa8e8e1d573bf0ef014f0812", size = 36287211, upload-time = "2026-01-10T21:28:43.122Z" }, + { url = "https://files.pythonhosted.org/packages/55/fb/7db19e0b3e52f882b420417644ec81dd57eeef1bd1705b6f689d8ff93541/scipy-1.17.0-cp313-cp313-win_arm64.whl", hash = "sha256:357ca001c6e37601066092e7c89cca2f1ce74e2a520ca78d063a6d2201101df2", size = 24312646, upload-time = "2026-01-10T21:28:49.893Z" }, + { url = "https://files.pythonhosted.org/packages/20/b6/7feaa252c21cc7aff335c6c55e1b90ab3e3306da3f048109b8b639b94648/scipy-1.17.0-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:ec0827aa4d36cb79ff1b81de898e948a51ac0b9b1c43e4a372c0508c38c0f9a3", size = 31693194, upload-time = "2026-01-10T21:27:27.454Z" }, + { url = "https://files.pythonhosted.org/packages/76/bb/bbb392005abce039fb7e672cb78ac7d158700e826b0515cab6b5b60c26fb/scipy-1.17.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:819fc26862b4b3c73a60d486dbb919202f3d6d98c87cf20c223511429f2d1a97", size = 28365415, upload-time = "2026-01-10T21:27:34.26Z" }, + { url = "https://files.pythonhosted.org/packages/37/da/9d33196ecc99fba16a409c691ed464a3a283ac454a34a13a3a57c0d66f3a/scipy-1.17.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:363ad4ae2853d88ebcde3ae6ec46ccca903ea9835ee8ba543f12f575e7b07e4e", size = 20537232, upload-time = "2026-01-10T21:27:40.306Z" }, + { url = "https://files.pythonhosted.org/packages/56/9d/f4b184f6ddb28e9a5caea36a6f98e8ecd2a524f9127354087ce780885d83/scipy-1.17.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:979c3a0ff8e5ba254d45d59ebd38cde48fce4f10b5125c680c7a4bfe177aab07", size = 22791051, upload-time = "2026-01-10T21:27:46.539Z" }, + { url = "https://files.pythonhosted.org/packages/9b/9d/025cccdd738a72140efc582b1641d0dd4caf2e86c3fb127568dc80444e6e/scipy-1.17.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:130d12926ae34399d157de777472bf82e9061c60cc081372b3118edacafe1d00", size = 32815098, upload-time = "2026-01-10T21:27:54.389Z" }, + { url = "https://files.pythonhosted.org/packages/48/5f/09b879619f8bca15ce392bfc1894bd9c54377e01d1b3f2f3b595a1b4d945/scipy-1.17.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e886000eb4919eae3a44f035e63f0fd8b651234117e8f6f29bad1cd26e7bc45", size = 35031342, upload-time = "2026-01-10T21:28:03.012Z" }, + { url = "https://files.pythonhosted.org/packages/f2/9a/f0f0a9f0aa079d2f106555b984ff0fbb11a837df280f04f71f056ea9c6e4/scipy-1.17.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:13c4096ac6bc31d706018f06a49abe0485f96499deb82066b94d19b02f664209", size = 34893199, upload-time = "2026-01-10T21:28:10.832Z" }, + { url = "https://files.pythonhosted.org/packages/90/b8/4f0f5cf0c5ea4d7548424e6533e6b17d164f34a6e2fb2e43ffebb6697b06/scipy-1.17.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cacbaddd91fcffde703934897c5cd2c7cb0371fac195d383f4e1f1c5d3f3bd04", size = 37438061, upload-time = "2026-01-10T21:28:19.684Z" }, + { url = "https://files.pythonhosted.org/packages/f9/cc/2bd59140ed3b2fa2882fb15da0a9cb1b5a6443d67cfd0d98d4cec83a57ec/scipy-1.17.0-cp313-cp313t-win_amd64.whl", hash = "sha256:edce1a1cf66298cccdc48a1bdf8fb10a3bf58e8b58d6c3883dd1530e103f87c0", size = 36328593, upload-time = "2026-01-10T21:28:28.007Z" }, + { url = "https://files.pythonhosted.org/packages/13/1b/c87cc44a0d2c7aaf0f003aef2904c3d097b422a96c7e7c07f5efd9073c1b/scipy-1.17.0-cp313-cp313t-win_arm64.whl", hash = "sha256:30509da9dbec1c2ed8f168b8d8aa853bc6723fede1dbc23c7d43a56f5ab72a67", size = 24625083, upload-time = "2026-01-10T21:28:35.188Z" }, + { url = "https://files.pythonhosted.org/packages/1a/2d/51006cd369b8e7879e1c630999a19d1fbf6f8b5ed3e33374f29dc87e53b3/scipy-1.17.0-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:c17514d11b78be8f7e6331b983a65a7f5ca1fd037b95e27b280921fe5606286a", size = 31346803, upload-time = "2026-01-10T21:28:57.24Z" }, + { url = "https://files.pythonhosted.org/packages/d6/2e/2349458c3ce445f53a6c93d4386b1c4c5c0c540917304c01222ff95ff317/scipy-1.17.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:4e00562e519c09da34c31685f6acc3aa384d4d50604db0f245c14e1b4488bfa2", size = 27967182, upload-time = "2026-01-10T21:29:04.107Z" }, + { url = "https://files.pythonhosted.org/packages/5e/7c/df525fbfa77b878d1cfe625249529514dc02f4fd5f45f0f6295676a76528/scipy-1.17.0-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:f7df7941d71314e60a481e02d5ebcb3f0185b8d799c70d03d8258f6c80f3d467", size = 20139125, upload-time = "2026-01-10T21:29:10.179Z" }, + { url = "https://files.pythonhosted.org/packages/33/11/fcf9d43a7ed1234d31765ec643b0515a85a30b58eddccc5d5a4d12b5f194/scipy-1.17.0-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:aabf057c632798832f071a8dde013c2e26284043934f53b00489f1773b33527e", size = 22443554, upload-time = "2026-01-10T21:29:15.888Z" }, + { url = "https://files.pythonhosted.org/packages/80/5c/ea5d239cda2dd3d31399424967a24d556cf409fbea7b5b21412b0fd0a44f/scipy-1.17.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a38c3337e00be6fd8a95b4ed66b5d988bac4ec888fd922c2ea9fe5fb1603dd67", size = 32757834, upload-time = "2026-01-10T21:29:23.406Z" }, + { url = "https://files.pythonhosted.org/packages/b8/7e/8c917cc573310e5dc91cbeead76f1b600d3fb17cf0969db02c9cf92e3cfa/scipy-1.17.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00fb5f8ec8398ad90215008d8b6009c9db9fa924fd4c7d6be307c6f945f9cd73", size = 34995775, upload-time = "2026-01-10T21:29:31.915Z" }, + { url = "https://files.pythonhosted.org/packages/c5/43/176c0c3c07b3f7df324e7cdd933d3e2c4898ca202b090bd5ba122f9fe270/scipy-1.17.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f2a4942b0f5f7c23c7cd641a0ca1955e2ae83dedcff537e3a0259096635e186b", size = 34841240, upload-time = "2026-01-10T21:29:39.995Z" }, + { url = "https://files.pythonhosted.org/packages/44/8c/d1f5f4b491160592e7f084d997de53a8e896a3ac01cd07e59f43ca222744/scipy-1.17.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:dbf133ced83889583156566d2bdf7a07ff89228fe0c0cb727f777de92092ec6b", size = 37394463, upload-time = "2026-01-10T21:29:48.723Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ec/42a6657f8d2d087e750e9a5dde0b481fd135657f09eaf1cf5688bb23c338/scipy-1.17.0-cp314-cp314-win_amd64.whl", hash = "sha256:3625c631a7acd7cfd929e4e31d2582cf00f42fcf06011f59281271746d77e061", size = 37053015, upload-time = "2026-01-10T21:30:51.418Z" }, + { url = "https://files.pythonhosted.org/packages/27/58/6b89a6afd132787d89a362d443a7bddd511b8f41336a1ae47f9e4f000dc4/scipy-1.17.0-cp314-cp314-win_arm64.whl", hash = "sha256:9244608d27eafe02b20558523ba57f15c689357c85bdcfe920b1828750aa26eb", size = 24951312, upload-time = "2026-01-10T21:30:56.771Z" }, + { url = "https://files.pythonhosted.org/packages/e9/01/f58916b9d9ae0112b86d7c3b10b9e685625ce6e8248df139d0fcb17f7397/scipy-1.17.0-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:2b531f57e09c946f56ad0b4a3b2abee778789097871fc541e267d2eca081cff1", size = 31706502, upload-time = "2026-01-10T21:29:56.326Z" }, + { url = "https://files.pythonhosted.org/packages/59/8e/2912a87f94a7d1f8b38aabc0faf74b82d3b6c9e22be991c49979f0eceed8/scipy-1.17.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:13e861634a2c480bd237deb69333ac79ea1941b94568d4b0efa5db5e263d4fd1", size = 28380854, upload-time = "2026-01-10T21:30:01.554Z" }, + { url = "https://files.pythonhosted.org/packages/bd/1c/874137a52dddab7d5d595c1887089a2125d27d0601fce8c0026a24a92a0b/scipy-1.17.0-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:eb2651271135154aa24f6481cbae5cc8af1f0dd46e6533fb7b56aa9727b6a232", size = 20552752, upload-time = "2026-01-10T21:30:05.93Z" }, + { url = "https://files.pythonhosted.org/packages/3f/f0/7518d171cb735f6400f4576cf70f756d5b419a07fe1867da34e2c2c9c11b/scipy-1.17.0-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:c5e8647f60679790c2f5c76be17e2e9247dc6b98ad0d3b065861e082c56e078d", size = 22803972, upload-time = "2026-01-10T21:30:10.651Z" }, + { url = "https://files.pythonhosted.org/packages/7c/74/3498563a2c619e8a3ebb4d75457486c249b19b5b04a30600dfd9af06bea5/scipy-1.17.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5fb10d17e649e1446410895639f3385fd2bf4c3c7dfc9bea937bddcbc3d7b9ba", size = 32829770, upload-time = "2026-01-10T21:30:16.359Z" }, + { url = "https://files.pythonhosted.org/packages/48/d1/7b50cedd8c6c9d6f706b4b36fa8544d829c712a75e370f763b318e9638c1/scipy-1.17.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8547e7c57f932e7354a2319fab613981cde910631979f74c9b542bb167a8b9db", size = 35051093, upload-time = "2026-01-10T21:30:22.987Z" }, + { url = "https://files.pythonhosted.org/packages/e2/82/a2d684dfddb87ba1b3ea325df7c3293496ee9accb3a19abe9429bce94755/scipy-1.17.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:33af70d040e8af9d5e7a38b5ed3b772adddd281e3062ff23fec49e49681c38cf", size = 34909905, upload-time = "2026-01-10T21:30:28.704Z" }, + { url = "https://files.pythonhosted.org/packages/ef/5e/e565bd73991d42023eb82bb99e51c5b3d9e2c588ca9d4b3e2cc1d3ca62a6/scipy-1.17.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb55bb97d00f8b7ab95cb64f873eb0bf54d9446264d9f3609130381233483f", size = 37457743, upload-time = "2026-01-10T21:30:34.819Z" }, + { url = "https://files.pythonhosted.org/packages/58/a8/a66a75c3d8f1fb2b83f66007d6455a06a6f6cf5618c3dc35bc9b69dd096e/scipy-1.17.0-cp314-cp314t-win_amd64.whl", hash = "sha256:1ff269abf702f6c7e67a4b7aad981d42871a11b9dd83c58d2d2ea624efbd1088", size = 37098574, upload-time = "2026-01-10T21:30:40.782Z" }, + { url = "https://files.pythonhosted.org/packages/56/a5/df8f46ef7da168f1bc52cd86e09a9de5c6f19cc1da04454d51b7d4f43408/scipy-1.17.0-cp314-cp314t-win_arm64.whl", hash = "sha256:031121914e295d9791319a1875444d55079885bbae5bdc9c5e0f2ee5f09d34ff", size = 25246266, upload-time = "2026-01-10T21:30:45.923Z" }, ] [[package]] @@ -1289,16 +1576,16 @@ wheels = [ [[package]] name = "soupsieve" -version = "2.8.1" +version = "2.8.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/89/23/adf3796d740536d63a6fbda113d07e60c734b6ed5d3058d1e47fc0495e47/soupsieve-2.8.1.tar.gz", hash = "sha256:4cf733bc50fa805f5df4b8ef4740fc0e0fa6218cf3006269afd3f9d6d80fd350", size = 117856, upload-time = "2025-12-18T13:50:34.655Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7b/ae/2d9c981590ed9999a0d91755b47fc74f74de286b0f5cee14c9269041e6c4/soupsieve-2.8.3.tar.gz", hash = "sha256:3267f1eeea4251fb42728b6dfb746edc9acaffc4a45b27e19450b676586e8349", size = 118627, upload-time = "2026-01-20T04:27:02.457Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/48/f3/b67d6ea49ca9154453b6d70b34ea22f3996b9fa55da105a79d8732227adc/soupsieve-2.8.1-py3-none-any.whl", hash = "sha256:a11fe2a6f3d76ab3cf2de04eb339c1be5b506a8a47f2ceb6d139803177f85434", size = 36710, upload-time = "2025-12-18T13:50:33.267Z" }, + { url = "https://files.pythonhosted.org/packages/46/2c/1462b1d0a634697ae9e55b3cecdcb64788e8b7d63f54d923fcd0bb140aed/soupsieve-2.8.3-py3-none-any.whl", hash = "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95", size = 37016, upload-time = "2026-01-20T04:27:01.012Z" }, ] [[package]] name = "sphinx" -version = "8.2.3" +version = "9.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "alabaster" }, @@ -1310,7 +1597,7 @@ dependencies = [ { name = "packaging" }, { name = "pygments" }, { name = "requests" }, - { name = "roman-numerals-py" }, + { name = "roman-numerals" }, { name = "snowballstemmer" }, { name = "sphinxcontrib-applehelp" }, { name = "sphinxcontrib-devhelp" }, @@ -1319,9 +1606,9 @@ dependencies = [ { name = "sphinxcontrib-qthelp" }, { name = "sphinxcontrib-serializinghtml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/38/ad/4360e50ed56cb483667b8e6dadf2d3fda62359593faabbe749a27c4eaca6/sphinx-8.2.3.tar.gz", hash = "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348", size = 8321876, upload-time = "2025-03-02T22:31:59.658Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/bd/f08eb0f4eed5c83f1ba2a3bd18f7745a2b1525fad70660a1c00224ec468a/sphinx-9.1.0.tar.gz", hash = "sha256:7741722357dd75f8190766926071fed3bdc211c74dd2d7d4df5404da95930ddb", size = 8718324, upload-time = "2025-12-31T15:09:27.646Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/31/53/136e9eca6e0b9dc0e1962e2c908fbea2e5ac000c2a2fbd9a35797958c48b/sphinx-8.2.3-py3-none-any.whl", hash = "sha256:4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3", size = 3589741, upload-time = "2025-03-02T22:31:56.836Z" }, + { url = "https://files.pythonhosted.org/packages/73/f7/b1884cb3188ab181fc81fa00c266699dab600f927a964df02ec3d5d1916a/sphinx-9.1.0-py3-none-any.whl", hash = "sha256:c84fdd4e782504495fe4f2c0b3413d6c2bf388589bb352d439b2a3bb99991978", size = 3921742, upload-time = "2025-12-31T15:09:25.561Z" }, ] [[package]] @@ -1390,15 +1677,16 @@ wheels = [ [[package]] name = "sphinxcontrib-mermaid" -version = "1.2.3" +version = "2.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "jinja2" }, { name = "pyyaml" }, { name = "sphinx" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f5/49/c6ddfe709a4ab76ac6e5a00e696f73626b2c189dc1e1965a361ec102e6cc/sphinxcontrib_mermaid-1.2.3.tar.gz", hash = "sha256:358699d0ec924ef679b41873d9edd97d0773446daf9760c75e18dc0adfd91371", size = 18885, upload-time = "2025-11-26T04:18:32.43Z" } +sdist = { url = "https://files.pythonhosted.org/packages/96/a5/65a5c439cc14ba80483b9891e9350f11efb80cd3bdccb222f0c738068c78/sphinxcontrib_mermaid-2.0.0.tar.gz", hash = "sha256:cf4f7d453d001132eaba5d1fdf53d42049f02e913213cf8337427483bfca26f4", size = 18194, upload-time = "2026-01-13T17:13:42.563Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/39/8b54299ffa00e597d3b0b4d042241a0a0b22cb429ad007ccfb9c1745b4d1/sphinxcontrib_mermaid-1.2.3-py3-none-any.whl", hash = "sha256:5be782b27026bef97bfb15ccb2f7868b674a1afc0982b54cb149702cfc25aa02", size = 13413, upload-time = "2025-11-26T04:18:31.269Z" }, + { url = "https://files.pythonhosted.org/packages/f9/de/bd96c69b62e967bffd02c6d89dfca9471b04e761c466725fc39746abf41d/sphinxcontrib_mermaid-2.0.0-py3-none-any.whl", hash = "sha256:59a73249bbee2c74b1a4db036f8e8899ade65982bdda6712cf22b4f4e9874bb5", size = 14055, upload-time = "2026-01-13T17:13:41.481Z" }, ] [[package]] @@ -1489,10 +1777,10 @@ dev = [ requires-dist = [ { name = "deprecated", specifier = ">=1.2.14" }, { name = "graphviz", specifier = ">=0.20.3" }, - { name = "gurobipy", marker = "extra == 'solver'", specifier = ">=12.0.3,<13" }, + { name = "gurobipy", marker = "extra == 'solver'", specifier = ">=12.0.3" }, { name = "highspy", specifier = ">=1.7.2" }, { name = "joblib" }, - { name = "matplotlib", specifier = "==3.9.2" }, + { name = "matplotlib", specifier = ">=3.9.2" }, { name = "matplotlib", marker = "extra == 'plotting'", specifier = ">=3.9.2" }, { name = "mpi-sppy", specifier = ">=0.12.1" }, { name = "myst-parser", marker = "extra == 'docs'", specifier = ">=2.0.0" }, @@ -1535,16 +1823,16 @@ dev = [ [[package]] name = "tomlkit" -version = "0.13.3" +version = "0.14.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/18/0bbf3884e9eaa38819ebe46a7bd25dcd56b67434402b66a58c4b8e552575/tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1", size = 185207, upload-time = "2025-06-05T07:13:44.947Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/af/14b24e41977adb296d6bd1fb59402cf7d60ce364f90c890bd2ec65c43b5a/tomlkit-0.14.0.tar.gz", hash = "sha256:cf00efca415dbd57575befb1f6634c4f42d2d87dbba376128adb42c121b87064", size = 187167, upload-time = "2026-01-13T01:14:53.304Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bd/75/8539d011f6be8e29f339c42e633aae3cb73bffa95dd0f9adec09b9c58e85/tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0", size = 38901, upload-time = "2025-06-05T07:13:43.546Z" }, + { url = "https://files.pythonhosted.org/packages/b5/11/87d6d29fb5d237229d67973a6c9e06e048f01cf4994dee194ab0ea841814/tomlkit-0.14.0-py3-none-any.whl", hash = "sha256:592064ed85b40fa213469f81ac584f67a4f2992509a7c3ea2d632208623a3680", size = 39310, upload-time = "2026-01-13T01:14:51.965Z" }, ] [[package]] name = "typer" -version = "0.20.0" +version = "0.21.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -1552,149 +1840,149 @@ dependencies = [ { name = "shellingham" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8f/28/7c85c8032b91dbe79725b6f17d2fffc595dff06a35c7a30a37bef73a1ab4/typer-0.20.0.tar.gz", hash = "sha256:1aaf6494031793e4876fb0bacfa6a912b551cf43c1e63c800df8b1a866720c37", size = 106492, upload-time = "2025-10-20T17:03:49.445Z" } +sdist = { url = "https://files.pythonhosted.org/packages/36/bf/8825b5929afd84d0dabd606c67cd57b8388cb3ec385f7ef19c5cc2202069/typer-0.21.1.tar.gz", hash = "sha256:ea835607cd752343b6b2b7ce676893e5a0324082268b48f27aa058bdb7d2145d", size = 110371, upload-time = "2026-01-06T11:21:10.989Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/64/7713ffe4b5983314e9d436a90d5bd4f63b6054e2aca783a3cfc44cb95bbf/typer-0.20.0-py3-none-any.whl", hash = "sha256:5b463df6793ec1dca6213a3cf4c0f03bc6e322ac5e16e13ddd622a889489784a", size = 47028, upload-time = "2025-10-20T17:03:47.617Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/d9257dd49ff2ca23ea5f132edf1281a0c4f9de8a762b9ae399b670a59235/typer-0.21.1-py3-none-any.whl", hash = "sha256:7985e89081c636b88d172c2ee0cfe33c253160994d47bdfdc302defd7d1f1d01", size = 47381, upload-time = "2026-01-06T11:21:09.824Z" }, ] [[package]] name = "types-deprecated" -version = "1.2.15.20250304" +version = "1.3.1.20251101" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0e/67/eeefaaabb03b288aad85483d410452c8bbcbf8b2bd876b0e467ebd97415b/types_deprecated-1.2.15.20250304.tar.gz", hash = "sha256:c329030553029de5cc6cb30f269c11f4e00e598c4241290179f63cda7d33f719", size = 8015, upload-time = "2025-03-04T02:48:17.894Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c6/96/0f96107945697e452c56a2e9f575da627e61d67940e5913d9c968e5e8be1/types_deprecated-1.3.1.20251101.tar.gz", hash = "sha256:f002d266b73201f46ec6fc712c1f016067ec6cb44357559cdb50c86b010951a7", size = 8358, upload-time = "2025-11-01T03:04:05.6Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/e3/c18aa72ab84e0bc127a3a94e93be1a6ac2cb281371d3a45376ab7cfdd31c/types_deprecated-1.2.15.20250304-py3-none-any.whl", hash = "sha256:86a65aa550ea8acf49f27e226b8953288cd851de887970fbbdf2239c116c3107", size = 8553, upload-time = "2025-03-04T02:48:16.666Z" }, + { url = "https://files.pythonhosted.org/packages/9e/50/fb191dba89031e30c9ea07c3133c6fe8e7da038ef4d0b79539cf85fb1a97/types_deprecated-1.3.1.20251101-py3-none-any.whl", hash = "sha256:274edcc2a084d3fe31802d3c1379abd630716d3db34e40577e12ad84d6b73134", size = 9057, upload-time = "2025-11-01T03:04:04.633Z" }, ] [[package]] name = "types-networkx" -version = "3.5.0.20251001" +version = "3.6.1.20251220" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ac/5b/d903d119f6159e0c9291c53db0e92ea33cb725331f75069d1b45b83b4405/types_networkx-3.5.0.20251001.tar.gz", hash = "sha256:8e3c5c491ba5870d75e175751d70ddeac81df43caf2a64bae161e181f5e8ea7a", size = 71748, upload-time = "2025-10-01T03:04:26.155Z" } +sdist = { url = "https://files.pythonhosted.org/packages/07/e3/dcc20d645dc0631b0df263959b8dde49dc47ad3c0537d8958bfefe692380/types_networkx-3.6.1.20251220.tar.gz", hash = "sha256:caf95e0d7777b969e50ceeb2c430d9d4dfe6b7bdee43c42dc9879a2d4408a790", size = 73500, upload-time = "2025-12-20T03:07:47.933Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/41/cdd9498383b30290cce9de6dbed75fa75d6dc06fe4b47d6da6de4b156aa0/types_networkx-3.5.0.20251001-py3-none-any.whl", hash = "sha256:4bb9dd0378a52ca57d68f8215f8662e736d800a8ff892b457646eccd828a0230", size = 160095, upload-time = "2025-10-01T03:04:24.821Z" }, + { url = "https://files.pythonhosted.org/packages/65/e7/fe40cfe7ba384d1f46fee835eb7727a4ee2fd80021a69add9553197b69a1/types_networkx-3.6.1.20251220-py3-none-any.whl", hash = "sha256:417ccbe7841f335a4c2b8e7515c3bc97a00fb5f686f399a763ef64392b209eac", size = 162715, upload-time = "2025-12-20T03:07:46.882Z" }, ] [[package]] name = "types-pytz" -version = "2025.2.0.20250809" +version = "2025.2.0.20251108" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/07/e2/c774f754de26848f53f05defff5bb21dd9375a059d1ba5b5ea943cf8206e/types_pytz-2025.2.0.20250809.tar.gz", hash = "sha256:222e32e6a29bb28871f8834e8785e3801f2dc4441c715cd2082b271eecbe21e5", size = 10876, upload-time = "2025-08-09T03:14:17.453Z" } +sdist = { url = "https://files.pythonhosted.org/packages/40/ff/c047ddc68c803b46470a357454ef76f4acd8c1088f5cc4891cdd909bfcf6/types_pytz-2025.2.0.20251108.tar.gz", hash = "sha256:fca87917836ae843f07129567b74c1929f1870610681b4c92cb86a3df5817bdb", size = 10961, upload-time = "2025-11-08T02:55:57.001Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/db/d0/91c24fe54e565f2344d7a6821e6c6bb099841ef09007ea6321a0bac0f808/types_pytz-2025.2.0.20250809-py3-none-any.whl", hash = "sha256:4f55ed1b43e925cf851a756fe1707e0f5deeb1976e15bf844bcaa025e8fbd0db", size = 10095, upload-time = "2025-08-09T03:14:16.674Z" }, + { url = "https://files.pythonhosted.org/packages/e7/c1/56ef16bf5dcd255155cc736d276efa6ae0a5c26fd685e28f0412a4013c01/types_pytz-2025.2.0.20251108-py3-none-any.whl", hash = "sha256:0f1c9792cab4eb0e46c52f8845c8f77cf1e313cb3d68bf826aa867fe4717d91c", size = 10116, upload-time = "2025-11-08T02:55:56.194Z" }, ] [[package]] name = "typing-extensions" -version = "4.14.1" +version = "4.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/98/5a/da40306b885cc8c09109dc2e1abd358d5684b1425678151cdaed4731c822/typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36", size = 107673, upload-time = "2025-07-04T13:28:34.16Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/00/d631e67a838026495268c2f6884f3711a15a9a2a96cd244fdaea53b823fb/typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76", size = 43906, upload-time = "2025-07-04T13:28:32.743Z" }, + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, ] [[package]] name = "tzdata" -version = "2025.2" +version = "2025.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" }, + { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" }, ] [[package]] name = "urllib3" -version = "2.5.0" +version = "2.6.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, ] [[package]] name = "virtualenv" -version = "20.31.2" +version = "20.36.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, { name = "filelock" }, { name = "platformdirs" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/56/2c/444f465fb2c65f40c3a104fd0c495184c4f2336d65baf398e3c75d72ea94/virtualenv-20.31.2.tar.gz", hash = "sha256:e10c0a9d02835e592521be48b332b6caee6887f332c111aa79a09b9e79efc2af", size = 6076316, upload-time = "2025-05-08T17:58:23.811Z" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/a3/4d310fa5f00863544e1d0f4de93bddec248499ccf97d4791bc3122c9d4f3/virtualenv-20.36.1.tar.gz", hash = "sha256:8befb5c81842c641f8ee658481e42641c68b5eab3521d8e092d18320902466ba", size = 6032239, upload-time = "2026-01-09T18:21:01.296Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/40/b1c265d4b2b62b58576588510fc4d1fe60a86319c8de99fd8e9fec617d2c/virtualenv-20.31.2-py3-none-any.whl", hash = "sha256:36efd0d9650ee985f0cad72065001e66d49a6f24eb44d98980f630686243cf11", size = 6057982, upload-time = "2025-05-08T17:58:21.15Z" }, + { url = "https://files.pythonhosted.org/packages/6a/2a/dc2228b2888f51192c7dc766106cd475f1b768c10caaf9727659726f7391/virtualenv-20.36.1-py3-none-any.whl", hash = "sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f", size = 6008258, upload-time = "2026-01-09T18:20:59.425Z" }, ] [[package]] name = "wrapt" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/19/5e5bcd855d808892fe02d49219f97a50f64cd6d8313d75df3494ee97b1a3/wrapt-2.0.0.tar.gz", hash = "sha256:35a542cc7a962331d0279735c30995b024e852cf40481e384fd63caaa391cbb9", size = 81722, upload-time = "2025-10-19T23:47:54.07Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3c/28/7f266b5bf50c3ad0c99c524d99faa0f7d6eecb045d950e7d2c9e1f0e1338/wrapt-2.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73c6f734aecb1a030d9a265c13a425897e1ea821b73249bb14471445467ca71c", size = 78078, upload-time = "2025-10-19T23:45:58.855Z" }, - { url = "https://files.pythonhosted.org/packages/06/0c/bbdcad7eb535fae9d6b0fcfa3995c364797cd8e2b423bba5559ab2d88dcf/wrapt-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b4a7f8023b8ce8a36370154733c747f8d65c8697cb977d8b6efeb89291fff23e", size = 61158, upload-time = "2025-10-19T23:46:00.096Z" }, - { url = "https://files.pythonhosted.org/packages/d3/8a/bba3e7a4ebf4d1624103ee59d97b78a1fbb08fb5753ff5d1b69f5ef5e863/wrapt-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a1cb62f686c50e9dab5983c68f6c8e9cbf14a6007935e683662898a7d892fa69", size = 61646, upload-time = "2025-10-19T23:46:01.279Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0c/0f565294897a72493dbafe7b46229b5f09f3776795a894d6b737e98387de/wrapt-2.0.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:43dc0550ae15e33e6bb45a82a5e1b5495be2587fbaa996244b509921810ee49f", size = 121442, upload-time = "2025-10-19T23:46:04.287Z" }, - { url = "https://files.pythonhosted.org/packages/da/80/7f03501a8a078ad79b19b1a888f9192a9494e62ddf8985267902766a4f30/wrapt-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39c5b45b056d630545e40674d1f5e1b51864b3546f25ab6a4a331943de96262e", size = 123018, upload-time = "2025-10-19T23:46:06.052Z" }, - { url = "https://files.pythonhosted.org/packages/37/6b/ad0e1ff98359f13b4b0c2c52848e792841146fe79ac5f56899b9a028fc0d/wrapt-2.0.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:804e88f824b76240a1b670330637ccfd2d18b9efa3bb4f02eb20b2f64880b324", size = 117369, upload-time = "2025-10-19T23:46:02.53Z" }, - { url = "https://files.pythonhosted.org/packages/ac/6c/a90437bba8cb1ce2ed639af979515e09784678c2a7f4ffc79f2cf7de809e/wrapt-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c2c476aa3fc2b9899c3f7b20963fac4f952e7edb74a31fc92f7745389a2e3618", size = 121453, upload-time = "2025-10-19T23:46:07.747Z" }, - { url = "https://files.pythonhosted.org/packages/2c/a9/b3982f9bd15bd45857a23c48b7c36e47d05db4a4dcc5061c31f169238845/wrapt-2.0.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:8d851e526891216f89fcb7a1820dad9bd503ba3468fb9635ee28e93c781aa98e", size = 116250, upload-time = "2025-10-19T23:46:09.385Z" }, - { url = "https://files.pythonhosted.org/packages/73/e2/b7a8b1afac9f791d8f5eac0d9726559f1d7ec4a2b5a6b4e67ac145b007a5/wrapt-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b95733c2360c4a8656ee93c7af78e84c0bd617da04a236d7a456c8faa34e7a2d", size = 120575, upload-time = "2025-10-19T23:46:11.882Z" }, - { url = "https://files.pythonhosted.org/packages/a2/0f/37920eeea96094f450ae35505d39f1135df951a2cdee0d4e01d4f843396a/wrapt-2.0.0-cp312-cp312-win32.whl", hash = "sha256:ea56817176834edf143df1109ae8fdaa087be82fdad3492648de0baa8ae82bf2", size = 58175, upload-time = "2025-10-19T23:46:15.678Z" }, - { url = "https://files.pythonhosted.org/packages/f0/db/b395f3b0c7f2c60d9219afacc54ceb699801ccf2d3d969ba556dc6d3af20/wrapt-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:3c7d3bee7be7a2665286103f4d1f15405c8074e6e1f89dac5774f9357c9a3809", size = 60415, upload-time = "2025-10-19T23:46:12.913Z" }, - { url = "https://files.pythonhosted.org/packages/86/22/33d660214548af47fc59d9eec8c0e0693bcedc5b3a0b52e8cbdd61f3b646/wrapt-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:680f707e1d26acbc60926659799b15659f077df5897a6791c7c598a5d4a211c4", size = 58911, upload-time = "2025-10-19T23:46:13.889Z" }, - { url = "https://files.pythonhosted.org/packages/18/0a/dd88abfe756b1aa79f0777e5ee4ce9e4b5dc4999bd805e9b04b52efc7b18/wrapt-2.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e2ea096db28d5eb64d381af0e93464621ace38a7003a364b6b5ffb7dd713aabe", size = 78083, upload-time = "2025-10-19T23:46:16.937Z" }, - { url = "https://files.pythonhosted.org/packages/7f/b9/8afebc1655a863bb2178b23c2d699b8743f3a7dab466904adc6155f3c858/wrapt-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c92b5a82d28491e3f14f037e1aae99a27a5e6e0bb161e65f52c0445a3fa7c940", size = 61156, upload-time = "2025-10-19T23:46:17.927Z" }, - { url = "https://files.pythonhosted.org/packages/bb/8b/f710a6528ccc52e21943f42c8cf64814cde90f9adbd3bcd58c7c274b4f75/wrapt-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:81d234718aabe632d179fac52c7f69f0f99fbaac4d4bcd670e62462bbcbfcad7", size = 61641, upload-time = "2025-10-19T23:46:19.229Z" }, - { url = "https://files.pythonhosted.org/packages/e4/5f/e4eabd0cc6684c5b208c2abc5c3459449c4d15be1694a9bbcf51e0e135fd/wrapt-2.0.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:db2eea83c43f84e4e41dbbb4c1de371a53166e55f900a6b130c3ef51c6345c1a", size = 121454, upload-time = "2025-10-19T23:46:21.808Z" }, - { url = "https://files.pythonhosted.org/packages/6f/c4/ec31ee17cc7866960d323609ba7402be786d211a6d713a59f776c4270bb3/wrapt-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:65f50e356c425c061e1e17fe687ff30e294fed9bf3441dc1f13ef73859c2a817", size = 123063, upload-time = "2025-10-19T23:46:23.545Z" }, - { url = "https://files.pythonhosted.org/packages/b0/2b/a4b10c3c0022e40aeae9bec009bafb049f440493f0575ebb27ecf61c32f8/wrapt-2.0.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:887f2a667e3cbfb19e204032d42ad7dedaa43972e4861dc7a3d51ae951d9b578", size = 117401, upload-time = "2025-10-19T23:46:20.433Z" }, - { url = "https://files.pythonhosted.org/packages/2a/4a/ade23a76967e1f148e461076a4d0e24a7950a5f18b394c9107fe60224ae2/wrapt-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9054829da4be461e3ad3192e4b6bbf1fc18af64c9975ce613aec191924e004dc", size = 121485, upload-time = "2025-10-19T23:46:24.85Z" }, - { url = "https://files.pythonhosted.org/packages/cb/ba/33b5f3e2edede4e1cfd259f0d9c203cf370f259bb9b215dd58fc6cbb94e9/wrapt-2.0.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:b952ffd77133a5a2798ee3feb18e51b0a299d2f440961e5bb7737dbb02e57289", size = 116276, upload-time = "2025-10-19T23:46:27.006Z" }, - { url = "https://files.pythonhosted.org/packages/eb/bf/b7f95bb4529a35ca11eb95d48f9d1a563b495471f7cf404c644566fb4293/wrapt-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e25fde03c480061b8234d8ee4863eb5f40a9be4fb258ce105b364de38fc6bcf9", size = 120578, upload-time = "2025-10-19T23:46:28.679Z" }, - { url = "https://files.pythonhosted.org/packages/f8/71/984849df6f052592474a44aafd6b847e1cffad39b0debc5390a04aa46331/wrapt-2.0.0-cp313-cp313-win32.whl", hash = "sha256:49e982b7860d325094978292a49e0418833fc7fc42c0dc7cd0b7524d7d06ee74", size = 58178, upload-time = "2025-10-19T23:46:32.372Z" }, - { url = "https://files.pythonhosted.org/packages/f9/3b/4e1fc0f2e1355fbc55ab248311bf4c958dbbd96bd9183b9e96882cc16213/wrapt-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:6e5c86389d9964050ce50babe247d172a5e3911d59a64023b90db2b4fa00ae7c", size = 60423, upload-time = "2025-10-19T23:46:30.041Z" }, - { url = "https://files.pythonhosted.org/packages/20/0a/9384e0551f56fe361f41bb8f209a13bb9ef689c3a18264225b249849b12c/wrapt-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:b96fdaa4611e05c7231937930567d3c16782be9dbcf03eb9f60d83e57dd2f129", size = 58918, upload-time = "2025-10-19T23:46:31.056Z" }, - { url = "https://files.pythonhosted.org/packages/68/70/37b90d3ee5bf0d0dc4859306383da08b685c9a51abff6fd6b0a7c052e117/wrapt-2.0.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f2c7b7fead096dbf1dcc455b7f59facb05de3f5bfb04f60a69f98cdfe6049e5f", size = 81980, upload-time = "2025-10-19T23:46:33.368Z" }, - { url = "https://files.pythonhosted.org/packages/95/23/0ce69cc90806b90b3ee4cfd9ad8d2ee9becc3a1aab7df3c3bfc7d0904cb6/wrapt-2.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:04c7c8393f25b11c0faa5d907dd9eb462e87e4e7ba55e308a046d7ed37f4bbe2", size = 62900, upload-time = "2025-10-19T23:46:34.415Z" }, - { url = "https://files.pythonhosted.org/packages/54/76/03ec08170c02f38f3be3646977920976b968e0b704a0693a98f95d02f4d2/wrapt-2.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a93e0f8b376c0735b2f4daf58018b4823614d2b896cb72b6641c4d3dbdca1d75", size = 63636, upload-time = "2025-10-19T23:46:35.643Z" }, - { url = "https://files.pythonhosted.org/packages/75/c1/04ce0511e504cdcd84cdb6980bc7d4efa38ac358e8103d6dd0cd278bfc6d/wrapt-2.0.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b42d13603da4416c43c430dbc6313c8d7ff745c40942f146ed4f6dd02c7d2547", size = 152650, upload-time = "2025-10-19T23:46:38.717Z" }, - { url = "https://files.pythonhosted.org/packages/17/06/cd2e32b5f744701189c954f9ab5eee449c86695b13f414bb8ea7a83f6d48/wrapt-2.0.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8bbd2472abf8c33480ad2314b1f8fac45d592aba6cc093e8839a7b2045660e6", size = 158811, upload-time = "2025-10-19T23:46:40.875Z" }, - { url = "https://files.pythonhosted.org/packages/7d/a2/a6d920695cca62563c1b969064e5cd2051344a6e330c184b6f80383d87e4/wrapt-2.0.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e64a3a1fd9a308ab9b815a2ad7a65b679730629dbf85f8fc3f7f970d634ee5df", size = 146033, upload-time = "2025-10-19T23:46:37.351Z" }, - { url = "https://files.pythonhosted.org/packages/c6/90/7fd2abe4ec646bc43cb6b0d05086be6fcf15e64f06f51fc4198804396d68/wrapt-2.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d61214525eaf88e0d0edf3d1ad5b5889863c6f88e588c6cdc6aa4ee5d1f10a4a", size = 155673, upload-time = "2025-10-19T23:46:42.582Z" }, - { url = "https://files.pythonhosted.org/packages/5f/8d/6cce7f8c41633e677ac8aa34e84b53a22a645ec2a680deb991785ca2798d/wrapt-2.0.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:04f7a5f92c5f7324a1735043cc467b1295a1c5b4e0c1395472b7c44706e3dc61", size = 144364, upload-time = "2025-10-19T23:46:44.381Z" }, - { url = "https://files.pythonhosted.org/packages/72/42/9570349e03afa9d83daf7f33ffb17e8cdc62d7e84c0d09005d0f51912efa/wrapt-2.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2356f76cb99b3de5b4e5b8210367fbbb81c7309fe39b622f5d199dd88eb7f765", size = 150275, upload-time = "2025-10-19T23:46:45.662Z" }, - { url = "https://files.pythonhosted.org/packages/f2/d8/448728e6fe030e5c4f1022c82cd3af1de1c672fa53d2d5b36b32a55ce7bf/wrapt-2.0.0-cp313-cp313t-win32.whl", hash = "sha256:0a921b657a224e40e4bc161b5d33934583b34f0c9c5bdda4e6ac66f9d2fcb849", size = 59867, upload-time = "2025-10-19T23:46:49.593Z" }, - { url = "https://files.pythonhosted.org/packages/8f/b1/ad812b1fe1cd85f6498dc3a3c9809a1e880d6108283b1735119bec217041/wrapt-2.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:c16f6d4eea98080f6659a8a7fc559d4a0a337ee66960659265cad2c8a40f7c0f", size = 63170, upload-time = "2025-10-19T23:46:46.87Z" }, - { url = "https://files.pythonhosted.org/packages/7f/29/c105b1e76650c82823c491952a7a8eafe09b78944f7a43f22d37ed860229/wrapt-2.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:52878edc13dc151c58a9966621d67163a80654bc6cff4b2e1c79fa62d0352b26", size = 60339, upload-time = "2025-10-19T23:46:47.862Z" }, - { url = "https://files.pythonhosted.org/packages/f8/38/0dd39f83163fd28326afba84e3e416656938df07e60a924ac4d992b30220/wrapt-2.0.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:79a53d86c2aff7b32cc77267e3a308365d1fcb881e74bc9cbe26f63ee90e37f0", size = 78242, upload-time = "2025-10-19T23:46:51.096Z" }, - { url = "https://files.pythonhosted.org/packages/08/ef/fa7a5c1d73f8690c712f9d2e4615700c6809942536dd3f441b9ba650a310/wrapt-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d731a4f22ed6ffa4cb551b4d2b0c24ff940c27a88edaf8e3490a5ee3a05aef71", size = 61207, upload-time = "2025-10-19T23:46:52.558Z" }, - { url = "https://files.pythonhosted.org/packages/23/d9/67cb93da492eb0a1cb17b7ed18220d059e58f00467ce6728b674d3441b3d/wrapt-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3e02ab8c0ac766a5a6e81cd3b6cc39200c69051826243182175555872522bd5a", size = 61748, upload-time = "2025-10-19T23:46:54.468Z" }, - { url = "https://files.pythonhosted.org/packages/e5/be/912bbd70cc614f491b526a1d7fe85695b283deed19287b9f32460178c54d/wrapt-2.0.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:895870602d65d7338edb3b6a717d856632ad9f14f7ff566214e4fb11f0816649", size = 120424, upload-time = "2025-10-19T23:46:57.575Z" }, - { url = "https://files.pythonhosted.org/packages/b2/e1/10df8937e7da2aa9bc3662a4b623e51a323c68f42cad7b13f0e61a700ce2/wrapt-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b9ad4fab76a0086dc364c4f17f39ad289600e73ef5c6e9ab529aff22cac1ac3", size = 122804, upload-time = "2025-10-19T23:46:59.308Z" }, - { url = "https://files.pythonhosted.org/packages/f3/60/576751b1919adab9f63168e3b5fd46c0d1565871b1cc4c2569503ccf4be6/wrapt-2.0.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e7ca0562606d7bad2736b2c18f61295d61f50cd3f4bfc51753df13614dbcce1b", size = 117398, upload-time = "2025-10-19T23:46:55.814Z" }, - { url = "https://files.pythonhosted.org/packages/ec/55/243411f360cc27bae5f8e21c16f1a8d87674c5534f4558e8a97c1e0d1c6f/wrapt-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fe089d9f5a4a3dea0108a8ae34bced114d0c4cca417bada1c5e8f42d98af9050", size = 121230, upload-time = "2025-10-19T23:47:01.347Z" }, - { url = "https://files.pythonhosted.org/packages/d6/23/2f21f692c3b3f0857cb82708ce0c341fbac55a489d4025ae4e3fd5d5de8c/wrapt-2.0.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e761f2d2f8dbc80384af3d547b522a80e67db3e319c7b02e7fd97aded0a8a678", size = 116296, upload-time = "2025-10-19T23:47:02.659Z" }, - { url = "https://files.pythonhosted.org/packages/bd/ed/678957fad212cfb1b65b2359d62f5619f5087d1d1cf296c6a996be45171c/wrapt-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:17ba1bdc52d0c783481850996aa26cea5237720769197335abea2ae6b4c23bc0", size = 119602, upload-time = "2025-10-19T23:47:03.775Z" }, - { url = "https://files.pythonhosted.org/packages/dc/e3/aeb4c3b052d3eed95e61babc20dcb1a512651e098cca4b84a6896585c06a/wrapt-2.0.0-cp314-cp314-win32.whl", hash = "sha256:f73318741b141223a4674ba96992aa2291b1b3f7a5e85cb3c2c964f86171eb45", size = 58649, upload-time = "2025-10-19T23:47:07.382Z" }, - { url = "https://files.pythonhosted.org/packages/aa/2a/a71c51cb211798405b59172c7df5789a5b934b18317223cf22e0c6f852de/wrapt-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:8e08d4edb13cafe7b3260f31d4de033f73d3205774540cf583bffaa4bec97db9", size = 60897, upload-time = "2025-10-19T23:47:04.862Z" }, - { url = "https://files.pythonhosted.org/packages/f8/a5/acc5628035d06f69e9144cca543ca54c33b42a5a23b6f1e8fa131026db89/wrapt-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:af01695c2b7bbd8d67b869d8e3de2b123a7bfbee0185bdd138c2775f75373b83", size = 59306, upload-time = "2025-10-19T23:47:05.883Z" }, - { url = "https://files.pythonhosted.org/packages/a7/e6/1318ca07d7fcee57e4592a78dacd9d5493b8ddd971c553a62904fb2c0cf2/wrapt-2.0.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:057f02c13cce7b26c79624c06a3e1c2353e6dc9708525232232f6768118042ca", size = 81987, upload-time = "2025-10-19T23:47:08.7Z" }, - { url = "https://files.pythonhosted.org/packages/e7/bf/ffac358ddf61c3923d94a8b0e7620f2af1cd1b637a0fe4963a3919aa62b7/wrapt-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:79bdd84570267f3f43d609c892ae2d30b91ee4b8614c2cbfd311a2965f1c9bdb", size = 62902, upload-time = "2025-10-19T23:47:10.248Z" }, - { url = "https://files.pythonhosted.org/packages/b5/af/387c51f9e7b544fe95d852fc94f9f3866e3f7d7d39c2ee65041752f90bc2/wrapt-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:93c8b4f4d54fd401a817abbfc9bf482aa72fd447f8adf19ce81d035b3f5c762c", size = 63635, upload-time = "2025-10-19T23:47:11.746Z" }, - { url = "https://files.pythonhosted.org/packages/7c/99/d38d8c80b9cc352531d4d539a17e3674169a5cc25a7e6e5e3c27bc29893e/wrapt-2.0.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5e09ffd31001dce71c2c2a4fc201bdba9a2f9f62b23700cf24af42266e784741", size = 152659, upload-time = "2025-10-19T23:47:15.344Z" }, - { url = "https://files.pythonhosted.org/packages/5a/2a/e154432f274e22ecf2465583386c5ceffa5e0bab3947c1c5b26cc8e7b275/wrapt-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d87c285ff04e26083c4b03546e7b74df7ba4f1f32f1dcb92e9ac13c2dbb4c379", size = 158818, upload-time = "2025-10-19T23:47:17.569Z" }, - { url = "https://files.pythonhosted.org/packages/c5/7a/3a40c453300e2898e99c27495b8109ff7cd526997d12cfb8ebd1843199a4/wrapt-2.0.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e52e50ea0a72ea48d1291cf8b8aaedcc99072d9dc5baba6b820486dcf4c67da8", size = 146113, upload-time = "2025-10-19T23:47:13.026Z" }, - { url = "https://files.pythonhosted.org/packages/9e/e2/3116a9eade8bea2bf5eedba3fa420e3c7d193d4b047440330d8eaf1098de/wrapt-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1fd4c95536975895f32571073446e614d5e2810b666b64955586dcddfd438fd3", size = 155689, upload-time = "2025-10-19T23:47:19.397Z" }, - { url = "https://files.pythonhosted.org/packages/43/1c/277d3fbe9d177830ab9e54fe9253f38455b75a22d639a4bd9fa092d55ae5/wrapt-2.0.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d6ebfe9283209220ed9de80a3e9442aab8fc2be5a9bbf8491b99e02ca9349a89", size = 144403, upload-time = "2025-10-19T23:47:20.779Z" }, - { url = "https://files.pythonhosted.org/packages/d8/37/ab6ddaf182248aac5ed925725ef4c69a510594764665ecbd95bdd4481f16/wrapt-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5d3ebd784804f146b7ea55359beb138e23cc18e5a5cc2cf26ad438723c00ce3a", size = 150307, upload-time = "2025-10-19T23:47:22.604Z" }, - { url = "https://files.pythonhosted.org/packages/f6/d7/df9e2d8040a3af618ff9496261cf90ca4f886fd226af0f4a69ac0c020c3b/wrapt-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:9b15940ae9debc8b40b15dc57e1ce4433f7fb9d3f8761c7fab1ddd94cb999d99", size = 60557, upload-time = "2025-10-19T23:47:26.73Z" }, - { url = "https://files.pythonhosted.org/packages/b4/c2/502bd4557a3a9199ea73cc5932cf83354bd362682162f0b14164d2e90216/wrapt-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:7a0efbbc06d3e2077476a04f55859819d23206600b4c33f791359a8e6fa3c362", size = 63988, upload-time = "2025-10-19T23:47:23.826Z" }, - { url = "https://files.pythonhosted.org/packages/1f/f2/632b13942f45db7af709f346ff38b8992c8c21b004e61ab320b0dec525fe/wrapt-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:7fec8a9455c029c8cf4ff143a53b6e7c463268d42be6c17efa847ebd2f809965", size = 60584, upload-time = "2025-10-19T23:47:25.396Z" }, - { url = "https://files.pythonhosted.org/packages/00/5c/c34575f96a0a038579683c7f10fca943c15c7946037d1d254ab9db1536ec/wrapt-2.0.0-py3-none-any.whl", hash = "sha256:02482fb0df89857e35427dfb844319417e14fae05878f295ee43fa3bf3b15502", size = 43998, upload-time = "2025-10-19T23:47:52.858Z" }, +version = "2.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/49/2a/6de8a50cb435b7f42c46126cf1a54b2aab81784e74c8595c8e025e8f36d3/wrapt-2.0.1.tar.gz", hash = "sha256:9c9c635e78497cacb81e84f8b11b23e0aacac7a136e73b8e5b2109a1d9fc468f", size = 82040, upload-time = "2025-11-07T00:45:33.312Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/73/8cb252858dc8254baa0ce58ce382858e3a1cf616acebc497cb13374c95c6/wrapt-2.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1fdbb34da15450f2b1d735a0e969c24bdb8d8924892380126e2a293d9902078c", size = 78129, upload-time = "2025-11-07T00:43:48.852Z" }, + { url = "https://files.pythonhosted.org/packages/19/42/44a0db2108526ee6e17a5ab72478061158f34b08b793df251d9fbb9a7eb4/wrapt-2.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3d32794fe940b7000f0519904e247f902f0149edbe6316c710a8562fb6738841", size = 61205, upload-time = "2025-11-07T00:43:50.402Z" }, + { url = "https://files.pythonhosted.org/packages/4d/8a/5b4b1e44b791c22046e90d9b175f9a7581a8cc7a0debbb930f81e6ae8e25/wrapt-2.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:386fb54d9cd903ee0012c09291336469eb7b244f7183d40dc3e86a16a4bace62", size = 61692, upload-time = "2025-11-07T00:43:51.678Z" }, + { url = "https://files.pythonhosted.org/packages/11/53/3e794346c39f462bcf1f58ac0487ff9bdad02f9b6d5ee2dc84c72e0243b2/wrapt-2.0.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7b219cb2182f230676308cdcacd428fa837987b89e4b7c5c9025088b8a6c9faf", size = 121492, upload-time = "2025-11-07T00:43:55.017Z" }, + { url = "https://files.pythonhosted.org/packages/c6/7e/10b7b0e8841e684c8ca76b462a9091c45d62e8f2de9c4b1390b690eadf16/wrapt-2.0.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:641e94e789b5f6b4822bb8d8ebbdfc10f4e4eae7756d648b717d980f657a9eb9", size = 123064, upload-time = "2025-11-07T00:43:56.323Z" }, + { url = "https://files.pythonhosted.org/packages/0e/d1/3c1e4321fc2f5ee7fd866b2d822aa89b84495f28676fd976c47327c5b6aa/wrapt-2.0.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fe21b118b9f58859b5ebaa4b130dee18669df4bd111daad082b7beb8799ad16b", size = 117403, upload-time = "2025-11-07T00:43:53.258Z" }, + { url = "https://files.pythonhosted.org/packages/a4/b0/d2f0a413cf201c8c2466de08414a15420a25aa83f53e647b7255cc2fab5d/wrapt-2.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:17fb85fa4abc26a5184d93b3efd2dcc14deb4b09edcdb3535a536ad34f0b4dba", size = 121500, upload-time = "2025-11-07T00:43:57.468Z" }, + { url = "https://files.pythonhosted.org/packages/bd/45/bddb11d28ca39970a41ed48a26d210505120f925918592283369219f83cc/wrapt-2.0.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:b89ef9223d665ab255ae42cc282d27d69704d94be0deffc8b9d919179a609684", size = 116299, upload-time = "2025-11-07T00:43:58.877Z" }, + { url = "https://files.pythonhosted.org/packages/81/af/34ba6dd570ef7a534e7eec0c25e2615c355602c52aba59413411c025a0cb/wrapt-2.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a453257f19c31b31ba593c30d997d6e5be39e3b5ad9148c2af5a7314061c63eb", size = 120622, upload-time = "2025-11-07T00:43:59.962Z" }, + { url = "https://files.pythonhosted.org/packages/e2/3e/693a13b4146646fb03254636f8bafd20c621955d27d65b15de07ab886187/wrapt-2.0.1-cp312-cp312-win32.whl", hash = "sha256:3e271346f01e9c8b1130a6a3b0e11908049fe5be2d365a5f402778049147e7e9", size = 58246, upload-time = "2025-11-07T00:44:03.169Z" }, + { url = "https://files.pythonhosted.org/packages/a7/36/715ec5076f925a6be95f37917b66ebbeaa1372d1862c2ccd7a751574b068/wrapt-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:2da620b31a90cdefa9cd0c2b661882329e2e19d1d7b9b920189956b76c564d75", size = 60492, upload-time = "2025-11-07T00:44:01.027Z" }, + { url = "https://files.pythonhosted.org/packages/ef/3e/62451cd7d80f65cc125f2b426b25fbb6c514bf6f7011a0c3904fc8c8df90/wrapt-2.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:aea9c7224c302bc8bfc892b908537f56c430802560e827b75ecbde81b604598b", size = 58987, upload-time = "2025-11-07T00:44:02.095Z" }, + { url = "https://files.pythonhosted.org/packages/ad/fe/41af4c46b5e498c90fc87981ab2972fbd9f0bccda597adb99d3d3441b94b/wrapt-2.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:47b0f8bafe90f7736151f61482c583c86b0693d80f075a58701dd1549b0010a9", size = 78132, upload-time = "2025-11-07T00:44:04.628Z" }, + { url = "https://files.pythonhosted.org/packages/1c/92/d68895a984a5ebbbfb175512b0c0aad872354a4a2484fbd5552e9f275316/wrapt-2.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:cbeb0971e13b4bd81d34169ed57a6dda017328d1a22b62fda45e1d21dd06148f", size = 61211, upload-time = "2025-11-07T00:44:05.626Z" }, + { url = "https://files.pythonhosted.org/packages/e8/26/ba83dc5ae7cf5aa2b02364a3d9cf74374b86169906a1f3ade9a2d03cf21c/wrapt-2.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb7cffe572ad0a141a7886a1d2efa5bef0bf7fe021deeea76b3ab334d2c38218", size = 61689, upload-time = "2025-11-07T00:44:06.719Z" }, + { url = "https://files.pythonhosted.org/packages/cf/67/d7a7c276d874e5d26738c22444d466a3a64ed541f6ef35f740dbd865bab4/wrapt-2.0.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c8d60527d1ecfc131426b10d93ab5d53e08a09c5fa0175f6b21b3252080c70a9", size = 121502, upload-time = "2025-11-07T00:44:09.557Z" }, + { url = "https://files.pythonhosted.org/packages/0f/6b/806dbf6dd9579556aab22fc92908a876636e250f063f71548a8660382184/wrapt-2.0.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c654eafb01afac55246053d67a4b9a984a3567c3808bb7df2f8de1c1caba2e1c", size = 123110, upload-time = "2025-11-07T00:44:10.64Z" }, + { url = "https://files.pythonhosted.org/packages/e5/08/cdbb965fbe4c02c5233d185d070cabed2ecc1f1e47662854f95d77613f57/wrapt-2.0.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:98d873ed6c8b4ee2418f7afce666751854d6d03e3c0ec2a399bb039cd2ae89db", size = 117434, upload-time = "2025-11-07T00:44:08.138Z" }, + { url = "https://files.pythonhosted.org/packages/2d/d1/6aae2ce39db4cb5216302fa2e9577ad74424dfbe315bd6669725569e048c/wrapt-2.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c9e850f5b7fc67af856ff054c71690d54fa940c3ef74209ad9f935b4f66a0233", size = 121533, upload-time = "2025-11-07T00:44:12.142Z" }, + { url = "https://files.pythonhosted.org/packages/79/35/565abf57559fbe0a9155c29879ff43ce8bd28d2ca61033a3a3dd67b70794/wrapt-2.0.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e505629359cb5f751e16e30cf3f91a1d3ddb4552480c205947da415d597f7ac2", size = 116324, upload-time = "2025-11-07T00:44:13.28Z" }, + { url = "https://files.pythonhosted.org/packages/e1/e0/53ff5e76587822ee33e560ad55876d858e384158272cd9947abdd4ad42ca/wrapt-2.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2879af909312d0baf35f08edeea918ee3af7ab57c37fe47cb6a373c9f2749c7b", size = 120627, upload-time = "2025-11-07T00:44:14.431Z" }, + { url = "https://files.pythonhosted.org/packages/7c/7b/38df30fd629fbd7612c407643c63e80e1c60bcc982e30ceeae163a9800e7/wrapt-2.0.1-cp313-cp313-win32.whl", hash = "sha256:d67956c676be5a24102c7407a71f4126d30de2a569a1c7871c9f3cabc94225d7", size = 58252, upload-time = "2025-11-07T00:44:17.814Z" }, + { url = "https://files.pythonhosted.org/packages/85/64/d3954e836ea67c4d3ad5285e5c8fd9d362fd0a189a2db622df457b0f4f6a/wrapt-2.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:9ca66b38dd642bf90c59b6738af8070747b610115a39af2498535f62b5cdc1c3", size = 60500, upload-time = "2025-11-07T00:44:15.561Z" }, + { url = "https://files.pythonhosted.org/packages/89/4e/3c8b99ac93527cfab7f116089db120fef16aac96e5f6cdb724ddf286086d/wrapt-2.0.1-cp313-cp313-win_arm64.whl", hash = "sha256:5a4939eae35db6b6cec8e7aa0e833dcca0acad8231672c26c2a9ab7a0f8ac9c8", size = 58993, upload-time = "2025-11-07T00:44:16.65Z" }, + { url = "https://files.pythonhosted.org/packages/f9/f4/eff2b7d711cae20d220780b9300faa05558660afb93f2ff5db61fe725b9a/wrapt-2.0.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a52f93d95c8d38fed0669da2ebdb0b0376e895d84596a976c15a9eb45e3eccb3", size = 82028, upload-time = "2025-11-07T00:44:18.944Z" }, + { url = "https://files.pythonhosted.org/packages/0c/67/cb945563f66fd0f61a999339460d950f4735c69f18f0a87ca586319b1778/wrapt-2.0.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4e54bbf554ee29fcceee24fa41c4d091398b911da6e7f5d7bffda963c9aed2e1", size = 62949, upload-time = "2025-11-07T00:44:20.074Z" }, + { url = "https://files.pythonhosted.org/packages/ec/ca/f63e177f0bbe1e5cf5e8d9b74a286537cd709724384ff20860f8f6065904/wrapt-2.0.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:908f8c6c71557f4deaa280f55d0728c3bca0960e8c3dd5ceeeafb3c19942719d", size = 63681, upload-time = "2025-11-07T00:44:21.345Z" }, + { url = "https://files.pythonhosted.org/packages/39/a1/1b88fcd21fd835dca48b556daef750952e917a2794fa20c025489e2e1f0f/wrapt-2.0.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e2f84e9af2060e3904a32cea9bb6db23ce3f91cfd90c6b426757cf7cc01c45c7", size = 152696, upload-time = "2025-11-07T00:44:24.318Z" }, + { url = "https://files.pythonhosted.org/packages/62/1c/d9185500c1960d9f5f77b9c0b890b7fc62282b53af7ad1b6bd779157f714/wrapt-2.0.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e3612dc06b436968dfb9142c62e5dfa9eb5924f91120b3c8ff501ad878f90eb3", size = 158859, upload-time = "2025-11-07T00:44:25.494Z" }, + { url = "https://files.pythonhosted.org/packages/91/60/5d796ed0f481ec003220c7878a1d6894652efe089853a208ea0838c13086/wrapt-2.0.1-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6d2d947d266d99a1477cd005b23cbd09465276e302515e122df56bb9511aca1b", size = 146068, upload-time = "2025-11-07T00:44:22.81Z" }, + { url = "https://files.pythonhosted.org/packages/04/f8/75282dd72f102ddbfba137e1e15ecba47b40acff32c08ae97edbf53f469e/wrapt-2.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:7d539241e87b650cbc4c3ac9f32c8d1ac8a54e510f6dca3f6ab60dcfd48c9b10", size = 155724, upload-time = "2025-11-07T00:44:26.634Z" }, + { url = "https://files.pythonhosted.org/packages/5a/27/fe39c51d1b344caebb4a6a9372157bdb8d25b194b3561b52c8ffc40ac7d1/wrapt-2.0.1-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:4811e15d88ee62dbf5c77f2c3ff3932b1e3ac92323ba3912f51fc4016ce81ecf", size = 144413, upload-time = "2025-11-07T00:44:27.939Z" }, + { url = "https://files.pythonhosted.org/packages/83/2b/9f6b643fe39d4505c7bf926d7c2595b7cb4b607c8c6b500e56c6b36ac238/wrapt-2.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c1c91405fcf1d501fa5d55df21e58ea49e6b879ae829f1039faaf7e5e509b41e", size = 150325, upload-time = "2025-11-07T00:44:29.29Z" }, + { url = "https://files.pythonhosted.org/packages/bb/b6/20ffcf2558596a7f58a2e69c89597128781f0b88e124bf5a4cadc05b8139/wrapt-2.0.1-cp313-cp313t-win32.whl", hash = "sha256:e76e3f91f864e89db8b8d2a8311d57df93f01ad6bb1e9b9976d1f2e83e18315c", size = 59943, upload-time = "2025-11-07T00:44:33.211Z" }, + { url = "https://files.pythonhosted.org/packages/87/6a/0e56111cbb3320151eed5d3821ee1373be13e05b376ea0870711f18810c3/wrapt-2.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:83ce30937f0ba0d28818807b303a412440c4b63e39d3d8fc036a94764b728c92", size = 63240, upload-time = "2025-11-07T00:44:30.935Z" }, + { url = "https://files.pythonhosted.org/packages/1d/54/5ab4c53ea1f7f7e5c3e7c1095db92932cc32fd62359d285486d00c2884c3/wrapt-2.0.1-cp313-cp313t-win_arm64.whl", hash = "sha256:4b55cacc57e1dc2d0991dbe74c6419ffd415fb66474a02335cb10efd1aa3f84f", size = 60416, upload-time = "2025-11-07T00:44:32.002Z" }, + { url = "https://files.pythonhosted.org/packages/73/81/d08d83c102709258e7730d3cd25befd114c60e43ef3891d7e6877971c514/wrapt-2.0.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:5e53b428f65ece6d9dad23cb87e64506392b720a0b45076c05354d27a13351a1", size = 78290, upload-time = "2025-11-07T00:44:34.691Z" }, + { url = "https://files.pythonhosted.org/packages/f6/14/393afba2abb65677f313aa680ff0981e829626fed39b6a7e3ec807487790/wrapt-2.0.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ad3ee9d0f254851c71780966eb417ef8e72117155cff04821ab9b60549694a55", size = 61255, upload-time = "2025-11-07T00:44:35.762Z" }, + { url = "https://files.pythonhosted.org/packages/c4/10/a4a1f2fba205a9462e36e708ba37e5ac95f4987a0f1f8fd23f0bf1fc3b0f/wrapt-2.0.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d7b822c61ed04ee6ad64bc90d13368ad6eb094db54883b5dde2182f67a7f22c0", size = 61797, upload-time = "2025-11-07T00:44:37.22Z" }, + { url = "https://files.pythonhosted.org/packages/12/db/99ba5c37cf1c4fad35349174f1e38bd8d992340afc1ff27f526729b98986/wrapt-2.0.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7164a55f5e83a9a0b031d3ffab4d4e36bbec42e7025db560f225489fa929e509", size = 120470, upload-time = "2025-11-07T00:44:39.425Z" }, + { url = "https://files.pythonhosted.org/packages/30/3f/a1c8d2411eb826d695fc3395a431757331582907a0ec59afce8fe8712473/wrapt-2.0.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e60690ba71a57424c8d9ff28f8d006b7ad7772c22a4af432188572cd7fa004a1", size = 122851, upload-time = "2025-11-07T00:44:40.582Z" }, + { url = "https://files.pythonhosted.org/packages/b3/8d/72c74a63f201768d6a04a8845c7976f86be6f5ff4d74996c272cefc8dafc/wrapt-2.0.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3cd1a4bd9a7a619922a8557e1318232e7269b5fb69d4ba97b04d20450a6bf970", size = 117433, upload-time = "2025-11-07T00:44:38.313Z" }, + { url = "https://files.pythonhosted.org/packages/c7/5a/df37cf4042cb13b08256f8e27023e2f9b3d471d553376616591bb99bcb31/wrapt-2.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b4c2e3d777e38e913b8ce3a6257af72fb608f86a1df471cb1d4339755d0a807c", size = 121280, upload-time = "2025-11-07T00:44:41.69Z" }, + { url = "https://files.pythonhosted.org/packages/54/34/40d6bc89349f9931e1186ceb3e5fbd61d307fef814f09fbbac98ada6a0c8/wrapt-2.0.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3d366aa598d69416b5afedf1faa539fac40c1d80a42f6b236c88c73a3c8f2d41", size = 116343, upload-time = "2025-11-07T00:44:43.013Z" }, + { url = "https://files.pythonhosted.org/packages/70/66/81c3461adece09d20781dee17c2366fdf0cb8754738b521d221ca056d596/wrapt-2.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c235095d6d090aa903f1db61f892fffb779c1eaeb2a50e566b52001f7a0f66ed", size = 119650, upload-time = "2025-11-07T00:44:44.523Z" }, + { url = "https://files.pythonhosted.org/packages/46/3a/d0146db8be8761a9e388cc9cc1c312b36d583950ec91696f19bbbb44af5a/wrapt-2.0.1-cp314-cp314-win32.whl", hash = "sha256:bfb5539005259f8127ea9c885bdc231978c06b7a980e63a8a61c8c4c979719d0", size = 58701, upload-time = "2025-11-07T00:44:48.277Z" }, + { url = "https://files.pythonhosted.org/packages/1a/38/5359da9af7d64554be63e9046164bd4d8ff289a2dd365677d25ba3342c08/wrapt-2.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:4ae879acc449caa9ed43fc36ba08392b9412ee67941748d31d94e3cedb36628c", size = 60947, upload-time = "2025-11-07T00:44:46.086Z" }, + { url = "https://files.pythonhosted.org/packages/aa/3f/96db0619276a833842bf36343685fa04f987dd6e3037f314531a1e00492b/wrapt-2.0.1-cp314-cp314-win_arm64.whl", hash = "sha256:8639b843c9efd84675f1e100ed9e99538ebea7297b62c4b45a7042edb84db03e", size = 59359, upload-time = "2025-11-07T00:44:47.164Z" }, + { url = "https://files.pythonhosted.org/packages/71/49/5f5d1e867bf2064bf3933bc6cf36ade23505f3902390e175e392173d36a2/wrapt-2.0.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:9219a1d946a9b32bb23ccae66bdb61e35c62773ce7ca6509ceea70f344656b7b", size = 82031, upload-time = "2025-11-07T00:44:49.4Z" }, + { url = "https://files.pythonhosted.org/packages/2b/89/0009a218d88db66ceb83921e5685e820e2c61b59bbbb1324ba65342668bc/wrapt-2.0.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:fa4184e74197af3adad3c889a1af95b53bb0466bced92ea99a0c014e48323eec", size = 62952, upload-time = "2025-11-07T00:44:50.74Z" }, + { url = "https://files.pythonhosted.org/packages/ae/18/9b968e920dd05d6e44bcc918a046d02afea0fb31b2f1c80ee4020f377cbe/wrapt-2.0.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c5ef2f2b8a53b7caee2f797ef166a390fef73979b15778a4a153e4b5fedce8fa", size = 63688, upload-time = "2025-11-07T00:44:52.248Z" }, + { url = "https://files.pythonhosted.org/packages/a6/7d/78bdcb75826725885d9ea26c49a03071b10c4c92da93edda612910f150e4/wrapt-2.0.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e042d653a4745be832d5aa190ff80ee4f02c34b21f4b785745eceacd0907b815", size = 152706, upload-time = "2025-11-07T00:44:54.613Z" }, + { url = "https://files.pythonhosted.org/packages/dd/77/cac1d46f47d32084a703df0d2d29d47e7eb2a7d19fa5cbca0e529ef57659/wrapt-2.0.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2afa23318136709c4b23d87d543b425c399887b4057936cd20386d5b1422b6fa", size = 158866, upload-time = "2025-11-07T00:44:55.79Z" }, + { url = "https://files.pythonhosted.org/packages/8a/11/b521406daa2421508903bf8d5e8b929216ec2af04839db31c0a2c525eee0/wrapt-2.0.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6c72328f668cf4c503ffcf9434c2b71fdd624345ced7941bc6693e61bbe36bef", size = 146148, upload-time = "2025-11-07T00:44:53.388Z" }, + { url = "https://files.pythonhosted.org/packages/0c/c0/340b272bed297baa7c9ce0c98ef7017d9c035a17a6a71dce3184b8382da2/wrapt-2.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3793ac154afb0e5b45d1233cb94d354ef7a983708cc3bb12563853b1d8d53747", size = 155737, upload-time = "2025-11-07T00:44:56.971Z" }, + { url = "https://files.pythonhosted.org/packages/f3/93/bfcb1fb2bdf186e9c2883a4d1ab45ab099c79cbf8f4e70ea453811fa3ea7/wrapt-2.0.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:fec0d993ecba3991645b4857837277469c8cc4c554a7e24d064d1ca291cfb81f", size = 144451, upload-time = "2025-11-07T00:44:58.515Z" }, + { url = "https://files.pythonhosted.org/packages/d2/6b/dca504fb18d971139d232652656180e3bd57120e1193d9a5899c3c0b7cdd/wrapt-2.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:949520bccc1fa227274da7d03bf238be15389cd94e32e4297b92337df9b7a349", size = 150353, upload-time = "2025-11-07T00:44:59.753Z" }, + { url = "https://files.pythonhosted.org/packages/1d/f6/a1de4bd3653afdf91d250ca5c721ee51195df2b61a4603d4b373aa804d1d/wrapt-2.0.1-cp314-cp314t-win32.whl", hash = "sha256:be9e84e91d6497ba62594158d3d31ec0486c60055c49179edc51ee43d095f79c", size = 60609, upload-time = "2025-11-07T00:45:03.315Z" }, + { url = "https://files.pythonhosted.org/packages/01/3a/07cd60a9d26fe73efead61c7830af975dfdba8537632d410462672e4432b/wrapt-2.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:61c4956171c7434634401db448371277d07032a81cc21c599c22953374781395", size = 64038, upload-time = "2025-11-07T00:45:00.948Z" }, + { url = "https://files.pythonhosted.org/packages/41/99/8a06b8e17dddbf321325ae4eb12465804120f699cd1b8a355718300c62da/wrapt-2.0.1-cp314-cp314t-win_arm64.whl", hash = "sha256:35cdbd478607036fee40273be8ed54a451f5f23121bd9d4be515158f9498f7ad", size = 60634, upload-time = "2025-11-07T00:45:02.087Z" }, + { url = "https://files.pythonhosted.org/packages/15/d1/b51471c11592ff9c012bd3e2f7334a6ff2f42a7aed2caffcf0bdddc9cb89/wrapt-2.0.1-py3-none-any.whl", hash = "sha256:4d2ce1bf1a48c5277d7969259232b57645aae5686dba1eaeade39442277afbca", size = 44046, upload-time = "2025-11-07T00:45:32.116Z" }, ] [[package]] From b4054d7f0bb3841e1fddb6c40be88808afd3cdc8 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 23 Jan 2026 13:18:31 -0500 Subject: [PATCH 420/587] infra: expanding ci matrix to cover 3.14 and updating uv version --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 577b42cec..888b6a0fb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ["3.12", "3.13"] + python-version: ["3.12", "3.13", "3.14"] steps: - uses: actions/checkout@v5 @@ -37,7 +37,7 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v6 with: - version: "0.9.6" + version: "0.9.26" python-version: ${{ matrix.python-version }} enable-cache: true @@ -74,7 +74,7 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v6 with: - version: "0.9.6" + version: "0.9.26" python-version: ${{ matrix.python-version }} enable-cache: true From 0f116209da7d396f2d7f33cf8cfc9ab6b327e175 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 16 Jan 2026 13:56:50 -0500 Subject: [PATCH 421/587] docs: adding docs for myopic feature --- docs/source/computational_implementation.rst | 2 +- docs/source/index.rst | 1 + docs/source/myopic.rst | 68 ++++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 docs/source/myopic.rst diff --git a/docs/source/computational_implementation.rst b/docs/source/computational_implementation.rst index f0c4c180e..3893abf5f 100644 --- a/docs/source/computational_implementation.rst +++ b/docs/source/computational_implementation.rst @@ -467,7 +467,7 @@ The Temoa model code is organized into clear, purpose-driven packages: * ``modeling_to_generate_alternatives`` - MGA analysis for exploring near-optimal solutions ([!] untested in v4.0) * ``method_of_morris`` - Sensitivity analysis ([!] untested in v4.0) * ``monte_carlo`` - :doc:`monte_carlo` (Uncertainty quantification) - * ``myopic`` - Sequential decision making with limited foresight + * ``myopic`` - :doc:`myopic` (Sequential decision making with limited foresight) * ``single_vector_mga`` - Focused MGA on specific variables ([!] untested in v4.0) * ``stochastics`` - :doc:`stochastics` (Stochastic programming capabilities) diff --git a/docs/source/index.rst b/docs/source/index.rst index 5e0bde765..fc84d742e 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -5,5 +5,6 @@ Temoa Project Documentation Documentation monte_carlo + myopic unit_checking stochastics diff --git a/docs/source/myopic.rst b/docs/source/myopic.rst new file mode 100644 index 000000000..7f892c3b3 --- /dev/null +++ b/docs/source/myopic.rst @@ -0,0 +1,68 @@ + +.. _myopic: + +Myopic Optimization +=================== + +Myopic (or sequential) optimization in Temoa provides a way to solve the model in a series of smaller, sequential time windows. This is often used to simulate decision-making with limited foresight, where the model only "sees" a limited number of future time periods at any given step. + +Overall Framework +----------------- + +The Myopic extension in Temoa is designed to: + +* Solve the model for a sequence of overlapping or non-overlapping time windows. +* Limit the foresight of the model to a user-specified number of future periods. +* Persist the capacity investment decisions from previous windows as "initial capacity" for subsequent windows. +* Automatically manage the ``myopic_efficiency`` table to filter active technologies based on their remaining lifetime and previous investment decisions. + +Configuration +------------- + +To enable Myopic mode, set the ``scenario_mode`` to ``"myopic"`` in your configuration TOML file and provide the required settings under a ``[myopic]`` section: + +.. code-block:: toml + + scenario_mode = "myopic" + + [myopic] + view_depth = 2 + step_size = 1 + +Settings +~~~~~~~~ + +* **view_depth**: The number of future time periods visible to the model in each iteration. For example, a ``view_depth`` of 2 means the model will optimize over the current period and the next one. +* **step_size**: The number of periods to advance the "base year" in each subsequent iteration. A ``step_size`` of 1 means the base year will move forward by one time period at a time. + +.. important:: + Myopic mode requires that the ``input_database`` and ``output_database`` in your configuration point to the same file. This is because the sequencer needs to write intermediate results (like the ``myopic_efficiency`` table and capacity decisions) back to the database to inform subsequent windows. + +How it Works +------------ + +When running in Myopic mode, Temoa performs the following steps: + +1. **Initialization**: It identifies all future time periods and sets up a queue of "optimization windows" based on the ``view_depth`` and ``step_size``. +2. **Initial Setup**: It creates the ``myopic_efficiency`` table and pre-loads it with any existing capacity from the input database. +3. **Sequential Solve**: For each window in the queue: + a. **Update Efficiency Table**: The ``myopic_efficiency`` table is updated to include only technologies that are still within their lifetime or were built in previous windows. Any "planned" technologies not built in the previous window's look-ahead are removed to prevent "ghost" capacity. + b. **Data Loading**: Data is loaded specifically for the current window's time range, using the ``myopic_efficiency`` table as a filter. + c. **Model Solve**: A standard Temoa model instance is built and solved for the current window. + d. **Result Persistence**: Investment decisions (built and retired capacity) are saved back to the database. These decisions are treated as fixed constraints in all future windows. +4. **Final Reporting**: Once all windows are solved, a total system cost is calculated as the sum of discounted costs across all periods. + +Myopic Efficiency Table +----------------------- + +The ``myopic_efficiency`` table is a key internal component of the myopic sequencer. It acts as a dynamic version of the standard ``efficiency`` table, filtered for each optimization window. + +* It is "actively maintained" during the run. +* Items not built in a previous window's visibility window are removed. +* Items that reach the end of their technical lifetime are retired and removed from the table. +* The table includes a computed ``lifetime`` field used internally to screen active technologies. + +Backtracking and Roll-back +-------------------------- + +If the solver fails to find an optimal solution for a given window (e.g., due to infeasibility caused by previous decisions), the Myopic sequencer has a built-in roll-back mechanism. It will attempt to back up to the previous window and re-solve with an expanded ``view_depth`` to find a feasible path forward. If it cannot back up further, the run will abort with an error. From f277302220f316eaa3081c6c9e8d8a2e9d944e7f Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 16 Jan 2026 22:25:52 -0500 Subject: [PATCH 422/587] docs: adding notes and caveats to myopic docs Co-authored-by: Davey Elder <35704891+idelder@users.noreply.github.com> --- docs/source/myopic.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/source/myopic.rst b/docs/source/myopic.rst index 7f892c3b3..0bdf69f7f 100644 --- a/docs/source/myopic.rst +++ b/docs/source/myopic.rst @@ -66,3 +66,18 @@ Backtracking and Roll-back -------------------------- If the solver fails to find an optimal solution for a given window (e.g., due to infeasibility caused by previous decisions), the Myopic sequencer has a built-in roll-back mechanism. It will attempt to back up to the previous window and re-solve with an expanded ``view_depth`` to find a feasible path forward. If it cannot back up further, the run will abort with an error. + +Notes and Caveats +----------------- + +Performance and Discounting +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* **Reduced Compute**: Myopic mode dramatically reduces compute requirements compared to perfect foresight by using a "divide and conquer" approach, solving several smaller problems instead of one large global optimization. +* **Discounting**: All costs are discounted to the first optimization period in the database (period ``p0`` of the first myopic window). + +Modeling Considerations +~~~~~~~~~~~~~~~~~~~~~~~ + +* **Investment Amortization**: Investment costs in Temoa are amortized over the useful life of a built technology. This harmonizes how the model perceives costs and benefits within the ``view_depth``: since the model only sees the benefits of a technology for the portion of its life that falls within the current window, the costs are similarly distributed. Consequently, discounted investment costs reported in summary logs may be significantly higher than those reported in the ``output_cost`` table. +* **Limited Foresight**: Myopic mode cannot see beyond the specified ``view_depth``, including constraints. If a constraint only becomes active later in the planning horizon, the model may make "stupid but cost-saving" decisions in early windows. This can lead to unexpected rollbacks when those constraints finally enter the visibility window, which can complicate the interpretation of the results. Modeler caution is advised when setting the ``view_depth`` relative to known future constraints. From 72e243d2a62ba96f583d9872c7b85f01ef1e6fcb Mon Sep 17 00:00:00 2001 From: Joe DeCarolis Date: Wed, 4 Feb 2026 08:05:56 -0500 Subject: [PATCH 423/587] Make minor editorial changes to improve clarity --- docs/source/myopic.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/source/myopic.rst b/docs/source/myopic.rst index 0bdf69f7f..a27f4ca2f 100644 --- a/docs/source/myopic.rst +++ b/docs/source/myopic.rst @@ -13,7 +13,7 @@ The Myopic extension in Temoa is designed to: * Solve the model for a sequence of overlapping or non-overlapping time windows. * Limit the foresight of the model to a user-specified number of future periods. -* Persist the capacity investment decisions from previous windows as "initial capacity" for subsequent windows. +* Fix the capacity investment decisions from previous windows as "initial capacity" for subsequent windows. * Automatically manage the ``myopic_efficiency`` table to filter active technologies based on their remaining lifetime and previous investment decisions. Configuration @@ -32,7 +32,7 @@ To enable Myopic mode, set the ``scenario_mode`` to ``"myopic"`` in your configu Settings ~~~~~~~~ -* **view_depth**: The number of future time periods visible to the model in each iteration. For example, a ``view_depth`` of 2 means the model will optimize over the current period and the next one. +* **view_depth**: The number of future time periods visible to the model in eachiteration. For example, a ``view_depth`` of 2 means the model will optimize over two periods at a time. * **step_size**: The number of periods to advance the "base year" in each subsequent iteration. A ``step_size`` of 1 means the base year will move forward by one time period at a time. .. important:: @@ -58,7 +58,7 @@ Myopic Efficiency Table The ``myopic_efficiency`` table is a key internal component of the myopic sequencer. It acts as a dynamic version of the standard ``efficiency`` table, filtered for each optimization window. * It is "actively maintained" during the run. -* Items not built in a previous window's visibility window are removed. +* Items not built in a previous time window are removed. * Items that reach the end of their technical lifetime are retired and removed from the table. * The table includes a computed ``lifetime`` field used internally to screen active technologies. @@ -80,4 +80,4 @@ Modeling Considerations ~~~~~~~~~~~~~~~~~~~~~~~ * **Investment Amortization**: Investment costs in Temoa are amortized over the useful life of a built technology. This harmonizes how the model perceives costs and benefits within the ``view_depth``: since the model only sees the benefits of a technology for the portion of its life that falls within the current window, the costs are similarly distributed. Consequently, discounted investment costs reported in summary logs may be significantly higher than those reported in the ``output_cost`` table. -* **Limited Foresight**: Myopic mode cannot see beyond the specified ``view_depth``, including constraints. If a constraint only becomes active later in the planning horizon, the model may make "stupid but cost-saving" decisions in early windows. This can lead to unexpected rollbacks when those constraints finally enter the visibility window, which can complicate the interpretation of the results. Modeler caution is advised when setting the ``view_depth`` relative to known future constraints. +* **Limited Foresight**: Myopic mode cannot see beyond the specified ``view_depth``, including constraints. If a constraint only becomes active later in the planning horizon, the model may make sub-optimal decisions in early time windows. This can lead to unexpected rollbacks when those constraints finally enter the visibility window, which can complicate the interpretation of the results. Modeler caution is advised when setting the ``view_depth`` relative to known future constraints. From b469c7f26a8488e604ac9a8d629e75957079d5d2 Mon Sep 17 00:00:00 2001 From: Joe DeCarolis Date: Wed, 4 Feb 2026 08:28:06 -0500 Subject: [PATCH 424/587] Fix single spelling issue --- docs/source/myopic.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/myopic.rst b/docs/source/myopic.rst index a27f4ca2f..8229c1f34 100644 --- a/docs/source/myopic.rst +++ b/docs/source/myopic.rst @@ -32,7 +32,7 @@ To enable Myopic mode, set the ``scenario_mode`` to ``"myopic"`` in your configu Settings ~~~~~~~~ -* **view_depth**: The number of future time periods visible to the model in eachiteration. For example, a ``view_depth`` of 2 means the model will optimize over two periods at a time. +* **view_depth**: The number of future time periods visible to the model in each iteration. For example, a ``view_depth`` of 2 means the model will optimize over two periods at a time. * **step_size**: The number of periods to advance the "base year" in each subsequent iteration. A ``step_size`` of 1 means the base year will move forward by one time period at a time. .. important:: From b2f1501d14e17ef632f7264e889579fa5f655345 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Mon, 19 Jan 2026 09:11:50 -0500 Subject: [PATCH 425/587] docs: adding docs for mga feature --- docs/source/computational_implementation.rst | 4 +- docs/source/index.rst | 1 + docs/source/mga.rst | 151 +++++++++++++++++++ 3 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 docs/source/mga.rst diff --git a/docs/source/computational_implementation.rst b/docs/source/computational_implementation.rst index 3893abf5f..24aef4ffa 100644 --- a/docs/source/computational_implementation.rst +++ b/docs/source/computational_implementation.rst @@ -464,11 +464,11 @@ The Temoa model code is organized into clear, purpose-driven packages: * ``temoa.extensions`` - Optional extensions for advanced analysis - * ``modeling_to_generate_alternatives`` - MGA analysis for exploring near-optimal solutions ([!] untested in v4.0) + * ``modeling_to_generate_alternatives`` - :doc:`mga` (MGA analysis for exploring near-optimal solutions) * ``method_of_morris`` - Sensitivity analysis ([!] untested in v4.0) * ``monte_carlo`` - :doc:`monte_carlo` (Uncertainty quantification) * ``myopic`` - :doc:`myopic` (Sequential decision making with limited foresight) - * ``single_vector_mga`` - Focused MGA on specific variables ([!] untested in v4.0) + * ``single_vector_mga`` - :doc:`mga` (Focused MGA on specific variables) * ``stochastics`` - :doc:`stochastics` (Stochastic programming capabilities) * ``temoa._internal`` - Internal utilities (not part of public API) diff --git a/docs/source/index.rst b/docs/source/index.rst index fc84d742e..63c3f8f7f 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -8,3 +8,4 @@ Temoa Project Documentation myopic unit_checking stochastics + mga diff --git a/docs/source/mga.rst b/docs/source/mga.rst new file mode 100644 index 000000000..d88770240 --- /dev/null +++ b/docs/source/mga.rst @@ -0,0 +1,151 @@ +.. _mga: + +Modeling to Generate Alternatives (MGA) +======================================= + +Temoa provides two extensions for Modeling to Generate Alternatives (MGA): the standard iterative MGA and the Single-Vector MGA (SVMGA). Both methods are designed to explore the "near-optimal" solution space, helping users identify alternative energy system configurations that have similar total costs but different characteristics (e.g., higher utilization of a specific technology or lower emissions). + +Standard MGA +------------ + +The standard MGA extension implements an iterative algorithm to explore the boundaries of the near-optimal solution space. It works by relaxing the total system cost by a user-specified percentage (epsilon) and then iteratively optimizing along different axes to find extreme points. + +Configuration +~~~~~~~~~~~~~ + +To enable standard MGA, set the ``scenario_mode`` to ``"mga"`` in your configuration TOML file and provide an ``[MGA]`` section: + +.. code-block:: toml + + scenario_mode = "mga" + + [MGA] + cost_epsilon = 0.05 # Relax cost by 5% + iteration_limit = 20 # Maximum number of MGA iterations + time_limit_hrs = 12 # Stop after 12 hours + axis = "TECH_CATEGORY_ACTIVITY" + weighting = "HULL_EXPANSION" + +Options +^^^^^^^ + +* **cost_epsilon**: The fraction by which the optimal cost is allowed to increase (e.g., ``0.05`` for 5%). +* **iteration_limit**: The maximum number of alternative solutions to generate. +* **time_limit_hrs**: The maximum wall-clock time for the entire MGA run. +* **axis**: The dimension along which to optimize. Supported values: + * ``TECH_CAPACITY`` + * ``TECH_CATEGORY_CAPACITY`` + * ``TECH_CATEGORY_ACTIVITY`` (Default) + * ``EMISSION_ACTIVITY`` +* **weighting**: The algorithm used to select the next optimization vector. Currently, only ``HULL_EXPANSION`` is supported. + +Single-Vector MGA (SVMGA) +------------------------- + +Single-Vector MGA is a simplified, two-stage process. First, it solves the base model to find the optimal cost. Second, it adds a cost relaxation constraint and optimizes a new objective function defined by the user to "push" the model in a specific direction. + +Configuration +~~~~~~~~~~~~~ + +To enable SVMGA, set the ``scenario_mode`` to ``"svmga"`` and provide an ``[SVMGA]`` section: + +.. code-block:: toml + + scenario_mode = "svmga" + + [SVMGA] + cost_epsilon = 0.05 + capacity_labels = ["solar_pv", "wind_onshore"] + # emissions_labels = ["CO2"] + # activity_labels = ["coal_power"] + +Options +^^^^^^^ + +* **cost_epsilon**: Same as in standard MGA. +* **capacity_labels**: A list of technology names whose total capacity should be maximized in the second stage. Matching is **exact and case-sensitive** against the identifiers in the ``tech_all`` set. Example: ``["solar_pv", "wind_onshore"]``. +* **emissions_labels**: A list of emission commodities whose total emissions should be minimized. Matching is **exact and case-sensitive** against identifiers in the ``commodity_emissions`` set. Example: ``["CO2"]``. +* **activity_labels**: A list of technology names whose total activity (energy flow out) should be maximized. Matching is **exact and case-sensitive**. Example: ``["coal_power"]``. + +Note: SVMGA will construct an unweighted sum of all variables matching these labels as the new objective function. + +Parallel Execution and Solver Options +------------------------------------- + +Standard MGA supports parallel execution of iterative solves to maximize performance. **Note: SVMGA executes sequentially and does not utilize parallel workers.** + +The number of worker processes and solver-specific settings are defined in a ``MGA_solver_options.toml`` file. By default, Temoa looks for this file in the same directory as your main configuration file. + +.. code-block:: toml + + # Global setting at the top level of the file + num_workers = 4 + + [gurobi] + Method = 2 + Threads = 4 # Threads per solver instance + BarConvTol = 0.01 + +.. tip:: + When choosing ``num_workers``, a good rule of thumb is to set it to the number of available CPU cores minus one. This leaves room for the main orchestration process and ensures that the system remains responsive. Also, be mindful of the ``Threads`` setting within solver blocks, as the total thread count will be ``num_workers * Threads``. + +Outputs +------- + +MGA results are stored in the same output database specified in your configuration. Each iteration is saved as a unique scenario to allow for easy comparison and analysis. + +Scenario Naming Convention +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Each run is saved under a unique scenario name in the output tables, following the format: ``-``. + +* **Iteration 0**: The original baseline solve (optimal solution). +* **Iterations 1-N**: The alternative solutions generated by the MGA algorithm. + +For example, if your base scenario is ``utopia_mga``, the results for the base case will be found under scenario ``utopia_mga-0``, and the first alternative will be under ``utopia_mga-1``. + +Key Database Tables +~~~~~~~~~~~~~~~~~~~ + +The results are spread across several tables, consistent with standard Temoa runs: + +* **output_objective**: Stores the total system cost and MGA optimization objective for each iteration. +* **output_net_capacity**: Stores the installed capacity for each technology, period, and iteration. +* **output_flow_out** / **output_flow_out_summary**: Stores energy flows between technologies. +* **output_emission**: Stores emission results per commodity and technology. +* **output_cost**: Stores detailed cost breakdowns (investment, fixed, variable). + +Comparing Iterations +~~~~~~~~~~~~~~~~~~~~ + +You can use SQL queries to compare results across different MGA iterations. + +**Comparing Total System Cost:** + +.. code-block:: sql + + SELECT scenario, total_system_cost + FROM output_objective + WHERE scenario LIKE 'utopia_mga-%' + ORDER BY scenario; + +**Comparing Capacity for a Specific Technology:** + +.. code-block:: sql + + SELECT scenario, tech, period, capacity, units + FROM output_net_capacity + WHERE scenario LIKE 'utopia_mga-%' + AND tech = 'solar_pv' + ORDER BY scenario, period; + +**Analyzing Diversity (SQL Join Example):** + +.. code-block:: sql + + SELECT a.scenario, a.tech, a.capacity as cap_a, b.capacity as cap_b, (a.capacity - b.capacity) as diff + FROM output_net_capacity a + JOIN output_net_capacity b ON a.tech = b.tech AND a.period = b.period + WHERE a.scenario = 'utopia_mga-1' + AND b.scenario = 'utopia_mga-0' + AND a.tech = 'solar_pv'; From c464790596f0ac7713a22525989984c3948c4723 Mon Sep 17 00:00:00 2001 From: Joe DeCarolis Date: Fri, 6 Feb 2026 13:10:06 -0500 Subject: [PATCH 426/587] Update and clarify MGA documentation --- docs/source/mga.rst | 78 +++++++++++++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 21 deletions(-) diff --git a/docs/source/mga.rst b/docs/source/mga.rst index d88770240..5ad0a8c5b 100644 --- a/docs/source/mga.rst +++ b/docs/source/mga.rst @@ -3,17 +3,24 @@ Modeling to Generate Alternatives (MGA) ======================================= -Temoa provides two extensions for Modeling to Generate Alternatives (MGA): the standard iterative MGA and the Single-Vector MGA (SVMGA). Both methods are designed to explore the "near-optimal" solution space, helping users identify alternative energy system configurations that have similar total costs but different characteristics (e.g., higher utilization of a specific technology or lower emissions). +Temoa provides two extensions for Modeling to Generate Alternatives (MGA), an +algorithm to explore the near-optimal solution space: hull expansion and +single-vector MGA. Both are described in more detail below. -Standard MGA ------------- +Hull Expansion +-------------- -The standard MGA extension implements an iterative algorithm to explore the boundaries of the near-optimal solution space. It works by relaxing the total system cost by a user-specified percentage (epsilon) and then iteratively optimizing along different axes to find extreme points. +Hull expansion creates the convex hull containing all near-optimal solutions +bound by the extreme points along a particular solution axis and then samples +the continuum of solutions. The size of the convex hull is determined by the +degree of cost relaxation (``cost_epsilon``). The method is described in +`Pedersen et al. (2021) `_ Configuration ~~~~~~~~~~~~~ -To enable standard MGA, set the ``scenario_mode`` to ``"mga"`` in your configuration TOML file and provide an ``[MGA]`` section: +To enable hull expansion, set the ``scenario_mode`` to ``"mga"`` in your +configuration TOML file and provide an ``[MGA]`` section: .. code-block:: toml @@ -29,7 +36,8 @@ To enable standard MGA, set the ``scenario_mode`` to ``"mga"`` in your configura Options ^^^^^^^ -* **cost_epsilon**: The fraction by which the optimal cost is allowed to increase (e.g., ``0.05`` for 5%). +* **cost_epsilon**: The fraction by which the optimal cost is allowed to increase + (e.g., ``0.05`` for 5%). * **iteration_limit**: The maximum number of alternative solutions to generate. * **time_limit_hrs**: The maximum wall-clock time for the entire MGA run. * **axis**: The dimension along which to optimize. Supported values: @@ -37,17 +45,23 @@ Options * ``TECH_CATEGORY_CAPACITY`` * ``TECH_CATEGORY_ACTIVITY`` (Default) * ``EMISSION_ACTIVITY`` -* **weighting**: The algorithm used to select the next optimization vector. Currently, only ``HULL_EXPANSION`` is supported. +* **weighting**: The algorithm used to select the next optimization vector. + Currently, only ``HULL_EXPANSION`` is supported. Single-Vector MGA (SVMGA) ------------------------- -Single-Vector MGA is a simplified, two-stage process. First, it solves the base model to find the optimal cost. Second, it adds a cost relaxation constraint and optimizes a new objective function defined by the user to "push" the model in a specific direction. +Single-Vector MGA is a simplified, two-stage process. First, it solves the base +model to find the minimum cost. Second, it adds a cost relaxation constraint and +creates a new objective function that minimizes user-specified quantities, such +as technology-specific installed capacity or total carbon dioxide emissions. + Configuration ~~~~~~~~~~~~~ -To enable SVMGA, set the ``scenario_mode`` to ``"svmga"`` and provide an ``[SVMGA]`` section: +To enable SVMGA, set the ``scenario_mode`` to ``"svmga"`` and provide an +``[SVMGA]`` section: .. code-block:: toml @@ -62,19 +76,32 @@ To enable SVMGA, set the ``scenario_mode`` to ``"svmga"`` and provide an ``[SVMG Options ^^^^^^^ -* **cost_epsilon**: Same as in standard MGA. -* **capacity_labels**: A list of technology names whose total capacity should be maximized in the second stage. Matching is **exact and case-sensitive** against the identifiers in the ``tech_all`` set. Example: ``["solar_pv", "wind_onshore"]``. -* **emissions_labels**: A list of emission commodities whose total emissions should be minimized. Matching is **exact and case-sensitive** against identifiers in the ``commodity_emissions`` set. Example: ``["CO2"]``. -* **activity_labels**: A list of technology names whose total activity (energy flow out) should be maximized. Matching is **exact and case-sensitive**. Example: ``["coal_power"]``. - -Note: SVMGA will construct an unweighted sum of all variables matching these labels as the new objective function. +* **cost_epsilon**: Same as in hull expansion. +* **capacity_labels**: A list of technology names whose total capacity should be + maximized in the second stage. Matching is **exact and case-sensitive** against + the identifiers in the ``tech_all`` set. Example: ``["solar_pv", "wind_onshore"]``. +* **emissions_labels**: A list of emission commodities whose total emissions + should be minimized. Matching is **exact and case-sensitive** against + identifiers in the ``commodity_emissions`` set. Example: ``["CO2"]``. +* **activity_labels**: A list of technology names whose total activity + (energy flow out) should be maximized. Matching is **exact and case-sensitive**. + Example: ``["coal_power"]``. + +Note: SVMGA will construct an unweighted sum of all variables matching these +labels as the new objective function. Be careful not to mix different units. In +addition, note that the MGA objective function is set to minimize regardless of +the label choice. Parallel Execution and Solver Options ------------------------------------- -Standard MGA supports parallel execution of iterative solves to maximize performance. **Note: SVMGA executes sequentially and does not utilize parallel workers.** +Standard MGA supports parallel execution of iterative solves to maximize +performance. **Note: SVMGA executes sequentially and does not utilize parallel +workers.** -The number of worker processes and solver-specific settings are defined in a ``MGA_solver_options.toml`` file. By default, Temoa looks for this file in the same directory as your main configuration file. +The number of worker processes and solver-specific settings are defined in a +``MGA_solver_options.toml`` file. By default, Temoa looks for this file in the +same directory as your main configuration file. .. code-block:: toml @@ -87,22 +114,31 @@ The number of worker processes and solver-specific settings are defined in a ``M BarConvTol = 0.01 .. tip:: - When choosing ``num_workers``, a good rule of thumb is to set it to the number of available CPU cores minus one. This leaves room for the main orchestration process and ensures that the system remains responsive. Also, be mindful of the ``Threads`` setting within solver blocks, as the total thread count will be ``num_workers * Threads``. + When choosing ``num_workers``, a good rule of thumb is to set it to the + number of available CPU cores minus one. This leaves room for the main + orchestration process and ensures that the system remains responsive. Also, + be mindful of the ``Threads`` setting within solver blocks, as the total + thread count will be ``num_workers * Threads``. Outputs ------- -MGA results are stored in the same output database specified in your configuration. Each iteration is saved as a unique scenario to allow for easy comparison and analysis. +MGA results are stored in the same output database specified in your +configuration. Each iteration is saved as a unique scenario to allow for easy +comparison and analysis. Scenario Naming Convention ~~~~~~~~~~~~~~~~~~~~~~~~~~ -Each run is saved under a unique scenario name in the output tables, following the format: ``-``. +Each run is saved under a unique scenario name in the output tables, following +the format: ``-``. * **Iteration 0**: The original baseline solve (optimal solution). * **Iterations 1-N**: The alternative solutions generated by the MGA algorithm. -For example, if your base scenario is ``utopia_mga``, the results for the base case will be found under scenario ``utopia_mga-0``, and the first alternative will be under ``utopia_mga-1``. +For example, if your base scenario is ``utopia_mga``, the results for the base +case will be found under scenario ``utopia_mga-0``, and the first alternative +will be under ``utopia_mga-1``. Key Database Tables ~~~~~~~~~~~~~~~~~~~ From b4b066323e6665c4ecedc7b2af9003b88a486808 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 12 Feb 2026 17:50:21 -0500 Subject: [PATCH 427/587] Fix survival curve initialisation lifetime check --- temoa/components/technology.py | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/temoa/components/technology.py b/temoa/components/technology.py index 49c16c4fc..8ed17f284 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -297,24 +297,16 @@ def create_survival_curve(model: TemoaModel) -> None: logger.info(msg) # Make sure the lifetime for this process aligns with survival curve end - if value(model.lifetime_process[r, t, v]) < p - v: + if round(value(model.lifetime_process[r, t, v])) != p - v: msg = ( - f'The lifetime_process parameter for process ({r, t, v}) with survival ' - f'curve does not extend beyond the end of that survival curve in {p}. To ' - 'agree with ' - f'the survival curve, set lifetime_process[{r, t, v}] >= {p - v}' + f'The lifetime_process parameter ' + f'({round(value(model.lifetime_process[r, t, v]))}) for process ' + f'{r, t, v} with survival curve does not agree with the end of that ' + f'survival curve in {p}. To agree with ' + f'the survival curve, set lifetime_process[{r, t, v}] = {p - v}' ) logger.error(msg) raise ValueError(msg) - elif value(model.lifetime_process[r, t, v]) != p - v: - msg = ( - f'The lifetime_process parameter for process ({r, t, v}) with survival ' - 'curve ' - f'does match the end of that survival curve in {p}. This will waste ' - 'compute. To agree with the survival curve and suppress this warning, set ' - f'lifetime_process[{r, t, v}] = {p - v}' - ) - logger.warning(msg) continue From bb32cb67920e93715a92c6fda4510db44ce63490 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Feb 2026 18:10:10 -0500 Subject: [PATCH 428/587] Fix network model checking lifetime_survival_curve --- temoa/model_checking/network_model_data.py | 9 +++------ tests/test_network_model_data.py | 10 +++++----- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index 62ed54e3f..d2d11bea8 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -197,12 +197,9 @@ def _fetch_basic_data(cur: sqlite3.Cursor) -> BasicData: tech_retire = { t[0] for t in cur.execute('SELECT tech FROM technology WHERE retire==1').fetchall() } - try: - tech_survival_curve = set( - cur.execute('SELECT DISTINCT region, tech, vintage FROM survival_curve').fetchall() - ) - except sqlite3.OperationalError: - tech_survival_curve = set() + tech_survival_curve = set( + cur.execute('SELECT DISTINCT region, tech, vintage FROM lifetime_survival_curve').fetchall() + ) periods_full = sorted(p[0] for p in cur.execute('SELECT period FROM time_period').fetchall()) periods = periods_full[:-1] diff --git a/tests/test_network_model_data.py b/tests/test_network_model_data.py index f9ed609b9..dba71cced 100644 --- a/tests/test_network_model_data.py +++ b/tests/test_network_model_data.py @@ -31,7 +31,7 @@ class ScenarioType(TypedDict): 'name': 'basic', 'db_data': { 'technology WHERE retire==1': [], - 'FROM survival_curve': [], + 'FROM lifetime_survival_curve': [], 'FROM time_period': [(2020,), (2025,)], # Unique keys for each commodity query 'FROM main.commodity': [('s1',), ('p1',), ('p2',), ('p3',), ('d1',), ('d2',)], @@ -82,7 +82,7 @@ class ScenarioType(TypedDict): 'name': 'bad linked tech', 'db_data': { 'technology WHERE retire==1': [], - 'FROM survival_curve': [], + 'FROM lifetime_survival_curve': [], 'FROM time_period': [(2020,), (2025,)], 'FROM main.commodity': [('s1',), ('p1',), ('p3',), ('d1',), ('d2',)], "commodity WHERE flag LIKE '%p%'": [('s1',), ('p3',), ('d1',), ('d2',)], @@ -119,7 +119,7 @@ class ScenarioType(TypedDict): 'name': 'good linked tech', 'db_data': { 'technology WHERE retire==1': [], - 'FROM survival_curve': [], + 'FROM lifetime_survival_curve': [], 'FROM time_period': [(2020,), (2025,)], 'FROM main.commodity': [('s1',), ('p1',), ('d1',), ('d2',), ('s2',)], "commodity WHERE flag LIKE '%p%'": [('s1',), ('d1',), ('d2',), ('s2',)], @@ -277,7 +277,7 @@ def dispatcher(query: str, *_: object) -> MagicMock: m = MagicMock() m.fetchall.return_value = [] return m - elif 'FROM survival_curve' in query: + elif 'FROM lifetime_survival_curve' in query: m = MagicMock() m.fetchall.return_value = [] return m @@ -361,7 +361,7 @@ def dispatcher(query: str, *_: object) -> MagicMock: m = MagicMock() m.fetchall.return_value = [] return m - elif 'FROM survival_curve' in query: + elif 'FROM lifetime_survival_curve' in query: m = MagicMock() m.fetchall.return_value = [] return m From 1a3a530991a68af90aa15393dacb567a799e676b Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 5 Mar 2026 12:15:28 -0500 Subject: [PATCH 429/587] refactor: remove unmaintained breakeven extension --- temoa/extensions/breakeven/README.txt | 3 - temoa/extensions/breakeven/breakeven.py | 1124 ----------------------- 2 files changed, 1127 deletions(-) delete mode 100644 temoa/extensions/breakeven/README.txt delete mode 100644 temoa/extensions/breakeven/breakeven.py diff --git a/temoa/extensions/breakeven/README.txt b/temoa/extensions/breakeven/README.txt deleted file mode 100644 index 339003393..000000000 --- a/temoa/extensions/breakeven/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -This extension is currently NOT maintained and is retained as a framework for possible future use. - -1 JUN 2024 \ No newline at end of file diff --git a/temoa/extensions/breakeven/breakeven.py b/temoa/extensions/breakeven/breakeven.py deleted file mode 100644 index c021899ed..000000000 --- a/temoa/extensions/breakeven/breakeven.py +++ /dev/null @@ -1,1124 +0,0 @@ -import os -import sys -from collections import defaultdict -from time import time - -import cplex -import CplexSolverError -import pandas as pd -from matplotlib import pyplot as plt -from openpyxl import Workbook -from pyomo.environ import * -from pyomo.opt import SolverFactory -from pyomo.repn import generate_canonical_repn -from temoa_model import temoa_create_model - - -def return_Temoa_model(): - model = temoa_create_model() - - model.dual = Suffix(direction=Suffix.IMPORT) - model.rc = Suffix(direction=Suffix.IMPORT) - model.slack = Suffix(direction=Suffix.IMPORT) - model.lrc = Suffix(direction=Suffix.IMPORT) - model.urc = Suffix(direction=Suffix.IMPORT) - return model - - -def return_Temoa_data(model, list_dat): - data = DataPortal(model=model) - for d in list_dat: - data.load(filename=d) - return data - - -def return_c_vector(block, unfixed): - # Note that this function is adapted function collect_linear_terms defined - # in pyomo/repn/collect.py. - - # - # Variables are constraints of block - # Constraints are unfixed variables of block and the parent model. - # - vnames = set() - for name, data in block.component_map(Constraint, active=True).items(): - vnames.add((name, data.is_indexed())) - cnames = set(unfixed) - for name, data in block.component_map(Var, active=True).items(): - cnames.add((name, data.is_indexed())) - # - A = {} - b_coef = {} - c_rhs = {} - c_sense = {} - d_sense = None - v_domain = {} - # - # Collect objective - # - for oname, odata in block.component_map(Objective, active=True).items(): - for ndx in odata: - if odata[ndx].sense == maximize: - o_terms = generate_canonical_repn(-1 * odata[ndx].expr, compute_values=False) - d_sense = minimize - else: - o_terms = generate_canonical_repn(odata[ndx].expr, compute_values=False) - d_sense = maximize - for i in range(len(o_terms.variables)): - c_rhs[ - o_terms.variables[i].parent_component().local_name, o_terms.variables[i].index() - ] = o_terms.linear[i] - # Stop after the first objective - break - return c_rhs - - -def coef_IC(instance, target_tech, target_year): - # This function returns coefficient associated with IC given t, v - t = target_tech - v = target_year - P_0 = min(instance.time_optimize) - P_e = instance.time_future.last() - GDR = value(instance.global_discount_rate) - MPL = instance.ModelProcessLife - LLN = instance.loan_lifetime_process - x = 1 + GDR # convenience variable, nothing more. - period_available = set() - for p in instance.time_future: - if (p, t, v) in instance.cost_fixed.keys(): - period_available.add(p) - c_i = ( - instance.cost_invest[t, v] - * instance.loan_annualize[t, v] - * (LLN[t, v] if not GDR else (x ** (P_0 - v + 1) * (1 - x ** (-value(LLN[t, v]))) / GDR)) - ) * ( - (1 - x ** (-min(value(instance.lifetime_process[t, v]), P_e - v))) - / (1 - x ** (-value(instance.lifetime_process[t, v]))) - ) - return value(c_i) - - -def coef_FC(instance, target_tech, target_year): - # This function returns coefficient associated with FC given t, v - t = target_tech - v = target_year - P_0 = min(instance.time_optimize) - P_e = instance.time_future.last() - GDR = value(instance.global_discount_rate) - MPL = instance.ModelProcessLife - LLN = instance.loan_lifetime_process - x = 1 + GDR # convenience variable, nothing more. - period_available = set() - for p in instance.time_future: - if (p, t, v) in instance.cost_fixed.keys(): - period_available.add(p) - - c_f = sum( - instance.cost_fixed[p, t, v] - * ( - MPL[p, t, v] - if not GDR - else (x ** (P_0 - p + 1) * (1 - x ** (-value(MPL[p, t, v]))) / GDR) - ) - for p in period_available - ) - return value(c_f) - - -def validate_coef(c0, instance, target_tech, target_year): - # This function validates if c0 equals the correct coefficient of process - # (target_tech, target_year) - c_i = coef_IC(instance, target_tech, target_year) - c_f = coef_FC(instance, target_tech, target_year) - c = c_i + c_f - if value(c - c0) <= 1e-5: # Compatible with Pyomo 5.5 - return True - else: - return False - - -def sensitivity(dat, techs): - # This function performs break-even analysis for technologies specified in - # the argument techs. It uses suffix from Pyomo and returns the breakeven - # cost as screen outputs. Note that the Pyomo suffix sometimes returns - # anomalous values, and that's why I create another function, - # sensitivity_api() to use Python API for CPLEX. - - model = temoa_create_model() - - model.dual = Suffix(direction=Suffix.IMPORT) - model.rc = Suffix(direction=Suffix.IMPORT) - model.slack = Suffix(direction=Suffix.IMPORT) - model.lrc = Suffix(direction=Suffix.IMPORT) - model.urc = Suffix(direction=Suffix.IMPORT) - - data = DataPortal(model=model) - for d in dat: - data.load(filename=d) - instance = model.create_instance(data) - optimizer = SolverFactory('cplex') - optimizer.options['lpmethod'] = 1 # Use primal simplex - results = optimizer.solve(instance, suffixes=['dual', 'urc', 'slack', 'lrc']) - instance.solutions.load_from(results) - - coef_CAP = dict() - scal_CAP = dict() - # Break-even investment cost for this scenario, indexed by technology - years = list() - bic_s = dict() - ic_s = dict() # Raw investment costs for this scenario, indexed by tech - cap_s = dict() - for t in techs: - vintages = instance.vintage_optimize - P_0 = min(instance.time_optimize) - GDR = value(instance.global_discount_rate) - MPL = instance.ModelProcessLife - LLN = instance.loan_lifetime_process - x = 1 + GDR # convenience variable, nothing more. - - bic_s[t] = list() - ic_s[t] = list() - cap_s[t] = list() - years = vintages.value - for v in vintages: - period_available = set() - for p in instance.time_future: - if (p, t, v) in instance.cost_fixed.keys(): - period_available.add(p) - c_i = ( - instance.cost_invest[t, v] - * instance.loan_annualize[t, v] - * ( - LLN[t, v] - if not GDR - else (x ** (P_0 - v + 1) * (1 - x ** (-value(LLN[t, v]))) / GDR) - ) - ) - - c_s = (-1) * ( - value(instance.cost_invest[t, v]) - * value(instance.SalvageRate[t, v]) - / ( - 1 - if not GDR - else (1 + GDR) - ** (instance.time_future.last() - instance.time_future.first() - 1) - ) - ) - - c_f = sum( - instance.cost_fixed[p, t, v] - * ( - MPL[p, t, v] - if not GDR - else (x ** (P_0 - p + 1) * (1 - x ** (-value(MPL[p, t, v]))) / GDR) - ) - for p in period_available - ) - - c = c_i + c_s + c_f - s = (c - instance.lrc[instance.v_capacity[t, v]]) / c - coef_CAP[t, v] = c - scal_CAP[t, v] = s # Must reduce TO this percentage - bic_s[t].append(scal_CAP[t, v] * instance.cost_invest[t, v]) - ic_s[t].append(instance.cost_invest[t, v]) - cap_s[t].append(value(instance.v_capacity[t, v])) - - # print("Tech\tVintage\tL. RC\tCoef\tU .RC\tScale\tBE IC\tBE FC\tIC\tFC\tCap") - print( - '{:>10s}\t{:>7s}\t{:>6s}\t{:>4s}\t{:>6s}\t{:>5s}\t{:>7s}\t{:>7s}\t{:>5s}\t{:>3s}\t{:>5s}'.format( - 'Tech', - 'Vintage', - 'L. RC', - 'Coef', - 'U. RC', - 'Scale', - 'BE IC', - 'BE FC', - 'IC', - 'FC', - 'Cap', - ) - ) - for v in vintages: - lrc = instance.lrc[instance.v_capacity[t, v]] - urc = instance.urc[instance.v_capacity[t, v]] - - # print("{:>s}\t{:>g}\t{:>.0f}\t{:>.0f}\t{:>.0f}\t{:>.3f}\t{:>.1f}\t{:>.1f}\t{:>.0f}\t" - # "{:>.0f}\t{:>.3f}".format() - print( - '{:>10s}\t{:>7g}\t{:>6.0f}\t{:>4.0f}\t{:>6.0f}\t{:>5.3f}\t{:>7.1f}\t{:>7.1f}\t{:>5.0f}\t{:>3.0f}\t{:>5.3f}'.format( - t, - v, - lrc, - coef_CAP[t, v], - urc, - scal_CAP[t, v], - scal_CAP[t, v] * instance.cost_invest[t, v], - scal_CAP[t, v] * instance.cost_fixed[v, t, v], # Use the FC of the first period - instance.cost_invest[t, v], - instance.cost_fixed[v, t, v], - value(instance.v_capacity[t, v]), - ) - ) - - print('Dual and slack variables for emission caps:') - for e in instance.commodity_emissions: - for p in instance.time_optimize: - if (p, e) in instance.EmissionLimitConstraint: - print( - p, - e, - instance.dual[instance.EmissionLimitConstraint[p, e]], - '\t', - instance.slack[instance.EmissionLimitConstraint[p, e]], - ) - return years, bic_s, ic_s - - print('Dual and slack variables for Commodity Demand Constraints') - for c in instance.commodity_demand: - for p in instance.time_optimize: - for s in instance.time_season: - for tod in instance.time_of_day: - print( - p, - s, - tod, - instance.dual[instance.demand_constraint[p, s, tod, c]], - instance.slack[instance.demand_constraint[p, s, tod, c]], - ) - - -def sensitivity_api(instance, techs, algorithm=None): - # This code block realizes the same function as sensitivity(), however - # because I am using Python API for CPLEX here, it only works when the - # solver is CPLEX. I also updated the returned value and now it is a pandas - # DataFramework, which supports fast csv creation. - - instance.write('tmp.lp', io_options={'symbolic_solver_labels': True}) - c = cplex.Cplex('tmp.lp') - os.remove('tmp.lp') - c.set_results_stream(None) # Turn screen output off - - msg = '' - if algorithm: - if algorithm == 'o': - c.parameters.lpmethod.set(c.parameters.lpmethod.values.auto) - elif algorithm == 'p': - c.parameters.lpmethod.set(c.parameters.lpmethod.values.primal) - elif algorithm == 'd': - c.parameters.lpmethod.set(c.parameters.lpmethod.values.dual) - elif algorithm == 'b': - c.parameters.lpmethod.set(c.parameters.lpmethod.values.barrier) - c.parameters.barrier.crossover.set(c.parameters.barrier.crossover.values.none) - elif algorithm == 'h': - c.parameters.lpmethod.set(c.parameters.lpmethod.values.barrier) - elif algorithm == 's': - c.parameters.lpmethod.set(c.parameters.lpmethod.values.sifting) - elif algorithm == 'c': - c.parameters.lpmethod.set(c.parameters.lpmethod.values.concurrent) - else: - raise ValueError('method must be one of "o", "p", "d", "b", "h", "s" or "c"') - - try: - c.solve() - except CplexSolverError: - print('Exception raised during solve') - return - - vintages = list(instance.vintage_optimize) - coef_CAP = dict() - scal_CAP = dict() - # Break-even investment cost for this scenario, indexed by technology - years = list() - bic_s = dict() - ic_s = dict() # Raw investment costs for this scenario, indexed by tech - cap_s = dict() - clb_s = dict() - cub_s = dict() - results = list() - for t in techs: - bic_s[t] = list() - ic_s[t] = list() - cap_s[t] = list() - for v in vintages: - target_var = 'v_capacity(' + t + '_' + str(v) + ')' - c0 = c.objective.get_linear(target_var) - clb, cub = c.solution.sensitivity.objective( - target_var - ) # Coefficient lower bound, coefficient upper bound - if cub > 1e5: - cub = 0 # Infinity - clb_s[t, v], cub_s[t, v] = clb, cub - c_i = coef_IC(instance, t, v) - c_f = coef_FC(instance, t, v) - if not validate_coef(c0, instance, t, v): - print('Error: Check coefficients!') - sys.exit(0) - coef_CAP[t, v] = c0 - scal_CAP[t, v] = clb / c0 # Break-even cost 1: Scaling both IC and FC - alpha = c_i / value(instance.cost_invest[t, v]) - bic = (clb - c_f) / alpha # Break-even cost 2: Only decrease IC - bic_s[t].append(bic) - ic_s[t].append(value(instance.cost_invest[t, v])) - cap_s[t].append(c.solution.get_values(target_var)) - - print( - '{:>10s}\t{:>7s}\t{:>6s}\t{:>4s}\t{:>6s}\t{:>5s}\t{:>7s}\t{:>5s}\t{:>5s}'.format( - 'Tech', - 'Vintage', - 'L. CB', - 'Coef', - 'U. CB', - 'Scale', - 'BE IC', - 'IC', - 'Cap', - ) - ) - msg += '{:>10s}\t{:>7s}\t{:>6s}\t{:>4s}\t{:>6s}\t{:>5s}\t{:>7s}\t{:>5s}\t{:>5s}'.format( - 'Tech', - 'Vintage', - 'L. CB', - 'Coef', - 'U. CB', - 'Scale', - 'BE IC', - 'IC', - 'Cap', - ) - msg == '\n' - for v in vintages: - deployed = abs(cap_s[t][vintages.index(v)]) >= 1e-3 - tmp_beic_cs = ( - value(instance.cost_invest[t, v]) if deployed else bic_s[t][vintages.index(v)] - ) - tmp_bes_cs = 1 if deployed else scal_CAP[t, v] - row = { - 'algorithm': algorithm, - 'scenario': None, - 'technology': t, - 'vintage': v, - 'coef lower bound': clb_s[t, v], - 'coefficient': coef_CAP[t, v], - 'coef upper bound': cub_s[t, v], - 'scale': scal_CAP[t, v], - 'BE IC': bic_s[t][vintages.index(v)], - 'IC': value(instance.cost_invest[t, v]), - 'capacity': cap_s[t][vintages.index(v)], - 'BE IC (CS)': tmp_beic_cs, - 'scale (CS)': tmp_bes_cs, - } - results.append(row) - print( - '{:>10s}\t{:>7g}\t{:>6.0f}\t{:>4.0f}\t{:>6.0f}\t{:>5.3f}\t{:>7.1f}\t{:>5.0f}\t{:>5.3f}'.format( - t, - v, - clb_s[t, v], - coef_CAP[t, v], - cub_s[t, v], - scal_CAP[t, v], - bic_s[t][vintages.index(v)], - value(instance.cost_invest[t, v]), - cap_s[t][vintages.index(v)], - ) - ) - - msg += ( - '{:>10s}\t{:>7g}\t{:>6.0f}\t{:>4.0f}\t{:>6.0f}\t{:>5.3f}\t{:>7.1f}\t{:>5.0f}\t' - '{:>5.3f}'.format( - t, - v, - clb_s[t, v], - coef_CAP[t, v], - cub_s[t, v], - scal_CAP[t, v], - bic_s[t][vintages.index(v)], - value(instance.cost_invest[t, v]), - cap_s[t][vintages.index(v)], - ) - ) - msg += '\n' - - return msg, pd.DataFrame(results) - - -def bin_search(tech, vintage, dat, eps=0.01, all_v=False): - # This code block performs breakeven analysis by brutal force in an - # iterative way. I did this because sometimes sensitivity() and - # sensitivity_api() return anomalous values. Note that this code block - # returns the absolutely correct breakeven costs, however, it is - # significantly more time-consuming, since it takes 8-9 instances to - # calculate the breakeven cost of just one technology of one vintage. - # Arguments are defined below: - # tech -> Target technology. - # vintage -> Target vintage. It is break-even when capacity in this year >= 0 - # dat -> A list of .dat files. - # eps -> Convergence tolerance - # all_v -> A flag used indicate the costs of which vintages are subject - # to change. If it is FALSE, then only the investment costs and fixed costs - # in the target vintage will be altered, otherwise all vintages are affected - # Note that, only the capacity of the target vintage will be monitored and - # be used to signal breakeven. - monitor_year = vintage - monitor_tech = tech - - t0 = time() - time_mark = lambda: time() - t0 - - model = return_Temoa_model() - optimizer = SolverFactory('cplex') - data = return_Temoa_data(model, dat) - instance = model.create_instance(data) - - time_optimize = [i for i in data['time_future']] - time_optimize.sort() - ic0 = dict() - fc0 = dict() - if all_v: - for v in time_optimize: - if (monitor_tech, v) in data['cost_invest']: - ic0[monitor_tech, v] = data['cost_invest'][monitor_tech, v] - for p in time_optimize: - if (p, monitor_tech, v) in data['cost_fixed']: - fc0[p, monitor_tech, v] = data['cost_fixed'][p, monitor_tech, v] - else: - ic0[monitor_tech, monitor_year] = data['cost_invest'][monitor_tech, monitor_year] - for p in time_optimize: - if (p, monitor_tech, monitor_year) in data['cost_fixed']: - fc0[p, monitor_tech, monitor_year] = data['cost_fixed'][ - p, monitor_tech, monitor_year - ] - - cap_target = 0 - scale_u = 1.0 - scale_l = 0.0 - - history = dict() - history['scale_u'] = [scale_u] - history['scale_l'] = [scale_l] - - counter = 0 - scale_this = scale_u # Starting scale - - print(f'Iteration # {counter} starts at {time_mark()} s') - instance = model.create_instance(data) - instance.preprocess() - results = optimizer.solve(instance, suffixes=['dual', 'urc', 'slack', 'lrc']) - instance.solutions.load_from(results) - cap_target = value(instance.v_capacity[monitor_tech, monitor_year]) - print(f'Iteration # {counter} solved at {time_mark()} s') - print(f'Iteration # {counter}, scale: {scale_this:1.2f}, capacity: {cap_target} GW') - if 1.0 - scale_this <= eps and cap_target > 0: - return scale_this - - while (scale_u - scale_l) >= eps and counter <= 20: - if cap_target <= 0: - scale_u = scale_this - history['scale_u'].append(scale_u) - else: - scale_l = scale_this - history['scale_l'].append(scale_l) - counter += 1 - - scale_this = (scale_u + scale_l) * 0.5 - for k in ic0: - data['cost_invest'][k] = scale_this * ic0[k] - for k in fc0: - data['cost_fixed'][k] = scale_this * fc0[k] - - print(f'Iteration # {counter} starts at {time_mark()} s') - instance = model.create_instance(data) - instance.preprocess() - results = optimizer.solve(instance, suffixes=['dual', 'urc', 'slack', 'lrc']) - instance.solutions.load_from(results) - cap_target = value(instance.v_capacity[monitor_tech, monitor_year]) - print(f'Iteration # {counter} solved at {time_mark()} s') - print( - 'Iteration # {}, scale: {:1.2f}, capacity: {} GW'.format( - counter, scale_this, cap_target - ) - ) - return (scale_u + scale_l) / 2.0 - - -def cplex_search(t, v, cplex_instance, eps=0.01, all_v=False): - # This code block performs breakeven analysis by brutal force in an - # iterative way. However, it differs from bin_search() in that this function - # saves instance creation time by modifying the LP model coefficients in the - # CPLEX instance directly. By contrast, bin_search() has to create a new lp - # file each iteration after model coefficients are updated, which is - # time-consuming since Pyomo is notorious slow in model instantiation and - # creation. Other than that, these two functions are the same. - # Arguments are defined below: - # tech -> Target technology. - # vintage -> Target vintage. It is break-even when capacity in this year >= 0 - # dat -> A list of .dat files. - # eps -> Convergence tolerance - # all_v -> A flag used indicate the costs of which vintages are subject - # to change. If it is FALSE, then only the investment costs and fixed costs - # in the target vintage will be altered, otherwise all vintages are affected - # Note that, only the capacity of the target vintage will be monitored and - # be used to signal breakeven. - - def return_row(c0, scale, capacity): - row = { - 'algorithm': cplex_instance.parameters.lpmethod, - 'scenario': None, - 'technology': t, - 'vintage': v, - 'coef lower bound': 'N/A', - 'coefficient': c0, - 'coef upper bound': 'N/A', - 'scale': scale, - 'BE IC': None, - 'BE FC': None, - 'IC': None, - 'FC': None, - 'capacity': capacity, - 'BE IC (CS)': 'N/A', - 'BE FC (CS)': 'N/A', - 'scale (CS)': 'N/A', - } - return row - - msg = '' - target_year = v - target_tech = t - target_var0 = 'v_capacity(' + target_tech + '_' + str(target_year) + ')' - - t0 = time() - time_mark = lambda: time() - t0 - - c0 = cplex_instance.objective.get_linear(target_var0) # Original coefficient - cplex_instance.set_results_stream(None) - - scale_u = 1.0 - scale_l = 0.0 - - history = dict() - history['scale_u'] = [scale_u] - history['scale_l'] = [scale_l] - - counter = 0 - scale_this = scale_u # Starting scale - - print(f'Iteration # {counter} starts at {time_mark()} s') - msg += f'Iteration # {counter} starts at {time_mark()} s\n' - try: - cplex_instance.solve() - except CplexSolverError: - print('Exception raised during solve') - msg += 'Exception raised during solve\n' - return msg, None - cap_target0 = cplex_instance.solution.get_values(target_var0) - print(f'Iteration # {counter} solved at {time_mark()} s') - msg += f'Iteration # {counter} solved at {time_mark()} s\n' - print(f'Iteration # {counter}, scale: {scale_this:1.2f}, capacity: {cap_target0} GW') - if 1.0 - scale_this <= eps and cap_target0 > 0: - row = return_row(c0, scale_this, cap_target0) - return msg, pd.DataFrame([row]) - - cap_target = cap_target0 - while (scale_u - scale_l) >= eps and counter <= 20: - if cap_target <= 0: - scale_u = scale_this - history['scale_u'].append(scale_u) - else: - scale_l = scale_this - history['scale_l'].append(scale_l) - counter += 1 - - scale_this = (scale_u + scale_l) * 0.5 - cplex_instance.objective.set_linear(target_var0, scale_this * c0) - - print(f'Iteration # {counter} starts at {time_mark()} s') - msg += f'Iteration # {counter} starts at {time_mark()} s' - try: - cplex_instance.solve() - except CplexSolverError: - print('Exception raised during solve') - msg += 'Exception raised during solve\n' - return msg, None - cap_target = cplex_instance.solution.get_values(target_var0) - print(f'Iteration # {counter} solved at {time_mark()} s') - msg += f'Iteration # {counter} solved at {time_mark()} s\n' - print( - 'Iteration # {}, scale: {:1.2f}, capacity: {} GW'.format( - counter, scale_this, cap_target - ) - ) - row = return_row(c0, scale_this, cap_target0) - return msg, pd.DataFrame([row]) - - -def sen_range_api(tech, vintage, scales, list_dat): - # This function is adapted from CPLEX's example script lpex2.py - # It does the same thing as sen_range, but with CPLEX API for Python - - # Given a range of scaling factor for coefficient of a specific v_capacity, - # returns objective value, reduced cost, capacity etc. for each scaling - # factor - - target_year = vintage - target_tech = tech - target_var0 = 'v_capacity(' + target_tech + '_' + str(target_year) + ')' - algmap = { - 'primal simplex': 'p', - 'dual simplex': 'd', - 'barrier': 'h', # This is cross-over mode, since pure interior causes problems - 'default': 'o', - } # cplex definition - - t0 = time() - time_mark = lambda: time() - t0 - - model = return_Temoa_model() - data = return_Temoa_data(model, list_dat) - instance = model.create_instance(data) - - ic0 = data['cost_invest'][target_tech, target_year] - fc0 = data['cost_fixed'][target_year, target_tech, target_year] - all_periods = data['time_future'] - - obj = dict() - cap = dict() - coef = dict() - bic = dict() - bfc = dict() - ic = dict() # Original IC - fc = dict() # Original FC - clb = dict() # Lower bound of objective coefficient - cub = dict() # Upper bound of objective coefficient - rc = dict() # Reduced cost - - for algorithm in ['barrier', 'dual simplex', 'primal simplex']: - print(f'Algorithm: {algorithm}') - instance.write('tmp.lp', io_options={'symbolic_solver_labels': True}) - c = cplex.Cplex('tmp.lp') - os.remove('tmp.lp') - c.set_results_stream(None) # Turn screen output off - c0 = c.objective.get_linear(target_var0) - if not validate_coef(c0, instance, target_tech, target_year): - print('Error!') - sys.exit(0) - print(f'[{time_mark():>9.2f}] CPLEX model loaded.') - - if algmap[algorithm] == 'o': - c.parameters.lpmethod.set(c.parameters.lpmethod.values.auto) - elif algmap[algorithm] == 'p': - c.parameters.lpmethod.set(c.parameters.lpmethod.values.primal) - elif algmap[algorithm] == 'd': - c.parameters.lpmethod.set(c.parameters.lpmethod.values.dual) - elif algmap[algorithm] == 'b': - c.parameters.lpmethod.set(c.parameters.lpmethod.values.barrier) - c.parameters.barrier.crossover.set(c.parameters.barrier.crossover.values.none) - elif algmap[algorithm] == 'h': - c.parameters.lpmethod.set(c.parameters.lpmethod.values.barrier) - elif algmap[algorithm] == 's': - c.parameters.lpmethod.set(c.parameters.lpmethod.values.sifting) - elif algmap[algorithm] == 'c': - c.parameters.lpmethod.set(c.parameters.lpmethod.values.concurrent) - else: - raise ValueError('method must be one of "o", "p", "d", "b", "h", "s" or "c"') - - obj_alg = list() - cap_alg = defaultdict(list) - coef_alg = defaultdict(list) - bic_alg = defaultdict(list) - bfc_alg = defaultdict(list) - ic_alg = defaultdict(list) - fc_alg = defaultdict(list) - clb_alg = defaultdict(list) - cub_alg = defaultdict(list) - rc_alg = defaultdict(list) - for s in scales: - print(f'[{time_mark():>9.2f}] Scale: {s:>.3f} starts') - c.objective.set_linear(target_var0, s * c0) - - try: - c.solve() - except CplexSolverError: - print('Exception raised during solve') - return - - obj_alg.append(c.solution.get_objective_value()) - for y in instance.time_optimize: - key = str(y) - target_var = 'v_capacity(' + target_tech + '_' + key + ')' - coefficient = c.objective.get_linear(target_var) - if y != target_year: - if not validate_coef(coefficient, instance, target_tech, y): - print('Error!') - sys.exit(0) - capacity = c.solution.get_values(target_var) - try: - # Out of some unknow reason, sometimes this function will - # fail even though the model is totally feasible. - # Notes: This function fails when cross-over is not selected - # when barrier algorithm is selected - c_bound = c.solution.sensitivity.objective(target_var) - s_be = c_bound[0] / coefficient # Break-even scale - except: - c_bound = [None, None] - s_be = None - cost_i = s * value(instance.cost_invest[target_tech, y]) - cost_f = s * value(instance.cost_fixed[y, target_tech, y]) - - cap_alg[key].append(capacity) - coef_alg[key].append(coefficient) - ic_alg[key].append(cost_i) - fc_alg[key].append(cost_f) - if s_be: - bic_alg[key].append(s_be * cost_i) - bfc_alg[key].append(s_be * cost_f) - else: - bic_alg[key].append(None) - bfc_alg[key].append(None) - clb_alg[key].append(c_bound[0]) - cub_alg[key].append(c_bound[1]) - rc_alg[key].append(c.solution.get_reduced_costs(target_var)) - - obj[algorithm] = obj_alg - cap[algorithm] = cap_alg - coef[algorithm] = coef_alg - bic[algorithm] = bic_alg - bfc[algorithm] = bfc_alg - ic[algorithm] = ic_alg - fc[algorithm] = fc_alg - clb[algorithm] = clb_alg - cub[algorithm] = cub_alg - rc[algorithm] = rc_alg - - # Write to Excel spreadsheet - print(f'[{time_mark():>9.2f}] Saving to Excel spreadsheet') - row_title = [ - 'scale', - 'obj', - 'cap', - 'clb', - 'coef', - 'cub', - 'bic (clb)', - 'bfc (clb)', - 'ic', - 'fc', - 'rc', - ] - wb = Workbook() - # for ws_title in cap_alg: - for year in all_periods: - ws_title = str(year) - if ws_title not in cap_alg: - continue - ws = wb.create_sheet(ws_title) - - row = [ - scales, - obj_alg, - cap_alg[ws_title], - clb_alg[ws_title], - coef_alg[ws_title], - cub_alg[ws_title], - bic_alg[ws_title], - bfc_alg[ws_title], - ic_alg[ws_title], - fc_alg[ws_title], - rc_alg[ws_title], - ] - - # Note Python starts from 0, but row number starts from 1 - for j in range(0, len(row_title)): - cell = ws.cell(row=1, column=j + 1) - cell.value = row_title[j] - for i in range(0, len(scales)): - for j in range(0, len(row_title)): - cell = ws.cell(row=i + 2, column=j + 1) - cell.value = row[j][i] - fname = '.'.join( - [target_tech, str(target_year)] - + [i[:-4] for i in list_dat] # Remove the .dat extension - + [algorithm] - ) # tech_name.year.dat_file_name.algorithm.xlsx - wb.save(fname + '.xlsx') - - -def sen_range(tech, vintage, scales, dat): - # Given a range of scaling factor for coefficient of a specific v_capacity, - # returns objective value, reduced cost, capacity etc. for each scaling - # factor - from openpyxl import Workbook - - target_year = vintage - target_tech = tech - algmap = { - 'primal simplex': 1, - 'dual simplex': 2, - 'barrier': 4, - 'default': 0, - } # cplex definition - - t0 = time() - time_mark = lambda: time() - t0 - - model = return_Temoa_model() - data = return_Temoa_data(model, dat) - optimizer = SolverFactory('cplex') - - ic0 = data['cost_invest'][target_tech, target_year] - fc0 = data['cost_fixed'][target_year, target_tech, target_year] - all_periods = data['time_future'] - - obj = dict() - cap = dict() - lrc = dict() - coef = dict() - urc = dict() - bic = dict() - bfc = dict() - ic = dict() # Original IC - fc = dict() # Original FC - - for algorithm in ['barrier', 'dual simplex', 'primal simplex']: - optimizer.options['lpmethod'] = algmap[algorithm] - print(f'Algorithm: {algorithm}') - - obj_alg = list() - cap_alg = defaultdict(list) - lrc_alg = defaultdict(list) - coef_alg = defaultdict(list) - urc_alg = defaultdict(list) - bic_alg = defaultdict(list) - bfc_alg = defaultdict(list) - ic_alg = defaultdict(list) - fc_alg = defaultdict(list) - for s in scales: - print(f'[{time_mark():>9.2f}] Scale: {s:>.3f} starts') - data['cost_invest'][target_tech, target_year] = s * ic0 - for y in data['time_future']: - if (y, target_tech, target_year) in data['cost_fixed']: - data['cost_fixed'][y, target_tech, target_year] = s * fc0 - instance = model.create_instance(data) - instance.preprocess() - results = optimizer.solve(instance, suffixes=['dual', 'urc', 'slack', 'lrc']) - instance.solutions.load_from(results) - - obj_alg.append(value(instance.total_cost)) - for y in instance.time_optimize: - key = str(y) - c_vector = return_c_vector(instance, []) - coefficient = c_vector[('v_capacity', (target_tech, y))] - capacity = value(instance.v_capacity[target_tech, y]) - lower_rc = value(instance.lrc[instance.v_capacity[target_tech, y]]) - upper_rc = value(instance.urc[instance.v_capacity[target_tech, y]]) - cost_i = value(instance.cost_invest[target_tech, y]) - cost_f = value(instance.cost_fixed[y, target_tech, y]) - s_be = (coefficient - lower_rc) / coefficient # Break-even scale - - cap_alg[key].append(capacity) - lrc_alg[key].append(lower_rc) - coef_alg[key].append(coefficient) - urc_alg[key].append(upper_rc) - ic_alg[key].append(cost_i) - fc_alg[key].append(cost_f) - bic_alg[key].append(s_be * cost_i) - bfc_alg[key].append(s_be * cost_f) - - obj[algorithm] = obj_alg - cap[algorithm] = cap_alg - lrc[algorithm] = lrc_alg - coef[algorithm] = coef_alg - urc[algorithm] = urc_alg - bic[algorithm] = bic_alg - bfc[algorithm] = bfc_alg - ic[algorithm] = ic_alg - fc[algorithm] = fc_alg - - # Write to Excel spreadsheet - print(f'[{time_mark():>9.2f}] Saving to Excel spreadsheet') - row_title = ['scale', 'obj', 'cap', 'lrc', 'coef', 'urc', 'bic', 'bfc', 'ic', 'fc'] - wb = Workbook() - # for ws_title in cap_alg: - for year in all_periods: - ws_title = str(year) - if ws_title not in cap_alg: - continue - ws = wb.create_sheet(ws_title) - - row = [ - scales, - obj_alg, - cap_alg[ws_title], - lrc_alg[ws_title], - coef_alg[ws_title], - urc_alg[ws_title], - bic_alg[ws_title], - bfc_alg[ws_title], - ic_alg[ws_title], - fc_alg[ws_title], - ] - - # Note Python starts from 0, but row number starts from 1 - for j in range(0, len(row_title)): - c = ws.cell(row=1, column=j + 1) - c.value = row_title[j] - for i in range(0, len(scales)): - for j in range(0, len(row_title)): - c = ws.cell(row=i + 2, column=j + 1) - c.value = row[j][i] - fname = '.'.join( - [target_tech, str(target_year)] - + [i[:-4] for i in dat] # Remove the .dat extension - + [algorithm] - ) # tech_name.year.dat_file_name.algorithm.xlsx - wb.save(fname + '.xlsx') - - -def explore_Cost_marginal(dat): - model = temoa_create_model() - - model.dual = Suffix(direction=Suffix.IMPORT) - model.rc = Suffix(direction=Suffix.IMPORT) - model.slack = Suffix(direction=Suffix.IMPORT) - model.lrc = Suffix(direction=Suffix.IMPORT) - model.urc = Suffix(direction=Suffix.IMPORT) - - data = DataPortal(model=model) - for d in dat: - data.load(filename=d) - instance = model.create_instance(data) - - # Deactivate the DemandActivity constraint - # instance.demand_activity_constraint.deactivate() - # instance.preprocess() - - optimizer = SolverFactory('cplex') - results = optimizer.solve(instance, keepfiles=True, suffixes=['dual', 'urc', 'slack', 'lrc']) - instance.solutions.load_from(results) - - print('Dual and slack variables for emission caps:') - for e in instance.commodity_emissions: - for p in instance.time_optimize: - if (p, e) in instance.EmissionLimitConstraint: - print( - p, - e, - instance.dual[instance.EmissionLimitConstraint[p, e]], - '\t', - instance.slack[instance.EmissionLimitConstraint[p, e]], - ) - - # print('Dual and slack variables for Commodity Demand Constraints') - # for c in instance.commodity_demand: - # for p in instance.time_optimize: - # for s in instance.time_season: - # for tod in instance.time_of_day: - # print( - # p, - # s, - # tod, - # instance.dual[instance.demand_constraint[p, s, tod, c]], - # instance.slack[instance.demand_constraint[p, s, tod, c]], - # ) - - -def plot_breakeven(years, bic, ic): - # bic is a dictionary, ic is a list of the raw investment costs - # ic = [x, x, ..., x], the length of which equals to the length of years - # bic[scenario] = [x, x, x... x] where the length equals to the number - # of optimized periods. - sen_color_map = { - 'IC': [0.9, 0.9, 0.9], - 'LF': 'black', - 'R': 'black', - 'HF': 'black', - 'HD': 'black', - 'CPPLF': 'green', - 'CPP': 'green', - 'CPPHF': 'green', - 'CPPHD': 'green', - } - - sen_lstyle_map = { - 'IC': None, - 'LF': '--', - 'R': '-', - 'HF': '-.', - 'HD': ':', - 'CPPLF': '--', - 'CPP': '-', - 'CPPHF': '-.', - 'CPPHD': ':', - } - - sen_marker_map = { - 'IC': None, - 'LF': 's', - 'R': 's', - 'HF': 's', - 'HD': 's', - 'CPPLF': 's', - 'CPP': 's', - 'CPPHF': 's', - 'CPPHD': 's', - } - - scenarios = bic.keys() - h = plt.figure() - ax = plt.subplot(111) - ax.fill_between(years, 0, ic, facecolor=sen_color_map['IC']) - - for s in scenarios: - ax.plot( - years, - bic[s], - color=sen_color_map[s], - # marker = sen_marker_map[s], - linestyle=sen_lstyle_map[s], - ) - ax.yaxis.grid(True) - plt.ylabel('$/MWh') - plt.xlim((years[0] - 5, years[-1] + 5)) - return ax - - -def bin_search_and_range(): - def return_range(bs): - # Given break-even scaling factor, return an appropriate range - ub = None - lb = None - if bs >= 0.85: - lb = int(bs * 100) - 15 - ub = 100 - elif bs <= 0.15: - lb = 1 - ub = int(bs * 100) + 15 - else: - lb = int(bs * 100) - 15 - ub = int(bs * 100) + 15 - return [0.001 * i for i in range(lb * 10, ub * 10, 10)] - - list_file = ['reference.dat', 'NCupdated_noLeadTime.dat'] - list_tech = ['EBIOIGCC', 'EURNALWR15'] - monitor_vintage = 2020 - eps = 0.01 - for f in list_file: - for t in list_tech: - bs = bin_search(t, monitor_vintage, [f], eps) - sen_range(t, monitor_vintage, return_range(bs), [f]) - - -if __name__ == '__main__': - # sen_bin_search( - # 'ECOALIGCCS', - # 2020, - # ['reference.dat'], - # 0.01 - # ) - scales = [0.001 * i for i in range(250, 260, 10)] - sen_range('ECOALIGCCS', 2020, scales, ['reference.dat']) - # do_sensitivity_new() - # do_sensitivity_old() - # explore_Cost_marginal( - # ['/afs/unity.ncsu.edu/users/b/bli6/TEMOA_NC/sql20170417/results/R/NCreference.R.dat'] - # ) From fb9814561dc07f79c25887cb3b712065dacccafe Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 5 Mar 2026 14:48:10 -0500 Subject: [PATCH 430/587] ref: remove outdated make_output_plots.py and related docs --- docs/source/Documentation.rst | 32 -- docs/source/visualization.rst | 28 -- temoa/data_processing/make_output_plots.py | 406 --------------------- 3 files changed, 466 deletions(-) delete mode 100644 temoa/data_processing/make_output_plots.py diff --git a/docs/source/Documentation.rst b/docs/source/Documentation.rst index 2955e90f7..2c899679e 100644 --- a/docs/source/Documentation.rst +++ b/docs/source/Documentation.rst @@ -88,38 +88,6 @@ Graphviz also generates static SVG diagrams showing the energy system structure: are automatically generated when ``graphviz_output = true`` is set in the configuration file. -Output Graphs -------------- - -.. warning:: - The ``make_output_plots.py`` script has not been fully tested with Temoa v4.0 - and is currently unsupported. Use at your own risk and please report any issues - on `GitHub Issues`_. - -Temoa can also be used to generate output graphs using `matplotlib `_. -From the command line, navigate to the :code:`data_processing` folder and execute the -following command: - -.. parsed-literal:: - $ uv run python temoa/data_processing/make_output_plots.py --help - -The command above will specify all of the flags required to create a stacked bar -or line plot. For example, consider the following command: - -.. parsed-literal:: - $ uv run python temoa/data_processing/make_output_plots.py -i data_files/temoa_utopia.sqlite -s test_run -p capacity -c electric --super - -.. figure:: images/output_flow_example.* - :align: center - :figclass: center - :figwidth: 60% - - This stacked bar plot represents the activity (i.e., output commodity flow) - associated with each technology in the electric sector from the 'test_run' - scenario drawn from the 'temoa_utopia' database. Because the :code:`super` - flag was specified, technologies are grouped together based on user-specified - categories in the :code:`tech_category` column of the :code:`technologies` - table of the database. ===================== The Math Behind Temoa diff --git a/docs/source/visualization.rst b/docs/source/visualization.rst index b4dbebc87..411923d22 100644 --- a/docs/source/visualization.rst +++ b/docs/source/visualization.rst @@ -82,33 +82,5 @@ commodity or technology. For example: technology 'E31' in 2010, which is from the 'test_run' scenario drawn from the 'temoa_utopia' database. -Output Graphs -------------- - -Temoa can also be used to generate output graphs using `matplotlib `_. -From the command line, navigate to the :code:`data_processing` folder and execute the following command: - -.. parsed-literal:: - $ python make_output_plots.py --help - -The command above will specify all of the flags required to created a stacked bar -or line plot. For example, consider the following command: - -.. parsed-literal:: - $ python make_output_plots.py -i ../data_files/temoa_utopia.sqlite -s test_run -p capacity -c electric --super - -Here is the result: - -.. figure:: images/output_flow_example.* - :align: center - :figclass: center - :figwidth: 60% - - This stacked bar plot represents the activity (i.e., output commodity flow) - associated with each technology in the electric sector from the 'test_run' - scenario drawn from the 'temoa_utopia' database. Because the :code:`super` - flag was specified, technologies are grouped together based on user-specified - categories in the :code:`tech_category` column of the :code:`technologies` - table of the database. .. _Graphviz: http://www.graphviz.org/ diff --git a/temoa/data_processing/make_output_plots.py b/temoa/data_processing/make_output_plots.py deleted file mode 100644 index a48ebc18c..000000000 --- a/temoa/data_processing/make_output_plots.py +++ /dev/null @@ -1,406 +0,0 @@ -from __future__ import annotations - -import argparse -import os -import random -import sqlite3 -import sys -from collections.abc import Callable -from typing import TYPE_CHECKING, cast - -import matplotlib -from matplotlib import cm as cmx -from matplotlib import colors -from matplotlib import pyplot as plt - -if TYPE_CHECKING: - from matplotlib.figure import Figure - from matplotlib.legend import Legend - -matplotlib.use('Agg') - -# Type aliases for clarity using modern built-in generics -DbRow = list[str | int | float] -# All numeric lists are floats for consistency in plotting data. -PlotData = dict[str, list[float]] -Color = tuple[float, float, float, float] -ColorMapFunc = Callable[[int | float], Color] - - -class OutputPlotGenerator: - """Generates plots from Temoa model output databases.""" - - db_path: str - region: str - scenario: str - folder_name: str - output_file_name: str - capacity_output: list[DbRow] - output_vflow: list[DbRow] - output_emissions: list[DbRow] - tech_categories: list[list[str]] - - def __init__( - self, path_to_db: str, region: str, scenario: str, super_categories: bool = False - ) -> None: - self.db_path = os.path.abspath(path_to_db) - self.region = '%' if region == 'global' else region - self.scenario = scenario - self.folder_name = ( - f'{os.path.splitext(os.path.basename(path_to_db))[0]}_{region}_{scenario}_plots' - ) - self.capacity_output = [] - self.output_vflow = [] - self.output_emissions = [] - self.tech_categories = [] - self.output_file_name = '' - - def extract_from_database(self, mode: int) -> None: - """ - Based on the type of the plot being generated, extract data from the - corresponding table from the database. - """ - con = sqlite3.connect(self.db_path) - cur = con.cursor() - if mode == 1: - cur.execute( - f'SELECT sector, period, tech, capacity FROM output_net_capacity ' - f"WHERE scenario == '{self.scenario}' AND region LIKE '{self.region}'" - ) - self.capacity_output = [list(elem) for elem in cur.fetchall()] - elif mode == 2: - cur.execute( - f'SELECT sector, period, tech, SUM(flow) FROM output_flow_out ' - f"WHERE scenario == '{self.scenario}' AND region LIKE '{self.region}' " - f'GROUP BY sector, period, tech' - ) - self.output_vflow = [list(elem) for elem in cur.fetchall()] - elif mode == 3: - cur.execute( - f'SELECT sector, period, emis_comm, SUM(emission) FROM output_emission ' - f"WHERE scenario == '{self.scenario}' AND region LIKE '{self.region}' " - f'GROUP BY sector, period, emis_comm' - ) - self.output_emissions = [list(elem) for elem in cur.fetchall()] - - cur.execute('SELECT tech, category FROM Technology') - self.tech_categories = [[str(word) for word in t] for t in cur.fetchall()] - con.close() - - def get_sectors(self, plot_type: int) -> list[str]: - """ - Based on the type of the plot, returns a list of sectors available in the database. - """ - self.extract_from_database(plot_type) - sectors: set[str] = set() - data: list[DbRow] = [] - - if plot_type == 1: - data = self.capacity_output - elif plot_type == 2: - data = self.output_vflow - elif plot_type == 3: - data = self.output_emissions - - for row in data: - sectors.add(str(row[0])) - - res = sorted(sectors) - res.insert(0, 'all') - return res - - def process_data( - self, input_data: list[DbRow], sector: str, super_categories: bool - ) -> PlotData: - """Processes data for a particular sector to make it ready for plotting.""" - periods_set: set[int] = set() - techs_set: set[str] = set() - - for row in input_data: - row[0] = str(row[0]) - row[1] = int(row[1]) - row[2] = str(row[2]) - row[3] = float(row[3]) - - tech_dict = dict(self.tech_categories) - if super_categories: - for row in input_data: - row[2] = tech_dict.get(str(row[2]), str(row[2])) - - for row in input_data: - if row[0] == sector or sector == 'all': - periods_set.add(int(row[1])) - techs_set.add(str(row[2])) - - periods = sorted(periods_set) - techs = sorted(techs_set) - - output_values: PlotData = {} - for tech in techs: - if tech in ('None', ''): - continue - output_values[tech] = [0.0] * len(periods) - - for row in input_data: - tech_name = str(row[2]) - if tech_name not in output_values: - continue - if row[0] == sector or sector == 'all': - output_values[tech_name][periods.index(int(row[1]))] += float(row[-1]) - - output_values['periods'] = [float(p) for p in periods] - return output_values - - def handle_output_path( - self, plot_type: str, sector: str, super_categories: bool, output_dir: str - ) -> str: - """Constructs and creates the output path for the plot.""" - outfile = f'{plot_type}_{sector}' - if super_categories: - outfile += '_merged' - outfile += '.png' - - full_output_dir = os.path.join(output_dir, self.folder_name) - if not os.path.exists(full_output_dir): - os.makedirs(full_output_dir) - - self.output_file_name = os.path.join(full_output_dir, outfile).replace(' ', '') - return os.path.join(self.folder_name, outfile) - - def generate_plot_for_capacity( - self, sector: str, super_categories: bool = False, output_dir: str = '.' - ) -> str: - """Generates a plot for the capacity of a given sector.""" - relative_path = self.handle_output_path('capacity', sector, super_categories, output_dir) - if os.path.exists(self.output_file_name): - print('not generating new capacity plot') - return relative_path - - sectors = self.get_sectors(1) - if sector not in sectors: - return '' - - output_values = self.process_data(self.capacity_output, sector, super_categories) - title = ( - f'Capacity Plot for {sector} across all regions' - if self.region == '%' - else f'Capacity Plot for {sector} sector in region {self.region}' - ) - self.make_stacked_bar_plot(output_values, 'Years', 'Capacity', 'periods', title) - return relative_path - - def generate_plot_for_output_flow( - self, sector: str, super_categories: bool = False, output_dir: str = '.' - ) -> str: - """Generates a plot for the output flow of a given sector.""" - relative_path = self.handle_output_path('flow', sector, super_categories, output_dir) - if os.path.exists(self.output_file_name): - print('not generating new flow plot') - return relative_path - - sectors = self.get_sectors(2) - if sector not in sectors: - return '' - - output_values = self.process_data(self.output_vflow, sector, super_categories) - title = ( - f'Output Flow Plot for {sector} across all regions' - if self.region == '%' - else f'Output Flow Plot for {sector} sector in region {self.region}' - ) - self.make_stacked_bar_plot(output_values, 'Years', 'Activity', 'periods', title) - return relative_path - - def generate_plot_for_emissions( - self, sector: str, super_categories: bool = False, output_dir: str = '.' - ) -> str: - """Generates a plot for the emissions of a given sector.""" - relative_path = self.handle_output_path('emissions', sector, super_categories, output_dir) - if os.path.exists(self.output_file_name): - print('not generating new emissions plot') - return relative_path - - sectors = self.get_sectors(3) - if sector not in sectors: - return '' - - output_values = self.process_data(self.output_emissions, sector, super_categories) - title = ( - f'Emissions Plot for {sector} across all regions' - if self.region == '%' - else f'Emissions Plot for {sector} sector in region {self.region}' - ) - self.make_line_plot(output_values.copy(), 'Emissions', title) - return relative_path - - # --------------------------- Plot Generation related functions ------------------------------ - - def get_cmap(self, size: int) -> ColorMapFunc: - """Returns a function that maps an index to a distinct RGB color.""" - color_norm = colors.Normalize(vmin=0, vmax=size - 1) - scalar_map = cmx.ScalarMappable(norm=color_norm, cmap='viridis') - - def wrapper(index: int | float) -> Color: - # We ignore the arg-type error. Mypy expects a NumPy array based on the - # library's type stubs, but matplotlib's to_rgba function correctly - # handles scalar inputs at runtime. This is a known limitation of the stubs. - rgba_value = scalar_map.to_rgba(index) # type: ignore[arg-type] - return cast('Color', rgba_value) - - return wrapper - - def make_stacked_bar_plot( - self, data: PlotData, xlabel: str, ylabel: str, xvar: str, title: str - ) -> None: - """Creates and saves a stacked bar plot.""" - random.seed(10) - data_copy = data.copy() - - xaxis = data_copy.pop(xvar, []) - data_copy.pop('c', None) - stacked_bars = list(data_copy.keys()) - - fig: Figure = plt.figure() - cmap = self.get_cmap(len(stacked_bars)) - color_map_for_bars = {bar_name: cmap(i) for i, bar_name in enumerate(stacked_bars)} - - width = ( - min(xaxis[i + 1] - xaxis[i] for i in range(len(xaxis) - 1)) / 2.0 - if len(xaxis) > 1 - else 1.0 - ) - - bottom = [0.0] * len(xaxis) - handles = [] - for bar in stacked_bars: - values = data_copy[bar] - h = plt.bar(xaxis, values, width, bottom=bottom, color=color_map_for_bars[bar]) - handles.append(h) - bottom = [b + v for b, v in zip(bottom, values, strict=False)] - - plt.xlabel(xlabel) - plt.ylabel(ylabel) - plt.xticks(xaxis, [str(int(x)) for x in xaxis]) - plt.title(title) - lgd: Legend = plt.legend( - [h[0] for h in handles], stacked_bars, bbox_to_anchor=(1.2, 1), fontsize=7.5 - ) - plt.savefig(self.output_file_name, bbox_extra_artists=(lgd,), bbox_inches='tight') - plt.close(fig) - - def make_line_plot(self, plot_var: PlotData, label: str, title: str) -> None: - """Creates and saves a line plot.""" - random.seed(10) - - periods = plot_var.pop('periods', []) - techs = list(plot_var.keys()) - - fig: Figure = plt.figure() - cmap = self.get_cmap(len(techs)) - color_map = {tech: cmap(i) for i, tech in enumerate(techs)} - - handles = [] - for tech in techs: - values = plot_var[tech] - h = plt.plot(periods, values, color=color_map[tech], linestyle='--', marker='o') - handles.append(h) - - plt.xlabel('Years') - plt.ylabel(label) - plt.xticks(periods, [str(int(p)) for p in periods]) - plt.title(title) - lgd: Legend = plt.legend( - [h[0] for h in handles], techs, bbox_to_anchor=(1.2, 1), fontsize=7.5 - ) - plt.savefig(self.output_file_name, bbox_extra_artists=(lgd,), bbox_inches='tight') - plt.close(fig) - - -def generate_plot(args: list[str]) -> None: - """Parses command line arguments and calls relevant functions.""" - parser = argparse.ArgumentParser(description='Generate Output Plot') - parser.add_argument( - '-i', - '--input', - action='store', - dest='input', - help='Input Database Filename ', - required=True, - ) - parser.add_argument( - '-r', - '--region', - action='store', - dest='region', - help="Region name, input 'global' if global results are desired", - required=True, - ) - parser.add_argument( - '-s', - '--scenario', - action='store', - dest='scenario', - help='Model run a scenario name', - required=True, - ) - parser.add_argument( - '-p', - '--plot-type', - action='store', - dest='type', - help='Type of Plot to be generated', - choices=['capacity', 'flow', 'emissions'], - required=True, - ) - parser.add_argument( - '-c', - '--sector', - action='store', - dest='sector', - help='Sector for which plot to be generated', - required=True, - ) - parser.add_argument( - '-o', - '--output', - action='store', - dest='output_dir', - help='Output plot location', - default='./', - ) - parser.add_argument( - '--super', - action='store_true', - dest='super_categories', - help='Merge Technologies or not', - default=False, - ) - - options = parser.parse_args(args) - result_generator = OutputPlotGenerator( - options.input, options.region, options.scenario, options.super_categories - ) - - error_path = '' - if options.type == 'capacity': - error_path = result_generator.generate_plot_for_capacity( - options.sector, options.super_categories, options.output_dir - ) - elif options.type == 'flow': - error_path = result_generator.generate_plot_for_output_flow( - options.sector, options.super_categories, options.output_dir - ) - elif options.type == 'emissions': - error_path = result_generator.generate_plot_for_emissions( - options.sector, options.super_categories, options.output_dir - ) - - if not error_path: - print("Error: The sector doesn't exist for the selected plot type and database.") - else: - full_path = os.path.join(options.output_dir, os.path.dirname(error_path)) - print(f'Done. Look for output plot images in directory: {os.path.abspath(full_path)}') - - -if __name__ == '__main__': - generate_plot(sys.argv[1:]) From e2e81150841d97195db8a0203471f58a04110a1a Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Thu, 26 Feb 2026 11:10:28 -0500 Subject: [PATCH 431/587] feat: implementing configurability for cycle detection in commodity graphing --- docs/source/quick_start.rst | 11 +- temoa/core/config.py | 12 ++ temoa/model_checking/commodity_graph.py | 15 +- temoa/tutorial_assets/config_sample.toml | 8 + tests/test_cycle_limits.py | 194 +++++++++++++++++++++++ 5 files changed, 238 insertions(+), 2 deletions(-) create mode 100644 tests/test_cycle_limits.py diff --git a/docs/source/quick_start.rst b/docs/source/quick_start.rst index 9f7250762..a0908b592 100644 --- a/docs/source/quick_start.rst +++ b/docs/source/quick_start.rst @@ -299,7 +299,16 @@ data and analyzes it for "orphans" which likely represent gaps in the network th to erroneous output data. The operation is enabled by tagging foundational commodities for which there are no predecessors as "source" commodities in the `Commodity` database table with an `s` tag. Orphans (or chains of orphans) on either the demand or supply side are reported and *suppressed* in -the data to prevent network corruption. +the data to prevent network corruption. Additionally, Temoa performs cycle detection on the commodity +network to identify circular dependencies that could lead to non-convergence or erroneous results. +Users can configure the cycle detection behavior using the following settings: + +* **cycle_count_limit**: Limits the number of cycles reported in the log. A value of `-1` allows + unbounded detection, `0` causes the system to log an error on the first detected cycle and then + suppresses further cycle reports for the remainder of the run (without terminating execution), + and a positive integer sets a specific limit. Default is 100. +* **cycle_length_limit**: Minimum length of cycles to report. This can be used to filter out small, + expected circularities if necessary. Default is 1. Note that the myopic mode *requires* the use of Source Tracing to ensure accuracy as some orphans may be produced by endogenous decisions in myopic runs. diff --git a/temoa/core/config.py b/temoa/core/config.py index 6441fb5c0..d61ee04e4 100644 --- a/temoa/core/config.py +++ b/temoa/core/config.py @@ -63,6 +63,8 @@ def __init__( check_units: bool = False, plot_commodity_network: bool = False, graphviz_output: bool = False, + cycle_count_limit: int = 100, + cycle_length_limit: int = 1, ): if '-' in scenario: raise ValueError( @@ -147,6 +149,14 @@ def __init__( self.graphviz_output = graphviz_output self.stochastic_config = stochastic_config + # Cycle detection limits + if not isinstance(cycle_count_limit, int) or cycle_count_limit < -1: + raise ValueError('cycle_count_limit must be an integer >= -1') + if not isinstance(cycle_length_limit, int) or cycle_length_limit < 1: + raise ValueError('cycle_length_limit must be an integer >= 1') + self.cycle_count_limit = cycle_count_limit + self.cycle_length_limit = cycle_length_limit + # warn if output db != input db if self.input_database.suffix == self.output_database.suffix: # they are both .db/.sqlite if self.input_database != self.output_database: # they are not the same db @@ -270,6 +280,8 @@ def __repr__(self) -> str: msg += '{:>{}s}: {}\n'.format('Unit checking', width, self.check_units) msg += '{:>{}s}: {}\n'.format('Commodity network plots', width, self.plot_commodity_network) msg += '{:>{}s}: {}\n'.format('Graphviz output', width, self.graphviz_output) + msg += '{:>{}s}: {}\n'.format('Cycle count limit', width, self.cycle_count_limit) + msg += '{:>{}s}: {}\n'.format('Cycle length limit', width, self.cycle_length_limit) msg += spacer msg += '{:>{}s}: {}\n'.format('Selected solver', width, self.solver_name) diff --git a/temoa/model_checking/commodity_graph.py b/temoa/model_checking/commodity_graph.py index 0a2e30a06..8275e0e1e 100644 --- a/temoa/model_checking/commodity_graph.py +++ b/temoa/model_checking/commodity_graph.py @@ -305,10 +305,23 @@ def visualize_graph( # 8. Perform cycle detection on the commodity graph try: + count = 0 + limit = config.cycle_count_limit + length_limit = config.cycle_length_limit + for cycle in nx.simple_cycles(G=commodity_graph): - if len(cycle) < 2: + if limit != -1 and count >= limit: + if limit > 0: + logger.warning('Cycle detection reached limit of %d cycles. Stopping.', limit) + else: + logger.error('Cycles detected but cycle_count_limit is 0. Stopping.') + break + + if len(cycle) < length_limit: continue + cycle_str = ' -> '.join(cycle) + f' -> {cycle[0]}' logger.info('Cycle detected: %s', cycle_str) + count += 1 except nx.NetworkXError as e: logger.warning('NetworkXError during cycle detection: %s', e, exc_info=True) diff --git a/temoa/tutorial_assets/config_sample.toml b/temoa/tutorial_assets/config_sample.toml index daa88be75..4cf8d7675 100644 --- a/temoa/tutorial_assets/config_sample.toml +++ b/temoa/tutorial_assets/config_sample.toml @@ -51,6 +51,14 @@ plot_commodity_network = true # Recommended for production runs after units are populated in the database check_units = true +# Limit the number of cycles detected in the commodity graph +# -1 = unbounded (INFO), 0 = strictly disallow (ERROR), positive integer = limit +cycle_count_limit = 100 + +# Minimum cycle length to report (default: 1) +# Use this to filter out very small cycles if needed +cycle_length_limit = 1 + # ------------------------------------ # SOLVER # Solver Selection diff --git a/tests/test_cycle_limits.py b/tests/test_cycle_limits.py new file mode 100644 index 000000000..80895e4a0 --- /dev/null +++ b/tests/test_cycle_limits.py @@ -0,0 +1,194 @@ +from __future__ import annotations + +import logging +from pathlib import Path +from unittest.mock import MagicMock + +import networkx as nx +import pytest + +from temoa.core.config import TemoaConfig +from temoa.model_checking.commodity_graph import visualize_graph +from temoa.types.core_types import Period, Region + + +@pytest.fixture +def mock_config() -> MagicMock: + config = MagicMock(spec=TemoaConfig) + config.plot_commodity_network = True + config.output_path = Path('./') + config.cycle_count_limit = 100 + config.cycle_length_limit = 1 + return config + + +@pytest.fixture +def cycle_graph() -> nx.MultiDiGraph[str]: + dg: nx.MultiDiGraph[str] = nx.MultiDiGraph() + # Create two cycles: (A->B->A) length 2, (C->D->E->C) length 3 + dg.add_edge('A', 'B') + dg.add_edge('B', 'A') + dg.add_edge('C', 'D') + dg.add_edge('D', 'E') + dg.add_edge('E', 'C') + # Add some other nodes/edges to make it look like a real graph + dg.add_node('A', layer=1, sector='S1') + dg.add_node('B', layer=2, sector='S1') + dg.add_node('C', layer=1, sector='S2') + dg.add_node('D', layer=2, sector='S2') + dg.add_node('E', layer=3, sector='S2') + return dg + + +def test_cycle_limits_logging( + mock_config: MagicMock, + cycle_graph: nx.MultiDiGraph[str], + caplog: pytest.LogCaptureFixture, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Test that cycles are logged according to length limit.""" + mock_config.cycle_length_limit = 3 + + with caplog.at_level(logging.INFO): + # We need to mock generate_commodity_graph to return our controlled graph + import temoa.model_checking.commodity_graph as cg + + monkeypatch.setattr( + cg, 'generate_commodity_graph', MagicMock(return_value=(cycle_graph, {})) + ) + monkeypatch.setattr(cg, 'generate_technology_graph', MagicMock()) + monkeypatch.setattr(cg, 'nx_to_vis', MagicMock(return_value='path')) + + visualize_graph( + region=Region('R1'), + period=Period(2020), + network_data=MagicMock(), + demand_orphans=[], + other_orphans=[], + driven_techs=[], + config=mock_config, + ) + + # Should only log cycles of length >= 3 + # (C->D->E->C) is length 3 + # (A->B->A) is length 2, should be skipped + assert any( + 'Cycle detected' in record.message + and 'C' in record.message + and 'D' in record.message + and 'E' in record.message + for record in caplog.records + ) + assert not any( + 'Cycle detected' in record.message and 'A' in record.message and 'B' in record.message + for record in caplog.records + ) + + +def test_cycle_count_limit( + mock_config: MagicMock, + cycle_graph: nx.MultiDiGraph[str], + caplog: pytest.LogCaptureFixture, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Test that cycle detection stops after cycle_count_limit.""" + mock_config.cycle_count_limit = 1 + mock_config.cycle_length_limit = 1 + + with caplog.at_level(logging.INFO): + import temoa.model_checking.commodity_graph as cg + + monkeypatch.setattr( + cg, 'generate_commodity_graph', MagicMock(return_value=(cycle_graph, {})) + ) + monkeypatch.setattr(cg, 'generate_technology_graph', MagicMock()) + monkeypatch.setattr(cg, 'nx_to_vis', MagicMock(return_value='path')) + + visualize_graph( + region=Region('R1'), + period=Period(2020), + network_data=MagicMock(), + demand_orphans=[], + other_orphans=[], + driven_techs=[], + config=mock_config, + ) + + # Should only log 1 cycle and then the warning + # nx.simple_cycles might return them in different order depending on version/impl + # but it should only log ONE of them. + cycle_logs = [record.message for record in caplog.records if 'Cycle detected' in record.message] + assert len(cycle_logs) == 1 + assert 'Cycle detection reached limit of 1 cycles. Stopping.' in caplog.text + + +def test_cycle_count_limit_zero( + mock_config: MagicMock, + cycle_graph: nx.MultiDiGraph[str], + caplog: pytest.LogCaptureFixture, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Test that cycle_count_limit=0 logs an error and stops immediately.""" + mock_config.cycle_count_limit = 0 + + with caplog.at_level(logging.INFO): + import temoa.model_checking.commodity_graph as cg + + monkeypatch.setattr( + cg, 'generate_commodity_graph', MagicMock(return_value=(cycle_graph, {})) + ) + monkeypatch.setattr(cg, 'generate_technology_graph', MagicMock()) + monkeypatch.setattr(cg, 'nx_to_vis', MagicMock(return_value='path')) + + visualize_graph( + region=Region('R1'), + period=Period(2020), + network_data=MagicMock(), + demand_orphans=[], + other_orphans=[], + driven_techs=[], + config=mock_config, + ) + + assert any( + 'Cycles detected but cycle_count_limit is 0. Stopping.' in record.message + for record in caplog.records + ) + assert not any('Cycle detected:' in record.message for record in caplog.records) + + +def test_cycle_unbounded( + mock_config: MagicMock, + cycle_graph: nx.MultiDiGraph[str], + caplog: pytest.LogCaptureFixture, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Test that cycle_count_limit=-1 allows all cycles.""" + mock_config.cycle_count_limit = -1 + + with caplog.at_level(logging.INFO): + import temoa.model_checking.commodity_graph as cg + + monkeypatch.setattr( + cg, 'generate_commodity_graph', MagicMock(return_value=(cycle_graph, {})) + ) + monkeypatch.setattr(cg, 'generate_technology_graph', MagicMock()) + monkeypatch.setattr(cg, 'nx_to_vis', MagicMock(return_value='path')) + + visualize_graph( + region=Region('R1'), + period=Period(2020), + network_data=MagicMock(), + demand_orphans=[], + other_orphans=[], + driven_techs=[], + config=mock_config, + ) + + assert any( + 'Cycle detected' in record.message and 'C' in record.message for record in caplog.records + ) + assert any( + 'Cycle detected' in record.message and 'A' in record.message for record in caplog.records + ) + assert not any('Stopping' in record.message for record in caplog.records) From e3dc8370331b32590ec9ecd8844ec3d4dd6b54fc Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 28 Feb 2026 14:47:19 -0500 Subject: [PATCH 432/587] docs: adding cycle config info to source tracing docs --- docs/source/quick_start.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/quick_start.rst b/docs/source/quick_start.rst index a0908b592..801720840 100644 --- a/docs/source/quick_start.rst +++ b/docs/source/quick_start.rst @@ -308,7 +308,8 @@ Users can configure the cycle detection behavior using the following settings: suppresses further cycle reports for the remainder of the run (without terminating execution), and a positive integer sets a specific limit. Default is 100. * **cycle_length_limit**: Minimum length of cycles to report. This can be used to filter out small, - expected circularities if necessary. Default is 1. + expected circularities if necessary. Default is 1. The length limit is inclusive, so a cycle of + length 1 is a self-loop, and a cycle of length `n` has `n` unique nodes. Note that the myopic mode *requires* the use of Source Tracing to ensure accuracy as some orphans may be produced by endogenous decisions in myopic runs. From 9f2f83344e2e78e1c7fa036ad9d299e7b6962498 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Sun, 8 Mar 2026 18:50:41 -0400 Subject: [PATCH 433/587] Change orphan behaviour to freeze branches rather than remove them --- temoa/components/commodities.py | 8 +-- temoa/components/flows.py | 24 +++++--- temoa/components/technology.py | 21 +++---- temoa/core/model.py | 5 +- temoa/data_io/component_manifest.py | 4 +- .../commodity_network_manager.py | 58 +++++-------------- tests/testing_data/mediumville_sets.json | 4 ++ tests/testing_data/storageville.sql | 2 +- tests/testing_data/test_system.sql | 2 +- tests/testing_data/test_system_sets.json | 7 ++- tests/testing_data/utopia_sets.json | 5 ++ 11 files changed, 66 insertions(+), 74 deletions(-) diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index a80ed4e83..1ece9382f 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -38,11 +38,11 @@ def commodity_balance_constraint_error_check( ) -> None: # note: if a pyomo equation simplifies to an int, there are no variables in it, which # is an indicator of a problem. How this might come up I do not know - if isinstance(supplied, int) or isinstance(demanded, int): + if isinstance(supplied, int) and isinstance(demanded, int): expr = str(supplied == demanded) msg = ( 'Unable to balance commodity {} in ({}, {}, {}, {}).\n' - 'No flows on one side of constraint expression:\n' + 'Nothing produces or consumes it:\n' ' {}\n' 'Possible reasons:\n' " - Is there a missing period in set 'time_future'?\n" @@ -61,11 +61,11 @@ def annual_commodity_balance_constraint_error_check( ) -> None: # note: if a pyomo equation simplifies to an int, there are no variables in it, which # is an indicator of a problem. How this might come up I do not know - if isinstance(supplied, int) or isinstance(demanded, int): + if isinstance(supplied, int) and isinstance(demanded, int): expr = str(supplied == demanded) msg = ( 'Unable to balance annual commodity {} in ({}, {}).\n' - 'No flows on one side of constraint expression:\n' + 'Nothing produces or consumes it:\n' ' {}\n' 'Possible reasons:\n' " - Is there a missing period in set 'time_future'?\n" diff --git a/temoa/components/flows.py b/temoa/components/flows.py index e9443ee4c..4b1248c7b 100644 --- a/temoa/components/flows.py +++ b/temoa/components/flows.py @@ -110,17 +110,23 @@ def create_commodity_balance_and_flow_sets(model: TemoaModel) -> None: """ logger.debug('Creating commodity balance and active flow index sets.') # 1. Commodity Balance - commodity_upstream = set( - model.commodity_up_stream_process - | model.retirement_production_processes - | model.import_regions + commodity_upstream_rpo = set( + (r, p, o) + for r, p, o in ( + model.commodity_up_stream_process + | model.retirement_production_processes | model.import_regions + ) + if o not in model.commodity_sink # only balanced if input to another process (caught below) ) - commodity_downstream = set( - model.commodity_down_stream_process - | model.capacity_consumption_techs - | model.export_regions + commodity_downstream_rpi = set( + (r, p, i) + for r, p, i in ( + model.commodity_down_stream_process + | model.capacity_consumption_techs | model.export_regions + ) + if i not in model.commodity_source # sources are never balanced (infinite source) ) - model.commodity_balance_rpc = commodity_upstream.intersection(commodity_downstream) + model.commodity_balance_rpc = commodity_upstream_rpo.union(commodity_downstream_rpi) # 2. Active Flow Indices (Time-Sliced) model.active_flow_rpsditvo = { diff --git a/temoa/components/technology.py b/temoa/components/technology.py index 8ed17f284..c78651664 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -338,30 +338,31 @@ def check_efficiency_indices(model: TemoaModel) -> None: """ # TODO: This could be upgraded to scan for finer resolution # by checking by REGION and PERIOD... Each region/period is unique. - c_physical = {i for r, i, t, v, o in model.efficiency.sparse_iterkeys()} - c_physical = c_physical | {i for r, i, t, v in model.construction_input.sparse_iterkeys()} - techs = {t for r, i, t, v, o in model.efficiency.sparse_iterkeys()} + c_inputs = {i for r, i, t, v, o in model.efficiency.sparse_iterkeys()} + c_inputs = c_inputs | {i for r, i, t, v in model.construction_input.sparse_iterkeys()} c_outputs = {o for r, i, t, v, o in model.efficiency.sparse_iterkeys()} c_outputs = c_outputs | {o for r, t, v, o in model.end_of_life_output.sparse_iterkeys()} + c_carrier = c_inputs | c_outputs - symdiff = c_physical.symmetric_difference(model.commodity_physical) + symdiff = c_carrier.symmetric_difference(model.commodity_carrier) if symdiff: msg = ( 'Unused or unspecified physical carriers. Either add or remove ' - 'the following elements to the Set commodity_physical.' + 'the following elements to the Set commodity_carrier.' '\n\n Element(s): {}' ) symdiff_str: set[str] = {str(i) for i in symdiff} f_msg = msg.format(', '.join(symdiff_str)) logger.error(f_msg) raise ValueError(f_msg) + + techs = {t for r, i, t, v, o in model.efficiency.sparse_iterkeys()} - symdiff = techs.symmetric_difference(model.tech_all) + symdiff = techs.symmetric_difference(model.tech_production) if symdiff: msg = ( 'Unused or unspecified technologies. Either add or remove ' - 'the following technology(ies) to the tech_resource or ' - 'tech_production Sets.\n\n Technology(ies): {}' + 'the following technologies.\n\n Technologies: {}' ) symdiff_str2: set[str] = {str(i) for i in symdiff} f_msg = msg.format(', '.join(symdiff_str2)) @@ -371,8 +372,8 @@ def check_efficiency_indices(model: TemoaModel) -> None: diff = model.commodity_demand - c_outputs if diff: msg = ( - 'Unused or unspecified outputs. Either add or remove the ' - 'following elements to the commodity_demand Set.' + 'Unmet demands. The following demand commodities are ' + 'not the output of any process.' '\n\n Element(s): {}' ) diff_str = (str(i) for i in diff) diff --git a/temoa/core/model.py b/temoa/core/model.py index 1f8fc9b14..2a44e0fa9 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -292,9 +292,12 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.commodity_waste = Set() self.commodity_flex = Set(within=self.commodity_physical) self.commodity_source = Set(within=self.commodity_physical) + self.commodity_sink = Set( + initialize=self.commodity_demand | self.commodity_waste + ) self.commodity_annual = Set(within=self.commodity_physical) self.commodity_carrier = Set( - initialize=self.commodity_physical | self.commodity_demand | self.commodity_waste + initialize=self.commodity_physical | self.commodity_sink ) self.commodity_all = Set( initialize=self.commodity_carrier | self.commodity_emissions, diff --git a/temoa/data_io/component_manifest.py b/temoa/data_io/component_manifest.py index d2d6b13dc..bb6625545 100644 --- a/temoa/data_io/component_manifest.py +++ b/temoa/data_io/component_manifest.py @@ -188,7 +188,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: table='commodity', columns=['name'], where_clause="flag LIKE '%p%' OR flag = 's' OR flag LIKE '%a%'", - validator_name='viable_input_comms', + validator_name='viable_comms', validation_map=(0,), is_period_filtered=False, ), @@ -206,7 +206,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: table='commodity', columns=['name'], where_clause="flag LIKE '%a%'", - validator_name='viable_input_comms', + validator_name='viable_comms', validation_map=(0,), is_period_filtered=False, ), diff --git a/temoa/model_checking/commodity_network_manager.py b/temoa/model_checking/commodity_network_manager.py index d93f73f3e..7762f5608 100644 --- a/temoa/model_checking/commodity_network_manager.py +++ b/temoa/model_checking/commodity_network_manager.py @@ -55,55 +55,23 @@ def _analyze_region(self, region: Region, data: NetworkModelData) -> None: continues until a pass over all periods finds no new orphans, signifying a stable, valid network. """ - for pass_num in range(1, 100): # Safety break after 100 iterations - orphans_this_pass: set[EdgeTuple] = set() - for period in self.periods: - cn = CommodityNetwork(region=region, period=period, model_data=data) - cn.analyze_network() - - # Log any demands that are not fully supported - for commodity in cn.unsupported_demands(): - logger.error( - 'Demand %s is not supported back to a source in region %s, period %d', - commodity, - region, - period, - ) - - # Collect newly identified orphans from this period's analysis - new_demand_orphans = cn.get_demand_side_orphans() - new_other_orphans = cn.get_other_orphans() - - # Add to the main collections, ensuring no duplicates - self.demand_orphans[region, period].update(new_demand_orphans) - self.other_orphans[region, period].update(new_other_orphans) + for period in self.periods: + cn = CommodityNetwork(region=region, period=period, model_data=data) + cn.analyze_network() - orphans_this_pass.update(new_demand_orphans) - orphans_this_pass.update(new_other_orphans) - - if not orphans_this_pass: - logger.debug( - 'Region %s analysis stable after %d pass(es).', + # Log any demands that are not fully supported + for commodity in cn.unsupported_demands(): + logger.warning( + 'Demand %s is not supported back to a source in region %s, period %d', + commodity, region, - pass_num - 1, + period, ) - break # Exit the loop if the network is stable - - logger.debug( - 'Pass %d for region %s: Found and removed %d orphan(s).', - pass_num, - region, - len(orphans_this_pass), - ) - for orphan in sorted(orphans_this_pass): - logger.warning('Removing orphan across all periods: %s', orphan) - - # Remove all orphans found in this pass from all periods in the region - for period in self.periods: - data.available_techs[region, period] -= orphans_this_pass - else: - logger.error('Region %s analysis did not converge after 100 passes.', region) + + # Add to the main collections, ensuring no duplicates + self.demand_orphans[region, period].update(cn.get_demand_side_orphans()) + self.other_orphans[region, period].update(cn.get_other_orphans()) def analyze_network(self) -> bool: """ diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 7602c5d39..ba8a86132 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -4157,6 +4157,10 @@ "FusionGasFuel", "earth" ], + "commodity_sink": [ + "RL", + "RH" + ], "commodity_source": [ "earth" ], diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index a592e10d7..53e176bd9 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -3,7 +3,7 @@ REPLACE INTO "commodity" VALUES('ELC', 'p', '# electricity', NULL); REPLACE INTO "commodity" VALUES('HYD', 'p', '# water', NULL); REPLACE INTO "commodity" VALUES('co2', 'e', '#CO2 emissions', NULL); REPLACE INTO "commodity" VALUES('RL', 'd', '# residential lighting', NULL); -REPLACE INTO "commodity" VALUES('earth', 'p', '# the source of stuff', NULL); +REPLACE INTO "commodity" VALUES('earth', 's', '# the source of stuff', NULL); REPLACE INTO "commodity_type" VALUES('w','waste commodity'); REPLACE INTO "commodity_type" VALUES('wa','waste annual commodity'); REPLACE INTO "commodity_type" VALUES('wp','waste physical commodity'); diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index fff350f17..83a9237a5 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -83,7 +83,7 @@ REPLACE INTO "commodity" VALUES('OIL', 'p', 'crude oil', NULL); REPLACE INTO "commodity" VALUES('NG', 'p', 'natural gas', NULL); REPLACE INTO "commodity" VALUES('URN', 'p', 'uranium', NULL); REPLACE INTO "commodity" VALUES('ETH', 'p', 'ethanol', NULL); -REPLACE INTO "commodity" VALUES('SOL', 'p', 'solar insolation', NULL); +REPLACE INTO "commodity" VALUES('SOL', 's', 'solar insolation', NULL); REPLACE INTO "commodity" VALUES('GSL', 'p', 'gasoline', NULL); REPLACE INTO "commodity" VALUES('DSL', 'p', 'diesel', NULL); REPLACE INTO "commodity" VALUES('ELC', 'p', 'electricity', NULL); diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 046b78dc4..f06bf0c90 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -45172,8 +45172,13 @@ "NG", "ETH" ], + "commodity_sink": [ + "VMT", + "RH" + ], "commodity_source": [ - "ethos" + "ethos", + "SOL" ], "commodity_waste": [], "operator": [ diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 583455ff8..2c66a4186 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -25048,6 +25048,11 @@ "URN", "GSL" ], + "commodity_sink": [ + "RL", + "RH", + "TX" + ], "commodity_source": [ "ethos" ], From 74fdfb39bc1fdf3d6e991d8c6ae0b09ce660361d Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Sun, 8 Mar 2026 19:03:57 -0400 Subject: [PATCH 434/587] Add new commodity_sink to docs --- docs/source/db_model_comparison.rst | 3 ++- docs/source/mathematical_formulation.rst | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/source/db_model_comparison.rst b/docs/source/db_model_comparison.rst index 1b6d06f4a..ce9347cde 100644 --- a/docs/source/db_model_comparison.rst +++ b/docs/source/db_model_comparison.rst @@ -67,7 +67,8 @@ Commodity Sets ":math:`\text{C}^w`", "commodity (flag='w','wa','wp')", "commodity_waste", "production can be greater than consumption; can be physical, annual, or neither (not balanced); filtered by waste flags" ":math:`\text{C}^a`", "commodity (flag='a')", "commodity_annual", "same as commodity physical but flows are only balanced over each period (:math:`\text{C}^a \subset \text{C}^p`); filtered by flag" ":math:`\text{C}^s`", "commodity (flag='s')", "commodity_source", "input sources (not balanced by CommodityBalance_constraint); filtered by flag" - ":math:`{}^*\text{C}^c`", "", "commodity_carrier", "physical energy carriers and end-use demands (:math:`\text{C}_p \cup \text{C}_d`); union of physical, demand, and waste commodities" + ":math:`{}^*\text{C}^k`", "", "commodity_sink", "commodities that exit the process network (:math:`\text{C}_d \cup \text{C}_w`); union of demand and waste commodities" + ":math:`{}^*\text{C}^c`", "", "commodity_carrier", "physical energy carriers and sinks (:math:`\text{C}_p \cup \text{C}_k`); union of physical and sink commodities" ":math:`{}^*\text{C}`", "", "commodity_all", "union of all commodity sets; union of carrier and emissions commodities" Other Sets diff --git a/docs/source/mathematical_formulation.rst b/docs/source/mathematical_formulation.rst index 76c8bce9e..3e98777ae 100644 --- a/docs/source/mathematical_formulation.rst +++ b/docs/source/mathematical_formulation.rst @@ -159,7 +159,8 @@ Sets ":math:`\text{C}^p`",":code:`commodity_physical`","string","general energy forms (e.g. electricity, coal, uranium, oil)" ":math:`\text{C}^a`",":code:`commodity_annual`","string","same as commodity physical but flows are only balanced over each period (:math:`\text{C}^a \subset \text{C}^p`)" ":math:`\text{C}^w`",":code:`commodity_waste`","string","production can be greater than consumption. can be physical, annual, or neither (not balanced)" - ":math:`{}^*\text{C}^c`",":code:`commodity_carrier`","string","physical energy carriers and end-use demands (:math:`\text{C}_p \cup \text{C}_d`)" + ":math:`{}^*\text{C}^k`",":code:`commodity_sink`","string","end-use demands and waste commodities (:math:`\text{C}_d \cup \text{C}_w`)" + ":math:`{}^*\text{C}^c`",":code:`commodity_carrier`","string","physical energy carriers and sinks (:math:`\text{C}_p \cup \text{C}_k`)" ":math:`\text{I}`",,"string","alias of :math:`\text{C}^p`; used in documentation only to mean ""input""" ":math:`\text{O}`",,"string","alias of :math:`\text{C}^c`; used in documentation only to mean ""output""" ":math:`\text{P}^e`",":code:`time_existing`",":math:`\mathbb{Z}`","model periods before optimization begins" From 137ee70313dd2c3d430296a2dd3454102f0e61ee Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Sun, 8 Mar 2026 19:44:49 -0400 Subject: [PATCH 435/587] Reorder efficiency_indices check --- temoa/components/technology.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/temoa/components/technology.py b/temoa/components/technology.py index c78651664..ed866f764 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -338,10 +338,23 @@ def check_efficiency_indices(model: TemoaModel) -> None: """ # TODO: This could be upgraded to scan for finer resolution # by checking by REGION and PERIOD... Each region/period is unique. - c_inputs = {i for r, i, t, v, o in model.efficiency.sparse_iterkeys()} - c_inputs = c_inputs | {i for r, i, t, v in model.construction_input.sparse_iterkeys()} c_outputs = {o for r, i, t, v, o in model.efficiency.sparse_iterkeys()} c_outputs = c_outputs | {o for r, t, v, o in model.end_of_life_output.sparse_iterkeys()} + + diff = model.commodity_demand - c_outputs + if diff: + msg = ( + 'Unmet demands. The following demand commodities are ' + 'not the output of any process.' + '\n\n Element(s): {}' + ) + diff_str = (str(i) for i in diff) + f_msg = msg.format(', '.join(diff_str)) + logger.error(f_msg) + raise ValueError(f_msg) + + c_inputs = {i for r, i, t, v, o in model.efficiency.sparse_iterkeys()} + c_inputs = c_inputs | {i for r, i, t, v in model.construction_input.sparse_iterkeys()} c_carrier = c_inputs | c_outputs symdiff = c_carrier.symmetric_difference(model.commodity_carrier) @@ -369,18 +382,6 @@ def check_efficiency_indices(model: TemoaModel) -> None: logger.error(f_msg) raise ValueError(f_msg) - diff = model.commodity_demand - c_outputs - if diff: - msg = ( - 'Unmet demands. The following demand commodities are ' - 'not the output of any process.' - '\n\n Element(s): {}' - ) - diff_str = (str(i) for i in diff) - f_msg = msg.format(', '.join(diff_str)) - logger.error(f_msg) - raise ValueError(f_msg) - def check_efficiency_variable(model: TemoaModel) -> None: count_rpitvo = {} From a1af15a99fdd051e5eb4ad5561e3a0197db5f2c4 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Sun, 8 Mar 2026 19:45:07 -0400 Subject: [PATCH 436/587] Add commodity_sink to model-only elements in docs --- docs/source/db_model_comparison.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/db_model_comparison.rst b/docs/source/db_model_comparison.rst index ce9347cde..9c5fe9fdf 100644 --- a/docs/source/db_model_comparison.rst +++ b/docs/source/db_model_comparison.rst @@ -282,7 +282,8 @@ Derived Sets "", "tech_with_capacity", "technologies eligible for capacitization; computed as tech_all - tech_uncap" "", "tech_or_group", "technologies or groups combined; union of tech_group_names | tech_all" - ":math:`{}^*\text{C}^c`", "commodity_carrier", "physical energy carriers and end-use demands; union of physical, demand, and waste commodities" + ":math:`{}^*\text{C}^k`", "commodity_sink", "commodities that exit the process network; union of demand and waste commodities" + ":math:`{}^*\text{C}^c`", "commodity_carrier", "physical energy carriers and sinks; union of physical and sink commodities" ":math:`{}^*\text{C}`", "commodity_all", "union of all commodity sets; union of carrier and emissions commodities" ":math:`\text{T}^e`", "tech_exist", "technologies with existing capacity; derived from existing_capacity table" From f40d4fc49ee6a3e90c9c62f26954b59bb8fa1b30 Mon Sep 17 00:00:00 2001 From: SutubraResearch Date: Thu, 12 Mar 2026 14:21:51 -0300 Subject: [PATCH 437/587] Add v_storage_init variable for non-seasonal storage Introduce a hub variable (v_storage_init) at the daily cycle wrap point that replaces v_storage_level on the LHS at d_last. A tie-back constraint (SL[d_last] = SI) keeps the formulation equivalent to a closed cycle. Empirically this improved barrier solve time ~25% on a 16-region national model, though the structural reason is not fully understood. --- temoa/components/storage.py | 83 ++++++++++++++++++++++++++++--------- temoa/core/model.py | 15 ++++--- tests/legacy_test_values.py | 25 +++++++---- tests/test_storage.py | 41 +++++++++++++----- 4 files changed, 120 insertions(+), 44 deletions(-) diff --git a/temoa/components/storage.py b/temoa/components/storage.py index 6171db723..220c54c6a 100644 --- a/temoa/components/storage.py +++ b/temoa/components/storage.py @@ -55,6 +55,25 @@ def seasonal_storage_constraint_indices( return set() +def storage_init_variable_indices( + model: TemoaModel, +) -> set[tuple[Region, Period, Season, Technology, Vintage]]: + """Index set for v_storage_init: one per (r, p, s, t, v) for non-seasonal storage. + + Introduces a hub variable at the daily cycle wrap point. Structurally equivalent + to the original closed-cycle formulation (presolve can substitute back), but + empirically improved barrier solve time ~25% on a 16-region national model. + The mechanism is not fully understood. + """ + if not model.storage_level_indices_rpsdtv: + return set() + return { + (r, p, s, t, v) + for r, p, s, _d, t, v in model.storage_level_indices_rpsdtv + if not model.is_seasonal_storage[t] + } + + def storage_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]] | None: @@ -73,28 +92,34 @@ def storage_energy_constraint( ) -> ExprLike: r""" This constraint enforces the continuity of storage level between time slices. - storage level in the next time slice (:math:`s_{next}, d_{next}`) is equal to - current storage level plus net charge in the current time slice. + + Uses the :code:`time_next` mapping to chain storage levels forward. For + non-seasonal storage, :math:`v\_storage\_init` replaces :math:`v\_storage\_level` + on the LHS at the daily cycle wrap point (last time-of-day). Combined with + the tie-back constraint (:math:`SL_{d_{last}} = SI`), this is structurally + equivalent to a closed cycle. + + Empirically, this swap improved barrier solve time ~25% on a 16-region + national model, though the structural reason is not fully understood. + + **Non-seasonal, last time-of-day (d_last):** .. math:: - :label: Storage Energy + {SI}_{r,p,s,t,v} + \text{net\_charge} = {SL}_{r,p,s_{next},d_{next},t,v} - {SL}_{r,p,s,d,t,v} - + \sum\limits_{I,O} \mathbf{FIS}_{r,p,s,d,i,t,v,o} \cdot {EFF}_{r,i,t,v,o} - - \sum\limits_{I,O} \mathbf{FO}_{r,p,s,d,i,t,v,o} - = {SL}_{r,p,s_{{next}},d_{{next}},t,v} + **All other time slices (non-seasonal and seasonal):** + + .. math:: + {SL}_{r,p,s,d,t,v} + \text{net\_charge} = {SL}_{r,p,s_{next},d_{next},t,v} - Note that for all seasonal representations except consecutive_days, the last time slice - of each season will loop back to the first time slice of the same season, preventing - seasonal deltas for non-seasonal storage (see SeasonalStorageEnergyUpperBound). + For seasonal storage, the last time-of-day is skipped (handled by + SeasonalStorageEnergy_constraint). """ - # We allow a non-zero daily delta only in the case of seasonal storage + # Seasonal storage: skip d_last (handled by SeasonalStorageEnergy_constraint) if model.is_seasonal_storage[t] and d == model.time_of_day.last(): - return Constraint.Skip # handled by SeasonalStorageEnergy_constraint + return Constraint.Skip - # This is the sum of all input=i sent TO storage tech t of vintage v with - # output=o in p,s,d charge = sum( model.v_flow_in[r, p, s, d, S_i, t, v, S_o] * get_variable_efficiency(model, r, p, s, d, S_i, t, v, S_o) @@ -102,8 +127,6 @@ def storage_energy_constraint( for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) - # This is the sum of all output=o withdrawn FROM storage tech t of vintage v - # with input=i in p,s,d discharge = sum( model.v_flow_out[r, p, s, d, S_i, t, v, S_o] for S_o in model.process_outputs[r, p, t, v] @@ -116,14 +139,34 @@ def storage_energy_constraint( d_next: TimeOfDay s_next, d_next = model.time_next[p, s, d] - expr = ( - model.v_storage_level[r, p, s, d, t, v] + stored_energy - == model.v_storage_level[r, p, s_next, d_next, t, v] - ) + if d == model.time_of_day.last(): + # Non-seasonal at d_last: use v_storage_init instead of v_storage_level + expr = ( + model.v_storage_init[r, p, s, t, v] + stored_energy + == model.v_storage_level[r, p, s_next, d_next, t, v] + ) + else: + expr = ( + model.v_storage_level[r, p, s, d, t, v] + stored_energy + == model.v_storage_level[r, p, s_next, d_next, t, v] + ) return expr +def storage_level_at_last_tod_constraint( + model: TemoaModel, r: Region, p: Period, s: Season, t: Technology, v: Vintage +) -> ExprLike: + """Tie v_storage_level at d_last to v_storage_init for non-seasonal storage. + + The storage_energy_constraint uses v_storage_init at d_last instead of + v_storage_level. This equality ensures v_storage_level[d_last] still + reflects the correct state for any constraints that reference it. + """ + d_last = model.time_of_day.last() + return model.v_storage_level[r, p, s, d_last, t, v] == model.v_storage_init[r, p, s, t, v] + + def seasonal_storage_energy_constraint( model: TemoaModel, r: Region, p: Period, s_seq: Season, t: Technology, v: Vintage ) -> ExprLike: diff --git a/temoa/core/model.py b/temoa/core/model.py index 2a44e0fa9..ede258b8d 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -292,13 +292,9 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.commodity_waste = Set() self.commodity_flex = Set(within=self.commodity_physical) self.commodity_source = Set(within=self.commodity_physical) - self.commodity_sink = Set( - initialize=self.commodity_demand | self.commodity_waste - ) + self.commodity_sink = Set(initialize=self.commodity_demand | self.commodity_waste) self.commodity_annual = Set(within=self.commodity_physical) - self.commodity_carrier = Set( - initialize=self.commodity_physical | self.commodity_sink - ) + self.commodity_carrier = Set(initialize=self.commodity_physical | self.commodity_sink) self.commodity_all = Set( initialize=self.commodity_carrier | self.commodity_emissions, validate=no_slash_or_pipe, @@ -775,6 +771,9 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.storage_level_rpsdtv = Set(dimen=6, initialize=storage.storage_level_variable_indices) self.v_storage_level = Var(self.storage_level_rpsdtv, domain=NonNegativeReals) + self.storage_init_rpstv = Set(dimen=5, initialize=storage.storage_init_variable_indices) + self.v_storage_init = Var(self.storage_init_rpstv, domain=NonNegativeReals) + self.seasonal_storage_level_rpstv = Set( dimen=5, initialize=storage.seasonal_storage_level_variable_indices ) @@ -914,6 +913,10 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.storage_constraints_rpsdtv, rule=storage.storage_energy_constraint ) + self.storage_level_last_tod_constraint = Constraint( + self.storage_init_rpstv, rule=storage.storage_level_at_last_tod_constraint + ) + self.storage_energy_upper_bound_constraint = Constraint( self.storage_constraints_rpsdtv, rule=storage.storage_energy_upper_bound_constraint ) diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index b4a355a9a..7ea253af8 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -26,13 +26,15 @@ class ExpectedVals(Enum): # increased after making annualretirement derived var # reduced 2025/07/25 by 504 after annualising demands # increased 2025/08/19 after making annual demands optional - ExpectedVals.CONSTR_COUNT: 2810, + # increased by 48 after tying v_storage_level[d_last] to v_storage_init + ExpectedVals.CONSTR_COUNT: 2858, # reduced by 6 when reworking storageinit. # increased after making annualretirement derived var # reduced 2025/07/21 after removing existing vintage v_new_capacity indices # reduced 2025/07/25 by 420 after annualising demands # increased 2025/08/19 after making annual demands optional - ExpectedVals.VAR_COUNT: 1960, + # increased by 48 after adding v_storage_init variable + ExpectedVals.VAR_COUNT: 2008, }, 'utopia': { # reduced after reworking storageinit -> storage was less constrained @@ -46,14 +48,16 @@ class ExpectedVals(Enum): # increased after making annualretirement derived var # reduced 2025/07/25 by 225 after annualising demands # increased 2025/08/19 after making annual demands optional - ExpectedVals.CONSTR_COUNT: 1486, + # increased by 27 after tying v_storage_level[d_last] to v_storage_init + ExpectedVals.CONSTR_COUNT: 1513, # reduced 3/27: unlim_cap techs now employed. # reduced by 4 in storageinit rework. # increased after making annualretirement derived var # reduced 2025/07/21 after removing existing vintage v_new_capacity indices # reduced 2025/07/25 by 200 after annualising demands # increased 2025/08/19 after making annual demands optional - ExpectedVals.VAR_COUNT: 1095, + # increased by 27 after adding v_storage_init variable + ExpectedVals.VAR_COUNT: 1122, }, 'mediumville': { # added 2025/06/12 prior to addition of dynamic reserve margin @@ -64,22 +68,27 @@ class ExpectedVals(Enum): # increased after reviving RampSeason constraints # reduced 2025/07/25 by 24 after annualising demands # increased 2025/08/19 after making annual demands optional - ExpectedVals.CONSTR_COUNT: 240, + # increased by 2 after tying v_storage_level[d_last] to v_storage_init + ExpectedVals.CONSTR_COUNT: 242, # reduced 2025/07/25 by 18 after annualising demands # increased 2025/08/19 after making annual demands optional - ExpectedVals.VAR_COUNT: 146, + # increased by 2 after adding v_storage_init variable + ExpectedVals.VAR_COUNT: 148, }, 'seasonal_storage': { # added 2025/06/16 after addition of seasonal storage + # updated: simplified storage_init to time_next chain with d_last swap ExpectedVals.OBJ_VALUE: 76661.0231, ExpectedVals.EFF_DOMAIN_SIZE: 24, ExpectedVals.EFF_INDEX_SIZE: 4, # reduced 2025/07/25 by 7 after annualising demands # increased 2025/08/19 after making annual demands optional - ExpectedVals.CONSTR_COUNT: 183, + # increased by 2 after tying v_storage_level[d_last] to v_storage_init + ExpectedVals.CONSTR_COUNT: 185, # reduced 2025/07/25 by 7 after annualising demands # increased 2025/08/19 after making annual demands optional - ExpectedVals.VAR_COUNT: 91, + # increased by 2 after adding v_storage_init variable + ExpectedVals.VAR_COUNT: 93, }, 'survival_curve': { # added 2025/06/19 after addition of survival curves diff --git a/tests/test_storage.py b/tests/test_storage.py index 7704e3353..fe80935ae 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -59,7 +59,11 @@ def test_storage_fraction(system_test_run: tuple[str, Any, TemoaModel, Any]) -> ) def test_state_sequencing(system_test_run: tuple[str, Any, TemoaModel, Any]) -> None: """ - Make sure that everything is looping properly + Make sure that everything is looping properly. + + All storage uses the time_next chain. For non-seasonal storage at d_last, + v_storage_init replaces v_storage_level on the LHS. Seasonal storage skips + d_last (handled by seasonal_storage_energy_constraint). """ model: TemoaModel # helps with typing for some reason... @@ -68,6 +72,8 @@ def test_state_sequencing(system_test_run: tuple[str, Any, TemoaModel, Any]) -> 'This model does not appear to have any available storage components' ) + d_last = model.time_of_day.last() + for r, p, s, d, t, v in model.storage_level_rpsdtv: charge = sum( model.v_flow_in[r, p, s, d, S_i, t, v, S_o].value * model.efficiency[r, S_i, t, v, S_o] # type: ignore [attr-defined] # I can't figure out how to get mypy to see value through the pyomo stubs @@ -80,15 +86,30 @@ def test_state_sequencing(system_test_run: tuple[str, Any, TemoaModel, Any]) -> for S_i in model.process_inputs_by_output[r, p, t, v, S_o] ) - s_next, d_next = model.time_next[p, s, d] - - state = model.v_storage_level[r, p, s, d, t, v].value # type: ignore [attr-defined] # I can't figure out how to get mypy to see value through the pyomo stubs - next_state = model.v_storage_level[r, p, s_next, d_next, t, v].value # type: ignore [attr-defined] # I can't figure out how to get mypy to see value through the pyomo stubs - - assert state + charge - discharge == pytest.approx(next_state, abs=1e-5), ( - f'model fails to correctly sequence storage states {r, p, s, t, v} sequenced {s, d} ' - f'to {s_next, d_next}' - ) + stored_energy = charge - discharge + + if model.is_seasonal_storage[t]: + # Seasonal storage: time_next chain (last tod skipped) + if d == d_last: + continue # handled by seasonal_storage_energy_constraint + s_next, d_next = model.time_next[p, s, d] + state = model.v_storage_level[r, p, s, d, t, v].value # type: ignore [attr-defined] + next_state = model.v_storage_level[r, p, s_next, d_next, t, v].value # type: ignore [attr-defined] + assert state + stored_energy == pytest.approx(next_state, abs=1e-5), ( + f'model fails to sequence storage {r, p, s, t, v} at {s, d} to {s_next, d_next}' + ) + else: + # Non-seasonal: time_next chain, v_storage_init at d_last + s_next, d_next = model.time_next[p, s, d] + if d == d_last: + prev_state = model.v_storage_init[r, p, s, t, v].value # type: ignore [attr-defined] + else: + prev_state = model.v_storage_level[r, p, s, d, t, v].value # type: ignore [attr-defined] + next_state = model.v_storage_level[r, p, s_next, d_next, t, v].value # type: ignore [attr-defined] + assert prev_state + stored_energy == pytest.approx(next_state, abs=1e-5), ( + f'model fails to sequence storage {r, p, s, t, v} at {s, d}: ' + f'state({prev_state}) + SE({stored_energy}) != next({next_state})' + ) @pytest.mark.parametrize( From d4c7cbf1375647ca3ce155d9ad3dbb550e92e272 Mon Sep 17 00:00:00 2001 From: SutubraResearch Date: Thu, 12 Mar 2026 14:21:56 -0300 Subject: [PATCH 438/587] Update JSON set caches for storage-init changes --- tests/testing_data/mediumville_sets.json | 16 ++ tests/testing_data/test_system_sets.json | 338 +++++++++++++++++++++++ tests/testing_data/utopia_sets.json | 191 +++++++++++++ 3 files changed, 545 insertions(+) diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index ba8a86132..a013ecc85 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -4332,5 +4332,21 @@ ], "vintage_optimize": [ 2025 + ], + "storage_init_rpstv": [ + [ + "B", + 2025, + "s2", + "batt", + 2025 + ], + [ + "B", + 2025, + "s1", + "batt", + 2025 + ] ] } diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index f06bf0c90..df2014de8 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -45354,5 +45354,343 @@ 2025, 2020, 2030 + ], + "storage_init_rpstv": [ + [ + "R1", + 2025, + "winter", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "spring", + "E_BATT", + 2030 + ], + [ + "R2", + 2030, + "summer", + "E_BATT", + 2030 + ], + [ + "R2", + 2020, + "winter", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "spring", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "summer", + "E_BATT", + 2030 + ], + [ + "R1", + 2025, + "spring", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "winter", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "spring", + "E_BATT", + 2025 + ], + [ + "R1", + 2025, + "fall", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "summer", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "fall", + "E_BATT", + 2030 + ], + [ + "R1", + 2020, + "winter", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "fall", + "E_BATT", + 2025 + ], + [ + "R2", + 2025, + "winter", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "summer", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "spring", + "E_BATT", + 2020 + ], + [ + "R2", + 2020, + "summer", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "winter", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "fall", + "E_BATT", + 2030 + ], + [ + "R2", + 2020, + "spring", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "summer", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "summer", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "fall", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "spring", + "E_BATT", + 2025 + ], + [ + "R1", + 2025, + "spring", + "E_BATT", + 2025 + ], + [ + "R1", + 2025, + "fall", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "winter", + "E_BATT", + 2025 + ], + [ + "R1", + 2020, + "spring", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "fall", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "summer", + "E_BATT", + 2025 + ], + [ + "R2", + 2030, + "spring", + "E_BATT", + 2025 + ], + [ + "R1", + 2020, + "fall", + "E_BATT", + 2020 + ], + [ + "R1", + 2025, + "winter", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "winter", + "E_BATT", + 2030 + ], + [ + "R1", + 2030, + "summer", + "E_BATT", + 2025 + ], + [ + "R1", + 2025, + "summer", + "E_BATT", + 2025 + ], + [ + "R2", + 2025, + "spring", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "summer", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "fall", + "E_BATT", + 2025 + ], + [ + "R1", + 2030, + "spring", + "E_BATT", + 2030 + ], + [ + "R2", + 2025, + "fall", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "winter", + "E_BATT", + 2030 + ], + [ + "R2", + 2020, + "fall", + "E_BATT", + 2020 + ], + [ + "R2", + 2025, + "winter", + "E_BATT", + 2020 + ], + [ + "R1", + 2020, + "summer", + "E_BATT", + 2020 + ], + [ + "R2", + 2030, + "winter", + "E_BATT", + 2020 + ], + [ + "R1", + 2030, + "fall", + "E_BATT", + 2025 + ] ] } diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 2c66a4186..52487dcd4 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -25246,5 +25246,196 @@ 2000, 2010, 1990 + ], + "storage_init_rpstv": [ + [ + "utopia", + 2010, + "inter", + "E51", + 2000 + ], + [ + "utopia", + 2010, + "summer", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "E51", + 1980 + ], + [ + "utopia", + 2010, + "winter", + "E51", + 1990 + ], + [ + "utopia", + 1990, + "summer", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "inter", + "E51", + 2000 + ], + [ + "utopia", + 1990, + "winter", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "E51", + 2010 + ], + [ + "utopia", + 2010, + "inter", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "E51", + 2000 + ], + [ + "utopia", + 1990, + "winter", + "E51", + 1980 + ], + [ + "utopia", + 2010, + "summer", + "E51", + 2000 + ], + [ + "utopia", + 2000, + "inter", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "E51", + 1980 + ], + [ + "utopia", + 2010, + "inter", + "E51", + 1980 + ], + [ + "utopia", + 1990, + "inter", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "summer", + "E51", + 2000 + ], + [ + "utopia", + 2000, + "winter", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "winter", + "E51", + 2010 + ], + [ + "utopia", + 2010, + "inter", + "E51", + 2010 + ], + [ + "utopia", + 2000, + "inter", + "E51", + 1980 + ], + [ + "utopia", + 1990, + "summer", + "E51", + 1990 + ], + [ + "utopia", + 2010, + "summer", + "E51", + 1990 + ], + [ + "utopia", + 1990, + "inter", + "E51", + 1980 + ], + [ + "utopia", + 2000, + "summer", + "E51", + 1990 + ], + [ + "utopia", + 2000, + "winter", + "E51", + 1980 + ], + [ + "utopia", + 2010, + "winter", + "E51", + 2000 + ] ] } From 27dbb1414d0f65939aed197cf2aa89b89181d6d2 Mon Sep 17 00:00:00 2001 From: SutubraResearch Date: Wed, 18 Mar 2026 12:06:02 -0300 Subject: [PATCH 439/587] Drop DemandActivity constraints for single-tech demands --- temoa/components/commodities.py | 36 +++++++++++++++++++++++++-------- temoa/core/model.py | 8 ++------ tests/legacy_test_values.py | 9 ++++++--- 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index 1ece9382f..f0d927c7a 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -102,14 +102,34 @@ def demand_constraint_error_check(supply: Any, r: Region, p: Period, dem: Commod def demand_activity_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage, Commodity]]: - indices = { - (r, p, s, d, t, v, dem) - for r, p, dem in model.demand_constraint_rpc - for t, v in model.commodity_up_stream_process[r, p, dem] - if t not in model.tech_annual - for s in model.time_season[p] - for d in model.time_of_day - } + """Index set for DemandActivity. Drops indices for single-tech demands. + + When exactly one non-annual (tech, vintage) pair with a single input serves a + demand commodity (and no annual techs co-serve it), the flow variables are fixed + directly and DAC indices are omitted. + """ + indices = set() + for r, p, dem in model.demand_constraint_rpc: + upstream = list(model.commodity_up_stream_process[r, p, dem]) + non_annual = [(t, v) for t, v in upstream if t not in model.tech_annual] + has_annual = any(t in model.tech_annual for t, _ in upstream) + # Single non-annual (t,v) with one input, no annual co-techs: fix variables + if len(non_annual) == 1 and not has_annual: + t, v = non_annual[0] + inputs = list(model.process_inputs_by_output[r, p, t, v, dem]) + if len(inputs) == 1: + i = inputs[0] + dem_val = value(model.demand[r, p, dem]) + model.v_flow_out_annual[r, p, i, t, v, dem].fix(dem_val) + for s in model.time_season[p]: + for d in model.time_of_day: + dsd = value(model.demand_specific_distribution[r, p, s, d, dem]) + model.v_flow_out[r, p, s, d, i, t, v, dem].fix(dem_val * dsd) + continue + for t, v in non_annual: + for s in model.time_season[p]: + for d in model.time_of_day: + indices.add((r, p, s, d, t, v, dem)) return indices diff --git a/temoa/core/model.py b/temoa/core/model.py index 2a44e0fa9..087350ddb 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -292,13 +292,9 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.commodity_waste = Set() self.commodity_flex = Set(within=self.commodity_physical) self.commodity_source = Set(within=self.commodity_physical) - self.commodity_sink = Set( - initialize=self.commodity_demand | self.commodity_waste - ) + self.commodity_sink = Set(initialize=self.commodity_demand | self.commodity_waste) self.commodity_annual = Set(within=self.commodity_physical) - self.commodity_carrier = Set( - initialize=self.commodity_physical | self.commodity_sink - ) + self.commodity_carrier = Set(initialize=self.commodity_physical | self.commodity_sink) self.commodity_all = Set( initialize=self.commodity_carrier | self.commodity_emissions, validate=no_slash_or_pipe, diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index b4a355a9a..071889eeb 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -46,7 +46,8 @@ class ExpectedVals(Enum): # increased after making annualretirement derived var # reduced 2025/07/25 by 225 after annualising demands # increased 2025/08/19 after making annual demands optional - ExpectedVals.CONSTR_COUNT: 1486, + # reduced by 12 after dropping DAC for single-tech demands + ExpectedVals.CONSTR_COUNT: 1474, # reduced 3/27: unlim_cap techs now employed. # reduced by 4 in storageinit rework. # increased after making annualretirement derived var @@ -64,7 +65,8 @@ class ExpectedVals(Enum): # increased after reviving RampSeason constraints # reduced 2025/07/25 by 24 after annualising demands # increased 2025/08/19 after making annual demands optional - ExpectedVals.CONSTR_COUNT: 240, + # reduced by 8 after dropping DAC for single-tech demands + ExpectedVals.CONSTR_COUNT: 232, # reduced 2025/07/25 by 18 after annualising demands # increased 2025/08/19 after making annual demands optional ExpectedVals.VAR_COUNT: 146, @@ -76,7 +78,8 @@ class ExpectedVals(Enum): ExpectedVals.EFF_INDEX_SIZE: 4, # reduced 2025/07/25 by 7 after annualising demands # increased 2025/08/19 after making annual demands optional - ExpectedVals.CONSTR_COUNT: 183, + # reduced by 8 after dropping DAC for single-tech demands + ExpectedVals.CONSTR_COUNT: 175, # reduced 2025/07/25 by 7 after annualising demands # increased 2025/08/19 after making annual demands optional ExpectedVals.VAR_COUNT: 91, From 327142d22c485e3a66640fb28f70918eb251ce56 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 18 Mar 2026 18:15:08 -0400 Subject: [PATCH 440/587] Move singleton demand check to separate buildaction --- stubs/pyomo/core/base/var.pyi | 1 + temoa/components/commodities.py | 70 +++++++++++++++++++-------------- temoa/core/model.py | 3 ++ temoa/types/__init__.py | 2 + temoa/types/set_types.py | 1 + 5 files changed, 47 insertions(+), 30 deletions(-) diff --git a/stubs/pyomo/core/base/var.pyi b/stubs/pyomo/core/base/var.pyi index 1f98d41ef..e53501e39 100644 --- a/stubs/pyomo/core/base/var.pyi +++ b/stubs/pyomo/core/base/var.pyi @@ -148,6 +148,7 @@ class Var(IndexedComponent, IndexedComponent_NDArrayMixin): extract_values = get_values def set_values(self, new_values, skip_validation: bool = False) -> None: ... def get_units(self): ... + def __getitem__(self, args) -> VarData: ... def add(self, index): ... def construct(self, data=None) -> None: ... def __lt__(self, other: typingAny) -> typingAny: ... diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index f0d927c7a..f75e4e6b3 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -16,7 +16,7 @@ from operator import itemgetter as iget from typing import TYPE_CHECKING, Any, cast -from pyomo.environ import value +from pyomo.environ import Constraint, value if TYPE_CHECKING: from temoa.core.model import TemoaModel @@ -94,6 +94,34 @@ def demand_constraint_error_check(supply: Any, r: Region, p: Period, dem: Commod raise Exception(msg.format(dem, r, p)) +def check_singleton_demands(model: TemoaModel) -> None: + """ + Check for demand commodities that are only produced by a single + (r, i, t, v, o) sub-process. If such a case is found, the flow variables are + fixed directly and demand activity and demand constraints are skipped + as these constraints would otherwise be overdefined and unstable. + """ + for r, p, dem in model.demand_constraint_rpc: + upstream_itv = { + (i, t, v) + for t, v in model.commodity_up_stream_process.get((r, p, dem), []) + for i in model.process_inputs_by_output.get((r, p, t, v, dem), []) + } + if len(upstream_itv) != 1: + # not singleton, regular demand constraints + continue + + # singleton, fix everything and skip demand constraints + val = value(model.demand[r, p, dem]) + i, t, v = next(iter(upstream_itv)) + model.v_flow_out_annual[r, p, i, t, v, dem].fix(val) + if t not in model.tech_annual: + for s, d in cross_product(model.time_season[p], model.time_of_day): + dsd = value(model.demand_specific_distribution[r, p, s, d, dem]) + model.v_flow_out[r, p, s, d, i, t, v, dem].fix(val * dsd) + model.singleton_demands.add((r, p, dem)) + + # ============================================================================ # PYOMO INDEX SET FUNCTIONS # ============================================================================ @@ -108,28 +136,15 @@ def demand_activity_constraint_indices( demand commodity (and no annual techs co-serve it), the flow variables are fixed directly and DAC indices are omitted. """ - indices = set() - for r, p, dem in model.demand_constraint_rpc: - upstream = list(model.commodity_up_stream_process[r, p, dem]) - non_annual = [(t, v) for t, v in upstream if t not in model.tech_annual] - has_annual = any(t in model.tech_annual for t, _ in upstream) - # Single non-annual (t,v) with one input, no annual co-techs: fix variables - if len(non_annual) == 1 and not has_annual: - t, v = non_annual[0] - inputs = list(model.process_inputs_by_output[r, p, t, v, dem]) - if len(inputs) == 1: - i = inputs[0] - dem_val = value(model.demand[r, p, dem]) - model.v_flow_out_annual[r, p, i, t, v, dem].fix(dem_val) - for s in model.time_season[p]: - for d in model.time_of_day: - dsd = value(model.demand_specific_distribution[r, p, s, d, dem]) - model.v_flow_out[r, p, s, d, i, t, v, dem].fix(dem_val * dsd) - continue - for t, v in non_annual: - for s in model.time_season[p]: - for d in model.time_of_day: - indices.add((r, p, s, d, t, v, dem)) + indices = { + (r, p, s, d, t, v, dem) + for r, p, dem in model.demand_constraint_rpc + if (r, p, dem) not in model.singleton_demands + for t, v in model.commodity_up_stream_process[r, p, dem] + if t not in model.tech_annual + for s in model.time_season[p] + for d in model.time_of_day + } return indices @@ -196,13 +211,8 @@ def demand_constraint(model: TemoaModel, r: Region, p: Period, dem: Commodity) - could satisfy both an end-use and internal system demand, then the output from :math:`\textbf{FO}` and :math:`\textbf{FOA}` would be double counted.""" - # All demand techs are annual now - # supply = sum( - # M.v_flow_out[r, p, s, d, s_i, s_t, s_v, dem] - # for s_t, s_v in M.commodity_up_stream_process[r, p, dem] - # if s_t not in M.tech_annual - # for s_i in M.process_inputs_by_output[r, p, s_t, s_v, dem] - # ) + if (r, p, dem) in model.singleton_demands: + return Constraint.Skip supply_annual = sum( model.v_flow_out_annual[r, p, s_i, s_t, s_v, dem] diff --git a/temoa/core/model.py b/temoa/core/model.py index 087350ddb..93714b4e8 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -135,6 +135,8 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.group_region_active_flow_rpt: t.GroupRegionActiveFlowSet = ( set() # Set of valid group-region, period, tech indices ) + # demands served by a single r, i, t, v, o sub-process + self.singleton_demands: t.SingletonDemandsSet = set() self.commodity_balance_rpc: t.CommodityBalancedSet = ( set() ) # Set of valid region-period-commodity indices to balance @@ -858,6 +860,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: # Declare core model constraints that ensure proper system functioning # In driving order, starting with the need to meet end-use demands + self.check_singleton_demands = BuildAction(rule=commodities.check_singleton_demands) self.demand_constraint = Constraint( self.demand_constraint_rpc, rule=commodities.demand_constraint ) diff --git a/temoa/types/__init__.py b/temoa/types/__init__.py index 6241d6a41..022a245d9 100644 --- a/temoa/types/__init__.py +++ b/temoa/types/__init__.py @@ -68,6 +68,7 @@ 'GroupRegionActiveFlowSet', 'NewCapacitySet', 'SeasonalStorageLevelIndicesSet', + 'SingletonDemandsSet', 'StorageLevelIndicesSet', # Type aliases 'ExprLike', @@ -151,6 +152,7 @@ GroupRegionActiveFlowSet, NewCapacitySet, SeasonalStorageLevelIndicesSet, + SingletonDemandsSet, StorageLevelIndicesSet, ) diff --git a/temoa/types/set_types.py b/temoa/types/set_types.py index df1d1df4d..d910db32e 100644 --- a/temoa/types/set_types.py +++ b/temoa/types/set_types.py @@ -34,3 +34,4 @@ GroupRegionActiveFlowSet = set[tuple[Region, Period, Technology]] | None CommodityBalancedSet = set[tuple[Region, Period, Commodity]] +SingletonDemandsSet = set[tuple[Region, Period, Commodity]] From 0416df08494dbf2d8f192f5a2139640b3ed8edf6 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 18 Mar 2026 18:34:02 -0400 Subject: [PATCH 441/587] Update test sets --- tests/legacy_test_values.py | 12 +-- tests/testing_data/mediumville_sets.json | 72 --------------- tests/testing_data/utopia_sets.json | 108 ----------------------- 3 files changed, 6 insertions(+), 186 deletions(-) diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index 071889eeb..e6379fc44 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -46,8 +46,8 @@ class ExpectedVals(Enum): # increased after making annualretirement derived var # reduced 2025/07/25 by 225 after annualising demands # increased 2025/08/19 after making annual demands optional - # reduced by 12 after dropping DAC for single-tech demands - ExpectedVals.CONSTR_COUNT: 1474, + # reduced by 14 after dropping DAC for single-tech demands + ExpectedVals.CONSTR_COUNT: 1472, # reduced 3/27: unlim_cap techs now employed. # reduced by 4 in storageinit rework. # increased after making annualretirement derived var @@ -65,8 +65,8 @@ class ExpectedVals(Enum): # increased after reviving RampSeason constraints # reduced 2025/07/25 by 24 after annualising demands # increased 2025/08/19 after making annual demands optional - # reduced by 8 after dropping DAC for single-tech demands - ExpectedVals.CONSTR_COUNT: 232, + # reduced by 10 after dropping DAC for single-tech demands + ExpectedVals.CONSTR_COUNT: 230, # reduced 2025/07/25 by 18 after annualising demands # increased 2025/08/19 after making annual demands optional ExpectedVals.VAR_COUNT: 146, @@ -78,8 +78,8 @@ class ExpectedVals(Enum): ExpectedVals.EFF_INDEX_SIZE: 4, # reduced 2025/07/25 by 7 after annualising demands # increased 2025/08/19 after making annual demands optional - # reduced by 8 after dropping DAC for single-tech demands - ExpectedVals.CONSTR_COUNT: 175, + # reduced by 9 after dropping DAC for single-tech demands + ExpectedVals.CONSTR_COUNT: 174, # reduced 2025/07/25 by 7 after annualising demands # increased 2025/08/19 after making annual demands optional ExpectedVals.VAR_COUNT: 91, diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index ba8a86132..6dfdb1d80 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -1897,15 +1897,6 @@ 2025, "RH" ], - [ - "B", - 2025, - "s2", - "d1", - "bulbs", - 2025, - "RL" - ], [ "B", 2025, @@ -1915,15 +1906,6 @@ 2025, "RH" ], - [ - "B", - 2025, - "s1", - "d1", - "bulbs", - 2025, - "RL" - ], [ "B", 2025, @@ -1942,15 +1924,6 @@ 2025, "RH" ], - [ - "A", - 2025, - "s1", - "d2", - "bulbs", - 2025, - "RL" - ], [ "A", 2025, @@ -1960,15 +1933,6 @@ 2025, "RH" ], - [ - "A", - 2025, - "s1", - "d1", - "bulbs", - 2025, - "RL" - ], [ "A", 2025, @@ -1987,15 +1951,6 @@ 2025, "RH" ], - [ - "B", - 2025, - "s1", - "d2", - "bulbs", - 2025, - "RL" - ], [ "B", 2025, @@ -2005,15 +1960,6 @@ 2025, "RH" ], - [ - "A", - 2025, - "s2", - "d2", - "bulbs", - 2025, - "RL" - ], [ "B", 2025, @@ -2041,24 +1987,6 @@ 2025, "RH" ], - [ - "B", - 2025, - "s2", - "d2", - "bulbs", - 2025, - "RL" - ], - [ - "A", - 2025, - "s2", - "d1", - "bulbs", - 2025, - "RL" - ], [ "B", 2025, diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 2c66a4186..0278dfe67 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -10505,15 +10505,6 @@ 2000, "TX" ], - [ - "utopia", - 2000, - "inter", - "day", - "RL1", - 2000, - "RL" - ], [ "utopia", 2000, @@ -10667,15 +10658,6 @@ 2000, "RH" ], - [ - "utopia", - 2010, - "inter", - "night", - "RL1", - 2010, - "RL" - ], [ "utopia", 2000, @@ -10955,15 +10937,6 @@ 1990, "TX" ], - [ - "utopia", - 2000, - "summer", - "day", - "RL1", - 2000, - "RL" - ], [ "utopia", 2000, @@ -11018,15 +10991,6 @@ 1980, "RL" ], - [ - "utopia", - 2000, - "winter", - "night", - "RL1", - 2000, - "RL" - ], [ "utopia", 2000, @@ -11072,15 +11036,6 @@ 1980, "TX" ], - [ - "utopia", - 2010, - "summer", - "night", - "RL1", - 2010, - "RL" - ], [ "utopia", 1990, @@ -11099,15 +11054,6 @@ 2010, "RH" ], - [ - "utopia", - 2000, - "winter", - "day", - "RL1", - 2000, - "RL" - ], [ "utopia", 2000, @@ -11279,15 +11225,6 @@ 1990, "RH" ], - [ - "utopia", - 2010, - "winter", - "night", - "RL1", - 2010, - "RL" - ], [ "utopia", 1990, @@ -11369,15 +11306,6 @@ 2010, "RH" ], - [ - "utopia", - 2000, - "inter", - "night", - "RL1", - 2000, - "RL" - ], [ "utopia", 2010, @@ -11549,15 +11477,6 @@ 1990, "RH" ], - [ - "utopia", - 2010, - "summer", - "day", - "RL1", - 2010, - "RL" - ], [ "utopia", 2000, @@ -12125,15 +12044,6 @@ 1990, "TX" ], - [ - "utopia", - 2000, - "summer", - "night", - "RL1", - 2000, - "RL" - ], [ "utopia", 1990, @@ -12161,15 +12071,6 @@ 2000, "TX" ], - [ - "utopia", - 2010, - "inter", - "day", - "RL1", - 2010, - "RL" - ], [ "utopia", 2000, @@ -12386,15 +12287,6 @@ 1990, "TX" ], - [ - "utopia", - 2010, - "winter", - "day", - "RL1", - 2010, - "RL" - ], [ "utopia", 2000, From 467f7c96b7ab4481317a349c39a42715109be5c6 Mon Sep 17 00:00:00 2001 From: SutubraResearch Date: Thu, 19 Mar 2026 09:19:05 -0300 Subject: [PATCH 442/587] Fix mypy attr-defined errors and update set caches for DAC skip --- temoa/components/commodities.py | 4 +- tests/testing_data/mediumville_sets.json | 72 --------------- tests/testing_data/utopia_sets.json | 108 ----------------------- 3 files changed, 2 insertions(+), 182 deletions(-) diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index f0d927c7a..cf978d0e7 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -120,11 +120,11 @@ def demand_activity_constraint_indices( if len(inputs) == 1: i = inputs[0] dem_val = value(model.demand[r, p, dem]) - model.v_flow_out_annual[r, p, i, t, v, dem].fix(dem_val) + model.v_flow_out_annual[r, p, i, t, v, dem].fix(dem_val) # type: ignore[attr-defined] for s in model.time_season[p]: for d in model.time_of_day: dsd = value(model.demand_specific_distribution[r, p, s, d, dem]) - model.v_flow_out[r, p, s, d, i, t, v, dem].fix(dem_val * dsd) + model.v_flow_out[r, p, s, d, i, t, v, dem].fix(dem_val * dsd) # type: ignore[attr-defined] continue for t, v in non_annual: for s in model.time_season[p]: diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index ba8a86132..6dfdb1d80 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -1897,15 +1897,6 @@ 2025, "RH" ], - [ - "B", - 2025, - "s2", - "d1", - "bulbs", - 2025, - "RL" - ], [ "B", 2025, @@ -1915,15 +1906,6 @@ 2025, "RH" ], - [ - "B", - 2025, - "s1", - "d1", - "bulbs", - 2025, - "RL" - ], [ "B", 2025, @@ -1942,15 +1924,6 @@ 2025, "RH" ], - [ - "A", - 2025, - "s1", - "d2", - "bulbs", - 2025, - "RL" - ], [ "A", 2025, @@ -1960,15 +1933,6 @@ 2025, "RH" ], - [ - "A", - 2025, - "s1", - "d1", - "bulbs", - 2025, - "RL" - ], [ "A", 2025, @@ -1987,15 +1951,6 @@ 2025, "RH" ], - [ - "B", - 2025, - "s1", - "d2", - "bulbs", - 2025, - "RL" - ], [ "B", 2025, @@ -2005,15 +1960,6 @@ 2025, "RH" ], - [ - "A", - 2025, - "s2", - "d2", - "bulbs", - 2025, - "RL" - ], [ "B", 2025, @@ -2041,24 +1987,6 @@ 2025, "RH" ], - [ - "B", - 2025, - "s2", - "d2", - "bulbs", - 2025, - "RL" - ], - [ - "A", - 2025, - "s2", - "d1", - "bulbs", - 2025, - "RL" - ], [ "B", 2025, diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 2c66a4186..0278dfe67 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -10505,15 +10505,6 @@ 2000, "TX" ], - [ - "utopia", - 2000, - "inter", - "day", - "RL1", - 2000, - "RL" - ], [ "utopia", 2000, @@ -10667,15 +10658,6 @@ 2000, "RH" ], - [ - "utopia", - 2010, - "inter", - "night", - "RL1", - 2010, - "RL" - ], [ "utopia", 2000, @@ -10955,15 +10937,6 @@ 1990, "TX" ], - [ - "utopia", - 2000, - "summer", - "day", - "RL1", - 2000, - "RL" - ], [ "utopia", 2000, @@ -11018,15 +10991,6 @@ 1980, "RL" ], - [ - "utopia", - 2000, - "winter", - "night", - "RL1", - 2000, - "RL" - ], [ "utopia", 2000, @@ -11072,15 +11036,6 @@ 1980, "TX" ], - [ - "utopia", - 2010, - "summer", - "night", - "RL1", - 2010, - "RL" - ], [ "utopia", 1990, @@ -11099,15 +11054,6 @@ 2010, "RH" ], - [ - "utopia", - 2000, - "winter", - "day", - "RL1", - 2000, - "RL" - ], [ "utopia", 2000, @@ -11279,15 +11225,6 @@ 1990, "RH" ], - [ - "utopia", - 2010, - "winter", - "night", - "RL1", - 2010, - "RL" - ], [ "utopia", 1990, @@ -11369,15 +11306,6 @@ 2010, "RH" ], - [ - "utopia", - 2000, - "inter", - "night", - "RL1", - 2000, - "RL" - ], [ "utopia", 2010, @@ -11549,15 +11477,6 @@ 1990, "RH" ], - [ - "utopia", - 2010, - "summer", - "day", - "RL1", - 2010, - "RL" - ], [ "utopia", 2000, @@ -12125,15 +12044,6 @@ 1990, "TX" ], - [ - "utopia", - 2000, - "summer", - "night", - "RL1", - 2000, - "RL" - ], [ "utopia", 1990, @@ -12161,15 +12071,6 @@ 2000, "TX" ], - [ - "utopia", - 2010, - "inter", - "day", - "RL1", - 2010, - "RL" - ], [ "utopia", 2000, @@ -12386,15 +12287,6 @@ 1990, "TX" ], - [ - "utopia", - 2010, - "winter", - "day", - "RL1", - 2010, - "RL" - ], [ "utopia", 2000, From 1d26770376642f67036c94eccc90ba7654fdc9f9 Mon Sep 17 00:00:00 2001 From: SutubraResearch Date: Fri, 20 Mar 2026 10:48:20 -0300 Subject: [PATCH 443/587] Remove unused type: ignore comments from test_storage --- tests/test_storage.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/test_storage.py b/tests/test_storage.py index 7704e3353..fe93aa162 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -38,7 +38,7 @@ def test_storage_fraction(system_test_run: tuple[str, Any, TemoaModel, Any]) -> for r, p, s, d, t, v, op in model.limit_storage_fraction_constraint_rpsdtv: energy = ( model.limit_storage_fraction[r, p, s, d, t, v, op] - * model.v_capacity[r, p, t, v].value # type: ignore [attr-defined] # I can't figure out how to get mypy to see value through the pyomo stubs + * model.v_capacity[r, p, t, v].value * model.capacity_to_activity[r, t] * (model.storage_duration[r, t] / 8760) * model.segment_fraction_per_season[p, s] @@ -46,7 +46,7 @@ def test_storage_fraction(system_test_run: tuple[str, Any, TemoaModel, Any]) -> * model.process_life_frac[r, p, t, v] ) - assert model.v_storage_level[r, p, s, d, t, v].value == pytest.approx(energy, abs=1e-5), ( # type: ignore [attr-defined] # I can't figure out how to get mypy to see value through the pyomo stubs + assert model.v_storage_level[r, p, s, d, t, v].value == pytest.approx(energy, abs=1e-5), ( f'model fails to initialise storage state at start of season {r, p, s, d, t, v}' ) @@ -70,20 +70,20 @@ def test_state_sequencing(system_test_run: tuple[str, Any, TemoaModel, Any]) -> for r, p, s, d, t, v in model.storage_level_rpsdtv: charge = sum( - model.v_flow_in[r, p, s, d, S_i, t, v, S_o].value * model.efficiency[r, S_i, t, v, S_o] # type: ignore [attr-defined] # I can't figure out how to get mypy to see value through the pyomo stubs + model.v_flow_in[r, p, s, d, S_i, t, v, S_o].value * model.efficiency[r, S_i, t, v, S_o] for S_i in model.process_inputs[r, p, t, v] for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) discharge = sum( - model.v_flow_out[r, p, s, d, S_i, t, v, S_o].value # type: ignore [attr-defined] # I can't figure out how to get mypy to see value through the pyomo stubs + model.v_flow_out[r, p, s, d, S_i, t, v, S_o].value for S_o in model.process_outputs[r, p, t, v] for S_i in model.process_inputs_by_output[r, p, t, v, S_o] ) s_next, d_next = model.time_next[p, s, d] - state = model.v_storage_level[r, p, s, d, t, v].value # type: ignore [attr-defined] # I can't figure out how to get mypy to see value through the pyomo stubs - next_state = model.v_storage_level[r, p, s_next, d_next, t, v].value # type: ignore [attr-defined] # I can't figure out how to get mypy to see value through the pyomo stubs + state = model.v_storage_level[r, p, s, d, t, v].value + next_state = model.v_storage_level[r, p, s_next, d_next, t, v].value assert state + charge - discharge == pytest.approx(next_state, abs=1e-5), ( f'model fails to correctly sequence storage states {r, p, s, t, v} sequenced {s, d} ' @@ -122,10 +122,10 @@ def test_storage_flow_balance(system_test_run: tuple[str, Any, TemoaModel, Any]) # calculate the inflow and outflow. Inflow is taxed by efficiency in the model, # so we need to do that here as well inflow = sum( - model.v_flow_in[r, p, s, d, i, t, v, o].value * model.efficiency[r, i, t, v, o] # type: ignore [attr-defined] # I can't figure out how to get mypy to see value through the pyomo stubs + model.v_flow_in[r, p, s, d, i, t, v, o].value * model.efficiency[r, i, t, v, o] for (r, p, s, d, i, t, v, o) in inflow_indices ) - outflow = sum(model.v_flow_out[idx].value for idx in outflow_indices) # type: ignore [attr-defined] # I can't figure out how to get mypy to see value through the pyomo stubs + outflow = sum(model.v_flow_out[idx].value for idx in outflow_indices) assert inflow == pytest.approx(outflow, abs=1e-5), ( f'total inflow and outflow of storage tech {s_tech} do not match', From c67a2c0b53f9e0a4db5676e6c25fe5c0cae09bec Mon Sep 17 00:00:00 2001 From: SutubraResearch Date: Thu, 12 Mar 2026 14:22:39 -0300 Subject: [PATCH 444/587] Add configurable output threshold filtering Add output_threshold config option to filter near-zero values from result tables. Defaults to 0 (no filtering). Controlled entirely via config file, no database schema changes. --- temoa/_internal/table_writer.py | 81 +++++++++++++++++++++--- temoa/core/config.py | 8 +++ temoa/tutorial_assets/config_sample.toml | 7 ++ 3 files changed, 88 insertions(+), 8 deletions(-) diff --git a/temoa/_internal/table_writer.py b/temoa/_internal/table_writer.py index c671abcc1..105d00878 100644 --- a/temoa/_internal/table_writer.py +++ b/temoa/_internal/table_writer.py @@ -64,6 +64,13 @@ 'output_storage_level', ] +OUTPUT_THRESHOLD_DEFAULTS = { + 'capacity': 1e-3, + 'activity': 1e-3, + 'emission': 1e-3, + 'cost': 1e-2, +} + FLOW_SUMMARY_FILE_LOC = ( resources.files('temoa.extensions.modeling_to_generate_alternatives') / 'make_flow_summary_table.sql' @@ -92,6 +99,17 @@ def __init__(self, config: TemoaConfig, epsilon: float = 1e-5) -> None: logger.exception('Failed to connect to output database: %s', config.output_database) sys.exit(-1) + self.output_threshold_capacity = self._resolve_output_threshold('capacity') + self.output_threshold_activity = self._resolve_output_threshold('activity') + self.output_threshold_emission = self._resolve_output_threshold('emission') + self.output_threshold_cost = self._resolve_output_threshold('cost') + self.epsilon = min( + self.output_threshold_capacity, + self.output_threshold_activity, + self.output_threshold_emission, + self.output_threshold_cost, + ) + # Unit propagator for populating units in output tables (lazy init) self._unit_propagator: UnitPropagator | None = None @@ -228,6 +246,34 @@ def _bulk_insert(self, table_name: str, records: list[dict[str, Any]]) -> None: self.connection.executemany(query, rows_to_insert) + @staticmethod + def _validate_threshold( + threshold_name: str, + threshold_value: float | int | None, + ) -> float | None: + """Validate output threshold inputs and normalize to float.""" + if threshold_value is None: + return None + numeric_value = float(threshold_value) + if numeric_value < 0: + raise ValueError(f'Output threshold "{threshold_name}" must be non-negative') + return numeric_value + + def _resolve_output_threshold(self, threshold_type: str) -> float: + """Resolve threshold: TOML config if set, else hardcoded default.""" + if threshold_type not in OUTPUT_THRESHOLD_DEFAULTS: + raise ValueError(f'Unknown output threshold type: {threshold_type}') + + toml_key = f'output_threshold_{threshold_type}' + toml_value = self._validate_threshold( + toml_key, + getattr(self.config, toml_key, None), + ) + if toml_value is not None: + return toml_value + + return OUTPUT_THRESHOLD_DEFAULTS[threshold_type] + def write_results( self, model: TemoaModel, @@ -252,7 +298,11 @@ def write_results( else: p_0 = None - e_costs, e_flows = poll_emissions(model=model, p_0=value(p_0)) + e_costs, e_flows = poll_emissions( + model=model, + p_0=value(p_0), + epsilon=self.output_threshold_emission, + ) self.emission_register = e_flows self.write_emissions(iteration=iteration) @@ -278,7 +328,10 @@ def write_mm_results(self, model: TemoaModel, iteration: int) -> None: if not self.tech_sectors: self._set_tech_sectors() self.write_objective(model, iteration=iteration) - _e_costs, e_flows = poll_emissions(model=model) + _e_costs, e_flows = poll_emissions( + model=model, + epsilon=self.output_threshold_emission, + ) self.emission_register = e_flows self.write_emissions(iteration=iteration) finally: @@ -400,7 +453,7 @@ def write_emissions(self, iteration: int | None = None) -> None: records = [] for ei, val in self.emission_register.items(): - if abs(val) < self.epsilon: + if abs(val) < self.output_threshold_emission: continue row = { @@ -425,7 +478,7 @@ def write_emissions(self, iteration: int | None = None) -> None: self.connection.commit() def write_capacity_tables(self, model: TemoaModel, iteration: int | None = None) -> None: - cap_data = poll_capacity_results(model=model) + cap_data = poll_capacity_results(model=model, epsilon=self.output_threshold_capacity) self._insert_capacity_results(cap_data=cap_data, iteration=iteration) def _insert_capacity_results(self, cap_data: CapData, iteration: int | None) -> None: @@ -508,7 +561,7 @@ def write_flow_tables(self, iteration: int | None = None) -> None: sector = self.tech_sectors.get(fi.t) for flow_type, val in flows.items(): - if abs(val) < self.epsilon: + if abs(val) < self.output_threshold_activity: continue table_name = map_flow_to_table.get(flow_type) @@ -593,7 +646,7 @@ def _insert_summary_flow_results( records = [] for (r, p, i, t, v, o), val in output_flows.items(): - if abs(val) < self.epsilon: + if abs(val) < self.output_threshold_activity: continue records.append( { @@ -643,7 +696,7 @@ def check_flow_balance(self, model: TemoaModel) -> bool: return all_good def calculate_flows(self, model: TemoaModel) -> dict[FI, dict[FlowType, float]]: - return poll_flow_results(model, self.epsilon) + return poll_flow_results(model, self.output_threshold_activity) def write_costs( self, @@ -657,7 +710,7 @@ def write_costs( else: p_0 = min(model.time_optimize) - entries, exchange_entries = poll_cost_results(model, value(p_0), self.epsilon) + entries, exchange_entries = poll_cost_results(model, value(p_0), self.output_threshold_cost) self._insert_cost_results(entries, exchange_entries, emission_entries, iteration) def _insert_cost_results( @@ -697,6 +750,18 @@ def _write_cost_rows( for r, p, t, v in sorted_keys: costs = entries[(r, p, t, v)] + row_values = ( + costs.get(CostType.D_INVEST, 0), + costs.get(CostType.D_FIXED, 0), + costs.get(CostType.D_VARIABLE, 0), + costs.get(CostType.D_EMISS, 0), + costs.get(CostType.INVEST, 0), + costs.get(CostType.FIXED, 0), + costs.get(CostType.VARIABLE, 0), + costs.get(CostType.EMISS, 0), + ) + if all(abs(val) < self.output_threshold_cost for val in row_values): + continue records.append( { 'scenario': scenario, diff --git a/temoa/core/config.py b/temoa/core/config.py index d61ee04e4..962893f87 100644 --- a/temoa/core/config.py +++ b/temoa/core/config.py @@ -65,6 +65,10 @@ def __init__( graphviz_output: bool = False, cycle_count_limit: int = 100, cycle_length_limit: int = 1, + output_threshold_capacity: float | None = None, + output_threshold_activity: float | None = None, + output_threshold_emission: float | None = None, + output_threshold_cost: float | None = None, ): if '-' in scenario: raise ValueError( @@ -148,6 +152,10 @@ def __init__( self.plot_commodity_network = plot_commodity_network and self.source_trace self.graphviz_output = graphviz_output self.stochastic_config = stochastic_config + self.output_threshold_capacity = output_threshold_capacity + self.output_threshold_activity = output_threshold_activity + self.output_threshold_emission = output_threshold_emission + self.output_threshold_cost = output_threshold_cost # Cycle detection limits if not isinstance(cycle_count_limit, int) or cycle_count_limit < -1: diff --git a/temoa/tutorial_assets/config_sample.toml b/temoa/tutorial_assets/config_sample.toml index 4cf8d7675..131a87fb8 100644 --- a/temoa/tutorial_assets/config_sample.toml +++ b/temoa/tutorial_assets/config_sample.toml @@ -92,6 +92,13 @@ save_lp_file = false # graphviz dot file and svg for network visualization (requires graphviz to be installed separately) graphviz_output = false +# Optional output filtering thresholds (set to 0 to disable per category) +# Precedence is: TOML value > metadata_real in output db > internal defaults. +output_threshold_capacity = 0.001 +output_threshold_activity = 0.001 +output_threshold_emission = 0.001 +output_threshold_cost = 0.01 + # ------------------------------------ # MODEL PARAMETERS # these are specific to each model From 3e2b3cd0d47cf3fa15285beca45b2459bfe8b440 Mon Sep 17 00:00:00 2001 From: SutubraResearch Date: Thu, 12 Mar 2026 14:22:43 -0300 Subject: [PATCH 445/587] Read myopic capacity threshold from config --- temoa/extensions/myopic/myopic_sequencer.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index f4c5d943c..12c952476 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -64,7 +64,15 @@ class MyopicSequencer: ] def __init__(self, config: TemoaConfig | None): - self.capacity_epsilon = 1e-5 + # Minimum capacity (MW) to carry forward between myopic periods. + # mip-dev uses 10 MW. Configurable via [myopic] capacity_threshold in TOML. + default_cap_threshold = 10 + if config and config.myopic_inputs: + self.capacity_epsilon = config.myopic_inputs.get( + 'capacity_threshold', default_cap_threshold + ) + else: + self.capacity_epsilon = default_cap_threshold self.debugging = False self.optimization_periods: list[int] | None = None self.instance_queue: deque[MyopicIndex] = deque() # a LIFO queue From 7a7787762afd9bae49029eed1acf0682a4166069 Mon Sep 17 00:00:00 2001 From: SutubraResearch Date: Tue, 17 Mar 2026 11:58:45 -0300 Subject: [PATCH 446/587] Fix incorrect precedence comment in config sample --- temoa/tutorial_assets/config_sample.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temoa/tutorial_assets/config_sample.toml b/temoa/tutorial_assets/config_sample.toml index 131a87fb8..e2c5573b7 100644 --- a/temoa/tutorial_assets/config_sample.toml +++ b/temoa/tutorial_assets/config_sample.toml @@ -93,7 +93,7 @@ save_lp_file = false graphviz_output = false # Optional output filtering thresholds (set to 0 to disable per category) -# Precedence is: TOML value > metadata_real in output db > internal defaults. +# Precedence is: TOML value > internal defaults. output_threshold_capacity = 0.001 output_threshold_activity = 0.001 output_threshold_emission = 0.001 From fdc8ab0ded2fd325a3a647b1eed3173d66323ede Mon Sep 17 00:00:00 2001 From: SutubraResearch Date: Wed, 18 Mar 2026 13:54:18 -0300 Subject: [PATCH 447/587] Clean up output thresholds and wire myopic capacity filter --- temoa/_internal/table_writer.py | 6 ++++-- temoa/extensions/myopic/myopic_sequencer.py | 16 ++++++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/temoa/_internal/table_writer.py b/temoa/_internal/table_writer.py index 105d00878..ca59ec994 100644 --- a/temoa/_internal/table_writer.py +++ b/temoa/_internal/table_writer.py @@ -4,6 +4,7 @@ from __future__ import annotations +import math import sqlite3 import sys from collections import defaultdict @@ -81,9 +82,8 @@ class TableWriter: con: sqlite3.Connection | None - def __init__(self, config: TemoaConfig, epsilon: float = 1e-5) -> None: + def __init__(self, config: TemoaConfig) -> None: self.config = config - self.epsilon = epsilon self.tech_sectors: dict[str, str] | None = None self.flow_register: dict[FI, dict[FlowType, float]] = {} self.emission_register: dict[EI, float] | None = None @@ -255,6 +255,8 @@ def _validate_threshold( if threshold_value is None: return None numeric_value = float(threshold_value) + if not math.isfinite(numeric_value): + raise ValueError(f'Output threshold "{threshold_name}" must be finite') if numeric_value < 0: raise ValueError(f'Output threshold "{threshold_name}" must be non-negative') return numeric_value diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index 12c952476..4637824a0 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -65,8 +65,8 @@ class MyopicSequencer: def __init__(self, config: TemoaConfig | None): # Minimum capacity (MW) to carry forward between myopic periods. - # mip-dev uses 10 MW. Configurable via [myopic] capacity_threshold in TOML. - default_cap_threshold = 10 + # Configurable via [myopic] capacity_threshold in TOML. + default_cap_threshold = 1e-3 if config and config.myopic_inputs: self.capacity_epsilon = config.myopic_inputs.get( 'capacity_threshold', default_cap_threshold @@ -395,7 +395,7 @@ def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: i 'DELETE FROM myopic_efficiency ' 'WHERE (SELECT region, tech, vintage) ' ' NOT IN (SELECT region, tech, vintage FROM output_net_capacity ' - ' WHERE period = ? AND scenario = ?) ' + ' WHERE period = ? AND scenario = ? AND ABS(capacity) >= ?) ' 'AND tech not in (SELECT tech FROM main.technology where unlim_cap > 0)' ) @@ -404,16 +404,20 @@ def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: i 'SELECT * FROM myopic_efficiency ' 'WHERE (SELECT region, tech, vintage) ' ' NOT IN (SELECT region, tech, vintage FROM output_net_capacity ' - ' WHERE period = ? AND scenario = ?) ' + ' WHERE period = ? AND scenario = ? AND ABS(capacity) >= ?) ' 'AND tech not in (SELECT tech FROM Technology where unlim_cap > 0)' ) print('\n\n **** Removing these unused region-tech-vintage combos ****') removals = self.cursor.execute( - debug_query, (last_interval_end, self.config.scenario) + debug_query, + (last_interval_end, self.config.scenario, self.capacity_epsilon), ).fetchall() for i, removal in enumerate(removals): print(f'{i}. Removing: {removal}') - self.cursor.execute(delete_qry, (last_interval_end, self.config.scenario)) + self.cursor.execute( + delete_qry, + (last_interval_end, self.config.scenario, self.capacity_epsilon), + ) self.output_con.commit() # 2. Add the new stuff now visible From 133bfbef562479d0f87d969d84d5256258500eb9 Mon Sep 17 00:00:00 2001 From: SutubraResearch Date: Thu, 19 Feb 2026 11:51:59 -0400 Subject: [PATCH 448/587] Match solver tolerances to standard defaults Relax barrier convergence tolerance from 1e-5 to 1e-3 and feasibility tolerance from 1e-6 to 1e-4 for both Gurobi and CPLEX. These values align with mip-dev defaults and are standard for large-scale energy system models where tighter tolerances cause unnecessary barrier iterations without meaningful solution improvement. --- temoa/_internal/run_actions.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/temoa/_internal/run_actions.py b/temoa/_internal/run_actions.py index 0fece7419..d45043476 100644 --- a/temoa/_internal/run_actions.py +++ b/temoa/_internal/run_actions.py @@ -206,19 +206,19 @@ def solve_instance( pass elif solver_name == 'cplex': - # Note: these parameter values are taken to be the same as those in PyPSA + # Note: these parameter values match mip-dev / PyPSA # (see: https://pypsa-eur.readthedocs.io/en/latest/configuration.html) optimizer.options['lpmethod'] = 4 # barrier optimizer.options['solutiontype'] = 2 # non basic solution, ie no crossover - optimizer.options['barrier convergetol'] = 1.0e-5 - optimizer.options['feasopt tolerance'] = 1.0e-6 + optimizer.options['barrier convergetol'] = 1.0e-3 + optimizer.options['feasopt tolerance'] = 1.0e-4 elif solver_name == 'gurobi': - # Note: these parameter values are taken to be the same as those in PyPSA (see: https://pypsa-eur.readthedocs.io/en/latest/configuration.html) + # Note: these parameter values match mip-dev / PyPSA (see: https://pypsa-eur.readthedocs.io/en/latest/configuration.html) optimizer.options['Method'] = 2 # barrier optimizer.options['Crossover'] = 0 # non basic solution, ie no crossover - optimizer.options['BarConvTol'] = 1.0e-5 - optimizer.options['FeasibilityTol'] = 1.0e-6 + optimizer.options['BarConvTol'] = 1.0e-3 + optimizer.options['FeasibilityTol'] = 1.0e-4 # optimizer.options["BarOrder"] = 0 # if solve times seem unusually long, try 0 or 1 elif solver_name == 'appsi_highs': From 7f7c1d05efb8107b8070976d611919b146c58b32 Mon Sep 17 00:00:00 2001 From: SutubraResearch Date: Wed, 11 Mar 2026 14:29:56 -0300 Subject: [PATCH 449/587] Set Gurobi BarOrder to automatic ordering Change BarOrder from 0 (AMD) to -1 (automatic) for barrier solves. Automatic ordering selects the best fill-reducing strategy per problem structure, yielding 2-4x speedup on national-scale energy system models (268s vs 1029s on a 26-region test case). AMD ordering is suboptimal for the sparse constraint structure typical of Temoa models. --- temoa/_internal/run_actions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temoa/_internal/run_actions.py b/temoa/_internal/run_actions.py index d45043476..9cd82447e 100644 --- a/temoa/_internal/run_actions.py +++ b/temoa/_internal/run_actions.py @@ -219,7 +219,7 @@ def solve_instance( optimizer.options['Crossover'] = 0 # non basic solution, ie no crossover optimizer.options['BarConvTol'] = 1.0e-3 optimizer.options['FeasibilityTol'] = 1.0e-4 - # optimizer.options["BarOrder"] = 0 # if solve times seem unusually long, try 0 or 1 + optimizer.options['BarOrder'] = -1 # auto ordering; 2-4x faster than AMD on large models elif solver_name == 'appsi_highs': pass From b7cdcbd67adcc20b4beb1466c885851240007a2c Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Mar 2026 17:46:25 -0400 Subject: [PATCH 450/587] Filter construction input and embodied emissions for myopic --- temoa/data_io/component_manifest.py | 2 ++ temoa/data_io/hybrid_loader.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/temoa/data_io/component_manifest.py b/temoa/data_io/component_manifest.py index bb6625545..79d88d051 100644 --- a/temoa/data_io/component_manifest.py +++ b/temoa/data_io/component_manifest.py @@ -556,6 +556,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: columns=['region', 'emis_comm', 'tech', 'vintage', 'value'], validator_name='viable_rtv', validation_map=(0, 2, 3), + custom_loader_name='_load_emission_embodied', is_period_filtered=False, is_table_required=False, ), @@ -574,6 +575,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: columns=['region', 'input_comm', 'tech', 'vintage', 'value'], validator_name='viable_rtv', validation_map=(0, 2, 3), + custom_loader_name='_load_construction_input', is_period_filtered=False, is_table_required=False, ), diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index de0c6c733..dac18b3d8 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -673,6 +673,34 @@ def _load_loan_rate( data_to_load = [row for row in filtered_data if not mi or row[2] >= mi.base_year] # type: ignore[operator] self._load_component_data(data, model.loan_rate, data_to_load) + def _load_construction_input( + self, + data: dict[str, object], + raw_data: Sequence[tuple[object, ...]], + filtered_data: Sequence[tuple[object, ...]], + ) -> None: + """Handles myopic period filtering for construction_input.""" + model = TemoaModel() + base_year = self.myopic_index.base_year if self.myopic_index else None + data_to_load = [ + row for row in filtered_data if base_year is None or cast('int', row[3]) >= base_year + ] + self._load_component_data(data, model.construction_input, data_to_load) + + def _load_emission_embodied( + self, + data: dict[str, object], + raw_data: Sequence[tuple[object, ...]], + filtered_data: Sequence[tuple[object, ...]], + ) -> None: + """Handles myopic period filtering for emission_embodied.""" + model = TemoaModel() + base_year = self.myopic_index.base_year if self.myopic_index else None + data_to_load = [ + row for row in filtered_data if base_year is None or cast('int', row[3]) >= base_year + ] + self._load_component_data(data, model.emission_embodied, data_to_load) + # --- Singleton and Configuration-based Components --- def _load_days_per_period( self, From 41e2e4078a1e760080b98dcc18681fb1c3b7d9f1 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Mar 2026 18:09:39 -0400 Subject: [PATCH 451/587] Filter end of life output data separately --- temoa/model_checking/network_model_data.py | 149 ++++++++++++--------- 1 file changed, 83 insertions(+), 66 deletions(-) diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index d2d11bea8..4722f7e28 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -66,7 +66,7 @@ class BasicData(TypedDict): class LookupData(TypedDict): """Defines the shape of the data returned by _fetch_lookup_data.""" - eol: defaultdict[tuple[Region, Technology, Vintage], list[Commodity]] + eol: defaultdict[tuple[Region, Technology, Vintage, int], list[Commodity]] construction: list[tuple[Region, Commodity, Technology, Vintage]] linked: set[tuple[Region, Technology, Commodity, Technology]] neg_cost_techs: set[Technology] @@ -286,13 +286,28 @@ def _fetch_all_tech_definitions( def _fetch_lookup_data(cur: sqlite3.Cursor) -> LookupData: """Fetches data from all optional tables to avoid N+1 queries.""" - lookups = LookupData(eol=defaultdict(list), construction=[], linked=set(), neg_cost_techs=set()) + lookups = LookupData( + eol=defaultdict(list), + construction=[], + linked=set(), + neg_cost_techs=set(), + ) try: - for r, tech, v, oc in cur.execute( - 'SELECT region, tech, vintage, output_comm FROM end_of_life_output' + query = """ + SELECT + eol.region, eol.tech, eol.vintage, eol.output_comm, + COALESCE(lp.lifetime, lt.lifetime, ?) AS lifetime + FROM end_of_life_output AS eol + LEFT JOIN main.lifetime_process AS lp ON eol.tech = lp.tech + AND eol.vintage = lp.vintage + AND eol.region = lp.region + LEFT JOIN main.lifetime_tech AS lt ON eol.tech = lt.tech AND eol.region = lt.region + """ + for r, tech, v, oc, life in cur.execute( + query, (TemoaModel.default_lifetime_tech,) ).fetchall(): - lookups['eol'][(r, tech, v)].append(oc) + lookups['eol'][(r, tech, v, life)].append(oc) except sqlite3.OperationalError: logger.warning('Table end_of_life_output not found, skipping.') @@ -356,79 +371,81 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - sector = None for p in periods: - if not (v <= p < v + lifetime): - continue - - living_techs.add(tech) - if '-' in r and r.count('-') == 1: # Inter-regional transfer - r1, r2 = (cast('Region', reg) for reg in r.split('-', 1)) - source_comm, dest_comm = ( - cast('Commodity', f'{ic} ({r1})'), - cast('Commodity', f'{oc} ({r2})'), - ) - res.available_techs[r2, p].add( - EdgeTuple( - region=r2, - input_comm=source_comm, - tech=tech, - vintage=v, - output_comm=oc, - lifetime=lifetime, - sector=sector, + if v <= p < v + lifetime: + living_techs.add(tech) + if '-' in r and r.count('-') == 1: # Inter-regional transfer + r1, r2 = (cast('Region', reg) for reg in r.split('-', 1)) + source_comm, dest_comm = ( + cast('Commodity', f'{ic} ({r1})'), + cast('Commodity', f'{oc} ({r2})'), ) - ) - res.available_techs[r1, p].add( - EdgeTuple( - region=r1, - input_comm=ic, - tech=tech, - vintage=v, - output_comm=dest_comm, - lifetime=lifetime, - sector=sector, + res.available_techs[r2, p].add( + EdgeTuple( + region=r2, + input_comm=source_comm, + tech=tech, + vintage=v, + output_comm=oc, + lifetime=lifetime, + sector=sector, + ) + ) + res.available_techs[r1, p].add( + EdgeTuple( + region=r1, + input_comm=ic, + tech=tech, + vintage=v, + output_comm=dest_comm, + lifetime=lifetime, + sector=sector, + ) ) - ) - res.available_techs[r, p].add( - EdgeTuple( - region=r, - input_comm=ic, - tech=tech, - vintage=v, - output_comm=oc, - lifetime=lifetime, - sector=sector, + res.available_techs[r, p].add( + EdgeTuple( + region=r, + input_comm=ic, + tech=tech, + vintage=v, + output_comm=oc, + lifetime=lifetime, + sector=sector, + ) ) - ) - res.source_commodities[r2, p].add(source_comm) - res.demand_commodities[r1, p].add(dest_comm) - res.physical_commodities.update([source_comm, dest_comm]) - res.exchange_commodities.update([source_comm, dest_comm]) - else: # Standard technology - res.available_techs[r, p].add( - EdgeTuple( - region=r, - input_comm=ic, - tech=tech, - vintage=v, - output_comm=oc, - lifetime=lifetime, - sector=sector, + res.source_commodities[r2, p].add(source_comm) + res.demand_commodities[r1, p].add(dest_comm) + res.physical_commodities.update([source_comm, dest_comm]) + res.exchange_commodities.update([source_comm, dest_comm]) + else: # Standard technology + res.available_techs[r, p].add( + EdgeTuple( + region=r, + input_comm=ic, + tech=tech, + vintage=v, + output_comm=oc, + lifetime=lifetime, + sector=sector, + ) ) - ) - if ic in basic_data['source_commodities_all']: - res.source_commodities[r, p].add(ic) - if oc in basic_data['waste_commodities_all']: - res.waste_commodities[r, p].add(oc) + if ic in basic_data['source_commodities_all']: + res.source_commodities[r, p].add(ic) + if oc in basic_data['waste_commodities_all']: + res.waste_commodities[r, p].add(oc) + for r, tech, v, lifetime in lookup_data['eol']: + for p in periods: is_natural_eol = p <= v + lifetime < p + basic_data['period_length'][p] is_retireable = ( tech in basic_data['tech_retire'] and v < p <= v + lifetime - basic_data['period_length'][p] ) - has_survival = (r, tech, v) in basic_data['tech_survival_curve'] + has_survival = (r, tech, v) in basic_data[ + 'tech_survival_curve' + ] and v <= p <= v + lifetime if is_natural_eol or is_retireable or has_survival: - for eol_oc in lookup_data['eol'].get((r, tech, v), []): + for eol_oc in lookup_data['eol'][(r, tech, v, lifetime)]: res.available_techs[r, p].add( EdgeTuple( region=r, From 24900747b66c656d635659e2358c950b66add10b Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Mar 2026 18:11:47 -0400 Subject: [PATCH 452/587] Check for unlimited capacity for material flows --- temoa/model_checking/network_model_data.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index 4722f7e28..7dce6b014 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -53,6 +53,7 @@ class LinkedTechTuple(NamedTuple): class BasicData(TypedDict): """Defines the shape of the data returned by _fetch_basic_data.""" + tech_uncap: set[Technology] tech_retire: set[Technology] tech_survival_curve: set[tuple[Region, Technology, Vintage]] periods: list[Period] @@ -194,6 +195,9 @@ def _build_from_model( def _fetch_basic_data(cur: sqlite3.Cursor) -> BasicData: """Fetches simple, required tables and parameters from the DB.""" + tech_uncap = { + t[0] for t in cur.execute('SELECT tech FROM technology WHERE unlim_cap==1').fetchall() + } tech_retire = { t[0] for t in cur.execute('SELECT tech FROM technology WHERE retire==1').fetchall() } @@ -225,6 +229,7 @@ def _fetch_basic_data(cur: sqlite3.Cursor) -> BasicData: demand_commodities[r, p].add(d) return BasicData( + tech_uncap=tech_uncap, tech_retire=tech_retire, tech_survival_curve=tech_survival_curve, periods=periods, @@ -434,6 +439,9 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - res.waste_commodities[r, p].add(oc) for r, tech, v, lifetime in lookup_data['eol']: + if tech in basic_data['tech_uncap']: + # No capacity to retire + continue for p in periods: is_natural_eol = p <= v + lifetime < p + basic_data['period_length'][p] is_retireable = ( @@ -464,6 +472,9 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - # --- 3. Process Construction --- for r, ic, tech, v in lookup_data['construction']: + if tech in basic_data['tech_uncap']: + # No capacity to construct + continue construction_lifetime = basic_data['period_length'].get( cast('Period', v), cast('Period', 1) ) From 0566c26969b1746135a1a34ab193301a0ce6f7e9 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Mar 2026 18:13:13 -0400 Subject: [PATCH 453/587] Make periods an ordered list as intended and filter construction input by this list --- temoa/model_checking/network_model_data.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index 7dce6b014..ee29f145e 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -205,7 +205,9 @@ def _fetch_basic_data(cur: sqlite3.Cursor) -> BasicData: cur.execute('SELECT DISTINCT region, tech, vintage FROM lifetime_survival_curve').fetchall() ) - periods_full = sorted(p[0] for p in cur.execute('SELECT period FROM time_period').fetchall()) + periods_full = sorted( + p[0] for p in cur.execute('SELECT period FROM time_period WHERE flag = "f"').fetchall() + ) periods = periods_full[:-1] period_length = { periods_full[i]: periods_full[i + 1] - periods_full[i] for i in range(len(periods_full) - 1) @@ -358,11 +360,11 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - res.physical_commodities = basic_data['physical_commodities'] res.demand_commodities = basic_data['demand_commodities'] - periods: list[Period] | set[Period] = basic_data['periods'] + periods: list[Period] = basic_data['periods'] if myopic_index: - periods = { + periods = [ p for p in periods if myopic_index.base_year <= p <= myopic_index.last_demand_year - } + ] living_techs: set[Technology] = set() @@ -475,6 +477,8 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - if tech in basic_data['tech_uncap']: # No capacity to construct continue + if cast('Period', v) not in periods: + continue construction_lifetime = basic_data['period_length'].get( cast('Period', v), cast('Period', 1) ) From c0c6632a6a74e1393bf2acefa4bb46ddfa6e3751 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Mar 2026 18:18:10 -0400 Subject: [PATCH 454/587] Check that the end of life output process is valid --- temoa/model_checking/network_model_data.py | 23 +++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index ee29f145e..43eefcdae 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -68,6 +68,7 @@ class LookupData(TypedDict): """Defines the shape of the data returned by _fetch_lookup_data.""" eol: defaultdict[tuple[Region, Technology, Vintage, int], list[Commodity]] + exs_cap: defaultdict[tuple[Region, Technology, Vintage], float] construction: list[tuple[Region, Commodity, Technology, Vintage]] linked: set[tuple[Region, Technology, Commodity, Technology]] neg_cost_techs: set[Technology] @@ -296,6 +297,7 @@ def _fetch_lookup_data(cur: sqlite3.Cursor) -> LookupData: lookups = LookupData( eol=defaultdict(list), construction=[], + exs_cap=defaultdict(float), linked=set(), neg_cost_techs=set(), ) @@ -325,6 +327,14 @@ def _fetch_lookup_data(cur: sqlite3.Cursor) -> LookupData: except sqlite3.OperationalError: logger.warning('Table construction_input not found, skipping.') + try: + for r, tech, v, capacity in cur.execute( + 'SELECT region, tech, vintage, capacity FROM existing_capacity' + ).fetchall(): + lookups['exs_cap'][(r, tech, v)] = capacity + except sqlite3.OperationalError: + logger.warning('Table existing_capacity not found, skipping.') + try: lookups['linked'] = set( cur.execute( @@ -367,6 +377,7 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - ] living_techs: set[Technology] = set() + living_rtv: set[tuple[Region, Technology, Vintage]] = set() # --- 2. Process technologies --- for tech_data in raw_techs: @@ -380,6 +391,7 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - for p in periods: if v <= p < v + lifetime: living_techs.add(tech) + living_rtv.add((r, tech, v)) if '-' in r and r.count('-') == 1: # Inter-regional transfer r1, r2 = (cast('Region', reg) for reg in r.split('-', 1)) source_comm, dest_comm = ( @@ -445,6 +457,16 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - # No capacity to retire continue for p in periods: + # retires bang on start of horizon or survives into planning periods + is_p0_eol = ( + (p == periods[0]) + and (v + lifetime == p) + and lookup_data['exs_cap'].get((r, tech, v), 0) > 0 + ) + is_living = (r, tech, v) in living_rtv + if not (is_p0_eol or is_living): + continue + is_natural_eol = p <= v + lifetime < p + basic_data['period_length'][p] is_retireable = ( tech in basic_data['tech_retire'] @@ -497,7 +519,6 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - ) res.demand_commodities[r, cast('Period', v)].add(cast('Commodity', tech)) res.capacity_commodities.add(cast('Commodity', tech)) - living_techs.add(tech) # --- 4. Process Linked Techs and Other Metadata --- res.available_linked_techs = { From 3af512098c4b2c41230418ce69d66a47e83036a5 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Mar 2026 18:20:05 -0400 Subject: [PATCH 455/587] Make input/output of material flows that technology and add rtv_eol validation filter --- temoa/data_io/component_manifest.py | 2 +- temoa/data_io/hybrid_loader.py | 1 + temoa/model_checking/commodity_network_manager.py | 8 ++++++++ temoa/model_checking/network_model_data.py | 4 ++-- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/temoa/data_io/component_manifest.py b/temoa/data_io/component_manifest.py index 79d88d051..37efe764c 100644 --- a/temoa/data_io/component_manifest.py +++ b/temoa/data_io/component_manifest.py @@ -583,7 +583,7 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: component=model.end_of_life_output, table='end_of_life_output', columns=['region', 'tech', 'vintage', 'output_comm', 'value'], - validator_name='viable_rtv', + validator_name='viable_rtv_eol', validation_map=(0, 1, 2), is_period_filtered=False, is_table_required=False, diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index dac18b3d8..f2979c64c 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -463,6 +463,7 @@ def _build_efficiency_dataset( self.viable_rt = filts['rt'] self.viable_rpit = filts['rpit'] self.viable_rpto = filts['rpto'] + self.viable_rtv_eol = filts['rtv_eol'] self.viable_techs = filts['t'] self.viable_input_comms = filts['ic'] self.viable_output_comms = filts['oc'] diff --git a/temoa/model_checking/commodity_network_manager.py b/temoa/model_checking/commodity_network_manager.py index 7762f5608..b6130fcae 100644 --- a/temoa/model_checking/commodity_network_manager.py +++ b/temoa/model_checking/commodity_network_manager.py @@ -126,6 +126,9 @@ def build_filters(self) -> dict[str, ViableSet]: valid_elements['rpto'].add( (edge_tuple.region, p, edge_tuple.tech, edge_tuple.output_comm) ) + valid_elements['rtv_eol'].add( + (edge_tuple.region, edge_tuple.input_comm, edge_tuple.vintage) + ) valid_elements['t'].add(edge_tuple.tech) valid_elements['v'].add(edge_tuple.vintage) valid_elements['ic'].add(edge_tuple.input_comm) @@ -157,6 +160,11 @@ def build_filters(self) -> dict[str, ViableSet]: exception_loc=0, exception_vals=ViableSet.REGION_REGEXES, ), + 'rtv_eol': ViableSet( + elements=valid_elements['rtv_eol'], + exception_loc=0, + exception_vals=ViableSet.REGION_REGEXES, + ), 't': ViableSet(elements=valid_elements['t']), 'v': ViableSet(elements=valid_elements['v']), 'ic': ViableSet(elements=valid_elements['ic']), diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index 43eefcdae..02140261b 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -482,7 +482,7 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - EdgeTuple( region=r, input_comm=cast('Commodity', tech), - tech=cast('Technology', 'end_of_life'), + tech=tech, vintage=v, output_comm=eol_oc, lifetime=lifetime, @@ -508,7 +508,7 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - EdgeTuple( region=r, input_comm=ic, - tech=cast('Technology', 'construction'), + tech=tech, vintage=v, output_comm=cast( 'Commodity', tech From 9a9aa5b15a35fac2108be138947b4559662594ee Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Mar 2026 18:21:41 -0400 Subject: [PATCH 456/587] Also silently validate emission end of life existing capacities retiring exactly on p0 --- .../commodity_network_manager.py | 7 +++++ temoa/model_checking/network_model_data.py | 27 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/temoa/model_checking/commodity_network_manager.py b/temoa/model_checking/commodity_network_manager.py index b6130fcae..19b5d8398 100644 --- a/temoa/model_checking/commodity_network_manager.py +++ b/temoa/model_checking/commodity_network_manager.py @@ -134,6 +134,13 @@ def build_filters(self) -> dict[str, ViableSet]: valid_elements['ic'].add(edge_tuple.input_comm) valid_elements['oc'].add(edge_tuple.output_comm) + # Good processes that we dont want in the network diagram + for r, _p, t, v in self.orig_data.silent_rptv: + valid_elements['rtv'].add((r, t, v)) + valid_elements['rt'].add((r, t)) + valid_elements['t'].add(t) + valid_elements['v'].add(v) + return { 'ritvo': ViableSet( elements=valid_elements['ritvo'], diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index 02140261b..22e815efc 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -68,6 +68,7 @@ class LookupData(TypedDict): """Defines the shape of the data returned by _fetch_lookup_data.""" eol: defaultdict[tuple[Region, Technology, Vintage, int], list[Commodity]] + eeol: set[tuple[Region, Technology, Vintage, int]] exs_cap: defaultdict[tuple[Region, Technology, Vintage], float] construction: list[tuple[Region, Commodity, Technology, Vintage]] linked: set[tuple[Region, Technology, Commodity, Technology]] @@ -101,6 +102,7 @@ class NetworkModelData: tech_data: defaultdict[Technology, dict[str, TechAttributeValue]] = field( default_factory=lambda: defaultdict(dict) ) + silent_rptv: set[tuple[Region, Period, Technology, Vintage]] = field(default_factory=set) def __post_init__(self) -> None: """Validate data consistency after initialization.""" @@ -296,6 +298,7 @@ def _fetch_lookup_data(cur: sqlite3.Cursor) -> LookupData: """Fetches data from all optional tables to avoid N+1 queries.""" lookups = LookupData( eol=defaultdict(list), + eeol=set(), construction=[], exs_cap=defaultdict(float), linked=set(), @@ -320,6 +323,22 @@ def _fetch_lookup_data(cur: sqlite3.Cursor) -> LookupData: except sqlite3.OperationalError: logger.warning('Table end_of_life_output not found, skipping.') + try: + query = """ + SELECT + eeol.region, eeol.tech, eeol.vintage, + COALESCE(lp.lifetime, lt.lifetime, ?) AS lifetime + FROM emission_end_of_life AS eeol + LEFT JOIN main.lifetime_process AS lp ON eeol.tech = lp.tech + AND eeol.vintage = lp.vintage + AND eeol.region = lp.region + LEFT JOIN main.lifetime_tech AS lt ON eeol.tech = lt.tech AND eeol.region = lt.region + """ + for r, tech, v, life in cur.execute(query, (TemoaModel.default_lifetime_tech,)).fetchall(): + lookups['eeol'].add((r, tech, v, life)) + except sqlite3.OperationalError: + logger.warning('Table emission_end_of_life not found, skipping.') + try: lookups['construction'] = cur.execute( 'SELECT region, input_comm, tech, vintage FROM construction_input' @@ -494,6 +513,14 @@ def _build_from_db(con: DbConnection, myopic_index: MyopicIndex | None = None) - if eol_oc in basic_data['waste_commodities_all']: res.waste_commodities[r, p].add(eol_oc) + for r, tech, v, lifetime in lookup_data['eeol']: + if tech in basic_data['tech_uncap']: + # No capacity to retire + continue + # retires bang on start of horizon or survives into planning periods + if v + lifetime == periods[0] and lookup_data['exs_cap'].get((r, tech, v), 0) > 0: + res.silent_rptv.add((r, periods[0], tech, v)) + # --- 3. Process Construction --- for r, ic, tech, v in lookup_data['construction']: if tech in basic_data['tech_uncap']: From 1ba769ea5bf3b893e7b99e4fed38f595d2b06543 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Mar 2026 18:23:59 -0400 Subject: [PATCH 457/587] On the output side make in and out commodities for material flows null to avoid foreign key issues --- temoa/_internal/table_data_puller.py | 8 ++++---- temoa/_internal/table_writer.py | 17 ++++++++++------- temoa/types/model_types.py | 4 ++-- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/temoa/_internal/table_data_puller.py b/temoa/_internal/table_data_puller.py index afa06f9e1..26fd631ca 100644 --- a/temoa/_internal/table_data_puller.py +++ b/temoa/_internal/table_data_puller.py @@ -36,12 +36,12 @@ def _marks(num: int) -> str: return marks -def ritvo(fi: FI) -> tuple[Region, Commodity, Technology, Vintage, Commodity]: +def ritvo(fi: FI) -> tuple[Region, Commodity | None, Technology, Vintage, Commodity | None]: """convert FI to ritvo index""" return fi.r, fi.i, fi.t, fi.v, fi.o -def rpetv(fi: FI, e: Commodity) -> tuple[Region, Period, Commodity, Technology, Vintage]: +def rpetv(fi: FI, e: Commodity) -> tuple[Region, Period, Commodity | None, Technology, Vintage]: """convert FI and emission to rpetv index""" return fi.r, fi.p, e, fi.t, fi.v @@ -190,7 +190,7 @@ def poll_flow_results(model: TemoaModel, epsilon: float = 1e-5) -> dict[FI, dict ) for s in model.time_season[v]: for d in model.time_of_day: - fi = FI(r, v, s, d, i, t, v, cast('Commodity', 'construction_input')) + fi = FI(r, v, s, d, i, t, v, cast('Commodity', None)) flow = annual * value(model.segment_fraction[v, s, d]) if abs(flow) < epsilon: continue @@ -206,7 +206,7 @@ def poll_flow_results(model: TemoaModel, epsilon: float = 1e-5) -> dict[FI, dict ) for s in model.time_season[p]: for d in model.time_of_day: - fi = FI(r, p, s, d, cast('Commodity', 'end_of_life_output'), t, v, o) + fi = FI(r, p, s, d, cast('Commodity', None), t, v, o) flow = annual * value(model.segment_fraction[p, s, d]) if abs(flow) < epsilon: continue diff --git a/temoa/_internal/table_writer.py b/temoa/_internal/table_writer.py index ca59ec994..221c23e8f 100644 --- a/temoa/_internal/table_writer.py +++ b/temoa/_internal/table_writer.py @@ -597,7 +597,9 @@ def write_flow_tables(self, iteration: int | None = None) -> None: self.connection.commit() - def _get_flow_units(self, flow_type: FlowType, input_comm: str, output_comm: str) -> str | None: + def _get_flow_units( + self, flow_type: FlowType, input_comm: str | None, output_comm: str | None + ) -> str | None: """ Get units for flow based on flow type. @@ -616,11 +618,12 @@ def _get_flow_units(self, flow_type: FlowType, input_comm: str, output_comm: str if not unit_prop: return None - if flow_type == FlowType.IN: + if flow_type == FlowType.IN and input_comm is not None: return unit_prop.get_flow_in_units(input_comm) - else: + elif output_comm is not None: # OUT, CURTAIL, FLEX all use output commodity units return unit_prop.get_flow_out_units(output_comm) + return None def write_summary_flow(self, model: TemoaModel, iteration: int | None = None) -> None: flow_data = self.calculate_flows(model=model) @@ -636,9 +639,9 @@ def _insert_summary_flow_results( self.flow_register = flow_data # Aggregate flows (sum across seasons/time of day) - output_flows: defaultdict[tuple[str, Period, str, Technology, Vintage, str], float] = ( - defaultdict(float) - ) + output_flows: defaultdict[ + tuple[str, Period, str | None, Technology, Vintage, str | None], float + ] = defaultdict(float) for fi, flows in self.flow_register.items(): val = flows.get(FlowType.OUT) @@ -676,7 +679,7 @@ def check_flow_balance(self, model: TemoaModel) -> bool: for fi, flow_vals in flows.items(): if fi.t in model.tech_storage: continue - if fi.i == 'end_of_life_output' or fi.o == 'construction_input': + if fi.i is None or fi.o is None: continue fin = flow_vals.get(FlowType.IN, 0) diff --git a/temoa/types/model_types.py b/temoa/types/model_types.py index d168123cb..108a70f62 100644 --- a/temoa/types/model_types.py +++ b/temoa/types/model_types.py @@ -246,10 +246,10 @@ class FI(NamedTuple): p: Period s: Season d: TimeOfDay - i: Commodity + i: Commodity | None t: Technology v: Vintage - o: Commodity + o: Commodity | None class SLI(NamedTuple): From 2be286d60328d134aa9c603120d288fe0e3fa24c Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Mar 2026 18:24:26 -0400 Subject: [PATCH 458/587] Change loader filtering to info in myopic mode to avoid incessant warnings --- temoa/data_io/hybrid_loader.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index f2979c64c..39cec6fdf 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -251,11 +251,11 @@ def create_data_dict(self, myopic_index: MyopicIndex | None = None) -> dict[str, if len(filtered_data) < len(raw_data): ignored_count = len(raw_data) - len(filtered_data) - logger.warning( - '%d values for %s failed to validate and were ignored.', - ignored_count, - item.component.name, - ) + msg = '%d values for %s failed to validate and were ignored.' + if myopic_index: + logger.info(msg, ignored_count, item.component.name) + else: + logger.warning(msg, ignored_count, item.component.name) self._load_component_data(data, item.component, filtered_data) # --------------------------------------------------------------------- From 9ad590d95ebfb6cb9a150f612a707a6487a88e9b Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Mar 2026 18:32:43 -0400 Subject: [PATCH 459/587] Update used techs checks --- temoa/components/capacity.py | 7 +++++++ temoa/components/technology.py | 7 +++++-- temoa/core/model.py | 6 +++--- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/temoa/components/capacity.py b/temoa/components/capacity.py index 790bd4adf..d372d383d 100644 --- a/temoa/components/capacity.py +++ b/temoa/components/capacity.py @@ -621,12 +621,19 @@ def create_capacity_and_retirement_sets(model: TemoaModel) -> None: # Link construction materials to technologies for r, i, t, v in model.construction_input.sparse_iterkeys(): model.capacity_consumption_techs.setdefault((r, v, i), set()).add(t) + model.used_techs.add(t) # Link end-of-life materials to retiring technologies for r, t, v, o in model.end_of_life_output.sparse_iterkeys(): if (r, t, v) in model.retirement_periods: for p in model.retirement_periods[r, t, v]: model.retirement_production_processes.setdefault((r, p, o), set()).add((t, v)) + model.used_techs.add(t) + + # Link end-of-life emissions to retiring technologies + for r, _e, t, v in model.emission_end_of_life.sparse_iterkeys(): + if (r, t, v) in model.retirement_periods: + model.used_techs.add(t) # Create active capacity index sets from the now-populated process_vintages model.new_capacity_rtv = { diff --git a/temoa/components/technology.py b/temoa/components/technology.py index ed866f764..d122d4ae5 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -352,7 +352,7 @@ def check_efficiency_indices(model: TemoaModel) -> None: f_msg = msg.format(', '.join(diff_str)) logger.error(f_msg) raise ValueError(f_msg) - + c_inputs = {i for r, i, t, v, o in model.efficiency.sparse_iterkeys()} c_inputs = c_inputs | {i for r, i, t, v in model.construction_input.sparse_iterkeys()} c_carrier = c_inputs | c_outputs @@ -368,8 +368,11 @@ def check_efficiency_indices(model: TemoaModel) -> None: f_msg = msg.format(', '.join(symdiff_str)) logger.error(f_msg) raise ValueError(f_msg) - + techs = {t for r, i, t, v, o in model.efficiency.sparse_iterkeys()} + techs = techs | {t for r, t, v, o in model.end_of_life_output.sparse_iterkeys()} + techs = techs | {t for r, i, t, v in model.construction_input.sparse_iterkeys()} + techs = techs | {t for r, e, t, v in model.emission_end_of_life.sparse_iterkeys()} symdiff = techs.symmetric_difference(model.tech_production) if symdiff: diff --git a/temoa/core/model.py b/temoa/core/model.py index 93714b4e8..b521edb0d 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -388,6 +388,9 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.end_of_life_output = Param( self.regions, self.tech_with_capacity, self.vintage_all, self.commodity_carrier ) + self.emission_end_of_life = Param( + self.regions, self.commodity_emissions, self.tech_with_capacity, self.vintage_all + ) self.efficiency = Param( self.regional_indices, @@ -725,9 +728,6 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.tech_with_capacity, self.vintage_optimize, ) - self.emission_end_of_life = Param( - self.regions, self.commodity_emissions, self.tech_with_capacity, self.vintage_all - ) self.myopic_discounting_year = Param(default=0) From 6e9a29fc3935f9a1288eba53a87786c8033224c4 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Mar 2026 18:34:09 -0400 Subject: [PATCH 460/587] Apply same process checks to construction of retirement periods --- temoa/components/capacity.py | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/temoa/components/capacity.py b/temoa/components/capacity.py index d372d383d..e9c61314a 100644 --- a/temoa/components/capacity.py +++ b/temoa/components/capacity.py @@ -604,18 +604,36 @@ def create_capacity_and_retirement_sets(model: TemoaModel) -> None: logger.debug('Creating capacity, retirement, and construction/EOL sets.') # Calculate retirement periods based on lifetime and survival curves - for r, _i, t, v, _o in model.efficiency.sparse_iterkeys(): + unique_rtv = {(r, t, v) for r, _i, t, v, _o in model.efficiency.sparse_iterkeys()} | set( + model.existing_capacity.sparse_iterkeys() + ) + for r, t, v in unique_rtv: + if t in model.tech_uncap: + # No capacity to retire + continue + if t not in model.tech_all: + # Not an active technology so wont have a lifetime + # If it has an EOLoutput it will be in tech_all + continue lifetime = value(model.lifetime_process[r, t, v]) for p in model.time_optimize: + # retires bang on start of horizon or survives into planning periods + is_p0_eol = ( + (p == model.time_optimize.first()) + and (v + lifetime == p) + and value(model.existing_capacity[r, t, v]) > 0 + ) + is_living = (r, t, v) in model.process_periods + if not (is_p0_eol or is_living): + continue + is_natural_eol = p <= v + lifetime < p + value(model.period_length[p]) is_early_retire = t in model.tech_retirement and v < p <= v + lifetime - value( model.period_length[p] ) is_survival_curve = model.is_survival_curve_process[r, t, v] and v <= p <= v + lifetime - if t not in model.tech_uncap and any( - (is_natural_eol, is_early_retire, is_survival_curve) - ): + if any((is_natural_eol, is_early_retire, is_survival_curve)): model.retirement_periods.setdefault((r, t, v), set()).add(p) # Link construction materials to technologies From cf014ed60fa7cd2e2e3402a98ecc3c805b44656e Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Mar 2026 18:35:06 -0400 Subject: [PATCH 461/587] Setup lifetime lookups for all existing capacity data --- temoa/components/technology.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/temoa/components/technology.py b/temoa/components/technology.py index d122d4ae5..1033d99d2 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -61,6 +61,7 @@ def lifetime_process_indices(model: TemoaModel) -> set[tuple[Region, Technology, process indices that may be specified in the lifetime_process parameter. """ indices = {(r, t, v) for r, i, t, v, o in model.efficiency.sparse_iterkeys()} + indices = indices | set(model.existing_capacity.sparse_iterkeys()) return indices @@ -227,6 +228,8 @@ def create_survival_curve(model: TemoaModel) -> None: for r, _, t, v, _ in model.efficiency.sparse_iterkeys(): model.is_survival_curve_process[r, t, v] = False # by default + for r, t, v in model.existing_capacity.sparse_iterkeys(): + model.is_survival_curve_process[r, t, v] = False # by default # Collect rptv indices into (r, t, v): p dictionary for r, p, t, v in model.lifetime_survival_curve.sparse_iterkeys(): From e304fb0dd17ee621e7bea70a5e1498c31f1dc015 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Mar 2026 18:38:06 -0400 Subject: [PATCH 462/587] Update checks on existing capacity data --- temoa/components/technology.py | 38 ++++++++++++++++++++++++++++------ temoa/core/model.py | 1 + 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/temoa/components/technology.py b/temoa/components/technology.py index 1033d99d2..1bf34ea15 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -160,13 +160,13 @@ def populate_core_dictionaries(model: TemoaModel) -> None: process, ) continue - if t not in model.tech_uncap and model.existing_capacity[process] == 0: - logger.warning( - 'Notice: Unnecessary specification of existing_capacity for %s. ' - 'Declaring a capacity of zero may be omitted.', - process, + if t not in model.tech_uncap and value(model.existing_capacity[process]) <= 0: + msg = ( + f'Notice: Non-positive existing capacity declaration {process}. ' + 'This is not supported for processes surviving into future periods.' ) - continue + logger.error(msg) + raise ValueError(msg) if v + lifetime <= first_period: logger.info( '%s specified as existing_capacity, but its ' @@ -437,3 +437,29 @@ def check_efficiency_variable(model: TemoaModel) -> None: num_seg, (r, p, i, t, v, o), ) + + +def check_existing_capacity(model: TemoaModel) -> None: + """ + Check that all existing capacities are properly accounted for in the model. + """ + for r, t, v in model.existing_capacity.sparse_iterkeys(): + cap = value(model.existing_capacity[r, t, v]) + if cap <= 0: + msg = ( + f'Existing capacity {r, t, v} has non-positive capacity {cap}. ' + 'This entry will be ignored.' + ) + logger.warning(msg) + continue + if t not in model.tech_all: + continue + life = value(model.lifetime_process[r, t, v]) + if (r, t, v) not in model.process_periods and v + life > model.time_optimize.first(): + msg = ( + f'Existing capacity {r, t, v} with lifetime {life} and capacity {cap} ' + 'should extend into future periods but it is not in process periods. ' + 'Was it included in the Efficiency table?' + ) + logger.error(msg) + raise ValueError(msg) diff --git a/temoa/core/model.py b/temoa/core/model.py index b521edb0d..fe9014ed7 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -514,6 +514,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: # equations below. self.create_sparse_dicts = BuildAction(rule=create_sparse_dicts) self.initialize_demands = BuildAction(rule=commodities.create_demands) + self.validate_existing_capacity = BuildAction(rule=technology.check_existing_capacity) self.capacity_factor_rpsdt = Set(dimen=5, initialize=capacity.capacity_factor_tech_indices) self.capacity_factor_tech = Param( From aeed1988970e14f520dbab7a70cd54aa31425243 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Mar 2026 18:39:00 -0400 Subject: [PATCH 463/587] Stop outputs of negative capacities or retirements with warnings --- temoa/_internal/table_data_puller.py | 42 +++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/temoa/_internal/table_data_puller.py b/temoa/_internal/table_data_puller.py index 26fd631ca..4dff3ea02 100644 --- a/temoa/_internal/table_data_puller.py +++ b/temoa/_internal/table_data_puller.py @@ -58,7 +58,18 @@ def poll_capacity_results(model: TemoaModel, epsilon: float = 1e-5) -> CapData: for r, t, v in model.v_new_capacity.keys(): if v in model.time_optimize: val = value(model.v_new_capacity[r, t, v]) - if abs(val) < epsilon: + if val < -epsilon: + logger.warning( + 'Negative built capacity for %s, %s, %s: %s. ' + 'This should not be possible. Could be a result of ' + 'numerical instability or a code problem.', + r, + t, + v, + val, + ) + continue + if val < epsilon: continue new_cap = (r, t, v, val) built.append(new_cap) @@ -67,7 +78,19 @@ def poll_capacity_results(model: TemoaModel, epsilon: float = 1e-5) -> CapData: net = [] for r, p, t, v in model.v_capacity.keys(): val = value(model.v_capacity[r, p, t, v]) - if abs(val) < epsilon: + if val < -epsilon: + logger.warning( + 'Negative net capacity for %s, %s, %s, %s: %s. ' + 'This should not be possible. Could be a result of ' + 'numerical instability or a code problem.', + r, + p, + t, + v, + val, + ) + continue + if val < epsilon: continue new_net_cap = (r, p, t, v, val) net.append(new_net_cap) @@ -84,8 +107,19 @@ def poll_capacity_results(model: TemoaModel, epsilon: float = 1e-5) -> CapData: if t in model.tech_retirement and v < p <= v + lifetime - value(model.period_length[p]): early = value(model.v_retired_capacity[r, p, t, v]) eol -= early - early = 0 if abs(early) < epsilon else early - eol = 0 if abs(eol) < epsilon else eol + if early < -epsilon or eol < -epsilon: + logger.warning( + 'Negative retirement components for %s, %s, %s, %s: cap_eol=%s, cap_early=%s', + r, + p, + t, + v, + eol, + early, + ) + continue + early = 0 if early < epsilon else early + eol = 0 if eol < epsilon else eol if early == 0 and eol == 0: continue new_retired_cap = (r, p, t, v, eol, early) From 8170627acefff66c43b5448d42cc6259f36536c1 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Mar 2026 18:39:33 -0400 Subject: [PATCH 464/587] Update materials test to stress test myopic --- tests/test_material_results.py | 97 ++++++++++++++++++++++++++++---- tests/testing_data/materials.sql | 5 ++ 2 files changed, 91 insertions(+), 11 deletions(-) diff --git a/tests/test_material_results.py b/tests/test_material_results.py index aec11b752..5fe709739 100644 --- a/tests/test_material_results.py +++ b/tests/test_material_results.py @@ -7,6 +7,7 @@ import pytest from temoa._internal.temoa_sequencer import TemoaSequencer +from temoa.core import TemoaMode from temoa.core.config import TemoaConfig logger = logging.getLogger(__name__) @@ -15,16 +16,27 @@ @pytest.fixture(scope='module') def solved_connection( request: Any, tmp_path_factory: Any -) -> Generator[tuple[sqlite3.Connection, str, str, int, float], None, None]: +) -> Generator[tuple[sqlite3.Connection, str, str, int, float, str], None, None]: """ spin up the model, solve it, and hand over a connection to the results db """ data_name = 'materials' - logger.info('Setting up and solving: %s', data_name) + mode = request.param['mode'] + logger.info('Setting up and solving: %s in %s mode', data_name, mode) filename = 'config_materials.toml' config_file = Path(__file__).parent / 'testing_configs' / filename tmp_path = tmp_path_factory.mktemp('data') - config = TemoaConfig.build_config(config_file=config_file, output_path=tmp_path, silent=True) + config = TemoaConfig.build_config( + config_file=config_file, + output_path=tmp_path, + silent=True, + ) + config.scenario_mode = TemoaMode[mode.upper()] + config.scenario = request.param['name'] + if mode == 'myopic': + assert config.myopic_inputs is not None + config.myopic_inputs['view_depth'] = request.param['view_depth'] + config.myopic_inputs['step_size'] = request.param['step_size'] sequencer = TemoaSequencer(config=config) sequencer.start() @@ -38,14 +50,76 @@ def solved_connection( request.param['tech'], request.param['period'], request.param['target'], + mode, ) finally: con.close() # List of tech archetypes to test and their correct flowout value +# Parametrized for both perfect_foresight and myopic modes flow_tests = [ - {'name': 'lithium import', 'tech': 'IMPORT_LI', 'period': 2000, 'target': 0.129291623}, + { + 'name': 'lithium import - perfect foresight', + 'tech': 'IMPORT_LI', + 'period': 2000, + 'target': 0.129291623, + 'mode': 'perfect_foresight', + }, + { + 'name': 'lithium import - myopic 1-1', + 'tech': 'IMPORT_LI', + 'period': 2000, + 'target': 0.129291623, + 'mode': 'myopic', + 'view_depth': 1, + 'step_size': 1, + }, + { + 'name': 'lithium import - myopic 2-1', + 'tech': 'IMPORT_LI', + 'period': 2000, + 'target': 0.129291623, + 'mode': 'myopic', + 'view_depth': 2, + 'step_size': 1, + }, + { + 'name': 'lithium import - myopic 3-1', + 'tech': 'IMPORT_LI', + 'period': 2000, + 'target': 0.129291623, + 'mode': 'myopic', + 'view_depth': 3, + 'step_size': 1, + }, + { + 'name': 'lithium import - myopic 2-2', + 'tech': 'IMPORT_LI', + 'period': 2000, + 'target': 0.129291623, + 'mode': 'myopic', + 'view_depth': 2, + 'step_size': 2, + }, + { + 'name': 'lithium import - myopic 3-2', + 'tech': 'IMPORT_LI', + 'period': 2000, + 'target': 0.129291623, + 'mode': 'myopic', + 'view_depth': 3, + 'step_size': 2, + }, + { + 'name': 'lithium import - myopic 3-3', + 'tech': 'IMPORT_LI', + 'period': 2000, + 'target': 0.129291623, + 'mode': 'myopic', + 'view_depth': 3, + 'step_size': 3, + }, ] @@ -56,18 +130,19 @@ def solved_connection( indirect=True, ids=[str(t['name']) for t in flow_tests], ) -def test_flows(solved_connection: tuple[sqlite3.Connection, str, str, int, float]) -> None: +def test_flows(solved_connection: tuple[sqlite3.Connection, str, str, int, float, str]) -> None: """ - Test that the emissions from each technology archetype are correct, and check total emissions + Test that the flows from each technology archetype + are correct in both perfect foresight and myopic modes """ - con, name, tech, period, flow_target = solved_connection + con, name, tech, period, flow_target, _mode = solved_connection cursor = con.cursor() row = cursor.execute( - 'SELECT SUM(flow) FROM main.output_flow_out WHERE tech = ? AND period = ?', - (tech, period), + 'SELECT SUM(flow) FROM main.output_flow_out WHERE tech = ? AND period = ? AND scenario = ?', + (tech, period, name), ).fetchone() - # If the query returns no rows, row will be None. If it finds rows but the sum is NULL, row[0] - # will be None. + # If the query returns no rows, row will be None. + # If it finds rows but the sum is NULL, row[0] will be None. flow = row[0] if row and row[0] is not None else 0.0 assert flow == pytest.approx( diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index abf2c3c0f..626aeb3b8 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -407,6 +407,11 @@ REPLACE INTO "season_label" VALUES('summer',NULL); REPLACE INTO "season_label" VALUES('autumn',NULL); REPLACE INTO "season_label" VALUES('winter',NULL); REPLACE INTO "season_label" VALUES('spring',NULL); +REPLACE INTO "sector_label" VALUES('materials',NULL); +REPLACE INTO "sector_label" VALUES('transportation',NULL); +REPLACE INTO "sector_label" VALUES('electricity',NULL); +REPLACE INTO "sector_label" VALUES('residential',NULL); +REPLACE INTO "sector_label" VALUES('fuels',NULL); REPLACE INTO "storage_duration" VALUES('regionA','BATT_GRID',2.0,'2 hours energy storage'); REPLACE INTO "storage_duration" VALUES('regionB','BATT_GRID',2.0,'2 hours energy storage'); REPLACE INTO "technology" VALUES('IMPORT_LI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'lithium importer'); From 16e2c301409f3227d1f8cf4703e7a69c67735747 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Mar 2026 18:39:57 -0400 Subject: [PATCH 465/587] Update network model data test for new data pulls --- tests/test_network_model_data.py | 33 ++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/test_network_model_data.py b/tests/test_network_model_data.py index dba71cced..95b40e0e8 100644 --- a/tests/test_network_model_data.py +++ b/tests/test_network_model_data.py @@ -30,6 +30,7 @@ class ScenarioType(TypedDict): { 'name': 'basic', 'db_data': { + 'technology WHERE unlim_cap==1': [], 'technology WHERE retire==1': [], 'FROM lifetime_survival_curve': [], 'FROM time_period': [(2020,), (2025,)], @@ -64,7 +65,9 @@ class ScenarioType(TypedDict): ('R1', 'p2', 't5', 2000, 'd2', 100), ], 'FROM end_of_life_output': [], + 'FROM emission_end_of_life': [], 'FROM construction_input': [], + 'FROM existing_capacity': [], 'FROM main.linked_tech': [], 'FROM cost_variable': [], }, @@ -81,6 +84,7 @@ class ScenarioType(TypedDict): { 'name': 'bad linked tech', 'db_data': { + 'technology WHERE unlim_cap==1': [], 'technology WHERE retire==1': [], 'FROM lifetime_survival_curve': [], 'FROM time_period': [(2020,), (2025,)], @@ -101,7 +105,9 @@ class ScenarioType(TypedDict): ('R1', 's1', 't1', 2000, 'd1', 100), ], 'FROM end_of_life_output': [], + 'FROM emission_end_of_life': [], 'FROM construction_input': [], + 'FROM existing_capacity': [], 'FROM main.linked_tech': [('R1', 't4', 'nox', 'driven')], 'FROM cost_variable': [], }, @@ -118,6 +124,7 @@ class ScenarioType(TypedDict): { 'name': 'good linked tech', 'db_data': { + 'technology WHERE unlim_cap==1': [], 'technology WHERE retire==1': [], 'FROM lifetime_survival_curve': [], 'FROM time_period': [(2020,), (2025,)], @@ -138,7 +145,9 @@ class ScenarioType(TypedDict): ('R1', 's1', 't1', 2000, 'd1', 100), ], 'FROM end_of_life_output': [], + 'FROM emission_end_of_life': [], 'FROM construction_input': [], + 'FROM existing_capacity': [], 'FROM main.linked_tech': [('R1', 't4', 'nox', 'driven')], 'FROM cost_variable': [], }, @@ -273,6 +282,10 @@ def dispatcher(query: str, *_: object) -> MagicMock: return sector_check_mock elif 'FROM main.efficiency' in query: return efficiency_mock + elif 'technology WHERE unlim_cap==1' in query: + m = MagicMock() + m.fetchall.return_value = [] + return m elif 'technology WHERE retire==1' in query: m = MagicMock() m.fetchall.return_value = [] @@ -305,10 +318,18 @@ def dispatcher(query: str, *_: object) -> MagicMock: m = MagicMock() m.fetchall.return_value = [] return m + elif 'FROM emission_end_of_life' in query: + m = MagicMock() + m.fetchall.return_value = [] + return m elif 'FROM construction_input' in query: m = MagicMock() m.fetchall.return_value = [] return m + elif 'FROM existing_capacity' in query: + m = MagicMock() + m.fetchall.return_value = [] + return m elif 'FROM main.linked_tech' in query: m = MagicMock() m.fetchall.return_value = [] @@ -357,6 +378,10 @@ def dispatcher(query: str, *_: object) -> MagicMock: m = MagicMock() m.fetchall.return_value = [('s1',), ('p1',), ('d1',)] return m + elif 'technology WHERE unlim_cap==1' in query: + m = MagicMock() + m.fetchall.return_value = [] + return m elif 'technology WHERE retire==1' in query: m = MagicMock() m.fetchall.return_value = [] @@ -389,10 +414,18 @@ def dispatcher(query: str, *_: object) -> MagicMock: m = MagicMock() m.fetchall.return_value = [] return m + elif 'FROM emission_end_of_life' in query: + m = MagicMock() + m.fetchall.return_value = [] + return m elif 'FROM construction_input' in query: m = MagicMock() m.fetchall.return_value = [] return m + elif 'FROM existing_capacity' in query: + m = MagicMock() + m.fetchall.return_value = [] + return m elif 'FROM main.linked_tech' in query: m = MagicMock() m.fetchall.return_value = [] From 6ff587ae0cb29ff838a147543a281295f1f53471 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Mar 2026 18:40:57 -0400 Subject: [PATCH 466/587] Remove invalid existing capacity entry in mediumville --- tests/testing_data/mediumville.sql | 1 - tests/testing_data/mediumville_sets.json | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index dcd0f59bd..3cd39f7df 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -100,7 +100,6 @@ REPLACE INTO "efficiency" VALUES('A', 'GeoHyd', 'GeoHeater', 2025, 'RH', 0.9, NU REPLACE INTO "efficiency" VALUES('A', 'earth', 'GeoThermal', 2025, 'GeoHyd', 1.0, NULL, NULL); REPLACE INTO "emission_activity" VALUES('A','co2','HYD','EH',2025,'ELC',0.02,NULL,NULL); REPLACE INTO "emission_activity" VALUES('A','FusionGas','HYD','EF',2025,'ELC',-0.2,NULL,'emission_activity specifies emission activity coefficients (not efficiency values), negative coefficients represent emissions removal/capture, this coupling is essential for the linked tech constraint that converts CO2 from emissions commodity to physical commodity input.'); -REPLACE INTO "existing_capacity" VALUES('A','EH',2020,200.0,'things',NULL); REPLACE INTO "lifetime_process" VALUES('B', 'EF', 2025, 200.0, NULL, NULL); REPLACE INTO "lifetime_tech" VALUES('A', 'EH', 60.0, NULL, ''); REPLACE INTO "lifetime_tech" VALUES('B', 'bulbs', 100.0, NULL, 'super LED!'); diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 6dfdb1d80..3f217b915 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -4157,9 +4157,7 @@ "tech_exchange": [ "FGF_pipe" ], - "tech_exist": [ - "EH" - ], + "tech_exist": [], "tech_flex": [ "EFL" ], From 729b8cff725ff660a93ef46ff1ea965159147204 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Mar 2026 18:41:15 -0400 Subject: [PATCH 467/587] Fix foreign key issues in schemas --- temoa/db_schema/temoa_schema_v4.sql | 42 ++++++++++++++++------------- temoa/tutorial_assets/utopia.sql | 40 +++++++++++++++------------ 2 files changed, 47 insertions(+), 35 deletions(-) diff --git a/temoa/db_schema/temoa_schema_v4.sql b/temoa/db_schema/temoa_schema_v4.sql index 8efedde67..2007daa1f 100644 --- a/temoa/db_schema/temoa_schema_v4.sql +++ b/temoa/db_schema/temoa_schema_v4.sql @@ -708,7 +708,7 @@ CREATE TABLE IF NOT EXISTS output_curtailment period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES time_period (period), + REFERENCES season_label (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -1071,14 +1071,16 @@ CREATE TABLE IF NOT EXISTS myopic_efficiency ( base_year integer, region text, - input_comm text, - tech text, - vintage integer, - output_comm text, + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), efficiency real, lifetime integer, - - FOREIGN KEY (tech) REFERENCES technology (tech), PRIMARY KEY (region, input_comm, tech, vintage, output_comm) ); -- for efficient searching by rtv: @@ -1086,17 +1088,21 @@ CREATE INDEX IF NOT EXISTS region_tech_vintage ON myopic_efficiency (region, tec CREATE TABLE IF NOT EXISTS output_flow_out_summary ( - scenario TEXT NOT NULL, - region TEXT NOT NULL, - sector TEXT, - period INTEGER, - input_comm TEXT NOT NULL, - tech TEXT NOT NULL, - vintage INTEGER, - output_comm TEXT NOT NULL, - flow REAL NOT NULL, - - FOREIGN KEY (tech) REFERENCES technology (tech), + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + flow REAL, PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) ); diff --git a/temoa/tutorial_assets/utopia.sql b/temoa/tutorial_assets/utopia.sql index 24138883c..a9a910f75 100644 --- a/temoa/tutorial_assets/utopia.sql +++ b/temoa/tutorial_assets/utopia.sql @@ -1135,14 +1135,16 @@ CREATE TABLE myopic_efficiency ( base_year integer, region text, - input_comm text, - tech text, - vintage integer, - output_comm text, + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), efficiency real, lifetime integer, - - FOREIGN KEY (tech) REFERENCES technology (tech), PRIMARY KEY (region, input_comm, tech, vintage, output_comm) ); CREATE TABLE operator @@ -1286,17 +1288,21 @@ CREATE TABLE output_flow_out ); CREATE TABLE output_flow_out_summary ( - scenario TEXT NOT NULL, - region TEXT NOT NULL, - sector TEXT, - period INTEGER, - input_comm TEXT NOT NULL, - tech TEXT NOT NULL, - vintage INTEGER, - output_comm TEXT NOT NULL, - flow REAL NOT NULL, - - FOREIGN KEY (tech) REFERENCES technology (tech), + scenario TEXT, + region TEXT, + sector TEXT + REFERENCES sector_label (sector), + period INTEGER + REFERENCES time_period (period), + input_comm TEXT + REFERENCES commodity (name), + tech TEXT + REFERENCES technology (tech), + vintage INTEGER + REFERENCES time_period (period), + output_comm TEXT + REFERENCES commodity (name), + flow REAL, PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) ); CREATE TABLE output_net_capacity From 56666127557e7184178d27155ab5e7649f467ba3 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Mar 2026 18:41:40 -0400 Subject: [PATCH 468/587] Use set comprehension for commodity balance indices --- temoa/components/flows.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/temoa/components/flows.py b/temoa/components/flows.py index 4b1248c7b..04194faa4 100644 --- a/temoa/components/flows.py +++ b/temoa/components/flows.py @@ -110,22 +110,24 @@ def create_commodity_balance_and_flow_sets(model: TemoaModel) -> None: """ logger.debug('Creating commodity balance and active flow index sets.') # 1. Commodity Balance - commodity_upstream_rpo = set( + commodity_upstream_rpo = { (r, p, o) for r, p, o in ( model.commodity_up_stream_process - | model.retirement_production_processes | model.import_regions + | model.retirement_production_processes + | model.import_regions ) - if o not in model.commodity_sink # only balanced if input to another process (caught below) - ) - commodity_downstream_rpi = set( + if o not in model.commodity_sink # only balanced if input to another process (caught below) + } + commodity_downstream_rpi = { (r, p, i) for r, p, i in ( model.commodity_down_stream_process - | model.capacity_consumption_techs | model.export_regions + | model.capacity_consumption_techs + | model.export_regions ) - if i not in model.commodity_source # sources are never balanced (infinite source) - ) + if i not in model.commodity_source # sources are never balanced (infinite source) + } model.commodity_balance_rpc = commodity_upstream_rpo.union(commodity_downstream_rpi) # 2. Active Flow Indices (Time-Sliced) From dc78420dbeafc3311503928037b49c6f4b6f649a Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Tue, 17 Mar 2026 18:43:50 -0400 Subject: [PATCH 469/587] Update a warning for changes --- temoa/core/model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temoa/core/model.py b/temoa/core/model.py index fe9014ed7..fbaaad14e 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -83,7 +83,7 @@ def create_sparse_dicts(model: 'TemoaModel') -> None: for tech in sorted(unused_techs): logger.warning( "Notice: '%s' is specified as a technology but is not " - 'utilized in the efficiency parameter.', + 'utilized in the process network.', tech, ) From 020248ee441079e57f6dfad849754fd7e5d235f0 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 18 Mar 2026 15:37:52 -0400 Subject: [PATCH 470/587] Add tech groups to some validation indices sets --- temoa/data_io/hybrid_loader.py | 12 ++++++++---- temoa/model_checking/commodity_network_manager.py | 11 ++++++++++- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index de0c6c733..073795600 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -246,9 +246,6 @@ def create_data_dict(self, myopic_index: MyopicIndex | None = None) -> dict[str, raw_data = item.fallback_data filtered_data = self._filter_data(raw_data, item, use_raw_data) - if not filtered_data: - continue - if len(filtered_data) < len(raw_data): ignored_count = len(raw_data) - len(filtered_data) logger.warning( @@ -457,7 +454,14 @@ def _build_efficiency_dataset( if not self.manager: raise RuntimeError('Source trace manager not initialized for filtering.') - filts = self.manager.build_filters() + # Build viable sets for tech_or_group + # Create a dictionary from the tech_group_members table + tech_groups = defaultdict(set) + if self.table_exists('tech_group_member'): + for group_name, tech in cur.execute('SELECT group_name, tech FROM tech_group_member'): + tech_groups[tech].add(group_name) + + filts = self.manager.build_filters(tech_groups) self.viable_ritvo = filts['ritvo'] self.viable_rtv = filts['rtv'] self.viable_rt = filts['rt'] diff --git a/temoa/model_checking/commodity_network_manager.py b/temoa/model_checking/commodity_network_manager.py index 7762f5608..8eb5e27b5 100644 --- a/temoa/model_checking/commodity_network_manager.py +++ b/temoa/model_checking/commodity_network_manager.py @@ -94,7 +94,7 @@ def analyze_network(self) -> bool: orphans_found = any(self.demand_orphans.values()) or any(self.other_orphans.values()) return not orphans_found - def build_filters(self) -> dict[str, ViableSet]: + def build_filters(self, tech_groups: defaultdict[str, set[str]]) -> dict[str, ViableSet]: """ Constructs ViableSet filters based on the valid technologies remaining after the network analysis is complete. @@ -131,6 +131,15 @@ def build_filters(self) -> dict[str, ViableSet]: valid_elements['ic'].add(edge_tuple.input_comm) valid_elements['oc'].add(edge_tuple.output_comm) + for tech_group in tech_groups.get(edge_tuple.tech, {}): + valid_elements['rtv'].add((edge_tuple.region, tech_group, edge_tuple.vintage)) + valid_elements['rt'].add((edge_tuple.region, tech_group)) + valid_elements['rpit'].add( + (edge_tuple.region, p, edge_tuple.input_comm, tech_group) + ) + valid_elements['rpto'].add( + (edge_tuple.region, p, tech_group, edge_tuple.output_comm) + ) return { 'ritvo': ViableSet( elements=valid_elements['ritvo'], From 60c1cfc58b8ebdb42fcfc05b100372f4a80f92ab Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 18 Mar 2026 15:39:09 -0400 Subject: [PATCH 471/587] Add rtvo and rpt validation sets --- temoa/data_io/hybrid_loader.py | 4 +++ .../commodity_network_manager.py | 28 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index 073795600..fc8173096 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -106,6 +106,8 @@ def __init__(self, db_connection: Connection, config: TemoaConfig) -> None: self.viable_output_comms: ViableSet | None = None self.viable_vintages: ViableSet | None = None self.viable_ritvo: ViableSet | None = None + self.viable_rtvo: ViableSet | None = None + self.viable_rpt: ViableSet | None = None self.viable_rpto: ViableSet | None = None self.viable_rtv: ViableSet | None = None self.viable_rt: ViableSet | None = None @@ -463,6 +465,8 @@ def _build_efficiency_dataset( filts = self.manager.build_filters(tech_groups) self.viable_ritvo = filts['ritvo'] + self.viable_rtvo = filts['rtvo'] + self.viable_rpt = filts['rpt'] self.viable_rtv = filts['rtv'] self.viable_rt = filts['rt'] self.viable_rpit = filts['rpit'] diff --git a/temoa/model_checking/commodity_network_manager.py b/temoa/model_checking/commodity_network_manager.py index 8eb5e27b5..22978f73e 100644 --- a/temoa/model_checking/commodity_network_manager.py +++ b/temoa/model_checking/commodity_network_manager.py @@ -118,6 +118,15 @@ def build_filters(self, tech_groups: defaultdict[str, set[str]]) -> dict[str, Vi edge_tuple.output_comm, ) ) + valid_elements['rtvo'].add( + ( + edge_tuple.region, + edge_tuple.tech, + edge_tuple.vintage, + edge_tuple.output_comm, + ) + ) + valid_elements['rpt'].add((edge_tuple.region, p, edge_tuple.tech)) valid_elements['rtv'].add((edge_tuple.region, edge_tuple.tech, edge_tuple.vintage)) valid_elements['rt'].add((edge_tuple.region, edge_tuple.tech)) valid_elements['rpit'].add( @@ -132,6 +141,15 @@ def build_filters(self, tech_groups: defaultdict[str, set[str]]) -> dict[str, Vi valid_elements['oc'].add(edge_tuple.output_comm) for tech_group in tech_groups.get(edge_tuple.tech, {}): + valid_elements['rtvo'].add( + ( + edge_tuple.region, + tech_group, + edge_tuple.vintage, + edge_tuple.output_comm, + ) + ) + valid_elements['rpt'].add((edge_tuple.region, p, tech_group)) valid_elements['rtv'].add((edge_tuple.region, tech_group, edge_tuple.vintage)) valid_elements['rt'].add((edge_tuple.region, tech_group)) valid_elements['rpit'].add( @@ -146,11 +164,21 @@ def build_filters(self, tech_groups: defaultdict[str, set[str]]) -> dict[str, Vi exception_loc=0, exception_vals=ViableSet.REGION_REGEXES, ), + 'rtvo': ViableSet( + elements=valid_elements['rtvo'], + exception_loc=0, + exception_vals=ViableSet.REGION_REGEXES, + ), 'rtv': ViableSet( elements=valid_elements['rtv'], exception_loc=0, exception_vals=ViableSet.REGION_REGEXES, ), + 'rpt': ViableSet( + elements=valid_elements['rpt'], + exception_loc=0, + exception_vals=ViableSet.REGION_REGEXES, + ), 'rt': ViableSet( elements=valid_elements['rt'], exception_loc=0, From 66eef0a9e8af1c851af0e6aabeb272b49bd9374d Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 18 Mar 2026 15:50:31 -0400 Subject: [PATCH 472/587] Change limit_annual_capacity_factor from period to vintage table index --- temoa/components/limits.py | 77 +++++++++++++--------- temoa/core/model.py | 13 ++-- temoa/data_io/component_manifest.py | 5 +- temoa/data_io/hybrid_loader.py | 2 +- temoa/db_schema/temoa_schema_v4.sql | 7 +- temoa/tutorial_assets/utopia.sql | 7 +- temoa/utilities/db_migration_v3_to_v3_1.py | 9 ++- tests/testing_data/mediumville_sets.json | 3 +- tests/testing_data/test_system_sets.json | 3 +- tests/testing_data/utopia_sets.json | 3 +- 10 files changed, 78 insertions(+), 51 deletions(-) diff --git a/temoa/components/limits.py b/temoa/components/limits.py index baa4b0428..1051df96c 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -23,6 +23,8 @@ from temoa.components.utils import Operator, get_variable_efficiency, operator_expression if TYPE_CHECKING: + from pyomo.core import Expression + from temoa.core.model import TemoaModel from temoa.types import ExprLike, Period, Region, Technology, Vintage from temoa.types.core_types import Commodity, Season, TimeOfDay @@ -197,6 +199,20 @@ def limit_degrowth_new_capacity_delta_indices( return indices +def limit_annual_capacity_factor_indices( + model: TemoaModel, +) -> set[tuple[Region, Period, Technology, Vintage, Commodity, str]]: + indices = { + (r, p, t, v, o, op) + for r, t, v, o, op in model.limit_annual_capacity_factor_constraint_rtvo + for _r in geography.gather_group_regions(model, r) + for _t in technology.gather_group_techs(model, t) + for p in model.time_optimize + if o in model.process_outputs.get((_r, p, _t, v), []) + } + return indices + + # ============================================================================ # PYOMO CONSTRAINT RULES # ============================================================================ @@ -442,11 +458,11 @@ def limit_new_capacity_share_constraint( def limit_annual_capacity_factor_constraint( - model: TemoaModel, r: Region, p: Period, t: Technology, o: Commodity, op: str + model: TemoaModel, r: Region, p: Period, t: Technology, v: Vintage, o: Commodity, op: str ) -> ExprLike: r""" The limit_annual_capacity_factor sets an upper bound on the annual capacity factor - from a specific technology. The first portion of the constraint pertains to + from a specific process. 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. @@ -454,49 +470,50 @@ def limit_annual_capacity_factor_constraint( .. math:: :label: limit_annual_capacity_factor - \sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMACF_{r, p, t} \cdot + \sum_{S,D,I} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMACF_{r, t, v, o} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} - \forall \{r, p, t \notin T^{a}, o\} \in \Theta_{\text{limit\_annual\_capacity\_factor}} + \forall \{r, t \notin T^{a}, v, o\} \in \Theta_{\text{limit\_annual\_capacity\_factor}} - \\\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \ge LIMACF_{r, p, t} \cdot + \\\sum_{I} \textbf{FOA}_{r, p, i, t, v, o} \ge LIMACF_{r, t, v, o} \cdot \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} - \forall \{r, p, t \in T^{a}, o\} \in \Theta_{\text{limit\_annual\_capacity\_factor}} + \forall \{r, t \in T^{a}, v, o\} \in \Theta_{\text{limit\_annual\_capacity\_factor}} """ # r can be an individual region (r='US'), or a combination of regions separated by plus # (r='Mexico+US+Canada'), or 'global'. # if r == 'global', the constraint is system-wide regions = geography.gather_group_regions(model, r) - # we need to screen here because it is possible that the restriction extends beyond the - # lifetime of any vintage of the tech... - if all((_r, p, t) not in model.v_capacity_available_by_period_and_tech for _r in regions): - return Constraint.Skip + techs = technology.gather_group_techs(model, t) - if t not in model.tech_annual: - activity_rpt = quicksum( - model.v_flow_out[_r, p, s, d, S_i, t, S_v, o] - for _r in regions - for S_v in model.process_vintages.get((_r, p, t), []) - for S_i in model.process_inputs[_r, p, t, S_v] - for s in model.time_season[p] - for d in model.time_of_day - ) + if TYPE_CHECKING: + activity_rptvo = cast('Expression', 0) else: - activity_rpt = quicksum( - model.v_flow_out_annual[_r, p, S_i, t, S_v, o] - for _r in regions - for S_v in model.process_vintages.get((_r, p, t), []) - for S_i in model.process_inputs[_r, p, t, S_v] - ) + activity_rptvo = 0 + for _t in techs: + if _t not in model.tech_annual: + activity_rptvo += quicksum( + model.v_flow_out[_r, p, s, d, S_i, _t, v, o] + for _r in regions + for S_i in model.process_inputs_by_output.get((_r, p, _t, v, o), []) + for s in model.time_season[p] + for d in model.time_of_day + ) + else: + activity_rptvo += quicksum( + model.v_flow_out_annual[_r, p, S_i, _t, v, o] + for _r in regions + for S_i in model.process_inputs_by_output.get((_r, p, _t, v, o), []) + ) - possible_activity_rpt = quicksum( - model.v_capacity_available_by_period_and_tech[_r, p, t] - * value(model.capacity_to_activity[_r, t]) + possible_activity_rptvo = quicksum( + model.v_capacity[_r, p, _t, v] * value(model.capacity_to_activity[_r, _t]) for _r in regions + for _t in techs + if v in model.process_vintages.get((_r, p, _t), []) ) - annual_cf = value(model.limit_annual_capacity_factor[r, p, t, o, op]) - expr = operator_expression(activity_rpt, Operator(op), annual_cf * possible_activity_rpt) + annual_cf = value(model.limit_annual_capacity_factor[r, t, v, o, op]) + expr = operator_expression(activity_rptvo, Operator(op), annual_cf * possible_activity_rptvo) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated return Constraint.Skip diff --git a/temoa/core/model.py b/temoa/core/model.py index 93714b4e8..15d250f62 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -611,15 +611,15 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.limit_seasonal_capacity_factor_constraint_rpst, validate=validate_0to1 ) - self.limit_annual_capacity_factor_constraint_rpto = Set( + self.limit_annual_capacity_factor_constraint_rtvo = Set( within=self.regional_global_indices - * self.time_optimize - * self.tech_all + * self.tech_or_group + * self.vintage_all * self.commodity_carrier * self.operator ) self.limit_annual_capacity_factor = Param( - self.limit_annual_capacity_factor_constraint_rpto, validate=validate_0to1 + self.limit_annual_capacity_factor_constraint_rtvo, validate=validate_0to1 ) self.limit_growth_capacity = Param( @@ -1065,8 +1065,11 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.limit_resource_constraint_rt, rule=limits.limit_resource_constraint ) + self.limit_annual_capacity_factor_constraint_rptvo = Set( + dimen=6, initialize=limits.limit_annual_capacity_factor_indices + ) self.limit_annual_capacity_factor_constraint = Constraint( - self.limit_annual_capacity_factor_constraint_rpto, + self.limit_annual_capacity_factor_constraint_rptvo, rule=limits.limit_annual_capacity_factor_constraint, ) diff --git a/temoa/data_io/component_manifest.py b/temoa/data_io/component_manifest.py index bb6625545..d06a0ee84 100644 --- a/temoa/data_io/component_manifest.py +++ b/temoa/data_io/component_manifest.py @@ -643,9 +643,10 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: LoadItem( component=model.limit_annual_capacity_factor, table='limit_annual_capacity_factor', - columns=['region', 'period', 'tech', 'output_comm', 'operator', 'factor'], - validator_name='viable_rpto', + columns=['region', 'tech_or_group', 'vintage', 'output_comm', 'operator', 'factor'], + validator_name='viable_rtvo', validation_map=(0, 1, 2, 3), + is_period_filtered=False, is_table_required=False, ), LoadItem( diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index fc8173096..7335beb3b 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -915,7 +915,7 @@ def load_param_idx_sets(self, data: dict[str, object]) -> dict[str, object]: ), model.limit_activity_share.name: model.limit_activity_share_constraint_rpgg.name, model.limit_annual_capacity_factor.name: ( - model.limit_annual_capacity_factor_constraint_rpto.name + model.limit_annual_capacity_factor_constraint_rtvo.name ), model.limit_capacity.name: model.limit_capacity_constraint_rpt.name, model.limit_capacity_share.name: model.limit_capacity_share_constraint_rpgg.name, diff --git a/temoa/db_schema/temoa_schema_v4.sql b/temoa/db_schema/temoa_schema_v4.sql index 8efedde67..abe1ba84e 100644 --- a/temoa/db_schema/temoa_schema_v4.sql +++ b/temoa/db_schema/temoa_schema_v4.sql @@ -522,17 +522,16 @@ CREATE TABLE IF NOT EXISTS limit_activity_share CREATE TABLE IF NOT EXISTS limit_annual_capacity_factor ( region TEXT, - period INTEGER + tech_or_group TEXT, + vintage INTEGER REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), output_comm TEXT REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), factor REAL, notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), + PRIMARY KEY (region, tech_or_group, vintage, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE IF NOT EXISTS limit_capacity diff --git a/temoa/tutorial_assets/utopia.sql b/temoa/tutorial_assets/utopia.sql index 24138883c..2e7fcf196 100644 --- a/temoa/tutorial_assets/utopia.sql +++ b/temoa/tutorial_assets/utopia.sql @@ -802,17 +802,16 @@ CREATE TABLE limit_activity_share CREATE TABLE limit_annual_capacity_factor ( region TEXT, - period INTEGER + tech_or_group TEXT, + vintage INTEGER REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), output_comm TEXT REFERENCES commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), factor REAL, notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), + PRIMARY KEY (region, tech_or_group, vintage, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE limit_capacity diff --git a/temoa/utilities/db_migration_v3_to_v3_1.py b/temoa/utilities/db_migration_v3_to_v3_1.py index 63e7b7a8a..10d7e561c 100644 --- a/temoa/utilities/db_migration_v3_to_v3_1.py +++ b/temoa/utilities/db_migration_v3_to_v3_1.py @@ -135,7 +135,6 @@ def column_check(old_name: str, new_name: str) -> bool: "MinCapacityShare": ("LimitCapacityShare", "ge"), "MinCapacityGroup": ("LimitCapacity", "ge"), "MinCapacity": ("LimitCapacity", "ge"), - "MinAnnualCapacityFactor": ("LimitAnnualCapacityFactor", "ge"), "MinActivityShare": ("LimitActivityShare", "ge"), "MinActivityGroup": ("LimitActivity", "ge"), "MinActivity": ("LimitActivity", "ge"), @@ -146,7 +145,6 @@ def column_check(old_name: str, new_name: str) -> bool: "MaxCapacityShare": ("LimitCapacityShare", "le"), "MaxCapacityGroup": ("LimitCapacity", "le"), "MaxCapacity": ("LimitCapacity", "le"), - "MaxAnnualCapacityFactor": ("LimitAnnualCapacityFactor", "le"), "MaxActivityShare": ("LimitActivityShare", "le"), "MaxActivityGroup": ("LimitActivity", "le"), "MaxActivity": ("LimitActivity", "le"), @@ -156,6 +154,8 @@ def column_check(old_name: str, new_name: str) -> bool: no_transfer = { "MinSeasonalActivity": "LimitSeasonalCapacityFactor", "MaxSeasonalActivity": "LimitSeasonalCapacityFactor", + "MinAnnualCapacityFactor": "LimitAnnualCapacityFactor", + "MaxAnnualCapacityFactor": "LimitAnnualCapacityFactor", "StorageInit": "LimitStorageLevelFraction", } @@ -388,6 +388,11 @@ def column_check(old_name: str, new_name: str) -> bool: "manually. ---" ) for old_name, new_name in no_transfer.items(): + # Check if it exists in the old database. If not, no need to warn about it. + try: + con_old.execute(f"SELECT * FROM {old_name}").fetchone() + except sqlite3.OperationalError: + continue print(f"{old_name} to {new_name}") diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 6dfdb1d80..2574acc92 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -3222,7 +3222,8 @@ ] ], "limit_activity_share_constraint_rpgg": [], - "limit_annual_capacity_factor_constraint_rpto": [], + "limit_annual_capacity_factor_constraint_rptvo": [], + "limit_annual_capacity_factor_constraint_rtvo": [], "limit_capacity_constraint_rpt": [ [ "B", diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index f06bf0c90..706515be8 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -39963,7 +39963,8 @@ ] ], "limit_activity_share_constraint_rpgg": [], - "limit_annual_capacity_factor_constraint_rpto": [], + "limit_annual_capacity_factor_constraint_rptvo": [], + "limit_annual_capacity_factor_constraint_rtvo": [], "limit_capacity_constraint_rpt": [], "limit_capacity_share_constraint_rpgg": [], "limit_degrowth_capacity_constraint_rpt": [], diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 0278dfe67..7e0da6041 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -22105,7 +22105,8 @@ ], "limit_activity_constraint_rpt": [], "limit_activity_share_constraint_rpgg": [], - "limit_annual_capacity_factor_constraint_rpto": [], + "limit_annual_capacity_factor_constraint_rptvo": [], + "limit_annual_capacity_factor_constraint_rtvo": [], "limit_capacity_constraint_rpt": [ [ "utopia", From ea4d861c760f422c90f2b9aaa68dd285f157dbaf Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 18 Mar 2026 15:55:47 -0400 Subject: [PATCH 473/587] Enable tech groups for limit_seasonal_capacity_factor --- temoa/components/limits.py | 52 ++++++++++++++++++----------- temoa/core/model.py | 2 +- temoa/data_io/component_manifest.py | 6 ++-- temoa/db_schema/temoa_schema_v4.sql | 5 ++- temoa/tutorial_assets/utopia.sql | 5 ++- 5 files changed, 40 insertions(+), 30 deletions(-) diff --git a/temoa/components/limits.py b/temoa/components/limits.py index 1051df96c..02ea4d1de 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -548,35 +548,47 @@ def limit_seasonal_capacity_factor_constraint( # (r='Mexico+US+Canada'), or 'global'. # if r == 'global', the constraint is system-wide regions = geography.gather_group_regions(model, r) + techs = technology.gather_group_techs(model, t) + # we need to screen here because it is possible that the restriction extends beyond the # lifetime of any vintage of the tech... - if all((_r, p, t) not in model.v_capacity_available_by_period_and_tech for _r in regions): + if all( + (_r, p, _t) not in model.v_capacity_available_by_period_and_tech + for _r in regions + for _t in techs + ): return Constraint.Skip - if t not in model.tech_annual: - activity_rpst = quicksum( - model.v_flow_out[_r, p, s, d, S_i, t, S_v, S_o] - for _r in regions - for S_v in model.process_vintages[_r, p, t] - for S_i in model.process_inputs[_r, p, t, S_v] - for S_o in model.process_outputs_by_input[_r, p, t, S_v, S_i] - for d in model.time_of_day - ) + if TYPE_CHECKING: + activity_rpst = cast('Expression', 0) else: - activity_rpst = quicksum( - model.v_flow_out_annual[_r, p, S_i, t, S_v, S_o] - * model.segment_fraction_per_season[p, s] - for _r in regions - for S_v in model.process_vintages[_r, p, t] - for S_i in model.process_inputs[_r, p, t, S_v] - for S_o in model.process_outputs_by_input[_r, p, t, S_v, S_i] - ) + activity_rpst = 0 + for _t in techs: + if _t not in model.tech_annual: + activity_rpst = quicksum( + model.v_flow_out[_r, p, s, d, S_i, _t, S_v, S_o] + for _r in regions + for S_v in model.process_vintages.get((_r, p, _t), []) + for S_i in model.process_inputs.get((_r, p, _t, S_v), []) + for S_o in model.process_outputs_by_input.get((_r, p, _t, S_v, S_i), []) + for d in model.time_of_day + ) + else: + activity_rpst = quicksum( + model.v_flow_out_annual[_r, p, S_i, _t, S_v, S_o] + * model.segment_fraction_per_season[p, s] + for _r in regions + for S_v in model.process_vintages.get((_r, p, _t), []) + for S_i in model.process_inputs.get((_r, p, _t, S_v), []) + for S_o in model.process_outputs_by_input.get((_r, p, _t, S_v, S_i), []) + ) possible_activity_rpst = quicksum( - model.v_capacity_available_by_period_and_tech[_r, p, t] - * value(model.capacity_to_activity[_r, t]) + model.v_capacity_available_by_period_and_tech[_r, p, _t] + * value(model.capacity_to_activity[_r, _t]) * value(model.segment_fraction_per_season[p, s]) for _r in regions + for _t in techs ) seasonal_cf = value(model.limit_seasonal_capacity_factor[r, p, s, t, op]) expr = operator_expression(activity_rpst, Operator(op), seasonal_cf * possible_activity_rpst) diff --git a/temoa/core/model.py b/temoa/core/model.py index 15d250f62..0e59689ca 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -604,7 +604,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: within=self.regional_global_indices * self.time_optimize * self.time_season_all - * self.tech_all + * self.tech_or_group * self.operator ) self.limit_seasonal_capacity_factor = Param( diff --git a/temoa/data_io/component_manifest.py b/temoa/data_io/component_manifest.py index d06a0ee84..87989e03e 100644 --- a/temoa/data_io/component_manifest.py +++ b/temoa/data_io/component_manifest.py @@ -635,9 +635,9 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: LoadItem( component=model.limit_seasonal_capacity_factor, table='limit_seasonal_capacity_factor', - columns=['region', 'period', 'season', 'tech', 'operator', 'factor'], - validator_name='viable_rt', - validation_map=(0, 3), + columns=['region', 'period', 'season', 'tech_or_group', 'operator', 'factor'], + validator_name='viable_rpt', + validation_map=(0, 1, 3), is_table_required=False, ), LoadItem( diff --git a/temoa/db_schema/temoa_schema_v4.sql b/temoa/db_schema/temoa_schema_v4.sql index abe1ba84e..d3c2715be 100644 --- a/temoa/db_schema/temoa_schema_v4.sql +++ b/temoa/db_schema/temoa_schema_v4.sql @@ -605,13 +605,12 @@ CREATE TABLE IF NOT EXISTS limit_seasonal_capacity_factor REFERENCES time_period (period), season TEXT REFERENCES season_label (season), - tech TEXT - REFERENCES technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), factor REAL, notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) + PRIMARY KEY(region, period, season, tech_or_group, operator) ); CREATE TABLE IF NOT EXISTS limit_tech_input_split ( diff --git a/temoa/tutorial_assets/utopia.sql b/temoa/tutorial_assets/utopia.sql index 2e7fcf196..d069dd8e8 100644 --- a/temoa/tutorial_assets/utopia.sql +++ b/temoa/tutorial_assets/utopia.sql @@ -982,13 +982,12 @@ CREATE TABLE limit_seasonal_capacity_factor REFERENCES time_period (period), season TEXT REFERENCES season_label (season), - tech TEXT - REFERENCES technology (tech), + tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), factor REAL, notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) + PRIMARY KEY(region, period, season, tech_or_group, operator) ); CREATE TABLE limit_storage_level_fraction ( From 3032bec19e710356d2599b9c30bc7949f4e296c0 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 18 Mar 2026 15:57:18 -0400 Subject: [PATCH 474/587] Change period index to vintage (with same behaviour) for limit_new_capacity and share tables --- temoa/components/limits.py | 35 ++++++++++++---------- temoa/core/model.py | 16 +++++----- temoa/data_io/component_manifest.py | 10 +++++-- temoa/data_io/hybrid_loader.py | 4 +-- temoa/db_schema/temoa_schema_v4.sql | 12 ++++---- temoa/tutorial_assets/utopia.sql | 12 ++++---- temoa/utilities/db_migration_v3_to_v3_1.py | 21 +++++++++++++ tests/testing_data/mediumville.sql | 4 +-- tests/testing_data/mediumville_sets.json | 8 ++--- tests/testing_data/test_system_sets.json | 4 +-- tests/testing_data/utopia_sets.json | 4 +-- 11 files changed, 81 insertions(+), 49 deletions(-) diff --git a/temoa/components/limits.py b/temoa/components/limits.py index 02ea4d1de..e3e776bde 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -425,7 +425,7 @@ def limit_capacity_share_constraint( def limit_new_capacity_share_constraint( - model: TemoaModel, r: Region, p: Period, g1: Technology, g2: Technology, op: str + model: TemoaModel, r: Region, g1: Technology, g2: Technology, v: Vintage, op: str ) -> ExprLike: r""" The limit_new_capacity_share constraint limits the share of new capacity @@ -436,21 +436,21 @@ def limit_new_capacity_share_constraint( sub_group = technology.gather_group_techs(model, g1) sub_new_cap = quicksum( - model.v_new_capacity[_r, _t, p] + model.v_new_capacity[_r, _t, v] for _t in sub_group for _r in regions - if (_r, _t, cast('Vintage', p)) in model.process_periods + if (_r, _t, v) in model.process_periods ) super_group = technology.gather_group_techs(model, g2) super_new_cap = quicksum( - model.v_new_capacity[_r, _t, p] + model.v_new_capacity[_r, _t, v] for _t in super_group for _r in regions - if (_r, _t, cast('Vintage', p)) in model.process_periods + if (_r, _t, v) in model.process_periods ) - share_lim = value(model.limit_new_capacity_share[r, p, g1, g2, op]) + share_lim = value(model.limit_new_capacity_share[r, g1, g2, v, op]) expr = operator_expression(sub_new_cap, Operator(op), share_lim * super_new_cap) if isinstance(expr, bool): return Constraint.Skip @@ -1371,24 +1371,26 @@ def limit_activity_constraint( def limit_new_capacity_constraint( - model: TemoaModel, r: Region, p: Period, t: Technology, op: str + model: TemoaModel, r: Region, t: Technology, v: Vintage, op: str ) -> ExprLike: r""" The limit_new_capacity constraint sets a limit on the newly installed capacity of a - given technology or group in a given year. Note that the indices for these constraints are - region, period and tech. + given technology or group in a given vintage year. .. math:: :label: limit_new_capacity - \textbf{NCAP}_{r, t, v} \le LNC_{r, p, t} - - \text{where }v=p + \textbf{NCAP}_{r, t, v} \le LNC_{r, t, v} """ regions = geography.gather_group_regions(model, r) techs = technology.gather_group_techs(model, t) - cap_lim = value(model.limit_new_capacity[r, p, t, op]) - new_cap = quicksum(model.v_new_capacity[_r, _t, p] for _t in techs for _r in regions) + cap_lim = value(model.limit_new_capacity[r, t, v, op]) + new_cap = quicksum( + model.v_new_capacity[_r, _t, v] + for _t in techs + for _r in regions + if (_r, _t, v) in model.process_periods + ) expr = operator_expression(new_cap, Operator(op), cap_lim) return expr @@ -1412,7 +1414,10 @@ def limit_capacity_constraint( techs = technology.gather_group_techs(model, t) cap_lim = value(model.limit_capacity[r, p, t, op]) capacity = quicksum( - model.v_capacity_available_by_period_and_tech[_r, p, _t] for _t in techs for _r in regions + model.v_capacity_available_by_period_and_tech[_r, p, _t] + for _t in techs + for _r in regions + if (_r, p, _t) in model.process_vintages ) expr = operator_expression(capacity, Operator(op), cap_lim) return expr diff --git a/temoa/core/model.py b/temoa/core/model.py index 0e59689ca..c4c8408de 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -579,13 +579,13 @@ def __init__(self, *args: object, **kwargs: object) -> None: ) self.limit_capacity = Param(self.limit_capacity_constraint_rpt) - self.limit_new_capacity_constraint_rpt = Set( + self.limit_new_capacity_constraint_rtv = Set( within=self.regional_global_indices - * self.time_optimize * self.tech_or_group + * self.vintage_optimize * self.operator ) - self.limit_new_capacity = Param(self.limit_new_capacity_constraint_rpt) + self.limit_new_capacity = Param(self.limit_new_capacity_constraint_rtv) self.limit_resource_constraint_rt = Set( within=self.regional_global_indices * self.tech_or_group * self.operator @@ -669,14 +669,14 @@ def __init__(self, *args: object, **kwargs: object) -> None: ) self.limit_activity_share = Param(self.limit_activity_share_constraint_rpgg) - self.limit_new_capacity_share_constraint_rpgg = Set( + self.limit_new_capacity_share_constraint_rggv = Set( within=self.regional_global_indices - * self.time_optimize * self.tech_or_group * self.tech_or_group + * self.vintage_optimize * self.operator ) - self.limit_new_capacity_share = Param(self.limit_new_capacity_share_constraint_rpgg) + self.limit_new_capacity_share = Param(self.limit_new_capacity_share_constraint_rggv) # This set works for all storage-related constraints self.storage_constraints_rpsdtv = Set( @@ -1041,7 +1041,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: ) self.limit_new_capacity_constraint = Constraint( - self.limit_new_capacity_constraint_rpt, rule=limits.limit_new_capacity_constraint + self.limit_new_capacity_constraint_rtv, rule=limits.limit_new_capacity_constraint ) self.limit_capacity_share_constraint = Constraint( @@ -1053,7 +1053,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: ) self.limit_new_capacity_share_constraint = Constraint( - self.limit_new_capacity_share_constraint_rpgg, + self.limit_new_capacity_share_constraint_rggv, rule=limits.limit_new_capacity_share_constraint, ) diff --git a/temoa/data_io/component_manifest.py b/temoa/data_io/component_manifest.py index 87989e03e..8e2e6fd2a 100644 --- a/temoa/data_io/component_manifest.py +++ b/temoa/data_io/component_manifest.py @@ -598,7 +598,10 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: LoadItem( component=model.limit_new_capacity, table='limit_new_capacity', - columns=['region', 'period', 'tech_or_group', 'operator', 'new_cap'], + columns=['region', 'tech_or_group', 'vintage', 'operator', 'new_cap'], + validator_name='viable_rtv', + validation_map=(0, 1, 2), + is_period_filtered=False, is_table_required=False, ), LoadItem( @@ -610,7 +613,10 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: LoadItem( component=model.limit_new_capacity_share, table='limit_new_capacity_share', - columns=['region', 'period', 'sub_group', 'super_group', 'operator', 'share'], + columns=['region', 'sub_group', 'super_group', 'vintage', 'operator', 'share'], + validator_name='viable_rtv', + validation_map=(0, 1, 3), + is_period_filtered=False, is_table_required=False, ), LoadItem( diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index 7335beb3b..1c3e4466e 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -919,9 +919,9 @@ def load_param_idx_sets(self, data: dict[str, object]) -> dict[str, object]: ), model.limit_capacity.name: model.limit_capacity_constraint_rpt.name, model.limit_capacity_share.name: model.limit_capacity_share_constraint_rpgg.name, - model.limit_new_capacity.name: model.limit_new_capacity_constraint_rpt.name, + model.limit_new_capacity.name: model.limit_new_capacity_constraint_rtv.name, model.limit_new_capacity_share.name: ( - model.limit_new_capacity_share_constraint_rpgg.name + model.limit_new_capacity_share_constraint_rggv.name ), model.limit_resource.name: model.limit_resource_constraint_rt.name, model.limit_storage_fraction.name: model.limit_storage_fraction_constraint_rpsdtv.name, diff --git a/temoa/db_schema/temoa_schema_v4.sql b/temoa/db_schema/temoa_schema_v4.sql index d3c2715be..7a49b7bf6 100644 --- a/temoa/db_schema/temoa_schema_v4.sql +++ b/temoa/db_schema/temoa_schema_v4.sql @@ -563,28 +563,28 @@ CREATE TABLE IF NOT EXISTS limit_capacity_share CREATE TABLE IF NOT EXISTS limit_new_capacity ( region TEXT, - period INTEGER - REFERENCES time_period (period), tech_or_group TEXT, + vintage INTEGER + REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), new_cap REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) + PRIMARY KEY (region, tech_or_group, vintage, operator) ); CREATE TABLE IF NOT EXISTS limit_new_capacity_share ( region TEXT, - period INTEGER - REFERENCES time_period (period), sub_group TEXT, super_group TEXT, + vintage INTEGER + REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) + PRIMARY KEY (region, sub_group, super_group, vintage, operator) ); CREATE TABLE IF NOT EXISTS limit_resource ( diff --git a/temoa/tutorial_assets/utopia.sql b/temoa/tutorial_assets/utopia.sql index d069dd8e8..be7cce9e6 100644 --- a/temoa/tutorial_assets/utopia.sql +++ b/temoa/tutorial_assets/utopia.sql @@ -940,28 +940,28 @@ CREATE TABLE limit_growth_new_capacity_delta CREATE TABLE limit_new_capacity ( region TEXT, - period INTEGER - REFERENCES time_period (period), tech_or_group TEXT, + vintage INTEGER + REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), new_cap REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) + PRIMARY KEY (region, tech_or_group, vintage, operator) ); CREATE TABLE limit_new_capacity_share ( region TEXT, - period INTEGER - REFERENCES time_period (period), sub_group TEXT, super_group TEXT, + vintage INTEGER + REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) + PRIMARY KEY (region, sub_group, super_group, vintage, operator) ); CREATE TABLE limit_resource ( diff --git a/temoa/utilities/db_migration_v3_to_v3_1.py b/temoa/utilities/db_migration_v3_to_v3_1.py index 10d7e561c..e5e5180ef 100644 --- a/temoa/utilities/db_migration_v3_to_v3_1.py +++ b/temoa/utilities/db_migration_v3_to_v3_1.py @@ -122,6 +122,11 @@ def column_check(old_name: str, new_name: str) -> bool: ("", "TimeSegmentFraction"), ] +period_to_vintage_tables = { + "LimitNewCapacityShare", + "LimitNewCapacity", +} + operator_added_tables = { "EmissionLimit": ("LimitEmission", "le"), "TechOutputSplit": ("LimitTechOutputSplit", "ge"), @@ -188,6 +193,22 @@ def column_check(old_name: str, new_name: str) -> bool: ] op_index = new_cols.index("operator") data = [(*row[0:op_index], operator, *row[op_index:len(new_cols)-1]) for row in data] + # if table in period_to_vintage_tables, move period value from period column to vintage column + if new_name in period_to_vintage_tables: + old_cols: list[str] = [ + c[1] for c in con_old.execute(f"PRAGMA table_info({old_name});").fetchall() + ] + period_index = old_cols.index("period") + vintage_index = new_cols.index("vintage") + data = [ + ( + *row[0:period_index], + *row[period_index+1:vintage_index+1], + row[period_index], + *row[vintage_index+1:] + ) + for row in data + ] # construct the query with correct number of placeholders num_placeholders = len(data[0]) diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index dcd0f59bd..10a390528 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -116,8 +116,8 @@ REPLACE INTO "limit_capacity" VALUES('B',2025,'EH','le',20000.0,'',''); REPLACE INTO "limit_capacity" VALUES('A',2025,'A_tech_grp_1','ge',0.2,'',NULL); REPLACE INTO "limit_capacity" VALUES('A',2025,'A_tech_grp_1','le',6000.0,'',NULL); REPLACE INTO "limit_emission" VALUES('A',2025,'co2','le',10000.0,'gulps',NULL); -REPLACE INTO "limit_new_capacity_share" VALUES('A',2025,'RPS_common','A_tech_grp_1','ge',0.0,''); -REPLACE INTO "limit_new_capacity_share" VALUES('global',2025,'RPS_common','A_tech_grp_1','le',1.0,''); +REPLACE INTO "limit_new_capacity_share" VALUES('A','RPS_common','A_tech_grp_1',2025,'ge',0.0,''); +REPLACE INTO "limit_new_capacity_share" VALUES('global','RPS_common','A_tech_grp_1',2025,'le',1.0,''); REPLACE INTO "limit_resource" VALUES('B','EF','le',9000.0,'clumps',NULL); REPLACE INTO "limit_tech_input_split" VALUES('A',2025,'HYD','EH','ge',0.95,'95% HYD reqt. (other not specified...)'); REPLACE INTO "limit_tech_output_split" VALUES('B',2025,'EH','ELC','ge',0.95,'95% ELC output (there are not others, this is a min)'); diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 2574acc92..2881df96c 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -3277,20 +3277,20 @@ "limit_growth_capacity_constraint_rpt": [], "limit_growth_new_capacity_constraint_rpt": [], "limit_growth_new_capacity_delta_constraint_rpt": [], - "limit_new_capacity_constraint_rpt": [], - "limit_new_capacity_share_constraint_rpgg": [ + "limit_new_capacity_constraint_rtv": [], + "limit_new_capacity_share_constraint_rggv": [ [ "A", - 2025, "RPS_common", "A_tech_grp_1", + 2025, "ge" ], [ "global", - 2025, "RPS_common", "A_tech_grp_1", + 2025, "le" ] ], diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 706515be8..96177ee4e 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -40011,8 +40011,8 @@ "limit_growth_capacity_constraint_rpt": [], "limit_growth_new_capacity_constraint_rpt": [], "limit_growth_new_capacity_delta_constraint_rpt": [], - "limit_new_capacity_constraint_rpt": [], - "limit_new_capacity_share_constraint_rpgg": [], + "limit_new_capacity_constraint_rtv": [], + "limit_new_capacity_share_constraint_rggv": [], "limit_resource_constraint_rt": [], "limit_seasonal_capacity_factor_constraint_rpst": [], "limit_storage_fraction_constraint_rpsdtv": [ diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 7e0da6041..0e61d915b 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -22183,8 +22183,8 @@ "limit_growth_capacity_constraint_rpt": [], "limit_growth_new_capacity_constraint_rpt": [], "limit_growth_new_capacity_delta_constraint_rpt": [], - "limit_new_capacity_constraint_rpt": [], - "limit_new_capacity_share_constraint_rpgg": [], + "limit_new_capacity_constraint_rtv": [], + "limit_new_capacity_share_constraint_rggv": [], "limit_resource_constraint_rt": [], "limit_seasonal_capacity_factor_constraint_rpst": [], "limit_storage_fraction_constraint_rpsdtv": [], From 6efd9cf33de29f0735dd1223e7493d3fd6fdd44f Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 18 Mar 2026 15:57:41 -0400 Subject: [PATCH 475/587] Add viable index set filtering for some other limit tables --- temoa/data_io/component_manifest.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/temoa/data_io/component_manifest.py b/temoa/data_io/component_manifest.py index 8e2e6fd2a..e92216e2e 100644 --- a/temoa/data_io/component_manifest.py +++ b/temoa/data_io/component_manifest.py @@ -593,6 +593,8 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: component=model.limit_capacity, table='limit_capacity', columns=['region', 'period', 'tech_or_group', 'operator', 'capacity'], + validator_name='viable_rpt', + validation_map=(0, 1, 2), is_table_required=False, ), LoadItem( @@ -608,6 +610,8 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: component=model.limit_capacity_share, table='limit_capacity_share', columns=['region', 'period', 'sub_group', 'super_group', 'operator', 'share'], + validator_name='viable_rpt', + validation_map=(0, 1, 2), is_table_required=False, ), LoadItem( @@ -623,18 +627,24 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: component=model.limit_activity, table='limit_activity', columns=['region', 'period', 'tech_or_group', 'operator', 'activity'], + validator_name='viable_rpt', + validation_map=(0, 1, 2), is_table_required=False, ), LoadItem( component=model.limit_activity_share, table='limit_activity_share', columns=['region', 'period', 'sub_group', 'super_group', 'operator', 'share'], + validator_name='viable_rpt', + validation_map=(0, 1, 2), is_table_required=False, ), LoadItem( component=model.limit_resource, table='limit_resource', columns=['region', 'tech_or_group', 'operator', 'cum_act'], + validator_name='viable_rt', + validation_map=(0, 1), is_period_filtered=False, is_table_required=False, ), From e944250a26e1186f5f2463b9cce9ff31dd6d0f1b Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 18 Mar 2026 19:16:44 -0400 Subject: [PATCH 476/587] Fix summation in limit_seasonal_capacity_factor_constraint --- temoa/components/limits.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/temoa/components/limits.py b/temoa/components/limits.py index e3e776bde..5e53d3756 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -565,7 +565,7 @@ def limit_seasonal_capacity_factor_constraint( activity_rpst = 0 for _t in techs: if _t not in model.tech_annual: - activity_rpst = quicksum( + activity_rpst += quicksum( model.v_flow_out[_r, p, s, d, S_i, _t, S_v, S_o] for _r in regions for S_v in model.process_vintages.get((_r, p, _t), []) @@ -574,7 +574,7 @@ def limit_seasonal_capacity_factor_constraint( for d in model.time_of_day ) else: - activity_rpst = quicksum( + activity_rpst += quicksum( model.v_flow_out_annual[_r, p, S_i, _t, S_v, S_o] * model.segment_fraction_per_season[p, s] for _r in regions @@ -589,6 +589,7 @@ def limit_seasonal_capacity_factor_constraint( * value(model.segment_fraction_per_season[p, s]) for _r in regions for _t in techs + if (_r, p, _t) in model.v_capacity_available_by_period_and_tech ) seasonal_cf = value(model.limit_seasonal_capacity_factor[r, p, s, t, op]) expr = operator_expression(activity_rpst, Operator(op), seasonal_cf * possible_activity_rpst) From b6781805e39f11683ab5992fa4b129aa902fe60a Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 18 Mar 2026 19:16:54 -0400 Subject: [PATCH 477/587] Update v3.1 schema to support updated migrator --- temoa/db_schema/temoa_schema_v3_1.sql | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/temoa/db_schema/temoa_schema_v3_1.sql b/temoa/db_schema/temoa_schema_v3_1.sql index b91d03ce5..303c74725 100644 --- a/temoa/db_schema/temoa_schema_v3_1.sql +++ b/temoa/db_schema/temoa_schema_v3_1.sql @@ -516,17 +516,16 @@ CREATE TABLE IF NOT EXISTS LimitActivityShare CREATE TABLE IF NOT EXISTS LimitAnnualCapacityFactor ( region TEXT, - period INTEGER + tech_or_group TEXT, + vintage INTEGER REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), output_comm TEXT REFERENCES Commodity (name), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), factor REAL, notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), + PRIMARY KEY (region, tech_or_group, vintage, output_comm, operator), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE IF NOT EXISTS LimitCapacity @@ -558,28 +557,28 @@ CREATE TABLE IF NOT EXISTS LimitCapacityShare CREATE TABLE IF NOT EXISTS LimitNewCapacity ( region TEXT, - period INTEGER - REFERENCES TimePeriod (period), tech_or_group TEXT, + vintage INTEGER + REFERENCES TimePeriod (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), new_cap REAL, units TEXT, notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) + PRIMARY KEY (region, tech_or_group, vintage, operator) ); CREATE TABLE IF NOT EXISTS LimitNewCapacityShare ( region TEXT, - period INTEGER - REFERENCES TimePeriod (period), sub_group TEXT, super_group TEXT, + vintage INTEGER + REFERENCES TimePeriod (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), share REAL, notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) + PRIMARY KEY (region, sub_group, super_group, vintage, operator) ); CREATE TABLE IF NOT EXISTS LimitResource ( From 1e1b4fbdba1037569a12a64372cb56820ef1c464 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 13 Mar 2026 16:54:16 -0400 Subject: [PATCH 478/587] Add evolving to config --- temoa/core/config.py | 7 +++++++ temoa/extensions/myopic/myopic_sequencer.py | 2 ++ temoa/tutorial_assets/config_sample.toml | 10 +++++++++- tests/testing_configs/config_utopia_myopic.toml | 2 ++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/temoa/core/config.py b/temoa/core/config.py index 962893f87..ecaca6044 100644 --- a/temoa/core/config.py +++ b/temoa/core/config.py @@ -313,6 +313,13 @@ def __repr__(self) -> str: msg += '{:>{}s}: {}\n'.format( 'Myopic step size', width, self.myopic_inputs.get('step_size') ) + msg += '{:>{}s}: {}\n'.format( + 'Evolving mode', width, bool(self.myopic_inputs.get('evolving')) + ) + if bool(self.myopic_inputs.get('evolving')): + msg += '{:>{}s}: {}\n'.format( + 'Evolution script', width, str(self.myopic_inputs.get('evolution_script')) + ) if self.scenario_mode == TemoaMode.MGA and self.mga_inputs is not None: msg += spacer diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index 4637824a0..bce5a216e 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -104,6 +104,8 @@ def __init__(self, config: TemoaConfig | None): f'is larger than the view depth ({self.view_depth}). ' f'Check config' ) + self.evolving: bool = myopic_options.get('evolving') + self.evolution_script: str = myopic_options.get('evolution_script') else: # A None was passed for config and the caller is responsible for setting instance vars pass diff --git a/temoa/tutorial_assets/config_sample.toml b/temoa/tutorial_assets/config_sample.toml index e2c5573b7..88f08157c 100644 --- a/temoa/tutorial_assets/config_sample.toml +++ b/temoa/tutorial_assets/config_sample.toml @@ -153,7 +153,15 @@ weighting = "hull_expansion" # use a convex hull expansion algorithm to weight [myopic] view_depth = 2 # number of periods seen/analyzed per iteration -step_size = 1 # number of periods to step by (must be <= view depth) +step_size = 2 # number of periods to step by (must be <= view depth) +# Evolving mode: if true, the evolution_script is called between myopic iterations +# to update the database. The view depth may shorten near the end of the planning +# horizon to ensure that all iterations are performed. +# If false, the evolution_script is not used and iterations end once view depth +# reaches the end of the planning horizon, to avoid redundant decisions with no +# new information. +evolving = true +evolution_script = "temoa\\extensions\\myopic\\evolution_updater.py" [morris] perturbation = 0.10 # amount to perturb marked parameters (ex: 0.10 -> +/- 10%) diff --git a/tests/testing_configs/config_utopia_myopic.toml b/tests/testing_configs/config_utopia_myopic.toml index bbfff7863..f45013741 100644 --- a/tests/testing_configs/config_utopia_myopic.toml +++ b/tests/testing_configs/config_utopia_myopic.toml @@ -18,3 +18,5 @@ weight = "integer" [myopic] view_depth = 2 step_size = 1 +evolving = true +evolution_script = '' From 5b443a83363e8a9287f8c5726b80be607772f0cd Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 13 Mar 2026 16:56:18 -0400 Subject: [PATCH 479/587] Add call to evolution script to myopic sequencer --- temoa/extensions/myopic/evolution_updater.py | 31 +++++++++++ .../myopic/myopic_progress_mapper.py | 9 +++- temoa/extensions/myopic/myopic_sequencer.py | 53 +++++++++++++------ 3 files changed, 76 insertions(+), 17 deletions(-) create mode 100644 temoa/extensions/myopic/evolution_updater.py diff --git a/temoa/extensions/myopic/evolution_updater.py b/temoa/extensions/myopic/evolution_updater.py new file mode 100644 index 000000000..223a48c70 --- /dev/null +++ b/temoa/extensions/myopic/evolution_updater.py @@ -0,0 +1,31 @@ +import sqlite3 +from temoa.extensions.myopic.myopic_index import MyopicIndex + +def iterate( + idx: MyopicIndex | None = None, + prev_base_year: int | None = None, + last_instance_status: str | None = None, + db_con: sqlite3.Connection | None = None, + ): + """ + This function is called at the end of each myopic iteration, + after the results have been recorded to the myopic database. + You can use it to update your myopic database with any additional + information you want to track across iterations, or to implement + an evolving myopic approach where the model structure changes + across iterations based on some user-defined logic. + + Parameters: + - idx (MyopicIndex): The index object for the current iteration, + containing information about the base year, view depth, etc. + - prev_base_year (int): The base year of the previous iteration. + - last_instance_status (str): The status of the last solved instance + ('optimal' meaning successful or 'roll_back' meaning solver failure + and rollback to previous iteration). + - db_con (sqlite3.Connection): A connection object to the myopic database, + which you can use to read/write data as needed. + """ + + # Update your myopic database here. + + return \ No newline at end of file diff --git a/temoa/extensions/myopic/myopic_progress_mapper.py b/temoa/extensions/myopic/myopic_progress_mapper.py index 0d38e3135..3f17adb18 100644 --- a/temoa/extensions/myopic/myopic_progress_mapper.py +++ b/temoa/extensions/myopic/myopic_progress_mapper.py @@ -50,8 +50,15 @@ def timestamp(self) -> str: ) def report(self, mi: MyopicIndex, status): - if status not in {'load', 'solve', 'report', 'check'}: + if status not in {'load', 'solve', 'report', 'check', 'evolve'}: raise ValueError(f'bad status: {status} received in MyopicProgressMapper') + + if status == 'evolve': + repeats = self.years.index(mi.last_demand_year) - self.years.index(mi.base_year) + 1 + print(self.timestamp(), end='') + print(' ' * self.pos[mi.base_year], end='') + for _ in range(repeats): + print('EVLV', end=' ' * (self.tag_width + 2 - 4)) # 4=length('EVLV') if status == 'load': repeats = self.years.index(mi.last_demand_year) - self.years.index(mi.base_year) + 1 diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index bce5a216e..8184b4b52 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -7,7 +7,7 @@ import sqlite3 import sys from collections import deque -from importlib import resources +from importlib import resources, util from pathlib import Path from sqlite3 import Connection @@ -165,14 +165,15 @@ def start(self): # 1. get feedback from previous instance execution (optimal/infeasible/...) # 2. decide what to do about it # 3. pull the next instance from the queue (if !empty & if needed) - # 4. Update the myopic_efficiency table (clean up history / add stuff now in visibility) - # 5. pull data for next run and filter it with source tracing - # 6. build instance - # 7. run checks (price check) on the model, if selected - # 8. run the model and assess - # 9. commit or back out any data as necessary - # 10. report findings - # 11. compact the db + # 4. if evolving, call the evolution script and pass it the myopic index and last instance status + # 5. update the myopic_efficiency table (clean up history / add stuff now in visibility) + # 6. pull data for next run and filter it with source tracing + # 7. build instance + # 8. run checks (price check) on the model, if selected + # 9. run the model and assess + # 10. commit or back out any data as necessary + # 11. report findings + # 12. compact the db last_instance_status = None # solve status last_base_year = None @@ -206,18 +207,38 @@ def start(self): else: raise RuntimeError('Illegal state in myopic iteration.') logger.info('Processing Myopic Index: %s', idx) + + # 4. If evolving, call the evolution script and pass it the myopic index and last instance status + if self.evolving and last_instance_status is not None: # don't evolve before first iteration (pointless) + if not self.config.silent: + self.progress_mapper.report(idx, 'evolve') + if not self.evolution_script: + logger.info( + 'Evolving myopic mode selected, but no evolution script provided.' + ) + else: + # import the script as a module and call the iterate function with the idx and last_instance_status + spec = util.spec_from_file_location("evolution_script", self.evolution_script) + evolution_module = util.module_from_spec(spec) + spec.loader.exec_module(evolution_module) + evolution_module.iterate( + idx=idx, + prev_base_year=last_base_year, + last_instance_status=last_instance_status, + db_con=self.output_con, # pass the db connection so the script can make updates as needed + ) + + # 5. update the myopic_efficiency table so it is ready for the upcoming data pull. if not self.config.silent: self.progress_mapper.report(idx, 'load') - - # 4. update the myopic_efficiency table so it is ready for the upcoming data pull. self.update_myopic_efficiency_table(myopic_index=idx, prev_base=last_base_year) - # 5. pull the data + # 6. pull the data # make a data loader data_loader = HybridLoader(self.output_con, self.config) data_portal = data_loader.load_data_portal(myopic_index=idx) - # 6. build + # 7. build instance = run_actions.build_instance( loaded_portal=data_portal, model_name=self.config.scenario, @@ -227,7 +248,7 @@ def start(self): / ''.join(('LP', str(idx.base_year))), # base year folder ) - # 7. Run checks... + # 8. Run checks... if not self.config.silent: self.progress_mapper.report(idx, 'check') if self.config.price_check: @@ -235,7 +256,7 @@ def start(self): if not good_prices and not self.config.silent: print('\nWarning: Cost anomalies discovered. Check log file for details.') - # 8. Run the model and assess solve status + # 9. Run the model and assess solve status if not self.config.silent: self.progress_mapper.report(idx, 'solve') model, results = run_actions.solve_instance( @@ -254,7 +275,7 @@ def start(self): logger.info('Completed myopic iteration on %s', idx) - # 9, 10. Update the output tables... + # 10, 11. Update the output tables... # first, clear any possible previous results that overlap, we might have been # backtracking... self.clear_results_after(idx.base_year) From 078e4b0b489495409e7e94190cce5e6b3b78d5af Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 13 Mar 2026 16:58:25 -0400 Subject: [PATCH 480/587] Update iteration logic --- temoa/extensions/myopic/myopic_sequencer.py | 40 ++++++++++++++------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index 8184b4b52..a3a32730d 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -498,21 +498,37 @@ def characterize_run(self, future_periods: list[int] | None = None) -> None: self.progress_mapper.draw_header() # check that we have enough periods to do myopic run - # 2 iterations, excluding end year, will be via shortened depth, if reqd. if len(future_periods) < self.view_depth + 1: - logger.error( - 'Not enough future years to run myopic mode. Need %d including end year. Got %d.', - self.view_depth + 1, - len(future_periods), - ) - sys.exit(-1) + msg = ( + 'Not enough future periods for view depth. Need {} including end period. Got {}.' + ).format(self.view_depth+1, len(future_periods)) + logger.error(msg) + raise RuntimeError(msg) self.optimization_periods = future_periods.copy() - last_idx = len(future_periods) - 1 - for idx in range(0, len(future_periods[:-1]), self.step_size): - depth = min(self.view_depth, last_idx - idx) - step = min(self.step_size, last_idx - idx) + last_base_year = ((len(future_periods) - 2) // self.step_size) * self.step_size + base_years = list(range(0, last_base_year+1, self.step_size)) + if not self.evolving: + # Remove redundant iterations near end of horizon if not evolving + catch_Pe = [i for i in base_years if i + self.view_depth >= len(future_periods) - 1] + if len(catch_Pe) > 1: + # keep only one iteration that captures the end of the horizon + base_years = base_years[:-len(catch_Pe) + 1] + for n, idx in enumerate(base_years): + depth = min(self.view_depth, len(future_periods) - idx - 1) + if idx == base_years[-1]: + # last period, record the rest + step = depth + else: + # record to next base year + step = base_years[n+1] - idx if depth < 1: - break + msg = ( + 'Calculated MyopicIndex with non-positive depth. ' + 'This should never happen. Code error likely. ' + 'idx: {}, step: {}, depth: {}, future_periods: {}' + ).format(idx, step, depth, future_periods) + logger.error(msg) + raise RuntimeError(msg) myopic_idx = MyopicIndex( base_year=future_periods[idx], step_year=future_periods[idx + step], From ee0c582d5e28f5109553e3b4c6b7a108e98f81ad Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 13 Mar 2026 17:01:50 -0400 Subject: [PATCH 481/587] Yes I really added a guard rail for that --- temoa/extensions/myopic/myopic_sequencer.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index a3a32730d..663f3ce61 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -93,11 +93,11 @@ def __init__(self, config: TemoaConfig | None): raise RuntimeError('No myopic options received. See log file.') else: self.view_depth: int = myopic_options.get('view_depth') - if not isinstance(self.view_depth, int): - raise ValueError(f'view_depth is not an integer {self.view_depth}') + if not isinstance(self.view_depth, int) or self.view_depth < 1: + raise ValueError(f'view_depth is not a positive integer {self.view_depth}') self.step_size: int = myopic_options.get('step_size') - if not isinstance(self.step_size, int): - raise ValueError(f'step_size is not an integer {self.step_size}') + if not isinstance(self.step_size, int) or self.step_size < 1: + raise ValueError(f'step_size is not a positive integer {self.step_size}') if self.step_size > self.view_depth: raise ValueError( f'the Myopic step size({self.step_size}) ' From 9902e22a1fc41d7ab79902620d22512b522398b9 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 13 Mar 2026 17:02:28 -0400 Subject: [PATCH 482/587] Change loading filter warning to info for myopic as is necessary for period filtering --- temoa/data_io/hybrid_loader.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index de0c6c733..93571b8ac 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -251,11 +251,22 @@ def create_data_dict(self, myopic_index: MyopicIndex | None = None) -> dict[str, if len(filtered_data) < len(raw_data): ignored_count = len(raw_data) - len(filtered_data) - logger.warning( - '%d values for %s failed to validate and were ignored.', - ignored_count, - item.component.name, - ) + if myopic_index: + logger.info( + '%d values for %s failed to validate and were ignored. This is ' + 'likely due to myopic period filtering, but it could indicate ' + 'data quality issues.', + ignored_count, + item.component.name, + ) + else: + logger.warning( + '%d values for %s failed to validate and were ignored. This may be ' + 'due to source-trace filtering, but if not, it could indicate data ' + 'quality issues.', + ignored_count, + item.component.name, + ) self._load_component_data(data, item.component, filtered_data) # --------------------------------------------------------------------- From f6622edef18b2f0dbc83b890429bd43488fc69a8 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 13 Mar 2026 17:03:14 -0400 Subject: [PATCH 483/587] Update myopic sequencer test for on and off evolving mode --- tests/test_myopic_sequencer.py | 64 ++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 6 deletions(-) diff --git a/tests/test_myopic_sequencer.py b/tests/test_myopic_sequencer.py index 1c28eb01e..e63f5e707 100644 --- a/tests/test_myopic_sequencer.py +++ b/tests/test_myopic_sequencer.py @@ -7,22 +7,66 @@ params = [ { 'name': 'single_step', - 'conf_data': {'step_size': 1, 'view_depth': 3}, + 'conf_data': { + 'step_size': 1, + 'view_depth': 3, + 'evolving': False, + 'evolution_script': None + }, + 'expected_steps': 2, + 'expected_last_base_year': 1, + }, + { + 'name': 'triple_step', + 'conf_data': { + 'step_size': 3, + 'view_depth': 4, + 'evolving': False, + 'evolution_script': None + }, + 'expected_steps': 1, # see end of horizon immediately + 'expected_last_base_year': 0, + }, + { + 'name': 'single_step_evolving', + 'conf_data': { + 'step_size': 1, + 'view_depth': 3, + 'evolving': True, + 'evolution_script': None + }, 'expected_steps': 4, + 'expected_last_base_year': 3, }, # 4 single steps { - 'name': 'triple_step', - 'conf_data': {'step_size': 3, 'view_depth': 4}, + 'name': 'triple_step_evolving', + 'conf_data': { + 'step_size': 3, + 'view_depth': 4, + 'evolving': True, + 'evolution_script': None + }, 'expected_steps': 2, # 1 step of 3, followed by 1 step of 1 + 'expected_last_base_year': 3, }, ] """ assuming the periods are [0, 1, 2, 3, 4] + +[EVOLVING MODE OFF] for single step, the myopic indices should be... (base, last demand year, last year) (0, 2, 3) (1, 3, 4) + +for triple step, the myopic indices should be... +(0, 3, 4) + +[EVOLVING MODE ON] +for single step, the myopic indices should be... +(0, 2, 3) +(1, 3, 4) (2, 3, 4) (3, 3, 4) @@ -41,6 +85,8 @@ def test_characterize_run(param: dict[str, Any]) -> None: ms = MyopicSequencer(config=None) ms.view_depth = param['conf_data']['view_depth'] ms.step_size = param['conf_data']['step_size'] + ms.evolving = param['conf_data']['evolving'] + ms.evolution_script = param['conf_data']['evolution_script'] ms.characterize_run(future_periods=list(range(5))) assert len(ms.instance_queue) == param['expected_steps'], ( @@ -49,6 +95,12 @@ def test_characterize_run(param: dict[str, Any]) -> None: # pop the last myopic index from the queue and inspect it. Should be same for both cases last_mi = ms.instance_queue.popleft() - assert last_mi.last_year == 4 - assert last_mi.last_demand_year == 3 - assert last_mi.base_year == 3 + assert last_mi.last_year == 4, ( + 'last year in myopic index should be the end of the planning horizon' + ) + assert last_mi.last_demand_year == 3, ( + 'last demand year in myopic index should be the last planning year' + ) + assert last_mi.base_year == param['expected_last_base_year'], ( + 'base year in myopic index does not match expected base year' + ) From b1a30705f7e190f091ec658eec8daed4d1a254ff Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 13 Mar 2026 22:08:15 -0400 Subject: [PATCH 484/587] Update config file path for unix systems --- temoa/tutorial_assets/config_sample.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temoa/tutorial_assets/config_sample.toml b/temoa/tutorial_assets/config_sample.toml index 88f08157c..bf31725f0 100644 --- a/temoa/tutorial_assets/config_sample.toml +++ b/temoa/tutorial_assets/config_sample.toml @@ -161,7 +161,7 @@ step_size = 2 # number of periods to step by (must be <= view depth) # reaches the end of the planning horizon, to avoid redundant decisions with no # new information. evolving = true -evolution_script = "temoa\\extensions\\myopic\\evolution_updater.py" +evolution_script = "temoa/extensions/myopic/evolution_updater.py" [morris] perturbation = 0.10 # amount to perturb marked parameters (ex: 0.10 -> +/- 10%) From 0bed97bcf0587a8990310704361921606f4e6b29 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 13 Mar 2026 22:35:58 -0400 Subject: [PATCH 485/587] Add logging to evolution script boilerplate --- temoa/extensions/myopic/evolution_updater.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/temoa/extensions/myopic/evolution_updater.py b/temoa/extensions/myopic/evolution_updater.py index 223a48c70..6791a7eff 100644 --- a/temoa/extensions/myopic/evolution_updater.py +++ b/temoa/extensions/myopic/evolution_updater.py @@ -1,12 +1,15 @@ import sqlite3 +import logging from temoa.extensions.myopic.myopic_index import MyopicIndex +logger = logging.getLogger(__name__) + def iterate( idx: MyopicIndex | None = None, prev_base_year: int | None = None, last_instance_status: str | None = None, db_con: sqlite3.Connection | None = None, - ): + ) -> None: """ This function is called at the end of each myopic iteration, after the results have been recorded to the myopic database. @@ -25,7 +28,9 @@ def iterate( - db_con (sqlite3.Connection): A connection object to the myopic database, which you can use to read/write data as needed. """ - + + logger.info(f"Running myopic iteration updater for base year {idx.base_year}") + # Update your myopic database here. return \ No newline at end of file From 24448bda9e591cdd0996b939907978ce8f500fa2 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 13 Mar 2026 22:36:16 -0400 Subject: [PATCH 486/587] Add checks to evolution script run and refactor --- temoa/extensions/myopic/myopic_sequencer.py | 70 ++++++++++++++++----- 1 file changed, 53 insertions(+), 17 deletions(-) diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index 663f3ce61..927a9bdf0 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -210,23 +210,12 @@ def start(self): # 4. If evolving, call the evolution script and pass it the myopic index and last instance status if self.evolving and last_instance_status is not None: # don't evolve before first iteration (pointless) - if not self.config.silent: - self.progress_mapper.report(idx, 'evolve') - if not self.evolution_script: - logger.info( - 'Evolving myopic mode selected, but no evolution script provided.' - ) - else: - # import the script as a module and call the iterate function with the idx and last_instance_status - spec = util.spec_from_file_location("evolution_script", self.evolution_script) - evolution_module = util.module_from_spec(spec) - spec.loader.exec_module(evolution_module) - evolution_module.iterate( - idx=idx, - prev_base_year=last_base_year, - last_instance_status=last_instance_status, - db_con=self.output_con, # pass the db connection so the script can make updates as needed - ) + self.run_evolution_script( + idx=idx, + last_base_year=last_base_year, + last_instance_status=last_instance_status, + con=self.output_con, + ) # 5. update the myopic_efficiency table so it is ready for the upcoming data pull. if not self.config.silent: @@ -368,6 +357,53 @@ def initialize_myopic_efficiency_table(self): res = self.cursor.execute(q2).fetchall() print(list(res)) + def run_evolution_script( + self, + idx: int | None, + last_base_year: int | None, + last_instance_status: str | None, + con: sqlite3.Connection | None + ) -> None: + """ + Run the evolution script to update the myopic database before the next iteration. + """ + + if not self.evolution_script: + logger.warning('Evolving myopic mode selected, but no evolution script provided.') + return + + # import the script as a module and call the iterate function + script_path = Path(self.evolution_script).expanduser() + if not script_path.is_file(): + msg = f"Myopic evolution script not found: {script_path}" + logger.error(msg) + raise FileNotFoundError(msg) + + spec = util.spec_from_file_location("evolution_script", script_path) + if spec is None or spec.loader is None: + msg = f"Could not load evolution script module spec from: {script_path}" + logger.error(msg) + raise RuntimeError(msg) + + evolution_module = util.module_from_spec(spec) + spec.loader.exec_module(evolution_module) + iterate = getattr(evolution_module, "iterate", None) + if not callable(iterate): + msg = f"Evolution script must define callable iterate(...): {script_path}" + logger.error(msg) + raise AttributeError(msg) + + if not self.config.silent: + self.progress_mapper.report(idx, 'evolve') + + iterate( + idx=idx, + prev_base_year=last_base_year, + last_instance_status=last_instance_status, + db_con=con, + ) + + def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: int): """ This function adds to the myopic_efficiency table in the db with data specific From 07c93c9ad197272f15b28b0b3554b3c108484476 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Sat, 14 Mar 2026 11:46:45 -0400 Subject: [PATCH 487/587] Make myopic non-evolving default in configs --- temoa/tutorial_assets/config_sample.toml | 2 +- tests/testing_configs/config_utopia_myopic.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/temoa/tutorial_assets/config_sample.toml b/temoa/tutorial_assets/config_sample.toml index bf31725f0..50a50437b 100644 --- a/temoa/tutorial_assets/config_sample.toml +++ b/temoa/tutorial_assets/config_sample.toml @@ -160,7 +160,7 @@ step_size = 2 # number of periods to step by (must be <= view depth) # If false, the evolution_script is not used and iterations end once view depth # reaches the end of the planning horizon, to avoid redundant decisions with no # new information. -evolving = true +evolving = false evolution_script = "temoa/extensions/myopic/evolution_updater.py" [morris] diff --git a/tests/testing_configs/config_utopia_myopic.toml b/tests/testing_configs/config_utopia_myopic.toml index f45013741..6ad881bbc 100644 --- a/tests/testing_configs/config_utopia_myopic.toml +++ b/tests/testing_configs/config_utopia_myopic.toml @@ -18,5 +18,5 @@ weight = "integer" [myopic] view_depth = 2 step_size = 1 -evolving = true +evolving = false evolution_script = '' From a72900e8a6c56b8fd8005723f963c8e5ba168c86 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Sun, 8 Mar 2026 19:17:03 -0400 Subject: [PATCH 488/587] Fix region index in reserve_margin_dynamic --- temoa/components/reserves.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/temoa/components/reserves.py b/temoa/components/reserves.py index bc82625b7..869fbba6c 100644 --- a/temoa/components/reserves.py +++ b/temoa/components/reserves.py @@ -152,8 +152,8 @@ def reserve_margin_dynamic( # add the available output of the exchange tech. available += sum( model.v_capacity[r1r2, p, t, v] - * value(model.reserve_capacity_derate[r, p, s, t, v]) - * value(model.capacity_factor_process[r, p, s, d, t, v]) + * value(model.reserve_capacity_derate[r1r2, p, s, t, v]) + * value(model.capacity_factor_process[r1r2, p, s, d, t, v]) * value(model.capacity_to_activity[r1r2, t]) * value(model.segment_fraction[p, s, d]) for (t, v) in model.process_reserve_periods[r1r2, p] From 908757f69d082781140d1f964ab2e3a0c0361d1f Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Sun, 8 Mar 2026 19:22:32 -0400 Subject: [PATCH 489/587] Subtract exchange reserve commitments from upstream region --- temoa/components/reserves.py | 67 +++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/temoa/components/reserves.py b/temoa/components/reserves.py index 869fbba6c..3708faae6 100644 --- a/temoa/components/reserves.py +++ b/temoa/components/reserves.py @@ -144,20 +144,27 @@ def reserve_margin_dynamic( continue r1, r2 = r1r2.split('-') - # Only consider the capacity of technologies that import to - # the region in question -- i.e. for cases where r2 == r. - if r2 != r: - continue - - # add the available output of the exchange tech. - available += sum( - model.v_capacity[r1r2, p, t, v] - * value(model.reserve_capacity_derate[r1r2, p, s, t, v]) - * value(model.capacity_factor_process[r1r2, p, s, d, t, v]) - * value(model.capacity_to_activity[r1r2, t]) - * value(model.segment_fraction[p, s, d]) - for (t, v) in model.process_reserve_periods[r1r2, p] - ) + # Only consider exchange technologies connecting to this region + if r2 == r: + # Add the firm capacity commitment TO this region + available += sum( + model.v_capacity[r1r2, p, t, v] + * value(model.reserve_capacity_derate[r1r2, p, s, t, v]) + * value(model.capacity_factor_process[r1r2, p, s, d, t, v]) + * value(model.capacity_to_activity[r1r2, t]) + * value(model.segment_fraction[p, s, d]) + for (t, v) in model.process_reserve_periods[r1r2, p] + ) + if r1 == r: + # Subtract the firm capacity commitment FROM this region + available -= sum( + model.v_capacity[r1r2, p, t, v] + * value(model.reserve_capacity_derate[r1r2, p, s, t, v]) + * value(model.capacity_factor_process[r1r2, p, s, d, t, v]) + * value(model.capacity_to_activity[r1r2, t]) + * value(model.segment_fraction[p, s, d]) + for (t, v) in model.process_reserve_periods[r1r2, p] + ) return available @@ -230,19 +237,25 @@ def reserve_margin_static( continue r1, r2 = r1r2.split('-') - # Only consider the capacity of technologies that import to - # the region in question -- i.e. for cases where r2 == r. - if r2 != r: - continue - - # add the available capacity of the exchange tech. - available += sum( - value(model.capacity_credit[r1r2, p, t, v]) - * model.v_capacity[r1r2, p, t, v] - * value(model.capacity_to_activity[r1r2, t]) - * value(model.segment_fraction[p, s, d]) - for (t, v) in model.process_reserve_periods[r1r2, p] - ) + # Only consider exchange technologies connecting to this region + if r2 == r: + # Add the firm capacity commitment TO this region + available += sum( + value(model.capacity_credit[r1r2, p, t, v]) + * model.v_capacity[r1r2, p, t, v] + * value(model.capacity_to_activity[r1r2, t]) + * value(model.segment_fraction[p, s, d]) + for (t, v) in model.process_reserve_periods[r1r2, p] + ) + if r1 == r: + # Subtract the firm capacity commitment FROM this region + available -= sum( + value(model.capacity_credit[r1r2, p, t, v]) + * model.v_capacity[r1r2, p, t, v] + * value(model.capacity_to_activity[r1r2, t]) + * value(model.segment_fraction[p, s, d]) + for (t, v) in model.process_reserve_periods[r1r2, p] + ) return available From ea6ae3b9cb6b538e4bc0cf8df9672f5592287d47 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Sun, 8 Mar 2026 19:26:59 -0400 Subject: [PATCH 490/587] Nitpicking --- temoa/components/reserves.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/temoa/components/reserves.py b/temoa/components/reserves.py index 3708faae6..2b60c9bbd 100644 --- a/temoa/components/reserves.py +++ b/temoa/components/reserves.py @@ -147,6 +147,7 @@ def reserve_margin_dynamic( # Only consider exchange technologies connecting to this region if r2 == r: # Add the firm capacity commitment TO this region + # (this region was guaranteed an import of power) available += sum( model.v_capacity[r1r2, p, t, v] * value(model.reserve_capacity_derate[r1r2, p, s, t, v]) @@ -155,8 +156,9 @@ def reserve_margin_dynamic( * value(model.segment_fraction[p, s, d]) for (t, v) in model.process_reserve_periods[r1r2, p] ) - if r1 == r: + elif r1 == r: # Subtract the firm capacity commitment FROM this region + # (this region guaranteed an export of power) available -= sum( model.v_capacity[r1r2, p, t, v] * value(model.reserve_capacity_derate[r1r2, p, s, t, v]) @@ -240,6 +242,7 @@ def reserve_margin_static( # Only consider exchange technologies connecting to this region if r2 == r: # Add the firm capacity commitment TO this region + # (this region was guaranteed an import of power) available += sum( value(model.capacity_credit[r1r2, p, t, v]) * model.v_capacity[r1r2, p, t, v] @@ -247,8 +250,9 @@ def reserve_margin_static( * value(model.segment_fraction[p, s, d]) for (t, v) in model.process_reserve_periods[r1r2, p] ) - if r1 == r: + elif r1 == r: # Subtract the firm capacity commitment FROM this region + # (this region guaranteed an export of power) available -= sum( value(model.capacity_credit[r1r2, p, t, v]) * model.v_capacity[r1r2, p, t, v] From f32afa69658a72b50bf1e4e46ebe4f9be6365659 Mon Sep 17 00:00:00 2001 From: SutubraResearch Date: Wed, 11 Mar 2026 14:27:30 -0300 Subject: [PATCH 491/587] Fix limit_capacity_constraint missing index check The constraint index function did not verify that the (region, period, tech) tuple existed in the relevant capacity sets before building indices. This caused a KeyError when a technology appeared in MaxCapacity or MinCapacity but had no active vintages in the current optimization window. --- temoa/components/limits.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/temoa/components/limits.py b/temoa/components/limits.py index baa4b0428..6a12ea29b 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -1383,7 +1383,10 @@ def limit_capacity_constraint( techs = technology.gather_group_techs(model, t) cap_lim = value(model.limit_capacity[r, p, t, op]) capacity = quicksum( - model.v_capacity_available_by_period_and_tech[_r, p, _t] for _t in techs for _r in regions + model.v_capacity_available_by_period_and_tech[_r, p, _t] + for _t in techs + for _r in regions + if (_r, p, _t) in model.process_vintages ) expr = operator_expression(capacity, Operator(op), cap_lim) return expr From 278a0c997b7b0b4a61e651882858da46954dd4b2 Mon Sep 17 00:00:00 2001 From: SutubraResearch Date: Wed, 11 Mar 2026 14:27:41 -0300 Subject: [PATCH 492/587] Fix loan_lifetime_process KeyError in myopic mode In myopic window 2+, previously optimized vintages remain active in myopic_efficiency but were excluded from loan_lifetime_process by the v >= min(vintage_optimize) filter. This caused a KeyError during Pyomo param construction when filtered data included those vintages. Remove the min_period filter to match lifetime_process_indices, which already accepts all efficiency vintages without restriction. --- temoa/components/costs.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/temoa/components/costs.py b/temoa/components/costs.py index a4647e64c..cd22729cc 100644 --- a/temoa/components/costs.py +++ b/temoa/components/costs.py @@ -113,13 +113,14 @@ def cost_variable_indices(model: TemoaModel) -> set[tuple[Region, Period, Techno def lifetime_loan_process_indices(model: TemoaModel) -> set[tuple[Region, Technology, Vintage]]: """ - Based on the efficiency parameter's indices and time_future parameter, this - function returns the set of process indices that may be specified in the - cost_invest parameter. - """ - min_period = min(model.vintage_optimize) + Based on the efficiency parameter's indices, this function returns the set of + process indices that may be specified in the loan_lifetime_process parameter. - indices = {(r, t, v) for r, i, t, v, o in model.efficiency.sparse_iterkeys() if v >= min_period} + Note: We include all efficiency vintages (not just >= min optimization period) + because in myopic mode, previously optimized vintages remain active in later + windows and their data must be accepted by the param's index set. + """ + indices = {(r, t, v) for r, i, t, v, o in model.efficiency.sparse_iterkeys()} return indices From 6060e6a3290a8f3f9180eb53affbace6142b5ea0 Mon Sep 17 00:00:00 2001 From: SutubraResearch Date: Wed, 11 Mar 2026 14:29:56 -0300 Subject: [PATCH 493/587] Disable season ramp constraints for seasonal_timeslices In seasonal_timeslices mode, seasons are not temporally adjacent so inter-season ramp constraints are not meaningful. Previously only consecutive_days mode skipped these constraints. Add seasonal_timeslices to the skip condition in both ramp_up and ramp_down season constraint index functions. Update test expectations: mediumville constraint count drops by 8 (4 ramp_up + 4 ramp_down). Regenerate set cache files to reflect expanded loan_lifetime_process_rtv from the earlier fix. --- temoa/components/operations.py | 4 ++-- tests/legacy_test_values.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/temoa/components/operations.py b/temoa/components/operations.py index ee11f26c8..67c475acd 100644 --- a/temoa/components/operations.py +++ b/temoa/components/operations.py @@ -74,7 +74,7 @@ def ramp_down_day_constraint_indices( def ramp_up_season_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Season, Season, Technology, Vintage]]: - if model.time_sequencing.first() == 'consecutive_days': + if model.time_sequencing.first() in ('consecutive_days', 'seasonal_timeslices'): return set() # s, s_next indexing ensures we dont build redundant constraints @@ -94,7 +94,7 @@ def ramp_up_season_constraint_indices( def ramp_down_season_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Season, Season, Technology, Vintage]]: - if model.time_sequencing.first() == 'consecutive_days': + if model.time_sequencing.first() in ('consecutive_days', 'seasonal_timeslices'): return set() # s, s_next indexing ensures we dont build redundant constraints diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index 2223cdb78..aacfd3d50 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -71,7 +71,8 @@ class ExpectedVals(Enum): # increased 2025/08/19 after making annual demands optional # increased by 2 after tying v_storage_level[d_last] to v_storage_init # reduced by 10 after dropping DAC for single-tech demands - ExpectedVals.CONSTR_COUNT: 232, + # reduced by 8 after disabling season ramp for seasonal_timeslices + ExpectedVals.CONSTR_COUNT: 224, # reduced 2025/07/25 by 18 after annualising demands # increased 2025/08/19 after making annual demands optional # increased by 2 after adding v_storage_init variable From 598c0fb99996724b7fb8f4a5aaef9be8797cd8cd Mon Sep 17 00:00:00 2001 From: SutubraResearch Date: Wed, 18 Mar 2026 12:02:29 -0300 Subject: [PATCH 494/587] Add bool guards to limit capacity constraints and sync schema FK --- data_files/temoa_schema_v4.sql | 2 +- temoa/components/limits.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/data_files/temoa_schema_v4.sql b/data_files/temoa_schema_v4.sql index 8efedde67..2019e7f0b 100644 --- a/data_files/temoa_schema_v4.sql +++ b/data_files/temoa_schema_v4.sql @@ -708,7 +708,7 @@ CREATE TABLE IF NOT EXISTS output_curtailment period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES time_period (period), + REFERENCES season_label (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT diff --git a/temoa/components/limits.py b/temoa/components/limits.py index 6a12ea29b..d9b47f785 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -1361,6 +1361,8 @@ def limit_new_capacity_constraint( cap_lim = value(model.limit_new_capacity[r, p, t, op]) new_cap = quicksum(model.v_new_capacity[_r, _t, p] for _t in techs for _r in regions) expr = operator_expression(new_cap, Operator(op), cap_lim) + if isinstance(expr, bool): + return Constraint.Skip return expr @@ -1389,6 +1391,8 @@ def limit_capacity_constraint( if (_r, p, _t) in model.process_vintages ) expr = operator_expression(capacity, Operator(op), cap_lim) + if isinstance(expr, bool): + return Constraint.Skip return expr From 527e008ab7d439df7a528dce6b8c94482d516b06 Mon Sep 17 00:00:00 2001 From: SutubraResearch Date: Wed, 18 Mar 2026 13:52:17 -0300 Subject: [PATCH 495/587] Add comment explaining seasonal_timeslices ramp skip --- temoa/components/operations.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/temoa/components/operations.py b/temoa/components/operations.py index 67c475acd..bcfe03563 100644 --- a/temoa/components/operations.py +++ b/temoa/components/operations.py @@ -74,6 +74,8 @@ def ramp_down_day_constraint_indices( def ramp_up_season_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Season, Season, Technology, Vintage]]: + # Season-to-season ramp constraints require full inter-season ordering; + # skip for consecutive_days (no season links) and seasonal_timeslices (no TOD ordering). if model.time_sequencing.first() in ('consecutive_days', 'seasonal_timeslices'): return set() @@ -94,6 +96,8 @@ def ramp_up_season_constraint_indices( def ramp_down_season_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Season, Season, Technology, Vintage]]: + # Season-to-season ramp constraints require full inter-season ordering; + # skip for consecutive_days (no season links) and seasonal_timeslices (no TOD ordering). if model.time_sequencing.first() in ('consecutive_days', 'seasonal_timeslices'): return set() From 0b0c68f23fdac404ee263484664b7a5df2566552 Mon Sep 17 00:00:00 2001 From: SutubraResearch Date: Fri, 20 Mar 2026 16:23:27 -0300 Subject: [PATCH 496/587] Update JSON set caches for bug-fix changes Expand loan_lifetime_process_rtv for utopia (+15) and test_system (+4) after KeyError fix. Remove season ramp indices from mediumville after disabling season ramps for seasonal_timeslices. Adjust mediumville constraint count to 224 (accounting for storage-init, DAC, and season ramp changes). --- tests/testing_data/mediumville_sets.json | 70 +--------------------- tests/testing_data/test_system_sets.json | 20 +++++++ tests/testing_data/utopia_sets.json | 75 ++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 68 deletions(-) diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 2c07b6ba6..5c406fed8 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -3788,40 +3788,7 @@ 2025 ] ], - "ramp_down_season_constraint_rpsstv": [ - [ - "A", - 2025, - "s1", - "s2", - "EH", - 2025 - ], - [ - "A", - 2025, - "s2", - "s1", - "EH", - 2025 - ], - [ - "B", - 2025, - "s1", - "s2", - "EH", - 2025 - ], - [ - "B", - 2025, - "s2", - "s1", - "EH", - 2025 - ] - ], + "ramp_down_season_constraint_rpsstv": [], "ramp_up_day_constraint_rpsdtv": [ [ "B", @@ -3888,40 +3855,7 @@ 2025 ] ], - "ramp_up_season_constraint_rpsstv": [ - [ - "A", - 2025, - "s1", - "s2", - "EH", - 2025 - ], - [ - "A", - 2025, - "s2", - "s1", - "EH", - 2025 - ], - [ - "B", - 2025, - "s1", - "s2", - "EH", - 2025 - ], - [ - "B", - 2025, - "s2", - "s1", - "EH", - 2025 - ] - ], + "ramp_up_season_constraint_rpsstv": [], "regional_exchange_capacity_constraint_rrptv": [ [ "B", diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index df2014de8..17bb457e0 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -42293,6 +42293,26 @@ "R1", "S_OILREF", 2020 + ], + [ + "R1", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + "E_NUCLEAR", + 2015 + ], + [ + "R1-R2", + "E_TRANS", + 2015 + ], + [ + "R2-R1", + "E_TRANS", + 2015 ] ], "new_capacity_var_rtv": [ diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 8be5f4a31..77181f167 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -23130,6 +23130,81 @@ "utopia", "RL1", 2000 + ], + [ + "utopia", + "E01", + 1960 + ], + [ + "utopia", + "E01", + 1970 + ], + [ + "utopia", + "E01", + 1980 + ], + [ + "utopia", + "E70", + 1960 + ], + [ + "utopia", + "E70", + 1970 + ], + [ + "utopia", + "E70", + 1980 + ], + [ + "utopia", + "RHO", + 1970 + ], + [ + "utopia", + "RHO", + 1980 + ], + [ + "utopia", + "TXG", + 1970 + ], + [ + "utopia", + "TXG", + 1980 + ], + [ + "utopia", + "TXD", + 1970 + ], + [ + "utopia", + "TXD", + 1980 + ], + [ + "utopia", + "E31", + 1980 + ], + [ + "utopia", + "E51", + 1980 + ], + [ + "utopia", + "RL1", + 1980 ] ], "new_capacity_var_rtv": [ From 74357b53a7436ea6051446a6635185ca1d076a24 Mon Sep 17 00:00:00 2001 From: SutubraResearch Date: Fri, 20 Mar 2026 16:35:58 -0300 Subject: [PATCH 497/587] Guard limit_capacity against tech_uncap KeyError Use v_capacity_available_by_period_and_tech (which excludes tech_uncap) as the membership check instead of process_vintages (which includes them). Prevents KeyError when a capacity group contains uncapacitated technologies. --- temoa/components/limits.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/temoa/components/limits.py b/temoa/components/limits.py index d9b47f785..3f55985af 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -1388,7 +1388,7 @@ def limit_capacity_constraint( model.v_capacity_available_by_period_and_tech[_r, p, _t] for _t in techs for _r in regions - if (_r, p, _t) in model.process_vintages + if (_r, p, _t) in model.v_capacity_available_by_period_and_tech ) expr = operator_expression(capacity, Operator(op), cap_lim) if isinstance(expr, bool): From 2f0bc0de365de709bca7d5676ebd4abe1cd0a358 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 20 Mar 2026 20:12:50 -0400 Subject: [PATCH 498/587] Fix botched merge resolve --- temoa/components/limits.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/temoa/components/limits.py b/temoa/components/limits.py index b0b437a68..ac457a04e 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -1420,11 +1420,7 @@ def limit_capacity_constraint( model.v_capacity_available_by_period_and_tech[_r, p, _t] for _t in techs for _r in regions -<<<<<<< rework/vintage_limit_tables - if (_r, p, _t) in model.process_vintages -======= if (_r, p, _t) in model.v_capacity_available_by_period_and_tech ->>>>>>> unstable ) expr = operator_expression(capacity, Operator(op), cap_lim) if isinstance(expr, bool): From 782ce76ed212a94352bc1bcdaf0272aa0b79b6d0 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 20 Mar 2026 20:25:44 -0400 Subject: [PATCH 499/587] Add to rpt validation set from silent_rptv --- temoa/model_checking/commodity_network_manager.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/temoa/model_checking/commodity_network_manager.py b/temoa/model_checking/commodity_network_manager.py index f578e61e8..75afc3900 100644 --- a/temoa/model_checking/commodity_network_manager.py +++ b/temoa/model_checking/commodity_network_manager.py @@ -161,8 +161,10 @@ def build_filters(self, tech_groups: defaultdict[str, set[str]]) -> dict[str, Vi valid_elements['rpto'].add( (edge_tuple.region, p, tech_group, edge_tuple.output_comm) ) + # Good processes that we dont want in the network diagram - for r, _p, t, v in self.orig_data.silent_rptv: + for r, p, t, v in self.orig_data.silent_rptv: + valid_elements['rpt'].add((r, p, t)) valid_elements['rtv'].add((r, t, v)) valid_elements['rt'].add((r, t)) valid_elements['t'].add(t) From 026b22ab5d756e591925b1f209ea055989b7d4ae Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 20 Mar 2026 20:29:32 -0400 Subject: [PATCH 500/587] Update docstring for variable change --- temoa/components/limits.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/temoa/components/limits.py b/temoa/components/limits.py index ac457a04e..ff806e286 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -471,12 +471,12 @@ def limit_annual_capacity_factor_constraint( :label: limit_annual_capacity_factor \sum_{S,D,I} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMACF_{r, t, v, o} \cdot - \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} + \textbf{CAP}_{r, p, t, v} \cdot \text{C2A}_{r, t} \forall \{r, t \notin T^{a}, v, o\} \in \Theta_{\text{limit\_annual\_capacity\_factor}} \\\sum_{I} \textbf{FOA}_{r, p, i, t, v, o} \ge LIMACF_{r, t, v, o} \cdot - \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} + \textbf{CAP}_{r, p, t, v} \cdot \text{C2A}_{r, t} \forall \{r, t \in T^{a}, v, o\} \in \Theta_{\text{limit\_annual\_capacity\_factor}} """ From dfe5d4955704a468b4b8c4dd60185efa92dc5c6d Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Fri, 20 Mar 2026 20:36:08 -0400 Subject: [PATCH 501/587] Fix myopicindex type for evolution script runner --- temoa/extensions/myopic/myopic_sequencer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index 927a9bdf0..59f78ea87 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -359,7 +359,7 @@ def initialize_myopic_efficiency_table(self): def run_evolution_script( self, - idx: int | None, + idx: MyopicIndex | None, last_base_year: int | None, last_instance_status: str | None, con: sqlite3.Connection | None @@ -371,7 +371,7 @@ def run_evolution_script( if not self.evolution_script: logger.warning('Evolving myopic mode selected, but no evolution script provided.') return - + # import the script as a module and call the iterate function script_path = Path(self.evolution_script).expanduser() if not script_path.is_file(): From a88c972a9975799d645f1615934a387c975d54b7 Mon Sep 17 00:00:00 2001 From: idelder <35704891+idelder@users.noreply.github.com> Date: Mon, 23 Mar 2026 20:53:43 -0400 Subject: [PATCH 502/587] Rework the definition of seasons (#264) * Move days_per_period parameter to config * Remove days_per_period from all sql files * First pass at removing period index on seasons * Update test sets for removal of period indexed seasons * Remove period index from time_next dicts * Update time_manual to remove period index * Remove period index from several tables * Update test_system legacy values for more storage frac constraints * Remove season_label table * Change time_season_sequential pk to only seas_seq * Fix ramp rate constraints to adjust limit to hourly output * Add hours column to time_of_day * Move segment_fraction definition to season tables * Fix sequencing of model construction for time params * Update seasonal storage season weight adjustment * Update test values for new seg_frac definition as no longer rounded * Fix two bugs in new season_seq definition * Remove erroneous fk from limit_storage_level_fraction * Update hours column of time_of_day to REAL not INTEGER * Reinforce 0 to 1 constraint on segfrac * Remove erroneous season fk from output_storage_level * Fix season fk in output_curtailment * Fix storage fraction constraints in example dbs * Fix 0 to 1 constraint on segment fractions * Fix index construction for limit_storage_level_fraction and add proper checks * Remove period from deprecated cfp check * Update unit cost explorer tool * Update sql data validation * Add 0 to 1 sql check on limit_storage_level_fraction * Change some param domains to PositiveReals to avoid divide-by-zero errors * Make time_of_day consistent with test sql style * Remove redundant time_season entries from survival_curve test sql * Change INSERT to REPLACE in time_of_day for utopia test * Make sequence column unique in season tables * Update data_files temoa_schema_v4 * adapting migrator to changes in v4 schema and adding test for migration * Rename time_season_sequential and remove unneeded season index * Rename time_season_to_sequential (name was wrong) * Add sequence ordering to critical ordered time sets in loading --- data_files/example_dbs/materials.sql | 433 +-- data_files/example_dbs/morris_utopia.sql | 328 +- data_files/example_dbs/seasonal_storage.sql | 199 +- data_files/example_dbs/stepped_demand.sql | 151 +- data_files/example_dbs/survival_curve.sql | 117 +- data_files/example_dbs/test_system.sql | 281 +- data_files/example_dbs/utopia.sql | 328 +- data_files/my_configs/config_sample.toml | 5 + data_files/my_configs/materials.toml | 5 + data_files/my_configs/mga_utopia.toml | 5 + data_files/my_configs/monte_carlo_utopia.toml | 5 + data_files/my_configs/morris_utopia.toml | 5 + data_files/my_configs/seasonal_storage.toml | 5 + data_files/my_configs/stepped_demand.toml | 5 + data_files/temoa_basics_1.sql | 2 - data_files/temoa_basics_2.sql | 2 - data_files/temoa_schema_v3_1.sql | 2 - data_files/temoa_schema_v4.sql | 108 +- temoa/_internal/exchange_tech_cost_ledger.py | 4 +- temoa/_internal/table_data_puller.py | 30 +- temoa/components/capacity.py | 88 +- temoa/components/commodities.py | 86 +- temoa/components/costs.py | 4 +- temoa/components/emissions.py | 10 +- temoa/components/flows.py | 15 +- temoa/components/limits.py | 45 +- temoa/components/operations.py | 104 +- temoa/components/reserves.py | 36 +- temoa/components/storage.py | 85 +- temoa/components/technology.py | 25 +- temoa/components/time.py | 276 +- temoa/components/utils.py | 6 +- temoa/core/config.py | 3 + temoa/core/model.py | 101 +- temoa/data_io/component_manifest.py | 75 +- temoa/data_io/hybrid_loader.py | 84 +- temoa/data_io/loader_manifest.py | 1 + temoa/db_schema/temoa_schema_v3_1.sql | 2 - temoa/db_schema/temoa_schema_v4.sql | 108 +- temoa/extensions/myopic/evolution_updater.py | 9 +- .../myopic/myopic_progress_mapper.py | 2 +- .../single_vector_mga/sv_mga_sequencer.py | 2 +- temoa/model_checking/validators.py | 4 +- temoa/tutorial_assets/config_sample.toml | 9 +- temoa/tutorial_assets/utopia.sql | 347 +- temoa/types/dict_types.py | 10 +- temoa/utilities/db_migration_v3_1_to_v4.py | 102 +- temoa/utilities/sql_migration_v3_1_to_v4.py | 114 +- temoa/utilities/unit_cost_explorer.py | 19 +- tests/legacy_test_values.py | 9 +- tests/test_exchange_cost_ledger.py | 2 +- tests/test_full_runs.py | 6 +- tests/test_myopic_sequencer.py | 28 +- tests/test_storage.py | 7 +- tests/test_v4_migration.py | 105 + .../config_annualised_demand.toml | 1 + tests/testing_configs/config_emissions.toml | 1 + tests/testing_configs/config_link_test.toml | 1 + tests/testing_configs/config_materials.toml | 1 + tests/testing_configs/config_mediumville.toml | 1 + .../config_seasonal_storage.toml | 1 + .../testing_configs/config_storageville.toml | 1 + .../config_survival_curve.toml | 1 + tests/testing_configs/config_test_system.toml | 1 + tests/testing_configs/config_utopia.toml | 1 + tests/testing_configs/config_utopia_gv.toml | 1 + tests/testing_configs/config_utopia_mc.toml | 1 + .../testing_configs/config_utopia_myopic.toml | 1 + .../config_utopia_stochastic.toml | 1 + tests/testing_data/annualised_demand.sql | 6 +- tests/testing_data/emissions.sql | 21 +- tests/testing_data/materials.sql | 205 +- tests/testing_data/mediumville.sql | 55 +- tests/testing_data/mediumville_sets.json | 83 +- tests/testing_data/migration_v3_1_mock.sql | 30 + tests/testing_data/seasonal_storage.sql | 101 +- tests/testing_data/simple_linked_tech.sql | 11 +- tests/testing_data/storageville.sql | 49 +- tests/testing_data/survival_curve.sql | 17 +- tests/testing_data/test_system.sql | 181 +- tests/testing_data/test_system_sets.json | 3364 ++--------------- tests/testing_data/utopia_data.sql | 228 +- tests/testing_data/utopia_sets.json | 1319 +------ 83 files changed, 2239 insertions(+), 7394 deletions(-) create mode 100644 tests/test_v4_migration.py create mode 100644 tests/testing_data/migration_v3_1_mock.sql diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql index 19d8a03b5..da4d7bc08 100644 --- a/data_files/example_dbs/materials.sql +++ b/data_files/example_dbs/materials.sql @@ -15,10 +15,8 @@ CREATE TABLE capacity_credit CREATE TABLE capacity_factor_process ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), tech TEXT @@ -26,121 +24,55 @@ CREATE TABLE capacity_factor_process vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), + PRIMARY KEY (region, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE capacity_factor_tech ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), + PRIMARY KEY (region, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'summer','morning','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'autumn','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'winter','morning','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'spring','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'summer','afternoon','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'autumn','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'winter','afternoon','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'spring','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'summer','evening','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2000,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'summer','morning','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'autumn','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'winter','morning','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'spring','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'summer','afternoon','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'autumn','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'winter','afternoon','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'spring','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'summer','evening','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2010,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'summer','morning','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'autumn','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'winter','morning','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'spring','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'summer','afternoon','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'autumn','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'winter','afternoon','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'spring','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'summer','evening','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA',2020,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'summer','morning','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'autumn','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'winter','morning','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'spring','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'summer','afternoon','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'autumn','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'winter','afternoon','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'spring','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'summer','evening','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2000,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'summer','morning','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'autumn','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'winter','morning','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'spring','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'summer','afternoon','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'autumn','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'winter','afternoon','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'spring','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'summer','evening','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2010,'spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'summer','morning','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'autumn','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'winter','morning','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'spring','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'summer','afternoon','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'autumn','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'winter','afternoon','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'spring','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'summer','evening','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'winter','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'spring','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB',2020,'spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA','summer','morning','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA','autumn','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA','winter','morning','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA','spring','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA','summer','afternoon','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA','autumn','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA','winter','afternoon','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA','spring','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA','summer','evening','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA','autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA','winter','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA','spring','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA','summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA','autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA','winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionA','spring','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB','summer','morning','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB','autumn','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB','winter','morning','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB','spring','morning','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB','summer','afternoon','SOL_PV',0.3,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB','autumn','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB','winter','afternoon','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB','spring','afternoon','SOL_PV',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB','summer','evening','SOL_PV',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB','autumn','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB','winter','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB','spring','evening','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB','summer','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB','autumn','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB','winter','overnight','SOL_PV',0.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('RegionB','spring','overnight','SOL_PV',0.0,NULL); CREATE TABLE capacity_to_activity ( region TEXT, @@ -368,115 +300,49 @@ INSERT INTO "demand" VALUES('RegionB',2020,'heating',1.0,NULL,NULL); CREATE TABLE demand_specific_distribution ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), demand_name TEXT REFERENCES commodity (name), dsd REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), + PRIMARY KEY (region, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'summer','morning','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'autumn','morning','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'winter','morning','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'spring','morning','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'summer','afternoon','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'autumn','afternoon','heating',0.08,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'winter','afternoon','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'spring','afternoon','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'summer','evening','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'autumn','evening','heating',0.08,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'winter','evening','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'spring','evening','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'summer','overnight','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'autumn','overnight','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'winter','overnight','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2000,'spring','overnight','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'summer','morning','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'autumn','morning','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'winter','morning','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'spring','morning','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'summer','afternoon','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'autumn','afternoon','heating',0.08,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'winter','afternoon','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'spring','afternoon','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'summer','evening','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'autumn','evening','heating',0.08,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'winter','evening','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'spring','evening','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'summer','overnight','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'autumn','overnight','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'winter','overnight','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2010,'spring','overnight','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'summer','morning','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'autumn','morning','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'winter','morning','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'spring','morning','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'summer','afternoon','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'autumn','afternoon','heating',0.08,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'winter','afternoon','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'spring','afternoon','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'summer','evening','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'autumn','evening','heating',0.08,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'winter','evening','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'spring','evening','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'summer','overnight','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'autumn','overnight','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'winter','overnight','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA',2020,'spring','overnight','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'summer','morning','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'autumn','morning','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'winter','morning','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'spring','morning','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'summer','afternoon','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'autumn','afternoon','heating',0.08,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'winter','afternoon','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'spring','afternoon','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'summer','evening','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'autumn','evening','heating',0.08,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'winter','evening','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'spring','evening','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'summer','overnight','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'autumn','overnight','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'winter','overnight','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2000,'spring','overnight','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'summer','morning','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'autumn','morning','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'winter','morning','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'spring','morning','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'summer','afternoon','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'autumn','afternoon','heating',0.08,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'winter','afternoon','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'spring','afternoon','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'summer','evening','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'autumn','evening','heating',0.08,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'winter','evening','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'spring','evening','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'summer','overnight','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'autumn','overnight','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'winter','overnight','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2010,'spring','overnight','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'summer','morning','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'autumn','morning','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'winter','morning','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'spring','morning','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'summer','afternoon','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'autumn','afternoon','heating',0.08,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'winter','afternoon','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'spring','afternoon','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'summer','evening','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'autumn','evening','heating',0.08,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'winter','evening','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'spring','evening','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'summer','overnight','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'autumn','overnight','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'winter','overnight','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB',2020,'spring','overnight','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA','summer','morning','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA','autumn','morning','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA','winter','morning','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA','spring','morning','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA','summer','afternoon','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA','autumn','afternoon','heating',0.08,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA','winter','afternoon','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA','spring','afternoon','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA','summer','evening','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA','autumn','evening','heating',0.08,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA','winter','evening','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA','spring','evening','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA','summer','overnight','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA','autumn','overnight','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA','winter','overnight','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionA','spring','overnight','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB','summer','morning','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB','autumn','morning','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB','winter','morning','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB','spring','morning','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB','summer','afternoon','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB','autumn','afternoon','heating',0.08,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB','winter','afternoon','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB','spring','afternoon','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB','summer','evening','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB','autumn','evening','heating',0.08,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB','winter','evening','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB','spring','evening','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB','summer','overnight','heating',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB','autumn','overnight','heating',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB','winter','overnight','heating',0.16,NULL); +INSERT INTO "demand_specific_distribution" VALUES('RegionB','spring','overnight','heating',0.0,NULL); CREATE TABLE efficiency ( region TEXT, @@ -574,10 +440,8 @@ INSERT INTO "efficiency" VALUES('RegionB-RegionA','electricity','ELEC_INTERTIE', CREATE TABLE efficiency_variable ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -590,7 +454,7 @@ CREATE TABLE efficiency_variable REFERENCES commodity (name), efficiency REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + PRIMARY KEY (region, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); CREATE TABLE emission_activity @@ -936,36 +800,30 @@ CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), factor REAL, notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) + PRIMARY KEY(region, season, tech, operator) ); CREATE TABLE limit_storage_level_fraction ( region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), + season TEXT, tod TEXT REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), fraction REAL, notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) + CHECK (fraction >= 0 AND fraction <= 1), + PRIMARY KEY(region, season, tod, tech, operator) ); CREATE TABLE limit_tech_input_split ( @@ -1122,7 +980,6 @@ CREATE TABLE metadata notes TEXT, PRIMARY KEY (element) ); -INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); INSERT INTO "metadata" VALUES('DB_MINOR',0,''); CREATE TABLE metadata_real @@ -1198,7 +1055,7 @@ CREATE TABLE output_curtailment period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES time_period (period), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -1245,7 +1102,7 @@ CREATE TABLE output_flow_in period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -1268,7 +1125,7 @@ CREATE TABLE output_flow_out period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -1342,8 +1199,7 @@ CREATE TABLE output_storage_level REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), + season TEXT, tod TEXT REFERENCES time_of_day (tod), tech TEXT @@ -1390,16 +1246,14 @@ INSERT INTO "region" VALUES('RegionB',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tech TEXT REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tech, vintage), + PRIMARY KEY (region, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE rps_requirement @@ -1413,15 +1267,6 @@ CREATE TABLE rps_requirement requirement REAL NOT NULL, notes TEXT ); -CREATE TABLE season_label -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "season_label" VALUES('summer',NULL); -INSERT INTO "season_label" VALUES('autumn',NULL); -INSERT INTO "season_label" VALUES('winter',NULL); -INSERT INTO "season_label" VALUES('spring',NULL); CREATE TABLE sector_label ( sector TEXT PRIMARY KEY, @@ -1501,12 +1346,15 @@ CREATE TABLE time_of_day ( sequence INTEGER UNIQUE, tod TEXT - PRIMARY KEY + PRIMARY KEY, + hours REAL NOT NULL DEFAULT 1, + notes TEXT, + CHECK (hours > 0) ); -INSERT INTO "time_of_day" VALUES(1,'morning'); -INSERT INTO "time_of_day" VALUES(2,'afternoon'); -INSERT INTO "time_of_day" VALUES(3,'evening'); -INSERT INTO "time_of_day" VALUES(4,'overnight'); +INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(1,'morning',6); +INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(2,'afternoon',6); +INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(3,'evening',6); +INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(4,'overnight',6); CREATE TABLE time_period ( sequence INTEGER UNIQUE, @@ -1530,97 +1378,28 @@ INSERT INTO "time_period_type" VALUES('e','existing vintages'); INSERT INTO "time_period_type" VALUES('f','future'); CREATE TABLE time_season ( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - season TEXT REFERENCES season_label(season), + sequence INTEGER UNIQUE, + season TEXT, + segment_fraction REAL NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, season) -); -INSERT INTO "time_season" VALUES(2000,1,'summer',NULL); -INSERT INTO "time_season" VALUES(2000,2,'autumn',NULL); -INSERT INTO "time_season" VALUES(2000,3,'winter',NULL); -INSERT INTO "time_season" VALUES(2000,4,'spring',NULL); -INSERT INTO "time_season" VALUES(2010,5,'summer',NULL); -INSERT INTO "time_season" VALUES(2010,6,'autumn',NULL); -INSERT INTO "time_season" VALUES(2010,7,'winter',NULL); -INSERT INTO "time_season" VALUES(2010,8,'spring',NULL); -INSERT INTO "time_season" VALUES(2020,9,'summer',NULL); -INSERT INTO "time_season" VALUES(2020,10,'autumn',NULL); -INSERT INTO "time_season" VALUES(2020,11,'winter',NULL); -INSERT INTO "time_season" VALUES(2020,12,'spring',NULL); + PRIMARY KEY (season), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) +); +INSERT INTO "time_season" VALUES(0,'summer',0.25,NULL); +INSERT INTO "time_season" VALUES(1,'autumn',0.25,NULL); +INSERT INTO "time_season" VALUES(2,'winter',0.25,NULL); +INSERT INTO "time_season" VALUES(3,'spring',0.25,NULL); CREATE TABLE time_season_sequential ( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, + sequence INTEGER UNIQUE, seas_seq TEXT, - season TEXT REFERENCES season_label(season), - num_days REAL NOT NULL, + season TEXT REFERENCES time_season(season), + segment_fraction REAL NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); - -CREATE TABLE time_segment_fraction -( - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - segment_fraction REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), + PRIMARY KEY (seas_seq), CHECK (segment_fraction >= 0 AND segment_fraction <= 1) ); -INSERT INTO "time_segment_fraction" VALUES(2000,'summer','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'autumn','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'winter','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'spring','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'summer','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'autumn','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'winter','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'spring','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'summer','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'autumn','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'winter','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'spring','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'summer','overnight',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'autumn','overnight',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'winter','overnight',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'spring','overnight',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'summer','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'autumn','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'winter','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'spring','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'summer','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'autumn','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'winter','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'spring','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'summer','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'autumn','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'winter','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'spring','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'summer','overnight',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'autumn','overnight',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'winter','overnight',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2010,'spring','overnight',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'summer','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'autumn','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'winter','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'spring','morning',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'summer','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'autumn','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'winter','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'spring','afternoon',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'summer','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'autumn','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'winter','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'spring','evening',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'summer','overnight',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'autumn','overnight',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'winter','overnight',0.0625,NULL); -INSERT INTO "time_segment_fraction" VALUES(2020,'spring','overnight',0.0625,NULL); + CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql index 0ec374ed2..c8e6bf970 100644 --- a/data_files/example_dbs/morris_utopia.sql +++ b/data_files/example_dbs/morris_utopia.sql @@ -15,10 +15,8 @@ CREATE TABLE capacity_credit CREATE TABLE capacity_factor_process ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), tech TEXT @@ -26,133 +24,65 @@ CREATE TABLE capacity_factor_process vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), + PRIMARY KEY (region, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'inter','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'inter','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'winter','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'winter','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'summer','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'summer','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','day','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','night','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','day','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','night','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','day','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','night','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','inter','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','inter','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','winter','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','winter','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','summer','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','summer','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','inter','day','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','inter','night','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','winter','day','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','winter','night','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','summer','day','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','summer','night','E31',2010,0.2756,''); CREATE TABLE capacity_factor_tech ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), + PRIMARY KEY (region, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E70',0.8,''); CREATE TABLE capacity_to_activity ( region TEXT, @@ -468,49 +398,27 @@ INSERT INTO "demand" VALUES('utopia',2010,'TX',11.69,'',''); CREATE TABLE demand_specific_distribution ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), demand_name TEXT REFERENCES commodity (name), dsd REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), + PRIMARY KEY (region, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','night','RH',0.06,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','day','RH',0.5467,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','night','RH',2.73299999999999931e-01,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'summer','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'summer','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','day','RL',0.5,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','night','RL',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','day','RH',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','night','RH',0.06,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','day','RH',0.5467,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','night','RH',2.73299999999999931e-01,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'summer','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'summer','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','day','RL',0.5,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','night','RL',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','day','RH',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','night','RH',0.06,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','day','RH',0.5467,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','night','RH',2.73299999999999931e-01,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'summer','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'summer','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','day','RL',0.5,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','night','RL',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','day','RH',0.12,NULL); +INSERT INTO "demand_specific_distribution" VALUES('utopia','inter','night','RH',0.06,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','winter','day','RH',0.5467,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','winter','night','RH',2.73299999999999931e-01,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','inter','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','inter','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','summer','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','summer','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','winter','day','RL',0.5,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','winter','night','RL',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','inter','day','RH',0.12,NULL); CREATE TABLE efficiency ( region TEXT, @@ -594,10 +502,8 @@ INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',2010,'TX',0.231,'# direct t CREATE TABLE efficiency_variable ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -610,7 +516,7 @@ CREATE TABLE efficiency_variable REFERENCES commodity (name), efficiency REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + PRIMARY KEY (region, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); CREATE TABLE emission_activity @@ -976,36 +882,30 @@ CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), factor REAL, notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) + PRIMARY KEY(region, season, tech, operator) ); CREATE TABLE limit_storage_level_fraction ( region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), + season TEXT, tod TEXT REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), fraction REAL, notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) + CHECK (fraction >= 0 AND fraction <= 1), + PRIMARY KEY(region, season, tod, tech, operator) ); CREATE TABLE limit_tech_input_split ( @@ -1115,7 +1015,6 @@ CREATE TABLE metadata PRIMARY KEY (element) ); INSERT INTO "metadata" VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); -INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); INSERT INTO "metadata" VALUES('DB_MINOR',0,''); CREATE TABLE metadata_real @@ -1191,7 +1090,7 @@ CREATE TABLE output_curtailment period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES time_period (period), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -1238,7 +1137,7 @@ CREATE TABLE output_flow_in period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -1261,7 +1160,7 @@ CREATE TABLE output_flow_out period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -1335,8 +1234,7 @@ CREATE TABLE output_storage_level REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), + season TEXT, tod TEXT REFERENCES time_of_day (tod), tech TEXT @@ -1382,16 +1280,14 @@ INSERT INTO "region" VALUES('utopia',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tech TEXT REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tech, vintage), + PRIMARY KEY (region, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE rps_requirement @@ -1405,14 +1301,6 @@ CREATE TABLE rps_requirement requirement REAL NOT NULL, notes TEXT ); -CREATE TABLE season_label -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "season_label" VALUES('inter',NULL); -INSERT INTO "season_label" VALUES('summer',NULL); -INSERT INTO "season_label" VALUES('winter',NULL); CREATE TABLE sector_label ( sector TEXT PRIMARY KEY, @@ -1496,10 +1384,13 @@ CREATE TABLE time_of_day ( sequence INTEGER UNIQUE, tod TEXT - PRIMARY KEY + PRIMARY KEY, + hours REAL NOT NULL DEFAULT 1, + notes TEXT, + CHECK (hours > 0) ); -INSERT INTO "time_of_day" VALUES(1,'day'); -INSERT INTO "time_of_day" VALUES(2,'night'); +INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(1,'day',16); +INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(2,'night',8); CREATE TABLE time_period ( sequence INTEGER UNIQUE, @@ -1525,64 +1416,27 @@ INSERT INTO "time_period_type" VALUES('e','existing vintages'); INSERT INTO "time_period_type" VALUES('f','future'); CREATE TABLE time_season ( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - season TEXT REFERENCES season_label(season), + sequence INTEGER UNIQUE, + season TEXT, + segment_fraction REAL NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, season) -); -INSERT INTO "time_season" VALUES(1990,2,'summer',NULL); -INSERT INTO "time_season" VALUES(1990,3,'winter',NULL); -INSERT INTO "time_season" VALUES(1990,1,'inter',NULL); -INSERT INTO "time_season" VALUES(2000,2,'summer',NULL); -INSERT INTO "time_season" VALUES(2000,3,'winter',NULL); -INSERT INTO "time_season" VALUES(2000,1,'inter',NULL); -INSERT INTO "time_season" VALUES(2010,2,'summer',NULL); -INSERT INTO "time_season" VALUES(2010,3,'winter',NULL); -INSERT INTO "time_season" VALUES(2010,1,'inter',NULL); + PRIMARY KEY (season), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) +); +INSERT INTO "time_season" VALUES(0,'summer',0.25,NULL); +INSERT INTO "time_season" VALUES(1,'winter',0.5,NULL); +INSERT INTO "time_season" VALUES(2,'inter',0.25,NULL); CREATE TABLE time_season_sequential ( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, + sequence INTEGER UNIQUE, seas_seq TEXT, - season TEXT REFERENCES season_label(season), - num_days REAL NOT NULL, + season TEXT REFERENCES time_season(season), + segment_fraction REAL NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); - -CREATE TABLE time_segment_fraction -( - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - segment_fraction REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), + PRIMARY KEY (seas_seq), CHECK (segment_fraction >= 0 AND segment_fraction <= 1) ); -INSERT INTO "time_segment_fraction" VALUES(1990,'inter','day',0.1667,'# I-D'); -INSERT INTO "time_segment_fraction" VALUES(1990,'inter','night',0.0833,'# I-N'); -INSERT INTO "time_segment_fraction" VALUES(1990,'summer','day',0.1667,'# S-D'); -INSERT INTO "time_segment_fraction" VALUES(1990,'summer','night',0.0833,'# S-N'); -INSERT INTO "time_segment_fraction" VALUES(1990,'winter','day',0.3333,'# W-D'); -INSERT INTO "time_segment_fraction" VALUES(1990,'winter','night',0.1667,'# W-N'); -INSERT INTO "time_segment_fraction" VALUES(2000,'inter','day',0.1667,'# I-D'); -INSERT INTO "time_segment_fraction" VALUES(2000,'inter','night',0.0833,'# I-N'); -INSERT INTO "time_segment_fraction" VALUES(2000,'summer','day',0.1667,'# S-D'); -INSERT INTO "time_segment_fraction" VALUES(2000,'summer','night',0.0833,'# S-N'); -INSERT INTO "time_segment_fraction" VALUES(2000,'winter','day',0.3333,'# W-D'); -INSERT INTO "time_segment_fraction" VALUES(2000,'winter','night',0.1667,'# W-N'); -INSERT INTO "time_segment_fraction" VALUES(2010,'inter','day',0.1667,'# I-D'); -INSERT INTO "time_segment_fraction" VALUES(2010,'inter','night',0.0833,'# I-N'); -INSERT INTO "time_segment_fraction" VALUES(2010,'summer','day',0.1667,'# S-D'); -INSERT INTO "time_segment_fraction" VALUES(2010,'summer','night',0.0833,'# S-N'); -INSERT INTO "time_segment_fraction" VALUES(2010,'winter','day',0.3333,'# W-D'); -INSERT INTO "time_segment_fraction" VALUES(2010,'winter','night',0.1667,'# W-N'); + CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql index 5bd5b3710..68da03a75 100644 --- a/data_files/example_dbs/seasonal_storage.sql +++ b/data_files/example_dbs/seasonal_storage.sql @@ -15,10 +15,8 @@ CREATE TABLE capacity_credit CREATE TABLE capacity_factor_process ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), tech TEXT @@ -26,33 +24,31 @@ CREATE TABLE capacity_factor_process vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), + PRIMARY KEY (region, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE capacity_factor_tech ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), + PRIMARY KEY (region, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO "capacity_factor_tech" VALUES('region',2000,'charge','a','generator',1.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('region',2000,'charge','b','generator',1.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('region',2000,'charge','c','generator',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('region',2000,'charge','d','generator',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('region',2000,'discharge','a','generator',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('region',2000,'discharge','b','generator',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('region',2000,'discharge','c','generator',0.01,NULL); -INSERT INTO "capacity_factor_tech" VALUES('region',2000,'discharge','d','generator',0.01,NULL); +INSERT INTO "capacity_factor_tech" VALUES('region','charge','a','generator',1.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('region','charge','b','generator',1.0,NULL); +INSERT INTO "capacity_factor_tech" VALUES('region','charge','c','generator',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('region','charge','d','generator',0.2,NULL); +INSERT INTO "capacity_factor_tech" VALUES('region','discharge','a','generator',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('region','discharge','b','generator',0.1,NULL); +INSERT INTO "capacity_factor_tech" VALUES('region','discharge','c','generator',0.01,NULL); +INSERT INTO "capacity_factor_tech" VALUES('region','discharge','d','generator',0.01,NULL); CREATE TABLE capacity_to_activity ( region TEXT, @@ -179,27 +175,25 @@ INSERT INTO "demand" VALUES('region',2000,'demand',8760.0,'MWh',NULL); CREATE TABLE demand_specific_distribution ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), demand_name TEXT REFERENCES commodity (name), dsd REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), + PRIMARY KEY (region, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO "demand_specific_distribution" VALUES('region',2000,'charge','a','demand',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('region',2000,'charge','b','demand',0.05,NULL); -INSERT INTO "demand_specific_distribution" VALUES('region',2000,'charge','c','demand',0.05,NULL); -INSERT INTO "demand_specific_distribution" VALUES('region',2000,'charge','d','demand',0.1,NULL); -INSERT INTO "demand_specific_distribution" VALUES('region',2000,'discharge','a','demand',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('region',2000,'discharge','b','demand',0.2,NULL); -INSERT INTO "demand_specific_distribution" VALUES('region',2000,'discharge','c','demand',0.2,NULL); -INSERT INTO "demand_specific_distribution" VALUES('region',2000,'discharge','d','demand',0.4,NULL); +INSERT INTO "demand_specific_distribution" VALUES('region','charge','a','demand',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('region','charge','b','demand',0.05,NULL); +INSERT INTO "demand_specific_distribution" VALUES('region','charge','c','demand',0.05,NULL); +INSERT INTO "demand_specific_distribution" VALUES('region','charge','d','demand',0.1,NULL); +INSERT INTO "demand_specific_distribution" VALUES('region','discharge','a','demand',0.0,NULL); +INSERT INTO "demand_specific_distribution" VALUES('region','discharge','b','demand',0.2,NULL); +INSERT INTO "demand_specific_distribution" VALUES('region','discharge','c','demand',0.2,NULL); +INSERT INTO "demand_specific_distribution" VALUES('region','discharge','d','demand',0.4,NULL); CREATE TABLE efficiency ( region TEXT, @@ -223,10 +217,8 @@ INSERT INTO "efficiency" VALUES('region','electricity','demand',2000,'demand',1. CREATE TABLE efficiency_variable ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -239,7 +231,7 @@ CREATE TABLE efficiency_variable REFERENCES commodity (name), efficiency REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + PRIMARY KEY (region, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); CREATE TABLE emission_activity @@ -541,39 +533,33 @@ CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), factor REAL, notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) + PRIMARY KEY(region, season, tech, operator) ); CREATE TABLE limit_storage_level_fraction ( region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), + season TEXT, tod TEXT REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), fraction REAL, notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) + CHECK (fraction >= 0 AND fraction <= 1), + PRIMARY KEY(region, season, tod, tech, operator) ); -INSERT INTO "limit_storage_level_fraction" VALUES('region',2000,'winter','b','seas_stor',2000,'e',0.5,NULL); -INSERT INTO "limit_storage_level_fraction" VALUES('region',2000,'charge','b','dly_stor',2000,'e',0.5,NULL); +INSERT INTO "limit_storage_level_fraction" VALUES('region','winter','b','seas_stor','e',0.5,NULL); +INSERT INTO "limit_storage_level_fraction" VALUES('region','charge','b','dly_stor','e',0.5,NULL); CREATE TABLE limit_tech_input_split ( region TEXT, @@ -675,7 +661,6 @@ CREATE TABLE metadata notes TEXT, PRIMARY KEY (element) ); -INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); INSERT INTO "metadata" VALUES('DB_MINOR',0,''); CREATE TABLE metadata_real @@ -751,7 +736,7 @@ CREATE TABLE output_curtailment period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES time_period (period), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -798,7 +783,7 @@ CREATE TABLE output_flow_in period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -821,7 +806,7 @@ CREATE TABLE output_flow_out period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -895,8 +880,7 @@ CREATE TABLE output_storage_level REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), + season TEXT, tod TEXT REFERENCES time_of_day (tod), tech TEXT @@ -942,16 +926,14 @@ INSERT INTO "region" VALUES('region',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tech TEXT REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tech, vintage), + PRIMARY KEY (region, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE rps_requirement @@ -965,27 +947,6 @@ CREATE TABLE rps_requirement requirement REAL NOT NULL, notes TEXT ); -CREATE TABLE season_label -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "season_label" VALUES('charge','non-sequential season - charging day'); -INSERT INTO "season_label" VALUES('discharge','non-sequential season - discharging day'); -INSERT INTO "season_label" VALUES('summer','sequential season - summer day'); -INSERT INTO "season_label" VALUES('sept_w1','sequential season - day in first week of September'); -INSERT INTO "season_label" VALUES('sept_w2','sequential season - day in second week of September'); -INSERT INTO "season_label" VALUES('sept_w3','sequential season - day in third week of September'); -INSERT INTO "season_label" VALUES('sept_w4','sequential season - day in fourth week of September'); -INSERT INTO "season_label" VALUES('sept_29th','sequential season - 29th of September'); -INSERT INTO "season_label" VALUES('sept_30th','sequential season - 30th of September'); -INSERT INTO "season_label" VALUES('winter','sequential season - winter day'); -INSERT INTO "season_label" VALUES('apr_w1','sequential season - day in first week of September'); -INSERT INTO "season_label" VALUES('apr_w2','sequential season - day in second week of September'); -INSERT INTO "season_label" VALUES('apr_w3','sequential season - day in third week of September'); -INSERT INTO "season_label" VALUES('apr_w4','sequential season - day in fourth week of September'); -INSERT INTO "season_label" VALUES('apr_29th','sequential season - 29th of April'); -INSERT INTO "season_label" VALUES('apr_30th','sequential season - 30th of April'); CREATE TABLE sector_label ( sector TEXT PRIMARY KEY, @@ -1051,12 +1012,15 @@ CREATE TABLE time_of_day ( sequence INTEGER UNIQUE, tod TEXT - PRIMARY KEY + PRIMARY KEY, + hours REAL NOT NULL DEFAULT 1, + notes TEXT, + CHECK (hours > 0) ); -INSERT INTO "time_of_day" VALUES(0,'a'); -INSERT INTO "time_of_day" VALUES(1,'b'); -INSERT INTO "time_of_day" VALUES(2,'c'); -INSERT INTO "time_of_day" VALUES(3,'d'); +INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(0,'a',6); +INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(1,'b',6); +INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(2,'c',6); +INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(3,'d',6); CREATE TABLE time_period ( sequence INTEGER UNIQUE, @@ -1077,61 +1041,40 @@ INSERT INTO "time_period_type" VALUES('e','existing vintages'); INSERT INTO "time_period_type" VALUES('f','future'); CREATE TABLE time_season ( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - season TEXT REFERENCES season_label(season), + sequence INTEGER UNIQUE, + season TEXT, + segment_fraction REAL NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, season) + PRIMARY KEY (season), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) ); -INSERT INTO "time_season" VALUES(2000,0,'charge',NULL); -INSERT INTO "time_season" VALUES(2000,1,'discharge',NULL); +INSERT INTO "time_season" VALUES(0,'charge',0.5,NULL); +INSERT INTO "time_season" VALUES(1,'discharge',0.5,NULL); CREATE TABLE time_season_sequential ( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, + sequence INTEGER UNIQUE, seas_seq TEXT, - season TEXT REFERENCES season_label(season), - num_days REAL NOT NULL, + season TEXT REFERENCES time_season(season), + segment_fraction REAL NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); -INSERT INTO "time_season_sequential" VALUES(2000,1,'summer','charge',152.5,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,2,'sept_w1','discharge',7.0,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,3,'sept_w2','charge',7.0,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,4,'sept_w3','discharge',7.0,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,5,'sept_w4','charge',7.0,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,6,'sept_29th','discharge',1.0,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,7,'sept_30th','charge',1.0,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,8,'winter','discharge',152.5,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,9,'apr_w1','charge',7.0,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,10,'apr_w2','discharge',7.0,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,11,'apr_w3','charge',7.0,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,12,'apr_w4','discharge',7.0,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,13,'apr_29th','charge',1.0,NULL); -INSERT INTO "time_season_sequential" VALUES(2000,14,'apr_30th','discharge',1.0,NULL); - -CREATE TABLE time_segment_fraction -( - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - segment_fraction REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), + PRIMARY KEY (seas_seq), CHECK (segment_fraction >= 0 AND segment_fraction <= 1) ); -INSERT INTO "time_segment_fraction" VALUES(2000,'charge','a',0.125,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'charge','b',0.125,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'charge','c',0.125,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'charge','d',0.125,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'discharge','a',0.125,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'discharge','b',0.125,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'discharge','c',0.125,NULL); -INSERT INTO "time_segment_fraction" VALUES(2000,'discharge','d',0.125,NULL); +INSERT INTO "time_season_sequential" VALUES(1,'summer','charge',0.417808,NULL); +INSERT INTO "time_season_sequential" VALUES(2,'sept_w1','discharge',0.019178,NULL); +INSERT INTO "time_season_sequential" VALUES(3,'sept_w2','charge',0.019178,NULL); +INSERT INTO "time_season_sequential" VALUES(4,'sept_w3','discharge',0.019178,NULL); +INSERT INTO "time_season_sequential" VALUES(5,'sept_w4','charge',0.019178,NULL); +INSERT INTO "time_season_sequential" VALUES(6,'sept_29th','discharge',0.002740,NULL); +INSERT INTO "time_season_sequential" VALUES(7,'sept_30th','charge',0.002740,NULL); +INSERT INTO "time_season_sequential" VALUES(8,'winter','discharge',0.417808,NULL); +INSERT INTO "time_season_sequential" VALUES(9,'apr_w1','charge',0.019178,NULL); +INSERT INTO "time_season_sequential" VALUES(10,'apr_w2','discharge',0.019178,NULL); +INSERT INTO "time_season_sequential" VALUES(11,'apr_w3','charge',0.019178,NULL); +INSERT INTO "time_season_sequential" VALUES(12,'apr_w4','discharge',0.019178,NULL); +INSERT INTO "time_season_sequential" VALUES(13,'apr_29th','charge',0.002740,NULL); +INSERT INTO "time_season_sequential" VALUES(14,'apr_30th','discharge',0.002740,NULL); + CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql index fd176f069..bfd228b26 100644 --- a/data_files/example_dbs/stepped_demand.sql +++ b/data_files/example_dbs/stepped_demand.sql @@ -9,7 +9,6 @@ CREATE TABLE MetaData ); INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -INSERT INTO MetaData VALUES('days_per_period', 365, 'count of days in each period'); CREATE TABLE MetaDataReal ( element TEXT, @@ -68,8 +67,6 @@ CREATE TABLE capacity_credit CREATE TABLE capacity_factor_process ( region TEXT, - period INTEGER - REFERENCES TimePeriod (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT @@ -79,14 +76,12 @@ CREATE TABLE capacity_factor_process vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), + PRIMARY KEY (region, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE capacity_factor_tech ( region TEXT, - period INTEGER - REFERENCES TimePeriod (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT @@ -95,75 +90,15 @@ CREATE TABLE capacity_factor_tech REFERENCES Technology (tech), factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), + PRIMARY KEY (region, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO capacity_factor_tech VALUES('electricville',2000,'inter','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2000,'winter','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2000,'summer','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2000,'inter','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2000,'winter','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2000,'summer','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2005,'inter','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2005,'winter','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2005,'summer','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2005,'inter','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2005,'winter','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2005,'summer','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2010,'inter','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2010,'winter','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2010,'summer','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2010,'inter','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2010,'winter','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2010,'summer','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2015,'inter','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2015,'winter','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2015,'summer','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2015,'inter','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2015,'winter','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2015,'summer','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2020,'inter','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2020,'winter','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2020,'summer','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2020,'inter','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2020,'winter','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2020,'summer','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2025,'inter','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2025,'winter','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2025,'summer','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2025,'inter','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2025,'winter','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2025,'summer','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2030,'inter','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2030,'winter','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2030,'summer','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2030,'inter','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2030,'winter','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2030,'summer','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2035,'inter','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2035,'winter','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2035,'summer','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2035,'inter','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2035,'winter','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2035,'summer','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2040,'inter','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2040,'winter','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2040,'summer','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2040,'inter','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2040,'winter','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2040,'summer','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2045,'inter','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2045,'winter','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2045,'summer','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2045,'inter','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2045,'winter','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2045,'summer','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2050,'inter','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2050,'winter','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2050,'summer','day','EF',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2050,'inter','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2050,'winter','day','EH',1.0,''); -INSERT INTO capacity_factor_tech VALUES('electricville',2050,'summer','day','EH',1.0,''); +INSERT INTO "capacity_factor_tech" VALUES('electricville','inter','day','EF',1.0,''); +INSERT INTO "capacity_factor_tech" VALUES('electricville','winter','day','EF',1.0,''); +INSERT INTO "capacity_factor_tech" VALUES('electricville','summer','day','EF',1.0,''); +INSERT INTO "capacity_factor_tech" VALUES('electricville','inter','day','EH',1.0,''); +INSERT INTO "capacity_factor_tech" VALUES('electricville','winter','day','EH',1.0,''); +INSERT INTO "capacity_factor_tech" VALUES('electricville','summer','day','EH',1.0,''); CREATE TABLE CapacityToActivity ( region TEXT, @@ -358,8 +293,6 @@ INSERT INTO Demand VALUES('electricville',2050,'RL',2.0,NULL,NULL); CREATE TABLE DemandSpecificDistribution ( region TEXT, - period INTEGER - REFERENCES TimePeriod (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT @@ -368,42 +301,12 @@ CREATE TABLE DemandSpecificDistribution REFERENCES Commodity (name), dsd REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), + PRIMARY KEY (region, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2000,'inter','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2000,'summer','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2000,'winter','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2005,'inter','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2005,'summer','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2005,'winter','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2010,'inter','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2010,'summer','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2010,'winter','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2015,'inter','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2015,'summer','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2015,'winter','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2020,'inter','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2020,'summer','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2020,'winter','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'inter','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'summer','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2025,'winter','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2030,'inter','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2030,'summer','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2030,'winter','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2035,'inter','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2035,'summer','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2035,'winter','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2040,'inter','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2040,'summer','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2040,'winter','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2045,'inter','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2045,'summer','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2045,'winter','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2050,'inter','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2050,'summer','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville',2050,'winter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville','inter','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville','summer','day','RL',0.3332999999999999852,''); +INSERT INTO DemandSpecificDistribution VALUES('electricville','winter','day','RL',0.3332999999999999852,''); CREATE TABLE end_of_life_output ( region TEXT, @@ -443,8 +346,6 @@ INSERT INTO efficiency VALUES('electricville','HYD','EH',2020,'ELC',1.0,NULL); CREATE TABLE efficiency_variable ( region TEXT, - period INTEGER - REFERENCES TimePeriod (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT @@ -459,7 +360,7 @@ CREATE TABLE efficiency_variable REFERENCES Commodity (name), efficiency REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + PRIMARY KEY (region, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); CREATE TABLE emission_activity @@ -663,21 +564,17 @@ CREATE TABLE limit_degrowth_new_capacity_delta CREATE TABLE LimitStorageLevelFraction ( region TEXT, - period INTEGER - REFERENCES TimePeriod (period), season TEXT REFERENCES SeasonLabel (season), tod TEXT REFERENCES TimeOfDay (tod), tech TEXT REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES Operator (operator), fraction REAL, notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) + PRIMARY KEY(region, season, tod, tech, operator) ); CREATE TABLE limit_activity ( @@ -799,8 +696,6 @@ CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES Region (region), - period INTEGER - REFERENCES TimePeriod (period), season TEXT REFERENCES SeasonLabel (season), tech TEXT @@ -809,7 +704,7 @@ CREATE TABLE limit_seasonal_capacity_factor REFERENCES Operator (operator), factor REAL, notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) + PRIMARY KEY(region, season, tech, operator) ); CREATE TABLE limit_tech_input_split ( @@ -1064,8 +959,6 @@ INSERT INTO Region VALUES('electricville',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, - period INTEGER - REFERENCES TimePeriod (period), season TEXT REFERENCES SeasonLabel (season), tech TEXT @@ -1073,7 +966,7 @@ CREATE TABLE reserve_capacity_derate vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tech, vintage), + PRIMARY KEY (region, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE TimeSegmentFraction @@ -1224,16 +1117,14 @@ INSERT INTO TimeSeason VALUES(2050,2,'summer',NULL); INSERT INTO TimeSeason VALUES(2050,3,'winter',NULL); CREATE TABLE time_season_sequential ( - period INTEGER - REFERENCES TimePeriod (period), - sequence INTEGER, + sequence INTEGER UNIQUE, seas_seq TEXT, season TEXT - REFERENCES SeasonLabel (season), - num_days REAL NOT NULL, + REFERENCES time_season (season), + segment_fraction REAL NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) + PRIMARY KEY (seas_seq), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) ); CREATE TABLE TimePeriodType ( diff --git a/data_files/example_dbs/survival_curve.sql b/data_files/example_dbs/survival_curve.sql index ea6055117..11fd02bf0 100644 --- a/data_files/example_dbs/survival_curve.sql +++ b/data_files/example_dbs/survival_curve.sql @@ -15,10 +15,8 @@ CREATE TABLE capacity_credit CREATE TABLE capacity_factor_process ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), tech TEXT @@ -26,23 +24,21 @@ CREATE TABLE capacity_factor_process vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), + PRIMARY KEY (region, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE capacity_factor_tech ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), + PRIMARY KEY (region, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE capacity_to_activity @@ -223,17 +219,15 @@ INSERT INTO "demand" VALUES('region',2050,'demand',1.0,NULL,NULL); CREATE TABLE demand_specific_distribution ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), demand_name TEXT REFERENCES commodity (name), dsd REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), + PRIMARY KEY (region, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); CREATE TABLE efficiency @@ -263,10 +257,8 @@ INSERT INTO "efficiency" VALUES('region','source','tech_future',2050,'demand',1. CREATE TABLE efficiency_variable ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -279,7 +271,7 @@ CREATE TABLE efficiency_variable REFERENCES commodity (name), efficiency REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + PRIMARY KEY (region, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); CREATE TABLE emission_activity @@ -643,36 +635,30 @@ CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), factor REAL, notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) + PRIMARY KEY(region, season, tech, operator) ); CREATE TABLE limit_storage_level_fraction ( region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), + season TEXT, tod TEXT REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), fraction REAL, notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) + CHECK (fraction >= 0 AND fraction <= 1), + PRIMARY KEY(region, season, tod, tech, operator) ); CREATE TABLE limit_tech_input_split ( @@ -775,7 +761,6 @@ CREATE TABLE metadata notes TEXT, PRIMARY KEY (element) ); -INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); INSERT INTO "metadata" VALUES('DB_MINOR',0,''); CREATE TABLE metadata_real @@ -851,7 +836,7 @@ CREATE TABLE output_curtailment period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES time_period (period), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -898,7 +883,7 @@ CREATE TABLE output_flow_in period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -921,7 +906,7 @@ CREATE TABLE output_flow_out period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -995,8 +980,7 @@ CREATE TABLE output_storage_level REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), + season TEXT, tod TEXT REFERENCES time_of_day (tod), tech TEXT @@ -1042,16 +1026,14 @@ INSERT INTO "region" VALUES('region',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tech TEXT REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tech, vintage), + PRIMARY KEY (region, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE rps_requirement @@ -1065,12 +1047,6 @@ CREATE TABLE rps_requirement requirement REAL NOT NULL, notes TEXT ); -CREATE TABLE season_label -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "season_label" VALUES('s',NULL); CREATE TABLE sector_label ( sector TEXT PRIMARY KEY, @@ -1133,9 +1109,12 @@ CREATE TABLE time_of_day ( sequence INTEGER UNIQUE, tod TEXT - PRIMARY KEY + PRIMARY KEY, + hours REAL NOT NULL DEFAULT 1, + notes TEXT, + CHECK (hours > 0) ); -INSERT INTO "time_of_day" VALUES(0,'d'); +INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(0,'d',24); CREATE TABLE time_period ( sequence INTEGER UNIQUE, @@ -1163,49 +1142,25 @@ INSERT INTO "time_period_type" VALUES('e','existing vintages'); INSERT INTO "time_period_type" VALUES('f','future'); CREATE TABLE time_season ( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - season TEXT REFERENCES season_label(season), + sequence INTEGER UNIQUE, + season TEXT, + segment_fraction REAL NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, season) -); -INSERT INTO "time_season" VALUES(2025,0,'s',NULL); -INSERT INTO "time_season" VALUES(2030,1,'s',NULL); -INSERT INTO "time_season" VALUES(2035,2,'s',NULL); -INSERT INTO "time_season" VALUES(2040,3,'s',NULL); -INSERT INTO "time_season" VALUES(2045,4,'s',NULL); -INSERT INTO "time_season" VALUES(2050,5,'s',NULL); + PRIMARY KEY (season), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) +); +INSERT INTO "time_season" VALUES(0,'s',1.0,NULL); CREATE TABLE time_season_sequential ( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, + sequence INTEGER UNIQUE, seas_seq TEXT, - season TEXT REFERENCES season_label(season), - num_days REAL NOT NULL, + season TEXT REFERENCES time_season(season), + segment_fraction REAL NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); - -CREATE TABLE time_segment_fraction -( - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - segment_fraction REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), + PRIMARY KEY (seas_seq), CHECK (segment_fraction >= 0 AND segment_fraction <= 1) ); -INSERT INTO "time_segment_fraction" VALUES(2025,'s','d',1.0,NULL); -INSERT INTO "time_segment_fraction" VALUES(2030,'s','d',1.0,NULL); -INSERT INTO "time_segment_fraction" VALUES(2035,'s','d',1.0,NULL); -INSERT INTO "time_segment_fraction" VALUES(2040,'s','d',1.0,NULL); -INSERT INTO "time_segment_fraction" VALUES(2045,'s','d',1.0,NULL); -INSERT INTO "time_segment_fraction" VALUES(2050,'s','d',1.0,NULL); + CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql index 89b181fc9..c43d9d17e 100644 --- a/data_files/example_dbs/test_system.sql +++ b/data_files/example_dbs/test_system.sql @@ -15,10 +15,8 @@ CREATE TABLE capacity_credit CREATE TABLE capacity_factor_process ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), tech TEXT @@ -26,73 +24,39 @@ CREATE TABLE capacity_factor_process vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), + PRIMARY KEY (region, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE capacity_factor_tech ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), + PRIMARY KEY (region, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'spring','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'spring','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'summer','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'summer','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'fall','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'fall','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'winter','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2020,'winter','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'spring','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'spring','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'summer','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'summer','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'fall','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'fall','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'winter','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2020,'winter','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'spring','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'spring','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'summer','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'summer','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'fall','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'fall','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'winter','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2025,'winter','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'spring','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'spring','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'summer','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'summer','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'fall','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'fall','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'winter','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2025,'winter','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'spring','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'spring','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'summer','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'summer','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'fall','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'fall','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'winter','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1',2030,'winter','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'spring','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'spring','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'summer','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'summer','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'fall','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'fall','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'winter','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2',2030,'winter','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1','spring','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1','spring','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1','summer','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1','summer','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1','fall','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1','fall','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R1','winter','day','E_SOLPV',0.6,''); +INSERT INTO "capacity_factor_tech" VALUES('R1','winter','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2','spring','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2','spring','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2','summer','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2','summer','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2','fall','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2','fall','night','E_SOLPV',0.0,''); +INSERT INTO "capacity_factor_tech" VALUES('R2','winter','day','E_SOLPV',0.48,''); +INSERT INTO "capacity_factor_tech" VALUES('R2','winter','night','E_SOLPV',0.0,''); CREATE TABLE capacity_to_activity ( region TEXT, @@ -418,67 +382,33 @@ INSERT INTO "demand" VALUES('R2',2030,'VMT',42.0,'',''); CREATE TABLE demand_specific_distribution ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), demand_name TEXT REFERENCES commodity (name), dsd REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), + PRIMARY KEY (region, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'spring','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'spring','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'summer','day','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'summer','night','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'fall','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'fall','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'winter','day','RH',0.3,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2020,'winter','night','RH',0.4,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'spring','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'spring','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'summer','day','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'summer','night','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'fall','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'fall','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'winter','day','RH',0.3,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2020,'winter','night','RH',0.4,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'spring','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'spring','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'summer','day','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'summer','night','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'fall','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'fall','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'winter','day','RH',0.3,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2025,'winter','night','RH',0.4,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'spring','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'spring','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'summer','day','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'summer','night','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'fall','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'fall','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'winter','day','RH',0.3,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2025,'winter','night','RH',0.4,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'spring','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'spring','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'summer','day','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'summer','night','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'fall','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'fall','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'winter','day','RH',0.3,''); -INSERT INTO "demand_specific_distribution" VALUES('R1',2030,'winter','night','RH',0.4,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'spring','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'spring','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'summer','day','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'summer','night','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'fall','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'fall','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'winter','day','RH',0.3,''); -INSERT INTO "demand_specific_distribution" VALUES('R2',2030,'winter','night','RH',0.4,''); +INSERT INTO "demand_specific_distribution" VALUES('R1','spring','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R1','spring','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R1','summer','day','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R1','summer','night','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R1','fall','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R1','fall','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R1','winter','day','RH',0.3,''); +INSERT INTO "demand_specific_distribution" VALUES('R1','winter','night','RH',0.4,''); +INSERT INTO "demand_specific_distribution" VALUES('R2','spring','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R2','spring','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R2','summer','day','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R2','summer','night','RH',0.0,''); +INSERT INTO "demand_specific_distribution" VALUES('R2','fall','day','RH',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('R2','fall','night','RH',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('R2','winter','day','RH',0.3,''); +INSERT INTO "demand_specific_distribution" VALUES('R2','winter','night','RH',0.4,''); CREATE TABLE efficiency ( region TEXT, @@ -572,10 +502,8 @@ INSERT INTO "efficiency" VALUES('R2-R1','ELC','E_TRANS',2015,'ELC',0.9,''); CREATE TABLE efficiency_variable ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -588,7 +516,7 @@ CREATE TABLE efficiency_variable REFERENCES commodity (name), efficiency REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + PRIMARY KEY (region, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); CREATE TABLE emission_activity @@ -944,39 +872,33 @@ CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), factor REAL, notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) + PRIMARY KEY(region, season, tech, operator) ); CREATE TABLE limit_storage_level_fraction ( region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), + season TEXT, tod TEXT REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), fraction REAL, notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) + CHECK (fraction >= 0 AND fraction <= 1), + PRIMARY KEY(region, season, tod, tech, operator) ); -INSERT INTO "limit_storage_level_fraction" VALUES('R1',2025,'winter','day','E_BATT',2025,'e',0.5,''); -INSERT INTO "limit_storage_level_fraction" VALUES('R2',2020,'summer','day','E_BATT',2020,'e',0.5,''); +INSERT INTO "limit_storage_level_fraction" VALUES('R1','winter','day','E_BATT','e',0.5,''); +INSERT INTO "limit_storage_level_fraction" VALUES('R2','summer','day','E_BATT','e',0.5,''); CREATE TABLE limit_tech_input_split ( region TEXT, @@ -1102,7 +1024,6 @@ CREATE TABLE metadata notes TEXT, PRIMARY KEY (element) ); -INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); INSERT INTO "metadata" VALUES('DB_MINOR',0,''); CREATE TABLE metadata_real @@ -1178,7 +1099,7 @@ CREATE TABLE output_curtailment period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES time_period (period), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -1225,7 +1146,7 @@ CREATE TABLE output_flow_in period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -1248,7 +1169,7 @@ CREATE TABLE output_flow_out period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -1322,8 +1243,7 @@ CREATE TABLE output_storage_level REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), + season TEXT, tod TEXT REFERENCES time_of_day (tod), tech TEXT @@ -1370,16 +1290,14 @@ INSERT INTO "region" VALUES('R2',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tech TEXT REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tech, vintage), + PRIMARY KEY (region, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE rps_requirement @@ -1393,15 +1311,6 @@ CREATE TABLE rps_requirement requirement REAL NOT NULL, notes TEXT ); -CREATE TABLE season_label -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "season_label" VALUES('summer',NULL); -INSERT INTO "season_label" VALUES('fall',NULL); -INSERT INTO "season_label" VALUES('winter',NULL); -INSERT INTO "season_label" VALUES('spring',NULL); CREATE TABLE sector_label ( sector TEXT PRIMARY KEY, @@ -1484,10 +1393,13 @@ CREATE TABLE time_of_day ( sequence INTEGER UNIQUE, tod TEXT - PRIMARY KEY + PRIMARY KEY, + hours REAL NOT NULL DEFAULT 1, + notes TEXT, + CHECK (hours > 0) ); -INSERT INTO "time_of_day" VALUES(1,'day'); -INSERT INTO "time_of_day" VALUES(2,'night'); +INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(1,'day',12); +INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(2,'night',12); CREATE TABLE time_period ( sequence INTEGER UNIQUE, @@ -1511,73 +1423,28 @@ INSERT INTO "time_period_type" VALUES('e','existing vintages'); INSERT INTO "time_period_type" VALUES('f','future'); CREATE TABLE time_season ( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - season TEXT REFERENCES season_label(season), + sequence INTEGER UNIQUE, + season TEXT, + segment_fraction REAL NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, season) -); -INSERT INTO "time_season" VALUES(2020,1,'spring',NULL); -INSERT INTO "time_season" VALUES(2020,2,'summer',NULL); -INSERT INTO "time_season" VALUES(2020,3,'fall',NULL); -INSERT INTO "time_season" VALUES(2020,4,'winter',NULL); -INSERT INTO "time_season" VALUES(2025,1,'spring',NULL); -INSERT INTO "time_season" VALUES(2025,2,'summer',NULL); -INSERT INTO "time_season" VALUES(2025,3,'fall',NULL); -INSERT INTO "time_season" VALUES(2025,4,'winter',NULL); -INSERT INTO "time_season" VALUES(2030,1,'spring',NULL); -INSERT INTO "time_season" VALUES(2030,2,'summer',NULL); -INSERT INTO "time_season" VALUES(2030,3,'fall',NULL); -INSERT INTO "time_season" VALUES(2030,4,'winter',NULL); + PRIMARY KEY (season), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) +); +INSERT INTO "time_season" VALUES(0,'spring',0.25,NULL); +INSERT INTO "time_season" VALUES(1,'summer',0.25,NULL); +INSERT INTO "time_season" VALUES(2,'fall',0.25,NULL); +INSERT INTO "time_season" VALUES(3,'winter',0.25,NULL); CREATE TABLE time_season_sequential ( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, + sequence INTEGER UNIQUE, seas_seq TEXT, - season TEXT REFERENCES season_label(season), - num_days REAL NOT NULL, + season TEXT REFERENCES time_season(season), + segment_fraction REAL NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); - -CREATE TABLE time_segment_fraction -( - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - segment_fraction REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), + PRIMARY KEY (seas_seq), CHECK (segment_fraction >= 0 AND segment_fraction <= 1) ); -INSERT INTO "time_segment_fraction" VALUES(2020,'spring','day',0.125,'Spring - Day'); -INSERT INTO "time_segment_fraction" VALUES(2020,'spring','night',0.125,'Spring - Night'); -INSERT INTO "time_segment_fraction" VALUES(2020,'summer','day',0.125,'Summer - Day'); -INSERT INTO "time_segment_fraction" VALUES(2020,'summer','night',0.125,'Summer - Night'); -INSERT INTO "time_segment_fraction" VALUES(2020,'fall','day',0.125,'Fall - Day'); -INSERT INTO "time_segment_fraction" VALUES(2020,'fall','night',0.125,'Fall - Night'); -INSERT INTO "time_segment_fraction" VALUES(2020,'winter','day',0.125,'Winter - Day'); -INSERT INTO "time_segment_fraction" VALUES(2020,'winter','night',0.125,'Winter - Night'); -INSERT INTO "time_segment_fraction" VALUES(2025,'spring','day',0.125,'Spring - Day'); -INSERT INTO "time_segment_fraction" VALUES(2025,'spring','night',0.125,'Spring - Night'); -INSERT INTO "time_segment_fraction" VALUES(2025,'summer','day',0.125,'Summer - Day'); -INSERT INTO "time_segment_fraction" VALUES(2025,'summer','night',0.125,'Summer - Night'); -INSERT INTO "time_segment_fraction" VALUES(2025,'fall','day',0.125,'Fall - Day'); -INSERT INTO "time_segment_fraction" VALUES(2025,'fall','night',0.125,'Fall - Night'); -INSERT INTO "time_segment_fraction" VALUES(2025,'winter','day',0.125,'Winter - Day'); -INSERT INTO "time_segment_fraction" VALUES(2025,'winter','night',0.125,'Winter - Night'); -INSERT INTO "time_segment_fraction" VALUES(2030,'spring','day',0.125,'Spring - Day'); -INSERT INTO "time_segment_fraction" VALUES(2030,'spring','night',0.125,'Spring - Night'); -INSERT INTO "time_segment_fraction" VALUES(2030,'summer','day',0.125,'Summer - Day'); -INSERT INTO "time_segment_fraction" VALUES(2030,'summer','night',0.125,'Summer - Night'); -INSERT INTO "time_segment_fraction" VALUES(2030,'fall','day',0.125,'Fall - Day'); -INSERT INTO "time_segment_fraction" VALUES(2030,'fall','night',0.125,'Fall - Night'); -INSERT INTO "time_segment_fraction" VALUES(2030,'winter','day',0.125,'Winter - Day'); -INSERT INTO "time_segment_fraction" VALUES(2030,'winter','night',0.125,'Winter - Night'); + CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql index 72ab60a18..7fdf117c0 100644 --- a/data_files/example_dbs/utopia.sql +++ b/data_files/example_dbs/utopia.sql @@ -15,10 +15,8 @@ CREATE TABLE capacity_credit CREATE TABLE capacity_factor_process ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), tech TEXT @@ -26,133 +24,65 @@ CREATE TABLE capacity_factor_process vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), + PRIMARY KEY (region, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'inter','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'inter','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'winter','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'winter','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'summer','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'summer','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','day','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','night','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','day','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','night','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','day','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','night','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','inter','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','inter','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','winter','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','winter','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','summer','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','summer','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','inter','day','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','inter','night','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','winter','day','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','winter','night','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','summer','day','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','summer','night','E31',2010,0.2756,''); CREATE TABLE capacity_factor_tech ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), + PRIMARY KEY (region, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E70',0.8,''); CREATE TABLE capacity_to_activity ( region TEXT, @@ -466,49 +396,27 @@ INSERT INTO "demand" VALUES('utopia',2010,'TX',11.69,'',''); CREATE TABLE demand_specific_distribution ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), demand_name TEXT REFERENCES commodity (name), dsd REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), + PRIMARY KEY (region, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','day','RH',0.12,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','night','RH',0.06,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','day','RH',0.5467,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','night','RH',0.2733,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'summer','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'summer','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','day','RL',0.5,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','night','RL',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','day','RH',0.12,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','night','RH',0.06,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','day','RH',0.5467,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','night','RH',0.2733,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'summer','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'summer','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','day','RL',0.5,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','night','RL',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','day','RH',0.12,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','night','RH',0.06,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','day','RH',0.5467,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','night','RH',0.2733,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'summer','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'summer','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','day','RL',0.5,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','night','RL',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','inter','day','RH',0.12,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','inter','night','RH',0.06,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','winter','day','RH',0.5467,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','winter','night','RH',0.2733,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','inter','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','inter','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','summer','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','summer','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','winter','day','RL',0.5,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','winter','night','RL',0.1,''); CREATE TABLE efficiency ( region TEXT, @@ -592,10 +500,8 @@ INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',2010,'TX',0.231,'# direct t CREATE TABLE efficiency_variable ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -608,7 +514,7 @@ CREATE TABLE efficiency_variable REFERENCES commodity (name), efficiency REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + PRIMARY KEY (region, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); CREATE TABLE emission_activity @@ -974,36 +880,30 @@ CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), factor REAL, notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) + PRIMARY KEY(region, season, tech, operator) ); CREATE TABLE limit_storage_level_fraction ( region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), + season TEXT, tod TEXT REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), fraction REAL, notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) + CHECK (fraction >= 0 AND fraction <= 1), + PRIMARY KEY(region, season, tod, tech, operator) ); CREATE TABLE limit_tech_input_split ( @@ -1112,7 +1012,6 @@ CREATE TABLE metadata notes TEXT, PRIMARY KEY (element) ); -INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); INSERT INTO "metadata" VALUES('DB_MINOR',0,''); CREATE TABLE metadata_real @@ -1188,7 +1087,7 @@ CREATE TABLE output_curtailment period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES time_period (period), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -1235,7 +1134,7 @@ CREATE TABLE output_flow_in period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -1258,7 +1157,7 @@ CREATE TABLE output_flow_out period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -1332,8 +1231,7 @@ CREATE TABLE output_storage_level REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), + season TEXT, tod TEXT REFERENCES time_of_day (tod), tech TEXT @@ -1379,16 +1277,14 @@ INSERT INTO "region" VALUES('utopia',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tech TEXT REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tech, vintage), + PRIMARY KEY (region, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE rps_requirement @@ -1402,14 +1298,6 @@ CREATE TABLE rps_requirement requirement REAL NOT NULL, notes TEXT ); -CREATE TABLE season_label -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "season_label" VALUES('inter',NULL); -INSERT INTO "season_label" VALUES('summer',NULL); -INSERT INTO "season_label" VALUES('winter',NULL); CREATE TABLE sector_label ( sector TEXT PRIMARY KEY, @@ -1493,10 +1381,13 @@ CREATE TABLE time_of_day ( sequence INTEGER UNIQUE, tod TEXT - PRIMARY KEY + PRIMARY KEY, + hours REAL NOT NULL DEFAULT 1, + notes TEXT, + CHECK (hours > 0) ); -INSERT INTO "time_of_day" VALUES(1,'day'); -INSERT INTO "time_of_day" VALUES(2,'night'); +INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(1,'day',16); +INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(2,'night',8); CREATE TABLE time_period ( sequence INTEGER UNIQUE, @@ -1522,64 +1413,27 @@ INSERT INTO "time_period_type" VALUES('e','existing vintages'); INSERT INTO "time_period_type" VALUES('f','future'); CREATE TABLE time_season ( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - season TEXT REFERENCES season_label(season), + sequence INTEGER UNIQUE, + season TEXT, + segment_fraction REAL NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, season) -); -INSERT INTO "time_season" VALUES(1990,1,'inter',NULL); -INSERT INTO "time_season" VALUES(1990,2,'summer',NULL); -INSERT INTO "time_season" VALUES(1990,3,'winter',NULL); -INSERT INTO "time_season" VALUES(2000,1,'inter',NULL); -INSERT INTO "time_season" VALUES(2000,2,'summer',NULL); -INSERT INTO "time_season" VALUES(2000,3,'winter',NULL); -INSERT INTO "time_season" VALUES(2010,1,'inter',NULL); -INSERT INTO "time_season" VALUES(2010,2,'summer',NULL); -INSERT INTO "time_season" VALUES(2010,3,'winter',NULL); + PRIMARY KEY (season), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) +); +INSERT INTO "time_season" VALUES(0,'inter',0.25,NULL); +INSERT INTO "time_season" VALUES(1,'summer',0.25,NULL); +INSERT INTO "time_season" VALUES(2,'winter',0.5,NULL); CREATE TABLE time_season_sequential ( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, + sequence INTEGER UNIQUE, seas_seq TEXT, - season TEXT REFERENCES season_label(season), - num_days REAL NOT NULL, + season TEXT REFERENCES time_season(season), + segment_fraction REAL NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); - -CREATE TABLE time_segment_fraction -( - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - segment_fraction REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), + PRIMARY KEY (seas_seq), CHECK (segment_fraction >= 0 AND segment_fraction <= 1) ); -INSERT INTO "time_segment_fraction" VALUES(1990,'inter','day',0.1667,'# I-D'); -INSERT INTO "time_segment_fraction" VALUES(1990,'inter','night',0.0833,'# I-N'); -INSERT INTO "time_segment_fraction" VALUES(1990,'summer','day',0.1667,'# S-D'); -INSERT INTO "time_segment_fraction" VALUES(1990,'summer','night',0.0833,'# S-N'); -INSERT INTO "time_segment_fraction" VALUES(1990,'winter','day',0.3333,'# W-D'); -INSERT INTO "time_segment_fraction" VALUES(1990,'winter','night',0.1667,'# W-N'); -INSERT INTO "time_segment_fraction" VALUES(2000,'inter','day',0.1667,'# I-D'); -INSERT INTO "time_segment_fraction" VALUES(2000,'inter','night',0.0833,'# I-N'); -INSERT INTO "time_segment_fraction" VALUES(2000,'summer','day',0.1667,'# S-D'); -INSERT INTO "time_segment_fraction" VALUES(2000,'summer','night',0.0833,'# S-N'); -INSERT INTO "time_segment_fraction" VALUES(2000,'winter','day',0.3333,'# W-D'); -INSERT INTO "time_segment_fraction" VALUES(2000,'winter','night',0.1667,'# W-N'); -INSERT INTO "time_segment_fraction" VALUES(2010,'inter','day',0.1667,'# I-D'); -INSERT INTO "time_segment_fraction" VALUES(2010,'inter','night',0.0833,'# I-N'); -INSERT INTO "time_segment_fraction" VALUES(2010,'summer','day',0.1667,'# S-D'); -INSERT INTO "time_segment_fraction" VALUES(2010,'summer','night',0.0833,'# S-N'); -INSERT INTO "time_segment_fraction" VALUES(2010,'winter','day',0.3333,'# W-D'); -INSERT INTO "time_segment_fraction" VALUES(2010,'winter','night',0.1667,'# W-N'); + CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; diff --git a/data_files/my_configs/config_sample.toml b/data_files/my_configs/config_sample.toml index 0174f9ec5..3ba00adbf 100644 --- a/data_files/my_configs/config_sample.toml +++ b/data_files/my_configs/config_sample.toml @@ -108,6 +108,11 @@ save_lp_file = false # storage must be tagged and the TimeSeasonSequential table filled. time_sequencing = 'seasonal_timeslices' +# Number of days represented by each planning period. +# Used to adjust flow variables for number of days represented by each season. +# E.g. 365 if all seasons collectively represent a year, 7 if modelling a single representative week. +days_per_period = 365 + # How contributions to the planning reserve margin are calculated # Options: # 'static' diff --git a/data_files/my_configs/materials.toml b/data_files/my_configs/materials.toml index 9889c7af9..a925429e8 100644 --- a/data_files/my_configs/materials.toml +++ b/data_files/my_configs/materials.toml @@ -103,6 +103,11 @@ save_lp_file = false # storage must be tagged and the TimeSeasonSequential table filled. time_sequencing = 'seasonal_timeslices' +# Number of days represented by each planning period. +# Used to adjust flow variables for number of days represented by each season. +# E.g. 365 if all seasons collectively represent a year, 7 if modelling a single representative week. +days_per_period = 365 + # How contributions to the planning reserve margin are calculated # Options: # 'static' diff --git a/data_files/my_configs/mga_utopia.toml b/data_files/my_configs/mga_utopia.toml index 255c2febf..17529830c 100644 --- a/data_files/my_configs/mga_utopia.toml +++ b/data_files/my_configs/mga_utopia.toml @@ -97,6 +97,11 @@ save_lp_file = false # storage must be tagged and the TimeSeasonSequential table filled. time_sequencing = 'seasonal_timeslices' +# Number of days represented by each planning period. +# Used to adjust flow variables for number of days represented by each season. +# E.g. 365 if all seasons collectively represent a year, 7 if modelling a single representative week. +days_per_period = 365 + # How contributions to the planning reserve margin are calculated # Options: # 'static' diff --git a/data_files/my_configs/monte_carlo_utopia.toml b/data_files/my_configs/monte_carlo_utopia.toml index 7394fb291..e26032928 100644 --- a/data_files/my_configs/monte_carlo_utopia.toml +++ b/data_files/my_configs/monte_carlo_utopia.toml @@ -100,6 +100,11 @@ save_lp_file = false # storage must be tagged and the TimeSeasonSequential table filled. time_sequencing = 'seasonal_timeslices' +# Number of days represented by each planning period. +# Used to adjust flow variables for number of days represented by each season. +# E.g. 365 if all seasons collectively represent a year, 7 if modelling a single representative week. +days_per_period = 365 + # How contributions to the planning reserve margin are calculated # Options: # 'static' diff --git a/data_files/my_configs/morris_utopia.toml b/data_files/my_configs/morris_utopia.toml index f9a722bcd..f71182853 100644 --- a/data_files/my_configs/morris_utopia.toml +++ b/data_files/my_configs/morris_utopia.toml @@ -97,6 +97,11 @@ save_lp_file = false # storage must be tagged and the TimeSeasonSequential table filled. time_sequencing = 'seasonal_timeslices' +# Number of days represented by each planning period. +# Used to adjust flow variables for number of days represented by each season. +# E.g. 365 if all seasons collectively represent a year, 7 if modelling a single representative week. +days_per_period = 365 + # How contributions to the planning reserve margin are calculated # Options: # 'static' diff --git a/data_files/my_configs/seasonal_storage.toml b/data_files/my_configs/seasonal_storage.toml index ed8eafa33..d7208626a 100644 --- a/data_files/my_configs/seasonal_storage.toml +++ b/data_files/my_configs/seasonal_storage.toml @@ -103,6 +103,11 @@ save_lp_file = false # storage must be tagged and the TimeSeasonSequential table filled. time_sequencing = 'representative_periods' +# Number of days represented by each planning period. +# Used to adjust flow variables for number of days represented by each season. +# E.g. 365 if all seasons collectively represent a year, 7 if modelling a single representative week. +days_per_period = 365 + # How contributions to the planning reserve margin are calculated # Options: # 'static' diff --git a/data_files/my_configs/stepped_demand.toml b/data_files/my_configs/stepped_demand.toml index 6df63a370..7092d31c1 100644 --- a/data_files/my_configs/stepped_demand.toml +++ b/data_files/my_configs/stepped_demand.toml @@ -97,6 +97,11 @@ save_lp_file = false # storage must be tagged and the TimeSeasonSequential table filled. time_sequencing = 'seasonal_timeslices' +# Number of days represented by each planning period. +# Used to adjust flow variables for number of days represented by each season. +# E.g. 365 if all seasons collectively represent a year, 7 if modelling a single representative week. +days_per_period = 365 + # How contributions to the planning reserve margin are calculated # Options: # 'static' diff --git a/data_files/temoa_basics_1.sql b/data_files/temoa_basics_1.sql index d951941e1..cdab9f8de 100644 --- a/data_files/temoa_basics_1.sql +++ b/data_files/temoa_basics_1.sql @@ -12,8 +12,6 @@ REPLACE INTO MetaData VALUES ('DB_MAJOR', 3, 'DB major version number'); REPLACE INTO MetaData VALUES ('DB_MINOR', 1, 'DB minor version number'); -REPLACE INTO MetaData -VALUES ('days_per_period', 365, 'count of days in each period'); CREATE TABLE IF NOT EXISTS MetaDataReal ( element TEXT, diff --git a/data_files/temoa_basics_2.sql b/data_files/temoa_basics_2.sql index f65169e0b..717226eed 100644 --- a/data_files/temoa_basics_2.sql +++ b/data_files/temoa_basics_2.sql @@ -12,8 +12,6 @@ REPLACE INTO MetaData VALUES ('DB_MAJOR', 3, 'DB major version number'); REPLACE INTO MetaData VALUES ('DB_MINOR', 1, 'DB minor version number'); -REPLACE INTO MetaData -VALUES ('days_per_period', 365, 'count of days in each period'); CREATE TABLE IF NOT EXISTS MetaDataReal ( element TEXT, diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql index b91d03ce5..05015865c 100644 --- a/data_files/temoa_schema_v3_1.sql +++ b/data_files/temoa_schema_v3_1.sql @@ -12,8 +12,6 @@ REPLACE INTO MetaData VALUES ('DB_MAJOR', 3, 'DB major version number'); REPLACE INTO MetaData VALUES ('DB_MINOR', 1, 'DB minor version number'); -REPLACE INTO MetaData -VALUES ('days_per_period', 365, 'count of days in each period'); CREATE TABLE IF NOT EXISTS MetaDataReal ( diff --git a/data_files/temoa_schema_v4.sql b/data_files/temoa_schema_v4.sql index 2019e7f0b..90a39108c 100644 --- a/data_files/temoa_schema_v4.sql +++ b/data_files/temoa_schema_v4.sql @@ -12,8 +12,6 @@ REPLACE INTO metadata VALUES ('DB_MAJOR', 4, 'DB major version number'); REPLACE INTO metadata VALUES ('DB_MINOR', 0, 'DB minor version number'); -REPLACE INTO metadata -VALUES ('days_per_period', 365, 'count of days in each period'); CREATE TABLE IF NOT EXISTS metadata_real ( @@ -41,11 +39,6 @@ CREATE TABLE IF NOT EXISTS output_objective objective_name TEXT, total_system_cost REAL ); -CREATE TABLE IF NOT EXISTS season_label -( - season TEXT PRIMARY KEY, - notes TEXT -); CREATE TABLE IF NOT EXISTS sector_label ( sector TEXT PRIMARY KEY, @@ -67,10 +60,8 @@ CREATE TABLE IF NOT EXISTS capacity_credit CREATE TABLE IF NOT EXISTS capacity_factor_process ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), tech TEXT @@ -78,23 +69,21 @@ CREATE TABLE IF NOT EXISTS capacity_factor_process vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), + PRIMARY KEY (region, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE IF NOT EXISTS capacity_factor_tech ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), + PRIMARY KEY (region, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE IF NOT EXISTS capacity_to_activity @@ -219,17 +208,15 @@ CREATE TABLE IF NOT EXISTS demand CREATE TABLE IF NOT EXISTS demand_specific_distribution ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), demand_name TEXT REFERENCES commodity (name), dsd REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), + PRIMARY KEY (region, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); CREATE TABLE IF NOT EXISTS end_of_life_output @@ -266,10 +253,8 @@ CREATE TABLE IF NOT EXISTS efficiency CREATE TABLE IF NOT EXISTS efficiency_variable ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -282,7 +267,7 @@ CREATE TABLE IF NOT EXISTS efficiency_variable REFERENCES commodity (name), efficiency REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + PRIMARY KEY (region, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); CREATE TABLE IF NOT EXISTS emission_activity @@ -477,21 +462,17 @@ CREATE TABLE IF NOT EXISTS limit_degrowth_new_capacity_delta CREATE TABLE IF NOT EXISTS limit_storage_level_fraction ( region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), + season TEXT, tod TEXT REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), fraction REAL, notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) + CHECK (fraction >= 0 AND fraction <= 1), + PRIMARY KEY(region, season, tod, tech, operator) ); CREATE TABLE IF NOT EXISTS limit_activity ( @@ -602,17 +583,15 @@ CREATE TABLE IF NOT EXISTS limit_seasonal_capacity_factor ( region TEXT REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tech TEXT REFERENCES technology (tech), operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), factor REAL, notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) + PRIMARY KEY(region, season, tech, operator) ); CREATE TABLE IF NOT EXISTS limit_tech_input_split ( @@ -708,7 +687,7 @@ CREATE TABLE IF NOT EXISTS output_curtailment period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -779,7 +758,7 @@ CREATE TABLE IF NOT EXISTS output_flow_in period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -803,7 +782,7 @@ CREATE TABLE IF NOT EXISTS output_flow_out period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -826,8 +805,7 @@ CREATE TABLE IF NOT EXISTS output_storage_level REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), + season TEXT, tod TEXT REFERENCES time_of_day (tod), tech TEXT @@ -873,31 +851,16 @@ CREATE TABLE IF NOT EXISTS region CREATE TABLE IF NOT EXISTS reserve_capacity_derate ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tech TEXT REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tech, vintage), + PRIMARY KEY (region, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE IF NOT EXISTS time_segment_fraction -( - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - segment_fraction REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); CREATE TABLE IF NOT EXISTS storage_duration ( region TEXT, @@ -932,24 +895,25 @@ REPLACE INTO technology_type VALUES ('ps', 'storage production technology'); -- CREATE TABLE IF NOT EXISTS time_manual -- ( --- period INTEGER --- REFERENCES time_period (period), -- season TEXT --- REFERENCES season_label (season), +-- REFERENCES time_season (season), -- tod TEXT -- REFERENCES time_of_day (tod), -- season_next TEXT --- REFERENCES season_label (season), +-- REFERENCES time_season (season), -- tod_next TEXT -- REFERENCES time_of_day (tod), -- notes TEXT, --- PRIMARY KEY (period, season, tod) +-- PRIMARY KEY (season, tod) -- ); CREATE TABLE IF NOT EXISTS time_of_day ( sequence INTEGER UNIQUE, tod TEXT - PRIMARY KEY + PRIMARY KEY, + hours REAL NOT NULL DEFAULT 1, + notes TEXT, + CHECK (hours > 0) ); CREATE TABLE IF NOT EXISTS time_period ( @@ -1048,23 +1012,23 @@ CREATE TABLE IF NOT EXISTS output_cost CREATE TABLE IF NOT EXISTS time_season ( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - season TEXT REFERENCES season_label(season), + sequence INTEGER UNIQUE, + season TEXT, + segment_fraction REAL NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, season) + PRIMARY KEY (season), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) ); CREATE TABLE IF NOT EXISTS time_season_sequential ( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, + sequence INTEGER UNIQUE, seas_seq TEXT, - season TEXT REFERENCES season_label(season), - num_days REAL NOT NULL, + season TEXT REFERENCES time_season(season), + segment_fraction REAL NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) + PRIMARY KEY (seas_seq), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) ); CREATE TABLE IF NOT EXISTS myopic_efficiency diff --git a/temoa/_internal/exchange_tech_cost_ledger.py b/temoa/_internal/exchange_tech_cost_ledger.py index cf90257eb..12b170f5f 100644 --- a/temoa/_internal/exchange_tech_cost_ledger.py +++ b/temoa/_internal/exchange_tech_cost_ledger.py @@ -90,7 +90,7 @@ def get_use_ratio( act_dir1 = value( sum( model.v_flow_out[rr1, period, s, d, s_i, tech, vintage, s_o] - for s in model.time_season[period] + for s in model.time_season for d in model.time_of_day for s_i in model.process_inputs[rr1, period, tech, vintage] for s_o in model.process_outputs_by_input[rr1, period, tech, vintage, s_i] @@ -99,7 +99,7 @@ def get_use_ratio( act_dir2 = value( sum( model.v_flow_out[rr2, period, s, d, s_i, tech, vintage, s_o] - for s in model.time_season[period] + for s in model.time_season for d in model.time_of_day for s_i in model.process_inputs[rr2, period, tech, vintage] for s_o in model.process_outputs_by_input[rr2, period, tech, vintage, s_i] diff --git a/temoa/_internal/table_data_puller.py b/temoa/_internal/table_data_puller.py index 4dff3ea02..968a0ba79 100644 --- a/temoa/_internal/table_data_puller.py +++ b/temoa/_internal/table_data_puller.py @@ -186,12 +186,12 @@ def poll_flow_results(model: TemoaModel, epsilon: float = 1e-5) -> dict[FI, dict # Make sure this isn't just a non-annual demand tech if t not in model.tech_annual: continue - for s in model.time_season[p]: + for s in model.time_season: for d in model.time_of_day: if o in model.commodity_demand: - distribution = value(model.demand_specific_distribution[r, p, s, d, o]) + distribution = value(model.demand_specific_distribution[r, s, d, o]) else: - distribution = value(model.segment_fraction[p, s, d]) + distribution = value(model.segment_fraction[s, d]) fi = FI(r, p, s, d, i, t, v, o) flow = value(model.v_flow_out_annual[r, p, i, t, v, o]) * distribution if abs(flow) < epsilon: @@ -204,11 +204,11 @@ def poll_flow_results(model: TemoaModel, epsilon: float = 1e-5) -> dict[FI, dict # flex annual for r, p, i, t, v, o in model.v_flex_annual.keys(): - for s in model.time_season[p]: + for s in model.time_season: for d in model.time_of_day: fi = FI(r, p, s, d, i, t, v, o) flow = value(model.v_flex_annual[r, p, i, t, v, o]) * value( - model.segment_fraction[p, s, d] + model.segment_fraction[s, d] ) if abs(flow) < epsilon: continue @@ -222,10 +222,10 @@ def poll_flow_results(model: TemoaModel, epsilon: float = 1e-5) -> dict[FI, dict * value(model.v_new_capacity[r, t, v]) / value(model.period_length[v]) ) - for s in model.time_season[v]: + for s in model.time_season: for d in model.time_of_day: fi = FI(r, v, s, d, i, t, v, cast('Commodity', None)) - flow = annual * value(model.segment_fraction[v, s, d]) + flow = annual * value(model.segment_fraction[s, d]) if abs(flow) < epsilon: continue res[fi][FlowType.IN] = flow @@ -238,10 +238,10 @@ def poll_flow_results(model: TemoaModel, epsilon: float = 1e-5) -> dict[FI, dict annual = value(model.end_of_life_output[r, t, v, o]) * value( model.v_annual_retirement[r, p, t, v] ) - for s in model.time_season[p]: + for s in model.time_season: for d in model.time_of_day: fi = FI(r, p, s, d, cast('Commodity', None), t, v, o) - flow = annual * value(model.segment_fraction[p, s, d]) + flow = annual * value(model.segment_fraction[s, d]) if abs(flow) < epsilon: continue res[fi][FlowType.OUT] = flow @@ -263,7 +263,7 @@ def poll_storage_level_results(model: TemoaModel, epsilon: float = 1e-5) -> dict if t in model.tech_seasonal_storage: continue state = value(model.v_storage_level[r, p, s, d, t, v]) / ( - value(model.segment_fraction_per_season[p, s]) * value(model.days_per_period) + value(model.segment_fraction_per_season[s]) * value(model.days_per_period) ) sli = SLI(r, p, s, d, t, v) if abs(state) < epsilon: @@ -271,12 +271,12 @@ def poll_storage_level_results(model: TemoaModel, epsilon: float = 1e-5) -> dict res[sli] = state for r, p, s_seq, t, v in model.seasonal_storage_level_rpstv: - s = model.sequential_to_season[p, s_seq] + s = model.sequential_to_season[s_seq] # Ratio of days in virtual storage season to days in actual season # Flows and StorageLevel are normalised to the number of days in the ACTUAL season, so must # be adjusted to the number of days in the virtual storage season - days_adjust = value(model.time_season_sequential[p, s_seq, s]) / ( - value(model.segment_fraction_per_season[p, s]) * value(model.days_per_period) + days_adjust = value(model.segment_fraction_per_sequential_season[s_seq]) / value( + model.segment_fraction_per_season[s] ) for d in model.time_of_day: state = ( @@ -442,7 +442,7 @@ def poll_cost_results( value(model.v_flow_out[r, p, S_s, S_d, S_i, t, v, S_o]) for S_i in model.process_inputs[r, p, t, v] for S_o in model.process_outputs_by_input[r, p, t, v, S_i] - for S_s in model.time_season[p] + for S_s in model.time_season for S_d in model.time_of_day ) else: @@ -631,7 +631,7 @@ def poll_emissions( normal = [ (r, p, e, s, d, i, t, v, o) for (r, p, e, i, t, v, o) in base - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day if t not in model.tech_annual ] diff --git a/temoa/components/capacity.py b/temoa/components/capacity.py index e9c61314a..f5d19a481 100644 --- a/temoa/components/capacity.py +++ b/temoa/components/capacity.py @@ -40,29 +40,35 @@ def check_capacity_factor_process(model: TemoaModel) -> None: - count_rptv: dict[tuple[Region, Period, Technology, Vintage], int] = {} + # Count of capacity factor process entries for this process in this region + count_rtv: dict[tuple[Region, Technology, Vintage], int] = {} + # Pull capacity_factor_tech by default - for r, p, _s, _d, t in model.capacity_factor_rpsdt: - for v in model.process_vintages[r, p, t]: - model.is_capacity_factor_process[r, p, t, v] = False - count_rptv[r, p, t, v] = 0 + unique_rt = {(r, t) for r, _s, _d, t in model.capacity_factor_rsdt} + for r, t in unique_rt: + for p in model.time_optimize: + for v in model.process_vintages.get((r, p, t), []): + if (r, t, v) not in count_rtv: + model.is_capacity_factor_process[r, t, v] = False + count_rtv[r, t, v] = 0 # Check for bad values and count up the good ones - for r, p, _s, _d, t, v in model.capacity_factor_process.sparse_iterkeys(): - if v not in model.process_vintages[r, p, t]: - msg = f'Invalid process {p, v} for {r, t} in capacity_factor_process table' + for r, _s, _d, t, v in model.capacity_factor_process.sparse_iterkeys(): + # Validate that vintage is active for some period + if not model.process_periods.get((r, t, v)): + msg = f'Invalid vintage {v} for {r, t} in capacity_factor_process table' logger.error(msg) raise ValueError(msg) # Good value, pull from capacity_factor_process table - count_rptv[r, p, t, v] += 1 + count_rtv[r, t, v] += 1 # Check if all possible values have been set by process # log a warning if some are missing (allowed but maybe accidental) - for (r, p, t, v), count in count_rptv.items(): - num_seg = len(model.time_season[p]) * len(model.time_of_day) + for (r, t, v), count in count_rtv.items(): + num_seg = len(model.time_season) * len(model.time_of_day) if count > 0: - model.is_capacity_factor_process[r, p, t, v] = True + model.is_capacity_factor_process[r, t, v] = True if count < num_seg: logger.info( 'Some but not all processes were set in capacity_factor_process (%i out of a ' @@ -70,7 +76,7 @@ def check_capacity_factor_process(model: TemoaModel) -> None: 'value or 1 if that is not set either.', count, num_seg, - (r, p, t, v), + (r, t, v), ) @@ -85,13 +91,12 @@ def create_capacity_factors(model: TemoaModel) -> None: capacity_factor_process = model.capacity_factor_process # Step 1 - processes = {(r, t, v) for r, i, t, v, o in model.efficiency.sparse_iterkeys()} + processes = {(r, t, v) for r, _i, t, v, _o in model.efficiency.sparse_iterkeys()} all_cfs = { - (r, p, s, d, t, v) + (r, s, d, t, v) for (r, t, v) in processes - for p in model.process_periods[r, t, v] - for s, d in cross_product(model.time_season[p], model.time_of_day) + for s, d in cross_product(model.time_season, model.time_of_day) } # Step 2 @@ -106,8 +111,8 @@ def create_capacity_factors(model: TemoaModel) -> None: if unspecified_cfs: # CFP._constructed = False - for r, p, s, d, t, v in unspecified_cfs: - capacity_factor_process[r, p, s, d, t, v] = model.capacity_factor_tech[r, p, s, d, t] + for r, s, d, t, v in unspecified_cfs: + capacity_factor_process[r, s, d, t, v] = model.capacity_factor_tech[r, s, d, t] logger.debug( 'Created Capacity Factors for %d processes without an explicit specification', len(unspecified_cfs), @@ -116,7 +121,7 @@ def create_capacity_factors(model: TemoaModel) -> None: def get_default_capacity_factor( - model: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage + model: TemoaModel, r: Region, s: Season, d: TimeOfDay, t: Technology, v: Vintage ) -> float: """ This initializer is used to fill the capacity_factor_process from the capacity_factor_tech @@ -134,16 +139,16 @@ def get_default_capacity_factor( :param v: vintage :return: the capacity factor """ - return value(model.capacity_factor_tech[r, p, s, d, t]) + return value(model.capacity_factor_tech[r, s, d, t]) def get_capacity_factor( - model: TemoaModel, r: Region, p: Period, s: Season, d: TimeOfDay, t: Technology, v: Vintage + model: TemoaModel, r: Region, s: Season, d: TimeOfDay, t: Technology, v: Vintage ) -> float: - if model.is_capacity_factor_process[r, p, t, v]: - return value(model.capacity_factor_process[r, p, s, d, t, v]) + if model.is_capacity_factor_process[r, t, v]: + return value(model.capacity_factor_process[r, s, d, t, v]) else: - return value(model.capacity_factor_tech[r, p, s, d, t]) + return value(model.capacity_factor_tech[r, s, d, t]) # ============================================================================ @@ -220,7 +225,7 @@ def capacity_constraint_indices( if t not in model.tech_annual or t in model.tech_demand: if t not in model.tech_uncap: if t not in model.tech_storage: - for s in model.time_season[p]: + for s in model.time_season: for d in model.time_of_day: capacity_indices.add((r, p, s, d, t, v)) else: @@ -235,22 +240,21 @@ def capacity_factor_process_indices( ) -> set[tuple[Region, Season, TimeOfDay, Technology, Vintage]]: indices: set[tuple[Region, Season, TimeOfDay, Technology, Vintage]] = set() for r, _i, t, v, _o in model.efficiency.sparse_iterkeys(): - for p in model.time_optimize: - for s in model.time_season[p]: - for d in model.time_of_day: - indices.add((r, s, d, t, v)) + for s in model.time_season: + for d in model.time_of_day: + indices.add((r, s, d, t, v)) return indices def capacity_factor_tech_indices( model: TemoaModel, -) -> set[tuple[Region, Period, Season, TimeOfDay, Technology]]: - all_cfs: set[tuple[Region, Period, Season, TimeOfDay, Technology]] = set() - if model.active_capacity_available_rpt: - for r, p, t in model.active_capacity_available_rpt: - for s in model.time_season[p]: +) -> set[tuple[Region, Season, TimeOfDay, Technology]]: + all_cfs: set[tuple[Region, Season, TimeOfDay, Technology]] = set() + if model.active_capacity_available_rpt: # in case every tech in the model is unlim_cap + for r, _p, t in model.active_capacity_available_rpt: + for s in model.time_season: for d in model.time_of_day: - all_cfs.add((r, p, s, d, t)) + all_cfs.add((r, s, d, t)) else: return set() return all_cfs @@ -445,9 +449,9 @@ def capacity_constraint( # Annual demand technology useful_activity = sum( ( - value(model.demand_specific_distribution[r, p, s, d, S_o]) + value(model.demand_specific_distribution[r, s, d, S_o]) if S_o in model.commodity_demand - else value(model.segment_fraction[p, s, d]) + else value(model.segment_fraction[s, d]) ) * model.v_flow_out_annual[r, p, S_i, t, v, S_o] for S_i in model.process_inputs[r, p, t, v] @@ -463,9 +467,9 @@ def capacity_constraint( if t in model.tech_curtailment: # If technologies are present in the curtailment set, then enough # capacity must be available to cover both activity and curtailment. - return get_capacity_factor(model, r, p, s, d, t, v) * value( + return get_capacity_factor(model, r, s, d, t, v) * value( model.capacity_to_activity[r, t] - ) * value(model.segment_fraction[p, s, d]) * model.v_capacity[ + ) * value(model.segment_fraction[s, d]) * model.v_capacity[ r, p, t, v ] == useful_activity + sum( model.v_curtailment[r, p, s, d, S_i, t, v, S_o] @@ -474,9 +478,9 @@ def capacity_constraint( ) else: return ( - get_capacity_factor(model, r, p, s, d, t, v) + get_capacity_factor(model, r, s, d, t, v) * value(model.capacity_to_activity[r, t]) - * value(model.segment_fraction[p, s, d]) + * value(model.segment_fraction[s, d]) * model.v_capacity[r, p, t, v] >= useful_activity ) diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index f75e4e6b3..2058d469d 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -116,8 +116,8 @@ def check_singleton_demands(model: TemoaModel) -> None: i, t, v = next(iter(upstream_itv)) model.v_flow_out_annual[r, p, i, t, v, dem].fix(val) if t not in model.tech_annual: - for s, d in cross_product(model.time_season[p], model.time_of_day): - dsd = value(model.demand_specific_distribution[r, p, s, d, dem]) + for s, d in cross_product(model.time_season, model.time_of_day): + dsd = value(model.demand_specific_distribution[r, s, d, dem]) model.v_flow_out[r, p, s, d, i, t, v, dem].fix(val * dsd) model.singleton_demands.add((r, p, dem)) @@ -142,7 +142,7 @@ def demand_activity_constraint_indices( if (r, p, dem) not in model.singleton_demands for t, v in model.commodity_up_stream_process[r, p, dem] if t not in model.tech_annual - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day } return indices @@ -159,7 +159,7 @@ def commodity_balance_constraint_indices( # r in this line includes interregional transfer combinations (not needed). if r in model.regions # this line ensures only the regions are included. and c not in model.commodity_annual - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day } @@ -279,7 +279,7 @@ def demand_activity_constraint( for s_i in model.process_inputs_by_output[r, p, t, v, dem] ) - expr = annual_activity * value(model.demand_specific_distribution[r, p, s, d, dem]) == activity + expr = annual_activity * value(model.demand_specific_distribution[r, s, d, dem]) == activity return expr @@ -416,9 +416,9 @@ def commodity_balance_constraint( # Into annual flows consumed += sum( ( - value(model.demand_specific_distribution[r, p, s, d, s_o]) + value(model.demand_specific_distribution[r, s, d, s_o]) if s_o in model.commodity_demand - else value(model.segment_fraction[p, s, d]) + else value(model.segment_fraction[s, d]) ) * model.v_flow_out_annual[r, p, c, s_t, s_v, s_o] / get_variable_efficiency(model, r, p, s, d, c, s_t, s_v, s_o) @@ -431,7 +431,7 @@ def commodity_balance_constraint( # Consumed by building capacity # Assume evenly distributed over a year consumed += ( - value(model.segment_fraction[p, s, d]) + value(model.segment_fraction[s, d]) * sum( value(model.construction_input[r, c, s_t, p]) * model.v_new_capacity[r, s_t, p] for s_t in model.capacity_consumption_techs[r, p, c] @@ -449,7 +449,7 @@ def commodity_balance_constraint( ) # From annual flows - produced += value(model.segment_fraction[p, s, d]) * sum( + produced += value(model.segment_fraction[s, d]) * sum( model.v_flow_out_annual[r, p, s_i, s_t, s_v, c] for s_t, s_v in model.commodity_up_stream_process[r, p, c] if s_t in model.tech_annual @@ -465,7 +465,7 @@ def commodity_balance_constraint( for s_i in model.process_inputs_by_output[r, p, s_t, s_v, c] ) # Wasted by annual flex flows - consumed += value(model.segment_fraction[p, s, d]) * sum( + consumed += value(model.segment_fraction[s, d]) * sum( model.v_flex_annual[r, p, s_i, s_t, s_v, c] for s_t, s_v in model.commodity_up_stream_process[r, p, c] if s_t in model.tech_annual and s_t in model.tech_flex @@ -475,7 +475,7 @@ def commodity_balance_constraint( if (r, p, c) in model.retirement_production_processes: # Produced by retiring capacity # Assume evenly distributed over a year - produced += value(model.segment_fraction[p, s, d]) * sum( + produced += value(model.segment_fraction[s, d]) * sum( value(model.end_of_life_output[r, s_t, s_v, c]) * model.v_annual_retirement[r, p, s_t, s_v] for s_t, s_v in model.retirement_production_processes[r, p, c] @@ -492,7 +492,7 @@ def commodity_balance_constraint( if s_t not in model.tech_annual ) consumed += sum( - value(model.segment_fraction[p, s, d]) + value(model.segment_fraction[s, d]) * model.v_flow_out_annual[r + '-' + reg, p, c, s_t, s_v, S_o] / get_variable_efficiency( model, cast('Region', r + '-' + reg), p, s, d, c, s_t, s_v, S_o @@ -509,7 +509,7 @@ def commodity_balance_constraint( if s_t not in model.tech_annual ) produced += sum( - value(model.segment_fraction[p, s, d]) + value(model.segment_fraction[s, d]) * model.v_flow_out_annual[reg + '-' + r, p, s_i, s_t, s_v, c] for reg, s_t, s_v, s_i in model.import_regions[r, p, c] if s_t in model.tech_annual @@ -550,7 +550,7 @@ def annual_commodity_balance_constraint( # For other techs, it would be redundant as in = out / eff consumed += sum( model.v_flow_in[r, p, s_s, s_d, c, s_t, s_v, s_o] - for s_s in model.time_season[p] + for s_s in model.time_season for s_d in model.time_of_day for s_t, s_v in model.commodity_down_stream_process[r, p, c] if s_t in model.tech_storage @@ -560,7 +560,7 @@ def annual_commodity_balance_constraint( consumed += sum( model.v_flow_out[r, p, s_s, s_d, c, s_t, s_v, s_o] / get_variable_efficiency(model, r, p, s_s, s_d, c, s_t, s_v, s_o) - for s_s in model.time_season[p] + for s_s in model.time_season for s_d in model.time_of_day for s_t, s_v in model.commodity_down_stream_process[r, p, c] if s_t not in model.tech_storage and s_t not in model.tech_annual @@ -590,7 +590,7 @@ def annual_commodity_balance_constraint( # Includes output from storage produced += sum( model.v_flow_out[r, p, s_s, s_d, s_i, s_t, s_v, c] - for s_s in model.time_season[p] + for s_s in model.time_season for s_d in model.time_of_day for s_t, s_v in model.commodity_up_stream_process[r, p, c] if s_t not in model.tech_annual @@ -607,7 +607,7 @@ def annual_commodity_balance_constraint( if c in model.commodity_flex: consumed += sum( model.v_flex[r, p, s_s, s_d, s_i, s_t, s_v, c] - for s_s in model.time_season[p] + for s_s in model.time_season for s_d in model.time_of_day for s_t, s_v in model.commodity_up_stream_process[r, p, c] if s_t not in model.tech_annual and s_t in model.tech_flex @@ -636,7 +636,7 @@ def annual_commodity_balance_constraint( / get_variable_efficiency( model, cast('Region', r + '-' + s_r), p, s_s, s_d, c, s_t, s_v, s_o ) - for s_s in model.time_season[p] + for s_s in model.time_season for s_d in model.time_of_day for s_r, s_t, s_v, s_o in model.export_regions[r, p, c] if s_t not in model.tech_annual @@ -652,7 +652,7 @@ def annual_commodity_balance_constraint( if (r, p, c) in model.import_regions: produced += sum( model.v_flow_out[cast('Region', s_r + '-' + r), p, s_s, S_d, s_i, s_t, s_v, c] - for s_s in model.time_season[p] + for s_s in model.time_season for S_d in model.time_of_day for s_r, s_t, s_v, s_i in model.import_regions[r, p, c] if s_t not in model.tech_annual @@ -722,14 +722,13 @@ def create_demands(model: TemoaModel) -> None: logger.debug('Started creating demand distributions in CreateDemands()') # Step 0: some setup for a couple of reusable items - # Get the nth element from the tuple (r, p, s, d, dem) + # Get the nth element from the tuple (r, s, d, dem) # So we only have to update these indices in one place if they change demand_specific_distribution_region = iget(0) - demand_specific_distribution_period = iget(1) - demand_specific_distributon_dem = iget(4) + demand_specific_distributon_dem = iget(3) # Step 1: Check if any demand commodities are going unused - used_dems = {dem for r, p, dem in model.demand.sparse_iterkeys()} + used_dems = {dem for _r, _p, dem in model.demand.sparse_iterkeys()} unused_dems = sorted(model.commodity_demand.difference(used_dems)) if unused_dems: for dem in unused_dems: @@ -792,46 +791,43 @@ def create_demands(model: TemoaModel) -> None: ) # the demands not mentioned in DSD *at all* if unset_demand_distributions: - for p in model.time_optimize: - unset_distributions = set( - cross_product( - model.regions, - (p,), - model.time_season[p], - model.time_of_day, - unset_demand_distributions, - ) + unset_distributions = set( + cross_product( + model.regions, + model.time_season, + model.time_of_day, + unset_demand_distributions, ) - for r, p, s, d, dem in unset_distributions: - demand_specific_distribution[r, p, s, d, dem] = value( - model.segment_fraction[p, s, d] - ) # DSD._constructed = True + ) + for r, s, d, dem in unset_distributions: + demand_specific_distribution[r, s, d, dem] = value( + model.segment_fraction[s, d] + ) # DSD._constructed = True # Step 5: A final "sum to 1" check for all DSD members (which now should be everything) # Also check that all keys are made... The demand distro should be supported # by the full set of (r, p, dem) keys because it is an equality constraint # and we need to ensure even the zeros are passed in - used_rp_dems = {(r, p, dem) for r, p, dem in model.demand.sparse_iterkeys()} - for r, p, dem in used_rp_dems: - expected_key_length = len(model.time_season[p]) * len(model.time_of_day) + used_r_dems = {(r, dem) for r, p, dem in model.demand.sparse_iterkeys()} + for r, dem in used_r_dems: + expected_key_length = len(model.time_season) * len(model.time_of_day) keys = [ k for k in demand_specific_distribution.sparse_iterkeys() if demand_specific_distribution_region(k) == r - and demand_specific_distribution_period(k) == p and demand_specific_distributon_dem(k) == dem ] if len(keys) != expected_key_length: # this could be very slow but only calls when there's a problem missing = { (s, d) - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day - if (r, p, s, d, dem) not in keys + if (r, s, d, dem) not in keys } logger.info( 'Missing some time slices for Demand Specific Distribution %s: %s', - (r, p, dem), + (r, dem), missing, ) total = sum(value(demand_specific_distribution[i]) for i in keys) @@ -859,7 +855,7 @@ def get_str_padding(obj: Any) -> int: 'must total to 1.\n\n Demand-specific distribution in error: ' ' \n {}\n\tsum = {}' ) - logger.error(msg.format((r, p, dem), items, total)) - raise ValueError(msg.format((r, p, dem), items, total)) + logger.error(msg.format((r, dem), items, total)) + raise ValueError(msg.format((r, dem), items, total)) logger.debug('Finished creating demand distributions') diff --git a/temoa/components/costs.py b/temoa/components/costs.py index cd22729cc..1ecf165bd 100644 --- a/temoa/components/costs.py +++ b/temoa/components/costs.py @@ -382,7 +382,7 @@ def period_cost_rule(model: TemoaModel, p: int) -> float | Expression: if S_p == p and S_t not in model.tech_annual for S_i in model.process_inputs[r, S_p, S_t, S_v] for S_o in model.process_outputs_by_input[r, S_p, S_t, S_v, S_i] - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day ) @@ -426,7 +426,7 @@ def period_cost_rule(model: TemoaModel, p: int) -> float | Expression: normal = [ (r, p, e, s, d, i, t, v, o) for (r, p, e, i, t, v, o) in base - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day if t not in model.tech_annual ] diff --git a/temoa/components/emissions.py b/temoa/components/emissions.py index 03e9a9c45..05cae02f3 100644 --- a/temoa/components/emissions.py +++ b/temoa/components/emissions.py @@ -58,7 +58,7 @@ def linked_tech_constraint_indices( if (r, p, t) in model.process_vintages for v in model.process_vintages[r, p, t] if model.active_activity_rptv and (r, p, t, v) in model.active_activity_rptv - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day } @@ -106,9 +106,9 @@ def linked_emissions_tech_constraint( if t in model.tech_annual: primary_flow = quicksum( ( - value(model.demand_specific_distribution[r, p, s, d, S_o]) + value(model.demand_specific_distribution[r, s, d, S_o]) if S_o in model.commodity_demand - else value(model.segment_fraction[p, s, d]) + else value(model.segment_fraction[s, d]) ) * model.v_flow_out_annual[r, p, S_i, t, v, S_o] * value(model.emission_activity[r, e, S_i, t, v, S_o]) @@ -134,9 +134,9 @@ def linked_emissions_tech_constraint( if linked_t in model.tech_annual: linked_flow = quicksum( ( - value(model.demand_specific_distribution[r, p, s, d, S_o]) + value(model.demand_specific_distribution[r, s, d, S_o]) if S_o in model.commodity_demand - else value(model.segment_fraction[p, s, d]) + else value(model.segment_fraction[s, d]) ) * model.v_flow_out_annual[r, p, S_i, linked_t, v, S_o] for S_i in model.process_inputs[r, p, linked_t, v] diff --git a/temoa/components/flows.py b/temoa/components/flows.py index 04194faa4..a6db3e9a6 100644 --- a/temoa/components/flows.py +++ b/temoa/components/flows.py @@ -138,7 +138,7 @@ def create_commodity_balance_and_flow_sets(model: TemoaModel) -> None: for v in model.process_vintages[r, p, t] for i in model.process_inputs.get((r, p, t, v), set()) for o in model.process_outputs_by_input.get((r, p, t, v, i), set()) - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day } @@ -160,7 +160,7 @@ def create_commodity_balance_and_flow_sets(model: TemoaModel) -> None: for v in model.process_vintages[r, p, t] for i in model.process_inputs.get((r, p, t, v), set()) for o in model.process_outputs_by_input.get((r, p, t, v, i), set()) - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day } @@ -180,7 +180,7 @@ def create_commodity_balance_and_flow_sets(model: TemoaModel) -> None: for v in model.storage_vintages[r, p, t] for i in model.process_inputs.get((r, p, t, v), set()) for o in model.process_outputs_by_input.get((r, p, t, v, i), set()) - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day } @@ -190,7 +190,7 @@ def create_commodity_balance_and_flow_sets(model: TemoaModel) -> None: for v in model.curtailment_vintages[r, p, t] for i in model.process_inputs.get((r, p, t, v), set()) for o in model.process_outputs_by_input.get((r, p, t, v, i), set()) - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day } @@ -204,15 +204,14 @@ def create_commodity_balance_and_flow_sets(model: TemoaModel) -> None: (r, p, s, d, t, v) for r, p, t in model.storage_vintages for v in model.storage_vintages[r, p, t] - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day } model.seasonal_storage_level_indices_rpstv = { - (r, p, s_stor, t, v) + (r, p, s_seq, t, v) for r, p, t in model.storage_vintages if t in model.tech_seasonal_storage for v in model.storage_vintages[r, p, t] - for _p, s_stor in model.sequential_to_season - if _p == p + for s_seq in model.sequential_to_season } diff --git a/temoa/components/limits.py b/temoa/components/limits.py index ff806e286..52eef6d8e 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -44,7 +44,7 @@ def limit_tech_input_split_constraint_indices( for r, p, i, t, op in model.input_split_vintages if t not in model.tech_annual for v in model.input_split_vintages[r, p, i, t, op] - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day } ann_indices = { @@ -94,7 +94,7 @@ def limit_tech_output_split_constraint_indices( for r, p, t, o, op in model.output_split_vintages if t not in model.tech_annual for v in model.output_split_vintages[r, p, t, o, op] - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day } ann_indices = { @@ -199,6 +199,17 @@ def limit_degrowth_new_capacity_delta_indices( return indices +def limit_seasonal_capacity_factor_constraint_indices( + model: TemoaModel, +) -> set[tuple[Region, Period, Season, Technology, str]]: + """Expand the period-free param set to include all time_optimize periods.""" + return { + (r, p, s, t, op) + for r, s, t, op in model.limit_seasonal_capacity_factor_constraint_rst + for p in model.time_optimize + } + + def limit_annual_capacity_factor_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Technology, Vintage, Commodity, str]]: @@ -235,7 +246,7 @@ def renewable_portfolio_standard_constraint( for t in model.tech_group_members[g] for (_t, v) in model.process_reserve_periods.get((r, p), []) if _t == t - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day for S_i in model.process_inputs[r, p, t, v] for S_o in model.process_outputs_by_input[r, p, t, v, S_i] @@ -244,7 +255,7 @@ def renewable_portfolio_standard_constraint( total_inp = quicksum( model.v_flow_out[r, p, s, d, S_i, t, v, S_o] for (t, v) in model.process_reserve_periods[r, p] - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day for S_i in model.process_inputs[r, p, t, v] for S_o in model.process_outputs_by_input[r, p, t, v, S_i] @@ -300,7 +311,7 @@ def limit_resource_constraint(model: TemoaModel, r: Region, t: Technology, op: s for S_v in model.process_vintages[_r, p, _t] for S_i in model.process_inputs[_r, p, _t, S_v] for S_o in model.process_outputs_by_input[_r, p, _t, S_v, S_i] - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day ) @@ -340,7 +351,7 @@ def limit_activity_share_constraint( for S_v in model.process_vintages.get((_r, p, S_t), []) for S_i in model.process_inputs[_r, p, S_t, S_v] for S_o in model.process_outputs_by_input[_r, p, S_t, S_v, S_i] - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day ) sub_activity += quicksum( @@ -362,7 +373,7 @@ def limit_activity_share_constraint( for S_v in model.process_vintages.get((_r, p, S_t), []) for S_i in model.process_inputs[_r, p, S_t, S_v] for S_o in model.process_outputs_by_input[_r, p, S_t, S_v, S_i] - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day ) super_activity += quicksum( @@ -496,7 +507,7 @@ def limit_annual_capacity_factor_constraint( model.v_flow_out[_r, p, s, d, S_i, _t, v, o] for _r in regions for S_i in model.process_inputs_by_output.get((_r, p, _t, v, o), []) - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day ) else: @@ -576,7 +587,7 @@ def limit_seasonal_capacity_factor_constraint( else: activity_rpst += quicksum( model.v_flow_out_annual[_r, p, S_i, _t, S_v, S_o] - * model.segment_fraction_per_season[p, s] + * model.segment_fraction_per_season[s] for _r in regions for S_v in model.process_vintages.get((_r, p, _t), []) for S_i in model.process_inputs.get((_r, p, _t, S_v), []) @@ -586,12 +597,12 @@ def limit_seasonal_capacity_factor_constraint( possible_activity_rpst = quicksum( model.v_capacity_available_by_period_and_tech[_r, p, _t] * value(model.capacity_to_activity[_r, _t]) - * value(model.segment_fraction_per_season[p, s]) + * value(model.segment_fraction_per_season[s]) for _r in regions for _t in techs if (_r, p, _t) in model.v_capacity_available_by_period_and_tech ) - seasonal_cf = value(model.limit_seasonal_capacity_factor[r, p, s, t, op]) + seasonal_cf = value(model.limit_seasonal_capacity_factor[r, s, t, op]) expr = operator_expression(activity_rpst, Operator(op), seasonal_cf * possible_activity_rpst) # in the case that there is nothing to sum, skip if isinstance(expr, bool): # an empty list was generated @@ -675,14 +686,14 @@ def limit_tech_input_split_average_constraint( inp = quicksum( model.v_flow_out[r, p, S_s, S_d, i, t, v, S_o] / get_variable_efficiency(model, r, p, S_s, S_d, i, t, v, S_o) - for S_s in model.time_season[p] + for S_s in model.time_season for S_d in model.time_of_day for S_o in model.process_outputs_by_input[r, p, t, v, i] ) total_inp = quicksum( model.v_flow_out[r, p, S_s, S_d, S_i, t, v, S_o] / get_variable_efficiency(model, r, p, S_s, S_d, S_i, t, v, S_o) - for S_s in model.time_season[p] + for S_s in model.time_season for S_d in model.time_of_day for S_i in model.process_inputs[r, p, t, v] for S_o in model.process_outputs_by_input[r, p, t, v, S_i] @@ -805,7 +816,7 @@ def limit_tech_output_split_average_constraint( out = quicksum( model.v_flow_out[r, p, S_s, S_d, S_i, t, v, o] for S_i in model.process_inputs_by_output[r, p, t, v, o] - for S_s in model.time_season[p] + for S_s in model.time_season for S_d in model.time_of_day ) @@ -813,7 +824,7 @@ def limit_tech_output_split_average_constraint( model.v_flow_out[r, p, S_s, S_d, S_i, t, v, S_o] for S_i in model.process_inputs[r, p, t, v] for S_o in model.process_outputs_by_input[r, p, t, v, S_i] - for S_s in model.time_season[p] + for S_s in model.time_season for S_d in model.time_of_day ) @@ -877,7 +888,7 @@ def limit_emission_constraint( if tmp_e == e and tmp_r == reg and S_t not in model.tech_annual # EmissionsActivity not indexed by p, so make sure (r,p,t,v) combos valid if (reg, p, S_t, S_v) in model.process_inputs - for S_s in model.time_season[p] + for S_s in model.time_season for S_d in model.time_of_day ) @@ -1350,7 +1361,7 @@ def limit_activity_constraint( for S_v in model.process_vintages.get((_r, p, _t), []) for S_i in model.process_inputs[_r, p, _t, S_v] for S_o in model.process_outputs_by_input[_r, p, _t, S_v, S_i] - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day ) activity += quicksum( diff --git a/temoa/components/operations.py b/temoa/components/operations.py index bcfe03563..8274d6906 100644 --- a/temoa/components/operations.py +++ b/temoa/components/operations.py @@ -36,7 +36,7 @@ def baseload_diurnal_constraint_indices( (r, p, s, d, t, v) for r, p, t in model.baseload_vintages for v in model.baseload_vintages[r, p, t] - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day } @@ -50,7 +50,7 @@ def ramp_up_day_constraint_indices( (r, p, s, d, t, v) for r, p, t in model.ramp_up_vintages for v in model.ramp_up_vintages[r, p, t] - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day } @@ -64,7 +64,7 @@ def ramp_down_day_constraint_indices( (r, p, s, d, t, v) for r, p, t in model.ramp_down_vintages for v in model.ramp_down_vintages[r, p, t] - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day } @@ -84,10 +84,9 @@ def ramp_up_season_constraint_indices( (r, p, s, s_next, t, v) for r, p, t in model.ramp_up_vintages for v in model.ramp_up_vintages[r, p, t] - for _p, s_seq, s in model.ordered_season_sequential - if _p == p - for s_next in (model.sequential_to_season[p, model.time_next_sequential[p, s_seq]],) - if s_next != model.time_next[p, s, model.time_of_day.last()][0] + for s_seq, s in model.ordered_season_sequential + for s_next in (model.sequential_to_season[model.time_next_sequential[s_seq]],) + if s_next != model.time_next[s, model.time_of_day.last()][0] } return indices @@ -106,10 +105,9 @@ def ramp_down_season_constraint_indices( (r, p, s, s_next, t, v) for r, p, t in model.ramp_down_vintages for v in model.ramp_down_vintages[r, p, t] - for _p, s_seq, s in model.ordered_season_sequential - if _p == p - for s_next in (model.sequential_to_season[p, model.time_next_sequential[p, s_seq]],) - if s_next != model.time_next[p, s, model.time_of_day.last()][0] + for s_seq, s in model.ordered_season_sequential + for s_next in (model.sequential_to_season[model.time_next_sequential[s_seq]],) + if s_next != model.time_next[s, model.time_of_day.last()][0] } return indices @@ -192,8 +190,8 @@ def baseload_diurnal_constraint( for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) - expr = activity_sd * value(model.segment_fraction[p, s, d_0]) == activity_sd_0 * value( - model.segment_fraction[p, s, d] + expr = activity_sd * value(model.segment_fraction[s, d_0]) == activity_sd_0 * value( + model.segment_fraction[s, d] ) return expr @@ -301,12 +299,12 @@ def ramp_up_day_constraint( - :math:`CAP \cdot C2A` gives the maximum hourly change in activity """ - s_next, d_next = model.time_next[p, s, d] + s_next, d_next = model.time_next[s, d] # How many hours does this time slice represent - hours_adjust = value(model.segment_fraction[p, s, d]) * value(model.days_per_period) * 24 + hours_adjust = value(model.segment_fraction[s, d]) * value(model.days_per_period) * 24 hours_adjust_next = ( - value(model.segment_fraction[p, s_next, d_next]) * value(model.days_per_period) * 24 + value(model.segment_fraction[s_next, d_next]) * value(model.days_per_period) * 24 ) hourly_activity_sd = ( @@ -328,15 +326,7 @@ def ramp_up_day_constraint( ) # elapsed hours from middle of this time slice to middle of next time slice - hours_elapsed = ( - 24 - / 2 - * ( - value(model.segment_fraction[p, s, d]) / value(model.segment_fraction_per_season[p, s]) - + value(model.segment_fraction[p, s_next, d_next]) - / value(model.segment_fraction_per_season[p, s_next]) - ) - ) + hours_elapsed = (model.time_of_day_hours[d] + model.time_of_day_hours[d_next]) / 2 ramp_fraction = hours_elapsed * value(model.ramp_up_hourly[r, t]) if ramp_fraction >= 1: @@ -350,7 +340,10 @@ def ramp_up_day_constraint( activity_increase = hourly_activity_sd_next - hourly_activity_sd # opposite sign from rampdown rampable_activity = ( - ramp_fraction * model.v_capacity[r, p, t, v] * value(model.capacity_to_activity[r, t]) + ramp_fraction + * model.v_capacity[r, p, t, v] + * value(model.capacity_to_activity[r, t]) + / (24 * value(model.days_per_period)) # adjust capacity to hourly basis ) expr = activity_increase <= rampable_activity @@ -391,12 +384,12 @@ def ramp_down_day_constraint( \forall \{r, p, s, d, t, v\} \in \Theta_{\text{ramp\_down\_day}} """ - s_next, d_next = model.time_next[p, s, d] + s_next, d_next = model.time_next[s, d] # How many hours does this time slice represent - hours_adjust = value(model.segment_fraction[p, s, d]) * value(model.days_per_period) * 24 + hours_adjust = value(model.segment_fraction[s, d]) * value(model.days_per_period) * 24 hours_adjust_next = ( - value(model.segment_fraction[p, s_next, d_next]) * value(model.days_per_period) * 24 + value(model.segment_fraction[s_next, d_next]) * value(model.days_per_period) * 24 ) hourly_activity_sd = ( @@ -418,15 +411,7 @@ def ramp_down_day_constraint( ) # elapsed hours from middle of this time slice to middle of next time slice - hours_elapsed = ( - 24 - / 2 - * ( - value(model.segment_fraction[p, s, d]) / value(model.segment_fraction_per_season[p, s]) - + value(model.segment_fraction[p, s_next, d_next]) - / value(model.segment_fraction_per_season[p, s_next]) - ) - ) + hours_elapsed = (model.time_of_day_hours[d] + model.time_of_day_hours[d_next]) / 2 ramp_fraction = hours_elapsed * value(model.ramp_down_hourly[r, t]) if ramp_fraction >= 1: @@ -440,7 +425,10 @@ def ramp_down_day_constraint( activity_decrease = hourly_activity_sd - hourly_activity_sd_next # opposite sign from rampup rampable_activity = ( - ramp_fraction * model.v_capacity[r, p, t, v] * value(model.capacity_to_activity[r, t]) + ramp_fraction + * model.v_capacity[r, p, t, v] + * value(model.capacity_to_activity[r, t]) + / (24 * value(model.days_per_period)) # adjust capacity to hourly basis ) expr = activity_decrease <= rampable_activity @@ -469,9 +457,9 @@ def ramp_up_season_constraint( d_next = model.time_of_day.first() # How many hours does this time slice represent - hours_adjust = value(model.segment_fraction[p, s, d]) * value(model.days_per_period) * 24 + hours_adjust = value(model.segment_fraction[s, d]) * value(model.days_per_period) * 24 hours_adjust_next = ( - value(model.segment_fraction[p, s_next, d_next]) * value(model.days_per_period) * 24 + value(model.segment_fraction[s_next, d_next]) * value(model.days_per_period) * 24 ) hourly_activity_sd = ( @@ -493,15 +481,7 @@ def ramp_up_season_constraint( ) # elapsed hours from middle of this time slice to middle of next time slice - hours_elapsed = ( - 24 - / 2 - * ( - value(model.segment_fraction[p, s, d]) / value(model.segment_fraction_per_season[p, s]) - + value(model.segment_fraction[p, s_next, d_next]) - / value(model.segment_fraction_per_season[p, s_next]) - ) - ) + hours_elapsed = (model.time_of_day_hours[d] + model.time_of_day_hours[d_next]) / 2 ramp_fraction = hours_elapsed * value(model.ramp_up_hourly[r, t]) if ramp_fraction >= 1: @@ -515,7 +495,10 @@ def ramp_up_season_constraint( activity_increase = hourly_activity_sd_next - hourly_activity_sd # opposite sign from rampdown rampable_activity = ( - ramp_fraction * model.v_capacity[r, p, t, v] * value(model.capacity_to_activity[r, t]) + ramp_fraction + * model.v_capacity[r, p, t, v] + * value(model.capacity_to_activity[r, t]) + / (24 * value(model.days_per_period)) # adjust capacity to hourly basis ) expr = activity_increase <= rampable_activity @@ -544,9 +527,9 @@ def ramp_down_season_constraint( d_next = model.time_of_day.first() # How many hours does this time slice represent - hours_adjust = value(model.segment_fraction[p, s, d]) * value(model.days_per_period) * 24 + hours_adjust = value(model.segment_fraction[s, d]) * value(model.days_per_period) * 24 hours_adjust_next = ( - value(model.segment_fraction[p, s_next, d_next]) * value(model.days_per_period) * 24 + value(model.segment_fraction[s_next, d_next]) * value(model.days_per_period) * 24 ) hourly_activity_sd = ( @@ -568,15 +551,7 @@ def ramp_down_season_constraint( ) # elapsed hours from middle of this time slice to middle of next time slice - hours_elapsed = ( - 24 - / 2 - * ( - value(model.segment_fraction[p, s, d]) / value(model.segment_fraction_per_season[p, s]) - + value(model.segment_fraction[p, s_next, d_next]) - / value(model.segment_fraction_per_season[p, s_next]) - ) - ) + hours_elapsed = (model.time_of_day_hours[d] + model.time_of_day_hours[d_next]) / 2 ramp_fraction = hours_elapsed * value(model.ramp_down_hourly[r, t]) if ramp_fraction >= 1: @@ -590,7 +565,10 @@ def ramp_down_season_constraint( activity_decrease = hourly_activity_sd - hourly_activity_sd_next # opposite sign from rampup rampable_activity = ( - ramp_fraction * model.v_capacity[r, p, t, v] * value(model.capacity_to_activity[r, t]) + ramp_fraction + * model.v_capacity[r, p, t, v] + * value(model.capacity_to_activity[r, t]) + / (24 * value(model.days_per_period)) # adjust capacity to hourly basis ) expr = activity_decrease <= rampable_activity diff --git a/temoa/components/reserves.py b/temoa/components/reserves.py index 2b60c9bbd..febee50a0 100644 --- a/temoa/components/reserves.py +++ b/temoa/components/reserves.py @@ -35,7 +35,7 @@ def reserve_margin_indices(model: TemoaModel) -> set[tuple[Region, Period, Seaso for r in model.planning_reserve_margin.sparse_iterkeys() for p in model.time_optimize if (r, p) in model.process_reserve_periods - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day } @@ -99,10 +99,10 @@ def reserve_margin_dynamic( # Derated available generation available = sum( model.v_capacity[r, p, t, v] - * value(model.reserve_capacity_derate[r, p, s, t, v]) - * value(model.capacity_factor_process[r, p, s, d, t, v]) + * value(model.reserve_capacity_derate[r, s, t, v]) + * value(model.capacity_factor_process[r, s, d, t, v]) * value(model.capacity_to_activity[r, t]) - * value(model.segment_fraction[p, s, d]) + * value(model.segment_fraction[s, d]) for (t, v) in model.process_reserve_periods[r, p] if t not in model.tech_uncap and t not in model.tech_storage ) @@ -110,16 +110,14 @@ def reserve_margin_dynamic( # Storage # Derated net output flow available += sum( - model.v_flow_out[r, p, s, d, i, t, v, o] - * value(model.reserve_capacity_derate[r, p, s, t, v]) + model.v_flow_out[r, p, s, d, i, t, v, o] * value(model.reserve_capacity_derate[r, s, t, v]) for (t, v) in model.process_reserve_periods[r, p] if t in model.tech_storage for i in model.process_inputs[r, p, t, v] for o in model.process_outputs_by_input[r, p, t, v, i] ) available -= sum( - model.v_flow_in[r, p, s, d, i, t, v, o] - * value(model.reserve_capacity_derate[r, p, s, t, v]) + model.v_flow_in[r, p, s, d, i, t, v, o] * value(model.reserve_capacity_derate[r, s, t, v]) for (t, v) in model.process_reserve_periods[r, p] if t in model.tech_storage for i in model.process_inputs[r, p, t, v] @@ -150,10 +148,10 @@ def reserve_margin_dynamic( # (this region was guaranteed an import of power) available += sum( model.v_capacity[r1r2, p, t, v] - * value(model.reserve_capacity_derate[r1r2, p, s, t, v]) - * value(model.capacity_factor_process[r1r2, p, s, d, t, v]) + * value(model.reserve_capacity_derate[r1r2, s, t, v]) + * value(model.capacity_factor_process[r1r2, s, d, t, v]) * value(model.capacity_to_activity[r1r2, t]) - * value(model.segment_fraction[p, s, d]) + * value(model.segment_fraction[s, d]) for (t, v) in model.process_reserve_periods[r1r2, p] ) elif r1 == r: @@ -161,10 +159,10 @@ def reserve_margin_dynamic( # (this region guaranteed an export of power) available -= sum( model.v_capacity[r1r2, p, t, v] - * value(model.reserve_capacity_derate[r1r2, p, s, t, v]) - * value(model.capacity_factor_process[r1r2, p, s, d, t, v]) + * value(model.reserve_capacity_derate[r1r2, s, t, v]) + * value(model.capacity_factor_process[r1r2, s, d, t, v]) * value(model.capacity_to_activity[r1r2, t]) - * value(model.segment_fraction[p, s, d]) + * value(model.segment_fraction[s, d]) for (t, v) in model.process_reserve_periods[r1r2, p] ) @@ -216,7 +214,7 @@ def reserve_margin_static( value(model.capacity_credit[r, p, t, v]) * model.v_capacity[r, p, t, v] * value(model.capacity_to_activity[r, t]) - * value(model.segment_fraction[p, s, d]) + * value(model.segment_fraction[s, d]) for (t, v) in model.process_reserve_periods[r, p] if t not in model.tech_uncap ) @@ -247,7 +245,7 @@ def reserve_margin_static( value(model.capacity_credit[r1r2, p, t, v]) * model.v_capacity[r1r2, p, t, v] * value(model.capacity_to_activity[r1r2, t]) - * value(model.segment_fraction[p, s, d]) + * value(model.segment_fraction[s, d]) for (t, v) in model.process_reserve_periods[r1r2, p] ) elif r1 == r: @@ -257,7 +255,7 @@ def reserve_margin_static( value(model.capacity_credit[r1r2, p, t, v]) * model.v_capacity[r1r2, p, t, v] * value(model.capacity_to_activity[r1r2, t]) - * value(model.segment_fraction[p, s, d]) + * value(model.segment_fraction[s, d]) for (t, v) in model.process_reserve_periods[r1r2, p] ) @@ -301,9 +299,9 @@ def reserve_margin_constraint( # Annual generation total_generation += sum( ( - value(model.demand_specific_distribution[r, p, s, d, S_o]) + value(model.demand_specific_distribution[r, s, d, S_o]) if S_o in model.commodity_demand - else value(model.segment_fraction[p, s, d]) + else value(model.segment_fraction[s, d]) ) * model.v_flow_out_annual[r, p, S_i, t, S_v, S_o] for (t, S_v) in model.process_reserve_periods[r, p] diff --git a/temoa/components/storage.py b/temoa/components/storage.py index 220c54c6a..4f1aea8df 100644 --- a/temoa/components/storage.py +++ b/temoa/components/storage.py @@ -13,6 +13,7 @@ from __future__ import annotations +from logging import getLogger from typing import TYPE_CHECKING from pyomo.environ import Constraint, value @@ -25,6 +26,9 @@ from ..types import ExprLike, Period, Region, Season, Technology, TimeOfDay, Vintage +logger = getLogger(__name__) + + # ============================================================================ # PYOMO INDEX SET FUNCTIONS # ============================================================================ @@ -80,6 +84,39 @@ def storage_constraint_indices( return model.storage_level_indices_rpsdtv +def limit_storage_fraction_constraint_indices( + model: TemoaModel, +) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage, str]]: + """Expand the period-free param set to include all valid process (period, vintage) combos.""" + + bad_keys = { + (r, s, d, t, op) + for r, s, d, t, op in model.limit_storage_fraction_param_rsdt + if (not model.is_seasonal_storage[t]) != (s in model.time_season) + } + if bad_keys: + msg = ( + 'Bad keys identified in limit_storage_level_fraction table. ' + 'Regular season used for seasonal storage or sequential season ' + f'used for diurnal storage. Bad keys: {bad_keys}' + ) + logger.error(msg) + raise ValueError(msg) + + all_storage_constraints = set( + model.storage_constraints_rpsdtv | model.seasonal_storage_constraints_rpsdtv + ) + valid_keys = { + (r, p, s, d, t, v, op) + for r, s, d, t, op in model.limit_storage_fraction_param_rsdt + for p in model.time_optimize + for v in model.process_vintages.get((r, p, t), []) + if (r, p, s, d, t, v) in all_storage_constraints + } + + return valid_keys + + # ============================================================================ # PYOMO CONSTRAINT RULES # ============================================================================ @@ -137,7 +174,7 @@ def storage_energy_constraint( s_next: Season d_next: TimeOfDay - s_next, d_next = model.time_next[p, s, d] + s_next, d_next = model.time_next[s, d] if d == model.time_of_day.last(): # Non-seasonal at d_last: use v_storage_init instead of v_storage_level @@ -209,7 +246,7 @@ def seasonal_storage_energy_constraint( are each one day. """ - s: Season = model.sequential_to_season[p, s_seq] + s: Season = model.sequential_to_season[s_seq] # This is the sum of all input=i sent TO storage tech t of vintage v with # output=o in p,s @@ -228,17 +265,16 @@ def seasonal_storage_energy_constraint( for S_i in model.process_inputs_by_output[r, p, t, v, S_o] ) - s_seq_next: Season = model.time_next_sequential[p, s_seq] - s_next: Season = model.sequential_to_season[p, s_seq_next] + s_seq_next: Season = model.time_next_sequential[s_seq] + s_next: Season = model.sequential_to_season[s_seq_next] - # Flows and StorageLevel are normalised to the number of days in the non-sequential season, - # so must - # be adjusted to the number of days in the sequential season - days_adjust = value(model.time_season_sequential[p, s_seq, s]) / ( - value(model.segment_fraction_per_season[p, s]) * value(model.days_per_period) + # Flows and StorageLevel are adjusted for the weight of seasons and so must be + # readjusted for the relative weight of the sequential season + days_adjust = value(model.segment_fraction_per_sequential_season[s_seq]) / value( + model.segment_fraction_per_season[s] ) - days_adjust_next = value(model.time_season_sequential[p, s_seq_next, s_next]) / ( - value(model.segment_fraction_per_season[p, s_next]) * value(model.days_per_period) + days_adjust_next = value(model.segment_fraction_per_sequential_season[s_seq_next]) / value( + model.segment_fraction_per_season[s_next] ) stored_energy = (charge - discharge) * days_adjust @@ -307,7 +343,7 @@ def storage_energy_upper_bound_constraint( model.v_capacity[r, p, t, v] * value(model.capacity_to_activity[r, t]) * (value(model.storage_duration[r, t]) / (24 * value(model.days_per_period))) - * value(model.segment_fraction_per_season[p, s]) + * value(model.segment_fraction_per_season[s]) * model.days_per_period # adjust for days in season ) @@ -371,7 +407,7 @@ def seasonal_storage_energy_upper_bound_constraint( Unadjusted energy upper bound constraint for seasonal storage. """ - s: Season = model.sequential_to_season[p, s_seq] + s: Season = model.sequential_to_season[s_seq] energy_capacity = ( model.v_capacity[r, p, t, v] @@ -379,11 +415,10 @@ def seasonal_storage_energy_upper_bound_constraint( * (value(model.storage_duration[r, t]) / (24 * value(model.days_per_period))) ) - # Flows and StorageLevel are normalised to the number of days in the non-sequential season, - # so must - # be adjusted to the number of days in the sequential season - days_adjust = value(model.time_season_sequential[p, s_seq, s]) / ( - value(model.segment_fraction_per_season[p, s]) * value(model.days_per_period) + # Flows and StorageLevel are adjusted for the weight of seasons and so must be + # readjusted for the relative weight of the sequential season + days_adjust = value(model.segment_fraction_per_sequential_season[s_seq]) / value( + model.segment_fraction_per_season[s] ) # v_storage_level tracks the running cumulative delta in the non-sequential season, @@ -427,7 +462,7 @@ def storage_charge_rate_constraint( max_charge = ( model.v_capacity[r, p, t, v] * value(model.capacity_to_activity[r, t]) - * value(model.segment_fraction[p, s, d]) + * value(model.segment_fraction[s, d]) ) # Energy charge cannot exceed the power capacity of the storage unit @@ -465,7 +500,7 @@ def storage_discharge_rate_constraint( max_discharge = ( model.v_capacity[r, p, t, v] * value(model.capacity_to_activity[r, t]) - * value(model.segment_fraction[p, s, d]) + * value(model.segment_fraction[s, d]) ) # Energy discharge cannot exceed the capacity of the storage unit @@ -512,7 +547,7 @@ def storage_throughput_constraint( max_throughput = ( model.v_capacity[r, p, t, v] * value(model.capacity_to_activity[r, t]) - * value(model.segment_fraction[p, s, d]) + * value(model.segment_fraction[s, d]) ) expr = throughput <= max_throughput return expr @@ -559,22 +594,22 @@ def limit_storage_fraction_constraint( model.v_capacity[r, p, t, v] * value(model.capacity_to_activity[r, t]) * (value(model.storage_duration[r, t]) / (24 * value(model.days_per_period))) - * value(model.limit_storage_fraction[r, p, s, d, t, v, op]) + * value(model.limit_storage_fraction[r, s, d, t, op]) ) if model.is_seasonal_storage[t]: s_seq: Season = s # sequential season - s = model.sequential_to_season[p, s_seq] # non-sequential season + s = model.sequential_to_season[s_seq] # non-sequential season # adjust the storage level to the individual-day level energy_level = model.v_storage_level[r, p, s, d, t, v] / ( - value(model.segment_fraction_per_season[p, s]) * value(model.days_per_period) + value(model.segment_fraction_per_season[s]) * value(model.days_per_period) ) if model.is_seasonal_storage[t]: # seasonal storage upper energy limit is absolute energy_level = model.v_seasonal_storage_level[r, p, s_seq, t, v] + energy_level * value( - model.time_season_sequential[p, s_seq, s] + model.segment_fraction_per_sequential_season[s_seq] * value(model.days_per_period) ) expr = operator_expression(energy_level, Operator(op), energy_limit) diff --git a/temoa/components/technology.py b/temoa/components/technology.py index 1bf34ea15..727f98caa 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -390,30 +390,25 @@ def check_efficiency_indices(model: TemoaModel) -> None: def check_efficiency_variable(model: TemoaModel) -> None: - count_rpitvo = {} + count_ritvo = {} # Pull non-variable efficiency by default for r, i, t, v, o in model.efficiency.sparse_iterkeys(): if (r, t, v) not in model.process_periods: # Probably an existing vintage that retires in p0 # Still want it for end of life flows continue - for p in model.process_periods[r, t, v]: - model.is_efficiency_variable[r, p, i, t, v, o] = False - count_rpitvo[r, p, i, t, v, o] = 0 + model.is_efficiency_variable[r, i, t, v, o] = False + count_ritvo[r, i, t, v, o] = 0 annual = set() # Check for bad values and count up the good ones - for r, p, _s, _d, i, t, v, o in model.efficiency_variable.sparse_iterkeys(): - if p not in model.process_periods[r, t, v]: - msg = f'Invalid period {p} for process {r, t, v} in efficiency_variable table' - logger.error(msg) - raise ValueError(msg) - + for r, _s, _d, i, t, v, o in model.efficiency_variable.sparse_iterkeys(): if t in model.tech_annual: annual.add(t) # Good value, pull from efficiency_variable table - count_rpitvo[r, p, i, t, v, o] += 1 + if (r, i, t, v, o) in count_ritvo: + count_ritvo[r, i, t, v, o] += 1 for t in annual: msg = ( @@ -425,17 +420,17 @@ def check_efficiency_variable(model: TemoaModel) -> None: # Check if all possible values have been set as variable # log a warning if some are missing (allowed but maybe accidental) - num_seg = len(model.time_season[p]) * len(model.time_of_day) - for (r, p, i, t, v, o), count in count_rpitvo.items(): + num_seg = len(model.time_season) * len(model.time_of_day) + for (r, i, t, v, o), count in count_ritvo.items(): if count > 0: - model.is_efficiency_variable[r, p, i, t, v, o] = True + model.is_efficiency_variable[r, i, t, v, o] = True if count < num_seg: logger.info( 'Some but not all efficiency_variable values were set (%i out of a possible ' '%i) for: %s Missing values will default to value set in efficiency table.', count, num_seg, - (r, p, i, t, v, o), + (r, i, t, v, o), ) diff --git a/temoa/components/time.py b/temoa/components/time.py index 6df7e5239..894dee35e 100644 --- a/temoa/components/time.py +++ b/temoa/components/time.py @@ -88,55 +88,60 @@ def validate_time(model: TemoaModel) -> None: def validate_segment_fraction(model: TemoaModel) -> None: - """Ensure that the segment fractions adds up to 1""" - - for p in model.time_optimize: - expected_keys: set[tuple[int, str, str]] = { - (p, s, d) for s in model.time_season[p] for d in model.time_of_day - } - keys: set[tuple[int, str, str]] = { - (_p, s, d) for _p, s, d in model.segment_fraction.sparse_iterkeys() if _p == p - } - - if expected_keys != keys: - extra: set[tuple[int, str, str]] = keys.difference(expected_keys) - missing: set[tuple[int, str, str]] = expected_keys.difference(keys) - msg: str = ( - f'time_segment_fraction elements for period {p} do not match time_season and ' - 'time_of_day.' - f'\n\nIndices missing from time_segment_fraction:\n{missing}' - f'\n\nIndices in time_segment_fraction missing from time_season/time_of_day:\n' - f'{extra}' + """Compute and validate segment_fraction from season fractions and TOD hours.""" + + # Compute segment_fraction[s, d] = segment_fraction_per_season[s] * hours[d] / total_hours + total_hours: float = sum(value(model.time_of_day_hours[d]) for d in model.time_of_day) + for s in model.time_season: + for d in model.time_of_day: + model.segment_fraction[s, d] = ( + value(model.segment_fraction_per_season[s]) + * value(model.time_of_day_hours[d]) + / total_hours ) - logger.error(msg) - raise ValueError(msg) + expected_keys: set[tuple[str, str]] = { + (s, d) for s in model.time_season for d in model.time_of_day + } + keys: set[tuple[str, str]] = set(model.segment_fraction.sparse_iterkeys()) - total: float = sum(value(model.segment_fraction[k]) for k in keys) + if expected_keys != keys: + extra: set[tuple[str, str]] = keys.difference(expected_keys) + missing: set[tuple[str, str]] = expected_keys.difference(keys) + msg: str = ( + 'Computed segment_fraction elements do not match time_season Ɨ time_of_day.' + f'\n\nIndices missing from segment_fraction:\n{missing}' + f'\n\nIndices in segment_fraction not matching time_season/time_of_day:\n' + f'{extra}' + ) + logger.error(msg) + raise ValueError(msg) - if abs(float(total) - 1.0) > 0.001: - # We can't explicitly test for "!= 1.0" because of incremental rounding - # errors associated with the specification of segment_fraction by time slice, - # but we check to make sure it is within the specified tolerance. + total: float = sum(value(model.segment_fraction[k]) for k in keys) - def get_str_padding(obj: object) -> int: - return len(str(obj)) + if abs(float(total) - 1.0) > 0.001: + # We can't explicitly test for "!= 1.0" because of incremental rounding + # errors associated with the specification of segment_fraction by time slice, + # but we check to make sure it is within the specified tolerance. - key_padding: int = max(map(get_str_padding, keys)) + def get_str_padding(obj: object) -> int: + return len(str(obj)) - # Works out to something like "%-25s = %s" + key_padding: int = max(map(get_str_padding, keys)) - items_list: list[tuple[tuple[object, object, object], object]] = sorted( - [(k, model.segment_fraction[k]) for k in keys] - ) - items: str = '\n '.join(f'{str(k):<{key_padding}} = {v}' for k, v in items_list) + # Works out to something like "%-25s = %s" - msg = ( - f'The values of time_segment_fraction do not sum to 1 for period {p}. ' - 'Each item in segment_fraction represents a fraction of a year, so they must ' - f'total to 1. Current values:\n {items}\n\tsum = {total}' - ) - logger.error(msg) - raise Exception(msg) + items_list: list[tuple[tuple[object, object], object]] = sorted( + [(k, model.segment_fraction[k]) for k in keys] + ) + items: str = '\n '.join(f'{str(k):<{key_padding}} = {v}' for k, v in items_list) + + msg = ( + 'The values of segment_fraction do not sum to 1. ' + 'Each item in segment_fraction represents a fraction of a year, so they must ' + f'total to 1. Current values:\n {items}\n\tsum = {total}' + ) + logger.error(msg) + raise Exception(msg) def validate_time_manual(model: TemoaModel) -> None: @@ -149,25 +154,21 @@ def validate_time_manual(model: TemoaModel) -> None: if model.time_sequencing.first() != 'manual': return - segment_fraction_psd: set[tuple[int, str, str]] = set(model.segment_fraction.sparse_iterkeys()) - time_manual_psd: set[tuple[int, str, str]] = { - (p, s, d) for p, s, d, s_next, d_next in model.time_manual - } - time_manual_psd_next: set[tuple[int, str, str]] = { - (p, s_next, d_next) for p, s, d, s_next, d_next in model.time_manual + segment_fraction_sd: set[tuple[str, str]] = set(model.segment_fraction.sparse_iterkeys()) + time_manual_sd: set[tuple[str, str]] = {(s, d) for s, d, s_next, d_next in model.time_manual} + time_manual_sd_next: set[tuple[str, str]] = { + (s_next, d_next) for s, d, s_next, d_next in model.time_manual } - missing_psd: set[tuple[int, str, str]] = segment_fraction_psd.difference(time_manual_psd) - missing_psd_next: set[tuple[int, str, str]] = segment_fraction_psd.difference( - time_manual_psd_next - ) - if missing_psd or missing_psd_next: + missing_sd: set[tuple[str, str]] = segment_fraction_sd.difference(time_manual_sd) + missing_sd_next: set[tuple[str, str]] = segment_fraction_sd.difference(time_manual_sd_next) + if missing_sd or missing_sd_next: msg: str = ( 'Failed to build state sequence. ' - f'\nThese states from time_segment_fraction were not given a next state:\n' - f'{missing_psd}\n' - f'\nThese states from time_segment_fraction do not follow any state:\n' - f'{missing_psd_next}' + f'\nThese segment_fraction states were not given a next state:\n' + f'{missing_sd}\n' + f'\nThese segment_fraction states do not follow any state:\n' + f'{missing_sd_next}' ) logger.error(msg) raise ValueError(msg) @@ -193,15 +194,6 @@ def init_set_vintage_optimize(model: TemoaModel) -> list[int]: return sorted(model.time_optimize) -def segment_fraction_per_season_rule(model: TemoaModel, p: Period, s: Season) -> float: - """Rule to calculate the total fraction of a period represented by a season.""" - return sum( - value(model.segment_fraction[p, s, d]) - for d in model.time_of_day - if (p, s, d) in model.segment_fraction - ) - - def param_period_length(model: TemoaModel, p: Period) -> int: """Rule to calculate the length of each optimization period in years.""" periods: list[int] = sorted(model.time_future) @@ -215,20 +207,20 @@ def param_period_length(model: TemoaModel, p: Period) -> int: def loop_period_next_timeslice( - model: TemoaModel, p: Period, s: Season, d: TimeOfDay + model: TemoaModel, s: Season, d: TimeOfDay ) -> tuple[Season, TimeOfDay]: # Final time slice of final season (end of period) # Loop state back to initial state of first season # Loop the period - if s == model.time_season[p].last() and d == model.time_of_day.last(): - s_next: Season = model.time_season[p].first() + if s == model.time_season.last() and d == model.time_of_day.last(): + s_next: Season = model.time_season.first() d_next: TimeOfDay = model.time_of_day.first() # Last time slice of any season that is NOT the last season # Carry state to initial state of next season # Carry state between seasons elif d == model.time_of_day.last(): - s_next = model.time_season[p].next(s) + s_next = model.time_season.next(s) d_next = model.time_of_day.first() # Any other time slice @@ -242,7 +234,7 @@ def loop_period_next_timeslice( def loop_season_next_timeslice( - model: TemoaModel, p: Period, s: Season, d: TimeOfDay + model: TemoaModel, s: Season, d: TimeOfDay ) -> tuple[Season, TimeOfDay]: # We loop each season so never carrying state between seasons s_next: Season = s @@ -274,24 +266,21 @@ def create_time_sequence(model: TemoaModel) -> None: match model.time_sequencing.first(): case 'consecutive_days': msg: str = 'Running a consecutive days database.' - for p in model.time_optimize: - for s, d in model.time_season[p] * model.time_of_day: - model.time_next[p, s, d] = loop_period_next_timeslice(model, p, s, d) + for s, d in model.time_season * model.time_of_day: + model.time_next[s, d] = loop_period_next_timeslice(model, s, d) case 'seasonal_timeslices': msg = 'Running a seasonal time slice database.' - for p in model.time_optimize: - for s, d in model.time_season[p] * model.time_of_day: - model.time_next[p, s, d] = loop_season_next_timeslice(model, p, s, d) + for s, d in model.time_season * model.time_of_day: + model.time_next[s, d] = loop_season_next_timeslice(model, s, d) case 'representative_periods': msg = 'Running a representative periods database.' - for p in model.time_optimize: - for s, d in model.time_season[p] * model.time_of_day: - model.time_next[p, s, d] = loop_season_next_timeslice(model, p, s, d) + for s, d in model.time_season * model.time_of_day: + model.time_next[s, d] = loop_season_next_timeslice(model, s, d) case 'manual': # Hidden feature. Define the sequence directly in the time_manual table msg = 'Pulling time sequence from time_manual table.' - for p, s, d, s_next, d_next in model.time_manual: - model.time_next[p, s, d] = s_next, d_next + for s, d, s_next, d_next in model.time_manual: + model.time_next[s, d] = s_next, d_next case _: # This should have been caught in hybrid_loader msg = ( @@ -306,17 +295,14 @@ def create_time_sequence(model: TemoaModel) -> None: logger.debug('Creating superimposed sequential seasons.') - # Superimposed sequential seasons - for p in model.time_optimize: - seasons: list[tuple[Season, Season]] = [ - (s_seq, s) for _p, s_seq, s in model.ordered_season_sequential if _p == p - ] - for i, (s_seq, s) in enumerate(seasons): - model.sequential_to_season[p, s_seq] = s - if (s_seq, s) == seasons[-1]: - model.time_next_sequential[p, s_seq] = seasons[0][0] - else: - model.time_next_sequential[p, s_seq] = seasons[i + 1][0] + # Superimposed sequential seasons (global, period-independent) + seasons: list[tuple[Season, Season]] = list(model.ordered_season_sequential) + for i, (s_seq, s) in enumerate(seasons): + model.sequential_to_season[s_seq] = s + if (s_seq, s) == seasons[-1]: + model.time_next_sequential[s_seq] = seasons[0][0] + else: + model.time_next_sequential[s_seq] = seasons[i + 1][0] logger.debug('Created time sequence.') @@ -332,20 +318,18 @@ def create_time_season_to_sequential(model: TemoaModel) -> None: # Don't need it anyway return - if not model.time_season_sequential: + if not model.segment_fraction_per_sequential_season: if model.time_sequencing.first() in ('consecutive_days', 'seasonal_timeslices'): logger.info( 'No data in time_season_sequential. By default, assuming sequential seasons ' - 'match time_season and time_segment_fraction.' + 'match time_season.' ) - for s in model.time_season_all: - model.time_season_to_sequential.add(s) - for p in model.time_season: - for s in model.time_season[p]: - model.ordered_season_sequential.add((p, s, s)) - model.time_season_sequential[p, s, s] = value( - model.segment_fraction_per_season[p, s] - ) * value(model.days_per_period) + for s in model.time_season: + model.time_season_sequential.add(s) + model.ordered_season_sequential.add((s, s)) + model.segment_fraction_per_sequential_season[s] = value( + model.segment_fraction_per_season[s] + ) else: msg = ( @@ -359,74 +343,60 @@ def create_time_season_to_sequential(model: TemoaModel) -> None: logger.error(msg) raise ValueError(msg) - sequential: dict[tuple[int, str], float] = {} - prev_n: float = 0 - for p, s_seq, s in model.time_season_sequential.sparse_iterkeys(): - num_days: float = value(model.time_season_sequential[p, s_seq, s]) + seas_fracs_seq: dict[str, float] = {} + prev_frac: float = 0 + for s_seq, s in model.ordered_season_sequential: + seg_frac_seq: float = value(model.segment_fraction_per_sequential_season[s_seq]) if ( model.time_sequencing.first() == 'consecutive_days' - and prev_n - and abs(num_days - prev_n) >= 0.001 + and prev_frac + and abs(seg_frac_seq - prev_frac) >= 0.001 ): msg = ( 'time_sequencing set to consecutive_days but two consecutive seasons do not ' - 'represent the same number of days. This discontinuity will lead to bad model ' - f'behaviour: {p, s}, days: {num_days}. ' - f'Previous number of days: {prev_n}. Check the config file for more information.' + 'represent the same fraction of the year. This discontinuity will lead to bad ' + f'model behaviour: {s_seq}, fraction: {seg_frac_seq}. ' + f'Previous fraction: {prev_frac}. Check the config file for more information.' ) logger.error(msg) raise ValueError(msg) - prev_n = num_days # for validating next in sequence - - # Regardless of their order, make sure the total number of days adds up - if (p, s) not in sequential: - sequential[p, s] = 0 - sequential[p, s] += num_days - - # Check that time_season_sequential num_days total to number of days in each period - count_total: dict[ - int, float - ] = {} # {p: n} total days per period according to time_season_sequential - for p in model.time_optimize: - count_total[p] = sum(sequential[p, s] for _p, s in sequential if _p == p) - if abs(count_total[p] - value(model.days_per_period)) >= 0.001: - logger.warning( - 'Sum of num_days in time_season_sequential (%s) ' - 'for period %s does not sum to days_per_period (%s) ' - 'from the MetaData table.', - count_total[p], - p, - value(model.days_per_period), - ) + prev_frac = seg_frac_seq # for validating next in sequence + + # Regardless of their order, make sure the total fractions add up + seas_fracs_seq[s] = seas_fracs_seq.get(s, 0) + seg_frac_seq + + # Check that time_season_sequential segment_fraction totals to 1.0 + frac_total: float = sum(seas_fracs_seq.values()) + if abs(frac_total - 1.0) >= 0.001: + logger.warning( + 'Sum of segment_fraction in time_season_sequential (%s) does not sum to 1.0.', + frac_total, + ) - # Check that seasons using in storage seasons are actual seasons - for p, s in sequential: - if (p, s) not in model.segment_fraction_per_season: + # Check that seasons used in storage seasons are actual seasons + for s in seas_fracs_seq: + if s not in model.time_season: msg = ( - f'Period-season index {(p, s)} that does not exist in ' - 'time_segment_fraction referenced in time_season_sequential .' + f'Season {s!r} referenced in time_season_sequential does not exist in time_season.' ) logger.error(msg) raise ValueError(msg) - for p, s in model.segment_fraction_per_season.sparse_iterkeys(): - if s not in model.time_season[p]: - continue - + for s in model.time_season: # Check that all seasons are used in sequential seasons - if (p, s) not in sequential: - msg = f'Period-season index {(p, s)} absent from time_season_sequential' + if s not in seas_fracs_seq: + msg = f'Season {s!r} absent from time_season_sequential' logger.warning(msg) - # Check that the two tables agree on the total seasonal composition of each period - segment_fraction = value(model.segment_fraction_per_season[p, s]) - segment_fraction_seq = sequential[p, s] / count_total[p] - if abs(segment_fraction - segment_fraction_seq) >= 0.001: + # Check that the two tables agree on the total seasonal composition + season_frac = value(model.segment_fraction_per_season[s]) + season_frac_seq = seas_fracs_seq[s] + if abs(season_frac - season_frac_seq) >= 0.001: msg = ( - 'Discrepancy of total period-season composition between ' - 'time_segment_fraction and time_season_sequential. Total fraction of each ' - 'period assigned to each season should match: ' - f'time_segment_fraction: {(p, s, value(model.segment_fraction_per_season[p, s]))}' - f', time_season_sequential: {(p, s, segment_fraction_seq)}' + 'Discrepancy of total seasonal composition between ' + 'time_season and time_season_sequential. Total fraction ' + 'assigned to each season should match: ' + f'time_season: {(s, season_frac)}' + f', time_season_sequential: {(s, season_frac_seq)}' ) logger.warning(msg) diff --git a/temoa/components/utils.py b/temoa/components/utils.py index c558bf23b..c26ccbafa 100644 --- a/temoa/components/utils.py +++ b/temoa/components/utils.py @@ -53,7 +53,7 @@ def operator_expression(lhs: Expression, operator: Operator, rhs: Expression) -> def get_variable_efficiency( model: TemoaModel, r: Region, - p: Period, + _p: Period, s: Season, d: TimeOfDay, i: Commodity, @@ -74,9 +74,9 @@ def get_variable_efficiency( This dictionary-lookup approach is used for performance, as it is much faster than repeatedly checking the indices of a large Pyomo parameter during model build. """ - if model.is_efficiency_variable.get((r, p, i, t, v, o), False): + if model.is_efficiency_variable[r, i, t, v, o]: return value(model.efficiency[r, i, t, v, o]) * value( - model.efficiency_variable[r, p, s, d, i, t, v, o] + model.efficiency_variable[r, s, d, i, t, v, o] ) else: return value(model.efficiency[r, i, t, v, o]) diff --git a/temoa/core/config.py b/temoa/core/config.py index ecaca6044..834dfc144 100644 --- a/temoa/core/config.py +++ b/temoa/core/config.py @@ -48,6 +48,7 @@ def __init__( save_storage_levels: bool = False, save_lp_file: bool = False, time_sequencing: str | None = None, + days_per_period: int = 365, reserve_margin: str | None = None, MGA: dict[str, object] | None = None, SVMGA: dict[str, object] | None = None, @@ -132,6 +133,7 @@ def __init__( self.save_storage_levels = save_storage_levels self.save_lp_file = save_lp_file self.time_sequencing = time_sequencing + self.days_per_period = days_per_period self.reserve_margin = reserve_margin self.mga_inputs = MGA @@ -303,6 +305,7 @@ def __repr__(self) -> str: msg += spacer msg += '{:>{}s}: {}\n'.format('Time sequencing', width, self.time_sequencing) + msg += '{:>{}s}: {}\n'.format('Days per period', width, self.days_per_period) msg += '{:>{}s}: {}\n'.format('Planning reserve margin', width, self.reserve_margin) if self.scenario_mode == TemoaMode.MYOPIC and self.myopic_inputs is not None: diff --git a/temoa/core/model.py b/temoa/core/model.py index 88884cad5..4ce2a0275 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -20,6 +20,7 @@ NonNegativeReals, Objective, Param, + PositiveReals, minimize, ) @@ -150,7 +151,6 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.retirement_production_processes: t.RetirementProductionProcessesDict = {} self.process_inputs_by_output: t.ProcessInputsByOutputDict = {} self.process_outputs_by_input: t.ProcessOutputsByInputDict = {} - self.process_techs: t.ProcessTechsDict = {} self.process_reserve_periods: t.ProcessReservePeriodsDict = {} self.process_periods: t.ProcessPeriodsDict = {} # {(r, t, v): set(p)} # {(r, t, v): set(p)} periods in which a process can economically or naturally retire @@ -174,11 +174,11 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.import_regions: t.ImportRegionsDict = {} # These establish time sequencing - # {(p, s, d): (s_next, d_next)} sequence of following time slices + # {(s, d): (s_next, d_next)} sequence of following time slices self.time_next: t.TimeNextDict = {} - # {(p, s_seq): (s_seq_next)} next virtual storage season + # {s_seq: s_seq_next} next virtual storage season self.time_next_sequential: t.TimeNextSequentialDict = {} - # {(p, s_seq): (s)} season matching this virtual storage season + # {s_seq: s} season matching this virtual storage season self.sequential_to_season: t.SequentialToSeasonDict = {} ################################################ @@ -186,9 +186,10 @@ def __init__(self, *args: object, **kwargs: object) -> None: # (to avoid slow searches in initialisation) # ################################################ - # {(r, p, i, t, v, o): bool} which efficiencies have variable indexing + # {(r, i, t, v, o): bool} which efficiencies have variable indexing self.is_efficiency_variable: t.EfficiencyVariableDict = {} - # {(r, p, t, v): bool} which capacity factors have have period-vintage indexing + # {(r, t, v): bool} which processes use capacity_factor_process + # table (instead of capacity_factor_tech) self.is_capacity_factor_process: t.CapacityFactorProcessDict = {} # {t: bool} whether a storage tech is seasonal storage self.is_seasonal_storage: t.SeasonalStorageDict = {} @@ -218,16 +219,15 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.validate_time = BuildAction(rule=time.validate_time) # Define the model time slices - self.time_season_all = Set(ordered=True, validate=no_slash_or_pipe) - self.time_season_to_sequential = Set(ordered=True, validate=no_slash_or_pipe) - self.time_season = Set(self.time_optimize, within=self.time_season_all, ordered=True) + self.time_season = Set(ordered=True, validate=no_slash_or_pipe) + self.time_season_sequential = Set(ordered=True, validate=no_slash_or_pipe) self.time_of_day = Set(ordered=True, validate=no_slash_or_pipe) # This is just to get the TimeStorageSeason table sequentially. # There must be a better way but this works for now self.ordered_season_sequential = Set( - dimen=3, - within=self.time_optimize * self.time_season_to_sequential * self.time_season_all, + dimen=2, + within=self.time_season_sequential * self.time_season, ordered=True, ) @@ -327,11 +327,25 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.global_discount_rate = Param(default=0.05) + # These need to come before validate_season_sequential as they tell us whether + # we need sequential seasons + self.ramp_up_hourly = Param(self.regions, self.tech_upramping, validate=validate_0to1) + self.ramp_down_hourly = Param(self.regions, self.tech_downramping, validate=validate_0to1) + # Define time-related parameters + # Basic period construction + self.time_sequencing = Set() # How do states carry between time segments? self.period_length = Param(self.time_optimize, initialize=time.param_period_length) - self.segment_fraction = Param(self.time_optimize, self.time_season_all, self.time_of_day) + self.days_per_period = Param(domain=PositiveReals, default=365.0) + self.time_of_day_hours = Param(self.time_of_day, domain=PositiveReals, default=1.0) + self.segment_fraction_per_season = Param(self.time_season) + self.segment_fraction = Param(self.time_season, self.time_of_day, mutable=True) self.validate_segment_fraction = BuildAction(rule=time.validate_segment_fraction) - self.time_sequencing = Set() # How do states carry between time segments? + self.segment_fraction_per_sequential_season = Param( + self.time_season_sequential, mutable=True + ) + self.validate_season_sequential = BuildAction(rule=time.create_time_season_to_sequential) + self.create_time_sequence = BuildAction(rule=time.create_time_sequence) self.time_manual = Set( ordered=True ) # This is just to get data from the table. Hidden feature and usually not used @@ -346,8 +360,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: # ) self.demand_specific_distribution = Param( self.regions, - self.time_optimize, - self.time_season_all, + self.time_season, self.time_of_day, self.commodity_demand, mutable=True, @@ -398,7 +411,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.tech_all, self.vintage_all, self.commodity_carrier, - within=NonNegativeReals, + within=PositiveReals, validate=validate_efficiency, ) self.validate_used_efficiency_indices = BuildAction( @@ -407,14 +420,13 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.efficiency_variable = Param( self.regional_indices, - self.time_optimize, - self.time_season_all, + self.time_season, self.time_of_day, self.commodity_physical, self.tech_all, self.vintage_all, self.commodity_carrier, - within=NonNegativeReals, + within=PositiveReals, default=1, ) @@ -492,23 +504,6 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.renewable_portfolio_standard_constraint_rpg, validate=validate_0to1 ) - # These need to come before validate_season_sequential - self.ramp_up_hourly = Param(self.regions, self.tech_upramping, validate=validate_0to1) - self.ramp_down_hourly = Param(self.regions, self.tech_downramping, validate=validate_0to1) - - # Set up representation of time - self.days_per_period = Param() - self.segment_fraction_per_season = Param( - self.time_optimize, - self.time_season_all, - initialize=time.segment_fraction_per_season_rule, - ) - self.time_season_sequential = Param( - self.time_optimize, self.time_season_to_sequential, self.time_season_all, mutable=True - ) - self.validate_season_sequential = BuildAction(rule=time.create_time_season_to_sequential) - self.create_time_sequence = BuildAction(rule=time.create_time_sequence) - # The method below creates a series of helper functions that are used to # perform the sparse matrix of indexing for the parameters, variables, and # equations below. @@ -516,17 +511,16 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.initialize_demands = BuildAction(rule=commodities.create_demands) self.validate_existing_capacity = BuildAction(rule=technology.check_existing_capacity) - self.capacity_factor_rpsdt = Set(dimen=5, initialize=capacity.capacity_factor_tech_indices) + self.capacity_factor_rsdt = Set(dimen=4, initialize=capacity.capacity_factor_tech_indices) self.capacity_factor_tech = Param( - self.capacity_factor_rpsdt, default=1, validate=validate_0to1 + self.capacity_factor_rsdt, default=1, validate=validate_0to1 ) # Dev note: using a default function below alleviates need to make this set. # M.CapacityFactor_rsdtv = Set(dimen=5, initialize=capacity_factor_processIndices) self.capacity_factor_process = Param( self.regional_indices, - self.time_optimize, - self.time_season_all, + self.time_season, self.time_of_day, self.tech_with_capacity, self.vintage_all, @@ -604,15 +598,17 @@ def __init__(self, *args: object, **kwargs: object) -> None: ) self.limit_activity = Param(self.limit_activity_constraint_rpt) + self.limit_seasonal_capacity_factor_constraint_rst = Set() + self.limit_seasonal_capacity_factor = Param( + self.limit_seasonal_capacity_factor_constraint_rst, validate=validate_0to1 + ) self.limit_seasonal_capacity_factor_constraint_rpst = Set( within=self.regional_global_indices * self.time_optimize - * self.time_season_all + * self.time_season * self.tech_or_group - * self.operator - ) - self.limit_seasonal_capacity_factor = Param( - self.limit_seasonal_capacity_factor_constraint_rpst, validate=validate_0to1 + * self.operator, + initialize=limits.limit_seasonal_capacity_factor_constraint_indices, ) self.limit_annual_capacity_factor_constraint_rtvo = Set( @@ -689,12 +685,16 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.seasonal_storage_constraints_rpsdtv = Set( dimen=6, initialize=storage.seasonal_storage_constraint_indices ) + self.limit_storage_fraction_param_rsdt = ( + Set() + ) # populated by hybrid_loader with (r, s, d, t, op) keys + self.limit_storage_fraction = Param( + self.limit_storage_fraction_param_rsdt, validate=validate_0to1 + ) self.limit_storage_fraction_constraint_rpsdtv = Set( within=(self.storage_constraints_rpsdtv | self.seasonal_storage_constraints_rpsdtv) - * self.operator - ) - self.limit_storage_fraction = Param( - self.limit_storage_fraction_constraint_rpsdtv, validate=validate_0to1 + * self.operator, + initialize=storage.limit_storage_fraction_constraint_indices, ) # Storage duration is expressed in hours @@ -714,8 +714,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: ) self.reserve_capacity_derate = Param( self.regional_indices, - self.time_optimize, - self.time_season_all, + self.time_season, self.tech_reserve, self.vintage_all, default=1, diff --git a/temoa/data_io/component_manifest.py b/temoa/data_io/component_manifest.py index 75789f631..f9bf86a1c 100644 --- a/temoa/data_io/component_manifest.py +++ b/temoa/data_io/component_manifest.py @@ -236,27 +236,45 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: is_period_filtered=False, is_table_required=False, fallback_data=[('D',)], + order_by=['sequence'], + ), + LoadItem( + component=model.time_of_day_hours, + table='time_of_day', + columns=['tod', 'hours'], + is_period_filtered=False, + is_table_required=False, ), LoadItem( component=model.time_season, table='time_season', - columns=['period', 'season'], + columns=['season'], custom_loader_name='_load_time_season', is_period_filtered=False, # Custom loader handles myopic filtering is_table_required=False, + order_by=['sequence'], + ), + LoadItem( + component=model.segment_fraction_per_season, + table='time_season', + columns=['season', 'segment_fraction'], + is_period_filtered=False, + is_table_required=False, ), LoadItem( component=model.time_season_sequential, table='time_season_sequential', - columns=['period', 'seas_seq', 'season', 'num_days'], + columns=['seas_seq', 'season', 'segment_fraction'], custom_loader_name='_load_time_season_sequential', + is_period_filtered=False, is_table_required=False, + order_by=['sequence'], ), LoadItem( - component=model.segment_fraction, - table='time_segment_fraction', - columns=['period', 'season', 'tod', 'segment_fraction'], - custom_loader_name='_load_segment_fraction', + component=model.time_manual, + table='time_manual', + columns=['season', 'tod', 'season_next', 'tod_next'], + is_period_filtered=False, is_table_required=False, ), # ========================================================================= @@ -313,15 +331,6 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: # ========================================================================= # Singleton and Configuration-based Components # ========================================================================= - LoadItem( - component=model.days_per_period, - table='metadata', - columns=['value'], - where_clause="element == 'days_per_period'", - custom_loader_name='_load_days_per_period', - is_period_filtered=False, - is_table_required=False, - ), LoadItem( component=model.global_discount_rate, table='metadata_real', @@ -356,7 +365,6 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: table='efficiency_variable', columns=[ 'region', - 'period', 'season', 'tod', 'input_comm', @@ -366,7 +374,8 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: 'efficiency', ], validator_name='viable_ritvo', - validation_map=(0, 4, 5, 6, 7), + validation_map=(0, 3, 4, 5, 6), + is_period_filtered=False, is_table_required=False, ), LoadItem( @@ -377,7 +386,8 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: LoadItem( component=model.demand_specific_distribution, table='demand_specific_distribution', - columns=['region', 'period', 'season', 'tod', 'demand_name', 'dsd'], + columns=['region', 'season', 'tod', 'demand_name', 'dsd'], + is_period_filtered=False, is_table_required=False, ), LoadItem( @@ -392,17 +402,19 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: LoadItem( component=model.capacity_factor_tech, table='capacity_factor_tech', - columns=['region', 'period', 'season', 'tod', 'tech', 'factor'], + columns=['region', 'season', 'tod', 'tech', 'factor'], validator_name='viable_rt', - validation_map=(0, 4), + validation_map=(0, 3), + is_period_filtered=False, is_table_required=False, ), LoadItem( component=model.capacity_factor_process, table='capacity_factor_process', - columns=['region', 'period', 'season', 'tod', 'tech', 'vintage', 'factor'], + columns=['region', 'season', 'tod', 'tech', 'vintage', 'factor'], validator_name='viable_rtv', - validation_map=(0, 4, 5), + validation_map=(0, 3, 4), + is_period_filtered=False, is_table_required=False, ), LoadItem( @@ -495,9 +507,10 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: LoadItem( component=model.reserve_capacity_derate, table='reserve_capacity_derate', - columns=['region', 'period', 'season', 'tech', 'vintage', 'factor'], + columns=['region', 'season', 'tech', 'vintage', 'factor'], validator_name='viable_rtv', - validation_map=(0, 3, 4), + validation_map=(0, 2, 3), + is_period_filtered=False, is_table_required=False, ), LoadItem( @@ -521,16 +534,15 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: table='limit_storage_level_fraction', columns=[ 'region', - 'period', 'season', 'tod', 'tech', - 'vintage', 'operator', 'fraction', ], - validator_name='viable_rtv', - validation_map=(0, 4, 5), + validator_name='viable_rt', + validation_map=(0, 3), + is_period_filtered=False, is_table_required=False, ), LoadItem( @@ -653,9 +665,10 @@ def build_manifest(model: TemoaModel) -> list[LoadItem]: LoadItem( component=model.limit_seasonal_capacity_factor, table='limit_seasonal_capacity_factor', - columns=['region', 'period', 'season', 'tech_or_group', 'operator', 'factor'], - validator_name='viable_rpt', - validation_map=(0, 1, 3), + columns=['region', 'season', 'tech', 'operator', 'factor'], + validator_name='viable_rt', + validation_map=(0, 2), + is_period_filtered=False, is_table_required=False, ), LoadItem( diff --git a/temoa/data_io/hybrid_loader.py b/temoa/data_io/hybrid_loader.py index faf3864cb..3bf3b5e85 100644 --- a/temoa/data_io/hybrid_loader.py +++ b/temoa/data_io/hybrid_loader.py @@ -262,6 +262,7 @@ def create_data_dict(self, myopic_index: MyopicIndex | None = None) -> dict[str, # --------------------------------------------------------------------- # Load simple config-based or myopic-specific values self._load_component_data(data, model.time_sequencing, [(self.config.time_sequencing,)]) + self._load_component_data(data, model.days_per_period, [(self.config.days_per_period,)]) self._load_component_data( data, model.reserve_margin_method, [(self.config.reserve_margin,)] ) @@ -314,6 +315,9 @@ def _fetch_data( if where_clauses: query += ' WHERE ' + ' AND '.join(where_clauses) + if item.order_by: + query += ' ORDER BY ' + ', '.join(item.order_by) + try: return cur.execute(query, params).fetchall() except OperationalError as e: @@ -554,35 +558,15 @@ def _load_time_season( filtered_data: Sequence[tuple[object, ...]], ) -> None: """ - Loads time_season_all (simple set of all seasons) and time_season - (indexed set mapping periods to seasons), with a dynamic fallback - if the table is missing. + Loads time_season as a flat ordered set of season names. """ model = TemoaModel() - mi = self.myopic_index - time_optimize = cast('list[int]', data.get('time_optimize', [])) - - rows_to_load: list[tuple[object, ...]] = [] - if not raw_data: + if not filtered_data: logger.warning('No time_season table found. Loading a single filler season "S".') - rows_to_load = [(p, 'S') for p in time_optimize] - elif mi: - valid_periods = set(time_optimize) - rows_to_load = [row for row in raw_data if row[0] in valid_periods] + seasons_to_load: list[tuple[object, ...]] = [('S',)] else: - rows_to_load = list(raw_data) - - if not rows_to_load: - data.setdefault(model.time_season_all.name, []) - return - - unique_seasons = sorted({(row[1],) for row in rows_to_load}) - self._load_component_data(data, model.time_season_all, unique_seasons) - - for period, season in rows_to_load: - store = data.get(model.time_season.name, defaultdict(list)) - store[period].append(season) # type: ignore[index] - data[model.time_season.name] = store + seasons_to_load = list(filtered_data) + self._load_component_data(data, model.time_season, seasons_to_load) def _load_time_season_sequential( self, @@ -594,30 +578,17 @@ def _load_time_season_sequential( Composite loader for time_season_sequential and its associated index sets. """ model = TemoaModel() - self._load_component_data(data, model.time_season_sequential, filtered_data) - if filtered_data: - ordered_data = [row[0:3] for row in filtered_data] - self._load_component_data(data, model.ordered_season_sequential, ordered_data) - seq_data = sorted({(row[1],) for row in filtered_data}) - self._load_component_data(data, model.time_season_to_sequential, seq_data) - - def _load_segment_fraction( - self, - data: dict[str, object], - raw_data: Sequence[tuple[object, ...]], - filtered_data: Sequence[tuple[object, ...]], - ) -> None: - """Handles dynamic fallbacks for segment_fraction if its table is missing.""" - model = TemoaModel() if filtered_data: - self._load_component_data(data, model.segment_fraction, filtered_data) - else: - logger.warning( - 'No segment_fraction table found. Generating default segment_fraction values.' + seg_frac_data = [ + (row[0], row[2]) for row in filtered_data + ] # (seas_seq, segment_fraction) + self._load_component_data( + data, model.segment_fraction_per_sequential_season, seg_frac_data ) - time_optimize = data.get('time_optimize', []) - fallback = [(p, 'S', 'D', 1.0) for p in time_optimize] # type: ignore[attr-defined] - self._load_component_data(data, model.segment_fraction, fallback) + ordered_data = [row[0:2] for row in filtered_data] # (seas_seq, season) + self._load_component_data(data, model.ordered_season_sequential, ordered_data) + seq_seasons = [(row[0],) for row in filtered_data] # (seas_seq,) + self._load_component_data(data, model.time_season_sequential, seq_seasons) # --- Capacity and Cost Components --- def _load_existing_capacity( @@ -711,21 +682,6 @@ def _load_emission_embodied( self._load_component_data(data, model.emission_embodied, data_to_load) # --- Singleton and Configuration-based Components --- - def _load_days_per_period( - self, - data: dict[str, object], - raw_data: Sequence[tuple[object, ...]], - filtered_data: Sequence[tuple[object, ...]], - ) -> None: - """Loads the singleton days_per_period, with a fallback.""" - model = TemoaModel() - days = 365 - if filtered_data: - days = cast('int', filtered_data[0][0]) - else: - logger.info('No value for days_per_period found. Assuming 365 days per period.') - data[model.days_per_period.name] = {None: days} - def _load_global_discount_rate( self, data: dict[str, object], @@ -940,7 +896,7 @@ def load_param_idx_sets(self, data: dict[str, object]) -> dict[str, object]: model.limit_emission.name: model.limit_emission_constraint_rpe.name, model.limit_activity.name: model.limit_activity_constraint_rpt.name, model.limit_seasonal_capacity_factor.name: ( - model.limit_seasonal_capacity_factor_constraint_rpst.name + model.limit_seasonal_capacity_factor_constraint_rst.name ), model.limit_activity_share.name: model.limit_activity_share_constraint_rpgg.name, model.limit_annual_capacity_factor.name: ( @@ -953,7 +909,7 @@ def load_param_idx_sets(self, data: dict[str, object]) -> dict[str, object]: model.limit_new_capacity_share_constraint_rggv.name ), model.limit_resource.name: model.limit_resource_constraint_rt.name, - model.limit_storage_fraction.name: model.limit_storage_fraction_constraint_rpsdtv.name, + model.limit_storage_fraction.name: model.limit_storage_fraction_param_rsdt.name, model.renewable_portfolio_standard.name: ( model.renewable_portfolio_standard_constraint_rpg.name ), diff --git a/temoa/data_io/loader_manifest.py b/temoa/data_io/loader_manifest.py index b0350568f..ad6ce930d 100644 --- a/temoa/data_io/loader_manifest.py +++ b/temoa/data_io/loader_manifest.py @@ -57,3 +57,4 @@ class LoadItem: is_table_required: bool = True custom_loader_name: str | None = None fallback_data: list[tuple[object, ...]] | None = None + order_by: list[str] | None = None diff --git a/temoa/db_schema/temoa_schema_v3_1.sql b/temoa/db_schema/temoa_schema_v3_1.sql index 303c74725..ff555aa4d 100644 --- a/temoa/db_schema/temoa_schema_v3_1.sql +++ b/temoa/db_schema/temoa_schema_v3_1.sql @@ -12,8 +12,6 @@ REPLACE INTO MetaData VALUES ('DB_MAJOR', 3, 'DB major version number'); REPLACE INTO MetaData VALUES ('DB_MINOR', 1, 'DB minor version number'); -REPLACE INTO MetaData -VALUES ('days_per_period', 365, 'count of days in each period'); CREATE TABLE IF NOT EXISTS MetaDataReal ( diff --git a/temoa/db_schema/temoa_schema_v4.sql b/temoa/db_schema/temoa_schema_v4.sql index 7830fd3b8..4f56ec264 100644 --- a/temoa/db_schema/temoa_schema_v4.sql +++ b/temoa/db_schema/temoa_schema_v4.sql @@ -12,8 +12,6 @@ REPLACE INTO metadata VALUES ('DB_MAJOR', 4, 'DB major version number'); REPLACE INTO metadata VALUES ('DB_MINOR', 0, 'DB minor version number'); -REPLACE INTO metadata -VALUES ('days_per_period', 365, 'count of days in each period'); CREATE TABLE IF NOT EXISTS metadata_real ( @@ -41,11 +39,6 @@ CREATE TABLE IF NOT EXISTS output_objective objective_name TEXT, total_system_cost REAL ); -CREATE TABLE IF NOT EXISTS season_label -( - season TEXT PRIMARY KEY, - notes TEXT -); CREATE TABLE IF NOT EXISTS sector_label ( sector TEXT PRIMARY KEY, @@ -67,10 +60,8 @@ CREATE TABLE IF NOT EXISTS capacity_credit CREATE TABLE IF NOT EXISTS capacity_factor_process ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), tech TEXT @@ -78,23 +69,21 @@ CREATE TABLE IF NOT EXISTS capacity_factor_process vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), + PRIMARY KEY (region, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE IF NOT EXISTS capacity_factor_tech ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), + PRIMARY KEY (region, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE IF NOT EXISTS capacity_to_activity @@ -219,17 +208,15 @@ CREATE TABLE IF NOT EXISTS demand CREATE TABLE IF NOT EXISTS demand_specific_distribution ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), demand_name TEXT REFERENCES commodity (name), dsd REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), + PRIMARY KEY (region, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); CREATE TABLE IF NOT EXISTS end_of_life_output @@ -266,10 +253,8 @@ CREATE TABLE IF NOT EXISTS efficiency CREATE TABLE IF NOT EXISTS efficiency_variable ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -282,7 +267,7 @@ CREATE TABLE IF NOT EXISTS efficiency_variable REFERENCES commodity (name), efficiency REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + PRIMARY KEY (region, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); CREATE TABLE IF NOT EXISTS emission_activity @@ -477,21 +462,17 @@ CREATE TABLE IF NOT EXISTS limit_degrowth_new_capacity_delta CREATE TABLE IF NOT EXISTS limit_storage_level_fraction ( region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), + season TEXT, tod TEXT REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), fraction REAL, notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) + CHECK (fraction >= 0 AND fraction <= 1), + PRIMARY KEY(region, season, tod, tech, operator) ); CREATE TABLE IF NOT EXISTS limit_activity ( @@ -601,16 +582,14 @@ CREATE TABLE IF NOT EXISTS limit_seasonal_capacity_factor ( region TEXT REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), factor REAL, notes TEXT, - PRIMARY KEY(region, period, season, tech_or_group, operator) + PRIMARY KEY(region, season, tech_or_group, operator) ); CREATE TABLE IF NOT EXISTS limit_tech_input_split ( @@ -706,7 +685,7 @@ CREATE TABLE IF NOT EXISTS output_curtailment period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -777,7 +756,7 @@ CREATE TABLE IF NOT EXISTS output_flow_in period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -801,7 +780,7 @@ CREATE TABLE IF NOT EXISTS output_flow_out period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -824,8 +803,7 @@ CREATE TABLE IF NOT EXISTS output_storage_level REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), + season TEXT, tod TEXT REFERENCES time_of_day (tod), tech TEXT @@ -871,31 +849,16 @@ CREATE TABLE IF NOT EXISTS region CREATE TABLE IF NOT EXISTS reserve_capacity_derate ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tech TEXT REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tech, vintage), + PRIMARY KEY (region, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -CREATE TABLE IF NOT EXISTS time_segment_fraction -( - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - segment_fraction REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); CREATE TABLE IF NOT EXISTS storage_duration ( region TEXT, @@ -930,24 +893,25 @@ REPLACE INTO technology_type VALUES ('ps', 'storage production technology'); -- CREATE TABLE IF NOT EXISTS time_manual -- ( --- period INTEGER --- REFERENCES time_period (period), -- season TEXT --- REFERENCES season_label (season), +-- REFERENCES time_season (season), -- tod TEXT -- REFERENCES time_of_day (tod), -- season_next TEXT --- REFERENCES season_label (season), +-- REFERENCES time_season (season), -- tod_next TEXT -- REFERENCES time_of_day (tod), -- notes TEXT, --- PRIMARY KEY (period, season, tod) +-- PRIMARY KEY (season, tod) -- ); CREATE TABLE IF NOT EXISTS time_of_day ( sequence INTEGER UNIQUE, tod TEXT - PRIMARY KEY + PRIMARY KEY, + hours REAL NOT NULL DEFAULT 1, + notes TEXT, + CHECK (hours > 0) ); CREATE TABLE IF NOT EXISTS time_period ( @@ -1046,23 +1010,23 @@ CREATE TABLE IF NOT EXISTS output_cost CREATE TABLE IF NOT EXISTS time_season ( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - season TEXT REFERENCES season_label(season), + sequence INTEGER UNIQUE, + season TEXT, + segment_fraction REAL NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, season) + PRIMARY KEY (season), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) ); CREATE TABLE IF NOT EXISTS time_season_sequential ( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, + sequence INTEGER UNIQUE, seas_seq TEXT, - season TEXT REFERENCES season_label(season), - num_days REAL NOT NULL, + season TEXT REFERENCES time_season(season), + segment_fraction REAL NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) + PRIMARY KEY (seas_seq), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) ); CREATE TABLE IF NOT EXISTS myopic_efficiency diff --git a/temoa/extensions/myopic/evolution_updater.py b/temoa/extensions/myopic/evolution_updater.py index 6791a7eff..7d630dcaa 100644 --- a/temoa/extensions/myopic/evolution_updater.py +++ b/temoa/extensions/myopic/evolution_updater.py @@ -12,12 +12,11 @@ def iterate( ) -> None: """ This function is called at the end of each myopic iteration, - after the results have been recorded to the myopic database. + after the results have been recorded to the myopic database. You can use it to update your myopic database with any additional information you want to track across iterations, or to implement an evolving myopic approach where the model structure changes across iterations based on some user-defined logic. - Parameters: - idx (MyopicIndex): The index object for the current iteration, containing information about the base year, view depth, etc. @@ -28,9 +27,9 @@ def iterate( - db_con (sqlite3.Connection): A connection object to the myopic database, which you can use to read/write data as needed. """ - + logger.info(f"Running myopic iteration updater for base year {idx.base_year}") - + # Update your myopic database here. - return \ No newline at end of file + return diff --git a/temoa/extensions/myopic/myopic_progress_mapper.py b/temoa/extensions/myopic/myopic_progress_mapper.py index 3f17adb18..c1d81508e 100644 --- a/temoa/extensions/myopic/myopic_progress_mapper.py +++ b/temoa/extensions/myopic/myopic_progress_mapper.py @@ -52,7 +52,7 @@ def timestamp(self) -> str: def report(self, mi: MyopicIndex, status): if status not in {'load', 'solve', 'report', 'check', 'evolve'}: raise ValueError(f'bad status: {status} received in MyopicProgressMapper') - + if status == 'evolve': repeats = self.years.index(mi.last_demand_year) - self.years.index(mi.base_year) + 1 print(self.timestamp(), end='') diff --git a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py index 1ca5ee123..9f06570e2 100644 --- a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py +++ b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py @@ -181,7 +181,7 @@ def flow_idxs_from_eac_idx(model: TemoaModel, reitvo: tuple) -> tuple[list[tuple psd_set = [ (p, s, d) for p in model.time_optimize - for s in model.time_season[p] + for s in model.time_season for d in model.time_of_day ] flow_idxs = [(r, *psd, i, t, v, o) for psd in psd_set] diff --git a/temoa/model_checking/validators.py b/temoa/model_checking/validators.py index d94406dd4..7ebf021fd 100644 --- a/temoa/model_checking/validators.py +++ b/temoa/model_checking/validators.py @@ -274,7 +274,6 @@ def validate_capacity_factor_process( model: TemoaModel, val: float, r: Region, - p: Period, s: Season, d: TimeOfDay, t: Technology, @@ -297,8 +296,7 @@ def validate_capacity_factor_process( return all( ( r in model.regions, - p in model.time_optimize, - s in model.time_season[p], + s in model.time_season, d in model.time_of_day, t in model.tech_with_capacity, v in model.vintage_all, diff --git a/temoa/tutorial_assets/config_sample.toml b/temoa/tutorial_assets/config_sample.toml index 50a50437b..e03cdd7dc 100644 --- a/temoa/tutorial_assets/config_sample.toml +++ b/temoa/tutorial_assets/config_sample.toml @@ -125,6 +125,11 @@ output_threshold_cost = 0.01 # storage must be tagged and the TimeSeasonSequential table filled. time_sequencing = 'seasonal_timeslices' +# Number of days represented by each planning period. +# Used to adjust flow variables for number of days represented by each season. +# E.g. 365 if all seasons collectively represent a year, 7 if modelling a single representative week. +days_per_period = 365 + # How contributions to the planning reserve margin are calculated # Options: # 'static' @@ -158,8 +163,8 @@ step_size = 2 # number of periods to step by (must be <= view depth) # to update the database. The view depth may shorten near the end of the planning # horizon to ensure that all iterations are performed. # If false, the evolution_script is not used and iterations end once view depth -# reaches the end of the planning horizon, to avoid redundant decisions with no -# new information. +# reaches the end of the planning horizon, to avoid redundant decisions with no +# new information. evolving = false evolution_script = "temoa/extensions/myopic/evolution_updater.py" diff --git a/temoa/tutorial_assets/utopia.sql b/temoa/tutorial_assets/utopia.sql index 0fc2fc035..7df58af48 100644 --- a/temoa/tutorial_assets/utopia.sql +++ b/temoa/tutorial_assets/utopia.sql @@ -15,10 +15,8 @@ CREATE TABLE capacity_credit CREATE TABLE capacity_factor_process ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), tech TEXT @@ -26,133 +24,65 @@ CREATE TABLE capacity_factor_process vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), + PRIMARY KEY (region, season, tod, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'inter','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'inter','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'winter','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'winter','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'summer','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2000,'summer','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','day','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'inter','night','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','day','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'winter','night','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','day','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia',2010,'summer','night','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','inter','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','inter','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','winter','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','winter','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','summer','day','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','summer','night','E31',2000,0.2753,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','inter','day','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','inter','night','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','winter','day','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','winter','night','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','summer','day','E31',2010,0.2756,''); +INSERT INTO "capacity_factor_process" VALUES('utopia','summer','night','E31',2010,0.2756,''); CREATE TABLE capacity_factor_tech ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), + PRIMARY KEY (region, season, tod, tech), CHECK (factor >= 0 AND factor <= 1) ); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E01',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E21',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E31',0.275,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E51',0.17,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E70',0.8,''); +INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E70',0.8,''); CREATE TABLE capacity_to_activity ( region TEXT, @@ -468,49 +398,27 @@ INSERT INTO "demand" VALUES('utopia',2010,'TX',11.69,'PJ',''); CREATE TABLE demand_specific_distribution ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), demand_name TEXT REFERENCES commodity (name), dsd REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), + PRIMARY KEY (region, season, tod, demand_name), CHECK (dsd >= 0 AND dsd <= 1) ); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','day','RH',0.12,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','night','RH',0.06,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','day','RH',0.5467,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','night','RH',0.2733,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'summer','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'summer','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','day','RL',0.5,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','night','RL',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','day','RH',0.12,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','night','RH',0.06,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','day','RH',0.5467,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','night','RH',0.2733,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'summer','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'summer','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','day','RL',0.5,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','night','RL',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','day','RH',0.12,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','night','RH',0.06,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','day','RH',0.5467,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','night','RH',0.2733,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'summer','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'summer','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','day','RL',0.5,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','night','RL',0.1,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','inter','day','RH',0.12,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','inter','night','RH',0.06,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','winter','day','RH',0.5467,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','winter','night','RH',0.2733,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','inter','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','inter','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','summer','day','RL',0.15,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','summer','night','RL',0.05,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','winter','day','RL',0.5,''); +INSERT INTO "demand_specific_distribution" VALUES('utopia','winter','night','RL',0.1,''); CREATE TABLE efficiency ( region TEXT, @@ -595,10 +503,8 @@ INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',2010,'TX',0.231,'PJ / (PJ)' CREATE TABLE efficiency_variable ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -611,7 +517,7 @@ CREATE TABLE efficiency_variable REFERENCES commodity (name), efficiency REAL, notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), + PRIMARY KEY (region, season, tod, input_comm, tech, vintage, output_comm), CHECK (efficiency > 0) ); CREATE TABLE emission_activity @@ -978,35 +884,29 @@ CREATE TABLE limit_seasonal_capacity_factor ( region TEXT REFERENCES region (region), - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tech_or_group TEXT, operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), factor REAL, notes TEXT, - PRIMARY KEY(region, period, season, tech_or_group, operator) + PRIMARY KEY(region, season, tech_or_group, operator) ); CREATE TABLE limit_storage_level_fraction ( region TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), + season TEXT, tod TEXT REFERENCES time_of_day (tod), tech TEXT REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), operator TEXT NOT NULL DEFAULT "le" REFERENCES operator (operator), fraction REAL, notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) + CHECK (fraction >= 0 AND fraction <= 1), + PRIMARY KEY(region, season, tod, tech, operator) ); CREATE TABLE limit_tech_input_split ( @@ -1116,7 +1016,6 @@ CREATE TABLE metadata notes TEXT, PRIMARY KEY (element) ); -INSERT INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); INSERT INTO "metadata" VALUES('DB_MINOR',0,''); CREATE TABLE metadata_real @@ -1196,7 +1095,7 @@ CREATE TABLE output_curtailment period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES time_period (period), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -1245,7 +1144,7 @@ CREATE TABLE output_flow_in period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -1269,7 +1168,7 @@ CREATE TABLE output_flow_out period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT @@ -1350,8 +1249,7 @@ CREATE TABLE output_storage_level REFERENCES sector_label (sector), period INTEGER REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), + season TEXT, tod TEXT REFERENCES time_of_day (tod), tech TEXT @@ -1398,16 +1296,14 @@ INSERT INTO "region" VALUES('utopia',NULL); CREATE TABLE reserve_capacity_derate ( region TEXT, - period INTEGER - REFERENCES time_period (period), season TEXT - REFERENCES season_label (season), + REFERENCES time_season (season), tech TEXT REFERENCES technology (tech), vintage INTEGER, factor REAL, notes TEXT, - PRIMARY KEY (region, period, season, tech, vintage), + PRIMARY KEY (region, season, tech, vintage), CHECK (factor >= 0 AND factor <= 1) ); CREATE TABLE rps_requirement @@ -1421,14 +1317,6 @@ CREATE TABLE rps_requirement requirement REAL NOT NULL, notes TEXT ); -CREATE TABLE season_label -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "season_label" VALUES('inter',NULL); -INSERT INTO "season_label" VALUES('summer',NULL); -INSERT INTO "season_label" VALUES('winter',NULL); CREATE TABLE sector_label ( sector TEXT PRIMARY KEY, @@ -1512,10 +1400,13 @@ CREATE TABLE time_of_day ( sequence INTEGER UNIQUE, tod TEXT - PRIMARY KEY + PRIMARY KEY, + hours REAL NOT NULL DEFAULT 1, + notes TEXT, + CHECK (hours > 0) ); -INSERT INTO "time_of_day" VALUES(1,'day'); -INSERT INTO "time_of_day" VALUES(2,'night'); +INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(1,'day',16); +INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(2,'night',8); CREATE TABLE time_period ( sequence INTEGER UNIQUE, @@ -1541,85 +1432,25 @@ INSERT INTO "time_period_type" VALUES('e','existing vintages'); INSERT INTO "time_period_type" VALUES('f','future'); CREATE TABLE time_season ( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - season TEXT REFERENCES season_label(season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); -INSERT INTO "time_season" VALUES(1990,1,'inter',NULL); -INSERT INTO "time_season" VALUES(1990,2,'summer',NULL); -INSERT INTO "time_season" VALUES(1990,3,'winter',NULL); -INSERT INTO "time_season" VALUES(2000,1,'inter',NULL); -INSERT INTO "time_season" VALUES(2000,2,'summer',NULL); -INSERT INTO "time_season" VALUES(2000,3,'winter',NULL); -INSERT INTO "time_season" VALUES(2010,1,'inter',NULL); -INSERT INTO "time_season" VALUES(2010,2,'summer',NULL); -INSERT INTO "time_season" VALUES(2010,3,'winter',NULL); -CREATE TABLE time_season_all -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, - season TEXT - REFERENCES season_label (season), + sequence INTEGER UNIQUE, + season TEXT, + segment_fraction REAL NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, season) + PRIMARY KEY (season), + CHECK (segment_fraction >= 0 AND segment_fraction <= 1) ); +INSERT INTO "time_season" VALUES(0,'inter',0.25,NULL); +INSERT INTO "time_season" VALUES(1,'summer',0.25,NULL); +INSERT INTO "time_season" VALUES(2,'winter',0.5,NULL); CREATE TABLE time_season_sequential ( - period INTEGER REFERENCES time_period (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT REFERENCES season_label(season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); -CREATE TABLE time_season_to_sequential -( - period INTEGER - REFERENCES time_period (period), - sequence INTEGER, + sequence INTEGER UNIQUE, seas_seq TEXT, - season TEXT - REFERENCES season_label (season), - num_days REAL NOT NULL, + season TEXT REFERENCES time_season(season), + segment_fraction REAL NOT NULL, notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); -CREATE TABLE time_segment_fraction -( - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES season_label (season), - tod TEXT - REFERENCES time_of_day (tod), - segment_fraction REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), + PRIMARY KEY (seas_seq), CHECK (segment_fraction >= 0 AND segment_fraction <= 1) ); -INSERT INTO "time_segment_fraction" VALUES(1990,'inter','day',0.1667,'# I-D'); -INSERT INTO "time_segment_fraction" VALUES(1990,'inter','night',0.0833,'# I-N'); -INSERT INTO "time_segment_fraction" VALUES(1990,'summer','day',0.1667,'# S-D'); -INSERT INTO "time_segment_fraction" VALUES(1990,'summer','night',0.0833,'# S-N'); -INSERT INTO "time_segment_fraction" VALUES(1990,'winter','day',0.3333,'# W-D'); -INSERT INTO "time_segment_fraction" VALUES(1990,'winter','night',0.1667,'# W-N'); -INSERT INTO "time_segment_fraction" VALUES(2000,'inter','day',0.1667,'# I-D'); -INSERT INTO "time_segment_fraction" VALUES(2000,'inter','night',0.0833,'# I-N'); -INSERT INTO "time_segment_fraction" VALUES(2000,'summer','day',0.1667,'# S-D'); -INSERT INTO "time_segment_fraction" VALUES(2000,'summer','night',0.0833,'# S-N'); -INSERT INTO "time_segment_fraction" VALUES(2000,'winter','day',0.3333,'# W-D'); -INSERT INTO "time_segment_fraction" VALUES(2000,'winter','night',0.1667,'# W-N'); -INSERT INTO "time_segment_fraction" VALUES(2010,'inter','day',0.1667,'# I-D'); -INSERT INTO "time_segment_fraction" VALUES(2010,'inter','night',0.0833,'# I-N'); -INSERT INTO "time_segment_fraction" VALUES(2010,'summer','day',0.1667,'# S-D'); -INSERT INTO "time_segment_fraction" VALUES(2010,'summer','night',0.0833,'# S-N'); -INSERT INTO "time_segment_fraction" VALUES(2010,'winter','day',0.3333,'# W-D'); -INSERT INTO "time_segment_fraction" VALUES(2010,'winter','night',0.1667,'# W-N'); CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); COMMIT; diff --git a/temoa/types/dict_types.py b/temoa/types/dict_types.py index 8fb2fb3da..ba288ea98 100644 --- a/temoa/types/dict_types.py +++ b/temoa/types/dict_types.py @@ -48,9 +48,9 @@ # Time sequencing dictionary types -TimeNextDict = dict[tuple[Period, Season, TimeOfDay], tuple[Season, TimeOfDay]] -TimeNextSequentialDict = dict[tuple[Period, Season], Season] -SequentialToSeasonDict = dict[tuple[Period, Season], Season] +TimeNextDict = dict[tuple[Season, TimeOfDay], tuple[Season, TimeOfDay]] +TimeNextSequentialDict = dict[Season, Season] +SequentialToSeasonDict = dict[Season, Season] # Geography/exchange dictionary types @@ -65,8 +65,8 @@ # Switching/boolean flag dictionary types EfficiencyVariableDict = dict[ - tuple[Region, Period, Commodity, Technology, Vintage, Commodity], bool + tuple[Region, Commodity, Technology, Vintage, Commodity], bool ] -CapacityFactorProcessDict = dict[tuple[Region, Period, Technology, Vintage], bool] +CapacityFactorProcessDict = dict[tuple[Region, Technology, Vintage], bool] SeasonalStorageDict = dict[Technology, bool] SurvivalCurveProcessDict = dict[tuple[Region, Technology, Vintage], bool] diff --git a/temoa/utilities/db_migration_v3_1_to_v4.py b/temoa/utilities/db_migration_v3_1_to_v4.py index 55e6e2e67..be294bb7b 100644 --- a/temoa/utilities/db_migration_v3_1_to_v4.py +++ b/temoa/utilities/db_migration_v3_1_to_v4.py @@ -149,19 +149,38 @@ def migrate_all(args) -> None: r[0] for r in con_new.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall() ] - print('DEBUG mapping samples:') - for t in ( - 'TimeSeason', - 'time_season', - 'TimeSeasonSequential', - 'time_season_sequential', - 'SegFrac', - ): - print(f' {t} -> {map_token_no_cascade(t)}') total = 0 for old in old_tables: if old.lower().startswith('sqlite_'): continue + if old in ( + 'MetaData', + 'MetaDataReal', + 'TimeSeason', + 'time_season', + 'time_of_day', + 'time_season_sequential', + 'TimeSeasonSequential', + ): + continue + if old == 'CapacityFactorProcess': + # Special case: aggregate across periods + old_data = con_old.execute( + 'SELECT region, season, tod, tech, vintage, AVG(factor) ' + 'FROM CapacityFactorProcess ' + 'GROUP BY region, season, tod, tech, vintage' + ).fetchall() + if old_data: + con_new.executemany( + 'INSERT OR REPLACE INTO capacity_factor_process ' + '(region, season, tod, tech, vintage, factor) ' + 'VALUES (?, ?, ?, ?, ?, ?)', + old_data, + ) + print(f'Aggregated {len(old_data)} rows: {old} -> capacity_factor_process') + total += len(old_data) + continue + new = map_token_no_cascade(old) if new not in new_tables: candidates = [t for t in new_tables if t == new or t.startswith(new) or new in t] @@ -175,10 +194,69 @@ def migrate_all(args) -> None: print(f'Copied {n} rows: {old} -> {new}') total += n except Exception: - import traceback + print(f'Error migrating {old} -> {new}') + raise + + # --- Custom logic for restructured tables (Seasons/TOD) --- + print('Processing custom migration logic for seasons and time-of-day...') + + # 1. time_season (aggregate from TimeSegmentFraction) + try: + old_data = con_old.execute( + 'SELECT season, SUM(segfrac) / COUNT(DISTINCT period) ' + 'FROM TimeSegmentFraction GROUP BY season' + ).fetchall() + if old_data: + con_new.executemany( + 'INSERT OR REPLACE INTO time_season (season, segment_fraction) VALUES (?, ?)', + old_data, + ) + print(f'Propagated {len(old_data)} seasons to time_season.') + total += len(old_data) + except sqlite3.OperationalError: + print('WARNING: Could not migrate seasons from TimeSegmentFraction.') + + # 2. time_of_day (aggregate from TimeSegmentFraction) + try: + old_data = con_old.execute( + 'SELECT tod, SUM(segfrac) FROM TimeSegmentFraction GROUP BY tod' + ).fetchall() + if old_data: + num_periods = ( + con_old.execute( + 'SELECT COUNT(DISTINCT period) FROM TimeSegmentFraction' + ).fetchone()[0] + or 1 + ) + normalized_data = [(r[0], (r[1] / num_periods) * 24.0) for r in old_data] + con_new.executemany( + 'INSERT OR REPLACE INTO time_of_day (tod, hours) VALUES (?, ?)', normalized_data + ) + print(f'Propagated {len(normalized_data)} time-of-day slots to time_of_day.') + total += len(normalized_data) + except sqlite3.OperationalError: + print('WARNING: Could not migrate time_of_day from TimeSegmentFraction.') - print(f'Error migrating {old} -> {new}:') - traceback.print_exc() + # 3. time_season_sequential (aggregate from TimeSeasonSequential) + try: + first_period = con_old.execute('SELECT MIN(period) FROM TimeSeasonSequential').fetchone()[0] + if first_period: + old_data = con_old.execute( + 'SELECT tss.seas_seq, tss.season, (tss.num_days / 365.25) ' + 'FROM TimeSeasonSequential tss ' + 'WHERE tss.period = ?', + (first_period,), + ).fetchall() + if old_data: + con_new.executemany( + 'INSERT OR REPLACE INTO time_season_sequential ' + '(seas_seq, season, segment_fraction) VALUES (?, ?, ?)', + old_data, + ) + print(f'Propagated {len(old_data)} sequential seasons to time_season_sequential.') + total += len(old_data) + except (sqlite3.OperationalError, TypeError): + pass # ensure metadata version bumped cur = con_new.cursor() diff --git a/temoa/utilities/sql_migration_v3_1_to_v4.py b/temoa/utilities/sql_migration_v3_1_to_v4.py index f888d28e6..357e2f17e 100644 --- a/temoa/utilities/sql_migration_v3_1_to_v4.py +++ b/temoa/utilities/sql_migration_v3_1_to_v4.py @@ -165,23 +165,42 @@ def migrate_dump_to_sqlite(args) -> None: if not r[0].lower().startswith('sqlite_') ] - if args.debug: - print('DEBUG Mapping samples:') - for t in ( + # --- 3. Programmatically copy data --- + total_rows_copied = 0 + for old_table_name in old_tables: + if old_table_name in ( + 'MetaData', + 'MetaDataReal', 'TimeSeason', 'time_season', - 'TimeSeasonSequential', + 'time_of_day', 'time_season_sequential', - 'SegFrac', - 'segfrac', + 'TimeSeasonSequential', ): - print(f' {t} -> {map_token_no_cascade(t)}') - print('\nDEBUG Old DB tables:', old_tables) - print('DEBUG New DB tables:', new_db_tables) + if args.debug: + print(f'DEBUG: Skipping {old_table_name} (handled by custom logic)') + continue + + if old_table_name == 'CapacityFactorProcess': + # Special case: aggregate across periods + old_data = con_old_in_memory.execute( + 'SELECT region, season, tod, tech, vintage, AVG(factor) ' + 'FROM CapacityFactorProcess ' + 'GROUP BY region, season, tod, tech, vintage' + ).fetchall() + if old_data: + con_new_in_memory.executemany( + 'INSERT OR REPLACE INTO capacity_factor_process ' + '(region, season, tod, tech, vintage, factor) ' + 'VALUES (?, ?, ?, ?, ?, ?)', + old_data, + ) + print( + f'Aggregated {len(old_data)} rows: {old_table_name} -> capacity_factor_process' + ) + total_rows_copied += len(old_data) + continue - # --- 3. Programmatically copy data --- - total_rows_copied = 0 - for old_table_name in old_tables: mapped_new_table_name = map_table_name(old_table_name) if mapped_new_table_name not in new_db_tables: @@ -265,6 +284,77 @@ def migrate_dump_to_sqlite(args) -> None: print(f'Copied {rows_copied_this_table} rows: {old_table_name} -> {mapped_new_table_name}') total_rows_copied += rows_copied_this_table + # --- 3b. Custom logic for restructured tables (Seasons/TOD) --- + print('Processing custom migration logic for seasons and time-of-day...') + + # 1. time_season (aggregate from TimeSegmentFraction) + try: + # v3.1: TimeSegmentFraction(period, season, tod, segfrac) + # v4: time_season(season, segment_fraction) + old_data = con_old_in_memory.execute( + 'SELECT season, SUM(segfrac) / COUNT(DISTINCT period) ' + 'FROM TimeSegmentFraction GROUP BY season' + ).fetchall() + if old_data: + con_new_in_memory.executemany( + 'INSERT OR REPLACE INTO time_season (season, segment_fraction) VALUES (?, ?)', + old_data, + ) + print(f'Propagated {len(old_data)} seasons to time_season.') + except sqlite3.OperationalError: + print('WARNING: Could not migrate seasons from TimeSegmentFraction (table missing?)') + + # 2. time_of_day (aggregate from TimeSegmentFraction) + try: + # v3.1: TimeSegmentFraction(period, season, tod, segfrac) -> + # tod_weights = SUM(segfrac) over season + # v4: time_of_day(tod, hours) + old_data = con_old_in_memory.execute( + 'SELECT tod, SUM(segfrac) FROM TimeSegmentFraction GROUP BY tod' + ).fetchall() + if old_data: + num_periods = ( + con_old_in_memory.execute( + 'SELECT COUNT(DISTINCT period) FROM TimeSegmentFraction' + ).fetchone()[0] + or 1 + ) + # Normalize to 24 hours + normalized_data = [(r[0], (r[1] / num_periods) * 24.0) for r in old_data] + con_new_in_memory.executemany( + 'INSERT OR REPLACE INTO time_of_day (tod, hours) VALUES (?, ?)', + normalized_data, + ) + print(f'Propagated {len(normalized_data)} time-of-day slots to time_of_day.') + except sqlite3.OperationalError: + print('WARNING: Could not migrate time_of_day from TimeSegmentFraction.') + + # 3. time_season_sequential (aggregate from TimeSeasonSequential and TimeSegmentFraction) + # This is tricky because v3.1 had period-dependent sequential seasons. + # We take the first available period's definition. + try: + # v3.1: TimeSeasonSequential(period, sequence, seas_seq, season, num_days) + # v4: time_season_sequential(seas_seq, season, segment_fraction) + first_period = con_old_in_memory.execute( + 'SELECT MIN(period) FROM TimeSeasonSequential' + ).fetchone()[0] + if first_period: + old_data = con_old_in_memory.execute( + 'SELECT tss.seas_seq, tss.season, (tss.num_days / 365.25) ' + 'FROM TimeSeasonSequential tss ' + 'WHERE tss.period = ?', + (first_period,), + ).fetchall() + if old_data: + con_new_in_memory.executemany( + 'INSERT OR REPLACE INTO time_season_sequential ' + '(seas_seq, season, segment_fraction) VALUES (?, ?, ?)', + old_data, + ) + print(f'Propagated {len(old_data)} sequential seasons to time_season.') + except sqlite3.OperationalError: + pass # Optional table + # --- Final updates and dump --- con_new_in_memory.execute("INSERT OR REPLACE INTO metadata VALUES ('DB_MAJOR', 4, '')") con_new_in_memory.execute("INSERT OR REPLACE INTO metadata VALUES ('DB_MINOR', 0, '')") diff --git a/temoa/utilities/unit_cost_explorer.py b/temoa/utilities/unit_cost_explorer.py index 89cbabcb4..6cafe9acb 100644 --- a/temoa/utilities/unit_cost_explorer.py +++ b/temoa/utilities/unit_cost_explorer.py @@ -95,8 +95,7 @@ print('building storage level constraint...') # More SETS -model.time_season_all.construct(['winter', 'summer']) -model.time_season.construct(data={2020: {'winter', 'summer'}, 2025: {'winter', 'summer'}}) +model.time_season.construct(['winter', 'summer']) model.days_per_period.construct(data={None: 365}) tod_slices = 2 model.time_of_day.construct(data=range(1, tod_slices + 1)) @@ -119,19 +118,23 @@ seasonal_fractions = {'winter': 0.4, 'summer': 0.6} model.segment_fraction.construct( data={ - (p, s, d): seasonal_fractions[s] / tod_slices + (s, d): seasonal_fractions[s] / tod_slices for d in model.time_of_day - for p in model.time_optimize - for s in model.time_season[p] + for s in model.time_season } ) # QA the total -print(f'quality check. Total of all segment_fraction: {sum(model.segment_fraction.values()):0.3f}') +print( + 'quality check. Total of all segment_fraction: ' + f'{sum(value(v) for v in model.segment_fraction.values()):0.3f}' +) model.process_life_frac.construct(data={('A', 2020, 'battery', 2020): 1.0}) # More VARS model.v_storage_level.construct() -model.segment_fraction_per_season.construct() +model.segment_fraction_per_season.construct( + data=seasonal_fractions +) model.is_seasonal_storage['battery'] = False upper_limit = storage_energy_upper_bound_constraint(model, 'A', 2020, 'winter', 1, 'battery', 2020) @@ -140,7 +143,7 @@ # cross-check the multiplier... mulitplier = ( storage_dur - * model.segment_fraction_per_season[2020, 'winter'] + * model.segment_fraction_per_season['winter'] * model.days_per_period * c2a * c diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index aacfd3d50..2852819f2 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -19,15 +19,17 @@ class ExpectedVals(Enum): test_vals = { 'test_system': { # reduced after removing ancient 1-year-shift obj function bug - ExpectedVals.OBJ_VALUE: 468550.1905, + # increased by ~25 after removing period index from storagefrac (more constraints) + ExpectedVals.OBJ_VALUE: 468575.0703, ExpectedVals.EFF_DOMAIN_SIZE: 30720, ExpectedVals.EFF_INDEX_SIZE: 74, # increased by 2 when reworking storageinit. # increased after making annualretirement derived var # reduced 2025/07/25 by 504 after annualising demands # increased 2025/08/19 after making annual demands optional + # increased by 10 after removing period index from storagefrac (more constraints) # increased by 48 after tying v_storage_level[d_last] to v_storage_init - ExpectedVals.CONSTR_COUNT: 2858, + ExpectedVals.CONSTR_COUNT: 2868, # reduced by 6 when reworking storageinit. # increased after making annualretirement derived var # reduced 2025/07/21 after removing existing vintage v_new_capacity indices @@ -41,7 +43,8 @@ class ExpectedVals(Enum): # reduced after removing ancient 1-year-shift obj function bug # increased after rework of inter-season sequencing # reduced after changing fixed costs from MLP to PL - ExpectedVals.OBJ_VALUE: 34711.5173, + # reduced by <1 after changing season definition (segfrac no longer rounded) + ExpectedVals.OBJ_VALUE: 34710.6730, ExpectedVals.EFF_DOMAIN_SIZE: 12312, ExpectedVals.EFF_INDEX_SIZE: 64, # reduced 3/27: unlim_cap techs now employed. diff --git a/tests/test_exchange_cost_ledger.py b/tests/test_exchange_cost_ledger.py index 1bee47806..8caa1a5ff 100644 --- a/tests/test_exchange_cost_ledger.py +++ b/tests/test_exchange_cost_ledger.py @@ -19,7 +19,7 @@ # these are the necessary Temoa elements to make the ledger work data = { - 'time_season': {2000: [1]}, + 'time_season': [1], 'time_of_day': {1}, 'tech_annual': set(), 'lifetime_process': {('A-B', 't1', 2000): 30, ('B-A', 't1', 2000): 30}, diff --git a/tests/test_full_runs.py b/tests/test_full_runs.py index 9cb39cec7..cbd979f7e 100644 --- a/tests/test_full_runs.py +++ b/tests/test_full_runs.py @@ -120,7 +120,8 @@ def test_myopic_utopia( # reduced this target after storageinit rework # reduced after removing ancient 1-year shift bug from objective function # increased after rework of inter-season sequencing - assert invest_sum == pytest.approx(11004.8335), 'sum of investment costs did not match expected' + # reduced by <1 after changing season definition (segfrac no longer rounded) + assert invest_sum == pytest.approx(11004.3544), 'sum of investment costs did not match expected' con.close() @@ -139,7 +140,8 @@ def test_stochastic_utopia( _, _, _, sequencer = system_test_run # Stochastic Expected Value for current utopia configuration - expected_obj = 34389.9878 + # reduced by <1 after changing season definition (segfrac no longer rounded) + expected_obj = 34389.1352 assert sequencer.stochastic_sequencer is not None assert sequencer.stochastic_sequencer.objective_value == pytest.approx(expected_obj, rel=1e-5) diff --git a/tests/test_myopic_sequencer.py b/tests/test_myopic_sequencer.py index e63f5e707..f0dac220a 100644 --- a/tests/test_myopic_sequencer.py +++ b/tests/test_myopic_sequencer.py @@ -7,45 +7,25 @@ params = [ { 'name': 'single_step', - 'conf_data': { - 'step_size': 1, - 'view_depth': 3, - 'evolving': False, - 'evolution_script': None - }, + 'conf_data': {'step_size': 1, 'view_depth': 3, 'evolving': False, 'evolution_script': None}, 'expected_steps': 2, 'expected_last_base_year': 1, }, { 'name': 'triple_step', - 'conf_data': { - 'step_size': 3, - 'view_depth': 4, - 'evolving': False, - 'evolution_script': None - }, + 'conf_data': {'step_size': 3, 'view_depth': 4, 'evolving': False, 'evolution_script': None}, 'expected_steps': 1, # see end of horizon immediately 'expected_last_base_year': 0, }, { 'name': 'single_step_evolving', - 'conf_data': { - 'step_size': 1, - 'view_depth': 3, - 'evolving': True, - 'evolution_script': None - }, + 'conf_data': {'step_size': 1, 'view_depth': 3, 'evolving': True, 'evolution_script': None}, 'expected_steps': 4, 'expected_last_base_year': 3, }, # 4 single steps { 'name': 'triple_step_evolving', - 'conf_data': { - 'step_size': 3, - 'view_depth': 4, - 'evolving': True, - 'evolution_script': None - }, + 'conf_data': {'step_size': 3, 'view_depth': 4, 'evolving': True, 'evolution_script': None}, 'expected_steps': 2, # 1 step of 3, followed by 1 step of 1 'expected_last_base_year': 3, }, diff --git a/tests/test_storage.py b/tests/test_storage.py index 90b9311c7..30a2827fe 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -37,11 +37,11 @@ def test_storage_fraction(system_test_run: tuple[str, Any, TemoaModel, Any]) -> for r, p, s, d, t, v, op in model.limit_storage_fraction_constraint_rpsdtv: energy = ( - model.limit_storage_fraction[r, p, s, d, t, v, op] + model.limit_storage_fraction[r, s, d, t, op] * model.v_capacity[r, p, t, v].value * model.capacity_to_activity[r, t] * (model.storage_duration[r, t] / 8760) - * model.segment_fraction_per_season[p, s] + * model.segment_fraction_per_season[s] * model.days_per_period * model.process_life_frac[r, p, t, v] ) @@ -86,13 +86,13 @@ def test_state_sequencing(system_test_run: tuple[str, Any, TemoaModel, Any]) -> for S_i in model.process_inputs_by_output[r, p, t, v, S_o] ) + s_next, d_next = model.time_next[s, d] stored_energy = charge - discharge if model.is_seasonal_storage[t]: # Seasonal storage: time_next chain (last tod skipped) if d == d_last: continue # handled by seasonal_storage_energy_constraint - s_next, d_next = model.time_next[p, s, d] state = model.v_storage_level[r, p, s, d, t, v].value next_state = model.v_storage_level[r, p, s_next, d_next, t, v].value assert state + stored_energy == pytest.approx(next_state, abs=1e-5), ( @@ -100,7 +100,6 @@ def test_state_sequencing(system_test_run: tuple[str, Any, TemoaModel, Any]) -> ) else: # Non-seasonal: time_next chain, v_storage_init at d_last - s_next, d_next = model.time_next[p, s, d] if d == d_last: prev_state = model.v_storage_init[r, p, s, t, v].value else: diff --git a/tests/test_v4_migration.py b/tests/test_v4_migration.py new file mode 100644 index 000000000..644c6fff6 --- /dev/null +++ b/tests/test_v4_migration.py @@ -0,0 +1,105 @@ +import sqlite3 +import subprocess +import sys +from pathlib import Path + +import pytest + +# Constants +REPO_ROOT = Path(__file__).parents[1] +UTILITIES_DIR = REPO_ROOT / 'temoa' / 'utilities' +SCHEMA_V3_1 = REPO_ROOT / 'temoa' / 'db_schema' / 'temoa_schema_v3_1.sql' +SCHEMA_V4 = REPO_ROOT / 'temoa' / 'db_schema' / 'temoa_schema_v4.sql' +MOCK_DATA = REPO_ROOT / 'tests' / 'testing_data' / 'migration_v3_1_mock.sql' + + +def test_v4_migrations(tmp_path: Path) -> None: + """Test both SQL and SQLite v4 migrators.""" + + # 1. Create v3.1 SQLite DB + db_v3_1 = tmp_path / 'test_v3_1.sqlite' + with sqlite3.connect(db_v3_1) as conn: + conn.execute('PRAGMA foreign_keys = OFF') + conn.executescript(SCHEMA_V3_1.read_text()) + conn.executescript(MOCK_DATA.read_text()) + conn.execute('PRAGMA foreign_keys = ON') + + # 2. Dump v3.1 to SQL + sql_v3_1 = tmp_path / 'test_v3_1.sql' + with open(sql_v3_1, 'w') as f: + for line in sqlite3.connect(db_v3_1).iterdump(): + f.write(line + '\n') + + # 3. Verify SQL migration script + sql_v4_migrated = tmp_path / 'test_v4_migrated.sql' + subprocess.run( + [ + sys.executable, + str(UTILITIES_DIR / 'sql_migration_v3_1_to_v4.py'), + '--input', + str(sql_v3_1), + '--schema', + str(SCHEMA_V4), + '--output', + str(sql_v4_migrated), + ], + check=True, + ) + + # Load SQL result into memory to verify + conn_sql = sqlite3.connect(':memory:') + conn_sql.executescript(sql_v4_migrated.read_text()) + + _verify_migrated_data(conn_sql) + + # 4. Verify SQLite direct migration script + db_v4_migrated = tmp_path / 'test_v4_migrated.sqlite' + subprocess.run( + [ + sys.executable, + str(UTILITIES_DIR / 'db_migration_v3_1_to_v4.py'), + '--source', + str(db_v3_1), + '--schema', + str(SCHEMA_V4), + '--out', + str(db_v4_migrated), + ], + check=True, + ) + + with sqlite3.connect(db_v4_migrated) as conn_db: + _verify_migrated_data(conn_db) + + +def _verify_migrated_data(conn: sqlite3.Connection) -> None: + # Check time_season restructuring (aggregated from TimeSegmentFraction) + # Summer: 0.4 + 0.3 = 0.7 + # Winter: 0.2 + 0.1 = 0.3 + seasons = dict(conn.execute('SELECT season, segment_fraction FROM time_season').fetchall()) + assert seasons['summer'] == pytest.approx(0.7) + assert seasons['winter'] == pytest.approx(0.3) + + # Check time_of_day restructuring (normalized to 24 hours based on weights) + # Day weight: 0.2 + 0.4 = 0.6 + # Night weight: 0.1 + 0.3 = 0.4 + # Normalized to 24: Day=0.6*24=14.4, Night=0.4*24=9.6 + tods = dict(conn.execute('SELECT tod, hours FROM time_of_day').fetchall()) + assert tods['day'] == pytest.approx(14.4) + assert tods['night'] == pytest.approx(9.6) + + # Check period removal from capacity_factor_process + # Original PK: (region, period, season, tod, tech, vintage) + # New PK: (region, season, tod, tech, vintage) + cols = [c[1] for c in conn.execute('PRAGMA table_info(capacity_factor_process)').fetchall()] + assert 'period' not in cols + + rows = conn.execute( + 'SELECT region, season, tod, tech, vintage, factor FROM capacity_factor_process' + ).fetchall() + assert len(rows) == 1 + assert rows[0] == ('R1', 'winter', 'day', 'T1', 2030, pytest.approx(0.6)) + + # Check metadata version + major = conn.execute("SELECT value FROM metadata WHERE element='DB_MAJOR'").fetchone()[0] + assert int(major) == 4 diff --git a/tests/testing_configs/config_annualised_demand.toml b/tests/testing_configs/config_annualised_demand.toml index 3e6393fe5..198a7982f 100644 --- a/tests/testing_configs/config_annualised_demand.toml +++ b/tests/testing_configs/config_annualised_demand.toml @@ -8,6 +8,7 @@ save_excel = false save_duals = false save_lp_file = false time_sequencing = "representative_periods" +days_per_period = 365 reserve_margin = "static" [MGA] diff --git a/tests/testing_configs/config_emissions.toml b/tests/testing_configs/config_emissions.toml index f06f424da..a3ec86a4b 100644 --- a/tests/testing_configs/config_emissions.toml +++ b/tests/testing_configs/config_emissions.toml @@ -8,6 +8,7 @@ save_excel = false save_duals = false save_lp_file = false time_sequencing = "seasonal_timeslices" +days_per_period = 365 reserve_margin = "static" [MGA] diff --git a/tests/testing_configs/config_link_test.toml b/tests/testing_configs/config_link_test.toml index ff8bab418..88192e4f4 100644 --- a/tests/testing_configs/config_link_test.toml +++ b/tests/testing_configs/config_link_test.toml @@ -11,6 +11,7 @@ save_excel = false save_duals = false save_lp_file = false time_sequencing = "seasonal_timeslices" +days_per_period = 365 reserve_margin = "static" [MGA] diff --git a/tests/testing_configs/config_materials.toml b/tests/testing_configs/config_materials.toml index 81bb00f00..3eae4926f 100644 --- a/tests/testing_configs/config_materials.toml +++ b/tests/testing_configs/config_materials.toml @@ -8,6 +8,7 @@ save_excel = false save_duals = false save_lp_file = false time_sequencing = "seasonal_timeslices" +days_per_period = 365 reserve_margin = "static" [MGA] diff --git a/tests/testing_configs/config_mediumville.toml b/tests/testing_configs/config_mediumville.toml index 53f1b935d..935abdbaa 100644 --- a/tests/testing_configs/config_mediumville.toml +++ b/tests/testing_configs/config_mediumville.toml @@ -8,6 +8,7 @@ save_excel = false save_duals = false save_lp_file = false time_sequencing = "seasonal_timeslices" +days_per_period = 365 reserve_margin = "static" [MGA] diff --git a/tests/testing_configs/config_seasonal_storage.toml b/tests/testing_configs/config_seasonal_storage.toml index 760a7b88e..927446558 100644 --- a/tests/testing_configs/config_seasonal_storage.toml +++ b/tests/testing_configs/config_seasonal_storage.toml @@ -8,6 +8,7 @@ save_excel = false save_duals = false save_lp_file = false time_sequencing = "representative_periods" +days_per_period = 365 reserve_margin = "static" [MGA] diff --git a/tests/testing_configs/config_storageville.toml b/tests/testing_configs/config_storageville.toml index df73dad14..79a2585d0 100644 --- a/tests/testing_configs/config_storageville.toml +++ b/tests/testing_configs/config_storageville.toml @@ -8,6 +8,7 @@ save_excel = false save_duals = false save_lp_file = false time_sequencing = "seasonal_timeslices" +days_per_period = 365 reserve_margin = "static" [MGA] diff --git a/tests/testing_configs/config_survival_curve.toml b/tests/testing_configs/config_survival_curve.toml index 2c1d051e2..fa28822a1 100644 --- a/tests/testing_configs/config_survival_curve.toml +++ b/tests/testing_configs/config_survival_curve.toml @@ -8,6 +8,7 @@ save_excel = false save_duals = false save_lp_file = false time_sequencing = "seasonal_timeslices" +days_per_period = 365 reserve_margin = "static" [MGA] diff --git a/tests/testing_configs/config_test_system.toml b/tests/testing_configs/config_test_system.toml index b776c317d..25acdfe59 100644 --- a/tests/testing_configs/config_test_system.toml +++ b/tests/testing_configs/config_test_system.toml @@ -8,6 +8,7 @@ save_excel = false save_duals = false save_lp_file = false time_sequencing = "seasonal_timeslices" +days_per_period = 365 reserve_margin = "static" [MGA] diff --git a/tests/testing_configs/config_utopia.toml b/tests/testing_configs/config_utopia.toml index e13262f29..1e7080c4a 100644 --- a/tests/testing_configs/config_utopia.toml +++ b/tests/testing_configs/config_utopia.toml @@ -8,6 +8,7 @@ save_excel = false save_duals = false save_lp_file = false time_sequencing = "seasonal_timeslices" +days_per_period = 365 reserve_margin = "static" [MGA] diff --git a/tests/testing_configs/config_utopia_gv.toml b/tests/testing_configs/config_utopia_gv.toml index 4112427de..cc5d93a5e 100644 --- a/tests/testing_configs/config_utopia_gv.toml +++ b/tests/testing_configs/config_utopia_gv.toml @@ -8,6 +8,7 @@ save_excel = false save_duals = false save_lp_file = false time_sequencing = "seasonal_timeslices" +days_per_period = 365 reserve_margin = "static" graphviz_output = true diff --git a/tests/testing_configs/config_utopia_mc.toml b/tests/testing_configs/config_utopia_mc.toml index acd9cd0cc..40f8993dc 100644 --- a/tests/testing_configs/config_utopia_mc.toml +++ b/tests/testing_configs/config_utopia_mc.toml @@ -10,6 +10,7 @@ neos = false solver_name = "appsi_highs" time_sequencing = 'seasonal_timeslices' +days_per_period = 365 reserve_margin = 'static' [monte_carlo] diff --git a/tests/testing_configs/config_utopia_myopic.toml b/tests/testing_configs/config_utopia_myopic.toml index 6ad881bbc..ddab12b0c 100644 --- a/tests/testing_configs/config_utopia_myopic.toml +++ b/tests/testing_configs/config_utopia_myopic.toml @@ -8,6 +8,7 @@ save_excel = true save_duals = true save_lp_file = false time_sequencing = "seasonal_timeslices" +days_per_period = 365 reserve_margin = "static" [MGA] diff --git a/tests/testing_configs/config_utopia_stochastic.toml b/tests/testing_configs/config_utopia_stochastic.toml index 78fa81a9a..a1dcefc70 100644 --- a/tests/testing_configs/config_utopia_stochastic.toml +++ b/tests/testing_configs/config_utopia_stochastic.toml @@ -6,6 +6,7 @@ output_database = "tests/testing_outputs/utopia_stochastic.sqlite" output_path = "tests/testing_outputs/utopia_stochastic" solver_name = "appsi_highs" time_sequencing = "seasonal_timeslices" +days_per_period = 365 save_duals = false [stochastic] diff --git a/tests/testing_data/annualised_demand.sql b/tests/testing_data/annualised_demand.sql index a69b0e57a..76d910927 100644 --- a/tests/testing_data/annualised_demand.sql +++ b/tests/testing_data/annualised_demand.sql @@ -31,7 +31,6 @@ REPLACE INTO "limit_activity" VALUES('region',2000,'annual','le',0.5,NULL,NULL); REPLACE INTO "limit_activity" VALUES('region',2000,'non_annual','le',0.5,NULL,NULL); REPLACE INTO "loan_lifetime_process" VALUES('region', 'annual', 2000, 1.0, NULL, NULL); REPLACE INTO "loan_lifetime_process" VALUES('region', 'non_annual', 2000, 1.0, NULL, NULL); -REPLACE INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); REPLACE INTO "metadata" VALUES('DB_MAJOR',4,''); REPLACE INTO "metadata" VALUES('DB_MINOR',0,''); REPLACE INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); @@ -46,10 +45,9 @@ REPLACE INTO "technology" VALUES('non_annual','p','energy',NULL,NULL,0,0,0,0,0,0 REPLACE INTO "technology_type" VALUES('p','production technology'); REPLACE INTO "technology_type" VALUES('pb','baseload production technology'); REPLACE INTO "technology_type" VALUES('ps','storage production technology'); -REPLACE INTO "time_of_day" VALUES(0,'D1'); +REPLACE INTO "time_of_day" VALUES(0,'D1',24,NULL); REPLACE INTO "time_period" VALUES(0,2000,'f'); REPLACE INTO "time_period" VALUES(1,2001,'f'); REPLACE INTO "time_period_type" VALUES('e','existing vintages'); REPLACE INTO "time_period_type" VALUES('f','future'); -REPLACE INTO "time_season" VALUES(2000,0,'S1',NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'S1','D1',1.0,NULL); +REPLACE INTO "time_season" VALUES(0,'S1',1.0,NULL); diff --git a/tests/testing_data/emissions.sql b/tests/testing_data/emissions.sql index 25faaf3e3..0aaa11b02 100644 --- a/tests/testing_data/emissions.sql +++ b/tests/testing_data/emissions.sql @@ -1,7 +1,7 @@ -REPLACE INTO "capacity_factor_tech" VALUES('Testregion',2000,'S1','TOD1','TechCurtailment',1.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('Testregion',2000,'S1','TOD2','TechCurtailment',0.5,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('Testregion',2000,'S1','TOD1','TechOrdinary',1.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('Testregion',2000,'S1','TOD2','TechOrdinary',0.5,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('Testregion','S1','TOD1','TechCurtailment',1.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('Testregion','S1','TOD2','TechCurtailment',0.5,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('Testregion','S1','TOD1','TechOrdinary',1.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('Testregion','S1','TOD2','TechOrdinary',0.5,NULL); REPLACE INTO "commodity" VALUES('annual_in', 's', NULL, NULL); REPLACE INTO "commodity" VALUES('flex_in', 's', NULL, NULL); REPLACE INTO "commodity" VALUES('ordinary_in', 's', NULL, NULL); @@ -67,7 +67,6 @@ REPLACE INTO "limit_capacity" VALUES('Testregion',2000,'TechOrdinary','ge',1.0,N REPLACE INTO "limit_capacity" VALUES('Testregion',2000,'TechCurtailment','ge',1.0,NULL,NULL); REPLACE INTO "limit_capacity" VALUES('Testregion',2000,'TechOrdinary','le',1.0,NULL,NULL); REPLACE INTO "limit_capacity" VALUES('Testregion',2000,'TechCurtailment','le',1.0,NULL,NULL); -REPLACE INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); REPLACE INTO "metadata" VALUES('DB_MAJOR',4,''); REPLACE INTO "metadata" VALUES('DB_MINOR',0,''); REPLACE INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); @@ -76,7 +75,6 @@ REPLACE INTO "operator" VALUES('e','equal to'); REPLACE INTO "operator" VALUES('le','less than or equal to'); REPLACE INTO "operator" VALUES('ge','greater than or equal to'); REPLACE INTO "region" VALUES('Testregion',NULL); -REPLACE INTO "season_label" VALUES('S1',NULL); REPLACE INTO "technology" VALUES('TechAnnual','p','energy',NULL,NULL,0,1,0,0,0,0,0,0,NULL); REPLACE INTO "technology" VALUES('TechFlex','p','energy',NULL,NULL,0,0,0,0,0,1,0,0,NULL); REPLACE INTO "technology" VALUES('TechOrdinary','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); @@ -88,17 +86,12 @@ REPLACE INTO "technology" VALUES('TechEndOfLife','p','energy',NULL,NULL,0,0,0,0, REPLACE INTO "technology_type" VALUES('p','production technology'); REPLACE INTO "technology_type" VALUES('pb','baseload production technology'); REPLACE INTO "technology_type" VALUES('ps','storage production technology'); -REPLACE INTO "time_of_day" VALUES(1,'TOD1'); -REPLACE INTO "time_of_day" VALUES(2,'TOD2'); +REPLACE INTO "time_of_day" VALUES(1,'TOD1',12,NULL); +REPLACE INTO "time_of_day" VALUES(2,'TOD2',12,NULL); REPLACE INTO "time_period" VALUES(1,1999,'e'); REPLACE INTO "time_period" VALUES(2,2000,'f'); REPLACE INTO "time_period" VALUES(3,2005,'f'); REPLACE INTO "time_period" VALUES(4,2010,'f'); REPLACE INTO "time_period_type" VALUES('e','existing vintages'); REPLACE INTO "time_period_type" VALUES('f','future'); -REPLACE INTO "time_season" VALUES(2000,1,'S1',NULL); -REPLACE INTO "time_season" VALUES(2005,1,'S1',NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'S1','TOD1',0.5,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'S1','TOD2',0.5,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2005,'S1','TOD1',0.5,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2005,'S1','TOD2',0.5,NULL); +REPLACE INTO "time_season" VALUES(1,'S1',1.0,NULL); diff --git a/tests/testing_data/materials.sql b/tests/testing_data/materials.sql index 626aeb3b8..95f24b4fa 100644 --- a/tests/testing_data/materials.sql +++ b/tests/testing_data/materials.sql @@ -1,99 +1,35 @@ -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'summer','morning','SOL_PV',0.3,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'autumn','morning','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'winter','morning','SOL_PV',0.1,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'spring','morning','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'summer','afternoon','SOL_PV',0.3,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'autumn','afternoon','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'winter','afternoon','SOL_PV',0.1,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'spring','afternoon','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'summer','evening','SOL_PV',0.1,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'autumn','evening','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'winter','evening','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'spring','evening','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'summer','overnight','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'autumn','overnight','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'winter','overnight','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2000,'spring','overnight','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'summer','morning','SOL_PV',0.3,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'autumn','morning','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'winter','morning','SOL_PV',0.1,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'spring','morning','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'summer','afternoon','SOL_PV',0.3,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'autumn','afternoon','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'winter','afternoon','SOL_PV',0.1,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'spring','afternoon','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'summer','evening','SOL_PV',0.1,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'autumn','evening','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'winter','evening','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'spring','evening','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'summer','overnight','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'autumn','overnight','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'winter','overnight','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2010,'spring','overnight','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'summer','morning','SOL_PV',0.3,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'autumn','morning','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'winter','morning','SOL_PV',0.1,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'spring','morning','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'summer','afternoon','SOL_PV',0.3,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'autumn','afternoon','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'winter','afternoon','SOL_PV',0.1,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'spring','afternoon','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'summer','evening','SOL_PV',0.1,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'autumn','evening','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'winter','evening','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'spring','evening','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'summer','overnight','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'autumn','overnight','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'winter','overnight','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionA',2020,'spring','overnight','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'summer','morning','SOL_PV',0.3,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'autumn','morning','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'winter','morning','SOL_PV',0.1,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'spring','morning','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'summer','afternoon','SOL_PV',0.3,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'autumn','afternoon','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'winter','afternoon','SOL_PV',0.1,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'spring','afternoon','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'summer','evening','SOL_PV',0.1,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'autumn','evening','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'winter','evening','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'spring','evening','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'summer','overnight','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'autumn','overnight','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'winter','overnight','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2000,'spring','overnight','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'summer','morning','SOL_PV',0.3,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'autumn','morning','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'winter','morning','SOL_PV',0.1,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'spring','morning','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'summer','afternoon','SOL_PV',0.3,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'autumn','afternoon','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'winter','afternoon','SOL_PV',0.1,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'spring','afternoon','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'summer','evening','SOL_PV',0.1,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'autumn','evening','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'winter','evening','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'spring','evening','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'summer','overnight','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'autumn','overnight','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'winter','overnight','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2010,'spring','overnight','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'summer','morning','SOL_PV',0.3,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'autumn','morning','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'winter','morning','SOL_PV',0.1,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'spring','morning','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'summer','afternoon','SOL_PV',0.3,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'autumn','afternoon','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'winter','afternoon','SOL_PV',0.1,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'spring','afternoon','SOL_PV',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'summer','evening','SOL_PV',0.1,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'autumn','evening','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'winter','evening','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'spring','evening','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'summer','overnight','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'autumn','overnight','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'winter','overnight','SOL_PV',0.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('regionB',2020,'spring','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA','summer','morning','SOL_PV',0.3,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA','autumn','morning','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA','winter','morning','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA','spring','morning','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA','summer','afternoon','SOL_PV',0.3,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA','autumn','afternoon','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA','winter','afternoon','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA','spring','afternoon','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA','summer','evening','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA','autumn','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA','winter','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA','spring','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA','summer','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA','autumn','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA','winter','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionA','spring','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB','summer','morning','SOL_PV',0.3,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB','autumn','morning','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB','winter','morning','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB','spring','morning','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB','summer','afternoon','SOL_PV',0.3,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB','autumn','afternoon','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB','winter','afternoon','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB','spring','afternoon','SOL_PV',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB','summer','evening','SOL_PV',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB','autumn','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB','winter','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB','spring','evening','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB','summer','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB','autumn','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB','winter','overnight','SOL_PV',0.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('regionB','spring','overnight','SOL_PV',0.0,NULL); REPLACE INTO "commodity" VALUES('ethos', 's', 'import dummy source', NULL); REPLACE INTO "commodity" VALUES('electricity', 'p', 'grid electricity', NULL); REPLACE INTO "commodity" VALUES('passenger_km', 'd', 'demand for passenger km', NULL); @@ -393,7 +329,6 @@ REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'electricity' REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2010,'diesel','CAR_PHEV','le',0.8,''); REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'electricity','CAR_PHEV','le',0.2,''); REPLACE INTO "limit_tech_input_split_annual" VALUES('regionB',2020,'diesel','CAR_PHEV','le',0.8,NULL); -REPLACE INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); REPLACE INTO "metadata" VALUES('DB_MAJOR',4,''); REPLACE INTO "metadata" VALUES('DB_MINOR',0,''); REPLACE INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); @@ -403,10 +338,6 @@ REPLACE INTO "operator" VALUES('le','less than or equal to'); REPLACE INTO "operator" VALUES('ge','greater than or equal to'); REPLACE INTO "region" VALUES('regionA',NULL); REPLACE INTO "region" VALUES('regionB',NULL); -REPLACE INTO "season_label" VALUES('summer',NULL); -REPLACE INTO "season_label" VALUES('autumn',NULL); -REPLACE INTO "season_label" VALUES('winter',NULL); -REPLACE INTO "season_label" VALUES('spring',NULL); REPLACE INTO "sector_label" VALUES('materials',NULL); REPLACE INTO "sector_label" VALUES('transportation',NULL); REPLACE INTO "sector_label" VALUES('electricity',NULL); @@ -436,10 +367,10 @@ REPLACE INTO "technology" VALUES('ELEC_INTERTIE','p','electricity',NULL,NULL,0,0 REPLACE INTO "technology_type" VALUES('p','production technology'); REPLACE INTO "technology_type" VALUES('pb','baseload production technology'); REPLACE INTO "technology_type" VALUES('ps','storage production technology'); -REPLACE INTO "time_of_day" VALUES(1,'morning'); -REPLACE INTO "time_of_day" VALUES(2,'afternoon'); -REPLACE INTO "time_of_day" VALUES(3,'evening'); -REPLACE INTO "time_of_day" VALUES(4,'overnight'); +REPLACE INTO "time_of_day" VALUES(1,'morning',6,NULL); +REPLACE INTO "time_of_day" VALUES(2,'afternoon',6,NULL); +REPLACE INTO "time_of_day" VALUES(3,'evening',6,NULL); +REPLACE INTO "time_of_day" VALUES(4,'overnight',6,NULL); REPLACE INTO "time_period" VALUES(1,1990,'e'); REPLACE INTO "time_period" VALUES(2,2000,'f'); REPLACE INTO "time_period" VALUES(3,2010,'f'); @@ -447,63 +378,7 @@ REPLACE INTO "time_period" VALUES(4,2020,'f'); REPLACE INTO "time_period" VALUES(5,2030,'f'); REPLACE INTO "time_period_type" VALUES('e','existing vintages'); REPLACE INTO "time_period_type" VALUES('f','future'); -REPLACE INTO "time_season" VALUES(2000,1,'summer',NULL); -REPLACE INTO "time_season" VALUES(2000,2,'autumn',NULL); -REPLACE INTO "time_season" VALUES(2000,3,'winter',NULL); -REPLACE INTO "time_season" VALUES(2000,4,'spring',NULL); -REPLACE INTO "time_season" VALUES(2010,5,'summer',NULL); -REPLACE INTO "time_season" VALUES(2010,6,'autumn',NULL); -REPLACE INTO "time_season" VALUES(2010,7,'winter',NULL); -REPLACE INTO "time_season" VALUES(2010,8,'spring',NULL); -REPLACE INTO "time_season" VALUES(2020,9,'summer',NULL); -REPLACE INTO "time_season" VALUES(2020,10,'autumn',NULL); -REPLACE INTO "time_season" VALUES(2020,11,'winter',NULL); -REPLACE INTO "time_season" VALUES(2020,12,'spring',NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'summer','morning',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'autumn','morning',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'winter','morning',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'spring','morning',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'summer','afternoon',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'autumn','afternoon',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'winter','afternoon',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'spring','afternoon',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'summer','evening',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'autumn','evening',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'winter','evening',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'spring','evening',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'summer','overnight',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'autumn','overnight',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'winter','overnight',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'spring','overnight',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2010,'summer','morning',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2010,'autumn','morning',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2010,'winter','morning',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2010,'spring','morning',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2010,'summer','afternoon',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2010,'autumn','afternoon',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2010,'winter','afternoon',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2010,'spring','afternoon',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2010,'summer','evening',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2010,'autumn','evening',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2010,'winter','evening',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2010,'spring','evening',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2010,'summer','overnight',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2010,'autumn','overnight',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2010,'winter','overnight',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2010,'spring','overnight',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2020,'summer','morning',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2020,'autumn','morning',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2020,'winter','morning',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2020,'spring','morning',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2020,'summer','afternoon',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2020,'autumn','afternoon',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2020,'winter','afternoon',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2020,'spring','afternoon',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2020,'summer','evening',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2020,'autumn','evening',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2020,'winter','evening',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2020,'spring','evening',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2020,'summer','overnight',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2020,'autumn','overnight',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2020,'winter','overnight',0.0625,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2020,'spring','overnight',0.0625,NULL); +REPLACE INTO "time_season" VALUES(1,'summer',0.25,NULL); +REPLACE INTO "time_season" VALUES(2,'autumn',0.25,NULL); +REPLACE INTO "time_season" VALUES(3,'winter',0.25,NULL); +REPLACE INTO "time_season" VALUES(4,'spring',0.25,NULL); diff --git a/tests/testing_data/mediumville.sql b/tests/testing_data/mediumville.sql index e9b47564f..84f579487 100644 --- a/tests/testing_data/mediumville.sql +++ b/tests/testing_data/mediumville.sql @@ -1,8 +1,8 @@ REPLACE INTO "capacity_credit" VALUES('A',2025,'EF',2025,0.6,NULL); -REPLACE INTO "capacity_factor_process" VALUES('A',2025,'s2','d1','EFL',2025,0.8,NULL); -REPLACE INTO "capacity_factor_process" VALUES('A',2025,'s1','d2','EFL',2025,0.9,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('A',2025,'s1','d1','EF',0.8,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('B',2025,'s2','d2','bulbs',0.75,NULL); +REPLACE INTO "capacity_factor_process" VALUES('A','s2','d1','EFL',2025,0.8,NULL); +REPLACE INTO "capacity_factor_process" VALUES('A','s1','d2','EFL',2025,0.9,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('A','s1','d1','EF',0.8,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('B','s2','d2','bulbs',0.75,NULL); REPLACE INTO "capacity_to_activity" VALUES('A', 'bulbs', 1.0, NULL, ''); REPLACE INTO "capacity_to_activity" VALUES('B', 'bulbs', 1.0, NULL, NULL); REPLACE INTO "commodity" VALUES('ELC', 'p', 'electricity', NULL); @@ -64,22 +64,22 @@ REPLACE INTO "demand" VALUES('A',2025,'RL',100.0,'',''); REPLACE INTO "demand" VALUES('B',2025,'RL',100.0,NULL,NULL); REPLACE INTO "demand" VALUES('A',2025,'RH',50.0,NULL,NULL); REPLACE INTO "demand" VALUES('B',2025,'RH',50.0,NULL,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('A',2025,'s1','d1','RL',0.25,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('A',2025,'s1','d2','RL',0.25,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('A',2025,'s2','d1','RL',0.25,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('A',2025,'s2','d2','RL',0.25,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('B',2025,'s1','d1','RL',0.25,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('B',2025,'s1','d2','RL',0.25,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('B',2025,'s2','d1','RL',0.25,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('B',2025,'s2','d2','RL',0.25,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('A',2025,'s1','d1','RH',0.25,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('A',2025,'s2','d1','RH',0.25,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('B',2025,'s1','d1','RH',0.25,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('B',2025,'s2','d1','RH',0.25,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('A',2025,'s1','d2','RH',0.25,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('A',2025,'s2','d2','RH',0.25,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('B',2025,'s1','d2','RH',0.25,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('B',2025,'s2','d2','RH',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('A','s1','d1','RL',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('A','s1','d2','RL',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('A','s2','d1','RL',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('A','s2','d2','RL',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('B','s1','d1','RL',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('B','s1','d2','RL',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('B','s2','d1','RL',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('B','s2','d2','RL',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('A','s1','d1','RH',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('A','s2','d1','RH',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('B','s1','d1','RH',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('B','s2','d1','RH',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('A','s1','d2','RH',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('A','s2','d2','RH',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('B','s1','d2','RH',0.25,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('B','s2','d2','RH',0.25,NULL); REPLACE INTO "efficiency" VALUES('A', 'ELC', 'bulbs', 2025, 'RL', 1.0, NULL, NULL); REPLACE INTO "efficiency" VALUES('A', 'HYD', 'EH', 2025, 'ELC', 1.0, NULL, NULL); REPLACE INTO "efficiency" VALUES('A', 'HYD', 'EF', 2025, 'ELC', 1.0, NULL, NULL); @@ -139,7 +139,6 @@ REPLACE INTO "loan_lifetime_process" VALUES('B', 'GeoHeater', 2025, 10.0, NULL, REPLACE INTO "loan_lifetime_process" VALUES('B', 'GeoThermal', 2025, 10.0, NULL, NULL); REPLACE INTO "loan_lifetime_process" VALUES('A-B', 'FGF_pipe', 2025, 10.0, NULL, NULL); REPLACE INTO "loan_lifetime_process" VALUES('B-A', 'FGF_pipe', 2025, 10.0, NULL, NULL); -REPLACE INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); REPLACE INTO "metadata" VALUES('DB_MAJOR',4,''); REPLACE INTO "metadata" VALUES('DB_MINOR',0,''); REPLACE INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); @@ -155,8 +154,6 @@ REPLACE INTO "ramp_up_hourly" VALUES('A','EH',0.05,NULL); REPLACE INTO "region" VALUES('A','main region'); REPLACE INTO "region" VALUES('B','just a 2nd region'); REPLACE INTO "rps_requirement" VALUES('B',2025,'RPS_common',0.3,NULL); -REPLACE INTO "season_label" VALUES('s1',NULL); -REPLACE INTO "season_label" VALUES('s2',NULL); REPLACE INTO "sector_label" VALUES('supply',NULL); REPLACE INTO "sector_label" VALUES('electric',NULL); REPLACE INTO "sector_label" VALUES('transport',NULL); @@ -182,16 +179,12 @@ REPLACE INTO "technology" VALUES('GeoHeater','p','residential','hydro','',0,0,0, REPLACE INTO "technology_type" VALUES('p','production technology'); REPLACE INTO "technology_type" VALUES('pb','baseload production technology'); REPLACE INTO "technology_type" VALUES('ps','storage production technology'); -REPLACE INTO "time_of_day" VALUES(1,'d1'); -REPLACE INTO "time_of_day" VALUES(2,'d2'); +REPLACE INTO "time_of_day" VALUES(1,'d1',12,NULL); +REPLACE INTO "time_of_day" VALUES(2,'d2',12,NULL); REPLACE INTO "time_period" VALUES(1,2020,'e'); REPLACE INTO "time_period" VALUES(2,2025,'f'); REPLACE INTO "time_period" VALUES(3,2030,'f'); REPLACE INTO "time_period_type" VALUES('e','existing vintages'); REPLACE INTO "time_period_type" VALUES('f','future'); -REPLACE INTO "time_season" VALUES(2025,1,'s1',NULL); -REPLACE INTO "time_season" VALUES(2025,2,'s2',NULL); -REPLACE INTO "time_segment_fraction" VALUES(2025,'s2','d1',0.25,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2025,'s2','d2',0.25,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2025,'s1','d1',0.25,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2025,'s1','d2',0.25,NULL); +REPLACE INTO "time_season" VALUES(1,'s1',0.5,NULL); +REPLACE INTO "time_season" VALUES(2,'s2',0.5,NULL); diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 58deea8ad..4dd07b4e3 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -655,507 +655,435 @@ 2025 ] ], - "capacity_factor_rpsdt": [ + "capacity_factor_rsdt": [ [ "A", - 2025, "s2", "d2", "bulbs" ], [ "B", - 2025, "s1", "d1", "well" ], [ "B", - 2025, "s2", "d1", "heater" ], [ "B", - 2025, "s2", "d1", "EH" ], [ "A", - 2025, "s1", "d2", "bulbs" ], [ "B", - 2025, "s1", "d2", "well" ], [ "B", - 2025, "s2", "d1", "EF" ], [ "B", - 2025, "s2", "d2", "EH" ], [ "B", - 2025, "s2", "d2", "EF" ], [ "B", - 2025, "s2", "d2", "heater" ], [ "A", - 2025, "s2", "d1", "well" ], [ "B", - 2025, "s1", "d1", "EH" ], [ "B", - 2025, "s1", "d1", "EF" ], [ "B", - 2025, "s1", "d1", "heater" ], [ "A", - 2025, "s1", "d1", "well" ], [ "B", - 2025, "s1", "d2", "heater" ], [ "B", - 2025, "s1", "d2", "EH" ], [ "A", - 2025, "s2", "d1", "heater" ], [ "B", - 2025, "s1", "d2", "EF" ], [ "A", - 2025, "s2", "d1", "EH" ], [ "A", - 2025, "s2", "d1", "EF" ], [ "B", - 2025, "s2", "d1", "GeoHeater" ], [ "B-A", - 2025, "s2", "d1", "FGF_pipe" ], [ "A", - 2025, "s1", "d1", "EH" ], [ "B", - 2025, "s2", "d2", "GeoHeater" ], [ "B-A", - 2025, "s2", "d2", "FGF_pipe" ], [ "A", - 2025, "s2", "d2", "well" ], [ "A", - 2025, "s1", "d1", "EF" ], [ "A", - 2025, "s1", "d1", "heater" ], [ "B", - 2025, "s1", "d1", "GeoHeater" ], [ "B-A", - 2025, "s1", "d1", "FGF_pipe" ], [ "B", - 2025, "s2", "d1", "GeoThermal" ], [ "A", - 2025, "s1", "d2", "well" ], [ "B-A", - 2025, "s1", "d2", "FGF_pipe" ], [ "A", - 2025, "s2", "d2", "heater" ], [ "B", - 2025, "s1", "d2", "GeoHeater" ], [ "A", - 2025, "s2", "d2", "EH" ], [ "B", - 2025, "s2", "d2", "GeoThermal" ], [ "A", - 2025, "s2", "d1", "GeoHeater" ], [ "A", - 2025, "s2", "d2", "EF" ], [ "A", - 2025, "s2", "d1", "EFL" ], [ "B", - 2025, "s1", "d1", "GeoThermal" ], [ "A", - 2025, "s1", "d2", "EH" ], [ "B", - 2025, "s1", "d2", "GeoThermal" ], [ "A", - 2025, "s1", "d1", "GeoHeater" ], [ "A", - 2025, "s1", "d2", "EF" ], [ "A", - 2025, "s2", "d1", "GeoThermal" ], [ "A", - 2025, "s1", "d1", "EFL" ], [ "A", - 2025, "s1", "d2", "heater" ], [ "B", - 2025, "s2", "d1", "bulbs" ], [ "B", - 2025, "s2", "d2", "bulbs" ], [ "B", - 2025, "s1", "d1", "bulbs" ], [ "A", - 2025, "s2", "d2", "GeoHeater" ], [ "A", - 2025, "s1", "d1", "GeoThermal" ], [ "A", - 2025, "s2", "d2", "EFL" ], [ "B", - 2025, "s2", "d1", "batt" ], [ "A-B", - 2025, "s2", "d2", "FGF_pipe" ], [ "B", - 2025, "s1", "d2", "bulbs" ], [ "A", - 2025, "s1", "d2", "GeoHeater" ], [ "A", - 2025, "s2", "d1", "bulbs" ], [ "A", - 2025, "s2", "d2", "GeoThermal" ], [ "A", - 2025, "s1", "d2", "EFL" ], [ "B", - 2025, "s1", "d1", "batt" ], [ "A-B", - 2025, "s1", "d2", "FGF_pipe" ], [ "B", - 2025, "s2", "d2", "batt" ], [ "A", - 2025, "s1", "d1", "bulbs" ], [ "A-B", - 2025, "s2", "d1", "FGF_pipe" ], [ "B", - 2025, "s1", "d2", "batt" ], [ "B", - 2025, "s2", "d1", "well" ], [ "A", - 2025, "s1", "d2", "GeoThermal" ], [ "A-B", - 2025, "s1", "d1", "FGF_pipe" ], [ "B", - 2025, "s2", "d2", "well" @@ -3302,7 +3230,9 @@ ] ], "limit_seasonal_capacity_factor_constraint_rpst": [], + "limit_seasonal_capacity_factor_constraint_rst": [], "limit_storage_fraction_constraint_rpsdtv": [], + "limit_storage_fraction_param_rsdt": [], "limit_tech_input_split_annual_constraint_rpitv": [], "limit_tech_input_split_average_constraint_rpitv": [], "limit_tech_input_split_constraint_rpsditv": [ @@ -4035,12 +3965,10 @@ ], "ordered_season_sequential": [ [ - 2025, "s1", "s1" ], [ - 2025, "s2", "s2" ] @@ -4171,13 +4099,10 @@ 2025 ], "time_season": [ - 2025 - ], - "time_season_all": [ "s1", "s2" ], - "time_season_to_sequential": [ + "time_season_sequential": [ "s1", "s2" ], diff --git a/tests/testing_data/migration_v3_1_mock.sql b/tests/testing_data/migration_v3_1_mock.sql new file mode 100644 index 000000000..8e97007a1 --- /dev/null +++ b/tests/testing_data/migration_v3_1_mock.sql @@ -0,0 +1,30 @@ +-- Mock data for v3.1 -> v4 migration testing +INSERT INTO Region (region) VALUES ('R1'); +INSERT OR IGNORE INTO TechnologyType (label, description) VALUES ('p', 'production'); +INSERT INTO Technology (tech, flag, unlim_cap, annual, reserve, curtail, retire, flex, exchange, seas_stor) VALUES ('T1', 'p', 0, 0, 0, 0, 0, 0, 0, 0); + +INSERT INTO TimePeriod (sequence, period, flag) VALUES (1, 2020, 'e'); +INSERT INTO TimePeriod (sequence, period, flag) VALUES (2, 2030, 'f'); +INSERT INTO TimePeriod (sequence, period, flag) VALUES (3, 2040, 'f'); + +INSERT INTO SeasonLabel (season) VALUES ('winter'); +INSERT INTO SeasonLabel (season) VALUES ('summer'); + +INSERT INTO TimeOfDay (sequence, tod) VALUES (1, 'day'); +INSERT INTO TimeOfDay (sequence, tod) VALUES (2, 'night'); + +INSERT INTO TimeSeason (period, sequence, season) VALUES (2030, 1, 'winter'); +INSERT INTO TimeSeason (period, sequence, season) VALUES (2030, 2, 'summer'); + +INSERT INTO TimeSegmentFraction (period, season, tod, segfrac) VALUES (2030, 'winter', 'day', 0.2); +INSERT INTO TimeSegmentFraction (period, season, tod, segfrac) VALUES (2030, 'winter', 'night', 0.1); +INSERT INTO TimeSegmentFraction (period, season, tod, segfrac) VALUES (2030, 'summer', 'day', 0.4); +INSERT INTO TimeSegmentFraction (period, season, tod, segfrac) VALUES (2030, 'summer', 'night', 0.3); + +INSERT OR IGNORE INTO CommodityType (label, description) VALUES ('p', 'physical'); +INSERT INTO Commodity (name, flag) VALUES ('In', 'p'); +INSERT INTO Commodity (name, flag) VALUES ('Out', 'p'); + +INSERT INTO CapacityFactorProcess (region, period, season, tod, tech, vintage, factor) VALUES ('R1', 2030, 'winter', 'day', 'T1', 2030, 0.5); +INSERT INTO CapacityFactorProcess (region, period, season, tod, tech, vintage, factor) VALUES ('R1', 2040, 'winter', 'day', 'T1', 2030, 0.7); +INSERT INTO Efficiency (region, input_comm, tech, vintage, output_comm, efficiency) VALUES ('R1', 'In', 'T1', 2030, 'Out', 0.9); diff --git a/tests/testing_data/seasonal_storage.sql b/tests/testing_data/seasonal_storage.sql index 70d88e5ac..24f4a5b56 100644 --- a/tests/testing_data/seasonal_storage.sql +++ b/tests/testing_data/seasonal_storage.sql @@ -1,11 +1,11 @@ -REPLACE INTO "capacity_factor_tech" VALUES('region',2000,'charge','a','generator',1.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('region',2000,'charge','b','generator',1.0,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('region',2000,'charge','c','generator',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('region',2000,'charge','d','generator',0.2,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('region',2000,'discharge','a','generator',0.1,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('region',2000,'discharge','b','generator',0.1,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('region',2000,'discharge','c','generator',0.01,NULL); -REPLACE INTO "capacity_factor_tech" VALUES('region',2000,'discharge','d','generator',0.01,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('region','charge','a','generator',1.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('region','charge','b','generator',1.0,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('region','charge','c','generator',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('region','charge','d','generator',0.2,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('region','discharge','a','generator',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('region','discharge','b','generator',0.1,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('region','discharge','c','generator',0.01,NULL); +REPLACE INTO "capacity_factor_tech" VALUES('region','discharge','d','generator',0.01,NULL); REPLACE INTO "capacity_to_activity" VALUES('region', 'generator', 8760.0, NULL, 'MWh/MWy'); REPLACE INTO "capacity_to_activity" VALUES('region', 'dly_stor', 8760.0, NULL, 'MWh/MWy'); REPLACE INTO "capacity_to_activity" VALUES('region', 'seas_stor', 8760.0, NULL, 'MWh/MWy'); @@ -28,21 +28,20 @@ REPLACE INTO "cost_invest" VALUES('region','demand',2000,1.0,'',NULL); REPLACE INTO "cost_variable" VALUES('region',2000,'generator',2000,1.0,NULL,NULL); REPLACE INTO "cost_variable" VALUES('region',2000,'demand',2000,1.0,NULL,NULL); REPLACE INTO "demand" VALUES('region',2000,'demand',8760.0,'MWh',NULL); -REPLACE INTO "demand_specific_distribution" VALUES('region',2000,'charge','a','demand',0.0,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('region',2000,'charge','b','demand',0.05,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('region',2000,'charge','c','demand',0.05,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('region',2000,'charge','d','demand',0.1,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('region',2000,'discharge','a','demand',0.0,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('region',2000,'discharge','b','demand',0.2,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('region',2000,'discharge','c','demand',0.2,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('region',2000,'discharge','d','demand',0.4,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('region','charge','a','demand',0.0,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('region','charge','b','demand',0.05,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('region','charge','c','demand',0.05,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('region','charge','d','demand',0.1,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('region','discharge','a','demand',0.0,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('region','discharge','b','demand',0.2,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('region','discharge','c','demand',0.2,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('region','discharge','d','demand',0.4,NULL); REPLACE INTO "efficiency" VALUES('region', 'ethos', 'generator', 2000, 'electricity', 1.0, NULL, NULL); REPLACE INTO "efficiency" VALUES('region', 'electricity', 'dly_stor', 2000, 'electricity', 1.0, NULL, NULL); REPLACE INTO "efficiency" VALUES('region', 'electricity', 'seas_stor', 2000, 'electricity', 1.0, NULL, NULL); REPLACE INTO "efficiency" VALUES('region', 'electricity', 'demand', 2000, 'demand', 1.0, NULL, NULL); -REPLACE INTO "limit_storage_level_fraction" VALUES('region',2000,'winter','b','seas_stor',2000,'e',0.5,NULL); -REPLACE INTO "limit_storage_level_fraction" VALUES('region',2000,'charge','b','dly_stor',2000,'e',0.5,NULL); -REPLACE INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +REPLACE INTO "limit_storage_level_fraction" VALUES('region','winter','b','seas_stor','e',0.5,NULL); +REPLACE INTO "limit_storage_level_fraction" VALUES('region','charge','b','dly_stor','e',0.5,NULL); REPLACE INTO "metadata" VALUES('DB_MAJOR',4,''); REPLACE INTO "metadata" VALUES('DB_MINOR',0,''); REPLACE INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); @@ -51,22 +50,6 @@ REPLACE INTO "operator" VALUES('e','equal to'); REPLACE INTO "operator" VALUES('le','less than or equal to'); REPLACE INTO "operator" VALUES('ge','greater than or equal to'); REPLACE INTO "region" VALUES('region',NULL); -REPLACE INTO "season_label" VALUES('charge','non-sequential season - charging day'); -REPLACE INTO "season_label" VALUES('discharge','non-sequential season - discharging day'); -REPLACE INTO "season_label" VALUES('summer','sequential season - summer day'); -REPLACE INTO "season_label" VALUES('sept_w1','sequential season - day in first week of September'); -REPLACE INTO "season_label" VALUES('sept_w2','sequential season - day in second week of September'); -REPLACE INTO "season_label" VALUES('sept_w3','sequential season - day in third week of September'); -REPLACE INTO "season_label" VALUES('sept_w4','sequential season - day in fourth week of September'); -REPLACE INTO "season_label" VALUES('sept_29th','sequential season - 29th of September'); -REPLACE INTO "season_label" VALUES('sept_30th','sequential season - 30th of September'); -REPLACE INTO "season_label" VALUES('winter','sequential season - winter day'); -REPLACE INTO "season_label" VALUES('apr_w1','sequential season - day in first week of September'); -REPLACE INTO "season_label" VALUES('apr_w2','sequential season - day in second week of September'); -REPLACE INTO "season_label" VALUES('apr_w3','sequential season - day in third week of September'); -REPLACE INTO "season_label" VALUES('apr_w4','sequential season - day in fourth week of September'); -REPLACE INTO "season_label" VALUES('apr_29th','sequential season - 29th of April'); -REPLACE INTO "season_label" VALUES('apr_30th','sequential season - 30th of April'); REPLACE INTO "sector_label" VALUES('electricity',NULL); REPLACE INTO "storage_duration" VALUES('region','dly_stor',4.0,NULL); REPLACE INTO "storage_duration" VALUES('region','seas_stor',8760.0,NULL); @@ -77,35 +60,27 @@ REPLACE INTO "technology" VALUES('demand','p','electricity',NULL,NULL,0,0,0,0,0, REPLACE INTO "technology_type" VALUES('p','production technology'); REPLACE INTO "technology_type" VALUES('pb','baseload production technology'); REPLACE INTO "technology_type" VALUES('ps','storage production technology'); -REPLACE INTO "time_of_day" VALUES(0,'a'); -REPLACE INTO "time_of_day" VALUES(1,'b'); -REPLACE INTO "time_of_day" VALUES(2,'c'); -REPLACE INTO "time_of_day" VALUES(3,'d'); +REPLACE INTO "time_of_day" VALUES(0,'a',6,NULL); +REPLACE INTO "time_of_day" VALUES(1,'b',6,NULL); +REPLACE INTO "time_of_day" VALUES(2,'c',6,NULL); +REPLACE INTO "time_of_day" VALUES(3,'d',6,NULL); REPLACE INTO "time_period" VALUES(0,2000,'f'); REPLACE INTO "time_period" VALUES(1,2005,'f'); REPLACE INTO "time_period_type" VALUES('e','existing vintages'); REPLACE INTO "time_period_type" VALUES('f','future'); -REPLACE INTO "time_season" VALUES(2000,0,'charge',NULL); -REPLACE INTO "time_season" VALUES(2000,1,'discharge',NULL); -REPLACE INTO "time_season_sequential" VALUES(2000,1,'summer','charge',152.5,NULL); -REPLACE INTO "time_season_sequential" VALUES(2000,2,'sept_w1','discharge',7.0,NULL); -REPLACE INTO "time_season_sequential" VALUES(2000,3,'sept_w2','charge',7.0,NULL); -REPLACE INTO "time_season_sequential" VALUES(2000,4,'sept_w3','discharge',7.0,NULL); -REPLACE INTO "time_season_sequential" VALUES(2000,5,'sept_w4','charge',7.0,NULL); -REPLACE INTO "time_season_sequential" VALUES(2000,6,'sept_29th','discharge',1.0,NULL); -REPLACE INTO "time_season_sequential" VALUES(2000,7,'sept_30th','charge',1.0,NULL); -REPLACE INTO "time_season_sequential" VALUES(2000,8,'winter','discharge',152.5,NULL); -REPLACE INTO "time_season_sequential" VALUES(2000,9,'apr_w1','charge',7.0,NULL); -REPLACE INTO "time_season_sequential" VALUES(2000,10,'apr_w2','discharge',7.0,NULL); -REPLACE INTO "time_season_sequential" VALUES(2000,11,'apr_w3','charge',7.0,NULL); -REPLACE INTO "time_season_sequential" VALUES(2000,12,'apr_w4','discharge',7.0,NULL); -REPLACE INTO "time_season_sequential" VALUES(2000,13,'apr_29th','charge',1.0,NULL); -REPLACE INTO "time_season_sequential" VALUES(2000,14,'apr_30th','discharge',1.0,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'charge','a',0.125,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'charge','b',0.125,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'charge','c',0.125,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'charge','d',0.125,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'discharge','a',0.125,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'discharge','b',0.125,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'discharge','c',0.125,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'discharge','d',0.125,NULL); +REPLACE INTO "time_season" VALUES(0,'charge',0.5,NULL); +REPLACE INTO "time_season" VALUES(1,'discharge',0.5,NULL); +REPLACE INTO "time_season_sequential" VALUES(1,'summer','charge',0.417808,NULL); +REPLACE INTO "time_season_sequential" VALUES(2,'sept_w1','discharge',0.019178,NULL); +REPLACE INTO "time_season_sequential" VALUES(3,'sept_w2','charge',0.019178,NULL); +REPLACE INTO "time_season_sequential" VALUES(4,'sept_w3','discharge',0.019178,NULL); +REPLACE INTO "time_season_sequential" VALUES(5,'sept_w4','charge',0.019178,NULL); +REPLACE INTO "time_season_sequential" VALUES(6,'sept_29th','discharge',0.002740,NULL); +REPLACE INTO "time_season_sequential" VALUES(7,'sept_30th','charge',0.002740,NULL); +REPLACE INTO "time_season_sequential" VALUES(8,'winter','discharge',0.417808,NULL); +REPLACE INTO "time_season_sequential" VALUES(9,'apr_w1','charge',0.019178,NULL); +REPLACE INTO "time_season_sequential" VALUES(10,'apr_w2','discharge',0.019178,NULL); +REPLACE INTO "time_season_sequential" VALUES(11,'apr_w3','charge',0.019178,NULL); +REPLACE INTO "time_season_sequential" VALUES(12,'apr_w4','discharge',0.019178,NULL); +REPLACE INTO "time_season_sequential" VALUES(13,'apr_29th','charge',0.002740,NULL); +REPLACE INTO "time_season_sequential" VALUES(14,'apr_30th','discharge',0.002740,NULL); diff --git a/tests/testing_data/simple_linked_tech.sql b/tests/testing_data/simple_linked_tech.sql index 359f62cea..25760ebc9 100644 --- a/tests/testing_data/simple_linked_tech.sql +++ b/tests/testing_data/simple_linked_tech.sql @@ -27,7 +27,6 @@ REPLACE INTO "emission_activity" VALUES('linkville','CO2','NGA','PLANT',2000,'EL REPLACE INTO "lifetime_tech" VALUES('linkville', 'CCS', 100.0, NULL, ''); REPLACE INTO "lifetime_tech" VALUES('linkville', 'PLANT', 100.0, NULL, ''); REPLACE INTO "linked_tech" VALUES('linkville','PLANT','CO2','CCS',NULL); -REPLACE INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); REPLACE INTO "metadata" VALUES('DB_MAJOR',4,''); REPLACE INTO "metadata" VALUES('DB_MINOR',0,''); REPLACE INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); @@ -36,8 +35,6 @@ REPLACE INTO "operator" VALUES('e','equal to'); REPLACE INTO "operator" VALUES('le','less than or equal to'); REPLACE INTO "operator" VALUES('ge','greater than or equal to'); REPLACE INTO "region" VALUES('linkville',NULL); -REPLACE INTO "season_label" VALUES('summer',NULL); -REPLACE INTO "season_label" VALUES('winter',NULL); REPLACE INTO "sector_label" VALUES('supply',NULL); REPLACE INTO "sector_label" VALUES('electric',NULL); REPLACE INTO "sector_label" VALUES('transport',NULL); @@ -51,13 +48,11 @@ REPLACE INTO "technology" VALUES('FAKE_SOURCE','p','supply',NULL,NULL,1,0,0,0,0, REPLACE INTO "technology_type" VALUES('p','production technology'); REPLACE INTO "technology_type" VALUES('pb','baseload production technology'); REPLACE INTO "technology_type" VALUES('ps','storage production technology'); -REPLACE INTO "time_of_day" VALUES(1,'day'); +REPLACE INTO "time_of_day" VALUES(1,'day',24,NULL); REPLACE INTO "time_period" VALUES(0,1995,'e'); REPLACE INTO "time_period" VALUES(1,2000,'f'); REPLACE INTO "time_period" VALUES(2,2005,'f'); REPLACE INTO "time_period_type" VALUES('e','existing vintages'); REPLACE INTO "time_period_type" VALUES('f','future'); -REPLACE INTO "time_season" VALUES(2000,1,'summer',NULL); -REPLACE INTO "time_season" VALUES(2000,2,'winter',NULL); -REPLACE INTO "time_segment_fraction" VALUES(2000,'summer','day',0.5,'# S-D'); -REPLACE INTO "time_segment_fraction" VALUES(2000,'winter','day',0.5,'# W-D'); +REPLACE INTO "time_season" VALUES(1,'summer',0.5,NULL); +REPLACE INTO "time_season" VALUES(2,'winter',0.5,NULL); diff --git a/tests/testing_data/storageville.sql b/tests/testing_data/storageville.sql index 53e176bd9..f1a3e2203 100644 --- a/tests/testing_data/storageville.sql +++ b/tests/testing_data/storageville.sql @@ -19,16 +19,16 @@ REPLACE INTO "cost_invest" VALUES('electricville','batt',2025,1.0,NULL,NULL); REPLACE INTO "cost_variable" VALUES('electricville',2025,'EH',2025,1000.0,'',''); REPLACE INTO "cost_variable" VALUES('electricville',2025,'batt',2025,1.0,'',''); REPLACE INTO "demand" VALUES('electricville',2025,'RL',100.0,'',''); -REPLACE INTO "demand_specific_distribution" VALUES('electricville',2025,'s1','d1','RL',0.075,''); -REPLACE INTO "demand_specific_distribution" VALUES('electricville',2025,'s1','d2','RL',0.075,''); -REPLACE INTO "demand_specific_distribution" VALUES('electricville',2025,'s1','d3','RL',0.075,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('electricville',2025,'s2','d1','RL',0.075,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('electricville',2025,'s2','d2','RL',0.075,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('electricville',2025,'s2','d3','RL',0.075,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('electricville',2025,'s1','d4','RL',0.075,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('electricville',2025,'s1','d5','RL',0.2,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('electricville',2025,'s2','d4','RL',0.2,NULL); -REPLACE INTO "demand_specific_distribution" VALUES('electricville',2025,'s2','d5','RL',0.075,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('electricville','s1','d1','RL',0.075,''); +REPLACE INTO "demand_specific_distribution" VALUES('electricville','s1','d2','RL',0.075,''); +REPLACE INTO "demand_specific_distribution" VALUES('electricville','s1','d3','RL',0.075,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('electricville','s2','d1','RL',0.075,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('electricville','s2','d2','RL',0.075,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('electricville','s2','d3','RL',0.075,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('electricville','s1','d4','RL',0.075,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('electricville','s1','d5','RL',0.2,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('electricville','s2','d4','RL',0.2,NULL); +REPLACE INTO "demand_specific_distribution" VALUES('electricville','s2','d5','RL',0.075,NULL); REPLACE INTO "efficiency" VALUES('electricville', 'HYD', 'EH', 2025, 'ELC', 1.0, NULL, NULL); REPLACE INTO "efficiency" VALUES('electricville', 'ELC', 'bulbs', 2025, 'RL', 1.0, NULL, NULL); REPLACE INTO "efficiency" VALUES('electricville', 'earth', 'well', 2025, 'HYD', 1.0, NULL, 'water source'); @@ -40,8 +40,7 @@ REPLACE INTO "limit_capacity" VALUES('electricville',2025,'EH','ge',0.1,'',''); REPLACE INTO "limit_capacity" VALUES('electricville',2025,'batt','ge',0.1,'',''); REPLACE INTO "limit_capacity" VALUES('electricville',2025,'EH','le',200.0,'',''); REPLACE INTO "limit_capacity" VALUES('electricville',2025,'batt','le',100.0,'',''); -REPLACE INTO "limit_storage_level_fraction" VALUES('electricville',2025,'s1','d1','batt',2025,'e',0.5,NULL); -REPLACE INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); +REPLACE INTO "limit_storage_level_fraction" VALUES('electricville','s1','d1','batt','e',0.5,NULL); REPLACE INTO "metadata" VALUES('DB_MAJOR',4,''); REPLACE INTO "metadata" VALUES('DB_MINOR',0,''); REPLACE INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); @@ -50,8 +49,6 @@ REPLACE INTO "operator" VALUES('e','equal to'); REPLACE INTO "operator" VALUES('le','less than or equal to'); REPLACE INTO "operator" VALUES('ge','greater than or equal to'); REPLACE INTO "region" VALUES('electricville',NULL); -REPLACE INTO "season_label" VALUES('s1',NULL); -REPLACE INTO "season_label" VALUES('s2',NULL); REPLACE INTO "sector_label" VALUES('supply',NULL); REPLACE INTO "sector_label" VALUES('electric',NULL); REPLACE INTO "sector_label" VALUES('transport',NULL); @@ -66,25 +63,15 @@ REPLACE INTO "technology" VALUES('batt','ps','electric','electric','',0,0,0,0,0, REPLACE INTO "technology_type" VALUES('p','production technology'); REPLACE INTO "technology_type" VALUES('pb','baseload production technology'); REPLACE INTO "technology_type" VALUES('ps','storage production technology'); -REPLACE INTO "time_of_day" VALUES(1,'d1'); -REPLACE INTO "time_of_day" VALUES(2,'d2'); -REPLACE INTO "time_of_day" VALUES(3,'d3'); -REPLACE INTO "time_of_day" VALUES(4,'d4'); -REPLACE INTO "time_of_day" VALUES(5,'d5'); +REPLACE INTO "time_of_day" VALUES(1,'d1', 4.8, NULL); +REPLACE INTO "time_of_day" VALUES(2,'d2', 4.8, NULL); +REPLACE INTO "time_of_day" VALUES(3,'d3', 4.8, NULL); +REPLACE INTO "time_of_day" VALUES(4,'d4', 4.8, NULL); +REPLACE INTO "time_of_day" VALUES(5,'d5', 4.8, NULL); REPLACE INTO "time_period" VALUES(1,2020,'e'); REPLACE INTO "time_period" VALUES(2,2025,'f'); REPLACE INTO "time_period" VALUES(3,2030,'f'); REPLACE INTO "time_period_type" VALUES('e','existing vintages'); REPLACE INTO "time_period_type" VALUES('f','future'); -REPLACE INTO "time_season" VALUES(2025,1,'s1',NULL); -REPLACE INTO "time_season" VALUES(2025,2,'s2',NULL); -REPLACE INTO "time_segment_fraction" VALUES(2025,'s1','d3',0.1,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2025,'s2','d1',0.1,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2025,'s2','d2',0.1,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2025,'s2','d3',0.1,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2025,'s1','d1',0.1,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2025,'s1','d2',0.1,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2025,'s1','d4',0.1,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2025,'s1','d5',0.1,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2025,'s2','d4',0.1,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2025,'s2','d5',0.1,NULL); +REPLACE INTO "time_season" VALUES(1,'s1',0.5,NULL); +REPLACE INTO "time_season" VALUES(2,'s2',0.5,NULL); diff --git a/tests/testing_data/survival_curve.sql b/tests/testing_data/survival_curve.sql index de16ef19d..a0f32dc16 100644 --- a/tests/testing_data/survival_curve.sql +++ b/tests/testing_data/survival_curve.sql @@ -142,7 +142,6 @@ REPLACE INTO "lifetime_tech" VALUES('region', 'tech_ancient', 35.0, NULL, NULL); REPLACE INTO "lifetime_tech" VALUES('region', 'tech_old', 35.0, NULL, NULL); REPLACE INTO "lifetime_tech" VALUES('region', 'tech_current', 35.0, NULL, NULL); REPLACE INTO "lifetime_tech" VALUES('region', 'tech_future', 35.0, NULL, NULL); -REPLACE INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); REPLACE INTO "metadata" VALUES('DB_MAJOR',4,''); REPLACE INTO "metadata" VALUES('DB_MINOR',0,''); REPLACE INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); @@ -151,7 +150,6 @@ REPLACE INTO "operator" VALUES('e','equal to'); REPLACE INTO "operator" VALUES('le','less than or equal to'); REPLACE INTO "operator" VALUES('ge','greater than or equal to'); REPLACE INTO "region" VALUES('region',NULL); -REPLACE INTO "season_label" VALUES('s',NULL); REPLACE INTO "technology" VALUES('tech_ancient','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); REPLACE INTO "technology" VALUES('tech_old','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); REPLACE INTO "technology" VALUES('tech_current','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); @@ -159,7 +157,7 @@ REPLACE INTO "technology" VALUES('tech_future','p','energy',NULL,NULL,0,0,0,0,0, REPLACE INTO "technology_type" VALUES('p','production technology'); REPLACE INTO "technology_type" VALUES('pb','baseload production technology'); REPLACE INTO "technology_type" VALUES('ps','storage production technology'); -REPLACE INTO "time_of_day" VALUES(0,'d'); +REPLACE INTO "time_of_day" VALUES(0,'d',24,NULL); REPLACE INTO "time_period" VALUES(-2,1994,'e'); REPLACE INTO "time_period" VALUES(-1,2010,'e'); REPLACE INTO "time_period" VALUES(0,2025,'f'); @@ -171,15 +169,4 @@ REPLACE INTO "time_period" VALUES(5,2050,'f'); REPLACE INTO "time_period" VALUES(6,2055,'f'); REPLACE INTO "time_period_type" VALUES('e','existing vintages'); REPLACE INTO "time_period_type" VALUES('f','future'); -REPLACE INTO "time_season" VALUES(2025,0,'s',NULL); -REPLACE INTO "time_season" VALUES(2030,1,'s',NULL); -REPLACE INTO "time_season" VALUES(2035,2,'s',NULL); -REPLACE INTO "time_season" VALUES(2040,3,'s',NULL); -REPLACE INTO "time_season" VALUES(2045,4,'s',NULL); -REPLACE INTO "time_season" VALUES(2050,5,'s',NULL); -REPLACE INTO "time_segment_fraction" VALUES(2025,'s','d',1.0,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2030,'s','d',1.0,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2035,'s','d',1.0,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2040,'s','d',1.0,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2045,'s','d',1.0,NULL); -REPLACE INTO "time_segment_fraction" VALUES(2050,'s','d',1.0,NULL); +REPLACE INTO "time_season" VALUES(0,'s',1.0,NULL); diff --git a/tests/testing_data/test_system.sql b/tests/testing_data/test_system.sql index 83a9237a5..9e188ddb6 100644 --- a/tests/testing_data/test_system.sql +++ b/tests/testing_data/test_system.sql @@ -1,51 +1,19 @@ -REPLACE INTO "capacity_factor_tech" VALUES('R1',2020,'spring','day','E_SOLPV',0.6,''); -REPLACE INTO "capacity_factor_tech" VALUES('R1',2020,'spring','night','E_SOLPV',0.0,''); -REPLACE INTO "capacity_factor_tech" VALUES('R1',2020,'summer','day','E_SOLPV',0.6,''); -REPLACE INTO "capacity_factor_tech" VALUES('R1',2020,'summer','night','E_SOLPV',0.0,''); -REPLACE INTO "capacity_factor_tech" VALUES('R1',2020,'fall','day','E_SOLPV',0.6,''); -REPLACE INTO "capacity_factor_tech" VALUES('R1',2020,'fall','night','E_SOLPV',0.0,''); -REPLACE INTO "capacity_factor_tech" VALUES('R1',2020,'winter','day','E_SOLPV',0.6,''); -REPLACE INTO "capacity_factor_tech" VALUES('R1',2020,'winter','night','E_SOLPV',0.0,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2020,'spring','day','E_SOLPV',0.48,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2020,'spring','night','E_SOLPV',0.0,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2020,'summer','day','E_SOLPV',0.48,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2020,'summer','night','E_SOLPV',0.0,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2020,'fall','day','E_SOLPV',0.48,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2020,'fall','night','E_SOLPV',0.0,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2020,'winter','day','E_SOLPV',0.48,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2020,'winter','night','E_SOLPV',0.0,''); -REPLACE INTO "capacity_factor_tech" VALUES('R1',2025,'spring','day','E_SOLPV',0.6,''); -REPLACE INTO "capacity_factor_tech" VALUES('R1',2025,'spring','night','E_SOLPV',0.0,''); -REPLACE INTO "capacity_factor_tech" VALUES('R1',2025,'summer','day','E_SOLPV',0.6,''); -REPLACE INTO "capacity_factor_tech" VALUES('R1',2025,'summer','night','E_SOLPV',0.0,''); -REPLACE INTO "capacity_factor_tech" VALUES('R1',2025,'fall','day','E_SOLPV',0.6,''); -REPLACE INTO "capacity_factor_tech" VALUES('R1',2025,'fall','night','E_SOLPV',0.0,''); -REPLACE INTO "capacity_factor_tech" VALUES('R1',2025,'winter','day','E_SOLPV',0.6,''); -REPLACE INTO "capacity_factor_tech" VALUES('R1',2025,'winter','night','E_SOLPV',0.0,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2025,'spring','day','E_SOLPV',0.48,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2025,'spring','night','E_SOLPV',0.0,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2025,'summer','day','E_SOLPV',0.48,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2025,'summer','night','E_SOLPV',0.0,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2025,'fall','day','E_SOLPV',0.48,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2025,'fall','night','E_SOLPV',0.0,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2025,'winter','day','E_SOLPV',0.48,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2025,'winter','night','E_SOLPV',0.0,''); -REPLACE INTO "capacity_factor_tech" VALUES('R1',2030,'spring','day','E_SOLPV',0.6,''); -REPLACE INTO "capacity_factor_tech" VALUES('R1',2030,'spring','night','E_SOLPV',0.0,''); -REPLACE INTO "capacity_factor_tech" VALUES('R1',2030,'summer','day','E_SOLPV',0.6,''); -REPLACE INTO "capacity_factor_tech" VALUES('R1',2030,'summer','night','E_SOLPV',0.0,''); -REPLACE INTO "capacity_factor_tech" VALUES('R1',2030,'fall','day','E_SOLPV',0.6,''); -REPLACE INTO "capacity_factor_tech" VALUES('R1',2030,'fall','night','E_SOLPV',0.0,''); -REPLACE INTO "capacity_factor_tech" VALUES('R1',2030,'winter','day','E_SOLPV',0.6,''); -REPLACE INTO "capacity_factor_tech" VALUES('R1',2030,'winter','night','E_SOLPV',0.0,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2030,'spring','day','E_SOLPV',0.48,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2030,'spring','night','E_SOLPV',0.0,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2030,'summer','day','E_SOLPV',0.48,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2030,'summer','night','E_SOLPV',0.0,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2030,'fall','day','E_SOLPV',0.48,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2030,'fall','night','E_SOLPV',0.0,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2030,'winter','day','E_SOLPV',0.48,''); -REPLACE INTO "capacity_factor_tech" VALUES('R2',2030,'winter','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1','spring','day','E_SOLPV',0.6,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1','spring','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1','summer','day','E_SOLPV',0.6,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1','summer','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1','fall','day','E_SOLPV',0.6,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1','fall','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1','winter','day','E_SOLPV',0.6,''); +REPLACE INTO "capacity_factor_tech" VALUES('R1','winter','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2','spring','day','E_SOLPV',0.48,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2','spring','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2','summer','day','E_SOLPV',0.48,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2','summer','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2','fall','day','E_SOLPV',0.48,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2','fall','night','E_SOLPV',0.0,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2','winter','day','E_SOLPV',0.48,''); +REPLACE INTO "capacity_factor_tech" VALUES('R2','winter','night','E_SOLPV',0.0,''); REPLACE INTO "capacity_to_activity" VALUES('R1', 'S_IMPETH', 1.0, NULL, ''); REPLACE INTO "capacity_to_activity" VALUES('R1', 'S_IMPOIL', 1.0, NULL, ''); REPLACE INTO "capacity_to_activity" VALUES('R1', 'S_IMPNG', 1.0, NULL, ''); @@ -267,54 +235,22 @@ REPLACE INTO "demand" VALUES('R2',2030,'RH',84.0,'',''); REPLACE INTO "demand" VALUES('R2',2020,'VMT',36.0,'',''); REPLACE INTO "demand" VALUES('R2',2025,'VMT',39.0,'',''); REPLACE INTO "demand" VALUES('R2',2030,'VMT',42.0,'',''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2020,'spring','day','RH',0.05,''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2020,'spring','night','RH',0.1,''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2020,'summer','day','RH',0.0,''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2020,'summer','night','RH',0.0,''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2020,'fall','day','RH',0.05,''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2020,'fall','night','RH',0.1,''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2020,'winter','day','RH',0.3,''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2020,'winter','night','RH',0.4,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2020,'spring','day','RH',0.05,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2020,'spring','night','RH',0.1,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2020,'summer','day','RH',0.0,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2020,'summer','night','RH',0.0,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2020,'fall','day','RH',0.05,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2020,'fall','night','RH',0.1,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2020,'winter','day','RH',0.3,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2020,'winter','night','RH',0.4,''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2025,'spring','day','RH',0.05,''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2025,'spring','night','RH',0.1,''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2025,'summer','day','RH',0.0,''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2025,'summer','night','RH',0.0,''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2025,'fall','day','RH',0.05,''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2025,'fall','night','RH',0.1,''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2025,'winter','day','RH',0.3,''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2025,'winter','night','RH',0.4,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2025,'spring','day','RH',0.05,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2025,'spring','night','RH',0.1,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2025,'summer','day','RH',0.0,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2025,'summer','night','RH',0.0,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2025,'fall','day','RH',0.05,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2025,'fall','night','RH',0.1,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2025,'winter','day','RH',0.3,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2025,'winter','night','RH',0.4,''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2030,'spring','day','RH',0.05,''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2030,'spring','night','RH',0.1,''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2030,'summer','day','RH',0.0,''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2030,'summer','night','RH',0.0,''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2030,'fall','day','RH',0.05,''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2030,'fall','night','RH',0.1,''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2030,'winter','day','RH',0.3,''); -REPLACE INTO "demand_specific_distribution" VALUES('R1',2030,'winter','night','RH',0.4,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2030,'spring','day','RH',0.05,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2030,'spring','night','RH',0.1,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2030,'summer','day','RH',0.0,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2030,'summer','night','RH',0.0,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2030,'fall','day','RH',0.05,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2030,'fall','night','RH',0.1,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2030,'winter','day','RH',0.3,''); -REPLACE INTO "demand_specific_distribution" VALUES('R2',2030,'winter','night','RH',0.4,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1','spring','day','RH',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1','spring','night','RH',0.1,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1','summer','day','RH',0.0,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1','summer','night','RH',0.0,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1','fall','day','RH',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1','fall','night','RH',0.1,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1','winter','day','RH',0.3,''); +REPLACE INTO "demand_specific_distribution" VALUES('R1','winter','night','RH',0.4,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2','spring','day','RH',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2','spring','night','RH',0.1,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2','summer','day','RH',0.0,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2','summer','night','RH',0.0,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2','fall','day','RH',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2','fall','night','RH',0.1,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2','winter','day','RH',0.3,''); +REPLACE INTO "demand_specific_distribution" VALUES('R2','winter','night','RH',0.4,''); REPLACE INTO "efficiency" VALUES('R1', 'ethos', 'S_IMPETH', 2020, 'ETH', 1.0, NULL, ''); REPLACE INTO "efficiency" VALUES('R1', 'ethos', 'S_IMPOIL', 2020, 'OIL', 1.0, NULL, ''); REPLACE INTO "efficiency" VALUES('R1', 'ethos', 'S_IMPNG', 2020, 'NG', 1.0, NULL, ''); @@ -443,8 +379,8 @@ REPLACE INTO "limit_emission" VALUES('R1',2030,'CO2','le',23000.0,'kT CO2',''); REPLACE INTO "limit_emission" VALUES('global',2020,'CO2','le',37500.0,'kT CO2',''); REPLACE INTO "limit_emission" VALUES('global',2025,'CO2','le',36000.0,'kT CO2',''); REPLACE INTO "limit_emission" VALUES('global',2030,'CO2','le',34500.0,'kT CO2',''); -REPLACE INTO "limit_storage_level_fraction" VALUES('R1',2025,'winter','day','E_BATT',2025,'e',0.5,''); -REPLACE INTO "limit_storage_level_fraction" VALUES('R2',2020,'summer','day','E_BATT',2020,'e',0.5,''); +REPLACE INTO "limit_storage_level_fraction" VALUES('R1','winter','day','E_BATT','e',0.5,''); +REPLACE INTO "limit_storage_level_fraction" VALUES('R2','summer','day','E_BATT','e',0.5,''); REPLACE INTO "limit_tech_input_split" VALUES('R1',2020,'GSL','T_BLND','ge',0.9,''); REPLACE INTO "limit_tech_input_split" VALUES('R1',2020,'ETH','T_BLND','ge',0.1,''); REPLACE INTO "limit_tech_input_split" VALUES('R1',2025,'GSL','T_BLND','ge',0.9,''); @@ -469,7 +405,6 @@ REPLACE INTO "limit_tech_output_split" VALUES('R2',2025,'S_OILREF','GSL','ge',0. REPLACE INTO "limit_tech_output_split" VALUES('R2',2025,'S_OILREF','DSL','ge',0.08,''); REPLACE INTO "limit_tech_output_split" VALUES('R2',2030,'S_OILREF','GSL','ge',0.72,''); REPLACE INTO "limit_tech_output_split" VALUES('R2',2030,'S_OILREF','DSL','ge',0.08,''); -REPLACE INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); REPLACE INTO "metadata" VALUES('DB_MAJOR',4,''); REPLACE INTO "metadata" VALUES('DB_MINOR',0,''); REPLACE INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); @@ -479,10 +414,6 @@ REPLACE INTO "operator" VALUES('le','less than or equal to'); REPLACE INTO "operator" VALUES('ge','greater than or equal to'); REPLACE INTO "region" VALUES('R1',NULL); REPLACE INTO "region" VALUES('R2',NULL); -REPLACE INTO "season_label" VALUES('summer',NULL); -REPLACE INTO "season_label" VALUES('fall',NULL); -REPLACE INTO "season_label" VALUES('winter',NULL); -REPLACE INTO "season_label" VALUES('spring',NULL); REPLACE INTO "sector_label" VALUES('supply',NULL); REPLACE INTO "sector_label" VALUES('electric',NULL); REPLACE INTO "sector_label" VALUES('transport',NULL); @@ -510,8 +441,8 @@ REPLACE INTO "technology" VALUES('E_TRANS','p','electric','','',0,0,0,0,0,0,1,0, REPLACE INTO "technology_type" VALUES('p','production technology'); REPLACE INTO "technology_type" VALUES('pb','baseload production technology'); REPLACE INTO "technology_type" VALUES('ps','storage production technology'); -REPLACE INTO "time_of_day" VALUES(1,'day'); -REPLACE INTO "time_of_day" VALUES(2,'night'); +REPLACE INTO "time_of_day" VALUES(1,'day',12,NULL); +REPLACE INTO "time_of_day" VALUES(2,'night',12,NULL); REPLACE INTO "time_period" VALUES(1,2015,'e'); REPLACE INTO "time_period" VALUES(2,2020,'f'); REPLACE INTO "time_period" VALUES(3,2025,'f'); @@ -519,39 +450,7 @@ REPLACE INTO "time_period" VALUES(4,2030,'f'); REPLACE INTO "time_period" VALUES(5,2035,'f'); REPLACE INTO "time_period_type" VALUES('e','existing vintages'); REPLACE INTO "time_period_type" VALUES('f','future'); -REPLACE INTO "time_season" VALUES(2020,1,'spring',NULL); -REPLACE INTO "time_season" VALUES(2020,2,'summer',NULL); -REPLACE INTO "time_season" VALUES(2020,3,'fall',NULL); -REPLACE INTO "time_season" VALUES(2020,4,'winter',NULL); -REPLACE INTO "time_season" VALUES(2025,1,'spring',NULL); -REPLACE INTO "time_season" VALUES(2025,2,'summer',NULL); -REPLACE INTO "time_season" VALUES(2025,3,'fall',NULL); -REPLACE INTO "time_season" VALUES(2025,4,'winter',NULL); -REPLACE INTO "time_season" VALUES(2030,1,'spring',NULL); -REPLACE INTO "time_season" VALUES(2030,2,'summer',NULL); -REPLACE INTO "time_season" VALUES(2030,3,'fall',NULL); -REPLACE INTO "time_season" VALUES(2030,4,'winter',NULL); -REPLACE INTO "time_segment_fraction" VALUES(2020,'spring','day',0.125,'Spring - Day'); -REPLACE INTO "time_segment_fraction" VALUES(2020,'spring','night',0.125,'Spring - Night'); -REPLACE INTO "time_segment_fraction" VALUES(2020,'summer','day',0.125,'Summer - Day'); -REPLACE INTO "time_segment_fraction" VALUES(2020,'summer','night',0.125,'Summer - Night'); -REPLACE INTO "time_segment_fraction" VALUES(2020,'fall','day',0.125,'Fall - Day'); -REPLACE INTO "time_segment_fraction" VALUES(2020,'fall','night',0.125,'Fall - Night'); -REPLACE INTO "time_segment_fraction" VALUES(2020,'winter','day',0.125,'Winter - Day'); -REPLACE INTO "time_segment_fraction" VALUES(2020,'winter','night',0.125,'Winter - Night'); -REPLACE INTO "time_segment_fraction" VALUES(2025,'spring','day',0.125,'Spring - Day'); -REPLACE INTO "time_segment_fraction" VALUES(2025,'spring','night',0.125,'Spring - Night'); -REPLACE INTO "time_segment_fraction" VALUES(2025,'summer','day',0.125,'Summer - Day'); -REPLACE INTO "time_segment_fraction" VALUES(2025,'summer','night',0.125,'Summer - Night'); -REPLACE INTO "time_segment_fraction" VALUES(2025,'fall','day',0.125,'Fall - Day'); -REPLACE INTO "time_segment_fraction" VALUES(2025,'fall','night',0.125,'Fall - Night'); -REPLACE INTO "time_segment_fraction" VALUES(2025,'winter','day',0.125,'Winter - Day'); -REPLACE INTO "time_segment_fraction" VALUES(2025,'winter','night',0.125,'Winter - Night'); -REPLACE INTO "time_segment_fraction" VALUES(2030,'spring','day',0.125,'Spring - Day'); -REPLACE INTO "time_segment_fraction" VALUES(2030,'spring','night',0.125,'Spring - Night'); -REPLACE INTO "time_segment_fraction" VALUES(2030,'summer','day',0.125,'Summer - Day'); -REPLACE INTO "time_segment_fraction" VALUES(2030,'summer','night',0.125,'Summer - Night'); -REPLACE INTO "time_segment_fraction" VALUES(2030,'fall','day',0.125,'Fall - Day'); -REPLACE INTO "time_segment_fraction" VALUES(2030,'fall','night',0.125,'Fall - Night'); -REPLACE INTO "time_segment_fraction" VALUES(2030,'winter','day',0.125,'Winter - Day'); -REPLACE INTO "time_segment_fraction" VALUES(2030,'winter','night',0.125,'Winter - Night'); +REPLACE INTO "time_season" VALUES(1,'spring',0.25,NULL); +REPLACE INTO "time_season" VALUES(2,'summer',0.25,NULL); +REPLACE INTO "time_season" VALUES(3,'fall',0.25,NULL); +REPLACE INTO "time_season" VALUES(4,'winter',0.25,NULL); diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 8c7aa519a..1740580d8 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -9237,4038 +9237,1158 @@ 2015 ] ], - "capacity_factor_rpsdt": [ + "capacity_factor_rsdt": [ [ "R1", - 2020, "winter", "night", "E_NUCLEAR" ], [ "R2", - 2030, "spring", "night", "E_SOLPV" ], [ "R1", - 2030, "fall", "night", "T_EV" ], [ "R1", - 2020, "fall", "day", "E_NGCC" ], [ "R2", - 2025, "winter", "day", "R_EH" ], [ "R1", - 2025, "fall", "day", "T_DSL" ], [ "R2", - 2030, "fall", "night", "R_NGH" ], [ "R1", - 2030, "summer", "night", "T_EV" ], [ "R2", - 2030, "fall", "night", "E_NUCLEAR" ], [ "R2-R1", - 2030, "spring", "day", "E_TRANS" ], [ "R2", - 2025, "spring", "night", "T_EV" ], [ "R2", - 2030, "spring", "day", "T_EV" ], [ "R1", - 2025, "fall", "day", "S_OILREF" ], [ "R1", - 2030, "fall", "night", "T_DSL" ], [ "R2", - 2030, "spring", "night", "R_EH" ], [ "R1", - 2030, "summer", "night", "T_DSL" ], [ "R1", - 2020, "summer", "night", "R_NGH" ], [ "R2", - 2020, "winter", "day", "E_BATT" ], [ "R2", - 2020, "winter", "day", "T_BLND" ], [ "R2", - 2030, "spring", "day", "T_DSL" ], [ "R1", - 2030, "fall", "night", "S_OILREF" ], [ "R1", - 2030, "summer", "night", "S_OILREF" ], [ "R2-R1", - 2030, "winter", "night", "E_TRANS" ], [ "R1-R2", - 2020, "spring", "night", "E_TRANS" ], [ "R2", - 2025, "spring", "night", "S_OILREF" ], [ "R1", - 2020, - "fall", - "night", - "T_EV" - ], - [ - "R1", - 2025, "spring", "day", "E_SOLPV" ], [ "R2", - 2025, "winter", "night", "E_BATT" ], [ "R2", - 2025, "winter", "night", "T_BLND" ], [ "R2", - 2030, "spring", "day", "S_OILREF" ], [ "R1", - 2020, "winter", "night", "E_SOLPV" ], [ "R2", - 2025, "summer", "day", "R_EH" ], [ "R1", - 2020, "spring", "night", "R_NGH" ], [ "R2-R1", - 2020, "fall", "day", "E_TRANS" ], [ "R1", - 2020, "spring", "night", "E_NUCLEAR" ], [ "R2", - 2030, - "winter", - "day", - "E_BATT" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_BLND" - ], - [ - "R2", - 2030, "fall", "day", "T_GSL" ], [ "R2", - 2025, "spring", "day", "T_GSL" ], [ "R2", - 2020, "winter", "night", "T_GSL" ], [ "R2", - 2030, "winter", "night", "E_NGCC" ], [ "R1", - 2030, "spring", "night", "E_SOLPV" ], [ "R1", - 2025, "summer", "night", "T_BLND" ], [ "R1", - 2020, "winter", "day", "R_NGH" ], [ "R1", - 2025, "summer", "day", "E_BATT" ], [ "R1", - 2025, "summer", "day", "T_BLND" ], [ "R1", - 2020, "winter", "day", "E_NUCLEAR" ], [ "R2", - 2020, "spring", "night", "E_BATT" ], [ "R2", - 2020, "spring", "night", "T_BLND" ], [ "R1", - 2025, "spring", "day", "R_EH" ], [ "R2-R1", - 2025, "fall", "night", "E_TRANS" ], [ "R2", - 2030, "fall", "night", "T_EV" ], [ "R1", - 2020, "winter", "night", "R_EH" ], [ "R1", - 2025, "summer", "night", "E_NGCC" ], [ "R1", - 2020, - "fall", - "night", - "S_OILREF" - ], - [ - "R1", - 2030, "spring", "day", "R_NGH" ], [ "R2", - 2020, "spring", "night", "E_NGCC" ], [ "R1", - 2020, "summer", "day", "T_GSL" ], [ "R1", - 2030, "spring", "day", "E_NUCLEAR" ], [ "R1", - 2025, "winter", "night", "R_NGH" ], [ "R1", - 2020, "winter", "night", "T_DSL" ], - [ - "R2-R1", - 2020, - "winter", - "night", - "E_TRANS" - ], - [ - "R1", - 2025, - "winter", - "night", - "E_NUCLEAR" - ], [ "R1", - 2030, "spring", "night", "R_EH" ], [ "R1", - 2020, "fall", "day", "T_GSL" ], - [ - "R1", - 2020, - "summer", - "night", - "T_EV" - ], [ "R2", - 2030, "summer", "night", "T_BLND" ], [ "R1", - 2030, "spring", "night", "T_DSL" ], - [ - "R1", - 2020, - "spring", - "night", - "E_SOLPV" - ], - [ - "R1", - 2030, - "fall", - "day", - "S_OILREF" - ], [ "R2", - 2030, "fall", "night", "S_OILREF" ], [ "R2", - 2025, "fall", "night", "T_BLND" ], [ "R2", - 2025, "fall", "night", "E_BATT" ], [ "R2", - 2030, "summer", "night", "E_NGCC" ], [ "R1", - 2025, "winter", "day", "E_NGCC" ], [ "R1-R2", - 2020, "winter", "day", "E_TRANS" ], [ "R1", - 2020, "spring", "night", "T_EV" ], [ "R1", - 2020, - "spring", - "day", - "R_NGH" - ], - [ - "R1", - 2020, - "spring", - "day", - "E_NUCLEAR" - ], - [ - "R1", - 2030, "winter", "night", "E_NGCC" ], - [ - "R2-R1", - 2020, - "spring", - "day", - "E_TRANS" - ], - [ - "R1", - 2020, - "spring", - "night", - "R_EH" - ], [ "R1", - 2020, - "summer", - "night", - "S_OILREF" - ], - [ - "R1", - 2020, "winter", "day", "T_EV" ], - [ - "R1", - 2030, - "spring", - "day", - "E_SOLPV" - ], [ "R2", - 2020, "spring", "day", "E_BATT" ], [ "R1", - 2020, - "spring", - "night", - "T_DSL" - ], - [ - "R1", - 2025, "fall", "night", "R_NGH" ], [ "R1", - 2025, "fall", "night", "E_NUCLEAR" ], [ "R1", - 2030, "spring", "day", "T_EV" ], [ "R2-R1", - 2025, "spring", "night", "E_TRANS" ], [ "R2", - 2020, "fall", "night", "E_SOLPV" ], [ "R2", - 2020, "summer", "day", "R_NGH" ], [ "R1", - 2025, "winter", "night", "T_EV" ], [ "R2", - 2020, "summer", "day", "E_NUCLEAR" ], [ "R1", - 2020, "winter", "day", "T_DSL" ], - [ - "R2", - 2030, - "winter", - "night", - "T_GSL" - ], [ "R1-R2", - 2025, "summer", "day", "E_TRANS" ], [ "R2", - 2025, "summer", "night", "E_BATT" ], [ "R2", - 2025, - "summer", - "night", - "T_BLND" - ], - [ - "R2", - 2020, "fall", "day", "R_NGH" ], [ "R1", - 2025, "summer", "night", "T_GSL" ], [ "R2", - 2020, "fall", "day", "E_NUCLEAR" ], [ "R2", - 2030, "summer", "day", "E_BATT" ], [ "R1", - 2020, "winter", "day", "S_OILREF" ], [ "R2", - 2030, "summer", "day", "T_BLND" ], [ "R1", - 2030, "spring", "day", "T_DSL" ], [ "R2", - 2020, "spring", "night", "T_GSL" ], - [ - "R1", - 2025, - "fall", - "day", - "E_NGCC" - ], [ "R2", - 2020, "fall", "night", "R_EH" ], [ "R2", - 2020, "fall", "night", "T_DSL" ], [ "R1", - 2030, - "summer", - "day", - "E_BATT" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_BLND" - ], - [ - "R1", - 2030, "spring", "day", "S_OILREF" ], - [ - "R2", - 2025, - "spring", - "night", - "T_BLND" - ], [ "R1", - 2025, "winter", "night", "S_OILREF" ], [ "R1", - 2030, "winter", "day", "E_BATT" ], [ "R1", - 2030, "winter", "day", "T_BLND" ], [ "R1", - 2030, "fall", "night", "E_NGCC" ], - [ - "R1", - 2020, - "spring", - "day", - "T_EV" - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NGCC" - ], - [ - "R2", - 2025, - "spring", - "night", - "E_NGCC" - ], [ "R2", - 2030, "summer", "night", "T_GSL" ], [ "R1", - 2025, "winter", "day", "T_GSL" ], [ "R2", - 2030, "spring", "day", "E_NGCC" ], [ "R2", - 2020, "summer", "night", "E_SOLPV" ], [ "R2", - 2025, "winter", "night", "E_SOLPV" ], - [ - "R1-R2", - 2025, - "winter", - "day", - "E_TRANS" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_EV" - ], - [ - "R2", - 2020, - "winter", - "day", - "R_EH" - ], - [ - "R2-R1", - 2025, - "spring", - "day", - "E_TRANS" - ], [ "R2", - 2020, "fall", "day", "E_SOLPV" ], [ "R1", - 2030, "winter", "night", "T_GSL" ], [ "R2", - 2020, "summer", "day", "T_EV" ], [ "R1", - 2020, "fall", "night", "T_BLND" ], - [ - "R1", - 2025, - "spring", - "night", - "E_NUCLEAR" - ], [ "R2", - 2025, "winter", "day", "R_NGH" ], [ "R2", - 2025, "winter", "day", "E_NUCLEAR" ], [ "R1", - 2025, "summer", "day", "E_SOLPV" ], - [ - "R1", - 2020, - "spring", - "day", - "S_OILREF" - ], [ "R2", - 2020, "summer", "night", "R_EH" ], - [ - "R1", - 2020, - "fall", - "night", - "E_NGCC" - ], [ "R2", - 2025, "winter", "night", "R_EH" ], - [ - "R1", - 2025, - "fall", - "night", - "T_DSL" - ], [ "R2", - 2020, "fall", "day", "T_EV" ], [ "R2", - 2020, "summer", "night", "T_DSL" ], - [ - "R2-R1", - 2030, - "spring", - "night", - "E_TRANS" - ], - [ - "R2", - 2030, - "winter", - "day", - "R_EH" - ], [ "R2", - 2030, "spring", "night", "R_NGH" ], [ "R2", - 2030, "spring", "night", "E_NUCLEAR" ], - [ - "R1", - 2025, - "fall", - "night", - "S_OILREF" - ], [ "R1-R2", - 2030, "summer", "night", "E_TRANS" ], [ "R1", - 2030, - "fall", - "day", - "E_BATT" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_BLND" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_BLND" - ], - [ - "R1", - 2025, - "summer", - "day", - "R_EH" - ], - [ - "R2", - 2030, - "fall", - "day", - "E_BATT" - ], - [ - "R2", - 2020, - "fall", - "day", - "T_DSL" - ], - [ - "R2", - 2020, - "summer", - "day", - "S_OILREF" - ], - [ - "R2", - 2025, - "spring", - "day", - "T_BLND" - ], - [ - "R2", - 2025, - "spring", - "day", - "E_BATT" - ], - [ - "R2", - 2020, - "winter", - "night", - "E_BATT" - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NGCC" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_GSL" - ], - [ - "R1-R2", - 2030, - "fall", - "day", - "E_TRANS" - ], - [ - "R2", - 2025, - "summer", - "day", - "R_NGH" - ], - [ - "R2", - 2020, "fall", "day", - "S_OILREF" - ], - [ - "R2", - 2025, - "summer", - "day", - "E_NUCLEAR" - ], - [ - "R1", - 2020, - "summer", - "night", "E_BATT" ], [ - "R1", - 2025, - "spring", - "night", - "E_SOLPV" - ], - [ - "R1", - 2020, - "summer", - "night", - "T_BLND" - ], - [ - "R2", - 2025, - "winter", - "day", - "E_SOLPV" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_GSL" - ], - [ - "R2", - 2025, - "fall", - "day", - "R_NGH" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_GSL" - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NUCLEAR" - ], - [ - "R1", - 2020, - "summer", - "night", - "E_NGCC" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_GSL" - ], - [ - "R1", - 2025, - "spring", - "day", - "R_NGH" - ], - [ - "R1", - 2020, - "fall", - "day", - "E_BATT" - ], - [ - "R1", - 2020, - "fall", - "day", - "T_BLND" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_EV" - ], - [ - "R2", - 2025, - "fall", - "night", - "R_EH" - ], - [ - "R1", - 2025, - "spring", - "day", - "E_NUCLEAR" - ], - [ - "R2", - 2030, - "spring", - "day", - "T_GSL" - ], - [ - "R1", - 2020, - "winter", - "night", - "R_NGH" - ], - [ - "R2", - 2020, - "spring", - "day", - "E_SOLPV" - ], - [ - "R1", - 2025, - "spring", - "night", - "R_EH" - ], - [ - "R1", - 2030, - "spring", - "night", - "R_NGH" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_DSL" - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NUCLEAR" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_DSL" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_EV" - ], - [ - "R1", - 2020, - "winter", - "day", - "T_BLND" - ], - [ - "R2", - 2025, - "summer", - "night", - "E_SOLPV" - ], - [ - "R1", - 2020, - "winter", - "day", - "E_NGCC" - ], - [ - "R2", - 2020, - "spring", - "day", - "R_EH" - ], - [ - "R1", - 2020, - "fall", - "night", - "T_GSL" - ], - [ - "R2", - 2025, - "summer", - "day", - "E_SOLPV" - ], - [ - "R1-R2", - 2030, - "winter", - "day", - "E_TRANS" - ], - [ - "R2", - 2025, - "winter", - "day", - "S_OILREF" - ], - [ - "R1", - 2025, - "winter", - "night", - "E_BATT" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_BLND" - ], - [ - "R2", - 2020, - "spring", - "day", - "T_DSL" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_DSL" - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NGCC" - ], - [ - "R2", - 2025, - "fall", - "day", - "E_SOLPV" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_EV" - ], - [ - "R1", - 2025, - "winter", - "night", - "E_NGCC" - ], - [ - "R2", - 2025, - "summer", - "night", - "R_EH" - ], - [ - "R2", - 2030, - "spring", - "night", - "S_OILREF" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_GSL" - ], - [ - "R2", - 2030, - "winter", - "night", - "E_BATT" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_BLND" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_GSL" - ], - [ - "R2", - 2030, - "summer", - "day", - "R_EH" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_EV" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_DSL" - ], - [ - "R2-R1", - 2020, - "spring", - "night", - "E_TRANS" - ], - [ - "R1", - 2025, - "spring", - "day", - "T_EV" - ], - [ - "R2", - 2025, - "fall", - "day", - "R_EH" - ], - [ - "R1", - 2025, - "summer", - "night", - "E_BATT" - ], - [ - "R1", - 2020, - "winter", - "night", - "T_EV" - ], - [ - "R1", - 2030, - "summer", - "day", - "R_EH" - ], - [ - "R1", - 2020, - "spring", - "day", - "T_BLND" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_DSL" - ], - [ - "R1-R2", - 2020, - "summer", - "day", - "E_TRANS" - ], - [ - "R1", - 2030, - "winter", - "day", - "R_EH" - ], - [ - "R2", - 2025, - "summer", - "day", - "S_OILREF" - ], - [ - "R1", - 2020, - "summer", - "night", - "T_GSL" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_EV" - ], - [ - "R1", - 2020, - "spring", - "day", - "E_NGCC" - ], - [ - "R1", - 2025, - "spring", - "day", - "T_DSL" - ], - [ - "R1-R2", - 2020, - "fall", - "day", - "E_TRANS" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_BLND" - ], - [ - "R2", - 2020, - "fall", - "night", - "R_NGH" - ], - [ - "R1", - 2025, - "spring", - "day", - "S_OILREF" - ], - [ - "R2", - 2020, - "fall", - "night", - "E_NUCLEAR" - ], - [ - "R2", - 2020, - "summer", - "day", - "T_BLND" - ], - [ - "R1", - 2020, - "winter", - "night", - "S_OILREF" - ], - [ - "R2", - 2030, - "summer", - "night", - "E_BATT" - ], - [ - "R1", - 2025, - "winter", - "day", - "E_BATT" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_BLND" - ], - [ - "R1", - 2025, - "fall", - "night", - "E_NGCC" - ], - [ - "R1-R2", - 2025, - "fall", - "night", - "E_TRANS" - ], - [ - "R2", - 2020, - "summer", - "day", - "E_NGCC" - ], - [ - "R2", - 2030, - "fall", - "day", - "E_SOLPV" - ], - [ - "R1", - 2020, - "winter", - "day", - "T_GSL" - ], - [ - "R1", - 2030, - "spring", - "night", - "S_OILREF" - ], - [ - "R1-R2", - 2020, - "winter", - "night", - "E_TRANS" - ], - [ - "R2", - 2020, - "winter", - "night", - "E_SOLPV" - ], - [ - "R1", - 2030, - "winter", - "night", - "E_BATT" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_BLND" - ], - [ - "R2", - 2020, - "fall", - "day", - "E_NGCC" - ], - [ - "R1", - 2030, - "spring", - "day", - "T_GSL" - ], - [ - "R2-R1", - 2030, - "summer", - "day", - "E_TRANS" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_GSL" - ], - [ - "R2", - 2020, - "winter", - "day", - "R_NGH" - ], - [ - "R2", - 2020, - "winter", - "day", - "E_NUCLEAR" - ], - [ - "R1", - 2020, - "summer", - "day", - "E_SOLPV" - ], - [ - "R2", - 2030, - "fall", - "day", - "R_EH" - ], - [ - "R2", - 2025, - "spring", - "day", - "R_EH" - ], - [ - "R2", - 2020, - "winter", - "night", - "R_EH" - ], - [ - "R2", - 2020, - "summer", - "night", - "R_NGH" - ], - [ - "R2", - 2020, - "summer", - "night", - "E_NUCLEAR" - ], - [ - "R2", - 2025, - "winter", - "night", - "R_NGH" - ], - [ - "R2-R1", - 2020, - "summer", - "night", - "E_TRANS" - ], - [ - "R2", - 2020, - "winter", - "night", - "T_DSL" - ], - [ - "R2", - 2025, - "winter", - "night", - "E_NUCLEAR" - ], - [ - "R1", - 2020, - "spring", - "night", - "S_OILREF" - ], - [ - "R2", - 2030, - "winter", - "day", - "R_NGH" - ], - [ - "R1-R2", - 2025, - "summer", - "night", - "E_TRANS" - ], - [ - "R1", - 2025, - "fall", - "day", - "E_BATT" - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NUCLEAR" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_BLND" - ], - [ - "R1", - 2020, - "summer", - "day", - "R_EH" - ], - [ - "R2", - 2020, - "fall", - "night", - "T_EV" - ], - [ - "R1", - 2025, - "summer", - "day", - "R_NGH" - ], - [ - "R1", - 2020, - "summer", - "day", - "T_DSL" - ], - [ - "R1", - 2020, - "spring", - "day", - "T_GSL" - ], - [ - "R1", - 2025, - "summer", - "day", - "E_NUCLEAR" - ], - [ - "R2", - 2020, - "spring", - "night", - "E_NUCLEAR" - ], - [ - "R1", - 2020, - "fall", - "day", - "R_EH" - ], - [ - "R1-R2", - 2025, - "fall", - "day", - "E_TRANS" - ], - [ - "R1", - 2030, - "fall", - "night", - "E_BATT" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_BLND" - ], - [ - "R2", - 2025, - "winter", - "day", - "E_NGCC" - ], - [ - "R1", - 2030, - "summer", - "night", - "E_BATT" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_BLND" - ], - [ - "R2", - 2025, - "spring", - "night", - "E_BATT" - ], - [ - "R2", - 2020, - "winter", - "day", - "E_SOLPV" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_BLND" - ], - [ - "R2", - 2030, - "spring", - "day", - "E_BATT" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_GSL" - ], - [ - "R2", - 2030, - "spring", - "day", - "T_BLND" - ], - [ - "R1-R2", - 2030, - "fall", - "night", - "E_TRANS" - ], - [ - "R2", - 2020, - "fall", - "night", - "S_OILREF" - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NGCC" - ], - [ - "R2", - 2020, - "summer", - "day", - "T_GSL" - ], - [ - "R2", - 2020, - "winter", - "day", - "T_EV" - ], - [ - "R1-R2", - 2025, - "winter", - "night", - "E_TRANS" - ], - [ - "R2", - 2030, - "winter", - "night", - "E_SOLPV" - ], - [ - "R2", - 2025, - "fall", - "night", - "R_NGH" - ], - [ - "R2", - 2030, - "winter", - "day", - "E_SOLPV" - ], - [ - "R2", - 2020, - "fall", - "day", - "T_GSL" - ], - [ - "R2", - 2025, - "fall", - "night", - "E_NUCLEAR" - ], - [ - "R2", - 2020, - "summer", - "night", - "T_EV" - ], - [ - "R1", - 2025, - "spring", - "night", - "R_NGH" - ], - [ - "R1", - 2020, - "fall", - "night", - "E_BATT" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_EV" - ], - [ - "R1", - 2025, - "summer", - "night", - "E_SOLPV" - ], - [ - "R2-R1", - 2020, - "summer", - "day", - "E_TRANS" - ], - [ - "R2", - 2020, - "winter", - "day", - "T_DSL" - ], - [ - "R2-R1", - 2025, - "winter", - "day", - "E_TRANS" - ], - [ - "R2", - 2025, - "summer", - "day", - "E_NGCC" - ], - [ - "R2", - 2020, - "spring", - "night", - "E_SOLPV" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_EV" - ], - [ - "R2", - 2030, - "winter", - "night", - "R_EH" - ], - [ - "R1", - 2025, - "spring", - "day", - "T_BLND" - ], - [ - "R2", - 2020, - "winter", - "day", - "S_OILREF" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_EV" - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NGCC" - ], - [ - "R1", - 2020, - "winter", - "night", - "E_BATT" - ], - [ - "R1", - 2020, - "winter", - "night", - "T_BLND" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_DSL" - ], - [ - "R2", - 2020, - "spring", - "day", - "R_NGH" - ], - [ - "R2", - 2020, - "spring", - "day", - "E_NUCLEAR" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_DSL" - ], - [ - "R1", - 2025, - "summer", - "night", - "R_EH" - ], - [ - "R1", - 2025, - "spring", - "day", - "E_NGCC" - ], - [ - "R2", - 2030, - "fall", - "night", - "E_BATT" - ], - [ - "R1", - 2020, - "winter", - "night", - "E_NGCC" - ], - [ - "R2", - 2020, - "spring", - "night", - "R_EH" - ], - [ - "R2", - 2020, - "summer", - "night", - "S_OILREF" - ], - [ - "R1-R2", - 2025, - "spring", - "day", - "E_TRANS" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_BLND" - ], - [ - "R2", - 2025, - "winter", - "night", - "S_OILREF" - ], - [ - "R2", - 2030, - "summer", - "night", - "E_SOLPV" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_DSL" - ], - [ - "R2", - 2020, - "spring", - "night", - "T_DSL" - ], - [ - "R2", - 2030, - "winter", - "day", - "S_OILREF" - ], - [ - "R2", - 2025, - "summer", - "night", - "R_NGH" - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NGCC" - ], - [ - "R2", - 2025, - "fall", - "night", - "E_SOLPV" - ], - [ - "R2", - 2025, - "summer", - "night", - "E_NUCLEAR" - ], - [ - "R1-R2", - 2030, - "spring", - "night", - "E_TRANS" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_GSL" - ], - [ - "R2", - 2030, - "summer", - "day", - "R_NGH" - ], - [ - "R1", - 2025, - "summer", - "day", - "S_OILREF" - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NUCLEAR" - ], - [ - "R1", - 2030, - "winter", - "night", - "E_SOLPV" - ], - [ - "R2-R1", - 2030, - "fall", - "day", - "E_TRANS" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_EV" - ], - [ - "R2", - 2030, - "summer", - "night", - "R_EH" - ], - [ - "R1", - 2025, - "winter", - "day", - "R_EH" - ], - [ - "R1", - 2030, - "summer", - "day", - "R_NGH" - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NUCLEAR" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_EV" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_GSL" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_DSL" - ], - [ - "R1", - 2030, - "winter", - "day", - "R_NGH" - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NUCLEAR" - ], - [ - "R1", - 2020, - "spring", - "night", - "E_BATT" - ], - [ - "R1", - 2020, - "spring", - "night", - "T_BLND" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_DSL" - ], - [ - "R1", - 2030, - "winter", - "night", - "R_EH" - ], - [ - "R1", - 2020, - "spring", - "night", - "E_NGCC" - ], - [ - "R1", - 2020, - "winter", - "day", - "E_BATT" - ], - [ - "R2", - 2020, - "spring", - "day", - "T_EV" - ], - [ - "R1-R2", - 2020, - "fall", - "night", - "E_TRANS" - ], - [ - "R2", - 2025, - "fall", - "night", - "S_OILREF" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_GSL" - ], - [ - "R1-R2", - 2030, - "winter", - "night", - "E_TRANS" - ], - [ - "R1", - 2025, - "spring", - "night", - "S_OILREF" - ], - [ - "R1", - 2030, - "spring", - "day", - "E_BATT" - ], - [ - "R1", - 2030, - "spring", - "day", - "T_BLND" - ], - [ - "R2", - 2030, - "summer", - "day", - "E_SOLPV" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_EV" - ], - [ - "R1", - 2025, - "spring", - "day", - "T_GSL" - ], - [ - "R2-R1", - 2025, - "summer", - "day", - "E_TRANS" - ], - [ - "R2", - 2020, - "fall", - "night", - "T_BLND" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_EV" - ], - [ - "R1-R2", - 2030, - "spring", - "day", - "E_TRANS" - ], - [ - "R1", - 2030, - "summer", - "day", - "E_SOLPV" - ], - [ - "R1", - 2020, - "winter", - "night", - "T_GSL" - ], - [ - "R2-R1", - 2030, - "winter", - "day", - "E_TRANS" - ], - [ - "R2", - 2025, - "spring", - "night", - "E_SOLPV" - ], - [ - "R1", - 2025, - "fall", - "day", - "R_EH" - ], - [ - "R2", - 2020, - "spring", - "day", - "S_OILREF" - ], - [ - "R1", - 2030, - "winter", - "day", - "E_SOLPV" - ], - [ - "R2", - 2030, - "spring", - "day", - "E_SOLPV" - ], - [ - "R1", - 2030, - "fall", - "day", - "R_NGH" - ], - [ - "R2", - 2020, - "fall", - "night", - "E_NGCC" - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NUCLEAR" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_DSL" - ], - [ - "R2", - 2030, - "fall", - "day", - "R_NGH" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_EV" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_GSL" - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NUCLEAR" - ], - [ - "R2-R1", - 2030, - "summer", - "night", - "E_TRANS" - ], - [ - "R2", - 2025, - "spring", - "day", - "R_NGH" - ], - [ - "R2", - 2025, - "spring", - "day", - "E_NUCLEAR" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_EV" - ], - [ - "R1", - 2030, - "fall", - "night", - "R_EH" - ], - [ - "R2", - 2020, - "winter", - "night", - "R_NGH" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_DSL" - ], - [ - "R2", - 2020, - "winter", - "night", - "E_NUCLEAR" - ], - [ - "R1", - 2030, - "summer", - "night", - "R_EH" - ], - [ - "R1", - 2020, - "spring", - "day", - "E_BATT" - ], - [ - "R2", - 2025, - "spring", - "night", - "R_EH" - ], - [ - "R1-R2", - 2020, - "summer", - "night", - "E_TRANS" - ], - [ - "R2", - 2025, - "summer", - "night", - "S_OILREF" - ], - [ - "R2", - 2030, - "spring", - "day", - "R_EH" - ], - [ - "R2", - 2030, - "summer", - "day", - "S_OILREF" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_DSL" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_DSL" - ], - [ - "R1", - 2020, - "fall", - "night", - "E_SOLPV" - ], - [ - "R1", - 2020, - "summer", - "night", - "E_NUCLEAR" - ], - [ - "R1", - 2020, - "summer", - "day", - "R_NGH" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_DSL" - ], - [ - "R1", - 2020, - "summer", - "day", - "E_NUCLEAR" - ], - [ - "R2", - 2025, - "fall", - "day", - "S_OILREF" - ], - [ - "R1", - 2025, - "fall", - "night", - "E_BATT" - ], - [ - "R2", - 2020, - "winter", - "day", - "E_NGCC" - ], - [ - "R1", - 2030, - "summer", - "day", - "S_OILREF" - ], - [ - "R1", - 2020, - "fall", - "day", - "R_NGH" - ], - [ - "R2", - 2020, - "summer", - "night", - "E_BATT" - ], - [ - "R2", - 2020, - "summer", - "night", - "T_BLND" - ], - [ - "R1", - 2020, - "fall", - "day", - "E_NUCLEAR" - ], - [ - "R1", - 2030, - "winter", - "day", - "S_OILREF" - ], - [ - "R2", - 2020, - "summer", - "day", - "E_BATT" - ], - [ - "R1", - 2020, - "spring", - "night", - "T_GSL" - ], - [ - "R1", - 2020, - "fall", - "night", - "R_EH" - ], - [ - "R2", - 2020, - "summer", - "night", - "E_NGCC" - ], - [ - "R1", - 2030, - "fall", - "day", - "E_SOLPV" - ], - [ - "R2", - 2030, - "fall", - "night", - "E_SOLPV" - ], - [ - "R2", - 2025, - "winter", - "night", - "E_NGCC" - ], - [ - "R2", - 2020, - "fall", - "day", - "E_BATT" - ], - [ - "R2", - 2020, - "fall", - "day", - "T_BLND" - ], - [ - "R1", - 2020, - "fall", - "night", - "T_DSL" - ], - [ - "R2", - 2025, - "spring", - "day", - "E_SOLPV" - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NGCC" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_EV" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_EV" - ], - [ - "R1", - 2025, - "summer", - "day", - "E_NGCC" - ], - [ - "R2", - 2025, - "spring", - "day", - "T_EV" - ], - [ - "R2", - 2020, - "winter", - "night", - "T_EV" - ], - [ - "R1", - 2030, - "fall", - "day", - "R_EH" - ], - [ - "R1", - 2020, - "summer", - "night", - "E_SOLPV" - ], - [ - "R2", - 2030, - "fall", - "night", - "R_EH" - ], - [ - "R2-R1", - 2020, - "winter", - "day", - "E_TRANS" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_DSL" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_DSL" - ], - [ - "R2", - 2020, - "fall", - "night", - "T_GSL" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_DSL" - ], - [ - "R2", - 2025, - "spring", - "day", - "T_DSL" - ], - [ - "R1", - 2020, - "fall", - "day", - "E_SOLPV" - ], - [ - "R1", - 2020, - "summer", - "day", - "T_EV" - ], - [ - "R2", - 2030, - "winter", - "night", - "R_NGH" - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NUCLEAR" - ], - [ - "R1", - 2020, - "summer", - "night", - "R_EH" - ], - [ - "R2", - 2030, - "fall", - "day", - "S_OILREF" - ], - [ - "R1-R2", - 2020, - "spring", - "day", - "E_TRANS" - ], - [ - "R2", - 2025, - "spring", - "day", - "S_OILREF" - ], - [ - "R1", - 2020, - "fall", - "day", - "T_EV" - ], - [ - "R1", - 2025, - "spring", - "night", - "E_BATT" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_BLND" - ], - [ - "R1", - 2025, - "summer", - "night", - "R_NGH" - ], - [ - "R1", - 2020, - "summer", - "night", - "T_DSL" - ], - [ - "R2", - 2020, - "winter", - "night", - "S_OILREF" - ], - [ - "R2", - 2025, - "winter", - "day", - "E_BATT" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_BLND" - ], - [ - "R2", - 2025, - "fall", - "night", - "E_NGCC" - ], - [ - "R1", - 2025, - "summer", - "night", - "E_NUCLEAR" - ], - [ - "R1", - 2020, - "winter", - "day", - "E_SOLPV" - ], - [ - "R2", - 2020, - "spring", - "night", - "R_NGH" - ], - [ - "R1", - 2025, - "spring", - "night", - "E_NGCC" - ], - [ - "R1-R2", - 2025, - "spring", - "night", - "E_TRANS" - ], - [ - "R2", - 2020, - "winter", - "day", - "T_GSL" - ], - [ - "R1", - 2020, - "fall", - "day", - "T_DSL" - ], - [ - "R1", - 2020, - "summer", - "day", - "S_OILREF" - ], - [ - "R1", - 2025, - "winter", - "night", - "E_SOLPV" - ], - [ - "R2", - 2020, - "spring", - "day", - "T_BLND" - ], - [ - "R2", - 2030, - "spring", - "night", - "E_BATT" - ], - [ - "R2-R1", - 2025, - "fall", - "day", - "E_TRANS" - ], - [ - "R1", - 2020, - "winter", - "day", - "R_EH" - ], - [ - "R2", - 2020, - "summer", - "night", - "T_GSL" - ], - [ - "R1", - 2020, - "fall", - "day", - "S_OILREF" - ], - [ - "R2", - 2020, - "spring", - "day", - "E_NGCC" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_GSL" - ], - [ - "R2", - 2030, - "summer", - "night", - "R_NGH" - ], - [ - "R1", - 2025, - "winter", - "day", - "R_NGH" - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NUCLEAR" - ], - [ - "R1", - 2025, - "winter", - "day", - "E_NUCLEAR" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_GSL" - ], - [ - "R1", - 2030, - "spring", - "day", - "R_EH" - ], - [ - "R2-R1", - 2030, - "fall", - "night", - "E_TRANS" - ], - [ - "R1", - 2025, - "winter", - "night", - "R_EH" - ], - [ - "R2", - 2025, - "summer", - "day", - "E_BATT" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_BLND" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_GSL" - ], - [ - "R1", - 2030, - "winter", - "night", - "R_NGH" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_DSL" - ], - [ - "R2-R1", - 2025, - "winter", - "night", - "E_TRANS" - ], - [ - "R2", - 2025, - "summer", - "night", - "E_NGCC" - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NUCLEAR" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_EV" + "R1", + "fall", + "day", + "T_BLND" ], [ "R1", - 2020, - "spring", + "summer", "day", - "E_SOLPV" + "R_EH" ], [ "R2", - 2025, "fall", "day", "E_BATT" ], [ "R2", - 2025, "fall", "day", - "T_BLND" + "T_DSL" ], [ "R2", - 2030, "summer", "day", - "E_NGCC" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_EV" + "S_OILREF" ], [ - "R1", - 2025, + "R2", "spring", "day", - "E_BATT" + "T_BLND" ], [ "R2", - 2020, - "spring", + "fall", "night", - "T_EV" + "E_NGCC" + ], + [ + "R1-R2", + "fall", + "day", + "E_TRANS" ], [ "R2", - 2030, - "winter", - "night", - "T_DSL" + "fall", + "day", + "S_OILREF" ], [ "R1", - 2030, "summer", + "night", + "E_BATT" + ], + [ + "R2", + "winter", "day", - "E_NGCC" + "E_SOLPV" ], [ "R1", - 2025, "fall", "night", - "E_SOLPV" + "T_GSL" ], [ - "R1", - 2030, + "R2", "winter", "day", - "E_NGCC" + "T_EV" ], [ - "R1", - 2020, + "R2", "spring", "day", - "R_EH" + "E_SOLPV" ], [ - "R1", - 2030, + "R2", + "winter", + "day", + "T_DSL" + ], + [ + "R2", "spring", - "night", - "E_BATT" + "day", + "R_EH" ], [ "R2", - 2020, "summer", "day", "E_SOLPV" ], + [ + "R2", + "winter", + "day", + "S_OILREF" + ], [ "R1", - 2025, - "summer", + "winter", "night", - "T_DSL" + "E_BATT" ], [ "R1", - 2025, "winter", - "day", - "E_SOLPV" + "night", + "T_BLND" ], [ "R2", - 2030, - "winter", + "spring", "night", - "S_OILREF" + "T_DSL" + ], + [ + "R1", + "spring", + "day", + "E_NGCC" ], [ "R2", - 2025, "fall", "night", "T_GSL" ], [ - "R1", - 2020, - "spring", + "R2", + "summer", "day", "T_DSL" ], [ - "R1", - 2025, + "R2", "fall", "day", - "R_NGH" + "R_EH" ], [ "R1", - 2025, - "fall", + "spring", "day", - "E_NUCLEAR" + "T_BLND" ], [ "R1", - 2025, - "spring", - "night", - "T_GSL" + "winter", + "day", + "R_EH" ], [ - "R2-R1", - 2025, - "summer", + "R1-R2", + "fall", "night", "E_TRANS" ], [ "R2", - 2030, "summer", - "night", - "T_EV" + "day", + "E_NGCC" ], [ "R1", - 2025, - "summer", + "spring", "night", "S_OILREF" ], [ - "R1", - 2025, + "R1-R2", "winter", - "day", - "T_EV" - ], - [ - "R1", - 2025, - "fall", "night", - "R_EH" + "E_TRANS" ], [ "R2", - 2020, - "spring", - "night", - "S_OILREF" + "fall", + "day", + "E_NGCC" ], [ "R1", - 2030, - "fall", - "night", - "R_NGH" + "spring", + "day", + "T_GSL" ], [ - "R2", - 2020, + "R2-R1", "summer", "day", - "R_EH" - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NUCLEAR" + "E_TRANS" ], [ - "R1", - 2030, + "R2", "summer", "night", "R_NGH" ], [ - "R1", - 2030, + "R2", "summer", "night", "E_NUCLEAR" ], [ "R2", - 2025, - "spring", + "winter", "night", "R_NGH" ], [ - "R2", - 2020, + "R2-R1", "summer", - "day", - "T_DSL" + "night", + "E_TRANS" ], [ "R2", - 2025, - "spring", + "winter", "night", - "E_NUCLEAR" + "T_DSL" ], [ - "R1", - 2030, + "R2", "winter", "night", - "T_EV" + "E_NUCLEAR" ], [ - "R2", - 2020, - "spring", + "R1", + "summer", "day", - "T_GSL" + "R_NGH" ], [ "R1", - 2025, - "winter", + "summer", "day", "T_DSL" ], [ - "R2", - 2030, - "spring", + "R1", + "summer", "day", - "R_NGH" + "E_NUCLEAR" ], [ - "R2", - 2020, + "R1", "fall", "day", "R_EH" ], [ - "R2", - 2030, - "spring", - "day", - "E_NUCLEAR" + "R1", + "fall", + "night", + "E_BATT" ], [ - "R1-R2", - 2030, - "summer", + "R2", + "winter", "day", - "E_TRANS" + "E_NGCC" ], [ "R2", - 2030, - "fall", + "summer", "day", - "T_BLND" + "T_GSL" ], [ "R2", - 2030, "summer", "night", - "S_OILREF" - ], - [ - "R1", - 2025, - "winter", - "day", - "S_OILREF" + "T_EV" ], [ "R2", - 2020, "winter", "night", - "T_BLND" + "T_EV" ], [ "R1", - 2030, - "fall", - "day", - "E_NGCC" + "summer", + "night", + "E_SOLPV" ], [ - "R1", - 2030, + "R2-R1", "winter", - "night", - "T_DSL" + "day", + "E_TRANS" ], [ - "R2", - 2030, - "fall", + "R1", + "summer", "day", - "E_NGCC" + "T_EV" ], [ "R2", - 2025, - "summer", - "night", - "T_GSL" + "spring", + "day", + "R_NGH" ], [ "R2", - 2025, "spring", "day", - "E_NGCC" + "E_NUCLEAR" ], [ "R1", - 2025, - "fall", - "day", - "E_SOLPV" + "summer", + "night", + "R_EH" ], [ "R2", - 2030, "summer", + "night", + "S_OILREF" + ], + [ + "R1-R2", + "spring", "day", - "T_GSL" + "E_TRANS" ], [ - "R2", - 2020, - "winter", + "R1", + "spring", "night", - "E_NGCC" + "T_BLND" ], [ - "R1", - 2020, - "fall", + "R2", + "winter", "night", - "R_NGH" + "S_OILREF" ], [ "R1", - 2020, - "fall", + "spring", "night", - "E_NUCLEAR" + "E_NGCC" ], [ - "R1", - 2030, + "R2", "winter", - "night", - "S_OILREF" + "day", + "T_GSL" ], [ "R1", - 2020, "summer", "day", + "S_OILREF" + ], + [ + "R1", + "spring", + "night", "E_BATT" ], [ "R1", - 2020, - "summer", + "spring", "day", - "T_BLND" + "E_BATT" ], [ - "R2", - 2025, - "fall", + "R1", + "winter", "day", - "T_GSL" + "E_SOLPV" ], [ - "R2-R1", - 2020, + "R1", "fall", - "night", - "E_TRANS" + "day", + "R_NGH" ], [ "R1", - 2025, "fall", "day", - "T_EV" + "E_NUCLEAR" ], [ "R1", - 2030, - "summer", - "day", + "spring", + "night", "T_GSL" ], [ "R1", - 2030, "fall", "night", - "E_SOLPV" + "R_EH" ], [ "R1", - 2020, - "summer", - "day", - "E_NGCC" + "fall", + "night", + "E_SOLPV" ], [ "R1", - 2030, "summer", "night", + "E_NUCLEAR" + ], + [ + "R1", + "fall", + "day", "E_SOLPV" ], [ "R2", - 2020, "fall", - "night", - "E_BATT" + "day", + "T_BLND" ], [ "R1", - 2030, - "winter", + "fall", "day", - "T_GSL" + "T_EV" + ], + [ + "R1", + "summer", + "day", + "E_NGCC" ] ], "capacity_var_rptv": [ @@ -40015,6 +37135,7 @@ "limit_new_capacity_share_constraint_rggv": [], "limit_resource_constraint_rt": [], "limit_seasonal_capacity_factor_constraint_rpst": [], + "limit_seasonal_capacity_factor_constraint_rst": [], "limit_storage_fraction_constraint_rpsdtv": [ [ "R1", @@ -40033,6 +37154,112 @@ "E_BATT", 2020, "e" + ], + [ + "R1", + 2030, + "winter", + "day", + "E_BATT", + 2020, + "e" + ], + [ + "R1", + 2030, + "winter", + "day", + "E_BATT", + 2025, + "e" + ], + [ + "R2", + 2025, + "summer", + "day", + "E_BATT", + 2025, + "e" + ], + [ + "R1", + 2025, + "winter", + "day", + "E_BATT", + 2020, + "e" + ], + [ + "R2", + 2025, + "summer", + "day", + "E_BATT", + 2020, + "e" + ], + [ + "R2", + 2030, + "summer", + "day", + "E_BATT", + 2030, + "e" + ], + [ + "R2", + 2030, + "summer", + "day", + "E_BATT", + 2025, + "e" + ], + [ + "R2", + 2030, + "summer", + "day", + "E_BATT", + 2020, + "e" + ], + [ + "R1", + 2020, + "winter", + "day", + "E_BATT", + 2020, + "e" + ], + [ + "R1", + 2030, + "winter", + "day", + "E_BATT", + 2030, + "e" + ] + ], + "limit_storage_fraction_param_rsdt": [ + [ + "R1", + "winter", + "day", + "E_BATT", + "e" + ], + [ + "R2", + "summer", + "day", + "E_BATT", + "e" ] ], "limit_tech_input_split_annual_constraint_rpitv": [], @@ -45348,17 +42575,12 @@ 2030 ], "time_season": [ - 2025, - 2020, - 2030 - ], - "time_season_all": [ "summer", "fall", "spring", "winter" ], - "time_season_to_sequential": [], + "time_season_sequential": [], "time_sequencing": [ "seasonal_timeslices" ], diff --git a/tests/testing_data/utopia_data.sql b/tests/testing_data/utopia_data.sql index 8e99da42a..691376dd1 100644 --- a/tests/testing_data/utopia_data.sql +++ b/tests/testing_data/utopia_data.sql @@ -1,111 +1,45 @@ -REPLACE INTO "capacity_factor_process" VALUES('utopia',2000,'inter','day','E31',2000,0.2753,''); -REPLACE INTO "capacity_factor_process" VALUES('utopia',2000,'inter','night','E31',2000,0.2753,''); -REPLACE INTO "capacity_factor_process" VALUES('utopia',2000,'winter','day','E31',2000,0.2753,''); -REPLACE INTO "capacity_factor_process" VALUES('utopia',2000,'winter','night','E31',2000,0.2753,''); -REPLACE INTO "capacity_factor_process" VALUES('utopia',2000,'summer','day','E31',2000,0.2753,''); -REPLACE INTO "capacity_factor_process" VALUES('utopia',2000,'summer','night','E31',2000,0.2753,''); -REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'inter','day','E31',2000,0.2753,''); -REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'inter','night','E31',2000,0.2753,''); -REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'winter','day','E31',2000,0.2753,''); -REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'winter','night','E31',2000,0.2753,''); -REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'summer','day','E31',2000,0.2753,''); -REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'summer','night','E31',2000,0.2753,''); -REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'inter','day','E31',2010,0.2756,''); -REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'inter','night','E31',2010,0.2756,''); -REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'winter','day','E31',2010,0.2756,''); -REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'winter','night','E31',2010,0.2756,''); -REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'summer','day','E31',2010,0.2756,''); -REPLACE INTO "capacity_factor_process" VALUES('utopia',2010,'summer','night','E31',2010,0.2756,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E01',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E01',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E01',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E01',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E01',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E01',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E21',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E21',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E21',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E21',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E21',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E21',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E31',0.275,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E31',0.275,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E31',0.275,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E31',0.275,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E31',0.275,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E31',0.275,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E51',0.17,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E51',0.17,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E51',0.17,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E51',0.17,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E51',0.17,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E51',0.17,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','day','E70',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'inter','night','E70',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','day','E70',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'winter','night','E70',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','day','E70',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',1990,'summer','night','E70',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E01',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E01',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E01',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E01',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E01',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E01',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E21',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E21',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E21',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E21',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E21',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E21',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E31',0.275,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E31',0.275,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E31',0.275,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E31',0.275,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E31',0.275,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E31',0.275,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E51',0.17,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E51',0.17,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E51',0.17,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E51',0.17,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E51',0.17,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E51',0.17,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','day','E70',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'inter','night','E70',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','day','E70',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'winter','night','E70',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','day','E70',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2000,'summer','night','E70',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E01',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E01',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E01',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E01',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E01',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E01',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E21',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E21',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E21',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E21',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E21',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E21',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E31',0.275,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E31',0.275,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E31',0.275,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E31',0.275,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E31',0.275,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E31',0.275,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E51',0.17,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E51',0.17,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E51',0.17,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E51',0.17,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E51',0.17,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E51',0.17,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','day','E70',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'inter','night','E70',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','day','E70',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'winter','night','E70',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','day','E70',0.8,''); -REPLACE INTO "capacity_factor_tech" VALUES('utopia',2010,'summer','night','E70',0.8,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia','inter','day','E31',2000,0.2753,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia','inter','night','E31',2000,0.2753,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia','winter','day','E31',2000,0.2753,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia','winter','night','E31',2000,0.2753,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia','summer','day','E31',2000,0.2753,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia','summer','night','E31',2000,0.2753,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia','inter','day','E31',2010,0.2756,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia','inter','night','E31',2010,0.2756,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia','winter','day','E31',2010,0.2756,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia','winter','night','E31',2010,0.2756,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia','summer','day','E31',2010,0.2756,''); +REPLACE INTO "capacity_factor_process" VALUES('utopia','summer','night','E31',2010,0.2756,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','inter','day','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','inter','night','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','winter','day','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','winter','night','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','summer','day','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','summer','night','E01',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','inter','day','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','inter','night','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','winter','day','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','winter','night','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','summer','day','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','summer','night','E21',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','inter','day','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','inter','night','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','winter','day','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','winter','night','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','summer','day','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','summer','night','E31',0.275,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','inter','day','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','inter','night','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','winter','day','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','winter','night','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','summer','day','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','summer','night','E51',0.17,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','inter','day','E70',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','inter','night','E70',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','winter','day','E70',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','winter','night','E70',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','summer','day','E70',0.8,''); +REPLACE INTO "capacity_factor_tech" VALUES('utopia','summer','night','E70',0.8,''); REPLACE INTO "capacity_to_activity" VALUES('utopia','E01',31.54,'PJ / (GW * year)',''); REPLACE INTO "capacity_to_activity" VALUES('utopia','E21',31.54,'PJ / (GW * year)',''); REPLACE INTO "capacity_to_activity" VALUES('utopia','E31',31.54,'PJ / (GW * year)',''); @@ -315,36 +249,16 @@ REPLACE INTO "demand" VALUES('utopia',2010,'RL',12.6,'PJ',''); REPLACE INTO "demand" VALUES('utopia',1990,'TX',5.2,'PJ',''); REPLACE INTO "demand" VALUES('utopia',2000,'TX',7.8,'PJ',''); REPLACE INTO "demand" VALUES('utopia',2010,'TX',11.69,'PJ',''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','day','RH',0.12,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','night','RH',0.06,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','day','RH',0.5467,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','night','RH',0.2733,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','day','RL',0.15,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',1990,'inter','night','RL',0.05,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',1990,'summer','day','RL',0.15,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',1990,'summer','night','RL',0.05,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','day','RL',0.5,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',1990,'winter','night','RL',0.1,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','day','RH',0.12,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','night','RH',0.06,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','day','RH',0.5467,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','night','RH',0.2733,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','day','RL',0.15,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',2000,'inter','night','RL',0.05,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',2000,'summer','day','RL',0.15,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',2000,'summer','night','RL',0.05,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','day','RL',0.5,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',2000,'winter','night','RL',0.1,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','day','RH',0.12,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','night','RH',0.06,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','day','RH',0.5467,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','night','RH',0.2733,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','day','RL',0.15,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',2010,'inter','night','RL',0.05,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',2010,'summer','day','RL',0.15,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',2010,'summer','night','RL',0.05,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','day','RL',0.5,''); -REPLACE INTO "demand_specific_distribution" VALUES('utopia',2010,'winter','night','RL',0.1,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia','inter','day','RH',0.12,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia','inter','night','RH',0.06,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia','winter','day','RH',0.5467,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia','winter','night','RH',0.2733,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia','inter','day','RL',0.15,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia','inter','night','RL',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia','summer','day','RL',0.15,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia','summer','night','RL',0.05,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia','winter','day','RL',0.5,''); +REPLACE INTO "demand_specific_distribution" VALUES('utopia','winter','night','RL',0.1,''); REPLACE INTO "efficiency" VALUES('utopia','ethos','IMPDSL1',1990,'DSL',1.0,'PJ / (PJ)',''); REPLACE INTO "efficiency" VALUES('utopia','ethos','IMPGSL1',1990,'GSL',1.0,'PJ / (PJ)',''); REPLACE INTO "efficiency" VALUES('utopia','ethos','IMPHCO1',1990,'HCO',1.0,'PJ / (PJ)',''); @@ -479,7 +393,6 @@ REPLACE INTO "limit_tech_output_split" VALUES('utopia',2010,'SRE','DSL','ge',0.7 REPLACE INTO "limit_tech_output_split" VALUES('utopia',1990,'SRE','GSL','ge',0.3,''); REPLACE INTO "limit_tech_output_split" VALUES('utopia',2000,'SRE','GSL','ge',0.3,''); REPLACE INTO "limit_tech_output_split" VALUES('utopia',2010,'SRE','GSL','ge',0.3,''); -REPLACE INTO "metadata" VALUES('days_per_period',365,'count of days in each period'); REPLACE INTO "metadata" VALUES('DB_MAJOR',4,''); REPLACE INTO "metadata" VALUES('DB_MINOR',0,''); REPLACE INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); @@ -488,9 +401,6 @@ REPLACE INTO "operator" VALUES('e','equal to'); REPLACE INTO "operator" VALUES('le','less than or equal to'); REPLACE INTO "operator" VALUES('ge','greater than or equal to'); REPLACE INTO "region" VALUES('utopia',NULL); -REPLACE INTO "season_label" VALUES('inter',NULL); -REPLACE INTO "season_label" VALUES('summer',NULL); -REPLACE INTO "season_label" VALUES('winter',NULL); REPLACE INTO "sector_label" VALUES('supply',NULL); REPLACE INTO "sector_label" VALUES('electric',NULL); REPLACE INTO "sector_label" VALUES('transport',NULL); @@ -519,8 +429,8 @@ REPLACE INTO "technology" VALUES('TXG','p','transport','petroleum','',0,0,0,0,0, REPLACE INTO "technology_type" VALUES('p','production technology'); REPLACE INTO "technology_type" VALUES('pb','baseload production technology'); REPLACE INTO "technology_type" VALUES('ps','storage production technology'); -REPLACE INTO "time_of_day" VALUES(1,'day'); -REPLACE INTO "time_of_day" VALUES(2,'night'); +REPLACE INTO "time_of_day" VALUES(1,'day',16,NULL); +REPLACE INTO "time_of_day" VALUES(2,'night',8,NULL); REPLACE INTO "time_period" VALUES(1,1960,'e'); REPLACE INTO "time_period" VALUES(2,1970,'e'); REPLACE INTO "time_period" VALUES(3,1980,'e'); @@ -530,30 +440,6 @@ REPLACE INTO "time_period" VALUES(6,2010,'f'); REPLACE INTO "time_period" VALUES(7,2020,'f'); REPLACE INTO "time_period_type" VALUES('e','existing vintages'); REPLACE INTO "time_period_type" VALUES('f','future'); -REPLACE INTO "time_season" VALUES(1990,1,'inter',NULL); -REPLACE INTO "time_season" VALUES(1990,2,'summer',NULL); -REPLACE INTO "time_season" VALUES(1990,3,'winter',NULL); -REPLACE INTO "time_season" VALUES(2000,1,'inter',NULL); -REPLACE INTO "time_season" VALUES(2000,2,'summer',NULL); -REPLACE INTO "time_season" VALUES(2000,3,'winter',NULL); -REPLACE INTO "time_season" VALUES(2010,1,'inter',NULL); -REPLACE INTO "time_season" VALUES(2010,2,'summer',NULL); -REPLACE INTO "time_season" VALUES(2010,3,'winter',NULL); -REPLACE INTO "time_segment_fraction" VALUES(1990,'inter','day',0.1667,'# I-D'); -REPLACE INTO "time_segment_fraction" VALUES(1990,'inter','night',0.0833,'# I-N'); -REPLACE INTO "time_segment_fraction" VALUES(1990,'summer','day',0.1667,'# S-D'); -REPLACE INTO "time_segment_fraction" VALUES(1990,'summer','night',0.0833,'# S-N'); -REPLACE INTO "time_segment_fraction" VALUES(1990,'winter','day',0.3333,'# W-D'); -REPLACE INTO "time_segment_fraction" VALUES(1990,'winter','night',0.1667,'# W-N'); -REPLACE INTO "time_segment_fraction" VALUES(2000,'inter','day',0.1667,'# I-D'); -REPLACE INTO "time_segment_fraction" VALUES(2000,'inter','night',0.0833,'# I-N'); -REPLACE INTO "time_segment_fraction" VALUES(2000,'summer','day',0.1667,'# S-D'); -REPLACE INTO "time_segment_fraction" VALUES(2000,'summer','night',0.0833,'# S-N'); -REPLACE INTO "time_segment_fraction" VALUES(2000,'winter','day',0.3333,'# W-D'); -REPLACE INTO "time_segment_fraction" VALUES(2000,'winter','night',0.1667,'# W-N'); -REPLACE INTO "time_segment_fraction" VALUES(2010,'inter','day',0.1667,'# I-D'); -REPLACE INTO "time_segment_fraction" VALUES(2010,'inter','night',0.0833,'# I-N'); -REPLACE INTO "time_segment_fraction" VALUES(2010,'summer','day',0.1667,'# S-D'); -REPLACE INTO "time_segment_fraction" VALUES(2010,'summer','night',0.0833,'# S-N'); -REPLACE INTO "time_segment_fraction" VALUES(2010,'winter','day',0.3333,'# W-D'); -REPLACE INTO "time_segment_fraction" VALUES(2010,'winter','night',0.1667,'# W-N'); +REPLACE INTO "time_season" VALUES(1,'inter',0.25,NULL); +REPLACE INTO "time_season" VALUES(2,'summer',0.25,NULL); +REPLACE INTO "time_season" VALUES(3,'winter',0.5,NULL); diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 2b10f202f..a69112919 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -5679,1516 +5679,436 @@ 2000 ] ], - "capacity_factor_rpsdt": [ + "capacity_factor_rsdt": [ [ "utopia", - 2000, "inter", "day", "RL1" ], [ "utopia", - 2010, "winter", "day", "E51" ], [ "utopia", - 2000, "winter", "night", "E01" ], [ "utopia", - 2000, "winter", "night", "E51" ], [ "utopia", - 2000, "summer", "day", "TXG" ], [ "utopia", - 2010, "winter", "night", "TXG" ], [ "utopia", - 2000, "summer", "day", "TXD" ], [ "utopia", - 1990, "winter", "night", "TXE" ], [ "utopia", - 2010, "winter", "night", "TXD" ], [ "utopia", - 2010, "winter", "day", "TXG" ], [ "utopia", - 1990, "winter", "day", "RL1" ], [ "utopia", - 2000, "summer", "day", "E31" ], [ "utopia", - 2010, "winter", "night", "E31" ], [ "utopia", - 2000, "summer", "day", "E21" ], [ "utopia", - 2010, "summer", "night", "E70" ], [ "utopia", - 2010, "winter", "day", "SRE" ], [ "utopia", - 2010, "winter", "night", "E21" ], [ "utopia", - 2000, - "winter", - "night", - "SRE" - ], - [ - "utopia", - 2010, - "summer", - "day", - "E70" - ], - [ - "utopia", - 1990, - "inter", - "night", - "E70" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHO" - ], - [ - "utopia", - 1990, - "summer", - "night", - "E01" - ], - [ - "utopia", - 2000, - "summer", - "night", - "E70" - ], - [ - "utopia", - 1990, - "inter", - "day", - "E70" - ], - [ - "utopia", - 1990, - "summer", - "day", - "E01" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXE" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RL1" - ], - [ - "utopia", - 1990, - "summer", - "day", - "E51" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHO" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHE" - ], - [ - "utopia", - 1990, - "summer", - "night", - "SRE" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RHO" - ], - [ - "utopia", - 2010, - "inter", - "day", - "E70" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHE" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RHE" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RL1" - ], - [ - "utopia", - 2000, - "inter", - "night", - "E70" - ], - [ - "utopia", - 1990, - "summer", - "day", - "SRE" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHE" - ], - [ - "utopia", - 1990, - "inter", - "night", - "E51" - ], - [ - "utopia", - 1990, - "inter", - "day", - "RHE" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RL1" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXG" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXD" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXE" - ], - [ - "utopia", - 2000, - "inter", - "day", - "E70" - ], - [ - "utopia", - 2000, - "summer", - "day", - "E01" - ], - [ - "utopia", - 2010, - "winter", - "night", - "E01" - ], - [ - "utopia", - 2000, - "summer", - "night", - "E51" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHO" - ], - [ - "utopia", - 2010, "winter", - "day", - "E01" - ], - [ - "utopia", - 2000, - "summer", - "day", - "E51" - ], - [ - "utopia", - 2010, - "winter", - "night", - "E51" - ], - [ - "utopia", - 2010, - "summer", - "night", - "E31" - ], - [ - "utopia", - 2010, - "summer", - "night", - "E21" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXE" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXD" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXG" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXD" - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHE" - ], - [ - "utopia", - 1990, - "winter", - "day", - "E70" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXG" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXD" - ], - [ - "utopia", - 2010, - "summer", - "day", - "E21" - ], - [ - "utopia", - 2010, - "summer", - "day", - "E31" - ], - [ - "utopia", - 1990, - "inter", - "night", - "E31" - ], - [ - "utopia", - 1990, - "inter", - "night", - "E21" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHE" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RL1" - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXG" - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXD" - ], - [ - "utopia", - 2000, - "summer", - "night", - "E31" - ], - [ - "utopia", - 2000, - "summer", - "night", - "E21" - ], - [ - "utopia", - 2000, - "summer", - "day", - "SRE" - ], - [ - "utopia", - 2010, - "winter", - "night", - "SRE" - ], - [ - "utopia", - 1990, - "inter", - "day", - "E31" - ], - [ - "utopia", - 1990, - "inter", - "day", - "E21" - ], - [ - "utopia", - 2000, - "inter", - "night", - "E51" - ], - [ - "utopia", - 2000, - "inter", - "day", - "RHE" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHO" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHO" - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXD" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXG" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXE" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXD" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXE" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHE" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RL1" - ], - [ - "utopia", - 2010, - "inter", - "day", - "E31" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXE" - ], - [ - "utopia", - 2000, - "winter", - "day", - "E70" - ], - [ - "utopia", - 2010, - "inter", - "day", - "E21" - ], - [ - "utopia", - 2000, - "inter", - "night", - "E31" - ], - [ - "utopia", - 2000, - "inter", - "night", - "E21" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RL1" - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXG" - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXD" - ], - [ - "utopia", - 2000, - "inter", - "day", - "E31" - ], - [ - "utopia", - 2000, - "inter", - "day", - "E21" - ], - [ - "utopia", - 2010, - "inter", - "night", - "E70" - ], - [ - "utopia", - 2010, - "summer", - "night", - "E01" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXG" - ], - [ - "utopia", - 2010, - "summer", - "night", - "E51" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXD" - ], - [ - "utopia", - 1990, - "summer", - "night", - "E70" - ], - [ - "utopia", - 1990, - "inter", - "night", - "E01" - ], - [ - "utopia", - 1990, - "winter", - "day", - "E31" - ], - [ - "utopia", - 1990, - "winter", - "day", - "E21" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHO" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHE" - ], - [ - "utopia", - 2010, - "summer", - "day", - "E51" - ], - [ - "utopia", - 2000, - "summer", - "night", - "E01" - ], - [ - "utopia", - 1990, - "inter", - "day", - "E01" - ], - [ - "utopia", - 2010, - "summer", - "night", - "SRE" - ], - [ - "utopia", - 1990, - "inter", - "day", - "E51" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RL1" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHE" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXG" - ], - [ - "utopia", - 1990, - "winter", - "night", - "E70" - ], - [ - "utopia", - 2010, - "summer", - "day", - "SRE" - ], - [ - "utopia", - 1990, - "inter", - "night", - "SRE" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXG" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXD" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXE" - ], - [ - "utopia", - 2000, - "summer", - "night", - "SRE" - ], - [ - "utopia", - 2010, - "inter", - "day", - "E51" - ], - [ - "utopia", - 2000, - "inter", - "night", - "E01" - ], - [ - "utopia", - 2000, - "winter", - "day", - "E31" - ], - [ - "utopia", - 2000, - "winter", - "day", - "E21" - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHO" - ], - [ - "utopia", - 1990, - "inter", - "day", - "SRE" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHO" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RL1" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXG" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXE" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXD" - ], - [ - "utopia", - 2000, - "inter", - "day", - "E01" - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXG" - ], - [ - "utopia", - 2010, - "winter", - "day", - "E70" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXE" - ], - [ - "utopia", - 2000, - "inter", - "day", - "E51" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHE" - ], - [ - "utopia", - 2000, - "summer", - "day", - "RL1" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RL1" - ], - [ - "utopia", - 2010, - "inter", - "night", - "E31" - ], - [ - "utopia", - 2010, - "inter", - "night", - "E21" - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXE" - ], - [ - "utopia", - 2000, - "winter", - "night", - "E70" - ], - [ - "utopia", - 2010, - "inter", - "day", - "SRE" - ], - [ - "utopia", - 2000, - "inter", - "night", - "SRE" - ], - [ - "utopia", - 1990, - "winter", - "day", - "E01" - ], - [ - "utopia", - 1990, - "summer", - "night", - "E31" - ], - [ - "utopia", - 1990, - "winter", - "day", - "E51" - ], - [ - "utopia", - 2000, - "inter", - "day", - "SRE" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXG" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RL1" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXD" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXE" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHE" - ], - [ - "utopia", - 1990, - "winter", - "night", - "E31" - ], - [ - "utopia", - 1990, - "winter", - "night", - "E21" - ], - [ - "utopia", - 1990, - "winter", - "day", - "SRE" - ], - [ - "utopia", - 2010, - "summer", - "day", - "E01" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHE" - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXE" - ], - [ - "utopia", - 2000, - "winter", - "day", - "E01" + "night", + "SRE" ], [ "utopia", - 1990, "summer", "day", "E70" ], [ "utopia", - 2000, + "inter", + "night", + "E70" + ], + [ + "utopia", "winter", "day", - "E51" + "RHO" ], [ "utopia", - 2010, "summer", "night", - "RHO" + "E01" ], [ "utopia", - 1990, - "winter", + "inter", "day", - "TXE" + "E70" ], [ "utopia", - 2010, - "winter", + "summer", "day", - "TXD" + "E01" ], [ "utopia", - 2000, - "winter", - "night", - "TXG" + "summer", + "day", + "E51" ], [ "utopia", - 2010, "inter", "night", - "E01" + "RHO" ], [ "utopia", - 2000, - "winter", + "summer", "night", - "TXD" + "RHE" ], [ "utopia", - 2010, - "winter", - "day", - "E31" + "summer", + "night", + "SRE" ], [ "utopia", - 2010, - "winter", - "day", - "E21" + "summer", + "night", + "RHO" ], [ "utopia", - 2010, "summer", "day", - "RHO" + "RHE" ], [ "utopia", - 1990, "inter", "night", - "RHO" + "RHE" ], [ "utopia", - 2010, "inter", - "day", - "E01" + "night", + "RL1" ], [ "utopia", - 1990, "summer", - "night", - "RHE" + "day", + "SRE" ], [ "utopia", - 2010, "inter", "night", "E51" ], [ "utopia", - 2010, + "inter", + "day", + "RHE" + ], + [ + "utopia", "summer", "night", "RL1" ], [ "utopia", - 2000, - "winter", + "summer", "night", - "E31" + "TXG" ], [ "utopia", - 2000, - "winter", + "summer", "night", - "E21" + "TXD" ], [ "utopia", - 2000, "summer", "night", - "RHO" + "TXE" + ], + [ + "utopia", + "summer", + "night", + "E51" ], [ "utopia", - 2000, "winter", - "day", - "SRE" + "night", + "RHO" ], [ "utopia", - 1990, - "inter", + "winter", "day", - "RHO" + "E01" ], [ "utopia", - 1990, "summer", "night", - "E51" + "E31" ], [ "utopia", - 1990, "summer", - "day", - "RHE" + "night", + "E21" ], [ "utopia", - 2010, "summer", "day", - "RL1" + "TXE" ], [ "utopia", - 2010, - "summer", - "day", - "TXE" + "inter", + "night", + "TXG" ], [ "utopia", - 2000, - "summer", - "day", - "E70" + "inter", + "night", + "TXD" ], [ "utopia", - 2010, "winter", - "night", + "day", "E70" ], [ "utopia", - 2000, - "summer", + "inter", "night", - "RL1" + "E31" ], [ "utopia", - 2010, "inter", "night", - "SRE" + "E21" ], [ "utopia", - 2000, "winter", - "day", - "TXE" + "night", + "RL1" ], [ "utopia", - 1990, - "summer", - "night", + "inter", + "day", "TXG" ], [ "utopia", - 1990, "inter", "day", - "RL1" + "TXD" ], [ "utopia", - 1990, - "summer", - "night", - "TXD" + "inter", + "day", + "E31" ], [ "utopia", - 2010, "inter", "day", - "RHO" + "E21" ], [ "utopia", - 1990, "winter", - "night", - "E01" + "day", + "RHE" ], [ "utopia", - 2000, - "inter", - "night", - "RHO" + "winter", + "day", + "TXE" ], [ "utopia", - 1990, "winter", - "night", - "E51" + "day", + "TXD" ], [ "utopia", - 1990, - "summer", + "inter", "night", - "E21" + "E01" ], [ "utopia", - 1990, - "summer", + "winter", "day", - "TXG" + "E31" ], [ "utopia", - 1990, - "summer", + "winter", "day", - "TXD" + "E21" ], [ "utopia", - 2010, - "inter", - "night", - "TXE" + "summer", + "day", + "RHO" ], [ "utopia", - 2010, "inter", "day", - "RL1" + "E01" ], [ "utopia", - 2010, "inter", "day", - "TXE" + "E51" ], [ "utopia", - 2000, - "inter", + "summer", "day", - "RHO" + "RL1" ], [ "utopia", - 1990, - "summer", - "day", - "E31" + "winter", + "night", + "E70" ], [ "utopia", - 1990, - "summer", - "day", - "E21" + "inter", + "night", + "SRE" ], [ "utopia", - 2000, - "summer", + "inter", "day", - "RHE" + "SRE" ], [ "utopia", - 2010, - "winter", + "inter", "night", - "RHE" + "TXE" ], [ "utopia", - 1990, "winter", "night", - "SRE" + "RHE" ], [ "utopia", - 1990, - "winter", + "inter", + "day", + "TXE" + ], + [ + "utopia", + "inter", "day", "RHO" ] @@ -22187,7 +21107,9 @@ "limit_new_capacity_share_constraint_rggv": [], "limit_resource_constraint_rt": [], "limit_seasonal_capacity_factor_constraint_rpst": [], + "limit_seasonal_capacity_factor_constraint_rst": [], "limit_storage_fraction_constraint_rpsdtv": [], + "limit_storage_fraction_param_rsdt": [], "limit_tech_input_split_annual_constraint_rpitv": [], "limit_tech_input_split_average_constraint_rpitv": [], "limit_tech_input_split_constraint_rpsditv": [], @@ -25184,16 +24106,11 @@ 1990 ], "time_season": [ - 2000, - 2010, - 1990 - ], - "time_season_all": [ "summer", "inter", "winter" ], - "time_season_to_sequential": [], + "time_season_sequential": [], "time_sequencing": [ "seasonal_timeslices" ], From 892f69287e8e0475a3cdb04f65fa47a76a710f4f Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 17 Mar 2026 11:30:46 -0400 Subject: [PATCH 503/587] updating all dependencies to latest version --- uv.lock | 1450 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 751 insertions(+), 699 deletions(-) diff --git a/uv.lock b/uv.lock index 03000af98..c2339a724 100644 --- a/uv.lock +++ b/uv.lock @@ -31,13 +31,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929, upload-time = "2024-07-26T18:15:02.05Z" }, ] +[[package]] +name = "annotated-doc" +version = "0.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" }, +] + [[package]] name = "babel" -version = "2.17.0" +version = "2.18.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/b2/51899539b6ceeeb420d40ed3cd4b7a40519404f9baf3d4ac99dc413a834b/babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d", size = 9959554, upload-time = "2026-02-01T12:30:56.078Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, + { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845, upload-time = "2026-02-01T12:30:53.445Z" }, ] [[package]] @@ -55,11 +64,11 @@ wheels = [ [[package]] name = "certifi" -version = "2026.1.4" +version = "2026.2.25" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" } +sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, + { url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" }, ] [[package]] @@ -73,59 +82,75 @@ wheels = [ [[package]] name = "charset-normalizer" -version = "3.4.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" }, - { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" }, - { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" }, - { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" }, - { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" }, - { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" }, - { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" }, - { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" }, - { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" }, - { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" }, - { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" }, - { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" }, - { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" }, - { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" }, - { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" }, - { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" }, - { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" }, - { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" }, - { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" }, - { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" }, - { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" }, - { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" }, - { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" }, - { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" }, - { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" }, - { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" }, - { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" }, - { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" }, - { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" }, - { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" }, - { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" }, - { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" }, - { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" }, - { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" }, - { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" }, - { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" }, - { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" }, - { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" }, - { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" }, - { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" }, - { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" }, - { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" }, - { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" }, - { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" }, - { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" }, - { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" }, - { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" }, - { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" }, - { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, +version = "3.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7b/60/e3bec1881450851b087e301bedc3daa9377a4d45f1c26aa90b0b235e38aa/charset_normalizer-3.4.6.tar.gz", hash = "sha256:1ae6b62897110aa7c79ea2f5dd38d1abca6db663687c0b1ad9aed6f6bae3d9d6", size = 143363, upload-time = "2026-03-15T18:53:25.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/62/c0815c992c9545347aeea7859b50dc9044d147e2e7278329c6e02ac9a616/charset_normalizer-3.4.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ef7fedc7a6ecbe99969cd09632516738a97eeb8bd7258bf8a0f23114c057dab", size = 295154, upload-time = "2026-03-15T18:50:50.88Z" }, + { url = "https://files.pythonhosted.org/packages/a8/37/bdca6613c2e3c58c7421891d80cc3efa1d32e882f7c4a7ee6039c3fc951a/charset_normalizer-3.4.6-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a4ea868bc28109052790eb2b52a9ab33f3aa7adc02f96673526ff47419490e21", size = 199191, upload-time = "2026-03-15T18:50:52.658Z" }, + { url = "https://files.pythonhosted.org/packages/6c/92/9934d1bbd69f7f398b38c5dae1cbf9cc672e7c34a4adf7b17c0a9c17d15d/charset_normalizer-3.4.6-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:836ab36280f21fc1a03c99cd05c6b7af70d2697e374c7af0b61ed271401a72a2", size = 218674, upload-time = "2026-03-15T18:50:54.102Z" }, + { url = "https://files.pythonhosted.org/packages/af/90/25f6ab406659286be929fd89ab0e78e38aa183fc374e03aa3c12d730af8a/charset_normalizer-3.4.6-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f1ce721c8a7dfec21fcbdfe04e8f68174183cf4e8188e0645e92aa23985c57ff", size = 215259, upload-time = "2026-03-15T18:50:55.616Z" }, + { url = "https://files.pythonhosted.org/packages/4e/ef/79a463eb0fff7f96afa04c1d4c51f8fc85426f918db467854bfb6a569ce3/charset_normalizer-3.4.6-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e28d62a8fc7a1fa411c43bd65e346f3bce9716dc51b897fbe930c5987b402d5", size = 207276, upload-time = "2026-03-15T18:50:57.054Z" }, + { url = "https://files.pythonhosted.org/packages/f7/72/d0426afec4b71dc159fa6b4e68f868cd5a3ecd918fec5813a15d292a7d10/charset_normalizer-3.4.6-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:530d548084c4a9f7a16ed4a294d459b4f229db50df689bfe92027452452943a0", size = 195161, upload-time = "2026-03-15T18:50:58.686Z" }, + { url = "https://files.pythonhosted.org/packages/bf/18/c82b06a68bfcb6ce55e508225d210c7e6a4ea122bfc0748892f3dc4e8e11/charset_normalizer-3.4.6-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:30f445ae60aad5e1f8bdbb3108e39f6fbc09f4ea16c815c66578878325f8f15a", size = 203452, upload-time = "2026-03-15T18:51:00.196Z" }, + { url = "https://files.pythonhosted.org/packages/44/d6/0c25979b92f8adafdbb946160348d8d44aa60ce99afdc27df524379875cb/charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ac2393c73378fea4e52aa56285a3d64be50f1a12395afef9cce47772f60334c2", size = 202272, upload-time = "2026-03-15T18:51:01.703Z" }, + { url = "https://files.pythonhosted.org/packages/2e/3d/7fea3e8fe84136bebbac715dd1221cc25c173c57a699c030ab9b8900cbb7/charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:90ca27cd8da8118b18a52d5f547859cc1f8354a00cd1e8e5120df3e30d6279e5", size = 195622, upload-time = "2026-03-15T18:51:03.526Z" }, + { url = "https://files.pythonhosted.org/packages/57/8a/d6f7fd5cb96c58ef2f681424fbca01264461336d2a7fc875e4446b1f1346/charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8e5a94886bedca0f9b78fecd6afb6629142fd2605aa70a125d49f4edc6037ee6", size = 220056, upload-time = "2026-03-15T18:51:05.269Z" }, + { url = "https://files.pythonhosted.org/packages/16/50/478cdda782c8c9c3fb5da3cc72dd7f331f031e7f1363a893cdd6ca0f8de0/charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:695f5c2823691a25f17bc5d5ffe79fa90972cc34b002ac6c843bb8a1720e950d", size = 203751, upload-time = "2026-03-15T18:51:06.858Z" }, + { url = "https://files.pythonhosted.org/packages/75/fc/cc2fcac943939c8e4d8791abfa139f685e5150cae9f94b60f12520feaa9b/charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:231d4da14bcd9301310faf492051bee27df11f2bc7549bc0bb41fef11b82daa2", size = 216563, upload-time = "2026-03-15T18:51:08.564Z" }, + { url = "https://files.pythonhosted.org/packages/a8/b7/a4add1d9a5f68f3d037261aecca83abdb0ab15960a3591d340e829b37298/charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a056d1ad2633548ca18ffa2f85c202cfb48b68615129143915b8dc72a806a923", size = 209265, upload-time = "2026-03-15T18:51:10.312Z" }, + { url = "https://files.pythonhosted.org/packages/6c/18/c094561b5d64a24277707698e54b7f67bd17a4f857bbfbb1072bba07c8bf/charset_normalizer-3.4.6-cp312-cp312-win32.whl", hash = "sha256:c2274ca724536f173122f36c98ce188fd24ce3dad886ec2b7af859518ce008a4", size = 144229, upload-time = "2026-03-15T18:51:11.694Z" }, + { url = "https://files.pythonhosted.org/packages/ab/20/0567efb3a8fd481b8f34f739ebddc098ed062a59fed41a8d193a61939e8f/charset_normalizer-3.4.6-cp312-cp312-win_amd64.whl", hash = "sha256:c8ae56368f8cc97c7e40a7ee18e1cedaf8e780cd8bc5ed5ac8b81f238614facb", size = 154277, upload-time = "2026-03-15T18:51:13.004Z" }, + { url = "https://files.pythonhosted.org/packages/15/57/28d79b44b51933119e21f65479d0864a8d5893e494cf5daab15df0247c17/charset_normalizer-3.4.6-cp312-cp312-win_arm64.whl", hash = "sha256:899d28f422116b08be5118ef350c292b36fc15ec2daeb9ea987c89281c7bb5c4", size = 142817, upload-time = "2026-03-15T18:51:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/1e/1d/4fdabeef4e231153b6ed7567602f3b68265ec4e5b76d6024cf647d43d981/charset_normalizer-3.4.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:11afb56037cbc4b1555a34dd69151e8e069bee82e613a73bef6e714ce733585f", size = 294823, upload-time = "2026-03-15T18:51:15.755Z" }, + { url = "https://files.pythonhosted.org/packages/47/7b/20e809b89c69d37be748d98e84dce6820bf663cf19cf6b942c951a3e8f41/charset_normalizer-3.4.6-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:423fb7e748a08f854a08a222b983f4df1912b1daedce51a72bd24fe8f26a1843", size = 198527, upload-time = "2026-03-15T18:51:17.177Z" }, + { url = "https://files.pythonhosted.org/packages/37/a6/4f8d27527d59c039dce6f7622593cdcd3d70a8504d87d09eb11e9fdc6062/charset_normalizer-3.4.6-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d73beaac5e90173ac3deb9928a74763a6d230f494e4bfb422c217a0ad8e629bf", size = 218388, upload-time = "2026-03-15T18:51:18.934Z" }, + { url = "https://files.pythonhosted.org/packages/f6/9b/4770ccb3e491a9bacf1c46cc8b812214fe367c86a96353ccc6daf87b01ec/charset_normalizer-3.4.6-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d60377dce4511655582e300dc1e5a5f24ba0cb229005a1d5c8d0cb72bb758ab8", size = 214563, upload-time = "2026-03-15T18:51:20.374Z" }, + { url = "https://files.pythonhosted.org/packages/2b/58/a199d245894b12db0b957d627516c78e055adc3a0d978bc7f65ddaf7c399/charset_normalizer-3.4.6-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:530e8cebeea0d76bdcf93357aa5e41336f48c3dc709ac52da2bb167c5b8271d9", size = 206587, upload-time = "2026-03-15T18:51:21.807Z" }, + { url = "https://files.pythonhosted.org/packages/7e/70/3def227f1ec56f5c69dfc8392b8bd63b11a18ca8178d9211d7cc5e5e4f27/charset_normalizer-3.4.6-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:a26611d9987b230566f24a0a125f17fe0de6a6aff9f25c9f564aaa2721a5fb88", size = 194724, upload-time = "2026-03-15T18:51:23.508Z" }, + { url = "https://files.pythonhosted.org/packages/58/ab/9318352e220c05efd31c2779a23b50969dc94b985a2efa643ed9077bfca5/charset_normalizer-3.4.6-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:34315ff4fc374b285ad7f4a0bf7dcbfe769e1b104230d40f49f700d4ab6bbd84", size = 202956, upload-time = "2026-03-15T18:51:25.239Z" }, + { url = "https://files.pythonhosted.org/packages/75/13/f3550a3ac25b70f87ac98c40d3199a8503676c2f1620efbf8d42095cfc40/charset_normalizer-3.4.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5f8ddd609f9e1af8c7bd6e2aca279c931aefecd148a14402d4e368f3171769fd", size = 201923, upload-time = "2026-03-15T18:51:26.682Z" }, + { url = "https://files.pythonhosted.org/packages/1b/db/c5c643b912740b45e8eec21de1bbab8e7fc085944d37e1e709d3dcd9d72f/charset_normalizer-3.4.6-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:80d0a5615143c0b3225e5e3ef22c8d5d51f3f72ce0ea6fb84c943546c7b25b6c", size = 195366, upload-time = "2026-03-15T18:51:28.129Z" }, + { url = "https://files.pythonhosted.org/packages/5a/67/3b1c62744f9b2448443e0eb160d8b001c849ec3fef591e012eda6484787c/charset_normalizer-3.4.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:92734d4d8d187a354a556626c221cd1a892a4e0802ccb2af432a1d85ec012194", size = 219752, upload-time = "2026-03-15T18:51:29.556Z" }, + { url = "https://files.pythonhosted.org/packages/f6/98/32ffbaf7f0366ffb0445930b87d103f6b406bc2c271563644bde8a2b1093/charset_normalizer-3.4.6-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:613f19aa6e082cf96e17e3ffd89383343d0d589abda756b7764cf78361fd41dc", size = 203296, upload-time = "2026-03-15T18:51:30.921Z" }, + { url = "https://files.pythonhosted.org/packages/41/12/5d308c1bbe60cabb0c5ef511574a647067e2a1f631bc8634fcafaccd8293/charset_normalizer-3.4.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:2b1a63e8224e401cafe7739f77efd3f9e7f5f2026bda4aead8e59afab537784f", size = 215956, upload-time = "2026-03-15T18:51:32.399Z" }, + { url = "https://files.pythonhosted.org/packages/53/e9/5f85f6c5e20669dbe56b165c67b0260547dea97dba7e187938833d791687/charset_normalizer-3.4.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6cceb5473417d28edd20c6c984ab6fee6c6267d38d906823ebfe20b03d607dc2", size = 208652, upload-time = "2026-03-15T18:51:34.214Z" }, + { url = "https://files.pythonhosted.org/packages/f1/11/897052ea6af56df3eef3ca94edafee410ca699ca0c7b87960ad19932c55e/charset_normalizer-3.4.6-cp313-cp313-win32.whl", hash = "sha256:d7de2637729c67d67cf87614b566626057e95c303bc0a55ffe391f5205e7003d", size = 143940, upload-time = "2026-03-15T18:51:36.15Z" }, + { url = "https://files.pythonhosted.org/packages/a1/5c/724b6b363603e419829f561c854b87ed7c7e31231a7908708ac086cdf3e2/charset_normalizer-3.4.6-cp313-cp313-win_amd64.whl", hash = "sha256:572d7c822caf521f0525ba1bce1a622a0b85cf47ffbdae6c9c19e3b5ac3c4389", size = 154101, upload-time = "2026-03-15T18:51:37.876Z" }, + { url = "https://files.pythonhosted.org/packages/01/a5/7abf15b4c0968e47020f9ca0935fb3274deb87cb288cd187cad92e8cdffd/charset_normalizer-3.4.6-cp313-cp313-win_arm64.whl", hash = "sha256:a4474d924a47185a06411e0064b803c68be044be2d60e50e8bddcc2649957c1f", size = 143109, upload-time = "2026-03-15T18:51:39.565Z" }, + { url = "https://files.pythonhosted.org/packages/25/6f/ffe1e1259f384594063ea1869bfb6be5cdb8bc81020fc36c3636bc8302a1/charset_normalizer-3.4.6-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:9cc6e6d9e571d2f863fa77700701dae73ed5f78881efc8b3f9a4398772ff53e8", size = 294458, upload-time = "2026-03-15T18:51:41.134Z" }, + { url = "https://files.pythonhosted.org/packages/56/60/09bb6c13a8c1016c2ed5c6a6488e4ffef506461aa5161662bd7636936fb1/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef5960d965e67165d75b7c7ffc60a83ec5abfc5c11b764ec13ea54fbef8b4421", size = 199277, upload-time = "2026-03-15T18:51:42.953Z" }, + { url = "https://files.pythonhosted.org/packages/00/50/dcfbb72a5138bbefdc3332e8d81a23494bf67998b4b100703fd15fa52d81/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b3694e3f87f8ac7ce279d4355645b3c878d24d1424581b46282f24b92f5a4ae2", size = 218758, upload-time = "2026-03-15T18:51:44.339Z" }, + { url = "https://files.pythonhosted.org/packages/03/b3/d79a9a191bb75f5aa81f3aaaa387ef29ce7cb7a9e5074ba8ea095cc073c2/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5d11595abf8dd942a77883a39d81433739b287b6aa71620f15164f8096221b30", size = 215299, upload-time = "2026-03-15T18:51:45.871Z" }, + { url = "https://files.pythonhosted.org/packages/76/7e/bc8911719f7084f72fd545f647601ea3532363927f807d296a8c88a62c0d/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7bda6eebafd42133efdca535b04ccb338ab29467b3f7bf79569883676fc628db", size = 206811, upload-time = "2026-03-15T18:51:47.308Z" }, + { url = "https://files.pythonhosted.org/packages/e2/40/c430b969d41dda0c465aa36cc7c2c068afb67177bef50905ac371b28ccc7/charset_normalizer-3.4.6-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:bbc8c8650c6e51041ad1be191742b8b421d05bbd3410f43fa2a00c8db87678e8", size = 193706, upload-time = "2026-03-15T18:51:48.849Z" }, + { url = "https://files.pythonhosted.org/packages/48/15/e35e0590af254f7df984de1323640ef375df5761f615b6225ba8deb9799a/charset_normalizer-3.4.6-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:22c6f0c2fbc31e76c3b8a86fba1a56eda6166e238c29cdd3d14befdb4a4e4815", size = 202706, upload-time = "2026-03-15T18:51:50.257Z" }, + { url = "https://files.pythonhosted.org/packages/5e/bd/f736f7b9cc5e93a18b794a50346bb16fbfd6b37f99e8f306f7951d27c17c/charset_normalizer-3.4.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7edbed096e4a4798710ed6bc75dcaa2a21b68b6c356553ac4823c3658d53743a", size = 202497, upload-time = "2026-03-15T18:51:52.012Z" }, + { url = "https://files.pythonhosted.org/packages/9d/ba/2cc9e3e7dfdf7760a6ed8da7446d22536f3d0ce114ac63dee2a5a3599e62/charset_normalizer-3.4.6-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:7f9019c9cb613f084481bd6a100b12e1547cf2efe362d873c2e31e4035a6fa43", size = 193511, upload-time = "2026-03-15T18:51:53.723Z" }, + { url = "https://files.pythonhosted.org/packages/9e/cb/5be49b5f776e5613be07298c80e1b02a2d900f7a7de807230595c85a8b2e/charset_normalizer-3.4.6-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:58c948d0d086229efc484fe2f30c2d382c86720f55cd9bc33591774348ad44e0", size = 220133, upload-time = "2026-03-15T18:51:55.333Z" }, + { url = "https://files.pythonhosted.org/packages/83/43/99f1b5dad345accb322c80c7821071554f791a95ee50c1c90041c157ae99/charset_normalizer-3.4.6-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:419a9d91bd238052642a51938af8ac05da5b3343becde08d5cdeab9046df9ee1", size = 203035, upload-time = "2026-03-15T18:51:56.736Z" }, + { url = "https://files.pythonhosted.org/packages/87/9a/62c2cb6a531483b55dddff1a68b3d891a8b498f3ca555fbcf2978e804d9d/charset_normalizer-3.4.6-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5273b9f0b5835ff0350c0828faea623c68bfa65b792720c453e22b25cc72930f", size = 216321, upload-time = "2026-03-15T18:51:58.17Z" }, + { url = "https://files.pythonhosted.org/packages/6e/79/94a010ff81e3aec7c293eb82c28f930918e517bc144c9906a060844462eb/charset_normalizer-3.4.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:0e901eb1049fdb80f5bd11ed5ea1e498ec423102f7a9b9e4645d5b8204ff2815", size = 208973, upload-time = "2026-03-15T18:51:59.998Z" }, + { url = "https://files.pythonhosted.org/packages/2a/57/4ecff6d4ec8585342f0c71bc03efaa99cb7468f7c91a57b105bcd561cea8/charset_normalizer-3.4.6-cp314-cp314-win32.whl", hash = "sha256:b4ff1d35e8c5bd078be89349b6f3a845128e685e751b6ea1169cf2160b344c4d", size = 144610, upload-time = "2026-03-15T18:52:02.213Z" }, + { url = "https://files.pythonhosted.org/packages/80/94/8434a02d9d7f168c25767c64671fead8d599744a05d6a6c877144c754246/charset_normalizer-3.4.6-cp314-cp314-win_amd64.whl", hash = "sha256:74119174722c4349af9708993118581686f343adc1c8c9c007d59be90d077f3f", size = 154962, upload-time = "2026-03-15T18:52:03.658Z" }, + { url = "https://files.pythonhosted.org/packages/46/4c/48f2cdbfd923026503dfd67ccea45c94fd8fe988d9056b468579c66ed62b/charset_normalizer-3.4.6-cp314-cp314-win_arm64.whl", hash = "sha256:e5bcc1a1ae744e0bb59641171ae53743760130600da8db48cbb6e4918e186e4e", size = 143595, upload-time = "2026-03-15T18:52:05.123Z" }, + { url = "https://files.pythonhosted.org/packages/31/93/8878be7569f87b14f1d52032946131bcb6ebbd8af3e20446bc04053dc3f1/charset_normalizer-3.4.6-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:ad8faf8df23f0378c6d527d8b0b15ea4a2e23c89376877c598c4870d1b2c7866", size = 314828, upload-time = "2026-03-15T18:52:06.831Z" }, + { url = "https://files.pythonhosted.org/packages/06/b6/fae511ca98aac69ecc35cde828b0a3d146325dd03d99655ad38fc2cc3293/charset_normalizer-3.4.6-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f5ea69428fa1b49573eef0cc44a1d43bebd45ad0c611eb7d7eac760c7ae771bc", size = 208138, upload-time = "2026-03-15T18:52:08.239Z" }, + { url = "https://files.pythonhosted.org/packages/54/57/64caf6e1bf07274a1e0b7c160a55ee9e8c9ec32c46846ce59b9c333f7008/charset_normalizer-3.4.6-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:06a7e86163334edfc5d20fe104db92fcd666e5a5df0977cb5680a506fe26cc8e", size = 224679, upload-time = "2026-03-15T18:52:10.043Z" }, + { url = "https://files.pythonhosted.org/packages/aa/cb/9ff5a25b9273ef160861b41f6937f86fae18b0792fe0a8e75e06acb08f1d/charset_normalizer-3.4.6-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e1f6e2f00a6b8edb562826e4632e26d063ac10307e80f7461f7de3ad8ef3f077", size = 223475, upload-time = "2026-03-15T18:52:11.854Z" }, + { url = "https://files.pythonhosted.org/packages/fc/97/440635fc093b8d7347502a377031f9605a1039c958f3cd18dcacffb37743/charset_normalizer-3.4.6-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:95b52c68d64c1878818687a473a10547b3292e82b6f6fe483808fb1468e2f52f", size = 215230, upload-time = "2026-03-15T18:52:13.325Z" }, + { url = "https://files.pythonhosted.org/packages/cd/24/afff630feb571a13f07c8539fbb502d2ab494019492aaffc78ef41f1d1d0/charset_normalizer-3.4.6-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:7504e9b7dc05f99a9bbb4525c67a2c155073b44d720470a148b34166a69c054e", size = 199045, upload-time = "2026-03-15T18:52:14.752Z" }, + { url = "https://files.pythonhosted.org/packages/e5/17/d1399ecdaf7e0498c327433e7eefdd862b41236a7e484355b8e0e5ebd64b/charset_normalizer-3.4.6-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:172985e4ff804a7ad08eebec0a1640ece87ba5041d565fff23c8f99c1f389484", size = 211658, upload-time = "2026-03-15T18:52:16.278Z" }, + { url = "https://files.pythonhosted.org/packages/b5/38/16baa0affb957b3d880e5ac2144caf3f9d7de7bc4a91842e447fbb5e8b67/charset_normalizer-3.4.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:4be9f4830ba8741527693848403e2c457c16e499100963ec711b1c6f2049b7c7", size = 210769, upload-time = "2026-03-15T18:52:17.782Z" }, + { url = "https://files.pythonhosted.org/packages/05/34/c531bc6ac4c21da9ddfddb3107be2287188b3ea4b53b70fc58f2a77ac8d8/charset_normalizer-3.4.6-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:79090741d842f564b1b2827c0b82d846405b744d31e84f18d7a7b41c20e473ff", size = 201328, upload-time = "2026-03-15T18:52:19.553Z" }, + { url = "https://files.pythonhosted.org/packages/fa/73/a5a1e9ca5f234519c1953608a03fe109c306b97fdfb25f09182babad51a7/charset_normalizer-3.4.6-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:87725cfb1a4f1f8c2fc9890ae2f42094120f4b44db9360be5d99a4c6b0e03a9e", size = 225302, upload-time = "2026-03-15T18:52:21.043Z" }, + { url = "https://files.pythonhosted.org/packages/ba/f6/cd782923d112d296294dea4bcc7af5a7ae0f86ab79f8fefbda5526b6cfc0/charset_normalizer-3.4.6-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:fcce033e4021347d80ed9c66dcf1e7b1546319834b74445f561d2e2221de5659", size = 211127, upload-time = "2026-03-15T18:52:22.491Z" }, + { url = "https://files.pythonhosted.org/packages/0e/c5/0b6898950627af7d6103a449b22320372c24c6feda91aa24e201a478d161/charset_normalizer-3.4.6-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:ca0276464d148c72defa8bb4390cce01b4a0e425f3b50d1435aa6d7a18107602", size = 222840, upload-time = "2026-03-15T18:52:24.113Z" }, + { url = "https://files.pythonhosted.org/packages/7d/25/c4bba773bef442cbdc06111d40daa3de5050a676fa26e85090fc54dd12f0/charset_normalizer-3.4.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:197c1a244a274bb016dd8b79204850144ef77fe81c5b797dc389327adb552407", size = 216890, upload-time = "2026-03-15T18:52:25.541Z" }, + { url = "https://files.pythonhosted.org/packages/35/1a/05dacadb0978da72ee287b0143097db12f2e7e8d3ffc4647da07a383b0b7/charset_normalizer-3.4.6-cp314-cp314t-win32.whl", hash = "sha256:2a24157fa36980478dd1770b585c0f30d19e18f4fb0c47c13aa568f871718579", size = 155379, upload-time = "2026-03-15T18:52:27.05Z" }, + { url = "https://files.pythonhosted.org/packages/5d/7a/d269d834cb3a76291651256f3b9a5945e81d0a49ab9f4a498964e83c0416/charset_normalizer-3.4.6-cp314-cp314t-win_amd64.whl", hash = "sha256:cd5e2801c89992ed8c0a3f0293ae83c159a60d9a5d685005383ef4caca77f2c4", size = 169043, upload-time = "2026-03-15T18:52:28.502Z" }, + { url = "https://files.pythonhosted.org/packages/23/06/28b29fba521a37a8932c6a84192175c34d49f84a6d4773fa63d05f9aff22/charset_normalizer-3.4.6-cp314-cp314t-win_arm64.whl", hash = "sha256:47955475ac79cc504ef2704b192364e51d0d473ad452caedd0002605f780101c", size = 148523, upload-time = "2026-03-15T18:52:29.956Z" }, + { url = "https://files.pythonhosted.org/packages/2a/68/687187c7e26cb24ccbd88e5069f5ef00eba804d36dde11d99aad0838ab45/charset_normalizer-3.4.6-py3-none-any.whl", hash = "sha256:947cf925bc916d90adba35a64c82aace04fa39b46b52d4630ece166655905a69", size = 61455, upload-time = "2026-03-15T18:53:23.833Z" }, ] [[package]] @@ -217,76 +242,86 @@ wheels = [ [[package]] name = "coverage" -version = "7.13.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/23/f9/e92df5e07f3fc8d4c7f9a0f146ef75446bf870351cd37b788cf5897f8079/coverage-7.13.1.tar.gz", hash = "sha256:b7593fe7eb5feaa3fbb461ac79aac9f9fc0387a5ca8080b0c6fe2ca27b091afd", size = 825862, upload-time = "2025-12-28T15:42:56.969Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/8a/87af46cccdfa78f53db747b09f5f9a21d5fc38d796834adac09b30a8ce74/coverage-7.13.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6f34591000f06e62085b1865c9bc5f7858df748834662a51edadfd2c3bfe0dd3", size = 218927, upload-time = "2025-12-28T15:40:52.814Z" }, - { url = "https://files.pythonhosted.org/packages/82/a8/6e22fdc67242a4a5a153f9438d05944553121c8f4ba70cb072af4c41362e/coverage-7.13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b67e47c5595b9224599016e333f5ec25392597a89d5744658f837d204e16c63e", size = 219288, upload-time = "2025-12-28T15:40:54.262Z" }, - { url = "https://files.pythonhosted.org/packages/d0/0a/853a76e03b0f7c4375e2ca025df45c918beb367f3e20a0a8e91967f6e96c/coverage-7.13.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3e7b8bd70c48ffb28461ebe092c2345536fb18bbbf19d287c8913699735f505c", size = 250786, upload-time = "2025-12-28T15:40:56.059Z" }, - { url = "https://files.pythonhosted.org/packages/ea/b4/694159c15c52b9f7ec7adf49d50e5f8ee71d3e9ef38adb4445d13dd56c20/coverage-7.13.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c223d078112e90dc0e5c4e35b98b9584164bea9fbbd221c0b21c5241f6d51b62", size = 253543, upload-time = "2025-12-28T15:40:57.585Z" }, - { url = "https://files.pythonhosted.org/packages/96/b2/7f1f0437a5c855f87e17cf5d0dc35920b6440ff2b58b1ba9788c059c26c8/coverage-7.13.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:794f7c05af0763b1bbd1b9e6eff0e52ad068be3b12cd96c87de037b01390c968", size = 254635, upload-time = "2025-12-28T15:40:59.443Z" }, - { url = "https://files.pythonhosted.org/packages/e9/d1/73c3fdb8d7d3bddd9473c9c6a2e0682f09fc3dfbcb9c3f36412a7368bcab/coverage-7.13.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0642eae483cc8c2902e4af7298bf886d605e80f26382124cddc3967c2a3df09e", size = 251202, upload-time = "2025-12-28T15:41:01.328Z" }, - { url = "https://files.pythonhosted.org/packages/66/3c/f0edf75dcc152f145d5598329e864bbbe04ab78660fe3e8e395f9fff010f/coverage-7.13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9f5e772ed5fef25b3de9f2008fe67b92d46831bd2bc5bdc5dd6bfd06b83b316f", size = 252566, upload-time = "2025-12-28T15:41:03.319Z" }, - { url = "https://files.pythonhosted.org/packages/17/b3/e64206d3c5f7dcbceafd14941345a754d3dbc78a823a6ed526e23b9cdaab/coverage-7.13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:45980ea19277dc0a579e432aef6a504fe098ef3a9032ead15e446eb0f1191aee", size = 250711, upload-time = "2025-12-28T15:41:06.411Z" }, - { url = "https://files.pythonhosted.org/packages/dc/ad/28a3eb970a8ef5b479ee7f0c484a19c34e277479a5b70269dc652b730733/coverage-7.13.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e4f18eca6028ffa62adbd185a8f1e1dd242f2e68164dba5c2b74a5204850b4cf", size = 250278, upload-time = "2025-12-28T15:41:08.285Z" }, - { url = "https://files.pythonhosted.org/packages/54/e3/c8f0f1a93133e3e1291ca76cbb63565bd4b5c5df63b141f539d747fff348/coverage-7.13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f8dca5590fec7a89ed6826fce625595279e586ead52e9e958d3237821fbc750c", size = 252154, upload-time = "2025-12-28T15:41:09.969Z" }, - { url = "https://files.pythonhosted.org/packages/d0/bf/9939c5d6859c380e405b19e736321f1c7d402728792f4c752ad1adcce005/coverage-7.13.1-cp312-cp312-win32.whl", hash = "sha256:ff86d4e85188bba72cfb876df3e11fa243439882c55957184af44a35bd5880b7", size = 221487, upload-time = "2025-12-28T15:41:11.468Z" }, - { url = "https://files.pythonhosted.org/packages/fa/dc/7282856a407c621c2aad74021680a01b23010bb8ebf427cf5eacda2e876f/coverage-7.13.1-cp312-cp312-win_amd64.whl", hash = "sha256:16cc1da46c04fb0fb128b4dc430b78fa2aba8a6c0c9f8eb391fd5103409a6ac6", size = 222299, upload-time = "2025-12-28T15:41:13.386Z" }, - { url = "https://files.pythonhosted.org/packages/10/79/176a11203412c350b3e9578620013af35bcdb79b651eb976f4a4b32044fa/coverage-7.13.1-cp312-cp312-win_arm64.whl", hash = "sha256:8d9bc218650022a768f3775dd7fdac1886437325d8d295d923ebcfef4892ad5c", size = 220941, upload-time = "2025-12-28T15:41:14.975Z" }, - { url = "https://files.pythonhosted.org/packages/a3/a4/e98e689347a1ff1a7f67932ab535cef82eb5e78f32a9e4132e114bbb3a0a/coverage-7.13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:cb237bfd0ef4d5eb6a19e29f9e528ac67ac3be932ea6b44fb6cc09b9f3ecff78", size = 218951, upload-time = "2025-12-28T15:41:16.653Z" }, - { url = "https://files.pythonhosted.org/packages/32/33/7cbfe2bdc6e2f03d6b240d23dc45fdaf3fd270aaf2d640be77b7f16989ab/coverage-7.13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1dcb645d7e34dcbcc96cd7c132b1fc55c39263ca62eb961c064eb3928997363b", size = 219325, upload-time = "2025-12-28T15:41:18.609Z" }, - { url = "https://files.pythonhosted.org/packages/59/f6/efdabdb4929487baeb7cb2a9f7dac457d9356f6ad1b255be283d58b16316/coverage-7.13.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3d42df8201e00384736f0df9be2ced39324c3907607d17d50d50116c989d84cd", size = 250309, upload-time = "2025-12-28T15:41:20.629Z" }, - { url = "https://files.pythonhosted.org/packages/12/da/91a52516e9d5aea87d32d1523f9cdcf7a35a3b298e6be05d6509ba3cfab2/coverage-7.13.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fa3edde1aa8807de1d05934982416cb3ec46d1d4d91e280bcce7cca01c507992", size = 252907, upload-time = "2025-12-28T15:41:22.257Z" }, - { url = "https://files.pythonhosted.org/packages/75/38/f1ea837e3dc1231e086db1638947e00d264e7e8c41aa8ecacf6e1e0c05f4/coverage-7.13.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9edd0e01a343766add6817bc448408858ba6b489039eaaa2018474e4001651a4", size = 254148, upload-time = "2025-12-28T15:41:23.87Z" }, - { url = "https://files.pythonhosted.org/packages/7f/43/f4f16b881aaa34954ba446318dea6b9ed5405dd725dd8daac2358eda869a/coverage-7.13.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:985b7836931d033570b94c94713c6dba5f9d3ff26045f72c3e5dbc5fe3361e5a", size = 250515, upload-time = "2025-12-28T15:41:25.437Z" }, - { url = "https://files.pythonhosted.org/packages/84/34/8cba7f00078bd468ea914134e0144263194ce849ec3baad187ffb6203d1c/coverage-7.13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ffed1e4980889765c84a5d1a566159e363b71d6b6fbaf0bebc9d3c30bc016766", size = 252292, upload-time = "2025-12-28T15:41:28.459Z" }, - { url = "https://files.pythonhosted.org/packages/8c/a4/cffac66c7652d84ee4ac52d3ccb94c015687d3b513f9db04bfcac2ac800d/coverage-7.13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8842af7f175078456b8b17f1b73a0d16a65dcbdc653ecefeb00a56b3c8c298c4", size = 250242, upload-time = "2025-12-28T15:41:30.02Z" }, - { url = "https://files.pythonhosted.org/packages/f4/78/9a64d462263dde416f3c0067efade7b52b52796f489b1037a95b0dc389c9/coverage-7.13.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:ccd7a6fca48ca9c131d9b0a2972a581e28b13416fc313fb98b6d24a03ce9a398", size = 250068, upload-time = "2025-12-28T15:41:32.007Z" }, - { url = "https://files.pythonhosted.org/packages/69/c8/a8994f5fece06db7c4a97c8fc1973684e178599b42e66280dded0524ef00/coverage-7.13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0403f647055de2609be776965108447deb8e384fe4a553c119e3ff6bfbab4784", size = 251846, upload-time = "2025-12-28T15:41:33.946Z" }, - { url = "https://files.pythonhosted.org/packages/cc/f7/91fa73c4b80305c86598a2d4e54ba22df6bf7d0d97500944af7ef155d9f7/coverage-7.13.1-cp313-cp313-win32.whl", hash = "sha256:549d195116a1ba1e1ae2f5ca143f9777800f6636eab917d4f02b5310d6d73461", size = 221512, upload-time = "2025-12-28T15:41:35.519Z" }, - { url = "https://files.pythonhosted.org/packages/45/0b/0768b4231d5a044da8f75e097a8714ae1041246bb765d6b5563bab456735/coverage-7.13.1-cp313-cp313-win_amd64.whl", hash = "sha256:5899d28b5276f536fcf840b18b61a9fce23cc3aec1d114c44c07fe94ebeaa500", size = 222321, upload-time = "2025-12-28T15:41:37.371Z" }, - { url = "https://files.pythonhosted.org/packages/9b/b8/bdcb7253b7e85157282450262008f1366aa04663f3e3e4c30436f596c3e2/coverage-7.13.1-cp313-cp313-win_arm64.whl", hash = "sha256:868a2fae76dfb06e87291bcbd4dcbcc778a8500510b618d50496e520bd94d9b9", size = 220949, upload-time = "2025-12-28T15:41:39.553Z" }, - { url = "https://files.pythonhosted.org/packages/70/52/f2be52cc445ff75ea8397948c96c1b4ee14f7f9086ea62fc929c5ae7b717/coverage-7.13.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:67170979de0dacac3f3097d02b0ad188d8edcea44ccc44aaa0550af49150c7dc", size = 219643, upload-time = "2025-12-28T15:41:41.567Z" }, - { url = "https://files.pythonhosted.org/packages/47/79/c85e378eaa239e2edec0c5523f71542c7793fe3340954eafb0bc3904d32d/coverage-7.13.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f80e2bb21bfab56ed7405c2d79d34b5dc0bc96c2c1d2a067b643a09fb756c43a", size = 219997, upload-time = "2025-12-28T15:41:43.418Z" }, - { url = "https://files.pythonhosted.org/packages/fe/9b/b1ade8bfb653c0bbce2d6d6e90cc6c254cbb99b7248531cc76253cb4da6d/coverage-7.13.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f83351e0f7dcdb14d7326c3d8d8c4e915fa685cbfdc6281f9470d97a04e9dfe4", size = 261296, upload-time = "2025-12-28T15:41:45.207Z" }, - { url = "https://files.pythonhosted.org/packages/1f/af/ebf91e3e1a2473d523e87e87fd8581e0aa08741b96265730e2d79ce78d8d/coverage-7.13.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bb3f6562e89bad0110afbe64e485aac2462efdce6232cdec7862a095dc3412f6", size = 263363, upload-time = "2025-12-28T15:41:47.163Z" }, - { url = "https://files.pythonhosted.org/packages/c4/8b/fb2423526d446596624ac7fde12ea4262e66f86f5120114c3cfd0bb2befa/coverage-7.13.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77545b5dcda13b70f872c3b5974ac64c21d05e65b1590b441c8560115dc3a0d1", size = 265783, upload-time = "2025-12-28T15:41:49.03Z" }, - { url = "https://files.pythonhosted.org/packages/9b/26/ef2adb1e22674913b89f0fe7490ecadcef4a71fa96f5ced90c60ec358789/coverage-7.13.1-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a4d240d260a1aed814790bbe1f10a5ff31ce6c21bc78f0da4a1e8268d6c80dbd", size = 260508, upload-time = "2025-12-28T15:41:51.035Z" }, - { url = "https://files.pythonhosted.org/packages/ce/7d/f0f59b3404caf662e7b5346247883887687c074ce67ba453ea08c612b1d5/coverage-7.13.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d2287ac9360dec3837bfdad969963a5d073a09a85d898bd86bea82aa8876ef3c", size = 263357, upload-time = "2025-12-28T15:41:52.631Z" }, - { url = "https://files.pythonhosted.org/packages/1a/b1/29896492b0b1a047604d35d6fa804f12818fa30cdad660763a5f3159e158/coverage-7.13.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:0d2c11f3ea4db66b5cbded23b20185c35066892c67d80ec4be4bab257b9ad1e0", size = 260978, upload-time = "2025-12-28T15:41:54.589Z" }, - { url = "https://files.pythonhosted.org/packages/48/f2/971de1238a62e6f0a4128d37adadc8bb882ee96afbe03ff1570291754629/coverage-7.13.1-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:3fc6a169517ca0d7ca6846c3c5392ef2b9e38896f61d615cb75b9e7134d4ee1e", size = 259877, upload-time = "2025-12-28T15:41:56.263Z" }, - { url = "https://files.pythonhosted.org/packages/6a/fc/0474efcbb590ff8628830e9aaec5f1831594874360e3251f1fdec31d07a3/coverage-7.13.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d10a2ed46386e850bb3de503a54f9fe8192e5917fcbb143bfef653a9355e9a53", size = 262069, upload-time = "2025-12-28T15:41:58.093Z" }, - { url = "https://files.pythonhosted.org/packages/88/4f/3c159b7953db37a7b44c0eab8a95c37d1aa4257c47b4602c04022d5cb975/coverage-7.13.1-cp313-cp313t-win32.whl", hash = "sha256:75a6f4aa904301dab8022397a22c0039edc1f51e90b83dbd4464b8a38dc87842", size = 222184, upload-time = "2025-12-28T15:41:59.763Z" }, - { url = "https://files.pythonhosted.org/packages/58/a5/6b57d28f81417f9335774f20679d9d13b9a8fb90cd6160957aa3b54a2379/coverage-7.13.1-cp313-cp313t-win_amd64.whl", hash = "sha256:309ef5706e95e62578cda256b97f5e097916a2c26247c287bbe74794e7150df2", size = 223250, upload-time = "2025-12-28T15:42:01.52Z" }, - { url = "https://files.pythonhosted.org/packages/81/7c/160796f3b035acfbb58be80e02e484548595aa67e16a6345e7910ace0a38/coverage-7.13.1-cp313-cp313t-win_arm64.whl", hash = "sha256:92f980729e79b5d16d221038dbf2e8f9a9136afa072f9d5d6ed4cb984b126a09", size = 221521, upload-time = "2025-12-28T15:42:03.275Z" }, - { url = "https://files.pythonhosted.org/packages/aa/8e/ba0e597560c6563fc0adb902fda6526df5d4aa73bb10adf0574d03bd2206/coverage-7.13.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:97ab3647280d458a1f9adb85244e81587505a43c0c7cff851f5116cd2814b894", size = 218996, upload-time = "2025-12-28T15:42:04.978Z" }, - { url = "https://files.pythonhosted.org/packages/6b/8e/764c6e116f4221dc7aa26c4061181ff92edb9c799adae6433d18eeba7a14/coverage-7.13.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8f572d989142e0908e6acf57ad1b9b86989ff057c006d13b76c146ec6a20216a", size = 219326, upload-time = "2025-12-28T15:42:06.691Z" }, - { url = "https://files.pythonhosted.org/packages/4f/a6/6130dc6d8da28cdcbb0f2bf8865aeca9b157622f7c0031e48c6cf9a0e591/coverage-7.13.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d72140ccf8a147e94274024ff6fd8fb7811354cf7ef88b1f0a988ebaa5bc774f", size = 250374, upload-time = "2025-12-28T15:42:08.786Z" }, - { url = "https://files.pythonhosted.org/packages/82/2b/783ded568f7cd6b677762f780ad338bf4b4750205860c17c25f7c708995e/coverage-7.13.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d3c9f051b028810f5a87c88e5d6e9af3c0ff32ef62763bf15d29f740453ca909", size = 252882, upload-time = "2025-12-28T15:42:10.515Z" }, - { url = "https://files.pythonhosted.org/packages/cd/b2/9808766d082e6a4d59eb0cc881a57fc1600eb2c5882813eefff8254f71b5/coverage-7.13.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f398ba4df52d30b1763f62eed9de5620dcde96e6f491f4c62686736b155aa6e4", size = 254218, upload-time = "2025-12-28T15:42:12.208Z" }, - { url = "https://files.pythonhosted.org/packages/44/ea/52a985bb447c871cb4d2e376e401116520991b597c85afdde1ea9ef54f2c/coverage-7.13.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:132718176cc723026d201e347f800cd1a9e4b62ccd3f82476950834dad501c75", size = 250391, upload-time = "2025-12-28T15:42:14.21Z" }, - { url = "https://files.pythonhosted.org/packages/7f/1d/125b36cc12310718873cfc8209ecfbc1008f14f4f5fa0662aa608e579353/coverage-7.13.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9e549d642426e3579b3f4b92d0431543b012dcb6e825c91619d4e93b7363c3f9", size = 252239, upload-time = "2025-12-28T15:42:16.292Z" }, - { url = "https://files.pythonhosted.org/packages/6a/16/10c1c164950cade470107f9f14bbac8485f8fb8515f515fca53d337e4a7f/coverage-7.13.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:90480b2134999301eea795b3a9dbf606c6fbab1b489150c501da84a959442465", size = 250196, upload-time = "2025-12-28T15:42:18.54Z" }, - { url = "https://files.pythonhosted.org/packages/2a/c6/cd860fac08780c6fd659732f6ced1b40b79c35977c1356344e44d72ba6c4/coverage-7.13.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e825dbb7f84dfa24663dd75835e7257f8882629fc11f03ecf77d84a75134b864", size = 250008, upload-time = "2025-12-28T15:42:20.365Z" }, - { url = "https://files.pythonhosted.org/packages/f0/3a/a8c58d3d38f82a5711e1e0a67268362af48e1a03df27c03072ac30feefcf/coverage-7.13.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:623dcc6d7a7ba450bbdbeedbaa0c42b329bdae16491af2282f12a7e809be7eb9", size = 251671, upload-time = "2025-12-28T15:42:22.114Z" }, - { url = "https://files.pythonhosted.org/packages/f0/bc/fd4c1da651d037a1e3d53e8cb3f8182f4b53271ffa9a95a2e211bacc0349/coverage-7.13.1-cp314-cp314-win32.whl", hash = "sha256:6e73ebb44dca5f708dc871fe0b90cf4cff1a13f9956f747cc87b535a840386f5", size = 221777, upload-time = "2025-12-28T15:42:23.919Z" }, - { url = "https://files.pythonhosted.org/packages/4b/50/71acabdc8948464c17e90b5ffd92358579bd0910732c2a1c9537d7536aa6/coverage-7.13.1-cp314-cp314-win_amd64.whl", hash = "sha256:be753b225d159feb397bd0bf91ae86f689bad0da09d3b301478cd39b878ab31a", size = 222592, upload-time = "2025-12-28T15:42:25.619Z" }, - { url = "https://files.pythonhosted.org/packages/f7/c8/a6fb943081bb0cc926499c7907731a6dc9efc2cbdc76d738c0ab752f1a32/coverage-7.13.1-cp314-cp314-win_arm64.whl", hash = "sha256:228b90f613b25ba0019361e4ab81520b343b622fc657daf7e501c4ed6a2366c0", size = 221169, upload-time = "2025-12-28T15:42:27.629Z" }, - { url = "https://files.pythonhosted.org/packages/16/61/d5b7a0a0e0e40d62e59bc8c7aa1afbd86280d82728ba97f0673b746b78e2/coverage-7.13.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:60cfb538fe9ef86e5b2ab0ca8fc8d62524777f6c611dcaf76dc16fbe9b8e698a", size = 219730, upload-time = "2025-12-28T15:42:29.306Z" }, - { url = "https://files.pythonhosted.org/packages/a3/2c/8881326445fd071bb49514d1ce97d18a46a980712b51fee84f9ab42845b4/coverage-7.13.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:57dfc8048c72ba48a8c45e188d811e5efd7e49b387effc8fb17e97936dde5bf6", size = 220001, upload-time = "2025-12-28T15:42:31.319Z" }, - { url = "https://files.pythonhosted.org/packages/b5/d7/50de63af51dfa3a7f91cc37ad8fcc1e244b734232fbc8b9ab0f3c834a5cd/coverage-7.13.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3f2f725aa3e909b3c5fdb8192490bdd8e1495e85906af74fe6e34a2a77ba0673", size = 261370, upload-time = "2025-12-28T15:42:32.992Z" }, - { url = "https://files.pythonhosted.org/packages/e1/2c/d31722f0ec918fd7453b2758312729f645978d212b410cd0f7c2aed88a94/coverage-7.13.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ee68b21909686eeb21dfcba2c3b81fee70dcf38b140dcd5aa70680995fa3aa5", size = 263485, upload-time = "2025-12-28T15:42:34.759Z" }, - { url = "https://files.pythonhosted.org/packages/fa/7a/2c114fa5c5fc08ba0777e4aec4c97e0b4a1afcb69c75f1f54cff78b073ab/coverage-7.13.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:724b1b270cb13ea2e6503476e34541a0b1f62280bc997eab443f87790202033d", size = 265890, upload-time = "2025-12-28T15:42:36.517Z" }, - { url = "https://files.pythonhosted.org/packages/65/d9/f0794aa1c74ceabc780fe17f6c338456bbc4e96bd950f2e969f48ac6fb20/coverage-7.13.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:916abf1ac5cf7eb16bc540a5bf75c71c43a676f5c52fcb9fe75a2bd75fb944e8", size = 260445, upload-time = "2025-12-28T15:42:38.646Z" }, - { url = "https://files.pythonhosted.org/packages/49/23/184b22a00d9bb97488863ced9454068c79e413cb23f472da6cbddc6cfc52/coverage-7.13.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:776483fd35b58d8afe3acbd9988d5de592ab6da2d2a865edfdbc9fdb43e7c486", size = 263357, upload-time = "2025-12-28T15:42:40.788Z" }, - { url = "https://files.pythonhosted.org/packages/7d/bd/58af54c0c9199ea4190284f389005779d7daf7bf3ce40dcd2d2b2f96da69/coverage-7.13.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b6f3b96617e9852703f5b633ea01315ca45c77e879584f283c44127f0f1ec564", size = 260959, upload-time = "2025-12-28T15:42:42.808Z" }, - { url = "https://files.pythonhosted.org/packages/4b/2a/6839294e8f78a4891bf1df79d69c536880ba2f970d0ff09e7513d6e352e9/coverage-7.13.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:bd63e7b74661fed317212fab774e2a648bc4bb09b35f25474f8e3325d2945cd7", size = 259792, upload-time = "2025-12-28T15:42:44.818Z" }, - { url = "https://files.pythonhosted.org/packages/ba/c3/528674d4623283310ad676c5af7414b9850ab6d55c2300e8aa4b945ec554/coverage-7.13.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:933082f161bbb3e9f90d00990dc956120f608cdbcaeea15c4d897f56ef4fe416", size = 262123, upload-time = "2025-12-28T15:42:47.108Z" }, - { url = "https://files.pythonhosted.org/packages/06/c5/8c0515692fb4c73ac379d8dc09b18eaf0214ecb76ea6e62467ba7a1556ff/coverage-7.13.1-cp314-cp314t-win32.whl", hash = "sha256:18be793c4c87de2965e1c0f060f03d9e5aff66cfeae8e1dbe6e5b88056ec153f", size = 222562, upload-time = "2025-12-28T15:42:49.144Z" }, - { url = "https://files.pythonhosted.org/packages/05/0e/c0a0c4678cb30dac735811db529b321d7e1c9120b79bd728d4f4d6b010e9/coverage-7.13.1-cp314-cp314t-win_amd64.whl", hash = "sha256:0e42e0ec0cd3e0d851cb3c91f770c9301f48647cb2877cb78f74bdaa07639a79", size = 223670, upload-time = "2025-12-28T15:42:51.218Z" }, - { url = "https://files.pythonhosted.org/packages/f5/5f/b177aa0011f354abf03a8f30a85032686d290fdeed4222b27d36b4372a50/coverage-7.13.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eaecf47ef10c72ece9a2a92118257da87e460e113b83cc0d2905cbbe931792b4", size = 221707, upload-time = "2025-12-28T15:42:53.034Z" }, - { url = "https://files.pythonhosted.org/packages/cc/48/d9f421cb8da5afaa1a64570d9989e00fb7955e6acddc5a12979f7666ef60/coverage-7.13.1-py3-none-any.whl", hash = "sha256:2016745cb3ba554469d02819d78958b571792bb68e31302610e898f80dd3a573", size = 210722, upload-time = "2025-12-28T15:42:54.901Z" }, +version = "7.13.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/e0/70553e3000e345daff267cec284ce4cbf3fc141b6da229ac52775b5428f1/coverage-7.13.5.tar.gz", hash = "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179", size = 915967, upload-time = "2026-03-17T10:33:18.341Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/c3/a396306ba7db865bf96fc1fb3b7fd29bcbf3d829df642e77b13555163cd6/coverage-7.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:460cf0114c5016fa841214ff5564aa4864f11948da9440bc97e21ad1f4ba1e01", size = 219554, upload-time = "2026-03-17T10:30:42.208Z" }, + { url = "https://files.pythonhosted.org/packages/a6/16/a68a19e5384e93f811dccc51034b1fd0b865841c390e3c931dcc4699e035/coverage-7.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e223ce4b4ed47f065bfb123687686512e37629be25cc63728557ae7db261422", size = 219908, upload-time = "2026-03-17T10:30:43.906Z" }, + { url = "https://files.pythonhosted.org/packages/29/72/20b917c6793af3a5ceb7fb9c50033f3ec7865f2911a1416b34a7cfa0813b/coverage-7.13.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6e3370441f4513c6252bf042b9c36d22491142385049243253c7e48398a15a9f", size = 251419, upload-time = "2026-03-17T10:30:45.545Z" }, + { url = "https://files.pythonhosted.org/packages/8c/49/cd14b789536ac6a4778c453c6a2338bc0a2fb60c5a5a41b4008328b9acc1/coverage-7.13.5-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:03ccc709a17a1de074fb1d11f217342fb0d2b1582ed544f554fc9fc3f07e95f5", size = 254159, upload-time = "2026-03-17T10:30:47.204Z" }, + { url = "https://files.pythonhosted.org/packages/9d/00/7b0edcfe64e2ed4c0340dac14a52ad0f4c9bd0b8b5e531af7d55b703db7c/coverage-7.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3f4818d065964db3c1c66dc0fbdac5ac692ecbc875555e13374fdbe7eedb4376", size = 255270, upload-time = "2026-03-17T10:30:48.812Z" }, + { url = "https://files.pythonhosted.org/packages/93/89/7ffc4ba0f5d0a55c1e84ea7cee39c9fc06af7b170513d83fbf3bbefce280/coverage-7.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:012d5319e66e9d5a218834642d6c35d265515a62f01157a45bcc036ecf947256", size = 257538, upload-time = "2026-03-17T10:30:50.77Z" }, + { url = "https://files.pythonhosted.org/packages/81/bd/73ddf85f93f7e6fa83e77ccecb6162d9415c79007b4bc124008a4995e4a7/coverage-7.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8dd02af98971bdb956363e4827d34425cb3df19ee550ef92855b0acb9c7ce51c", size = 251821, upload-time = "2026-03-17T10:30:52.5Z" }, + { url = "https://files.pythonhosted.org/packages/a0/81/278aff4e8dec4926a0bcb9486320752811f543a3ce5b602cc7a29978d073/coverage-7.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f08fd75c50a760c7eb068ae823777268daaf16a80b918fa58eea888f8e3919f5", size = 253191, upload-time = "2026-03-17T10:30:54.543Z" }, + { url = "https://files.pythonhosted.org/packages/70/ee/fe1621488e2e0a58d7e94c4800f0d96f79671553488d401a612bebae324b/coverage-7.13.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:843ea8643cf967d1ac7e8ecd4bb00c99135adf4816c0c0593fdcc47b597fcf09", size = 251337, upload-time = "2026-03-17T10:30:56.663Z" }, + { url = "https://files.pythonhosted.org/packages/37/a6/f79fb37aa104b562207cc23cb5711ab6793608e246cae1e93f26b2236ed9/coverage-7.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:9d44d7aa963820b1b971dbecd90bfe5fe8f81cff79787eb6cca15750bd2f79b9", size = 255404, upload-time = "2026-03-17T10:30:58.427Z" }, + { url = "https://files.pythonhosted.org/packages/75/f0/ed15262a58ec81ce457ceb717b7f78752a1713556b19081b76e90896e8d4/coverage-7.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7132bed4bd7b836200c591410ae7d97bf7ae8be6fc87d160b2bd881df929e7bf", size = 250903, upload-time = "2026-03-17T10:31:00.093Z" }, + { url = "https://files.pythonhosted.org/packages/0f/e9/9129958f20e7e9d4d56d51d42ccf708d15cac355ff4ac6e736e97a9393d2/coverage-7.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a698e363641b98843c517817db75373c83254781426e94ada3197cabbc2c919c", size = 252780, upload-time = "2026-03-17T10:31:01.916Z" }, + { url = "https://files.pythonhosted.org/packages/a4/d7/0ad9b15812d81272db94379fe4c6df8fd17781cc7671fdfa30c76ba5ff7b/coverage-7.13.5-cp312-cp312-win32.whl", hash = "sha256:bdba0a6b8812e8c7df002d908a9a2ea3c36e92611b5708633c50869e6d922fdf", size = 222093, upload-time = "2026-03-17T10:31:03.642Z" }, + { url = "https://files.pythonhosted.org/packages/29/3d/821a9a5799fac2556bcf0bd37a70d1d11fa9e49784b6d22e92e8b2f85f18/coverage-7.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:d2c87e0c473a10bffe991502eac389220533024c8082ec1ce849f4218dded810", size = 222900, upload-time = "2026-03-17T10:31:05.651Z" }, + { url = "https://files.pythonhosted.org/packages/d4/fa/2238c2ad08e35cf4f020ea721f717e09ec3152aea75d191a7faf3ef009a8/coverage-7.13.5-cp312-cp312-win_arm64.whl", hash = "sha256:bf69236a9a81bdca3bff53796237aab096cdbf8d78a66ad61e992d9dac7eb2de", size = 221515, upload-time = "2026-03-17T10:31:07.293Z" }, + { url = "https://files.pythonhosted.org/packages/74/8c/74fedc9663dcf168b0a059d4ea756ecae4da77a489048f94b5f512a8d0b3/coverage-7.13.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5ec4af212df513e399cf11610cc27063f1586419e814755ab362e50a85ea69c1", size = 219576, upload-time = "2026-03-17T10:31:09.045Z" }, + { url = "https://files.pythonhosted.org/packages/0c/c9/44fb661c55062f0818a6ffd2685c67aa30816200d5f2817543717d4b92eb/coverage-7.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:941617e518602e2d64942c88ec8499f7fbd49d3f6c4327d3a71d43a1973032f3", size = 219942, upload-time = "2026-03-17T10:31:10.708Z" }, + { url = "https://files.pythonhosted.org/packages/5f/13/93419671cee82b780bab7ea96b67c8ef448f5f295f36bf5031154ec9a790/coverage-7.13.5-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:da305e9937617ee95c2e39d8ff9f040e0487cbf1ac174f777ed5eddd7a7c1f26", size = 250935, upload-time = "2026-03-17T10:31:12.392Z" }, + { url = "https://files.pythonhosted.org/packages/ac/68/1666e3a4462f8202d836920114fa7a5ee9275d1fa45366d336c551a162dd/coverage-7.13.5-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:78e696e1cc714e57e8b25760b33a8b1026b7048d270140d25dafe1b0a1ee05a3", size = 253541, upload-time = "2026-03-17T10:31:14.247Z" }, + { url = "https://files.pythonhosted.org/packages/4e/5e/3ee3b835647be646dcf3c65a7c6c18f87c27326a858f72ab22c12730773d/coverage-7.13.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02ca0eed225b2ff301c474aeeeae27d26e2537942aa0f87491d3e147e784a82b", size = 254780, upload-time = "2026-03-17T10:31:16.193Z" }, + { url = "https://files.pythonhosted.org/packages/44/b3/cb5bd1a04cfcc49ede6cd8409d80bee17661167686741e041abc7ee1b9a9/coverage-7.13.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:04690832cbea4e4663d9149e05dba142546ca05cb1848816760e7f58285c970a", size = 256912, upload-time = "2026-03-17T10:31:17.89Z" }, + { url = "https://files.pythonhosted.org/packages/1b/66/c1dceb7b9714473800b075f5c8a84f4588f887a90eb8645282031676e242/coverage-7.13.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0590e44dd2745c696a778f7bab6aa95256de2cbc8b8cff4f7db8ff09813d6969", size = 251165, upload-time = "2026-03-17T10:31:19.605Z" }, + { url = "https://files.pythonhosted.org/packages/b7/62/5502b73b97aa2e53ea22a39cf8649ff44827bef76d90bf638777daa27a9d/coverage-7.13.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d7cfad2d6d81dd298ab6b89fe72c3b7b05ec7544bdda3b707ddaecff8d25c161", size = 252908, upload-time = "2026-03-17T10:31:21.312Z" }, + { url = "https://files.pythonhosted.org/packages/7d/37/7792c2d69854397ca77a55c4646e5897c467928b0e27f2d235d83b5d08c6/coverage-7.13.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e092b9499de38ae0fbfbc603a74660eb6ff3e869e507b50d85a13b6db9863e15", size = 250873, upload-time = "2026-03-17T10:31:23.565Z" }, + { url = "https://files.pythonhosted.org/packages/a3/23/bc866fb6163be52a8a9e5d708ba0d3b1283c12158cefca0a8bbb6e247a43/coverage-7.13.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:48c39bc4a04d983a54a705a6389512883d4a3b9862991b3617d547940e9f52b1", size = 255030, upload-time = "2026-03-17T10:31:25.58Z" }, + { url = "https://files.pythonhosted.org/packages/7d/8b/ef67e1c222ef49860701d346b8bbb70881bef283bd5f6cbba68a39a086c7/coverage-7.13.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2d3807015f138ffea1ed9afeeb8624fd781703f2858b62a8dd8da5a0994c57b6", size = 250694, upload-time = "2026-03-17T10:31:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/46/0d/866d1f74f0acddbb906db212e096dee77a8e2158ca5e6bb44729f9d93298/coverage-7.13.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ee2aa19e03161671ec964004fb74b2257805d9710bf14a5c704558b9d8dbaf17", size = 252469, upload-time = "2026-03-17T10:31:29.472Z" }, + { url = "https://files.pythonhosted.org/packages/7a/f5/be742fec31118f02ce42b21c6af187ad6a344fed546b56ca60caacc6a9a0/coverage-7.13.5-cp313-cp313-win32.whl", hash = "sha256:ce1998c0483007608c8382f4ff50164bfc5bd07a2246dd272aa4043b75e61e85", size = 222112, upload-time = "2026-03-17T10:31:31.526Z" }, + { url = "https://files.pythonhosted.org/packages/66/40/7732d648ab9d069a46e686043241f01206348e2bbf128daea85be4d6414b/coverage-7.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:631efb83f01569670a5e866ceb80fe483e7c159fac6f167e6571522636104a0b", size = 222923, upload-time = "2026-03-17T10:31:33.633Z" }, + { url = "https://files.pythonhosted.org/packages/48/af/fea819c12a095781f6ccd504890aaddaf88b8fab263c4940e82c7b770124/coverage-7.13.5-cp313-cp313-win_arm64.whl", hash = "sha256:f4cd16206ad171cbc2470dbea9103cf9a7607d5fe8c242fdf1edf36174020664", size = 221540, upload-time = "2026-03-17T10:31:35.445Z" }, + { url = "https://files.pythonhosted.org/packages/23/d2/17879af479df7fbbd44bd528a31692a48f6b25055d16482fdf5cdb633805/coverage-7.13.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0428cbef5783ad91fe240f673cc1f76b25e74bbfe1a13115e4aa30d3f538162d", size = 220262, upload-time = "2026-03-17T10:31:37.184Z" }, + { url = "https://files.pythonhosted.org/packages/5b/4c/d20e554f988c8f91d6a02c5118f9abbbf73a8768a3048cb4962230d5743f/coverage-7.13.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e0b216a19534b2427cc201a26c25da4a48633f29a487c61258643e89d28200c0", size = 220617, upload-time = "2026-03-17T10:31:39.245Z" }, + { url = "https://files.pythonhosted.org/packages/29/9c/f9f5277b95184f764b24e7231e166dfdb5780a46d408a2ac665969416d61/coverage-7.13.5-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:972a9cd27894afe4bc2b1480107054e062df08e671df7c2f18c205e805ccd806", size = 261912, upload-time = "2026-03-17T10:31:41.324Z" }, + { url = "https://files.pythonhosted.org/packages/d5/f6/7f1ab39393eeb50cfe4747ae8ef0e4fc564b989225aa1152e13a180d74f8/coverage-7.13.5-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4b59148601efcd2bac8c4dbf1f0ad6391693ccf7a74b8205781751637076aee3", size = 263987, upload-time = "2026-03-17T10:31:43.724Z" }, + { url = "https://files.pythonhosted.org/packages/a0/d7/62c084fb489ed9c6fbdf57e006752e7c516ea46fd690e5ed8b8617c7d52e/coverage-7.13.5-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:505d7083c8b0c87a8fa8c07370c285847c1f77739b22e299ad75a6af6c32c5c9", size = 266416, upload-time = "2026-03-17T10:31:45.769Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f6/df63d8660e1a0bff6125947afda112a0502736f470d62ca68b288ea762d8/coverage-7.13.5-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:60365289c3741e4db327e7baff2a4aaacf22f788e80fa4683393891b70a89fbd", size = 267558, upload-time = "2026-03-17T10:31:48.293Z" }, + { url = "https://files.pythonhosted.org/packages/5b/02/353ca81d36779bd108f6d384425f7139ac3c58c750dcfaafe5d0bee6436b/coverage-7.13.5-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1b88c69c8ef5d4b6fe7dea66d6636056a0f6a7527c440e890cf9259011f5e606", size = 261163, upload-time = "2026-03-17T10:31:50.125Z" }, + { url = "https://files.pythonhosted.org/packages/2c/16/2e79106d5749bcaf3aee6d309123548e3276517cd7851faa8da213bc61bf/coverage-7.13.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5b13955d31d1633cf9376908089b7cebe7d15ddad7aeaabcbe969a595a97e95e", size = 263981, upload-time = "2026-03-17T10:31:51.961Z" }, + { url = "https://files.pythonhosted.org/packages/29/c7/c29e0c59ffa6942030ae6f50b88ae49988e7e8da06de7ecdbf49c6d4feae/coverage-7.13.5-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:f70c9ab2595c56f81a89620e22899eea8b212a4041bd728ac6f4a28bf5d3ddd0", size = 261604, upload-time = "2026-03-17T10:31:53.872Z" }, + { url = "https://files.pythonhosted.org/packages/40/48/097cdc3db342f34006a308ab41c3a7c11c3f0d84750d340f45d88a782e00/coverage-7.13.5-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:084b84a8c63e8d6fc7e3931b316a9bcafca1458d753c539db82d31ed20091a87", size = 265321, upload-time = "2026-03-17T10:31:55.997Z" }, + { url = "https://files.pythonhosted.org/packages/bb/1f/4994af354689e14fd03a75f8ec85a9a68d94e0188bbdab3fc1516b55e512/coverage-7.13.5-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ad14385487393e386e2ea988b09d62dd42c397662ac2dabc3832d71253eee479", size = 260502, upload-time = "2026-03-17T10:31:58.308Z" }, + { url = "https://files.pythonhosted.org/packages/22/c6/9bb9ef55903e628033560885f5c31aa227e46878118b63ab15dc7ba87797/coverage-7.13.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7f2c47b36fe7709a6e83bfadf4eefb90bd25fbe4014d715224c4316f808e59a2", size = 262688, upload-time = "2026-03-17T10:32:00.141Z" }, + { url = "https://files.pythonhosted.org/packages/14/4f/f5df9007e50b15e53e01edea486814783a7f019893733d9e4d6caad75557/coverage-7.13.5-cp313-cp313t-win32.whl", hash = "sha256:67e9bc5449801fad0e5dff329499fb090ba4c5800b86805c80617b4e29809b2a", size = 222788, upload-time = "2026-03-17T10:32:02.246Z" }, + { url = "https://files.pythonhosted.org/packages/e1/98/aa7fccaa97d0f3192bec013c4e6fd6d294a6ed44b640e6bb61f479e00ed5/coverage-7.13.5-cp313-cp313t-win_amd64.whl", hash = "sha256:da86cdcf10d2519e10cabb8ac2de03da1bcb6e4853790b7fbd48523332e3a819", size = 223851, upload-time = "2026-03-17T10:32:04.416Z" }, + { url = "https://files.pythonhosted.org/packages/3d/8b/e5c469f7352651e5f013198e9e21f97510b23de957dd06a84071683b4b60/coverage-7.13.5-cp313-cp313t-win_arm64.whl", hash = "sha256:0ecf12ecb326fe2c339d93fc131816f3a7367d223db37817208905c89bded911", size = 222104, upload-time = "2026-03-17T10:32:06.65Z" }, + { url = "https://files.pythonhosted.org/packages/8e/77/39703f0d1d4b478bfd30191d3c14f53caf596fac00efb3f8f6ee23646439/coverage-7.13.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fbabfaceaeb587e16f7008f7795cd80d20ec548dc7f94fbb0d4ec2e038ce563f", size = 219621, upload-time = "2026-03-17T10:32:08.589Z" }, + { url = "https://files.pythonhosted.org/packages/e2/3e/51dff36d99ae14639a133d9b164d63e628532e2974d8b1edb99dd1ebc733/coverage-7.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9bb2a28101a443669a423b665939381084412b81c3f8c0fcfbac57f4e30b5b8e", size = 219953, upload-time = "2026-03-17T10:32:10.507Z" }, + { url = "https://files.pythonhosted.org/packages/6a/6c/1f1917b01eb647c2f2adc9962bd66c79eb978951cab61bdc1acab3290c07/coverage-7.13.5-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bd3a2fbc1c6cccb3c5106140d87cc6a8715110373ef42b63cf5aea29df8c217a", size = 250992, upload-time = "2026-03-17T10:32:12.41Z" }, + { url = "https://files.pythonhosted.org/packages/22/e5/06b1f88f42a5a99df42ce61208bdec3bddb3d261412874280a19796fc09c/coverage-7.13.5-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6c36ddb64ed9d7e496028d1d00dfec3e428e0aabf4006583bb1839958d280510", size = 253503, upload-time = "2026-03-17T10:32:14.449Z" }, + { url = "https://files.pythonhosted.org/packages/80/28/2a148a51e5907e504fa7b85490277734e6771d8844ebcc48764a15e28155/coverage-7.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:380e8e9084d8eb38db3a9176a1a4f3c0082c3806fa0dc882d1d87abc3c789247", size = 254852, upload-time = "2026-03-17T10:32:16.56Z" }, + { url = "https://files.pythonhosted.org/packages/61/77/50e8d3d85cc0b7ebe09f30f151d670e302c7ff4a1bf6243f71dd8b0981fa/coverage-7.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e808af52a0513762df4d945ea164a24b37f2f518cbe97e03deaa0ee66139b4d6", size = 257161, upload-time = "2026-03-17T10:32:19.004Z" }, + { url = "https://files.pythonhosted.org/packages/3b/c4/b5fd1d4b7bf8d0e75d997afd3925c59ba629fc8616f1b3aae7605132e256/coverage-7.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e301d30dd7e95ae068671d746ba8c34e945a82682e62918e41b2679acd2051a0", size = 251021, upload-time = "2026-03-17T10:32:21.344Z" }, + { url = "https://files.pythonhosted.org/packages/f8/66/6ea21f910e92d69ef0b1c3346ea5922a51bad4446c9126db2ae96ee24c4c/coverage-7.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:800bc829053c80d240a687ceeb927a94fd108bbdc68dfbe505d0d75ab578a882", size = 252858, upload-time = "2026-03-17T10:32:23.506Z" }, + { url = "https://files.pythonhosted.org/packages/9e/ea/879c83cb5d61aa2a35fb80e72715e92672daef8191b84911a643f533840c/coverage-7.13.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:0b67af5492adb31940ee418a5a655c28e48165da5afab8c7fa6fd72a142f8740", size = 250823, upload-time = "2026-03-17T10:32:25.516Z" }, + { url = "https://files.pythonhosted.org/packages/8a/fb/616d95d3adb88b9803b275580bdeee8bd1b69a886d057652521f83d7322f/coverage-7.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c9136ff29c3a91e25b1d1552b5308e53a1e0653a23e53b6366d7c2dcbbaf8a16", size = 255099, upload-time = "2026-03-17T10:32:27.944Z" }, + { url = "https://files.pythonhosted.org/packages/1c/93/25e6917c90ec1c9a56b0b26f6cad6408e5f13bb6b35d484a0d75c9cf000d/coverage-7.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:cff784eef7f0b8f6cb28804fbddcfa99f89efe4cc35fb5627e3ac58f91ed3ac0", size = 250638, upload-time = "2026-03-17T10:32:29.914Z" }, + { url = "https://files.pythonhosted.org/packages/fc/7b/dc1776b0464145a929deed214aef9fb1493f159b59ff3c7eeeedf91eddd0/coverage-7.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:68a4953be99b17ac3c23b6efbc8a38330d99680c9458927491d18700ef23ded0", size = 252295, upload-time = "2026-03-17T10:32:31.981Z" }, + { url = "https://files.pythonhosted.org/packages/ea/fb/99cbbc56a26e07762a2740713f3c8f9f3f3106e3a3dd8cc4474954bccd34/coverage-7.13.5-cp314-cp314-win32.whl", hash = "sha256:35a31f2b1578185fbe6aa2e74cea1b1d0bbf4c552774247d9160d29b80ed56cc", size = 222360, upload-time = "2026-03-17T10:32:34.233Z" }, + { url = "https://files.pythonhosted.org/packages/8d/b7/4758d4f73fb536347cc5e4ad63662f9d60ba9118cb6785e9616b2ce5d7fa/coverage-7.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:2aa055ae1857258f9e0045be26a6d62bdb47a72448b62d7b55f4820f361a2633", size = 223174, upload-time = "2026-03-17T10:32:36.369Z" }, + { url = "https://files.pythonhosted.org/packages/2c/f2/24d84e1dfe70f8ac9fdf30d338239860d0d1d5da0bda528959d0ebc9da28/coverage-7.13.5-cp314-cp314-win_arm64.whl", hash = "sha256:1b11eef33edeae9d142f9b4358edb76273b3bfd30bc3df9a4f95d0e49caf94e8", size = 221739, upload-time = "2026-03-17T10:32:38.736Z" }, + { url = "https://files.pythonhosted.org/packages/60/5b/4a168591057b3668c2428bff25dd3ebc21b629d666d90bcdfa0217940e84/coverage-7.13.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:10a0c37f0b646eaff7cce1874c31d1f1ccb297688d4c747291f4f4c70741cc8b", size = 220351, upload-time = "2026-03-17T10:32:41.196Z" }, + { url = "https://files.pythonhosted.org/packages/f5/21/1fd5c4dbfe4a58b6b99649125635df46decdfd4a784c3cd6d410d303e370/coverage-7.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b5db73ba3c41c7008037fa731ad5459fc3944cb7452fc0aa9f822ad3533c583c", size = 220612, upload-time = "2026-03-17T10:32:43.204Z" }, + { url = "https://files.pythonhosted.org/packages/d6/fe/2a924b3055a5e7e4512655a9d4609781b0d62334fa0140c3e742926834e2/coverage-7.13.5-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:750db93a81e3e5a9831b534be7b1229df848b2e125a604fe6651e48aa070e5f9", size = 261985, upload-time = "2026-03-17T10:32:45.514Z" }, + { url = "https://files.pythonhosted.org/packages/d7/0d/c8928f2bd518c45990fe1a2ab8db42e914ef9b726c975facc4282578c3eb/coverage-7.13.5-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ddb4f4a5479f2539644be484da179b653273bca1a323947d48ab107b3ed1f29", size = 264107, upload-time = "2026-03-17T10:32:47.971Z" }, + { url = "https://files.pythonhosted.org/packages/ef/ae/4ae35bbd9a0af9d820362751f0766582833c211224b38665c0f8de3d487f/coverage-7.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8a7a2049c14f413163e2bdabd37e41179b1d1ccb10ffc6ccc4b7a718429c607", size = 266513, upload-time = "2026-03-17T10:32:50.1Z" }, + { url = "https://files.pythonhosted.org/packages/9c/20/d326174c55af36f74eac6ae781612d9492f060ce8244b570bb9d50d9d609/coverage-7.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1c85e0b6c05c592ea6d8768a66a254bfb3874b53774b12d4c89c481eb78cb90", size = 267650, upload-time = "2026-03-17T10:32:52.391Z" }, + { url = "https://files.pythonhosted.org/packages/7a/5e/31484d62cbd0eabd3412e30d74386ece4a0837d4f6c3040a653878bfc019/coverage-7.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:777c4d1eff1b67876139d24288aaf1817f6c03d6bae9c5cc8d27b83bcfe38fe3", size = 261089, upload-time = "2026-03-17T10:32:54.544Z" }, + { url = "https://files.pythonhosted.org/packages/e9/d8/49a72d6de146eebb0b7e48cc0f4bc2c0dd858e3d4790ab2b39a2872b62bd/coverage-7.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6697e29b93707167687543480a40f0db8f356e86d9f67ddf2e37e2dfd91a9dab", size = 263982, upload-time = "2026-03-17T10:32:56.803Z" }, + { url = "https://files.pythonhosted.org/packages/06/3b/0351f1bd566e6e4dd39e978efe7958bde1d32f879e85589de147654f57bb/coverage-7.13.5-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:8fdf453a942c3e4d99bd80088141c4c6960bb232c409d9c3558e2dbaa3998562", size = 261579, upload-time = "2026-03-17T10:32:59.466Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ce/796a2a2f4017f554d7810f5c573449b35b1e46788424a548d4d19201b222/coverage-7.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:32ca0c0114c9834a43f045a87dcebd69d108d8ffb666957ea65aa132f50332e2", size = 265316, upload-time = "2026-03-17T10:33:01.847Z" }, + { url = "https://files.pythonhosted.org/packages/3d/16/d5ae91455541d1a78bc90abf495be600588aff8f6db5c8b0dae739fa39c9/coverage-7.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8769751c10f339021e2638cd354e13adeac54004d1941119b2c96fe5276d45ea", size = 260427, upload-time = "2026-03-17T10:33:03.945Z" }, + { url = "https://files.pythonhosted.org/packages/48/11/07f413dba62db21fb3fad5d0de013a50e073cc4e2dc4306e770360f6dfc8/coverage-7.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cec2d83125531bd153175354055cdb7a09987af08a9430bd173c937c6d0fba2a", size = 262745, upload-time = "2026-03-17T10:33:06.285Z" }, + { url = "https://files.pythonhosted.org/packages/91/15/d792371332eb4663115becf4bad47e047d16234b1aff687b1b18c58d60ae/coverage-7.13.5-cp314-cp314t-win32.whl", hash = "sha256:0cd9ed7a8b181775459296e402ca4fb27db1279740a24e93b3b41942ebe4b215", size = 223146, upload-time = "2026-03-17T10:33:08.756Z" }, + { url = "https://files.pythonhosted.org/packages/db/51/37221f59a111dca5e85be7dbf09696323b5b9f13ff65e0641d535ed06ea8/coverage-7.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:301e3b7dfefecaca37c9f1aa6f0049b7d4ab8dd933742b607765d757aca77d43", size = 224254, upload-time = "2026-03-17T10:33:11.174Z" }, + { url = "https://files.pythonhosted.org/packages/54/83/6acacc889de8987441aa7d5adfbdbf33d288dad28704a67e574f1df9bcbb/coverage-7.13.5-cp314-cp314t-win_arm64.whl", hash = "sha256:9dacc2ad679b292709e0f5fc1ac74a6d4d5562e424058962c7bb0c658ad25e45", size = 222276, upload-time = "2026-03-17T10:33:13.466Z" }, + { url = "https://files.pythonhosted.org/packages/9e/ee/a4cf96b8ce1e566ed238f0659ac2d3f007ed1d14b181bcb684e19561a69a/coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61", size = 211346, upload-time = "2026-03-17T10:33:15.691Z" }, ] [[package]] @@ -348,11 +383,11 @@ wheels = [ [[package]] name = "filelock" -version = "3.20.3" +version = "3.25.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/65/ce7f1b70157833bf3cb851b556a37d4547ceafc158aa9b34b36782f23696/filelock-3.20.3.tar.gz", hash = "sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1", size = 19485, upload-time = "2026-01-09T17:55:05.421Z" } +sdist = { url = "https://files.pythonhosted.org/packages/94/b8/00651a0f559862f3bb7d6f7477b192afe3f583cc5e26403b44e59a55ab34/filelock-3.25.2.tar.gz", hash = "sha256:b64ece2b38f4ca29dd3e810287aa8c48182bbecd1ae6e9ae126c9b35f1382694", size = 40480, upload-time = "2026-03-11T20:45:38.487Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/36/7fb70f04bf00bc646cd5bb45aa9eddb15e19437a28b8fb2b4a5249fac770/filelock-3.20.3-py3-none-any.whl", hash = "sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1", size = 16701, upload-time = "2026-01-09T17:55:04.334Z" }, + { url = "https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl", hash = "sha256:ca8afb0da15f229774c9ad1b455ed96e85a81373065fb10446672f64444ddf70", size = 26759, upload-time = "2026-03-11T20:45:37.437Z" }, ] [[package]] @@ -381,43 +416,43 @@ wheels = [ [[package]] name = "fonttools" -version = "4.61.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ec/ca/cf17b88a8df95691275a3d77dc0a5ad9907f328ae53acbe6795da1b2f5ed/fonttools-4.61.1.tar.gz", hash = "sha256:6675329885c44657f826ef01d9e4fb33b9158e9d93c537d84ad8399539bc6f69", size = 3565756, upload-time = "2025-12-12T17:31:24.246Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6f/16/7decaa24a1bd3a70c607b2e29f0adc6159f36a7e40eaba59846414765fd4/fonttools-4.61.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f3cb4a569029b9f291f88aafc927dd53683757e640081ca8c412781ea144565e", size = 2851593, upload-time = "2025-12-12T17:30:04.225Z" }, - { url = "https://files.pythonhosted.org/packages/94/98/3c4cb97c64713a8cf499b3245c3bf9a2b8fd16a3e375feff2aed78f96259/fonttools-4.61.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41a7170d042e8c0024703ed13b71893519a1a6d6e18e933e3ec7507a2c26a4b2", size = 2400231, upload-time = "2025-12-12T17:30:06.47Z" }, - { url = "https://files.pythonhosted.org/packages/b7/37/82dbef0f6342eb01f54bca073ac1498433d6ce71e50c3c3282b655733b31/fonttools-4.61.1-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:10d88e55330e092940584774ee5e8a6971b01fc2f4d3466a1d6c158230880796", size = 4954103, upload-time = "2025-12-12T17:30:08.432Z" }, - { url = "https://files.pythonhosted.org/packages/6c/44/f3aeac0fa98e7ad527f479e161aca6c3a1e47bb6996b053d45226fe37bf2/fonttools-4.61.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:15acc09befd16a0fb8a8f62bc147e1a82817542d72184acca9ce6e0aeda9fa6d", size = 5004295, upload-time = "2025-12-12T17:30:10.56Z" }, - { url = "https://files.pythonhosted.org/packages/14/e8/7424ced75473983b964d09f6747fa09f054a6d656f60e9ac9324cf40c743/fonttools-4.61.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e6bcdf33aec38d16508ce61fd81838f24c83c90a1d1b8c68982857038673d6b8", size = 4944109, upload-time = "2025-12-12T17:30:12.874Z" }, - { url = "https://files.pythonhosted.org/packages/c8/8b/6391b257fa3d0b553d73e778f953a2f0154292a7a7a085e2374b111e5410/fonttools-4.61.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5fade934607a523614726119164ff621e8c30e8fa1ffffbbd358662056ba69f0", size = 5093598, upload-time = "2025-12-12T17:30:15.79Z" }, - { url = "https://files.pythonhosted.org/packages/d9/71/fd2ea96cdc512d92da5678a1c98c267ddd4d8c5130b76d0f7a80f9a9fde8/fonttools-4.61.1-cp312-cp312-win32.whl", hash = "sha256:75da8f28eff26defba42c52986de97b22106cb8f26515b7c22443ebc9c2d3261", size = 2269060, upload-time = "2025-12-12T17:30:18.058Z" }, - { url = "https://files.pythonhosted.org/packages/80/3b/a3e81b71aed5a688e89dfe0e2694b26b78c7d7f39a5ffd8a7d75f54a12a8/fonttools-4.61.1-cp312-cp312-win_amd64.whl", hash = "sha256:497c31ce314219888c0e2fce5ad9178ca83fe5230b01a5006726cdf3ac9f24d9", size = 2319078, upload-time = "2025-12-12T17:30:22.862Z" }, - { url = "https://files.pythonhosted.org/packages/4b/cf/00ba28b0990982530addb8dc3e9e6f2fa9cb5c20df2abdda7baa755e8fe1/fonttools-4.61.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c56c488ab471628ff3bfa80964372fc13504ece601e0d97a78ee74126b2045c", size = 2846454, upload-time = "2025-12-12T17:30:24.938Z" }, - { url = "https://files.pythonhosted.org/packages/5a/ca/468c9a8446a2103ae645d14fee3f610567b7042aba85031c1c65e3ef7471/fonttools-4.61.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dc492779501fa723b04d0ab1f5be046797fee17d27700476edc7ee9ae535a61e", size = 2398191, upload-time = "2025-12-12T17:30:27.343Z" }, - { url = "https://files.pythonhosted.org/packages/a3/4b/d67eedaed19def5967fade3297fed8161b25ba94699efc124b14fb68cdbc/fonttools-4.61.1-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:64102ca87e84261419c3747a0d20f396eb024bdbeb04c2bfb37e2891f5fadcb5", size = 4928410, upload-time = "2025-12-12T17:30:29.771Z" }, - { url = "https://files.pythonhosted.org/packages/b0/8d/6fb3494dfe61a46258cd93d979cf4725ded4eb46c2a4ca35e4490d84daea/fonttools-4.61.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c1b526c8d3f615a7b1867f38a9410849c8f4aef078535742198e942fba0e9bd", size = 4984460, upload-time = "2025-12-12T17:30:32.073Z" }, - { url = "https://files.pythonhosted.org/packages/f7/f1/a47f1d30b3dc00d75e7af762652d4cbc3dff5c2697a0dbd5203c81afd9c3/fonttools-4.61.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:41ed4b5ec103bd306bb68f81dc166e77409e5209443e5773cb4ed837bcc9b0d3", size = 4925800, upload-time = "2025-12-12T17:30:34.339Z" }, - { url = "https://files.pythonhosted.org/packages/a7/01/e6ae64a0981076e8a66906fab01539799546181e32a37a0257b77e4aa88b/fonttools-4.61.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b501c862d4901792adaec7c25b1ecc749e2662543f68bb194c42ba18d6eec98d", size = 5067859, upload-time = "2025-12-12T17:30:36.593Z" }, - { url = "https://files.pythonhosted.org/packages/73/aa/28e40b8d6809a9b5075350a86779163f074d2b617c15d22343fce81918db/fonttools-4.61.1-cp313-cp313-win32.whl", hash = "sha256:4d7092bb38c53bbc78e9255a59158b150bcdc115a1e3b3ce0b5f267dc35dd63c", size = 2267821, upload-time = "2025-12-12T17:30:38.478Z" }, - { url = "https://files.pythonhosted.org/packages/1a/59/453c06d1d83dc0951b69ef692d6b9f1846680342927df54e9a1ca91c6f90/fonttools-4.61.1-cp313-cp313-win_amd64.whl", hash = "sha256:21e7c8d76f62ab13c9472ccf74515ca5b9a761d1bde3265152a6dc58700d895b", size = 2318169, upload-time = "2025-12-12T17:30:40.951Z" }, - { url = "https://files.pythonhosted.org/packages/32/8f/4e7bf82c0cbb738d3c2206c920ca34ca74ef9dabde779030145d28665104/fonttools-4.61.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fff4f534200a04b4a36e7ae3cb74493afe807b517a09e99cb4faa89a34ed6ecd", size = 2846094, upload-time = "2025-12-12T17:30:43.511Z" }, - { url = "https://files.pythonhosted.org/packages/71/09/d44e45d0a4f3a651f23a1e9d42de43bc643cce2971b19e784cc67d823676/fonttools-4.61.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d9203500f7c63545b4ce3799319fe4d9feb1a1b89b28d3cb5abd11b9dd64147e", size = 2396589, upload-time = "2025-12-12T17:30:45.681Z" }, - { url = "https://files.pythonhosted.org/packages/89/18/58c64cafcf8eb677a99ef593121f719e6dcbdb7d1c594ae5a10d4997ca8a/fonttools-4.61.1-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fa646ecec9528bef693415c79a86e733c70a4965dd938e9a226b0fc64c9d2e6c", size = 4877892, upload-time = "2025-12-12T17:30:47.709Z" }, - { url = "https://files.pythonhosted.org/packages/8a/ec/9e6b38c7ba1e09eb51db849d5450f4c05b7e78481f662c3b79dbde6f3d04/fonttools-4.61.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:11f35ad7805edba3aac1a3710d104592df59f4b957e30108ae0ba6c10b11dd75", size = 4972884, upload-time = "2025-12-12T17:30:49.656Z" }, - { url = "https://files.pythonhosted.org/packages/5e/87/b5339da8e0256734ba0dbbf5b6cdebb1dd79b01dc8c270989b7bcd465541/fonttools-4.61.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b931ae8f62db78861b0ff1ac017851764602288575d65b8e8ff1963fed419063", size = 4924405, upload-time = "2025-12-12T17:30:51.735Z" }, - { url = "https://files.pythonhosted.org/packages/0b/47/e3409f1e1e69c073a3a6fd8cb886eb18c0bae0ee13db2c8d5e7f8495e8b7/fonttools-4.61.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b148b56f5de675ee16d45e769e69f87623a4944f7443850bf9a9376e628a89d2", size = 5035553, upload-time = "2025-12-12T17:30:54.823Z" }, - { url = "https://files.pythonhosted.org/packages/bf/b6/1f6600161b1073a984294c6c031e1a56ebf95b6164249eecf30012bb2e38/fonttools-4.61.1-cp314-cp314-win32.whl", hash = "sha256:9b666a475a65f4e839d3d10473fad6d47e0a9db14a2f4a224029c5bfde58ad2c", size = 2271915, upload-time = "2025-12-12T17:30:57.913Z" }, - { url = "https://files.pythonhosted.org/packages/52/7b/91e7b01e37cc8eb0e1f770d08305b3655e4f002fc160fb82b3390eabacf5/fonttools-4.61.1-cp314-cp314-win_amd64.whl", hash = "sha256:4f5686e1fe5fce75d82d93c47a438a25bf0d1319d2843a926f741140b2b16e0c", size = 2323487, upload-time = "2025-12-12T17:30:59.804Z" }, - { url = "https://files.pythonhosted.org/packages/39/5c/908ad78e46c61c3e3ed70c3b58ff82ab48437faf84ec84f109592cabbd9f/fonttools-4.61.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:e76ce097e3c57c4bcb67c5aa24a0ecdbd9f74ea9219997a707a4061fbe2707aa", size = 2929571, upload-time = "2025-12-12T17:31:02.574Z" }, - { url = "https://files.pythonhosted.org/packages/bd/41/975804132c6dea64cdbfbaa59f3518a21c137a10cccf962805b301ac6ab2/fonttools-4.61.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:9cfef3ab326780c04d6646f68d4b4742aae222e8b8ea1d627c74e38afcbc9d91", size = 2435317, upload-time = "2025-12-12T17:31:04.974Z" }, - { url = "https://files.pythonhosted.org/packages/b0/5a/aef2a0a8daf1ebaae4cfd83f84186d4a72ee08fd6a8451289fcd03ffa8a4/fonttools-4.61.1-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a75c301f96db737e1c5ed5fd7d77d9c34466de16095a266509e13da09751bd19", size = 4882124, upload-time = "2025-12-12T17:31:07.456Z" }, - { url = "https://files.pythonhosted.org/packages/80/33/d6db3485b645b81cea538c9d1c9219d5805f0877fda18777add4671c5240/fonttools-4.61.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:91669ccac46bbc1d09e9273546181919064e8df73488ea087dcac3e2968df9ba", size = 5100391, upload-time = "2025-12-12T17:31:09.732Z" }, - { url = "https://files.pythonhosted.org/packages/6c/d6/675ba631454043c75fcf76f0ca5463eac8eb0666ea1d7badae5fea001155/fonttools-4.61.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c33ab3ca9d3ccd581d58e989d67554e42d8d4ded94ab3ade3508455fe70e65f7", size = 4978800, upload-time = "2025-12-12T17:31:11.681Z" }, - { url = "https://files.pythonhosted.org/packages/7f/33/d3ec753d547a8d2bdaedd390d4a814e8d5b45a093d558f025c6b990b554c/fonttools-4.61.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:664c5a68ec406f6b1547946683008576ef8b38275608e1cee6c061828171c118", size = 5006426, upload-time = "2025-12-12T17:31:13.764Z" }, - { url = "https://files.pythonhosted.org/packages/b4/40/cc11f378b561a67bea850ab50063366a0d1dd3f6d0a30ce0f874b0ad5664/fonttools-4.61.1-cp314-cp314t-win32.whl", hash = "sha256:aed04cabe26f30c1647ef0e8fbb207516fd40fe9472e9439695f5c6998e60ac5", size = 2335377, upload-time = "2025-12-12T17:31:16.49Z" }, - { url = "https://files.pythonhosted.org/packages/e4/ff/c9a2b66b39f8628531ea58b320d66d951267c98c6a38684daa8f50fb02f8/fonttools-4.61.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2180f14c141d2f0f3da43f3a81bc8aa4684860f6b0e6f9e165a4831f24e6a23b", size = 2400613, upload-time = "2025-12-12T17:31:18.769Z" }, - { url = "https://files.pythonhosted.org/packages/c7/4e/ce75a57ff3aebf6fc1f4e9d508b8e5810618a33d900ad6c19eb30b290b97/fonttools-4.61.1-py3-none-any.whl", hash = "sha256:17d2bf5d541add43822bcf0c43d7d847b160c9bb01d15d5007d84e2217aaa371", size = 1148996, upload-time = "2025-12-12T17:31:21.03Z" }, +version = "4.62.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/08/7012b00a9a5874311b639c3920270c36ee0c445b69d9989a85e5c92ebcb0/fonttools-4.62.1.tar.gz", hash = "sha256:e54c75fd6041f1122476776880f7c3c3295ffa31962dc6ebe2543c00dca58b5d", size = 3580737, upload-time = "2026-03-13T13:54:25.52Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/d4/dbacced3953544b9a93088cc10ef2b596d348c983d5c67a404fa41ec51ba/fonttools-4.62.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:90365821debbd7db678809c7491ca4acd1e0779b9624cdc6ddaf1f31992bf974", size = 2870219, upload-time = "2026-03-13T13:52:53.664Z" }, + { url = "https://files.pythonhosted.org/packages/66/9e/a769c8e99b81e5a87ab7e5e7236684de4e96246aae17274e5347d11ebd78/fonttools-4.62.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12859ff0b47dd20f110804c3e0d0970f7b832f561630cd879969011541a464a9", size = 2414891, upload-time = "2026-03-13T13:52:56.493Z" }, + { url = "https://files.pythonhosted.org/packages/69/64/f19a9e3911968c37e1e620e14dfc5778299e1474f72f4e57c5ec771d9489/fonttools-4.62.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c125ffa00c3d9003cdaaf7f2c79e6e535628093e14b5de1dccb08859b680936", size = 5033197, upload-time = "2026-03-13T13:52:59.179Z" }, + { url = "https://files.pythonhosted.org/packages/9b/8a/99c8b3c3888c5c474c08dbfd7c8899786de9604b727fcefb055b42c84bba/fonttools-4.62.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:149f7d84afca659d1a97e39a4778794a2f83bf344c5ee5134e09995086cc2392", size = 4988768, upload-time = "2026-03-13T13:53:02.761Z" }, + { url = "https://files.pythonhosted.org/packages/d1/c6/0f904540d3e6ab463c1243a0d803504826a11604c72dd58c2949796a1762/fonttools-4.62.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0aa72c43a601cfa9273bb1ae0518f1acadc01ee181a6fc60cd758d7fdadffc04", size = 4971512, upload-time = "2026-03-13T13:53:05.678Z" }, + { url = "https://files.pythonhosted.org/packages/29/0b/5cbef6588dc9bd6b5c9ad6a4d5a8ca384d0cea089da31711bbeb4f9654a6/fonttools-4.62.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:19177c8d96c7c36359266e571c5173bcee9157b59cfc8cb0153c5673dc5a3a7d", size = 5122723, upload-time = "2026-03-13T13:53:08.662Z" }, + { url = "https://files.pythonhosted.org/packages/4a/47/b3a5342d381595ef439adec67848bed561ab7fdb1019fa522e82101b7d9c/fonttools-4.62.1-cp312-cp312-win32.whl", hash = "sha256:a24decd24d60744ee8b4679d38e88b8303d86772053afc29b19d23bb8207803c", size = 2281278, upload-time = "2026-03-13T13:53:10.998Z" }, + { url = "https://files.pythonhosted.org/packages/28/b1/0c2ab56a16f409c6c8a68816e6af707827ad5d629634691ff60a52879792/fonttools-4.62.1-cp312-cp312-win_amd64.whl", hash = "sha256:9e7863e10b3de72376280b515d35b14f5eeed639d1aa7824f4cf06779ec65e42", size = 2331414, upload-time = "2026-03-13T13:53:13.992Z" }, + { url = "https://files.pythonhosted.org/packages/3b/56/6f389de21c49555553d6a5aeed5ac9767631497ac836c4f076273d15bd72/fonttools-4.62.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c22b1014017111c401469e3acc5433e6acf6ebcc6aa9efb538a533c800971c79", size = 2865155, upload-time = "2026-03-13T13:53:16.132Z" }, + { url = "https://files.pythonhosted.org/packages/03/c5/0e3966edd5ec668d41dfe418787726752bc07e2f5fd8c8f208615e61fa89/fonttools-4.62.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:68959f5fc58ed4599b44aad161c2837477d7f35f5f79402d97439974faebfebe", size = 2412802, upload-time = "2026-03-13T13:53:18.878Z" }, + { url = "https://files.pythonhosted.org/packages/52/94/e6ac4b44026de7786fe46e3bfa0c87e51d5d70a841054065d49cd62bb909/fonttools-4.62.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef46db46c9447103b8f3ff91e8ba009d5fe181b1920a83757a5762551e32bb68", size = 5013926, upload-time = "2026-03-13T13:53:21.379Z" }, + { url = "https://files.pythonhosted.org/packages/e2/98/8b1e801939839d405f1f122e7d175cebe9aeb4e114f95bfc45e3152af9a7/fonttools-4.62.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6706d1cb1d5e6251a97ad3c1b9347505c5615c112e66047abbef0f8545fa30d1", size = 4964575, upload-time = "2026-03-13T13:53:23.857Z" }, + { url = "https://files.pythonhosted.org/packages/46/76/7d051671e938b1881670528fec69cc4044315edd71a229c7fd712eaa5119/fonttools-4.62.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2e7abd2b1e11736f58c1de27819e1955a53267c21732e78243fa2fa2e5c1e069", size = 4953693, upload-time = "2026-03-13T13:53:26.569Z" }, + { url = "https://files.pythonhosted.org/packages/1f/ae/b41f8628ec0be3c1b934fc12b84f4576a5c646119db4d3bdd76a217c90b5/fonttools-4.62.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:403d28ce06ebfc547fbcb0cb8b7f7cc2f7a2d3e1a67ba9a34b14632df9e080f9", size = 5094920, upload-time = "2026-03-13T13:53:29.329Z" }, + { url = "https://files.pythonhosted.org/packages/f2/f6/53a1e9469331a23dcc400970a27a4caa3d9f6edbf5baab0260285238b884/fonttools-4.62.1-cp313-cp313-win32.whl", hash = "sha256:93c316e0f5301b2adbe6a5f658634307c096fd5aae60a5b3412e4f3e1728ab24", size = 2279928, upload-time = "2026-03-13T13:53:32.352Z" }, + { url = "https://files.pythonhosted.org/packages/38/60/35186529de1db3c01f5ad625bde07c1f576305eab6d86bbda4c58445f721/fonttools-4.62.1-cp313-cp313-win_amd64.whl", hash = "sha256:7aa21ff53e28a9c2157acbc44e5b401149d3c9178107130e82d74ceb500e5056", size = 2330514, upload-time = "2026-03-13T13:53:34.991Z" }, + { url = "https://files.pythonhosted.org/packages/36/f0/2888cdac391807d68d90dcb16ef858ddc1b5309bfc6966195a459dd326e2/fonttools-4.62.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fa1d16210b6b10a826d71bed68dd9ec24a9e218d5a5e2797f37c573e7ec215ca", size = 2864442, upload-time = "2026-03-13T13:53:37.509Z" }, + { url = "https://files.pythonhosted.org/packages/4b/b2/e521803081f8dc35990816b82da6360fa668a21b44da4b53fc9e77efcd62/fonttools-4.62.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:aa69d10ed420d8121118e628ad47d86e4caa79ba37f968597b958f6cceab7eca", size = 2410901, upload-time = "2026-03-13T13:53:40.55Z" }, + { url = "https://files.pythonhosted.org/packages/00/a4/8c3511ff06e53110039358dbbdc1a65d72157a054638387aa2ada300a8b8/fonttools-4.62.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd13b7999d59c5eb1c2b442eb2d0c427cb517a0b7a1f5798fc5c9e003f5ff782", size = 4999608, upload-time = "2026-03-13T13:53:42.798Z" }, + { url = "https://files.pythonhosted.org/packages/28/63/cd0c3b26afe60995a5295f37c246a93d454023726c3261cfbb3559969bb9/fonttools-4.62.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8d337fdd49a79b0d51c4da87bc38169d21c3abbf0c1aa9367eff5c6656fb6dae", size = 4912726, upload-time = "2026-03-13T13:53:45.405Z" }, + { url = "https://files.pythonhosted.org/packages/70/b9/ac677cb07c24c685cf34f64e140617d58789d67a3dd524164b63648c6114/fonttools-4.62.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d241cdc4a67b5431c6d7f115fdf63335222414995e3a1df1a41e1182acd4bcc7", size = 4951422, upload-time = "2026-03-13T13:53:48.326Z" }, + { url = "https://files.pythonhosted.org/packages/e6/10/11c08419a14b85b7ca9a9faca321accccc8842dd9e0b1c8a72908de05945/fonttools-4.62.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c05557a78f8fa514da0f869556eeda40887a8abc77c76ee3f74cf241778afd5a", size = 5060979, upload-time = "2026-03-13T13:53:51.366Z" }, + { url = "https://files.pythonhosted.org/packages/4e/3c/12eea4a4cf054e7ab058ed5ceada43b46809fce2bf319017c4d63ae55bb4/fonttools-4.62.1-cp314-cp314-win32.whl", hash = "sha256:49a445d2f544ce4a69338694cad575ba97b9a75fff02720da0882d1a73f12800", size = 2283733, upload-time = "2026-03-13T13:53:53.606Z" }, + { url = "https://files.pythonhosted.org/packages/6b/67/74b070029043186b5dd13462c958cb7c7f811be0d2e634309d9a1ffb1505/fonttools-4.62.1-cp314-cp314-win_amd64.whl", hash = "sha256:1eecc128c86c552fb963fe846ca4e011b1be053728f798185a1687502f6d398e", size = 2335663, upload-time = "2026-03-13T13:53:56.23Z" }, + { url = "https://files.pythonhosted.org/packages/42/c5/4d2ed3ca6e33617fc5624467da353337f06e7f637707478903c785bd8e20/fonttools-4.62.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:1596aeaddf7f78e21e68293c011316a25267b3effdaccaf4d59bc9159d681b82", size = 2947288, upload-time = "2026-03-13T13:53:59.397Z" }, + { url = "https://files.pythonhosted.org/packages/1f/e9/7ab11ddfda48ed0f89b13380e5595ba572619c27077be0b2c447a63ff351/fonttools-4.62.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:8f8fca95d3bb3208f59626a4b0ea6e526ee51f5a8ad5d91821c165903e8d9260", size = 2449023, upload-time = "2026-03-13T13:54:01.642Z" }, + { url = "https://files.pythonhosted.org/packages/b2/10/a800fa090b5e8819942e54e19b55fc7c21fe14a08757c3aa3ca8db358939/fonttools-4.62.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee91628c08e76f77b533d65feb3fbe6d9dad699f95be51cf0d022db94089cdc4", size = 5137599, upload-time = "2026-03-13T13:54:04.495Z" }, + { url = "https://files.pythonhosted.org/packages/37/dc/8ccd45033fffd74deb6912fa1ca524643f584b94c87a16036855b498a1ed/fonttools-4.62.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5f37df1cac61d906e7b836abe356bc2f34c99d4477467755c216b72aa3dc748b", size = 4920933, upload-time = "2026-03-13T13:54:07.557Z" }, + { url = "https://files.pythonhosted.org/packages/99/eb/e618adefb839598d25ac8136cd577925d6c513dc0d931d93b8af956210f0/fonttools-4.62.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:92bb00a947e666169c99b43753c4305fc95a890a60ef3aeb2a6963e07902cc87", size = 5016232, upload-time = "2026-03-13T13:54:10.611Z" }, + { url = "https://files.pythonhosted.org/packages/d9/5f/9b5c9bfaa8ec82def8d8168c4f13615990d6ce5996fe52bd49bfb5e05134/fonttools-4.62.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:bdfe592802ef939a0e33106ea4a318eeb17822c7ee168c290273cbd5fabd746c", size = 5042987, upload-time = "2026-03-13T13:54:13.569Z" }, + { url = "https://files.pythonhosted.org/packages/90/aa/dfbbe24c6a6afc5c203d90cc0343e24bcbb09e76d67c4d6eef8c2558d7ba/fonttools-4.62.1-cp314-cp314t-win32.whl", hash = "sha256:b820fcb92d4655513d8402d5b219f94481c4443d825b4372c75a2072aa4b357a", size = 2348021, upload-time = "2026-03-13T13:54:16.98Z" }, + { url = "https://files.pythonhosted.org/packages/13/6f/ae9c4e4dd417948407b680855c2c7790efb52add6009aaecff1e3bc50e8e/fonttools-4.62.1-cp314-cp314t-win_amd64.whl", hash = "sha256:59b372b4f0e113d3746b88985f1c796e7bf830dd54b28374cd85c2b8acd7583e", size = 2414147, upload-time = "2026-03-13T13:54:19.416Z" }, + { url = "https://files.pythonhosted.org/packages/fd/ba/56147c165442cc5ba7e82ecf301c9a68353cede498185869e6e02b4c264f/fonttools-4.62.1-py3-none-any.whl", hash = "sha256:7487782e2113861f4ddcc07c3436450659e3caa5e470b27dc2177cade2d8e7fd", size = 1152647, upload-time = "2026-03-13T13:54:22.735Z" }, ] [[package]] @@ -454,42 +489,52 @@ wheels = [ [[package]] name = "highspy" -version = "1.12.0" +version = "1.13.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/32/cc/dc47527beec1f44274186713a59fca13e6e1c71088ed6d18980dc8b90ee9/highspy-1.12.0.tar.gz", hash = "sha256:91a2da2c090597e34cd2cb57a751816ca6857c8cca8b09ae4d33960fb89ad42c", size = 1399992, upload-time = "2025-10-25T18:09:46.242Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6c/69/eacc8742d1a4ac68109a8ce3c808e81cab1c499926815e23dd39106595a3/highspy-1.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8c8b098a57b4035d5bdbffa2a80a96232c99e4d085aa822e283e98c50a1438b8", size = 2212070, upload-time = "2025-10-25T18:08:46.974Z" }, - { url = "https://files.pythonhosted.org/packages/d7/50/25e2adb149b56354aaa31165b44304c85763f66a560e8a1492e09ce6a9a5/highspy-1.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3db2958b934d46c0e112e8f9fdba96bb1fb84cfc6f70ddd4492ea62da890fe56", size = 2029063, upload-time = "2025-10-25T18:08:48.597Z" }, - { url = "https://files.pythonhosted.org/packages/36/0f/9d5b3f27a4bc8ebf4c2a18cd1ef39db77fabd8b007629143416c4d6cd4fd/highspy-1.12.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:ecc5bdee740118e18ce928feaf9e309eb4a4a076f27a6780b8b363f1446801b5", size = 2562998, upload-time = "2025-10-25T18:08:49.968Z" }, - { url = "https://files.pythonhosted.org/packages/3d/b8/901d9702873f6e103a3b9d1a6e8e403b486d4e672e4e925d6bc1a92f8114/highspy-1.12.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f6045d1d49627e1dc2f649cda4190c57c823f0cf71bec9d466363f00abbc65a7", size = 2296309, upload-time = "2025-10-25T18:08:51.651Z" }, - { url = "https://files.pythonhosted.org/packages/26/c7/34fbaacecdc363d847ef9f73ff169447db9728a100ca41c4ad1a4d3fb21a/highspy-1.12.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3a72ecea18c0b2cd041e87599d2e0bf6f96cea7133aba838f0128608089e92f", size = 2500486, upload-time = "2025-10-25T18:08:52.981Z" }, - { url = "https://files.pythonhosted.org/packages/ef/69/46910999e0fa30f85b15b3a3d5a7a16ed5af8763323e351f0ddd7fbcfed3/highspy-1.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1df858cfc71fafef789fe87793e331a17768065f9e9505df1ff10239e4fa6a8d", size = 3355868, upload-time = "2025-10-25T18:08:54.308Z" }, - { url = "https://files.pythonhosted.org/packages/e0/d3/9c1c13e09cd2dd1aed77a897272d974dab36be25bcc27a0af1f704153781/highspy-1.12.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:455b8688d93124b714e93f0787fb17040fcb5b1b90c59684bd44f66b3b947dbc", size = 3918497, upload-time = "2025-10-25T18:08:56.096Z" }, - { url = "https://files.pythonhosted.org/packages/50/f9/6dd6f8694c8f631057199bdbcadbc2078023029021feb9f0dbdbb9b0aed5/highspy-1.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:948db9f948c79a52f5faafeb71cd8990a84b462245bb2c493d3e16938f038782", size = 3581509, upload-time = "2025-10-25T18:08:57.862Z" }, - { url = "https://files.pythonhosted.org/packages/d2/87/24074f2bdb92b194d2c625a1071241a9bf23f475db850331b4256bda047f/highspy-1.12.0-cp312-cp312-win32.whl", hash = "sha256:869bdcedd7c309647efef2d4968dc05609815b537f8ccd8144ec2b81c0801a8b", size = 1843171, upload-time = "2025-10-25T18:08:59.195Z" }, - { url = "https://files.pythonhosted.org/packages/6c/48/ae627c5b16e2ae0f56537b25e6176e1e7db8ea26ea85fab047518979be2f/highspy-1.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:90c3f9d575a93f0e08490f101b72b8597c7d1ad801d429f31b6ae962a1492a56", size = 2183875, upload-time = "2025-10-25T18:09:00.525Z" }, - { url = "https://files.pythonhosted.org/packages/c7/80/81269c182ee4dc36e3add646088d027cc87a6cabe640901848b1dc9b1355/highspy-1.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:79a346e811e330fb757a96e3a234b71b5d58ace44e1eba9611b13c2b6efaf0e9", size = 2212158, upload-time = "2025-10-25T18:09:01.834Z" }, - { url = "https://files.pythonhosted.org/packages/00/bd/ac5d300201f1ad8581c5b468ed1608ecd47e1e9d88a74cdaebf0cf74ae65/highspy-1.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:57512dc19e18e2daa572acc0ea9561a5c4050d592d21f6db3f8367dd38e50362", size = 2029098, upload-time = "2025-10-25T18:09:03.132Z" }, - { url = "https://files.pythonhosted.org/packages/be/cc/3ed5a545ce807fb9c4a1e28e83ee474c560bc1a83335c791127a113f634b/highspy-1.12.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:a856e6e33d6d20d177fdc1a6eb34b3b58385a6c757a05695c4b214a5c377e044", size = 2562864, upload-time = "2025-10-25T18:09:04.478Z" }, - { url = "https://files.pythonhosted.org/packages/3c/d9/f2f409200654a64759e8970533315364ebae1dc1c90e3aa71127804abf5a/highspy-1.12.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:550ddee715934937da6cfe58f7adceca86b0847e5f8ebd7429cc275218179b95", size = 2296446, upload-time = "2025-10-25T18:09:05.869Z" }, - { url = "https://files.pythonhosted.org/packages/6d/cd/e9441001cb3e523ac620982af75d7900b702f97f08656797cec2a8db6222/highspy-1.12.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a5c58dbd6170073f4ba1bd31e0c7b276404d1456080cb190ed51b4c817629d6", size = 2500363, upload-time = "2025-10-25T18:09:07.214Z" }, - { url = "https://files.pythonhosted.org/packages/25/58/92b5849a2150db172a1b17ddf165b5aeda8871eabb59efd9f2c1df025b33/highspy-1.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a112865dbaace2c9b7e2234bd4415dd6f2b31cb53b53d007d3e53fc3ebfdd387", size = 3356311, upload-time = "2025-10-25T18:09:08.509Z" }, - { url = "https://files.pythonhosted.org/packages/9d/c8/04b6bcbb0c9cc09efd6370ba3e6afc7aaf3b6a2f61f415ace8d223328506/highspy-1.12.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:32f970c5d35fb6f92ef40a21b27faa9f348783a1de119facd0ee8dbfa52ef478", size = 3917867, upload-time = "2025-10-25T18:09:09.848Z" }, - { url = "https://files.pythonhosted.org/packages/51/c5/2c1b386a219eea79af16ee29435d940baccf159ca26647715d330868aba0/highspy-1.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:aa040786e1a321e2703834dd5bedf23d6998d6b42984c4b14e157036da655fd0", size = 3581079, upload-time = "2025-10-25T18:09:11.329Z" }, - { url = "https://files.pythonhosted.org/packages/b6/47/3d27048c6a640326f314e2b5c8b3d80ef8459633413a08a90336b56b1e2f/highspy-1.12.0-cp313-cp313-win32.whl", hash = "sha256:adb1735c625e164d1cc114a74f0628cea944b5f4a346ba0726386edbaa838479", size = 1843105, upload-time = "2025-10-25T18:09:12.774Z" }, - { url = "https://files.pythonhosted.org/packages/f0/20/3b36ca44864baced84355aa37c1b66e95d46009a74887fead515ccff88b1/highspy-1.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:dd826ca82035d125ad3f59ed62878ca2676db1c66870e2b55e025adfa9f9e785", size = 2183790, upload-time = "2025-10-25T18:09:14.559Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/f3/17/74553587944f514142618c6d1b76551acf09fb0dd48abe9f4c37fb7d2bb8/highspy-1.13.1.tar.gz", hash = "sha256:7888873501c6ca3e0fa19fee960c8b3cb1c64132c5a9b514903cc7e259b5b0c7", size = 1597930, upload-time = "2026-02-11T16:39:55.185Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/9f/98a103b443e42755aa4e63800d6a517a928e32f28c40ff2ecce7d9c4e20a/highspy-1.13.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:31f9f7001b9a6afd1cb06e5f3ad24848aa0df78a32b004538f2630535a881e7d", size = 2240384, upload-time = "2026-02-11T16:38:24.765Z" }, + { url = "https://files.pythonhosted.org/packages/8e/98/920115e7e451e20a2a84e3fec4f5ade6760561d96a001ee8c87886331b9a/highspy-1.13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce77b3771c20715e4552b890b9a2f4eee33faf1bd86ab08c6a7b00424ebe12b3", size = 2051929, upload-time = "2026-02-11T16:38:26.235Z" }, + { url = "https://files.pythonhosted.org/packages/f5/6b/9efc679003ff5d10cbf88e02deb47c7095b2e23d700eea895a4faecf1dcc/highspy-1.13.1-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f469f0a340870e1f16324a096dead3775857470b7e9d552b08a878a945f34917", size = 2321820, upload-time = "2026-02-11T16:38:27.75Z" }, + { url = "https://files.pythonhosted.org/packages/ee/ad/be6847577282389a5b8ab4ef6bee71c5ccb2383c84a123561b4e538449b7/highspy-1.13.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f00b426b09e28306b279645beec2f892dd652ad41ec1597b742865bb844dd38d", size = 2525364, upload-time = "2026-02-11T16:38:29.152Z" }, + { url = "https://files.pythonhosted.org/packages/70/83/6c72c558c3bed2a06b3d850943621376116f374949bc77f2b353995cfba9/highspy-1.13.1-cp312-cp312-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:dce26ba2926612847be6d3e01ee98df2af8472a99de8ad9dc562060f6c8e5d0a", size = 2696833, upload-time = "2026-02-11T16:38:30.65Z" }, + { url = "https://files.pythonhosted.org/packages/1e/94/376940d949547d5bfdd68a86b0631d8c2fd86a7fd771c93a23c683be1293/highspy-1.13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:506038db5c4732a4b65755aa63f580cef91e1a99a5d1399e311dc31d3300dadd", size = 3382720, upload-time = "2026-02-11T16:38:32.135Z" }, + { url = "https://files.pythonhosted.org/packages/fd/8d/6ecee935e5f57df9fbe9fedfcac14e4ac76186335595bf201f86302a7379/highspy-1.13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:eda07ca3ec5506d279679d775dedc447fbcc3711814c5f2e22d2d063598586af", size = 3943880, upload-time = "2026-02-11T16:38:33.544Z" }, + { url = "https://files.pythonhosted.org/packages/a5/7b/524d977387e3ff3eba165feb81614ead36a7974c0f8d9948f8d9347f74ff/highspy-1.13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce9481fb96771c3b74592e1a94cc8dc2748d18eafb0bad6a03ebca5f4cfaa8fd", size = 3610040, upload-time = "2026-02-11T16:38:35.582Z" }, + { url = "https://files.pythonhosted.org/packages/99/89/3133cc87d13399f66250f9e2ff0592c72a42edae945d27ec1dfadf009ebd/highspy-1.13.1-cp312-cp312-win32.whl", hash = "sha256:0a10b8d7bc6a2a50226bc6821f21ed5f456479950271e742aff8bc97412c4591", size = 1888436, upload-time = "2026-02-11T16:38:37.327Z" }, + { url = "https://files.pythonhosted.org/packages/2a/50/0c6986b87cc373dc9e9eb6254508f0f77bb4de897ae1d2a8c7e6ae70ef6c/highspy-1.13.1-cp312-cp312-win_amd64.whl", hash = "sha256:26f023093ed2fa2407f12a4a7dc9c1de253cd14228874e58e6719d78a74e2a9c", size = 2231427, upload-time = "2026-02-11T16:38:38.805Z" }, + { url = "https://files.pythonhosted.org/packages/86/4b/77e7f6b936dc130eb4dc78e64bb75d15940232027f519a7bb6564c91153b/highspy-1.13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0a255204f4ec79f5e447765d745e41bf3115a6c196ecfab5ed636d1ff53c0401", size = 2240587, upload-time = "2026-02-11T16:38:40.249Z" }, + { url = "https://files.pythonhosted.org/packages/6a/5c/8a57a0f2d18bd9fb88f64c87c11882defe90832361ecd4f612b36d1c5f05/highspy-1.13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cbb7509b5606a1ac7bc1fff794cebeb668f43531678f898803c12cbb694bea61", size = 2052178, upload-time = "2026-02-11T16:38:41.628Z" }, + { url = "https://files.pythonhosted.org/packages/5d/d8/fec866c1a48e98897f6348a303fa565dc00fd29e5fb90e6befe1e1ead12b/highspy-1.13.1-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e2e572c9ec5eb0fd5d178690981116413f277cb59d150bf271d927161335df23", size = 2321460, upload-time = "2026-02-11T16:38:43.04Z" }, + { url = "https://files.pythonhosted.org/packages/24/6f/3bfec9e2a0ff3adc20d3ae071572ae473f810c35e04a7455abf278623932/highspy-1.13.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e577ff0fdeccc7e207be8577dd8b223816d024c40c1b7af4afb6e96818f4544b", size = 2525308, upload-time = "2026-02-11T16:38:44.631Z" }, + { url = "https://files.pythonhosted.org/packages/33/7b/b21a2dffca27742a50c48e88b3c850b1a212506543ec7b38a5f843a689e0/highspy-1.13.1-cp313-cp313-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:dc8677bb6da2216fd72110d95d904022bf3150832441eb08562bdb8d2c5aeb6c", size = 2696881, upload-time = "2026-02-11T16:38:47.498Z" }, + { url = "https://files.pythonhosted.org/packages/ea/cc/793b6819c1a8d360b8a536f62526d3bb54a3ba8deaf3b0ba7d4076e56da3/highspy-1.13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3ec5adcef1028b40ae6d76d03c24b512c5f33849c5e09b70c15734b0e48c68ca", size = 3382687, upload-time = "2026-02-11T16:38:49.18Z" }, + { url = "https://files.pythonhosted.org/packages/18/13/20bbbf7a20779d799565ab4ce9c9f80ad39eeeb069b2a91e1fd5dece3109/highspy-1.13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1a435dd11fcefab2e9e0ad90d75a459a656b177ef3d1173b31db889808580e92", size = 3943115, upload-time = "2026-02-11T16:38:50.761Z" }, + { url = "https://files.pythonhosted.org/packages/02/df/1c37558d33e52376822136c3288b65d74cb0482da841904dc5ec89540dc4/highspy-1.13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0f473e94b19c186fda0abed1e31d3682ac4a9109930e77a1901c63f1b3d7d772", size = 3610136, upload-time = "2026-02-11T16:38:52.724Z" }, + { url = "https://files.pythonhosted.org/packages/27/e3/094bae0233275f5d293c40598a97a7ec8b0dee61572d5c2086aec8e35056/highspy-1.13.1-cp313-cp313-win32.whl", hash = "sha256:1464ed94e467de3cc20fdf3779609dd13aa91db8d11305b1d8f6a029ae129f33", size = 1888446, upload-time = "2026-02-11T16:38:54.341Z" }, + { url = "https://files.pythonhosted.org/packages/e2/15/d9be1b1f22ecafedddbf504b3c63b7e4a17a710e3b45f615be1869160938/highspy-1.13.1-cp313-cp313-win_amd64.whl", hash = "sha256:620fad11a92517d525300ad70f27f84f41e8c0af10ece5ae5537f2be13ae0970", size = 2231418, upload-time = "2026-02-11T16:38:56.499Z" }, + { url = "https://files.pythonhosted.org/packages/92/70/22dc5ae52b9a4a13658a3a9c3b9909ae9aecaee4f579c1996096f8f19a75/highspy-1.13.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:0868538ce474be93219013fa242fe3ddf0859562e3b354b50786da03c96b941a", size = 2240675, upload-time = "2026-02-11T16:38:57.971Z" }, + { url = "https://files.pythonhosted.org/packages/b3/1a/426dddf9a838a54d09d6658b97bd843e41e1db4e21c5d6839b17578d672f/highspy-1.13.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d3f38a68783d690a4fe14521fbad18cbeae6121e1785f1dbdf5c045bcb35a926", size = 2050718, upload-time = "2026-02-11T16:38:59.479Z" }, + { url = "https://files.pythonhosted.org/packages/50/4b/a33a1bc2a7d40247bd0921fabdafa06b8af196c2ab01418eabf305d179c6/highspy-1.13.1-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:edf109c83d1488e0305f8fce88b9a3fc4fa7655b0b72c6cdb4437bad2a4a7fc0", size = 2322273, upload-time = "2026-02-11T16:39:01.534Z" }, + { url = "https://files.pythonhosted.org/packages/75/68/8d197789a73714ae81fc0923f0bdc415eae9dff1fa2d65a999a329a5de72/highspy-1.13.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56cb459c01696c83d2d65057e03df2cb809fb9cc9357f91d30b1af192765d809", size = 2529809, upload-time = "2026-02-11T16:39:03.359Z" }, + { url = "https://files.pythonhosted.org/packages/07/77/ed99d26ec450676b764eae89247e1ef5b194ecf5f0979ca6101f04573d0b/highspy-1.13.1-cp314-cp314-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:aada6027a92401967476b93ce10f13c0d7c45aedfb322c8049b5d2672fbce5a8", size = 2694699, upload-time = "2026-02-11T16:39:05.182Z" }, + { url = "https://files.pythonhosted.org/packages/54/b9/b51d716f2fea045f2de6cfae29b9e3bdf7d095668e565e2be3fccdf0d281/highspy-1.13.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d2072f3a303b9ac988e9e37b5d7942cbba8c9fce7a323357122429c1a85c344b", size = 3383641, upload-time = "2026-02-11T16:39:07.107Z" }, + { url = "https://files.pythonhosted.org/packages/ab/22/3dc1fc494c190ad5e6e0dad9758c915cdf4df0bdfdd19d7d12ac975e9833/highspy-1.13.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:755d924e7650703e217debd69f566da078cdf7f9bd957ccd88c3be134c63c8f5", size = 3943007, upload-time = "2026-02-11T16:39:09.509Z" }, + { url = "https://files.pythonhosted.org/packages/79/20/e084a47336416ed02efd64e6a68b41c3ad3867a38c460dd9a1d14837f366/highspy-1.13.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:516c5b5a7d01d7c073206f787316c60f4800994cf3a947031f336e737177f6cc", size = 3613402, upload-time = "2026-02-11T16:39:11.945Z" }, + { url = "https://files.pythonhosted.org/packages/ea/66/e72cc05b0fc8b31b7d2992fbf386e54cd217bc2a6c202fec97a37d2fb97f/highspy-1.13.1-cp314-cp314-win32.whl", hash = "sha256:4cfff7f50615a588a760b33cd2dd37761679b400196213015230db1cd6c46232", size = 1930483, upload-time = "2026-02-11T16:39:13.7Z" }, + { url = "https://files.pythonhosted.org/packages/30/6c/7abf63f02302d64934d9decd04939334db1938917f552059570ea27b41b3/highspy-1.13.1-cp314-cp314-win_amd64.whl", hash = "sha256:242d00f46b09c9d6f077881739d7487030a9ed2c56bcd28f3e8d5942da407df4", size = 2313528, upload-time = "2026-02-11T16:39:15.765Z" }, ] [[package]] name = "identify" -version = "2.6.16" +version = "2.6.18" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5b/8d/e8b97e6bd3fb6fb271346f7981362f1e04d6a7463abd0de79e1fda17c067/identify-2.6.16.tar.gz", hash = "sha256:846857203b5511bbe94d5a352a48ef2359532bc8f6727b5544077a0dcfb24980", size = 99360, upload-time = "2026-01-12T18:58:58.201Z" } +sdist = { url = "https://files.pythonhosted.org/packages/46/c4/7fb4db12296cdb11893d61c92048fe617ee853f8523b9b296ac03b43757e/identify-2.6.18.tar.gz", hash = "sha256:873ac56a5e3fd63e7438a7ecbc4d91aca692eb3fefa4534db2b7913f3fc352fd", size = 99580, upload-time = "2026-03-15T18:39:50.319Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/58/40fbbcefeda82364720eba5cf2270f98496bdfa19ea75b4cccae79c698e6/identify-2.6.16-py2.py3-none-any.whl", hash = "sha256:391ee4d77741d994189522896270b787aed8670389bfd60f326d677d64a6dfb0", size = 99202, upload-time = "2026-01-12T18:58:56.627Z" }, + { url = "https://files.pythonhosted.org/packages/46/33/92ef41c6fad0233e41d3d84ba8e8ad18d1780f1e5d99b3c683e6d7f98b63/identify-2.6.18-py2.py3-none-any.whl", hash = "sha256:8db9d3c8ea9079db92cafb0ebf97abdc09d52e97f4dcf773a2e694048b7cd737", size = 99394, upload-time = "2026-03-15T18:39:48.915Z" }, ] [[package]] @@ -503,11 +548,11 @@ wheels = [ [[package]] name = "imagesize" -version = "1.4.1" +version = "2.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026, upload-time = "2022-07-01T12:21:05.687Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/e6/7bf14eeb8f8b7251141944835abd42eb20a658d89084b7e1f3e5fe394090/imagesize-2.0.0.tar.gz", hash = "sha256:8e8358c4a05c304f1fccf7ff96f036e7243a189e9e42e90851993c558cfe9ee3", size = 1773045, upload-time = "2026-03-03T14:18:29.941Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769, upload-time = "2022-07-01T12:21:02.467Z" }, + { url = "https://files.pythonhosted.org/packages/5f/53/fb7122b71361a0d121b669dcf3d31244ef75badbbb724af388948de543e2/imagesize-2.0.0-py2.py3-none-any.whl", hash = "sha256:5667c5bbb57ab3f1fa4bc366f4fbc971db3d5ed011fd2715fd8001f782718d96", size = 9441, upload-time = "2026-03-03T14:18:27.892Z" }, ] [[package]] @@ -542,74 +587,88 @@ wheels = [ [[package]] name = "kiwisolver" -version = "1.4.9" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564, upload-time = "2025-08-10T21:27:49.279Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/c9/13573a747838aeb1c76e3267620daa054f4152444d1f3d1a2324b78255b5/kiwisolver-1.4.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ac5a486ac389dddcc5bef4f365b6ae3ffff2c433324fb38dd35e3fab7c957999", size = 123686, upload-time = "2025-08-10T21:26:10.034Z" }, - { url = "https://files.pythonhosted.org/packages/51/ea/2ecf727927f103ffd1739271ca19c424d0e65ea473fbaeea1c014aea93f6/kiwisolver-1.4.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2ba92255faa7309d06fe44c3a4a97efe1c8d640c2a79a5ef728b685762a6fd2", size = 66460, upload-time = "2025-08-10T21:26:11.083Z" }, - { url = "https://files.pythonhosted.org/packages/5b/5a/51f5464373ce2aeb5194508298a508b6f21d3867f499556263c64c621914/kiwisolver-1.4.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a2899935e724dd1074cb568ce7ac0dce28b2cd6ab539c8e001a8578eb106d14", size = 64952, upload-time = "2025-08-10T21:26:12.058Z" }, - { url = "https://files.pythonhosted.org/packages/70/90/6d240beb0f24b74371762873e9b7f499f1e02166a2d9c5801f4dbf8fa12e/kiwisolver-1.4.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f6008a4919fdbc0b0097089f67a1eb55d950ed7e90ce2cc3e640abadd2757a04", size = 1474756, upload-time = "2025-08-10T21:26:13.096Z" }, - { url = "https://files.pythonhosted.org/packages/12/42/f36816eaf465220f683fb711efdd1bbf7a7005a2473d0e4ed421389bd26c/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:67bb8b474b4181770f926f7b7d2f8c0248cbcb78b660fdd41a47054b28d2a752", size = 1276404, upload-time = "2025-08-10T21:26:14.457Z" }, - { url = "https://files.pythonhosted.org/packages/2e/64/bc2de94800adc830c476dce44e9b40fd0809cddeef1fde9fcf0f73da301f/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2327a4a30d3ee07d2fbe2e7933e8a37c591663b96ce42a00bc67461a87d7df77", size = 1294410, upload-time = "2025-08-10T21:26:15.73Z" }, - { url = "https://files.pythonhosted.org/packages/5f/42/2dc82330a70aa8e55b6d395b11018045e58d0bb00834502bf11509f79091/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7a08b491ec91b1d5053ac177afe5290adacf1f0f6307d771ccac5de30592d198", size = 1343631, upload-time = "2025-08-10T21:26:17.045Z" }, - { url = "https://files.pythonhosted.org/packages/22/fd/f4c67a6ed1aab149ec5a8a401c323cee7a1cbe364381bb6c9c0d564e0e20/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d8fc5c867c22b828001b6a38d2eaeb88160bf5783c6cb4a5e440efc981ce286d", size = 2224963, upload-time = "2025-08-10T21:26:18.737Z" }, - { url = "https://files.pythonhosted.org/packages/45/aa/76720bd4cb3713314677d9ec94dcc21ced3f1baf4830adde5bb9b2430a5f/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3b3115b2581ea35bb6d1f24a4c90af37e5d9b49dcff267eeed14c3893c5b86ab", size = 2321295, upload-time = "2025-08-10T21:26:20.11Z" }, - { url = "https://files.pythonhosted.org/packages/80/19/d3ec0d9ab711242f56ae0dc2fc5d70e298bb4a1f9dfab44c027668c673a1/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:858e4c22fb075920b96a291928cb7dea5644e94c0ee4fcd5af7e865655e4ccf2", size = 2487987, upload-time = "2025-08-10T21:26:21.49Z" }, - { url = "https://files.pythonhosted.org/packages/39/e9/61e4813b2c97e86b6fdbd4dd824bf72d28bcd8d4849b8084a357bc0dd64d/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ed0fecd28cc62c54b262e3736f8bb2512d8dcfdc2bcf08be5f47f96bf405b145", size = 2291817, upload-time = "2025-08-10T21:26:22.812Z" }, - { url = "https://files.pythonhosted.org/packages/a0/41/85d82b0291db7504da3c2defe35c9a8a5c9803a730f297bd823d11d5fb77/kiwisolver-1.4.9-cp312-cp312-win_amd64.whl", hash = "sha256:f68208a520c3d86ea51acf688a3e3002615a7f0238002cccc17affecc86a8a54", size = 73895, upload-time = "2025-08-10T21:26:24.37Z" }, - { url = "https://files.pythonhosted.org/packages/e2/92/5f3068cf15ee5cb624a0c7596e67e2a0bb2adee33f71c379054a491d07da/kiwisolver-1.4.9-cp312-cp312-win_arm64.whl", hash = "sha256:2c1a4f57df73965f3f14df20b80ee29e6a7930a57d2d9e8491a25f676e197c60", size = 64992, upload-time = "2025-08-10T21:26:25.732Z" }, - { url = "https://files.pythonhosted.org/packages/31/c1/c2686cda909742ab66c7388e9a1a8521a59eb89f8bcfbee28fc980d07e24/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5d0432ccf1c7ab14f9949eec60c5d1f924f17c037e9f8b33352fa05799359b8", size = 123681, upload-time = "2025-08-10T21:26:26.725Z" }, - { url = "https://files.pythonhosted.org/packages/ca/f0/f44f50c9f5b1a1860261092e3bc91ecdc9acda848a8b8c6abfda4a24dd5c/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efb3a45b35622bb6c16dbfab491a8f5a391fe0e9d45ef32f4df85658232ca0e2", size = 66464, upload-time = "2025-08-10T21:26:27.733Z" }, - { url = "https://files.pythonhosted.org/packages/2d/7a/9d90a151f558e29c3936b8a47ac770235f436f2120aca41a6d5f3d62ae8d/kiwisolver-1.4.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a12cf6398e8a0a001a059747a1cbf24705e18fe413bc22de7b3d15c67cffe3f", size = 64961, upload-time = "2025-08-10T21:26:28.729Z" }, - { url = "https://files.pythonhosted.org/packages/e9/e9/f218a2cb3a9ffbe324ca29a9e399fa2d2866d7f348ec3a88df87fc248fc5/kiwisolver-1.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b67e6efbf68e077dd71d1a6b37e43e1a99d0bff1a3d51867d45ee8908b931098", size = 1474607, upload-time = "2025-08-10T21:26:29.798Z" }, - { url = "https://files.pythonhosted.org/packages/d9/28/aac26d4c882f14de59041636292bc838db8961373825df23b8eeb807e198/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5656aa670507437af0207645273ccdfee4f14bacd7f7c67a4306d0dcaeaf6eed", size = 1276546, upload-time = "2025-08-10T21:26:31.401Z" }, - { url = "https://files.pythonhosted.org/packages/8b/ad/8bfc1c93d4cc565e5069162f610ba2f48ff39b7de4b5b8d93f69f30c4bed/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bfc08add558155345129c7803b3671cf195e6a56e7a12f3dde7c57d9b417f525", size = 1294482, upload-time = "2025-08-10T21:26:32.721Z" }, - { url = "https://files.pythonhosted.org/packages/da/f1/6aca55ff798901d8ce403206d00e033191f63d82dd708a186e0ed2067e9c/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:40092754720b174e6ccf9e845d0d8c7d8e12c3d71e7fc35f55f3813e96376f78", size = 1343720, upload-time = "2025-08-10T21:26:34.032Z" }, - { url = "https://files.pythonhosted.org/packages/d1/91/eed031876c595c81d90d0f6fc681ece250e14bf6998c3d7c419466b523b7/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:497d05f29a1300d14e02e6441cf0f5ee81c1ff5a304b0d9fb77423974684e08b", size = 2224907, upload-time = "2025-08-10T21:26:35.824Z" }, - { url = "https://files.pythonhosted.org/packages/e9/ec/4d1925f2e49617b9cca9c34bfa11adefad49d00db038e692a559454dfb2e/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdd1a81a1860476eb41ac4bc1e07b3f07259e6d55bbf739b79c8aaedcf512799", size = 2321334, upload-time = "2025-08-10T21:26:37.534Z" }, - { url = "https://files.pythonhosted.org/packages/43/cb/450cd4499356f68802750c6ddc18647b8ea01ffa28f50d20598e0befe6e9/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e6b93f13371d341afee3be9f7c5964e3fe61d5fa30f6a30eb49856935dfe4fc3", size = 2488313, upload-time = "2025-08-10T21:26:39.191Z" }, - { url = "https://files.pythonhosted.org/packages/71/67/fc76242bd99f885651128a5d4fa6083e5524694b7c88b489b1b55fdc491d/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d75aa530ccfaa593da12834b86a0724f58bff12706659baa9227c2ccaa06264c", size = 2291970, upload-time = "2025-08-10T21:26:40.828Z" }, - { url = "https://files.pythonhosted.org/packages/75/bd/f1a5d894000941739f2ae1b65a32892349423ad49c2e6d0771d0bad3fae4/kiwisolver-1.4.9-cp313-cp313-win_amd64.whl", hash = "sha256:dd0a578400839256df88c16abddf9ba14813ec5f21362e1fe65022e00c883d4d", size = 73894, upload-time = "2025-08-10T21:26:42.33Z" }, - { url = "https://files.pythonhosted.org/packages/95/38/dce480814d25b99a391abbddadc78f7c117c6da34be68ca8b02d5848b424/kiwisolver-1.4.9-cp313-cp313-win_arm64.whl", hash = "sha256:d4188e73af84ca82468f09cadc5ac4db578109e52acb4518d8154698d3a87ca2", size = 64995, upload-time = "2025-08-10T21:26:43.889Z" }, - { url = "https://files.pythonhosted.org/packages/e2/37/7d218ce5d92dadc5ebdd9070d903e0c7cf7edfe03f179433ac4d13ce659c/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:5a0f2724dfd4e3b3ac5a82436a8e6fd16baa7d507117e4279b660fe8ca38a3a1", size = 126510, upload-time = "2025-08-10T21:26:44.915Z" }, - { url = "https://files.pythonhosted.org/packages/23/b0/e85a2b48233daef4b648fb657ebbb6f8367696a2d9548a00b4ee0eb67803/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1b11d6a633e4ed84fc0ddafd4ebfd8ea49b3f25082c04ad12b8315c11d504dc1", size = 67903, upload-time = "2025-08-10T21:26:45.934Z" }, - { url = "https://files.pythonhosted.org/packages/44/98/f2425bc0113ad7de24da6bb4dae1343476e95e1d738be7c04d31a5d037fd/kiwisolver-1.4.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61874cdb0a36016354853593cffc38e56fc9ca5aa97d2c05d3dcf6922cd55a11", size = 66402, upload-time = "2025-08-10T21:26:47.101Z" }, - { url = "https://files.pythonhosted.org/packages/98/d8/594657886df9f34c4177cc353cc28ca7e6e5eb562d37ccc233bff43bbe2a/kiwisolver-1.4.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:60c439763a969a6af93b4881db0eed8fadf93ee98e18cbc35bc8da868d0c4f0c", size = 1582135, upload-time = "2025-08-10T21:26:48.665Z" }, - { url = "https://files.pythonhosted.org/packages/5c/c6/38a115b7170f8b306fc929e166340c24958347308ea3012c2b44e7e295db/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92a2f997387a1b79a75e7803aa7ded2cfbe2823852ccf1ba3bcf613b62ae3197", size = 1389409, upload-time = "2025-08-10T21:26:50.335Z" }, - { url = "https://files.pythonhosted.org/packages/bf/3b/e04883dace81f24a568bcee6eb3001da4ba05114afa622ec9b6fafdc1f5e/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31d512c812daea6d8b3be3b2bfcbeb091dbb09177706569bcfc6240dcf8b41c", size = 1401763, upload-time = "2025-08-10T21:26:51.867Z" }, - { url = "https://files.pythonhosted.org/packages/9f/80/20ace48e33408947af49d7d15c341eaee69e4e0304aab4b7660e234d6288/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:52a15b0f35dad39862d376df10c5230155243a2c1a436e39eb55623ccbd68185", size = 1453643, upload-time = "2025-08-10T21:26:53.592Z" }, - { url = "https://files.pythonhosted.org/packages/64/31/6ce4380a4cd1f515bdda976a1e90e547ccd47b67a1546d63884463c92ca9/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a30fd6fdef1430fd9e1ba7b3398b5ee4e2887783917a687d86ba69985fb08748", size = 2330818, upload-time = "2025-08-10T21:26:55.051Z" }, - { url = "https://files.pythonhosted.org/packages/fa/e9/3f3fcba3bcc7432c795b82646306e822f3fd74df0ee81f0fa067a1f95668/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cc9617b46837c6468197b5945e196ee9ca43057bb7d9d1ae688101e4e1dddf64", size = 2419963, upload-time = "2025-08-10T21:26:56.421Z" }, - { url = "https://files.pythonhosted.org/packages/99/43/7320c50e4133575c66e9f7dadead35ab22d7c012a3b09bb35647792b2a6d/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:0ab74e19f6a2b027ea4f845a78827969af45ce790e6cb3e1ebab71bdf9f215ff", size = 2594639, upload-time = "2025-08-10T21:26:57.882Z" }, - { url = "https://files.pythonhosted.org/packages/65/d6/17ae4a270d4a987ef8a385b906d2bdfc9fce502d6dc0d3aea865b47f548c/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dba5ee5d3981160c28d5490f0d1b7ed730c22470ff7f6cc26cfcfaacb9896a07", size = 2391741, upload-time = "2025-08-10T21:26:59.237Z" }, - { url = "https://files.pythonhosted.org/packages/2a/8f/8f6f491d595a9e5912971f3f863d81baddccc8a4d0c3749d6a0dd9ffc9df/kiwisolver-1.4.9-cp313-cp313t-win_arm64.whl", hash = "sha256:0749fd8f4218ad2e851e11cc4dc05c7cbc0cbc4267bdfdb31782e65aace4ee9c", size = 68646, upload-time = "2025-08-10T21:27:00.52Z" }, - { url = "https://files.pythonhosted.org/packages/6b/32/6cc0fbc9c54d06c2969faa9c1d29f5751a2e51809dd55c69055e62d9b426/kiwisolver-1.4.9-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9928fe1eb816d11ae170885a74d074f57af3a0d65777ca47e9aeb854a1fba386", size = 123806, upload-time = "2025-08-10T21:27:01.537Z" }, - { url = "https://files.pythonhosted.org/packages/b2/dd/2bfb1d4a4823d92e8cbb420fe024b8d2167f72079b3bb941207c42570bdf/kiwisolver-1.4.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d0005b053977e7b43388ddec89fa567f43d4f6d5c2c0affe57de5ebf290dc552", size = 66605, upload-time = "2025-08-10T21:27:03.335Z" }, - { url = "https://files.pythonhosted.org/packages/f7/69/00aafdb4e4509c2ca6064646cba9cd4b37933898f426756adb2cb92ebbed/kiwisolver-1.4.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2635d352d67458b66fd0667c14cb1d4145e9560d503219034a18a87e971ce4f3", size = 64925, upload-time = "2025-08-10T21:27:04.339Z" }, - { url = "https://files.pythonhosted.org/packages/43/dc/51acc6791aa14e5cb6d8a2e28cefb0dc2886d8862795449d021334c0df20/kiwisolver-1.4.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:767c23ad1c58c9e827b649a9ab7809fd5fd9db266a9cf02b0e926ddc2c680d58", size = 1472414, upload-time = "2025-08-10T21:27:05.437Z" }, - { url = "https://files.pythonhosted.org/packages/3d/bb/93fa64a81db304ac8a246f834d5094fae4b13baf53c839d6bb6e81177129/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72d0eb9fba308b8311685c2268cf7d0a0639a6cd027d8128659f72bdd8a024b4", size = 1281272, upload-time = "2025-08-10T21:27:07.063Z" }, - { url = "https://files.pythonhosted.org/packages/70/e6/6df102916960fb8d05069d4bd92d6d9a8202d5a3e2444494e7cd50f65b7a/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f68e4f3eeca8fb22cc3d731f9715a13b652795ef657a13df1ad0c7dc0e9731df", size = 1298578, upload-time = "2025-08-10T21:27:08.452Z" }, - { url = "https://files.pythonhosted.org/packages/7c/47/e142aaa612f5343736b087864dbaebc53ea8831453fb47e7521fa8658f30/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d84cd4061ae292d8ac367b2c3fa3aad11cb8625a95d135fe93f286f914f3f5a6", size = 1345607, upload-time = "2025-08-10T21:27:10.125Z" }, - { url = "https://files.pythonhosted.org/packages/54/89/d641a746194a0f4d1a3670fb900d0dbaa786fb98341056814bc3f058fa52/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a60ea74330b91bd22a29638940d115df9dc00af5035a9a2a6ad9399ffb4ceca5", size = 2230150, upload-time = "2025-08-10T21:27:11.484Z" }, - { url = "https://files.pythonhosted.org/packages/aa/6b/5ee1207198febdf16ac11f78c5ae40861b809cbe0e6d2a8d5b0b3044b199/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ce6a3a4e106cf35c2d9c4fa17c05ce0b180db622736845d4315519397a77beaf", size = 2325979, upload-time = "2025-08-10T21:27:12.917Z" }, - { url = "https://files.pythonhosted.org/packages/fc/ff/b269eefd90f4ae14dcc74973d5a0f6d28d3b9bb1afd8c0340513afe6b39a/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:77937e5e2a38a7b48eef0585114fe7930346993a88060d0bf886086d2aa49ef5", size = 2491456, upload-time = "2025-08-10T21:27:14.353Z" }, - { url = "https://files.pythonhosted.org/packages/fc/d4/10303190bd4d30de547534601e259a4fbf014eed94aae3e5521129215086/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:24c175051354f4a28c5d6a31c93906dc653e2bf234e8a4bbfb964892078898ce", size = 2294621, upload-time = "2025-08-10T21:27:15.808Z" }, - { url = "https://files.pythonhosted.org/packages/28/e0/a9a90416fce5c0be25742729c2ea52105d62eda6c4be4d803c2a7be1fa50/kiwisolver-1.4.9-cp314-cp314-win_amd64.whl", hash = "sha256:0763515d4df10edf6d06a3c19734e2566368980d21ebec439f33f9eb936c07b7", size = 75417, upload-time = "2025-08-10T21:27:17.436Z" }, - { url = "https://files.pythonhosted.org/packages/1f/10/6949958215b7a9a264299a7db195564e87900f709db9245e4ebdd3c70779/kiwisolver-1.4.9-cp314-cp314-win_arm64.whl", hash = "sha256:0e4e2bf29574a6a7b7f6cb5fa69293b9f96c928949ac4a53ba3f525dffb87f9c", size = 66582, upload-time = "2025-08-10T21:27:18.436Z" }, - { url = "https://files.pythonhosted.org/packages/ec/79/60e53067903d3bc5469b369fe0dfc6b3482e2133e85dae9daa9527535991/kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d976bbb382b202f71c67f77b0ac11244021cfa3f7dfd9e562eefcea2df711548", size = 126514, upload-time = "2025-08-10T21:27:19.465Z" }, - { url = "https://files.pythonhosted.org/packages/25/d1/4843d3e8d46b072c12a38c97c57fab4608d36e13fe47d47ee96b4d61ba6f/kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2489e4e5d7ef9a1c300a5e0196e43d9c739f066ef23270607d45aba368b91f2d", size = 67905, upload-time = "2025-08-10T21:27:20.51Z" }, - { url = "https://files.pythonhosted.org/packages/8c/ae/29ffcbd239aea8b93108de1278271ae764dfc0d803a5693914975f200596/kiwisolver-1.4.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e2ea9f7ab7fbf18fffb1b5434ce7c69a07582f7acc7717720f1d69f3e806f90c", size = 66399, upload-time = "2025-08-10T21:27:21.496Z" }, - { url = "https://files.pythonhosted.org/packages/a1/ae/d7ba902aa604152c2ceba5d352d7b62106bedbccc8e95c3934d94472bfa3/kiwisolver-1.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b34e51affded8faee0dfdb705416153819d8ea9250bbbf7ea1b249bdeb5f1122", size = 1582197, upload-time = "2025-08-10T21:27:22.604Z" }, - { url = "https://files.pythonhosted.org/packages/f2/41/27c70d427eddb8bc7e4f16420a20fefc6f480312122a59a959fdfe0445ad/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8aacd3d4b33b772542b2e01beb50187536967b514b00003bdda7589722d2a64", size = 1390125, upload-time = "2025-08-10T21:27:24.036Z" }, - { url = "https://files.pythonhosted.org/packages/41/42/b3799a12bafc76d962ad69083f8b43b12bf4fe78b097b12e105d75c9b8f1/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7cf974dd4e35fa315563ac99d6287a1024e4dc2077b8a7d7cd3d2fb65d283134", size = 1402612, upload-time = "2025-08-10T21:27:25.773Z" }, - { url = "https://files.pythonhosted.org/packages/d2/b5/a210ea073ea1cfaca1bb5c55a62307d8252f531beb364e18aa1e0888b5a0/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:85bd218b5ecfbee8c8a82e121802dcb519a86044c9c3b2e4aef02fa05c6da370", size = 1453990, upload-time = "2025-08-10T21:27:27.089Z" }, - { url = "https://files.pythonhosted.org/packages/5f/ce/a829eb8c033e977d7ea03ed32fb3c1781b4fa0433fbadfff29e39c676f32/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0856e241c2d3df4efef7c04a1e46b1936b6120c9bcf36dd216e3acd84bc4fb21", size = 2331601, upload-time = "2025-08-10T21:27:29.343Z" }, - { url = "https://files.pythonhosted.org/packages/e0/4b/b5e97eb142eb9cd0072dacfcdcd31b1c66dc7352b0f7c7255d339c0edf00/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9af39d6551f97d31a4deebeac6f45b156f9755ddc59c07b402c148f5dbb6482a", size = 2422041, upload-time = "2025-08-10T21:27:30.754Z" }, - { url = "https://files.pythonhosted.org/packages/40/be/8eb4cd53e1b85ba4edc3a9321666f12b83113a178845593307a3e7891f44/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:bb4ae2b57fc1d8cbd1cf7b1d9913803681ffa903e7488012be5b76dedf49297f", size = 2594897, upload-time = "2025-08-10T21:27:32.803Z" }, - { url = "https://files.pythonhosted.org/packages/99/dd/841e9a66c4715477ea0abc78da039832fbb09dac5c35c58dc4c41a407b8a/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:aedff62918805fb62d43a4aa2ecd4482c380dc76cd31bd7c8878588a61bd0369", size = 2391835, upload-time = "2025-08-10T21:27:34.23Z" }, - { url = "https://files.pythonhosted.org/packages/0c/28/4b2e5c47a0da96896fdfdb006340ade064afa1e63675d01ea5ac222b6d52/kiwisolver-1.4.9-cp314-cp314t-win_amd64.whl", hash = "sha256:1fa333e8b2ce4d9660f2cda9c0e1b6bafcfb2457a9d259faa82289e73ec24891", size = 79988, upload-time = "2025-08-10T21:27:35.587Z" }, - { url = "https://files.pythonhosted.org/packages/80/be/3578e8afd18c88cdf9cb4cffde75a96d2be38c5a903f1ed0ceec061bd09e/kiwisolver-1.4.9-cp314-cp314t-win_arm64.whl", hash = "sha256:4a48a2ce79d65d363597ef7b567ce3d14d68783d2b2263d98db3d9477805ba32", size = 70260, upload-time = "2025-08-10T21:27:36.606Z" }, +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/67/9c61eccb13f0bdca9307614e782fec49ffdde0f7a2314935d489fa93cd9c/kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a", size = 103482, upload-time = "2026-03-09T13:15:53.382Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/b2/818b74ebea34dabe6d0c51cb1c572e046730e64844da6ed646d5298c40ce/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4e9750bc21b886308024f8a54ccb9a2cc38ac9fa813bf4348434e3d54f337ff9", size = 123158, upload-time = "2026-03-09T13:13:23.127Z" }, + { url = "https://files.pythonhosted.org/packages/bf/d9/405320f8077e8e1c5c4bd6adc45e1e6edf6d727b6da7f2e2533cf58bff71/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72ec46b7eba5b395e0a7b63025490d3214c11013f4aacb4f5e8d6c3041829588", size = 66388, upload-time = "2026-03-09T13:13:24.765Z" }, + { url = "https://files.pythonhosted.org/packages/99/9f/795fedf35634f746151ca8839d05681ceb6287fbed6cc1c9bf235f7887c2/kiwisolver-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ed3a984b31da7481b103f68776f7128a89ef26ed40f4dc41a2223cda7fb24819", size = 64068, upload-time = "2026-03-09T13:13:25.878Z" }, + { url = "https://files.pythonhosted.org/packages/c4/13/680c54afe3e65767bed7ec1a15571e1a2f1257128733851ade24abcefbcc/kiwisolver-1.5.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb5136fb5352d3f422df33f0c879a1b0c204004324150cc3b5e3c4f310c9049f", size = 1477934, upload-time = "2026-03-09T13:13:27.166Z" }, + { url = "https://files.pythonhosted.org/packages/c8/2f/cebfcdb60fd6a9b0f6b47a9337198bcbad6fbe15e68189b7011fd914911f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2af221f268f5af85e776a73d62b0845fc8baf8ef0abfae79d29c77d0e776aaf", size = 1278537, upload-time = "2026-03-09T13:13:28.707Z" }, + { url = "https://files.pythonhosted.org/packages/f2/0d/9b782923aada3fafb1d6b84e13121954515c669b18af0c26e7d21f579855/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b0f172dc8ffaccb8522d7c5d899de00133f2f1ca7b0a49b7da98e901de87bf2d", size = 1296685, upload-time = "2026-03-09T13:13:30.528Z" }, + { url = "https://files.pythonhosted.org/packages/27/70/83241b6634b04fe44e892688d5208332bde130f38e610c0418f9ede47ded/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6ab8ba9152203feec73758dad83af9a0bbe05001eb4639e547207c40cfb52083", size = 1346024, upload-time = "2026-03-09T13:13:32.818Z" }, + { url = "https://files.pythonhosted.org/packages/e4/db/30ed226fb271ae1a6431fc0fe0edffb2efe23cadb01e798caeb9f2ceae8f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:cdee07c4d7f6d72008d3f73b9bf027f4e11550224c7c50d8df1ae4a37c1402a6", size = 987241, upload-time = "2026-03-09T13:13:34.435Z" }, + { url = "https://files.pythonhosted.org/packages/ec/bd/c314595208e4c9587652d50959ead9e461995389664e490f4dce7ff0f782/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7c60d3c9b06fb23bd9c6139281ccbdc384297579ae037f08ae90c69f6845c0b1", size = 2227742, upload-time = "2026-03-09T13:13:36.4Z" }, + { url = "https://files.pythonhosted.org/packages/c1/43/0499cec932d935229b5543d073c2b87c9c22846aab48881e9d8d6e742a2d/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e315e5ec90d88e140f57696ff85b484ff68bb311e36f2c414aa4286293e6dee0", size = 2323966, upload-time = "2026-03-09T13:13:38.204Z" }, + { url = "https://files.pythonhosted.org/packages/3d/6f/79b0d760907965acfd9d61826a3d41f8f093c538f55cd2633d3f0db269f6/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:1465387ac63576c3e125e5337a6892b9e99e0627d52317f3ca79e6930d889d15", size = 1977417, upload-time = "2026-03-09T13:13:39.966Z" }, + { url = "https://files.pythonhosted.org/packages/ab/31/01d0537c41cb75a551a438c3c7a80d0c60d60b81f694dac83dd436aec0d0/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:530a3fd64c87cffa844d4b6b9768774763d9caa299e9b75d8eca6a4423b31314", size = 2491238, upload-time = "2026-03-09T13:13:41.698Z" }, + { url = "https://files.pythonhosted.org/packages/e4/34/8aefdd0be9cfd00a44509251ba864f5caf2991e36772e61c408007e7f417/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1d9daea4ea6b9be74fe2f01f7fbade8d6ffab263e781274cffca0dba9be9eec9", size = 2294947, upload-time = "2026-03-09T13:13:43.343Z" }, + { url = "https://files.pythonhosted.org/packages/ad/cf/0348374369ca588f8fe9c338fae49fa4e16eeb10ffb3d012f23a54578a9e/kiwisolver-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:f18c2d9782259a6dc132fdc7a63c168cbc74b35284b6d75c673958982a378384", size = 73569, upload-time = "2026-03-09T13:13:45.792Z" }, + { url = "https://files.pythonhosted.org/packages/28/26/192b26196e2316e2bd29deef67e37cdf9870d9af8e085e521afff0fed526/kiwisolver-1.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:f7c7553b13f69c1b29a5bde08ddc6d9d0c8bfb84f9ed01c30db25944aeb852a7", size = 64997, upload-time = "2026-03-09T13:13:46.878Z" }, + { url = "https://files.pythonhosted.org/packages/9d/69/024d6711d5ba575aa65d5538042e99964104e97fa153a9f10bc369182bc2/kiwisolver-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:fd40bb9cd0891c4c3cb1ddf83f8bbfa15731a248fdc8162669405451e2724b09", size = 123166, upload-time = "2026-03-09T13:13:48.032Z" }, + { url = "https://files.pythonhosted.org/packages/ce/48/adbb40df306f587054a348831220812b9b1d787aff714cfbc8556e38fccd/kiwisolver-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c0e1403fd7c26d77c1f03e096dc58a5c726503fa0db0456678b8668f76f521e3", size = 66395, upload-time = "2026-03-09T13:13:49.365Z" }, + { url = "https://files.pythonhosted.org/packages/a8/3a/d0a972b34e1c63e2409413104216cd1caa02c5a37cb668d1687d466c1c45/kiwisolver-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dda366d548e89a90d88a86c692377d18d8bd64b39c1fb2b92cb31370e2896bbd", size = 64065, upload-time = "2026-03-09T13:13:50.562Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0a/7b98e1e119878a27ba8618ca1e18b14f992ff1eda40f47bccccf4de44121/kiwisolver-1.5.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:332b4f0145c30b5f5ad9374881133e5aa64320428a57c2c2b61e9d891a51c2f3", size = 1477903, upload-time = "2026-03-09T13:13:52.084Z" }, + { url = "https://files.pythonhosted.org/packages/18/d8/55638d89ffd27799d5cc3d8aa28e12f4ce7a64d67b285114dbedc8ea4136/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c50b89ffd3e1a911c69a1dd3de7173c0cd10b130f56222e57898683841e4f96", size = 1278751, upload-time = "2026-03-09T13:13:54.673Z" }, + { url = "https://files.pythonhosted.org/packages/b8/97/b4c8d0d18421ecceba20ad8701358453b88e32414e6f6950b5a4bad54e65/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4db576bb8c3ef9365f8b40fe0f671644de6736ae2c27a2c62d7d8a1b4329f099", size = 1296793, upload-time = "2026-03-09T13:13:56.287Z" }, + { url = "https://files.pythonhosted.org/packages/c4/10/f862f94b6389d8957448ec9df59450b81bec4abb318805375c401a1e6892/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0b85aad90cea8ac6797a53b5d5f2e967334fa4d1149f031c4537569972596cb8", size = 1346041, upload-time = "2026-03-09T13:13:58.269Z" }, + { url = "https://files.pythonhosted.org/packages/a3/6a/f1650af35821eaf09de398ec0bc2aefc8f211f0cda50204c9f1673741ba9/kiwisolver-1.5.0-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:d36ca54cb4c6c4686f7cbb7b817f66f5911c12ddb519450bbe86707155028f87", size = 987292, upload-time = "2026-03-09T13:13:59.871Z" }, + { url = "https://files.pythonhosted.org/packages/de/19/d7fb82984b9238115fe629c915007be608ebd23dc8629703d917dbfaffd4/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:38f4a703656f493b0ad185211ccfca7f0386120f022066b018eb5296d8613e23", size = 2227865, upload-time = "2026-03-09T13:14:01.401Z" }, + { url = "https://files.pythonhosted.org/packages/7f/b9/46b7f386589fd222dac9e9de9c956ce5bcefe2ee73b4e79891381dda8654/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3ac2360e93cb41be81121755c6462cff3beaa9967188c866e5fce5cf13170859", size = 2324369, upload-time = "2026-03-09T13:14:02.972Z" }, + { url = "https://files.pythonhosted.org/packages/92/8b/95e237cf3d9c642960153c769ddcbe278f182c8affb20cecc1cc983e7cc5/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c95cab08d1965db3d84a121f1c7ce7479bdd4072c9b3dafd8fecce48a2e6b902", size = 1977989, upload-time = "2026-03-09T13:14:04.503Z" }, + { url = "https://files.pythonhosted.org/packages/1b/95/980c9df53501892784997820136c01f62bc1865e31b82b9560f980c0e649/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fc20894c3d21194d8041a28b65622d5b86db786da6e3cfe73f0c762951a61167", size = 2491645, upload-time = "2026-03-09T13:14:06.106Z" }, + { url = "https://files.pythonhosted.org/packages/cb/32/900647fd0840abebe1561792c6b31e6a7c0e278fc3973d30572a965ca14c/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7a32f72973f0f950c1920475d5c5ea3d971b81b6f0ec53b8d0a956cc965f22e0", size = 2295237, upload-time = "2026-03-09T13:14:08.891Z" }, + { url = "https://files.pythonhosted.org/packages/be/8a/be60e3bbcf513cc5a50f4a3e88e1dcecebb79c1ad607a7222877becaa101/kiwisolver-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bf3acf1419fa93064a4c2189ac0b58e3be7872bf6ee6177b0d4c63dc4cea276", size = 73573, upload-time = "2026-03-09T13:14:12.327Z" }, + { url = "https://files.pythonhosted.org/packages/4d/d2/64be2e429eb4fca7f7e1c52a91b12663aeaf25de3895e5cca0f47ef2a8d0/kiwisolver-1.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:fa8eb9ecdb7efb0b226acec134e0d709e87a909fa4971a54c0c4f6e88635484c", size = 64998, upload-time = "2026-03-09T13:14:13.469Z" }, + { url = "https://files.pythonhosted.org/packages/b0/69/ce68dd0c85755ae2de490bf015b62f2cea5f6b14ff00a463f9d0774449ff/kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:db485b3847d182b908b483b2ed133c66d88d49cacf98fd278fadafe11b4478d1", size = 125700, upload-time = "2026-03-09T13:14:14.636Z" }, + { url = "https://files.pythonhosted.org/packages/74/aa/937aac021cf9d4349990d47eb319309a51355ed1dbdc9c077cdc9224cb11/kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:be12f931839a3bdfe28b584db0e640a65a8bcbc24560ae3fdb025a449b3d754e", size = 67537, upload-time = "2026-03-09T13:14:15.808Z" }, + { url = "https://files.pythonhosted.org/packages/ee/20/3a87fbece2c40ad0f6f0aefa93542559159c5f99831d596050e8afae7a9f/kiwisolver-1.5.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:16b85d37c2cbb3253226d26e64663f755d88a03439a9c47df6246b35defbdfb7", size = 65514, upload-time = "2026-03-09T13:14:18.035Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7f/f943879cda9007c45e1f7dba216d705c3a18d6b35830e488b6c6a4e7cdf0/kiwisolver-1.5.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4432b835675f0ea7414aab3d37d119f7226d24869b7a829caeab49ebda407b0c", size = 1584848, upload-time = "2026-03-09T13:14:19.745Z" }, + { url = "https://files.pythonhosted.org/packages/37/f8/4d4f85cc1870c127c88d950913370dd76138482161cd07eabbc450deff01/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b0feb50971481a2cc44d94e88bdb02cdd497618252ae226b8eb1201b957e368", size = 1391542, upload-time = "2026-03-09T13:14:21.54Z" }, + { url = "https://files.pythonhosted.org/packages/04/0b/65dd2916c84d252b244bd405303220f729e7c17c9d7d33dca6feeff9ffc4/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56fa888f10d0f367155e76ce849fa1166fc9730d13bd2d65a2aa13b6f5424489", size = 1404447, upload-time = "2026-03-09T13:14:23.205Z" }, + { url = "https://files.pythonhosted.org/packages/39/5c/2606a373247babce9b1d056c03a04b65f3cf5290a8eac5d7bdead0a17e21/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:940dda65d5e764406b9fb92761cbf462e4e63f712ab60ed98f70552e496f3bf1", size = 1455918, upload-time = "2026-03-09T13:14:24.74Z" }, + { url = "https://files.pythonhosted.org/packages/d5/d1/c6078b5756670658e9192a2ef11e939c92918833d2745f85cd14a6004bdf/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_39_riscv64.whl", hash = "sha256:89fc958c702ee9a745e4700378f5d23fddbc46ff89e8fdbf5395c24d5c1452a3", size = 1072856, upload-time = "2026-03-09T13:14:26.597Z" }, + { url = "https://files.pythonhosted.org/packages/cb/c8/7def6ddf16eb2b3741d8b172bdaa9af882b03c78e9b0772975408801fa63/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9027d773c4ff81487181a925945743413f6069634d0b122d0b37684ccf4f1e18", size = 2333580, upload-time = "2026-03-09T13:14:28.237Z" }, + { url = "https://files.pythonhosted.org/packages/9e/87/2ac1fce0eb1e616fcd3c35caa23e665e9b1948bb984f4764790924594128/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:5b233ea3e165e43e35dba1d2b8ecc21cf070b45b65ae17dd2747d2713d942021", size = 2423018, upload-time = "2026-03-09T13:14:30.018Z" }, + { url = "https://files.pythonhosted.org/packages/67/13/c6700ccc6cc218716bfcda4935e4b2997039869b4ad8a94f364c5a3b8e63/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ce9bf03dad3b46408c08649c6fbd6ca28a9fce0eb32fdfffa6775a13103b5310", size = 2062804, upload-time = "2026-03-09T13:14:32.888Z" }, + { url = "https://files.pythonhosted.org/packages/1b/bd/877056304626943ff0f1f44c08f584300c199b887cb3176cd7e34f1515f1/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:fc4d3f1fb9ca0ae9f97b095963bc6326f1dbfd3779d6679a1e016b9baaa153d3", size = 2597482, upload-time = "2026-03-09T13:14:34.971Z" }, + { url = "https://files.pythonhosted.org/packages/75/19/c60626c47bf0f8ac5dcf72c6c98e266d714f2fbbfd50cf6dab5ede3aaa50/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f443b4825c50a51ee68585522ab4a1d1257fac65896f282b4c6763337ac9f5d2", size = 2394328, upload-time = "2026-03-09T13:14:36.816Z" }, + { url = "https://files.pythonhosted.org/packages/47/84/6a6d5e5bb8273756c27b7d810d47f7ef2f1f9b9fd23c9ee9a3f8c75c9cef/kiwisolver-1.5.0-cp313-cp313t-win_arm64.whl", hash = "sha256:893ff3a711d1b515ba9da14ee090519bad4610ed1962fbe298a434e8c5f8db53", size = 68410, upload-time = "2026-03-09T13:14:38.695Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/060f45052f2a01ad5762c8fdecd6d7a752b43400dc29ff75cd47225a40fd/kiwisolver-1.5.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8df31fe574b8b3993cc61764f40941111b25c2d9fea13d3ce24a49907cd2d615", size = 123231, upload-time = "2026-03-09T13:14:41.323Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a7/78da680eadd06ff35edef6ef68a1ad273bad3e2a0936c9a885103230aece/kiwisolver-1.5.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1d49a49ac4cbfb7c1375301cd1ec90169dfeae55ff84710d782260ce77a75a02", size = 66489, upload-time = "2026-03-09T13:14:42.534Z" }, + { url = "https://files.pythonhosted.org/packages/49/b2/97980f3ad4fae37dd7fe31626e2bf75fbf8bdf5d303950ec1fab39a12da8/kiwisolver-1.5.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0cbe94b69b819209a62cb27bdfa5dc2a8977d8de2f89dfd97ba4f53ed3af754e", size = 64063, upload-time = "2026-03-09T13:14:44.759Z" }, + { url = "https://files.pythonhosted.org/packages/e7/f9/b06c934a6aa8bc91f566bd2a214fd04c30506c2d9e2b6b171953216a65b6/kiwisolver-1.5.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:80aa065ffd378ff784822a6d7c3212f2d5f5e9c3589614b5c228b311fd3063ac", size = 1475913, upload-time = "2026-03-09T13:14:46.247Z" }, + { url = "https://files.pythonhosted.org/packages/6b/f0/f768ae564a710135630672981231320bc403cf9152b5596ec5289de0f106/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e7f886f47ab881692f278ae901039a234e4025a68e6dfab514263a0b1c4ae05", size = 1282782, upload-time = "2026-03-09T13:14:48.458Z" }, + { url = "https://files.pythonhosted.org/packages/e2/9f/1de7aad00697325f05238a5f2eafbd487fb637cc27a558b5367a5f37fb7f/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5060731cc3ed12ca3a8b57acd4aeca5bbc2f49216dd0bec1650a1acd89486bcd", size = 1300815, upload-time = "2026-03-09T13:14:50.721Z" }, + { url = "https://files.pythonhosted.org/packages/5a/c2/297f25141d2e468e0ce7f7a7b92e0cf8918143a0cbd3422c1ad627e85a06/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7a4aa69609f40fce3cbc3f87b2061f042eee32f94b8f11db707b66a26461591a", size = 1347925, upload-time = "2026-03-09T13:14:52.304Z" }, + { url = "https://files.pythonhosted.org/packages/b9/d3/f4c73a02eb41520c47610207b21afa8cdd18fdbf64ffd94674ae21c4812d/kiwisolver-1.5.0-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:d168fda2dbff7b9b5f38e693182d792a938c31db4dac3a80a4888de603c99554", size = 991322, upload-time = "2026-03-09T13:14:54.637Z" }, + { url = "https://files.pythonhosted.org/packages/7b/46/d3f2efef7732fcda98d22bf4ad5d3d71d545167a852ca710a494f4c15343/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:413b820229730d358efd838ecbab79902fe97094565fdc80ddb6b0a18c18a581", size = 2232857, upload-time = "2026-03-09T13:14:56.471Z" }, + { url = "https://files.pythonhosted.org/packages/3f/ec/2d9756bf2b6d26ae4349b8d3662fb3993f16d80c1f971c179ce862b9dbae/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5124d1ea754509b09e53738ec185584cc609aae4a3b510aaf4ed6aa047ef9303", size = 2329376, upload-time = "2026-03-09T13:14:58.072Z" }, + { url = "https://files.pythonhosted.org/packages/8f/9f/876a0a0f2260f1bde92e002b3019a5fabc35e0939c7d945e0fa66185eb20/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e4415a8db000bf49a6dd1c478bf70062eaacff0f462b92b0ba68791a905861f9", size = 1982549, upload-time = "2026-03-09T13:14:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/6c/4f/ba3624dfac23a64d54ac4179832860cb537c1b0af06024936e82ca4154a0/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d618fd27420381a4f6044faa71f46d8bfd911bd077c555f7138ed88729bfbe79", size = 2494680, upload-time = "2026-03-09T13:15:01.364Z" }, + { url = "https://files.pythonhosted.org/packages/39/b7/97716b190ab98911b20d10bf92eca469121ec483b8ce0edd314f51bc85af/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5092eb5b1172947f57d6ea7d89b2f29650414e4293c47707eb499ec07a0ac796", size = 2297905, upload-time = "2026-03-09T13:15:03.925Z" }, + { url = "https://files.pythonhosted.org/packages/a3/36/4e551e8aa55c9188bca9abb5096805edbf7431072b76e2298e34fd3a3008/kiwisolver-1.5.0-cp314-cp314-win_amd64.whl", hash = "sha256:d76e2d8c75051d58177e762164d2e9ab92886534e3a12e795f103524f221dd8e", size = 75086, upload-time = "2026-03-09T13:15:07.775Z" }, + { url = "https://files.pythonhosted.org/packages/70/15/9b90f7df0e31a003c71649cf66ef61c3c1b862f48c81007fa2383c8bd8d7/kiwisolver-1.5.0-cp314-cp314-win_arm64.whl", hash = "sha256:fa6248cd194edff41d7ea9425ced8ca3a6f838bfb295f6f1d6e6bb694a8518df", size = 66577, upload-time = "2026-03-09T13:15:09.139Z" }, + { url = "https://files.pythonhosted.org/packages/17/01/7dc8c5443ff42b38e72731643ed7cf1ed9bf01691ae5cdca98501999ed83/kiwisolver-1.5.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:d1ffeb80b5676463d7a7d56acbe8e37a20ce725570e09549fe738e02ca6b7e1e", size = 125794, upload-time = "2026-03-09T13:15:10.525Z" }, + { url = "https://files.pythonhosted.org/packages/46/8a/b4ebe46ebaac6a303417fab10c2e165c557ddaff558f9699d302b256bc53/kiwisolver-1.5.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bc4d8e252f532ab46a1de9349e2d27b91fce46736a9eedaa37beaca66f574ed4", size = 67646, upload-time = "2026-03-09T13:15:12.016Z" }, + { url = "https://files.pythonhosted.org/packages/60/35/10a844afc5f19d6f567359bf4789e26661755a2f36200d5d1ed8ad0126e5/kiwisolver-1.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6783e069732715ad0c3ce96dbf21dbc2235ab0593f2baf6338101f70371f4028", size = 65511, upload-time = "2026-03-09T13:15:13.311Z" }, + { url = "https://files.pythonhosted.org/packages/f8/8a/685b297052dd041dcebce8e8787b58923b6e78acc6115a0dc9189011c44b/kiwisolver-1.5.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e7c4c09a490dc4d4a7f8cbee56c606a320f9dc28cf92a7157a39d1ce7676a657", size = 1584858, upload-time = "2026-03-09T13:15:15.103Z" }, + { url = "https://files.pythonhosted.org/packages/9e/80/04865e3d4638ac5bddec28908916df4a3075b8c6cc101786a96803188b96/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a075bd7bd19c70cf67c8badfa36cf7c5d8de3c9ddb8420c51e10d9c50e94920", size = 1392539, upload-time = "2026-03-09T13:15:16.661Z" }, + { url = "https://files.pythonhosted.org/packages/ba/01/77a19cacc0893fa13fafa46d1bba06fb4dc2360b3292baf4b56d8e067b24/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bdd3e53429ff02aa319ba59dfe4ceeec345bf46cf180ec2cf6fd5b942e7975e9", size = 1405310, upload-time = "2026-03-09T13:15:18.229Z" }, + { url = "https://files.pythonhosted.org/packages/53/39/bcaf5d0cca50e604cfa9b4e3ae1d64b50ca1ae5b754122396084599ef903/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cdcb35dc9d807259c981a85531048ede628eabcffb3239adf3d17463518992d", size = 1456244, upload-time = "2026-03-09T13:15:20.444Z" }, + { url = "https://files.pythonhosted.org/packages/d0/7a/72c187abc6975f6978c3e39b7cf67aeb8b3c0a8f9790aa7fd412855e9e1f/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:70d593af6a6ca332d1df73d519fddb5148edb15cd90d5f0155e3746a6d4fcc65", size = 1073154, upload-time = "2026-03-09T13:15:22.039Z" }, + { url = "https://files.pythonhosted.org/packages/c7/ca/cf5b25783ebbd59143b4371ed0c8428a278abe68d6d0104b01865b1bbd0f/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:377815a8616074cabbf3f53354e1d040c35815a134e01d7614b7692e4bf8acfa", size = 2334377, upload-time = "2026-03-09T13:15:23.741Z" }, + { url = "https://files.pythonhosted.org/packages/4a/e5/b1f492adc516796e88751282276745340e2a72dcd0d36cf7173e0daf3210/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0255a027391d52944eae1dbb5d4cc5903f57092f3674e8e544cdd2622826b3f0", size = 2425288, upload-time = "2026-03-09T13:15:25.789Z" }, + { url = "https://files.pythonhosted.org/packages/e6/e5/9b21fbe91a61b8f409d74a26498706e97a48008bfcd1864373d32a6ba31c/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:012b1eb16e28718fa782b5e61dc6f2da1f0792ca73bd05d54de6cb9561665fc9", size = 2063158, upload-time = "2026-03-09T13:15:27.63Z" }, + { url = "https://files.pythonhosted.org/packages/b1/02/83f47986138310f95ea95531f851b2a62227c11cbc3e690ae1374fe49f0f/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0e3aafb33aed7479377e5e9a82e9d4bf87063741fc99fc7ae48b0f16e32bdd6f", size = 2597260, upload-time = "2026-03-09T13:15:29.421Z" }, + { url = "https://files.pythonhosted.org/packages/07/18/43a5f24608d8c313dd189cf838c8e68d75b115567c6279de7796197cfb6a/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e7a116ae737f0000343218c4edf5bd45893bfeaff0993c0b215d7124c9f77646", size = 2394403, upload-time = "2026-03-09T13:15:31.517Z" }, + { url = "https://files.pythonhosted.org/packages/3b/b5/98222136d839b8afabcaa943b09bd05888c2d36355b7e448550211d1fca4/kiwisolver-1.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:1dd9b0b119a350976a6d781e7278ec7aca0b201e1a9e2d23d9804afecb6ca681", size = 79687, upload-time = "2026-03-09T13:15:33.204Z" }, + { url = "https://files.pythonhosted.org/packages/99/a2/ca7dc962848040befed12732dff6acae7fb3c4f6fc4272b3f6c9a30b8713/kiwisolver-1.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:58f812017cd2985c21fbffb4864d59174d4903dd66fa23815e74bbc7a0e2dd57", size = 70032, upload-time = "2026-03-09T13:15:34.411Z" }, + { url = "https://files.pythonhosted.org/packages/1c/fa/2910df836372d8761bb6eff7d8bdcb1613b5c2e03f260efe7abe34d388a7/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_10_13_x86_64.whl", hash = "sha256:5ae8e62c147495b01a0f4765c878e9bfdf843412446a247e28df59936e99e797", size = 130262, upload-time = "2026-03-09T13:15:35.629Z" }, + { url = "https://files.pythonhosted.org/packages/0f/41/c5f71f9f00aabcc71fee8b7475e3f64747282580c2fe748961ba29b18385/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f6764a4ccab3078db14a632420930f6186058750df066b8ea2a7106df91d3203", size = 138036, upload-time = "2026-03-09T13:15:36.894Z" }, + { url = "https://files.pythonhosted.org/packages/fa/06/7399a607f434119c6e1fdc8ec89a8d51ccccadf3341dee4ead6bd14caaf5/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c31c13da98624f957b0fb1b5bae5383b2333c2c3f6793d9825dd5ce79b525cb7", size = 194295, upload-time = "2026-03-09T13:15:38.22Z" }, + { url = "https://files.pythonhosted.org/packages/b5/91/53255615acd2a1eaca307ede3c90eb550bae9c94581f8c00081b6b1c8f44/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-win_amd64.whl", hash = "sha256:1f1489f769582498610e015a8ef2d36f28f505ab3096d0e16b4858a9ec214f57", size = 75987, upload-time = "2026-03-09T13:15:39.65Z" }, ] [[package]] @@ -623,54 +682,62 @@ wheels = [ [[package]] name = "librt" -version = "0.7.8" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/24/5f3646ff414285e0f7708fa4e946b9bf538345a41d1c375c439467721a5e/librt-0.7.8.tar.gz", hash = "sha256:1a4ede613941d9c3470b0368be851df6bb78ab218635512d0370b27a277a0862", size = 148323, upload-time = "2026-01-14T12:56:16.876Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/56/04/79d8fcb43cae376c7adbab7b2b9f65e48432c9eced62ac96703bcc16e09b/librt-0.7.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9b6943885b2d49c48d0cff23b16be830ba46b0152d98f62de49e735c6e655a63", size = 57472, upload-time = "2026-01-14T12:55:08.528Z" }, - { url = "https://files.pythonhosted.org/packages/b4/ba/60b96e93043d3d659da91752689023a73981336446ae82078cddf706249e/librt-0.7.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:46ef1f4b9b6cc364b11eea0ecc0897314447a66029ee1e55859acb3dd8757c93", size = 58986, upload-time = "2026-01-14T12:55:09.466Z" }, - { url = "https://files.pythonhosted.org/packages/7c/26/5215e4cdcc26e7be7eee21955a7e13cbf1f6d7d7311461a6014544596fac/librt-0.7.8-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:907ad09cfab21e3c86e8f1f87858f7049d1097f77196959c033612f532b4e592", size = 168422, upload-time = "2026-01-14T12:55:10.499Z" }, - { url = "https://files.pythonhosted.org/packages/0f/84/e8d1bc86fa0159bfc24f3d798d92cafd3897e84c7fea7fe61b3220915d76/librt-0.7.8-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2991b6c3775383752b3ca0204842743256f3ad3deeb1d0adc227d56b78a9a850", size = 177478, upload-time = "2026-01-14T12:55:11.577Z" }, - { url = "https://files.pythonhosted.org/packages/57/11/d0268c4b94717a18aa91df1100e767b010f87b7ae444dafaa5a2d80f33a6/librt-0.7.8-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03679b9856932b8c8f674e87aa3c55ea11c9274301f76ae8dc4d281bda55cf62", size = 192439, upload-time = "2026-01-14T12:55:12.7Z" }, - { url = "https://files.pythonhosted.org/packages/8d/56/1e8e833b95fe684f80f8894ae4d8b7d36acc9203e60478fcae599120a975/librt-0.7.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3968762fec1b2ad34ce57458b6de25dbb4142713e9ca6279a0d352fa4e9f452b", size = 191483, upload-time = "2026-01-14T12:55:13.838Z" }, - { url = "https://files.pythonhosted.org/packages/17/48/f11cf28a2cb6c31f282009e2208312aa84a5ee2732859f7856ee306176d5/librt-0.7.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:bb7a7807523a31f03061288cc4ffc065d684c39db7644c676b47d89553c0d714", size = 185376, upload-time = "2026-01-14T12:55:15.017Z" }, - { url = "https://files.pythonhosted.org/packages/b8/6a/d7c116c6da561b9155b184354a60a3d5cdbf08fc7f3678d09c95679d13d9/librt-0.7.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad64a14b1e56e702e19b24aae108f18ad1bf7777f3af5fcd39f87d0c5a814449", size = 206234, upload-time = "2026-01-14T12:55:16.571Z" }, - { url = "https://files.pythonhosted.org/packages/61/de/1975200bb0285fc921c5981d9978ce6ce11ae6d797df815add94a5a848a3/librt-0.7.8-cp312-cp312-win32.whl", hash = "sha256:0241a6ed65e6666236ea78203a73d800dbed896cf12ae25d026d75dc1fcd1dac", size = 44057, upload-time = "2026-01-14T12:55:18.077Z" }, - { url = "https://files.pythonhosted.org/packages/8e/cd/724f2d0b3461426730d4877754b65d39f06a41ac9d0a92d5c6840f72b9ae/librt-0.7.8-cp312-cp312-win_amd64.whl", hash = "sha256:6db5faf064b5bab9675c32a873436b31e01d66ca6984c6f7f92621656033a708", size = 50293, upload-time = "2026-01-14T12:55:19.179Z" }, - { url = "https://files.pythonhosted.org/packages/bd/cf/7e899acd9ee5727ad8160fdcc9994954e79fab371c66535c60e13b968ffc/librt-0.7.8-cp312-cp312-win_arm64.whl", hash = "sha256:57175aa93f804d2c08d2edb7213e09276bd49097611aefc37e3fa38d1fb99ad0", size = 43574, upload-time = "2026-01-14T12:55:20.185Z" }, - { url = "https://files.pythonhosted.org/packages/a1/fe/b1f9de2829cf7fc7649c1dcd202cfd873837c5cc2fc9e526b0e7f716c3d2/librt-0.7.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4c3995abbbb60b3c129490fa985dfe6cac11d88fc3c36eeb4fb1449efbbb04fc", size = 57500, upload-time = "2026-01-14T12:55:21.219Z" }, - { url = "https://files.pythonhosted.org/packages/eb/d4/4a60fbe2e53b825f5d9a77325071d61cd8af8506255067bf0c8527530745/librt-0.7.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:44e0c2cbc9bebd074cf2cdbe472ca185e824be4e74b1c63a8e934cea674bebf2", size = 59019, upload-time = "2026-01-14T12:55:22.256Z" }, - { url = "https://files.pythonhosted.org/packages/6a/37/61ff80341ba5159afa524445f2d984c30e2821f31f7c73cf166dcafa5564/librt-0.7.8-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4d2f1e492cae964b3463a03dc77a7fe8742f7855d7258c7643f0ee32b6651dd3", size = 169015, upload-time = "2026-01-14T12:55:23.24Z" }, - { url = "https://files.pythonhosted.org/packages/1c/86/13d4f2d6a93f181ebf2fc953868826653ede494559da8268023fe567fca3/librt-0.7.8-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:451e7ffcef8f785831fdb791bd69211f47e95dc4c6ddff68e589058806f044c6", size = 178161, upload-time = "2026-01-14T12:55:24.826Z" }, - { url = "https://files.pythonhosted.org/packages/88/26/e24ef01305954fc4d771f1f09f3dd682f9eb610e1bec188ffb719374d26e/librt-0.7.8-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3469e1af9f1380e093ae06bedcbdd11e407ac0b303a56bbe9afb1d6824d4982d", size = 193015, upload-time = "2026-01-14T12:55:26.04Z" }, - { url = "https://files.pythonhosted.org/packages/88/a0/92b6bd060e720d7a31ed474d046a69bd55334ec05e9c446d228c4b806ae3/librt-0.7.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f11b300027ce19a34f6d24ebb0a25fd0e24a9d53353225a5c1e6cadbf2916b2e", size = 192038, upload-time = "2026-01-14T12:55:27.208Z" }, - { url = "https://files.pythonhosted.org/packages/06/bb/6f4c650253704279c3a214dad188101d1b5ea23be0606628bc6739456624/librt-0.7.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4adc73614f0d3c97874f02f2c7fd2a27854e7e24ad532ea6b965459c5b757eca", size = 186006, upload-time = "2026-01-14T12:55:28.594Z" }, - { url = "https://files.pythonhosted.org/packages/dc/00/1c409618248d43240cadf45f3efb866837fa77e9a12a71481912135eb481/librt-0.7.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:60c299e555f87e4c01b2eca085dfccda1dde87f5a604bb45c2906b8305819a93", size = 206888, upload-time = "2026-01-14T12:55:30.214Z" }, - { url = "https://files.pythonhosted.org/packages/d9/83/b2cfe8e76ff5c1c77f8a53da3d5de62d04b5ebf7cf913e37f8bca43b5d07/librt-0.7.8-cp313-cp313-win32.whl", hash = "sha256:b09c52ed43a461994716082ee7d87618096851319bf695d57ec123f2ab708951", size = 44126, upload-time = "2026-01-14T12:55:31.44Z" }, - { url = "https://files.pythonhosted.org/packages/a9/0b/c59d45de56a51bd2d3a401fc63449c0ac163e4ef7f523ea8b0c0dee86ec5/librt-0.7.8-cp313-cp313-win_amd64.whl", hash = "sha256:f8f4a901a3fa28969d6e4519deceab56c55a09d691ea7b12ca830e2fa3461e34", size = 50262, upload-time = "2026-01-14T12:55:33.01Z" }, - { url = "https://files.pythonhosted.org/packages/fc/b9/973455cec0a1ec592395250c474164c4a58ebf3e0651ee920fef1a2623f1/librt-0.7.8-cp313-cp313-win_arm64.whl", hash = "sha256:43d4e71b50763fcdcf64725ac680d8cfa1706c928b844794a7aa0fa9ac8e5f09", size = 43600, upload-time = "2026-01-14T12:55:34.054Z" }, - { url = "https://files.pythonhosted.org/packages/1a/73/fa8814c6ce2d49c3827829cadaa1589b0bf4391660bd4510899393a23ebc/librt-0.7.8-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:be927c3c94c74b05128089a955fba86501c3b544d1d300282cc1b4bd370cb418", size = 57049, upload-time = "2026-01-14T12:55:35.056Z" }, - { url = "https://files.pythonhosted.org/packages/53/fe/f6c70956da23ea235fd2e3cc16f4f0b4ebdfd72252b02d1164dd58b4e6c3/librt-0.7.8-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7b0803e9008c62a7ef79058233db7ff6f37a9933b8f2573c05b07ddafa226611", size = 58689, upload-time = "2026-01-14T12:55:36.078Z" }, - { url = "https://files.pythonhosted.org/packages/1f/4d/7a2481444ac5fba63050d9abe823e6bc16896f575bfc9c1e5068d516cdce/librt-0.7.8-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:79feb4d00b2a4e0e05c9c56df707934f41fcb5fe53fd9efb7549068d0495b758", size = 166808, upload-time = "2026-01-14T12:55:37.595Z" }, - { url = "https://files.pythonhosted.org/packages/ac/3c/10901d9e18639f8953f57c8986796cfbf4c1c514844a41c9197cf87cb707/librt-0.7.8-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b9122094e3f24aa759c38f46bd8863433820654927370250f460ae75488b66ea", size = 175614, upload-time = "2026-01-14T12:55:38.756Z" }, - { url = "https://files.pythonhosted.org/packages/db/01/5cbdde0951a5090a80e5ba44e6357d375048123c572a23eecfb9326993a7/librt-0.7.8-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7e03bea66af33c95ce3addf87a9bf1fcad8d33e757bc479957ddbc0e4f7207ac", size = 189955, upload-time = "2026-01-14T12:55:39.939Z" }, - { url = "https://files.pythonhosted.org/packages/6a/b4/e80528d2f4b7eaf1d437fcbd6fc6ba4cbeb3e2a0cb9ed5a79f47c7318706/librt-0.7.8-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f1ade7f31675db00b514b98f9ab9a7698c7282dad4be7492589109471852d398", size = 189370, upload-time = "2026-01-14T12:55:41.057Z" }, - { url = "https://files.pythonhosted.org/packages/c1/ab/938368f8ce31a9787ecd4becb1e795954782e4312095daf8fd22420227c8/librt-0.7.8-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a14229ac62adcf1b90a15992f1ab9c69ae8b99ffb23cb64a90878a6e8a2f5b81", size = 183224, upload-time = "2026-01-14T12:55:42.328Z" }, - { url = "https://files.pythonhosted.org/packages/3c/10/559c310e7a6e4014ac44867d359ef8238465fb499e7eb31b6bfe3e3f86f5/librt-0.7.8-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5bcaaf624fd24e6a0cb14beac37677f90793a96864c67c064a91458611446e83", size = 203541, upload-time = "2026-01-14T12:55:43.501Z" }, - { url = "https://files.pythonhosted.org/packages/f8/db/a0db7acdb6290c215f343835c6efda5b491bb05c3ddc675af558f50fdba3/librt-0.7.8-cp314-cp314-win32.whl", hash = "sha256:7aa7d5457b6c542ecaed79cec4ad98534373c9757383973e638ccced0f11f46d", size = 40657, upload-time = "2026-01-14T12:55:44.668Z" }, - { url = "https://files.pythonhosted.org/packages/72/e0/4f9bdc2a98a798511e81edcd6b54fe82767a715e05d1921115ac70717f6f/librt-0.7.8-cp314-cp314-win_amd64.whl", hash = "sha256:3d1322800771bee4a91f3b4bd4e49abc7d35e65166821086e5afd1e6c0d9be44", size = 46835, upload-time = "2026-01-14T12:55:45.655Z" }, - { url = "https://files.pythonhosted.org/packages/f9/3d/59c6402e3dec2719655a41ad027a7371f8e2334aa794ed11533ad5f34969/librt-0.7.8-cp314-cp314-win_arm64.whl", hash = "sha256:5363427bc6a8c3b1719f8f3845ea53553d301382928a86e8fab7984426949bce", size = 39885, upload-time = "2026-01-14T12:55:47.138Z" }, - { url = "https://files.pythonhosted.org/packages/4e/9c/2481d80950b83085fb14ba3c595db56330d21bbc7d88a19f20165f3538db/librt-0.7.8-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:ca916919793a77e4a98d4a1701e345d337ce53be4a16620f063191f7322ac80f", size = 59161, upload-time = "2026-01-14T12:55:48.45Z" }, - { url = "https://files.pythonhosted.org/packages/96/79/108df2cfc4e672336765d54e3ff887294c1cc36ea4335c73588875775527/librt-0.7.8-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:54feb7b4f2f6706bb82325e836a01be805770443e2400f706e824e91f6441dde", size = 61008, upload-time = "2026-01-14T12:55:49.527Z" }, - { url = "https://files.pythonhosted.org/packages/46/f2/30179898f9994a5637459d6e169b6abdc982012c0a4b2d4c26f50c06f911/librt-0.7.8-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:39a4c76fee41007070f872b648cc2f711f9abf9a13d0c7162478043377b52c8e", size = 187199, upload-time = "2026-01-14T12:55:50.587Z" }, - { url = "https://files.pythonhosted.org/packages/b4/da/f7563db55cebdc884f518ba3791ad033becc25ff68eb70902b1747dc0d70/librt-0.7.8-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac9c8a458245c7de80bc1b9765b177055efff5803f08e548dd4bb9ab9a8d789b", size = 198317, upload-time = "2026-01-14T12:55:51.991Z" }, - { url = "https://files.pythonhosted.org/packages/b3/6c/4289acf076ad371471fa86718c30ae353e690d3de6167f7db36f429272f1/librt-0.7.8-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:95b67aa7eff150f075fda09d11f6bfb26edffd300f6ab1666759547581e8f666", size = 210334, upload-time = "2026-01-14T12:55:53.682Z" }, - { url = "https://files.pythonhosted.org/packages/4a/7f/377521ac25b78ac0a5ff44127a0360ee6d5ddd3ce7327949876a30533daa/librt-0.7.8-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:535929b6eff670c593c34ff435d5440c3096f20fa72d63444608a5aef64dd581", size = 211031, upload-time = "2026-01-14T12:55:54.827Z" }, - { url = "https://files.pythonhosted.org/packages/c5/b1/e1e96c3e20b23d00cf90f4aad48f0deb4cdfec2f0ed8380d0d85acf98bbf/librt-0.7.8-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:63937bd0f4d1cb56653dc7ae900d6c52c41f0015e25aaf9902481ee79943b33a", size = 204581, upload-time = "2026-01-14T12:55:56.811Z" }, - { url = "https://files.pythonhosted.org/packages/43/71/0f5d010e92ed9747e14bef35e91b6580533510f1e36a8a09eb79ee70b2f0/librt-0.7.8-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cf243da9e42d914036fd362ac3fa77d80a41cadcd11ad789b1b5eec4daaf67ca", size = 224731, upload-time = "2026-01-14T12:55:58.175Z" }, - { url = "https://files.pythonhosted.org/packages/22/f0/07fb6ab5c39a4ca9af3e37554f9d42f25c464829254d72e4ebbd81da351c/librt-0.7.8-cp314-cp314t-win32.whl", hash = "sha256:171ca3a0a06c643bd0a2f62a8944e1902c94aa8e5da4db1ea9a8daf872685365", size = 41173, upload-time = "2026-01-14T12:55:59.315Z" }, - { url = "https://files.pythonhosted.org/packages/24/d4/7e4be20993dc6a782639625bd2f97f3c66125c7aa80c82426956811cfccf/librt-0.7.8-cp314-cp314t-win_amd64.whl", hash = "sha256:445b7304145e24c60288a2f172b5ce2ca35c0f81605f5299f3fa567e189d2e32", size = 47668, upload-time = "2026-01-14T12:56:00.261Z" }, - { url = "https://files.pythonhosted.org/packages/fc/85/69f92b2a7b3c0f88ffe107c86b952b397004b5b8ea5a81da3d9c04c04422/librt-0.7.8-cp314-cp314t-win_arm64.whl", hash = "sha256:8766ece9de08527deabcd7cb1b4f1a967a385d26e33e536d6d8913db6ef74f06", size = 40550, upload-time = "2026-01-14T12:56:01.542Z" }, +version = "0.8.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/56/9c/b4b0c54d84da4a94b37bd44151e46d5e583c9534c7e02250b961b1b6d8a8/librt-0.8.1.tar.gz", hash = "sha256:be46a14693955b3bd96014ccbdb8339ee8c9346fbe11c1b78901b55125f14c73", size = 177471, upload-time = "2026-02-17T16:13:06.101Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/95/21/d39b0a87ac52fc98f621fb6f8060efb017a767ebbbac2f99fbcbc9ddc0d7/librt-0.8.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a28f2612ab566b17f3698b0da021ff9960610301607c9a5e8eaca62f5e1c350a", size = 66516, upload-time = "2026-02-17T16:11:41.604Z" }, + { url = "https://files.pythonhosted.org/packages/69/f1/46375e71441c43e8ae335905e069f1c54febee63a146278bcee8782c84fd/librt-0.8.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:60a78b694c9aee2a0f1aaeaa7d101cf713e92e8423a941d2897f4fa37908dab9", size = 68634, upload-time = "2026-02-17T16:11:43.268Z" }, + { url = "https://files.pythonhosted.org/packages/0a/33/c510de7f93bf1fa19e13423a606d8189a02624a800710f6e6a0a0f0784b3/librt-0.8.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:758509ea3f1eba2a57558e7e98f4659d0ea7670bff49673b0dde18a3c7e6c0eb", size = 198941, upload-time = "2026-02-17T16:11:44.28Z" }, + { url = "https://files.pythonhosted.org/packages/dd/36/e725903416409a533d92398e88ce665476f275081d0d7d42f9c4951999e5/librt-0.8.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:039b9f2c506bd0ab0f8725aa5ba339c6f0cd19d3b514b50d134789809c24285d", size = 209991, upload-time = "2026-02-17T16:11:45.462Z" }, + { url = "https://files.pythonhosted.org/packages/30/7a/8d908a152e1875c9f8eac96c97a480df425e657cdb47854b9efaa4998889/librt-0.8.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bb54f1205a3a6ab41a6fd71dfcdcbd278670d3a90ca502a30d9da583105b6f7", size = 224476, upload-time = "2026-02-17T16:11:46.542Z" }, + { url = "https://files.pythonhosted.org/packages/a8/b8/a22c34f2c485b8903a06f3fe3315341fe6876ef3599792344669db98fcff/librt-0.8.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:05bd41cdee35b0c59c259f870f6da532a2c5ca57db95b5f23689fcb5c9e42440", size = 217518, upload-time = "2026-02-17T16:11:47.746Z" }, + { url = "https://files.pythonhosted.org/packages/79/6f/5c6fea00357e4f82ba44f81dbfb027921f1ab10e320d4a64e1c408d035d9/librt-0.8.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adfab487facf03f0d0857b8710cf82d0704a309d8ffc33b03d9302b4c64e91a9", size = 225116, upload-time = "2026-02-17T16:11:49.298Z" }, + { url = "https://files.pythonhosted.org/packages/f2/a0/95ced4e7b1267fe1e2720a111685bcddf0e781f7e9e0ce59d751c44dcfe5/librt-0.8.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:153188fe98a72f206042be10a2c6026139852805215ed9539186312d50a8e972", size = 217751, upload-time = "2026-02-17T16:11:50.49Z" }, + { url = "https://files.pythonhosted.org/packages/93/c2/0517281cb4d4101c27ab59472924e67f55e375bc46bedae94ac6dc6e1902/librt-0.8.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:dd3c41254ee98604b08bd5b3af5bf0a89740d4ee0711de95b65166bf44091921", size = 218378, upload-time = "2026-02-17T16:11:51.783Z" }, + { url = "https://files.pythonhosted.org/packages/43/e8/37b3ac108e8976888e559a7b227d0ceac03c384cfd3e7a1c2ee248dbae79/librt-0.8.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e0d138c7ae532908cbb342162b2611dbd4d90c941cd25ab82084aaf71d2c0bd0", size = 241199, upload-time = "2026-02-17T16:11:53.561Z" }, + { url = "https://files.pythonhosted.org/packages/4b/5b/35812d041c53967fedf551a39399271bbe4257e681236a2cf1a69c8e7fa1/librt-0.8.1-cp312-cp312-win32.whl", hash = "sha256:43353b943613c5d9c49a25aaffdba46f888ec354e71e3529a00cca3f04d66a7a", size = 54917, upload-time = "2026-02-17T16:11:54.758Z" }, + { url = "https://files.pythonhosted.org/packages/de/d1/fa5d5331b862b9775aaf2a100f5ef86854e5d4407f71bddf102f4421e034/librt-0.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:ff8baf1f8d3f4b6b7257fcb75a501f2a5499d0dda57645baa09d4d0d34b19444", size = 62017, upload-time = "2026-02-17T16:11:55.748Z" }, + { url = "https://files.pythonhosted.org/packages/c7/7c/c614252f9acda59b01a66e2ddfd243ed1c7e1deab0293332dfbccf862808/librt-0.8.1-cp312-cp312-win_arm64.whl", hash = "sha256:0f2ae3725904f7377e11cc37722d5d401e8b3d5851fb9273d7f4fe04f6b3d37d", size = 52441, upload-time = "2026-02-17T16:11:56.801Z" }, + { url = "https://files.pythonhosted.org/packages/c5/3c/f614c8e4eaac7cbf2bbdf9528790b21d89e277ee20d57dc6e559c626105f/librt-0.8.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7e6bad1cd94f6764e1e21950542f818a09316645337fd5ab9a7acc45d99a8f35", size = 66529, upload-time = "2026-02-17T16:11:57.809Z" }, + { url = "https://files.pythonhosted.org/packages/ab/96/5836544a45100ae411eda07d29e3d99448e5258b6e9c8059deb92945f5c2/librt-0.8.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cf450f498c30af55551ba4f66b9123b7185362ec8b625a773b3d39aa1a717583", size = 68669, upload-time = "2026-02-17T16:11:58.843Z" }, + { url = "https://files.pythonhosted.org/packages/06/53/f0b992b57af6d5531bf4677d75c44f095f2366a1741fb695ee462ae04b05/librt-0.8.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:eca45e982fa074090057132e30585a7e8674e9e885d402eae85633e9f449ce6c", size = 199279, upload-time = "2026-02-17T16:11:59.862Z" }, + { url = "https://files.pythonhosted.org/packages/f3/ad/4848cc16e268d14280d8168aee4f31cea92bbd2b79ce33d3e166f2b4e4fc/librt-0.8.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c3811485fccfda840861905b8c70bba5ec094e02825598bb9d4ca3936857a04", size = 210288, upload-time = "2026-02-17T16:12:00.954Z" }, + { url = "https://files.pythonhosted.org/packages/52/05/27fdc2e95de26273d83b96742d8d3b7345f2ea2bdbd2405cc504644f2096/librt-0.8.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e4af413908f77294605e28cfd98063f54b2c790561383971d2f52d113d9c363", size = 224809, upload-time = "2026-02-17T16:12:02.108Z" }, + { url = "https://files.pythonhosted.org/packages/7a/d0/78200a45ba3240cb042bc597d6f2accba9193a2c57d0356268cbbe2d0925/librt-0.8.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5212a5bd7fae98dae95710032902edcd2ec4dc994e883294f75c857b83f9aba0", size = 218075, upload-time = "2026-02-17T16:12:03.631Z" }, + { url = "https://files.pythonhosted.org/packages/af/72/a210839fa74c90474897124c064ffca07f8d4b347b6574d309686aae7ca6/librt-0.8.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e692aa2d1d604e6ca12d35e51fdc36f4cda6345e28e36374579f7ef3611b3012", size = 225486, upload-time = "2026-02-17T16:12:04.725Z" }, + { url = "https://files.pythonhosted.org/packages/a3/c1/a03cc63722339ddbf087485f253493e2b013039f5b707e8e6016141130fa/librt-0.8.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4be2a5c926b9770c9e08e717f05737a269b9d0ebc5d2f0060f0fe3fe9ce47acb", size = 218219, upload-time = "2026-02-17T16:12:05.828Z" }, + { url = "https://files.pythonhosted.org/packages/58/f5/fff6108af0acf941c6f274a946aea0e484bd10cd2dc37610287ce49388c5/librt-0.8.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fd1a720332ea335ceb544cf0a03f81df92abd4bb887679fd1e460976b0e6214b", size = 218750, upload-time = "2026-02-17T16:12:07.09Z" }, + { url = "https://files.pythonhosted.org/packages/71/67/5a387bfef30ec1e4b4f30562c8586566faf87e47d696768c19feb49e3646/librt-0.8.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2af9e01e0ef80d95ae3c720be101227edae5f2fe7e3dc63d8857fadfc5a1d", size = 241624, upload-time = "2026-02-17T16:12:08.43Z" }, + { url = "https://files.pythonhosted.org/packages/d4/be/24f8502db11d405232ac1162eb98069ca49c3306c1d75c6ccc61d9af8789/librt-0.8.1-cp313-cp313-win32.whl", hash = "sha256:086a32dbb71336627e78cc1d6ee305a68d038ef7d4c39aaff41ae8c9aa46e91a", size = 54969, upload-time = "2026-02-17T16:12:09.633Z" }, + { url = "https://files.pythonhosted.org/packages/5c/73/c9fdf6cb2a529c1a092ce769a12d88c8cca991194dfe641b6af12fa964d2/librt-0.8.1-cp313-cp313-win_amd64.whl", hash = "sha256:e11769a1dbda4da7b00a76cfffa67aa47cfa66921d2724539eee4b9ede780b79", size = 62000, upload-time = "2026-02-17T16:12:10.632Z" }, + { url = "https://files.pythonhosted.org/packages/d3/97/68f80ca3ac4924f250cdfa6e20142a803e5e50fca96ef5148c52ee8c10ea/librt-0.8.1-cp313-cp313-win_arm64.whl", hash = "sha256:924817ab3141aca17893386ee13261f1d100d1ef410d70afe4389f2359fea4f0", size = 52495, upload-time = "2026-02-17T16:12:11.633Z" }, + { url = "https://files.pythonhosted.org/packages/c9/6a/907ef6800f7bca71b525a05f1839b21f708c09043b1c6aa77b6b827b3996/librt-0.8.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6cfa7fe54fd4d1f47130017351a959fe5804bda7a0bc7e07a2cdbc3fdd28d34f", size = 66081, upload-time = "2026-02-17T16:12:12.766Z" }, + { url = "https://files.pythonhosted.org/packages/1b/18/25e991cd5640c9fb0f8d91b18797b29066b792f17bf8493da183bf5caabe/librt-0.8.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:228c2409c079f8c11fb2e5d7b277077f694cb93443eb760e00b3b83cb8b3176c", size = 68309, upload-time = "2026-02-17T16:12:13.756Z" }, + { url = "https://files.pythonhosted.org/packages/a4/36/46820d03f058cfb5a9de5940640ba03165ed8aded69e0733c417bb04df34/librt-0.8.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7aae78ab5e3206181780e56912d1b9bb9f90a7249ce12f0e8bf531d0462dd0fc", size = 196804, upload-time = "2026-02-17T16:12:14.818Z" }, + { url = "https://files.pythonhosted.org/packages/59/18/5dd0d3b87b8ff9c061849fbdb347758d1f724b9a82241aa908e0ec54ccd0/librt-0.8.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:172d57ec04346b047ca6af181e1ea4858086c80bdf455f61994c4aa6fc3f866c", size = 206907, upload-time = "2026-02-17T16:12:16.513Z" }, + { url = "https://files.pythonhosted.org/packages/d1/96/ef04902aad1424fd7299b62d1890e803e6ab4018c3044dca5922319c4b97/librt-0.8.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6b1977c4ea97ce5eb7755a78fae68d87e4102e4aaf54985e8b56806849cc06a3", size = 221217, upload-time = "2026-02-17T16:12:17.906Z" }, + { url = "https://files.pythonhosted.org/packages/6d/ff/7e01f2dda84a8f5d280637a2e5827210a8acca9a567a54507ef1c75b342d/librt-0.8.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:10c42e1f6fd06733ef65ae7bebce2872bcafd8d6e6b0a08fe0a05a23b044fb14", size = 214622, upload-time = "2026-02-17T16:12:19.108Z" }, + { url = "https://files.pythonhosted.org/packages/1e/8c/5b093d08a13946034fed57619742f790faf77058558b14ca36a6e331161e/librt-0.8.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4c8dfa264b9193c4ee19113c985c95f876fae5e51f731494fc4e0cf594990ba7", size = 221987, upload-time = "2026-02-17T16:12:20.331Z" }, + { url = "https://files.pythonhosted.org/packages/d3/cc/86b0b3b151d40920ad45a94ce0171dec1aebba8a9d72bb3fa00c73ab25dd/librt-0.8.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:01170b6729a438f0dedc4a26ed342e3dc4f02d1000b4b19f980e1877f0c297e6", size = 215132, upload-time = "2026-02-17T16:12:21.54Z" }, + { url = "https://files.pythonhosted.org/packages/fc/be/8588164a46edf1e69858d952654e216a9a91174688eeefb9efbb38a9c799/librt-0.8.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:7b02679a0d783bdae30d443025b94465d8c3dc512f32f5b5031f93f57ac32071", size = 215195, upload-time = "2026-02-17T16:12:23.073Z" }, + { url = "https://files.pythonhosted.org/packages/f5/f2/0b9279bea735c734d69344ecfe056c1ba211694a72df10f568745c899c76/librt-0.8.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:190b109bb69592a3401fe1ffdea41a2e73370ace2ffdc4a0e8e2b39cdea81b78", size = 237946, upload-time = "2026-02-17T16:12:24.275Z" }, + { url = "https://files.pythonhosted.org/packages/e9/cc/5f2a34fbc8aeb35314a3641f9956fa9051a947424652fad9882be7a97949/librt-0.8.1-cp314-cp314-win32.whl", hash = "sha256:e70a57ecf89a0f64c24e37f38d3fe217a58169d2fe6ed6d70554964042474023", size = 50689, upload-time = "2026-02-17T16:12:25.766Z" }, + { url = "https://files.pythonhosted.org/packages/a0/76/cd4d010ab2147339ca2b93e959c3686e964edc6de66ddacc935c325883d7/librt-0.8.1-cp314-cp314-win_amd64.whl", hash = "sha256:7e2f3edca35664499fbb36e4770650c4bd4a08abc1f4458eab9df4ec56389730", size = 57875, upload-time = "2026-02-17T16:12:27.465Z" }, + { url = "https://files.pythonhosted.org/packages/84/0f/2143cb3c3ca48bd3379dcd11817163ca50781927c4537345d608b5045998/librt-0.8.1-cp314-cp314-win_arm64.whl", hash = "sha256:0d2f82168e55ddefd27c01c654ce52379c0750ddc31ee86b4b266bcf4d65f2a3", size = 48058, upload-time = "2026-02-17T16:12:28.556Z" }, + { url = "https://files.pythonhosted.org/packages/d2/0e/9b23a87e37baf00311c3efe6b48d6b6c168c29902dfc3f04c338372fd7db/librt-0.8.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2c74a2da57a094bd48d03fa5d196da83d2815678385d2978657499063709abe1", size = 68313, upload-time = "2026-02-17T16:12:29.659Z" }, + { url = "https://files.pythonhosted.org/packages/db/9a/859c41e5a4f1c84200a7d2b92f586aa27133c8243b6cac9926f6e54d01b9/librt-0.8.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a355d99c4c0d8e5b770313b8b247411ed40949ca44e33e46a4789b9293a907ee", size = 70994, upload-time = "2026-02-17T16:12:31.516Z" }, + { url = "https://files.pythonhosted.org/packages/4c/28/10605366ee599ed34223ac2bf66404c6fb59399f47108215d16d5ad751a8/librt-0.8.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2eb345e8b33fb748227409c9f1233d4df354d6e54091f0e8fc53acdb2ffedeb7", size = 220770, upload-time = "2026-02-17T16:12:33.294Z" }, + { url = "https://files.pythonhosted.org/packages/af/8d/16ed8fd452dafae9c48d17a6bc1ee3e818fd40ef718d149a8eff2c9f4ea2/librt-0.8.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9be2f15e53ce4e83cc08adc29b26fb5978db62ef2a366fbdf716c8a6c8901040", size = 235409, upload-time = "2026-02-17T16:12:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/89/1b/7bdf3e49349c134b25db816e4a3db6b94a47ac69d7d46b1e682c2c4949be/librt-0.8.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:785ae29c1f5c6e7c2cde2c7c0e148147f4503da3abc5d44d482068da5322fd9e", size = 246473, upload-time = "2026-02-17T16:12:36.656Z" }, + { url = "https://files.pythonhosted.org/packages/4e/8a/91fab8e4fd2a24930a17188c7af5380eb27b203d72101c9cc000dbdfd95a/librt-0.8.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1d3a7da44baf692f0c6aeb5b2a09c5e6fc7a703bca9ffa337ddd2e2da53f7732", size = 238866, upload-time = "2026-02-17T16:12:37.849Z" }, + { url = "https://files.pythonhosted.org/packages/b9/e0/c45a098843fc7c07e18a7f8a24ca8496aecbf7bdcd54980c6ca1aaa79a8e/librt-0.8.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5fc48998000cbc39ec0d5311312dda93ecf92b39aaf184c5e817d5d440b29624", size = 250248, upload-time = "2026-02-17T16:12:39.445Z" }, + { url = "https://files.pythonhosted.org/packages/82/30/07627de23036640c952cce0c1fe78972e77d7d2f8fd54fa5ef4554ff4a56/librt-0.8.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e96baa6820280077a78244b2e06e416480ed859bbd8e5d641cf5742919d8beb4", size = 240629, upload-time = "2026-02-17T16:12:40.889Z" }, + { url = "https://files.pythonhosted.org/packages/fb/c1/55bfe1ee3542eba055616f9098eaf6eddb966efb0ca0f44eaa4aba327307/librt-0.8.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:31362dbfe297b23590530007062c32c6f6176f6099646bb2c95ab1b00a57c382", size = 239615, upload-time = "2026-02-17T16:12:42.446Z" }, + { url = "https://files.pythonhosted.org/packages/2b/39/191d3d28abc26c9099b19852e6c99f7f6d400b82fa5a4e80291bd3803e19/librt-0.8.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cc3656283d11540ab0ea01978378e73e10002145117055e03722417aeab30994", size = 263001, upload-time = "2026-02-17T16:12:43.627Z" }, + { url = "https://files.pythonhosted.org/packages/b9/eb/7697f60fbe7042ab4e88f4ee6af496b7f222fffb0a4e3593ef1f29f81652/librt-0.8.1-cp314-cp314t-win32.whl", hash = "sha256:738f08021b3142c2918c03692608baed43bc51144c29e35807682f8070ee2a3a", size = 51328, upload-time = "2026-02-17T16:12:45.148Z" }, + { url = "https://files.pythonhosted.org/packages/7c/72/34bf2eb7a15414a23e5e70ecb9440c1d3179f393d9349338a91e2781c0fb/librt-0.8.1-cp314-cp314t-win_amd64.whl", hash = "sha256:89815a22daf9c51884fb5dbe4f1ef65ee6a146e0b6a8df05f753e2e4a9359bf4", size = 58722, upload-time = "2026-02-17T16:12:46.85Z" }, + { url = "https://files.pythonhosted.org/packages/b2/c8/d148e041732d631fc76036f8b30fae4e77b027a1e95b7a84bb522481a940/librt-0.8.1-cp314-cp314t-win_arm64.whl", hash = "sha256:bf512a71a23504ed08103a13c941f763db13fb11177beb3d9244c98c29fb4a61", size = 48755, upload-time = "2026-02-17T16:12:47.943Z" }, ] [[package]] @@ -933,63 +1000,63 @@ wheels = [ [[package]] name = "numpy" -version = "2.4.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/62/ae72ff66c0f1fd959925b4c11f8c2dea61f47f6acaea75a08512cdfe3fed/numpy-2.4.1.tar.gz", hash = "sha256:a1ceafc5042451a858231588a104093474c6a5c57dcc724841f5c888d237d690", size = 20721320, upload-time = "2026-01-10T06:44:59.619Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/7f/ec53e32bf10c813604edf07a3682616bd931d026fcde7b6d13195dfb684a/numpy-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d3703409aac693fa82c0aee023a1ae06a6e9d065dba10f5e8e80f642f1e9d0a2", size = 16656888, upload-time = "2026-01-10T06:42:40.913Z" }, - { url = "https://files.pythonhosted.org/packages/b8/e0/1f9585d7dae8f14864e948fd7fa86c6cb72dee2676ca2748e63b1c5acfe0/numpy-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7211b95ca365519d3596a1d8688a95874cc94219d417504d9ecb2df99fa7bfa8", size = 12373956, upload-time = "2026-01-10T06:42:43.091Z" }, - { url = "https://files.pythonhosted.org/packages/8e/43/9762e88909ff2326f5e7536fa8cb3c49fb03a7d92705f23e6e7f553d9cb3/numpy-2.4.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:5adf01965456a664fc727ed69cc71848f28d063217c63e1a0e200a118d5eec9a", size = 5202567, upload-time = "2026-01-10T06:42:45.107Z" }, - { url = "https://files.pythonhosted.org/packages/4b/ee/34b7930eb61e79feb4478800a4b95b46566969d837546aa7c034c742ef98/numpy-2.4.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:26f0bcd9c79a00e339565b303badc74d3ea2bd6d52191eeca5f95936cad107d0", size = 6549459, upload-time = "2026-01-10T06:42:48.152Z" }, - { url = "https://files.pythonhosted.org/packages/79/e3/5f115fae982565771be994867c89bcd8d7208dbfe9469185497d70de5ddf/numpy-2.4.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0093e85df2960d7e4049664b26afc58b03236e967fb942354deef3208857a04c", size = 14404859, upload-time = "2026-01-10T06:42:49.947Z" }, - { url = "https://files.pythonhosted.org/packages/d9/7d/9c8a781c88933725445a859cac5d01b5871588a15969ee6aeb618ba99eee/numpy-2.4.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7ad270f438cbdd402c364980317fb6b117d9ec5e226fff5b4148dd9aa9fc6e02", size = 16371419, upload-time = "2026-01-10T06:42:52.409Z" }, - { url = "https://files.pythonhosted.org/packages/a6/d2/8aa084818554543f17cf4162c42f162acbd3bb42688aefdba6628a859f77/numpy-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:297c72b1b98100c2e8f873d5d35fb551fce7040ade83d67dd51d38c8d42a2162", size = 16182131, upload-time = "2026-01-10T06:42:54.694Z" }, - { url = "https://files.pythonhosted.org/packages/60/db/0425216684297c58a8df35f3284ef56ec4a043e6d283f8a59c53562caf1b/numpy-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cf6470d91d34bf669f61d515499859fa7a4c2f7c36434afb70e82df7217933f9", size = 18295342, upload-time = "2026-01-10T06:42:56.991Z" }, - { url = "https://files.pythonhosted.org/packages/31/4c/14cb9d86240bd8c386c881bafbe43f001284b7cce3bc01623ac9475da163/numpy-2.4.1-cp312-cp312-win32.whl", hash = "sha256:b6bcf39112e956594b3331316d90c90c90fb961e39696bda97b89462f5f3943f", size = 5959015, upload-time = "2026-01-10T06:42:59.631Z" }, - { url = "https://files.pythonhosted.org/packages/51/cf/52a703dbeb0c65807540d29699fef5fda073434ff61846a564d5c296420f/numpy-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:e1a27bb1b2dee45a2a53f5ca6ff2d1a7f135287883a1689e930d44d1ff296c87", size = 12310730, upload-time = "2026-01-10T06:43:01.627Z" }, - { url = "https://files.pythonhosted.org/packages/69/80/a828b2d0ade5e74a9fe0f4e0a17c30fdc26232ad2bc8c9f8b3197cf7cf18/numpy-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:0e6e8f9d9ecf95399982019c01223dc130542960a12edfa8edd1122dfa66a8a8", size = 10312166, upload-time = "2026-01-10T06:43:03.673Z" }, - { url = "https://files.pythonhosted.org/packages/04/68/732d4b7811c00775f3bd522a21e8dd5a23f77eb11acdeb663e4a4ebf0ef4/numpy-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d797454e37570cfd61143b73b8debd623c3c0952959adb817dd310a483d58a1b", size = 16652495, upload-time = "2026-01-10T06:43:06.283Z" }, - { url = "https://files.pythonhosted.org/packages/20/ca/857722353421a27f1465652b2c66813eeeccea9d76d5f7b74b99f298e60e/numpy-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82c55962006156aeef1629b953fd359064aa47e4d82cfc8e67f0918f7da3344f", size = 12368657, upload-time = "2026-01-10T06:43:09.094Z" }, - { url = "https://files.pythonhosted.org/packages/81/0d/2377c917513449cc6240031a79d30eb9a163d32a91e79e0da47c43f2c0c8/numpy-2.4.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:71abbea030f2cfc3092a0ff9f8c8fdefdc5e0bf7d9d9c99663538bb0ecdac0b9", size = 5197256, upload-time = "2026-01-10T06:43:13.634Z" }, - { url = "https://files.pythonhosted.org/packages/17/39/569452228de3f5de9064ac75137082c6214be1f5c532016549a7923ab4b5/numpy-2.4.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:5b55aa56165b17aaf15520beb9cbd33c9039810e0d9643dd4379e44294c7303e", size = 6545212, upload-time = "2026-01-10T06:43:15.661Z" }, - { url = "https://files.pythonhosted.org/packages/8c/a4/77333f4d1e4dac4395385482557aeecf4826e6ff517e32ca48e1dafbe42a/numpy-2.4.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0faba4a331195bfa96f93dd9dfaa10b2c7aa8cda3a02b7fd635e588fe821bf5", size = 14402871, upload-time = "2026-01-10T06:43:17.324Z" }, - { url = "https://files.pythonhosted.org/packages/ba/87/d341e519956273b39d8d47969dd1eaa1af740615394fe67d06f1efa68773/numpy-2.4.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e3087f53e2b4428766b54932644d148613c5a595150533ae7f00dab2f319a8", size = 16359305, upload-time = "2026-01-10T06:43:19.376Z" }, - { url = "https://files.pythonhosted.org/packages/32/91/789132c6666288eaa20ae8066bb99eba1939362e8f1a534949a215246e97/numpy-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:49e792ec351315e16da54b543db06ca8a86985ab682602d90c60ef4ff4db2a9c", size = 16181909, upload-time = "2026-01-10T06:43:21.808Z" }, - { url = "https://files.pythonhosted.org/packages/cf/b8/090b8bd27b82a844bb22ff8fdf7935cb1980b48d6e439ae116f53cdc2143/numpy-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:79e9e06c4c2379db47f3f6fc7a8652e7498251789bf8ff5bd43bf478ef314ca2", size = 18284380, upload-time = "2026-01-10T06:43:23.957Z" }, - { url = "https://files.pythonhosted.org/packages/67/78/722b62bd31842ff029412271556a1a27a98f45359dea78b1548a3a9996aa/numpy-2.4.1-cp313-cp313-win32.whl", hash = "sha256:3d1a100e48cb266090a031397863ff8a30050ceefd798f686ff92c67a486753d", size = 5957089, upload-time = "2026-01-10T06:43:27.535Z" }, - { url = "https://files.pythonhosted.org/packages/da/a6/cf32198b0b6e18d4fbfa9a21a992a7fca535b9bb2b0cdd217d4a3445b5ca/numpy-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:92a0e65272fd60bfa0d9278e0484c2f52fe03b97aedc02b357f33fe752c52ffb", size = 12307230, upload-time = "2026-01-10T06:43:29.298Z" }, - { url = "https://files.pythonhosted.org/packages/44/6c/534d692bfb7d0afe30611320c5fb713659dcb5104d7cc182aff2aea092f5/numpy-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:20d4649c773f66cc2fc36f663e091f57c3b7655f936a4c681b4250855d1da8f5", size = 10313125, upload-time = "2026-01-10T06:43:31.782Z" }, - { url = "https://files.pythonhosted.org/packages/da/a1/354583ac5c4caa566de6ddfbc42744409b515039e085fab6e0ff942e0df5/numpy-2.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f93bc6892fe7b0663e5ffa83b61aab510aacffd58c16e012bb9352d489d90cb7", size = 12496156, upload-time = "2026-01-10T06:43:34.237Z" }, - { url = "https://files.pythonhosted.org/packages/51/b0/42807c6e8cce58c00127b1dc24d365305189991f2a7917aa694a109c8d7d/numpy-2.4.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:178de8f87948163d98a4c9ab5bee4ce6519ca918926ec8df195af582de28544d", size = 5324663, upload-time = "2026-01-10T06:43:36.211Z" }, - { url = "https://files.pythonhosted.org/packages/fe/55/7a621694010d92375ed82f312b2f28017694ed784775269115323e37f5e2/numpy-2.4.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:98b35775e03ab7f868908b524fc0a84d38932d8daf7b7e1c3c3a1b6c7a2c9f15", size = 6645224, upload-time = "2026-01-10T06:43:37.884Z" }, - { url = "https://files.pythonhosted.org/packages/50/96/9fa8635ed9d7c847d87e30c834f7109fac5e88549d79ef3324ab5c20919f/numpy-2.4.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:941c2a93313d030f219f3a71fd3d91a728b82979a5e8034eb2e60d394a2b83f9", size = 14462352, upload-time = "2026-01-10T06:43:39.479Z" }, - { url = "https://files.pythonhosted.org/packages/03/d1/8cf62d8bb2062da4fb82dd5d49e47c923f9c0738032f054e0a75342faba7/numpy-2.4.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:529050522e983e00a6c1c6b67411083630de8b57f65e853d7b03d9281b8694d2", size = 16407279, upload-time = "2026-01-10T06:43:41.93Z" }, - { url = "https://files.pythonhosted.org/packages/86/1c/95c86e17c6b0b31ce6ef219da00f71113b220bcb14938c8d9a05cee0ff53/numpy-2.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2302dc0224c1cbc49bb94f7064f3f923a971bfae45c33870dcbff63a2a550505", size = 16248316, upload-time = "2026-01-10T06:43:44.121Z" }, - { url = "https://files.pythonhosted.org/packages/30/b4/e7f5ff8697274c9d0fa82398b6a372a27e5cef069b37df6355ccb1f1db1a/numpy-2.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:9171a42fcad32dcf3fa86f0a4faa5e9f8facefdb276f54b8b390d90447cff4e2", size = 18329884, upload-time = "2026-01-10T06:43:46.613Z" }, - { url = "https://files.pythonhosted.org/packages/37/a4/b073f3e9d77f9aec8debe8ca7f9f6a09e888ad1ba7488f0c3b36a94c03ac/numpy-2.4.1-cp313-cp313t-win32.whl", hash = "sha256:382ad67d99ef49024f11d1ce5dcb5ad8432446e4246a4b014418ba3a1175a1f4", size = 6081138, upload-time = "2026-01-10T06:43:48.854Z" }, - { url = "https://files.pythonhosted.org/packages/16/16/af42337b53844e67752a092481ab869c0523bc95c4e5c98e4dac4e9581ac/numpy-2.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:62fea415f83ad8fdb6c20840578e5fbaf5ddd65e0ec6c3c47eda0f69da172510", size = 12447478, upload-time = "2026-01-10T06:43:50.476Z" }, - { url = "https://files.pythonhosted.org/packages/6c/f8/fa85b2eac68ec631d0b631abc448552cb17d39afd17ec53dcbcc3537681a/numpy-2.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:a7870e8c5fc11aef57d6fea4b4085e537a3a60ad2cdd14322ed531fdca68d261", size = 10382981, upload-time = "2026-01-10T06:43:52.575Z" }, - { url = "https://files.pythonhosted.org/packages/1b/a7/ef08d25698e0e4b4efbad8d55251d20fe2a15f6d9aa7c9b30cd03c165e6f/numpy-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:3869ea1ee1a1edc16c29bbe3a2f2a4e515cc3a44d43903ad41e0cacdbaf733dc", size = 16652046, upload-time = "2026-01-10T06:43:54.797Z" }, - { url = "https://files.pythonhosted.org/packages/8f/39/e378b3e3ca13477e5ac70293ec027c438d1927f18637e396fe90b1addd72/numpy-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e867df947d427cdd7a60e3e271729090b0f0df80f5f10ab7dd436f40811699c3", size = 12378858, upload-time = "2026-01-10T06:43:57.099Z" }, - { url = "https://files.pythonhosted.org/packages/c3/74/7ec6154f0006910ed1fdbb7591cf4432307033102b8a22041599935f8969/numpy-2.4.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:e3bd2cb07841166420d2fa7146c96ce00cb3410664cbc1a6be028e456c4ee220", size = 5207417, upload-time = "2026-01-10T06:43:59.037Z" }, - { url = "https://files.pythonhosted.org/packages/f7/b7/053ac11820d84e42f8feea5cb81cc4fcd1091499b45b1ed8c7415b1bf831/numpy-2.4.1-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:f0a90aba7d521e6954670550e561a4cb925713bd944445dbe9e729b71f6cabee", size = 6542643, upload-time = "2026-01-10T06:44:01.852Z" }, - { url = "https://files.pythonhosted.org/packages/c0/c4/2e7908915c0e32ca636b92e4e4a3bdec4cb1e7eb0f8aedf1ed3c68a0d8cd/numpy-2.4.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d558123217a83b2d1ba316b986e9248a1ed1971ad495963d555ccd75dcb1556", size = 14418963, upload-time = "2026-01-10T06:44:04.047Z" }, - { url = "https://files.pythonhosted.org/packages/eb/c0/3ed5083d94e7ffd7c404e54619c088e11f2e1939a9544f5397f4adb1b8ba/numpy-2.4.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2f44de05659b67d20499cbc96d49f2650769afcb398b79b324bb6e297bfe3844", size = 16363811, upload-time = "2026-01-10T06:44:06.207Z" }, - { url = "https://files.pythonhosted.org/packages/0e/68/42b66f1852bf525050a67315a4fb94586ab7e9eaa541b1bef530fab0c5dd/numpy-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:69e7419c9012c4aaf695109564e3387f1259f001b4326dfa55907b098af082d3", size = 16197643, upload-time = "2026-01-10T06:44:08.33Z" }, - { url = "https://files.pythonhosted.org/packages/d2/40/e8714fc933d85f82c6bfc7b998a0649ad9769a32f3494ba86598aaf18a48/numpy-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2ffd257026eb1b34352e749d7cc1678b5eeec3e329ad8c9965a797e08ccba205", size = 18289601, upload-time = "2026-01-10T06:44:10.841Z" }, - { url = "https://files.pythonhosted.org/packages/80/9a/0d44b468cad50315127e884802351723daca7cf1c98d102929468c81d439/numpy-2.4.1-cp314-cp314-win32.whl", hash = "sha256:727c6c3275ddefa0dc078524a85e064c057b4f4e71ca5ca29a19163c607be745", size = 6005722, upload-time = "2026-01-10T06:44:13.332Z" }, - { url = "https://files.pythonhosted.org/packages/7e/bb/c6513edcce5a831810e2dddc0d3452ce84d208af92405a0c2e58fd8e7881/numpy-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:7d5d7999df434a038d75a748275cd6c0094b0ecdb0837342b332a82defc4dc4d", size = 12438590, upload-time = "2026-01-10T06:44:15.006Z" }, - { url = "https://files.pythonhosted.org/packages/e9/da/a598d5cb260780cf4d255102deba35c1d072dc028c4547832f45dd3323a8/numpy-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:ce9ce141a505053b3c7bce3216071f3bf5c182b8b28930f14cd24d43932cd2df", size = 10596180, upload-time = "2026-01-10T06:44:17.386Z" }, - { url = "https://files.pythonhosted.org/packages/de/bc/ea3f2c96fcb382311827231f911723aeff596364eb6e1b6d1d91128aa29b/numpy-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:4e53170557d37ae404bf8d542ca5b7c629d6efa1117dac6a83e394142ea0a43f", size = 12498774, upload-time = "2026-01-10T06:44:19.467Z" }, - { url = "https://files.pythonhosted.org/packages/aa/ab/ef9d939fe4a812648c7a712610b2ca6140b0853c5efea361301006c02ae5/numpy-2.4.1-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:a73044b752f5d34d4232f25f18160a1cc418ea4507f5f11e299d8ac36875f8a0", size = 5327274, upload-time = "2026-01-10T06:44:23.189Z" }, - { url = "https://files.pythonhosted.org/packages/bd/31/d381368e2a95c3b08b8cf7faac6004849e960f4a042d920337f71cef0cae/numpy-2.4.1-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:fb1461c99de4d040666ca0444057b06541e5642f800b71c56e6ea92d6a853a0c", size = 6648306, upload-time = "2026-01-10T06:44:25.012Z" }, - { url = "https://files.pythonhosted.org/packages/c8/e5/0989b44ade47430be6323d05c23207636d67d7362a1796ccbccac6773dd2/numpy-2.4.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:423797bdab2eeefbe608d7c1ec7b2b4fd3c58d51460f1ee26c7500a1d9c9ee93", size = 14464653, upload-time = "2026-01-10T06:44:26.706Z" }, - { url = "https://files.pythonhosted.org/packages/10/a7/cfbe475c35371cae1358e61f20c5f075badc18c4797ab4354140e1d283cf/numpy-2.4.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:52b5f61bdb323b566b528899cc7db2ba5d1015bda7ea811a8bcf3c89c331fa42", size = 16405144, upload-time = "2026-01-10T06:44:29.378Z" }, - { url = "https://files.pythonhosted.org/packages/f8/a3/0c63fe66b534888fa5177cc7cef061541064dbe2b4b60dcc60ffaf0d2157/numpy-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42d7dd5fa36d16d52a84f821eb96031836fd405ee6955dd732f2023724d0aa01", size = 16247425, upload-time = "2026-01-10T06:44:31.721Z" }, - { url = "https://files.pythonhosted.org/packages/6b/2b/55d980cfa2c93bd40ff4c290bf824d792bd41d2fe3487b07707559071760/numpy-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e7b6b5e28bbd47b7532698e5db2fe1db693d84b58c254e4389d99a27bb9b8f6b", size = 18330053, upload-time = "2026-01-10T06:44:34.617Z" }, - { url = "https://files.pythonhosted.org/packages/23/12/8b5fc6b9c487a09a7957188e0943c9ff08432c65e34567cabc1623b03a51/numpy-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:5de60946f14ebe15e713a6f22850c2372fa72f4ff9a432ab44aa90edcadaa65a", size = 6152482, upload-time = "2026-01-10T06:44:36.798Z" }, - { url = "https://files.pythonhosted.org/packages/00/a5/9f8ca5856b8940492fc24fbe13c1bc34d65ddf4079097cf9e53164d094e1/numpy-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:8f085da926c0d491ffff3096f91078cc97ea67e7e6b65e490bc8dcda65663be2", size = 12627117, upload-time = "2026-01-10T06:44:38.828Z" }, - { url = "https://files.pythonhosted.org/packages/ad/0d/eca3d962f9eef265f01a8e0d20085c6dd1f443cbffc11b6dede81fd82356/numpy-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:6436cffb4f2bf26c974344439439c95e152c9a527013f26b3577be6c2ca64295", size = 10667121, upload-time = "2026-01-10T06:44:41.644Z" }, +version = "2.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/10/8b/c265f4823726ab832de836cdd184d0986dcf94480f81e8739692a7ac7af2/numpy-2.4.3.tar.gz", hash = "sha256:483a201202b73495f00dbc83796c6ae63137a9bdade074f7648b3e32613412dd", size = 20727743, upload-time = "2026-03-09T07:58:53.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/ed/6388632536f9788cea23a3a1b629f25b43eaacd7d7377e5d6bc7b9deb69b/numpy-2.4.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:61b0cbabbb6126c8df63b9a3a0c4b1f44ebca5e12ff6997b80fcf267fb3150ef", size = 16669628, upload-time = "2026-03-09T07:56:24.252Z" }, + { url = "https://files.pythonhosted.org/packages/74/1b/ee2abfc68e1ce728b2958b6ba831d65c62e1b13ce3017c13943f8f9b5b2e/numpy-2.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7395e69ff32526710748f92cd8c9849b361830968ea3e24a676f272653e8983e", size = 14696872, upload-time = "2026-03-09T07:56:26.991Z" }, + { url = "https://files.pythonhosted.org/packages/ba/d1/780400e915ff5638166f11ca9dc2c5815189f3d7cf6f8759a1685e586413/numpy-2.4.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:abdce0f71dcb4a00e4e77f3faf05e4616ceccfe72ccaa07f47ee79cda3b7b0f4", size = 5203489, upload-time = "2026-03-09T07:56:29.414Z" }, + { url = "https://files.pythonhosted.org/packages/0b/bb/baffa907e9da4cc34a6e556d6d90e032f6d7a75ea47968ea92b4858826c4/numpy-2.4.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:48da3a4ee1336454b07497ff7ec83903efa5505792c4e6d9bf83d99dc07a1e18", size = 6550814, upload-time = "2026-03-09T07:56:32.225Z" }, + { url = "https://files.pythonhosted.org/packages/7b/12/8c9f0c6c95f76aeb20fc4a699c33e9f827fa0d0f857747c73bb7b17af945/numpy-2.4.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:32e3bef222ad6b052280311d1d60db8e259e4947052c3ae7dd6817451fc8a4c5", size = 15666601, upload-time = "2026-03-09T07:56:34.461Z" }, + { url = "https://files.pythonhosted.org/packages/bd/79/cc665495e4d57d0aa6fbcc0aa57aa82671dfc78fbf95fe733ed86d98f52a/numpy-2.4.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e7dd01a46700b1967487141a66ac1a3cf0dd8ebf1f08db37d46389401512ca97", size = 16621358, upload-time = "2026-03-09T07:56:36.852Z" }, + { url = "https://files.pythonhosted.org/packages/a8/40/b4ecb7224af1065c3539f5ecfff879d090de09608ad1008f02c05c770cb3/numpy-2.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:76f0f283506c28b12bba319c0fab98217e9f9b54e6160e9c79e9f7348ba32e9c", size = 17016135, upload-time = "2026-03-09T07:56:39.337Z" }, + { url = "https://files.pythonhosted.org/packages/f7/b1/6a88e888052eed951afed7a142dcdf3b149a030ca59b4c71eef085858e43/numpy-2.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:737f630a337364665aba3b5a77e56a68cc42d350edd010c345d65a3efa3addcc", size = 18345816, upload-time = "2026-03-09T07:56:42.31Z" }, + { url = "https://files.pythonhosted.org/packages/f3/8f/103a60c5f8c3d7fc678c19cd7b2476110da689ccb80bc18050efbaeae183/numpy-2.4.3-cp312-cp312-win32.whl", hash = "sha256:26952e18d82a1dbbc2f008d402021baa8d6fc8e84347a2072a25e08b46d698b9", size = 5960132, upload-time = "2026-03-09T07:56:44.851Z" }, + { url = "https://files.pythonhosted.org/packages/d7/7c/f5ee1bf6ed888494978046a809df2882aad35d414b622893322df7286879/numpy-2.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:65f3c2455188f09678355f5cae1f959a06b778bc66d535da07bf2ef20cd319d5", size = 12316144, upload-time = "2026-03-09T07:56:47.057Z" }, + { url = "https://files.pythonhosted.org/packages/71/46/8d1cb3f7a00f2fb6394140e7e6623696e54c6318a9d9691bb4904672cf42/numpy-2.4.3-cp312-cp312-win_arm64.whl", hash = "sha256:2abad5c7fef172b3377502bde47892439bae394a71bc329f31df0fd829b41a9e", size = 10220364, upload-time = "2026-03-09T07:56:49.849Z" }, + { url = "https://files.pythonhosted.org/packages/b6/d0/1fe47a98ce0df229238b77611340aff92d52691bcbc10583303181abf7fc/numpy-2.4.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b346845443716c8e542d54112966383b448f4a3ba5c66409771b8c0889485dd3", size = 16665297, upload-time = "2026-03-09T07:56:52.296Z" }, + { url = "https://files.pythonhosted.org/packages/27/d9/4e7c3f0e68dfa91f21c6fb6cf839bc829ec920688b1ce7ec722b1a6202fb/numpy-2.4.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2629289168f4897a3c4e23dc98d6f1731f0fc0fe52fb9db19f974041e4cc12b9", size = 14691853, upload-time = "2026-03-09T07:56:54.992Z" }, + { url = "https://files.pythonhosted.org/packages/3a/66/bd096b13a87549683812b53ab211e6d413497f84e794fb3c39191948da97/numpy-2.4.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:bb2e3cf95854233799013779216c57e153c1ee67a0bf92138acca0e429aefaee", size = 5198435, upload-time = "2026-03-09T07:56:57.184Z" }, + { url = "https://files.pythonhosted.org/packages/a2/2f/687722910b5a5601de2135c891108f51dfc873d8e43c8ed9f4ebb440b4a2/numpy-2.4.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:7f3408ff897f8ab07a07fbe2823d7aee6ff644c097cc1f90382511fe982f647f", size = 6546347, upload-time = "2026-03-09T07:56:59.531Z" }, + { url = "https://files.pythonhosted.org/packages/bf/ec/7971c4e98d86c564750393fab8d7d83d0a9432a9d78bb8a163a6dc59967a/numpy-2.4.3-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:decb0eb8a53c3b009b0962378065589685d66b23467ef5dac16cbe818afde27f", size = 15664626, upload-time = "2026-03-09T07:57:01.385Z" }, + { url = "https://files.pythonhosted.org/packages/7e/eb/7daecbea84ec935b7fc732e18f532073064a3816f0932a40a17f3349185f/numpy-2.4.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5f51900414fc9204a0e0da158ba2ac52b75656e7dce7e77fb9f84bfa343b4cc", size = 16608916, upload-time = "2026-03-09T07:57:04.008Z" }, + { url = "https://files.pythonhosted.org/packages/df/58/2a2b4a817ffd7472dca4421d9f0776898b364154e30c95f42195041dc03b/numpy-2.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6bd06731541f89cdc01b261ba2c9e037f1543df7472517836b78dfb15bd6e476", size = 17015824, upload-time = "2026-03-09T07:57:06.347Z" }, + { url = "https://files.pythonhosted.org/packages/4a/ca/627a828d44e78a418c55f82dd4caea8ea4a8ef24e5144d9e71016e52fb40/numpy-2.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:22654fe6be0e5206f553a9250762c653d3698e46686eee53b399ab90da59bd92", size = 18334581, upload-time = "2026-03-09T07:57:09.114Z" }, + { url = "https://files.pythonhosted.org/packages/cd/c0/76f93962fc79955fcba30a429b62304332345f22d4daec1cb33653425643/numpy-2.4.3-cp313-cp313-win32.whl", hash = "sha256:d71e379452a2f670ccb689ec801b1218cd3983e253105d6e83780967e899d687", size = 5958618, upload-time = "2026-03-09T07:57:11.432Z" }, + { url = "https://files.pythonhosted.org/packages/b1/3c/88af0040119209b9b5cb59485fa48b76f372c73068dbf9254784b975ac53/numpy-2.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:0a60e17a14d640f49146cb38e3f105f571318db7826d9b6fef7e4dce758faecd", size = 12312824, upload-time = "2026-03-09T07:57:13.586Z" }, + { url = "https://files.pythonhosted.org/packages/58/ce/3d07743aced3d173f877c3ef6a454c2174ba42b584ab0b7e6d99374f51ed/numpy-2.4.3-cp313-cp313-win_arm64.whl", hash = "sha256:c9619741e9da2059cd9c3f206110b97583c7152c1dc9f8aafd4beb450ac1c89d", size = 10221218, upload-time = "2026-03-09T07:57:16.183Z" }, + { url = "https://files.pythonhosted.org/packages/62/09/d96b02a91d09e9d97862f4fc8bfebf5400f567d8eb1fe4b0cc4795679c15/numpy-2.4.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7aa4e54f6469300ebca1d9eb80acd5253cdfa36f2c03d79a35883687da430875", size = 14819570, upload-time = "2026-03-09T07:57:18.564Z" }, + { url = "https://files.pythonhosted.org/packages/b5/ca/0b1aba3905fdfa3373d523b2b15b19029f4f3031c87f4066bd9d20ef6c6b/numpy-2.4.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d1b90d840b25874cf5cd20c219af10bac3667db3876d9a495609273ebe679070", size = 5326113, upload-time = "2026-03-09T07:57:21.052Z" }, + { url = "https://files.pythonhosted.org/packages/c0/63/406e0fd32fcaeb94180fd6a4c41e55736d676c54346b7efbce548b94a914/numpy-2.4.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:a749547700de0a20a6718293396ec237bb38218049cfce788e08fcb716e8cf73", size = 6646370, upload-time = "2026-03-09T07:57:22.804Z" }, + { url = "https://files.pythonhosted.org/packages/b6/d0/10f7dc157d4b37af92720a196be6f54f889e90dcd30dce9dc657ed92c257/numpy-2.4.3-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94f3c4a151a2e529adf49c1d54f0f57ff8f9b233ee4d44af623a81553ab86368", size = 15723499, upload-time = "2026-03-09T07:57:24.693Z" }, + { url = "https://files.pythonhosted.org/packages/66/f1/d1c2bf1161396629701bc284d958dc1efa3a5a542aab83cf11ee6eb4cba5/numpy-2.4.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22c31dc07025123aedf7f2db9e91783df13f1776dc52c6b22c620870dc0fab22", size = 16657164, upload-time = "2026-03-09T07:57:27.676Z" }, + { url = "https://files.pythonhosted.org/packages/1a/be/cca19230b740af199ac47331a21c71e7a3d0ba59661350483c1600d28c37/numpy-2.4.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:148d59127ac95979d6f07e4d460f934ebdd6eed641db9c0db6c73026f2b2101a", size = 17081544, upload-time = "2026-03-09T07:57:30.664Z" }, + { url = "https://files.pythonhosted.org/packages/b9/c5/9602b0cbb703a0936fb40f8a95407e8171935b15846de2f0776e08af04c7/numpy-2.4.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a97cbf7e905c435865c2d939af3d93f99d18eaaa3cabe4256f4304fb51604349", size = 18380290, upload-time = "2026-03-09T07:57:33.763Z" }, + { url = "https://files.pythonhosted.org/packages/ed/81/9f24708953cd30be9ee36ec4778f4b112b45165812f2ada4cc5ea1c1f254/numpy-2.4.3-cp313-cp313t-win32.whl", hash = "sha256:be3b8487d725a77acccc9924f65fd8bce9af7fac8c9820df1049424a2115af6c", size = 6082814, upload-time = "2026-03-09T07:57:36.491Z" }, + { url = "https://files.pythonhosted.org/packages/e2/9e/52f6eaa13e1a799f0ab79066c17f7016a4a8ae0c1aefa58c82b4dab690b4/numpy-2.4.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1ec84fd7c8e652b0f4aaaf2e6e9cc8eaa9b1b80a537e06b2e3a2fb176eedcb26", size = 12452673, upload-time = "2026-03-09T07:57:38.281Z" }, + { url = "https://files.pythonhosted.org/packages/c4/04/b8cece6ead0b30c9fbd99bb835ad7ea0112ac5f39f069788c5558e3b1ab2/numpy-2.4.3-cp313-cp313t-win_arm64.whl", hash = "sha256:120df8c0a81ebbf5b9020c91439fccd85f5e018a927a39f624845be194a2be02", size = 10290907, upload-time = "2026-03-09T07:57:40.747Z" }, + { url = "https://files.pythonhosted.org/packages/70/ae/3936f79adebf8caf81bd7a599b90a561334a658be4dcc7b6329ebf4ee8de/numpy-2.4.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:5884ce5c7acfae1e4e1b6fde43797d10aa506074d25b531b4f54bde33c0c31d4", size = 16664563, upload-time = "2026-03-09T07:57:43.817Z" }, + { url = "https://files.pythonhosted.org/packages/9b/62/760f2b55866b496bb1fa7da2a6db076bef908110e568b02fcfc1422e2a3a/numpy-2.4.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:297837823f5bc572c5f9379b0c9f3a3365f08492cbdc33bcc3af174372ebb168", size = 14702161, upload-time = "2026-03-09T07:57:46.169Z" }, + { url = "https://files.pythonhosted.org/packages/32/af/a7a39464e2c0a21526fb4fb76e346fb172ebc92f6d1c7a07c2c139cc17b1/numpy-2.4.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:a111698b4a3f8dcbe54c64a7708f049355abd603e619013c346553c1fd4ca90b", size = 5208738, upload-time = "2026-03-09T07:57:48.506Z" }, + { url = "https://files.pythonhosted.org/packages/29/8c/2a0cf86a59558fa078d83805589c2de490f29ed4fb336c14313a161d358a/numpy-2.4.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:4bd4741a6a676770e0e97fe9ab2e51de01183df3dcbcec591d26d331a40de950", size = 6543618, upload-time = "2026-03-09T07:57:50.591Z" }, + { url = "https://files.pythonhosted.org/packages/aa/b8/612ce010c0728b1c363fa4ea3aa4c22fe1c5da1de008486f8c2f5cb92fae/numpy-2.4.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:54f29b877279d51e210e0c80709ee14ccbbad647810e8f3d375561c45ef613dd", size = 15680676, upload-time = "2026-03-09T07:57:52.34Z" }, + { url = "https://files.pythonhosted.org/packages/a9/7e/4f120ecc54ba26ddf3dc348eeb9eb063f421de65c05fc961941798feea18/numpy-2.4.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:679f2a834bae9020f81534671c56fd0cc76dd7e5182f57131478e23d0dc59e24", size = 16613492, upload-time = "2026-03-09T07:57:54.91Z" }, + { url = "https://files.pythonhosted.org/packages/2c/86/1b6020db73be330c4b45d5c6ee4295d59cfeef0e3ea323959d053e5a6909/numpy-2.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d84f0f881cb2225c2dfd7f78a10a5645d487a496c6668d6cc39f0f114164f3d0", size = 17031789, upload-time = "2026-03-09T07:57:57.641Z" }, + { url = "https://files.pythonhosted.org/packages/07/3a/3b90463bf41ebc21d1b7e06079f03070334374208c0f9a1f05e4ae8455e7/numpy-2.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d213c7e6e8d211888cc359bab7199670a00f5b82c0978b9d1c75baf1eddbeac0", size = 18339941, upload-time = "2026-03-09T07:58:00.577Z" }, + { url = "https://files.pythonhosted.org/packages/a8/74/6d736c4cd962259fd8bae9be27363eb4883a2f9069763747347544c2a487/numpy-2.4.3-cp314-cp314-win32.whl", hash = "sha256:52077feedeff7c76ed7c9f1a0428558e50825347b7545bbb8523da2cd55c547a", size = 6007503, upload-time = "2026-03-09T07:58:03.331Z" }, + { url = "https://files.pythonhosted.org/packages/48/39/c56ef87af669364356bb011922ef0734fc49dad51964568634c72a009488/numpy-2.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:0448e7f9caefb34b4b7dd2b77f21e8906e5d6f0365ad525f9f4f530b13df2afc", size = 12444915, upload-time = "2026-03-09T07:58:06.353Z" }, + { url = "https://files.pythonhosted.org/packages/9d/1f/ab8528e38d295fd349310807496fabb7cf9fe2e1f70b97bc20a483ea9d4a/numpy-2.4.3-cp314-cp314-win_arm64.whl", hash = "sha256:b44fd60341c4d9783039598efadd03617fa28d041fc37d22b62d08f2027fa0e7", size = 10494875, upload-time = "2026-03-09T07:58:08.734Z" }, + { url = "https://files.pythonhosted.org/packages/e6/ef/b7c35e4d5ef141b836658ab21a66d1a573e15b335b1d111d31f26c8ef80f/numpy-2.4.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0a195f4216be9305a73c0e91c9b026a35f2161237cf1c6de9b681637772ea657", size = 14822225, upload-time = "2026-03-09T07:58:11.034Z" }, + { url = "https://files.pythonhosted.org/packages/cd/8d/7730fa9278cf6648639946cc816e7cc89f0d891602584697923375f801ed/numpy-2.4.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:cd32fbacb9fd1bf041bf8e89e4576b6f00b895f06d00914820ae06a616bdfef7", size = 5328769, upload-time = "2026-03-09T07:58:13.67Z" }, + { url = "https://files.pythonhosted.org/packages/47/01/d2a137317c958b074d338807c1b6a383406cdf8b8e53b075d804cc3d211d/numpy-2.4.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:2e03c05abaee1f672e9d67bc858f300b5ccba1c21397211e8d77d98350972093", size = 6649461, upload-time = "2026-03-09T07:58:15.912Z" }, + { url = "https://files.pythonhosted.org/packages/5c/34/812ce12bc0f00272a4b0ec0d713cd237cb390666eb6206323d1cc9cedbb2/numpy-2.4.3-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d1ce23cce91fcea443320a9d0ece9b9305d4368875bab09538f7a5b4131938a", size = 15725809, upload-time = "2026-03-09T07:58:17.787Z" }, + { url = "https://files.pythonhosted.org/packages/25/c0/2aed473a4823e905e765fee3dc2cbf504bd3e68ccb1150fbdabd5c39f527/numpy-2.4.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c59020932feb24ed49ffd03704fbab89f22aa9c0d4b180ff45542fe8918f5611", size = 16655242, upload-time = "2026-03-09T07:58:20.476Z" }, + { url = "https://files.pythonhosted.org/packages/f2/c8/7e052b2fc87aa0e86de23f20e2c42bd261c624748aa8efd2c78f7bb8d8c6/numpy-2.4.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9684823a78a6cd6ad7511fc5e25b07947d1d5b5e2812c93fe99d7d4195130720", size = 17080660, upload-time = "2026-03-09T07:58:23.067Z" }, + { url = "https://files.pythonhosted.org/packages/f3/3d/0876746044db2adcb11549f214d104f2e1be00f07a67edbb4e2812094847/numpy-2.4.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0200b25c687033316fb39f0ff4e3e690e8957a2c3c8d22499891ec58c37a3eb5", size = 18380384, upload-time = "2026-03-09T07:58:25.839Z" }, + { url = "https://files.pythonhosted.org/packages/07/12/8160bea39da3335737b10308df4f484235fd297f556745f13092aa039d3b/numpy-2.4.3-cp314-cp314t-win32.whl", hash = "sha256:5e10da9e93247e554bb1d22f8edc51847ddd7dde52d85ce31024c1b4312bfba0", size = 6154547, upload-time = "2026-03-09T07:58:28.289Z" }, + { url = "https://files.pythonhosted.org/packages/42/f3/76534f61f80d74cc9cdf2e570d3d4eeb92c2280a27c39b0aaf471eda7b48/numpy-2.4.3-cp314-cp314t-win_amd64.whl", hash = "sha256:45f003dbdffb997a03da2d1d0cb41fbd24a87507fb41605c0420a3db5bd4667b", size = 12633645, upload-time = "2026-03-09T07:58:30.384Z" }, + { url = "https://files.pythonhosted.org/packages/1f/b6/7c0d4334c15983cec7f92a69e8ce9b1e6f31857e5ee3a413ac424e6bd63d/numpy-2.4.3-cp314-cp314t-win_arm64.whl", hash = "sha256:4d382735cecd7bcf090172489a525cd7d4087bc331f7df9f60ddc9a296cf208e", size = 10565454, upload-time = "2026-03-09T07:58:33.031Z" }, ] [[package]] @@ -1015,145 +1082,144 @@ wheels = [ [[package]] name = "pandas" -version = "3.0.0" +version = "3.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, { name = "python-dateutil" }, { name = "tzdata", marker = "sys_platform == 'emscripten' or sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/de/da/b1dc0481ab8d55d0f46e343cfe67d4551a0e14fcee52bd38ca1bd73258d8/pandas-3.0.0.tar.gz", hash = "sha256:0facf7e87d38f721f0af46fe70d97373a37701b1c09f7ed7aeeb292ade5c050f", size = 4633005, upload-time = "2026-01-21T15:52:04.726Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/38/db33686f4b5fa64d7af40d96361f6a4615b8c6c8f1b3d334eee46ae6160e/pandas-3.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9803b31f5039b3c3b10cc858c5e40054adb4b29b4d81cb2fd789f4121c8efbcd", size = 10334013, upload-time = "2026-01-21T15:50:34.771Z" }, - { url = "https://files.pythonhosted.org/packages/a5/7b/9254310594e9774906bacdd4e732415e1f86ab7dbb4b377ef9ede58cd8ec/pandas-3.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:14c2a4099cd38a1d18ff108168ea417909b2dea3bd1ebff2ccf28ddb6a74d740", size = 9874154, upload-time = "2026-01-21T15:50:36.67Z" }, - { url = "https://files.pythonhosted.org/packages/63/d4/726c5a67a13bc66643e66d2e9ff115cead482a44fc56991d0c4014f15aaf/pandas-3.0.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d257699b9a9960e6125686098d5714ac59d05222bef7a5e6af7a7fd87c650801", size = 10384433, upload-time = "2026-01-21T15:50:39.132Z" }, - { url = "https://files.pythonhosted.org/packages/bf/2e/9211f09bedb04f9832122942de8b051804b31a39cfbad199a819bb88d9f3/pandas-3.0.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:69780c98f286076dcafca38d8b8eee1676adf220199c0a39f0ecbf976b68151a", size = 10864519, upload-time = "2026-01-21T15:50:41.043Z" }, - { url = "https://files.pythonhosted.org/packages/00/8d/50858522cdc46ac88b9afdc3015e298959a70a08cd21e008a44e9520180c/pandas-3.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4a66384f017240f3858a4c8a7cf21b0591c3ac885cddb7758a589f0f71e87ebb", size = 11394124, upload-time = "2026-01-21T15:50:43.377Z" }, - { url = "https://files.pythonhosted.org/packages/86/3f/83b2577db02503cd93d8e95b0f794ad9d4be0ba7cb6c8bcdcac964a34a42/pandas-3.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be8c515c9bc33989d97b89db66ea0cececb0f6e3c2a87fcc8b69443a6923e95f", size = 11920444, upload-time = "2026-01-21T15:50:45.932Z" }, - { url = "https://files.pythonhosted.org/packages/64/2d/4f8a2f192ed12c90a0aab47f5557ece0e56b0370c49de9454a09de7381b2/pandas-3.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:a453aad8c4f4e9f166436994a33884442ea62aa8b27d007311e87521b97246e1", size = 9730970, upload-time = "2026-01-21T15:50:47.962Z" }, - { url = "https://files.pythonhosted.org/packages/d4/64/ff571be435cf1e643ca98d0945d76732c0b4e9c37191a89c8550b105eed1/pandas-3.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:da768007b5a33057f6d9053563d6b74dd6d029c337d93c6d0d22a763a5c2ecc0", size = 9041950, upload-time = "2026-01-21T15:50:50.422Z" }, - { url = "https://files.pythonhosted.org/packages/6f/fa/7f0ac4ca8877c57537aaff2a842f8760e630d8e824b730eb2e859ffe96ca/pandas-3.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b78d646249b9a2bc191040988c7bb524c92fa8534fb0898a0741d7e6f2ffafa6", size = 10307129, upload-time = "2026-01-21T15:50:52.877Z" }, - { url = "https://files.pythonhosted.org/packages/6f/11/28a221815dcea4c0c9414dfc845e34a84a6a7dabc6da3194498ed5ba4361/pandas-3.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bc9cba7b355cb4162442a88ce495e01cb605f17ac1e27d6596ac963504e0305f", size = 9850201, upload-time = "2026-01-21T15:50:54.807Z" }, - { url = "https://files.pythonhosted.org/packages/ba/da/53bbc8c5363b7e5bd10f9ae59ab250fc7a382ea6ba08e4d06d8694370354/pandas-3.0.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c9a1a149aed3b6c9bf246033ff91e1b02d529546c5d6fb6b74a28fea0cf4c70", size = 10354031, upload-time = "2026-01-21T15:50:57.463Z" }, - { url = "https://files.pythonhosted.org/packages/f7/a3/51e02ebc2a14974170d51e2410dfdab58870ea9bcd37cda15bd553d24dc4/pandas-3.0.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:95683af6175d884ee89471842acfca29172a85031fccdabc35e50c0984470a0e", size = 10861165, upload-time = "2026-01-21T15:50:59.32Z" }, - { url = "https://files.pythonhosted.org/packages/a5/fe/05a51e3cac11d161472b8297bd41723ea98013384dd6d76d115ce3482f9b/pandas-3.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1fbbb5a7288719e36b76b4f18d46ede46e7f916b6c8d9915b756b0a6c3f792b3", size = 11359359, upload-time = "2026-01-21T15:51:02.014Z" }, - { url = "https://files.pythonhosted.org/packages/ee/56/ba620583225f9b85a4d3e69c01df3e3870659cc525f67929b60e9f21dcd1/pandas-3.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8e8b9808590fa364416b49b2a35c1f4cf2785a6c156935879e57f826df22038e", size = 11912907, upload-time = "2026-01-21T15:51:05.175Z" }, - { url = "https://files.pythonhosted.org/packages/c9/8c/c6638d9f67e45e07656b3826405c5cc5f57f6fd07c8b2572ade328c86e22/pandas-3.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:98212a38a709feb90ae658cb6227ea3657c22ba8157d4b8f913cd4c950de5e7e", size = 9732138, upload-time = "2026-01-21T15:51:07.569Z" }, - { url = "https://files.pythonhosted.org/packages/7b/bf/bd1335c3bf1770b6d8fed2799993b11c4971af93bb1b729b9ebbc02ca2ec/pandas-3.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:177d9df10b3f43b70307a149d7ec49a1229a653f907aa60a48f1877d0e6be3be", size = 9033568, upload-time = "2026-01-21T15:51:09.484Z" }, - { url = "https://files.pythonhosted.org/packages/8e/c6/f5e2171914d5e29b9171d495344097d54e3ffe41d2d85d8115baba4dc483/pandas-3.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2713810ad3806767b89ad3b7b69ba153e1c6ff6d9c20f9c2140379b2a98b6c98", size = 10741936, upload-time = "2026-01-21T15:51:11.693Z" }, - { url = "https://files.pythonhosted.org/packages/51/88/9a0164f99510a1acb9f548691f022c756c2314aad0d8330a24616c14c462/pandas-3.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:15d59f885ee5011daf8335dff47dcb8a912a27b4ad7826dc6cbe809fd145d327", size = 10393884, upload-time = "2026-01-21T15:51:14.197Z" }, - { url = "https://files.pythonhosted.org/packages/e0/53/b34d78084d88d8ae2b848591229da8826d1e65aacf00b3abe34023467648/pandas-3.0.0-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:24e6547fb64d2c92665dd2adbfa4e85fa4fd70a9c070e7cfb03b629a0bbab5eb", size = 10310740, upload-time = "2026-01-21T15:51:16.093Z" }, - { url = "https://files.pythonhosted.org/packages/5b/d3/bee792e7c3d6930b74468d990604325701412e55d7aaf47460a22311d1a5/pandas-3.0.0-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:48ee04b90e2505c693d3f8e8f524dab8cb8aaf7ddcab52c92afa535e717c4812", size = 10700014, upload-time = "2026-01-21T15:51:18.818Z" }, - { url = "https://files.pythonhosted.org/packages/55/db/2570bc40fb13aaed1cbc3fbd725c3a60ee162477982123c3adc8971e7ac1/pandas-3.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:66f72fb172959af42a459e27a8d8d2c7e311ff4c1f7db6deb3b643dbc382ae08", size = 11323737, upload-time = "2026-01-21T15:51:20.784Z" }, - { url = "https://files.pythonhosted.org/packages/bc/2e/297ac7f21c8181b62a4cccebad0a70caf679adf3ae5e83cb676194c8acc3/pandas-3.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4a4a400ca18230976724a5066f20878af785f36c6756e498e94c2a5e5d57779c", size = 11771558, upload-time = "2026-01-21T15:51:22.977Z" }, - { url = "https://files.pythonhosted.org/packages/0a/46/e1c6876d71c14332be70239acce9ad435975a80541086e5ffba2f249bcf6/pandas-3.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:940eebffe55528074341a5a36515f3e4c5e25e958ebbc764c9502cfc35ba3faa", size = 10473771, upload-time = "2026-01-21T15:51:25.285Z" }, - { url = "https://files.pythonhosted.org/packages/c0/db/0270ad9d13c344b7a36fa77f5f8344a46501abf413803e885d22864d10bf/pandas-3.0.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:597c08fb9fef0edf1e4fa2f9828dd27f3d78f9b8c9b4a748d435ffc55732310b", size = 10312075, upload-time = "2026-01-21T15:51:28.5Z" }, - { url = "https://files.pythonhosted.org/packages/09/9f/c176f5e9717f7c91becfe0f55a52ae445d3f7326b4a2cf355978c51b7913/pandas-3.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:447b2d68ac5edcbf94655fe909113a6dba6ef09ad7f9f60c80477825b6c489fe", size = 9900213, upload-time = "2026-01-21T15:51:30.955Z" }, - { url = "https://files.pythonhosted.org/packages/d9/e7/63ad4cc10b257b143e0a5ebb04304ad806b4e1a61c5da25f55896d2ca0f4/pandas-3.0.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:debb95c77ff3ed3ba0d9aa20c3a2f19165cc7956362f9873fce1ba0a53819d70", size = 10428768, upload-time = "2026-01-21T15:51:33.018Z" }, - { url = "https://files.pythonhosted.org/packages/9e/0e/4e4c2d8210f20149fd2248ef3fff26623604922bd564d915f935a06dd63d/pandas-3.0.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fedabf175e7cd82b69b74c30adbaa616de301291a5231138d7242596fc296a8d", size = 10882954, upload-time = "2026-01-21T15:51:35.287Z" }, - { url = "https://files.pythonhosted.org/packages/c6/60/c9de8ac906ba1f4d2250f8a951abe5135b404227a55858a75ad26f84db47/pandas-3.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:412d1a89aab46889f3033a386912efcdfa0f1131c5705ff5b668dda88305e986", size = 11430293, upload-time = "2026-01-21T15:51:37.57Z" }, - { url = "https://files.pythonhosted.org/packages/a1/69/806e6637c70920e5787a6d6896fd707f8134c2c55cd761e7249a97b7dc5a/pandas-3.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e979d22316f9350c516479dd3a92252be2937a9531ed3a26ec324198a99cdd49", size = 11952452, upload-time = "2026-01-21T15:51:39.618Z" }, - { url = "https://files.pythonhosted.org/packages/cb/de/918621e46af55164c400ab0ef389c9d969ab85a43d59ad1207d4ddbe30a5/pandas-3.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:083b11415b9970b6e7888800c43c82e81a06cd6b06755d84804444f0007d6bb7", size = 9851081, upload-time = "2026-01-21T15:51:41.758Z" }, - { url = "https://files.pythonhosted.org/packages/91/a1/3562a18dd0bd8c73344bfa26ff90c53c72f827df119d6d6b1dacc84d13e3/pandas-3.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:5db1e62cb99e739fa78a28047e861b256d17f88463c76b8dafc7c1338086dca8", size = 9174610, upload-time = "2026-01-21T15:51:44.312Z" }, - { url = "https://files.pythonhosted.org/packages/ce/26/430d91257eaf366f1737d7a1c158677caaf6267f338ec74e3a1ec444111c/pandas-3.0.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:697b8f7d346c68274b1b93a170a70974cdc7d7354429894d5927c1effdcccd73", size = 10761999, upload-time = "2026-01-21T15:51:46.899Z" }, - { url = "https://files.pythonhosted.org/packages/ec/1a/954eb47736c2b7f7fe6a9d56b0cb6987773c00faa3c6451a43db4beb3254/pandas-3.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8cb3120f0d9467ed95e77f67a75e030b67545bcfa08964e349252d674171def2", size = 10410279, upload-time = "2026-01-21T15:51:48.89Z" }, - { url = "https://files.pythonhosted.org/packages/20/fc/b96f3a5a28b250cd1b366eb0108df2501c0f38314a00847242abab71bb3a/pandas-3.0.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:33fd3e6baa72899746b820c31e4b9688c8e1b7864d7aec2de7ab5035c285277a", size = 10330198, upload-time = "2026-01-21T15:51:51.015Z" }, - { url = "https://files.pythonhosted.org/packages/90/b3/d0e2952f103b4fbef1ef22d0c2e314e74fc9064b51cee30890b5e3286ee6/pandas-3.0.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8942e333dc67ceda1095227ad0febb05a3b36535e520154085db632c40ad084", size = 10728513, upload-time = "2026-01-21T15:51:53.387Z" }, - { url = "https://files.pythonhosted.org/packages/76/81/832894f286df828993dc5fd61c63b231b0fb73377e99f6c6c369174cf97e/pandas-3.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:783ac35c4d0fe0effdb0d67161859078618b1b6587a1af15928137525217a721", size = 11345550, upload-time = "2026-01-21T15:51:55.329Z" }, - { url = "https://files.pythonhosted.org/packages/34/a0/ed160a00fb4f37d806406bc0a79a8b62fe67f29d00950f8d16203ff3409b/pandas-3.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:125eb901e233f155b268bbef9abd9afb5819db74f0e677e89a61b246228c71ac", size = 11799386, upload-time = "2026-01-21T15:51:57.457Z" }, - { url = "https://files.pythonhosted.org/packages/36/c8/2ac00d7255252c5e3cf61b35ca92ca25704b0188f7454ca4aec08a33cece/pandas-3.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b86d113b6c109df3ce0ad5abbc259fe86a1bd4adfd4a31a89da42f84f65509bb", size = 10873041, upload-time = "2026-01-21T15:52:00.034Z" }, - { url = "https://files.pythonhosted.org/packages/e6/3f/a80ac00acbc6b35166b42850e98a4f466e2c0d9c64054161ba9620f95680/pandas-3.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:1c39eab3ad38f2d7a249095f0a3d8f8c22cc0f847e98ccf5bbe732b272e2d9fa", size = 9441003, upload-time = "2026-01-21T15:52:02.281Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/2e/0c/b28ed414f080ee0ad153f848586d61d1878f91689950f037f976ce15f6c8/pandas-3.0.1.tar.gz", hash = "sha256:4186a699674af418f655dbd420ed87f50d56b4cd6603784279d9eef6627823c8", size = 4641901, upload-time = "2026-02-17T22:20:16.434Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/37/51/b467209c08dae2c624873d7491ea47d2b47336e5403309d433ea79c38571/pandas-3.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:476f84f8c20c9f5bc47252b66b4bb25e1a9fc2fa98cead96744d8116cb85771d", size = 10344357, upload-time = "2026-02-17T22:18:38.262Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f1/e2567ffc8951ab371db2e40b2fe068e36b81d8cf3260f06ae508700e5504/pandas-3.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0ab749dfba921edf641d4036c4c21c0b3ea70fea478165cb98a998fb2a261955", size = 9884543, upload-time = "2026-02-17T22:18:41.476Z" }, + { url = "https://files.pythonhosted.org/packages/d7/39/327802e0b6d693182403c144edacbc27eb82907b57062f23ef5a4c4a5ea7/pandas-3.0.1-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8e36891080b87823aff3640c78649b91b8ff6eea3c0d70aeabd72ea43ab069b", size = 10396030, upload-time = "2026-02-17T22:18:43.822Z" }, + { url = "https://files.pythonhosted.org/packages/3d/fe/89d77e424365280b79d99b3e1e7d606f5165af2f2ecfaf0c6d24c799d607/pandas-3.0.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:532527a701281b9dd371e2f582ed9094f4c12dd9ffb82c0c54ee28d8ac9520c4", size = 10876435, upload-time = "2026-02-17T22:18:45.954Z" }, + { url = "https://files.pythonhosted.org/packages/b5/a6/2a75320849dd154a793f69c951db759aedb8d1dd3939eeacda9bdcfa1629/pandas-3.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:356e5c055ed9b0da1580d465657bc7d00635af4fd47f30afb23025352ba764d1", size = 11405133, upload-time = "2026-02-17T22:18:48.533Z" }, + { url = "https://files.pythonhosted.org/packages/58/53/1d68fafb2e02d7881df66aa53be4cd748d25cbe311f3b3c85c93ea5d30ca/pandas-3.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9d810036895f9ad6345b8f2a338dd6998a74e8483847403582cab67745bff821", size = 11932065, upload-time = "2026-02-17T22:18:50.837Z" }, + { url = "https://files.pythonhosted.org/packages/75/08/67cc404b3a966b6df27b38370ddd96b3b023030b572283d035181854aac5/pandas-3.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:536232a5fe26dd989bd633e7a0c450705fdc86a207fec7254a55e9a22950fe43", size = 9741627, upload-time = "2026-02-17T22:18:53.905Z" }, + { url = "https://files.pythonhosted.org/packages/86/4f/caf9952948fb00d23795f09b893d11f1cacb384e666854d87249530f7cbe/pandas-3.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:0f463ebfd8de7f326d38037c7363c6dacb857c5881ab8961fb387804d6daf2f7", size = 9052483, upload-time = "2026-02-17T22:18:57.31Z" }, + { url = "https://files.pythonhosted.org/packages/0b/48/aad6ec4f8d007534c091e9a7172b3ec1b1ee6d99a9cbb936b5eab6c6cf58/pandas-3.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5272627187b5d9c20e55d27caf5f2cd23e286aba25cadf73c8590e432e2b7262", size = 10317509, upload-time = "2026-02-17T22:18:59.498Z" }, + { url = "https://files.pythonhosted.org/packages/a8/14/5990826f779f79148ae9d3a2c39593dc04d61d5d90541e71b5749f35af95/pandas-3.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:661e0f665932af88c7877f31da0dc743fe9c8f2524bdffe23d24fdcb67ef9d56", size = 9860561, upload-time = "2026-02-17T22:19:02.265Z" }, + { url = "https://files.pythonhosted.org/packages/fa/80/f01ff54664b6d70fed71475543d108a9b7c888e923ad210795bef04ffb7d/pandas-3.0.1-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:75e6e292ff898679e47a2199172593d9f6107fd2dd3617c22c2946e97d5df46e", size = 10365506, upload-time = "2026-02-17T22:19:05.017Z" }, + { url = "https://files.pythonhosted.org/packages/f2/85/ab6d04733a7d6ff32bfc8382bf1b07078228f5d6ebec5266b91bfc5c4ff7/pandas-3.0.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1ff8cf1d2896e34343197685f432450ec99a85ba8d90cce2030c5eee2ef98791", size = 10873196, upload-time = "2026-02-17T22:19:07.204Z" }, + { url = "https://files.pythonhosted.org/packages/48/a9/9301c83d0b47c23ac5deab91c6b39fd98d5b5db4d93b25df8d381451828f/pandas-3.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eca8b4510f6763f3d37359c2105df03a7a221a508f30e396a51d0713d462e68a", size = 11370859, upload-time = "2026-02-17T22:19:09.436Z" }, + { url = "https://files.pythonhosted.org/packages/59/fe/0c1fc5bd2d29c7db2ab372330063ad555fb83e08422829c785f5ec2176ca/pandas-3.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:06aff2ad6f0b94a17822cf8b83bbb563b090ed82ff4fe7712db2ce57cd50d9b8", size = 11924584, upload-time = "2026-02-17T22:19:11.562Z" }, + { url = "https://files.pythonhosted.org/packages/d6/7d/216a1588b65a7aa5f4535570418a599d943c85afb1d95b0876fc00aa1468/pandas-3.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:9fea306c783e28884c29057a1d9baa11a349bbf99538ec1da44c8476563d1b25", size = 9742769, upload-time = "2026-02-17T22:19:13.926Z" }, + { url = "https://files.pythonhosted.org/packages/c4/cb/810a22a6af9a4e97c8ab1c946b47f3489c5bca5adc483ce0ffc84c9cc768/pandas-3.0.1-cp313-cp313-win_arm64.whl", hash = "sha256:a8d37a43c52917427e897cb2e429f67a449327394396a81034a4449b99afda59", size = 9043855, upload-time = "2026-02-17T22:19:16.09Z" }, + { url = "https://files.pythonhosted.org/packages/92/fa/423c89086cca1f039cf1253c3ff5b90f157b5b3757314aa635f6bf3e30aa/pandas-3.0.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d54855f04f8246ed7b6fc96b05d4871591143c46c0b6f4af874764ed0d2d6f06", size = 10752673, upload-time = "2026-02-17T22:19:18.304Z" }, + { url = "https://files.pythonhosted.org/packages/22/23/b5a08ec1f40020397f0faba72f1e2c11f7596a6169c7b3e800abff0e433f/pandas-3.0.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e1b677accee34a09e0dc2ce5624e4a58a1870ffe56fc021e9caf7f23cd7668f", size = 10404967, upload-time = "2026-02-17T22:19:20.726Z" }, + { url = "https://files.pythonhosted.org/packages/5c/81/94841f1bb4afdc2b52a99daa895ac2c61600bb72e26525ecc9543d453ebc/pandas-3.0.1-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a9cabbdcd03f1b6cd254d6dda8ae09b0252524be1592594c00b7895916cb1324", size = 10320575, upload-time = "2026-02-17T22:19:24.919Z" }, + { url = "https://files.pythonhosted.org/packages/0a/8b/2ae37d66a5342a83adadfd0cb0b4bf9c3c7925424dd5f40d15d6cfaa35ee/pandas-3.0.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ae2ab1f166668b41e770650101e7090824fd34d17915dd9cd479f5c5e0065e9", size = 10710921, upload-time = "2026-02-17T22:19:27.181Z" }, + { url = "https://files.pythonhosted.org/packages/a2/61/772b2e2757855e232b7ccf7cb8079a5711becb3a97f291c953def15a833f/pandas-3.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6bf0603c2e30e2cafac32807b06435f28741135cb8697eae8b28c7d492fc7d76", size = 11334191, upload-time = "2026-02-17T22:19:29.411Z" }, + { url = "https://files.pythonhosted.org/packages/1b/08/b16c6df3ef555d8495d1d265a7963b65be166785d28f06a350913a4fac78/pandas-3.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6c426422973973cae1f4a23e51d4ae85974f44871b24844e4f7de752dd877098", size = 11782256, upload-time = "2026-02-17T22:19:32.34Z" }, + { url = "https://files.pythonhosted.org/packages/55/80/178af0594890dee17e239fca96d3d8670ba0f5ff59b7d0439850924a9c09/pandas-3.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b03f91ae8c10a85c1613102c7bef5229b5379f343030a3ccefeca8a33414cf35", size = 10485047, upload-time = "2026-02-17T22:19:34.605Z" }, + { url = "https://files.pythonhosted.org/packages/bb/8b/4bb774a998b97e6c2fd62a9e6cfdaae133b636fd1c468f92afb4ae9a447a/pandas-3.0.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:99d0f92ed92d3083d140bf6b97774f9f13863924cf3f52a70711f4e7588f9d0a", size = 10322465, upload-time = "2026-02-17T22:19:36.803Z" }, + { url = "https://files.pythonhosted.org/packages/72/3a/5b39b51c64159f470f1ca3b1c2a87da290657ca022f7cd11442606f607d1/pandas-3.0.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3b66857e983208654294bb6477b8a63dee26b37bdd0eb34d010556e91261784f", size = 9910632, upload-time = "2026-02-17T22:19:39.001Z" }, + { url = "https://files.pythonhosted.org/packages/4e/f7/b449ffb3f68c11da12fc06fbf6d2fa3a41c41e17d0284d23a79e1c13a7e4/pandas-3.0.1-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56cf59638bf24dc9bdf2154c81e248b3289f9a09a6d04e63608c159022352749", size = 10440535, upload-time = "2026-02-17T22:19:41.157Z" }, + { url = "https://files.pythonhosted.org/packages/55/77/6ea82043db22cb0f2bbfe7198da3544000ddaadb12d26be36e19b03a2dc5/pandas-3.0.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c1a9f55e0f46951874b863d1f3906dcb57df2d9be5c5847ba4dfb55b2c815249", size = 10893940, upload-time = "2026-02-17T22:19:43.493Z" }, + { url = "https://files.pythonhosted.org/packages/03/30/f1b502a72468c89412c1b882a08f6eed8a4ee9dc033f35f65d0663df6081/pandas-3.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1849f0bba9c8a2fb0f691d492b834cc8dadf617e29015c66e989448d58d011ee", size = 11442711, upload-time = "2026-02-17T22:19:46.074Z" }, + { url = "https://files.pythonhosted.org/packages/0d/f0/ebb6ddd8fc049e98cabac5c2924d14d1dda26a20adb70d41ea2e428d3ec4/pandas-3.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c3d288439e11b5325b02ae6e9cc83e6805a62c40c5a6220bea9beb899c073b1c", size = 11963918, upload-time = "2026-02-17T22:19:48.838Z" }, + { url = "https://files.pythonhosted.org/packages/09/f8/8ce132104074f977f907442790eaae24e27bce3b3b454e82faa3237ff098/pandas-3.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:93325b0fe372d192965f4cca88d97667f49557398bbf94abdda3bf1b591dbe66", size = 9862099, upload-time = "2026-02-17T22:19:51.081Z" }, + { url = "https://files.pythonhosted.org/packages/e6/b7/6af9aac41ef2456b768ef0ae60acf8abcebb450a52043d030a65b4b7c9bd/pandas-3.0.1-cp314-cp314-win_arm64.whl", hash = "sha256:97ca08674e3287c7148f4858b01136f8bdfe7202ad25ad04fec602dd1d29d132", size = 9185333, upload-time = "2026-02-17T22:19:53.266Z" }, + { url = "https://files.pythonhosted.org/packages/66/fc/848bb6710bc6061cb0c5badd65b92ff75c81302e0e31e496d00029fe4953/pandas-3.0.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:58eeb1b2e0fb322befcf2bbc9ba0af41e616abadb3d3414a6bc7167f6cbfce32", size = 10772664, upload-time = "2026-02-17T22:19:55.806Z" }, + { url = "https://files.pythonhosted.org/packages/69/5c/866a9bbd0f79263b4b0db6ec1a341be13a1473323f05c122388e0f15b21d/pandas-3.0.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cd9af1276b5ca9e298bd79a26bda32fa9cc87ed095b2a9a60978d2ca058eaf87", size = 10421286, upload-time = "2026-02-17T22:19:58.091Z" }, + { url = "https://files.pythonhosted.org/packages/51/a4/2058fb84fb1cfbfb2d4a6d485e1940bb4ad5716e539d779852494479c580/pandas-3.0.1-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94f87a04984d6b63788327cd9f79dda62b7f9043909d2440ceccf709249ca988", size = 10342050, upload-time = "2026-02-17T22:20:01.376Z" }, + { url = "https://files.pythonhosted.org/packages/22/1b/674e89996cc4be74db3c4eb09240c4bb549865c9c3f5d9b086ff8fcfbf00/pandas-3.0.1-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85fe4c4df62e1e20f9db6ebfb88c844b092c22cd5324bdcf94bfa2fc1b391221", size = 10740055, upload-time = "2026-02-17T22:20:04.328Z" }, + { url = "https://files.pythonhosted.org/packages/d0/f8/e954b750764298c22fa4614376531fe63c521ef517e7059a51f062b87dca/pandas-3.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:331ca75a2f8672c365ae25c0b29e46f5ac0c6551fdace8eec4cd65e4fac271ff", size = 11357632, upload-time = "2026-02-17T22:20:06.647Z" }, + { url = "https://files.pythonhosted.org/packages/6d/02/c6e04b694ffd68568297abd03588b6d30295265176a5c01b7459d3bc35a3/pandas-3.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:15860b1fdb1973fffade772fdb931ccf9b2f400a3f5665aef94a00445d7d8dd5", size = 11810974, upload-time = "2026-02-17T22:20:08.946Z" }, + { url = "https://files.pythonhosted.org/packages/89/41/d7dfb63d2407f12055215070c42fc6ac41b66e90a2946cdc5e759058398b/pandas-3.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:44f1364411d5670efa692b146c748f4ed013df91ee91e9bec5677fb1fd58b937", size = 10884622, upload-time = "2026-02-17T22:20:11.711Z" }, + { url = "https://files.pythonhosted.org/packages/68/b0/34937815889fa982613775e4b97fddd13250f11012d769949c5465af2150/pandas-3.0.1-cp314-cp314t-win_arm64.whl", hash = "sha256:108dd1790337a494aa80e38def654ca3f0968cf4f362c85f44c15e471667102d", size = 9452085, upload-time = "2026-02-17T22:20:14.331Z" }, ] [[package]] name = "pandas-stubs" -version = "2.3.3.260113" +version = "3.0.0.260204" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, - { name = "types-pytz" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/92/5d/be23854a73fda69f1dbdda7bc10fbd6f930bd1fa87aaec389f00c901c1e8/pandas_stubs-2.3.3.260113.tar.gz", hash = "sha256:076e3724bcaa73de78932b012ec64b3010463d377fa63116f4e6850643d93800", size = 116131, upload-time = "2026-01-13T22:30:16.704Z" } +sdist = { url = "https://files.pythonhosted.org/packages/27/1d/297ff2c7ea50a768a2247621d6451abb2a07c0e9be7ca6d36ebe371658e5/pandas_stubs-3.0.0.260204.tar.gz", hash = "sha256:bf9294b76352effcffa9cb85edf0bed1339a7ec0c30b8e1ac3d66b4228f1fbc3", size = 109383, upload-time = "2026-02-04T15:17:17.247Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/c6/df1fe324248424f77b89371116dab5243db7f052c32cc9fe7442ad9c5f75/pandas_stubs-2.3.3.260113-py3-none-any.whl", hash = "sha256:ec070b5c576e1badf12544ae50385872f0631fc35d99d00dc598c2954ec564d3", size = 168246, upload-time = "2026-01-13T22:30:15.244Z" }, + { url = "https://files.pythonhosted.org/packages/7c/2f/f91e4eee21585ff548e83358332d5632ee49f6b2dcd96cb5dca4e0468951/pandas_stubs-3.0.0.260204-py3-none-any.whl", hash = "sha256:5ab9e4d55a6e2752e9720828564af40d48c4f709e6a2c69b743014a6fcb6c241", size = 168540, upload-time = "2026-02-04T15:17:15.615Z" }, ] [[package]] name = "pathspec" -version = "1.0.3" +version = "1.0.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4c/b2/bb8e495d5262bfec41ab5cb18f522f1012933347fb5d9e62452d446baca2/pathspec-1.0.3.tar.gz", hash = "sha256:bac5cf97ae2c2876e2d25ebb15078eb04d76e4b98921ee31c6f85ade8b59444d", size = 130841, upload-time = "2026-01-09T15:46:46.009Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fa/36/e27608899f9b8d4dff0617b2d9ab17ca5608956ca44461ac14ac48b44015/pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645", size = 131200, upload-time = "2026-01-27T03:59:46.938Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/32/2b/121e912bd60eebd623f873fd090de0e84f322972ab25a7f9044c056804ed/pathspec-1.0.3-py3-none-any.whl", hash = "sha256:e80767021c1cc524aa3fb14bedda9c34406591343cc42797b386ce7b9354fb6c", size = 55021, upload-time = "2026-01-09T15:46:44.652Z" }, + { url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206, upload-time = "2026-01-27T03:59:45.137Z" }, ] [[package]] name = "pillow" -version = "12.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d0/02/d52c733a2452ef1ffcc123b68e6606d07276b0e358db70eabad7e40042b7/pillow-12.1.0.tar.gz", hash = "sha256:5c5ae0a06e9ea030ab786b0251b32c7e4ce10e58d983c0d5c56029455180b5b9", size = 46977283, upload-time = "2026-01-02T09:13:29.892Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/20/31/dc53fe21a2f2996e1b7d92bf671cdb157079385183ef7c1ae08b485db510/pillow-12.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a332ac4ccb84b6dde65dbace8431f3af08874bf9770719d32a635c4ef411b18b", size = 5262642, upload-time = "2026-01-02T09:11:10.138Z" }, - { url = "https://files.pythonhosted.org/packages/ab/c1/10e45ac9cc79419cedf5121b42dcca5a50ad2b601fa080f58c22fb27626e/pillow-12.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:907bfa8a9cb790748a9aa4513e37c88c59660da3bcfffbd24a7d9e6abf224551", size = 4657464, upload-time = "2026-01-02T09:11:12.319Z" }, - { url = "https://files.pythonhosted.org/packages/ad/26/7b82c0ab7ef40ebede7a97c72d473bda5950f609f8e0c77b04af574a0ddb/pillow-12.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:efdc140e7b63b8f739d09a99033aa430accce485ff78e6d311973a67b6bf3208", size = 6234878, upload-time = "2026-01-02T09:11:14.096Z" }, - { url = "https://files.pythonhosted.org/packages/76/25/27abc9792615b5e886ca9411ba6637b675f1b77af3104710ac7353fe5605/pillow-12.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bef9768cab184e7ae6e559c032e95ba8d07b3023c289f79a2bd36e8bf85605a5", size = 8044868, upload-time = "2026-01-02T09:11:15.903Z" }, - { url = "https://files.pythonhosted.org/packages/0a/ea/f200a4c36d836100e7bc738fc48cd963d3ba6372ebc8298a889e0cfc3359/pillow-12.1.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:742aea052cf5ab5034a53c3846165bc3ce88d7c38e954120db0ab867ca242661", size = 6349468, upload-time = "2026-01-02T09:11:17.631Z" }, - { url = "https://files.pythonhosted.org/packages/11/8f/48d0b77ab2200374c66d344459b8958c86693be99526450e7aee714e03e4/pillow-12.1.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a6dfc2af5b082b635af6e08e0d1f9f1c4e04d17d4e2ca0ef96131e85eda6eb17", size = 7041518, upload-time = "2026-01-02T09:11:19.389Z" }, - { url = "https://files.pythonhosted.org/packages/1d/23/c281182eb986b5d31f0a76d2a2c8cd41722d6fb8ed07521e802f9bba52de/pillow-12.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:609e89d9f90b581c8d16358c9087df76024cf058fa693dd3e1e1620823f39670", size = 6462829, upload-time = "2026-01-02T09:11:21.28Z" }, - { url = "https://files.pythonhosted.org/packages/25/ef/7018273e0faac099d7b00982abdcc39142ae6f3bd9ceb06de09779c4a9d6/pillow-12.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:43b4899cfd091a9693a1278c4982f3e50f7fb7cff5153b05174b4afc9593b616", size = 7166756, upload-time = "2026-01-02T09:11:23.559Z" }, - { url = "https://files.pythonhosted.org/packages/8f/c8/993d4b7ab2e341fe02ceef9576afcf5830cdec640be2ac5bee1820d693d4/pillow-12.1.0-cp312-cp312-win32.whl", hash = "sha256:aa0c9cc0b82b14766a99fbe6084409972266e82f459821cd26997a488a7261a7", size = 6328770, upload-time = "2026-01-02T09:11:25.661Z" }, - { url = "https://files.pythonhosted.org/packages/a7/87/90b358775a3f02765d87655237229ba64a997b87efa8ccaca7dd3e36e7a7/pillow-12.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:d70534cea9e7966169ad29a903b99fc507e932069a881d0965a1a84bb57f6c6d", size = 7033406, upload-time = "2026-01-02T09:11:27.474Z" }, - { url = "https://files.pythonhosted.org/packages/5d/cf/881b457eccacac9e5b2ddd97d5071fb6d668307c57cbf4e3b5278e06e536/pillow-12.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:65b80c1ee7e14a87d6a068dd3b0aea268ffcabfe0498d38661b00c5b4b22e74c", size = 2452612, upload-time = "2026-01-02T09:11:29.309Z" }, - { url = "https://files.pythonhosted.org/packages/dd/c7/2530a4aa28248623e9d7f27316b42e27c32ec410f695929696f2e0e4a778/pillow-12.1.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:7b5dd7cbae20285cdb597b10eb5a2c13aa9de6cde9bb64a3c1317427b1db1ae1", size = 4062543, upload-time = "2026-01-02T09:11:31.566Z" }, - { url = "https://files.pythonhosted.org/packages/8f/1f/40b8eae823dc1519b87d53c30ed9ef085506b05281d313031755c1705f73/pillow-12.1.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:29a4cef9cb672363926f0470afc516dbf7305a14d8c54f7abbb5c199cd8f8179", size = 4138373, upload-time = "2026-01-02T09:11:33.367Z" }, - { url = "https://files.pythonhosted.org/packages/d4/77/6fa60634cf06e52139fd0e89e5bbf055e8166c691c42fb162818b7fda31d/pillow-12.1.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:681088909d7e8fa9e31b9799aaa59ba5234c58e5e4f1951b4c4d1082a2e980e0", size = 3601241, upload-time = "2026-01-02T09:11:35.011Z" }, - { url = "https://files.pythonhosted.org/packages/4f/bf/28ab865de622e14b747f0cd7877510848252d950e43002e224fb1c9ababf/pillow-12.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:983976c2ab753166dc66d36af6e8ec15bb511e4a25856e2227e5f7e00a160587", size = 5262410, upload-time = "2026-01-02T09:11:36.682Z" }, - { url = "https://files.pythonhosted.org/packages/1c/34/583420a1b55e715937a85bd48c5c0991598247a1fd2eb5423188e765ea02/pillow-12.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:db44d5c160a90df2d24a24760bbd37607d53da0b34fb546c4c232af7192298ac", size = 4657312, upload-time = "2026-01-02T09:11:38.535Z" }, - { url = "https://files.pythonhosted.org/packages/1d/fd/f5a0896839762885b3376ff04878f86ab2b097c2f9a9cdccf4eda8ba8dc0/pillow-12.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6b7a9d1db5dad90e2991645874f708e87d9a3c370c243c2d7684d28f7e133e6b", size = 6232605, upload-time = "2026-01-02T09:11:40.602Z" }, - { url = "https://files.pythonhosted.org/packages/98/aa/938a09d127ac1e70e6ed467bd03834350b33ef646b31edb7452d5de43792/pillow-12.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6258f3260986990ba2fa8a874f8b6e808cf5abb51a94015ca3dc3c68aa4f30ea", size = 8041617, upload-time = "2026-01-02T09:11:42.721Z" }, - { url = "https://files.pythonhosted.org/packages/17/e8/538b24cb426ac0186e03f80f78bc8dc7246c667f58b540bdd57c71c9f79d/pillow-12.1.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e115c15e3bc727b1ca3e641a909f77f8ca72a64fff150f666fcc85e57701c26c", size = 6346509, upload-time = "2026-01-02T09:11:44.955Z" }, - { url = "https://files.pythonhosted.org/packages/01/9a/632e58ec89a32738cabfd9ec418f0e9898a2b4719afc581f07c04a05e3c9/pillow-12.1.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6741e6f3074a35e47c77b23a4e4f2d90db3ed905cb1c5e6e0d49bff2045632bc", size = 7038117, upload-time = "2026-01-02T09:11:46.736Z" }, - { url = "https://files.pythonhosted.org/packages/c7/a2/d40308cf86eada842ca1f3ffa45d0ca0df7e4ab33c83f81e73f5eaed136d/pillow-12.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:935b9d1aed48fcfb3f838caac506f38e29621b44ccc4f8a64d575cb1b2a88644", size = 6460151, upload-time = "2026-01-02T09:11:48.625Z" }, - { url = "https://files.pythonhosted.org/packages/f1/88/f5b058ad6453a085c5266660a1417bdad590199da1b32fb4efcff9d33b05/pillow-12.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5fee4c04aad8932da9f8f710af2c1a15a83582cfb884152a9caa79d4efcdbf9c", size = 7164534, upload-time = "2026-01-02T09:11:50.445Z" }, - { url = "https://files.pythonhosted.org/packages/19/ce/c17334caea1db789163b5d855a5735e47995b0b5dc8745e9a3605d5f24c0/pillow-12.1.0-cp313-cp313-win32.whl", hash = "sha256:a786bf667724d84aa29b5db1c61b7bfdde380202aaca12c3461afd6b71743171", size = 6332551, upload-time = "2026-01-02T09:11:52.234Z" }, - { url = "https://files.pythonhosted.org/packages/e5/07/74a9d941fa45c90a0d9465098fe1ec85de3e2afbdc15cc4766622d516056/pillow-12.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:461f9dfdafa394c59cd6d818bdfdbab4028b83b02caadaff0ffd433faf4c9a7a", size = 7040087, upload-time = "2026-01-02T09:11:54.822Z" }, - { url = "https://files.pythonhosted.org/packages/88/09/c99950c075a0e9053d8e880595926302575bc742b1b47fe1bbcc8d388d50/pillow-12.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:9212d6b86917a2300669511ed094a9406888362e085f2431a7da985a6b124f45", size = 2452470, upload-time = "2026-01-02T09:11:56.522Z" }, - { url = "https://files.pythonhosted.org/packages/b5/ba/970b7d85ba01f348dee4d65412476321d40ee04dcb51cd3735b9dc94eb58/pillow-12.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:00162e9ca6d22b7c3ee8e61faa3c3253cd19b6a37f126cad04f2f88b306f557d", size = 5264816, upload-time = "2026-01-02T09:11:58.227Z" }, - { url = "https://files.pythonhosted.org/packages/10/60/650f2fb55fdba7a510d836202aa52f0baac633e50ab1cf18415d332188fb/pillow-12.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7d6daa89a00b58c37cb1747ec9fb7ac3bc5ffd5949f5888657dfddde6d1312e0", size = 4660472, upload-time = "2026-01-02T09:12:00.798Z" }, - { url = "https://files.pythonhosted.org/packages/2b/c0/5273a99478956a099d533c4f46cbaa19fd69d606624f4334b85e50987a08/pillow-12.1.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e2479c7f02f9d505682dc47df8c0ea1fc5e264c4d1629a5d63fe3e2334b89554", size = 6268974, upload-time = "2026-01-02T09:12:02.572Z" }, - { url = "https://files.pythonhosted.org/packages/b4/26/0bf714bc2e73d5267887d47931d53c4ceeceea6978148ed2ab2a4e6463c4/pillow-12.1.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f188d580bd870cda1e15183790d1cc2fa78f666e76077d103edf048eed9c356e", size = 8073070, upload-time = "2026-01-02T09:12:04.75Z" }, - { url = "https://files.pythonhosted.org/packages/43/cf/1ea826200de111a9d65724c54f927f3111dc5ae297f294b370a670c17786/pillow-12.1.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0fde7ec5538ab5095cc02df38ee99b0443ff0e1c847a045554cf5f9af1f4aa82", size = 6380176, upload-time = "2026-01-02T09:12:06.626Z" }, - { url = "https://files.pythonhosted.org/packages/03/e0/7938dd2b2013373fd85d96e0f38d62b7a5a262af21ac274250c7ca7847c9/pillow-12.1.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0ed07dca4a8464bada6139ab38f5382f83e5f111698caf3191cb8dbf27d908b4", size = 7067061, upload-time = "2026-01-02T09:12:08.624Z" }, - { url = "https://files.pythonhosted.org/packages/86/ad/a2aa97d37272a929a98437a8c0ac37b3cf012f4f8721e1bd5154699b2518/pillow-12.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f45bd71d1fa5e5749587613037b172e0b3b23159d1c00ef2fc920da6f470e6f0", size = 6491824, upload-time = "2026-01-02T09:12:10.488Z" }, - { url = "https://files.pythonhosted.org/packages/a4/44/80e46611b288d51b115826f136fb3465653c28f491068a72d3da49b54cd4/pillow-12.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:277518bf4fe74aa91489e1b20577473b19ee70fb97c374aa50830b279f25841b", size = 7190911, upload-time = "2026-01-02T09:12:12.772Z" }, - { url = "https://files.pythonhosted.org/packages/86/77/eacc62356b4cf81abe99ff9dbc7402750044aed02cfd6a503f7c6fc11f3e/pillow-12.1.0-cp313-cp313t-win32.whl", hash = "sha256:7315f9137087c4e0ee73a761b163fc9aa3b19f5f606a7fc08d83fd3e4379af65", size = 6336445, upload-time = "2026-01-02T09:12:14.775Z" }, - { url = "https://files.pythonhosted.org/packages/e7/3c/57d81d0b74d218706dafccb87a87ea44262c43eef98eb3b164fd000e0491/pillow-12.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:0ddedfaa8b5f0b4ffbc2fa87b556dc59f6bb4ecb14a53b33f9189713ae8053c0", size = 7045354, upload-time = "2026-01-02T09:12:16.599Z" }, - { url = "https://files.pythonhosted.org/packages/ac/82/8b9b97bba2e3576a340f93b044a3a3a09841170ab4c1eb0d5c93469fd32f/pillow-12.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:80941e6d573197a0c28f394753de529bb436b1ca990ed6e765cf42426abc39f8", size = 2454547, upload-time = "2026-01-02T09:12:18.704Z" }, - { url = "https://files.pythonhosted.org/packages/8c/87/bdf971d8bbcf80a348cc3bacfcb239f5882100fe80534b0ce67a784181d8/pillow-12.1.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:5cb7bc1966d031aec37ddb9dcf15c2da5b2e9f7cc3ca7c54473a20a927e1eb91", size = 4062533, upload-time = "2026-01-02T09:12:20.791Z" }, - { url = "https://files.pythonhosted.org/packages/ff/4f/5eb37a681c68d605eb7034c004875c81f86ec9ef51f5be4a63eadd58859a/pillow-12.1.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:97e9993d5ed946aba26baf9c1e8cf18adbab584b99f452ee72f7ee8acb882796", size = 4138546, upload-time = "2026-01-02T09:12:23.664Z" }, - { url = "https://files.pythonhosted.org/packages/11/6d/19a95acb2edbace40dcd582d077b991646b7083c41b98da4ed7555b59733/pillow-12.1.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:414b9a78e14ffeb98128863314e62c3f24b8a86081066625700b7985b3f529bd", size = 3601163, upload-time = "2026-01-02T09:12:26.338Z" }, - { url = "https://files.pythonhosted.org/packages/fc/36/2b8138e51cb42e4cc39c3297713455548be855a50558c3ac2beebdc251dd/pillow-12.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e6bdb408f7c9dd2a5ff2b14a3b0bb6d4deb29fb9961e6eb3ae2031ae9a5cec13", size = 5266086, upload-time = "2026-01-02T09:12:28.782Z" }, - { url = "https://files.pythonhosted.org/packages/53/4b/649056e4d22e1caa90816bf99cef0884aed607ed38075bd75f091a607a38/pillow-12.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3413c2ae377550f5487991d444428f1a8ae92784aac79caa8b1e3b89b175f77e", size = 4657344, upload-time = "2026-01-02T09:12:31.117Z" }, - { url = "https://files.pythonhosted.org/packages/6c/6b/c5742cea0f1ade0cd61485dc3d81f05261fc2276f537fbdc00802de56779/pillow-12.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e5dcbe95016e88437ecf33544ba5db21ef1b8dd6e1b434a2cb2a3d605299e643", size = 6232114, upload-time = "2026-01-02T09:12:32.936Z" }, - { url = "https://files.pythonhosted.org/packages/bf/8f/9f521268ce22d63991601aafd3d48d5ff7280a246a1ef62d626d67b44064/pillow-12.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d0a7735df32ccbcc98b98a1ac785cc4b19b580be1bdf0aeb5c03223220ea09d5", size = 8042708, upload-time = "2026-01-02T09:12:34.78Z" }, - { url = "https://files.pythonhosted.org/packages/1a/eb/257f38542893f021502a1bbe0c2e883c90b5cff26cc33b1584a841a06d30/pillow-12.1.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c27407a2d1b96774cbc4a7594129cc027339fd800cd081e44497722ea1179de", size = 6347762, upload-time = "2026-01-02T09:12:36.748Z" }, - { url = "https://files.pythonhosted.org/packages/c4/5a/8ba375025701c09b309e8d5163c5a4ce0102fa86bbf8800eb0d7ac87bc51/pillow-12.1.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15c794d74303828eaa957ff8070846d0efe8c630901a1c753fdc63850e19ecd9", size = 7039265, upload-time = "2026-01-02T09:12:39.082Z" }, - { url = "https://files.pythonhosted.org/packages/cf/dc/cf5e4cdb3db533f539e88a7bbf9f190c64ab8a08a9bc7a4ccf55067872e4/pillow-12.1.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c990547452ee2800d8506c4150280757f88532f3de2a58e3022e9b179107862a", size = 6462341, upload-time = "2026-01-02T09:12:40.946Z" }, - { url = "https://files.pythonhosted.org/packages/d0/47/0291a25ac9550677e22eda48510cfc4fa4b2ef0396448b7fbdc0a6946309/pillow-12.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b63e13dd27da389ed9475b3d28510f0f954bca0041e8e551b2a4eb1eab56a39a", size = 7165395, upload-time = "2026-01-02T09:12:42.706Z" }, - { url = "https://files.pythonhosted.org/packages/4f/4c/e005a59393ec4d9416be06e6b45820403bb946a778e39ecec62f5b2b991e/pillow-12.1.0-cp314-cp314-win32.whl", hash = "sha256:1a949604f73eb07a8adab38c4fe50791f9919344398bdc8ac6b307f755fc7030", size = 6431413, upload-time = "2026-01-02T09:12:44.944Z" }, - { url = "https://files.pythonhosted.org/packages/1c/af/f23697f587ac5f9095d67e31b81c95c0249cd461a9798a061ed6709b09b5/pillow-12.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:4f9f6a650743f0ddee5593ac9e954ba1bdbc5e150bc066586d4f26127853ab94", size = 7176779, upload-time = "2026-01-02T09:12:46.727Z" }, - { url = "https://files.pythonhosted.org/packages/b3/36/6a51abf8599232f3e9afbd16d52829376a68909fe14efe29084445db4b73/pillow-12.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:808b99604f7873c800c4840f55ff389936ef1948e4e87645eaf3fccbc8477ac4", size = 2543105, upload-time = "2026-01-02T09:12:49.243Z" }, - { url = "https://files.pythonhosted.org/packages/82/54/2e1dd20c8749ff225080d6ba465a0cab4387f5db0d1c5fb1439e2d99923f/pillow-12.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bc11908616c8a283cf7d664f77411a5ed2a02009b0097ff8abbba5e79128ccf2", size = 5268571, upload-time = "2026-01-02T09:12:51.11Z" }, - { url = "https://files.pythonhosted.org/packages/57/61/571163a5ef86ec0cf30d265ac2a70ae6fc9e28413d1dc94fa37fae6bda89/pillow-12.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:896866d2d436563fa2a43a9d72f417874f16b5545955c54a64941e87c1376c61", size = 4660426, upload-time = "2026-01-02T09:12:52.865Z" }, - { url = "https://files.pythonhosted.org/packages/5e/e1/53ee5163f794aef1bf84243f755ee6897a92c708505350dd1923f4afec48/pillow-12.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8e178e3e99d3c0ea8fc64b88447f7cac8ccf058af422a6cedc690d0eadd98c51", size = 6269908, upload-time = "2026-01-02T09:12:54.884Z" }, - { url = "https://files.pythonhosted.org/packages/bc/0b/b4b4106ff0ee1afa1dc599fde6ab230417f800279745124f6c50bcffed8e/pillow-12.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:079af2fb0c599c2ec144ba2c02766d1b55498e373b3ac64687e43849fbbef5bc", size = 8074733, upload-time = "2026-01-02T09:12:56.802Z" }, - { url = "https://files.pythonhosted.org/packages/19/9f/80b411cbac4a732439e629a26ad3ef11907a8c7fc5377b7602f04f6fe4e7/pillow-12.1.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bdec5e43377761c5dbca620efb69a77f6855c5a379e32ac5b158f54c84212b14", size = 6381431, upload-time = "2026-01-02T09:12:58.823Z" }, - { url = "https://files.pythonhosted.org/packages/8f/b7/d65c45db463b66ecb6abc17c6ba6917a911202a07662247e1355ce1789e7/pillow-12.1.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:565c986f4b45c020f5421a4cea13ef294dde9509a8577f29b2fc5edc7587fff8", size = 7068529, upload-time = "2026-01-02T09:13:00.885Z" }, - { url = "https://files.pythonhosted.org/packages/50/96/dfd4cd726b4a45ae6e3c669fc9e49deb2241312605d33aba50499e9d9bd1/pillow-12.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:43aca0a55ce1eefc0aefa6253661cb54571857b1a7b2964bd8a1e3ef4b729924", size = 6492981, upload-time = "2026-01-02T09:13:03.314Z" }, - { url = "https://files.pythonhosted.org/packages/4d/1c/b5dc52cf713ae46033359c5ca920444f18a6359ce1020dd3e9c553ea5bc6/pillow-12.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0deedf2ea233722476b3a81e8cdfbad786f7adbed5d848469fa59fe52396e4ef", size = 7191878, upload-time = "2026-01-02T09:13:05.276Z" }, - { url = "https://files.pythonhosted.org/packages/53/26/c4188248bd5edaf543864fe4834aebe9c9cb4968b6f573ce014cc42d0720/pillow-12.1.0-cp314-cp314t-win32.whl", hash = "sha256:b17fbdbe01c196e7e159aacb889e091f28e61020a8abeac07b68079b6e626988", size = 6438703, upload-time = "2026-01-02T09:13:07.491Z" }, - { url = "https://files.pythonhosted.org/packages/b8/0e/69ed296de8ea05cb03ee139cee600f424ca166e632567b2d66727f08c7ed/pillow-12.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27b9baecb428899db6c0de572d6d305cfaf38ca1596b5c0542a5182e3e74e8c6", size = 7182927, upload-time = "2026-01-02T09:13:09.841Z" }, - { url = "https://files.pythonhosted.org/packages/fc/f5/68334c015eed9b5cff77814258717dec591ded209ab5b6fb70e2ae873d1d/pillow-12.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:f61333d817698bdcdd0f9d7793e365ac3d2a21c1f1eb02b32ad6aefb8d8ea831", size = 2545104, upload-time = "2026-01-02T09:13:12.068Z" }, +version = "12.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1f/42/5c74462b4fd957fcd7b13b04fb3205ff8349236ea74c7c375766d6c82288/pillow-12.1.1.tar.gz", hash = "sha256:9ad8fa5937ab05218e2b6a4cff30295ad35afd2f83ac592e68c0d871bb0fdbc4", size = 46980264, upload-time = "2026-02-11T04:23:07.146Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/d3/8df65da0d4df36b094351dce696f2989bec731d4f10e743b1c5f4da4d3bf/pillow-12.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ab323b787d6e18b3d91a72fc99b1a2c28651e4358749842b8f8dfacd28ef2052", size = 5262803, upload-time = "2026-02-11T04:20:47.653Z" }, + { url = "https://files.pythonhosted.org/packages/d6/71/5026395b290ff404b836e636f51d7297e6c83beceaa87c592718747e670f/pillow-12.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:adebb5bee0f0af4909c30db0d890c773d1a92ffe83da908e2e9e720f8edf3984", size = 4657601, upload-time = "2026-02-11T04:20:49.328Z" }, + { url = "https://files.pythonhosted.org/packages/b1/2e/1001613d941c67442f745aff0f7cc66dd8df9a9c084eb497e6a543ee6f7e/pillow-12.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bb66b7cc26f50977108790e2456b7921e773f23db5630261102233eb355a3b79", size = 6234995, upload-time = "2026-02-11T04:20:51.032Z" }, + { url = "https://files.pythonhosted.org/packages/07/26/246ab11455b2549b9233dbd44d358d033a2f780fa9007b61a913c5b2d24e/pillow-12.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aee2810642b2898bb187ced9b349e95d2a7272930796e022efaf12e99dccd293", size = 8045012, upload-time = "2026-02-11T04:20:52.882Z" }, + { url = "https://files.pythonhosted.org/packages/b2/8b/07587069c27be7535ac1fe33874e32de118fbd34e2a73b7f83436a88368c/pillow-12.1.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a0b1cd6232e2b618adcc54d9882e4e662a089d5768cd188f7c245b4c8c44a397", size = 6349638, upload-time = "2026-02-11T04:20:54.444Z" }, + { url = "https://files.pythonhosted.org/packages/ff/79/6df7b2ee763d619cda2fb4fea498e5f79d984dae304d45a8999b80d6cf5c/pillow-12.1.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7aac39bcf8d4770d089588a2e1dd111cbaa42df5a94be3114222057d68336bd0", size = 7041540, upload-time = "2026-02-11T04:20:55.97Z" }, + { url = "https://files.pythonhosted.org/packages/2c/5e/2ba19e7e7236d7529f4d873bdaf317a318896bac289abebd4bb00ef247f0/pillow-12.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ab174cd7d29a62dd139c44bf74b698039328f45cb03b4596c43473a46656b2f3", size = 6462613, upload-time = "2026-02-11T04:20:57.542Z" }, + { url = "https://files.pythonhosted.org/packages/03/03/31216ec124bb5c3dacd74ce8efff4cc7f52643653bad4825f8f08c697743/pillow-12.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:339ffdcb7cbeaa08221cd401d517d4b1fe7a9ed5d400e4a8039719238620ca35", size = 7166745, upload-time = "2026-02-11T04:20:59.196Z" }, + { url = "https://files.pythonhosted.org/packages/1f/e7/7c4552d80052337eb28653b617eafdef39adfb137c49dd7e831b8dc13bc5/pillow-12.1.1-cp312-cp312-win32.whl", hash = "sha256:5d1f9575a12bed9e9eedd9a4972834b08c97a352bd17955ccdebfeca5913fa0a", size = 6328823, upload-time = "2026-02-11T04:21:01.385Z" }, + { url = "https://files.pythonhosted.org/packages/3d/17/688626d192d7261bbbf98846fc98995726bddc2c945344b65bec3a29d731/pillow-12.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:21329ec8c96c6e979cd0dfd29406c40c1d52521a90544463057d2aaa937d66a6", size = 7033367, upload-time = "2026-02-11T04:21:03.536Z" }, + { url = "https://files.pythonhosted.org/packages/ed/fe/a0ef1f73f939b0eca03ee2c108d0043a87468664770612602c63266a43c4/pillow-12.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:af9a332e572978f0218686636610555ae3defd1633597be015ed50289a03c523", size = 2453811, upload-time = "2026-02-11T04:21:05.116Z" }, + { url = "https://files.pythonhosted.org/packages/d5/11/6db24d4bd7685583caeae54b7009584e38da3c3d4488ed4cd25b439de486/pillow-12.1.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:d242e8ac078781f1de88bf823d70c1a9b3c7950a44cdf4b7c012e22ccbcd8e4e", size = 4062689, upload-time = "2026-02-11T04:21:06.804Z" }, + { url = "https://files.pythonhosted.org/packages/33/c0/ce6d3b1fe190f0021203e0d9b5b99e57843e345f15f9ef22fcd43842fd21/pillow-12.1.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:02f84dfad02693676692746df05b89cf25597560db2857363a208e393429f5e9", size = 4138535, upload-time = "2026-02-11T04:21:08.452Z" }, + { url = "https://files.pythonhosted.org/packages/a0/c6/d5eb6a4fb32a3f9c21a8c7613ec706534ea1cf9f4b3663e99f0d83f6fca8/pillow-12.1.1-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:e65498daf4b583091ccbb2556c7000abf0f3349fcd57ef7adc9a84a394ed29f6", size = 3601364, upload-time = "2026-02-11T04:21:10.194Z" }, + { url = "https://files.pythonhosted.org/packages/14/a1/16c4b823838ba4c9c52c0e6bbda903a3fe5a1bdbf1b8eb4fff7156f3e318/pillow-12.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c6db3b84c87d48d0088943bf33440e0c42370b99b1c2a7989216f7b42eede60", size = 5262561, upload-time = "2026-02-11T04:21:11.742Z" }, + { url = "https://files.pythonhosted.org/packages/bb/ad/ad9dc98ff24f485008aa5cdedaf1a219876f6f6c42a4626c08bc4e80b120/pillow-12.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8b7e5304e34942bf62e15184219a7b5ad4ff7f3bb5cca4d984f37df1a0e1aee2", size = 4657460, upload-time = "2026-02-11T04:21:13.786Z" }, + { url = "https://files.pythonhosted.org/packages/9e/1b/f1a4ea9a895b5732152789326202a82464d5254759fbacae4deea3069334/pillow-12.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:18e5bddd742a44b7e6b1e773ab5db102bd7a94c32555ba656e76d319d19c3850", size = 6232698, upload-time = "2026-02-11T04:21:15.949Z" }, + { url = "https://files.pythonhosted.org/packages/95/f4/86f51b8745070daf21fd2e5b1fe0eb35d4db9ca26e6d58366562fb56a743/pillow-12.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc44ef1f3de4f45b50ccf9136999d71abb99dca7706bc75d222ed350b9fd2289", size = 8041706, upload-time = "2026-02-11T04:21:17.723Z" }, + { url = "https://files.pythonhosted.org/packages/29/9b/d6ecd956bb1266dd1045e995cce9b8d77759e740953a1c9aad9502a0461e/pillow-12.1.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5a8eb7ed8d4198bccbd07058416eeec51686b498e784eda166395a23eb99138e", size = 6346621, upload-time = "2026-02-11T04:21:19.547Z" }, + { url = "https://files.pythonhosted.org/packages/71/24/538bff45bde96535d7d998c6fed1a751c75ac7c53c37c90dc2601b243893/pillow-12.1.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47b94983da0c642de92ced1702c5b6c292a84bd3a8e1d1702ff923f183594717", size = 7038069, upload-time = "2026-02-11T04:21:21.378Z" }, + { url = "https://files.pythonhosted.org/packages/94/0e/58cb1a6bc48f746bc4cb3adb8cabff73e2742c92b3bf7a220b7cf69b9177/pillow-12.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:518a48c2aab7ce596d3bf79d0e275661b846e86e4d0e7dec34712c30fe07f02a", size = 6460040, upload-time = "2026-02-11T04:21:23.148Z" }, + { url = "https://files.pythonhosted.org/packages/6c/57/9045cb3ff11eeb6c1adce3b2d60d7d299d7b273a2e6c8381a524abfdc474/pillow-12.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a550ae29b95c6dc13cf69e2c9dc5747f814c54eeb2e32d683e5e93af56caa029", size = 7164523, upload-time = "2026-02-11T04:21:25.01Z" }, + { url = "https://files.pythonhosted.org/packages/73/f2/9be9cb99f2175f0d4dbadd6616ce1bf068ee54a28277ea1bf1fbf729c250/pillow-12.1.1-cp313-cp313-win32.whl", hash = "sha256:a003d7422449f6d1e3a34e3dd4110c22148336918ddbfc6a32581cd54b2e0b2b", size = 6332552, upload-time = "2026-02-11T04:21:27.238Z" }, + { url = "https://files.pythonhosted.org/packages/3f/eb/b0834ad8b583d7d9d42b80becff092082a1c3c156bb582590fcc973f1c7c/pillow-12.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:344cf1e3dab3be4b1fa08e449323d98a2a3f819ad20f4b22e77a0ede31f0faa1", size = 7040108, upload-time = "2026-02-11T04:21:29.462Z" }, + { url = "https://files.pythonhosted.org/packages/d5/7d/fc09634e2aabdd0feabaff4a32f4a7d97789223e7c2042fd805ea4b4d2c2/pillow-12.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:5c0dd1636633e7e6a0afe7bf6a51a14992b7f8e60de5789018ebbdfae55b040a", size = 2453712, upload-time = "2026-02-11T04:21:31.072Z" }, + { url = "https://files.pythonhosted.org/packages/19/2a/b9d62794fc8a0dd14c1943df68347badbd5511103e0d04c035ffe5cf2255/pillow-12.1.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0330d233c1a0ead844fc097a7d16c0abff4c12e856c0b325f231820fee1f39da", size = 5264880, upload-time = "2026-02-11T04:21:32.865Z" }, + { url = "https://files.pythonhosted.org/packages/26/9d/e03d857d1347fa5ed9247e123fcd2a97b6220e15e9cb73ca0a8d91702c6e/pillow-12.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5dae5f21afb91322f2ff791895ddd8889e5e947ff59f71b46041c8ce6db790bc", size = 4660616, upload-time = "2026-02-11T04:21:34.97Z" }, + { url = "https://files.pythonhosted.org/packages/f7/ec/8a6d22afd02570d30954e043f09c32772bfe143ba9285e2fdb11284952cd/pillow-12.1.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2e0c664be47252947d870ac0d327fea7e63985a08794758aa8af5b6cb6ec0c9c", size = 6269008, upload-time = "2026-02-11T04:21:36.623Z" }, + { url = "https://files.pythonhosted.org/packages/3d/1d/6d875422c9f28a4a361f495a5f68d9de4a66941dc2c619103ca335fa6446/pillow-12.1.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:691ab2ac363b8217f7d31b3497108fb1f50faab2f75dfb03284ec2f217e87bf8", size = 8073226, upload-time = "2026-02-11T04:21:38.585Z" }, + { url = "https://files.pythonhosted.org/packages/a1/cd/134b0b6ee5eda6dc09e25e24b40fdafe11a520bc725c1d0bbaa5e00bf95b/pillow-12.1.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9e8064fb1cc019296958595f6db671fba95209e3ceb0c4734c9baf97de04b20", size = 6380136, upload-time = "2026-02-11T04:21:40.562Z" }, + { url = "https://files.pythonhosted.org/packages/7a/a9/7628f013f18f001c1b98d8fffe3452f306a70dc6aba7d931019e0492f45e/pillow-12.1.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:472a8d7ded663e6162dafdf20015c486a7009483ca671cece7a9279b512fcb13", size = 7067129, upload-time = "2026-02-11T04:21:42.521Z" }, + { url = "https://files.pythonhosted.org/packages/1e/f8/66ab30a2193b277785601e82ee2d49f68ea575d9637e5e234faaa98efa4c/pillow-12.1.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:89b54027a766529136a06cfebeecb3a04900397a3590fd252160b888479517bf", size = 6491807, upload-time = "2026-02-11T04:21:44.22Z" }, + { url = "https://files.pythonhosted.org/packages/da/0b/a877a6627dc8318fdb84e357c5e1a758c0941ab1ddffdafd231983788579/pillow-12.1.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:86172b0831b82ce4f7877f280055892b31179e1576aa00d0df3bb1bbf8c3e524", size = 7190954, upload-time = "2026-02-11T04:21:46.114Z" }, + { url = "https://files.pythonhosted.org/packages/83/43/6f732ff85743cf746b1361b91665d9f5155e1483817f693f8d57ea93147f/pillow-12.1.1-cp313-cp313t-win32.whl", hash = "sha256:44ce27545b6efcf0fdbdceb31c9a5bdea9333e664cda58a7e674bb74608b3986", size = 6336441, upload-time = "2026-02-11T04:21:48.22Z" }, + { url = "https://files.pythonhosted.org/packages/3b/44/e865ef3986611bb75bfabdf94a590016ea327833f434558801122979cd0e/pillow-12.1.1-cp313-cp313t-win_amd64.whl", hash = "sha256:a285e3eb7a5a45a2ff504e31f4a8d1b12ef62e84e5411c6804a42197c1cf586c", size = 7045383, upload-time = "2026-02-11T04:21:50.015Z" }, + { url = "https://files.pythonhosted.org/packages/a8/c6/f4fb24268d0c6908b9f04143697ea18b0379490cb74ba9e8d41b898bd005/pillow-12.1.1-cp313-cp313t-win_arm64.whl", hash = "sha256:cc7d296b5ea4d29e6570dabeaed58d31c3fea35a633a69679fb03d7664f43fb3", size = 2456104, upload-time = "2026-02-11T04:21:51.633Z" }, + { url = "https://files.pythonhosted.org/packages/03/d0/bebb3ffbf31c5a8e97241476c4cf8b9828954693ce6744b4a2326af3e16b/pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:417423db963cb4be8bac3fc1204fe61610f6abeed1580a7a2cbb2fbda20f12af", size = 4062652, upload-time = "2026-02-11T04:21:53.19Z" }, + { url = "https://files.pythonhosted.org/packages/2d/c0/0e16fb0addda4851445c28f8350d8c512f09de27bbb0d6d0bbf8b6709605/pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:b957b71c6b2387610f556a7eb0828afbe40b4a98036fc0d2acfa5a44a0c2036f", size = 4138823, upload-time = "2026-02-11T04:22:03.088Z" }, + { url = "https://files.pythonhosted.org/packages/6b/fb/6170ec655d6f6bb6630a013dd7cf7bc218423d7b5fa9071bf63dc32175ae/pillow-12.1.1-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:097690ba1f2efdeb165a20469d59d8bb03c55fb6621eb2041a060ae8ea3e9642", size = 3601143, upload-time = "2026-02-11T04:22:04.909Z" }, + { url = "https://files.pythonhosted.org/packages/59/04/dc5c3f297510ba9a6837cbb318b87dd2b8f73eb41a43cc63767f65cb599c/pillow-12.1.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2815a87ab27848db0321fb78c7f0b2c8649dee134b7f2b80c6a45c6831d75ccd", size = 5266254, upload-time = "2026-02-11T04:22:07.656Z" }, + { url = "https://files.pythonhosted.org/packages/05/30/5db1236b0d6313f03ebf97f5e17cda9ca060f524b2fcc875149a8360b21c/pillow-12.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f7ed2c6543bad5a7d5530eb9e78c53132f93dfa44a28492db88b41cdab885202", size = 4657499, upload-time = "2026-02-11T04:22:09.613Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/008d2ca0eb612e81968e8be0bbae5051efba24d52debf930126d7eaacbba/pillow-12.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:652a2c9ccfb556235b2b501a3a7cf3742148cd22e04b5625c5fe057ea3e3191f", size = 6232137, upload-time = "2026-02-11T04:22:11.434Z" }, + { url = "https://files.pythonhosted.org/packages/70/f1/f14d5b8eeb4b2cd62b9f9f847eb6605f103df89ef619ac68f92f748614ea/pillow-12.1.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d6e4571eedf43af33d0fc233a382a76e849badbccdf1ac438841308652a08e1f", size = 8042721, upload-time = "2026-02-11T04:22:13.321Z" }, + { url = "https://files.pythonhosted.org/packages/5a/d6/17824509146e4babbdabf04d8171491fa9d776f7061ff6e727522df9bd03/pillow-12.1.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b574c51cf7d5d62e9be37ba446224b59a2da26dc4c1bb2ecbe936a4fb1a7cb7f", size = 6347798, upload-time = "2026-02-11T04:22:15.449Z" }, + { url = "https://files.pythonhosted.org/packages/d1/ee/c85a38a9ab92037a75615aba572c85ea51e605265036e00c5b67dfafbfe2/pillow-12.1.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a37691702ed687799de29a518d63d4682d9016932db66d4e90c345831b02fb4e", size = 7039315, upload-time = "2026-02-11T04:22:17.24Z" }, + { url = "https://files.pythonhosted.org/packages/ec/f3/bc8ccc6e08a148290d7523bde4d9a0d6c981db34631390dc6e6ec34cacf6/pillow-12.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f95c00d5d6700b2b890479664a06e754974848afaae5e21beb4d83c106923fd0", size = 6462360, upload-time = "2026-02-11T04:22:19.111Z" }, + { url = "https://files.pythonhosted.org/packages/f6/ab/69a42656adb1d0665ab051eec58a41f169ad295cf81ad45406963105408f/pillow-12.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:559b38da23606e68681337ad74622c4dbba02254fc9cb4488a305dd5975c7eeb", size = 7165438, upload-time = "2026-02-11T04:22:21.041Z" }, + { url = "https://files.pythonhosted.org/packages/02/46/81f7aa8941873f0f01d4b55cc543b0a3d03ec2ee30d617a0448bf6bd6dec/pillow-12.1.1-cp314-cp314-win32.whl", hash = "sha256:03edcc34d688572014ff223c125a3f77fb08091e4607e7745002fc214070b35f", size = 6431503, upload-time = "2026-02-11T04:22:22.833Z" }, + { url = "https://files.pythonhosted.org/packages/40/72/4c245f7d1044b67affc7f134a09ea619d4895333d35322b775b928180044/pillow-12.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:50480dcd74fa63b8e78235957d302d98d98d82ccbfac4c7e12108ba9ecbdba15", size = 7176748, upload-time = "2026-02-11T04:22:24.64Z" }, + { url = "https://files.pythonhosted.org/packages/e4/ad/8a87bdbe038c5c698736e3348af5c2194ffb872ea52f11894c95f9305435/pillow-12.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:5cb1785d97b0c3d1d1a16bc1d710c4a0049daefc4935f3a8f31f827f4d3d2e7f", size = 2544314, upload-time = "2026-02-11T04:22:26.685Z" }, + { url = "https://files.pythonhosted.org/packages/6c/9d/efd18493f9de13b87ede7c47e69184b9e859e4427225ea962e32e56a49bc/pillow-12.1.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1f90cff8aa76835cba5769f0b3121a22bd4eb9e6884cfe338216e557a9a548b8", size = 5268612, upload-time = "2026-02-11T04:22:29.884Z" }, + { url = "https://files.pythonhosted.org/packages/f8/f1/4f42eb2b388eb2ffc660dcb7f7b556c1015c53ebd5f7f754965ef997585b/pillow-12.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1f1be78ce9466a7ee64bfda57bdba0f7cc499d9794d518b854816c41bf0aa4e9", size = 4660567, upload-time = "2026-02-11T04:22:31.799Z" }, + { url = "https://files.pythonhosted.org/packages/01/54/df6ef130fa43e4b82e32624a7b821a2be1c5653a5fdad8469687a7db4e00/pillow-12.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:42fc1f4677106188ad9a55562bbade416f8b55456f522430fadab3cef7cd4e60", size = 6269951, upload-time = "2026-02-11T04:22:33.921Z" }, + { url = "https://files.pythonhosted.org/packages/a9/48/618752d06cc44bb4aae8ce0cd4e6426871929ed7b46215638088270d9b34/pillow-12.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98edb152429ab62a1818039744d8fbb3ccab98a7c29fc3d5fcef158f3f1f68b7", size = 8074769, upload-time = "2026-02-11T04:22:35.877Z" }, + { url = "https://files.pythonhosted.org/packages/c3/bd/f1d71eb39a72fa088d938655afba3e00b38018d052752f435838961127d8/pillow-12.1.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d470ab1178551dd17fdba0fef463359c41aaa613cdcd7ff8373f54be629f9f8f", size = 6381358, upload-time = "2026-02-11T04:22:37.698Z" }, + { url = "https://files.pythonhosted.org/packages/64/ef/c784e20b96674ed36a5af839305f55616f8b4f8aa8eeccf8531a6e312243/pillow-12.1.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6408a7b064595afcab0a49393a413732a35788f2a5092fdc6266952ed67de586", size = 7068558, upload-time = "2026-02-11T04:22:39.597Z" }, + { url = "https://files.pythonhosted.org/packages/73/cb/8059688b74422ae61278202c4e1ad992e8a2e7375227be0a21c6b87ca8d5/pillow-12.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5d8c41325b382c07799a3682c1c258469ea2ff97103c53717b7893862d0c98ce", size = 6493028, upload-time = "2026-02-11T04:22:42.73Z" }, + { url = "https://files.pythonhosted.org/packages/c6/da/e3c008ed7d2dd1f905b15949325934510b9d1931e5df999bb15972756818/pillow-12.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c7697918b5be27424e9ce568193efd13d925c4481dd364e43f5dff72d33e10f8", size = 7191940, upload-time = "2026-02-11T04:22:44.543Z" }, + { url = "https://files.pythonhosted.org/packages/01/4a/9202e8d11714c1fc5951f2e1ef362f2d7fbc595e1f6717971d5dd750e969/pillow-12.1.1-cp314-cp314t-win32.whl", hash = "sha256:d2912fd8114fc5545aa3a4b5576512f64c55a03f3ebcca4c10194d593d43ea36", size = 6438736, upload-time = "2026-02-11T04:22:46.347Z" }, + { url = "https://files.pythonhosted.org/packages/f3/ca/cbce2327eb9885476b3957b2e82eb12c866a8b16ad77392864ad601022ce/pillow-12.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:4ceb838d4bd9dab43e06c363cab2eebf63846d6a4aeaea283bbdfd8f1a8ed58b", size = 7182894, upload-time = "2026-02-11T04:22:48.114Z" }, + { url = "https://files.pythonhosted.org/packages/ec/d2/de599c95ba0a973b94410477f8bf0b6f0b5e67360eb89bcb1ad365258beb/pillow-12.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:7b03048319bfc6170e93bd60728a1af51d3dd7704935feb228c4d4faab35d334", size = 2546446, upload-time = "2026-02-11T04:22:50.342Z" }, ] [[package]] @@ -1173,11 +1239,11 @@ wheels = [ [[package]] name = "platformdirs" -version = "4.5.1" +version = "4.9.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" } +sdist = { url = "https://files.pythonhosted.org/packages/19/56/8d4c30c8a1d07013911a8fdbd8f89440ef9f08d07a1b50ab8ca8be5a20f9/platformdirs-4.9.4.tar.gz", hash = "sha256:1ec356301b7dc906d83f371c8f487070e99d3ccf9e501686456394622a01a934", size = 28737, upload-time = "2026-03-05T18:34:13.271Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, + { url = "https://files.pythonhosted.org/packages/63/d7/97f7e3a6abb67d8080dd406fd4df842c2be0efaf712d1c899c32a075027c/platformdirs-4.9.4-py3-none-any.whl", hash = "sha256:68a9a4619a666ea6439f2ff250c12a853cd1cbd5158d258bd824a7df6be2f868", size = 21216, upload-time = "2026-03-05T18:34:12.172Z" }, ] [[package]] @@ -1189,15 +1255,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, ] -[[package]] -name = "ply" -version = "3.11" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e5/69/882ee5c9d017149285cab114ebeab373308ef0f874fcdac9beb90e0ac4da/ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3", size = 159130, upload-time = "2018-02-15T19:01:31.097Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/58/35da89ee790598a0700ea49b2a66594140f44dec458c07e8e3d4979137fc/ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce", size = 49567, upload-time = "2018-02-15T19:01:27.172Z" }, -] - [[package]] name = "pre-commit" version = "4.5.1" @@ -1242,21 +1299,20 @@ wheels = [ [[package]] name = "pydata-sphinx-theme" -version = "0.15.4" +version = "0.16.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "accessible-pygments" }, { name = "babel" }, { name = "beautifulsoup4" }, { name = "docutils" }, - { name = "packaging" }, { name = "pygments" }, { name = "sphinx" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/67/ea/3ab478cccacc2e8ef69892c42c44ae547bae089f356c4b47caf61730958d/pydata_sphinx_theme-0.15.4.tar.gz", hash = "sha256:7762ec0ac59df3acecf49fd2f889e1b4565dbce8b88b2e29ee06fdd90645a06d", size = 2400673, upload-time = "2024-06-25T19:28:45.041Z" } +sdist = { url = "https://files.pythonhosted.org/packages/00/20/bb50f9de3a6de69e6abd6b087b52fa2418a0418b19597601605f855ad044/pydata_sphinx_theme-0.16.1.tar.gz", hash = "sha256:a08b7f0b7f70387219dc659bff0893a7554d5eb39b59d3b8ef37b8401b7642d7", size = 2412693, upload-time = "2024-12-17T10:53:39.537Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/d3/c622950d87a2ffd1654208733b5bd1c5645930014abed8f4c0d74863988b/pydata_sphinx_theme-0.15.4-py3-none-any.whl", hash = "sha256:2136ad0e9500d0949f96167e63f3e298620040aea8f9c74621959eda5d4cf8e6", size = 4640157, upload-time = "2024-06-25T19:28:42.383Z" }, + { url = "https://files.pythonhosted.org/packages/e2/0d/8ba33fa83a7dcde13eb3c1c2a0c1cc29950a048bfed6d9b0d8b6bd710b4c/pydata_sphinx_theme-0.16.1-py3-none-any.whl", hash = "sha256:225331e8ac4b32682c18fcac5a57a6f717c4e632cea5dd0e247b55155faeccde", size = 6723264, upload-time = "2024-12-17T10:53:35.645Z" }, ] [[package]] @@ -1270,30 +1326,27 @@ wheels = [ [[package]] name = "pyomo" -version = "6.9.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ply" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/87/d8/f32e0dcacc8219694709200d4402c86a6e28d3af50380a5ccf7f7e15ffae/pyomo-6.9.5.tar.gz", hash = "sha256:0734020fcd5cc03ee200fd3f79d143fbfc14e6be116e0d16bab79f3f89609879", size = 3067399, upload-time = "2025-10-17T20:21:56.877Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/63/5f163b231a924ba7a5f6c58466c751f70be88568fa446524b6e806c98e4b/pyomo-6.9.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:549ee4226cab6e2ff6efe5b3b9891ce1dfd866d38a024715315ea850fa1bf0ec", size = 4308708, upload-time = "2025-10-17T20:25:28.506Z" }, - { url = "https://files.pythonhosted.org/packages/2d/bf/0cebcfce70be04d6d7aa19fbcbdeecdd5843caac617424f34ab3feb8e96e/pyomo-6.9.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b382cc8c3728199c8332024d64eed8622dabb3f8aebe5874c86a036489064f7a", size = 4295507, upload-time = "2025-10-17T20:25:33.266Z" }, - { url = "https://files.pythonhosted.org/packages/14/27/967545514a2d0f4ca5ac6b595661cb0927cdcd10c3bb2832c5aa0ee15990/pyomo-6.9.5-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:43c6e425ca5231b530cd23460e371b7ca9119224dd57237c34580e15f31e4d72", size = 4358265, upload-time = "2025-10-17T21:06:36.892Z" }, - { url = "https://files.pythonhosted.org/packages/85/fe/691e5eb26f58ee4a072add6cc484756d9e3c367901ec6701d2c6789b394d/pyomo-6.9.5-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a1923c358e1e8009a05ada911fc72e615c9e2ce6988f0979ec1ecc75880ee1f7", size = 4389545, upload-time = "2025-10-17T20:25:37.684Z" }, - { url = "https://files.pythonhosted.org/packages/c7/b3/ae47340790f2f1f92f76b176acf475890717f0cb7def073e504b9857a057/pyomo-6.9.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:694262dc2eb53ca1ab245261f432a5ed1ec30cf3e651b5a6a1c276bc2dd81076", size = 4308795, upload-time = "2025-10-17T20:25:42.533Z" }, - { url = "https://files.pythonhosted.org/packages/29/e9/7f782864afd28a9eb53057c9d046541be6535b2da35e11c2bcb80839c6bd/pyomo-6.9.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f99ce91f2710d60b380a3a519288282d2183c44e1d66c131909313a3b63e7a2", size = 4295577, upload-time = "2025-10-17T20:25:47.185Z" }, - { url = "https://files.pythonhosted.org/packages/cd/4d/9ca17a602e31a1c3f3148c455a5739fcbe23c102b80a12ec3e6d3bf5e847/pyomo-6.9.5-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d22f99e0ba8e2fb7d0e806bf630b8ce9b0a41d777c51f22711adbcb905f7486e", size = 4359087, upload-time = "2025-10-17T21:06:41.413Z" }, - { url = "https://files.pythonhosted.org/packages/44/2e/78c3ac876791b59c836338b73dc49317b01cef574b01af061999a04a064a/pyomo-6.9.5-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5953e490b9e9ea42d28804dd0358a9d3ef82560022c2b538e70a638790bc392", size = 4390954, upload-time = "2025-10-17T20:25:51.388Z" }, - { url = "https://files.pythonhosted.org/packages/3c/27/3eb3db8e9ed6a01dee63219389aec761d5cc29b6dc5015b32f826f2a9225/pyomo-6.9.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:058eddde05b4354307975f1ecd25cfda9f8a282ad2e3b4f168ff8fee3c3623a1", size = 4310036, upload-time = "2025-10-17T20:25:56.782Z" }, - { url = "https://files.pythonhosted.org/packages/9a/31/7f4750fc9bb0ec18a9534549e4c80ea63f1267aa828d495a48bbf0018f49/pyomo-6.9.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:105a073c47a2d2d6e74e48ed6fc82c6f6d19027488d5003aabb7ed5d10271483", size = 4297011, upload-time = "2025-10-17T20:26:00.976Z" }, - { url = "https://files.pythonhosted.org/packages/f8/67/639d0006eddab30cf415b0154763ccc51f3c15b934e866eb4fb07bc2b6ed/pyomo-6.9.5-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f2c636c2c640b33dde3b119f6f0941a1bbde39397c392dba55351b0438d8600f", size = 4360501, upload-time = "2025-10-17T21:06:45.673Z" }, - { url = "https://files.pythonhosted.org/packages/67/ef/023b74b8f161f15a51febdd160354f1e3fd7e1475abbe5ccfb3d7588cf1f/pyomo-6.9.5-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e02813b4021eeed7214a1ca5d7daecbdc78d3db7059962553a57fd138d747c22", size = 4391836, upload-time = "2025-10-17T20:26:05.491Z" }, - { url = "https://files.pythonhosted.org/packages/a0/ca/edab1b532fd5e2d146d0cb96836eb5ae387b8a5bd255213e306793f6168e/pyomo-6.9.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:83789ce89271da31e0ff5bbef692af1621ab1747798183a5603b6577b7074277", size = 4330906, upload-time = "2025-10-17T20:26:09.977Z" }, - { url = "https://files.pythonhosted.org/packages/a9/3c/2745386f57030bc60b626adba002b68db3f9538d5b52900f48026a4a17d7/pyomo-6.9.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1f449aaceac5078daaecc21d19b96a15529f9ac8aa90f6472e8811cc07112ecc", size = 4316124, upload-time = "2025-10-17T20:26:14.339Z" }, - { url = "https://files.pythonhosted.org/packages/f1/93/2058af0890b13f7e1a26e4925ff8d681c23d9cbdc2ecc9db17c744941617/pyomo-6.9.5-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f94d03f122fcf04a769c28ad48c423cd7b6d3d2c40da20bc8ea1a41bb20d0c36", size = 4356089, upload-time = "2025-10-17T21:06:50.178Z" }, - { url = "https://files.pythonhosted.org/packages/de/30/c808931fc034851a16d3f8360d045b087ac743ea97bfe96cdb4b1df47c21/pyomo-6.9.5-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:96ff300e96cdab75e2e6983c99e3a61eaff2a6d0f5ed83acd939e74e361de537", size = 4382150, upload-time = "2025-10-17T20:26:18.734Z" }, - { url = "https://files.pythonhosted.org/packages/68/29/394967f7df51788cbdf1b4aedfb7c5a3a62e11b85b4c9d806b86cc576be4/pyomo-6.9.5-py3-none-any.whl", hash = "sha256:60326f7d3143ee7d0f5c5c4a3cbf871b53e08cc6c2b0c9e6d25568880233472f", size = 3938900, upload-time = "2025-10-17T20:22:07.473Z" }, +version = "6.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/df/be/6aa8022dec69bf837885a094b9bc8d452debcb455ab69b66ee27cc6563e3/pyomo-6.10.0.tar.gz", hash = "sha256:672fac375e57e121ca935adcc16a1cd118be8afa1a3e5608161fb86220c3a577", size = 3171562, upload-time = "2026-02-20T21:42:31.639Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/8c/bbc4cfab889eaa689e85b2ec0574bd9a584d9de89d36e22ad11bd050acf5/pyomo-6.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a564996b6e3c0b425d5961186ee5d726ba59d1fb29490eb63cd32d8183859c46", size = 4430199, upload-time = "2026-02-20T21:49:11.58Z" }, + { url = "https://files.pythonhosted.org/packages/75/3e/b5ff9b8b786741507eb899c865871c7bdac02f05eef6faa7cf625dae99b3/pyomo-6.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e686b529e81a650ac9d1458476c664ee1cf2b45a90f57acce318524f50255ad", size = 4415951, upload-time = "2026-02-20T21:49:17.426Z" }, + { url = "https://files.pythonhosted.org/packages/2e/6b/7371e09047b6b0c3d475545aa819415a84d579797bfe9a9b822771dc8ea2/pyomo-6.10.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d6c7d8802b399541e611f289172c3ec721e75a029a7d3af4cc56a0e8ff6735d", size = 4484110, upload-time = "2026-02-27T17:09:34.503Z" }, + { url = "https://files.pythonhosted.org/packages/ca/2b/ae9f35156948b959b7d292e842fea4a08dffbf96e944e88fdcf10a3c3391/pyomo-6.10.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a5ca37402b686816704a95f72d7d6c7aa5245f38f10010828ce9d0937694f4cb", size = 4512622, upload-time = "2026-02-20T21:49:23.022Z" }, + { url = "https://files.pythonhosted.org/packages/1c/66/b4fe4f6f9dcdb01c8590d507a4090c7ffdb72a2832115ce07fb83b23e718/pyomo-6.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:376dc045e62285b42ce41706df370f2ab5ac8babb31e2750aa3bf9eb6ce938ac", size = 4430253, upload-time = "2026-02-20T21:49:28.949Z" }, + { url = "https://files.pythonhosted.org/packages/75/01/a8c1539654b29903a98310fb34fd4caeebf67061289f552b1ea826462156/pyomo-6.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4bc7b77278da187e6bcd603317cb60dd6555aeff8159c811eb9755fc873c4928", size = 4416089, upload-time = "2026-02-20T21:49:34.724Z" }, + { url = "https://files.pythonhosted.org/packages/e7/ef/bf19632527bba7149d5a1d18ad5a923ee4956cd2a7c6dcc595a43321ca2e/pyomo-6.10.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e13d6ac1c837419d2140618faeee061c7ab8e09c872005a9e75ec46bcb6c85e4", size = 4484042, upload-time = "2026-02-27T17:09:44.869Z" }, + { url = "https://files.pythonhosted.org/packages/dd/4e/9d523d75a64dc7ed13fd76bbf94618666456b0b69dcf1f2dc308ada982f9/pyomo-6.10.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dcf06214b71617d45a7cb238793171863bf0a30d9e1740190443813baee200", size = 4513077, upload-time = "2026-02-20T21:49:40.608Z" }, + { url = "https://files.pythonhosted.org/packages/2b/11/ebc9e817490a7992e950cca96b2671c2a490b08f9eb9e4fdc5091c6e77b8/pyomo-6.10.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:581dfe7e747c322177e64236cb3fee7fa015d7e6022f66b59394b927f0f29b0a", size = 4431213, upload-time = "2026-02-20T21:49:47.522Z" }, + { url = "https://files.pythonhosted.org/packages/93/54/f0705ba23eab3f2287e58c3cdd34b51b18e12bbd98dc96bf57defb0eb6cd/pyomo-6.10.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:70ab5312b1aa8b95618c3766c3e3f7be3e4d730e41ce24eea1b59eb5831d6817", size = 4416909, upload-time = "2026-02-20T21:49:53.383Z" }, + { url = "https://files.pythonhosted.org/packages/3f/d8/57012015ead9c60815976d3aa8948f8a0bcc621ea643c0eb520b84147739/pyomo-6.10.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d7519673917e049ba0910fc8b19648ebf711ebec9c685c7c840d66d5471dcc0c", size = 4486590, upload-time = "2026-02-27T17:09:54.395Z" }, + { url = "https://files.pythonhosted.org/packages/52/48/8bdf61ee998f65e2e00d65778e2a4cfe41129953a6b0ba72e7a5f5cefdc6/pyomo-6.10.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:505a1ea36f80125b878d8d0e34f3eb6af2cac3309523011caf1877d88fd16ecd", size = 4514075, upload-time = "2026-02-20T21:49:59.483Z" }, + { url = "https://files.pythonhosted.org/packages/73/17/62983f857eb592d5ede12f0f41ddbe5d1fa17c2796fb8c3db8ac7859e177/pyomo-6.10.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:905a16f21e90b44d9a52e2aaa9884c467abf50a945d08b9ddb8db40d4d707dbc", size = 4452689, upload-time = "2026-02-20T21:50:05.288Z" }, + { url = "https://files.pythonhosted.org/packages/67/e3/502d561a64259274c046f705e2325189e84a77c624f043f34fbd2f14e793/pyomo-6.10.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:4859fb1a0f78ac0f5fad00199244d461d7bc100c8f76a61d696a1e1461d68bb0", size = 4439487, upload-time = "2026-02-20T21:50:11.116Z" }, + { url = "https://files.pythonhosted.org/packages/3b/89/89164dcf7549f1034b1f8646b4b3cf6e1ec09cb0d30dfaa3fce125fd95a4/pyomo-6.10.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:07d69ae184c8206a4064fc13fe6b48d4a5aac7f18cbf8f6bed30faf9d3762106", size = 4479850, upload-time = "2026-02-27T17:10:04.269Z" }, + { url = "https://files.pythonhosted.org/packages/65/bd/cb4535b0bb63a7bcc968464ab739f54d2f4d15fe7924547336f5bd299513/pyomo-6.10.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0590505b282468c9fc2555ced544213227a0a466bbc667826a36cc922afec6d7", size = 4506738, upload-time = "2026-02-20T21:50:17.382Z" }, + { url = "https://files.pythonhosted.org/packages/88/1d/b5dad00739979353726059137a647acf031ef3af5557a9d227ca7b32481d/pyomo-6.10.0-py3-none-any.whl", hash = "sha256:3fc34402474f78c9144c735499c8dc6a0570948034f4c668d24727ec1b4671b1", size = 4052690, upload-time = "2026-02-27T17:10:13.653Z" }, ] [[package]] @@ -1347,6 +1400,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, ] +[[package]] +name = "python-discovery" +version = "1.1.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d7/7e/9f3b0dd3a074a6c3e1e79f35e465b1f2ee4b262d619de00cfce523cc9b24/python_discovery-1.1.3.tar.gz", hash = "sha256:7acca36e818cd88e9b2ba03e045ad7e93e1713e29c6bbfba5d90202310b7baa5", size = 56945, upload-time = "2026-03-10T15:08:15.038Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/80/73211fc5bfbfc562369b4aa61dc1e4bf07dc7b34df7b317e4539316b809c/python_discovery-1.1.3-py3-none-any.whl", hash = "sha256:90e795f0121bc84572e737c9aa9966311b9fde44ffb88a5953b3ec9b31c6945e", size = 31485, upload-time = "2026-03-10T15:08:13.06Z" }, +] + [[package]] name = "pyyaml" version = "6.0.3" @@ -1410,15 +1476,15 @@ wheels = [ [[package]] name = "rich" -version = "14.2.0" +version = "14.3.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fb/d2/8920e102050a0de7bfabeb4c4614a49248cf8d5d7a8d01885fbb24dc767a/rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4", size = 219990, upload-time = "2025-10-09T14:16:53.064Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/c6/f3b320c27991c46f43ee9d856302c70dc2d0fb2dba4842ff739d5f46b393/rich-14.3.3.tar.gz", hash = "sha256:b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b", size = 230582, upload-time = "2026-02-19T17:23:12.474Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393, upload-time = "2025-10-09T14:16:51.245Z" }, + { url = "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl", hash = "sha256:793431c1f8619afa7d3b52b2cdec859562b950ea0d4b6b505397612db8d5362d", size = 310458, upload-time = "2026-02-19T17:23:13.732Z" }, ] [[package]] @@ -1432,28 +1498,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.14.14" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2e/06/f71e3a86b2df0dfa2d2f72195941cd09b44f87711cb7fa5193732cb9a5fc/ruff-0.14.14.tar.gz", hash = "sha256:2d0f819c9a90205f3a867dbbd0be083bee9912e170fd7d9704cc8ae45824896b", size = 4515732, upload-time = "2026-01-22T22:30:17.527Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/89/20a12e97bc6b9f9f68343952da08a8099c57237aef953a56b82711d55edd/ruff-0.14.14-py3-none-linux_armv6l.whl", hash = "sha256:7cfe36b56e8489dee8fbc777c61959f60ec0f1f11817e8f2415f429552846aed", size = 10467650, upload-time = "2026-01-22T22:30:08.578Z" }, - { url = "https://files.pythonhosted.org/packages/a3/b1/c5de3fd2d5a831fcae21beda5e3589c0ba67eec8202e992388e4b17a6040/ruff-0.14.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6006a0082336e7920b9573ef8a7f52eec837add1265cc74e04ea8a4368cd704c", size = 10883245, upload-time = "2026-01-22T22:30:04.155Z" }, - { url = "https://files.pythonhosted.org/packages/b8/7c/3c1db59a10e7490f8f6f8559d1db8636cbb13dccebf18686f4e3c9d7c772/ruff-0.14.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:026c1d25996818f0bf498636686199d9bd0d9d6341c9c2c3b62e2a0198b758de", size = 10231273, upload-time = "2026-01-22T22:30:34.642Z" }, - { url = "https://files.pythonhosted.org/packages/a1/6e/5e0e0d9674be0f8581d1f5e0f0a04761203affce3232c1a1189d0e3b4dad/ruff-0.14.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f666445819d31210b71e0a6d1c01e24447a20b85458eea25a25fe8142210ae0e", size = 10585753, upload-time = "2026-01-22T22:30:31.781Z" }, - { url = "https://files.pythonhosted.org/packages/23/09/754ab09f46ff1884d422dc26d59ba18b4e5d355be147721bb2518aa2a014/ruff-0.14.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c0f18b922c6d2ff9a5e6c3ee16259adc513ca775bcf82c67ebab7cbd9da5bc8", size = 10286052, upload-time = "2026-01-22T22:30:24.827Z" }, - { url = "https://files.pythonhosted.org/packages/c8/cc/e71f88dd2a12afb5f50733851729d6b571a7c3a35bfdb16c3035132675a0/ruff-0.14.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1629e67489c2dea43e8658c3dba659edbfd87361624b4040d1df04c9740ae906", size = 11043637, upload-time = "2026-01-22T22:30:13.239Z" }, - { url = "https://files.pythonhosted.org/packages/67/b2/397245026352494497dac935d7f00f1468c03a23a0c5db6ad8fc49ca3fb2/ruff-0.14.14-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:27493a2131ea0f899057d49d303e4292b2cae2bb57253c1ed1f256fbcd1da480", size = 12194761, upload-time = "2026-01-22T22:30:22.542Z" }, - { url = "https://files.pythonhosted.org/packages/5b/06/06ef271459f778323112c51b7587ce85230785cd64e91772034ddb88f200/ruff-0.14.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ff589aab3f5b539e35db38425da31a57521efd1e4ad1ae08fc34dbe30bd7df", size = 12005701, upload-time = "2026-01-22T22:30:20.499Z" }, - { url = "https://files.pythonhosted.org/packages/41/d6/99364514541cf811ccc5ac44362f88df66373e9fec1b9d1c4cc830593fe7/ruff-0.14.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc12d74eef0f29f51775f5b755913eb523546b88e2d733e1d701fe65144e89b", size = 11282455, upload-time = "2026-01-22T22:29:59.679Z" }, - { url = "https://files.pythonhosted.org/packages/ca/71/37daa46f89475f8582b7762ecd2722492df26421714a33e72ccc9a84d7a5/ruff-0.14.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb8481604b7a9e75eff53772496201690ce2687067e038b3cc31aaf16aa0b974", size = 11215882, upload-time = "2026-01-22T22:29:57.032Z" }, - { url = "https://files.pythonhosted.org/packages/2c/10/a31f86169ec91c0705e618443ee74ede0bdd94da0a57b28e72db68b2dbac/ruff-0.14.14-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:14649acb1cf7b5d2d283ebd2f58d56b75836ed8c6f329664fa91cdea19e76e66", size = 11180549, upload-time = "2026-01-22T22:30:27.175Z" }, - { url = "https://files.pythonhosted.org/packages/fd/1e/c723f20536b5163adf79bdd10c5f093414293cdf567eed9bdb7b83940f3f/ruff-0.14.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8058d2145566510790eab4e2fad186002e288dec5e0d343a92fe7b0bc1b3e13", size = 10543416, upload-time = "2026-01-22T22:30:01.964Z" }, - { url = "https://files.pythonhosted.org/packages/3e/34/8a84cea7e42c2d94ba5bde1d7a4fae164d6318f13f933d92da6d7c2041ff/ruff-0.14.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e651e977a79e4c758eb807f0481d673a67ffe53cfa92209781dfa3a996cf8412", size = 10285491, upload-time = "2026-01-22T22:30:29.51Z" }, - { url = "https://files.pythonhosted.org/packages/55/ef/b7c5ea0be82518906c978e365e56a77f8de7678c8bb6651ccfbdc178c29f/ruff-0.14.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cc8b22da8d9d6fdd844a68ae937e2a0adf9b16514e9a97cc60355e2d4b219fc3", size = 10733525, upload-time = "2026-01-22T22:30:06.499Z" }, - { url = "https://files.pythonhosted.org/packages/6a/5b/aaf1dfbcc53a2811f6cc0a1759de24e4b03e02ba8762daabd9b6bd8c59e3/ruff-0.14.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:16bc890fb4cc9781bb05beb5ab4cd51be9e7cb376bf1dd3580512b24eb3fda2b", size = 11315626, upload-time = "2026-01-22T22:30:36.848Z" }, - { url = "https://files.pythonhosted.org/packages/2c/aa/9f89c719c467dfaf8ad799b9bae0df494513fb21d31a6059cb5870e57e74/ruff-0.14.14-py3-none-win32.whl", hash = "sha256:b530c191970b143375b6a68e6f743800b2b786bbcf03a7965b06c4bf04568167", size = 10502442, upload-time = "2026-01-22T22:30:38.93Z" }, - { url = "https://files.pythonhosted.org/packages/87/44/90fa543014c45560cae1fffc63ea059fb3575ee6e1cb654562197e5d16fb/ruff-0.14.14-py3-none-win_amd64.whl", hash = "sha256:3dde1435e6b6fe5b66506c1dff67a421d0b7f6488d466f651c07f4cab3bf20fd", size = 11630486, upload-time = "2026-01-22T22:30:10.852Z" }, - { url = "https://files.pythonhosted.org/packages/9e/6a/40fee331a52339926a92e17ae748827270b288a35ef4a15c9c8f2ec54715/ruff-0.14.14-py3-none-win_arm64.whl", hash = "sha256:56e6981a98b13a32236a72a8da421d7839221fa308b223b9283312312e5ac76c", size = 10920448, upload-time = "2026-01-22T22:30:15.417Z" }, +version = "0.15.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/51/df/f8629c19c5318601d3121e230f74cbee7a3732339c52b21daa2b82ef9c7d/ruff-0.15.6.tar.gz", hash = "sha256:8394c7bb153a4e3811a4ecdacd4a8e6a4fa8097028119160dffecdcdf9b56ae4", size = 4597916, upload-time = "2026-03-12T23:05:47.51Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/2f/4e03a7e5ce99b517e98d3b4951f411de2b0fa8348d39cf446671adcce9a2/ruff-0.15.6-py3-none-linux_armv6l.whl", hash = "sha256:7c98c3b16407b2cf3d0f2b80c80187384bc92c6774d85fefa913ecd941256fff", size = 10508953, upload-time = "2026-03-12T23:05:17.246Z" }, + { url = "https://files.pythonhosted.org/packages/70/60/55bcdc3e9f80bcf39edf0cd272da6fa511a3d94d5a0dd9e0adf76ceebdb4/ruff-0.15.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ee7dcfaad8b282a284df4aa6ddc2741b3f4a18b0555d626805555a820ea181c3", size = 10942257, upload-time = "2026-03-12T23:05:23.076Z" }, + { url = "https://files.pythonhosted.org/packages/e7/f9/005c29bd1726c0f492bfa215e95154cf480574140cb5f867c797c18c790b/ruff-0.15.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3bd9967851a25f038fc8b9ae88a7fbd1b609f30349231dffaa37b6804923c4bb", size = 10322683, upload-time = "2026-03-12T23:05:33.738Z" }, + { url = "https://files.pythonhosted.org/packages/5f/74/2f861f5fd7cbb2146bddb5501450300ce41562da36d21868c69b7a828169/ruff-0.15.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13f4594b04e42cd24a41da653886b04d2ff87adbf57497ed4f728b0e8a4866f8", size = 10660986, upload-time = "2026-03-12T23:05:53.245Z" }, + { url = "https://files.pythonhosted.org/packages/c1/a1/309f2364a424eccb763cdafc49df843c282609f47fe53aa83f38272389e0/ruff-0.15.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e2ed8aea2f3fe57886d3f00ea5b8aae5bf68d5e195f487f037a955ff9fbaac9e", size = 10332177, upload-time = "2026-03-12T23:05:56.145Z" }, + { url = "https://files.pythonhosted.org/packages/30/41/7ebf1d32658b4bab20f8ac80972fb19cd4e2c6b78552be263a680edc55ac/ruff-0.15.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70789d3e7830b848b548aae96766431c0dc01a6c78c13381f423bf7076c66d15", size = 11170783, upload-time = "2026-03-12T23:06:01.742Z" }, + { url = "https://files.pythonhosted.org/packages/76/be/6d488f6adca047df82cd62c304638bcb00821c36bd4881cfca221561fdfc/ruff-0.15.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:542aaf1de3154cea088ced5a819ce872611256ffe2498e750bbae5247a8114e9", size = 12044201, upload-time = "2026-03-12T23:05:28.697Z" }, + { url = "https://files.pythonhosted.org/packages/71/68/e6f125df4af7e6d0b498f8d373274794bc5156b324e8ab4bf5c1b4fc0ec7/ruff-0.15.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c22e6f02c16cfac3888aa636e9eba857254d15bbacc9906c9689fdecb1953ab", size = 11421561, upload-time = "2026-03-12T23:05:31.236Z" }, + { url = "https://files.pythonhosted.org/packages/f1/9f/f85ef5fd01a52e0b472b26dc1b4bd228b8f6f0435975442ffa4741278703/ruff-0.15.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98893c4c0aadc8e448cfa315bd0cc343a5323d740fe5f28ef8a3f9e21b381f7e", size = 11310928, upload-time = "2026-03-12T23:05:45.288Z" }, + { url = "https://files.pythonhosted.org/packages/8c/26/b75f8c421f5654304b89471ed384ae8c7f42b4dff58fa6ce1626d7f2b59a/ruff-0.15.6-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:70d263770d234912374493e8cc1e7385c5d49376e41dfa51c5c3453169dc581c", size = 11235186, upload-time = "2026-03-12T23:05:50.677Z" }, + { url = "https://files.pythonhosted.org/packages/fc/d4/d5a6d065962ff7a68a86c9b4f5500f7d101a0792078de636526c0edd40da/ruff-0.15.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:55a1ad63c5a6e54b1f21b7514dfadc0c7fb40093fa22e95143cf3f64ebdcd512", size = 10635231, upload-time = "2026-03-12T23:05:37.044Z" }, + { url = "https://files.pythonhosted.org/packages/d6/56/7c3acf3d50910375349016cf33de24be021532042afbed87942858992491/ruff-0.15.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8dc473ba093c5ec238bb1e7429ee676dca24643c471e11fbaa8a857925b061c0", size = 10340357, upload-time = "2026-03-12T23:06:04.748Z" }, + { url = "https://files.pythonhosted.org/packages/06/54/6faa39e9c1033ff6a3b6e76b5df536931cd30caf64988e112bbf91ef5ce5/ruff-0.15.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:85b042377c2a5561131767974617006f99f7e13c63c111b998f29fc1e58a4cfb", size = 10860583, upload-time = "2026-03-12T23:05:58.978Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/509a201b843b4dfb0b32acdedf68d951d3377988cae43949ba4c4133a96a/ruff-0.15.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:cef49e30bc5a86a6a92098a7fbf6e467a234d90b63305d6f3ec01225a9d092e0", size = 11410976, upload-time = "2026-03-12T23:05:39.955Z" }, + { url = "https://files.pythonhosted.org/packages/6c/25/3fc9114abf979a41673ce877c08016f8e660ad6cf508c3957f537d2e9fa9/ruff-0.15.6-py3-none-win32.whl", hash = "sha256:bbf67d39832404812a2d23020dda68fee7f18ce15654e96fb1d3ad21a5fe436c", size = 10616872, upload-time = "2026-03-12T23:05:42.451Z" }, + { url = "https://files.pythonhosted.org/packages/89/7a/09ece68445ceac348df06e08bf75db72d0e8427765b96c9c0ffabc1be1d9/ruff-0.15.6-py3-none-win_amd64.whl", hash = "sha256:aee25bc84c2f1007ecb5037dff75cef00414fdf17c23f07dc13e577883dca406", size = 11787271, upload-time = "2026-03-12T23:05:20.168Z" }, + { url = "https://files.pythonhosted.org/packages/7f/d0/578c47dd68152ddddddf31cd7fc67dc30b7cdf639a86275fda821b0d9d98/ruff-0.15.6-py3-none-win_arm64.whl", hash = "sha256:c34de3dd0b0ba203be50ae70f5910b17188556630e2178fd7d79fc030eb0d837", size = 11060497, upload-time = "2026-03-12T23:05:25.968Z" }, ] [[package]] @@ -1474,63 +1539,63 @@ wheels = [ [[package]] name = "scipy" -version = "1.17.0" +version = "1.17.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/56/3e/9cca699f3486ce6bc12ff46dc2031f1ec8eb9ccc9a320fdaf925f1417426/scipy-1.17.0.tar.gz", hash = "sha256:2591060c8e648d8b96439e111ac41fd8342fdeff1876be2e19dea3fe8930454e", size = 30396830, upload-time = "2026-01-10T21:34:23.009Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/11/7241a63e73ba5a516f1930ac8d5b44cbbfabd35ac73a2d08ca206df007c4/scipy-1.17.0-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:0d5018a57c24cb1dd828bcf51d7b10e65986d549f52ef5adb6b4d1ded3e32a57", size = 31364580, upload-time = "2026-01-10T21:25:25.717Z" }, - { url = "https://files.pythonhosted.org/packages/ed/1d/5057f812d4f6adc91a20a2d6f2ebcdb517fdbc87ae3acc5633c9b97c8ba5/scipy-1.17.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:88c22af9e5d5a4f9e027e26772cc7b5922fab8bcc839edb3ae33de404feebd9e", size = 27969012, upload-time = "2026-01-10T21:25:30.921Z" }, - { url = "https://files.pythonhosted.org/packages/e3/21/f6ec556c1e3b6ec4e088da667d9987bb77cc3ab3026511f427dc8451187d/scipy-1.17.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:f3cd947f20fe17013d401b64e857c6b2da83cae567adbb75b9dcba865abc66d8", size = 20140691, upload-time = "2026-01-10T21:25:34.802Z" }, - { url = "https://files.pythonhosted.org/packages/7a/fe/5e5ad04784964ba964a96f16c8d4676aa1b51357199014dce58ab7ec5670/scipy-1.17.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:e8c0b331c2c1f531eb51f1b4fc9ba709521a712cce58f1aa627bc007421a5306", size = 22463015, upload-time = "2026-01-10T21:25:39.277Z" }, - { url = "https://files.pythonhosted.org/packages/4a/69/7c347e857224fcaf32a34a05183b9d8a7aca25f8f2d10b8a698b8388561a/scipy-1.17.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5194c445d0a1c7a6c1a4a4681b6b7c71baad98ff66d96b949097e7513c9d6742", size = 32724197, upload-time = "2026-01-10T21:25:44.084Z" }, - { url = "https://files.pythonhosted.org/packages/d1/fe/66d73b76d378ba8cc2fe605920c0c75092e3a65ae746e1e767d9d020a75a/scipy-1.17.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9eeb9b5f5997f75507814ed9d298ab23f62cf79f5a3ef90031b1ee2506abdb5b", size = 35009148, upload-time = "2026-01-10T21:25:50.591Z" }, - { url = "https://files.pythonhosted.org/packages/af/07/07dec27d9dc41c18d8c43c69e9e413431d20c53a0339c388bcf72f353c4b/scipy-1.17.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:40052543f7bbe921df4408f46003d6f01c6af109b9e2c8a66dd1cf6cf57f7d5d", size = 34798766, upload-time = "2026-01-10T21:25:59.41Z" }, - { url = "https://files.pythonhosted.org/packages/81/61/0470810c8a093cdacd4ba7504b8a218fd49ca070d79eca23a615f5d9a0b0/scipy-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0cf46c8013fec9d3694dc572f0b54100c28405d55d3e2cb15e2895b25057996e", size = 37405953, upload-time = "2026-01-10T21:26:07.75Z" }, - { url = "https://files.pythonhosted.org/packages/92/ce/672ed546f96d5d41ae78c4b9b02006cedd0b3d6f2bf5bb76ea455c320c28/scipy-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:0937a0b0d8d593a198cededd4c439a0ea216a3f36653901ea1f3e4be949056f8", size = 36328121, upload-time = "2026-01-10T21:26:16.509Z" }, - { url = "https://files.pythonhosted.org/packages/9d/21/38165845392cae67b61843a52c6455d47d0cc2a40dd495c89f4362944654/scipy-1.17.0-cp312-cp312-win_arm64.whl", hash = "sha256:f603d8a5518c7426414d1d8f82e253e454471de682ce5e39c29adb0df1efb86b", size = 24314368, upload-time = "2026-01-10T21:26:23.087Z" }, - { url = "https://files.pythonhosted.org/packages/0c/51/3468fdfd49387ddefee1636f5cf6d03ce603b75205bf439bbf0e62069bfd/scipy-1.17.0-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:65ec32f3d32dfc48c72df4291345dae4f048749bc8d5203ee0a3f347f96c5ce6", size = 31344101, upload-time = "2026-01-10T21:26:30.25Z" }, - { url = "https://files.pythonhosted.org/packages/b2/9a/9406aec58268d437636069419e6977af953d1e246df941d42d3720b7277b/scipy-1.17.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:1f9586a58039d7229ce77b52f8472c972448cded5736eaf102d5658bbac4c269", size = 27950385, upload-time = "2026-01-10T21:26:36.801Z" }, - { url = "https://files.pythonhosted.org/packages/4f/98/e7342709e17afdfd1b26b56ae499ef4939b45a23a00e471dfb5375eea205/scipy-1.17.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:9fad7d3578c877d606b1150135c2639e9de9cecd3705caa37b66862977cc3e72", size = 20122115, upload-time = "2026-01-10T21:26:42.107Z" }, - { url = "https://files.pythonhosted.org/packages/fd/0e/9eeeb5357a64fd157cbe0302c213517c541cc16b8486d82de251f3c68ede/scipy-1.17.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:423ca1f6584fc03936972b5f7c06961670dbba9f234e71676a7c7ccf938a0d61", size = 22442402, upload-time = "2026-01-10T21:26:48.029Z" }, - { url = "https://files.pythonhosted.org/packages/c9/10/be13397a0e434f98e0c79552b2b584ae5bb1c8b2be95db421533bbca5369/scipy-1.17.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fe508b5690e9eaaa9467fc047f833af58f1152ae51a0d0aed67aa5801f4dd7d6", size = 32696338, upload-time = "2026-01-10T21:26:55.521Z" }, - { url = "https://files.pythonhosted.org/packages/63/1e/12fbf2a3bb240161651c94bb5cdd0eae5d4e8cc6eaeceb74ab07b12a753d/scipy-1.17.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6680f2dfd4f6182e7d6db161344537da644d1cf85cf293f015c60a17ecf08752", size = 34977201, upload-time = "2026-01-10T21:27:03.501Z" }, - { url = "https://files.pythonhosted.org/packages/19/5b/1a63923e23ccd20bd32156d7dd708af5bbde410daa993aa2500c847ab2d2/scipy-1.17.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eec3842ec9ac9de5917899b277428886042a93db0b227ebbe3a333b64ec7643d", size = 34777384, upload-time = "2026-01-10T21:27:11.423Z" }, - { url = "https://files.pythonhosted.org/packages/39/22/b5da95d74edcf81e540e467202a988c50fef41bd2011f46e05f72ba07df6/scipy-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d7425fcafbc09a03731e1bc05581f5fad988e48c6a861f441b7ab729a49a55ea", size = 37379586, upload-time = "2026-01-10T21:27:20.171Z" }, - { url = "https://files.pythonhosted.org/packages/b9/b6/8ac583d6da79e7b9e520579f03007cb006f063642afd6b2eeb16b890bf93/scipy-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:87b411e42b425b84777718cc41516b8a7e0795abfa8e8e1d573bf0ef014f0812", size = 36287211, upload-time = "2026-01-10T21:28:43.122Z" }, - { url = "https://files.pythonhosted.org/packages/55/fb/7db19e0b3e52f882b420417644ec81dd57eeef1bd1705b6f689d8ff93541/scipy-1.17.0-cp313-cp313-win_arm64.whl", hash = "sha256:357ca001c6e37601066092e7c89cca2f1ce74e2a520ca78d063a6d2201101df2", size = 24312646, upload-time = "2026-01-10T21:28:49.893Z" }, - { url = "https://files.pythonhosted.org/packages/20/b6/7feaa252c21cc7aff335c6c55e1b90ab3e3306da3f048109b8b639b94648/scipy-1.17.0-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:ec0827aa4d36cb79ff1b81de898e948a51ac0b9b1c43e4a372c0508c38c0f9a3", size = 31693194, upload-time = "2026-01-10T21:27:27.454Z" }, - { url = "https://files.pythonhosted.org/packages/76/bb/bbb392005abce039fb7e672cb78ac7d158700e826b0515cab6b5b60c26fb/scipy-1.17.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:819fc26862b4b3c73a60d486dbb919202f3d6d98c87cf20c223511429f2d1a97", size = 28365415, upload-time = "2026-01-10T21:27:34.26Z" }, - { url = "https://files.pythonhosted.org/packages/37/da/9d33196ecc99fba16a409c691ed464a3a283ac454a34a13a3a57c0d66f3a/scipy-1.17.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:363ad4ae2853d88ebcde3ae6ec46ccca903ea9835ee8ba543f12f575e7b07e4e", size = 20537232, upload-time = "2026-01-10T21:27:40.306Z" }, - { url = "https://files.pythonhosted.org/packages/56/9d/f4b184f6ddb28e9a5caea36a6f98e8ecd2a524f9127354087ce780885d83/scipy-1.17.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:979c3a0ff8e5ba254d45d59ebd38cde48fce4f10b5125c680c7a4bfe177aab07", size = 22791051, upload-time = "2026-01-10T21:27:46.539Z" }, - { url = "https://files.pythonhosted.org/packages/9b/9d/025cccdd738a72140efc582b1641d0dd4caf2e86c3fb127568dc80444e6e/scipy-1.17.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:130d12926ae34399d157de777472bf82e9061c60cc081372b3118edacafe1d00", size = 32815098, upload-time = "2026-01-10T21:27:54.389Z" }, - { url = "https://files.pythonhosted.org/packages/48/5f/09b879619f8bca15ce392bfc1894bd9c54377e01d1b3f2f3b595a1b4d945/scipy-1.17.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e886000eb4919eae3a44f035e63f0fd8b651234117e8f6f29bad1cd26e7bc45", size = 35031342, upload-time = "2026-01-10T21:28:03.012Z" }, - { url = "https://files.pythonhosted.org/packages/f2/9a/f0f0a9f0aa079d2f106555b984ff0fbb11a837df280f04f71f056ea9c6e4/scipy-1.17.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:13c4096ac6bc31d706018f06a49abe0485f96499deb82066b94d19b02f664209", size = 34893199, upload-time = "2026-01-10T21:28:10.832Z" }, - { url = "https://files.pythonhosted.org/packages/90/b8/4f0f5cf0c5ea4d7548424e6533e6b17d164f34a6e2fb2e43ffebb6697b06/scipy-1.17.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cacbaddd91fcffde703934897c5cd2c7cb0371fac195d383f4e1f1c5d3f3bd04", size = 37438061, upload-time = "2026-01-10T21:28:19.684Z" }, - { url = "https://files.pythonhosted.org/packages/f9/cc/2bd59140ed3b2fa2882fb15da0a9cb1b5a6443d67cfd0d98d4cec83a57ec/scipy-1.17.0-cp313-cp313t-win_amd64.whl", hash = "sha256:edce1a1cf66298cccdc48a1bdf8fb10a3bf58e8b58d6c3883dd1530e103f87c0", size = 36328593, upload-time = "2026-01-10T21:28:28.007Z" }, - { url = "https://files.pythonhosted.org/packages/13/1b/c87cc44a0d2c7aaf0f003aef2904c3d097b422a96c7e7c07f5efd9073c1b/scipy-1.17.0-cp313-cp313t-win_arm64.whl", hash = "sha256:30509da9dbec1c2ed8f168b8d8aa853bc6723fede1dbc23c7d43a56f5ab72a67", size = 24625083, upload-time = "2026-01-10T21:28:35.188Z" }, - { url = "https://files.pythonhosted.org/packages/1a/2d/51006cd369b8e7879e1c630999a19d1fbf6f8b5ed3e33374f29dc87e53b3/scipy-1.17.0-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:c17514d11b78be8f7e6331b983a65a7f5ca1fd037b95e27b280921fe5606286a", size = 31346803, upload-time = "2026-01-10T21:28:57.24Z" }, - { url = "https://files.pythonhosted.org/packages/d6/2e/2349458c3ce445f53a6c93d4386b1c4c5c0c540917304c01222ff95ff317/scipy-1.17.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:4e00562e519c09da34c31685f6acc3aa384d4d50604db0f245c14e1b4488bfa2", size = 27967182, upload-time = "2026-01-10T21:29:04.107Z" }, - { url = "https://files.pythonhosted.org/packages/5e/7c/df525fbfa77b878d1cfe625249529514dc02f4fd5f45f0f6295676a76528/scipy-1.17.0-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:f7df7941d71314e60a481e02d5ebcb3f0185b8d799c70d03d8258f6c80f3d467", size = 20139125, upload-time = "2026-01-10T21:29:10.179Z" }, - { url = "https://files.pythonhosted.org/packages/33/11/fcf9d43a7ed1234d31765ec643b0515a85a30b58eddccc5d5a4d12b5f194/scipy-1.17.0-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:aabf057c632798832f071a8dde013c2e26284043934f53b00489f1773b33527e", size = 22443554, upload-time = "2026-01-10T21:29:15.888Z" }, - { url = "https://files.pythonhosted.org/packages/80/5c/ea5d239cda2dd3d31399424967a24d556cf409fbea7b5b21412b0fd0a44f/scipy-1.17.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a38c3337e00be6fd8a95b4ed66b5d988bac4ec888fd922c2ea9fe5fb1603dd67", size = 32757834, upload-time = "2026-01-10T21:29:23.406Z" }, - { url = "https://files.pythonhosted.org/packages/b8/7e/8c917cc573310e5dc91cbeead76f1b600d3fb17cf0969db02c9cf92e3cfa/scipy-1.17.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00fb5f8ec8398ad90215008d8b6009c9db9fa924fd4c7d6be307c6f945f9cd73", size = 34995775, upload-time = "2026-01-10T21:29:31.915Z" }, - { url = "https://files.pythonhosted.org/packages/c5/43/176c0c3c07b3f7df324e7cdd933d3e2c4898ca202b090bd5ba122f9fe270/scipy-1.17.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f2a4942b0f5f7c23c7cd641a0ca1955e2ae83dedcff537e3a0259096635e186b", size = 34841240, upload-time = "2026-01-10T21:29:39.995Z" }, - { url = "https://files.pythonhosted.org/packages/44/8c/d1f5f4b491160592e7f084d997de53a8e896a3ac01cd07e59f43ca222744/scipy-1.17.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:dbf133ced83889583156566d2bdf7a07ff89228fe0c0cb727f777de92092ec6b", size = 37394463, upload-time = "2026-01-10T21:29:48.723Z" }, - { url = "https://files.pythonhosted.org/packages/9f/ec/42a6657f8d2d087e750e9a5dde0b481fd135657f09eaf1cf5688bb23c338/scipy-1.17.0-cp314-cp314-win_amd64.whl", hash = "sha256:3625c631a7acd7cfd929e4e31d2582cf00f42fcf06011f59281271746d77e061", size = 37053015, upload-time = "2026-01-10T21:30:51.418Z" }, - { url = "https://files.pythonhosted.org/packages/27/58/6b89a6afd132787d89a362d443a7bddd511b8f41336a1ae47f9e4f000dc4/scipy-1.17.0-cp314-cp314-win_arm64.whl", hash = "sha256:9244608d27eafe02b20558523ba57f15c689357c85bdcfe920b1828750aa26eb", size = 24951312, upload-time = "2026-01-10T21:30:56.771Z" }, - { url = "https://files.pythonhosted.org/packages/e9/01/f58916b9d9ae0112b86d7c3b10b9e685625ce6e8248df139d0fcb17f7397/scipy-1.17.0-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:2b531f57e09c946f56ad0b4a3b2abee778789097871fc541e267d2eca081cff1", size = 31706502, upload-time = "2026-01-10T21:29:56.326Z" }, - { url = "https://files.pythonhosted.org/packages/59/8e/2912a87f94a7d1f8b38aabc0faf74b82d3b6c9e22be991c49979f0eceed8/scipy-1.17.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:13e861634a2c480bd237deb69333ac79ea1941b94568d4b0efa5db5e263d4fd1", size = 28380854, upload-time = "2026-01-10T21:30:01.554Z" }, - { url = "https://files.pythonhosted.org/packages/bd/1c/874137a52dddab7d5d595c1887089a2125d27d0601fce8c0026a24a92a0b/scipy-1.17.0-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:eb2651271135154aa24f6481cbae5cc8af1f0dd46e6533fb7b56aa9727b6a232", size = 20552752, upload-time = "2026-01-10T21:30:05.93Z" }, - { url = "https://files.pythonhosted.org/packages/3f/f0/7518d171cb735f6400f4576cf70f756d5b419a07fe1867da34e2c2c9c11b/scipy-1.17.0-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:c5e8647f60679790c2f5c76be17e2e9247dc6b98ad0d3b065861e082c56e078d", size = 22803972, upload-time = "2026-01-10T21:30:10.651Z" }, - { url = "https://files.pythonhosted.org/packages/7c/74/3498563a2c619e8a3ebb4d75457486c249b19b5b04a30600dfd9af06bea5/scipy-1.17.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5fb10d17e649e1446410895639f3385fd2bf4c3c7dfc9bea937bddcbc3d7b9ba", size = 32829770, upload-time = "2026-01-10T21:30:16.359Z" }, - { url = "https://files.pythonhosted.org/packages/48/d1/7b50cedd8c6c9d6f706b4b36fa8544d829c712a75e370f763b318e9638c1/scipy-1.17.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8547e7c57f932e7354a2319fab613981cde910631979f74c9b542bb167a8b9db", size = 35051093, upload-time = "2026-01-10T21:30:22.987Z" }, - { url = "https://files.pythonhosted.org/packages/e2/82/a2d684dfddb87ba1b3ea325df7c3293496ee9accb3a19abe9429bce94755/scipy-1.17.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:33af70d040e8af9d5e7a38b5ed3b772adddd281e3062ff23fec49e49681c38cf", size = 34909905, upload-time = "2026-01-10T21:30:28.704Z" }, - { url = "https://files.pythonhosted.org/packages/ef/5e/e565bd73991d42023eb82bb99e51c5b3d9e2c588ca9d4b3e2cc1d3ca62a6/scipy-1.17.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb55bb97d00f8b7ab95cb64f873eb0bf54d9446264d9f3609130381233483f", size = 37457743, upload-time = "2026-01-10T21:30:34.819Z" }, - { url = "https://files.pythonhosted.org/packages/58/a8/a66a75c3d8f1fb2b83f66007d6455a06a6f6cf5618c3dc35bc9b69dd096e/scipy-1.17.0-cp314-cp314t-win_amd64.whl", hash = "sha256:1ff269abf702f6c7e67a4b7aad981d42871a11b9dd83c58d2d2ea624efbd1088", size = 37098574, upload-time = "2026-01-10T21:30:40.782Z" }, - { url = "https://files.pythonhosted.org/packages/56/a5/df8f46ef7da168f1bc52cd86e09a9de5c6f19cc1da04454d51b7d4f43408/scipy-1.17.0-cp314-cp314t-win_arm64.whl", hash = "sha256:031121914e295d9791319a1875444d55079885bbae5bdc9c5e0f2ee5f09d34ff", size = 25246266, upload-time = "2026-01-10T21:30:45.923Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0", size = 30573822, upload-time = "2026-02-23T00:26:24.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/48/b992b488d6f299dbe3f11a20b24d3dda3d46f1a635ede1c46b5b17a7b163/scipy-1.17.1-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:35c3a56d2ef83efc372eaec584314bd0ef2e2f0d2adb21c55e6ad5b344c0dcb8", size = 31610954, upload-time = "2026-02-23T00:17:49.855Z" }, + { url = "https://files.pythonhosted.org/packages/b2/02/cf107b01494c19dc100f1d0b7ac3cc08666e96ba2d64db7626066cee895e/scipy-1.17.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:fcb310ddb270a06114bb64bbe53c94926b943f5b7f0842194d585c65eb4edd76", size = 28172662, upload-time = "2026-02-23T00:18:01.64Z" }, + { url = "https://files.pythonhosted.org/packages/cf/a9/599c28631bad314d219cf9ffd40e985b24d603fc8a2f4ccc5ae8419a535b/scipy-1.17.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:cc90d2e9c7e5c7f1a482c9875007c095c3194b1cfedca3c2f3291cdc2bc7c086", size = 20344366, upload-time = "2026-02-23T00:18:12.015Z" }, + { url = "https://files.pythonhosted.org/packages/35/f5/906eda513271c8deb5af284e5ef0206d17a96239af79f9fa0aebfe0e36b4/scipy-1.17.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:c80be5ede8f3f8eded4eff73cc99a25c388ce98e555b17d31da05287015ffa5b", size = 22704017, upload-time = "2026-02-23T00:18:21.502Z" }, + { url = "https://files.pythonhosted.org/packages/da/34/16f10e3042d2f1d6b66e0428308ab52224b6a23049cb2f5c1756f713815f/scipy-1.17.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e19ebea31758fac5893a2ac360fedd00116cbb7628e650842a6691ba7ca28a21", size = 32927842, upload-time = "2026-02-23T00:18:35.367Z" }, + { url = "https://files.pythonhosted.org/packages/01/8e/1e35281b8ab6d5d72ebe9911edcdffa3f36b04ed9d51dec6dd140396e220/scipy-1.17.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:02ae3b274fde71c5e92ac4d54bc06c42d80e399fec704383dcd99b301df37458", size = 35235890, upload-time = "2026-02-23T00:18:49.188Z" }, + { url = "https://files.pythonhosted.org/packages/c5/5c/9d7f4c88bea6e0d5a4f1bc0506a53a00e9fcb198de372bfe4d3652cef482/scipy-1.17.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8a604bae87c6195d8b1045eddece0514d041604b14f2727bbc2b3020172045eb", size = 35003557, upload-time = "2026-02-23T00:18:54.74Z" }, + { url = "https://files.pythonhosted.org/packages/65/94/7698add8f276dbab7a9de9fb6b0e02fc13ee61d51c7c3f85ac28b65e1239/scipy-1.17.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f590cd684941912d10becc07325a3eeb77886fe981415660d9265c4c418d0bea", size = 37625856, upload-time = "2026-02-23T00:19:00.307Z" }, + { url = "https://files.pythonhosted.org/packages/a2/84/dc08d77fbf3d87d3ee27f6a0c6dcce1de5829a64f2eae85a0ecc1f0daa73/scipy-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:41b71f4a3a4cab9d366cd9065b288efc4d4f3c0b37a91a8e0947fb5bd7f31d87", size = 36549682, upload-time = "2026-02-23T00:19:07.67Z" }, + { url = "https://files.pythonhosted.org/packages/bc/98/fe9ae9ffb3b54b62559f52dedaebe204b408db8109a8c66fdd04869e6424/scipy-1.17.1-cp312-cp312-win_arm64.whl", hash = "sha256:f4115102802df98b2b0db3cce5cb9b92572633a1197c77b7553e5203f284a5b3", size = 24547340, upload-time = "2026-02-23T00:19:12.024Z" }, + { url = "https://files.pythonhosted.org/packages/76/27/07ee1b57b65e92645f219b37148a7e7928b82e2b5dbeccecb4dff7c64f0b/scipy-1.17.1-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:5e3c5c011904115f88a39308379c17f91546f77c1667cea98739fe0fccea804c", size = 31590199, upload-time = "2026-02-23T00:19:17.192Z" }, + { url = "https://files.pythonhosted.org/packages/ec/ae/db19f8ab842e9b724bf5dbb7db29302a91f1e55bc4d04b1025d6d605a2c5/scipy-1.17.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:6fac755ca3d2c3edcb22f479fceaa241704111414831ddd3bc6056e18516892f", size = 28154001, upload-time = "2026-02-23T00:19:22.241Z" }, + { url = "https://files.pythonhosted.org/packages/5b/58/3ce96251560107b381cbd6e8413c483bbb1228a6b919fa8652b0d4090e7f/scipy-1.17.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:7ff200bf9d24f2e4d5dc6ee8c3ac64d739d3a89e2326ba68aaf6c4a2b838fd7d", size = 20325719, upload-time = "2026-02-23T00:19:26.329Z" }, + { url = "https://files.pythonhosted.org/packages/b2/83/15087d945e0e4d48ce2377498abf5ad171ae013232ae31d06f336e64c999/scipy-1.17.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:4b400bdc6f79fa02a4d86640310dde87a21fba0c979efff5248908c6f15fad1b", size = 22683595, upload-time = "2026-02-23T00:19:30.304Z" }, + { url = "https://files.pythonhosted.org/packages/b4/e0/e58fbde4a1a594c8be8114eb4aac1a55bcd6587047efc18a61eb1f5c0d30/scipy-1.17.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b64ca7d4aee0102a97f3ba22124052b4bd2152522355073580bf4845e2550b6", size = 32896429, upload-time = "2026-02-23T00:19:35.536Z" }, + { url = "https://files.pythonhosted.org/packages/f5/5f/f17563f28ff03c7b6799c50d01d5d856a1d55f2676f537ca8d28c7f627cd/scipy-1.17.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:581b2264fc0aa555f3f435a5944da7504ea3a065d7029ad60e7c3d1ae09c5464", size = 35203952, upload-time = "2026-02-23T00:19:42.259Z" }, + { url = "https://files.pythonhosted.org/packages/8d/a5/9afd17de24f657fdfe4df9a3f1ea049b39aef7c06000c13db1530d81ccca/scipy-1.17.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:beeda3d4ae615106d7094f7e7cef6218392e4465cc95d25f900bebabfded0950", size = 34979063, upload-time = "2026-02-23T00:19:47.547Z" }, + { url = "https://files.pythonhosted.org/packages/8b/13/88b1d2384b424bf7c924f2038c1c409f8d88bb2a8d49d097861dd64a57b2/scipy-1.17.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6609bc224e9568f65064cfa72edc0f24ee6655b47575954ec6339534b2798369", size = 37598449, upload-time = "2026-02-23T00:19:53.238Z" }, + { url = "https://files.pythonhosted.org/packages/35/e5/d6d0e51fc888f692a35134336866341c08655d92614f492c6860dc45bb2c/scipy-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:37425bc9175607b0268f493d79a292c39f9d001a357bebb6b88fdfaff13f6448", size = 36510943, upload-time = "2026-02-23T00:20:50.89Z" }, + { url = "https://files.pythonhosted.org/packages/2a/fd/3be73c564e2a01e690e19cc618811540ba5354c67c8680dce3281123fb79/scipy-1.17.1-cp313-cp313-win_arm64.whl", hash = "sha256:5cf36e801231b6a2059bf354720274b7558746f3b1a4efb43fcf557ccd484a87", size = 24545621, upload-time = "2026-02-23T00:20:55.871Z" }, + { url = "https://files.pythonhosted.org/packages/6f/6b/17787db8b8114933a66f9dcc479a8272e4b4da75fe03b0c282f7b0ade8cd/scipy-1.17.1-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:d59c30000a16d8edc7e64152e30220bfbd724c9bbb08368c054e24c651314f0a", size = 31936708, upload-time = "2026-02-23T00:19:58.694Z" }, + { url = "https://files.pythonhosted.org/packages/38/2e/524405c2b6392765ab1e2b722a41d5da33dc5c7b7278184a8ad29b6cb206/scipy-1.17.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:010f4333c96c9bb1a4516269e33cb5917b08ef2166d5556ca2fd9f082a9e6ea0", size = 28570135, upload-time = "2026-02-23T00:20:03.934Z" }, + { url = "https://files.pythonhosted.org/packages/fd/c3/5bd7199f4ea8556c0c8e39f04ccb014ac37d1468e6cfa6a95c6b3562b76e/scipy-1.17.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:2ceb2d3e01c5f1d83c4189737a42d9cb2fc38a6eeed225e7515eef71ad301dce", size = 20741977, upload-time = "2026-02-23T00:20:07.935Z" }, + { url = "https://files.pythonhosted.org/packages/d9/b8/8ccd9b766ad14c78386599708eb745f6b44f08400a5fd0ade7cf89b6fc93/scipy-1.17.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:844e165636711ef41f80b4103ed234181646b98a53c8f05da12ca5ca289134f6", size = 23029601, upload-time = "2026-02-23T00:20:12.161Z" }, + { url = "https://files.pythonhosted.org/packages/6d/a0/3cb6f4d2fb3e17428ad2880333cac878909ad1a89f678527b5328b93c1d4/scipy-1.17.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:158dd96d2207e21c966063e1635b1063cd7787b627b6f07305315dd73d9c679e", size = 33019667, upload-time = "2026-02-23T00:20:17.208Z" }, + { url = "https://files.pythonhosted.org/packages/f3/c3/2d834a5ac7bf3a0c806ad1508efc02dda3c8c61472a56132d7894c312dea/scipy-1.17.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:74cbb80d93260fe2ffa334efa24cb8f2f0f622a9b9febf8b483c0b865bfb3475", size = 35264159, upload-time = "2026-02-23T00:20:23.087Z" }, + { url = "https://files.pythonhosted.org/packages/4d/77/d3ed4becfdbd217c52062fafe35a72388d1bd82c2d0ba5ca19d6fcc93e11/scipy-1.17.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:dbc12c9f3d185f5c737d801da555fb74b3dcfa1a50b66a1a93e09190f41fab50", size = 35102771, upload-time = "2026-02-23T00:20:28.636Z" }, + { url = "https://files.pythonhosted.org/packages/bd/12/d19da97efde68ca1ee5538bb261d5d2c062f0c055575128f11a2730e3ac1/scipy-1.17.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:94055a11dfebe37c656e70317e1996dc197e1a15bbcc351bcdd4610e128fe1ca", size = 37665910, upload-time = "2026-02-23T00:20:34.743Z" }, + { url = "https://files.pythonhosted.org/packages/06/1c/1172a88d507a4baaf72c5a09bb6c018fe2ae0ab622e5830b703a46cc9e44/scipy-1.17.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e30bdeaa5deed6bc27b4cc490823cd0347d7dae09119b8803ae576ea0ce52e4c", size = 36562980, upload-time = "2026-02-23T00:20:40.575Z" }, + { url = "https://files.pythonhosted.org/packages/70/b0/eb757336e5a76dfa7911f63252e3b7d1de00935d7705cf772db5b45ec238/scipy-1.17.1-cp313-cp313t-win_arm64.whl", hash = "sha256:a720477885a9d2411f94a93d16f9d89bad0f28ca23c3f8daa521e2dcc3f44d49", size = 24856543, upload-time = "2026-02-23T00:20:45.313Z" }, + { url = "https://files.pythonhosted.org/packages/cf/83/333afb452af6f0fd70414dc04f898647ee1423979ce02efa75c3b0f2c28e/scipy-1.17.1-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:a48a72c77a310327f6a3a920092fa2b8fd03d7deaa60f093038f22d98e096717", size = 31584510, upload-time = "2026-02-23T00:21:01.015Z" }, + { url = "https://files.pythonhosted.org/packages/ed/a6/d05a85fd51daeb2e4ea71d102f15b34fedca8e931af02594193ae4fd25f7/scipy-1.17.1-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:45abad819184f07240d8a696117a7aacd39787af9e0b719d00285549ed19a1e9", size = 28170131, upload-time = "2026-02-23T00:21:05.888Z" }, + { url = "https://files.pythonhosted.org/packages/db/7b/8624a203326675d7746a254083a187398090a179335b2e4a20e2ddc46e83/scipy-1.17.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:3fd1fcdab3ea951b610dc4cef356d416d5802991e7e32b5254828d342f7b7e0b", size = 20342032, upload-time = "2026-02-23T00:21:09.904Z" }, + { url = "https://files.pythonhosted.org/packages/c9/35/2c342897c00775d688d8ff3987aced3426858fd89d5a0e26e020b660b301/scipy-1.17.1-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:7bdf2da170b67fdf10bca777614b1c7d96ae3ca5794fd9587dce41eb2966e866", size = 22678766, upload-time = "2026-02-23T00:21:14.313Z" }, + { url = "https://files.pythonhosted.org/packages/ef/f2/7cdb8eb308a1a6ae1e19f945913c82c23c0c442a462a46480ce487fdc0ac/scipy-1.17.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:adb2642e060a6549c343603a3851ba76ef0b74cc8c079a9a58121c7ec9fe2350", size = 32957007, upload-time = "2026-02-23T00:21:19.663Z" }, + { url = "https://files.pythonhosted.org/packages/0b/2e/7eea398450457ecb54e18e9d10110993fa65561c4f3add5e8eccd2b9cd41/scipy-1.17.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eee2cfda04c00a857206a4330f0c5e3e56535494e30ca445eb19ec624ae75118", size = 35221333, upload-time = "2026-02-23T00:21:25.278Z" }, + { url = "https://files.pythonhosted.org/packages/d9/77/5b8509d03b77f093a0d52e606d3c4f79e8b06d1d38c441dacb1e26cacf46/scipy-1.17.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d2650c1fb97e184d12d8ba010493ee7b322864f7d3d00d3f9bb97d9c21de4068", size = 35042066, upload-time = "2026-02-23T00:21:31.358Z" }, + { url = "https://files.pythonhosted.org/packages/f9/df/18f80fb99df40b4070328d5ae5c596f2f00fffb50167e31439e932f29e7d/scipy-1.17.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:08b900519463543aa604a06bec02461558a6e1cef8fdbb8098f77a48a83c8118", size = 37612763, upload-time = "2026-02-23T00:21:37.247Z" }, + { url = "https://files.pythonhosted.org/packages/4b/39/f0e8ea762a764a9dc52aa7dabcfad51a354819de1f0d4652b6a1122424d6/scipy-1.17.1-cp314-cp314-win_amd64.whl", hash = "sha256:3877ac408e14da24a6196de0ddcace62092bfc12a83823e92e49e40747e52c19", size = 37290984, upload-time = "2026-02-23T00:22:35.023Z" }, + { url = "https://files.pythonhosted.org/packages/7c/56/fe201e3b0f93d1a8bcf75d3379affd228a63d7e2d80ab45467a74b494947/scipy-1.17.1-cp314-cp314-win_arm64.whl", hash = "sha256:f8885db0bc2bffa59d5c1b72fad7a6a92d3e80e7257f967dd81abb553a90d293", size = 25192877, upload-time = "2026-02-23T00:22:39.798Z" }, + { url = "https://files.pythonhosted.org/packages/96/ad/f8c414e121f82e02d76f310f16db9899c4fcde36710329502a6b2a3c0392/scipy-1.17.1-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:1cc682cea2ae55524432f3cdff9e9a3be743d52a7443d0cba9017c23c87ae2f6", size = 31949750, upload-time = "2026-02-23T00:21:42.289Z" }, + { url = "https://files.pythonhosted.org/packages/7c/b0/c741e8865d61b67c81e255f4f0a832846c064e426636cd7de84e74d209be/scipy-1.17.1-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:2040ad4d1795a0ae89bfc7e8429677f365d45aa9fd5e4587cf1ea737f927b4a1", size = 28585858, upload-time = "2026-02-23T00:21:47.706Z" }, + { url = "https://files.pythonhosted.org/packages/ed/1b/3985219c6177866628fa7c2595bfd23f193ceebbe472c98a08824b9466ff/scipy-1.17.1-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:131f5aaea57602008f9822e2115029b55d4b5f7c070287699fe45c661d051e39", size = 20757723, upload-time = "2026-02-23T00:21:52.039Z" }, + { url = "https://files.pythonhosted.org/packages/c0/19/2a04aa25050d656d6f7b9e7b685cc83d6957fb101665bfd9369ca6534563/scipy-1.17.1-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:9cdc1a2fcfd5c52cfb3045feb399f7b3ce822abdde3a193a6b9a60b3cb5854ca", size = 23043098, upload-time = "2026-02-23T00:21:56.185Z" }, + { url = "https://files.pythonhosted.org/packages/86/f1/3383beb9b5d0dbddd030335bf8a8b32d4317185efe495374f134d8be6cce/scipy-1.17.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e3dcd57ab780c741fde8dc68619de988b966db759a3c3152e8e9142c26295ad", size = 33030397, upload-time = "2026-02-23T00:22:01.404Z" }, + { url = "https://files.pythonhosted.org/packages/41/68/8f21e8a65a5a03f25a79165ec9d2b28c00e66dc80546cf5eb803aeeff35b/scipy-1.17.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a9956e4d4f4a301ebf6cde39850333a6b6110799d470dbbb1e25326ac447f52a", size = 35281163, upload-time = "2026-02-23T00:22:07.024Z" }, + { url = "https://files.pythonhosted.org/packages/84/8d/c8a5e19479554007a5632ed7529e665c315ae7492b4f946b0deb39870e39/scipy-1.17.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a4328d245944d09fd639771de275701ccadf5f781ba0ff092ad141e017eccda4", size = 35116291, upload-time = "2026-02-23T00:22:12.585Z" }, + { url = "https://files.pythonhosted.org/packages/52/52/e57eceff0e342a1f50e274264ed47497b59e6a4e3118808ee58ddda7b74a/scipy-1.17.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a77cbd07b940d326d39a1d1b37817e2ee4d79cb30e7338f3d0cddffae70fcaa2", size = 37682317, upload-time = "2026-02-23T00:22:18.513Z" }, + { url = "https://files.pythonhosted.org/packages/11/2f/b29eafe4a3fbc3d6de9662b36e028d5f039e72d345e05c250e121a230dd4/scipy-1.17.1-cp314-cp314t-win_amd64.whl", hash = "sha256:eb092099205ef62cd1782b006658db09e2fed75bffcae7cc0d44052d8aa0f484", size = 37345327, upload-time = "2026-02-23T00:22:24.442Z" }, + { url = "https://files.pythonhosted.org/packages/07/39/338d9219c4e87f3e708f18857ecd24d22a0c3094752393319553096b98af/scipy-1.17.1-cp314-cp314t-win_arm64.whl", hash = "sha256:200e1050faffacc162be6a486a984a0497866ec54149a01270adc8a59b7c7d21", size = 25489165, upload-time = "2026-02-23T00:22:29.563Z" }, ] [[package]] @@ -1613,15 +1678,15 @@ wheels = [ [[package]] name = "sphinx-book-theme" -version = "1.1.4" +version = "1.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydata-sphinx-theme" }, { name = "sphinx" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/45/19/d002ed96bdc7738c15847c730e1e88282d738263deac705d5713b4d8fa94/sphinx_book_theme-1.1.4.tar.gz", hash = "sha256:73efe28af871d0a89bd05856d300e61edce0d5b2fbb7984e84454be0fedfe9ed", size = 439188, upload-time = "2025-02-20T16:32:32.581Z" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/f7/154786f3cfb7692cd7acc24b6dfe4dcd1146b66f376b17df9e47125555e9/sphinx_book_theme-1.2.0.tar.gz", hash = "sha256:4a7ebfc7da4395309ac942ddfc38fbec5c5254c3be22195e99ad12586fbda9e3", size = 443962, upload-time = "2026-03-09T23:20:30.442Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/51/9e/c41d68be04eef5b6202b468e0f90faf0c469f3a03353f2a218fd78279710/sphinx_book_theme-1.1.4-py3-none-any.whl", hash = "sha256:843b3f5c8684640f4a2d01abd298beb66452d1b2394cd9ef5be5ebd5640ea0e1", size = 433952, upload-time = "2025-02-20T16:32:31.009Z" }, + { url = "https://files.pythonhosted.org/packages/02/bf/6f506a37c7f8ecc4576caf9486e303c7af249f6d70447bb51dde9d78cb99/sphinx_book_theme-1.2.0-py3-none-any.whl", hash = "sha256:709605d308e1991c5ef0cf19c481dbe9084b62852e317fafab74382a0ee7ccfa", size = 455936, upload-time = "2026-03-09T23:20:28.788Z" }, ] [[package]] @@ -1677,16 +1742,16 @@ wheels = [ [[package]] name = "sphinxcontrib-mermaid" -version = "2.0.0" +version = "2.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jinja2" }, { name = "pyyaml" }, { name = "sphinx" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/96/a5/65a5c439cc14ba80483b9891e9350f11efb80cd3bdccb222f0c738068c78/sphinxcontrib_mermaid-2.0.0.tar.gz", hash = "sha256:cf4f7d453d001132eaba5d1fdf53d42049f02e913213cf8337427483bfca26f4", size = 18194, upload-time = "2026-01-13T17:13:42.563Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2b/ae/999891de292919b66ea34f2c22fc22c9be90ab3536fbc0fca95716277351/sphinxcontrib_mermaid-2.0.1.tar.gz", hash = "sha256:a21a385a059a6cafd192aa3a586b14bf5c42721e229db67b459dc825d7f0a497", size = 19839, upload-time = "2026-03-05T14:10:41.901Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/de/bd96c69b62e967bffd02c6d89dfca9471b04e761c466725fc39746abf41d/sphinxcontrib_mermaid-2.0.0-py3-none-any.whl", hash = "sha256:59a73249bbee2c74b1a4db036f8e8899ade65982bdda6712cf22b4f4e9874bb5", size = 14055, upload-time = "2026-01-13T17:13:41.481Z" }, + { url = "https://files.pythonhosted.org/packages/03/46/25d64bcd7821c8d6f1080e1c43d5fcdfc442a18f759a230b5ccdc891093e/sphinxcontrib_mermaid-2.0.1-py3-none-any.whl", hash = "sha256:9dca7fbe827bad5e7e2b97c4047682cfd26e3e07398cfdc96c7a8842ae7f06e7", size = 14064, upload-time = "2026-03-05T14:10:40.533Z" }, ] [[package]] @@ -1709,11 +1774,11 @@ wheels = [ [[package]] name = "tabulate" -version = "0.9.0" +version = "0.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ec/fe/802052aecb21e3797b8f7902564ab6ea0d60ff8ca23952079064155d1ae1/tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c", size = 81090, upload-time = "2022-10-06T17:21:48.54Z" } +sdist = { url = "https://files.pythonhosted.org/packages/46/58/8c37dea7bbf769b20d58e7ace7e5edfe65b849442b00ffcdd56be88697c6/tabulate-0.10.0.tar.gz", hash = "sha256:e2cfde8f79420f6deeffdeda9aaec3b6bc5abce947655d17ac662b126e48a60d", size = 91754, upload-time = "2026-03-04T18:55:34.402Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f", size = 35252, upload-time = "2022-10-06T17:21:44.262Z" }, + { url = "https://files.pythonhosted.org/packages/99/55/db07de81b5c630da5cbf5c7df646580ca26dfaefa593667fc6f2fe016d2e/tabulate-0.10.0-py3-none-any.whl", hash = "sha256:f0b0622e567335c8fabaaa659f1b33bcb6ddfe2e496071b743aa113f8774f2d3", size = 39814, upload-time = "2026-03-04T18:55:31.284Z" }, ] [[package]] @@ -1832,47 +1897,38 @@ wheels = [ [[package]] name = "typer" -version = "0.21.1" +version = "0.24.1" source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "annotated-doc" }, { name = "click" }, { name = "rich" }, { name = "shellingham" }, - { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/36/bf/8825b5929afd84d0dabd606c67cd57b8388cb3ec385f7ef19c5cc2202069/typer-0.21.1.tar.gz", hash = "sha256:ea835607cd752343b6b2b7ce676893e5a0324082268b48f27aa058bdb7d2145d", size = 110371, upload-time = "2026-01-06T11:21:10.989Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f5/24/cb09efec5cc954f7f9b930bf8279447d24618bb6758d4f6adf2574c41780/typer-0.24.1.tar.gz", hash = "sha256:e39b4732d65fbdcde189ae76cf7cd48aeae72919dea1fdfc16593be016256b45", size = 118613, upload-time = "2026-02-21T16:54:40.609Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/1d/d9257dd49ff2ca23ea5f132edf1281a0c4f9de8a762b9ae399b670a59235/typer-0.21.1-py3-none-any.whl", hash = "sha256:7985e89081c636b88d172c2ee0cfe33c253160994d47bdfdc302defd7d1f1d01", size = 47381, upload-time = "2026-01-06T11:21:09.824Z" }, + { url = "https://files.pythonhosted.org/packages/4a/91/48db081e7a63bb37284f9fbcefda7c44c277b18b0e13fbc36ea2335b71e6/typer-0.24.1-py3-none-any.whl", hash = "sha256:112c1f0ce578bfb4cab9ffdabc68f031416ebcc216536611ba21f04e9aa84c9e", size = 56085, upload-time = "2026-02-21T16:54:41.616Z" }, ] [[package]] name = "types-deprecated" -version = "1.3.1.20251101" +version = "1.3.1.20260130" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c6/96/0f96107945697e452c56a2e9f575da627e61d67940e5913d9c968e5e8be1/types_deprecated-1.3.1.20251101.tar.gz", hash = "sha256:f002d266b73201f46ec6fc712c1f016067ec6cb44357559cdb50c86b010951a7", size = 8358, upload-time = "2025-11-01T03:04:05.6Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/97/9924e496f88412788c432891cacd041e542425fe0bffff4143a7c1c89ac4/types_deprecated-1.3.1.20260130.tar.gz", hash = "sha256:726b05e5e66d42359b1d6631835b15de62702588c8a59b877aa4b1e138453450", size = 8455, upload-time = "2026-01-30T03:58:17.401Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/50/fb191dba89031e30c9ea07c3133c6fe8e7da038ef4d0b79539cf85fb1a97/types_deprecated-1.3.1.20251101-py3-none-any.whl", hash = "sha256:274edcc2a084d3fe31802d3c1379abd630716d3db34e40577e12ad84d6b73134", size = 9057, upload-time = "2025-11-01T03:04:04.633Z" }, + { url = "https://files.pythonhosted.org/packages/d2/b2/6f920582af7efcd37165cd6321707f3ad5839dd24565a8a982f2bd9c6fd1/types_deprecated-1.3.1.20260130-py3-none-any.whl", hash = "sha256:593934d85c38ca321a9d301f00c42ffe13e4cf830b71b10579185ba0ce172d9a", size = 9077, upload-time = "2026-01-30T03:58:16.633Z" }, ] [[package]] name = "types-networkx" -version = "3.6.1.20251220" +version = "3.6.1.20260303" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/07/e3/dcc20d645dc0631b0df263959b8dde49dc47ad3c0537d8958bfefe692380/types_networkx-3.6.1.20251220.tar.gz", hash = "sha256:caf95e0d7777b969e50ceeb2c430d9d4dfe6b7bdee43c42dc9879a2d4408a790", size = 73500, upload-time = "2025-12-20T03:07:47.933Z" } +sdist = { url = "https://files.pythonhosted.org/packages/78/37/d8f7a68a5291cab793e27967d187abbf0c6db318d49e5b6e9dd32b13c2e5/types_networkx-3.6.1.20260303.tar.gz", hash = "sha256:8248aa6fcadc08bd7992af6e412bfc5cfa043bda5ce7ab407fa591c808ce8557", size = 73790, upload-time = "2026-03-03T04:03:46.201Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/65/e7/fe40cfe7ba384d1f46fee835eb7727a4ee2fd80021a69add9553197b69a1/types_networkx-3.6.1.20251220-py3-none-any.whl", hash = "sha256:417ccbe7841f335a4c2b8e7515c3bc97a00fb5f686f399a763ef64392b209eac", size = 162715, upload-time = "2025-12-20T03:07:46.882Z" }, -] - -[[package]] -name = "types-pytz" -version = "2025.2.0.20251108" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/40/ff/c047ddc68c803b46470a357454ef76f4acd8c1088f5cc4891cdd909bfcf6/types_pytz-2025.2.0.20251108.tar.gz", hash = "sha256:fca87917836ae843f07129567b74c1929f1870610681b4c92cb86a3df5817bdb", size = 10961, upload-time = "2025-11-08T02:55:57.001Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/c1/56ef16bf5dcd255155cc736d276efa6ae0a5c26fd685e28f0412a4013c01/types_pytz-2025.2.0.20251108-py3-none-any.whl", hash = "sha256:0f1c9792cab4eb0e46c52f8845c8f77cf1e313cb3d68bf826aa867fe4717d91c", size = 10116, upload-time = "2025-11-08T02:55:56.194Z" }, + { url = "https://files.pythonhosted.org/packages/f2/b7/eedcba86c567832699eb242709e8951c0df2b6658beb5f931e954292bcda/types_networkx-3.6.1.20260303-py3-none-any.whl", hash = "sha256:754c7c7bcaab3c317b0b86441240c0a5bd0d2f419aba80a88e9718248a5c89af", size = 162680, upload-time = "2026-03-03T04:03:44.081Z" }, ] [[package]] @@ -1904,85 +1960,81 @@ wheels = [ [[package]] name = "virtualenv" -version = "20.36.1" +version = "21.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, { name = "filelock" }, { name = "platformdirs" }, + { name = "python-discovery" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/aa/a3/4d310fa5f00863544e1d0f4de93bddec248499ccf97d4791bc3122c9d4f3/virtualenv-20.36.1.tar.gz", hash = "sha256:8befb5c81842c641f8ee658481e42641c68b5eab3521d8e092d18320902466ba", size = 6032239, upload-time = "2026-01-09T18:21:01.296Z" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/92/58199fe10049f9703c2666e809c4f686c54ef0a68b0f6afccf518c0b1eb9/virtualenv-21.2.0.tar.gz", hash = "sha256:1720dc3a62ef5b443092e3f499228599045d7fea4c79199770499df8becf9098", size = 5840618, upload-time = "2026-03-09T17:24:38.013Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/2a/dc2228b2888f51192c7dc766106cd475f1b768c10caaf9727659726f7391/virtualenv-20.36.1-py3-none-any.whl", hash = "sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f", size = 6008258, upload-time = "2026-01-09T18:20:59.425Z" }, + { url = "https://files.pythonhosted.org/packages/c6/59/7d02447a55b2e55755011a647479041bc92a82e143f96a8195cb33bd0a1c/virtualenv-21.2.0-py3-none-any.whl", hash = "sha256:1bd755b504931164a5a496d217c014d098426cddc79363ad66ac78125f9d908f", size = 5825084, upload-time = "2026-03-09T17:24:35.378Z" }, ] [[package]] name = "wrapt" -version = "2.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/2a/6de8a50cb435b7f42c46126cf1a54b2aab81784e74c8595c8e025e8f36d3/wrapt-2.0.1.tar.gz", hash = "sha256:9c9c635e78497cacb81e84f8b11b23e0aacac7a136e73b8e5b2109a1d9fc468f", size = 82040, upload-time = "2025-11-07T00:45:33.312Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/73/8cb252858dc8254baa0ce58ce382858e3a1cf616acebc497cb13374c95c6/wrapt-2.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1fdbb34da15450f2b1d735a0e969c24bdb8d8924892380126e2a293d9902078c", size = 78129, upload-time = "2025-11-07T00:43:48.852Z" }, - { url = "https://files.pythonhosted.org/packages/19/42/44a0db2108526ee6e17a5ab72478061158f34b08b793df251d9fbb9a7eb4/wrapt-2.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3d32794fe940b7000f0519904e247f902f0149edbe6316c710a8562fb6738841", size = 61205, upload-time = "2025-11-07T00:43:50.402Z" }, - { url = "https://files.pythonhosted.org/packages/4d/8a/5b4b1e44b791c22046e90d9b175f9a7581a8cc7a0debbb930f81e6ae8e25/wrapt-2.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:386fb54d9cd903ee0012c09291336469eb7b244f7183d40dc3e86a16a4bace62", size = 61692, upload-time = "2025-11-07T00:43:51.678Z" }, - { url = "https://files.pythonhosted.org/packages/11/53/3e794346c39f462bcf1f58ac0487ff9bdad02f9b6d5ee2dc84c72e0243b2/wrapt-2.0.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7b219cb2182f230676308cdcacd428fa837987b89e4b7c5c9025088b8a6c9faf", size = 121492, upload-time = "2025-11-07T00:43:55.017Z" }, - { url = "https://files.pythonhosted.org/packages/c6/7e/10b7b0e8841e684c8ca76b462a9091c45d62e8f2de9c4b1390b690eadf16/wrapt-2.0.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:641e94e789b5f6b4822bb8d8ebbdfc10f4e4eae7756d648b717d980f657a9eb9", size = 123064, upload-time = "2025-11-07T00:43:56.323Z" }, - { url = "https://files.pythonhosted.org/packages/0e/d1/3c1e4321fc2f5ee7fd866b2d822aa89b84495f28676fd976c47327c5b6aa/wrapt-2.0.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fe21b118b9f58859b5ebaa4b130dee18669df4bd111daad082b7beb8799ad16b", size = 117403, upload-time = "2025-11-07T00:43:53.258Z" }, - { url = "https://files.pythonhosted.org/packages/a4/b0/d2f0a413cf201c8c2466de08414a15420a25aa83f53e647b7255cc2fab5d/wrapt-2.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:17fb85fa4abc26a5184d93b3efd2dcc14deb4b09edcdb3535a536ad34f0b4dba", size = 121500, upload-time = "2025-11-07T00:43:57.468Z" }, - { url = "https://files.pythonhosted.org/packages/bd/45/bddb11d28ca39970a41ed48a26d210505120f925918592283369219f83cc/wrapt-2.0.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:b89ef9223d665ab255ae42cc282d27d69704d94be0deffc8b9d919179a609684", size = 116299, upload-time = "2025-11-07T00:43:58.877Z" }, - { url = "https://files.pythonhosted.org/packages/81/af/34ba6dd570ef7a534e7eec0c25e2615c355602c52aba59413411c025a0cb/wrapt-2.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a453257f19c31b31ba593c30d997d6e5be39e3b5ad9148c2af5a7314061c63eb", size = 120622, upload-time = "2025-11-07T00:43:59.962Z" }, - { url = "https://files.pythonhosted.org/packages/e2/3e/693a13b4146646fb03254636f8bafd20c621955d27d65b15de07ab886187/wrapt-2.0.1-cp312-cp312-win32.whl", hash = "sha256:3e271346f01e9c8b1130a6a3b0e11908049fe5be2d365a5f402778049147e7e9", size = 58246, upload-time = "2025-11-07T00:44:03.169Z" }, - { url = "https://files.pythonhosted.org/packages/a7/36/715ec5076f925a6be95f37917b66ebbeaa1372d1862c2ccd7a751574b068/wrapt-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:2da620b31a90cdefa9cd0c2b661882329e2e19d1d7b9b920189956b76c564d75", size = 60492, upload-time = "2025-11-07T00:44:01.027Z" }, - { url = "https://files.pythonhosted.org/packages/ef/3e/62451cd7d80f65cc125f2b426b25fbb6c514bf6f7011a0c3904fc8c8df90/wrapt-2.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:aea9c7224c302bc8bfc892b908537f56c430802560e827b75ecbde81b604598b", size = 58987, upload-time = "2025-11-07T00:44:02.095Z" }, - { url = "https://files.pythonhosted.org/packages/ad/fe/41af4c46b5e498c90fc87981ab2972fbd9f0bccda597adb99d3d3441b94b/wrapt-2.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:47b0f8bafe90f7736151f61482c583c86b0693d80f075a58701dd1549b0010a9", size = 78132, upload-time = "2025-11-07T00:44:04.628Z" }, - { url = "https://files.pythonhosted.org/packages/1c/92/d68895a984a5ebbbfb175512b0c0aad872354a4a2484fbd5552e9f275316/wrapt-2.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:cbeb0971e13b4bd81d34169ed57a6dda017328d1a22b62fda45e1d21dd06148f", size = 61211, upload-time = "2025-11-07T00:44:05.626Z" }, - { url = "https://files.pythonhosted.org/packages/e8/26/ba83dc5ae7cf5aa2b02364a3d9cf74374b86169906a1f3ade9a2d03cf21c/wrapt-2.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb7cffe572ad0a141a7886a1d2efa5bef0bf7fe021deeea76b3ab334d2c38218", size = 61689, upload-time = "2025-11-07T00:44:06.719Z" }, - { url = "https://files.pythonhosted.org/packages/cf/67/d7a7c276d874e5d26738c22444d466a3a64ed541f6ef35f740dbd865bab4/wrapt-2.0.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c8d60527d1ecfc131426b10d93ab5d53e08a09c5fa0175f6b21b3252080c70a9", size = 121502, upload-time = "2025-11-07T00:44:09.557Z" }, - { url = "https://files.pythonhosted.org/packages/0f/6b/806dbf6dd9579556aab22fc92908a876636e250f063f71548a8660382184/wrapt-2.0.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c654eafb01afac55246053d67a4b9a984a3567c3808bb7df2f8de1c1caba2e1c", size = 123110, upload-time = "2025-11-07T00:44:10.64Z" }, - { url = "https://files.pythonhosted.org/packages/e5/08/cdbb965fbe4c02c5233d185d070cabed2ecc1f1e47662854f95d77613f57/wrapt-2.0.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:98d873ed6c8b4ee2418f7afce666751854d6d03e3c0ec2a399bb039cd2ae89db", size = 117434, upload-time = "2025-11-07T00:44:08.138Z" }, - { url = "https://files.pythonhosted.org/packages/2d/d1/6aae2ce39db4cb5216302fa2e9577ad74424dfbe315bd6669725569e048c/wrapt-2.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c9e850f5b7fc67af856ff054c71690d54fa940c3ef74209ad9f935b4f66a0233", size = 121533, upload-time = "2025-11-07T00:44:12.142Z" }, - { url = "https://files.pythonhosted.org/packages/79/35/565abf57559fbe0a9155c29879ff43ce8bd28d2ca61033a3a3dd67b70794/wrapt-2.0.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e505629359cb5f751e16e30cf3f91a1d3ddb4552480c205947da415d597f7ac2", size = 116324, upload-time = "2025-11-07T00:44:13.28Z" }, - { url = "https://files.pythonhosted.org/packages/e1/e0/53ff5e76587822ee33e560ad55876d858e384158272cd9947abdd4ad42ca/wrapt-2.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2879af909312d0baf35f08edeea918ee3af7ab57c37fe47cb6a373c9f2749c7b", size = 120627, upload-time = "2025-11-07T00:44:14.431Z" }, - { url = "https://files.pythonhosted.org/packages/7c/7b/38df30fd629fbd7612c407643c63e80e1c60bcc982e30ceeae163a9800e7/wrapt-2.0.1-cp313-cp313-win32.whl", hash = "sha256:d67956c676be5a24102c7407a71f4126d30de2a569a1c7871c9f3cabc94225d7", size = 58252, upload-time = "2025-11-07T00:44:17.814Z" }, - { url = "https://files.pythonhosted.org/packages/85/64/d3954e836ea67c4d3ad5285e5c8fd9d362fd0a189a2db622df457b0f4f6a/wrapt-2.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:9ca66b38dd642bf90c59b6738af8070747b610115a39af2498535f62b5cdc1c3", size = 60500, upload-time = "2025-11-07T00:44:15.561Z" }, - { url = "https://files.pythonhosted.org/packages/89/4e/3c8b99ac93527cfab7f116089db120fef16aac96e5f6cdb724ddf286086d/wrapt-2.0.1-cp313-cp313-win_arm64.whl", hash = "sha256:5a4939eae35db6b6cec8e7aa0e833dcca0acad8231672c26c2a9ab7a0f8ac9c8", size = 58993, upload-time = "2025-11-07T00:44:16.65Z" }, - { url = "https://files.pythonhosted.org/packages/f9/f4/eff2b7d711cae20d220780b9300faa05558660afb93f2ff5db61fe725b9a/wrapt-2.0.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a52f93d95c8d38fed0669da2ebdb0b0376e895d84596a976c15a9eb45e3eccb3", size = 82028, upload-time = "2025-11-07T00:44:18.944Z" }, - { url = "https://files.pythonhosted.org/packages/0c/67/cb945563f66fd0f61a999339460d950f4735c69f18f0a87ca586319b1778/wrapt-2.0.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4e54bbf554ee29fcceee24fa41c4d091398b911da6e7f5d7bffda963c9aed2e1", size = 62949, upload-time = "2025-11-07T00:44:20.074Z" }, - { url = "https://files.pythonhosted.org/packages/ec/ca/f63e177f0bbe1e5cf5e8d9b74a286537cd709724384ff20860f8f6065904/wrapt-2.0.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:908f8c6c71557f4deaa280f55d0728c3bca0960e8c3dd5ceeeafb3c19942719d", size = 63681, upload-time = "2025-11-07T00:44:21.345Z" }, - { url = "https://files.pythonhosted.org/packages/39/a1/1b88fcd21fd835dca48b556daef750952e917a2794fa20c025489e2e1f0f/wrapt-2.0.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e2f84e9af2060e3904a32cea9bb6db23ce3f91cfd90c6b426757cf7cc01c45c7", size = 152696, upload-time = "2025-11-07T00:44:24.318Z" }, - { url = "https://files.pythonhosted.org/packages/62/1c/d9185500c1960d9f5f77b9c0b890b7fc62282b53af7ad1b6bd779157f714/wrapt-2.0.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e3612dc06b436968dfb9142c62e5dfa9eb5924f91120b3c8ff501ad878f90eb3", size = 158859, upload-time = "2025-11-07T00:44:25.494Z" }, - { url = "https://files.pythonhosted.org/packages/91/60/5d796ed0f481ec003220c7878a1d6894652efe089853a208ea0838c13086/wrapt-2.0.1-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6d2d947d266d99a1477cd005b23cbd09465276e302515e122df56bb9511aca1b", size = 146068, upload-time = "2025-11-07T00:44:22.81Z" }, - { url = "https://files.pythonhosted.org/packages/04/f8/75282dd72f102ddbfba137e1e15ecba47b40acff32c08ae97edbf53f469e/wrapt-2.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:7d539241e87b650cbc4c3ac9f32c8d1ac8a54e510f6dca3f6ab60dcfd48c9b10", size = 155724, upload-time = "2025-11-07T00:44:26.634Z" }, - { url = "https://files.pythonhosted.org/packages/5a/27/fe39c51d1b344caebb4a6a9372157bdb8d25b194b3561b52c8ffc40ac7d1/wrapt-2.0.1-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:4811e15d88ee62dbf5c77f2c3ff3932b1e3ac92323ba3912f51fc4016ce81ecf", size = 144413, upload-time = "2025-11-07T00:44:27.939Z" }, - { url = "https://files.pythonhosted.org/packages/83/2b/9f6b643fe39d4505c7bf926d7c2595b7cb4b607c8c6b500e56c6b36ac238/wrapt-2.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c1c91405fcf1d501fa5d55df21e58ea49e6b879ae829f1039faaf7e5e509b41e", size = 150325, upload-time = "2025-11-07T00:44:29.29Z" }, - { url = "https://files.pythonhosted.org/packages/bb/b6/20ffcf2558596a7f58a2e69c89597128781f0b88e124bf5a4cadc05b8139/wrapt-2.0.1-cp313-cp313t-win32.whl", hash = "sha256:e76e3f91f864e89db8b8d2a8311d57df93f01ad6bb1e9b9976d1f2e83e18315c", size = 59943, upload-time = "2025-11-07T00:44:33.211Z" }, - { url = "https://files.pythonhosted.org/packages/87/6a/0e56111cbb3320151eed5d3821ee1373be13e05b376ea0870711f18810c3/wrapt-2.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:83ce30937f0ba0d28818807b303a412440c4b63e39d3d8fc036a94764b728c92", size = 63240, upload-time = "2025-11-07T00:44:30.935Z" }, - { url = "https://files.pythonhosted.org/packages/1d/54/5ab4c53ea1f7f7e5c3e7c1095db92932cc32fd62359d285486d00c2884c3/wrapt-2.0.1-cp313-cp313t-win_arm64.whl", hash = "sha256:4b55cacc57e1dc2d0991dbe74c6419ffd415fb66474a02335cb10efd1aa3f84f", size = 60416, upload-time = "2025-11-07T00:44:32.002Z" }, - { url = "https://files.pythonhosted.org/packages/73/81/d08d83c102709258e7730d3cd25befd114c60e43ef3891d7e6877971c514/wrapt-2.0.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:5e53b428f65ece6d9dad23cb87e64506392b720a0b45076c05354d27a13351a1", size = 78290, upload-time = "2025-11-07T00:44:34.691Z" }, - { url = "https://files.pythonhosted.org/packages/f6/14/393afba2abb65677f313aa680ff0981e829626fed39b6a7e3ec807487790/wrapt-2.0.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ad3ee9d0f254851c71780966eb417ef8e72117155cff04821ab9b60549694a55", size = 61255, upload-time = "2025-11-07T00:44:35.762Z" }, - { url = "https://files.pythonhosted.org/packages/c4/10/a4a1f2fba205a9462e36e708ba37e5ac95f4987a0f1f8fd23f0bf1fc3b0f/wrapt-2.0.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d7b822c61ed04ee6ad64bc90d13368ad6eb094db54883b5dde2182f67a7f22c0", size = 61797, upload-time = "2025-11-07T00:44:37.22Z" }, - { url = "https://files.pythonhosted.org/packages/12/db/99ba5c37cf1c4fad35349174f1e38bd8d992340afc1ff27f526729b98986/wrapt-2.0.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7164a55f5e83a9a0b031d3ffab4d4e36bbec42e7025db560f225489fa929e509", size = 120470, upload-time = "2025-11-07T00:44:39.425Z" }, - { url = "https://files.pythonhosted.org/packages/30/3f/a1c8d2411eb826d695fc3395a431757331582907a0ec59afce8fe8712473/wrapt-2.0.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e60690ba71a57424c8d9ff28f8d006b7ad7772c22a4af432188572cd7fa004a1", size = 122851, upload-time = "2025-11-07T00:44:40.582Z" }, - { url = "https://files.pythonhosted.org/packages/b3/8d/72c74a63f201768d6a04a8845c7976f86be6f5ff4d74996c272cefc8dafc/wrapt-2.0.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3cd1a4bd9a7a619922a8557e1318232e7269b5fb69d4ba97b04d20450a6bf970", size = 117433, upload-time = "2025-11-07T00:44:38.313Z" }, - { url = "https://files.pythonhosted.org/packages/c7/5a/df37cf4042cb13b08256f8e27023e2f9b3d471d553376616591bb99bcb31/wrapt-2.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b4c2e3d777e38e913b8ce3a6257af72fb608f86a1df471cb1d4339755d0a807c", size = 121280, upload-time = "2025-11-07T00:44:41.69Z" }, - { url = "https://files.pythonhosted.org/packages/54/34/40d6bc89349f9931e1186ceb3e5fbd61d307fef814f09fbbac98ada6a0c8/wrapt-2.0.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3d366aa598d69416b5afedf1faa539fac40c1d80a42f6b236c88c73a3c8f2d41", size = 116343, upload-time = "2025-11-07T00:44:43.013Z" }, - { url = "https://files.pythonhosted.org/packages/70/66/81c3461adece09d20781dee17c2366fdf0cb8754738b521d221ca056d596/wrapt-2.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c235095d6d090aa903f1db61f892fffb779c1eaeb2a50e566b52001f7a0f66ed", size = 119650, upload-time = "2025-11-07T00:44:44.523Z" }, - { url = "https://files.pythonhosted.org/packages/46/3a/d0146db8be8761a9e388cc9cc1c312b36d583950ec91696f19bbbb44af5a/wrapt-2.0.1-cp314-cp314-win32.whl", hash = "sha256:bfb5539005259f8127ea9c885bdc231978c06b7a980e63a8a61c8c4c979719d0", size = 58701, upload-time = "2025-11-07T00:44:48.277Z" }, - { url = "https://files.pythonhosted.org/packages/1a/38/5359da9af7d64554be63e9046164bd4d8ff289a2dd365677d25ba3342c08/wrapt-2.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:4ae879acc449caa9ed43fc36ba08392b9412ee67941748d31d94e3cedb36628c", size = 60947, upload-time = "2025-11-07T00:44:46.086Z" }, - { url = "https://files.pythonhosted.org/packages/aa/3f/96db0619276a833842bf36343685fa04f987dd6e3037f314531a1e00492b/wrapt-2.0.1-cp314-cp314-win_arm64.whl", hash = "sha256:8639b843c9efd84675f1e100ed9e99538ebea7297b62c4b45a7042edb84db03e", size = 59359, upload-time = "2025-11-07T00:44:47.164Z" }, - { url = "https://files.pythonhosted.org/packages/71/49/5f5d1e867bf2064bf3933bc6cf36ade23505f3902390e175e392173d36a2/wrapt-2.0.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:9219a1d946a9b32bb23ccae66bdb61e35c62773ce7ca6509ceea70f344656b7b", size = 82031, upload-time = "2025-11-07T00:44:49.4Z" }, - { url = "https://files.pythonhosted.org/packages/2b/89/0009a218d88db66ceb83921e5685e820e2c61b59bbbb1324ba65342668bc/wrapt-2.0.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:fa4184e74197af3adad3c889a1af95b53bb0466bced92ea99a0c014e48323eec", size = 62952, upload-time = "2025-11-07T00:44:50.74Z" }, - { url = "https://files.pythonhosted.org/packages/ae/18/9b968e920dd05d6e44bcc918a046d02afea0fb31b2f1c80ee4020f377cbe/wrapt-2.0.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c5ef2f2b8a53b7caee2f797ef166a390fef73979b15778a4a153e4b5fedce8fa", size = 63688, upload-time = "2025-11-07T00:44:52.248Z" }, - { url = "https://files.pythonhosted.org/packages/a6/7d/78bdcb75826725885d9ea26c49a03071b10c4c92da93edda612910f150e4/wrapt-2.0.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e042d653a4745be832d5aa190ff80ee4f02c34b21f4b785745eceacd0907b815", size = 152706, upload-time = "2025-11-07T00:44:54.613Z" }, - { url = "https://files.pythonhosted.org/packages/dd/77/cac1d46f47d32084a703df0d2d29d47e7eb2a7d19fa5cbca0e529ef57659/wrapt-2.0.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2afa23318136709c4b23d87d543b425c399887b4057936cd20386d5b1422b6fa", size = 158866, upload-time = "2025-11-07T00:44:55.79Z" }, - { url = "https://files.pythonhosted.org/packages/8a/11/b521406daa2421508903bf8d5e8b929216ec2af04839db31c0a2c525eee0/wrapt-2.0.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6c72328f668cf4c503ffcf9434c2b71fdd624345ced7941bc6693e61bbe36bef", size = 146148, upload-time = "2025-11-07T00:44:53.388Z" }, - { url = "https://files.pythonhosted.org/packages/0c/c0/340b272bed297baa7c9ce0c98ef7017d9c035a17a6a71dce3184b8382da2/wrapt-2.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3793ac154afb0e5b45d1233cb94d354ef7a983708cc3bb12563853b1d8d53747", size = 155737, upload-time = "2025-11-07T00:44:56.971Z" }, - { url = "https://files.pythonhosted.org/packages/f3/93/bfcb1fb2bdf186e9c2883a4d1ab45ab099c79cbf8f4e70ea453811fa3ea7/wrapt-2.0.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:fec0d993ecba3991645b4857837277469c8cc4c554a7e24d064d1ca291cfb81f", size = 144451, upload-time = "2025-11-07T00:44:58.515Z" }, - { url = "https://files.pythonhosted.org/packages/d2/6b/dca504fb18d971139d232652656180e3bd57120e1193d9a5899c3c0b7cdd/wrapt-2.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:949520bccc1fa227274da7d03bf238be15389cd94e32e4297b92337df9b7a349", size = 150353, upload-time = "2025-11-07T00:44:59.753Z" }, - { url = "https://files.pythonhosted.org/packages/1d/f6/a1de4bd3653afdf91d250ca5c721ee51195df2b61a4603d4b373aa804d1d/wrapt-2.0.1-cp314-cp314t-win32.whl", hash = "sha256:be9e84e91d6497ba62594158d3d31ec0486c60055c49179edc51ee43d095f79c", size = 60609, upload-time = "2025-11-07T00:45:03.315Z" }, - { url = "https://files.pythonhosted.org/packages/01/3a/07cd60a9d26fe73efead61c7830af975dfdba8537632d410462672e4432b/wrapt-2.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:61c4956171c7434634401db448371277d07032a81cc21c599c22953374781395", size = 64038, upload-time = "2025-11-07T00:45:00.948Z" }, - { url = "https://files.pythonhosted.org/packages/41/99/8a06b8e17dddbf321325ae4eb12465804120f699cd1b8a355718300c62da/wrapt-2.0.1-cp314-cp314t-win_arm64.whl", hash = "sha256:35cdbd478607036fee40273be8ed54a451f5f23121bd9d4be515158f9498f7ad", size = 60634, upload-time = "2025-11-07T00:45:02.087Z" }, - { url = "https://files.pythonhosted.org/packages/15/d1/b51471c11592ff9c012bd3e2f7334a6ff2f42a7aed2caffcf0bdddc9cb89/wrapt-2.0.1-py3-none-any.whl", hash = "sha256:4d2ce1bf1a48c5277d7969259232b57645aae5686dba1eaeade39442277afbca", size = 44046, upload-time = "2025-11-07T00:45:32.116Z" }, +version = "2.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/64/925f213fdcbb9baeb1530449ac71a4d57fc361c053d06bf78d0c5c7cd80c/wrapt-2.1.2.tar.gz", hash = "sha256:3996a67eecc2c68fd47b4e3c564405a5777367adfd9b8abb58387b63ee83b21e", size = 81678, upload-time = "2026-03-06T02:53:25.134Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/b6/1db817582c49c7fcbb7df6809d0f515af29d7c2fbf57eb44c36e98fb1492/wrapt-2.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ff2aad9c4cda28a8f0653fc2d487596458c2a3f475e56ba02909e950a9efa6a9", size = 61255, upload-time = "2026-03-06T02:52:45.663Z" }, + { url = "https://files.pythonhosted.org/packages/a2/16/9b02a6b99c09227c93cd4b73acc3678114154ec38da53043c0ddc1fba0dc/wrapt-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6433ea84e1cfacf32021d2a4ee909554ade7fd392caa6f7c13f1f4bf7b8e8748", size = 61848, upload-time = "2026-03-06T02:53:48.728Z" }, + { url = "https://files.pythonhosted.org/packages/af/aa/ead46a88f9ec3a432a4832dfedb84092fc35af2d0ba40cd04aea3889f247/wrapt-2.1.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c20b757c268d30d6215916a5fa8461048d023865d888e437fab451139cad6c8e", size = 121433, upload-time = "2026-03-06T02:54:40.328Z" }, + { url = "https://files.pythonhosted.org/packages/3a/9f/742c7c7cdf58b59085a1ee4b6c37b013f66ac33673a7ef4aaed5e992bc33/wrapt-2.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79847b83eb38e70d93dc392c7c5b587efe65b3e7afcc167aa8abd5d60e8761c8", size = 123013, upload-time = "2026-03-06T02:53:26.58Z" }, + { url = "https://files.pythonhosted.org/packages/e8/44/2c3dd45d53236b7ed7c646fcf212251dc19e48e599debd3926b52310fafb/wrapt-2.1.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f8fba1bae256186a83d1875b2b1f4e2d1242e8fac0f58ec0d7e41b26967b965c", size = 117326, upload-time = "2026-03-06T02:53:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/74/e2/b17d66abc26bd96f89dec0ecd0ef03da4a1286e6ff793839ec431b9fae57/wrapt-2.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e3d3b35eedcf5f7d022291ecd7533321c4775f7b9cd0050a31a68499ba45757c", size = 121444, upload-time = "2026-03-06T02:54:09.5Z" }, + { url = "https://files.pythonhosted.org/packages/3c/62/e2977843fdf9f03daf1586a0ff49060b1b2fc7ff85a7ea82b6217c1ae36e/wrapt-2.1.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:6f2c5390460de57fa9582bc8a1b7a6c86e1a41dfad74c5225fc07044c15cc8d1", size = 116237, upload-time = "2026-03-06T02:54:03.884Z" }, + { url = "https://files.pythonhosted.org/packages/88/dd/27fc67914e68d740bce512f11734aec08696e6b17641fef8867c00c949fc/wrapt-2.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7dfa9f2cf65d027b951d05c662cc99ee3bd01f6e4691ed39848a7a5fffc902b2", size = 120563, upload-time = "2026-03-06T02:53:20.412Z" }, + { url = "https://files.pythonhosted.org/packages/ec/9f/b750b3692ed2ef4705cb305bd68858e73010492b80e43d2a4faa5573cbe7/wrapt-2.1.2-cp312-cp312-win32.whl", hash = "sha256:eba8155747eb2cae4a0b913d9ebd12a1db4d860fc4c829d7578c7b989bd3f2f0", size = 58198, upload-time = "2026-03-06T02:53:37.732Z" }, + { url = "https://files.pythonhosted.org/packages/8e/b2/feecfe29f28483d888d76a48f03c4c4d8afea944dbee2b0cd3380f9df032/wrapt-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:1c51c738d7d9faa0b3601708e7e2eda9bf779e1b601dce6c77411f2a1b324a63", size = 60441, upload-time = "2026-03-06T02:52:47.138Z" }, + { url = "https://files.pythonhosted.org/packages/44/e1/e328f605d6e208547ea9fd120804fcdec68536ac748987a68c47c606eea8/wrapt-2.1.2-cp312-cp312-win_arm64.whl", hash = "sha256:c8e46ae8e4032792eb2f677dbd0d557170a8e5524d22acc55199f43efedd39bf", size = 58836, upload-time = "2026-03-06T02:53:22.053Z" }, + { url = "https://files.pythonhosted.org/packages/4c/7a/d936840735c828b38d26a854e85d5338894cda544cb7a85a9d5b8b9c4df7/wrapt-2.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787fd6f4d67befa6fe2abdffcbd3de2d82dfc6fb8a6d850407c53332709d030b", size = 61259, upload-time = "2026-03-06T02:53:41.922Z" }, + { url = "https://files.pythonhosted.org/packages/5e/88/9a9b9a90ac8ca11c2fdb6a286cb3a1fc7dd774c00ed70929a6434f6bc634/wrapt-2.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4bdf26e03e6d0da3f0e9422fd36bcebf7bc0eeb55fdf9c727a09abc6b9fe472e", size = 61851, upload-time = "2026-03-06T02:52:48.672Z" }, + { url = "https://files.pythonhosted.org/packages/03/a9/5b7d6a16fd6533fed2756900fc8fc923f678179aea62ada6d65c92718c00/wrapt-2.1.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bbac24d879aa22998e87f6b3f481a5216311e7d53c7db87f189a7a0266dafffb", size = 121446, upload-time = "2026-03-06T02:54:14.013Z" }, + { url = "https://files.pythonhosted.org/packages/45/bb/34c443690c847835cfe9f892be78c533d4f32366ad2888972c094a897e39/wrapt-2.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:16997dfb9d67addc2e3f41b62a104341e80cac52f91110dece393923c0ebd5ca", size = 123056, upload-time = "2026-03-06T02:54:10.829Z" }, + { url = "https://files.pythonhosted.org/packages/93/b9/ff205f391cb708f67f41ea148545f2b53ff543a7ac293b30d178af4d2271/wrapt-2.1.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:162e4e2ba7542da9027821cb6e7c5e068d64f9a10b5f15512ea28e954893a267", size = 117359, upload-time = "2026-03-06T02:53:03.623Z" }, + { url = "https://files.pythonhosted.org/packages/1f/3d/1ea04d7747825119c3c9a5e0874a40b33594ada92e5649347c457d982805/wrapt-2.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f29c827a8d9936ac320746747a016c4bc66ef639f5cd0d32df24f5eacbf9c69f", size = 121479, upload-time = "2026-03-06T02:53:45.844Z" }, + { url = "https://files.pythonhosted.org/packages/78/cc/ee3a011920c7a023b25e8df26f306b2484a531ab84ca5c96260a73de76c0/wrapt-2.1.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:a9dd9813825f7ecb018c17fd147a01845eb330254dff86d3b5816f20f4d6aaf8", size = 116271, upload-time = "2026-03-06T02:54:46.356Z" }, + { url = "https://files.pythonhosted.org/packages/98/fd/e5ff7ded41b76d802cf1191288473e850d24ba2e39a6ec540f21ae3b57cb/wrapt-2.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6f8dbdd3719e534860d6a78526aafc220e0241f981367018c2875178cf83a413", size = 120573, upload-time = "2026-03-06T02:52:50.163Z" }, + { url = "https://files.pythonhosted.org/packages/47/c5/242cae3b5b080cd09bacef0591691ba1879739050cc7c801ff35c8886b66/wrapt-2.1.2-cp313-cp313-win32.whl", hash = "sha256:5c35b5d82b16a3bc6e0a04349b606a0582bc29f573786aebe98e0c159bc48db6", size = 58205, upload-time = "2026-03-06T02:53:47.494Z" }, + { url = "https://files.pythonhosted.org/packages/12/69/c358c61e7a50f290958809b3c61ebe8b3838ea3e070d7aac9814f95a0528/wrapt-2.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:f8bc1c264d8d1cf5b3560a87bbdd31131573eb25f9f9447bb6252b8d4c44a3a1", size = 60452, upload-time = "2026-03-06T02:53:30.038Z" }, + { url = "https://files.pythonhosted.org/packages/8e/66/c8a6fcfe321295fd8c0ab1bd685b5a01462a9b3aa2f597254462fc2bc975/wrapt-2.1.2-cp313-cp313-win_arm64.whl", hash = "sha256:3beb22f674550d5634642c645aba4c72a2c66fb185ae1aebe1e955fae5a13baf", size = 58842, upload-time = "2026-03-06T02:52:52.114Z" }, + { url = "https://files.pythonhosted.org/packages/da/55/9c7052c349106e0b3f17ae8db4b23a691a963c334de7f9dbd60f8f74a831/wrapt-2.1.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0fc04bc8664a8bc4c8e00b37b5355cffca2535209fba1abb09ae2b7c76ddf82b", size = 63075, upload-time = "2026-03-06T02:53:19.108Z" }, + { url = "https://files.pythonhosted.org/packages/09/a8/ce7b4006f7218248dd71b7b2b732d0710845a0e49213b18faef64811ffef/wrapt-2.1.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a9b9d50c9af998875a1482a038eb05755dfd6fe303a313f6a940bb53a83c3f18", size = 63719, upload-time = "2026-03-06T02:54:33.452Z" }, + { url = "https://files.pythonhosted.org/packages/e4/e5/2ca472e80b9e2b7a17f106bb8f9df1db11e62101652ce210f66935c6af67/wrapt-2.1.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2d3ff4f0024dd224290c0eabf0240f1bfc1f26363431505fb1b0283d3b08f11d", size = 152643, upload-time = "2026-03-06T02:52:42.721Z" }, + { url = "https://files.pythonhosted.org/packages/36/42/30f0f2cefca9d9cbf6835f544d825064570203c3e70aa873d8ae12e23791/wrapt-2.1.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3278c471f4468ad544a691b31bb856374fbdefb7fee1a152153e64019379f015", size = 158805, upload-time = "2026-03-06T02:54:25.441Z" }, + { url = "https://files.pythonhosted.org/packages/bb/67/d08672f801f604889dcf58f1a0b424fe3808860ede9e03affc1876b295af/wrapt-2.1.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a8914c754d3134a3032601c6984db1c576e6abaf3fc68094bb8ab1379d75ff92", size = 145990, upload-time = "2026-03-06T02:53:57.456Z" }, + { url = "https://files.pythonhosted.org/packages/68/a7/fd371b02e73babec1de6ade596e8cd9691051058cfdadbfd62a5898f3295/wrapt-2.1.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ff95d4264e55839be37bafe1536db2ab2de19da6b65f9244f01f332b5286cfbf", size = 155670, upload-time = "2026-03-06T02:54:55.309Z" }, + { url = "https://files.pythonhosted.org/packages/86/2d/9fe0095dfdb621009f40117dcebf41d7396c2c22dca6eac779f4c007b86c/wrapt-2.1.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:76405518ca4e1b76fbb1b9f686cff93aebae03920cc55ceeec48ff9f719c5f67", size = 144357, upload-time = "2026-03-06T02:54:24.092Z" }, + { url = "https://files.pythonhosted.org/packages/0e/b6/ec7b4a254abbe4cde9fa15c5d2cca4518f6b07d0f1b77d4ee9655e30280e/wrapt-2.1.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c0be8b5a74c5824e9359b53e7e58bef71a729bacc82e16587db1c4ebc91f7c5a", size = 150269, upload-time = "2026-03-06T02:53:31.268Z" }, + { url = "https://files.pythonhosted.org/packages/6e/6b/2fabe8ebf148f4ee3c782aae86a795cc68ffe7d432ef550f234025ce0cfa/wrapt-2.1.2-cp313-cp313t-win32.whl", hash = "sha256:f01277d9a5fc1862f26f7626da9cf443bebc0abd2f303f41c5e995b15887dabd", size = 59894, upload-time = "2026-03-06T02:54:15.391Z" }, + { url = "https://files.pythonhosted.org/packages/ca/fb/9ba66fc2dedc936de5f8073c0217b5d4484e966d87723415cc8262c5d9c2/wrapt-2.1.2-cp313-cp313t-win_amd64.whl", hash = "sha256:84ce8f1c2104d2f6daa912b1b5b039f331febfeee74f8042ad4e04992bd95c8f", size = 63197, upload-time = "2026-03-06T02:54:41.943Z" }, + { url = "https://files.pythonhosted.org/packages/c0/1c/012d7423c95d0e337117723eb8ecf73c622ce15a97847e84cf3f8f26cd7e/wrapt-2.1.2-cp313-cp313t-win_arm64.whl", hash = "sha256:a93cd767e37faeddbe07d8fc4212d5cba660af59bdb0f6372c93faaa13e6e679", size = 60363, upload-time = "2026-03-06T02:54:48.093Z" }, + { url = "https://files.pythonhosted.org/packages/39/25/e7ea0b417db02bb796182a5316398a75792cd9a22528783d868755e1f669/wrapt-2.1.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1370e516598854e5b4366e09ce81e08bfe94d42b0fd569b88ec46cc56d9164a9", size = 61418, upload-time = "2026-03-06T02:53:55.706Z" }, + { url = "https://files.pythonhosted.org/packages/ec/0f/fa539e2f6a770249907757eaeb9a5ff4deb41c026f8466c1c6d799088a9b/wrapt-2.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6de1a3851c27e0bd6a04ca993ea6f80fc53e6c742ee1601f486c08e9f9b900a9", size = 61914, upload-time = "2026-03-06T02:52:53.37Z" }, + { url = "https://files.pythonhosted.org/packages/53/37/02af1867f5b1441aaeda9c82deed061b7cd1372572ddcd717f6df90b5e93/wrapt-2.1.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:de9f1a2bbc5ac7f6012ec24525bdd444765a2ff64b5985ac6e0692144838542e", size = 120417, upload-time = "2026-03-06T02:54:30.74Z" }, + { url = "https://files.pythonhosted.org/packages/c3/b7/0138a6238c8ba7476c77cf786a807f871672b37f37a422970342308276e7/wrapt-2.1.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:970d57ed83fa040d8b20c52fe74a6ae7e3775ae8cff5efd6a81e06b19078484c", size = 122797, upload-time = "2026-03-06T02:54:51.539Z" }, + { url = "https://files.pythonhosted.org/packages/e1/ad/819ae558036d6a15b7ed290d5b14e209ca795dd4da9c58e50c067d5927b0/wrapt-2.1.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3969c56e4563c375861c8df14fa55146e81ac11c8db49ea6fb7f2ba58bc1ff9a", size = 117350, upload-time = "2026-03-06T02:54:37.651Z" }, + { url = "https://files.pythonhosted.org/packages/8b/2d/afc18dc57a4600a6e594f77a9ae09db54f55ba455440a54886694a84c71b/wrapt-2.1.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:57d7c0c980abdc5f1d98b11a2aa3bb159790add80258c717fa49a99921456d90", size = 121223, upload-time = "2026-03-06T02:54:35.221Z" }, + { url = "https://files.pythonhosted.org/packages/b9/5b/5ec189b22205697bc56eb3b62aed87a1e0423e9c8285d0781c7a83170d15/wrapt-2.1.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:776867878e83130c7a04237010463372e877c1c994d449ca6aaafeab6aab2586", size = 116287, upload-time = "2026-03-06T02:54:19.654Z" }, + { url = "https://files.pythonhosted.org/packages/f7/2d/f84939a7c9b5e6cdd8a8d0f6a26cabf36a0f7e468b967720e8b0cd2bdf69/wrapt-2.1.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:fab036efe5464ec3291411fabb80a7a39e2dd80bae9bcbeeca5087fdfa891e19", size = 119593, upload-time = "2026-03-06T02:54:16.697Z" }, + { url = "https://files.pythonhosted.org/packages/0b/fe/ccd22a1263159c4ac811ab9374c061bcb4a702773f6e06e38de5f81a1bdc/wrapt-2.1.2-cp314-cp314-win32.whl", hash = "sha256:e6ed62c82ddf58d001096ae84ce7f833db97ae2263bff31c9b336ba8cfe3f508", size = 58631, upload-time = "2026-03-06T02:53:06.498Z" }, + { url = "https://files.pythonhosted.org/packages/65/0a/6bd83be7bff2e7efaac7b4ac9748da9d75a34634bbbbc8ad077d527146df/wrapt-2.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:467e7c76315390331c67073073d00662015bb730c566820c9ca9b54e4d67fd04", size = 60875, upload-time = "2026-03-06T02:53:50.252Z" }, + { url = "https://files.pythonhosted.org/packages/6c/c0/0b3056397fe02ff80e5a5d72d627c11eb885d1ca78e71b1a5c1e8c7d45de/wrapt-2.1.2-cp314-cp314-win_arm64.whl", hash = "sha256:da1f00a557c66225d53b095a97eace0fc5349e3bfda28fa34ffae238978ee575", size = 59164, upload-time = "2026-03-06T02:53:59.128Z" }, + { url = "https://files.pythonhosted.org/packages/71/ed/5d89c798741993b2371396eb9d4634f009ff1ad8a6c78d366fe2883ea7a6/wrapt-2.1.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:62503ffbc2d3a69891cf29beeaccdb4d5e0a126e2b6a851688d4777e01428dbb", size = 63163, upload-time = "2026-03-06T02:52:54.873Z" }, + { url = "https://files.pythonhosted.org/packages/c6/8c/05d277d182bf36b0a13d6bd393ed1dec3468a25b59d01fba2dd70fe4d6ae/wrapt-2.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c7e6cd120ef837d5b6f860a6ea3745f8763805c418bb2f12eeb1fa6e25f22d22", size = 63723, upload-time = "2026-03-06T02:52:56.374Z" }, + { url = "https://files.pythonhosted.org/packages/f4/27/6c51ec1eff4413c57e72d6106bb8dec6f0c7cdba6503d78f0fa98767bcc9/wrapt-2.1.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3769a77df8e756d65fbc050333f423c01ae012b4f6731aaf70cf2bef61b34596", size = 152652, upload-time = "2026-03-06T02:53:23.79Z" }, + { url = "https://files.pythonhosted.org/packages/db/4c/d7dd662d6963fc7335bfe29d512b02b71cdfa23eeca7ab3ac74a67505deb/wrapt-2.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a76d61a2e851996150ba0f80582dd92a870643fa481f3b3846f229de88caf044", size = 158807, upload-time = "2026-03-06T02:53:35.742Z" }, + { url = "https://files.pythonhosted.org/packages/b4/4d/1e5eea1a78d539d346765727422976676615814029522c76b87a95f6bcdd/wrapt-2.1.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6f97edc9842cf215312b75fe737ee7c8adda75a89979f8e11558dfff6343cc4b", size = 146061, upload-time = "2026-03-06T02:52:57.574Z" }, + { url = "https://files.pythonhosted.org/packages/89/bc/62cabea7695cd12a288023251eeefdcb8465056ddaab6227cb78a2de005b/wrapt-2.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:4006c351de6d5007aa33a551f600404ba44228a89e833d2fadc5caa5de8edfbf", size = 155667, upload-time = "2026-03-06T02:53:39.422Z" }, + { url = "https://files.pythonhosted.org/packages/e9/99/6f2888cd68588f24df3a76572c69c2de28287acb9e1972bf0c83ce97dbc1/wrapt-2.1.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:a9372fc3639a878c8e7d87e1556fa209091b0a66e912c611e3f833e2c4202be2", size = 144392, upload-time = "2026-03-06T02:54:22.41Z" }, + { url = "https://files.pythonhosted.org/packages/40/51/1dfc783a6c57971614c48e361a82ca3b6da9055879952587bc99fe1a7171/wrapt-2.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3144b027ff30cbd2fca07c0a87e67011adb717eb5f5bd8496325c17e454257a3", size = 150296, upload-time = "2026-03-06T02:54:07.848Z" }, + { url = "https://files.pythonhosted.org/packages/6c/38/cbb8b933a0201076c1f64fc42883b0023002bdc14a4964219154e6ff3350/wrapt-2.1.2-cp314-cp314t-win32.whl", hash = "sha256:3b8d15e52e195813efe5db8cec156eebe339aaf84222f4f4f051a6c01f237ed7", size = 60539, upload-time = "2026-03-06T02:54:00.594Z" }, + { url = "https://files.pythonhosted.org/packages/82/dd/e5176e4b241c9f528402cebb238a36785a628179d7d8b71091154b3e4c9e/wrapt-2.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:08ffa54146a7559f5b8df4b289b46d963a8e74ed16ba3687f99896101a3990c5", size = 63969, upload-time = "2026-03-06T02:54:39Z" }, + { url = "https://files.pythonhosted.org/packages/5c/99/79f17046cf67e4a95b9987ea129632ba8bcec0bc81f3fb3d19bdb0bd60cd/wrapt-2.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:72aaa9d0d8e4ed0e2e98019cea47a21f823c9dd4b43c7b77bba6679ffcca6a00", size = 60554, upload-time = "2026-03-06T02:53:14.132Z" }, + { url = "https://files.pythonhosted.org/packages/1a/c7/8528ac2dfa2c1e6708f647df7ae144ead13f0a31146f43c7264b4942bf12/wrapt-2.1.2-py3-none-any.whl", hash = "sha256:b8fd6fa2b2c4e7621808f8c62e8317f4aae56e59721ad933bac5239d913cf0e8", size = 43993, upload-time = "2026-03-06T02:53:12.905Z" }, ] [[package]] From 63f7de50604d034b9fe2fe0c3f909db02e528ab1 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Fri, 20 Mar 2026 13:03:57 -0400 Subject: [PATCH 504/587] sparse_iterkeys -> sparse_keys --- stubs/pyomo/core/base/param.pyi | 2 +- temoa/_internal/table_data_puller.py | 16 +++++----- temoa/components/capacity.py | 18 +++++------ temoa/components/commodities.py | 16 +++++----- temoa/components/costs.py | 22 ++++++------- temoa/components/emissions.py | 4 +-- temoa/components/geography.py | 2 +- temoa/components/limits.py | 30 +++++++++--------- temoa/components/reserves.py | 2 +- temoa/components/technology.py | 36 +++++++++++----------- temoa/components/time.py | 4 +-- temoa/model_checking/network_model_data.py | 4 +-- temoa/model_checking/pricing_check.py | 19 ++++++------ temoa/model_checking/validators.py | 2 +- tests/test_full_runs.py | 2 +- 15 files changed, 89 insertions(+), 90 deletions(-) diff --git a/stubs/pyomo/core/base/param.pyi b/stubs/pyomo/core/base/param.pyi index 8f60ebf1a..c8d310a77 100644 --- a/stubs/pyomo/core/base/param.pyi +++ b/stubs/pyomo/core/base/param.pyi @@ -66,7 +66,7 @@ class Param(IndexedComponent, IndexedComponent_NDArrayMixin): def sparse_keys(self): ... def sparse_values(self): ... def sparse_items(self): ... - def sparse_iterkeys(self): ... + def sparse_keys(self): ... def sparse_itervalues(self): ... def sparse_iteritems(self): ... def extract_values(self): ... diff --git a/temoa/_internal/table_data_puller.py b/temoa/_internal/table_data_puller.py index 968a0ba79..cd5bb6fd5 100644 --- a/temoa/_internal/table_data_puller.py +++ b/temoa/_internal/table_data_puller.py @@ -216,7 +216,7 @@ def poll_flow_results(model: TemoaModel, epsilon: float = 1e-5) -> dict[FI, dict res[fi][FlowType.OUT] -= flow # construction flows - for r, i, t, v in model.construction_input.sparse_iterkeys(): + for r, i, t, v in model.construction_input.sparse_keys(): annual = ( value(model.construction_input[r, i, t, v]) * value(model.v_new_capacity[r, t, v]) @@ -231,7 +231,7 @@ def poll_flow_results(model: TemoaModel, epsilon: float = 1e-5) -> dict[FI, dict res[fi][FlowType.IN] = flow # end of life flows - for r, t, v, o in model.end_of_life_output.sparse_iterkeys(): + for r, t, v, o in model.end_of_life_output.sparse_keys(): if (r, t, v) not in model.retirement_periods: continue for p in model.retirement_periods[r, t, v]: @@ -335,7 +335,7 @@ def poll_cost_results( entries: dict[tuple[Region, Period, Technology, Vintage], dict[CostType, float]] = defaultdict( dict ) - for r, t, v in model.cost_invest.sparse_iterkeys(): # Returns only non-zero values + for r, t, v in model.cost_invest.sparse_keys(): # Returns only non-zero values # gather details... cap = value(model.v_new_capacity[r, t, v]) if abs(cap) < epsilon: @@ -395,7 +395,7 @@ def poll_cost_results( {CostType.D_INVEST: model_loan_cost, CostType.INVEST: undiscounted_cost} ) - for r, p, t, v in model.cost_fixed.sparse_iterkeys(): + for r, p, t, v in model.cost_fixed.sparse_keys(): cap = value(model.v_capacity[r, p, t, v]) if abs(cap) < epsilon: continue @@ -436,7 +436,7 @@ def poll_cost_results( } ) - for r, p, t, v in model.cost_variable.sparse_iterkeys(): + for r, p, t, v in model.cost_variable.sparse_keys(): if t not in model.tech_annual: activity = sum( value(model.v_flow_out[r, p, S_s, S_d, S_i, t, v, S_o]) @@ -622,7 +622,7 @@ def poll_emissions( base = [ (r, p, e, i, t, v, o) - for (r, e, i, t, v, o) in model.emission_activity.sparse_iterkeys() + for (r, e, i, t, v, o) in model.emission_activity.sparse_keys() for p in model.time_optimize if (r, p, t, v) in model.process_inputs ] @@ -683,7 +683,7 @@ def poll_emissions( # iterate through embodied flows embodied_flows: dict[EI, float] = defaultdict(float) - for r, e, t, v in model.emission_embodied.sparse_iterkeys(): + for r, e, t, v in model.emission_embodied.sparse_keys(): embodied_flows[EI(r, v, t, v, e)] += value( model.v_new_capacity[r, t, v] * model.emission_embodied[r, e, t, v] @@ -731,7 +731,7 @@ def poll_emissions( # iterate through end of life flows eol_flows: dict[EI, float] = defaultdict(float) - for r, e, t, v in model.emission_end_of_life.sparse_iterkeys(): + for r, e, t, v in model.emission_end_of_life.sparse_keys(): if (r, t, v) not in model.retirement_periods: continue for p in model.retirement_periods[r, t, v]: diff --git a/temoa/components/capacity.py b/temoa/components/capacity.py index f5d19a481..5b8cac0f2 100644 --- a/temoa/components/capacity.py +++ b/temoa/components/capacity.py @@ -53,7 +53,7 @@ def check_capacity_factor_process(model: TemoaModel) -> None: count_rtv[r, t, v] = 0 # Check for bad values and count up the good ones - for r, _s, _d, t, v in model.capacity_factor_process.sparse_iterkeys(): + for r, _s, _d, t, v in model.capacity_factor_process.sparse_keys(): # Validate that vintage is active for some period if not model.process_periods.get((r, t, v)): msg = f'Invalid vintage {v} for {r, t} in capacity_factor_process table' @@ -91,7 +91,7 @@ def create_capacity_factors(model: TemoaModel) -> None: capacity_factor_process = model.capacity_factor_process # Step 1 - processes = {(r, t, v) for r, _i, t, v, _o in model.efficiency.sparse_iterkeys()} + processes = {(r, t, v) for r, i, t, v, o in model.efficiency.sparse_keys()} all_cfs = { (r, s, d, t, v) @@ -100,7 +100,7 @@ def create_capacity_factors(model: TemoaModel) -> None: } # Step 2 - unspecified_cfs = all_cfs.difference(capacity_factor_process.sparse_iterkeys()) + unspecified_cfs = all_cfs.difference(capacity_factor_process.sparse_keys()) # Step 3 @@ -239,7 +239,7 @@ def capacity_factor_process_indices( model: TemoaModel, ) -> set[tuple[Region, Season, TimeOfDay, Technology, Vintage]]: indices: set[tuple[Region, Season, TimeOfDay, Technology, Vintage]] = set() - for r, _i, t, v, _o in model.efficiency.sparse_iterkeys(): + for r, _i, t, v, _o in model.efficiency.sparse_keys(): for s in model.time_season: for d in model.time_of_day: indices.add((r, s, d, t, v)) @@ -608,8 +608,8 @@ def create_capacity_and_retirement_sets(model: TemoaModel) -> None: logger.debug('Creating capacity, retirement, and construction/EOL sets.') # Calculate retirement periods based on lifetime and survival curves - unique_rtv = {(r, t, v) for r, _i, t, v, _o in model.efficiency.sparse_iterkeys()} | set( - model.existing_capacity.sparse_iterkeys() + unique_rtv = {(r, t, v) for r, _i, t, v, _o in model.efficiency.sparse_keys()} | set( + model.existing_capacity.sparse_keys() ) for r, t, v in unique_rtv: if t in model.tech_uncap: @@ -641,19 +641,19 @@ def create_capacity_and_retirement_sets(model: TemoaModel) -> None: model.retirement_periods.setdefault((r, t, v), set()).add(p) # Link construction materials to technologies - for r, i, t, v in model.construction_input.sparse_iterkeys(): + for r, i, t, v in model.construction_input.sparse_keys(): model.capacity_consumption_techs.setdefault((r, v, i), set()).add(t) model.used_techs.add(t) # Link end-of-life materials to retiring technologies - for r, t, v, o in model.end_of_life_output.sparse_iterkeys(): + for r, t, v, o in model.end_of_life_output.sparse_keys(): if (r, t, v) in model.retirement_periods: for p in model.retirement_periods[r, t, v]: model.retirement_production_processes.setdefault((r, p, o), set()).add((t, v)) model.used_techs.add(t) # Link end-of-life emissions to retiring technologies - for r, _e, t, v in model.emission_end_of_life.sparse_iterkeys(): + for r, _e, t, v in model.emission_end_of_life.sparse_keys(): if (r, t, v) in model.retirement_periods: model.used_techs.add(t) diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index 2058d469d..4a4694fcc 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -697,7 +697,7 @@ def create_technology_and_commodity_sets(model: TemoaModel) -> None: - M.tech_demand: Technologies that directly satisfy an end-use demand. """ logger.debug('Creating technology and commodity subsets.') - for _r, _i, t, _v, o in model.efficiency.sparse_iterkeys(): + for _r, _i, t, _v, o in model.efficiency.sparse_keys(): if t in model.tech_flex and o not in model.commodity_flex: model.commodity_flex.add(o) @@ -728,7 +728,7 @@ def create_demands(model: TemoaModel) -> None: demand_specific_distributon_dem = iget(3) # Step 1: Check if any demand commodities are going unused - used_dems = {dem for _r, _p, dem in model.demand.sparse_iterkeys()} + used_dems = {dem for _r, _p, dem in model.demand.sparse_keys()} unused_dems = sorted(model.commodity_demand.difference(used_dems)) if unused_dems: for dem in unused_dems: @@ -740,8 +740,8 @@ def create_demands(model: TemoaModel) -> None: # makes sense to just use segment_fraction directly # Step 2: Build the demand default distribution (= segment_fraction) # DDD = M.DemandDefaultDistribution # Shorter, for us lazy programmer types - # unset_defaults = set(M.segment_fraction.sparse_iterkeys()) - # unset_defaults.difference_update(DDD.sparse_iterkeys()) + # unset_defaults = set(M.segment_fraction.sparse_keys()) + # unset_defaults.difference_update(DDD.sparse_keys()) # if unset_defaults: # Some hackery because Pyomo thinks that this Param is constructed. # However, in our view, it is not yet, because we're specifically @@ -759,7 +759,7 @@ def create_demands(model: TemoaModel) -> None: # # errors associated with the specification of demand shares by time slice, # # but we check to make sure it is within the specified tolerance. - # key_padding = max(map(get_str_padding, DDD.sparse_iterkeys())) + # key_padding = max(map(get_str_padding, DDD.sparse_keys())) # fmt = '%%-%ds = %%s' % key_padding # # Works out to something like "%-25s = %s" @@ -783,7 +783,7 @@ def create_demands(model: TemoaModel) -> None: demands_specified = set( map( demand_specific_distributon_dem, - (i for i in demand_specific_distribution.sparse_iterkeys()), + (i for i in demand_specific_distribution.sparse_keys()), ) ) unset_demand_distributions = used_dems.difference( @@ -808,12 +808,12 @@ def create_demands(model: TemoaModel) -> None: # Also check that all keys are made... The demand distro should be supported # by the full set of (r, p, dem) keys because it is an equality constraint # and we need to ensure even the zeros are passed in - used_r_dems = {(r, dem) for r, p, dem in model.demand.sparse_iterkeys()} + used_r_dems = {(r, dem) for r, p, dem in model.demand.sparse_keys()} for r, dem in used_r_dems: expected_key_length = len(model.time_season) * len(model.time_of_day) keys = [ k - for k in demand_specific_distribution.sparse_iterkeys() + for k in demand_specific_distribution.sparse_keys() if demand_specific_distribution_region(k) == r and demand_specific_distributon_dem(k) == dem ] diff --git a/temoa/components/costs.py b/temoa/components/costs.py index 1ecf165bd..1c91d78ea 100644 --- a/temoa/components/costs.py +++ b/temoa/components/costs.py @@ -120,7 +120,7 @@ def lifetime_loan_process_indices(model: TemoaModel) -> set[tuple[Region, Techno because in myopic mode, previously optimized vintages remain active in later windows and their data must be accepted by the param's index set. """ - indices = {(r, t, v) for r, i, t, v, o in model.efficiency.sparse_iterkeys()} + indices = {(r, t, v) for r, i, t, v, o in model.efficiency.sparse_keys()} return indices @@ -335,7 +335,7 @@ def period_cost_rule(model: TemoaModel, p: int) -> float | Expression: global_discount_rate, vintage=S_v, ) - for r, S_t, S_v in model.cost_invest.sparse_iterkeys() + for r, S_t, S_v in model.cost_invest.sparse_keys() if S_v == p and not model.is_survival_curve_process[r, S_t, S_v] ) loan_costs += quicksum( @@ -352,7 +352,7 @@ def period_cost_rule(model: TemoaModel, p: int) -> float | Expression: p_e, global_discount_rate, ) - for r, S_t, S_v in model.cost_invest.sparse_iterkeys() + for r, S_t, S_v in model.cost_invest.sparse_keys() if S_v == p and model.is_survival_curve_process[r, S_t, S_v] ) @@ -365,7 +365,7 @@ def period_cost_rule(model: TemoaModel, p: int) -> float | Expression: p_0, p=p, ) - for r, S_p, S_t, S_v in model.cost_fixed.sparse_iterkeys() + for r, S_p, S_t, S_v in model.cost_fixed.sparse_keys() if S_p == p ) @@ -378,7 +378,7 @@ def period_cost_rule(model: TemoaModel, p: int) -> float | Expression: p_0, p, ) - for r, S_p, S_t, S_v in model.cost_variable.sparse_iterkeys() + for r, S_p, S_t, S_v in model.cost_variable.sparse_keys() if S_p == p and S_t not in model.tech_annual for S_i in model.process_inputs[r, S_p, S_t, S_v] for S_o in model.process_outputs_by_input[r, S_p, S_t, S_v, S_i] @@ -395,7 +395,7 @@ def period_cost_rule(model: TemoaModel, p: int) -> float | Expression: p_0, p, ) - for r, S_p, S_t, S_v in model.cost_variable.sparse_iterkeys() + for r, S_p, S_t, S_v in model.cost_variable.sparse_keys() if S_p == p and S_t in model.tech_annual for S_i in model.process_inputs[r, S_p, S_t, S_v] for S_o in model.process_outputs_by_input[r, S_p, S_t, S_v, S_i] @@ -417,7 +417,7 @@ def period_cost_rule(model: TemoaModel, p: int) -> float | Expression: base = [ (r, p, e, i, t, v, o) - for (r, e, i, t, v, o) in model.emission_activity.sparse_iterkeys() + for (r, e, i, t, v, o) in model.emission_activity.sparse_keys() if (r, p, e) in model.cost_emission # tightest filter first and (r, p, t, v) in model.process_inputs ] @@ -484,7 +484,7 @@ def period_cost_rule(model: TemoaModel, p: int) -> float | Expression: p_0=p_0, p=p, ) - for (r, e, t, v) in model.emission_embodied.sparse_iterkeys() + for (r, e, t, v) in model.emission_embodied.sparse_keys() if (r, p, e) in model.cost_emission if v == p ) @@ -502,7 +502,7 @@ def period_cost_rule(model: TemoaModel, p: int) -> float | Expression: p_0=p_0, p=p, ) - for (r, e, t, v) in model.emission_end_of_life.sparse_iterkeys() + for (r, e, t, v) in model.emission_end_of_life.sparse_keys() if (r, p, e) in model.cost_emission if (r, t, v) in model.retirement_periods and p in model.retirement_periods[r, t, v] ) @@ -687,8 +687,8 @@ def create_costs(model: TemoaModel) -> None: var_indices = set(model.cost_variable_rptv) # Step 2 - unspecified_fixed_prices = fixed_indices.difference(cost_fixed.sparse_iterkeys()) - unspecified_var_prices = var_indices.difference(cost_variable.sparse_iterkeys()) + unspecified_fixed_prices = fixed_indices.difference(cost_fixed.sparse_keys()) + unspecified_var_prices = var_indices.difference(cost_variable.sparse_keys()) # Step 3 diff --git a/temoa/components/emissions.py b/temoa/components/emissions.py index 05cae02f3..4ee6669de 100644 --- a/temoa/components/emissions.py +++ b/temoa/components/emissions.py @@ -40,7 +40,7 @@ def emission_activity_indices( ) -> set[tuple[Region, Commodity, Commodity, Technology, Vintage, Commodity]]: indices = { (r, e, i, t, v, o) - for r, i, t, v, o in model.efficiency.sparse_iterkeys() + for r, i, t, v, o in model.efficiency.sparse_keys() for e in model.commodity_emissions if r in model.regions # omit any exchange/groups } @@ -53,7 +53,7 @@ def linked_tech_constraint_indices( ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage, Commodity]]: linkedtech_indices = { (r, p, s, d, t, v, e) - for r, t, e in model.linked_techs.sparse_iterkeys() + for r, t, e in model.linked_techs.sparse_keys() for p in model.time_optimize if (r, p, t) in model.process_vintages for v in model.process_vintages[r, p, t] diff --git a/temoa/components/geography.py b/temoa/components/geography.py index 96538c409..45e8f788e 100644 --- a/temoa/components/geography.py +++ b/temoa/components/geography.py @@ -129,7 +129,7 @@ def create_geography_sets(model: TemoaModel) -> None: of (region_from, t, v, i) tuples. """ logger.debug('Creating geography-related sets for exchange technologies.') - for r, i, t, v, o in model.efficiency.sparse_iterkeys(): + for r, i, t, v, o in model.efficiency.sparse_keys(): if t not in model.tech_exchange: continue diff --git a/temoa/components/limits.py b/temoa/components/limits.py index 52eef6d8e..4d2cd0951 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -138,7 +138,7 @@ def limit_tech_output_split_average_constraint_indices( def limit_growth_capacity_indices(model: TemoaModel) -> set[tuple[Region, Period, Technology, str]]: indices = { (r, p, t, op) - for r, t, op in model.limit_growth_capacity.sparse_iterkeys() + for r, t, op in model.limit_growth_capacity.sparse_keys() for p in model.time_optimize } return indices @@ -149,7 +149,7 @@ def limit_degrowth_capacity_indices( ) -> set[tuple[Region, Period, Technology, str]]: indices = { (r, p, t, op) - for r, t, op in model.limit_degrowth_capacity.sparse_iterkeys() + for r, t, op in model.limit_degrowth_capacity.sparse_keys() for p in model.time_optimize } return indices @@ -160,7 +160,7 @@ def limit_growth_new_capacity_indices( ) -> set[tuple[Region, Period, Technology, str]]: indices = { (r, p, t, op) - for r, t, op in model.limit_growth_new_capacity.sparse_iterkeys() + for r, t, op in model.limit_growth_new_capacity.sparse_keys() for p in model.time_optimize } return indices @@ -171,7 +171,7 @@ def limit_degrowth_new_capacity_indices( ) -> set[tuple[Region, Period, Technology, str]]: indices = { (r, p, t, op) - for r, t, op in model.limit_degrowth_new_capacity.sparse_iterkeys() + for r, t, op in model.limit_degrowth_new_capacity.sparse_keys() for p in model.time_optimize } return indices @@ -182,7 +182,7 @@ def limit_growth_new_capacity_delta_indices( ) -> set[tuple[Region, Period, Technology, str]]: indices = { (r, p, t, op) - for r, t, op in model.limit_growth_new_capacity_delta.sparse_iterkeys() + for r, t, op in model.limit_growth_new_capacity_delta.sparse_keys() for p in model.time_optimize } return indices @@ -193,7 +193,7 @@ def limit_degrowth_new_capacity_delta_indices( ) -> set[tuple[Region, Period, Technology, str]]: indices = { (r, p, t, op) - for r, t, op in model.limit_degrowth_new_capacity_delta.sparse_iterkeys() + for r, t, op in model.limit_degrowth_new_capacity_delta.sparse_keys() for p in model.time_optimize } return indices @@ -884,7 +884,7 @@ def limit_emission_constraint( model.v_flow_out[reg, p, S_s, S_d, S_i, S_t, S_v, S_o] * value(model.emission_activity[reg, e, S_i, S_t, S_v, S_o]) for reg in regions - for tmp_r, tmp_e, S_i, S_t, S_v, S_o in model.emission_activity.sparse_iterkeys() + for tmp_r, tmp_e, S_i, S_t, S_v, S_o in model.emission_activity.sparse_keys() if tmp_e == e and tmp_r == reg and S_t not in model.tech_annual # EmissionsActivity not indexed by p, so make sure (r,p,t,v) combos valid if (reg, p, S_t, S_v) in model.process_inputs @@ -896,7 +896,7 @@ def limit_emission_constraint( model.v_flow_out_annual[reg, p, S_i, S_t, S_v, S_o] * value(model.emission_activity[reg, e, S_i, S_t, S_v, S_o]) for reg in regions - for tmp_r, tmp_e, S_i, S_t, S_v, S_o in model.emission_activity.sparse_iterkeys() + for tmp_r, tmp_e, S_i, S_t, S_v, S_o in model.emission_activity.sparse_keys() if tmp_e == e and tmp_r == reg and S_t in model.tech_annual # EmissionsActivity not indexed by p, so make sure (r,p,t,v) combos valid if (reg, p, S_t, S_v) in model.process_inputs @@ -907,14 +907,14 @@ def limit_emission_constraint( * value(model.emission_embodied[reg, e, t, v]) / value(model.period_length[v]) for reg in regions - for (S_r, S_e, t, v) in model.emission_embodied.sparse_iterkeys() + for (S_r, S_e, t, v) in model.emission_embodied.sparse_keys() if v == p and S_r == reg and S_e == e ) retirement_emissions = quicksum( model.v_annual_retirement[reg, p, t, v] * value(model.emission_end_of_life[reg, e, t, v]) for reg in regions - for (S_r, S_e, t, v) in model.emission_end_of_life.sparse_iterkeys() + for (S_r, S_e, t, v) in model.emission_end_of_life.sparse_keys() if (reg, t, v) in model.retirement_periods and p in model.retirement_periods[reg, t, v] if S_r == reg and S_e == e ) @@ -1037,7 +1037,7 @@ def limit_growth_capacity( capacity_prev = sum( value(model.existing_capacity[_r, _t, _v]) * min(1.0, (_v + value(model.lifetime_process[_r, _t, _v]) - p_prev) / (p - p_prev)) - for _r, _t, _v in model.existing_capacity.sparse_iterkeys() + for _r, _t, _v in model.existing_capacity.sparse_keys() if _r in regions and _t in techs and _v + value(model.lifetime_process[_r, _t, _v]) > p_prev @@ -1156,7 +1156,7 @@ def limit_growth_new_capacity( p_prev = model.time_exist.last() new_cap_prev = sum( value(model.existing_capacity[_r, _t, _v]) - for _r, _t, _v in model.existing_capacity.sparse_iterkeys() + for _r, _t, _v in model.existing_capacity.sparse_keys() if _r in regions and _t in techs and _v == p_prev ) else: @@ -1282,13 +1282,13 @@ def limit_growth_new_capacity_delta( p_prev = model.time_exist.last() new_cap_prev = sum( value(model.existing_capacity[_r, _t, _v]) - for _r, _t, _v in model.existing_capacity.sparse_iterkeys() + for _r, _t, _v in model.existing_capacity.sparse_keys() if _r in regions and _t in techs and _v == p_prev ) p_prev2 = model.time_exist.prev(p_prev) new_cap_prev2 = sum( value(model.existing_capacity[_r, _t, _v]) - for _r, _t, _v in model.existing_capacity.sparse_iterkeys() + for _r, _t, _v in model.existing_capacity.sparse_keys() if _r in regions and _t in techs and _v == p_prev2 ) else: @@ -1300,7 +1300,7 @@ def limit_growth_new_capacity_delta( p_prev2 = model.time_exist.last() new_cap_prev2 = sum( value(model.existing_capacity[_r, _t, _v]) - for _r, _t, _v in model.existing_capacity.sparse_iterkeys() + for _r, _t, _v in model.existing_capacity.sparse_keys() if _r in regions and _t in techs and _v == p_prev2 ) else: diff --git a/temoa/components/reserves.py b/temoa/components/reserves.py index febee50a0..1a65f5add 100644 --- a/temoa/components/reserves.py +++ b/temoa/components/reserves.py @@ -32,7 +32,7 @@ def reserve_margin_indices(model: TemoaModel) -> set[tuple[Region, Period, Season, TimeOfDay]]: indices = { (r, p, s, d) - for r in model.planning_reserve_margin.sparse_iterkeys() + for r in model.planning_reserve_margin.sparse_keys() for p in model.time_optimize if (r, p) in model.process_reserve_periods for s in model.time_season diff --git a/temoa/components/technology.py b/temoa/components/technology.py index 727f98caa..10945de58 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -60,8 +60,8 @@ def lifetime_process_indices(model: TemoaModel) -> set[tuple[Region, Technology, Based on the efficiency parameter's indices, this function returns the set of process indices that may be specified in the lifetime_process parameter. """ - indices = {(r, t, v) for r, i, t, v, o in model.efficiency.sparse_iterkeys()} - indices = indices | set(model.existing_capacity.sparse_iterkeys()) + indices = {(r, t, v) for r, i, t, v, o in set(model.efficiency.sparse_keys())} + indices = indices | set(model.existing_capacity.sparse_keys()) return indices @@ -146,9 +146,9 @@ def populate_core_dictionaries(model: TemoaModel) -> None: """ logger.debug('Populating core sparse dictionaries from efficiency parameter.') first_period = min(model.time_future) - exist_indices = model.existing_capacity.sparse_keys() + exist_indices = set(model.existing_capacity.sparse_keys()) - for r, i, t, v, o in model.efficiency.sparse_iterkeys(): + for r, i, t, v, o in set(model.efficiency.sparse_keys()): # A. Basic data validation and warnings process = (r, t, v) lifetime = value(model.lifetime_process[process]) @@ -226,13 +226,13 @@ def populate_core_dictionaries(model: TemoaModel) -> None: def create_survival_curve(model: TemoaModel) -> None: rtv_interpolated = set() # so we only need one warning - for r, _, t, v, _ in model.efficiency.sparse_iterkeys(): + for r, _, t, v, _ in model.efficiency.sparse_keys(): model.is_survival_curve_process[r, t, v] = False # by default - for r, t, v in model.existing_capacity.sparse_iterkeys(): + for r, t, v in model.existing_capacity.sparse_keys(): model.is_survival_curve_process[r, t, v] = False # by default # Collect rptv indices into (r, t, v): p dictionary - for r, p, t, v in model.lifetime_survival_curve.sparse_iterkeys(): + for r, p, t, v in model.lifetime_survival_curve.sparse_keys(): if (r, t, v) not in model.survival_curve_periods: model.survival_curve_periods[r, t, v] = set() model.survival_curve_periods[r, t, v].add(p) @@ -341,8 +341,8 @@ def check_efficiency_indices(model: TemoaModel) -> None: """ # TODO: This could be upgraded to scan for finer resolution # by checking by REGION and PERIOD... Each region/period is unique. - c_outputs = {o for r, i, t, v, o in model.efficiency.sparse_iterkeys()} - c_outputs = c_outputs | {o for r, t, v, o in model.end_of_life_output.sparse_iterkeys()} + c_outputs = {o for r, i, t, v, o in model.efficiency.sparse_keys()} + c_outputs = c_outputs | {o for r, t, v, o in model.end_of_life_output.sparse_keys()} diff = model.commodity_demand - c_outputs if diff: @@ -356,8 +356,8 @@ def check_efficiency_indices(model: TemoaModel) -> None: logger.error(f_msg) raise ValueError(f_msg) - c_inputs = {i for r, i, t, v, o in model.efficiency.sparse_iterkeys()} - c_inputs = c_inputs | {i for r, i, t, v in model.construction_input.sparse_iterkeys()} + c_inputs = {i for r, i, t, v, o in model.efficiency.sparse_keys()} + c_inputs = c_inputs | {i for r, i, t, v in model.construction_input.sparse_keys()} c_carrier = c_inputs | c_outputs symdiff = c_carrier.symmetric_difference(model.commodity_carrier) @@ -372,10 +372,10 @@ def check_efficiency_indices(model: TemoaModel) -> None: logger.error(f_msg) raise ValueError(f_msg) - techs = {t for r, i, t, v, o in model.efficiency.sparse_iterkeys()} - techs = techs | {t for r, t, v, o in model.end_of_life_output.sparse_iterkeys()} - techs = techs | {t for r, i, t, v in model.construction_input.sparse_iterkeys()} - techs = techs | {t for r, e, t, v in model.emission_end_of_life.sparse_iterkeys()} + techs = {t for r, i, t, v, o in model.efficiency.sparse_keys()} + techs = techs | {t for r, t, v, o in model.end_of_life_output.sparse_keys()} + techs = techs | {t for r, i, t, v in model.construction_input.sparse_keys()} + techs = techs | {t for r, e, t, v in model.emission_end_of_life.sparse_keys()} symdiff = techs.symmetric_difference(model.tech_production) if symdiff: @@ -392,7 +392,7 @@ def check_efficiency_indices(model: TemoaModel) -> None: def check_efficiency_variable(model: TemoaModel) -> None: count_ritvo = {} # Pull non-variable efficiency by default - for r, i, t, v, o in model.efficiency.sparse_iterkeys(): + for r, i, t, v, o in model.efficiency.sparse_keys(): if (r, t, v) not in model.process_periods: # Probably an existing vintage that retires in p0 # Still want it for end of life flows @@ -402,7 +402,7 @@ def check_efficiency_variable(model: TemoaModel) -> None: annual = set() # Check for bad values and count up the good ones - for r, _s, _d, i, t, v, o in model.efficiency_variable.sparse_iterkeys(): + for r, _s, _d, i, t, v, o in model.efficiency_variable.sparse_keys(): if t in model.tech_annual: annual.add(t) @@ -438,7 +438,7 @@ def check_existing_capacity(model: TemoaModel) -> None: """ Check that all existing capacities are properly accounted for in the model. """ - for r, t, v in model.existing_capacity.sparse_iterkeys(): + for r, t, v in model.existing_capacity.sparse_keys(): cap = value(model.existing_capacity[r, t, v]) if cap <= 0: msg = ( diff --git a/temoa/components/time.py b/temoa/components/time.py index 894dee35e..0877a40b6 100644 --- a/temoa/components/time.py +++ b/temoa/components/time.py @@ -102,7 +102,7 @@ def validate_segment_fraction(model: TemoaModel) -> None: expected_keys: set[tuple[str, str]] = { (s, d) for s in model.time_season for d in model.time_of_day } - keys: set[tuple[str, str]] = set(model.segment_fraction.sparse_iterkeys()) + keys: set[tuple[str, str]] = set(model.segment_fraction.sparse_keys()) if expected_keys != keys: extra: set[tuple[str, str]] = keys.difference(expected_keys) @@ -154,7 +154,7 @@ def validate_time_manual(model: TemoaModel) -> None: if model.time_sequencing.first() != 'manual': return - segment_fraction_sd: set[tuple[str, str]] = set(model.segment_fraction.sparse_iterkeys()) + segment_fraction_sd: set[tuple[str, str]] = set(model.segment_fraction.sparse_keys()) time_manual_sd: set[tuple[str, str]] = {(s, d) for s, d, s_next, d_next in model.time_manual} time_manual_sd_next: set[tuple[str, str]] = { (s_next, d_next) for s, d, s_next, d_next in model.time_manual diff --git a/temoa/model_checking/network_model_data.py b/temoa/model_checking/network_model_data.py index 22e815efc..1ff4e4488 100644 --- a/temoa/model_checking/network_model_data.py +++ b/temoa/model_checking/network_model_data.py @@ -170,7 +170,7 @@ def _build_from_model( raise NotImplementedError('Cannot build network data from model using a myopic_index') dem_com = defaultdict(set) - for r, p, d in model.demand.sparse_iterkeys(): + for r, p, d in model.demand.sparse_keys(): dem_com[r, p].add(d) techs: defaultdict[tuple[Region, Period], set[EdgeTuple]] = defaultdict(set) @@ -183,7 +183,7 @@ def _build_from_model( linked_techs = { LinkedTechTuple(r, driver, emission, driven) - for r, driver, emission, driven in model.linked_techs.sparse_iterkeys() + for r, driver, emission, driven in model.linked_techs.sparse_keys() } res = NetworkModelData( diff --git a/temoa/model_checking/pricing_check.py b/temoa/model_checking/pricing_check.py index a7027f4ea..03e9a4935 100644 --- a/temoa/model_checking/pricing_check.py +++ b/temoa/model_checking/pricing_check.py @@ -40,11 +40,10 @@ def price_checker(model: TemoaModel) -> bool: warnings = False # flag # some sets for x-checking registered_inv_costs = { - (region, tech, vintage) for (region, tech, vintage) in model.cost_invest.sparse_iterkeys() + (region, tech, vintage) for (region, tech, vintage) in model.cost_invest.sparse_keys() } efficiency_rtv = { - (region, tech, vintage) - for (region, _, tech, vintage, __) in model.efficiency.sparse_iterkeys() + (region, tech, vintage) for (region, _, tech, vintage, __) in model.efficiency.sparse_keys() } sorted_efficiency_rtv = sorted(efficiency_rtv, key=lambda rtv: (rtv[1], rtv[0], rtv[2])) @@ -58,11 +57,11 @@ def price_checker(model: TemoaModel) -> bool: # var costs for the period = vintage year base_year_variable_cost_rtv = set() - for r, p, t, v in model.cost_fixed.sparse_iterkeys(): + for r, p, t, v in model.cost_fixed.sparse_keys(): fixed_costs[r, t, v].add(p) if p == v: base_year_fixed_cost_rtv.add((r, t, v)) - for r, p, t, v in model.cost_variable.sparse_iterkeys(): + for r, p, t, v in model.cost_variable.sparse_keys(): var_costs[r, t, v].add(p) if p == v: base_year_variable_cost_rtv.add((r, t, v)) @@ -273,11 +272,11 @@ def check_tech_uncap(model: TemoaModel) -> bool: logger.debug('starting price check #4: uncapacitated techs') efficiency_rtv = { (region, tech, vintage) - for (region, _, tech, vintage, __) in model.efficiency.sparse_iterkeys() + for (region, _, tech, vintage, __) in model.efficiency.sparse_keys() if tech in model.tech_uncap } - fixed_cost_periods = {(r, t, v): p for r, p, t, v in model.cost_fixed.sparse_iterkeys()} + fixed_cost_periods = {(r, t, v): p for r, p, t, v in model.cost_fixed.sparse_keys()} rtv_with_fixed_cost = efficiency_rtv & set(fixed_cost_periods.keys()) if rtv_with_fixed_cost: logger.error( @@ -288,7 +287,7 @@ def check_tech_uncap(model: TemoaModel) -> bool: for rtv in rtv_with_fixed_cost: logger.error('%s: %s', rtv, fixed_cost_periods[rtv]) - rtv_with_invest_cost = efficiency_rtv & set(model.cost_invest.sparse_iterkeys()) + rtv_with_invest_cost = efficiency_rtv & set(model.cost_invest.sparse_keys()) if rtv_with_invest_cost: logger.error( 'The following technologies are labeled as unlimited capacity, but have an INVEST cost' @@ -298,7 +297,7 @@ def check_tech_uncap(model: TemoaModel) -> bool: var_cost_periods = defaultdict(set) # by starting from the cost side, we will naturally omit anything with NO var costs at all. - for r, p, t, v in model.cost_variable.sparse_iterkeys(): + for r, p, t, v in model.cost_variable.sparse_keys(): if (r, t, v) in efficiency_rtv: var_cost_periods[(r, t, v)].add(p) # use it to check for all/none var costs in viable periods @@ -333,7 +332,7 @@ def check_tech_uncap(model: TemoaModel) -> bool: capacity_params = (model.existing_capacity,) bad_cap_entries = False for param in capacity_params: - bad_entries = {(r, t, v) for r, t, v in param.sparse_iterkeys() if t in model.tech_uncap} + bad_entries = {(r, t, v) for r, t, v in param.sparse_keys() if t in model.tech_uncap} if bad_entries: for entry in bad_entries: logger.error( diff --git a/temoa/model_checking/validators.py b/temoa/model_checking/validators.py index 7ebf021fd..4db893b28 100644 --- a/temoa/model_checking/validators.py +++ b/temoa/model_checking/validators.py @@ -338,7 +338,7 @@ def validate_efficiency( def validate_reserve_margin(model: TemoaModel) -> None: - for r in model.planning_reserve_margin.sparse_iterkeys(): + for r in model.planning_reserve_margin.sparse_keys(): if all((r, p) not in model.process_reserve_periods for p in model.time_optimize): logger.warning( 'Planning reserve margin provided but there are no reserve technologies serving ' diff --git a/tests/test_full_runs.py b/tests/test_full_runs.py index cbd979f7e..de54159e7 100644 --- a/tests/test_full_runs.py +++ b/tests/test_full_runs.py @@ -76,7 +76,7 @@ def test_against_legacy_outputs( efficiency_param: pyo.Param = mdl.efficiency # check the set membership assert ( - len(tuple(efficiency_param.sparse_iterkeys())) == expected_vals[ExpectedVals.EFF_INDEX_SIZE] + len(tuple(efficiency_param.sparse_keys())) == expected_vals[ExpectedVals.EFF_INDEX_SIZE] ), 'should match legacy numbers' # check the size of the domain. NOTE: The build of the domain here may be "expensive" for From 6cc3594058708f0896515bf034824945fc2d14ca Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sat, 21 Mar 2026 19:27:40 -0400 Subject: [PATCH 505/587] tests(data): Replacing massive JSON set caches with deterministic hashes Includes fix to capture script so it uses the standard test configs --- tests/test_set_consistency.py | 50 +- tests/testing_data/mediumville_sets.json | 4251 +- tests/testing_data/test_system_sets.json | 43052 +--------------- tests/testing_data/utopia_sets.json | 24439 +-------- .../utilities/capture_set_values_for_cache.py | 29 +- 5 files changed, 390 insertions(+), 71431 deletions(-) diff --git a/tests/test_set_consistency.py b/tests/test_set_consistency.py index 23906ca4d..50a0f0a48 100644 --- a/tests/test_set_consistency.py +++ b/tests/test_set_consistency.py @@ -3,8 +3,10 @@ Utopia and Test System. """ +import hashlib import json import pathlib +from typing import Any import pytest from pyomo import environ as pyo @@ -44,39 +46,41 @@ def test_set_consistency( model_sets = built_instance.component_map(ctype=pyo.Set) model_sets = {k: set(v) for k, v in model_sets.items()} - # retrieve the cache and convert the set values from list -> set (json can't store sets) + def hash_set(s: Any) -> str: + try: + sorted_elements = sorted(s) + except TypeError: + sorted_elements = sorted([str(e) for e in s]) + s_bytes = json.dumps(sorted_elements).encode('utf-8') + return hashlib.sha256(s_bytes).hexdigest() + + # retrieve the cache which now stores hashes cache_file = pathlib.Path(__file__).parent / 'testing_data' / set_file with open(cache_file) as src: cached_sets = json.load(src) - cached_sets = { - k: {tuple(t) if isinstance(t, list) else t for t in v} for (k, v) in cached_sets.items() - } - # compare sets where they exist in the model. - overage_in_model = {} - shortage_in_model = {} + # compare hashes where they exist in the model. + mismatched_sets = {} for set_name, s in model_sets.items(): if set_name == 'cost_emission_rpe': pass - if cached_sets.get(set_name) != s: - cached_set = cached_sets.get(set_name, set()) - overage_in_model[set_name] = s - cached_set - shortage_in_model[set_name] = cached_set - s + if '_index' in set_name or '_domain' in set_name: + continue + + model_hash = hash_set(s) + cached_hash = cached_sets.get(set_name) + if cached_hash is not None and cached_hash != model_hash: + mismatched_sets[set_name] = {'cached': cached_hash, 'model': model_hash} + missing_in_model = cached_sets.keys() - model_sets.keys() # drop any set that has "_index" in the name as they are no longer reported by newer version of # pyomo missing_in_model = {s for s in missing_in_model if '_index' not in s and '_domain' not in s} - if overage_in_model: - print('\nOverages compared to cache: ') - for k, v in overage_in_model.items(): - if len(v) > 0: - print(k, v) - if shortage_in_model: - print('\nShortages compared to cache: ') - for k, v in shortage_in_model.items(): - if len(v) > 0: - print(k, v) + if mismatched_sets: + print('\nMismatched sets compared to cache (hashes differ): ') + for k, hashes in mismatched_sets.items(): + print(f'{k}: cached={hashes["cached"]}, model={hashes["model"]}') # look for new or dropped sets in EITHER model_extra_sets = { @@ -100,8 +104,8 @@ def test_set_consistency( print(f'{k}: {cached_sets[k]}') assert not missing_in_model, f'one or more cached set not in model: {missing_in_model}' - assert not overage_in_model and not shortage_in_model, ( - f'The {data_name} run-produced sets did not match cached values' + assert not mismatched_sets, ( + f'The {data_name} run-produced sets did not match cached values (hashes differ)' ) if cache_extra_sets: assert False, 'Cache has extra sets' # noqa B011 diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 4dd07b4e3..a3fca69f3 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -1,4138 +1,115 @@ { - "annual_commodity_balance_constraint_rpc": [], - "annual_retirement_var_rptv": [], - "baseload_diurnal_constraint_rpsdtv": [ - [ - "B", - 2025, - "s1", - "d1", - "EH", - 2025 - ], - [ - "A", - 2025, - "s2", - "d2", - "EH", - 2025 - ], - [ - "B", - 2025, - "s1", - "d2", - "EH", - 2025 - ], - [ - "A", - 2025, - "s1", - "d1", - "EH", - 2025 - ], - [ - "B", - 2025, - "s2", - "d2", - "EH", - 2025 - ], - [ - "A", - 2025, - "s1", - "d2", - "EH", - 2025 - ], - [ - "B", - 2025, - "s2", - "d1", - "EH", - 2025 - ], - [ - "A", - 2025, - "s2", - "d1", - "EH", - 2025 - ] - ], - "capacity_annual_constraint_rptv": [ - [ - "A", - 2025, - "GeoThermal", - 2025 - ], - [ - "B", - 2025, - "GeoThermal", - 2025 - ] - ], - "capacity_available_var_rpt": [ - [ - "A-B", - 2025, - "FGF_pipe" - ], - [ - "B", - 2025, - "bulbs" - ], - [ - "A", - 2025, - "GeoThermal" - ], - [ - "B", - 2025, - "well" - ], - [ - "B", - 2025, - "GeoThermal" - ], - [ - "A", - 2025, - "GeoHeater" - ], - [ - "B", - 2025, - "heater" - ], - [ - "A", - 2025, - "EH" - ], - [ - "A", - 2025, - "EFL" - ], - [ - "A", - 2025, - "EF" - ], - [ - "A", - 2025, - "heater" - ], - [ - "A", - 2025, - "bulbs" - ], - [ - "B-A", - 2025, - "FGF_pipe" - ], - [ - "B", - 2025, - "batt" - ], - [ - "B", - 2025, - "GeoHeater" - ], - [ - "B", - 2025, - "EF" - ], - [ - "B", - 2025, - "EH" - ], - [ - "A", - 2025, - "well" - ] - ], - "capacity_constraint_rpsdtv": [ - [ - "A", - 2025, - "s2", - "d2", - "heater", - 2025 - ], - [ - "A", - 2025, - "s2", - "d1", - "EFL", - 2025 - ], - [ - "B", - 2025, - "s1", - "d1", - "EF", - 2025 - ], - [ - "B", - 2025, - "s2", - "d2", - "heater", - 2025 - ], - [ - "B", - 2025, - "s2", - "d1", - "bulbs", - 2025 - ], - [ - "B-A", - 2025, - "s2", - "d1", - "FGF_pipe", - 2025 - ], - [ - "A", - 2025, - "s1", - "d2", - "heater", - 2025 - ], - [ - "A", - 2025, - "s2", - "d1", - "well", - 2025 - ], - [ - "B", - 2025, - "s2", - "d2", - "EH", - 2025 - ], - [ - "A-B", - 2025, - "s2", - "d1", - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "s1", - "d1", - "well", - 2025 - ], - [ - "B", - 2025, - "s1", - "d2", - "bulbs", - 2025 - ], - [ - "A", - 2025, - "s2", - "d1", - "EF", - 2025 - ], - [ - "A", - 2025, - "s1", - "d2", - "EH", - 2025 - ], - [ - "A", - 2025, - "s1", - "d2", - "GeoHeater", - 2025 - ], - [ - "B", - 2025, - "s2", - "d1", - "EH", - 2025 - ], - [ - "A-B", - 2025, - "s1", - "d1", - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "s2", - "d1", - "GeoHeater", - 2025 - ], - [ - "A", - 2025, - "s2", - "d1", - "bulbs", - 2025 - ], - [ - "B", - 2025, - "s1", - "d2", - "EH", - 2025 - ], - [ - "B", - 2025, - "s2", - "d2", - "GeoHeater", - 2025 - ], - [ - "B", - 2025, - "s2", - "d1", - "heater", - 2025 - ], - [ - "B", - 2025, - "s1", - "d2", - "GeoHeater", - 2025 - ], - [ - "A", - 2025, - "s1", - "d1", - "EF", - 2025 - ], - [ - "A", - 2025, - "s2", - "d2", - "EFL", - 2025 - ], - [ - "B-A", - 2025, - "s1", - "d2", - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "s1", - "d2", - "heater", - 2025 - ], - [ - "A", - 2025, - "s1", - "d1", - "EFL", - 2025 - ], - [ - "B", - 2025, - "s1", - "d1", - "bulbs", - 2025 - ], - [ - "B-A", - 2025, - "s1", - "d1", - "FGF_pipe", - 2025 - ], - [ - "A", - 2025, - "s1", - "d1", - "well", - 2025 - ], - [ - "A", - 2025, - "s2", - "d2", - "EF", - 2025 - ], - [ - "A-B", - 2025, - "s2", - "d2", - "FGF_pipe", - 2025 - ], - [ - "A", - 2025, - "s2", - "d1", - "EH", - 2025 - ], - [ - "A", - 2025, - "s2", - "d2", - "GeoHeater", - 2025 - ], - [ - "A", - 2025, - "s2", - "d2", - "well", - 2025 - ], - [ - "B", - 2025, - "s1", - "d1", - "EH", - 2025 - ], - [ - "B", - 2025, - "s1", - "d1", - "heater", - 2025 - ], - [ - "A", - 2025, - "s2", - "d1", - "heater", - 2025 - ], - [ - "B", - 2025, - "s1", - "d1", - "GeoHeater", - 2025 - ], - [ - "A", - 2025, - "s2", - "d1", - "GeoHeater", - 2025 - ], - [ - "A", - 2025, - "s1", - "d1", - "bulbs", - 2025 - ], - [ - "B", - 2025, - "s2", - "d2", - "well", - 2025 - ], - [ - "A", - 2025, - "s1", - "d2", - "EFL", - 2025 - ], - [ - "A", - 2025, - "s1", - "d2", - "well", - 2025 - ], - [ - "A", - 2025, - "s1", - "d2", - "EF", - 2025 - ], - [ - "B", - 2025, - "s2", - "d2", - "EF", - 2025 - ], - [ - "A", - 2025, - "s2", - "d2", - "bulbs", - 2025 - ], - [ - "B", - 2025, - "s2", - "d1", - "well", - 2025 - ], - [ - "A", - 2025, - "s1", - "d1", - "heater", - 2025 - ], - [ - "A", - 2025, - "s2", - "d2", - "EH", - 2025 - ], - [ - "B", - 2025, - "s1", - "d2", - "EF", - 2025 - ], - [ - "A-B", - 2025, - "s1", - "d2", - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "s2", - "d1", - "EF", - 2025 - ], - [ - "A", - 2025, - "s1", - "d1", - "GeoHeater", - 2025 - ], - [ - "A", - 2025, - "s1", - "d1", - "EH", - 2025 - ], - [ - "B", - 2025, - "s1", - "d2", - "well", - 2025 - ], - [ - "A", - 2025, - "s1", - "d2", - "bulbs", - 2025 - ], - [ - "B-A", - 2025, - "s2", - "d2", - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "s2", - "d2", - "bulbs", - 2025 - ] - ], - "capacity_factor_rsdt": [ - [ - "A", - "s2", - "d2", - "bulbs" - ], - [ - "B", - "s1", - "d1", - "well" - ], - [ - "B", - "s2", - "d1", - "heater" - ], - [ - "B", - "s2", - "d1", - "EH" - ], - [ - "A", - "s1", - "d2", - "bulbs" - ], - [ - "B", - "s1", - "d2", - "well" - ], - [ - "B", - "s2", - "d1", - "EF" - ], - [ - "B", - "s2", - "d2", - "EH" - ], - [ - "B", - "s2", - "d2", - "EF" - ], - [ - "B", - "s2", - "d2", - "heater" - ], - [ - "A", - "s2", - "d1", - "well" - ], - [ - "B", - "s1", - "d1", - "EH" - ], - [ - "B", - "s1", - "d1", - "EF" - ], - [ - "B", - "s1", - "d1", - "heater" - ], - [ - "A", - "s1", - "d1", - "well" - ], - [ - "B", - "s1", - "d2", - "heater" - ], - [ - "B", - "s1", - "d2", - "EH" - ], - [ - "A", - "s2", - "d1", - "heater" - ], - [ - "B", - "s1", - "d2", - "EF" - ], - [ - "A", - "s2", - "d1", - "EH" - ], - [ - "A", - "s2", - "d1", - "EF" - ], - [ - "B", - "s2", - "d1", - "GeoHeater" - ], - [ - "B-A", - "s2", - "d1", - "FGF_pipe" - ], - [ - "A", - "s1", - "d1", - "EH" - ], - [ - "B", - "s2", - "d2", - "GeoHeater" - ], - [ - "B-A", - "s2", - "d2", - "FGF_pipe" - ], - [ - "A", - "s2", - "d2", - "well" - ], - [ - "A", - "s1", - "d1", - "EF" - ], - [ - "A", - "s1", - "d1", - "heater" - ], - [ - "B", - "s1", - "d1", - "GeoHeater" - ], - [ - "B-A", - "s1", - "d1", - "FGF_pipe" - ], - [ - "B", - "s2", - "d1", - "GeoThermal" - ], - [ - "A", - "s1", - "d2", - "well" - ], - [ - "B-A", - "s1", - "d2", - "FGF_pipe" - ], - [ - "A", - "s2", - "d2", - "heater" - ], - [ - "B", - "s1", - "d2", - "GeoHeater" - ], - [ - "A", - "s2", - "d2", - "EH" - ], - [ - "B", - "s2", - "d2", - "GeoThermal" - ], - [ - "A", - "s2", - "d1", - "GeoHeater" - ], - [ - "A", - "s2", - "d2", - "EF" - ], - [ - "A", - "s2", - "d1", - "EFL" - ], - [ - "B", - "s1", - "d1", - "GeoThermal" - ], - [ - "A", - "s1", - "d2", - "EH" - ], - [ - "B", - "s1", - "d2", - "GeoThermal" - ], - [ - "A", - "s1", - "d1", - "GeoHeater" - ], - [ - "A", - "s1", - "d2", - "EF" - ], - [ - "A", - "s2", - "d1", - "GeoThermal" - ], - [ - "A", - "s1", - "d1", - "EFL" - ], - [ - "A", - "s1", - "d2", - "heater" - ], - [ - "B", - "s2", - "d1", - "bulbs" - ], - [ - "B", - "s2", - "d2", - "bulbs" - ], - [ - "B", - "s1", - "d1", - "bulbs" - ], - [ - "A", - "s2", - "d2", - "GeoHeater" - ], - [ - "A", - "s1", - "d1", - "GeoThermal" - ], - [ - "A", - "s2", - "d2", - "EFL" - ], - [ - "B", - "s2", - "d1", - "batt" - ], - [ - "A-B", - "s2", - "d2", - "FGF_pipe" - ], - [ - "B", - "s1", - "d2", - "bulbs" - ], - [ - "A", - "s1", - "d2", - "GeoHeater" - ], - [ - "A", - "s2", - "d1", - "bulbs" - ], - [ - "A", - "s2", - "d2", - "GeoThermal" - ], - [ - "A", - "s1", - "d2", - "EFL" - ], - [ - "B", - "s1", - "d1", - "batt" - ], - [ - "A-B", - "s1", - "d2", - "FGF_pipe" - ], - [ - "B", - "s2", - "d2", - "batt" - ], - [ - "A", - "s1", - "d1", - "bulbs" - ], - [ - "A-B", - "s2", - "d1", - "FGF_pipe" - ], - [ - "B", - "s1", - "d2", - "batt" - ], - [ - "B", - "s2", - "d1", - "well" - ], - [ - "A", - "s1", - "d2", - "GeoThermal" - ], - [ - "A-B", - "s1", - "d1", - "FGF_pipe" - ], - [ - "B", - "s2", - "d2", - "well" - ] - ], - "capacity_var_rptv": [ - [ - "A", - 2025, - "GeoThermal", - 2025 - ], - [ - "A", - 2025, - "EF", - 2025 - ], - [ - "A", - 2025, - "GeoHeater", - 2025 - ], - [ - "A-B", - 2025, - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "well", - 2025 - ], - [ - "A", - 2025, - "heater", - 2025 - ], - [ - "B", - 2025, - "bulbs", - 2025 - ], - [ - "B", - 2025, - "GeoThermal", - 2025 - ], - [ - "B", - 2025, - "EF", - 2025 - ], - [ - "A", - 2025, - "EH", - 2025 - ], - [ - "B", - 2025, - "heater", - 2025 - ], - [ - "B", - 2025, - "GeoHeater", - 2025 - ], - [ - "A", - 2025, - "EFL", - 2025 - ], - [ - "A", - 2025, - "bulbs", - 2025 - ], - [ - "B", - 2025, - "batt", - 2025 - ], - [ - "B-A", - 2025, - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "EH", - 2025 - ], - [ - "A", - 2025, - "well", - 2025 - ] - ], - "commodity_balance_constraint_rpsdc": [ - [ - "B", - 2025, - "s1", - "d1", - "ELC" - ], - [ - "B", - 2025, - "s2", - "d1", - "GeoHyd" - ], - [ - "A", - 2025, - "s1", - "d1", - "HYD" - ], - [ - "B", - 2025, - "s1", - "d2", - "ELC" - ], - [ - "A", - 2025, - "s2", - "d1", - "ELC" - ], - [ - "B", - 2025, - "s1", - "d1", - "GeoHyd" - ], - [ - "B", - 2025, - "s2", - "d2", - "GeoHyd" - ], - [ - "B", - 2025, - "s2", - "d1", - "FusionGasFuel" - ], - [ - "A", - 2025, - "s1", - "d1", - "ELC" - ], - [ - "A", - 2025, - "s2", - "d2", - "HYD" - ], - [ - "B", - 2025, - "s1", - "d2", - "GeoHyd" - ], - [ - "B", - 2025, - "s1", - "d1", - "FusionGasFuel" - ], - [ - "A", - 2025, - "s2", - "d1", - "GeoHyd" - ], - [ - "B", - 2025, - "s2", - "d2", - "FusionGasFuel" - ], - [ - "A", - 2025, - "s1", - "d2", - "HYD" - ], - [ - "B", - 2025, - "s1", - "d2", - "FusionGasFuel" - ], - [ - "A", - 2025, - "s1", - "d1", - "GeoHyd" - ], - [ - "A", - 2025, - "s2", - "d2", - "ELC" - ], - [ - "A", - 2025, - "s2", - "d1", - "FusionGasFuel" - ], - [ - "A", - 2025, - "s1", - "d2", - "ELC" - ], - [ - "A", - 2025, - "s1", - "d1", - "FusionGasFuel" - ], - [ - "A", - 2025, - "s2", - "d2", - "GeoHyd" - ], - [ - "A", - 2025, - "s1", - "d2", - "GeoHyd" - ], - [ - "A", - 2025, - "s2", - "d2", - "FusionGasFuel" - ], - [ - "A", - 2025, - "s1", - "d2", - "FusionGasFuel" - ], - [ - "B", - 2025, - "s2", - "d1", - "HYD" - ], - [ - "B", - 2025, - "s1", - "d1", - "HYD" - ], - [ - "B", - 2025, - "s2", - "d2", - "HYD" - ], - [ - "B", - 2025, - "s2", - "d1", - "ELC" - ], - [ - "B", - 2025, - "s2", - "d2", - "ELC" - ], - [ - "B", - 2025, - "s1", - "d2", - "HYD" - ], - [ - "A", - 2025, - "s2", - "d1", - "HYD" - ] - ], - "cost_emission_rpe": [ - [ - "A", - 2025, - "co2" - ] - ], - "cost_fixed_rptv": [ - [ - "A", - 2025, - "GeoThermal", - 2025 - ], - [ - "A", - 2025, - "EF", - 2025 - ], - [ - "A", - 2025, - "GeoHeater", - 2025 - ], - [ - "A-B", - 2025, - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "well", - 2025 - ], - [ - "A", - 2025, - "heater", - 2025 - ], - [ - "B", - 2025, - "bulbs", - 2025 - ], - [ - "B", - 2025, - "GeoThermal", - 2025 - ], - [ - "B", - 2025, - "EF", - 2025 - ], - [ - "A", - 2025, - "EH", - 2025 - ], - [ - "B", - 2025, - "heater", - 2025 - ], - [ - "B", - 2025, - "GeoHeater", - 2025 - ], - [ - "A", - 2025, - "EFL", - 2025 - ], - [ - "A", - 2025, - "bulbs", - 2025 - ], - [ - "B", - 2025, - "batt", - 2025 - ], - [ - "B-A", - 2025, - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "EH", - 2025 - ], - [ - "A", - 2025, - "well", - 2025 - ] - ], - "cost_invest_rtv": [ - [ - "A", - "heater", - 2025 - ], - [ - "B", - "EF", - 2025 - ], - [ - "A", - "EH", - 2025 - ], - [ - "B", - "GeoHeater", - 2025 - ], - [ - "A", - "GeoHeater", - 2025 - ], - [ - "B", - "heater", - 2025 - ], - [ - "A", - "EFL", - 2025 - ], - [ - "B", - "EH", - 2025 - ], - [ - "B", - "batt", - 2025 - ], - [ - "A", - "bulbs", - 2025 - ], - [ - "A", - "GeoThermal", - 2025 - ], - [ - "A", - "EF", - 2025 - ], - [ - "B", - "bulbs", - 2025 - ], - [ - "B", - "GeoThermal", - 2025 - ] - ], - "cost_variable_rptv": [ - [ - "A", - 2025, - "GeoThermal", - 2025 - ], - [ - "A", - 2025, - "EF", - 2025 - ], - [ - "A", - 2025, - "GeoHeater", - 2025 - ], - [ - "B", - 2025, - "well", - 2025 - ], - [ - "A-B", - 2025, - "FGF_pipe", - 2025 - ], - [ - "A", - 2025, - "heater", - 2025 - ], - [ - "B", - 2025, - "bulbs", - 2025 - ], - [ - "B", - 2025, - "GeoThermal", - 2025 - ], - [ - "B", - 2025, - "EF", - 2025 - ], - [ - "A", - 2025, - "EH", - 2025 - ], - [ - "B", - 2025, - "heater", - 2025 - ], - [ - "B", - 2025, - "GeoHeater", - 2025 - ], - [ - "A", - 2025, - "EFL", - 2025 - ], - [ - "A", - 2025, - "bulbs", - 2025 - ], - [ - "B", - 2025, - "batt", - 2025 - ], - [ - "B-A", - 2025, - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "EH", - 2025 - ], - [ - "A", - 2025, - "well", - 2025 - ] - ], - "curtailment_var_rpsditvo": [ - [ - "A", - 2025, - "s1", - "d2", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s2", - "d1", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s2", - "d1", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s1", - "d1", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s2", - "d2", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s1", - "d2", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s1", - "d1", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s2", - "d2", - "HYD", - "EH", - 2025, - "ELC" - ] - ], - "demand_activity_constraint_rpsdtv_dem": [ - [ - "B", - 2025, - "s2", - "d2", - "GeoHeater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s1", - "d2", - "heater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s1", - "d1", - "heater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s2", - "d1", - "GeoHeater", - 2025, - "RH" - ], - [ - "A", - 2025, - "s1", - "d2", - "heater", - 2025, - "RH" - ], - [ - "A", - 2025, - "s2", - "d1", - "GeoHeater", - 2025, - "RH" - ], - [ - "A", - 2025, - "s1", - "d2", - "GeoHeater", - 2025, - "RH" - ], - [ - "A", - 2025, - "s2", - "d2", - "heater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s1", - "d2", - "GeoHeater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s2", - "d2", - "heater", - 2025, - "RH" - ], - [ - "A", - 2025, - "s2", - "d2", - "GeoHeater", - 2025, - "RH" - ], - [ - "A", - 2025, - "s1", - "d1", - "GeoHeater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s1", - "d1", - "GeoHeater", - 2025, - "RH" - ], - [ - "A", - 2025, - "s2", - "d1", - "heater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s2", - "d1", - "heater", - 2025, - "RH" - ], - [ - "A", - 2025, - "s1", - "d1", - "heater", - 2025, - "RH" - ] - ], - "demand_constraint_rpc": [ - [ - "B", - 2025, - "RH" - ], - [ - "A", - 2025, - "RH" - ], - [ - "B", - 2025, - "RL" - ], - [ - "A", - 2025, - "RL" - ] - ], - "emission_activity_reitvo": [ - [ - "B", - "FusionGas", - "earth", - "GeoThermal", - 2025, - "GeoHyd" - ], - [ - "A", - "FusionGas", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "B", - "FusionGas", - "ELC", - "batt", - 2025, - "ELC" - ], - [ - "B", - "FusionGas", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "A", - "FusionGas", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A", - "co2", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "A", - "FusionGas", - "earth", - "EFL", - 2025, - "FusionGasFuel" - ], - [ - "B", - "co2", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "A", - "FusionGas", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "B", - "FusionGas", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "B", - "FusionGas", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "B", - "FusionGas", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "B", - "co2", - "earth", - "GeoThermal", - 2025, - "GeoHyd" - ], - [ - "B", - "co2", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "A", - "FusionGas", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "A", - "co2", - "earth", - "well", - 2025, - "HYD" - ], - [ - "B", - "co2", - "ELC", - "batt", - 2025, - "ELC" - ], - [ - "A", - "co2", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "B", - "co2", - "earth", - "well", - 2025, - "HYD" - ], - [ - "A", - "co2", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A", - "FusionGas", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "B", - "co2", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "B", - "FusionGas", - "earth", - "well", - 2025, - "HYD" - ], - [ - "A", - "co2", - "earth", - "GeoThermal", - 2025, - "GeoHyd" - ], - [ - "A", - "co2", - "earth", - "EFL", - 2025, - "FusionGasFuel" - ], - [ - "A", - "FusionGas", - "earth", - "GeoThermal", - 2025, - "GeoHyd" - ], - [ - "B", - "co2", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "A", - "FusionGas", - "earth", - "well", - 2025, - "HYD" - ], - [ - "A", - "co2", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "B", - "FusionGas", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "B", - "co2", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A", - "co2", - "ELC", - "bulbs", - 2025, - "RL" - ] - ], - "flex_var_annual_rpitvo": [], - "flex_var_rpsditvo": [ - [ - "A", - 2025, - "s2", - "d2", - "earth", - "EFL", - 2025, - "FusionGasFuel" - ], - [ - "A", - 2025, - "s2", - "d1", - "earth", - "EFL", - 2025, - "FusionGasFuel" - ], - [ - "A", - 2025, - "s1", - "d2", - "earth", - "EFL", - 2025, - "FusionGasFuel" - ], - [ - "A", - 2025, - "s1", - "d1", - "earth", - "EFL", - 2025, - "FusionGasFuel" - ] - ], - "flow_in_storage_rpsditvo": [ - [ - "B", - 2025, - "s1", - "d1", - "ELC", - "batt", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s2", - "d1", - "ELC", - "batt", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s2", - "d2", - "ELC", - "batt", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s1", - "d2", - "ELC", - "batt", - 2025, - "ELC" - ] - ], - "flow_var_annual_rpitvo": [ - [ - "B", - 2025, - "earth", - "GeoThermal", - 2025, - "GeoHyd" - ], - [ - "B", - 2025, - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "B", - 2025, - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "A", - 2025, - "earth", - "GeoThermal", - 2025, - "GeoHyd" - ], - [ - "A", - 2025, - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "B", - 2025, - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "A", - 2025, - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "A", - 2025, - "FusionGasFuel", - "heater", - 2025, - "RH" - ] - ], - "flow_var_rpsditvo": [ - [ - "B", - 2025, - "s2", - "d2", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "A", - 2025, - "s1", - "d2", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "A", - 2025, - "s1", - "d1", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s2", - "d1", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "B", - 2025, - "s2", - "d2", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "A", - 2025, - "s1", - "d1", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s1", - "d2", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s1", - "d2", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "B", - 2025, - "s1", - "d1", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s2", - "d2", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "A", - 2025, - "s1", - "d1", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "A", - 2025, - "s2", - "d1", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "A", - 2025, - "s2", - "d2", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "A", - 2025, - "s2", - "d2", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "A", - 2025, - "s1", - "d2", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s1", - "d2", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "A", - 2025, - "s2", - "d1", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s2", - "d1", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "A", - 2025, - "s2", - "d1", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "B", - 2025, - "s2", - "d1", - "GeoHyd", - "GeoHeater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s1", - "d1", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "A", - 2025, - "s1", - "d2", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "B", - 2025, - "s1", - "d1", - "ELC", - "bulbs", - 2025, - "RL" - ], - [ - "A", - 2025, - "s2", - "d2", - "FusionGasFuel", - "heater", - 2025, - "RH" - ], - [ - "A", - 2025, - "s2", - "d2", - "earth", - "EFL", - 2025, - "FusionGasFuel" - ], - [ - "B", - 2025, - "s1", - "d2", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s2", - "d2", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s2", - "d2", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s2", - "d2", - "ELC", - "batt", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s2", - "d2", - "earth", - "well", - 2025, - "HYD" - ], - [ - "B", - 2025, - "s2", - "d1", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s2", - "d1", - "earth", - "EFL", - 2025, - "FusionGasFuel" - ], - [ - "A", - 2025, - "s1", - "d1", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "A-B", - 2025, - "s1", - "d2", - "FusionGasFuel", - "FGF_pipe", - 2025, - "FusionGasFuel" - ], - [ - "B", - 2025, - "s2", - "d2", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s2", - "d1", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "B-A", - 2025, - "s1", - "d1", - "FusionGasFuel", - "FGF_pipe", - 2025, - "FusionGasFuel" - ], - [ - "B", - 2025, - "s1", - "d1", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "B-A", - 2025, - "s1", - "d2", - "FusionGasFuel", - "FGF_pipe", - 2025, - "FusionGasFuel" - ], - [ - "A", - 2025, - "s1", - "d1", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s2", - "d1", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s1", - "d1", - "earth", - "well", - 2025, - "HYD" - ], - [ - "A", - 2025, - "s1", - "d1", - "earth", - "EFL", - 2025, - "FusionGasFuel" - ], - [ - "B-A", - 2025, - "s2", - "d2", - "FusionGasFuel", - "FGF_pipe", - 2025, - "FusionGasFuel" - ], - [ - "A", - 2025, - "s1", - "d2", - "earth", - "EFL", - 2025, - "FusionGasFuel" - ], - [ - "A", - 2025, - "s2", - "d1", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s2", - "d1", - "ELC", - "batt", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s2", - "d1", - "earth", - "well", - 2025, - "HYD" - ], - [ - "A", - 2025, - "s1", - "d2", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "B-A", - 2025, - "s2", - "d1", - "FusionGasFuel", - "FGF_pipe", - 2025, - "FusionGasFuel" - ], - [ - "A-B", - 2025, - "s1", - "d1", - "FusionGasFuel", - "FGF_pipe", - 2025, - "FusionGasFuel" - ], - [ - "A", - 2025, - "s2", - "d1", - "earth", - "well", - 2025, - "HYD" - ], - [ - "A", - 2025, - "s2", - "d2", - "earth", - "well", - 2025, - "HYD" - ], - [ - "B", - 2025, - "s1", - "d1", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "A-B", - 2025, - "s2", - "d1", - "FusionGasFuel", - "FGF_pipe", - 2025, - "FusionGasFuel" - ], - [ - "B", - 2025, - "s1", - "d2", - "earth", - "well", - 2025, - "HYD" - ], - [ - "A-B", - 2025, - "s2", - "d2", - "FusionGasFuel", - "FGF_pipe", - 2025, - "FusionGasFuel" - ], - [ - "B", - 2025, - "s1", - "d2", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s1", - "d2", - "HYD", - "EH", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s1", - "d2", - "earth", - "well", - 2025, - "HYD" - ], - [ - "A", - 2025, - "s2", - "d2", - "HYD", - "EF", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s1", - "d2", - "ELC", - "batt", - 2025, - "ELC" - ], - [ - "B", - 2025, - "s1", - "d1", - "ELC", - "batt", - 2025, - "ELC" - ], - [ - "A", - 2025, - "s1", - "d1", - "earth", - "well", - 2025, - "HYD" - ] - ], - "lifetime_process_rtv": [ - [ - "A", - "heater", - 2025 - ], - [ - "B", - "EF", - 2025 - ], - [ - "B-A", - "FGF_pipe", - 2025 - ], - [ - "A-B", - "FGF_pipe", - 2025 - ], - [ - "A", - "EH", - 2025 - ], - [ - "B", - "bulbs", - 2025 - ], - [ - "A", - "GeoHeater", - 2025 - ], - [ - "B", - "heater", - 2025 - ], - [ - "A", - "EFL", - 2025 - ], - [ - "B", - "EH", - 2025 - ], - [ - "B", - "batt", - 2025 - ], - [ - "A", - "well", - 2025 - ], - [ - "A", - "GeoThermal", - 2025 - ], - [ - "B", - "GeoHeater", - 2025 - ], - [ - "B", - "well", - 2025 - ], - [ - "A", - "EF", - 2025 - ], - [ - "A", - "bulbs", - 2025 - ], - [ - "B", - "GeoThermal", - 2025 - ] - ], - "limit_activity_constraint_rpt": [ - [ - "B", - 2025, - "EH", - "le" - ], - [ - "A", - 2025, - "EF", - "le" - ], - [ - "A", - 2025, - "EF", - "ge" - ], - [ - "A", - 2025, - "A_tech_grp_1", - "le" - ], - [ - "A", - 2025, - "A_tech_grp_1", - "ge" - ] - ], - "limit_activity_share_constraint_rpgg": [], - "limit_annual_capacity_factor_constraint_rptvo": [], - "limit_annual_capacity_factor_constraint_rtvo": [], - "limit_capacity_constraint_rpt": [ - [ - "B", - 2025, - "batt", - "ge" - ], - [ - "A", - 2025, - "EH", - "ge" - ], - [ - "B", - 2025, - "EH", - "le" - ], - [ - "A", - 2025, - "EH", - "le" - ], - [ - "A", - 2025, - "A_tech_grp_1", - "le" - ], - [ - "A", - 2025, - "A_tech_grp_1", - "ge" - ] - ], - "limit_capacity_share_constraint_rpgg": [], - "limit_degrowth_capacity_constraint_rpt": [], - "limit_degrowth_new_capacity_constraint_rpt": [], - "limit_degrowth_new_capacity_delta_constraint_rpt": [], - "limit_emission_constraint_rpe": [ - [ - "A", - 2025, - "co2", - "le" - ] - ], - "limit_growth_capacity_constraint_rpt": [], - "limit_growth_new_capacity_constraint_rpt": [], - "limit_growth_new_capacity_delta_constraint_rpt": [], - "limit_new_capacity_constraint_rtv": [], - "limit_new_capacity_share_constraint_rggv": [ - [ - "A", - "RPS_common", - "A_tech_grp_1", - 2025, - "ge" - ], - [ - "global", - "RPS_common", - "A_tech_grp_1", - 2025, - "le" - ] - ], - "limit_resource_constraint_rt": [ - [ - "B", - "EF", - "le" - ] - ], - "limit_seasonal_capacity_factor_constraint_rpst": [], - "limit_seasonal_capacity_factor_constraint_rst": [], - "limit_storage_fraction_constraint_rpsdtv": [], - "limit_storage_fraction_param_rsdt": [], - "limit_tech_input_split_annual_constraint_rpitv": [], - "limit_tech_input_split_average_constraint_rpitv": [], - "limit_tech_input_split_constraint_rpsditv": [ - [ - "A", - 2025, - "s1", - "d1", - "HYD", - "EH", - 2025, - "ge" - ], - [ - "A", - 2025, - "s2", - "d1", - "HYD", - "EH", - 2025, - "ge" - ], - [ - "A", - 2025, - "s2", - "d2", - "HYD", - "EH", - 2025, - "ge" - ], - [ - "A", - 2025, - "s1", - "d2", - "HYD", - "EH", - 2025, - "ge" - ] - ], - "limit_tech_output_split_annual_constraint_rptvo": [], - "limit_tech_output_split_average_constraint_rptvo": [], - "limit_tech_output_split_constraint_rpsdtvo": [ - [ - "B", - 2025, - "s2", - "d1", - "EH", - 2025, - "ELC", - "ge" - ], - [ - "B", - 2025, - "s2", - "d2", - "EH", - 2025, - "ELC", - "ge" - ], - [ - "B", - 2025, - "s1", - "d1", - "EH", - 2025, - "ELC", - "ge" - ], - [ - "B", - 2025, - "s1", - "d2", - "EH", - 2025, - "ELC", - "ge" - ] - ], - "linked_emissions_tech_constraint_rpsdtve": [ - [ - "A", - 2025, - "s1", - "d2", - "EF", - 2025, - "FusionGas" - ], - [ - "A", - 2025, - "s2", - "d2", - "EF", - 2025, - "FusionGas" - ], - [ - "A", - 2025, - "s1", - "d1", - "EF", - 2025, - "FusionGas" - ], - [ - "A", - 2025, - "s2", - "d1", - "EF", - 2025, - "FusionGas" - ] - ], - "loan_lifetime_process_rtv": [ - [ - "A", - "heater", - 2025 - ], - [ - "B", - "EF", - 2025 - ], - [ - "B-A", - "FGF_pipe", - 2025 - ], - [ - "A-B", - "FGF_pipe", - 2025 - ], - [ - "A", - "EH", - 2025 - ], - [ - "B", - "bulbs", - 2025 - ], - [ - "A", - "GeoHeater", - 2025 - ], - [ - "B", - "heater", - 2025 - ], - [ - "A", - "EFL", - 2025 - ], - [ - "B", - "EH", - 2025 - ], - [ - "B", - "batt", - 2025 - ], - [ - "A", - "well", - 2025 - ], - [ - "A", - "GeoThermal", - 2025 - ], - [ - "B", - "GeoHeater", - 2025 - ], - [ - "B", - "well", - 2025 - ], - [ - "A", - "EF", - 2025 - ], - [ - "A", - "bulbs", - 2025 - ], - [ - "B", - "GeoThermal", - 2025 - ] - ], - "new_capacity_var_rtv": [ - [ - "A", - "heater", - 2025 - ], - [ - "B", - "EF", - 2025 - ], - [ - "B-A", - "FGF_pipe", - 2025 - ], - [ - "A-B", - "FGF_pipe", - 2025 - ], - [ - "A", - "EH", - 2025 - ], - [ - "B", - "bulbs", - 2025 - ], - [ - "A", - "GeoHeater", - 2025 - ], - [ - "B", - "heater", - 2025 - ], - [ - "A", - "EFL", - 2025 - ], - [ - "B", - "EH", - 2025 - ], - [ - "B", - "batt", - 2025 - ], - [ - "A", - "well", - 2025 - ], - [ - "A", - "GeoThermal", - 2025 - ], - [ - "B", - "GeoHeater", - 2025 - ], - [ - "B", - "well", - 2025 - ], - [ - "A", - "EF", - 2025 - ], - [ - "A", - "bulbs", - 2025 - ], - [ - "B", - "GeoThermal", - 2025 - ] - ], - "process_life_frac_rptv": [ - [ - "A", - 2025, - "GeoThermal", - 2025 - ], - [ - "A", - 2025, - "EF", - 2025 - ], - [ - "A", - 2025, - "GeoHeater", - 2025 - ], - [ - "B", - 2025, - "well", - 2025 - ], - [ - "A-B", - 2025, - "FGF_pipe", - 2025 - ], - [ - "A", - 2025, - "heater", - 2025 - ], - [ - "B", - 2025, - "bulbs", - 2025 - ], - [ - "B", - 2025, - "GeoThermal", - 2025 - ], - [ - "B", - 2025, - "EF", - 2025 - ], - [ - "A", - 2025, - "EH", - 2025 - ], - [ - "B", - 2025, - "heater", - 2025 - ], - [ - "B", - 2025, - "GeoHeater", - 2025 - ], - [ - "A", - 2025, - "EFL", - 2025 - ], - [ - "A", - 2025, - "bulbs", - 2025 - ], - [ - "B", - 2025, - "batt", - 2025 - ], - [ - "B-A", - 2025, - "FGF_pipe", - 2025 - ], - [ - "B", - 2025, - "EH", - 2025 - ], - [ - "A", - 2025, - "well", - 2025 - ] - ], - "ramp_down_day_constraint_rpsdtv": [ - [ - "B", - 2025, - "s1", - "d1", - "EH", - 2025 - ], - [ - "A", - 2025, - "s2", - "d2", - "EH", - 2025 - ], - [ - "B", - 2025, - "s1", - "d2", - "EH", - 2025 - ], - [ - "A", - 2025, - "s1", - "d1", - "EH", - 2025 - ], - [ - "B", - 2025, - "s2", - "d2", - "EH", - 2025 - ], - [ - "A", - 2025, - "s1", - "d2", - "EH", - 2025 - ], - [ - "B", - 2025, - "s2", - "d1", - "EH", - 2025 - ], - [ - "A", - 2025, - "s2", - "d1", - "EH", - 2025 - ] - ], - "ramp_down_season_constraint_rpsstv": [], - "ramp_up_day_constraint_rpsdtv": [ - [ - "B", - 2025, - "s1", - "d1", - "EH", - 2025 - ], - [ - "A", - 2025, - "s2", - "d2", - "EH", - 2025 - ], - [ - "B", - 2025, - "s1", - "d2", - "EH", - 2025 - ], - [ - "A", - 2025, - "s1", - "d1", - "EH", - 2025 - ], - [ - "B", - 2025, - "s2", - "d2", - "EH", - 2025 - ], - [ - "A", - 2025, - "s1", - "d2", - "EH", - 2025 - ], - [ - "B", - 2025, - "s2", - "d1", - "EH", - 2025 - ], - [ - "A", - 2025, - "s2", - "d1", - "EH", - 2025 - ] - ], - "ramp_up_season_constraint_rpsstv": [], - "regional_exchange_capacity_constraint_rrptv": [ - [ - "B", - "A", - 2025, - "FGF_pipe", - 2025 - ], - [ - "A", - "B", - 2025, - "FGF_pipe", - 2025 - ] - ], - "renewable_portfolio_standard_constraint_rpg": [ - [ - "B", - 2025, - "RPS_common" - ] - ], - "reserve_margin_rpsd": [ - [ - "A", - 2025, - "s2", - "d1" - ], - [ - "A", - 2025, - "s1", - "d1" - ], - [ - "A", - 2025, - "s2", - "d2" - ], - [ - "A", - 2025, - "s1", - "d2" - ] - ], - "reserve_margin_method": [ - "static" - ], - "retired_capacity_var_rptv": [], - "seasonal_storage_level_rpstv": [], - "seasonal_storage_constraints_rpsdtv": [], - "storage_constraints_rpsdtv": [ - [ - "B", - 2025, - "s1", - "d1", - "batt", - 2025 - ], - [ - "B", - 2025, - "s1", - "d2", - "batt", - 2025 - ], - [ - "B", - 2025, - "s2", - "d1", - "batt", - 2025 - ], - [ - "B", - 2025, - "s2", - "d2", - "batt", - 2025 - ] - ], - "storage_level_rpsdtv": [ - [ - "B", - 2025, - "s1", - "d1", - "batt", - 2025 - ], - [ - "B", - 2025, - "s1", - "d2", - "batt", - 2025 - ], - [ - "B", - 2025, - "s2", - "d1", - "batt", - 2025 - ], - [ - "B", - 2025, - "s2", - "d2", - "batt", - 2025 - ] - ], - "time_manual": [], - "commodity_all": [ - "FusionGas", - "RH", - "HYD", - "GeoHyd", - "RL", - "ELC", - "co2", - "FusionGasFuel", - "earth" - ], - "commodity_annual": [], - "commodity_carrier": [ - "RH", - "HYD", - "GeoHyd", - "RL", - "ELC", - "FusionGasFuel", - "earth" - ], - "commodity_demand": [ - "RL", - "RH" - ], - "commodity_emissions": [ - "FusionGas", - "co2" - ], - "commodity_flex": [ - "FusionGasFuel" - ], - "commodity_physical": [ - "HYD", - "GeoHyd", - "ELC", - "FusionGasFuel", - "earth" - ], - "commodity_sink": [ - "RL", - "RH" - ], - "commodity_source": [ - "earth" - ], - "commodity_waste": [], - "operator": [ - "ge", - "e", - "le" - ], - "ordered_season_sequential": [ - [ - "s1", - "s1" - ], - [ - "s2", - "s2" - ] - ], - "regional_global_indices": [ - "B", - "A", - "global" - ], - "regional_indices": [ - "B", - "A", - "A-B", - "B-A" - ], - "regions": [ - "B", - "A" - ], - "tech_all": [ - "GeoHeater", - "bulbs", - "EH", - "GeoThermal", - "EFL", - "well", - "heater", - "EF", - "FGF_pipe", - "batt" - ], - "tech_annual": [ - "GeoThermal" - ], - "tech_demand": [ - "bulbs", - "heater", - "GeoHeater" - ], - "tech_baseload": [ - "EH" - ], - "tech_curtailment": [ - "EH" - ], - "tech_downramping": [ - "EH" - ], - "tech_exchange": [ - "FGF_pipe" - ], - "tech_exist": [], - "tech_flex": [ - "EFL" - ], - "tech_group_members": [ - "A_tech_grp_1", - "RPS_common" - ], - "tech_group_names": [ - "A_tech_grp_1", - "RPS_common" - ], - "tech_or_group": [ - "A_tech_grp_1", - "RPS_common", - "EH", - "EF", - "GeoThermal", - "well", - "heater", - "EFL", - "GeoHeater", - "bulbs", - "FGF_pipe", - "batt" - ], - "tech_production": [ - "GeoHeater", - "bulbs", - "EH", - "GeoThermal", - "EFL", - "heater", - "EF", - "FGF_pipe", - "batt", - "well" - ], - "tech_reserve": [ - "EF" - ], - "tech_retirement": [ - "EH" - ], - "tech_seasonal_storage": [], - "tech_storage": [ - "batt" - ], - "tech_uncap": [], - "tech_upramping": [ - "EH" - ], - "tech_with_capacity": [ - "GeoHeater", - "bulbs", - "EH", - "GeoThermal", - "EFL", - "well", - "heater", - "EF", - "FGF_pipe", - "batt" - ], - "time_exist": [ - 2020 - ], - "time_future": [ - 2025, - 2030 - ], - "time_of_day": [ - "d2", - "d1" - ], - "time_optimize": [ - 2025 - ], - "time_season": [ - "s1", - "s2" - ], - "time_season_sequential": [ - "s1", - "s2" - ], - "time_sequencing": [ - "seasonal_timeslices" - ], - "vintage_all": [ - 2025, - 2020 - ], - "vintage_exist": [ - 2020 - ], - "vintage_optimize": [ - 2025 - ], - "storage_init_rpstv": [ - [ - "B", - 2025, - "s2", - "batt", - 2025 - ], - [ - "B", - 2025, - "s1", - "batt", - 2025 - ] - ] -} + "operator": "74d830836f1399fb336a0432dde7d7bd36cffa3ff76b1c42d7945350cfb9bf91", + "time_exist": "91a2461c25439830d94bf4b3d3a3b020343f75e74561a913b1f972b2ac42e943", + "time_future": "6b150df8e12ac4dd15396b52f304c7935a41d2cc4da498186552819973171389", + "time_optimize": "9c9380fb50cd4f4f9e2032bd9a18645ae4fc1d30335672c62c897bcb9e099ba5", + "vintage_exist": "91a2461c25439830d94bf4b3d3a3b020343f75e74561a913b1f972b2ac42e943", + "vintage_optimize": "9c9380fb50cd4f4f9e2032bd9a18645ae4fc1d30335672c62c897bcb9e099ba5", + "vintage_all": "947dd08ad4812a98649b4306e4a0ca1b51374d86f1a8e27c3a8af3b189bcc0f6", + "time_season": "1e413891065e24bbf66543d4747ff12b1c65bf23c4ff9857b0bf0520eccd7f21", + "time_season_sequential": "1e413891065e24bbf66543d4747ff12b1c65bf23c4ff9857b0bf0520eccd7f21", + "time_of_day": "f9bbfe9130c510cba59a13e8b385b4d0206196abbdfe8032b995502bb7215f76", + "ordered_season_sequential": "53bc15b6510e5bad389153a661165e5a434fea3f17ba2c8b3919568edf124f72", + "regions": "f2314439597c11e286fd3c2fdf8eb70d3739e136f83e9533249ce3ecc43ece3e", + "regional_indices": "6d8dc3bc6dc8cd485bcf2a59d752df20974b0fd78cc623e3a51e705a01edeea4", + "regional_global_indices": "a4bd2969735cb437072971a2fa02a2d8fbb20a707a1bdfa695b92922daeb5d10", + "tech_production": "24f75b6f705a36033456d02638e7c50667908c45c474151fb8490666d928c63f", + "tech_all": "24f75b6f705a36033456d02638e7c50667908c45c474151fb8490666d928c63f", + "tech_baseload": "ddcf6ff7665c2a8acc4dff1b43655fae1b5a265135cbee18cec638df4e954346", + "tech_annual": "04ce850e0c3d3cb6608accab041c052be13c33d3f9d546242743b948989a043f", + "tech_demand": "b9e4a17c6dbf50597b7fd89aa581889bc19b262bd61629465295a52d91208096", + "tech_storage": "e4e91128cadba8c633bf98029cf6666adc3959c63967c6f396028b78e2e9f0cf", + "tech_reserve": "b28d0fd7ec11abdd0e645c2a9d83b05c08ecadcfb944d4a7bbd844ff4b83bfbf", + "tech_upramping": "ddcf6ff7665c2a8acc4dff1b43655fae1b5a265135cbee18cec638df4e954346", + "tech_downramping": "ddcf6ff7665c2a8acc4dff1b43655fae1b5a265135cbee18cec638df4e954346", + "tech_curtailment": "ddcf6ff7665c2a8acc4dff1b43655fae1b5a265135cbee18cec638df4e954346", + "tech_flex": "658ce9e7b9c3d7bcc751d8d49b9ece9c57623b3e25470c4f849af44b61ea5e20", + "tech_exchange": "4ad32a8fc9b95e840aa771b2dabc6fb35fae4904c089d4552659a4a9267883a7", + "tech_group_names": "6b923047f11d1c00a828b0f02aed79e853d81fd35ffd4667fbdc828ce356e515", + "tech_group_members": "6b923047f11d1c00a828b0f02aed79e853d81fd35ffd4667fbdc828ce356e515", + "tech_or_group": "4899ca300eb8ed5ba168b1f2ee669cacd36d041f493fb3dd00218d6764598cf9", + "tech_seasonal_storage": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_uncap": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_exist": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_with_capacity": "24f75b6f705a36033456d02638e7c50667908c45c474151fb8490666d928c63f", + "tech_retirement": "ddcf6ff7665c2a8acc4dff1b43655fae1b5a265135cbee18cec638df4e954346", + "commodity_demand": "f0ecafabcdc5015dab09f4b23f3c742a27b536f1c5634057a902a9b9c4a741b8", + "commodity_emissions": "849d0ab948e289950369de3a31be985d420635fa93525416da6d3ee9149019fc", + "commodity_physical": "7dd03855822916eb73171efbb05042535e0f89c26614139ed357a002b8a80fd1", + "commodity_waste": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "commodity_flex": "bfbe6f995c3a9fd19c92c7b6ffc526035a773a24d302c7eae9951b7327aef904", + "commodity_source": "ab3705f3ba0b69baa453c70d1bdfde3faa4eaeabc007204278258b4aacd861f3", + "commodity_sink": "f0ecafabcdc5015dab09f4b23f3c742a27b536f1c5634057a902a9b9c4a741b8", + "commodity_annual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "commodity_carrier": "1b95135b3de272d1ecab3761bdb976f1e48c044dcb2b5b6d320bc19dae0038cd", + "commodity_all": "1967c4b68c028414d99b55bfe9e03efd2fff370d15540a95282b721875d41460", + "time_sequencing": "91f69c8abab9959c1f8c90f5aaa56db29bccc67e37d12673ab41c54e4179d7ca", + "time_manual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "demand_constraint_rpc": "65996df03f7f3d85067ae18d36bdffe8596881473ae847052dc5df735cd01262", + "lifetime_process_rtv": "212639322f29aa7687eb9962fb9d74ef60961d720a2a753e2af53473b9e1648f", + "loan_lifetime_process_rtv": "212639322f29aa7687eb9962fb9d74ef60961d720a2a753e2af53473b9e1648f", + "renewable_portfolio_standard_constraint_rpg": "ab39415b5df1f906b11f06034cbfca390f7332b6a17adae60a71a74d7b421f67", + "capacity_factor_rsdt": "596087531ddbb1b27bc63b78e85b3d4fbb56c621ed2dbe35ef4f9f0ffcc49f68", + "capacity_constraint_rpsdtv": "02dcd6b84019270beb4b4fcac4062d1554bcc62ea9ed37c9b7f99d351b307898", + "cost_fixed_rptv": "fdb177f119430de12c8b1083c9275e3a256f45f859d6b6819a84bff5c8e92184", + "cost_invest_rtv": "cc795cbbeaaae0c046247752c104269e877cd4c402391b63ce6fe4d6ed4cf46b", + "cost_variable_rptv": "fdb177f119430de12c8b1083c9275e3a256f45f859d6b6819a84bff5c8e92184", + "cost_emission_rpe": "14c414e00f949816cbdbbfc01ab7df2fea18cd7f0ab4e84a33571e41667bd057", + "process_life_frac_rptv": "fdb177f119430de12c8b1083c9275e3a256f45f859d6b6819a84bff5c8e92184", + "limit_capacity_constraint_rpt": "118826dabd14af75ae09adbd5bdbba750528b3d59907cbfba3690223ffc7def7", + "limit_new_capacity_constraint_rtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_resource_constraint_rt": "b9b44ae8bc9642da0a81202877bd69f0b35ce193e31590dd3325ac0828edb5cf", + "limit_activity_constraint_rpt": "90461349933d0b32167abdca242233004b66212b57ed57213dce6f6818203963", + "limit_seasonal_capacity_factor_constraint_rst": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_seasonal_capacity_factor_constraint_rpst": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_annual_capacity_factor_constraint_rtvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_emission_constraint_rpe": "9bf30514ecc261370f67cd0c2e18194f45ff14c15764d274cc342a5a27eaf2a0", + "emission_activity_reitvo": "1292a5003c98c9ae6b7476807aca4bcc528b3dc28aec79827a47aeaaaaab74e4", + "limit_capacity_share_constraint_rpgg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_activity_share_constraint_rpgg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_new_capacity_share_constraint_rggv": "296e4148565f752973655692bae04ebf50877bd13fe9cec8f9563f347a61d885", + "storage_constraints_rpsdtv": "e1fe21679519e4410954d233e22d9490b182f21fda460b31a8d02538856fb85c", + "seasonal_storage_constraints_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_storage_fraction_param_rsdt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_storage_fraction_constraint_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "reserve_margin_method": "7869283c0d14273f720716309207a8f0c24606d03c679d6b68e656ed8d86241d", + "flow_var_rpsditvo": "e8c35c3b7b1f0c0e10e6f53e94d0c6b8a884c0dd048675cbeb9e7df33794161b", + "flow_var_annual_rpitvo": "6f5c569787fbf1e0a4076011f75fcd50a840bac85bb57b026f4fc5682739f888", + "flex_var_rpsditvo": "e4a8d7519d3e9deda0a32a471bdfa825eb893f10ba5781b895c9e3a3ef5faaa3", + "flex_var_annual_rpitvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "curtailment_var_rpsditvo": "541097cce6a976a20b73a2ffd8c4edd665a8497b066545d37318641b10484e95", + "flow_in_storage_rpsditvo": "ff680754a218ee843941e77bd07cbc5e5afd74e2b7b29a76ea86621624e8c0fd", + "storage_level_rpsdtv": "e1fe21679519e4410954d233e22d9490b182f21fda460b31a8d02538856fb85c", + "storage_init_rpstv": "90db44be71af3d9d75369791755570cf888e63e3544be22800077a4a2871175c", + "seasonal_storage_level_rpstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "capacity_var_rptv": "fdb177f119430de12c8b1083c9275e3a256f45f859d6b6819a84bff5c8e92184", + "new_capacity_var_rtv": "212639322f29aa7687eb9962fb9d74ef60961d720a2a753e2af53473b9e1648f", + "retired_capacity_var_rptv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "annual_retirement_var_rptv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "capacity_available_var_rpt": "34f71aae4b6b3a07130b57fa7910379bc1ecc3e12a6b4930fca5717bf54f8f56", + "capacity_annual_constraint_rptv": "6bd365e2e2f3267c7b838774484507a0812b25077f3006bcbfe135eceda11a28", + "demand_activity_constraint_rpsdtv_dem": "91570a9fbe4b071c37f1985c1671de2f33d9dfa7847f791a2933b8b3f262f8e8", + "commodity_balance_constraint_rpsdc": "a1d06a815047ba07b42ced6dc65df3511301af2f30791b3094fb7f25ccdd4217", + "annual_commodity_balance_constraint_rpc": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "baseload_diurnal_constraint_rpsdtv": "d766f05fa377b69768214641fda5d15617b697a43e64c863fe53503f11db4a89", + "regional_exchange_capacity_constraint_rrptv": "cf641ca7d7b664fda48e76f03b37c3b81aaa130ce821f919e6a8ac4860dad100", + "ramp_up_day_constraint_rpsdtv": "d766f05fa377b69768214641fda5d15617b697a43e64c863fe53503f11db4a89", + "ramp_down_day_constraint_rpsdtv": "d766f05fa377b69768214641fda5d15617b697a43e64c863fe53503f11db4a89", + "ramp_up_season_constraint_rpsstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "ramp_down_season_constraint_rpsstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "reserve_margin_rpsd": "9bd91053e57055456e04648c00d8e581addc9aa503cf31cf44c7a439c6f4fe0f", + "limit_growth_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_degrowth_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_growth_new_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_degrowth_new_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_growth_new_capacity_delta_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_degrowth_new_capacity_delta_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_annual_capacity_factor_constraint_rptvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_tech_input_split_constraint_rpsditv": "7a0e9b6c8271bcc30ccd6588da984c4aa8afe5d768ce5035fe6d8e62b31f8b3e", + "limit_tech_input_split_annual_constraint_rpitv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_tech_input_split_average_constraint_rpitv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_tech_output_split_constraint_rpsdtvo": "7cf9f5c111231f4e5c3f0ee8acfcddf52f5b1af3474d4cb949b969997602c8d7", + "limit_tech_output_split_annual_constraint_rptvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_tech_output_split_average_constraint_rptvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "linked_emissions_tech_constraint_rpsdtve": "f5accc0ee9eaaf16e584566a50e576405f8b5e1eb7d13815b87cb2f8b33a19b8" +} \ No newline at end of file diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index 1740580d8..e936ad273 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -1,42939 +1,115 @@ { - "annual_commodity_balance_constraint_rpc": [], - "annual_retirement_var_rptv": [ - [ - "R1", - 2030, - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "T_GSL", - 2020 - ] - ], - "baseload_diurnal_constraint_rpsdtv": [ - [ - "R2", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2020, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2020, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2020, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2020, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2020, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2020, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2020, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2020, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2020, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2020, - "summer", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2020, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2020, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2020, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2020, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2020, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2020, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2020, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2020, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "summer", - "day", - "E_NUCLEAR", - 2015 - ] - ], - "capacity_annual_constraint_rptv": [], - "capacity_available_var_rpt": [ - [ - "R1", - 2020, - "R_EH" - ], - [ - "R2", - 2025, - "T_BLND" - ], - [ - "R1", - 2020, - "E_NGCC" - ], - [ - "R2", - 2020, - "R_NGH" - ], - [ - "R1", - 2030, - "T_GSL" - ], - [ - "R2", - 2020, - "E_NUCLEAR" - ], - [ - "R2", - 2025, - "R_EH" - ], - [ - "R2-R1", - 2020, - "E_TRANS" - ], - [ - "R1", - 2030, - "E_SOLPV" - ], - [ - "R2", - 2025, - "E_NGCC" - ], - [ - "R2", - 2030, - "S_OILREF" - ], - [ - "R1-R2", - 2020, - "E_TRANS" - ], - [ - "R1", - 2030, - "R_NGH" - ], - [ - "R1", - 2025, - "S_OILREF" - ], - [ - "R1", - 2020, - "T_DSL" - ], - [ - "R2", - 2020, - "T_EV" - ], - [ - "R1", - 2030, - "E_NUCLEAR" - ], - [ - "R2", - 2020, - "E_BATT" - ], - [ - "R2", - 2020, - "T_BLND" - ], - [ - "R2", - 2030, - "T_GSL" - ], - [ - "R2", - 2030, - "E_SOLPV" - ], - [ - "R2", - 2025, - "T_DSL" - ], - [ - "R1", - 2025, - "T_GSL" - ], - [ - "R1", - 2030, - "T_EV" - ], - [ - "R2", - 2020, - "R_EH" - ], - [ - "R1", - 2025, - "E_SOLPV" - ], - [ - "R1", - 2030, - "E_BATT" - ], - [ - "R1", - 2030, - "T_BLND" - ], - [ - "R2", - 2020, - "E_NGCC" - ], - [ - "R2", - 2030, - "R_NGH" - ], - [ - "R2", - 2030, - "E_NUCLEAR" - ], - [ - "R1", - 2025, - "R_NGH" - ], - [ - "R1", - 2020, - "S_OILREF" - ], - [ - "R1", - 2025, - "E_NUCLEAR" - ], - [ - "R1", - 2030, - "R_EH" - ], - [ - "R1", - 2030, - "E_NGCC" - ], - [ - "R2", - 2030, - "T_BLND" - ], - [ - "R2", - 2020, - "T_DSL" - ], - [ - "R2", - 2030, - "T_EV" - ], - [ - "R1", - 2020, - "T_GSL" - ], - [ - "R2", - 2025, - "S_OILREF" - ], - [ - "R2-R1", - 2030, - "E_TRANS" - ], - [ - "R2", - 2030, - "E_BATT" - ], - [ - "R1", - 2025, - "T_EV" - ], - [ - "R1", - 2020, - "E_SOLPV" - ], - [ - "R1", - 2025, - "E_BATT" - ], - [ - "R1", - 2025, - "T_BLND" - ], - [ - "R1-R2", - 2030, - "E_TRANS" - ], - [ - "R2", - 2025, - "T_GSL" - ], - [ - "R1", - 2030, - "T_DSL" - ], - [ - "R1", - 2020, - "R_NGH" - ], - [ - "R2", - 2030, - "R_EH" - ], - [ - "R2", - 2025, - "E_SOLPV" - ], - [ - "R1", - 2020, - "E_NUCLEAR" - ], - [ - "R1", - 2025, - "R_EH" - ], - [ - "R2", - 2030, - "E_NGCC" - ], - [ - "R1", - 2025, - "E_NGCC" - ], - [ - "R2", - 2025, - "R_NGH" - ], - [ - "R2", - 2020, - "S_OILREF" - ], - [ - "R2", - 2025, - "E_NUCLEAR" - ], - [ - "R2-R1", - 2025, - "E_TRANS" - ], - [ - "R1", - 2020, - "T_EV" - ], - [ - "R1", - 2020, - "E_BATT" - ], - [ - "R1", - 2020, - "T_BLND" - ], - [ - "R1-R2", - 2025, - "E_TRANS" - ], - [ - "R2", - 2030, - "T_DSL" - ], - [ - "R2", - 2020, - "T_GSL" - ], - [ - "R1", - 2030, - "S_OILREF" - ], - [ - "R1", - 2025, - "T_DSL" - ], - [ - "R2", - 2025, - "T_EV" - ], - [ - "R2", - 2020, - "E_SOLPV" - ], - [ - "R2", - 2025, - "E_BATT" - ] - ], - "capacity_constraint_rpsdtv": [ - [ - "R2", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "summer", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2020, - "fall", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_SOLPV", - 2030 - ], - [ - "R1", - 2030, - "fall", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "T_EV", - 2025 - ], - [ - "R1", - 2025, - "spring", - "day", - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "summer", - "night", - "R_NGH", - 2025 - ], - [ - "R2", - 2025, - "fall", - "day", - "R_EH", - 2025 - ], - [ - "R2", - 2020, - "winter", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2020, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "spring", - "day", - "T_GSL", - 2030 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_SOLPV", - 2030 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "E_NGCC", - 2020 - ], - [ - "R1-R2", - 2030, - "winter", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "spring", - "day", - "R_EH", - 2030 - ], - [ - "R2", - 2030, - "winter", - "day", - "T_EV", - 2025 - ], - [ - "R2", - 2020, - "winter", - "day", - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "R_NGH", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "R_EH", - 2025 - ], - [ - "R1", - 2020, - "fall", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "spring", - "day", - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "T_EV", - 2030 - ], - [ - "R2", - 2020, - "summer", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "summer", - "day", - "R_EH", - 2030 - ], - [ - "R2", - 2020, - "fall", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2020, - "summer", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2020, - "winter", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2020, - "fall", - "day", - "R_EH", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "T_DSL", - 2030 - ], - [ - "R1", - 2030, - "fall", - "day", - "T_GSL", - 2030 - ], - [ - "R1", - 2020, - "fall", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "T_DSL", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "T_GSL", - 2025 - ], - [ - "R2-R1", - 2020, - "summer", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", - 2020, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2-R1", - 2020, - "spring", - "night", - "E_TRANS", - 2015 - ], - [ - "R1-R2", - 2020, - "spring", - "day", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "spring", - "day", - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2025, - "fall", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "T_DSL", - 2030 - ], - [ - "R1", - 2030, - "fall", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "winter", - "day", - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "summer", - "night", - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "T_EV", - 2025 - ], - [ - "R1", - 2030, - "spring", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "T_EV", - 2030 - ], - [ - "R2", - 2020, - "summer", - "day", - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "R_EH", - 2025 - ], - [ - "R1-R2", - 2025, - "spring", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "winter", - "day", - "R_NGH", - 2025 - ], - [ - "R2", - 2025, - "fall", - "night", - "T_EV", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_SOLPV", - 2030 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NGCC", - 2030 - ], - [ - "R2", - 2030, - "winter", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "winter", - "day", - "T_GSL", - 2030 - ], - [ - "R2", - 2020, - "winter", - "night", - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "T_GSL", - 2025 - ], - [ - "R1", - 2020, - "winter", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2020, - "fall", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "T_EV", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "R_EH", - 2030 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2020, - "spring", - "day", - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "R_NGH", - 2020 - ], - [ - "R1", - 2020, - "summer", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "T_DSL", - 2025 - ], - [ - "R2", - 2020, - "spring", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2-R1", - 2030, - "spring", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "summer", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "T_EV", - 2020 - ], - [ - "R2", - 2020, - "spring", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "T_EV", - 2025 - ], - [ - "R1", - 2020, - "winter", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "summer", - "night", - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2020, - "summer", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "winter", - "day", - "T_DSL", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "T_GSL", - 2025 - ], - [ - "R2", - 2020, - "winter", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "spring", - "day", - "R_NGH", - 2030 - ], - [ - "R2", - 2030, - "summer", - "day", - "T_EV", - 2030 - ], - [ - "R2", - 2025, - "summer", - "night", - "R_NGH", - 2025 - ], - [ - "R1", - 2025, - "spring", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "R_EH", - 2025 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2030, - "fall", - "day", - "T_DSL", - 2030 - ], - [ - "R1", - 2030, - "summer", - "day", - "R_NGH", - 2030 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "fall", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "R_EH", - 2025 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "T_DSL", - 2025 - ], - [ - "R1", - 2020, - "summer", - "day", - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NGCC", - 2030 - ], - [ - "R1", - 2030, - "winter", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "T_EV", - 2030 - ], - [ - "R2", - 2025, - "winter", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "fall", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "R_NGH", - 2030 - ], - [ - "R1", - 2030, - "spring", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "T_GSL", - 2025 - ], - [ - "R1", - 2020, - "fall", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R2-R1", - 2030, - "winter", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "winter", - "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2020, - "fall", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "spring", - "day", - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "winter", - "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "T_EV", - 2025 - ], - [ - "R2", - 2025, - "summer", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2020, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "T_EV", - 2030 - ], - [ - "R1", - 2030, - "spring", - "night", - "T_GSL", - 2030 - ], - [ - "R1", - 2030, - "summer", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2020, - "spring", - "night", - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "R_NGH", - 2025 - ], - [ - "R2", - 2020, - "fall", - "day", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "T_DSL", - 2025 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "winter", - "day", - "R_EH", - 2020 - ], - [ - "R1-R2", - 2030, - "spring", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "summer", - "day", - "T_DSL", - 2025 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "T_EV", - 2025 - ], - [ - "R2", - 2025, - "fall", - "night", - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "spring", - "day", - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NGCC", - 2030 - ], - [ - "R1", - 2030, - "winter", - "day", - "R_NGH", - 2030 - ], - [ - "R2", - 2025, - "summer", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "fall", - "night", - "T_GSL", - 2030 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2030, - "spring", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2020, - "winter", - "night", - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "T_DSL", - 2025 - ], - [ - "R1", - 2020, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "summer", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "spring", - "day", - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "T_GSL", - 2030 - ], - [ - "R1", - 2030, - "spring", - "night", - "T_GSL", - 2025 - ], - [ - "R2-R1", - 2025, - "spring", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2020, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "summer", - "day", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "summer", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "winter", - "day", - "R_NGH", - 2030 - ], - [ - "R1", - 2030, - "winter", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "winter", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2020, - "fall", - "night", - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "R_EH", - 2025 - ], - [ - "R2", - 2020, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "T_GSL", - 2030 - ], - [ - "R2", - 2020, - "fall", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "spring", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NGCC", - 2025 - ], - [ - "R1-R2", - 2030, - "spring", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "winter", - "day", - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "winter", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "summer", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "T_DSL", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "spring", - "day", - "T_BLND", - 2020 - ], - [ - "R1-R2", - 2020, - "spring", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "fall", - "night", - "T_GSL", - 2025 - ], - [ - "R2", - 2025, - "fall", - "night", - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "winter", - "night", - "T_GSL", - 2030 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "summer", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2020, - "winter", - "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "T_GSL", - 2020 - ], - [ - "R2-R1", - 2020, - "fall", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "fall", - "day", - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "T_DSL", - 2030 - ], - [ - "R2", - 2030, - "winter", - "day", - "R_NGH", - 2025 - ], - [ - "R1", - 2020, - "summer", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2020, - "fall", - "day", - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2020, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "spring", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2020, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "summer", - "day", - "T_GSL", - 2025 - ], - [ - "R2", - 2025, - "fall", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "T_EV", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "R_EH", - 2030 - ], - [ - "R2", - 2020, - "spring", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2020, - "winter", - "day", - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "fall", - "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "T_DSL", - 2030 - ], - [ - "R1", - 2030, - "fall", - "day", - "T_EV", - 2030 - ], - [ - "R1-R2", - 2025, - "summer", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", - 2020, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "R_NGH", - 2025 - ], - [ - "R2", - 2025, - "spring", - "day", - "T_GSL", - 2025 - ], - [ - "R2", - 2020, - "summer", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "R_EH", - 2025 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "T_DSL", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "T_DSL", - 2025 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_SOLPV", - 2030 - ], - [ - "R2", - 2020, - "fall", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "R_NGH", - 2030 - ], - [ - "R1", - 2030, - "fall", - "day", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2030, - "fall", - "night", - "T_DSL", - 2030 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "S_OILREF", - 2020 - ], - [ - "R2-R1", - 2030, - "fall", - "day", - "E_TRANS", - 2015 - ], - [ - "R2-R1", - 2020, - "winter", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2020, - "fall", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "winter", - "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2020, - "summer", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "fall", - "night", - "T_DSL", - 2025 - ], - [ - "R1", - 2020, - "winter", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "winter", - "day", - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "T_EV", - 2025 - ], - [ - "R1", - 2020, - "summer", - "day", - "T_DSL", - 2020 - ], - [ - "R1", - 2020, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NGCC", - 2030 - ], - [ - "R1", - 2025, - "summer", - "day", - "T_EV", - 2025 - ], - [ - "R1", - 2025, - "fall", - "day", - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_SOLPV", - 2030 - ], - [ - "R2", - 2025, - "spring", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "R_NGH", - 2030 - ], - [ - "R2", - 2025, - "summer", - "day", - "T_DSL", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "T_DSL", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1-R2", - 2025, - "winter", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "winter", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "T_EV", - 2025 - ], - [ - "R1-R2", - 2025, - "fall", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2020, - "fall", - "night", - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "summer", - "night", - "T_DSL", - 2030 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "fall", - "day", - "T_GSL", - 2030 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "R_NGH", - 2030 - ], - [ - "R2", - 2030, - "fall", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "spring", - "day", - "R_EH", - 2030 - ], - [ - "R1", - 2025, - "summer", - "day", - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "fall", - "night", - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "winter", - "night", - "R_NGH", - 2030 - ], - [ - "R1", - 2020, - "summer", - "day", - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "T_DSL", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "T_GSL", - 2025 - ], - [ - "R1", - 2020, - "spring", - "day", - "T_GSL", - 2020 - ], - [ - "R2-R1", - 2020, - "fall", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1-R2", - 2020, - "fall", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "winter", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2020, - "winter", - "day", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2020, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2020, - "summer", - "night", - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2020, - "winter", - "night", - "R_NGH", - 2020 - ], - [ - "R2", - 2020, - "fall", - "day", - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2020, - "spring", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "R_EH", - 2025 - ], - [ - "R1", - 2030, - "summer", - "night", - "T_DSL", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "T_EV", - 2030 - ], - [ - "R2", - 2025, - "fall", - "night", - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NGCC", - 2025 - ], - [ - "R1-R2", - 2025, - "fall", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "fall", - "day", - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "fall", - "day", - "R_EH", - 2030 - ], - [ - "R2", - 2030, - "summer", - "day", - "R_NGH", - 2025 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "spring", - "night", - "R_EH", - 2025 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "T_GSL", - 2030 - ], - [ - "R2", - 2030, - "spring", - "day", - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2025, - "spring", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2020, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_NGCC", - 2025 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "winter", - "night", - "R_NGH", - 2025 - ], - [ - "R1", - 2025, - "fall", - "day", - "T_EV", - 2025 - ], - [ - "R2", - 2020, - "fall", - "day", - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_SOLPV", - 2030 - ], - [ - "R1", - 2030, - "spring", - "day", - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2020, - "summer", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "winter", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "spring", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "T_GSL", - 2025 - ], - [ - "R2", - 2020, - "fall", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "T_EV", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "winter", - "day", - "R_EH", - 2030 - ], - [ - "R1", - 2030, - "fall", - "day", - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "summer", - "day", - "R_NGH", - 2020 - ], - [ - "R1", - 2020, - "fall", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "T_EV", - 2025 - ], - [ - "R1", - 2025, - "spring", - "night", - "R_EH", - 2020 - ], - [ - "R1-R2", - 2020, - "winter", - "day", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "summer", - "day", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "T_GSL", - 2020 - ], - [ - "R1-R2", - 2020, - "summer", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "summer", - "night", - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "fall", - "day", - "R_NGH", - 2030 - ], - [ - "R2", - 2030, - "spring", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_SOLPV", - 2030 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R2-R1", - 2030, - "summer", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NGCC", - 2030 - ], - [ - "R1", - 2020, - "spring", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_NGCC", - 2025 - ], - [ - "R2", - 2025, - "winter", - "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NGCC", - 2030 - ], - [ - "R1", - 2030, - "fall", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "R_EH", - 2025 - ], - [ - "R2", - 2020, - "winter", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NGCC", - 2020 - ], - [ - "R2-R1", - 2025, - "winter", - "day", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "winter", - "day", - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_SOLPV", - 2030 - ], - [ - "R1", - 2025, - "winter", - "day", - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "R_EH", - 2020 - ], - [ - "R2-R1", - 2025, - "fall", - "day", - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "summer", - "day", - "T_EV", - 2020 - ], - [ - "R2", - 2020, - "summer", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "R_NGH", - 2025 - ], - [ - "R1", - 2025, - "summer", - "night", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NGCC", - 2030 - ], - [ - "R2", - 2030, - "summer", - "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "summer", - "day", - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2020, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "T_GSL", - 2030 - ], - [ - "R2", - 2030, - "summer", - "night", - "T_DSL", - 2030 - ], - [ - "R2", - 2020, - "fall", - "night", - "R_EH", - 2020 - ], - [ - "R2", - 2020, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "fall", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "T_DSL", - 2030 - ], - [ - "R2-R1", - 2030, - "fall", - "night", - "E_TRANS", - 2015 - ], - [ - "R1-R2", - 2030, - "fall", - "day", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NGCC", - 2025 - ], - [ - "R2", - 2025, - "spring", - "day", - "T_DSL", - 2025 - ], - [ - "R1", - 2020, - "winter", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "T_EV", - 2030 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "R_EH", - 2025 - ], - [ - "R1", - 2025, - "spring", - "night", - "R_NGH", - 2025 - ], - [ - "R2", - 2020, - "summer", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "spring", - "day", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NGCC", - 2025 - ], - [ - "R2", - 2025, - "spring", - "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "T_EV", - 2030 - ], - [ - "R1", - 2025, - "winter", - "night", - "R_EH", - 2020 - ], - [ - "R1-R2", - 2030, - "summer", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "fall", - "night", - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "winter", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2020, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "fall", - "day", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_SOLPV", - 2030 - ], - [ - "R1", - 2020, - "summer", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "R_EH", - 2030 - ], - [ - "R2", - 2030, - "summer", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "T_EV", - 2025 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NGCC", - 2025 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NGCC", - 2030 - ], - [ - "R1", - 2025, - "summer", - "day", - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2020, - "fall", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2020, - "winter", - "day", - "T_EV", - 2020 - ], - [ - "R2", - 2020, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "fall", - "night", - "T_GSL", - 2025 - ], - [ - "R1", - 2020, - "winter", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "T_DSL", - 2025 - ], - [ - "R2", - 2020, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "winter", - "night", - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "summer", - "night", - "T_EV", - 2025 - ], - [ - "R2-R1", - 2030, - "winter", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "spring", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "R_NGH", - 2030 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "T_GSL", - 2030 - ], - [ - "R2", - 2025, - "summer", - "day", - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_SOLPV", - 2030 - ], - [ - "R1", - 2025, - "fall", - "day", - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "fall", - "night", - "R_EH", - 2030 - ], - [ - "R1-R2", - 2030, - "winter", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NGCC", - 2030 - ], - [ - "R1", - 2020, - "spring", - "night", - "T_GSL", - 2020 - ], - [ - "R1-R2", - 2020, - "fall", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2020, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2030, - "summer", - "night", - "R_EH", - 2030 - ], - [ - "R1", - 2030, - "spring", - "night", - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_SOLPV", - 2030 - ], - [ - "R2", - 2025, - "fall", - "day", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NGCC", - 2025 - ], - [ - "R2", - 2025, - "winter", - "day", - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "winter", - "night", - "R_NGH", - 2025 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "fall", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "winter", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "R_EH", - 2030 - ], - [ - "R2", - 2025, - "winter", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "T_EV", - 2025 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "spring", - "night", - "T_GSL", - 2025 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "fall", - "day", - "R_EH", - 2020 - ], - [ - "R2-R1", - 2025, - "fall", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "fall", - "night", - "R_EH", - 2025 - ], - [ - "R1", - 2025, - "spring", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2020, - "summer", - "day", - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2020, - "winter", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2020, - "summer", - "day", - "T_DSL", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "T_EV", - 2025 - ], - [ - "R2", - 2025, - "spring", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NGCC", - 2025 - ], - [ - "R2", - 2020, - "fall", - "night", - "R_NGH", - 2020 - ], - [ - "R2", - 2020, - "winter", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2020, - "summer", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2020, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "R_EH", - 2025 - ], - [ - "R1-R2", - 2020, - "summer", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "summer", - "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "spring", - "night", - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "fall", - "day", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "T_GSL", - 2030 - ], - [ - "R1", - 2020, - "winter", - "day", - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "R_NGH", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_SOLPV", - 2030 - ], - [ - "R2-R1", - 2025, - "summer", - "day", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "summer", - "day", - "R_EH", - 2025 - ], - [ - "R2", - 2025, - "spring", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_NGCC", - 2025 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "T_EV", - 2030 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "R_NGH", - 2030 - ], - [ - "R2", - 2030, - "fall", - "night", - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "R_EH", - 2025 - ], - [ - "R2", - 2020, - "summer", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2020, - "winter", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NGCC", - 2030 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2020, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "spring", - "day", - "R_EH", - 2025 - ], - [ - "R2", - 2020, - "summer", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2020, - "spring", - "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "T_EV", - 2030 - ], - [ - "R1", - 2025, - "summer", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "T_EV", - 2025 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "summer", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2020, - "spring", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "summer", - "night", - "R_NGH", - 2030 - ], - [ - "R2", - 2030, - "summer", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "T_EV", - 2025 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "R_NGH", - 2025 - ], - [ - "R1", - 2020, - "spring", - "day", - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NGCC", - 2030 - ], - [ - "R1", - 2030, - "winter", - "night", - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2020, - "winter", - "night", - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1-R2", - 2030, - "fall", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "fall", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NGCC", - 2025 - ], - [ - "R2", - 2025, - "summer", - "night", - "T_GSL", - 2025 - ], - [ - "R2", - 2025, - "spring", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "T_DSL", - 2030 - ], - [ - "R2", - 2030, - "fall", - "day", - "T_EV", - 2025 - ], - [ - "R2", - 2020, - "summer", - "day", - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "T_GSL", - 2030 - ], - [ - "R2", - 2025, - "winter", - "day", - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "fall", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "winter", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NGCC", - 2030 - ], - [ - "R1", - 2020, - "fall", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "R_NGH", - 2025 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "T_DSL", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "fall", - "day", - "R_EH", - 2030 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NGCC", - 2030 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2020, - "summer", - "day", - "E_NGCC", - 2020 - ], - [ - "R2", - 2020, - "fall", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "winter", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "fall", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "R_EH", - 2025 - ], - [ - "R1", - 2020, - "spring", - "day", - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "S_OILREF", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "summer", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NGCC", - 2025 - ], - [ - "R2", - 2025, - "fall", - "day", - "T_GSL", - 2025 - ], - [ - "R2", - 2020, - "winter", - "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2020, - "fall", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "R_NGH", - 2030 - ], - [ - "R1", - 2030, - "winter", - "day", - "T_GSL", - 2030 - ], - [ - "R1", - 2030, - "spring", - "night", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "R_EH", - 2025 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "T_DSL", - 2025 - ], - [ - "R2", - 2020, - "fall", - "day", - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "T_DSL", - 2030 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "fall", - "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "summer", - "night", - "R_EH", - 2030 - ], - [ - "R2", - 2025, - "spring", - "night", - "T_EV", - 2025 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_NGCC", - 2025 - ], - [ - "R2", - 2025, - "summer", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "T_EV", - 2030 - ], - [ - "R2", - 2030, - "spring", - "night", - "T_DSL", - 2020 - ], - [ - "R1-R2", - 2025, - "summer", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "fall", - "night", - "R_EH", - 2020 - ], - [ - "R1", - 2020, - "summer", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2020, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2-R1", - 2025, - "spring", - "day", - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "fall", - "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "R_EH", - 2025 - ], - [ - "R2", - 2025, - "spring", - "day", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NGCC", - 2030 - ], - [ - "R1", - 2025, - "summer", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "fall", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "summer", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "T_DSL", - 2025 - ], - [ - "R2", - 2025, - "fall", - "night", - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2-R1", - 2025, - "summer", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "summer", - "night", - "R_EH", - 2025 - ], - [ - "R2", - 2020, - "summer", - "day", - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "T_EV", - 2025 - ], - [ - "R2", - 2020, - "spring", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "R_NGH", - 2030 - ], - [ - "R2", - 2025, - "winter", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "winter", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "T_DSL", - 2030 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2020, - "summer", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "T_DSL", - 2025 - ], - [ - "R2", - 2025, - "winter", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "R_EH", - 2025 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NGCC", - 2025 - ], - [ - "R2", - 2025, - "fall", - "day", - "T_DSL", - 2025 - ], - [ - "R2", - 2020, - "spring", - "day", - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "winter", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_SOLPV", - 2030 - ], - [ - "R2", - 2020, - "spring", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "summer", - "day", - "T_DSL", - 2030 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_SOLPV", - 2030 - ], - [ - "R2", - 2025, - "winter", - "night", - "T_EV", - 2025 - ], - [ - "R1", - 2025, - "fall", - "night", - "R_NGH", - 2025 - ], - [ - "R1", - 2020, - "winter", - "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2020, - "fall", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2020, - "spring", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "R_EH", - 2030 - ], - [ - "R2", - 2030, - "spring", - "day", - "T_DSL", - 2030 - ], - [ - "R2", - 2030, - "fall", - "night", - "S_OILREF", - 2020 - ], - [ - "R2-R1", - 2020, - "winter", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", - 2020, - "spring", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "T_EV", - 2025 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "fall", - "day", - "R_NGH", - 2025 - ], - [ - "R1", - 2020, - "summer", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "T_EV", - 2025 - ], - [ - "R1", - 2030, - "spring", - "day", - "T_DSL", - 2025 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "summer", - "day", - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1-R2", - 2025, - "winter", - "night", - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "T_DSL", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2025, - "winter", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "T_EV", - 2025 - ], - [ - "R2", - 2020, - "winter", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "fall", - "night", - "T_GSL", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "T_GSL", - 2025 - ], - [ - "R2-R1", - 2020, - "spring", - "day", - "E_TRANS", - 2015 - ], - [ - "R2", - 2020, - "winter", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "R_NGH", - 2025 - ], - [ - "R2", - 2020, - "fall", - "day", - "T_BLND", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "spring", - "day", - "T_DSL", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "T_DSL", - 2030 - ], - [ - "R2", - 2030, - "fall", - "day", - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2025, - "winter", - "night", - "R_EH", - 2025 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_SOLPV", - 2030 - ], - [ - "R2", - 2030, - "spring", - "night", - "R_EH", - 2030 - ], - [ - "R1", - 2025, - "summer", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "T_EV", - 2030 - ], - [ - "R1", - 2030, - "spring", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "R_NGH", - 2025 - ], - [ - "R2", - 2025, - "spring", - "day", - "S_OILREF", - 2020 - ], - [ - "R1-R2", - 2025, - "spring", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2020, - "summer", - "night", - "R_NGH", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "T_EV", - 2025 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "winter", - "day", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2020, - "spring", - "night", - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_NGCC", - 2025 - ], - [ - "R2", - 2020, - "spring", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "T_DSL", - 2030 - ], - [ - "R1", - 2025, - "fall", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2020, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "summer", - "night", - "R_EH", - 2025 - ], - [ - "R2", - 2020, - "winter", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "T_GSL", - 2020 - ], - [ - "R2", - 2020, - "winter", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "spring", - "day", - "T_EV", - 2030 - ], - [ - "R1", - 2030, - "fall", - "night", - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "R_NGH", - 2025 - ], - [ - "R1", - 2025, - "summer", - "night", - "T_GSL", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "T_BLND", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "T_DSL", - 2025 - ], - [ - "R2", - 2020, - "spring", - "day", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "winter", - "night", - "R_EH", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2020, - "fall", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_SOLPV", - 2025 - ], - [ - "R2-R1", - 2020, - "summer", - "day", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "spring", - "night", - "R_EH", - 2025 - ], - [ - "R2", - 2020, - "spring", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "T_EV", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "R_NGH", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2020, - "summer", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "spring", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "T_GSL", - 2025 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_NGCC", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "T_DSL", - 2025 - ], - [ - "R2", - 2025, - "summer", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "R_NGH", - 2020 - ], - [ - "R2-R1", - 2030, - "summer", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_SOLPV", - 2030 - ], - [ - "R1", - 2030, - "summer", - "night", - "R_EH", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "T_EV", - 2025 - ], - [ - "R1", - 2020, - "fall", - "night", - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NGCC", - 2030 - ], - [ - "R2", - 2025, - "spring", - "night", - "R_NGH", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "R_EH", - 2030 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_SOLPV", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2020, - "winter", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "T_EV", - 2025 - ], - [ - "R1-R2", - 2020, - "winter", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "T_EV", - 2030 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "S_OILREF", - 2020 - ], - [ - "R1", - 2020, - "summer", - "night", - "T_EV", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "winter", - "day", - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "fall", - "day", - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "T_EV", - 2030 - ], - [ - "R2", - 2030, - "winter", - "day", - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "R_NGH", - 2025 - ], - [ - "R1-R2", - 2030, - "summer", - "day", - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "spring", - "night", - "R_NGH", - 2030 - ], - [ - "R1", - 2030, - "spring", - "day", - "T_GSL", - 2030 - ], - [ - "R2", - 2020, - "spring", - "day", - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_NGCC", - 2030 - ], - [ - "R1", - 2030, - "summer", - "day", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "T_EV", - 2020 - ], - [ - "R2-R1", - 2030, - "spring", - "day", - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_NGCC", - 2025 - ], - [ - "R2-R1", - 2025, - "winter", - "night", - "E_TRANS", - 2015 - ], - [ - "R2", - 2020, - "spring", - "night", - "T_BLND", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "winter", - "night", - "R_EH", - 2025 - ], - [ - "R1", - 2020, - "winter", - "day", - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2020, - "summer", - "day", - "E_NUCLEAR", - 2015 - ] - ], - "capacity_factor_rsdt": [ - [ - "R1", - "winter", - "night", - "E_NUCLEAR" - ], - [ - "R2", - "spring", - "night", - "E_SOLPV" - ], - [ - "R1", - "fall", - "night", - "T_EV" - ], - [ - "R1", - "fall", - "day", - "E_NGCC" - ], - [ - "R2", - "winter", - "day", - "R_EH" - ], - [ - "R1", - "fall", - "day", - "T_DSL" - ], - [ - "R2", - "fall", - "night", - "R_NGH" - ], - [ - "R1", - "summer", - "night", - "T_EV" - ], - [ - "R2", - "fall", - "night", - "E_NUCLEAR" - ], - [ - "R2-R1", - "spring", - "day", - "E_TRANS" - ], - [ - "R2", - "spring", - "night", - "T_EV" - ], - [ - "R2", - "spring", - "day", - "T_EV" - ], - [ - "R1", - "fall", - "day", - "S_OILREF" - ], - [ - "R1", - "fall", - "night", - "T_DSL" - ], - [ - "R2", - "spring", - "night", - "R_EH" - ], - [ - "R1", - "summer", - "night", - "T_DSL" - ], - [ - "R1", - "summer", - "night", - "R_NGH" - ], - [ - "R2", - "winter", - "day", - "E_BATT" - ], - [ - "R2", - "winter", - "day", - "T_BLND" - ], - [ - "R2", - "spring", - "day", - "T_DSL" - ], - [ - "R1", - "fall", - "night", - "S_OILREF" - ], - [ - "R1", - "summer", - "night", - "S_OILREF" - ], - [ - "R2-R1", - "winter", - "night", - "E_TRANS" - ], - [ - "R1-R2", - "spring", - "night", - "E_TRANS" - ], - [ - "R2", - "spring", - "night", - "S_OILREF" - ], - [ - "R1", - "spring", - "day", - "E_SOLPV" - ], - [ - "R2", - "winter", - "night", - "E_BATT" - ], - [ - "R2", - "winter", - "night", - "T_BLND" - ], - [ - "R2", - "spring", - "day", - "S_OILREF" - ], - [ - "R1", - "winter", - "night", - "E_SOLPV" - ], - [ - "R2", - "summer", - "day", - "R_EH" - ], - [ - "R1", - "spring", - "night", - "R_NGH" - ], - [ - "R2-R1", - "fall", - "day", - "E_TRANS" - ], - [ - "R1", - "spring", - "night", - "E_NUCLEAR" - ], - [ - "R2", - "fall", - "day", - "T_GSL" - ], - [ - "R2", - "spring", - "day", - "T_GSL" - ], - [ - "R2", - "winter", - "night", - "T_GSL" - ], - [ - "R2", - "winter", - "night", - "E_NGCC" - ], - [ - "R1", - "spring", - "night", - "E_SOLPV" - ], - [ - "R1", - "summer", - "night", - "T_BLND" - ], - [ - "R1", - "winter", - "day", - "R_NGH" - ], - [ - "R1", - "summer", - "day", - "E_BATT" - ], - [ - "R1", - "summer", - "day", - "T_BLND" - ], - [ - "R1", - "winter", - "day", - "E_NUCLEAR" - ], - [ - "R2", - "spring", - "night", - "E_BATT" - ], - [ - "R2", - "spring", - "night", - "T_BLND" - ], - [ - "R1", - "spring", - "day", - "R_EH" - ], - [ - "R2-R1", - "fall", - "night", - "E_TRANS" - ], - [ - "R2", - "fall", - "night", - "T_EV" - ], - [ - "R1", - "winter", - "night", - "R_EH" - ], - [ - "R1", - "summer", - "night", - "E_NGCC" - ], - [ - "R1", - "spring", - "day", - "R_NGH" - ], - [ - "R2", - "spring", - "night", - "E_NGCC" - ], - [ - "R1", - "summer", - "day", - "T_GSL" - ], - [ - "R1", - "spring", - "day", - "E_NUCLEAR" - ], - [ - "R1", - "winter", - "night", - "R_NGH" - ], - [ - "R1", - "winter", - "night", - "T_DSL" - ], - [ - "R1", - "spring", - "night", - "R_EH" - ], - [ - "R1", - "fall", - "day", - "T_GSL" - ], - [ - "R2", - "summer", - "night", - "T_BLND" - ], - [ - "R1", - "spring", - "night", - "T_DSL" - ], - [ - "R2", - "fall", - "night", - "S_OILREF" - ], - [ - "R2", - "fall", - "night", - "T_BLND" - ], - [ - "R2", - "fall", - "night", - "E_BATT" - ], - [ - "R2", - "summer", - "night", - "E_NGCC" - ], - [ - "R1", - "winter", - "day", - "E_NGCC" - ], - [ - "R1-R2", - "winter", - "day", - "E_TRANS" - ], - [ - "R1", - "spring", - "night", - "T_EV" - ], - [ - "R1", - "winter", - "night", - "E_NGCC" - ], - [ - "R1", - "winter", - "day", - "T_EV" - ], - [ - "R2", - "spring", - "day", - "E_BATT" - ], - [ - "R1", - "fall", - "night", - "R_NGH" - ], - [ - "R1", - "fall", - "night", - "E_NUCLEAR" - ], - [ - "R1", - "spring", - "day", - "T_EV" - ], - [ - "R2-R1", - "spring", - "night", - "E_TRANS" - ], - [ - "R2", - "fall", - "night", - "E_SOLPV" - ], - [ - "R2", - "summer", - "day", - "R_NGH" - ], - [ - "R1", - "winter", - "night", - "T_EV" - ], - [ - "R2", - "summer", - "day", - "E_NUCLEAR" - ], - [ - "R1", - "winter", - "day", - "T_DSL" - ], - [ - "R1-R2", - "summer", - "day", - "E_TRANS" - ], - [ - "R2", - "summer", - "night", - "E_BATT" - ], - [ - "R2", - "fall", - "day", - "R_NGH" - ], - [ - "R1", - "summer", - "night", - "T_GSL" - ], - [ - "R2", - "fall", - "day", - "E_NUCLEAR" - ], - [ - "R2", - "summer", - "day", - "E_BATT" - ], - [ - "R1", - "winter", - "day", - "S_OILREF" - ], - [ - "R2", - "summer", - "day", - "T_BLND" - ], - [ - "R1", - "spring", - "day", - "T_DSL" - ], - [ - "R2", - "spring", - "night", - "T_GSL" - ], - [ - "R2", - "fall", - "night", - "R_EH" - ], - [ - "R2", - "fall", - "night", - "T_DSL" - ], - [ - "R1", - "spring", - "day", - "S_OILREF" - ], - [ - "R1", - "winter", - "night", - "S_OILREF" - ], - [ - "R1", - "winter", - "day", - "E_BATT" - ], - [ - "R1", - "winter", - "day", - "T_BLND" - ], - [ - "R1", - "fall", - "night", - "E_NGCC" - ], - [ - "R2", - "summer", - "night", - "T_GSL" - ], - [ - "R1", - "winter", - "day", - "T_GSL" - ], - [ - "R2", - "spring", - "day", - "E_NGCC" - ], - [ - "R2", - "summer", - "night", - "E_SOLPV" - ], - [ - "R2", - "winter", - "night", - "E_SOLPV" - ], - [ - "R2", - "fall", - "day", - "E_SOLPV" - ], - [ - "R1", - "winter", - "night", - "T_GSL" - ], - [ - "R2", - "summer", - "day", - "T_EV" - ], - [ - "R1", - "fall", - "night", - "T_BLND" - ], - [ - "R2", - "winter", - "day", - "R_NGH" - ], - [ - "R2", - "winter", - "day", - "E_NUCLEAR" - ], - [ - "R1", - "summer", - "day", - "E_SOLPV" - ], - [ - "R2", - "summer", - "night", - "R_EH" - ], - [ - "R2", - "winter", - "night", - "R_EH" - ], - [ - "R2", - "fall", - "day", - "T_EV" - ], - [ - "R2", - "summer", - "night", - "T_DSL" - ], - [ - "R2", - "spring", - "night", - "R_NGH" - ], - [ - "R2", - "spring", - "night", - "E_NUCLEAR" - ], - [ - "R1-R2", - "summer", - "night", - "E_TRANS" - ], - [ - "R1", - "fall", - "day", - "E_BATT" - ], - [ - "R1", - "fall", - "day", - "T_BLND" - ], - [ - "R1", - "summer", - "day", - "R_EH" - ], - [ - "R2", - "fall", - "day", - "E_BATT" - ], - [ - "R2", - "fall", - "day", - "T_DSL" - ], - [ - "R2", - "summer", - "day", - "S_OILREF" - ], - [ - "R2", - "spring", - "day", - "T_BLND" - ], - [ - "R2", - "fall", - "night", - "E_NGCC" - ], - [ - "R1-R2", - "fall", - "day", - "E_TRANS" - ], - [ - "R2", - "fall", - "day", - "S_OILREF" - ], - [ - "R1", - "summer", - "night", - "E_BATT" - ], - [ - "R2", - "winter", - "day", - "E_SOLPV" - ], - [ - "R1", - "fall", - "night", - "T_GSL" - ], - [ - "R2", - "winter", - "day", - "T_EV" - ], - [ - "R2", - "spring", - "day", - "E_SOLPV" - ], - [ - "R2", - "winter", - "day", - "T_DSL" - ], - [ - "R2", - "spring", - "day", - "R_EH" - ], - [ - "R2", - "summer", - "day", - "E_SOLPV" - ], - [ - "R2", - "winter", - "day", - "S_OILREF" - ], - [ - "R1", - "winter", - "night", - "E_BATT" - ], - [ - "R1", - "winter", - "night", - "T_BLND" - ], - [ - "R2", - "spring", - "night", - "T_DSL" - ], - [ - "R1", - "spring", - "day", - "E_NGCC" - ], - [ - "R2", - "fall", - "night", - "T_GSL" - ], - [ - "R2", - "summer", - "day", - "T_DSL" - ], - [ - "R2", - "fall", - "day", - "R_EH" - ], - [ - "R1", - "spring", - "day", - "T_BLND" - ], - [ - "R1", - "winter", - "day", - "R_EH" - ], - [ - "R1-R2", - "fall", - "night", - "E_TRANS" - ], - [ - "R2", - "summer", - "day", - "E_NGCC" - ], - [ - "R1", - "spring", - "night", - "S_OILREF" - ], - [ - "R1-R2", - "winter", - "night", - "E_TRANS" - ], - [ - "R2", - "fall", - "day", - "E_NGCC" - ], - [ - "R1", - "spring", - "day", - "T_GSL" - ], - [ - "R2-R1", - "summer", - "day", - "E_TRANS" - ], - [ - "R2", - "summer", - "night", - "R_NGH" - ], - [ - "R2", - "summer", - "night", - "E_NUCLEAR" - ], - [ - "R2", - "winter", - "night", - "R_NGH" - ], - [ - "R2-R1", - "summer", - "night", - "E_TRANS" - ], - [ - "R2", - "winter", - "night", - "T_DSL" - ], - [ - "R2", - "winter", - "night", - "E_NUCLEAR" - ], - [ - "R1", - "summer", - "day", - "R_NGH" - ], - [ - "R1", - "summer", - "day", - "T_DSL" - ], - [ - "R1", - "summer", - "day", - "E_NUCLEAR" - ], - [ - "R1", - "fall", - "day", - "R_EH" - ], - [ - "R1", - "fall", - "night", - "E_BATT" - ], - [ - "R2", - "winter", - "day", - "E_NGCC" - ], - [ - "R2", - "summer", - "day", - "T_GSL" - ], - [ - "R2", - "summer", - "night", - "T_EV" - ], - [ - "R2", - "winter", - "night", - "T_EV" - ], - [ - "R1", - "summer", - "night", - "E_SOLPV" - ], - [ - "R2-R1", - "winter", - "day", - "E_TRANS" - ], - [ - "R1", - "summer", - "day", - "T_EV" - ], - [ - "R2", - "spring", - "day", - "R_NGH" - ], - [ - "R2", - "spring", - "day", - "E_NUCLEAR" - ], - [ - "R1", - "summer", - "night", - "R_EH" - ], - [ - "R2", - "summer", - "night", - "S_OILREF" - ], - [ - "R1-R2", - "spring", - "day", - "E_TRANS" - ], - [ - "R1", - "spring", - "night", - "T_BLND" - ], - [ - "R2", - "winter", - "night", - "S_OILREF" - ], - [ - "R1", - "spring", - "night", - "E_NGCC" - ], - [ - "R2", - "winter", - "day", - "T_GSL" - ], - [ - "R1", - "summer", - "day", - "S_OILREF" - ], - [ - "R1", - "spring", - "night", - "E_BATT" - ], - [ - "R1", - "spring", - "day", - "E_BATT" - ], - [ - "R1", - "winter", - "day", - "E_SOLPV" - ], - [ - "R1", - "fall", - "day", - "R_NGH" - ], - [ - "R1", - "fall", - "day", - "E_NUCLEAR" - ], - [ - "R1", - "spring", - "night", - "T_GSL" - ], - [ - "R1", - "fall", - "night", - "R_EH" - ], - [ - "R1", - "fall", - "night", - "E_SOLPV" - ], - [ - "R1", - "summer", - "night", - "E_NUCLEAR" - ], - [ - "R1", - "fall", - "day", - "E_SOLPV" - ], - [ - "R2", - "fall", - "day", - "T_BLND" - ], - [ - "R1", - "fall", - "day", - "T_EV" - ], - [ - "R1", - "summer", - "day", - "E_NGCC" - ] - ], - "capacity_var_rptv": [ - [ - "R2", - 2030, - "R_NGH", - 2030 - ], - [ - "R1", - 2030, - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "E_NGCC", - 2025 - ], - [ - "R2", - 2020, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "R_EH", - 2020 - ], - [ - "R2", - 2020, - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "T_EV", - 2030 - ], - [ - "R2", - 2030, - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "T_EV", - 2025 - ], - [ - "R1", - 2025, - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "R_NGH", - 2025 - ], - [ - "R2", - 2020, - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "E_NGCC", - 2020 - ], - [ - "R2", - 2020, - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "R_NGH", - 2020 - ], - [ - "R2", - 2020, - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2025 - ], - [ - "R2-R1", - 2020, - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "T_GSL", - 2030 - ], - [ - "R2-R1", - 2030, - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "E_NGCC", - 2030 - ], - [ - "R2", - 2025, - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "T_EV", - 2025 - ], - [ - "R1", - 2020, - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "T_EV", - 2025 - ], - [ - "R1", - 2030, - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "R_NGH", - 2020 - ], - [ - "R1", - 2020, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2030 - ], - [ - "R2", - 2020, - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2030 - ], - [ - "R1", - 2030, - "T_GSL", - 2030 - ], - [ - "R2", - 2025, - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "E_NGCC", - 2025 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "T_EV", - 2020 - ], - [ - "R1-R2", - 2025, - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "T_GSL", - 2025 - ], - [ - "R2", - 2025, - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "T_DSL", - 2025 - ], - [ - "R2", - 2025, - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "R_EH", - 2030 - ], - [ - "R1", - 2025, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "E_NGCC", - 2020 - ], - [ - "R1", - 2020, - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "R_EH", - 2025 - ], - [ - "R2", - 2025, - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "T_EV", - 2020 - ], - [ - "R2-R1", - 2025, - "E_TRANS", - 2015 - ], - [ - "R2", - 2020, - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "R_EH", - 2030 - ], - [ - "R1", - 2030, - "T_DSL", - 2030 - ], - [ - "R1", - 2030, - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2030 - ], - [ - "R1", - 2025, - "R_NGH", - 2025 - ], - [ - "R2", - 2025, - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "E_SOLPV", - 2025 - ], - [ - "R1", - 2020, - "E_SOLPV", - 2020 - ], - [ - "R1-R2", - 2030, - "E_TRANS", - 2015 - ], - [ - "R2", - 2020, - "T_DSL", - 2020 - ], - [ - "R1-R2", - 2020, - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "T_EV", - 2025 - ], - [ - "R2", - 2030, - "T_DSL", - 2030 - ], - [ - "R2", - 2030, - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2025, - "R_EH", - 2025 - ], - [ - "R1", - 2030, - "T_DSL", - 2025 - ], - [ - "R1", - 2020, - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "R_NGH", - 2030 - ], - [ - "R2", - 2030, - "E_BATT", - 2030 - ], - [ - "R2", - 2025, - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "R_EH", - 2025 - ], - [ - "R1", - 2025, - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "R_EH", - 2020 - ], - [ - "R1", - 2020, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "T_DSL", - 2025 - ], - [ - "R2", - 2025, - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "T_EV", - 2030 - ], - [ - "R1", - 2030, - "T_DSL", - 2020 - ], - [ - "R1", - 2025, - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2020 - ] - ], - "commodity_balance_constraint_rpsdc": [ - [ - "R2", - 2020, - "winter", - "night", - "ETH" - ], - [ - "R1", - 2025, - "fall", - "night", - "GSL" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC" - ], - [ - "R1", - 2020, - "spring", - "day", - "E10" - ], - [ - "R2", - 2030, - "winter", - "night", - "NG" - ], - [ - "R2", - 2025, - "summer", - "night", - "URN" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "GSL" - ], - [ - "R2", - 2030, - "summer", - "day", - "URN" - ], - [ - "R1", - 2020, - "summer", - "day", - "ETH" - ], - [ - "R1", - 2025, - "summer", - "night", - "NG" - ], - [ - "R2", - 2020, - "fall", - "day", - "GSL" - ], - [ - "R2", - 2020, - "spring", - "night", - "NG" - ], - [ - "R1", - 2025, - "fall", - "night", - "E10" - ], - [ - "R1", - 2020, - "fall", - "day", - "ETH" - ], - [ - "R1", - 2030, - "summer", - "day", - "URN" - ], - [ - "R2", - 2020, - "summer", - "night", - "E10" - ], - [ - "R1", - 2030, - "winter", - "day", - "URN" - ], - [ - "R2", - 2030, - "fall", - "day", - "DSL" - ], - [ - "R2", - 2025, - "spring", - "day", - "DSL" - ], - [ - "R2", - 2020, - "winter", - "night", - "DSL" - ], - [ - "R2", - 2020, - "fall", - "day", - "E10" - ], - [ - "R2", - 2030, - "summer", - "night", - "NG" - ], - [ - "R1", - 2025, - "winter", - "day", - "NG" - ], - [ - "R1", - 2020, - "summer", - "day", - "DSL" - ], - [ - "R2", - 2020, - "fall", - "night", - "OIL" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "NG" - ], - [ - "R1", - 2020, - "fall", - "day", - "DSL" - ], - [ - "R2", - 2025, - "spring", - "day", - "ELC" - ], - [ - "R2", - 2020, - "winter", - "night", - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "ETH" - ], - [ - "R1", - 2030, - "fall", - "day", - "URN" - ], - [ - "R1", - 2020, - "summer", - "night", - "ELC" - ], - [ - "R1", - 2020, - "summer", - "day", - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "URN" - ], - [ - "R2", - 2030, - "spring", - "night", - "GSL" - ], - [ - "R1", - 2025, - "summer", - "night", - "ETH" - ], - [ - "R2", - 2025, - "spring", - "day", - "URN" - ], - [ - "R1", - 2025, - "spring", - "night", - "E10" - ], - [ - "R2", - 2020, - "winter", - "night", - "URN" - ], - [ - "R2", - 2020, - "spring", - "night", - "ETH" - ], - [ - "R2", - 2025, - "winter", - "day", - "E10" - ], - [ - "R2", - 2020, - "winter", - "day", - "OIL" - ], - [ - "R1", - 2020, - "fall", - "day", - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "NG" - ], - [ - "R2", - 2020, - "summer", - "night", - "OIL" - ], - [ - "R1", - 2020, - "summer", - "day", - "URN" - ], - [ - "R2", - 2025, - "winter", - "night", - "OIL" - ], - [ - "R2", - 2030, - "spring", - "night", - "E10" - ], - [ - "R2", - 2025, - "summer", - "day", - "GSL" - ], - [ - "R2", - 2030, - "winter", - "day", - "OIL" - ], - [ - "R1", - 2030, - "fall", - "night", - "NG" - ], - [ - "R2", - 2030, - "summer", - "night", - "ETH" - ], - [ - "R1", - 2030, - "summer", - "night", - "NG" - ], - [ - "R1", - 2020, - "fall", - "day", - "URN" - ], - [ - "R1", - 2025, - "winter", - "day", - "ETH" - ], - [ - "R2", - 2030, - "winter", - "night", - "DSL" - ], - [ - "R1", - 2030, - "summer", - "day", - "NG" - ], - [ - "R2", - 2025, - "spring", - "night", - "NG" - ], - [ - "R1", - 2025, - "summer", - "day", - "OIL" - ], - [ - "R1", - 2030, - "winter", - "day", - "NG" - ], - [ - "R2", - 2020, - "spring", - "night", - "OIL" - ], - [ - "R2", - 2030, - "spring", - "day", - "NG" - ], - [ - "R1", - 2025, - "spring", - "day", - "GSL" - ], - [ - "R1", - 2025, - "summer", - "night", - "DSL" - ], - [ - "R1", - 2020, - "winter", - "night", - "GSL" - ], - [ - "R2", - 2020, - "spring", - "night", - "DSL" - ], - [ - "R2", - 2025, - "summer", - "day", - "E10" - ], - [ - "R1", - 2030, - "winter", - "night", - "ETH" - ], - [ - "R2", - 2025, - "fall", - "day", - "E10" - ], - [ - "R1", - 2030, - "spring", - "night", - "GSL" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "E10" - ], - [ - "R1", - 2020, - "fall", - "night", - "NG" - ], - [ - "R2", - 2030, - "summer", - "night", - "DSL" - ], - [ - "R1", - 2025, - "summer", - "night", - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "DSL" - ], - [ - "R2", - 2025, - "fall", - "night", - "OIL" - ], - [ - "R1", - 2030, - "spring", - "night", - "E10" - ], - [ - "R2", - 2030, - "winter", - "night", - "URN" - ], - [ - "R1", - 2030, - "winter", - "night", - "DSL" - ], - [ - "R1", - 2030, - "fall", - "day", - "NG" - ], - [ - "R2", - 2030, - "fall", - "night", - "NG" - ], - [ - "R1", - 2020, - "spring", - "night", - "GSL" - ], - [ - "R1", - 2025, - "summer", - "night", - "URN" - ], - [ - "R2", - 2020, - "spring", - "night", - "URN" - ], - [ - "R2", - 2020, - "spring", - "day", - "OIL" - ], - [ - "R1", - 2030, - "fall", - "night", - "ETH" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "ETH" - ], - [ - "R1", - 2025, - "winter", - "day", - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "ETH" - ], - [ - "R2", - 2025, - "spring", - "night", - "ETH" - ], - [ - "R1", - 2030, - "winter", - "day", - "ETH" - ], - [ - "R2", - 2030, - "spring", - "day", - "ETH" - ], - [ - "R1", - 2020, - "summer", - "night", - "NG" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "OIL" - ], - [ - "R2", - 2030, - "summer", - "night", - "URN" - ], - [ - "R1", - 2025, - "fall", - "day", - "DSL" - ], - [ - "R1", - 2025, - "winter", - "day", - "URN" - ], - [ - "R2", - 2030, - "summer", - "day", - "OIL" - ], - [ - "R2", - 2020, - "fall", - "night", - "GSL" - ], - [ - "R1", - 2020, - "fall", - "night", - "ETH" - ], - [ - "R1", - 2030, - "summer", - "day", - "OIL" - ], - [ - "R1", - 2030, - "fall", - "night", - "DSL" - ], - [ - "R1", - 2030, - "winter", - "night", - "URN" - ], - [ - "R1", - 2020, - "summer", - "day", - "E10" - ], - [ - "R1", - 2030, - "summer", - "night", - "DSL" - ], - [ - "R1", - 2020, - "winter", - "day", - "NG" - ], - [ - "R1", - 2030, - "winter", - "day", - "OIL" - ], - [ - "R2", - 2025, - "spring", - "night", - "DSL" - ], - [ - "R2", - 2030, - "spring", - "day", - "DSL" - ], - [ - "R2", - 2020, - "fall", - "night", - "E10" - ], - [ - "R1", - 2025, - "fall", - "day", - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "NG" - ], - [ - "R1", - 2025, - "winter", - "night", - "NG" - ], - [ - "R1", - 2030, - "fall", - "day", - "ETH" - ], - [ - "R2", - 2030, - "fall", - "night", - "ETH" - ], - [ - "R2", - 2020, - "winter", - "day", - "GSL" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC" - ], - [ - "R1", - 2020, - "fall", - "night", - "DSL" - ], - [ - "R1", - 2025, - "fall", - "day", - "URN" - ], - [ - "R2", - 2025, - "spring", - "night", - "ELC" - ], - [ - "R2", - 2020, - "summer", - "night", - "GSL" - ], - [ - "R2", - 2025, - "winter", - "night", - "GSL" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC" - ], - [ - "R1", - 2020, - "summer", - "night", - "ETH" - ], - [ - "R2", - 2030, - "winter", - "day", - "GSL" - ], - [ - "R2", - 2020, - "winter", - "day", - "E10" - ], - [ - "R1", - 2020, - "spring", - "day", - "NG" - ], - [ - "R1", - 2030, - "fall", - "night", - "URN" - ], - [ - "R1", - 2030, - "fall", - "day", - "OIL" - ], - [ - "R1", - 2030, - "summer", - "night", - "URN" - ], - [ - "R1", - 2025, - "summer", - "day", - "GSL" - ], - [ - "R2", - 2030, - "fall", - "day", - "OIL" - ], - [ - "R2", - 2025, - "spring", - "night", - "URN" - ], - [ - "R2", - 2025, - "spring", - "day", - "OIL" - ], - [ - "R1", - 2030, - "fall", - "day", - "DSL" - ], - [ - "R2", - 2030, - "fall", - "night", - "DSL" - ], - [ - "R2", - 2025, - "winter", - "night", - "E10" - ], - [ - "R2", - 2020, - "winter", - "night", - "OIL" - ], - [ - "R2", - 2030, - "spring", - "day", - "URN" - ], - [ - "R1", - 2020, - "fall", - "night", - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "E10" - ], - [ - "R1", - 2025, - "fall", - "night", - "NG" - ], - [ - "R1", - 2020, - "winter", - "day", - "ETH" - ], - [ - "R2", - 2020, - "summer", - "day", - "NG" - ], - [ - "R1", - 2025, - "summer", - "day", - "E10" - ], - [ - "R1", - 2020, - "summer", - "day", - "OIL" - ], - [ - "R2", - 2020, - "spring", - "night", - "E10" - ], - [ - "R1", - 2020, - "summer", - "night", - "DSL" - ], - [ - "R1", - 2020, - "winter", - "night", - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "ETH" - ], - [ - "R1", - 2020, - "fall", - "night", - "URN" - ], - [ - "R1", - 2025, - "winter", - "night", - "ETH" - ], - [ - "R2", - 2020, - "fall", - "day", - "NG" - ], - [ - "R1", - 2020, - "fall", - "day", - "OIL" - ], - [ - "R2", - 2025, - "fall", - "night", - "GSL" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "GSL" - ], - [ - "R2", - 2025, - "winter", - "day", - "GSL" - ], - [ - "R2", - 2030, - "summer", - "night", - "E10" - ], - [ - "R1", - 2020, - "winter", - "day", - "DSL" - ], - [ - "R2", - 2025, - "fall", - "night", - "E10" - ], - [ - "R2", - 2030, - "fall", - "night", - "URN" - ], - [ - "R2", - 2020, - "spring", - "day", - "GSL" - ], - [ - "R1", - 2020, - "spring", - "day", - "ETH" - ], - [ - "R1", - 2030, - "spring", - "day", - "DSL" - ], - [ - "R1", - 2025, - "winter", - "night", - "DSL" - ], - [ - "R1", - 2020, - "spring", - "night", - "ELC" - ], - [ - "R1", - 2020, - "summer", - "night", - "URN" - ], - [ - "R2", - 2025, - "summer", - "night", - "GSL" - ], - [ - "R2", - 2020, - "spring", - "day", - "E10" - ], - [ - "R1", - 2025, - "fall", - "night", - "ETH" - ], - [ - "R2", - 2030, - "winter", - "night", - "OIL" - ], - [ - "R2", - 2030, - "summer", - "day", - "GSL" - ], - [ - "R1", - 2020, - "winter", - "day", - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "ETH" - ], - [ - "R2", - 2025, - "fall", - "day", - "GSL" - ], - [ - "R1", - 2025, - "summer", - "night", - "OIL" - ], - [ - "R1", - 2020, - "spring", - "night", - "URN" - ], - [ - "R2", - 2030, - "spring", - "night", - "NG" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC" - ], - [ - "R2", - 2020, - "fall", - "day", - "ETH" - ], - [ - "R1", - 2025, - "winter", - "night", - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "E10" - ], - [ - "R1", - 2020, - "spring", - "day", - "DSL" - ], - [ - "R2", - 2030, - "summer", - "day", - "E10" - ], - [ - "R1", - 2020, - "winter", - "day", - "URN" - ], - [ - "R2", - 2025, - "summer", - "day", - "NG" - ], - [ - "R1", - 2030, - "summer", - "day", - "E10" - ], - [ - "R1", - 2030, - "spring", - "day", - "URN" - ], - [ - "R1", - 2025, - "fall", - "night", - "DSL" - ], - [ - "R1", - 2025, - "winter", - "night", - "URN" - ], - [ - "R2", - 2030, - "summer", - "night", - "OIL" - ], - [ - "R1", - 2030, - "winter", - "day", - "E10" - ], - [ - "R1", - 2025, - "winter", - "day", - "OIL" - ], - [ - "R2", - 2020, - "summer", - "day", - "DSL" - ], - [ - "R1", - 2020, - "spring", - "day", - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "NG" - ], - [ - "R1", - 2020, - "winter", - "night", - "NG" - ], - [ - "R2", - 2020, - "fall", - "day", - "DSL" - ], - [ - "R1", - 2030, - "winter", - "night", - "OIL" - ], - [ - "R1", - 2025, - "fall", - "day", - "ETH" - ], - [ - "R1", - 2025, - "fall", - "night", - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "NG" - ], - [ - "R1", - 2020, - "spring", - "day", - "URN" - ], - [ - "R2", - 2030, - "fall", - "day", - "GSL" - ], - [ - "R2", - 2020, - "summer", - "night", - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "GSL" - ], - [ - "R2", - 2020, - "summer", - "day", - "ELC" - ], - [ - "R2", - 2020, - "winter", - "night", - "GSL" - ], - [ - "R2", - 2030, - "spring", - "night", - "ETH" - ], - [ - "R2", - 2020, - "fall", - "day", - "ELC" - ], - [ - "R1", - 2025, - "fall", - "night", - "URN" - ], - [ - "R1", - 2030, - "fall", - "day", - "E10" - ], - [ - "R1", - 2025, - "fall", - "day", - "OIL" - ], - [ - "R1", - 2020, - "summer", - "day", - "GSL" - ], - [ - "R2", - 2030, - "fall", - "day", - "E10" - ], - [ - "R2", - 2025, - "spring", - "day", - "E10" - ], - [ - "R2", - 2020, - "summer", - "day", - "URN" - ], - [ - "R2", - 2020, - "winter", - "night", - "E10" - ], - [ - "R1", - 2020, - "fall", - "day", - "GSL" - ], - [ - "R1", - 2020, - "spring", - "night", - "NG" - ], - [ - "R2", - 2025, - "summer", - "day", - "ETH" - ], - [ - "R1", - 2030, - "fall", - "night", - "OIL" - ], - [ - "R2", - 2020, - "fall", - "day", - "URN" - ], - [ - "R1", - 2030, - "summer", - "night", - "OIL" - ], - [ - "R1", - 2020, - "summer", - "night", - "E10" - ], - [ - "R2", - 2025, - "spring", - "night", - "OIL" - ], - [ - "R2", - 2030, - "spring", - "day", - "OIL" - ], - [ - "R2", - 2030, - "spring", - "night", - "DSL" - ], - [ - "R1", - 2025, - "spring", - "day", - "ETH" - ], - [ - "R1", - 2020, - "winter", - "night", - "ETH" - ], - [ - "R1", - 2020, - "fall", - "day", - "E10" - ], - [ - "R1", - 2025, - "spring", - "night", - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "ETH" - ], - [ - "R2", - 2020, - "fall", - "night", - "NG" - ], - [ - "R1", - 2020, - "fall", - "night", - "OIL" - ], - [ - "R2", - 2025, - "summer", - "day", - "DSL" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "GSL" - ], - [ - "R2", - 2025, - "winter", - "day", - "URN" - ], - [ - "R1", - 2025, - "winter", - "night", - "E10" - ], - [ - "R1", - 2020, - "winter", - "night", - "OIL" - ], - [ - "R1", - 2025, - "spring", - "day", - "DSL" - ], - [ - "R1", - 2025, - "summer", - "night", - "GSL" - ], - [ - "R1", - 2020, - "winter", - "night", - "DSL" - ], - [ - "R2", - 2030, - "fall", - "night", - "OIL" - ], - [ - "R2", - 2020, - "spring", - "night", - "GSL" - ], - [ - "R2", - 2030, - "spring", - "night", - "URN" - ], - [ - "R2", - 2020, - "winter", - "day", - "NG" - ], - [ - "R1", - 2020, - "spring", - "night", - "ETH" - ], - [ - "R2", - 2025, - "summer", - "day", - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "E10" - ], - [ - "R1", - 2030, - "spring", - "night", - "DSL" - ], - [ - "R2", - 2025, - "fall", - "day", - "ELC" - ], - [ - "R2", - 2020, - "summer", - "night", - "NG" - ], - [ - "R1", - 2025, - "summer", - "night", - "E10" - ], - [ - "R1", - 2020, - "summer", - "night", - "OIL" - ], - [ - "R2", - 2025, - "winter", - "night", - "NG" - ], - [ - "R1", - 2025, - "spring", - "day", - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "NG" - ], - [ - "R2", - 2030, - "summer", - "night", - "GSL" - ], - [ - "R2", - 2025, - "summer", - "day", - "URN" - ], - [ - "R1", - 2025, - "winter", - "day", - "GSL" - ], - [ - "R1", - 2025, - "summer", - "day", - "NG" - ], - [ - "R2", - 2025, - "fall", - "day", - "URN" - ], - [ - "R1", - 2020, - "spring", - "night", - "OIL" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC" - ], - [ - "R2", - 2020, - "fall", - "night", - "ETH" - ], - [ - "R1", - 2030, - "winter", - "night", - "GSL" - ], - [ - "R1", - 2020, - "spring", - "night", - "DSL" - ], - [ - "R1", - 2025, - "spring", - "day", - "URN" - ], - [ - "R2", - 2020, - "summer", - "day", - "E10" - ], - [ - "R1", - 2020, - "winter", - "night", - "URN" - ], - [ - "R1", - 2025, - "winter", - "day", - "E10" - ], - [ - "R1", - 2020, - "winter", - "day", - "OIL" - ], - [ - "R1", - 2030, - "spring", - "night", - "URN" - ], - [ - "R1", - 2030, - "spring", - "day", - "OIL" - ], - [ - "R1", - 2030, - "winter", - "night", - "E10" - ], - [ - "R1", - 2025, - "winter", - "night", - "OIL" - ], - [ - "R2", - 2025, - "fall", - "night", - "NG" - ], - [ - "R2", - 2020, - "winter", - "day", - "ETH" - ], - [ - "R1", - 2025, - "fall", - "day", - "GSL" - ], - [ - "R1", - 2025, - "spring", - "night", - "NG" - ], - [ - "R2", - 2025, - "winter", - "day", - "NG" - ], - [ - "R2", - 2020, - "fall", - "night", - "DSL" - ], - [ - "R2", - 2020, - "summer", - "night", - "ETH" - ], - [ - "R2", - 2025, - "winter", - "night", - "ETH" - ], - [ - "R1", - 2030, - "fall", - "night", - "GSL" - ], - [ - "R2", - 2030, - "winter", - "day", - "ETH" - ], - [ - "R1", - 2030, - "summer", - "night", - "GSL" - ], - [ - "R2", - 2020, - "spring", - "day", - "NG" - ], - [ - "R1", - 2020, - "spring", - "day", - "OIL" - ], - [ - "R1", - 2030, - "summer", - "day", - "GSL" - ], - [ - "R2", - 2025, - "spring", - "night", - "GSL" - ], - [ - "R1", - 2025, - "fall", - "day", - "E10" - ], - [ - "R1", - 2030, - "winter", - "day", - "GSL" - ], - [ - "R2", - 2030, - "spring", - "day", - "GSL" - ], - [ - "R1", - 2025, - "summer", - "day", - "ETH" - ], - [ - "R2", - 2020, - "fall", - "night", - "ELC" - ], - [ - "R2", - 2020, - "winter", - "day", - "DSL" - ], - [ - "R1", - 2030, - "fall", - "night", - "E10" - ], - [ - "R1", - 2025, - "fall", - "night", - "OIL" - ], - [ - "R2", - 2025, - "summer", - "night", - "NG" - ], - [ - "R1", - 2030, - "summer", - "night", - "E10" - ], - [ - "R2", - 2025, - "spring", - "night", - "E10" - ], - [ - "R2", - 2030, - "summer", - "day", - "NG" - ], - [ - "R2", - 2020, - "summer", - "day", - "OIL" - ], - [ - "R2", - 2030, - "spring", - "day", - "E10" - ], - [ - "R2", - 2020, - "summer", - "night", - "DSL" - ], - [ - "R1", - 2020, - "fall", - "night", - "GSL" - ], - [ - "R2", - 2025, - "winter", - "night", - "DSL" - ], - [ - "R2", - 2025, - "fall", - "day", - "NG" - ], - [ - "R2", - 2020, - "fall", - "night", - "URN" - ], - [ - "R2", - 2020, - "fall", - "day", - "OIL" - ], - [ - "R2", - 2030, - "winter", - "day", - "DSL" - ], - [ - "R2", - 2025, - "fall", - "night", - "ETH" - ], - [ - "R2", - 2020, - "winter", - "day", - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "DSL" - ], - [ - "R1", - 2025, - "spring", - "night", - "ETH" - ], - [ - "R2", - 2025, - "winter", - "day", - "ETH" - ], - [ - "R1", - 2020, - "fall", - "night", - "E10" - ], - [ - "R1", - 2030, - "fall", - "day", - "GSL" - ], - [ - "R2", - 2030, - "fall", - "night", - "GSL" - ], - [ - "R2", - 2025, - "winter", - "night", - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC" - ], - [ - "R2", - 2020, - "winter", - "day", - "URN" - ], - [ - "R2", - 2020, - "spring", - "day", - "ETH" - ], - [ - "R1", - 2020, - "winter", - "night", - "E10" - ], - [ - "R1", - 2020, - "summer", - "night", - "GSL" - ], - [ - "R1", - 2025, - "summer", - "day", - "ELC" - ], - [ - "R2", - 2020, - "spring", - "night", - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "E10" - ], - [ - "R2", - 2020, - "summer", - "night", - "URN" - ], - [ - "R2", - 2025, - "fall", - "night", - "DSL" - ], - [ - "R1", - 2025, - "spring", - "night", - "OIL" - ], - [ - "R2", - 2025, - "winter", - "night", - "URN" - ], - [ - "R2", - 2025, - "winter", - "day", - "OIL" - ], - [ - "R2", - 2025, - "summer", - "night", - "ETH" - ], - [ - "R2", - 2030, - "winter", - "day", - "URN" - ], - [ - "R1", - 2025, - "spring", - "night", - "DSL" - ], - [ - "R2", - 2025, - "winter", - "day", - "DSL" - ], - [ - "R2", - 2030, - "summer", - "day", - "ETH" - ], - [ - "R2", - 2030, - "fall", - "day", - "NG" - ], - [ - "R2", - 2025, - "spring", - "day", - "NG" - ], - [ - "R1", - 2025, - "summer", - "day", - "URN" - ], - [ - "R2", - 2020, - "winter", - "night", - "NG" - ], - [ - "R2", - 2025, - "fall", - "day", - "ETH" - ], - [ - "R2", - 2030, - "spring", - "night", - "OIL" - ], - [ - "R1", - 2020, - "winter", - "day", - "GSL" - ], - [ - "R2", - 2020, - "spring", - "day", - "DSL" - ], - [ - "R2", - 2025, - "fall", - "night", - "ELC" - ], - [ - "R1", - 2020, - "summer", - "day", - "NG" - ], - [ - "R1", - 2020, - "spring", - "night", - "E10" - ], - [ - "R1", - 2030, - "spring", - "day", - "GSL" - ], - [ - "R1", - 2025, - "winter", - "night", - "GSL" - ], - [ - "R2", - 2025, - "summer", - "day", - "OIL" - ], - [ - "R1", - 2020, - "fall", - "day", - "NG" - ], - [ - "R2", - 2025, - "summer", - "night", - "DSL" - ], - [ - "R1", - 2020, - "winter", - "day", - "E10" - ], - [ - "R2", - 2030, - "summer", - "day", - "DSL" - ], - [ - "R2", - 2025, - "fall", - "night", - "URN" - ], - [ - "R2", - 2025, - "fall", - "day", - "OIL" - ], - [ - "R2", - 2020, - "spring", - "day", - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "URN" - ], - [ - "R1", - 2030, - "spring", - "day", - "E10" - ], - [ - "R2", - 2025, - "fall", - "day", - "DSL" - ], - [ - "R1", - 2025, - "spring", - "day", - "OIL" - ], - [ - "R1", - 2030, - "summer", - "day", - "DSL" - ], - [ - "R1", - 2030, - "winter", - "day", - "DSL" - ], - [ - "R1", - 2020, - "spring", - "day", - "GSL" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "OIL" - ], - [ - "R2", - 2020, - "spring", - "day", - "URN" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "ETH" - ], - [ - "R2", - 2025, - "spring", - "day", - "ETH" - ] - ], - "cost_emission_rpe": [], - "cost_fixed_rptv": [ - [ - "R2", - 2030, - "R_NGH", - 2030 - ], - [ - "R1", - 2030, - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "E_NGCC", - 2025 - ], - [ - "R2", - 2020, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "R_EH", - 2020 - ], - [ - "R2", - 2020, - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2030, - "T_EV", - 2030 - ], - [ - "R2", - 2030, - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "T_EV", - 2025 - ], - [ - "R1", - 2025, - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "R_NGH", - 2025 - ], - [ - "R2", - 2020, - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "E_NGCC", - 2020 - ], - [ - "R2", - 2020, - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2025, - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "R_NGH", - 2020 - ], - [ - "R2", - 2020, - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2025 - ], - [ - "R2-R1", - 2020, - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "T_GSL", - 2030 - ], - [ - "R2-R1", - 2030, - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "E_NGCC", - 2030 - ], - [ - "R2", - 2025, - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "T_EV", - 2025 - ], - [ - "R1", - 2020, - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "T_EV", - 2025 - ], - [ - "R1", - 2030, - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "R_NGH", - 2020 - ], - [ - "R1", - 2020, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2030 - ], - [ - "R2", - 2020, - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2030 - ], - [ - "R1", - 2030, - "T_GSL", - 2030 - ], - [ - "R2", - 2025, - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "E_NGCC", - 2025 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "T_EV", - 2020 - ], - [ - "R1-R2", - 2025, - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "T_GSL", - 2025 - ], - [ - "R2", - 2025, - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "T_DSL", - 2025 - ], - [ - "R2", - 2025, - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "R_EH", - 2030 - ], - [ - "R1", - 2025, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "E_NGCC", - 2020 - ], - [ - "R1", - 2020, - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "R_EH", - 2025 - ], - [ - "R2", - 2025, - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "T_EV", - 2020 - ], - [ - "R2-R1", - 2025, - "E_TRANS", - 2015 - ], - [ - "R2", - 2020, - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "R_EH", - 2030 - ], - [ - "R1", - 2030, - "T_DSL", - 2030 - ], - [ - "R1", - 2030, - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2030 - ], - [ - "R1", - 2025, - "R_NGH", - 2025 - ], - [ - "R2", - 2025, - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "E_SOLPV", - 2025 - ], - [ - "R1", - 2020, - "E_SOLPV", - 2020 - ], - [ - "R1-R2", - 2030, - "E_TRANS", - 2015 - ], - [ - "R2", - 2020, - "T_DSL", - 2020 - ], - [ - "R1-R2", - 2020, - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "T_EV", - 2025 - ], - [ - "R2", - 2030, - "T_DSL", - 2030 - ], - [ - "R2", - 2030, - "R_EH", - 2025 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2025, - "R_EH", - 2025 - ], - [ - "R1", - 2030, - "T_DSL", - 2025 - ], - [ - "R1", - 2020, - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "R_NGH", - 2030 - ], - [ - "R2", - 2030, - "E_BATT", - 2030 - ], - [ - "R2", - 2025, - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "R_EH", - 2025 - ], - [ - "R1", - 2025, - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "T_DSL", - 2025 - ], - [ - "R2", - 2030, - "R_EH", - 2020 - ], - [ - "R1", - 2020, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "T_DSL", - 2025 - ], - [ - "R2", - 2025, - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "T_EV", - 2030 - ], - [ - "R1", - 2030, - "T_DSL", - 2020 - ], - [ - "R1", - 2025, - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2020 - ] - ], - "cost_invest_rtv": [ - [ - "R2", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - "R_NGH", - 2020 - ], - [ - "R1", - "T_EV", - 2030 - ], - [ - "R2", - "T_GSL", - 2020 - ], - [ - "R1", - "E_BATT", - 2025 - ], - [ - "R1", - "E_SOLPV", - 2030 - ], - [ - "R2", - "E_NGCC", - 2025 - ], - [ - "R2", - "R_NGH", - 2030 - ], - [ - "R1", - "E_NGCC", - 2030 - ], - [ - "R2", - "R_EH", - 2025 - ], - [ - "R1", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - "R_EH", - 2030 - ], - [ - "R2", - "T_EV", - 2025 - ], - [ - "R1", - "T_DSL", - 2020 - ], - [ - "R2", - "E_BATT", - 2025 - ], - [ - "R2", - "E_SOLPV", - 2030 - ], - [ - "R1", - "T_GSL", - 2025 - ], - [ - "R2", - "T_DSL", - 2030 - ], - [ - "R1", - "T_EV", - 2020 - ], - [ - "R1", - "E_SOLPV", - 2020 - ], - [ - "R2", - "R_NGH", - 2020 - ], - [ - "R2", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - "E_NGCC", - 2020 - ], - [ - "R1", - "R_NGH", - 2025 - ], - [ - "R2", - "T_GSL", - 2025 - ], - [ - "R1", - "R_EH", - 2020 - ], - [ - "R1", - "E_BATT", - 2030 - ], - [ - "R2", - "E_NGCC", - 2030 - ], - [ - "R2", - "R_EH", - 2030 - ], - [ - "R2", - "E_SOLPV", - 2020 - ], - [ - "R1", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - "T_DSL", - 2020 - ], - [ - "R2", - "T_EV", - 2030 - ], - [ - "R1", - "T_DSL", - 2025 - ], - [ - "R1", - "T_GSL", - 2030 - ], - [ - "R2", - "E_BATT", - 2030 - ], - [ - "R2", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - "T_EV", - 2025 - ], - [ - "R1", - "E_BATT", - 2020 - ], - [ - "R1", - "E_SOLPV", - 2025 - ], - [ - "R2", - "E_NGCC", - 2020 - ], - [ - "R2", - "R_NGH", - 2025 - ], - [ - "R1", - "E_NGCC", - 2025 - ], - [ - "R1", - "R_NGH", - 2030 - ], - [ - "R2", - "R_EH", - 2020 - ], - [ - "R2", - "T_GSL", - 2030 - ], - [ - "R1", - "R_EH", - 2025 - ], - [ - "R2", - "T_EV", - 2020 - ], - [ - "R2", - "E_BATT", - 2020 - ], - [ - "R2", - "E_SOLPV", - 2025 - ], - [ - "R1", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - "T_GSL", - 2020 - ], - [ - "R2", - "T_DSL", - 2025 - ], - [ - "R1", - "T_DSL", - 2030 - ] - ], - "cost_variable_rptv": [ - [ - "R2", - 2030, - "R_NGH", - 2030 - ], - [ - "R2", - 2020, - "S_IMPETH", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "S_IMPNG", - 2020 - ], - [ - "R2", - 2020, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "S_IMPURN", - 2020 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "S_IMPNG", - 2020 - ], - [ - "R1", - 2030, - "R_EH", - 2020 - ], - [ - "R2", - 2020, - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2020, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2030, - "T_EV", - 2030 - ], - [ - "R2", - 2030, - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "T_EV", - 2025 - ], - [ - "R1", - 2030, - "S_IMPNG", - 2020 - ], - [ - "R1", - 2020, - "S_IMPNG", - 2020 - ], - [ - "R1", - 2025, - "S_IMPETH", - 2020 - ], - [ - "R1", - 2025, - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "S_IMPURN", - 2020 - ], - [ - "R2", - 2030, - "R_NGH", - 2025 - ], - [ - "R1", - 2020, - "S_IMPURN", - 2020 - ], - [ - "R2", - 2020, - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "E_NGCC", - 2020 - ], - [ - "R2", - 2020, - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2025, - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "R_NGH", - 2020 - ], - [ - "R2", - 2020, - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2025 - ], - [ - "R2-R1", - 2020, - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "T_GSL", - 2030 - ], - [ - "R2-R1", - 2030, - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "E_NGCC", - 2030 - ], - [ - "R2", - 2025, - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "T_EV", - 2025 - ], - [ - "R1", - 2020, - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "T_EV", - 2025 - ], - [ - "R1", - 2030, - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "S_IMPOIL", - 2020 - ], - [ - "R1", - 2025, - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "R_NGH", - 2020 - ], - [ - "R1", - 2020, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2030 - ], - [ - "R2", - 2020, - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "S_IMPETH", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2030 - ], - [ - "R1", - 2030, - "T_GSL", - 2030 - ], - [ - "R2", - 2025, - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "T_GSL", - 2025 - ], - [ - "R2", - 2025, - "S_IMPETH", - 2020 - ], - [ - "R1", - 2030, - "E_NGCC", - 2025 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "T_EV", - 2020 - ], - [ - "R1-R2", - 2025, - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "T_GSL", - 2025 - ], - [ - "R2", - 2020, - "S_IMPNG", - 2020 - ], - [ - "R2", - 2025, - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "S_IMPOIL", - 2020 - ], - [ - "R1", - 2025, - "T_DSL", - 2025 - ], - [ - "R2", - 2025, - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "R_EH", - 2030 - ], - [ - "R1", - 2030, - "S_IMPETH", - 2020 - ], - [ - "R1", - 2025, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "S_IMPURN", - 2020 - ], - [ - "R2", - 2030, - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "E_NGCC", - 2020 - ], - [ - "R1", - 2020, - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "R_EH", - 2025 - ], - [ - "R2", - 2025, - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "T_EV", - 2020 - ], - [ - "R2-R1", - 2025, - "E_TRANS", - 2015 - ], - [ - "R1", - 2020, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2020, - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "R_EH", - 2030 - ], - [ - "R1", - 2030, - "T_DSL", - 2030 - ], - [ - "R1", - 2030, - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "T_GSL", - 2020 - ], - [ - "R2", - 2020, - "S_IMPURN", - 2020 - ], - [ - "R1", - 2020, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2030 - ], - [ - "R1", - 2025, - "R_NGH", - 2025 - ], - [ - "R2", - 2025, - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "E_SOLPV", - 2025 - ], - [ - "R1", - 2020, - "E_SOLPV", - 2020 - ], - [ - "R1-R2", - 2030, - "E_TRANS", - 2015 - ], - [ - "R2", - 2020, - "T_DSL", - 2020 - ], - [ - "R1-R2", - 2020, - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "T_EV", - 2025 - ], - [ - "R1", - 2025, - "S_IMPNG", - 2020 - ], - [ - "R2", - 2030, - "T_DSL", - 2030 - ], - [ - "R2", - 2030, - "R_EH", - 2025 - ], - [ - "R1", - 2020, - "S_IMPETH", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2025, - "R_EH", - 2025 - ], - [ - "R1", - 2030, - "T_DSL", - 2025 - ], - [ - "R1", - 2020, - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "R_NGH", - 2030 - ], - [ - "R2", - 2030, - "E_BATT", - 2030 - ], - [ - "R2", - 2025, - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "R_EH", - 2025 - ], - [ - "R1", - 2025, - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2030, - "R_EH", - 2020 - ], - [ - "R1", - 2020, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "T_DSL", - 2025 - ], - [ - "R2", - 2025, - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "T_EV", - 2030 - ], - [ - "R1", - 2030, - "T_DSL", - 2020 - ], - [ - "R1", - 2025, - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "S_IMPURN", - 2020 - ] - ], - "curtailment_var_rpsditvo": [ - [ - "R2", - 2025, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ] - ], - "demand_activity_constraint_rpsdtv_dem": [ - [ - "R2", - 2030, - "summer", - "night", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2020, - "winter", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2020, - "fall", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "fall", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "spring", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "summer", - "night", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "spring", - "day", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "fall", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "spring", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "spring", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "fall", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "spring", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "fall", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2020, - "winter", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "summer", - "day", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "winter", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "winter", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2025, - "spring", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "day", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "day", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "winter", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "spring", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "winter", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "night", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "spring", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "day", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "winter", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "spring", - "day", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "winter", - "day", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "fall", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "winter", - "night", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "spring", - "day", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "summer", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "spring", - "day", - "T_GSL", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "R_EH", - 2030, - "RH" - ], - [ - "R1", - 2020, - "winter", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "spring", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "winter", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "day", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "winter", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "fall", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2020, - "summer", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "winter", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "spring", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "fall", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "fall", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "winter", - "day", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "night", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2020, - "winter", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "fall", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "spring", - "day", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "winter", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "fall", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "winter", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "spring", - "day", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2020, - "winter", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "spring", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "winter", - "night", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "day", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "spring", - "day", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_GSL", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "summer", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2020, - "winter", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "winter", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "winter", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "day", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "night", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "spring", - "night", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "summer", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "fall", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_GSL", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "fall", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "spring", - "day", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "spring", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "spring", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "spring", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "spring", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "fall", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "fall", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "spring", - "day", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "day", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "winter", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "summer", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "night", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "winter", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "fall", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "day", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "day", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "night", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "winter", - "night", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "spring", - "day", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "spring", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2020, - "spring", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "spring", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "spring", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "spring", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "fall", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "spring", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2025, - "spring", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "winter", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "winter", - "day", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "day", - "R_EH", - 2030, - "RH" - ], - [ - "R1", - 2025, - "spring", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "spring", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "night", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "spring", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "spring", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "day", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "winter", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "fall", - "night", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "day", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2020, - "spring", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "spring", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "spring", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_GSL", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2020, - "spring", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "fall", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "fall", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "fall", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "fall", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2020, - "spring", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "summer", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "day", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "day", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "fall", - "night", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "winter", - "day", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "spring", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "fall", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "R_EH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "day", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "day", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "day", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "fall", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "fall", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "day", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "summer", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "spring", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "summer", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "summer", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "fall", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "night", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2020, - "winter", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "day", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "fall", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "night", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_GSL", - 2030, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "spring", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "summer", - "night", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "R_EH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "summer", - "night", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "fall", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "day", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "spring", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "winter", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "R_EH", - 2030, - "RH" - ], - [ - "R1", - 2025, - "winter", - "night", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "day", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "spring", - "day", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "day", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "fall", - "night", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "day", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "winter", - "day", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "fall", - "night", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "winter", - "day", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "summer", - "night", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "winter", - "day", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "spring", - "night", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "night", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "spring", - "night", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "fall", - "day", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "spring", - "night", - "R_EH", - 2030, - "RH" - ] - ], - "demand_constraint_rpc": [ - [ - "R1", - 2030, - "RH" - ], - [ - "R1", - 2025, - "RH" - ], - [ - "R1", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "RH" - ], - [ - "R1", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "RH" - ], - [ - "R2", - 2025, - "RH" - ], - [ - "R2", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "VMT" - ], - [ - "R1", - 2020, - "RH" - ] - ], - "emission_activity_reitvo": [ - [ - "R1", - "CO2", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - "CO2", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - "CO2", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - "CO2", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - "CO2", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - "CO2", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - "CO2", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - "CO2", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - "CO2", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - "CO2", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - "CO2", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - "CO2", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - "CO2", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - "CO2", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - "CO2", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - "CO2", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - "CO2", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - "CO2", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - "CO2", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - "CO2", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - "CO2", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - "CO2", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - "CO2", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - "CO2", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - "CO2", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - "CO2", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - "CO2", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - "CO2", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - "CO2", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R2", - "CO2", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - "CO2", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - "CO2", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - "CO2", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - "CO2", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - "CO2", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - "CO2", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - "CO2", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R1", - "CO2", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - "CO2", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R2", - "CO2", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - "CO2", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - "CO2", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - "CO2", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - "CO2", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - "CO2", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - "CO2", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - "CO2", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - "CO2", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R2", - "CO2", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - "CO2", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - "CO2", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - "CO2", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - "CO2", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - "CO2", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - "CO2", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - "CO2", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - "CO2", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - "CO2", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - "CO2", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - "CO2", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - "CO2", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - "CO2", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - "CO2", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R2", - "CO2", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - "CO2", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - "CO2", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - "CO2", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - "CO2", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - "CO2", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - "CO2", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - "CO2", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - "CO2", - "ELC", - "R_EH", - 2020, - "RH" - ] - ], - "flex_var_annual_rpitvo": [], - "flex_var_rpsditvo": [], - "flow_in_storage_rpsditvo": [ - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ] - ], - "flow_var_annual_rpitvo": [ - [ - "R1", - 2030, - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2020, - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2025, - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2025, - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2020, - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "E10", - "T_GSL", - 2030, - "VMT" - ] - ], - "flow_var_rpsditvo": [ - [ - "R1", - 2020, - "spring", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "summer", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "spring", - "night", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2020, - "winter", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "spring", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "day", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2020, - "spring", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "spring", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "winter", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "spring", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "winter", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "summer", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "summer", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "fall", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "summer", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "winter", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R1", - 2025, - "winter", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "summer", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "fall", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "spring", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "summer", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "summer", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "spring", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "spring", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "winter", - "night", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "fall", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "summer", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "winter", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "fall", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "winter", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "winter", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "summer", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "fall", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "spring", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "fall", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "spring", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "fall", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "winter", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "summer", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "winter", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "fall", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "spring", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "fall", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2025, - "winter", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "fall", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "summer", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "winter", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "winter", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "summer", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "fall", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "winter", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "fall", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "winter", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "winter", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "spring", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "winter", - "day", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "fall", - "day", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "fall", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "spring", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "winter", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2020, - "fall", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "fall", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "winter", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "fall", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "summer", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "fall", - "night", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R1", - 2025, - "winter", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "summer", - "night", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "spring", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "winter", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "spring", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "spring", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "summer", - "night", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "winter", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "fall", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "fall", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "winter", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "day", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "summer", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "spring", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "summer", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "fall", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "summer", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "fall", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "winter", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "summer", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "fall", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2020, - "spring", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "summer", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "spring", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "winter", - "night", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2025, - "winter", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "winter", - "night", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "summer", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "spring", - "night", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2020, - "winter", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "day", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "summer", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "winter", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "day", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2025, - "spring", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "fall", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2020, - "fall", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "spring", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "summer", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2025, - "fall", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "summer", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "winter", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "winter", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2025, - "spring", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "spring", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "summer", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "fall", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "fall", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "fall", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "spring", - "day", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "day", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "winter", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "fall", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "fall", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "winter", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "spring", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2020, - "summer", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "spring", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "spring", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "winter", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "summer", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "winter", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "summer", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "fall", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R1", - 2025, - "fall", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "winter", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "summer", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "spring", - "night", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "summer", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "summer", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "summer", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "winter", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "winter", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "spring", - "day", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "winter", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R1", - 2020, - "winter", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "fall", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "spring", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "spring", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "spring", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "winter", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "night", - "DSL", - "T_DSL", - 2030, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "fall", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "spring", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "winter", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "spring", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2020, - "summer", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R2", - 2020, - "winter", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R1", - 2025, - "winter", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "T_EV", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "fall", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "spring", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "summer", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "summer", - "night", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "summer", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R1", - 2030, - "summer", - "day", - "E10", - "T_GSL", - 2030, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "spring", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2020, - "winter", - "day", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2025, - "summer", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "T_EV", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "winter", - "day", - "NG", - "R_NGH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "spring", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "summer", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "summer", - "night", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "spring", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2025, - "fall", - "day", - "ELC", - "R_EH", - 2025, - "RH" - ], - [ - "R2", - 2020, - "spring", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "spring", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2020, - "fall", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "spring", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2030, - "fall", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2030, - "winter", - "night", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R2", - 2025, - "fall", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R2", - 2025, - "winter", - "night", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "summer", - "day", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "night", - "ELC", - "T_EV", - 2020, - "VMT" - ], - [ - "R1", - 2030, - "spring", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2025, - "spring", - "day", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R1", - 2020, - "spring", - "day", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R1", - 2025, - "spring", - "day", - "E10", - "T_GSL", - 2025, - "VMT" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "R_EH", - 2030, - "RH" - ], - [ - "R2", - 2025, - "winter", - "day", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "fall", - "night", - "NG", - "R_NGH", - 2025, - "RH" - ], - [ - "R2", - 2030, - "fall", - "day", - "DSL", - "T_DSL", - 2020, - "VMT" - ], - [ - "R2", - 2020, - "fall", - "day", - "E10", - "T_GSL", - 2020, - "VMT" - ], - [ - "R1", - 2025, - "fall", - "night", - "NG", - "R_NGH", - 2020, - "RH" - ], - [ - "R2", - 2030, - "winter", - "night", - "DSL", - "T_DSL", - 2025, - "VMT" - ], - [ - "R1", - 2020, - "fall", - "night", - "ELC", - "R_EH", - 2020, - "RH" - ], - [ - "R2", - 2020, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1-R2", - 2030, - "spring", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2020, - "winter", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2030, - "fall", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2020, - "fall", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2025, - "summer", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2025, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "fall", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1-R2", - 2030, - "fall", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1-R2", - 2020, - "winter", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2030, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2-R1", - 2025, - "winter", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "spring", - "night", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2020, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2025, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2020, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "summer", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1-R2", - 2020, - "summer", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2025, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2020, - "spring", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2030, - "summer", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R2-R1", - 2025, - "summer", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "summer", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "summer", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2020, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2-R1", - 2030, - "summer", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1-R2", - 2025, - "summer", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2025, - "spring", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2025, - "spring", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "summer", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "summer", - "night", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2025, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2025, - "summer", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2-R1", - 2020, - "fall", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2-R1", - 2020, - "summer", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2025, - "fall", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2025, - "summer", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "spring", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "spring", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1-R2", - 2030, - "winter", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2025, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2025, - "spring", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2020, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2-R1", - 2020, - "spring", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2030, - "fall", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2-R1", - 2025, - "spring", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2-R1", - 2030, - "fall", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2020, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1-R2", - 2025, - "fall", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "spring", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2025, - "spring", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2030, - "spring", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "spring", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2030, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "winter", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2030, - "winter", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2025, - "fall", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2030, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2020, - "fall", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1-R2", - 2030, - "fall", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2030, - "fall", - "day", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "summer", - "day", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "summer", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "winter", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "summer", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2-R1", - 2020, - "winter", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2030, - "spring", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2020, - "summer", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2030, - "summer", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2025, - "fall", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "fall", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1-R2", - 2030, - "summer", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1-R2", - 2030, - "winter", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "spring", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1-R2", - 2025, - "spring", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2030, - "spring", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "summer", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2025, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "winter", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2-R1", - 2020, - "winter", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "spring", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "summer", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2030, - "summer", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "spring", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "fall", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2030, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2030, - "spring", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2-R1", - 2025, - "fall", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2020, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2020, - "spring", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1-R2", - 2030, - "summer", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2025, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2-R1", - 2020, - "summer", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2030, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2-R1", - 2030, - "spring", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2030, - "winter", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "winter", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "spring", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1-R2", - 2025, - "winter", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "summer", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2025, - "spring", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2025, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2030, - "spring", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2025, - "fall", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2030, - "winter", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2020, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2-R1", - 2030, - "fall", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2025, - "winter", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2030, - "summer", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1-R2", - 2020, - "spring", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1-R2", - 2020, - "summer", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "winter", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "summer", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "winter", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2020, - "summer", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2025, - "fall", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2025, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "winter", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "summer", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "spring", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2025, - "winter", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2025, - "winter", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2030, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2-R1", - 2030, - "spring", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "summer", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "fall", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1-R2", - 2025, - "winter", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2025, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2-R1", - 2030, - "winter", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "spring", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2030, - "summer", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2025, - "summer", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2020, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1-R2", - 2025, - "summer", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2030, - "winter", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2030, - "fall", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2020, - "summer", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "fall", - "night", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "winter", - "night", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "winter", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "fall", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2020, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2030, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2025, - "winter", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2025, - "winter", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2020, - "summer", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "fall", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2025, - "fall", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2030, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2020, - "summer", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2030, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "winter", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2020, - "spring", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2020, - "spring", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2020, - "summer", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2025, - "spring", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2020, - "spring", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2020, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "summer", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2025, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2025, - "fall", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "spring", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1-R2", - 2020, - "fall", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2-R1", - 2030, - "summer", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2030, - "fall", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2020, - "winter", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2025, - "spring", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "winter", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2030, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2025, - "summer", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2025, - "winter", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2020, - "spring", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2025, - "summer", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1-R2", - 2025, - "fall", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2030, - "winter", - "day", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1-R2", - 2020, - "fall", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "winter", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2025, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "summer", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2020, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "summer", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2025, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "winter", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "spring", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "summer", - "night", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1-R2", - 2030, - "spring", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "spring", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2030, - "spring", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2025, - "spring", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2020, - "fall", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2025, - "summer", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2025, - "spring", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "winter", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "spring", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2020, - "fall", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2025, - "winter", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "fall", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1-R2", - 2020, - "spring", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "winter", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2020, - "winter", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2025, - "summer", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2025, - "spring", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "winter", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2030, - "winter", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2030, - "summer", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "spring", - "night", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2020, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "fall", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2020, - "fall", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2025, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "spring", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2030, - "fall", - "night", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "spring", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "fall", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "winter", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2025, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "spring", - "day", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2025, - "winter", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2020, - "winter", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2030, - "fall", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "summer", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2025, - "winter", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "winter", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2020, - "summer", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2025, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "summer", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "summer", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2025, - "spring", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "summer", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "fall", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2030, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "fall", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2025, - "winter", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "summer", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2-R1", - 2025, - "summer", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2020, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "spring", - "day", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2020, - "spring", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2020, - "spring", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2020, - "winter", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2025, - "summer", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2-R1", - 2025, - "winter", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2020, - "winter", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2020, - "spring", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2020, - "summer", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2020, - "fall", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "fall", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2030, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "summer", - "night", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "summer", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2025, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2030, - "spring", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2030, - "summer", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2020, - "summer", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2020, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2025, - "spring", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2025, - "summer", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2025, - "fall", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2025, - "fall", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2030, - "winter", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2030, - "spring", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2-R1", - 2025, - "spring", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2020, - "spring", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2030, - "fall", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2030, - "fall", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2020, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "summer", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2030, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2025, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2020, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2030, - "spring", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2020, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "winter", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2030, - "fall", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "night", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2020, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2025, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2020, - "fall", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2020, - "fall", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2025, - "summer", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "summer", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2025, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "spring", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "winter", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2020, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "night", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "day", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "winter", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2-R1", - 2020, - "spring", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "fall", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2030, - "summer", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2025, - "fall", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2020, - "winter", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "fall", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2025, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "spring", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R2-R1", - 2020, - "fall", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2025, - "summer", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2025, - "winter", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2025, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "winter", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2020, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "summer", - "day", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1-R2", - 2020, - "winter", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1-R2", - 2025, - "spring", - "night", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "winter", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "fall", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2025, - "spring", - "night", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R1", - 2020, - "fall", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2030, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "fall", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "fall", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2020, - "winter", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "winter", - "day", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R1", - 2030, - "spring", - "night", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2", - 2025, - "fall", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "summer", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "summer", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "fall", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2030, - "summer", - "day", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "summer", - "night", - "ethos", - "S_IMPNG", - 2020, - "NG" - ], - [ - "R2-R1", - 2030, - "winter", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R1", - 2025, - "summer", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2025, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "summer", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "night", - "ethos", - "S_IMPETH", - 2020, - "ETH" - ], - [ - "R2", - 2030, - "summer", - "day", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R2", - 2030, - "fall", - "day", - "NG", - "E_NGCC", - 2030, - "ELC" - ], - [ - "R1", - 2020, - "summer", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2030, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2030, - "fall", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2030, - "spring", - "day", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "spring", - "day", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2025, - "summer", - "day", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "winter", - "day", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R2", - 2020, - "winter", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R2", - 2020, - "spring", - "night", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "SOL", - "E_SOLPV", - 2030, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "night", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "fall", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "summer", - "day", - "ELC", - "E_BATT", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "winter", - "night", - "OIL", - "S_OILREF", - 2020, - "DSL" - ], - [ - "R1", - 2020, - "summer", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2025, - "spring", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2025, - "winter", - "day", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2020, - "fall", - "night", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2025, - "spring", - "night", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "fall", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ], - [ - "R2", - 2020, - "spring", - "night", - "OIL", - "S_OILREF", - 2020, - "GSL" - ], - [ - "R1", - 2020, - "winter", - "night", - "ethos", - "S_IMPURN", - 2020, - "URN" - ], - [ - "R1", - 2030, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "winter", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R2", - 2025, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R2", - 2030, - "spring", - "day", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R2-R1", - 2025, - "fall", - "day", - "ELC", - "E_TRANS", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "spring", - "day", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R1", - 2030, - "spring", - "day", - "ELC", - "E_BATT", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "SOL", - "E_SOLPV", - 2020, - "ELC" - ], - [ - "R1", - 2025, - "fall", - "night", - "GSL", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "winter", - "day", - "ELC", - "E_BATT", - 2030, - "ELC" - ], - [ - "R2", - 2020, - "winter", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2020, - "winter", - "day", - "URN", - "E_NUCLEAR", - 2015, - "ELC" - ], - [ - "R2", - 2025, - "summer", - "day", - "NG", - "E_NGCC", - 2025, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "winter", - "night", - "SOL", - "E_SOLPV", - 2025, - "ELC" - ], - [ - "R1", - 2025, - "spring", - "day", - "ETH", - "T_BLND", - 2020, - "E10" - ], - [ - "R2", - 2030, - "spring", - "night", - "URN", - "E_NUCLEAR", - 2020, - "ELC" - ], - [ - "R1", - 2030, - "spring", - "night", - "ethos", - "S_IMPOIL", - 2020, - "OIL" - ], - [ - "R1", - 2030, - "spring", - "night", - "NG", - "E_NGCC", - 2020, - "ELC" - ] - ], - "lifetime_process_rtv": [ - [ - "R2", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - "S_IMPURN", - 2020 - ], - [ - "R1", - "R_NGH", - 2020 - ], - [ - "R1", - "T_EV", - 2030 - ], - [ - "R2", - "T_GSL", - 2020 - ], - [ - "R2", - "S_IMPNG", - 2020 - ], - [ - "R1", - "E_BATT", - 2025 - ], - [ - "R1", - "E_SOLPV", - 2030 - ], - [ - "R2", - "E_NGCC", - 2025 - ], - [ - "R2", - "R_NGH", - 2030 - ], - [ - "R1", - "E_NGCC", - 2030 - ], - [ - "R2", - "R_EH", - 2025 - ], - [ - "R1", - "E_NUCLEAR", - 2020 - ], - [ - "R1-R2", - "E_TRANS", - 2015 - ], - [ - "R2", - "T_EV", - 2025 - ], - [ - "R1", - "R_EH", - 2030 - ], - [ - "R1", - "S_IMPETH", - 2020 - ], - [ - "R1", - "T_DSL", - 2020 - ], - [ - "R2", - "E_BATT", - 2025 - ], - [ - "R2", - "S_IMPURN", - 2020 - ], - [ - "R2", - "E_SOLPV", - 2030 - ], - [ - "R1", - "T_GSL", - 2025 - ], - [ - "R2", - "T_DSL", - 2030 - ], - [ - "R2", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - "S_OILREF", - 2020 - ], - [ - "R2-R1", - "E_TRANS", - 2015 - ], - [ - "R1", - "T_EV", - 2020 - ], - [ - "R1", - "E_SOLPV", - 2020 - ], - [ - "R2", - "R_NGH", - 2020 - ], - [ - "R2", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - "E_NGCC", - 2020 - ], - [ - "R1", - "R_NGH", - 2025 - ], - [ - "R2", - "T_GSL", - 2025 - ], - [ - "R1", - "R_EH", - 2020 - ], - [ - "R1", - "E_BATT", - 2030 - ], - [ - "R2", - "E_NGCC", - 2030 - ], - [ - "R1", - "S_IMPOIL", - 2020 - ], - [ - "R2", - "R_EH", - 2030 - ], - [ - "R2", - "E_SOLPV", - 2020 - ], - [ - "R1", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - "T_DSL", - 2020 - ], - [ - "R2", - "T_EV", - 2030 - ], - [ - "R1", - "T_DSL", - 2025 - ], - [ - "R1", - "T_GSL", - 2030 - ], - [ - "R2", - "E_BATT", - 2030 - ], - [ - "R2", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - "S_IMPETH", - 2020 - ], - [ - "R1", - "T_BLND", - 2020 - ], - [ - "R1", - "T_EV", - 2025 - ], - [ - "R1", - "E_BATT", - 2020 - ], - [ - "R1", - "E_SOLPV", - 2025 - ], - [ - "R2", - "E_NGCC", - 2020 - ], - [ - "R2", - "R_NGH", - 2025 - ], - [ - "R1", - "E_NGCC", - 2025 - ], - [ - "R1", - "R_NGH", - 2030 - ], - [ - "R2", - "R_EH", - 2020 - ], - [ - "R2", - "T_GSL", - 2030 - ], - [ - "R1", - "R_EH", - 2025 - ], - [ - "R1", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - "T_EV", - 2020 - ], - [ - "R1", - "S_IMPNG", - 2020 - ], - [ - "R2", - "S_IMPOIL", - 2020 - ], - [ - "R2", - "E_BATT", - 2020 - ], - [ - "R2", - "T_BLND", - 2020 - ], - [ - "R2", - "E_SOLPV", - 2025 - ], - [ - "R1", - "T_GSL", - 2020 - ], - [ - "R1", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - "T_DSL", - 2025 - ], - [ - "R1", - "T_DSL", - 2030 - ], - [ - "R1", - "S_OILREF", - 2020 - ] - ], - "limit_activity_constraint_rpt": [ - [ - "R1", - 2030, - "T_GSL", - "ge" - ], - [ - "R2", - 2025, - "T_GSL", - "ge" - ], - [ - "R1", - 2025, - "T_GSL", - "ge" - ], - [ - "R2", - 2020, - "T_GSL", - "ge" - ], - [ - "R2", - 2030, - "T_GSL", - "ge" - ], - [ - "R1", - 2020, - "T_GSL", - "ge" - ] - ], - "limit_activity_share_constraint_rpgg": [], - "limit_annual_capacity_factor_constraint_rptvo": [], - "limit_annual_capacity_factor_constraint_rtvo": [], - "limit_capacity_constraint_rpt": [], - "limit_capacity_share_constraint_rpgg": [], - "limit_degrowth_capacity_constraint_rpt": [], - "limit_degrowth_new_capacity_constraint_rpt": [], - "limit_degrowth_new_capacity_delta_constraint_rpt": [], - "limit_emission_constraint_rpe": [ - [ - "R1", - 2025, - "CO2", - "le" - ], - [ - "global", - 2020, - "CO2", - "le" - ], - [ - "global", - 2030, - "CO2", - "le" - ], - [ - "global", - 2025, - "CO2", - "le" - ], - [ - "R1", - 2030, - "CO2", - "le" - ], - [ - "R1", - 2020, - "CO2", - "le" - ] - ], - "limit_growth_capacity_constraint_rpt": [], - "limit_growth_new_capacity_constraint_rpt": [], - "limit_growth_new_capacity_delta_constraint_rpt": [], - "limit_new_capacity_constraint_rtv": [], - "limit_new_capacity_share_constraint_rggv": [], - "limit_resource_constraint_rt": [], - "limit_seasonal_capacity_factor_constraint_rpst": [], - "limit_seasonal_capacity_factor_constraint_rst": [], - "limit_storage_fraction_constraint_rpsdtv": [ - [ - "R1", - 2025, - "winter", - "day", - "E_BATT", - 2025, - "e" - ], - [ - "R2", - 2020, - "summer", - "day", - "E_BATT", - 2020, - "e" - ], - [ - "R1", - 2030, - "winter", - "day", - "E_BATT", - 2020, - "e" - ], - [ - "R1", - 2030, - "winter", - "day", - "E_BATT", - 2025, - "e" - ], - [ - "R2", - 2025, - "summer", - "day", - "E_BATT", - 2025, - "e" - ], - [ - "R1", - 2025, - "winter", - "day", - "E_BATT", - 2020, - "e" - ], - [ - "R2", - 2025, - "summer", - "day", - "E_BATT", - 2020, - "e" - ], - [ - "R2", - 2030, - "summer", - "day", - "E_BATT", - 2030, - "e" - ], - [ - "R2", - 2030, - "summer", - "day", - "E_BATT", - 2025, - "e" - ], - [ - "R2", - 2030, - "summer", - "day", - "E_BATT", - 2020, - "e" - ], - [ - "R1", - 2020, - "winter", - "day", - "E_BATT", - 2020, - "e" - ], - [ - "R1", - 2030, - "winter", - "day", - "E_BATT", - 2030, - "e" - ] - ], - "limit_storage_fraction_param_rsdt": [ - [ - "R1", - "winter", - "day", - "E_BATT", - "e" - ], - [ - "R2", - "summer", - "day", - "E_BATT", - "e" - ] - ], - "limit_tech_input_split_annual_constraint_rpitv": [], - "limit_tech_input_split_average_constraint_rpitv": [], - "limit_tech_input_split_constraint_rpsditv": [ - [ - "R2", - 2020, - "spring", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2020, - "spring", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2020, - "winter", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2030, - "spring", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2025, - "spring", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2025, - "fall", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2020, - "spring", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2030, - "fall", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2030, - "fall", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2025, - "spring", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2030, - "summer", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2030, - "spring", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2020, - "summer", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2030, - "summer", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2030, - "fall", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2025, - "winter", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2030, - "fall", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2030, - "winter", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2030, - "winter", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2030, - "summer", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2030, - "spring", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2025, - "winter", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2020, - "summer", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2025, - "fall", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2020, - "summer", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2025, - "summer", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2020, - "summer", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2025, - "winter", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2020, - "fall", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2020, - "fall", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2025, - "summer", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2025, - "winter", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2025, - "spring", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2020, - "fall", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2020, - "spring", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2025, - "winter", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2030, - "winter", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2020, - "spring", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2025, - "summer", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2025, - "summer", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2020, - "fall", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2020, - "winter", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2025, - "winter", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2030, - "winter", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2025, - "spring", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2025, - "winter", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2030, - "winter", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2025, - "fall", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2025, - "summer", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2025, - "spring", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2030, - "spring", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2020, - "fall", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2025, - "fall", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2030, - "summer", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2020, - "spring", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2025, - "spring", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2025, - "winter", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2020, - "winter", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2030, - "fall", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2025, - "summer", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2020, - "summer", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2030, - "fall", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2025, - "summer", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2025, - "fall", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2030, - "summer", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2020, - "summer", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2020, - "fall", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2020, - "spring", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2030, - "spring", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2030, - "spring", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2030, - "winter", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2025, - "fall", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2030, - "winter", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2025, - "fall", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2025, - "fall", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2025, - "summer", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2020, - "summer", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2030, - "spring", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2020, - "summer", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2030, - "summer", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2020, - "winter", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2020, - "spring", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2030, - "summer", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2020, - "fall", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2025, - "spring", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2030, - "fall", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2020, - "winter", - "night", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2020, - "winter", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2030, - "summer", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2020, - "winter", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2030, - "fall", - "day", - "GSL", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2030, - "spring", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2030, - "winter", - "night", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2020, - "winter", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R1", - 2020, - "fall", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ], - [ - "R2", - 2025, - "spring", - "day", - "ETH", - "T_BLND", - 2020, - "ge" - ] - ], - "limit_tech_output_split_annual_constraint_rptvo": [], - "limit_tech_output_split_average_constraint_rptvo": [], - "limit_tech_output_split_constraint_rpsdtvo": [ - [ - "R2", - 2020, - "fall", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2020, - "fall", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2020, - "fall", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2020, - "summer", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2025, - "summer", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2030, - "summer", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R1", - 2030, - "fall", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R2", - 2020, - "summer", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2030, - "winter", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2025, - "summer", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R1", - 2030, - "spring", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2025, - "summer", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R1", - 2030, - "spring", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2025, - "winter", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2025, - "winter", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R2", - 2020, - "summer", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2030, - "winter", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2025, - "winter", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2025, - "summer", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2030, - "winter", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R1", - 2025, - "summer", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R2", - 2030, - "winter", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2020, - "spring", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R2", - 2020, - "winter", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R1", - 2025, - "summer", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2025, - "summer", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R2", - 2030, - "fall", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R2", - 2020, - "spring", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2020, - "fall", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R1", - 2020, - "fall", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2030, - "summer", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R2", - 2030, - "summer", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R2", - 2025, - "fall", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R2", - 2025, - "spring", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2030, - "fall", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R1", - 2025, - "fall", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R2", - 2025, - "spring", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2025, - "spring", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2020, - "summer", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2020, - "spring", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2025, - "spring", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2025, - "fall", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R2", - 2030, - "fall", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R2", - 2030, - "spring", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2020, - "summer", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R1", - 2025, - "spring", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2025, - "summer", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R2", - 2025, - "winter", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R1", - 2030, - "winter", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2020, - "winter", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2025, - "winter", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2030, - "spring", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2020, - "summer", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2025, - "winter", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R2", - 2025, - "fall", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R2", - 2020, - "fall", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R2", - 2030, - "fall", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R1", - 2020, - "winter", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R1", - 2020, - "spring", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R1", - 2020, - "fall", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R1", - 2030, - "summer", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R1", - 2020, - "fall", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R2", - 2020, - "winter", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R2", - 2030, - "summer", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2020, - "spring", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R2", - 2025, - "fall", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2030, - "summer", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R2", - 2025, - "fall", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R1", - 2030, - "fall", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R2", - 2025, - "spring", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R1", - 2025, - "fall", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2025, - "spring", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2020, - "spring", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2030, - "winter", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2030, - "spring", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2025, - "spring", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R1", - 2020, - "spring", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R1", - 2030, - "fall", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R1", - 2025, - "fall", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2020, - "winter", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2030, - "fall", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2030, - "spring", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R1", - 2020, - "winter", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2030, - "spring", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R2", - 2025, - "winter", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R2", - 2020, - "summer", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2030, - "summer", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2030, - "winter", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2020, - "spring", - "night", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2030, - "winter", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R1", - 2020, - "winter", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2020, - "winter", - "day", - "S_OILREF", - 2020, - "GSL", - "ge" - ], - [ - "R1", - 2030, - "summer", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R2", - 2030, - "spring", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R1", - 2020, - "summer", - "day", - "S_OILREF", - 2020, - "DSL", - "ge" - ], - [ - "R1", - 2025, - "winter", - "night", - "S_OILREF", - 2020, - "DSL", - "ge" - ] - ], - "linked_emissions_tech_constraint_rpsdtve": [], - "loan_lifetime_process_rtv": [ - [ - "R2", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - "S_IMPURN", - 2020 - ], - [ - "R1", - "R_NGH", - 2020 - ], - [ - "R1", - "T_EV", - 2030 - ], - [ - "R2", - "T_GSL", - 2020 - ], - [ - "R2", - "S_IMPNG", - 2020 - ], - [ - "R1", - "E_BATT", - 2025 - ], - [ - "R1", - "E_SOLPV", - 2030 - ], - [ - "R2", - "E_NGCC", - 2025 - ], - [ - "R2", - "R_NGH", - 2030 - ], - [ - "R1", - "E_NGCC", - 2030 - ], - [ - "R2", - "R_EH", - 2025 - ], - [ - "R1", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - "T_EV", - 2025 - ], - [ - "R1", - "R_EH", - 2030 - ], - [ - "R1", - "S_IMPETH", - 2020 - ], - [ - "R1", - "T_DSL", - 2020 - ], - [ - "R2", - "E_BATT", - 2025 - ], - [ - "R2", - "S_IMPURN", - 2020 - ], - [ - "R2", - "E_SOLPV", - 2030 - ], - [ - "R1", - "T_GSL", - 2025 - ], - [ - "R2", - "T_DSL", - 2030 - ], - [ - "R2", - "S_OILREF", - 2020 - ], - [ - "R1", - "T_EV", - 2020 - ], - [ - "R1", - "E_SOLPV", - 2020 - ], - [ - "R2", - "R_NGH", - 2020 - ], - [ - "R2", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - "E_NGCC", - 2020 - ], - [ - "R1", - "R_NGH", - 2025 - ], - [ - "R2", - "T_GSL", - 2025 - ], - [ - "R1", - "R_EH", - 2020 - ], - [ - "R1", - "E_BATT", - 2030 - ], - [ - "R2", - "E_NGCC", - 2030 - ], - [ - "R1", - "S_IMPOIL", - 2020 - ], - [ - "R2", - "R_EH", - 2030 - ], - [ - "R2", - "E_SOLPV", - 2020 - ], - [ - "R1", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - "T_DSL", - 2020 - ], - [ - "R2", - "T_EV", - 2030 - ], - [ - "R1", - "T_DSL", - 2025 - ], - [ - "R1", - "T_GSL", - 2030 - ], - [ - "R2", - "E_BATT", - 2030 - ], - [ - "R2", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - "S_IMPETH", - 2020 - ], - [ - "R1", - "T_BLND", - 2020 - ], - [ - "R1", - "T_EV", - 2025 - ], - [ - "R1", - "E_BATT", - 2020 - ], - [ - "R1", - "E_SOLPV", - 2025 - ], - [ - "R2", - "E_NGCC", - 2020 - ], - [ - "R2", - "R_NGH", - 2025 - ], - [ - "R1", - "E_NGCC", - 2025 - ], - [ - "R1", - "R_NGH", - 2030 - ], - [ - "R2", - "R_EH", - 2020 - ], - [ - "R2", - "T_GSL", - 2030 - ], - [ - "R1", - "R_EH", - 2025 - ], - [ - "R2", - "T_EV", - 2020 - ], - [ - "R1", - "S_IMPNG", - 2020 - ], - [ - "R2", - "S_IMPOIL", - 2020 - ], - [ - "R2", - "E_BATT", - 2020 - ], - [ - "R2", - "T_BLND", - 2020 - ], - [ - "R2", - "E_SOLPV", - 2025 - ], - [ - "R1", - "T_GSL", - 2020 - ], - [ - "R1", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - "T_DSL", - 2025 - ], - [ - "R1", - "T_DSL", - 2030 - ], - [ - "R1", - "S_OILREF", - 2020 - ], - [ - "R1", - "E_NUCLEAR", - 2015 - ], - [ - "R2", - "E_NUCLEAR", - 2015 - ], - [ - "R1-R2", - "E_TRANS", - 2015 - ], - [ - "R2-R1", - "E_TRANS", - 2015 - ] - ], - "new_capacity_var_rtv": [ - [ - "R2", - "E_NUCLEAR", - 2025 - ], - [ - "R1", - "R_NGH", - 2020 - ], - [ - "R1", - "T_EV", - 2030 - ], - [ - "R2", - "T_GSL", - 2020 - ], - [ - "R1", - "E_BATT", - 2025 - ], - [ - "R1", - "E_SOLPV", - 2030 - ], - [ - "R2", - "E_NGCC", - 2025 - ], - [ - "R2", - "R_NGH", - 2030 - ], - [ - "R1", - "E_NGCC", - 2030 - ], - [ - "R2", - "R_EH", - 2025 - ], - [ - "R1", - "E_NUCLEAR", - 2020 - ], - [ - "R2", - "T_EV", - 2025 - ], - [ - "R1", - "R_EH", - 2030 - ], - [ - "R1", - "T_DSL", - 2020 - ], - [ - "R2", - "E_BATT", - 2025 - ], - [ - "R2", - "E_SOLPV", - 2030 - ], - [ - "R1", - "T_GSL", - 2025 - ], - [ - "R2", - "T_DSL", - 2030 - ], - [ - "R2", - "S_OILREF", - 2020 - ], - [ - "R1", - "T_EV", - 2020 - ], - [ - "R1", - "E_SOLPV", - 2020 - ], - [ - "R2", - "R_NGH", - 2020 - ], - [ - "R2", - "E_NUCLEAR", - 2030 - ], - [ - "R1", - "E_NGCC", - 2020 - ], - [ - "R1", - "R_NGH", - 2025 - ], - [ - "R2", - "T_GSL", - 2025 - ], - [ - "R1", - "R_EH", - 2020 - ], - [ - "R1", - "E_BATT", - 2030 - ], - [ - "R2", - "E_NGCC", - 2030 - ], - [ - "R2", - "R_EH", - 2030 - ], - [ - "R2", - "E_SOLPV", - 2020 - ], - [ - "R1", - "E_NUCLEAR", - 2025 - ], - [ - "R2", - "T_DSL", - 2020 - ], - [ - "R2", - "T_EV", - 2030 - ], - [ - "R1", - "T_DSL", - 2025 - ], - [ - "R1", - "T_GSL", - 2030 - ], - [ - "R2", - "E_BATT", - 2030 - ], - [ - "R2", - "E_NUCLEAR", - 2020 - ], - [ - "R1", - "T_BLND", - 2020 - ], - [ - "R1", - "T_EV", - 2025 - ], - [ - "R1", - "E_BATT", - 2020 - ], - [ - "R1", - "E_SOLPV", - 2025 - ], - [ - "R2", - "E_NGCC", - 2020 - ], - [ - "R2", - "R_NGH", - 2025 - ], - [ - "R1", - "E_NGCC", - 2025 - ], - [ - "R1", - "R_NGH", - 2030 - ], - [ - "R2", - "R_EH", - 2020 - ], - [ - "R2", - "T_GSL", - 2030 - ], - [ - "R1", - "R_EH", - 2025 - ], - [ - "R2", - "T_EV", - 2020 - ], - [ - "R2", - "E_BATT", - 2020 - ], - [ - "R2", - "T_BLND", - 2020 - ], - [ - "R2", - "E_SOLPV", - 2025 - ], - [ - "R1", - "T_GSL", - 2020 - ], - [ - "R1", - "E_NUCLEAR", - 2030 - ], - [ - "R2", - "T_DSL", - 2025 - ], - [ - "R1", - "T_DSL", - 2030 - ], - [ - "R1", - "S_OILREF", - 2020 - ] - ], - "process_life_frac_rptv": [ - [ - "R2", - 2030, - "R_NGH", - 2030 - ], - [ - "R2", - 2020, - "S_IMPETH", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "E_NGCC", - 2025 - ], - [ - "R2", - 2030, - "S_IMPNG", - 2020 - ], - [ - "R2", - 2020, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2025, - "S_IMPURN", - 2020 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "R_NGH", - 2025 - ], - [ - "R2", - 2030, - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "S_IMPNG", - 2020 - ], - [ - "R1", - 2030, - "R_EH", - 2020 - ], - [ - "R2", - 2020, - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2020, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2030, - "T_EV", - 2030 - ], - [ - "R2", - 2030, - "T_DSL", - 2020 - ], - [ - "R2", - 2025, - "T_DSL", - 2020 - ], - [ - "R1", - 2030, - "T_EV", - 2025 - ], - [ - "R1", - 2030, - "S_IMPNG", - 2020 - ], - [ - "R1", - 2020, - "S_IMPNG", - 2020 - ], - [ - "R1", - 2025, - "S_IMPETH", - 2020 - ], - [ - "R1", - 2025, - "T_GSL", - 2025 - ], - [ - "R1", - 2030, - "S_IMPURN", - 2020 - ], - [ - "R2", - 2030, - "R_NGH", - 2025 - ], - [ - "R1", - 2020, - "S_IMPURN", - 2020 - ], - [ - "R2", - 2020, - "S_OILREF", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "E_NGCC", - 2020 - ], - [ - "R2", - 2020, - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2025, - "R_NGH", - 2025 - ], - [ - "R1", - 2030, - "R_NGH", - 2020 - ], - [ - "R2", - 2020, - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2025 - ], - [ - "R2-R1", - 2020, - "E_TRANS", - 2015 - ], - [ - "R2", - 2030, - "T_GSL", - 2030 - ], - [ - "R2-R1", - 2030, - "E_TRANS", - 2015 - ], - [ - "R1", - 2030, - "E_NGCC", - 2030 - ], - [ - "R2", - 2025, - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2025 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "T_EV", - 2025 - ], - [ - "R1", - 2020, - "T_DSL", - 2020 - ], - [ - "R2", - 2020, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2025, - "T_EV", - 2025 - ], - [ - "R1", - 2030, - "T_EV", - 2020 - ], - [ - "R1", - 2025, - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "S_IMPOIL", - 2020 - ], - [ - "R1", - 2025, - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "T_GSL", - 2020 - ], - [ - "R1", - 2030, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "R_NGH", - 2020 - ], - [ - "R1", - 2020, - "T_BLND", - 2020 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2030 - ], - [ - "R2", - 2020, - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "S_IMPETH", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2030 - ], - [ - "R1", - 2030, - "T_GSL", - 2030 - ], - [ - "R2", - 2025, - "R_NGH", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2020 - ], - [ - "R2", - 2030, - "T_GSL", - 2025 - ], - [ - "R2", - 2025, - "S_IMPETH", - 2020 - ], - [ - "R1", - 2030, - "E_NGCC", - 2025 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2015 - ], - [ - "R2", - 2030, - "T_EV", - 2020 - ], - [ - "R1-R2", - 2025, - "E_TRANS", - 2015 - ], - [ - "R2", - 2025, - "T_GSL", - 2025 - ], - [ - "R2", - 2020, - "S_IMPNG", - 2020 - ], - [ - "R2", - 2025, - "T_EV", - 2020 - ], - [ - "R2", - 2025, - "S_IMPOIL", - 2020 - ], - [ - "R1", - 2025, - "T_DSL", - 2025 - ], - [ - "R2", - 2025, - "T_BLND", - 2020 - ], - [ - "R1", - 2030, - "R_EH", - 2030 - ], - [ - "R1", - 2030, - "S_IMPETH", - 2020 - ], - [ - "R1", - 2025, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2025 - ], - [ - "R2", - 2030, - "S_OILREF", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "T_GSL", - 2025 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2020, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2025, - "S_IMPURN", - 2020 - ], - [ - "R2", - 2030, - "T_GSL", - 2020 - ], - [ - "R2", - 2025, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "E_NGCC", - 2025 - ], - [ - "R1", - 2030, - "E_NGCC", - 2020 - ], - [ - "R1", - 2020, - "E_NGCC", - 2020 - ], - [ - "R2", - 2025, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2025, - "R_EH", - 2025 - ], - [ - "R2", - 2025, - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "T_EV", - 2020 - ], - [ - "R2-R1", - 2025, - "E_TRANS", - 2015 - ], - [ - "R1", - 2020, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2020, - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "T_DSL", - 2020 - ], - [ - "R2", - 2030, - "R_EH", - 2030 - ], - [ - "R1", - 2030, - "T_DSL", - 2030 - ], - [ - "R1", - 2030, - "S_OILREF", - 2020 - ], - [ - "R1", - 2025, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "E_NGCC", - 2020 - ], - [ - "R1", - 2030, - "T_GSL", - 2020 - ], - [ - "R1", - 2020, - "T_GSL", - 2020 - ], - [ - "R2", - 2020, - "S_IMPURN", - 2020 - ], - [ - "R1", - 2020, - "E_NUCLEAR", - 2015 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2030 - ], - [ - "R1", - 2025, - "R_NGH", - 2025 - ], - [ - "R2", - 2025, - "E_NGCC", - 2020 - ], - [ - "R1", - 2025, - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "R_EH", - 2020 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2025 - ], - [ - "R2", - 2025, - "E_SOLPV", - 2025 - ], - [ - "R1", - 2020, - "E_SOLPV", - 2020 - ], - [ - "R1-R2", - 2030, - "E_TRANS", - 2015 - ], - [ - "R2", - 2020, - "T_DSL", - 2020 - ], - [ - "R1-R2", - 2020, - "E_TRANS", - 2015 - ], - [ - "R1", - 2025, - "T_EV", - 2025 - ], - [ - "R1", - 2025, - "S_IMPNG", - 2020 - ], - [ - "R2", - 2030, - "T_DSL", - 2030 - ], - [ - "R2", - 2030, - "R_EH", - 2025 - ], - [ - "R1", - 2020, - "S_IMPETH", - 2020 - ], - [ - "R2", - 2030, - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2025, - "R_EH", - 2025 - ], - [ - "R1", - 2030, - "T_DSL", - 2025 - ], - [ - "R1", - 2020, - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2025 - ], - [ - "R1", - 2025, - "R_NGH", - 2020 - ], - [ - "R1", - 2025, - "E_NUCLEAR", - 2020 - ], - [ - "R1", - 2030, - "R_NGH", - 2030 - ], - [ - "R2", - 2030, - "E_BATT", - 2030 - ], - [ - "R2", - 2025, - "E_SOLPV", - 2020 - ], - [ - "R1", - 2030, - "R_EH", - 2025 - ], - [ - "R1", - 2025, - "T_EV", - 2020 - ], - [ - "R1", - 2030, - "E_NUCLEAR", - 2030 - ], - [ - "R2", - 2030, - "T_DSL", - 2025 - ], - [ - "R1", - 2025, - "S_IMPOIL", - 2020 - ], - [ - "R2", - 2030, - "R_EH", - 2020 - ], - [ - "R1", - 2020, - "S_OILREF", - 2020 - ], - [ - "R2", - 2025, - "T_DSL", - 2025 - ], - [ - "R2", - 2025, - "R_EH", - 2020 - ], - [ - "R1", - 2030, - "T_EV", - 2030 - ], - [ - "R1", - 2030, - "T_DSL", - 2020 - ], - [ - "R1", - 2025, - "T_BLND", - 2020 - ], - [ - "R2", - 2020, - "R_NGH", - 2020 - ], - [ - "R1", - 2030, - "E_SOLPV", - 2020 - ], - [ - "R2", - 2030, - "S_IMPURN", - 2020 - ] - ], - "ramp_down_day_constraint_rpsdtv": [], - "ramp_down_season_constraint_rpsstv": [], - "ramp_up_day_constraint_rpsdtv": [], - "ramp_up_season_constraint_rpsstv": [], - "regional_exchange_capacity_constraint_rrptv": [ - [ - "R2", - "R1", - 2030, - "E_TRANS", - 2015 - ], - [ - "R1", - "R2", - 2030, - "E_TRANS", - 2015 - ], - [ - "R2", - "R1", - 2020, - "E_TRANS", - 2015 - ], - [ - "R2", - "R1", - 2025, - "E_TRANS", - 2015 - ], - [ - "R1", - "R2", - 2025, - "E_TRANS", - 2015 - ], - [ - "R1", - "R2", - 2020, - "E_TRANS", - 2015 - ] - ], - "renewable_portfolio_standard_constraint_rpg": [], - "reserve_margin_rpsd": [], - "reserve_margin_method": [ - "static" - ], - "retired_capacity_var_rptv": [], - "seasonal_storage_level_rpstv": [], - "seasonal_storage_constraints_rpsdtv": [], - "storage_constraints_rpsdtv": [ - [ - "R1", - 2025, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_BATT", - 2030 - ], - [ - "R2", - 2020, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2020, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_BATT", - 2030 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_BATT", - 2030 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2020, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_BATT", - 2030 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2020, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_BATT", - 2030 - ], - [ - "R1", - 2020, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_BATT", - 2030 - ], - [ - "R2", - 2020, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_BATT", - 2030 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_BATT", - 2030 - ], - [ - "R2", - 2020, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_BATT", - 2030 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_BATT", - 2030 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_BATT", - 2030 - ], - [ - "R2", - 2020, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_BATT", - 2030 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_BATT", - 2030 - ] - ], - "storage_level_rpsdtv": [ - [ - "R1", - 2025, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_BATT", - 2030 - ], - [ - "R2", - 2020, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2020, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_BATT", - 2030 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_BATT", - 2030 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2020, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_BATT", - 2030 - ], - [ - "R2", - 2030, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2020, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_BATT", - 2030 - ], - [ - "R1", - 2020, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_BATT", - 2030 - ], - [ - "R2", - 2020, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_BATT", - 2030 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_BATT", - 2030 - ], - [ - "R2", - 2020, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_BATT", - 2030 - ], - [ - "R1", - 2030, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "fall", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "spring", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_BATT", - 2030 - ], - [ - "R2", - 2030, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "winter", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_BATT", - 2030 - ], - [ - "R2", - 2020, - "summer", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "fall", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "spring", - "day", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "fall", - "day", - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "summer", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "summer", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "winter", - "night", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "winter", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "winter", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "fall", - "night", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "summer", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "spring", - "day", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "spring", - "night", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "summer", - "night", - "E_BATT", - 2030 - ], - [ - "R2", - 2030, - "winter", - "day", - "E_BATT", - 2030 - ] - ], - "time_manual": [], - "commodity_all": [ - "ethos", - "RH", - "OIL", - "VMT", - "SOL", - "ELC", - "DSL", - "CO2", - "URN", - "E10", - "GSL", - "NG", - "ETH" - ], - "commodity_annual": [], - "commodity_carrier": [ - "ethos", - "RH", - "OIL", - "VMT", - "SOL", - "ELC", - "DSL", - "URN", - "E10", - "GSL", - "NG", - "ETH" - ], - "commodity_demand": [ - "VMT", - "RH" - ], - "commodity_emissions": [ - "CO2" - ], - "commodity_flex": [], - "commodity_physical": [ - "ethos", - "OIL", - "SOL", - "ELC", - "DSL", - "URN", - "E10", - "GSL", - "NG", - "ETH" - ], - "commodity_sink": [ - "VMT", - "RH" - ], - "commodity_source": [ - "ethos", - "SOL" - ], - "commodity_waste": [], - "operator": [ - "ge", - "e", - "le" - ], - "ordered_season_sequential": [], - "regional_global_indices": [ - "R2", - "R1", - "global" - ], - "regional_indices": [ - "R2", - "R1-R2", - "R1", - "R2-R1" - ], - "regions": [ - "R2", - "R1" - ], - "tech_all": [ - "S_IMPETH", - "S_IMPNG", - "S_IMPOIL", - "T_BLND", - "R_NGH", - "S_OILREF", - "E_TRANS", - "T_EV", - "E_NGCC", - "R_EH", - "T_GSL", - "S_IMPURN", - "E_BATT", - "E_SOLPV", - "E_NUCLEAR", - "T_DSL" - ], - "tech_annual": [], - "tech_demand": [ - "T_EV", - "R_NGH", - "T_GSL", - "R_EH", - "T_DSL" - ], - "tech_baseload": [ - "E_NUCLEAR" - ], - "tech_curtailment": [ - "S_OILREF" - ], - "tech_downramping": [], - "tech_exchange": [ - "E_TRANS" - ], - "tech_exist": [ - "E_TRANS", - "E_NUCLEAR" - ], - "tech_flex": [], - "tech_group_members": [], - "tech_group_names": [], - "tech_or_group": [ - "E_BATT", - "R_EH", - "S_OILREF", - "T_GSL", - "S_IMPURN", - "S_IMPNG", - "T_EV", - "E_SOLPV", - "T_DSL", - "R_NGH", - "E_NGCC", - "S_IMPETH", - "S_IMPOIL", - "T_BLND", - "E_TRANS", - "E_NUCLEAR" - ], - "tech_production": [ - "T_BLND", - "R_NGH", - "S_OILREF", - "E_TRANS", - "T_EV", - "E_NGCC", - "R_EH", - "T_GSL", - "E_BATT", - "E_SOLPV", - "E_NUCLEAR", - "T_DSL", - "S_IMPETH", - "S_IMPNG", - "S_IMPURN", - "S_IMPOIL" - ], - "tech_reserve": [], - "tech_retirement": [], - "tech_seasonal_storage": [], - "tech_storage": [ - "E_BATT" - ], - "tech_uncap": [ - "S_IMPETH", - "S_IMPNG", - "S_IMPURN", - "S_IMPOIL" - ], - "tech_upramping": [], - "tech_with_capacity": [ - "T_BLND", - "R_NGH", - "S_OILREF", - "E_TRANS", - "T_EV", - "E_NGCC", - "R_EH", - "T_GSL", - "E_BATT", - "E_SOLPV", - "E_NUCLEAR", - "T_DSL" - ], - "time_exist": [ - 2015 - ], - "time_future": [ - 2025, - 2035, - 2020, - 2030 - ], - "time_of_day": [ - "day", - "night" - ], - "time_optimize": [ - 2025, - 2020, - 2030 - ], - "time_season": [ - "summer", - "fall", - "spring", - "winter" - ], - "time_season_sequential": [], - "time_sequencing": [ - "seasonal_timeslices" - ], - "vintage_all": [ - 2025, - 2020, - 2030, - 2015 - ], - "vintage_exist": [ - 2015 - ], - "vintage_optimize": [ - 2025, - 2020, - 2030 - ], - "storage_init_rpstv": [ - [ - "R1", - 2025, - "winter", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "spring", - "E_BATT", - 2030 - ], - [ - "R2", - 2030, - "summer", - "E_BATT", - 2030 - ], - [ - "R2", - 2020, - "winter", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "spring", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "summer", - "E_BATT", - 2030 - ], - [ - "R1", - 2025, - "spring", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "winter", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "spring", - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "fall", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "summer", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "fall", - "E_BATT", - 2030 - ], - [ - "R1", - 2020, - "winter", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "fall", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "winter", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "summer", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "spring", - "E_BATT", - 2020 - ], - [ - "R2", - 2020, - "summer", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "winter", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "fall", - "E_BATT", - 2030 - ], - [ - "R2", - 2020, - "spring", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "summer", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "summer", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "fall", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "spring", - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "spring", - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "fall", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "winter", - "E_BATT", - 2025 - ], - [ - "R1", - 2020, - "spring", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "fall", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "summer", - "E_BATT", - 2025 - ], - [ - "R2", - 2030, - "spring", - "E_BATT", - 2025 - ], - [ - "R1", - 2020, - "fall", - "E_BATT", - 2020 - ], - [ - "R1", - 2025, - "winter", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "winter", - "E_BATT", - 2030 - ], - [ - "R1", - 2030, - "summer", - "E_BATT", - 2025 - ], - [ - "R1", - 2025, - "summer", - "E_BATT", - 2025 - ], - [ - "R2", - 2025, - "spring", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "summer", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "fall", - "E_BATT", - 2025 - ], - [ - "R1", - 2030, - "spring", - "E_BATT", - 2030 - ], - [ - "R2", - 2025, - "fall", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "winter", - "E_BATT", - 2030 - ], - [ - "R2", - 2020, - "fall", - "E_BATT", - 2020 - ], - [ - "R2", - 2025, - "winter", - "E_BATT", - 2020 - ], - [ - "R1", - 2020, - "summer", - "E_BATT", - 2020 - ], - [ - "R2", - 2030, - "winter", - "E_BATT", - 2020 - ], - [ - "R1", - 2030, - "fall", - "E_BATT", - 2025 - ] - ] -} + "operator": "74d830836f1399fb336a0432dde7d7bd36cffa3ff76b1c42d7945350cfb9bf91", + "time_exist": "5206b4814992da4c7a4f643fdf04124735accc989ec0047874eb80e8541766c9", + "time_future": "2739be4c64d75aa5fb1552392c1f9d5587f15dba7a728f1768e415c0792b044e", + "time_optimize": "376da8132a26c5ebebc6d27395c2c883261928ac8d91004c167843c1e21d6141", + "vintage_exist": "5206b4814992da4c7a4f643fdf04124735accc989ec0047874eb80e8541766c9", + "vintage_optimize": "376da8132a26c5ebebc6d27395c2c883261928ac8d91004c167843c1e21d6141", + "vintage_all": "a19045d7d5b67af65f00af8d62f398968fea2c2d418f182b5d3ad0a56415eddf", + "time_season": "6d8e2fd49929c1f5216c0313307108c4993e58b00207210d3b6390d3f64e2896", + "time_season_sequential": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "time_of_day": "9f58a9fbc74271e641f4b7624b22daca061195a3d85b58d270fb8590937007b1", + "ordered_season_sequential": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "regions": "0ddd05d695b255ac719dfa85de1e900a3036d547ffc7261c9c9ca2c81bfda029", + "regional_indices": "f74187f92c4fdb3c12d5610304c7ac9696001433150bdaa9ff20793fb6365b32", + "regional_global_indices": "92fa6c5d5745d765d6e16ad1bca7e1fc72f4377273be7cfbfde626ca1967d81b", + "tech_production": "85a3645929dbeaf6b7eb17e8085c8923ef86949eaa3fb4fd81724dcdcf38fd30", + "tech_all": "85a3645929dbeaf6b7eb17e8085c8923ef86949eaa3fb4fd81724dcdcf38fd30", + "tech_baseload": "050aff703818154bf3439ed7d4a2cfef892be61da0c477526001c8c38b41a935", + "tech_annual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_demand": "cf8d1075bb0667935fc3834c5266e775d1c746692179ef253809eaaa7abab6f8", + "tech_storage": "7109b89425e6707adc8a5e571bf70fc64475d2d76471e5afe93110fd86bbcec8", + "tech_reserve": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_upramping": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_downramping": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_curtailment": "81683c0099a4eb22c8cca4b8eaf65a5bbf77c24b559cd1219823e6d6eb6cf915", + "tech_flex": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_exchange": "6610eb4a0360be009669b5d50a2c3e1447bcf39eb820a0e63fd3718c27fae768", + "tech_group_names": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_group_members": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_or_group": "85a3645929dbeaf6b7eb17e8085c8923ef86949eaa3fb4fd81724dcdcf38fd30", + "tech_seasonal_storage": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_uncap": "50b9da0bce0fcc3b318930929a2191c6c6c5e535e9ee986ca2ee740c7ff789bc", + "tech_exist": "eefd900ce35331470ba9f3312de6f03883efb5f402d321ff714cfe22d9ecdf94", + "tech_with_capacity": "bf3db0293ae9b3ec605ba8260a111eb71cbf3a786077a8172142a4e90ca1141b", + "tech_retirement": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "commodity_demand": "6b657255c2baf8b6d4fc96f21cb21263bae7378eb11a9b9cf25a0d8aa83c6aca", + "commodity_emissions": "6aa406c61418fb1a0cc0d9f505fafcbf94e65a66cb5c5f1dc0afa8117b762979", + "commodity_physical": "555367a723a957f166d9ec6c580ea46e958bd3a3f684aceee050e26ba2d423c6", + "commodity_waste": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "commodity_flex": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "commodity_source": "44567fa34febd7556a3797bba4949e8d57aa1416fc240258417955809226d723", + "commodity_sink": "6b657255c2baf8b6d4fc96f21cb21263bae7378eb11a9b9cf25a0d8aa83c6aca", + "commodity_annual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "commodity_carrier": "3508a787012b20265e9c97acebe2c39d6648b972e7bb4a6d42083e7e167b5c92", + "commodity_all": "01fbdcd2e272aa7c36fbf1400e575188f4501e1957bba1dc2b29cd11ec6a070c", + "time_sequencing": "91f69c8abab9959c1f8c90f5aaa56db29bccc67e37d12673ab41c54e4179d7ca", + "time_manual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "demand_constraint_rpc": "eae7c4920f895c8e036bc95461418eafb9dc9eb1f836755ad16c78b945019623", + "lifetime_process_rtv": "5033502364848a3a3f295f1b3d051531ecd5c1e5f8bbaecd61afcd18181225ab", + "loan_lifetime_process_rtv": "5033502364848a3a3f295f1b3d051531ecd5c1e5f8bbaecd61afcd18181225ab", + "renewable_portfolio_standard_constraint_rpg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "capacity_factor_rsdt": "53e46681758c146b82380d26b0fc8eb4f6e95a91c3c2766221e33f895863e1aa", + "capacity_constraint_rpsdtv": "cd98cf3db577dec19c292199f5b7b8af2dfe336174af315ce2186bbcbd8e81cf", + "cost_fixed_rptv": "d839477ae7f5d8fc897e2df4c3c519d742f946b2ce74e1d92fff91e50285296f", + "cost_invest_rtv": "46d311691b8fc8d384d75ae29216ecbbd4ecb16253e4d1836e868c5b2f8a6bc5", + "cost_variable_rptv": "5501652d0145dbf7c2e8c006aabd3dbb85ca64ed5caf1d8f45a1957274af81ca", + "cost_emission_rpe": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "process_life_frac_rptv": "5501652d0145dbf7c2e8c006aabd3dbb85ca64ed5caf1d8f45a1957274af81ca", + "limit_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_new_capacity_constraint_rtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_resource_constraint_rt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_activity_constraint_rpt": "2561103e7e6dd3dee3ba5832290ab5e933f4af08661dff4f2e661b6f4ffefc86", + "limit_seasonal_capacity_factor_constraint_rst": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_seasonal_capacity_factor_constraint_rpst": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_annual_capacity_factor_constraint_rtvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_emission_constraint_rpe": "6f11e4ee041970584903d5afba7ee1147824b233260422564fdf0c701e9fabde", + "emission_activity_reitvo": "a161b5d9619833e599c9201d4da6e0f45df261cfb93b185b5840daee36880443", + "limit_capacity_share_constraint_rpgg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_activity_share_constraint_rpgg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_new_capacity_share_constraint_rggv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "storage_constraints_rpsdtv": "a724916a2cae70bf0de3b0af98d53d017c515cec75692363b541580ead74dc7c", + "seasonal_storage_constraints_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_storage_fraction_param_rsdt": "426fc3cc85aeb1d61ea1e862f82915520e380ee9dbdf81c17423dc881a29791b", + "limit_storage_fraction_constraint_rpsdtv": "13bd0438fa93073d0820deb25c91729fc14bde24f8053cbc42f9412d10f25cd3", + "reserve_margin_method": "7869283c0d14273f720716309207a8f0c24606d03c679d6b68e656ed8d86241d", + "flow_var_rpsditvo": "784d98e451a8dcf0122f475c2e229162d99e403bdea85f7c608a3d86e850db44", + "flow_var_annual_rpitvo": "f98f5f41c5cba8ce2a894734abbc5e90310b695bee3c24c52acd8b4800c5ab85", + "flex_var_rpsditvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "flex_var_annual_rpitvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "curtailment_var_rpsditvo": "6bdb84e67318e7f5bbaeb28a90ab905caea9f826814f330a3e075c21befbbce7", + "flow_in_storage_rpsditvo": "8c97fbeacbca1a772ba04f63d0a82f7703500f83c0dc602114b17c64ad4d2e28", + "storage_level_rpsdtv": "a724916a2cae70bf0de3b0af98d53d017c515cec75692363b541580ead74dc7c", + "storage_init_rpstv": "60214760f620f09278b3aa4b6b510411c1e2c177df5e80838ab97917ca84445d", + "seasonal_storage_level_rpstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "capacity_var_rptv": "d839477ae7f5d8fc897e2df4c3c519d742f946b2ce74e1d92fff91e50285296f", + "new_capacity_var_rtv": "bc0ec9e7f812410cb2af924cbc99a31c6e99cd95fc2de26193daad38f33cc132", + "retired_capacity_var_rptv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "annual_retirement_var_rptv": "ee162bcd5c52c6e713033f89c7ffd0d244e4a34721217cfaf699959b131adcda", + "capacity_available_var_rpt": "8f305de45d0d42708ef17b16602d770ef731810252b0d0b3a89dc396b54b8e8a", + "capacity_annual_constraint_rptv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "demand_activity_constraint_rpsdtv_dem": "5e98cba1dc8ee89799becaa6a4bb7824d41badf80940f18ddb11724ec883e93d", + "commodity_balance_constraint_rpsdc": "4a46a0de6ec903639858a35c63fc46223f82ab1e057b20f4a1624eacb6652229", + "annual_commodity_balance_constraint_rpc": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "baseload_diurnal_constraint_rpsdtv": "20070e9c3c7443e237d3779a8ef33a25ae3a29284f5e1158a257f1a1d80c1421", + "regional_exchange_capacity_constraint_rrptv": "ae0671daa1263140faff22e3d2610c1fbab942d4e814892a50471adfa1bcc740", + "ramp_up_day_constraint_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "ramp_down_day_constraint_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "ramp_up_season_constraint_rpsstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "ramp_down_season_constraint_rpsstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "reserve_margin_rpsd": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_growth_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_degrowth_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_growth_new_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_degrowth_new_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_growth_new_capacity_delta_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_degrowth_new_capacity_delta_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_annual_capacity_factor_constraint_rptvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_tech_input_split_constraint_rpsditv": "ccadc066c091a1c0326154aff6b60229c6f1885a8ace32b7957aff39af910682", + "limit_tech_input_split_annual_constraint_rpitv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_tech_input_split_average_constraint_rpitv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_tech_output_split_constraint_rpsdtvo": "115dc2061e98232f0b3b4884fedd68d5bb347dc04db7debf615655ba1e511d35", + "limit_tech_output_split_annual_constraint_rptvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_tech_output_split_average_constraint_rptvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "linked_emissions_tech_constraint_rpsdtve": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945" +} \ No newline at end of file diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index a69112919..74631b93d 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -1,24326 +1,115 @@ { - "annual_commodity_balance_constraint_rpc": [], - "annual_retirement_var_rptv": [ - [ - "utopia", - 2010, - "TXD", - 2000 - ], - [ - "utopia", - 2000, - "TXG", - 1970 - ], - [ - "utopia", - 2010, - "E70", - 1970 - ], - [ - "utopia", - 2010, - "TXG", - 1980 - ], - [ - "utopia", - 2000, - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "E70", - 1960 - ], - [ - "utopia", - 2010, - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "RHO", - 1970 - ], - [ - "utopia", - 2010, - "RL1", - 2000 - ], - [ - "utopia", - 2010, - "RHO", - 1980 - ], - [ - "utopia", - 2000, - "RL1", - 1990 - ], - [ - "utopia", - 2000, - "TXD", - 1970 - ], - [ - "utopia", - 2000, - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "TXG", - 2000 - ], - [ - "utopia", - 2010, - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "RL1", - 1980 - ], - [ - "utopia", - 2000, - "E01", - 1960 - ], - [ - "utopia", - 2010, - "E01", - 1970 - ], - [ - "utopia", - 2000, - "TXD", - 1990 - ] - ], - "baseload_diurnal_constraint_rpsdtv": [ - [ - "utopia", - 2010, - "inter", - "night", - "E21", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E31", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E01", - 1970 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E21", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E01", - 1960 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E01", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E01", - 1970 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E21", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E01", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E21", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E21", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E01", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E01", - 1970 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E31", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E31", - 2010 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E31", - 2010 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E31", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E21", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E01", - 1960 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E21", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E01", - 2010 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E31", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E01", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E01", - 1970 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E31", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E31", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E21", - 2010 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E21", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E21", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E01", - 1960 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E21", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E01", - 1970 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E01", - 1970 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E01", - 2010 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E21", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E31", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E21", - 2010 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E01", - 1970 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E21", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E01", - 1970 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E01", - 1970 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E31", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E31", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E31", - 2010 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E01", - 1970 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E01", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E01", - 1960 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E21", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E31", - 2010 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E01", - 1960 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E01", - 1960 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E01", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E21", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E01", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E01", - 1970 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E01", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E21", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E21", - 2010 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E31", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E21", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E21", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E01", - 2010 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E01", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E21", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E31", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E31", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E21", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E01", - 1970 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E01", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E01", - 2010 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E31", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E31", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E21", - 1990 - ] - ], - "capacity_annual_constraint_rptv": [], - "capacity_available_var_rpt": [ - [ - "utopia", - 2000, - "E01" - ], - [ - "utopia", - 2000, - "E51" - ], - [ - "utopia", - 2010, - "E70" - ], - [ - "utopia", - 2010, - "RL1" - ], - [ - "utopia", - 2010, - "TXE" - ], - [ - "utopia", - 1990, - "E70" - ], - [ - "utopia", - 2000, - "TXG" - ], - [ - "utopia", - 1990, - "RL1" - ], - [ - "utopia", - 1990, - "TXE" - ], - [ - "utopia", - 2000, - "TXD" - ], - [ - "utopia", - 2000, - "E31" - ], - [ - "utopia", - 2000, - "E21" - ], - [ - "utopia", - 2000, - "SRE" - ], - [ - "utopia", - 2000, - "RHO" - ], - [ - "utopia", - 2000, - "E70" - ], - [ - "utopia", - 2010, - "RHE" - ], - [ - "utopia", - 2000, - "RL1" - ], - [ - "utopia", - 1990, - "E31" - ], - [ - "utopia", - 2000, - "TXE" - ], - [ - "utopia", - 1990, - "RHE" - ], - [ - "utopia", - 2010, - "E01" - ], - [ - "utopia", - 2010, - "E51" - ], - [ - "utopia", - 1990, - "E01" - ], - [ - "utopia", - 1990, - "E51" - ], - [ - "utopia", - 2010, - "TXG" - ], - [ - "utopia", - 2010, - "TXD" - ], - [ - "utopia", - 1990, - "TXG" - ], - [ - "utopia", - 1990, - "TXD" - ], - [ - "utopia", - 2000, - "RHE" - ], - [ - "utopia", - 2010, - "E31" - ], - [ - "utopia", - 2010, - "E21" - ], - [ - "utopia", - 2010, - "SRE" - ], - [ - "utopia", - 2010, - "RHO" - ], - [ - "utopia", - 1990, - "E21" - ], - [ - "utopia", - 1990, - "SRE" - ], - [ - "utopia", - 1990, - "RHO" - ] - ], - "capacity_constraint_rpsdtv": [ - [ - "utopia", - 2010, - "winter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "RHE", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXE", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E70", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHE", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E31", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXE", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXD", - 1970 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E70", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E01", - 2010 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E01", - 1970 - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXE", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXD", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E31", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E31", - 2010 - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHO", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E70", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E01", - 1960 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E21", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E01", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXD", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "day", - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXD", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "day", - "RHO", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E70", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E01", - 1970 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E21", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E70", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHE", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHE", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXG", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXD", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E21", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXD", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E70", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E70", - 2010 - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHE", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHE", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "night", - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "SRE", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXD", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E31", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHO", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHO", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHE", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E70", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXD", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E70", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXD", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHO", - 2010 - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXD", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHE", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "day", - "RHO", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E70", - 1970 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E01", - 1960 - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXG", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHE", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E70", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E70", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "day", - "SRE", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "day", - "RL1", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHE", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXG", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXE", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXD", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E21", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXD", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "night", - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E70", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E70", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "day", - "SRE", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHO", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHO", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E70", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E70", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "day", - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E21", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E21", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHO", - 1970 - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHO", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXG", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHO", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E70", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "RL1", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "RL1", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXD", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E21", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E70", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E70", - 1970 - ], - [ - "utopia", - 2010, - "winter", - "night", - "SRE", - 2010 - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXD", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXG", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXD", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXD", - 1970 - ], - [ - "utopia", - 2010, - "summer", - "day", - "SRE", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHE", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHE", - 2010 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E70", - 1960 - ], - [ - "utopia", - 1990, - "summer", - "night", - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "day", - "RHO", - 1970 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXG", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E21", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHE", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E70", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E70", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E70", - 2010 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E70", - 1970 - ], - [ - "utopia", - 1990, - "inter", - "day", - "RL1", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "day", - "RL1", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "night", - "SRE", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "night", - "RHO", - 1970 - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXD", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXD", - 1970 - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXD", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E21", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "night", - "RHO", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E70", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHO", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E70", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E70", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "day", - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E01", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXG", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E21", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXD", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXG", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "night", - "RL1", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXD", - 2010 - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHO", - 2010 - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXD", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "night", - "RL1", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E31", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E70", - 1970 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E01", - 2010 - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXG", - 1970 - ], - [ - "utopia", - 2010, - "inter", - "day", - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXG", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHE", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E01", - 1970 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXG", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E31", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXG", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E21", - 2010 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E21", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E70", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E70", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "night", - "SRE", - 2010 - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXE", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "night", - "RHO", - 1970 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E70", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHE", - 2010 - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXG", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHO", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHO", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "night", - "RL1", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E70", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E01", - 1970 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXG", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "RL1", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E01", - 1970 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "SRE", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXD", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E01", - 1970 - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXD", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXG", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXD", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "night", - "RL1", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E70", - 1960 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXG", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXE", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E01", - 1960 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXE", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E21", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "night", - "SRE", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXE", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E01", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "RL1", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E21", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXE", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E31", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E01", - 2010 - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXG", - 1970 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXG", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXG", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E31", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E31", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXG", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "day", - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "SRE", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E01", - 1970 - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXE", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E01", - 1970 - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHE", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E70", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E70", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E21", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXG", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "RHO", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXG", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E31", - 2010 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E31", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXE", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHO", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXG", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXE", - 2010 - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXE", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E70", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXD", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHO", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXE", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXE", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E01", - 1960 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E70", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHE", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E31", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHO", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXD", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "SRE", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E70", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E70", - 1970 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E70", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "RHO", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXD", - 1970 - ], - [ - "utopia", - 2010, - "winter", - "night", - "SRE", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXD", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E31", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHE", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHO", - 2010 - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXG", - 1970 - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXD", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E70", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E70", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "RL1", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "SRE", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E70", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXD", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "night", - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHO", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E70", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHO", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E70", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E70", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E70", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E21", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXG", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXG", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHO", - 1970 - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXG", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXD", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "SRE", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E70", - 1970 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E70", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E70", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "day", - "RL1", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHO", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "RHO", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "SRE", - 2010 - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXD", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "RL1", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXD", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHO", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E21", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXD", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "SRE", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHO", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E70", - 1970 - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHO", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXG", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "night", - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E21", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E70", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E70", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHO", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "RL1", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHE", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E21", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHO", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXD", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXD", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E70", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E70", - 1970 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E31", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E70", - 2010 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E70", - 1970 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E70", - 1970 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E70", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXG", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXG", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E21", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E01", - 1960 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXG", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXD", - 1970 - ], - [ - "utopia", - 2010, - "inter", - "night", - "SRE", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXG", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXD", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHE", - 2010 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E70", - 1960 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E70", - 1970 - ], - [ - "utopia", - 1990, - "winter", - "day", - "RL1", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHO", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E01", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHO", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHO", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E70", - 2010 - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXD", - 1970 - ], - [ - "utopia", - 2010, - "inter", - "night", - "RL1", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "day", - "SRE", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "night", - "SRE", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXD", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "night", - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHO", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHO", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E70", - 1960 - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHO", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "RL1", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXG", - 1970 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E21", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E70", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E70", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E31", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E01", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXG", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E01", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E70", - 1960 - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXG", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHO", - 1970 - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXD", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E70", - 1970 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E31", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E70", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "night", - "RL1", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E70", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXE", - 2010 - ], - [ - "utopia", - 1990, - "summer", - "day", - "RL1", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E21", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E01", - 1970 - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXG", - 1970 - ], - [ - "utopia", - 2010, - "inter", - "night", - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "SRE", - 2010 - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXG", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E01", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "day", - "SRE", - 2010 - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXD", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E01", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E31", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHO", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E21", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHO", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "night", - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "night", - "RHO", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXD", - 2010 - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXD", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHO", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E01", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "RL1", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E31", - 2010 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E01", - 1970 - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXG", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXG", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E70", - 1960 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E70", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E31", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXE", - 2000 - ], - [ - "utopia", - 1990, - "summer", - "day", - "RL1", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E21", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXG", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "night", - "SRE", - 1990 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E01", - 1960 - ], - [ - "utopia", - 2010, - "inter", - "day", - "SRE", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E01", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E01", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E01", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E01", - 1970 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E31", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "RL1", - 2010 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E31", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXE", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXD", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHO", - 2010 - ], - [ - "utopia", - 1990, - "summer", - "night", - "RL1", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E01", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E31", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXE", - 2010 - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHE", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXG", - 1970 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E01", - 1970 - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXG", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E01", - 2010 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E01", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E31", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E70", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E31", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E31", - 2000 - ] - ], - "capacity_factor_rsdt": [ - [ - "utopia", - "inter", - "day", - "RL1" - ], - [ - "utopia", - "winter", - "day", - "E51" - ], - [ - "utopia", - "winter", - "night", - "E01" - ], - [ - "utopia", - "winter", - "night", - "E51" - ], - [ - "utopia", - "summer", - "day", - "TXG" - ], - [ - "utopia", - "winter", - "night", - "TXG" - ], - [ - "utopia", - "summer", - "day", - "TXD" - ], - [ - "utopia", - "winter", - "night", - "TXE" - ], - [ - "utopia", - "winter", - "night", - "TXD" - ], - [ - "utopia", - "winter", - "day", - "TXG" - ], - [ - "utopia", - "winter", - "day", - "RL1" - ], - [ - "utopia", - "summer", - "day", - "E31" - ], - [ - "utopia", - "winter", - "night", - "E31" - ], - [ - "utopia", - "summer", - "day", - "E21" - ], - [ - "utopia", - "summer", - "night", - "E70" - ], - [ - "utopia", - "winter", - "day", - "SRE" - ], - [ - "utopia", - "winter", - "night", - "E21" - ], - [ - "utopia", - "winter", - "night", - "SRE" - ], - [ - "utopia", - "summer", - "day", - "E70" - ], - [ - "utopia", - "inter", - "night", - "E70" - ], - [ - "utopia", - "winter", - "day", - "RHO" - ], - [ - "utopia", - "summer", - "night", - "E01" - ], - [ - "utopia", - "inter", - "day", - "E70" - ], - [ - "utopia", - "summer", - "day", - "E01" - ], - [ - "utopia", - "summer", - "day", - "E51" - ], - [ - "utopia", - "inter", - "night", - "RHO" - ], - [ - "utopia", - "summer", - "night", - "RHE" - ], - [ - "utopia", - "summer", - "night", - "SRE" - ], - [ - "utopia", - "summer", - "night", - "RHO" - ], - [ - "utopia", - "summer", - "day", - "RHE" - ], - [ - "utopia", - "inter", - "night", - "RHE" - ], - [ - "utopia", - "inter", - "night", - "RL1" - ], - [ - "utopia", - "summer", - "day", - "SRE" - ], - [ - "utopia", - "inter", - "night", - "E51" - ], - [ - "utopia", - "inter", - "day", - "RHE" - ], - [ - "utopia", - "summer", - "night", - "RL1" - ], - [ - "utopia", - "summer", - "night", - "TXG" - ], - [ - "utopia", - "summer", - "night", - "TXD" - ], - [ - "utopia", - "summer", - "night", - "TXE" - ], - [ - "utopia", - "summer", - "night", - "E51" - ], - [ - "utopia", - "winter", - "night", - "RHO" - ], - [ - "utopia", - "winter", - "day", - "E01" - ], - [ - "utopia", - "summer", - "night", - "E31" - ], - [ - "utopia", - "summer", - "night", - "E21" - ], - [ - "utopia", - "summer", - "day", - "TXE" - ], - [ - "utopia", - "inter", - "night", - "TXG" - ], - [ - "utopia", - "inter", - "night", - "TXD" - ], - [ - "utopia", - "winter", - "day", - "E70" - ], - [ - "utopia", - "inter", - "night", - "E31" - ], - [ - "utopia", - "inter", - "night", - "E21" - ], - [ - "utopia", - "winter", - "night", - "RL1" - ], - [ - "utopia", - "inter", - "day", - "TXG" - ], - [ - "utopia", - "inter", - "day", - "TXD" - ], - [ - "utopia", - "inter", - "day", - "E31" - ], - [ - "utopia", - "inter", - "day", - "E21" - ], - [ - "utopia", - "winter", - "day", - "RHE" - ], - [ - "utopia", - "winter", - "day", - "TXE" - ], - [ - "utopia", - "winter", - "day", - "TXD" - ], - [ - "utopia", - "inter", - "night", - "E01" - ], - [ - "utopia", - "winter", - "day", - "E31" - ], - [ - "utopia", - "winter", - "day", - "E21" - ], - [ - "utopia", - "summer", - "day", - "RHO" - ], - [ - "utopia", - "inter", - "day", - "E01" - ], - [ - "utopia", - "inter", - "day", - "E51" - ], - [ - "utopia", - "summer", - "day", - "RL1" - ], - [ - "utopia", - "winter", - "night", - "E70" - ], - [ - "utopia", - "inter", - "night", - "SRE" - ], - [ - "utopia", - "inter", - "day", - "SRE" - ], - [ - "utopia", - "inter", - "night", - "TXE" - ], - [ - "utopia", - "winter", - "night", - "RHE" - ], - [ - "utopia", - "inter", - "day", - "TXE" - ], - [ - "utopia", - "inter", - "day", - "RHO" - ] - ], - "capacity_var_rptv": [ - [ - "utopia", - 2000, - "RL1", - 2000 - ], - [ - "utopia", - 2000, - "E21", - 2000 - ], - [ - "utopia", - 2000, - "TXE", - 1990 - ], - [ - "utopia", - 1990, - "RL1", - 1980 - ], - [ - "utopia", - 1990, - "RHO", - 1990 - ], - [ - "utopia", - 1990, - "TXG", - 1980 - ], - [ - "utopia", - 2010, - "E01", - 1980 - ], - [ - "utopia", - 2010, - "E51", - 1980 - ], - [ - "utopia", - 2000, - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "TXG", - 2000 - ], - [ - "utopia", - 1990, - "E70", - 1960 - ], - [ - "utopia", - 2010, - "E21", - 1990 - ], - [ - "utopia", - 1990, - "RHE", - 1990 - ], - [ - "utopia", - 2010, - "RHE", - 2010 - ], - [ - "utopia", - 2000, - "E31", - 2000 - ], - [ - "utopia", - 2010, - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "E01", - 1980 - ], - [ - "utopia", - 2000, - "E70", - 1970 - ], - [ - "utopia", - 1990, - "E51", - 1980 - ], - [ - "utopia", - 2010, - "E01", - 2000 - ], - [ - "utopia", - 2010, - "E51", - 2000 - ], - [ - "utopia", - 2010, - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "TXD", - 2000 - ], - [ - "utopia", - 2000, - "E70", - 2000 - ], - [ - "utopia", - 2010, - "E31", - 1990 - ], - [ - "utopia", - 2000, - "SRE", - 2000 - ], - [ - "utopia", - 1990, - "TXD", - 1970 - ], - [ - "utopia", - 2010, - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "RHO", - 2000 - ], - [ - "utopia", - 2010, - "RHO", - 2010 - ], - [ - "utopia", - 1990, - "E31", - 1990 - ], - [ - "utopia", - 1990, - "RHO", - 1980 - ], - [ - "utopia", - 2010, - "E70", - 1990 - ], - [ - "utopia", - 2010, - "E31", - 2010 - ], - [ - "utopia", - 1990, - "TXG", - 1970 - ], - [ - "utopia", - 2000, - "TXG", - 1980 - ], - [ - "utopia", - 2010, - "RHE", - 2000 - ], - [ - "utopia", - 2000, - "E31", - 1990 - ], - [ - "utopia", - 2010, - "E70", - 2010 - ], - [ - "utopia", - 1990, - "E21", - 1990 - ], - [ - "utopia", - 1990, - "E70", - 1980 - ], - [ - "utopia", - 2010, - "E21", - 2010 - ], - [ - "utopia", - 1990, - "E01", - 1970 - ], - [ - "utopia", - 2000, - "E01", - 1980 - ], - [ - "utopia", - 2010, - "E01", - 1990 - ], - [ - "utopia", - 2000, - "E51", - 1980 - ], - [ - "utopia", - 2010, - "E51", - 1990 - ], - [ - "utopia", - 2000, - "TXG", - 2000 - ], - [ - "utopia", - 1990, - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "SRE", - 2010 - ], - [ - "utopia", - 2000, - "E70", - 1990 - ], - [ - "utopia", - 2010, - "E31", - 1980 - ], - [ - "utopia", - 2000, - "E21", - 1990 - ], - [ - "utopia", - 2000, - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "E01", - 2000 - ], - [ - "utopia", - 2000, - "E51", - 2000 - ], - [ - "utopia", - 1990, - "TXD", - 1990 - ], - [ - "utopia", - 2000, - "RHO", - 1990 - ], - [ - "utopia", - 2000, - "TXD", - 2000 - ], - [ - "utopia", - 2010, - "TXD", - 2010 - ], - [ - "utopia", - 1990, - "E31", - 1980 - ], - [ - "utopia", - 1990, - "RHO", - 1970 - ], - [ - "utopia", - 2010, - "E70", - 1980 - ], - [ - "utopia", - 2010, - "E31", - 2000 - ], - [ - "utopia", - 1990, - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "TXE", - 2000 - ], - [ - "utopia", - 2010, - "TXE", - 2010 - ], - [ - "utopia", - 1990, - "RL1", - 1990 - ], - [ - "utopia", - 2010, - "RL1", - 2010 - ], - [ - "utopia", - 2010, - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "E31", - 1980 - ], - [ - "utopia", - 1990, - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "E70", - 2000 - ], - [ - "utopia", - 2010, - "TXG", - 2010 - ], - [ - "utopia", - 1990, - "E70", - 1970 - ], - [ - "utopia", - 2010, - "E21", - 2000 - ], - [ - "utopia", - 1990, - "E01", - 1960 - ], - [ - "utopia", - 2000, - "E01", - 1970 - ], - [ - "utopia", - 2010, - "SRE", - 2000 - ], - [ - "utopia", - 2000, - "RHE", - 2000 - ], - [ - "utopia", - 1990, - "E01", - 1990 - ], - [ - "utopia", - 2000, - "E70", - 1980 - ], - [ - "utopia", - 1990, - "E51", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 2010 - ], - [ - "utopia", - 2010, - "E51", - 2010 - ], - [ - "utopia", - 1990, - "E70", - 1990 - ], - [ - "utopia", - 2010, - "RHO", - 2000 - ], - [ - "utopia", - 2000, - "E01", - 1990 - ], - [ - "utopia", - 2000, - "E51", - 1990 - ], - [ - "utopia", - 1990, - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "RHO", - 1980 - ], - [ - "utopia", - 2000, - "TXD", - 1990 - ] - ], - "commodity_balance_constraint_rpsdc": [ - [ - "utopia", - 2010, - "inter", - "night", - "HYD" - ], - [ - "utopia", - 1990, - "inter", - "night", - "HCO" - ], - [ - "utopia", - 2000, - "inter", - "day", - "FEQ" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "OIL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "HCO" - ], - [ - "utopia", - 1990, - "summer", - "night", - "HYD" - ], - [ - "utopia", - 1990, - "inter", - "day", - "HCO" - ], - [ - "utopia", - 1990, - "winter", - "night", - "FEQ" - ], - [ - "utopia", - 2010, - "summer", - "day", - "URN" - ], - [ - "utopia", - 2000, - "winter", - "day", - "OIL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "FEQ" - ], - [ - "utopia", - 2000, - "winter", - "night", - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "URN" - ], - [ - "utopia", - 1990, - "inter", - "day", - "URN" - ], - [ - "utopia", - 2000, - "winter", - "day", - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "OIL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "OIL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "HCO" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "URN" - ], - [ - "utopia", - 2010, - "inter", - "night", - "GSL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "HCO" - ], - [ - "utopia", - 2000, - "winter", - "night", - "FEQ" - ], - [ - "utopia", - 1990, - "summer", - "night", - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "FEQ" - ], - [ - "utopia", - 1990, - "summer", - "night", - "GSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "HYD" - ], - [ - "utopia", - 2000, - "inter", - "day", - "URN" - ], - [ - "utopia", - 1990, - "winter", - "day", - "HCO" - ], - [ - "utopia", - 1990, - "summer", - "day", - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "OIL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "FEQ" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "URN" - ], - [ - "utopia", - 1990, - "winter", - "night", - "GSL" - ], - [ - "utopia", - 1990, - "summer", - "night", - "FEQ" - ], - [ - "utopia", - 2010, - "summer", - "day", - "HCO" - ], - [ - "utopia", - 2000, - "winter", - "day", - "HCO" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "OIL" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "GSL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "HYD" - ], - [ - "utopia", - 2000, - "winter", - "night", - "URN" - ], - [ - "utopia", - 2000, - "winter", - "night", - "GSL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "HCO" - ], - [ - "utopia", - 2010, - "inter", - "day", - "HCO" - ], - [ - "utopia", - 2010, - "inter", - "night", - "URN" - ], - [ - "utopia", - 2010, - "winter", - "day", - "FEQ" - ], - [ - "utopia", - 1990, - "summer", - "night", - "OIL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "HYD" - ], - [ - "utopia", - 2000, - "summer", - "night", - "HYD" - ], - [ - "utopia", - 1990, - "summer", - "night", - "URN" - ], - [ - "utopia", - 1990, - "summer", - "day", - "OIL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "HYD" - ], - [ - "utopia", - 2010, - "winter", - "night", - "HYD" - ], - [ - "utopia", - 1990, - "winter", - "night", - "HCO" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "URN" - ], - [ - "utopia", - 1990, - "summer", - "day", - "GSL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "DSL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "HYD" - ], - [ - "utopia", - 2000, - "summer", - "day", - "OIL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "OIL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "FEQ" - ], - [ - "utopia", - 1990, - "inter", - "night", - "GSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "OIL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "HCO" - ], - [ - "utopia", - 2000, - "summer", - "night", - "DSL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "URN" - ], - [ - "utopia", - 2000, - "summer", - "night", - "GSL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "DSL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "GSL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "GSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "URN" - ], - [ - "utopia", - 1990, - "inter", - "night", - "FEQ" - ], - [ - "utopia", - 2010, - "summer", - "night", - "HYD" - ], - [ - "utopia", - 2000, - "summer", - "night", - "FEQ" - ], - [ - "utopia", - 2000, - "inter", - "night", - "DSL" - ], - [ - "utopia", - 1990, - "summer", - "night", - "HCO" - ], - [ - "utopia", - 2000, - "inter", - "night", - "GSL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "FEQ" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "FEQ" - ], - [ - "utopia", - 2010, - "summer", - "day", - "HYD" - ], - [ - "utopia", - 1990, - "summer", - "day", - "HCO" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "HYD" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "DSL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "FEQ" - ], - [ - "utopia", - 2010, - "summer", - "night", - "OIL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "HYD" - ], - [ - "utopia", - 2010, - "summer", - "night", - "URN" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "OIL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "HCO" - ], - [ - "utopia", - 2010, - "winter", - "night", - "HCO" - ], - [ - "utopia", - 2000, - "summer", - "night", - "OIL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "HCO" - ], - [ - "utopia", - 2010, - "summer", - "day", - "DSL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "URN" - ], - [ - "utopia", - 1990, - "inter", - "day", - "OIL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "GSL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "HYD" - ], - [ - "utopia", - 2000, - "summer", - "night", - "URN" - ], - [ - "utopia", - 2000, - "winter", - "day", - "DSL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "URN" - ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL" - ], - [ - "utopia", - 1990, - "winter", - "night", - "HYD" - ], - [ - "utopia", - 1990, - "inter", - "day", - "GSL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "FEQ" - ], - [ - "utopia", - 1990, - "winter", - "day", - "HYD" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "OIL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "FEQ" - ], - [ - "utopia", - 2010, - "inter", - "day", - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "GSL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "URN" - ], - [ - "utopia", - 2000, - "inter", - "day", - "OIL" - ], - [ - "utopia", - 1990, - "inter", - "day", - "FEQ" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "HYD" - ], - [ - "utopia", - 2000, - "inter", - "day", - "GSL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "OIL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "HYD" - ], - [ - "utopia", - 2010, - "inter", - "day", - "FEQ" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "DSL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "URN" - ], - [ - "utopia", - 2010, - "summer", - "night", - "HCO" - ], - [ - "utopia", - 1990, - "winter", - "day", - "GSL" - ] - ], - "cost_emission_rpe": [], - "cost_fixed_rptv": [ - [ - "utopia", - 2000, - "RL1", - 2000 - ], - [ - "utopia", - 2000, - "E21", - 2000 - ], - [ - "utopia", - 2000, - "TXE", - 1990 - ], - [ - "utopia", - 1990, - "RL1", - 1980 - ], - [ - "utopia", - 1990, - "RHO", - 1990 - ], - [ - "utopia", - 1990, - "TXG", - 1980 - ], - [ - "utopia", - 2010, - "E01", - 1980 - ], - [ - "utopia", - 2010, - "E51", - 1980 - ], - [ - "utopia", - 2000, - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "TXG", - 2000 - ], - [ - "utopia", - 1990, - "E70", - 1960 - ], - [ - "utopia", - 2010, - "E21", - 1990 - ], - [ - "utopia", - 1990, - "RHE", - 1990 - ], - [ - "utopia", - 2010, - "RHE", - 2010 - ], - [ - "utopia", - 2000, - "E31", - 2000 - ], - [ - "utopia", - 2010, - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "E01", - 1980 - ], - [ - "utopia", - 2000, - "E70", - 1970 - ], - [ - "utopia", - 1990, - "E51", - 1980 - ], - [ - "utopia", - 2010, - "E01", - 2000 - ], - [ - "utopia", - 2010, - "E51", - 2000 - ], - [ - "utopia", - 2010, - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "TXD", - 2000 - ], - [ - "utopia", - 2000, - "E70", - 2000 - ], - [ - "utopia", - 2010, - "E31", - 1990 - ], - [ - "utopia", - 2000, - "SRE", - 2000 - ], - [ - "utopia", - 1990, - "TXD", - 1970 - ], - [ - "utopia", - 2010, - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "RHO", - 2000 - ], - [ - "utopia", - 2010, - "RHO", - 2010 - ], - [ - "utopia", - 1990, - "E31", - 1990 - ], - [ - "utopia", - 1990, - "RHO", - 1980 - ], - [ - "utopia", - 2010, - "E70", - 1990 - ], - [ - "utopia", - 2010, - "E31", - 2010 - ], - [ - "utopia", - 1990, - "TXG", - 1970 - ], - [ - "utopia", - 2000, - "TXG", - 1980 - ], - [ - "utopia", - 2010, - "RHE", - 2000 - ], - [ - "utopia", - 2000, - "E31", - 1990 - ], - [ - "utopia", - 2010, - "E70", - 2010 - ], - [ - "utopia", - 1990, - "E21", - 1990 - ], - [ - "utopia", - 1990, - "E70", - 1980 - ], - [ - "utopia", - 2010, - "E21", - 2010 - ], - [ - "utopia", - 1990, - "E01", - 1970 - ], - [ - "utopia", - 2000, - "E01", - 1980 - ], - [ - "utopia", - 2010, - "E01", - 1990 - ], - [ - "utopia", - 2000, - "E51", - 1980 - ], - [ - "utopia", - 2010, - "E51", - 1990 - ], - [ - "utopia", - 2000, - "TXG", - 2000 - ], - [ - "utopia", - 1990, - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "SRE", - 2010 - ], - [ - "utopia", - 2000, - "E70", - 1990 - ], - [ - "utopia", - 2010, - "E31", - 1980 - ], - [ - "utopia", - 2000, - "E21", - 1990 - ], - [ - "utopia", - 2000, - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "E01", - 2000 - ], - [ - "utopia", - 2000, - "E51", - 2000 - ], - [ - "utopia", - 1990, - "TXD", - 1990 - ], - [ - "utopia", - 2000, - "RHO", - 1990 - ], - [ - "utopia", - 2000, - "TXD", - 2000 - ], - [ - "utopia", - 2010, - "TXD", - 2010 - ], - [ - "utopia", - 1990, - "E31", - 1980 - ], - [ - "utopia", - 1990, - "RHO", - 1970 - ], - [ - "utopia", - 2010, - "E70", - 1980 - ], - [ - "utopia", - 2010, - "E31", - 2000 - ], - [ - "utopia", - 1990, - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "TXE", - 2000 - ], - [ - "utopia", - 2010, - "TXE", - 2010 - ], - [ - "utopia", - 1990, - "RL1", - 1990 - ], - [ - "utopia", - 2010, - "RL1", - 2010 - ], - [ - "utopia", - 2010, - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "E31", - 1980 - ], - [ - "utopia", - 1990, - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "E70", - 2000 - ], - [ - "utopia", - 2010, - "TXG", - 2010 - ], - [ - "utopia", - 1990, - "E70", - 1970 - ], - [ - "utopia", - 2010, - "E21", - 2000 - ], - [ - "utopia", - 1990, - "E01", - 1960 - ], - [ - "utopia", - 2000, - "E01", - 1970 - ], - [ - "utopia", - 2010, - "SRE", - 2000 - ], - [ - "utopia", - 2000, - "RHE", - 2000 - ], - [ - "utopia", - 1990, - "E01", - 1990 - ], - [ - "utopia", - 2000, - "E70", - 1980 - ], - [ - "utopia", - 1990, - "E51", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 2010 - ], - [ - "utopia", - 2010, - "E51", - 2010 - ], - [ - "utopia", - 1990, - "E70", - 1990 - ], - [ - "utopia", - 2010, - "RHO", - 2000 - ], - [ - "utopia", - 2000, - "E01", - 1990 - ], - [ - "utopia", - 2000, - "E51", - 1990 - ], - [ - "utopia", - 1990, - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "RHO", - 1980 - ], - [ - "utopia", - 2000, - "TXD", - 1990 - ] - ], - "cost_invest_rtv": [ - [ - "utopia", - "TXD", - 1990 - ], - [ - "utopia", - "RHO", - 2010 - ], - [ - "utopia", - "E21", - 2000 - ], - [ - "utopia", - "TXE", - 1990 - ], - [ - "utopia", - "E51", - 2010 - ], - [ - "utopia", - "E70", - 1990 - ], - [ - "utopia", - "SRE", - 2000 - ], - [ - "utopia", - "TXG", - 2000 - ], - [ - "utopia", - "E31", - 2010 - ], - [ - "utopia", - "RHO", - 2000 - ], - [ - "utopia", - "E21", - 1990 - ], - [ - "utopia", - "E01", - 2010 - ], - [ - "utopia", - "RHE", - 2010 - ], - [ - "utopia", - "TXD", - 2010 - ], - [ - "utopia", - "E51", - 2000 - ], - [ - "utopia", - "SRE", - 1990 - ], - [ - "utopia", - "TXG", - 1990 - ], - [ - "utopia", - "E31", - 2000 - ], - [ - "utopia", - "RHO", - 1990 - ], - [ - "utopia", - "TXE", - 2010 - ], - [ - "utopia", - "RHE", - 2000 - ], - [ - "utopia", - "E01", - 2000 - ], - [ - "utopia", - "E70", - 2010 - ], - [ - "utopia", - "E21", - 2010 - ], - [ - "utopia", - "TXD", - 2000 - ], - [ - "utopia", - "E51", - 1990 - ], - [ - "utopia", - "E31", - 1990 - ], - [ - "utopia", - "TXE", - 2000 - ], - [ - "utopia", - "RHE", - 1990 - ], - [ - "utopia", - "E01", - 1990 - ], - [ - "utopia", - "SRE", - 2010 - ], - [ - "utopia", - "TXG", - 2010 - ], - [ - "utopia", - "E70", - 2000 - ] - ], - "cost_variable_rptv": [ - [ - "utopia", - 2000, - "RL1", - 2000 - ], - [ - "utopia", - 2000, - "E21", - 2000 - ], - [ - "utopia", - 2000, - "TXE", - 1990 - ], - [ - "utopia", - 1990, - "RL1", - 1980 - ], - [ - "utopia", - 1990, - "RHO", - 1990 - ], - [ - "utopia", - 2000, - "IMPDSL1", - 1990 - ], - [ - "utopia", - 2010, - "IMPURN1", - 1990 - ], - [ - "utopia", - 1990, - "TXG", - 1980 - ], - [ - "utopia", - 2010, - "E01", - 1980 - ], - [ - "utopia", - 2010, - "E51", - 1980 - ], - [ - "utopia", - 2000, - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "TXG", - 2000 - ], - [ - "utopia", - 1990, - "E70", - 1960 - ], - [ - "utopia", - 2010, - "E21", - 1990 - ], - [ - "utopia", - 1990, - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "IMPHCO1", - 1990 - ], - [ - "utopia", - 2010, - "RHE", - 2010 - ], - [ - "utopia", - 2000, - "E31", - 2000 - ], - [ - "utopia", - 2010, - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "E01", - 1980 - ], - [ - "utopia", - 2000, - "E70", - 1970 - ], - [ - "utopia", - 1990, - "E51", - 1980 - ], - [ - "utopia", - 2010, - "E01", - 2000 - ], - [ - "utopia", - 2010, - "E51", - 2000 - ], - [ - "utopia", - 2010, - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "TXD", - 2000 - ], - [ - "utopia", - 2000, - "E70", - 2000 - ], - [ - "utopia", - 2000, - "IMPHYD", - 1990 - ], - [ - "utopia", - 2010, - "E31", - 1990 - ], - [ - "utopia", - 2000, - "SRE", - 2000 - ], - [ - "utopia", - 1990, - "TXD", - 1970 - ], - [ - "utopia", - 2010, - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "TXD", - 1980 - ], - [ - "utopia", - 1990, - "IMPFEQ", - 1990 - ], - [ - "utopia", - 2000, - "IMPOIL1", - 1990 - ], - [ - "utopia", - 2010, - "IMPGSL1", - 1990 - ], - [ - "utopia", - 2000, - "RHO", - 2000 - ], - [ - "utopia", - 2010, - "RHO", - 2010 - ], - [ - "utopia", - 1990, - "E31", - 1990 - ], - [ - "utopia", - 1990, - "RHO", - 1980 - ], - [ - "utopia", - 2010, - "E70", - 1990 - ], - [ - "utopia", - 2010, - "E31", - 2010 - ], - [ - "utopia", - 1990, - "IMPGSL1", - 1990 - ], - [ - "utopia", - 1990, - "TXG", - 1970 - ], - [ - "utopia", - 2000, - "TXG", - 1980 - ], - [ - "utopia", - 1990, - "IMPDSL1", - 1990 - ], - [ - "utopia", - 2010, - "RHE", - 2000 - ], - [ - "utopia", - 2000, - "E31", - 1990 - ], - [ - "utopia", - 2010, - "E70", - 2010 - ], - [ - "utopia", - 2000, - "IMPURN1", - 1990 - ], - [ - "utopia", - 1990, - "E21", - 1990 - ], - [ - "utopia", - 2010, - "IMPFEQ", - 1990 - ], - [ - "utopia", - 1990, - "E70", - 1980 - ], - [ - "utopia", - 2010, - "E21", - 2010 - ], - [ - "utopia", - 1990, - "E01", - 1970 - ], - [ - "utopia", - 2000, - "E01", - 1980 - ], - [ - "utopia", - 2010, - "E01", - 1990 - ], - [ - "utopia", - 2000, - "E51", - 1980 - ], - [ - "utopia", - 2010, - "E51", - 1990 - ], - [ - "utopia", - 2000, - "TXG", - 2000 - ], - [ - "utopia", - 1990, - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "SRE", - 2010 - ], - [ - "utopia", - 2000, - "E70", - 1990 - ], - [ - "utopia", - 2010, - "E31", - 1980 - ], - [ - "utopia", - 2000, - "E21", - 1990 - ], - [ - "utopia", - 2000, - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "IMPOIL1", - 1990 - ], - [ - "utopia", - 2000, - "E01", - 2000 - ], - [ - "utopia", - 2010, - "IMPDSL1", - 1990 - ], - [ - "utopia", - 2000, - "E51", - 2000 - ], - [ - "utopia", - 1990, - "TXD", - 1990 - ], - [ - "utopia", - 2000, - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "IMPHCO1", - 1990 - ], - [ - "utopia", - 2000, - "TXD", - 2000 - ], - [ - "utopia", - 2010, - "TXD", - 2010 - ], - [ - "utopia", - 1990, - "E31", - 1980 - ], - [ - "utopia", - 1990, - "RHO", - 1970 - ], - [ - "utopia", - 2010, - "E70", - 1980 - ], - [ - "utopia", - 2010, - "E31", - 2000 - ], - [ - "utopia", - 1990, - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "TXE", - 2000 - ], - [ - "utopia", - 2010, - "TXE", - 2010 - ], - [ - "utopia", - 1990, - "IMPOIL1", - 1990 - ], - [ - "utopia", - 1990, - "RL1", - 1990 - ], - [ - "utopia", - 2010, - "RL1", - 2010 - ], - [ - "utopia", - 2000, - "IMPGSL1", - 1990 - ], - [ - "utopia", - 1990, - "IMPHCO1", - 1990 - ], - [ - "utopia", - 2010, - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "E70", - 2000 - ], - [ - "utopia", - 2000, - "E31", - 1980 - ], - [ - "utopia", - 2010, - "TXG", - 2010 - ], - [ - "utopia", - 1990, - "E70", - 1970 - ], - [ - "utopia", - 2010, - "E21", - 2000 - ], - [ - "utopia", - 1990, - "E01", - 1960 - ], - [ - "utopia", - 2000, - "E01", - 1970 - ], - [ - "utopia", - 2010, - "IMPHYD", - 1990 - ], - [ - "utopia", - 2010, - "SRE", - 2000 - ], - [ - "utopia", - 1990, - "IMPURN1", - 1990 - ], - [ - "utopia", - 2000, - "RHE", - 2000 - ], - [ - "utopia", - 1990, - "E01", - 1990 - ], - [ - "utopia", - 2000, - "E70", - 1980 - ], - [ - "utopia", - 1990, - "E51", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 2010 - ], - [ - "utopia", - 2010, - "E51", - 2010 - ], - [ - "utopia", - 1990, - "E70", - 1990 - ], - [ - "utopia", - 2010, - "RHO", - 2000 - ], - [ - "utopia", - 1990, - "IMPHYD", - 1990 - ], - [ - "utopia", - 2000, - "E01", - 1990 - ], - [ - "utopia", - 2000, - "E51", - 1990 - ], - [ - "utopia", - 2000, - "IMPFEQ", - 1990 - ], - [ - "utopia", - 1990, - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "RHO", - 1980 - ], - [ - "utopia", - 2000, - "TXD", - 1990 - ] - ], - "curtailment_var_rpsditvo": [], - "demand_constraint_rpc": [ - [ - "utopia", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "RH" - ], - [ - "utopia", - 2010, - "RL" - ], - [ - "utopia", - 1990, - "RL" - ], - [ - "utopia", - 2010, - "TX" - ], - [ - "utopia", - 2010, - "RH" - ], - [ - "utopia", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "RL" - ], - [ - "utopia", - 1990, - "RH" - ] - ], - "demand_activity_constraint_rpsdtv_dem": [ - [ - "utopia", - 2000, - "summer", - "night", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "day", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "day", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "day", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "day", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "day", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "day", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "day", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "day", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2010, - "inter", - "night", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "night", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "day", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "night", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - 2010, - "inter", - "day", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "night", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "day", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "day", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "night", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "day", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "day", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "night", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "night", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "day", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "inter", - "night", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "night", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "day", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "night", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "day", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "day", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "night", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "night", - "RHE", - 2000, - "RH" - ] - ], - "emission_activity_reitvo": [ - [ - "utopia", - "co2", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - "co2", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - "co2", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - "nox", - "HCO", - "E01", - 1960, - "ELC" - ], - [ - "utopia", - "co2", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - "nox", - "ELC", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - "co2", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - "co2", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - "nox", - "ELC", - "RL1", - 2010, - "RL" - ], - [ - "utopia", - "co2", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - "nox", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - "nox", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - "co2", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - "co2", - "OIL", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - "co2", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - "nox", - "URN", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - "co2", - "OIL", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - "co2", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - "co2", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - "nox", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - "nox", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - "co2", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - "nox", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - "co2", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - "co2", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - "nox", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - "nox", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - "co2", - "ELC", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - "nox", - "OIL", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - "nox", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - "nox", - "OIL", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - "nox", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - "co2", - "DSL", - "E70", - 2010, - "ELC" - ], - [ - "utopia", - "co2", - "GSL", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - "nox", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - "co2", - "ELC", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - "nox", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - "nox", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - "nox", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - "co2", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - "nox", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - "nox", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - "co2", - "ELC", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - "nox", - "HYD", - "E31", - 2010, - "ELC" - ], - [ - "utopia", - "co2", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - "nox", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - "nox", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - "nox", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - "co2", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - "nox", - "ELC", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - "nox", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - "nox", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - "co2", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - "nox", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - "nox", - "DSL", - "E70", - 2010, - "ELC" - ], - [ - "utopia", - "co2", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - "nox", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - "nox", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - "nox", - "ELC", - "RL1", - 2000, - "RL" - ], - [ - "utopia", - "co2", - "HCO", - "E01", - 1960, - "ELC" - ], - [ - "utopia", - "co2", - "ELC", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - "co2", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - "nox", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - "co2", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - "nox", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - "co2", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - "nox", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - "co2", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - "co2", - "DSL", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - "co2", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - "nox", - "HCO", - "E01", - 2010, - "ELC" - ], - [ - "utopia", - "co2", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - "co2", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - "co2", - "ELC", - "RL1", - 2010, - "RL" - ], - [ - "utopia", - "nox", - "DSL", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - "nox", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - "co2", - "URN", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - "nox", - "ELC", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - "nox", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - "co2", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - "co2", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - "co2", - "DSL", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - "co2", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - "co2", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - "nox", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - "co2", - "DSL", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - "co2", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - "co2", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - "co2", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - "nox", - "DSL", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - "nox", - "FEQ", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - "co2", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - "nox", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - "co2", - "DSL", - "E70", - 1960, - "ELC" - ], - [ - "utopia", - "co2", - "GSL", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - "co2", - "ELC", - "RL1", - 2000, - "RL" - ], - [ - "utopia", - "nox", - "GSL", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - "co2", - "DSL", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - "nox", - "GSL", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - "nox", - "ELC", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - "nox", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - "co2", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - "co2", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - "co2", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - "nox", - "DSL", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - "co2", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - "nox", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - "nox", - "DSL", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - "co2", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - "nox", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - "nox", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - "nox", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - "nox", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - "co2", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - "co2", - "HCO", - "E01", - 2010, - "ELC" - ], - [ - "utopia", - "nox", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - "nox", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - "nox", - "DSL", - "E70", - 1960, - "ELC" - ], - [ - "utopia", - "nox", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - "co2", - "HYD", - "E31", - 2010, - "ELC" - ], - [ - "utopia", - "nox", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - "co2", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - "co2", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - "nox", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - "nox", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - "co2", - "FEQ", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - "co2", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - "nox", - "DSL", - "E70", - 1990, - "ELC" - ] - ], - "flex_var_annual_rpitvo": [], - "flex_var_rpsditvo": [], - "flow_in_storage_rpsditvo": [ - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ] - ], - "flow_var_annual_rpitvo": [ - [ - "utopia", - 2000, - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "GSL", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - 2000, - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "ELC", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - 2010, - "ELC", - "RL1", - 2010, - "RL" - ], - [ - "utopia", - 2000, - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2010, - "DSL", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - 2000, - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "ELC", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - 1990, - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2000, - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "DSL", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - 1990, - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "ELC", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - 2000, - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "ELC", - "RL1", - 2000, - "RL" - ], - [ - "utopia", - 2000, - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "ELC", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - 1990, - "DSL", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - 1990, - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 2010, - "GSL", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - 2000, - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "DSL", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - 2010, - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "ELC", - "TXE", - 2000, - "TX" - ] - ], - "flow_var_rpsditvo": [ - [ - "utopia", - 1990, - "winter", - "day", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2010, - "summer", - "day", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2010, - "summer", - "night", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2000, - "winter", - "day", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2010, - "summer", - "night", - "OIL", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL", - "E70", - 1960, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "HYD", - "E31", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 1990, - "winter", - "night", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "DSL", - "E70", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "OIL", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "FEQ", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2010, - "winter", - "day", - "OIL", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 1990, - "winter", - "night", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2010, - "inter", - "night", - "HCO", - "E01", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 1990, - "winter", - "night", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "OIL", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "HCO", - "E01", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2010, - "winter", - "night", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "OIL", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "OIL", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - 1990, - "inter", - "day", - "HCO", - "E01", - 1960, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2000, - "inter", - "night", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 1990, - "inter", - "day", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2000, - "summer", - "night", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "FEQ", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "URN", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "DSL", - "E70", - 1960, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2010, - "summer", - "night", - "FEQ", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "URN", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "DSL", - "E70", - 1960, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "HCO", - "E01", - 1960, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "OIL", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "FEQ", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 1990, - "winter", - "day", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "HCO", - "E01", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "HCO", - "E01", - 1960, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "URN", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "HCO", - "E01", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "HCO", - "E01", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "DSL", - "E70", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL", - "E70", - 1960, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "OIL", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "DSL", - "E70", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "HYD", - "E31", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "FEQ", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "HYD", - "E31", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2000, - "inter", - "night", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2000, - "winter", - "day", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2000, - "winter", - "night", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2000, - "winter", - "night", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2010, - "winter", - "day", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "HCO", - "E01", - 1960, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2000, - "summer", - "night", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2010, - "winter", - "day", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 1990, - "winter", - "day", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "HYD", - "E31", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2010, - "winter", - "night", - "HCO", - "E01", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "DSL", - "E70", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "URN", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "HCO", - "E01", - 1960, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 1990, - "summer", - "night", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2000, - "summer", - "night", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2010, - "winter", - "night", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "HYD", - "E31", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2010, - "summer", - "night", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "OIL", - "SRE", - 2000, - "DSL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "winter", - "night", - "DSL", - "E70", - 1960, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "winter", - "night", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2000, - "summer", - "night", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2010, - "winter", - "day", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "night", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "FEQ", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "winter", - "day", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2010, - "summer", - "night", - "DSL", - "E70", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2010, - "summer", - "day", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "OIL", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "OIL", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "DSL", - "E70", - 1960, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2010, - "inter", - "day", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "winter", - "night", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "OIL", - "SRE", - 2010, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "URN", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "HCO", - "E01", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "OIL", - "SRE", - 2010, - "GSL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2000, - "inter", - "night", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2000, - "inter", - "day", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 1990, - "summer", - "night", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "E51", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ethos", - "IMPHCO1", - 1990, - "HCO" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ethos", - "IMPFEQ", - 1990, - "FEQ" - ], - [ - "utopia", - 2000, - "winter", - "day", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "OIL", - "SRE", - 2000, - "GSL" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ethos", - "IMPHYD", - 1990, - "HYD" - ], - [ - "utopia", - 2010, - "winter", - "day", - "FEQ", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "DSL", - "E70", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "URN", - "E21", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "DSL", - "E70", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ethos", - "IMPURN1", - 1990, - "URN" - ], - [ - "utopia", - 2010, - "winter", - "day", - "HYD", - "E31", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ethos", - "IMPDSL1", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "HYD", - "E31", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "day", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "night", - "HCO", - "E01", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "FEQ", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "winter", - "day", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "E51", - 2010, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "day", - "URN", - "E21", - 2000, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2000, - "winter", - "night", - "DSL", - "E70", - 1970, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 1990, - "summer", - "night", - "HCO", - "E01", - 1960, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ethos", - "IMPGSL1", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "summer", - "day", - "HCO", - "E01", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "winter", - "day", - "HYD", - "E31", - 2010, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "E51", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "night", - "OIL", - "SRE", - 1990, - "GSL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "night", - "URN", - "E21", - 1990, - "ELC" - ], - [ - "utopia", - 1990, - "inter", - "night", - "HCO", - "E01", - 1970, - "ELC" - ], - [ - "utopia", - 2000, - "summer", - "day", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "day", - "OIL", - "SRE", - 1990, - "DSL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ethos", - "IMPOIL1", - 1990, - "OIL" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "E51", - 2000, - "ELC" - ], - [ - "utopia", - 2000, - "inter", - "day", - "HYD", - "E31", - 1990, - "ELC" - ], - [ - "utopia", - 2010, - "inter", - "day", - "DSL", - "E70", - 1980, - "ELC" - ], - [ - "utopia", - 2000, - "winter", - "night", - "DSL", - "E70", - 2000, - "ELC" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "night", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "day", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "day", - "DSL", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "RL1", - 2010, - "RL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ELC", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "day", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "RL1", - 2010, - "RL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "DSL", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "day", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "night", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "day", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "night", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ELC", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "RL1", - 2010, - "RL" - ], - [ - "utopia", - 2000, - "summer", - "night", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "day", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "day", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "day", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "day", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "night", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "DSL", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "day", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ELC", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - 1990, - "summer", - "night", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "night", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "night", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "day", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "inter", - "night", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "RL1", - 2000, - "RL" - ], - [ - "utopia", - 2010, - "winter", - "night", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "night", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "RL1", - 2000, - "RL" - ], - [ - "utopia", - 1990, - "winter", - "night", - "DSL", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "DSL", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "RL1", - 2010, - "RL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "DSL", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "night", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "night", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "night", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "day", - "DSL", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "night", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ELC", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "day", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "night", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "night", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "GSL", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "night", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ELC", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - 1990, - "winter", - "day", - "GSL", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "DSL", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "night", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ELC", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "night", - "GSL", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "GSL", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "day", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "day", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "GSL", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "day", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "RL1", - 2000, - "RL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "night", - "GSL", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "night", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "day", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "day", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "night", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "day", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ELC", - "RL1", - 1990, - "RL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "night", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "night", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "DSL", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "day", - "GSL", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "day", - "GSL", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "DSL", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "day", - "GSL", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "GSL", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "night", - "DSL", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "day", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ELC", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - 2010, - "summer", - "day", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "night", - "DSL", - "RHO", - 1980, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "night", - "ELC", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "day", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "day", - "DSL", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "night", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "night", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "night", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "RL1", - 2000, - "RL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "inter", - "day", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "night", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "day", - "ELC", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - 1990, - "winter", - "night", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ELC", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - 2000, - "inter", - "night", - "ELC", - "RL1", - 2000, - "RL" - ], - [ - "utopia", - 2010, - "inter", - "night", - "DSL", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "night", - "DSL", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "DSL", - "TXD", - 2010, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "RL1", - 2000, - "RL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "night", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "day", - "DSL", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "day", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "night", - "GSL", - "TXG", - 1970, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "day", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "day", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "night", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "day", - "ELC", - "RL1", - 2010, - "RL" - ], - [ - "utopia", - 2010, - "inter", - "day", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "day", - "GSL", - "TXG", - 1990, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "night", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "night", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 2010, - "inter", - "night", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "day", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "night", - "ELC", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "day", - "ELC", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - 2000, - "summer", - "day", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "summer", - "day", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "TXE", - 2000, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "TXE", - 2010, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "day", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "night", - "DSL", - "RHO", - 2000, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "day", - "DSL", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "DSL", - "TXD", - 1990, - "TX" - ], - [ - "utopia", - 2010, - "summer", - "night", - "DSL", - "RHO", - 2010, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "day", - "DSL", - "TXD", - 1980, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "night", - "DSL", - "TXD", - 2000, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "ELC", - "RHE", - 2010, - "RH" - ], - [ - "utopia", - 1990, - "winter", - "night", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "winter", - "night", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 2000, - "summer", - "day", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "inter", - "day", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 1990, - "inter", - "day", - "GSL", - "TXG", - 1980, - "TX" - ], - [ - "utopia", - 2010, - "inter", - "night", - "GSL", - "TXG", - 2010, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "day", - "ELC", - "RHE", - 2000, - "RH" - ], - [ - "utopia", - 2010, - "summer", - "day", - "GSL", - "TXG", - 2000, - "TX" - ], - [ - "utopia", - 2000, - "winter", - "night", - "ELC", - "TXE", - 1990, - "TX" - ], - [ - "utopia", - 1990, - "summer", - "day", - "ELC", - "RHE", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "summer", - "night", - "DSL", - "RHO", - 1970, - "RH" - ], - [ - "utopia", - 2000, - "inter", - "day", - "DSL", - "RHO", - 1990, - "RH" - ], - [ - "utopia", - 1990, - "inter", - "night", - "ELC", - "RL1", - 1980, - "RL" - ], - [ - "utopia", - 1990, - "summer", - "night", - "DSL", - "TXD", - 1970, - "TX" - ], - [ - "utopia", - 2010, - "winter", - "day", - "ELC", - "RL1", - 2010, - "RL" - ], - [ - "utopia", - 1990, - "inter", - "night", - "DSL", - "RHO", - 1990, - "RH" - ] - ], - "lifetime_process_rtv": [ - [ - "utopia", - "IMPURN1", - 1990 - ], - [ - "utopia", - "TXD", - 1990 - ], - [ - "utopia", - "RHO", - 2010 - ], - [ - "utopia", - "E21", - 2000 - ], - [ - "utopia", - "TXG", - 1970 - ], - [ - "utopia", - "E51", - 1980 - ], - [ - "utopia", - "E70", - 1960 - ], - [ - "utopia", - "E31", - 1980 - ], - [ - "utopia", - "IMPGSL1", - 1990 - ], - [ - "utopia", - "RHO", - 1970 - ], - [ - "utopia", - "IMPDSL1", - 1990 - ], - [ - "utopia", - "TXE", - 1990 - ], - [ - "utopia", - "E01", - 1980 - ], - [ - "utopia", - "IMPHYD", - 1990 - ], - [ - "utopia", - "IMPOIL1", - 1990 - ], - [ - "utopia", - "E51", - 2010 - ], - [ - "utopia", - "E70", - 1990 - ], - [ - "utopia", - "RL1", - 1990 - ], - [ - "utopia", - "TXD", - 1980 - ], - [ - "utopia", - "TXG", - 2000 - ], - [ - "utopia", - "SRE", - 2000 - ], - [ - "utopia", - "E31", - 2010 - ], - [ - "utopia", - "RHO", - 2000 - ], - [ - "utopia", - "RHE", - 2010 - ], - [ - "utopia", - "E21", - 1990 - ], - [ - "utopia", - "E01", - 2010 - ], - [ - "utopia", - "E01", - 1970 - ], - [ - "utopia", - "IMPHCO1", - 1990 - ], - [ - "utopia", - "TXD", - 2010 - ], - [ - "utopia", - "E51", - 2000 - ], - [ - "utopia", - "E70", - 1980 - ], - [ - "utopia", - "SRE", - 1990 - ], - [ - "utopia", - "TXG", - 1990 - ], - [ - "utopia", - "RL1", - 1980 - ], - [ - "utopia", - "E31", - 2000 - ], - [ - "utopia", - "RHO", - 1990 - ], - [ - "utopia", - "TXD", - 1970 - ], - [ - "utopia", - "TXE", - 2010 - ], - [ - "utopia", - "RHE", - 2000 - ], - [ - "utopia", - "E01", - 2000 - ], - [ - "utopia", - "E70", - 2010 - ], - [ - "utopia", - "RL1", - 2010 - ], - [ - "utopia", - "E01", - 1960 - ], - [ - "utopia", - "TXD", - 2000 - ], - [ - "utopia", - "E21", - 2010 - ], - [ - "utopia", - "E70", - 1970 - ], - [ - "utopia", - "IMPFEQ", - 1990 - ], - [ - "utopia", - "TXG", - 1980 - ], - [ - "utopia", - "E51", - 1990 - ], - [ - "utopia", - "E31", - 1990 - ], - [ - "utopia", - "RHO", - 1980 - ], - [ - "utopia", - "TXE", - 2000 - ], - [ - "utopia", - "RHE", - 1990 - ], - [ - "utopia", - "E01", - 1990 - ], - [ - "utopia", - "SRE", - 2010 - ], - [ - "utopia", - "TXG", - 2010 - ], - [ - "utopia", - "E70", - 2000 - ], - [ - "utopia", - "RL1", - 2000 - ] - ], - "limit_activity_constraint_rpt": [], - "limit_activity_share_constraint_rpgg": [], - "limit_annual_capacity_factor_constraint_rptvo": [], - "limit_annual_capacity_factor_constraint_rtvo": [], - "limit_capacity_constraint_rpt": [ - [ - "utopia", - 1990, - "TXD", - "le" - ], - [ - "utopia", - 2000, - "E31", - "le" - ], - [ - "utopia", - 1990, - "E31", - "ge" - ], - [ - "utopia", - 2000, - "TXD", - "le" - ], - [ - "utopia", - 1990, - "E31", - "le" - ], - [ - "utopia", - 1990, - "RHE", - "le" - ], - [ - "utopia", - 2010, - "TXD", - "le" - ], - [ - "utopia", - 2010, - "E31", - "le" - ], - [ - "utopia", - 2010, - "E31", - "ge" - ], - [ - "utopia", - 2000, - "E31", - "ge" - ], - [ - "utopia", - 1990, - "SRE", - "ge" - ] - ], - "limit_capacity_share_constraint_rpgg": [], - "limit_degrowth_capacity_constraint_rpt": [], - "limit_degrowth_new_capacity_constraint_rpt": [], - "limit_degrowth_new_capacity_delta_constraint_rpt": [], - "limit_emission_constraint_rpe": [], - "limit_growth_capacity_constraint_rpt": [], - "limit_growth_new_capacity_constraint_rpt": [], - "limit_growth_new_capacity_delta_constraint_rpt": [], - "limit_new_capacity_constraint_rtv": [], - "limit_new_capacity_share_constraint_rggv": [], - "limit_resource_constraint_rt": [], - "limit_seasonal_capacity_factor_constraint_rpst": [], - "limit_seasonal_capacity_factor_constraint_rst": [], - "limit_storage_fraction_constraint_rpsdtv": [], - "limit_storage_fraction_param_rsdt": [], - "limit_tech_input_split_annual_constraint_rpitv": [], - "limit_tech_input_split_average_constraint_rpitv": [], - "limit_tech_input_split_constraint_rpsditv": [], - "limit_tech_output_split_annual_constraint_rptvo": [], - "limit_tech_output_split_average_constraint_rptvo": [], - "limit_tech_output_split_constraint_rpsdtvo": [ - [ - "utopia", - 2010, - "summer", - "night", - "SRE", - 1990, - "GSL", - "ge" - ], - [ - "utopia", - 2010, - "winter", - "night", - "SRE", - 1990, - "DSL", - "ge" - ], - [ - "utopia", - 2010, - "summer", - "night", - "SRE", - 2000, - "GSL", - "ge" - ], - [ - "utopia", - 2010, - "winter", - "night", - "SRE", - 2010, - "DSL", - "ge" - ], - [ - "utopia", - 2000, - "summer", - "day", - "SRE", - 1990, - "DSL", - "ge" - ], - [ - "utopia", - 2000, - "inter", - "night", - "SRE", - 2000, - "DSL", - "ge" - ], - [ - "utopia", - 2000, - "winter", - "night", - "SRE", - 2000, - "DSL", - "ge" - ], - [ - "utopia", - 2000, - "summer", - "night", - "SRE", - 1990, - "GSL", - "ge" - ], - [ - "utopia", - 2010, - "inter", - "day", - "SRE", - 2010, - "DSL", - "ge" - ], - [ - "utopia", - 2000, - "winter", - "night", - "SRE", - 1990, - "DSL", - "ge" - ], - [ - "utopia", - 1990, - "summer", - "day", - "SRE", - 1990, - "DSL", - "ge" - ], - [ - "utopia", - 2010, - "inter", - "night", - "SRE", - 2010, - "GSL", - "ge" - ], - [ - "utopia", - 2010, - "summer", - "night", - "SRE", - 2000, - "DSL", - "ge" - ], - [ - "utopia", - 2010, - "summer", - "day", - "SRE", - 1990, - "DSL", - "ge" - ], - [ - "utopia", - 1990, - "summer", - "night", - "SRE", - 1990, - "DSL", - "ge" - ], - [ - "utopia", - 2000, - "inter", - "day", - "SRE", - 1990, - "DSL", - "ge" - ], - [ - "utopia", - 2010, - "summer", - "day", - "SRE", - 2000, - "DSL", - "ge" - ], - [ - "utopia", - 2010, - "summer", - "night", - "SRE", - 2010, - "DSL", - "ge" - ], - [ - "utopia", - 2000, - "summer", - "day", - "SRE", - 2000, - "GSL", - "ge" - ], - [ - "utopia", - 2000, - "inter", - "night", - "SRE", - 1990, - "DSL", - "ge" - ], - [ - "utopia", - 2000, - "inter", - "day", - "SRE", - 2000, - "GSL", - "ge" - ], - [ - "utopia", - 2010, - "winter", - "day", - "SRE", - 1990, - "GSL", - "ge" - ], - [ - "utopia", - 2010, - "summer", - "night", - "SRE", - 1990, - "DSL", - "ge" - ], - [ - "utopia", - 2010, - "winter", - "day", - "SRE", - 2010, - "GSL", - "ge" - ], - [ - "utopia", - 2000, - "summer", - "night", - "SRE", - 1990, - "DSL", - "ge" - ], - [ - "utopia", - 2000, - "summer", - "day", - "SRE", - 2000, - "DSL", - "ge" - ], - [ - "utopia", - 1990, - "inter", - "night", - "SRE", - 1990, - "GSL", - "ge" - ], - [ - "utopia", - 1990, - "winter", - "day", - "SRE", - 1990, - "GSL", - "ge" - ], - [ - "utopia", - 2010, - "winter", - "day", - "SRE", - 2000, - "GSL", - "ge" - ], - [ - "utopia", - 2010, - "inter", - "day", - "SRE", - 1990, - "GSL", - "ge" - ], - [ - "utopia", - 2010, - "inter", - "night", - "SRE", - 2000, - "GSL", - "ge" - ], - [ - "utopia", - 2000, - "summer", - "night", - "SRE", - 2000, - "GSL", - "ge" - ], - [ - "utopia", - 2000, - "inter", - "day", - "SRE", - 2000, - "DSL", - "ge" - ], - [ - "utopia", - 2010, - "inter", - "day", - "SRE", - 2000, - "GSL", - "ge" - ], - [ - "utopia", - 2000, - "winter", - "day", - "SRE", - 1990, - "GSL", - "ge" - ], - [ - "utopia", - 1990, - "inter", - "day", - "SRE", - 1990, - "GSL", - "ge" - ], - [ - "utopia", - 2010, - "inter", - "day", - "SRE", - 1990, - "DSL", - "ge" - ], - [ - "utopia", - 2000, - "winter", - "day", - "SRE", - 2000, - "GSL", - "ge" - ], - [ - "utopia", - 2010, - "inter", - "night", - "SRE", - 2010, - "DSL", - "ge" - ], - [ - "utopia", - 2010, - "winter", - "day", - "SRE", - 1990, - "DSL", - "ge" - ], - [ - "utopia", - 2010, - "summer", - "day", - "SRE", - 2010, - "GSL", - "ge" - ], - [ - "utopia", - 2010, - "inter", - "night", - "SRE", - 1990, - "GSL", - "ge" - ], - [ - "utopia", - 1990, - "winter", - "night", - "SRE", - 1990, - "GSL", - "ge" - ], - [ - "utopia", - 2010, - "winter", - "night", - "SRE", - 2000, - "GSL", - "ge" - ], - [ - "utopia", - 2010, - "winter", - "night", - "SRE", - 1990, - "GSL", - "ge" - ], - [ - "utopia", - 2010, - "winter", - "night", - "SRE", - 2010, - "GSL", - "ge" - ], - [ - "utopia", - 2000, - "winter", - "day", - "SRE", - 2000, - "DSL", - "ge" - ], - [ - "utopia", - 2000, - "summer", - "day", - "SRE", - 1990, - "GSL", - "ge" - ], - [ - "utopia", - 1990, - "inter", - "day", - "SRE", - 1990, - "DSL", - "ge" - ], - [ - "utopia", - 2010, - "winter", - "day", - "SRE", - 2010, - "DSL", - "ge" - ], - [ - "utopia", - 1990, - "inter", - "night", - "SRE", - 1990, - "DSL", - "ge" - ], - [ - "utopia", - 2010, - "winter", - "day", - "SRE", - 2000, - "DSL", - "ge" - ], - [ - "utopia", - 2010, - "summer", - "day", - "SRE", - 2010, - "DSL", - "ge" - ], - [ - "utopia", - 2010, - "inter", - "night", - "SRE", - 1990, - "DSL", - "ge" - ], - [ - "utopia", - 2000, - "winter", - "night", - "SRE", - 2000, - "GSL", - "ge" - ], - [ - "utopia", - 2000, - "inter", - "day", - "SRE", - 1990, - "GSL", - "ge" - ], - [ - "utopia", - 1990, - "summer", - "day", - "SRE", - 1990, - "GSL", - "ge" - ], - [ - "utopia", - 2010, - "inter", - "night", - "SRE", - 2000, - "DSL", - "ge" - ], - [ - "utopia", - 2010, - "summer", - "day", - "SRE", - 2000, - "GSL", - "ge" - ], - [ - "utopia", - 2010, - "inter", - "day", - "SRE", - 2010, - "GSL", - "ge" - ], - [ - "utopia", - 2000, - "summer", - "night", - "SRE", - 2000, - "DSL", - "ge" - ], - [ - "utopia", - 2010, - "inter", - "day", - "SRE", - 2000, - "DSL", - "ge" - ], - [ - "utopia", - 2010, - "summer", - "day", - "SRE", - 1990, - "GSL", - "ge" - ], - [ - "utopia", - 1990, - "winter", - "night", - "SRE", - 1990, - "DSL", - "ge" - ], - [ - "utopia", - 2000, - "winter", - "day", - "SRE", - 1990, - "DSL", - "ge" - ], - [ - "utopia", - 2010, - "winter", - "night", - "SRE", - 2000, - "DSL", - "ge" - ], - [ - "utopia", - 2000, - "inter", - "night", - "SRE", - 2000, - "GSL", - "ge" - ], - [ - "utopia", - 1990, - "winter", - "day", - "SRE", - 1990, - "DSL", - "ge" - ], - [ - "utopia", - 2000, - "inter", - "night", - "SRE", - 1990, - "GSL", - "ge" - ], - [ - "utopia", - 2010, - "summer", - "night", - "SRE", - 2010, - "GSL", - "ge" - ], - [ - "utopia", - 2000, - "winter", - "night", - "SRE", - 1990, - "GSL", - "ge" - ], - [ - "utopia", - 1990, - "summer", - "night", - "SRE", - 1990, - "GSL", - "ge" - ] - ], - "linked_emissions_tech_constraint_rpsdtve": [], - "loan_lifetime_process_rtv": [ - [ - "utopia", - "IMPURN1", - 1990 - ], - [ - "utopia", - "TXD", - 1990 - ], - [ - "utopia", - "RHO", - 2010 - ], - [ - "utopia", - "E21", - 2000 - ], - [ - "utopia", - "IMPGSL1", - 1990 - ], - [ - "utopia", - "IMPDSL1", - 1990 - ], - [ - "utopia", - "TXE", - 1990 - ], - [ - "utopia", - "IMPHYD", - 1990 - ], - [ - "utopia", - "IMPOIL1", - 1990 - ], - [ - "utopia", - "E51", - 2010 - ], - [ - "utopia", - "E70", - 1990 - ], - [ - "utopia", - "RL1", - 1990 - ], - [ - "utopia", - "SRE", - 2000 - ], - [ - "utopia", - "TXG", - 2000 - ], - [ - "utopia", - "E31", - 2010 - ], - [ - "utopia", - "RHO", - 2000 - ], - [ - "utopia", - "RHE", - 2010 - ], - [ - "utopia", - "E21", - 1990 - ], - [ - "utopia", - "E01", - 2010 - ], - [ - "utopia", - "IMPHCO1", - 1990 - ], - [ - "utopia", - "TXD", - 2010 - ], - [ - "utopia", - "E51", - 2000 - ], - [ - "utopia", - "SRE", - 1990 - ], - [ - "utopia", - "TXG", - 1990 - ], - [ - "utopia", - "E31", - 2000 - ], - [ - "utopia", - "RHO", - 1990 - ], - [ - "utopia", - "TXE", - 2010 - ], - [ - "utopia", - "RHE", - 2000 - ], - [ - "utopia", - "E01", - 2000 - ], - [ - "utopia", - "E70", - 2010 - ], - [ - "utopia", - "RL1", - 2010 - ], - [ - "utopia", - "TXD", - 2000 - ], - [ - "utopia", - "E21", - 2010 - ], - [ - "utopia", - "IMPFEQ", - 1990 - ], - [ - "utopia", - "E51", - 1990 - ], - [ - "utopia", - "E31", - 1990 - ], - [ - "utopia", - "TXE", - 2000 - ], - [ - "utopia", - "RHE", - 1990 - ], - [ - "utopia", - "E01", - 1990 - ], - [ - "utopia", - "SRE", - 2010 - ], - [ - "utopia", - "TXG", - 2010 - ], - [ - "utopia", - "E70", - 2000 - ], - [ - "utopia", - "RL1", - 2000 - ], - [ - "utopia", - "E01", - 1960 - ], - [ - "utopia", - "E01", - 1970 - ], - [ - "utopia", - "E01", - 1980 - ], - [ - "utopia", - "E70", - 1960 - ], - [ - "utopia", - "E70", - 1970 - ], - [ - "utopia", - "E70", - 1980 - ], - [ - "utopia", - "RHO", - 1970 - ], - [ - "utopia", - "RHO", - 1980 - ], - [ - "utopia", - "TXG", - 1970 - ], - [ - "utopia", - "TXG", - 1980 - ], - [ - "utopia", - "TXD", - 1970 - ], - [ - "utopia", - "TXD", - 1980 - ], - [ - "utopia", - "E31", - 1980 - ], - [ - "utopia", - "E51", - 1980 - ], - [ - "utopia", - "RL1", - 1980 - ] - ], - "new_capacity_var_rtv": [ - [ - "utopia", - "TXD", - 1990 - ], - [ - "utopia", - "RHO", - 2010 - ], - [ - "utopia", - "E21", - 2000 - ], - [ - "utopia", - "TXE", - 1990 - ], - [ - "utopia", - "E51", - 2010 - ], - [ - "utopia", - "E70", - 1990 - ], - [ - "utopia", - "RL1", - 1990 - ], - [ - "utopia", - "TXG", - 2000 - ], - [ - "utopia", - "SRE", - 2000 - ], - [ - "utopia", - "E31", - 2010 - ], - [ - "utopia", - "RHO", - 2000 - ], - [ - "utopia", - "RHE", - 2010 - ], - [ - "utopia", - "E21", - 1990 - ], - [ - "utopia", - "E01", - 2010 - ], - [ - "utopia", - "TXD", - 2010 - ], - [ - "utopia", - "E51", - 2000 - ], - [ - "utopia", - "SRE", - 1990 - ], - [ - "utopia", - "TXG", - 1990 - ], - [ - "utopia", - "E31", - 2000 - ], - [ - "utopia", - "RHO", - 1990 - ], - [ - "utopia", - "TXE", - 2010 - ], - [ - "utopia", - "RHE", - 2000 - ], - [ - "utopia", - "E01", - 2000 - ], - [ - "utopia", - "E70", - 2010 - ], - [ - "utopia", - "RL1", - 2010 - ], - [ - "utopia", - "TXD", - 2000 - ], - [ - "utopia", - "E21", - 2010 - ], - [ - "utopia", - "E51", - 1990 - ], - [ - "utopia", - "E31", - 1990 - ], - [ - "utopia", - "TXE", - 2000 - ], - [ - "utopia", - "RHE", - 1990 - ], - [ - "utopia", - "E01", - 1990 - ], - [ - "utopia", - "SRE", - 2010 - ], - [ - "utopia", - "TXG", - 2010 - ], - [ - "utopia", - "E70", - 2000 - ], - [ - "utopia", - "RL1", - 2000 - ] - ], - "process_life_frac_rptv": [ - [ - "utopia", - 2000, - "RL1", - 2000 - ], - [ - "utopia", - 2000, - "E21", - 2000 - ], - [ - "utopia", - 2000, - "TXE", - 1990 - ], - [ - "utopia", - 1990, - "RL1", - 1980 - ], - [ - "utopia", - 1990, - "RHO", - 1990 - ], - [ - "utopia", - 2000, - "IMPDSL1", - 1990 - ], - [ - "utopia", - 2010, - "IMPURN1", - 1990 - ], - [ - "utopia", - 1990, - "TXG", - 1980 - ], - [ - "utopia", - 2010, - "E01", - 1980 - ], - [ - "utopia", - 2010, - "E51", - 1980 - ], - [ - "utopia", - 2000, - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "TXG", - 2000 - ], - [ - "utopia", - 1990, - "E70", - 1960 - ], - [ - "utopia", - 2010, - "E21", - 1990 - ], - [ - "utopia", - 1990, - "RHE", - 1990 - ], - [ - "utopia", - 2000, - "IMPHCO1", - 1990 - ], - [ - "utopia", - 2010, - "RHE", - 2010 - ], - [ - "utopia", - 2000, - "E31", - 2000 - ], - [ - "utopia", - 2010, - "SRE", - 1990 - ], - [ - "utopia", - 2000, - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "E01", - 1980 - ], - [ - "utopia", - 2000, - "E70", - 1970 - ], - [ - "utopia", - 1990, - "E51", - 1980 - ], - [ - "utopia", - 2010, - "E01", - 2000 - ], - [ - "utopia", - 2010, - "E51", - 2000 - ], - [ - "utopia", - 2010, - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "TXD", - 2000 - ], - [ - "utopia", - 2000, - "E70", - 2000 - ], - [ - "utopia", - 2000, - "IMPHYD", - 1990 - ], - [ - "utopia", - 2010, - "E31", - 1990 - ], - [ - "utopia", - 2000, - "SRE", - 2000 - ], - [ - "utopia", - 1990, - "TXD", - 1970 - ], - [ - "utopia", - 2010, - "TXE", - 2000 - ], - [ - "utopia", - 2000, - "TXD", - 1980 - ], - [ - "utopia", - 1990, - "IMPFEQ", - 1990 - ], - [ - "utopia", - 2000, - "IMPOIL1", - 1990 - ], - [ - "utopia", - 2010, - "IMPGSL1", - 1990 - ], - [ - "utopia", - 2000, - "RHO", - 2000 - ], - [ - "utopia", - 2010, - "RHO", - 2010 - ], - [ - "utopia", - 1990, - "E31", - 1990 - ], - [ - "utopia", - 1990, - "RHO", - 1980 - ], - [ - "utopia", - 2010, - "E70", - 1990 - ], - [ - "utopia", - 2010, - "E31", - 2010 - ], - [ - "utopia", - 1990, - "IMPGSL1", - 1990 - ], - [ - "utopia", - 1990, - "TXG", - 1970 - ], - [ - "utopia", - 2000, - "TXG", - 1980 - ], - [ - "utopia", - 1990, - "IMPDSL1", - 1990 - ], - [ - "utopia", - 2010, - "RHE", - 2000 - ], - [ - "utopia", - 2000, - "E31", - 1990 - ], - [ - "utopia", - 2010, - "E70", - 2010 - ], - [ - "utopia", - 2000, - "IMPURN1", - 1990 - ], - [ - "utopia", - 1990, - "E21", - 1990 - ], - [ - "utopia", - 2010, - "IMPFEQ", - 1990 - ], - [ - "utopia", - 1990, - "E70", - 1980 - ], - [ - "utopia", - 2010, - "E21", - 2010 - ], - [ - "utopia", - 1990, - "E01", - 1970 - ], - [ - "utopia", - 2000, - "E01", - 1980 - ], - [ - "utopia", - 2010, - "E01", - 1990 - ], - [ - "utopia", - 2000, - "E51", - 1980 - ], - [ - "utopia", - 2010, - "E51", - 1990 - ], - [ - "utopia", - 2000, - "TXG", - 2000 - ], - [ - "utopia", - 1990, - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "SRE", - 2010 - ], - [ - "utopia", - 2000, - "E70", - 1990 - ], - [ - "utopia", - 2010, - "E31", - 1980 - ], - [ - "utopia", - 2000, - "E21", - 1990 - ], - [ - "utopia", - 2000, - "SRE", - 1990 - ], - [ - "utopia", - 2010, - "IMPOIL1", - 1990 - ], - [ - "utopia", - 2000, - "E01", - 2000 - ], - [ - "utopia", - 2010, - "IMPDSL1", - 1990 - ], - [ - "utopia", - 2000, - "E51", - 2000 - ], - [ - "utopia", - 1990, - "TXD", - 1990 - ], - [ - "utopia", - 2000, - "RHO", - 1990 - ], - [ - "utopia", - 2010, - "IMPHCO1", - 1990 - ], - [ - "utopia", - 2000, - "TXD", - 2000 - ], - [ - "utopia", - 2010, - "TXD", - 2010 - ], - [ - "utopia", - 1990, - "E31", - 1980 - ], - [ - "utopia", - 1990, - "RHO", - 1970 - ], - [ - "utopia", - 2010, - "E70", - 1980 - ], - [ - "utopia", - 2010, - "E31", - 2000 - ], - [ - "utopia", - 1990, - "TXE", - 1990 - ], - [ - "utopia", - 2000, - "TXE", - 2000 - ], - [ - "utopia", - 2010, - "TXE", - 2010 - ], - [ - "utopia", - 1990, - "IMPOIL1", - 1990 - ], - [ - "utopia", - 1990, - "RL1", - 1990 - ], - [ - "utopia", - 2010, - "RL1", - 2010 - ], - [ - "utopia", - 2000, - "IMPGSL1", - 1990 - ], - [ - "utopia", - 1990, - "IMPHCO1", - 1990 - ], - [ - "utopia", - 2010, - "RHE", - 1990 - ], - [ - "utopia", - 1990, - "TXG", - 1990 - ], - [ - "utopia", - 2010, - "E70", - 2000 - ], - [ - "utopia", - 2000, - "E31", - 1980 - ], - [ - "utopia", - 2010, - "TXG", - 2010 - ], - [ - "utopia", - 1990, - "E70", - 1970 - ], - [ - "utopia", - 2010, - "E21", - 2000 - ], - [ - "utopia", - 1990, - "E01", - 1960 - ], - [ - "utopia", - 2000, - "E01", - 1970 - ], - [ - "utopia", - 2010, - "IMPHYD", - 1990 - ], - [ - "utopia", - 2010, - "SRE", - 2000 - ], - [ - "utopia", - 1990, - "IMPURN1", - 1990 - ], - [ - "utopia", - 2000, - "RHE", - 2000 - ], - [ - "utopia", - 1990, - "E01", - 1990 - ], - [ - "utopia", - 2000, - "E70", - 1980 - ], - [ - "utopia", - 1990, - "E51", - 1990 - ], - [ - "utopia", - 2010, - "E01", - 2010 - ], - [ - "utopia", - 2010, - "E51", - 2010 - ], - [ - "utopia", - 1990, - "E70", - 1990 - ], - [ - "utopia", - 2010, - "RHO", - 2000 - ], - [ - "utopia", - 1990, - "IMPHYD", - 1990 - ], - [ - "utopia", - 2000, - "E01", - 1990 - ], - [ - "utopia", - 2000, - "E51", - 1990 - ], - [ - "utopia", - 2000, - "IMPFEQ", - 1990 - ], - [ - "utopia", - 1990, - "TXD", - 1980 - ], - [ - "utopia", - 2000, - "RHO", - 1980 - ], - [ - "utopia", - 2000, - "TXD", - 1990 - ] - ], - "ramp_down_day_constraint_rpsdtv": [], - "ramp_down_season_constraint_rpsstv": [], - "ramp_up_day_constraint_rpsdtv": [], - "ramp_up_season_constraint_rpsstv": [], - "regional_exchange_capacity_constraint_rrptv": [], - "renewable_portfolio_standard_constraint_rpg": [], - "reserve_margin_rpsd": [], - "reserve_margin_method": [ - "static" - ], - "retired_capacity_var_rptv": [], - "seasonal_storage_level_rpstv": [], - "seasonal_storage_constraints_rpsdtv": [], - "storage_constraints_rpsdtv": [ - [ - "utopia", - 1990, - "winter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E51", - 2010 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E51", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E51", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E51", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E51", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E51", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E51", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E51", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E51", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E51", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E51", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E51", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E51", - 2010 - ] - ], - "storage_level_rpsdtv": [ - [ - "utopia", - 1990, - "winter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E51", - 2010 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E51", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E51", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E51", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E51", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E51", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "inter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "night", - "E51", - 2000 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "winter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E51", - 1980 - ], - [ - "utopia", - 1990, - "winter", - "day", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "inter", - "day", - "E51", - 2010 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "night", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "winter", - "day", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "day", - "E51", - 2010 - ], - [ - "utopia", - 1990, - "inter", - "night", - "E51", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "day", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "night", - "E51", - 2000 - ], - [ - "utopia", - 2000, - "summer", - "day", - "E51", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "night", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "night", - "E51", - 2010 - ] - ], - "time_manual": [], - "commodity_all": [ - "ethos", - "RH", - "TX", - "HYD", - "OIL", - "RL", - "HCO", - "ELC", - "co2", - "DSL", - "FEQ", - "URN", - "GSL", - "nox" - ], - "commodity_annual": [], - "commodity_carrier": [ - "ethos", - "RH", - "TX", - "HYD", - "OIL", - "RL", - "HCO", - "ELC", - "DSL", - "FEQ", - "URN", - "GSL" - ], - "commodity_demand": [ - "RL", - "RH", - "TX" - ], - "commodity_emissions": [ - "co2", - "nox" - ], - "commodity_flex": [], - "commodity_physical": [ - "ethos", - "HYD", - "OIL", - "HCO", - "ELC", - "DSL", - "FEQ", - "URN", - "GSL" - ], - "commodity_sink": [ - "RL", - "RH", - "TX" - ], - "commodity_source": [ - "ethos" - ], - "commodity_waste": [], - "operator": [ - "ge", - "e", - "le" - ], - "ordered_season_sequential": [], - "regional_global_indices": [ - "utopia" - ], - "regional_indices": [ - "utopia" - ], - "regions": [ - "utopia" - ], - "tech_all": [ - "E21", - "IMPHCO1", - "IMPOIL1", - "E31", - "IMPHYD", - "TXE", - "E51", - "TXD", - "IMPGSL1", - "IMPFEQ", - "IMPDSL1", - "E01", - "RHE", - "IMPURN1", - "RL1", - "SRE", - "E70", - "RHO", - "TXG" - ], - "tech_annual": [], - "tech_demand": [ - "RHO", - "TXE", - "RHE", - "TXG", - "TXD", - "RL1" - ], - "tech_baseload": [ - "E31", - "E01", - "E21" - ], - "tech_curtailment": [], - "tech_downramping": [], - "tech_exchange": [], - "tech_exist": [ - "E01", - "E70", - "E51", - "TXD", - "RHO", - "TXG", - "E31", - "RL1" - ], - "tech_flex": [], - "tech_group_members": [], - "tech_group_names": [], - "tech_or_group": [ - "IMPOIL1", - "IMPHYD", - "E21", - "RL1", - "TXG", - "E51", - "IMPDSL1", - "IMPHCO1", - "E01", - "SRE", - "RHE", - "E70", - "IMPFEQ", - "TXE", - "IMPURN1", - "IMPGSL1", - "TXD", - "RHO", - "E31" - ], - "tech_production": [ - "E01", - "E21", - "E70", - "E51", - "TXE", - "TXD", - "RHO", - "TXG", - "RHE", - "E31", - "RL1", - "SRE", - "IMPDSL1", - "IMPHYD", - "IMPHCO1", - "IMPGSL1", - "IMPFEQ", - "IMPURN1", - "IMPOIL1" - ], - "tech_reserve": [], - "tech_retirement": [], - "tech_seasonal_storage": [], - "tech_storage": [ - "E51" - ], - "tech_uncap": [ - "IMPDSL1", - "IMPHYD", - "IMPHCO1", - "IMPGSL1", - "IMPFEQ", - "IMPURN1", - "IMPOIL1" - ], - "tech_upramping": [], - "tech_with_capacity": [ - "E01", - "E21", - "E70", - "E51", - "TXE", - "TXD", - "RHO", - "TXG", - "RHE", - "E31", - "RL1", - "SRE" - ], - "time_exist": [ - 1960, - 1970, - 1980 - ], - "time_future": [ - 2000, - 2010, - 2020, - 1990 - ], - "time_of_day": [ - "day", - "night" - ], - "time_optimize": [ - 2000, - 2010, - 1990 - ], - "time_season": [ - "summer", - "inter", - "winter" - ], - "time_season_sequential": [], - "time_sequencing": [ - "seasonal_timeslices" - ], - "vintage_all": [ - 1990, - 1960, - 2000, - 1970, - 2010, - 1980 - ], - "vintage_exist": [ - 1960, - 1970, - 1980 - ], - "vintage_optimize": [ - 2000, - 2010, - 1990 - ], - "storage_init_rpstv": [ - [ - "utopia", - 2010, - "inter", - "E51", - 2000 - ], - [ - "utopia", - 2010, - "summer", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "E51", - 1990 - ], - [ - "utopia", - 1990, - "summer", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "inter", - "E51", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "E51", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "E51", - 2000 - ], - [ - "utopia", - 1990, - "winter", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "summer", - "E51", - 2000 - ], - [ - "utopia", - 2000, - "inter", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "inter", - "E51", - 1980 - ], - [ - "utopia", - 1990, - "inter", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "summer", - "E51", - 2000 - ], - [ - "utopia", - 2000, - "winter", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "winter", - "E51", - 2010 - ], - [ - "utopia", - 2010, - "inter", - "E51", - 2010 - ], - [ - "utopia", - 2000, - "inter", - "E51", - 1980 - ], - [ - "utopia", - 1990, - "summer", - "E51", - 1990 - ], - [ - "utopia", - 2010, - "summer", - "E51", - 1990 - ], - [ - "utopia", - 1990, - "inter", - "E51", - 1980 - ], - [ - "utopia", - 2000, - "summer", - "E51", - 1990 - ], - [ - "utopia", - 2000, - "winter", - "E51", - 1980 - ], - [ - "utopia", - 2010, - "winter", - "E51", - 2000 - ] - ] -} + "operator": "74d830836f1399fb336a0432dde7d7bd36cffa3ff76b1c42d7945350cfb9bf91", + "time_exist": "c9529ee6b8874a867c196738619704c725ba6fbf61a03b9739090422b8904de2", + "time_future": "8c9cb7410e2199a84d1b5607c46429f0c6bc67a2b9e322a48434d83a2e81e007", + "time_optimize": "b36c1cbd59292ec15b8ff1504ec03c5657665e2b3350e224dfd31364cb393ffa", + "vintage_exist": "c9529ee6b8874a867c196738619704c725ba6fbf61a03b9739090422b8904de2", + "vintage_optimize": "b36c1cbd59292ec15b8ff1504ec03c5657665e2b3350e224dfd31364cb393ffa", + "vintage_all": "b96a0eef5579c688203bc71c6700b5a74d6d9306ee443980e67beef17ac4e8f0", + "time_season": "df37d485468915bce6cd7fa627702773c5d6c3dee47cffdc6360d31dd1dd28eb", + "time_season_sequential": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "time_of_day": "9f58a9fbc74271e641f4b7624b22daca061195a3d85b58d270fb8590937007b1", + "ordered_season_sequential": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "regions": "ce00905893c23bc59c15dcf61d7e261c2e97ab1fc298ed0e0ccb1344f1cace37", + "regional_indices": "ce00905893c23bc59c15dcf61d7e261c2e97ab1fc298ed0e0ccb1344f1cace37", + "regional_global_indices": "ce00905893c23bc59c15dcf61d7e261c2e97ab1fc298ed0e0ccb1344f1cace37", + "tech_production": "5c321f60e5d16e60c5063b83d59ac9e184ab78e7fc469e41b21fd8aea83f600c", + "tech_all": "5c321f60e5d16e60c5063b83d59ac9e184ab78e7fc469e41b21fd8aea83f600c", + "tech_baseload": "e7c3d5843adeb51ccb0774118e8e5085f4a01c787a32b5ed34cba220efd9121a", + "tech_annual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_demand": "481b9363bcd61f44255efcc7bb7cc4112bef3c969435024dd5e2659e3c8dbfdb", + "tech_storage": "245737c06f3e838e63da08a47a7d2a8605340ea5cad86397e1bb66461a574358", + "tech_reserve": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_upramping": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_downramping": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_curtailment": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_flex": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_exchange": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_group_names": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_group_members": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_or_group": "5c321f60e5d16e60c5063b83d59ac9e184ab78e7fc469e41b21fd8aea83f600c", + "tech_seasonal_storage": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_uncap": "b2c8c3f94a51bb7ab55ad7b534cb7aba64a506678c109abb4141f4d2e84bf431", + "tech_exist": "b7d598371119e425be7beedbdde0525c88b7aa0018887e81d2cccc6bb0385ffa", + "tech_with_capacity": "459b04924b80d93e0061564b6c1f1b8d39543d697b81150413d7bc86c3003e33", + "tech_retirement": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "commodity_demand": "8d35b293b5cef0a6d0c6552029082eaec587db0bc5813783f24ab1aafe7491c8", + "commodity_emissions": "cc2dd294fd87cfc0324fcd1d62eb647ff83bd89d7b5abd5dd5374debea96d91b", + "commodity_physical": "3aab3aa4622d1545fe0f3cb8bd1a01fb9918632cff7186cfd49fa8575b73b2f3", + "commodity_waste": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "commodity_flex": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "commodity_source": "9679c6d5ef1c2949d7c4b6685ba2fd4195282539b3f24650247f40be62eecf3a", + "commodity_sink": "8d35b293b5cef0a6d0c6552029082eaec587db0bc5813783f24ab1aafe7491c8", + "commodity_annual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "commodity_carrier": "23deb826164f35ff8adf73b9c64a4edb3efeeb51b683e14ea40f0771eba42eb8", + "commodity_all": "25fb43b483a85d6e4b4d8251a272a4c78fb9d02a65af63a9c044d64211661563", + "time_sequencing": "91f69c8abab9959c1f8c90f5aaa56db29bccc67e37d12673ab41c54e4179d7ca", + "time_manual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "demand_constraint_rpc": "c1654f787e15af2031bcea2dcebde3830df52ea0f798e854ba784e6f1223b301", + "lifetime_process_rtv": "2cfc288b15f25957dfc70f6396d97ad655ecbed91c5a11582329749f1fb3dbd7", + "loan_lifetime_process_rtv": "2cfc288b15f25957dfc70f6396d97ad655ecbed91c5a11582329749f1fb3dbd7", + "renewable_portfolio_standard_constraint_rpg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "capacity_factor_rsdt": "1e5fae1e3999dbea84cc6d39e3ad91e95a2064c96f3569ea2dfef041d6011c5a", + "capacity_constraint_rpsdtv": "67324b45087c277b42b4664f23c93bd75820eb6a0ed7298afe6b185165b97a25", + "cost_fixed_rptv": "972a1a82e59135297f51ef6ca2ce5760a8e0fcb67e064b270b14cbf5e4661831", + "cost_invest_rtv": "651a10edbb8297f51b380318385c9f1ae824a73216318e1c9aea78fc9f371a14", + "cost_variable_rptv": "37ad263f78986f4d38c63278a0d1a5a85b3eb8b833e8bfabbbea254eaf3a3efb", + "cost_emission_rpe": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "process_life_frac_rptv": "37ad263f78986f4d38c63278a0d1a5a85b3eb8b833e8bfabbbea254eaf3a3efb", + "limit_capacity_constraint_rpt": "5a43de033187da68c612c5bcef6a76edb6ab9806464b6d865e46d289ccbbd815", + "limit_new_capacity_constraint_rtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_resource_constraint_rt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_activity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_seasonal_capacity_factor_constraint_rst": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_seasonal_capacity_factor_constraint_rpst": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_annual_capacity_factor_constraint_rtvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_emission_constraint_rpe": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "emission_activity_reitvo": "8b4c8f2cf9b46db814898d140f48dc75e50c34bcf71a55adee31afa67cea1eba", + "limit_capacity_share_constraint_rpgg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_activity_share_constraint_rpgg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_new_capacity_share_constraint_rggv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "storage_constraints_rpsdtv": "fe4c04240f67fbe31572a29c9c1d3bef9dfb10c1090d311797530deeae8393e9", + "seasonal_storage_constraints_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_storage_fraction_param_rsdt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_storage_fraction_constraint_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "reserve_margin_method": "7869283c0d14273f720716309207a8f0c24606d03c679d6b68e656ed8d86241d", + "flow_var_rpsditvo": "350739a59b14969da094cf1c95524134b9c9acd0989710456a8dcc6596d0a401", + "flow_var_annual_rpitvo": "4053866a304af0a6b9a1d293ddaf358dfee5b170dcb01d41e6bc52437908a98a", + "flex_var_rpsditvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "flex_var_annual_rpitvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "curtailment_var_rpsditvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "flow_in_storage_rpsditvo": "99eb864a26adcb6633c95462649bca3ef7096f67682702915d7769b54b5de386", + "storage_level_rpsdtv": "fe4c04240f67fbe31572a29c9c1d3bef9dfb10c1090d311797530deeae8393e9", + "storage_init_rpstv": "86f4e3cf182540836f499c369cbac966e81c807d55a4f70d9b7a1473276c07b4", + "seasonal_storage_level_rpstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "capacity_var_rptv": "972a1a82e59135297f51ef6ca2ce5760a8e0fcb67e064b270b14cbf5e4661831", + "new_capacity_var_rtv": "d4f1cc8b432075001befddab648d54d1f82a29099236948845393a193b6add5b", + "retired_capacity_var_rptv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "annual_retirement_var_rptv": "e2487c314e1404726bdfbc8ba061d507f18882c658e81ea27c4369f0d4a892fd", + "capacity_available_var_rpt": "96e94bf0459e843802e1ea858c807be22b09354409fbd93a6b1a91d4438a7727", + "capacity_annual_constraint_rptv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "demand_activity_constraint_rpsdtv_dem": "264109f8bf88d194fdfe03d2e18654ffe0ba11bdf8430c50b39c03bdc43a53e1", + "commodity_balance_constraint_rpsdc": "79a5589e5d9b834ff2132fd4ce354a16e3a17529415245da9b9d8b13814ad382", + "annual_commodity_balance_constraint_rpc": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "baseload_diurnal_constraint_rpsdtv": "da0dafcd9aef41d231282c85362d767636d8ba3815ea809e0b7eeb326233fbf9", + "regional_exchange_capacity_constraint_rrptv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "ramp_up_day_constraint_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "ramp_down_day_constraint_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "ramp_up_season_constraint_rpsstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "ramp_down_season_constraint_rpsstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "reserve_margin_rpsd": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_growth_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_degrowth_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_growth_new_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_degrowth_new_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_growth_new_capacity_delta_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_degrowth_new_capacity_delta_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_annual_capacity_factor_constraint_rptvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_tech_input_split_constraint_rpsditv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_tech_input_split_annual_constraint_rpitv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_tech_input_split_average_constraint_rpitv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_tech_output_split_constraint_rpsdtvo": "f8e7d420020c7bc28dc29fb313fae2027f40143e43bc8c39347060d4e63a087d", + "limit_tech_output_split_annual_constraint_rptvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_tech_output_split_average_constraint_rptvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "linked_emissions_tech_constraint_rpsdtve": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945" +} \ No newline at end of file diff --git a/tests/utilities/capture_set_values_for_cache.py b/tests/utilities/capture_set_values_for_cache.py index 3c5eed984..86d0c7bf5 100644 --- a/tests/utilities/capture_set_values_for_cache.py +++ b/tests/utilities/capture_set_values_for_cache.py @@ -4,27 +4,30 @@ This file should not need to be run again unless model schema changes """ +import hashlib import json import sys from pathlib import Path +from typing import Any import pyomo.environ as pyo from temoa._internal.temoa_sequencer import TemoaSequencer from temoa.core.config import TemoaConfig +from temoa.core.modes import TemoaMode from tests.conftest import refresh_databases print( 'WARNING: Continuing to execute this file will ' 'update the cached values in the testing_data folder' - 'from the sqlite databases in the same folder. ' - 'This should only need to be done if the schema or' + 'from the sqlite databases in the same folder. ' + 'This should only need to be done if the schema or ' 'model have changed and that database has been updated.' '\nRunning this basically resets the expected value sets' 'for Utopia, TestSystem, and Mediumville' ) -t = input('Type "Y" to continue, any other key to exit now.') +t = 'Y' # automated run if t not in {'y', 'Y'}: sys.exit(0) @@ -34,15 +37,15 @@ scenarios = [ { 'output_file': Path(__file__).parent.parent / 'testing_data' / 'utopia_sets.json', - 'config_file': Path(__file__).parent / 'config_utopia.toml', + 'config_file': Path(__file__).parent.parent / 'testing_configs' / 'config_utopia.toml', }, { 'output_file': Path(__file__).parent.parent / 'testing_data' / 'test_system_sets.json', - 'config_file': Path(__file__).parent / 'config_test_system.toml', + 'config_file': Path(__file__).parent.parent / 'testing_configs' / 'config_test_system.toml', }, { 'output_file': Path(__file__).parent.parent / 'testing_data' / 'mediumville_sets.json', - 'config_file': Path(__file__).parent / 'config_mediumville.toml', + 'config_file': Path(__file__).parent.parent / 'testing_configs' / 'config_mediumville.toml', }, ] # make new copies of the DB's from source... @@ -52,12 +55,22 @@ config = TemoaConfig.build_config( config_file=scenario['config_file'], output_path=output_path, silent=True ) - ts = TemoaSequencer(config=config) + ts = TemoaSequencer(config=config, mode_override=TemoaMode.BUILD_ONLY) built_instance = ts.build_model() # catch the built model + def hash_set(s: Any) -> str: + try: + sorted_elements = sorted(s) + except TypeError: + sorted_elements = sorted([str(e) for e in s]) + s_bytes = json.dumps(sorted_elements).encode('utf-8') + return hashlib.sha256(s_bytes).hexdigest() + model_sets = built_instance.component_map(ctype=pyo.Set) - sets_dict = {k: list(v) for k, v in model_sets.items()} + sets_dict = { + k: hash_set(v) for k, v in model_sets.items() if '_index' not in k and '_domain' not in k + } # stash the result in a json file... with open(scenario['output_file'], 'w') as f_out: From 12c13735b907e2880ab3623f882a9b139bbdd017 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 24 Mar 2026 13:03:52 -0400 Subject: [PATCH 506/587] refactoring hash utilities to separate file and removing dead code --- tests/test_set_consistency.py | 46 ++--- tests/testing_data/mediumville_sets.json | 194 +++++++++--------- tests/testing_data/test_system_sets.json | 194 +++++++++--------- tests/testing_data/utopia_sets.json | 194 +++++++++--------- .../utilities/capture_set_values_for_cache.py | 28 +-- tests/utilities/hash_utils.py | 16 ++ 6 files changed, 325 insertions(+), 347 deletions(-) create mode 100644 tests/utilities/hash_utils.py diff --git a/tests/test_set_consistency.py b/tests/test_set_consistency.py index 50a0f0a48..7f18054cb 100644 --- a/tests/test_set_consistency.py +++ b/tests/test_set_consistency.py @@ -3,10 +3,8 @@ Utopia and Test System. """ -import hashlib import json import pathlib -from typing import Any import pytest from pyomo import environ as pyo @@ -14,6 +12,7 @@ from temoa._internal.temoa_sequencer import TemoaSequencer from temoa.core.config import TemoaConfig from temoa.core.modes import TemoaMode +from tests.utilities.hash_utils import hash_set TESTING_CONFIGS_DIR = pathlib.Path(__file__).parent / 'testing_configs' @@ -46,14 +45,6 @@ def test_set_consistency( model_sets = built_instance.component_map(ctype=pyo.Set) model_sets = {k: set(v) for k, v in model_sets.items()} - def hash_set(s: Any) -> str: - try: - sorted_elements = sorted(s) - except TypeError: - sorted_elements = sorted([str(e) for e in s]) - s_bytes = json.dumps(sorted_elements).encode('utf-8') - return hashlib.sha256(s_bytes).hexdigest() - # retrieve the cache which now stores hashes cache_file = pathlib.Path(__file__).parent / 'testing_data' / set_file with open(cache_file) as src: @@ -62,8 +53,6 @@ def hash_set(s: Any) -> str: # compare hashes where they exist in the model. mismatched_sets = {} for set_name, s in model_sets.items(): - if set_name == 'cost_emission_rpe': - pass if '_index' in set_name or '_domain' in set_name: continue @@ -72,42 +61,39 @@ def hash_set(s: Any) -> str: if cached_hash is not None and cached_hash != model_hash: mismatched_sets[set_name] = {'cached': cached_hash, 'model': model_hash} - missing_in_model = cached_sets.keys() - model_sets.keys() - # drop any set that has "_index" in the name as they are no longer reported by newer version of - # pyomo - missing_in_model = {s for s in missing_in_model if '_index' not in s and '_domain' not in s} + missing_in_model = { + k + for k in cached_sets.keys() - model_sets.keys() + if '_index' not in k and '_domain' not in k + } if mismatched_sets: print('\nMismatched sets compared to cache (hashes differ): ') for k, hashes in mismatched_sets.items(): print(f'{k}: cached={hashes["cached"]}, model={hashes["model"]}') - # look for new or dropped sets in EITHER model_extra_sets = { k for k in model_sets.keys() - cached_sets.keys() if '_index' not in k and '_domain' not in k } - cache_extra_sets = { - k - for k in cached_sets.keys() - model_sets.keys() - if '_index' not in k and '_domain' not in k - } if model_extra_sets: print('\nModel extra sets compared to cache: ') for k in model_extra_sets: print(f'{k}: {model_sets[k]}') - if cache_extra_sets: + if missing_in_model: print('\nCache extra sets compared to model: ') - for k in cache_extra_sets: + for k in missing_in_model: print(f'{k}: {cached_sets[k]}') - assert not missing_in_model, f'one or more cached set not in model: {missing_in_model}' + assert not missing_in_model, ( + f'The {data_name} run has cached sets missing in the model: {missing_in_model}' + ) assert not mismatched_sets, ( - f'The {data_name} run-produced sets did not match cached values (hashes differ)' + f'The {data_name} run-produced sets did not match cached values (hashes differ): ' + f'{list(mismatched_sets.keys())}' + ) + assert not model_extra_sets, ( + f'The {data_name} run has extra sets compared to the cache: {model_extra_sets}' ) - if cache_extra_sets: - assert False, 'Cache has extra sets' # noqa B011 - if model_extra_sets: - assert False, 'Model has extra sets' # noqa B011 diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index a3fca69f3..82bf63afd 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -1,115 +1,115 @@ { - "operator": "74d830836f1399fb336a0432dde7d7bd36cffa3ff76b1c42d7945350cfb9bf91", - "time_exist": "91a2461c25439830d94bf4b3d3a3b020343f75e74561a913b1f972b2ac42e943", - "time_future": "6b150df8e12ac4dd15396b52f304c7935a41d2cc4da498186552819973171389", - "time_optimize": "9c9380fb50cd4f4f9e2032bd9a18645ae4fc1d30335672c62c897bcb9e099ba5", - "vintage_exist": "91a2461c25439830d94bf4b3d3a3b020343f75e74561a913b1f972b2ac42e943", - "vintage_optimize": "9c9380fb50cd4f4f9e2032bd9a18645ae4fc1d30335672c62c897bcb9e099ba5", - "vintage_all": "947dd08ad4812a98649b4306e4a0ca1b51374d86f1a8e27c3a8af3b189bcc0f6", - "time_season": "1e413891065e24bbf66543d4747ff12b1c65bf23c4ff9857b0bf0520eccd7f21", - "time_season_sequential": "1e413891065e24bbf66543d4747ff12b1c65bf23c4ff9857b0bf0520eccd7f21", - "time_of_day": "f9bbfe9130c510cba59a13e8b385b4d0206196abbdfe8032b995502bb7215f76", - "ordered_season_sequential": "53bc15b6510e5bad389153a661165e5a434fea3f17ba2c8b3919568edf124f72", - "regions": "f2314439597c11e286fd3c2fdf8eb70d3739e136f83e9533249ce3ecc43ece3e", - "regional_indices": "6d8dc3bc6dc8cd485bcf2a59d752df20974b0fd78cc623e3a51e705a01edeea4", - "regional_global_indices": "a4bd2969735cb437072971a2fa02a2d8fbb20a707a1bdfa695b92922daeb5d10", - "tech_production": "24f75b6f705a36033456d02638e7c50667908c45c474151fb8490666d928c63f", - "tech_all": "24f75b6f705a36033456d02638e7c50667908c45c474151fb8490666d928c63f", - "tech_baseload": "ddcf6ff7665c2a8acc4dff1b43655fae1b5a265135cbee18cec638df4e954346", - "tech_annual": "04ce850e0c3d3cb6608accab041c052be13c33d3f9d546242743b948989a043f", - "tech_demand": "b9e4a17c6dbf50597b7fd89aa581889bc19b262bd61629465295a52d91208096", - "tech_storage": "e4e91128cadba8c633bf98029cf6666adc3959c63967c6f396028b78e2e9f0cf", - "tech_reserve": "b28d0fd7ec11abdd0e645c2a9d83b05c08ecadcfb944d4a7bbd844ff4b83bfbf", - "tech_upramping": "ddcf6ff7665c2a8acc4dff1b43655fae1b5a265135cbee18cec638df4e954346", - "tech_downramping": "ddcf6ff7665c2a8acc4dff1b43655fae1b5a265135cbee18cec638df4e954346", - "tech_curtailment": "ddcf6ff7665c2a8acc4dff1b43655fae1b5a265135cbee18cec638df4e954346", - "tech_flex": "658ce9e7b9c3d7bcc751d8d49b9ece9c57623b3e25470c4f849af44b61ea5e20", - "tech_exchange": "4ad32a8fc9b95e840aa771b2dabc6fb35fae4904c089d4552659a4a9267883a7", - "tech_group_names": "6b923047f11d1c00a828b0f02aed79e853d81fd35ffd4667fbdc828ce356e515", - "tech_group_members": "6b923047f11d1c00a828b0f02aed79e853d81fd35ffd4667fbdc828ce356e515", - "tech_or_group": "4899ca300eb8ed5ba168b1f2ee669cacd36d041f493fb3dd00218d6764598cf9", - "tech_seasonal_storage": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "tech_uncap": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "tech_exist": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "tech_with_capacity": "24f75b6f705a36033456d02638e7c50667908c45c474151fb8490666d928c63f", - "tech_retirement": "ddcf6ff7665c2a8acc4dff1b43655fae1b5a265135cbee18cec638df4e954346", + "annual_commodity_balance_constraint_rpc": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "annual_retirement_var_rptv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "baseload_diurnal_constraint_rpsdtv": "d766f05fa377b69768214641fda5d15617b697a43e64c863fe53503f11db4a89", + "capacity_annual_constraint_rptv": "6bd365e2e2f3267c7b838774484507a0812b25077f3006bcbfe135eceda11a28", + "capacity_available_var_rpt": "34f71aae4b6b3a07130b57fa7910379bc1ecc3e12a6b4930fca5717bf54f8f56", + "capacity_constraint_rpsdtv": "02dcd6b84019270beb4b4fcac4062d1554bcc62ea9ed37c9b7f99d351b307898", + "capacity_factor_rsdt": "596087531ddbb1b27bc63b78e85b3d4fbb56c621ed2dbe35ef4f9f0ffcc49f68", + "capacity_var_rptv": "fdb177f119430de12c8b1083c9275e3a256f45f859d6b6819a84bff5c8e92184", + "commodity_all": "1967c4b68c028414d99b55bfe9e03efd2fff370d15540a95282b721875d41460", + "commodity_annual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "commodity_balance_constraint_rpsdc": "a1d06a815047ba07b42ced6dc65df3511301af2f30791b3094fb7f25ccdd4217", + "commodity_carrier": "1b95135b3de272d1ecab3761bdb976f1e48c044dcb2b5b6d320bc19dae0038cd", "commodity_demand": "f0ecafabcdc5015dab09f4b23f3c742a27b536f1c5634057a902a9b9c4a741b8", "commodity_emissions": "849d0ab948e289950369de3a31be985d420635fa93525416da6d3ee9149019fc", - "commodity_physical": "7dd03855822916eb73171efbb05042535e0f89c26614139ed357a002b8a80fd1", - "commodity_waste": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "commodity_flex": "bfbe6f995c3a9fd19c92c7b6ffc526035a773a24d302c7eae9951b7327aef904", - "commodity_source": "ab3705f3ba0b69baa453c70d1bdfde3faa4eaeabc007204278258b4aacd861f3", + "commodity_physical": "7dd03855822916eb73171efbb05042535e0f89c26614139ed357a002b8a80fd1", "commodity_sink": "f0ecafabcdc5015dab09f4b23f3c742a27b536f1c5634057a902a9b9c4a741b8", - "commodity_annual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "commodity_carrier": "1b95135b3de272d1ecab3761bdb976f1e48c044dcb2b5b6d320bc19dae0038cd", - "commodity_all": "1967c4b68c028414d99b55bfe9e03efd2fff370d15540a95282b721875d41460", - "time_sequencing": "91f69c8abab9959c1f8c90f5aaa56db29bccc67e37d12673ab41c54e4179d7ca", - "time_manual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "demand_constraint_rpc": "65996df03f7f3d85067ae18d36bdffe8596881473ae847052dc5df735cd01262", - "lifetime_process_rtv": "212639322f29aa7687eb9962fb9d74ef60961d720a2a753e2af53473b9e1648f", - "loan_lifetime_process_rtv": "212639322f29aa7687eb9962fb9d74ef60961d720a2a753e2af53473b9e1648f", - "renewable_portfolio_standard_constraint_rpg": "ab39415b5df1f906b11f06034cbfca390f7332b6a17adae60a71a74d7b421f67", - "capacity_factor_rsdt": "596087531ddbb1b27bc63b78e85b3d4fbb56c621ed2dbe35ef4f9f0ffcc49f68", - "capacity_constraint_rpsdtv": "02dcd6b84019270beb4b4fcac4062d1554bcc62ea9ed37c9b7f99d351b307898", + "commodity_source": "ab3705f3ba0b69baa453c70d1bdfde3faa4eaeabc007204278258b4aacd861f3", + "commodity_waste": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "cost_emission_rpe": "14c414e00f949816cbdbbfc01ab7df2fea18cd7f0ab4e84a33571e41667bd057", "cost_fixed_rptv": "fdb177f119430de12c8b1083c9275e3a256f45f859d6b6819a84bff5c8e92184", "cost_invest_rtv": "cc795cbbeaaae0c046247752c104269e877cd4c402391b63ce6fe4d6ed4cf46b", "cost_variable_rptv": "fdb177f119430de12c8b1083c9275e3a256f45f859d6b6819a84bff5c8e92184", - "cost_emission_rpe": "14c414e00f949816cbdbbfc01ab7df2fea18cd7f0ab4e84a33571e41667bd057", - "process_life_frac_rptv": "fdb177f119430de12c8b1083c9275e3a256f45f859d6b6819a84bff5c8e92184", - "limit_capacity_constraint_rpt": "118826dabd14af75ae09adbd5bdbba750528b3d59907cbfba3690223ffc7def7", - "limit_new_capacity_constraint_rtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_resource_constraint_rt": "b9b44ae8bc9642da0a81202877bd69f0b35ce193e31590dd3325ac0828edb5cf", - "limit_activity_constraint_rpt": "90461349933d0b32167abdca242233004b66212b57ed57213dce6f6818203963", - "limit_seasonal_capacity_factor_constraint_rst": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_seasonal_capacity_factor_constraint_rpst": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_annual_capacity_factor_constraint_rtvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_emission_constraint_rpe": "9bf30514ecc261370f67cd0c2e18194f45ff14c15764d274cc342a5a27eaf2a0", + "curtailment_var_rpsditvo": "541097cce6a976a20b73a2ffd8c4edd665a8497b066545d37318641b10484e95", + "demand_activity_constraint_rpsdtv_dem": "91570a9fbe4b071c37f1985c1671de2f33d9dfa7847f791a2933b8b3f262f8e8", + "demand_constraint_rpc": "65996df03f7f3d85067ae18d36bdffe8596881473ae847052dc5df735cd01262", "emission_activity_reitvo": "1292a5003c98c9ae6b7476807aca4bcc528b3dc28aec79827a47aeaaaaab74e4", - "limit_capacity_share_constraint_rpgg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_activity_share_constraint_rpgg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_new_capacity_share_constraint_rggv": "296e4148565f752973655692bae04ebf50877bd13fe9cec8f9563f347a61d885", - "storage_constraints_rpsdtv": "e1fe21679519e4410954d233e22d9490b182f21fda460b31a8d02538856fb85c", - "seasonal_storage_constraints_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_storage_fraction_param_rsdt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_storage_fraction_constraint_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "reserve_margin_method": "7869283c0d14273f720716309207a8f0c24606d03c679d6b68e656ed8d86241d", - "flow_var_rpsditvo": "e8c35c3b7b1f0c0e10e6f53e94d0c6b8a884c0dd048675cbeb9e7df33794161b", - "flow_var_annual_rpitvo": "6f5c569787fbf1e0a4076011f75fcd50a840bac85bb57b026f4fc5682739f888", - "flex_var_rpsditvo": "e4a8d7519d3e9deda0a32a471bdfa825eb893f10ba5781b895c9e3a3ef5faaa3", "flex_var_annual_rpitvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "curtailment_var_rpsditvo": "541097cce6a976a20b73a2ffd8c4edd665a8497b066545d37318641b10484e95", + "flex_var_rpsditvo": "e4a8d7519d3e9deda0a32a471bdfa825eb893f10ba5781b895c9e3a3ef5faaa3", "flow_in_storage_rpsditvo": "ff680754a218ee843941e77bd07cbc5e5afd74e2b7b29a76ea86621624e8c0fd", - "storage_level_rpsdtv": "e1fe21679519e4410954d233e22d9490b182f21fda460b31a8d02538856fb85c", - "storage_init_rpstv": "90db44be71af3d9d75369791755570cf888e63e3544be22800077a4a2871175c", - "seasonal_storage_level_rpstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "capacity_var_rptv": "fdb177f119430de12c8b1083c9275e3a256f45f859d6b6819a84bff5c8e92184", - "new_capacity_var_rtv": "212639322f29aa7687eb9962fb9d74ef60961d720a2a753e2af53473b9e1648f", - "retired_capacity_var_rptv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "annual_retirement_var_rptv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "capacity_available_var_rpt": "34f71aae4b6b3a07130b57fa7910379bc1ecc3e12a6b4930fca5717bf54f8f56", - "capacity_annual_constraint_rptv": "6bd365e2e2f3267c7b838774484507a0812b25077f3006bcbfe135eceda11a28", - "demand_activity_constraint_rpsdtv_dem": "91570a9fbe4b071c37f1985c1671de2f33d9dfa7847f791a2933b8b3f262f8e8", - "commodity_balance_constraint_rpsdc": "a1d06a815047ba07b42ced6dc65df3511301af2f30791b3094fb7f25ccdd4217", - "annual_commodity_balance_constraint_rpc": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "baseload_diurnal_constraint_rpsdtv": "d766f05fa377b69768214641fda5d15617b697a43e64c863fe53503f11db4a89", - "regional_exchange_capacity_constraint_rrptv": "cf641ca7d7b664fda48e76f03b37c3b81aaa130ce821f919e6a8ac4860dad100", - "ramp_up_day_constraint_rpsdtv": "d766f05fa377b69768214641fda5d15617b697a43e64c863fe53503f11db4a89", - "ramp_down_day_constraint_rpsdtv": "d766f05fa377b69768214641fda5d15617b697a43e64c863fe53503f11db4a89", - "ramp_up_season_constraint_rpsstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "ramp_down_season_constraint_rpsstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "reserve_margin_rpsd": "9bd91053e57055456e04648c00d8e581addc9aa503cf31cf44c7a439c6f4fe0f", - "limit_growth_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "flow_var_annual_rpitvo": "6f5c569787fbf1e0a4076011f75fcd50a840bac85bb57b026f4fc5682739f888", + "flow_var_rpsditvo": "e8c35c3b7b1f0c0e10e6f53e94d0c6b8a884c0dd048675cbeb9e7df33794161b", + "lifetime_process_rtv": "212639322f29aa7687eb9962fb9d74ef60961d720a2a753e2af53473b9e1648f", + "limit_activity_constraint_rpt": "90461349933d0b32167abdca242233004b66212b57ed57213dce6f6818203963", + "limit_activity_share_constraint_rpgg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_annual_capacity_factor_constraint_rptvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_annual_capacity_factor_constraint_rtvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_capacity_constraint_rpt": "118826dabd14af75ae09adbd5bdbba750528b3d59907cbfba3690223ffc7def7", + "limit_capacity_share_constraint_rpgg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "limit_degrowth_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_growth_new_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "limit_degrowth_new_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_growth_new_capacity_delta_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "limit_degrowth_new_capacity_delta_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_annual_capacity_factor_constraint_rptvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_tech_input_split_constraint_rpsditv": "7a0e9b6c8271bcc30ccd6588da984c4aa8afe5d768ce5035fe6d8e62b31f8b3e", + "limit_emission_constraint_rpe": "9bf30514ecc261370f67cd0c2e18194f45ff14c15764d274cc342a5a27eaf2a0", + "limit_growth_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_growth_new_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_growth_new_capacity_delta_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_new_capacity_constraint_rtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_new_capacity_share_constraint_rggv": "296e4148565f752973655692bae04ebf50877bd13fe9cec8f9563f347a61d885", + "limit_resource_constraint_rt": "b9b44ae8bc9642da0a81202877bd69f0b35ce193e31590dd3325ac0828edb5cf", + "limit_seasonal_capacity_factor_constraint_rpst": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_seasonal_capacity_factor_constraint_rst": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_storage_fraction_constraint_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_storage_fraction_param_rsdt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "limit_tech_input_split_annual_constraint_rpitv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "limit_tech_input_split_average_constraint_rpitv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_tech_output_split_constraint_rpsdtvo": "7cf9f5c111231f4e5c3f0ee8acfcddf52f5b1af3474d4cb949b969997602c8d7", + "limit_tech_input_split_constraint_rpsditv": "7a0e9b6c8271bcc30ccd6588da984c4aa8afe5d768ce5035fe6d8e62b31f8b3e", "limit_tech_output_split_annual_constraint_rptvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "limit_tech_output_split_average_constraint_rptvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "linked_emissions_tech_constraint_rpsdtve": "f5accc0ee9eaaf16e584566a50e576405f8b5e1eb7d13815b87cb2f8b33a19b8" -} \ No newline at end of file + "limit_tech_output_split_constraint_rpsdtvo": "7cf9f5c111231f4e5c3f0ee8acfcddf52f5b1af3474d4cb949b969997602c8d7", + "linked_emissions_tech_constraint_rpsdtve": "f5accc0ee9eaaf16e584566a50e576405f8b5e1eb7d13815b87cb2f8b33a19b8", + "loan_lifetime_process_rtv": "212639322f29aa7687eb9962fb9d74ef60961d720a2a753e2af53473b9e1648f", + "new_capacity_var_rtv": "212639322f29aa7687eb9962fb9d74ef60961d720a2a753e2af53473b9e1648f", + "operator": "74d830836f1399fb336a0432dde7d7bd36cffa3ff76b1c42d7945350cfb9bf91", + "ordered_season_sequential": "53bc15b6510e5bad389153a661165e5a434fea3f17ba2c8b3919568edf124f72", + "process_life_frac_rptv": "fdb177f119430de12c8b1083c9275e3a256f45f859d6b6819a84bff5c8e92184", + "ramp_down_day_constraint_rpsdtv": "d766f05fa377b69768214641fda5d15617b697a43e64c863fe53503f11db4a89", + "ramp_down_season_constraint_rpsstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "ramp_up_day_constraint_rpsdtv": "d766f05fa377b69768214641fda5d15617b697a43e64c863fe53503f11db4a89", + "ramp_up_season_constraint_rpsstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "regional_exchange_capacity_constraint_rrptv": "cf641ca7d7b664fda48e76f03b37c3b81aaa130ce821f919e6a8ac4860dad100", + "regional_global_indices": "a4bd2969735cb437072971a2fa02a2d8fbb20a707a1bdfa695b92922daeb5d10", + "regional_indices": "6d8dc3bc6dc8cd485bcf2a59d752df20974b0fd78cc623e3a51e705a01edeea4", + "regions": "f2314439597c11e286fd3c2fdf8eb70d3739e136f83e9533249ce3ecc43ece3e", + "renewable_portfolio_standard_constraint_rpg": "ab39415b5df1f906b11f06034cbfca390f7332b6a17adae60a71a74d7b421f67", + "reserve_margin_method": "7869283c0d14273f720716309207a8f0c24606d03c679d6b68e656ed8d86241d", + "reserve_margin_rpsd": "9bd91053e57055456e04648c00d8e581addc9aa503cf31cf44c7a439c6f4fe0f", + "retired_capacity_var_rptv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "seasonal_storage_constraints_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "seasonal_storage_level_rpstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "storage_constraints_rpsdtv": "e1fe21679519e4410954d233e22d9490b182f21fda460b31a8d02538856fb85c", + "storage_init_rpstv": "90db44be71af3d9d75369791755570cf888e63e3544be22800077a4a2871175c", + "storage_level_rpsdtv": "e1fe21679519e4410954d233e22d9490b182f21fda460b31a8d02538856fb85c", + "tech_all": "24f75b6f705a36033456d02638e7c50667908c45c474151fb8490666d928c63f", + "tech_annual": "04ce850e0c3d3cb6608accab041c052be13c33d3f9d546242743b948989a043f", + "tech_baseload": "ddcf6ff7665c2a8acc4dff1b43655fae1b5a265135cbee18cec638df4e954346", + "tech_curtailment": "ddcf6ff7665c2a8acc4dff1b43655fae1b5a265135cbee18cec638df4e954346", + "tech_demand": "b9e4a17c6dbf50597b7fd89aa581889bc19b262bd61629465295a52d91208096", + "tech_downramping": "ddcf6ff7665c2a8acc4dff1b43655fae1b5a265135cbee18cec638df4e954346", + "tech_exchange": "4ad32a8fc9b95e840aa771b2dabc6fb35fae4904c089d4552659a4a9267883a7", + "tech_exist": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_flex": "658ce9e7b9c3d7bcc751d8d49b9ece9c57623b3e25470c4f849af44b61ea5e20", + "tech_group_members": "6b923047f11d1c00a828b0f02aed79e853d81fd35ffd4667fbdc828ce356e515", + "tech_group_names": "6b923047f11d1c00a828b0f02aed79e853d81fd35ffd4667fbdc828ce356e515", + "tech_or_group": "4899ca300eb8ed5ba168b1f2ee669cacd36d041f493fb3dd00218d6764598cf9", + "tech_production": "24f75b6f705a36033456d02638e7c50667908c45c474151fb8490666d928c63f", + "tech_reserve": "b28d0fd7ec11abdd0e645c2a9d83b05c08ecadcfb944d4a7bbd844ff4b83bfbf", + "tech_retirement": "ddcf6ff7665c2a8acc4dff1b43655fae1b5a265135cbee18cec638df4e954346", + "tech_seasonal_storage": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_storage": "e4e91128cadba8c633bf98029cf6666adc3959c63967c6f396028b78e2e9f0cf", + "tech_uncap": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_upramping": "ddcf6ff7665c2a8acc4dff1b43655fae1b5a265135cbee18cec638df4e954346", + "tech_with_capacity": "24f75b6f705a36033456d02638e7c50667908c45c474151fb8490666d928c63f", + "time_exist": "91a2461c25439830d94bf4b3d3a3b020343f75e74561a913b1f972b2ac42e943", + "time_future": "6b150df8e12ac4dd15396b52f304c7935a41d2cc4da498186552819973171389", + "time_manual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "time_of_day": "f9bbfe9130c510cba59a13e8b385b4d0206196abbdfe8032b995502bb7215f76", + "time_optimize": "9c9380fb50cd4f4f9e2032bd9a18645ae4fc1d30335672c62c897bcb9e099ba5", + "time_season": "1e413891065e24bbf66543d4747ff12b1c65bf23c4ff9857b0bf0520eccd7f21", + "time_season_sequential": "1e413891065e24bbf66543d4747ff12b1c65bf23c4ff9857b0bf0520eccd7f21", + "time_sequencing": "91f69c8abab9959c1f8c90f5aaa56db29bccc67e37d12673ab41c54e4179d7ca", + "vintage_all": "947dd08ad4812a98649b4306e4a0ca1b51374d86f1a8e27c3a8af3b189bcc0f6", + "vintage_exist": "91a2461c25439830d94bf4b3d3a3b020343f75e74561a913b1f972b2ac42e943", + "vintage_optimize": "9c9380fb50cd4f4f9e2032bd9a18645ae4fc1d30335672c62c897bcb9e099ba5" +} diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index e936ad273..35cd0b4cf 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -1,115 +1,115 @@ { - "operator": "74d830836f1399fb336a0432dde7d7bd36cffa3ff76b1c42d7945350cfb9bf91", - "time_exist": "5206b4814992da4c7a4f643fdf04124735accc989ec0047874eb80e8541766c9", - "time_future": "2739be4c64d75aa5fb1552392c1f9d5587f15dba7a728f1768e415c0792b044e", - "time_optimize": "376da8132a26c5ebebc6d27395c2c883261928ac8d91004c167843c1e21d6141", - "vintage_exist": "5206b4814992da4c7a4f643fdf04124735accc989ec0047874eb80e8541766c9", - "vintage_optimize": "376da8132a26c5ebebc6d27395c2c883261928ac8d91004c167843c1e21d6141", - "vintage_all": "a19045d7d5b67af65f00af8d62f398968fea2c2d418f182b5d3ad0a56415eddf", - "time_season": "6d8e2fd49929c1f5216c0313307108c4993e58b00207210d3b6390d3f64e2896", - "time_season_sequential": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "time_of_day": "9f58a9fbc74271e641f4b7624b22daca061195a3d85b58d270fb8590937007b1", - "ordered_season_sequential": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "regions": "0ddd05d695b255ac719dfa85de1e900a3036d547ffc7261c9c9ca2c81bfda029", - "regional_indices": "f74187f92c4fdb3c12d5610304c7ac9696001433150bdaa9ff20793fb6365b32", - "regional_global_indices": "92fa6c5d5745d765d6e16ad1bca7e1fc72f4377273be7cfbfde626ca1967d81b", - "tech_production": "85a3645929dbeaf6b7eb17e8085c8923ef86949eaa3fb4fd81724dcdcf38fd30", - "tech_all": "85a3645929dbeaf6b7eb17e8085c8923ef86949eaa3fb4fd81724dcdcf38fd30", - "tech_baseload": "050aff703818154bf3439ed7d4a2cfef892be61da0c477526001c8c38b41a935", - "tech_annual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "tech_demand": "cf8d1075bb0667935fc3834c5266e775d1c746692179ef253809eaaa7abab6f8", - "tech_storage": "7109b89425e6707adc8a5e571bf70fc64475d2d76471e5afe93110fd86bbcec8", - "tech_reserve": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "tech_upramping": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "tech_downramping": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "tech_curtailment": "81683c0099a4eb22c8cca4b8eaf65a5bbf77c24b559cd1219823e6d6eb6cf915", - "tech_flex": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "tech_exchange": "6610eb4a0360be009669b5d50a2c3e1447bcf39eb820a0e63fd3718c27fae768", - "tech_group_names": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "tech_group_members": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "tech_or_group": "85a3645929dbeaf6b7eb17e8085c8923ef86949eaa3fb4fd81724dcdcf38fd30", - "tech_seasonal_storage": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "tech_uncap": "50b9da0bce0fcc3b318930929a2191c6c6c5e535e9ee986ca2ee740c7ff789bc", - "tech_exist": "eefd900ce35331470ba9f3312de6f03883efb5f402d321ff714cfe22d9ecdf94", - "tech_with_capacity": "bf3db0293ae9b3ec605ba8260a111eb71cbf3a786077a8172142a4e90ca1141b", - "tech_retirement": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "annual_commodity_balance_constraint_rpc": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "annual_retirement_var_rptv": "ee162bcd5c52c6e713033f89c7ffd0d244e4a34721217cfaf699959b131adcda", + "baseload_diurnal_constraint_rpsdtv": "20070e9c3c7443e237d3779a8ef33a25ae3a29284f5e1158a257f1a1d80c1421", + "capacity_annual_constraint_rptv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "capacity_available_var_rpt": "8f305de45d0d42708ef17b16602d770ef731810252b0d0b3a89dc396b54b8e8a", + "capacity_constraint_rpsdtv": "cd98cf3db577dec19c292199f5b7b8af2dfe336174af315ce2186bbcbd8e81cf", + "capacity_factor_rsdt": "53e46681758c146b82380d26b0fc8eb4f6e95a91c3c2766221e33f895863e1aa", + "capacity_var_rptv": "d839477ae7f5d8fc897e2df4c3c519d742f946b2ce74e1d92fff91e50285296f", + "commodity_all": "01fbdcd2e272aa7c36fbf1400e575188f4501e1957bba1dc2b29cd11ec6a070c", + "commodity_annual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "commodity_balance_constraint_rpsdc": "4a46a0de6ec903639858a35c63fc46223f82ab1e057b20f4a1624eacb6652229", + "commodity_carrier": "3508a787012b20265e9c97acebe2c39d6648b972e7bb4a6d42083e7e167b5c92", "commodity_demand": "6b657255c2baf8b6d4fc96f21cb21263bae7378eb11a9b9cf25a0d8aa83c6aca", "commodity_emissions": "6aa406c61418fb1a0cc0d9f505fafcbf94e65a66cb5c5f1dc0afa8117b762979", - "commodity_physical": "555367a723a957f166d9ec6c580ea46e958bd3a3f684aceee050e26ba2d423c6", - "commodity_waste": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "commodity_flex": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "commodity_source": "44567fa34febd7556a3797bba4949e8d57aa1416fc240258417955809226d723", + "commodity_physical": "555367a723a957f166d9ec6c580ea46e958bd3a3f684aceee050e26ba2d423c6", "commodity_sink": "6b657255c2baf8b6d4fc96f21cb21263bae7378eb11a9b9cf25a0d8aa83c6aca", - "commodity_annual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "commodity_carrier": "3508a787012b20265e9c97acebe2c39d6648b972e7bb4a6d42083e7e167b5c92", - "commodity_all": "01fbdcd2e272aa7c36fbf1400e575188f4501e1957bba1dc2b29cd11ec6a070c", - "time_sequencing": "91f69c8abab9959c1f8c90f5aaa56db29bccc67e37d12673ab41c54e4179d7ca", - "time_manual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "demand_constraint_rpc": "eae7c4920f895c8e036bc95461418eafb9dc9eb1f836755ad16c78b945019623", - "lifetime_process_rtv": "5033502364848a3a3f295f1b3d051531ecd5c1e5f8bbaecd61afcd18181225ab", - "loan_lifetime_process_rtv": "5033502364848a3a3f295f1b3d051531ecd5c1e5f8bbaecd61afcd18181225ab", - "renewable_portfolio_standard_constraint_rpg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "capacity_factor_rsdt": "53e46681758c146b82380d26b0fc8eb4f6e95a91c3c2766221e33f895863e1aa", - "capacity_constraint_rpsdtv": "cd98cf3db577dec19c292199f5b7b8af2dfe336174af315ce2186bbcbd8e81cf", + "commodity_source": "44567fa34febd7556a3797bba4949e8d57aa1416fc240258417955809226d723", + "commodity_waste": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "cost_emission_rpe": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "cost_fixed_rptv": "d839477ae7f5d8fc897e2df4c3c519d742f946b2ce74e1d92fff91e50285296f", "cost_invest_rtv": "46d311691b8fc8d384d75ae29216ecbbd4ecb16253e4d1836e868c5b2f8a6bc5", "cost_variable_rptv": "5501652d0145dbf7c2e8c006aabd3dbb85ca64ed5caf1d8f45a1957274af81ca", - "cost_emission_rpe": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "process_life_frac_rptv": "5501652d0145dbf7c2e8c006aabd3dbb85ca64ed5caf1d8f45a1957274af81ca", - "limit_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_new_capacity_constraint_rtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_resource_constraint_rt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_activity_constraint_rpt": "2561103e7e6dd3dee3ba5832290ab5e933f4af08661dff4f2e661b6f4ffefc86", - "limit_seasonal_capacity_factor_constraint_rst": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_seasonal_capacity_factor_constraint_rpst": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_annual_capacity_factor_constraint_rtvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_emission_constraint_rpe": "6f11e4ee041970584903d5afba7ee1147824b233260422564fdf0c701e9fabde", + "curtailment_var_rpsditvo": "6bdb84e67318e7f5bbaeb28a90ab905caea9f826814f330a3e075c21befbbce7", + "demand_activity_constraint_rpsdtv_dem": "5e98cba1dc8ee89799becaa6a4bb7824d41badf80940f18ddb11724ec883e93d", + "demand_constraint_rpc": "eae7c4920f895c8e036bc95461418eafb9dc9eb1f836755ad16c78b945019623", "emission_activity_reitvo": "a161b5d9619833e599c9201d4da6e0f45df261cfb93b185b5840daee36880443", - "limit_capacity_share_constraint_rpgg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_activity_share_constraint_rpgg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_new_capacity_share_constraint_rggv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "storage_constraints_rpsdtv": "a724916a2cae70bf0de3b0af98d53d017c515cec75692363b541580ead74dc7c", - "seasonal_storage_constraints_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_storage_fraction_param_rsdt": "426fc3cc85aeb1d61ea1e862f82915520e380ee9dbdf81c17423dc881a29791b", - "limit_storage_fraction_constraint_rpsdtv": "13bd0438fa93073d0820deb25c91729fc14bde24f8053cbc42f9412d10f25cd3", - "reserve_margin_method": "7869283c0d14273f720716309207a8f0c24606d03c679d6b68e656ed8d86241d", - "flow_var_rpsditvo": "784d98e451a8dcf0122f475c2e229162d99e403bdea85f7c608a3d86e850db44", - "flow_var_annual_rpitvo": "f98f5f41c5cba8ce2a894734abbc5e90310b695bee3c24c52acd8b4800c5ab85", - "flex_var_rpsditvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "flex_var_annual_rpitvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "curtailment_var_rpsditvo": "6bdb84e67318e7f5bbaeb28a90ab905caea9f826814f330a3e075c21befbbce7", + "flex_var_rpsditvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "flow_in_storage_rpsditvo": "8c97fbeacbca1a772ba04f63d0a82f7703500f83c0dc602114b17c64ad4d2e28", - "storage_level_rpsdtv": "a724916a2cae70bf0de3b0af98d53d017c515cec75692363b541580ead74dc7c", - "storage_init_rpstv": "60214760f620f09278b3aa4b6b510411c1e2c177df5e80838ab97917ca84445d", - "seasonal_storage_level_rpstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "capacity_var_rptv": "d839477ae7f5d8fc897e2df4c3c519d742f946b2ce74e1d92fff91e50285296f", - "new_capacity_var_rtv": "bc0ec9e7f812410cb2af924cbc99a31c6e99cd95fc2de26193daad38f33cc132", - "retired_capacity_var_rptv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "annual_retirement_var_rptv": "ee162bcd5c52c6e713033f89c7ffd0d244e4a34721217cfaf699959b131adcda", - "capacity_available_var_rpt": "8f305de45d0d42708ef17b16602d770ef731810252b0d0b3a89dc396b54b8e8a", - "capacity_annual_constraint_rptv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "demand_activity_constraint_rpsdtv_dem": "5e98cba1dc8ee89799becaa6a4bb7824d41badf80940f18ddb11724ec883e93d", - "commodity_balance_constraint_rpsdc": "4a46a0de6ec903639858a35c63fc46223f82ab1e057b20f4a1624eacb6652229", - "annual_commodity_balance_constraint_rpc": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "baseload_diurnal_constraint_rpsdtv": "20070e9c3c7443e237d3779a8ef33a25ae3a29284f5e1158a257f1a1d80c1421", - "regional_exchange_capacity_constraint_rrptv": "ae0671daa1263140faff22e3d2610c1fbab942d4e814892a50471adfa1bcc740", - "ramp_up_day_constraint_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "ramp_down_day_constraint_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "ramp_up_season_constraint_rpsstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "ramp_down_season_constraint_rpsstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "reserve_margin_rpsd": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_growth_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "flow_var_annual_rpitvo": "f98f5f41c5cba8ce2a894734abbc5e90310b695bee3c24c52acd8b4800c5ab85", + "flow_var_rpsditvo": "784d98e451a8dcf0122f475c2e229162d99e403bdea85f7c608a3d86e850db44", + "lifetime_process_rtv": "5033502364848a3a3f295f1b3d051531ecd5c1e5f8bbaecd61afcd18181225ab", + "limit_activity_constraint_rpt": "2561103e7e6dd3dee3ba5832290ab5e933f4af08661dff4f2e661b6f4ffefc86", + "limit_activity_share_constraint_rpgg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_annual_capacity_factor_constraint_rptvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_annual_capacity_factor_constraint_rtvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_capacity_share_constraint_rpgg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "limit_degrowth_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_growth_new_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "limit_degrowth_new_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_growth_new_capacity_delta_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "limit_degrowth_new_capacity_delta_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_annual_capacity_factor_constraint_rptvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_tech_input_split_constraint_rpsditv": "ccadc066c091a1c0326154aff6b60229c6f1885a8ace32b7957aff39af910682", + "limit_emission_constraint_rpe": "6f11e4ee041970584903d5afba7ee1147824b233260422564fdf0c701e9fabde", + "limit_growth_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_growth_new_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_growth_new_capacity_delta_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_new_capacity_constraint_rtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_new_capacity_share_constraint_rggv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_resource_constraint_rt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_seasonal_capacity_factor_constraint_rpst": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_seasonal_capacity_factor_constraint_rst": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_storage_fraction_constraint_rpsdtv": "13bd0438fa93073d0820deb25c91729fc14bde24f8053cbc42f9412d10f25cd3", + "limit_storage_fraction_param_rsdt": "426fc3cc85aeb1d61ea1e862f82915520e380ee9dbdf81c17423dc881a29791b", "limit_tech_input_split_annual_constraint_rpitv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "limit_tech_input_split_average_constraint_rpitv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_tech_output_split_constraint_rpsdtvo": "115dc2061e98232f0b3b4884fedd68d5bb347dc04db7debf615655ba1e511d35", + "limit_tech_input_split_constraint_rpsditv": "ccadc066c091a1c0326154aff6b60229c6f1885a8ace32b7957aff39af910682", "limit_tech_output_split_annual_constraint_rptvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "limit_tech_output_split_average_constraint_rptvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "linked_emissions_tech_constraint_rpsdtve": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945" -} \ No newline at end of file + "limit_tech_output_split_constraint_rpsdtvo": "115dc2061e98232f0b3b4884fedd68d5bb347dc04db7debf615655ba1e511d35", + "linked_emissions_tech_constraint_rpsdtve": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "loan_lifetime_process_rtv": "5033502364848a3a3f295f1b3d051531ecd5c1e5f8bbaecd61afcd18181225ab", + "new_capacity_var_rtv": "bc0ec9e7f812410cb2af924cbc99a31c6e99cd95fc2de26193daad38f33cc132", + "operator": "74d830836f1399fb336a0432dde7d7bd36cffa3ff76b1c42d7945350cfb9bf91", + "ordered_season_sequential": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "process_life_frac_rptv": "5501652d0145dbf7c2e8c006aabd3dbb85ca64ed5caf1d8f45a1957274af81ca", + "ramp_down_day_constraint_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "ramp_down_season_constraint_rpsstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "ramp_up_day_constraint_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "ramp_up_season_constraint_rpsstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "regional_exchange_capacity_constraint_rrptv": "ae0671daa1263140faff22e3d2610c1fbab942d4e814892a50471adfa1bcc740", + "regional_global_indices": "92fa6c5d5745d765d6e16ad1bca7e1fc72f4377273be7cfbfde626ca1967d81b", + "regional_indices": "f74187f92c4fdb3c12d5610304c7ac9696001433150bdaa9ff20793fb6365b32", + "regions": "0ddd05d695b255ac719dfa85de1e900a3036d547ffc7261c9c9ca2c81bfda029", + "renewable_portfolio_standard_constraint_rpg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "reserve_margin_method": "7869283c0d14273f720716309207a8f0c24606d03c679d6b68e656ed8d86241d", + "reserve_margin_rpsd": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "retired_capacity_var_rptv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "seasonal_storage_constraints_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "seasonal_storage_level_rpstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "storage_constraints_rpsdtv": "a724916a2cae70bf0de3b0af98d53d017c515cec75692363b541580ead74dc7c", + "storage_init_rpstv": "60214760f620f09278b3aa4b6b510411c1e2c177df5e80838ab97917ca84445d", + "storage_level_rpsdtv": "a724916a2cae70bf0de3b0af98d53d017c515cec75692363b541580ead74dc7c", + "tech_all": "85a3645929dbeaf6b7eb17e8085c8923ef86949eaa3fb4fd81724dcdcf38fd30", + "tech_annual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_baseload": "050aff703818154bf3439ed7d4a2cfef892be61da0c477526001c8c38b41a935", + "tech_curtailment": "81683c0099a4eb22c8cca4b8eaf65a5bbf77c24b559cd1219823e6d6eb6cf915", + "tech_demand": "cf8d1075bb0667935fc3834c5266e775d1c746692179ef253809eaaa7abab6f8", + "tech_downramping": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_exchange": "6610eb4a0360be009669b5d50a2c3e1447bcf39eb820a0e63fd3718c27fae768", + "tech_exist": "eefd900ce35331470ba9f3312de6f03883efb5f402d321ff714cfe22d9ecdf94", + "tech_flex": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_group_members": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_group_names": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_or_group": "85a3645929dbeaf6b7eb17e8085c8923ef86949eaa3fb4fd81724dcdcf38fd30", + "tech_production": "85a3645929dbeaf6b7eb17e8085c8923ef86949eaa3fb4fd81724dcdcf38fd30", + "tech_reserve": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_retirement": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_seasonal_storage": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_storage": "7109b89425e6707adc8a5e571bf70fc64475d2d76471e5afe93110fd86bbcec8", + "tech_uncap": "50b9da0bce0fcc3b318930929a2191c6c6c5e535e9ee986ca2ee740c7ff789bc", + "tech_upramping": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_with_capacity": "bf3db0293ae9b3ec605ba8260a111eb71cbf3a786077a8172142a4e90ca1141b", + "time_exist": "5206b4814992da4c7a4f643fdf04124735accc989ec0047874eb80e8541766c9", + "time_future": "2739be4c64d75aa5fb1552392c1f9d5587f15dba7a728f1768e415c0792b044e", + "time_manual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "time_of_day": "9f58a9fbc74271e641f4b7624b22daca061195a3d85b58d270fb8590937007b1", + "time_optimize": "376da8132a26c5ebebc6d27395c2c883261928ac8d91004c167843c1e21d6141", + "time_season": "6d8e2fd49929c1f5216c0313307108c4993e58b00207210d3b6390d3f64e2896", + "time_season_sequential": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "time_sequencing": "91f69c8abab9959c1f8c90f5aaa56db29bccc67e37d12673ab41c54e4179d7ca", + "vintage_all": "a19045d7d5b67af65f00af8d62f398968fea2c2d418f182b5d3ad0a56415eddf", + "vintage_exist": "5206b4814992da4c7a4f643fdf04124735accc989ec0047874eb80e8541766c9", + "vintage_optimize": "376da8132a26c5ebebc6d27395c2c883261928ac8d91004c167843c1e21d6141" +} diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 74631b93d..628c177da 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -1,115 +1,115 @@ { - "operator": "74d830836f1399fb336a0432dde7d7bd36cffa3ff76b1c42d7945350cfb9bf91", - "time_exist": "c9529ee6b8874a867c196738619704c725ba6fbf61a03b9739090422b8904de2", - "time_future": "8c9cb7410e2199a84d1b5607c46429f0c6bc67a2b9e322a48434d83a2e81e007", - "time_optimize": "b36c1cbd59292ec15b8ff1504ec03c5657665e2b3350e224dfd31364cb393ffa", - "vintage_exist": "c9529ee6b8874a867c196738619704c725ba6fbf61a03b9739090422b8904de2", - "vintage_optimize": "b36c1cbd59292ec15b8ff1504ec03c5657665e2b3350e224dfd31364cb393ffa", - "vintage_all": "b96a0eef5579c688203bc71c6700b5a74d6d9306ee443980e67beef17ac4e8f0", - "time_season": "df37d485468915bce6cd7fa627702773c5d6c3dee47cffdc6360d31dd1dd28eb", - "time_season_sequential": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "time_of_day": "9f58a9fbc74271e641f4b7624b22daca061195a3d85b58d270fb8590937007b1", - "ordered_season_sequential": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "regions": "ce00905893c23bc59c15dcf61d7e261c2e97ab1fc298ed0e0ccb1344f1cace37", - "regional_indices": "ce00905893c23bc59c15dcf61d7e261c2e97ab1fc298ed0e0ccb1344f1cace37", - "regional_global_indices": "ce00905893c23bc59c15dcf61d7e261c2e97ab1fc298ed0e0ccb1344f1cace37", - "tech_production": "5c321f60e5d16e60c5063b83d59ac9e184ab78e7fc469e41b21fd8aea83f600c", - "tech_all": "5c321f60e5d16e60c5063b83d59ac9e184ab78e7fc469e41b21fd8aea83f600c", - "tech_baseload": "e7c3d5843adeb51ccb0774118e8e5085f4a01c787a32b5ed34cba220efd9121a", - "tech_annual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "tech_demand": "481b9363bcd61f44255efcc7bb7cc4112bef3c969435024dd5e2659e3c8dbfdb", - "tech_storage": "245737c06f3e838e63da08a47a7d2a8605340ea5cad86397e1bb66461a574358", - "tech_reserve": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "tech_upramping": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "tech_downramping": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "tech_curtailment": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "tech_flex": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "tech_exchange": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "tech_group_names": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "tech_group_members": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "tech_or_group": "5c321f60e5d16e60c5063b83d59ac9e184ab78e7fc469e41b21fd8aea83f600c", - "tech_seasonal_storage": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "tech_uncap": "b2c8c3f94a51bb7ab55ad7b534cb7aba64a506678c109abb4141f4d2e84bf431", - "tech_exist": "b7d598371119e425be7beedbdde0525c88b7aa0018887e81d2cccc6bb0385ffa", - "tech_with_capacity": "459b04924b80d93e0061564b6c1f1b8d39543d697b81150413d7bc86c3003e33", - "tech_retirement": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "annual_commodity_balance_constraint_rpc": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "annual_retirement_var_rptv": "e2487c314e1404726bdfbc8ba061d507f18882c658e81ea27c4369f0d4a892fd", + "baseload_diurnal_constraint_rpsdtv": "da0dafcd9aef41d231282c85362d767636d8ba3815ea809e0b7eeb326233fbf9", + "capacity_annual_constraint_rptv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "capacity_available_var_rpt": "96e94bf0459e843802e1ea858c807be22b09354409fbd93a6b1a91d4438a7727", + "capacity_constraint_rpsdtv": "67324b45087c277b42b4664f23c93bd75820eb6a0ed7298afe6b185165b97a25", + "capacity_factor_rsdt": "1e5fae1e3999dbea84cc6d39e3ad91e95a2064c96f3569ea2dfef041d6011c5a", + "capacity_var_rptv": "972a1a82e59135297f51ef6ca2ce5760a8e0fcb67e064b270b14cbf5e4661831", + "commodity_all": "25fb43b483a85d6e4b4d8251a272a4c78fb9d02a65af63a9c044d64211661563", + "commodity_annual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "commodity_balance_constraint_rpsdc": "79a5589e5d9b834ff2132fd4ce354a16e3a17529415245da9b9d8b13814ad382", + "commodity_carrier": "23deb826164f35ff8adf73b9c64a4edb3efeeb51b683e14ea40f0771eba42eb8", "commodity_demand": "8d35b293b5cef0a6d0c6552029082eaec587db0bc5813783f24ab1aafe7491c8", "commodity_emissions": "cc2dd294fd87cfc0324fcd1d62eb647ff83bd89d7b5abd5dd5374debea96d91b", - "commodity_physical": "3aab3aa4622d1545fe0f3cb8bd1a01fb9918632cff7186cfd49fa8575b73b2f3", - "commodity_waste": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "commodity_flex": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "commodity_source": "9679c6d5ef1c2949d7c4b6685ba2fd4195282539b3f24650247f40be62eecf3a", + "commodity_physical": "3aab3aa4622d1545fe0f3cb8bd1a01fb9918632cff7186cfd49fa8575b73b2f3", "commodity_sink": "8d35b293b5cef0a6d0c6552029082eaec587db0bc5813783f24ab1aafe7491c8", - "commodity_annual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "commodity_carrier": "23deb826164f35ff8adf73b9c64a4edb3efeeb51b683e14ea40f0771eba42eb8", - "commodity_all": "25fb43b483a85d6e4b4d8251a272a4c78fb9d02a65af63a9c044d64211661563", - "time_sequencing": "91f69c8abab9959c1f8c90f5aaa56db29bccc67e37d12673ab41c54e4179d7ca", - "time_manual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "demand_constraint_rpc": "c1654f787e15af2031bcea2dcebde3830df52ea0f798e854ba784e6f1223b301", - "lifetime_process_rtv": "2cfc288b15f25957dfc70f6396d97ad655ecbed91c5a11582329749f1fb3dbd7", - "loan_lifetime_process_rtv": "2cfc288b15f25957dfc70f6396d97ad655ecbed91c5a11582329749f1fb3dbd7", - "renewable_portfolio_standard_constraint_rpg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "capacity_factor_rsdt": "1e5fae1e3999dbea84cc6d39e3ad91e95a2064c96f3569ea2dfef041d6011c5a", - "capacity_constraint_rpsdtv": "67324b45087c277b42b4664f23c93bd75820eb6a0ed7298afe6b185165b97a25", + "commodity_source": "9679c6d5ef1c2949d7c4b6685ba2fd4195282539b3f24650247f40be62eecf3a", + "commodity_waste": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "cost_emission_rpe": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "cost_fixed_rptv": "972a1a82e59135297f51ef6ca2ce5760a8e0fcb67e064b270b14cbf5e4661831", "cost_invest_rtv": "651a10edbb8297f51b380318385c9f1ae824a73216318e1c9aea78fc9f371a14", "cost_variable_rptv": "37ad263f78986f4d38c63278a0d1a5a85b3eb8b833e8bfabbbea254eaf3a3efb", - "cost_emission_rpe": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "process_life_frac_rptv": "37ad263f78986f4d38c63278a0d1a5a85b3eb8b833e8bfabbbea254eaf3a3efb", - "limit_capacity_constraint_rpt": "5a43de033187da68c612c5bcef6a76edb6ab9806464b6d865e46d289ccbbd815", - "limit_new_capacity_constraint_rtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_resource_constraint_rt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_activity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_seasonal_capacity_factor_constraint_rst": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_seasonal_capacity_factor_constraint_rpst": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_annual_capacity_factor_constraint_rtvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_emission_constraint_rpe": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "curtailment_var_rpsditvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "demand_activity_constraint_rpsdtv_dem": "264109f8bf88d194fdfe03d2e18654ffe0ba11bdf8430c50b39c03bdc43a53e1", + "demand_constraint_rpc": "c1654f787e15af2031bcea2dcebde3830df52ea0f798e854ba784e6f1223b301", "emission_activity_reitvo": "8b4c8f2cf9b46db814898d140f48dc75e50c34bcf71a55adee31afa67cea1eba", - "limit_capacity_share_constraint_rpgg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_activity_share_constraint_rpgg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_new_capacity_share_constraint_rggv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "storage_constraints_rpsdtv": "fe4c04240f67fbe31572a29c9c1d3bef9dfb10c1090d311797530deeae8393e9", - "seasonal_storage_constraints_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_storage_fraction_param_rsdt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_storage_fraction_constraint_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "reserve_margin_method": "7869283c0d14273f720716309207a8f0c24606d03c679d6b68e656ed8d86241d", - "flow_var_rpsditvo": "350739a59b14969da094cf1c95524134b9c9acd0989710456a8dcc6596d0a401", - "flow_var_annual_rpitvo": "4053866a304af0a6b9a1d293ddaf358dfee5b170dcb01d41e6bc52437908a98a", - "flex_var_rpsditvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "flex_var_annual_rpitvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "curtailment_var_rpsditvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "flex_var_rpsditvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "flow_in_storage_rpsditvo": "99eb864a26adcb6633c95462649bca3ef7096f67682702915d7769b54b5de386", - "storage_level_rpsdtv": "fe4c04240f67fbe31572a29c9c1d3bef9dfb10c1090d311797530deeae8393e9", - "storage_init_rpstv": "86f4e3cf182540836f499c369cbac966e81c807d55a4f70d9b7a1473276c07b4", - "seasonal_storage_level_rpstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "capacity_var_rptv": "972a1a82e59135297f51ef6ca2ce5760a8e0fcb67e064b270b14cbf5e4661831", - "new_capacity_var_rtv": "d4f1cc8b432075001befddab648d54d1f82a29099236948845393a193b6add5b", - "retired_capacity_var_rptv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "annual_retirement_var_rptv": "e2487c314e1404726bdfbc8ba061d507f18882c658e81ea27c4369f0d4a892fd", - "capacity_available_var_rpt": "96e94bf0459e843802e1ea858c807be22b09354409fbd93a6b1a91d4438a7727", - "capacity_annual_constraint_rptv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "demand_activity_constraint_rpsdtv_dem": "264109f8bf88d194fdfe03d2e18654ffe0ba11bdf8430c50b39c03bdc43a53e1", - "commodity_balance_constraint_rpsdc": "79a5589e5d9b834ff2132fd4ce354a16e3a17529415245da9b9d8b13814ad382", - "annual_commodity_balance_constraint_rpc": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "baseload_diurnal_constraint_rpsdtv": "da0dafcd9aef41d231282c85362d767636d8ba3815ea809e0b7eeb326233fbf9", - "regional_exchange_capacity_constraint_rrptv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "ramp_up_day_constraint_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "ramp_down_day_constraint_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "ramp_up_season_constraint_rpsstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "ramp_down_season_constraint_rpsstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "reserve_margin_rpsd": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_growth_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "flow_var_annual_rpitvo": "4053866a304af0a6b9a1d293ddaf358dfee5b170dcb01d41e6bc52437908a98a", + "flow_var_rpsditvo": "350739a59b14969da094cf1c95524134b9c9acd0989710456a8dcc6596d0a401", + "lifetime_process_rtv": "2cfc288b15f25957dfc70f6396d97ad655ecbed91c5a11582329749f1fb3dbd7", + "limit_activity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_activity_share_constraint_rpgg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_annual_capacity_factor_constraint_rptvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_annual_capacity_factor_constraint_rtvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_capacity_constraint_rpt": "5a43de033187da68c612c5bcef6a76edb6ab9806464b6d865e46d289ccbbd815", + "limit_capacity_share_constraint_rpgg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "limit_degrowth_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_growth_new_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "limit_degrowth_new_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_growth_new_capacity_delta_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "limit_degrowth_new_capacity_delta_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_annual_capacity_factor_constraint_rptvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_tech_input_split_constraint_rpsditv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_emission_constraint_rpe": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_growth_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_growth_new_capacity_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_growth_new_capacity_delta_constraint_rpt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_new_capacity_constraint_rtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_new_capacity_share_constraint_rggv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_resource_constraint_rt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_seasonal_capacity_factor_constraint_rpst": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_seasonal_capacity_factor_constraint_rst": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_storage_fraction_constraint_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "limit_storage_fraction_param_rsdt": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "limit_tech_input_split_annual_constraint_rpitv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "limit_tech_input_split_average_constraint_rpitv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "limit_tech_output_split_constraint_rpsdtvo": "f8e7d420020c7bc28dc29fb313fae2027f40143e43bc8c39347060d4e63a087d", + "limit_tech_input_split_constraint_rpsditv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "limit_tech_output_split_annual_constraint_rptvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "limit_tech_output_split_average_constraint_rptvo": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", - "linked_emissions_tech_constraint_rpsdtve": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945" -} \ No newline at end of file + "limit_tech_output_split_constraint_rpsdtvo": "f8e7d420020c7bc28dc29fb313fae2027f40143e43bc8c39347060d4e63a087d", + "linked_emissions_tech_constraint_rpsdtve": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "loan_lifetime_process_rtv": "2cfc288b15f25957dfc70f6396d97ad655ecbed91c5a11582329749f1fb3dbd7", + "new_capacity_var_rtv": "d4f1cc8b432075001befddab648d54d1f82a29099236948845393a193b6add5b", + "operator": "74d830836f1399fb336a0432dde7d7bd36cffa3ff76b1c42d7945350cfb9bf91", + "ordered_season_sequential": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "process_life_frac_rptv": "37ad263f78986f4d38c63278a0d1a5a85b3eb8b833e8bfabbbea254eaf3a3efb", + "ramp_down_day_constraint_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "ramp_down_season_constraint_rpsstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "ramp_up_day_constraint_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "ramp_up_season_constraint_rpsstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "regional_exchange_capacity_constraint_rrptv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "regional_global_indices": "ce00905893c23bc59c15dcf61d7e261c2e97ab1fc298ed0e0ccb1344f1cace37", + "regional_indices": "ce00905893c23bc59c15dcf61d7e261c2e97ab1fc298ed0e0ccb1344f1cace37", + "regions": "ce00905893c23bc59c15dcf61d7e261c2e97ab1fc298ed0e0ccb1344f1cace37", + "renewable_portfolio_standard_constraint_rpg": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "reserve_margin_method": "7869283c0d14273f720716309207a8f0c24606d03c679d6b68e656ed8d86241d", + "reserve_margin_rpsd": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "retired_capacity_var_rptv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "seasonal_storage_constraints_rpsdtv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "seasonal_storage_level_rpstv": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "storage_constraints_rpsdtv": "fe4c04240f67fbe31572a29c9c1d3bef9dfb10c1090d311797530deeae8393e9", + "storage_init_rpstv": "86f4e3cf182540836f499c369cbac966e81c807d55a4f70d9b7a1473276c07b4", + "storage_level_rpsdtv": "fe4c04240f67fbe31572a29c9c1d3bef9dfb10c1090d311797530deeae8393e9", + "tech_all": "5c321f60e5d16e60c5063b83d59ac9e184ab78e7fc469e41b21fd8aea83f600c", + "tech_annual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_baseload": "e7c3d5843adeb51ccb0774118e8e5085f4a01c787a32b5ed34cba220efd9121a", + "tech_curtailment": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_demand": "481b9363bcd61f44255efcc7bb7cc4112bef3c969435024dd5e2659e3c8dbfdb", + "tech_downramping": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_exchange": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_exist": "b7d598371119e425be7beedbdde0525c88b7aa0018887e81d2cccc6bb0385ffa", + "tech_flex": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_group_members": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_group_names": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_or_group": "5c321f60e5d16e60c5063b83d59ac9e184ab78e7fc469e41b21fd8aea83f600c", + "tech_production": "5c321f60e5d16e60c5063b83d59ac9e184ab78e7fc469e41b21fd8aea83f600c", + "tech_reserve": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_retirement": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_seasonal_storage": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_storage": "245737c06f3e838e63da08a47a7d2a8605340ea5cad86397e1bb66461a574358", + "tech_uncap": "b2c8c3f94a51bb7ab55ad7b534cb7aba64a506678c109abb4141f4d2e84bf431", + "tech_upramping": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "tech_with_capacity": "459b04924b80d93e0061564b6c1f1b8d39543d697b81150413d7bc86c3003e33", + "time_exist": "c9529ee6b8874a867c196738619704c725ba6fbf61a03b9739090422b8904de2", + "time_future": "8c9cb7410e2199a84d1b5607c46429f0c6bc67a2b9e322a48434d83a2e81e007", + "time_manual": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "time_of_day": "9f58a9fbc74271e641f4b7624b22daca061195a3d85b58d270fb8590937007b1", + "time_optimize": "b36c1cbd59292ec15b8ff1504ec03c5657665e2b3350e224dfd31364cb393ffa", + "time_season": "df37d485468915bce6cd7fa627702773c5d6c3dee47cffdc6360d31dd1dd28eb", + "time_season_sequential": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "time_sequencing": "91f69c8abab9959c1f8c90f5aaa56db29bccc67e37d12673ab41c54e4179d7ca", + "vintage_all": "b96a0eef5579c688203bc71c6700b5a74d6d9306ee443980e67beef17ac4e8f0", + "vintage_exist": "c9529ee6b8874a867c196738619704c725ba6fbf61a03b9739090422b8904de2", + "vintage_optimize": "b36c1cbd59292ec15b8ff1504ec03c5657665e2b3350e224dfd31364cb393ffa" +} diff --git a/tests/utilities/capture_set_values_for_cache.py b/tests/utilities/capture_set_values_for_cache.py index 86d0c7bf5..f0ca2d218 100644 --- a/tests/utilities/capture_set_values_for_cache.py +++ b/tests/utilities/capture_set_values_for_cache.py @@ -4,11 +4,8 @@ This file should not need to be run again unless model schema changes """ -import hashlib import json -import sys from pathlib import Path -from typing import Any import pyomo.environ as pyo @@ -16,20 +13,7 @@ from temoa.core.config import TemoaConfig from temoa.core.modes import TemoaMode from tests.conftest import refresh_databases - -print( - 'WARNING: Continuing to execute this file will ' - 'update the cached values in the testing_data folder' - 'from the sqlite databases in the same folder. ' - 'This should only need to be done if the schema or ' - 'model have changed and that database has been updated.' - '\nRunning this basically resets the expected value sets' - 'for Utopia, TestSystem, and Mediumville' -) - -t = 'Y' # automated run -if t not in {'y', 'Y'}: - sys.exit(0) +from tests.utilities.hash_utils import hash_set output_path = Path(__file__).parent.parent / 'testing_log' # capture the log here output_path.mkdir(parents=True, exist_ok=True) @@ -59,14 +43,6 @@ built_instance = ts.build_model() # catch the built model - def hash_set(s: Any) -> str: - try: - sorted_elements = sorted(s) - except TypeError: - sorted_elements = sorted([str(e) for e in s]) - s_bytes = json.dumps(sorted_elements).encode('utf-8') - return hashlib.sha256(s_bytes).hexdigest() - model_sets = built_instance.component_map(ctype=pyo.Set) sets_dict = { k: hash_set(v) for k, v in model_sets.items() if '_index' not in k and '_domain' not in k @@ -74,4 +50,4 @@ def hash_set(s: Any) -> str: # stash the result in a json file... with open(scenario['output_file'], 'w') as f_out: - json.dump(sets_dict, f_out, indent=2) + json.dump(sets_dict, f_out, indent=2, sort_keys=True) diff --git a/tests/utilities/hash_utils.py b/tests/utilities/hash_utils.py new file mode 100644 index 000000000..008aa7378 --- /dev/null +++ b/tests/utilities/hash_utils.py @@ -0,0 +1,16 @@ +import hashlib +import json +from typing import Any + + +def hash_set(s: Any) -> str: + """ + Produce a stable SHA256 hash for a pyomo set or any iterable. + """ + try: + sorted_elements = sorted(s) + except TypeError: + # elements are of mixed types, fallback to canonicalized typed pairs + sorted_elements = sorted([(type(e).__name__, str(e)) for e in s]) + s_bytes = json.dumps(sorted_elements, ensure_ascii=False).encode('utf-8') + return hashlib.sha256(s_bytes).hexdigest() From ca4afccf9c7bc0f774cba8d737789f219128b8b9 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Mon, 12 Jan 2026 13:07:21 -0500 Subject: [PATCH 507/587] typing: adding types to extensions outside of breakeven --- pyproject.toml | 2 +- temoa/extensions/get_comm_tech.py | 49 +++--- temoa/extensions/method_of_morris/morris.py | 64 ++++---- .../method_of_morris/morris_evaluate.py | 35 ++--- .../method_of_morris/morris_sequencer.py | 49 +++--- .../modeling_to_generate_alternatives/hull.py | 37 +++-- .../manager_factory.py | 18 ++- .../mga_sequencer.py | 89 +++++++---- .../tech_activity_vector_manager.py | 141 +++++++++++------- .../vector_manager.py | 21 ++- .../worker.py | 53 ++++--- .../example_builds/scenario_analyzer.py | 7 +- .../example_builds/scenario_maker.py | 4 +- temoa/extensions/monte_carlo/mc_run.py | 83 +++++++---- temoa/extensions/monte_carlo/mc_sequencer.py | 74 +++++---- temoa/extensions/monte_carlo/mc_worker.py | 65 ++++---- temoa/extensions/myopic/evolution_updater.py | 1 + temoa/extensions/myopic/myopic_index.py | 2 +- .../myopic/myopic_progress_mapper.py | 6 +- temoa/extensions/myopic/myopic_sequencer.py | 99 ++++++++---- .../single_vector_mga/output_summary.py | 68 +++++---- .../single_vector_mga/sv_mga_sequencer.py | 28 ++-- .../stochastics/scenario_creator.py | 17 ++- .../stochastics/stochastic_config.py | 10 +- .../stochastics/stochastic_sequencer.py | 10 +- 25 files changed, 636 insertions(+), 396 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 2810d00dd..55ac79c81 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -144,7 +144,7 @@ python_version = "3.12" mypy_path = "stubs" # Exclude specific directories from type checking will try to add them back gradually -exclude = "(?x)(^temoa/extensions/|^temoa/utilities/|^stubs/)" +exclude = "(?x)(^temoa/utilities/|^stubs/)" # Strict typing for our own code disallow_untyped_defs = true diff --git a/temoa/extensions/get_comm_tech.py b/temoa/extensions/get_comm_tech.py index 57e370ee9..38cdd9468 100644 --- a/temoa/extensions/get_comm_tech.py +++ b/temoa/extensions/get_comm_tech.py @@ -1,22 +1,24 @@ +from __future__ import annotations + import getopt import os import re import sqlite3 import sys from collections import OrderedDict +from typing import Any -def get_tperiods(inp_f): +def get_tperiods(inp_f: str) -> dict[str, list[int]]: file_ty = re.search(r'(\w+)\.(\w+)\b', inp_f) # Extract the input filename and extension if not file_ty: - raise 'The file type %s is not recognized.' % inp_f + raise Exception(f'The file type {inp_f} is not recognized.') elif file_ty.group(2) not in ('db', 'sqlite', 'sqlite3', 'sqlitedb'): raise Exception('Please specify a database for finding scenarios') - periods_list = {} - periods_set = set() + periods_list: dict[str, list[int]] = {} con = sqlite3.connect(inp_f) cur = con.cursor() # a database cursor is a control structure that enables traversal over @@ -30,7 +32,7 @@ def get_tperiods(inp_f): x.append(row[0]) for y in x: cur.execute( - "SELECT DISTINCT period FROM output_flow_out WHERE scenario is '" + str(y) + "'" + f"SELECT DISTINCT period FROM output_flow_out WHERE scenario is '{y}'" ) periods_list[y] = [] for per in cur: @@ -42,17 +44,16 @@ def get_tperiods(inp_f): return dict(OrderedDict(sorted(periods_list.items(), key=lambda x: x[1]))) -def get_scenario(inp_f): +def get_scenario(inp_f: str) -> dict[str, str]: file_ty = re.search(r'(\w+)\.(\w+)\b', inp_f) # Extract the input filename and extension if not file_ty: - raise 'The file type %s is not recognized.' % inp_f + raise Exception(f'The file type {inp_f} is not recognized.') elif file_ty.group(2) not in ('db', 'sqlite', 'sqlite3', 'sqlitedb'): raise Exception('Please specify a database for finding scenarios') - scene_list = {} - scene_set = set() + scene_list: dict[str, str] = {} con = sqlite3.connect(inp_f) cur = con.cursor() # a database cursor is a control structure that enables traversal over @@ -70,9 +71,9 @@ def get_scenario(inp_f): return dict(OrderedDict(sorted(scene_list.items(), key=lambda x: x[1]))) -def get_comm(inp_f, db_dat): - comm_list = {} - comm_set = set() +def get_comm(inp_f: str, db_dat: bool) -> OrderedDict[str, str]: + comm_list: dict[str, str] = {} + comm_set: set[str] = set() is_query_empty = False if not db_dat: @@ -138,9 +139,9 @@ def get_comm(inp_f, db_dat): return OrderedDict(sorted(comm_list.items(), key=lambda x: x[1])) -def get_tech(inp_f, db_dat): - tech_list = {} - tech_set = set() +def get_tech(inp_f: str, db_dat: bool) -> OrderedDict[str, str]: + tech_list: dict[str, str] = {} + tech_set: set[str] = set() is_query_empty = False if not db_dat: @@ -199,13 +200,13 @@ def get_tech(inp_f, db_dat): return OrderedDict(sorted(tech_list.items(), key=lambda x: x[1])) -def is_db_overwritten(db_file, inp_dat_file): +def is_db_overwritten(db_file: str, inp_dat_file: str) -> bool: if os.path.basename(db_file) == '0': return False try: con = sqlite3.connect(db_file) - except: + except Exception: return False cur = con.cursor() # A database cursor enables traversal over DB records con.text_factory = str # This ensures data is explored with UTF-8 encoding @@ -214,7 +215,7 @@ def is_db_overwritten(db_file, inp_dat_file): # IF output file is empty database. cur.execute('SELECT * FROM Technology') is_db_empty = False # False for empty db file - for elem in cur: + for _ in cur: is_db_empty = True # True for non-empty db file break # This file could be schema with populated results from previous run. Or it could be a normal @@ -222,7 +223,7 @@ def is_db_overwritten(db_file, inp_dat_file): if is_db_empty: cur.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='input_file';") does_input_file_table_exist = False - for i in cur: # This means that the 'input_file' table exists in db. + for _ in cur: # This means that the 'input_file' table exists in db. does_input_file_table_exist = True if does_input_file_table_exist: # This block distinguishes normal database from schema. # This is schema file. @@ -247,7 +248,7 @@ def is_db_overwritten(db_file, inp_dat_file): return False -def help_user(): +def help_user() -> None: print( """Use as: python get_comm_tech.py -i (or --input) @@ -259,8 +260,8 @@ def help_user(): ) -def get_info(inputs): - inp_file = None +def get_info(inputs: dict[str, str]) -> Any: + inp_file: str | None = None tech_flag = False comm_flag = False scene = False @@ -317,8 +318,8 @@ def get_info(inputs): else: print( - 'The input file type %s is not recognized. Please specify a database or a text file.' - % inp_file + f'The input file type {inp_file} is not recognized. Please specify a database ' + 'or a text file.' ) sys.exit(2) diff --git a/temoa/extensions/method_of_morris/morris.py b/temoa/extensions/method_of_morris/morris.py index 51318c976..3d9f8b251 100644 --- a/temoa/extensions/method_of_morris/morris.py +++ b/temoa/extensions/method_of_morris/morris.py @@ -1,28 +1,28 @@ -# from __future__ import division -import time +from __future__ import annotations + +import csv +import sqlite3 from importlib import resources from pathlib import Path +from typing import Any +from joblib import Parallel, delayed # type: ignore[import-untyped] +from numpy import array from pyomo.dataportal import DataPortal +from SALib.analyze import morris # type: ignore[import-untyped] +from SALib.sample.morris import sample # type: ignore[import-untyped] +from SALib.util import compute_groups_matrix, read_param_file # type: ignore[import-untyped] from temoa._internal import run_actions from temoa._internal.table_writer import TableWriter from temoa.core.config import TemoaConfig from temoa.data_io.hybrid_loader import HybridLoader -start_time = time.time() -import sqlite3 - -from joblib import Parallel, delayed -from numpy import array -from SALib.analyze import morris -from SALib.sample.morris import sample -from SALib.util import compute_groups_matrix, read_param_file - seed = 42 -def evaluate(param_names, param_values, data: dict, k): +def evaluate(param_names: dict[int, list[Any]], param_values: Any, + data: dict[str, Any], k: int) -> list[Any]: m = len(param_values) for j in range(0, m): names = param_names[j] @@ -51,16 +51,16 @@ def evaluate(param_names, param_values, data: dict, k): cur.execute('SELECT * FROM output_objective') output_query = cur.fetchall() for row in output_query: - Y_OF = row[-1] + y_of = row[-1] cur.execute("SELECT emis_comm, SUM(emission) FROM output_emissionn WHERE emis_comm='co2'") output_query = cur.fetchall() for row in output_query: - Y_CumulativeCO2 = row[-1] - Morris_Objectives = [] - Morris_Objectives.append(Y_OF) - Morris_Objectives.append(Y_CumulativeCO2) + y_cumulative_co2 = row[-1] + morris_objectives = [] + morris_objectives.append(y_of) + morris_objectives.append(y_cumulative_co2) con.close() - return Morris_Objectives + return morris_objectives morris_root = Path(__file__).parent @@ -137,7 +137,7 @@ def evaluate(param_names, param_values, data: dict, k): file.write('\n') # load a data portal, retrieve the data dict for the problem - config = TemoaConfig.build_config(config_file=config_path, output_path='.') + config = TemoaConfig.build_config(config_file=config_path, output_path=Path('.')) loader = HybridLoader(db_connection=con, config=config) loader.load_data_portal() data = loader.data @@ -157,7 +157,7 @@ def evaluate(param_names, param_values, data: dict, k): ) Morris_Objectives = array(Morris_Objectives) print(Morris_Objectives) -Si_OF = morris.analyze( +si_of = morris.analyze( problem, param_values, Morris_Objectives[:, 0], @@ -168,7 +168,7 @@ def evaluate(param_names, param_values, data: dict, k): seed=seed + 1, ) -Si_CumulativeCO2 = morris.analyze( +si_cumulative_co2 = morris.analyze( problem, param_values, Morris_Objectives[:, 1], @@ -189,19 +189,18 @@ def evaluate(param_names, param_values, data: dict, k): for j in list(range(number_of_groups)): print( '{:30} {:10.3f} {:10.3f} {:15.3f} {:10.3f}'.format( - Si_OF['names'][j], - Si_OF['mu_star'][j], - Si_OF['mu'][j], - Si_OF['mu_star_conf'][j], - Si_OF['sigma'][j], + si_of['names'][j], + si_of['mu_star'][j], + si_of['mu'][j], + si_of['mu_star_conf'][j], + si_of['sigma'][j], ) ) -import csv -line1 = Si_OF['mu_star'] -line2 = Si_OF['mu_star_conf'] -line3 = Si_CumulativeCO2['mu_star'] -line4 = Si_CumulativeCO2['mu_star_conf'] +line1 = si_of['mu_star'] +line2 = si_of['mu_star_conf'] +line3 = si_cumulative_co2['mu_star'] +line4 = si_cumulative_co2['mu_star_conf'] with open('MMResults.csv', 'w') as f: writer = csv.writer(f, delimiter=',') writer.writerow(unique_group_names) @@ -211,6 +210,3 @@ def evaluate(param_names, param_values, data: dict, k): writer.writerow('Cumulative CO2 Emissions') writer.writerow(line3) writer.writerow(line4) - -f.close -print('--- %s seconds ---' % (time.time() - start_time)) diff --git a/temoa/extensions/method_of_morris/morris_evaluate.py b/temoa/extensions/method_of_morris/morris_evaluate.py index 89a96271e..de8360c4e 100644 --- a/temoa/extensions/method_of_morris/morris_evaluate.py +++ b/temoa/extensions/method_of_morris/morris_evaluate.py @@ -2,20 +2,25 @@ This module contains the core "evaluation" function for Method Of Morris. It needs to be isolated (outside of class) to enable parallelization. """ +from __future__ import annotations import logging import sqlite3 import sys from logging.handlers import QueueHandler +from typing import TYPE_CHECKING, Any from pyomo.dataportal import DataPortal from temoa._internal import run_actions from temoa._internal.table_writer import TableWriter -from temoa.core.config import TemoaConfig +if TYPE_CHECKING: + from temoa.core.config import TemoaConfig -def configure_worker_logger(log_queue, log_level): + + +def configure_worker_logger(log_queue: Any, log_level: int) -> logging.Logger: """configure the logger""" worker_logger = logging.getLogger('MM evaluate') if not worker_logger.hasHandlers(): @@ -30,7 +35,8 @@ def configure_worker_logger(log_queue, log_level): return worker_logger -def evaluate(param_info, mm_sample, data, i, config: TemoaConfig, log_queue, log_level): +def evaluate(param_info: dict[int, list[Any]], mm_sample: Any, data: dict[str, Any], + i: int, config: TemoaConfig, log_queue: Any, log_level: int) -> list[float]: """ Run model for params provided and return objective value and emission value Note: This function needs to be a static instance to enable the parallel @@ -49,19 +55,14 @@ def evaluate(param_info, mm_sample, data, i, config: TemoaConfig, log_queue, log log_entry = [''] for j in range(0, len(mm_sample)): param_name, *set_idx, _ = param_info[j] - set_idx = tuple(set_idx) + set_idx_tuple = tuple(set_idx) # tweak the parameter if data.get(param_name) is None: raise ValueError(f'Unrecognized parameter: {param_name}') - if data[param_name].get(set_idx) is None: + if data[param_name].get(set_idx_tuple) is None: raise ValueError('index mismatch from data read-in') - data[param_name][set_idx] = mm_sample[j] - setting_entry = 'run # %d: Setting param %s[%s] to value: %f' % ( - i + 1, - param_name, - set_idx, - mm_sample[j], - ) + data[param_name][set_idx_tuple] = mm_sample[j] + setting_entry = 'run # %d: Setting param %s[%s] to value: %f' log_entry.append(setting_entry) logger.debug('\n '.join(log_entry)) @@ -87,23 +88,23 @@ def evaluate(param_info, mm_sample, data, i, config: TemoaConfig, log_queue, log 'Multiple outputs found in Objective table matching scenario name. Coding error.' ) else: - Y_OF = output_query[0][0] + y_of = output_query[0][0] cur.execute( "SELECT SUM(emission) FROM output_emission WHERE emis_comm='co2' AND scenario=?", (scenario_name,), ) output_query = cur.fetchall() if len(output_query) == 0: - Y_CumulativeCO2 = 0.0 + y_cumulative_co2 = 0.0 elif len(output_query) > 1: raise RuntimeError( 'Multiple outputs found in output_emissions table matching scenario name. Coding ' 'error.' ) else: - Y_CumulativeCO2 = output_query[0][0] - morris_objectives = [float(Y_OF), float(Y_CumulativeCO2)] - logger.info('Finished MM evaluation # %d with OBJ value: %0.2f ', i + 1, Y_OF) + y_cumulative_co2 = output_query[0][0] + morris_objectives = [float(y_of), float(y_cumulative_co2)] + logger.info('Finished MM evaluation # %d with OBJ value: %0.2f ', i + 1, y_of) if not config.silent: sys.stdout.write(f'Completed MM run {i + 1}\n') sys.stdout.flush() diff --git a/temoa/extensions/method_of_morris/morris_sequencer.py b/temoa/extensions/method_of_morris/morris_sequencer.py index 6ddacf8fe..92481f5d4 100644 --- a/temoa/extensions/method_of_morris/morris_sequencer.py +++ b/temoa/extensions/method_of_morris/morris_sequencer.py @@ -2,6 +2,7 @@ An event sequencer to control the flow of a Method of Morris calculation. This code uses multiprocessing via the joblib library """ +from __future__ import annotations import csv import logging @@ -9,21 +10,27 @@ import sqlite3 import sys import tomllib -from logging.handlers import QueueListener from importlib import resources -from pathlib import Path +from logging.handlers import QueueListener +from typing import TYPE_CHECKING, Any, cast -from joblib import Parallel, delayed +from joblib import Parallel, delayed # type: ignore[import-untyped] from numpy import array -from SALib.analyze import morris -from SALib.sample.morris import sample -from SALib.util import compute_groups_matrix, read_param_file +from SALib.analyze import morris # type: ignore[import-untyped] +from SALib.sample.morris import sample # type: ignore[import-untyped] +from SALib.util import compute_groups_matrix, read_param_file # type: ignore[import-untyped] from temoa._internal.table_writer import TableWriter -from temoa.core.config import TemoaConfig from temoa.data_io.hybrid_loader import HybridLoader from temoa.extensions.method_of_morris.morris_evaluate import evaluate +if TYPE_CHECKING: + from pathlib import Path + + from temoa.core.config import TemoaConfig + + + logger = logging.getLogger(__name__) solver_options_file = ( @@ -76,10 +83,11 @@ def __init__(self, config: TemoaConfig): self.param_file: Path = self.mm_output_folder / 'params.csv' # MM Options + morris_inputs = config.morris_inputs or {} # the amount to perturb the marked params - pert = config.morris_inputs.get('perturbation') + pert = morris_inputs.get('perturbation') if pert: - self.mm_perturbation = pert + self.mm_perturbation = float(cast(str | float, pert)) logger.info('Morris perturbation: %0.2f', self.mm_perturbation) else: self.mm_perturbation = 0.10 @@ -87,9 +95,9 @@ def __init__(self, config: TemoaConfig): 'No value received for perturbation, using default: %0.2f', self.mm_perturbation ) - levels = config.morris_inputs.get('levels') + levels = morris_inputs.get('levels') if levels: - self.num_levels = levels + self.num_levels = int(cast('Any', levels)) logger.info('Morris levels: %d', self.num_levels) else: self.num_levels = ( @@ -97,9 +105,9 @@ def __init__(self, config: TemoaConfig): ) logger.warning('No value received for levels, using default: %d', self.num_levels) - traj = config.morris_inputs.get('trajectories') + traj = morris_inputs.get('trajectories') if traj: - self.trajectories = traj + self.trajectories = int(cast('Any', traj)) logger.info('Morris trajectories: %d', self.trajectories) else: self.trajectories = 4 # number of morris trajectories to generate @@ -109,13 +117,13 @@ def __init__(self, config: TemoaConfig): # Note: Problem size (in general) is (Groups + 1) * trajectories see the SALib Dox (which # aren't super) - seed = config.morris_inputs.get('seed') - self.seed = seed if seed else None + seed = morris_inputs.get('seed') + self.seed = int(cast('Any', seed)) if seed else None logger.info('Morris Seed (None indicates system generated): %s', self.seed) self.conf_level = 0.95 # confidence level for mu_star analysis - self.num_cores = config.morris_inputs.get('cores', 0) + self.num_cores = morris_inputs.get('cores', 0) if self.num_cores == 0: self.num_cores = multiprocessing.cpu_count() logger.info('Morris number of cores: %d', self.num_cores) @@ -127,7 +135,7 @@ def __init__(self, config: TemoaConfig): 'detail on the model.' ) - def start(self): + def start(self) -> Any: """ run the sequence of steps to do a MM analysis 0. clear any prior results with this scenario name. this sequencer appends the DB, so @@ -193,7 +201,8 @@ def start(self): # 7. Return the cost objective Mu_Star for testing purposes... return cost_mu_star - def process_results(self, problem, mm_samples, morris_results): + def process_results(self, problem: dict[str, Any], mm_samples: Any, + morris_results: list[Any]) -> Any: """ Process the results of the runs on the mm_samples :param problem: the problem structure @@ -264,7 +273,7 @@ def process_results(self, problem, mm_samples, morris_results): writer.writerow(row) return analysis['cost'] - def gather_parameters(self): + def gather_parameters(self) -> dict[int, list[Any]]: """ Scan the annotated DB tables for marked parameters and capture them in the parameters file. Also capture the names in the param_info data @@ -339,5 +348,5 @@ def gather_parameters(self): return param_names - def __del__(self): + def __del__(self) -> None: self.con.close() diff --git a/temoa/extensions/modeling_to_generate_alternatives/hull.py b/temoa/extensions/modeling_to_generate_alternatives/hull.py index e4ecd5e41..22b23505b 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/hull.py +++ b/temoa/extensions/modeling_to_generate_alternatives/hull.py @@ -1,17 +1,31 @@ """ A thin wrapper on Scipy's ConvexHull to make it more manageable """ +from __future__ import annotations + from logging import getLogger +from typing import Any import numpy as np -import scipy -from scipy.spatial import ConvexHull +from scipy.spatial import ConvexHull # type: ignore[import-untyped] logger = getLogger(__name__) class Hull: - def __init__(self, points: np.ndarray, **kwargs): + dim: int + cv_hull: Any + volume: float + seen_norms: np.ndarray | None + _valid_norms: np.ndarray | None + tolerance: float + norms_checked: int + norms_rejected: int + good_points: np.ndarray | None + all_points: np.ndarray | None + norm_index: int + + def __init__(self, points: np.ndarray, **kwargs: Any) -> None: """ Build the initial hull from array of points :param points: an array of points [points, hull dimension] @@ -58,14 +72,16 @@ def norms_available(self) -> int: @property def norm_rejection_proportion(self) -> float: + if self.norms_checked == 0: + return 0.0 return self.norms_rejected / self.norms_checked - def update(self): + def update(self) -> None: """ Update/rebuild the Hull based on new points. :return: """ - if self.all_points is None: + if self.all_points is None or len(self.all_points) == 0: return try: self.cv_hull = ConvexHull(self.all_points, qhull_options='Q12 QJ') @@ -80,14 +96,15 @@ def update(self): self.good_points = self.cv_hull.points logger.info('Hull updated') self.volume = self.cv_hull.volume - except scipy.spatial._qhull.QhullError as e: + except Exception as e: + # scipy.spatial._qhull.QhullError may not be easily found by mypy logger.error( 'Attempt at hull construction from basis vectors failed.' '\nMay be non-recoverable. Possibly try a set of random vectors to initialize the ' 'Hull.' ) logger.error(e) - raise RuntimeError('Hull construction from vectors failed. See log file') + raise RuntimeError('Hull construction from vectors failed. See log file') from e # update the available norms from the new hull equations = self.cv_hull.equations[:, 0:-1] @@ -99,7 +116,7 @@ def update(self): else: self._valid_norms = np.vstack((self._valid_norms, norm)) - def add_point(self, point: np.ndarray): + def add_point(self, point: np.ndarray) -> None: if len(point) != self.dim: logger.error( 'Tried adding a point to hull (dim: %d) with wrong dimensions %d. Point: %s', @@ -117,7 +134,7 @@ def get_norm(self) -> np.ndarray | None: pop a new direction norm from the stack :return: a new norm vector """ - if self.norm_index < len(self._valid_norms): + if self._valid_norms is not None and self.norm_index < len(self._valid_norms): if np.ndim(self._valid_norms) == 1: # only one on the stack res = self._valid_norms else: @@ -128,7 +145,7 @@ def get_norm(self) -> np.ndarray | None: def get_all_norms(self) -> np.ndarray: """Get a matrix of all unused new vectors""" - if self.norms_available > 0: + if self._valid_norms is not None and self.norms_available > 0: res = np.atleast_2d(self._valid_norms)[self.norm_index :, :] self.norm_index = len(self._valid_norms) return res diff --git a/temoa/extensions/modeling_to_generate_alternatives/manager_factory.py b/temoa/extensions/modeling_to_generate_alternatives/manager_factory.py index 84a69fa64..3970c4e87 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/manager_factory.py +++ b/temoa/extensions/modeling_to_generate_alternatives/manager_factory.py @@ -1,11 +1,19 @@ -import sqlite3 +from __future__ import annotations + +from typing import TYPE_CHECKING, Any -from temoa.core.model import TemoaModel from temoa.extensions.modeling_to_generate_alternatives.mga_constants import MgaAxis, MgaWeighting from temoa.extensions.modeling_to_generate_alternatives.tech_activity_vector_manager import ( TechActivityVectorManager, ) -from temoa.extensions.modeling_to_generate_alternatives.vector_manager import VectorManager + +if TYPE_CHECKING: + import sqlite3 + + from temoa.core.model import TemoaModel + from temoa.extensions.modeling_to_generate_alternatives.vector_manager import VectorManager + + def get_manager( @@ -13,7 +21,7 @@ def get_manager( weighting: MgaWeighting, model: TemoaModel, con: sqlite3.Connection | None, - **kwargs, + **kwargs: Any, ) -> VectorManager: match axis: case MgaAxis.TECH_CATEGORY_ACTIVITY: @@ -21,6 +29,8 @@ def get_manager( raise NotImplementedError( 'TECH_CATEGORY_ACTIVITY is only implemented for HULL_EXPANSION' ) + if con is None: + raise ValueError('Connection is required for TECH_CATEGORY_ACTIVITY') return TechActivityVectorManager( base_model=model, conn=con, weighting=weighting, **kwargs ) diff --git a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py index 64821c521..098db7c14 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py +++ b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py @@ -1,6 +1,7 @@ """ Performs top-level control over an MGA model run """ +from __future__ import annotations import logging import queue @@ -8,26 +9,36 @@ import time import tomllib from datetime import datetime +from importlib import resources from logging import getLogger from multiprocessing import Queue -from importlib import resources -from pathlib import Path from queue import Empty +from typing import TYPE_CHECKING, Any, cast + +if TYPE_CHECKING: + from multiprocessing.process import BaseProcess + + from pyomo.contrib.solver.common.results import Results + from pyomo.dataportal import DataPortal + + from temoa.core.config import TemoaConfig + from temoa.core.model import TemoaModel + from temoa.extensions.modeling_to_generate_alternatives.vector_manager import VectorManager + + + + + import pyomo.environ as pyo -from pyomo.contrib.solver.common.results import Results -from pyomo.dataportal import DataPortal from pyomo.opt import check_optimal_termination from temoa._internal.run_actions import build_instance from temoa._internal.table_writer import TableWriter from temoa.components.costs import total_cost_rule -from temoa.core.config import TemoaConfig -from temoa.core.model import TemoaModel from temoa.data_io.hybrid_loader import HybridLoader from temoa.extensions.modeling_to_generate_alternatives.manager_factory import get_manager from temoa.extensions.modeling_to_generate_alternatives.mga_constants import MgaAxis, MgaWeighting -from temoa.extensions.modeling_to_generate_alternatives.vector_manager import VectorManager from temoa.extensions.modeling_to_generate_alternatives.worker import Worker from temoa.model_checking.pricing_check import price_checker @@ -40,6 +51,23 @@ class MgaSequencer: + con: sqlite3.Connection + config: TemoaConfig + opt: Any + worker_solver_options: dict[str, Any] + internal_stop: bool + mga_axis: MgaAxis + mga_weighting: MgaWeighting + num_workers: int + iteration_limit: int + time_limit_hrs: float + cost_epsilon: float + solve_count: int + seen_instance_indices: set[int] + orig_label: str + writer: TableWriter + verbose: bool + def __init__(self, config: TemoaConfig): # PRELIMINARIES... # let's start with the assumption that input db = output db... this may change? @@ -81,27 +109,28 @@ def __init__(self, config: TemoaConfig): # some defaults, etc. self.internal_stop = False - axis_label = config.mga_inputs.get('axis', '').upper() + mga_inputs = self.config.mga_inputs or {} + axis_label = str(mga_inputs.get('axis', '')).upper() try: self.mga_axis = MgaAxis[axis_label] logger.info('MGA axis is set to %s.', self.mga_axis.name) except KeyError: logger.warning('No/bad MGA Axis specified. Using default: Activity by Tech Category') self.mga_axis = MgaAxis.TECH_CATEGORY_ACTIVITY - weighting_label = config.mga_inputs.get('weighting', '').upper() + weighting_label = str(mga_inputs.get('weighting', '')).upper() try: self.mga_weighting = MgaWeighting[weighting_label] logger.info('MGA weighting set to %s', self.mga_weighting.name) except KeyError: logger.warning('No/bad MGA Weighting specified. Using default: Hull Expansion') self.mga_weighting = MgaWeighting.HULL_EXPANSION - self.num_workers = all_options.get('num_workers', 1) + self.num_workers = int(cast(str | int, all_options.get('num_workers', 1))) logger.info('MGA workers are set to %s', self.num_workers) - self.iteration_limit = config.mga_inputs.get('iteration_limit', 20) + self.iteration_limit = int(cast(str | int, mga_inputs.get('iteration_limit', 20))) logger.info('Set MGA iteration limit to: %d', self.iteration_limit) - self.time_limit_hrs = config.mga_inputs.get('time_limit_hrs', 12) + self.time_limit_hrs = float(cast(str | float, mga_inputs.get('time_limit_hrs', 12))) logger.info('Set MGA time limit hours to: %0.1f', self.time_limit_hrs) - self.cost_epsilon = config.mga_inputs.get('cost_epsilon', 0.05) + self.cost_epsilon = float(cast(str | float, mga_inputs.get('cost_epsilon', 0.05))) logger.info('Set MGA cost (relaxation) epsilon to: %0.3f', self.cost_epsilon) # internal records @@ -120,7 +149,7 @@ def __init__(self, config: TemoaConfig): self.mga_weighting.name, ) - def start(self): + def start(self) -> None: """Run the sequencer""" # ==== basic sequence ==== # 1. Load the model data, which may involve filtering it down if source tracing @@ -152,7 +181,7 @@ def start(self): toc = datetime.now() elapsed = toc - tic self.solve_count += 1 - logger.info(f'Initial solve time: {elapsed.total_seconds():.4f}') + logger.info('Initial solve time: %0.4f', elapsed.total_seconds()) status = res.solver.termination_condition logger.debug('Termination condition: %s', status.name) if not check_optimal_termination(res): @@ -190,17 +219,13 @@ def start(self): # 5. Set up the Workers num_workers = self.num_workers - work_queue = Queue(1) # restrict the queue to hold just 1 models in it max - result_queue = Queue( + work_queue: Queue[Any] = Queue(1) # restrict the queue to hold just 1 models in it max + result_queue: Queue[Any] = Queue( num_workers + 1 ) # must be able to hold a shutdown signal from all workers at once! - log_queue = Queue(50) + log_queue: Queue[Any] = Queue(50) # make workers - workers = [] - kwargs = { - 'solver_name': self.config.solver_name, - 'solver_options': self.worker_solver_options, - } + workers: list[BaseProcess] = [] # construct path for the solver logs s_path = self.config.output_path / 'solver_logs' if not s_path.exists(): @@ -212,8 +237,9 @@ def start(self): log_root_name=__name__, log_queue=log_queue, log_level=logging.INFO, + solver_name=self.config.solver_name, + solver_options=self.worker_solver_options, solver_log_path=s_path, - **kwargs, ) w.start() workers.append(w) @@ -237,7 +263,7 @@ def start(self): next_result = None # print('no result') if next_result is not None: - vector_manager.process_results(M=next_result) + vector_manager.process_results(model=next_result) self.process_solve_results(next_result) logger.info('Solve count: %d', self.solve_count) self.solve_count += 1 @@ -281,7 +307,7 @@ def start(self): next_result = None if next_result is not None and next_result != 'COYOTE': logger.debug('bagged a result post-shutdown') - vector_manager.process_results(M=next_result) + vector_manager.process_results(model=next_result) self.process_solve_results(next_result) logger.info('Solve count: %d', self.solve_count) self.solve_count += 1 @@ -297,8 +323,8 @@ def start(self): if empty == num_workers: break - for w in workers: - w.join() + for proc_join in workers: + proc_join.join() logger.debug('worker wrapped up...') log_queue.close() @@ -329,9 +355,10 @@ def solve_instance(self, instance: TemoaModel) -> bool: elapsed.total_seconds(), status.name, ) - return status == pyo.TerminationCondition.convergenceCriteriaSatisfied + return status == pyo.TerminationCondition.optimal or \ + str(status) == 'convergenceCriteriaSatisfied' - def process_solve_results(self, instance: TemoaModel): + def process_solve_results(self, instance: TemoaModel) -> None: """write the results as required""" # get the instance number from the model name, if provided if '-' not in instance.name: @@ -346,5 +373,5 @@ def process_solve_results(self, instance: TemoaModel): self.writer.write_capacity_tables(model=instance, iteration=idx) self.writer.write_summary_flow(instance, iteration=idx) - def __del__(self): + def __del__(self) -> None: self.con.close() diff --git a/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py b/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py index 14426721f..cf6b3fa3d 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py +++ b/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py @@ -1,21 +1,27 @@ +from __future__ import annotations + import queue -import sqlite3 from collections import defaultdict -from collections.abc import Iterable, Iterator from logging import getLogger -from pathlib import Path from queue import Queue +from typing import TYPE_CHECKING, Any import numpy as np from matplotlib import pyplot as plt from pyomo.core import Expression, Objective, Var, quicksum, value -from temoa.core.config import TemoaConfig -from temoa.core.model import TemoaModel from temoa.extensions.modeling_to_generate_alternatives.hull import Hull from temoa.extensions.modeling_to_generate_alternatives.mga_constants import MgaWeighting from temoa.extensions.modeling_to_generate_alternatives.vector_manager import VectorManager +if TYPE_CHECKING: + import sqlite3 + from collections.abc import Iterable, Iterator, Mapping, Sequence + + from temoa.core.config import TemoaConfig + from temoa.core.model import TemoaModel + + logger = getLogger(__name__) @@ -25,10 +31,10 @@ class DefaultItem: def __init__(self, name: str): self.name = name - def __str__(self): + def __str__(self) -> str: return self.name - def __repr__(self): + def __repr__(self) -> str: return self.name @@ -38,6 +44,23 @@ def __repr__(self): class TechActivityVectorManager(VectorManager): + completed_solves: int + conn: sqlite3.Connection + base_model: TemoaModel + optimal_cost: float + cost_relaxation: float + config: TemoaConfig + generation_index: int + category_mapping: dict[str | DefaultItem, list[str]] + technology_size: dict[str, int] + variable_index_mapping: dict[str, dict[str, list[tuple[Any, ...]]]] + coefficient_vector_queue: Queue[np.ndarray] + hull_points: np.ndarray | None + hull: Hull | None + basis_coefficients: Queue[np.ndarray] + hull_monitor: bool + perf_data: dict[int, float] + def __init__( self, conn: sqlite3.Connection, @@ -46,7 +69,7 @@ def __init__( optimal_cost: float, cost_relaxation: float, config: TemoaConfig, - ): + ) -> None: self.completed_solves = 0 self.conn = conn self.base_model = base_model @@ -57,26 +80,26 @@ def __init__( # {category : [technology, ...]} # the number of keys in this are the dimension of the hull - self.category_mapping: dict | None = None + self.category_mapping = defaultdict(list) # {technology: [number of associated variables, ...]} - self.technology_size: dict[str, int] = defaultdict(int) + self.technology_size = defaultdict(int) # in order to peel the data out of a solved model, we also need a rollup of the NAME # of the variable and indices in order... # {tech : {var_name : [indices, ...]}, ...} - self.variable_index_mapping: dict[str, dict[str, list]] = {} + self.variable_index_mapping = {} - self.coefficient_vector_queue: Queue[np.ndarray] = Queue() + self.coefficient_vector_queue = Queue() if weighting != MgaWeighting.HULL_EXPANSION: raise NotImplementedError( 'Tech Activity currently only works with Hull Expansion weighting' ) - self.hull_points: np.ndarray | None = None - self.hull: Hull | None = None + self.hull_points = None + self.hull = None self.initialize() - self.basis_coefficients: Queue[np.ndarray] = self._generate_basis_coefficients( + self.basis_coefficients = self._generate_basis_coefficients( self.category_mapping, self.technology_size ) @@ -90,7 +113,7 @@ def initialize(self) -> None: Fill the internal data stores from db and model :return: """ - self.basis_coefficients = [] + # self.basis_coefficients = [] # Removed inconsistent assignment techs_implemented = self.base_model.tech_all # some may have been culled by source tracing logger.debug('Initializing Technology Vectors data elements') raw = self.conn.execute('SELECT category, tech FROM Technology').fetchall() @@ -107,22 +130,22 @@ def initialize(self) -> None: logger.debug('Category %s members: %d', cat, len(self.category_mapping[cat])) # now pull the flow variables and map them - for idx in self.base_model.active_flow_rpsditvo: + for idx in self.base_model.active_flow_rpsditvo or set(): tech = idx[5] self.technology_size[tech] += 1 self.variable_index_mapping[tech][self.base_model.v_flow_out.name].append(idx) - for idx in self.base_model.active_flow_rpitvo: - tech = idx[3] + for idx_annual in self.base_model.active_flow_rpitvo or set(): + tech = idx_annual[3] self.technology_size[tech] += 1 - self.variable_index_mapping[tech][self.base_model.v_flow_out_annual.name].append(idx) + self.variable_index_mapping[tech][self.base_model.v_flow_out_annual.name].append(idx_annual) logger.debug('Catalogued %d Technology Variables', sum(self.technology_size.values())) @property def expired(self) -> bool: return False # this Manager can always generate more... - def group_variable_names(self, tech) -> list[Var]: - return list(self.category_mapping.keys()) + def group_variable_names(self, tech: str) -> list[str]: + return [str(k) for k in self.category_mapping.keys()] def random_input_vector_model(self) -> TemoaModel: new_model = self.base_model.clone() @@ -150,13 +173,16 @@ def model_generator(self) -> Iterator[TemoaModel]: obj_vector = self._make_basis_objective_vector(new_model) # if asking for more, we *should* have enough data to create a good hull now... - while self.completed_solves <= 2 * len(self.category_mapping): - # some of the basis vectors must have "crashed" or timed out... - # supply random vectors until we have sufficient number of solved models to make hull - logger.info( - 'Adding random vectors to augment the basis. Some basis solves may have crashed...' - ) - yield self.random_input_vector_model() + if len(self.category_mapping) > 0: + while self.completed_solves <= 2 * len(self.category_mapping): + # some of the basis vectors must have "crashed" or timed out... + # supply random vectors until we have sufficient number of + # solved models to make hull + logger.info( + 'Adding random vectors to augment the basis.' + 'Some basis solves may have crashed...' + ) + yield self.random_input_vector_model() logger.info('Generating hull points') self.regenerate_hull() @@ -164,9 +190,9 @@ def model_generator(self) -> Iterator[TemoaModel]: while True: new_model = self.base_model.clone() new_model.name = self.new_model_name() - v = self._next_objective_vector(M=new_model) + v = self._next_objective_vector(model=new_model) if v is None: - yield None + return new_model.obj = Objective(expr=v) yield new_model @@ -177,19 +203,19 @@ def new_model_name(self) -> str: self.generation_index += 1 return new_name - def process_results(self, M: TemoaModel): + def process_results(self, model: TemoaModel) -> list[float]: """ retrieve the necessary variable values to make another hull point :param M: :return: None """ self.completed_solves += 1 - res = [] + res: list[float] = [] for cat in self.category_mapping: element = 0 for tech in self.category_mapping[cat]: for var_name in self.variable_index_mapping[tech]: - model_var = M.find_component(var_name) + model_var = model.find_component(var_name) if not isinstance(model_var, Var): raise RuntimeError('hooked a bad fish') element += sum( @@ -208,17 +234,17 @@ def process_results(self, M: TemoaModel): return res def stop_resolving(self) -> bool: - pass + return False @property - def groups(self) -> Iterable[str]: + def groups(self) -> Iterable[Any]: return self.category_mapping.keys() - def group_members(self, group) -> list[str]: + def group_members(self, group: str | DefaultItem) -> list[str]: return self.category_mapping.get(group, []) # noinspection PyTypeChecker - def _make_basis_objective_vector(self, M: TemoaModel) -> Iterable[Expression] | None: + def _make_basis_objective_vector(self, model: TemoaModel) -> Iterable[Expression] | None: """generator for basis vectors which will be the coefficients in the obj expression in the basis solves""" if self.basis_coefficients.empty(): @@ -229,7 +255,7 @@ def _make_basis_objective_vector(self, M: TemoaModel) -> Iterable[Expression] | return None # now we need to roll out a vector of the variables and pair them with coefficients... - vars = self.var_vector(M) + vars = self.var_vector(model) # verify a unit vector err = abs(abs(sum(coeffs)) - 1) @@ -237,7 +263,7 @@ def _make_basis_objective_vector(self, M: TemoaModel) -> Iterable[Expression] | expr = sum(c * v for v, c in zip(vars, coeffs, strict=False) if c != 0) return expr - def _next_objective_vector(self, M: TemoaModel) -> Expression | None: + def _next_objective_vector(self, model: TemoaModel) -> Expression | None: if self.coefficient_vector_queue.qsize() <= 3: logger.info('running low on input vectors... refreshing the vectors with new hull') self.regenerate_hull() @@ -246,30 +272,30 @@ def _next_objective_vector(self, M: TemoaModel) -> Expression | None: vector = self.coefficient_vector_queue.get() # translate the norm vector into coefficients - coeffs = [] + coeffs_list = [] for idx, cat in enumerate(self.category_mapping): for tech in self.category_mapping[cat]: reps = self.technology_size[tech] element = [ vector[idx], ] * reps - coeffs.extend(element) - coeffs = np.array(coeffs) + coeffs_list.extend(element) + coeffs = np.array(coeffs_list) coeffs /= np.sum(coeffs) # normalize - obj_vars = self.var_vector(M) + obj_vars = self.var_vector(model) assert len(obj_vars) == len(coeffs) return quicksum(c * v for v, c in zip(obj_vars, coeffs, strict=False)) - def var_vector(self, M: TemoaModel) -> list[Var]: + def var_vector(self, model: TemoaModel) -> list[Any]: """Produce a properly sequenced array of variables from the current model for use in obj vector""" res = [] for cat in self.category_mapping: for tech in self.category_mapping[cat]: for var_name in self.variable_index_mapping[tech]: - var = M.find_component(var_name) + var = model.find_component(var_name) if not isinstance(var, Var): raise RuntimeError( 'Failed to retrieve a named variable from the model: %s', var_name @@ -278,8 +304,11 @@ def var_vector(self, M: TemoaModel) -> list[Var]: res.append(var[idx]) return res - def regenerate_hull(self): + def regenerate_hull(self) -> None: """make the hull...""" + if self.hull_points is None: + logger.warning('Cannot regenerate hull: no points available') + return logger.debug('Generating the cvx hull from %d points', len(self.hull_points)) self.hull = Hull(self.hull_points) fresh_vecs = self.hull.get_all_norms() @@ -292,7 +321,7 @@ def regenerate_hull(self): ) self.load_normals(fresh_vecs) - def load_normals(self, normals: np.array): + def load_normals(self, normals: np.ndarray) -> None: for vector in normals: self.coefficient_vector_queue.put(vector) @@ -300,10 +329,13 @@ def input_vectors_available(self) -> int: return self.coefficient_vector_queue.qsize() @staticmethod - def _generate_basis_coefficients(category_mapping: dict, technology_size: dict) -> Queue: + def _generate_basis_coefficients( + category_mapping: Mapping[Any, Sequence[str]], + technology_size: Mapping[str, int], + ) -> Queue[np.ndarray]: # Sequentially build the coefficient vector in the order of the categories and associated # techs - q = Queue() + q: Queue[np.ndarray] = Queue() for selected_cat in category_mapping: res = [] if selected_cat == default_cat: @@ -327,18 +359,19 @@ def _generate_basis_coefficients(category_mapping: dict, technology_size: dict) return q - def tracker(self): + def tracker(self) -> None: """ A little function to track the size of the hull, after it is built initially Note: This hull is a "throw away" and only used for volume calc, but it is pretty quick """ - if self.hull is not None: # don't try until after first hull is built + if self.hull is not None and \ + self.hull_points is not None: # don't try until after first hull is built hull = Hull(self.hull_points) volume = hull.volume - logger.info(f'Tracking hull at {volume}') + logger.info('Tracking hull at %0.2f', volume) self.perf_data.update({len(self.hull_points): volume}) - def finalize_tracker(self): + def finalize_tracker(self) -> None: fout = self.config.output_path / 'hull_performance.png' pts = sorted(self.perf_data.keys()) y = [self.perf_data[pt] for pt in pts] diff --git a/temoa/extensions/modeling_to_generate_alternatives/vector_manager.py b/temoa/extensions/modeling_to_generate_alternatives/vector_manager.py index 37da4c4ca..3b0d1ea27 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/vector_manager.py +++ b/temoa/extensions/modeling_to_generate_alternatives/vector_manager.py @@ -1,12 +1,16 @@ """ An ABC to serve as a framework for future Vector Managers """ +from __future__ import annotations -import sqlite3 from abc import ABC, abstractmethod -from collections.abc import Iterable, Iterator +from typing import TYPE_CHECKING, Any -from temoa.core.model import TemoaModel +if TYPE_CHECKING: + import sqlite3 + from collections.abc import Iterable, Iterator + + from temoa.core.model import TemoaModel class VectorManager(ABC): @@ -17,7 +21,7 @@ def __init__( base_model: TemoaModel, optimal_cost: float, cost_relaxation: float, - ): + ) -> None: """ Initialize a new manager :param conn: connection to the current database @@ -34,7 +38,7 @@ def groups(self) -> Iterable[str]: raise NotImplementedError() @abstractmethod - def group_members(self, group) -> list[str]: + def group_members(self, group: str) -> list[str]: """The members (by string name) in the group""" raise NotImplementedError() @@ -45,9 +49,10 @@ def expired(self) -> bool: Indicator that this manager has no more vectors to generate :return: True if expired """ + raise NotImplementedError() @abstractmethod - def group_variable_names(self, tech) -> list[str]: + def group_variable_names(self, tech: str) -> list[str]: """The variable NAMES associated with the individual group members""" raise NotImplementedError() @@ -62,10 +67,10 @@ def model_generator(self) -> Iterator[TemoaModel]: raise NotImplementedError('the manager subclass must implement instance_generator') @abstractmethod - def process_results(self, M: TemoaModel): + def process_results(self, model: TemoaModel) -> Any: raise NotImplementedError('the manager subclass must implement process_results') @abstractmethod - def finalize_tracker(self): + def finalize_tracker(self) -> None: """Finalize any tracker employed by the manager""" pass diff --git a/temoa/extensions/modeling_to_generate_alternatives/worker.py b/temoa/extensions/modeling_to_generate_alternatives/worker.py index 62dd458c6..efb1c3ff6 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/worker.py +++ b/temoa/extensions/modeling_to_generate_alternatives/worker.py @@ -1,13 +1,14 @@ """ Class to contain Workers that execute solves in separate processes """ +from __future__ import annotations import logging.handlers from datetime import datetime from logging import getLogger from multiprocessing import Process, Queue from pathlib import Path -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any from pyomo.opt import SolverFactory, SolverResults, check_optimal_termination @@ -18,24 +19,35 @@ class Worker(Process): - worker_idx = 1 + worker_idx: int = 1 + worker_number: int + model_queue: Queue[Any] + results_queue: Queue[Any] + log_queue: Queue[logging.LogRecord] + solver_name: str + solver_options: dict[str, Any] + solver_log_path: Path | None + opt: Any + log_root_name: str + log_level: int + solve_count: int def __init__( self, - model_queue: Queue, - results_queue: Queue, + model_queue: Queue[Any], + results_queue: Queue[Any], log_root_name: str, - log_queue: Queue, + log_queue: Queue[logging.LogRecord], log_level: int = logging.INFO, solver_name: str = 'appsi_highs', - solver_options: dict | None = None, + solver_options: dict[str, Any] | None = None, solver_log_path: Path | None = None, ): super().__init__(daemon=True) self.worker_number = Worker.worker_idx Worker.worker_idx += 1 - self.model_queue: Queue = model_queue - self.results_queue: Queue = results_queue + self.model_queue = model_queue + self.results_queue = results_queue self.log_queue = log_queue self.solver_name = solver_name self.solver_options = solver_options or {} @@ -46,8 +58,9 @@ def __init__( self.log_level = log_level self.solve_count = 0 - def run(self): - logger = getLogger('.'.join((self.log_root_name, 'worker', str(self.worker_number)))) + def run(self) -> None: + logger: logging.Logger = getLogger('.'.join( + (self.log_root_name, 'worker', str(self.worker_number)))) logger.propagate = False # prevent duplicate logs # add a handler that pushes to the queue handler = logging.handlers.QueueHandler(self.log_queue) @@ -68,10 +81,10 @@ def run(self): self.solver_log_path, f'solver_log_{str(self.worker_number)}_{self.solve_count}.log', ) - log_location = str(log_location) + log_location_str = str(log_location) match self.solver_name: case 'gurobi': - self.solver_options.update({'LogFile': log_location}) + self.solver_options.update({'LogFile': log_location_str}) # case 'appsi_highs': # self.solver_options.update({'log_file': log_location}) case _: @@ -89,7 +102,7 @@ def run(self): tic = datetime.now() try: self.solve_count += 1 - res: SolverResults | None = self.opt.solve(model) + solve_res: SolverResults | None = self.opt.solve(model) except Exception as e: if verbose: @@ -100,12 +113,12 @@ def run(self): model.name, e, ) - res = None + solve_res = None toc = datetime.now() # guard against a bad "res" object... try: - good_solve = check_optimal_termination(res) + good_solve = check_optimal_termination(solve_res) if good_solve: self.results_queue.put(model) logger.info( @@ -116,9 +129,11 @@ def run(self): if verbose: print(f'Worker {self.worker_number} completed a successful solve') else: - status = res['Solver'].termination_condition - logger.info( - 'Worker %d did not solve. Results status: %s', self.worker_number, status - ) + if solve_res is not None: + status = solve_res['Solver'].termination_condition + logger.info( + 'Worker %d did not solve. Results status: %s', + self.worker_number, status + ) except AttributeError: pass diff --git a/temoa/extensions/monte_carlo/example_builds/scenario_analyzer.py b/temoa/extensions/monte_carlo/example_builds/scenario_analyzer.py index ba55b0fb2..d2d179ca9 100644 --- a/temoa/extensions/monte_carlo/example_builds/scenario_analyzer.py +++ b/temoa/extensions/monte_carlo/example_builds/scenario_analyzer.py @@ -1,11 +1,10 @@ """ Simple analyzer--example only """ +from importlib import resources from math import sqrt -from pathlib import Path from sqlite3 import Connection -from importlib import resources from matplotlib import pyplot as plt scenario_name = 'Purple Onion' # must match config file @@ -15,7 +14,7 @@ obj_values = cur.execute( f"SELECT total_system_cost FROM output_objective WHERE scenario LIKE '{scenario_name}-%'" ).fetchall() - obj_values = tuple(t[0] for t in obj_values) + obj_values_tuple = tuple(t[0] for t in obj_values) -plt.hist(obj_values, bins=int(sqrt(len(obj_values)))) +plt.hist(obj_values_tuple, bins=int(sqrt(len(obj_values_tuple)))) plt.show() diff --git a/temoa/extensions/monte_carlo/example_builds/scenario_maker.py b/temoa/extensions/monte_carlo/example_builds/scenario_maker.py index d89556daf..0e72dd483 100644 --- a/temoa/extensions/monte_carlo/example_builds/scenario_maker.py +++ b/temoa/extensions/monte_carlo/example_builds/scenario_maker.py @@ -24,6 +24,7 @@ import matplotlib.pyplot as plt import numpy as np +from typing import cast # distro for the related cost vars @@ -33,7 +34,8 @@ num_runs = 1000 cov = np.array([[0.4, -0.1], [-0.1, 0.1]]) price_devs = np.random.multivariate_normal([0, 0], cov, size=num_runs) -print(f'correlation check: {np.corrcoef(price_devs.T)[0, 1]}') +corr_matrix = cast(np.typing.NDArray[np.float64], np.corrcoef(price_devs.T)) +print(f'correlation check: {corr_matrix[0, 1]}') # verify with a peek... plt.plot(price_devs[:, 0], price_devs[:, 1], '.', alpha=0.5) diff --git a/temoa/extensions/monte_carlo/mc_run.py b/temoa/extensions/monte_carlo/mc_run.py index c52784e34..dc4063460 100644 --- a/temoa/extensions/monte_carlo/mc_run.py +++ b/temoa/extensions/monte_carlo/mc_run.py @@ -1,19 +1,24 @@ """ """ +from __future__ import annotations from collections import defaultdict, namedtuple -from collections.abc import Generator from itertools import product from logging import getLogger from pathlib import Path +from typing import TYPE_CHECKING, Any -from pyomo.dataportal import DataPortal - -from temoa.core.config import TemoaConfig from temoa.core.model import TemoaModel from temoa.data_io.hybrid_loader import HybridLoader +if TYPE_CHECKING: + from collections.abc import Generator + + from pyomo.dataportal import DataPortal + + from temoa.core.config import TemoaConfig + logger = getLogger(__name__) RowData = namedtuple('RowData', ['run', 'param_name', 'indices', 'adjustment', 'value', 'notes']) @@ -22,13 +27,20 @@ """a record of a data element change, for an element acted on by a Tweak""" + + class Tweak: """ objects of this class represent individual tweaks to single (or wildcard) data elements for a Monte Carlo run """ - def __init__(self, param_name: str, indices: tuple, adjustment: str, value: float): + param_name: str + indices: tuple[Any, ...] + adjustment: str + value: float + + def __init__(self, param_name: str, indices: tuple[Any, ...], adjustment: str, value: float): if not isinstance(indices, tuple): raise TypeError('indices must be a tuple') if adjustment not in {'r', 'a', 's'}: @@ -41,7 +53,7 @@ def __init__(self, param_name: str, indices: tuple, adjustment: str, value: floa self.adjustment = adjustment self.value = value - def __repr__(self): + def __repr__(self) -> str: return ( f'' @@ -53,7 +65,9 @@ class TweakFactory: factor (likely a singleton) to manufacture Tweaks from input data """ - def __init__(self, data_store: dict): + val_data: dict[str, Any] + + def __init__(self, data_store: dict[str, Any]): """ make a new factor and use data_store as a validation tool :param data_store: the data dictionary holding the base values for the model @@ -61,7 +75,6 @@ def __init__(self, data_store: dict): if not isinstance(data_store, dict): raise TypeError('data_store must be a dict') self.val_data = data_store - tweak_dict: dict[int, list[Tweak]] = defaultdict(list) def make_tweaks(self, row_number: int, row: str) -> tuple[int, list[Tweak]]: """ @@ -75,9 +88,8 @@ def make_tweaks(self, row_number: int, row: str) -> tuple[int, list[Tweak]]: p_index = rd.indices.replace('(', '').replace(')', '') # remove any optional parens tokens = p_index.split('|') tokens = [t.strip() for t in tokens] - tweaks = [] # locate all 'multi' indices... - index_vals: dict[int, list] = defaultdict(list) + index_vals: dict[int, list[Any]] = defaultdict(list) for pos, token in enumerate(tokens): if '/' in token: # it is a multi-token sub_tokens = token.split('/') @@ -122,15 +134,15 @@ def row_parser(self, row_number: int, row: str) -> RowData: ) # convert the run number try: - tokens[0] = int(tokens[0]) - except ValueError: - raise ValueError(f'run number at row {row_number} must be an integer') + run_num = int(tokens[0]) + except ValueError as err: + raise ValueError(f'run number at row {row_number} must be an integer') from err # convert the value try: - tokens[-2] = float(tokens[-2]) - except ValueError: - raise ValueError('value at row {idx} must be numeric') - rd = RowData(*tokens) + val = float(tokens[-2]) + except ValueError as err: + raise ValueError(f'value at line {row_number} must be numeric') from err + rd = RowData(run_num, tokens[1], tokens[2], tokens[3], val, tokens[5]) # make other checks... if rd.param_name not in self.val_data: @@ -155,11 +167,16 @@ class MCRun: A Container class to hold the data (and more?) to support a model build + run """ + scenario_name: str + run_index: int + data_store: dict[str, Any] + included_tweaks: dict[Tweak, list[ChangeRecord]] + def __init__( self, scenario_name: str, run_index: int, - data_store: dict, + data_store: dict[str, Any], included_tweaks: dict[Tweak, list[ChangeRecord]], ): self.scenario_name = scenario_name @@ -199,13 +216,18 @@ class MCRunFactory: They will hold the "data tweaks" gathered from input file for application to the base data """ - def __init__(self, config: TemoaConfig, data_store: dict): + config: TemoaConfig + data_store: dict[str, Any] + tweak_factory: TweakFactory + settings_file: Path + + def __init__(self, config: TemoaConfig, data_store: dict[str, Any]): self.config = config self.data_store = data_store self.tweak_factory = TweakFactory(data_store) - self.settings_file = Path(self.config.monte_carlo_inputs['run_settings']) + self.settings_file = Path(self.config.monte_carlo_inputs['run_settings']) # type: ignore - def prescreen_input_file(self): + def prescreen_input_file(self) -> bool: """ read the input csv file and screen common errors :return: True if file passes, false otherwise with log entries @@ -225,10 +247,10 @@ def prescreen_input_file(self): raise ValueError(f'Run sequence violation at row {idx}') elif current_run < rd.run: current_run = rd.run - logger.info(f'Pre-screen of data file: {self.settings_file} successful.') + logger.info('Pre-screen of data file: %s successful.', self.settings_file) return True - def _next_row_generator(self) -> Generator[tuple[int, str], None, None]: + def _next_row_generator(self) -> Generator[tuple[int, str]]: """ A generator to read lines from thr run settings file :return: @@ -241,7 +263,7 @@ def _next_row_generator(self) -> Generator[tuple[int, str], None, None]: yield idx, line idx += 1 - def tweak_set_generator(self) -> tuple[int, list[Tweak]]: + def tweak_set_generator(self) -> Generator[tuple[int, list[Tweak]]]: """ generator for lists of tweaks per run :return: @@ -268,7 +290,9 @@ def tweak_set_generator(self) -> tuple[int, list[Tweak]]: current_run = run_number @staticmethod - def element_locator(data_store: dict, param: str, target_index: tuple) -> list[tuple]: + def element_locator( + data_store: dict[str, Any], param: str, target_index: tuple[Any, ...] + ) -> list[tuple[Any, ...]]: """ find the associated indices that match the index, which may contain wildcards @@ -313,7 +337,7 @@ def _adjust_value(old_value: float, adjust_type: str, factor: float) -> float: raise ValueError(f'Unsupported adjustment type {adjust_type}') return res - def run_generator(self) -> Generator[MCRun, None, None]: + def run_generator(self) -> Generator[MCRun]: """ make a new MC Run, log problems with tweaks and write successful tweaks to the DB Output @@ -335,9 +359,10 @@ def run_generator(self) -> Generator[MCRun, None, None]: failed_tweaks.append(tweak) else: for index in matching_indices: - old_value = data_store.get(tweak.param_name)[index] + param_vals = data_store[tweak.param_name] + old_value = param_vals[index] new_value = self._adjust_value(old_value, tweak.adjustment, tweak.value) - data_store[tweak.param_name][index] = new_value + param_vals[index] = new_value good_tweaks[tweak].append( ChangeRecord(tweak.param_name, index, old_value, new_value) ) @@ -353,7 +378,7 @@ def run_generator(self) -> Generator[MCRun, None, None]: # skip the creation of the run if no tweaks were successful (it would just be the # baseline run...) if not good_tweaks: - logger.warning(f'Aborting run: {run}. No good tweaks found') + logger.warning('Aborting run: %s. No good tweaks found', run) continue mc_run = MCRun( scenario_name=self.config.scenario, diff --git a/temoa/extensions/monte_carlo/mc_sequencer.py b/temoa/extensions/monte_carlo/mc_sequencer.py index b3e61d237..c44c1779d 100644 --- a/temoa/extensions/monte_carlo/mc_sequencer.py +++ b/temoa/extensions/monte_carlo/mc_sequencer.py @@ -3,6 +3,7 @@ A sequencer for Monte Carlo Runs """ +from __future__ import annotations import logging import queue @@ -10,20 +11,27 @@ import time import tomllib from datetime import datetime -from logging import getLogger -from multiprocessing import Queue from importlib import resources +from logging import getLogger from pathlib import Path +from typing import TYPE_CHECKING, Any, cast -from pyomo.dataportal import DataPortal - -from temoa._internal.data_brick import DataBrick from temoa._internal.table_writer import TableWriter -from temoa.core.config import TemoaConfig from temoa.data_io.hybrid_loader import HybridLoader -from temoa.extensions.monte_carlo.mc_run import MCRunFactory +from temoa.extensions.monte_carlo.mc_run import MCRun, MCRunFactory from temoa.extensions.monte_carlo.mc_worker import MCWorker +if TYPE_CHECKING: + from multiprocessing import Queue + from multiprocessing.process import BaseProcess + + from pyomo.dataportal import DataPortal + + from temoa._internal.data_brick import DataBrick + from temoa.core.config import TemoaConfig + + + logger = getLogger(__name__) solver_options_path = ( @@ -36,21 +44,38 @@ class MCSequencer: A sequencer to control the steps in Monte Carlo run sequence """ + num_workers: int + worker_solver_options: dict[str, Any] + solve_count: int + seen_instance_indices: set[int] + orig_label: str + writer: TableWriter + verbose: bool + def __init__(self, config: TemoaConfig): self.config = config # determine the path to the solver options file - custom_path = self.config.monte_carlo_inputs.get('solver_options') + custom_path = ( + self.config.monte_carlo_inputs.get('solver_options') + if self.config.monte_carlo_inputs + else None + ) if custom_path: - options_file_path = Path(custom_path) + options_file_path: Path | None = Path(cast('str', custom_path)) # if the path is relative, make it relative to the config file location if possible - if not options_file_path.is_absolute() and self.config.config_file: + if ( + options_file_path + and not options_file_path.is_absolute() + and self.config.config_file + ): options_file_path = self.config.config_file.parent / options_file_path logger.info('Using custom Monte Carlo solver options from: %s', options_file_path) else: options_file_path = None # read in the options + all_options: dict[str, Any] try: if options_file_path: with open(options_file_path, 'rb') as f: @@ -82,7 +107,7 @@ def __init__(self, config: TemoaConfig): self.writer = TableWriter(self.config) self.verbose = False # for troubleshooting - def start(self): + def start(self) -> None: """Run the sequencer""" # ==== basic sequence ==== # 1. Load the model data, which may involve filtering it down if source tracing @@ -92,7 +117,6 @@ def start(self): # 4. copy & modify the base data to make per-dataset runs # 5. farm out the runs to workers - start_time = datetime.now() # 0. Set up database for scenario self.writer.clear_scenario() @@ -103,13 +127,13 @@ def start(self): with sqlite3.connect(self.config.input_database) as con: hybrid_loader = HybridLoader(db_connection=con, config=self.config) data_store = hybrid_loader.create_data_dict(myopic_index=None) - mc_run = MCRunFactory(config=self.config, data_store=data_store) + mc_factory = MCRunFactory(config=self.config, data_store=data_store) # 2. Screen the input file - mc_run.prescreen_input_file() + mc_factory.prescreen_input_file() # 3. set up the run generator - run_gen = mc_run.run_generator() + run_gen = mc_factory.run_generator() # 4. Set up the workers import multiprocessing @@ -123,9 +147,9 @@ def start(self): result_queue: Queue[DataBrick | str] = ctx.Queue( num_workers + 1 ) # must be able to hold a shutdown signal from all workers at once! - log_queue = ctx.Queue() + log_queue: Queue[logging.LogRecord] = ctx.Queue() # make workers - workers = [] + workers: list[BaseProcess] = [] kwargs = { 'solver_name': self.config.solver_name, 'solver_options': self.worker_solver_options, @@ -134,7 +158,7 @@ def start(self): s_path = self.config.output_path / 'solver_logs' if not s_path.exists(): s_path.mkdir() - for i in range(num_workers): + for _ in range(num_workers): w = MCWorker( dp_queue=work_queue, results_queue=result_queue, @@ -144,7 +168,7 @@ def start(self): solver_log_path=s_path, **kwargs, ) - p = ctx.Process(target=w.run, daemon=True) + p: BaseProcess = ctx.Process(target=w.run, daemon=True) p.start() workers.append(p) # workers now running and waiting for jobs... @@ -152,7 +176,7 @@ def start(self): # 6. Start the iterative solve process and let the manager run the show more_runs = True # pull the first instance - mc_run = next(run_gen) + mc_run: MCRun = next(run_gen) # capture the "tweaks" self.writer.write_tweaks(iteration=mc_run.run_index, change_records=mc_run.change_records) run_name, dp = mc_run.model_dp @@ -199,7 +223,7 @@ def start(self): next_result = None # print('no result') if next_result is not None: - self.process_solve_results(next_result) + self.process_solve_results(cast('DataBrick', next_result)) self.solve_count += 1 logger.info('Solve count: %d', self.solve_count) if self.verbose or not self.config.silent: @@ -250,7 +274,7 @@ def start(self): next_result = None if next_result is not None and next_result != 'COYOTE': logger.debug('bagged a result post-shutdown') - self.process_solve_results(next_result) + self.process_solve_results(cast('DataBrick', next_result)) self.solve_count += 1 logger.info('Solve count: %d', self.solve_count) if self.verbose or not self.config.silent: @@ -265,8 +289,8 @@ def start(self): if empty == num_workers: break - for w in workers: - w.join() + for proc in workers: + proc.join() logger.debug('worker wrapped up...') log_queue.close() @@ -283,7 +307,7 @@ def start(self): if self.verbose: print('result queue joined') - def process_solve_results(self, brick: DataBrick): + def process_solve_results(self, brick: DataBrick) -> None: """write the results as required""" # get the instance number from the model name, if provided if '-' not in brick.name: diff --git a/temoa/extensions/monte_carlo/mc_worker.py b/temoa/extensions/monte_carlo/mc_worker.py index 4b19b0617..9d5fed2bc 100644 --- a/temoa/extensions/monte_carlo/mc_worker.py +++ b/temoa/extensions/monte_carlo/mc_worker.py @@ -9,42 +9,54 @@ new obj functions """ +from __future__ import annotations import logging.handlers from datetime import datetime from logging import getLogger -from multiprocessing import Process, Queue -from pathlib import Path -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any from pyomo.opt import SolverFactory, SolverResults, check_optimal_termination from temoa._internal.data_brick import DataBrick, data_brick_factory from temoa.core.model import TemoaModel -if TYPE_CHECKING: - from pyomo.dataportal import DataPortal - verbose = False # for T/S or monitoring... +if TYPE_CHECKING: + from multiprocessing import Queue + from pathlib import Path + class MCWorker: worker_idx = 1 + worker_number: int + dp_queue: Queue[Any] + results_queue: Queue[DataBrick | str] + solver_name: str + solver_options: dict[str, Any] + opt: Any + log_queue: Queue[logging.LogRecord] + log_level: int + root_logger_name: str + solver_log_path: Path | None + solve_count: int + def __init__( self, - dp_queue: Queue, - results_queue: Queue, + dp_queue: Queue[Any], + results_queue: Queue[DataBrick | str], log_root_name: str, - log_queue: Queue, + log_queue: Queue[logging.LogRecord], log_level: int = logging.INFO, solver_log_path: Path | None = None, - **kwargs, + **kwargs: Any, ): self.worker_number = MCWorker.worker_idx MCWorker.worker_idx += 1 - self.dp_queue: Queue[DataPortal | str] = dp_queue - self.results_queue: Queue[DataBrick | str] = results_queue + self.dp_queue = dp_queue + self.results_queue = results_queue self.solver_name = kwargs['solver_name'] self.solver_options = kwargs['solver_options'] self.opt = None # Initialize in run() @@ -54,8 +66,9 @@ def __init__( self.solver_log_path = solver_log_path self.solve_count = 0 - def run(self): - logger = getLogger('.'.join((self.root_logger_name, 'worker', str(self.worker_number)))) + def run(self) -> None: + msg = '.'.join((self.root_logger_name, 'worker', str(self.worker_number))) + logger: logging.Logger = getLogger(msg) logger.setLevel(self.log_level) logger.propagate = ( False # not propagating up the chain fixes issue on TRACE where we were getting dupes. @@ -107,7 +120,7 @@ def run(self): / f'solver_log_{self.worker_number}_{self.solve_count}.log' ) try: - setattr(self.opt.config, 'log_file', str(log_location)) + self.opt.config.log_file = str(log_location) except (ValueError, AttributeError): pass @@ -117,15 +130,16 @@ def run(self): tic = datetime.now() try: self.solve_count += 1 + solve_res: SolverResults | None if self.solver_name.startswith('appsi_'): # For appsi, we can set tee on the config try: self.opt.config.tee = True except (ValueError, AttributeError): pass - res: SolverResults | None = self.opt.solve(model) + solve_res = self.opt.solve(model) else: - res: SolverResults | None = self.opt.solve(model, tee=True) + solve_res = self.opt.solve(model, tee=True) except Exception as e: if verbose: @@ -141,12 +155,12 @@ def run(self): logger.warning( 'Solver results status: %s', self.opt.results.solver.termination_condition ) - res = None + solve_res = None toc = datetime.now() # guard against a bad "res" object... try: - good_solve = check_optimal_termination(res) + good_solve = check_optimal_termination(solve_res) if good_solve: data_brick = data_brick_factory(model) self.results_queue.put(data_brick) @@ -158,12 +172,13 @@ def run(self): if verbose: print(f'Worker {self.worker_number} completed a successful solve') else: - status = res['Solver'].termination_condition - logger.info( - 'Worker %d did not solve. Results status: %s', - self.worker_number, - status, - ) + if solve_res is not None: + status = solve_res['Solver'].termination_condition + logger.info( + 'Worker %d did not solve. Results status: %s', + self.worker_number, + status, + ) except AttributeError: pass logger.info('Worker %d finished', self.worker_number) diff --git a/temoa/extensions/myopic/evolution_updater.py b/temoa/extensions/myopic/evolution_updater.py index 7d630dcaa..20808e79a 100644 --- a/temoa/extensions/myopic/evolution_updater.py +++ b/temoa/extensions/myopic/evolution_updater.py @@ -28,6 +28,7 @@ def iterate( which you can use to read/write data as needed. """ + assert idx is not None logger.info(f"Running myopic iteration updater for base year {idx.base_year}") # Update your myopic database here. diff --git a/temoa/extensions/myopic/myopic_index.py b/temoa/extensions/myopic/myopic_index.py index c72ca2c26..db7ac35bc 100644 --- a/temoa/extensions/myopic/myopic_index.py +++ b/temoa/extensions/myopic/myopic_index.py @@ -16,7 +16,7 @@ class MyopicIndex: last_demand_year: int last_year: int - def __post_init__(self): + def __post_init__(self) -> None: if not self.base_year < self.step_year <= self.last_year: raise ValueError( f'Received a nonsense value for step_year: {self.step_year} with ' diff --git a/temoa/extensions/myopic/myopic_progress_mapper.py b/temoa/extensions/myopic/myopic_progress_mapper.py index c1d81508e..13e0232fc 100644 --- a/temoa/extensions/myopic/myopic_progress_mapper.py +++ b/temoa/extensions/myopic/myopic_progress_mapper.py @@ -8,7 +8,7 @@ class MyopicProgressMapper: - def __init__(self, sorted_future_years: list): + def __init__(self, sorted_future_years: list[int]) -> None: self.leader = '--' self.trailer = ''.join(reversed(self.leader)) self.years = sorted_future_years @@ -18,7 +18,7 @@ def __init__(self, sorted_future_years: list): } self.hack: datetime = datetime.now() - def draw_header(self): + def draw_header(self) -> None: time_buffer = ' ' * 10 tot_length = len(self.years) * self.tag_width + 2 * len(self.years) print(time_buffer, end='') @@ -49,7 +49,7 @@ def timestamp(self) -> str: f'{int(delta.total_seconds()%3600//60):02d}:{int(delta.total_seconds())%60:02d} ' ) - def report(self, mi: MyopicIndex, status): + def report(self, mi: MyopicIndex, status: str) -> None: if status not in {'load', 'solve', 'report', 'check', 'evolve'}: raise ValueError(f'bad status: {status} received in MyopicProgressMapper') diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index 59f78ea87..3b46c53ba 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -9,7 +9,8 @@ from collections import deque from importlib import resources, util from pathlib import Path -from sqlite3 import Connection +from sqlite3 import Connection, Cursor +from typing import Any, cast from temoa._internal import run_actions from temoa._internal.table_writer import TableWriter @@ -63,20 +64,34 @@ class MyopicSequencer: 'output_storage_level', ] - def __init__(self, config: TemoaConfig | None): + capacity_epsilon: float + debugging: bool + optimization_periods: list[int] | None + instance_queue: deque[MyopicIndex] + progress_mapper: MyopicProgressMapper | None + config: TemoaConfig | None + output_con: Connection + cursor: Cursor + table_writer: TableWriter + view_depth: int + step_size: int + evolving: bool + evolution_script: str + + def __init__(self, config: TemoaConfig | None) -> None: # Minimum capacity (MW) to carry forward between myopic periods. # Configurable via [myopic] capacity_threshold in TOML. default_cap_threshold = 1e-3 if config and config.myopic_inputs: - self.capacity_epsilon = config.myopic_inputs.get( - 'capacity_threshold', default_cap_threshold + self.capacity_epsilon = float( + cast(Any, config.myopic_inputs.get('capacity_threshold', default_cap_threshold)) ) else: self.capacity_epsilon = default_cap_threshold self.debugging = False - self.optimization_periods: list[int] | None = None - self.instance_queue: deque[MyopicIndex] = deque() # a LIFO queue - self.progress_mapper: MyopicProgressMapper | None = None + self.optimization_periods = None + self.instance_queue = deque() # a LIFO queue + self.progress_mapper = None self.config = config # allow a "shunt" (None) here so we can test parts of this by passing a None config if self.config: @@ -84,18 +99,18 @@ def __init__(self, config: TemoaConfig | None): self.cursor = self.output_con.cursor() self.table_writer = TableWriter(self.config) # break out what is needed from the config - myopic_options = config.myopic_inputs + myopic_options = config.myopic_inputs if config else None if not myopic_options: logger.error( 'The myopic mode was selected, but no options were received.\n %s', - config.myopic_inputs, + config.myopic_inputs if config else None, ) raise RuntimeError('No myopic options received. See log file.') else: - self.view_depth: int = myopic_options.get('view_depth') + self.view_depth = int(cast(Any, myopic_options.get('view_depth'))) if not isinstance(self.view_depth, int) or self.view_depth < 1: raise ValueError(f'view_depth is not a positive integer {self.view_depth}') - self.step_size: int = myopic_options.get('step_size') + self.step_size = int(cast(Any, myopic_options.get('step_size'))) if not isinstance(self.step_size, int) or self.step_size < 1: raise ValueError(f'step_size is not a positive integer {self.step_size}') if self.step_size > self.view_depth: @@ -104,8 +119,8 @@ def __init__(self, config: TemoaConfig | None): f'is larger than the view depth ({self.view_depth}). ' f'Check config' ) - self.evolving: bool = myopic_options.get('evolving') - self.evolution_script: str = myopic_options.get('evolution_script') + self.evolving = bool(myopic_options.get('evolving')) + self.evolution_script = str(myopic_options.get('evolution_script') or '') else: # A None was passed for config and the caller is responsible for setting instance vars pass @@ -115,6 +130,8 @@ def get_connection(self) -> Connection: Get a connection to the output database :return: a database connection """ + if self.config is None: + raise RuntimeError('Config is not initialized') input_file = self.config.input_database output_db = self.config.output_database @@ -147,7 +164,7 @@ def get_connection(self) -> Connection: return con - def start(self): + def start(self) -> None: # load up the instance queue self.characterize_run() @@ -178,6 +195,10 @@ def start(self): last_instance_status = None # solve status last_base_year = None idx: MyopicIndex | None = None # just a type-hint + + if self.config is None: + raise RuntimeError('Config is not initialized') + logger.info('Starting Myopic Sequence') # 1, 2, 3... while len(self.instance_queue) > 0: @@ -187,6 +208,10 @@ def start(self): elif last_instance_status == 'optimal': idx = self.instance_queue.pop() elif last_instance_status == 'roll_back': + if self.optimization_periods is None: + raise RuntimeError('optimization_periods not initialized') + if idx is None: + raise RuntimeError('idx is None') curr_start_idx = self.optimization_periods.index(idx.base_year) new_start_idx = curr_start_idx - 1 # back up 1 increment, expanding the window if new_start_idx < 0: @@ -218,7 +243,7 @@ def start(self): ) # 5. update the myopic_efficiency table so it is ready for the upcoming data pull. - if not self.config.silent: + if not self.config.silent and self.progress_mapper: self.progress_mapper.report(idx, 'load') self.update_myopic_efficiency_table(myopic_index=idx, prev_base=last_base_year) @@ -238,7 +263,7 @@ def start(self): ) # 8. Run checks... - if not self.config.silent: + if not self.config.silent and self.progress_mapper: self.progress_mapper.report(idx, 'check') if self.config.price_check: good_prices = price_checker(instance) @@ -246,7 +271,7 @@ def start(self): print('\nWarning: Cost anomalies discovered. Check log file for details.') # 9. Run the model and assess solve status - if not self.config.silent: + if not self.config.silent and self.progress_mapper: self.progress_mapper.report(idx, 'solve') model, results = run_actions.solve_instance( instance=instance, solver_name=self.config.solver_name, silent=True @@ -269,7 +294,7 @@ def start(self): # backtracking... self.clear_results_after(idx.base_year) # add the new results... - if not self.config.silent: + if not self.config.silent and self.progress_mapper: self.progress_mapper.report(idx, 'report') # write results by appending. We have already cleared necessary items self.table_writer.write_results(model=model, append=True) @@ -307,7 +332,7 @@ def start(self): excel_filename = self.config.output_path / self.config.scenario make_excel(str(self.config.output_database), excel_filename, temp_scenario) - def initialize_myopic_efficiency_table(self): + def initialize_myopic_efficiency_table(self) -> None: """ create a new myopic_efficiency table and pre-load it with all existing_capacity :return: @@ -393,8 +418,9 @@ def run_evolution_script( logger.error(msg) raise AttributeError(msg) - if not self.config.silent: - self.progress_mapper.report(idx, 'evolve') + if self.config and not self.config.silent: + if self.progress_mapper and idx: + self.progress_mapper.report(idx, 'evolve') iterate( idx=idx, @@ -404,7 +430,9 @@ def run_evolution_script( ) - def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: int): + def update_myopic_efficiency_table( + self, myopic_index: 'MyopicIndex', prev_base: int | None + ) -> None: """ This function adds to the myopic_efficiency table in the db with data specific to the current MyopicIndex timeframe. Basically: prep it for the current iteration. @@ -458,6 +486,7 @@ def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: i 'AND tech not in (SELECT tech FROM main.technology where unlim_cap > 0)' ) + scenario_name = self.config.scenario if self.config else None if self.debugging: debug_query = ( 'SELECT * FROM myopic_efficiency ' @@ -469,13 +498,13 @@ def update_myopic_efficiency_table(self, myopic_index: MyopicIndex, prev_base: i print('\n\n **** Removing these unused region-tech-vintage combos ****') removals = self.cursor.execute( debug_query, - (last_interval_end, self.config.scenario, self.capacity_epsilon), + (last_interval_end, scenario_name, self.capacity_epsilon), ).fetchall() for i, removal in enumerate(removals): print(f'{i}. Removing: {removal}') self.cursor.execute( delete_qry, - (last_interval_end, self.config.scenario, self.capacity_epsilon), + (last_interval_end, scenario_name, self.capacity_epsilon), ) self.output_con.commit() @@ -523,10 +552,10 @@ def characterize_run(self, future_periods: list[int] | None = None) -> None: :return: """ if not future_periods: - future_periods = self.cursor.execute( + rows = self.cursor.execute( "SELECT period FROM main.time_period WHERE flag = 'f'" ).fetchall() - future_periods = sorted(t[0] for t in future_periods) + future_periods = sorted(row[0] for row in rows) # set up the progress mapper self.progress_mapper = MyopicProgressMapper(future_periods) @@ -577,7 +606,7 @@ def characterize_run(self, future_periods: list[int] | None = None) -> None: logger.debug('Added myopic index %s', myopic_idx) logger.info('myopic run is divided into %d instances', len(self.instance_queue)) - def execute_script(self, script_file: Path): + def execute_script(self, script_file: Path) -> None: """ A utility to execute a sql script on the current db connection :return: @@ -588,12 +617,12 @@ def execute_script(self, script_file: Path): self.cursor.executescript(sql_commands) self.output_con.commit() - def clear_old_results(self): + def clear_old_results(self) -> None: """ Clear old results from tables :return: """ - scenario_name = self.config.scenario + scenario_name = self.config.scenario if self.config else None logger.debug('Deleting old results for scenario name %s', scenario_name) for table in self.tables_with_scenario_reference: try: @@ -612,12 +641,14 @@ def clear_old_results(self): raise sqlite3.OperationalError from e self.output_con.commit() - def clear_results_after(self, period): + def clear_results_after(self, period: int) -> None: """ clear the results tables for the periods on/after the period specified :param period: the starting period to clear :return: """ + if self.optimization_periods is None: + raise RuntimeError('Optimization periods not initialized') if period not in self.optimization_periods: logger.error( 'Tried to clear period results for %s that is not in %s', @@ -628,24 +659,26 @@ def clear_results_after(self, period): logger.debug('Clearing periods %s+ from output tables', period) for table in self.tables_with_period: + scenario_name = self.config.scenario if self.config else None try: self.cursor.execute( f'DELETE FROM {table} WHERE period >= (?) and scenario = (?)', - (period, self.config.scenario), + (period, scenario_name), ) except sqlite3.OperationalError as e: sys.stderr.write(f'Failed to clear periods from table {table}.\n') raise sqlite3.OperationalError from e # special case... new capacity has vintage only... + scenario_name = self.config.scenario if self.config else None self.cursor.execute( 'DELETE FROM main.output_built_capacity WHERE ' 'main.output_built_capacity.vintage >= (?) AND scenario = (?)', - (period, self.config.scenario), + (period, scenario_name), ) self.output_con.commit() - def __del__(self): + def __del__(self) -> None: """ensure the connection is closed when destructor is called.""" if ( hasattr(self, 'output_con') and self.output_con is not None diff --git a/temoa/extensions/single_vector_mga/output_summary.py b/temoa/extensions/single_vector_mga/output_summary.py index 0c5cf778c..713e65985 100644 --- a/temoa/extensions/single_vector_mga/output_summary.py +++ b/temoa/extensions/single_vector_mga/output_summary.py @@ -1,49 +1,55 @@ """ A tabular summation of the results from an SVMGA run """ +from __future__ import annotations import sqlite3 -from sqlite3 import Connection +from typing import TYPE_CHECKING, Any, cast -import tabulate +if TYPE_CHECKING: + from collections.abc import Iterable -from temoa.core.config import TemoaConfig + from temoa.core.config import TemoaConfig + + +import tabulate # type: ignore[import-untyped] def summarize(config: TemoaConfig, orig_cost: float, option_cost: float) -> None: scenarios = (config.scenario + '-0', config.scenario + '-1') - emission_labels = config.svmga_inputs.get('emission_labels', []) - capacity_labels = config.svmga_inputs.get('capacity_labels', []) - activity_labels = config.svmga_inputs.get('activity_labels', []) + svmga_inputs = config.svmga_inputs or {} + emission_labels = svmga_inputs.get('emission_labels', []) + capacity_labels = svmga_inputs.get('capacity_labels', []) + activity_labels = svmga_inputs.get('activity_labels', []) conn = sqlite3.connect(config.output_database) - records = [['Category', 'Label', 'Original', 'Option', 'Delta [%]']] - delta = (option_cost - orig_cost) / orig_cost * 100 - records.append(['Cost', 'Total Cost', orig_cost, option_cost, delta]) + records: list[list[Any]] = [['Category', 'Label', 'Original', 'Option', 'Delta [%]']] + total_delta = (option_cost - orig_cost) / orig_cost * 100 + records.append(['Cost', 'Total Cost', orig_cost, option_cost, total_delta]) - for item in sorted(emission_labels): + for item in sorted(cast('Iterable[Any]', emission_labels)): orig = poll_emission( conn, scenarios[0], item, ) option = poll_emission(conn, scenarios[1], item) - delta = float((option - orig) / orig * 100) if all((orig, option)) else None - records.append(['Emission', item, orig, option, delta]) - for item in sorted(activity_labels): + row_delta = float((option - orig) / orig * 100) if all((orig, option)) else None + records.append(['Emission', item, orig, option, row_delta]) + for item in sorted(cast('Iterable[Any]', activity_labels)): orig = poll_activity(conn, scenarios[0], item) option = poll_activity(conn, scenarios[1], item) - delta = (option - orig) / orig * 100 if all((orig, option)) else None + row_delta = (option - orig) / orig * 100 if all((orig, option)) else None - records.append(['Activity', item, orig, option, delta]) + records.append(['Activity', item, orig, option, row_delta]) - for item in sorted(capacity_labels): + for item in sorted(cast('Iterable[Any]', capacity_labels)): orig = poll_capacity(conn, scenarios[0], item) option = poll_capacity(conn, scenarios[1], item) - delta = (option - orig) / orig * 100 if all((orig, option)) else None + row_delta = (option - orig) / orig * 100 if all((orig, option)) else None - records.append(['Capacity', item, orig, option, delta]) + records.append(['Capacity', item, orig, option, row_delta]) print() print(tabulate.tabulate(records, headers='firstrow', tablefmt='outline', floatfmt='.2f')) @@ -55,34 +61,34 @@ def summarize(config: TemoaConfig, orig_cost: float, option_cost: float) -> None conn.close() -def poll_emission(conn: Connection, scenario: str, label: str) -> float: +def poll_emission(conn: sqlite3.Connection, scenario: str, label: str) -> float: """ poll the output database of selected iteration for the given emission label total """ - raw = conn.execute( - 'SELECT sum(emission) FROM main.output_emissionn WHERE scenario=? AND emis_comm=?', + row = conn.execute( + 'SELECT sum(emission) FROM main.output_emission WHERE scenario=? AND emis_comm=?', (scenario, label), - ).fetchone()[0] - return raw + ).fetchone() + return float(row[0] if row and row[0] is not None else 0.0) -def poll_activity(conn: Connection, scenario: str, label: str) -> float: +def poll_activity(conn: sqlite3.Connection, scenario: str, label: str) -> float: """ poll the Flow Out activity for the given emission label total """ - raw = conn.execute( + row = conn.execute( 'SELECT sum(flow) FROM main.output_flow_out WHERE scenario=? AND tech=?', (scenario, label), - ).fetchone()[0] - return raw + ).fetchone() + return float(row[0] if row and row[0] is not None else 0.0) -def poll_capacity(conn: Connection, scenario: str, label: str) -> float: +def poll_capacity(conn: sqlite3.Connection, scenario: str, label: str) -> float: """ poll the built capacity for the given emission label total """ - raw = conn.execute( + row = conn.execute( 'SELECT sum(capacity) FROM main.output_built_capacity WHERE scenario=? AND tech=?', (scenario, label), - ).fetchone()[0] - return raw + ).fetchone() + return float(row[0] if row and row[0] is not None else 0.0) diff --git a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py index 9f06570e2..311e765c8 100644 --- a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py +++ b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py @@ -9,9 +9,9 @@ import sqlite3 import sys from collections.abc import Iterable +from typing import TYPE_CHECKING, Any from pyomo.core import Constraint, Expression, Objective, value -from pyomo.dataportal import DataPortal from pyomo.opt import check_optimal_termination from temoa._internal.run_actions import build_instance, handle_results, save_lp, solve_instance @@ -23,6 +23,9 @@ from temoa.extensions.single_vector_mga.output_summary import summarize from temoa.model_checking.pricing_check import price_checker +if TYPE_CHECKING: + from pyomo.dataportal import DataPortal + logger = logging.getLogger(__name__) @@ -46,12 +49,13 @@ def __init__(self, config: TemoaConfig): self.writer.clear_scenario() self.verbose = False # for troubleshooting - self.cost_epsilon = config.svmga_inputs.get('cost_epsilon', 0.05) + svmga_inputs = config.svmga_inputs or {} + self.cost_epsilon: float = float(svmga_inputs.get('cost_epsilon', 0.05)) # type: ignore[arg-type] logger.info('Set SVMGA cost (relaxation) epsilon to: %0.3f', self.cost_epsilon) logger.info('Initialized SVMGA sequencer.') - def start(self): + def start(self) -> None: """Run the sequencer... This should look pretty similar to 2 PF runs, back-to-back @@ -118,11 +122,15 @@ def start(self): instance.del_component(instance.total_cost) # 4. Reconstruct the OBJ function... - emission_labels = self.config.svmga_inputs.get('emission_labels', []) - capacity_labels = self.config.svmga_inputs.get('capacity_labels', []) - activity_labels = self.config.svmga_inputs.get('activity_labels', []) + svmga_inputs = self.config.svmga_inputs or {} + emission_labels = svmga_inputs.get('emission_labels', []) + capacity_labels = svmga_inputs.get('capacity_labels', []) + activity_labels = svmga_inputs.get('activity_labels', []) new_obj = SvMgaSequencer.construct_obj( - instance, emission_labels, capacity_labels, activity_labels + instance, + emission_labels, # type: ignore[arg-type] + capacity_labels, # type: ignore[arg-type] + activity_labels, # type: ignore[arg-type] ) # check for an empty objective @@ -171,7 +179,9 @@ def start(self): summarize(self.config, tot_cost, value(total_cost_rule(instance))) @staticmethod - def flow_idxs_from_eac_idx(model: TemoaModel, reitvo: tuple) -> tuple[list[tuple], ...]: + def flow_idxs_from_eac_idx( + model: TemoaModel, reitvo: tuple[Any, ...] + ) -> tuple[list[tuple[Any, ...]], list[tuple[Any, ...]]]: """ From the emission index, expand to create the full list of possible flow indices for regular and annual flows. These may/may not be valid and must be screened @@ -195,7 +205,7 @@ def construct_obj( emission_labels: Iterable[str], capacity_labels: Iterable[str], activity_labels: Iterable[str], - verbose=True, + verbose: bool = True, ) -> Expression | int: """ Construct an alternative OBJ statement from the config data diff --git a/temoa/extensions/stochastics/scenario_creator.py b/temoa/extensions/stochastics/scenario_creator.py index 9055d8c2e..1ff997b4c 100644 --- a/temoa/extensions/stochastics/scenario_creator.py +++ b/temoa/extensions/stochastics/scenario_creator.py @@ -1,9 +1,10 @@ +from __future__ import annotations + import logging import sqlite3 -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, cast -import pyomo.environ as pyo -from mpisppy.utils.sputils import attach_root_node +from mpisppy.utils.sputils import attach_root_node # type: ignore[import-untyped] from temoa._internal.run_actions import build_instance from temoa.components.costs import period_cost_rule @@ -11,12 +12,13 @@ if TYPE_CHECKING: from temoa.core.config import TemoaConfig + from temoa.data_io.hybrid_loader import LoadItem from temoa.extensions.stochastics.stochastic_config import StochasticConfig logger = logging.getLogger(__name__) -def scenario_creator(scenario_name: str, **kwargs: Any) -> pyo.ConcreteModel: +def scenario_creator(scenario_name: str, **kwargs: Any) -> Any: """ Creator for mpi-sppy scenarios. @@ -38,10 +40,11 @@ def scenario_creator(scenario_name: str, **kwargs: Any) -> pyo.ConcreteModel: # Build a map of table -> index columns from the manifest # For each LoadItem, the index columns are all but the last one (which is the value) - table_index_map = {} + table_index_map: dict[str, list[str]] = {} + item: LoadItem for item in hybrid_loader.manifest: if item.table not in table_index_map and item.columns: - table_index_map[item.table] = item.columns[:-1] + table_index_map[item.table] = list(item.columns[:-1]) except Exception as e: logger.exception('Failed to connect to database %s', temoa_config.input_database) raise RuntimeError(f'Failed to connect to database {temoa_config.input_database}') from e @@ -51,7 +54,7 @@ def scenario_creator(scenario_name: str, **kwargs: Any) -> pyo.ConcreteModel: if p.scenario != scenario_name: continue - target_param = data_dict.get(p.table) + target_param = cast('dict[Any, Any] | None', data_dict.get(p.table)) if target_param is None: logger.warning( 'Table %s not found in data_dict for scenario %s', p.table, scenario_name diff --git a/temoa/extensions/stochastics/stochastic_config.py b/temoa/extensions/stochastics/stochastic_config.py index fb69ceeca..a46df1e32 100644 --- a/temoa/extensions/stochastics/stochastic_config.py +++ b/temoa/extensions/stochastics/stochastic_config.py @@ -1,8 +1,12 @@ +from __future__ import annotations + import logging import tomllib from dataclasses import dataclass, field -from pathlib import Path -from typing import Any +from typing import TYPE_CHECKING, Any, Self + +if TYPE_CHECKING: + from pathlib import Path logger = logging.getLogger(__name__) @@ -31,7 +35,7 @@ class StochasticConfig: @classmethod - def from_toml(cls, path: Path) -> 'StochasticConfig': + def from_toml(cls, path: Path) -> Self: with open(path, 'rb') as f: data = tomllib.load(f) diff --git a/temoa/extensions/stochastics/stochastic_sequencer.py b/temoa/extensions/stochastics/stochastic_sequencer.py index 1ff7d7727..07430cd49 100644 --- a/temoa/extensions/stochastics/stochastic_sequencer.py +++ b/temoa/extensions/stochastics/stochastic_sequencer.py @@ -1,11 +1,15 @@ +from __future__ import annotations + import logging -from typing import Any +from typing import TYPE_CHECKING import pyomo.environ as pyo -from temoa.core.config import TemoaConfig from temoa.extensions.stochastics.stochastic_config import StochasticConfig +if TYPE_CHECKING: + from temoa.core.config import TemoaConfig + logger = logging.getLogger(__name__) @@ -37,7 +41,7 @@ def start(self) -> None: Execute the stochastic run. """ try: - from mpisppy.opt.ef import ExtensiveForm + from mpisppy.opt.ef import ExtensiveForm # type: ignore[import-untyped] except ImportError as e: logger.exception('mpi-sppy is not installed. Please install it to use stochastic mode.') raise RuntimeError('mpi-sppy not found') from e From 6a0ef526692d06fd8d534e45695e40a7f1f10568 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 24 Mar 2026 11:58:36 -0400 Subject: [PATCH 508/587] improving robustness and type safety of extensions --- temoa/extensions/get_comm_tech.py | 4 +- temoa/extensions/method_of_morris/morris.py | 136 ++++++++--------- .../method_of_morris/morris_evaluate.py | 4 +- .../method_of_morris/morris_sequencer.py | 2 +- .../modeling_to_generate_alternatives/hull.py | 10 +- .../mga_sequencer.py | 6 +- .../tech_activity_vector_manager.py | 2 +- temoa/extensions/monte_carlo/mc_run.py | 16 +- temoa/extensions/monte_carlo/mc_sequencer.py | 3 +- temoa/extensions/monte_carlo/mc_worker.py | 7 +- .../myopic/myopic_progress_mapper.py | 6 +- temoa/extensions/myopic/myopic_sequencer.py | 140 +++++++++++++----- .../single_vector_mga/output_summary.py | 6 +- .../single_vector_mga/sv_mga_sequencer.py | 8 +- .../stochastics/scenario_creator.py | 16 +- .../stochastics/stochastic_sequencer.py | 4 +- 16 files changed, 228 insertions(+), 142 deletions(-) diff --git a/temoa/extensions/get_comm_tech.py b/temoa/extensions/get_comm_tech.py index 38cdd9468..8c7167c28 100644 --- a/temoa/extensions/get_comm_tech.py +++ b/temoa/extensions/get_comm_tech.py @@ -32,7 +32,7 @@ def get_tperiods(inp_f: str) -> dict[str, list[int]]: x.append(row[0]) for y in x: cur.execute( - f"SELECT DISTINCT period FROM output_flow_out WHERE scenario is '{y}'" + 'SELECT DISTINCT period FROM output_flow_out WHERE scenario = ?', (y,) ) periods_list[y] = [] for per in cur: @@ -206,7 +206,7 @@ def is_db_overwritten(db_file: str, inp_dat_file: str) -> bool: try: con = sqlite3.connect(db_file) - except Exception: + except sqlite3.Error: return False cur = con.cursor() # A database cursor enables traversal over DB records con.text_factory = str # This ensures data is explored with UTF-8 encoding diff --git a/temoa/extensions/method_of_morris/morris.py b/temoa/extensions/method_of_morris/morris.py index 3d9f8b251..6af977a56 100644 --- a/temoa/extensions/method_of_morris/morris.py +++ b/temoa/extensions/method_of_morris/morris.py @@ -52,7 +52,7 @@ def evaluate(param_names: dict[int, list[Any]], param_values: Any, output_query = cur.fetchall() for row in output_query: y_of = row[-1] - cur.execute("SELECT emis_comm, SUM(emission) FROM output_emissionn WHERE emis_comm='co2'") + cur.execute("SELECT emis_comm, SUM(emission) FROM output_emission WHERE emis_comm='co2'") output_query = cur.fetchall() for row in output_query: y_cumulative_co2 = row[-1] @@ -142,71 +142,71 @@ def evaluate(param_names: dict[int, list[Any]], param_values: Any, loader.load_data_portal() data = loader.data -problem = read_param_file(str(param_file), delimiter=' ') -param_values = sample( - problem, N=10, num_levels=8, optimal_trajectories=False, local_optimization=False, seed=seed -) -print(param_values) -print(param_names) -n = len(param_values) -# pull the data - -num_cores = 1 # multiprocessing.cpu_count() -Morris_Objectives = Parallel(n_jobs=num_cores)( - delayed(evaluate)(param_names, param_values[i, :], data, i) for i in range(0, n) -) -Morris_Objectives = array(Morris_Objectives) -print(Morris_Objectives) -si_of = morris.analyze( - problem, - param_values, - Morris_Objectives[:, 0], - conf_level=0.95, - print_to_console=False, - num_levels=8, - num_resamples=1000, - seed=seed + 1, -) - -si_cumulative_co2 = morris.analyze( - problem, - param_values, - Morris_Objectives[:, 1], - conf_level=0.95, - print_to_console=False, - num_levels=8, - num_resamples=1000, - seed=seed + 2, -) -num_vars = problem['num_vars'] -groups, unique_group_names = compute_groups_matrix(problem['groups']) -number_of_groups = len(unique_group_names) -print( - '{:<30} {:>10} {:>10} {:>15} {:>10}'.format( - 'Parameter', 'Mu_Star', 'Mu', 'Mu_Star_Conf', 'Sigma' - ) -) -for j in list(range(number_of_groups)): - print( - '{:30} {:10.3f} {:10.3f} {:15.3f} {:10.3f}'.format( - si_of['names'][j], - si_of['mu_star'][j], - si_of['mu'][j], - si_of['mu_star_conf'][j], - si_of['sigma'][j], + problem = read_param_file(str(param_file), delimiter=' ') + param_values = sample( + problem, N=10, num_levels=8, optimal_trajectories=False, local_optimization=False, seed=seed ) - ) - -line1 = si_of['mu_star'] -line2 = si_of['mu_star_conf'] -line3 = si_cumulative_co2['mu_star'] -line4 = si_cumulative_co2['mu_star_conf'] -with open('MMResults.csv', 'w') as f: - writer = csv.writer(f, delimiter=',') - writer.writerow(unique_group_names) - writer.writerow('Objective Function') - writer.writerow(line1) - writer.writerow(line2) - writer.writerow('Cumulative CO2 Emissions') - writer.writerow(line3) - writer.writerow(line4) + print(param_values) + print(param_names) + n = len(param_values) + + # pull the data + num_cores = 1 # multiprocessing.cpu_count() + Morris_Objectives = Parallel(n_jobs=num_cores)( + delayed(evaluate)(param_names, param_values[i, :], data, i) for i in range(0, n) + ) + + Morris_Objectives = array(Morris_Objectives) + print(Morris_Objectives) + si_of = morris.analyze( + problem, + param_values, + Morris_Objectives[:, 0], + conf_level=0.95, + print_to_console=False, + num_levels=8, + num_resamples=1000, + seed=seed + 1, + ) + + si_cumulative_co2 = morris.analyze( + problem, + param_values, + Morris_Objectives[:, 1], + conf_level=0.95, + print_to_console=False, + num_levels=8, + num_resamples=1000, + seed=seed + 2, + ) + groups, unique_group_names = compute_groups_matrix(problem['groups']) + number_of_groups = len(unique_group_names) + print( + '{:<30} {:>10} {:>10} {:>15} {:>10}'.format( + 'Parameter', 'Mu_Star', 'Mu', 'Mu_Star_Conf', 'Sigma' + ) + ) + for j in list(range(number_of_groups)): + print( + '{:30} {:10.3f} {:10.3f} {:15.3f} {:10.3f}'.format( + si_of['names'][j], + si_of['mu_star'][j], + si_of['mu'][j], + si_of['mu_star_conf'][j], + si_of['sigma'][j], + ) + ) + + line1 = si_of['mu_star'] + line2 = si_of['mu_star_conf'] + line3 = si_cumulative_co2['mu_star'] + line4 = si_cumulative_co2['mu_star_conf'] + with open('MMResults.csv', 'w') as f: + writer = csv.writer(f, delimiter=',') + writer.writerow(unique_group_names) + writer.writerow('Objective Function') + writer.writerow(line1) + writer.writerow(line2) + writer.writerow('Cumulative CO2 Emissions') + writer.writerow(line3) + writer.writerow(line4) diff --git a/temoa/extensions/method_of_morris/morris_evaluate.py b/temoa/extensions/method_of_morris/morris_evaluate.py index de8360c4e..6104d80cf 100644 --- a/temoa/extensions/method_of_morris/morris_evaluate.py +++ b/temoa/extensions/method_of_morris/morris_evaluate.py @@ -88,7 +88,7 @@ def evaluate(param_info: dict[int, list[Any]], mm_sample: Any, data: dict[str, A 'Multiple outputs found in Objective table matching scenario name. Coding error.' ) else: - y_of = output_query[0][0] + y_of = output_query[0][0] if output_query[0][0] is not None else 0.0 cur.execute( "SELECT SUM(emission) FROM output_emission WHERE emis_comm='co2' AND scenario=?", (scenario_name,), @@ -102,7 +102,7 @@ def evaluate(param_info: dict[int, list[Any]], mm_sample: Any, data: dict[str, A 'error.' ) else: - y_cumulative_co2 = output_query[0][0] + y_cumulative_co2 = output_query[0][0] if output_query[0][0] is not None else 0.0 morris_objectives = [float(y_of), float(y_cumulative_co2)] logger.info('Finished MM evaluation # %d with OBJ value: %0.2f ', i + 1, y_of) if not config.silent: diff --git a/temoa/extensions/method_of_morris/morris_sequencer.py b/temoa/extensions/method_of_morris/morris_sequencer.py index 92481f5d4..fd2c6ce5e 100644 --- a/temoa/extensions/method_of_morris/morris_sequencer.py +++ b/temoa/extensions/method_of_morris/morris_sequencer.py @@ -118,7 +118,7 @@ def __init__(self, config: TemoaConfig): # aren't super) seed = morris_inputs.get('seed') - self.seed = int(cast('Any', seed)) if seed else None + self.seed = int(cast('Any', seed)) if seed is not None else None logger.info('Morris Seed (None indicates system generated): %s', self.seed) self.conf_level = 0.95 # confidence level for mu_star analysis diff --git a/temoa/extensions/modeling_to_generate_alternatives/hull.py b/temoa/extensions/modeling_to_generate_alternatives/hull.py index 22b23505b..d0f79c132 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/hull.py +++ b/temoa/extensions/modeling_to_generate_alternatives/hull.py @@ -118,12 +118,12 @@ def update(self) -> None: def add_point(self, point: np.ndarray) -> None: if len(point) != self.dim: - logger.error( - 'Tried adding a point to hull (dim: %d) with wrong dimensions %d. Point: %s', - self.dim, - len(point), - point, + msg = ( + f'Tried adding a point to hull (dim: {self.dim}) with wrong dimensions {len(point)}. ' + f'Point: {point}' ) + logger.error(msg) + raise ValueError(msg) if self.all_points is None: self.all_points = np.atleast_2d(point) else: diff --git a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py index 098db7c14..83b228fec 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py +++ b/temoa/extensions/modeling_to_generate_alternatives/mga_sequencer.py @@ -374,4 +374,8 @@ def process_solve_results(self, instance: TemoaModel) -> None: self.writer.write_summary_flow(instance, iteration=idx) def __del__(self) -> None: - self.con.close() + if hasattr(self, 'con') and self.con is not None: + try: + self.con.close() + except Exception: + pass diff --git a/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py b/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py index cf6b3fa3d..62f9a99a4 100644 --- a/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py +++ b/temoa/extensions/modeling_to_generate_alternatives/tech_activity_vector_manager.py @@ -145,7 +145,7 @@ def expired(self) -> bool: return False # this Manager can always generate more... def group_variable_names(self, tech: str) -> list[str]: - return [str(k) for k in self.category_mapping.keys()] + return list(self.variable_index_mapping.get(tech, {}).keys()) def random_input_vector_model(self) -> TemoaModel: new_model = self.base_model.clone() diff --git a/temoa/extensions/monte_carlo/mc_run.py b/temoa/extensions/monte_carlo/mc_run.py index dc4063460..7c2874a7a 100644 --- a/temoa/extensions/monte_carlo/mc_run.py +++ b/temoa/extensions/monte_carlo/mc_run.py @@ -7,7 +7,7 @@ from itertools import product from logging import getLogger from pathlib import Path -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, cast from temoa.core.model import TemoaModel from temoa.data_io.hybrid_loader import HybridLoader @@ -225,7 +225,19 @@ def __init__(self, config: TemoaConfig, data_store: dict[str, Any]): self.config = config self.data_store = data_store self.tweak_factory = TweakFactory(data_store) - self.settings_file = Path(self.config.monte_carlo_inputs['run_settings']) # type: ignore + + if not config.monte_carlo_inputs: + raise ValueError("Monte Carlo mode requires 'monte_carlo_inputs' in the configuration.") + + settings_path = config.monte_carlo_inputs.get('run_settings') + if not settings_path: + raise ValueError( + "Monte Carlo mode requires 'run_settings' path in 'monte_carlo_inputs'." + ) + + self.settings_file = Path(cast(str, settings_path)) + if not self.settings_file.exists(): + raise FileNotFoundError(f'Monte Carlo run settings file not found: {self.settings_file}') def prescreen_input_file(self) -> bool: """ diff --git a/temoa/extensions/monte_carlo/mc_sequencer.py b/temoa/extensions/monte_carlo/mc_sequencer.py index c44c1779d..b770bbdab 100644 --- a/temoa/extensions/monte_carlo/mc_sequencer.py +++ b/temoa/extensions/monte_carlo/mc_sequencer.py @@ -164,9 +164,10 @@ def start(self) -> None: results_queue=result_queue, log_root_name=__name__, log_queue=log_queue, + solver_name=self.config.solver_name, + solver_options=self.worker_solver_options, log_level=logging.INFO, solver_log_path=s_path, - **kwargs, ) p: BaseProcess = ctx.Process(target=w.run, daemon=True) p.start() diff --git a/temoa/extensions/monte_carlo/mc_worker.py b/temoa/extensions/monte_carlo/mc_worker.py index 9d5fed2bc..7bf987ea9 100644 --- a/temoa/extensions/monte_carlo/mc_worker.py +++ b/temoa/extensions/monte_carlo/mc_worker.py @@ -49,16 +49,17 @@ def __init__( results_queue: Queue[DataBrick | str], log_root_name: str, log_queue: Queue[logging.LogRecord], + solver_name: str, + solver_options: dict[str, Any], log_level: int = logging.INFO, solver_log_path: Path | None = None, - **kwargs: Any, ): self.worker_number = MCWorker.worker_idx MCWorker.worker_idx += 1 self.dp_queue = dp_queue self.results_queue = results_queue - self.solver_name = kwargs['solver_name'] - self.solver_options = kwargs['solver_options'] + self.solver_name = solver_name + self.solver_options = solver_options self.opt = None # Initialize in run() self.log_queue = log_queue self.log_level = log_level diff --git a/temoa/extensions/myopic/myopic_progress_mapper.py b/temoa/extensions/myopic/myopic_progress_mapper.py index 13e0232fc..3dc3c2955 100644 --- a/temoa/extensions/myopic/myopic_progress_mapper.py +++ b/temoa/extensions/myopic/myopic_progress_mapper.py @@ -4,6 +4,8 @@ from datetime import datetime, timedelta +from typing import Literal + from temoa.extensions.myopic.myopic_index import MyopicIndex @@ -49,7 +51,9 @@ def timestamp(self) -> str: f'{int(delta.total_seconds()%3600//60):02d}:{int(delta.total_seconds())%60:02d} ' ) - def report(self, mi: MyopicIndex, status: str) -> None: + def report( + self, mi: MyopicIndex, status: Literal['load', 'solve', 'report', 'check', 'evolve'] + ) -> None: if status not in {'load', 'solve', 'report', 'check', 'evolve'}: raise ValueError(f'bad status: {status} received in MyopicProgressMapper') diff --git a/temoa/extensions/myopic/myopic_sequencer.py b/temoa/extensions/myopic/myopic_sequencer.py index 3b46c53ba..d7f9601df 100644 --- a/temoa/extensions/myopic/myopic_sequencer.py +++ b/temoa/extensions/myopic/myopic_sequencer.py @@ -70,11 +70,13 @@ class MyopicSequencer: instance_queue: deque[MyopicIndex] progress_mapper: MyopicProgressMapper | None config: TemoaConfig | None - output_con: Connection - cursor: Cursor - table_writer: TableWriter - view_depth: int - step_size: int + # these are initialized during characterize_run() + output_con: sqlite3.Connection | None = None + cursor: sqlite3.Cursor | None = None + table_writer: TableWriter | None = None + view_depth: int | None = None + step_size: int | None = None + run_status: bool | None = None evolving: bool evolution_script: str @@ -165,6 +167,9 @@ def get_connection(self) -> Connection: return con def start(self) -> None: + if self.config is None: + raise RuntimeError('Config is not initialized') + # load up the instance queue self.characterize_run() @@ -178,27 +183,10 @@ def start(self) -> None: # start building the myopic_efficiency table. self.initialize_myopic_efficiency_table() - # start the fundamental control loop - # 1. get feedback from previous instance execution (optimal/infeasible/...) - # 2. decide what to do about it - # 3. pull the next instance from the queue (if !empty & if needed) - # 4. if evolving, call the evolution script and pass it the myopic index and last instance status - # 5. update the myopic_efficiency table (clean up history / add stuff now in visibility) - # 6. pull data for next run and filter it with source tracing - # 7. build instance - # 8. run checks (price check) on the model, if selected - # 9. run the model and assess - # 10. commit or back out any data as necessary - # 11. report findings - # 12. compact the db - last_instance_status = None # solve status last_base_year = None idx: MyopicIndex | None = None # just a type-hint - if self.config is None: - raise RuntimeError('Config is not initialized') - logger.info('Starting Myopic Sequence') # 1, 2, 3... while len(self.instance_queue) > 0: @@ -243,11 +231,12 @@ def start(self) -> None: ) # 5. update the myopic_efficiency table so it is ready for the upcoming data pull. - if not self.config.silent and self.progress_mapper: + if not self.config.silent and self.progress_mapper and idx: self.progress_mapper.report(idx, 'load') self.update_myopic_efficiency_table(myopic_index=idx, prev_base=last_base_year) # 6. pull the data + assert self.output_con is not None # make a data loader data_loader = HybridLoader(self.output_con, self.config) data_portal = data_loader.load_data_portal(myopic_index=idx) @@ -263,7 +252,7 @@ def start(self) -> None: ) # 8. Run checks... - if not self.config.silent and self.progress_mapper: + if not self.config.silent and self.progress_mapper and idx: self.progress_mapper.report(idx, 'check') if self.config.price_check: good_prices = price_checker(instance) @@ -271,7 +260,7 @@ def start(self) -> None: print('\nWarning: Cost anomalies discovered. Check log file for details.') # 9. Run the model and assess solve status - if not self.config.silent and self.progress_mapper: + if not self.config.silent and self.progress_mapper and idx: self.progress_mapper.report(idx, 'solve') model, results = run_actions.solve_instance( instance=instance, solver_name=self.config.solver_name, silent=True @@ -292,20 +281,23 @@ def start(self) -> None: # 10, 11. Update the output tables... # first, clear any possible previous results that overlap, we might have been # backtracking... - self.clear_results_after(idx.base_year) + if idx: + self.clear_results_after(idx.base_year) # add the new results... - if not self.config.silent and self.progress_mapper: + if not self.config.silent and self.progress_mapper and idx: self.progress_mapper.report(idx, 'report') # write results by appending. We have already cleared necessary items + assert self.table_writer is not None self.table_writer.write_results(model=model, append=True) # handle side-case for writing duals if self.config.save_duals: self.table_writer.write_dual_variables(results=results, iteration=idx.base_year) # prep next loop - last_base_year = idx.base_year # update + last_base_year = idx.base_year if idx else last_base_year # update # delete anything in the output_objective table, it is nonsensical... + assert self.output_con is not None self.output_con.execute( f'DELETE FROM output_objective WHERE scenario == "{self.config.scenario}"' ) @@ -315,14 +307,11 @@ def start(self) -> None: self.output_con.execute('VACUUM;') # Total system cost is, theoretically, sum of discounted costs from output_cost table - total_cost = self.output_con.execute( - 'SELECT SUM(d_invest)+SUM(d_fixed)+SUM(d_var)+SUM(d_emiss) FROM output_cost ' - f'WHERE scenario == "{self.config.scenario}"' - ).fetchone()[0] + total_cost = self.get_current_total_cost(last_base_year if last_base_year is not None else 0) + + assert self.output_con is not None self.output_con.execute( - f"""INSERT INTO - output_objective(scenario, objective_name, total_system_cost) - VALUES('{self.config.scenario}', 'total_cost', {total_cost})""" + f"INSERT INTO output_objective(scenario, objective_name, total_system_cost) VALUES('{self.config.scenario}', 'total_cost', {total_cost})" ) self.output_con.commit() @@ -332,12 +321,23 @@ def start(self) -> None: excel_filename = self.config.output_path / self.config.scenario make_excel(str(self.config.output_database), excel_filename, temp_scenario) + def get_current_total_cost(self, base_year: int) -> float: + assert self.output_con is not None + assert self.config is not None + total_cost = self.output_con.execute( + 'SELECT SUM(d_invest)+SUM(d_fixed)+SUM(d_var)+SUM(d_emiss) FROM output_cost ' + f'WHERE scenario == "{self.config.scenario}"' + ).fetchone()[0] + return float(total_cost) if total_cost is not None else 0.0 + def initialize_myopic_efficiency_table(self) -> None: """ create a new myopic_efficiency table and pre-load it with all existing_capacity :return: """ # clear out everything from previous runs + assert self.cursor is not None + assert self.output_con is not None self.cursor.execute('DELETE FROM myopic_efficiency WHERE 1') self.output_con.commit() @@ -429,7 +429,6 @@ def run_evolution_script( db_con=con, ) - def update_myopic_efficiency_table( self, myopic_index: 'MyopicIndex', prev_base: int | None ) -> None: @@ -465,6 +464,8 @@ def update_myopic_efficiency_table( # 0. Clear any future things past the base year for housekeeping # ease with steps, depth, etc. These may have been added if we are stepping less # than the previous solve depth or if backtracking. + assert self.cursor is not None + assert self.output_con is not None self.cursor.execute( 'DELETE FROM myopic_efficiency WHERE myopic_efficiency.vintage >= ?', (base,) ) @@ -502,6 +503,7 @@ def update_myopic_efficiency_table( ).fetchall() for i, removal in enumerate(removals): print(f'{i}. Removing: {removal}') + self.cursor.execute( delete_qry, (last_interval_end, scenario_name, self.capacity_epsilon), @@ -510,14 +512,13 @@ def update_myopic_efficiency_table( # 2. Add the new stuff now visible # dev note: the `coalesce()` command is a nested if-else. The first hit wins, so it is - # priority: process lifetime > tech lifetime > lifetime default - lifetime = TemoaModel.default_lifetime_tech + default_lifetime = TemoaModel.default_lifetime_tech query = ( 'INSERT INTO myopic_efficiency ' f'SELECT {base}, efficiency.region, input_comm, ' ' efficiency.tech, efficiency.vintage, output_comm, efficiency, ' f' coalesce(main.lifetime_process.lifetime, main.lifetime_tech.lifetime, ' - f'{lifetime}) AS lifetime ' + f'{default_lifetime}) AS lifetime ' ' FROM main.efficiency ' ' LEFT JOIN main.lifetime_process ' ' ON main.efficiency.tech = lifetime_process.tech ' @@ -552,6 +553,7 @@ def characterize_run(self, future_periods: list[int] | None = None) -> None: :return: """ if not future_periods: + assert self.cursor is not None rows = self.cursor.execute( "SELECT period FROM main.time_period WHERE flag = 'f'" ).fetchall() @@ -563,6 +565,8 @@ def characterize_run(self, future_periods: list[int] | None = None) -> None: self.progress_mapper.draw_header() # check that we have enough periods to do myopic run + if self.view_depth is None: + raise RuntimeError('view_depth not initialized') if len(future_periods) < self.view_depth + 1: msg = ( 'Not enough future periods for view depth. Need {} including end period. Got {}.' @@ -570,6 +574,8 @@ def characterize_run(self, future_periods: list[int] | None = None) -> None: logger.error(msg) raise RuntimeError(msg) self.optimization_periods = future_periods.copy() + if self.step_size is None: + raise RuntimeError('step_size not initialized') last_base_year = ((len(future_periods) - 2) // self.step_size) * self.step_size base_years = list(range(0, last_base_year+1, self.step_size)) if not self.evolving: @@ -614,6 +620,8 @@ def execute_script(self, script_file: Path) -> None: with open(script_file) as table_script: sql_commands = table_script.read() logger.debug('Executing sql from file: %s on connection: %s', script_file, self.output_con) + assert self.cursor is not None + assert self.output_con is not None self.cursor.executescript(sql_commands) self.output_con.commit() @@ -622,6 +630,8 @@ def clear_old_results(self) -> None: Clear old results from tables :return: """ + assert self.cursor is not None + assert self.output_con is not None scenario_name = self.config.scenario if self.config else None logger.debug('Deleting old results for scenario name %s', scenario_name) for table in self.tables_with_scenario_reference: @@ -641,6 +651,19 @@ def clear_old_results(self) -> None: raise sqlite3.OperationalError from e self.output_con.commit() + def cleanup_outputs_by_period(self, base_year: int) -> None: + assert self.output_con is not None + assert self.cursor is not None + assert self.progress_mapper is not None + assert self.config is not None + self.progress_mapper.report( + MyopicIndex(base_year, 0, 0, 0), 'check' + ) # reusing 'check' for lack of a better 'cleanup' status + self.output_con.execute( + f'DELETE FROM output_objective WHERE scenario == "{self.config.scenario}"' + ) + self.output_con.commit() + def clear_results_after(self, period: int) -> None: """ clear the results tables for the periods on/after the period specified @@ -658,6 +681,8 @@ def clear_results_after(self, period: int) -> None: raise ValueError(f'Trying to clear a year {period} that is not in the optimize periods') logger.debug('Clearing periods %s+ from output tables', period) + assert self.cursor is not None + assert self.output_con is not None for table in self.tables_with_period: scenario_name = self.config.scenario if self.config else None try: @@ -678,6 +703,43 @@ def clear_results_after(self, period: int) -> None: ) self.output_con.commit() + def report_total_demand(self, mi: MyopicIndex) -> None: + assert self.output_con is not None + assert self.cursor is not None + self.cursor.execute( + "SELECT SUM(demand) FROM output_demand WHERE scenario='original'" + ) + self.output_con.commit() + + def write_myopic_efficiency(self, mi: MyopicIndex, status: str) -> None: + assert self.output_con is not None + assert self.cursor is not None + self.cursor.execute( + 'SELECT COUNT(*) FROM myopic_efficiency WHERE base_year=? AND step_year=?', + (mi.base_year, mi.step_year), + ) + if self.cursor.fetchone()[0] == 0: + self.cursor.execute( + 'INSERT INTO myopic_efficiency ' + '(base_year, step_year, last_demand_year, last_year, status) ' + 'VALUES (?, ?, ?, ?, ?)', + (mi.base_year, mi.step_year, mi.last_demand_year, mi.last_year, status), + ) + else: + self.cursor.execute( + 'UPDATE myopic_efficiency SET status=? WHERE base_year=? AND step_year=?', + (status, mi.base_year, mi.step_year), + ) + self.output_con.commit() + + def report_cumulative_capacity(self, mi: MyopicIndex) -> None: + assert self.output_con is not None + assert self.cursor is not None + self.cursor.execute( + "SELECT SUM(capacity) FROM output_capacity WHERE scenario='original'" + ) + self.output_con.commit() + def __del__(self) -> None: """ensure the connection is closed when destructor is called.""" if ( diff --git a/temoa/extensions/single_vector_mga/output_summary.py b/temoa/extensions/single_vector_mga/output_summary.py index 713e65985..54e387b15 100644 --- a/temoa/extensions/single_vector_mga/output_summary.py +++ b/temoa/extensions/single_vector_mga/output_summary.py @@ -35,19 +35,19 @@ def summarize(config: TemoaConfig, orig_cost: float, option_cost: float) -> None item, ) option = poll_emission(conn, scenarios[1], item) - row_delta = float((option - orig) / orig * 100) if all((orig, option)) else None + row_delta = float((option - orig) / orig * 100) if orig != 0.0 else None records.append(['Emission', item, orig, option, row_delta]) for item in sorted(cast('Iterable[Any]', activity_labels)): orig = poll_activity(conn, scenarios[0], item) option = poll_activity(conn, scenarios[1], item) - row_delta = (option - orig) / orig * 100 if all((orig, option)) else None + row_delta = (option - orig) / orig * 100 if orig != 0.0 else None records.append(['Activity', item, orig, option, row_delta]) for item in sorted(cast('Iterable[Any]', capacity_labels)): orig = poll_capacity(conn, scenarios[0], item) option = poll_capacity(conn, scenarios[1], item) - row_delta = (option - orig) / orig * 100 if all((orig, option)) else None + row_delta = (option - orig) / orig * 100 if orig != 0.0 else None records.append(['Capacity', item, orig, option, row_delta]) diff --git a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py index 311e765c8..8498390bf 100644 --- a/temoa/extensions/single_vector_mga/sv_mga_sequencer.py +++ b/temoa/extensions/single_vector_mga/sv_mga_sequencer.py @@ -9,7 +9,7 @@ import sqlite3 import sys from collections.abc import Iterable -from typing import TYPE_CHECKING, Any +from typing import Any, cast, TYPE_CHECKING from pyomo.core import Constraint, Expression, Objective, value from pyomo.opt import check_optimal_termination @@ -128,9 +128,9 @@ def start(self) -> None: activity_labels = svmga_inputs.get('activity_labels', []) new_obj = SvMgaSequencer.construct_obj( instance, - emission_labels, # type: ignore[arg-type] - capacity_labels, # type: ignore[arg-type] - activity_labels, # type: ignore[arg-type] + cast('list[str]', emission_labels), + cast('list[str]', capacity_labels), + cast('list[str]', activity_labels), ) # check for an empty objective diff --git a/temoa/extensions/stochastics/scenario_creator.py b/temoa/extensions/stochastics/scenario_creator.py index 1ff997b4c..a75e70430 100644 --- a/temoa/extensions/stochastics/scenario_creator.py +++ b/temoa/extensions/stochastics/scenario_creator.py @@ -3,6 +3,7 @@ import logging import sqlite3 from typing import TYPE_CHECKING, Any, cast +from collections.abc import Iterable from mpisppy.utils.sputils import attach_root_node # type: ignore[import-untyped] @@ -41,8 +42,7 @@ def scenario_creator(scenario_name: str, **kwargs: Any) -> Any: # Build a map of table -> index columns from the manifest # For each LoadItem, the index columns are all but the last one (which is the value) table_index_map: dict[str, list[str]] = {} - item: LoadItem - for item in hybrid_loader.manifest: + for item in cast('Iterable[LoadItem]', hybrid_loader.manifest): if item.table not in table_index_map and item.columns: table_index_map[item.table] = list(item.columns[:-1]) except Exception as e: @@ -54,7 +54,7 @@ def scenario_creator(scenario_name: str, **kwargs: Any) -> Any: if p.scenario != scenario_name: continue - target_param = cast('dict[Any, Any] | None', data_dict.get(p.table)) + target_param = cast(dict[Any, Any] | None, data_dict.get(p.table)) if target_param is None: logger.warning( 'Table %s not found in data_dict for scenario %s', p.table, scenario_name @@ -72,8 +72,10 @@ def scenario_creator(scenario_name: str, **kwargs: Any) -> Any: ) continue - for idx_tuple, current_val in list(target_param.items()): + for idx, current_val in list(target_param.items()): # Map index tuple to names based on table manifest + # normalize idx to tuple if it is a single value + idx_tuple = idx if isinstance(idx, tuple) else (idx,) index_map = dict(zip(index_cols, idx_tuple, strict=True)) # Check if filter matches @@ -85,11 +87,11 @@ def scenario_creator(scenario_name: str, **kwargs: Any) -> Any: if match: if p.action == 'multiply': - target_param[idx_tuple] = current_val * p.value + target_param[idx] = current_val * p.value elif p.action == 'add': - target_param[idx_tuple] = current_val + p.value + target_param[idx] = current_val + p.value elif p.action == 'set': - target_param[idx_tuple] = p.value + target_param[idx] = p.value # 3. Build instance data_portal = HybridLoader.data_portal_from_data(data_dict) diff --git a/temoa/extensions/stochastics/stochastic_sequencer.py b/temoa/extensions/stochastics/stochastic_sequencer.py index 07430cd49..9950ee6cc 100644 --- a/temoa/extensions/stochastics/stochastic_sequencer.py +++ b/temoa/extensions/stochastics/stochastic_sequencer.py @@ -34,7 +34,7 @@ def __init__(self, config: TemoaConfig) -> None: self.stoch_config = StochasticConfig.from_toml(sc_path) except Exception as e: logger.exception('Failed to load stochastic config from %s', sc_path) - raise ValueError(f'Error parsing stochastic config {sc_path}') from e + raise ValueError(f'Error parsing stochastic config {sc_path}. Original error: {e}') from e def start(self) -> None: """ @@ -44,7 +44,7 @@ def start(self) -> None: from mpisppy.opt.ef import ExtensiveForm # type: ignore[import-untyped] except ImportError as e: logger.exception('mpi-sppy is not installed. Please install it to use stochastic mode.') - raise RuntimeError('mpi-sppy not found') from e + raise RuntimeError(f'mpi-sppy not found. Original error: {e}') from e from temoa.extensions.stochastics.scenario_creator import scenario_creator From 4f97ad665581bd20d9e8859619c3f7852af110ab Mon Sep 17 00:00:00 2001 From: Joe DeCarolis Date: Mon, 12 Jan 2026 08:16:01 -0500 Subject: [PATCH 509/587] Update descriptions of Temoa sets in documentation --- docs/source/db_model_comparison.rst | 114 ++++++++++++----------- docs/source/mathematical_formulation.rst | 21 +---- 2 files changed, 65 insertions(+), 70 deletions(-) diff --git a/docs/source/db_model_comparison.rst b/docs/source/db_model_comparison.rst index 9c5fe9fdf..7bb153ab6 100644 --- a/docs/source/db_model_comparison.rst +++ b/docs/source/db_model_comparison.rst @@ -1,84 +1,90 @@ -Database Tables vs Model Sets/Parameters Comparison -====================================================== - -Direct Mappings: Sets ---------------------- - -Time-Related Sets -^^^^^^^^^^^^^^^^^ +Our discussion of sets is broken down into several logical categories to make it +easier to parse. The first group of sets pertains to Temoa's treatment of time, +as shown below. **Note:** Some entries in the "Database Table" column are +comma-separated. In those cases, the first element refers to the name of the database +table, and the second refers to specific column within the database column used to +identify a specific subset. For example, in the first table below, :code:`time_period` +is the master set and :code:`time_exist` is a subset that defines the user-defined +model time periods to define historical technology vintages that exist prior to +the model's time horizon for optimization. + +Note: In instances where the "Database Table" column contains two comma-separated +elements, the first element refers to the name of the dtabase table and the second +refers to a specific column within the database table. .. csv-table:: - :header: "Set", "Database Table", "Model Element", "Notes" + :header: "Set", "Database Table", "Model Code", "Notes" :widths: 15, 20, 25, 40 - ":math:`\text{P}^e`", "time_period", "time_exist", "model periods before optimization begins; partitioned by period type flag" - ":math:`\text{P}^f`", "time_period", "time_future", "model time scale of interest; the last year is not optimized; partitioned by period type flag" - ":math:`{}^*\text{P}^o`", "time_period", "time_optimize", "model time periods to optimize; (:math:`\text{P}^f - \text{max}(\text{P}^f)`); partitioned by period type flag" - ":math:`{}^*\text{V}`", "time_period", "vintage_exist, vintage_optimize, vintage_all", "possible tech vintages; (:math:`\text{P}^e \cup \text{P}^o`); same data, used for vintage tracking" - ":math:`\text{D}`", "time_of_day", "time_of_day", "time-of-day divisions (e.g. morning); direct mapping" - ":math:`\text{S}`", "season_label", "time_season_all, time_season", "seasonal divisions (e.g. winter, summer); direct mapping" - "", "time_season", "time_season", "seasons by period" - "", "time_season_sequential", "time_season_to_sequential, ordered_season_sequential", "sequential season ordering" + ":math:`\text{P}^e`", ":code:`time_period, flag = e`", ":code:`time_exist`", "model periods prior to the beginning of the optimization time horizon" + ":math:`\text{P}^f`", ":code:`time_period, flag = f`", ":code:`time_future`", "model periods within the optimization time horizon" + ":math:`{}^*\text{P}^o`", ":code:`time_period`", ":code:`time_optimize`", "model time periods to optimize, (:math:`\text{P}^f - \text{max}(\text{P}^f)`); the last time period is removed as it represents the end of the final period" + ":math:`{}^*\text{V}`", ":code:`time_period`", ":code:`vintage_exist`, :code:`vintage_optimize`, :code:`vintage_all`", "tech vintages, (:math:`\text{P}^e \cup \text{P}^o`), derived from time period set" + ":math:`\text{D}`", ":code:`time_of_day`", ":code:`time_of_day`", "intraday time divisions" + ":math:`\text{S}`", ":code:`season_label`", ":code:`time_season`", "intra-annual divisions, e.g., different seasons or different representative days" + "", ":code:`time_season`", ":code:`time_season`", "ordered tuple of seasons by time period" + "", ":code:`time_season_sequential`", ":code:`time_season_to_sequential, ordered_season_sequential`", "NEED HELP" -Geography Sets -^^^^^^^^^^^^^^ +The sets in the table below define Temoa's representation of regions. .. csv-table:: :header: "Set", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`\text{R}`", "region", "regions", "distinct geographical regions; direct mapping" - "", "region", "regional_indices", "derived with exchange logic" - "", "region", "regional_global_indices", "regional groups" + ":math:`\text{R}`", ":code:`region`", ":code:`regions`", "distinct geographical regions; direct mapping" + "", ":code:`region`", ":code:`regional_indices`", "set of all the possible combinations of interregional exchanges plus original region indices" + "", ":code:`region`", ":code:`regional_global_indices`", "NEED HELP - is this set required? It appears to be deprecated?" -Technology Sets -^^^^^^^^^^^^^^^ +The sets below define how technologies are represented within Temoa. Because technologies +can serve many different functions across an energy system, we need to define a large +number of technology subsets. .. csv-table:: :header: "Set", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`{}^*\text{T}`", "technology", "tech_all", "all technologies to be modeled; (:math:`{T}^r \cup {T}^p`); all technologies" - ":math:`\text{T}^p`", "technology", "tech_production", "techs producing intermediate commodities" - ":math:`\text{T}^b`", "technology (flag='pb')", "tech_baseload", "baseload electric generators; (:math:`{T}^b \subset T`); filtered by flag" - ":math:`\text{T}^s`", "technology (flag='ps')", "tech_storage", "all storage technologies; (:math:`{T}^s \subset T`); filtered by flag" - ":math:`\text{T}^a`", "technology (annual=1)", "tech_annual", "technologies that produce constant annual output; (:math:`{T}^a \subset T`); filtered by annual flag" - ":math:`\text{T}^{res}`", "technology (reserve=1)", "tech_reserve", "electric generators contributing to the reserve margin requirement; (:math:`{T}^{res} \subset T`); filtered by reserve flag" - ":math:`\text{T}^c`", "technology (curtail=1)", "tech_curtailment", "technologies with curtailable output and no upstream cost; (:math:`{T}^c \subset (T - T^{res})`); filtered by curtail flag" - ":math:`\text{T}^f`", "technology (flex=1)", "tech_flex", "technologies producing excess commodity flows; (:math:`{T}^f \subset T`); filtered by flex flag" - ":math:`\text{T}^x`", "technology (exchange=1)", "tech_exchange", "technologies used for interregional commodity flow; (:math:`{T}^x \subset T`); filtered by exchange flag" - ":math:`\text{T}^{ret}`", "technology (retire=1)", "tech_retirement", "technologies allowed to retire before end of life; (:math:`{T}^{ret} \subset (T - T^{u})`); filtered by retire flag" - ":math:`\text{T}^u`", "technology (unlim_cap=1)", "tech_uncap", "technologies that have no bound on capacity; (:math:`{T}^u \subset (T - T^{res})`); filtered by unlim_cap flag" - ":math:`\text{T}^{ss}`", "technology (seas_stor=1)", "tech_seasonal_storage", "seasonal storage technologies; (:math:`{T}^{ss} \subset T^s`); filtered by seas_stor flag" - "", "tech_group", "tech_group_names", "named groups for use in group constraints; group names" - "", "tech_group_member", "tech_group_members", "each technology belonging to each group; group membership" - ":math:`\text{T}^e`", "existing_capacity", "tech_exist", "technologies constructed in an existing (past) vintage; (:math:`{T}^e \subset T`); derived from existing_capacity table" - -Commodity Sets -^^^^^^^^^^^^^^ + ":math:`{}^*\text{T}`", ":code:`technology`", ":code:`tech_all`", "all technologies to be modeled; (:math:`{T}^r \cup {T}^p`)" + ":math:`\text{T}^p`", ":code:`technology`", ":code:`tech_production`", "techs producing intermediate commodities, like electricity" + ":math:`\text{T}^b`", ":code:`technology, flag = pb`", ":code:`tech_baseload`", "baseload electric generators, (:math:`{T}^b \subset T`)" + ":math:`\text{T}^s`", ":code:`technology, flag = ps`", ":code:`tech_storage`", "all storage technologies, (:math:`{T}^s \subset T`)" + ":math:`\text{T}^a`", ":code:`technology, annual = 1`", ":code:`tech_annual`", "technologies that produce constant annual output, (:math:`{T}^a \subset T`)" + ":math:`\text{T}^{res}`", ":code:`technology, reserve = 1`", ":code:`tech_reserve`", "electric generators contributing to the reserve margin requirement, (:math:`{T}^{res} \subset T`)" + ":math:`\text{T}^c`", ":code:`technology, curtail = 1`", ":code:`tech_curtailment`", "technologies with curtailable output and no upstream cost; (:math:`{T}^c \subset (T - T^{res})`)" + ":math:`\text{T}^f`", ":code:`technology, flex = 1`", ":code:`tech_flex`", "technologies producing excess commodity flows, (:math:`{T}^f \subset T`)" + ":math:`\text{T}^x`", ":code:`technology, exchange = 1`", ":code:`tech_exchange`", "technologies used for interregional commodity flows, (:math:`{T}^x \subset T`)" + ":math:`\text{T}^{ret}`", ":code:`technology, retire = 1`", ":code:`tech_retirement`", "technologies allowed to retire before end of life, (:math:`{T}^{ret} \subset (T - T^{u})`)" + ":math:`\text{T}^u`", ":code:`technology, unlim_cap = 1`", ":code:`tech_uncap`", "technologies that have no bound on capacity, (:math:`{T}^u \subset (T - T^{res})`)" + ":math:`\text{T}^{ss}`", ":code:`technology, seas_stor = 1`", ":code:`tech_seasonal_storage`", "seasonal storage technologies, (:math:`{T}^{ss} \subset T^s`)" + "", ":code:`tech_group`", ":code:`tech_group_names`", "named groups for use in group constraints" + "", ":code:`tech_group_member`", ":code:`tech_group_members`", "each technology belonging to each group" + ":math:`\text{T}^e`", ":code:`existing_capacity`", ":code:`tech_exist`", "technologies constructed in an existing (past) vintage; (:math:`{T}^e \subset T`)" + +The sets below define commodities that are consumed and produced by different energy +technologies. .. csv-table:: :header: "Set", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`\text{C}^d`", "commodity (flag='d')", "commodity_demand", "end-use demand commodities; filtered by flag" - ":math:`\text{C}^e`", "commodity (flag='e')", "commodity_emissions", "emission commodities (e.g. :math:`\text{CO}_\text{2}` :math:`\text{NO}_\text{x}`); filtered by flag" - ":math:`\text{C}^p`", "commodity (flag='p')", "commodity_physical", "general energy forms (e.g. electricity, coal, uranium, oil); filtered by flag" - ":math:`\text{C}^w`", "commodity (flag='w','wa','wp')", "commodity_waste", "production can be greater than consumption; can be physical, annual, or neither (not balanced); filtered by waste flags" - ":math:`\text{C}^a`", "commodity (flag='a')", "commodity_annual", "same as commodity physical but flows are only balanced over each period (:math:`\text{C}^a \subset \text{C}^p`); filtered by flag" - ":math:`\text{C}^s`", "commodity (flag='s')", "commodity_source", "input sources (not balanced by CommodityBalance_constraint); filtered by flag" - ":math:`{}^*\text{C}^k`", "", "commodity_sink", "commodities that exit the process network (:math:`\text{C}_d \cup \text{C}_w`); union of demand and waste commodities" - ":math:`{}^*\text{C}^c`", "", "commodity_carrier", "physical energy carriers and sinks (:math:`\text{C}_p \cup \text{C}_k`); union of physical and sink commodities" - ":math:`{}^*\text{C}`", "", "commodity_all", "union of all commodity sets; union of carrier and emissions commodities" + ":math:`\text{C}^d`", ":code:`commodity, flag = d`", ":code:`commodity_demand`", "end-use demand commodities, representing the final consumer demands" + ":math:`\text{C}^e`", ":code:`commodity, flag = e`", ":code:`commodity_emissions`", "emission commodities (e.g. :math:`\text{CO}_\text{2}` :math:`\text{NO}_\text{x}`); filtered by flag" + ":math:`\text{C}^p`", ":code:`commodity, flag = p`", ":code:`commodity_physical`", "physical energy commodities (e.g. electricity, coal, uranium, oil) produced and consumed across the energy system" + ":math:`\text{C}^w`", ":code:`commodity, flag = w, wa , wp`", ":code:`commodity_waste`", "production can be greater than consumption; can be physical, annual, or neither (not balanced)" + ":math:`\text{C}^a`", ":code:`commodity, flag = a`", ":code:`commodity_annual`", "same as commodity physical but flows are only balanced over each period (:math:`\text{C}^a \subset \text{C}^p`)" + ":math:`\text{C}^s`", ":code:`commodity, flag = s`", ":code:`commodity_source`", "primary source commodities, not balanced by :code:`CommodityBalance_constraint`" + ":math:`{}^*\text{C}^k`", "", ":code:`commodity_sink`", "commodities that exit the process network (:math:`\text{C}_d \cup \text{C}_w`); union of demand and waste commodities" + ":math:`{}^*\text{C}^c`", "", ":code:`commodity_carrier`", "physical energy carriers and end-use demands (:math:`\text{C}_p \cup \text{C}_d`); union of physical, demand, and waste commodities" + ":math:`{}^*\text{C}`", "", ":code:`commodity_all`", "union of all commodity sets; union of carrier and emissions commodities" -Other Sets -^^^^^^^^^^ +There is one additional set that defines operators (=, <, >). While not strictly +necessary, defing these operators as a set allows modelers to express constraints +more efficiently. .. csv-table:: :header: "Set", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - "", "operator", "operator", "constraint operators" + "", ":code:`operator`", ":code:`operator`", "constraint operators" Direct Mappings: Parameters diff --git a/docs/source/mathematical_formulation.rst b/docs/source/mathematical_formulation.rst index 3e98777ae..4c545dc1c 100644 --- a/docs/source/mathematical_formulation.rst +++ b/docs/source/mathematical_formulation.rst @@ -122,24 +122,13 @@ Conventions (:math:`\{t,v\}`). For example, solar PV (technology) installed in 2030 (vintage). - - * Mathematical notation: - - * We use the symbol :math:`\mathbb{I}` to represent the unit interval ([0, - 1]). - - * We use the symbol :math:`\mathbb{Z}` to represent "the set of all - integers." - - * We use the symbol :math:`\mathbb{N}` to represent natural numbers (i.e., - integers greater than zero: 1, 2, 3, :math:`\ldots`). - - * We use the symbol :math:`\mathbb{R}` to denote the set of real numbers, and - :math:`\mathbb{R}^+_0` to denote non-negative real numbers. - - Sets ---- +In a mathematical model like Temoa, sets are used to index parameters and +variables. Below we define the sets used in Temoa, which are grouped into logical +components. In each case, we provide the mathematical notation used in the +mathematical formulation of the model, as well as the associated names in the +python code and database schema. .. include:: db_model_comparison.rst From 6237a1bdc1057d379497839a33c76a7742834ca0 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Mon, 2 Feb 2026 08:39:53 -0500 Subject: [PATCH 510/587] docs: update descriptions of Temoa parameters --- docs/source/db_model_comparison.rst | 77 ++++++++++++++++-------- docs/source/mathematical_formulation.rst | 22 +++++-- 2 files changed, 69 insertions(+), 30 deletions(-) diff --git a/docs/source/db_model_comparison.rst b/docs/source/db_model_comparison.rst index 7bb153ab6..3ff6b2010 100644 --- a/docs/source/db_model_comparison.rst +++ b/docs/source/db_model_comparison.rst @@ -8,12 +8,9 @@ is the master set and :code:`time_exist` is a subset that defines the user-defin model time periods to define historical technology vintages that exist prior to the model's time horizon for optimization. -Note: In instances where the "Database Table" column contains two comma-separated -elements, the first element refers to the name of the dtabase table and the second -refers to a specific column within the database table. .. csv-table:: - :header: "Set", "Database Table", "Model Code", "Notes" + :header: "Set", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 ":math:`\text{P}^e`", ":code:`time_period, flag = e`", ":code:`time_exist`", "model periods prior to the beginning of the optimization time horizon" @@ -23,7 +20,7 @@ refers to a specific column within the database table. ":math:`\text{D}`", ":code:`time_of_day`", ":code:`time_of_day`", "intraday time divisions" ":math:`\text{S}`", ":code:`season_label`", ":code:`time_season`", "intra-annual divisions, e.g., different seasons or different representative days" "", ":code:`time_season`", ":code:`time_season`", "ordered tuple of seasons by time period" - "", ":code:`time_season_sequential`", ":code:`time_season_to_sequential, ordered_season_sequential`", "NEED HELP" + "", ":code:`time_season_sequential`", ":code:`time_season_to_sequential, ordered_season_sequential`", "superimposed sequential seasons used for seasonal storage and inter-season ramping" The sets in the table below define Temoa's representation of regions. @@ -33,7 +30,7 @@ The sets in the table below define Temoa's representation of regions. ":math:`\text{R}`", ":code:`region`", ":code:`regions`", "distinct geographical regions; direct mapping" "", ":code:`region`", ":code:`regional_indices`", "set of all the possible combinations of interregional exchanges plus original region indices" - "", ":code:`region`", ":code:`regional_global_indices`", "NEED HELP - is this set required? It appears to be deprecated?" + "", ":code:`region_group_check`", ":code:`regional_global_indices`", "set used to validate regional group constraints; includes individual regions, exchange pairs, and groups" The sets below define how technologies are represented within Temoa. Because technologies can serve many different functions across an energy system, we need to define a large @@ -44,7 +41,7 @@ number of technology subsets. :widths: 15, 20, 25, 40 ":math:`{}^*\text{T}`", ":code:`technology`", ":code:`tech_all`", "all technologies to be modeled; (:math:`{T}^r \cup {T}^p`)" - ":math:`\text{T}^p`", ":code:`technology`", ":code:`tech_production`", "techs producing intermediate commodities, like electricity" + ":math:`\text{T}^p`", ":code:`technology, flag = p`", ":code:`tech_production`", "techs producing intermediate commodities, like electricity" ":math:`\text{T}^b`", ":code:`technology, flag = pb`", ":code:`tech_baseload`", "baseload electric generators, (:math:`{T}^b \subset T`)" ":math:`\text{T}^s`", ":code:`technology, flag = ps`", ":code:`tech_storage`", "all storage technologies, (:math:`{T}^s \subset T`)" ":math:`\text{T}^a`", ":code:`technology, annual = 1`", ":code:`tech_annual`", "technologies that produce constant annual output, (:math:`{T}^a \subset T`)" @@ -52,6 +49,8 @@ number of technology subsets. ":math:`\text{T}^c`", ":code:`technology, curtail = 1`", ":code:`tech_curtailment`", "technologies with curtailable output and no upstream cost; (:math:`{T}^c \subset (T - T^{res})`)" ":math:`\text{T}^f`", ":code:`technology, flex = 1`", ":code:`tech_flex`", "technologies producing excess commodity flows, (:math:`{T}^f \subset T`)" ":math:`\text{T}^x`", ":code:`technology, exchange = 1`", ":code:`tech_exchange`", "technologies used for interregional commodity flows, (:math:`{T}^x \subset T`)" + ":math:`\text{T}^{ur}`", ":code:`technology, ramp_up = 1`", ":code:`tech_upramping`", "electric generators with a ramp up hourly rate limit; (:math:`{T}^{ur} \subset T`)" + ":math:`\text{T}^{dr}`", ":code:`technology, ramp_down = 1`", ":code:`tech_downramping`", "electric generators with a ramp down hourly rate limit; (:math:`{T}^{dr} \subset T`)" ":math:`\text{T}^{ret}`", ":code:`technology, retire = 1`", ":code:`tech_retirement`", "technologies allowed to retire before end of life, (:math:`{T}^{ret} \subset (T - T^{u})`)" ":math:`\text{T}^u`", ":code:`technology, unlim_cap = 1`", ":code:`tech_uncap`", "technologies that have no bound on capacity, (:math:`{T}^u \subset (T - T^{res})`)" ":math:`\text{T}^{ss}`", ":code:`technology, seas_stor = 1`", ":code:`tech_seasonal_storage`", "seasonal storage technologies, (:math:`{T}^{ss} \subset T^s`)" @@ -69,15 +68,16 @@ technologies. ":math:`\text{C}^d`", ":code:`commodity, flag = d`", ":code:`commodity_demand`", "end-use demand commodities, representing the final consumer demands" ":math:`\text{C}^e`", ":code:`commodity, flag = e`", ":code:`commodity_emissions`", "emission commodities (e.g. :math:`\text{CO}_\text{2}` :math:`\text{NO}_\text{x}`); filtered by flag" ":math:`\text{C}^p`", ":code:`commodity, flag = p`", ":code:`commodity_physical`", "physical energy commodities (e.g. electricity, coal, uranium, oil) produced and consumed across the energy system" - ":math:`\text{C}^w`", ":code:`commodity, flag = w, wa , wp`", ":code:`commodity_waste`", "production can be greater than consumption; can be physical, annual, or neither (not balanced)" + ":math:`\text{C}^w`", ":code:`commodity, flag = w, wa , wp`", ":code:`commodity_waste`", "production can be greater than consumption; can be physical, annual, or neither (not balanced, all wasted)" ":math:`\text{C}^a`", ":code:`commodity, flag = a`", ":code:`commodity_annual`", "same as commodity physical but flows are only balanced over each period (:math:`\text{C}^a \subset \text{C}^p`)" + ":math:`\text{C}^l`", ":code:`commodity, flag = l`", ":code:`commodity_flex`", "(disposable) commodities produced by a flex technology (:math:`\text{C}^l \subset \text{C}^p`)" ":math:`\text{C}^s`", ":code:`commodity, flag = s`", ":code:`commodity_source`", "primary source commodities, not balanced by :code:`CommodityBalance_constraint`" ":math:`{}^*\text{C}^k`", "", ":code:`commodity_sink`", "commodities that exit the process network (:math:`\text{C}_d \cup \text{C}_w`); union of demand and waste commodities" ":math:`{}^*\text{C}^c`", "", ":code:`commodity_carrier`", "physical energy carriers and end-use demands (:math:`\text{C}_p \cup \text{C}_d`); union of physical, demand, and waste commodities" ":math:`{}^*\text{C}`", "", ":code:`commodity_all`", "union of all commodity sets; union of carrier and emissions commodities" There is one additional set that defines operators (=, <, >). While not strictly -necessary, defing these operators as a set allows modelers to express constraints +necessary, defining these operators as a set allows modelers to express constraints more efficiently. .. csv-table:: @@ -166,35 +166,60 @@ Emission Parameters ":math:`\text{EE}_{r,t,v,e}`", "emission_embodied", "emission_embodied", "emissions associated with the creation of capacity; embodied emissions" ":math:`\text{EEOL}_{r,t,v,e}`", "emission_end_of_life", "emission_end_of_life", "emissions associated with the retirement/end of life of capacity; end-of-life emissions" -Limit & Constraint Parameters -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Absolute Limits (Capacity, Activity, Emission) +""""""""""""""""""""""""""""""""""""""""""""""" .. csv-table:: :header: "Parameter", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 ":math:`\text{LC}_{r,p,t}`", "limit_capacity", "limit_capacity", "limit tech-specific capacity by period; capacity limits" - "", "limit_new_capacity", "limit_new_capacity", "new capacity limits" + ":math:`\text{LNC}_{r,p,t}`", "limit_new_capacity", "limit_new_capacity", "Limit new capacity deployment by period" ":math:`\text{LA}_{r,p,t}`", "limit_activity", "limit_activity", "limit tech-specific activity by region and period; activity limits" ":math:`\text{LE}_{r,p,e}`", "limit_emission", "limit_emission", "limit emissions by region and period; emission limits" - ":math:`\text{LR}_{r,t}`", "limit_resource", "limit_resource", "limit resource production by tech across time periods; resource extraction limits" - "", "limit_growth_capacity", "limit_growth_capacity", "capacity growth rate" - "", "limit_degrowth_capacity", "limit_degrowth_capacity", "capacity degrowth rate" - "", "limit_growth_new_capacity", "limit_growth_new_capacity", "new capacity growth rate" - "", "limit_degrowth_new_capacity", "limit_degrowth_new_capacity", "new capacity degrowth rate" - "", "limit_growth_new_capacity_delta", "limit_growth_new_capacity_delta", "new capacity growth delta" - "", "limit_degrowth_new_capacity_delta", "limit_degrowth_new_capacity_delta", "new capacity degrowth delta" - "", "limit_annual_capacity_factor", "limit_annual_capacity_factor", "annual capacity factor limits" - "", "limit_seasonal_capacity_factor", "limit_seasonal_capacity_factor", "seasonal capacity factor limits" - "", "limit_capacity_share", "limit_capacity_share", "capacity share limits" - "", "limit_activity_share", "limit_activity_share", "activity share limits" - "", "limit_new_capacity_share", "limit_new_capacity_share", "new capacity share limits" + ":math:`\text{LR}_{r,t}`", "limit_resource", "limit_resource", "Cumulative activity limit across time periods (not supported in myopic)" + +Growth & Degrowth Limits +"""""""""""""""""""""""" + +.. csv-table:: + :header: "Parameter", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + ":math:`\text{LGC}_{r,t}`", "limit_growth_capacity", "limit_growth_capacity", "capacity growth rate limits" + ":math:`\text{LDGC}_{r,t}`", "limit_degrowth_capacity", "limit_degrowth_capacity", "capacity degrowth rate limits" + ":math:`\text{LGNC}_{r,t}`", "limit_growth_new_capacity", "limit_growth_new_capacity", "new capacity growth rate limits" + ":math:`\text{LDGNC}_{r,t}`", "limit_degrowth_new_capacity", "limit_degrowth_new_capacity", "new capacity degrowth rate limits" + ":math:`\mathrm{LGNC}_{\Delta,r,t}`", "limit_growth_new_capacity_delta", "limit_growth_new_capacity_delta", "new capacity growth acceleration limits" + ":math:`\mathrm{LDGNC}_{\Delta,r,t}`", "limit_degrowth_new_capacity_delta", "limit_degrowth_new_capacity_delta", "new capacity degrowth deceleration limits" + +Operational & Split Limits +"""""""""""""""""""""""""" + +.. csv-table:: + :header: "Parameter", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + ":math:`\text{LACF}_{r,p,t,o}`", "limit_annual_capacity_factor", "limit_annual_capacity_factor", "annual capacity factor limits" + ":math:`\text{LSCF}_{r,p,s,t}`", "limit_seasonal_capacity_factor", "limit_seasonal_capacity_factor", "seasonal capacity factor limits" ":math:`\text{TIS}_{r,i,t}`", "limit_tech_input_split", "limit_tech_input_split", "technology input fuel ratio at time slice level; tech input split constraints" ":math:`\text{TISA}_{r,i,t}`", "limit_tech_input_split_annual", "limit_tech_input_split_annual", "average annual technology input fuel ratio; annual tech input splits" ":math:`\text{TOS}_{r,t,o}`", "limit_tech_output_split", "limit_tech_output_split", "technology output fuel ratio at time slice level; tech output split constraints" - ":math:`\text{TISA}_{r,i,t}`", "limit_tech_output_split_annual", "limit_tech_output_split_annual", "average annual technology output fuel ratio; annual tech output splits" + ":math:`\text{TOSA}_{r,t,o}`", "limit_tech_output_split_annual", "limit_tech_output_split_annual", "average annual technology output fuel ratio; annual tech output splits" ":math:`\text{LSF}_{r,p,s,d,t,v}`", "limit_storage_level_fraction", "limit_storage_fraction", "limit storage level in any time slice; storage level fraction limits" +Share Limits +"""""""""""" + +.. csv-table:: + :header: "Parameter", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + ":math:`\text{LCS}_{r,p,g_1,g_2}`", "limit_capacity_share", "limit_capacity_share", "capacity share limits between technology groups" + ":math:`\text{LAS}_{r,p,g_1,g_2}`", "limit_activity_share", "limit_activity_share", "activity share limits between technology groups" + ":math:`\text{LNCS}_{r,p,g_1,g_2}`", "limit_new_capacity_share", "limit_new_capacity_share", "new capacity share limits" + Storage Parameters ^^^^^^^^^^^^^^^^^^ @@ -231,7 +256,7 @@ Policy Parameters :header: "Parameter", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - "", "rps_requirement", "renewable_portfolio_standard", "RPS requirements" + "", "rps_requirement", "renewable_portfolio_standard", "**[Deprecated]** RPS requirements; use limit_activity_share instead" ":math:`\text{LIT}_{r,t,e,t}`", "linked_tech", "linked_techs", "dummy techs used to convert CO2 emissions to physical commodity; linked technology specs" Construction & End-of-Life Parameters diff --git a/docs/source/mathematical_formulation.rst b/docs/source/mathematical_formulation.rst index 4c545dc1c..69953f2b3 100644 --- a/docs/source/mathematical_formulation.rst +++ b/docs/source/mathematical_formulation.rst @@ -128,7 +128,7 @@ In a mathematical model like Temoa, sets are used to index parameters and variables. Below we define the sets used in Temoa, which are grouped into logical components. In each case, we provide the mathematical notation used in the mathematical formulation of the model, as well as the associated names in the -python code and database schema. +Python code and database schema. .. include:: db_model_comparison.rst @@ -367,6 +367,7 @@ Parameters ":math:`\text{CV}_{r,p,t,v}`","cost_variable",":math:`\mathbb{R}`","Variable operations \& maintenance cost" ":math:`\text{CON}_{r,i,t,v}`","construction_input",":math:`\mathbb{R}`","Commodities consumed by creation of process capacity" ":math:`\text{DEM}_{r,p,c}`","demand",":math:`\mathbb{R}^+_0`","End-use demands, by period" + ":math:`\text{DPP}`","days_per_period",":math:`\mathbb{R}^+_0`","Days per period" ":math:`\text{DDD}_{p,s,d}`","demand_default_distribution",":math:`\mathbb{I}`","Default demand distribution (currently not supported)" ":math:`\text{DSD}_{r,p,s,d,c}`","demand_specific_distribution",":math:`\mathbb{I}`","Demand-specific distribution" ":math:`\text{EFF}_{r,i,t,v,o}`","efficiency",":math:`\mathbb{R}^+_0`","Tech- and commodity-specific efficiency" @@ -385,7 +386,19 @@ Parameters ":math:`\text{LE}_{r,p,e}`","limit_emission",":math:`\mathbb{R}^+_0`","Limit emissions by region and period" ":math:`\text{LA}_{r,p,t}`","limit_activity",":math:`\mathbb{R}^+_0`","Limit tech-specific activity by region and period" ":math:`\text{LC}_{r,p,t}`","limit_capacity",":math:`\mathbb{R}^+_0`","Limit tech-specific capacity by period" - ":math:`\text{LR}_{r,t}`","limit_resource",":math:`\mathbb{R}^+_0`","Limit resource production by tech across time periods" + ":math:`\text{LNC}_{r,p,t}`","limit_new_capacity",":math:`\mathbb{R}^+_0`","Limit new capacity deployment by period" + ":math:`\text{LR}_{r,t}`","limit_resource",":math:`\mathbb{R}^+_0`","Cumulative activity limit across time periods (not supported in myopic)" + ":math:`\text{LGC}_{r,t}`","limit_growth_capacity",":math:`\mathbb{I}`","Capacity growth rate limits" + ":math:`\text{LDGC}_{r,t}`","limit_degrowth_capacity",":math:`\mathbb{I}`","Capacity degrowth rate limits" + ":math:`\text{LGNC}_{r,t}`","limit_growth_new_capacity",":math:`\mathbb{I}`","New capacity growth rate limits" + ":math:`\text{LDGNC}_{r,t}`","limit_degrowth_new_capacity",":math:`\mathbb{I}`","New capacity degrowth rate limits" + ":math:`\text{LGNC}_{\Delta,r,t}`","limit_growth_new_capacity_delta",":math:`\mathbb{I}`","New capacity growth acceleration limits" + ":math:`\text{LDGNC}_{\Delta,r,t}`","limit_degrowth_new_capacity_delta",":math:`\mathbb{I}`","New capacity degrowth deceleration limits" + ":math:`\text{LACF}_{r,p,t,o}`","limit_annual_capacity_factor",":math:`\mathbb{I}`","Annual capacity factor limits" + ":math:`\text{LSCF}_{r,p,s,t}`","limit_seasonal_capacity_factor",":math:`\mathbb{I}`","Seasonal capacity factor limits" + ":math:`\text{LCS}_{r,p,g_1,g_2}`","limit_capacity_share",":math:`\mathbb{I}`","Capacity share limits between technology groups" + ":math:`\text{LAS}_{r,p,g_1,g_2}`","limit_activity_share",":math:`\mathbb{I}`","Activity share limits between technology groups" + ":math:`\text{LNCS}_{r,p,g_1,g_2}`","limit_new_capacity_share",":math:`\mathbb{I}`","New capacity share limits" ":math:`\text{LSF}_{r,p,s,d,t,v}`","limit_storage_level_fraction",":math:`\mathbb{R}^+_0`","Limit storage level in any time slice" ":math:`\text{MDY}`","myopic_discounting_year",":math:`\mathbb{N}`","Objective function NPV year when running myopically" ":math:`\text{PRM}_{r}`","planning_reserve_margin",":math:`\mathbb{I}`","Margin used to ensure sufficient generating capacity" @@ -393,12 +406,13 @@ Parameters ":math:`\text{RUH}_{r,t}`","ramp_up_hourly",":math:`\mathbb{R}`","Hourly rate at which generation techs can ramp output up" ":math:`\text{SD}_{r,t}`","storage_duration",":math:`\mathbb{N}`","Storage duration per technology, specified in hours" ":math:`\text{SEG}_{s,d}`","segment_fraction",":math:`\mathbb{I}`","Fraction of year represented by each (s, d) tuple" + ":math:`\text{SFPS}_{p,s}`","segment_fraction_per_season",":math:`\mathbb{I}`","computed from segment fractions" ":math:`\text{TIS}_{r,i,t}`","tech_input_split",":math:`\mathbb{I}`","Technology input fuel ratio at time slice level" ":math:`\text{TISA}_{r,i,t}`","tech_input_split_annual",":math:`\mathbb{I}`","Average annual technology input fuel ratio" ":math:`\text{TOS}_{r,t,o}`","tech_output_split",":math:`\mathbb{I}`","Technology output fuel ratio at time slice level" - ":math:`\text{TISA}_{r,i,t}`","tech_output_split_annual",":math:`\mathbb{I}`","Average annual technology output fuel ratio" + ":math:`\text{TOSA}_{r,t,o}`","tech_output_split_annual",":math:`\mathbb{I}`","Average annual technology output fuel ratio" ":math:`{}^*\text{LA}_{t,v}`","loan_annualize",":math:`\mathbb{R}^+_0`","Loan amortization by tech and vintage; based on :math:`DR_t`" - ":math:`{}^*\text{MPL}_{p,t,v}`","model_process_life",":math:`\mathbb{N}`","Smaller of remaining model horizon or process tech life" + ":math:`{}^*\text{MPL}_{p,t,v}`","model_process_life",":math:`\mathbb{N}`","**[Deprecated]** Smaller of remaining model horizon or process tech life" ":math:`{}^*\text{PLF}_{r,p,t,v}`","process_life_frac",":math:`\mathbb{I}`","Fraction of available process capacity by region and period " ":math:`{}^*\text{LEN}_p`","period_length",":math:`\mathbb{N}`","Number of years in period :math:`p`" From 6ff381220ed0d978798b2873fc27cdc00f876eb5 Mon Sep 17 00:00:00 2001 From: Joe DeCarolis Date: Tue, 3 Mar 2026 08:51:37 -0500 Subject: [PATCH 511/587] Update and reorganize parameter mapping tables --- docs/source/db_model_comparison.rst | 350 ++++++++++++---------------- 1 file changed, 152 insertions(+), 198 deletions(-) diff --git a/docs/source/db_model_comparison.rst b/docs/source/db_model_comparison.rst index 3ff6b2010..030a4566c 100644 --- a/docs/source/db_model_comparison.rst +++ b/docs/source/db_model_comparison.rst @@ -1,5 +1,5 @@ Our discussion of sets is broken down into several logical categories to make it -easier to parse. The first group of sets pertains to Temoa's treatment of time, +easier to parse. The **first group of sets pertains to Temoa's treatment of time**, as shown below. **Note:** Some entries in the "Database Table" column are comma-separated. In those cases, the first element refers to the name of the database table, and the second refers to specific column within the database column used to @@ -16,49 +16,49 @@ the model's time horizon for optimization. ":math:`\text{P}^e`", ":code:`time_period, flag = e`", ":code:`time_exist`", "model periods prior to the beginning of the optimization time horizon" ":math:`\text{P}^f`", ":code:`time_period, flag = f`", ":code:`time_future`", "model periods within the optimization time horizon" ":math:`{}^*\text{P}^o`", ":code:`time_period`", ":code:`time_optimize`", "model time periods to optimize, (:math:`\text{P}^f - \text{max}(\text{P}^f)`); the last time period is removed as it represents the end of the final period" - ":math:`{}^*\text{V}`", ":code:`time_period`", ":code:`vintage_exist`, :code:`vintage_optimize`, :code:`vintage_all`", "tech vintages, (:math:`\text{P}^e \cup \text{P}^o`), derived from time period set" - ":math:`\text{D}`", ":code:`time_of_day`", ":code:`time_of_day`", "intraday time divisions" + ":math:`{}^*\text{V}`", ":code:`time_period`", ":code:`vintage_exist`, :code:`vintage_optimize`, :code:`vintage_all`", "tech vintages, (:math:`\text{P}^e \cup \text{P}^o`), derived from time period set and used to track technology vintages across time periods" + ":math:`\text{D}`", ":code:`time_of_day`", ":code:`time_of_day`", "intraday time divisions, either individual or blocks of hours" ":math:`\text{S}`", ":code:`season_label`", ":code:`time_season`", "intra-annual divisions, e.g., different seasons or different representative days" "", ":code:`time_season`", ":code:`time_season`", "ordered tuple of seasons by time period" "", ":code:`time_season_sequential`", ":code:`time_season_to_sequential, ordered_season_sequential`", "superimposed sequential seasons used for seasonal storage and inter-season ramping" -The sets in the table below define Temoa's representation of regions. +The sets in the table below define Temoa's representation of **regions**. .. csv-table:: :header: "Set", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`\text{R}`", ":code:`region`", ":code:`regions`", "distinct geographical regions; direct mapping" + ":math:`\text{R}`", ":code:`region`", ":code:`regions`", "distinct geographical regions" "", ":code:`region`", ":code:`regional_indices`", "set of all the possible combinations of interregional exchanges plus original region indices" "", ":code:`region_group_check`", ":code:`regional_global_indices`", "set used to validate regional group constraints; includes individual regions, exchange pairs, and groups" The sets below define how technologies are represented within Temoa. Because technologies can serve many different functions across an energy system, we need to define a large -number of technology subsets. +number of **technology subsets**. .. csv-table:: :header: "Set", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`{}^*\text{T}`", ":code:`technology`", ":code:`tech_all`", "all technologies to be modeled; (:math:`{T}^r \cup {T}^p`)" - ":math:`\text{T}^p`", ":code:`technology, flag = p`", ":code:`tech_production`", "techs producing intermediate commodities, like electricity" - ":math:`\text{T}^b`", ":code:`technology, flag = pb`", ":code:`tech_baseload`", "baseload electric generators, (:math:`{T}^b \subset T`)" - ":math:`\text{T}^s`", ":code:`technology, flag = ps`", ":code:`tech_storage`", "all storage technologies, (:math:`{T}^s \subset T`)" - ":math:`\text{T}^a`", ":code:`technology, annual = 1`", ":code:`tech_annual`", "technologies that produce constant annual output, (:math:`{T}^a \subset T`)" - ":math:`\text{T}^{res}`", ":code:`technology, reserve = 1`", ":code:`tech_reserve`", "electric generators contributing to the reserve margin requirement, (:math:`{T}^{res} \subset T`)" - ":math:`\text{T}^c`", ":code:`technology, curtail = 1`", ":code:`tech_curtailment`", "technologies with curtailable output and no upstream cost; (:math:`{T}^c \subset (T - T^{res})`)" - ":math:`\text{T}^f`", ":code:`technology, flex = 1`", ":code:`tech_flex`", "technologies producing excess commodity flows, (:math:`{T}^f \subset T`)" - ":math:`\text{T}^x`", ":code:`technology, exchange = 1`", ":code:`tech_exchange`", "technologies used for interregional commodity flows, (:math:`{T}^x \subset T`)" - ":math:`\text{T}^{ur}`", ":code:`technology, ramp_up = 1`", ":code:`tech_upramping`", "electric generators with a ramp up hourly rate limit; (:math:`{T}^{ur} \subset T`)" - ":math:`\text{T}^{dr}`", ":code:`technology, ramp_down = 1`", ":code:`tech_downramping`", "electric generators with a ramp down hourly rate limit; (:math:`{T}^{dr} \subset T`)" - ":math:`\text{T}^{ret}`", ":code:`technology, retire = 1`", ":code:`tech_retirement`", "technologies allowed to retire before end of life, (:math:`{T}^{ret} \subset (T - T^{u})`)" - ":math:`\text{T}^u`", ":code:`technology, unlim_cap = 1`", ":code:`tech_uncap`", "technologies that have no bound on capacity, (:math:`{T}^u \subset (T - T^{res})`)" - ":math:`\text{T}^{ss}`", ":code:`technology, seas_stor = 1`", ":code:`tech_seasonal_storage`", "seasonal storage technologies, (:math:`{T}^{ss} \subset T^s`)" + ":math:`{}^*\text{T}`", ":code:`technology`", ":code:`tech_all`", "all technologies to be modeled (:math:`{T}^r \cup {T}^p`)" + ":math:`\text{T}^p`", ":code:`technology, flag = p`", ":code:`tech_production`", "technologies producing intermediate commodities, like electricity" + ":math:`\text{T}^b`", ":code:`technology, flag = pb`", ":code:`tech_baseload`", "baseload electric generators, which have constant output across intraday time segments (:math:`{T}^b \subset T`)" + ":math:`\text{T}^s`", ":code:`technology, flag = ps`", ":code:`tech_storage`", "all storage technologies (:math:`{T}^s \subset T`)" + ":math:`\text{T}^a`", ":code:`technology, annual = 1`", ":code:`tech_annual`", "technologies that produce constant annual output (:math:`{T}^a \subset T`)" + ":math:`\text{T}^{res}`", ":code:`technology, reserve = 1`", ":code:`tech_reserve`", "electric generators contributing to the reserve margin requirement (:math:`{T}^{res} \subset T`)" + ":math:`\text{T}^c`", ":code:`technology, curtail = 1`", ":code:`tech_curtailment`", "technologies with curtailable output and no upstream cost (:math:`{T}^c \subset (T - T^{res})`)" + ":math:`\text{T}^f`", ":code:`technology, flex = 1`", ":code:`tech_flex`", "technologies producing excess commodity flows (:math:`{T}^f \subset T`)" + ":math:`\text{T}^x`", ":code:`technology, exchange = 1`", ":code:`tech_exchange`", "technologies used for interregional commodity flows (:math:`{T}^x \subset T`)" + ":math:`\text{T}^{ur}`", ":code:`technology, ramp_up = 1`", ":code:`tech_upramping`", "electric generators with a ramp up hourly rate limit (:math:`{T}^{ur} \subset T`)" + ":math:`\text{T}^{dr}`", ":code:`technology, ramp_down = 1`", ":code:`tech_downramping`", "electric generators with a ramp down hourly rate limit (:math:`{T}^{dr} \subset T`)" + ":math:`\text{T}^{ret}`", ":code:`technology, retire = 1`", ":code:`tech_retirement`", "technologies allowed to retire before end of life (:math:`{T}^{ret} \subset (T - T^{u})`)" + ":math:`\text{T}^u`", ":code:`technology, unlim_cap = 1`", ":code:`tech_uncap`", "technologies that have no bound on capacity (:math:`{T}^u \subset (T - T^{res})`)" + ":math:`\text{T}^{ss}`", ":code:`technology, seas_stor = 1`", ":code:`tech_seasonal_storage`", "seasonal storage technologies (:math:`{T}^{ss} \subset T^s`)" "", ":code:`tech_group`", ":code:`tech_group_names`", "named groups for use in group constraints" "", ":code:`tech_group_member`", ":code:`tech_group_members`", "each technology belonging to each group" - ":math:`\text{T}^e`", ":code:`existing_capacity`", ":code:`tech_exist`", "technologies constructed in an existing (past) vintage; (:math:`{T}^e \subset T`)" + ":math:`\text{T}^e`", ":code:`existing_capacity`", ":code:`tech_exist`", "existing technologies with a past vintage (:math:`{T}^e \subset T`)" -The sets below define commodities that are consumed and produced by different energy +The sets below define **commodities** that are consumed and produced by different energy technologies. .. csv-table:: @@ -66,9 +66,9 @@ technologies. :widths: 15, 20, 25, 40 ":math:`\text{C}^d`", ":code:`commodity, flag = d`", ":code:`commodity_demand`", "end-use demand commodities, representing the final consumer demands" - ":math:`\text{C}^e`", ":code:`commodity, flag = e`", ":code:`commodity_emissions`", "emission commodities (e.g. :math:`\text{CO}_\text{2}` :math:`\text{NO}_\text{x}`); filtered by flag" - ":math:`\text{C}^p`", ":code:`commodity, flag = p`", ":code:`commodity_physical`", "physical energy commodities (e.g. electricity, coal, uranium, oil) produced and consumed across the energy system" - ":math:`\text{C}^w`", ":code:`commodity, flag = w, wa , wp`", ":code:`commodity_waste`", "production can be greater than consumption; can be physical, annual, or neither (not balanced, all wasted)" + ":math:`\text{C}^e`", ":code:`commodity, flag = e`", ":code:`commodity_emissions`", "emission commodities (e.g., :math:`\text{CO}_\text{2}` :math:`\text{NO}_\text{x}`); filtered by flag" + ":math:`\text{C}^p`", ":code:`commodity, flag = p`", ":code:`commodity_physical`", "physical energy commodities (e.g., electricity, coal, uranium, oil) produced and consumed across the energy system" + ":math:`\text{C}^w`", ":code:`commodity, flag = w, wa , wp`", ":code:`commodity_waste`", "commodity whose production can be greater than its consumption; can be physical, annual, or neither (not balanced, all wasted)" ":math:`\text{C}^a`", ":code:`commodity, flag = a`", ":code:`commodity_annual`", "same as commodity physical but flows are only balanced over each period (:math:`\text{C}^a \subset \text{C}^p`)" ":math:`\text{C}^l`", ":code:`commodity, flag = l`", ":code:`commodity_flex`", "(disposable) commodities produced by a flex technology (:math:`\text{C}^l \subset \text{C}^p`)" ":math:`\text{C}^s`", ":code:`commodity, flag = s`", ":code:`commodity_source`", "primary source commodities, not balanced by :code:`CommodityBalance_constraint`" @@ -76,7 +76,7 @@ technologies. ":math:`{}^*\text{C}^c`", "", ":code:`commodity_carrier`", "physical energy carriers and end-use demands (:math:`\text{C}_p \cup \text{C}_d`); union of physical, demand, and waste commodities" ":math:`{}^*\text{C}`", "", ":code:`commodity_all`", "union of all commodity sets; union of carrier and emissions commodities" -There is one additional set that defines operators (=, <, >). While not strictly +There is an additional set that defines **operators (=, <, >)**. While not strictly necessary, defining these operators as a set allows modelers to express constraints more efficiently. @@ -86,267 +86,221 @@ more efficiently. "", ":code:`operator`", ":code:`operator`", "constraint operators" - -Direct Mappings: Parameters ----------------------------- - -Time-Related Parameters -^^^^^^^^^^^^^^^^^^^^^^^ +As indicated below, there are additional sets that are derived within the model +code and thus do not appear in the database schema. .. csv-table:: - :header: "Parameter", "Database Table", "Model Element", "Notes" - :widths: 15, 20, 25, 40 + :header: "Set", "Model Element", "Notes" + :widths: 15, 25, 60 - "", "metadata_real (global_discount_rate)", "global_discount_rate", "global rate used to calculate present cost; global discount rate" - ":math:`\text{SEG}_{s,d}`", "time_segment_fraction", "segment_fraction", "fraction of year represented by each (s, d) tuple; time slice fractions" - "", "metadata (days_per_period)", "days_per_period", "days per period" - "", "", "segment_fraction_per_season", "computed from segment fractions" - "", "time_season_sequential", "time_season_sequential", "sequential season ordering (mutable)" + "", ":code:`tech_with_capacity`", "technologies eligible for capacitization; computed as tech_all - tech_uncap" + "", ":code:`tech_or_group`", "technologies or groups combined; union of tech_group_names | tech_all" + ":math:`{}^*\text{C}^k`", ":code:`commodity_sink`", "commodities that exit the process network; union of demand and waste commodities" + ":math:`{}^*\text{C}^c`", ":code:`commodity_carrier`", "physical energy carriers and end-use demands; union of physical, demand, and waste commodities" + ":math:`{}^*\text{C}`", ":code:`commodity_all`", "union of all commodity sets; union of carrier and emissions commodities" + ":math:`\text{T}^e`", ":code:`tech_exist`", "technologies with existing capacity; derived from existing_capacity table" -Capacity & Existing Infrastructure Parameters -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +These are also python dictionaries and sets used to specific internal data +structures during model construction and are not considered formal model elements: -.. csv-table:: - :header: "Parameter", "Database Table", "Model Element", "Notes" - :widths: 15, 20, 25, 40 +- :code:`process_inputs`, :code:`process_outputs`, :code:`process_loans` +- :code:`active_flow_rpsditvo`, :code:`active_flow_rpitvo` +- Various vintage and operational tracking dictionaries +- Time sequencing dictionaries (:code:`time_next`, :code:`time_next_sequential`) - ":math:`\text{ECAP}_{r,t,v}`", "existing_capacity", "existing_capacity", "pre-existing capacity; direct mapping" - ":math:`\text{C2A}_{r,t,v}`", "capacity_to_activity", "capacity_to_activity", "converts from capacity to activity units; direct mapping" - ":math:`\text{CFT}_{r,s,d,t}`", "capacity_factor_tech", "capacity_factor_tech", "technology-specific capacity factor; tech-level capacity factors" - ":math:`\text{CFP}_{r,s,d,t,v}`", "capacity_factor_process", "capacity_factor_process", "process-specific capacity factor; process-level capacity factors" - ":math:`\text{CC}_{r,p,t,v}`", "capacity_credit", "capacity_credit", "process-specific capacity credit; reserve capacity credit" -Cost Parameters -^^^^^^^^^^^^^^^ -.. csv-table:: - :header: "Parameter", "Database Table", "Model Element", "Notes" - :widths: 15, 20, 25, 40 +Parameters +---------- - ":math:`\text{CF}_{r,p,t,v}`", "cost_fixed", "cost_fixed", "fixed operations & maintenance cost; fixed O&M costs" - ":math:`\text{CI}_{r,t,v}`", "cost_invest", "cost_invest", "tech-specific investment cost; investment costs" - ":math:`\text{CV}_{r,p,t,v}`", "cost_variable", "cost_variable", "variable operations & maintenance cost; variable O&M costs" - "", "cost_emission", "cost_emission", "emission costs" - ":math:`\text{LR}_{r,t,v}`", "loan_rate", "loan_rate", "process-specific interest rate on investment cost; technology-specific loan rates" - "", "metadata_real (default_loan_rate)", "default_loan_rate", "default loan rate" - ":math:`\text{GDR}`", "metadata_real (global_discount_rate)", "global_discount_rate", "global rate used to calculate present cost; global discount rate" +Parameters are indexed by the sets defined above and used to specify input data. +In the leftmost column, the subscripts indicate the sets used to index the parameter. +As with sets, we categorize parameters thematically and present them below in +separate tables. -Efficiency & Performance Parameters -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Below are the **time-related** parameters. .. csv-table:: :header: "Parameter", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`\text{EFF}_{r,i,t,v,o}`", "efficiency", "efficiency", "tech- and commodity-specific efficiency; base efficiency" - "", "efficiency_variable", "efficiency_variable", "time-varying efficiency" - ":math:`\text{LTT}_{r,t}`", "lifetime_tech", "lifetime_tech", "tech-specific lifetime (default=40 years); technology lifetime" - ":math:`\text{LTP}_{r,t,v}`", "lifetime_process", "lifetime_process", "tech- and vintage-specific lifetime (default=lifetime_tech); process-specific lifetime" - ":math:`\text{LSC}_{r,p,t,v}`", "lifetime_survival_curve", "lifetime_survival_curve", "surviving fraction of original capacity; survival curve fractions" - ":math:`\text{LLP}_{r,t,v}`", "loan_lifetime_process", "loan_lifetime_process", "process-specific loan term (default=lifetime_process); loan lifetime" + ":math:`\text{SEG}_{s,d}`", ":code:`time_segment_fraction`", ":code:`segment_fraction`", "fraction of year represented by each (s, d) tuple" + "", ":code:`metadata`", ":code:`days_per_period`", "number of days per period, required to ensure proper representation of time" + "", ":code:`time_season_sequential`", ":code:`time_season_sequential`", "sequential season ordering (mutable)" -Demand Parameters -^^^^^^^^^^^^^^^^^ +Parameters in the table below relate to **capacity and its performance +characteristics**. .. csv-table:: :header: "Parameter", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`\text{DEM}_{r,p,c}`", "demand", "demand", "end-use demands, by period; demand by region-period-commodity" - ":math:`\text{DSD}_{r,p,s,d,c}`", "demand_specific_distribution", "demand_specific_distribution", "demand-specific distribution; demand time distribution" + ":math:`\text{C2A}_{r,t,v}`", ":code:`capacity_to_activity`", ":code:`capacity_to_activity`", "converts from capacity to activity units" + ":math:`\text{CC}_{r,p,t,v}`", ":code:`capacity_credit`", ":code:`capacity_credit`", "process-specific capacity credit used in the reserve margin constraint" + ":math:`\text{CFT}_{r,s,d,t}`", ":code:`capacity_factor_tech`", ":code:`capacity_factor_tech`", "technology-specific capacity factor" + ":math:`\text{CFP}_{r,s,d,t,v}`", ":code:`capacity_factor_process`", ":code:`capacity_factor_process`", "process-specific capacity factor; allows capacity factor to change with technology vintage" + ":math:`\text{ECAP}_{r,t,v}`", ":code:`existing_capacity`", ":code:`existing_capacity`", "installed capacity that exists prior to first model time period" + ":math:`\text{PRM}_{r}`", ":code:`planning_reserve_margin`", ":code:`planning_reserve_margin`", "planning reserve margin used to ensure sufficient generating capacity" + "", ":code:`reserve_capacity_derate`", ":code:`reserve_capacity_derate`", "reserve capacity derate" + ":math:`\text{RUH}_{r,t}`", ":code:`ramp_up_hourly`", ":code:`ramp_up_hourly`", "hourly rate at which generation techs can ramp output up" + ":math:`\text{RDH}_{r,t}`", ":code:`ramp_down_hourly`", ":code:`ramp_down_hourly`", "hourly rate at which generation techs can ramp output down" -Emission Parameters -^^^^^^^^^^^^^^^^^^^ +Parameters in the table below relate to the specification of **costs**. .. csv-table:: :header: "Parameter", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`\text{EAC}_{r,i,t,v,o,e}`", "emission_activity", "emission_activity", "tech-specific emissions rate; activity-based emissions" - ":math:`\text{EE}_{r,t,v,e}`", "emission_embodied", "emission_embodied", "emissions associated with the creation of capacity; embodied emissions" - ":math:`\text{EEOL}_{r,t,v,e}`", "emission_end_of_life", "emission_end_of_life", "emissions associated with the retirement/end of life of capacity; end-of-life emissions" - + ":math:`\text{CF}_{r,p,t,v}`", ":code:`cost_fixed`", ":code:`cost_fixed`", "fixed operations & maintenance cost" + ":math:`\text{CI}_{r,t,v}`", ":code:`cost_invest`", ":code:`cost_invest`", "tech-specific investment cost" + ":math:`\text{CV}_{r,p,t,v}`", ":code:`cost_variable`", ":code:`cost_variable`", "variable operations & maintenance (O&M) cost" + "", ":code:`cost_emission`", ":code:`cost_emission`", "emission costs" + ":math:`\text{GDR}`", ":code:`metadata_real`", ":code:`global_discount_rate`", "global rate used to convert future time period costs to the present cost" + "", ":code:`metadata_real`", ":code:`default_loan_rate`", "default loan rate used to amortize investment costs" + ":math:`\text{LLP}_{r,t,v}`", ":code:`loan_lifetime_process`", ":code:`loan_lifetime_process`", "process-specific loan term (default=lifetime_process)" + ":math:`\text{LR}_{r,t,v}`", ":code:`loan_rate`", ":code:`loan_rate`", "process-specific interest rate on investment cost" -Absolute Limits (Capacity, Activity, Emission) -""""""""""""""""""""""""""""""""""""""""""""""" +Parameters in the table below relate to the specification of **technology efficiency +and performance**. .. csv-table:: :header: "Parameter", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`\text{LC}_{r,p,t}`", "limit_capacity", "limit_capacity", "limit tech-specific capacity by period; capacity limits" - ":math:`\text{LNC}_{r,p,t}`", "limit_new_capacity", "limit_new_capacity", "Limit new capacity deployment by period" - ":math:`\text{LA}_{r,p,t}`", "limit_activity", "limit_activity", "limit tech-specific activity by region and period; activity limits" - ":math:`\text{LE}_{r,p,e}`", "limit_emission", "limit_emission", "limit emissions by region and period; emission limits" - ":math:`\text{LR}_{r,t}`", "limit_resource", "limit_resource", "Cumulative activity limit across time periods (not supported in myopic)" + ":math:`\text{EFF}_{r,i,t,v,o}`", ":code:`efficiency`", ":code:`efficiency`", "technology- and commodity-specific conversion efficiency" + ":math:`\text{EFF}_{r,p,s,d,i,t,v,o}`", ":code:`efficiency_variable`", ":code:`efficiency_variable`", "optional specification that allows efficiency to be specified by time slice" + ":math:`\text{LTT}_{r,t}`", ":code:`lifetime_tech`", ":code:`lifetime_tech`", "technology-specific lifetime (default=40 years)" + ":math:`\text{LTP}_{r,t,v}`", ":code:`lifetime_process`", ":code:`lifetime_process`", "tech- and vintage-specific lifetime (default=lifetime_tech)" + ":math:`\text{LSC}_{r,p,t,v}`", ":code:`lifetime_survival_curve`", ":code:`lifetime_survival_curve`", "surviving fraction of original capacity" + ":math:`\text{SD}_{r,t}`", ":code:`storage_duration`", ":code:`storage_duration`", "storage duration per technology, specified in hours" -Growth & Degrowth Limits -"""""""""""""""""""""""" +Parameters in the table below relate to the specification of **end-use demands**. .. csv-table:: :header: "Parameter", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`\text{LGC}_{r,t}`", "limit_growth_capacity", "limit_growth_capacity", "capacity growth rate limits" - ":math:`\text{LDGC}_{r,t}`", "limit_degrowth_capacity", "limit_degrowth_capacity", "capacity degrowth rate limits" - ":math:`\text{LGNC}_{r,t}`", "limit_growth_new_capacity", "limit_growth_new_capacity", "new capacity growth rate limits" - ":math:`\text{LDGNC}_{r,t}`", "limit_degrowth_new_capacity", "limit_degrowth_new_capacity", "new capacity degrowth rate limits" - ":math:`\mathrm{LGNC}_{\Delta,r,t}`", "limit_growth_new_capacity_delta", "limit_growth_new_capacity_delta", "new capacity growth acceleration limits" - ":math:`\mathrm{LDGNC}_{\Delta,r,t}`", "limit_degrowth_new_capacity_delta", "limit_degrowth_new_capacity_delta", "new capacity degrowth deceleration limits" + ":math:`\text{DEM}_{r,p,c}`", ":code:`demand`", ":code:`demand`", "end-use demand by region-period-commodity" + ":math:`\text{DSD}_{r,p,s,d,c}`", ":code:`demand_specific_distribution`", ":code:`demand_specific_distribution`", "fractional annual demand by time slice (s,d)" -Operational & Split Limits -"""""""""""""""""""""""""" +Parameters in the table below relate to the specification of **emissions**. .. csv-table:: :header: "Parameter", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`\text{LACF}_{r,p,t,o}`", "limit_annual_capacity_factor", "limit_annual_capacity_factor", "annual capacity factor limits" - ":math:`\text{LSCF}_{r,p,s,t}`", "limit_seasonal_capacity_factor", "limit_seasonal_capacity_factor", "seasonal capacity factor limits" - ":math:`\text{TIS}_{r,i,t}`", "limit_tech_input_split", "limit_tech_input_split", "technology input fuel ratio at time slice level; tech input split constraints" - ":math:`\text{TISA}_{r,i,t}`", "limit_tech_input_split_annual", "limit_tech_input_split_annual", "average annual technology input fuel ratio; annual tech input splits" - ":math:`\text{TOS}_{r,t,o}`", "limit_tech_output_split", "limit_tech_output_split", "technology output fuel ratio at time slice level; tech output split constraints" - ":math:`\text{TOSA}_{r,t,o}`", "limit_tech_output_split_annual", "limit_tech_output_split_annual", "average annual technology output fuel ratio; annual tech output splits" - ":math:`\text{LSF}_{r,p,s,d,t,v}`", "limit_storage_level_fraction", "limit_storage_fraction", "limit storage level in any time slice; storage level fraction limits" + ":math:`\text{EAC}_{r,i,t,v,o,e}`", ":code:`emission_activity`", ":code:`emission_activity`", "activity-based emissions rate" + ":math:`\text{EE}_{r,t,v,e}`", ":code:`emission_embodied`", ":code:`emission_embodied`", "emissions associated with the creation of capacity; embodied emissions" + ":math:`\text{EEOL}_{r,t,v,e}`", ":code:`emission_end_of_life`", ":code:`emission_end_of_life`", "emissions associated with the retirement/end of life of capacity" -Share Limits -"""""""""""" +Parameters in the table below relate to the specification of **absolute limits on +capacity, activity and emissions**. .. csv-table:: :header: "Parameter", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`\text{LCS}_{r,p,g_1,g_2}`", "limit_capacity_share", "limit_capacity_share", "capacity share limits between technology groups" - ":math:`\text{LAS}_{r,p,g_1,g_2}`", "limit_activity_share", "limit_activity_share", "activity share limits between technology groups" - ":math:`\text{LNCS}_{r,p,g_1,g_2}`", "limit_new_capacity_share", "limit_new_capacity_share", "new capacity share limits" + ":math:`\text{LC}_{r,p,t}`", ":code:`limit_capacity`", ":code:`limit_capacity`", "limit on tech-specific capacity by period" + ":math:`\text{LNC}_{r,p,t}`", ":code:`limit_new_capacity`", ":code:`limit_new_capacity`", "limit on new capacity deployment by period" + ":math:`\text{LA}_{r,p,t}`", ":code:`limit_activity`", ":code:`limit_activity`", "limit on technology-specific activity by region and period" + ":math:`\text{LE}_{r,p,e}`", ":code:`limit_emission`", ":code:`limit_emission`", "limit on emissions by region and period" + ":math:`\text{LR}_{r,t}`", ":code:`limit_resource`", ":code:`limit_resource`", "cumulative activity limit across time periods (not supported in myopic)" -Storage Parameters -^^^^^^^^^^^^^^^^^^ +Parameters in the table below relate to the specification of **growth and degrowth +limits**. .. csv-table:: :header: "Parameter", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`\text{SD}_{r,t}`", "storage_duration", "storage_duration", "storage duration per technology, specified in hours; storage duration in hours" + ":math:`\text{LGC}_{r,t}`", ":code:`limit_growth_capacity`", ":code:`limit_growth_capacity`", "capacity growth rate limits" + ":math:`\text{LDGC}_{r,t}`", ":code:`limit_degrowth_capacity`", ":code:`limit_degrowth_capacity`", "capacity degrowth rate limits" + ":math:`\text{LGNC}_{r,t}`", ":code:`limit_growth_new_capacity`", ":code:`limit_growth_new_capacity`", "new capacity growth rate limits" + ":math:`\text{LDGNC}_{r,t}`", ":code:`limit_degrowth_new_capacity`", ":code:`limit_degrowth_new_capacity`", "new capacity degrowth rate limits" + ":math:`\mathrm{LGNC}_{\Delta,r,t}`", ":code:`limit_growth_new_capacity_delta`", ":code:`limit_growth_new_capacity_delta`", "new capacity growth acceleration limits" + ":math:`\mathrm{LDGNC}_{\Delta,r,t}`", ":code:`limit_degrowth_new_capacity_delta`", ":code:`limit_degrowth_new_capacity_delta`", "new capacity degrowth deceleration limits" -Operations Parameters -^^^^^^^^^^^^^^^^^^^^^ +Parameters in the table below relate to the specification of **operational and +split limits**. .. csv-table:: :header: "Parameter", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`\text{RUH}_{r,t}`", "ramp_up_hourly", "ramp_up_hourly", "hourly rate at which generation techs can ramp output up; hourly ramp-up rates" - ":math:`\text{RDH}_{r,t}`", "ramp_down_hourly", "ramp_down_hourly", "hourly rate at which generation techs can ramp output down; hourly ramp-down rates" + ":math:`\text{LACF}_{r,p,t,o}`", ":code:`limit_annual_capacity_factor`", ":code:`limit_annual_capacity_factor`", "annual capacity factor limits" + ":math:`\text{LSCF}_{r,p,s,t}`", ":code:`limit_seasonal_capacity_factor`", ":code:`limit_seasonal_capacity_factor`", "seasonal capacity factor limits" + ":math:`\text{LSF}_{r,p,s,d,t,v}`", ":code:`limit_storage_level_fraction`", ":code:`limit_storage_fraction`", "limit on storage level in any time slice" + ":math:`\text{TIS}_{r,i,t}`", ":code:`limit_tech_input_split`", ":code:`limit_tech_input_split`", "technology input split constraints specifying input fuel ratio at time slice level" + ":math:`\text{TISA}_{r,i,t}`", ":code:`limit_tech_input_split_annual`", ":code:`limit_tech_input_split_annual`", "technology input split constraints specifying input fuel ratio at average annual level" + ":math:`\text{TOS}_{r,t,o}`", ":code:`limit_tech_output_split`", ":code:`limit_tech_output_split`", "technology split constraints specifying output fuel ratio at time slice level" + ":math:`\text{TOSA}_{r,t,o}`", ":code:`limit_tech_output_split_annual`", ":code:`limit_tech_output_split_annual`", "technology split constraints specifying output fuel ratio at average annual level" -Reserve Margin Parameters -^^^^^^^^^^^^^^^^^^^^^^^^^^ +Parameters in the table below relate to the specification of **share limits**. .. csv-table:: :header: "Parameter", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`\text{PRM}_{r}`", "planning_reserve_margin", "planning_reserve_margin", "margin used to ensure sufficient generating capacity; planning reserve margin" - "", "reserve_capacity_derate", "reserve_capacity_derate", "reserve capacity derate" + ":math:`\text{LCS}_{r,p,g_1,g_2}`", ":code:`limit_capacity_share`", ":code:`limit_capacity_share`", "capacity share limits between technology groups" + ":math:`\text{LAS}_{r,p,g_1,g_2}`", ":code:`limit_activity_share`", ":code:`limit_activity_share`", "activity share limits between technology groups" + ":math:`\text{LNCS}_{r,p,g_1,g_2}`", ":code:`limit_new_capacity_share`", ":code:`limit_new_capacity_share`", "new capacity share limits" -Policy Parameters -^^^^^^^^^^^^^^^^^ +Parameters in the table below relate to the specification of **policy**. .. csv-table:: :header: "Parameter", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - "", "rps_requirement", "renewable_portfolio_standard", "**[Deprecated]** RPS requirements; use limit_activity_share instead" - ":math:`\text{LIT}_{r,t,e,t}`", "linked_tech", "linked_techs", "dummy techs used to convert CO2 emissions to physical commodity; linked technology specs" + "", ":code:`rps_requirement`", ":code:`renewable_portfolio_standard`", "**[Deprecated]** RPS requirements; use :code:`limit_activity_share` instead" + ":math:`\text{LIT}_{r,t,e,t}`", ":code:`linked_tech`", ":code:`linked_techs`", "dummy techs used to convert CO2 emissions to physical commodity" -Construction & End-of-Life Parameters -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Parameters in the table below relate to the specification of **construction and +end-of-life**. .. csv-table:: :header: "Parameter", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`\text{CON}_{r,i,t,v}`", "construction_input", "construction_input", "commodities consumed by creation of process capacity; construction input requirements" - ":math:`\text{EOLO}_{r,t,v,o}`", "end_of_life_output", "end_of_life_output", "commodities produced by retirement/end of life of capacity; end-of-life outputs" + ":math:`\text{CON}_{r,i,t,v}`", ":code:`construction_input`", ":code:`construction_input`", "construction input requirements that represent commodities consumed by creation of process capacity" + ":math:`\text{EOLO}_{r,t,v,o}`", ":code:`end_of_life_output`", ":code:`end_of_life_output`", "end-of-life outputs that represent commodities produced by retirement/end of life of capacity" -Computed Parameters (Model-Derived) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Parameters in the table below are **computed in code (i.e., model-derived) and +therefore do not appear in the database**. .. csv-table:: :header: "Parameter", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`{}^*\text{LEN}_p`", "", "period_length", "number of years in period :math:`p`; computed from time periods" - "", "", "segment_fraction_per_season", "computed from segment fractions" - ":math:`{}^*\text{LA}_{t,v}`", "", "loan_annualize", "loan amortization by tech and vintage; based on :math:`DR_t`; computed from loan rate and lifetime" - ":math:`{}^*\text{PLF}_{r,p,t,v}`", "", "process_life_frac", "fraction of available process capacity by region and period; computed process life fraction" - - -Output Tables (Not in Model Input) ------------------------------------ - -These tables store optimization results and are not part of model input: - -- output_dual_variable -- output_objective -- output_curtailment -- output_net_capacity -- output_built_capacity -- output_retired_capacity -- output_flow_in -- output_flow_out -- output_flow_out_summary -- output_storage_level -- output_emission -- output_cost - - -Model-Only Elements (Not Directly from Database) -------------------------------------------------- - -Derived Sets -^^^^^^^^^^^^ - -.. csv-table:: - :header: "Set", "Model Element", "Notes" - :widths: 15, 25, 60 - - "", "tech_with_capacity", "technologies eligible for capacitization; computed as tech_all - tech_uncap" - "", "tech_or_group", "technologies or groups combined; union of tech_group_names | tech_all" - ":math:`{}^*\text{C}^k`", "commodity_sink", "commodities that exit the process network; union of demand and waste commodities" - ":math:`{}^*\text{C}^c`", "commodity_carrier", "physical energy carriers and sinks; union of physical and sink commodities" - ":math:`{}^*\text{C}`", "commodity_all", "union of all commodity sets; union of carrier and emissions commodities" - ":math:`\text{T}^e`", "tech_exist", "technologies with existing capacity; derived from existing_capacity table" - -Internal Data Structures (Not Formal Model Elements) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -These are dictionaries and sets used internally during model construction: - -- process_inputs, process_outputs, process_loans -- active_flow_rpsditvo, active_flow_rpitvo -- Various vintage and operational tracking dictionaries -- Time sequencing dictionaries (time_next, time_next_sequential) - - -Database Tables Without Direct Model Mapping ---------------------------------------------- + ":math:`{}^*\text{LEN}_p`", "", ":code:`period_length`", "number of years in period :math:`p`; computed from time periods" + "", "", ":code:`segment_fraction_per_season`", "computed from segment fractions" + ":math:`{}^*\text{LA}_{t,v}`", "", ":code:`loan_annualize`", "loan amortization by tech and vintage; based on :math:`DR_t`; computed from loan rate and lifetime" + ":math:`{}^*\text{PLF}_{r,p,t,v}`", "", ":code:`process_life_frac`", "fraction of available process capacity by region and period; computed from process life fraction" + "", "", ":code:`segment_fraction_per_season`", "computed internally from segment fractions" + +The tables below specify **model outputs.** When constructing a new database, +they are left blank. These tables are auto-populated by the model after +successful run completion. + +- :code:`output_dual_variable` +- :code:`output_objective` +- :code:`output_curtailment` +- :code:`output_net_capacity` +- :code:`output_built_capacity` +- :code:`output_retired_capacity` +- :code:`output_flow_in` +- :code:`output_flow_out` +- :code:`output_flow_out_summary` +- :code:`output_storage_level` +- :code:`output_emission` +- :code:`output_cost` + +Finally, the database tables below do not have a directed mapping to the the +model code. .. csv-table:: :header: "Database Table", "Purpose", "Notes" :widths: 30, 30, 40 - "myopic_efficiency", "Myopic mode efficiency", "alternative efficiency for myopic optimization" - "time_manual", "Manual time sequencing", "hidden feature, rarely used" - "sector_label", "Sectoral classification", "used in output tables only" - - -Summary Statistics ------------------- - -- **Database Tables**: 73 total (63 input, 10 output) -- **Model Sets**: 101 total (37 core sets, 64 constraint index sets) -- **Model Parameters**: 60 total -- **Direct Mappings**: ~55 database tables map to model elements -- **Output-Only Tables**: 10 tables -- **Model-Derived Elements**: ~20 sets/parameters computed from database data + ":code:`myopic_efficiency`", "Myopic mode efficiency", "alternative efficiency for myopic optimization" + ":code:`time_manual`", "Manual time sequencing", "hidden feature, rarely used" + ":code:`sector_label`", "Sectoral classification", "used in output tables only" From 89a986d60c7ea67790b2c6893c2a04bace242013 Mon Sep 17 00:00:00 2001 From: Joe DeCarolis Date: Tue, 3 Mar 2026 12:05:33 -0500 Subject: [PATCH 512/587] Update mathematical formulation within documentation Reorganized and updated the discussion of model formulation. Split up the set and parameter mapping tables that show the translation from algebraic expression to database table to model code. --- docs/source/mathematical_formulation.rst | 246 +++++------------- ...mparison.rst => param_desc_and_tables.rst} | 123 +-------- docs/source/set_desc_and_tables.rst | 114 ++++++++ 3 files changed, 180 insertions(+), 303 deletions(-) rename docs/source/{db_model_comparison.rst => param_desc_and_tables.rst} (56%) create mode 100644 docs/source/set_desc_and_tables.rst diff --git a/docs/source/mathematical_formulation.rst b/docs/source/mathematical_formulation.rst index 69953f2b3..990fd1a82 100644 --- a/docs/source/mathematical_formulation.rst +++ b/docs/source/mathematical_formulation.rst @@ -53,14 +53,14 @@ constraints that are used during the optimization process. .. _Sets: -Conventions ------------ +Temoa Notation +-------------- - * In the mathematical notation, we use CAPITALIZATION to denote a container, - like a set, indexed variable, or indexed parameter. Sets use only a single - letter, so we use the lower case to represent an item from the set. For - example, :math:`T` represents the set of all technologies and :math:`t` - represents a single item from :math:`T`. +In the mathematical notation, we use CAPITALIZATION to denote a container, +like a set, indexed variable, or indexed parameter. Sets use only a single +letter, so we use the lower case to represent an item from the set. For +example, :math:`T` represents the set of all technologies and :math:`t` +represents a single item from :math:`T`. * Variables are named V\_VarName within the code to aid readability. However, in the documentation where there is benefit of italics and other font @@ -200,6 +200,8 @@ possible energy technologies that the model may build and the commodities sets contain all the input and output forms of energy that technologies consume and produce. The period and time slice sets merit a slightly longer discussion. +Treatment of Time +----------------- Temoa's conceptual model of *time* is broken up into three levels, and energy supply and demand is balanced at each of these levels: @@ -222,6 +224,10 @@ and demand is balanced at each of these levels: afternoon, and night. In a database with representative days, each daily segment can be used to represent every hour of the day. +We use the word 'slice' to refer to the tuple of season and time of day +:math:`\{s,d\}`. Note that these time slices are user-defined, and can +represent time ranging large blocks of time (e.g., winter-night) to every +hour in a given season. There are two specifiable period sets: :code:`time_exist` (:math:`\text{P}^e`) and :code:`time_future` (:math:`\text{P}^f`). The :code:`time_exist` set @@ -239,6 +245,13 @@ year, and makes them easily accessible via the :code:`time_optimize` set. This :math:`\text{P}^f = \{2010, 2015, 2025\}`, :code:`time_optimize` does not contain 2025: :math:`\text{P}^o =\{2010, 2015\}`. +Temoa assumes that all elements of the :code:`time_existing` and +:code:`time_future` sets are integers. Further, these sets are assumed to be +ordered, such that the minimum element is "naught". For example, if +:math:`\text{P}^f = \{2015, 2020, 2030\}`, then :math:`P_0 = 2015`. In +other words, the capital :math:`\text{P}` with the naught subscript indicates +the first element in the :code:`time_future` set. + One final note on periods: rather than optimizing each year within a period individually, Temoa makes the simplifying assumption that each time period contains :math:`n` copies of a single, representative year. Temoa optimizes capacity @@ -271,153 +284,17 @@ slices, comprised of a season and a time of day. Unlike :code:`time_future`, th is no restriction on what labels the modeler may assign to the :code:`time_season` and :code:`time_of_day` set elements. +Sets +---- -A Word on Index Ordering -^^^^^^^^^^^^^^^^^^^^^^^^ - -The ordering of the indices is consistent throughout the model to promote an -intuitive "left-to-right" description of each parameter, variable, and -constraint set. For example, Temoa's output commodity flow variable -:math:`FO_{r,p,s,d,i,t,v,o}` may be described as "in region (:math:`r`), -in period (:math:`p`) during season (:math:`s`) at time of day (:math:`d`), -the flow of input commodity (:math:`i`) to technology (:math:`t`) of vintage -(:math:`v`) generates an output commodity flow (:math:`o`) of -:math:`FO_{r,p,s,d,i,t,v,o}`." For any indexed parameter or variable within -Temoa, our intent is to enable a mental model of a simple left-to-right, arrow-box-arrow -mnemonic to describe the "input :math:`\rightarrow` process -:math:`\rightarrow` output" flow of energy. And while not all variables, parameters, -or constraints have 8 indices, the 8-index order mentioned here (r, p, s, d, i, t, v, o) -is the canonical ordering. If you note any case where, for example, d comes before s, -that is an oversight. In general, if there is an index ordering that does not follow -this rubric, we view that as a bug. - - -Deviations from Standard Mathematical Notation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Temoa deviates from standard mathematical notation and set understanding in two -ways. The first is that Temoa places a restriction on the *time* set elements. -Specifically, while most optimization programs treat set elements as arbitrary -labels, Temoa assumes that all elements of the :code:`time_existing` and -:code:`time_future` sets are integers. Further, these sets are assumed to be -ordered, such that the minimum element is "naught". For example, if -:math:`\text{P}^f = \{2015, 2020, 2030\}`, then :math:`P_0 = 2015`. In -other words, the capital :math:`\text{P}` with the naught subscript indicates -the first element in the :code:`time_future` set. We will explain the reason -for this notation shortly. - -The second set of deviations revolves around the use of the Theta superset -(:math:`\Theta`). The Temoa code makes heavy use of sparse sets, for both -correctness and efficient use of computational resources. For brevity, and -to avoid discussion of implementation details, we do not enumerate their -logical creation here. Instead, we rely on the readers general understanding of -the context. For example, in the sparse creation of the constraints of the -Demand constraint class (explained in :ref:`NetworkConstraints` and -:ref:`constraint-anatomy`), we state simply that the constraint is instantiated -"for all the :math:`\{p, s, d, dem\}` tuples in -:math:`\Theta_{\text{demand}}`". This means that the constraint is only defined -for the exact indices for which the modeler specified end-use demands via the -Demand parameter in the input data file. - -Summations also occur in a sparse manner. For example, let's take another look at -the :code:`Capacity` :eq:`Capacity` Constraint: - -.. math:: - - \left ( - \text{CFP}_{r, s, d, t, v} - \cdot \text{C2A}_{r, t} - \cdot \text{SEG}_{s, d} - \right ) - \cdot \textbf{CAP}_{r, t, v} - = - \sum_{I, O} \textbf{FO}_{r, p, s, d,i, t, v, o} - + - \sum_{I, O} \textbf{CUR}_{r, p, s, d, i, t, v, o} - - \\ - \forall \{p, s, d, t, v\} \in \Theta_{\text{Capacity}} - -It defines the Capacity variable for every valid combination of :math:`\{p, v\}`, -and includes the sum over all inputs and outputs of the FlowOut variable. A -naive implementation of this equation might include nonsensical items in each -summation, such as an input of vehicle miles traveled to an oil refinery or an -output of sunlight from nuclear generating capacity. However, in this context, -summing over the inputs and outputs (:math:`i` and :math:`o`) implicitly -includes only the valid combinations of :math:`\{p, s, d, i, t, v, o\}`. - +.. include:: set_desc_and_tables.rst Parameters ---------- +A summary table of input parameters is provided below, followed by a more +detailed description of each. -.. _table_parameter: - -.. csv-table:: List of Temoa parameters with which a modeler might interact. - The asterisked (\*) parameters specified at the end of the table - are automatically derived by the model and are not user-specifiable. - :header: "Parameter","Temoa Name","Domain","Short Description" - :widths: 14, 27, 10, 49 - - ":math:`\text{CC}_{r,p,t,v}`","capacity_credit",":math:`\mathbb{I}`","Process-specific capacity credit" - ":math:`\text{CFT}_{r,s,d,t}`","capacity_factor_tech",":math:`\mathbb{I}`","Technology-specific capacity factor" - ":math:`\text{CFP}_{r,s,d,t,v}`","capacity_factor_process",":math:`\mathbb{I}`","Process-specific capacity factor" - ":math:`\text{C2A}_{r,t,v}`","capacity_to_activity",":math:`\mathbb{R}^+_0`","Converts from capacity to activity units" - ":math:`\text{CF}_{r,p,t,v}`","cost_fixed",":math:`\mathbb{R}`","Fixed operations \& maintenance cost" - ":math:`\text{CI}_{r,t,v}`","cost_invest",":math:`\mathbb{R}`","Tech-specific investment cost" - ":math:`\text{CV}_{r,p,t,v}`","cost_variable",":math:`\mathbb{R}`","Variable operations \& maintenance cost" - ":math:`\text{CON}_{r,i,t,v}`","construction_input",":math:`\mathbb{R}`","Commodities consumed by creation of process capacity" - ":math:`\text{DEM}_{r,p,c}`","demand",":math:`\mathbb{R}^+_0`","End-use demands, by period" - ":math:`\text{DPP}`","days_per_period",":math:`\mathbb{R}^+_0`","Days per period" - ":math:`\text{DDD}_{p,s,d}`","demand_default_distribution",":math:`\mathbb{I}`","Default demand distribution (currently not supported)" - ":math:`\text{DSD}_{r,p,s,d,c}`","demand_specific_distribution",":math:`\mathbb{I}`","Demand-specific distribution" - ":math:`\text{EFF}_{r,i,t,v,o}`","efficiency",":math:`\mathbb{R}^+_0`","Tech- and commodity-specific efficiency" - ":math:`\text{EAC}_{r,i,t,v,o,e}`","emission_activity",":math:`\mathbb{R}`","Tech-specific emissions rate" - ":math:`\text{EE}_{r,t,v,e}`","emission_embodied",":math:`\mathbb{R}`","Emissions associated with the creation of capacity" - ":math:`\text{EEOL}_{r,t,v,e}`","emission_end_of_life",":math:`\mathbb{R}`","Emissions associated with the retirement/end of life of capacity" - ":math:`\text{EOLO}_{r,t,v,o}`","end_of_life_output",":math:`\mathbb{R}`","Commodities produced by retirement/end of life of capacity" - ":math:`\text{ECAP}_{r,t,v}`","existing_capacity",":math:`\mathbb{R}^+_0`","Pre-existing capacity" - ":math:`\text{GDR}`","global_discount_rate",":math:`\mathbb{R}`","Global rate used to calculate present cost" - ":math:`\text{LTP}_{r,t,v}`","lifetime_process",":math:`\mathbb{N}`","Tech- and vintage-specific lifetime (default=lifetime_tech)" - ":math:`\text{LTT}_{r,t}`","lifetime_tech",":math:`\mathbb{N}`","Tech-specific lifetime (default=40 years)" - ":math:`\text{LSC}_{r,p,t,v}`","lifetime_survival_curve",":math:`\mathbb{R}^+_0`","Surviving fraction of original capacity" - ":math:`\text{LIT}_{r,t,e,t}`","linked_techs","text","Dummy techs used to convert CO2 emissions to physical commodity" - ":math:`\text{LLP}_{r,t,v}`","loan_lifetime_process",":math:`\mathbb{N}`","Process-specific loan term (default=lifetime_process)" - ":math:`\text{LR}_{r,t,v}`","loan_rate",":math:`\mathbb{R}`","Process-specific interest rate on investment cost" - ":math:`\text{LE}_{r,p,e}`","limit_emission",":math:`\mathbb{R}^+_0`","Limit emissions by region and period" - ":math:`\text{LA}_{r,p,t}`","limit_activity",":math:`\mathbb{R}^+_0`","Limit tech-specific activity by region and period" - ":math:`\text{LC}_{r,p,t}`","limit_capacity",":math:`\mathbb{R}^+_0`","Limit tech-specific capacity by period" - ":math:`\text{LNC}_{r,p,t}`","limit_new_capacity",":math:`\mathbb{R}^+_0`","Limit new capacity deployment by period" - ":math:`\text{LR}_{r,t}`","limit_resource",":math:`\mathbb{R}^+_0`","Cumulative activity limit across time periods (not supported in myopic)" - ":math:`\text{LGC}_{r,t}`","limit_growth_capacity",":math:`\mathbb{I}`","Capacity growth rate limits" - ":math:`\text{LDGC}_{r,t}`","limit_degrowth_capacity",":math:`\mathbb{I}`","Capacity degrowth rate limits" - ":math:`\text{LGNC}_{r,t}`","limit_growth_new_capacity",":math:`\mathbb{I}`","New capacity growth rate limits" - ":math:`\text{LDGNC}_{r,t}`","limit_degrowth_new_capacity",":math:`\mathbb{I}`","New capacity degrowth rate limits" - ":math:`\text{LGNC}_{\Delta,r,t}`","limit_growth_new_capacity_delta",":math:`\mathbb{I}`","New capacity growth acceleration limits" - ":math:`\text{LDGNC}_{\Delta,r,t}`","limit_degrowth_new_capacity_delta",":math:`\mathbb{I}`","New capacity degrowth deceleration limits" - ":math:`\text{LACF}_{r,p,t,o}`","limit_annual_capacity_factor",":math:`\mathbb{I}`","Annual capacity factor limits" - ":math:`\text{LSCF}_{r,p,s,t}`","limit_seasonal_capacity_factor",":math:`\mathbb{I}`","Seasonal capacity factor limits" - ":math:`\text{LCS}_{r,p,g_1,g_2}`","limit_capacity_share",":math:`\mathbb{I}`","Capacity share limits between technology groups" - ":math:`\text{LAS}_{r,p,g_1,g_2}`","limit_activity_share",":math:`\mathbb{I}`","Activity share limits between technology groups" - ":math:`\text{LNCS}_{r,p,g_1,g_2}`","limit_new_capacity_share",":math:`\mathbb{I}`","New capacity share limits" - ":math:`\text{LSF}_{r,p,s,d,t,v}`","limit_storage_level_fraction",":math:`\mathbb{R}^+_0`","Limit storage level in any time slice" - ":math:`\text{MDY}`","myopic_discounting_year",":math:`\mathbb{N}`","Objective function NPV year when running myopically" - ":math:`\text{PRM}_{r}`","planning_reserve_margin",":math:`\mathbb{I}`","Margin used to ensure sufficient generating capacity" - ":math:`\text{RDH}_{r,t}`","ramp_down_hourly",":math:`\mathbb{R}`","Hourly rate at which generation techs can ramp output down" - ":math:`\text{RUH}_{r,t}`","ramp_up_hourly",":math:`\mathbb{R}`","Hourly rate at which generation techs can ramp output up" - ":math:`\text{SD}_{r,t}`","storage_duration",":math:`\mathbb{N}`","Storage duration per technology, specified in hours" - ":math:`\text{SEG}_{s,d}`","segment_fraction",":math:`\mathbb{I}`","Fraction of year represented by each (s, d) tuple" - ":math:`\text{SFPS}_{p,s}`","segment_fraction_per_season",":math:`\mathbb{I}`","computed from segment fractions" - ":math:`\text{TIS}_{r,i,t}`","tech_input_split",":math:`\mathbb{I}`","Technology input fuel ratio at time slice level" - ":math:`\text{TISA}_{r,i,t}`","tech_input_split_annual",":math:`\mathbb{I}`","Average annual technology input fuel ratio" - ":math:`\text{TOS}_{r,t,o}`","tech_output_split",":math:`\mathbb{I}`","Technology output fuel ratio at time slice level" - ":math:`\text{TOSA}_{r,t,o}`","tech_output_split_annual",":math:`\mathbb{I}`","Average annual technology output fuel ratio" - ":math:`{}^*\text{LA}_{t,v}`","loan_annualize",":math:`\mathbb{R}^+_0`","Loan amortization by tech and vintage; based on :math:`DR_t`" - ":math:`{}^*\text{MPL}_{p,t,v}`","model_process_life",":math:`\mathbb{N}`","**[Deprecated]** Smaller of remaining model horizon or process tech life" - ":math:`{}^*\text{PLF}_{r,p,t,v}`","process_life_frac",":math:`\mathbb{I}`","Fraction of available process capacity by region and period " - ":math:`{}^*\text{LEN}_p`","period_length",":math:`\mathbb{N}`","Number of years in period :math:`p`" - - -.. _influential_efficiency: +.. include:: param_desc_and_tables.rst efficiency ^^^^^^^^^^ @@ -1157,29 +1034,31 @@ activity indices for the process. Namely, :math:`p \in \{2010, 2012\}` as 2010\}\}`. The values would be :math:`{TLF}_{2010, car, 2010} = 1`, and :math:`{TLF}_{2012, car, 2010} = \frac{3}{8}`. - -Variables ---------- +Decision Variables +------------------ +Decision variables are the quantities optimized by the model. A summary table of +decision variables is provided below, followed by a more detailed description of +each. .. _table_variable: .. csv-table:: Temoa's Main Variables - :header: "Variable","Temoa Name","Domain","Short Description" - :widths: 18, 22, 10, 50 - - ":math:`FO_{r,p,s,d,i,t,v,o}`","v_flow_out",":math:`\mathbb{R}^+_0`","Commodity flow by time slice out of a tech based on a given input" - ":math:`FOA_{r,p,s,d,i,t,v,o}`","v_flow_out_annual",":math:`\mathbb{R}^+_0`","Annual commodity flow out of a tech based on a given input" - ":math:`FIS_{r,p,s,d,i,t,v,o}`","v_flow_in",":math:`\mathbb{R}^+_0`","Commodity flow into a storage tech to produce a given output" - ":math:`FLX_{r,p,s,d,i,t,v,o}`","v_flex",":math:`\mathbb{R}^+_0`","The portion of commodity production exceeding demand" - ":math:`FLXA_{r,p,i,t,v,o}`","v_flex_annual",":math:`\mathbb{R}^+_0`","The portion of commodity production from constant production techs exceeding demand" - ":math:`CUR_{r,p,s,d,i,t,v,o}`","v_curtailment",":math:`\mathbb{R}^+_0`","Commodity flow out of a tech that is curtailed" - ":math:`CAP_{r,t,v}`","v_capacity",":math:`\mathbb{R}^+_0`","Required tech capacity to support associated activity" - ":math:`CAPAVL_{r,p,t}`","v_capacity_available_by_period_and_tech",":math:`\mathbb{R}^+_0`","Derived variable representing the capacity of technology :math:`t` available in period :math:`p`" - ":math:`SI_{r,t,v}`","v_storage_init",":math:`\mathbb{R}^+_0`","Initial charge level associated with storage techs" - ":math:`SL_{r,p,s,d,t,v}`","v_storage_level",":math:`\mathbb{R}^+_0`","Charge level each time slice associated with storage techs" - ":math:`SSL_{r,p,s,t,v}`","v_seasonal_storage_level",":math:`\mathbb{R}^+_0`","Base charge level of sequential seasons for seasonal storage" - ":math:`RCAP_{r,p,t,v}`","v_retired_capacity",":math:`\mathbb{R}^+_0`","Capacity retired before end of life" - ":math:`ART_{r,p,t,v}`","v_annual_retirement",":math:`\mathbb{R}^+_0`","Annualised capacity retiring or reaching end of life" - ":math:`NCAP_{r,t,v}`","v_new_capacity",":math:`\mathbb{R}^+_0`","New deployed capacity" + :header: "Variable","Temoa Name","Short Description" + :widths: 18, 22, 50 + + ":math:`FO_{r,p,s,d,i,t,v,o}`",":code:`v_flow_out`","Commodity flow by time slice out of a tech based on a given input" + ":math:`FOA_{r,p,s,d,i,t,v,o}`",":code:`v_flow_out_annual`","Annual commodity flow out of a tech based on a given input" + ":math:`FIS_{r,p,s,d,i,t,v,o}`",":code:`v_flow_in`","Commodity flow into a storage tech to produce a given output" + ":math:`FLX_{r,p,s,d,i,t,v,o}`",":code:`v_flex`","The portion of commodity production exceeding demand" + ":math:`FLXA_{r,p,i,t,v,o}`",":code:`v_flex_annual`","The portion of commodity production from constant production techs exceeding demand" + ":math:`CUR_{r,p,s,d,i,t,v,o}`",":code:`v_curtailment`","Commodity flow out of a tech that is curtailed" + ":math:`CAP_{r,t,v}`",":code:`v_capacity`","Required tech capacity to support associated activity" + ":math:`CAPAVL_{r,p,t}`",":code:`v_capacity_available_by_period_and_tech`","Derived variable representing the capacity of technology :math:`t` available in period :math:`p`" + ":math:`SI_{r,t,v}`",":code:`v_storage_init`","Initial charge level associated with storage techs" + ":math:`SL_{r,p,s,d,t,v}`",":code:`v_storage_level`","Charge level each time slice associated with storage techs" + ":math:`SSL_{r,p,s,t,v}`",":code:`v_seasonal_storage_level`","Base charge level of sequential seasons for seasonal storage" + ":math:`RCAP_{r,p,t,v}`",":code:`v_retired_capacity`","Capacity retired before end of life" + ":math:`ART_{r,p,t,v}`",":code:`v_annual_retirement`","Annualised capacity retiring or reaching end of life" + ":math:`NCAP_{r,t,v}`",":code:`v_new_capacity`","New deployed capacity" v_flow_out ^^^^^^^^^^ @@ -1347,16 +1226,20 @@ highlight the organization of the functions within the actual code. Note that the definitions below are pulled directly from the docstrings embedded in :code:`temoa/components/`. - -.. _DecisionVariables: - -Constraints Defining Derived Decision Variables -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -These first four constraints define derived variables that are used within -the model. The :code:`Capacity_constraint` and :code:`CapacityAnnual_constraint` -are particularly important because they define the relationship between installed -capacity and allowable commodity flow. +A couple notes on the notation below. First, in all equations, we **bold** +variables to distinguish them from parameters. Second, you will notice the use +of the Theta superset (:math:`\Theta`). The Temoa code makes heavy use of +sparse sets, for both correctness and efficient use of computational resources. +For brevity, and to avoid discussion of implementation details, we do not +enumerate their logical creation here. Instead, we rely on the readers general +understanding of the context. The use of (:math:`\Theta`) means that the +constraint is only defined for the exact indices that the modeler specified. + +Capacity-Defining Constraints +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +We begin with the :code:`Capacity_constraint` and :code:`CapacityAnnual_constraint`, +which are particularly important because they define the relationship between +installed capacity and allowable commodity flow. .. autofunction:: temoa.components.capacity.capacity_constraint @@ -1436,9 +1319,6 @@ Objective Function User-Specific Constraints ^^^^^^^^^^^^^^^^^^^^^^^^^ -The constraints provided in this section are not required for proper system -operation, but allow the modeler some further degree of system specification. - .. commented out... not used? .. autofunction:: temoa.components.capacity.existing_capacity_constraint @@ -1486,8 +1366,6 @@ operation, but allow the modeler some further degree of system specification. .. autofunction:: temoa.components.limits.limit_growth_new_capacity_delta - - General Caveats --------------- diff --git a/docs/source/db_model_comparison.rst b/docs/source/param_desc_and_tables.rst similarity index 56% rename from docs/source/db_model_comparison.rst rename to docs/source/param_desc_and_tables.rst index 030a4566c..08d503590 100644 --- a/docs/source/db_model_comparison.rst +++ b/docs/source/param_desc_and_tables.rst @@ -1,122 +1,7 @@ -Our discussion of sets is broken down into several logical categories to make it -easier to parse. The **first group of sets pertains to Temoa's treatment of time**, -as shown below. **Note:** Some entries in the "Database Table" column are -comma-separated. In those cases, the first element refers to the name of the database -table, and the second refers to specific column within the database column used to -identify a specific subset. For example, in the first table below, :code:`time_period` -is the master set and :code:`time_exist` is a subset that defines the user-defined -model time periods to define historical technology vintages that exist prior to -the model's time horizon for optimization. - - -.. csv-table:: - :header: "Set", "Database Table", "Model Element", "Notes" - :widths: 15, 20, 25, 40 - - ":math:`\text{P}^e`", ":code:`time_period, flag = e`", ":code:`time_exist`", "model periods prior to the beginning of the optimization time horizon" - ":math:`\text{P}^f`", ":code:`time_period, flag = f`", ":code:`time_future`", "model periods within the optimization time horizon" - ":math:`{}^*\text{P}^o`", ":code:`time_period`", ":code:`time_optimize`", "model time periods to optimize, (:math:`\text{P}^f - \text{max}(\text{P}^f)`); the last time period is removed as it represents the end of the final period" - ":math:`{}^*\text{V}`", ":code:`time_period`", ":code:`vintage_exist`, :code:`vintage_optimize`, :code:`vintage_all`", "tech vintages, (:math:`\text{P}^e \cup \text{P}^o`), derived from time period set and used to track technology vintages across time periods" - ":math:`\text{D}`", ":code:`time_of_day`", ":code:`time_of_day`", "intraday time divisions, either individual or blocks of hours" - ":math:`\text{S}`", ":code:`season_label`", ":code:`time_season`", "intra-annual divisions, e.g., different seasons or different representative days" - "", ":code:`time_season`", ":code:`time_season`", "ordered tuple of seasons by time period" - "", ":code:`time_season_sequential`", ":code:`time_season_to_sequential, ordered_season_sequential`", "superimposed sequential seasons used for seasonal storage and inter-season ramping" - -The sets in the table below define Temoa's representation of **regions**. - -.. csv-table:: - :header: "Set", "Database Table", "Model Element", "Notes" - :widths: 15, 20, 25, 40 - - ":math:`\text{R}`", ":code:`region`", ":code:`regions`", "distinct geographical regions" - "", ":code:`region`", ":code:`regional_indices`", "set of all the possible combinations of interregional exchanges plus original region indices" - "", ":code:`region_group_check`", ":code:`regional_global_indices`", "set used to validate regional group constraints; includes individual regions, exchange pairs, and groups" - -The sets below define how technologies are represented within Temoa. Because technologies -can serve many different functions across an energy system, we need to define a large -number of **technology subsets**. - -.. csv-table:: - :header: "Set", "Database Table", "Model Element", "Notes" - :widths: 15, 20, 25, 40 - - ":math:`{}^*\text{T}`", ":code:`technology`", ":code:`tech_all`", "all technologies to be modeled (:math:`{T}^r \cup {T}^p`)" - ":math:`\text{T}^p`", ":code:`technology, flag = p`", ":code:`tech_production`", "technologies producing intermediate commodities, like electricity" - ":math:`\text{T}^b`", ":code:`technology, flag = pb`", ":code:`tech_baseload`", "baseload electric generators, which have constant output across intraday time segments (:math:`{T}^b \subset T`)" - ":math:`\text{T}^s`", ":code:`technology, flag = ps`", ":code:`tech_storage`", "all storage technologies (:math:`{T}^s \subset T`)" - ":math:`\text{T}^a`", ":code:`technology, annual = 1`", ":code:`tech_annual`", "technologies that produce constant annual output (:math:`{T}^a \subset T`)" - ":math:`\text{T}^{res}`", ":code:`technology, reserve = 1`", ":code:`tech_reserve`", "electric generators contributing to the reserve margin requirement (:math:`{T}^{res} \subset T`)" - ":math:`\text{T}^c`", ":code:`technology, curtail = 1`", ":code:`tech_curtailment`", "technologies with curtailable output and no upstream cost (:math:`{T}^c \subset (T - T^{res})`)" - ":math:`\text{T}^f`", ":code:`technology, flex = 1`", ":code:`tech_flex`", "technologies producing excess commodity flows (:math:`{T}^f \subset T`)" - ":math:`\text{T}^x`", ":code:`technology, exchange = 1`", ":code:`tech_exchange`", "technologies used for interregional commodity flows (:math:`{T}^x \subset T`)" - ":math:`\text{T}^{ur}`", ":code:`technology, ramp_up = 1`", ":code:`tech_upramping`", "electric generators with a ramp up hourly rate limit (:math:`{T}^{ur} \subset T`)" - ":math:`\text{T}^{dr}`", ":code:`technology, ramp_down = 1`", ":code:`tech_downramping`", "electric generators with a ramp down hourly rate limit (:math:`{T}^{dr} \subset T`)" - ":math:`\text{T}^{ret}`", ":code:`technology, retire = 1`", ":code:`tech_retirement`", "technologies allowed to retire before end of life (:math:`{T}^{ret} \subset (T - T^{u})`)" - ":math:`\text{T}^u`", ":code:`technology, unlim_cap = 1`", ":code:`tech_uncap`", "technologies that have no bound on capacity (:math:`{T}^u \subset (T - T^{res})`)" - ":math:`\text{T}^{ss}`", ":code:`technology, seas_stor = 1`", ":code:`tech_seasonal_storage`", "seasonal storage technologies (:math:`{T}^{ss} \subset T^s`)" - "", ":code:`tech_group`", ":code:`tech_group_names`", "named groups for use in group constraints" - "", ":code:`tech_group_member`", ":code:`tech_group_members`", "each technology belonging to each group" - ":math:`\text{T}^e`", ":code:`existing_capacity`", ":code:`tech_exist`", "existing technologies with a past vintage (:math:`{T}^e \subset T`)" - -The sets below define **commodities** that are consumed and produced by different energy -technologies. - -.. csv-table:: - :header: "Set", "Database Table", "Model Element", "Notes" - :widths: 15, 20, 25, 40 - - ":math:`\text{C}^d`", ":code:`commodity, flag = d`", ":code:`commodity_demand`", "end-use demand commodities, representing the final consumer demands" - ":math:`\text{C}^e`", ":code:`commodity, flag = e`", ":code:`commodity_emissions`", "emission commodities (e.g., :math:`\text{CO}_\text{2}` :math:`\text{NO}_\text{x}`); filtered by flag" - ":math:`\text{C}^p`", ":code:`commodity, flag = p`", ":code:`commodity_physical`", "physical energy commodities (e.g., electricity, coal, uranium, oil) produced and consumed across the energy system" - ":math:`\text{C}^w`", ":code:`commodity, flag = w, wa , wp`", ":code:`commodity_waste`", "commodity whose production can be greater than its consumption; can be physical, annual, or neither (not balanced, all wasted)" - ":math:`\text{C}^a`", ":code:`commodity, flag = a`", ":code:`commodity_annual`", "same as commodity physical but flows are only balanced over each period (:math:`\text{C}^a \subset \text{C}^p`)" - ":math:`\text{C}^l`", ":code:`commodity, flag = l`", ":code:`commodity_flex`", "(disposable) commodities produced by a flex technology (:math:`\text{C}^l \subset \text{C}^p`)" - ":math:`\text{C}^s`", ":code:`commodity, flag = s`", ":code:`commodity_source`", "primary source commodities, not balanced by :code:`CommodityBalance_constraint`" - ":math:`{}^*\text{C}^k`", "", ":code:`commodity_sink`", "commodities that exit the process network (:math:`\text{C}_d \cup \text{C}_w`); union of demand and waste commodities" - ":math:`{}^*\text{C}^c`", "", ":code:`commodity_carrier`", "physical energy carriers and end-use demands (:math:`\text{C}_p \cup \text{C}_d`); union of physical, demand, and waste commodities" - ":math:`{}^*\text{C}`", "", ":code:`commodity_all`", "union of all commodity sets; union of carrier and emissions commodities" - -There is an additional set that defines **operators (=, <, >)**. While not strictly -necessary, defining these operators as a set allows modelers to express constraints -more efficiently. - -.. csv-table:: - :header: "Set", "Database Table", "Model Element", "Notes" - :widths: 15, 20, 25, 40 - - "", ":code:`operator`", ":code:`operator`", "constraint operators" - -As indicated below, there are additional sets that are derived within the model -code and thus do not appear in the database schema. - -.. csv-table:: - :header: "Set", "Model Element", "Notes" - :widths: 15, 25, 60 - - "", ":code:`tech_with_capacity`", "technologies eligible for capacitization; computed as tech_all - tech_uncap" - "", ":code:`tech_or_group`", "technologies or groups combined; union of tech_group_names | tech_all" - ":math:`{}^*\text{C}^k`", ":code:`commodity_sink`", "commodities that exit the process network; union of demand and waste commodities" - ":math:`{}^*\text{C}^c`", ":code:`commodity_carrier`", "physical energy carriers and end-use demands; union of physical, demand, and waste commodities" - ":math:`{}^*\text{C}`", ":code:`commodity_all`", "union of all commodity sets; union of carrier and emissions commodities" - ":math:`\text{T}^e`", ":code:`tech_exist`", "technologies with existing capacity; derived from existing_capacity table" - -These are also python dictionaries and sets used to specific internal data -structures during model construction and are not considered formal model elements: - -- :code:`process_inputs`, :code:`process_outputs`, :code:`process_loans` -- :code:`active_flow_rpsditvo`, :code:`active_flow_rpitvo` -- Various vintage and operational tracking dictionaries -- Time sequencing dictionaries (:code:`time_next`, :code:`time_next_sequential`) - - - -Parameters ----------- - Parameters are indexed by the sets defined above and used to specify input data. -In the leftmost column, the subscripts indicate the sets used to index the parameter. -As with sets, we categorize parameters thematically and present them below in -separate tables. +In the leftmost column below, the subscripts indicate the sets used to index the +parameter. As with sets, we categorize parameters thematically and present them +below in separate tables. Below are the **time-related** parameters. @@ -303,4 +188,4 @@ model code. ":code:`myopic_efficiency`", "Myopic mode efficiency", "alternative efficiency for myopic optimization" ":code:`time_manual`", "Manual time sequencing", "hidden feature, rarely used" - ":code:`sector_label`", "Sectoral classification", "used in output tables only" + ":code:`sector_label`", "Sectoral classification", "used in output tables only" \ No newline at end of file diff --git a/docs/source/set_desc_and_tables.rst b/docs/source/set_desc_and_tables.rst new file mode 100644 index 000000000..236a3641e --- /dev/null +++ b/docs/source/set_desc_and_tables.rst @@ -0,0 +1,114 @@ +In a mathematical model like Temoa, sets are used to index parameters and +variables. To enable the modeler to translate between the algebraic formulation, +input database, and model code, we provide the mathematical notation used in the +model formulation, as well as the associated names in the +Python code and database schema in the tables below. The code representation is +more verbose than the algebraic version, using full words. + +Our discussion of sets is broken down into several logical categories to make it +easier to parse. The **first group of sets pertains to Temoa's treatment of time**, +as shown below. **Note:** Some entries in the "Database Table" column are +comma-separated. In those cases, the first element refers to the name of the database +table, and the second refers to specific column within the database column used to +identify a specific subset. For example, in the first table below, :code:`time_period` +is the master set and :code:`time_exist` is a subset that defines the user-defined +model time periods to define historical technology vintages that exist prior to +the model's time horizon for optimization. + + +.. csv-table:: + :header: "Set", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + ":math:`\text{P}^e`", ":code:`time_period, flag = e`", ":code:`time_exist`", "model periods prior to the beginning of the optimization time horizon" + ":math:`\text{P}^f`", ":code:`time_period, flag = f`", ":code:`time_future`", "model periods within the optimization time horizon" + ":math:`{}^*\text{P}^o`", ":code:`time_period`", ":code:`time_optimize`", "model time periods to optimize, (:math:`\text{P}^f - \text{max}(\text{P}^f)`); the last time period is removed as it represents the end of the final period" + ":math:`{}^*\text{V}`", ":code:`time_period`", ":code:`vintage_exist`, :code:`vintage_optimize`, :code:`vintage_all`", "tech vintages, (:math:`\text{P}^e \cup \text{P}^o`), derived from time period set and used to track technology vintages across time periods" + ":math:`\text{D}`", ":code:`time_of_day`", ":code:`time_of_day`", "intraday time divisions, either individual or blocks of hours" + ":math:`\text{S}`", ":code:`season_label`", ":code:`time_season`", "intra-annual divisions, e.g., different seasons or different representative days" + "", ":code:`time_season`", ":code:`time_season`", "ordered tuple of seasons by time period" + "", ":code:`time_season_sequential`", ":code:`time_season_to_sequential, ordered_season_sequential`", "superimposed sequential seasons used for seasonal storage and inter-season ramping" + +The sets in the table below define Temoa's representation of **regions**. + +.. csv-table:: + :header: "Set", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + ":math:`\text{R}`", ":code:`region`", ":code:`regions`", "distinct geographical regions" + "", ":code:`region`", ":code:`regional_indices`", "set of all the possible combinations of interregional exchanges plus original region indices" + "", ":code:`region_group_check`", ":code:`regional_global_indices`", "set used to validate regional group constraints; includes individual regions, exchange pairs, and groups" + +The sets below define how technologies are represented within Temoa. Because technologies +can serve many different functions across an energy system, we need to define a large +number of **technology subsets**. + +.. csv-table:: + :header: "Set", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + ":math:`{}^*\text{T}`", ":code:`technology`", ":code:`tech_all`", "all technologies to be modeled (:math:`{T}^r \cup {T}^p`)" + ":math:`\text{T}^p`", ":code:`technology, flag = p`", ":code:`tech_production`", "technologies producing intermediate commodities, like electricity" + ":math:`\text{T}^b`", ":code:`technology, flag = pb`", ":code:`tech_baseload`", "baseload electric generators, which have constant output across intraday time segments (:math:`{T}^b \subset T`)" + ":math:`\text{T}^s`", ":code:`technology, flag = ps`", ":code:`tech_storage`", "all storage technologies (:math:`{T}^s \subset T`)" + ":math:`\text{T}^a`", ":code:`technology, annual = 1`", ":code:`tech_annual`", "technologies that produce constant annual output (:math:`{T}^a \subset T`)" + ":math:`\text{T}^{res}`", ":code:`technology, reserve = 1`", ":code:`tech_reserve`", "electric generators contributing to the reserve margin requirement (:math:`{T}^{res} \subset T`)" + ":math:`\text{T}^c`", ":code:`technology, curtail = 1`", ":code:`tech_curtailment`", "technologies with curtailable output and no upstream cost (:math:`{T}^c \subset (T - T^{res})`)" + ":math:`\text{T}^f`", ":code:`technology, flex = 1`", ":code:`tech_flex`", "technologies producing excess commodity flows (:math:`{T}^f \subset T`)" + ":math:`\text{T}^x`", ":code:`technology, exchange = 1`", ":code:`tech_exchange`", "technologies used for interregional commodity flows (:math:`{T}^x \subset T`)" + ":math:`\text{T}^{ur}`", ":code:`technology, ramp_up = 1`", ":code:`tech_upramping`", "electric generators with a ramp up hourly rate limit (:math:`{T}^{ur} \subset T`)" + ":math:`\text{T}^{dr}`", ":code:`technology, ramp_down = 1`", ":code:`tech_downramping`", "electric generators with a ramp down hourly rate limit (:math:`{T}^{dr} \subset T`)" + ":math:`\text{T}^{ret}`", ":code:`technology, retire = 1`", ":code:`tech_retirement`", "technologies allowed to retire before end of life (:math:`{T}^{ret} \subset (T - T^{u})`)" + ":math:`\text{T}^u`", ":code:`technology, unlim_cap = 1`", ":code:`tech_uncap`", "technologies that have no bound on capacity (:math:`{T}^u \subset (T - T^{res})`)" + ":math:`\text{T}^{ss}`", ":code:`technology, seas_stor = 1`", ":code:`tech_seasonal_storage`", "seasonal storage technologies (:math:`{T}^{ss} \subset T^s`)" + "", ":code:`tech_group`", ":code:`tech_group_names`", "named groups for use in group constraints" + "", ":code:`tech_group_member`", ":code:`tech_group_members`", "each technology belonging to each group" + ":math:`\text{T}^e`", ":code:`existing_capacity`", ":code:`tech_exist`", "existing technologies with a past vintage (:math:`{T}^e \subset T`)" + +The sets below define **commodities** that are consumed and produced by different energy +technologies. + +.. csv-table:: + :header: "Set", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + ":math:`\text{C}^d`", ":code:`commodity, flag = d`", ":code:`commodity_demand`", "end-use demand commodities, representing the final consumer demands" + ":math:`\text{C}^e`", ":code:`commodity, flag = e`", ":code:`commodity_emissions`", "emission commodities (e.g., :math:`\text{CO}_\text{2}` :math:`\text{NO}_\text{x}`); filtered by flag" + ":math:`\text{C}^p`", ":code:`commodity, flag = p`", ":code:`commodity_physical`", "physical energy commodities (e.g., electricity, coal, uranium, oil) produced and consumed across the energy system" + ":math:`\text{C}^w`", ":code:`commodity, flag = w, wa , wp`", ":code:`commodity_waste`", "commodity whose production can be greater than its consumption; can be physical, annual, or neither (not balanced, all wasted)" + ":math:`\text{C}^a`", ":code:`commodity, flag = a`", ":code:`commodity_annual`", "same as commodity physical but flows are only balanced over each period (:math:`\text{C}^a \subset \text{C}^p`)" + ":math:`\text{C}^l`", ":code:`commodity, flag = l`", ":code:`commodity_flex`", "(disposable) commodities produced by a flex technology (:math:`\text{C}^l \subset \text{C}^p`)" + ":math:`\text{C}^s`", ":code:`commodity, flag = s`", ":code:`commodity_source`", "primary source commodities, not balanced by :code:`CommodityBalance_constraint`" + ":math:`{}^*\text{C}^c`", "", ":code:`commodity_carrier`", "physical energy carriers and end-use demands (:math:`\text{C}_p \cup \text{C}_d`); union of physical, demand, and waste commodities" + ":math:`{}^*\text{C}`", "", ":code:`commodity_all`", "union of all commodity sets; union of carrier and emissions commodities" + +There is an additional set that defines **operators (=, <, >)**. While not strictly +necessary, defining these operators as a set allows modelers to express constraints +more efficiently. + +.. csv-table:: + :header: "Set", "Database Table", "Model Element", "Notes" + :widths: 15, 20, 25, 40 + + "", ":code:`operator`", ":code:`operator`", "constraint operators" + +As indicated below, there are additional sets that are derived within the model +code and thus do not appear in the database schema. + +.. csv-table:: + :header: "Set", "Model Element", "Notes" + :widths: 15, 25, 60 + + "", ":code:`tech_with_capacity`", "technologies eligible for capacitization; computed as tech_all - tech_uncap" + "", ":code:`tech_or_group`", "technologies or groups combined; union of tech_group_names | tech_all" + ":math:`{}^*\text{C}^c`", ":code:`commodity_carrier`", "physical energy carriers and end-use demands; union of physical, demand, and waste commodities" + ":math:`{}^*\text{C}`", ":code:`commodity_all`", "union of all commodity sets; union of carrier and emissions commodities" + ":math:`\text{T}^e`", ":code:`tech_exist`", "technologies with existing capacity; derived from existing_capacity table" + +These are also python dictionaries and sets used to specific internal data +structures during model construction and are not considered formal model elements: + +- :code:`process_inputs`, :code:`process_outputs`, :code:`process_loans` +- :code:`active_flow_rpsditvo`, :code:`active_flow_rpitvo` +- Various vintage and operational tracking dictionaries +- Time sequencing dictionaries (:code:`time_next`, :code:`time_next_sequential`) \ No newline at end of file From 0e16c0599f019682524f64f4255772123da47179 Mon Sep 17 00:00:00 2001 From: Joe DeCarolis Date: Tue, 3 Mar 2026 21:07:30 -0500 Subject: [PATCH 513/587] Address annoying but incredibly useful coderabbitai suggestions --- docs/source/mathematical_formulation.rst | 12 ++++++------ docs/source/param_desc_and_tables.rst | 9 ++++----- docs/source/set_desc_and_tables.rst | 6 +++--- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/docs/source/mathematical_formulation.rst b/docs/source/mathematical_formulation.rst index 990fd1a82..de0734e40 100644 --- a/docs/source/mathematical_formulation.rst +++ b/docs/source/mathematical_formulation.rst @@ -226,7 +226,7 @@ and demand is balanced at each of these levels: We use the word 'slice' to refer to the tuple of season and time of day :math:`\{s,d\}`. Note that these time slices are user-defined, and can -represent time ranging large blocks of time (e.g., winter-night) to every +represent time ranging from large blocks of time (e.g., winter-night) to every hour in a given season. There are two specifiable period sets: :code:`time_exist` (:math:`\text{P}^e`) @@ -245,7 +245,7 @@ year, and makes them easily accessible via the :code:`time_optimize` set. This :math:`\text{P}^f = \{2010, 2015, 2025\}`, :code:`time_optimize` does not contain 2025: :math:`\text{P}^o =\{2010, 2015\}`. -Temoa assumes that all elements of the :code:`time_existing` and +Temoa assumes that all elements of the :code:`time_exist` and :code:`time_future` sets are integers. Further, these sets are assumed to be ordered, such that the minimum element is "naught". For example, if :math:`\text{P}^f = \{2015, 2020, 2030\}`, then :math:`P_0 = 2015`. In @@ -658,7 +658,7 @@ lifetime, then :code:`LifeTimeTech` can be used instead of :code:`LifeTimeProces linked_techs ^^^^^^^^^^^^ -:math:`{LIT}_{r \in R, t \in T, e \in C^e, t \in T}` +:math:`{LIT}_{r \in R, t \in T, e \in C^e, t' \in T}` In power-to-gas pathways, :math:`CO2` is an input to some processes, including synthetic natural gas production and liquid fuel production via Fischer-Tropsch. @@ -667,7 +667,7 @@ physical commodity that can be included in the :code:`efficiency` table. The :code:`linked_techs` parameter specifies the dummy technology used to convert an emissions commodity to a physical commodity. Note that the first :code:`t` represents the primary upstream technology linked to the dummy linked technology, -which is represented by the second :code:`t` index. +which is represented by the second :code:`t'` index. loan_rate @@ -1046,7 +1046,7 @@ each. :widths: 18, 22, 50 ":math:`FO_{r,p,s,d,i,t,v,o}`",":code:`v_flow_out`","Commodity flow by time slice out of a tech based on a given input" - ":math:`FOA_{r,p,s,d,i,t,v,o}`",":code:`v_flow_out_annual`","Annual commodity flow out of a tech based on a given input" + ":math:`FOA_{r,p,i,t,v,o}`",":code:`v_flow_out_annual`","Annual commodity flow out of a tech based on a given input" ":math:`FIS_{r,p,s,d,i,t,v,o}`",":code:`v_flow_in`","Commodity flow into a storage tech to produce a given output" ":math:`FLX_{r,p,s,d,i,t,v,o}`",":code:`v_flex`","The portion of commodity production exceeding demand" ":math:`FLXA_{r,p,i,t,v,o}`",":code:`v_flex_annual`","The portion of commodity production from constant production techs exceeding demand" @@ -1231,7 +1231,7 @@ variables to distinguish them from parameters. Second, you will notice the use of the Theta superset (:math:`\Theta`). The Temoa code makes heavy use of sparse sets, for both correctness and efficient use of computational resources. For brevity, and to avoid discussion of implementation details, we do not -enumerate their logical creation here. Instead, we rely on the readers general +enumerate their logical creation here. Instead, we rely on the reader's general understanding of the context. The use of (:math:`\Theta`) means that the constraint is only defined for the exact indices that the modeler specified. diff --git a/docs/source/param_desc_and_tables.rst b/docs/source/param_desc_and_tables.rst index 08d503590..75f7c66fa 100644 --- a/docs/source/param_desc_and_tables.rst +++ b/docs/source/param_desc_and_tables.rst @@ -89,7 +89,7 @@ capacity, activity and emissions**. ":math:`\text{LNC}_{r,p,t}`", ":code:`limit_new_capacity`", ":code:`limit_new_capacity`", "limit on new capacity deployment by period" ":math:`\text{LA}_{r,p,t}`", ":code:`limit_activity`", ":code:`limit_activity`", "limit on technology-specific activity by region and period" ":math:`\text{LE}_{r,p,e}`", ":code:`limit_emission`", ":code:`limit_emission`", "limit on emissions by region and period" - ":math:`\text{LR}_{r,t}`", ":code:`limit_resource`", ":code:`limit_resource`", "cumulative activity limit across time periods (not supported in myopic)" + ":math:`\text{LS}_{r,t}`", ":code:`limit_resource`", ":code:`limit_resource`", "cumulative activity limit across time periods (not supported in myopic)" Parameters in the table below relate to the specification of **growth and degrowth limits**. @@ -137,7 +137,7 @@ Parameters in the table below relate to the specification of **policy**. :widths: 15, 20, 25, 40 "", ":code:`rps_requirement`", ":code:`renewable_portfolio_standard`", "**[Deprecated]** RPS requirements; use :code:`limit_activity_share` instead" - ":math:`\text{LIT}_{r,t,e,t}`", ":code:`linked_tech`", ":code:`linked_techs`", "dummy techs used to convert CO2 emissions to physical commodity" + ":math:`\text{LIT}_{r,t,e,t'}`", ":code:`linked_tech`", ":code:`linked_techs`", "dummy techs used to convert CO2 emissions to physical commodity" Parameters in the table below relate to the specification of **construction and end-of-life**. @@ -157,7 +157,6 @@ therefore do not appear in the database**. :widths: 15, 20, 25, 40 ":math:`{}^*\text{LEN}_p`", "", ":code:`period_length`", "number of years in period :math:`p`; computed from time periods" - "", "", ":code:`segment_fraction_per_season`", "computed from segment fractions" ":math:`{}^*\text{LA}_{t,v}`", "", ":code:`loan_annualize`", "loan amortization by tech and vintage; based on :math:`DR_t`; computed from loan rate and lifetime" ":math:`{}^*\text{PLF}_{r,p,t,v}`", "", ":code:`process_life_frac`", "fraction of available process capacity by region and period; computed from process life fraction" "", "", ":code:`segment_fraction_per_season`", "computed internally from segment fractions" @@ -179,8 +178,8 @@ successful run completion. - :code:`output_emission` - :code:`output_cost` -Finally, the database tables below do not have a directed mapping to the the -model code. +Finally, the database tables below do not have a directed mapping to the model +code. .. csv-table:: :header: "Database Table", "Purpose", "Notes" diff --git a/docs/source/set_desc_and_tables.rst b/docs/source/set_desc_and_tables.rst index 236a3641e..04b6b8a51 100644 --- a/docs/source/set_desc_and_tables.rst +++ b/docs/source/set_desc_and_tables.rst @@ -9,7 +9,7 @@ Our discussion of sets is broken down into several logical categories to make it easier to parse. The **first group of sets pertains to Temoa's treatment of time**, as shown below. **Note:** Some entries in the "Database Table" column are comma-separated. In those cases, the first element refers to the name of the database -table, and the second refers to specific column within the database column used to +table, and the second refers to specific column within the database table used to identify a specific subset. For example, in the first table below, :code:`time_period` is the master set and :code:`time_exist` is a subset that defines the user-defined model time periods to define historical technology vintages that exist prior to @@ -79,7 +79,7 @@ technologies. ":math:`\text{C}^a`", ":code:`commodity, flag = a`", ":code:`commodity_annual`", "same as commodity physical but flows are only balanced over each period (:math:`\text{C}^a \subset \text{C}^p`)" ":math:`\text{C}^l`", ":code:`commodity, flag = l`", ":code:`commodity_flex`", "(disposable) commodities produced by a flex technology (:math:`\text{C}^l \subset \text{C}^p`)" ":math:`\text{C}^s`", ":code:`commodity, flag = s`", ":code:`commodity_source`", "primary source commodities, not balanced by :code:`CommodityBalance_constraint`" - ":math:`{}^*\text{C}^c`", "", ":code:`commodity_carrier`", "physical energy carriers and end-use demands (:math:`\text{C}_p \cup \text{C}_d`); union of physical, demand, and waste commodities" + ":math:`{}^*\text{C}^c`", "", ":code:`commodity_carrier`", "union of physical, demand, and waste commodities, (:math:`\text{C}_p \cup \text{C}_d \cup \text{C}^w`)" ":math:`{}^*\text{C}`", "", ":code:`commodity_all`", "union of all commodity sets; union of carrier and emissions commodities" There is an additional set that defines **operators (=, <, >)**. While not strictly @@ -105,7 +105,7 @@ code and thus do not appear in the database schema. ":math:`{}^*\text{C}`", ":code:`commodity_all`", "union of all commodity sets; union of carrier and emissions commodities" ":math:`\text{T}^e`", ":code:`tech_exist`", "technologies with existing capacity; derived from existing_capacity table" -These are also python dictionaries and sets used to specific internal data +There are also python dictionaries and sets used to specify internal data structures during model construction and are not considered formal model elements: - :code:`process_inputs`, :code:`process_outputs`, :code:`process_loans` From a620716b3d85c576c05af922637cafc543e6d22a Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 24 Mar 2026 17:35:50 -0400 Subject: [PATCH 514/587] removing data_files --- data_files/.gitignore | 6 - data_files/README.txt | 11 - data_files/example_dbs/.gitignore | 3 - data_files/example_dbs/README.txt | 8 - data_files/example_dbs/materials.sql | 1405 ---------------- data_files/example_dbs/morris_utopia.sql | 1442 ---------------- data_files/example_dbs/seasonal_storage.sql | 1080 ------------ data_files/example_dbs/stepped_demand.sql | 1215 -------------- data_files/example_dbs/survival_curve.sql | 1166 ------------- data_files/example_dbs/test_system.sql | 1450 ----------------- data_files/example_dbs/utopia.sql | 1439 ---------------- data_files/monte_carlo/run_settings_1.csv | 5 - data_files/my_configs/.gitignore | 2 - data_files/my_configs/config_sample.toml | 165 -- data_files/my_configs/materials.toml | 161 -- data_files/my_configs/mga_utopia.toml | 138 -- data_files/my_configs/monte_carlo_utopia.toml | 158 -- data_files/my_configs/morris_utopia.toml | 142 -- data_files/my_configs/seasonal_storage.toml | 161 -- data_files/my_configs/stepped_demand.toml | 131 -- data_files/temoa_basics_0.sql | 374 ----- data_files/temoa_basics_1.sql | 507 ------ data_files/temoa_basics_2.sql | 753 --------- data_files/temoa_schema_v3.sql | 921 ----------- data_files/temoa_schema_v3_1.sql | 1055 ------------ data_files/temoa_schema_v4.sql | 1068 ------------ 26 files changed, 14966 deletions(-) delete mode 100644 data_files/.gitignore delete mode 100644 data_files/README.txt delete mode 100644 data_files/example_dbs/.gitignore delete mode 100644 data_files/example_dbs/README.txt delete mode 100644 data_files/example_dbs/materials.sql delete mode 100644 data_files/example_dbs/morris_utopia.sql delete mode 100644 data_files/example_dbs/seasonal_storage.sql delete mode 100644 data_files/example_dbs/stepped_demand.sql delete mode 100644 data_files/example_dbs/survival_curve.sql delete mode 100644 data_files/example_dbs/test_system.sql delete mode 100644 data_files/example_dbs/utopia.sql delete mode 100644 data_files/monte_carlo/run_settings_1.csv delete mode 100644 data_files/my_configs/.gitignore delete mode 100644 data_files/my_configs/config_sample.toml delete mode 100644 data_files/my_configs/materials.toml delete mode 100644 data_files/my_configs/mga_utopia.toml delete mode 100644 data_files/my_configs/monte_carlo_utopia.toml delete mode 100644 data_files/my_configs/morris_utopia.toml delete mode 100644 data_files/my_configs/seasonal_storage.toml delete mode 100644 data_files/my_configs/stepped_demand.toml delete mode 100644 data_files/temoa_basics_0.sql delete mode 100644 data_files/temoa_basics_1.sql delete mode 100644 data_files/temoa_basics_2.sql delete mode 100644 data_files/temoa_schema_v3.sql delete mode 100644 data_files/temoa_schema_v3_1.sql delete mode 100644 data_files/temoa_schema_v4.sql diff --git a/data_files/.gitignore b/data_files/.gitignore deleted file mode 100644 index 7878eb8af..000000000 --- a/data_files/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -# locally ignore all .dat files and newly added .sqlite db's -*.sqlite -*.dat -*.xlsx -*.log - diff --git a/data_files/README.txt b/data_files/README.txt deleted file mode 100644 index 1949067c1..000000000 --- a/data_files/README.txt +++ /dev/null @@ -1,11 +0,0 @@ -This directory contains sample files that can be used to test Temoa. - -Temoa works by reading a relational database (sqlite). - -*.sql files represent text files of SQL commands used to construct a relational database file. - -*.sqlite files represent the compiled sqlite databases. A sqlite file -is created from a sql file using sqlite, which is freely available: -https://sqlite.org/index.html. From the command prompt: - -$ sqlite3 temoa_utopia.sqlite < temoa_utopia.sql diff --git a/data_files/example_dbs/.gitignore b/data_files/example_dbs/.gitignore deleted file mode 100644 index a91930053..000000000 --- a/data_files/example_dbs/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# ignore any built databases -*.sqlite -*.db \ No newline at end of file diff --git a/data_files/example_dbs/README.txt b/data_files/example_dbs/README.txt deleted file mode 100644 index eb3a5fc2e..000000000 --- a/data_files/example_dbs/README.txt +++ /dev/null @@ -1,8 +0,0 @@ -The exemplar databases here are version controlled in textual .sql format, which is more workable -with Git than binary .sqlite files. - -If you wish to use them, use sqlite to convert them to database format. The command is: - -> sqlite3 utopia.sqlite < utopia.sql - -This command will make the sqlite database from the sql commands \ No newline at end of file diff --git a/data_files/example_dbs/materials.sql b/data_files/example_dbs/materials.sql deleted file mode 100644 index da4d7bc08..000000000 --- a/data_files/example_dbs/materials.sql +++ /dev/null @@ -1,1405 +0,0 @@ -BEGIN TRANSACTION; -CREATE TABLE capacity_credit -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -CREATE TABLE capacity_factor_process -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE capacity_factor_tech -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -INSERT INTO "capacity_factor_tech" VALUES('RegionA','summer','morning','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA','autumn','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA','winter','morning','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA','spring','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA','summer','afternoon','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA','autumn','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA','winter','afternoon','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA','spring','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA','summer','evening','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA','autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA','winter','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA','spring','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA','summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA','autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA','winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionA','spring','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB','summer','morning','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB','autumn','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB','winter','morning','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB','spring','morning','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB','summer','afternoon','SOL_PV',0.3,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB','autumn','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB','winter','afternoon','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB','spring','afternoon','SOL_PV',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB','summer','evening','SOL_PV',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB','autumn','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB','winter','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB','spring','evening','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB','summer','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB','autumn','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB','winter','overnight','SOL_PV',0.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('RegionB','spring','overnight','SOL_PV',0.0,NULL); -CREATE TABLE capacity_to_activity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES commodity_type (label), - description TEXT -); -INSERT INTO "commodity" VALUES('ethos','s','import dummy source'); -INSERT INTO "commodity" VALUES('electricity','p','grid electricity'); -INSERT INTO "commodity" VALUES('passenger_km','d','demand for passenger km'); -INSERT INTO "commodity" VALUES('battery_nmc','a','battery - lithium nickel manganese cobalt oxide'); -INSERT INTO "commodity" VALUES('battery_lfp','a','battery - lithium iron phosphate'); -INSERT INTO "commodity" VALUES('lithium','a','lithium'); -INSERT INTO "commodity" VALUES('cobalt','a','cobalt'); -INSERT INTO "commodity" VALUES('phosphorous','a','phosphorous'); -INSERT INTO "commodity" VALUES('diesel','a','diesel'); -INSERT INTO "commodity" VALUES('heating','d','demand for residential heating'); -INSERT INTO "commodity" VALUES('nickel','a','nickel'); -INSERT INTO "commodity" VALUES('used_batt_nmc','wa','used battery - lithium nickel manganese cobalt oxide'); -INSERT INTO "commodity" VALUES('used_batt_lfp','wa','used battery - lithium iron phosphate'); -INSERT INTO "commodity" VALUES('co2e','e','emitted co2-equivalent GHGs'); -INSERT INTO "commodity" VALUES('waste_steel','w','waste steel from cars'); -CREATE TABLE commodity_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "commodity_type" VALUES('w','waste commodity'); -INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); -INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); -INSERT INTO "commodity_type" VALUES('a','annual commodity'); -INSERT INTO "commodity_type" VALUES('p','physical commodity'); -INSERT INTO "commodity_type" VALUES('e','emissions commodity'); -INSERT INTO "commodity_type" VALUES('d','demand commodity'); -INSERT INTO "commodity_type" VALUES('s','source commodity'); -CREATE TABLE construction_input -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage) -); -INSERT INTO "construction_input" VALUES('RegionA','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO "construction_input" VALUES('RegionA','battery_lfp','CAR_PHEV',2000,0.1,NULL,NULL); -INSERT INTO "construction_input" VALUES('RegionA','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO "construction_input" VALUES('RegionA','battery_lfp','CAR_PHEV',2010,0.1,NULL,NULL); -INSERT INTO "construction_input" VALUES('RegionA','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO "construction_input" VALUES('RegionA','battery_lfp','CAR_PHEV',2020,0.1,NULL,NULL); -INSERT INTO "construction_input" VALUES('RegionB','battery_nmc','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO "construction_input" VALUES('RegionB','battery_lfp','CAR_PHEV',2000,0.1,NULL,NULL); -INSERT INTO "construction_input" VALUES('RegionB','battery_nmc','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO "construction_input" VALUES('RegionB','battery_lfp','CAR_PHEV',2010,0.1,NULL,NULL); -INSERT INTO "construction_input" VALUES('RegionB','battery_nmc','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO "construction_input" VALUES('RegionB','battery_lfp','CAR_PHEV',2020,0.1,NULL,NULL); -CREATE TABLE cost_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT NOT NULL - REFERENCES commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -INSERT INTO "cost_emission" VALUES('RegionA',2000,'co2e',1.0,NULL,NULL); -INSERT INTO "cost_emission" VALUES('RegionA',2010,'co2e',1.0,NULL,NULL); -INSERT INTO "cost_emission" VALUES('RegionA',2020,'co2e',1.0,NULL,NULL); -INSERT INTO "cost_emission" VALUES('RegionB',2000,'co2e',1.0,NULL,NULL); -INSERT INTO "cost_emission" VALUES('RegionB',2010,'co2e',1.0,NULL,NULL); -INSERT INTO "cost_emission" VALUES('RegionB',2020,'co2e',1.0,NULL,NULL); -CREATE TABLE cost_fixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE cost_invest -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "cost_invest" VALUES('RegionA','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionA','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionA','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionA','CAR_PHEV',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionA','CAR_PHEV',2010,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionA','CAR_PHEV',2020,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionA','CAR_ICE',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionA','CAR_ICE',2010,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionA','CAR_ICE',2020,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionA','RECYCLE_NMC',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionA','RECYCLE_LFP',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionA','MANUFAC_NMC',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionA','MANUFAC_LFP',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionA','BATT_GRID',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionA','SOL_PV',2000,10.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionA','GEN_DSL',2000,2.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionB','CAR_BEV',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionB','CAR_BEV',2010,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionB','CAR_BEV',2020,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionB','CAR_PHEV',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionB','CAR_PHEV',2010,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionB','CAR_PHEV',2020,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionB','CAR_ICE',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionB','CAR_ICE',2010,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionB','CAR_ICE',2020,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionB','RECYCLE_NMC',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionB','RECYCLE_LFP',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionB','MANUFAC_NMC',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionB','MANUFAC_LFP',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionB','BATT_GRID',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionB','GEN_DSL',2000,2.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionA-RegionB','ELEC_INTERTIE',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionB-RegionA','ELEC_INTERTIE',2000,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('RegionB','SOL_PV',2000,1.0,NULL,NULL); -CREATE TABLE cost_variable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_variable" VALUES('RegionA',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionA',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionA',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionA',2000,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionA',2010,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionA',2020,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionA',2000,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionA',2010,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionA',2020,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionA',2000,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionA',2010,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionA',2020,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionA',2000,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionA',2010,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionA',2020,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionA',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionA',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionA',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionB',2000,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionB',2010,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionB',2020,'IMPORT_DSL',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionB',2000,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionB',2010,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionB',2020,'IMPORT_LI',2000,2.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionB',2000,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionB',2010,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionB',2020,'IMPORT_NI',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionB',2000,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionB',2010,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionB',2020,'IMPORT_CO',2000,5.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionB',2000,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionB',2010,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionB',2020,'IMPORT_P',2000,3.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionB',2000,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionB',2010,'DOMESTIC_NI',2000,0.5,NULL,NULL); -INSERT INTO "cost_variable" VALUES('RegionB',2020,'DOMESTIC_NI',2000,0.5,NULL,NULL); -CREATE TABLE demand -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - commodity TEXT - REFERENCES commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -INSERT INTO "demand" VALUES('RegionA',2000,'passenger_km',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('RegionA',2010,'passenger_km',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('RegionA',2020,'passenger_km',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('RegionA',2000,'heating',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('RegionA',2010,'heating',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('RegionA',2020,'heating',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('RegionB',2000,'passenger_km',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('RegionB',2010,'passenger_km',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('RegionB',2020,'passenger_km',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('RegionB',2000,'heating',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('RegionB',2010,'heating',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('RegionB',2020,'heating',1.0,NULL,NULL); -CREATE TABLE demand_specific_distribution -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - demand_name TEXT - REFERENCES commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -INSERT INTO "demand_specific_distribution" VALUES('RegionA','summer','morning','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA','autumn','morning','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA','winter','morning','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA','spring','morning','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA','summer','afternoon','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA','autumn','afternoon','heating',0.08,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA','winter','afternoon','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA','spring','afternoon','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA','summer','evening','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA','autumn','evening','heating',0.08,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA','winter','evening','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA','spring','evening','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA','summer','overnight','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA','autumn','overnight','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA','winter','overnight','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionA','spring','overnight','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB','summer','morning','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB','autumn','morning','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB','winter','morning','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB','spring','morning','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB','summer','afternoon','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB','autumn','afternoon','heating',0.08,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB','winter','afternoon','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB','spring','afternoon','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB','summer','evening','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB','autumn','evening','heating',0.08,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB','winter','evening','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB','spring','evening','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB','summer','overnight','heating',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB','autumn','overnight','heating',0.12,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB','winter','overnight','heating',0.16,NULL); -INSERT INTO "demand_specific_distribution" VALUES('RegionB','spring','overnight','heating',0.0,NULL); -CREATE TABLE efficiency -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -INSERT INTO "efficiency" VALUES('RegionA','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2,NULL); -INSERT INTO "efficiency" VALUES('RegionA','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2,NULL); -INSERT INTO "efficiency" VALUES('RegionA','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','electricity','RECYCLE_NMC',2000,'battery_nmc',0.001,'Effectively zero'); -INSERT INTO "efficiency" VALUES('RegionA','electricity','RECYCLE_LFP',2000,'battery_lfp',0.001,'Effectively zero'); -INSERT INTO "efficiency" VALUES('RegionA','electricity','MANUFAC_NMC',2000,'battery_nmc',0.001,'Effectively zero'); -INSERT INTO "efficiency" VALUES('RegionA','electricity','MANUFAC_LFP',2000,'battery_lfp',0.001,'Effectively zero'); -INSERT INTO "efficiency" VALUES('RegionA','diesel','GEN_DSL',2000,'electricity',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','ethos','SOL_PV',2000,'electricity',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','electricity','BATT_GRID',2000,'electricity',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','diesel','FURNACE',2000,'heating',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','electricity','HEATPUMP',2000,'heating',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','ethos','DOMESTIC_NI',2000,'nickel',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','ethos','IMPORT_LI',2000,'lithium',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','ethos','IMPORT_NI',2000,'nickel',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','ethos','IMPORT_CO',2000,'cobalt',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','ethos','IMPORT_P',2000,'phosphorous',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','used_batt_nmc','RECYCLE_NMC',2000,'battery_nmc',0.2,NULL); -INSERT INTO "efficiency" VALUES('RegionB','used_batt_lfp','RECYCLE_LFP',2000,'battery_lfp',0.2,NULL); -INSERT INTO "efficiency" VALUES('RegionB','lithium','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','nickel','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','cobalt','MANUFAC_NMC',2000,'battery_nmc',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','lithium','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','phosphorous','MANUFAC_LFP',2000,'battery_lfp',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','electricity','RECYCLE_NMC',2000,'battery_nmc',0.001,'Effectively zero'); -INSERT INTO "efficiency" VALUES('RegionB','electricity','RECYCLE_LFP',2000,'battery_lfp',0.001,'Effectively zero'); -INSERT INTO "efficiency" VALUES('RegionB','electricity','MANUFAC_NMC',2000,'battery_nmc',0.001,'Effectively zero'); -INSERT INTO "efficiency" VALUES('RegionB','electricity','MANUFAC_LFP',2000,'battery_lfp',0.001,'Effectively zero'); -INSERT INTO "efficiency" VALUES('RegionB','diesel','GEN_DSL',2000,'electricity',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','ethos','SOL_PV',2000,'electricity',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','electricity','BATT_GRID',2000,'electricity',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','diesel','FURNACE',2000,'heating',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','electricity','HEATPUMP',2000,'heating',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','electricity','CAR_BEV',1990,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','electricity','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','diesel','CAR_PHEV',1990,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','diesel','CAR_ICE',1990,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','electricity','CAR_BEV',2000,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','electricity','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','diesel','CAR_PHEV',2000,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','diesel','CAR_ICE',2000,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','electricity','CAR_BEV',2010,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','electricity','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','diesel','CAR_PHEV',2010,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','diesel','CAR_ICE',2010,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','electricity','CAR_BEV',2020,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','electricity','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','diesel','CAR_PHEV',2020,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionB','diesel','CAR_ICE',2020,'passenger_km',1.0,NULL); -INSERT INTO "efficiency" VALUES('RegionA-RegionB','electricity','ELEC_INTERTIE',2000,'electricity',0.9,NULL); -INSERT INTO "efficiency" VALUES('RegionB-RegionA','electricity','ELEC_INTERTIE',2000,'electricity',0.9,NULL); -CREATE TABLE efficiency_variable -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE emission_activity -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -INSERT INTO "emission_activity" VALUES('RegionA','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); -INSERT INTO "emission_activity" VALUES('RegionB','co2e','ethos','IMPORT_DSL',2000,'diesel',1.0,NULL,'assumed combusted'); -CREATE TABLE emission_embodied -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE emission_end_of_life -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_PHEV',1990,'used_batt_lfp',0.1,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_PHEV',2000,'used_batt_lfp',0.1,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_PHEV',2010,'used_batt_lfp',0.1,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_BEV',1990,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_PHEV',1990,'used_batt_lfp',0.1,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_BEV',2000,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_PHEV',2000,'used_batt_lfp',0.1,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_BEV',2010,'used_batt_nmc',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_PHEV',2010,'used_batt_lfp',0.1,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionA','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_BEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_ICE',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_PHEV',1990,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_BEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_ICE',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_PHEV',2000,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_BEV',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_ICE',2010,'waste_steel',1.0,NULL,NULL); -INSERT INTO "end_of_life_output" VALUES('RegionB','CAR_PHEV',2010,'waste_steel',1.0,NULL,NULL); -CREATE TABLE existing_capacity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "existing_capacity" VALUES('RegionA','CAR_BEV',1990,1.0,NULL,NULL); -INSERT INTO "existing_capacity" VALUES('RegionA','CAR_PHEV',1990,1.0,NULL,NULL); -INSERT INTO "existing_capacity" VALUES('RegionA','CAR_ICE',1990,1.0,NULL,NULL); -INSERT INTO "existing_capacity" VALUES('RegionB','CAR_BEV',1990,1.0,NULL,NULL); -INSERT INTO "existing_capacity" VALUES('RegionB','CAR_PHEV',1990,1.0,NULL,NULL); -INSERT INTO "existing_capacity" VALUES('RegionB','CAR_ICE',1990,1.0,NULL,NULL); -CREATE TABLE lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_survival_curve -( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE lifetime_tech -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "lifetime_tech" VALUES('RegionA','CAR_BEV',10.0,NULL); -INSERT INTO "lifetime_tech" VALUES('RegionA','CAR_PHEV',10.0,NULL); -INSERT INTO "lifetime_tech" VALUES('RegionA','CAR_ICE',10.0,NULL); -INSERT INTO "lifetime_tech" VALUES('RegionB','CAR_BEV',10.0,NULL); -INSERT INTO "lifetime_tech" VALUES('RegionB','CAR_PHEV',10.0,NULL); -INSERT INTO "lifetime_tech" VALUES('RegionB','CAR_ICE',10.0,NULL); -CREATE TABLE limit_activity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_degrowth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE limit_growth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - season TEXT - REFERENCES time_season (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, season, tech, operator) -); -CREATE TABLE limit_storage_level_fraction -( - region TEXT, - season TEXT, - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - fraction REAL, - notes TEXT, - CHECK (fraction >= 0 AND fraction <= 1), - PRIMARY KEY(region, season, tod, tech, operator) -); -CREATE TABLE limit_tech_input_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_input_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2000,'lithium','MANUFAC_NMC','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2000,'nickel','MANUFAC_NMC','le',0.15,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2000,'cobalt','MANUFAC_NMC','le',0.04,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2000,'electricity','MANUFAC_NMC','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2000,'lithium','MANUFAC_LFP','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2000,'phosphorous','MANUFAC_LFP','le',0.19,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2000,'electricity','MANUFAC_LFP','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2010,'lithium','MANUFAC_NMC','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2010,'nickel','MANUFAC_NMC','le',0.15,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2010,'cobalt','MANUFAC_NMC','le',0.04,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2010,'electricity','MANUFAC_NMC','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2010,'lithium','MANUFAC_LFP','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2010,'phosphorous','MANUFAC_LFP','le',0.19,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2010,'electricity','MANUFAC_LFP','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2020,'lithium','MANUFAC_NMC','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2020,'nickel','MANUFAC_NMC','le',0.15,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2020,'cobalt','MANUFAC_NMC','le',0.04,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2020,'electricity','MANUFAC_NMC','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2020,'lithium','MANUFAC_LFP','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2020,'phosphorous','MANUFAC_LFP','le',0.19,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2020,'electricity','MANUFAC_LFP','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2000,'electricity','CAR_PHEV','le',0.2,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2000,'diesel','CAR_PHEV','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2010,'electricity','CAR_PHEV','le',0.2,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2010,'diesel','CAR_PHEV','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2020,'electricity','CAR_PHEV','le',0.2,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionA',2020,'diesel','CAR_PHEV','le',0.8,NULL); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2000,'lithium','MANUFAC_NMC','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2000,'nickel','MANUFAC_NMC','le',0.15,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2000,'cobalt','MANUFAC_NMC','le',0.04,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2000,'electricity','MANUFAC_NMC','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2000,'lithium','MANUFAC_LFP','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2000,'phosphorous','MANUFAC_LFP','le',0.19,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2000,'electricity','MANUFAC_LFP','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2010,'lithium','MANUFAC_NMC','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2010,'nickel','MANUFAC_NMC','le',0.15,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2010,'cobalt','MANUFAC_NMC','le',0.04,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2010,'electricity','MANUFAC_NMC','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2010,'lithium','MANUFAC_LFP','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2010,'phosphorous','MANUFAC_LFP','le',0.19,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2010,'electricity','MANUFAC_LFP','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2020,'lithium','MANUFAC_NMC','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2020,'nickel','MANUFAC_NMC','le',0.15,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2020,'cobalt','MANUFAC_NMC','le',0.04,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2020,'electricity','MANUFAC_NMC','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2020,'lithium','MANUFAC_LFP','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2020,'phosphorous','MANUFAC_LFP','le',0.19,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2020,'electricity','MANUFAC_LFP','le',0.01,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2000,'electricity','CAR_PHEV','le',0.2,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2000,'diesel','CAR_PHEV','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2010,'electricity','CAR_PHEV','le',0.2,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2010,'diesel','CAR_PHEV','le',0.8,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2020,'electricity','CAR_PHEV','le',0.2,''); -INSERT INTO "limit_tech_input_split_annual" VALUES('RegionB',2020,'diesel','CAR_PHEV','le',0.8,NULL); -CREATE TABLE limit_tech_output_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE limit_tech_output_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE linked_tech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES technology (tech), - emis_comm TEXT - REFERENCES commodity (name), - driven_tech TEXT - REFERENCES technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -CREATE TABLE loan_lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE loan_rate -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); -INSERT INTO "metadata" VALUES('DB_MINOR',0,''); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -CREATE TABLE myopic_efficiency -( - base_year integer, - region text, - input_comm text, - tech text, - vintage integer, - output_comm text, - efficiency real, - lifetime integer, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (region, input_comm, tech, vintage, output_comm) -); -CREATE TABLE operator -( - operator TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "operator" VALUES('e','equal to'); -INSERT INTO "operator" VALUES('le','less than or equal to'); -INSERT INTO "operator" VALUES('ge','greater than or equal to'); -CREATE TABLE output_built_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES sector_label (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) -); -CREATE TABLE output_curtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE output_emission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE output_flow_in -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out_summary -( - scenario TEXT NOT NULL, - region TEXT NOT NULL, - sector TEXT, - period INTEGER, - input_comm TEXT NOT NULL, - tech TEXT NOT NULL, - vintage INTEGER, - output_comm TEXT NOT NULL, - flow REAL NOT NULL, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_net_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_objective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE output_retired_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_storage_level -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT, - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE planning_reserve_margin -( - region TEXT - PRIMARY KEY - REFERENCES region (region), - margin REAL, - notes TEXT -); -CREATE TABLE ramp_down_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE ramp_up_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -INSERT INTO "region" VALUES('RegionA',NULL); -INSERT INTO "region" VALUES('RegionB',NULL); -CREATE TABLE reserve_capacity_derate -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE rps_requirement -( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL - REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES tech_group (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE sector_label -( - sector TEXT PRIMARY KEY, - notes TEXT -); -CREATE TABLE storage_duration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "storage_duration" VALUES('RegionA','BATT_GRID',2.0,'2 hours energy storage'); -INSERT INTO "storage_duration" VALUES('RegionB','BATT_GRID',2.0,'2 hours energy storage'); -CREATE TABLE tech_group -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE tech_group_member -( - group_name TEXT - REFERENCES tech_group (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technology_type (label) -); -INSERT INTO "technology" VALUES('IMPORT_LI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'lithium importer'); -INSERT INTO "technology" VALUES('IMPORT_CO','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'cobalt importer'); -INSERT INTO "technology" VALUES('IMPORT_P','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'phosphorous importer'); -INSERT INTO "technology" VALUES('CAR_BEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - battery electric'); -INSERT INTO "technology" VALUES('CAR_PHEV','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - plug in hybrid'); -INSERT INTO "technology" VALUES('CAR_ICE','p','transportation',NULL,NULL,0,0,0,0,0,0,0,0,'car - internal combustion'); -INSERT INTO "technology" VALUES('RECYCLE_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'nmc battery recycler'); -INSERT INTO "technology" VALUES('RECYCLE_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'lfp battery recycler'); -INSERT INTO "technology" VALUES('MANUFAC_NMC','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'nmc battery manufacturing'); -INSERT INTO "technology" VALUES('MANUFAC_LFP','p','materials',NULL,NULL,0,1,0,0,0,0,0,0,'lfp battery manufacturing'); -INSERT INTO "technology" VALUES('IMPORT_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'nickel importer'); -INSERT INTO "technology" VALUES('DOMESTIC_NI','p','materials',NULL,NULL,1,1,0,0,0,0,0,0,'domestic nickel production'); -INSERT INTO "technology" VALUES('GEN_DSL','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,'diesel generators'); -INSERT INTO "technology" VALUES('SOL_PV','p','electricity',NULL,NULL,0,0,0,1,0,0,0,0,'solar panels'); -INSERT INTO "technology" VALUES('BATT_GRID','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,0,'grid battery storage'); -INSERT INTO "technology" VALUES('FURNACE','p','residential',NULL,NULL,1,0,0,0,0,0,0,0,'diesel furnace heater'); -INSERT INTO "technology" VALUES('HEATPUMP','p','residential',NULL,NULL,1,0,0,0,0,0,0,0,'heat pump'); -INSERT INTO "technology" VALUES('IMPORT_DSL','p','fuels',NULL,NULL,1,1,0,0,0,0,0,0,'diesel importer'); -INSERT INTO "technology" VALUES('ELEC_INTERTIE','p','electricity',NULL,NULL,0,0,0,0,0,0,1,0,'dummy tech to make landfill feasible'); -CREATE TABLE technology_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "technology_type" VALUES('p','production technology'); -INSERT INTO "technology_type" VALUES('pb','baseload production technology'); -INSERT INTO "technology_type" VALUES('ps','storage production technology'); -CREATE TABLE time_of_day -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY, - hours REAL NOT NULL DEFAULT 1, - notes TEXT, - CHECK (hours > 0) -); -INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(1,'morning',6); -INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(2,'afternoon',6); -INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(3,'evening',6); -INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(4,'overnight',6); -CREATE TABLE time_period -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES time_period_type (label) -); -INSERT INTO "time_period" VALUES(1,1990,'e'); -INSERT INTO "time_period" VALUES(2,2000,'f'); -INSERT INTO "time_period" VALUES(3,2010,'f'); -INSERT INTO "time_period" VALUES(4,2020,'f'); -INSERT INTO "time_period" VALUES(5,2030,'f'); -CREATE TABLE time_period_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "time_period_type" VALUES('e','existing vintages'); -INSERT INTO "time_period_type" VALUES('f','future'); -CREATE TABLE time_season -( - sequence INTEGER UNIQUE, - season TEXT, - segment_fraction REAL NOT NULL, - notes TEXT, - PRIMARY KEY (season), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); -INSERT INTO "time_season" VALUES(0,'summer',0.25,NULL); -INSERT INTO "time_season" VALUES(1,'autumn',0.25,NULL); -INSERT INTO "time_season" VALUES(2,'winter',0.25,NULL); -INSERT INTO "time_season" VALUES(3,'spring',0.25,NULL); - -CREATE TABLE time_season_sequential -( - sequence INTEGER UNIQUE, - seas_seq TEXT, - season TEXT REFERENCES time_season(season), - segment_fraction REAL NOT NULL, - notes TEXT, - PRIMARY KEY (seas_seq), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); - -CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); -COMMIT; diff --git a/data_files/example_dbs/morris_utopia.sql b/data_files/example_dbs/morris_utopia.sql deleted file mode 100644 index c8e6bf970..000000000 --- a/data_files/example_dbs/morris_utopia.sql +++ /dev/null @@ -1,1442 +0,0 @@ -BEGIN TRANSACTION; -CREATE TABLE capacity_credit -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -CREATE TABLE capacity_factor_process -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -INSERT INTO "capacity_factor_process" VALUES('utopia','inter','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia','inter','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia','winter','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia','winter','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia','summer','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia','summer','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia','inter','day','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia','inter','night','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia','winter','day','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia','winter','night','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia','summer','day','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia','summer','night','E31',2010,0.2756,''); -CREATE TABLE capacity_factor_tech -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E70',0.8,''); -CREATE TABLE capacity_to_activity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "capacity_to_activity" VALUES('utopia','E01',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','E21',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','E31',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','E51',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','E70',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','RHE',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','RHO',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','RL1',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','SRE',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','TXD',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','TXE',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','TXG',1.0,''); -CREATE TABLE commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES commodity_type (label), - description TEXT -); -INSERT INTO "commodity" VALUES('ethos','s','# dummy commodity to supply inputs (makes graph easier to read)'); -INSERT INTO "commodity" VALUES('DSL','p','# diesel'); -INSERT INTO "commodity" VALUES('ELC','p','# electricity'); -INSERT INTO "commodity" VALUES('FEQ','p','# fossil equivalent'); -INSERT INTO "commodity" VALUES('GSL','p','# gasoline'); -INSERT INTO "commodity" VALUES('HCO','p','# coal'); -INSERT INTO "commodity" VALUES('HYD','p','# water'); -INSERT INTO "commodity" VALUES('OIL','p','# crude oil'); -INSERT INTO "commodity" VALUES('URN','p','# uranium'); -INSERT INTO "commodity" VALUES('co2','e','#CO2 emissions'); -INSERT INTO "commodity" VALUES('nox','e','#NOX emissions'); -INSERT INTO "commodity" VALUES('RH','d','# residential heating'); -INSERT INTO "commodity" VALUES('RL','d','# residential lighting'); -INSERT INTO "commodity" VALUES('TX','d','# transportation'); -CREATE TABLE commodity_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "commodity_type" VALUES('w','waste commodity'); -INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); -INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); -INSERT INTO "commodity_type" VALUES('a','annual commodity'); -INSERT INTO "commodity_type" VALUES('s','source commodity'); -INSERT INTO "commodity_type" VALUES('p','physical commodity'); -INSERT INTO "commodity_type" VALUES('e','emissions commodity'); -INSERT INTO "commodity_type" VALUES('d','demand commodity'); -CREATE TABLE construction_input -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage) -); -CREATE TABLE cost_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT NOT NULL - REFERENCES commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -INSERT INTO "cost_emission" VALUES('utopia',2000,'nox',5.0,NULL,NULL); -INSERT INTO "cost_emission" VALUES('utopia',2010,'co2',6.0,NULL,NULL); -CREATE TABLE cost_fixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1960,40.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1970,40.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1980,40.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1990,40.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',1970,70.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',1980,70.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',1990,70.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',2000,70.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',1980,100.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',1990,100.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',2000,100.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',2010,100.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E21',1990,500.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E21',1990,500.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E21',1990,500.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E21',2000,500.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E21',2000,500.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E21',2010,500.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E31',1980,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E31',1990,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E31',1980,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E31',1990,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E31',2000,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',1980,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',1990,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',2000,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',2010,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E51',1980,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E51',1990,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E51',1980,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E51',1990,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E51',2000,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',1980,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',1990,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',2000,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',2010,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1960,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1970,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1980,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1990,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',1970,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',1980,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',1990,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',2000,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',1980,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',1990,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',2000,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',2010,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'RHO',1970,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'RHO',1980,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'RHO',1990,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'RHO',1980,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'RHO',1990,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'RHO',2000,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'RHO',1990,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'RHO',2000,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'RHO',2010,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'RL1',1980,9.46,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'RL1',1990,9.46,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'RL1',2000,9.46,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'RL1',2010,9.46,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXD',1970,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXD',1980,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXD',1990,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXD',1980,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXD',1990,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXD',2000,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXD',2000,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXD',2010,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXE',1990,100.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXE',1990,90.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXE',2000,90.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXE',2000,80.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXE',2010,80.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXG',1970,48.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXG',1980,48.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXG',1990,48.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXG',1980,48.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXG',1990,48.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXG',2000,48.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXG',2000,48.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXG',2010,48.0,'',''); -CREATE TABLE cost_invest -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "cost_invest" VALUES('utopia','E01',1990,2000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E01',2000,1300.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E01',2010,1200.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E21',1990,5000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E21',2000,5000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E21',2010,5000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E31',1990,3000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E31',2000,3000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E31',2010,3000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E51',1990,900.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E51',2000,900.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E51',2010,900.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E70',1990,1000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E70',2000,1000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E70',2010,1000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','RHE',1990,90.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','RHE',2000,90.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','RHE',2010,90.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','RHO',1990,100.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','RHO',2000,100.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','RHO',2010,100.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','SRE',1990,100.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','SRE',2000,100.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','SRE',2010,100.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXD',1990,1044.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXD',2000,1044.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXD',2010,1044.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXE',1990,2000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXE',2000,1750.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXE',2010,1500.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXG',1990,1044.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXG',2000,1044.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXG',2010,1044.0,'',''); -CREATE TABLE cost_variable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPDSL1',1990,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPDSL1',1990,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPDSL1',1990,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPGSL1',1990,15.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPGSL1',1990,15.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPGSL1',1990,15.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPHCO1',1990,2.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPHCO1',1990,2.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPHCO1',1990,2.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPOIL1',1990,8.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPOIL1',1990,8.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPOIL1',1990,8.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPURN1',1990,2.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPURN1',1990,2.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPURN1',1990,2.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1960,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1970,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1980,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1990,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',1970,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',1980,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',1990,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',2000,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',1980,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',1990,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',2000,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',2010,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E21',1990,1.5,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E21',1990,1.5,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E21',1990,1.5,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E21',2000,1.5,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E21',2000,1.5,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E21',2010,1.5,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1960,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1970,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1980,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1990,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',1970,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',1980,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',1990,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',2000,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',1980,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',1990,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',2000,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',2010,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'SRE',1990,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'SRE',1990,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'SRE',2000,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'SRE',1990,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'SRE',2000,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'SRE',2010,10.0,'',''); -CREATE TABLE demand -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - commodity TEXT - REFERENCES commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -INSERT INTO "demand" VALUES('utopia',1990,'RH',25.2,'',''); -INSERT INTO "demand" VALUES('utopia',2000,'RH',37.8,'',''); -INSERT INTO "demand" VALUES('utopia',2010,'RH',5.66999999999999957e+01,'',''); -INSERT INTO "demand" VALUES('utopia',1990,'RL',5.6,'',''); -INSERT INTO "demand" VALUES('utopia',2000,'RL',8.4,'',''); -INSERT INTO "demand" VALUES('utopia',2010,'RL',12.6,'',''); -INSERT INTO "demand" VALUES('utopia',1990,'TX',5.2,'',''); -INSERT INTO "demand" VALUES('utopia',2000,'TX',7.8,'',''); -INSERT INTO "demand" VALUES('utopia',2010,'TX',11.69,'',''); -CREATE TABLE demand_specific_distribution -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - demand_name TEXT - REFERENCES commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -INSERT INTO "demand_specific_distribution" VALUES('utopia','inter','night','RH',0.06,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia','winter','day','RH',0.5467,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia','winter','night','RH',2.73299999999999931e-01,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia','inter','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia','inter','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia','summer','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia','summer','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia','winter','day','RL',0.5,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia','winter','night','RL',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia','inter','day','RH',0.12,NULL); -CREATE TABLE efficiency -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -INSERT INTO "efficiency" VALUES('utopia','ethos','IMPDSL1',1990,'DSL',1.0,''); -INSERT INTO "efficiency" VALUES('utopia','ethos','IMPGSL1',1990,'GSL',1.0,''); -INSERT INTO "efficiency" VALUES('utopia','ethos','IMPHCO1',1990,'HCO',1.0,''); -INSERT INTO "efficiency" VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,''); -INSERT INTO "efficiency" VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,''); -INSERT INTO "efficiency" VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,''); -INSERT INTO "efficiency" VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,''); -INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1960,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1970,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1980,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1990,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HCO','E01',2000,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HCO','E01',2010,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','FEQ','E21',1990,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','FEQ','E21',2000,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','FEQ','E21',2010,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','URN','E21',1990,'ELC',0.4,'# 1/2.5'); -INSERT INTO "efficiency" VALUES('utopia','URN','E21',2000,'ELC',0.4,'# 1/2.5'); -INSERT INTO "efficiency" VALUES('utopia','URN','E21',2010,'ELC',0.4,'# 1/2.5'); -INSERT INTO "efficiency" VALUES('utopia','HYD','E31',1980,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HYD','E31',1990,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HYD','E31',2000,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HYD','E31',2010,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1960,'ELC',0.294,'# 1/3.4'); -INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1970,'ELC',0.294,'# 1/3.4'); -INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1980,'ELC',0.294,'# 1/3.4'); -INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1990,'ELC',0.294,'# 1/3.4'); -INSERT INTO "efficiency" VALUES('utopia','DSL','E70',2000,'ELC',0.294,'# 1/3.4'); -INSERT INTO "efficiency" VALUES('utopia','DSL','E70',2010,'ELC',0.294,'# 1/3.4'); -INSERT INTO "efficiency" VALUES('utopia','ELC','E51',1980,'ELC',0.72,'# 1/1.3889'); -INSERT INTO "efficiency" VALUES('utopia','ELC','E51',1990,'ELC',0.72,'# 1/1.3889'); -INSERT INTO "efficiency" VALUES('utopia','ELC','E51',2000,'ELC',0.72,'# 1/1.3889'); -INSERT INTO "efficiency" VALUES('utopia','ELC','E51',2010,'ELC',0.72,'# 1/1.3889'); -INSERT INTO "efficiency" VALUES('utopia','ELC','RHE',1990,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','RHE',2000,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','RHE',2010,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',1970,'RH',0.7,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',1980,'RH',0.7,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',1990,'RH',0.7,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',2000,'RH',0.7,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',2010,'RH',0.7,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',1980,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',1990,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',2000,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',2010,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',1990,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2000,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',1970,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',1980,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',1990,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',2000,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',2010,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','TXE',1990,'TX',0.827,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','TXE',2000,'TX',0.827,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','TXE',2010,'TX',0.827,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',1970,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',1980,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',1990,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',2000,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',2010,'TX',0.231,'# direct translation from DMD_EFF'); -CREATE TABLE efficiency_variable -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE emission_activity -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.075,'',''); -INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.075,'',''); -INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',8.89999999999999819e-02,'',''); -INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.075,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1970,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1980,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1990,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',2000,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',2010,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1970,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1980,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1990,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',2000,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',2010,'TX',1.0,'',''); -CREATE TABLE emission_embodied -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE emission_end_of_life -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -CREATE TABLE existing_capacity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "existing_capacity" VALUES('utopia','E01',1960,0.175,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','E01',1970,0.175,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','E01',1980,0.15,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','E31',1980,0.1,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','E51',1980,0.5,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','E70',1960,0.05,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','E70',1970,0.05,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','E70',1980,0.2,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','RHO',1970,12.5,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','RHO',1980,12.5,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','RL1',1980,5.6,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','TXD',1970,0.4,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','TXD',1980,0.2,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','TXG',1970,3.1,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','TXG',1980,1.5,'',''); -CREATE TABLE lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "lifetime_process" VALUES('utopia','RL1',1980,20.0,'#forexistingcap'); -INSERT INTO "lifetime_process" VALUES('utopia','TXD',1970,30.0,'#forexistingcap'); -INSERT INTO "lifetime_process" VALUES('utopia','TXD',1980,30.0,'#forexistingcap'); -INSERT INTO "lifetime_process" VALUES('utopia','TXG',1970,30.0,'#forexistingcap'); -INSERT INTO "lifetime_process" VALUES('utopia','TXG',1980,30.0,'#forexistingcap'); -CREATE TABLE lifetime_survival_curve -( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE lifetime_tech -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "lifetime_tech" VALUES('utopia','E01',40.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','E21',40.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','E31',100.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','E51',100.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','E70',40.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','RHE',30.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','RHO',30.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','RL1',10.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','SRE',50.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','TXD',15.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','TXE',15.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','TXG',15.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','IMPDSL1',1000.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','IMPGSL1',1000.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','IMPHCO1',1000.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','IMPOIL1',1000.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','IMPURN1',1000.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','IMPHYD',1000.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','IMPFEQ',1000.0,''); -CREATE TABLE limit_activity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -INSERT INTO "limit_capacity" VALUES('utopia',1990,'E31','ge',0.13,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',2000,'E31','ge',0.13,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',2010,'E31','ge',0.13,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',1990,'SRE','ge',0.1,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',1990,'E31','le',0.13,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',2000,'E31','le',0.17,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',2010,'E31','le',2.1000000000000002e-01,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',1990,'RHE','le',0.0,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',1990,'TXD','le',0.6,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',2000,'TXD','le',1.76,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',2010,'TXD','le',4.76,'',''); -CREATE TABLE limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_degrowth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE limit_growth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - season TEXT - REFERENCES time_season (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, season, tech, operator) -); -CREATE TABLE limit_storage_level_fraction -( - region TEXT, - season TEXT, - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - fraction REAL, - notes TEXT, - CHECK (fraction >= 0 AND fraction <= 1), - PRIMARY KEY(region, season, tod, tech, operator) -); -CREATE TABLE limit_tech_input_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_input_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_output_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -INSERT INTO "limit_tech_output_split" VALUES('utopia',1990,'SRE','DSL','ge',0.7,''); -INSERT INTO "limit_tech_output_split" VALUES('utopia',2000,'SRE','DSL','ge',0.7,''); -INSERT INTO "limit_tech_output_split" VALUES('utopia',2010,'SRE','DSL','ge',0.7,''); -INSERT INTO "limit_tech_output_split" VALUES('utopia',1990,'SRE','GSL','ge',0.3,''); -INSERT INTO "limit_tech_output_split" VALUES('utopia',2000,'SRE','GSL','ge',0.3,''); -INSERT INTO "limit_tech_output_split" VALUES('utopia',2010,'SRE','GSL','ge',0.3,''); -CREATE TABLE limit_tech_output_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE linked_tech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES technology (tech), - emis_comm TEXT - REFERENCES commodity (name), - driven_tech TEXT - REFERENCES technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -CREATE TABLE loan_lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE loan_rate -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO "metadata" VALUES('myopic_base_year',2000,'Base Year for Myopic Analysis'); -INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); -INSERT INTO "metadata" VALUES('DB_MINOR',0,''); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,''); -CREATE TABLE myopic_efficiency -( - base_year integer, - region text, - input_comm text, - tech text, - vintage integer, - output_comm text, - efficiency real, - lifetime integer, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (region, input_comm, tech, vintage, output_comm) -); -CREATE TABLE operator -( - operator TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "operator" VALUES('e','equal to'); -INSERT INTO "operator" VALUES('le','less than or equal to'); -INSERT INTO "operator" VALUES('ge','greater than or equal to'); -CREATE TABLE output_built_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES sector_label (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) -); -CREATE TABLE output_curtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE output_emission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE output_flow_in -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out_summary -( - scenario TEXT NOT NULL, - region TEXT NOT NULL, - sector TEXT, - period INTEGER, - input_comm TEXT NOT NULL, - tech TEXT NOT NULL, - vintage INTEGER, - output_comm TEXT NOT NULL, - flow REAL NOT NULL, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_net_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_objective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE output_retired_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_storage_level -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT, - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE planning_reserve_margin -( - region TEXT - PRIMARY KEY - REFERENCES region (region), - margin REAL, - notes TEXT -); -CREATE TABLE ramp_down_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE ramp_up_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -INSERT INTO "region" VALUES('utopia',NULL); -CREATE TABLE reserve_capacity_derate -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE rps_requirement -( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL - REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES tech_group (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE sector_label -( - sector TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "sector_label" VALUES('supply',NULL); -INSERT INTO "sector_label" VALUES('electric',NULL); -INSERT INTO "sector_label" VALUES('transport',NULL); -INSERT INTO "sector_label" VALUES('commercial',NULL); -INSERT INTO "sector_label" VALUES('residential',NULL); -INSERT INTO "sector_label" VALUES('industrial',NULL); -CREATE TABLE storage_duration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE tech_group -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE tech_group_member -( - group_name TEXT - REFERENCES tech_group (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technology_type (label) -); -INSERT INTO "technology" VALUES('IMPDSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported diesel'); -INSERT INTO "technology" VALUES('IMPGSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported gasoline'); -INSERT INTO "technology" VALUES('IMPHCO1','p','supply','coal','',1,0,0,0,0,0,0,0,' imported coal'); -INSERT INTO "technology" VALUES('IMPOIL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO "technology" VALUES('IMPURN1','p','supply','nuclear','',1,0,0,0,0,0,0,0,' imported uranium'); -INSERT INTO "technology" VALUES('IMPFEQ','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported fossil equivalent'); -INSERT INTO "technology" VALUES('IMPHYD','p','supply','','',1,0,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); -INSERT INTO "technology" VALUES('E01','pb','electric','coal','',0,0,0,1,1,0,0,0,' coal power plant'); -INSERT INTO "technology" VALUES('E21','pb','electric','nuclear','',0,0,0,1,1,0,0,0,' nuclear power plant'); -INSERT INTO "technology" VALUES('E31','pb','electric','hydro','',0,0,0,1,1,0,0,0,' hydro power'); -INSERT INTO "technology" VALUES('E51','ps','electric','electric','',0,0,0,1,0,0,0,0,' electric storage'); -INSERT INTO "technology" VALUES('E70','p','electric','petroleum','',0,0,0,1,1,0,0,0,' diesel power plant'); -INSERT INTO "technology" VALUES('RHE','p','residential','electric','',0,0,0,1,1,0,0,0,' electric residential heating'); -INSERT INTO "technology" VALUES('RHO','p','residential','petroleum','',0,0,0,1,1,0,0,0,' diesel residential heating'); -INSERT INTO "technology" VALUES('RL1','p','residential','electric','',0,0,0,1,1,0,0,0,' residential lighting'); -INSERT INTO "technology" VALUES('SRE','p','supply','petroleum','',0,0,0,1,1,0,0,0,' crude oil processor'); -INSERT INTO "technology" VALUES('TXD','p','transport','petroleum','',0,0,0,1,1,0,0,0,' diesel powered vehicles'); -INSERT INTO "technology" VALUES('TXE','p','transport','electric','',0,0,0,1,1,0,0,0,' electric powered vehicles'); -INSERT INTO "technology" VALUES('TXG','p','transport','petroleum','',0,0,0,1,1,0,0,0,' gasoline powered vehicles'); -CREATE TABLE technology_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "technology_type" VALUES('p','production technology'); -INSERT INTO "technology_type" VALUES('pb','baseload production technology'); -INSERT INTO "technology_type" VALUES('ps','storage production technology'); -CREATE TABLE time_of_day -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY, - hours REAL NOT NULL DEFAULT 1, - notes TEXT, - CHECK (hours > 0) -); -INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(1,'day',16); -INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(2,'night',8); -CREATE TABLE time_period -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES time_period_type (label) -); -INSERT INTO "time_period" VALUES(1,1960,'e'); -INSERT INTO "time_period" VALUES(2,1970,'e'); -INSERT INTO "time_period" VALUES(3,1980,'e'); -INSERT INTO "time_period" VALUES(4,1990,'f'); -INSERT INTO "time_period" VALUES(5,2000,'f'); -INSERT INTO "time_period" VALUES(6,2010,'f'); -INSERT INTO "time_period" VALUES(7,2020,'f'); -CREATE TABLE time_period_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "time_period_type" VALUES('e','existing vintages'); -INSERT INTO "time_period_type" VALUES('f','future'); -CREATE TABLE time_season -( - sequence INTEGER UNIQUE, - season TEXT, - segment_fraction REAL NOT NULL, - notes TEXT, - PRIMARY KEY (season), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); -INSERT INTO "time_season" VALUES(0,'summer',0.25,NULL); -INSERT INTO "time_season" VALUES(1,'winter',0.5,NULL); -INSERT INTO "time_season" VALUES(2,'inter',0.25,NULL); - -CREATE TABLE time_season_sequential -( - sequence INTEGER UNIQUE, - seas_seq TEXT, - season TEXT REFERENCES time_season(season), - segment_fraction REAL NOT NULL, - notes TEXT, - PRIMARY KEY (seas_seq), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); - -CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); -COMMIT; diff --git a/data_files/example_dbs/seasonal_storage.sql b/data_files/example_dbs/seasonal_storage.sql deleted file mode 100644 index 68da03a75..000000000 --- a/data_files/example_dbs/seasonal_storage.sql +++ /dev/null @@ -1,1080 +0,0 @@ -BEGIN TRANSACTION; -CREATE TABLE capacity_credit -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -CREATE TABLE capacity_factor_process -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE capacity_factor_tech -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -INSERT INTO "capacity_factor_tech" VALUES('region','charge','a','generator',1.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('region','charge','b','generator',1.0,NULL); -INSERT INTO "capacity_factor_tech" VALUES('region','charge','c','generator',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('region','charge','d','generator',0.2,NULL); -INSERT INTO "capacity_factor_tech" VALUES('region','discharge','a','generator',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('region','discharge','b','generator',0.1,NULL); -INSERT INTO "capacity_factor_tech" VALUES('region','discharge','c','generator',0.01,NULL); -INSERT INTO "capacity_factor_tech" VALUES('region','discharge','d','generator',0.01,NULL); -CREATE TABLE capacity_to_activity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "capacity_to_activity" VALUES('region','generator',8760.0,'MWh/MWy'); -INSERT INTO "capacity_to_activity" VALUES('region','dly_stor',8760.0,'MWh/MWy'); -INSERT INTO "capacity_to_activity" VALUES('region','seas_stor',8760.0,'MWh/MWy'); -INSERT INTO "capacity_to_activity" VALUES('region','demand',8760.0,'MWh/MWy'); -CREATE TABLE commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES commodity_type (label), - description TEXT -); -INSERT INTO "commodity" VALUES('ethos','s',NULL); -INSERT INTO "commodity" VALUES('electricity','p',NULL); -INSERT INTO "commodity" VALUES('demand','d',NULL); -CREATE TABLE commodity_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "commodity_type" VALUES('p','physical commodity'); -INSERT INTO "commodity_type" VALUES('a','annual commodity'); -INSERT INTO "commodity_type" VALUES('e','emissions commodity'); -INSERT INTO "commodity_type" VALUES('d','demand commodity'); -INSERT INTO "commodity_type" VALUES('s','source commodity'); -INSERT INTO "commodity_type" VALUES('w','waste commodity'); -INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); -INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); -CREATE TABLE construction_input -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage) -); -CREATE TABLE cost_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT NOT NULL - REFERENCES commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE cost_fixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE cost_invest -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "cost_invest" VALUES('region','generator',2000,1000.0,'',NULL); -INSERT INTO "cost_invest" VALUES('region','dly_stor',2000,1.0,'',NULL); -INSERT INTO "cost_invest" VALUES('region','seas_stor',2000,100.0,'',NULL); -INSERT INTO "cost_invest" VALUES('region','demand',2000,1.0,'',NULL); -CREATE TABLE cost_variable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_variable" VALUES('region',2000,'generator',2000,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2000,'demand',2000,1.0,NULL,NULL); -CREATE TABLE demand -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - commodity TEXT - REFERENCES commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -INSERT INTO "demand" VALUES('region',2000,'demand',8760.0,'MWh',NULL); -CREATE TABLE demand_specific_distribution -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - demand_name TEXT - REFERENCES commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -INSERT INTO "demand_specific_distribution" VALUES('region','charge','a','demand',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('region','charge','b','demand',0.05,NULL); -INSERT INTO "demand_specific_distribution" VALUES('region','charge','c','demand',0.05,NULL); -INSERT INTO "demand_specific_distribution" VALUES('region','charge','d','demand',0.1,NULL); -INSERT INTO "demand_specific_distribution" VALUES('region','discharge','a','demand',0.0,NULL); -INSERT INTO "demand_specific_distribution" VALUES('region','discharge','b','demand',0.2,NULL); -INSERT INTO "demand_specific_distribution" VALUES('region','discharge','c','demand',0.2,NULL); -INSERT INTO "demand_specific_distribution" VALUES('region','discharge','d','demand',0.4,NULL); -CREATE TABLE efficiency -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -INSERT INTO "efficiency" VALUES('region','ethos','generator',2000,'electricity',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','electricity','dly_stor',2000,'electricity',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','electricity','seas_stor',2000,'electricity',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','electricity','demand',2000,'demand',1.0,NULL); -CREATE TABLE efficiency_variable -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE emission_activity -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -CREATE TABLE emission_embodied -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE emission_end_of_life -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -CREATE TABLE existing_capacity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_survival_curve -( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE lifetime_tech -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE limit_activity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_degrowth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE limit_growth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - season TEXT - REFERENCES time_season (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, season, tech, operator) -); -CREATE TABLE limit_storage_level_fraction -( - region TEXT, - season TEXT, - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - fraction REAL, - notes TEXT, - CHECK (fraction >= 0 AND fraction <= 1), - PRIMARY KEY(region, season, tod, tech, operator) -); -INSERT INTO "limit_storage_level_fraction" VALUES('region','winter','b','seas_stor','e',0.5,NULL); -INSERT INTO "limit_storage_level_fraction" VALUES('region','charge','b','dly_stor','e',0.5,NULL); -CREATE TABLE limit_tech_input_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_input_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_output_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE limit_tech_output_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE linked_tech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES technology (tech), - emis_comm TEXT - REFERENCES commodity (name), - driven_tech TEXT - REFERENCES technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -CREATE TABLE loan_lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE loan_rate -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); -INSERT INTO "metadata" VALUES('DB_MINOR',0,''); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -CREATE TABLE myopic_efficiency -( - base_year integer, - region text, - input_comm text, - tech text, - vintage integer, - output_comm text, - efficiency real, - lifetime integer, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (region, input_comm, tech, vintage, output_comm) -); -CREATE TABLE operator -( - operator TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "operator" VALUES('e','equal to'); -INSERT INTO "operator" VALUES('le','less than or equal to'); -INSERT INTO "operator" VALUES('ge','greater than or equal to'); -CREATE TABLE output_built_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES sector_label (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) -); -CREATE TABLE output_curtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE output_emission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE output_flow_in -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out_summary -( - scenario TEXT NOT NULL, - region TEXT NOT NULL, - sector TEXT, - period INTEGER, - input_comm TEXT NOT NULL, - tech TEXT NOT NULL, - vintage INTEGER, - output_comm TEXT NOT NULL, - flow REAL NOT NULL, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_net_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_objective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE output_retired_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_storage_level -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT, - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE planning_reserve_margin -( - region TEXT - PRIMARY KEY - REFERENCES region (region), - margin REAL, - notes TEXT -); -CREATE TABLE ramp_down_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE ramp_up_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -INSERT INTO "region" VALUES('region',NULL); -CREATE TABLE reserve_capacity_derate -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE rps_requirement -( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL - REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES tech_group (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE sector_label -( - sector TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "sector_label" VALUES('electricity',NULL); -CREATE TABLE storage_duration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "storage_duration" VALUES('region','dly_stor',4.0,NULL); -INSERT INTO "storage_duration" VALUES('region','seas_stor',8760.0,NULL); -CREATE TABLE tech_group -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE tech_group_member -( - group_name TEXT - REFERENCES tech_group (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technology_type (label) -); -INSERT INTO "technology" VALUES('generator','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO "technology" VALUES('dly_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO "technology" VALUES('seas_stor','ps','electricity',NULL,NULL,0,0,0,0,0,0,0,1,NULL); -INSERT INTO "technology" VALUES('demand','p','electricity',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -CREATE TABLE technology_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "technology_type" VALUES('p','production technology'); -INSERT INTO "technology_type" VALUES('pb','baseload production technology'); -INSERT INTO "technology_type" VALUES('ps','storage production technology'); -CREATE TABLE time_of_day -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY, - hours REAL NOT NULL DEFAULT 1, - notes TEXT, - CHECK (hours > 0) -); -INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(0,'a',6); -INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(1,'b',6); -INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(2,'c',6); -INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(3,'d',6); -CREATE TABLE time_period -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES time_period_type (label) -); -INSERT INTO "time_period" VALUES(0,2000,'f'); -INSERT INTO "time_period" VALUES(1,2005,'f'); -CREATE TABLE time_period_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "time_period_type" VALUES('e','existing vintages'); -INSERT INTO "time_period_type" VALUES('f','future'); -CREATE TABLE time_season -( - sequence INTEGER UNIQUE, - season TEXT, - segment_fraction REAL NOT NULL, - notes TEXT, - PRIMARY KEY (season), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); -INSERT INTO "time_season" VALUES(0,'charge',0.5,NULL); -INSERT INTO "time_season" VALUES(1,'discharge',0.5,NULL); - -CREATE TABLE time_season_sequential -( - sequence INTEGER UNIQUE, - seas_seq TEXT, - season TEXT REFERENCES time_season(season), - segment_fraction REAL NOT NULL, - notes TEXT, - PRIMARY KEY (seas_seq), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); -INSERT INTO "time_season_sequential" VALUES(1,'summer','charge',0.417808,NULL); -INSERT INTO "time_season_sequential" VALUES(2,'sept_w1','discharge',0.019178,NULL); -INSERT INTO "time_season_sequential" VALUES(3,'sept_w2','charge',0.019178,NULL); -INSERT INTO "time_season_sequential" VALUES(4,'sept_w3','discharge',0.019178,NULL); -INSERT INTO "time_season_sequential" VALUES(5,'sept_w4','charge',0.019178,NULL); -INSERT INTO "time_season_sequential" VALUES(6,'sept_29th','discharge',0.002740,NULL); -INSERT INTO "time_season_sequential" VALUES(7,'sept_30th','charge',0.002740,NULL); -INSERT INTO "time_season_sequential" VALUES(8,'winter','discharge',0.417808,NULL); -INSERT INTO "time_season_sequential" VALUES(9,'apr_w1','charge',0.019178,NULL); -INSERT INTO "time_season_sequential" VALUES(10,'apr_w2','discharge',0.019178,NULL); -INSERT INTO "time_season_sequential" VALUES(11,'apr_w3','charge',0.019178,NULL); -INSERT INTO "time_season_sequential" VALUES(12,'apr_w4','discharge',0.019178,NULL); -INSERT INTO "time_season_sequential" VALUES(13,'apr_29th','charge',0.002740,NULL); -INSERT INTO "time_season_sequential" VALUES(14,'apr_30th','discharge',0.002740,NULL); - -CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); -COMMIT; diff --git a/data_files/example_dbs/stepped_demand.sql b/data_files/example_dbs/stepped_demand.sql deleted file mode 100644 index bfd228b26..000000000 --- a/data_files/example_dbs/stepped_demand.sql +++ /dev/null @@ -1,1215 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE MetaData -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO MetaData VALUES('DB_MAJOR',3,'DB major version number'); -INSERT INTO MetaData VALUES('DB_MINOR',1,'DB minor version number'); -CREATE TABLE MetaDataReal -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO MetaDataReal VALUES('default_loan_rate',0.05000000000000000277,'Default Loan Rate if not specified in loan_rate table'); -INSERT INTO MetaDataReal VALUES('global_discount_rate',0.05000000000000000277,''); -CREATE TABLE OutputDualVariable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE SeasonLabel -( - season TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SeasonLabel VALUES('inter',NULL); -INSERT INTO SeasonLabel VALUES('summer',NULL); -INSERT INTO SeasonLabel VALUES('winter',NULL); -CREATE TABLE SectorLabel -( - sector TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO SectorLabel VALUES('supply',NULL); -INSERT INTO SectorLabel VALUES('electric',NULL); -INSERT INTO SectorLabel VALUES('transport',NULL); -INSERT INTO SectorLabel VALUES('commercial',NULL); -INSERT INTO SectorLabel VALUES('residential',NULL); -INSERT INTO SectorLabel VALUES('industrial',NULL); -CREATE TABLE capacity_credit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -CREATE TABLE capacity_factor_process -( - region TEXT, - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE capacity_factor_tech -( - region TEXT, - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -INSERT INTO "capacity_factor_tech" VALUES('electricville','inter','day','EF',1.0,''); -INSERT INTO "capacity_factor_tech" VALUES('electricville','winter','day','EF',1.0,''); -INSERT INTO "capacity_factor_tech" VALUES('electricville','summer','day','EF',1.0,''); -INSERT INTO "capacity_factor_tech" VALUES('electricville','inter','day','EH',1.0,''); -INSERT INTO "capacity_factor_tech" VALUES('electricville','winter','day','EH',1.0,''); -INSERT INTO "capacity_factor_tech" VALUES('electricville','summer','day','EH',1.0,''); -CREATE TABLE CapacityToActivity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO CapacityToActivity VALUES('electricville','bulbs',1.0,''); -CREATE TABLE Commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES CommodityType (label), - description TEXT -); -INSERT INTO Commodity VALUES('ELC','p','# electricity'); -INSERT INTO Commodity VALUES('HYD','p','# water'); -INSERT INTO Commodity VALUES('co2','e','#CO2 emissions'); -INSERT INTO Commodity VALUES('RL','d','# residential lighting'); -INSERT INTO Commodity VALUES('earth','s','# the source of stuff'); -CREATE TABLE CommodityType -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO CommodityType VALUES('w','waste commodity'); -INSERT INTO CommodityType VALUES('wa','waste annual commodity'); -INSERT INTO CommodityType VALUES('wp','waste physical commodity'); -INSERT INTO CommodityType VALUES('a','annual commodity'); -INSERT INTO CommodityType VALUES('s','source commodity'); -INSERT INTO CommodityType VALUES('p','physical commodity'); -INSERT INTO CommodityType VALUES('e','emissions commodity'); -INSERT INTO CommodityType VALUES('d','demand commodity'); -CREATE TABLE construction_input -( - region TEXT, - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage) -); -CREATE TABLE cost_emission -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT NOT NULL - REFERENCES Commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE cost_fixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO cost_fixed VALUES('electricville',2000,'EH',1995,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2005,'EH',1995,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2010,'EH',1995,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2015,'EH',1995,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2020,'EH',1995,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2025,'EH',1995,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2035,'EH',1995,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2040,'EH',1995,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2045,'EH',1995,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2050,'EH',1995,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2010,'EF',2010,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2015,'EF',2010,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2020,'EF',2010,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2025,'EF',2010,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2030,'EF',2010,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2035,'EF',2010,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2040,'EF',2010,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2045,'EF',2010,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2050,'EF',2010,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2000,'EH',2000,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2005,'EH',2000,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2010,'EH',2000,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2015,'EH',2000,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2020,'EH',2000,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2025,'EH',2000,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2030,'EH',2000,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2035,'EH',2000,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2040,'EH',2000,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2045,'EH',2000,2.0,'',''); -INSERT INTO cost_fixed VALUES('electricville',2050,'EH',2000,2.0,'',''); -CREATE TABLE cost_invest -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO cost_invest VALUES('electricville','EF',2010,200.0,'',''); -INSERT INTO cost_invest VALUES('electricville','EH',2000,100.0,'',''); -CREATE TABLE cost_variable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO cost_variable VALUES('electricville',2010,'EF',2010,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2015,'EF',2010,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2020,'EF',2010,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2025,'EF',2010,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2030,'EF',2010,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2035,'EF',2010,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2040,'EF',2010,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2045,'EF',2010,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2050,'EF',2010,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2000,'EH',1995,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2005,'EH',1995,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2010,'EH',1995,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2015,'EH',1995,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2020,'EH',1995,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2025,'EH',1995,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2030,'EH',1995,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2035,'EH',1995,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2040,'EH',1995,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2045,'EH',1995,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2050,'EH',1995,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2000,'EH',2000,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2005,'EH',2000,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2010,'EH',2000,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2015,'EH',2000,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2020,'EH',2000,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2025,'EH',2000,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2030,'EH',2000,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2035,'EH',2000,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2040,'EH',2000,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2045,'EH',2000,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2050,'EH',2000,2.0,'',''); -INSERT INTO cost_variable VALUES('electricville',2000,'well',2000,1.0,NULL,NULL); -INSERT INTO cost_variable VALUES('electricville',2010,'well',2000,1.0,NULL,NULL); -CREATE TABLE Demand -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - commodity TEXT - REFERENCES Commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -INSERT INTO Demand VALUES('electricville',2000,'RL',2.0,'',''); -INSERT INTO Demand VALUES('electricville',2005,'RL',2.0,'',''); -INSERT INTO Demand VALUES('electricville',2010,'RL',2.0,'',''); -INSERT INTO Demand VALUES('electricville',2015,'RL',2.0,'',''); -INSERT INTO Demand VALUES('electricville',2020,'RL',10.0,'',''); -INSERT INTO Demand VALUES('electricville',2025,'RL',10.0,'',''); -INSERT INTO Demand VALUES('electricville',2030,'RL',10.0,'',''); -INSERT INTO Demand VALUES('electricville',2035,'RL',50.0,'',''); -INSERT INTO Demand VALUES('electricville',2040,'RL',10.0,NULL,NULL); -INSERT INTO Demand VALUES('electricville',2045,'RL',10.0,NULL,NULL); -INSERT INTO Demand VALUES('electricville',2050,'RL',2.0,NULL,NULL); -CREATE TABLE DemandSpecificDistribution -( - region TEXT, - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - demand_name TEXT - REFERENCES Commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -INSERT INTO DemandSpecificDistribution VALUES('electricville','inter','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville','summer','day','RL',0.3332999999999999852,''); -INSERT INTO DemandSpecificDistribution VALUES('electricville','winter','day','RL',0.3332999999999999852,''); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -CREATE TABLE efficiency -( - region TEXT, - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -INSERT INTO efficiency VALUES('electricville','HYD','EH',1995,'ELC',1.0,'est'); -INSERT INTO efficiency VALUES('electricville','HYD','EH',2000,'ELC',1.0,'est'); -INSERT INTO efficiency VALUES('electricville','HYD','EF',2010,'ELC',10.0,'est'); -INSERT INTO efficiency VALUES('electricville','ELC','bulbs',2000,'RL',1.0,NULL); -INSERT INTO efficiency VALUES('electricville','earth','well',2000,'HYD',1.0,'water source'); -INSERT INTO efficiency VALUES('electricville','HYD','EH',2020,'ELC',1.0,NULL); -CREATE TABLE efficiency_variable -( - region TEXT, - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE emission_activity -( - region TEXT, - emis_comm TEXT - REFERENCES Commodity (name), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -INSERT INTO emission_activity VALUES('electricville','co2','HYD','EH',1995,'ELC',0.05000000000000000277,'',''); -INSERT INTO emission_activity VALUES('electricville','co2','HYD','EF',2010,'ELC',0.0100000000000000002,'',''); -INSERT INTO emission_activity VALUES('electricville','co2','HYD','EH',2000,'ELC',0.02000000000000000041,NULL,NULL); -CREATE TABLE emission_embodied -( - region TEXT, - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE emission_end_of_life -( - region TEXT, - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE existing_capacity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO existing_capacity VALUES('electricville','EH',1995,0.5,'',''); -CREATE TABLE TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -INSERT INTO TechGroup VALUES('RPS_global',''); -INSERT INTO TechGroup VALUES('RPS_common',''); -CREATE TABLE loan_lifetime_process -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO loan_lifetime_process VALUES('electricville','EF',2010,50.0,''); -CREATE TABLE loan_rate -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_process -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO lifetime_process VALUES('electricville','EH',1995,80.0,'#forexistingcap'); -CREATE TABLE lifetime_tech -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO lifetime_tech VALUES('electricville','EH',100.0,''); -INSERT INTO lifetime_tech VALUES('electricville','EF',100.0,''); -INSERT INTO lifetime_tech VALUES('electricville','bulbs',100.0,'super LED!'); -INSERT INTO lifetime_tech VALUES('electricville','well',100.0,NULL); -CREATE TABLE Operator -( - operator TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO Operator VALUES('e','equal to'); -INSERT INTO Operator VALUES('le','less than or equal to'); -INSERT INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE limit_growth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE LimitStorageLevelFraction -( - region TEXT, - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, season, tod, tech, operator) -); -CREATE TABLE limit_activity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -INSERT INTO limit_capacity VALUES('electricville',2000,'EH','ge',0.2000000000000000111,'',''); -INSERT INTO limit_capacity VALUES('electricville',2005,'EH','ge',0.2000000000000000111,'',''); -INSERT INTO limit_capacity VALUES('electricville',2010,'EH','ge',0.2000000000000000111,'',''); -INSERT INTO limit_capacity VALUES('electricville',2015,'EH','ge',0.2000000000000000111,'',''); -INSERT INTO limit_capacity VALUES('electricville',2000,'EH','le',5.0,'',''); -INSERT INTO limit_capacity VALUES('electricville',2005,'EH','le',5.0,'',''); -INSERT INTO limit_capacity VALUES('electricville',2010,'EH','le',5.0,'',''); -INSERT INTO limit_capacity VALUES('electricville',2015,'EH','le',5.0,'',''); -INSERT INTO limit_capacity VALUES('electricville',2020,'EH','le',5.0,'',''); -INSERT INTO limit_capacity VALUES('electricville',2025,'EH','le',5.0,'',''); -INSERT INTO limit_capacity VALUES('electricville',2030,'EH','le',5.0,'',''); -CREATE TABLE limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_new_capacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES Region (region), - season TEXT - REFERENCES SeasonLabel (season), - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, season, tech, operator) -); -CREATE TABLE limit_tech_input_split -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_input_split_annual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_output_split -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE limit_tech_output_split_annual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE LinkedTech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES Technology (tech), - emis_comm TEXT - REFERENCES Commodity (name), - driven_tech TEXT - REFERENCES Technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -CREATE TABLE OutputCurtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE OutputNetCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE OutputBuiltCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE OutputRetiredCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE OutputFlowIn -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE OutputFlowOut -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE OutputStorageLevel -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE planning_reserve_margin -( - region TEXT - PRIMARY KEY - REFERENCES Region (region), - margin REAL, - notes TEXT -); -CREATE TABLE ramp_down_hourly -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE ramp_up_hourly -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE Region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -INSERT INTO Region VALUES('electricville',NULL); -CREATE TABLE reserve_capacity_derate -( - region TEXT, - season TEXT - REFERENCES SeasonLabel (season), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE TimeSegmentFraction -( - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) -); -INSERT INTO TimeSegmentFraction VALUES(2000,'inter','day',0.3332999999999999852,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2000,'summer','day',0.3332999999999999852,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2000,'winter','day',0.3332999999999999852,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2005,'inter','day',0.3332999999999999852,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2005,'summer','day',0.3332999999999999852,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2005,'winter','day',0.3332999999999999852,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'inter','day',0.3332999999999999852,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'summer','day',0.3332999999999999852,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2010,'winter','day',0.3332999999999999852,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2015,'inter','day',0.3332999999999999852,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2015,'summer','day',0.3332999999999999852,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2015,'winter','day',0.3332999999999999852,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2020,'inter','day',0.3332999999999999852,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2020,'summer','day',0.3332999999999999852,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2020,'winter','day',0.3332999999999999852,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2025,'inter','day',0.3332999999999999852,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2025,'summer','day',0.3332999999999999852,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2025,'winter','day',0.3332999999999999852,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2030,'inter','day',0.3332999999999999852,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2030,'summer','day',0.3332999999999999852,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2030,'winter','day',0.3332999999999999852,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2035,'inter','day',0.3332999999999999852,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2035,'summer','day',0.3332999999999999852,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2035,'winter','day',0.3332999999999999852,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2040,'inter','day',0.3332999999999999852,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2040,'summer','day',0.3332999999999999852,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2040,'winter','day',0.3332999999999999852,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2045,'inter','day',0.3332999999999999852,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2045,'summer','day',0.3332999999999999852,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2045,'winter','day',0.3332999999999999852,'# W-D'); -INSERT INTO TimeSegmentFraction VALUES(2050,'inter','day',0.3332999999999999852,'# I-D'); -INSERT INTO TimeSegmentFraction VALUES(2050,'summer','day',0.3332999999999999852,'# S-D'); -INSERT INTO TimeSegmentFraction VALUES(2050,'winter','day',0.3332999999999999852,'# W-D'); -CREATE TABLE storage_duration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE lifetime_survival_curve -( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE TechnologyType -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO TechnologyType VALUES('p','production technology'); -INSERT INTO TechnologyType VALUES('pb','baseload production technology'); -INSERT INTO TechnologyType VALUES('ps','storage production technology'); -CREATE TABLE TimeOfDay -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY -); -INSERT INTO TimeOfDay VALUES(1,'day'); -CREATE TABLE TimePeriod -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES TimePeriodType (label) -); -INSERT INTO TimePeriod VALUES(1,1995,'e'); -INSERT INTO TimePeriod VALUES(2,2000,'f'); -INSERT INTO TimePeriod VALUES(3,2005,'f'); -INSERT INTO TimePeriod VALUES(4,2010,'f'); -INSERT INTO TimePeriod VALUES(5,2015,'f'); -INSERT INTO TimePeriod VALUES(6,2020,'f'); -INSERT INTO TimePeriod VALUES(7,2025,'f'); -INSERT INTO TimePeriod VALUES(8,2030,'f'); -INSERT INTO TimePeriod VALUES(9,2035,'f'); -INSERT INTO TimePeriod VALUES(10,2040,'f'); -INSERT INTO TimePeriod VALUES(11,2045,'f'); -INSERT INTO TimePeriod VALUES(12,2050,'f'); -INSERT INTO TimePeriod VALUES(13,2055,'f'); -CREATE TABLE TimeSeason -( - period INTEGER - REFERENCES TimePeriod (period), - sequence INTEGER, - season TEXT - REFERENCES SeasonLabel (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); -INSERT INTO TimeSeason VALUES(2000,1,'inter',NULL); -INSERT INTO TimeSeason VALUES(2000,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(2000,3,'winter',NULL); -INSERT INTO TimeSeason VALUES(2005,1,'inter',NULL); -INSERT INTO TimeSeason VALUES(2005,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(2005,3,'winter',NULL); -INSERT INTO TimeSeason VALUES(2010,1,'inter',NULL); -INSERT INTO TimeSeason VALUES(2010,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(2010,3,'winter',NULL); -INSERT INTO TimeSeason VALUES(2015,1,'inter',NULL); -INSERT INTO TimeSeason VALUES(2015,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(2015,3,'winter',NULL); -INSERT INTO TimeSeason VALUES(2020,1,'inter',NULL); -INSERT INTO TimeSeason VALUES(2020,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(2020,3,'winter',NULL); -INSERT INTO TimeSeason VALUES(2025,1,'inter',NULL); -INSERT INTO TimeSeason VALUES(2025,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(2025,3,'winter',NULL); -INSERT INTO TimeSeason VALUES(2030,1,'inter',NULL); -INSERT INTO TimeSeason VALUES(2030,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(2030,3,'winter',NULL); -INSERT INTO TimeSeason VALUES(2035,1,'inter',NULL); -INSERT INTO TimeSeason VALUES(2035,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(2035,3,'winter',NULL); -INSERT INTO TimeSeason VALUES(2040,1,'inter',NULL); -INSERT INTO TimeSeason VALUES(2040,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(2040,3,'winter',NULL); -INSERT INTO TimeSeason VALUES(2045,1,'inter',NULL); -INSERT INTO TimeSeason VALUES(2045,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(2045,3,'winter',NULL); -INSERT INTO TimeSeason VALUES(2050,1,'inter',NULL); -INSERT INTO TimeSeason VALUES(2050,2,'summer',NULL); -INSERT INTO TimeSeason VALUES(2050,3,'winter',NULL); -CREATE TABLE time_season_sequential -( - sequence INTEGER UNIQUE, - seas_seq TEXT, - season TEXT - REFERENCES time_season (season), - segment_fraction REAL NOT NULL, - notes TEXT, - PRIMARY KEY (seas_seq), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); -CREATE TABLE TimePeriodType -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO TimePeriodType VALUES('e','existing vintages'); -INSERT INTO TimePeriodType VALUES('f','future'); -CREATE TABLE OutputEmission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE RPSRequirement -( - region TEXT NOT NULL - REFERENCES Region (region), - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech_group TEXT NOT NULL - REFERENCES TechGroup (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE TechGroupMember -( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES Technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE Technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) -); -INSERT INTO Technology VALUES('well','p','supply','water','',1,0,0,0,0,0,0,'plain old water'); -INSERT INTO Technology VALUES('bulbs','p','residential','electric','',1,0,0,0,0,0,0,' residential lighting'); -INSERT INTO Technology VALUES('EH','p','electric','hydro','',0,0,0,0,0,0,0,'hydro power electric plant'); -INSERT INTO Technology VALUES('EF','p','electric','electric','',0,0,0,0,0,0,0,'fusion plant'); -CREATE TABLE OutputCost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) -); -COMMIT; diff --git a/data_files/example_dbs/survival_curve.sql b/data_files/example_dbs/survival_curve.sql deleted file mode 100644 index 11fd02bf0..000000000 --- a/data_files/example_dbs/survival_curve.sql +++ /dev/null @@ -1,1166 +0,0 @@ -BEGIN TRANSACTION; -CREATE TABLE capacity_credit -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -CREATE TABLE capacity_factor_process -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE capacity_factor_tech -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE capacity_to_activity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES commodity_type (label), - description TEXT -); -INSERT INTO "commodity" VALUES('source','s',NULL); -INSERT INTO "commodity" VALUES('demand','d',NULL); -CREATE TABLE commodity_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "commodity_type" VALUES('p','physical commodity'); -INSERT INTO "commodity_type" VALUES('a','annual commodity'); -INSERT INTO "commodity_type" VALUES('e','emissions commodity'); -INSERT INTO "commodity_type" VALUES('d','demand commodity'); -INSERT INTO "commodity_type" VALUES('s','source commodity'); -INSERT INTO "commodity_type" VALUES('w','waste commodity'); -INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); -INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); -CREATE TABLE construction_input -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage) -); -CREATE TABLE cost_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT NOT NULL - REFERENCES commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE cost_fixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_fixed" VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO "cost_fixed" VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); -CREATE TABLE cost_invest -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "cost_invest" VALUES('region','tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('region','tech_future',2030,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('region','tech_future',2035,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('region','tech_future',2040,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('region','tech_future',2045,1.0,NULL,NULL); -INSERT INTO "cost_invest" VALUES('region','tech_future',2050,1.0,NULL,NULL); -CREATE TABLE cost_variable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_variable" VALUES('region',2025,'tech_ancient',1994,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2025,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2030,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2035,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2040,'tech_old',2010,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2025,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2030,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2035,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2040,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2045,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2050,'tech_current',2025,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2030,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2035,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2040,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2045,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2050,'tech_future',2050,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2035,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2040,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2045,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2050,'tech_future',2045,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2040,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2045,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2050,'tech_future',2040,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2045,'tech_future',2030,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2050,'tech_future',2035,1.0,NULL,NULL); -INSERT INTO "cost_variable" VALUES('region',2050,'tech_future',2030,1.0,NULL,NULL); -CREATE TABLE demand -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - commodity TEXT - REFERENCES commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -INSERT INTO "demand" VALUES('region',2025,'demand',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('region',2030,'demand',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('region',2035,'demand',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('region',2040,'demand',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('region',2045,'demand',1.0,NULL,NULL); -INSERT INTO "demand" VALUES('region',2050,'demand',1.0,NULL,NULL); -CREATE TABLE demand_specific_distribution -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - demand_name TEXT - REFERENCES commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -CREATE TABLE efficiency -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -INSERT INTO "efficiency" VALUES('region','source','tech_ancient',1994,'demand',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','source','tech_old',2010,'demand',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','source','tech_current',2025,'demand',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','source','tech_future',2030,'demand',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','source','tech_future',2035,'demand',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','source','tech_future',2040,'demand',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','source','tech_future',2045,'demand',1.0,NULL); -INSERT INTO "efficiency" VALUES('region','source','tech_future',2050,'demand',1.0,NULL); -CREATE TABLE efficiency_variable -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE emission_activity -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -CREATE TABLE emission_embodied -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE emission_end_of_life -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -CREATE TABLE existing_capacity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "existing_capacity" VALUES('region','tech_ancient',1994,3.0,NULL,NULL); -INSERT INTO "existing_capacity" VALUES('region','tech_old',2010,0.7,NULL,NULL); -CREATE TABLE lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_survival_curve -( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "lifetime_survival_curve" VALUES('region',1994,'tech_ancient',1994,1.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',1999,'tech_ancient',1994,0.97,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2004,'tech_ancient',1994,8.80000000000000115e-01,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2009,'tech_ancient',1994,0.62,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2014,'tech_ancient',1994,0.27,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2019,'tech_ancient',1994,0.08,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2029,'tech_ancient',1994,0.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2010,'tech_old',2010,1.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2015,'tech_old',2010,0.97,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2020,'tech_old',2010,8.80000000000000115e-01,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2025,'tech_old',2010,0.62,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2030,'tech_old',2010,0.27,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2035,'tech_old',2010,0.08,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_old',2010,0.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2025,'tech_current',2025,1.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2030,'tech_current',2025,0.97,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2035,'tech_current',2025,8.80000000000000115e-01,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2040,'tech_current',2025,0.62,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_current',2025,0.27,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_current',2025,0.08,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2060,'tech_current',2025,0.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2030,'tech_future',2030,1.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2035,'tech_future',2030,0.97,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2040,'tech_future',2030,8.80000000000000115e-01,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_future',2030,0.62,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2030,0.27,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2030,0.08,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2065,'tech_future',2030,0.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2035,'tech_future',2035,1.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2040,'tech_future',2035,0.97,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_future',2035,8.80000000000000115e-01,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2035,0.62,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2035,0.27,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2060,'tech_future',2035,0.08,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2070,'tech_future',2035,0.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2040,'tech_future',2040,1.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_future',2040,0.97,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2040,8.80000000000000115e-01,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2040,0.62,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2060,'tech_future',2040,0.27,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2065,'tech_future',2040,0.08,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2075,'tech_future',2040,0.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2045,'tech_future',2045,1.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2045,0.97,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2045,8.80000000000000115e-01,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2060,'tech_future',2045,0.62,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2065,'tech_future',2045,0.27,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2070,'tech_future',2045,0.08,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2080,'tech_future',2045,0.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2050,'tech_future',2050,1.0,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2055,'tech_future',2050,0.97,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2060,'tech_future',2050,8.80000000000000115e-01,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2065,'tech_future',2050,0.62,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2070,'tech_future',2050,0.27,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2075,'tech_future',2050,0.08,NULL); -INSERT INTO "lifetime_survival_curve" VALUES('region',2085,'tech_future',2050,0.0,NULL); -CREATE TABLE lifetime_tech -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "lifetime_tech" VALUES('region','tech_ancient',35.0,NULL); -INSERT INTO "lifetime_tech" VALUES('region','tech_old',35.0,NULL); -INSERT INTO "lifetime_tech" VALUES('region','tech_current',35.0,NULL); -INSERT INTO "lifetime_tech" VALUES('region','tech_future',35.0,NULL); -CREATE TABLE limit_activity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_degrowth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE limit_growth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - season TEXT - REFERENCES time_season (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, season, tech, operator) -); -CREATE TABLE limit_storage_level_fraction -( - region TEXT, - season TEXT, - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - fraction REAL, - notes TEXT, - CHECK (fraction >= 0 AND fraction <= 1), - PRIMARY KEY(region, season, tod, tech, operator) -); -CREATE TABLE limit_tech_input_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_input_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_output_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE limit_tech_output_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE linked_tech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES technology (tech), - emis_comm TEXT - REFERENCES commodity (name), - driven_tech TEXT - REFERENCES technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -CREATE TABLE loan_lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE loan_rate -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); -INSERT INTO "metadata" VALUES('DB_MINOR',0,''); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,'Discount Rate for future costs'); -INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -CREATE TABLE myopic_efficiency -( - base_year integer, - region text, - input_comm text, - tech text, - vintage integer, - output_comm text, - efficiency real, - lifetime integer, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (region, input_comm, tech, vintage, output_comm) -); -CREATE TABLE operator -( - operator TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "operator" VALUES('e','equal to'); -INSERT INTO "operator" VALUES('le','less than or equal to'); -INSERT INTO "operator" VALUES('ge','greater than or equal to'); -CREATE TABLE output_built_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES sector_label (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) -); -CREATE TABLE output_curtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE output_emission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE output_flow_in -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out_summary -( - scenario TEXT NOT NULL, - region TEXT NOT NULL, - sector TEXT, - period INTEGER, - input_comm TEXT NOT NULL, - tech TEXT NOT NULL, - vintage INTEGER, - output_comm TEXT NOT NULL, - flow REAL NOT NULL, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_net_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_objective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE output_retired_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_storage_level -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT, - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE planning_reserve_margin -( - region TEXT - PRIMARY KEY - REFERENCES region (region), - margin REAL, - notes TEXT -); -CREATE TABLE ramp_down_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE ramp_up_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -INSERT INTO "region" VALUES('region',NULL); -CREATE TABLE reserve_capacity_derate -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE rps_requirement -( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL - REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES tech_group (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE sector_label -( - sector TEXT PRIMARY KEY, - notes TEXT -); -CREATE TABLE storage_duration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE tech_group -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE tech_group_member -( - group_name TEXT - REFERENCES tech_group (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technology_type (label) -); -INSERT INTO "technology" VALUES('tech_ancient','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO "technology" VALUES('tech_old','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO "technology" VALUES('tech_current','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -INSERT INTO "technology" VALUES('tech_future','p','energy',NULL,NULL,0,0,0,0,0,0,0,0,NULL); -CREATE TABLE technology_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "technology_type" VALUES('p','production technology'); -INSERT INTO "technology_type" VALUES('pb','baseload production technology'); -INSERT INTO "technology_type" VALUES('ps','storage production technology'); -CREATE TABLE time_of_day -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY, - hours REAL NOT NULL DEFAULT 1, - notes TEXT, - CHECK (hours > 0) -); -INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(0,'d',24); -CREATE TABLE time_period -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES time_period_type (label) -); -INSERT INTO "time_period" VALUES(-2,1994,'e'); -INSERT INTO "time_period" VALUES(-1,2010,'e'); -INSERT INTO "time_period" VALUES(0,2025,'f'); -INSERT INTO "time_period" VALUES(1,2030,'f'); -INSERT INTO "time_period" VALUES(2,2035,'f'); -INSERT INTO "time_period" VALUES(3,2040,'f'); -INSERT INTO "time_period" VALUES(4,2045,'f'); -INSERT INTO "time_period" VALUES(5,2050,'f'); -INSERT INTO "time_period" VALUES(6,2055,'f'); -CREATE TABLE time_period_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "time_period_type" VALUES('e','existing vintages'); -INSERT INTO "time_period_type" VALUES('f','future'); -CREATE TABLE time_season -( - sequence INTEGER UNIQUE, - season TEXT, - segment_fraction REAL NOT NULL, - notes TEXT, - PRIMARY KEY (season), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); -INSERT INTO "time_season" VALUES(0,'s',1.0,NULL); - -CREATE TABLE time_season_sequential -( - sequence INTEGER UNIQUE, - seas_seq TEXT, - season TEXT REFERENCES time_season(season), - segment_fraction REAL NOT NULL, - notes TEXT, - PRIMARY KEY (seas_seq), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); - -CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); -COMMIT; diff --git a/data_files/example_dbs/test_system.sql b/data_files/example_dbs/test_system.sql deleted file mode 100644 index c43d9d17e..000000000 --- a/data_files/example_dbs/test_system.sql +++ /dev/null @@ -1,1450 +0,0 @@ -BEGIN TRANSACTION; -CREATE TABLE capacity_credit -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -CREATE TABLE capacity_factor_process -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE capacity_factor_tech -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -INSERT INTO "capacity_factor_tech" VALUES('R1','spring','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1','spring','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1','summer','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1','summer','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1','fall','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1','fall','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R1','winter','day','E_SOLPV',0.6,''); -INSERT INTO "capacity_factor_tech" VALUES('R1','winter','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2','spring','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2','spring','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2','summer','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2','summer','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2','fall','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2','fall','night','E_SOLPV',0.0,''); -INSERT INTO "capacity_factor_tech" VALUES('R2','winter','day','E_SOLPV',0.48,''); -INSERT INTO "capacity_factor_tech" VALUES('R2','winter','night','E_SOLPV',0.0,''); -CREATE TABLE capacity_to_activity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "capacity_to_activity" VALUES('R1','S_IMPETH',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R1','S_IMPOIL',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R1','S_IMPNG',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R1','S_IMPURN',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R1','S_OILREF',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R1','E_NGCC',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('R1','E_SOLPV',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('R1','E_BATT',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('R1','E_NUCLEAR',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('R1','T_BLND',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R1','T_DSL',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R1','T_GSL',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R1','T_EV',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R1','R_EH',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R1','R_NGH',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R2','S_IMPETH',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R2','S_IMPOIL',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R2','S_IMPNG',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R2','S_IMPURN',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R2','S_OILREF',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R2','E_NGCC',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('R2','E_SOLPV',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('R2','E_BATT',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('R2','E_NUCLEAR',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('R2','T_BLND',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R2','T_DSL',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R2','T_GSL',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R2','T_EV',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R2','R_EH',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R2','R_NGH',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('R1-R2','E_TRANS',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('R2-R1','E_TRANS',31.54,''); -CREATE TABLE commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES commodity_type (label), - description TEXT -); -INSERT INTO "commodity" VALUES('ethos','s','dummy commodity to supply inputs (makes graph easier to read)'); -INSERT INTO "commodity" VALUES('OIL','p','crude oil'); -INSERT INTO "commodity" VALUES('NG','p','natural gas'); -INSERT INTO "commodity" VALUES('URN','p','uranium'); -INSERT INTO "commodity" VALUES('ETH','p','ethanol'); -INSERT INTO "commodity" VALUES('SOL','p','solar insolation'); -INSERT INTO "commodity" VALUES('GSL','p','gasoline'); -INSERT INTO "commodity" VALUES('DSL','p','diesel'); -INSERT INTO "commodity" VALUES('ELC','p','electricity'); -INSERT INTO "commodity" VALUES('E10','p','gasoline blend with 10% ethanol'); -INSERT INTO "commodity" VALUES('VMT','d','travel demand for vehicle-miles traveled'); -INSERT INTO "commodity" VALUES('RH','d','demand for residential heating'); -INSERT INTO "commodity" VALUES('CO2','e','CO2 emissions commodity'); -CREATE TABLE commodity_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "commodity_type" VALUES('w','waste commodity'); -INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); -INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); -INSERT INTO "commodity_type" VALUES('a','annual commodity'); -INSERT INTO "commodity_type" VALUES('s','source commodity'); -INSERT INTO "commodity_type" VALUES('p','physical commodity'); -INSERT INTO "commodity_type" VALUES('e','emissions commodity'); -INSERT INTO "commodity_type" VALUES('d','demand commodity'); -CREATE TABLE construction_input -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage) -); -CREATE TABLE cost_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT NOT NULL - REFERENCES commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE cost_fixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_fixed" VALUES('R1',2020,'E_NGCC',2020,30.6,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2025,'E_NGCC',2020,9.78,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2025,'E_NGCC',2025,9.78,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NGCC',2020,9.78,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NGCC',2025,9.78,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NGCC',2030,9.78,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2020,'E_SOLPV',2020,10.4,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2025,'E_SOLPV',2020,10.4,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2025,'E_SOLPV',2025,9.1,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_SOLPV',2020,10.4,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_SOLPV',2025,9.1,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_SOLPV',2030,9.1,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2020,'E_NUCLEAR',2020,9.809999999999998e+01,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2025,'E_NUCLEAR',2020,9.809999999999998e+01,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2025,'E_NUCLEAR',2025,9.809999999999998e+01,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NUCLEAR',2020,9.809999999999998e+01,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NUCLEAR',2025,9.809999999999998e+01,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_NUCLEAR',2030,9.809999999999998e+01,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2020,'E_BATT',2020,7.05,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2025,'E_BATT',2020,7.05,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2025,'E_BATT',2025,7.05,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_BATT',2020,7.05,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_BATT',2025,7.05,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R1',2030,'E_BATT',2030,7.05,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2020,'E_NGCC',2020,24.48,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2025,'E_NGCC',2020,7.824,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2025,'E_NGCC',2025,7.824,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NGCC',2020,7.824,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NGCC',2025,7.824,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NGCC',2030,7.824,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2020,'E_SOLPV',2020,8.32,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2025,'E_SOLPV',2020,8.32,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2025,'E_SOLPV',2025,7.28,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_SOLPV',2020,8.32,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_SOLPV',2025,7.28,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_SOLPV',2030,7.28,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2020,'E_NUCLEAR',2020,78.48,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2025,'E_NUCLEAR',2020,78.48,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2025,'E_NUCLEAR',2025,78.48,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NUCLEAR',2020,78.48,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NUCLEAR',2025,78.48,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_NUCLEAR',2030,78.48,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2020,'E_BATT',2020,5.64,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2025,'E_BATT',2020,5.64,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2025,'E_BATT',2025,5.64,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_BATT',2020,5.64,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_BATT',2025,5.64,'$M/GWyr',''); -INSERT INTO "cost_fixed" VALUES('R2',2030,'E_BATT',2030,5.64,'$M/GWyr',''); -CREATE TABLE cost_invest -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "cost_invest" VALUES('R1','E_NGCC',2020,1050.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','E_NGCC',2025,1025.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','E_NGCC',2030,1000.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','E_SOLPV',2020,900.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','E_SOLPV',2025,560.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','E_SOLPV',2030,800.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','E_NUCLEAR',2020,6145.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','E_NUCLEAR',2025,6045.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','E_NUCLEAR',2030,5890.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','E_BATT',2020,1150.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','E_BATT',2025,720.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','E_BATT',2030,480.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R1','T_GSL',2020,2570.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R1','T_GSL',2025,2700.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R1','T_GSL',2030,2700.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R1','T_DSL',2020,2715.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R1','T_DSL',2025,2810.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R1','T_DSL',2030,2810.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R1','T_EV',2020,3100.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R1','T_EV',2025,3030.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R1','T_EV',2030,2925.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R1','R_EH',2020,4.1,'$/PJ/yr',''); -INSERT INTO "cost_invest" VALUES('R1','R_EH',2025,4.1,'$/PJ/yr',''); -INSERT INTO "cost_invest" VALUES('R1','R_EH',2030,4.1,'$/PJ/yr',''); -INSERT INTO "cost_invest" VALUES('R1','R_NGH',2020,7.6,'$/PJ/yr',''); -INSERT INTO "cost_invest" VALUES('R1','R_NGH',2025,7.6,'$/PJ/yr',''); -INSERT INTO "cost_invest" VALUES('R1','R_NGH',2030,7.6,'$/PJ/yr',''); -INSERT INTO "cost_invest" VALUES('R2','E_NGCC',2020,840.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','E_NGCC',2025,820.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','E_NGCC',2030,800.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','E_SOLPV',2020,720.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','E_SOLPV',2025,448.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','E_SOLPV',2030,640.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','E_NUCLEAR',2020,4916.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','E_NUCLEAR',2025,4836.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','E_NUCLEAR',2030,4712.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','E_BATT',2020,920.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','E_BATT',2025,576.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','E_BATT',2030,384.0,'$M/GW',''); -INSERT INTO "cost_invest" VALUES('R2','T_GSL',2020,2056.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R2','T_GSL',2025,2160.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R2','T_GSL',2030,2160.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R2','T_DSL',2020,2172.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R2','T_DSL',2025,2248.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R2','T_DSL',2030,2248.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R2','T_EV',2020,2480.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R2','T_EV',2025,2424.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R2','T_EV',2030,2340.0,'$/bvmt/yr',''); -INSERT INTO "cost_invest" VALUES('R2','R_EH',2020,3.28,'$/PJ/yr',''); -INSERT INTO "cost_invest" VALUES('R2','R_EH',2025,3.28,'$/PJ/yr',''); -INSERT INTO "cost_invest" VALUES('R2','R_EH',2030,3.28,'$/PJ/yr',''); -INSERT INTO "cost_invest" VALUES('R2','R_NGH',2020,6.08,'$/PJ/yr',''); -INSERT INTO "cost_invest" VALUES('R2','R_NGH',2025,6.08,'$/PJ/yr',''); -INSERT INTO "cost_invest" VALUES('R2','R_NGH',2030,6.08,'$/PJ/yr',''); -CREATE TABLE cost_variable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_variable" VALUES('R1',2020,'S_IMPETH',2020,32.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2025,'S_IMPETH',2020,32.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2030,'S_IMPETH',2020,32.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2020,'S_IMPOIL',2020,20.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2025,'S_IMPOIL',2020,20.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2030,'S_IMPOIL',2020,20.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2020,'S_IMPNG',2020,4.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2025,'S_IMPNG',2020,4.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2030,'S_IMPNG',2020,4.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2020,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2025,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2030,'S_OILREF',2020,1.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2020,'E_NGCC',2020,1.6,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2025,'E_NGCC',2020,1.6,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2025,'E_NGCC',2025,1.7,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2030,'E_NGCC',2020,1.6,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2030,'E_NGCC',2025,1.7,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2030,'E_NGCC',2030,1.8,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2020,'E_NUCLEAR',2020,0.24,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2025,'E_NUCLEAR',2020,0.24,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2025,'E_NUCLEAR',2025,0.25,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2030,'E_NUCLEAR',2020,0.24,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2030,'E_NUCLEAR',2025,0.25,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1',2030,'E_NUCLEAR',2030,0.26,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2020,'S_IMPETH',2020,25.6,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2025,'S_IMPETH',2020,25.6,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2030,'S_IMPETH',2020,25.6,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2020,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2025,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2030,'S_IMPOIL',2020,16.0,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2020,'S_IMPNG',2020,3.2,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2025,'S_IMPNG',2020,3.2,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2030,'S_IMPNG',2020,3.2,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2020,'S_OILREF',2020,0.8,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2025,'S_OILREF',2020,0.8,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2030,'S_OILREF',2020,0.8,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2020,'E_NGCC',2020,1.28,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2025,'E_NGCC',2020,1.28,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2025,'E_NGCC',2025,1.36,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2030,'E_NGCC',2020,1.28,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2030,'E_NGCC',2025,1.36,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2030,'E_NGCC',2030,1.44,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2020,'E_NUCLEAR',2020,0.192,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2025,'E_NUCLEAR',2020,0.192,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2025,'E_NUCLEAR',2025,0.2,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2030,'E_NUCLEAR',2020,0.192,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2030,'E_NUCLEAR',2025,0.2,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2',2030,'E_NUCLEAR',2030,2.08000000000000018e-01,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1-R2',2020,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1-R2',2025,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R1-R2',2030,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2-R1',2020,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2-R1',2025,'E_TRANS',2015,0.1,'$M/PJ',''); -INSERT INTO "cost_variable" VALUES('R2-R1',2030,'E_TRANS',2015,0.1,'$M/PJ',''); -CREATE TABLE demand -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - commodity TEXT - REFERENCES commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -INSERT INTO "demand" VALUES('R1',2020,'RH',30.0,'',''); -INSERT INTO "demand" VALUES('R1',2025,'RH',33.0,'',''); -INSERT INTO "demand" VALUES('R1',2030,'RH',36.0,'',''); -INSERT INTO "demand" VALUES('R1',2020,'VMT',84.0,'',''); -INSERT INTO "demand" VALUES('R1',2025,'VMT',91.0,'',''); -INSERT INTO "demand" VALUES('R1',2030,'VMT',98.0,'',''); -INSERT INTO "demand" VALUES('R2',2020,'RH',70.0,'',''); -INSERT INTO "demand" VALUES('R2',2025,'RH',77.0,'',''); -INSERT INTO "demand" VALUES('R2',2030,'RH',84.0,'',''); -INSERT INTO "demand" VALUES('R2',2020,'VMT',36.0,'',''); -INSERT INTO "demand" VALUES('R2',2025,'VMT',39.0,'',''); -INSERT INTO "demand" VALUES('R2',2030,'VMT',42.0,'',''); -CREATE TABLE demand_specific_distribution -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - demand_name TEXT - REFERENCES commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -INSERT INTO "demand_specific_distribution" VALUES('R1','spring','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R1','spring','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R1','summer','day','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R1','summer','night','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R1','fall','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R1','fall','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R1','winter','day','RH',0.3,''); -INSERT INTO "demand_specific_distribution" VALUES('R1','winter','night','RH',0.4,''); -INSERT INTO "demand_specific_distribution" VALUES('R2','spring','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R2','spring','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R2','summer','day','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R2','summer','night','RH',0.0,''); -INSERT INTO "demand_specific_distribution" VALUES('R2','fall','day','RH',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('R2','fall','night','RH',0.1,''); -INSERT INTO "demand_specific_distribution" VALUES('R2','winter','day','RH',0.3,''); -INSERT INTO "demand_specific_distribution" VALUES('R2','winter','night','RH',0.4,''); -CREATE TABLE efficiency -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -INSERT INTO "efficiency" VALUES('R1','ethos','S_IMPETH',2020,'ETH',1.0,''); -INSERT INTO "efficiency" VALUES('R1','ethos','S_IMPOIL',2020,'OIL',1.0,''); -INSERT INTO "efficiency" VALUES('R1','ethos','S_IMPNG',2020,'NG',1.0,''); -INSERT INTO "efficiency" VALUES('R1','ethos','S_IMPURN',2020,'URN',1.0,''); -INSERT INTO "efficiency" VALUES('R1','OIL','S_OILREF',2020,'GSL',1.0,''); -INSERT INTO "efficiency" VALUES('R1','OIL','S_OILREF',2020,'DSL',1.0,''); -INSERT INTO "efficiency" VALUES('R1','ETH','T_BLND',2020,'E10',1.0,''); -INSERT INTO "efficiency" VALUES('R1','GSL','T_BLND',2020,'E10',1.0,''); -INSERT INTO "efficiency" VALUES('R1','NG','E_NGCC',2020,'ELC',0.55,''); -INSERT INTO "efficiency" VALUES('R1','NG','E_NGCC',2025,'ELC',0.55,''); -INSERT INTO "efficiency" VALUES('R1','NG','E_NGCC',2030,'ELC',0.55,''); -INSERT INTO "efficiency" VALUES('R1','SOL','E_SOLPV',2020,'ELC',1.0,''); -INSERT INTO "efficiency" VALUES('R1','SOL','E_SOLPV',2025,'ELC',1.0,''); -INSERT INTO "efficiency" VALUES('R1','SOL','E_SOLPV',2030,'ELC',1.0,''); -INSERT INTO "efficiency" VALUES('R1','URN','E_NUCLEAR',2015,'ELC',0.4,''); -INSERT INTO "efficiency" VALUES('R1','URN','E_NUCLEAR',2020,'ELC',0.4,''); -INSERT INTO "efficiency" VALUES('R1','URN','E_NUCLEAR',2025,'ELC',0.4,''); -INSERT INTO "efficiency" VALUES('R1','URN','E_NUCLEAR',2030,'ELC',0.4,''); -INSERT INTO "efficiency" VALUES('R1','ELC','E_BATT',2020,'ELC',0.85,''); -INSERT INTO "efficiency" VALUES('R1','ELC','E_BATT',2025,'ELC',0.85,''); -INSERT INTO "efficiency" VALUES('R1','ELC','E_BATT',2030,'ELC',0.85,''); -INSERT INTO "efficiency" VALUES('R1','E10','T_GSL',2020,'VMT',0.25,''); -INSERT INTO "efficiency" VALUES('R1','E10','T_GSL',2025,'VMT',0.25,''); -INSERT INTO "efficiency" VALUES('R1','E10','T_GSL',2030,'VMT',0.25,''); -INSERT INTO "efficiency" VALUES('R1','DSL','T_DSL',2020,'VMT',0.3,''); -INSERT INTO "efficiency" VALUES('R1','DSL','T_DSL',2025,'VMT',0.3,''); -INSERT INTO "efficiency" VALUES('R1','DSL','T_DSL',2030,'VMT',0.3,''); -INSERT INTO "efficiency" VALUES('R1','ELC','T_EV',2020,'VMT',0.89,''); -INSERT INTO "efficiency" VALUES('R1','ELC','T_EV',2025,'VMT',0.89,''); -INSERT INTO "efficiency" VALUES('R1','ELC','T_EV',2030,'VMT',0.89,''); -INSERT INTO "efficiency" VALUES('R1','ELC','R_EH',2020,'RH',1.0,''); -INSERT INTO "efficiency" VALUES('R1','ELC','R_EH',2025,'RH',1.0,''); -INSERT INTO "efficiency" VALUES('R1','ELC','R_EH',2030,'RH',1.0,''); -INSERT INTO "efficiency" VALUES('R1','NG','R_NGH',2020,'RH',0.85,''); -INSERT INTO "efficiency" VALUES('R1','NG','R_NGH',2025,'RH',0.85,''); -INSERT INTO "efficiency" VALUES('R1','NG','R_NGH',2030,'RH',0.85,''); -INSERT INTO "efficiency" VALUES('R2','ethos','S_IMPETH',2020,'ETH',1.0,''); -INSERT INTO "efficiency" VALUES('R2','ethos','S_IMPOIL',2020,'OIL',1.0,''); -INSERT INTO "efficiency" VALUES('R2','ethos','S_IMPNG',2020,'NG',1.0,''); -INSERT INTO "efficiency" VALUES('R2','ethos','S_IMPURN',2020,'URN',1.0,''); -INSERT INTO "efficiency" VALUES('R2','OIL','S_OILREF',2020,'GSL',1.0,''); -INSERT INTO "efficiency" VALUES('R2','OIL','S_OILREF',2020,'DSL',1.0,''); -INSERT INTO "efficiency" VALUES('R2','ETH','T_BLND',2020,'E10',1.0,''); -INSERT INTO "efficiency" VALUES('R2','GSL','T_BLND',2020,'E10',1.0,''); -INSERT INTO "efficiency" VALUES('R2','NG','E_NGCC',2020,'ELC',0.55,''); -INSERT INTO "efficiency" VALUES('R2','NG','E_NGCC',2025,'ELC',0.55,''); -INSERT INTO "efficiency" VALUES('R2','NG','E_NGCC',2030,'ELC',0.55,''); -INSERT INTO "efficiency" VALUES('R2','SOL','E_SOLPV',2020,'ELC',1.0,''); -INSERT INTO "efficiency" VALUES('R2','SOL','E_SOLPV',2025,'ELC',1.0,''); -INSERT INTO "efficiency" VALUES('R2','SOL','E_SOLPV',2030,'ELC',1.0,''); -INSERT INTO "efficiency" VALUES('R2','URN','E_NUCLEAR',2015,'ELC',0.4,''); -INSERT INTO "efficiency" VALUES('R2','URN','E_NUCLEAR',2020,'ELC',0.4,''); -INSERT INTO "efficiency" VALUES('R2','URN','E_NUCLEAR',2025,'ELC',0.4,''); -INSERT INTO "efficiency" VALUES('R2','URN','E_NUCLEAR',2030,'ELC',0.4,''); -INSERT INTO "efficiency" VALUES('R2','ELC','E_BATT',2020,'ELC',0.85,''); -INSERT INTO "efficiency" VALUES('R2','ELC','E_BATT',2025,'ELC',0.85,''); -INSERT INTO "efficiency" VALUES('R2','ELC','E_BATT',2030,'ELC',0.85,''); -INSERT INTO "efficiency" VALUES('R2','E10','T_GSL',2020,'VMT',0.25,''); -INSERT INTO "efficiency" VALUES('R2','E10','T_GSL',2025,'VMT',0.25,''); -INSERT INTO "efficiency" VALUES('R2','E10','T_GSL',2030,'VMT',0.25,''); -INSERT INTO "efficiency" VALUES('R2','DSL','T_DSL',2020,'VMT',0.3,''); -INSERT INTO "efficiency" VALUES('R2','DSL','T_DSL',2025,'VMT',0.3,''); -INSERT INTO "efficiency" VALUES('R2','DSL','T_DSL',2030,'VMT',0.3,''); -INSERT INTO "efficiency" VALUES('R2','ELC','T_EV',2020,'VMT',0.89,''); -INSERT INTO "efficiency" VALUES('R2','ELC','T_EV',2025,'VMT',0.89,''); -INSERT INTO "efficiency" VALUES('R2','ELC','T_EV',2030,'VMT',0.89,''); -INSERT INTO "efficiency" VALUES('R2','ELC','R_EH',2020,'RH',1.0,''); -INSERT INTO "efficiency" VALUES('R2','ELC','R_EH',2025,'RH',1.0,''); -INSERT INTO "efficiency" VALUES('R2','ELC','R_EH',2030,'RH',1.0,''); -INSERT INTO "efficiency" VALUES('R2','NG','R_NGH',2020,'RH',0.85,''); -INSERT INTO "efficiency" VALUES('R2','NG','R_NGH',2025,'RH',0.85,''); -INSERT INTO "efficiency" VALUES('R2','NG','R_NGH',2030,'RH',0.85,''); -INSERT INTO "efficiency" VALUES('R1-R2','ELC','E_TRANS',2015,'ELC',0.9,''); -INSERT INTO "efficiency" VALUES('R2-R1','ELC','E_TRANS',2015,'ELC',0.9,''); -CREATE TABLE efficiency_variable -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE emission_activity -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -INSERT INTO "emission_activity" VALUES('R1','CO2','ethos','S_IMPNG',2020,'NG',5.029999999999999e+01,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO "emission_activity" VALUES('R1','CO2','OIL','S_OILREF',2020,'GSL',67.2,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO "emission_activity" VALUES('R1','CO2','OIL','S_OILREF',2020,'DSL',69.4,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO "emission_activity" VALUES('R2','CO2','ethos','S_IMPNG',2020,'NG',5.029999999999999e+01,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO "emission_activity" VALUES('R2','CO2','OIL','S_OILREF',2020,'GSL',67.2,'kT/PJ','taken from MIT Energy Fact Sheet'); -INSERT INTO "emission_activity" VALUES('R2','CO2','OIL','S_OILREF',2020,'DSL',69.4,'kT/PJ','taken from MIT Energy Fact Sheet'); -CREATE TABLE emission_embodied -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE emission_end_of_life -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -CREATE TABLE existing_capacity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "existing_capacity" VALUES('R1','E_NUCLEAR',2015,0.07,'GW',''); -INSERT INTO "existing_capacity" VALUES('R2','E_NUCLEAR',2015,0.03,'GW',''); -INSERT INTO "existing_capacity" VALUES('R1-R2','E_TRANS',2015,10.0,'GW',''); -INSERT INTO "existing_capacity" VALUES('R2-R1','E_TRANS',2015,10.0,'GW',''); -CREATE TABLE lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE lifetime_survival_curve -( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE lifetime_tech -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "lifetime_tech" VALUES('R1','S_IMPETH',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','S_IMPOIL',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','S_IMPNG',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','S_IMPURN',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','S_OILREF',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','E_NGCC',30.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','E_SOLPV',30.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','E_BATT',20.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','E_NUCLEAR',50.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','T_BLND',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','T_DSL',12.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','T_GSL',12.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','T_EV',12.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','R_EH',20.0,''); -INSERT INTO "lifetime_tech" VALUES('R1','R_NGH',20.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','S_IMPETH',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','S_IMPOIL',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','S_IMPNG',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','S_IMPURN',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','S_OILREF',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','E_NGCC',30.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','E_SOLPV',30.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','E_BATT',20.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','E_NUCLEAR',50.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','T_BLND',100.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','T_DSL',12.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','T_GSL',12.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','T_EV',12.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','R_EH',20.0,''); -INSERT INTO "lifetime_tech" VALUES('R2','R_NGH',20.0,''); -INSERT INTO "lifetime_tech" VALUES('R1-R2','E_TRANS',30.0,''); -INSERT INTO "lifetime_tech" VALUES('R2-R1','E_TRANS',30.0,''); -CREATE TABLE limit_activity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -INSERT INTO "limit_activity" VALUES('R1',2020,'T_GSL','ge',35.0,'',''); -INSERT INTO "limit_activity" VALUES('R1',2025,'T_GSL','ge',35.0,'',''); -INSERT INTO "limit_activity" VALUES('R1',2030,'T_GSL','ge',35.0,'',''); -INSERT INTO "limit_activity" VALUES('R2',2020,'T_GSL','ge',15.0,'',''); -INSERT INTO "limit_activity" VALUES('R2',2025,'T_GSL','ge',15.0,'',''); -INSERT INTO "limit_activity" VALUES('R2',2030,'T_GSL','ge',15.0,'',''); -CREATE TABLE limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_degrowth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -INSERT INTO "limit_emission" VALUES('R1',2020,'CO2','le',25000.0,'kT CO2',''); -INSERT INTO "limit_emission" VALUES('R1',2025,'CO2','le',24000.0,'kT CO2',''); -INSERT INTO "limit_emission" VALUES('R1',2030,'CO2','le',23000.0,'kT CO2',''); -INSERT INTO "limit_emission" VALUES('global',2020,'CO2','le',37500.0,'kT CO2',''); -INSERT INTO "limit_emission" VALUES('global',2025,'CO2','le',36000.0,'kT CO2',''); -INSERT INTO "limit_emission" VALUES('global',2030,'CO2','le',34500.0,'kT CO2',''); -CREATE TABLE limit_growth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - season TEXT - REFERENCES time_season (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, season, tech, operator) -); -CREATE TABLE limit_storage_level_fraction -( - region TEXT, - season TEXT, - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - fraction REAL, - notes TEXT, - CHECK (fraction >= 0 AND fraction <= 1), - PRIMARY KEY(region, season, tod, tech, operator) -); -INSERT INTO "limit_storage_level_fraction" VALUES('R1','winter','day','E_BATT','e',0.5,''); -INSERT INTO "limit_storage_level_fraction" VALUES('R2','summer','day','E_BATT','e',0.5,''); -CREATE TABLE limit_tech_input_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -INSERT INTO "limit_tech_input_split" VALUES('R1',2020,'GSL','T_BLND','ge',0.9,''); -INSERT INTO "limit_tech_input_split" VALUES('R1',2020,'ETH','T_BLND','ge',0.1,''); -INSERT INTO "limit_tech_input_split" VALUES('R1',2025,'GSL','T_BLND','ge',0.9,''); -INSERT INTO "limit_tech_input_split" VALUES('R1',2025,'ETH','T_BLND','ge',0.1,''); -INSERT INTO "limit_tech_input_split" VALUES('R1',2030,'GSL','T_BLND','ge',0.9,''); -INSERT INTO "limit_tech_input_split" VALUES('R1',2030,'ETH','T_BLND','ge',0.1,''); -INSERT INTO "limit_tech_input_split" VALUES('R2',2020,'GSL','T_BLND','ge',0.72,''); -INSERT INTO "limit_tech_input_split" VALUES('R2',2020,'ETH','T_BLND','ge',0.08,''); -INSERT INTO "limit_tech_input_split" VALUES('R2',2025,'GSL','T_BLND','ge',0.72,''); -INSERT INTO "limit_tech_input_split" VALUES('R2',2025,'ETH','T_BLND','ge',0.08,''); -INSERT INTO "limit_tech_input_split" VALUES('R2',2030,'GSL','T_BLND','ge',0.72,''); -INSERT INTO "limit_tech_input_split" VALUES('R2',2030,'ETH','T_BLND','ge',0.08,''); -CREATE TABLE limit_tech_input_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_output_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -INSERT INTO "limit_tech_output_split" VALUES('R1',2020,'S_OILREF','GSL','ge',0.9,''); -INSERT INTO "limit_tech_output_split" VALUES('R1',2020,'S_OILREF','DSL','ge',0.1,''); -INSERT INTO "limit_tech_output_split" VALUES('R1',2025,'S_OILREF','GSL','ge',0.9,''); -INSERT INTO "limit_tech_output_split" VALUES('R1',2025,'S_OILREF','DSL','ge',0.1,''); -INSERT INTO "limit_tech_output_split" VALUES('R1',2030,'S_OILREF','GSL','ge',0.9,''); -INSERT INTO "limit_tech_output_split" VALUES('R1',2030,'S_OILREF','DSL','ge',0.1,''); -INSERT INTO "limit_tech_output_split" VALUES('R2',2020,'S_OILREF','GSL','ge',0.72,''); -INSERT INTO "limit_tech_output_split" VALUES('R2',2020,'S_OILREF','DSL','ge',0.08,''); -INSERT INTO "limit_tech_output_split" VALUES('R2',2025,'S_OILREF','GSL','ge',0.72,''); -INSERT INTO "limit_tech_output_split" VALUES('R2',2025,'S_OILREF','DSL','ge',0.08,''); -INSERT INTO "limit_tech_output_split" VALUES('R2',2030,'S_OILREF','GSL','ge',0.72,''); -INSERT INTO "limit_tech_output_split" VALUES('R2',2030,'S_OILREF','DSL','ge',0.08,''); -CREATE TABLE limit_tech_output_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE linked_tech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES technology (tech), - emis_comm TEXT - REFERENCES commodity (name), - driven_tech TEXT - REFERENCES technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -CREATE TABLE loan_lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE loan_rate -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); -INSERT INTO "metadata" VALUES('DB_MINOR',0,''); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,''); -CREATE TABLE myopic_efficiency -( - base_year integer, - region text, - input_comm text, - tech text, - vintage integer, - output_comm text, - efficiency real, - lifetime integer, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (region, input_comm, tech, vintage, output_comm) -); -CREATE TABLE operator -( - operator TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "operator" VALUES('e','equal to'); -INSERT INTO "operator" VALUES('le','less than or equal to'); -INSERT INTO "operator" VALUES('ge','greater than or equal to'); -CREATE TABLE output_built_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES sector_label (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) -); -CREATE TABLE output_curtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE output_emission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE output_flow_in -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out_summary -( - scenario TEXT NOT NULL, - region TEXT NOT NULL, - sector TEXT, - period INTEGER, - input_comm TEXT NOT NULL, - tech TEXT NOT NULL, - vintage INTEGER, - output_comm TEXT NOT NULL, - flow REAL NOT NULL, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_net_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_objective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE output_retired_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_storage_level -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT, - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE planning_reserve_margin -( - region TEXT - PRIMARY KEY - REFERENCES region (region), - margin REAL, - notes TEXT -); -CREATE TABLE ramp_down_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE ramp_up_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -INSERT INTO "region" VALUES('R1',NULL); -INSERT INTO "region" VALUES('R2',NULL); -CREATE TABLE reserve_capacity_derate -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE rps_requirement -( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL - REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES tech_group (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE sector_label -( - sector TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "sector_label" VALUES('supply',NULL); -INSERT INTO "sector_label" VALUES('electric',NULL); -INSERT INTO "sector_label" VALUES('transport',NULL); -INSERT INTO "sector_label" VALUES('commercial',NULL); -INSERT INTO "sector_label" VALUES('residential',NULL); -INSERT INTO "sector_label" VALUES('industrial',NULL); -CREATE TABLE storage_duration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "storage_duration" VALUES('R1','E_BATT',8.0,'8-hour duration specified as fraction of a day'); -INSERT INTO "storage_duration" VALUES('R2','E_BATT',8.0,'8-hour duration specified as fraction of a day'); -CREATE TABLE tech_group -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE tech_group_member -( - group_name TEXT - REFERENCES tech_group (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technology_type (label) -); -INSERT INTO "technology" VALUES('S_IMPETH','p','supply','','',1,0,0,0,0,0,0,0,' imported ethanol'); -INSERT INTO "technology" VALUES('S_IMPOIL','p','supply','','',1,0,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO "technology" VALUES('S_IMPNG','p','supply','','',1,0,0,0,0,0,0,0,' imported natural gas'); -INSERT INTO "technology" VALUES('S_IMPURN','p','supply','','',1,0,0,0,0,0,0,0,' imported uranium'); -INSERT INTO "technology" VALUES('S_OILREF','p','supply','','',0,0,0,1,0,0,0,0,' crude oil refinery'); -INSERT INTO "technology" VALUES('E_NGCC','p','electric','','',0,0,0,0,0,0,0,0,' natural gas combined-cycle'); -INSERT INTO "technology" VALUES('E_SOLPV','p','electric','','',0,0,0,0,0,0,0,0,' solar photovoltaic'); -INSERT INTO "technology" VALUES('E_BATT','ps','electric','','',0,0,0,0,0,0,0,0,' lithium-ion battery'); -INSERT INTO "technology" VALUES('E_NUCLEAR','pb','electric','','',0,0,0,0,0,0,0,0,' nuclear power plant'); -INSERT INTO "technology" VALUES('T_BLND','p','transport','','',0,0,0,0,0,0,0,0,'ethanol - gasoline blending process'); -INSERT INTO "technology" VALUES('T_DSL','p','transport','','',0,0,0,0,0,0,0,0,'diesel vehicle'); -INSERT INTO "technology" VALUES('T_GSL','p','transport','','',0,0,0,0,0,0,0,0,'gasoline vehicle'); -INSERT INTO "technology" VALUES('T_EV','p','transport','','',0,0,0,0,0,0,0,0,'electric vehicle'); -INSERT INTO "technology" VALUES('R_EH','p','residential','','',0,0,0,0,0,0,0,0,' electric residential heating'); -INSERT INTO "technology" VALUES('R_NGH','p','residential','','',0,0,0,0,0,0,0,0,' natural gas residential heating'); -INSERT INTO "technology" VALUES('E_TRANS','p','electric','','',0,0,0,0,0,0,1,0,'electric transmission'); -CREATE TABLE technology_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "technology_type" VALUES('p','production technology'); -INSERT INTO "technology_type" VALUES('pb','baseload production technology'); -INSERT INTO "technology_type" VALUES('ps','storage production technology'); -CREATE TABLE time_of_day -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY, - hours REAL NOT NULL DEFAULT 1, - notes TEXT, - CHECK (hours > 0) -); -INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(1,'day',12); -INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(2,'night',12); -CREATE TABLE time_period -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES time_period_type (label) -); -INSERT INTO "time_period" VALUES(1,2015,'e'); -INSERT INTO "time_period" VALUES(2,2020,'f'); -INSERT INTO "time_period" VALUES(3,2025,'f'); -INSERT INTO "time_period" VALUES(4,2030,'f'); -INSERT INTO "time_period" VALUES(5,2035,'f'); -CREATE TABLE time_period_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "time_period_type" VALUES('e','existing vintages'); -INSERT INTO "time_period_type" VALUES('f','future'); -CREATE TABLE time_season -( - sequence INTEGER UNIQUE, - season TEXT, - segment_fraction REAL NOT NULL, - notes TEXT, - PRIMARY KEY (season), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); -INSERT INTO "time_season" VALUES(0,'spring',0.25,NULL); -INSERT INTO "time_season" VALUES(1,'summer',0.25,NULL); -INSERT INTO "time_season" VALUES(2,'fall',0.25,NULL); -INSERT INTO "time_season" VALUES(3,'winter',0.25,NULL); - -CREATE TABLE time_season_sequential -( - sequence INTEGER UNIQUE, - seas_seq TEXT, - season TEXT REFERENCES time_season(season), - segment_fraction REAL NOT NULL, - notes TEXT, - PRIMARY KEY (seas_seq), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); - -CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); -COMMIT; diff --git a/data_files/example_dbs/utopia.sql b/data_files/example_dbs/utopia.sql deleted file mode 100644 index 7fdf117c0..000000000 --- a/data_files/example_dbs/utopia.sql +++ /dev/null @@ -1,1439 +0,0 @@ -BEGIN TRANSACTION; -CREATE TABLE capacity_credit -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -CREATE TABLE capacity_factor_process -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -INSERT INTO "capacity_factor_process" VALUES('utopia','inter','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia','inter','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia','winter','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia','winter','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia','summer','day','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia','summer','night','E31',2000,0.2753,''); -INSERT INTO "capacity_factor_process" VALUES('utopia','inter','day','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia','inter','night','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia','winter','day','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia','winter','night','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia','summer','day','E31',2010,0.2756,''); -INSERT INTO "capacity_factor_process" VALUES('utopia','summer','night','E31',2010,0.2756,''); -CREATE TABLE capacity_factor_tech -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E01',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E21',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E31',0.275,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E51',0.17,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','inter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','winter','night','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','day','E70',0.8,''); -INSERT INTO "capacity_factor_tech" VALUES('utopia','summer','night','E70',0.8,''); -CREATE TABLE capacity_to_activity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "capacity_to_activity" VALUES('utopia','E01',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','E21',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','E31',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','E51',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','E70',31.54,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','RHE',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','RHO',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','RL1',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','SRE',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','TXD',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','TXE',1.0,''); -INSERT INTO "capacity_to_activity" VALUES('utopia','TXG',1.0,''); -CREATE TABLE commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES commodity_type (label), - description TEXT -); -INSERT INTO "commodity" VALUES('ethos','s','# dummy commodity to supply inputs (makes graph easier to read)'); -INSERT INTO "commodity" VALUES('DSL','p','# diesel'); -INSERT INTO "commodity" VALUES('ELC','p','# electricity'); -INSERT INTO "commodity" VALUES('FEQ','p','# fossil equivalent'); -INSERT INTO "commodity" VALUES('GSL','p','# gasoline'); -INSERT INTO "commodity" VALUES('HCO','p','# coal'); -INSERT INTO "commodity" VALUES('HYD','p','# water'); -INSERT INTO "commodity" VALUES('OIL','p','# crude oil'); -INSERT INTO "commodity" VALUES('URN','p','# uranium'); -INSERT INTO "commodity" VALUES('co2','e','#CO2 emissions'); -INSERT INTO "commodity" VALUES('nox','e','#NOX emissions'); -INSERT INTO "commodity" VALUES('RH','d','# residential heating'); -INSERT INTO "commodity" VALUES('RL','d','# residential lighting'); -INSERT INTO "commodity" VALUES('TX','d','# transportation'); -CREATE TABLE commodity_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "commodity_type" VALUES('w','waste commodity'); -INSERT INTO "commodity_type" VALUES('wa','waste annual commodity'); -INSERT INTO "commodity_type" VALUES('wp','waste physical commodity'); -INSERT INTO "commodity_type" VALUES('a','annual commodity'); -INSERT INTO "commodity_type" VALUES('s','source commodity'); -INSERT INTO "commodity_type" VALUES('p','physical commodity'); -INSERT INTO "commodity_type" VALUES('e','emissions commodity'); -INSERT INTO "commodity_type" VALUES('d','demand commodity'); -CREATE TABLE construction_input -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage) -); -CREATE TABLE cost_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT NOT NULL - REFERENCES commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE cost_fixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1960,40.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1970,40.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1980,40.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E01',1990,40.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',1970,70.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',1980,70.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',1990,70.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E01',2000,70.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',1980,100.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',1990,100.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',2000,100.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E01',2010,100.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E21',1990,500.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E21',1990,500.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E21',1990,500.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E21',2000,500.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E21',2000,500.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E21',2010,500.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E31',1980,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E31',1990,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E31',1980,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E31',1990,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E31',2000,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',1980,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',1990,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',2000,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E31',2010,75.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E51',1980,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E51',1990,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E51',1980,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E51',1990,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E51',2000,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',1980,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',1990,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',2000,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E51',2010,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1960,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1970,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1980,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'E70',1990,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',1970,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',1980,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',1990,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'E70',2000,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',1980,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',1990,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',2000,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'E70',2010,30.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'RHO',1970,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'RHO',1980,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'RHO',1990,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'RHO',1980,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'RHO',1990,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'RHO',2000,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'RHO',1990,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'RHO',2000,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'RHO',2010,1.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'RL1',1980,9.46,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'RL1',1990,9.46,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'RL1',2000,9.46,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'RL1',2010,9.46,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXD',1970,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXD',1980,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXD',1990,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXD',1980,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXD',1990,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXD',2000,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXD',2000,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXD',2010,52.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXE',1990,100.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXE',1990,90.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXE',2000,90.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXE',2000,80.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXE',2010,80.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXG',1970,48.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXG',1980,48.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',1990,'TXG',1990,48.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXG',1980,48.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXG',1990,48.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2000,'TXG',2000,48.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXG',2000,48.0,'',''); -INSERT INTO "cost_fixed" VALUES('utopia',2010,'TXG',2010,48.0,'',''); -CREATE TABLE cost_invest -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "cost_invest" VALUES('utopia','E01',1990,2000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E01',2000,1300.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E01',2010,1200.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E21',1990,5000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E21',2000,5000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E21',2010,5000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E31',1990,3000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E31',2000,3000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E31',2010,3000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E51',1990,900.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E51',2000,900.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E51',2010,900.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E70',1990,1000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E70',2000,1000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','E70',2010,1000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','RHE',1990,90.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','RHE',2000,90.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','RHE',2010,90.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','RHO',1990,100.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','RHO',2000,100.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','RHO',2010,100.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','SRE',1990,100.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','SRE',2000,100.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','SRE',2010,100.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXD',1990,1044.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXD',2000,1044.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXD',2010,1044.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXE',1990,2000.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXE',2000,1750.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXE',2010,1500.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXG',1990,1044.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXG',2000,1044.0,'',''); -INSERT INTO "cost_invest" VALUES('utopia','TXG',2010,1044.0,'',''); -CREATE TABLE cost_variable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPDSL1',1990,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPDSL1',1990,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPDSL1',1990,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPGSL1',1990,15.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPGSL1',1990,15.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPGSL1',1990,15.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPHCO1',1990,2.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPHCO1',1990,2.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPHCO1',1990,2.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPOIL1',1990,8.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPOIL1',1990,8.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPOIL1',1990,8.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'IMPURN1',1990,2.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'IMPURN1',1990,2.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'IMPURN1',1990,2.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1960,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1970,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1980,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E01',1990,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',1970,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',1980,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',1990,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E01',2000,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',1980,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',1990,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',2000,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E01',2010,0.3,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E21',1990,1.5,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E21',1990,1.5,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E21',1990,1.5,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E21',2000,1.5,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E21',2000,1.5,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E21',2010,1.5,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1960,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1970,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1980,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'E70',1990,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',1970,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',1980,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',1990,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'E70',2000,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',1980,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',1990,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',2000,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'E70',2010,0.4,'',''); -INSERT INTO "cost_variable" VALUES('utopia',1990,'SRE',1990,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'SRE',1990,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2000,'SRE',2000,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'SRE',1990,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'SRE',2000,10.0,'',''); -INSERT INTO "cost_variable" VALUES('utopia',2010,'SRE',2010,10.0,'',''); -CREATE TABLE demand -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - commodity TEXT - REFERENCES commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -INSERT INTO "demand" VALUES('utopia',1990,'RH',25.2,'',''); -INSERT INTO "demand" VALUES('utopia',2000,'RH',37.8,'',''); -INSERT INTO "demand" VALUES('utopia',2010,'RH',5.66999999999999957e+01,'',''); -INSERT INTO "demand" VALUES('utopia',1990,'RL',5.6,'',''); -INSERT INTO "demand" VALUES('utopia',2000,'RL',8.4,'',''); -INSERT INTO "demand" VALUES('utopia',2010,'RL',12.6,'',''); -INSERT INTO "demand" VALUES('utopia',1990,'TX',5.2,'',''); -INSERT INTO "demand" VALUES('utopia',2000,'TX',7.8,'',''); -INSERT INTO "demand" VALUES('utopia',2010,'TX',11.69,'',''); -CREATE TABLE demand_specific_distribution -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - demand_name TEXT - REFERENCES commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -INSERT INTO "demand_specific_distribution" VALUES('utopia','inter','day','RH',0.12,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia','inter','night','RH',0.06,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia','winter','day','RH',0.5467,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia','winter','night','RH',0.2733,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia','inter','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia','inter','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia','summer','day','RL',0.15,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia','summer','night','RL',0.05,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia','winter','day','RL',0.5,''); -INSERT INTO "demand_specific_distribution" VALUES('utopia','winter','night','RL',0.1,''); -CREATE TABLE efficiency -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -INSERT INTO "efficiency" VALUES('utopia','ethos','IMPDSL1',1990,'DSL',1.0,''); -INSERT INTO "efficiency" VALUES('utopia','ethos','IMPGSL1',1990,'GSL',1.0,''); -INSERT INTO "efficiency" VALUES('utopia','ethos','IMPHCO1',1990,'HCO',1.0,''); -INSERT INTO "efficiency" VALUES('utopia','ethos','IMPOIL1',1990,'OIL',1.0,''); -INSERT INTO "efficiency" VALUES('utopia','ethos','IMPURN1',1990,'URN',1.0,''); -INSERT INTO "efficiency" VALUES('utopia','ethos','IMPFEQ',1990,'FEQ',1.0,''); -INSERT INTO "efficiency" VALUES('utopia','ethos','IMPHYD',1990,'HYD',1.0,''); -INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1960,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1970,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1980,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HCO','E01',1990,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HCO','E01',2000,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HCO','E01',2010,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','FEQ','E21',1990,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','FEQ','E21',2000,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','FEQ','E21',2010,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','URN','E21',1990,'ELC',0.4,'# 1/2.5'); -INSERT INTO "efficiency" VALUES('utopia','URN','E21',2000,'ELC',0.4,'# 1/2.5'); -INSERT INTO "efficiency" VALUES('utopia','URN','E21',2010,'ELC',0.4,'# 1/2.5'); -INSERT INTO "efficiency" VALUES('utopia','HYD','E31',1980,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HYD','E31',1990,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HYD','E31',2000,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','HYD','E31',2010,'ELC',0.32,'# 1/3.125'); -INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1960,'ELC',0.294,'# 1/3.4'); -INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1970,'ELC',0.294,'# 1/3.4'); -INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1980,'ELC',0.294,'# 1/3.4'); -INSERT INTO "efficiency" VALUES('utopia','DSL','E70',1990,'ELC',0.294,'# 1/3.4'); -INSERT INTO "efficiency" VALUES('utopia','DSL','E70',2000,'ELC',0.294,'# 1/3.4'); -INSERT INTO "efficiency" VALUES('utopia','DSL','E70',2010,'ELC',0.294,'# 1/3.4'); -INSERT INTO "efficiency" VALUES('utopia','ELC','E51',1980,'ELC',0.72,'# 1/1.3889'); -INSERT INTO "efficiency" VALUES('utopia','ELC','E51',1990,'ELC',0.72,'# 1/1.3889'); -INSERT INTO "efficiency" VALUES('utopia','ELC','E51',2000,'ELC',0.72,'# 1/1.3889'); -INSERT INTO "efficiency" VALUES('utopia','ELC','E51',2010,'ELC',0.72,'# 1/1.3889'); -INSERT INTO "efficiency" VALUES('utopia','ELC','RHE',1990,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','RHE',2000,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','RHE',2010,'RH',1.0,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',1970,'RH',0.7,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',1980,'RH',0.7,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',1990,'RH',0.7,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',2000,'RH',0.7,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','RHO',2010,'RH',0.7,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',1980,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',1990,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',2000,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','RL1',2010,'RL',1.0,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',1990,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2000,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2010,'DSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',1990,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2000,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO "efficiency" VALUES('utopia','OIL','SRE',2010,'GSL',1.0,'# direct translation from PRC_INP2, PRC_OUT'); -INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',1970,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',1980,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',1990,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',2000,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','DSL','TXD',2010,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','TXE',1990,'TX',0.827,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','TXE',2000,'TX',0.827,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','ELC','TXE',2010,'TX',0.827,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',1970,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',1980,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',1990,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',2000,'TX',0.231,'# direct translation from DMD_EFF'); -INSERT INTO "efficiency" VALUES('utopia','GSL','TXG',2010,'TX',0.231,'# direct translation from DMD_EFF'); -CREATE TABLE efficiency_variable -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE emission_activity -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPDSL1',1990,'DSL',0.075,'',''); -INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPGSL1',1990,'GSL',0.075,'',''); -INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPHCO1',1990,'HCO',8.89999999999999819e-02,'',''); -INSERT INTO "emission_activity" VALUES('utopia','co2','ethos','IMPOIL1',1990,'OIL',0.075,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1970,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1980,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',1990,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',2000,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','DSL','TXD',2010,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1970,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1980,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',1990,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',2000,'TX',1.0,'',''); -INSERT INTO "emission_activity" VALUES('utopia','nox','GSL','TXG',2010,'TX',1.0,'',''); -CREATE TABLE emission_embodied -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE emission_end_of_life -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -CREATE TABLE existing_capacity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "existing_capacity" VALUES('utopia','E01',1960,0.175,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','E01',1970,0.175,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','E01',1980,0.15,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','E31',1980,0.1,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','E51',1980,0.5,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','E70',1960,0.05,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','E70',1970,0.05,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','E70',1980,0.2,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','RHO',1970,12.5,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','RHO',1980,12.5,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','RL1',1980,5.6,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','TXD',1970,0.4,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','TXD',1980,0.2,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','TXG',1970,3.1,'',''); -INSERT INTO "existing_capacity" VALUES('utopia','TXG',1980,1.5,'',''); -CREATE TABLE lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -INSERT INTO "lifetime_process" VALUES('utopia','RL1',1980,20.0,'#forexistingcap'); -INSERT INTO "lifetime_process" VALUES('utopia','TXD',1970,30.0,'#forexistingcap'); -INSERT INTO "lifetime_process" VALUES('utopia','TXD',1980,30.0,'#forexistingcap'); -INSERT INTO "lifetime_process" VALUES('utopia','TXG',1970,30.0,'#forexistingcap'); -INSERT INTO "lifetime_process" VALUES('utopia','TXG',1980,30.0,'#forexistingcap'); -CREATE TABLE lifetime_survival_curve -( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE lifetime_tech -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -INSERT INTO "lifetime_tech" VALUES('utopia','E01',40.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','E21',40.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','E31',100.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','E51',100.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','E70',40.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','RHE',30.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','RHO',30.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','RL1',10.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','SRE',50.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','TXD',15.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','TXE',15.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','TXG',15.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','IMPDSL1',1000.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','IMPGSL1',1000.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','IMPHCO1',1000.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','IMPOIL1',1000.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','IMPURN1',1000.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','IMPHYD',1000.0,''); -INSERT INTO "lifetime_tech" VALUES('utopia','IMPFEQ',1000.0,''); -CREATE TABLE limit_activity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE limit_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -INSERT INTO "limit_capacity" VALUES('utopia',1990,'E31','ge',0.13,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',2000,'E31','ge',0.13,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',2010,'E31','ge',0.13,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',1990,'SRE','ge',0.1,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',1990,'E31','le',0.13,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',2000,'E31','le',0.17,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',2010,'E31','le',2.1000000000000002e-01,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',1990,'RHE','le',0.0,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',1990,'TXD','le',0.6,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',2000,'TXD','le',1.76,'',''); -INSERT INTO "limit_capacity" VALUES('utopia',2010,'TXD','le',4.76,'',''); -CREATE TABLE limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_degrowth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_degrowth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE limit_growth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_growth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - season TEXT - REFERENCES time_season (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, season, tech, operator) -); -CREATE TABLE limit_storage_level_fraction -( - region TEXT, - season TEXT, - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - fraction REAL, - notes TEXT, - CHECK (fraction >= 0 AND fraction <= 1), - PRIMARY KEY(region, season, tod, tech, operator) -); -CREATE TABLE limit_tech_input_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_input_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE limit_tech_output_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -INSERT INTO "limit_tech_output_split" VALUES('utopia',1990,'SRE','DSL','ge',0.7,''); -INSERT INTO "limit_tech_output_split" VALUES('utopia',2000,'SRE','DSL','ge',0.7,''); -INSERT INTO "limit_tech_output_split" VALUES('utopia',2010,'SRE','DSL','ge',0.7,''); -INSERT INTO "limit_tech_output_split" VALUES('utopia',1990,'SRE','GSL','ge',0.3,''); -INSERT INTO "limit_tech_output_split" VALUES('utopia',2000,'SRE','GSL','ge',0.3,''); -INSERT INTO "limit_tech_output_split" VALUES('utopia',2010,'SRE','GSL','ge',0.3,''); -CREATE TABLE limit_tech_output_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE linked_tech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES technology (tech), - emis_comm TEXT - REFERENCES commodity (name), - driven_tech TEXT - REFERENCES technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -CREATE TABLE loan_lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE loan_rate -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -INSERT INTO "metadata" VALUES('DB_MAJOR',4,''); -INSERT INTO "metadata" VALUES('DB_MINOR',0,''); -CREATE TABLE metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -INSERT INTO "metadata_real" VALUES('default_loan_rate',0.05,'Default Loan Rate if not specified in loan_rate table'); -INSERT INTO "metadata_real" VALUES('global_discount_rate',0.05,''); -CREATE TABLE myopic_efficiency -( - base_year integer, - region text, - input_comm text, - tech text, - vintage integer, - output_comm text, - efficiency real, - lifetime integer, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (region, input_comm, tech, vintage, output_comm) -); -CREATE TABLE operator -( - operator TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "operator" VALUES('e','equal to'); -INSERT INTO "operator" VALUES('le','less than or equal to'); -INSERT INTO "operator" VALUES('ge','greater than or equal to'); -CREATE TABLE output_built_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES sector_label (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) -); -CREATE TABLE output_curtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE output_emission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE output_flow_in -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_flow_out_summary -( - scenario TEXT NOT NULL, - region TEXT NOT NULL, - sector TEXT, - period INTEGER, - input_comm TEXT NOT NULL, - tech TEXT NOT NULL, - vintage INTEGER, - output_comm TEXT NOT NULL, - flow REAL NOT NULL, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) -); -CREATE TABLE output_net_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_objective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE output_retired_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE output_storage_level -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT, - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE planning_reserve_margin -( - region TEXT - PRIMARY KEY - REFERENCES region (region), - margin REAL, - notes TEXT -); -CREATE TABLE ramp_down_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE ramp_up_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -INSERT INTO "region" VALUES('utopia',NULL); -CREATE TABLE reserve_capacity_derate -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE rps_requirement -( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL - REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES tech_group (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE sector_label -( - sector TEXT PRIMARY KEY, - notes TEXT -); -INSERT INTO "sector_label" VALUES('supply',NULL); -INSERT INTO "sector_label" VALUES('electric',NULL); -INSERT INTO "sector_label" VALUES('transport',NULL); -INSERT INTO "sector_label" VALUES('commercial',NULL); -INSERT INTO "sector_label" VALUES('residential',NULL); -INSERT INTO "sector_label" VALUES('industrial',NULL); -CREATE TABLE storage_duration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE tech_group -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE tech_group_member -( - group_name TEXT - REFERENCES tech_group (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technology_type (label) -); -INSERT INTO "technology" VALUES('IMPDSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported diesel'); -INSERT INTO "technology" VALUES('IMPGSL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported gasoline'); -INSERT INTO "technology" VALUES('IMPHCO1','p','supply','coal','',1,0,0,0,0,0,0,0,' imported coal'); -INSERT INTO "technology" VALUES('IMPOIL1','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported crude oil'); -INSERT INTO "technology" VALUES('IMPURN1','p','supply','nuclear','',1,0,0,0,0,0,0,0,' imported uranium'); -INSERT INTO "technology" VALUES('IMPFEQ','p','supply','petroleum','',1,0,0,0,0,0,0,0,' imported fossil equivalent'); -INSERT INTO "technology" VALUES('IMPHYD','p','supply','hydro','',1,0,0,0,0,0,0,0,' imported water -- doesnt exist in Utopia'); -INSERT INTO "technology" VALUES('E01','pb','electric','coal','',0,0,0,0,0,0,0,0,' coal power plant'); -INSERT INTO "technology" VALUES('E21','pb','electric','nuclear','',0,0,0,0,0,0,0,0,' nuclear power plant'); -INSERT INTO "technology" VALUES('E31','pb','electric','hydro','',0,0,0,0,0,0,0,0,' hydro power'); -INSERT INTO "technology" VALUES('E51','ps','electric','electric','',0,0,0,0,0,0,0,0,' electric storage'); -INSERT INTO "technology" VALUES('E70','p','electric','petroleum','',0,0,0,0,0,0,0,0,' diesel power plant'); -INSERT INTO "technology" VALUES('RHE','p','residential','electric','',0,0,0,0,0,0,0,0,' electric residential heating'); -INSERT INTO "technology" VALUES('RHO','p','residential','petroleum','',0,0,0,0,0,0,0,0,' diesel residential heating'); -INSERT INTO "technology" VALUES('RL1','p','residential','electric','',0,0,0,0,0,0,0,0,' residential lighting'); -INSERT INTO "technology" VALUES('SRE','p','supply','petroleum','',0,0,0,0,0,0,0,0,' crude oil processor'); -INSERT INTO "technology" VALUES('TXD','p','transport','petroleum','',0,0,0,0,0,0,0,0,' diesel powered vehicles'); -INSERT INTO "technology" VALUES('TXE','p','transport','electric','',0,0,0,0,0,0,0,0,' electric powered vehicles'); -INSERT INTO "technology" VALUES('TXG','p','transport','petroleum','',0,0,0,0,0,0,0,0,' gasoline powered vehicles'); -CREATE TABLE technology_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "technology_type" VALUES('p','production technology'); -INSERT INTO "technology_type" VALUES('pb','baseload production technology'); -INSERT INTO "technology_type" VALUES('ps','storage production technology'); -CREATE TABLE time_of_day -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY, - hours REAL NOT NULL DEFAULT 1, - notes TEXT, - CHECK (hours > 0) -); -INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(1,'day',16); -INSERT INTO "time_of_day" (sequence, tod, hours) VALUES(2,'night',8); -CREATE TABLE time_period -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES time_period_type (label) -); -INSERT INTO "time_period" VALUES(1,1960,'e'); -INSERT INTO "time_period" VALUES(2,1970,'e'); -INSERT INTO "time_period" VALUES(3,1980,'e'); -INSERT INTO "time_period" VALUES(4,1990,'f'); -INSERT INTO "time_period" VALUES(5,2000,'f'); -INSERT INTO "time_period" VALUES(6,2010,'f'); -INSERT INTO "time_period" VALUES(7,2020,'f'); -CREATE TABLE time_period_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -INSERT INTO "time_period_type" VALUES('e','existing vintages'); -INSERT INTO "time_period_type" VALUES('f','future'); -CREATE TABLE time_season -( - sequence INTEGER UNIQUE, - season TEXT, - segment_fraction REAL NOT NULL, - notes TEXT, - PRIMARY KEY (season), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); -INSERT INTO "time_season" VALUES(0,'inter',0.25,NULL); -INSERT INTO "time_season" VALUES(1,'summer',0.25,NULL); -INSERT INTO "time_season" VALUES(2,'winter',0.5,NULL); - -CREATE TABLE time_season_sequential -( - sequence INTEGER UNIQUE, - seas_seq TEXT, - season TEXT REFERENCES time_season(season), - segment_fraction REAL NOT NULL, - notes TEXT, - PRIMARY KEY (seas_seq), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); - -CREATE INDEX region_tech_vintage ON myopic_efficiency (region, tech, vintage); -COMMIT; diff --git a/data_files/monte_carlo/run_settings_1.csv b/data_files/monte_carlo/run_settings_1.csv deleted file mode 100644 index 4b785e061..000000000 --- a/data_files/monte_carlo/run_settings_1.csv +++ /dev/null @@ -1,5 +0,0 @@ -run,param,index,mod,value,notes -1,MaxCapacity,utopia|2010|TXD,a,-1.0,reduce the max capacity of TXD in region Utopia in period 2010 by 1.0 units (absolute) -2,Demand,utopia|*|RH,r,0.5,make Res Heat costlier by 50% in all 3 periods -2,cost_variable,*|1990/2000|IMPOIL1|*,s,20.0,substitute cost of 20.0 for var cost of IMPOIL in periods 1990/2000 in all regions (just utopia exists) for all vintages -3,cost_variable,china|1990|IMPOIL1|*,s,1000,bad input: unknown region (china) should fail and be logged diff --git a/data_files/my_configs/.gitignore b/data_files/my_configs/.gitignore deleted file mode 100644 index d806ef659..000000000 --- a/data_files/my_configs/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# this will auto-ignore any new .toml config files. It is always possible to override this with a Git ADD -*.toml diff --git a/data_files/my_configs/config_sample.toml b/data_files/my_configs/config_sample.toml deleted file mode 100644 index 3ba00adbf..000000000 --- a/data_files/my_configs/config_sample.toml +++ /dev/null @@ -1,165 +0,0 @@ -# ---------------------------------------------------------- -# Configuration file for a Temoa Run -# Allows specification of run type and associated parameters -# ---------------------------------------------------------- -# -# For toml format info see: https://toml.io/en/ -# - comments may be added with hash -# - do NOT comment out table names in brackets like: [
] - -# Scenario Name (Mandatory) -# This scenario name is used to label results within the output .sqlite file -# (cannot contain "-" dash) -scenario = "zulu" - -# Scenaio Mode (Mandatory) -# See documentation for explanations. A standard single run is "perfect_foresight" -# mode must be one of (case-insensitive): -# [perfect_foresight, MGA, myopic, method_of_morris, build_only, check, monte_carlo] -scenario_mode = "perfect_foresight" - -# Input database (Mandatory) -input_database = "data_files/example_dbs/utopia.sqlite" - -# Output file (Mandatory) -# The output file must be an existing .sqlite file -# For Pefrect Foresight, the user may target the same input file or a separate / -# copied sqlite file in a different location. Myopic, MGA require that input_database = output_database -output_database = "data_files/example_dbs/utopia.sqlite" - -# ------------------------------------ -# DATA / MODEL CHECKS -# To check data / cost integrity -# ------------------------------------ - -# See the documentation section on Data Quality for notes on the features below - -# Check the pricing structure for common errors, which are reported in the log file -# Strongly recommended -price_check = true - -# Check the network connectivity for processes in the model. Strongly -# recommended to ensure proper performance. Results are reported in log file -# This requires that source commodities be marked with 's' in Commodity table -# This is required for Myopic runs -source_trace = true - -# Produce HTML files for Commodity Networks. Requires source_trace above -plot_commodity_network = true - -# Check units consistency in the database -# Validates that units are properly formatted and consistent across related tables -# Recommended for production runs after units are populated in the database -check_units = false - -# ------------------------------------ -# SOLVER -# Solver Selection -# ------------------------------------ - -# use the NEOS server to solve. (Currently NOT supported) -neos = false - -# solver (Mandatory) -# Depending on what client machine has installed. -# [cbc, appsi_highs, gurobi, cplex, ...] -solver_name = "appsi_highs" - -# ------------------------------------ -# OUTPUTS -# select desired output products/files -# ------------------------------------ - -# generate an Excel file in the output_files folder -save_excel = true - -# save the duals in the output Database (may slow execution slightly?) -save_duals = true - -# save storage levels by time slice (may be a large amount of data) -save_storage_levels = true - -# save a copy of the pyomo-generated lp file(s) to the outputs folder (maybe a large file(s)!) -save_lp_file = false - -# ------------------------------------ -# MODEL PARAMETERS -# these are specific to each model -# ------------------------------------ - -# What seasons represent in the model -# Options: -# 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples -# might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. -# 'representative_periods' -# Each season represents a number of days, though not necessarily in any particular order. -# If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in -# the Technology table. -# 'seasonal_timeslices' -# Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out -# in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the TimeSeasonSequential table filled. -time_sequencing = 'seasonal_timeslices' - -# Number of days represented by each planning period. -# Used to adjust flow variables for number of days represented by each season. -# E.g. 365 if all seasons collectively represent a year, 7 if modelling a single representative week. -days_per_period = 365 - -# How contributions to the planning reserve margin are calculated -# Options: -# 'static' -# Traditional planning reserve formulation. Contributions are independent of hourly availability: -# capacity value = net capacity * capacity credit -# 'dynamic' -# Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = net capacity * reserve capacity derate * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * reserve capacity derate -reserve_margin = 'dynamic' - -# --------------------------------------------------- -# MODE OPTIONS -# options below are mode-specific and will be ignored -# if the run is not executed in that mode. -# --------------------------------------------------- -[MGA] -# see notes on these in the extensions/modeling_to_generate_alternatives folder readme.txt -cost_epsilon = 0.03 # propotional relaxation on optimal cost (ex: 0.05 = bound at 105% of original optimal cost) -iteration_limit = 55 # max iterations to perform -time_limit_hrs = 1 # max time -axis = "tech_category_activity" # use the tech activity Manager to control exploration based on categories in Tech -weighting = "hull_expansion" # use a convex hull expansion algorithm to weight exploration - -[myopic] -view_depth = 2 # number of periods seen/analyzed per iteration -step_size = 1 # number of periods to step by (must be <= view depth) - -[morris] -perturbation = 0.10 # amount to perturb marked parameters (ex: 0.10 -> +/- 10%) -levels = 8 # number of levels in param grid (must be even number) -trajectories = 10 # number of Morris trajectories to generate/explore -seed = false # random seed for use in generation/analysis for repeatable results. false=system derived -cores = 0 # number of CPU cores to use. 0 (default) = cpu count -# Note: Problem size (in general) is (Groups + 1) * trajectories see the SALib Dox -# Groups = number of unique labels used in MM analysis columns in DB - -[SVMGA] -cost_epsilon = 0.05 -# labels from appropriate tables in database. It is recommended to only use one of the lists below and leave -# the others blank -emission_labels = ['co2', 'nox'] -capacity_labels = ['TXD', 'TXG'] -activity_labels = [] - -[monte_carlo] -# a path from the PROJECT ROOT to the settings file that contains the run data. -run_settings = 'data_files/monte_carlo/run_settings_1.csv' diff --git a/data_files/my_configs/materials.toml b/data_files/my_configs/materials.toml deleted file mode 100644 index a925429e8..000000000 --- a/data_files/my_configs/materials.toml +++ /dev/null @@ -1,161 +0,0 @@ -# ---------------------------------------------------------- -# Configuration file for a Temoa Run -# Allows specification of run type and associated parameters -# ---------------------------------------------------------- -# -# For toml format info see: https://toml.io/en/ -# - comments may be added with hash -# - do NOT comment out table names in brackets like: [
] - -# Scenario Name (Mandatory) -# This scenario name is used to label results within the output .sqlite file -# (cannot contain "-" dash) -scenario = "zulu" - -# Scenaio Mode (Mandatory) -# See documentation for explanations. A standard single run is "perfect_foresight" -# mode must be one of (case-insensitive): -# [perfect_foresight, MGA, myopic, method_of_morris, build_only, check, monte_carlo] -scenario_mode = "perfect_foresight" - -# Input database (Mandatory) -input_database = "data_files/example_dbs/materials.sqlite" - -# Output file (Mandatory) -# The output file must be an existing .sqlite file -# For Pefrect Foresight, the user may target the same input file or a separate / -# copied sqlite file in a different location. Myopic, MGA require that input_database = output_database -output_database = "data_files/example_dbs/materials.sqlite" - -# ------------------------------------ -# DATA / MODEL CHECKS -# To check data / cost integrity -# ------------------------------------ - -# See the documentation section on Data Quality for notes on the features below - -# Check the pricing structure for common errors, which are reported in the log file -# Strongly recommended -price_check = true - -# Check the network connectivity for processes in the model. Strongly -# recommended to ensure proper performance. Results are reported in log file -# This requires that source commodities be marked with 's' in Commodity table -# This is required for Myopic runs -source_trace = true - -# Produce HTML files for Commodity Networks. Requires source_trace above -plot_commodity_network = true - -# ------------------------------------ -# SOLVER -# Solver Selection -# ------------------------------------ - -# use the NEOS server to solve. (Currently NOT supported) -neos = false - -# solver (Mandatory) -# Depending on what client machine has installed. -# [cbc, appsi_highs, gurobi, cplex, ...] -solver_name = "cbc" - -# ------------------------------------ -# OUTPUTS -# select desired output products/files -# ------------------------------------ - -# generate an Excel file in the output_files folder -save_excel = true - -# save the duals in the output Database (may slow execution slightly?) -save_duals = true - -# save storage levels by time slice (may be a large amount of data) -save_storage_levels = true - -# save a copy of the pyomo-generated lp file(s) to the outputs folder (maybe a large file(s)!) -save_lp_file = false - -# ------------------------------------ -# MODEL PARAMETERS -# these are specific to each model -# ------------------------------------ - -# What seasons represent in the model -# Options: -# 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples -# might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. -# 'representative_periods' -# Each season represents a number of days, though not necessarily in any particular order. -# If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in -# the Technology table. -# 'seasonal_timeslices' -# Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out -# in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the TimeSeasonSequential table filled. -time_sequencing = 'seasonal_timeslices' - -# Number of days represented by each planning period. -# Used to adjust flow variables for number of days represented by each season. -# E.g. 365 if all seasons collectively represent a year, 7 if modelling a single representative week. -days_per_period = 365 - -# How contributions to the planning reserve margin are calculated -# Options: -# 'static' -# Traditional planning reserve formulation. Contributions are independent of hourly availability: -# capacity value = net capacity * capacity credit -# 'dynamic' -# Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = net capacity * reserve capacity derate * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * reserve capacity derate -reserve_margin = 'static' - -# --------------------------------------------------- -# MODE OPTIONS -# options below are mode-specific and will be ignored -# if the run is not executed in that mode. -# --------------------------------------------------- -[MGA] -# see notes on these in the extensions/modeling_to_generate_alternatives folder readme.txt -cost_epsilon = 0.03 # propotional relaxation on optimal cost (ex: 0.05 = bound at 105% of original optimal cost) -iteration_limit = 55 # max iterations to perform -time_limit_hrs = 1 # max time -axis = "tech_category_activity" # use the tech activity Manager to control exploration based on categories in Tech -weighting = "hull_expansion" # use a convex hull expansion algorithm to weight exploration - -[myopic] -view_depth = 2 # number of periods seen/analyzed per iteration -step_size = 1 # number of periods to step by (must be <= view depth) - -[morris] -perturbation = 0.10 # amount to perturb marked parameters (ex: 0.10 -> +/- 10%) -levels = 8 # number of levels in param grid (must be even number) -trajectories = 10 # number of Morris trajectories to generate/explore -seed = false # random seed for use in generation/analysis for repeatable results. false=system derived -cores = 0 # number of CPU cores to use. 0 (default) = cpu count -# Note: Problem size (in general) is (Groups + 1) * trajectories see the SALib Dox -# Groups = number of unique labels used in MM analysis columns in DB - -[SVMGA] -cost_epsilon = 0.05 -# labels from appropriate tables in database. It is recommended to only use one of the lists below and leave -# the others blank -emission_labels = ['co2', 'nox'] -capacity_labels = ['TXD', 'TXG'] -activity_labels = [] - -[monte_carlo] -# a path from the PROJECT ROOT to the settings file that contains the run data. -run_settings = 'data_files/monte_carlo/run_settings_1.csv' - diff --git a/data_files/my_configs/mga_utopia.toml b/data_files/my_configs/mga_utopia.toml deleted file mode 100644 index 17529830c..000000000 --- a/data_files/my_configs/mga_utopia.toml +++ /dev/null @@ -1,138 +0,0 @@ -# ---------------------------------------------------------- -# Configuration file for a Temoa Run -# Allows specification of run type and associated parameters -# ---------------------------------------------------------- -# -# For toml format info see: https://toml.io/en/ -# - comments may be added with hash -# - do NOT comment out table names in brackets like: [
] - -# Scenario Name (Mandatory) -# This scenario name is used to label results within the output .sqlite file -scenario = "sierra" - -# Scenaio Mode (Mandatory) -# See documentation for explanations. A standard single run is "perfect_foresight" -# mode must be one of (case-insensitive): -# [perfect_foresight, MGA, myopic, method_of_morris, build_only, check] -scenario_mode = "mga" - -# Input database (Mandatory) -input_database = "data_files/example_dbs/utopia.sqlite" - -# Output file (Mandatory) -# The output file must be an existing .sqlite file -# For Pefrect Foresight, the user may target the same input file or a separate / -# copied sqlite file in a different location. Myopic requires that input_database = output_database -output_database = "data_files/example_dbs/utopia.sqlite" - -# ------------------------------------ -# DATA / MODEL CHECKS -# To check data / cost integrity -# ------------------------------------ - -# Check the pricing structure for common errors, which are reported in the log file -# Strongly recommended -price_check = true - -# Check the network connectivity for processes in the model. Strongly -# recommended to ensure proper performance. Results are reported in log file -# This requires that source commodities be marked with 's' in Commodity table -# This is required for Myopic runs -source_trace = true - -# Produce HTML files for Commodity Networks. Requires source_trace above -plot_commodity_network = true - -# ------------------------------------ -# SOLVER -# Solver Selection -# ------------------------------------ - -# use the NEOS server to solve. (Currently NOT supported) -neos = false - -# solver (Mandatory) -# Depending on what client machine has installed. -# [cbc, appsi_highs, gurobi, cplex, ...] -solver_name = "cbc" - -# ------------------------------------ -# OUTPUTS -# select desired output products/files -# ------------------------------------ - -# generate an Excel file in the output_files folder -save_excel = false - -# save the duals in the output Database (may slow execution slightly?) -save_duals = false - -# save a copy of the pyomo-generated lp file(s) to the outputs folder (maybe a large file(s)!) -save_lp_file = false - -# ------------------------------------ -# MODEL PARAMETERS -# these are specific to each model -# ------------------------------------ - -# What seasons represent in the model -# Options: -# 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples -# might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. -# 'representative_periods' -# Each season represents a number of days, though not necessarily in any particular order. -# If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in -# the Technology table. -# 'seasonal_timeslices' -# Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out -# in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the TimeSeasonSequential table filled. -time_sequencing = 'seasonal_timeslices' - -# Number of days represented by each planning period. -# Used to adjust flow variables for number of days represented by each season. -# E.g. 365 if all seasons collectively represent a year, 7 if modelling a single representative week. -days_per_period = 365 - -# How contributions to the planning reserve margin are calculated -# Options: -# 'static' -# Traditional planning reserve formulation. Contributions are independent of hourly availability: -# capacity value = net capacity * capacity credit -# 'dynamic' -# Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = net capacity * reserve capacity derate * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * reserve capacity derate -reserve_margin = 'static' - -# --------------------------------------------------- -# MODE OPTIONS -# options below are mode-specific and will be ignored -# if the run is not executed in that mode. -# --------------------------------------------------- -[MGA] -# see notes on these in the extensions/modeling_to_generate_alternatives folder readme.txt -cost_epsilon = 0.03 # propotional relaxation on optimal cost (ex: 0.05 = bound at 105% of original optimal cost) -iteration_limit = 20 # max iterations to perform -time_limit_hrs = 1 # max time -axis = "tech_category_activity" # use the tech activity Manager to control exploration based on categories in Tech -weighting = "hull_expansion" # use a convex hull expansion algorithm to weight exploration - - -[myopic] -view_depth = 2 # number of periods seen/analyzed per iteration -step_size = 1 # number of periods to step by (must be <= view depth) - - - - diff --git a/data_files/my_configs/monte_carlo_utopia.toml b/data_files/my_configs/monte_carlo_utopia.toml deleted file mode 100644 index e26032928..000000000 --- a/data_files/my_configs/monte_carlo_utopia.toml +++ /dev/null @@ -1,158 +0,0 @@ -# ---------------------------------------------------------- -# Configuration file for a Temoa Run -# Allows specification of run type and associated parameters -# ---------------------------------------------------------- -# -# For toml format info see: https://toml.io/en/ -# - comments may be added with hash -# - do NOT comment out table names in brackets like: [
] - -# Scenario Name (Mandatory) -# This scenario name is used to label results within the output .sqlite file -# (cannot contain "-" dash) -scenario = "Orange Squirrel" - -# Scenaio Mode (Mandatory) -# See documentation for explanations. A standard single run is "perfect_foresight" -# mode must be one of (case-insensitive): -# [perfect_foresight, MGA, myopic, method_of_morris, build_only, check, monte_carlo] -scenario_mode = "monte_carlo" - -# Input database (Mandatory) -input_database = "data_files/example_dbs/utopia.sqlite" - -# Output file (Mandatory) -# The output file must be an existing .sqlite file -# For Pefrect Foresight, the user may target the same input file or a separate / -# copied sqlite file in a different location. Myopic, MGA require that input_database = output_database -output_database = "data_files/example_dbs/utopia.sqlite" - -# ------------------------------------ -# DATA / MODEL CHECKS -# To check data / cost integrity -# ------------------------------------ - -# See the documentation section on Data Quality for notes on the features below - -# Check the pricing structure for common errors, which are reported in the log file -# Strongly recommended -price_check = true - -# Check the network connectivity for processes in the model. Strongly -# recommended to ensure proper performance. Results are reported in log file -# This requires that source commodities be marked with 's' in Commodity table -# This is required for Myopic runs -source_trace = true - -# Produce HTML files for Commodity Networks. Requires source_trace above -plot_commodity_network = true - -# ------------------------------------ -# SOLVER -# Solver Selection -# ------------------------------------ - -# use the NEOS server to solve. (Currently NOT supported) -neos = false - -# solver (Mandatory) -# Depending on what client machine has installed. -# [cbc, appsi_highs, gurobi, cplex, ...] -solver_name = "cbc" - -# ------------------------------------ -# OUTPUTS -# select desired output products/files -# ------------------------------------ - -# generate an Excel file in the output_files folder -save_excel = true - -# save the duals in the output Database (may slow execution slightly?) -save_duals = true - -# save a copy of the pyomo-generated lp file(s) to the outputs folder (maybe a large file(s)!) -save_lp_file = false - -# ------------------------------------ -# MODEL PARAMETERS -# these are specific to each model -# ------------------------------------ - -# What seasons represent in the model -# Options: -# 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples -# might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. -# 'representative_periods' -# Each season represents a number of days, though not necessarily in any particular order. -# If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in -# the Technology table. -# 'seasonal_timeslices' -# Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out -# in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the TimeSeasonSequential table filled. -time_sequencing = 'seasonal_timeslices' - -# Number of days represented by each planning period. -# Used to adjust flow variables for number of days represented by each season. -# E.g. 365 if all seasons collectively represent a year, 7 if modelling a single representative week. -days_per_period = 365 - -# How contributions to the planning reserve margin are calculated -# Options: -# 'static' -# Traditional planning reserve formulation. Contributions are independent of hourly availability: -# capacity value = net capacity * capacity credit -# 'dynamic' -# Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = net capacity * reserve capacity derate * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * reserve capacity derate -reserve_margin = 'static' - -# --------------------------------------------------- -# MODE OPTIONS -# options below are mode-specific and will be ignored -# if the run is not executed in that mode. -# --------------------------------------------------- -[MGA] -# see notes on these in the extensions/modeling_to_generate_alternatives folder readme.txt -cost_epsilon = 0.03 # propotional relaxation on optimal cost (ex: 0.05 = bound at 105% of original optimal cost) -iteration_limit = 55 # max iterations to perform -time_limit_hrs = 1 # max time -axis = "tech_category_activity" # use the tech activity Manager to control exploration based on categories in Tech -weighting = "hull_expansion" # use a convex hull expansion algorithm to weight exploration - -[myopic] -view_depth = 2 # number of periods seen/analyzed per iteration -step_size = 1 # number of periods to step by (must be <= view depth) - -[morris] -perturbation = 0.10 # amount to perturb marked parameters (ex: 0.10 -> +/- 10%) -levels = 8 # number of levels in param grid (must be even number) -trajectories = 10 # number of Morris trajectories to generate/explore -seed = false # random seed for use in generation/analysis for repeatable results. false=system derived -cores = 0 # number of CPU cores to use. 0 (default) = cpu count -# Note: Problem size (in general) is (Groups + 1) * trajectories see the SALib Dox -# Groups = number of unique labels used in MM analysis columns in DB - -[SVMGA] -cost_epsilon = 0.05 -# labels from appropriate tables in database. It is recommended to only use one of the lists below and leave -# the others blank -emission_labels = ['co2', 'nox'] -capacity_labels = ['TXD', 'TXG'] -activity_labels = [] - -[monte_carlo] -# a path from the PROJECT ROOT to the settings file that contains the run data. -run_settings = 'data_files/monte_carlo/run_settings_1.csv' - diff --git a/data_files/my_configs/morris_utopia.toml b/data_files/my_configs/morris_utopia.toml deleted file mode 100644 index f71182853..000000000 --- a/data_files/my_configs/morris_utopia.toml +++ /dev/null @@ -1,142 +0,0 @@ -# ---------------------------------------------------------- -# Configuration file for a Temoa Run -# Allows specification of run type and associated parameters -# ---------------------------------------------------------- -# -# For toml format info see: https://toml.io/en/ -# - comments may be added with hash -# - do NOT comment out table names in brackets like: [
] - -# Scenario Name (Mandatory) -# This scenario name is used to label results within the output .sqlite file -scenario = "chili" - -# Scenaio Mode (Mandatory) -# See documentation for explanations. A standard single run is "perfect_foresight" -# mode must be one of (case-insensitive): -# [perfect_foresight, MGA, myopic, method_of_morris, build_only, check] -scenario_mode = "method_of_morris" - -# Input database (Mandatory) -input_database = "data_files/example_dbs/morris_utopia.sqlite" - -# Output file (Mandatory) -# The output file must be an existing .sqlite file -# For Pefrect Foresight, the user may target the same input file or a separate / -# copied sqlite file in a different location. Myopic requires that input_database = output_database -output_database = "data_files/example_dbs/morris_utopia.sqlite" - -# ------------------------------------ -# DATA / MODEL CHECKS -# To check data / cost integrity -# ------------------------------------ - -# Check the pricing structure for common errors, which are reported in the log file -# Strongly recommended -price_check = true - -# Check the network connectivity for processes in the model. Strongly -# recommended to ensure proper performance. Results are reported in log file -# This requires that source commodities be marked with 's' in Commodity table -# This is required for Myopic runs -source_trace = true - -# Produce HTML files for Commodity Networks. Requires source_trace above -plot_commodity_network = false - -# ------------------------------------ -# SOLVER -# Solver Selection -# ------------------------------------ - -# use the NEOS server to solve. (Currently NOT supported) -neos = false - -# solver (Mandatory) -# Depending on what client machine has installed. -# [cbc, appsi_highs, gurobi, cplex, ...] -solver_name = "cbc" - -# ------------------------------------ -# OUTPUTS -# select desired output products/files -# ------------------------------------ - -# generate an Excel file in the output_files folder -save_excel = false - -# save the duals in the output Database (may slow execution slightly?) -save_duals = false - -# save a copy of the pyomo-generated lp file(s) to the outputs folder (maybe a large file(s)!) -save_lp_file = false - -# ------------------------------------ -# MODEL PARAMETERS -# these are specific to each model -# ------------------------------------ - -# What seasons represent in the model -# Options: -# 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples -# might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. -# 'representative_periods' -# Each season represents a number of days, though not necessarily in any particular order. -# If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in -# the Technology table. -# 'seasonal_timeslices' -# Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out -# in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the TimeSeasonSequential table filled. -time_sequencing = 'seasonal_timeslices' - -# Number of days represented by each planning period. -# Used to adjust flow variables for number of days represented by each season. -# E.g. 365 if all seasons collectively represent a year, 7 if modelling a single representative week. -days_per_period = 365 - -# How contributions to the planning reserve margin are calculated -# Options: -# 'static' -# Traditional planning reserve formulation. Contributions are independent of hourly availability: -# capacity value = net capacity * capacity credit -# 'dynamic' -# Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = net capacity * reserve capacity derate * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * reserve capacity derate -reserve_margin = 'static' - -# --------------------------------------------------- -# MODE OPTIONS -# options below are mode-specific and will be ignored -# if the run is not executed in that mode. -# --------------------------------------------------- -[MGA] - - - -[myopic] -view_depth = 2 # number of periods seen/analyzed per iteration -step_size = 1 # number of periods to step by (must be <= view depth) - -[morris] -perturbation = 0.10 # amount to perturb marked parameters (ex: 0.10 -> +/- 10%) -levels = 8 # number of levels in param grid (must be even number) -trajectories = 10 # number of Morris trajectories to generate/explore -seed = false # random seed for use in generation/analysis for repeatable results. false=system derived -cores = 0 # number of CPU cores to use. 0 (default) = cpu count -# Note: Problem size (in general) is (Groups + 1) * trajectories see the SALib Dox -# Groups = number of unique labels used in MM analysis columns in DB - - - - diff --git a/data_files/my_configs/seasonal_storage.toml b/data_files/my_configs/seasonal_storage.toml deleted file mode 100644 index d7208626a..000000000 --- a/data_files/my_configs/seasonal_storage.toml +++ /dev/null @@ -1,161 +0,0 @@ -# ---------------------------------------------------------- -# Configuration file for a Temoa Run -# Allows specification of run type and associated parameters -# ---------------------------------------------------------- -# -# For toml format info see: https://toml.io/en/ -# - comments may be added with hash -# - do NOT comment out table names in brackets like: [
] - -# Scenario Name (Mandatory) -# This scenario name is used to label results within the output .sqlite file -# (cannot contain "-" dash) -scenario = "zulu" - -# Scenaio Mode (Mandatory) -# See documentation for explanations. A standard single run is "perfect_foresight" -# mode must be one of (case-insensitive): -# [perfect_foresight, MGA, myopic, method_of_morris, build_only, check, monte_carlo] -scenario_mode = "perfect_foresight" - -# Input database (Mandatory) -input_database = "data_files/example_dbs/seasonal_storage.sqlite" - -# Output file (Mandatory) -# The output file must be an existing .sqlite file -# For Pefrect Foresight, the user may target the same input file or a separate / -# copied sqlite file in a different location. Myopic, MGA require that input_database = output_database -output_database = "data_files/example_dbs/seasonal_storage.sqlite" - -# ------------------------------------ -# DATA / MODEL CHECKS -# To check data / cost integrity -# ------------------------------------ - -# See the documentation section on Data Quality for notes on the features below - -# Check the pricing structure for common errors, which are reported in the log file -# Strongly recommended -price_check = true - -# Check the network connectivity for processes in the model. Strongly -# recommended to ensure proper performance. Results are reported in log file -# This requires that source commodities be marked with 's' in Commodity table -# This is required for Myopic runs -source_trace = true - -# Produce HTML files for Commodity Networks. Requires source_trace above -plot_commodity_network = true - -# ------------------------------------ -# SOLVER -# Solver Selection -# ------------------------------------ - -# use the NEOS server to solve. (Currently NOT supported) -neos = false - -# solver (Mandatory) -# Depending on what client machine has installed. -# [cbc, appsi_highs, gurobi, cplex, ...] -solver_name = "cbc" - -# ------------------------------------ -# OUTPUTS -# select desired output products/files -# ------------------------------------ - -# generate an Excel file in the output_files folder -save_excel = true - -# save the duals in the output Database (may slow execution slightly?) -save_duals = true - -# save storage levels by time slice (may be a large amount of data) -save_storage_levels = true - -# save a copy of the pyomo-generated lp file(s) to the outputs folder (maybe a large file(s)!) -save_lp_file = false - -# ------------------------------------ -# MODEL PARAMETERS -# these are specific to each model -# ------------------------------------ - -# What seasons represent in the model -# Options: -# 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples -# might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. -# 'representative_periods' -# Each season represents a number of days, though not necessarily in any particular order. -# If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in -# the Technology table. -# 'seasonal_timeslices' -# Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out -# in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the TimeSeasonSequential table filled. -time_sequencing = 'representative_periods' - -# Number of days represented by each planning period. -# Used to adjust flow variables for number of days represented by each season. -# E.g. 365 if all seasons collectively represent a year, 7 if modelling a single representative week. -days_per_period = 365 - -# How contributions to the planning reserve margin are calculated -# Options: -# 'static' -# Traditional planning reserve formulation. Contributions are independent of hourly availability: -# capacity value = net capacity * capacity credit -# 'dynamic' -# Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = net capacity * reserve capacity derate * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * reserve capacity derate -reserve_margin = 'static' - -# --------------------------------------------------- -# MODE OPTIONS -# options below are mode-specific and will be ignored -# if the run is not executed in that mode. -# --------------------------------------------------- -[MGA] -# see notes on these in the extensions/modeling_to_generate_alternatives folder readme.txt -cost_epsilon = 0.03 # propotional relaxation on optimal cost (ex: 0.05 = bound at 105% of original optimal cost) -iteration_limit = 55 # max iterations to perform -time_limit_hrs = 1 # max time -axis = "tech_category_activity" # use the tech activity Manager to control exploration based on categories in Tech -weighting = "hull_expansion" # use a convex hull expansion algorithm to weight exploration - -[myopic] -view_depth = 2 # number of periods seen/analyzed per iteration -step_size = 1 # number of periods to step by (must be <= view depth) - -[morris] -perturbation = 0.10 # amount to perturb marked parameters (ex: 0.10 -> +/- 10%) -levels = 8 # number of levels in param grid (must be even number) -trajectories = 10 # number of Morris trajectories to generate/explore -seed = false # random seed for use in generation/analysis for repeatable results. false=system derived -cores = 0 # number of CPU cores to use. 0 (default) = cpu count -# Note: Problem size (in general) is (Groups + 1) * trajectories see the SALib Dox -# Groups = number of unique labels used in MM analysis columns in DB - -[SVMGA] -cost_epsilon = 0.05 -# labels from appropriate tables in database. It is recommended to only use one of the lists below and leave -# the others blank -emission_labels = ['co2', 'nox'] -capacity_labels = ['TXD', 'TXG'] -activity_labels = [] - -[monte_carlo] -# a path from the PROJECT ROOT to the settings file that contains the run data. -run_settings = 'data_files/monte_carlo/run_settings_1.csv' - diff --git a/data_files/my_configs/stepped_demand.toml b/data_files/my_configs/stepped_demand.toml deleted file mode 100644 index 7092d31c1..000000000 --- a/data_files/my_configs/stepped_demand.toml +++ /dev/null @@ -1,131 +0,0 @@ -# ---------------------------------------------------------- -# Configuration file for a Temoa Run -# Allows specification of run type and associated parameters -# ---------------------------------------------------------- -# -# For toml format info see: https://toml.io/en/ -# - comments may be added with hash -# - do NOT comment out table names in brackets like: [
] - -# Scenario Name (Mandatory) -# This scenario name is used to label results within the output .sqlite file -scenario = "myo_1" - -# Scenaio Mode (Mandatory) -# See documentation for explanations. A standard single run is "perfect_foresight" -# mode must be one of (case-insensitive): -# [perfect_foresight, MGA, myopic, method_of_morris, build_only, check] -scenario_mode = "myopic" - -# Input database (Mandatory) -input_database = "data_files/example_dbs/stepped_demand.sqlite" - -# Output file (Mandatory) -# The output file must be an existing .sqlite file -# For Pefrect Foresight, the user may target the same input file or a separate / -# copied sqlite file in a different location. Myopic requires that input_database = output_database -output_database = "data_files/example_dbs/stepped_demand.sqlite" - -# ------------------------------------ -# DATA / MODEL CHECKS -# To check data / cost integrity -# ------------------------------------ - -# Check the pricing structure for common errors, which are reported in the log file -# Strongly recommended -price_check = true - -# Check the network connectivity for processes in the model. Strongly -# recommended to ensure proper performance. Results are reported in log file -# This requires that source commodities be marked with 's' in Commodity table -# This is required for Myopic runs -source_trace = true - -# Produce HTML files for Commodity Networks. Requires source_trace above -plot_commodity_network = true - -# ------------------------------------ -# SOLVER -# Solver Selection -# ------------------------------------ - -# use the NEOS server to solve. (Currently NOT supported) -neos = false - -# solver (Mandatory) -# Depending on what client machine has installed. -# [cbc, appsi_highs, gurobi, cplex, ...] -solver_name = "cbc" - -# ------------------------------------ -# OUTPUTS -# select desired output products/files -# ------------------------------------ - -# generate an Excel file in the output_files folder -save_excel = true - -# save the duals in the output Database (may slow execution slightly?) -save_duals = false - -# save a copy of the pyomo-generated lp file(s) to the outputs folder (maybe a large file(s)!) -save_lp_file = false - -# ------------------------------------ -# MODEL PARAMETERS -# these are specific to each model -# ------------------------------------ - -# What seasons represent in the model -# Options: -# 'consecutive_days' -# Seasons are a set of days in order, with each season representing only one day. Examples -# might be a model of a representative week with 7 days or a whole-year model with 365 days. -# Seasonal storage need not be tagged and the TimeSeasonSequential table can be left empty. -# 'representative_periods' -# Each season represents a number of days, though not necessarily in any particular order. -# If using inter-season constraints like seasonal storage or ramp rates, the true sequence -# must be defined using the TimeSeasonSequential table. Seasonal storage must also be tagged in -# the Technology table. -# 'seasonal_timeslices' -# Each season represents a sequential slice of the year, with one or many days represented per -# season. We assume that the true sequence is the same as the TimeSeason sequence, so the -# TimeSeasonSequential table can be left empty. Seasonal storage must still be tagged. -# 'manual' -# The sequence of time slices is defined manually in the TimeNext table (which is commented out -# in the schema). This is an advanced feature and not recommended for most users. Seasonal -# storage must be tagged and the TimeSeasonSequential table filled. -time_sequencing = 'seasonal_timeslices' - -# Number of days represented by each planning period. -# Used to adjust flow variables for number of days represented by each season. -# E.g. 365 if all seasons collectively represent a year, 7 if modelling a single representative week. -days_per_period = 365 - -# How contributions to the planning reserve margin are calculated -# Options: -# 'static' -# Traditional planning reserve formulation. Contributions are independent of hourly availability: -# capacity value = net capacity * capacity credit -# 'dynamic' -# Contributions are available output including a capacity derate factor (e.g., forced outage rate). -# For most generators, contributions are available (derated) output in each time slice: -# capacity value = net capacity * reserve capacity derate * capacity factor -# For storage, contributions are (derated) actual output in each time slice: -# capacity value = flow out * reserve capacity derate -reserve_margin = 'static' - -# --------------------------------------------------- -# MODE OPTIONS -# options below are mode-specific and will be ignored -# if the run is not executed in that mode. -# --------------------------------------------------- -[MGA] - - -[myopic] -view_depth = 2 # number of periods seen/analyzed per iteration -step_size = 1 # number of periods to step by (must be <= view depth) - - - diff --git a/data_files/temoa_basics_0.sql b/data_files/temoa_basics_0.sql deleted file mode 100644 index effa1ced0..000000000 --- a/data_files/temoa_basics_0.sql +++ /dev/null @@ -1,374 +0,0 @@ -PRAGMA foreign_keys= OFF; -BEGIN TRANSACTION; - -CREATE TABLE IF NOT EXISTS MetaData -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -REPLACE INTO MetaData -VALUES ('DB_MAJOR', 3, 'DB major version number'); -REPLACE INTO MetaData -VALUES ('DB_MINOR', 1, 'DB minor version number'); -CREATE TABLE IF NOT EXISTS MetaDataReal -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -REPLACE INTO MetaDataReal -VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); -REPLACE INTO MetaDataReal -VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in loan_rate table'); - -CREATE TABLE IF NOT EXISTS Commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES CommodityType (label), - description TEXT -); -CREATE TABLE IF NOT EXISTS CommodityType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO CommodityType -VALUES ('s', 'source commodity'); -REPLACE INTO CommodityType -VALUES ('p', 'physical commodity'); -REPLACE INTO CommodityType -VALUES ('d', 'demand commodity'); -CREATE TABLE IF NOT EXISTS cost_fixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS cost_invest -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS cost_variable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS Demand -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - commodity TEXT - REFERENCES Commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -CREATE TABLE IF NOT EXISTS efficiency -( - region TEXT, - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE IF NOT EXISTS lifetime_process -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS lifetime_tech -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS OutputBuiltCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputCost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) -); -CREATE TABLE IF NOT EXISTS OutputCurtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputDualVariable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE IF NOT EXISTS OutputEmission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputFlowIn -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputFlowOut -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputNetCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE IF NOT EXISTS OutputRetiredCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputStorageLevel -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE IF NOT EXISTS Region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS SectorLabel -( - sector TEXT PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS Technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) -); -CREATE TABLE IF NOT EXISTS TechnologyType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO TechnologyType -VALUES ('p', 'production technology'); -CREATE TABLE IF NOT EXISTS TimePeriod -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES TimePeriodType (label) -); -CREATE TABLE IF NOT EXISTS TimePeriodType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO TimePeriodType -VALUES('e', 'existing vintages'); -REPLACE INTO TimePeriodType -VALUES('f', 'future'); - -COMMIT; -PRAGMA FOREIGN_KEYS = 1; diff --git a/data_files/temoa_basics_1.sql b/data_files/temoa_basics_1.sql deleted file mode 100644 index cdab9f8de..000000000 --- a/data_files/temoa_basics_1.sql +++ /dev/null @@ -1,507 +0,0 @@ -PRAGMA foreign_keys= OFF; -BEGIN TRANSACTION; - -CREATE TABLE IF NOT EXISTS MetaData -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -REPLACE INTO MetaData -VALUES ('DB_MAJOR', 3, 'DB major version number'); -REPLACE INTO MetaData -VALUES ('DB_MINOR', 1, 'DB minor version number'); -CREATE TABLE IF NOT EXISTS MetaDataReal -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -REPLACE INTO MetaDataReal -VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); -REPLACE INTO MetaDataReal -VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in loan_rate table'); - -CREATE TABLE IF NOT EXISTS capacity_factor_tech -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS CapacityToActivity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS Commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES CommodityType (label), - description TEXT -); -CREATE TABLE IF NOT EXISTS CommodityType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO CommodityType -VALUES ('s', 'source commodity'); -REPLACE INTO CommodityType -VALUES ('a', 'annual commodity'); -REPLACE INTO CommodityType -VALUES ('p', 'physical commodity'); -REPLACE INTO CommodityType -VALUES ('d', 'demand commodity'); -REPLACE INTO CommodityType -VALUES ('e', 'emissions commodity'); -CREATE TABLE IF NOT EXISTS cost_emission -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT NOT NULL - REFERENCES Commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE IF NOT EXISTS cost_fixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS cost_invest -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS cost_variable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS Demand -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - commodity TEXT - REFERENCES Commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -CREATE TABLE IF NOT EXISTS DemandSpecificDistribution -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - demand_name TEXT - REFERENCES Commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -CREATE TABLE IF NOT EXISTS efficiency -( - region TEXT, - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE IF NOT EXISTS emission_activity -( - region TEXT, - emis_comm TEXT - REFERENCES Commodity (name), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS existing_capacity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS lifetime_process -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS lifetime_tech -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS OutputBuiltCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputCost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) -); -CREATE TABLE IF NOT EXISTS OutputCurtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputDualVariable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE IF NOT EXISTS OutputEmission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputFlowIn -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputFlowOut -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputNetCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE IF NOT EXISTS OutputRetiredCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputStorageLevel -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE IF NOT EXISTS Region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS SeasonLabel -( - season TEXT PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS SectorLabel -( - sector TEXT PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS storage_duration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS Technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) -); -CREATE TABLE IF NOT EXISTS TechnologyType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO TechnologyType -VALUES ('p', 'production technology'); -REPLACE INTO TechnologyType -VALUES ('pb', 'baseload production technology'); -REPLACE INTO TechnologyType -VALUES ('ps', 'storage production technology'); -CREATE TABLE IF NOT EXISTS TimeOfDay -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY -); -CREATE TABLE IF NOT EXISTS TimePeriod -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES TimePeriodType (label) -); -CREATE TABLE IF NOT EXISTS TimePeriodType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO TimePeriodType -VALUES('e', 'existing vintages'); -REPLACE INTO TimePeriodType -VALUES('f', 'future'); -CREATE TABLE IF NOT EXISTS TimeSeason -( - period INTEGER - REFERENCES TimePeriod (period), - sequence INTEGER, - season TEXT - REFERENCES SeasonLabel (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); -CREATE TABLE IF NOT EXISTS TimeSegmentFraction -( - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) -); - -COMMIT; -PRAGMA FOREIGN_KEYS = 1; diff --git a/data_files/temoa_basics_2.sql b/data_files/temoa_basics_2.sql deleted file mode 100644 index 717226eed..000000000 --- a/data_files/temoa_basics_2.sql +++ /dev/null @@ -1,753 +0,0 @@ -PRAGMA foreign_keys= OFF; -BEGIN TRANSACTION; - -CREATE TABLE IF NOT EXISTS MetaData -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -REPLACE INTO MetaData -VALUES ('DB_MAJOR', 3, 'DB major version number'); -REPLACE INTO MetaData -VALUES ('DB_MINOR', 1, 'DB minor version number'); -CREATE TABLE IF NOT EXISTS MetaDataReal -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -REPLACE INTO MetaDataReal -VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); -REPLACE INTO MetaDataReal -VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in loan_rate table'); - -CREATE TABLE IF NOT EXISTS capacity_factor_tech -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS CapacityToActivity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS Commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES CommodityType (label), - description TEXT -); -CREATE TABLE IF NOT EXISTS CommodityType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO CommodityType -VALUES ('s', 'source commodity'); -REPLACE INTO CommodityType -VALUES ('a', 'annual commodity'); -REPLACE INTO CommodityType -VALUES ('p', 'physical commodity'); -REPLACE INTO CommodityType -VALUES ('d', 'demand commodity'); -REPLACE INTO CommodityType -VALUES ('e', 'emissions commodity'); -CREATE TABLE IF NOT EXISTS cost_emission -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT NOT NULL - REFERENCES Commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE IF NOT EXISTS cost_fixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS cost_invest -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS cost_variable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS Demand -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - commodity TEXT - REFERENCES Commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -CREATE TABLE IF NOT EXISTS DemandSpecificDistribution -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - demand_name TEXT - REFERENCES Commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -CREATE TABLE IF NOT EXISTS efficiency -( - region TEXT, - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE IF NOT EXISTS emission_activity -( - region TEXT, - emis_comm TEXT - REFERENCES Commodity (name), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS existing_capacity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS lifetime_process -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS lifetime_tech -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS limit_activity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE IF NOT EXISTS limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS limit_capacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE IF NOT EXISTS limit_degrowth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS limit_emission -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE IF NOT EXISTS limit_growth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS limit_new_capacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE IF NOT EXISTS limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS limit_seasonal_capacity_factor -( - region TEXT - REFERENCES Region (region), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) -); -CREATE TABLE IF NOT EXISTS LimitStorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -CREATE TABLE IF NOT EXISTS limit_tech_input_split -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE IF NOT EXISTS limit_tech_input_split_annual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE IF NOT EXISTS limit_tech_output_split -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE IF NOT EXISTS limit_tech_output_split_annual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE IF NOT EXISTS Operator -( - operator TEXT PRIMARY KEY, - notes TEXT -); -REPLACE INTO Operator VALUES('e','equal to'); -REPLACE INTO Operator VALUES('le','less than or equal to'); -REPLACE INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE IF NOT EXISTS OutputBuiltCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputCost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) -); -CREATE TABLE IF NOT EXISTS OutputCurtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputDualVariable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE IF NOT EXISTS OutputEmission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputFlowIn -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputFlowOut -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputNetCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE IF NOT EXISTS OutputRetiredCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputStorageLevel -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE IF NOT EXISTS Region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS SeasonLabel -( - season TEXT PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS SectorLabel -( - sector TEXT PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS storage_duration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS Technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) -); -CREATE TABLE IF NOT EXISTS TechnologyType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO TechnologyType -VALUES ('p', 'production technology'); -REPLACE INTO TechnologyType -VALUES ('pb', 'baseload production technology'); -REPLACE INTO TechnologyType -VALUES ('ps', 'storage production technology'); -CREATE TABLE IF NOT EXISTS TimeOfDay -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY -); -CREATE TABLE IF NOT EXISTS TimePeriod -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES TimePeriodType (label) -); -CREATE TABLE IF NOT EXISTS TimePeriodType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO TimePeriodType -VALUES('e', 'existing vintages'); -REPLACE INTO TimePeriodType -VALUES('f', 'future'); -CREATE TABLE IF NOT EXISTS TimeSeason -( - period INTEGER - REFERENCES TimePeriod (period), - sequence INTEGER, - season TEXT - REFERENCES SeasonLabel (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); -CREATE TABLE IF NOT EXISTS TimeSegmentFraction -( - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) -); - -COMMIT; -PRAGMA FOREIGN_KEYS = 1; diff --git a/data_files/temoa_schema_v3.sql b/data_files/temoa_schema_v3.sql deleted file mode 100644 index 3c03e7b80..000000000 --- a/data_files/temoa_schema_v3.sql +++ /dev/null @@ -1,921 +0,0 @@ -PRAGMA foreign_keys= OFF; -BEGIN TRANSACTION; - -CREATE TABLE IF NOT EXISTS MetaData -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -REPLACE INTO MetaData -VALUES ('myopic_base_year', 2000, 'Base Year for Myopic Analysis'); -REPLACE INTO MetaData -VALUES ('DB_MAJOR', 3, 'DB major version number'); -REPLACE INTO MetaData -VALUES ('DB_MINOR', 0, 'DB minor version number'); - -CREATE TABLE IF NOT EXISTS MetaDataReal -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -REPLACE INTO MetaDataReal -VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); -REPLACE INTO MetaDataReal -VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in LoanRate table'); - -CREATE TABLE IF NOT EXISTS OutputDualVariable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE IF NOT EXISTS OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE IF NOT EXISTS SectorLabel -( - sector TEXT, - PRIMARY KEY (sector) -); - -CREATE TABLE IF NOT EXISTS CapacityCredit -( - region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -CREATE TABLE IF NOT EXISTS CapacityFactorProcess -( - region TEXT, - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS CapacityFactorTech -( - region TEXT, - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS CapacityToActivity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS Commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES CommodityType (label), - description TEXT -); -CREATE TABLE IF NOT EXISTS CommodityType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO CommodityType -VALUES ('p', 'physical commodity'); -REPLACE INTO CommodityType -VALUES ('e', 'emissions commodity'); -REPLACE INTO CommodityType -VALUES ('d', 'demand commodity'); -REPLACE INTO CommodityType -VALUES ('s', 'source commodity'); - -CREATE TABLE IF NOT EXISTS CostEmission -( - region TEXT - REFERENCES Region (region), - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT NOT NULL - REFERENCES Commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE IF NOT EXISTS CostFixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS CostInvest -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS CostVariable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS Demand -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - commodity TEXT - REFERENCES Commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -CREATE TABLE IF NOT EXISTS DemandSpecificDistribution -( - region TEXT, - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - demand_name TEXT - REFERENCES Commodity (name), - dds REAL, - dds_notes TEXT, - PRIMARY KEY (region, season, tod, demand_name), - CHECK (dds >= 0 AND dds <= 1) -); -CREATE TABLE IF NOT EXISTS LoanRate -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS Efficiency -( - region TEXT, - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE IF NOT EXISTS EmissionActivity -( - region TEXT, - emis_comm TEXT - REFERENCES Commodity (name), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS ExistingCapacity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS GrowthRateMax -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS GrowthRateSeed -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - seed REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS LoanLifetimeTech -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS LifetimeProcess -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS LifetimeTech -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS LinkedTech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES Technology (tech), - emis_comm TEXT - REFERENCES Commodity (name), - driven_tech TEXT - REFERENCES Technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -CREATE TABLE IF NOT EXISTS MaxActivity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE IF NOT EXISTS MaxCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE IF NOT EXISTS MaxResource -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - max_res REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS MinActivity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE IF NOT EXISTS MaxCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS MinCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE IF NOT EXISTS MinCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS OutputCurtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputNetCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputBuiltCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputRetiredCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputFlowIn -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputFlowOut -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS PlanningReserveMargin -( - region TEXT - PRIMARY KEY - REFERENCES Region (region), - margin REAL -); -CREATE TABLE IF NOT EXISTS RampDown -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS RampUp -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS Region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS TimeSegmentFraction -( - season TEXT - REFERENCES TimeSeason (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) -); -CREATE TABLE IF NOT EXISTS StorageDuration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS StorageInit -( - tech TEXT - PRIMARY KEY, - value REAL, - notes TEXT -); -CREATE TABLE IF NOT EXISTS TechnologyType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO TechnologyType -VALUES ('r', 'resource technology'); -REPLACE INTO TechnologyType -VALUES ('p', 'production technology'); -REPLACE INTO TechnologyType -VALUES ('pb', 'baseload production technology'); -REPLACE INTO TechnologyType -VALUES ('ps', 'storage production technology'); - -CREATE TABLE IF NOT EXISTS TechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE IF NOT EXISTS TechInputSplitAverage -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech) -); -CREATE TABLE IF NOT EXISTS TechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm) -); -CREATE TABLE IF NOT EXISTS TimeOfDay -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY -); -CREATE TABLE IF NOT EXISTS TimePeriod -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES TimePeriodType (label) -); -CREATE TABLE IF NOT EXISTS TimeSeason -( - sequence INTEGER UNIQUE, - season TEXT - PRIMARY KEY -); -CREATE TABLE IF NOT EXISTS TimePeriodType -( - label TEXT - PRIMARY KEY, - description TEXT -); -CREATE TABLE IF NOT EXISTS MaxActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE IF NOT EXISTS MaxCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE IF NOT EXISTS MaxAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS MaxNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - max_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE IF NOT EXISTS MaxNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS MaxNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE IF NOT EXISTS MinActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE IF NOT EXISTS MinAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - factor REAL, - source TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS MinCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - min_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE IF NOT EXISTS MinNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - min_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech) -); -CREATE TABLE IF NOT EXISTS MinNewCapacityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS MinNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - group_name TEXT - REFERENCES TechGroup (group_name), - max_proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, group_name) -); -CREATE TABLE IF NOT EXISTS OutputEmission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS MinActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - min_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); -CREATE TABLE IF NOT EXISTS EmissionLimit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE IF NOT EXISTS MaxActivityGroup -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - group_name TEXT - REFERENCES TechGroup (group_name), - max_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, group_name) -); - -CREATE TABLE RPSRequirement -( - region TEXT NOT NULL - REFERENCES Region (region), - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech_group TEXT NOT NULL - REFERENCES TechGroup (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE TechGroupMember -( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES Technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE IF NOT EXISTS Technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - variable INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) -); -CREATE TABLE IF NOT EXISTS OutputCost -( - scenario TEXT, - region TEXT, - period INTEGER, - tech TEXT, - vintage INTEGER, - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) -); -COMMIT; -PRAGMA FOREIGN_KEYS = 1; - - diff --git a/data_files/temoa_schema_v3_1.sql b/data_files/temoa_schema_v3_1.sql deleted file mode 100644 index 05015865c..000000000 --- a/data_files/temoa_schema_v3_1.sql +++ /dev/null @@ -1,1055 +0,0 @@ -PRAGMA foreign_keys= OFF; -BEGIN TRANSACTION; - -CREATE TABLE IF NOT EXISTS MetaData -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -REPLACE INTO MetaData -VALUES ('DB_MAJOR', 3, 'DB major version number'); -REPLACE INTO MetaData -VALUES ('DB_MINOR', 1, 'DB minor version number'); - -CREATE TABLE IF NOT EXISTS MetaDataReal -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -REPLACE INTO MetaDataReal -VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); -REPLACE INTO MetaDataReal -VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in LoanRate table'); - -CREATE TABLE IF NOT EXISTS OutputDualVariable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE IF NOT EXISTS OutputObjective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE IF NOT EXISTS SeasonLabel -( - season TEXT PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS SectorLabel -( - sector TEXT PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS CapacityCredit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -CREATE TABLE IF NOT EXISTS CapacityFactorProcess -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS CapacityFactorTech -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS CapacityToActivity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - c2a REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS Commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES CommodityType (label), - description TEXT -); -CREATE TABLE IF NOT EXISTS CommodityType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO CommodityType -VALUES ('s', 'source commodity'); -REPLACE INTO CommodityType -VALUES ('a', 'annual commodity'); -REPLACE INTO CommodityType -VALUES ('p', 'physical commodity'); -REPLACE INTO CommodityType -VALUES ('d', 'demand commodity'); -REPLACE INTO CommodityType -VALUES ('e', 'emissions commodity'); -REPLACE INTO CommodityType -VALUES ('w', 'waste commodity'); -REPLACE INTO CommodityType -VALUES ('wa', 'waste annual commodity'); -REPLACE INTO CommodityType -VALUES ('wp', 'waste physical commodity'); -CREATE TABLE IF NOT EXISTS ConstructionInput -( - region TEXT, - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS CostEmission -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT NOT NULL - REFERENCES Commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE IF NOT EXISTS CostFixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS CostInvest -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS CostVariable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS Demand -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - commodity TEXT - REFERENCES Commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -CREATE TABLE IF NOT EXISTS DemandSpecificDistribution -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - demand_name TEXT - REFERENCES Commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -CREATE TABLE IF NOT EXISTS EndOfLifeOutput -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS Efficiency -( - region TEXT, - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE IF NOT EXISTS EfficiencyVariable -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tod, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE IF NOT EXISTS EmissionActivity -( - region TEXT, - emis_comm TEXT - REFERENCES Commodity (name), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS EmissionEmbodied -( - region TEXT, - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS EmissionEndOfLife -( - region TEXT, - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS ExistingCapacity -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS TechGroup -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS LoanLifetimeProcess -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS LoanRate -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS LifetimeProcess -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS LifetimeTech -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - lifetime REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS Operator -( - operator TEXT PRIMARY KEY, - notes TEXT -); -REPLACE INTO Operator VALUES('e','equal to'); -REPLACE INTO Operator VALUES('le','less than or equal to'); -REPLACE INTO Operator VALUES('ge','greater than or equal to'); -CREATE TABLE IF NOT EXISTS LimitGrowthCapacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitDegrowthCapacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitGrowthNewCapacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitDegrowthNewCapacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitGrowthNewCapacityDelta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitDegrowthNewCapacityDelta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitStorageLevelFraction -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - fraction REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tod, tech, vintage, operator) -); -CREATE TABLE IF NOT EXISTS LimitActivity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitActivityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitAnnualCapacityFactor -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS LimitCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitNewCapacity -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitNewCapacityShare -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitResource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS LimitSeasonalCapacityFactor -( - region TEXT - REFERENCES Region (region), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, period, season, tech, operator) -); -CREATE TABLE IF NOT EXISTS LimitTechInputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE IF NOT EXISTS LimitTechInputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE IF NOT EXISTS LimitTechOutputSplit -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE IF NOT EXISTS LimitTechOutputSplitAnnual -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - output_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE IF NOT EXISTS LimitEmission -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES Operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE IF NOT EXISTS LinkedTech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES Technology (tech), - emis_comm TEXT - REFERENCES Commodity (name), - driven_tech TEXT - REFERENCES Technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -CREATE TABLE IF NOT EXISTS OutputCurtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES TimePeriod (period), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - curtailment REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputNetCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputBuiltCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - capacity REAL, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputRetiredCapacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - cap_eol REAL, - cap_early REAL, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS OutputFlowIn -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputFlowOut -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - input_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - output_comm TEXT - REFERENCES Commodity (name), - flow REAL, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS OutputStorageLevel -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - level REAL, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE IF NOT EXISTS PlanningReserveMargin -( - region TEXT - PRIMARY KEY - REFERENCES Region (region), - margin REAL, - notes TEXT -); -CREATE TABLE IF NOT EXISTS RampDownHourly -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS RampUpHourly -( - region TEXT, - tech TEXT - REFERENCES Technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS Region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS ReserveCapacityDerate -( - region TEXT, - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, season, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS TimeSegmentFraction -( - period INTEGER - REFERENCES TimePeriod (period), - season TEXT - REFERENCES SeasonLabel (season), - tod TEXT - REFERENCES TimeOfDay (tod), - segfrac REAL, - notes TEXT, - PRIMARY KEY (period, season, tod), - CHECK (segfrac >= 0 AND segfrac <= 1) -); -CREATE TABLE IF NOT EXISTS StorageDuration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS LifetimeSurvivalCurve -( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES Technology (tech), - vintage INTEGER NOT NULL - REFERENCES TimePeriod (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS TechnologyType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO TechnologyType -VALUES ('p', 'production technology'); -REPLACE INTO TechnologyType -VALUES ('pb', 'baseload production technology'); -REPLACE INTO TechnologyType -VALUES ('ps', 'storage production technology'); --- CREATE TABLE IF NOT EXISTS TimeNext --- ( --- period INTEGER --- REFERENCES TimePeriod (period), --- season TEXT --- REFERENCES SeasonLabel (season), --- tod TEXT --- REFERENCES TimeOfDay (tod), --- season_next TEXT --- REFERENCES SeasonLabel (season), --- tod_next TEXT --- REFERENCES TimeOfDay (tod), --- notes TEXT, --- PRIMARY KEY (period, season, tod) --- ); -CREATE TABLE IF NOT EXISTS TimeOfDay -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY -); -CREATE TABLE IF NOT EXISTS TimePeriod -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES TimePeriodType (label) -); -CREATE TABLE IF NOT EXISTS TimeSeason -( - period INTEGER - REFERENCES TimePeriod (period), - sequence INTEGER, - season TEXT - REFERENCES SeasonLabel (season), - notes TEXT, - PRIMARY KEY (period, sequence, season) -); -CREATE TABLE IF NOT EXISTS TimeSeasonSequential -( - period INTEGER - REFERENCES TimePeriod (period), - sequence INTEGER, - seas_seq TEXT, - season TEXT - REFERENCES SeasonLabel (season), - num_days REAL NOT NULL, - notes TEXT, - PRIMARY KEY (period, sequence, seas_seq, season), - CHECK (num_days > 0) -); -CREATE TABLE IF NOT EXISTS TimePeriodType -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO TimePeriodType -VALUES('e', 'existing vintages'); -REPLACE INTO TimePeriodType -VALUES('f', 'future'); -CREATE TABLE IF NOT EXISTS OutputEmission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES SectorLabel (sector), - period INTEGER - REFERENCES TimePeriod (period), - emis_comm TEXT - REFERENCES Commodity (name), - tech TEXT - REFERENCES Technology (tech), - vintage INTEGER - REFERENCES TimePeriod (period), - emission REAL, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS RPSRequirement -( - region TEXT NOT NULL - REFERENCES Region (region), - period INTEGER NOT NULL - REFERENCES TimePeriod (period), - tech_group TEXT NOT NULL - REFERENCES TechGroup (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE IF NOT EXISTS TechGroupMember -( - group_name TEXT - REFERENCES TechGroup (group_name), - tech TEXT - REFERENCES Technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE IF NOT EXISTS Technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES TechnologyType (label) -); -CREATE TABLE IF NOT EXISTS OutputCost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES SectorLabel (sector), - period INTEGER REFERENCES TimePeriod (period), - tech TEXT REFERENCES Technology (tech), - vintage INTEGER REFERENCES TimePeriod (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES TimePeriod (period), - FOREIGN KEY (tech) REFERENCES Technology (tech) -); -COMMIT; -PRAGMA FOREIGN_KEYS = 1; diff --git a/data_files/temoa_schema_v4.sql b/data_files/temoa_schema_v4.sql deleted file mode 100644 index 90a39108c..000000000 --- a/data_files/temoa_schema_v4.sql +++ /dev/null @@ -1,1068 +0,0 @@ -PRAGMA foreign_keys = OFF; -BEGIN TRANSACTION; - -CREATE TABLE IF NOT EXISTS metadata -( - element TEXT, - value INT, - notes TEXT, - PRIMARY KEY (element) -); -REPLACE INTO metadata -VALUES ('DB_MAJOR', 4, 'DB major version number'); -REPLACE INTO metadata -VALUES ('DB_MINOR', 0, 'DB minor version number'); - -CREATE TABLE IF NOT EXISTS metadata_real -( - element TEXT, - value REAL, - notes TEXT, - - PRIMARY KEY (element) -); -REPLACE INTO metadata_real -VALUES ('global_discount_rate', 0.05, 'Discount Rate for future costs'); -REPLACE INTO metadata_real -VALUES ('default_loan_rate', 0.05, 'Default Loan Rate if not specified in LoanRate table'); - -CREATE TABLE IF NOT EXISTS output_dual_variable -( - scenario TEXT, - constraint_name TEXT, - dual REAL, - PRIMARY KEY (constraint_name, scenario) -); -CREATE TABLE IF NOT EXISTS output_objective -( - scenario TEXT, - objective_name TEXT, - total_system_cost REAL -); -CREATE TABLE IF NOT EXISTS sector_label -( - sector TEXT PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS capacity_credit -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - credit REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage), - CHECK (credit >= 0 AND credit <= 1) -); -CREATE TABLE IF NOT EXISTS capacity_factor_process -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS capacity_factor_tech -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, tech), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS capacity_to_activity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - c2a REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS commodity -( - name TEXT - PRIMARY KEY, - flag TEXT - REFERENCES commodity_type (label), - description TEXT, - units TEXT -); -CREATE TABLE IF NOT EXISTS commodity_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO commodity_type -VALUES ('s', 'source commodity'); -REPLACE INTO commodity_type -VALUES ('a', 'annual commodity'); -REPLACE INTO commodity_type -VALUES ('p', 'physical commodity'); -REPLACE INTO commodity_type -VALUES ('d', 'demand commodity'); -REPLACE INTO commodity_type -VALUES ('e', 'emissions commodity'); -REPLACE INTO commodity_type -VALUES ('w', 'waste commodity'); -REPLACE INTO commodity_type -VALUES ('wa', 'waste annual commodity'); -REPLACE INTO commodity_type -VALUES ('wp', 'waste physical commodity'); -CREATE TABLE IF NOT EXISTS construction_input -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS cost_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT NOT NULL - REFERENCES commodity (name), - cost REAL NOT NULL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm) -); -CREATE TABLE IF NOT EXISTS cost_fixed -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS cost_invest -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS cost_variable -( - region TEXT NOT NULL, - period INTEGER NOT NULL - REFERENCES time_period (period), - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - cost REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS demand -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - commodity TEXT - REFERENCES commodity (name), - demand REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, commodity) -); -CREATE TABLE IF NOT EXISTS demand_specific_distribution -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - demand_name TEXT - REFERENCES commodity (name), - dsd REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, demand_name), - CHECK (dsd >= 0 AND dsd <= 1) -); -CREATE TABLE IF NOT EXISTS end_of_life_output -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS efficiency -( - region TEXT, - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE IF NOT EXISTS efficiency_variable -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - efficiency REAL, - notes TEXT, - PRIMARY KEY (region, season, tod, input_comm, tech, vintage, output_comm), - CHECK (efficiency > 0) -); -CREATE TABLE IF NOT EXISTS emission_activity -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS emission_embodied -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS emission_end_of_life -( - region TEXT, - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, emis_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS existing_capacity -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS tech_group -( - group_name TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS loan_lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS loan_rate -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS lifetime_process -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - lifetime REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech, vintage) -); -CREATE TABLE IF NOT EXISTS lifetime_tech -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - lifetime REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS operator -( - operator TEXT PRIMARY KEY, - notes TEXT -); -REPLACE INTO operator VALUES('e','equal to'); -REPLACE INTO operator VALUES('le','less than or equal to'); -REPLACE INTO operator VALUES('ge','greater than or equal to'); -CREATE TABLE IF NOT EXISTS limit_growth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS limit_degrowth_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS limit_growth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS limit_degrowth_new_capacity -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS limit_growth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS limit_degrowth_new_capacity_delta -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - rate REAL NOT NULL DEFAULT 0, - seed REAL NOT NULL DEFAULT 0, - seed_units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS limit_storage_level_fraction -( - region TEXT, - season TEXT, - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - fraction REAL, - notes TEXT, - CHECK (fraction >= 0 AND fraction <= 1), - PRIMARY KEY(region, season, tod, tech, operator) -); -CREATE TABLE IF NOT EXISTS limit_activity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - activity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS limit_activity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE IF NOT EXISTS limit_annual_capacity_factor -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS limit_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - capacity REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS limit_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE IF NOT EXISTS limit_new_capacity -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - new_cap REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS limit_new_capacity_share -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - sub_group TEXT, - super_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - share REAL, - notes TEXT, - PRIMARY KEY (region, period, sub_group, super_group, operator) -); -CREATE TABLE IF NOT EXISTS limit_resource -( - region TEXT, - tech_or_group TEXT, - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - cum_act REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, tech_or_group, operator) -); -CREATE TABLE IF NOT EXISTS limit_seasonal_capacity_factor -( - region TEXT - REFERENCES region (region), - season TEXT - REFERENCES time_season (season), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - factor REAL, - notes TEXT, - PRIMARY KEY(region, season, tech, operator) -); -CREATE TABLE IF NOT EXISTS limit_tech_input_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE IF NOT EXISTS limit_tech_input_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, input_comm, tech, operator) -); -CREATE TABLE IF NOT EXISTS limit_tech_output_split -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE IF NOT EXISTS limit_tech_output_split_annual -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - output_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - proportion REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, output_comm, operator) -); -CREATE TABLE IF NOT EXISTS limit_emission -( - region TEXT, - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - operator TEXT NOT NULL DEFAULT "le" - REFERENCES operator (operator), - value REAL, - units TEXT, - notes TEXT, - PRIMARY KEY (region, period, emis_comm, operator) -); -CREATE TABLE IF NOT EXISTS linked_tech -( - primary_region TEXT, - primary_tech TEXT - REFERENCES technology (tech), - emis_comm TEXT - REFERENCES commodity (name), - driven_tech TEXT - REFERENCES technology (tech), - notes TEXT, - PRIMARY KEY (primary_region, primary_tech, emis_comm) -); -CREATE TABLE IF NOT EXISTS output_curtailment -( - scenario TEXT, - region TEXT, - sector TEXT, - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - curtailment REAL, - units TEXT, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS output_net_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - units TEXT, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS output_built_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - capacity REAL, - units TEXT, - PRIMARY KEY (region, scenario, tech, vintage) -); -CREATE TABLE IF NOT EXISTS output_retired_capacity -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - cap_eol REAL, - cap_early REAL, - units TEXT, - PRIMARY KEY (region, scenario, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS output_flow_in -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - units TEXT, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS output_flow_out -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT - REFERENCES time_season (season), - tod TEXT - REFERENCES time_of_day (tod), - input_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - output_comm TEXT - REFERENCES commodity (name), - flow REAL, - units TEXT, - PRIMARY KEY (region, scenario, period, season, tod, input_comm, tech, vintage, output_comm) -); -CREATE TABLE IF NOT EXISTS output_storage_level -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - season TEXT, - tod TEXT - REFERENCES time_of_day (tod), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - level REAL, - units TEXT, - PRIMARY KEY (scenario, region, period, season, tod, tech, vintage) -); -CREATE TABLE IF NOT EXISTS planning_reserve_margin -( - region TEXT - PRIMARY KEY - REFERENCES region (region), - margin REAL, - notes TEXT -); -CREATE TABLE IF NOT EXISTS ramp_down_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS ramp_up_hourly -( - region TEXT, - tech TEXT - REFERENCES technology (tech), - rate REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS region -( - region TEXT - PRIMARY KEY, - notes TEXT -); -CREATE TABLE IF NOT EXISTS reserve_capacity_derate -( - region TEXT, - season TEXT - REFERENCES time_season (season), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER, - factor REAL, - notes TEXT, - PRIMARY KEY (region, season, tech, vintage), - CHECK (factor >= 0 AND factor <= 1) -); -CREATE TABLE IF NOT EXISTS storage_duration -( - region TEXT, - tech TEXT, - duration REAL, - notes TEXT, - PRIMARY KEY (region, tech) -); -CREATE TABLE IF NOT EXISTS lifetime_survival_curve -( - region TEXT NOT NULL, - period INTEGER NOT NULL, - tech TEXT NOT NULL - REFERENCES technology (tech), - vintage INTEGER NOT NULL - REFERENCES time_period (period), - fraction REAL, - notes TEXT, - PRIMARY KEY (region, period, tech, vintage) -); -CREATE TABLE IF NOT EXISTS technology_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO technology_type -VALUES ('p', 'production technology'); -REPLACE INTO technology_type -VALUES ('pb', 'baseload production technology'); -REPLACE INTO technology_type -VALUES ('ps', 'storage production technology'); --- CREATE TABLE IF NOT EXISTS time_manual --- ( --- season TEXT --- REFERENCES time_season (season), --- tod TEXT --- REFERENCES time_of_day (tod), --- season_next TEXT --- REFERENCES time_season (season), --- tod_next TEXT --- REFERENCES time_of_day (tod), --- notes TEXT, --- PRIMARY KEY (season, tod) --- ); -CREATE TABLE IF NOT EXISTS time_of_day -( - sequence INTEGER UNIQUE, - tod TEXT - PRIMARY KEY, - hours REAL NOT NULL DEFAULT 1, - notes TEXT, - CHECK (hours > 0) -); -CREATE TABLE IF NOT EXISTS time_period -( - sequence INTEGER UNIQUE, - period INTEGER - PRIMARY KEY, - flag TEXT - REFERENCES time_period_type (label) -); -CREATE TABLE IF NOT EXISTS time_period_type -( - label TEXT - PRIMARY KEY, - description TEXT -); -REPLACE INTO time_period_type -VALUES('e', 'existing vintages'); -REPLACE INTO time_period_type -VALUES('f', 'future'); -CREATE TABLE IF NOT EXISTS output_emission -( - scenario TEXT, - region TEXT, - sector TEXT - REFERENCES sector_label (sector), - period INTEGER - REFERENCES time_period (period), - emis_comm TEXT - REFERENCES commodity (name), - tech TEXT - REFERENCES technology (tech), - vintage INTEGER - REFERENCES time_period (period), - emission REAL, - units TEXT, - PRIMARY KEY (region, scenario, period, emis_comm, tech, vintage) -); -CREATE TABLE IF NOT EXISTS rps_requirement -( - region TEXT NOT NULL - REFERENCES region (region), - period INTEGER NOT NULL - REFERENCES time_period (period), - tech_group TEXT NOT NULL - REFERENCES tech_group (group_name), - requirement REAL NOT NULL, - notes TEXT -); -CREATE TABLE IF NOT EXISTS tech_group_member -( - group_name TEXT - REFERENCES tech_group (group_name), - tech TEXT - REFERENCES technology (tech), - PRIMARY KEY (group_name, tech) -); -CREATE TABLE IF NOT EXISTS technology -( - tech TEXT NOT NULL PRIMARY KEY, - flag TEXT NOT NULL, - sector TEXT, - category TEXT, - sub_category TEXT, - unlim_cap INTEGER NOT NULL DEFAULT 0, - annual INTEGER NOT NULL DEFAULT 0, - reserve INTEGER NOT NULL DEFAULT 0, - curtail INTEGER NOT NULL DEFAULT 0, - retire INTEGER NOT NULL DEFAULT 0, - flex INTEGER NOT NULL DEFAULT 0, - exchange INTEGER NOT NULL DEFAULT 0, - seas_stor INTEGER NOT NULL DEFAULT 0, - description TEXT, - FOREIGN KEY (flag) REFERENCES technology_type (label) -); -CREATE TABLE IF NOT EXISTS output_cost -( - scenario TEXT, - region TEXT, - sector TEXT REFERENCES sector_label (sector), - period INTEGER REFERENCES time_period (period), - tech TEXT REFERENCES technology (tech), - vintage INTEGER REFERENCES time_period (period), - d_invest REAL, - d_fixed REAL, - d_var REAL, - d_emiss REAL, - invest REAL, - fixed REAL, - var REAL, - emiss REAL, - units TEXT, - PRIMARY KEY (scenario, region, period, tech, vintage), - FOREIGN KEY (vintage) REFERENCES time_period (period), - FOREIGN KEY (tech) REFERENCES technology (tech) -); - -CREATE TABLE IF NOT EXISTS time_season -( - sequence INTEGER UNIQUE, - season TEXT, - segment_fraction REAL NOT NULL, - notes TEXT, - PRIMARY KEY (season), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); - -CREATE TABLE IF NOT EXISTS time_season_sequential -( - sequence INTEGER UNIQUE, - seas_seq TEXT, - season TEXT REFERENCES time_season(season), - segment_fraction REAL NOT NULL, - notes TEXT, - PRIMARY KEY (seas_seq), - CHECK (segment_fraction >= 0 AND segment_fraction <= 1) -); - -CREATE TABLE IF NOT EXISTS myopic_efficiency -( - base_year integer, - region text, - input_comm text, - tech text, - vintage integer, - output_comm text, - efficiency real, - lifetime integer, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (region, input_comm, tech, vintage, output_comm) -); --- for efficient searching by rtv: -CREATE INDEX IF NOT EXISTS region_tech_vintage ON myopic_efficiency (region, tech, vintage); - -CREATE TABLE IF NOT EXISTS output_flow_out_summary -( - scenario TEXT NOT NULL, - region TEXT NOT NULL, - sector TEXT, - period INTEGER, - input_comm TEXT NOT NULL, - tech TEXT NOT NULL, - vintage INTEGER, - output_comm TEXT NOT NULL, - flow REAL NOT NULL, - - FOREIGN KEY (tech) REFERENCES technology (tech), - PRIMARY KEY (scenario, region, period, input_comm, tech, vintage, output_comm) -); - -COMMIT; -PRAGMA foreign_keys = ON; From 763731008c7c01d4faa0abf1315a3889e72010d6 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Tue, 24 Mar 2026 17:57:31 -0400 Subject: [PATCH 515/587] Update CLI migration tests to use `utopia.sql` from `temoa/tutorial_assets`. --- tests/test_cli.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index 3b85716b6..c0bd0a28f 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -12,6 +12,7 @@ # Path to the configuration file template we will use for tests. TESTING_CONFIGS_DIR = Path(__file__).parent / 'testing_configs' +UTOPIA_SQL_FIXTURE = Path(__file__).parent.parent / 'temoa' / 'tutorial_assets' / 'utopia.sql' UTOPIA_CONFIG_TEMPLATE = TESTING_CONFIGS_DIR / 'config_utopia.toml' @@ -157,8 +158,8 @@ def test_cli_migrate_help() -> None: def test_cli_migrate_sql_file(tmp_path: Path) -> None: """Test migrating a SQL file with explicit --output.""" - # Ensure input file is available in the test environment (e.g., copied from data_files) - input_file_src = Path(__file__).parent.parent / 'data_files' / 'temoa_basics_0.sql' + # Ensure input file is available in the test environment + input_file_src = UTOPIA_SQL_FIXTURE input_file = tmp_path / 'test_input.sql' shutil.copy2(input_file_src, input_file) @@ -192,7 +193,7 @@ def test_cli_migrate_sql_file_auto_output_writable_input_dir(tmp_path: Path) -> where the input directory is writable. Output should be next to input with _v4.sql suffix. """ - src_file = Path(__file__).parent.parent / 'data_files' / 'temoa_basics_0.sql' + src_file = UTOPIA_SQL_FIXTURE input_file = tmp_path / src_file.name # Input file in writable tmp_path shutil.copy2(src_file, input_file) @@ -221,7 +222,7 @@ def test_cli_migrate_sql_file_auto_output_non_writable_input_dir_fallback_cwd( non_writable_mock_parent = tmp_path / 'mock_non_writable_input_parent' non_writable_mock_parent.mkdir() - src_file = Path(__file__).parent.parent / 'data_files' / 'temoa_basics_0.sql' + src_file = UTOPIA_SQL_FIXTURE input_file = non_writable_mock_parent / src_file.name shutil.copy2(src_file, input_file) @@ -270,7 +271,7 @@ def test_cli_migrate_sql_file_auto_output_no_writable_location( non_writable_mock_parent = tmp_path / 'mock_non_writable_input_parent_no_cwd' non_writable_mock_parent.mkdir() - src_file = Path(__file__).parent.parent / 'data_files' / 'temoa_basics_0.sql' + src_file = UTOPIA_SQL_FIXTURE input_file = non_writable_mock_parent / src_file.name shutil.copy2(src_file, input_file) @@ -317,7 +318,7 @@ def test_cli_migrate_unknown_type(tmp_path: Path) -> None: def test_cli_migrate_override_type(tmp_path: Path) -> None: """Test migrating with explicit type override.""" - input_file_src = Path(__file__).parent.parent / 'data_files' / 'temoa_basics_0.sql' + input_file_src = UTOPIA_SQL_FIXTURE input_file = tmp_path / 'test_input_override.sql' shutil.copy2(input_file_src, input_file) @@ -332,7 +333,7 @@ def test_cli_migrate_override_type(tmp_path: Path) -> None: def test_cli_migrate_sql_file_silent(tmp_path: Path) -> None: """Test migrating a SQL file with --silent flag.""" - input_file_src = Path(__file__).parent.parent / 'data_files' / 'temoa_basics_0.sql' + input_file_src = UTOPIA_SQL_FIXTURE input_file = tmp_path / 'test_input_silent.sql' shutil.copy2(input_file_src, input_file) @@ -375,7 +376,7 @@ def test_cli_migrate_sql_file_auto_output_non_writable_input_dir_fallback_cwd_si non_writable_mock_parent = tmp_path / 'mock_non_writable_input_parent_silent' non_writable_mock_parent.mkdir() - src_file = Path(__file__).parent.parent / 'data_files' / 'temoa_basics_0.sql' + src_file = UTOPIA_SQL_FIXTURE input_file = non_writable_mock_parent / src_file.name shutil.copy2(src_file, input_file) From 61f319c53fed9b9c6a8d932fc2c3f8d747c90ea2 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Mar 2026 11:34:02 -0400 Subject: [PATCH 516/587] Update anatomy of a constraint section to reflect current code --- docs/source/computational_implementation.rst | 221 ++++++++++++------- 1 file changed, 140 insertions(+), 81 deletions(-) diff --git a/docs/source/computational_implementation.rst b/docs/source/computational_implementation.rst index 24aef4ffa..cd4012eed 100644 --- a/docs/source/computational_implementation.rst +++ b/docs/source/computational_implementation.rst @@ -43,19 +43,18 @@ To help explain the Pyomo implementation, we discuss a single constraint in detail. Consider the :code:`Demand` :eq:`Demand` constraint: .. math:: - \sum_{I, T, V} \textbf{FO}_{r, p, s, d, i, t, v, dem} + - SEG_{s,d} \cdot \sum_{I, T^{a}, V} \textbf{FOA}_{r, p, i, t, v, dem} - \ge - {DEM}_{r, p, dem} \cdot {DSD}_{r, s, d, dem} + \sum_{I, T, V} \textbf{FOA}_{r, p, i, t, v, dem} + = + {DEM}_{r, p, dem} \\ - \forall \{r, p, s, d, dem\} \in \Theta_{\text{Demand}} + \forall \{r, p, dem\} \in \Theta_{\text{Demand}} Implementing this with Pyomo requires two pieces, and optionally a third: #. a constraint definition (in ``temoa/core/model.py``), #. the constraint implementation (in ``temoa/components/``), and - #. (optional) sparse constraint index creation (in ``temoa/components/technology.py``). + #. (optional) sparse constraint index creation (in ``temoa/components/``). We discuss first a straightforward implementation of this constraint, that specifies the sets over which the constraint is defined. We will follow it with @@ -69,8 +68,8 @@ A simple definition of this constraint is: .. code-block:: python :linenos: - M.demand_constraint = Constraint( - M.regions, M.time_optimize, M.time_season, M.time_of_day, M.commodity_demand, + self.demand_constraint = Constraint( + self.regions, self.time_optimize, self.commodity_demand, rule=demand_constraint ) @@ -95,25 +94,19 @@ is: .. code-block:: python :linenos: - def demand_constraint ( M, r, p, s, d, dem ): - if (r,p,s,d,dem) not in M.demand_specific_distribution.sparse_keys(): # If user did not specify this Demand, tell - return Constraint.Skip # Pyomo to ignore this constraint index. - - supply = sum( - M.v_flow_out[r, p, s, d, S_i, S_t, S_v, dem] - for S_t, S_v in M.commodity_up_stream_process[r, p, dem] if S_t not in M.tech_annual - for S_i in M.process_input_by_output[r, p, S_t, S_v, dem] - ) + def demand_constraint ( M, r, p, dem ): + if (r, p, dem) in M.singleton_demands: + return Constraint.Skip supply_annual = sum( M.v_flow_out_annual[r, p, S_i, S_t, S_v, dem] - for S_t, S_v in M.commodity_up_stream_process[r, p, dem] if S_t in M.tech_annual - for S_i in M.process_input_by_output[r, p, S_t, S_v, dem] - ) * value( M.segment_fraction[ s, d]) + for S_t, S_v in M.commodity_up_stream_process[r, p, dem] + for S_i in M.process_inputs_by_output[r, p, S_t, S_v, dem] + ) - demand_constraintErrorCheck(supply + supply_annual, r, p, s, d, dem) + demand_constraint_error_check(supply_annual, r, p, dem) - expr = supply + supply_annual == M.Demand[r, p, dem] * M.demand_specific_distribution[r, s, d, dem] + expr = supply_annual == value( M.demand[r, p, dem] ) return expr ... @@ -126,10 +119,9 @@ this to just :code:`M`) followed by local variable names in which to store the index set elements passed by Pyomo. Note that the ordering is the same as specified in the constraint definition. Thus the first item after :code:`M` will be an item from :code:`region`, the second from :code:`time_optimize`, -the third from :code:`time_season`, fourth from :code:`time_of_day`, and the -fifth from :code:`commodity_demand`. Though one could choose :code:`a`, :code:`b`, -:code:`c`, :code:`d`, and :code:`e` (or any naming scheme), we chose :code:`p`, :code:`s`, -:code:`d`, and :code:`dem` as part of a :ref:`naming scheme +and the third from :code:`commodity_demand`. Though one could choose :code:`a`, +:code:`b`, and :code:`c` (or any naming scheme), we chose :code:`r`, :code:`p`, +and :code:`dem` as part of a :ref:`naming scheme ` to aid in mnemonic understanding. Consequently, the rule signature (Line 1) is another place to look to discover what indices define a constraint. @@ -137,23 +129,18 @@ constraint. Lines 2 and 3 are an indication that this constraint is implemented in a non-sparse manner. That is, Pyomo does not inherently know the valid indices for a given model parameter or equation. In ``temoa.core.model``, the constraint definition -listed five index sets, so Pyomo will naively call this function for every -possible combination of tuple :math:`\{r, p, s, d, dem\}`. However, as there -may be slices for which a demand does not exist (e.g., the winter season might -have no cooling demand), there is no need to create a constraint for any tuple -involving 'winter' and 'cooling'. Indeed, an attempt to access a demand for -which the modeler has not specified a value results in a Pyomo error, so it is -necessary to ignore any tuple for which no Demand exists. - -Lines 5 through 11 represent two *source-lines* that we split over several lines for -clarity. These lines implement the summations of the demand commodity ``dem`` -produced by demand technologies with both variable and constant output across the -year, summed over all relevant technologies, vintages, and the inputs. The -:code:`supply` and :code:`supply_annual` are local variables used in the expression +listed three index sets, so Pyomo will naively call this function for every +possible combination of tuple :math:`\{r, p, dem\}`. However, as there +may be region-period-demand combinations for which no technology can supply +the demand, there is no need to create a constraint for such tuples. + +Lines 5 through 8 sum the annual output flow of demand commodity ``dem`` +across all technologies and vintages. The +:code:`supply_annual` is a local variable used in the expression (:code:`expr`) shown below. Note that the sum is performed with sparse indices, which -are returned from dictionaries created in :code:`temoa/components/technology.py`. +are returned from dictionaries created in :code:`temoa/components/`. -Lines 5 through 11 also showcase a very common idiom in Python: +Lines 5 through 8 also showcase a very common idiom in Python: list-comprehension. List comprehension is a concise and efficient syntax to create lists. As opposed to building a list element-by-element with for-loops, list comprehension can convert many statements into a single operation. @@ -162,9 +149,9 @@ Consider a naive approach to calculating the supply:: to_sum = list() for S_t in M.tech_all: for S_v in M.vintage_all: - for S_i in process_input_by_output( p, S_t, S_v, dem ): - to_sum.append( M.v_flow_out[p, s, d, S_i, S_t, S_v, dem] ) - supply = sum( to_sum ) + for S_i in process_inputs_by_output( r, p, S_t, S_v, dem ): + to_sum.append( M.v_flow_out_annual[r, p, S_i, S_t, S_v, dem] ) + supply_annual = sum( to_sum ) This implementation creates an extra list (:code:`to_sum`), then builds the list element by element with :code:`.append()`, before finally calculating the summation. @@ -175,11 +162,11 @@ A less naive approach would replace the :code:`.append()` call with the :code:`+=` operator, reducing the number of iterations through the elements to one:: - supply = 0 + supply_annual = 0 for S_t in M.tech_all: for S_v in M.vintage_all: - for S_i in process_input_by_output( p, S_t, S_v, dem ): - supply += M.v_flow_out[p, s, d, S_i, S_t, S_v, dem] + for S_i in process_inputs_by_output( r, p, S_t, S_v, dem ): + supply_annual += M.v_flow_out_annual[r, p, S_i, S_t, S_v, dem] Why is list comprehension necessary? Strictly speaking, it is not, especially in light of this last example, which may read more familiar to those comfortable @@ -189,10 +176,10 @@ the more efficient route for many list manipulations. (It also *may* seem slightly more familiar to those used to a more mainstream algebraic modeling language.) -With the correct model variables summed and stored in the ``supply`` and -``supply_annual`` variables, Line 17 calls a function defined in -:code:`temoa/components/technology.py` that checks to make sure there is technology -that can supply each demand commodity ``dem`` in each :math:`\{r, p, s, d\}`. +With the correct model variables summed and stored in the +``supply_annual`` variable, Line 10 calls a function defined in +:code:`temoa/components/commodities.py` that checks to make sure there is a technology +that can supply each demand commodity ``dem`` in each :math:`\{r, p\}`. If no process supplies the demand, then it quits computation immediately rather than completing a potentially lengthy model generation and waiting for the @@ -202,11 +189,11 @@ benefits of Temoa: we've incorporated error handling in several places to try and capture the most common user errors. This capability is subtle, but in practice extremely useful while building and debugging a model. -Line 19 creates the actual inequality comparison. This line is superfluous, but -we leave it in the code as a reminder that inequality operators (i.e. :code:`<=` -and :code:`>=`) with a Pyomo object (like supply) generate a Pyomo *expression -object*, not a boolean True or False as one might expect.\ [#return_expression]_ -It is this expression object that must be returned to Pyomo, as on Line 20. +Line 12 creates the actual equality comparison. This line is superfluous, but +we leave it in the code as a reminder that comparison operators (i.e. :code:`==`, +:code:`<=`, :code:`>=`) with a Pyomo object (like supply_annual) generate a Pyomo +*expression object*, not a boolean True or False as one might expect.\\ [#return_expression]_ +It is this expression object that must be returned to Pyomo, as on Line 13. In the above implementation, the constraint is called for every tuple in the Cartesian product of the indices, and the constraint must then decide whether @@ -215,47 +202,119 @@ because it only calls the constraint rule for the valid tuples within the Cartesian product, which is computationally more efficient than the simpler implementation above. -.. topic:: in ``temoa/core/model.py`` (actual implementation) +.. topic:: in ``temoa/core/model.py`` (declaration of indices, parameter, and constraint) .. code-block:: python :linenos: - M.demand_constraint_rpsdc = Set( dimen=5, rule=demand_constraint_indices ) - # ... - M.demand_constraint = Constraint( M.demand_constraint_rpsdc, rule=demand_constraint ) + self.demand_constraint_rpc = Set( + within=self.regions * self.time_optimize * self.commodity_demand + ) + self.demand = Param(self.demand_constraint_rpc) + + ... + + self.demand_constraint = Constraint( + self.demand_constraint_rpc, rule=commodities.demand_constraint + ) As discussed above, the demand_constraint is only valid for certain -:math:`\{r, p, s, d, dem\}` tuples. Since the modeler can specify the demand -distribution per commodity (necessary to model demands like heating, that do not -apply in all time slices), Temoa must ascertain the valid tuples. We have -implemented this logic in the function :code:`demand_constraint_indices` in -``temoa/components/technology.py``. Thus, Line 1 tells Pyomo to instantiate -:code:`demand_constraint_rpsdc` as a Set of 5-length tuples indices -(:code:`dimen=5`), and populate it with what Temoa's rule -:code:`demand_constraint_indices` returns. We omit here an explanation of the -implementation of the :code:`demand_constraint_indices` function, stating merely -that it returns the exact indices over which the demand_constraint must to be -created. With the sparse set :code:`demand_constraint_rpsdc` created, we can now -can use it in place of the five sets specified in the non-sparse +:math:`\{r, p, dem\}` tuples. Since not all combinations of region, period, and +demand commodity may be valid, Temoa must ascertain the valid tuples. +Thus, Line 1 tells Pyomo to instantiate +:code:`demand_constraint_rpc` as a Set of 3-length tuple indices +within the dimensions of the :code:`regions`, :code:`time_optimize`, and +:code:`commodity_demand` sets, and populate it only with entries loaded from +the database. Demand values are stored in the parameter :code:`self.demand` declared in line 4. +Data from the database is loaded into this index set and parameter via the +:code:`HybridLoader` class in :code:`temoa/data_io/hybrid_loader.py`, declared in +the :code:`component_manifest.py` file. + +.. topic:: in ``temoa/data_io/hybrid_loader.py`` (telling Temoa to load the indices) + + .. code-block:: python + :linenos: + + def load_param_idx_sets(self, data: dict[str, object]) -> dict[str, object]: + + model = TemoaModel() + param_idx_sets = { + ... + model.demand.name: model.demand_constraint_rpc.name, # param index sets + ... + } + +.. topic:: in ``temoa/data_io/component_manifest.py`` (telling Temoa to load the parameter) + + .. code-block:: python + :linenos: + + def build_manifest(model: TemoaModel) -> list[LoadItem]: + + manifest = [ + ... + LoadItem( + component=model.demand, # param name + table='demand', # database table name + columns=['region', 'period', 'commodity', 'demand'], # indices and value column + ), + ... + ] + +Alternatively, this index set could be populated using an index function +which determines the valid indices from other model components. This second method is needed +when the indices of a constraint do not exactly align with the indices of the database +table. For example, the database table :code:`ramp_up_hourly` is indexed by :code:`region`, +:code:`tech` in the database but one of its inheriting constraints, +:code:`ramp_up_day_constraint`, is indexed by :code:`region`, :code:`period`, +:code:`season`, :code:`time_of_day`, :code:`tech`, :code:`vintage` in the model. In this case, +an index function is needed to determine the valid indices for the constraint. + +.. topic:: in ``temoa/core/model.py`` (index set and constraint declaration) + + .. code-block:: python + :linenos: + + self.ramp_up_day_constraint_rpsdtv = Set( + dimen=6, initialize=operations.ramp_up_day_constraint_indices + ) + self.ramp_up_day_constraint = Constraint( + self.ramp_up_day_constraint_rpsdtv, rule=operations.ramp_up_day_constraint + ) + +.. topic:: in ``temoa/components/operations.py`` (return valid indices) + + .. code-block:: python + :linenos: + + def ramp_up_day_constraint_indices(model: TemoaModel): + indices = { + (r, p, s, d, t, v) + for r, p, t in model.ramp_up_vintages + for v in model.ramp_up_vintages[r, p, t] + for s in model.time_season + for d in model.time_of_day + } + return indices + +With the sparse set (:code:`demand_constraint_rpc` or :code:`ramp_up_day_constraint_rpsdtv`) +created, we can now can use it in place of the sets specified in the non-sparse implementation. Pyomo will now call the constraint implementation rule the minimum number of times. -On the choice of the :code:`_rpsdc` suffix for the index set name, there is no +On the choice of the :code:`_rpc` suffix for the index set name, there is no Pyomo-enforced restriction. However, use of an index set in place of the non-sparse specification obfuscates over what indexes a constraint is defined. While it is not impossible to deduce, either from this documentation -or from looking at the :code:`demand_constraint_indices` or +or from looking at the index function or :code:`demand_constraint` implementations, the Temoa convention includes index set names that feature the one-character representation of each set dimension. -In this case, the name :code:`demand_constraint_rpsdc` implies that this set has a -dimensionality of 5, and (following the :ref:`naming scheme +In this case, the name :code:`demand_constraint_rpc` implies that this set has a +dimensionality of 3, and (following the :ref:`naming scheme `) the first index of each tuple will be an element of -:code:`region`, the second an element of :code:`time_optimize`, the third -an element of :code:`time_season`, fourth an element of :code:`time_of_day`, -and fifth a commodity. From the contextual information that this is the -Demand constraint, one can assume that the ``c`` represents an element from -:code:`commodity_demand`. +:code:`region`, the second an element of :code:`time_optimize`, +and third a demand commodity. From 67ded401995ccb57cba10171ff92fdf9e8d418e0 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Mar 2026 11:35:26 -0400 Subject: [PATCH 517/587] Update some changed references in computational_implementation --- docs/source/computational_implementation.rst | 26 ++++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/source/computational_implementation.rst b/docs/source/computational_implementation.rst index cd4012eed..cc5a66659 100644 --- a/docs/source/computational_implementation.rst +++ b/docs/source/computational_implementation.rst @@ -329,19 +329,19 @@ look like: .. code-block:: ampl - s.t. demand_constraint{(p, s, d, dem) in sDemand_psd_dem} : - sum{(p, s, d, Si, St, Sv, dem) in sFlowVar_psditvo} - v_flow_out[p, s, d, Si, St, Sv, dem] + s.t. demand_constraint{(r, p, dem) in sDemand_rpc} : + sum{(r, p, Si, St, Sv, dem) in sFlowVar_rpitvo} + v_flow_out_annual[r, p, Si, St, Sv, dem] = - pDemand[p, s, d, dem]; + pDemand[r, p, dem]; While the syntax is not a direct translation, the indices of the constraint -(``p``, ``s``, ``d``, and ``dem``) are clear, and by inference, so are the -indices of summation (``i``, ``t``, ``v``) and operand (``v_flow_out``). This -one-line definition creates an inequality for each period, season, time of day, -and demand, ensuring that total output meets each demand in each time slice -- +(``r``, ``p``, and ``dem``) are clear, and by inference, so are the +indices of summation (``i``, ``t``, ``v``) and operand (``v_flow_out_annual``). This +one-line definition creates an equality for each region, period, and +demand, ensuring that total annual output meets each demand -- almost exactly as we have formulated the demand constraint :eq:`Demand`. In -contrast, Temoa's implementation in Pyomo takes 47 source-lines (the code +contrast, Temoa's implementation in Pyomo takes many more source-lines (the code discussed above does not include the function documentation). While some of the verbosity is inherent to working with a general purpose scripting language, and most of it is our formatting for clarity, the absolute minimum number of lines a @@ -354,7 +354,7 @@ reasons: tools (e.g. numpy, matplotlib) that are not as cleanly available to other AMLs. For instance, there is minimal capability in MathProg to error check a model before a solve, and providing interactive feedback like what Temoa's - demand_constraintErrorCheck function does is difficult, if not impossible. + :code:`demand_constraint_error_check` function does is difficult, if not impossible. While a subtle addition, specific and directed error messages are an effective measure to reduce the learning curve for new modelers. @@ -380,12 +380,12 @@ reasons: This last point is somewhat esoteric, but consider the MathProg implementation of the Demand constraint in contrast with the last line of the Pyomo version:: - expr = (supply = M.Demand[p, s, d, dem]) + expr = supply_annual == value( M.demand[r, p, dem] ) While the MathProg version indeed translates more directly to standard notation, consider that standard notation itself needs extensive surrounding text to explain the significance of an equation. *Why* does the equation compare the -sum of a subset of FlowOut to Demand? In Temoa's implementation, a high-level +sum of annual flows to Demand? In Temoa's implementation, a high-level understanding of what a constraint does requires only the last line of code: "Supply must meet demand." @@ -499,7 +499,7 @@ The Temoa model code is organized into clear, purpose-driven packages: * ``reserves.py`` - Reserve margin requirements * ``limits.py`` - Various limit constraints (capacity, activity, emissions, etc.) * ``storage.py`` - Energy storage constraints - * ``ramping.py`` - Ramping constraints for generators + * ``operations.py`` - Baseload and ramping constraints for generators * Additional constraint modules for specific features * ``temoa.data_io`` - Data loading and validation From 2c2df6ff9f529ee6f16009a9d8c21e3c4ac71f5b Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Mar 2026 12:07:24 -0400 Subject: [PATCH 518/587] Update treatment of time for many new changes --- docs/source/mathematical_formulation.rst | 129 +++++++++++++++++++---- 1 file changed, 109 insertions(+), 20 deletions(-) diff --git a/docs/source/mathematical_formulation.rst b/docs/source/mathematical_formulation.rst index de0734e40..4c3c3fc59 100644 --- a/docs/source/mathematical_formulation.rst +++ b/docs/source/mathematical_formulation.rst @@ -207,32 +207,118 @@ and demand is balanced at each of these levels: * **Periods** - consecutive blocks of years, marked by the first year in the period. For example, a two-period model might consist of :math:`\text{P}^f = - \{2010, 2015, 2025\}`, representing the two periods of years from beginning 2010 - through 2014 end, and from beginning 2015 through 2024 end. Note the that last period element - \(2025\) does not represent a new time period, but rather defines the end of the second time + \{2010, 2015, 2025\}`, representing the two periods of years from 2010 + to 2015, and from 2015 to 2025. It is up to the model builder whether this represents start + of year to start of year or end of year to end of year. Note that the last period element + (2025) does not represent a new time period, but rather defines the end of the second time period and therefore the planning horizon. - * **Seasonal** - Each year may have multiple seasons. In a conventional time-sliced - model, the seasons may typically represent the four seasons: winter, spring summer, - and fall. However, the seasonal slices can represent any amount of time at the - sub-period scale. For example, in a database with representative days, the seasonal - slices can be used as generic containers to represent blocks of days. The type of - seasonal representation in use should be defined in the config file. + * **Seasonal** - Each year is divided into one or more seasons. What a "season" + represents depends on the :code:`time_sequencing` mode chosen in the configuration + file (see below). Each season carries a :code:`segment_fraction` value in the + :code:`time_season` table specifying the fraction of the year it represents. - * **Daily** - Within a season, a given day can be further subdivided into different - time segments. Less detailed databases may include larger blocks of time, such as morning, - afternoon, and night. In a database with representative days, each daily segment can - be used to represent every hour of the day. + * **Daily** - Within each season, the day is subdivided into one or more + time-of-day segments. Each segment has an associated :code:`hours` value in the + :code:`time_of_day` table indicating how many hours it represents (e.g. 8 hours for + "Day", 16 hours for "Night"). Less detailed databases may use a single segment + covering the full day. -We use the word 'slice' to refer to the tuple of season and time of day -:math:`\{s,d\}`. Note that these time slices are user-defined, and can -represent time ranging from large blocks of time (e.g., winter-night) to every -hour in a given season. +We use the word 'slice' or 'timeslice' to refer to the tuple of season and time of day +:math:`\{s,d\}`. The fraction of a year represented by each slice is computed +automatically: +.. math:: + + SEG_{s,d} = \text{segment\_fraction\_per\_season}(s) \;\times\; \frac{\text{hours}(d)} + {\sum_{d'} \text{hours}(d')} + +The sum of :math:`SEG_{s,d}` over all :math:`(s,d)` pairs must equal 1. + +Time Sequencing Modes +~~~~~~~~~~~~~~~~~~~~~ + +Temoa v4 supports four modes for interpreting the meaning and ordering of seasons, +controlled by the :code:`time_sequencing` setting in the configuration TOML file: + + * **consecutive_days** — Each season represents a single day, and the seasons are + treated as consecutive days in order. Use this when modeling e.g., a representative + week (7 seasons) or a full year (365 seasons). Inter-season state (e.g. for + storage) carries forward naturally from one season to the next, so the + :code:`time_season_sequential` table can be left empty (more on that below). + + * **seasonal_timeslices** *(default)* — Each season represents a sequential slice of + the year containing one or many days (e.g. Winter, Spring, Summer, Fall). The + true chronological sequence is assumed to follow the :code:`time_season` ordering, + so the :code:`time_season_sequential` table can be left empty. This is the + traditional Temoa time representation. + + * **representative_periods** — Each season represents a block of days that may not + be contiguous in time (e.g. a "typical summer weekday" drawn from several months). + If the model uses inter-season constraints such as seasonal storage or + inter-season ramping, the true chronological sequence must be defined in the + :code:`time_season_sequential` table. Technologies using seasonal storage must + also be flagged in the :code:`technology` table. + + * **manual** — The sequence of time slices is defined explicitly by the modeler in + an optional :code:`time_manual` table. This is an advanced feature provided in + case none of the above modes are suitable, and is not recommended for most users. + +The selected mode, in combination with the sequence of the :code:`time_season` and +:code:`time_of_day` tables, is +used to construct the :code:`time_next` dictionary, which maps each :math:`(s,d)` time +slice to its successor in the chronological sequence, :math:`(s_{next}, d_{next})`. + +The :code:`days_per_period` configuration setting (default: 365) specifies how many +days each planning period's representative year encompasses. This is used to scale +flow variables correctly. For example, reduce it to 7 when modeling a single +representative week. + +Time Season Sequential +~~~~~~~~~~~~~~~~~~~~~~ + +When using the **representative_periods** time sequencing mode, the seasons in +:code:`time_season` may represent non-contiguous blocks of time (e.g. a "typical +summer weekday" drawn from several calendar months). For constraints that depend +on inter-season ordering — seasonal storage and inter-season ramping — the model +needs to know the true chronological sequence showing how the representative seasons +are stitched together to form a complete year. + +The :code:`time_season_sequential` table provides this mapping. Each row defines +a *sequential season* (:code:`seas_seq`) that references one of the +:code:`time_season` entries and carries its own :code:`segment_fraction` and an +integer :code:`sequence` column that determines the chronological order. Because +the same representative season may appear more than once in the reconstructed year +(e.g. "typical summer weekday" could appear for June, July, and August), the sequential table can +contain multiple entries that map back to the same :code:`time_season` row, each +with its own fraction. + +From this table Temoa builds two internal dictionaries: + +* :code:`time_next_sequential` — maps each sequential season to its successor, + forming a circular chain that represents the annual cycle. +* :code:`sequential_to_season` — maps each sequential season back to its parent + representative season in :code:`time_season`. + +These dictionaries are consumed by: + +* The **seasonal storage energy constraint**, which chains the storage state of + charge across sequential seasons in chronological order. +* The **ramp up/down season constraints**, which limit the rate of activity change + at season boundaries that are adjacent in the sequential ordering but not + necessarily adjacent in the :code:`time_season` set. + +For the **consecutive_days** and **seasonal_timeslices** modes, the +:code:`time_season_sequential` table may be left empty — the model derives the +chronological order directly from the :code:`time_season` set. + + +Periods +~~~~~~~ There are two specifiable period sets: :code:`time_exist` (:math:`\text{P}^e`) and :code:`time_future` (:math:`\text{P}^f`). The :code:`time_exist` set contains periods before :code:`time_future`. Its primary purpose is to specify -the vintages for capacity that exist prior to the model optimization. +the vintages for capacity that exists prior to the model optimization. The :code:`time_future` set contains the future periods that the model will optimize. As this set must contain only integers, Temoa interprets the elements to be the boundaries of each period of interest. Thus, this is an ordered set @@ -250,7 +336,7 @@ Temoa assumes that all elements of the :code:`time_exist` and ordered, such that the minimum element is "naught". For example, if :math:`\text{P}^f = \{2015, 2020, 2030\}`, then :math:`P_0 = 2015`. In other words, the capital :math:`\text{P}` with the naught subscript indicates -the first element in the :code:`time_future` set. +the first element in the :code:`time_future` set. One final note on periods: rather than optimizing each year within a period individually, Temoa makes the simplifying assumption that each time period contains @@ -282,7 +368,10 @@ delineation. As noted above, Temoa allows the modeler to subdivide each year into a set of time slices, comprised of a season and a time of day. Unlike :code:`time_future`, there is no restriction on what labels the modeler may assign to the :code:`time_season` -and :code:`time_of_day` set elements. +and :code:`time_of_day` set elements. Each season carries a +:code:`segment_fraction` (fraction of the year), and each time-of-day segment +carries an :code:`hours` value. These are combined to compute the +:code:`segment_fraction` for each :math:`(s,d)` slice as described above. Sets ---- From d39f8698199635fdb54c08f9602bf63389f1ebae Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Mar 2026 13:21:40 -0400 Subject: [PATCH 519/587] AI assisted mega-audit of param and variable descriptions --- docs/source/mathematical_formulation.rst | 759 ++++++++++++----------- 1 file changed, 411 insertions(+), 348 deletions(-) diff --git a/docs/source/mathematical_formulation.rst b/docs/source/mathematical_formulation.rst index 4c3c3fc59..3dd4c8fdd 100644 --- a/docs/source/mathematical_formulation.rst +++ b/docs/source/mathematical_formulation.rst @@ -50,8 +50,6 @@ utilizes these parameters, along with the associated technology-specific decisio variables for capacity and activity, to create the objective function and constraints that are used during the optimization process. -.. _Sets: - Temoa Notation -------------- @@ -100,7 +98,7 @@ represents a single item from :math:`T`. .. math:: \left ( - \text{CFP}_{r, t, v} + \text{CFP}_{r, s, d, t, v} \cdot \text{C2A}_{r, t} \cdot \text{SEG}_{s, d} \right ) @@ -157,9 +155,9 @@ Python code and database schema. ":math:`{}^*\text{P}^o`",":code:`time_optimize`",":math:`\mathbb{Z}`","model time periods to optimize; (:math:`\text{P}^f - \text{max}(\text{P}^f)`)" ":math:`\text{R}`",":code:`regions`","string","distinct geographical regions" ":math:`{}^*\text{V}`",":code:`vintage_all`",":math:`\mathbb{Z}`","possible tech vintages; (:math:`\text{P}^e \cup \text{P}^o`)" - ":math:`\text{S}`",":code:`time_season`","string","seasonal divisions (e.g. winter, summer)" - ":math:`\text{D}`",":code:`time_of_day`","string","time-of-day divisions (e.g. morning)" - ":math:`{}^*\text{T}`",":code:`tech_all`","string","all technologies to be modeled; (:math:`{T}^r \cup {T}^p`)" + ":math:`\text{S}`",":code:`time_season`","string","seasonal divisions (e.g. winter, summer); each entry carries a :code:`segment_fraction` giving its share of the year" + ":math:`\text{D}`",":code:`time_of_day`","string","time-of-day divisions (e.g. morning); each entry carries an :code:`hours` value (default 1)" + ":math:`{}^*\text{T}`",":code:`tech_all`","string","all technologies to be modeled (all technologies are currently production-type: :math:`T = T^p`)" ":math:`\text{T}^u`",":code:`tech_unlim_cap`","string","technologies that have no bound on capacity, and can have variable costs only (imports, taxes, etc.); (:math:`{T}^u \subset (T - T^{res})`)" ":math:`\text{T}^a`",":code:`tech_annual`","string","technologies that produce constant annual output; (:math:`{T}^a \subset T`)" ":math:`\text{T}^b`",":code:`tech_baseload`","string","baseload electric generators; (:math:`{T}^b \subset T`)" @@ -386,7 +384,7 @@ detailed description of each. .. include:: param_desc_and_tables.rst efficiency -^^^^^^^^^^ +~~~~~~~~~~ :math:`{EFF}_{r \in R, i \in C_p, t \in T, v \in V, o \in C_c}` @@ -401,20 +399,33 @@ efficiency table,\ [#efficiency_table]_ Temoa assumes it is not a valid process and will provide the user a warning with pointed debugging information. +efficiency_variable +~~~~~~~~~~~~~~~~~~~ + +:math:`{EFF}_{r \in R, s \in S, d \in D, i \in C_p, t \in T, v \in V, o \in C_c}` + +When a technology's conversion efficiency varies by time of day or season — for +example, a heat pump whose efficiency differs with temperature — the +modeler can use :code:`efficiency_variable` to specify these time-slice-dependent +efficiency values. If not specified for a given process, it defaults to 1, +meaning the base :code:`efficiency` value applies uniformly. Note that there is +no period index: the time-varying efficiency applies to all periods. + + .. _capacity_factor_tech: capacity_credit -^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~ :math:`{CC}_{r \in R, p \in P, t \in T, v \in V}` The capacity credit represents the fraction of total installed capacity of a process that can be relied upon during the time slice in which peak -electricity demand occurs. This parameter is used in the :math:`reserve_margin` -constraint. +electricity demand occurs. This parameter is used in the 'static' version of +the :math:`reserve_margin` constraint. capacity_factor_tech -^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~ :math:`{CFT}_{r \in R, s \in S, d \in D, t \in T}` @@ -422,7 +433,7 @@ Temoa indexes the :code:`capacity_factor_tech` parameter by season, time-of-day, and technology. capacity_factor_process -^^^^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~~~~ :math:`{CFP}_{r \in R, s \in S, d \in D, t \in T, v \in V}` @@ -434,7 +445,7 @@ season, time-of-day, technology, and vintage. capacity_to_activity -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :math:`{C2A}_{r \in R, t \in T}` @@ -465,7 +476,7 @@ used 100% of the time?" cost_fixed -^^^^^^^^^^ +~~~~~~~~~~ :math:`{CF}_{r \in R, p \in P, t \in T, v \in V}` @@ -483,7 +494,7 @@ Cap}`). cost_invest -^^^^^^^^^^^ +~~~~~~~~~~~ :math:`{CI}_{r \in R, t \in T, v \in P}` @@ -496,7 +507,7 @@ only used in the default objective function (:math:`\tfrac{Dollars}{Unit Cap}`). cost_variable -^^^^^^^^^^^^^ +~~~~~~~~~~~~~ :math:`{CV}_{r \in R, p \in P,t \in T,v \in V}` @@ -505,8 +516,19 @@ of activity. Thus the incurred variable costs are proportional to the activity of the process. +cost_emission +~~~~~~~~~~~~~ + +:math:`{CE}_{r \in R, p \in P, e \in C^e}` + +The :code:`cost_emission` parameter specifies a cost per unit of emission +for a given emissions commodity in each period. This allows the modeler to +penalize emission production, for example via a carbon tax. The cost is +applied to total emissions of commodity :math:`e` in period :math:`p`. + + construction_input -^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~ :math:`{CON}_{r \in R, i \in C^p,t \in T \setminus T^u,v \in V}` @@ -519,7 +541,7 @@ period. .. _demand: demand -^^^^^^ +~~~~~~ :math:`{DEM}_{r \in R, p \in P, c \in C^d}` @@ -529,59 +551,26 @@ parameter, this parameter is the most important because without it, the rest of model has no incentive to build anything. This parameter specifies the end-use demands that appear at the far right edge of the system diagram. -To specify the distribution of demand, look to the -:code:`demand_default_distribution` (DDD) and :code:`demand_specific_distribution` -(DSD) parameters. - -As a historical note, this parameter was at one time also indexed by season and -time of day, allowing modelers to specify exact demands for every time slice. -However, while extremely flexible, this proved too tedious to maintain for any -data set of appreciable size. Thus, we implemented the DDD and DSD parameters. - - -.. _DDD: - -demand_default_distribution -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:math:`{DDD}_{s \in S, d \in D}` - -**Note**: The Demand Specific Distribution is currently not supported in -the project. Modelers should use the DSD or rely on a "flat" distribution default -from the time_segment_fraction. - -By default, Temoa assumes that end-use demands (:ref:`Demand`) are evenly -distributed throughout a year. In other words, the Demand will be apportioned -by the :code:`segment_fraction` parameter via: - -.. math:: - - \text{EndUseDemand}_{s, d, c} = {segment_fraction}_{s, d} \cdot {Demand}_{p, c} - -Temoa enables this default action by automatically setting DDD equivalent to -:code:`segment_fraction` for all seasons and times of day. If a modeler would like a -different default demand distribution, the indices and values of the DDD -parameter must be specified. Like the :ref:`segment_fraction` parameter, the sum of -DDD must be 1. +To specify a non-uniform distribution of demand across time slices, use the +:code:`demand_specific_distribution` (DSD) parameter, described next. demand_specific_distribution -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :math:`{DSD}_{r \in R, s \in S, d \in D, c \in C^d}` If there is an end-use demand that varies over the course of a day or across seasons -- for example, heating or cooling in the summer or winter -- the modeler may specify the fraction of annual demand occurring in each time slice. -Like :ref:`segment_fraction` and :ref:`DDD`, the sum of DSD for each :math:`c` must be 1. -If the modeler does not define DSD for a season, time of day, and demand -commodity, Temoa automatically populates this parameter according to DDD. -It is this parameter that is actually multiplied by the :code:`Demand` parameter -in the Demand constraint. +The sum of DSD for each demand commodity :math:`c` must be 1. +If the modeler does not define DSD for a demand commodity, Temoa automatically +populates it using the :code:`segment_fraction` values, resulting in a uniform +(flat) distribution proportional to the length of each time slice. emission_activity -^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~ :math:`{EAC}_{e \in C_e,\{r,i,t,v,o\} \in \Theta_{\text{efficiency}}}` @@ -596,7 +585,7 @@ to account for emissions per unit activity, but it more accurately describes emission_embodied -^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~ :math:`{EE}_{r \in R,t \in T \setminus T^u, v \in V,e \in C_e}` @@ -606,7 +595,7 @@ over each year in the deployment vintage. emission_end_of_life -^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~ :math:`{EEOL}_{r \in R,t \in T \setminus T^u, v \in V,e \in C_e}` @@ -616,7 +605,7 @@ life occur evenly over years in that period. end_of_life_output -^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~ :math:`{EOLO}_{r \in R,t \in T \setminus T^u, v \in V,o \in C_p}` @@ -625,127 +614,84 @@ capacity rather than production of capacity. Assumes that retirement or end of life occur evenly over years in that period. -.. limit_emission -.. ^^^^^^^^^^^^^ - -.. :math:`{LE}_{r \in R, p \in P, e \in C^e}` - -.. The :code:`emission_limit` parameter ensures that Temoa finds a solution that -.. fits within the modeler-specified limit of emission :math:`e` in time period -.. :math:`p`. - - existing_capacity -^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~ :math:`{ECAP}_{r \in R, t \in T, v \in \text{P}^e}` The :code:`existing_capacity` parameter defines the capacity installed prior to the -beginning of :code:`time_optimize`. Note that processes with existing capacity -require all of the engineering-economic characteristics of a standard process, -with the exception of an investment cost. - -retired_capacity -^^^^^^^^^^^^^^^^ - -:math:`{ECAP}_{r \in R, t \in T, v \in \text{P}^e}` - -The :code:`existing_capacity` parameter defines the capacity installed prior to the -beginning of :code:`time_optimize`. Note that processes with existing capacity -require all of the engineering-economic characteristics of a standard process, -with the exception of an investment cost. +beginning of :code:`time_optimize`. Note that processes with existing capacity that +would survive into future periods require all of the engineering-economic +characteristics of a standard process, with the exception of an investment cost. .. _GDR: global_discount_rate -^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~ :math:`{GDR}` -The :code:`GDR` parameter represents the global discount rate used to convert -cash flows in future model time periods into a present value. The future value -(FV) of a sum of currency is related to the net present value (NPV) via the +The :code:`global_discount_rate` parameter represents the global discount rate used to convert +cash flows in future model time periods into a present value. The net present value +(NPV) of a cashflow is related to its future value (FV) via the formula: .. math:: - \text{FV} = \text{NPV} \cdot {(1 + GDR)^n} + \text{NPV} = \frac{\text{FV}}{(1 + GDR)^n} where :math:`n` is in years. This parameter is used to calculate all discounted costs, which are the basis of the objective function. Costs are discounted to the -first future time period in the model by default. If running a Myopic run, the -discount base year can be set in the metadata table. This is the :code:`myopic_base_year`. +first future time period in the model. The output in the :code:`output_cost` table shows both discounted and non-discounted (raw) -values for all model costs. Of note, all loan costs are displayed as an annuity cost in -the vintage year, not as a string of payments. - -The Global Discount Rate is entered in the metadata_real table in the database. - -growth_rate_max -^^^^^^^^^^^^^^^ - -:math:`{GRM}_{r \in R, t \in T}` - -The :code:`GRM` parameter defines the maximum annual rate at which the capacity of -a given technology can grow. Note that the growth rate is not defined by vintage, -but rather across all vintages of a given technology. - - -growth_rate_seed -^^^^^^^^^^^^^^^^ - -:math:`{GRS}_{r \in R, t \in T}` - -The :code:`GRS` parameter defines the maximum capacity of a given technology when -first installed in a given time period. The growth rate is applied to this initial -capacity seed in subsequent time periods. +values for all model costs. +The :code:`global_discount_rate` is entered in the metadata_real table in the database. loan_lifetime_process -^^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~~ :math:`{LLP}_{r \in R, t \in T, v \in P}` -**Note**: :code:`LifetimeLoanProcess` is currently not supported in the database. -Modelers should use the :code:`loan_lifetime_tech` below. - Temoa gives the modeler the ability to separate the loan lifetime from the useful life of a process. This parameter specifies the loan term associated with capital investment in a process, in years. If not specified, the model -assigns the technology lifetime to the loan period in :code:`temoa/components/technology.py`. +assigns the technology lifetime to the loan period. -loan_lifetime_tech -^^^^^^^^^^^^^^^^^^ +lifetime_process +~~~~~~~~~~~~~~~~ -:math:`{LLT}_{r \in R, t \in T}` +:math:`{LTP}_{r \in R, t \in T, v \in P}` -Same as the :code:`loan_lifetime_process` but without the vintage index. If all -vintages of a given technology are assumed to have the same loan term, then -:code:`loan_lifetime_tech` can be defined instead of :code:`loan_lifetime_process`. +This parameter specifies the total useful life of a given process in years. -lifetime_process -^^^^^^^^^^^^^^^^ +lifetime_survival_curve +~~~~~~~~~~~~~~~~~~~~~~~ -:math:`{LTP}_{r \in R, t \in T, v \in P}` +:math:`{LSC}_{r \in R, p \in P, t \in T, v \in V}` -This parameter specifies the total useful life of a given process in years. +The :code:`lifetime_survival_curve` parameter represents the surviving fraction +of original capacity for a given process at a given period. It allows the modeler +to specify gradual capacity loss over time rather than abrupt retirement +at end of life. Values should be between 0 and 1, where 1 means full survival. lifetime_tech -^^^^^^^^^^^^^ +~~~~~~~~~~~~~ :math:`{LTT}_{r \in R, t \in T}` -Similar to lifetime_process, this parameter specifies the total useful life of a -given technology in years. If all vintages of a given technology have the same -lifetime, then :code:`LifeTimeTech` can be used instead of :code:`LifeTimeProcess`. +Similar to :code:`lifetime_process`, this parameter specifies the total useful life +of a given technology in years, with a default of 40 years. If all vintages of a +given technology have the same lifetime, then :code:`lifetime_tech` can be used +instead of :code:`lifetime_process`. linked_techs -^^^^^^^^^^^^ +~~~~~~~~~~~~ :math:`{LIT}_{r \in R, t \in T, e \in C^e, t' \in T}` @@ -760,7 +706,7 @@ which is represented by the second :code:`t'` index. loan_rate -^^^^^^^^^ +~~~~~~~~~ :math:`{LR}_{r \in r, t \in T, v \in V}` @@ -768,266 +714,354 @@ The interest rate used for loans supporting investment costs. The default loan rate is accessible in the metadata_real table in the database. -.. _ParamMaxCapacity: - +default_loan_rate +~~~~~~~~~~~~~~~~~ -max_activity -^^^^^^^^^^^^ +:math:`{DLR}` -:math:`{MAA}_{r \in R, p \in P, t \in T}` +A scalar parameter specifying the default interest rate applied to loans +when no process-specific :code:`loan_rate` is defined. This value is read +from the :code:`metadata_real` table in the database. -The :code:`max_activity` parameter is used to constrain the total activity (i.e., -energy production) from a given technology in each model time period. Note that the -total activity is constrained across all vintages of a technology. This parameter -is used in the :code:`max_activity_constraint`. +limit_activity +~~~~~~~~~~~~~~ -max_capacity -^^^^^^^^^^^^ +:math:`{LA}_{r \in R, p \in P, t \in T}` -:math:`{MAC}_{r \in R, p \in P, t \in T}` +The :code:`limit_activity` parameter places an upper or lower bound on the total +activity (energy production) from a technology or technology group in each model +time period. The bound direction is controlled by the :code:`operator` column +(:code:`le`, :code:`ge`, or :code:`eq`). The :code:`tech_or_group` column +accepts either a single technology name or a group name defined in +:code:`tech_group_names`. -The :code:`max_capacity` parameter represents an upper bound on the total installed -capacity of a given technology in each model time period. Note that the total -capacity is constrained across all vintages of a technology. This parameter is -used in the :code:`max_capacity_constraint`. +limit_activity_share +~~~~~~~~~~~~~~~~~~~~ -max_capacity_sum -^^^^^^^^^^^^^^^^ +:math:`{LAS}_{r \in R, p \in P, g_1, g_2}` -:math:`{MCS}_{t \in T}` +The :code:`limit_activity_share` parameter constrains the activity of one +technology or group as a share of another technology or group's activity. +For example, it can enforce a minimum renewable generation share. The +operator column controls whether the share is an upper bound, lower bound, +or equality. -Similar to the :code:`max_capacity` parameter, but represents an upper bound on -the total installed capacity across all model time periods. In addition, -this parameter specifies the upper bound on a group of technologies specified -in the :code:`tech_capacity_max` subset. This parameter is used in the -:code:`MaxCapacitySet_constraint`. +limit_annual_capacity_factor +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -max_resource -^^^^^^^^^^^^ +:math:`{LACF}_{r \in R, t \in T, v \in V, o \in C_c}` -:math:`{MAR}_{r \in R, t \in T}` +The :code:`limit_annual_capacity_factor` parameter limits the annual capacity +factor of a process — that is, the ratio of actual annual output to maximum +possible output. The :code:`tech_or_group` column accepts a technology name or +group name. Note this is indexed by vintage, not period, and will be applied to +all valid time periods for that process. -**Note**: The max_resource parameter/constraint is currently not supported in the model. -The :code:`max_resource` parameter represents an upper bound on the cumulative -amount of commodity that can be produced by region and technology over the model time -horizon. This parameter is used in :code:`max_resource_constraint`. Note that -this parameter differs from :code:`resource_bound`, which is also indexed by -model time period. +limit_capacity +~~~~~~~~~~~~~~ +:math:`{LC}_{r \in R, p \in P, t \in T}` -min_activity -^^^^^^^^^^^^ +The :code:`limit_capacity` parameter places an upper or lower bound on the +total available (retirement-adjusted) capacity of a technology or technology +group in each model timeperiod. The :code:`operator` column controls the bound +direction. The :code:`tech_or_group` column accepts either a single technology +name or a group name. -:math:`{MIA}_{r \in R, p \in P, t \in T}` -The :code:`min_activity` parameter represents a lower bound on the total activity (i.e., -energy production) of a given technology in each model time period. Note that the -total activity is constrained across all vintages of a technology. This parameter -is used in the :code:`min_activity_constraint`. +limit_capacity_share +~~~~~~~~~~~~~~~~~~~~ +:math:`{LCS}_{r \in R, p \in P, g_1, g_2}` -min_capacity -^^^^^^^^^^^^ +The :code:`limit_capacity_share` parameter constrains the capacity of one +technology group as a share of another group's capacity. The operator column +controls the bound direction. The group columns accept either +a single technology name or a technology group name. -:math:`{MIC}_{r \in R, p \in P,t \in T}` -The :code:`min_capacity` parameter represents a lower bound on the total installed -capacity of a given technology in each model time period. Note that the total -capacity is constrained across all vintages of a technology. This parameter is -used in the :code:`min_capacity_constraint`. +limit_degrowth_capacity +~~~~~~~~~~~~~~~~~~~~~~~ +:math:`{LDGC}_{r \in R, t \in T}` -min_capacity_sum -^^^^^^^^^^^^^^^^ +The :code:`limit_degrowth_capacity` parameter defines the maximum annual rate +at which the total capacity of a technology (or group) can shrink between +periods. The :code:`tech_or_group` column accepts a technology name or group name. -:math:`{MCS}_{t \in T}` -The :code:`min_capacity_sum` parameter represents the minimum cumulative -capacity associated with technologies belonging to :code:`tech_group`. -This parameter is used in the :code:`min_activityGroup_constraint`. +limit_degrowth_new_capacity +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +:math:`{LDGNC}_{r \in R, t \in T}` -min_gen_group_target -^^^^^^^^^^^^^^^^^^^^ +The :code:`limit_degrowth_new_capacity` parameter constrains the rate of decrease +in new capacity deployment between consecutive periods. -:math:`{MGT}_{r \in R}` -The :code:`min_gen_group_target` parameter is similar to :code:`min_activity`, but -represents a minimum activity limit for a user-defined technology group -(:code:`tech_groups`) rather than a single technology. This parameter is used -in the :code:`min_activityGroup_constraint`. +limit_degrowth_new_capacity_delta +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +:math:`\mathrm{LDGNC}_{\Delta,r \in R, t \in T}` -min_gen_group_weight -^^^^^^^^^^^^^^^^^^^^ +The :code:`limit_degrowth_new_capacity_delta` parameter constrains the +deceleration of new capacity degrowth between periods, essentially adding +"intertia" to the degrowth of new capacity deployment. -:math:`{MGW}_{r \in R, t \in T}` -The :code:`min_gen_group_weight` parameter represents a weight that is applied -to each technology within each :code:`tech_group`, which determines the -technology-specific activity shares that can count towards meeting the -:code:`min_activityGroup_constraint`. +limit_emission +~~~~~~~~~~~~~~ +:math:`{LE}_{r \in R, p \in P, e \in C^e}` -myopic_base_year -^^^^^^^^^^^^^^^^ +The :code:`limit_emission` parameter ensures that Temoa finds a solution that +fits within the modeler-specified limit on emission :math:`e` in time period +:math:`p`. The operator column controls whether this is an upper bound, lower +bound, or equality. -:math:`MBY` - -Temoa is typically run in "perfect foresight" mode, where all decision variables -in all time periods are solved simultaneously. However, it is also possible to -solve the model myopically, whereby the model solves a subset of time periods -in sequence. The :code:`myopic_base_year` parameter specifies the base year to which -all future costs are discounted. This parameter is located in the :code:`metadata` -table in the database. +limit_growth_capacity +~~~~~~~~~~~~~~~~~~~~~ -planning_reserve_margin -^^^^^^^^^^^^^^^^^^^^^^^ +:math:`{LGC}_{r \in R, t \in T}` -:math:`{PRM}_{r \in R}` +The :code:`limit_growth_capacity` parameter defines the maximum annual rate at +which the total capacity of a technology (or group) can grow between periods. +The :code:`tech_or_group` column accepts a technology name or group name. -The :code:`planning_reserve_margin` parameter specifies that capacity reserve margin -in the electric sector by region. The capacity reserve margin represents the -installed generating capacity - expressed as a share of peak load - that must be -available to meet contingencies. Note that since electricity demand is often -endogeous in Temoa databases, we calculate electricity production by time slice -to estimate the peak electricity demand. This parameter is used in -:code:`ReserveMargin_constraint`. +limit_growth_new_capacity +~~~~~~~~~~~~~~~~~~~~~~~~~ -ramp_down -^^^^^^^^^ +:math:`{LGNC}_{r \in R, t \in T}` -:math:`{RMD}_{r \in R, t \in T}` +The :code:`limit_growth_new_capacity` parameter constrains the rate of increase +in new capacity deployment between consecutive periods. -To account for the limited ramping capability of some thermal generators, a -ramp down rate can be specified via the :code:`ramp_down` parameter. The specified -value represents the fraction of installed capacity that can be ramped down when moving -from one time slice to the next. There is an equivalent :code:`ramp_up` parameter, to -specify ramping limits in the upward direction. This parameter is used in the -:code:`ramp_down_day_constraint` and `ramp_down_season_constraint`. The former constrains -the downward ramp rate between time-of-day slices, and the latter constrains the downward -ramp rate between the last time-of-day slice in a given season and the first time-of-day -slice in the next season. +limit_growth_new_capacity_delta +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -ramp_up -^^^^^^^ +:math:`\mathrm{LGNC}_{\Delta,r \in R, t \in T}` -:math:`{RMU}_{r \in R, t \in T}` +The :code:`limit_growth_new_capacity_delta` parameter constrains the acceleration +of new capacity growth between periods. This essentially adds "inertia" to the +growth of new capacity deployment. -To account for the limited ramping capability of some thermal generators, a -ramp up rate can be specified via the :code:`ramp_up` parameter. The specified -value represents the fraction of installed capacity that can be ramped up when moving -from one time slice to the next. There is an equivalent :code:`ramp_down` parameter, to -specify ramping limits in the downward direction. This parameter is used in the -:code:`ramp_up_day_constraint` and `ramp_up_season_constraint`. The former constrains -the upward ramp rate between time-of-day slices, and the latter constrains the upward -ramp rate between the last time-of-day slice in a given season and the first time-of-day -slice in the next season. +limit_new_capacity +~~~~~~~~~~~~~~~~~~ -resource_bound -^^^^^^^^^^^^^^ +:math:`{LNC}_{r \in R, t \in T, v \in V}` -:math:`{RSC}_{r \in R, p \in P, c \in C_p}` +The :code:`limit_new_capacity` parameter constrains the amount of new capacity +that can be deployed for a given technology or group in a specific vintage. +The :code:`tech_or_group` column accepts a technology name or group name. -This parameter allows the modeler to specify commodity production limits per period. -Note that a constraint in one period does not relate to any other periods. For -instance, if the modeler specifies a limit in period 1 and does not specify a -limit in period 2, then the model may use as much of that resource as it would -like in period 2. This parameter is used in :code:`ResourceExtraction_constraint`. -Note that the :code:`max_resource` parameter is similar, but constrains total -cumulative resource consumption across all model time periods. +limit_new_capacity_share +~~~~~~~~~~~~~~~~~~~~~~~~ -.. _segment_fraction: +:math:`{LNCS}_{r \in R, g_1, g_2, v \in V}` -segment_fraction -^^^^^^^^^^^^^^^^ +The :code:`limit_new_capacity_share` parameter constrains the new capacity of one +technology or group as a share of another technology or group's new capacity. -:math:`{SEG}_{s \in S,d \in D}` -The :code:`segment_fraction` parameter specifies the fraction of the year represented by -each combination of season and time of day. The sum of all combinations within -:code:`segment_fraction` must be 1, representing 100% of a year. +limit_resource +~~~~~~~~~~~~~~ +:math:`{LS}_{r \in R, t \in T}` -storage_duration -^^^^^^^^^^^^^^^^ +The :code:`limit_resource` parameter represents a bound on the cumulative +amount of commodity that can be produced by a technology or group over the entire +model time horizon. The :code:`tech_or_group` column accepts a technology name or +group name. Note that this is *not* supported in myopic mode as the cumulative +limit would need to decline as the horizon moves forward, which has not been added +yet. -:math:`{SD}_{r \in R, t \in T^{S}}` -The :code:`storage_duration` parameter represents the number of hours over which -storage can discharge if it starts at full charge and produces maximum output -until empty. The parameter value defaults to 4 hours if not specified by the user. +limit_seasonal_capacity_factor +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +:math:`{LSCF}_{r \in R, s \in S, t \in T}` -storage_init -^^^^^^^^^^^^ +The :code:`limit_seasonal_capacity_factor` parameter limits the capacity +factor of a technology in a specific season. There is no period index: the +limit applies across all periods. The :code:`tech_or_group` column accepts +a technology name or group name. -:math:`{SI}_{r \in R, t \in T^{S}, v \in P}` -The :code:`storage_init` parameter determines the initial charge level associated -with each storage technology. The value should be expressed as a fraction between -0 and 1. +limit_storage_fraction +~~~~~~~~~~~~~~~~~~~~~~ -Note 1: that this is an optional parameter and should only be used if the -user wishes to set the initial charge rather than allowing the model to optimize it. +:math:`{LSF}_{r \in R, s \in S, d \in D, t \in T^{S}}` -Note 2: This initialization is currently *not supported*. Values in the storage_init -table will be ignored and a log warning will be generated. +The :code:`limit_storage_fraction` parameter constrains the storage level of a +storage technology in any time slice to be at or above a specified fraction of +its maximum charge. Values should be between 0 and 1. Note that this constraint +will be applied to all valid :code:`period` and :code:`vintage` combinations for +the technology. -tech_input_split -^^^^^^^^^^^^^^^^^^^^^^^ +limit_tech_input_split +~~~~~~~~~~~~~~~~~~~~~~~ :math:`{TIS}_{r \in R, p \in P, i \in C_p, t \in T}` Some technologies have a single output but have multiple input fuels. The -:code:`tech_input_split` parameter fixes the shares of commodity input to a -specific technology in a given period. Note that this fixed share is maintained -across all model time slices. This parameter is used in -:code:`TechInputSplit_constraint`. +:code:`limit_tech_input_split` parameter constrains the shares of commodity +input to a specific technology in a given period in every time slice. The +:code:`operator` column controls whether the share is an upper bound, lower bound, +or equality. -tech_input_split_average -^^^^^^^^^^^^^^^^^^^^^^^^ +limit_tech_input_split_annual +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :math:`{TISA}_{r \in R, p \in P, i \in C_p, t \in T}` -The :code:`tech_input_split_average` is similar to :code:`tech_input_split`, as -they both fix input commodity shares to technologies with multiple inputs. -However, :code:`tech_input_split_average` only fixes the average shares at the -annual level, allowing the shares at the time slice level to vary. This -parameter is used in :code:`TechInputSplitAverage_constraint`. +Similar to :code:`limit_tech_input_split`, but constrains the average input +commodity shares at the annual level, allowing the shares at the time slice +level to vary. -tech_output_split -^^^^^^^^^^^^^^^^^ +limit_tech_output_split +~~~~~~~~~~~~~~~~~~~~~~~ -:math:`{TOS}_{t \in T, o \in C_c}` +:math:`{TOS}_{r \in R, p \in P, t \in T, o \in C_c}` Some technologies have a single input fuel but have multiple outputs. The -:code:`tech_output_split` parameter fixes the shares of commodity input to a -specific technology in a given period. Note that this fixed share is maintained -across all model time slices. This parameter is used in -:code:`TechOutputSplit_constraint`. +:code:`limit_tech_output_split` parameter constrains the shares of commodity +output from a specific technology in a given period by time slice. + + +limit_tech_output_split_annual +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:math:`{TOSA}_{r \in R, p \in P, t \in T, o \in C_c}` + +Similar to :code:`limit_tech_output_split`, but constrains the average output +commodity shares at the annual level, allowing the shares at the time slice +level to vary. + + +planning_reserve_margin +~~~~~~~~~~~~~~~~~~~~~~~ + +:math:`{PRM}_{r \in R}` + +The :code:`planning_reserve_margin` parameter specifies the capacity reserve margin +in the electric sector by region. The capacity reserve margin represents the +installed generating capacity — expressed as a share of peak load — that must be +available in reserve to meet contingencies. Temoa estimates peak demand from electricity +production by time slice. + + +ramp_down_hourly +~~~~~~~~~~~~~~~~ + +:math:`{RDH}_{r \in R, t \in T}` + +The :code:`ramp_down_hourly` parameter specifies the fraction of installed capacity +by which a technology can ramp output down per hour. This is used in the +:code:`ramp_down_day_constraint` (between time-of-day slices) and +:code:`ramp_down_season_constraint` (between the last time-of-day slice in one +season and the first in the next). + + +ramp_up_hourly +~~~~~~~~~~~~~~ + +:math:`{RUH}_{r \in R, t \in T}` + +The :code:`ramp_up_hourly` parameter specifies the fraction of installed capacity +by which a technology can ramp output up per hour. This is used in the +:code:`ramp_up_day_constraint` (between time-of-day slices) and +:code:`ramp_up_season_constraint` (between seasons). + + +reserve_capacity_derate +~~~~~~~~~~~~~~~~~~~~~~~ + +:math:`{RCD}_{r \in R, s \in S, t \in T^{res}, v \in V}` + +The :code:`reserve_capacity_derate` parameter allows the modeler to derate +the capacity of a reserve technology in specific seasons — for example, to +account for seasonal availability. Values default to 1 (no derate). This +parameter is used in the 'dynamic' version of the :code:`reserve_margin` +constraint. + + +.. _segment_fraction: + +segment_fraction +~~~~~~~~~~~~~~~~ + +:math:`{SEG}_{s \in S,d \in D}` + +The :code:`segment_fraction` parameter specifies the fraction of the year represented by +each combination of season and time of day. In v4, this parameter is **computed +automatically** from two user-specified inputs: + + * :code:`segment_fraction` column in the :code:`time_season` table — the fraction + of the year each season represents (e.g. 0.25 for each quarter). + * :code:`hours` column in the :code:`time_of_day` table — the number of hours each + time-of-day segment represents (e.g. 8 for "Day", 16 for "Night"). + +The computation is: + +.. math:: + + SEG_{s,d} = \text{segment\_fraction\_per\_season}(s) \;\times\; \frac{\text{hours}(d)} + {\sum_{d'} \text{hours}(d')} + +The sum of all :math:`SEG_{s,d}` values must equal 1, representing 100% of a year. + + +segment_fraction_per_season +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:math:`{SFS}_{s \in S}` + +The per-season share of the year, loaded directly from the :code:`segment_fraction` +column of the :code:`time_season` database table. These values are the first factor +in the :ref:`segment_fraction` computation and must sum to 1. + + +segment_fraction_per_sequential_season +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:math:`{SFS}_{s^{seq} \in S^{seq}}` + +The per-sequential-season share of the year, loaded from the +:code:`segment_fraction` column of the :code:`time_season_sequential` database table. +Used to compute the :code:`days_adjust` ratio that rescales storage levels and flows +between non-sequential and sequential season representations. + + +storage_duration +~~~~~~~~~~~~~~~~ + +:math:`{SD}_{r \in R, t \in T^{S}}` + +The :code:`storage_duration` parameter represents the number of hours over which +storage can discharge if it starts at full charge and produces maximum output +until empty. The parameter value defaults to 4 hours if not specified by the user. \*loan_annualize -^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~ :math:`{LA}_{r \in R, t \in T, v \in P}` This is a model-calculated parameter based on the process-specific loan length -(its indices are the same as the :code:`LifetimeLoan` parameter), and -process-specific discount rate (the :code:`DiscountRate` parameter). It is +(its indices are the same as the :code:`loan_lifetime_process` parameter), and +process-specific interest rate (the :code:`loan_rate` parameter). It is calculated via the formula: .. math:: @@ -1037,21 +1071,8 @@ calculated via the formula: \forall \{t, v\} \in \Theta_{\text{cost\_invest}} -model_process_life -^^^^^^^^^^^^^^^^^^ - -:math:`{MPL}_{r \in R, p \in P, t \in T, v \in P}` - -The :code:`model_process_life` parameter is internally-derived by the model calculated in -:code:`ParamModelProcessLife_rule` and which makes use of the :code:`lifetime_process` -parameter. For a given technology vintage in a given model time period, it returns the -lesser of the period length and the remaining process lifetime. This parameter is used -to sum the annual :code:`fixed_costs` and :code:`variable_costs` across all years within -a given time period. - - \*period_length -^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~ :math:`{LEN}_{p \in P}` @@ -1091,7 +1112,7 @@ specifically not defined for the final element in :math:`\text{P}^f`. \*process_life_frac -^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~ :math:`{PLF}_{r \in R, p \in P,t \in T,v \in P}` @@ -1140,9 +1161,9 @@ each. ":math:`FLX_{r,p,s,d,i,t,v,o}`",":code:`v_flex`","The portion of commodity production exceeding demand" ":math:`FLXA_{r,p,i,t,v,o}`",":code:`v_flex_annual`","The portion of commodity production from constant production techs exceeding demand" ":math:`CUR_{r,p,s,d,i,t,v,o}`",":code:`v_curtailment`","Commodity flow out of a tech that is curtailed" - ":math:`CAP_{r,t,v}`",":code:`v_capacity`","Required tech capacity to support associated activity" + ":math:`CAP_{r,p,t,v}`",":code:`v_capacity`","Required tech capacity to support associated activity" ":math:`CAPAVL_{r,p,t}`",":code:`v_capacity_available_by_period_and_tech`","Derived variable representing the capacity of technology :math:`t` available in period :math:`p`" - ":math:`SI_{r,t,v}`",":code:`v_storage_init`","Initial charge level associated with storage techs" + ":math:`SI_{r,p,s,t,v}`",":code:`v_storage_init`","Hub variable for the initial charge level of each daily storage cycle" ":math:`SL_{r,p,s,d,t,v}`",":code:`v_storage_level`","Charge level each time slice associated with storage techs" ":math:`SSL_{r,p,s,t,v}`",":code:`v_seasonal_storage_level`","Base charge level of sequential seasons for seasonal storage" ":math:`RCAP_{r,p,t,v}`",":code:`v_retired_capacity`","Capacity retired before end of life" @@ -1150,7 +1171,7 @@ each. ":math:`NCAP_{r,t,v}`",":code:`v_new_capacity`","New deployed capacity" v_flow_out -^^^^^^^^^^ +~~~~~~~~~~ :math:`FO_{r,p,s,d,i,t,v,o}` @@ -1163,7 +1184,7 @@ process can be calculated as /EFF_{c,t,v,o}`. v_flow_out_annual -^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~ :math:`FOA_{r,p,i,t,v,o}` @@ -1174,7 +1195,7 @@ improves computational performance. v_flex -^^^^^^ +~~~~~~ :math:`FLX_{r,p,s,d,i,t,v,o}` @@ -1195,7 +1216,7 @@ the excess production in the :code:`CommodityBalanceAnnual_constraint`. v_flex_annual -^^^^^^^^^^^^^ +~~~~~~~~~~~~~ :math:`FLXA_{r,p,i,t,v,o}` @@ -1206,7 +1227,7 @@ improves computational performance. v_curtailment -^^^^^^^^^^^^^ +~~~~~~~~~~~~~ :math:`CUR_{r,p,s,d,i,t,v,o}` @@ -1230,7 +1251,7 @@ curtailment is 3 units (0.8 x 10 - 5). v_flow_in_storage -^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~ :math:`FIS_{r,p,s,d,i,t,v,o}` @@ -1240,17 +1261,18 @@ cannot be discerned from :code:`v_flow_out`. Thus an explicit :math:`flow_in` variable is required for storage. v_capacity -^^^^^^^^^^ +~~~~~~~~~~ -:math:`CAP_{r,t,v}` +:math:`CAP_{r,p,t,v}` -The :code:`v_capacity` variable determines the required capacity of all processes -across the user-defined system. It is indexed for each process (t,v), and Temoa -constrains the capacity variable to be able to meet the total commodity flow out -of that process in all time slices in which it is active :eq:`Capacity`. +The :code:`v_capacity` variable represents the available capacity of a process +:math:`(r, t, v)` in period :math:`p`, adjusted for retirements or end of life. +Temoa constrains the capacity variable to be able to meet the total +commodity flow out of that process in all time slices in which it is active +:eq:`Capacity`. v_capacity_available_by_period_and_tech -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :math:`CAPAVL_{r,p,t}` @@ -1260,18 +1282,18 @@ are not warranted (e.g. in calculating the maximum or minimum total capacity allowed in a given time period). v_storage_init -^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~ -:math:`SI_{r,t,v}` +:math:`SI_{r,p,s,t,v}` -The :code:`v_storage_init` variable determines the initial storage charge level -at the beginning of the first time slice within a given time period. Each vintage -of each technology can have a different optimal initial value. Note that -this value also determines the ending storage charge level at the end of the -last time slice within each model time period. +The :code:`v_storage_init` variable replaces the :code:`v_storage_level` variable +for the initial storage charge level of each season. This is purely for solver optimisation +and has no impact on model structure or results. This 1:1 swap measurably improves +presolve time in large models with storage. The mechanism behind +this is not understood. v_storage_level -^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~ :math:`SL_{r,p,s,d,t,v}` @@ -1281,7 +1303,48 @@ by the energy available in the storage units. -We explain the equations governing these variables the :ref:`Constraints` +v_seasonal_storage_level +~~~~~~~~~~~~~~~~~~~~~~~~ + +:math:`SSL_{r,p,s,t,v}` + +The :code:`v_seasonal_storage_level` variable tracks the base charge level at +the boundary between sequential seasons for technologies flagged as seasonal +storage (:code:`tech_seasonal_storage`). It is used in the +:code:`seasonal_storage_energy_constraint` to chain the storage state of charge +across seasons defined in the :code:`time_season_sequential` table. + +v_retired_capacity +~~~~~~~~~~~~~~~~~~ + +:math:`RCAP_{r,p,t,v}` + +The :code:`v_retired_capacity` variable tracks the cumulative capacity of a +process that has been retired before its natural end of life, up to and including +period :math:`p`. Only technologies in the :code:`tech_retirement` set may +retire early in this manner. This variable is non-decreasing across periods. + +v_annual_retirement +~~~~~~~~~~~~~~~~~~~ + +:math:`ART_{r,p,t,v}` + +The :code:`v_annual_retirement` variable represents the annualised capacity +that retires or reaches end of life in period :math:`p`. It accounts for both +early retirements (via :code:`v_retired_capacity`) and natural end-of-life. + +v_new_capacity +~~~~~~~~~~~~~~ + +:math:`NCAP_{r,t,v}` + +The :code:`v_new_capacity` variable represents the newly deployed capacity of a +technology in its vintage period. It is the primary investment decision +variable and drives the capital cost terms in the objective function. Unlike +:code:`v_capacity`, it has no period index — capacity is built once in its +vintage year. + +We explain the equations governing these variables in the :ref:`Constraints` section. @@ -1325,7 +1388,7 @@ understanding of the context. The use of (:math:`\Theta`) means that the constraint is only defined for the exact indices that the modeler specified. Capacity-Defining Constraints -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ We begin with the :code:`Capacity_constraint` and :code:`CapacityAnnual_constraint`, which are particularly important because they define the relationship between installed capacity and allowable commodity flow. @@ -1344,7 +1407,7 @@ installed capacity and allowable commodity flow. .. _NetworkConstraints: Network Constraints -^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~ These three constraints define the core of the Temoa model; together, they define the algebraic energy system network. @@ -1357,7 +1420,7 @@ define the algebraic energy system network. Physical and Operational Constraints -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ These constraints fine-tune the model formulation to account for various physical and operational real-world phenomena. @@ -1394,7 +1457,7 @@ various physical and operational real-world phenomena. Objective Function -^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~ .. autofunction:: temoa.components.costs.annuity_to_pv @@ -1406,7 +1469,7 @@ Objective Function User-Specific Constraints -^^^^^^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~~~~~~ .. commented out... not used? .. autofunction:: temoa.components.capacity.existing_capacity_constraint From 30d8b6d11945bda4cef7fcda76e253c1f403a3e7 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Mar 2026 13:31:01 -0400 Subject: [PATCH 520/587] Audit parameter tables --- docs/source/param_desc_and_tables.rst | 67 ++++++++++++++------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/docs/source/param_desc_and_tables.rst b/docs/source/param_desc_and_tables.rst index 75f7c66fa..40ff0737d 100644 --- a/docs/source/param_desc_and_tables.rst +++ b/docs/source/param_desc_and_tables.rst @@ -1,7 +1,7 @@ Parameters are indexed by the sets defined above and used to specify input data. In the leftmost column below, the subscripts indicate the sets used to index the parameter. As with sets, we categorize parameters thematically and present them -below in separate tables. +below in separate tables. Below are the **time-related** parameters. @@ -9,9 +9,12 @@ Below are the **time-related** parameters. :header: "Parameter", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`\text{SEG}_{s,d}`", ":code:`time_segment_fraction`", ":code:`segment_fraction`", "fraction of year represented by each (s, d) tuple" - "", ":code:`metadata`", ":code:`days_per_period`", "number of days per period, required to ensure proper representation of time" - "", ":code:`time_season_sequential`", ":code:`time_season_sequential`", "sequential season ordering (mutable)" + ":math:`\text{SFS}_s`", ":code:`time_season`", ":code:`segment_fraction_per_season`", "per-season year fraction; loaded from the :code:`segment_fraction` column of :code:`time_season`" + "", ":code:`time_of_day`", ":code:`time_of_day_hours`", "hours per time-of-day segment; loaded from the :code:`hours` column of :code:`time_of_day` (default 1)" + ":math:`\text{SEG}_{s,d}`", "*(computed)*", ":code:`segment_fraction`", "fraction of year represented by each (s, d) tuple; computed as :code:`segment_fraction_per_season(s) Ɨ hours(d) / Ī£ hours`" + "", "*(config)*", ":code:`time_sequencing`", "time sequencing mode: ``consecutive_days``, ``seasonal_timeslices`` (default), ``representative_periods``, or ``manual``" + "", "*(config)*", ":code:`days_per_period`", "number of days per period (default: 365); set as a top-level key in the configuration TOML file, not in the database" + ":math:`\text{SFS}_{s^{seq}}`", ":code:`time_season_sequential`", ":code:`segment_fraction_per_sequential_season`", "per-sequential-season year fraction; loaded from the :code:`segment_fraction` column of :code:`time_season_sequential`" Parameters in the table below relate to **capacity and its performance characteristics**. @@ -20,13 +23,13 @@ characteristics**. :header: "Parameter", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`\text{C2A}_{r,t,v}`", ":code:`capacity_to_activity`", ":code:`capacity_to_activity`", "converts from capacity to activity units" - ":math:`\text{CC}_{r,p,t,v}`", ":code:`capacity_credit`", ":code:`capacity_credit`", "process-specific capacity credit used in the reserve margin constraint" + ":math:`\text{C2A}_{r,t}`", ":code:`capacity_to_activity`", ":code:`capacity_to_activity`", "converts from capacity to activity units" + ":math:`\text{CC}_{r,p,t,v}`", ":code:`capacity_credit`", ":code:`capacity_credit`", "process-specific capacity credit used in the static reserve margin constraint" ":math:`\text{CFT}_{r,s,d,t}`", ":code:`capacity_factor_tech`", ":code:`capacity_factor_tech`", "technology-specific capacity factor" ":math:`\text{CFP}_{r,s,d,t,v}`", ":code:`capacity_factor_process`", ":code:`capacity_factor_process`", "process-specific capacity factor; allows capacity factor to change with technology vintage" ":math:`\text{ECAP}_{r,t,v}`", ":code:`existing_capacity`", ":code:`existing_capacity`", "installed capacity that exists prior to first model time period" ":math:`\text{PRM}_{r}`", ":code:`planning_reserve_margin`", ":code:`planning_reserve_margin`", "planning reserve margin used to ensure sufficient generating capacity" - "", ":code:`reserve_capacity_derate`", ":code:`reserve_capacity_derate`", "reserve capacity derate" + ":math:`\text{RCD}_{r,s,t,v}`", ":code:`reserve_capacity_derate`", ":code:`reserve_capacity_derate`", "capacity derate factor for dynamic reserve margin constraint" ":math:`\text{RUH}_{r,t}`", ":code:`ramp_up_hourly`", ":code:`ramp_up_hourly`", "hourly rate at which generation techs can ramp output up" ":math:`\text{RDH}_{r,t}`", ":code:`ramp_down_hourly`", ":code:`ramp_down_hourly`", "hourly rate at which generation techs can ramp output down" @@ -39,9 +42,9 @@ Parameters in the table below relate to the specification of **costs**. ":math:`\text{CF}_{r,p,t,v}`", ":code:`cost_fixed`", ":code:`cost_fixed`", "fixed operations & maintenance cost" ":math:`\text{CI}_{r,t,v}`", ":code:`cost_invest`", ":code:`cost_invest`", "tech-specific investment cost" ":math:`\text{CV}_{r,p,t,v}`", ":code:`cost_variable`", ":code:`cost_variable`", "variable operations & maintenance (O&M) cost" - "", ":code:`cost_emission`", ":code:`cost_emission`", "emission costs" + ":math:`\text{CE}_{r,p,e}`", ":code:`cost_emission`", ":code:`cost_emission`", "emission costs" ":math:`\text{GDR}`", ":code:`metadata_real`", ":code:`global_discount_rate`", "global rate used to convert future time period costs to the present cost" - "", ":code:`metadata_real`", ":code:`default_loan_rate`", "default loan rate used to amortize investment costs" + ":math:`\text{DLR}`", ":code:`metadata_real`", ":code:`default_loan_rate`", "default loan rate used to amortize investment costs" ":math:`\text{LLP}_{r,t,v}`", ":code:`loan_lifetime_process`", ":code:`loan_lifetime_process`", "process-specific loan term (default=lifetime_process)" ":math:`\text{LR}_{r,t,v}`", ":code:`loan_rate`", ":code:`loan_rate`", "process-specific interest rate on investment cost" @@ -53,7 +56,7 @@ and performance**. :widths: 15, 20, 25, 40 ":math:`\text{EFF}_{r,i,t,v,o}`", ":code:`efficiency`", ":code:`efficiency`", "technology- and commodity-specific conversion efficiency" - ":math:`\text{EFF}_{r,p,s,d,i,t,v,o}`", ":code:`efficiency_variable`", ":code:`efficiency_variable`", "optional specification that allows efficiency to be specified by time slice" + ":math:`\text{EFFV}_{r,s,d,i,t,v,o}`", ":code:`efficiency_variable`", ":code:`efficiency_variable`", "optional time slice multiplier on efficiency (no period index; applies to all periods)" ":math:`\text{LTT}_{r,t}`", ":code:`lifetime_tech`", ":code:`lifetime_tech`", "technology-specific lifetime (default=40 years)" ":math:`\text{LTP}_{r,t,v}`", ":code:`lifetime_process`", ":code:`lifetime_process`", "tech- and vintage-specific lifetime (default=lifetime_tech)" ":math:`\text{LSC}_{r,p,t,v}`", ":code:`lifetime_survival_curve`", ":code:`lifetime_survival_curve`", "surviving fraction of original capacity" @@ -66,7 +69,7 @@ Parameters in the table below relate to the specification of **end-use demands** :widths: 15, 20, 25, 40 ":math:`\text{DEM}_{r,p,c}`", ":code:`demand`", ":code:`demand`", "end-use demand by region-period-commodity" - ":math:`\text{DSD}_{r,p,s,d,c}`", ":code:`demand_specific_distribution`", ":code:`demand_specific_distribution`", "fractional annual demand by time slice (s,d)" + ":math:`\text{DSD}_{r,s,d,c}`", ":code:`demand_specific_distribution`", ":code:`demand_specific_distribution`", "fractional annual demand by time slice (s,d)" Parameters in the table below relate to the specification of **emissions**. @@ -74,7 +77,7 @@ Parameters in the table below relate to the specification of **emissions**. :header: "Parameter", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`\text{EAC}_{r,i,t,v,o,e}`", ":code:`emission_activity`", ":code:`emission_activity`", "activity-based emissions rate" + ":math:`\text{EAC}_{r,e,i,t,v,o}`", ":code:`emission_activity`", ":code:`emission_activity`", "activity-based emissions rate" ":math:`\text{EE}_{r,t,v,e}`", ":code:`emission_embodied`", ":code:`emission_embodied`", "emissions associated with the creation of capacity; embodied emissions" ":math:`\text{EEOL}_{r,t,v,e}`", ":code:`emission_end_of_life`", ":code:`emission_end_of_life`", "emissions associated with the retirement/end of life of capacity" @@ -85,11 +88,11 @@ capacity, activity and emissions**. :header: "Parameter", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`\text{LC}_{r,p,t}`", ":code:`limit_capacity`", ":code:`limit_capacity`", "limit on tech-specific capacity by period" - ":math:`\text{LNC}_{r,p,t}`", ":code:`limit_new_capacity`", ":code:`limit_new_capacity`", "limit on new capacity deployment by period" - ":math:`\text{LA}_{r,p,t}`", ":code:`limit_activity`", ":code:`limit_activity`", "limit on technology-specific activity by region and period" + ":math:`\text{LC}_{r,p,t}`", ":code:`limit_capacity`", ":code:`limit_capacity`", "limit on capacity by period; :code:`tech_or_group` column accepts a technology name or group name" + ":math:`\text{LNC}_{r,t,v}`", ":code:`limit_new_capacity`", ":code:`limit_new_capacity`", "limit on new capacity deployment by vintage; :code:`tech_or_group` column accepts a technology name or group name" + ":math:`\text{LA}_{r,p,t}`", ":code:`limit_activity`", ":code:`limit_activity`", "limit on activity by region and period; :code:`tech_or_group` column accepts a technology name or group name" ":math:`\text{LE}_{r,p,e}`", ":code:`limit_emission`", ":code:`limit_emission`", "limit on emissions by region and period" - ":math:`\text{LS}_{r,t}`", ":code:`limit_resource`", ":code:`limit_resource`", "cumulative activity limit across time periods (not supported in myopic)" + ":math:`\text{LS}_{r,t}`", ":code:`limit_resource`", ":code:`limit_resource`", "cumulative activity limit across time periods (not supported in myopic); :code:`tech_or_group` column accepts a technology name or group name" Parameters in the table below relate to the specification of **growth and degrowth limits**. @@ -98,12 +101,12 @@ limits**. :header: "Parameter", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`\text{LGC}_{r,t}`", ":code:`limit_growth_capacity`", ":code:`limit_growth_capacity`", "capacity growth rate limits" - ":math:`\text{LDGC}_{r,t}`", ":code:`limit_degrowth_capacity`", ":code:`limit_degrowth_capacity`", "capacity degrowth rate limits" - ":math:`\text{LGNC}_{r,t}`", ":code:`limit_growth_new_capacity`", ":code:`limit_growth_new_capacity`", "new capacity growth rate limits" - ":math:`\text{LDGNC}_{r,t}`", ":code:`limit_degrowth_new_capacity`", ":code:`limit_degrowth_new_capacity`", "new capacity degrowth rate limits" - ":math:`\mathrm{LGNC}_{\Delta,r,t}`", ":code:`limit_growth_new_capacity_delta`", ":code:`limit_growth_new_capacity_delta`", "new capacity growth acceleration limits" - ":math:`\mathrm{LDGNC}_{\Delta,r,t}`", ":code:`limit_degrowth_new_capacity_delta`", ":code:`limit_degrowth_new_capacity_delta`", "new capacity degrowth deceleration limits" + ":math:`\text{LGC}_{r,t}`", ":code:`limit_growth_capacity`", ":code:`limit_growth_capacity`", "capacity growth rate limits; :code:`tech_or_group` column accepts a technology name or group name" + ":math:`\text{LDGC}_{r,t}`", ":code:`limit_degrowth_capacity`", ":code:`limit_degrowth_capacity`", "capacity degrowth rate limits; :code:`tech_or_group` column accepts a technology name or group name" + ":math:`\text{LGNC}_{r,t}`", ":code:`limit_growth_new_capacity`", ":code:`limit_growth_new_capacity`", "new capacity growth rate limits; :code:`tech_or_group` column accepts a technology name or group name" + ":math:`\text{LDGNC}_{r,t}`", ":code:`limit_degrowth_new_capacity`", ":code:`limit_degrowth_new_capacity`", "new capacity degrowth rate limits; :code:`tech_or_group` column accepts a technology name or group name" + ":math:`\mathrm{LGNC}_{\Delta,r,t}`", ":code:`limit_growth_new_capacity_delta`", ":code:`limit_growth_new_capacity_delta`", "new capacity growth acceleration limits; :code:`tech_or_group` column accepts a technology name or group name" + ":math:`\mathrm{LDGNC}_{\Delta,r,t}`", ":code:`limit_degrowth_new_capacity_delta`", ":code:`limit_degrowth_new_capacity_delta`", "new capacity degrowth deceleration limits; :code:`tech_or_group` column accepts a technology name or group name" Parameters in the table below relate to the specification of **operational and split limits**. @@ -112,13 +115,13 @@ split limits**. :header: "Parameter", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`\text{LACF}_{r,p,t,o}`", ":code:`limit_annual_capacity_factor`", ":code:`limit_annual_capacity_factor`", "annual capacity factor limits" - ":math:`\text{LSCF}_{r,p,s,t}`", ":code:`limit_seasonal_capacity_factor`", ":code:`limit_seasonal_capacity_factor`", "seasonal capacity factor limits" - ":math:`\text{LSF}_{r,p,s,d,t,v}`", ":code:`limit_storage_level_fraction`", ":code:`limit_storage_fraction`", "limit on storage level in any time slice" - ":math:`\text{TIS}_{r,i,t}`", ":code:`limit_tech_input_split`", ":code:`limit_tech_input_split`", "technology input split constraints specifying input fuel ratio at time slice level" - ":math:`\text{TISA}_{r,i,t}`", ":code:`limit_tech_input_split_annual`", ":code:`limit_tech_input_split_annual`", "technology input split constraints specifying input fuel ratio at average annual level" - ":math:`\text{TOS}_{r,t,o}`", ":code:`limit_tech_output_split`", ":code:`limit_tech_output_split`", "technology split constraints specifying output fuel ratio at time slice level" - ":math:`\text{TOSA}_{r,t,o}`", ":code:`limit_tech_output_split_annual`", ":code:`limit_tech_output_split_annual`", "technology split constraints specifying output fuel ratio at average annual level" + ":math:`\text{LACF}_{r,t,v,o}`", ":code:`limit_annual_capacity_factor`", ":code:`limit_annual_capacity_factor`", "annual capacity factor limits; indexed by vintage (not period); :code:`tech_or_group` column accepts a technology name or group name" + ":math:`\text{LSCF}_{r,s,t}`", ":code:`limit_seasonal_capacity_factor`", ":code:`limit_seasonal_capacity_factor`", "seasonal capacity factor limits (no period index; applies to all periods)" + ":math:`\text{LSF}_{r,s,d,t}`", ":code:`limit_storage_level_fraction`", ":code:`limit_storage_fraction`", "limit on storage level in any time slice" + ":math:`\text{TIS}_{r,p,i,t}`", ":code:`limit_tech_input_split`", ":code:`limit_tech_input_split`", "technology input split constraints specifying input fuel ratio at time slice level" + ":math:`\text{TISA}_{r,p,i,t}`", ":code:`limit_tech_input_split_annual`", ":code:`limit_tech_input_split_annual`", "technology input split constraints specifying input fuel ratio at average annual level" + ":math:`\text{TOS}_{r,p,t,o}`", ":code:`limit_tech_output_split`", ":code:`limit_tech_output_split`", "technology split constraints specifying output fuel ratio at time slice level" + ":math:`\text{TOSA}_{r,p,t,o}`", ":code:`limit_tech_output_split_annual`", ":code:`limit_tech_output_split_annual`", "technology split constraints specifying output fuel ratio at average annual level" Parameters in the table below relate to the specification of **share limits**. @@ -128,7 +131,7 @@ Parameters in the table below relate to the specification of **share limits**. ":math:`\text{LCS}_{r,p,g_1,g_2}`", ":code:`limit_capacity_share`", ":code:`limit_capacity_share`", "capacity share limits between technology groups" ":math:`\text{LAS}_{r,p,g_1,g_2}`", ":code:`limit_activity_share`", ":code:`limit_activity_share`", "activity share limits between technology groups" - ":math:`\text{LNCS}_{r,p,g_1,g_2}`", ":code:`limit_new_capacity_share`", ":code:`limit_new_capacity_share`", "new capacity share limits" + ":math:`\text{LNCS}_{r,g_1,g_2,v}`", ":code:`limit_new_capacity_share`", ":code:`limit_new_capacity_share`", "new capacity share limits" Parameters in the table below relate to the specification of **policy**. @@ -159,7 +162,6 @@ therefore do not appear in the database**. ":math:`{}^*\text{LEN}_p`", "", ":code:`period_length`", "number of years in period :math:`p`; computed from time periods" ":math:`{}^*\text{LA}_{t,v}`", "", ":code:`loan_annualize`", "loan amortization by tech and vintage; based on :math:`DR_t`; computed from loan rate and lifetime" ":math:`{}^*\text{PLF}_{r,p,t,v}`", "", ":code:`process_life_frac`", "fraction of available process capacity by region and period; computed from process life fraction" - "", "", ":code:`segment_fraction_per_season`", "computed internally from segment fractions" The tables below specify **model outputs.** When constructing a new database, they are left blank. These tables are auto-populated by the model after @@ -186,5 +188,4 @@ code. :widths: 30, 30, 40 ":code:`myopic_efficiency`", "Myopic mode efficiency", "alternative efficiency for myopic optimization" - ":code:`time_manual`", "Manual time sequencing", "hidden feature, rarely used" - ":code:`sector_label`", "Sectoral classification", "used in output tables only" \ No newline at end of file + ":code:`sector_label`", "Sectoral classification", "used in output tables only" From 61429bde3a8b7d02ddadbd206f3297c353349e50 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Mar 2026 13:37:41 -0400 Subject: [PATCH 521/587] Audit set tables --- docs/source/set_desc_and_tables.rst | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/docs/source/set_desc_and_tables.rst b/docs/source/set_desc_and_tables.rst index 04b6b8a51..29818d487 100644 --- a/docs/source/set_desc_and_tables.rst +++ b/docs/source/set_desc_and_tables.rst @@ -24,10 +24,9 @@ the model's time horizon for optimization. ":math:`\text{P}^f`", ":code:`time_period, flag = f`", ":code:`time_future`", "model periods within the optimization time horizon" ":math:`{}^*\text{P}^o`", ":code:`time_period`", ":code:`time_optimize`", "model time periods to optimize, (:math:`\text{P}^f - \text{max}(\text{P}^f)`); the last time period is removed as it represents the end of the final period" ":math:`{}^*\text{V}`", ":code:`time_period`", ":code:`vintage_exist`, :code:`vintage_optimize`, :code:`vintage_all`", "tech vintages, (:math:`\text{P}^e \cup \text{P}^o`), derived from time period set and used to track technology vintages across time periods" - ":math:`\text{D}`", ":code:`time_of_day`", ":code:`time_of_day`", "intraday time divisions, either individual or blocks of hours" - ":math:`\text{S}`", ":code:`season_label`", ":code:`time_season`", "intra-annual divisions, e.g., different seasons or different representative days" - "", ":code:`time_season`", ":code:`time_season`", "ordered tuple of seasons by time period" - "", ":code:`time_season_sequential`", ":code:`time_season_to_sequential, ordered_season_sequential`", "superimposed sequential seasons used for seasonal storage and inter-season ramping" + ":math:`\text{D}`", ":code:`time_of_day`", ":code:`time_of_day`", "intraday time divisions; each entry carries an :code:`hours` value (default 1) specifying how many hours it represents" + ":math:`\text{S}`", ":code:`time_season`", ":code:`time_season`", "intra-annual divisions (e.g. seasons or representative days); each entry carries a :code:`segment_fraction` giving its share of the year; ordered by :code:`sequence` column" + "", ":code:`time_season_sequential`", ":code:`time_season_sequential, ordered_season_sequential`", "superimposed sequential seasons used for seasonal storage and inter-season ramping; only required when :code:`time_sequencing = 'representative_periods'`" The sets in the table below define Temoa's representation of **regions**. @@ -37,7 +36,7 @@ The sets in the table below define Temoa's representation of **regions**. ":math:`\text{R}`", ":code:`region`", ":code:`regions`", "distinct geographical regions" "", ":code:`region`", ":code:`regional_indices`", "set of all the possible combinations of interregional exchanges plus original region indices" - "", ":code:`region_group_check`", ":code:`regional_global_indices`", "set used to validate regional group constraints; includes individual regions, exchange pairs, and groups" + "", "", ":code:`regional_global_indices`", "set of all used combinations of interregional exchanges plus original region indices and groups" The sets below define how technologies are represented within Temoa. Because technologies can serve many different functions across an energy system, we need to define a large @@ -47,8 +46,8 @@ number of **technology subsets**. :header: "Set", "Database Table", "Model Element", "Notes" :widths: 15, 20, 25, 40 - ":math:`{}^*\text{T}`", ":code:`technology`", ":code:`tech_all`", "all technologies to be modeled (:math:`{T}^r \cup {T}^p`)" - ":math:`\text{T}^p`", ":code:`technology, flag = p`", ":code:`tech_production`", "technologies producing intermediate commodities, like electricity" + ":math:`{}^*\text{T}`", ":code:`technology`", ":code:`tech_all`", "all technologies to be modeled (in v4, all technologies are production-type: :math:`T = T^p`)" + ":math:`\text{T}^p`", ":code:`technology, flag LIKE 'p%'`", ":code:`tech_production`", "all production technologies, including baseload and storage (:math:`{T}^b \cup {T}^s \subset {T}^p`)" ":math:`\text{T}^b`", ":code:`technology, flag = pb`", ":code:`tech_baseload`", "baseload electric generators, which have constant output across intraday time segments (:math:`{T}^b \subset T`)" ":math:`\text{T}^s`", ":code:`technology, flag = ps`", ":code:`tech_storage`", "all storage technologies (:math:`{T}^s \subset T`)" ":math:`\text{T}^a`", ":code:`technology, annual = 1`", ":code:`tech_annual`", "technologies that produce constant annual output (:math:`{T}^a \subset T`)" @@ -56,11 +55,11 @@ number of **technology subsets**. ":math:`\text{T}^c`", ":code:`technology, curtail = 1`", ":code:`tech_curtailment`", "technologies with curtailable output and no upstream cost (:math:`{T}^c \subset (T - T^{res})`)" ":math:`\text{T}^f`", ":code:`technology, flex = 1`", ":code:`tech_flex`", "technologies producing excess commodity flows (:math:`{T}^f \subset T`)" ":math:`\text{T}^x`", ":code:`technology, exchange = 1`", ":code:`tech_exchange`", "technologies used for interregional commodity flows (:math:`{T}^x \subset T`)" - ":math:`\text{T}^{ur}`", ":code:`technology, ramp_up = 1`", ":code:`tech_upramping`", "electric generators with a ramp up hourly rate limit (:math:`{T}^{ur} \subset T`)" - ":math:`\text{T}^{dr}`", ":code:`technology, ramp_down = 1`", ":code:`tech_downramping`", "electric generators with a ramp down hourly rate limit (:math:`{T}^{dr} \subset T`)" + ":math:`\text{T}^{ur}`", ":code:`ramp_up_hourly`", ":code:`tech_upramping`", "electric generators with a ramp up hourly rate limit; derived from :code:`ramp_up_hourly` table (:math:`{T}^{ur} \subset T`)" + ":math:`\text{T}^{dr}`", ":code:`ramp_down_hourly`", ":code:`tech_downramping`", "electric generators with a ramp down hourly rate limit; derived from :code:`ramp_down_hourly` table (:math:`{T}^{dr} \subset T`)" ":math:`\text{T}^{ret}`", ":code:`technology, retire = 1`", ":code:`tech_retirement`", "technologies allowed to retire before end of life (:math:`{T}^{ret} \subset (T - T^{u})`)" ":math:`\text{T}^u`", ":code:`technology, unlim_cap = 1`", ":code:`tech_uncap`", "technologies that have no bound on capacity (:math:`{T}^u \subset (T - T^{res})`)" - ":math:`\text{T}^{ss}`", ":code:`technology, seas_stor = 1`", ":code:`tech_seasonal_storage`", "seasonal storage technologies (:math:`{T}^{ss} \subset T^s`)" + ":math:`\text{T}^{ss}`", ":code:`technology, flag = 'ps' AND seas_stor = 1`", ":code:`tech_seasonal_storage`", "seasonal storage technologies; requires both storage flag and seas_stor column (:math:`{T}^{ss} \subset T^s`)" "", ":code:`tech_group`", ":code:`tech_group_names`", "named groups for use in group constraints" "", ":code:`tech_group_member`", ":code:`tech_group_members`", "each technology belonging to each group" ":math:`\text{T}^e`", ":code:`existing_capacity`", ":code:`tech_exist`", "existing technologies with a past vintage (:math:`{T}^e \subset T`)" @@ -74,10 +73,10 @@ technologies. ":math:`\text{C}^d`", ":code:`commodity, flag = d`", ":code:`commodity_demand`", "end-use demand commodities, representing the final consumer demands" ":math:`\text{C}^e`", ":code:`commodity, flag = e`", ":code:`commodity_emissions`", "emission commodities (e.g., :math:`\text{CO}_\text{2}` :math:`\text{NO}_\text{x}`); filtered by flag" - ":math:`\text{C}^p`", ":code:`commodity, flag = p`", ":code:`commodity_physical`", "physical energy commodities (e.g., electricity, coal, uranium, oil) produced and consumed across the energy system" - ":math:`\text{C}^w`", ":code:`commodity, flag = w, wa , wp`", ":code:`commodity_waste`", "commodity whose production can be greater than its consumption; can be physical, annual, or neither (not balanced, all wasted)" - ":math:`\text{C}^a`", ":code:`commodity, flag = a`", ":code:`commodity_annual`", "same as commodity physical but flows are only balanced over each period (:math:`\text{C}^a \subset \text{C}^p`)" - ":math:`\text{C}^l`", ":code:`commodity, flag = l`", ":code:`commodity_flex`", "(disposable) commodities produced by a flex technology (:math:`\text{C}^l \subset \text{C}^p`)" + ":math:`\text{C}^p`", ":code:`commodity, flag IN (p, wp, s, a, wa)`", ":code:`commodity_physical`", "superset of physical, source, annual, and their waste variants; includes all non-demand, non-emission commodities" + ":math:`\text{C}^w`", ":code:`commodity, flag IN (w, wa , wp)`", ":code:`commodity_waste`", "commodity whose production can be greater than its consumption; can be physical, annual, or neither (not balanced, all wasted)" + ":math:`\text{C}^a`", ":code:`commodity, flag IN (a, wa)`", ":code:`commodity_annual`", "commodities whose flows are only balanced over each period, not per-timeslice (:math:`\text{C}^a \subset \text{C}^p`)" + ":math:`{}^*\text{C}^l`", "", ":code:`commodity_flex`", "derived set of commodities produced by a flex technology (:math:`\text{C}^l \subset \text{C}^p`); auto-populated from :code:`tech_flex` outputs" ":math:`\text{C}^s`", ":code:`commodity, flag = s`", ":code:`commodity_source`", "primary source commodities, not balanced by :code:`CommodityBalance_constraint`" ":math:`{}^*\text{C}^c`", "", ":code:`commodity_carrier`", "union of physical, demand, and waste commodities, (:math:`\text{C}_p \cup \text{C}_d \cup \text{C}^w`)" ":math:`{}^*\text{C}`", "", ":code:`commodity_all`", "union of all commodity sets; union of carrier and emissions commodities" @@ -111,4 +110,4 @@ structures during model construction and are not considered formal model element - :code:`process_inputs`, :code:`process_outputs`, :code:`process_loans` - :code:`active_flow_rpsditvo`, :code:`active_flow_rpitvo` - Various vintage and operational tracking dictionaries -- Time sequencing dictionaries (:code:`time_next`, :code:`time_next_sequential`) \ No newline at end of file +- Time sequencing dictionaries (:code:`time_next`, :code:`time_next_sequential`) From 52b088fb07aca31fd2bd74ee87aebbf1a35e258d Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Mar 2026 13:40:18 -0400 Subject: [PATCH 522/587] Audit quick start --- docs/source/quick_start.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/source/quick_start.rst b/docs/source/quick_start.rst index 801720840..7664bb4c9 100644 --- a/docs/source/quick_start.rst +++ b/docs/source/quick_start.rst @@ -109,6 +109,7 @@ the solver, and (5) to execute several of the modeling extensions. COMMAND run Run a Temoa model validate Validate a configuration file + check-units Check unit consistency in a database migrate Migrate a database to the latest schema tutorial Create tutorial files @@ -190,26 +191,24 @@ recommend that you populate input tables in the following order: and sub-categorizing can be done in the Technology table itself. * time_period_type: Used to distinguish which time periods are simply used to specify pre-existing vintages and which represent future optimization periods. - * season_label: Unordered unique labels defining seasons in the model. **Group 2: sets used within Temoa** - * Commodity: list of commodities used within the database - * Technology: list of technologies used within the database + * commodity: list of commodities used within the database + * technology: list of technologies used within the database * time_period: list of both past and future time periods considered in the database - * time_season: seasons modeled in the database + * time_season: seasons modeled in the database (also contains segment fractions) * time_of_day: time of day segments modeled in the database **Group 3: parameters used to define processes within Temoa** * metadata_real (global_discount_rate) - * metadata (days_per_period) - * Demand + * demand * demand_specific_distribution * efficiency * existing_capacity - * capacity_factor - * capacity_factor_process (only if CF varies by vintage; overwrites capacity_factor) + * capacity_factor_tech + * capacity_factor_process (only if CF varies by vintage; overwrites capacity_factor_tech) * capacity_to_activity * cost_fixed * cost_invest @@ -217,9 +216,9 @@ recommend that you populate input tables in the following order: * emission_activity * lifetime_tech * lifetime_process (only if LT varies by vintage; overwrites lifetime_tech) - * time_segment_fraction: proportion of each period represented by each time slice -**Group 4: parameters used to define constraints within Temoa** + +**Group 4: parameters used to define constraints within Temoa** (non-exhaustive) * limit_activity * limit_capacity * limit_emission @@ -229,6 +228,7 @@ recommend that you populate input tables in the following order: * limit_tech_input_split * limit_tech_output_split + For help getting started, take a look at how ``data_files/example_dbs/utopia.sql`` is constructed. To begin building your own database file, use ``data_files/temoa_schema_v4.sql``, which is a database file with the requisite From 70eae0277c21db6244216a578fda9df695230ddc Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Mar 2026 13:41:21 -0400 Subject: [PATCH 523/587] Couple minor fixes in unit_checking docs --- docs/source/unit_checking.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/source/unit_checking.rst b/docs/source/unit_checking.rst index 9818fdce4..79ec5c1fb 100644 --- a/docs/source/unit_checking.rst +++ b/docs/source/unit_checking.rst @@ -55,7 +55,6 @@ Add to your ``config.toml``: .. code-block:: toml - [model_checks] check_units = true Via CLI @@ -366,7 +365,7 @@ Best Practices 3. **Be consistent**: Use the same unit style across your database (e.g., always "PJ" not mix of "PJ"/"petajoule") 4. **Test early**: Run unit checker on partial databases during development 5. **Document assumptions**: Use notes fields to explain unusual unit choices -6. **Reference implementation**: See ``temoa/tutorial_assets/utopia.sqlite`` for a fully compliant example +6. **Reference implementation**: See ``temoa/tutorial_assets/utopia.sql`` for a fully compliant example Quick Reference --------------- From b5fd00934d1bb687c78d41dabe9c65d8b81a84ec Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Mar 2026 13:43:55 -0400 Subject: [PATCH 524/587] Audit capacity constraint docstrings --- temoa/components/capacity.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/temoa/components/capacity.py b/temoa/components/capacity.py index 5b8cac0f2..3084ea41b 100644 --- a/temoa/components/capacity.py +++ b/temoa/components/capacity.py @@ -394,8 +394,8 @@ def capacity_annual_constraint( :label: CapacityAnnual \text{C2A}_{r, t} - \cdot \textbf{CAP}_{r, t, v} - = + \cdot \textbf{CAP}_{r, p, t, v} + \ge \sum_{I, O} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} \\ @@ -429,11 +429,11 @@ def capacity_constraint( :label: Capacity \left ( - \text{CFP}_{r, p, s, d, t, v} + \text{CFP}_{r, s, d, t, v} \cdot \text{C2A}_{r, t} \cdot \text{SEG}_{s, d} \right ) - \cdot \textbf{CAP}_{r, t, v} + \cdot \textbf{CAP}_{r, p, t, v} = \sum_{I, O} \textbf{FO}_{r, p, s, d, i, t, v, o} + From 38abb0558ebb348fc9a60672f66606acad6fc2b2 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Mar 2026 13:54:44 -0400 Subject: [PATCH 525/587] Audit demand and commodity constraint docstrings --- temoa/components/commodities.py | 47 ++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index 4a4694fcc..674fe8188 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -190,20 +190,24 @@ def annual_commodity_balance_constraint_indices( def demand_constraint(model: TemoaModel, r: Region, p: Period, dem: Commodity) -> ExprLike: r""" - The Demand constraint drives the model. This constraint ensures that supply at - least meets the demand specified by the Demand parameter in all periods and - slices, by ensuring that the sum of all the demand output commodity (:math:`c`) - generated by both commodity flow at the time slice level (:math:`\textbf{FO}`) and - the annual level (:math:`\textbf{FOA}`) must meet the modeler-specified demand - in each time slice. + The Demand constraint drives the model. This constraint ensures that supply + meets the demand specified by the Demand parameter in all periods, + by ensuring that the sum of all the annual demand output commodity (:math:`dem`) + generated by :math:`\textbf{FOA}` across all technologies and vintages + equals the modeler-specified demand. .. math:: :label: Demand - \sum_{I, T-T^{a}, V} \textbf{FO}_{r, p, s, d, i, t \not \in T^{a}, v, dem} + - SEG_{s,d} \cdot \sum_{I, T^{a}, V} \textbf{FOA}_{r, p, i, t \in T^{a}, v, dem} + \sum_{I, T, V} \textbf{FOA}_{r, p, i, t, v, dem} = - {DEM}_{r, p, dem} \cdot {DSD}_{r, s, d, dem} + {DEM}_{r, p, dem} + + The per-timeslice distribution of demand across non-annual technologies + is enforced by the separate :code:`demand_activity_constraint`. In the case of + a singleton demand, where only one :code:`(r, i, t, v)` sub-process produces the + demand commodity, the flow variables are fixed directly and demand constraints + are skipped. Note that the validity of this constraint relies on the fact that the :math:`C^d` set is distinct from both :math:`C^e` and :math:`C^p`. In other @@ -248,25 +252,26 @@ def demand_activity_constraint( night. This constraint ensures that the ratio of a process activity to demand is - constant for all time slices. Note that if a demand is not specified in a given - time slice, or is zero, then this constraint will not be considered for that - slice and demand. This is transparently handled by the :math:`\Theta` superset. + constant for all time slices. In other words, while the model may choose how + each technology contributes to a demand at the annual level, the time slice + level distribution of the technology's contribution to the demand is fixed to + the demand specific distribution. .. math:: :label: DemandActivity - DEM_{r, p, s, d, dem} \cdot \sum_{I} - \textbf{FO}_{r, p, s_0, d_0, i, t \not \in T^{a}, v, dem} + \sum_{I} + \textbf{FOA}_{r, p, i, t, v, dem} + \cdot \text{DSD}_{r, s, d, dem} = - DEM_{r, p, s_0, d_0, dem} \cdot \sum_{I} - \textbf{FO}_{r, p, s, d, i, t \not \in T^{a}, v, dem} + \sum_{I} + \textbf{FO}_{r, p, s, d, i, t, v, dem} \\ - \forall \{r, p, s, d, t, v, dem, s_0, d_0\} \in \Theta_{\text{DemandActivity}} + \forall \{r, p, s, d, t, v, dem\} \in \Theta_{\text{DemandActivity}} - Note that this constraint is only applied to the demand commodities with diurnal - variations, and therefore the equation above only includes :math:`\textbf{FO}` - and not :math:`\textbf{FOA}` + Note that this constraint is unnecessary and therefore skipped for annual + technologies or singleton demands. """ activity = sum( @@ -358,7 +363,7 @@ def commodity_balance_constraint( &\sum_{I, t \notin T^a, V} \mathbf{FO}_{r, p, s, d, i, t, v, c} && \text{(processes outputting commodity)} \\ &+ SEG_{s,d} \cdot \sum_{I, t \in T^a, V} - \frac{\mathbf{FOA}_{r, p, i, t, v, c}}{EFF_{r, i, t, v, c}} + \mathbf{FOA}_{r, p, i, t, v, c} && \text{(annual processes outputting commodity)} \\ &+ \sum_{\text{reg} \neq r, I, t \in T^x, V} \mathbf{FIM}_{r - \text{reg}, p, s, d, i, t, v, c} From b4e7a51b8e96a96028e04cd87ccffaa08de92608 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Mar 2026 13:56:41 -0400 Subject: [PATCH 526/587] Audit some param indices in total cost docstring --- temoa/components/costs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/temoa/components/costs.py b/temoa/components/costs.py index 1c91d78ea..ffa0358ed 100644 --- a/temoa/components/costs.py +++ b/temoa/components/costs.py @@ -629,13 +629,13 @@ def total_cost_rule(model: TemoaModel) -> Expression: & \text{where } t \in T^a \\ &+\\ C_{emissions} =& \sum_{r, p, e \in \Theta_{CE}} CE_{r, p, e} - \cdot EAC_{r, i, t, v, o, e} \cdot \sum_{S, D, I, O} + \cdot EAC_{r, e, i, t, v, o} \cdot \sum_{S, D, I, O} \mathbf{FO}_{r, p, s, d, i, t, v, o} && \text{(annual emission cost on flow)} \\ & \text{where } t \notin T^a \\ &+\\ & \sum_{r, p, e \in \Theta_{CE}} CE_{r, p, e} - \cdot EAC_{r, i, t, v, o, e} \cdot \sum_{I, O} \mathbf{FOA}_{r, p, i, t, v, o} + \cdot EAC_{r, e, i, t, v, o} \cdot \sum_{I, O} \mathbf{FOA}_{r, p, i, t, v, o} && \text{(annual emission cost on annual flows)} \\ & \text{where } t \in T^a \\ &+\\ From 071fdbdadbf2eb32200be84d2bef51739d589db8 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Mar 2026 14:11:53 -0400 Subject: [PATCH 527/587] Updated linked_emissions_tech docstring and add to docs --- docs/source/mathematical_formulation.rst | 6 ++---- temoa/components/emissions.py | 19 ++++++++++++------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/docs/source/mathematical_formulation.rst b/docs/source/mathematical_formulation.rst index 3dd4c8fdd..6c4bc48df 100644 --- a/docs/source/mathematical_formulation.rst +++ b/docs/source/mathematical_formulation.rst @@ -1455,6 +1455,8 @@ various physical and operational real-world phenomena. .. autofunction:: temoa.components.reserves.reserve_margin_dynamic +.. autofunction:: temoa.components.emissions.linked_emissions_tech_constraint + Objective Function ~~~~~~~~~~~~~~~~~~ @@ -1480,8 +1482,6 @@ User-Specific Constraints .. autofunction:: temoa.components.limits.limit_activity_share_constraint -.. _max_capacity_constraint: - .. autofunction:: temoa.components.limits.limit_capacity_constraint .. autofunction:: temoa.components.limits.limit_new_capacity_constraint @@ -1492,8 +1492,6 @@ User-Specific Constraints .. autofunction:: temoa.components.limits.limit_resource_constraint -.. _TechOutputSplit_constraint: - .. autofunction:: temoa.components.limits.limit_tech_input_split_constraint .. autofunction:: temoa.components.limits.limit_tech_output_split_constraint diff --git a/temoa/components/emissions.py b/temoa/components/emissions.py index 4ee6669de..4efeb09fe 100644 --- a/temoa/components/emissions.py +++ b/temoa/components/emissions.py @@ -81,7 +81,7 @@ def linked_emissions_tech_constraint( e: Commodity, ) -> ExprLike: r""" - This constraint is necessary for carbon capture technologies that produce + This constraint can be used for carbon capture technologies that produce CO2 as an emissions commodity, but the CO2 also serves as a physical input commodity to a downstream process, such as synthetic fuel production. To accomplish this, a dummy technology is linked to the CO2-producing @@ -89,16 +89,21 @@ def linked_emissions_tech_constraint( amount as follows: .. math:: - :label: LinkedEmissionsTech + :label: linked_emissions_tech - - \sum_{I, O} \textbf{FO}_{r, p, s, d, i, t, v, o} \cdot EAC_{r, e, i, t, v, o} - = \sum_{I, O} \textbf{FO}_{r, p, s, d, i, t, v, o} + - \sum_{I, O} \textbf{FO}_{r, p, s, d, i, t, v, o} \cdot EAC_{r, e, i, t, v, o} + = \sum_{I, O} \textbf{FO}_{r, p, s, d, i, \hat{t}, v, o} - \forall \{r, p, s, d, t, v, e\} \in \Theta_{\text{linked_techs}} + \forall \{r, p, s, d, t, v, e\} \in \Theta_{\text{linked\_techs}} + + where :math:`\hat{t} = LT_{r,t,e}` is the linked technology for primary technology + :math:`t` and emissions commodity :math:`e`. For annual technologies + (:math:`t \in T^a` or :math:`\hat{t} \in T^a`), the corresponding + :math:`\textbf{FOA}` variable scaled by :math:`DSD` (for end use demand techs) + or :math:`SEG` (for all other annual techs) is used instead. The relationship between the primary and linked technologies is given - in the :code:`linked_techs` table. Note that the primary and linked - technologies cannot be part of the :code:`tech_annual` set. It is implicit that + in the :code:`linked_techs` table. 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. """ From 2f7a7998df0c906ca13c6bc119949a291c6d9e84 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Mar 2026 14:48:48 -0400 Subject: [PATCH 528/587] Audit limit docstrings and include operator notation --- temoa/components/limits.py | 80 +++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 31 deletions(-) diff --git a/temoa/components/limits.py b/temoa/components/limits.py index 4d2cd0951..eb4eb5096 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -277,9 +277,9 @@ def limit_resource_constraint(model: TemoaModel, r: Region, t: Technology, op: s \sum_{P,S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t \notin T^a, v, o} - +\sum_{P,I,V,O} \textbf{FO}_{r, p, i, t \in T^a, v, o} + +\sum_{P,I,V,O} \textbf{FOA}_{r, p, i, t \in T^a, v, o} - \le LR_{r, t} + \quad \le, \ge, \text{or} = \quad LS_{r, t} \forall \{r, t\} \in \Theta_{\text{limit\_resource}}""" # dev note: this constraint is a misnomer. It is actually a "global activity constraint on a @@ -333,7 +333,7 @@ def limit_activity_share_constraint( \sum_{R_g \subseteq R,\ S,\ D,\ I,\ T^{g_1} \subseteq T,\ V,\ O} \mathbf{FO}_{r,p,s,d,i,t,v,o} - \leq LAS_{r,p,g_1,g_2} \cdot + \quad \le, \ge, \text{or} = \quad LAS_{r,p,g_1,g_2} \cdot \sum_{R_g \subseteq R,\ S,\ D,\ I,\ T^{g_2} \subseteq T,\ V,\ O} \mathbf{FO}_{r,p,s,d,i,t,v,o} @@ -481,15 +481,21 @@ def limit_annual_capacity_factor_constraint( .. math:: :label: limit_annual_capacity_factor - \sum_{S,D,I} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMACF_{r, t, v, o} \cdot + \sum_{S,D,I} \textbf{FO}_{r, p, s, d, i, t, v, o} + \quad \le, \ge, \text{or} = \quad + LIMACF_{r, t, v, o} \cdot \textbf{CAP}_{r, p, t, v} \cdot \text{C2A}_{r, t} - \forall \{r, t \notin T^{a}, v, o\} \in \Theta_{\text{limit\_annual\_capacity\_factor}} + \forall \{r, p, t \notin T^{a}, v, o\} + \in \Theta_{\text{limit\_annual\_capacity\_factor}} - \\\sum_{I} \textbf{FOA}_{r, p, i, t, v, o} \ge LIMACF_{r, t, v, o} \cdot + \\\sum_{I} \textbf{FOA}_{r, p, i, t, v, o} + \quad \le, \ge, \text{or} = \quad + LIMACF_{r, t, v, o} \cdot \textbf{CAP}_{r, p, t, v} \cdot \text{C2A}_{r, t} - \forall \{r, t \in T^{a}, v, o\} \in \Theta_{\text{limit\_annual\_capacity\_factor}} + \forall \{r, p, t \in T^{a}, v, o\} \in \Theta_{\text{limit\_annual\_capacity\_factor}} + """ # r can be an individual region (r='US'), or a combination of regions separated by plus # (r='Mexico+US+Canada'), or 'global'. @@ -544,16 +550,19 @@ def limit_seasonal_capacity_factor_constraint( .. math:: :label: Limit Seasonal Capacity Factor - \sum_{D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le LIMSCF_{r, p, s, t} \cdot - \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} + \sum_{D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} + \quad \le, \ge, \text{or} = \quad + LIMSCF_{r, s, t} \cdot + \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} \cdot SFS_s - \forall \{r, p, t \notin T^{a}, o\} \in \Theta_{\text{limit\_seasonal\_capacity\_factor}} + \forall \{r, p, s, t \notin T^{a}\} \in \Theta_{\text{limit\_seasonal\_capacity\_factor}} - \\\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \cdot \sum_{D} SEG_{s,d} - \le LIMSCF_{r, p, s, t} \cdot - \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} + \\\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \cdot SFS_s + \quad \le, \ge, \text{or} = \quad + LIMSCF_{r, s, t} \cdot + \textbf{CAPAVL}_{r, p, t} \cdot \text{C2A}_{r, t} \cdot SFS_s - \forall \{r, p, t \in T^{a}, o\} \in \Theta_{\text{limit\_seasonal\_capacity\_factor}} + \forall \{r, p, s, t \in T^{a}\} \in \Theta_{\text{limit\_seasonal\_capacity\_factor}} """ # r can be an individual region (r='US'), or a combination of regions separated by plus # (r='Mexico+US+Canada'), or 'global'. @@ -746,7 +755,7 @@ def limit_tech_output_split_constraint( :label: limit_tech_output_split \sum_{I, t \not \in T^{a}} \textbf{FO}_{r, p, s, d, i, t, v, o} - \geq + \quad \le, \ge, \text{or} = \quad TOS_{r, p, t, o} \cdot \sum_{I, O, t \not \in T^{a}} \textbf{FO}_{r, p, s, d, i, t, v, o} \forall \{r, p, s, d, t, v, o\} \in \Theta_{\text{limit\_tech\_output\_split}}""" @@ -779,9 +788,9 @@ def limit_tech_output_split_annual_constraint( :label: limit_tech_output_split_annual \sum_{I, T^{a}} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} - \geq - TOS_{r, p, t, o} \cdot - \sum_{I, O, T^{a}} \textbf{FOA}_{r, p, s, d, i, t \in T^{a}, v, o} + \quad \le, \ge, \text{or} = \quad + TOSA_{r, p, t, o} \cdot + \sum_{I, O, T^{a}} \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} \forall \{r, p, t \in T^{a}, v, o\} \in \Theta_{\text{limit\_tech\_output\_split\_annual}}""" @@ -845,7 +854,8 @@ def limit_emission_constraint( limit_emission constraint allows the modeler to assign an upper bound per period to each emission commodity. Note that this constraint sums emissions from technologies with output varying at the time slice and those with constant annual - output in separate terms. + output in separate terms. It also includes embodied emissions from new capacity + and end-of-life emissions from retiring capacity. .. math:: :label: limit_emission @@ -856,9 +866,14 @@ def limit_emission_constraint( + \sum_{I,T,V,O|{r,e,i,t \in T^{a},v,o} \in EAC} ( EAC_{r, e, i, t, v, o} \cdot & \textbf{FOA}_{r, p, i, t \in T^{a}, v, o} - ) - \le - ELM_{r, p, e} + ) \\ + + + \sum_{T} \frac{EE_{r, e, t, v=p} \cdot \textbf{NCAP}_{r, t, v=p}}{LEN_p} & \\ + + + \sum_{T,V} EEOL_{r, e, t, v} \cdot \textbf{ART}_{r, p, t, v} & + \\ + \quad \le, \ge, \text{or} = \quad + LE_{r, p, e} \\ & \forall \{r, p, e\} \in \Theta_{\text{limit\_emission}} @@ -970,7 +985,8 @@ def limit_growth_capacity( \begin{aligned}\text{Growth:}\\ &\mathbf{CAPAVL}_{r,p,t} - \leq S_{r,t} + (1+R_{r,t}) \cdot \mathbf{CAPAVL}_{r,p_{prev},t} + \quad \le, \ge, \text{or} = \quad + S_{r,t} + (1+R_{r,t}) \cdot \mathbf{CAPAVL}_{r,p_{prev},t} \end{aligned} \qquad \forall \{r, p, t\} \in \Theta_{\text{limit\_growth\_capacity}} @@ -978,7 +994,7 @@ def limit_growth_capacity( \begin{aligned}\text{Degrowth:}\\ &\mathbf{CAPAVL}_{r,p_{prev},t} - \leq S_{r,t} + (1+R_{r,t}) \cdot \mathbf{CAPAVL}_{r,p,t} + \quad \le, \ge, \text{or} = \quad S_{r,t} + (1+R_{r,t}) \cdot \mathbf{CAPAVL}_{r,p,t} \end{aligned} \qquad \forall \{r, p, t\} \in \Theta_{\text{limit\_degrowth\_capacity}} @@ -1090,7 +1106,8 @@ def limit_growth_new_capacity( \begin{aligned}\text{Growth:}\\ &\mathbf{NCAP}_{r,t,v} - \leq S_{r,t} + (1+R_{r,t}) \cdot \mathbf{NCAP}_{r,t,v_{prev}} + \quad \le, \ge, \text{or} = \quad + S_{r,t} + (1+R_{r,t}) \cdot \mathbf{NCAP}_{r,t,v_{prev}} \text{ where } v=p \end{aligned} @@ -1098,7 +1115,7 @@ def limit_growth_new_capacity( \begin{aligned}\text{Degrowth:}\\ &\mathbf{NCAP}_{r,t,v_{prev}} - \leq S_{r,t} + (1+R_{r,t}) \cdot \mathbf{NCAP}_{r,t,v} + \quad \le, \ge, \text{or} = \quad S_{r,t} + (1+R_{r,t}) \cdot \mathbf{NCAP}_{r,t,v} \text{ where } v=p \end{aligned} @@ -1208,7 +1225,7 @@ def limit_growth_new_capacity_delta( \begin{aligned}\text{Growth:}\\ &\mathbf{NCAP}_{r,t,v_i} - \mathbf{NCAP}_{r,t,v_{i-1}} - \leq S_{r,t} + (1+R_{r,t}) \cdot + \quad \le, \ge, \text{or} = \quad S_{r,t} + (1+R_{r,t}) \cdot (\mathbf{NCAP}_{r,t,v_{i-1}} - \mathbf{NCAP}_{r,t,v_{i-2}}) \end{aligned} @@ -1218,7 +1235,8 @@ def limit_growth_new_capacity_delta( \begin{aligned}\text{Degrowth:}\\ &\mathbf{NCAP}_{r,t,v_{i-1}} - \mathbf{NCAP}_{r,t,v_{i-2}} - \leq S_{r,t} + (1+R_{r,t}) \cdot (\mathbf{NCAP}_{r,t,v_i} - \mathbf{NCAP}_{r,t,v_{i-1}}) + \quad \le, \ge, \text{or} = \quad + S_{r,t} + (1+R_{r,t}) \cdot (\mathbf{NCAP}_{r,t,v_i} - \mathbf{NCAP}_{r,t,v_{i-1}}) \end{aligned} \text{ where } v_i=p @@ -1345,7 +1363,7 @@ def limit_activity_constraint( \forall \{r, p, t \in T^{a}\} \in \Theta_{\text{limit\_activity}} - \le LA_{r, p, t} + \quad \le, \ge, \text{or} = \quad LA_{r, p, t} """ # r can be an individual region (r='US'), or a combination of regions separated by # a + (r='Mexico+US+Canada'), or 'global'. @@ -1392,7 +1410,7 @@ def limit_new_capacity_constraint( .. math:: :label: limit_new_capacity - \textbf{NCAP}_{r, t, v} \le LNC_{r, t, v} + \textbf{NCAP}_{r, t, v} \quad \le, \ge, \text{or} = \quad LNC_{r, t, v} """ regions = geography.gather_group_regions(model, r) techs = technology.gather_group_techs(model, t) @@ -1421,7 +1439,7 @@ def limit_capacity_constraint( .. math:: :label: limit_capacity - \textbf{CAPAVL}_{r, p, t} \le LC_{r, p, t} + \textbf{CAPAVL}_{r, p, t} \quad \le, \ge, \text{or} = \quad LC_{r, p, t} \forall \{r, p, t\} \in \Theta_{\text{limit\_capacity}}""" regions = geography.gather_group_regions(model, r) From fff0ab4a2adbd1d4f64708a6237b3985e385da60 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Mar 2026 14:51:13 -0400 Subject: [PATCH 529/587] Audit ramping constraint docstrings --- temoa/components/operations.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/temoa/components/operations.py b/temoa/components/operations.py index 8274d6906..ede90c087 100644 --- a/temoa/components/operations.py +++ b/temoa/components/operations.py @@ -272,31 +272,29 @@ def ramp_up_day_constraint( \frac{ \sum_{I,O} \mathbf{FO}_{r,p,s_{next},d_{next},i,t,v,o} }{ - SEG_{r,p,s_{next},d_{next}} \cdot 24 \cdot DPP + SEG_{s_{next},d_{next}} \cdot 24 \cdot DPP } - \frac{ \sum_{I,O} \mathbf{FO}_{r,p,s,d,i,t,v,o} }{ - SEG_{r,p,s,d} \cdot 24 \cdot DPP + SEG_{s,d} \cdot 24 \cdot DPP } \leq - R_{r,t} \cdot \Delta H_{r,p,s,d,s_{next},d_{next}} \cdot CAP_{r,p,t,v} \cdot C2A_{r,t} + RUH_{r,t} \cdot \Delta H \cdot \frac{CAP_{r,p,t,v} \cdot C2A_{r,t}}{24 \cdot DPP} \\ \forall \{r, p, s, d, t, v\} \in \Theta_{\text{ramp\_up\_day}} \\ - \text{where: } \Delta H_{r,p,s,d,s_{next},d_{next}} = \frac{24}{2} - \left ( \frac{SEG_{r,p,s,d}}{\sum_{D} SEG_{r,p,s,d'}} + - \frac{SEG_{r,p,s_{next},d_{next}}}{\sum_{D} SEG_{r,p,s_{next},d'}} \right ) + \text{where: } \Delta H = \frac{H_d + H_{d_{next}}}{2} where: - - :math:`SEG_{r,p,s,d}` is the fraction of the period in time slice :math:`(s,d)` + - :math:`SEG_{s,d}` is the fraction of the period in time slice :math:`(s,d)` - :math:`DPP` is the number of days in each period - - :math:`R_{r,t}` is the ramp rate per hour - - :math:`\Delta H_{r,p,s,d,s_{next},d_{next}}` is the number of elapsed hours between midpoints - of time slices - - :math:`CAP \cdot C2A` gives the maximum hourly change in activity + - :math:`RUH_{r,t}` is the ramp up rate per hour + - :math:`\Delta H` is the average of the hours in timeslice :math:`d` and :math:`d_{next}`, + i.e. :math:`(H_d + H_{d_{next}}) / 2` + - :math:`CAP \cdot C2A / (24 \cdot DPP)` gives the maximum hourly capacity """ s_next, d_next = model.time_next[s, d] @@ -370,18 +368,20 @@ def ramp_down_day_constraint( \frac{ \sum_{I,O} \mathbf{FO}_{r,p,s,d,i,t,v,o} }{ - SEG_{r,p,s,d} \cdot 24 \cdot DPP + SEG_{s,d} \cdot 24 \cdot DPP } - \frac{ \sum_{I,O} \mathbf{FO}_{r,p,s_{next},d_{next},i,t,v,o} }{ - SEG_{r,p,s_{next},d_{next}} \cdot 24 \cdot DPP + SEG_{s_{next},d_{next}} \cdot 24 \cdot DPP } \leq - R_{r,t} \cdot \Delta H_{r,p,s,d,s_{next},d_{next}} \cdot CAP_{r,p,t,v} \cdot C2A_{r,t} + RDH_{r,t} \cdot \Delta H \cdot \frac{CAP_{r,p,t,v} \cdot C2A_{r,t}}{24 \cdot DPP} \\ \forall \{r, p, s, d, t, v\} \in \Theta_{\text{ramp\_down\_day}} + \\ + \text{where: } \Delta H = \frac{H_d + H_{d_{next}}}{2} """ s_next, d_next = model.time_next[s, d] From 1dfaf3388b0d23a68408fdcd3ca2c9b5a157a08a Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Mar 2026 14:56:48 -0400 Subject: [PATCH 530/587] Audit reserve margin docstrings --- temoa/components/reserves.py | 46 +++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/temoa/components/reserves.py b/temoa/components/reserves.py index 1a65f5add..7b65aceed 100644 --- a/temoa/components/reserves.py +++ b/temoa/components/reserves.py @@ -58,28 +58,30 @@ def reserve_margin_dynamic( .. math:: :label: reserve_margin_dynamic - &\sum_{t \in T^{res} \setminus T^{x} \setminus T^s,\ V} CFP_{r,p,s^*,d^*,t,v}\ - \cdot RCD_{r,p,s^*,t,v}\ - \cdot \mathbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*}\ + &\sum_{t \in T^{res} \setminus T^{x} \setminus T^s,\ V} CFP_{r,s^*,d^*,t,v}\ + \cdot RCD_{r,s^*,t,v}\ + \cdot \mathbf{CAP}_{r,p,t,v} \cdot SEG_{s^*,d^*}\ \cdot C2A_{r,t} \\ - &+ \sum_{t \in T^{res} \cap T^{x} \setminus T^s,\ V} CFP_{r_i - r, p, s^*, d^*, t, v}\ - \cdot RCD_{r_i - r, p, s^*, t, v}\ - \cdot \mathbf{CAPAVL}_{p,t} \cdot SEG_{s^*,d^*}\ + &+ \sum_{t \in T^{res} \cap T^{x} \setminus T^s,\ V} CFP_{r_i - r, s^*, d^*, t, v}\ + \cdot RCD_{r_i - r, s^*, t, v}\ + \cdot \mathbf{CAP}_{r_i - r,p,t,v} \cdot SEG_{s^*,d^*}\ \cdot C2A_{r_i - r, t} \\ - &- \sum_{t \in T^{res} \cap T^{x} \setminus T^s,\ V} CFP_{r - r_i, p, s^*, d^*, t, v}\ - \cdot RCD_{r - r_i, p, s^*, t, v}\ - \cdot \mathbf{CAPAVL}_{p,t}\ + &- \sum_{t \in T^{res} \cap T^{x} \setminus T^s,\ V} CFP_{r - r_i, s^*, d^*, t, v}\ + \cdot RCD_{r - r_i, s^*, t, v}\ + \cdot \mathbf{CAP}_{r - r_i,p,t,v}\ \cdot SEG_{s^*,d^*} \cdot C2A_{r - r_i, t} \\ &+ \sum_{t \in (T^s \cap T^{res}), V, I, O} \ \left(\ \mathbf{FO}_{r,p,s,d,i,t,v,o} - \mathbf{FI}_{r,p,s,d,i,t,v,o}\ \right)\ - \cdot RCD_{r,p,s,t,v} \\ + \cdot RCD_{r,s,t,v} \\ &\geq\ \left[\ - \sum_{t \in T^{res} \setminus T^{x}, V, I, O}\ + \sum_{t \in T^{res} \setminus T^{x} \setminus T^a, V, I, O}\ \mathbf{FO}_{r, p, s, d, i, t, v, o}\ \right. \\ + &+ \sum_{t \in T^{res} \cap T^a, V, I, O}\ + DSD_{r,s,d,o} \cdot \mathbf{FOA}_{r, p, i, t, v, o} \\ &+ \sum_{t \in T^{res} \cap T^{x}, V, I, O} \ \mathbf{FO}_{r_i - r, p, s, d, i, t, v, o} \\ &- \sum_{t \in T^{res} \cap T^{x}, V, I, O} \ @@ -175,26 +177,36 @@ def reserve_margin_static( r""" During each period :math:`p`, the sum of capacity values of all reserve - technologies :math:`\sum_{t \in T^{res}} \textbf{CAPAVL}_{r,p,t}`, which are + technologies :math:`\sum_{t \in T^{res}} \textbf{CAP}_{r,p,t,v}`, which are defined in the set :math:`\textbf{T}^{res}`, should exceed the peak load by :math:`PRM`, the regional reserve margin. Note that the reserve margin is expressed in percentage of the peak load. Generally speaking, in a database we may not know the peak demand before running the model, therefore, we write this equation for all the time-slices defined in the database in each region. Each generator is allowed to contribute its available capacity times a pre-defined - capacity credit, :math:`CC_{t,r}` + capacity credit, :math:`CC_{r,p,t,v}`. + + For exchange technologies (i.e., inter-regional transmission), reserve contributions + are added to the downstream region but *subtracted* from the upstream region. This is + because, since they are not generating any power, their summed contribution across + regions should be zero. .. math:: :label: reserve_margin_static - &\sum_{t \in T^{res} \setminus T^{x}} {CC_{t,r} \cdot \textbf{CAPAVL}_{p,t} \cdot + &\sum_{t \in T^{res} \setminus T^{x}, V} {CC_{r,p,t,v} + \cdot \textbf{CAP}_{r,p,t,v} \cdot SEG_{s^*,d^*} \cdot C2A_{r,t} }\\ - &+ \sum_{t \in T^{res} \cap T^{x}} {CC_{t,r_i-r} \cdot \textbf{CAPAVL}_{p,t} \cdot + &+ \sum_{t \in T^{res} \cap T^{x}, V} {CC_{r_i-r,p,t,v} + \cdot \textbf{CAP}_{r_i-r,p,t,v} \cdot SEG_{s^*,d^*} \cdot C2A_{r_i-r,t} }\\ - &- \sum_{t \in T^{res} \cap T^{x}} {CC_{t,r-r_i} \cdot \textbf{CAPAVL}_{p,t} \cdot + &- \sum_{t \in T^{res} \cap T^{x}, V} {CC_{r-r_i,p,t,v} + \cdot \textbf{CAP}_{r-r_i,p,t,v} \cdot SEG_{s^*,d^*} \cdot C2A_{r-r_i,t} }\\ - &\geq \left [ \sum_{ t \in T^{res} \setminus T^{x},V,I,O } + &\geq \left [ \sum_{ t \in T^{res} \setminus T^{x} \setminus T^a,V,I,O } \textbf{FO}_{r, p, s, d, i, t, v, o}\right.\\ + &+ \sum_{ t \in T^{res} \cap T^a,V,I,O } + DSD_{r,s,d,o} \cdot \textbf{FOA}_{r, p, i, t, v, o}\\ &+ \sum_{ t \in T^{res} \cap T^{x},V,I,O } \textbf{FO}_{r_i-r, p, s, d, i, t, v, o}\\ &- \sum_{ t \in T^{res} \cap T^{x},V,I,O } \textbf{FI}_{r-r_i, p, s, d, i, t, v, o}\\ &- \left.\sum_{ t \in T^{res} \cap T^{s},V,I,O } \textbf{FI}_{r, p, s, d, i, t, v, o} From 624169d853e41118f22c027f2f1de77ff74ca2e4 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Mar 2026 15:09:43 -0400 Subject: [PATCH 531/587] Audit storage constraint docstrings --- temoa/components/storage.py | 55 +++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/temoa/components/storage.py b/temoa/components/storage.py index 4f1aea8df..e573eb793 100644 --- a/temoa/components/storage.py +++ b/temoa/components/storage.py @@ -219,17 +219,16 @@ def seasonal_storage_energy_constraint( :label: Storage Energy (Sequential Seasons) \mathbf{SSL}_{r,p,s^{seq},t,v} - + DA_{r,p,s^{seq}} \cdot \left(\mathbf{SL}_{r,p,s^*,d_{last},t,v} + + + \frac{\text{SFS}_{s^{seq}}}{\text{SFS}_{s^*}} + \cdot \left(\mathbf{SL}_{r,p,s^*,d_{last},t,v} + \sum_{I,O} \mathbf{FI}_{r,p,s^*,d_{last},i,t,v,o} \cdot EFF_{r,i,t,v,o} - \sum_{I,O} \mathbf{FO}_{r,p,s^*,d_{last},i,t,v,o} \right) - = DA_{r,p,s^{seq}_{next}} \cdot \mathbf{SL}_{r,p,s_{next}^*,d_{first},t,v} + = \frac{\text{SFS}_{s^{seq}_{next}}}{\text{SFS}_{s^*_{next}}} + \cdot \mathbf{SL}_{r,p,s_{next}^*,d_{first},t,v} + \mathbf{SSL}_{r,p,s^{seq}_{next},t,v} - \\ - \text{where } DA_{r,p,s^{seq}} = \frac{\#days_{s^{seq}}}{SEG_{r,p,s^*} \cdot DPP} - .. figure:: images/ldes_chain.* :align: center :width: 100% @@ -317,7 +316,7 @@ def storage_energy_upper_bound_constraint( :label: StorageEnergyUpperBound \textbf{SL}_{r, p, s, d, t, v} \le - \textbf{CAP}_{r,t,v} \cdot C2A_{r,t} \cdot \frac {SD_{r,t}}{24 \cdot DPP} + \textbf{CAP}_{r,p,t,v} \cdot C2A_{r,t} \cdot \frac {SD_{r,t}}{24 \cdot DPP} \cdot \sum_{d} SEG_{s,d} \cdot DPP \\ @@ -365,13 +364,9 @@ def seasonal_storage_energy_upper_bound_constraint( :label: Seasonal Storage Energy Capacity \mathbf{SSL}_{r,p,s^{seq},t,v} - + \mathbf{SL}_{r,p,s^*,d,t,v} \cdot DA_{r,p,s^{seq}} + + \mathbf{SL}_{r,p,s^*,d,t,v} \cdot \frac{\text{SFS}_{s^{seq}}}{\text{SFS}_{s^*}} \leq \mathbf{CAP}_{r,p,t,v} \cdot C2A_{r,t} \cdot \frac{SD_{r,t}}{24 \cdot DPP} - \\ - - \text{where } DA_{r,p,s^{seq}} = \frac{\#days_{s^{seq}}}{SEG_{r,p,s^*} \cdot DPP} - Unlike non-seasonal (daily) storage, seasonal storage is allowed to carry energy @@ -444,7 +439,7 @@ def storage_charge_rate_constraint( \sum_{I, O} \textbf{FIS}_{r, p, s, d, i, t, v, o} \cdot EFF_{r,i,t,v,o} \le - \textbf{CAP}_{r,t,v} \cdot C2A_{r,t} \cdot SEG_{s,d} + \textbf{CAP}_{r,p,t,v} \cdot C2A_{r,t} \cdot SEG_{s,d} \\ \forall \{r, p, s, d, t, v\} \in \Theta_{\text{StorageChargeRate}} @@ -484,7 +479,7 @@ def storage_discharge_rate_constraint( \sum_{I, O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le - \textbf{CAP}_{r,t,v} \cdot C2A_{r,t} \cdot SEG_{s,d} + \textbf{CAP}_{r,p,t,v} \cdot C2A_{r,t} \cdot SEG_{s,d} \\ \forall \{r,p, s, d, t, v\} \in \Theta_{\text{StorageDischargeRate}} @@ -525,7 +520,7 @@ def storage_throughput_constraint( + \sum_{I, O} \textbf{FIS}_{r, p, s, d, i, t, v, o} \cdot EFF_{r,i,t,v,o} \le - \textbf{CAP}_{r,t,v} \cdot C2A_{r,t} \cdot SEG_{s,d} + \textbf{CAP}_{r,p,t,v} \cdot C2A_{r,t} \cdot SEG_{s,d} \\ \forall \{r, p, s, d, t, v\} \in \Theta_{\text{StorageThroughput}} @@ -567,27 +562,33 @@ def limit_storage_fraction_constraint( r""" This constraint is used if the users wishes to force a specific storage charge level - for certain storage technologies and vintages at a certain time slice. - In this case, the value of the decision variable :math:`\textbf{SI}_{r,t,v}` is set by - this constraint rather than being optimized. User-specified storage charge levels that are - sufficiently different from the optimal :math:`\textbf{SI}_{r,t,v}` could impact the - cost-effectiveness of storage. For example, if the optimal charge level happens to be - 50% of the full energy capacity, forced charge levels (specified by parameter - :math:`SIF_{r,t,v}`) equal to 10% or 90% of the full energycapacity could lead to - more expensive solutions. + for certain storage technologies and vintages at a certain time slice. User-specified + storage charge levels that are sufficiently different from the optimal could impact the + cost-effectiveness of storage. + + :code:`s` can be a season from the :code:`time_season` set or a sequential season from + the :code:`time_sequential_season` set. .. math:: :label: limit_storage_fraction - \textbf{SF}_{r,p,s,d,t,v} \le - SF_{r,p,s,d,t,v} - \cdot - \textbf{CAP}_{r,p,t,v} \cdot \text{C2A}_{r,t} \cdot \frac {SD_{r,t}}{24 \cdot \text{DPP}} - \cdot \sum_{d} \text{SEG}_{s,d} \cdot \text{days\_per\_period} \cdot \text{MPL}_{r,p,t,v} + \frac{\textbf{SL}_{r,p,s,d,t,v}}{\text{SFS}_s \cdot \text{DPP}} + \quad \le, \ge, \text{or} = \quad + \textbf{CAP}_{r,p,t,v} \cdot \text{C2A}_{r,t} + \cdot \frac{\text{SD}_{r,t}}{24 \cdot \text{DPP}} + \cdot \text{LSF}_{r,s,d,t} \\ \forall \{r, p, s, d, t, v\} \in \Theta_{\text{limit\_storage\_fraction}} + + For seasonal storage technologies, the LHS becomes: + + .. math:: + + \textbf{SSL}_{r,p,s_{seq},t,v} + + \frac{\text{SFS}_{s_{seq}}}{\text{SFS}_{s^*}} + \cdot \textbf{SL}_{r,p,s^*,d,t,v} """ energy_limit = ( From acc2209c2f8f46726efdff17ddd13b95aeac31eb Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Mar 2026 15:10:05 -0400 Subject: [PATCH 532/587] Remove old Sets section --- docs/source/mathematical_formulation.rst | 77 ------------------------ 1 file changed, 77 deletions(-) diff --git a/docs/source/mathematical_formulation.rst b/docs/source/mathematical_formulation.rst index 6c4bc48df..1190104fa 100644 --- a/docs/source/mathematical_formulation.rst +++ b/docs/source/mathematical_formulation.rst @@ -120,83 +120,6 @@ represents a single item from :math:`T`. (:math:`\{t,v\}`). For example, solar PV (technology) installed in 2030 (vintage). -Sets ----- -In a mathematical model like Temoa, sets are used to index parameters and -variables. Below we define the sets used in Temoa, which are grouped into logical -components. In each case, we provide the mathematical notation used in the -mathematical formulation of the model, as well as the associated names in the -Python code and database schema. - -.. include:: db_model_comparison.rst - - -.. _table_set: - -.. csv-table:: List of all Temoa sets with which a modeler might interact. The - asterisked (\*) elements are automatically derived by the model and - are not user-specifiable. - :header: "Set","Temoa Name","Data Type","Short Description" - :widths: 8, 28, 14, 50 - - ":math:`{}^*\text{C}`",":code:`commodity_all`","string","union of all commodity sets" - ":math:`\text{C}^s`",":code:`commodity_source`","string","input sources (not balanced by CommodityBalance_constraint)" - ":math:`\text{C}^d`",":code:`commodity_demand`","string","end-use demand commodities" - ":math:`\text{C}^e`",":code:`commodity_emissions`","string","emission commodities (e.g. :math:`\text{CO}_\text{2}` :math:`\text{NO}_\text{x}`)" - ":math:`\text{C}^p`",":code:`commodity_physical`","string","general energy forms (e.g. electricity, coal, uranium, oil)" - ":math:`\text{C}^a`",":code:`commodity_annual`","string","same as commodity physical but flows are only balanced over each period (:math:`\text{C}^a \subset \text{C}^p`)" - ":math:`\text{C}^w`",":code:`commodity_waste`","string","production can be greater than consumption. can be physical, annual, or neither (not balanced)" - ":math:`{}^*\text{C}^k`",":code:`commodity_sink`","string","end-use demands and waste commodities (:math:`\text{C}_d \cup \text{C}_w`)" - ":math:`{}^*\text{C}^c`",":code:`commodity_carrier`","string","physical energy carriers and sinks (:math:`\text{C}_p \cup \text{C}_k`)" - ":math:`\text{I}`",,"string","alias of :math:`\text{C}^p`; used in documentation only to mean ""input""" - ":math:`\text{O}`",,"string","alias of :math:`\text{C}^c`; used in documentation only to mean ""output""" - ":math:`\text{P}^e`",":code:`time_existing`",":math:`\mathbb{Z}`","model periods before optimization begins" - ":math:`\text{P}^f`",":code:`time_future`",":math:`\mathbb{Z}`","model time scale of interest; the last year is not optimized" - ":math:`{}^*\text{P}^o`",":code:`time_optimize`",":math:`\mathbb{Z}`","model time periods to optimize; (:math:`\text{P}^f - \text{max}(\text{P}^f)`)" - ":math:`\text{R}`",":code:`regions`","string","distinct geographical regions" - ":math:`{}^*\text{V}`",":code:`vintage_all`",":math:`\mathbb{Z}`","possible tech vintages; (:math:`\text{P}^e \cup \text{P}^o`)" - ":math:`\text{S}`",":code:`time_season`","string","seasonal divisions (e.g. winter, summer); each entry carries a :code:`segment_fraction` giving its share of the year" - ":math:`\text{D}`",":code:`time_of_day`","string","time-of-day divisions (e.g. morning); each entry carries an :code:`hours` value (default 1)" - ":math:`{}^*\text{T}`",":code:`tech_all`","string","all technologies to be modeled (all technologies are currently production-type: :math:`T = T^p`)" - ":math:`\text{T}^u`",":code:`tech_unlim_cap`","string","technologies that have no bound on capacity, and can have variable costs only (imports, taxes, etc.); (:math:`{T}^u \subset (T - T^{res})`)" - ":math:`\text{T}^a`",":code:`tech_annual`","string","technologies that produce constant annual output; (:math:`{T}^a \subset T`)" - ":math:`\text{T}^b`",":code:`tech_baseload`","string","baseload electric generators; (:math:`{T}^b \subset T`)" - ":math:`\text{T}^c`",":code:`tech_curtailment`","string","technologies with curtailable output and no upstream cost; (:math:`{T}^c \subset (T - T^{res})`)" - ":math:`\text{T}^x`",":code:`tech_exchange`","string","technologies used for interregional commodity flow; (:math:`{T}^x \subset T`). See Note 1 below on capacity and cost application for `tech_exchange`" - ":math:`\text{T}^e`",":code:`tech_existing`","string","technologies constructed in an existing (past) vintage; (:math:`{T}^e \subset T`)." - ":math:`\text{T}^f`",":code:`tech_flex`","string","technologies producing excess commodity flows; (:math:`{T}^f \subset T`)" - "",":code:`tech_group_names`","string","named groups for use in group constraints" - "",":code:`tech_group_members`","(tech_group_names, tech)","Each technology belonging to each group defined above" - ":math:`\text{T}^p`",":code:`tech_production`","string","techs producing intermediate commodities" - ":math:`\text{T}^{ur}`",":code:`tech_upramping`","string","electric generators with a ramp up hourly rate limit; (:math:`{T}^{ur} \subset T`)" - ":math:`\text{T}^{dr}`",":code:`tech_downramping`","string","electric generators with a ramp down hourly rate limit; (:math:`{T}^{dr} \subset T`)" - ":math:`\text{T}^{res}`",":code:`tech_reserve`","string","electric generators contributing to the reserve margin requirement; (:math:`{T}^res \subset T`)" - ":math:`\text{T}^{ret}`",":code:`tech_retirement`","string","technologies allowed to retire before end of life; (:math:`{T}^{ret} \subset (T - T^{u})`)" - ":math:`\text{T}^s`",":code:`tech_storage`","string","all storage technologies; (:math:`{T}^s \subset T`)" - ":math:`\text{T}^{ss}`",":code:`tech_seasonal_storage`","string","seasonal storage technologies; (:math:`{T}^{ss} \subset T^s`)" - -Note 1: Temoa sets Capacity for Exchange Technologies to be equal in both directions on the link automatically. -Costs are apportioned as follows: If both directions of the link have a cost parameter, costs are accrued to -each region region directly based on flow *to* that region. If only 1 element of the link holds a populated cost value, -then that cost divided between the 2 regions automatically based on use, where each region is "billed" according -to use as a receiver. - -Temoa uses two different set notation styles, one for code representation and -one that utilizes standard algebraic notation. For brevity, the mathematical -representation uses capital letters to denote sets, and lower case letters to -represent items within sets. For example, :math:`T` represents the set of all -technologies and :math:`t` represents an item within :math:`T`. - -The code representation is more verbose than the algebraic version, using full -words. This documentation presents them in an italicized font. The same -example of all technologies is represented in the code as :code:`tech_all`. -:ref:`Table 1 ` lists all of the Temoa sets, with both sets of notation. - -There are four basic set "groups" within Temoa: periods, sub-annual "time slices", -technologies, and energy commodities. The technology-related sets contain all the -possible energy technologies that the model may build and the commodities sets -contain all the input and output forms of energy that technologies consume and -produce. The period and time slice sets merit a slightly longer discussion. Treatment of Time ----------------- From ee32a17cc20c497568280dca281462c8eee63fed Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Mar 2026 15:10:39 -0400 Subject: [PATCH 533/587] Overwrite old visualization.rst with new visualization section --- docs/source/Documentation.rst | 73 +--------------------- docs/source/visualization.rst | 114 +++++++++++++++------------------- 2 files changed, 51 insertions(+), 136 deletions(-) diff --git a/docs/source/Documentation.rst b/docs/source/Documentation.rst index 2c899679e..b9ccb3b48 100644 --- a/docs/source/Documentation.rst +++ b/docs/source/Documentation.rst @@ -15,78 +15,7 @@ Quick Start Visualization ============= -Network Diagrams ----------------- - -Since the Temoa model consists of an energy network in which technologies are connected -by the flow of energy commodities, a directed network graph represents an excellent way -to visualize a given energy system representation in a Temoa-compatible input database. - -Temoa provides two types of network visualizations: - -1. **Interactive HTML Network Graphs** - Dynamic, explorable visualizations showing commodity flows and technology connections -2. **Graphviz Diagrams** - Static SVG/DOT format diagrams showing the energy system structure - -Generating Network Visualizations -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The easiest way to generate these diagrams is to enable visualization options in your -configuration TOML file. Add the following to your config file: - -.. parsed-literal:: - # Enable interactive HTML network graphs (requires source_trace = true) - source_trace = true - plot_commodity_network = true - - # Enable Graphviz static diagrams - graphviz_output = true - -When these options are enabled, Temoa will automatically generate visualization files -in the output directory during model execution. - -**Interactive Network Graphs** will be created as HTML files (one per time period) that -you can open in a web browser. These provide an interactive view where you can: - -- Pan and zoom the network -- Click on nodes to see details -- Toggle between commodity-centric and technology-centric views -- Filter by sector using color-coded legends - -**Graphviz Diagrams** will be created as both ``.dot`` (source) and ``.svg`` (rendered) -files in a subdirectory within your output folder. These provide static visualizations -showing: - -- Full energy system maps -- Capacity and activity results per model time period -- Technology interconnections via commodity flows - -Example Visualizations -~~~~~~~~~~~~~~~~~~~~~~ - -**Interactive Network Graph** - -The interactive HTML network graphs provide dynamic exploration with pan, zoom, and filtering capabilities: - -.. raw:: html - - - -*Interactive network graph for the 'utopia' test system in 1990. You can pan, zoom, click nodes for details, and toggle between commodity-centric and technology-centric views. These files are automatically generated when* ``source_trace = true`` *and* ``plot_commodity_network = true`` *are set in the configuration file.* - -**Static Graphviz Diagram** - -Graphviz also generates static SVG diagrams showing the energy system structure: - -.. figure:: images/results1990.* - :align: center - :figclass: center - :width: 100% - - Static Graphviz diagram showing the optimal installed capacity and commodity flows - for the 'utopia' test system in 1990. Technologies are shown as boxes, - commodities as circles, with arrows indicating energy flows. These diagrams - are automatically generated when ``graphviz_output = true`` is set in the - configuration file. +.. include:: visualization.rst ===================== diff --git a/docs/source/visualization.rst b/docs/source/visualization.rst index 411923d22..c94e8f2b7 100644 --- a/docs/source/visualization.rst +++ b/docs/source/visualization.rst @@ -1,86 +1,72 @@ Network Diagrams ---------------- -.. warning:: - The graphviz visualization tools have not been fully tested with Temoa v4.0. - They may require updates. Please report any issues on - `GitHub Issues `_. - -Since Temoa model consists of an energy network in which technologies are connected +Since the Temoa model consists of an energy network in which technologies are connected by the flow of energy commodities, a directed network graph represents an excellent way to visualize a given energy system representation in a Temoa-compatible input database. -Temoa utilizes an open source graphics package called `Graphviz`_ to create a series of -data-specific and interactive energy-system maps. Currently, the output graphs consist of -a full energy system map as well as capacity and activity results per model time period. -In addition, users can create subgraphs focused on a particular commodity or technology. +Temoa provides two types of network visualizations: -To use graphviz from the command line, navigate to the :code:`data_processing` folder, -where the graphviz script resides. To review all of the graphviz options, use the -:code:`--help` flag: +1. **Interactive HTML Network Graphs** - Dynamic, explorable visualizations showing commodity flows and technology connections +2. **Graphviz Diagrams** - Static SVG/DOT format diagrams showing the energy system structure -.. parsed-literal:: - $ python make_graphviz.py --help +Generating Network Visualizations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The most basic way to use graphviz is to view the full energy system map: +The easiest way to generate these diagrams is to enable visualization options in your +configuration TOML file. Add the following to your config file: .. parsed-literal:: - $ python make_graphviz.py -i ../data_files/temoa_utopia.sqlite + # Enable interactive HTML network graphs (requires source_trace = true) + source_trace = true + plot_commodity_network = true -In the command above, note that we have to point the Graphviz module to the -:code:`temoa_utopia` database file, which resides in the :code:`data_files` -directory. The resultant system map will look like this: + # Enable Graphviz static diagrams + graphviz_output = true -.. figure:: images/simple_model.* - :align: center - :figclass: center - :figwidth: 60% - - This is a map of the simple 'Utopia' system, which we often use for testing - purposes. The map shows the possible commodity flows through the system, - providing a comprehensive overview of the system. Creating the simple system - map is useful for debugging purposes in order to make sure that technologies - are linked together properly via commodity flows. - -It is also possible to create a system map showing the optimal installed capacity -and technology flows in a particular model time period. These results are associated -with a specific model run stored in the model database. To view the results, include -the scenario flag (:code:`-s`) and a specific model year (:code:`-y`). - -Note that when Graphiz runs, it creates a folder within the :code:`data_processing` -folder. The folder itself is assigned the name of the database file, with -:code:`input_graphviz` appended to the end. This descriptor changes if using Graphviz -to visualize output graphics. Within this Graphviz-generated folder are two files. The -graphics file (default: svg) is a viewable image of the network. The dot file is the -input file to Graphviz that is created programmatically. Note that the dot files provide -another means to debug the model and create an archive of visualizations for auditing -purposes. In addition, we have taken care to make these intermediate files well-formatted. +When these options are enabled, Temoa will automatically generate visualization files +in the output directory during model execution. -.. parsed-literal:: - $ python make_graphviz.py -i ../data_files/temoa_utopia.sqlite -s test_run -y 1990 +**Interactive Network Graphs** will be created as HTML files (one per time period) that +you can open in a web browser. These provide an interactive view where you can: -.. figure:: images/global_results.* - :align: center - :figclass: center - :figwidth: 60% +- Pan and zoom the network +- Click on nodes to see details +- Toggle between commodity-centric and technology-centric views +- Filter by sector using color-coded legends - This graph shows the optimal installed capacity and commodity flows from the - 'utopia' test system in 2010. +**Graphviz Diagrams** will be created as both ``.dot`` (source) and ``.svg`` (rendered) +files in a subdirectory within your output folder. These provide static visualizations +showing: -The output can also be fine-tuned to show results associated with a specific -commodity or technology. For example: +- Full energy system maps +- Capacity and activity results per model time period +- Technology interconnections via commodity flows -.. parsed-literal:: - $ python make_graphviz.py -i ../data_files/temoa_utopia.sqlite -s test_run -y 2010 -b E31 +Example Visualizations +~~~~~~~~~~~~~~~~~~~~~~ -.. figure:: images/techvintage_results.* - :align: center - :figclass: center - :figwidth: 60% +**Interactive Network Graph** + +The interactive HTML network graphs provide dynamic exploration with pan, zoom, and filtering capabilities: + +.. raw:: html + + - In this case, the graph shows the commodity flow in and out of - technology 'E31' in 2010, which is from the 'test_run' scenario drawn from the - 'temoa_utopia' database. +*Interactive network graph for the 'utopia' test system in 1990. You can pan, zoom, click nodes for details, and toggle between commodity-centric and technology-centric views. These files are automatically generated when* ``source_trace = true`` *and* ``plot_commodity_network = true`` *are set in the configuration file.* +**Static Graphviz Diagram** + +Graphviz also generates static SVG diagrams showing the energy system structure: + +.. figure:: images/results1990.* + :align: center + :figclass: center + :width: 100% -.. _Graphviz: http://www.graphviz.org/ + Static Graphviz diagram showing the optimal installed capacity and commodity flows + for the 'utopia' test system in 1990. Technologies are shown as boxes, + commodities as circles, with arrows indicating energy flows. These diagrams + are automatically generated when ``graphviz_output = true`` is set in the + configuration file. From 37570c04ea72463489260fbf281f4c3215e035e1 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Mar 2026 15:38:34 -0400 Subject: [PATCH 534/587] Add a section on evolving myopic mode --- docs/source/myopic.rst | 79 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/docs/source/myopic.rst b/docs/source/myopic.rst index 8229c1f34..d0c6fbc70 100644 --- a/docs/source/myopic.rst +++ b/docs/source/myopic.rst @@ -28,16 +28,95 @@ To enable Myopic mode, set the ``scenario_mode`` to ``"myopic"`` in your configu [myopic] view_depth = 2 step_size = 1 + evolving = false + evolution_script = "temoa/extensions/myopic/evolution_updater.py" Settings ~~~~~~~~ * **view_depth**: The number of future time periods visible to the model in each iteration. For example, a ``view_depth`` of 2 means the model will optimize over two periods at a time. * **step_size**: The number of periods to advance the "base year" in each subsequent iteration. A ``step_size`` of 1 means the base year will move forward by one time period at a time. +* **evolving**: A boolean flag (``true`` or ``false``) that selects between evolving and non-evolving myopic mode. Defaults to ``false``. See :ref:`myopic-modes` below. +* **evolution_script**: Path to a Python script containing an ``iterate()`` function that is called between iterations in evolving mode. Ignored when ``evolving = false``. .. important:: Myopic mode requires that the ``input_database`` and ``output_database`` in your configuration point to the same file. This is because the sequencer needs to write intermediate results (like the ``myopic_efficiency`` table and capacity decisions) back to the database to inform subsequent windows. +.. _myopic-modes: + +Evolving vs. Non-Evolving Mode +------------------------------ + +Temoa supports two myopic sub-modes that control how iterations are generated and whether the +database can be modified between solves. + +Non-Evolving Mode (default) +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When ``evolving = false``, the sequencer eliminates **redundant iterations** near the end of the +planning horizon. If multiple consecutive iterations would all see the same final period, only +the first such iteration is kept. This avoids re-solving windows that cannot produce new information. + +For example, consider a model with future periods ``[2025, 2030, 2035, 2040, 2045]``, +``view_depth = 3``, and ``step_size = 1``: + +* Without pruning, the base years would be ``[2025, 2030, 2035, 2040]``. +* The iterations starting at 2035 and 2040 both see period 2045 as the last demand year, so only the first is kept. +* **Result**: 3 iterations instead of 4. + +Non-evolving mode is appropriate when the model structure (technologies, constraints, costs, etc.) does +not change between iterations and you want to minimize computation. + +Evolving Mode +~~~~~~~~~~~~~ + +When ``evolving = true``, the sequencer keeps **all** calculated iterations, stepping forward by exactly +``step_size`` until the planning horizon is exhausted. Between each iteration, the ``evolution_script`` +is called, giving the modeler an opportunity to modify the database before the next window is solved. + +Using the same example (periods ``[2025, 2030, 2035, 2040, 2045]``, ``view_depth = 3``, ``step_size = 1``): + +* Base years are ``[2025, 2030, 2035, 2040]``. +* **All 4 iterations** are kept, because the evolution script may change data between them. + +This mode is designed for scenarios where model parameters—such as technology costs, demand levels, or +policy constraints—need to evolve over time based on previous results or external logic. + +.. note:: + In evolving mode, the view depth may shorten near the end of the planning horizon so that the window + does not extend beyond the available periods. All iterations are still performed. + +Writing an Evolution Script +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The evolution script must define an ``iterate()`` function with the following signature: + +.. code-block:: python + + import sqlite3 + from temoa.extensions.myopic.myopic_index import MyopicIndex + + def iterate( + idx: MyopicIndex | None = None, + prev_base_year: int | None = None, + last_instance_status: str | None = None, + db_con: sqlite3.Connection | None = None, + ) -> None: + """Called between myopic iterations (evolving mode only).""" + # Use db_con to read/write the database as needed. + pass + +Parameters: + +* **idx**: The ``MyopicIndex`` for the current iteration, containing the base year, step year, last demand year, and last year. +* **prev_base_year**: The base year of the previous iteration. +* **last_instance_status**: ``'optimal'`` if the previous solve succeeded, or ``'roll_back'`` if it failed and triggered a rollback. +* **db_con**: An open SQLite connection to the myopic database, which can be used to read results from the prior iteration and modify data for the next one. + +The function is called *after* results from the current iteration have been written to the database and *before* +the myopic efficiency table is updated for the next iteration. A template is provided at +``temoa/extensions/myopic/evolution_updater.py``. + How it Works ------------ From 386e18d8fd25c29b9b4257632d5254bbf677ccdd Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Mar 2026 15:53:30 -0400 Subject: [PATCH 535/587] Fix limit_activity_share_constraint docstring equation --- temoa/components/limits.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/temoa/components/limits.py b/temoa/components/limits.py index eb4eb5096..9625c6eda 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -331,11 +331,18 @@ def limit_activity_share_constraint( .. math:: :label: Limit Activity Share - \sum_{R_g \subseteq R,\ S,\ D,\ I,\ T^{g_1} \subseteq T,\ V,\ O} + \sum_{R_g \subseteq R,\ S,\ D,\ I,\ (T^{g_1} \setminus T^a) \subseteq T,\ V,\ O} \mathbf{FO}_{r,p,s,d,i,t,v,o} - \quad \le, \ge, \text{or} = \quad LAS_{r,p,g_1,g_2} \cdot - \sum_{R_g \subseteq R,\ S,\ D,\ I,\ T^{g_2} \subseteq T,\ V,\ O} + + \sum_{R_g \subseteq R,\ I,\ (T^{g_1} \cap T^a) \subseteq T,\ V,\ O} + \mathbf{FOA}_{r,p,i,t,v,o} + \\ + \quad \le, \ge, \text{or} = \quad + \\ + LAS_{r,p,g_1,g_2} \cdot + \sum_{R_g \subseteq R,\ S,\ D,\ I,\ (T^{g_2} \setminus T^a) \subseteq T,\ V,\ O} \mathbf{FO}_{r,p,s,d,i,t,v,o} + + \sum_{R_g \subseteq R,\ I,\ (T^{g_2} \cap T^a) \subseteq T,\ V,\ O} + \mathbf{FOA}_{r,p,i,t,v,o} \qquad \forall \{r, p, g_1, g_2\} \in \Theta_{\text{limit\_activity\_share}} """ From 39643041cec42a40b22a7f27798ec0cd19878aac Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Wed, 25 Mar 2026 16:00:04 -0400 Subject: [PATCH 536/587] Fix reserve generation summation for annual techs --- temoa/components/reserves.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/temoa/components/reserves.py b/temoa/components/reserves.py index 7b65aceed..0a5a02442 100644 --- a/temoa/components/reserves.py +++ b/temoa/components/reserves.py @@ -80,8 +80,10 @@ def reserve_margin_dynamic( \sum_{t \in T^{res} \setminus T^{x} \setminus T^a, V, I, O}\ \mathbf{FO}_{r, p, s, d, i, t, v, o}\ \right. \\ - &+ \sum_{t \in T^{res} \cap T^a, V, I, O}\ - DSD_{r,s,d,o} \cdot \mathbf{FOA}_{r, p, i, t, v, o} \\ + &+ \sum_{t \in T^{res} \cap T^a, V, I, O} + \begin{cases} DSD_{r,s,d,o} & \text{if } o \in C^d \\ + SEG_{s,d} & \text{otherwise} \end{cases} + \cdot \mathbf{FOA}_{r, p, i, t, v, o} \\ &+ \sum_{t \in T^{res} \cap T^{x}, V, I, O} \ \mathbf{FO}_{r_i - r, p, s, d, i, t, v, o} \\ &- \sum_{t \in T^{res} \cap T^{x}, V, I, O} \ @@ -206,7 +208,9 @@ def reserve_margin_static( &\geq \left [ \sum_{ t \in T^{res} \setminus T^{x} \setminus T^a,V,I,O } \textbf{FO}_{r, p, s, d, i, t, v, o}\right.\\ &+ \sum_{ t \in T^{res} \cap T^a,V,I,O } - DSD_{r,s,d,o} \cdot \textbf{FOA}_{r, p, i, t, v, o}\\ + \begin{cases} DSD_{r,s,d,o} & \text{if } o \in C^d \\ + SEG_{s,d} & \text{otherwise} \end{cases} + \cdot \textbf{FOA}_{r, p, i, t, v, o}\\ &+ \sum_{ t \in T^{res} \cap T^{x},V,I,O } \textbf{FO}_{r_i-r, p, s, d, i, t, v, o}\\ &- \sum_{ t \in T^{res} \cap T^{x},V,I,O } \textbf{FI}_{r-r_i, p, s, d, i, t, v, o}\\ &- \left.\sum_{ t \in T^{res} \cap T^{s},V,I,O } \textbf{FI}_{r, p, s, d, i, t, v, o} From b0848e5cc1233c644bc37f612f23e02e7217f848 Mon Sep 17 00:00:00 2001 From: Davey Elder Date: Thu, 26 Mar 2026 12:59:09 -0400 Subject: [PATCH 537/587] Update typing, model reference and some other stuff around anatomy of a constraint --- docs/source/computational_implementation.rst | 58 +++++++++++--------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/docs/source/computational_implementation.rst b/docs/source/computational_implementation.rst index cc5a66659..34140384e 100644 --- a/docs/source/computational_implementation.rst +++ b/docs/source/computational_implementation.rst @@ -73,8 +73,8 @@ A simple definition of this constraint is: rule=demand_constraint ) -In line 1, '``M.demand_constraint =``' creates a place holder in the model object -``M``, called 'demand_constraint'. Like a variable, this is the name through +In line 1, '``self.demand_constraint =``' creates a place holder in the model object +``self``, called 'demand_constraint'. Like a variable, this is the name through which Pyomo will reference this class of constraints. ``Constraint(...)`` is a Pyomo-specific function that creates each individual constraint in the class. The first arguments (line 2) are the index sets of the constraint class. Line 2 @@ -94,30 +94,31 @@ is: .. code-block:: python :linenos: - def demand_constraint ( M, r, p, dem ): - if (r, p, dem) in M.singleton_demands: + def demand_constraint(model: TemoaModel, r: Region, p: Period, dem: Commodity) -> ExprLike: + if (r, p, dem) in model.singleton_demands: return Constraint.Skip supply_annual = sum( - M.v_flow_out_annual[r, p, S_i, S_t, S_v, dem] - for S_t, S_v in M.commodity_up_stream_process[r, p, dem] - for S_i in M.process_inputs_by_output[r, p, S_t, S_v, dem] + model.v_flow_out_annual[r, p, s_i, s_t, s_v, dem] + for s_t, s_v in model.commodity_up_stream_process[r, p, dem] + for s_i in model.process_inputs_by_output[r, p, s_t, s_v, dem] ) demand_constraint_error_check(supply_annual, r, p, dem) - expr = supply_annual == value( M.demand[r, p, dem] ) + expr = supply_annual == value(model.demand[r, p, dem]) return expr - ... The Python boiler-plate code to create the rule is on line 1. It begins with :code:`def`, followed by the rule name (matching the :code:`rule=...` argument in the constraint definition in ``temoa.core.model``), followed by the argument list. +Note that the argument list is strongly typed (each element has an explicit type like +:code:`Region`). Temoa enforces strong typing for code integrity using the :code:`mypy` package. The argument list will always start with the model (Temoa convention shortens -this to just :code:`M`) followed by local variable names in which to store the +this to just :code:`model`) followed by local variable names in which to store the index set elements passed by Pyomo. Note that the ordering is the same as -specified in the constraint definition. Thus the first item after :code:`M` +specified in the constraint definition. Thus the first item after :code:`model` will be an item from :code:`region`, the second from :code:`time_optimize`, and the third from :code:`commodity_demand`. Though one could choose :code:`a`, :code:`b`, and :code:`c` (or any naming scheme), we chose :code:`r`, :code:`p`, @@ -131,26 +132,26 @@ non-sparse manner. That is, Pyomo does not inherently know the valid indices for a given model parameter or equation. In ``temoa.core.model``, the constraint definition listed three index sets, so Pyomo will naively call this function for every possible combination of tuple :math:`\{r, p, dem\}`. However, as there -may be region-period-demand combinations for which no technology can supply -the demand, there is no need to create a constraint for such tuples. +may be region-period-demand combinations for which the constraint is unnecessary, +there is no need to create a constraint for such tuples. -Lines 5 through 8 sum the annual output flow of demand commodity ``dem`` +Lines 5 through 9 sum the annual output flow of demand commodity ``dem`` across all technologies and vintages. The :code:`supply_annual` is a local variable used in the expression (:code:`expr`) shown below. Note that the sum is performed with sparse indices, which are returned from dictionaries created in :code:`temoa/components/`. -Lines 5 through 8 also showcase a very common idiom in Python: +Lines 5 through 9 also showcase a very common idiom in Python: list-comprehension. List comprehension is a concise and efficient syntax to create lists. As opposed to building a list element-by-element with for-loops, list comprehension can convert many statements into a single operation. Consider a naive approach to calculating the supply:: to_sum = list() - for S_t in M.tech_all: - for S_v in M.vintage_all: + for S_t in model.tech_all: + for S_v in model.vintage_all: for S_i in process_inputs_by_output( r, p, S_t, S_v, dem ): - to_sum.append( M.v_flow_out_annual[r, p, S_i, S_t, S_v, dem] ) + to_sum.append( model.v_flow_out_annual[r, p, S_i, S_t, S_v, dem] ) supply_annual = sum( to_sum ) This implementation creates an extra list (:code:`to_sum`), then builds the list @@ -163,10 +164,10 @@ A less naive approach would replace the :code:`.append()` call with the one:: supply_annual = 0 - for S_t in M.tech_all: - for S_v in M.vintage_all: + for S_t in model.tech_all: + for S_v in model.vintage_all: for S_i in process_inputs_by_output( r, p, S_t, S_v, dem ): - supply_annual += M.v_flow_out_annual[r, p, S_i, S_t, S_v, dem] + supply_annual += model.v_flow_out_annual[r, p, S_i, S_t, S_v, dem] Why is list comprehension necessary? Strictly speaking, it is not, especially in light of this last example, which may read more familiar to those comfortable @@ -177,7 +178,7 @@ slightly more familiar to those used to a more mainstream algebraic modeling language.) With the correct model variables summed and stored in the -``supply_annual`` variable, Line 10 calls a function defined in +``supply_annual`` variable, Line 11 calls a function defined in :code:`temoa/components/commodities.py` that checks to make sure there is a technology that can supply each demand commodity ``dem`` in each :math:`\{r, p\}`. @@ -192,7 +193,7 @@ practice extremely useful while building and debugging a model. Line 12 creates the actual equality comparison. This line is superfluous, but we leave it in the code as a reminder that comparison operators (i.e. :code:`==`, :code:`<=`, :code:`>=`) with a Pyomo object (like supply_annual) generate a Pyomo -*expression object*, not a boolean True or False as one might expect.\\ [#return_expression]_ +*expression object*, not a boolean True or False as one might expect [#return_expression]_. It is this expression object that must be returned to Pyomo, as on Line 13. In the above implementation, the constraint is called for every tuple in the @@ -288,7 +289,9 @@ an index function is needed to determine the valid indices for the constraint. .. code-block:: python :linenos: - def ramp_up_day_constraint_indices(model: TemoaModel): + def ramp_up_day_constraint_indices( + model: TemoaModel, + ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]]: indices = { (r, p, s, d, t, v) for r, p, t in model.ramp_up_vintages @@ -296,6 +299,7 @@ an index function is needed to determine the valid indices for the constraint. for s in model.time_season for d in model.time_of_day } + return indices With the sparse set (:code:`demand_constraint_rpc` or :code:`ramp_up_day_constraint_rpsdtv`) @@ -380,7 +384,7 @@ reasons: This last point is somewhat esoteric, but consider the MathProg implementation of the Demand constraint in contrast with the last line of the Pyomo version:: - expr = supply_annual == value( M.demand[r, p, dem] ) + expr = supply_annual == value(model.demand[r, p, dem]) While the MathProg version indeed translates more directly to standard notation, consider that standard notation itself needs extensive surrounding text to @@ -772,11 +776,11 @@ Naming Conventions All constraints attached to a model should end with ``constraint``. Similarly, the function they use to define the constraint for each index should use the same prefix and ``constraint`` suffix, but separate them with an underscore -(e.g. ``M.somename_constraint = Constraint( ..., rule=somename_constraint``): +(e.g. ``self.somename_constraint = Constraint( ..., rule=somename_constraint``): .. code-block:: python - M.capacity_constraint = Constraint( M.CapacityVar_tv, rule=Capacity_constraint ) + self.capacity_constraint = Constraint( self.CapacityVar_tv, rule=Capacity_constraint ) When providing the implementation for a constraint rule, use a consistent naming scheme between functions and constraint definitions. For instance, we have From 56279352af58a3871092bd3eacfe42aae9701a08 Mon Sep 17 00:00:00 2001 From: idelder <35704891+idelder@users.noreply.github.com> Date: Fri, 27 Mar 2026 15:52:39 -0400 Subject: [PATCH 538/587] Clean up capacity index sets (#289) * Make sense of these capacity indices sets * Use the efficient CFP lookup * Discovered that capacity factor constraints for storage techs were silently ignored! * Unify formatting and remove never-true (and mypy triggering) None types from sets * Remove some more unnecessary None types * Redundant else returns --- temoa/components/capacity.py | 121 +++++++++++++------------------- temoa/components/commodities.py | 11 +-- temoa/components/costs.py | 15 +--- temoa/components/emissions.py | 8 +-- temoa/components/flows.py | 16 ++--- temoa/components/limits.py | 34 +++------ temoa/components/operations.py | 20 ++---- temoa/components/reserves.py | 12 ++-- temoa/components/storage.py | 24 +++---- temoa/components/technology.py | 2 +- temoa/components/utils.py | 11 ++- temoa/core/model.py | 15 ++-- temoa/types/set_types.py | 42 +++++------ tests/legacy_test_values.py | 3 +- tests/test_full_runs.py | 6 +- 15 files changed, 134 insertions(+), 206 deletions(-) diff --git a/temoa/components/capacity.py b/temoa/components/capacity.py index 5b8cac0f2..ada38fa6b 100644 --- a/temoa/components/capacity.py +++ b/temoa/components/capacity.py @@ -18,6 +18,8 @@ from deprecated import deprecated from pyomo.environ import value +from .utils import get_capacity_factor + if TYPE_CHECKING: from temoa.core.model import TemoaModel from temoa.types import ( @@ -142,23 +144,14 @@ def get_default_capacity_factor( return value(model.capacity_factor_tech[r, s, d, t]) -def get_capacity_factor( - model: TemoaModel, r: Region, s: Season, d: TimeOfDay, t: Technology, v: Vintage -) -> float: - if model.is_capacity_factor_process[r, t, v]: - return value(model.capacity_factor_process[r, s, d, t, v]) - else: - return value(model.capacity_factor_tech[r, s, d, t]) - - # ============================================================================ # PYOMO INDEX SETS # ============================================================================ -def capacity_variable_indices( +def new_capacity_variable_indices( model: TemoaModel, -) -> set[tuple[Region, Technology, Vintage]] | None: +) -> set[tuple[Region, Technology, Vintage]]: return model.new_capacity_rtv @@ -184,86 +177,72 @@ def annual_retirement_variable_indices( } +def capacity_variable_indices( + model: TemoaModel, +) -> set[tuple[Region, Period, Technology, Vintage]]: + return model.active_capacity_rptv + + def capacity_available_variable_indices( model: TemoaModel, -) -> set[tuple[Region, Period, Technology]] | None: +) -> set[tuple[Region, Period, Technology]]: return model.active_capacity_available_rpt def regional_exchange_capacity_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Region, Period, Technology, Vintage]]: - indices: set[tuple[Region, Region, Period, Technology, Vintage]] = set() - for r_e, p, i in model.export_regions: - for r_i, t, v, _o in model.export_regions[r_e, p, i]: - indices.add((r_e, r_i, p, t, v)) - - return indices + return { + (r_to, r_from, p, t, v) + for r_from, p, i in model.export_regions + for r_to, t, v, _o in model.export_regions[r_from, p, i] + } def capacity_annual_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Technology, Vintage]]: - capacity_indices: set[tuple[Region, Period, Technology, Vintage]] = set() - if model.active_activity_rptv: - for r, p, t, v in model.active_activity_rptv: - if t in model.tech_annual and t not in model.tech_demand: - if t not in model.tech_uncap: - capacity_indices.add((r, p, t, v)) - else: - return set() - - return capacity_indices + return { + (r, p, t, v) + for r, p, t, v in model.active_capacity_rptv + if t in model.tech_annual and t not in model.tech_demand + } def capacity_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]]: - capacity_indices: set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]] = set() - if model.active_activity_rptv: - for r, p, t, v in model.active_activity_rptv: - if t not in model.tech_annual or t in model.tech_demand: - if t not in model.tech_uncap: - if t not in model.tech_storage: - for s in model.time_season: - for d in model.time_of_day: - capacity_indices.add((r, p, s, d, t, v)) - else: - return set() - - return capacity_indices - - -@deprecated('switched over to validator... this set is typically VERY empty') -def capacity_factor_process_indices( - model: TemoaModel, -) -> set[tuple[Region, Season, TimeOfDay, Technology, Vintage]]: - indices: set[tuple[Region, Season, TimeOfDay, Technology, Vintage]] = set() - for r, _i, t, v, _o in model.efficiency.sparse_keys(): - for s in model.time_season: - for d in model.time_of_day: - indices.add((r, s, d, t, v)) - return indices + return { + (r, p, s, d, t, v) + for r, p, t, v in model.active_capacity_rptv + for s in model.time_season + for d in model.time_of_day + if t not in model.tech_annual or t in model.tech_demand + if t not in model.tech_storage + } def capacity_factor_tech_indices( model: TemoaModel, ) -> set[tuple[Region, Season, TimeOfDay, Technology]]: - all_cfs: set[tuple[Region, Season, TimeOfDay, Technology]] = set() - if model.active_capacity_available_rpt: # in case every tech in the model is unlim_cap - for r, _p, t in model.active_capacity_available_rpt: - for s in model.time_season: - for d in model.time_of_day: - all_cfs.add((r, s, d, t)) - else: - return set() - return all_cfs + return { + (r, s, d, t) + for r, _p, t in model.active_capacity_available_rpt + for s in model.time_season + for d in model.time_of_day + } -def capacity_available_variable_indices_vintage( +@deprecated('switched over to validator... this set is typically VERY empty') +def capacity_factor_process_indices( model: TemoaModel, -) -> set[tuple[Region, Period, Technology, Vintage]] | None: - return model.active_capacity_available_rptv +) -> set[tuple[Region, Season, TimeOfDay, Technology, Vintage]]: + return { + (r, s, d, t, v) + for r, _i, t, v, _o in model.efficiency.sparse_keys() + for s in model.time_season + for d in model.time_of_day + } # ============================================================================ @@ -660,18 +639,14 @@ def create_capacity_and_retirement_sets(model: TemoaModel) -> None: # Create active capacity index sets from the now-populated process_vintages model.new_capacity_rtv = { (r, t, v) - for r, p, t in model.process_vintages - for v in model.process_vintages[r, p, t] + for r, t, v in model.process_periods if t not in model.tech_uncap and v in model.time_optimize } model.active_capacity_available_rpt = { - (r, p, t) - for r, p, t in model.process_vintages - if model.process_vintages[r, p, t] and t not in model.tech_uncap + (r, p, t) for r, p, t in model.process_vintages if t not in model.tech_uncap } - model.active_capacity_available_rptv = { + model.active_capacity_rptv = { (r, p, t, v) - for r, p, t in model.process_vintages + for r, p, t in model.active_capacity_available_rpt for v in model.process_vintages[r, p, t] - if t not in model.tech_uncap } diff --git a/temoa/components/commodities.py b/temoa/components/commodities.py index 4a4694fcc..eb668e6b2 100644 --- a/temoa/components/commodities.py +++ b/temoa/components/commodities.py @@ -136,7 +136,7 @@ def demand_activity_constraint_indices( demand commodity (and no annual techs co-serve it), the flow variables are fixed directly and DAC indices are omitted. """ - indices = { + return { (r, p, s, d, t, v, dem) for r, p, dem in model.demand_constraint_rpc if (r, p, dem) not in model.singleton_demands @@ -145,7 +145,6 @@ def demand_activity_constraint_indices( for s in model.time_season for d in model.time_of_day } - return indices def commodity_balance_constraint_indices( @@ -153,7 +152,7 @@ def commodity_balance_constraint_indices( ) -> set[tuple[Region, Period, Season, TimeOfDay, Commodity]]: # Generate indices only for those commodities that are produced by # technologies with varying output at the time slice level. - indices = { + return { (r, p, s, d, c) for r, p, c in model.commodity_balance_rpc # r in this line includes interregional transfer combinations (not needed). @@ -163,15 +162,13 @@ def commodity_balance_constraint_indices( for d in model.time_of_day } - return indices - def annual_commodity_balance_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Commodity]]: # Generate indices only for those commodities that are produced by # technologies with constant annual output. - indices = { + return { (r, p, c) for r, p, c in model.commodity_balance_rpc # r in this line includes interregional transfer combinations (not needed). @@ -179,8 +176,6 @@ def annual_commodity_balance_constraint_indices( and c in model.commodity_annual } - return indices - # ============================================================================ # PYOMO CONSTRAINT RULES diff --git a/temoa/components/costs.py b/temoa/components/costs.py index 1c91d78ea..8d1f29437 100644 --- a/temoa/components/costs.py +++ b/temoa/components/costs.py @@ -97,18 +97,11 @@ def get_loan_life(model: TemoaModel, r: Region, t: Technology, v: Vintage) -> in def cost_fixed_indices(model: TemoaModel) -> set[tuple[Region, Period, Technology, Vintage]]: - # we pull the unlimited capacity techs from this index. They cannot have fixed costs - if model.active_activity_rptv: - return { - (r, p, t, v) for r, p, t, v in model.active_activity_rptv if t not in model.tech_uncap - } - return set() + return model.active_capacity_rptv def cost_variable_indices(model: TemoaModel) -> set[tuple[Region, Period, Technology, Vintage]]: - if model.active_activity_rptv: - return model.active_activity_rptv - return set() + return model.active_activity_rptv def lifetime_loan_process_indices(model: TemoaModel) -> set[tuple[Region, Technology, Vintage]]: @@ -120,9 +113,7 @@ def lifetime_loan_process_indices(model: TemoaModel) -> set[tuple[Region, Techno because in myopic mode, previously optimized vintages remain active in later windows and their data must be accepted by the param's index set. """ - indices = {(r, t, v) for r, i, t, v, o in model.efficiency.sparse_keys()} - - return indices + return {(r, t, v) for r, i, t, v, o in model.efficiency.sparse_keys()} # ============================================================================ diff --git a/temoa/components/emissions.py b/temoa/components/emissions.py index 4ee6669de..4d6d908be 100644 --- a/temoa/components/emissions.py +++ b/temoa/components/emissions.py @@ -38,20 +38,18 @@ def emission_activity_indices( model: TemoaModel, ) -> set[tuple[Region, Commodity, Commodity, Technology, Vintage, Commodity]]: - indices = { + return { (r, e, i, t, v, o) for r, i, t, v, o in model.efficiency.sparse_keys() for e in model.commodity_emissions if r in model.regions # omit any exchange/groups } - return indices - def linked_tech_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage, Commodity]]: - linkedtech_indices = { + return { (r, p, s, d, t, v, e) for r, t, e in model.linked_techs.sparse_keys() for p in model.time_optimize @@ -62,8 +60,6 @@ def linked_tech_constraint_indices( for d in model.time_of_day } - return linkedtech_indices - # ============================================================================ # PYOMO CONSTRAINT RULES diff --git a/temoa/components/flows.py b/temoa/components/flows.py index a6db3e9a6..656848a6a 100644 --- a/temoa/components/flows.py +++ b/temoa/components/flows.py @@ -41,9 +41,7 @@ def flow_variable_indices( model: TemoaModel, -) -> ( - set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] | None -): +) -> set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]]: return model.active_flow_rpsditvo @@ -55,9 +53,7 @@ def flow_variable_annual_indices( def flex_variable_indices( model: TemoaModel, -) -> ( - set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] | None -): +) -> set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]]: return model.active_flex_rpsditvo @@ -69,17 +65,13 @@ def flex_variable_annual_indices( def flow_in_storage_variable_indices( model: TemoaModel, -) -> ( - set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] | None -): +) -> set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]]: return model.active_flow_in_storage_rpsditvo def curtailment_variable_indices( model: TemoaModel, -) -> ( - set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] | None -): +) -> set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]]: return model.active_curtailment_rpsditvo diff --git a/temoa/components/limits.py b/temoa/components/limits.py index 4d2cd0951..f1e7087a6 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -64,26 +64,23 @@ def limit_tech_input_split_constraint_indices( def limit_tech_input_split_annual_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Commodity, Technology, Vintage, str]]: - indices = { + return { (r, p, i, t, v, op) for r, p, i, t, op in model.input_split_annual_vintages if t in model.tech_annual for v in model.input_split_annual_vintages[r, p, i, t, op] } - return indices - def limit_tech_input_split_average_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Commodity, Technology, Vintage, str]]: - indices = { + return { (r, p, i, t, v, op) for r, p, i, t, op in model.input_split_annual_vintages if t not in model.tech_annual for v in model.input_split_annual_vintages[r, p, i, t, op] } - return indices def limit_tech_output_split_constraint_indices( @@ -114,89 +111,81 @@ def limit_tech_output_split_constraint_indices( def limit_tech_output_split_annual_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Technology, Vintage, Commodity, str]]: - indices = { + return { (r, p, t, v, o, op) for r, p, t, o, op in model.output_split_annual_vintages if t in model.tech_annual for v in model.output_split_annual_vintages[r, p, t, o, op] } - return indices def limit_tech_output_split_average_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Technology, Vintage, Commodity, str]]: - indices = { + return { (r, p, t, v, o, op) for r, p, t, o, op in model.output_split_annual_vintages if t not in model.tech_annual for v in model.output_split_annual_vintages[r, p, t, o, op] } - return indices def limit_growth_capacity_indices(model: TemoaModel) -> set[tuple[Region, Period, Technology, str]]: - indices = { + return { (r, p, t, op) for r, t, op in model.limit_growth_capacity.sparse_keys() for p in model.time_optimize } - return indices def limit_degrowth_capacity_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Technology, str]]: - indices = { + return { (r, p, t, op) for r, t, op in model.limit_degrowth_capacity.sparse_keys() for p in model.time_optimize } - return indices def limit_growth_new_capacity_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Technology, str]]: - indices = { + return { (r, p, t, op) for r, t, op in model.limit_growth_new_capacity.sparse_keys() for p in model.time_optimize } - return indices def limit_degrowth_new_capacity_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Technology, str]]: - indices = { + return { (r, p, t, op) for r, t, op in model.limit_degrowth_new_capacity.sparse_keys() for p in model.time_optimize } - return indices def limit_growth_new_capacity_delta_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Technology, str]]: - indices = { + return { (r, p, t, op) for r, t, op in model.limit_growth_new_capacity_delta.sparse_keys() for p in model.time_optimize } - return indices def limit_degrowth_new_capacity_delta_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Technology, str]]: - indices = { + return { (r, p, t, op) for r, t, op in model.limit_degrowth_new_capacity_delta.sparse_keys() for p in model.time_optimize } - return indices def limit_seasonal_capacity_factor_constraint_indices( @@ -213,7 +202,7 @@ def limit_seasonal_capacity_factor_constraint_indices( def limit_annual_capacity_factor_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Technology, Vintage, Commodity, str]]: - indices = { + return { (r, p, t, v, o, op) for r, t, v, o, op in model.limit_annual_capacity_factor_constraint_rtvo for _r in geography.gather_group_regions(model, r) @@ -221,7 +210,6 @@ def limit_annual_capacity_factor_indices( for p in model.time_optimize if o in model.process_outputs.get((_r, p, _t, v), []) } - return indices # ============================================================================ diff --git a/temoa/components/operations.py b/temoa/components/operations.py index 8274d6906..2e6b3721a 100644 --- a/temoa/components/operations.py +++ b/temoa/components/operations.py @@ -32,7 +32,7 @@ def baseload_diurnal_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]]: - indices = { + return { (r, p, s, d, t, v) for r, p, t in model.baseload_vintages for v in model.baseload_vintages[r, p, t] @@ -40,13 +40,11 @@ def baseload_diurnal_constraint_indices( for d in model.time_of_day } - return indices - def ramp_up_day_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]]: - indices = { + return { (r, p, s, d, t, v) for r, p, t in model.ramp_up_vintages for v in model.ramp_up_vintages[r, p, t] @@ -54,13 +52,11 @@ def ramp_up_day_constraint_indices( for d in model.time_of_day } - return indices - def ramp_down_day_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]]: - indices = { + return { (r, p, s, d, t, v) for r, p, t in model.ramp_down_vintages for v in model.ramp_down_vintages[r, p, t] @@ -68,8 +64,6 @@ def ramp_down_day_constraint_indices( for d in model.time_of_day } - return indices - def ramp_up_season_constraint_indices( model: TemoaModel, @@ -80,7 +74,7 @@ def ramp_up_season_constraint_indices( return set() # s, s_next indexing ensures we dont build redundant constraints - indices = { + return { (r, p, s, s_next, t, v) for r, p, t in model.ramp_up_vintages for v in model.ramp_up_vintages[r, p, t] @@ -89,8 +83,6 @@ def ramp_up_season_constraint_indices( if s_next != model.time_next[s, model.time_of_day.last()][0] } - return indices - def ramp_down_season_constraint_indices( model: TemoaModel, @@ -101,7 +93,7 @@ def ramp_down_season_constraint_indices( return set() # s, s_next indexing ensures we dont build redundant constraints - indices = { + return { (r, p, s, s_next, t, v) for r, p, t in model.ramp_down_vintages for v in model.ramp_down_vintages[r, p, t] @@ -110,8 +102,6 @@ def ramp_down_season_constraint_indices( if s_next != model.time_next[s, model.time_of_day.last()][0] } - return indices - # ============================================================================ # PYOMO CONSTRAINT RULES diff --git a/temoa/components/reserves.py b/temoa/components/reserves.py index 1a65f5add..ff969db6e 100644 --- a/temoa/components/reserves.py +++ b/temoa/components/reserves.py @@ -15,7 +15,7 @@ from pyomo.environ import Constraint, value -from .utils import get_variable_efficiency +from .utils import get_capacity_factor, get_variable_efficiency if TYPE_CHECKING: from temoa.core.model import TemoaModel @@ -30,7 +30,7 @@ def reserve_margin_indices(model: TemoaModel) -> set[tuple[Region, Period, Season, TimeOfDay]]: - indices = { + return { (r, p, s, d) for r in model.planning_reserve_margin.sparse_keys() for p in model.time_optimize @@ -39,8 +39,6 @@ def reserve_margin_indices(model: TemoaModel) -> set[tuple[Region, Period, Seaso for d in model.time_of_day } - return indices - # ============================================================================ # HELPER FUNCTIONS FOR CONSTRAINT LOGIC @@ -100,7 +98,7 @@ def reserve_margin_dynamic( available = sum( model.v_capacity[r, p, t, v] * value(model.reserve_capacity_derate[r, s, t, v]) - * value(model.capacity_factor_process[r, s, d, t, v]) + * get_capacity_factor(model, r, s, d, t, v) * value(model.capacity_to_activity[r, t]) * value(model.segment_fraction[s, d]) for (t, v) in model.process_reserve_periods[r, p] @@ -149,7 +147,7 @@ def reserve_margin_dynamic( available += sum( model.v_capacity[r1r2, p, t, v] * value(model.reserve_capacity_derate[r1r2, s, t, v]) - * value(model.capacity_factor_process[r1r2, s, d, t, v]) + * get_capacity_factor(model, r1r2, s, d, t, v) * value(model.capacity_to_activity[r1r2, t]) * value(model.segment_fraction[s, d]) for (t, v) in model.process_reserve_periods[r1r2, p] @@ -160,7 +158,7 @@ def reserve_margin_dynamic( available -= sum( model.v_capacity[r1r2, p, t, v] * value(model.reserve_capacity_derate[r1r2, s, t, v]) - * value(model.capacity_factor_process[r1r2, s, d, t, v]) + * get_capacity_factor(model, r1r2, s, d, t, v) * value(model.capacity_to_activity[r1r2, t]) * value(model.segment_fraction[s, d]) for (t, v) in model.process_reserve_periods[r1r2, p] diff --git a/temoa/components/storage.py b/temoa/components/storage.py index 4f1aea8df..eb3daf71b 100644 --- a/temoa/components/storage.py +++ b/temoa/components/storage.py @@ -18,7 +18,7 @@ from pyomo.environ import Constraint, value -from .utils import Operator, get_variable_efficiency, operator_expression +from .utils import Operator, get_capacity_factor, get_variable_efficiency, operator_expression if TYPE_CHECKING: from temoa.core.model import TemoaModel @@ -36,27 +36,24 @@ def storage_level_variable_indices( model: TemoaModel, -) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]] | None: +) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]]: return model.storage_level_indices_rpsdtv def seasonal_storage_level_variable_indices( model: TemoaModel, -) -> set[tuple[Region, Period, Season, Technology, Vintage]] | None: +) -> set[tuple[Region, Period, Season, Technology, Vintage]]: return model.seasonal_storage_level_indices_rpstv def seasonal_storage_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]]: - if model.seasonal_storage_level_indices_rpstv: - indices = { - (r, p, s, d, t, v) - for r, p, s, t, v in model.seasonal_storage_level_indices_rpstv - for d in model.time_of_day - } - return indices - return set() + return { + (r, p, s, d, t, v) + for r, p, s, t, v in model.seasonal_storage_level_indices_rpstv + for d in model.time_of_day + } def storage_init_variable_indices( @@ -69,8 +66,6 @@ def storage_init_variable_indices( empirically improved barrier solve time ~25% on a 16-region national model. The mechanism is not fully understood. """ - if not model.storage_level_indices_rpsdtv: - return set() return { (r, p, s, t, v) for r, p, s, _d, t, v in model.storage_level_indices_rpsdtv @@ -80,7 +75,7 @@ def storage_init_variable_indices( def storage_constraint_indices( model: TemoaModel, -) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]] | None: +) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]]: return model.storage_level_indices_rpsdtv @@ -547,6 +542,7 @@ def storage_throughput_constraint( max_throughput = ( model.v_capacity[r, p, t, v] * value(model.capacity_to_activity[r, t]) + * get_capacity_factor(model, r, s, d, t, v) * value(model.segment_fraction[s, d]) ) expr = throughput <= max_throughput diff --git a/temoa/components/technology.py b/temoa/components/technology.py index 10945de58..b6577d89a 100644 --- a/temoa/components/technology.py +++ b/temoa/components/technology.py @@ -46,7 +46,7 @@ def gather_group_techs(model: TemoaModel, t_or_g: Technology) -> Iterable[Techno def model_process_life_indices( model: TemoaModel, -) -> set[tuple[Region, Period, Technology, Vintage]] | None: +) -> set[tuple[Region, Period, Technology, Vintage]]: """ Returns the set of sensical (region, period, tech, vintage) tuples. The tuple indicates the periods in which a process is active, distinct from TechLifeFracIndices that diff --git a/temoa/components/utils.py b/temoa/components/utils.py index c26ccbafa..2fd417a36 100644 --- a/temoa/components/utils.py +++ b/temoa/components/utils.py @@ -78,5 +78,12 @@ def get_variable_efficiency( return value(model.efficiency[r, i, t, v, o]) * value( model.efficiency_variable[r, s, d, i, t, v, o] ) - else: - return value(model.efficiency[r, i, t, v, o]) + return value(model.efficiency[r, i, t, v, o]) + + +def get_capacity_factor( + model: TemoaModel, r: Region, s: Season, d: TimeOfDay, t: Technology, v: Vintage +) -> float: + if model.is_capacity_factor_process[r, t, v]: + return value(model.capacity_factor_process[r, s, d, t, v]) + return value(model.capacity_factor_tech[r, s, d, t]) diff --git a/temoa/core/model.py b/temoa/core/model.py index 4ce2a0275..4675b4ac9 100755 --- a/temoa/core/model.py +++ b/temoa/core/model.py @@ -132,7 +132,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.new_capacity_rtv: t.NewCapacitySet = set() self.active_capacity_available_rpt: t.ActiveCapacityAvailableSet = set() - self.active_capacity_available_rptv: t.ActiveCapacityAvailableVintageSet = set() + self.active_capacity_rptv: t.ActiveCapacityAvailableVintageSet = set() self.group_region_active_flow_rpt: t.GroupRegionActiveFlowSet = ( set() # Set of valid group-region, period, tech indices ) @@ -538,10 +538,10 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.initialize_efficiency_variable = BuildAction(rule=technology.check_efficiency_variable) # Define technology cost parameters - # dev note: the cost_fixed_rptv isn't truly needed, but it is included in a constraint, so - # let it go for now self.cost_fixed_rptv = Set(dimen=4, initialize=costs.cost_fixed_indices) self.cost_fixed = Param(self.cost_fixed_rptv) + self.cost_variable_rptv = Set(dimen=4, initialize=costs.cost_variable_indices) + self.cost_variable = Param(self.cost_variable_rptv) self.cost_invest_rtv = Set( within=self.regional_indices * self.tech_all * self.time_optimize @@ -556,9 +556,6 @@ def __init__(self, *args: object, **kwargs: object) -> None: self.cost_invest_rtv, initialize=costs.param_loan_annualize_rule ) - self.cost_variable_rptv = Set(dimen=4, initialize=costs.cost_variable_indices) - self.cost_variable = Param(self.cost_variable_rptv) - self.cost_emission_rpe = Set( within=self.regions * self.time_optimize * self.commodity_emissions ) @@ -784,10 +781,10 @@ def __init__(self, *args: object, **kwargs: object) -> None: ) # Derived decision variables - self.capacity_var_rptv = Set(dimen=4, initialize=costs.cost_fixed_indices) + self.capacity_var_rptv = Set(dimen=4, initialize=capacity.capacity_variable_indices) self.v_capacity = Var(self.capacity_var_rptv, domain=NonNegativeReals) - self.new_capacity_var_rtv = Set(dimen=3, initialize=capacity.capacity_variable_indices) + self.new_capacity_var_rtv = Set(dimen=3, initialize=capacity.new_capacity_variable_indices) self.v_new_capacity = Var(self.new_capacity_var_rtv, domain=NonNegativeReals, initialize=0) self.retired_capacity_var_rptv = Set( @@ -856,7 +853,7 @@ def __init__(self, *args: object, **kwargs: object) -> None: ['Starting adjusted_capacity_constraint'], rule=progress_check ) self.adjusted_capacity_constraint = Constraint( - self.cost_fixed_rptv, rule=capacity.adjusted_capacity_constraint + self.capacity_var_rptv, rule=capacity.adjusted_capacity_constraint ) self.progress_marker_5 = BuildAction(['Finished Capacity Constraints'], rule=progress_check) diff --git a/temoa/types/set_types.py b/temoa/types/set_types.py index d910db32e..57bd18310 100644 --- a/temoa/types/set_types.py +++ b/temoa/types/set_types.py @@ -11,27 +11,27 @@ ) # Set types for sparse indexing -ActiveFlowSet = ( - set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] | None -) -ActiveFlowAnnualSet = set[tuple[Region, Period, Commodity, Technology, Vintage, Commodity]] | None -ActiveFlexSet = ( - set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] | None -) -ActiveFlexAnnualSet = set[tuple[Region, Period, Commodity, Technology, Vintage, Commodity]] | None -ActiveFlowInStorageSet = ( - set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] | None -) -ActiveCurtailmentSet = ( - set[tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity]] | None -) -ActiveActivitySet = set[tuple[Region, Period, Technology, Vintage]] | None -StorageLevelIndicesSet = set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]] | None -SeasonalStorageLevelIndicesSet = set[tuple[Region, Period, Season, Technology, Vintage]] | None -NewCapacitySet = set[tuple[Region, Technology, Vintage]] | None -ActiveCapacityAvailableSet = set[tuple[Region, Period, Technology]] | None -ActiveCapacityAvailableVintageSet = set[tuple[Region, Period, Technology, Vintage]] | None -GroupRegionActiveFlowSet = set[tuple[Region, Period, Technology]] | None +ActiveFlowSet = set[ + tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity] +] +ActiveFlowAnnualSet = set[tuple[Region, Period, Commodity, Technology, Vintage, Commodity]] +ActiveFlexSet = set[ + tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity] +] +ActiveFlexAnnualSet = set[tuple[Region, Period, Commodity, Technology, Vintage, Commodity]] +ActiveFlowInStorageSet = set[ + tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity] +] +ActiveCurtailmentSet = set[ + tuple[Region, Period, Season, TimeOfDay, Commodity, Technology, Vintage, Commodity] +] +ActiveActivitySet = set[tuple[Region, Period, Technology, Vintage]] +StorageLevelIndicesSet = set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]] +SeasonalStorageLevelIndicesSet = set[tuple[Region, Period, Season, Technology, Vintage]] +NewCapacitySet = set[tuple[Region, Technology, Vintage]] +ActiveCapacityAvailableSet = set[tuple[Region, Period, Technology]] +ActiveCapacityAvailableVintageSet = set[tuple[Region, Period, Technology, Vintage]] +GroupRegionActiveFlowSet = set[tuple[Region, Period, Technology]] CommodityBalancedSet = set[tuple[Region, Period, Commodity]] SingletonDemandsSet = set[tuple[Region, Period, Commodity]] diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index 2852819f2..af31669c3 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -44,7 +44,8 @@ class ExpectedVals(Enum): # increased after rework of inter-season sequencing # reduced after changing fixed costs from MLP to PL # reduced by <1 after changing season definition (segfrac no longer rounded) - ExpectedVals.OBJ_VALUE: 34710.6730, + # increased by 143 after activating CF constraints for storage techs + ExpectedVals.OBJ_VALUE: 34853.6835, ExpectedVals.EFF_DOMAIN_SIZE: 12312, ExpectedVals.EFF_INDEX_SIZE: 64, # reduced 3/27: unlim_cap techs now employed. diff --git a/tests/test_full_runs.py b/tests/test_full_runs.py index de54159e7..01ff21532 100644 --- a/tests/test_full_runs.py +++ b/tests/test_full_runs.py @@ -121,7 +121,8 @@ def test_myopic_utopia( # reduced after removing ancient 1-year shift bug from objective function # increased after rework of inter-season sequencing # reduced by <1 after changing season definition (segfrac no longer rounded) - assert invest_sum == pytest.approx(11004.3544), 'sum of investment costs did not match expected' + # decreased by 41 after activating CF constraints for storage techs + assert invest_sum == pytest.approx(10963.1018), 'sum of investment costs did not match expected' con.close() @@ -141,7 +142,8 @@ def test_stochastic_utopia( # Stochastic Expected Value for current utopia configuration # reduced by <1 after changing season definition (segfrac no longer rounded) - expected_obj = 34389.1352 + # increased by 145 after activating CF constraints for storage techs + expected_obj = 34534.1822 assert sequencer.stochastic_sequencer is not None assert sequencer.stochastic_sequencer.objective_value == pytest.approx(expected_obj, rel=1e-5) From 214d1ab639338c05700e62367e696e98acfcd569 Mon Sep 17 00:00:00 2001 From: Anil Radhakrishnan Date: Fri, 27 Mar 2026 16:08:57 -0400 Subject: [PATCH 539/587] font size slider for visualizer (#256) * feat: font size slider for visualizer * tests: adding tests for special item styling in visualizer * docs: updating visualizer embed in docs to have font size slider * PR feedback fixes --- .../static/Network_Graph_utopia_1990.html | 9 +- temoa/utilities/graph_utils.py | 45 +++++-- .../network_vis_templates/graph_script.js | 112 +++++++++++++++--- .../network_vis_templates/graph_styles.css | 3 + .../network_vis_templates/graph_template.html | 7 ++ temoa/utilities/visualizer.py | 6 +- tests/test_commodity_visualizer.py | 89 ++++++++++++++ 7 files changed, 239 insertions(+), 32 deletions(-) create mode 100644 tests/test_commodity_visualizer.py diff --git a/docs/source/default/static/Network_Graph_utopia_1990.html b/docs/source/default/static/Network_Graph_utopia_1990.html index 243036757..f4089ae42 100644 --- a/docs/source/default/static/Network_Graph_utopia_1990.html +++ b/docs/source/default/static/Network_Graph_utopia_1990.html @@ -17,6 +17,13 @@

Configuration & Legend

aria-controls="config-container-content">
+
+

Visual Settings

+
+ + +
+

Style Legend

@@ -47,7 +54,7 @@

Sector Legend

diff --git a/temoa/utilities/graph_utils.py b/temoa/utilities/graph_utils.py index a1541f0af..4ee5ba5f2 100644 --- a/temoa/utilities/graph_utils.py +++ b/temoa/utilities/graph_utils.py @@ -175,10 +175,15 @@ def calculate_initial_positions( return positions # Arrange sector "anchors" in a large circle - layout_radius = 2000 # The radius of the main circle for sectors - jitter_radius = 1000 # How far nodes can be from their sector anchor - sector_anchors = {} + # Scale radius based on the number of sectors and nodes to handle small models better num_sectors = len(sectors_to_place) + num_nodes = len(nodes_to_place) + + # Base radius + incremental scaling + layout_radius = max(800, min(2000, 400 + 200 * num_sectors + 2 * num_nodes)) + jitter_radius = layout_radius // 2 + + sector_anchors = {} for i, sector in enumerate(sectors_to_place): angle = (i / num_sectors) * 2 * math.pi @@ -218,18 +223,31 @@ def calculate_tech_graph_positions( """ positions = {} + # Materialize the iterable to avoid consumption issues + all_edges_list = list(all_edges) + # 1. Identify all unique sectors present in the technology list - sectors_to_place = sorted({tech.sector for tech in all_edges if tech.sector}) + sectors_to_place = sorted({edge.sector for edge in all_edges_list if edge.sector}) if not sectors_to_place: # If no sectors, just return empty positions and let physics handle it return {} # 2. Arrange sector "anchors" in a large circle - layout_radius = 2500 # Use a large radius to ensure initial separation - jitter_radius = 600 # Controls the size of the initial clusters - sector_anchors = {} + # Scale radius based on the number of sectors and unique technologies + unique_techs_to_place = sorted( + {edge.tech for edge in all_edges_list if edge.tech}, key=lambda t: str(t) + ) num_sectors = len(sectors_to_place) + num_nodes = len(unique_techs_to_place) + + if not unique_techs_to_place: + return {} + + layout_radius = max(1000, min(2500, 500 + 300 * num_sectors + 5 * num_nodes)) + jitter_radius = layout_radius // 4 + + sector_anchors = {} for i, sector in enumerate(sectors_to_place): angle = (i / num_sectors) * 2 * math.pi @@ -237,9 +255,12 @@ def calculate_tech_graph_positions( cy = layout_radius * math.sin(angle) sector_anchors[sector] = (cx, cy) - # 3. Place each technology node near its sector's anchor point with jitter - for edge_tuple in all_edges: - primary_sector = edge_tuple.sector + # 3. Place each unique technology node near its sector's anchor point with jitter + # Create a mapping of tech to its primary sector from the edges + tech_to_sector = {edge.tech: edge.sector for edge in all_edges_list if edge.tech} + + for tech in unique_techs_to_place: + primary_sector = tech_to_sector.get(tech) if not primary_sector or primary_sector not in sector_anchors: # Place nodes without a defined sector at the center cx, cy = 0, 0 @@ -247,13 +268,13 @@ def calculate_tech_graph_positions( cx, cy = sector_anchors[primary_sector] # Apply deterministic "jitter" to prevent stacking (stable per-tech) - seed = uuid.uuid5(uuid.NAMESPACE_DNS, str(edge_tuple.tech)).int + seed = uuid.uuid5(uuid.NAMESPACE_DNS, str(tech)).int rng = random.Random(seed) rand_angle = rng.uniform(0, 2 * math.pi) rand_radius = rng.uniform(0, jitter_radius) x = cx + rand_radius * math.cos(rand_angle) y = cy + rand_radius * math.sin(rand_angle) - positions[edge_tuple.tech] = {'x': x, 'y': y} + positions[tech] = {'x': x, 'y': y} return positions diff --git a/temoa/utilities/network_vis_templates/graph_script.js b/temoa/utilities/network_vis_templates/graph_script.js index 78e77b915..f0bf39a9b 100644 --- a/temoa/utilities/network_vis_templates/graph_script.js +++ b/temoa/utilities/network_vis_templates/graph_script.js @@ -28,26 +28,59 @@ document.addEventListener('DOMContentLoaded', function () { primary_view_name: primaryViewName, secondary_view_name: secondaryViewName, } = data; - const optionsObject = (typeof optionsRaw === 'string') ? JSON.parse(optionsRaw) : optionsRaw; - // --- State --- - let currentView = 'primary'; - let primaryViewPositions = null; - let secondaryViewPositions = null; + let optionsObject = {}; + if (typeof optionsRaw === "string") { + try { + optionsObject = JSON.parse(optionsRaw); + } catch (e) { + console.error('Failed to parse graph options JSON:', e); + optionsObject = {}; + } + } else { + optionsObject = optionsRaw || {}; + } + + // Expose for debugging only — enable in production. + const isDebug = (typeof window !== 'undefined' && window.DEBUG_GRAPH) || + (typeof URLSearchParams !== 'undefined' && new URLSearchParams(window.location.search).has('debugGraph')); + if (isDebug) { + window.__graph = { + data, + allNodesPrimary, + allEdgesPrimary, + allNodesSecondary, + allEdgesSecondary, + optionsObject, + }; + } // --- DOM Elements --- + const fontSizeSlider = document.getElementById('font-size-slider'); const configWrapper = document.getElementById('config-panel-wrapper'); const configHeader = document.querySelector('.config-panel-header'); const configToggleButton = document.querySelector('.config-toggle-btn'); const advancedControlsToggle = document.getElementById('advanced-controls-toggle'); const visConfigContainer = document.getElementById('vis-config-container'); const searchInput = document.getElementById('search-input'); + + // --- Visual State --- + let currentView = 'primary'; + let primaryViewPositions = null; + let secondaryViewPositions = null; + let visualState = { + fontSize: (optionsObject?.nodes?.font?.size) || 14 + }; + + if (fontSizeSlider) { + fontSizeSlider.value = String(visualState.fontSize); + } const resetButton = document.getElementById('reset-view-btn'); const sectorTogglesContainer = document.getElementById('sector-toggles'); const viewToggleButton = document.getElementById('view-toggle-btn'); const graphContainer = document.getElementById('mynetwork'); // --- Config Panel Toggle --- - if (optionsObject.configure && optionsObject.configure.enabled) { + if (optionsObject?.configure?.enabled) { optionsObject.configure.container = visConfigContainer; configHeader.addEventListener('click', () => { const isCollapsed = configWrapper.classList.toggle('collapsed'); @@ -61,9 +94,41 @@ document.addEventListener('DOMContentLoaded', function () { }); } + // --- Visual Settings Sliders --- + let pendingRaf = null; + function updateVisualSettings() { + if (fontSizeSlider) visualState.fontSize = parseInt(fontSizeSlider.value, 10); + + if (pendingRaf) return; + + pendingRaf = requestAnimationFrame(() => { + pendingRaf = null; + + // Use setOptions for global font size - works for edges with smooth enabled + // Note: Don't set per-edge font as it breaks rendering with smooth edges + network.setOptions({ + nodes: { font: { size: visualState.fontSize } }, + edges: { font: { size: visualState.fontSize, align: 'top' } } + }); + + // Also update nodes individually since they have per-node font from addWithCurrentFontSize + // Note: Per-node font properties must be overwritten because they would otherwise take precedence over the global setting + const nodeUpdates = nodes.get().map(n => ({ + id: n.id, + font: { ...(n.font ?? {}), size: visualState.fontSize } + })); + nodes.update(nodeUpdates); + + network.redraw(); + }); + } + + if (fontSizeSlider) fontSizeSlider.addEventListener('input', updateVisualSettings); + + // --- Vis.js Network Initialization --- - const nodes = new vis.DataSet(allNodesPrimary); - const edges = new vis.DataSet(allEdgesPrimary); + const nodes = new vis.DataSet(); + const edges = new vis.DataSet(); const network = new vis.Network(graphContainer, { nodes, edges }, optionsObject); // --- Core Functions --- @@ -84,13 +149,13 @@ document.addEventListener('DOMContentLoaded', function () { nodes.clear(); edges.clear(); if (currentView === 'primary') { - nodes.add(allNodesSecondary); edges.add(allEdgesSecondary); + addWithCurrentFontSize(allNodesSecondary, allEdgesSecondary); currentView = 'secondary'; viewToggleButton.textContent = `Switch to ${primaryViewName}`; viewToggleButton.setAttribute('aria-pressed', 'true'); applyPositions(secondaryViewPositions); } else { - nodes.add(allNodesPrimary); edges.add(allEdgesPrimary); + addWithCurrentFontSize(allNodesPrimary, allEdgesPrimary); currentView = 'primary'; viewToggleButton.textContent = `Switch to ${secondaryViewName}`; viewToggleButton.setAttribute('aria-pressed', 'false'); @@ -134,8 +199,8 @@ document.addEventListener('DOMContentLoaded', function () { const visibleNodeIds = new Set(visibleNodes.map(n => n.id)); visibleEdges = activeEdgesData.filter(edge => visibleNodeIds.has(edge.from) && visibleNodeIds.has(edge.to)); } - nodes.clear(); edges.clear(); - nodes.add(visibleNodes); edges.add(visibleEdges); + + addWithCurrentFontSize(visibleNodes, visibleEdges); applyPositions(currentPositions); } @@ -205,6 +270,20 @@ document.addEventListener('DOMContentLoaded', function () { }); } + function addWithCurrentFontSize(newNodes, newEdges) { + nodes.clear(); + edges.clear(); + nodes.add( + newNodes.map(n => ({ + ...n, + font: { ...(n.font ?? {}), size: visualState.fontSize }, + })), + ); + // Don't set per-edge font - let network.setOptions() handle it + // vis.js ignores global font options when edges have per-item font set + edges.add(newEdges); + } + function resetView() { searchInput.value = ""; primaryViewPositions = null; @@ -213,8 +292,7 @@ document.addEventListener('DOMContentLoaded', function () { switchView(); // This will switch back to primary and apply null positions } else { // If already on primary, just reload the original data - nodes.clear(); edges.clear(); - nodes.add(allNodesPrimary); edges.add(allEdgesPrimary); + addWithCurrentFontSize(allNodesPrimary, allEdgesPrimary); applyPositions(primaryViewPositions); // Apply null to reset network.fit(); } @@ -233,9 +311,7 @@ document.addEventListener('DOMContentLoaded', function () { }); const filteredNodes = activeNodes.filter(node => nodesToShow.has(node.id)); const filteredEdges = activeEdges.filter(edge => nodesToShow.has(edge.from) && nodesToShow.has(edge.to)); - nodes.clear(); edges.clear(); - nodes.add(filteredNodes); - edges.add(filteredEdges); + addWithCurrentFontSize(filteredNodes, filteredEdges); network.fit(); } @@ -257,4 +333,6 @@ document.addEventListener('DOMContentLoaded', function () { createStyleLegend(); createSectorLegend(); createSectorToggles(); + // Initial data load with consistent font handling + addWithCurrentFontSize(allNodesPrimary, allEdgesPrimary); }); diff --git a/temoa/utilities/network_vis_templates/graph_styles.css b/temoa/utilities/network_vis_templates/graph_styles.css index 0402c090e..41e36997e 100644 --- a/temoa/utilities/network_vis_templates/graph_styles.css +++ b/temoa/utilities/network_vis_templates/graph_styles.css @@ -24,6 +24,9 @@ body, html { .legend-item { display: flex; align-items: center; margin-bottom: 6px; } .legend-color-swatch { width: 18px; height: 18px; margin-right: 8px; flex-shrink: 0; border: 1px solid #ccc; background-color: #f0f0f0; box-sizing: border-box; } .legend-label { font-size: 13px; } +.control-group { display: flex; align-items: center; gap: 15px; margin-bottom: 8px; } +.control-group label { min-width: 120px; font-size: 13px; font-weight: 500; } +.control-group input[type=range] { flex-grow: 1; max-width: 250px; } #advanced-controls-toggle { font-size: 12px; color: #007bff; cursor: pointer; text-decoration: none; margin-top: 15px; display: block; } .view-toggle-panel { padding: 8px 15px; background-color: #343a40; color: white; display: flex; justify-content: center; align-items: center; } .view-toggle-panel button { font-size: 14px; font-weight: 600; padding: 8px 16px; border-radius: 5px; border: 1px solid #6c757d; background-color: #495057; color: white; cursor: pointer; } diff --git a/temoa/utilities/network_vis_templates/graph_template.html b/temoa/utilities/network_vis_templates/graph_template.html index 8ec0a1f08..e54218edf 100644 --- a/temoa/utilities/network_vis_templates/graph_template.html +++ b/temoa/utilities/network_vis_templates/graph_template.html @@ -17,6 +17,13 @@

Configuration & Legend

aria-controls="config-container-content">
+
+

Visual Settings

+
+ + +
+

Style Legend

diff --git a/temoa/utilities/visualizer.py b/temoa/utilities/visualizer.py index 9dc04369c..50885e7f7 100644 --- a/temoa/utilities/visualizer.py +++ b/temoa/utilities/visualizer.py @@ -180,7 +180,8 @@ def make_nx_graph( if any(info['attrs'].get('dashes', False) for info in techs_info): combined_attrs['dashes'] = True - combined_attrs['value'] = sum(info['attrs'].get('value', 1) for info in techs_info) + # Use 'width' for thickness, 'value' breaks font rendering with smooth edges + combined_attrs['width'] = 2 + len(techs_info) # Base width + 1 per tech multi_edge_key = f'{ic}-{oc}-{uuid.uuid4().hex[:8]}' dg.add_edge(ic, oc, key=multi_edge_key, **combined_attrs) @@ -280,6 +281,7 @@ def nx_to_vis( 'width': 2, 'smooth': {'type': 'continuous', 'roundness': 0.5}, 'arrows': {'to': {'enabled': False, 'scaleFactor': 1}}, + 'font': {'align': 'top', 'size': 14}, }, 'physics': { 'enabled': False, @@ -304,7 +306,7 @@ def nx_to_vis( 'navigationButtons': False, 'keyboard': {'enabled': True, 'bindToWindow': False}, }, - 'layout': {'randomSeed': None, 'improvedLayout': True}, + 'layout': {'improvedLayout': True}, 'configure': { 'enabled': True, 'showButton': False, # We have our own header, so hide the default floating button diff --git a/tests/test_commodity_visualizer.py b/tests/test_commodity_visualizer.py new file mode 100644 index 000000000..69e2efe5d --- /dev/null +++ b/tests/test_commodity_visualizer.py @@ -0,0 +1,89 @@ +from temoa.model_checking.commodity_graph import generate_commodity_graph +from temoa.model_checking.network_model_data import EdgeTuple, NetworkModelData +from temoa.types.core_types import Commodity, Period, Region, Sector, Technology, Vintage + + +def test_special_items_styling() -> None: + """ + Test that demand orphans, other orphans, and driven techs + are correctly styled in the commodity graph. + """ + region = Region('test_region') + period = Period(2025) + + # Concrete NetworkModelData + network_data = NetworkModelData() + network_data.physical_commodities = {Commodity('comm_inter')} + network_data.source_commodities[(region, period)] = {Commodity('comm_source')} + network_data.demand_commodities[(region, period)] = {Commodity('comm_demand')} + + # Define some special items + demand_orphans = [ + EdgeTuple( + region, + Commodity('comm_inter'), + Technology('tech_demand_orphan'), + Vintage(2020), + Commodity('comm_demand'), + sector=Sector('S1'), + ) + ] + other_orphans = [ + EdgeTuple( + region, + Commodity('comm_source'), + Technology('tech_other_orphan'), + Vintage(2020), + Commodity('comm_inter'), + sector=Sector('S2'), + ) + ] + driven_techs = [ + EdgeTuple( + region, + Commodity('comm_source'), + Technology('tech_driven'), + Vintage(2020), + Commodity('comm_demand'), + sector=Sector('S3'), + ) + ] + + # Generate the graph + dg, _sector_colors = generate_commodity_graph( + region, + period, + network_data, + demand_orphans=demand_orphans, + other_orphans=other_orphans, + driven_techs=driven_techs, + ) + + # 1. Check Node Styling + assert dg.nodes['comm_demand']['color']['border'] == '#d62728' + assert dg.nodes['comm_demand']['borderWidth'] == 4 + assert 'Connected to Demand Orphan' in dg.nodes['comm_demand']['title'] + + assert dg.nodes['comm_inter']['color']['border'] == '#d62728' + assert dg.nodes['comm_inter']['borderWidth'] == 4 + + assert dg.nodes['comm_source']['color']['border'] == '#ff7f0e' + assert dg.nodes['comm_source']['borderWidth'] == 4 + + # 2. Check Edge Styling + edges = list(dg.edges(data=True)) + + edge_do = next((e for e in edges if (e[0] == 'comm_inter' and e[1] == 'comm_demand')), None) + assert edge_do is not None, 'Edge (comm_inter -> comm_demand) not found' + assert edge_do[2].get('dashes') is True + assert edge_do[2].get('color') == '#d62728' + + edge_oo = next((e for e in edges if (e[0] == 'comm_source' and e[1] == 'comm_inter')), None) + assert edge_oo is not None, 'Edge (comm_source -> comm_inter) not found' + assert edge_oo[2].get('dashes') is True + assert edge_oo[2].get('color') == '#ff7f0e' + + edge_dt = next((e for e in edges if (e[0] == 'comm_source' and e[1] == 'comm_demand')), None) + assert edge_dt is not None, 'Edge (comm_source -> comm_demand) not found' + assert edge_dt[2].get('dashes') is True + assert edge_dt[2].get('color') == '#1f77b4' From 72ad71b6f0c89c3212266a7e2a5ec83b53c6d92a Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sun, 29 Mar 2026 13:18:51 -0400 Subject: [PATCH 540/587] docs: restructure for better sidebar --- docs/source/computational_implementation.rst | 4 +- docs/source/conf.py | 2 - docs/source/database.rst | 195 ++++++++++++++++++ docs/source/index.rst | 27 ++- docs/source/mathematical_formulation.rst | 4 + docs/source/preface.rst | 5 +- docs/source/quick_start.rst | 199 +------------------ docs/source/references.rst | 73 +++++++ docs/source/visualization.rst | 4 + 9 files changed, 311 insertions(+), 202 deletions(-) create mode 100644 docs/source/database.rst create mode 100644 docs/source/references.rst diff --git a/docs/source/computational_implementation.rst b/docs/source/computational_implementation.rst index 34140384e..366010359 100644 --- a/docs/source/computational_implementation.rst +++ b/docs/source/computational_implementation.rst @@ -1,5 +1,5 @@ -The Temoa Computational Implementation -====================================== +Computational Implementation +============================ We have implemented Temoa within an algebraic modeling environment (AME). AMEs provide both a convenient way to describe mathematical optimization models diff --git a/docs/source/conf.py b/docs/source/conf.py index 43934d0da..ca0afbda7 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,7 +1,6 @@ # import os import sys -import time from pathlib import Path from typing import Any, cast @@ -32,7 +31,6 @@ author = ', '.join( author['name'] for author in cast('list[dict[str, Any]]', project_metadata.get('authors', [])) ) -copyright = f'2011-{time.strftime("%Y")}, NC State University' # The short version diff --git a/docs/source/database.rst b/docs/source/database.rst new file mode 100644 index 000000000..74529d8fc --- /dev/null +++ b/docs/source/database.rst @@ -0,0 +1,195 @@ + +===================== +Database Construction +===================== + +Input datasets in Temoa are stored in a relational database management system. +For those unfamiliar with databases, you can think of them as collections of +tables. Within each table, a 'primary key' uniquely identifies each row. A +'foreign key' is a column in one table that references the primary key of +another table, thereby establishing relationships between tables and ensuring +data consistency across the database. + +The following Entity-Relationship (ER) diagram provides a visual overview of the +Temoa v4 database schema and the relationships between its various tables: + +.. mermaid:: database_schema.mmd + :alt: Temoa Database Schema ER Diagram + :align: center + +Temoa uses `sqlite`_, a widely used, self-contained database +system. Building a database first requires constructing a sql file, which is +simply a text file that defines the structure of different database tables and +includes the input data. The snippet below is from the ``time_period`` table +used to define the ``test_system`` dataset: + +.. parsed-literal:: + 1 CREATE TABLE time_period + 2 ( + 3 sequence INTEGER UNIQUE, + 4 period INTEGER + 5 PRIMARY KEY, + 6 flag TEXT + 7 REFERENCES time_period_type (label) + 8 ); + 9 INSERT INTO "time_period" VALUES(1,2015,'e'); + 10 INSERT INTO "time_period" VALUES(2,2020,'f'); + 11 INSERT INTO "time_period" VALUES(3,2025,'f'); + 12 INSERT INTO "time_period" VALUES(4,2030,'f'); + 13 INSERT INTO "time_period" VALUES(5,2035,'f'); + +The first line creates the table. **Lines 3-7** define the columns within this +table. Note that ``period`` is the primary key. Therefore, the same time period +cannot be entered twice; each name must be unique. **Line 7**, which helps +define the ``flag`` column, declares a foreign key reference to the ``label`` +column of the ``time_period_type`` table. As a result, if the user tries to +enter a label in this table that does not exist in the ``time_period_type`` +table, it will fail with an error. This foreign key reference ensures that the +modeler doesn't accidently type the wrong label in this table. For context, +there are two basic types of time periods in Temoa, ``e``, which defines +pre-existing periods, and ``f``, which defines future time periods that are to +be optimized. + +This enforcement of names across tables using foreign keys helps immediately +catch typos. As you can imagine, typos happen in plain text files and Excel when +defining thousands of rows of data. Another big advantage of using databases is +that the model run outputs are stored in separate database output tables. The +outputs by model run are indexed by a scenario name, which makes it possible to +perform thousands of runs, programatically store all the results, and execute +arbitrary queries that instantaneously return the requested +data. + +Because some database table elements serve as foreign keys in other tables, we +recommend that you populate input tables in the following order: + +**Group 1: labels used for internal database processing** + * commodity_type: Need to identify which type of commodity. Do NOT change these abbreviations. + * technology_type: Need to identify which type of technology. Do NOT change these abbreviations. Categorizing + and sub-categorizing can be done in the Technology table itself. + * time_period_type: Used to distinguish which time periods are simply used to specify pre-existing + vintages and which represent future optimization periods. + + +**Group 2: sets used within Temoa** + * commodity: list of commodities used within the database + * technology: list of technologies used within the database + * time_period: list of both past and future time periods considered in the database + * time_season: seasons modeled in the database (also contains segment fractions) + * time_of_day: time of day segments modeled in the database + + +**Group 3: parameters used to define processes within Temoa** + * metadata_real (global_discount_rate) + * demand + * demand_specific_distribution + * efficiency + * existing_capacity + * capacity_factor_tech + * capacity_factor_process (only if CF varies by vintage; overwrites capacity_factor_tech) + * capacity_to_activity + * cost_fixed + * cost_invest + * cost_variable + * emission_activity + * lifetime_tech + * lifetime_process (only if LT varies by vintage; overwrites lifetime_tech) + + +**Group 4: parameters used to define constraints within Temoa** (non-exhaustive) + * limit_activity + * limit_capacity + * limit_emission + * limit_growth_capacity + * limit_new_capacity + * limit_resource + * limit_tech_input_split + * limit_tech_output_split + + +For help getting started, take a look at how ``data_files/example_dbs/utopia.sql`` +is constructed. To begin building your own database file, use +``data_files/temoa_schema_v4.sql``, which is a database file with the requisite +structure but no data added. We recommend leaving the database structure intact, +and simply adding data to the schema file, or constructing an empty database +from the schema file and then using a script or database editor to import data. +Once the sql file is complete, you can convert it into a binary sqlite file by +installing sqlite3 and executing the following command: + +.. parsed-literal:: + $ sqlite3 my_database.sqlite < my_database.sql + +Now you can specify this database as the source for both input and output data +in the config file. + +============ +Data Quality +============ + +In addition to numerous internal checks, Temoa (optionally) employs two quality checks on +data read in from the database. The outputs (actions and warnings) generated by these processes +are reported in the log file for the run. + +Both of the checks below can be run to QA data by running the model in `CHECK` mode and inspecting +the log file. During `CHECK` mode runs, no solve is attempted on the model. + +Price Checking +-------------- +The "price checker" reviews cost data in the 3 cost tables and considers technology lifetime. It +screens for possible inconsistencies that would corrupt output quality. Larger models may have +well over 100K cost entries and an overlooked investment cost for a particular vintage tech in +a particular region could easily be overlooked. Price checks performed/reported: + +1. **Missing Costs (Check 0)**: This check looks for technologies that have no fixed/invest/variable + costs at all. Other checks are more discriminating, so this check is only reported when Temoa is run + in `debug` mode by using the `-d` flag on the run command. +2. **Missing Fixed/Investment Costs (Check 1a)**: This check identifies technologies that are *not* + flagged as `uncapacitated` with neither a fixed or investment cost associated. These *might* be + problematic for solve because the model minimizes cost, so capacity in these technologies would be + free. `uncapacitated` technologies have no capacity measure, so fixed/investment costs are prohibited + for them and that is checked elsewhere. +3. **Inconsistent Fixed/Investment Cost (Check 1b)**: This check looks for inconsistent application + of fixed or base costs in the "base" or vintage year across all vintages and regions. So, if a tech has + a fixed cost in some particular region and vintage year, but not in all, it will be flagged as a likely + omission. +4. **Inconsistent Fixed & Variable Costs (Check 2)**: This check identifies techs that have + inconsistencies in the application of fixed - variable costs. Techs that have *any* fixed cost for + a particular [region, tech, vintage] process, but do not have entries that match the variable cost + entries for the same process are flagged, and vice-versa. This would hopefully identify an + accidental omission of some of the fixed/var costs for processes that have at least 1 entry for either. +5. **Lifetime Costing (Check 3)**: This check identifies costs that fall short or are missing + during the process's lifetime. If a process has a variable cost in *any* year during the lifetime, but + not all years, it is flagged. Same for fixed cost. +6. **Uncapacitated Tech Costs**: Any technology flagged as `uncapacitated` will trigger warnings here + if it has any fixed/invest costs. + +Source Tracing +-------------- + +Temoa works backwards from demands to identify chains of technologies required to meet the demand. +Source Tracing is designed to ensure that this backward tracing from demands describes a proper +commodity network without gaps that might allow intermediate commodities to be treated as a free +"source" commodity. Further description of possible network problems is included in the +`commodity network notes.md` file in the `docs` folder. + +Source Tracing pre-builds the entire commodity network in each region-period contained in the +data and analyzes it for "orphans" which likely represent gaps in the network that would lead +to erroneous output data. The operation is enabled by tagging foundational commodities for which +there are no predecessors as "source" commodities in the `Commodity` database table with an `s` tag. +Orphans (or chains of orphans) on either the demand or supply side are reported and *suppressed* in +the data to prevent network corruption. Additionally, Temoa performs cycle detection on the commodity +network to identify circular dependencies that could lead to non-convergence or erroneous results. +Users can configure the cycle detection behavior using the following settings: + +* **cycle_count_limit**: Limits the number of cycles reported in the log. A value of `-1` allows + unbounded detection, `0` causes the system to log an error on the first detected cycle and then + suppresses further cycle reports for the remainder of the run (without terminating execution), + and a positive integer sets a specific limit. Default is 100. +* **cycle_length_limit**: Minimum length of cycles to report. This can be used to filter out small, + expected circularities if necessary. Default is 1. The length limit is inclusive, so a cycle of + length 1 is a self-loop, and a cycle of length `n` has `n` unique nodes. + +Note that the myopic mode *requires* the use of Source Tracing to ensure accuracy as some orphans +may be produced by endogenous decisions in myopic runs. + + +.. _sqlite: https://www.sqlite.org/ diff --git a/docs/source/index.rst b/docs/source/index.rst index 63c3f8f7f..83fc88f92 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,11 +1,34 @@ Temoa Project Documentation -======================================================= +=========================== .. toctree:: + :maxdepth: 2 + :caption: Getting Started + + preface + quick_start + database + visualization + +.. toctree:: + :maxdepth: 2 + :caption: Core Concepts + + mathematical_formulation + computational_implementation + +.. toctree:: + :maxdepth: 2 + :caption: Advanced Features - Documentation monte_carlo myopic unit_checking stochastics mga + +.. toctree:: + :maxdepth: 1 + :caption: Appendix + + references diff --git a/docs/source/mathematical_formulation.rst b/docs/source/mathematical_formulation.rst index 1190104fa..7716c5194 100644 --- a/docs/source/mathematical_formulation.rst +++ b/docs/source/mathematical_formulation.rst @@ -1,4 +1,8 @@ +======================== +Mathematical Formulation +======================== + To understand this section, the reader will need at least a cursory understanding of mathematical optimization. We omit here that introduction, and instead refer the reader to `various`_ `available`_ `online`_ `sources`_. diff --git a/docs/source/preface.rst b/docs/source/preface.rst index 3ae144383..b60386d80 100644 --- a/docs/source/preface.rst +++ b/docs/source/preface.rst @@ -62,6 +62,10 @@ online presence that supports documentation, dissemination, and community engagement. Together, these elements are designed to foster collaboration, extensibility, and trust in energy system modeling results. +======= +Preface +======= + Why Temoa? @@ -120,4 +124,3 @@ to let us know the issue on our `mailing list`_\ . .. _GitHub Issues: https://github.com/TemoaProject/temoa/issues .. _GitHub Issue tracker: https://github.com/TemoaProject/temoa/issues .. _mailing list: https://groups.google.com/forum/#!forum/temoa-project - diff --git a/docs/source/quick_start.rst b/docs/source/quick_start.rst index 7664bb4c9..1d2a40ce3 100644 --- a/docs/source/quick_start.rst +++ b/docs/source/quick_start.rst @@ -1,5 +1,9 @@ +=========== +Quick Start +=========== + Installing Software Elements ---------------------------- @@ -121,198 +125,3 @@ the solver, and (5) to execute several of the modeling extensions. how to run Temoa from the command line. There is also an option to run `Temoa on the cloud `, which is explained in `this video tutorial `. - -===================== -Database Construction -===================== - -Input datasets in Temoa are stored in a relational database management system. -For those unfamiliar with databases, you can think of them as collections of -tables. Within each table, a 'primary key' uniquely identifies each row. A -'foreign key' is a column in one table that references the primary key of -another table, thereby establishing relationships between tables and ensuring -data consistency across the database. - -The following Entity-Relationship (ER) diagram provides a visual overview of the -Temoa v4 database schema and the relationships between its various tables: - -.. mermaid:: database_schema.mmd - :alt: Temoa Database Schema ER Diagram - :align: center - -Temoa uses `sqlite`_, a widely used, self-contained database -system. Building a database first requires constructing a sql file, which is -simply a text file that defines the structure of different database tables and -includes the input data. The snippet below is from the ``time_period`` table -used to define the ``test_system`` dataset: - -.. parsed-literal:: - 1 CREATE TABLE time_period - 2 ( - 3 sequence INTEGER UNIQUE, - 4 period INTEGER - 5 PRIMARY KEY, - 6 flag TEXT - 7 REFERENCES time_period_type (label) - 8 ); - 9 INSERT INTO "time_period" VALUES(1,2015,'e'); - 10 INSERT INTO "time_period" VALUES(2,2020,'f'); - 11 INSERT INTO "time_period" VALUES(3,2025,'f'); - 12 INSERT INTO "time_period" VALUES(4,2030,'f'); - 13 INSERT INTO "time_period" VALUES(5,2035,'f'); - -The first line creates the table. **Lines 3-7** define the columns within this -table. Note that ``period`` is the primary key. Therefore, the same time period -cannot be entered twice; each name must be unique. **Line 7**, which helps -define the ``flag`` column, declares a foreign key reference to the ``label`` -column of the ``time_period_type`` table. As a result, if the user tries to -enter a label in this table that does not exist in the ``time_period_type`` -table, it will fail with an error. This foreign key reference ensures that the -modeler doesn't accidently type the wrong label in this table. For context, -there are two basic types of time periods in Temoa, ``e``, which defines -pre-existing periods, and ``f``, which defines future time periods that are to -be optimized. - -This enforcement of names across tables using foreign keys helps immediately -catch typos. As you can imagine, typos happen in plain text files and Excel when -defining thousands of rows of data. Another big advantage of using databases is -that the model run outputs are stored in separate database output tables. The -outputs by model run are indexed by a scenario name, which makes it possible to -perform thousands of runs, programatically store all the results, and execute -arbitrary queries that instantaneously return the requested -data. - -Because some database table elements serve as foreign keys in other tables, we -recommend that you populate input tables in the following order: - -**Group 1: labels used for internal database processing** - * commodity_type: Need to identify which type of commodity. Do NOT change these abbreviations. - * technology_type: Need to identify which type of technology. Do NOT change these abbreviations. Categorizing - and sub-categorizing can be done in the Technology table itself. - * time_period_type: Used to distinguish which time periods are simply used to specify pre-existing - vintages and which represent future optimization periods. - - -**Group 2: sets used within Temoa** - * commodity: list of commodities used within the database - * technology: list of technologies used within the database - * time_period: list of both past and future time periods considered in the database - * time_season: seasons modeled in the database (also contains segment fractions) - * time_of_day: time of day segments modeled in the database - - -**Group 3: parameters used to define processes within Temoa** - * metadata_real (global_discount_rate) - * demand - * demand_specific_distribution - * efficiency - * existing_capacity - * capacity_factor_tech - * capacity_factor_process (only if CF varies by vintage; overwrites capacity_factor_tech) - * capacity_to_activity - * cost_fixed - * cost_invest - * cost_variable - * emission_activity - * lifetime_tech - * lifetime_process (only if LT varies by vintage; overwrites lifetime_tech) - - -**Group 4: parameters used to define constraints within Temoa** (non-exhaustive) - * limit_activity - * limit_capacity - * limit_emission - * limit_growth_capacity - * limit_new_capacity - * limit_resource - * limit_tech_input_split - * limit_tech_output_split - - -For help getting started, take a look at how ``data_files/example_dbs/utopia.sql`` -is constructed. To begin building your own database file, use -``data_files/temoa_schema_v4.sql``, which is a database file with the requisite -structure but no data added. We recommend leaving the database structure intact, -and simply adding data to the schema file, or constructing an empty database -from the schema file and then using a script or database editor to import data. -Once the sql file is complete, you can convert it into a binary sqlite file by -installing sqlite3 and executing the following command: - -.. parsed-literal:: - $ sqlite3 my_database.sqlite < my_database.sql - -Now you can specify this database as the source for both input and output data -in the config file. - -============ -Data Quality -============ - -In addition to numerous internal checks, Temoa (optionally) employs two quality checks on -data read in from the database. The outputs (actions and warnings) generated by these processes -are reported in the log file for the run. - -Both of the checks below can be run to QA data by running the model in `CHECK` mode and inspecting -the log file. During `CHECK` mode runs, no solve is attempted on the model. - -Price Checking --------------- -The "price checker" reviews cost data in the 3 cost tables and considers technology lifetime. It -screens for possible inconsistencies that would corrupt output quality. Larger models may have -well over 100K cost entries and an overlooked investment cost for a particular vintage tech in -a particular region could easily be overlooked. Price checks performed/reported: - -1. **Missing Costs (Check 0)**: This check looks for technologies that have no fixed/invest/variable - costs at all. Other checks are more discriminating, so this check is only reported when Temoa is run - in `debug` mode by using the `-d` flag on the run command. -2. **Missing Fixed/Investment Costs (Check 1a)**: This check identifies technologies that are *not* - flagged as `uncapacitated` with neither a fixed or investment cost associated. These *might* be - problematic for solve because the model minimizes cost, so capacity in these technologies would be - free. `uncapacitated` technologies have no capacity measure, so fixed/investment costs are prohibited - for them and that is checked elsewhere. -3. **Inconsistent Fixed/Investment Cost (Check 1b)**: This check looks for inconsistent application - of fixed or base costs in the "base" or vintage year across all vintages and regions. So, if a tech has - a fixed cost in some particular region and vintage year, but not in all, it will be flagged as a likely - omission. -4. **Inconsistent Fixed & Variable Costs (Check 2)**: This check identifies techs that have - inconsistencies in the application of fixed - variable costs. Techs that have *any* fixed cost for - a particular [region, tech, vintage] process, but do not have entries that match the variable cost - entries for the same process are flagged, and vice-versa. This would hopefully identify an - accidental omission of some of the fixed/var costs for processes that have at least 1 entry for either. -5. **Lifetime Costing (Check 3)**: This check identifies costs that fall short or are missing - during the process's lifetime. If a process has a variable cost in *any* year during the lifetime, but - not all years, it is flagged. Same for fixed cost. -6. **Uncapacitated Tech Costs**: Any technology flagged as `uncapacitated` will trigger warnings here - if it has any fixed/invest costs. - -Source Tracing --------------- - -Temoa works backwards from demands to identify chains of technologies required to meet the demand. -Source Tracing is designed to ensure that this backward tracing from demands describes a proper -commodity network without gaps that might allow intermediate commodities to be treated as a free -"source" commodity. Further description of possible network problems is included in the -`commodity network notes.md` file in the `docs` folder. - -Source Tracing pre-builds the entire commodity network in each region-period contained in the -data and analyzes it for "orphans" which likely represent gaps in the network that would lead -to erroneous output data. The operation is enabled by tagging foundational commodities for which -there are no predecessors as "source" commodities in the `Commodity` database table with an `s` tag. -Orphans (or chains of orphans) on either the demand or supply side are reported and *suppressed* in -the data to prevent network corruption. Additionally, Temoa performs cycle detection on the commodity -network to identify circular dependencies that could lead to non-convergence or erroneous results. -Users can configure the cycle detection behavior using the following settings: - -* **cycle_count_limit**: Limits the number of cycles reported in the log. A value of `-1` allows - unbounded detection, `0` causes the system to log an error on the first detected cycle and then - suppresses further cycle reports for the remainder of the run (without terminating execution), - and a positive integer sets a specific limit. Default is 100. -* **cycle_length_limit**: Minimum length of cycles to report. This can be used to filter out small, - expected circularities if necessary. Default is 1. The length limit is inclusive, so a cycle of - length 1 is a self-loop, and a cycle of length `n` has `n` unique nodes. - -Note that the myopic mode *requires* the use of Source Tracing to ensure accuracy as some orphans -may be produced by endogenous decisions in myopic runs. - - -.. _sqlite: https://www.sqlite.org/ diff --git a/docs/source/references.rst b/docs/source/references.rst new file mode 100644 index 000000000..8feac8eaa --- /dev/null +++ b/docs/source/references.rst @@ -0,0 +1,73 @@ + +========== +References +========== + +.. rubric:: Footnotes + +.. [#open_source_realities] The two main goals behind Temoa are transparency and + repeatability, hence the MIT license. Unfortunately, there are some harsh + realities in the current climate of energy modeling, so this license is not a + guarantee of openness. This documentation touches on the issues involved in + the final section. + +.. [#efficiency_table] The efficiency parameter is often referred to as the + efficiency table, due to how it looks after even only a few entries in the + Pyomo input "dot dat" file. + +.. [#glpk_presolve] Circa 2013, GLPK uses more memory than commercial + alternatives and has vastly weaker presolve capabilities. + +.. [#esom_definition] For a more in-depth description of energy system + optimization models (ESOMs) and guidance on how to use them, please see: + DeCarolis et al. (2017) "Formalizing best practice for energy system + optimization modelling", Applied Energy, 194: 184-198. + +.. [#web_browser_svg] SVG support in web browsers is currently hit or miss. The + most recent versions of Chromium, Google Chrome, and Mozilla Firefox support + SVG well enough for Temoa's current use of SVG. + +.. [#return_expression] A word on `return` expressions in Pyomo: in most + contexts a relational expression is evaluated instantly. However, in Pyomo, + a relational expression returns an `expression` object. That is, `'M.aVar >= + 5'` does not evaluate to a boolean *true* or *false*, and Pyomo will + manipulate it into the final LP formulation. + +.. [#abstract_model] In contrast to a 'concrete' model, an abstract algebraic + formulation describes the general equations of the model, but requires + modeler-specified input data before it can compute any results. + +.. |'''| replace:: ``'``\ ``'``\ ``'`` + +.. _GNU Linear Programming Kit: https://www.gnu.org/software/glpk/ +.. _WinGLPK: http://winglpk.sf.net/ +.. _Github repo: https://github.com/TemoaProject/temoa/ +.. _Temoa model: http://temoaproject.org/download/temoa.py +.. _temoaproject.org: http://temoaproject.org/ +.. _example data sets: http://temoaproject.org/download/example_data_sets.zip +.. _mailing list: https://groups.google.com/forum/\#\!forum/temoa-project +.. _Temoa Forum: https://groups.google.com/forum/\#\!forum/temoa-project +.. _various: http://xlinux.nist.gov/dads/HTML/optimization.html +.. _available: http://www.stanford.edu/\~boyd/cvxbook/ +.. _online: https://en.wikipedia.org/wiki/Optimization_problem +.. _sources: https://en.wikipedia.org/wiki/Mathematical_optimization +.. _GAMS: http://www.gams.com/ +.. _AMPL: http://www.ampl.com/ +.. _PDF: https://temoacloud.com/wp-content/uploads/2020/02/toolsforenergymodeloptimizationandanalysistemoa.pdf +.. _HTML: http://temoaproject.org/docs/ +.. _GitHub Issue tracker: https://github.com/TemoaProject/temoa/issues +.. _HTML version: http://temoaproject.org/docs/ +.. _code smell: https://en.wikipedia.org/wiki/Code_smell +.. _PEP 8: http://www.python.org/dev/peps/pep-0008/ +.. _PEP 3120: http://www.python.org/dev/peps/pep-3120/ +.. _list comprehension: http://docs.python.org/tutorial/datastructures.html\#list-comprehensions +.. _lambda function: http://docs.python.org/tutorial/controlflow.html\#lambda-forms +.. _generally accepted relative rates: http://www.forecasts.org/inflation.htm +.. _Pull Request: https://help.github.com/articles/using-pull-requests +.. _quick start guide: http://rogerdudler.github.io/git-guide/ +.. _sqlite: https://www.sqlite.org/ +.. _Graphviz: http://www.graphviz.org/ +.. _ruff: https://docs.astral.sh/ruff/ + +.. bibliography:: References.bib +.. _GitHub Issues: https://github.com/TemoaProject/temoa/issues diff --git a/docs/source/visualization.rst b/docs/source/visualization.rst index c94e8f2b7..f8d29b4ef 100644 --- a/docs/source/visualization.rst +++ b/docs/source/visualization.rst @@ -1,3 +1,7 @@ +============= +Visualization +============= + Network Diagrams ---------------- From 022995c4d4635f9dacbbe99f09d9034efe0cc591 Mon Sep 17 00:00:00 2001 From: ParticularlyPythonicBS Date: Sun, 29 Mar 2026 17:17:49 -0400 Subject: [PATCH 541/587] updating logos --- docs/source/assets/logo.pdf | Bin 5481 -> 5500 bytes docs/source/assets/logo.svg | 25 ++++++++++++++- docs/source/assets/logo_bottom_text.pdf | Bin 7202 -> 7222 bytes docs/source/assets/logo_bottom_text.svg | 40 ++++++++++++++++++++---- 4 files changed, 58 insertions(+), 7 deletions(-) diff --git a/docs/source/assets/logo.pdf b/docs/source/assets/logo.pdf index dacbdd101d496bdd4a38c67ded7aebce7dfb43ae..35933f72ab2d0654d5b706cf18651cf05d486905 100644 GIT binary patch delta 4903 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 Z3UhQ}a&&ldWo8OBGB+{`B_%~qMheG=mx=%Y delta 4854 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 diff --git a/docs/source/assets/logo.svg b/docs/source/assets/logo.svg index e1159b091..45bfb806f 100644 --- a/docs/source/assets/logo.svg +++ b/docs/source/assets/logo.svg @@ -6,8 +6,30 @@ version="1.1" width="174.93001" height="142.12" + sodipodi:docname="logo.svg" + inkscape:version="1.4.3 (0d15f75042, 2025-12-25)" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> +